Merge "Skip dexopt if app has preferCodeIntegrity=true"
diff --git a/Android.bp b/Android.bp
index cd0720d..56f3c23 100644
--- a/Android.bp
+++ b/Android.bp
@@ -49,6 +49,9 @@
         "rs/java/**/*.java",
 
         ":framework-javastream-protos",
+        // TODO: Resolve circular library dependency and remove media1-srcs and mediasession2-srcs
+        ":media1-srcs",
+        ":mediasession2-srcs",
 
         "core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl",
         "core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl",
@@ -104,6 +107,11 @@
         "core/java/android/app/backup/IRestoreObserver.aidl",
         "core/java/android/app/backup/IRestoreSession.aidl",
         "core/java/android/app/backup/ISelectBackupTransportCallback.aidl",
+        "core/java/android/app/contentsuggestions/IClassificationsCallback.aidl",
+        "core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl",
+        "core/java/android/app/contentsuggestions/ISelectionsCallback.aidl",
+        "core/java/android/app/prediction/IPredictionCallback.aidl",
+        "core/java/android/app/prediction/IPredictionManager.aidl",
         "core/java/android/app/role/IOnRoleHoldersChangedListener.aidl",
         "core/java/android/app/role/IRoleManager.aidl",
         "core/java/android/app/role/IRoleManagerCallback.aidl",
@@ -206,7 +214,6 @@
         "core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl",
         "core/java/android/hardware/usb/IUsbManager.aidl",
         "core/java/android/hardware/usb/IUsbSerialReader.aidl",
-        "core/java/android/net/ICaptivePortal.aidl",
         "core/java/android/net/IConnectivityManager.aidl",
         "core/java/android/hardware/ISensorPrivacyListener.aidl",
         "core/java/android/hardware/ISensorPrivacyManager.aidl",
@@ -269,10 +276,11 @@
         "core/java/android/os/storage/IStorageEventListener.aidl",
         "core/java/android/os/storage/IStorageShutdownObserver.aidl",
         "core/java/android/os/storage/IObbActionListener.aidl",
-        "core/java/android/permission/IRuntimePermissionPresenter.aidl",
+        "core/java/android/permission/IPermissionController.aidl",
         "core/java/android/rolecontrollerservice/IRoleControllerService.aidl",
         ":keystore_aidl",
         "core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
+        "core/java/android/service/appprediction/IPredictionService.aidl",
         "core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl",
         "core/java/android/service/autofill/augmented/IFillCallback.aidl",
         "core/java/android/service/autofill/IAutoFillService.aidl",
@@ -282,6 +290,7 @@
         "core/java/android/service/carrier/ICarrierService.aidl",
         "core/java/android/service/carrier/ICarrierMessagingCallback.aidl",
         "core/java/android/service/carrier/ICarrierMessagingService.aidl",
+        "core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl",
         "core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl",
         "core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl",
         "core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl",
@@ -298,6 +307,7 @@
         "core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl",
         "core/java/android/service/gatekeeper/IGateKeeperService.aidl",
         "core/java/android/service/contentcapture/IContentCaptureService.aidl",
+        "core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl",
         "core/java/android/service/notification/INotificationListener.aidl",
         "core/java/android/service/notification/IStatusBarNotificationHolder.aidl",
         "core/java/android/service/notification/IConditionListener.aidl",
@@ -350,6 +360,8 @@
         "core/java/android/service/textclassifier/ITextLanguageCallback.aidl",
         "core/java/android/service/textclassifier/ITextLinksCallback.aidl",
         "core/java/android/service/textclassifier/ITextSelectionCallback.aidl",
+        "core/java/android/service/attention/IAttentionService.aidl",
+        "core/java/android/service/attention/IAttentionCallback.aidl",
         "core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl",
         "core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl",
         "core/java/android/view/accessibility/IAccessibilityManager.aidl",
@@ -462,13 +474,11 @@
         "media/java/android/media/IAudioRoutesObserver.aidl",
         "media/java/android/media/IAudioService.aidl",
         "media/java/android/media/IAudioServerStateDispatcher.aidl",
-        "media/java/android/media/IMediaController2.aidl",
         "media/java/android/media/IMediaHTTPConnection.aidl",
         "media/java/android/media/IMediaHTTPService.aidl",
         "media/java/android/media/IMediaResourceMonitor.aidl",
         "media/java/android/media/IMediaRouterClient.aidl",
         "media/java/android/media/IMediaRouterService.aidl",
-        "media/java/android/media/IMediaSession2.aidl",
         "media/java/android/media/IMediaScannerListener.aidl",
         "media/java/android/media/IMediaScannerService.aidl",
         "media/java/android/media/IPlaybackConfigDispatcher.aidl",
@@ -494,10 +504,7 @@
         "media/java/android/media/session/ICallback.aidl",
         "media/java/android/media/session/IOnMediaKeyListener.aidl",
         "media/java/android/media/session/IOnVolumeKeyLongPressListener.aidl",
-        "media/java/android/media/session/ISession.aidl",
-        "media/java/android/media/session/ISessionCallback.aidl",
-        "media/java/android/media/session/ISessionController.aidl",
-        "media/java/android/media/session/ISessionControllerCallback.aidl",
+        "media/java/android/media/session/ISession2TokensListener.aidl",
         "media/java/android/media/session/ISessionManager.aidl",
         "media/java/android/media/soundtrigger/ISoundTriggerDetectionService.aidl",
         "media/java/android/media/soundtrigger/ISoundTriggerDetectionServiceClient.aidl",
@@ -512,8 +519,6 @@
         "media/java/android/media/tv/ITvInputSessionCallback.aidl",
         "media/java/android/media/tv/ITvRemoteProvider.aidl",
         "media/java/android/media/tv/ITvRemoteServiceInput.aidl",
-        "media/java/android/service/media/IMediaBrowserService.aidl",
-        "media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl",
         "telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl",
         "telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl",
         "telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl",
@@ -593,7 +598,7 @@
         "telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl",
         "telephony/java/com/android/internal/telephony/ISms.aidl",
         "telephony/java/com/android/internal/telephony/ISub.aidl",
-        "telephony/java/com/android/internal/telephony/IAns.aidl",
+        "telephony/java/com/android/internal/telephony/IOns.aidl",
         "telephony/java/com/android/internal/telephony/ITelephony.aidl",
         "telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl",
         "telephony/java/com/android/internal/telephony/IWapPushManager.aidl",
@@ -626,6 +631,7 @@
         "wifi/java/android/net/wifi/ISoftApCallback.aidl",
         "wifi/java/android/net/wifi/ITrafficStateCallback.aidl",
         "wifi/java/android/net/wifi/IWifiManager.aidl",
+        "wifi/java/android/net/wifi/IWifiUsabilityStatsListener.aidl",
         "wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl",
         "wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl",
         "wifi/java/android/net/wifi/aware/IWifiAwareMacAddressProvider.aidl",
@@ -680,6 +686,7 @@
             "location/java",
             "lowpan/java",
             "media/java",
+            "media/apex/java",
             "media/mca/effect/java",
             "media/mca/filterfw/java",
             "media/mca/filterpacks/java",
@@ -721,29 +728,36 @@
         "ext",
     ],
 
+    jarjar_rules: ":framework-hidl-jarjar",
+
     static_libs: [
         "apex_aidl_interface-java",
         "networkstack-aidl-interfaces-java",
         "framework-protos",
+        "game-driver-protos",
         "mediaplayer2-protos",
         "android.hidl.base-V1.0-java",
         "android.hardware.cas-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
         "android.hardware.health-V1.0-java-constants",
         "android.hardware.thermal-V1.0-java-constants",
+        "android.hardware.thermal-V1.0-java",
         "android.hardware.thermal-V1.1-java",
         "android.hardware.thermal-V2.0-java",
         "android.hardware.tv.input-V1.0-java-constants",
         "android.hardware.usb-V1.0-java-constants",
         "android.hardware.usb-V1.1-java-constants",
+        "android.hardware.usb-V1.2-java-constants",
         "android.hardware.vibrator-V1.0-java",
         "android.hardware.vibrator-V1.1-java",
         "android.hardware.vibrator-V1.2-java",
+        "android.hardware.vibrator-V1.3-java",
         "android.hardware.wifi-V1.0-java-constants",
         "android.hardware.radio-V1.0-java",
         "android.hardware.radio-V1.3-java",
         "android.hardware.radio-V1.4-java",
         "android.hardware.usb.gadget-V1.0-java",
+        "networkstack-aidl-interfaces-java",
         "netd_aidl_interface-java",
         "devicepolicyprotosnano",
     ],
@@ -751,8 +765,6 @@
     required: [
         // TODO: remove gps_debug when the build system propagates "required" properly.
         "gps_debug.conf",
-        // Loaded with System.loadLibrary by android.view.textclassifier
-        "libmedia2_jni",
     ],
 
     dxflags: [
@@ -778,6 +790,11 @@
     ],
 }
 
+filegroup {
+    name: "framework-hidl-jarjar",
+    srcs: ["jarjar_rules_hidl.txt"],
+}
+
 java_library {
     name: "framework",
     defaults: ["framework-defaults"],
@@ -788,11 +805,7 @@
     name: "framework-annotation-proc",
     defaults: ["framework-defaults"],
     // Use UsedByApps annotation processor
-    annotation_processors: ["unsupportedappusage-annotation-processor"],
-    // b/25860419: annotation processors must be explicitly specified for grok
-    annotation_processor_classes: [
-        "android.processor.unsupportedappusage.UsedByAppsProcessor",
-    ],
+    plugins: ["unsupportedappusage-annotation-processor"],
 }
 
 // A host library including just UnsupportedAppUsage.java so that the annotation
@@ -871,7 +884,30 @@
     name: "networkstack-aidl-interfaces",
     local_include_dir: "core/java",
     srcs: [
+        "core/java/android/net/ApfCapabilitiesParcelable.aidl",
+        "core/java/android/net/DhcpResultsParcelable.aidl",
+        "core/java/android/net/ICaptivePortal.aidl",
+        "core/java/android/net/INetworkMonitor.aidl",
+        "core/java/android/net/INetworkMonitorCallbacks.aidl",
+        "core/java/android/net/IIpMemoryStore.aidl",
         "core/java/android/net/INetworkStackConnector.aidl",
+        "core/java/android/net/INetworkStackStatusCallback.aidl",
+        "core/java/android/net/InitialConfigurationParcelable.aidl",
+        "core/java/android/net/IpPrefixParcelable.aidl",
+        "core/java/android/net/LinkAddressParcelable.aidl",
+        "core/java/android/net/LinkPropertiesParcelable.aidl",
+        "core/java/android/net/NetworkParcelable.aidl",
+        "core/java/android/net/PrivateDnsConfigParcel.aidl",
+        "core/java/android/net/ProvisioningConfigurationParcelable.aidl",
+        "core/java/android/net/ProxyInfoParcelable.aidl",
+        "core/java/android/net/RouteInfoParcelable.aidl",
+        "core/java/android/net/StaticIpConfigurationParcelable.aidl",
+        "core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
+        "core/java/android/net/dhcp/IDhcpServer.aidl",
+        "core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
+        "core/java/android/net/ip/IIpClient.aidl",
+        "core/java/android/net/ip/IIpClientCallbacks.aidl",
+        "core/java/android/net/ipmemorystore/**/*.aidl",
     ],
     api_dir: "aidl/networkstack",
 }
@@ -1047,6 +1083,7 @@
         "core/java/android/annotation/IntDef.java",
         "core/java/android/annotation/NonNull.java",
         "core/java/android/annotation/SystemApi.java",
+        "core/java/android/annotation/TestApi.java",
         "core/java/android/os/HwBinder.java",
         "core/java/android/os/HwBlob.java",
         "core/java/android/os/HwParcel.java",
@@ -1227,6 +1264,7 @@
         ":non_openjdk_javadoc_files",
         ":android_icu4j_src_files_for_docs",
         ":conscrypt_public_api_files",
+        ":media-srcs-without-aidls",
         "test-mock/src/**/*.java",
         "test-runner/src/**/*.java",
     ],
@@ -1288,6 +1326,7 @@
         ":non_openjdk_javadoc_files",
         ":android_icu4j_src_files_for_docs",
         ":conscrypt_public_api_files",
+        ":media-srcs-without-aidls",
     ],
     srcs_lib: "framework",
     srcs_lib_whitelist_dirs: frameworks_base_subdirs,
@@ -1296,7 +1335,6 @@
         "ext",
         "framework",
         "voip-common",
-        "android.test.mock.impl",
     ],
     local_sourcepaths: frameworks_base_subdirs,
     installable: false,
@@ -1734,6 +1772,7 @@
     name: "framework-media-annotation-srcs",
     srcs: [
         "core/java/android/annotation/CallbackExecutor.java",
+        "core/java/android/annotation/CallSuper.java",
         "core/java/android/annotation/DrawableRes.java",
         "core/java/android/annotation/IntDef.java",
         "core/java/android/annotation/LongDef.java",
@@ -1742,6 +1781,7 @@
         "core/java/android/annotation/RequiresPermission.java",
         "core/java/android/annotation/SdkConstant.java",
         "core/java/android/annotation/StringDef.java",
+        "core/java/android/annotation/SystemApi.java",
         "core/java/android/annotation/TestApi.java",
         "core/java/android/annotation/UnsupportedAppUsage.java",
         "core/java/com/android/internal/annotations/GuardedBy.java",
diff --git a/Android.mk b/Android.mk
index e3cc275..e405345 100644
--- a/Android.mk
+++ b/Android.mk
@@ -80,18 +80,18 @@
 # ==== hiddenapi lists =======================================
 .KATI_RESTAT: $(INTERNAL_PLATFORM_HIDDENAPI_FLAGS)
 $(INTERNAL_PLATFORM_HIDDENAPI_FLAGS): \
+    PRIVATE_FLAGS_INPUTS := $(PRIVATE_FLAGS_INPUTS) $(SOONG_HIDDENAPI_FLAGS)
+$(INTERNAL_PLATFORM_HIDDENAPI_FLAGS): \
     frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py \
     frameworks/base/config/hiddenapi-greylist.txt \
     frameworks/base/config/hiddenapi-greylist-max-p.txt \
     frameworks/base/config/hiddenapi-greylist-max-o.txt \
     frameworks/base/config/hiddenapi-force-blacklist.txt \
-    $(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \
-    $(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST) \
-    $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE)
+    $(INTERNAL_PLATFORM_HIDDENAPI_STUB_FLAGS) \
+    $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE) \
+    $(SOONG_HIDDENAPI_FLAGS)
 	frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py \
-	    --public $(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \
-	    --private $(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST) \
-	    --csv $(PRIVATE_FLAGS_INPUTS) \
+	    --csv $(INTERNAL_PLATFORM_HIDDENAPI_STUB_FLAGS) $(PRIVATE_FLAGS_INPUTS) \
 	    --greylist frameworks/base/config/hiddenapi-greylist.txt \
 	    --greylist-ignore-conflicts $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE) \
 	    --greylist-max-p frameworks/base/config/hiddenapi-greylist-max-p.txt \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index d01e183..30c2c69 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -252,6 +252,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/vendor/overlay/ExperimentNavigationBarSlim)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/overlay/ExperimentNavigationBarSlim)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/SystemUI)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio)
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
 # ******************************************************************
diff --git a/apct-tests/perftests/autofill/Android.mk b/apct-tests/perftests/autofill/Android.mk
index 28555a0..f4da40b 100644
--- a/apct-tests/perftests/autofill/Android.mk
+++ b/apct-tests/perftests/autofill/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-test \
+    androidx.test.rules \
     androidx.annotation_annotation \
     apct-perftests-utils
 
diff --git a/apct-tests/perftests/autofill/AndroidManifest.xml b/apct-tests/perftests/autofill/AndroidManifest.xml
index e706a32..9c8abc3 100644
--- a/apct-tests/perftests/autofill/AndroidManifest.xml
+++ b/apct-tests/perftests/autofill/AndroidManifest.xml
@@ -35,6 +35,6 @@
 
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.perftests.autofill"/>
 </manifest>
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java b/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
index 86a5c10..6979f0f 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
@@ -16,34 +16,23 @@
 
 package android.view.autofill;
 
+import static org.junit.Assert.assertTrue;
+
 import android.os.Looper;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.SettingsHelper;
 import android.perftests.utils.SettingsStateKeeperRule;
-import android.perftests.utils.ShellHelper;
-import android.view.View;
 import android.perftests.utils.StubActivity;
 import android.provider.Settings;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.InstrumentationRegistry;
 
-import com.android.perftests.autofill.R;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
 
-import java.util.Locale;
-import java.util.Collection;
-import java.util.Arrays;
-
-import org.junit.Test;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.assertTrue;
 
 /**
  * Base class for all autofill tests.
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java b/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
index 62662e4..8090826 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
@@ -16,34 +16,18 @@
 
 package android.view.autofill;
 
-import android.app.Activity;
-import android.os.Looper;
-import android.os.Bundle;
-import android.perftests.utils.PerfStatusReporter;
-import android.util.Log;
-import android.view.View;
-import android.widget.EditText;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.StubActivity;
-import android.provider.Settings;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.InstrumentationRegistry;
-import com.android.perftests.autofill.R;
-
-import java.util.Locale;
-import java.util.Collection;
-import java.util.Arrays;
-
-import org.junit.Test;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.runner.RunWith;
-
 import static android.view.autofill.AutofillManager.AutofillCallback.EVENT_INPUT_HIDDEN;
 import static android.view.autofill.AutofillManager.AutofillCallback.EVENT_INPUT_SHOWN;
 
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.StubActivity;
+import android.view.View;
+import android.widget.EditText;
+
+import com.android.perftests.autofill.R;
+
+import org.junit.Test;
+
 public class LoginTest extends AbstractAutofillPerfTestCase {
 
     private EditText mUsername;
diff --git a/apct-tests/perftests/core/Android.mk b/apct-tests/perftests/core/Android.mk
index 77bacbe..3f87a1c 100644
--- a/apct-tests/perftests/core/Android.mk
+++ b/apct-tests/perftests/core/Android.mk
@@ -9,7 +9,7 @@
   src/android/os/ISomeService.aidl
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-test \
+    androidx.test.rules \
     androidx.annotation_annotation \
     apct-perftests-utils \
     guava
diff --git a/apct-tests/perftests/core/AndroidManifest.xml b/apct-tests/perftests/core/AndroidManifest.xml
index 13c24d9..a564a4d 100644
--- a/apct-tests/perftests/core/AndroidManifest.xml
+++ b/apct-tests/perftests/core/AndroidManifest.xml
@@ -28,7 +28,7 @@
 
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.perftests.core"/>
 
 </manifest>
diff --git a/apct-tests/perftests/core/src/android/accounts/AccountManagerPerfTest.java b/apct-tests/perftests/core/src/android/accounts/AccountManagerPerfTest.java
index b9411fa..e455e6a 100644
--- a/apct-tests/perftests/core/src/android/accounts/AccountManagerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/accounts/AccountManagerPerfTest.java
@@ -23,10 +23,10 @@
 import android.content.pm.PackageManager;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java b/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java
index f8fd51d..b3f8359 100644
--- a/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java
+++ b/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java
@@ -21,9 +21,10 @@
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.StubActivity;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -33,7 +34,6 @@
 // Due to b/71353150, you might get "java.lang.AssertionError: Binder ProxyMap has too many
 // entries", but it's flaky. Adding "Runtime.getRuntime().gc()" between each iteration solves
 // the problem, but it doesn't seem like it's currently needed.
-
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class PendingIntentPerfTest {
diff --git a/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java
index 9cdeb48..c3e43ee 100644
--- a/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java
+++ b/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java
@@ -23,7 +23,8 @@
 import android.content.res.XmlResourceParser;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java
index bb0627e..1b07572 100644
--- a/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java
+++ b/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java
@@ -19,8 +19,9 @@
 import android.content.res.Resources;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/database/CursorWindowPerfTest.java b/apct-tests/perftests/core/src/android/database/CursorWindowPerfTest.java
index 897d0ae..c5ef80d 100644
--- a/apct-tests/perftests/core/src/android/database/CursorWindowPerfTest.java
+++ b/apct-tests/perftests/core/src/android/database/CursorWindowPerfTest.java
@@ -23,9 +23,10 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
diff --git a/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java b/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java
index 7c5316d..830302e 100644
--- a/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java
+++ b/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java
@@ -16,17 +16,20 @@
 
 package android.database;
 
+import static org.junit.Assert.assertEquals;
+
 import android.app.Activity;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.sqlite.SQLiteDatabase;
 import android.os.Bundle;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.util.Preconditions;
 
 import org.junit.After;
@@ -40,8 +43,6 @@
 import java.util.List;
 import java.util.Map;
 
-import static org.junit.Assert.assertEquals;
-
 /**
  * Performance tests for measuring amount of data written during typical DB operations
  *
diff --git a/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java b/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java
index e2b75c3..973e996 100644
--- a/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java
+++ b/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java
@@ -16,14 +16,18 @@
 
 package android.database;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.sqlite.SQLiteDatabase;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
@@ -33,9 +37,6 @@
 
 import java.util.Random;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
 /**
  * Performance tests for typical CRUD operations and loading rows into the Cursor
  *
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
index c742df3..9f09305 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
@@ -24,7 +24,8 @@
 import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java
index f9c3758..10a5128 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/OutlinePerfTest.java
@@ -19,7 +19,8 @@
 import android.graphics.Outline;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java
index 26b8309..3a80020 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java
@@ -20,17 +20,18 @@
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.StubActivity;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
 
-import java.util.Arrays;
-import java.util.Collection;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
 
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized.Parameters;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.Collection;
 
 @LargeTest
 @RunWith(Parameterized.class)
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java
index b9ee613..fc8c673 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/PaintMeasureTextTest.java
@@ -19,9 +19,10 @@
 import android.graphics.Canvas;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
 import android.text.TextPaint;
 
+import androidx.test.filters.LargeTest;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/PathPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/PathPerfTest.java
index 7a49b4f..c6de9ec 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/PathPerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/PathPerfTest.java
@@ -20,7 +20,8 @@
 import android.graphics.RectF;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
index 62dd124..e7fe235 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/RenderNodePerfTest.java
@@ -20,7 +20,8 @@
 import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
index 11ee599..d6e8ab2 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
@@ -21,9 +21,14 @@
 import android.graphics.Typeface;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -31,10 +36,6 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class TypefaceCreatePerfTest {
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java
index 5533782..3b2b8a9 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java
@@ -16,6 +16,8 @@
 
 package android.graphics.perftests;
 
+import static junit.framework.Assert.assertTrue;
+
 import android.app.Activity;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -25,21 +27,17 @@
 import android.perftests.utils.BitmapUtils;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.StubActivity;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.LargeTest;
 
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.perftests.core.R;
 
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.IOException;
-
-import static junit.framework.Assert.assertTrue;
-
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class VectorDrawablePerfTest {
diff --git a/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java
index 99e4ba1..12e49e3 100644
--- a/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java
@@ -18,8 +18,9 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.os.BinderCallsStats;
 import com.android.internal.os.BinderInternal.CallSession;
@@ -31,7 +32,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-
 /**
  * Performance tests for {@link BinderCallsStats}
  */
diff --git a/apct-tests/perftests/core/src/android/os/CpuUsageTrackingPerfTest.java b/apct-tests/perftests/core/src/android/os/CpuUsageTrackingPerfTest.java
index 4961b4f..0d7b7ca 100644
--- a/apct-tests/perftests/core/src/android/os/CpuUsageTrackingPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/CpuUsageTrackingPerfTest.java
@@ -18,8 +18,9 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -28,7 +29,6 @@
 import java.nio.file.Files;
 import java.nio.file.Paths;
 
-
 /**
  * Performance tests collecting CPU data different mechanisms.
  */
diff --git a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
index 9034034..11c7599 100644
--- a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
@@ -20,8 +20,9 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.os.KernelCpuThreadReader;
 
@@ -29,7 +30,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-
 /**
  * Performance tests collecting per-thread CPU data.
  */
diff --git a/apct-tests/perftests/core/src/android/os/LooperStatsPerfTest.java b/apct-tests/perftests/core/src/android/os/LooperStatsPerfTest.java
index 0f880b7..162167d 100644
--- a/apct-tests/perftests/core/src/android/os/LooperStatsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/LooperStatsPerfTest.java
@@ -19,8 +19,9 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.os.CachedDeviceState;
 import com.android.internal.os.LooperStats;
@@ -31,7 +32,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-
 /**
  * Performance tests for {@link LooperStats}.
  */
diff --git a/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java b/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java
index 145fbcd..3aa6749 100644
--- a/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java
@@ -16,20 +16,16 @@
 
 package android.os;
 
-import static android.content.pm.PackageManager.PERMISSION_DENIED;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 
-import org.junit.Assert;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/apct-tests/perftests/core/src/android/os/ParcelArrayPerfTest.java b/apct-tests/perftests/core/src/android/os/ParcelArrayPerfTest.java
index a67aeca..af6d6b0 100644
--- a/apct-tests/perftests/core/src/android/os/ParcelArrayPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/ParcelArrayPerfTest.java
@@ -18,7 +18,8 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java b/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
index 6e4c9c5..4db9262 100644
--- a/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
@@ -16,10 +16,15 @@
 
 package android.os;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
@@ -27,10 +32,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ParcelPerfTest {
diff --git a/apct-tests/perftests/core/src/android/os/PssPerfTest.java b/apct-tests/perftests/core/src/android/os/PssPerfTest.java
index 400115d..2cc294f 100644
--- a/apct-tests/perftests/core/src/android/os/PssPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/PssPerfTest.java
@@ -18,8 +18,9 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/os/SharedPreferencesTest.java b/apct-tests/perftests/core/src/android/os/SharedPreferencesTest.java
index 099134f..dd479ac 100644
--- a/apct-tests/perftests/core/src/android/os/SharedPreferencesTest.java
+++ b/apct-tests/perftests/core/src/android/os/SharedPreferencesTest.java
@@ -20,9 +20,10 @@
 import android.content.SharedPreferences;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/os/StrictModeTest.java b/apct-tests/perftests/core/src/android/os/StrictModeTest.java
index d973c20..60678e9 100644
--- a/apct-tests/perftests/core/src/android/os/StrictModeTest.java
+++ b/apct-tests/perftests/core/src/android/os/StrictModeTest.java
@@ -23,17 +23,21 @@
 import android.net.Uri;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.google.common.util.concurrent.SettableFuture;
-import java.io.File;
-import java.io.IOException;
-import java.util.concurrent.ExecutionException;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class StrictModeTest {
diff --git a/apct-tests/perftests/core/src/android/os/TracePerfTest.java b/apct-tests/perftests/core/src/android/os/TracePerfTest.java
index 8e5cfaa..0d64c39 100644
--- a/apct-tests/perftests/core/src/android/os/TracePerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/TracePerfTest.java
@@ -20,7 +20,8 @@
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.ShellHelper;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.AfterClass;
 import org.junit.Assert;
diff --git a/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java b/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java
index 95a7144..4f0d108 100644
--- a/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java
+++ b/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java
@@ -18,8 +18,9 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import dalvik.annotation.optimization.FastNative;
 
diff --git a/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java
index 9245c1b..c8121c5 100644
--- a/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java
@@ -22,9 +22,10 @@
 import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
 import android.text.NonEditableTextGenerator.TextType;
 
+import androidx.test.filters.LargeTest;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java b/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java
index 194a88c..ad1327c 100644
--- a/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java
@@ -18,9 +18,10 @@
 import android.graphics.Canvas;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
 import android.text.NonEditableTextGenerator.TextType;
 
+import androidx.test.filters.LargeTest;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java b/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
index ad9fb5f..bb6b691 100644
--- a/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
+++ b/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
@@ -19,8 +19,9 @@
 import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java
index b4c7f54..5be99d9 100644
--- a/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java
@@ -24,11 +24,12 @@
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.StubActivity;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
 import android.text.style.ReplacementSpan;
 import android.util.ArraySet;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java
index a7972f5..bbe75b7 100644
--- a/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java
@@ -21,7 +21,8 @@
 import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java b/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java
index 00a6267..4ae2b93 100644
--- a/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java
+++ b/apct-tests/perftests/core/src/android/text/PrecomputedTextMemoryUsageTest.java
@@ -18,9 +18,10 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java b/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java
index 33b1a47..3be9114 100644
--- a/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/PrecomputedTextPerfTest.java
@@ -18,8 +18,9 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java
index b40dd6b..6c92229 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java
@@ -22,9 +22,10 @@
 import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
 import android.text.NonEditableTextGenerator.TextType;
 
+import androidx.test.filters.LargeTest;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutGetOffsetForHorizontalPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutGetOffsetForHorizontalPerfTest.java
index 2768a7d..47e04ef 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutGetOffsetForHorizontalPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutGetOffsetForHorizontalPerfTest.java
@@ -19,8 +19,8 @@
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutMultithreadPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutMultithreadPerfTest.java
index 60c6d89..0b79834 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutMultithreadPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutMultithreadPerfTest.java
@@ -19,17 +19,16 @@
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.Random;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 @LargeTest
 @RunWith(AndroidJUnit4.class)
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index f60cbee..bd7522d 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -21,8 +21,9 @@
 import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java b/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java
index 25cc707..10bfa42 100644
--- a/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java
@@ -23,11 +23,12 @@
 import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
 import android.text.NonEditableTextGenerator.TextType;
 import android.widget.TextView;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java b/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java
index a482c4a..a7a81f2 100644
--- a/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java
+++ b/apct-tests/perftests/core/src/android/textclassifier/TextClassifierPerfTest.java
@@ -18,13 +18,14 @@
 import android.content.Context;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
 import android.view.textclassifier.ConversationActions;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textclassifier.TextClassifier;
 import android.view.textclassifier.TextLanguage;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java b/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java
index 0c1f289..b24bf42 100644
--- a/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java
+++ b/apct-tests/perftests/core/src/android/util/ArraySetPerfTest.java
@@ -18,8 +18,9 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/util/perftests/LogPerfTest.java b/apct-tests/perftests/core/src/android/util/perftests/LogPerfTest.java
index 07cd33f..26cec95 100644
--- a/apct-tests/perftests/core/src/android/util/perftests/LogPerfTest.java
+++ b/apct-tests/perftests/core/src/android/util/perftests/LogPerfTest.java
@@ -18,11 +18,11 @@
 
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
index 990be24..a1f8608 100644
--- a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
+++ b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
@@ -17,13 +17,13 @@
 package android.view;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
 import android.widget.FrameLayout;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
 import com.android.perftests.core.R;
 
 import org.junit.Rule;
diff --git a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java
index dc4d4bd..b34001d 100644
--- a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java
+++ b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java
@@ -24,14 +24,15 @@
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.StubActivity;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
 import android.view.View.MeasureSpec;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java
index d219d3a..b3ea62a 100644
--- a/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java
@@ -19,14 +19,15 @@
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.StubActivity;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
 import android.text.Selection;
 import android.view.KeyEvent;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java
index b6cf7d3..aa47d5b 100644
--- a/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java
@@ -19,14 +19,15 @@
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.StubActivity;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
 import android.text.Selection;
 import android.view.KeyEvent;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java
index ce0c357..e50016c 100644
--- a/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java
@@ -16,10 +16,16 @@
 
 package android.widget;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Locale;
-import java.util.Random;
+import android.app.Activity;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.perftests.utils.StubActivity;
+import android.view.KeyEvent;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -27,22 +33,9 @@
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
 
-import android.app.Activity;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.RenderNodeAnimator;
-import android.view.ViewGroup;
-import android.view.View.MeasureSpec;
-
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
-import android.perftests.utils.StubActivity;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.InstrumentationRegistry;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Random;
 
 @LargeTest
 @RunWith(Parameterized.class)
diff --git a/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java
index d570ef3..644095b 100644
--- a/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java
@@ -16,17 +16,26 @@
 
 package android.widget;
 
+import static android.perftests.utils.LayoutUtils.gatherViewTree;
+import static android.perftests.utils.LayoutUtils.requestLayoutForAllNodes;
+import static android.view.View.MeasureSpec.AT_MOST;
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.UNSPECIFIED;
+
+import static org.junit.Assert.assertTrue;
+
 import android.app.Activity;
 import android.os.Looper;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.StubActivity;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+
 import com.android.perftests.core.R;
 
 import org.junit.Rule;
@@ -38,13 +47,6 @@
 import java.util.Collection;
 import java.util.List;
 
-import static android.perftests.utils.LayoutUtils.gatherViewTree;
-import static android.perftests.utils.LayoutUtils.requestLayoutForAllNodes;
-import static android.view.View.MeasureSpec.AT_MOST;
-import static android.view.View.MeasureSpec.EXACTLY;
-import static android.view.View.MeasureSpec.UNSPECIFIED;
-import static org.junit.Assert.assertTrue;
-
 @LargeTest
 @RunWith(Parameterized.class)
 public class LayoutPerfTest {
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java
index c310166..bed173b 100644
--- a/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java
@@ -16,33 +16,27 @@
 
 package android.widget;
 
+import static org.junit.Assert.assertTrue;
+
 import android.app.Activity;
 import android.os.Looper;
-import android.os.Bundle;
-import android.perftests.utils.PerfStatusReporter;
-import android.util.Log;
-import android.view.View;
-
 import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.StubActivity;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.InstrumentationRegistry;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
 
 import com.android.perftests.core.R;
 
-import java.util.Locale;
-import java.util.Collection;
-import java.util.Arrays;
-
-import org.junit.Test;
 import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
-import org.junit.runner.RunWith;
 
-import static org.junit.Assert.assertTrue;
+import java.util.Arrays;
+import java.util.Collection;
 
 @LargeTest
 @RunWith(Parameterized.class)
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewFontFamilyLayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewFontFamilyLayoutPerfTest.java
index 4b6da6b..1f00838 100644
--- a/apct-tests/perftests/core/src/android/widget/TextViewFontFamilyLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/TextViewFontFamilyLayoutPerfTest.java
@@ -19,23 +19,21 @@
 import android.content.Context;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.LayoutInflater;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
 import com.android.perftests.core.R;
 
-import java.util.Collection;
-import java.util.Arrays;
-
-import org.junit.Test;
 import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
-import org.junit.runner.RunWith;
 
-import static org.junit.Assert.assertTrue;
+import java.util.Arrays;
+import java.util.Collection;
 
 @LargeTest
 @RunWith(Parameterized.class)
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewOnMeasurePerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewOnMeasurePerfTest.java
index a14dd25..88acbba 100644
--- a/apct-tests/perftests/core/src/android/widget/TextViewOnMeasurePerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/TextViewOnMeasurePerfTest.java
@@ -25,24 +25,20 @@
 import android.graphics.Typeface;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.style.TextAppearanceSpan;
-import android.view.LayoutInflater;
 
-import com.android.perftests.core.R;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
-import java.util.Random;
-import java.util.Locale;
-
-import org.junit.Test;
 import org.junit.Rule;
+import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static org.junit.Assert.assertTrue;
+import java.util.Locale;
+import java.util.Random;
 
 @LargeTest
 @RunWith(AndroidJUnit4.class)
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
index bd91112..0bc9ee4 100644
--- a/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/TextViewPrecomputedTextPerfTest.java
@@ -24,9 +24,6 @@
 import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.BoringLayout;
 import android.text.Layout;
 import android.text.PrecomputedText;
@@ -34,6 +31,10 @@
 import android.text.TextPerfUtils;
 import android.view.View.MeasureSpec;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java
index e95676b..00bd8db 100644
--- a/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java
@@ -19,8 +19,9 @@
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.StubActivity;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/apct-tests/perftests/utils/Android.mk b/apct-tests/perftests/utils/Android.mk
index 604f0ad..19f83c8 100644
--- a/apct-tests/perftests/utils/Android.mk
+++ b/apct-tests/perftests/utils/Android.mk
@@ -2,7 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-test \
+    androidx.test.rules \
     androidx.annotation_annotation
 
 # Build all java files in the java subdirectory
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
index da17818..93bf541 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
@@ -20,9 +20,10 @@
 import android.app.Instrumentation;
 import android.os.Bundle;
 import android.os.Debug;
-import android.support.test.InstrumentationRegistry;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+
 import java.io.File;
 import java.util.ArrayList;
 import java.util.concurrent.TimeUnit;
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java b/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java
index 0de6f1d..8187c6f 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java
@@ -16,7 +16,7 @@
 
 package android.perftests.utils;
 
-import android.support.test.InstrumentationRegistry;
+import androidx.test.InstrumentationRegistry;
 
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/PerfStatusReporter.java b/apct-tests/perftests/utils/src/android/perftests/utils/PerfStatusReporter.java
index 4b7b98d..d54a851 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/PerfStatusReporter.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/PerfStatusReporter.java
@@ -16,16 +16,17 @@
 
 package android.perftests.utils;
 
-import android.support.test.InstrumentationRegistry;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
 /**
  * Use this rule to make sure we report the status after the test success.
  *
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java b/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java
index 895547d..7b52576 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java
@@ -17,14 +17,13 @@
 
 import android.app.UiAutomation;
 import android.os.ParcelFileDescriptor;
-import android.support.test.InstrumentationRegistry;
 import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
-import android.util.Log;
-
-import java.io.FileInputStream;
 
 import androidx.annotation.NonNull;
+import androidx.test.InstrumentationRegistry;
+
+import java.io.FileInputStream;
 
 /**
  * Provides Shell-based utilities such as running a command.
diff --git a/api/current.txt b/api/current.txt
index fad607c..912d52e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1,3 +1,4 @@
+// Signature format: 2.0
 package android {
 
   public final class Manifest {
@@ -6,183 +7,183 @@
 
   public static final class Manifest.permission {
     ctor public Manifest.permission();
-    field public static final java.lang.String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER";
-    field public static final java.lang.String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION";
-    field public static final java.lang.String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
-    field public static final java.lang.String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
-    field public static final java.lang.String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
-    field public static final java.lang.String ACCESS_LOCATION_EXTRA_COMMANDS = "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS";
-    field public static final java.lang.String ACCESS_MEDIA_LOCATION = "android.permission.ACCESS_MEDIA_LOCATION";
-    field public static final java.lang.String ACCESS_NETWORK_STATE = "android.permission.ACCESS_NETWORK_STATE";
-    field public static final java.lang.String ACCESS_NOTIFICATION_POLICY = "android.permission.ACCESS_NOTIFICATION_POLICY";
-    field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
-    field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
-    field public static final java.lang.String ACTIVITY_RECOGNITION = "android.permission.ACTIVITY_RECOGNITION";
-    field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
-    field public static final java.lang.String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
-    field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
-    field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
-    field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
-    field public static final java.lang.String BIND_AUTOFILL_SERVICE = "android.permission.BIND_AUTOFILL_SERVICE";
-    field public static final java.lang.String BIND_CALL_REDIRECTION_SERVICE = "android.permission.BIND_CALL_REDIRECTION_SERVICE";
-    field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
-    field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
-    field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
-    field public static final java.lang.String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
-    field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
-    field public static final java.lang.String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
-    field public static final java.lang.String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
-    field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
-    field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
-    field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
-    field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
-    field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
-    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";
-    field public static final java.lang.String BIND_VISUAL_VOICEMAIL_SERVICE = "android.permission.BIND_VISUAL_VOICEMAIL_SERVICE";
-    field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
-    field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
-    field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
-    field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
-    field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
-    field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
-    field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
-    field public static final java.lang.String BODY_SENSORS = "android.permission.BODY_SENSORS";
-    field public static final java.lang.String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
-    field public static final java.lang.String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
-    field public static final java.lang.String BROADCAST_STICKY = "android.permission.BROADCAST_STICKY";
-    field public static final java.lang.String BROADCAST_WAP_PUSH = "android.permission.BROADCAST_WAP_PUSH";
-    field public static final java.lang.String CALL_COMPANION_APP = "android.permission.CALL_COMPANION_APP";
-    field public static final java.lang.String CALL_PHONE = "android.permission.CALL_PHONE";
-    field public static final java.lang.String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED";
-    field public static final java.lang.String CAMERA = "android.permission.CAMERA";
-    field public static final java.lang.String CAPTURE_AUDIO_OUTPUT = "android.permission.CAPTURE_AUDIO_OUTPUT";
-    field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
-    field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
-    field public static final java.lang.String CHANGE_NETWORK_STATE = "android.permission.CHANGE_NETWORK_STATE";
-    field public static final java.lang.String CHANGE_WIFI_MULTICAST_STATE = "android.permission.CHANGE_WIFI_MULTICAST_STATE";
-    field public static final java.lang.String CHANGE_WIFI_STATE = "android.permission.CHANGE_WIFI_STATE";
-    field public static final java.lang.String CLEAR_APP_CACHE = "android.permission.CLEAR_APP_CACHE";
-    field public static final java.lang.String CONTROL_LOCATION_UPDATES = "android.permission.CONTROL_LOCATION_UPDATES";
-    field public static final java.lang.String DELETE_CACHE_FILES = "android.permission.DELETE_CACHE_FILES";
-    field public static final java.lang.String DELETE_PACKAGES = "android.permission.DELETE_PACKAGES";
-    field public static final java.lang.String DIAGNOSTIC = "android.permission.DIAGNOSTIC";
-    field public static final java.lang.String DISABLE_KEYGUARD = "android.permission.DISABLE_KEYGUARD";
-    field public static final java.lang.String DUMP = "android.permission.DUMP";
-    field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
-    field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
-    field public static final java.lang.String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE";
-    field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
-    field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
-    field public static final java.lang.String GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY = "android.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY";
-    field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
-    field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
-    field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
-    field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
-    field public static final java.lang.String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
-    field public static final java.lang.String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
-    field public static final java.lang.String INSTANT_APP_FOREGROUND_SERVICE = "android.permission.INSTANT_APP_FOREGROUND_SERVICE";
-    field public static final java.lang.String INTERNET = "android.permission.INTERNET";
-    field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
-    field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
-    field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
-    field public static final java.lang.String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
-    field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
-    field public static final java.lang.String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
-    field public static final java.lang.String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
-    field public static final java.lang.String MODIFY_PHONE_STATE = "android.permission.MODIFY_PHONE_STATE";
-    field public static final java.lang.String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
-    field public static final java.lang.String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
-    field public static final java.lang.String NFC = "android.permission.NFC";
-    field public static final java.lang.String NFC_TRANSACTION_EVENT = "android.permission.NFC_TRANSACTION_EVENT";
-    field public static final java.lang.String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
-    field public static final deprecated java.lang.String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
-    field public static final java.lang.String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
-    field public static final java.lang.String READ_CALENDAR = "android.permission.READ_CALENDAR";
-    field public static final java.lang.String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
-    field public static final java.lang.String READ_CONTACTS = "android.permission.READ_CONTACTS";
-    field public static final deprecated java.lang.String READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE";
-    field public static final deprecated java.lang.String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
-    field public static final java.lang.String READ_LOGS = "android.permission.READ_LOGS";
-    field public static final java.lang.String READ_MEDIA_AUDIO = "android.permission.READ_MEDIA_AUDIO";
-    field public static final java.lang.String READ_MEDIA_IMAGES = "android.permission.READ_MEDIA_IMAGES";
-    field public static final java.lang.String READ_MEDIA_VIDEO = "android.permission.READ_MEDIA_VIDEO";
-    field public static final java.lang.String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS";
-    field public static final java.lang.String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
-    field public static final java.lang.String READ_SMS = "android.permission.READ_SMS";
-    field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
-    field public static final java.lang.String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
-    field public static final java.lang.String READ_VOICEMAIL = "com.android.voicemail.permission.READ_VOICEMAIL";
-    field public static final java.lang.String REBOOT = "android.permission.REBOOT";
-    field public static final java.lang.String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED";
-    field public static final java.lang.String RECEIVE_MMS = "android.permission.RECEIVE_MMS";
-    field public static final java.lang.String RECEIVE_SMS = "android.permission.RECEIVE_SMS";
-    field public static final java.lang.String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
-    field public static final java.lang.String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
-    field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS";
-    field public static final java.lang.String REQUEST_COMPANION_RUN_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
-    field public static final java.lang.String REQUEST_COMPANION_USE_DATA_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND";
-    field public static final java.lang.String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
-    field public static final java.lang.String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
-    field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
-    field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
-    field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
-    field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
-    field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
-    field public static final java.lang.String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH";
-    field public static final java.lang.String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
-    field public static final java.lang.String SET_DEBUG_APP = "android.permission.SET_DEBUG_APP";
-    field public static final deprecated java.lang.String SET_PREFERRED_APPLICATIONS = "android.permission.SET_PREFERRED_APPLICATIONS";
-    field public static final java.lang.String SET_PROCESS_LIMIT = "android.permission.SET_PROCESS_LIMIT";
-    field public static final java.lang.String SET_TIME = "android.permission.SET_TIME";
-    field public static final java.lang.String SET_TIME_ZONE = "android.permission.SET_TIME_ZONE";
-    field public static final java.lang.String SET_WALLPAPER = "android.permission.SET_WALLPAPER";
-    field public static final java.lang.String SET_WALLPAPER_HINTS = "android.permission.SET_WALLPAPER_HINTS";
-    field public static final java.lang.String SIGNAL_PERSISTENT_PROCESSES = "android.permission.SIGNAL_PERSISTENT_PROCESSES";
-    field public static final java.lang.String SMS_FINANCIAL_TRANSACTIONS = "android.permission.SMS_FINANCIAL_TRANSACTIONS";
-    field public static final java.lang.String STATUS_BAR = "android.permission.STATUS_BAR";
-    field public static final java.lang.String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
-    field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
-    field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
-    field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
-    field public static final java.lang.String USE_BIOMETRIC = "android.permission.USE_BIOMETRIC";
-    field public static final deprecated java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
-    field public static final java.lang.String USE_FULL_SCREEN_INTENT = "android.permission.USE_FULL_SCREEN_INTENT";
-    field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
-    field public static final java.lang.String VIBRATE = "android.permission.VIBRATE";
-    field public static final java.lang.String WAKE_LOCK = "android.permission.WAKE_LOCK";
-    field public static final java.lang.String WRITE_APN_SETTINGS = "android.permission.WRITE_APN_SETTINGS";
-    field public static final java.lang.String WRITE_CALENDAR = "android.permission.WRITE_CALENDAR";
-    field public static final java.lang.String WRITE_CALL_LOG = "android.permission.WRITE_CALL_LOG";
-    field public static final java.lang.String WRITE_CONTACTS = "android.permission.WRITE_CONTACTS";
-    field public static final deprecated java.lang.String WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE";
-    field public static final java.lang.String WRITE_GSERVICES = "android.permission.WRITE_GSERVICES";
-    field public static final java.lang.String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS";
-    field public static final java.lang.String WRITE_SETTINGS = "android.permission.WRITE_SETTINGS";
-    field public static final java.lang.String WRITE_SYNC_SETTINGS = "android.permission.WRITE_SYNC_SETTINGS";
-    field public static final java.lang.String WRITE_VOICEMAIL = "com.android.voicemail.permission.WRITE_VOICEMAIL";
+    field public static final String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER";
+    field public static final String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION";
+    field public static final String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
+    field public static final String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
+    field public static final String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
+    field public static final String ACCESS_LOCATION_EXTRA_COMMANDS = "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS";
+    field public static final String ACCESS_MEDIA_LOCATION = "android.permission.ACCESS_MEDIA_LOCATION";
+    field public static final String ACCESS_NETWORK_STATE = "android.permission.ACCESS_NETWORK_STATE";
+    field public static final String ACCESS_NOTIFICATION_POLICY = "android.permission.ACCESS_NOTIFICATION_POLICY";
+    field public static final String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
+    field public static final String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
+    field public static final String ACTIVITY_RECOGNITION = "android.permission.ACTIVITY_RECOGNITION";
+    field public static final String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
+    field public static final String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
+    field public static final String BATTERY_STATS = "android.permission.BATTERY_STATS";
+    field public static final String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
+    field public static final String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+    field public static final String BIND_AUTOFILL_SERVICE = "android.permission.BIND_AUTOFILL_SERVICE";
+    field public static final String BIND_CALL_REDIRECTION_SERVICE = "android.permission.BIND_CALL_REDIRECTION_SERVICE";
+    field @Deprecated public static final String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
+    field public static final String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
+    field public static final String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
+    field public static final String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
+    field public static final String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
+    field public static final String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
+    field public static final String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
+    field public static final String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
+    field public static final String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
+    field public static final String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
+    field public static final String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
+    field public static final String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
+    field public static final String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
+    field public static final String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
+    field public static final String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
+    field public static final String BIND_SMS_APP_SERVICE = "android.permission.BIND_SMS_APP_SERVICE";
+    field public static final String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
+    field public static final String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
+    field public static final String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
+    field public static final String BIND_VISUAL_VOICEMAIL_SERVICE = "android.permission.BIND_VISUAL_VOICEMAIL_SERVICE";
+    field public static final String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
+    field public static final String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
+    field public static final String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
+    field public static final String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
+    field public static final String BLUETOOTH = "android.permission.BLUETOOTH";
+    field public static final String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
+    field public static final String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
+    field public static final String BODY_SENSORS = "android.permission.BODY_SENSORS";
+    field public static final String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
+    field public static final String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
+    field public static final String BROADCAST_STICKY = "android.permission.BROADCAST_STICKY";
+    field public static final String BROADCAST_WAP_PUSH = "android.permission.BROADCAST_WAP_PUSH";
+    field public static final String CALL_COMPANION_APP = "android.permission.CALL_COMPANION_APP";
+    field public static final String CALL_PHONE = "android.permission.CALL_PHONE";
+    field public static final String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED";
+    field public static final String CAMERA = "android.permission.CAMERA";
+    field public static final String CAPTURE_AUDIO_OUTPUT = "android.permission.CAPTURE_AUDIO_OUTPUT";
+    field public static final String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
+    field public static final String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
+    field public static final String CHANGE_NETWORK_STATE = "android.permission.CHANGE_NETWORK_STATE";
+    field public static final String CHANGE_WIFI_MULTICAST_STATE = "android.permission.CHANGE_WIFI_MULTICAST_STATE";
+    field public static final String CHANGE_WIFI_STATE = "android.permission.CHANGE_WIFI_STATE";
+    field public static final String CLEAR_APP_CACHE = "android.permission.CLEAR_APP_CACHE";
+    field public static final String CONTROL_LOCATION_UPDATES = "android.permission.CONTROL_LOCATION_UPDATES";
+    field public static final String DELETE_CACHE_FILES = "android.permission.DELETE_CACHE_FILES";
+    field public static final String DELETE_PACKAGES = "android.permission.DELETE_PACKAGES";
+    field public static final String DIAGNOSTIC = "android.permission.DIAGNOSTIC";
+    field public static final String DISABLE_KEYGUARD = "android.permission.DISABLE_KEYGUARD";
+    field public static final String DUMP = "android.permission.DUMP";
+    field public static final String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
+    field public static final String FACTORY_TEST = "android.permission.FACTORY_TEST";
+    field public static final String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE";
+    field public static final String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
+    field public static final String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
+    field public static final String GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY = "android.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY";
+    field public static final String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+    field @Deprecated public static final String GET_TASKS = "android.permission.GET_TASKS";
+    field public static final String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
+    field public static final String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
+    field public static final String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
+    field public static final String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
+    field public static final String INSTANT_APP_FOREGROUND_SERVICE = "android.permission.INSTANT_APP_FOREGROUND_SERVICE";
+    field public static final String INTERNET = "android.permission.INTERNET";
+    field public static final String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
+    field public static final String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
+    field public static final String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
+    field public static final String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
+    field public static final String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
+    field public static final String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
+    field public static final String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
+    field public static final String MODIFY_PHONE_STATE = "android.permission.MODIFY_PHONE_STATE";
+    field public static final String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
+    field public static final String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
+    field public static final String NFC = "android.permission.NFC";
+    field public static final String NFC_TRANSACTION_EVENT = "android.permission.NFC_TRANSACTION_EVENT";
+    field public static final String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
+    field @Deprecated public static final String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
+    field public static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
+    field public static final String READ_CALENDAR = "android.permission.READ_CALENDAR";
+    field public static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
+    field public static final String READ_CONTACTS = "android.permission.READ_CONTACTS";
+    field @Deprecated public static final String READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE";
+    field @Deprecated public static final String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
+    field public static final String READ_LOGS = "android.permission.READ_LOGS";
+    field public static final String READ_MEDIA_AUDIO = "android.permission.READ_MEDIA_AUDIO";
+    field public static final String READ_MEDIA_IMAGES = "android.permission.READ_MEDIA_IMAGES";
+    field public static final String READ_MEDIA_VIDEO = "android.permission.READ_MEDIA_VIDEO";
+    field public static final String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS";
+    field public static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
+    field public static final String READ_SMS = "android.permission.READ_SMS";
+    field public static final String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
+    field public static final String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
+    field public static final String READ_VOICEMAIL = "com.android.voicemail.permission.READ_VOICEMAIL";
+    field public static final String REBOOT = "android.permission.REBOOT";
+    field public static final String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED";
+    field public static final String RECEIVE_MMS = "android.permission.RECEIVE_MMS";
+    field public static final String RECEIVE_SMS = "android.permission.RECEIVE_SMS";
+    field public static final String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
+    field public static final String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
+    field public static final String REORDER_TASKS = "android.permission.REORDER_TASKS";
+    field public static final String REQUEST_COMPANION_RUN_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
+    field public static final String REQUEST_COMPANION_USE_DATA_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND";
+    field public static final String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
+    field public static final String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+    field public static final String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
+    field @Deprecated public static final String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
+    field public static final String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
+    field public static final String SEND_SMS = "android.permission.SEND_SMS";
+    field public static final String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
+    field public static final String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH";
+    field public static final String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
+    field public static final String SET_DEBUG_APP = "android.permission.SET_DEBUG_APP";
+    field @Deprecated public static final String SET_PREFERRED_APPLICATIONS = "android.permission.SET_PREFERRED_APPLICATIONS";
+    field public static final String SET_PROCESS_LIMIT = "android.permission.SET_PROCESS_LIMIT";
+    field public static final String SET_TIME = "android.permission.SET_TIME";
+    field public static final String SET_TIME_ZONE = "android.permission.SET_TIME_ZONE";
+    field public static final String SET_WALLPAPER = "android.permission.SET_WALLPAPER";
+    field public static final String SET_WALLPAPER_HINTS = "android.permission.SET_WALLPAPER_HINTS";
+    field public static final String SIGNAL_PERSISTENT_PROCESSES = "android.permission.SIGNAL_PERSISTENT_PROCESSES";
+    field public static final String SMS_FINANCIAL_TRANSACTIONS = "android.permission.SMS_FINANCIAL_TRANSACTIONS";
+    field public static final String STATUS_BAR = "android.permission.STATUS_BAR";
+    field public static final String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
+    field public static final String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
+    field public static final String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
+    field public static final String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
+    field public static final String USE_BIOMETRIC = "android.permission.USE_BIOMETRIC";
+    field @Deprecated public static final String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
+    field public static final String USE_FULL_SCREEN_INTENT = "android.permission.USE_FULL_SCREEN_INTENT";
+    field public static final String USE_SIP = "android.permission.USE_SIP";
+    field public static final String VIBRATE = "android.permission.VIBRATE";
+    field public static final String WAKE_LOCK = "android.permission.WAKE_LOCK";
+    field public static final String WRITE_APN_SETTINGS = "android.permission.WRITE_APN_SETTINGS";
+    field public static final String WRITE_CALENDAR = "android.permission.WRITE_CALENDAR";
+    field public static final String WRITE_CALL_LOG = "android.permission.WRITE_CALL_LOG";
+    field public static final String WRITE_CONTACTS = "android.permission.WRITE_CONTACTS";
+    field @Deprecated public static final String WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE";
+    field public static final String WRITE_GSERVICES = "android.permission.WRITE_GSERVICES";
+    field public static final String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS";
+    field public static final String WRITE_SETTINGS = "android.permission.WRITE_SETTINGS";
+    field public static final String WRITE_SYNC_SETTINGS = "android.permission.WRITE_SYNC_SETTINGS";
+    field public static final String WRITE_VOICEMAIL = "com.android.voicemail.permission.WRITE_VOICEMAIL";
   }
 
   public static final class Manifest.permission_group {
     ctor public Manifest.permission_group();
-    field public static final java.lang.String ACTIVITY_RECOGNITION = "android.permission-group.ACTIVITY_RECOGNITION";
-    field public static final java.lang.String CALENDAR = "android.permission-group.CALENDAR";
-    field public static final java.lang.String CALL_LOG = "android.permission-group.CALL_LOG";
-    field public static final java.lang.String CAMERA = "android.permission-group.CAMERA";
-    field public static final java.lang.String CONTACTS = "android.permission-group.CONTACTS";
-    field public static final java.lang.String LOCATION = "android.permission-group.LOCATION";
-    field public static final java.lang.String MEDIA_AURAL = "android.permission-group.MEDIA_AURAL";
-    field public static final java.lang.String MEDIA_VISUAL = "android.permission-group.MEDIA_VISUAL";
-    field public static final java.lang.String MICROPHONE = "android.permission-group.MICROPHONE";
-    field public static final java.lang.String PHONE = "android.permission-group.PHONE";
-    field public static final java.lang.String SENSORS = "android.permission-group.SENSORS";
-    field public static final java.lang.String SMS = "android.permission-group.SMS";
-    field public static final deprecated java.lang.String STORAGE = "android.permission-group.STORAGE";
+    field public static final String ACTIVITY_RECOGNITION = "android.permission-group.ACTIVITY_RECOGNITION";
+    field public static final String CALENDAR = "android.permission-group.CALENDAR";
+    field public static final String CALL_LOG = "android.permission-group.CALL_LOG";
+    field public static final String CAMERA = "android.permission-group.CAMERA";
+    field public static final String CONTACTS = "android.permission-group.CONTACTS";
+    field public static final String LOCATION = "android.permission-group.LOCATION";
+    field public static final String MEDIA_AURAL = "android.permission-group.MEDIA_AURAL";
+    field public static final String MEDIA_VISUAL = "android.permission-group.MEDIA_VISUAL";
+    field public static final String MICROPHONE = "android.permission-group.MICROPHONE";
+    field public static final String PHONE = "android.permission-group.PHONE";
+    field public static final String SENSORS = "android.permission-group.SENSORS";
+    field public static final String SMS = "android.permission-group.SMS";
+    field @Deprecated public static final String STORAGE = "android.permission-group.STORAGE";
   }
 
   public final class R {
@@ -293,8 +294,8 @@
     field public static final int alphabeticShortcut = 16843235; // 0x10101e3
     field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
     field public static final int alwaysRetainTaskState = 16843267; // 0x1010203
-    field public static final deprecated int amPmBackgroundColor = 16843941; // 0x10104a5
-    field public static final deprecated int amPmTextColor = 16843940; // 0x10104a4
+    field @Deprecated public static final int amPmBackgroundColor = 16843941; // 0x10104a5
+    field @Deprecated public static final int amPmTextColor = 16843940; // 0x10104a4
     field public static final int ambientShadowAlpha = 16843966; // 0x10104be
     field public static final int angle = 16843168; // 0x10101a0
     field public static final int animateFirstView = 16843477; // 0x10102d5
@@ -304,7 +305,7 @@
     field public static final int animationCache = 16842989; // 0x10100ed
     field public static final int animationDuration = 16843026; // 0x1010112
     field public static final int animationOrder = 16843214; // 0x10101ce
-    field public static final deprecated int animationResolution = 16843546; // 0x101031a
+    field @Deprecated public static final int animationResolution = 16843546; // 0x101031a
     field public static final int antialias = 16843034; // 0x101011a
     field public static final int anyDensity = 16843372; // 0x101026c
     field public static final int apduServiceBanner = 16843757; // 0x10103ed
@@ -324,7 +325,7 @@
     field public static final int autoSizeStepGranularity = 16844086; // 0x1010536
     field public static final int autoSizeTextType = 16844085; // 0x1010535
     field public static final int autoStart = 16843445; // 0x10102b5
-    field public static final deprecated int autoText = 16843114; // 0x101016a
+    field @Deprecated public static final int autoText = 16843114; // 0x101016a
     field public static final int autoUrlDetect = 16843404; // 0x101028c
     field public static final int autoVerify = 16844014; // 0x10104ee
     field public static final int autofillHints = 16844118; // 0x1010556
@@ -377,14 +378,14 @@
     field public static final int canControlMagnification = 16844039; // 0x1010507
     field public static final int canPerformGestures = 16844045; // 0x101050d
     field public static final int canRecord = 16844060; // 0x101051c
-    field public static final deprecated int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
+    field @Deprecated public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
     field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
     field public static final int canRequestFingerprintGestures = 16844109; // 0x101054d
     field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
     field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
     field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
     field public static final int cantSaveState = 16844142; // 0x101056e
-    field public static final deprecated int capitalize = 16843113; // 0x1010169
+    field @Deprecated public static final int capitalize = 16843113; // 0x1010169
     field public static final int category = 16843752; // 0x10103e8
     field public static final int centerBright = 16842956; // 0x10100cc
     field public static final int centerColor = 16843275; // 0x101020b
@@ -417,7 +418,7 @@
     field public static final int clipOrientation = 16843274; // 0x101020a
     field public static final int clipToPadding = 16842987; // 0x10100eb
     field public static final int closeIcon = 16843905; // 0x1010481
-    field public static final deprecated int codes = 16843330; // 0x1010242
+    field @Deprecated public static final int codes = 16843330; // 0x1010242
     field public static final int collapseColumns = 16843083; // 0x101014b
     field public static final int collapseContentDescription = 16843984; // 0x10104d0
     field public static final int collapseIcon = 16844031; // 0x10104ff
@@ -491,8 +492,8 @@
     field public static final int datePickerMode = 16843955; // 0x10104b3
     field public static final int datePickerStyle = 16843612; // 0x101035c
     field public static final int dateTextAppearance = 16843593; // 0x1010349
-    field public static final deprecated int dayOfWeekBackground = 16843924; // 0x1010494
-    field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
+    field @Deprecated public static final int dayOfWeekBackground = 16843924; // 0x1010494
+    field @Deprecated public static final int dayOfWeekTextAppearance = 16843925; // 0x1010495
     field public static final int debuggable = 16842767; // 0x101000f
     field public static final int defaultFocusHighlightEnabled = 16844130; // 0x1010562
     field public static final int defaultHeight = 16844021; // 0x10104f5
@@ -519,7 +520,7 @@
     field public static final int digits = 16843110; // 0x1010166
     field public static final int directBootAware = 16844037; // 0x1010505
     field public static final int direction = 16843217; // 0x10101d1
-    field public static final deprecated int directionDescriptions = 16843681; // 0x10103a1
+    field @Deprecated public static final int directionDescriptions = 16843681; // 0x10103a1
     field public static final int directionPriority = 16843218; // 0x10101d2
     field public static final int disableDependentsState = 16843249; // 0x10101f1
     field public static final int disabledAlpha = 16842803; // 0x1010033
@@ -559,7 +560,7 @@
     field public static final int editTextColor = 16843601; // 0x1010351
     field public static final int editTextPreferenceStyle = 16842898; // 0x1010092
     field public static final int editTextStyle = 16842862; // 0x101006e
-    field public static final deprecated int editable = 16843115; // 0x101016b
+    field @Deprecated public static final int editable = 16843115; // 0x101016b
     field public static final int editorExtras = 16843300; // 0x1010224
     field public static final int elegantTextHeight = 16843869; // 0x101045d
     field public static final int elevation = 16843840; // 0x1010440
@@ -571,7 +572,7 @@
     field public static final int endColor = 16843166; // 0x101019e
     field public static final int endX = 16844050; // 0x1010512
     field public static final int endY = 16844051; // 0x1010513
-    field public static final deprecated int endYear = 16843133; // 0x101017d
+    field @Deprecated public static final int endYear = 16843133; // 0x101017d
     field public static final int enterFadeDuration = 16843532; // 0x101030c
     field public static final int entries = 16842930; // 0x10100b2
     field public static final int entryValues = 16843256; // 0x10101f8
@@ -630,7 +631,7 @@
     field public static final int focusable = 16842970; // 0x10100da
     field public static final int focusableInTouchMode = 16842971; // 0x10100db
     field public static final int focusedByDefault = 16844100; // 0x1010544
-    field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
+    field @Deprecated public static final int focusedMonthDateColor = 16843587; // 0x1010343
     field public static final int font = 16844082; // 0x1010532
     field public static final int fontFamily = 16843692; // 0x10103ac
     field public static final int fontFeatureSettings = 16843959; // 0x10104b7
@@ -705,20 +706,20 @@
     field public static final int hardwareAccelerated = 16843475; // 0x10102d3
     field public static final int hasCode = 16842764; // 0x101000c
     field public static final int hasFragileUserData = 16844192; // 0x10105a0
-    field public static final deprecated int headerAmPmTextAppearance = 16843936; // 0x10104a0
+    field @Deprecated public static final int headerAmPmTextAppearance = 16843936; // 0x10104a0
     field public static final int headerBackground = 16843055; // 0x101012f
-    field public static final deprecated int headerDayOfMonthTextAppearance = 16843927; // 0x1010497
+    field @Deprecated public static final int headerDayOfMonthTextAppearance = 16843927; // 0x1010497
     field public static final int headerDividersEnabled = 16843310; // 0x101022e
-    field public static final deprecated int headerMonthTextAppearance = 16843926; // 0x1010496
-    field public static final deprecated int headerTimeTextAppearance = 16843935; // 0x101049f
-    field public static final deprecated int headerYearTextAppearance = 16843928; // 0x1010498
+    field @Deprecated public static final int headerMonthTextAppearance = 16843926; // 0x1010496
+    field @Deprecated public static final int headerTimeTextAppearance = 16843935; // 0x101049f
+    field @Deprecated public static final int headerYearTextAppearance = 16843928; // 0x1010498
     field public static final int height = 16843093; // 0x1010155
     field public static final int hideOnContentScroll = 16843843; // 0x1010443
     field public static final int hint = 16843088; // 0x1010150
     field public static final int homeAsUpIndicator = 16843531; // 0x101030b
     field public static final int homeLayout = 16843549; // 0x101031d
     field public static final int horizontalDivider = 16843053; // 0x101012d
-    field public static final deprecated int horizontalGap = 16843327; // 0x101023f
+    field @Deprecated public static final int horizontalGap = 16843327; // 0x101023f
     field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
     field public static final int horizontalSpacing = 16843028; // 0x1010114
     field public static final int host = 16842792; // 0x1010028
@@ -726,7 +727,7 @@
     field public static final int hotSpotY = 16844056; // 0x1010518
     field public static final int hyphenationFrequency = 16843998; // 0x10104de
     field public static final int icon = 16842754; // 0x1010002
-    field public static final deprecated int iconPreview = 16843337; // 0x1010249
+    field @Deprecated public static final int iconPreview = 16843337; // 0x1010249
     field public static final int iconSpaceReserved = 16844129; // 0x1010561
     field public static final int iconTint = 16844126; // 0x101055e
     field public static final int iconTintMode = 16844127; // 0x101055f
@@ -769,7 +770,7 @@
     field public static final int initialLayout = 16843345; // 0x1010251
     field public static final int innerRadius = 16843359; // 0x101025f
     field public static final int innerRadiusRatio = 16843163; // 0x101019b
-    field public static final deprecated int inputMethod = 16843112; // 0x1010168
+    field @Deprecated public static final int inputMethod = 16843112; // 0x1010168
     field public static final int inputType = 16843296; // 0x1010220
     field public static final int inset = 16843957; // 0x10104b5
     field public static final int insetBottom = 16843194; // 0x10101ba
@@ -787,12 +788,12 @@
     field public static final int isGame = 16843764; // 0x10103f4
     field public static final int isIndicator = 16843079; // 0x1010147
     field public static final int isLightTheme = 16844176; // 0x1010590
-    field public static final deprecated int isModifier = 16843334; // 0x1010246
-    field public static final deprecated int isRepeatable = 16843336; // 0x1010248
+    field @Deprecated public static final int isModifier = 16843334; // 0x1010246
+    field @Deprecated public static final int isRepeatable = 16843336; // 0x1010248
     field public static final int isScrollContainer = 16843342; // 0x101024e
     field public static final int isSplitRequired = 16844177; // 0x1010591
     field public static final int isStatic = 16844122; // 0x101055a
-    field public static final deprecated int isSticky = 16843335; // 0x1010247
+    field @Deprecated public static final int isSticky = 16843335; // 0x1010247
     field public static final int isolatedProcess = 16843689; // 0x10103a9
     field public static final int isolatedSplits = 16844107; // 0x101054b
     field public static final int itemBackground = 16843056; // 0x1010130
@@ -802,27 +803,27 @@
     field public static final int justificationMode = 16844135; // 0x1010567
     field public static final int keepScreenOn = 16843286; // 0x1010216
     field public static final int key = 16843240; // 0x10101e8
-    field public static final deprecated int keyBackground = 16843315; // 0x1010233
-    field public static final deprecated int keyEdgeFlags = 16843333; // 0x1010245
-    field public static final deprecated int keyHeight = 16843326; // 0x101023e
-    field public static final deprecated int keyIcon = 16843340; // 0x101024c
-    field public static final deprecated int keyLabel = 16843339; // 0x101024b
-    field public static final deprecated int keyOutputText = 16843338; // 0x101024a
-    field public static final deprecated int keyPreviewHeight = 16843321; // 0x1010239
-    field public static final deprecated int keyPreviewLayout = 16843319; // 0x1010237
-    field public static final deprecated int keyPreviewOffset = 16843320; // 0x1010238
+    field @Deprecated public static final int keyBackground = 16843315; // 0x1010233
+    field @Deprecated public static final int keyEdgeFlags = 16843333; // 0x1010245
+    field @Deprecated public static final int keyHeight = 16843326; // 0x101023e
+    field @Deprecated public static final int keyIcon = 16843340; // 0x101024c
+    field @Deprecated public static final int keyLabel = 16843339; // 0x101024b
+    field @Deprecated public static final int keyOutputText = 16843338; // 0x101024a
+    field @Deprecated public static final int keyPreviewHeight = 16843321; // 0x1010239
+    field @Deprecated public static final int keyPreviewLayout = 16843319; // 0x1010237
+    field @Deprecated public static final int keyPreviewOffset = 16843320; // 0x1010238
     field public static final int keySet = 16843739; // 0x10103db
-    field public static final deprecated int keyTextColor = 16843318; // 0x1010236
-    field public static final deprecated int keyTextSize = 16843316; // 0x1010234
-    field public static final deprecated int keyWidth = 16843325; // 0x101023d
+    field @Deprecated public static final int keyTextColor = 16843318; // 0x1010236
+    field @Deprecated public static final int keyTextSize = 16843316; // 0x1010234
+    field @Deprecated public static final int keyWidth = 16843325; // 0x101023d
     field public static final int keyboardLayout = 16843691; // 0x10103ab
-    field public static final deprecated int keyboardMode = 16843341; // 0x101024d
+    field @Deprecated public static final int keyboardMode = 16843341; // 0x101024d
     field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
     field public static final int keycode = 16842949; // 0x10100c5
     field public static final int killAfterRestore = 16843420; // 0x101029c
     field public static final int label = 16842753; // 0x1010001
     field public static final int labelFor = 16843718; // 0x10103c6
-    field public static final deprecated int labelTextSize = 16843317; // 0x1010235
+    field @Deprecated public static final int labelTextSize = 16843317; // 0x1010235
     field public static final int languageTag = 16844040; // 0x1010508
     field public static final int largeHeap = 16843610; // 0x101035a
     field public static final int largeScreens = 16843398; // 0x1010286
@@ -984,7 +985,7 @@
     field public static final int numbersInnerTextColor = 16844001; // 0x10104e1
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
     field public static final int numbersTextColor = 16843937; // 0x10104a1
-    field public static final deprecated int numeric = 16843109; // 0x1010165
+    field @Deprecated public static final int numeric = 16843109; // 0x1010165
     field public static final int numericModifiers = 16844111; // 0x101054f
     field public static final int numericShortcut = 16843236; // 0x10101e4
     field public static final int offset = 16844052; // 0x1010514
@@ -1027,7 +1028,7 @@
     field public static final int panelFullBackground = 16842847; // 0x101005f
     field public static final int panelTextAppearance = 16842850; // 0x1010062
     field public static final int parentActivityName = 16843687; // 0x10103a7
-    field public static final deprecated int password = 16843100; // 0x101015c
+    field @Deprecated public static final int password = 16843100; // 0x101015c
     field public static final int path = 16842794; // 0x101002a
     field public static final int pathData = 16843781; // 0x1010405
     field public static final int pathPattern = 16842796; // 0x101002c
@@ -1041,18 +1042,18 @@
     field public static final int persistent = 16842765; // 0x101000d
     field public static final int persistentDrawingCache = 16842990; // 0x10100ee
     field public static final int persistentWhenFeatureAvailable = 16844131; // 0x1010563
-    field public static final deprecated int phoneNumber = 16843111; // 0x1010167
+    field @Deprecated public static final int phoneNumber = 16843111; // 0x1010167
     field public static final int pivotX = 16843189; // 0x10101b5
     field public static final int pivotY = 16843190; // 0x10101b6
     field public static final int pointerIcon = 16844041; // 0x1010509
     field public static final int popupAnimationStyle = 16843465; // 0x10102c9
     field public static final int popupBackground = 16843126; // 0x1010176
-    field public static final deprecated int popupCharacters = 16843332; // 0x1010244
+    field @Deprecated public static final int popupCharacters = 16843332; // 0x1010244
     field public static final int popupElevation = 16843916; // 0x101048c
     field public static final int popupEnterTransition = 16844063; // 0x101051f
     field public static final int popupExitTransition = 16844064; // 0x1010520
-    field public static final deprecated int popupKeyboard = 16843331; // 0x1010243
-    field public static final deprecated int popupLayout = 16843323; // 0x101023b
+    field @Deprecated public static final int popupKeyboard = 16843331; // 0x1010243
+    field @Deprecated public static final int popupLayout = 16843323; // 0x101023b
     field public static final int popupMenuStyle = 16843520; // 0x1010300
     field public static final int popupTheme = 16843945; // 0x10104a9
     field public static final int popupWindowStyle = 16842870; // 0x1010076
@@ -1135,7 +1136,7 @@
     field public static final int resizeableActivity = 16844022; // 0x10104f6
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
-    field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
+    field @Deprecated public static final int restoreNeedsApplication = 16843421; // 0x101029d
     field public static final int restrictedAccountType = 16843733; // 0x10103d5
     field public static final int restrictionType = 16843923; // 0x1010493
     field public static final int resumeWhilePausing = 16843954; // 0x10104b2
@@ -1151,7 +1152,7 @@
     field public static final int roundIcon = 16844076; // 0x101052c
     field public static final int rowCount = 16843637; // 0x1010375
     field public static final int rowDelay = 16843216; // 0x10101d0
-    field public static final deprecated int rowEdgeFlags = 16843329; // 0x1010241
+    field @Deprecated public static final int rowEdgeFlags = 16843329; // 0x1010241
     field public static final int rowHeight = 16843058; // 0x1010132
     field public static final int rowOrderPreserved = 16843638; // 0x1010376
     field public static final int saveEnabled = 16842983; // 0x10100e7
@@ -1183,7 +1184,7 @@
     field public static final int scrollbarTrackVertical = 16842855; // 0x1010067
     field public static final int scrollbars = 16842974; // 0x10100de
     field public static final int scrollingCache = 16843006; // 0x10100fe
-    field public static final deprecated int searchButtonText = 16843269; // 0x1010205
+    field @Deprecated public static final int searchButtonText = 16843269; // 0x1010205
     field public static final int searchHintIcon = 16843988; // 0x10104d4
     field public static final int searchIcon = 16843907; // 0x1010483
     field public static final int searchMode = 16843221; // 0x10101d5
@@ -1205,8 +1206,8 @@
     field public static final int selectable = 16843238; // 0x10101e6
     field public static final int selectableItemBackground = 16843534; // 0x101030e
     field public static final int selectableItemBackgroundBorderless = 16843868; // 0x101045c
-    field public static final deprecated int selectedDateVerticalBar = 16843591; // 0x1010347
-    field public static final deprecated int selectedWeekBackgroundColor = 16843586; // 0x1010342
+    field @Deprecated public static final int selectedDateVerticalBar = 16843591; // 0x1010347
+    field @Deprecated public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342
     field public static final int selectionDividerHeight = 16844190; // 0x101059e
     field public static final int sessionService = 16843837; // 0x101043d
     field public static final int settingsActivity = 16843301; // 0x1010225
@@ -1231,14 +1232,14 @@
     field public static final int showDividers = 16843561; // 0x1010329
     field public static final int showForAllUsers = 16844015; // 0x10104ef
     field public static final int showMetadataInPreview = 16844079; // 0x101052f
-    field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
+    field @Deprecated public static final int showOnLockScreen = 16843721; // 0x10103c9
     field public static final int showSilent = 16843259; // 0x10101fb
     field public static final int showText = 16843949; // 0x10104ad
-    field public static final deprecated int showWeekNumber = 16843582; // 0x101033e
+    field @Deprecated public static final int showWeekNumber = 16843582; // 0x101033e
     field public static final int showWhenLocked = 16844137; // 0x1010569
-    field public static final deprecated int shownWeekCount = 16843585; // 0x1010341
+    field @Deprecated public static final int shownWeekCount = 16843585; // 0x1010341
     field public static final int shrinkColumns = 16843082; // 0x101014a
-    field public static final deprecated int singleLine = 16843101; // 0x101015d
+    field @Deprecated public static final int singleLine = 16843101; // 0x101015d
     field public static final int singleLineTitle = 16844124; // 0x101055c
     field public static final int singleUser = 16843711; // 0x10103bf
     field public static final int slideEdge = 16843824; // 0x1010430
@@ -1269,7 +1270,7 @@
     field public static final int startOffset = 16843198; // 0x10101be
     field public static final int startX = 16844048; // 0x1010510
     field public static final int startY = 16844049; // 0x1010511
-    field public static final deprecated int startYear = 16843132; // 0x101017c
+    field @Deprecated public static final int startYear = 16843132; // 0x101017c
     field public static final int stateListAnimator = 16843848; // 0x1010448
     field public static final int stateNotNeeded = 16842774; // 0x1010016
     field public static final int state_above_anchor = 16842922; // 0x10100aa
@@ -1287,7 +1288,7 @@
     field public static final int state_focused = 16842908; // 0x101009c
     field public static final int state_hovered = 16843623; // 0x1010367
     field public static final int state_last = 16842918; // 0x10100a6
-    field public static final deprecated int state_long_pressable = 16843324; // 0x101023c
+    field @Deprecated public static final int state_long_pressable = 16843324; // 0x101023c
     field public static final int state_middle = 16842917; // 0x10100a5
     field public static final int state_multiline = 16843597; // 0x101034d
     field public static final int state_pressed = 16842919; // 0x10100a7
@@ -1346,12 +1347,12 @@
     field public static final int tag = 16842961; // 0x10100d1
     field public static final int targetActivity = 16843266; // 0x1010202
     field public static final int targetClass = 16842799; // 0x101002f
-    field public static final deprecated int targetDescriptions = 16843680; // 0x10103a0
+    field @Deprecated public static final int targetDescriptions = 16843680; // 0x10103a0
     field public static final int targetId = 16843740; // 0x10103dc
     field public static final int targetName = 16843853; // 0x101044d
     field public static final int targetPackage = 16842785; // 0x1010021
     field public static final int targetProcesses = 16844097; // 0x1010541
-    field public static final deprecated int targetSandboxVersion = 16844108; // 0x101054c
+    field @Deprecated public static final int targetSandboxVersion = 16844108; // 0x101054c
     field public static final int targetSdkVersion = 16843376; // 0x1010270
     field public static final int taskAffinity = 16842770; // 0x1010012
     field public static final int taskCloseEnterAnimation = 16842942; // 0x10100be
@@ -1503,7 +1504,7 @@
     field public static final int typeface = 16842902; // 0x1010096
     field public static final int uiOptions = 16843672; // 0x1010398
     field public static final int uncertainGestureColor = 16843382; // 0x1010276
-    field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
+    field @Deprecated public static final int unfocusedMonthDateColor = 16843588; // 0x1010344
     field public static final int unselectedAlpha = 16843278; // 0x101020e
     field public static final int updatePeriodMillis = 16843344; // 0x1010250
     field public static final int usageInfoRequired = 16844185; // 0x1010599
@@ -1525,9 +1526,9 @@
     field public static final int versionCodeMajor = 16844150; // 0x1010576
     field public static final int versionMajor = 16844151; // 0x1010577
     field public static final int versionName = 16843292; // 0x101021c
-    field public static final deprecated int verticalCorrection = 16843322; // 0x101023a
+    field @Deprecated public static final int verticalCorrection = 16843322; // 0x101023a
     field public static final int verticalDivider = 16843054; // 0x101012e
-    field public static final deprecated int verticalGap = 16843328; // 0x1010240
+    field @Deprecated public static final int verticalGap = 16843328; // 0x1010240
     field public static final int verticalScrollbarPosition = 16843572; // 0x1010334
     field public static final int verticalSpacing = 16843029; // 0x1010115
     field public static final int viewportHeight = 16843779; // 0x1010403
@@ -1553,8 +1554,8 @@
     field public static final int webTextViewStyle = 16843449; // 0x10102b9
     field public static final int webViewStyle = 16842885; // 0x1010085
     field public static final int weekDayTextAppearance = 16843592; // 0x1010348
-    field public static final deprecated int weekNumberColor = 16843589; // 0x1010345
-    field public static final deprecated int weekSeparatorLineColor = 16843590; // 0x1010346
+    field @Deprecated public static final int weekNumberColor = 16843589; // 0x1010345
+    field @Deprecated public static final int weekSeparatorLineColor = 16843590; // 0x1010346
     field public static final int weightSum = 16843048; // 0x1010128
     field public static final int widgetCategory = 16843716; // 0x10103c4
     field public static final int widgetFeatures = 16844153; // 0x1010579
@@ -1617,8 +1618,8 @@
     field public static final int x = 16842924; // 0x10100ac
     field public static final int xlargeScreens = 16843455; // 0x10102bf
     field public static final int y = 16842925; // 0x10100ad
-    field public static final deprecated int yearListItemTextAppearance = 16843929; // 0x1010499
-    field public static final deprecated int yearListSelectorColor = 16843930; // 0x101049a
+    field @Deprecated public static final int yearListItemTextAppearance = 16843929; // 0x1010499
+    field @Deprecated public static final int yearListSelectorColor = 16843930; // 0x101049a
     field public static final int yesNoPreferenceStyle = 16842896; // 0x1010090
     field public static final int zAdjustment = 16843201; // 0x10101c1
   }
@@ -1643,17 +1644,17 @@
     field public static final int holo_purple = 17170458; // 0x106001a
     field public static final int holo_red_dark = 17170455; // 0x1060017
     field public static final int holo_red_light = 17170454; // 0x1060016
-    field public static final deprecated int primary_text_dark = 17170433; // 0x1060001
-    field public static final deprecated int primary_text_dark_nodisable = 17170434; // 0x1060002
-    field public static final deprecated int primary_text_light = 17170435; // 0x1060003
-    field public static final deprecated int primary_text_light_nodisable = 17170436; // 0x1060004
-    field public static final deprecated int secondary_text_dark = 17170437; // 0x1060005
-    field public static final deprecated int secondary_text_dark_nodisable = 17170438; // 0x1060006
-    field public static final deprecated int secondary_text_light = 17170439; // 0x1060007
-    field public static final deprecated int secondary_text_light_nodisable = 17170440; // 0x1060008
+    field @Deprecated public static final int primary_text_dark = 17170433; // 0x1060001
+    field @Deprecated public static final int primary_text_dark_nodisable = 17170434; // 0x1060002
+    field @Deprecated public static final int primary_text_light = 17170435; // 0x1060003
+    field @Deprecated public static final int primary_text_light_nodisable = 17170436; // 0x1060004
+    field @Deprecated public static final int secondary_text_dark = 17170437; // 0x1060005
+    field @Deprecated public static final int secondary_text_dark_nodisable = 17170438; // 0x1060006
+    field @Deprecated public static final int secondary_text_light = 17170439; // 0x1060007
+    field @Deprecated public static final int secondary_text_light_nodisable = 17170440; // 0x1060008
     field public static final int tab_indicator_text = 17170441; // 0x1060009
-    field public static final deprecated int tertiary_text_dark = 17170448; // 0x1060010
-    field public static final deprecated int tertiary_text_light = 17170449; // 0x1060011
+    field @Deprecated public static final int tertiary_text_dark = 17170448; // 0x1060010
+    field @Deprecated public static final int tertiary_text_light = 17170449; // 0x1060011
     field public static final int transparent = 17170445; // 0x106000d
     field public static final int white = 17170443; // 0x106000b
     field public static final int widget_edittext_dark = 17170442; // 0x106000a
@@ -1823,14 +1824,14 @@
     field public static final int stat_sys_download = 17301633; // 0x1080081
     field public static final int stat_sys_download_done = 17301634; // 0x1080082
     field public static final int stat_sys_headset = 17301635; // 0x1080083
-    field public static final deprecated int stat_sys_phone_call = 17301636; // 0x1080084
-    field public static final deprecated int stat_sys_phone_call_forward = 17301637; // 0x1080085
-    field public static final deprecated int stat_sys_phone_call_on_hold = 17301638; // 0x1080086
+    field @Deprecated public static final int stat_sys_phone_call = 17301636; // 0x1080084
+    field @Deprecated public static final int stat_sys_phone_call_forward = 17301637; // 0x1080085
+    field @Deprecated public static final int stat_sys_phone_call_on_hold = 17301638; // 0x1080086
     field public static final int stat_sys_speakerphone = 17301639; // 0x1080087
     field public static final int stat_sys_upload = 17301640; // 0x1080088
     field public static final int stat_sys_upload_done = 17301641; // 0x1080089
-    field public static final deprecated int stat_sys_vp_phone_call = 17301671; // 0x10800a7
-    field public static final deprecated int stat_sys_vp_phone_call_on_hold = 17301672; // 0x10800a8
+    field @Deprecated public static final int stat_sys_vp_phone_call = 17301671; // 0x10800a7
+    field @Deprecated public static final int stat_sys_vp_phone_call_on_hold = 17301672; // 0x10800a8
     field public static final int stat_sys_warning = 17301642; // 0x108008a
     field public static final int status_bar_item_app_background = 17301643; // 0x108008b
     field public static final int status_bar_item_background = 17301644; // 0x108008c
@@ -1895,7 +1896,7 @@
     field public static final int input = 16908297; // 0x1020009
     field public static final int inputArea = 16908318; // 0x102001e
     field public static final int inputExtractEditText = 16908325; // 0x1020025
-    field public static final deprecated int keyboardView = 16908326; // 0x1020026
+    field @Deprecated public static final int keyboardView = 16908326; // 0x1020026
     field public static final int list = 16908298; // 0x102000a
     field public static final int list_container = 16908351; // 0x102003f
     field public static final int mask = 16908334; // 0x102002e
@@ -2077,13 +2078,13 @@
     field public static final int TextAppearance_DeviceDefault_Widget = 16974265; // 0x10301b9
     field public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Menu = 16974286; // 0x10301ce
     field public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Subtitle = 16974279; // 0x10301c7
-    field public static final deprecated int TextAppearance_DeviceDefault_Widget_ActionBar_Subtitle_Inverse = 16974283; // 0x10301cb
+    field @Deprecated public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Subtitle_Inverse = 16974283; // 0x10301cb
     field public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Title = 16974278; // 0x10301c6
-    field public static final deprecated int TextAppearance_DeviceDefault_Widget_ActionBar_Title_Inverse = 16974282; // 0x10301ca
+    field @Deprecated public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Title_Inverse = 16974282; // 0x10301ca
     field public static final int TextAppearance_DeviceDefault_Widget_ActionMode_Subtitle = 16974281; // 0x10301c9
-    field public static final deprecated int TextAppearance_DeviceDefault_Widget_ActionMode_Subtitle_Inverse = 16974285; // 0x10301cd
+    field @Deprecated public static final int TextAppearance_DeviceDefault_Widget_ActionMode_Subtitle_Inverse = 16974285; // 0x10301cd
     field public static final int TextAppearance_DeviceDefault_Widget_ActionMode_Title = 16974280; // 0x10301c8
-    field public static final deprecated int TextAppearance_DeviceDefault_Widget_ActionMode_Title_Inverse = 16974284; // 0x10301cc
+    field @Deprecated public static final int TextAppearance_DeviceDefault_Widget_ActionMode_Title_Inverse = 16974284; // 0x10301cc
     field public static final int TextAppearance_DeviceDefault_Widget_Button = 16974266; // 0x10301ba
     field public static final int TextAppearance_DeviceDefault_Widget_DropDownHint = 16974271; // 0x10301bf
     field public static final int TextAppearance_DeviceDefault_Widget_DropDownItem = 16974272; // 0x10301c0
@@ -2260,34 +2261,34 @@
     field public static final int Theme_DeviceDefault_Wallpaper = 16974140; // 0x103013c
     field public static final int Theme_DeviceDefault_Wallpaper_NoTitleBar = 16974141; // 0x103013d
     field public static final int Theme_Dialog = 16973835; // 0x103000b
-    field public static final deprecated int Theme_Holo = 16973931; // 0x103006b
-    field public static final deprecated int Theme_Holo_Dialog = 16973935; // 0x103006f
-    field public static final deprecated int Theme_Holo_DialogWhenLarge = 16973943; // 0x1030077
-    field public static final deprecated int Theme_Holo_DialogWhenLarge_NoActionBar = 16973944; // 0x1030078
-    field public static final deprecated int Theme_Holo_Dialog_MinWidth = 16973936; // 0x1030070
-    field public static final deprecated int Theme_Holo_Dialog_NoActionBar = 16973937; // 0x1030071
-    field public static final deprecated int Theme_Holo_Dialog_NoActionBar_MinWidth = 16973938; // 0x1030072
-    field public static final deprecated int Theme_Holo_InputMethod = 16973951; // 0x103007f
-    field public static final deprecated int Theme_Holo_Light = 16973934; // 0x103006e
-    field public static final deprecated int Theme_Holo_Light_DarkActionBar = 16974105; // 0x1030119
-    field public static final deprecated int Theme_Holo_Light_Dialog = 16973939; // 0x1030073
-    field public static final deprecated int Theme_Holo_Light_DialogWhenLarge = 16973945; // 0x1030079
-    field public static final deprecated int Theme_Holo_Light_DialogWhenLarge_NoActionBar = 16973946; // 0x103007a
-    field public static final deprecated int Theme_Holo_Light_Dialog_MinWidth = 16973940; // 0x1030074
-    field public static final deprecated int Theme_Holo_Light_Dialog_NoActionBar = 16973941; // 0x1030075
-    field public static final deprecated int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076
-    field public static final deprecated int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
-    field public static final deprecated int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
-    field public static final deprecated int Theme_Holo_Light_NoActionBar_Overscan = 16974302; // 0x10301de
-    field public static final deprecated int Theme_Holo_Light_NoActionBar_TranslucentDecor = 16974306; // 0x10301e2
-    field public static final deprecated int Theme_Holo_Light_Panel = 16973948; // 0x103007c
-    field public static final deprecated int Theme_Holo_NoActionBar = 16973932; // 0x103006c
-    field public static final deprecated int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
-    field public static final deprecated int Theme_Holo_NoActionBar_Overscan = 16974301; // 0x10301dd
-    field public static final deprecated int Theme_Holo_NoActionBar_TranslucentDecor = 16974305; // 0x10301e1
-    field public static final deprecated int Theme_Holo_Panel = 16973947; // 0x103007b
-    field public static final deprecated int Theme_Holo_Wallpaper = 16973949; // 0x103007d
-    field public static final deprecated int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
+    field @Deprecated public static final int Theme_Holo = 16973931; // 0x103006b
+    field @Deprecated public static final int Theme_Holo_Dialog = 16973935; // 0x103006f
+    field @Deprecated public static final int Theme_Holo_DialogWhenLarge = 16973943; // 0x1030077
+    field @Deprecated public static final int Theme_Holo_DialogWhenLarge_NoActionBar = 16973944; // 0x1030078
+    field @Deprecated public static final int Theme_Holo_Dialog_MinWidth = 16973936; // 0x1030070
+    field @Deprecated public static final int Theme_Holo_Dialog_NoActionBar = 16973937; // 0x1030071
+    field @Deprecated public static final int Theme_Holo_Dialog_NoActionBar_MinWidth = 16973938; // 0x1030072
+    field @Deprecated public static final int Theme_Holo_InputMethod = 16973951; // 0x103007f
+    field @Deprecated public static final int Theme_Holo_Light = 16973934; // 0x103006e
+    field @Deprecated public static final int Theme_Holo_Light_DarkActionBar = 16974105; // 0x1030119
+    field @Deprecated public static final int Theme_Holo_Light_Dialog = 16973939; // 0x1030073
+    field @Deprecated public static final int Theme_Holo_Light_DialogWhenLarge = 16973945; // 0x1030079
+    field @Deprecated public static final int Theme_Holo_Light_DialogWhenLarge_NoActionBar = 16973946; // 0x103007a
+    field @Deprecated public static final int Theme_Holo_Light_Dialog_MinWidth = 16973940; // 0x1030074
+    field @Deprecated public static final int Theme_Holo_Light_Dialog_NoActionBar = 16973941; // 0x1030075
+    field @Deprecated public static final int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076
+    field @Deprecated public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
+    field @Deprecated public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
+    field @Deprecated public static final int Theme_Holo_Light_NoActionBar_Overscan = 16974302; // 0x10301de
+    field @Deprecated public static final int Theme_Holo_Light_NoActionBar_TranslucentDecor = 16974306; // 0x10301e2
+    field @Deprecated public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
+    field @Deprecated public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
+    field @Deprecated public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
+    field @Deprecated public static final int Theme_Holo_NoActionBar_Overscan = 16974301; // 0x10301dd
+    field @Deprecated public static final int Theme_Holo_NoActionBar_TranslucentDecor = 16974305; // 0x10301e1
+    field @Deprecated public static final int Theme_Holo_Panel = 16973947; // 0x103007b
+    field @Deprecated public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
+    field @Deprecated public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
     field public static final int Theme_InputMethod = 16973908; // 0x1030054
     field public static final int Theme_Light = 16973836; // 0x103000c
     field public static final int Theme_Light_NoTitleBar = 16973837; // 0x103000d
@@ -2401,18 +2402,18 @@
     field public static final int Widget_DeviceDefault_Light = 16974196; // 0x1030174
     field public static final int Widget_DeviceDefault_Light_ActionBar = 16974243; // 0x10301a3
     field public static final int Widget_DeviceDefault_Light_ActionBar_Solid = 16974247; // 0x10301a7
-    field public static final deprecated int Widget_DeviceDefault_Light_ActionBar_Solid_Inverse = 16974248; // 0x10301a8
+    field @Deprecated public static final int Widget_DeviceDefault_Light_ActionBar_Solid_Inverse = 16974248; // 0x10301a8
     field public static final int Widget_DeviceDefault_Light_ActionBar_TabBar = 16974246; // 0x10301a6
-    field public static final deprecated int Widget_DeviceDefault_Light_ActionBar_TabBar_Inverse = 16974249; // 0x10301a9
+    field @Deprecated public static final int Widget_DeviceDefault_Light_ActionBar_TabBar_Inverse = 16974249; // 0x10301a9
     field public static final int Widget_DeviceDefault_Light_ActionBar_TabText = 16974245; // 0x10301a5
-    field public static final deprecated int Widget_DeviceDefault_Light_ActionBar_TabText_Inverse = 16974251; // 0x10301ab
+    field @Deprecated public static final int Widget_DeviceDefault_Light_ActionBar_TabText_Inverse = 16974251; // 0x10301ab
     field public static final int Widget_DeviceDefault_Light_ActionBar_TabView = 16974244; // 0x10301a4
-    field public static final deprecated int Widget_DeviceDefault_Light_ActionBar_TabView_Inverse = 16974250; // 0x10301aa
+    field @Deprecated public static final int Widget_DeviceDefault_Light_ActionBar_TabView_Inverse = 16974250; // 0x10301aa
     field public static final int Widget_DeviceDefault_Light_ActionButton = 16974239; // 0x103019f
     field public static final int Widget_DeviceDefault_Light_ActionButton_CloseMode = 16974242; // 0x10301a2
     field public static final int Widget_DeviceDefault_Light_ActionButton_Overflow = 16974240; // 0x10301a0
     field public static final int Widget_DeviceDefault_Light_ActionMode = 16974241; // 0x10301a1
-    field public static final deprecated int Widget_DeviceDefault_Light_ActionMode_Inverse = 16974252; // 0x10301ac
+    field @Deprecated public static final int Widget_DeviceDefault_Light_ActionMode_Inverse = 16974252; // 0x10301ac
     field public static final int Widget_DeviceDefault_Light_AutoCompleteTextView = 16974203; // 0x103017b
     field public static final int Widget_DeviceDefault_Light_Button = 16974197; // 0x1030175
     field public static final int Widget_DeviceDefault_Light_Button_Borderless_Small = 16974201; // 0x1030179
@@ -2606,7 +2607,7 @@
     field public static final int Widget_Holo_WebView = 16973993; // 0x10300a9
     field public static final int Widget_ImageButton = 16973862; // 0x1030026
     field public static final int Widget_ImageWell = 16973861; // 0x1030025
-    field public static final deprecated int Widget_KeyboardView = 16973911; // 0x1030057
+    field @Deprecated public static final int Widget_KeyboardView = 16973911; // 0x1030057
     field public static final int Widget_ListPopupWindow = 16973957; // 0x1030085
     field public static final int Widget_ListView = 16973870; // 0x103002e
     field public static final int Widget_ListView_DropDown = 16973872; // 0x1030030
@@ -2795,12 +2796,12 @@
 
   public final class AccessibilityButtonController {
     method public boolean isAccessibilityButtonAvailable();
-    method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
-    method public void registerAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback, android.os.Handler);
-    method public void unregisterAccessibilityButtonCallback(android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+    method public void registerAccessibilityButtonCallback(@NonNull android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
+    method public void registerAccessibilityButtonCallback(@NonNull android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback, @NonNull android.os.Handler);
+    method public void unregisterAccessibilityButtonCallback(@NonNull android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback);
   }
 
-  public static abstract class AccessibilityButtonController.AccessibilityButtonCallback {
+  public abstract static class AccessibilityButtonController.AccessibilityButtonCallback {
     ctor public AccessibilityButtonController.AccessibilityButtonCallback();
     method public void onAvailabilityChanged(android.accessibilityservice.AccessibilityButtonController, boolean);
     method public void onClicked(android.accessibilityservice.AccessibilityButtonController);
@@ -2809,14 +2810,14 @@
   public abstract class AccessibilityService extends android.app.Service {
     ctor public AccessibilityService();
     method public final void disableSelf();
-    method public final boolean dispatchGesture(android.accessibilityservice.GestureDescription, android.accessibilityservice.AccessibilityService.GestureResultCallback, android.os.Handler);
+    method public final boolean dispatchGesture(@NonNull android.accessibilityservice.GestureDescription, @Nullable android.accessibilityservice.AccessibilityService.GestureResultCallback, @Nullable android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
-    method public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
-    method public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
-    method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
+    method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
+    method @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) @NonNull public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
+    method @NonNull public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
-    method public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
+    method @NonNull public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
     method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
     method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public final android.os.IBinder onBind(android.content.Intent);
@@ -2851,70 +2852,70 @@
     field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
     field public static final int GLOBAL_ACTION_TAKE_SCREENSHOT = 9; // 0x9
     field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
-    field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
-    field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
+    field public static final String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
+    field public static final String SERVICE_META_DATA = "android.accessibilityservice";
     field public static final int SHOW_MODE_AUTO = 0; // 0x0
     field public static final int SHOW_MODE_HIDDEN = 1; // 0x1
     field public static final int SHOW_MODE_IGNORE_HARD_KEYBOARD = 2; // 0x2
   }
 
-  public static abstract class AccessibilityService.GestureResultCallback {
+  public abstract static class AccessibilityService.GestureResultCallback {
     ctor public AccessibilityService.GestureResultCallback();
     method public void onCancelled(android.accessibilityservice.GestureDescription);
     method public void onCompleted(android.accessibilityservice.GestureDescription);
   }
 
   public static final class AccessibilityService.MagnificationController {
-    method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
-    method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler);
+    method public void addListener(@NonNull android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
+    method public void addListener(@NonNull android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, @Nullable android.os.Handler);
     method public float getCenterX();
     method public float getCenterY();
-    method public android.graphics.Region getMagnificationRegion();
+    method @NonNull public android.graphics.Region getMagnificationRegion();
     method public float getScale();
-    method public boolean removeListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
+    method public boolean removeListener(@NonNull android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
     method public boolean reset(boolean);
     method public boolean setCenter(float, float, boolean);
     method public boolean setScale(float, boolean);
   }
 
-  public static abstract interface AccessibilityService.MagnificationController.OnMagnificationChangedListener {
-    method public abstract void onMagnificationChanged(android.accessibilityservice.AccessibilityService.MagnificationController, android.graphics.Region, float, float, float);
+  public static interface AccessibilityService.MagnificationController.OnMagnificationChangedListener {
+    method public void onMagnificationChanged(@NonNull android.accessibilityservice.AccessibilityService.MagnificationController, @NonNull android.graphics.Region, float, float, float);
   }
 
   public static final class AccessibilityService.SoftKeyboardController {
-    method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
-    method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, android.os.Handler);
+    method public void addOnShowModeChangedListener(@NonNull android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+    method public void addOnShowModeChangedListener(@NonNull android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, @Nullable android.os.Handler);
     method public int getShowMode();
-    method public boolean removeOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+    method public boolean removeOnShowModeChangedListener(@NonNull android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
     method public boolean setShowMode(int);
   }
 
-  public static abstract interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
-    method public abstract void onShowModeChanged(android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
+  public static interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
+    method public void onShowModeChanged(@NonNull android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
   }
 
   public class AccessibilityServiceInfo implements android.os.Parcelable {
     ctor public AccessibilityServiceInfo();
-    method public static java.lang.String capabilityToString(int);
+    method public static String capabilityToString(int);
     method public int describeContents();
-    method public static java.lang.String feedbackTypeToString(int);
-    method public static java.lang.String flagToString(int);
-    method public deprecated boolean getCanRetrieveWindowContent();
+    method public static String feedbackTypeToString(int);
+    method public static String flagToString(int);
+    method @Deprecated public boolean getCanRetrieveWindowContent();
     method public int getCapabilities();
-    method public deprecated java.lang.String getDescription();
-    method public java.lang.String getId();
+    method @Deprecated public String getDescription();
+    method public String getId();
     method public int getInteractiveUiTimeoutMillis();
     method public int getNonInteractiveUiTimeoutMillis();
     method public android.content.pm.ResolveInfo getResolveInfo();
-    method public java.lang.String getSettingsActivityName();
-    method public java.lang.String loadDescription(android.content.pm.PackageManager);
-    method public java.lang.CharSequence loadSummary(android.content.pm.PackageManager);
-    method public void setInteractiveUiTimeoutMillis(int);
-    method public void setNonInteractiveUiTimeoutMillis(int);
+    method public String getSettingsActivityName();
+    method public String loadDescription(android.content.pm.PackageManager);
+    method public CharSequence loadSummary(android.content.pm.PackageManager);
+    method public void setInteractiveUiTimeoutMillis(@IntRange(from=0) int);
+    method public void setNonInteractiveUiTimeoutMillis(@IntRange(from=0) int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
     field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
-    field public static final deprecated int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+    field @Deprecated public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
     field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8
     field public static final int CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES = 64; // 0x40
     field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
@@ -2932,7 +2933,7 @@
     field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
     field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
     field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100
-    field public static final deprecated int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+    field @Deprecated public static final 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
@@ -2942,12 +2943,12 @@
     field public int feedbackType;
     field public int flags;
     field public long notificationTimeout;
-    field public java.lang.String[] packageNames;
+    field public String[] packageNames;
   }
 
   public final class FingerprintGestureController {
     method public boolean isGestureDetectionAvailable();
-    method public void registerFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback, android.os.Handler);
+    method public void registerFingerprintGestureCallback(@NonNull android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback, @Nullable android.os.Handler);
     method public void unregisterFingerprintGestureCallback(android.accessibilityservice.FingerprintGestureController.FingerprintGestureCallback);
     field public static final int FINGERPRINT_GESTURE_SWIPE_DOWN = 8; // 0x8
     field public static final int FINGERPRINT_GESTURE_SWIPE_LEFT = 2; // 0x2
@@ -2955,7 +2956,7 @@
     field public static final int FINGERPRINT_GESTURE_SWIPE_UP = 4; // 0x4
   }
 
-  public static abstract class FingerprintGestureController.FingerprintGestureCallback {
+  public abstract static class FingerprintGestureController.FingerprintGestureCallback {
     ctor public FingerprintGestureController.FingerprintGestureCallback();
     method public void onGestureDetected(int);
     method public void onGestureDetectionAvailabilityChanged(boolean);
@@ -2964,19 +2965,19 @@
   public final class GestureDescription {
     method public static long getMaxGestureDuration();
     method public static int getMaxStrokeCount();
-    method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(int);
+    method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(@IntRange(from=0) int);
     method public int getStrokeCount();
   }
 
   public static class GestureDescription.Builder {
     ctor public GestureDescription.Builder();
-    method public android.accessibilityservice.GestureDescription.Builder addStroke(android.accessibilityservice.GestureDescription.StrokeDescription);
+    method public android.accessibilityservice.GestureDescription.Builder addStroke(@NonNull android.accessibilityservice.GestureDescription.StrokeDescription);
     method public android.accessibilityservice.GestureDescription build();
   }
 
   public static class GestureDescription.StrokeDescription {
-    ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long);
-    ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long, boolean);
+    ctor public GestureDescription.StrokeDescription(@NonNull android.graphics.Path, @IntRange(from=0) long, @IntRange(from=0) long);
+    ctor public GestureDescription.StrokeDescription(@NonNull android.graphics.Path, @IntRange(from=0) long, @IntRange(from=0) long, boolean);
     method public android.accessibilityservice.GestureDescription.StrokeDescription continueStroke(android.graphics.Path, long, long, boolean);
     method public long getDuration();
     method public android.graphics.Path getPath();
@@ -2990,32 +2991,32 @@
 
   public abstract class AbstractAccountAuthenticator {
     ctor public AbstractAccountAuthenticator(android.content.Context);
-    method public abstract android.os.Bundle addAccount(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
+    method public abstract android.os.Bundle addAccount(android.accounts.AccountAuthenticatorResponse, String, String, String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle addAccountFromCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle confirmCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public abstract android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, java.lang.String);
-    method public android.os.Bundle finishSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
+    method public abstract android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, String);
+    method public android.os.Bundle finishSession(android.accounts.AccountAuthenticatorResponse, String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle getAccountCredentialsForCloning(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle getAccountRemovalAllowed(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
-    method public abstract android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public abstract java.lang.String getAuthTokenLabel(java.lang.String);
+    method public abstract android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, String, android.os.Bundle) throws android.accounts.NetworkErrorException;
+    method public abstract String getAuthTokenLabel(String);
     method public final android.os.IBinder getIBinder();
-    method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle isCredentialsUpdateSuggested(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle startAddAccountSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle startUpdateCredentialsSession(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
-    field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
+    method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, String[]) throws android.accounts.NetworkErrorException;
+    method public android.os.Bundle isCredentialsUpdateSuggested(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, String) throws android.accounts.NetworkErrorException;
+    method public android.os.Bundle startAddAccountSession(android.accounts.AccountAuthenticatorResponse, String, String, String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
+    method public android.os.Bundle startUpdateCredentialsSession(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, String, android.os.Bundle) throws android.accounts.NetworkErrorException;
+    method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, String, android.os.Bundle) throws android.accounts.NetworkErrorException;
+    field public static final String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
   }
 
   public class Account implements android.os.Parcelable {
-    ctor public Account(java.lang.String, java.lang.String);
+    ctor public Account(String, String);
     ctor public Account(android.os.Parcel);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.accounts.Account> CREATOR;
-    field public final java.lang.String name;
-    field public final java.lang.String type;
+    field public final String name;
+    field public final String type;
   }
 
   public class AccountAuthenticatorActivity extends android.app.Activity {
@@ -3026,7 +3027,7 @@
   public class AccountAuthenticatorResponse implements android.os.Parcelable {
     ctor public AccountAuthenticatorResponse(android.os.Parcel);
     method public int describeContents();
-    method public void onError(int, java.lang.String);
+    method public void onError(int, String);
     method public void onRequestContinued();
     method public void onResult(android.os.Bundle);
     method public void writeToParcel(android.os.Parcel, int);
@@ -3034,55 +3035,55 @@
   }
 
   public class AccountManager {
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
-    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.String, java.lang.Integer>);
-    method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
-    method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean, java.lang.String[]);
-    method public java.lang.String blockingGetAuthToken(android.accounts.Account, java.lang.String, boolean) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
-    method public void clearPassword(android.accounts.Account);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(java.lang.String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public boolean addAccountExplicitly(android.accounts.Account, String, android.os.Bundle);
+    method public boolean addAccountExplicitly(android.accounts.Account, String, android.os.Bundle, java.util.Map<java.lang.String,java.lang.Integer>);
+    method @RequiresPermission(value="android.permission.GET_ACCOUNTS", apis="..22") public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
+    method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean, String[]);
+    method @RequiresPermission(value="android.permission.USE_CREDENTIALS", apis="..22") public String blockingGetAuthToken(android.accounts.Account, String, boolean) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
+    method @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public void clearPassword(android.accounts.Account);
+    method @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<android.os.Bundle> confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<android.os.Bundle> editProperties(String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public static android.accounts.AccountManager get(android.content.Context);
-    method public int getAccountVisibility(android.accounts.Account, java.lang.String);
-    method public android.accounts.Account[] getAccounts();
-    method public java.util.Map<android.accounts.Account, java.lang.Integer> getAccountsAndVisibilityForPackage(java.lang.String, java.lang.String);
-    method public android.accounts.Account[] getAccountsByType(java.lang.String);
-    method public android.accounts.AccountManagerFuture<android.accounts.Account[]> getAccountsByTypeAndFeatures(java.lang.String, java.lang.String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler);
-    method public android.accounts.Account[] getAccountsByTypeForPackage(java.lang.String, java.lang.String);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public deprecated android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthTokenByFeatures(java.lang.String, java.lang.String, java.lang.String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method public int getAccountVisibility(android.accounts.Account, String);
+    method @NonNull @RequiresPermission(value="android.permission.GET_ACCOUNTS", apis="..22") public android.accounts.Account[] getAccounts();
+    method public java.util.Map<android.accounts.Account,java.lang.Integer> getAccountsAndVisibilityForPackage(String, String);
+    method @NonNull @RequiresPermission(value="android.permission.GET_ACCOUNTS", apis="..22") public android.accounts.Account[] getAccountsByType(String);
+    method public android.accounts.AccountManagerFuture<android.accounts.Account[]> getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler);
+    method @NonNull public android.accounts.Account[] getAccountsByTypeForPackage(String, String);
+    method @RequiresPermission(value="android.permission.USE_CREDENTIALS", apis="..22") public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method @Deprecated @RequiresPermission(value="android.permission.USE_CREDENTIALS", apis="..22") public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method @RequiresPermission(value="android.permission.USE_CREDENTIALS", apis="..22") public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthTokenByFeatures(String, String, String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
-    method public java.util.Map<java.lang.String, java.lang.Integer> getPackagesAndVisibilityForAccount(android.accounts.Account);
-    method public java.lang.String getPassword(android.accounts.Account);
-    method public java.lang.String getPreviousName(android.accounts.Account);
-    method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
-    method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
-    method public void invalidateAuthToken(java.lang.String, java.lang.String);
-    method public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
-    method public static deprecated android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
-    method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.List<android.accounts.Account>, java.lang.String[], java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
-    method public boolean notifyAccountAuthenticated(android.accounts.Account);
-    method public java.lang.String peekAuthToken(android.accounts.Account, java.lang.String);
-    method public deprecated android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public boolean removeAccountExplicitly(android.accounts.Account);
+    method public java.util.Map<java.lang.String,java.lang.Integer> getPackagesAndVisibilityForAccount(android.accounts.Account);
+    method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public String getPassword(android.accounts.Account);
+    method public String getPreviousName(android.accounts.Account);
+    method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public String getUserData(android.accounts.Account, String);
+    method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
+    method @RequiresPermission(anyOf={"android.permission.MANAGE_ACCOUNTS", "android.permission.USE_CREDENTIALS"}, apis="..22") public void invalidateAuthToken(String, String);
+    method public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
+    method @Deprecated public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, String[], boolean, String, String, String[], android.os.Bundle);
+    method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.List<android.accounts.Account>, String[], String, String, String[], android.os.Bundle);
+    method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public boolean notifyAccountAuthenticated(android.accounts.Account);
+    method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public String peekAuthToken(android.accounts.Account, String);
+    method @Deprecated @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
+    method @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public boolean removeAccountExplicitly(android.accounts.Account);
     method public void removeOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener);
-    method public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler);
-    method public boolean setAccountVisibility(android.accounts.Account, java.lang.String, int);
-    method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
-    method public void setPassword(android.accounts.Account, java.lang.String);
-    method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> startUpdateCredentialsSession(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
-    field public static final java.lang.String ACTION_ACCOUNT_REMOVED = "android.accounts.action.ACCOUNT_REMOVED";
-    field public static final java.lang.String ACTION_AUTHENTICATOR_INTENT = "android.accounts.AccountAuthenticator";
-    field public static final java.lang.String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
-    field public static final java.lang.String AUTHENTICATOR_META_DATA_NAME = "android.accounts.AccountAuthenticator";
+    method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, @Size(min=1) String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler);
+    method public boolean setAccountVisibility(android.accounts.Account, String, int);
+    method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public void setAuthToken(android.accounts.Account, String, String);
+    method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public void setPassword(android.accounts.Account, String);
+    method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public void setUserData(android.accounts.Account, String, String);
+    method public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method public android.accounts.AccountManagerFuture<android.os.Bundle> startUpdateCredentialsSession(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    field public static final String ACTION_ACCOUNT_REMOVED = "android.accounts.action.ACCOUNT_REMOVED";
+    field public static final String ACTION_AUTHENTICATOR_INTENT = "android.accounts.AccountAuthenticator";
+    field public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
+    field public static final String AUTHENTICATOR_META_DATA_NAME = "android.accounts.AccountAuthenticator";
     field public static final int ERROR_CODE_BAD_ARGUMENTS = 7; // 0x7
     field public static final int ERROR_CODE_BAD_AUTHENTICATION = 9; // 0x9
     field public static final int ERROR_CODE_BAD_REQUEST = 8; // 0x8
@@ -3091,30 +3092,30 @@
     field public static final int ERROR_CODE_NETWORK_ERROR = 3; // 0x3
     field public static final int ERROR_CODE_REMOTE_EXCEPTION = 1; // 0x1
     field public static final int ERROR_CODE_UNSUPPORTED_OPERATION = 6; // 0x6
-    field public static final java.lang.String KEY_ACCOUNTS = "accounts";
-    field public static final java.lang.String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
-    field public static final java.lang.String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
-    field public static final java.lang.String KEY_ACCOUNT_NAME = "authAccount";
-    field public static final java.lang.String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
-    field public static final java.lang.String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
-    field public static final java.lang.String KEY_ACCOUNT_TYPE = "accountType";
-    field public static final java.lang.String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
-    field public static final java.lang.String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
-    field public static final java.lang.String KEY_AUTHTOKEN = "authtoken";
-    field public static final java.lang.String KEY_AUTH_FAILED_MESSAGE = "authFailedMessage";
-    field public static final java.lang.String KEY_AUTH_TOKEN_LABEL = "authTokenLabelKey";
-    field public static final java.lang.String KEY_BOOLEAN_RESULT = "booleanResult";
-    field public static final java.lang.String KEY_CALLER_PID = "callerPid";
-    field public static final java.lang.String KEY_CALLER_UID = "callerUid";
-    field public static final java.lang.String KEY_ERROR_CODE = "errorCode";
-    field public static final java.lang.String KEY_ERROR_MESSAGE = "errorMessage";
-    field public static final java.lang.String KEY_INTENT = "intent";
-    field public static final java.lang.String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
-    field public static final java.lang.String KEY_PASSWORD = "password";
-    field public static final java.lang.String KEY_USERDATA = "userdata";
-    field public static final deprecated java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
-    field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android:accounts:key_legacy_not_visible";
-    field public static final java.lang.String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android:accounts:key_legacy_visible";
+    field public static final String KEY_ACCOUNTS = "accounts";
+    field public static final String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
+    field public static final String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
+    field public static final String KEY_ACCOUNT_NAME = "authAccount";
+    field public static final String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
+    field public static final String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
+    field public static final String KEY_ACCOUNT_TYPE = "accountType";
+    field public static final String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
+    field public static final String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
+    field public static final String KEY_AUTHTOKEN = "authtoken";
+    field public static final String KEY_AUTH_FAILED_MESSAGE = "authFailedMessage";
+    field public static final String KEY_AUTH_TOKEN_LABEL = "authTokenLabelKey";
+    field public static final String KEY_BOOLEAN_RESULT = "booleanResult";
+    field public static final String KEY_CALLER_PID = "callerPid";
+    field public static final String KEY_CALLER_UID = "callerUid";
+    field public static final String KEY_ERROR_CODE = "errorCode";
+    field public static final String KEY_ERROR_MESSAGE = "errorMessage";
+    field public static final String KEY_INTENT = "intent";
+    field public static final String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
+    field public static final String KEY_PASSWORD = "password";
+    field public static final String KEY_USERDATA = "userdata";
+    field @Deprecated public static final String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
+    field public static final String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE = "android:accounts:key_legacy_not_visible";
+    field public static final String PACKAGE_NAME_KEY_LEGACY_VISIBLE = "android:accounts:key_legacy_visible";
     field public static final int VISIBILITY_NOT_VISIBLE = 3; // 0x3
     field public static final int VISIBILITY_UNDEFINED = 0; // 0x0
     field public static final int VISIBILITY_USER_MANAGED_NOT_VISIBLE = 4; // 0x4
@@ -3122,64 +3123,64 @@
     field public static final int VISIBILITY_VISIBLE = 1; // 0x1
   }
 
-  public abstract interface AccountManagerCallback<V> {
-    method public abstract void run(android.accounts.AccountManagerFuture<V>);
+  public interface AccountManagerCallback<V> {
+    method public void run(android.accounts.AccountManagerFuture<V>);
   }
 
-  public abstract interface AccountManagerFuture<V> {
-    method public abstract boolean cancel(boolean);
-    method public abstract V getResult() throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
-    method public abstract V getResult(long, java.util.concurrent.TimeUnit) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
-    method public abstract boolean isCancelled();
-    method public abstract boolean isDone();
+  public interface AccountManagerFuture<V> {
+    method public boolean cancel(boolean);
+    method public V getResult() throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
+    method public V getResult(long, java.util.concurrent.TimeUnit) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
+    method public boolean isCancelled();
+    method public boolean isDone();
   }
 
   public class AccountsException extends java.lang.Exception {
     ctor public AccountsException();
-    ctor public AccountsException(java.lang.String);
-    ctor public AccountsException(java.lang.String, java.lang.Throwable);
-    ctor public AccountsException(java.lang.Throwable);
+    ctor public AccountsException(String);
+    ctor public AccountsException(String, Throwable);
+    ctor public AccountsException(Throwable);
   }
 
   public class AuthenticatorDescription implements android.os.Parcelable {
-    ctor public AuthenticatorDescription(java.lang.String, java.lang.String, int, int, int, int, boolean);
-    ctor public AuthenticatorDescription(java.lang.String, java.lang.String, int, int, int, int);
+    ctor public AuthenticatorDescription(String, String, int, int, int, int, boolean);
+    ctor public AuthenticatorDescription(String, String, int, int, int, int);
     method public int describeContents();
-    method public static android.accounts.AuthenticatorDescription newKey(java.lang.String);
+    method public static android.accounts.AuthenticatorDescription newKey(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.accounts.AuthenticatorDescription> CREATOR;
     field public final int accountPreferencesId;
     field public final boolean customTokens;
     field public final int iconId;
     field public final int labelId;
-    field public final java.lang.String packageName;
+    field public final String packageName;
     field public final int smallIconId;
-    field public final java.lang.String type;
+    field public final String type;
   }
 
   public class AuthenticatorException extends android.accounts.AccountsException {
     ctor public AuthenticatorException();
-    ctor public AuthenticatorException(java.lang.String);
-    ctor public AuthenticatorException(java.lang.String, java.lang.Throwable);
-    ctor public AuthenticatorException(java.lang.Throwable);
+    ctor public AuthenticatorException(String);
+    ctor public AuthenticatorException(String, Throwable);
+    ctor public AuthenticatorException(Throwable);
   }
 
   public class NetworkErrorException extends android.accounts.AccountsException {
     ctor public NetworkErrorException();
-    ctor public NetworkErrorException(java.lang.String);
-    ctor public NetworkErrorException(java.lang.String, java.lang.Throwable);
-    ctor public NetworkErrorException(java.lang.Throwable);
+    ctor public NetworkErrorException(String);
+    ctor public NetworkErrorException(String, Throwable);
+    ctor public NetworkErrorException(Throwable);
   }
 
-  public abstract interface OnAccountsUpdateListener {
-    method public abstract void onAccountsUpdated(android.accounts.Account[]);
+  public interface OnAccountsUpdateListener {
+    method public void onAccountsUpdated(android.accounts.Account[]);
   }
 
   public class OperationCanceledException extends android.accounts.AccountsException {
     ctor public OperationCanceledException();
-    ctor public OperationCanceledException(java.lang.String);
-    ctor public OperationCanceledException(java.lang.String, java.lang.Throwable);
-    ctor public OperationCanceledException(java.lang.Throwable);
+    ctor public OperationCanceledException(String);
+    ctor public OperationCanceledException(String, Throwable);
+    ctor public OperationCanceledException(Throwable);
   }
 
 }
@@ -3209,30 +3210,30 @@
     method public abstract android.animation.Animator setDuration(long);
     method public abstract void setInterpolator(android.animation.TimeInterpolator);
     method public abstract void setStartDelay(long);
-    method public void setTarget(java.lang.Object);
+    method public void setTarget(@Nullable Object);
     method public void setupEndValues();
     method public void setupStartValues();
     method public void start();
     field public static final long DURATION_INFINITE = -1L; // 0xffffffffffffffffL
   }
 
-  public static abstract interface Animator.AnimatorListener {
-    method public abstract void onAnimationCancel(android.animation.Animator);
+  public static interface Animator.AnimatorListener {
+    method public void onAnimationCancel(android.animation.Animator);
     method public default void onAnimationEnd(android.animation.Animator, boolean);
-    method public abstract void onAnimationEnd(android.animation.Animator);
-    method public abstract void onAnimationRepeat(android.animation.Animator);
+    method public void onAnimationEnd(android.animation.Animator);
+    method public void onAnimationRepeat(android.animation.Animator);
     method public default void onAnimationStart(android.animation.Animator, boolean);
-    method public abstract void onAnimationStart(android.animation.Animator);
+    method public void onAnimationStart(android.animation.Animator);
   }
 
-  public static abstract interface Animator.AnimatorPauseListener {
-    method public abstract void onAnimationPause(android.animation.Animator);
-    method public abstract void onAnimationResume(android.animation.Animator);
+  public static interface Animator.AnimatorPauseListener {
+    method public void onAnimationPause(android.animation.Animator);
+    method public void onAnimationResume(android.animation.Animator);
   }
 
   public class AnimatorInflater {
     ctor public AnimatorInflater();
-    method public static android.animation.Animator loadAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
+    method public static android.animation.Animator loadAnimator(android.content.Context, @AnimatorRes int) throws android.content.res.Resources.NotFoundException;
     method public static android.animation.StateListAnimator loadStateListAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
   }
 
@@ -3275,35 +3276,35 @@
 
   public class ArgbEvaluator implements android.animation.TypeEvaluator {
     ctor public ArgbEvaluator();
-    method public java.lang.Object evaluate(float, java.lang.Object, java.lang.Object);
+    method public Object evaluate(float, Object, Object);
   }
 
-  public abstract class BidirectionalTypeConverter<T, V> extends android.animation.TypeConverter {
-    ctor public BidirectionalTypeConverter(java.lang.Class<T>, java.lang.Class<V>);
+  public abstract class BidirectionalTypeConverter<T, V> extends android.animation.TypeConverter<T,V> {
+    ctor public BidirectionalTypeConverter(Class<T>, Class<V>);
     method public abstract T convertBack(V);
-    method public android.animation.BidirectionalTypeConverter<V, T> invert();
+    method public android.animation.BidirectionalTypeConverter<V,T> invert();
   }
 
-  public class FloatArrayEvaluator implements android.animation.TypeEvaluator {
+  public class FloatArrayEvaluator implements android.animation.TypeEvaluator<float[]> {
     ctor public FloatArrayEvaluator();
     ctor public FloatArrayEvaluator(float[]);
     method public float[] evaluate(float, float[], float[]);
   }
 
-  public class FloatEvaluator implements android.animation.TypeEvaluator {
+  public class FloatEvaluator implements android.animation.TypeEvaluator<java.lang.Number> {
     ctor public FloatEvaluator();
-    method public java.lang.Float evaluate(float, java.lang.Number, java.lang.Number);
+    method public Float evaluate(float, Number, Number);
   }
 
-  public class IntArrayEvaluator implements android.animation.TypeEvaluator {
+  public class IntArrayEvaluator implements android.animation.TypeEvaluator<int[]> {
     ctor public IntArrayEvaluator();
     ctor public IntArrayEvaluator(int[]);
     method public int[] evaluate(float, int[], int[]);
   }
 
-  public class IntEvaluator implements android.animation.TypeEvaluator {
+  public class IntEvaluator implements android.animation.TypeEvaluator<java.lang.Integer> {
     ctor public IntEvaluator();
-    method public java.lang.Integer evaluate(float, java.lang.Integer, java.lang.Integer);
+    method public Integer evaluate(float, Integer, Integer);
   }
 
   public abstract class Keyframe implements java.lang.Cloneable {
@@ -3311,18 +3312,18 @@
     method public abstract android.animation.Keyframe clone();
     method public float getFraction();
     method public android.animation.TimeInterpolator getInterpolator();
-    method public java.lang.Class getType();
-    method public abstract java.lang.Object getValue();
+    method public Class getType();
+    method public abstract Object getValue();
     method public boolean hasValue();
     method public static android.animation.Keyframe ofFloat(float, float);
     method public static android.animation.Keyframe ofFloat(float);
     method public static android.animation.Keyframe ofInt(float, int);
     method public static android.animation.Keyframe ofInt(float);
-    method public static android.animation.Keyframe ofObject(float, java.lang.Object);
+    method public static android.animation.Keyframe ofObject(float, Object);
     method public static android.animation.Keyframe ofObject(float);
     method public void setFraction(float);
     method public void setInterpolator(android.animation.TimeInterpolator);
-    method public abstract void setValue(java.lang.Object);
+    method public abstract void setValue(Object);
   }
 
   public class LayoutTransition {
@@ -3337,7 +3338,7 @@
     method public long getStagger(int);
     method public long getStartDelay(int);
     method public java.util.List<android.animation.LayoutTransition.TransitionListener> getTransitionListeners();
-    method public deprecated void hideChild(android.view.ViewGroup, android.view.View);
+    method @Deprecated public void hideChild(android.view.ViewGroup, android.view.View);
     method public void hideChild(android.view.ViewGroup, android.view.View, int);
     method public boolean isChangingLayout();
     method public boolean isRunning();
@@ -3351,7 +3352,7 @@
     method public void setInterpolator(int, android.animation.TimeInterpolator);
     method public void setStagger(int, long);
     method public void setStartDelay(int, long);
-    method public deprecated void showChild(android.view.ViewGroup, android.view.View);
+    method @Deprecated public void showChild(android.view.ViewGroup, android.view.View);
     method public void showChild(android.view.ViewGroup, android.view.View, int);
     field public static final int APPEARING = 2; // 0x2
     field public static final int CHANGE_APPEARING = 0; // 0x0
@@ -3360,45 +3361,45 @@
     field public static final int DISAPPEARING = 3; // 0x3
   }
 
-  public static abstract interface LayoutTransition.TransitionListener {
-    method public abstract void endTransition(android.animation.LayoutTransition, android.view.ViewGroup, android.view.View, int);
-    method public abstract void startTransition(android.animation.LayoutTransition, android.view.ViewGroup, android.view.View, int);
+  public static interface LayoutTransition.TransitionListener {
+    method public void endTransition(android.animation.LayoutTransition, android.view.ViewGroup, android.view.View, int);
+    method public void startTransition(android.animation.LayoutTransition, android.view.ViewGroup, android.view.View, int);
   }
 
   public final class ObjectAnimator extends android.animation.ValueAnimator {
     ctor public ObjectAnimator();
     method public android.animation.ObjectAnimator clone();
-    method public java.lang.String getPropertyName();
-    method public java.lang.Object getTarget();
-    method public static android.animation.ObjectAnimator ofArgb(java.lang.Object, java.lang.String, int...);
-    method public static <T> android.animation.ObjectAnimator ofArgb(T, android.util.Property<T, java.lang.Integer>, int...);
-    method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, float...);
-    method public static android.animation.ObjectAnimator ofFloat(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
-    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, float...);
-    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T, java.lang.Float>, android.util.Property<T, java.lang.Float>, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, int...);
-    method public static android.animation.ObjectAnimator ofInt(java.lang.Object, java.lang.String, java.lang.String, android.graphics.Path);
-    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, int...);
-    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T, java.lang.Integer>, android.util.Property<T, java.lang.Integer>, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, float[][]);
-    method public static android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.graphics.Path);
-    method public static <T> android.animation.ObjectAnimator ofMultiFloat(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, T...);
-    method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, int[][]);
-    method public static android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.graphics.Path);
-    method public static <T> android.animation.ObjectAnimator ofMultiInt(java.lang.Object, java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, T...);
-    method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
-    method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
-    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
-    method public static <T, V, P> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, P>, android.animation.TypeConverter<V, P>, android.animation.TypeEvaluator<V>, V...);
-    method public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
-    method public static android.animation.ObjectAnimator ofPropertyValuesHolder(java.lang.Object, android.animation.PropertyValuesHolder...);
+    method @Nullable public String getPropertyName();
+    method @Nullable public Object getTarget();
+    method public static android.animation.ObjectAnimator ofArgb(Object, String, int...);
+    method public static <T> android.animation.ObjectAnimator ofArgb(T, android.util.Property<T,java.lang.Integer>, int...);
+    method public static android.animation.ObjectAnimator ofFloat(Object, String, float...);
+    method public static android.animation.ObjectAnimator ofFloat(Object, String, String, android.graphics.Path);
+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T,java.lang.Float>, float...);
+    method public static <T> android.animation.ObjectAnimator ofFloat(T, android.util.Property<T,java.lang.Float>, android.util.Property<T,java.lang.Float>, android.graphics.Path);
+    method public static android.animation.ObjectAnimator ofInt(Object, String, int...);
+    method public static android.animation.ObjectAnimator ofInt(Object, String, String, android.graphics.Path);
+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T,java.lang.Integer>, int...);
+    method public static <T> android.animation.ObjectAnimator ofInt(T, android.util.Property<T,java.lang.Integer>, android.util.Property<T,java.lang.Integer>, android.graphics.Path);
+    method public static android.animation.ObjectAnimator ofMultiFloat(Object, String, float[][]);
+    method public static android.animation.ObjectAnimator ofMultiFloat(Object, String, android.graphics.Path);
+    method @java.lang.SafeVarargs public static <T> android.animation.ObjectAnimator ofMultiFloat(Object, String, android.animation.TypeConverter<T,float[]>, android.animation.TypeEvaluator<T>, T...);
+    method public static android.animation.ObjectAnimator ofMultiInt(Object, String, int[][]);
+    method public static android.animation.ObjectAnimator ofMultiInt(Object, String, android.graphics.Path);
+    method @java.lang.SafeVarargs public static <T> android.animation.ObjectAnimator ofMultiInt(Object, String, android.animation.TypeConverter<T,int[]>, android.animation.TypeEvaluator<T>, T...);
+    method public static android.animation.ObjectAnimator ofObject(Object, String, android.animation.TypeEvaluator, java.lang.Object...);
+    method @NonNull public static android.animation.ObjectAnimator ofObject(Object, String, @Nullable android.animation.TypeConverter<android.graphics.PointF,?>, android.graphics.Path);
+    method @NonNull @java.lang.SafeVarargs public static <T, V> android.animation.ObjectAnimator ofObject(T, android.util.Property<T,V>, android.animation.TypeEvaluator<V>, V...);
+    method @NonNull @java.lang.SafeVarargs public static <T, V, P> android.animation.ObjectAnimator ofObject(T, android.util.Property<T,P>, android.animation.TypeConverter<V,P>, android.animation.TypeEvaluator<V>, V...);
+    method @NonNull public static <T, V> android.animation.ObjectAnimator ofObject(T, @NonNull android.util.Property<T,V>, @Nullable android.animation.TypeConverter<android.graphics.PointF,V>, android.graphics.Path);
+    method @NonNull public static android.animation.ObjectAnimator ofPropertyValuesHolder(Object, android.animation.PropertyValuesHolder...);
     method public void setAutoCancel(boolean);
-    method public android.animation.ObjectAnimator setDuration(long);
-    method public void setProperty(android.util.Property);
-    method public void setPropertyName(java.lang.String);
+    method @NonNull public android.animation.ObjectAnimator setDuration(long);
+    method public void setProperty(@NonNull android.util.Property);
+    method public void setPropertyName(@NonNull String);
   }
 
-  public class PointFEvaluator implements android.animation.TypeEvaluator {
+  public class PointFEvaluator implements android.animation.TypeEvaluator<android.graphics.PointF> {
     ctor public PointFEvaluator();
     ctor public PointFEvaluator(android.graphics.PointF);
     method public android.graphics.PointF evaluate(float, android.graphics.PointF, android.graphics.PointF);
@@ -3406,26 +3407,26 @@
 
   public class PropertyValuesHolder implements java.lang.Cloneable {
     method public android.animation.PropertyValuesHolder clone();
-    method public java.lang.String getPropertyName();
-    method public static android.animation.PropertyValuesHolder ofFloat(java.lang.String, float...);
-    method public static android.animation.PropertyValuesHolder ofFloat(android.util.Property<?, java.lang.Float>, float...);
-    method public static android.animation.PropertyValuesHolder ofInt(java.lang.String, int...);
-    method public static android.animation.PropertyValuesHolder ofInt(android.util.Property<?, java.lang.Integer>, int...);
-    method public static android.animation.PropertyValuesHolder ofKeyframe(java.lang.String, android.animation.Keyframe...);
+    method public String getPropertyName();
+    method public static android.animation.PropertyValuesHolder ofFloat(String, float...);
+    method public static android.animation.PropertyValuesHolder ofFloat(android.util.Property<?,java.lang.Float>, float...);
+    method public static android.animation.PropertyValuesHolder ofInt(String, int...);
+    method public static android.animation.PropertyValuesHolder ofInt(android.util.Property<?,java.lang.Integer>, int...);
+    method public static android.animation.PropertyValuesHolder ofKeyframe(String, android.animation.Keyframe...);
     method public static android.animation.PropertyValuesHolder ofKeyframe(android.util.Property, android.animation.Keyframe...);
-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, float[][]);
-    method public static android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.graphics.Path);
-    method public static <V> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<V, float[]>, android.animation.TypeEvaluator<V>, V...);
-    method public static <T> android.animation.PropertyValuesHolder ofMultiFloat(java.lang.String, android.animation.TypeConverter<T, float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, int[][]);
-    method public static android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.graphics.Path);
-    method public static <V> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<V, int[]>, android.animation.TypeEvaluator<V>, V...);
-    method public static <T> android.animation.PropertyValuesHolder ofMultiInt(java.lang.String, android.animation.TypeConverter<T, int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
-    method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
-    method public static android.animation.PropertyValuesHolder ofObject(java.lang.String, android.animation.TypeConverter<android.graphics.PointF, ?>, android.graphics.Path);
-    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
-    method public static <T, V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<T, V>, android.animation.TypeEvaluator<T>, T...);
-    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?, V>, android.animation.TypeConverter<android.graphics.PointF, V>, android.graphics.Path);
+    method public static android.animation.PropertyValuesHolder ofMultiFloat(String, float[][]);
+    method public static android.animation.PropertyValuesHolder ofMultiFloat(String, android.graphics.Path);
+    method @java.lang.SafeVarargs public static <V> android.animation.PropertyValuesHolder ofMultiFloat(String, android.animation.TypeConverter<V,float[]>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T> android.animation.PropertyValuesHolder ofMultiFloat(String, android.animation.TypeConverter<T,float[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
+    method public static android.animation.PropertyValuesHolder ofMultiInt(String, int[][]);
+    method public static android.animation.PropertyValuesHolder ofMultiInt(String, android.graphics.Path);
+    method @java.lang.SafeVarargs public static <V> android.animation.PropertyValuesHolder ofMultiInt(String, android.animation.TypeConverter<V,int[]>, android.animation.TypeEvaluator<V>, V...);
+    method public static <T> android.animation.PropertyValuesHolder ofMultiInt(String, android.animation.TypeConverter<T,int[]>, android.animation.TypeEvaluator<T>, android.animation.Keyframe...);
+    method public static android.animation.PropertyValuesHolder ofObject(String, android.animation.TypeEvaluator, java.lang.Object...);
+    method public static android.animation.PropertyValuesHolder ofObject(String, android.animation.TypeConverter<android.graphics.PointF,?>, android.graphics.Path);
+    method @java.lang.SafeVarargs public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property, android.animation.TypeEvaluator<V>, V...);
+    method @java.lang.SafeVarargs public static <T, V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?,V>, android.animation.TypeConverter<T,V>, android.animation.TypeEvaluator<T>, T...);
+    method public static <V> android.animation.PropertyValuesHolder ofObject(android.util.Property<?,V>, android.animation.TypeConverter<android.graphics.PointF,V>, android.graphics.Path);
     method public void setConverter(android.animation.TypeConverter);
     method public void setEvaluator(android.animation.TypeEvaluator);
     method public void setFloatValues(float...);
@@ -3433,10 +3434,10 @@
     method public void setKeyframes(android.animation.Keyframe...);
     method public void setObjectValues(java.lang.Object...);
     method public void setProperty(android.util.Property);
-    method public void setPropertyName(java.lang.String);
+    method public void setPropertyName(String);
   }
 
-  public class RectEvaluator implements android.animation.TypeEvaluator {
+  public class RectEvaluator implements android.animation.TypeEvaluator<android.graphics.Rect> {
     ctor public RectEvaluator();
     ctor public RectEvaluator(android.graphics.Rect);
     method public android.graphics.Rect evaluate(float, android.graphics.Rect, android.graphics.Rect);
@@ -3454,21 +3455,21 @@
     method public void setTimeListener(android.animation.TimeAnimator.TimeListener);
   }
 
-  public static abstract interface TimeAnimator.TimeListener {
-    method public abstract void onTimeUpdate(android.animation.TimeAnimator, long, long);
+  public static interface TimeAnimator.TimeListener {
+    method public void onTimeUpdate(android.animation.TimeAnimator, long, long);
   }
 
-  public abstract interface TimeInterpolator {
-    method public abstract float getInterpolation(float);
+  public interface TimeInterpolator {
+    method public float getInterpolation(float);
   }
 
   public abstract class TypeConverter<T, V> {
-    ctor public TypeConverter(java.lang.Class<T>, java.lang.Class<V>);
+    ctor public TypeConverter(Class<T>, Class<V>);
     method public abstract V convert(T);
   }
 
-  public abstract interface TypeEvaluator<T> {
-    method public abstract T evaluate(float, T, T);
+  public interface TypeEvaluator<T> {
+    method public T evaluate(float, T, T);
   }
 
   public class ValueAnimator extends android.animation.Animator {
@@ -3477,8 +3478,8 @@
     method public static boolean areAnimatorsEnabled();
     method public android.animation.ValueAnimator clone();
     method public float getAnimatedFraction();
-    method public java.lang.Object getAnimatedValue();
-    method public java.lang.Object getAnimatedValue(java.lang.String);
+    method public Object getAnimatedValue();
+    method public Object getAnimatedValue(String);
     method public long getCurrentPlayTime();
     method public long getDuration();
     method public static long getFrameDelay();
@@ -3513,18 +3514,20 @@
     field public static final int REVERSE = 2; // 0x2
   }
 
-  public static abstract interface ValueAnimator.AnimatorUpdateListener {
-    method public abstract void onAnimationUpdate(android.animation.ValueAnimator);
+  public static interface ValueAnimator.AnimatorUpdateListener {
+    method public void onAnimationUpdate(android.animation.ValueAnimator);
   }
 
 }
 
 package android.annotation {
 
-  public abstract class SuppressLint implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface SuppressLint {
+    method public abstract String[] value();
   }
 
-  public abstract class TargetApi implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface TargetApi {
+    method public abstract int value();
   }
 
 }
@@ -3534,37 +3537,37 @@
   public abstract class ActionBar {
     ctor public ActionBar();
     method public abstract void addOnMenuVisibilityListener(android.app.ActionBar.OnMenuVisibilityListener);
-    method public abstract deprecated void addTab(android.app.ActionBar.Tab);
-    method public abstract deprecated void addTab(android.app.ActionBar.Tab, boolean);
-    method public abstract deprecated void addTab(android.app.ActionBar.Tab, int);
-    method public abstract deprecated void addTab(android.app.ActionBar.Tab, int, boolean);
+    method @Deprecated public abstract void addTab(android.app.ActionBar.Tab);
+    method @Deprecated public abstract void addTab(android.app.ActionBar.Tab, boolean);
+    method @Deprecated public abstract void addTab(android.app.ActionBar.Tab, int);
+    method @Deprecated public abstract void addTab(android.app.ActionBar.Tab, int, boolean);
     method public abstract android.view.View getCustomView();
     method public abstract int getDisplayOptions();
     method public float getElevation();
     method public abstract int getHeight();
     method public int getHideOffset();
-    method public abstract deprecated int getNavigationItemCount();
-    method public abstract deprecated int getNavigationMode();
-    method public abstract deprecated int getSelectedNavigationIndex();
-    method public abstract deprecated android.app.ActionBar.Tab getSelectedTab();
-    method public abstract java.lang.CharSequence getSubtitle();
-    method public abstract deprecated android.app.ActionBar.Tab getTabAt(int);
-    method public abstract deprecated int getTabCount();
+    method @Deprecated public abstract int getNavigationItemCount();
+    method @Deprecated public abstract int getNavigationMode();
+    method @Deprecated public abstract int getSelectedNavigationIndex();
+    method @Deprecated public abstract android.app.ActionBar.Tab getSelectedTab();
+    method public abstract CharSequence getSubtitle();
+    method @Deprecated public abstract android.app.ActionBar.Tab getTabAt(int);
+    method @Deprecated public abstract int getTabCount();
     method public android.content.Context getThemedContext();
-    method public abstract java.lang.CharSequence getTitle();
+    method public abstract CharSequence getTitle();
     method public abstract void hide();
     method public boolean isHideOnContentScrollEnabled();
     method public abstract boolean isShowing();
-    method public abstract deprecated android.app.ActionBar.Tab newTab();
-    method public abstract deprecated void removeAllTabs();
+    method @Deprecated public abstract android.app.ActionBar.Tab newTab();
+    method @Deprecated public abstract void removeAllTabs();
     method public abstract void removeOnMenuVisibilityListener(android.app.ActionBar.OnMenuVisibilityListener);
-    method public abstract deprecated void removeTab(android.app.ActionBar.Tab);
-    method public abstract deprecated void removeTabAt(int);
-    method public abstract deprecated void selectTab(android.app.ActionBar.Tab);
-    method public abstract void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method @Deprecated public abstract void removeTab(android.app.ActionBar.Tab);
+    method @Deprecated public abstract void removeTabAt(int);
+    method @Deprecated public abstract void selectTab(android.app.ActionBar.Tab);
+    method public abstract void setBackgroundDrawable(@Nullable android.graphics.drawable.Drawable);
     method public abstract void setCustomView(android.view.View);
     method public abstract void setCustomView(android.view.View, android.app.ActionBar.LayoutParams);
-    method public abstract void setCustomView(int);
+    method public abstract void setCustomView(@LayoutRes int);
     method public abstract void setDisplayHomeAsUpEnabled(boolean);
     method public abstract void setDisplayOptions(int);
     method public abstract void setDisplayOptions(int, int);
@@ -3575,79 +3578,79 @@
     method public void setElevation(float);
     method public void setHideOffset(int);
     method public void setHideOnContentScrollEnabled(boolean);
-    method public void setHomeActionContentDescription(java.lang.CharSequence);
-    method public void setHomeActionContentDescription(int);
+    method public void setHomeActionContentDescription(CharSequence);
+    method public void setHomeActionContentDescription(@StringRes int);
     method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
-    method public void setHomeAsUpIndicator(int);
+    method public void setHomeAsUpIndicator(@DrawableRes int);
     method public void setHomeButtonEnabled(boolean);
-    method public abstract void setIcon(int);
+    method public abstract void setIcon(@DrawableRes int);
     method public abstract void setIcon(android.graphics.drawable.Drawable);
-    method public abstract deprecated void setListNavigationCallbacks(android.widget.SpinnerAdapter, android.app.ActionBar.OnNavigationListener);
-    method public abstract void setLogo(int);
+    method @Deprecated public abstract void setListNavigationCallbacks(android.widget.SpinnerAdapter, android.app.ActionBar.OnNavigationListener);
+    method public abstract void setLogo(@DrawableRes int);
     method public abstract void setLogo(android.graphics.drawable.Drawable);
-    method public abstract deprecated void setNavigationMode(int);
-    method public abstract deprecated void setSelectedNavigationItem(int);
+    method @Deprecated public abstract void setNavigationMode(int);
+    method @Deprecated public abstract void setSelectedNavigationItem(int);
     method public void setSplitBackgroundDrawable(android.graphics.drawable.Drawable);
     method public void setStackedBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public abstract void setSubtitle(java.lang.CharSequence);
-    method public abstract void setSubtitle(int);
-    method public abstract void setTitle(java.lang.CharSequence);
-    method public abstract void setTitle(int);
+    method public abstract void setSubtitle(CharSequence);
+    method public abstract void setSubtitle(@StringRes int);
+    method public abstract void setTitle(CharSequence);
+    method public abstract void setTitle(@StringRes int);
     method public abstract void show();
     field public static final int DISPLAY_HOME_AS_UP = 4; // 0x4
     field public static final int DISPLAY_SHOW_CUSTOM = 16; // 0x10
     field public static final int DISPLAY_SHOW_HOME = 2; // 0x2
     field public static final int DISPLAY_SHOW_TITLE = 8; // 0x8
     field public static final int DISPLAY_USE_LOGO = 1; // 0x1
-    field public static final deprecated int NAVIGATION_MODE_LIST = 1; // 0x1
-    field public static final deprecated int NAVIGATION_MODE_STANDARD = 0; // 0x0
-    field public static final deprecated int NAVIGATION_MODE_TABS = 2; // 0x2
+    field @Deprecated public static final int NAVIGATION_MODE_LIST = 1; // 0x1
+    field @Deprecated public static final int NAVIGATION_MODE_STANDARD = 0; // 0x0
+    field @Deprecated public static final int NAVIGATION_MODE_TABS = 2; // 0x2
   }
 
   public static class ActionBar.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
-    ctor public ActionBar.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public ActionBar.LayoutParams(@NonNull android.content.Context, android.util.AttributeSet);
     ctor public ActionBar.LayoutParams(int, int);
     ctor public ActionBar.LayoutParams(int, int, int);
     ctor public ActionBar.LayoutParams(int);
     ctor public ActionBar.LayoutParams(android.app.ActionBar.LayoutParams);
     ctor public ActionBar.LayoutParams(android.view.ViewGroup.LayoutParams);
-    field public int gravity;
+    field @android.view.ViewDebug.ExportedProperty(category="layout", mapping={@android.view.ViewDebug.IntToString(from=0xffffffff, to="NONE"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.NO_GRAVITY, to="NONE"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.TOP, to="TOP"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.BOTTOM, to="BOTTOM"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.LEFT, to="LEFT"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.RIGHT, to="RIGHT"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.START, to="START"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.END, to="END"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.CENTER_VERTICAL, to="CENTER_VERTICAL"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.FILL_VERTICAL, to="FILL_VERTICAL"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.CENTER_HORIZONTAL, to="CENTER_HORIZONTAL"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.FILL_HORIZONTAL, to="FILL_HORIZONTAL"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.CENTER, to="CENTER"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.FILL, to="FILL")}) public int gravity;
   }
 
-  public static abstract interface ActionBar.OnMenuVisibilityListener {
-    method public abstract void onMenuVisibilityChanged(boolean);
+  public static interface ActionBar.OnMenuVisibilityListener {
+    method public void onMenuVisibilityChanged(boolean);
   }
 
-  public static abstract deprecated interface ActionBar.OnNavigationListener {
-    method public abstract boolean onNavigationItemSelected(int, long);
+  @Deprecated public static interface ActionBar.OnNavigationListener {
+    method @Deprecated public boolean onNavigationItemSelected(int, long);
   }
 
-  public static abstract deprecated class ActionBar.Tab {
-    ctor public ActionBar.Tab();
-    method public abstract java.lang.CharSequence getContentDescription();
-    method public abstract android.view.View getCustomView();
-    method public abstract android.graphics.drawable.Drawable getIcon();
-    method public abstract int getPosition();
-    method public abstract java.lang.Object getTag();
-    method public abstract java.lang.CharSequence getText();
-    method public abstract void select();
-    method public abstract android.app.ActionBar.Tab setContentDescription(int);
-    method public abstract android.app.ActionBar.Tab setContentDescription(java.lang.CharSequence);
-    method public abstract android.app.ActionBar.Tab setCustomView(android.view.View);
-    method public abstract android.app.ActionBar.Tab setCustomView(int);
-    method public abstract android.app.ActionBar.Tab setIcon(android.graphics.drawable.Drawable);
-    method public abstract android.app.ActionBar.Tab setIcon(int);
-    method public abstract android.app.ActionBar.Tab setTabListener(android.app.ActionBar.TabListener);
-    method public abstract android.app.ActionBar.Tab setTag(java.lang.Object);
-    method public abstract android.app.ActionBar.Tab setText(java.lang.CharSequence);
-    method public abstract android.app.ActionBar.Tab setText(int);
-    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  @Deprecated public abstract static class ActionBar.Tab {
+    ctor @Deprecated public ActionBar.Tab();
+    method @Deprecated public abstract CharSequence getContentDescription();
+    method @Deprecated public abstract android.view.View getCustomView();
+    method @Deprecated public abstract android.graphics.drawable.Drawable getIcon();
+    method @Deprecated public abstract int getPosition();
+    method @Deprecated public abstract Object getTag();
+    method @Deprecated public abstract CharSequence getText();
+    method @Deprecated public abstract void select();
+    method @Deprecated public abstract android.app.ActionBar.Tab setContentDescription(@StringRes int);
+    method @Deprecated public abstract android.app.ActionBar.Tab setContentDescription(CharSequence);
+    method @Deprecated public abstract android.app.ActionBar.Tab setCustomView(android.view.View);
+    method @Deprecated public abstract android.app.ActionBar.Tab setCustomView(@LayoutRes int);
+    method @Deprecated public abstract android.app.ActionBar.Tab setIcon(android.graphics.drawable.Drawable);
+    method @Deprecated public abstract android.app.ActionBar.Tab setIcon(@DrawableRes int);
+    method @Deprecated public abstract android.app.ActionBar.Tab setTabListener(android.app.ActionBar.TabListener);
+    method @Deprecated public abstract android.app.ActionBar.Tab setTag(Object);
+    method @Deprecated public abstract android.app.ActionBar.Tab setText(CharSequence);
+    method @Deprecated public abstract android.app.ActionBar.Tab setText(@StringRes int);
+    field @Deprecated public static final int INVALID_POSITION = -1; // 0xffffffff
   }
 
-  public static abstract deprecated interface ActionBar.TabListener {
-    method public abstract void onTabReselected(android.app.ActionBar.Tab, android.app.FragmentTransaction);
-    method public abstract void onTabSelected(android.app.ActionBar.Tab, android.app.FragmentTransaction);
-    method public abstract void onTabUnselected(android.app.ActionBar.Tab, android.app.FragmentTransaction);
+  @Deprecated public static interface ActionBar.TabListener {
+    method @Deprecated public void onTabReselected(android.app.ActionBar.Tab, android.app.FragmentTransaction);
+    method @Deprecated public void onTabSelected(android.app.ActionBar.Tab, android.app.FragmentTransaction);
+    method @Deprecated public void onTabUnselected(android.app.ActionBar.Tab, android.app.FragmentTransaction);
   }
 
   public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback {
@@ -3655,8 +3658,8 @@
     method public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public void closeContextMenu();
     method public void closeOptionsMenu();
-    method public android.app.PendingIntent createPendingResult(int, android.content.Intent, int);
-    method public final deprecated void dismissDialog(int);
+    method public android.app.PendingIntent createPendingResult(int, @NonNull android.content.Intent, int);
+    method @Deprecated public final void dismissDialog(int);
     method public final void dismissKeyboardShortcutsHelper();
     method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
     method public boolean dispatchKeyEvent(android.view.KeyEvent);
@@ -3664,43 +3667,43 @@
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public boolean dispatchTouchEvent(android.view.MotionEvent);
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
-    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public deprecated void enterPictureInPictureMode();
-    method public boolean enterPictureInPictureMode(android.app.PictureInPictureParams);
-    method public <T extends android.view.View> T findViewById(int);
+    method public void dump(@NonNull String, @Nullable java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[]);
+    method @Deprecated public void enterPictureInPictureMode();
+    method public boolean enterPictureInPictureMode(@NonNull android.app.PictureInPictureParams);
+    method public <T extends android.view.View> T findViewById(@IdRes int);
     method public void finish();
     method public void finishActivity(int);
-    method public void finishActivityFromChild(android.app.Activity, int);
+    method public void finishActivityFromChild(@NonNull android.app.Activity, int);
     method public void finishAffinity();
     method public void finishAfterTransition();
     method public void finishAndRemoveTask();
     method public void finishFromChild(android.app.Activity);
-    method public android.app.ActionBar getActionBar();
+    method @Nullable public android.app.ActionBar getActionBar();
     method public final android.app.Application getApplication();
-    method public android.content.ComponentName getCallingActivity();
-    method public java.lang.String getCallingPackage();
+    method @Nullable public android.content.ComponentName getCallingActivity();
+    method @Nullable public String getCallingPackage();
     method public int getChangingConfigurations();
     method public android.content.ComponentName getComponentName();
     method public android.transition.Scene getContentScene();
     method public android.transition.TransitionManager getContentTransitionManager();
-    method public android.view.View getCurrentFocus();
-    method public deprecated android.app.FragmentManager getFragmentManager();
+    method @Nullable public android.view.View getCurrentFocus();
+    method @Deprecated public android.app.FragmentManager getFragmentManager();
     method public android.content.Intent getIntent();
-    method public java.lang.Object getLastNonConfigurationInstance();
-    method public android.view.LayoutInflater getLayoutInflater();
-    method public deprecated android.app.LoaderManager getLoaderManager();
-    method public java.lang.String getLocalClassName();
+    method @Nullable public Object getLastNonConfigurationInstance();
+    method @NonNull public android.view.LayoutInflater getLayoutInflater();
+    method @Deprecated public android.app.LoaderManager getLoaderManager();
+    method @NonNull public String getLocalClassName();
     method public int getMaxNumPictureInPictureActions();
     method public final android.media.session.MediaController getMediaController();
-    method public android.view.MenuInflater getMenuInflater();
+    method @NonNull public android.view.MenuInflater getMenuInflater();
     method public final android.app.Activity getParent();
-    method public android.content.Intent getParentActivityIntent();
+    method @Nullable public android.content.Intent getParentActivityIntent();
     method public android.content.SharedPreferences getPreferences(int);
-    method public android.net.Uri getReferrer();
+    method @Nullable public android.net.Uri getReferrer();
     method public int getRequestedOrientation();
     method public final android.view.SearchEvent getSearchEvent();
     method public int getTaskId();
-    method public final java.lang.CharSequence getTitle();
+    method public final CharSequence getTitle();
     method public final int getTitleColor();
     method public android.app.VoiceInteractor getVoiceInteractor();
     method public final int getVolumeControlStream();
@@ -3720,36 +3723,36 @@
     method public boolean isTaskRoot();
     method public boolean isVoiceInteraction();
     method public boolean isVoiceInteractionRoot();
-    method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method @Deprecated public final android.database.Cursor managedQuery(android.net.Uri, String[], String, String[], String);
     method public boolean moveTaskToBack(boolean);
     method public boolean navigateUpTo(android.content.Intent);
     method public boolean navigateUpToFromChild(android.app.Activity, android.content.Intent);
-    method public void onActionModeFinished(android.view.ActionMode);
-    method public void onActionModeStarted(android.view.ActionMode);
+    method @CallSuper public void onActionModeFinished(android.view.ActionMode);
+    method @CallSuper public void onActionModeStarted(android.view.ActionMode);
     method public void onActivityReenter(int, android.content.Intent);
     method protected void onActivityResult(int, int, android.content.Intent);
-    method public deprecated void onAttachFragment(android.app.Fragment);
+    method @Deprecated public void onAttachFragment(android.app.Fragment);
     method public void onAttachedToWindow();
     method public void onBackPressed();
-    method protected void onChildTitleChanged(android.app.Activity, java.lang.CharSequence);
-    method public void onConfigurationChanged(android.content.res.Configuration);
+    method protected void onChildTitleChanged(android.app.Activity, CharSequence);
+    method public void onConfigurationChanged(@NonNull android.content.res.Configuration);
     method public void onContentChanged();
-    method public boolean onContextItemSelected(android.view.MenuItem);
-    method public void onContextMenuClosed(android.view.Menu);
-    method protected void onCreate(android.os.Bundle);
-    method public void onCreate(android.os.Bundle, android.os.PersistableBundle);
+    method public boolean onContextItemSelected(@NonNull android.view.MenuItem);
+    method public void onContextMenuClosed(@NonNull android.view.Menu);
+    method @MainThread @CallSuper protected void onCreate(@Nullable android.os.Bundle);
+    method public void onCreate(@Nullable android.os.Bundle, @Nullable android.os.PersistableBundle);
     method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
-    method public java.lang.CharSequence onCreateDescription();
-    method protected deprecated android.app.Dialog onCreateDialog(int);
-    method protected deprecated android.app.Dialog onCreateDialog(int, android.os.Bundle);
+    method @Nullable public CharSequence onCreateDescription();
+    method @Deprecated protected android.app.Dialog onCreateDialog(int);
+    method @Deprecated @Nullable protected android.app.Dialog onCreateDialog(int, android.os.Bundle);
     method public void onCreateNavigateUpTaskStack(android.app.TaskStackBuilder);
     method public boolean onCreateOptionsMenu(android.view.Menu);
-    method public boolean onCreatePanelMenu(int, android.view.Menu);
-    method public android.view.View onCreatePanelView(int);
-    method public deprecated boolean onCreateThumbnail(android.graphics.Bitmap, android.graphics.Canvas);
-    method public android.view.View onCreateView(java.lang.String, android.content.Context, android.util.AttributeSet);
-    method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
-    method protected void onDestroy();
+    method public boolean onCreatePanelMenu(int, @NonNull android.view.Menu);
+    method @Nullable public android.view.View onCreatePanelView(int);
+    method @Deprecated public boolean onCreateThumbnail(android.graphics.Bitmap, android.graphics.Canvas);
+    method @Nullable public android.view.View onCreateView(@NonNull String, @NonNull android.content.Context, @NonNull android.util.AttributeSet);
+    method @Nullable public android.view.View onCreateView(@Nullable android.view.View, @NonNull String, @NonNull android.content.Context, @NonNull android.util.AttributeSet);
+    method @CallSuper protected void onDestroy();
     method public void onDetachedFromWindow();
     method public void onEnterAnimationComplete();
     method public boolean onGenericMotionEvent(android.view.MotionEvent);
@@ -3761,74 +3764,74 @@
     method public void onLocalVoiceInteractionStarted();
     method public void onLocalVoiceInteractionStopped();
     method public void onLowMemory();
-    method public boolean onMenuItemSelected(int, android.view.MenuItem);
-    method public boolean onMenuOpened(int, android.view.Menu);
+    method public boolean onMenuItemSelected(int, @NonNull android.view.MenuItem);
+    method public boolean onMenuOpened(int, @NonNull android.view.Menu);
     method public void onMultiWindowModeChanged(boolean, android.content.res.Configuration);
-    method public deprecated void onMultiWindowModeChanged(boolean);
+    method @Deprecated public void onMultiWindowModeChanged(boolean);
     method public boolean onNavigateUp();
     method public boolean onNavigateUpFromChild(android.app.Activity);
     method protected void onNewIntent(android.content.Intent);
-    method public boolean onOptionsItemSelected(android.view.MenuItem);
+    method public boolean onOptionsItemSelected(@NonNull android.view.MenuItem);
     method public void onOptionsMenuClosed(android.view.Menu);
-    method public void onPanelClosed(int, android.view.Menu);
-    method protected void onPause();
+    method public void onPanelClosed(int, @NonNull android.view.Menu);
+    method @CallSuper protected void onPause();
     method public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration);
-    method public deprecated void onPictureInPictureModeChanged(boolean);
-    method protected void onPostCreate(android.os.Bundle);
-    method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
-    method protected void onPostResume();
-    method protected deprecated void onPrepareDialog(int, android.app.Dialog);
-    method protected deprecated void onPrepareDialog(int, android.app.Dialog, android.os.Bundle);
+    method @Deprecated public void onPictureInPictureModeChanged(boolean);
+    method @CallSuper protected void onPostCreate(@Nullable android.os.Bundle);
+    method public void onPostCreate(@Nullable android.os.Bundle, @Nullable android.os.PersistableBundle);
+    method @CallSuper protected void onPostResume();
+    method @Deprecated protected void onPrepareDialog(int, android.app.Dialog);
+    method @Deprecated protected void onPrepareDialog(int, android.app.Dialog, android.os.Bundle);
     method public void onPrepareNavigateUpTaskStack(android.app.TaskStackBuilder);
     method public boolean onPrepareOptionsMenu(android.view.Menu);
-    method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
+    method public boolean onPreparePanel(int, @Nullable android.view.View, @NonNull android.view.Menu);
     method public void onProvideAssistContent(android.app.assist.AssistContent);
     method public void onProvideAssistData(android.os.Bundle);
     method public android.net.Uri onProvideReferrer();
-    method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
-    method protected void onRestart();
-    method protected void onRestoreInstanceState(android.os.Bundle);
-    method public void onRestoreInstanceState(android.os.Bundle, android.os.PersistableBundle);
-    method protected void onResume();
-    method public java.lang.Object onRetainNonConfigurationInstance();
-    method protected void onSaveInstanceState(android.os.Bundle);
-    method public void onSaveInstanceState(android.os.Bundle, android.os.PersistableBundle);
-    method public boolean onSearchRequested(android.view.SearchEvent);
+    method public void onRequestPermissionsResult(int, @NonNull String[], @NonNull int[]);
+    method @CallSuper protected void onRestart();
+    method protected void onRestoreInstanceState(@NonNull android.os.Bundle);
+    method public void onRestoreInstanceState(@Nullable android.os.Bundle, @Nullable android.os.PersistableBundle);
+    method @CallSuper protected void onResume();
+    method public Object onRetainNonConfigurationInstance();
+    method protected void onSaveInstanceState(@NonNull android.os.Bundle);
+    method public void onSaveInstanceState(@NonNull android.os.Bundle, @NonNull android.os.PersistableBundle);
+    method public boolean onSearchRequested(@Nullable android.view.SearchEvent);
     method public boolean onSearchRequested();
-    method protected void onStart();
-    method public deprecated void onStateNotSaved();
-    method protected void onStop();
-    method protected void onTitleChanged(java.lang.CharSequence, int);
+    method @CallSuper protected void onStart();
+    method @Deprecated public void onStateNotSaved();
+    method @CallSuper protected void onStop();
+    method protected void onTitleChanged(CharSequence, int);
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
     method public void onTrimMemory(int);
     method public void onUserInteraction();
     method protected void onUserLeaveHint();
-    method public deprecated void onVisibleBehindCanceled();
+    method @Deprecated @CallSuper public void onVisibleBehindCanceled();
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
     method public void onWindowFocusChanged(boolean);
-    method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
-    method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
+    method @Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
+    method @Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
     method public void openContextMenu(android.view.View);
     method public void openOptionsMenu();
     method public void overridePendingTransition(int, int);
     method public void postponeEnterTransition();
     method public void recreate();
-    method public void registerActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks);
+    method public void registerActivityLifecycleCallbacks(@NonNull android.app.Application.ActivityLifecycleCallbacks);
     method public void registerForContextMenu(android.view.View);
     method public boolean releaseInstance();
-    method public final deprecated void removeDialog(int);
+    method @Deprecated public final void removeDialog(int);
     method public void reportFullyDrawn();
     method public android.view.DragAndDropPermissions requestDragAndDropPermissions(android.view.DragEvent);
-    method public final void requestPermissions(java.lang.String[], int);
+    method public final void requestPermissions(@NonNull String[], int);
     method public final void requestShowKeyboardShortcuts();
-    method public deprecated boolean requestVisibleBehind(boolean);
+    method @Deprecated public boolean requestVisibleBehind(boolean);
     method public final boolean requestWindowFeature(int);
-    method public final <T extends android.view.View> T requireViewById(int);
-    method public final void runOnUiThread(java.lang.Runnable);
-    method public void setActionBar(android.widget.Toolbar);
+    method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
+    method public final void runOnUiThread(Runnable);
+    method public void setActionBar(@Nullable android.widget.Toolbar);
     method public void setContentTransitionManager(android.transition.TransitionManager);
-    method public void setContentView(int);
+    method public void setContentView(@LayoutRes int);
     method public void setContentView(android.view.View);
     method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public final void setDefaultKeyMode(int);
@@ -3836,63 +3839,63 @@
     method public void setExitSharedElementCallback(android.app.SharedElementCallback);
     method public final void setFeatureDrawable(int, android.graphics.drawable.Drawable);
     method public final void setFeatureDrawableAlpha(int, int);
-    method public final void setFeatureDrawableResource(int, int);
+    method public final void setFeatureDrawableResource(int, @DrawableRes int);
     method public final void setFeatureDrawableUri(int, android.net.Uri);
     method public void setFinishOnTouchOutside(boolean);
     method public void setImmersive(boolean);
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
-    method public void setPictureInPictureParams(android.app.PictureInPictureParams);
-    method public final deprecated void setProgress(int);
-    method public final deprecated void setProgressBarIndeterminate(boolean);
-    method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
-    method public final deprecated void setProgressBarVisibility(boolean);
+    method public void setPictureInPictureParams(@NonNull android.app.PictureInPictureParams);
+    method @Deprecated public final void setProgress(int);
+    method @Deprecated public final void setProgressBarIndeterminate(boolean);
+    method @Deprecated public final void setProgressBarIndeterminateVisibility(boolean);
+    method @Deprecated public final void setProgressBarVisibility(boolean);
     method public void setRequestedOrientation(int);
     method public final void setResult(int);
     method public final void setResult(int, android.content.Intent);
-    method public final deprecated void setSecondaryProgress(int);
+    method @Deprecated public final void setSecondaryProgress(int);
     method public void setShowWhenLocked(boolean);
     method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
-    method public void setTitle(java.lang.CharSequence);
+    method public void setTitle(CharSequence);
     method public void setTitle(int);
-    method public deprecated void setTitleColor(int);
+    method @Deprecated public void setTitleColor(int);
     method public void setTurnScreenOn(boolean);
     method public void setVisible(boolean);
     method public final void setVolumeControlStream(int);
-    method public void setVrModeEnabled(boolean, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public boolean shouldShowRequestPermissionRationale(java.lang.String);
+    method public void setVrModeEnabled(boolean, @NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public boolean shouldShowRequestPermissionRationale(@NonNull String);
     method public boolean shouldUpRecreateTask(android.content.Intent);
     method public boolean showAssist(android.os.Bundle);
-    method public final deprecated void showDialog(int);
-    method public final deprecated boolean showDialog(int, android.os.Bundle);
+    method @Deprecated public final void showDialog(int);
+    method @Deprecated public final boolean showDialog(int, android.os.Bundle);
     method public void showLockTaskEscapeMessage();
-    method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
-    method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int);
-    method public void startActivityForResult(android.content.Intent, int);
-    method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
-    method public void startActivityFromChild(android.app.Activity, android.content.Intent, int);
-    method public void startActivityFromChild(android.app.Activity, android.content.Intent, int, android.os.Bundle);
-    method public deprecated void startActivityFromFragment(android.app.Fragment, android.content.Intent, int);
-    method public deprecated void startActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
-    method public boolean startActivityIfNeeded(android.content.Intent, int);
-    method public boolean startActivityIfNeeded(android.content.Intent, int, android.os.Bundle);
-    method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
-    method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method @Nullable public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
+    method @Nullable public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int);
+    method public void startActivityForResult(@RequiresPermission android.content.Intent, int);
+    method public void startActivityForResult(@RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle);
+    method public void startActivityFromChild(@NonNull android.app.Activity, @RequiresPermission android.content.Intent, int);
+    method public void startActivityFromChild(@NonNull android.app.Activity, @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle);
+    method @Deprecated public void startActivityFromFragment(@NonNull android.app.Fragment, @RequiresPermission android.content.Intent, int);
+    method @Deprecated public void startActivityFromFragment(@NonNull android.app.Fragment, @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle);
+    method public boolean startActivityIfNeeded(@RequiresPermission @NonNull android.content.Intent, int);
+    method public boolean startActivityIfNeeded(@RequiresPermission @NonNull android.content.Intent, int, @Nullable android.os.Bundle);
+    method public void startIntentSenderForResult(android.content.IntentSender, int, @Nullable android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
+    method public void startIntentSenderForResult(android.content.IntentSender, int, @Nullable android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
-    method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, @Nullable android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public void startLocalVoiceInteraction(android.os.Bundle);
     method public void startLockTask();
-    method public deprecated void startManagingCursor(android.database.Cursor);
-    method public boolean startNextMatchingActivity(android.content.Intent);
-    method public boolean startNextMatchingActivity(android.content.Intent, android.os.Bundle);
+    method @Deprecated public void startManagingCursor(android.database.Cursor);
+    method public boolean startNextMatchingActivity(@RequiresPermission @NonNull android.content.Intent);
+    method public boolean startNextMatchingActivity(@RequiresPermission @NonNull android.content.Intent, @Nullable android.os.Bundle);
     method public void startPostponedEnterTransition();
-    method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
+    method public void startSearch(@Nullable String, boolean, @Nullable android.os.Bundle, boolean);
     method public void stopLocalVoiceInteraction();
     method public void stopLockTask();
-    method public deprecated void stopManagingCursor(android.database.Cursor);
+    method @Deprecated public void stopManagingCursor(android.database.Cursor);
     method public void takeKeyEvents(boolean);
-    method public void triggerSearch(java.lang.String, android.os.Bundle);
-    method public void unregisterActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks);
+    method public void triggerSearch(String, @Nullable android.os.Bundle);
+    method public void unregisterActivityLifecycleCallbacks(@NonNull android.app.Application.ActivityLifecycleCallbacks);
     method public void unregisterForContextMenu(android.view.View);
     field public static final int DEFAULT_KEYS_DIALER = 1; // 0x1
     field public static final int DEFAULT_KEYS_DISABLE = 0; // 0x0
@@ -3905,18 +3908,18 @@
     field public static final int RESULT_OK = -1; // 0xffffffff
   }
 
-  public deprecated class ActivityGroup extends android.app.Activity {
-    ctor public ActivityGroup();
-    ctor public ActivityGroup(boolean);
-    method public android.app.Activity getCurrentActivity();
-    method public final android.app.LocalActivityManager getLocalActivityManager();
+  @Deprecated public class ActivityGroup extends android.app.Activity {
+    ctor @Deprecated public ActivityGroup();
+    ctor @Deprecated public ActivityGroup(boolean);
+    method @Deprecated public android.app.Activity getCurrentActivity();
+    method @Deprecated public final android.app.LocalActivityManager getLocalActivityManager();
   }
 
   public class ActivityManager {
-    method public int addAppTask(android.app.Activity, android.content.Intent, android.app.ActivityManager.TaskDescription, android.graphics.Bitmap);
+    method public int addAppTask(@NonNull android.app.Activity, @NonNull android.content.Intent, @Nullable android.app.ActivityManager.TaskDescription, @NonNull android.graphics.Bitmap);
     method public boolean clearApplicationUserData();
     method public void clearWatchHeapLimit();
-    method public void dumpPackageState(java.io.FileDescriptor, java.lang.String);
+    method @RequiresPermission(android.Manifest.permission.DUMP) public void dumpPackageState(java.io.FileDescriptor, String);
     method public android.util.Size getAppTaskThumbnailSize();
     method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
     method public android.content.pm.ConfigurationInfo getDeviceConfigurationInfo();
@@ -3929,28 +3932,29 @@
     method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
     method public android.os.Debug.MemoryInfo[] getProcessMemoryInfo(int[]);
     method public java.util.List<android.app.ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState();
-    method public deprecated java.util.List<android.app.ActivityManager.RecentTaskInfo> getRecentTasks(int, int) throws java.lang.SecurityException;
+    method @Deprecated public java.util.List<android.app.ActivityManager.RecentTaskInfo> getRecentTasks(int, int) throws java.lang.SecurityException;
     method public java.util.List<android.app.ActivityManager.RunningAppProcessInfo> getRunningAppProcesses();
     method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException;
-    method public deprecated java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException;
-    method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException;
+    method @Deprecated public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException;
+    method @Deprecated public java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException;
     method public boolean isActivityStartAllowedOnDisplay(android.content.Context, int, android.content.Intent);
     method public boolean isBackgroundRestricted();
-    method public deprecated boolean isInLockTaskMode();
+    method @Deprecated public boolean isInLockTaskMode();
     method public boolean isLowRamDevice();
-    method public static boolean isRunningInTestHarness();
+    method @Deprecated public static boolean isRunningInTestHarness();
+    method public static boolean isRunningInUserTestHarness();
     method public static boolean isUserAMonkey();
-    method public void killBackgroundProcesses(java.lang.String);
-    method public void moveTaskToFront(int, int);
-    method public void moveTaskToFront(int, int, android.os.Bundle);
-    method public deprecated void restartPackage(java.lang.String);
+    method @RequiresPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES) public void killBackgroundProcesses(String);
+    method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int);
+    method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int, android.os.Bundle);
+    method @Deprecated public void restartPackage(String);
     method public static void setVrThread(int);
     method public void setWatchHeapLimit(long);
-    field public static final java.lang.String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
+    field public static final String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
     field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
     field public static final int LOCK_TASK_MODE_NONE = 0; // 0x0
     field public static final int LOCK_TASK_MODE_PINNED = 2; // 0x2
-    field public static final java.lang.String META_HOME_ALTERNATE = "android.app.home.alternate";
+    field public static final String META_HOME_ALTERNATE = "android.app.home.alternate";
     field public static final int MOVE_TASK_NO_USER_ACTION = 2; // 0x2
     field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
     field public static final int RECENT_IGNORE_UNAVAILABLE = 2; // 0x2
@@ -3988,12 +3992,12 @@
     field public static final int NO_ERROR = 0; // 0x0
     field public int condition;
     field public byte[] crashData;
-    field public java.lang.String longMsg;
+    field public String longMsg;
     field public int pid;
-    field public java.lang.String processName;
-    field public java.lang.String shortMsg;
-    field public java.lang.String stackTrace;
-    field public java.lang.String tag;
+    field public String processName;
+    field public String shortMsg;
+    field public String stackTrace;
+    field public String tag;
     field public int uid;
   }
 
@@ -4003,23 +4007,23 @@
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.ActivityManager.RecentTaskInfo> CREATOR;
-    field public deprecated int affiliatedTaskId;
-    field public deprecated java.lang.CharSequence description;
-    field public deprecated int id;
-    field public deprecated int persistentId;
+    field @Deprecated public int affiliatedTaskId;
+    field @Deprecated public CharSequence description;
+    field @Deprecated public int id;
+    field @Deprecated public int persistentId;
   }
 
   public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable {
     ctor public ActivityManager.RunningAppProcessInfo();
-    ctor public ActivityManager.RunningAppProcessInfo(java.lang.String, int, java.lang.String[]);
+    ctor public ActivityManager.RunningAppProcessInfo(String, int, String[]);
     method public int describeContents();
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.ActivityManager.RunningAppProcessInfo> CREATOR;
-    field public static final deprecated int IMPORTANCE_BACKGROUND = 400; // 0x190
+    field @Deprecated public static final int IMPORTANCE_BACKGROUND = 400; // 0x190
     field public static final int IMPORTANCE_CACHED = 400; // 0x190
     field public static final int IMPORTANCE_CANT_SAVE_STATE = 350; // 0x15e
-    field public static final deprecated int IMPORTANCE_EMPTY = 500; // 0x1f4
+    field @Deprecated public static final int IMPORTANCE_EMPTY = 500; // 0x1f4
     field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64
     field public static final int IMPORTANCE_FOREGROUND_SERVICE = 125; // 0x7d
     field public static final int IMPORTANCE_GONE = 1000; // 0x3e8
@@ -4027,7 +4031,7 @@
     field public static final int IMPORTANCE_PERCEPTIBLE_PRE_26 = 130; // 0x82
     field public static final int IMPORTANCE_SERVICE = 300; // 0x12c
     field public static final int IMPORTANCE_TOP_SLEEPING = 325; // 0x145
-    field public static final deprecated int IMPORTANCE_TOP_SLEEPING_PRE_28 = 150; // 0x96
+    field @Deprecated public static final int IMPORTANCE_TOP_SLEEPING_PRE_28 = 150; // 0x96
     field public static final int IMPORTANCE_VISIBLE = 200; // 0xc8
     field public static final int REASON_PROVIDER_IN_USE = 1; // 0x1
     field public static final int REASON_SERVICE_IN_USE = 2; // 0x2
@@ -4039,8 +4043,8 @@
     field public int lastTrimLevel;
     field public int lru;
     field public int pid;
-    field public java.lang.String[] pkgList;
-    field public java.lang.String processName;
+    field public String[] pkgList;
+    field public String processName;
     field public int uid;
   }
 
@@ -4057,13 +4061,13 @@
     field public long activeSince;
     field public int clientCount;
     field public int clientLabel;
-    field public java.lang.String clientPackage;
+    field public String clientPackage;
     field public int crashCount;
     field public int flags;
     field public boolean foreground;
     field public long lastActivityTime;
     field public int pid;
-    field public java.lang.String process;
+    field public String process;
     field public long restarting;
     field public android.content.ComponentName service;
     field public boolean started;
@@ -4076,23 +4080,23 @@
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.ActivityManager.RunningTaskInfo> CREATOR;
-    field public deprecated java.lang.CharSequence description;
-    field public deprecated int id;
-    field public deprecated int numRunning;
-    field public deprecated android.graphics.Bitmap thumbnail;
+    field @Deprecated public CharSequence description;
+    field @Deprecated public int id;
+    field @Deprecated public int numRunning;
+    field @Deprecated public android.graphics.Bitmap thumbnail;
   }
 
   public static class ActivityManager.TaskDescription implements android.os.Parcelable {
-    ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
-    ctor public ActivityManager.TaskDescription(java.lang.String, int, int);
-    ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
-    ctor public ActivityManager.TaskDescription(java.lang.String, int);
-    ctor public ActivityManager.TaskDescription(java.lang.String);
+    ctor @Deprecated public ActivityManager.TaskDescription(String, android.graphics.Bitmap, int);
+    ctor public ActivityManager.TaskDescription(String, @DrawableRes int, int);
+    ctor @Deprecated public ActivityManager.TaskDescription(String, android.graphics.Bitmap);
+    ctor public ActivityManager.TaskDescription(String, @DrawableRes int);
+    ctor public ActivityManager.TaskDescription(String);
     ctor public ActivityManager.TaskDescription();
     ctor public ActivityManager.TaskDescription(android.app.ActivityManager.TaskDescription);
     method public int describeContents();
     method public android.graphics.Bitmap getIcon();
-    method public java.lang.String getLabel();
+    method public String getLabel();
     method public int getPrimaryColor();
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
@@ -4100,26 +4104,26 @@
   }
 
   public class ActivityOptions {
-    method public android.graphics.Rect getLaunchBounds();
+    method @Nullable public android.graphics.Rect getLaunchBounds();
     method public int getLaunchDisplayId();
     method public boolean getLockTaskMode();
     method public static android.app.ActivityOptions makeBasic();
     method public static android.app.ActivityOptions makeClipRevealAnimation(android.view.View, int, int, int, int);
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
     method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
-    method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.app.Activity, android.view.View, java.lang.String);
-    method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.app.Activity, android.util.Pair<android.view.View, java.lang.String>...);
+    method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.app.Activity, android.view.View, String);
+    method @java.lang.SafeVarargs public static android.app.ActivityOptions makeSceneTransitionAnimation(android.app.Activity, android.util.Pair<android.view.View,java.lang.String>...);
     method public static android.app.ActivityOptions makeTaskLaunchBehind();
     method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
     method public void requestUsageTimeReport(android.app.PendingIntent);
     method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle);
-    method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
+    method public android.app.ActivityOptions setLaunchBounds(@Nullable android.graphics.Rect);
     method public android.app.ActivityOptions setLaunchDisplayId(int);
     method public android.app.ActivityOptions setLockTaskEnabled(boolean);
     method public android.os.Bundle toBundle();
     method public void update(android.app.ActivityOptions);
-    field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
-    field public static final java.lang.String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
+    field public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
+    field public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
   }
 
   public class AlarmManager {
@@ -4127,19 +4131,19 @@
     method public void cancel(android.app.AlarmManager.OnAlarmListener);
     method public android.app.AlarmManager.AlarmClockInfo getNextAlarmClock();
     method public void set(int, long, android.app.PendingIntent);
-    method public void set(int, long, java.lang.String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
+    method public void set(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
     method public void setAlarmClock(android.app.AlarmManager.AlarmClockInfo, android.app.PendingIntent);
     method public void setAndAllowWhileIdle(int, long, android.app.PendingIntent);
     method public void setExact(int, long, android.app.PendingIntent);
-    method public void setExact(int, long, java.lang.String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
+    method public void setExact(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
     method public void setExactAndAllowWhileIdle(int, long, android.app.PendingIntent);
     method public void setInexactRepeating(int, long, long, android.app.PendingIntent);
     method public void setRepeating(int, long, long, android.app.PendingIntent);
-    method public void setTime(long);
-    method public void setTimeZone(java.lang.String);
+    method @RequiresPermission(android.Manifest.permission.SET_TIME) public void setTime(long);
+    method @RequiresPermission(android.Manifest.permission.SET_TIME_ZONE) public void setTimeZone(String);
     method public void setWindow(int, long, long, android.app.PendingIntent);
-    method public void setWindow(int, long, long, java.lang.String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
-    field public static final java.lang.String ACTION_NEXT_ALARM_CLOCK_CHANGED = "android.app.action.NEXT_ALARM_CLOCK_CHANGED";
+    method public void setWindow(int, long, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
+    field public static final String ACTION_NEXT_ALARM_CLOCK_CHANGED = "android.app.action.NEXT_ALARM_CLOCK_CHANGED";
     field public static final int ELAPSED_REALTIME = 3; // 0x3
     field public static final int ELAPSED_REALTIME_WAKEUP = 2; // 0x2
     field public static final long INTERVAL_DAY = 86400000L; // 0x5265c00L
@@ -4160,37 +4164,37 @@
     field public static final android.os.Parcelable.Creator<android.app.AlarmManager.AlarmClockInfo> CREATOR;
   }
 
-  public static abstract interface AlarmManager.OnAlarmListener {
-    method public abstract void onAlarm();
+  public static interface AlarmManager.OnAlarmListener {
+    method public void onAlarm();
   }
 
   public class AlertDialog extends android.app.Dialog implements android.content.DialogInterface {
     ctor protected AlertDialog(android.content.Context);
     ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
-    ctor protected AlertDialog(android.content.Context, int);
+    ctor protected AlertDialog(android.content.Context, @StyleRes int);
     method public android.widget.Button getButton(int);
     method public android.widget.ListView getListView();
-    method public void setButton(int, java.lang.CharSequence, android.os.Message);
-    method public void setButton(int, java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
-    method public deprecated void setButton(java.lang.CharSequence, android.os.Message);
-    method public deprecated void setButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
-    method public deprecated void setButton2(java.lang.CharSequence, android.os.Message);
-    method public deprecated void setButton2(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
-    method public deprecated void setButton3(java.lang.CharSequence, android.os.Message);
-    method public deprecated void setButton3(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public void setButton(int, CharSequence, android.os.Message);
+    method public void setButton(int, CharSequence, android.content.DialogInterface.OnClickListener);
+    method @Deprecated public void setButton(CharSequence, android.os.Message);
+    method @Deprecated public void setButton(CharSequence, android.content.DialogInterface.OnClickListener);
+    method @Deprecated public void setButton2(CharSequence, android.os.Message);
+    method @Deprecated public void setButton2(CharSequence, android.content.DialogInterface.OnClickListener);
+    method @Deprecated public void setButton3(CharSequence, android.os.Message);
+    method @Deprecated public void setButton3(CharSequence, android.content.DialogInterface.OnClickListener);
     method public void setCustomTitle(android.view.View);
-    method public void setIcon(int);
+    method public void setIcon(@DrawableRes int);
     method public void setIcon(android.graphics.drawable.Drawable);
-    method public void setIconAttribute(int);
+    method public void setIconAttribute(@AttrRes int);
     method public void setInverseBackgroundForced(boolean);
-    method public void setMessage(java.lang.CharSequence);
+    method public void setMessage(CharSequence);
     method public void setView(android.view.View);
     method public void setView(android.view.View, int, int, int, int);
-    field public static final deprecated int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
-    field public static final deprecated int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
-    field public static final deprecated int THEME_HOLO_DARK = 2; // 0x2
-    field public static final deprecated int THEME_HOLO_LIGHT = 3; // 0x3
-    field public static final deprecated int THEME_TRADITIONAL = 1; // 0x1
+    field @Deprecated public static final int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
+    field @Deprecated public static final int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
+    field @Deprecated public static final int THEME_HOLO_DARK = 2; // 0x2
+    field @Deprecated public static final int THEME_HOLO_LIGHT = 3; // 0x3
+    field @Deprecated public static final int THEME_TRADITIONAL = 1; // 0x1
   }
 
   public static class AlertDialog.Builder {
@@ -4200,35 +4204,35 @@
     method public android.content.Context getContext();
     method public android.app.AlertDialog.Builder setAdapter(android.widget.ListAdapter, android.content.DialogInterface.OnClickListener);
     method public android.app.AlertDialog.Builder setCancelable(boolean);
-    method public android.app.AlertDialog.Builder setCursor(android.database.Cursor, android.content.DialogInterface.OnClickListener, java.lang.String);
+    method public android.app.AlertDialog.Builder setCursor(android.database.Cursor, android.content.DialogInterface.OnClickListener, String);
     method public android.app.AlertDialog.Builder setCustomTitle(android.view.View);
-    method public android.app.AlertDialog.Builder setIcon(int);
+    method public android.app.AlertDialog.Builder setIcon(@DrawableRes int);
     method public android.app.AlertDialog.Builder setIcon(android.graphics.drawable.Drawable);
-    method public android.app.AlertDialog.Builder setIconAttribute(int);
-    method public deprecated android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
-    method public android.app.AlertDialog.Builder setItems(int, android.content.DialogInterface.OnClickListener);
-    method public android.app.AlertDialog.Builder setItems(java.lang.CharSequence[], android.content.DialogInterface.OnClickListener);
-    method public android.app.AlertDialog.Builder setMessage(int);
-    method public android.app.AlertDialog.Builder setMessage(java.lang.CharSequence);
-    method public android.app.AlertDialog.Builder setMultiChoiceItems(int, boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
-    method public android.app.AlertDialog.Builder setMultiChoiceItems(java.lang.CharSequence[], boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
-    method public android.app.AlertDialog.Builder setMultiChoiceItems(android.database.Cursor, java.lang.String, java.lang.String, android.content.DialogInterface.OnMultiChoiceClickListener);
-    method public android.app.AlertDialog.Builder setNegativeButton(int, android.content.DialogInterface.OnClickListener);
-    method public android.app.AlertDialog.Builder setNegativeButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
-    method public android.app.AlertDialog.Builder setNeutralButton(int, android.content.DialogInterface.OnClickListener);
-    method public android.app.AlertDialog.Builder setNeutralButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
+    method public android.app.AlertDialog.Builder setIconAttribute(@AttrRes int);
+    method @Deprecated public android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
+    method public android.app.AlertDialog.Builder setItems(@ArrayRes int, android.content.DialogInterface.OnClickListener);
+    method public android.app.AlertDialog.Builder setItems(CharSequence[], android.content.DialogInterface.OnClickListener);
+    method public android.app.AlertDialog.Builder setMessage(@StringRes int);
+    method public android.app.AlertDialog.Builder setMessage(CharSequence);
+    method public android.app.AlertDialog.Builder setMultiChoiceItems(@ArrayRes int, boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
+    method public android.app.AlertDialog.Builder setMultiChoiceItems(CharSequence[], boolean[], android.content.DialogInterface.OnMultiChoiceClickListener);
+    method public android.app.AlertDialog.Builder setMultiChoiceItems(android.database.Cursor, String, String, android.content.DialogInterface.OnMultiChoiceClickListener);
+    method public android.app.AlertDialog.Builder setNegativeButton(@StringRes int, android.content.DialogInterface.OnClickListener);
+    method public android.app.AlertDialog.Builder setNegativeButton(CharSequence, android.content.DialogInterface.OnClickListener);
+    method public android.app.AlertDialog.Builder setNeutralButton(@StringRes int, android.content.DialogInterface.OnClickListener);
+    method public android.app.AlertDialog.Builder setNeutralButton(CharSequence, android.content.DialogInterface.OnClickListener);
     method public android.app.AlertDialog.Builder setOnCancelListener(android.content.DialogInterface.OnCancelListener);
     method public android.app.AlertDialog.Builder setOnDismissListener(android.content.DialogInterface.OnDismissListener);
     method public android.app.AlertDialog.Builder setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
     method public android.app.AlertDialog.Builder setOnKeyListener(android.content.DialogInterface.OnKeyListener);
-    method public android.app.AlertDialog.Builder setPositiveButton(int, android.content.DialogInterface.OnClickListener);
-    method public android.app.AlertDialog.Builder setPositiveButton(java.lang.CharSequence, android.content.DialogInterface.OnClickListener);
-    method public android.app.AlertDialog.Builder setSingleChoiceItems(int, int, android.content.DialogInterface.OnClickListener);
-    method public android.app.AlertDialog.Builder setSingleChoiceItems(android.database.Cursor, int, java.lang.String, android.content.DialogInterface.OnClickListener);
-    method public android.app.AlertDialog.Builder setSingleChoiceItems(java.lang.CharSequence[], int, android.content.DialogInterface.OnClickListener);
+    method public android.app.AlertDialog.Builder setPositiveButton(@StringRes int, android.content.DialogInterface.OnClickListener);
+    method public android.app.AlertDialog.Builder setPositiveButton(CharSequence, android.content.DialogInterface.OnClickListener);
+    method public android.app.AlertDialog.Builder setSingleChoiceItems(@ArrayRes int, int, android.content.DialogInterface.OnClickListener);
+    method public android.app.AlertDialog.Builder setSingleChoiceItems(android.database.Cursor, int, String, android.content.DialogInterface.OnClickListener);
+    method public android.app.AlertDialog.Builder setSingleChoiceItems(CharSequence[], int, android.content.DialogInterface.OnClickListener);
     method public android.app.AlertDialog.Builder setSingleChoiceItems(android.widget.ListAdapter, int, android.content.DialogInterface.OnClickListener);
-    method public android.app.AlertDialog.Builder setTitle(int);
-    method public android.app.AlertDialog.Builder setTitle(java.lang.CharSequence);
+    method public android.app.AlertDialog.Builder setTitle(@StringRes int);
+    method public android.app.AlertDialog.Builder setTitle(CharSequence);
     method public android.app.AlertDialog.Builder setView(int);
     method public android.app.AlertDialog.Builder setView(android.view.View);
     method public android.app.AlertDialog show();
@@ -4241,125 +4245,125 @@
   public class AppComponentFactory {
     ctor public AppComponentFactory();
     method public android.content.pm.ApplicationInfo getApplicationInfo();
-    method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
-    method public android.app.Application instantiateApplication(java.lang.ClassLoader, java.lang.String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
-    method public java.lang.ClassLoader instantiateClassLoader(java.lang.ClassLoader);
-    method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
-    method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
-    method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method @NonNull public android.app.Activity instantiateActivity(@NonNull ClassLoader, @NonNull String, @Nullable android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method @NonNull public android.app.Application instantiateApplication(@NonNull ClassLoader, @NonNull String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method @NonNull public ClassLoader instantiateClassLoader(@NonNull ClassLoader);
+    method @NonNull public android.content.ContentProvider instantiateProvider(@NonNull ClassLoader, @NonNull String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method @NonNull public android.content.BroadcastReceiver instantiateReceiver(@NonNull ClassLoader, @NonNull String, @Nullable android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method @NonNull public android.app.Service instantiateService(@NonNull ClassLoader, @NonNull String, @Nullable android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
   public class AppOpsManager {
-    method public deprecated int checkOp(java.lang.String, int, java.lang.String);
-    method public deprecated int checkOpNoThrow(java.lang.String, int, java.lang.String);
-    method public void checkPackage(int, java.lang.String);
-    method public void finishOp(java.lang.String, int, java.lang.String);
-    method public int noteOp(java.lang.String, int, java.lang.String);
-    method public int noteOpNoThrow(java.lang.String, int, java.lang.String);
-    method public int noteProxyOp(java.lang.String, java.lang.String);
-    method public int noteProxyOpNoThrow(java.lang.String, java.lang.String);
-    method public static java.lang.String permissionToOp(java.lang.String);
-    method public int startOp(java.lang.String, int, java.lang.String);
-    method public int startOpNoThrow(java.lang.String, int, java.lang.String);
-    method public void startWatchingMode(java.lang.String, java.lang.String, android.app.AppOpsManager.OnOpChangedListener);
-    method public void startWatchingMode(java.lang.String, java.lang.String, int, android.app.AppOpsManager.OnOpChangedListener);
+    method @Deprecated public int checkOp(String, int, String);
+    method @Deprecated public int checkOpNoThrow(String, int, String);
+    method public void checkPackage(int, String);
+    method public void finishOp(String, int, String);
+    method public int noteOp(String, int, String);
+    method public int noteOpNoThrow(String, int, String);
+    method public int noteProxyOp(String, String);
+    method public int noteProxyOpNoThrow(String, String);
+    method public static String permissionToOp(String);
+    method public int startOp(String, int, String);
+    method public int startOpNoThrow(String, int, String);
+    method public void startWatchingMode(String, String, android.app.AppOpsManager.OnOpChangedListener);
+    method public void startWatchingMode(String, String, int, android.app.AppOpsManager.OnOpChangedListener);
     method public void stopWatchingMode(android.app.AppOpsManager.OnOpChangedListener);
-    method public int unsafeCheckOp(java.lang.String, int, java.lang.String);
-    method public int unsafeCheckOpNoThrow(java.lang.String, int, java.lang.String);
-    method public int unsafeCheckOpRaw(java.lang.String, int, java.lang.String);
+    method public int unsafeCheckOp(String, int, String);
+    method public int unsafeCheckOpNoThrow(String, int, String);
+    method public int unsafeCheckOpRaw(String, int, String);
     field public static final int MODE_ALLOWED = 0; // 0x0
     field public static final int MODE_DEFAULT = 3; // 0x3
     field public static final int MODE_ERRORED = 2; // 0x2
     field public static final int MODE_FOREGROUND = 4; // 0x4
     field public static final int MODE_IGNORED = 1; // 0x1
-    field public static final java.lang.String OPSTR_ADD_VOICEMAIL = "android:add_voicemail";
-    field public static final java.lang.String OPSTR_ANSWER_PHONE_CALLS = "android:answer_phone_calls";
-    field public static final java.lang.String OPSTR_BODY_SENSORS = "android:body_sensors";
-    field public static final java.lang.String OPSTR_CALL_PHONE = "android:call_phone";
-    field public static final java.lang.String OPSTR_CAMERA = "android:camera";
-    field public static final java.lang.String OPSTR_COARSE_LOCATION = "android:coarse_location";
-    field public static final java.lang.String OPSTR_FINE_LOCATION = "android:fine_location";
-    field public static final java.lang.String OPSTR_GET_USAGE_STATS = "android:get_usage_stats";
-    field public static final java.lang.String OPSTR_MOCK_LOCATION = "android:mock_location";
-    field public static final java.lang.String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power";
-    field public static final java.lang.String OPSTR_MONITOR_LOCATION = "android:monitor_location";
-    field public static final java.lang.String OPSTR_PICTURE_IN_PICTURE = "android:picture_in_picture";
-    field public static final java.lang.String OPSTR_PROCESS_OUTGOING_CALLS = "android:process_outgoing_calls";
-    field public static final java.lang.String OPSTR_READ_CALENDAR = "android:read_calendar";
-    field public static final java.lang.String OPSTR_READ_CALL_LOG = "android:read_call_log";
-    field public static final java.lang.String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts";
-    field public static final java.lang.String OPSTR_READ_CONTACTS = "android:read_contacts";
-    field public static final java.lang.String OPSTR_READ_EXTERNAL_STORAGE = "android:read_external_storage";
-    field public static final java.lang.String OPSTR_READ_PHONE_NUMBERS = "android:read_phone_numbers";
-    field public static final java.lang.String OPSTR_READ_PHONE_STATE = "android:read_phone_state";
-    field public static final java.lang.String OPSTR_READ_SMS = "android:read_sms";
-    field public static final java.lang.String OPSTR_RECEIVE_MMS = "android:receive_mms";
-    field public static final java.lang.String OPSTR_RECEIVE_SMS = "android:receive_sms";
-    field public static final java.lang.String OPSTR_RECEIVE_WAP_PUSH = "android:receive_wap_push";
-    field public static final java.lang.String OPSTR_RECORD_AUDIO = "android:record_audio";
-    field public static final java.lang.String OPSTR_SEND_SMS = "android:send_sms";
-    field public static final java.lang.String OPSTR_SYSTEM_ALERT_WINDOW = "android:system_alert_window";
-    field public static final java.lang.String OPSTR_USE_FINGERPRINT = "android:use_fingerprint";
-    field public static final java.lang.String OPSTR_USE_SIP = "android:use_sip";
-    field public static final java.lang.String OPSTR_WRITE_CALENDAR = "android:write_calendar";
-    field public static final java.lang.String OPSTR_WRITE_CALL_LOG = "android:write_call_log";
-    field public static final java.lang.String OPSTR_WRITE_CONTACTS = "android:write_contacts";
-    field public static final java.lang.String OPSTR_WRITE_EXTERNAL_STORAGE = "android:write_external_storage";
-    field public static final java.lang.String OPSTR_WRITE_SETTINGS = "android:write_settings";
+    field public static final String OPSTR_ADD_VOICEMAIL = "android:add_voicemail";
+    field public static final String OPSTR_ANSWER_PHONE_CALLS = "android:answer_phone_calls";
+    field public static final String OPSTR_BODY_SENSORS = "android:body_sensors";
+    field public static final String OPSTR_CALL_PHONE = "android:call_phone";
+    field public static final String OPSTR_CAMERA = "android:camera";
+    field public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
+    field public static final String OPSTR_FINE_LOCATION = "android:fine_location";
+    field public static final String OPSTR_GET_USAGE_STATS = "android:get_usage_stats";
+    field public static final String OPSTR_MOCK_LOCATION = "android:mock_location";
+    field public static final String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power";
+    field public static final String OPSTR_MONITOR_LOCATION = "android:monitor_location";
+    field public static final String OPSTR_PICTURE_IN_PICTURE = "android:picture_in_picture";
+    field public static final String OPSTR_PROCESS_OUTGOING_CALLS = "android:process_outgoing_calls";
+    field public static final String OPSTR_READ_CALENDAR = "android:read_calendar";
+    field public static final String OPSTR_READ_CALL_LOG = "android:read_call_log";
+    field public static final String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts";
+    field public static final String OPSTR_READ_CONTACTS = "android:read_contacts";
+    field public static final String OPSTR_READ_EXTERNAL_STORAGE = "android:read_external_storage";
+    field public static final String OPSTR_READ_PHONE_NUMBERS = "android:read_phone_numbers";
+    field public static final String OPSTR_READ_PHONE_STATE = "android:read_phone_state";
+    field public static final String OPSTR_READ_SMS = "android:read_sms";
+    field public static final String OPSTR_RECEIVE_MMS = "android:receive_mms";
+    field public static final String OPSTR_RECEIVE_SMS = "android:receive_sms";
+    field public static final String OPSTR_RECEIVE_WAP_PUSH = "android:receive_wap_push";
+    field public static final String OPSTR_RECORD_AUDIO = "android:record_audio";
+    field public static final String OPSTR_SEND_SMS = "android:send_sms";
+    field public static final String OPSTR_SYSTEM_ALERT_WINDOW = "android:system_alert_window";
+    field public static final String OPSTR_USE_FINGERPRINT = "android:use_fingerprint";
+    field public static final String OPSTR_USE_SIP = "android:use_sip";
+    field public static final String OPSTR_WRITE_CALENDAR = "android:write_calendar";
+    field public static final String OPSTR_WRITE_CALL_LOG = "android:write_call_log";
+    field public static final String OPSTR_WRITE_CONTACTS = "android:write_contacts";
+    field public static final String OPSTR_WRITE_EXTERNAL_STORAGE = "android:write_external_storage";
+    field public static final String OPSTR_WRITE_SETTINGS = "android:write_settings";
     field public static final int WATCH_FOREGROUND_CHANGES = 1; // 0x1
   }
 
-  public static abstract interface AppOpsManager.OnOpChangedListener {
-    method public abstract void onOpChanged(java.lang.String, java.lang.String);
+  public static interface AppOpsManager.OnOpChangedListener {
+    method public void onOpChanged(String, String);
   }
 
   public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
     ctor public Application();
-    method public static java.lang.String getProcessName();
-    method public void onConfigurationChanged(android.content.res.Configuration);
-    method public void onCreate();
-    method public void onLowMemory();
-    method public void onTerminate();
-    method public void onTrimMemory(int);
+    method public static String getProcessName();
+    method @CallSuper public void onConfigurationChanged(@NonNull android.content.res.Configuration);
+    method @CallSuper public void onCreate();
+    method @CallSuper public void onLowMemory();
+    method @CallSuper public void onTerminate();
+    method @CallSuper public void onTrimMemory(int);
     method public void registerActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks);
     method public void registerOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener);
     method public void unregisterActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks);
     method public void unregisterOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener);
   }
 
-  public static abstract interface Application.ActivityLifecycleCallbacks {
-    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);
-    method public abstract void onActivityStopped(android.app.Activity);
+  public static interface Application.ActivityLifecycleCallbacks {
+    method public void onActivityCreated(@NonNull android.app.Activity, @Nullable android.os.Bundle);
+    method public void onActivityDestroyed(@NonNull android.app.Activity);
+    method public void onActivityPaused(@NonNull android.app.Activity);
+    method public default void onActivityPostCreated(@NonNull android.app.Activity, @Nullable android.os.Bundle);
+    method public default void onActivityPostDestroyed(@NonNull android.app.Activity);
+    method public default void onActivityPostPaused(@NonNull android.app.Activity);
+    method public default void onActivityPostResumed(@NonNull android.app.Activity);
+    method public default void onActivityPostSaveInstanceState(@NonNull android.app.Activity, @NonNull android.os.Bundle);
+    method public default void onActivityPostStarted(@NonNull android.app.Activity);
+    method public default void onActivityPostStopped(@NonNull android.app.Activity);
+    method public default void onActivityPreCreated(@NonNull android.app.Activity, @Nullable android.os.Bundle);
+    method public default void onActivityPreDestroyed(@NonNull android.app.Activity);
+    method public default void onActivityPrePaused(@NonNull android.app.Activity);
+    method public default void onActivityPreResumed(@NonNull android.app.Activity);
+    method public default void onActivityPreSaveInstanceState(@NonNull android.app.Activity, @NonNull android.os.Bundle);
+    method public default void onActivityPreStarted(@NonNull android.app.Activity);
+    method public default void onActivityPreStopped(@NonNull android.app.Activity);
+    method public void onActivityResumed(@NonNull android.app.Activity);
+    method public void onActivitySaveInstanceState(@NonNull android.app.Activity, @NonNull android.os.Bundle);
+    method public void onActivityStarted(@NonNull android.app.Activity);
+    method public void onActivityStopped(@NonNull android.app.Activity);
   }
 
-  public static abstract interface Application.OnProvideAssistDataListener {
-    method public abstract void onProvideAssistData(android.app.Activity, android.os.Bundle);
+  public static interface Application.OnProvideAssistDataListener {
+    method public void onProvideAssistData(android.app.Activity, android.os.Bundle);
   }
 
   public class ApplicationErrorReport implements android.os.Parcelable {
     ctor public ApplicationErrorReport();
     method public int describeContents();
-    method public void dump(android.util.Printer, java.lang.String);
-    method public static android.content.ComponentName getErrorReportReceiver(android.content.Context, java.lang.String, int);
+    method public void dump(android.util.Printer, String);
+    method public static android.content.ComponentName getErrorReportReceiver(android.content.Context, String, int);
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.ApplicationErrorReport> CREATOR;
@@ -4371,9 +4375,9 @@
     field public android.app.ApplicationErrorReport.AnrInfo anrInfo;
     field public android.app.ApplicationErrorReport.BatteryInfo batteryInfo;
     field public android.app.ApplicationErrorReport.CrashInfo crashInfo;
-    field public java.lang.String installerPackageName;
-    field public java.lang.String packageName;
-    field public java.lang.String processName;
+    field public String installerPackageName;
+    field public String packageName;
+    field public String processName;
     field public android.app.ApplicationErrorReport.RunningServiceInfo runningServiceInfo;
     field public boolean systemApp;
     field public long time;
@@ -4383,50 +4387,50 @@
   public static class ApplicationErrorReport.AnrInfo {
     ctor public ApplicationErrorReport.AnrInfo();
     ctor public ApplicationErrorReport.AnrInfo(android.os.Parcel);
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(android.util.Printer, String);
     method public void writeToParcel(android.os.Parcel, int);
-    field public java.lang.String activity;
-    field public java.lang.String cause;
-    field public java.lang.String info;
+    field public String activity;
+    field public String cause;
+    field public String info;
   }
 
   public static class ApplicationErrorReport.BatteryInfo {
     ctor public ApplicationErrorReport.BatteryInfo();
     ctor public ApplicationErrorReport.BatteryInfo(android.os.Parcel);
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(android.util.Printer, String);
     method public void writeToParcel(android.os.Parcel, int);
-    field public java.lang.String checkinDetails;
+    field public String checkinDetails;
     field public long durationMicros;
-    field public java.lang.String usageDetails;
+    field public String usageDetails;
     field public int usagePercent;
   }
 
   public static class ApplicationErrorReport.CrashInfo {
     ctor public ApplicationErrorReport.CrashInfo();
-    ctor public ApplicationErrorReport.CrashInfo(java.lang.Throwable);
+    ctor public ApplicationErrorReport.CrashInfo(Throwable);
     ctor public ApplicationErrorReport.CrashInfo(android.os.Parcel);
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(android.util.Printer, String);
     method public void writeToParcel(android.os.Parcel, int);
-    field public java.lang.String exceptionClassName;
-    field public java.lang.String exceptionMessage;
-    field public java.lang.String stackTrace;
-    field public java.lang.String throwClassName;
-    field public java.lang.String throwFileName;
+    field public String exceptionClassName;
+    field public String exceptionMessage;
+    field public String stackTrace;
+    field public String throwClassName;
+    field public String throwFileName;
     field public int throwLineNumber;
-    field public java.lang.String throwMethodName;
+    field public String throwMethodName;
   }
 
   public static class ApplicationErrorReport.RunningServiceInfo {
     ctor public ApplicationErrorReport.RunningServiceInfo();
     ctor public ApplicationErrorReport.RunningServiceInfo(android.os.Parcel);
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(android.util.Printer, String);
     method public void writeToParcel(android.os.Parcel, int);
     field public long durationMillis;
-    field public java.lang.String serviceDetails;
+    field public String serviceDetails;
   }
 
   public final class AuthenticationRequiredException extends java.lang.SecurityException implements android.os.Parcelable {
-    ctor public AuthenticationRequiredException(java.lang.Throwable, android.app.PendingIntent);
+    ctor public AuthenticationRequiredException(Throwable, android.app.PendingIntent);
     method public int describeContents();
     method public android.app.PendingIntent getUserAction();
     method public void writeToParcel(android.os.Parcel, int);
@@ -4434,15 +4438,15 @@
   }
 
   public final class AutomaticZenRule implements android.os.Parcelable {
-    ctor public deprecated AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
-    ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.content.ComponentName, android.net.Uri, android.service.notification.ZenPolicy, int, boolean);
+    ctor @Deprecated public AutomaticZenRule(String, android.content.ComponentName, android.net.Uri, int, boolean);
+    ctor public AutomaticZenRule(String, android.content.ComponentName, android.content.ComponentName, android.net.Uri, android.service.notification.ZenPolicy, int, boolean);
     ctor public AutomaticZenRule(android.os.Parcel);
     method public int describeContents();
     method public android.net.Uri getConditionId();
     method public android.content.ComponentName getConfigurationActivity();
     method public long getCreationTime();
     method public int getInterruptionFilter();
-    method public java.lang.String getName();
+    method public String getName();
     method public android.content.ComponentName getOwner();
     method public android.service.notification.ZenPolicy getZenPolicy();
     method public boolean isEnabled();
@@ -4450,171 +4454,172 @@
     method public void setConfigurationActivity(android.content.ComponentName);
     method public void setEnabled(boolean);
     method public void setInterruptionFilter(int);
-    method public void setName(java.lang.String);
+    method public void setName(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;
   }
 
   public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
-    ctor public DatePickerDialog(android.content.Context);
-    ctor public DatePickerDialog(android.content.Context, int);
-    ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
-    ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
-    method public android.widget.DatePicker getDatePicker();
-    method public void onClick(android.content.DialogInterface, int);
-    method public void onDateChanged(android.widget.DatePicker, int, int, int);
-    method public void setOnDateSetListener(android.app.DatePickerDialog.OnDateSetListener);
+    ctor public DatePickerDialog(@NonNull android.content.Context);
+    ctor public DatePickerDialog(@NonNull android.content.Context, @StyleRes int);
+    ctor public DatePickerDialog(@NonNull android.content.Context, @Nullable android.app.DatePickerDialog.OnDateSetListener, int, int, int);
+    ctor public DatePickerDialog(@NonNull android.content.Context, @StyleRes int, @Nullable android.app.DatePickerDialog.OnDateSetListener, int, int, int);
+    method @NonNull public android.widget.DatePicker getDatePicker();
+    method public void onClick(@NonNull android.content.DialogInterface, int);
+    method public void onDateChanged(@NonNull android.widget.DatePicker, int, int, int);
+    method public void setOnDateSetListener(@Nullable android.app.DatePickerDialog.OnDateSetListener);
     method public void updateDate(int, int, int);
   }
 
-  public static abstract interface DatePickerDialog.OnDateSetListener {
-    method public abstract void onDateSet(android.widget.DatePicker, int, int, int);
+  public static interface DatePickerDialog.OnDateSetListener {
+    method public void onDateSet(android.widget.DatePicker, int, int, int);
   }
 
   public class Dialog implements android.content.DialogInterface android.view.KeyEvent.Callback android.view.View.OnCreateContextMenuListener android.view.Window.Callback {
-    ctor public Dialog(android.content.Context);
-    ctor public Dialog(android.content.Context, int);
-    ctor protected Dialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
-    method public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    ctor public Dialog(@NonNull android.content.Context);
+    ctor public Dialog(@NonNull android.content.Context, @StyleRes int);
+    ctor protected Dialog(@NonNull android.content.Context, boolean, @Nullable android.content.DialogInterface.OnCancelListener);
+    method public void addContentView(@NonNull android.view.View, @Nullable android.view.ViewGroup.LayoutParams);
     method public void cancel();
     method public void closeOptionsMenu();
     method public void create();
     method public void dismiss();
-    method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
-    method public boolean dispatchKeyEvent(android.view.KeyEvent);
-    method public boolean dispatchKeyShortcutEvent(android.view.KeyEvent);
-    method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public boolean dispatchTouchEvent(android.view.MotionEvent);
-    method public boolean dispatchTrackballEvent(android.view.MotionEvent);
-    method public <T extends android.view.View> T findViewById(int);
-    method public android.app.ActionBar getActionBar();
-    method public final android.content.Context getContext();
-    method public android.view.View getCurrentFocus();
-    method public android.view.LayoutInflater getLayoutInflater();
-    method public final android.app.Activity getOwnerActivity();
-    method public final android.view.SearchEvent getSearchEvent();
+    method public boolean dispatchGenericMotionEvent(@NonNull android.view.MotionEvent);
+    method public boolean dispatchKeyEvent(@NonNull android.view.KeyEvent);
+    method public boolean dispatchKeyShortcutEvent(@NonNull android.view.KeyEvent);
+    method public boolean dispatchPopulateAccessibilityEvent(@NonNull android.view.accessibility.AccessibilityEvent);
+    method public boolean dispatchTouchEvent(@NonNull android.view.MotionEvent);
+    method public boolean dispatchTrackballEvent(@NonNull android.view.MotionEvent);
+    method public <T extends android.view.View> T findViewById(@IdRes int);
+    method @Nullable public android.app.ActionBar getActionBar();
+    method @NonNull public final android.content.Context getContext();
+    method @Nullable public android.view.View getCurrentFocus();
+    method @NonNull public android.view.LayoutInflater getLayoutInflater();
+    method @Nullable public final android.app.Activity getOwnerActivity();
+    method @Nullable public final android.view.SearchEvent getSearchEvent();
     method public final int getVolumeControlStream();
-    method public android.view.Window getWindow();
+    method @Nullable public android.view.Window getWindow();
     method public void hide();
     method public void invalidateOptionsMenu();
     method public boolean isShowing();
-    method public void onActionModeFinished(android.view.ActionMode);
-    method public void onActionModeStarted(android.view.ActionMode);
+    method @CallSuper public void onActionModeFinished(android.view.ActionMode);
+    method @CallSuper public void onActionModeStarted(android.view.ActionMode);
     method public void onAttachedToWindow();
     method public void onBackPressed();
     method public void onContentChanged();
-    method public boolean onContextItemSelected(android.view.MenuItem);
-    method public void onContextMenuClosed(android.view.Menu);
+    method public boolean onContextItemSelected(@NonNull android.view.MenuItem);
+    method public void onContextMenuClosed(@NonNull android.view.Menu);
     method protected void onCreate(android.os.Bundle);
     method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
-    method public boolean onCreateOptionsMenu(android.view.Menu);
-    method public boolean onCreatePanelMenu(int, android.view.Menu);
+    method public boolean onCreateOptionsMenu(@NonNull android.view.Menu);
+    method public boolean onCreatePanelMenu(int, @NonNull android.view.Menu);
     method public android.view.View onCreatePanelView(int);
     method public void onDetachedFromWindow();
-    method public boolean onGenericMotionEvent(android.view.MotionEvent);
-    method public boolean onKeyDown(int, android.view.KeyEvent);
-    method public boolean onKeyLongPress(int, android.view.KeyEvent);
-    method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
-    method public boolean onKeyShortcut(int, android.view.KeyEvent);
-    method public boolean onKeyUp(int, android.view.KeyEvent);
-    method public boolean onMenuItemSelected(int, android.view.MenuItem);
-    method public boolean onMenuOpened(int, android.view.Menu);
-    method public boolean onOptionsItemSelected(android.view.MenuItem);
-    method public void onOptionsMenuClosed(android.view.Menu);
-    method public void onPanelClosed(int, android.view.Menu);
-    method public boolean onPrepareOptionsMenu(android.view.Menu);
-    method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
-    method public void onRestoreInstanceState(android.os.Bundle);
-    method public android.os.Bundle onSaveInstanceState();
-    method public boolean onSearchRequested(android.view.SearchEvent);
+    method public boolean onGenericMotionEvent(@NonNull android.view.MotionEvent);
+    method public boolean onKeyDown(int, @NonNull android.view.KeyEvent);
+    method public boolean onKeyLongPress(int, @NonNull android.view.KeyEvent);
+    method public boolean onKeyMultiple(int, int, @NonNull android.view.KeyEvent);
+    method public boolean onKeyShortcut(int, @NonNull android.view.KeyEvent);
+    method public boolean onKeyUp(int, @NonNull android.view.KeyEvent);
+    method public boolean onMenuItemSelected(int, @NonNull android.view.MenuItem);
+    method public boolean onMenuOpened(int, @NonNull android.view.Menu);
+    method public boolean onOptionsItemSelected(@NonNull android.view.MenuItem);
+    method public void onOptionsMenuClosed(@NonNull android.view.Menu);
+    method public void onPanelClosed(int, @NonNull android.view.Menu);
+    method public boolean onPrepareOptionsMenu(@NonNull android.view.Menu);
+    method public boolean onPreparePanel(int, @Nullable android.view.View, @NonNull android.view.Menu);
+    method public void onRestoreInstanceState(@NonNull android.os.Bundle);
+    method @NonNull public android.os.Bundle onSaveInstanceState();
+    method public boolean onSearchRequested(@NonNull android.view.SearchEvent);
     method public boolean onSearchRequested();
     method protected void onStart();
     method protected void onStop();
-    method public boolean onTouchEvent(android.view.MotionEvent);
-    method public boolean onTrackballEvent(android.view.MotionEvent);
+    method public boolean onTouchEvent(@NonNull android.view.MotionEvent);
+    method public boolean onTrackballEvent(@NonNull android.view.MotionEvent);
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
-    method public void openContextMenu(android.view.View);
+    method public void openContextMenu(@NonNull android.view.View);
     method public void openOptionsMenu();
-    method public void registerForContextMenu(android.view.View);
+    method public void registerForContextMenu(@NonNull android.view.View);
     method public final boolean requestWindowFeature(int);
-    method public final <T extends android.view.View> T requireViewById(int);
-    method public void setCancelMessage(android.os.Message);
+    method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
+    method public void setCancelMessage(@Nullable android.os.Message);
     method public void setCancelable(boolean);
     method public void setCanceledOnTouchOutside(boolean);
-    method public void setContentView(int);
-    method public void setContentView(android.view.View);
-    method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
-    method public void setDismissMessage(android.os.Message);
-    method public final void setFeatureDrawable(int, android.graphics.drawable.Drawable);
+    method public void setContentView(@LayoutRes int);
+    method public void setContentView(@NonNull android.view.View);
+    method public void setContentView(@NonNull android.view.View, @Nullable android.view.ViewGroup.LayoutParams);
+    method public void setDismissMessage(@Nullable android.os.Message);
+    method public final void setFeatureDrawable(int, @Nullable android.graphics.drawable.Drawable);
     method public final void setFeatureDrawableAlpha(int, int);
-    method public final void setFeatureDrawableResource(int, int);
-    method public final void setFeatureDrawableUri(int, android.net.Uri);
-    method public void setOnCancelListener(android.content.DialogInterface.OnCancelListener);
-    method public void setOnDismissListener(android.content.DialogInterface.OnDismissListener);
-    method public void setOnKeyListener(android.content.DialogInterface.OnKeyListener);
-    method public void setOnShowListener(android.content.DialogInterface.OnShowListener);
-    method public final void setOwnerActivity(android.app.Activity);
-    method public void setTitle(java.lang.CharSequence);
-    method public void setTitle(int);
+    method public final void setFeatureDrawableResource(int, @DrawableRes int);
+    method public final void setFeatureDrawableUri(int, @Nullable android.net.Uri);
+    method public void setOnCancelListener(@Nullable android.content.DialogInterface.OnCancelListener);
+    method public void setOnDismissListener(@Nullable android.content.DialogInterface.OnDismissListener);
+    method public void setOnKeyListener(@Nullable android.content.DialogInterface.OnKeyListener);
+    method public void setOnShowListener(@Nullable android.content.DialogInterface.OnShowListener);
+    method public final void setOwnerActivity(@NonNull android.app.Activity);
+    method public void setTitle(@Nullable CharSequence);
+    method public void setTitle(@StringRes int);
     method public final void setVolumeControlStream(int);
     method public void show();
     method public void takeKeyEvents(boolean);
-    method public void unregisterForContextMenu(android.view.View);
+    method public void unregisterForContextMenu(@NonNull android.view.View);
   }
 
-  public deprecated class DialogFragment extends android.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
-    ctor public DialogFragment();
-    method public void dismiss();
-    method public void dismissAllowingStateLoss();
-    method public android.app.Dialog getDialog();
-    method public boolean getShowsDialog();
-    method public int getTheme();
-    method public boolean isCancelable();
-    method public void onCancel(android.content.DialogInterface);
-    method public android.app.Dialog onCreateDialog(android.os.Bundle);
-    method public void onDismiss(android.content.DialogInterface);
-    method public void setCancelable(boolean);
-    method public void setShowsDialog(boolean);
-    method public void setStyle(int, int);
-    method public void show(android.app.FragmentManager, java.lang.String);
-    method public int show(android.app.FragmentTransaction, java.lang.String);
-    field public static final int STYLE_NORMAL = 0; // 0x0
-    field public static final int STYLE_NO_FRAME = 2; // 0x2
-    field public static final int STYLE_NO_INPUT = 3; // 0x3
-    field public static final int STYLE_NO_TITLE = 1; // 0x1
+  @Deprecated public class DialogFragment extends android.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+    ctor @Deprecated public DialogFragment();
+    method @Deprecated public void dismiss();
+    method @Deprecated public void dismissAllowingStateLoss();
+    method @Deprecated public android.app.Dialog getDialog();
+    method @Deprecated public boolean getShowsDialog();
+    method @Deprecated public int getTheme();
+    method @Deprecated public boolean isCancelable();
+    method @Deprecated public void onCancel(android.content.DialogInterface);
+    method @Deprecated public android.app.Dialog onCreateDialog(android.os.Bundle);
+    method @Deprecated public void onDismiss(android.content.DialogInterface);
+    method public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle);
+    method @Deprecated public void setCancelable(boolean);
+    method @Deprecated public void setShowsDialog(boolean);
+    method @Deprecated public void setStyle(int, int);
+    method @Deprecated public void show(android.app.FragmentManager, String);
+    method @Deprecated public int show(android.app.FragmentTransaction, String);
+    field @Deprecated public static final int STYLE_NORMAL = 0; // 0x0
+    field @Deprecated public static final int STYLE_NO_FRAME = 2; // 0x2
+    field @Deprecated public static final int STYLE_NO_INPUT = 3; // 0x3
+    field @Deprecated public static final int STYLE_NO_TITLE = 1; // 0x1
   }
 
   public class DownloadManager {
-    method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean);
-    method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean, android.net.Uri, android.net.Uri);
+    method public long addCompletedDownload(String, String, boolean, String, String, long, boolean);
+    method public long addCompletedDownload(String, String, boolean, String, String, long, boolean, android.net.Uri, android.net.Uri);
     method public long enqueue(android.app.DownloadManager.Request);
-    method public static java.lang.Long getMaxBytesOverMobile(android.content.Context);
-    method public java.lang.String getMimeTypeForDownloadedFile(long);
-    method public static java.lang.Long getRecommendedMaxBytesOverMobile(android.content.Context);
+    method public static Long getMaxBytesOverMobile(android.content.Context);
+    method public String getMimeTypeForDownloadedFile(long);
+    method public static Long getRecommendedMaxBytesOverMobile(android.content.Context);
     method public android.net.Uri getUriForDownloadedFile(long);
     method public android.os.ParcelFileDescriptor openDownloadedFile(long) throws java.io.FileNotFoundException;
     method public android.database.Cursor query(android.app.DownloadManager.Query);
     method public int remove(long...);
-    field public static final java.lang.String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE";
-    field public static final java.lang.String ACTION_NOTIFICATION_CLICKED = "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
-    field public static final java.lang.String ACTION_VIEW_DOWNLOADS = "android.intent.action.VIEW_DOWNLOADS";
-    field public static final java.lang.String COLUMN_BYTES_DOWNLOADED_SO_FAR = "bytes_so_far";
-    field public static final java.lang.String COLUMN_DESCRIPTION = "description";
-    field public static final java.lang.String COLUMN_ID = "_id";
-    field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
-    field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
-    field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri";
-    field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
-    field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type";
-    field public static final java.lang.String COLUMN_REASON = "reason";
-    field public static final java.lang.String COLUMN_STATUS = "status";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_TOTAL_SIZE_BYTES = "total_size";
-    field public static final java.lang.String COLUMN_URI = "uri";
+    field public static final String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE";
+    field public static final String ACTION_NOTIFICATION_CLICKED = "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
+    field public static final String ACTION_VIEW_DOWNLOADS = "android.intent.action.VIEW_DOWNLOADS";
+    field public static final String COLUMN_BYTES_DOWNLOADED_SO_FAR = "bytes_so_far";
+    field public static final String COLUMN_DESCRIPTION = "description";
+    field public static final String COLUMN_ID = "_id";
+    field public static final String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
+    field @Deprecated public static final String COLUMN_LOCAL_FILENAME = "local_filename";
+    field public static final String COLUMN_LOCAL_URI = "local_uri";
+    field public static final String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
+    field public static final String COLUMN_MEDIA_TYPE = "media_type";
+    field public static final String COLUMN_REASON = "reason";
+    field public static final String COLUMN_STATUS = "status";
+    field public static final String COLUMN_TITLE = "title";
+    field public static final String COLUMN_TOTAL_SIZE_BYTES = "total_size";
+    field public static final String COLUMN_URI = "uri";
     field public static final int ERROR_CANNOT_RESUME = 1008; // 0x3f0
     field public static final int ERROR_DEVICE_NOT_FOUND = 1007; // 0x3ef
     field public static final int ERROR_FILE_ALREADY_EXISTS = 1009; // 0x3f1
@@ -4624,9 +4629,9 @@
     field public static final int ERROR_TOO_MANY_REDIRECTS = 1005; // 0x3ed
     field public static final int ERROR_UNHANDLED_HTTP_CODE = 1002; // 0x3ea
     field public static final int ERROR_UNKNOWN = 1000; // 0x3e8
-    field public static final java.lang.String EXTRA_DOWNLOAD_ID = "extra_download_id";
-    field public static final java.lang.String EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS = "extra_click_download_ids";
-    field public static final java.lang.String INTENT_EXTRAS_SORT_BY_SIZE = "android.app.DownloadManager.extra_sortBySize";
+    field public static final String EXTRA_DOWNLOAD_ID = "extra_download_id";
+    field public static final String EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS = "extra_click_download_ids";
+    field public static final String INTENT_EXTRAS_SORT_BY_SIZE = "android.app.DownloadManager.extra_sortBySize";
     field public static final int PAUSED_QUEUED_FOR_WIFI = 3; // 0x3
     field public static final int PAUSED_UNKNOWN = 4; // 0x4
     field public static final int PAUSED_WAITING_FOR_NETWORK = 2; // 0x2
@@ -4646,21 +4651,21 @@
 
   public static class DownloadManager.Request {
     ctor public DownloadManager.Request(android.net.Uri);
-    method public android.app.DownloadManager.Request addRequestHeader(java.lang.String, java.lang.String);
+    method public android.app.DownloadManager.Request addRequestHeader(String, String);
     method public void allowScanningByMediaScanner();
     method public android.app.DownloadManager.Request setAllowedNetworkTypes(int);
     method public android.app.DownloadManager.Request setAllowedOverMetered(boolean);
     method public android.app.DownloadManager.Request setAllowedOverRoaming(boolean);
-    method public android.app.DownloadManager.Request setDescription(java.lang.CharSequence);
-    method public android.app.DownloadManager.Request setDestinationInExternalFilesDir(android.content.Context, java.lang.String, java.lang.String);
-    method public android.app.DownloadManager.Request setDestinationInExternalPublicDir(java.lang.String, java.lang.String);
+    method public android.app.DownloadManager.Request setDescription(CharSequence);
+    method public android.app.DownloadManager.Request setDestinationInExternalFilesDir(android.content.Context, String, String);
+    method public android.app.DownloadManager.Request setDestinationInExternalPublicDir(String, String);
     method public android.app.DownloadManager.Request setDestinationUri(android.net.Uri);
-    method public android.app.DownloadManager.Request setMimeType(java.lang.String);
+    method public android.app.DownloadManager.Request setMimeType(String);
     method public android.app.DownloadManager.Request setNotificationVisibility(int);
     method public android.app.DownloadManager.Request setRequiresCharging(boolean);
     method public android.app.DownloadManager.Request setRequiresDeviceIdle(boolean);
-    method public deprecated android.app.DownloadManager.Request setShowRunningNotification(boolean);
-    method public android.app.DownloadManager.Request setTitle(java.lang.CharSequence);
+    method @Deprecated public android.app.DownloadManager.Request setShowRunningNotification(boolean);
+    method public android.app.DownloadManager.Request setTitle(CharSequence);
     method public android.app.DownloadManager.Request setVisibleInDownloadsUi(boolean);
     field public static final int NETWORK_MOBILE = 1; // 0x1
     field public static final int NETWORK_WIFI = 2; // 0x2
@@ -4684,314 +4689,314 @@
     method public void setSelectedGroup(int);
   }
 
-  public deprecated class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener {
-    ctor public Fragment();
-    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public final boolean equals(java.lang.Object);
-    method public final android.app.Activity getActivity();
-    method public boolean getAllowEnterTransitionOverlap();
-    method public boolean getAllowReturnTransitionOverlap();
-    method public final android.os.Bundle getArguments();
-    method public final android.app.FragmentManager getChildFragmentManager();
-    method public android.content.Context getContext();
-    method public android.transition.Transition getEnterTransition();
-    method public android.transition.Transition getExitTransition();
-    method public final android.app.FragmentManager getFragmentManager();
-    method public final java.lang.Object getHost();
-    method public final int getId();
-    method public final android.view.LayoutInflater getLayoutInflater();
-    method public deprecated android.app.LoaderManager getLoaderManager();
-    method public final android.app.Fragment getParentFragment();
-    method public android.transition.Transition getReenterTransition();
-    method public final android.content.res.Resources getResources();
-    method public final boolean getRetainInstance();
-    method public android.transition.Transition getReturnTransition();
-    method public android.transition.Transition getSharedElementEnterTransition();
-    method public android.transition.Transition getSharedElementReturnTransition();
-    method public final java.lang.String getString(int);
-    method public final java.lang.String getString(int, java.lang.Object...);
-    method public final java.lang.String getTag();
-    method public final android.app.Fragment getTargetFragment();
-    method public final int getTargetRequestCode();
-    method public final java.lang.CharSequence getText(int);
-    method public boolean getUserVisibleHint();
-    method public android.view.View getView();
-    method public final int hashCode();
-    method public static android.app.Fragment instantiate(android.content.Context, java.lang.String);
-    method public static android.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
-    method public final boolean isAdded();
-    method public final boolean isDetached();
-    method public final boolean isHidden();
-    method public final boolean isInLayout();
-    method public final boolean isRemoving();
-    method public final boolean isResumed();
-    method public final boolean isStateSaved();
-    method public final boolean isVisible();
-    method public void onActivityCreated(android.os.Bundle);
-    method public void onActivityResult(int, int, android.content.Intent);
-    method public void onAttach(android.content.Context);
-    method public deprecated void onAttach(android.app.Activity);
-    method public void onAttachFragment(android.app.Fragment);
-    method public void onConfigurationChanged(android.content.res.Configuration);
-    method public boolean onContextItemSelected(android.view.MenuItem);
-    method public void onCreate(android.os.Bundle);
-    method public android.animation.Animator onCreateAnimator(int, boolean, int);
-    method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
-    method public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
-    method public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public void onDestroy();
-    method public void onDestroyOptionsMenu();
-    method public void onDestroyView();
-    method public void onDetach();
-    method public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle);
-    method public void onHiddenChanged(boolean);
-    method public deprecated void onInflate(android.util.AttributeSet, android.os.Bundle);
-    method public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
-    method public deprecated void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
-    method public void onLowMemory();
-    method public void onMultiWindowModeChanged(boolean, android.content.res.Configuration);
-    method public deprecated void onMultiWindowModeChanged(boolean);
-    method public boolean onOptionsItemSelected(android.view.MenuItem);
-    method public void onOptionsMenuClosed(android.view.Menu);
-    method public void onPause();
-    method public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration);
-    method public deprecated void onPictureInPictureModeChanged(boolean);
-    method public void onPrepareOptionsMenu(android.view.Menu);
-    method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
-    method public void onResume();
-    method public void onSaveInstanceState(android.os.Bundle);
-    method public void onStart();
-    method public void onStop();
-    method public void onTrimMemory(int);
-    method public void onViewCreated(android.view.View, android.os.Bundle);
-    method public void onViewStateRestored(android.os.Bundle);
-    method public void postponeEnterTransition();
-    method public void registerForContextMenu(android.view.View);
-    method public final void requestPermissions(java.lang.String[], int);
-    method public void setAllowEnterTransitionOverlap(boolean);
-    method public void setAllowReturnTransitionOverlap(boolean);
-    method public void setArguments(android.os.Bundle);
-    method public void setEnterSharedElementCallback(android.app.SharedElementCallback);
-    method public void setEnterTransition(android.transition.Transition);
-    method public void setExitSharedElementCallback(android.app.SharedElementCallback);
-    method public void setExitTransition(android.transition.Transition);
-    method public void setHasOptionsMenu(boolean);
-    method public void setInitialSavedState(android.app.Fragment.SavedState);
-    method public void setMenuVisibility(boolean);
-    method public void setReenterTransition(android.transition.Transition);
-    method public void setRetainInstance(boolean);
-    method public void setReturnTransition(android.transition.Transition);
-    method public void setSharedElementEnterTransition(android.transition.Transition);
-    method public void setSharedElementReturnTransition(android.transition.Transition);
-    method public void setTargetFragment(android.app.Fragment, int);
-    method public void setUserVisibleHint(boolean);
-    method public boolean shouldShowRequestPermissionRationale(java.lang.String);
-    method public void startActivity(android.content.Intent);
-    method public void startActivity(android.content.Intent, android.os.Bundle);
-    method public void startActivityForResult(android.content.Intent, int);
-    method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
-    method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
-    method public void startPostponedEnterTransition();
-    method public void unregisterForContextMenu(android.view.View);
+  @Deprecated public class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener {
+    ctor @Deprecated public Fragment();
+    method @Deprecated public void dump(String, java.io.FileDescriptor, java.io.PrintWriter, String[]);
+    method @Deprecated public final boolean equals(Object);
+    method @Deprecated public final android.app.Activity getActivity();
+    method @Deprecated public boolean getAllowEnterTransitionOverlap();
+    method @Deprecated public boolean getAllowReturnTransitionOverlap();
+    method @Deprecated public final android.os.Bundle getArguments();
+    method @Deprecated public final android.app.FragmentManager getChildFragmentManager();
+    method @Deprecated public android.content.Context getContext();
+    method @Deprecated public android.transition.Transition getEnterTransition();
+    method @Deprecated public android.transition.Transition getExitTransition();
+    method @Deprecated public final android.app.FragmentManager getFragmentManager();
+    method @Deprecated @Nullable public final Object getHost();
+    method @Deprecated public final int getId();
+    method @Deprecated public final android.view.LayoutInflater getLayoutInflater();
+    method @Deprecated public android.app.LoaderManager getLoaderManager();
+    method @Deprecated public final android.app.Fragment getParentFragment();
+    method @Deprecated public android.transition.Transition getReenterTransition();
+    method @Deprecated public final android.content.res.Resources getResources();
+    method @Deprecated public final boolean getRetainInstance();
+    method @Deprecated public android.transition.Transition getReturnTransition();
+    method @Deprecated public android.transition.Transition getSharedElementEnterTransition();
+    method @Deprecated public android.transition.Transition getSharedElementReturnTransition();
+    method @Deprecated public final String getString(@StringRes int);
+    method @Deprecated public final String getString(@StringRes int, java.lang.Object...);
+    method @Deprecated public final String getTag();
+    method @Deprecated public final android.app.Fragment getTargetFragment();
+    method @Deprecated public final int getTargetRequestCode();
+    method @Deprecated public final CharSequence getText(@StringRes int);
+    method @Deprecated public boolean getUserVisibleHint();
+    method @Deprecated @Nullable public android.view.View getView();
+    method @Deprecated public final int hashCode();
+    method @Deprecated public static android.app.Fragment instantiate(android.content.Context, String);
+    method @Deprecated public static android.app.Fragment instantiate(android.content.Context, String, @Nullable android.os.Bundle);
+    method @Deprecated public final boolean isAdded();
+    method @Deprecated public final boolean isDetached();
+    method @Deprecated public final boolean isHidden();
+    method @Deprecated public final boolean isInLayout();
+    method @Deprecated public final boolean isRemoving();
+    method @Deprecated public final boolean isResumed();
+    method @Deprecated public final boolean isStateSaved();
+    method @Deprecated public final boolean isVisible();
+    method @Deprecated @CallSuper public void onActivityCreated(@Nullable android.os.Bundle);
+    method @Deprecated public void onActivityResult(int, int, android.content.Intent);
+    method @Deprecated @CallSuper public void onAttach(android.content.Context);
+    method @Deprecated @CallSuper public void onAttach(android.app.Activity);
+    method @Deprecated public void onAttachFragment(android.app.Fragment);
+    method @Deprecated @CallSuper public void onConfigurationChanged(android.content.res.Configuration);
+    method @Deprecated public boolean onContextItemSelected(android.view.MenuItem);
+    method @Deprecated @CallSuper public void onCreate(@Nullable android.os.Bundle);
+    method @Deprecated public android.animation.Animator onCreateAnimator(int, boolean, int);
+    method @Deprecated public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
+    method @Deprecated public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method @Deprecated @Nullable public android.view.View onCreateView(android.view.LayoutInflater, @Nullable android.view.ViewGroup, android.os.Bundle);
+    method @Deprecated @CallSuper public void onDestroy();
+    method @Deprecated public void onDestroyOptionsMenu();
+    method @Deprecated @CallSuper public void onDestroyView();
+    method @Deprecated @CallSuper public void onDetach();
+    method @Deprecated public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle);
+    method @Deprecated public void onHiddenChanged(boolean);
+    method @Deprecated @CallSuper public void onInflate(android.util.AttributeSet, android.os.Bundle);
+    method @Deprecated @CallSuper public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle);
+    method @Deprecated @CallSuper public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle);
+    method @Deprecated @CallSuper public void onLowMemory();
+    method @Deprecated public void onMultiWindowModeChanged(boolean, android.content.res.Configuration);
+    method @Deprecated public void onMultiWindowModeChanged(boolean);
+    method @Deprecated public boolean onOptionsItemSelected(android.view.MenuItem);
+    method @Deprecated public void onOptionsMenuClosed(android.view.Menu);
+    method @Deprecated @CallSuper public void onPause();
+    method @Deprecated public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration);
+    method @Deprecated public void onPictureInPictureModeChanged(boolean);
+    method @Deprecated public void onPrepareOptionsMenu(android.view.Menu);
+    method @Deprecated public void onRequestPermissionsResult(int, @NonNull String[], @NonNull int[]);
+    method @Deprecated @CallSuper public void onResume();
+    method @Deprecated public void onSaveInstanceState(android.os.Bundle);
+    method @Deprecated @CallSuper public void onStart();
+    method @Deprecated @CallSuper public void onStop();
+    method @Deprecated @CallSuper public void onTrimMemory(int);
+    method @Deprecated public void onViewCreated(android.view.View, @Nullable android.os.Bundle);
+    method @Deprecated @CallSuper public void onViewStateRestored(android.os.Bundle);
+    method @Deprecated public void postponeEnterTransition();
+    method @Deprecated public void registerForContextMenu(android.view.View);
+    method @Deprecated public final void requestPermissions(@NonNull String[], int);
+    method @Deprecated public void setAllowEnterTransitionOverlap(boolean);
+    method @Deprecated public void setAllowReturnTransitionOverlap(boolean);
+    method @Deprecated public void setArguments(android.os.Bundle);
+    method @Deprecated public void setEnterSharedElementCallback(android.app.SharedElementCallback);
+    method @Deprecated public void setEnterTransition(android.transition.Transition);
+    method @Deprecated public void setExitSharedElementCallback(android.app.SharedElementCallback);
+    method @Deprecated public void setExitTransition(android.transition.Transition);
+    method @Deprecated public void setHasOptionsMenu(boolean);
+    method @Deprecated public void setInitialSavedState(android.app.Fragment.SavedState);
+    method @Deprecated public void setMenuVisibility(boolean);
+    method @Deprecated public void setReenterTransition(android.transition.Transition);
+    method @Deprecated public void setRetainInstance(boolean);
+    method @Deprecated public void setReturnTransition(android.transition.Transition);
+    method @Deprecated public void setSharedElementEnterTransition(android.transition.Transition);
+    method @Deprecated public void setSharedElementReturnTransition(android.transition.Transition);
+    method @Deprecated public void setTargetFragment(android.app.Fragment, int);
+    method @Deprecated public void setUserVisibleHint(boolean);
+    method @Deprecated public boolean shouldShowRequestPermissionRationale(@NonNull String);
+    method @Deprecated public void startActivity(android.content.Intent);
+    method @Deprecated public void startActivity(android.content.Intent, android.os.Bundle);
+    method @Deprecated public void startActivityForResult(android.content.Intent, int);
+    method @Deprecated public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
+    method @Deprecated public void startIntentSenderForResult(android.content.IntentSender, int, @Nullable android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method @Deprecated public void startPostponedEnterTransition();
+    method @Deprecated public void unregisterForContextMenu(android.view.View);
   }
 
-  public static deprecated class Fragment.InstantiationException extends android.util.AndroidRuntimeException {
-    ctor public Fragment.InstantiationException(java.lang.String, java.lang.Exception);
+  @Deprecated public static class Fragment.InstantiationException extends android.util.AndroidRuntimeException {
+    ctor @Deprecated public Fragment.InstantiationException(String, Exception);
   }
 
-  public static deprecated class Fragment.SavedState implements android.os.Parcelable {
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.ClassLoaderCreator<android.app.Fragment.SavedState> CREATOR;
+  @Deprecated public static class Fragment.SavedState implements android.os.Parcelable {
+    method @Deprecated public int describeContents();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.ClassLoaderCreator<android.app.Fragment.SavedState> CREATOR;
   }
 
-  public deprecated class FragmentBreadCrumbs extends android.view.ViewGroup implements android.app.FragmentManager.OnBackStackChangedListener {
-    ctor public FragmentBreadCrumbs(android.content.Context);
-    ctor public FragmentBreadCrumbs(android.content.Context, android.util.AttributeSet);
-    ctor public FragmentBreadCrumbs(android.content.Context, android.util.AttributeSet, int);
-    method public void onBackStackChanged();
-    method public void setActivity(android.app.Activity);
-    method public void setMaxVisible(int);
-    method public void setOnBreadCrumbClickListener(android.app.FragmentBreadCrumbs.OnBreadCrumbClickListener);
-    method public void setParentTitle(java.lang.CharSequence, java.lang.CharSequence, android.view.View.OnClickListener);
-    method public void setTitle(java.lang.CharSequence, java.lang.CharSequence);
+  @Deprecated public class FragmentBreadCrumbs extends android.view.ViewGroup implements android.app.FragmentManager.OnBackStackChangedListener {
+    ctor @Deprecated public FragmentBreadCrumbs(android.content.Context);
+    ctor @Deprecated public FragmentBreadCrumbs(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public FragmentBreadCrumbs(android.content.Context, android.util.AttributeSet, int);
+    method @Deprecated public void onBackStackChanged();
+    method @Deprecated public void setActivity(android.app.Activity);
+    method @Deprecated public void setMaxVisible(int);
+    method @Deprecated public void setOnBreadCrumbClickListener(android.app.FragmentBreadCrumbs.OnBreadCrumbClickListener);
+    method @Deprecated public void setParentTitle(CharSequence, CharSequence, android.view.View.OnClickListener);
+    method @Deprecated public void setTitle(CharSequence, CharSequence);
   }
 
-  public static abstract deprecated interface FragmentBreadCrumbs.OnBreadCrumbClickListener {
-    method public abstract boolean onBreadCrumbClick(android.app.FragmentManager.BackStackEntry, int);
+  @Deprecated public static interface FragmentBreadCrumbs.OnBreadCrumbClickListener {
+    method @Deprecated public boolean onBreadCrumbClick(android.app.FragmentManager.BackStackEntry, int);
   }
 
-  public abstract deprecated class FragmentContainer {
-    ctor public FragmentContainer();
-    method public abstract <T extends android.view.View> T onFindViewById(int);
-    method public abstract boolean onHasView();
+  @Deprecated public abstract class FragmentContainer {
+    ctor @Deprecated public FragmentContainer();
+    method @Deprecated @Nullable public abstract <T extends android.view.View> T onFindViewById(@IdRes int);
+    method @Deprecated public abstract boolean onHasView();
   }
 
-  public deprecated class FragmentController {
-    method public void attachHost(android.app.Fragment);
-    method public static final android.app.FragmentController createController(android.app.FragmentHostCallback<?>);
-    method public void dispatchActivityCreated();
-    method public void dispatchConfigurationChanged(android.content.res.Configuration);
-    method public boolean dispatchContextItemSelected(android.view.MenuItem);
-    method public void dispatchCreate();
-    method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
-    method public void dispatchDestroy();
-    method public void dispatchDestroyView();
-    method public void dispatchLowMemory();
-    method public deprecated void dispatchMultiWindowModeChanged(boolean);
-    method public void dispatchMultiWindowModeChanged(boolean, android.content.res.Configuration);
-    method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
-    method public void dispatchOptionsMenuClosed(android.view.Menu);
-    method public void dispatchPause();
-    method public deprecated void dispatchPictureInPictureModeChanged(boolean);
-    method public void dispatchPictureInPictureModeChanged(boolean, android.content.res.Configuration);
-    method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
-    method public void dispatchResume();
-    method public void dispatchStart();
-    method public void dispatchStop();
-    method public void dispatchTrimMemory(int);
-    method public void doLoaderDestroy();
-    method public void doLoaderStart();
-    method public void doLoaderStop(boolean);
-    method public void dumpLoaders(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public boolean execPendingActions();
-    method public android.app.Fragment findFragmentByWho(java.lang.String);
-    method public android.app.FragmentManager getFragmentManager();
-    method public android.app.LoaderManager getLoaderManager();
-    method public void noteStateNotSaved();
-    method public android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
-    method public void reportLoaderStart();
-    method public deprecated void restoreAllState(android.os.Parcelable, java.util.List<android.app.Fragment>);
-    method public void restoreAllState(android.os.Parcelable, android.app.FragmentManagerNonConfig);
-    method public void restoreLoaderNonConfig(android.util.ArrayMap<java.lang.String, android.app.LoaderManager>);
-    method public android.util.ArrayMap<java.lang.String, android.app.LoaderManager> retainLoaderNonConfig();
-    method public android.app.FragmentManagerNonConfig retainNestedNonConfig();
-    method public deprecated java.util.List<android.app.Fragment> retainNonConfig();
-    method public android.os.Parcelable saveAllState();
+  @Deprecated public class FragmentController {
+    method @Deprecated public void attachHost(android.app.Fragment);
+    method @Deprecated public static final android.app.FragmentController createController(android.app.FragmentHostCallback<?>);
+    method @Deprecated public void dispatchActivityCreated();
+    method @Deprecated public void dispatchConfigurationChanged(android.content.res.Configuration);
+    method @Deprecated public boolean dispatchContextItemSelected(android.view.MenuItem);
+    method @Deprecated public void dispatchCreate();
+    method @Deprecated public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method @Deprecated public void dispatchDestroy();
+    method @Deprecated public void dispatchDestroyView();
+    method @Deprecated public void dispatchLowMemory();
+    method @Deprecated public void dispatchMultiWindowModeChanged(boolean);
+    method @Deprecated public void dispatchMultiWindowModeChanged(boolean, android.content.res.Configuration);
+    method @Deprecated public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+    method @Deprecated public void dispatchOptionsMenuClosed(android.view.Menu);
+    method @Deprecated public void dispatchPause();
+    method @Deprecated public void dispatchPictureInPictureModeChanged(boolean);
+    method @Deprecated public void dispatchPictureInPictureModeChanged(boolean, android.content.res.Configuration);
+    method @Deprecated public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+    method @Deprecated public void dispatchResume();
+    method @Deprecated public void dispatchStart();
+    method @Deprecated public void dispatchStop();
+    method @Deprecated public void dispatchTrimMemory(int);
+    method @Deprecated public void doLoaderDestroy();
+    method @Deprecated public void doLoaderStart();
+    method @Deprecated public void doLoaderStop(boolean);
+    method @Deprecated public void dumpLoaders(String, java.io.FileDescriptor, java.io.PrintWriter, String[]);
+    method @Deprecated public boolean execPendingActions();
+    method @Deprecated @Nullable public android.app.Fragment findFragmentByWho(String);
+    method @Deprecated public android.app.FragmentManager getFragmentManager();
+    method @Deprecated public android.app.LoaderManager getLoaderManager();
+    method @Deprecated public void noteStateNotSaved();
+    method @Deprecated public android.view.View onCreateView(android.view.View, String, android.content.Context, android.util.AttributeSet);
+    method @Deprecated public void reportLoaderStart();
+    method @Deprecated public void restoreAllState(android.os.Parcelable, java.util.List<android.app.Fragment>);
+    method @Deprecated public void restoreAllState(android.os.Parcelable, android.app.FragmentManagerNonConfig);
+    method @Deprecated public void restoreLoaderNonConfig(android.util.ArrayMap<java.lang.String,android.app.LoaderManager>);
+    method @Deprecated public android.util.ArrayMap<java.lang.String,android.app.LoaderManager> retainLoaderNonConfig();
+    method @Deprecated public android.app.FragmentManagerNonConfig retainNestedNonConfig();
+    method @Deprecated public java.util.List<android.app.Fragment> retainNonConfig();
+    method @Deprecated public android.os.Parcelable saveAllState();
   }
 
-  public abstract deprecated class FragmentHostCallback<E> extends android.app.FragmentContainer {
-    ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
-    method public void onAttachFragment(android.app.Fragment);
-    method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public <T extends android.view.View> T onFindViewById(int);
-    method public abstract E onGetHost();
-    method public android.view.LayoutInflater onGetLayoutInflater();
-    method public int onGetWindowAnimations();
-    method public boolean onHasView();
-    method public boolean onHasWindowAnimations();
-    method public void onInvalidateOptionsMenu();
-    method public void onRequestPermissionsFromFragment(android.app.Fragment, java.lang.String[], int);
-    method public boolean onShouldSaveFragmentState(android.app.Fragment);
-    method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
-    method public void onStartIntentSenderFromFragment(android.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
-    method public boolean onUseFragmentManagerInflaterFactory();
+  @Deprecated public abstract class FragmentHostCallback<E> extends android.app.FragmentContainer {
+    ctor @Deprecated public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+    method @Deprecated public void onAttachFragment(android.app.Fragment);
+    method @Deprecated public void onDump(String, java.io.FileDescriptor, java.io.PrintWriter, String[]);
+    method @Deprecated @Nullable public <T extends android.view.View> T onFindViewById(int);
+    method @Deprecated @Nullable public abstract E onGetHost();
+    method @Deprecated public android.view.LayoutInflater onGetLayoutInflater();
+    method @Deprecated public int onGetWindowAnimations();
+    method @Deprecated public boolean onHasView();
+    method @Deprecated public boolean onHasWindowAnimations();
+    method @Deprecated public void onInvalidateOptionsMenu();
+    method @Deprecated public void onRequestPermissionsFromFragment(@NonNull android.app.Fragment, @NonNull String[], int);
+    method @Deprecated public boolean onShouldSaveFragmentState(android.app.Fragment);
+    method @Deprecated public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+    method @Deprecated public void onStartIntentSenderFromFragment(android.app.Fragment, android.content.IntentSender, int, @Nullable android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method @Deprecated public boolean onUseFragmentManagerInflaterFactory();
   }
 
-  public abstract deprecated class FragmentManager {
-    ctor public FragmentManager();
-    method public abstract void addOnBackStackChangedListener(android.app.FragmentManager.OnBackStackChangedListener);
-    method public abstract android.app.FragmentTransaction beginTransaction();
-    method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public static void enableDebugLogging(boolean);
-    method public abstract boolean executePendingTransactions();
-    method public abstract android.app.Fragment findFragmentById(int);
-    method public abstract android.app.Fragment findFragmentByTag(java.lang.String);
-    method public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
-    method public abstract int getBackStackEntryCount();
-    method public abstract android.app.Fragment getFragment(android.os.Bundle, java.lang.String);
-    method public abstract java.util.List<android.app.Fragment> getFragments();
-    method public abstract android.app.Fragment getPrimaryNavigationFragment();
-    method public void invalidateOptionsMenu();
-    method public abstract boolean isDestroyed();
-    method public abstract boolean isStateSaved();
-    method public abstract void popBackStack();
-    method public abstract void popBackStack(java.lang.String, int);
-    method public abstract void popBackStack(int, int);
-    method public abstract boolean popBackStackImmediate();
-    method public abstract boolean popBackStackImmediate(java.lang.String, int);
-    method public abstract boolean popBackStackImmediate(int, int);
-    method public abstract void putFragment(android.os.Bundle, java.lang.String, android.app.Fragment);
-    method public abstract void registerFragmentLifecycleCallbacks(android.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
-    method public abstract void removeOnBackStackChangedListener(android.app.FragmentManager.OnBackStackChangedListener);
-    method public abstract android.app.Fragment.SavedState saveFragmentInstanceState(android.app.Fragment);
-    method public abstract void unregisterFragmentLifecycleCallbacks(android.app.FragmentManager.FragmentLifecycleCallbacks);
-    field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+  @Deprecated public abstract class FragmentManager {
+    ctor @Deprecated public FragmentManager();
+    method @Deprecated public abstract void addOnBackStackChangedListener(android.app.FragmentManager.OnBackStackChangedListener);
+    method @Deprecated public abstract android.app.FragmentTransaction beginTransaction();
+    method @Deprecated public abstract void dump(String, java.io.FileDescriptor, java.io.PrintWriter, String[]);
+    method @Deprecated public static void enableDebugLogging(boolean);
+    method @Deprecated public abstract boolean executePendingTransactions();
+    method @Deprecated public abstract android.app.Fragment findFragmentById(int);
+    method @Deprecated public abstract android.app.Fragment findFragmentByTag(String);
+    method @Deprecated public abstract android.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+    method @Deprecated public abstract int getBackStackEntryCount();
+    method @Deprecated public abstract android.app.Fragment getFragment(android.os.Bundle, String);
+    method @Deprecated public abstract java.util.List<android.app.Fragment> getFragments();
+    method @Deprecated public abstract android.app.Fragment getPrimaryNavigationFragment();
+    method @Deprecated public void invalidateOptionsMenu();
+    method @Deprecated public abstract boolean isDestroyed();
+    method @Deprecated public abstract boolean isStateSaved();
+    method @Deprecated public abstract void popBackStack();
+    method @Deprecated public abstract void popBackStack(String, int);
+    method @Deprecated public abstract void popBackStack(int, int);
+    method @Deprecated public abstract boolean popBackStackImmediate();
+    method @Deprecated public abstract boolean popBackStackImmediate(String, int);
+    method @Deprecated public abstract boolean popBackStackImmediate(int, int);
+    method @Deprecated public abstract void putFragment(android.os.Bundle, String, android.app.Fragment);
+    method @Deprecated public abstract void registerFragmentLifecycleCallbacks(android.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
+    method @Deprecated public abstract void removeOnBackStackChangedListener(android.app.FragmentManager.OnBackStackChangedListener);
+    method @Deprecated public abstract android.app.Fragment.SavedState saveFragmentInstanceState(android.app.Fragment);
+    method @Deprecated public abstract void unregisterFragmentLifecycleCallbacks(android.app.FragmentManager.FragmentLifecycleCallbacks);
+    field @Deprecated public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
   }
 
-  public static abstract deprecated interface FragmentManager.BackStackEntry {
-    method public abstract java.lang.CharSequence getBreadCrumbShortTitle();
-    method public abstract int getBreadCrumbShortTitleRes();
-    method public abstract java.lang.CharSequence getBreadCrumbTitle();
-    method public abstract int getBreadCrumbTitleRes();
-    method public abstract int getId();
-    method public abstract java.lang.String getName();
+  @Deprecated public static interface FragmentManager.BackStackEntry {
+    method @Deprecated public CharSequence getBreadCrumbShortTitle();
+    method @Deprecated public int getBreadCrumbShortTitleRes();
+    method @Deprecated public CharSequence getBreadCrumbTitle();
+    method @Deprecated public int getBreadCrumbTitleRes();
+    method @Deprecated public int getId();
+    method @Deprecated public String getName();
   }
 
-  public static abstract deprecated class FragmentManager.FragmentLifecycleCallbacks {
-    ctor public FragmentManager.FragmentLifecycleCallbacks();
-    method public void onFragmentActivityCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
-    method public void onFragmentAttached(android.app.FragmentManager, android.app.Fragment, android.content.Context);
-    method public void onFragmentCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
-    method public void onFragmentDestroyed(android.app.FragmentManager, android.app.Fragment);
-    method public void onFragmentDetached(android.app.FragmentManager, android.app.Fragment);
-    method public void onFragmentPaused(android.app.FragmentManager, android.app.Fragment);
-    method public void onFragmentPreAttached(android.app.FragmentManager, android.app.Fragment, android.content.Context);
-    method public void onFragmentPreCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
-    method public void onFragmentResumed(android.app.FragmentManager, android.app.Fragment);
-    method public void onFragmentSaveInstanceState(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
-    method public void onFragmentStarted(android.app.FragmentManager, android.app.Fragment);
-    method public void onFragmentStopped(android.app.FragmentManager, android.app.Fragment);
-    method public void onFragmentViewCreated(android.app.FragmentManager, android.app.Fragment, android.view.View, android.os.Bundle);
-    method public void onFragmentViewDestroyed(android.app.FragmentManager, android.app.Fragment);
+  @Deprecated public abstract static class FragmentManager.FragmentLifecycleCallbacks {
+    ctor @Deprecated public FragmentManager.FragmentLifecycleCallbacks();
+    method @Deprecated public void onFragmentActivityCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
+    method @Deprecated public void onFragmentAttached(android.app.FragmentManager, android.app.Fragment, android.content.Context);
+    method @Deprecated public void onFragmentCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
+    method @Deprecated public void onFragmentDestroyed(android.app.FragmentManager, android.app.Fragment);
+    method @Deprecated public void onFragmentDetached(android.app.FragmentManager, android.app.Fragment);
+    method @Deprecated public void onFragmentPaused(android.app.FragmentManager, android.app.Fragment);
+    method @Deprecated public void onFragmentPreAttached(android.app.FragmentManager, android.app.Fragment, android.content.Context);
+    method @Deprecated public void onFragmentPreCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
+    method @Deprecated public void onFragmentResumed(android.app.FragmentManager, android.app.Fragment);
+    method @Deprecated public void onFragmentSaveInstanceState(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
+    method @Deprecated public void onFragmentStarted(android.app.FragmentManager, android.app.Fragment);
+    method @Deprecated public void onFragmentStopped(android.app.FragmentManager, android.app.Fragment);
+    method @Deprecated public void onFragmentViewCreated(android.app.FragmentManager, android.app.Fragment, android.view.View, android.os.Bundle);
+    method @Deprecated public void onFragmentViewDestroyed(android.app.FragmentManager, android.app.Fragment);
   }
 
-  public static abstract deprecated interface FragmentManager.OnBackStackChangedListener {
-    method public abstract void onBackStackChanged();
+  @Deprecated public static interface FragmentManager.OnBackStackChangedListener {
+    method @Deprecated public void onBackStackChanged();
   }
 
-  public deprecated class FragmentManagerNonConfig {
+  @Deprecated public class FragmentManagerNonConfig {
   }
 
-  public abstract deprecated class FragmentTransaction {
-    ctor public FragmentTransaction();
-    method public abstract android.app.FragmentTransaction add(android.app.Fragment, java.lang.String);
-    method public abstract android.app.FragmentTransaction add(int, android.app.Fragment);
-    method public abstract android.app.FragmentTransaction add(int, android.app.Fragment, java.lang.String);
-    method public abstract android.app.FragmentTransaction addSharedElement(android.view.View, java.lang.String);
-    method public abstract android.app.FragmentTransaction addToBackStack(java.lang.String);
-    method public abstract android.app.FragmentTransaction attach(android.app.Fragment);
-    method public abstract int commit();
-    method public abstract int commitAllowingStateLoss();
-    method public abstract void commitNow();
-    method public abstract void commitNowAllowingStateLoss();
-    method public abstract android.app.FragmentTransaction detach(android.app.Fragment);
-    method public abstract android.app.FragmentTransaction disallowAddToBackStack();
-    method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
-    method public abstract boolean isAddToBackStackAllowed();
-    method public abstract boolean isEmpty();
-    method public abstract android.app.FragmentTransaction remove(android.app.Fragment);
-    method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment);
-    method public abstract android.app.FragmentTransaction replace(int, android.app.Fragment, java.lang.String);
-    method public abstract android.app.FragmentTransaction runOnCommit(java.lang.Runnable);
-    method public abstract android.app.FragmentTransaction setBreadCrumbShortTitle(int);
-    method public abstract android.app.FragmentTransaction setBreadCrumbShortTitle(java.lang.CharSequence);
-    method public abstract android.app.FragmentTransaction setBreadCrumbTitle(int);
-    method public abstract android.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
-    method public abstract android.app.FragmentTransaction setCustomAnimations(int, int);
-    method public abstract android.app.FragmentTransaction setCustomAnimations(int, int, int, int);
-    method public abstract android.app.FragmentTransaction setPrimaryNavigationFragment(android.app.Fragment);
-    method public abstract android.app.FragmentTransaction setReorderingAllowed(boolean);
-    method public abstract android.app.FragmentTransaction setTransition(int);
-    method public abstract android.app.FragmentTransaction setTransitionStyle(int);
-    method public abstract android.app.FragmentTransaction show(android.app.Fragment);
-    field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
-    field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
-    field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
-    field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
-    field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
-    field public static final int TRANSIT_NONE = 0; // 0x0
-    field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+  @Deprecated public abstract class FragmentTransaction {
+    ctor @Deprecated public FragmentTransaction();
+    method @Deprecated public abstract android.app.FragmentTransaction add(android.app.Fragment, String);
+    method @Deprecated public abstract android.app.FragmentTransaction add(@IdRes int, android.app.Fragment);
+    method @Deprecated public abstract android.app.FragmentTransaction add(@IdRes int, android.app.Fragment, String);
+    method @Deprecated public abstract android.app.FragmentTransaction addSharedElement(android.view.View, String);
+    method @Deprecated public abstract android.app.FragmentTransaction addToBackStack(@Nullable String);
+    method @Deprecated public abstract android.app.FragmentTransaction attach(android.app.Fragment);
+    method @Deprecated public abstract int commit();
+    method @Deprecated public abstract int commitAllowingStateLoss();
+    method @Deprecated public abstract void commitNow();
+    method @Deprecated public abstract void commitNowAllowingStateLoss();
+    method @Deprecated public abstract android.app.FragmentTransaction detach(android.app.Fragment);
+    method @Deprecated public abstract android.app.FragmentTransaction disallowAddToBackStack();
+    method @Deprecated public abstract android.app.FragmentTransaction hide(android.app.Fragment);
+    method @Deprecated public abstract boolean isAddToBackStackAllowed();
+    method @Deprecated public abstract boolean isEmpty();
+    method @Deprecated public abstract android.app.FragmentTransaction remove(android.app.Fragment);
+    method @Deprecated public abstract android.app.FragmentTransaction replace(@IdRes int, android.app.Fragment);
+    method @Deprecated public abstract android.app.FragmentTransaction replace(@IdRes int, android.app.Fragment, String);
+    method @Deprecated public abstract android.app.FragmentTransaction runOnCommit(Runnable);
+    method @Deprecated public abstract android.app.FragmentTransaction setBreadCrumbShortTitle(@StringRes int);
+    method @Deprecated public abstract android.app.FragmentTransaction setBreadCrumbShortTitle(CharSequence);
+    method @Deprecated public abstract android.app.FragmentTransaction setBreadCrumbTitle(@StringRes int);
+    method @Deprecated public abstract android.app.FragmentTransaction setBreadCrumbTitle(CharSequence);
+    method @Deprecated public abstract android.app.FragmentTransaction setCustomAnimations(@AnimatorRes int, @AnimatorRes int);
+    method @Deprecated public abstract android.app.FragmentTransaction setCustomAnimations(@AnimatorRes int, @AnimatorRes int, @AnimatorRes int, @AnimatorRes int);
+    method @Deprecated public abstract android.app.FragmentTransaction setPrimaryNavigationFragment(android.app.Fragment);
+    method @Deprecated public abstract android.app.FragmentTransaction setReorderingAllowed(boolean);
+    method @Deprecated public abstract android.app.FragmentTransaction setTransition(int);
+    method @Deprecated public abstract android.app.FragmentTransaction setTransitionStyle(@StyleRes int);
+    method @Deprecated public abstract android.app.FragmentTransaction show(android.app.Fragment);
+    field @Deprecated public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+    field @Deprecated public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+    field @Deprecated public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+    field @Deprecated public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+    field @Deprecated public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+    field @Deprecated public static final int TRANSIT_NONE = 0; // 0x0
+    field @Deprecated public static final int TRANSIT_UNSET = -1; // 0xffffffff
   }
 
   public class Instrumentation {
@@ -4999,21 +5004,21 @@
     method public android.os.TestLooperManager acquireLooperManager(android.os.Looper);
     method public void addMonitor(android.app.Instrumentation.ActivityMonitor);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
-    method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
+    method public android.app.Instrumentation.ActivityMonitor addMonitor(String, android.app.Instrumentation.ActivityResult, boolean);
     method public void addResults(android.os.Bundle);
     method public void callActivityOnCreate(android.app.Activity, android.os.Bundle);
     method public void callActivityOnCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
     method public void callActivityOnDestroy(android.app.Activity);
     method public void callActivityOnNewIntent(android.app.Activity, android.content.Intent);
     method public void callActivityOnPause(android.app.Activity);
-    method public void callActivityOnPostCreate(android.app.Activity, android.os.Bundle);
-    method public void callActivityOnPostCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
+    method public void callActivityOnPostCreate(@NonNull android.app.Activity, @Nullable android.os.Bundle);
+    method public void callActivityOnPostCreate(@NonNull android.app.Activity, @Nullable android.os.Bundle, @Nullable android.os.PersistableBundle);
     method public void callActivityOnRestart(android.app.Activity);
-    method public void callActivityOnRestoreInstanceState(android.app.Activity, android.os.Bundle);
-    method public void callActivityOnRestoreInstanceState(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
+    method public void callActivityOnRestoreInstanceState(@NonNull android.app.Activity, @NonNull android.os.Bundle);
+    method public void callActivityOnRestoreInstanceState(@NonNull android.app.Activity, @Nullable android.os.Bundle, @Nullable android.os.PersistableBundle);
     method public void callActivityOnResume(android.app.Activity);
-    method public void callActivityOnSaveInstanceState(android.app.Activity, android.os.Bundle);
-    method public void callActivityOnSaveInstanceState(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
+    method public void callActivityOnSaveInstanceState(@NonNull android.app.Activity, @NonNull android.os.Bundle);
+    method public void callActivityOnSaveInstanceState(@NonNull android.app.Activity, @NonNull android.os.Bundle, @NonNull android.os.PersistableBundle);
     method public void callActivityOnStart(android.app.Activity);
     method public void callActivityOnStop(android.app.Activity);
     method public void callActivityOnUserLeaving(android.app.Activity);
@@ -5025,51 +5030,51 @@
     method public android.os.Bundle getBinderCounts();
     method public android.content.ComponentName getComponentName();
     method public android.content.Context getContext();
-    method public java.lang.String getProcessName();
+    method public String getProcessName();
     method public android.content.Context getTargetContext();
     method public android.app.UiAutomation getUiAutomation();
     method public android.app.UiAutomation getUiAutomation(int);
     method public boolean invokeContextMenuAction(android.app.Activity, int, int);
     method public boolean invokeMenuActionSync(android.app.Activity, int, int);
     method public boolean isProfiling();
-    method public android.app.Activity newActivity(java.lang.Class<?>, android.content.Context, android.os.IBinder, android.app.Application, android.content.Intent, android.content.pm.ActivityInfo, java.lang.CharSequence, android.app.Activity, java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
-    method public android.app.Activity newActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
-    method public android.app.Application newApplication(java.lang.ClassLoader, java.lang.String, android.content.Context) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
-    method public static android.app.Application newApplication(java.lang.Class<?>, android.content.Context) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.app.Activity newActivity(Class<?>, android.content.Context, android.os.IBinder, android.app.Application, android.content.Intent, android.content.pm.ActivityInfo, CharSequence, android.app.Activity, String, Object) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.app.Activity newActivity(ClassLoader, String, android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.app.Application newApplication(ClassLoader, String, android.content.Context) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static android.app.Application newApplication(Class<?>, android.content.Context) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
     method public void onCreate(android.os.Bundle);
     method public void onDestroy();
-    method public boolean onException(java.lang.Object, java.lang.Throwable);
+    method public boolean onException(Object, Throwable);
     method public void onStart();
     method public void removeMonitor(android.app.Instrumentation.ActivityMonitor);
-    method public void runOnMainSync(java.lang.Runnable);
+    method public void runOnMainSync(Runnable);
     method public void sendCharacterSync(int);
     method public void sendKeyDownUpSync(int);
     method public void sendKeySync(android.view.KeyEvent);
     method public void sendPointerSync(android.view.MotionEvent);
     method public void sendStatus(int, android.os.Bundle);
-    method public void sendStringSync(java.lang.String);
+    method public void sendStringSync(String);
     method public void sendTrackballEventSync(android.view.MotionEvent);
     method public void setAutomaticPerformanceSnapshots();
     method public void setInTouchMode(boolean);
     method public void start();
     method public android.app.Activity startActivitySync(android.content.Intent);
-    method public android.app.Activity startActivitySync(android.content.Intent, android.os.Bundle);
-    method public deprecated void startAllocCounting();
+    method @NonNull public android.app.Activity startActivitySync(@NonNull android.content.Intent, @Nullable android.os.Bundle);
+    method @Deprecated public void startAllocCounting();
     method public void startPerformanceSnapshot();
     method public void startProfiling();
-    method public deprecated void stopAllocCounting();
+    method @Deprecated public void stopAllocCounting();
     method public void stopProfiling();
-    method public void waitForIdle(java.lang.Runnable);
+    method public void waitForIdle(Runnable);
     method public void waitForIdleSync();
     method public android.app.Activity waitForMonitor(android.app.Instrumentation.ActivityMonitor);
     method public android.app.Activity waitForMonitorWithTimeout(android.app.Instrumentation.ActivityMonitor, long);
-    field public static final java.lang.String REPORT_KEY_IDENTIFIER = "id";
-    field public static final java.lang.String REPORT_KEY_STREAMRESULT = "stream";
+    field public static final String REPORT_KEY_IDENTIFIER = "id";
+    field public static final String REPORT_KEY_STREAMRESULT = "stream";
   }
 
   public static class Instrumentation.ActivityMonitor {
     ctor public Instrumentation.ActivityMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
-    ctor public Instrumentation.ActivityMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
+    ctor public Instrumentation.ActivityMonitor(String, android.app.Instrumentation.ActivityResult, boolean);
     ctor public Instrumentation.ActivityMonitor();
     method public final android.content.IntentFilter getFilter();
     method public final int getHits();
@@ -5088,39 +5093,39 @@
   }
 
   public abstract class IntentService extends android.app.Service {
-    ctor public IntentService(java.lang.String);
-    method public android.os.IBinder onBind(android.content.Intent);
-    method protected abstract void onHandleIntent(android.content.Intent);
-    method public void onStart(android.content.Intent, int);
+    ctor public IntentService(String);
+    method @Nullable public android.os.IBinder onBind(android.content.Intent);
+    method @WorkerThread protected abstract void onHandleIntent(@Nullable android.content.Intent);
+    method public void onStart(@Nullable android.content.Intent, int);
     method public void setIntentRedelivery(boolean);
   }
 
   public class KeyguardManager {
-    method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
-    method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
-    method public deprecated boolean inKeyguardRestrictedInputMode();
+    method public android.content.Intent createConfirmDeviceCredentialIntent(CharSequence, CharSequence);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.DISABLE_KEYGUARD) public void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
+    method @Deprecated public boolean inKeyguardRestrictedInputMode();
     method public boolean isDeviceLocked();
     method public boolean isDeviceSecure();
     method public boolean isKeyguardLocked();
     method public boolean isKeyguardSecure();
-    method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
-    method public void requestDismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback);
+    method @Deprecated public android.app.KeyguardManager.KeyguardLock newKeyguardLock(String);
+    method public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable android.app.KeyguardManager.KeyguardDismissCallback);
   }
 
-  public static abstract class KeyguardManager.KeyguardDismissCallback {
+  public abstract static class KeyguardManager.KeyguardDismissCallback {
     ctor public KeyguardManager.KeyguardDismissCallback();
     method public void onDismissCancelled();
     method public void onDismissError();
     method public void onDismissSucceeded();
   }
 
-  public deprecated class KeyguardManager.KeyguardLock {
-    method public void disableKeyguard();
-    method public void reenableKeyguard();
+  @Deprecated public class KeyguardManager.KeyguardLock {
+    method @Deprecated @RequiresPermission(android.Manifest.permission.DISABLE_KEYGUARD) public void disableKeyguard();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.DISABLE_KEYGUARD) public void reenableKeyguard();
   }
 
-  public static abstract deprecated interface KeyguardManager.OnKeyguardExitResult {
-    method public abstract void onKeyguardExitResult(boolean);
+  @Deprecated public static interface KeyguardManager.OnKeyguardExitResult {
+    method @Deprecated public void onKeyguardExitResult(boolean);
   }
 
   public abstract class LauncherActivity extends android.app.ListActivity {
@@ -5140,11 +5145,11 @@
 
   public static class LauncherActivity.ListItem {
     ctor public LauncherActivity.ListItem();
-    field public java.lang.String className;
+    field public String className;
     field public android.os.Bundle extras;
     field public android.graphics.drawable.Drawable icon;
-    field public java.lang.CharSequence label;
-    field public java.lang.String packageName;
+    field public CharSequence label;
+    field public String packageName;
     field public android.content.pm.ResolveInfo resolveInfo;
   }
 
@@ -5159,50 +5164,50 @@
     method public void setSelection(int);
   }
 
-  public deprecated class ListFragment extends android.app.Fragment {
-    ctor public ListFragment();
-    method public android.widget.ListAdapter getListAdapter();
-    method public android.widget.ListView getListView();
-    method public long getSelectedItemId();
-    method public int getSelectedItemPosition();
-    method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
-    method public void setEmptyText(java.lang.CharSequence);
-    method public void setListAdapter(android.widget.ListAdapter);
-    method public void setListShown(boolean);
-    method public void setListShownNoAnimation(boolean);
-    method public void setSelection(int);
+  @Deprecated public class ListFragment extends android.app.Fragment {
+    ctor @Deprecated public ListFragment();
+    method @Deprecated public android.widget.ListAdapter getListAdapter();
+    method @Deprecated public android.widget.ListView getListView();
+    method @Deprecated public long getSelectedItemId();
+    method @Deprecated public int getSelectedItemPosition();
+    method @Deprecated public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+    method @Deprecated public void setEmptyText(CharSequence);
+    method @Deprecated public void setListAdapter(android.widget.ListAdapter);
+    method @Deprecated public void setListShown(boolean);
+    method @Deprecated public void setListShownNoAnimation(boolean);
+    method @Deprecated public void setSelection(int);
   }
 
-  public abstract deprecated class LoaderManager {
-    ctor public LoaderManager();
-    method public abstract void destroyLoader(int);
-    method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public static void enableDebugLogging(boolean);
-    method public abstract <D> android.content.Loader<D> getLoader(int);
-    method public abstract <D> android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
-    method public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
+  @Deprecated public abstract class LoaderManager {
+    ctor @Deprecated public LoaderManager();
+    method @Deprecated public abstract void destroyLoader(int);
+    method @Deprecated public abstract void dump(String, java.io.FileDescriptor, java.io.PrintWriter, String[]);
+    method @Deprecated public static void enableDebugLogging(boolean);
+    method @Deprecated public abstract <D> android.content.Loader<D> getLoader(int);
+    method @Deprecated public abstract <D> android.content.Loader<D> initLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
+    method @Deprecated public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
   }
 
-  public static abstract deprecated interface LoaderManager.LoaderCallbacks<D> {
-    method public abstract android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
-    method public abstract void onLoadFinished(android.content.Loader<D>, D);
-    method public abstract void onLoaderReset(android.content.Loader<D>);
+  @Deprecated public static interface LoaderManager.LoaderCallbacks<D> {
+    method @Deprecated public android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
+    method @Deprecated public void onLoadFinished(android.content.Loader<D>, D);
+    method @Deprecated public void onLoaderReset(android.content.Loader<D>);
   }
 
-  public deprecated class LocalActivityManager {
-    ctor public LocalActivityManager(android.app.Activity, boolean);
-    method public android.view.Window destroyActivity(java.lang.String, boolean);
-    method public void dispatchCreate(android.os.Bundle);
-    method public void dispatchDestroy(boolean);
-    method public void dispatchPause(boolean);
-    method public void dispatchResume();
-    method public void dispatchStop();
-    method public android.app.Activity getActivity(java.lang.String);
-    method public android.app.Activity getCurrentActivity();
-    method public java.lang.String getCurrentId();
-    method public void removeAllActivities();
-    method public android.os.Bundle saveInstanceState();
-    method public android.view.Window startActivity(java.lang.String, android.content.Intent);
+  @Deprecated public class LocalActivityManager {
+    ctor @Deprecated public LocalActivityManager(android.app.Activity, boolean);
+    method @Deprecated public android.view.Window destroyActivity(String, boolean);
+    method @Deprecated public void dispatchCreate(android.os.Bundle);
+    method @Deprecated public void dispatchDestroy(boolean);
+    method @Deprecated public void dispatchPause(boolean);
+    method @Deprecated public void dispatchResume();
+    method @Deprecated public void dispatchStop();
+    method @Deprecated public android.app.Activity getActivity(String);
+    method @Deprecated public android.app.Activity getCurrentActivity();
+    method @Deprecated public String getCurrentId();
+    method @Deprecated public void removeAllActivities();
+    method @Deprecated public android.os.Bundle saveInstanceState();
+    method @Deprecated public android.view.Window startActivity(String, android.content.Intent);
   }
 
   public class MediaRouteActionProvider extends android.view.ActionProvider {
@@ -5234,149 +5239,149 @@
     method public void surfaceCreated(android.view.SurfaceHolder);
     method public void surfaceDestroyed(android.view.SurfaceHolder);
     method public void surfaceRedrawNeeded(android.view.SurfaceHolder);
-    field public static final java.lang.String META_DATA_FUNC_NAME = "android.app.func_name";
-    field public static final java.lang.String META_DATA_LIB_NAME = "android.app.lib_name";
+    field public static final String META_DATA_FUNC_NAME = "android.app.func_name";
+    field public static final String META_DATA_LIB_NAME = "android.app.lib_name";
   }
 
   public class Notification implements android.os.Parcelable {
     ctor public Notification();
-    ctor public deprecated Notification(int, java.lang.CharSequence, long);
+    ctor @Deprecated public Notification(int, CharSequence, long);
     ctor public Notification(android.os.Parcel);
     method public android.app.Notification clone();
     method public int describeContents();
     method public boolean getAllowSystemGeneratedContextualActions();
-    method public android.app.PendingIntent getAppOverlayIntent();
     method public int getBadgeIconType();
-    method public java.lang.String getChannelId();
-    method public java.lang.String getGroup();
+    method public android.app.Notification.BubbleMetadata getBubbleMetadata();
+    method public String getChannelId();
+    method public String getGroup();
     method public int getGroupAlertBehavior();
     method public android.graphics.drawable.Icon getLargeIcon();
-    method public java.lang.CharSequence getSettingsText();
-    method public java.lang.String getShortcutId();
+    method public CharSequence getSettingsText();
+    method public String getShortcutId();
     method public android.graphics.drawable.Icon getSmallIcon();
-    method public java.lang.String getSortKey();
+    method public String getSortKey();
     method public long getTimeoutAfter();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
     field public static final int BADGE_ICON_LARGE = 2; // 0x2
     field public static final int BADGE_ICON_NONE = 0; // 0x0
     field public static final int BADGE_ICON_SMALL = 1; // 0x1
-    field public static final java.lang.String CATEGORY_ALARM = "alarm";
-    field public static final java.lang.String CATEGORY_CALL = "call";
-    field public static final java.lang.String CATEGORY_EMAIL = "email";
-    field public static final java.lang.String CATEGORY_ERROR = "err";
-    field public static final java.lang.String CATEGORY_EVENT = "event";
-    field public static final java.lang.String CATEGORY_MESSAGE = "msg";
-    field public static final java.lang.String CATEGORY_NAVIGATION = "navigation";
-    field public static final java.lang.String CATEGORY_PROGRESS = "progress";
-    field public static final java.lang.String CATEGORY_PROMO = "promo";
-    field public static final java.lang.String CATEGORY_RECOMMENDATION = "recommendation";
-    field public static final java.lang.String CATEGORY_REMINDER = "reminder";
-    field public static final java.lang.String CATEGORY_SERVICE = "service";
-    field public static final java.lang.String CATEGORY_SOCIAL = "social";
-    field public static final java.lang.String CATEGORY_STATUS = "status";
-    field public static final java.lang.String CATEGORY_SYSTEM = "sys";
-    field public static final java.lang.String CATEGORY_TRANSPORT = "transport";
-    field public static final int COLOR_DEFAULT = 0; // 0x0
+    field public static final String CATEGORY_ALARM = "alarm";
+    field public static final String CATEGORY_CALL = "call";
+    field public static final String CATEGORY_EMAIL = "email";
+    field public static final String CATEGORY_ERROR = "err";
+    field public static final String CATEGORY_EVENT = "event";
+    field public static final String CATEGORY_MESSAGE = "msg";
+    field public static final String CATEGORY_NAVIGATION = "navigation";
+    field public static final String CATEGORY_PROGRESS = "progress";
+    field public static final String CATEGORY_PROMO = "promo";
+    field public static final String CATEGORY_RECOMMENDATION = "recommendation";
+    field public static final String CATEGORY_REMINDER = "reminder";
+    field public static final String CATEGORY_SERVICE = "service";
+    field public static final String CATEGORY_SOCIAL = "social";
+    field public static final String CATEGORY_STATUS = "status";
+    field public static final String CATEGORY_SYSTEM = "sys";
+    field public static final String CATEGORY_TRANSPORT = "transport";
+    field @ColorInt public static final int COLOR_DEFAULT = 0; // 0x0
     field public static final android.os.Parcelable.Creator<android.app.Notification> CREATOR;
     field public static final int DEFAULT_ALL = -1; // 0xffffffff
     field public static final int DEFAULT_LIGHTS = 4; // 0x4
     field public static final int DEFAULT_SOUND = 1; // 0x1
     field public static final int DEFAULT_VIBRATE = 2; // 0x2
-    field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
-    field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
-    field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
-    field public static final java.lang.String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
-    field public static final java.lang.String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
-    field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
-    field public static final java.lang.String EXTRA_COLORIZED = "android.colorized";
-    field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
-    field public static final java.lang.String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
-    field public static final java.lang.String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
-    field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
-    field public static final java.lang.String EXTRA_IS_GROUP_CONVERSATION = "android.isGroupConversation";
-    field public static final deprecated java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
-    field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
-    field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession";
-    field public static final java.lang.String EXTRA_MESSAGES = "android.messages";
-    field public static final java.lang.String EXTRA_MESSAGING_PERSON = "android.messagingUser";
-    field public static final java.lang.String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID";
-    field public static final java.lang.String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG";
-    field public static final deprecated java.lang.String EXTRA_PEOPLE = "android.people";
-    field public static final java.lang.String EXTRA_PEOPLE_LIST = "android.people.list";
-    field public static final java.lang.String EXTRA_PICTURE = "android.picture";
-    field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
-    field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
-    field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
-    field public static final java.lang.String EXTRA_REMOTE_INPUT_DRAFT = "android.remoteInputDraft";
-    field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
-    field public static final deprecated java.lang.String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
-    field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
-    field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
-    field public static final deprecated java.lang.String EXTRA_SMALL_ICON = "android.icon";
-    field public static final java.lang.String EXTRA_SUB_TEXT = "android.subText";
-    field public static final java.lang.String EXTRA_SUMMARY_TEXT = "android.summaryText";
-    field public static final java.lang.String EXTRA_TEMPLATE = "android.template";
-    field public static final java.lang.String EXTRA_TEXT = "android.text";
-    field public static final java.lang.String EXTRA_TEXT_LINES = "android.textLines";
-    field public static final java.lang.String EXTRA_TITLE = "android.title";
-    field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big";
+    field public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+    field public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
+    field public static final String EXTRA_BIG_TEXT = "android.bigText";
+    field public static final String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
+    field public static final String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
+    field public static final String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
+    field public static final String EXTRA_COLORIZED = "android.colorized";
+    field public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+    field public static final String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+    field public static final String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
+    field public static final String EXTRA_INFO_TEXT = "android.infoText";
+    field public static final String EXTRA_IS_GROUP_CONVERSATION = "android.isGroupConversation";
+    field @Deprecated public static final String EXTRA_LARGE_ICON = "android.largeIcon";
+    field public static final String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+    field public static final String EXTRA_MEDIA_SESSION = "android.mediaSession";
+    field public static final String EXTRA_MESSAGES = "android.messages";
+    field public static final String EXTRA_MESSAGING_PERSON = "android.messagingUser";
+    field public static final String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID";
+    field public static final String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG";
+    field @Deprecated public static final String EXTRA_PEOPLE = "android.people";
+    field public static final String EXTRA_PEOPLE_LIST = "android.people.list";
+    field public static final String EXTRA_PICTURE = "android.picture";
+    field public static final String EXTRA_PROGRESS = "android.progress";
+    field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+    field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
+    field public static final String EXTRA_REMOTE_INPUT_DRAFT = "android.remoteInputDraft";
+    field public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+    field @Deprecated public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
+    field public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+    field public static final String EXTRA_SHOW_WHEN = "android.showWhen";
+    field @Deprecated public static final String EXTRA_SMALL_ICON = "android.icon";
+    field public static final String EXTRA_SUB_TEXT = "android.subText";
+    field public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
+    field public static final String EXTRA_TEMPLATE = "android.template";
+    field public static final String EXTRA_TEXT = "android.text";
+    field public static final String EXTRA_TEXT_LINES = "android.textLines";
+    field public static final String EXTRA_TITLE = "android.title";
+    field public static final String EXTRA_TITLE_BIG = "android.title.big";
     field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
     field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
     field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
-    field public static final deprecated int FLAG_HIGH_PRIORITY = 128; // 0x80
+    field @Deprecated public static final int FLAG_HIGH_PRIORITY = 128; // 0x80
     field public static final int FLAG_INSISTENT = 4; // 0x4
     field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
     field public static final int FLAG_NO_CLEAR = 32; // 0x20
     field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
     field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
-    field public static final deprecated int FLAG_SHOW_LIGHTS = 1; // 0x1
+    field @Deprecated public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
     field public static final int GROUP_ALERT_ALL = 0; // 0x0
     field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
     field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
-    field public static final java.lang.String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
-    field public static final deprecated int PRIORITY_DEFAULT = 0; // 0x0
-    field public static final deprecated int PRIORITY_HIGH = 1; // 0x1
-    field public static final deprecated int PRIORITY_LOW = -1; // 0xffffffff
-    field public static final deprecated int PRIORITY_MAX = 2; // 0x2
-    field public static final deprecated int PRIORITY_MIN = -2; // 0xfffffffe
-    field public static final deprecated int STREAM_DEFAULT = -1; // 0xffffffff
+    field public static final String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
+    field @Deprecated public static final int PRIORITY_DEFAULT = 0; // 0x0
+    field @Deprecated public static final int PRIORITY_HIGH = 1; // 0x1
+    field @Deprecated public static final int PRIORITY_LOW = -1; // 0xffffffff
+    field @Deprecated public static final int PRIORITY_MAX = 2; // 0x2
+    field @Deprecated public static final int PRIORITY_MIN = -2; // 0xfffffffe
+    field @Deprecated public static final int STREAM_DEFAULT = -1; // 0xffffffff
     field public static final int VISIBILITY_PRIVATE = 0; // 0x0
     field public static final int VISIBILITY_PUBLIC = 1; // 0x1
     field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
     field public android.app.Notification.Action[] actions;
-    field public deprecated android.media.AudioAttributes audioAttributes;
-    field public deprecated int audioStreamType;
-    field public deprecated android.widget.RemoteViews bigContentView;
-    field public java.lang.String category;
-    field public int color;
+    field @Deprecated public android.media.AudioAttributes audioAttributes;
+    field @Deprecated public int audioStreamType;
+    field @Deprecated public android.widget.RemoteViews bigContentView;
+    field public String category;
+    field @ColorInt public int color;
     field public android.app.PendingIntent contentIntent;
-    field public deprecated android.widget.RemoteViews contentView;
-    field public deprecated int defaults;
+    field @Deprecated public android.widget.RemoteViews contentView;
+    field @Deprecated public int defaults;
     field public android.app.PendingIntent deleteIntent;
     field public android.os.Bundle extras;
     field public int flags;
     field public android.app.PendingIntent fullScreenIntent;
-    field public deprecated android.widget.RemoteViews headsUpContentView;
-    field public deprecated int icon;
+    field @Deprecated public android.widget.RemoteViews headsUpContentView;
+    field @Deprecated @DrawableRes public int icon;
     field public int iconLevel;
-    field public deprecated android.graphics.Bitmap largeIcon;
-    field public deprecated int ledARGB;
-    field public deprecated int ledOffMS;
-    field public deprecated int ledOnMS;
+    field @Deprecated public android.graphics.Bitmap largeIcon;
+    field @Deprecated @ColorInt public int ledARGB;
+    field @Deprecated public int ledOffMS;
+    field @Deprecated public int ledOnMS;
     field public int number;
-    field public deprecated int priority;
+    field @Deprecated public int priority;
     field public android.app.Notification publicVersion;
-    field public deprecated android.net.Uri sound;
-    field public java.lang.CharSequence tickerText;
-    field public deprecated android.widget.RemoteViews tickerView;
-    field public deprecated long[] vibrate;
+    field @Deprecated public android.net.Uri sound;
+    field public CharSequence tickerText;
+    field @Deprecated public android.widget.RemoteViews tickerView;
+    field @Deprecated public long[] vibrate;
     field public int visibility;
     field public long when;
   }
 
   public static class Notification.Action implements android.os.Parcelable {
-    ctor public deprecated Notification.Action(int, java.lang.CharSequence, android.app.PendingIntent);
+    ctor @Deprecated public Notification.Action(int, CharSequence, android.app.PendingIntent);
     method public android.app.Notification.Action clone();
     method public int describeContents();
     method public boolean getAllowGeneratedReplies();
@@ -5385,11 +5390,11 @@
     method public android.graphics.drawable.Icon getIcon();
     method public android.app.RemoteInput[] getRemoteInputs();
     method public int getSemanticAction();
+    method public boolean isContextual();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR;
     field public static final int SEMANTIC_ACTION_ARCHIVE = 5; // 0x5
     field public static final int SEMANTIC_ACTION_CALL = 10; // 0xa
-    field public static final int SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION = 11; // 0xb
     field public static final int SEMANTIC_ACTION_DELETE = 4; // 0x4
     field public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; // 0x2
     field public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; // 0x3
@@ -5400,13 +5405,13 @@
     field public static final int SEMANTIC_ACTION_THUMBS_UP = 8; // 0x8
     field public static final int SEMANTIC_ACTION_UNMUTE = 7; // 0x7
     field public android.app.PendingIntent actionIntent;
-    field public deprecated int icon;
-    field public java.lang.CharSequence title;
+    field @Deprecated public int icon;
+    field public CharSequence title;
   }
 
   public static final class Notification.Action.Builder {
-    ctor public deprecated Notification.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent);
-    ctor public Notification.Action.Builder(android.graphics.drawable.Icon, java.lang.CharSequence, android.app.PendingIntent);
+    ctor @Deprecated public Notification.Action.Builder(int, CharSequence, android.app.PendingIntent);
+    ctor public Notification.Action.Builder(android.graphics.drawable.Icon, CharSequence, android.app.PendingIntent);
     ctor public Notification.Action.Builder(android.app.Notification.Action);
     method public android.app.Notification.Action.Builder addExtras(android.os.Bundle);
     method public android.app.Notification.Action.Builder addRemoteInput(android.app.RemoteInput);
@@ -5414,11 +5419,12 @@
     method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender);
     method public android.os.Bundle getExtras();
     method public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean);
+    method public android.app.Notification.Action.Builder setContextual(boolean);
     method public android.app.Notification.Action.Builder setSemanticAction(int);
   }
 
-  public static abstract interface Notification.Action.Extender {
-    method public abstract android.app.Notification.Action.Builder extend(android.app.Notification.Action.Builder);
+  public static interface Notification.Action.Extender {
+    method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Builder);
   }
 
   public static final class Notification.Action.WearableExtender implements android.app.Notification.Action.Extender {
@@ -5426,45 +5432,64 @@
     ctor public Notification.Action.WearableExtender(android.app.Notification.Action);
     method public android.app.Notification.Action.WearableExtender clone();
     method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Builder);
-    method public deprecated java.lang.CharSequence getCancelLabel();
-    method public deprecated java.lang.CharSequence getConfirmLabel();
+    method @Deprecated public CharSequence getCancelLabel();
+    method @Deprecated public CharSequence getConfirmLabel();
     method public boolean getHintDisplayActionInline();
     method public boolean getHintLaunchesActivity();
-    method public deprecated java.lang.CharSequence getInProgressLabel();
+    method @Deprecated public CharSequence getInProgressLabel();
     method public boolean isAvailableOffline();
     method public android.app.Notification.Action.WearableExtender setAvailableOffline(boolean);
-    method public deprecated android.app.Notification.Action.WearableExtender setCancelLabel(java.lang.CharSequence);
-    method public deprecated android.app.Notification.Action.WearableExtender setConfirmLabel(java.lang.CharSequence);
+    method @Deprecated public android.app.Notification.Action.WearableExtender setCancelLabel(CharSequence);
+    method @Deprecated public android.app.Notification.Action.WearableExtender setConfirmLabel(CharSequence);
     method public android.app.Notification.Action.WearableExtender setHintDisplayActionInline(boolean);
     method public android.app.Notification.Action.WearableExtender setHintLaunchesActivity(boolean);
-    method public deprecated android.app.Notification.Action.WearableExtender setInProgressLabel(java.lang.CharSequence);
+    method @Deprecated public android.app.Notification.Action.WearableExtender setInProgressLabel(CharSequence);
   }
 
   public static class Notification.BigPictureStyle extends android.app.Notification.Style {
     ctor public Notification.BigPictureStyle();
-    ctor public deprecated Notification.BigPictureStyle(android.app.Notification.Builder);
+    ctor @Deprecated public Notification.BigPictureStyle(android.app.Notification.Builder);
     method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.Bitmap);
     method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.drawable.Icon);
     method public android.app.Notification.BigPictureStyle bigPicture(android.graphics.Bitmap);
-    method public android.app.Notification.BigPictureStyle setBigContentTitle(java.lang.CharSequence);
-    method public android.app.Notification.BigPictureStyle setSummaryText(java.lang.CharSequence);
+    method public android.app.Notification.BigPictureStyle setBigContentTitle(CharSequence);
+    method public android.app.Notification.BigPictureStyle setSummaryText(CharSequence);
   }
 
   public static class Notification.BigTextStyle extends android.app.Notification.Style {
     ctor public Notification.BigTextStyle();
-    ctor public deprecated Notification.BigTextStyle(android.app.Notification.Builder);
-    method public android.app.Notification.BigTextStyle bigText(java.lang.CharSequence);
-    method public android.app.Notification.BigTextStyle setBigContentTitle(java.lang.CharSequence);
-    method public android.app.Notification.BigTextStyle setSummaryText(java.lang.CharSequence);
+    ctor @Deprecated public Notification.BigTextStyle(android.app.Notification.Builder);
+    method public android.app.Notification.BigTextStyle bigText(CharSequence);
+    method public android.app.Notification.BigTextStyle setBigContentTitle(CharSequence);
+    method public android.app.Notification.BigTextStyle setSummaryText(CharSequence);
+  }
+
+  public static final class Notification.BubbleMetadata implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getDesiredHeight();
+    method public android.graphics.drawable.Icon getIcon();
+    method public android.app.PendingIntent getIntent();
+    method public CharSequence getTitle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
+  }
+
+  public static class Notification.BubbleMetadata.Builder {
+    ctor public Notification.BubbleMetadata.Builder();
+    method public android.app.Notification.BubbleMetadata build();
+    method public android.app.Notification.BubbleMetadata.Builder setDesiredHeight(int);
+    method public android.app.Notification.BubbleMetadata.Builder setIcon(android.graphics.drawable.Icon);
+    method public android.app.Notification.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
+    method public android.app.Notification.BubbleMetadata.Builder setTitle(CharSequence);
   }
 
   public static class Notification.Builder {
-    ctor public Notification.Builder(android.content.Context, java.lang.String);
-    ctor public deprecated Notification.Builder(android.content.Context);
-    method public deprecated android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
+    ctor public Notification.Builder(android.content.Context, String);
+    ctor @Deprecated public Notification.Builder(android.content.Context);
+    method @Deprecated public android.app.Notification.Builder addAction(int, CharSequence, android.app.PendingIntent);
     method public android.app.Notification.Builder addAction(android.app.Notification.Action);
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
-    method public deprecated android.app.Notification.Builder addPerson(java.lang.String);
+    method @Deprecated public android.app.Notification.Builder addPerson(String);
     method public android.app.Notification.Builder addPerson(android.app.Person);
     method public android.app.Notification build();
     method public android.widget.RemoteViews createBigContentView();
@@ -5472,62 +5497,62 @@
     method public android.widget.RemoteViews createHeadsUpContentView();
     method public android.app.Notification.Builder extend(android.app.Notification.Extender);
     method public android.os.Bundle getExtras();
-    method public deprecated android.app.Notification getNotification();
+    method @Deprecated public android.app.Notification getNotification();
     method public android.app.Notification.Style getStyle();
     method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
     method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
     method public android.app.Notification.Builder setAllowSystemGeneratedContextualActions(boolean);
-    method public android.app.Notification.Builder setAppOverlayIntent(android.app.PendingIntent);
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setBadgeIconType(int);
-    method public android.app.Notification.Builder setCategory(java.lang.String);
-    method public android.app.Notification.Builder setChannelId(java.lang.String);
+    method public android.app.Notification.Builder setBubbleMetadata(android.app.Notification.BubbleMetadata);
+    method public android.app.Notification.Builder setCategory(String);
+    method public android.app.Notification.Builder setChannelId(String);
     method public android.app.Notification.Builder setChronometerCountDown(boolean);
-    method public android.app.Notification.Builder setColor(int);
+    method public android.app.Notification.Builder setColor(@ColorInt int);
     method public android.app.Notification.Builder setColorized(boolean);
-    method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
-    method public deprecated android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
+    method @Deprecated public android.app.Notification.Builder setContent(android.widget.RemoteViews);
+    method @Deprecated public android.app.Notification.Builder setContentInfo(CharSequence);
     method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
-    method public android.app.Notification.Builder setContentText(java.lang.CharSequence);
-    method public android.app.Notification.Builder setContentTitle(java.lang.CharSequence);
+    method public android.app.Notification.Builder setContentText(CharSequence);
+    method public android.app.Notification.Builder setContentTitle(CharSequence);
     method public android.app.Notification.Builder setCustomBigContentView(android.widget.RemoteViews);
     method public android.app.Notification.Builder setCustomContentView(android.widget.RemoteViews);
     method public android.app.Notification.Builder setCustomHeadsUpContentView(android.widget.RemoteViews);
-    method public deprecated android.app.Notification.Builder setDefaults(int);
+    method @Deprecated public android.app.Notification.Builder setDefaults(int);
     method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
     method public android.app.Notification.Builder setExtras(android.os.Bundle);
     method public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
-    method public android.app.Notification.Builder setGroup(java.lang.String);
+    method public android.app.Notification.Builder setGroup(String);
     method public android.app.Notification.Builder setGroupAlertBehavior(int);
     method public android.app.Notification.Builder setGroupSummary(boolean);
     method public android.app.Notification.Builder setLargeIcon(android.graphics.Bitmap);
     method public android.app.Notification.Builder setLargeIcon(android.graphics.drawable.Icon);
-    method public deprecated android.app.Notification.Builder setLights(int, int, int);
+    method @Deprecated public android.app.Notification.Builder setLights(@ColorInt int, int, int);
     method public android.app.Notification.Builder setLocalOnly(boolean);
     method public android.app.Notification.Builder setNumber(int);
     method public android.app.Notification.Builder setOngoing(boolean);
     method public android.app.Notification.Builder setOnlyAlertOnce(boolean);
-    method public deprecated android.app.Notification.Builder setPriority(int);
+    method @Deprecated public android.app.Notification.Builder setPriority(int);
     method public android.app.Notification.Builder setProgress(int, int, boolean);
     method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
-    method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
-    method public android.app.Notification.Builder setSettingsText(java.lang.CharSequence);
-    method public android.app.Notification.Builder setShortcutId(java.lang.String);
+    method public android.app.Notification.Builder setRemoteInputHistory(CharSequence[]);
+    method public android.app.Notification.Builder setSettingsText(CharSequence);
+    method public android.app.Notification.Builder setShortcutId(String);
     method public android.app.Notification.Builder setShowWhen(boolean);
-    method public android.app.Notification.Builder setSmallIcon(int);
-    method public android.app.Notification.Builder setSmallIcon(int, int);
+    method public android.app.Notification.Builder setSmallIcon(@DrawableRes int);
+    method public android.app.Notification.Builder setSmallIcon(@DrawableRes int, int);
     method public android.app.Notification.Builder setSmallIcon(android.graphics.drawable.Icon);
-    method public android.app.Notification.Builder setSortKey(java.lang.String);
-    method public deprecated android.app.Notification.Builder setSound(android.net.Uri);
-    method public deprecated android.app.Notification.Builder setSound(android.net.Uri, int);
-    method public deprecated android.app.Notification.Builder setSound(android.net.Uri, android.media.AudioAttributes);
+    method public android.app.Notification.Builder setSortKey(String);
+    method @Deprecated public android.app.Notification.Builder setSound(android.net.Uri);
+    method @Deprecated public android.app.Notification.Builder setSound(android.net.Uri, int);
+    method @Deprecated public android.app.Notification.Builder setSound(android.net.Uri, android.media.AudioAttributes);
     method public android.app.Notification.Builder setStyle(android.app.Notification.Style);
-    method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
-    method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
-    method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
+    method public android.app.Notification.Builder setSubText(CharSequence);
+    method public android.app.Notification.Builder setTicker(CharSequence);
+    method @Deprecated public android.app.Notification.Builder setTicker(CharSequence, android.widget.RemoteViews);
     method public android.app.Notification.Builder setTimeoutAfter(long);
     method public android.app.Notification.Builder setUsesChronometer(boolean);
-    method public deprecated android.app.Notification.Builder setVibrate(long[]);
+    method @Deprecated public android.app.Notification.Builder setVibrate(long[]);
     method public android.app.Notification.Builder setVisibility(int);
     method public android.app.Notification.Builder setWhen(long);
   }
@@ -5536,17 +5561,17 @@
     ctor public Notification.CarExtender();
     ctor public Notification.CarExtender(android.app.Notification);
     method public android.app.Notification.Builder extend(android.app.Notification.Builder);
-    method public int getColor();
+    method @ColorInt public int getColor();
     method public android.graphics.Bitmap getLargeIcon();
     method public android.app.Notification.CarExtender.UnreadConversation getUnreadConversation();
-    method public android.app.Notification.CarExtender setColor(int);
+    method public android.app.Notification.CarExtender setColor(@ColorInt int);
     method public android.app.Notification.CarExtender setLargeIcon(android.graphics.Bitmap);
     method public android.app.Notification.CarExtender setUnreadConversation(android.app.Notification.CarExtender.UnreadConversation);
   }
 
   public static class Notification.CarExtender.Builder {
-    ctor public Notification.CarExtender.Builder(java.lang.String);
-    method public android.app.Notification.CarExtender.Builder addMessage(java.lang.String);
+    ctor public Notification.CarExtender.Builder(String);
+    method public android.app.Notification.CarExtender.Builder addMessage(String);
     method public android.app.Notification.CarExtender.UnreadConversation build();
     method public android.app.Notification.CarExtender.Builder setLatestTimestamp(long);
     method public android.app.Notification.CarExtender.Builder setReadPendingIntent(android.app.PendingIntent);
@@ -5555,9 +5580,9 @@
 
   public static class Notification.CarExtender.UnreadConversation {
     method public long getLatestTimestamp();
-    method public java.lang.String[] getMessages();
-    method public java.lang.String getParticipant();
-    method public java.lang.String[] getParticipants();
+    method public String[] getMessages();
+    method public String getParticipant();
+    method public String[] getParticipants();
     method public android.app.PendingIntent getReadPendingIntent();
     method public android.app.RemoteInput getRemoteInput();
     method public android.app.PendingIntent getReplyPendingIntent();
@@ -5571,63 +5596,63 @@
     ctor public Notification.DecoratedMediaCustomViewStyle();
   }
 
-  public static abstract interface Notification.Extender {
-    method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
+  public static interface Notification.Extender {
+    method public android.app.Notification.Builder extend(android.app.Notification.Builder);
   }
 
   public static class Notification.InboxStyle extends android.app.Notification.Style {
     ctor public Notification.InboxStyle();
-    ctor public deprecated Notification.InboxStyle(android.app.Notification.Builder);
-    method public android.app.Notification.InboxStyle addLine(java.lang.CharSequence);
-    method public android.app.Notification.InboxStyle setBigContentTitle(java.lang.CharSequence);
-    method public android.app.Notification.InboxStyle setSummaryText(java.lang.CharSequence);
+    ctor @Deprecated public Notification.InboxStyle(android.app.Notification.Builder);
+    method public android.app.Notification.InboxStyle addLine(CharSequence);
+    method public android.app.Notification.InboxStyle setBigContentTitle(CharSequence);
+    method public android.app.Notification.InboxStyle setSummaryText(CharSequence);
   }
 
   public static class Notification.MediaStyle extends android.app.Notification.Style {
     ctor public Notification.MediaStyle();
-    ctor public deprecated Notification.MediaStyle(android.app.Notification.Builder);
+    ctor @Deprecated public Notification.MediaStyle(android.app.Notification.Builder);
     method public android.app.Notification.MediaStyle setMediaSession(android.media.session.MediaSession.Token);
     method public android.app.Notification.MediaStyle setShowActionsInCompactView(int...);
   }
 
   public static class Notification.MessagingStyle extends android.app.Notification.Style {
-    ctor public deprecated Notification.MessagingStyle(java.lang.CharSequence);
-    ctor public Notification.MessagingStyle(android.app.Person);
+    ctor @Deprecated public Notification.MessagingStyle(@NonNull CharSequence);
+    ctor public Notification.MessagingStyle(@NonNull android.app.Person);
     method public android.app.Notification.MessagingStyle addHistoricMessage(android.app.Notification.MessagingStyle.Message);
-    method public deprecated android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence);
-    method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, android.app.Person);
+    method @Deprecated public android.app.Notification.MessagingStyle addMessage(CharSequence, long, CharSequence);
+    method public android.app.Notification.MessagingStyle addMessage(@NonNull CharSequence, long, @Nullable android.app.Person);
     method public android.app.Notification.MessagingStyle addMessage(android.app.Notification.MessagingStyle.Message);
-    method public java.lang.CharSequence getConversationTitle();
+    method @Nullable public CharSequence getConversationTitle();
     method public java.util.List<android.app.Notification.MessagingStyle.Message> getHistoricMessages();
     method public java.util.List<android.app.Notification.MessagingStyle.Message> getMessages();
-    method public android.app.Person getUser();
-    method public deprecated java.lang.CharSequence getUserDisplayName();
+    method @NonNull public android.app.Person getUser();
+    method @Deprecated public CharSequence getUserDisplayName();
     method public boolean isGroupConversation();
-    method public android.app.Notification.MessagingStyle setConversationTitle(java.lang.CharSequence);
+    method public android.app.Notification.MessagingStyle setConversationTitle(@Nullable CharSequence);
     method public android.app.Notification.MessagingStyle setGroupConversation(boolean);
     field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
   }
 
   public static final class Notification.MessagingStyle.Message {
-    ctor public deprecated Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence);
-    ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, android.app.Person);
-    method public java.lang.String getDataMimeType();
+    ctor @Deprecated public Notification.MessagingStyle.Message(CharSequence, long, CharSequence);
+    ctor public Notification.MessagingStyle.Message(@NonNull CharSequence, long, @Nullable android.app.Person);
+    method public String getDataMimeType();
     method public android.net.Uri getDataUri();
     method public android.os.Bundle getExtras();
-    method public deprecated java.lang.CharSequence getSender();
-    method public android.app.Person getSenderPerson();
-    method public java.lang.CharSequence getText();
+    method @Deprecated public CharSequence getSender();
+    method @Nullable public android.app.Person getSenderPerson();
+    method public CharSequence getText();
     method public long getTimestamp();
-    method public android.app.Notification.MessagingStyle.Message setData(java.lang.String, android.net.Uri);
+    method public android.app.Notification.MessagingStyle.Message setData(String, android.net.Uri);
   }
 
-  public static abstract class Notification.Style {
+  public abstract static class Notification.Style {
     ctor public Notification.Style();
     method public android.app.Notification build();
     method protected void checkBuilder();
     method protected android.widget.RemoteViews getStandardView(int);
-    method protected void internalSetBigContentTitle(java.lang.CharSequence);
-    method protected void internalSetSummaryText(java.lang.CharSequence);
+    method protected void internalSetBigContentTitle(CharSequence);
+    method protected void internalSetSummaryText(CharSequence);
     method public void setBuilder(android.app.Notification.Builder);
     field protected android.app.Notification.Builder mBuilder;
   }
@@ -5637,88 +5662,88 @@
     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 deprecated android.app.Notification.WearableExtender addPage(android.app.Notification);
-    method public deprecated android.app.Notification.WearableExtender addPages(java.util.List<android.app.Notification>);
+    method @Deprecated public android.app.Notification.WearableExtender addPage(android.app.Notification);
+    method @Deprecated public android.app.Notification.WearableExtender addPages(java.util.List<android.app.Notification>);
     method public android.app.Notification.WearableExtender clearActions();
-    method public deprecated android.app.Notification.WearableExtender clearPages();
+    method @Deprecated public 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 deprecated android.graphics.Bitmap getBackground();
-    method public java.lang.String getBridgeTag();
+    method @Deprecated public android.graphics.Bitmap getBackground();
+    method public String getBridgeTag();
     method public int getContentAction();
-    method public deprecated int getContentIcon();
-    method public deprecated int getContentIconGravity();
+    method @Deprecated public int getContentIcon();
+    method @Deprecated public int getContentIconGravity();
     method public boolean getContentIntentAvailableOffline();
-    method public deprecated int getCustomContentHeight();
-    method public deprecated int getCustomSizePreset();
-    method public java.lang.String getDismissalId();
-    method public deprecated android.app.PendingIntent getDisplayIntent();
-    method public deprecated int getGravity();
-    method public deprecated boolean getHintAmbientBigPicture();
-    method public deprecated boolean getHintAvoidBackgroundClipping();
+    method @Deprecated public int getCustomContentHeight();
+    method @Deprecated public int getCustomSizePreset();
+    method public String getDismissalId();
+    method @Deprecated public android.app.PendingIntent getDisplayIntent();
+    method @Deprecated public int getGravity();
+    method @Deprecated public boolean getHintAmbientBigPicture();
+    method @Deprecated public boolean getHintAvoidBackgroundClipping();
     method public boolean getHintContentIntentLaunchesActivity();
-    method public deprecated boolean getHintHideIcon();
-    method public deprecated int getHintScreenTimeout();
-    method public deprecated boolean getHintShowBackgroundOnly();
-    method public deprecated java.util.List<android.app.Notification> getPages();
+    method @Deprecated public boolean getHintHideIcon();
+    method @Deprecated public int getHintScreenTimeout();
+    method @Deprecated public boolean getHintShowBackgroundOnly();
+    method @Deprecated public java.util.List<android.app.Notification> getPages();
     method public boolean getStartScrollBottom();
-    method public deprecated android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
-    method public android.app.Notification.WearableExtender setBridgeTag(java.lang.String);
+    method @Deprecated public android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
+    method public android.app.Notification.WearableExtender setBridgeTag(String);
     method public android.app.Notification.WearableExtender setContentAction(int);
-    method public deprecated android.app.Notification.WearableExtender setContentIcon(int);
-    method public deprecated android.app.Notification.WearableExtender setContentIconGravity(int);
+    method @Deprecated public android.app.Notification.WearableExtender setContentIcon(int);
+    method @Deprecated public android.app.Notification.WearableExtender setContentIconGravity(int);
     method public android.app.Notification.WearableExtender setContentIntentAvailableOffline(boolean);
-    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 deprecated android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
-    method public deprecated android.app.Notification.WearableExtender setGravity(int);
-    method public deprecated android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean);
-    method public deprecated android.app.Notification.WearableExtender setHintAvoidBackgroundClipping(boolean);
+    method @Deprecated public android.app.Notification.WearableExtender setCustomContentHeight(int);
+    method @Deprecated public android.app.Notification.WearableExtender setCustomSizePreset(int);
+    method public android.app.Notification.WearableExtender setDismissalId(String);
+    method @Deprecated public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
+    method @Deprecated public android.app.Notification.WearableExtender setGravity(int);
+    method @Deprecated public android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean);
+    method @Deprecated public 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 @Deprecated public android.app.Notification.WearableExtender setHintHideIcon(boolean);
+    method @Deprecated public android.app.Notification.WearableExtender setHintScreenTimeout(int);
+    method @Deprecated public android.app.Notification.WearableExtender setHintShowBackgroundOnly(boolean);
     method public android.app.Notification.WearableExtender setStartScrollBottom(boolean);
-    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 @Deprecated public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+    field @Deprecated public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+    field @Deprecated public static final int SIZE_DEFAULT = 0; // 0x0
+    field @Deprecated public static final int SIZE_FULL_SCREEN = 5; // 0x5
+    field @Deprecated public static final int SIZE_LARGE = 4; // 0x4
+    field @Deprecated public static final int SIZE_MEDIUM = 3; // 0x3
+    field @Deprecated public static final int SIZE_SMALL = 2; // 0x2
+    field @Deprecated public static final int SIZE_XSMALL = 1; // 0x1
     field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
   }
 
   public final class NotificationChannel implements android.os.Parcelable {
-    ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
+    ctor public NotificationChannel(String, CharSequence, int);
+    method public boolean canBubble();
     method public boolean canBypassDnd();
-    method public boolean canOverlayApps();
     method public boolean canShowBadge();
     method public int describeContents();
     method public void enableLights(boolean);
     method public void enableVibration(boolean);
     method public android.media.AudioAttributes getAudioAttributes();
-    method public java.lang.String getDescription();
-    method public java.lang.String getGroup();
-    method public java.lang.String getId();
+    method public String getDescription();
+    method public String getGroup();
+    method public String getId();
     method public int getImportance();
     method public int getLightColor();
     method public int getLockscreenVisibility();
-    method public java.lang.CharSequence getName();
+    method public CharSequence getName();
     method public android.net.Uri getSound();
     method public long[] getVibrationPattern();
     method public boolean hasUserSetImportance();
-    method public void setAllowAppOverlay(boolean);
+    method public void setAllowBubbles(boolean);
     method public void setBypassDnd(boolean);
-    method public void setDescription(java.lang.String);
-    method public void setGroup(java.lang.String);
+    method public void setDescription(String);
+    method public void setGroup(String);
     method public void setImportance(int);
     method public void setLightColor(int);
     method public void setLockscreenVisibility(int);
-    method public void setName(java.lang.CharSequence);
+    method public void setName(CharSequence);
     method public void setShowBadge(boolean);
     method public void setSound(android.net.Uri, android.media.AudioAttributes);
     method public void setVibrationPattern(long[]);
@@ -5726,71 +5751,71 @@
     method public boolean shouldVibrate();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.NotificationChannel> CREATOR;
-    field public static final java.lang.String DEFAULT_CHANNEL_ID = "miscellaneous";
+    field public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
   }
 
   public final class NotificationChannelGroup implements android.os.Parcelable {
-    ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence);
+    ctor public NotificationChannelGroup(String, CharSequence);
     method public android.app.NotificationChannelGroup clone();
     method public int describeContents();
     method public java.util.List<android.app.NotificationChannel> getChannels();
-    method public java.lang.String getDescription();
-    method public java.lang.String getId();
-    method public java.lang.CharSequence getName();
+    method public String getDescription();
+    method public String getId();
+    method public CharSequence getName();
     method public boolean isBlocked();
-    method public void setDescription(java.lang.String);
+    method public void setDescription(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
   }
 
   public class NotificationManager {
-    method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
-    method public boolean areAppOverlaysAllowed();
+    method public String addAutomaticZenRule(android.app.AutomaticZenRule);
+    method public boolean areBubblesAllowed();
     method public boolean areNotificationsEnabled();
-    method public boolean canNotifyAsPackage(java.lang.String);
+    method public boolean canNotifyAsPackage(String);
     method public void cancel(int);
-    method public void cancel(java.lang.String, int);
+    method public void cancel(String, int);
     method public void cancelAll();
-    method public void createNotificationChannel(android.app.NotificationChannel);
-    method public void createNotificationChannelGroup(android.app.NotificationChannelGroup);
-    method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup>);
-    method public void createNotificationChannels(java.util.List<android.app.NotificationChannel>);
-    method public void deleteNotificationChannel(java.lang.String);
-    method public void deleteNotificationChannelGroup(java.lang.String);
+    method public void createNotificationChannel(@NonNull android.app.NotificationChannel);
+    method public void createNotificationChannelGroup(@NonNull android.app.NotificationChannelGroup);
+    method public void createNotificationChannelGroups(@NonNull java.util.List<android.app.NotificationChannelGroup>);
+    method public void createNotificationChannels(@NonNull java.util.List<android.app.NotificationChannel>);
+    method public void deleteNotificationChannel(String);
+    method public void deleteNotificationChannelGroup(String);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
-    method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
-    method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
+    method public android.app.AutomaticZenRule getAutomaticZenRule(String);
+    method public java.util.Map<java.lang.String,android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public int getImportance();
-    method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
-    method public android.app.NotificationChannelGroup getNotificationChannelGroup(java.lang.String);
+    method public android.app.NotificationChannel getNotificationChannel(String);
+    method public android.app.NotificationChannelGroup getNotificationChannelGroup(String);
     method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups();
     method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
-    method public java.lang.String getNotificationDelegate();
+    method @Nullable public String getNotificationDelegate();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
     method public boolean isNotificationListenerAccessGranted(android.content.ComponentName);
     method public boolean isNotificationPolicyAccessGranted();
     method public void notify(int, android.app.Notification);
-    method public void notify(java.lang.String, int, android.app.Notification);
-    method public void notifyAsPackage(java.lang.String, java.lang.String, int, android.app.Notification);
-    method public boolean removeAutomaticZenRule(java.lang.String);
+    method public void notify(String, int, android.app.Notification);
+    method public void notifyAsPackage(@NonNull String, @NonNull String, int, android.app.Notification);
+    method public boolean removeAutomaticZenRule(String);
     method public void revokeNotificationDelegate();
-    method public void setAutomaticZenRuleState(java.lang.String, android.service.notification.Condition);
+    method public void setAutomaticZenRuleState(String, android.service.notification.Condition);
     method public final void setInterruptionFilter(int);
-    method public void setNotificationDelegate(java.lang.String);
-    method public void setNotificationPolicy(android.app.NotificationManager.Policy);
-    method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
-    field public static final java.lang.String ACTION_APP_BLOCK_STATE_CHANGED = "android.app.action.APP_BLOCK_STATE_CHANGED";
-    field public static final java.lang.String ACTION_AUTOMATIC_ZEN_RULE = "android.app.action.AUTOMATIC_ZEN_RULE";
-    field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
-    field public static final java.lang.String ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED";
-    field public static final java.lang.String ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED";
-    field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
-    field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
-    field public static final java.lang.String EXTRA_AUTOMATIC_RULE_ID = "android.app.extra.AUTOMATIC_RULE_ID";
-    field public static final java.lang.String EXTRA_BLOCKED_STATE = "android.app.extra.BLOCKED_STATE";
-    field public static final java.lang.String EXTRA_NOTIFICATION_CHANNEL_GROUP_ID = "android.app.extra.NOTIFICATION_CHANNEL_GROUP_ID";
-    field public static final java.lang.String EXTRA_NOTIFICATION_CHANNEL_ID = "android.app.extra.NOTIFICATION_CHANNEL_ID";
+    method public void setNotificationDelegate(@NonNull String);
+    method public void setNotificationPolicy(@NonNull android.app.NotificationManager.Policy);
+    method public boolean updateAutomaticZenRule(String, android.app.AutomaticZenRule);
+    field public static final String ACTION_APP_BLOCK_STATE_CHANGED = "android.app.action.APP_BLOCK_STATE_CHANGED";
+    field public static final String ACTION_AUTOMATIC_ZEN_RULE = "android.app.action.AUTOMATIC_ZEN_RULE";
+    field public static final String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
+    field public static final String ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED";
+    field public static final String ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED";
+    field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
+    field public static final String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
+    field public static final String EXTRA_AUTOMATIC_RULE_ID = "android.app.extra.AUTOMATIC_RULE_ID";
+    field public static final String EXTRA_BLOCKED_STATE = "android.app.extra.BLOCKED_STATE";
+    field public static final String EXTRA_NOTIFICATION_CHANNEL_GROUP_ID = "android.app.extra.NOTIFICATION_CHANNEL_GROUP_ID";
+    field public static final String EXTRA_NOTIFICATION_CHANNEL_ID = "android.app.extra.NOTIFICATION_CHANNEL_ID";
     field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
     field public static final int IMPORTANCE_HIGH = 4; // 0x4
     field public static final int IMPORTANCE_LOW = 2; // 0x2
@@ -5803,17 +5828,17 @@
     field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
     field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
-    field public static final java.lang.String META_DATA_AUTOMATIC_RULE_TYPE = "android.app.automatic.ruleType";
-    field public static final java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.app.zen.automatic.ruleInstanceLimit";
+    field public static final String META_DATA_AUTOMATIC_RULE_TYPE = "android.app.automatic.ruleType";
+    field public static final String META_DATA_RULE_INSTANCE_LIMIT = "android.app.zen.automatic.ruleInstanceLimit";
   }
 
   public static class NotificationManager.Policy implements android.os.Parcelable {
     ctor public NotificationManager.Policy(int, int, int);
     ctor public NotificationManager.Policy(int, int, int, int);
     method public int describeContents();
-    method public static java.lang.String priorityCategoriesToString(int);
-    method public static java.lang.String prioritySendersToString(int);
-    method public static java.lang.String suppressedEffectsToString(int);
+    method public static String priorityCategoriesToString(int);
+    method public static String prioritySendersToString(int);
+    method public static String suppressedEffectsToString(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy> CREATOR;
     field public static final int PRIORITY_CATEGORY_ALARMS = 32; // 0x20
@@ -5833,8 +5858,8 @@
     field public static final int SUPPRESSED_EFFECT_LIGHTS = 8; // 0x8
     field public static final int SUPPRESSED_EFFECT_NOTIFICATION_LIST = 256; // 0x100
     field public static final int SUPPRESSED_EFFECT_PEEK = 16; // 0x10
-    field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
-    field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
+    field @Deprecated public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
+    field @Deprecated public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
     field public static final int SUPPRESSED_EFFECT_STATUS_BAR = 32; // 0x20
     field public final int priorityCallSenders;
     field public final int priorityCategories;
@@ -5845,27 +5870,27 @@
   public final class PendingIntent implements android.os.Parcelable {
     method public void cancel();
     method public int describeContents();
-    method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent[], int);
-    method public static android.app.PendingIntent getActivities(android.content.Context, int, android.content.Intent[], int, android.os.Bundle);
+    method public static android.app.PendingIntent getActivities(android.content.Context, int, @NonNull android.content.Intent[], int);
+    method public static android.app.PendingIntent getActivities(android.content.Context, int, @NonNull android.content.Intent[], int, @Nullable android.os.Bundle);
     method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int);
-    method public static android.app.PendingIntent getActivity(android.content.Context, int, android.content.Intent, int, android.os.Bundle);
+    method public static android.app.PendingIntent getActivity(android.content.Context, int, @NonNull android.content.Intent, int, @Nullable android.os.Bundle);
     method public static android.app.PendingIntent getBroadcast(android.content.Context, int, android.content.Intent, int);
-    method public java.lang.String getCreatorPackage();
+    method @Nullable public String getCreatorPackage();
     method public int getCreatorUid();
-    method public android.os.UserHandle getCreatorUserHandle();
-    method public static android.app.PendingIntent getForegroundService(android.content.Context, int, android.content.Intent, int);
+    method @Nullable public android.os.UserHandle getCreatorUserHandle();
+    method public static android.app.PendingIntent getForegroundService(android.content.Context, int, @NonNull android.content.Intent, int);
     method public android.content.IntentSender getIntentSender();
-    method public static android.app.PendingIntent getService(android.content.Context, int, android.content.Intent, int);
-    method public deprecated java.lang.String getTargetPackage();
-    method public static android.app.PendingIntent readPendingIntentOrNullFromParcel(android.os.Parcel);
+    method public static android.app.PendingIntent getService(android.content.Context, int, @NonNull android.content.Intent, int);
+    method @Deprecated public String getTargetPackage();
+    method @Nullable public static android.app.PendingIntent readPendingIntentOrNullFromParcel(@NonNull android.os.Parcel);
     method public void send() throws android.app.PendingIntent.CanceledException;
     method public void send(int) throws android.app.PendingIntent.CanceledException;
-    method public void send(android.content.Context, int, android.content.Intent) throws android.app.PendingIntent.CanceledException;
-    method public void send(int, android.app.PendingIntent.OnFinished, android.os.Handler) throws android.app.PendingIntent.CanceledException;
-    method public void send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler) throws android.app.PendingIntent.CanceledException;
-    method public void send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler, java.lang.String) throws android.app.PendingIntent.CanceledException;
-    method public void send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler, java.lang.String, android.os.Bundle) throws android.app.PendingIntent.CanceledException;
-    method public static void writePendingIntentOrNullToParcel(android.app.PendingIntent, android.os.Parcel);
+    method public void send(android.content.Context, int, @Nullable android.content.Intent) throws android.app.PendingIntent.CanceledException;
+    method public void send(int, @Nullable android.app.PendingIntent.OnFinished, @Nullable android.os.Handler) throws android.app.PendingIntent.CanceledException;
+    method public void send(android.content.Context, int, @Nullable android.content.Intent, @Nullable android.app.PendingIntent.OnFinished, @Nullable android.os.Handler) throws android.app.PendingIntent.CanceledException;
+    method public void send(android.content.Context, int, @Nullable android.content.Intent, @Nullable android.app.PendingIntent.OnFinished, @Nullable android.os.Handler, @Nullable String) throws android.app.PendingIntent.CanceledException;
+    method public void send(android.content.Context, int, @Nullable android.content.Intent, @Nullable android.app.PendingIntent.OnFinished, @Nullable android.os.Handler, @Nullable String, @Nullable android.os.Bundle) throws android.app.PendingIntent.CanceledException;
+    method public static void writePendingIntentOrNullToParcel(@Nullable android.app.PendingIntent, @NonNull android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.PendingIntent> CREATOR;
     field public static final int FLAG_CANCEL_CURRENT = 268435456; // 0x10000000
@@ -5877,20 +5902,20 @@
 
   public static class PendingIntent.CanceledException extends android.util.AndroidException {
     ctor public PendingIntent.CanceledException();
-    ctor public PendingIntent.CanceledException(java.lang.String);
-    ctor public PendingIntent.CanceledException(java.lang.Exception);
+    ctor public PendingIntent.CanceledException(String);
+    ctor public PendingIntent.CanceledException(Exception);
   }
 
-  public static abstract interface PendingIntent.OnFinished {
-    method public abstract void onSendFinished(android.app.PendingIntent, android.content.Intent, int, java.lang.String, android.os.Bundle);
+  public static interface PendingIntent.OnFinished {
+    method public void onSendFinished(android.app.PendingIntent, android.content.Intent, int, String, android.os.Bundle);
   }
 
   public final class Person implements android.os.Parcelable {
     method public int describeContents();
-    method public android.graphics.drawable.Icon getIcon();
-    method public java.lang.String getKey();
-    method public java.lang.CharSequence getName();
-    method public java.lang.String getUri();
+    method @Nullable public android.graphics.drawable.Icon getIcon();
+    method @Nullable public String getKey();
+    method @Nullable public CharSequence getName();
+    method @Nullable public String getUri();
     method public boolean isBot();
     method public boolean isImportant();
     method public android.app.Person.Builder toBuilder();
@@ -5900,13 +5925,13 @@
 
   public static class Person.Builder {
     ctor public Person.Builder();
-    method public android.app.Person build();
-    method public android.app.Person.Builder setBot(boolean);
-    method public android.app.Person.Builder setIcon(android.graphics.drawable.Icon);
-    method public android.app.Person.Builder setImportant(boolean);
-    method public android.app.Person.Builder setKey(java.lang.String);
-    method public android.app.Person.Builder setName(java.lang.CharSequence);
-    method public android.app.Person.Builder setUri(java.lang.String);
+    method @NonNull public android.app.Person build();
+    method @NonNull public android.app.Person.Builder setBot(boolean);
+    method @NonNull public android.app.Person.Builder setIcon(@Nullable android.graphics.drawable.Icon);
+    method @NonNull public android.app.Person.Builder setImportant(boolean);
+    method @NonNull public android.app.Person.Builder setKey(@Nullable String);
+    method @NonNull public android.app.Person.Builder setName(@Nullable CharSequence);
+    method @NonNull public android.app.Person.Builder setUri(@Nullable String);
   }
 
   public final class PictureInPictureParams implements android.os.Parcelable {
@@ -5932,51 +5957,51 @@
     method public void onDisplayRemoved();
   }
 
-  public deprecated class ProgressDialog extends android.app.AlertDialog {
-    ctor public ProgressDialog(android.content.Context);
-    ctor public ProgressDialog(android.content.Context, int);
-    method public int getMax();
-    method public int getProgress();
-    method public int getSecondaryProgress();
-    method public void incrementProgressBy(int);
-    method public void incrementSecondaryProgressBy(int);
-    method public boolean isIndeterminate();
-    method public void onStart();
-    method public void setIndeterminate(boolean);
-    method public void setIndeterminateDrawable(android.graphics.drawable.Drawable);
-    method public void setMax(int);
-    method public void setProgress(int);
-    method public void setProgressDrawable(android.graphics.drawable.Drawable);
-    method public void setProgressNumberFormat(java.lang.String);
-    method public void setProgressPercentFormat(java.text.NumberFormat);
-    method public void setProgressStyle(int);
-    method public void setSecondaryProgress(int);
-    method public static android.app.ProgressDialog show(android.content.Context, java.lang.CharSequence, java.lang.CharSequence);
-    method public static android.app.ProgressDialog show(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, boolean);
-    method public static android.app.ProgressDialog show(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, boolean, boolean);
-    method public static android.app.ProgressDialog show(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, boolean, boolean, android.content.DialogInterface.OnCancelListener);
-    field public static final int STYLE_HORIZONTAL = 1; // 0x1
-    field public static final int STYLE_SPINNER = 0; // 0x0
+  @Deprecated public class ProgressDialog extends android.app.AlertDialog {
+    ctor @Deprecated public ProgressDialog(android.content.Context);
+    ctor @Deprecated public ProgressDialog(android.content.Context, int);
+    method @Deprecated public int getMax();
+    method @Deprecated public int getProgress();
+    method @Deprecated public int getSecondaryProgress();
+    method @Deprecated public void incrementProgressBy(int);
+    method @Deprecated public void incrementSecondaryProgressBy(int);
+    method @Deprecated public boolean isIndeterminate();
+    method @Deprecated public void onStart();
+    method @Deprecated public void setIndeterminate(boolean);
+    method @Deprecated public void setIndeterminateDrawable(android.graphics.drawable.Drawable);
+    method @Deprecated public void setMax(int);
+    method @Deprecated public void setProgress(int);
+    method @Deprecated public void setProgressDrawable(android.graphics.drawable.Drawable);
+    method @Deprecated public void setProgressNumberFormat(String);
+    method @Deprecated public void setProgressPercentFormat(java.text.NumberFormat);
+    method @Deprecated public void setProgressStyle(int);
+    method @Deprecated public void setSecondaryProgress(int);
+    method @Deprecated public static android.app.ProgressDialog show(android.content.Context, CharSequence, CharSequence);
+    method @Deprecated public static android.app.ProgressDialog show(android.content.Context, CharSequence, CharSequence, boolean);
+    method @Deprecated public static android.app.ProgressDialog show(android.content.Context, CharSequence, CharSequence, boolean, boolean);
+    method @Deprecated public static android.app.ProgressDialog show(android.content.Context, CharSequence, CharSequence, boolean, boolean, android.content.DialogInterface.OnCancelListener);
+    field @Deprecated public static final int STYLE_HORIZONTAL = 1; // 0x1
+    field @Deprecated public static final int STYLE_SPINNER = 0; // 0x0
   }
 
   public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
-    ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, android.app.RemoteAction);
+    ctor public RecoverableSecurityException(@NonNull Throwable, @NonNull CharSequence, @NonNull android.app.RemoteAction);
     method public int describeContents();
-    method public android.app.RemoteAction getUserAction();
-    method public java.lang.CharSequence getUserMessage();
+    method @NonNull public android.app.RemoteAction getUserAction();
+    method @NonNull public CharSequence getUserMessage();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR;
   }
 
   public final class RemoteAction implements android.os.Parcelable {
-    ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
+    ctor public RemoteAction(@NonNull android.graphics.drawable.Icon, @NonNull CharSequence, @NonNull CharSequence, @NonNull android.app.PendingIntent);
     method public android.app.RemoteAction clone();
     method public int describeContents();
-    method public void dump(java.lang.String, java.io.PrintWriter);
-    method public android.app.PendingIntent getActionIntent();
-    method public java.lang.CharSequence getContentDescription();
-    method public android.graphics.drawable.Icon getIcon();
-    method public java.lang.CharSequence getTitle();
+    method public void dump(String, java.io.PrintWriter);
+    method @NonNull public android.app.PendingIntent getActionIntent();
+    method @NonNull public CharSequence getContentDescription();
+    method @NonNull public android.graphics.drawable.Icon getIcon();
+    method @NonNull public CharSequence getTitle();
     method public boolean isEnabled();
     method public void setEnabled(boolean);
     method public void setShouldShowIcon(boolean);
@@ -5986,17 +6011,17 @@
   }
 
   public final class RemoteInput implements android.os.Parcelable {
-    method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
+    method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String,android.net.Uri>);
     method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
     method public int describeContents();
     method public boolean getAllowFreeFormInput();
     method public java.util.Set<java.lang.String> getAllowedDataTypes();
-    method public java.lang.CharSequence[] getChoices();
-    method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
+    method public CharSequence[] getChoices();
+    method public static java.util.Map<java.lang.String,android.net.Uri> getDataResultsFromIntent(android.content.Intent, String);
     method public int getEditChoicesBeforeSending();
     method public android.os.Bundle getExtras();
-    method public java.lang.CharSequence getLabel();
-    method public java.lang.String getResultKey();
+    method public CharSequence getLabel();
+    method public String getResultKey();
     method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
     method public static int getResultsSource(android.content.Intent);
     method public boolean isDataOnly();
@@ -6006,95 +6031,95 @@
     field public static final int EDIT_CHOICES_BEFORE_SENDING_AUTO = 0; // 0x0
     field public static final int EDIT_CHOICES_BEFORE_SENDING_DISABLED = 1; // 0x1
     field public static final int EDIT_CHOICES_BEFORE_SENDING_ENABLED = 2; // 0x2
-    field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
-    field public static final java.lang.String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+    field public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+    field public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
     field public static final int SOURCE_CHOICE = 1; // 0x1
     field public static final int SOURCE_FREE_FORM_INPUT = 0; // 0x0
   }
 
   public static final class RemoteInput.Builder {
-    ctor public RemoteInput.Builder(java.lang.String);
-    method public android.app.RemoteInput.Builder addExtras(android.os.Bundle);
-    method public android.app.RemoteInput build();
-    method public android.os.Bundle getExtras();
-    method public android.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
-    method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
-    method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
-    method public android.app.RemoteInput.Builder setEditChoicesBeforeSending(int);
-    method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
+    ctor public RemoteInput.Builder(@NonNull String);
+    method @NonNull public android.app.RemoteInput.Builder addExtras(@NonNull android.os.Bundle);
+    method @NonNull public android.app.RemoteInput build();
+    method @NonNull public android.os.Bundle getExtras();
+    method @NonNull public android.app.RemoteInput.Builder setAllowDataType(@NonNull String, boolean);
+    method @NonNull public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+    method @NonNull public android.app.RemoteInput.Builder setChoices(@Nullable CharSequence[]);
+    method @NonNull public android.app.RemoteInput.Builder setEditChoicesBeforeSending(int);
+    method @NonNull public android.app.RemoteInput.Builder setLabel(@Nullable CharSequence);
   }
 
   public class SearchManager implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
     method public android.content.ComponentName getGlobalSearchActivity();
     method public android.app.SearchableInfo getSearchableInfo(android.content.ComponentName);
     method public java.util.List<android.app.SearchableInfo> getSearchablesInGlobalSearch();
-    method public deprecated void onCancel(android.content.DialogInterface);
-    method public deprecated void onDismiss(android.content.DialogInterface);
+    method @Deprecated public void onCancel(android.content.DialogInterface);
+    method @Deprecated public void onDismiss(android.content.DialogInterface);
     method public void setOnCancelListener(android.app.SearchManager.OnCancelListener);
     method public void setOnDismissListener(android.app.SearchManager.OnDismissListener);
-    method public void startSearch(java.lang.String, boolean, android.content.ComponentName, android.os.Bundle, boolean);
+    method public void startSearch(String, boolean, android.content.ComponentName, android.os.Bundle, boolean);
     method public void stopSearch();
-    method public void triggerSearch(java.lang.String, android.content.ComponentName, android.os.Bundle);
-    field public static final java.lang.String ACTION_KEY = "action_key";
-    field public static final java.lang.String ACTION_MSG = "action_msg";
-    field public static final java.lang.String APP_DATA = "app_data";
-    field public static final java.lang.String CURSOR_EXTRA_KEY_IN_PROGRESS = "in_progress";
-    field public static final java.lang.String EXTRA_DATA_KEY = "intent_extra_data_key";
-    field public static final java.lang.String EXTRA_NEW_SEARCH = "new_search";
-    field public static final java.lang.String EXTRA_SELECT_QUERY = "select_query";
-    field public static final java.lang.String EXTRA_WEB_SEARCH_PENDINGINTENT = "web_search_pendingintent";
+    method public void triggerSearch(String, android.content.ComponentName, android.os.Bundle);
+    field public static final String ACTION_KEY = "action_key";
+    field public static final String ACTION_MSG = "action_msg";
+    field public static final String APP_DATA = "app_data";
+    field public static final String CURSOR_EXTRA_KEY_IN_PROGRESS = "in_progress";
+    field public static final String EXTRA_DATA_KEY = "intent_extra_data_key";
+    field public static final String EXTRA_NEW_SEARCH = "new_search";
+    field public static final String EXTRA_SELECT_QUERY = "select_query";
+    field public static final String EXTRA_WEB_SEARCH_PENDINGINTENT = "web_search_pendingintent";
     field public static final int FLAG_QUERY_REFINEMENT = 1; // 0x1
-    field public static final java.lang.String INTENT_ACTION_GLOBAL_SEARCH = "android.search.action.GLOBAL_SEARCH";
-    field public static final java.lang.String INTENT_ACTION_SEARCHABLES_CHANGED = "android.search.action.SEARCHABLES_CHANGED";
-    field public static final java.lang.String INTENT_ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
-    field public static final java.lang.String INTENT_ACTION_SEARCH_SETTINGS_CHANGED = "android.search.action.SETTINGS_CHANGED";
-    field public static final java.lang.String INTENT_ACTION_WEB_SEARCH_SETTINGS = "android.search.action.WEB_SEARCH_SETTINGS";
-    field public static final java.lang.String INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED = "android.search.action.GLOBAL_SEARCH_ACTIVITY_CHANGED";
+    field public static final String INTENT_ACTION_GLOBAL_SEARCH = "android.search.action.GLOBAL_SEARCH";
+    field public static final String INTENT_ACTION_SEARCHABLES_CHANGED = "android.search.action.SEARCHABLES_CHANGED";
+    field public static final String INTENT_ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
+    field public static final String INTENT_ACTION_SEARCH_SETTINGS_CHANGED = "android.search.action.SETTINGS_CHANGED";
+    field public static final String INTENT_ACTION_WEB_SEARCH_SETTINGS = "android.search.action.WEB_SEARCH_SETTINGS";
+    field public static final String INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED = "android.search.action.GLOBAL_SEARCH_ACTIVITY_CHANGED";
     field public static final char MENU_KEY = 115; // 0x0073 's'
     field public static final int MENU_KEYCODE = 47; // 0x2f
-    field public static final java.lang.String QUERY = "query";
-    field public static final java.lang.String SHORTCUT_MIME_TYPE = "vnd.android.cursor.item/vnd.android.search.suggest";
-    field public static final java.lang.String SUGGEST_COLUMN_AUDIO_CHANNEL_CONFIG = "suggest_audio_channel_config";
-    field public static final java.lang.String SUGGEST_COLUMN_CONTENT_TYPE = "suggest_content_type";
-    field public static final java.lang.String SUGGEST_COLUMN_DURATION = "suggest_duration";
-    field public static final java.lang.String SUGGEST_COLUMN_FLAGS = "suggest_flags";
-    field public static final java.lang.String SUGGEST_COLUMN_FORMAT = "suggest_format";
-    field public static final java.lang.String SUGGEST_COLUMN_ICON_1 = "suggest_icon_1";
-    field public static final java.lang.String SUGGEST_COLUMN_ICON_2 = "suggest_icon_2";
-    field public static final java.lang.String SUGGEST_COLUMN_INTENT_ACTION = "suggest_intent_action";
-    field public static final java.lang.String SUGGEST_COLUMN_INTENT_DATA = "suggest_intent_data";
-    field public static final java.lang.String SUGGEST_COLUMN_INTENT_DATA_ID = "suggest_intent_data_id";
-    field public static final java.lang.String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
-    field public static final java.lang.String SUGGEST_COLUMN_IS_LIVE = "suggest_is_live";
-    field public static final java.lang.String SUGGEST_COLUMN_LAST_ACCESS_HINT = "suggest_last_access_hint";
-    field public static final java.lang.String SUGGEST_COLUMN_PRODUCTION_YEAR = "suggest_production_year";
-    field public static final java.lang.String SUGGEST_COLUMN_PURCHASE_PRICE = "suggest_purchase_price";
-    field public static final java.lang.String SUGGEST_COLUMN_QUERY = "suggest_intent_query";
-    field public static final java.lang.String SUGGEST_COLUMN_RATING_SCORE = "suggest_rating_score";
-    field public static final java.lang.String SUGGEST_COLUMN_RATING_STYLE = "suggest_rating_style";
-    field public static final java.lang.String SUGGEST_COLUMN_RENTAL_PRICE = "suggest_rental_price";
-    field public static final java.lang.String SUGGEST_COLUMN_RESULT_CARD_IMAGE = "suggest_result_card_image";
-    field public static final java.lang.String SUGGEST_COLUMN_SHORTCUT_ID = "suggest_shortcut_id";
-    field public static final java.lang.String SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING = "suggest_spinner_while_refreshing";
-    field public static final java.lang.String SUGGEST_COLUMN_TEXT_1 = "suggest_text_1";
-    field public static final java.lang.String SUGGEST_COLUMN_TEXT_2 = "suggest_text_2";
-    field public static final java.lang.String SUGGEST_COLUMN_TEXT_2_URL = "suggest_text_2_url";
-    field public static final java.lang.String SUGGEST_COLUMN_VIDEO_HEIGHT = "suggest_video_height";
-    field public static final java.lang.String SUGGEST_COLUMN_VIDEO_WIDTH = "suggest_video_width";
-    field public static final java.lang.String SUGGEST_MIME_TYPE = "vnd.android.cursor.dir/vnd.android.search.suggest";
-    field public static final java.lang.String SUGGEST_NEVER_MAKE_SHORTCUT = "_-1";
-    field public static final java.lang.String SUGGEST_PARAMETER_LIMIT = "limit";
-    field public static final java.lang.String SUGGEST_URI_PATH_QUERY = "search_suggest_query";
-    field public static final java.lang.String SUGGEST_URI_PATH_SHORTCUT = "search_suggest_shortcut";
-    field public static final java.lang.String USER_QUERY = "user_query";
+    field public static final String QUERY = "query";
+    field public static final String SHORTCUT_MIME_TYPE = "vnd.android.cursor.item/vnd.android.search.suggest";
+    field public static final String SUGGEST_COLUMN_AUDIO_CHANNEL_CONFIG = "suggest_audio_channel_config";
+    field public static final String SUGGEST_COLUMN_CONTENT_TYPE = "suggest_content_type";
+    field public static final String SUGGEST_COLUMN_DURATION = "suggest_duration";
+    field public static final String SUGGEST_COLUMN_FLAGS = "suggest_flags";
+    field public static final String SUGGEST_COLUMN_FORMAT = "suggest_format";
+    field public static final String SUGGEST_COLUMN_ICON_1 = "suggest_icon_1";
+    field public static final String SUGGEST_COLUMN_ICON_2 = "suggest_icon_2";
+    field public static final String SUGGEST_COLUMN_INTENT_ACTION = "suggest_intent_action";
+    field public static final String SUGGEST_COLUMN_INTENT_DATA = "suggest_intent_data";
+    field public static final String SUGGEST_COLUMN_INTENT_DATA_ID = "suggest_intent_data_id";
+    field public static final String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
+    field public static final String SUGGEST_COLUMN_IS_LIVE = "suggest_is_live";
+    field public static final String SUGGEST_COLUMN_LAST_ACCESS_HINT = "suggest_last_access_hint";
+    field public static final String SUGGEST_COLUMN_PRODUCTION_YEAR = "suggest_production_year";
+    field public static final String SUGGEST_COLUMN_PURCHASE_PRICE = "suggest_purchase_price";
+    field public static final String SUGGEST_COLUMN_QUERY = "suggest_intent_query";
+    field public static final String SUGGEST_COLUMN_RATING_SCORE = "suggest_rating_score";
+    field public static final String SUGGEST_COLUMN_RATING_STYLE = "suggest_rating_style";
+    field public static final String SUGGEST_COLUMN_RENTAL_PRICE = "suggest_rental_price";
+    field public static final String SUGGEST_COLUMN_RESULT_CARD_IMAGE = "suggest_result_card_image";
+    field public static final String SUGGEST_COLUMN_SHORTCUT_ID = "suggest_shortcut_id";
+    field public static final String SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING = "suggest_spinner_while_refreshing";
+    field public static final String SUGGEST_COLUMN_TEXT_1 = "suggest_text_1";
+    field public static final String SUGGEST_COLUMN_TEXT_2 = "suggest_text_2";
+    field public static final String SUGGEST_COLUMN_TEXT_2_URL = "suggest_text_2_url";
+    field public static final String SUGGEST_COLUMN_VIDEO_HEIGHT = "suggest_video_height";
+    field public static final String SUGGEST_COLUMN_VIDEO_WIDTH = "suggest_video_width";
+    field public static final String SUGGEST_MIME_TYPE = "vnd.android.cursor.dir/vnd.android.search.suggest";
+    field public static final String SUGGEST_NEVER_MAKE_SHORTCUT = "_-1";
+    field public static final String SUGGEST_PARAMETER_LIMIT = "limit";
+    field public static final String SUGGEST_URI_PATH_QUERY = "search_suggest_query";
+    field public static final String SUGGEST_URI_PATH_SHORTCUT = "search_suggest_shortcut";
+    field public static final String USER_QUERY = "user_query";
   }
 
-  public static abstract interface SearchManager.OnCancelListener {
-    method public abstract void onCancel();
+  public static interface SearchManager.OnCancelListener {
+    method public void onCancel();
   }
 
-  public static abstract interface SearchManager.OnDismissListener {
-    method public abstract void onDismiss();
+  public static interface SearchManager.OnDismissListener {
+    method public void onDismiss();
   }
 
   public final class SearchableInfo implements android.os.Parcelable {
@@ -6105,17 +6130,17 @@
     method public int getInputType();
     method public android.content.ComponentName getSearchActivity();
     method public int getSettingsDescriptionId();
-    method public java.lang.String getSuggestAuthority();
-    method public java.lang.String getSuggestIntentAction();
-    method public java.lang.String getSuggestIntentData();
-    method public java.lang.String getSuggestPackage();
-    method public java.lang.String getSuggestPath();
-    method public java.lang.String getSuggestSelection();
+    method public String getSuggestAuthority();
+    method public String getSuggestIntentAction();
+    method public String getSuggestIntentData();
+    method public String getSuggestPackage();
+    method public String getSuggestPath();
+    method public String getSuggestSelection();
     method public int getSuggestThreshold();
-    method public int getVoiceLanguageId();
-    method public int getVoiceLanguageModeId();
+    method @StringRes public int getVoiceLanguageId();
+    method @StringRes public int getVoiceLanguageModeId();
     method public int getVoiceMaxResults();
-    method public int getVoicePromptTextId();
+    method @StringRes public int getVoicePromptTextId();
     method public boolean getVoiceSearchEnabled();
     method public boolean getVoiceSearchLaunchRecognizer();
     method public boolean getVoiceSearchLaunchWebSearch();
@@ -6129,15 +6154,15 @@
 
   public abstract class Service extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
     ctor public Service();
-    method protected void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method protected void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
     method public final android.app.Application getApplication();
-    method public abstract android.os.IBinder onBind(android.content.Intent);
+    method @Nullable public abstract android.os.IBinder onBind(android.content.Intent);
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onCreate();
     method public void onDestroy();
     method public void onLowMemory();
     method public void onRebind(android.content.Intent);
-    method public deprecated void onStart(android.content.Intent, int);
+    method @Deprecated public void onStart(android.content.Intent, int);
     method public int onStartCommand(android.content.Intent, int, int);
     method public void onTaskRemoved(android.content.Intent);
     method public void onTrimMemory(int);
@@ -6163,15 +6188,15 @@
     ctor public SharedElementCallback();
     method public android.os.Parcelable onCaptureSharedElementSnapshot(android.view.View, android.graphics.Matrix, android.graphics.RectF);
     method public android.view.View onCreateSnapshotView(android.content.Context, android.os.Parcelable);
-    method public void onMapSharedElements(java.util.List<java.lang.String>, java.util.Map<java.lang.String, android.view.View>);
+    method public void onMapSharedElements(java.util.List<java.lang.String>, java.util.Map<java.lang.String,android.view.View>);
     method public void onRejectSharedElements(java.util.List<android.view.View>);
     method public void onSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
     method public void onSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
     method public void onSharedElementsArrived(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.app.SharedElementCallback.OnSharedElementsReadyListener);
   }
 
-  public static abstract interface SharedElementCallback.OnSharedElementsReadyListener {
-    method public abstract void onSharedElementsReady();
+  public static interface SharedElementCallback.OnSharedElementsReadyListener {
+    method public void onSharedElementsReady();
   }
 
   public class SmsAppService extends android.app.Service {
@@ -6179,12 +6204,12 @@
     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();
-    method public android.widget.TabWidget getTabWidget();
-    method public void setDefaultTab(java.lang.String);
-    method public void setDefaultTab(int);
+  @Deprecated public class TabActivity extends android.app.ActivityGroup {
+    ctor @Deprecated public TabActivity();
+    method @Deprecated public android.widget.TabHost getTabHost();
+    method @Deprecated public android.widget.TabWidget getTabWidget();
+    method @Deprecated public void setDefaultTab(String);
+    method @Deprecated public void setDefaultTab(int);
   }
 
   public class TaskInfo {
@@ -6202,12 +6227,12 @@
     method public android.app.TaskStackBuilder addNextIntent(android.content.Intent);
     method public android.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
     method public android.app.TaskStackBuilder addParentStack(android.app.Activity);
-    method public android.app.TaskStackBuilder addParentStack(java.lang.Class<?>);
+    method public android.app.TaskStackBuilder addParentStack(Class<?>);
     method public android.app.TaskStackBuilder addParentStack(android.content.ComponentName);
     method public static android.app.TaskStackBuilder create(android.content.Context);
     method public android.content.Intent editIntentAt(int);
     method public int getIntentCount();
-    method public android.content.Intent[] getIntents();
+    method @NonNull public android.content.Intent[] getIntents();
     method public android.app.PendingIntent getPendingIntent(int, int);
     method public android.app.PendingIntent getPendingIntent(int, int, android.os.Bundle);
     method public void startActivities();
@@ -6222,8 +6247,8 @@
     method public void updateTime(int, int);
   }
 
-  public static abstract interface TimePickerDialog.OnTimeSetListener {
-    method public abstract void onTimeSet(android.widget.TimePicker, int, int);
+  public static interface TimePickerDialog.OnTimeSetListener {
+    method public void onTimeSet(android.widget.TimePicker, int, int);
   }
 
   public final class UiAutomation {
@@ -6232,20 +6257,20 @@
     method public void clearWindowAnimationFrameStats();
     method public boolean clearWindowContentFrameStats(int);
     method public void dropShellPermissionIdentity();
-    method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
-    method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String);
+    method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
+    method public android.os.ParcelFileDescriptor executeShellCommand(String);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
     method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats();
     method public android.view.WindowContentFrameStats getWindowContentFrameStats(int);
     method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
-    method public void grantRuntimePermission(java.lang.String, java.lang.String);
-    method public void grantRuntimePermissionAsUser(java.lang.String, java.lang.String, android.os.UserHandle);
+    method public void grantRuntimePermission(String, String);
+    method public void grantRuntimePermissionAsUser(String, String, android.os.UserHandle);
     method public boolean injectInputEvent(android.view.InputEvent, boolean);
     method public boolean performGlobalAction(int);
-    method public void revokeRuntimePermission(java.lang.String, java.lang.String);
-    method public void revokeRuntimePermissionAsUser(java.lang.String, java.lang.String, android.os.UserHandle);
+    method public void revokeRuntimePermission(String, String);
+    method public void revokeRuntimePermissionAsUser(String, String, android.os.UserHandle);
     method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener);
     method public boolean setRotation(int);
     method public void setRunAsMonkey(boolean);
@@ -6261,12 +6286,12 @@
     field public static final int ROTATION_UNFREEZE = -2; // 0xfffffffe
   }
 
-  public static abstract interface UiAutomation.AccessibilityEventFilter {
-    method public abstract boolean accept(android.view.accessibility.AccessibilityEvent);
+  public static interface UiAutomation.AccessibilityEventFilter {
+    method public boolean accept(android.view.accessibility.AccessibilityEvent);
   }
 
-  public static abstract interface UiAutomation.OnAccessibilityEventListener {
-    method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+  public static interface UiAutomation.OnAccessibilityEventListener {
+    method public void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
   }
 
   public class UiModeManager {
@@ -6275,10 +6300,10 @@
     method public int getCurrentModeType();
     method public int getNightMode();
     method public void setNightMode(int);
-    field public static java.lang.String ACTION_ENTER_CAR_MODE;
-    field public static java.lang.String ACTION_ENTER_DESK_MODE;
-    field public static java.lang.String ACTION_EXIT_CAR_MODE;
-    field public static java.lang.String ACTION_EXIT_DESK_MODE;
+    field public static String ACTION_ENTER_CAR_MODE;
+    field public static String ACTION_ENTER_DESK_MODE;
+    field public static String ACTION_EXIT_CAR_MODE;
+    field public static String ACTION_EXIT_DESK_MODE;
     field public static final int DISABLE_CAR_MODE_GO_HOME = 1; // 0x1
     field public static final int ENABLE_CAR_MODE_ALLOW_SLEEP = 2; // 0x2
     field public static final int ENABLE_CAR_MODE_GO_CAR_HOME = 1; // 0x1
@@ -6288,68 +6313,68 @@
   }
 
   public final class VoiceInteractor {
-    method public android.app.VoiceInteractor.Request getActiveRequest(java.lang.String);
+    method public android.app.VoiceInteractor.Request getActiveRequest(String);
     method public android.app.VoiceInteractor.Request[] getActiveRequests();
     method public boolean submitRequest(android.app.VoiceInteractor.Request);
-    method public boolean submitRequest(android.app.VoiceInteractor.Request, java.lang.String);
-    method public boolean[] supportsCommands(java.lang.String[]);
+    method public boolean submitRequest(android.app.VoiceInteractor.Request, String);
+    method public boolean[] supportsCommands(String[]);
   }
 
   public static class VoiceInteractor.AbortVoiceRequest extends android.app.VoiceInteractor.Request {
-    ctor public VoiceInteractor.AbortVoiceRequest(android.app.VoiceInteractor.Prompt, android.os.Bundle);
+    ctor public VoiceInteractor.AbortVoiceRequest(@Nullable android.app.VoiceInteractor.Prompt, @Nullable android.os.Bundle);
     method public void onAbortResult(android.os.Bundle);
   }
 
   public static class VoiceInteractor.CommandRequest extends android.app.VoiceInteractor.Request {
-    ctor public VoiceInteractor.CommandRequest(java.lang.String, android.os.Bundle);
+    ctor public VoiceInteractor.CommandRequest(String, android.os.Bundle);
     method public void onCommandResult(boolean, android.os.Bundle);
   }
 
   public static class VoiceInteractor.CompleteVoiceRequest extends android.app.VoiceInteractor.Request {
-    ctor public VoiceInteractor.CompleteVoiceRequest(android.app.VoiceInteractor.Prompt, android.os.Bundle);
+    ctor public VoiceInteractor.CompleteVoiceRequest(@Nullable android.app.VoiceInteractor.Prompt, @Nullable android.os.Bundle);
     method public void onCompleteResult(android.os.Bundle);
   }
 
   public static class VoiceInteractor.ConfirmationRequest extends android.app.VoiceInteractor.Request {
-    ctor public VoiceInteractor.ConfirmationRequest(android.app.VoiceInteractor.Prompt, android.os.Bundle);
+    ctor public VoiceInteractor.ConfirmationRequest(@Nullable android.app.VoiceInteractor.Prompt, @Nullable android.os.Bundle);
     method public void onConfirmationResult(boolean, android.os.Bundle);
   }
 
   public static class VoiceInteractor.PickOptionRequest extends android.app.VoiceInteractor.Request {
-    ctor public VoiceInteractor.PickOptionRequest(android.app.VoiceInteractor.Prompt, android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle);
+    ctor public VoiceInteractor.PickOptionRequest(@Nullable android.app.VoiceInteractor.Prompt, android.app.VoiceInteractor.PickOptionRequest.Option[], @Nullable android.os.Bundle);
     method public void onPickOptionResult(boolean, android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle);
   }
 
   public static final class VoiceInteractor.PickOptionRequest.Option implements android.os.Parcelable {
-    ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence, int);
-    method public android.app.VoiceInteractor.PickOptionRequest.Option addSynonym(java.lang.CharSequence);
+    ctor public VoiceInteractor.PickOptionRequest.Option(CharSequence, int);
+    method public android.app.VoiceInteractor.PickOptionRequest.Option addSynonym(CharSequence);
     method public int countSynonyms();
     method public int describeContents();
     method public android.os.Bundle getExtras();
     method public int getIndex();
-    method public java.lang.CharSequence getLabel();
-    method public java.lang.CharSequence getSynonymAt(int);
+    method public CharSequence getLabel();
+    method public CharSequence getSynonymAt(int);
     method public void setExtras(android.os.Bundle);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.VoiceInteractor.PickOptionRequest.Option> CREATOR;
   }
 
   public static class VoiceInteractor.Prompt implements android.os.Parcelable {
-    ctor public VoiceInteractor.Prompt(java.lang.CharSequence[], java.lang.CharSequence);
-    ctor public VoiceInteractor.Prompt(java.lang.CharSequence);
+    ctor public VoiceInteractor.Prompt(@NonNull CharSequence[], @NonNull CharSequence);
+    ctor public VoiceInteractor.Prompt(@NonNull CharSequence);
     method public int countVoicePrompts();
     method public int describeContents();
-    method public java.lang.CharSequence getVisualPrompt();
-    method public java.lang.CharSequence getVoicePromptAt(int);
+    method @NonNull public CharSequence getVisualPrompt();
+    method @NonNull public CharSequence getVoicePromptAt(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.VoiceInteractor.Prompt> CREATOR;
   }
 
-  public static abstract class VoiceInteractor.Request {
+  public abstract static class VoiceInteractor.Request {
     method public void cancel();
     method public android.app.Activity getActivity();
     method public android.content.Context getContext();
-    method public java.lang.String getName();
+    method public String getName();
     method public void onAttached(android.app.Activity);
     method public void onCancel();
     method public void onDetached();
@@ -6357,13 +6382,13 @@
 
   public final class WallpaperColors implements android.os.Parcelable {
     ctor public WallpaperColors(android.os.Parcel);
-    ctor public WallpaperColors(android.graphics.Color, android.graphics.Color, android.graphics.Color);
+    ctor public WallpaperColors(@NonNull android.graphics.Color, @Nullable android.graphics.Color, @Nullable android.graphics.Color);
     method public int describeContents();
-    method public static android.app.WallpaperColors fromBitmap(android.graphics.Bitmap);
+    method public static android.app.WallpaperColors fromBitmap(@NonNull android.graphics.Bitmap);
     method public static android.app.WallpaperColors fromDrawable(android.graphics.drawable.Drawable);
-    method public android.graphics.Color getPrimaryColor();
-    method public android.graphics.Color getSecondaryColor();
-    method public android.graphics.Color getTertiaryColor();
+    method @NonNull public android.graphics.Color getPrimaryColor();
+    method @Nullable public android.graphics.Color getSecondaryColor();
+    method @Nullable public android.graphics.Color getTertiaryColor();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR;
   }
@@ -6371,20 +6396,20 @@
   public final class WallpaperInfo implements android.os.Parcelable {
     ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(android.util.Printer, String);
     method public android.content.ComponentName getComponent();
-    method public java.lang.String getPackageName();
+    method public String getPackageName();
     method public android.content.pm.ServiceInfo getServiceInfo();
-    method public java.lang.String getServiceName();
-    method public java.lang.String getSettingsActivity();
+    method public String getServiceName();
+    method public String getSettingsActivity();
     method public android.net.Uri getSettingsSliceUri();
     method public boolean getShowMetadataInPreview();
-    method public java.lang.CharSequence loadAuthor(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
-    method public java.lang.CharSequence loadContextDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+    method public CharSequence loadAuthor(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+    method public CharSequence loadContextDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
     method public android.net.Uri loadContextUri(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
-    method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+    method public CharSequence loadDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
-    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
+    method public CharSequence loadLabel(android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadThumbnail(android.content.pm.PackageManager);
     method public boolean supportsMultipleDisplays();
     method public void writeToParcel(android.os.Parcel, int);
@@ -6392,10 +6417,10 @@
   }
 
   public class WallpaperManager {
-    method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler);
-    method public void clear() throws java.io.IOException;
-    method public void clear(int) throws java.io.IOException;
-    method public void clearWallpaper();
+    method public void addOnColorsChangedListener(@NonNull android.app.WallpaperManager.OnColorsChangedListener, @NonNull android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public void clear() throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public void clear(int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public void clearWallpaper();
     method public void clearWallpaperOffsets(android.os.IBinder);
     method public void forgetLoadedWallpaper();
     method public android.graphics.drawable.Drawable getBuiltInDrawable();
@@ -6406,45 +6431,45 @@
     method public int getDesiredMinimumHeight();
     method public int getDesiredMinimumWidth();
     method public android.graphics.drawable.Drawable getDrawable();
-    method public android.graphics.drawable.Drawable getFastDrawable();
+    method @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public android.graphics.drawable.Drawable getFastDrawable();
     method public static android.app.WallpaperManager getInstance(android.content.Context);
-    method public android.app.WallpaperColors getWallpaperColors(int);
-    method public android.os.ParcelFileDescriptor getWallpaperFile(int);
+    method @Nullable public android.app.WallpaperColors getWallpaperColors(int);
+    method @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public android.os.ParcelFileDescriptor getWallpaperFile(int);
     method public int getWallpaperId(int);
     method public android.app.WallpaperInfo getWallpaperInfo();
-    method public boolean hasResourceWallpaper(int);
+    method public boolean hasResourceWallpaper(@RawRes int);
     method public boolean isSetWallpaperAllowed();
     method public boolean isWallpaperSupported();
     method public android.graphics.drawable.Drawable peekDrawable();
-    method public android.graphics.drawable.Drawable peekFastDrawable();
-    method public void removeOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener);
-    method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
-    method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
-    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
-    method public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean, int) throws java.io.IOException;
-    method public void setDisplayPadding(android.graphics.Rect);
-    method public void setResource(int) throws java.io.IOException;
-    method public int setResource(int, int) throws java.io.IOException;
-    method public void setStream(java.io.InputStream) throws java.io.IOException;
-    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
-    method public int setStream(java.io.InputStream, android.graphics.Rect, boolean, int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public android.graphics.drawable.Drawable peekFastDrawable();
+    method public void removeOnColorsChangedListener(@NonNull android.app.WallpaperManager.OnColorsChangedListener);
+    method public void sendWallpaperCommand(android.os.IBinder, String, int, int, int, android.os.Bundle);
+    method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean, int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_HINTS) public void setDisplayPadding(android.graphics.Rect);
+    method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public void setResource(@RawRes int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setResource(@RawRes int, int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public void setStream(java.io.InputStream) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStream(java.io.InputStream, android.graphics.Rect, boolean, int) throws java.io.IOException;
     method public void setWallpaperOffsetSteps(float, float);
     method public void setWallpaperOffsets(android.os.IBinder, float, float);
     method public void suggestDesiredDimensions(int, int);
-    field public static final java.lang.String ACTION_CHANGE_LIVE_WALLPAPER = "android.service.wallpaper.CHANGE_LIVE_WALLPAPER";
-    field public static final java.lang.String ACTION_CROP_AND_SET_WALLPAPER = "android.service.wallpaper.CROP_AND_SET_WALLPAPER";
-    field public static final java.lang.String ACTION_LIVE_WALLPAPER_CHOOSER = "android.service.wallpaper.LIVE_WALLPAPER_CHOOSER";
-    field public static final java.lang.String COMMAND_DROP = "android.home.drop";
-    field public static final java.lang.String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
-    field public static final java.lang.String COMMAND_TAP = "android.wallpaper.tap";
-    field public static final java.lang.String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
+    field public static final String ACTION_CHANGE_LIVE_WALLPAPER = "android.service.wallpaper.CHANGE_LIVE_WALLPAPER";
+    field public static final String ACTION_CROP_AND_SET_WALLPAPER = "android.service.wallpaper.CROP_AND_SET_WALLPAPER";
+    field public static final String ACTION_LIVE_WALLPAPER_CHOOSER = "android.service.wallpaper.LIVE_WALLPAPER_CHOOSER";
+    field public static final String COMMAND_DROP = "android.home.drop";
+    field public static final String COMMAND_SECONDARY_TAP = "android.wallpaper.secondaryTap";
+    field public static final String COMMAND_TAP = "android.wallpaper.tap";
+    field public static final String EXTRA_LIVE_WALLPAPER_COMPONENT = "android.service.wallpaper.extra.LIVE_WALLPAPER_COMPONENT";
     field public static final int FLAG_LOCK = 2; // 0x2
     field public static final int FLAG_SYSTEM = 1; // 0x1
-    field public static final java.lang.String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
+    field public static final String WALLPAPER_PREVIEW_META_DATA = "android.wallpaper.preview";
   }
 
-  public static abstract interface WallpaperManager.OnColorsChangedListener {
-    method public abstract void onColorsChanged(android.app.WallpaperColors, int);
+  public static interface WallpaperManager.OnColorsChangedListener {
+    method public void onColorsChanged(android.app.WallpaperColors, int);
   }
 
 }
@@ -6460,7 +6485,7 @@
 
   public class DelegatedAdminReceiver extends android.content.BroadcastReceiver {
     ctor public DelegatedAdminReceiver();
-    method public java.lang.String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, android.net.Uri, java.lang.String);
+    method public String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, android.net.Uri, String);
     method public void onNetworkLogsAvailable(android.content.Context, android.content.Intent, long, int);
     method public void onReceive(android.content.Context, android.content.Intent);
   }
@@ -6468,16 +6493,16 @@
   public final class DeviceAdminInfo implements android.os.Parcelable {
     ctor public DeviceAdminInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(android.util.Printer, String);
     method public android.content.pm.ActivityInfo getActivityInfo();
-    method public android.content.ComponentName getComponent();
-    method public java.lang.String getPackageName();
-    method public java.lang.String getReceiverName();
-    method public java.lang.String getTagForPolicy(int);
+    method @NonNull public android.content.ComponentName getComponent();
+    method public String getPackageName();
+    method public String getReceiverName();
+    method public String getTagForPolicy(int);
     method public boolean isVisible();
-    method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+    method public CharSequence loadDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
-    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
+    method public CharSequence loadLabel(android.content.pm.PackageManager);
     method public boolean supportsTransferOwnership();
     method public boolean usesPolicy(int);
     method public void writeToParcel(android.os.Parcel, int);
@@ -6498,53 +6523,53 @@
     method public android.app.admin.DevicePolicyManager getManager(android.content.Context);
     method public android.content.ComponentName getWho(android.content.Context);
     method public void onBugreportFailed(android.content.Context, android.content.Intent, int);
-    method public void onBugreportShared(android.content.Context, android.content.Intent, java.lang.String);
+    method public void onBugreportShared(android.content.Context, android.content.Intent, String);
     method public void onBugreportSharingDeclined(android.content.Context, android.content.Intent);
-    method public java.lang.String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, android.net.Uri, java.lang.String);
-    method public java.lang.CharSequence onDisableRequested(android.content.Context, android.content.Intent);
+    method public String onChoosePrivateKeyAlias(android.content.Context, android.content.Intent, int, android.net.Uri, String);
+    method public CharSequence onDisableRequested(android.content.Context, android.content.Intent);
     method public void onDisabled(android.content.Context, android.content.Intent);
     method public void onEnabled(android.content.Context, android.content.Intent);
-    method public void onLockTaskModeEntering(android.content.Context, android.content.Intent, java.lang.String);
+    method public void onLockTaskModeEntering(android.content.Context, android.content.Intent, String);
     method public void onLockTaskModeExiting(android.content.Context, android.content.Intent);
     method public void onNetworkLogsAvailable(android.content.Context, android.content.Intent, long, int);
-    method public deprecated void onPasswordChanged(android.content.Context, android.content.Intent);
+    method @Deprecated public void onPasswordChanged(android.content.Context, android.content.Intent);
     method public void onPasswordChanged(android.content.Context, android.content.Intent, android.os.UserHandle);
-    method public deprecated void onPasswordExpiring(android.content.Context, android.content.Intent);
+    method @Deprecated public void onPasswordExpiring(android.content.Context, android.content.Intent);
     method public void onPasswordExpiring(android.content.Context, android.content.Intent, android.os.UserHandle);
-    method public deprecated void onPasswordFailed(android.content.Context, android.content.Intent);
+    method @Deprecated public void onPasswordFailed(android.content.Context, android.content.Intent);
     method public void onPasswordFailed(android.content.Context, android.content.Intent, android.os.UserHandle);
-    method public deprecated void onPasswordSucceeded(android.content.Context, android.content.Intent);
+    method @Deprecated public void onPasswordSucceeded(android.content.Context, android.content.Intent);
     method public void onPasswordSucceeded(android.content.Context, android.content.Intent, android.os.UserHandle);
     method public void onProfileProvisioningComplete(android.content.Context, android.content.Intent);
-    method public deprecated void onReadyForUserInitialization(android.content.Context, android.content.Intent);
+    method @Deprecated public void onReadyForUserInitialization(android.content.Context, android.content.Intent);
     method public void onReceive(android.content.Context, android.content.Intent);
     method public void onSecurityLogsAvailable(android.content.Context, android.content.Intent);
     method public void onSystemUpdatePending(android.content.Context, android.content.Intent, long);
     method public void onTransferAffiliatedProfileOwnershipComplete(android.content.Context, android.os.UserHandle);
-    method public void onTransferOwnershipComplete(android.content.Context, android.os.PersistableBundle);
-    method public void onUserAdded(android.content.Context, android.content.Intent, android.os.UserHandle);
-    method public void onUserRemoved(android.content.Context, android.content.Intent, android.os.UserHandle);
-    method public void onUserStarted(android.content.Context, android.content.Intent, android.os.UserHandle);
-    method public void onUserStopped(android.content.Context, android.content.Intent, android.os.UserHandle);
-    method public void onUserSwitched(android.content.Context, android.content.Intent, android.os.UserHandle);
-    field public static final java.lang.String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS";
-    field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED";
-    field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
-    field public static final java.lang.String ACTION_DEVICE_ADMIN_ENABLED = "android.app.action.DEVICE_ADMIN_ENABLED";
-    field public static final java.lang.String ACTION_LOCK_TASK_ENTERING = "android.app.action.LOCK_TASK_ENTERING";
-    field public static final java.lang.String ACTION_LOCK_TASK_EXITING = "android.app.action.LOCK_TASK_EXITING";
-    field public static final java.lang.String ACTION_NETWORK_LOGS_AVAILABLE = "android.app.action.NETWORK_LOGS_AVAILABLE";
-    field public static final java.lang.String ACTION_PASSWORD_CHANGED = "android.app.action.ACTION_PASSWORD_CHANGED";
-    field public static final java.lang.String ACTION_PASSWORD_EXPIRING = "android.app.action.ACTION_PASSWORD_EXPIRING";
-    field public static final java.lang.String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";
-    field public static final java.lang.String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
-    field public static final java.lang.String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE";
+    method public void onTransferOwnershipComplete(@NonNull android.content.Context, @Nullable android.os.PersistableBundle);
+    method public void onUserAdded(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle);
+    method public void onUserRemoved(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle);
+    method public void onUserStarted(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle);
+    method public void onUserStopped(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle);
+    method public void onUserSwitched(android.content.Context, android.content.Intent, @NonNull android.os.UserHandle);
+    field public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS";
+    field public static final String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED";
+    field public static final String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
+    field public static final String ACTION_DEVICE_ADMIN_ENABLED = "android.app.action.DEVICE_ADMIN_ENABLED";
+    field public static final String ACTION_LOCK_TASK_ENTERING = "android.app.action.LOCK_TASK_ENTERING";
+    field public static final String ACTION_LOCK_TASK_EXITING = "android.app.action.LOCK_TASK_EXITING";
+    field public static final String ACTION_NETWORK_LOGS_AVAILABLE = "android.app.action.NETWORK_LOGS_AVAILABLE";
+    field public static final String ACTION_PASSWORD_CHANGED = "android.app.action.ACTION_PASSWORD_CHANGED";
+    field public static final String ACTION_PASSWORD_EXPIRING = "android.app.action.ACTION_PASSWORD_EXPIRING";
+    field public static final String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";
+    field public static final String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
+    field public static final String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE";
     field public static final int BUGREPORT_FAILURE_FAILED_COMPLETING = 0; // 0x0
     field public static final int BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE = 1; // 0x1
-    field public static final java.lang.String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
-    field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
-    field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
-    field public static final java.lang.String EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE = "android.app.extra.TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE";
+    field public static final String DEVICE_ADMIN_META_DATA = "android.app.device_admin";
+    field public static final String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
+    field public static final String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
+    field public static final String EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE = "android.app.extra.TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE";
   }
 
   public class DeviceAdminService extends android.app.Service {
@@ -6553,286 +6578,292 @@
   }
 
   public class DevicePolicyManager {
-    method public void addCrossProfileCalendarPackage(android.content.ComponentName, java.lang.String);
-    method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
-    method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
-    method public int addOverrideApn(android.content.ComponentName, android.telephony.data.ApnSetting);
-    method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
-    method public void addUserRestriction(android.content.ComponentName, java.lang.String);
-    method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
-    method public void clearApplicationUserData(android.content.ComponentName, java.lang.String, java.util.concurrent.Executor, android.app.admin.DevicePolicyManager.OnClearApplicationUserDataListener);
-    method public void clearCrossProfileIntentFilters(android.content.ComponentName);
-    method public deprecated void clearDeviceOwnerApp(java.lang.String);
-    method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
-    method public deprecated void clearProfileOwner(android.content.ComponentName);
+    method public void addCrossProfileCalendarPackage(@NonNull android.content.ComponentName, @NonNull String);
+    method public void addCrossProfileIntentFilter(@NonNull android.content.ComponentName, android.content.IntentFilter, int);
+    method public boolean addCrossProfileWidgetProvider(@NonNull android.content.ComponentName, String);
+    method public int addOverrideApn(@NonNull android.content.ComponentName, @NonNull android.telephony.data.ApnSetting);
+    method public void addPersistentPreferredActivity(@NonNull android.content.ComponentName, android.content.IntentFilter, @NonNull android.content.ComponentName);
+    method public void addUserRestriction(@NonNull android.content.ComponentName, String);
+    method public boolean bindDeviceAdminServiceAsUser(@NonNull android.content.ComponentName, android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull android.os.UserHandle);
+    method public void clearApplicationUserData(@NonNull android.content.ComponentName, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.app.admin.DevicePolicyManager.OnClearApplicationUserDataListener);
+    method public void clearCrossProfileIntentFilters(@NonNull android.content.ComponentName);
+    method @Deprecated public void clearDeviceOwnerApp(String);
+    method public void clearPackagePersistentPreferredActivities(@NonNull android.content.ComponentName, String);
+    method @Deprecated public void clearProfileOwner(@NonNull android.content.ComponentName);
     method public boolean clearResetPasswordToken(android.content.ComponentName);
-    method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
-    method public android.content.Intent createAdminSupportIntent(java.lang.String);
-    method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int);
-    method public void enableSystemApp(android.content.ComponentName, java.lang.String);
-    method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
-    method public android.security.AttestedKeyPair generateKeyPair(android.content.ComponentName, java.lang.String, android.security.keystore.KeyGenParameterSpec, int);
-    method public java.lang.String[] getAccountTypesWithManagementDisabled();
-    method public java.util.List<android.content.ComponentName> getActiveAdmins();
-    method public java.util.Set<java.lang.String> getAffiliationIds(android.content.ComponentName);
-    method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
-    method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
-    method public deprecated java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
+    method public void clearUserRestriction(@NonNull android.content.ComponentName, String);
+    method public android.content.Intent createAdminSupportIntent(@NonNull String);
+    method @Nullable public android.os.UserHandle createAndManageUser(@NonNull android.content.ComponentName, @NonNull String, @NonNull android.content.ComponentName, @Nullable android.os.PersistableBundle, int);
+    method public void enableSystemApp(@NonNull android.content.ComponentName, String);
+    method public int enableSystemApp(@NonNull android.content.ComponentName, android.content.Intent);
+    method public android.security.AttestedKeyPair generateKeyPair(@Nullable android.content.ComponentName, @NonNull String, @NonNull android.security.keystore.KeyGenParameterSpec, int);
+    method @Nullable public String[] getAccountTypesWithManagementDisabled();
+    method @Nullable public java.util.List<android.content.ComponentName> getActiveAdmins();
+    method @NonNull public java.util.Set<java.lang.String> getAffiliationIds(@NonNull android.content.ComponentName);
+    method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName);
+    method @WorkerThread @NonNull public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
+    method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
     method public boolean getAutoTimeRequired();
-    method public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(android.content.ComponentName);
-    method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName);
-    method public boolean getCameraDisabled(android.content.ComponentName);
-    method public deprecated java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
-    method public java.util.Set<java.lang.String> getCrossProfileCalendarPackages(android.content.ComponentName);
-    method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
-    method public boolean getCrossProfileContactsSearchDisabled(android.content.ComponentName);
-    method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
+    method @NonNull public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(@NonNull android.content.ComponentName);
+    method public boolean getBluetoothContactSharingDisabled(@NonNull android.content.ComponentName);
+    method public boolean getCameraDisabled(@Nullable android.content.ComponentName);
+    method @Deprecated @Nullable public String getCertInstallerPackage(@NonNull android.content.ComponentName) throws java.lang.SecurityException;
+    method @NonNull public java.util.Set<java.lang.String> getCrossProfileCalendarPackages(@NonNull android.content.ComponentName);
+    method public boolean getCrossProfileCallerIdDisabled(@NonNull android.content.ComponentName);
+    method public boolean getCrossProfileContactsSearchDisabled(@NonNull android.content.ComponentName);
+    method @NonNull public java.util.List<java.lang.String> getCrossProfileWidgetProviders(@NonNull android.content.ComponentName);
     method public int getCurrentFailedPasswordAttempts();
-    method public java.util.List<java.lang.String> getDelegatePackages(android.content.ComponentName, java.lang.String);
-    method public java.util.List<java.lang.String> getDelegatedScopes(android.content.ComponentName, java.lang.String);
-    method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
-    method public java.lang.CharSequence getEndUserSessionMessage(android.content.ComponentName);
-    method public java.lang.String getGlobalPrivateDnsHost(android.content.ComponentName);
-    method public int getGlobalPrivateDnsMode(android.content.ComponentName);
-    method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
-    method public java.util.List<java.lang.String> getKeepUninstalledPackages(android.content.ComponentName);
-    method public int getKeyguardDisabledFeatures(android.content.ComponentName);
-    method public int getLockTaskFeatures(android.content.ComponentName);
-    method public java.lang.String[] getLockTaskPackages(android.content.ComponentName);
-    method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
-    method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
-    method public long getMaximumTimeToLock(android.content.ComponentName);
-    method public java.util.List<java.lang.String> getMeteredDataDisabledPackages(android.content.ComponentName);
-    method public int getOrganizationColor(android.content.ComponentName);
-    method public java.lang.CharSequence getOrganizationName(android.content.ComponentName);
-    method public java.util.List<android.telephony.data.ApnSetting> getOverrideApns(android.content.ComponentName);
-    method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
-    method public int getPasswordComplexity();
-    method public long getPasswordExpiration(android.content.ComponentName);
-    method public long getPasswordExpirationTimeout(android.content.ComponentName);
-    method public int getPasswordHistoryLength(android.content.ComponentName);
+    method @Nullable public java.util.List<java.lang.String> getDelegatePackages(@NonNull android.content.ComponentName, @NonNull String);
+    method @NonNull public java.util.List<java.lang.String> getDelegatedScopes(@Nullable android.content.ComponentName, @NonNull String);
+    method public CharSequence getDeviceOwnerLockScreenInfo();
+    method public CharSequence getEndUserSessionMessage(@NonNull android.content.ComponentName);
+    method public String getGlobalPrivateDnsHost(@NonNull android.content.ComponentName);
+    method public int getGlobalPrivateDnsMode(@NonNull android.content.ComponentName);
+    method @NonNull public java.util.List<byte[]> getInstalledCaCerts(@Nullable android.content.ComponentName);
+    method @Nullable public java.util.List<java.lang.String> getKeepUninstalledPackages(@Nullable android.content.ComponentName);
+    method public int getKeyguardDisabledFeatures(@Nullable android.content.ComponentName);
+    method public int getLockTaskFeatures(@NonNull android.content.ComponentName);
+    method @NonNull public String[] getLockTaskPackages(@NonNull android.content.ComponentName);
+    method @Nullable public CharSequence getLongSupportMessage(@NonNull android.content.ComponentName);
+    method public int getMaximumFailedPasswordsForWipe(@Nullable android.content.ComponentName);
+    method public long getMaximumTimeToLock(@Nullable android.content.ComponentName);
+    method @NonNull public java.util.List<java.lang.String> getMeteredDataDisabledPackages(@NonNull android.content.ComponentName);
+    method @ColorInt public int getOrganizationColor(@NonNull android.content.ComponentName);
+    method @Nullable public CharSequence getOrganizationName(@NonNull android.content.ComponentName);
+    method public java.util.List<android.telephony.data.ApnSetting> getOverrideApns(@NonNull android.content.ComponentName);
+    method @NonNull public android.app.admin.DevicePolicyManager getParentProfileInstance(@NonNull android.content.ComponentName);
+    method @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY) public int getPasswordComplexity();
+    method public long getPasswordExpiration(@Nullable android.content.ComponentName);
+    method public long getPasswordExpirationTimeout(@Nullable android.content.ComponentName);
+    method public int getPasswordHistoryLength(@Nullable android.content.ComponentName);
     method public int getPasswordMaximumLength(int);
-    method public int getPasswordMinimumLength(android.content.ComponentName);
-    method public int getPasswordMinimumLetters(android.content.ComponentName);
-    method public int getPasswordMinimumLowerCase(android.content.ComponentName);
-    method public int getPasswordMinimumNonLetter(android.content.ComponentName);
-    method public int getPasswordMinimumNumeric(android.content.ComponentName);
-    method public int getPasswordMinimumSymbols(android.content.ComponentName);
-    method public int getPasswordMinimumUpperCase(android.content.ComponentName);
-    method public int getPasswordQuality(android.content.ComponentName);
-    method public android.app.admin.SystemUpdateInfo getPendingSystemUpdate(android.content.ComponentName);
-    method public int getPermissionGrantState(android.content.ComponentName, java.lang.String, java.lang.String);
+    method public int getPasswordMinimumLength(@Nullable android.content.ComponentName);
+    method public int getPasswordMinimumLetters(@Nullable android.content.ComponentName);
+    method public int getPasswordMinimumLowerCase(@Nullable android.content.ComponentName);
+    method public int getPasswordMinimumNonLetter(@Nullable android.content.ComponentName);
+    method public int getPasswordMinimumNumeric(@Nullable android.content.ComponentName);
+    method public int getPasswordMinimumSymbols(@Nullable android.content.ComponentName);
+    method public int getPasswordMinimumUpperCase(@Nullable android.content.ComponentName);
+    method public int getPasswordQuality(@Nullable android.content.ComponentName);
+    method @Nullable public android.app.admin.SystemUpdateInfo getPendingSystemUpdate(@NonNull android.content.ComponentName);
+    method public int getPermissionGrantState(@Nullable android.content.ComponentName, String, String);
     method public int getPermissionPolicy(android.content.ComponentName);
-    method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
-    method public java.util.List<java.lang.String> getPermittedCrossProfileNotificationListeners(android.content.ComponentName);
-    method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
-    method public long getRequiredStrongAuthTimeout(android.content.ComponentName);
-    method public boolean getScreenCaptureDisabled(android.content.ComponentName);
-    method public java.util.List<android.os.UserHandle> getSecondaryUsers(android.content.ComponentName);
-    method public java.lang.CharSequence getShortSupportMessage(android.content.ComponentName);
-    method public java.lang.CharSequence getStartUserSessionMessage(android.content.ComponentName);
-    method public boolean getStorageEncryption(android.content.ComponentName);
+    method @Nullable public java.util.List<java.lang.String> getPermittedAccessibilityServices(@NonNull android.content.ComponentName);
+    method @Nullable public java.util.List<java.lang.String> getPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName);
+    method @Nullable public java.util.List<java.lang.String> getPermittedInputMethods(@NonNull android.content.ComponentName);
+    method public long getRequiredStrongAuthTimeout(@Nullable android.content.ComponentName);
+    method public boolean getScreenCaptureDisabled(@Nullable android.content.ComponentName);
+    method public java.util.List<android.os.UserHandle> getSecondaryUsers(@NonNull android.content.ComponentName);
+    method public CharSequence getShortSupportMessage(@NonNull android.content.ComponentName);
+    method public CharSequence getStartUserSessionMessage(@NonNull android.content.ComponentName);
+    method public boolean getStorageEncryption(@Nullable android.content.ComponentName);
     method public int getStorageEncryptionStatus();
-    method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
-    method public android.os.PersistableBundle getTransferOwnershipBundle();
-    method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
-    method public android.os.Bundle getUserRestrictions(android.content.ComponentName);
-    method public java.lang.String getWifiMacAddress(android.content.ComponentName);
-    method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
-    method public boolean hasGrantedPolicy(android.content.ComponentName, int);
-    method public boolean installCaCert(android.content.ComponentName, byte[]);
-    method public boolean installExistingPackage(android.content.ComponentName, java.lang.String);
-    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
-    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean);
-    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, int);
-    method public void installSystemUpdate(android.content.ComponentName, android.net.Uri, java.util.concurrent.Executor, android.app.admin.DevicePolicyManager.InstallUpdateCallback);
+    method @Nullable public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
+    method @Nullable public android.os.PersistableBundle getTransferOwnershipBundle();
+    method @Nullable public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(@Nullable android.content.ComponentName, @NonNull android.content.ComponentName);
+    method @NonNull public android.os.Bundle getUserRestrictions(@NonNull android.content.ComponentName);
+    method @Nullable public String getWifiMacAddress(@NonNull android.content.ComponentName);
+    method public boolean hasCaCertInstalled(@Nullable android.content.ComponentName, byte[]);
+    method public boolean hasGrantedPolicy(@NonNull android.content.ComponentName, int);
+    method public boolean installCaCert(@Nullable android.content.ComponentName, byte[]);
+    method public boolean installExistingPackage(@NonNull android.content.ComponentName, String);
+    method public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate, @NonNull String);
+    method public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate[], @NonNull String, boolean);
+    method public boolean installKeyPair(@Nullable android.content.ComponentName, @NonNull java.security.PrivateKey, @NonNull java.security.cert.Certificate[], @NonNull String, int);
+    method public void installSystemUpdate(@NonNull android.content.ComponentName, @NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.app.admin.DevicePolicyManager.InstallUpdateCallback);
     method public boolean isActivePasswordSufficient();
-    method public boolean isAdminActive(android.content.ComponentName);
+    method public boolean isAdminActive(@NonNull android.content.ComponentName);
     method public boolean isAffiliatedUser();
-    method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
-    method public boolean isBackupServiceEnabled(android.content.ComponentName);
-    method public deprecated boolean isCallerApplicationRestrictionsManagingPackage();
+    method public boolean isApplicationHidden(@NonNull android.content.ComponentName, String);
+    method public boolean isBackupServiceEnabled(@NonNull android.content.ComponentName);
+    method @Deprecated public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceIdAttestationSupported();
-    method public boolean isDeviceOwnerApp(java.lang.String);
-    method public boolean isEphemeralUser(android.content.ComponentName);
-    method public boolean isLockTaskPermitted(java.lang.String);
+    method public boolean isDeviceOwnerApp(String);
+    method public boolean isEphemeralUser(@NonNull android.content.ComponentName);
+    method public boolean isLockTaskPermitted(String);
     method public boolean isLogoutEnabled();
-    method public boolean isManagedProfile(android.content.ComponentName);
-    method public boolean isMasterVolumeMuted(android.content.ComponentName);
-    method public boolean isNetworkLoggingEnabled(android.content.ComponentName);
-    method public boolean isOverrideApnEnabled(android.content.ComponentName);
-    method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public boolean isProfileOwnerApp(java.lang.String);
-    method public boolean isProvisioningAllowed(java.lang.String);
+    method public boolean isManagedProfile(@NonNull android.content.ComponentName);
+    method public boolean isMasterVolumeMuted(@NonNull android.content.ComponentName);
+    method public boolean isNetworkLoggingEnabled(@Nullable android.content.ComponentName);
+    method public boolean isOverrideApnEnabled(@NonNull android.content.ComponentName);
+    method public boolean isPackageSuspended(@NonNull android.content.ComponentName, String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public boolean isProfileOwnerApp(String);
+    method public boolean isProvisioningAllowed(@NonNull String);
     method public boolean isResetPasswordTokenActive(android.content.ComponentName);
-    method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
-    method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
-    method public boolean isUsingUnifiedPassword(android.content.ComponentName);
+    method public boolean isSecurityLoggingEnabled(@Nullable android.content.ComponentName);
+    method public boolean isUninstallBlocked(@Nullable android.content.ComponentName, String);
+    method public boolean isUsingUnifiedPassword(@NonNull android.content.ComponentName);
     method public void lockNow();
     method public void lockNow(int);
-    method public int logoutUser(android.content.ComponentName);
-    method public void reboot(android.content.ComponentName);
-    method public void removeActiveAdmin(android.content.ComponentName);
-    method public boolean removeCrossProfileCalendarPackage(android.content.ComponentName, java.lang.String);
-    method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
-    method public boolean removeKeyPair(android.content.ComponentName, java.lang.String);
-    method public boolean removeOverrideApn(android.content.ComponentName, int);
-    method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
-    method public boolean requestBugreport(android.content.ComponentName);
-    method public boolean resetPassword(java.lang.String, int);
-    method public boolean resetPasswordWithToken(android.content.ComponentName, java.lang.String, byte[], int);
-    method public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(android.content.ComponentName, long);
-    method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
-    method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
-    method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
-    method public void setAffiliationIds(android.content.ComponentName, java.util.Set<java.lang.String>);
-    method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
-    method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
-    method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
-    method public deprecated void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public void setAutoTimeRequired(android.content.ComponentName, boolean);
-    method public void setBackupServiceEnabled(android.content.ComponentName, boolean);
-    method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
-    method public void setCameraDisabled(android.content.ComponentName, boolean);
-    method public deprecated void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
-    method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
-    method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
-    method public void setDelegatedScopes(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
-    method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
-    method public void setEndUserSessionMessage(android.content.ComponentName, java.lang.CharSequence);
-    method public int setGlobalPrivateDns(android.content.ComponentName, int, java.lang.String);
-    method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
-    method public void setKeepUninstalledPackages(android.content.ComponentName, java.util.List<java.lang.String>);
-    method public boolean setKeyPairCertificate(android.content.ComponentName, java.lang.String, java.util.List<java.security.cert.Certificate>, boolean);
-    method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
-    method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
-    method public void setLockTaskFeatures(android.content.ComponentName, int);
-    method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
-    method public void setLogoutEnabled(android.content.ComponentName, boolean);
-    method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
-    method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
-    method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
-    method public void setMaximumTimeToLock(android.content.ComponentName, long);
-    method public java.util.List<java.lang.String> setMeteredDataDisabledPackages(android.content.ComponentName, java.util.List<java.lang.String>);
-    method public void setNetworkLoggingEnabled(android.content.ComponentName, boolean);
-    method public void setOrganizationColor(android.content.ComponentName, int);
-    method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence);
-    method public void setOverrideApnsEnabled(android.content.ComponentName, boolean);
-    method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
-    method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
-    method public void setPasswordHistoryLength(android.content.ComponentName, int);
-    method public void setPasswordMinimumLength(android.content.ComponentName, int);
-    method public void setPasswordMinimumLetters(android.content.ComponentName, int);
-    method public void setPasswordMinimumLowerCase(android.content.ComponentName, int);
-    method public void setPasswordMinimumNonLetter(android.content.ComponentName, int);
-    method public void setPasswordMinimumNumeric(android.content.ComponentName, int);
-    method public void setPasswordMinimumSymbols(android.content.ComponentName, int);
-    method public void setPasswordMinimumUpperCase(android.content.ComponentName, int);
-    method public void setPasswordQuality(android.content.ComponentName, int);
-    method public boolean setPermissionGrantState(android.content.ComponentName, java.lang.String, java.lang.String, int);
-    method public void setPermissionPolicy(android.content.ComponentName, int);
-    method public boolean setPermittedAccessibilityServices(android.content.ComponentName, java.util.List<java.lang.String>);
-    method public boolean setPermittedCrossProfileNotificationListeners(android.content.ComponentName, java.util.List<java.lang.String>);
-    method public boolean setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>);
-    method public void setProfileEnabled(android.content.ComponentName);
-    method public void setProfileName(android.content.ComponentName, java.lang.String);
-    method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo);
-    method public void setRequiredStrongAuthTimeout(android.content.ComponentName, long);
+    method public int logoutUser(@NonNull android.content.ComponentName);
+    method public void reboot(@NonNull android.content.ComponentName);
+    method public void removeActiveAdmin(@NonNull android.content.ComponentName);
+    method public boolean removeCrossProfileCalendarPackage(@NonNull android.content.ComponentName, @NonNull String);
+    method public boolean removeCrossProfileWidgetProvider(@NonNull android.content.ComponentName, String);
+    method public boolean removeKeyPair(@Nullable android.content.ComponentName, @NonNull String);
+    method public boolean removeOverrideApn(@NonNull android.content.ComponentName, int);
+    method public boolean removeUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
+    method public boolean requestBugreport(@NonNull android.content.ComponentName);
+    method public boolean resetPassword(String, int);
+    method public boolean resetPasswordWithToken(@NonNull android.content.ComponentName, String, byte[], int);
+    method @Nullable public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(@Nullable android.content.ComponentName, long);
+    method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(@NonNull android.content.ComponentName);
+    method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(@NonNull android.content.ComponentName);
+    method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean);
+    method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
+    method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
+    method public boolean setApplicationHidden(@NonNull android.content.ComponentName, String, boolean);
+    method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle);
+    method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public void setAutoTimeRequired(@NonNull android.content.ComponentName, boolean);
+    method public void setBackupServiceEnabled(@NonNull android.content.ComponentName, boolean);
+    method public void setBluetoothContactSharingDisabled(@NonNull android.content.ComponentName, boolean);
+    method public void setCameraDisabled(@NonNull android.content.ComponentName, boolean);
+    method @Deprecated public void setCertInstallerPackage(@NonNull android.content.ComponentName, @Nullable String) throws java.lang.SecurityException;
+    method public void setCrossProfileCallerIdDisabled(@NonNull android.content.ComponentName, boolean);
+    method public void setCrossProfileContactsSearchDisabled(@NonNull android.content.ComponentName, boolean);
+    method public void setDelegatedScopes(@NonNull android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.lang.String>);
+    method public void setDeviceOwnerLockScreenInfo(@NonNull android.content.ComponentName, CharSequence);
+    method public void setEndUserSessionMessage(@NonNull android.content.ComponentName, @Nullable CharSequence);
+    method public int setGlobalPrivateDns(@NonNull android.content.ComponentName, int, @Nullable String);
+    method public void setGlobalSetting(@NonNull android.content.ComponentName, String, String);
+    method public void setKeepUninstalledPackages(@Nullable android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
+    method public boolean setKeyPairCertificate(@Nullable android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.security.cert.Certificate>, boolean);
+    method public boolean setKeyguardDisabled(@NonNull android.content.ComponentName, boolean);
+    method public void setKeyguardDisabledFeatures(@NonNull android.content.ComponentName, int);
+    method public void setLockTaskFeatures(@NonNull android.content.ComponentName, int);
+    method public void setLockTaskPackages(@NonNull android.content.ComponentName, @NonNull String[]) throws java.lang.SecurityException;
+    method public void setLogoutEnabled(@NonNull android.content.ComponentName, boolean);
+    method public void setLongSupportMessage(@NonNull android.content.ComponentName, @Nullable CharSequence);
+    method public void setMasterVolumeMuted(@NonNull android.content.ComponentName, boolean);
+    method public void setMaximumFailedPasswordsForWipe(@NonNull android.content.ComponentName, int);
+    method public void setMaximumTimeToLock(@NonNull android.content.ComponentName, long);
+    method @NonNull public java.util.List<java.lang.String> setMeteredDataDisabledPackages(@NonNull android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
+    method public void setNetworkLoggingEnabled(@Nullable android.content.ComponentName, boolean);
+    method public void setOrganizationColor(@NonNull android.content.ComponentName, int);
+    method public void setOrganizationName(@NonNull android.content.ComponentName, @Nullable CharSequence);
+    method public void setOverrideApnsEnabled(@NonNull android.content.ComponentName, boolean);
+    method @NonNull public String[] setPackagesSuspended(@NonNull android.content.ComponentName, @NonNull String[], boolean);
+    method public void setPasswordExpirationTimeout(@NonNull android.content.ComponentName, long);
+    method public void setPasswordHistoryLength(@NonNull android.content.ComponentName, int);
+    method public void setPasswordMinimumLength(@NonNull android.content.ComponentName, int);
+    method public void setPasswordMinimumLetters(@NonNull android.content.ComponentName, int);
+    method public void setPasswordMinimumLowerCase(@NonNull android.content.ComponentName, int);
+    method public void setPasswordMinimumNonLetter(@NonNull android.content.ComponentName, int);
+    method public void setPasswordMinimumNumeric(@NonNull android.content.ComponentName, int);
+    method public void setPasswordMinimumSymbols(@NonNull android.content.ComponentName, int);
+    method public void setPasswordMinimumUpperCase(@NonNull android.content.ComponentName, int);
+    method public void setPasswordQuality(@NonNull android.content.ComponentName, int);
+    method public boolean setPermissionGrantState(@NonNull android.content.ComponentName, String, String, int);
+    method public void setPermissionPolicy(@NonNull android.content.ComponentName, int);
+    method public boolean setPermittedAccessibilityServices(@NonNull android.content.ComponentName, java.util.List<java.lang.String>);
+    method public boolean setPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName, @Nullable java.util.List<java.lang.String>);
+    method public boolean setPermittedInputMethods(@NonNull android.content.ComponentName, java.util.List<java.lang.String>);
+    method public void setProfileEnabled(@NonNull android.content.ComponentName);
+    method public void setProfileName(@NonNull android.content.ComponentName, String);
+    method public void setRecommendedGlobalProxy(@NonNull android.content.ComponentName, @Nullable android.net.ProxyInfo);
+    method public void setRequiredStrongAuthTimeout(@NonNull android.content.ComponentName, long);
     method public boolean setResetPasswordToken(android.content.ComponentName, byte[]);
-    method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
-    method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
-    method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
-    method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
-    method public void setShortSupportMessage(android.content.ComponentName, java.lang.CharSequence);
-    method public void setStartUserSessionMessage(android.content.ComponentName, java.lang.CharSequence);
-    method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
-    method public int setStorageEncryption(android.content.ComponentName, boolean);
-    method public void setSystemSetting(android.content.ComponentName, java.lang.String, java.lang.String);
-    method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
-    method public boolean setTime(android.content.ComponentName, long);
-    method public boolean setTimeZone(android.content.ComponentName, java.lang.String);
-    method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
-    method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
-    method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap);
-    method public int startUserInBackground(android.content.ComponentName, android.os.UserHandle);
-    method public int stopUser(android.content.ComponentName, android.os.UserHandle);
-    method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
-    method public void transferOwnership(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
-    method public void uninstallAllUserCaCerts(android.content.ComponentName);
-    method public void uninstallCaCert(android.content.ComponentName, byte[]);
-    method public boolean updateOverrideApn(android.content.ComponentName, int, android.telephony.data.ApnSetting);
+    method public void setRestrictionsProvider(@NonNull android.content.ComponentName, @Nullable android.content.ComponentName);
+    method public void setScreenCaptureDisabled(@NonNull android.content.ComponentName, boolean);
+    method public void setSecureSetting(@NonNull android.content.ComponentName, String, String);
+    method public void setSecurityLoggingEnabled(@NonNull android.content.ComponentName, boolean);
+    method public void setShortSupportMessage(@NonNull android.content.ComponentName, @Nullable CharSequence);
+    method public void setStartUserSessionMessage(@NonNull android.content.ComponentName, @Nullable CharSequence);
+    method public boolean setStatusBarDisabled(@NonNull android.content.ComponentName, boolean);
+    method public int setStorageEncryption(@NonNull android.content.ComponentName, boolean);
+    method public void setSystemSetting(@NonNull android.content.ComponentName, @NonNull String, String);
+    method public void setSystemUpdatePolicy(@NonNull android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
+    method public boolean setTime(@NonNull android.content.ComponentName, long);
+    method public boolean setTimeZone(@NonNull android.content.ComponentName, String);
+    method public void setTrustAgentConfiguration(@NonNull android.content.ComponentName, @NonNull android.content.ComponentName, android.os.PersistableBundle);
+    method public void setUninstallBlocked(@Nullable android.content.ComponentName, String, boolean);
+    method public void setUserIcon(@NonNull android.content.ComponentName, android.graphics.Bitmap);
+    method public int startUserInBackground(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
+    method public int stopUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
+    method public boolean switchUser(@NonNull android.content.ComponentName, @Nullable android.os.UserHandle);
+    method public void transferOwnership(@NonNull android.content.ComponentName, @NonNull android.content.ComponentName, @Nullable android.os.PersistableBundle);
+    method public void uninstallAllUserCaCerts(@Nullable android.content.ComponentName);
+    method public void uninstallCaCert(@Nullable android.content.ComponentName, byte[]);
+    method public boolean updateOverrideApn(@NonNull android.content.ComponentName, int, @NonNull android.telephony.data.ApnSetting);
     method public void wipeData(int);
-    method public void wipeData(int, java.lang.CharSequence);
-    field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
-    field public static final java.lang.String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
-    field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
-    field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
-    field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
-    field public static final java.lang.String ACTION_PROFILE_OWNER_CHANGED = "android.app.action.PROFILE_OWNER_CHANGED";
-    field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
-    field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
-    field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
-    field public static final java.lang.String ACTION_SET_NEW_PARENT_PROFILE_PASSWORD = "android.app.action.SET_NEW_PARENT_PROFILE_PASSWORD";
-    field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
-    field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
-    field public static final java.lang.String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
-    field public static final java.lang.String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
-    field public static final java.lang.String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
-    field public static final java.lang.String DELEGATION_CERT_INSTALL = "delegation-cert-install";
-    field public static final java.lang.String DELEGATION_CERT_SELECTION = "delegation-cert-selection";
-    field public static final java.lang.String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app";
-    field public static final java.lang.String DELEGATION_INSTALL_EXISTING_PACKAGE = "delegation-install-existing-package";
-    field public static final java.lang.String DELEGATION_KEEP_UNINSTALLED_PACKAGES = "delegation-keep-uninstalled-packages";
-    field public static final java.lang.String DELEGATION_NETWORK_LOGGING = "delegation-network-logging";
-    field public static final java.lang.String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
-    field public static final java.lang.String DELEGATION_PACKAGE_INSTALLATION = "delegation-package-installation";
-    field public static final java.lang.String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
+    method public void wipeData(int, CharSequence);
+    field public static final String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
+    field public static final String ACTION_ADMIN_POLICY_COMPLIANCE = "android.app.action.ADMIN_POLICY_COMPLIANCE";
+    field public static final String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
+    field public static final String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
+    field public static final String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
+    field public static final String ACTION_GET_PROVISIONING_MODE = "android.app.action.GET_PROVISIONING_MODE";
+    field public static final String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
+    field public static final String ACTION_PROFILE_OWNER_CHANGED = "android.app.action.PROFILE_OWNER_CHANGED";
+    field public static final String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL";
+    field public static final String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
+    field public static final String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
+    field public static final String ACTION_SET_NEW_PARENT_PROFILE_PASSWORD = "android.app.action.SET_NEW_PARENT_PROFILE_PASSWORD";
+    field public static final String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
+    field public static final String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
+    field public static final String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
+    field public static final String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
+    field public static final String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
+    field public static final String DELEGATION_CERT_INSTALL = "delegation-cert-install";
+    field public static final String DELEGATION_CERT_SELECTION = "delegation-cert-selection";
+    field public static final String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app";
+    field public static final String DELEGATION_INSTALL_EXISTING_PACKAGE = "delegation-install-existing-package";
+    field public static final String DELEGATION_KEEP_UNINSTALLED_PACKAGES = "delegation-keep-uninstalled-packages";
+    field public static final String DELEGATION_NETWORK_LOGGING = "delegation-network-logging";
+    field public static final String DELEGATION_PACKAGE_ACCESS = "delegation-package-access";
+    field public static final String DELEGATION_PACKAGE_INSTALLATION = "delegation-package-installation";
+    field public static final String DELEGATION_PERMISSION_GRANT = "delegation-permission-grant";
     field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
     field public static final int ENCRYPTION_STATUS_ACTIVE = 3; // 0x3
     field public static final int ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY = 4; // 0x4
     field public static final int ENCRYPTION_STATUS_ACTIVE_PER_USER = 5; // 0x5
     field public static final int ENCRYPTION_STATUS_INACTIVE = 1; // 0x1
     field public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0; // 0x0
-    field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
-    field public static final java.lang.String EXTRA_DELEGATION_SCOPES = "android.app.extra.DELEGATION_SCOPES";
-    field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
-    field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
-    field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
-    field public static final deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM";
-    field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMERS = "android.app.extra.PROVISIONING_DISCLAIMERS";
-    field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_CONTENT = "android.app.extra.PROVISIONING_DISCLAIMER_CONTENT";
-    field public static final java.lang.String EXTRA_PROVISIONING_DISCLAIMER_HEADER = "android.app.extra.PROVISIONING_DISCLAIMER_HEADER";
-    field public static final deprecated java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
-    field public static final java.lang.String EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION = "android.app.extra.PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION";
-    field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
-    field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
-    field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
-    field public static final java.lang.String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
-    field public static final java.lang.String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
-    field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
-    field public static final java.lang.String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
-    field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_ANONYMOUS_IDENTITY = "android.app.extra.PROVISIONING_WIFI_ANONYMOUS_IDENTITY";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_CA_CERTIFICATE = "android.app.extra.PROVISIONING_WIFI_CA_CERTIFICATE";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_DOMAIN = "android.app.extra.PROVISIONING_WIFI_DOMAIN";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_EAP_METHOD = "android.app.extra.PROVISIONING_WIFI_EAP_METHOD";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_IDENTITY = "android.app.extra.PROVISIONING_WIFI_IDENTITY";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PASSWORD = "android.app.extra.PROVISIONING_WIFI_PASSWORD";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PHASE2_AUTH = "android.app.extra.PROVISIONING_WIFI_PHASE2_AUTH";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_BYPASS = "android.app.extra.PROVISIONING_WIFI_PROXY_BYPASS";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_HOST = "android.app.extra.PROVISIONING_WIFI_PROXY_HOST";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_PORT = "android.app.extra.PROVISIONING_WIFI_PROXY_PORT";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.PROVISIONING_WIFI_SSID";
-    field public static final java.lang.String EXTRA_PROVISIONING_WIFI_USER_CERTIFICATE = "android.app.extra.PROVISIONING_WIFI_USER_CERTIFICATE";
+    field public static final String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
+    field public static final String EXTRA_DELEGATION_SCOPES = "android.app.extra.DELEGATION_SCOPES";
+    field public static final String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
+    field @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY) public static final String EXTRA_PASSWORD_COMPLEXITY = "android.app.extra.PASSWORD_COMPLEXITY";
+    field public static final String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
+    field public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
+    field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
+    field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE";
+    field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
+    field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
+    field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
+    field @Deprecated public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
+    field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM";
+    field public static final String EXTRA_PROVISIONING_DISCLAIMERS = "android.app.extra.PROVISIONING_DISCLAIMERS";
+    field public static final String EXTRA_PROVISIONING_DISCLAIMER_CONTENT = "android.app.extra.PROVISIONING_DISCLAIMER_CONTENT";
+    field public static final String EXTRA_PROVISIONING_DISCLAIMER_HEADER = "android.app.extra.PROVISIONING_DISCLAIMER_HEADER";
+    field @Deprecated public static final String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
+    field public static final String EXTRA_PROVISIONING_IMEI = "android.app.extra.PROVISIONING_IMEI";
+    field public static final String EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION = "android.app.extra.PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION";
+    field public static final String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
+    field public static final String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
+    field public static final String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
+    field public static final String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
+    field public static final String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
+    field public static final String EXTRA_PROVISIONING_MODE = "android.app.extra.PROVISIONING_MODE";
+    field public static final String EXTRA_PROVISIONING_SERIAL_NUMBER = "android.app.extra.PROVISIONING_SERIAL_NUMBER";
+    field public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
+    field public static final String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
+    field public static final String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
+    field public static final String EXTRA_PROVISIONING_WIFI_ANONYMOUS_IDENTITY = "android.app.extra.PROVISIONING_WIFI_ANONYMOUS_IDENTITY";
+    field public static final String EXTRA_PROVISIONING_WIFI_CA_CERTIFICATE = "android.app.extra.PROVISIONING_WIFI_CA_CERTIFICATE";
+    field public static final String EXTRA_PROVISIONING_WIFI_DOMAIN = "android.app.extra.PROVISIONING_WIFI_DOMAIN";
+    field public static final String EXTRA_PROVISIONING_WIFI_EAP_METHOD = "android.app.extra.PROVISIONING_WIFI_EAP_METHOD";
+    field public static final String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
+    field public static final String EXTRA_PROVISIONING_WIFI_IDENTITY = "android.app.extra.PROVISIONING_WIFI_IDENTITY";
+    field public static final String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
+    field public static final String EXTRA_PROVISIONING_WIFI_PASSWORD = "android.app.extra.PROVISIONING_WIFI_PASSWORD";
+    field public static final String EXTRA_PROVISIONING_WIFI_PHASE2_AUTH = "android.app.extra.PROVISIONING_WIFI_PHASE2_AUTH";
+    field public static final String EXTRA_PROVISIONING_WIFI_PROXY_BYPASS = "android.app.extra.PROVISIONING_WIFI_PROXY_BYPASS";
+    field public static final String EXTRA_PROVISIONING_WIFI_PROXY_HOST = "android.app.extra.PROVISIONING_WIFI_PROXY_HOST";
+    field public static final String EXTRA_PROVISIONING_WIFI_PROXY_PORT = "android.app.extra.PROVISIONING_WIFI_PROXY_PORT";
+    field public static final String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE";
+    field public static final String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.PROVISIONING_WIFI_SSID";
+    field public static final String EXTRA_PROVISIONING_WIFI_USER_CERTIFICATE = "android.app.extra.PROVISIONING_WIFI_USER_CERTIFICATE";
     field public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1; // 0x1
     field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
     field public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 1; // 0x1
@@ -6863,7 +6894,7 @@
     field public static final int LOCK_TASK_FEATURE_OVERVIEW = 8; // 0x8
     field public static final int LOCK_TASK_FEATURE_SYSTEM_INFO = 1; // 0x1
     field public static final int MAKE_USER_EPHEMERAL = 2; // 0x2
-    field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
+    field public static final String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
     field public static final int PASSWORD_COMPLEXITY_HIGH = 327680; // 0x50000
     field public static final int PASSWORD_COMPLEXITY_LOW = 65536; // 0x10000
     field public static final int PASSWORD_COMPLEXITY_MEDIUM = 196608; // 0x30000
@@ -6882,8 +6913,8 @@
     field public static final int PERMISSION_POLICY_AUTO_DENY = 2; // 0x2
     field public static final int PERMISSION_POLICY_AUTO_GRANT = 1; // 0x1
     field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0
-    field public static final java.lang.String POLICY_DISABLE_CAMERA = "policy_disable_camera";
-    field public static final java.lang.String POLICY_DISABLE_SCREEN_CAPTURE = "policy_disable_screen_capture";
+    field public static final String POLICY_DISABLE_CAMERA = "policy_disable_camera";
+    field public static final String POLICY_DISABLE_SCREEN_CAPTURE = "policy_disable_screen_capture";
     field public static final int PRIVATE_DNS_MODE_OFF = 1; // 0x1
     field public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; // 0x2
     field public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; // 0x3
@@ -6891,6 +6922,9 @@
     field public static final int PRIVATE_DNS_SET_ERROR_FAILURE_SETTING = 2; // 0x2
     field public static final int PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING = 1; // 0x1
     field public static final int PRIVATE_DNS_SET_SUCCESS = 0; // 0x0
+    field public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1; // 0x1
+    field public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2; // 0x2
+    field public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE = 3; // 0x3
     field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
     field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
     field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
@@ -6899,9 +6933,9 @@
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
   }
 
-  public static abstract class DevicePolicyManager.InstallUpdateCallback {
+  public abstract static class DevicePolicyManager.InstallUpdateCallback {
     ctor public DevicePolicyManager.InstallUpdateCallback();
-    method public void onInstallUpdateError(int, java.lang.String);
+    method public void onInstallUpdateError(int, String);
     field public static final int UPDATE_ERROR_BATTERY_LOW = 5; // 0x5
     field public static final int UPDATE_ERROR_FILE_NOT_FOUND = 4; // 0x4
     field public static final int UPDATE_ERROR_INCORRECT_OS_VERSION = 2; // 0x2
@@ -6909,12 +6943,12 @@
     field public static final int UPDATE_ERROR_UPDATE_FILE_INVALID = 3; // 0x3
   }
 
-  public static abstract interface DevicePolicyManager.OnClearApplicationUserDataListener {
-    method public abstract void onApplicationUserDataCleared(java.lang.String, boolean);
+  public static interface DevicePolicyManager.OnClearApplicationUserDataListener {
+    method public void onApplicationUserDataCleared(String, boolean);
   }
 
   public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
-    method public java.lang.String getHostname();
+    method public String getHostname();
     method public java.util.List<java.net.InetAddress> getInetAddresses();
     method public int getTotalResolvedAddressCount();
     method public void writeToParcel(android.os.Parcel, int);
@@ -6930,7 +6964,7 @@
   public abstract class NetworkEvent implements android.os.Parcelable {
     method public int describeContents();
     method public long getId();
-    method public java.lang.String getPackageName();
+    method public String getPackageName();
     method public long getTimestamp();
     field public static final android.os.Parcelable.Creator<android.app.admin.NetworkEvent> CREATOR;
   }
@@ -6977,7 +7011,7 @@
 
   public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.Object getData();
+    method public Object getData();
     method public long getId();
     method public int getLogLevel();
     method public int getTag();
@@ -7037,13 +7071,13 @@
     method public android.content.ClipData getClipData();
     method public android.os.Bundle getExtras();
     method public android.content.Intent getIntent();
-    method public java.lang.String getStructuredData();
+    method public String getStructuredData();
     method public android.net.Uri getWebUri();
     method public boolean isAppProvidedIntent();
     method public boolean isAppProvidedWebUri();
     method public void setClipData(android.content.ClipData);
     method public void setIntent(android.content.Intent);
-    method public void setStructuredData(java.lang.String);
+    method public void setStructuredData(String);
     method public void setWebUri(android.net.Uri);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.assist.AssistContent> CREATOR;
@@ -7064,37 +7098,37 @@
 
   public static class AssistStructure.ViewNode {
     method public float getAlpha();
-    method public java.lang.String[] getAutofillHints();
-    method public android.view.autofill.AutofillId getAutofillId();
-    method public java.lang.CharSequence[] getAutofillOptions();
+    method @Nullable public String[] getAutofillHints();
+    method @Nullable public android.view.autofill.AutofillId getAutofillId();
+    method @Nullable public CharSequence[] getAutofillOptions();
     method public int getAutofillType();
-    method public android.view.autofill.AutofillValue getAutofillValue();
+    method @Nullable public android.view.autofill.AutofillValue getAutofillValue();
     method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
     method public int getChildCount();
-    method public java.lang.String getClassName();
-    method public java.lang.CharSequence getContentDescription();
+    method public String getClassName();
+    method public CharSequence getContentDescription();
     method public float getElevation();
     method public android.os.Bundle getExtras();
     method public int getHeight();
-    method public java.lang.String getHint();
-    method public android.view.ViewStructure.HtmlInfo getHtmlInfo();
+    method public String getHint();
+    method @Nullable public android.view.ViewStructure.HtmlInfo getHtmlInfo();
     method public int getId();
-    method public java.lang.String getIdEntry();
-    method public java.lang.String getIdPackage();
-    method public java.lang.String getIdType();
+    method public String getIdEntry();
+    method public String getIdPackage();
+    method public String getIdType();
     method public int getImportantForAutofill();
     method public int getInputType();
     method public int getLeft();
-    method public android.os.LocaleList getLocaleList();
+    method @Nullable public android.os.LocaleList getLocaleList();
     method public int getMaxTextEms();
     method public int getMaxTextLength();
     method public int getMinTextEms();
     method public int getScrollX();
     method public int getScrollY();
-    method public java.lang.CharSequence getText();
+    method public CharSequence getText();
     method public int getTextBackgroundColor();
     method public int getTextColor();
-    method public java.lang.String getTextIdEntry();
+    method @Nullable public String getTextIdEntry();
     method public int[] getTextLineBaselines();
     method public int[] getTextLineCharOffsets();
     method public int getTextSelectionEnd();
@@ -7104,8 +7138,8 @@
     method public int getTop();
     method public android.graphics.Matrix getTransformation();
     method public int getVisibility();
-    method public java.lang.String getWebDomain();
-    method public java.lang.String getWebScheme();
+    method @Nullable public String getWebDomain();
+    method @Nullable public String getWebScheme();
     method public int getWidth();
     method public boolean isAccessibilityFocused();
     method public boolean isActivated();
@@ -7132,7 +7166,7 @@
     method public int getHeight();
     method public int getLeft();
     method public android.app.assist.AssistStructure.ViewNode getRootViewNode();
-    method public java.lang.CharSequence getTitle();
+    method public CharSequence getTitle();
     method public int getTop();
     method public int getWidth();
   }
@@ -7161,21 +7195,21 @@
 
   public class BackupAgentHelper extends android.app.backup.BackupAgent {
     ctor public BackupAgentHelper();
-    method public void addHelper(java.lang.String, android.app.backup.BackupHelper);
+    method public void addHelper(String, android.app.backup.BackupHelper);
     method public void onBackup(android.os.ParcelFileDescriptor, android.app.backup.BackupDataOutput, android.os.ParcelFileDescriptor) throws java.io.IOException;
     method public void onRestore(android.app.backup.BackupDataInput, int, android.os.ParcelFileDescriptor) throws java.io.IOException;
   }
 
   public class BackupDataInput {
     method public int getDataSize();
-    method public java.lang.String getKey();
+    method public String getKey();
     method public int readEntityData(byte[], int, int) throws java.io.IOException;
     method public boolean readNextHeader() throws java.io.IOException;
     method public void skipEntityData() throws java.io.IOException;
   }
 
   public class BackupDataInputStream extends java.io.InputStream {
-    method public java.lang.String getKey();
+    method public String getKey();
     method public int read() throws java.io.IOException;
     method public int size();
   }
@@ -7184,26 +7218,27 @@
     method public long getQuota();
     method public int getTransportFlags();
     method public int writeEntityData(byte[], int) throws java.io.IOException;
-    method public int writeEntityHeader(java.lang.String, int) throws java.io.IOException;
+    method public int writeEntityHeader(String, int) throws java.io.IOException;
   }
 
-  public abstract interface BackupHelper {
-    method public abstract void performBackup(android.os.ParcelFileDescriptor, android.app.backup.BackupDataOutput, android.os.ParcelFileDescriptor);
-    method public abstract void restoreEntity(android.app.backup.BackupDataInputStream);
-    method public abstract void writeNewStateDescription(android.os.ParcelFileDescriptor);
+  public interface BackupHelper {
+    method public void performBackup(android.os.ParcelFileDescriptor, android.app.backup.BackupDataOutput, android.os.ParcelFileDescriptor);
+    method public void restoreEntity(android.app.backup.BackupDataInputStream);
+    method public void writeNewStateDescription(android.os.ParcelFileDescriptor);
   }
 
   public class BackupManager {
     ctor public BackupManager(android.content.Context);
     method public void dataChanged();
-    method public static void dataChanged(java.lang.String);
-    method public deprecated int requestRestore(android.app.backup.RestoreObserver);
+    method public static void dataChanged(String);
+    method @Deprecated public int requestRestore(android.app.backup.RestoreObserver);
   }
 
   public class FileBackupHelper implements android.app.backup.BackupHelper {
     ctor public FileBackupHelper(android.content.Context, java.lang.String...);
     method public void performBackup(android.os.ParcelFileDescriptor, android.app.backup.BackupDataOutput, android.os.ParcelFileDescriptor);
     method public void restoreEntity(android.app.backup.BackupDataInputStream);
+    method public void writeNewStateDescription(android.os.ParcelFileDescriptor);
   }
 
   public class FullBackupDataOutput {
@@ -7213,7 +7248,7 @@
 
   public abstract class RestoreObserver {
     ctor public RestoreObserver();
-    method public void onUpdate(int, java.lang.String);
+    method public void onUpdate(int, String);
     method public void restoreFinished(int);
     method public void restoreStarting(int);
   }
@@ -7222,6 +7257,7 @@
     ctor public SharedPreferencesBackupHelper(android.content.Context, java.lang.String...);
     method public void performBackup(android.os.ParcelFileDescriptor, android.app.backup.BackupDataOutput, android.os.ParcelFileDescriptor);
     method public void restoreEntity(android.app.backup.BackupDataInputStream);
+    method public void writeNewStateDescription(android.os.ParcelFileDescriptor);
   }
 
 }
@@ -7231,11 +7267,11 @@
   public class JobInfo implements android.os.Parcelable {
     method public int describeContents();
     method public int getBackoffPolicy();
-    method public android.content.ClipData getClipData();
+    method @Nullable public android.content.ClipData getClipData();
     method public int getClipGrantFlags();
     method public long getEstimatedNetworkDownloadBytes();
     method public long getEstimatedNetworkUploadBytes();
-    method public android.os.PersistableBundle getExtras();
+    method @NonNull public android.os.PersistableBundle getExtras();
     method public long getFlexMillis();
     method public int getId();
     method public long getInitialBackoffMillis();
@@ -7244,13 +7280,13 @@
     method public static final long getMinFlexMillis();
     method public long getMinLatencyMillis();
     method public static final long getMinPeriodMillis();
-    method public deprecated int getNetworkType();
-    method public android.net.NetworkRequest getRequiredNetwork();
-    method public android.content.ComponentName getService();
-    method public android.os.Bundle getTransientExtras();
+    method @Deprecated public int getNetworkType();
+    method @Nullable public android.net.NetworkRequest getRequiredNetwork();
+    method @NonNull public android.content.ComponentName getService();
+    method @NonNull public android.os.Bundle getTransientExtras();
     method public long getTriggerContentMaxDelay();
     method public long getTriggerContentUpdateDelay();
-    method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
+    method @Nullable public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
     method public boolean isImportantWhileForeground();
     method public boolean isPeriodic();
     method public boolean isPersisted();
@@ -7268,40 +7304,40 @@
     field public static final int NETWORK_BYTES_UNKNOWN = -1; // 0xffffffff
     field public static final int NETWORK_TYPE_ANY = 1; // 0x1
     field public static final int NETWORK_TYPE_CELLULAR = 4; // 0x4
-    field public static final deprecated int NETWORK_TYPE_METERED = 4; // 0x4
+    field @Deprecated public static final int NETWORK_TYPE_METERED = 4; // 0x4
     field public static final int NETWORK_TYPE_NONE = 0; // 0x0
     field public static final int NETWORK_TYPE_NOT_ROAMING = 3; // 0x3
     field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
   }
 
   public static final class JobInfo.Builder {
-    ctor public JobInfo.Builder(int, android.content.ComponentName);
-    method public android.app.job.JobInfo.Builder addTriggerContentUri(android.app.job.JobInfo.TriggerContentUri);
+    ctor public JobInfo.Builder(int, @NonNull android.content.ComponentName);
+    method public android.app.job.JobInfo.Builder addTriggerContentUri(@NonNull android.app.job.JobInfo.TriggerContentUri);
     method public android.app.job.JobInfo build();
     method public android.app.job.JobInfo.Builder setBackoffCriteria(long, int);
-    method public android.app.job.JobInfo.Builder setClipData(android.content.ClipData, int);
+    method public android.app.job.JobInfo.Builder setClipData(@Nullable android.content.ClipData, int);
     method public android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long, long);
-    method public android.app.job.JobInfo.Builder setExtras(android.os.PersistableBundle);
+    method public android.app.job.JobInfo.Builder setExtras(@NonNull android.os.PersistableBundle);
     method public android.app.job.JobInfo.Builder setImportantWhileForeground(boolean);
     method public android.app.job.JobInfo.Builder setMinimumLatency(long);
     method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
     method public android.app.job.JobInfo.Builder setPeriodic(long);
     method public android.app.job.JobInfo.Builder setPeriodic(long, long);
-    method public android.app.job.JobInfo.Builder setPersisted(boolean);
+    method @RequiresPermission(android.Manifest.permission.RECEIVE_BOOT_COMPLETED) public android.app.job.JobInfo.Builder setPersisted(boolean);
     method public android.app.job.JobInfo.Builder setPrefetch(boolean);
-    method public android.app.job.JobInfo.Builder setRequiredNetwork(android.net.NetworkRequest);
+    method public android.app.job.JobInfo.Builder setRequiredNetwork(@Nullable android.net.NetworkRequest);
     method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
     method public android.app.job.JobInfo.Builder setRequiresBatteryNotLow(boolean);
     method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
     method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
     method public android.app.job.JobInfo.Builder setRequiresStorageNotLow(boolean);
-    method public android.app.job.JobInfo.Builder setTransientExtras(android.os.Bundle);
+    method public android.app.job.JobInfo.Builder setTransientExtras(@NonNull android.os.Bundle);
     method public android.app.job.JobInfo.Builder setTriggerContentMaxDelay(long);
     method public android.app.job.JobInfo.Builder setTriggerContentUpdateDelay(long);
   }
 
   public static final class JobInfo.TriggerContentUri implements android.os.Parcelable {
-    ctor public JobInfo.TriggerContentUri(android.net.Uri, int);
+    ctor public JobInfo.TriggerContentUri(@NonNull android.net.Uri, int);
     method public int describeContents();
     method public int getFlags();
     method public android.net.Uri getUri();
@@ -7311,17 +7347,17 @@
   }
 
   public class JobParameters implements android.os.Parcelable {
-    method public void completeWork(android.app.job.JobWorkItem);
-    method public android.app.job.JobWorkItem dequeueWork();
+    method public void completeWork(@NonNull android.app.job.JobWorkItem);
+    method @Nullable public android.app.job.JobWorkItem dequeueWork();
     method public int describeContents();
-    method public android.content.ClipData getClipData();
+    method @Nullable public android.content.ClipData getClipData();
     method public int getClipGrantFlags();
-    method public android.os.PersistableBundle getExtras();
+    method @NonNull public android.os.PersistableBundle getExtras();
     method public int getJobId();
-    method public android.net.Network getNetwork();
-    method public android.os.Bundle getTransientExtras();
-    method public java.lang.String[] getTriggeredContentAuthorities();
-    method public android.net.Uri[] getTriggeredContentUris();
+    method @Nullable public android.net.Network getNetwork();
+    method @NonNull public android.os.Bundle getTransientExtras();
+    method @Nullable public String[] getTriggeredContentAuthorities();
+    method @Nullable public android.net.Uri[] getTriggeredContentUris();
     method public boolean isOverrideDeadlineExpired();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.job.JobParameters> CREATOR;
@@ -7331,10 +7367,10 @@
     ctor public JobScheduler();
     method public abstract void cancel(int);
     method public abstract void cancelAll();
-    method public abstract int enqueue(android.app.job.JobInfo, android.app.job.JobWorkItem);
-    method public abstract java.util.List<android.app.job.JobInfo> getAllPendingJobs();
-    method public abstract android.app.job.JobInfo getPendingJob(int);
-    method public abstract int schedule(android.app.job.JobInfo);
+    method public abstract int enqueue(@NonNull android.app.job.JobInfo, @NonNull android.app.job.JobWorkItem);
+    method @NonNull public abstract java.util.List<android.app.job.JobInfo> getAllPendingJobs();
+    method @Nullable public abstract android.app.job.JobInfo getPendingJob(int);
+    method public abstract int schedule(@NonNull android.app.job.JobInfo);
     field public static final int RESULT_FAILURE = 0; // 0x0
     field public static final int RESULT_SUCCESS = 1; // 0x1
   }
@@ -7345,7 +7381,7 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract boolean onStartJob(android.app.job.JobParameters);
     method public abstract boolean onStopJob(android.app.job.JobParameters);
-    field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE";
+    field public static final String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE";
   }
 
   public abstract class JobServiceEngine {
@@ -7373,14 +7409,16 @@
 package android.app.role {
 
   public final class RoleManager {
-    method public android.content.Intent createRequestRoleIntent(java.lang.String);
-    method public boolean isRoleAvailable(java.lang.String);
-    method public boolean isRoleHeld(java.lang.String);
-    field public static final java.lang.String ROLE_BROWSER = "android.app.role.BROWSER";
-    field public static final java.lang.String ROLE_DIALER = "android.app.role.DIALER";
-    field public static final java.lang.String ROLE_GALLERY = "android.app.role.GALLERY";
-    field public static final java.lang.String ROLE_MUSIC = "android.app.role.MUSIC";
-    field public static final java.lang.String ROLE_SMS = "android.app.role.SMS";
+    method @NonNull public android.content.Intent createRequestRoleIntent(@NonNull String);
+    method public boolean isRoleAvailable(@NonNull String);
+    method public boolean isRoleHeld(@NonNull String);
+    field public static final String ROLE_BROWSER = "android.app.role.BROWSER";
+    field public static final String ROLE_DIALER = "android.app.role.DIALER";
+    field public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
+    field public static final String ROLE_GALLERY = "android.app.role.GALLERY";
+    field public static final String ROLE_HOME = "android.app.role.HOME";
+    field public static final String ROLE_MUSIC = "android.app.role.MUSIC";
+    field public static final String ROLE_SMS = "android.app.role.SMS";
   }
 
 }
@@ -7392,55 +7430,55 @@
     method public int describeContents();
     method public java.util.List<java.lang.String> getHints();
     method public java.util.List<android.app.slice.SliceItem> getItems();
-    method public android.app.slice.SliceSpec getSpec();
+    method @Nullable public android.app.slice.SliceSpec getSpec();
     method public android.net.Uri getUri();
     method public boolean isCallerNeeded();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.slice.Slice> CREATOR;
-    field public static final java.lang.String EXTRA_RANGE_VALUE = "android.app.slice.extra.RANGE_VALUE";
-    field public static final java.lang.String EXTRA_TOGGLE_STATE = "android.app.slice.extra.TOGGLE_STATE";
-    field public static final java.lang.String HINT_ACTIONS = "actions";
-    field public static final java.lang.String HINT_ERROR = "error";
-    field public static final java.lang.String HINT_HORIZONTAL = "horizontal";
-    field public static final java.lang.String HINT_KEYWORDS = "keywords";
-    field public static final java.lang.String HINT_LARGE = "large";
-    field public static final java.lang.String HINT_LAST_UPDATED = "last_updated";
-    field public static final java.lang.String HINT_LIST = "list";
-    field public static final java.lang.String HINT_LIST_ITEM = "list_item";
-    field public static final java.lang.String HINT_NO_TINT = "no_tint";
-    field public static final java.lang.String HINT_PARTIAL = "partial";
-    field public static final java.lang.String HINT_PERMISSION_REQUEST = "permission_request";
-    field public static final java.lang.String HINT_SEE_MORE = "see_more";
-    field public static final java.lang.String HINT_SELECTED = "selected";
-    field public static final java.lang.String HINT_SHORTCUT = "shortcut";
-    field public static final java.lang.String HINT_SUMMARY = "summary";
-    field public static final java.lang.String HINT_TITLE = "title";
-    field public static final java.lang.String HINT_TTL = "ttl";
-    field public static final java.lang.String SUBTYPE_COLOR = "color";
-    field public static final java.lang.String SUBTYPE_CONTENT_DESCRIPTION = "content_description";
-    field public static final java.lang.String SUBTYPE_LAYOUT_DIRECTION = "layout_direction";
-    field public static final java.lang.String SUBTYPE_MAX = "max";
-    field public static final java.lang.String SUBTYPE_MESSAGE = "message";
-    field public static final java.lang.String SUBTYPE_MILLIS = "millis";
-    field public static final java.lang.String SUBTYPE_PRIORITY = "priority";
-    field public static final java.lang.String SUBTYPE_RANGE = "range";
-    field public static final java.lang.String SUBTYPE_SOURCE = "source";
-    field public static final java.lang.String SUBTYPE_TOGGLE = "toggle";
-    field public static final java.lang.String SUBTYPE_VALUE = "value";
+    field public static final String EXTRA_RANGE_VALUE = "android.app.slice.extra.RANGE_VALUE";
+    field public static final String EXTRA_TOGGLE_STATE = "android.app.slice.extra.TOGGLE_STATE";
+    field public static final String HINT_ACTIONS = "actions";
+    field public static final String HINT_ERROR = "error";
+    field public static final String HINT_HORIZONTAL = "horizontal";
+    field public static final String HINT_KEYWORDS = "keywords";
+    field public static final String HINT_LARGE = "large";
+    field public static final String HINT_LAST_UPDATED = "last_updated";
+    field public static final String HINT_LIST = "list";
+    field public static final String HINT_LIST_ITEM = "list_item";
+    field public static final String HINT_NO_TINT = "no_tint";
+    field public static final String HINT_PARTIAL = "partial";
+    field public static final String HINT_PERMISSION_REQUEST = "permission_request";
+    field public static final String HINT_SEE_MORE = "see_more";
+    field public static final String HINT_SELECTED = "selected";
+    field public static final String HINT_SHORTCUT = "shortcut";
+    field public static final String HINT_SUMMARY = "summary";
+    field public static final String HINT_TITLE = "title";
+    field public static final String HINT_TTL = "ttl";
+    field public static final String SUBTYPE_COLOR = "color";
+    field public static final String SUBTYPE_CONTENT_DESCRIPTION = "content_description";
+    field public static final String SUBTYPE_LAYOUT_DIRECTION = "layout_direction";
+    field public static final String SUBTYPE_MAX = "max";
+    field public static final String SUBTYPE_MESSAGE = "message";
+    field public static final String SUBTYPE_MILLIS = "millis";
+    field public static final String SUBTYPE_PRIORITY = "priority";
+    field public static final String SUBTYPE_RANGE = "range";
+    field public static final String SUBTYPE_SOURCE = "source";
+    field public static final String SUBTYPE_TOGGLE = "toggle";
+    field public static final String SUBTYPE_VALUE = "value";
   }
 
   public static class Slice.Builder {
-    ctor public Slice.Builder(android.net.Uri, android.app.slice.SliceSpec);
-    ctor public Slice.Builder(android.app.slice.Slice.Builder);
-    method public android.app.slice.Slice.Builder addAction(android.app.PendingIntent, android.app.slice.Slice, java.lang.String);
-    method public android.app.slice.Slice.Builder addBundle(android.os.Bundle, java.lang.String, java.util.List<java.lang.String>);
+    ctor public Slice.Builder(@NonNull android.net.Uri, android.app.slice.SliceSpec);
+    ctor public Slice.Builder(@NonNull android.app.slice.Slice.Builder);
+    method public android.app.slice.Slice.Builder addAction(@NonNull android.app.PendingIntent, @NonNull android.app.slice.Slice, @Nullable String);
+    method public android.app.slice.Slice.Builder addBundle(android.os.Bundle, @Nullable String, java.util.List<java.lang.String>);
     method public android.app.slice.Slice.Builder addHints(java.util.List<java.lang.String>);
-    method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.lang.String, java.util.List<java.lang.String>);
-    method public android.app.slice.Slice.Builder addInt(int, java.lang.String, java.util.List<java.lang.String>);
-    method public android.app.slice.Slice.Builder addLong(long, java.lang.String, java.util.List<java.lang.String>);
-    method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.lang.String, java.util.List<java.lang.String>);
-    method public android.app.slice.Slice.Builder addSubSlice(android.app.slice.Slice, java.lang.String);
-    method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.lang.String, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, @Nullable String, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addInt(int, @Nullable String, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addLong(long, @Nullable String, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, @Nullable String, java.util.List<java.lang.String>);
+    method public android.app.slice.Slice.Builder addSubSlice(@NonNull android.app.slice.Slice, @Nullable String);
+    method public android.app.slice.Slice.Builder addText(CharSequence, @Nullable String, java.util.List<java.lang.String>);
     method public android.app.slice.Slice build();
     method public android.app.slice.Slice.Builder setCallerNeeded(boolean);
   }
@@ -7449,76 +7487,76 @@
     method public int describeContents();
     method public android.app.PendingIntent getAction();
     method public android.os.Bundle getBundle();
-    method public java.lang.String getFormat();
-    method public java.util.List<java.lang.String> getHints();
+    method public String getFormat();
+    method @NonNull public java.util.List<java.lang.String> getHints();
     method public android.graphics.drawable.Icon getIcon();
     method public int getInt();
     method public long getLong();
     method public android.app.RemoteInput getRemoteInput();
     method public android.app.slice.Slice getSlice();
-    method public java.lang.String getSubType();
-    method public java.lang.CharSequence getText();
-    method public boolean hasHint(java.lang.String);
+    method public String getSubType();
+    method public CharSequence getText();
+    method public boolean hasHint(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.slice.SliceItem> CREATOR;
-    field public static final java.lang.String FORMAT_ACTION = "action";
-    field public static final java.lang.String FORMAT_BUNDLE = "bundle";
-    field public static final java.lang.String FORMAT_IMAGE = "image";
-    field public static final java.lang.String FORMAT_INT = "int";
-    field public static final java.lang.String FORMAT_LONG = "long";
-    field public static final java.lang.String FORMAT_REMOTE_INPUT = "input";
-    field public static final java.lang.String FORMAT_SLICE = "slice";
-    field public static final java.lang.String FORMAT_TEXT = "text";
+    field public static final String FORMAT_ACTION = "action";
+    field public static final String FORMAT_BUNDLE = "bundle";
+    field public static final String FORMAT_IMAGE = "image";
+    field public static final String FORMAT_INT = "int";
+    field public static final String FORMAT_LONG = "long";
+    field public static final String FORMAT_REMOTE_INPUT = "input";
+    field public static final String FORMAT_SLICE = "slice";
+    field public static final String FORMAT_TEXT = "text";
   }
 
   public class SliceManager {
-    method public android.app.slice.Slice bindSlice(android.net.Uri, java.util.Set<android.app.slice.SliceSpec>);
-    method public android.app.slice.Slice bindSlice(android.content.Intent, java.util.Set<android.app.slice.SliceSpec>);
-    method public int checkSlicePermission(android.net.Uri, int, int);
-    method public java.util.List<android.net.Uri> getPinnedSlices();
-    method public java.util.Set<android.app.slice.SliceSpec> getPinnedSpecs(android.net.Uri);
-    method public java.util.Collection<android.net.Uri> getSliceDescendants(android.net.Uri);
-    method public void grantSlicePermission(java.lang.String, android.net.Uri);
-    method public android.net.Uri mapIntentToUri(android.content.Intent);
-    method public void pinSlice(android.net.Uri, java.util.Set<android.app.slice.SliceSpec>);
-    method public void revokeSlicePermission(java.lang.String, android.net.Uri);
-    method public void unpinSlice(android.net.Uri);
-    field public static final java.lang.String CATEGORY_SLICE = "android.app.slice.category.SLICE";
-    field public static final java.lang.String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
+    method @Nullable public android.app.slice.Slice bindSlice(@NonNull android.net.Uri, @NonNull java.util.Set<android.app.slice.SliceSpec>);
+    method @Nullable public android.app.slice.Slice bindSlice(@NonNull android.content.Intent, @NonNull java.util.Set<android.app.slice.SliceSpec>);
+    method public int checkSlicePermission(@NonNull android.net.Uri, int, int);
+    method @NonNull public java.util.List<android.net.Uri> getPinnedSlices();
+    method @NonNull public java.util.Set<android.app.slice.SliceSpec> getPinnedSpecs(android.net.Uri);
+    method @WorkerThread @NonNull public java.util.Collection<android.net.Uri> getSliceDescendants(@NonNull android.net.Uri);
+    method public void grantSlicePermission(@NonNull String, @NonNull android.net.Uri);
+    method @Nullable public android.net.Uri mapIntentToUri(@NonNull android.content.Intent);
+    method public void pinSlice(@NonNull android.net.Uri, @NonNull java.util.Set<android.app.slice.SliceSpec>);
+    method public void revokeSlicePermission(@NonNull String, @NonNull android.net.Uri);
+    method public void unpinSlice(@NonNull android.net.Uri);
+    field public static final String CATEGORY_SLICE = "android.app.slice.category.SLICE";
+    field public static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
   }
 
   public class SliceMetrics {
-    ctor public SliceMetrics(android.content.Context, android.net.Uri);
+    ctor public SliceMetrics(@NonNull android.content.Context, @NonNull android.net.Uri);
     method public void logHidden();
-    method public void logTouch(int, android.net.Uri);
+    method public void logTouch(int, @NonNull android.net.Uri);
     method public void logVisible();
   }
 
   public abstract class SliceProvider extends android.content.ContentProvider {
-    ctor public SliceProvider(java.lang.String...);
+    ctor public SliceProvider(@NonNull java.lang.String...);
     ctor public SliceProvider();
-    method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
-    method public final java.lang.String getType(android.net.Uri);
+    method public final int delete(android.net.Uri, String, String[]);
+    method public final String getType(android.net.Uri);
     method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
     method public android.app.slice.Slice onBindSlice(android.net.Uri, java.util.Set<android.app.slice.SliceSpec>);
-    method public android.app.PendingIntent onCreatePermissionRequest(android.net.Uri);
-    method public java.util.Collection<android.net.Uri> onGetSliceDescendants(android.net.Uri);
-    method public android.net.Uri onMapIntentToUri(android.content.Intent);
+    method @NonNull public android.app.PendingIntent onCreatePermissionRequest(android.net.Uri);
+    method @NonNull public java.util.Collection<android.net.Uri> onGetSliceDescendants(@NonNull android.net.Uri);
+    method @NonNull public android.net.Uri onMapIntentToUri(android.content.Intent);
     method public void onSlicePinned(android.net.Uri);
     method public void onSliceUnpinned(android.net.Uri);
-    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
-    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
-    method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
-    field public static final java.lang.String SLICE_TYPE = "vnd.android.slice";
+    method public final android.database.Cursor query(android.net.Uri, String[], String, String[], String);
+    method public final android.database.Cursor query(android.net.Uri, String[], String, String[], String, android.os.CancellationSignal);
+    method public final android.database.Cursor query(android.net.Uri, String[], android.os.Bundle, android.os.CancellationSignal);
+    method public final int update(android.net.Uri, android.content.ContentValues, String, String[]);
+    field public static final String SLICE_TYPE = "vnd.android.slice";
   }
 
   public final class SliceSpec implements android.os.Parcelable {
-    ctor public SliceSpec(java.lang.String, int);
-    method public boolean canRender(android.app.slice.SliceSpec);
+    ctor public SliceSpec(@NonNull String, int);
+    method public boolean canRender(@NonNull android.app.slice.SliceSpec);
     method public int describeContents();
     method public int getRevision();
-    method public java.lang.String getType();
+    method public String getType();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.slice.SliceSpec> CREATOR;
   }
@@ -7604,21 +7642,21 @@
   }
 
   public class NetworkStatsManager {
-    method public android.app.usage.NetworkStats queryDetails(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method public android.app.usage.NetworkStats queryDetailsForUid(int, java.lang.String, long, long, int) throws java.lang.SecurityException;
-    method public android.app.usage.NetworkStats queryDetailsForUidTag(int, java.lang.String, long, long, int, int) throws java.lang.SecurityException;
-    method public android.app.usage.NetworkStats queryDetailsForUidTagState(int, java.lang.String, long, long, int, int, int) throws java.lang.SecurityException;
-    method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method public void registerUsageCallback(int, java.lang.String, long, android.app.usage.NetworkStatsManager.UsageCallback);
-    method public void registerUsageCallback(int, java.lang.String, long, android.app.usage.NetworkStatsManager.UsageCallback, android.os.Handler);
+    method public android.app.usage.NetworkStats queryDetails(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats queryDetailsForUid(int, String, long, long, int) throws java.lang.SecurityException;
+    method public android.app.usage.NetworkStats queryDetailsForUidTag(int, String, long, long, int, int) throws java.lang.SecurityException;
+    method public android.app.usage.NetworkStats queryDetailsForUidTagState(int, String, long, long, int, int, int) throws java.lang.SecurityException;
+    method public android.app.usage.NetworkStats querySummary(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+    method public void registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback);
+    method public void registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback, @Nullable android.os.Handler);
     method public void unregisterUsageCallback(android.app.usage.NetworkStatsManager.UsageCallback);
   }
 
-  public static abstract class NetworkStatsManager.UsageCallback {
+  public abstract static class NetworkStatsManager.UsageCallback {
     ctor public NetworkStatsManager.UsageCallback();
-    method public abstract void onThresholdReached(int, java.lang.String);
+    method public abstract void onThresholdReached(int, String);
   }
 
   public final class StorageStats implements android.os.Parcelable {
@@ -7631,12 +7669,12 @@
   }
 
   public class StorageStatsManager {
-    method public long getFreeBytes(java.util.UUID) throws java.io.IOException;
-    method public long getTotalBytes(java.util.UUID) throws java.io.IOException;
-    method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException;
-    method public android.app.usage.StorageStats queryStatsForPackage(java.util.UUID, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
-    method public android.app.usage.StorageStats queryStatsForUid(java.util.UUID, int) throws java.io.IOException;
-    method public android.app.usage.StorageStats queryStatsForUser(java.util.UUID, android.os.UserHandle) throws java.io.IOException;
+    method @WorkerThread public long getFreeBytes(@NonNull java.util.UUID) throws java.io.IOException;
+    method @WorkerThread public long getTotalBytes(@NonNull java.util.UUID) throws java.io.IOException;
+    method @WorkerThread @NonNull public android.app.usage.ExternalStorageStats queryExternalStatsForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle) throws java.io.IOException;
+    method @WorkerThread @NonNull public android.app.usage.StorageStats queryStatsForPackage(@NonNull java.util.UUID, @NonNull String, @NonNull android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
+    method @WorkerThread @NonNull public android.app.usage.StorageStats queryStatsForUid(@NonNull java.util.UUID, int) throws java.io.IOException;
+    method @WorkerThread @NonNull public android.app.usage.StorageStats queryStatsForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle) throws java.io.IOException;
   }
 
   public final class UsageEvents implements android.os.Parcelable {
@@ -7650,22 +7688,23 @@
   public static final class UsageEvents.Event {
     ctor public UsageEvents.Event();
     method public int getAppStandbyBucket();
-    method public java.lang.String getClassName();
+    method public String getClassName();
     method public android.content.res.Configuration getConfiguration();
     method public int getEventType();
-    method public java.lang.String getPackageName();
-    method public java.lang.String getShortcutId();
+    method public String getPackageName();
+    method public String getShortcutId();
     method public long getTimeStamp();
     field public static final int ACTIVITY_PAUSED = 2; // 0x2
     field public static final int ACTIVITY_RESUMED = 1; // 0x1
     field public static final int ACTIVITY_STOPPED = 23; // 0x17
     field public static final int CONFIGURATION_CHANGE = 5; // 0x5
+    field public static final int DEVICE_SHUTDOWN = 26; // 0x1a
     field public static final int FOREGROUND_SERVICE_START = 19; // 0x13
     field public static final int FOREGROUND_SERVICE_STOP = 20; // 0x14
     field public static final int KEYGUARD_HIDDEN = 18; // 0x12
     field public static final int KEYGUARD_SHOWN = 17; // 0x11
-    field public static final deprecated int MOVE_TO_BACKGROUND = 2; // 0x2
-    field public static final deprecated int MOVE_TO_FOREGROUND = 1; // 0x1
+    field @Deprecated public static final int MOVE_TO_BACKGROUND = 2; // 0x2
+    field @Deprecated public static final int MOVE_TO_FOREGROUND = 1; // 0x1
     field public static final int NONE = 0; // 0x0
     field public static final int SCREEN_INTERACTIVE = 15; // 0xf
     field public static final int SCREEN_NON_INTERACTIVE = 16; // 0x10
@@ -7683,7 +7722,7 @@
     method public long getLastTimeStamp();
     method public long getLastTimeUsed();
     method public long getLastTimeVisible();
-    method public java.lang.String getPackageName();
+    method public String getPackageName();
     method public long getTotalTimeForegroundServiceUsed();
     method public long getTotalTimeInForeground();
     method public long getTotalTimeVisible();
@@ -7693,8 +7732,8 @@
 
   public final class UsageStatsManager {
     method public int getAppStandbyBucket();
-    method public boolean isAppInactive(java.lang.String);
-    method public java.util.Map<java.lang.String, android.app.usage.UsageStats> queryAndAggregateUsageStats(long, long);
+    method public boolean isAppInactive(String);
+    method public java.util.Map<java.lang.String,android.app.usage.UsageStats> queryAndAggregateUsageStats(long, long);
     method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long);
     method public java.util.List<android.app.usage.EventStats> queryEventStats(int, long, long);
     method public android.app.usage.UsageEvents queryEvents(long, long);
@@ -7727,7 +7766,7 @@
     method protected android.appwidget.AppWidgetHostView onCreateView(android.content.Context, int, android.appwidget.AppWidgetProviderInfo);
     method protected void onProviderChanged(int, android.appwidget.AppWidgetProviderInfo);
     method protected void onProvidersChanged();
-    method public final void startAppWidgetConfigureActivityForResult(android.app.Activity, int, int, int, android.os.Bundle);
+    method public final void startAppWidgetConfigureActivityForResult(@NonNull android.app.Activity, int, int, int, @Nullable android.os.Bundle);
     method public void startListening();
     method public void stopListening();
   }
@@ -7757,47 +7796,47 @@
     method public android.appwidget.AppWidgetProviderInfo getAppWidgetInfo(int);
     method public android.os.Bundle getAppWidgetOptions(int);
     method public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProviders();
-    method public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProvidersForPackage(java.lang.String, android.os.UserHandle);
-    method public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProvidersForProfile(android.os.UserHandle);
+    method @NonNull public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProvidersForPackage(@NonNull String, @Nullable android.os.UserHandle);
+    method @NonNull public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProvidersForProfile(@Nullable android.os.UserHandle);
     method public static android.appwidget.AppWidgetManager getInstance(android.content.Context);
     method public boolean isRequestPinAppWidgetSupported();
     method public void notifyAppWidgetViewDataChanged(int[], int);
     method public void notifyAppWidgetViewDataChanged(int, int);
     method public void partiallyUpdateAppWidget(int[], android.widget.RemoteViews);
     method public void partiallyUpdateAppWidget(int, android.widget.RemoteViews);
-    method public boolean requestPinAppWidget(android.content.ComponentName, android.os.Bundle, android.app.PendingIntent);
+    method public boolean requestPinAppWidget(@NonNull android.content.ComponentName, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent);
     method public void updateAppWidget(int[], android.widget.RemoteViews);
     method public void updateAppWidget(int, android.widget.RemoteViews);
     method public void updateAppWidget(android.content.ComponentName, android.widget.RemoteViews);
     method public void updateAppWidgetOptions(int, android.os.Bundle);
-    method public void updateAppWidgetProviderInfo(android.content.ComponentName, java.lang.String);
-    field public static final java.lang.String ACTION_APPWIDGET_BIND = "android.appwidget.action.APPWIDGET_BIND";
-    field public static final java.lang.String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
-    field public static final java.lang.String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
-    field public static final java.lang.String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
-    field public static final java.lang.String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
-    field public static final java.lang.String ACTION_APPWIDGET_HOST_RESTORED = "android.appwidget.action.APPWIDGET_HOST_RESTORED";
-    field public static final java.lang.String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS";
-    field public static final java.lang.String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
-    field public static final java.lang.String ACTION_APPWIDGET_RESTORED = "android.appwidget.action.APPWIDGET_RESTORED";
-    field public static final java.lang.String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
-    field public static final java.lang.String EXTRA_APPWIDGET_ID = "appWidgetId";
-    field public static final java.lang.String EXTRA_APPWIDGET_IDS = "appWidgetIds";
-    field public static final java.lang.String EXTRA_APPWIDGET_OLD_IDS = "appWidgetOldIds";
-    field public static final java.lang.String EXTRA_APPWIDGET_OPTIONS = "appWidgetOptions";
-    field public static final java.lang.String EXTRA_APPWIDGET_PREVIEW = "appWidgetPreview";
-    field public static final java.lang.String EXTRA_APPWIDGET_PROVIDER = "appWidgetProvider";
-    field public static final java.lang.String EXTRA_APPWIDGET_PROVIDER_PROFILE = "appWidgetProviderProfile";
-    field public static final java.lang.String EXTRA_CUSTOM_EXTRAS = "customExtras";
-    field public static final java.lang.String EXTRA_CUSTOM_INFO = "customInfo";
-    field public static final java.lang.String EXTRA_HOST_ID = "hostId";
+    method public void updateAppWidgetProviderInfo(android.content.ComponentName, @Nullable String);
+    field public static final String ACTION_APPWIDGET_BIND = "android.appwidget.action.APPWIDGET_BIND";
+    field public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
+    field public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
+    field public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
+    field public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
+    field public static final String ACTION_APPWIDGET_HOST_RESTORED = "android.appwidget.action.APPWIDGET_HOST_RESTORED";
+    field public static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS";
+    field public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
+    field public static final String ACTION_APPWIDGET_RESTORED = "android.appwidget.action.APPWIDGET_RESTORED";
+    field public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
+    field public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
+    field public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds";
+    field public static final String EXTRA_APPWIDGET_OLD_IDS = "appWidgetOldIds";
+    field public static final String EXTRA_APPWIDGET_OPTIONS = "appWidgetOptions";
+    field public static final String EXTRA_APPWIDGET_PREVIEW = "appWidgetPreview";
+    field public static final String EXTRA_APPWIDGET_PROVIDER = "appWidgetProvider";
+    field public static final String EXTRA_APPWIDGET_PROVIDER_PROFILE = "appWidgetProviderProfile";
+    field public static final String EXTRA_CUSTOM_EXTRAS = "customExtras";
+    field public static final String EXTRA_CUSTOM_INFO = "customInfo";
+    field public static final String EXTRA_HOST_ID = "hostId";
     field public static final int INVALID_APPWIDGET_ID = 0; // 0x0
-    field public static final java.lang.String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
-    field public static final java.lang.String OPTION_APPWIDGET_HOST_CATEGORY = "appWidgetCategory";
-    field public static final java.lang.String OPTION_APPWIDGET_MAX_HEIGHT = "appWidgetMaxHeight";
-    field public static final java.lang.String OPTION_APPWIDGET_MAX_WIDTH = "appWidgetMaxWidth";
-    field public static final java.lang.String OPTION_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight";
-    field public static final java.lang.String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth";
+    field public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
+    field public static final String OPTION_APPWIDGET_HOST_CATEGORY = "appWidgetCategory";
+    field public static final String OPTION_APPWIDGET_MAX_HEIGHT = "appWidgetMaxHeight";
+    field public static final String OPTION_APPWIDGET_MAX_WIDTH = "appWidgetMaxWidth";
+    field public static final String OPTION_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight";
+    field public static final String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth";
   }
 
   public class AppWidgetProvider extends android.content.BroadcastReceiver {
@@ -7817,9 +7856,9 @@
     method public android.appwidget.AppWidgetProviderInfo clone();
     method public int describeContents();
     method public final android.os.UserHandle getProfile();
-    method public final android.graphics.drawable.Drawable loadIcon(android.content.Context, int);
-    method public final java.lang.String loadLabel(android.content.pm.PackageManager);
-    method public final android.graphics.drawable.Drawable loadPreviewImage(android.content.Context, int);
+    method public final android.graphics.drawable.Drawable loadIcon(@NonNull android.content.Context, int);
+    method public final String loadLabel(android.content.pm.PackageManager);
+    method public final android.graphics.drawable.Drawable loadPreviewImage(@NonNull android.content.Context, int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.appwidget.AppWidgetProviderInfo> CREATOR;
     field public static final int RESIZE_BOTH = 3; // 0x3
@@ -7836,7 +7875,7 @@
     field public int icon;
     field public int initialKeyguardLayout;
     field public int initialLayout;
-    field public deprecated java.lang.String label;
+    field @Deprecated public String label;
     field public int minHeight;
     field public int minResizeHeight;
     field public int minResizeWidth;
@@ -7859,33 +7898,33 @@
     method public int getConnectionState(android.bluetooth.BluetoothDevice);
     method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
     method public boolean isA2dpPlaying(android.bluetooth.BluetoothDevice);
-    field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
-    field public static final java.lang.String ACTION_PLAYING_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
+    field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
+    field public static final String ACTION_PLAYING_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
     field public static final int STATE_NOT_PLAYING = 11; // 0xb
     field public static final int STATE_PLAYING = 10; // 0xa
   }
 
   public final class BluetoothAdapter {
-    method public boolean cancelDiscovery();
-    method public static boolean checkBluetoothAddress(java.lang.String);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelDiscovery();
+    method public static boolean checkBluetoothAddress(String);
     method public void closeProfileProxy(int, android.bluetooth.BluetoothProfile);
-    method public boolean disable();
-    method public boolean enable();
-    method public java.lang.String getAddress();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disable();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enable();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public String getAddress();
     method public android.bluetooth.le.BluetoothLeAdvertiser getBluetoothLeAdvertiser();
     method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
-    method public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
-    method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
+    method public static android.bluetooth.BluetoothAdapter getDefaultAdapter();
     method public int getLeMaximumAdvertisingDataLength();
-    method public java.lang.String getName();
-    method public int getProfileConnectionState(int);
+    method public String getName();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getProfileConnectionState(int);
     method public boolean getProfileProxy(android.content.Context, android.bluetooth.BluetoothProfile.ServiceListener, int);
-    method public android.bluetooth.BluetoothDevice getRemoteDevice(java.lang.String);
+    method public android.bluetooth.BluetoothDevice getRemoteDevice(String);
     method public android.bluetooth.BluetoothDevice getRemoteDevice(byte[]);
-    method public int getScanMode();
-    method public int getState();
-    method public boolean isDiscovering();
-    method public boolean isEnabled();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getScanMode();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getState();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isDiscovering();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEnabled();
     method public boolean isLe2MPhySupported();
     method public boolean isLeCodedPhySupported();
     method public boolean isLeExtendedAdvertisingSupported();
@@ -7893,32 +7932,32 @@
     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();
-    method public deprecated boolean startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
-    method public deprecated boolean startLeScan(java.util.UUID[], android.bluetooth.BluetoothAdapter.LeScanCallback);
-    method public deprecated void stopLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
-    field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
-    field public static final java.lang.String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
-    field public static final java.lang.String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
-    field public static final java.lang.String ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
-    field public static final java.lang.String ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
-    field public static final java.lang.String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
-    field public static final java.lang.String ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
-    field public static final java.lang.String ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED";
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setName(String);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startDiscovery();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startLeScan(java.util.UUID[], android.bluetooth.BluetoothAdapter.LeScanCallback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void stopLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
+    field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
+    field public static final String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
+    field public static final String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
+    field public static final String ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
+    field public static final String ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
+    field public static final String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
+    field public static final String ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
+    field public static final String ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED";
     field public static final int ERROR = -2147483648; // 0x80000000
-    field public static final java.lang.String EXTRA_CONNECTION_STATE = "android.bluetooth.adapter.extra.CONNECTION_STATE";
-    field public static final java.lang.String EXTRA_DISCOVERABLE_DURATION = "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION";
-    field public static final java.lang.String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME";
-    field public static final java.lang.String EXTRA_PREVIOUS_CONNECTION_STATE = "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE";
-    field public static final java.lang.String EXTRA_PREVIOUS_SCAN_MODE = "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
-    field public static final java.lang.String EXTRA_PREVIOUS_STATE = "android.bluetooth.adapter.extra.PREVIOUS_STATE";
-    field public static final java.lang.String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE";
-    field public static final java.lang.String EXTRA_STATE = "android.bluetooth.adapter.extra.STATE";
+    field public static final String EXTRA_CONNECTION_STATE = "android.bluetooth.adapter.extra.CONNECTION_STATE";
+    field public static final String EXTRA_DISCOVERABLE_DURATION = "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION";
+    field public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME";
+    field public static final String EXTRA_PREVIOUS_CONNECTION_STATE = "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE";
+    field public static final String EXTRA_PREVIOUS_SCAN_MODE = "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
+    field public static final String EXTRA_PREVIOUS_STATE = "android.bluetooth.adapter.extra.PREVIOUS_STATE";
+    field public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE";
+    field public static final String EXTRA_STATE = "android.bluetooth.adapter.extra.STATE";
     field public static final int SCAN_MODE_CONNECTABLE = 21; // 0x15
     field public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23; // 0x17
     field public static final int SCAN_MODE_NONE = 20; // 0x14
@@ -7932,8 +7971,8 @@
     field public static final int STATE_TURNING_ON = 11; // 0xb
   }
 
-  public static abstract interface BluetoothAdapter.LeScanCallback {
-    method public abstract void onLeScan(android.bluetooth.BluetoothDevice, int, byte[]);
+  public static interface BluetoothAdapter.LeScanCallback {
+    method public void onLeScan(android.bluetooth.BluetoothDevice, int, byte[]);
   }
 
   public class BluetoothAssignedNumbers {
@@ -8262,31 +8301,31 @@
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
     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 @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean createBond();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public int describeContents();
-    method public boolean fetchUuidsWithSdp();
-    method public java.lang.String getAddress();
-    method public android.bluetooth.BluetoothClass getBluetoothClass();
-    method public int getBondState();
-    method public java.lang.String getName();
-    method public int getType();
-    method public android.os.ParcelUuid[] getUuids();
-    method public boolean setPairingConfirmation(boolean);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean fetchUuidsWithSdp();
+    method public String getAddress();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothClass getBluetoothClass();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getBondState();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public String getName();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getType();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.os.ParcelUuid[] getUuids();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPairingConfirmation(boolean);
     method public boolean setPin(byte[]);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final java.lang.String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";
-    field public static final java.lang.String ACTION_ACL_DISCONNECTED = "android.bluetooth.device.action.ACL_DISCONNECTED";
-    field public static final java.lang.String ACTION_ACL_DISCONNECT_REQUESTED = "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
-    field public static final java.lang.String ACTION_BOND_STATE_CHANGED = "android.bluetooth.device.action.BOND_STATE_CHANGED";
-    field public static final java.lang.String ACTION_CLASS_CHANGED = "android.bluetooth.device.action.CLASS_CHANGED";
-    field public static final java.lang.String ACTION_FOUND = "android.bluetooth.device.action.FOUND";
-    field public static final java.lang.String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
-    field public static final java.lang.String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
-    field public static final java.lang.String ACTION_UUID = "android.bluetooth.device.action.UUID";
+    field public static final String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";
+    field public static final String ACTION_ACL_DISCONNECTED = "android.bluetooth.device.action.ACL_DISCONNECTED";
+    field public static final String ACTION_ACL_DISCONNECT_REQUESTED = "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
+    field public static final String ACTION_BOND_STATE_CHANGED = "android.bluetooth.device.action.BOND_STATE_CHANGED";
+    field public static final String ACTION_CLASS_CHANGED = "android.bluetooth.device.action.CLASS_CHANGED";
+    field public static final String ACTION_FOUND = "android.bluetooth.device.action.FOUND";
+    field public static final String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
+    field public static final String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
+    field public static final String ACTION_UUID = "android.bluetooth.device.action.UUID";
     field public static final int BOND_BONDED = 12; // 0xc
     field public static final int BOND_BONDING = 11; // 0xb
     field public static final int BOND_NONE = 10; // 0xa
@@ -8296,15 +8335,15 @@
     field public static final int DEVICE_TYPE_LE = 2; // 0x2
     field public static final int DEVICE_TYPE_UNKNOWN = 0; // 0x0
     field public static final int ERROR = -2147483648; // 0x80000000
-    field public static final java.lang.String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
-    field public static final java.lang.String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
-    field public static final java.lang.String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
-    field public static final java.lang.String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
-    field public static final java.lang.String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
-    field public static final java.lang.String EXTRA_PAIRING_VARIANT = "android.bluetooth.device.extra.PAIRING_VARIANT";
-    field public static final java.lang.String EXTRA_PREVIOUS_BOND_STATE = "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
-    field public static final java.lang.String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
-    field public static final java.lang.String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
+    field public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
+    field public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
+    field public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
+    field public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
+    field public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
+    field public static final String EXTRA_PAIRING_VARIANT = "android.bluetooth.device.extra.PAIRING_VARIANT";
+    field public static final String EXTRA_PREVIOUS_BOND_STATE = "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
+    field public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
+    field public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
     field public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2; // 0x2
     field public static final int PAIRING_VARIANT_PIN = 0; // 0x0
     field public static final int PHY_LE_1M = 1; // 0x1
@@ -8323,7 +8362,7 @@
 
   public final class BluetoothGatt implements android.bluetooth.BluetoothProfile {
     method public void abortReliableWrite();
-    method public deprecated void abortReliableWrite(android.bluetooth.BluetoothDevice);
+    method @Deprecated public void abortReliableWrite(android.bluetooth.BluetoothDevice);
     method public boolean beginReliableWrite();
     method public void close();
     method public boolean connect();
@@ -8383,20 +8422,20 @@
     method public int describeContents();
     method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors();
-    method public java.lang.Float getFloatValue(int, int);
+    method public Float getFloatValue(int, int);
     method public int getInstanceId();
-    method public java.lang.Integer getIntValue(int, int);
+    method public Integer getIntValue(int, int);
     method public int getPermissions();
     method public int getProperties();
     method public android.bluetooth.BluetoothGattService getService();
-    method public java.lang.String getStringValue(int);
+    method public String getStringValue(int);
     method public java.util.UUID getUuid();
     method public byte[] getValue();
     method public int getWriteType();
     method public boolean setValue(byte[]);
     method public boolean setValue(int, int, int);
     method public boolean setValue(int, int, int, int);
-    method public boolean setValue(java.lang.String);
+    method public boolean setValue(String);
     method public void setWriteType(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothGattCharacteristic> CREATOR;
@@ -8510,63 +8549,72 @@
     method public int getConnectionState(android.bluetooth.BluetoothDevice);
     method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
     method public boolean isAudioConnected(android.bluetooth.BluetoothDevice);
-    method public boolean sendVendorSpecificResultCode(android.bluetooth.BluetoothDevice, java.lang.String, java.lang.String);
+    method public boolean sendVendorSpecificResultCode(android.bluetooth.BluetoothDevice, String, String);
     method public boolean startVoiceRecognition(android.bluetooth.BluetoothDevice);
     method public boolean stopVoiceRecognition(android.bluetooth.BluetoothDevice);
-    field public static final java.lang.String ACTION_AUDIO_STATE_CHANGED = "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
-    field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED";
-    field public static final java.lang.String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT = "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
+    field public static final String ACTION_AUDIO_STATE_CHANGED = "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
+    field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED";
+    field public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT = "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
     field public static final int AT_CMD_TYPE_ACTION = 4; // 0x4
     field public static final int AT_CMD_TYPE_BASIC = 3; // 0x3
     field public static final int AT_CMD_TYPE_READ = 0; // 0x0
     field public static final int AT_CMD_TYPE_SET = 2; // 0x2
     field public static final int AT_CMD_TYPE_TEST = 1; // 0x1
-    field public static final java.lang.String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS = "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_ARGS";
-    field public static final java.lang.String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD = "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD";
-    field public static final java.lang.String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE = "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE";
+    field public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS = "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_ARGS";
+    field public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD = "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD";
+    field public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE = "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE";
     field public static final int STATE_AUDIO_CONNECTED = 12; // 0xc
     field public static final int STATE_AUDIO_CONNECTING = 11; // 0xb
     field public static final int STATE_AUDIO_DISCONNECTED = 10; // 0xa
-    field public static final java.lang.String VENDOR_RESULT_CODE_COMMAND_ANDROID = "+ANDROID";
-    field public static final java.lang.String VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY = "android.bluetooth.headset.intent.category.companyid";
+    field public static final String VENDOR_RESULT_CODE_COMMAND_ANDROID = "+ANDROID";
+    field public static final String VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY = "android.bluetooth.headset.intent.category.companyid";
   }
 
-  public final class BluetoothHealth implements android.bluetooth.BluetoothProfile {
-    method public boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
-    method public boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int);
+  @Deprecated public final class BluetoothHealth implements android.bluetooth.BluetoothProfile {
+    ctor @Deprecated public BluetoothHealth();
+    method @Deprecated public boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+    method @Deprecated public boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int);
+    method @Deprecated public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method @Deprecated public int getConnectionState(android.bluetooth.BluetoothDevice);
+    method @Deprecated public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+    method @Deprecated public android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+    method @Deprecated public boolean registerSinkAppConfiguration(String, int, android.bluetooth.BluetoothHealthCallback);
+    method @Deprecated public boolean unregisterAppConfiguration(android.bluetooth.BluetoothHealthAppConfiguration);
+    field @Deprecated public static final int APP_CONFIG_REGISTRATION_FAILURE = 1; // 0x1
+    field @Deprecated public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0; // 0x0
+    field @Deprecated public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3; // 0x3
+    field @Deprecated public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2; // 0x2
+    field @Deprecated public static final int CHANNEL_TYPE_RELIABLE = 10; // 0xa
+    field @Deprecated public static final int CHANNEL_TYPE_STREAMING = 11; // 0xb
+    field @Deprecated public static final int SINK_ROLE = 2; // 0x2
+    field @Deprecated public static final int SOURCE_ROLE = 1; // 0x1
+    field @Deprecated public static final int STATE_CHANNEL_CONNECTED = 2; // 0x2
+    field @Deprecated public static final int STATE_CHANNEL_CONNECTING = 1; // 0x1
+    field @Deprecated public static final int STATE_CHANNEL_DISCONNECTED = 0; // 0x0
+    field @Deprecated public static final int STATE_CHANNEL_DISCONNECTING = 3; // 0x3
+  }
+
+  @Deprecated public final class BluetoothHealthAppConfiguration implements android.os.Parcelable {
+    ctor @Deprecated public BluetoothHealthAppConfiguration();
+    method @Deprecated public int describeContents();
+    method @Deprecated public int getDataType();
+    method @Deprecated public String getName();
+    method @Deprecated public int getRole();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHealthAppConfiguration> CREATOR;
+  }
+
+  @Deprecated public abstract class BluetoothHealthCallback {
+    ctor @Deprecated public BluetoothHealthCallback();
+    method @Deprecated @BinderThread public void onHealthAppConfigurationStatusChange(android.bluetooth.BluetoothHealthAppConfiguration, int);
+    method @Deprecated @BinderThread public void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int);
+  }
+
+  public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
     method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method public int getConnectionState(android.bluetooth.BluetoothDevice);
     method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
-    method public android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
-    method public boolean registerSinkAppConfiguration(java.lang.String, int, android.bluetooth.BluetoothHealthCallback);
-    method public boolean unregisterAppConfiguration(android.bluetooth.BluetoothHealthAppConfiguration);
-    field public static final int APP_CONFIG_REGISTRATION_FAILURE = 1; // 0x1
-    field public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0; // 0x0
-    field public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3; // 0x3
-    field public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2; // 0x2
-    field public static final int CHANNEL_TYPE_RELIABLE = 10; // 0xa
-    field public static final int CHANNEL_TYPE_STREAMING = 11; // 0xb
-    field public static final int SINK_ROLE = 2; // 0x2
-    field public static final int SOURCE_ROLE = 1; // 0x1
-    field public static final int STATE_CHANNEL_CONNECTED = 2; // 0x2
-    field public static final int STATE_CHANNEL_CONNECTING = 1; // 0x1
-    field public static final int STATE_CHANNEL_DISCONNECTED = 0; // 0x0
-    field public static final int STATE_CHANNEL_DISCONNECTING = 3; // 0x3
-  }
-
-  public final class BluetoothHealthAppConfiguration implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getDataType();
-    method public java.lang.String getName();
-    method public int getRole();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHealthAppConfiguration> CREATOR;
-  }
-
-  public abstract class BluetoothHealthCallback {
-    ctor public BluetoothHealthCallback();
-    method public void onHealthAppConfigurationStatusChange(android.bluetooth.BluetoothHealthAppConfiguration, int);
-    method public void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int);
+    field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED";
   }
 
   public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile {
@@ -8580,7 +8628,7 @@
     method public boolean reportError(android.bluetooth.BluetoothDevice, byte);
     method public boolean sendReport(android.bluetooth.BluetoothDevice, int, byte[]);
     method public boolean unregisterApp();
-    field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
+    field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
     field public static final byte ERROR_RSP_INVALID_PARAM = 4; // 0x4
     field public static final byte ERROR_RSP_INVALID_RPT_ID = 2; // 0x2
     field public static final byte ERROR_RSP_NOT_READY = 1; // 0x1
@@ -8605,7 +8653,7 @@
     field public static final byte SUBCLASS2_UNCATEGORIZED = 0; // 0x0
   }
 
-  public static abstract class BluetoothHidDevice.Callback {
+  public abstract static class BluetoothHidDevice.Callback {
     ctor public BluetoothHidDevice.Callback();
     method public void onAppStatusChanged(android.bluetooth.BluetoothDevice, boolean);
     method public void onConnectionStateChanged(android.bluetooth.BluetoothDevice, int);
@@ -8634,12 +8682,12 @@
   }
 
   public final class BluetoothHidDeviceAppSdpSettings implements android.os.Parcelable {
-    ctor public BluetoothHidDeviceAppSdpSettings(java.lang.String, java.lang.String, java.lang.String, byte, byte[]);
+    ctor public BluetoothHidDeviceAppSdpSettings(String, String, String, byte, byte[]);
     method public int describeContents();
-    method public java.lang.String getDescription();
+    method public String getDescription();
     method public byte[] getDescriptors();
-    method public java.lang.String getName();
-    method public java.lang.String getProvider();
+    method public String getName();
+    method public String getProvider();
     method public byte getSubclass();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppSdpSettings> CREATOR;
@@ -8647,23 +8695,24 @@
 
   public final class BluetoothManager {
     method public android.bluetooth.BluetoothAdapter getAdapter();
-    method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
-    method public int getConnectionState(android.bluetooth.BluetoothDevice, int);
-    method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int, int[]);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(android.bluetooth.BluetoothDevice, int);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int, int[]);
     method public android.bluetooth.BluetoothGattServer openGattServer(android.content.Context, android.bluetooth.BluetoothGattServerCallback);
   }
 
-  public abstract interface BluetoothProfile {
-    method public abstract java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method public abstract int getConnectionState(android.bluetooth.BluetoothDevice);
-    method public abstract java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+  public interface BluetoothProfile {
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
     field public static final int A2DP = 2; // 0x2
-    field public static final java.lang.String EXTRA_PREVIOUS_STATE = "android.bluetooth.profile.extra.PREVIOUS_STATE";
-    field public static final java.lang.String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
+    field public static final String EXTRA_PREVIOUS_STATE = "android.bluetooth.profile.extra.PREVIOUS_STATE";
+    field public static final String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
     field public static final int GATT = 7; // 0x7
     field public static final int GATT_SERVER = 8; // 0x8
     field public static final int HEADSET = 1; // 0x1
-    field public static final int HEALTH = 3; // 0x3
+    field @Deprecated public static final int HEALTH = 3; // 0x3
+    field public static final int HEARING_AID = 21; // 0x15
     field public static final int HID_DEVICE = 19; // 0x13
     field public static final int SAP = 10; // 0xa
     field public static final int STATE_CONNECTED = 2; // 0x2
@@ -8672,9 +8721,9 @@
     field public static final int STATE_DISCONNECTING = 3; // 0x3
   }
 
-  public static abstract interface BluetoothProfile.ServiceListener {
-    method public abstract void onServiceConnected(int, android.bluetooth.BluetoothProfile);
-    method public abstract void onServiceDisconnected(int);
+  public static interface BluetoothProfile.ServiceListener {
+    method public void onServiceConnected(int, android.bluetooth.BluetoothProfile);
+    method public void onServiceDisconnected(int);
   }
 
   public final class BluetoothServerSocket implements java.io.Closeable {
@@ -8719,7 +8768,7 @@
     method public boolean getIncludeDeviceName();
     method public boolean getIncludeTxPowerLevel();
     method public android.util.SparseArray<byte[]> getManufacturerSpecificData();
-    method public java.util.Map<android.os.ParcelUuid, byte[]> getServiceData();
+    method public java.util.Map<android.os.ParcelUuid,byte[]> getServiceData();
     method public java.util.List<android.os.ParcelUuid> getServiceUuids();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertiseData> CREATOR;
@@ -8843,14 +8892,14 @@
 
   public final class BluetoothLeScanner {
     method public void flushPendingScanResults(android.bluetooth.le.ScanCallback);
-    method public void startScan(android.bluetooth.le.ScanCallback);
-    method public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
-    method public int startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.app.PendingIntent);
-    method public void stopScan(android.bluetooth.le.ScanCallback);
-    method public void stopScan(android.app.PendingIntent);
-    field public static final java.lang.String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE";
-    field public static final java.lang.String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE";
-    field public static final java.lang.String EXTRA_LIST_SCAN_RESULT = "android.bluetooth.le.extra.LIST_SCAN_RESULT";
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void startScan(android.bluetooth.le.ScanCallback);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int startScan(@Nullable java.util.List<android.bluetooth.le.ScanFilter>, @Nullable android.bluetooth.le.ScanSettings, @NonNull android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void stopScan(android.bluetooth.le.ScanCallback);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void stopScan(android.app.PendingIntent);
+    field public static final String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE";
+    field public static final String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE";
+    field public static final String EXTRA_LIST_SCAN_RESULT = "android.bluetooth.le.extra.LIST_SCAN_RESULT";
   }
 
   public final class PeriodicAdvertisingParameters implements android.os.Parcelable {
@@ -8881,18 +8930,18 @@
 
   public final class ScanFilter implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getDeviceAddress();
-    method public java.lang.String getDeviceName();
-    method public byte[] getManufacturerData();
-    method public byte[] getManufacturerDataMask();
+    method @Nullable public String getDeviceAddress();
+    method @Nullable public String getDeviceName();
+    method @Nullable public byte[] getManufacturerData();
+    method @Nullable public byte[] getManufacturerDataMask();
     method public int getManufacturerId();
-    method public byte[] getServiceData();
-    method public byte[] getServiceDataMask();
-    method public android.os.ParcelUuid getServiceDataUuid();
-    method public android.os.ParcelUuid getServiceSolicitationUuid();
-    method public android.os.ParcelUuid getServiceSolicitationUuidMask();
-    method public android.os.ParcelUuid getServiceUuid();
-    method public android.os.ParcelUuid getServiceUuidMask();
+    method @Nullable public byte[] getServiceData();
+    method @Nullable public byte[] getServiceDataMask();
+    method @Nullable public android.os.ParcelUuid getServiceDataUuid();
+    method @Nullable public android.os.ParcelUuid getServiceSolicitationUuid();
+    method @Nullable public android.os.ParcelUuid getServiceSolicitationUuidMask();
+    method @Nullable public android.os.ParcelUuid getServiceUuid();
+    method @Nullable public android.os.ParcelUuid getServiceUuidMask();
     method public boolean matches(android.bluetooth.le.ScanResult);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanFilter> CREATOR;
@@ -8901,8 +8950,8 @@
   public static final class ScanFilter.Builder {
     ctor public ScanFilter.Builder();
     method public android.bluetooth.le.ScanFilter build();
-    method public android.bluetooth.le.ScanFilter.Builder setDeviceAddress(java.lang.String);
-    method public android.bluetooth.le.ScanFilter.Builder setDeviceName(java.lang.String);
+    method public android.bluetooth.le.ScanFilter.Builder setDeviceAddress(String);
+    method public android.bluetooth.le.ScanFilter.Builder setDeviceName(String);
     method public android.bluetooth.le.ScanFilter.Builder setManufacturerData(int, byte[]);
     method public android.bluetooth.le.ScanFilter.Builder setManufacturerData(int, byte[], byte[]);
     method public android.bluetooth.le.ScanFilter.Builder setServiceData(android.os.ParcelUuid, byte[]);
@@ -8916,18 +8965,18 @@
   public final class ScanRecord {
     method public int getAdvertiseFlags();
     method public byte[] getBytes();
-    method public java.lang.String getDeviceName();
+    method @Nullable public String getDeviceName();
     method public android.util.SparseArray<byte[]> getManufacturerSpecificData();
-    method public byte[] getManufacturerSpecificData(int);
-    method public java.util.Map<android.os.ParcelUuid, byte[]> getServiceData();
-    method public byte[] getServiceData(android.os.ParcelUuid);
-    method public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids();
+    method @Nullable public byte[] getManufacturerSpecificData(int);
+    method public java.util.Map<android.os.ParcelUuid,byte[]> getServiceData();
+    method @Nullable public byte[] getServiceData(android.os.ParcelUuid);
+    method @Nullable public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids();
     method public java.util.List<android.os.ParcelUuid> getServiceUuids();
     method public int getTxPowerLevel();
   }
 
   public final class ScanResult implements android.os.Parcelable {
-    ctor public deprecated ScanResult(android.bluetooth.BluetoothDevice, android.bluetooth.le.ScanRecord, int, long);
+    ctor @Deprecated public ScanResult(android.bluetooth.BluetoothDevice, android.bluetooth.le.ScanRecord, int, long);
     ctor public ScanResult(android.bluetooth.BluetoothDevice, int, int, int, int, int, int, int, android.bluetooth.le.ScanRecord, long);
     method public int describeContents();
     method public int getAdvertisingSid();
@@ -8936,7 +8985,7 @@
     method public int getPeriodicAdvertisingInterval();
     method public int getPrimaryPhy();
     method public int getRssi();
-    method public android.bluetooth.le.ScanRecord getScanRecord();
+    method @Nullable public android.bluetooth.le.ScanRecord getScanRecord();
     method public int getSecondaryPhy();
     method public long getTimestampNanos();
     method public int getTxPower();
@@ -9001,12 +9050,12 @@
 
   public static final class AssociationRequest.Builder {
     ctor public AssociationRequest.Builder();
-    method public android.companion.AssociationRequest.Builder addDeviceFilter(android.companion.DeviceFilter<?>);
-    method public android.companion.AssociationRequest build();
-    method public android.companion.AssociationRequest.Builder setSingleDevice(boolean);
+    method @NonNull public android.companion.AssociationRequest.Builder addDeviceFilter(@Nullable android.companion.DeviceFilter<?>);
+    method @NonNull public android.companion.AssociationRequest build();
+    method @NonNull public android.companion.AssociationRequest.Builder setSingleDevice(boolean);
   }
 
-  public final class BluetoothDeviceFilter implements android.companion.DeviceFilter {
+  public final class BluetoothDeviceFilter implements android.companion.DeviceFilter<android.bluetooth.BluetoothDevice> {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.companion.BluetoothDeviceFilter> CREATOR;
@@ -9014,13 +9063,13 @@
 
   public static final class BluetoothDeviceFilter.Builder {
     ctor public BluetoothDeviceFilter.Builder();
-    method public android.companion.BluetoothDeviceFilter.Builder addServiceUuid(android.os.ParcelUuid, android.os.ParcelUuid);
-    method public android.companion.BluetoothDeviceFilter build();
-    method public android.companion.BluetoothDeviceFilter.Builder setAddress(java.lang.String);
-    method public android.companion.BluetoothDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+    method @NonNull public android.companion.BluetoothDeviceFilter.Builder addServiceUuid(@Nullable android.os.ParcelUuid, @Nullable android.os.ParcelUuid);
+    method @NonNull public android.companion.BluetoothDeviceFilter build();
+    method @NonNull public android.companion.BluetoothDeviceFilter.Builder setAddress(@Nullable String);
+    method public android.companion.BluetoothDeviceFilter.Builder setNamePattern(@Nullable java.util.regex.Pattern);
   }
 
-  public final class BluetoothLeDeviceFilter implements android.companion.DeviceFilter {
+  public final class BluetoothLeDeviceFilter implements android.companion.DeviceFilter<android.bluetooth.le.ScanResult> {
     method public int describeContents();
     method public static int getRenamePrefixLengthLimit();
     method public void writeToParcel(android.os.Parcel, int);
@@ -9029,33 +9078,33 @@
 
   public static final class BluetoothLeDeviceFilter.Builder {
     ctor public BluetoothLeDeviceFilter.Builder();
-    method public android.companion.BluetoothLeDeviceFilter build();
-    method public android.companion.BluetoothLeDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
-    method public android.companion.BluetoothLeDeviceFilter.Builder setRawDataFilter(byte[], byte[]);
-    method public android.companion.BluetoothLeDeviceFilter.Builder setRenameFromBytes(java.lang.String, java.lang.String, int, int, java.nio.ByteOrder);
-    method public android.companion.BluetoothLeDeviceFilter.Builder setRenameFromName(java.lang.String, java.lang.String, int, int);
-    method public android.companion.BluetoothLeDeviceFilter.Builder setScanFilter(android.bluetooth.le.ScanFilter);
+    method @NonNull public android.companion.BluetoothLeDeviceFilter build();
+    method public android.companion.BluetoothLeDeviceFilter.Builder setNamePattern(@Nullable java.util.regex.Pattern);
+    method @NonNull public android.companion.BluetoothLeDeviceFilter.Builder setRawDataFilter(@NonNull byte[], @Nullable byte[]);
+    method @NonNull public android.companion.BluetoothLeDeviceFilter.Builder setRenameFromBytes(@NonNull String, @NonNull String, int, int, java.nio.ByteOrder);
+    method @NonNull public android.companion.BluetoothLeDeviceFilter.Builder setRenameFromName(@NonNull String, @NonNull String, int, int);
+    method @NonNull public android.companion.BluetoothLeDeviceFilter.Builder setScanFilter(@Nullable android.bluetooth.le.ScanFilter);
   }
 
   public final class CompanionDeviceManager {
-    method public void associate(android.companion.AssociationRequest, android.companion.CompanionDeviceManager.Callback, android.os.Handler);
-    method public void disassociate(java.lang.String);
-    method public java.util.List<java.lang.String> getAssociations();
+    method public void associate(@NonNull android.companion.AssociationRequest, @NonNull android.companion.CompanionDeviceManager.Callback, @Nullable android.os.Handler);
+    method public void disassociate(@NonNull String);
+    method @NonNull public java.util.List<java.lang.String> getAssociations();
     method public boolean hasNotificationAccess(android.content.ComponentName);
     method public void requestNotificationAccess(android.content.ComponentName);
-    field public static final java.lang.String EXTRA_DEVICE = "android.companion.extra.DEVICE";
+    field public static final String EXTRA_DEVICE = "android.companion.extra.DEVICE";
   }
 
-  public static abstract class CompanionDeviceManager.Callback {
+  public abstract static class CompanionDeviceManager.Callback {
     ctor public CompanionDeviceManager.Callback();
     method public abstract void onDeviceFound(android.content.IntentSender);
-    method public abstract void onFailure(java.lang.CharSequence);
+    method public abstract void onFailure(CharSequence);
   }
 
-  public abstract interface DeviceFilter<D extends android.os.Parcelable> implements android.os.Parcelable {
+  public interface DeviceFilter<D extends android.os.Parcelable> extends android.os.Parcelable {
   }
 
-  public final class WifiDeviceFilter implements android.companion.DeviceFilter {
+  public final class WifiDeviceFilter implements android.companion.DeviceFilter<android.net.wifi.ScanResult> {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.companion.WifiDeviceFilter> CREATOR;
@@ -9063,8 +9112,8 @@
 
   public static final class WifiDeviceFilter.Builder {
     ctor public WifiDeviceFilter.Builder();
-    method public android.companion.WifiDeviceFilter build();
-    method public android.companion.WifiDeviceFilter.Builder setNamePattern(java.util.regex.Pattern);
+    method @NonNull public android.companion.WifiDeviceFilter build();
+    method public android.companion.WifiDeviceFilter.Builder setNamePattern(@Nullable java.util.regex.Pattern);
   }
 
 }
@@ -9076,42 +9125,42 @@
     ctor public AbstractThreadedSyncAdapter(android.content.Context, boolean, boolean);
     method public android.content.Context getContext();
     method public final android.os.IBinder getSyncAdapterBinder();
-    method public abstract void onPerformSync(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.ContentProviderClient, android.content.SyncResult);
-    method public void onSecurityException(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.SyncResult);
+    method public abstract void onPerformSync(android.accounts.Account, android.os.Bundle, String, android.content.ContentProviderClient, android.content.SyncResult);
+    method public void onSecurityException(android.accounts.Account, android.os.Bundle, String, android.content.SyncResult);
     method public void onSyncCanceled();
-    method public void onSyncCanceled(java.lang.Thread);
-    method public boolean onUnsyncableAccount();
-    field public static final deprecated int LOG_SYNC_DETAILS = 2743; // 0xab7
+    method public void onSyncCanceled(Thread);
+    method @MainThread public boolean onUnsyncableAccount();
+    field @Deprecated public static final int LOG_SYNC_DETAILS = 2743; // 0xab7
   }
 
   public class ActivityNotFoundException extends java.lang.RuntimeException {
     ctor public ActivityNotFoundException();
-    ctor public ActivityNotFoundException(java.lang.String);
+    ctor public ActivityNotFoundException(String);
   }
 
   public abstract class AsyncQueryHandler extends android.os.Handler {
     ctor public AsyncQueryHandler(android.content.ContentResolver);
     method public final void cancelOperation(int);
     method protected android.os.Handler createHandler(android.os.Looper);
-    method protected void onDeleteComplete(int, java.lang.Object, int);
-    method protected void onInsertComplete(int, java.lang.Object, android.net.Uri);
-    method protected void onQueryComplete(int, java.lang.Object, android.database.Cursor);
-    method protected void onUpdateComplete(int, java.lang.Object, int);
-    method public final void startDelete(int, java.lang.Object, android.net.Uri, java.lang.String, java.lang.String[]);
-    method public final void startInsert(int, java.lang.Object, android.net.Uri, android.content.ContentValues);
-    method public void startQuery(int, java.lang.Object, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public final void startUpdate(int, java.lang.Object, android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+    method protected void onDeleteComplete(int, Object, int);
+    method protected void onInsertComplete(int, Object, android.net.Uri);
+    method protected void onQueryComplete(int, Object, android.database.Cursor);
+    method protected void onUpdateComplete(int, Object, int);
+    method public final void startDelete(int, Object, android.net.Uri, String, String[]);
+    method public final void startInsert(int, Object, android.net.Uri, android.content.ContentValues);
+    method public void startQuery(int, Object, android.net.Uri, String[], String, String[], String);
+    method public final void startUpdate(int, Object, android.net.Uri, android.content.ContentValues, String, String[]);
   }
 
   protected static final class AsyncQueryHandler.WorkerArgs {
     ctor protected AsyncQueryHandler.WorkerArgs();
-    field public java.lang.Object cookie;
+    field public Object cookie;
     field public android.os.Handler handler;
-    field public java.lang.String orderBy;
-    field public java.lang.String[] projection;
-    field public java.lang.Object result;
-    field public java.lang.String selection;
-    field public java.lang.String[] selectionArgs;
+    field public String orderBy;
+    field public String[] projection;
+    field public Object result;
+    field public String selection;
+    field public String[] selectionArgs;
     field public android.net.Uri uri;
     field public android.content.ContentValues values;
   }
@@ -9120,14 +9169,14 @@
     ctor public AsyncQueryHandler.WorkerHandler(android.os.Looper);
   }
 
-  public abstract deprecated class AsyncTaskLoader<D> extends android.content.Loader {
-    ctor public AsyncTaskLoader(android.content.Context);
-    method public void cancelLoadInBackground();
-    method public boolean isLoadInBackgroundCanceled();
-    method public abstract D loadInBackground();
-    method public void onCanceled(D);
-    method protected D onLoadInBackground();
-    method public void setUpdateThrottle(long);
+  @Deprecated public abstract class AsyncTaskLoader<D> extends android.content.Loader<D> {
+    ctor @Deprecated public AsyncTaskLoader(android.content.Context);
+    method @Deprecated public void cancelLoadInBackground();
+    method @Deprecated public boolean isLoadInBackgroundCanceled();
+    method @Deprecated public abstract D loadInBackground();
+    method @Deprecated public void onCanceled(D);
+    method @Deprecated protected D onLoadInBackground();
+    method @Deprecated public void setUpdateThrottle(long);
   }
 
   public abstract class BroadcastReceiver {
@@ -9137,7 +9186,7 @@
     method public final boolean getAbortBroadcast();
     method public final boolean getDebugUnregister();
     method public final int getResultCode();
-    method public final java.lang.String getResultData();
+    method public final String getResultData();
     method public final android.os.Bundle getResultExtras(boolean);
     method public final android.content.BroadcastReceiver.PendingResult goAsync();
     method public final boolean isInitialStickyBroadcast();
@@ -9146,9 +9195,9 @@
     method public android.os.IBinder peekService(android.content.Context, android.content.Intent);
     method public final void setDebugUnregister(boolean);
     method public final void setOrderedHint(boolean);
-    method public final void setResult(int, java.lang.String, android.os.Bundle);
+    method public final void setResult(int, String, android.os.Bundle);
     method public final void setResultCode(int);
-    method public final void setResultData(java.lang.String);
+    method public final void setResultData(String);
     method public final void setResultExtras(android.os.Bundle);
   }
 
@@ -9158,16 +9207,16 @@
     method public final void finish();
     method public final boolean getAbortBroadcast();
     method public final int getResultCode();
-    method public final java.lang.String getResultData();
+    method public final String getResultData();
     method public final android.os.Bundle getResultExtras(boolean);
-    method public final void setResult(int, java.lang.String, android.os.Bundle);
+    method public final void setResult(int, String, android.os.Bundle);
     method public final void setResultCode(int);
-    method public final void setResultData(java.lang.String);
+    method public final void setResultData(String);
     method public final void setResultExtras(android.os.Bundle);
   }
 
   public class ClipData implements android.os.Parcelable {
-    ctor public ClipData(java.lang.CharSequence, java.lang.String[], android.content.ClipData.Item);
+    ctor public ClipData(CharSequence, String[], android.content.ClipData.Item);
     ctor public ClipData(android.content.ClipDescription, android.content.ClipData.Item);
     ctor public ClipData(android.content.ClipData);
     method public void addItem(android.content.ClipData.Item);
@@ -9176,76 +9225,76 @@
     method public android.content.ClipDescription getDescription();
     method public android.content.ClipData.Item getItemAt(int);
     method public int getItemCount();
-    method public static android.content.ClipData newHtmlText(java.lang.CharSequence, java.lang.CharSequence, java.lang.String);
-    method public static android.content.ClipData newIntent(java.lang.CharSequence, android.content.Intent);
-    method public static android.content.ClipData newPlainText(java.lang.CharSequence, java.lang.CharSequence);
-    method public static android.content.ClipData newRawUri(java.lang.CharSequence, android.net.Uri);
-    method public static android.content.ClipData newUri(android.content.ContentResolver, java.lang.CharSequence, android.net.Uri);
+    method public static android.content.ClipData newHtmlText(CharSequence, CharSequence, String);
+    method public static android.content.ClipData newIntent(CharSequence, android.content.Intent);
+    method public static android.content.ClipData newPlainText(CharSequence, CharSequence);
+    method public static android.content.ClipData newRawUri(CharSequence, android.net.Uri);
+    method public static android.content.ClipData newUri(android.content.ContentResolver, CharSequence, android.net.Uri);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.ClipData> CREATOR;
   }
 
   public static class ClipData.Item {
-    ctor public ClipData.Item(java.lang.CharSequence);
-    ctor public ClipData.Item(java.lang.CharSequence, java.lang.String);
+    ctor public ClipData.Item(CharSequence);
+    ctor public ClipData.Item(CharSequence, String);
     ctor public ClipData.Item(android.content.Intent);
     ctor public ClipData.Item(android.net.Uri);
-    ctor public ClipData.Item(java.lang.CharSequence, android.content.Intent, android.net.Uri);
-    ctor public ClipData.Item(java.lang.CharSequence, java.lang.String, android.content.Intent, android.net.Uri);
-    method public java.lang.String coerceToHtmlText(android.content.Context);
-    method public java.lang.CharSequence coerceToStyledText(android.content.Context);
-    method public java.lang.CharSequence coerceToText(android.content.Context);
-    method public java.lang.String getHtmlText();
+    ctor public ClipData.Item(CharSequence, android.content.Intent, android.net.Uri);
+    ctor public ClipData.Item(CharSequence, String, android.content.Intent, android.net.Uri);
+    method public String coerceToHtmlText(android.content.Context);
+    method public CharSequence coerceToStyledText(android.content.Context);
+    method public CharSequence coerceToText(android.content.Context);
+    method public String getHtmlText();
     method public android.content.Intent getIntent();
-    method public java.lang.CharSequence getText();
+    method public CharSequence getText();
     method public android.net.Uri getUri();
   }
 
   public class ClipDescription implements android.os.Parcelable {
-    ctor public ClipDescription(java.lang.CharSequence, java.lang.String[]);
+    ctor public ClipDescription(CharSequence, String[]);
     ctor public ClipDescription(android.content.ClipDescription);
-    method public static boolean compareMimeTypes(java.lang.String, java.lang.String);
+    method public static boolean compareMimeTypes(String, String);
     method public int describeContents();
-    method public java.lang.String[] filterMimeTypes(java.lang.String);
+    method public String[] filterMimeTypes(String);
     method public android.os.PersistableBundle getExtras();
-    method public java.lang.CharSequence getLabel();
-    method public java.lang.String getMimeType(int);
+    method public CharSequence getLabel();
+    method public String getMimeType(int);
     method public int getMimeTypeCount();
     method public long getTimestamp();
-    method public boolean hasMimeType(java.lang.String);
+    method public boolean hasMimeType(String);
     method public void setExtras(android.os.PersistableBundle);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.ClipDescription> CREATOR;
-    field public static final java.lang.String MIMETYPE_TEXT_HTML = "text/html";
-    field public static final java.lang.String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent";
-    field public static final java.lang.String MIMETYPE_TEXT_PLAIN = "text/plain";
-    field public static final java.lang.String MIMETYPE_TEXT_URILIST = "text/uri-list";
+    field public static final String MIMETYPE_TEXT_HTML = "text/html";
+    field public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent";
+    field public static final String MIMETYPE_TEXT_PLAIN = "text/plain";
+    field public static final String MIMETYPE_TEXT_URILIST = "text/uri-list";
   }
 
   public class ClipboardManager extends android.text.ClipboardManager {
     method public void addPrimaryClipChangedListener(android.content.ClipboardManager.OnPrimaryClipChangedListener);
     method public void clearPrimaryClip();
-    method public android.content.ClipData getPrimaryClip();
-    method public android.content.ClipDescription getPrimaryClipDescription();
-    method public deprecated java.lang.CharSequence getText();
+    method @Nullable public android.content.ClipData getPrimaryClip();
+    method @Nullable public android.content.ClipDescription getPrimaryClipDescription();
+    method @Deprecated public CharSequence getText();
     method public boolean hasPrimaryClip();
-    method public deprecated boolean hasText();
+    method @Deprecated public boolean hasText();
     method public void removePrimaryClipChangedListener(android.content.ClipboardManager.OnPrimaryClipChangedListener);
-    method public void setPrimaryClip(android.content.ClipData);
-    method public deprecated void setText(java.lang.CharSequence);
+    method public void setPrimaryClip(@NonNull android.content.ClipData);
+    method @Deprecated public void setText(CharSequence);
   }
 
-  public static abstract interface ClipboardManager.OnPrimaryClipChangedListener {
-    method public abstract void onPrimaryClipChanged();
+  public static interface ClipboardManager.OnPrimaryClipChangedListener {
+    method public void onPrimaryClipChanged();
   }
 
-  public abstract interface ComponentCallbacks {
-    method public abstract void onConfigurationChanged(android.content.res.Configuration);
-    method public abstract void onLowMemory();
+  public interface ComponentCallbacks {
+    method public void onConfigurationChanged(@NonNull android.content.res.Configuration);
+    method public void onLowMemory();
   }
 
-  public abstract interface ComponentCallbacks2 implements android.content.ComponentCallbacks {
-    method public abstract void onTrimMemory(int);
+  public interface ComponentCallbacks2 extends android.content.ComponentCallbacks {
+    method public void onTrimMemory(int);
     field public static final int TRIM_MEMORY_BACKGROUND = 40; // 0x28
     field public static final int TRIM_MEMORY_COMPLETE = 80; // 0x50
     field public static final int TRIM_MEMORY_MODERATE = 60; // 0x3c
@@ -9255,128 +9304,128 @@
     field public static final int TRIM_MEMORY_UI_HIDDEN = 20; // 0x14
   }
 
-  public final class ComponentName implements java.lang.Cloneable java.lang.Comparable android.os.Parcelable {
-    ctor public ComponentName(java.lang.String, java.lang.String);
-    ctor public ComponentName(android.content.Context, java.lang.String);
-    ctor public ComponentName(android.content.Context, java.lang.Class<?>);
+  public final class ComponentName implements java.lang.Cloneable java.lang.Comparable<android.content.ComponentName> android.os.Parcelable {
+    ctor public ComponentName(@NonNull String, @NonNull String);
+    ctor public ComponentName(@NonNull android.content.Context, @NonNull String);
+    ctor public ComponentName(@NonNull android.content.Context, @NonNull Class<?>);
     ctor public ComponentName(android.os.Parcel);
     method public android.content.ComponentName clone();
     method public int compareTo(android.content.ComponentName);
-    method public static android.content.ComponentName createRelative(java.lang.String, java.lang.String);
-    method public static android.content.ComponentName createRelative(android.content.Context, java.lang.String);
+    method @NonNull public static android.content.ComponentName createRelative(@NonNull String, @NonNull String);
+    method @NonNull public static android.content.ComponentName createRelative(@NonNull android.content.Context, @NonNull String);
     method public int describeContents();
-    method public java.lang.String flattenToShortString();
-    method public java.lang.String flattenToString();
-    method public java.lang.String getClassName();
-    method public java.lang.String getPackageName();
-    method public java.lang.String getShortClassName();
+    method @NonNull public String flattenToShortString();
+    method @NonNull public String flattenToString();
+    method @NonNull public String getClassName();
+    method @NonNull public String getPackageName();
+    method public String getShortClassName();
     method public static android.content.ComponentName readFromParcel(android.os.Parcel);
-    method public java.lang.String toShortString();
-    method public static android.content.ComponentName unflattenFromString(java.lang.String);
+    method public String toShortString();
+    method @Nullable public static android.content.ComponentName unflattenFromString(@NonNull String);
     method public void writeToParcel(android.os.Parcel, int);
     method public static void writeToParcel(android.content.ComponentName, android.os.Parcel);
     field public static final android.os.Parcelable.Creator<android.content.ComponentName> CREATOR;
   }
 
-  public abstract interface ContentInterface {
-    method public abstract android.content.ContentProviderResult[] applyBatch(java.lang.String, java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
-    method public abstract int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
-    method public abstract android.os.Bundle call(java.lang.String, java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
-    method public abstract android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
-    method public abstract int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
-    method public abstract java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
-    method public abstract java.lang.String getType(android.net.Uri) throws android.os.RemoteException;
-    method public abstract android.net.Uri insert(android.net.Uri, android.content.ContentValues) throws android.os.RemoteException;
-    method public abstract android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
-    method public abstract android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
-    method public abstract android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
-    method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal) throws android.os.RemoteException;
-    method public abstract boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal) throws android.os.RemoteException;
-    method public abstract android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
-    method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
+  public interface ContentInterface {
+    method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull String, @NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
+    method public int bulkInsert(@NonNull android.net.Uri, @NonNull android.content.ContentValues[]) throws android.os.RemoteException;
+    method @Nullable public android.os.Bundle call(@NonNull String, @NonNull String, @Nullable String, @Nullable android.os.Bundle) throws android.os.RemoteException;
+    method @Nullable public android.net.Uri canonicalize(@NonNull android.net.Uri) throws android.os.RemoteException;
+    method public int delete(@NonNull android.net.Uri, @Nullable String, @Nullable String[]) throws android.os.RemoteException;
+    method @Nullable public String[] getStreamTypes(@NonNull android.net.Uri, @NonNull String) throws android.os.RemoteException;
+    method @Nullable public String getType(@NonNull android.net.Uri) throws android.os.RemoteException;
+    method @Nullable public android.net.Uri insert(@NonNull android.net.Uri, @Nullable android.content.ContentValues) throws android.os.RemoteException;
+    method @Nullable public android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method @Nullable public android.os.ParcelFileDescriptor openFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method @Nullable public android.content.res.AssetFileDescriptor openTypedAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method @Nullable public android.database.Cursor query(@NonNull android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws android.os.RemoteException;
+    method public boolean refresh(@NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws android.os.RemoteException;
+    method @Nullable public android.net.Uri uncanonicalize(@NonNull android.net.Uri) throws android.os.RemoteException;
+    method public int update(@NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[]) throws android.os.RemoteException;
   }
 
   public abstract class ContentProvider implements android.content.ComponentCallbacks2 android.content.ContentInterface {
     ctor public ContentProvider();
-    method public android.content.ContentProviderResult[] applyBatch(java.lang.String, java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException;
-    method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException;
+    method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull String, @NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException;
+    method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException;
     method public void attachInfo(android.content.Context, android.content.pm.ProviderInfo);
-    method public int bulkInsert(android.net.Uri, android.content.ContentValues[]);
-    method public android.os.Bundle call(java.lang.String, java.lang.String, java.lang.String, android.os.Bundle);
-    method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle);
-    method public android.net.Uri canonicalize(android.net.Uri);
-    method public final android.content.ContentProvider.CallingIdentity clearCallingIdentity();
-    method public abstract int delete(android.net.Uri, java.lang.String, java.lang.String[]);
-    method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public final java.lang.String getCallingPackage();
-    method public final android.content.Context getContext();
-    method public final android.content.pm.PathPermission[] getPathPermissions();
-    method public final java.lang.String getReadPermission();
-    method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String);
-    method public abstract java.lang.String getType(android.net.Uri);
-    method public final java.lang.String getWritePermission();
-    method public abstract android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+    method public int bulkInsert(@NonNull android.net.Uri, @NonNull android.content.ContentValues[]);
+    method @Nullable public android.os.Bundle call(@NonNull String, @NonNull String, @Nullable String, @Nullable android.os.Bundle);
+    method @Nullable public android.os.Bundle call(@NonNull String, @Nullable String, @Nullable android.os.Bundle);
+    method @Nullable public android.net.Uri canonicalize(@NonNull android.net.Uri);
+    method @NonNull public final android.content.ContentProvider.CallingIdentity clearCallingIdentity();
+    method public abstract int delete(@NonNull android.net.Uri, @Nullable String, @Nullable String[]);
+    method public void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
+    method @Nullable public final String getCallingPackage();
+    method @Nullable public final android.content.Context getContext();
+    method @Nullable public final android.content.pm.PathPermission[] getPathPermissions();
+    method @Nullable public final String getReadPermission();
+    method @Nullable public String[] getStreamTypes(@NonNull android.net.Uri, @NonNull String);
+    method @Nullable public abstract String getType(@NonNull android.net.Uri);
+    method @Nullable public final String getWritePermission();
+    method @Nullable public abstract android.net.Uri insert(@NonNull android.net.Uri, @Nullable android.content.ContentValues);
     method protected boolean isTemporary();
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public abstract boolean onCreate();
     method public void onLowMemory();
     method public void onTrimMemory(int);
-    method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
-    method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
-    method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method protected final android.os.ParcelFileDescriptor openFileHelper(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
-    method public <T> android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
-    method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
-    method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
-    method public android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
-    method public boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal);
-    method public final void restoreCallingIdentity(android.content.ContentProvider.CallingIdentity);
-    method protected final void setPathPermissions(android.content.pm.PathPermission[]);
-    method protected final void setReadPermission(java.lang.String);
-    method protected final void setWritePermission(java.lang.String);
+    method @Nullable public android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
+    method @Nullable public android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method @Nullable public android.os.ParcelFileDescriptor openFile(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
+    method @Nullable public android.os.ParcelFileDescriptor openFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method @NonNull protected final android.os.ParcelFileDescriptor openFileHelper(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
+    method @NonNull public <T> android.os.ParcelFileDescriptor openPipeHelper(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable T, @NonNull android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
+    method @Nullable public android.content.res.AssetFileDescriptor openTypedAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle) throws java.io.FileNotFoundException;
+    method @Nullable public android.content.res.AssetFileDescriptor openTypedAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method @Nullable public abstract android.database.Cursor query(@NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String);
+    method @Nullable public android.database.Cursor query(@NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal);
+    method @Nullable public android.database.Cursor query(@NonNull android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
+    method public boolean refresh(android.net.Uri, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
+    method public final void restoreCallingIdentity(@NonNull android.content.ContentProvider.CallingIdentity);
+    method protected final void setPathPermissions(@Nullable android.content.pm.PathPermission[]);
+    method protected final void setReadPermission(@Nullable String);
+    method protected final void setWritePermission(@Nullable String);
     method public void shutdown();
-    method public android.net.Uri uncanonicalize(android.net.Uri);
-    method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+    method @Nullable public android.net.Uri uncanonicalize(@NonNull android.net.Uri);
+    method public abstract int update(@NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[]);
   }
 
   public final class ContentProvider.CallingIdentity {
   }
 
-  public static abstract interface ContentProvider.PipeDataWriter<T> {
-    method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
+  public static interface ContentProvider.PipeDataWriter<T> {
+    method public void writeDataToPipe(@NonNull android.os.ParcelFileDescriptor, @NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable T);
   }
 
   public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
-    method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
-    method public android.content.ContentProviderResult[] applyBatch(java.lang.String, java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
-    method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
-    method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
-    method public android.os.Bundle call(java.lang.String, java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
-    method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+    method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
+    method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull String, @NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
+    method public int bulkInsert(@NonNull android.net.Uri, @NonNull android.content.ContentValues[]) throws android.os.RemoteException;
+    method @Nullable public android.os.Bundle call(@NonNull String, @Nullable String, @Nullable android.os.Bundle) throws android.os.RemoteException;
+    method @Nullable public android.os.Bundle call(@NonNull String, @NonNull String, @Nullable String, @Nullable android.os.Bundle) throws android.os.RemoteException;
+    method @Nullable public final android.net.Uri canonicalize(@NonNull android.net.Uri) throws android.os.RemoteException;
     method public void close();
     method public static void closeQuietly(android.content.ContentProviderClient);
-    method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
-    method public android.content.ContentProvider getLocalContentProvider();
-    method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
-    method public java.lang.String getType(android.net.Uri) throws android.os.RemoteException;
-    method public android.net.Uri insert(android.net.Uri, android.content.ContentValues) throws android.os.RemoteException;
-    method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException, android.os.RemoteException;
-    method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
-    method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException, android.os.RemoteException;
-    method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
-    method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
-    method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException, android.os.RemoteException;
-    method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
-    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
-    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
-    method public android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal) throws android.os.RemoteException;
-    method public boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal) throws android.os.RemoteException;
-    method public deprecated boolean release();
-    method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
-    method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
+    method public int delete(@NonNull android.net.Uri, @Nullable String, @Nullable String[]) throws android.os.RemoteException;
+    method @Nullable public android.content.ContentProvider getLocalContentProvider();
+    method @Nullable public String[] getStreamTypes(@NonNull android.net.Uri, @NonNull String) throws android.os.RemoteException;
+    method @Nullable public String getType(@NonNull android.net.Uri) throws android.os.RemoteException;
+    method @Nullable public android.net.Uri insert(@NonNull android.net.Uri, @Nullable android.content.ContentValues) throws android.os.RemoteException;
+    method @Nullable public android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method @Nullable public android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method @Nullable public android.os.ParcelFileDescriptor openFile(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method @Nullable public android.os.ParcelFileDescriptor openFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
+    method @Nullable public android.database.Cursor query(@NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String) throws android.os.RemoteException;
+    method @Nullable public android.database.Cursor query(@NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal) throws android.os.RemoteException;
+    method @Nullable public android.database.Cursor query(@NonNull android.net.Uri, @Nullable String[], android.os.Bundle, @Nullable android.os.CancellationSignal) throws android.os.RemoteException;
+    method public boolean refresh(android.net.Uri, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws android.os.RemoteException;
+    method @Deprecated public boolean release();
+    method @Nullable public final android.net.Uri uncanonicalize(@NonNull android.net.Uri) throws android.os.RemoteException;
+    method public int update(@NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[]) throws android.os.RemoteException;
   }
 
   public class ContentProviderOperation implements android.os.Parcelable {
@@ -9394,7 +9443,7 @@
     method public static android.content.ContentProviderOperation.Builder newDelete(android.net.Uri);
     method public static android.content.ContentProviderOperation.Builder newInsert(android.net.Uri);
     method public static android.content.ContentProviderOperation.Builder newUpdate(android.net.Uri);
-    method public java.lang.String[] resolveSelectionArgsBackReferences(android.content.ContentProviderResult[], int);
+    method public String[] resolveSelectionArgsBackReferences(android.content.ContentProviderResult[], int);
     method public android.content.ContentValues resolveValueBackReferences(android.content.ContentProviderResult[], int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.ContentProviderOperation> CREATOR;
@@ -9403,10 +9452,10 @@
   public static class ContentProviderOperation.Builder {
     method public android.content.ContentProviderOperation build();
     method public android.content.ContentProviderOperation.Builder withExpectedCount(int);
-    method public android.content.ContentProviderOperation.Builder withSelection(java.lang.String, java.lang.String[]);
+    method public android.content.ContentProviderOperation.Builder withSelection(String, String[]);
     method public android.content.ContentProviderOperation.Builder withSelectionBackReference(int, int);
-    method public android.content.ContentProviderOperation.Builder withValue(java.lang.String, java.lang.Object);
-    method public android.content.ContentProviderOperation.Builder withValueBackReference(java.lang.String, int);
+    method public android.content.ContentProviderOperation.Builder withValue(String, Object);
+    method public android.content.ContentProviderOperation.Builder withValueBackReference(String, int);
     method public android.content.ContentProviderOperation.Builder withValueBackReferences(android.content.ContentValues);
     method public android.content.ContentProviderOperation.Builder withValues(android.content.ContentValues);
     method public android.content.ContentProviderOperation.Builder withYieldAllowed(boolean);
@@ -9419,121 +9468,121 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.ContentProviderResult> CREATOR;
-    field public final java.lang.Integer count;
+    field public final Integer count;
     field public final android.net.Uri uri;
   }
 
   public class ContentQueryMap extends java.util.Observable {
-    ctor public ContentQueryMap(android.database.Cursor, java.lang.String, boolean, android.os.Handler);
-    method public synchronized void close();
-    method public synchronized java.util.Map<java.lang.String, android.content.ContentValues> getRows();
-    method public synchronized android.content.ContentValues getValues(java.lang.String);
+    ctor public ContentQueryMap(android.database.Cursor, String, boolean, android.os.Handler);
+    method public void close();
+    method public java.util.Map<java.lang.String,android.content.ContentValues> getRows();
+    method public android.content.ContentValues getValues(String);
     method public void requery();
     method public void setKeepUpdated(boolean);
   }
 
   public abstract class ContentResolver implements android.content.ContentInterface {
     ctor public ContentResolver(android.content.Context);
-    method public final android.content.ContentProviderClient acquireContentProviderClient(android.net.Uri);
-    method public final android.content.ContentProviderClient acquireContentProviderClient(java.lang.String);
-    method public final android.content.ContentProviderClient acquireUnstableContentProviderClient(android.net.Uri);
-    method public final android.content.ContentProviderClient acquireUnstableContentProviderClient(java.lang.String);
-    method public static void addPeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle, long);
-    method public static java.lang.Object addStatusChangeListener(int, android.content.SyncStatusObserver);
-    method public android.content.ContentProviderResult[] applyBatch(java.lang.String, java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
-    method public final int bulkInsert(android.net.Uri, android.content.ContentValues[]);
-    method public final android.os.Bundle call(android.net.Uri, java.lang.String, java.lang.String, android.os.Bundle);
-    method public final android.os.Bundle call(java.lang.String, java.lang.String, java.lang.String, android.os.Bundle);
-    method public deprecated void cancelSync(android.net.Uri);
-    method public static void cancelSync(android.accounts.Account, java.lang.String);
+    method @Nullable public final android.content.ContentProviderClient acquireContentProviderClient(@NonNull android.net.Uri);
+    method @Nullable public final android.content.ContentProviderClient acquireContentProviderClient(@NonNull String);
+    method @Nullable public final android.content.ContentProviderClient acquireUnstableContentProviderClient(@NonNull android.net.Uri);
+    method @Nullable public final android.content.ContentProviderClient acquireUnstableContentProviderClient(@NonNull String);
+    method public static void addPeriodicSync(android.accounts.Account, String, android.os.Bundle, long);
+    method public static Object addStatusChangeListener(int, android.content.SyncStatusObserver);
+    method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull String, @NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
+    method public final int bulkInsert(@RequiresPermission.Write @NonNull android.net.Uri, @NonNull android.content.ContentValues[]);
+    method @Nullable public final android.os.Bundle call(@NonNull android.net.Uri, @NonNull String, @Nullable String, @Nullable android.os.Bundle);
+    method @Nullable public final android.os.Bundle call(@NonNull String, @NonNull String, @Nullable String, @Nullable android.os.Bundle);
+    method @Deprecated public void cancelSync(android.net.Uri);
+    method public static void cancelSync(android.accounts.Account, String);
     method public static void cancelSync(android.content.SyncRequest);
-    method public final android.net.Uri canonicalize(android.net.Uri);
-    method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+    method @Nullable public final android.net.Uri canonicalize(@NonNull android.net.Uri);
+    method public final int delete(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable String, @Nullable String[]);
     method public android.os.Bundle getCache(android.net.Uri);
-    method public static deprecated android.content.SyncInfo getCurrentSync();
+    method @Deprecated public static android.content.SyncInfo getCurrentSync();
     method public static java.util.List<android.content.SyncInfo> getCurrentSyncs();
-    method public static int getIsSyncable(android.accounts.Account, java.lang.String);
+    method public static int getIsSyncable(android.accounts.Account, String);
     method public static boolean getMasterSyncAutomatically();
-    method public java.util.List<android.content.UriPermission> getOutgoingPersistedUriPermissions();
-    method public static java.util.List<android.content.PeriodicSync> getPeriodicSyncs(android.accounts.Account, java.lang.String);
-    method public java.util.List<android.content.UriPermission> getPersistedUriPermissions();
-    method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String);
+    method @NonNull public java.util.List<android.content.UriPermission> getOutgoingPersistedUriPermissions();
+    method public static java.util.List<android.content.PeriodicSync> getPeriodicSyncs(android.accounts.Account, String);
+    method @NonNull public java.util.List<android.content.UriPermission> getPersistedUriPermissions();
+    method @Nullable public String[] getStreamTypes(@NonNull android.net.Uri, @NonNull String);
     method public static android.content.SyncAdapterType[] getSyncAdapterTypes();
-    method public static boolean getSyncAutomatically(android.accounts.Account, java.lang.String);
-    method public final java.lang.String getType(android.net.Uri);
-    method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
-    method public static boolean isSyncActive(android.accounts.Account, java.lang.String);
-    method public static boolean isSyncPending(android.accounts.Account, java.lang.String);
-    method public android.graphics.Bitmap loadThumbnail(android.net.Uri, android.util.Size, android.os.CancellationSignal) throws java.io.IOException;
-    method public void notifyChange(android.net.Uri, android.database.ContentObserver);
-    method public void notifyChange(android.net.Uri, android.database.ContentObserver, boolean);
-    method public void notifyChange(android.net.Uri, android.database.ContentObserver, int);
-    method public final android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
-    method public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public final android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public final android.os.ParcelFileDescriptor openFileDescriptor(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
-    method public final android.os.ParcelFileDescriptor openFileDescriptor(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public final java.io.InputStream openInputStream(android.net.Uri) throws java.io.FileNotFoundException;
-    method public final java.io.OutputStream openOutputStream(android.net.Uri) throws java.io.FileNotFoundException;
-    method public final java.io.OutputStream openOutputStream(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
-    method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
-    method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method public static boolean getSyncAutomatically(android.accounts.Account, String);
+    method @Nullable public final String getType(@NonNull android.net.Uri);
+    method @Nullable public final android.net.Uri insert(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable android.content.ContentValues);
+    method public static boolean isSyncActive(android.accounts.Account, String);
+    method public static boolean isSyncPending(android.accounts.Account, String);
+    method @NonNull public android.graphics.Bitmap loadThumbnail(@NonNull android.net.Uri, @NonNull android.util.Size, @Nullable android.os.CancellationSignal) throws java.io.IOException;
+    method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver);
+    method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, boolean);
+    method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, int);
+    method @Nullable public final android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
+    method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method @Nullable public final android.os.ParcelFileDescriptor openFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method @Nullable public final android.os.ParcelFileDescriptor openFileDescriptor(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
+    method @Nullable public final android.os.ParcelFileDescriptor openFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method @Nullable public final java.io.InputStream openInputStream(@NonNull android.net.Uri) throws java.io.FileNotFoundException;
+    method @Nullable public final java.io.OutputStream openOutputStream(@NonNull android.net.Uri) throws java.io.FileNotFoundException;
+    method @Nullable public final java.io.OutputStream openOutputStream(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
+    method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle) throws java.io.FileNotFoundException;
+    method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method public void putCache(android.net.Uri, android.os.Bundle);
-    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
-    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
-    method public final boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal);
-    method public final void registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver);
-    method public void releasePersistableUriPermission(android.net.Uri, int);
-    method public static void removePeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle);
-    method public static void removeStatusChangeListener(java.lang.Object);
-    method public static void requestSync(android.accounts.Account, java.lang.String, android.os.Bundle);
+    method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String);
+    method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal);
+    method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
+    method public final boolean refresh(@NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
+    method public final void registerContentObserver(@NonNull android.net.Uri, boolean, @NonNull android.database.ContentObserver);
+    method public void releasePersistableUriPermission(@NonNull android.net.Uri, int);
+    method public static void removePeriodicSync(android.accounts.Account, String, android.os.Bundle);
+    method public static void removeStatusChangeListener(Object);
+    method public static void requestSync(android.accounts.Account, String, android.os.Bundle);
     method public static void requestSync(android.content.SyncRequest);
-    method public static void setIsSyncable(android.accounts.Account, java.lang.String, int);
+    method public static void setIsSyncable(android.accounts.Account, String, int);
     method public static void setMasterSyncAutomatically(boolean);
-    method public static void setSyncAutomatically(android.accounts.Account, java.lang.String, boolean);
-    method public deprecated void startSync(android.net.Uri, android.os.Bundle);
-    method public void takePersistableUriPermission(android.net.Uri, int);
-    method public final android.net.Uri uncanonicalize(android.net.Uri);
-    method public final void unregisterContentObserver(android.database.ContentObserver);
-    method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+    method public static void setSyncAutomatically(android.accounts.Account, String, boolean);
+    method @Deprecated public void startSync(android.net.Uri, android.os.Bundle);
+    method public void takePersistableUriPermission(@NonNull android.net.Uri, int);
+    method @Nullable public final android.net.Uri uncanonicalize(@NonNull android.net.Uri);
+    method public final void unregisterContentObserver(@NonNull android.database.ContentObserver);
+    method public final int update(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[]);
     method public static void validateSyncExtrasBundle(android.os.Bundle);
-    field public static final java.lang.String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
-    field public static final java.lang.String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
-    field public static final java.lang.String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
-    field public static final java.lang.String EXTRA_HONORED_ARGS = "android.content.extra.HONORED_ARGS";
-    field public static final java.lang.String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED";
-    field public static final java.lang.String EXTRA_SIZE = "android.content.extra.SIZE";
-    field public static final java.lang.String EXTRA_TOTAL_COUNT = "android.content.extra.TOTAL_COUNT";
+    field public static final String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
+    field public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
+    field public static final String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
+    field public static final String EXTRA_HONORED_ARGS = "android.content.extra.HONORED_ARGS";
+    field public static final String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED";
+    field public static final String EXTRA_SIZE = "android.content.extra.SIZE";
+    field public static final String EXTRA_TOTAL_COUNT = "android.content.extra.TOTAL_COUNT";
     field public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 2; // 0x2
     field public static final int NOTIFY_SYNC_TO_NETWORK = 1; // 0x1
-    field public static final java.lang.String QUERY_ARG_LIMIT = "android:query-arg-limit";
-    field public static final java.lang.String QUERY_ARG_OFFSET = "android:query-arg-offset";
-    field public static final java.lang.String QUERY_ARG_SORT_COLLATION = "android:query-arg-sort-collation";
-    field public static final java.lang.String QUERY_ARG_SORT_COLUMNS = "android:query-arg-sort-columns";
-    field public static final java.lang.String QUERY_ARG_SORT_DIRECTION = "android:query-arg-sort-direction";
-    field public static final java.lang.String QUERY_ARG_SQL_SELECTION = "android:query-arg-sql-selection";
-    field public static final java.lang.String QUERY_ARG_SQL_SELECTION_ARGS = "android:query-arg-sql-selection-args";
-    field public static final java.lang.String QUERY_ARG_SQL_SORT_ORDER = "android:query-arg-sql-sort-order";
+    field public static final String QUERY_ARG_LIMIT = "android:query-arg-limit";
+    field public static final String QUERY_ARG_OFFSET = "android:query-arg-offset";
+    field public static final String QUERY_ARG_SORT_COLLATION = "android:query-arg-sort-collation";
+    field public static final String QUERY_ARG_SORT_COLUMNS = "android:query-arg-sort-columns";
+    field public static final String QUERY_ARG_SORT_DIRECTION = "android:query-arg-sort-direction";
+    field public static final String QUERY_ARG_SQL_SELECTION = "android:query-arg-sql-selection";
+    field public static final String QUERY_ARG_SQL_SELECTION_ARGS = "android:query-arg-sql-selection-args";
+    field public static final String QUERY_ARG_SQL_SORT_ORDER = "android:query-arg-sql-sort-order";
     field public static final int QUERY_SORT_DIRECTION_ASCENDING = 0; // 0x0
     field public static final int QUERY_SORT_DIRECTION_DESCENDING = 1; // 0x1
-    field public static final java.lang.String SCHEME_ANDROID_RESOURCE = "android.resource";
-    field public static final java.lang.String SCHEME_CONTENT = "content";
-    field public static final java.lang.String SCHEME_FILE = "file";
-    field public static final deprecated java.lang.String SYNC_EXTRAS_ACCOUNT = "account";
-    field public static final java.lang.String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
-    field public static final java.lang.String SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry";
-    field public static final java.lang.String SYNC_EXTRAS_EXPEDITED = "expedited";
-    field public static final deprecated java.lang.String SYNC_EXTRAS_FORCE = "force";
-    field public static final java.lang.String SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff";
-    field public static final java.lang.String SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings";
-    field public static final java.lang.String SYNC_EXTRAS_INITIALIZE = "initialize";
-    field public static final java.lang.String SYNC_EXTRAS_MANUAL = "force";
-    field public static final java.lang.String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
-    field public static final java.lang.String SYNC_EXTRAS_REQUIRE_CHARGING = "require_charging";
-    field public static final java.lang.String SYNC_EXTRAS_UPLOAD = "upload";
+    field public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
+    field public static final String SCHEME_CONTENT = "content";
+    field public static final String SCHEME_FILE = "file";
+    field @Deprecated public static final String SYNC_EXTRAS_ACCOUNT = "account";
+    field public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
+    field public static final String SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry";
+    field public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
+    field @Deprecated public static final String SYNC_EXTRAS_FORCE = "force";
+    field public static final String SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff";
+    field public static final String SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings";
+    field public static final String SYNC_EXTRAS_INITIALIZE = "initialize";
+    field public static final String SYNC_EXTRAS_MANUAL = "force";
+    field public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
+    field public static final String SYNC_EXTRAS_REQUIRE_CHARGING = "require_charging";
+    field public static final String SYNC_EXTRAS_UPLOAD = "upload";
     field public static final int SYNC_OBSERVER_TYPE_ACTIVE = 4; // 0x4
     field public static final int SYNC_OBSERVER_TYPE_PENDING = 2; // 0x2
     field public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1; // 0x1
@@ -9552,169 +9601,169 @@
     ctor public ContentValues(int);
     ctor public ContentValues(android.content.ContentValues);
     method public void clear();
-    method public boolean containsKey(java.lang.String);
+    method public boolean containsKey(String);
     method public int describeContents();
-    method public java.lang.Object get(java.lang.String);
-    method public java.lang.Boolean getAsBoolean(java.lang.String);
-    method public java.lang.Byte getAsByte(java.lang.String);
-    method public byte[] getAsByteArray(java.lang.String);
-    method public java.lang.Double getAsDouble(java.lang.String);
-    method public java.lang.Float getAsFloat(java.lang.String);
-    method public java.lang.Integer getAsInteger(java.lang.String);
-    method public java.lang.Long getAsLong(java.lang.String);
-    method public java.lang.Short getAsShort(java.lang.String);
-    method public java.lang.String getAsString(java.lang.String);
+    method public Object get(String);
+    method public Boolean getAsBoolean(String);
+    method public Byte getAsByte(String);
+    method public byte[] getAsByteArray(String);
+    method public Double getAsDouble(String);
+    method public Float getAsFloat(String);
+    method public Integer getAsInteger(String);
+    method public Long getAsLong(String);
+    method public Short getAsShort(String);
+    method public String getAsString(String);
     method public java.util.Set<java.lang.String> keySet();
-    method public void put(java.lang.String, java.lang.String);
-    method public void put(java.lang.String, java.lang.Byte);
-    method public void put(java.lang.String, java.lang.Short);
-    method public void put(java.lang.String, java.lang.Integer);
-    method public void put(java.lang.String, java.lang.Long);
-    method public void put(java.lang.String, java.lang.Float);
-    method public void put(java.lang.String, java.lang.Double);
-    method public void put(java.lang.String, java.lang.Boolean);
-    method public void put(java.lang.String, byte[]);
+    method public void put(String, String);
+    method public void put(String, Byte);
+    method public void put(String, Short);
+    method public void put(String, Integer);
+    method public void put(String, Long);
+    method public void put(String, Float);
+    method public void put(String, Double);
+    method public void put(String, Boolean);
+    method public void put(String, byte[]);
     method public void putAll(android.content.ContentValues);
-    method public void putNull(java.lang.String);
-    method public void remove(java.lang.String);
+    method public void putNull(String);
+    method public void remove(String);
     method public int size();
-    method public java.util.Set<java.util.Map.Entry<java.lang.String, java.lang.Object>> valueSet();
+    method public java.util.Set<java.util.Map.Entry<java.lang.String,java.lang.Object>> valueSet();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.ContentValues> CREATOR;
-    field public static final java.lang.String TAG = "ContentValues";
+    field public static final String TAG = "ContentValues";
   }
 
   public abstract class Context {
     ctor public Context();
-    method public abstract boolean bindIsolatedService(android.content.Intent, android.content.ServiceConnection, int, java.lang.String);
-    method public abstract boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
-    method public abstract int checkCallingOrSelfPermission(java.lang.String);
-    method public abstract int checkCallingOrSelfUriPermission(android.net.Uri, int);
-    method public abstract int checkCallingPermission(java.lang.String);
-    method public abstract int checkCallingUriPermission(android.net.Uri, int);
-    method public abstract int checkPermission(java.lang.String, int, int);
-    method public abstract int checkSelfPermission(java.lang.String);
-    method public abstract int checkUriPermission(android.net.Uri, int, int, int);
-    method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
-    method public abstract deprecated void clearWallpaper() throws java.io.IOException;
-    method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public abstract android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public boolean bindIsolatedService(@RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull String);
+    method public abstract boolean bindService(@RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int);
+    method @CheckResult(suggest="#enforceCallingOrSelfPermission(String,String)") public abstract int checkCallingOrSelfPermission(@NonNull String);
+    method @CheckResult(suggest="#enforceCallingOrSelfUriPermission(Uri,int,String)") public abstract int checkCallingOrSelfUriPermission(android.net.Uri, int);
+    method @CheckResult(suggest="#enforceCallingPermission(String,String)") public abstract int checkCallingPermission(@NonNull String);
+    method @CheckResult(suggest="#enforceCallingUriPermission(Uri,int,String)") public abstract int checkCallingUriPermission(android.net.Uri, int);
+    method @CheckResult(suggest="#enforcePermission(String,int,int,String)") public abstract int checkPermission(@NonNull String, int, int);
+    method public abstract int checkSelfPermission(@NonNull String);
+    method @CheckResult(suggest="#enforceUriPermission(Uri,int,int,String)") public abstract int checkUriPermission(android.net.Uri, int, int, int);
+    method @CheckResult(suggest="#enforceUriPermission(Uri,String,String,int,int,int,String)") public abstract int checkUriPermission(@Nullable android.net.Uri, @Nullable String, @Nullable String, int, int, int);
+    method @Deprecated public abstract void clearWallpaper() throws java.io.IOException;
+    method public abstract android.content.Context createConfigurationContext(@NonNull android.content.res.Configuration);
+    method public abstract android.content.Context createContextForSplit(String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.Context createDeviceProtectedStorageContext();
-    method public abstract android.content.Context createDisplayContext(android.view.Display);
-    method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract java.lang.String[] databaseList();
-    method public abstract boolean deleteDatabase(java.lang.String);
-    method public abstract boolean deleteFile(java.lang.String);
-    method public abstract boolean deleteSharedPreferences(java.lang.String);
-    method public abstract void enforceCallingOrSelfPermission(java.lang.String, java.lang.String);
-    method public abstract void enforceCallingOrSelfUriPermission(android.net.Uri, int, java.lang.String);
-    method public abstract void enforceCallingPermission(java.lang.String, java.lang.String);
-    method public abstract void enforceCallingUriPermission(android.net.Uri, int, java.lang.String);
-    method public abstract void enforcePermission(java.lang.String, int, int, java.lang.String);
-    method public abstract void enforceUriPermission(android.net.Uri, int, int, int, java.lang.String);
-    method public abstract void enforceUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int, java.lang.String);
-    method public abstract java.lang.String[] fileList();
+    method public abstract android.content.Context createDisplayContext(@NonNull android.view.Display);
+    method public abstract android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract String[] databaseList();
+    method public abstract boolean deleteDatabase(String);
+    method public abstract boolean deleteFile(String);
+    method public abstract boolean deleteSharedPreferences(String);
+    method public abstract void enforceCallingOrSelfPermission(@NonNull String, @Nullable String);
+    method public abstract void enforceCallingOrSelfUriPermission(android.net.Uri, int, String);
+    method public abstract void enforceCallingPermission(@NonNull String, @Nullable String);
+    method public abstract void enforceCallingUriPermission(android.net.Uri, int, String);
+    method public abstract void enforcePermission(@NonNull String, int, int, @Nullable String);
+    method public abstract void enforceUriPermission(android.net.Uri, int, int, int, String);
+    method public abstract void enforceUriPermission(@Nullable android.net.Uri, @Nullable String, @Nullable String, int, int, int, @Nullable String);
+    method public abstract String[] fileList();
     method public abstract android.content.Context getApplicationContext();
     method public abstract android.content.pm.ApplicationInfo getApplicationInfo();
     method public abstract android.content.res.AssetManager getAssets();
     method public abstract java.io.File getCacheDir();
-    method public abstract java.lang.ClassLoader getClassLoader();
+    method public abstract ClassLoader getClassLoader();
     method public abstract java.io.File getCodeCacheDir();
-    method public final int getColor(int);
-    method public final android.content.res.ColorStateList getColorStateList(int);
+    method @ColorInt public final int getColor(@ColorRes int);
+    method @NonNull public final android.content.res.ColorStateList getColorStateList(@ColorRes int);
     method public abstract android.content.ContentResolver getContentResolver();
     method public abstract java.io.File getDataDir();
-    method public abstract java.io.File getDatabasePath(java.lang.String);
-    method public abstract java.io.File getDir(java.lang.String, int);
-    method public final android.graphics.drawable.Drawable getDrawable(int);
-    method public abstract java.io.File getExternalCacheDir();
+    method public abstract java.io.File getDatabasePath(String);
+    method public abstract java.io.File getDir(String, int);
+    method @Nullable public final android.graphics.drawable.Drawable getDrawable(@DrawableRes int);
+    method @Nullable public abstract java.io.File getExternalCacheDir();
     method public abstract java.io.File[] getExternalCacheDirs();
-    method public abstract java.io.File getExternalFilesDir(java.lang.String);
-    method public abstract java.io.File[] getExternalFilesDirs(java.lang.String);
+    method @Nullable public abstract java.io.File getExternalFilesDir(@Nullable String);
+    method public abstract java.io.File[] getExternalFilesDirs(String);
     method public abstract java.io.File[] getExternalMediaDirs();
-    method public abstract java.io.File getFileStreamPath(java.lang.String);
+    method public abstract java.io.File getFileStreamPath(String);
     method public abstract java.io.File getFilesDir();
     method public java.util.concurrent.Executor getMainExecutor();
     method public abstract android.os.Looper getMainLooper();
     method public abstract java.io.File getNoBackupFilesDir();
     method public abstract java.io.File getObbDir();
     method public abstract java.io.File[] getObbDirs();
-    method public abstract java.lang.String getOpPackageName();
-    method public abstract java.lang.String getPackageCodePath();
+    method public String getOpPackageName();
+    method public abstract String getPackageCodePath();
     method public abstract android.content.pm.PackageManager getPackageManager();
-    method public abstract java.lang.String getPackageName();
-    method public abstract java.lang.String getPackageResourcePath();
+    method public abstract String getPackageName();
+    method public abstract String getPackageResourcePath();
     method public abstract android.content.res.Resources getResources();
-    method public abstract android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public final java.lang.String getString(int);
-    method public final java.lang.String getString(int, java.lang.Object...);
-    method public abstract java.lang.Object getSystemService(java.lang.String);
-    method public final <T> T getSystemService(java.lang.Class<T>);
-    method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
-    method public final java.lang.CharSequence getText(int);
-    method public abstract android.content.res.Resources.Theme getTheme();
-    method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
-    method public abstract deprecated int getWallpaperDesiredMinimumHeight();
-    method public abstract deprecated int getWallpaperDesiredMinimumWidth();
-    method public abstract void grantUriPermission(java.lang.String, android.net.Uri, int);
+    method public abstract android.content.SharedPreferences getSharedPreferences(String, int);
+    method @NonNull public final String getString(@StringRes int);
+    method @NonNull public final String getString(@StringRes int, java.lang.Object...);
+    method public abstract Object getSystemService(@NonNull String);
+    method public final <T> T getSystemService(@NonNull Class<T>);
+    method @Nullable public abstract String getSystemServiceName(@NonNull Class<?>);
+    method @NonNull public final CharSequence getText(@StringRes int);
+    method @android.view.ViewDebug.ExportedProperty(deepExport=true) public abstract android.content.res.Resources.Theme getTheme();
+    method @Deprecated public abstract android.graphics.drawable.Drawable getWallpaper();
+    method @Deprecated public abstract int getWallpaperDesiredMinimumHeight();
+    method @Deprecated public abstract int getWallpaperDesiredMinimumWidth();
+    method public abstract void grantUriPermission(String, android.net.Uri, int);
     method public abstract boolean isDeviceProtectedStorage();
     method public boolean isRestricted();
-    method public abstract boolean moveDatabaseFrom(android.content.Context, java.lang.String);
-    method public abstract boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
-    method public final android.content.res.TypedArray obtainStyledAttributes(int[]);
-    method public final android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
-    method public final android.content.res.TypedArray obtainStyledAttributes(android.util.AttributeSet, int[]);
-    method public final android.content.res.TypedArray obtainStyledAttributes(android.util.AttributeSet, int[], int, int);
-    method public abstract java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
-    method public abstract java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
-    method public abstract android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
-    method public abstract android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
-    method public abstract deprecated android.graphics.drawable.Drawable peekWallpaper();
+    method public abstract boolean moveDatabaseFrom(android.content.Context, String);
+    method public abstract boolean moveSharedPreferencesFrom(android.content.Context, String);
+    method @NonNull public final android.content.res.TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[]);
+    method @NonNull public final android.content.res.TypedArray obtainStyledAttributes(@StyleRes int, @NonNull @StyleableRes int[]) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public final android.content.res.TypedArray obtainStyledAttributes(@Nullable android.util.AttributeSet, @NonNull @StyleableRes int[]);
+    method @NonNull public final android.content.res.TypedArray obtainStyledAttributes(@Nullable android.util.AttributeSet, @NonNull @StyleableRes int[], @AttrRes int, @StyleRes int);
+    method public abstract java.io.FileInputStream openFileInput(String) throws java.io.FileNotFoundException;
+    method public abstract java.io.FileOutputStream openFileOutput(String, int) throws java.io.FileNotFoundException;
+    method public abstract android.database.sqlite.SQLiteDatabase openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
+    method public abstract android.database.sqlite.SQLiteDatabase openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, @Nullable android.database.DatabaseErrorHandler);
+    method @Deprecated public abstract android.graphics.drawable.Drawable peekWallpaper();
     method public void registerComponentCallbacks(android.content.ComponentCallbacks);
-    method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
-    method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
-    method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
-    method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
-    method public abstract deprecated void removeStickyBroadcast(android.content.Intent);
-    method public abstract deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+    method @Nullable public abstract android.content.Intent registerReceiver(@Nullable android.content.BroadcastReceiver, android.content.IntentFilter);
+    method @Nullable public abstract android.content.Intent registerReceiver(@Nullable android.content.BroadcastReceiver, android.content.IntentFilter, int);
+    method @Nullable public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler);
+    method @Nullable public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void removeStickyBroadcast(@RequiresPermission android.content.Intent);
+    method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void removeStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
     method public abstract void revokeUriPermission(android.net.Uri, int);
-    method public abstract void revokeUriPermission(java.lang.String, android.net.Uri, int);
-    method public abstract void sendBroadcast(android.content.Intent);
-    method public abstract void sendBroadcast(android.content.Intent, java.lang.String);
-    method public abstract void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle);
-    method public abstract void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String);
-    method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String);
-    method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public abstract void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public abstract deprecated void sendStickyBroadcast(android.content.Intent);
-    method public abstract deprecated void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
-    method public abstract deprecated void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public abstract deprecated void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public abstract void setTheme(int);
-    method public abstract deprecated void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
-    method public abstract deprecated void setWallpaper(java.io.InputStream) throws java.io.IOException;
-    method public abstract void startActivities(android.content.Intent[]);
-    method public abstract void startActivities(android.content.Intent[], android.os.Bundle);
-    method public abstract void startActivity(android.content.Intent);
-    method public abstract void startActivity(android.content.Intent, android.os.Bundle);
-    method public abstract android.content.ComponentName startForegroundService(android.content.Intent);
-    method public abstract boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
-    method public abstract void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
-    method public abstract void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
-    method public abstract android.content.ComponentName startService(android.content.Intent);
+    method public abstract void revokeUriPermission(String, android.net.Uri, int);
+    method public abstract void sendBroadcast(@RequiresPermission android.content.Intent);
+    method public abstract void sendBroadcast(@RequiresPermission android.content.Intent, @Nullable String);
+    method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
+    method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String);
+    method public abstract void sendOrderedBroadcast(@RequiresPermission android.content.Intent, @Nullable String);
+    method public abstract void sendOrderedBroadcast(@RequiresPermission @NonNull android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+    method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyBroadcast(@RequiresPermission android.content.Intent);
+    method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyOrderedBroadcast(@RequiresPermission android.content.Intent, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+    method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+    method public abstract void setTheme(@StyleRes int);
+    method @Deprecated public abstract void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
+    method @Deprecated public abstract void setWallpaper(java.io.InputStream) throws java.io.IOException;
+    method public abstract void startActivities(@RequiresPermission android.content.Intent[]);
+    method public abstract void startActivities(@RequiresPermission android.content.Intent[], android.os.Bundle);
+    method public abstract void startActivity(@RequiresPermission android.content.Intent);
+    method public abstract void startActivity(@RequiresPermission android.content.Intent, @Nullable android.os.Bundle);
+    method @Nullable public abstract android.content.ComponentName startForegroundService(android.content.Intent);
+    method public abstract boolean startInstrumentation(@NonNull android.content.ComponentName, @Nullable String, @Nullable android.os.Bundle);
+    method public abstract void startIntentSender(android.content.IntentSender, @Nullable android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
+    method public abstract void startIntentSender(android.content.IntentSender, @Nullable android.content.Intent, int, int, int, @Nullable android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method @Nullable public abstract android.content.ComponentName startService(android.content.Intent);
     method public abstract boolean stopService(android.content.Intent);
-    method public abstract void unbindService(android.content.ServiceConnection);
+    method public abstract void unbindService(@NonNull android.content.ServiceConnection);
     method public void unregisterComponentCallbacks(android.content.ComponentCallbacks);
     method public abstract void unregisterReceiver(android.content.BroadcastReceiver);
-    method public abstract void updateServiceGroup(android.content.ServiceConnection, int, int);
-    field public static final java.lang.String ACCESSIBILITY_SERVICE = "accessibility";
-    field public static final java.lang.String ACCOUNT_SERVICE = "account";
-    field public static final java.lang.String ACTIVITY_SERVICE = "activity";
-    field public static final java.lang.String ALARM_SERVICE = "alarm";
-    field public static final java.lang.String APPWIDGET_SERVICE = "appwidget";
-    field public static final java.lang.String APP_OPS_SERVICE = "appops";
-    field public static final java.lang.String AUDIO_SERVICE = "audio";
-    field public static final java.lang.String BATTERY_SERVICE = "batterymanager";
+    method public void updateServiceGroup(@NonNull android.content.ServiceConnection, int, int);
+    field public static final String ACCESSIBILITY_SERVICE = "accessibility";
+    field public static final String ACCOUNT_SERVICE = "account";
+    field public static final String ACTIVITY_SERVICE = "activity";
+    field public static final String ALARM_SERVICE = "alarm";
+    field public static final String APPWIDGET_SERVICE = "appwidget";
+    field public static final String APP_OPS_SERVICE = "appops";
+    field public static final String AUDIO_SERVICE = "audio";
+    field public static final String BATTERY_SERVICE = "batterymanager";
     field public static final int BIND_ABOVE_CLIENT = 8; // 0x8
     field public static final int BIND_ADJUST_WITH_ACTIVITY = 128; // 0x80
     field public static final int BIND_ALLOW_OOM_MANAGEMENT = 16; // 0x10
@@ -9724,242 +9773,239 @@
     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";
-    field public static final java.lang.String CARRIER_CONFIG_SERVICE = "carrier_config";
-    field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
-    field public static final java.lang.String COMPANION_DEVICE_SERVICE = "companiondevice";
-    field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
-    field public static final java.lang.String CONSUMER_IR_SERVICE = "consumer_ir";
+    field public static final String BIOMETRIC_SERVICE = "biometric";
+    field public static final String BLUETOOTH_SERVICE = "bluetooth";
+    field public static final String CAMERA_SERVICE = "camera";
+    field public static final String CAPTIONING_SERVICE = "captioning";
+    field public static final String CARRIER_CONFIG_SERVICE = "carrier_config";
+    field public static final String CLIPBOARD_SERVICE = "clipboard";
+    field public static final String COMPANION_DEVICE_SERVICE = "companiondevice";
+    field public static final String CONNECTIVITY_SERVICE = "connectivity";
+    field public static final String CONSUMER_IR_SERVICE = "consumer_ir";
     field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
     field public static final int CONTEXT_INCLUDE_CODE = 1; // 0x1
     field public static final int CONTEXT_RESTRICTED = 4; // 0x4
-    field public static final java.lang.String CROSS_PROFILE_APPS_SERVICE = "crossprofileapps";
-    field public static final java.lang.String DEVICE_POLICY_SERVICE = "device_policy";
-    field public static final java.lang.String DISPLAY_SERVICE = "display";
-    field public static final java.lang.String DOWNLOAD_SERVICE = "download";
-    field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
-    field public static final java.lang.String EUICC_SERVICE = "euicc";
-    field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
-    field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
-    field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
-    field public static final java.lang.String INPUT_SERVICE = "input";
-    field public static final java.lang.String IPSEC_SERVICE = "ipsec";
-    field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
-    field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
-    field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
-    field public static final java.lang.String LAYOUT_INFLATER_SERVICE = "layout_inflater";
-    field public static final java.lang.String LOCATION_SERVICE = "location";
-    field public static final java.lang.String MEDIA_PROJECTION_SERVICE = "media_projection";
-    field public static final java.lang.String MEDIA_ROUTER_SERVICE = "media_router";
-    field public static final java.lang.String MEDIA_SESSION_SERVICE = "media_session";
-    field public static final java.lang.String MIDI_SERVICE = "midi";
+    field public static final String CROSS_PROFILE_APPS_SERVICE = "crossprofileapps";
+    field public static final String DEVICE_POLICY_SERVICE = "device_policy";
+    field public static final String DISPLAY_SERVICE = "display";
+    field public static final String DOWNLOAD_SERVICE = "download";
+    field public static final String DROPBOX_SERVICE = "dropbox";
+    field public static final String EUICC_SERVICE = "euicc";
+    field public static final String FINGERPRINT_SERVICE = "fingerprint";
+    field public static final String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
+    field public static final String INPUT_METHOD_SERVICE = "input_method";
+    field public static final String INPUT_SERVICE = "input";
+    field public static final String IPSEC_SERVICE = "ipsec";
+    field public static final String JOB_SCHEDULER_SERVICE = "jobscheduler";
+    field public static final String KEYGUARD_SERVICE = "keyguard";
+    field public static final String LAUNCHER_APPS_SERVICE = "launcherapps";
+    field public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
+    field public static final String LOCATION_SERVICE = "location";
+    field public static final String MEDIA_PROJECTION_SERVICE = "media_projection";
+    field public static final String MEDIA_ROUTER_SERVICE = "media_router";
+    field public static final String MEDIA_SESSION_SERVICE = "media_session";
+    field public static final String MIDI_SERVICE = "midi";
     field public static final int MODE_APPEND = 32768; // 0x8000
     field public static final int MODE_ENABLE_WRITE_AHEAD_LOGGING = 8; // 0x8
-    field public static final deprecated int MODE_MULTI_PROCESS = 4; // 0x4
+    field @Deprecated public static final int MODE_MULTI_PROCESS = 4; // 0x4
     field public static final int MODE_NO_LOCALIZED_COLLATORS = 16; // 0x10
     field public static final int MODE_PRIVATE = 0; // 0x0
-    field public static final deprecated int MODE_WORLD_READABLE = 1; // 0x1
-    field public static final deprecated int MODE_WORLD_WRITEABLE = 2; // 0x2
-    field public static final java.lang.String NETWORK_STATS_SERVICE = "netstats";
-    field public static final java.lang.String NFC_SERVICE = "nfc";
-    field public static final java.lang.String NOTIFICATION_SERVICE = "notification";
-    field public static final java.lang.String NSD_SERVICE = "servicediscovery";
-    field public static final java.lang.String POWER_SERVICE = "power";
-    field public static final java.lang.String PRINT_SERVICE = "print";
+    field @Deprecated public static final int MODE_WORLD_READABLE = 1; // 0x1
+    field @Deprecated public static final int MODE_WORLD_WRITEABLE = 2; // 0x2
+    field public static final String NETWORK_STATS_SERVICE = "netstats";
+    field public static final String NFC_SERVICE = "nfc";
+    field public static final String NOTIFICATION_SERVICE = "notification";
+    field public static final String NSD_SERVICE = "servicediscovery";
+    field public static final String POWER_SERVICE = "power";
+    field public static final String PRINT_SERVICE = "print";
     field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
-    field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
-    field public static final java.lang.String ROLE_SERVICE = "role";
-    field public static final java.lang.String SEARCH_SERVICE = "search";
-    field public static final java.lang.String SENSOR_SERVICE = "sensor";
-    field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
-    field public static final java.lang.String STORAGE_SERVICE = "storage";
-    field public static final java.lang.String STORAGE_STATS_SERVICE = "storagestats";
-    field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
-    field public static final java.lang.String TELECOM_SERVICE = "telecom";
-    field public static final java.lang.String TELEPHONY_SERVICE = "phone";
-    field public static final java.lang.String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
-    field public static final java.lang.String TEXT_CLASSIFICATION_SERVICE = "textclassification";
-    field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
-    field public static final java.lang.String TV_INPUT_SERVICE = "tv_input";
-    field public static final java.lang.String UI_MODE_SERVICE = "uimode";
-    field public static final java.lang.String USAGE_STATS_SERVICE = "usagestats";
-    field public static final java.lang.String USB_SERVICE = "usb";
-    field public static final java.lang.String USER_SERVICE = "user";
-    field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
-    field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
-    field public static final java.lang.String WIFI_AWARE_SERVICE = "wifiaware";
-    field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
-    field public static final java.lang.String WIFI_RTT_RANGING_SERVICE = "wifirtt";
-    field public static final java.lang.String WIFI_SERVICE = "wifi";
-    field public static final java.lang.String WINDOW_SERVICE = "window";
+    field public static final String RESTRICTIONS_SERVICE = "restrictions";
+    field public static final String ROLE_SERVICE = "role";
+    field public static final String SEARCH_SERVICE = "search";
+    field public static final String SENSOR_SERVICE = "sensor";
+    field public static final String SHORTCUT_SERVICE = "shortcut";
+    field public static final String STORAGE_SERVICE = "storage";
+    field public static final String STORAGE_STATS_SERVICE = "storagestats";
+    field public static final String SYSTEM_HEALTH_SERVICE = "systemhealth";
+    field public static final String TELECOM_SERVICE = "telecom";
+    field public static final String TELEPHONY_SERVICE = "phone";
+    field public static final String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
+    field public static final String TEXT_CLASSIFICATION_SERVICE = "textclassification";
+    field public static final String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
+    field public static final String TV_INPUT_SERVICE = "tv_input";
+    field public static final String UI_MODE_SERVICE = "uimode";
+    field public static final String USAGE_STATS_SERVICE = "usagestats";
+    field public static final String USB_SERVICE = "usb";
+    field public static final String USER_SERVICE = "user";
+    field public static final String VIBRATOR_SERVICE = "vibrator";
+    field public static final String WALLPAPER_SERVICE = "wallpaper";
+    field public static final String WIFI_AWARE_SERVICE = "wifiaware";
+    field public static final String WIFI_P2P_SERVICE = "wifip2p";
+    field public static final String WIFI_RTT_RANGING_SERVICE = "wifirtt";
+    field public static final String WIFI_SERVICE = "wifi";
+    field public static final String WINDOW_SERVICE = "window";
   }
 
   public class ContextWrapper extends android.content.Context {
     ctor public ContextWrapper(android.content.Context);
     method protected void attachBaseContext(android.content.Context);
-    method public boolean bindIsolatedService(android.content.Intent, android.content.ServiceConnection, int, java.lang.String);
     method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
-    method public int checkCallingOrSelfPermission(java.lang.String);
+    method public int checkCallingOrSelfPermission(String);
     method public int checkCallingOrSelfUriPermission(android.net.Uri, int);
-    method public int checkCallingPermission(java.lang.String);
+    method public int checkCallingPermission(String);
     method public int checkCallingUriPermission(android.net.Uri, int);
-    method public int checkPermission(java.lang.String, int, int);
-    method public int checkSelfPermission(java.lang.String);
+    method public int checkPermission(String, int, int);
+    method public int checkSelfPermission(String);
     method public int checkUriPermission(android.net.Uri, int, int, int);
-    method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
-    method public deprecated void clearWallpaper() throws java.io.IOException;
+    method public int checkUriPermission(android.net.Uri, String, String, int, int, int);
+    method @Deprecated public void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public android.content.Context createContextForSplit(String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.Context createDeviceProtectedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
-    method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public java.lang.String[] databaseList();
-    method public boolean deleteDatabase(java.lang.String);
-    method public boolean deleteFile(java.lang.String);
-    method public boolean deleteSharedPreferences(java.lang.String);
-    method public void enforceCallingOrSelfPermission(java.lang.String, java.lang.String);
-    method public void enforceCallingOrSelfUriPermission(android.net.Uri, int, java.lang.String);
-    method public void enforceCallingPermission(java.lang.String, java.lang.String);
-    method public void enforceCallingUriPermission(android.net.Uri, int, java.lang.String);
-    method public void enforcePermission(java.lang.String, int, int, java.lang.String);
-    method public void enforceUriPermission(android.net.Uri, int, int, int, java.lang.String);
-    method public void enforceUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int, java.lang.String);
-    method public java.lang.String[] fileList();
+    method public android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public String[] databaseList();
+    method public boolean deleteDatabase(String);
+    method public boolean deleteFile(String);
+    method public boolean deleteSharedPreferences(String);
+    method public void enforceCallingOrSelfPermission(String, String);
+    method public void enforceCallingOrSelfUriPermission(android.net.Uri, int, String);
+    method public void enforceCallingPermission(String, String);
+    method public void enforceCallingUriPermission(android.net.Uri, int, String);
+    method public void enforcePermission(String, int, int, String);
+    method public void enforceUriPermission(android.net.Uri, int, int, int, String);
+    method public void enforceUriPermission(android.net.Uri, String, String, int, int, int, String);
+    method public String[] fileList();
     method public android.content.Context getApplicationContext();
     method public android.content.pm.ApplicationInfo getApplicationInfo();
     method public android.content.res.AssetManager getAssets();
     method public android.content.Context getBaseContext();
     method public java.io.File getCacheDir();
-    method public java.lang.ClassLoader getClassLoader();
+    method public ClassLoader getClassLoader();
     method public java.io.File getCodeCacheDir();
     method public android.content.ContentResolver getContentResolver();
     method public java.io.File getDataDir();
-    method public java.io.File getDatabasePath(java.lang.String);
-    method public java.io.File getDir(java.lang.String, int);
+    method public java.io.File getDatabasePath(String);
+    method public java.io.File getDir(String, int);
     method public java.io.File getExternalCacheDir();
     method public java.io.File[] getExternalCacheDirs();
-    method public java.io.File getExternalFilesDir(java.lang.String);
-    method public java.io.File[] getExternalFilesDirs(java.lang.String);
+    method public java.io.File getExternalFilesDir(String);
+    method public java.io.File[] getExternalFilesDirs(String);
     method public java.io.File[] getExternalMediaDirs();
-    method public java.io.File getFileStreamPath(java.lang.String);
+    method public java.io.File getFileStreamPath(String);
     method public java.io.File getFilesDir();
     method public android.os.Looper getMainLooper();
     method public java.io.File getNoBackupFilesDir();
     method public java.io.File getObbDir();
     method public java.io.File[] getObbDirs();
-    method public java.lang.String getOpPackageName();
-    method public java.lang.String getPackageCodePath();
+    method public String getPackageCodePath();
     method public android.content.pm.PackageManager getPackageManager();
-    method public java.lang.String getPackageName();
-    method public java.lang.String getPackageResourcePath();
+    method public String getPackageName();
+    method public String getPackageResourcePath();
     method public android.content.res.Resources getResources();
-    method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public java.lang.Object getSystemService(java.lang.String);
-    method public java.lang.String getSystemServiceName(java.lang.Class<?>);
+    method public android.content.SharedPreferences getSharedPreferences(String, int);
+    method public Object getSystemService(String);
+    method public String getSystemServiceName(Class<?>);
     method public android.content.res.Resources.Theme getTheme();
-    method public deprecated android.graphics.drawable.Drawable getWallpaper();
-    method public deprecated int getWallpaperDesiredMinimumHeight();
-    method public deprecated int getWallpaperDesiredMinimumWidth();
-    method public void grantUriPermission(java.lang.String, android.net.Uri, int);
+    method @Deprecated public android.graphics.drawable.Drawable getWallpaper();
+    method @Deprecated public int getWallpaperDesiredMinimumHeight();
+    method @Deprecated public int getWallpaperDesiredMinimumWidth();
+    method public void grantUriPermission(String, android.net.Uri, int);
     method public boolean isDeviceProtectedStorage();
-    method public boolean moveDatabaseFrom(android.content.Context, java.lang.String);
-    method public boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
-    method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
-    method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
-    method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
-    method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
-    method public deprecated android.graphics.drawable.Drawable peekWallpaper();
+    method public boolean moveDatabaseFrom(android.content.Context, String);
+    method public boolean moveSharedPreferencesFrom(android.content.Context, String);
+    method public java.io.FileInputStream openFileInput(String) throws java.io.FileNotFoundException;
+    method public java.io.FileOutputStream openFileOutput(String, int) throws java.io.FileNotFoundException;
+    method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
+    method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
+    method @Deprecated public android.graphics.drawable.Drawable peekWallpaper();
     method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
     method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
-    method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
-    method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
-    method public deprecated void removeStickyBroadcast(android.content.Intent);
-    method public deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+    method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler);
+    method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler, int);
+    method @Deprecated public void removeStickyBroadcast(android.content.Intent);
+    method @Deprecated public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public void revokeUriPermission(android.net.Uri, int);
-    method public void revokeUriPermission(java.lang.String, android.net.Uri, int);
+    method public void revokeUriPermission(String, android.net.Uri, int);
     method public void sendBroadcast(android.content.Intent);
-    method public void sendBroadcast(android.content.Intent, java.lang.String);
+    method public void sendBroadcast(android.content.Intent, String);
     method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle);
-    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String);
-    method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
-    method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public deprecated void sendStickyBroadcast(android.content.Intent);
-    method public deprecated void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
-    method public deprecated void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public deprecated void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, String);
+    method public void sendOrderedBroadcast(android.content.Intent, String);
+    method public void sendOrderedBroadcast(android.content.Intent, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
+    method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
+    method @Deprecated public void sendStickyBroadcast(android.content.Intent);
+    method @Deprecated public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+    method @Deprecated public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
+    method @Deprecated public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
     method public void setTheme(int);
-    method public deprecated void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
-    method public deprecated void setWallpaper(java.io.InputStream) throws java.io.IOException;
+    method @Deprecated public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
+    method @Deprecated public void setWallpaper(java.io.InputStream) throws java.io.IOException;
     method public void startActivities(android.content.Intent[]);
     method public void startActivities(android.content.Intent[], android.os.Bundle);
     method public void startActivity(android.content.Intent);
     method public void startActivity(android.content.Intent, android.os.Bundle);
     method public android.content.ComponentName startForegroundService(android.content.Intent);
-    method public boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
+    method public boolean startInstrumentation(android.content.ComponentName, String, android.os.Bundle);
     method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public android.content.ComponentName startService(android.content.Intent);
     method public boolean stopService(android.content.Intent);
     method public void unbindService(android.content.ServiceConnection);
     method public void unregisterReceiver(android.content.BroadcastReceiver);
-    method public void updateServiceGroup(android.content.ServiceConnection, int, int);
   }
 
-  public deprecated class CursorLoader extends android.content.AsyncTaskLoader {
-    ctor public CursorLoader(android.content.Context);
-    ctor public CursorLoader(android.content.Context, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public void deliverResult(android.database.Cursor);
-    method public java.lang.String[] getProjection();
-    method public java.lang.String getSelection();
-    method public java.lang.String[] getSelectionArgs();
-    method public java.lang.String getSortOrder();
-    method public android.net.Uri getUri();
-    method public android.database.Cursor loadInBackground();
-    method public void onCanceled(android.database.Cursor);
-    method public void setProjection(java.lang.String[]);
-    method public void setSelection(java.lang.String);
-    method public void setSelectionArgs(java.lang.String[]);
-    method public void setSortOrder(java.lang.String);
-    method public void setUri(android.net.Uri);
+  @Deprecated public class CursorLoader extends android.content.AsyncTaskLoader<android.database.Cursor> {
+    ctor @Deprecated public CursorLoader(android.content.Context);
+    ctor @Deprecated public CursorLoader(android.content.Context, android.net.Uri, String[], String, String[], String);
+    method @Deprecated public void deliverResult(android.database.Cursor);
+    method @Deprecated public String[] getProjection();
+    method @Deprecated public String getSelection();
+    method @Deprecated public String[] getSelectionArgs();
+    method @Deprecated public String getSortOrder();
+    method @Deprecated public android.net.Uri getUri();
+    method @Deprecated public android.database.Cursor loadInBackground();
+    method @Deprecated public void onCanceled(android.database.Cursor);
+    method @Deprecated public void setProjection(String[]);
+    method @Deprecated public void setSelection(String);
+    method @Deprecated public void setSelectionArgs(String[]);
+    method @Deprecated public void setSortOrder(String);
+    method @Deprecated public void setUri(android.net.Uri);
   }
 
-  public abstract interface DialogInterface {
-    method public abstract void cancel();
-    method public abstract void dismiss();
-    field public static final deprecated int BUTTON1 = -1; // 0xffffffff
-    field public static final deprecated int BUTTON2 = -2; // 0xfffffffe
-    field public static final deprecated int BUTTON3 = -3; // 0xfffffffd
+  public interface DialogInterface {
+    method public void cancel();
+    method public void dismiss();
+    field @Deprecated public static final int BUTTON1 = -1; // 0xffffffff
+    field @Deprecated public static final int BUTTON2 = -2; // 0xfffffffe
+    field @Deprecated public static final int BUTTON3 = -3; // 0xfffffffd
     field public static final int BUTTON_NEGATIVE = -2; // 0xfffffffe
     field public static final int BUTTON_NEUTRAL = -3; // 0xfffffffd
     field public static final int BUTTON_POSITIVE = -1; // 0xffffffff
   }
 
-  public static abstract interface DialogInterface.OnCancelListener {
-    method public abstract void onCancel(android.content.DialogInterface);
+  public static interface DialogInterface.OnCancelListener {
+    method public void onCancel(android.content.DialogInterface);
   }
 
-  public static abstract interface DialogInterface.OnClickListener {
-    method public abstract void onClick(android.content.DialogInterface, int);
+  public static interface DialogInterface.OnClickListener {
+    method public void onClick(android.content.DialogInterface, int);
   }
 
-  public static abstract interface DialogInterface.OnDismissListener {
-    method public abstract void onDismiss(android.content.DialogInterface);
+  public static interface DialogInterface.OnDismissListener {
+    method public void onDismiss(android.content.DialogInterface);
   }
 
-  public static abstract interface DialogInterface.OnKeyListener {
-    method public abstract boolean onKey(android.content.DialogInterface, int, android.view.KeyEvent);
+  public static interface DialogInterface.OnKeyListener {
+    method public boolean onKey(android.content.DialogInterface, int, android.view.KeyEvent);
   }
 
-  public static abstract interface DialogInterface.OnMultiChoiceClickListener {
-    method public abstract void onClick(android.content.DialogInterface, int, boolean);
+  public static interface DialogInterface.OnMultiChoiceClickListener {
+    method public void onClick(android.content.DialogInterface, int, boolean);
   }
 
-  public static abstract interface DialogInterface.OnShowListener {
-    method public abstract void onShow(android.content.DialogInterface);
+  public static interface DialogInterface.OnShowListener {
+    method public void onShow(android.content.DialogInterface);
   }
 
   public final class Entity {
@@ -9975,383 +10021,387 @@
     field public final android.content.ContentValues values;
   }
 
-  public abstract interface EntityIterator implements java.util.Iterator {
-    method public abstract void close();
-    method public abstract void reset();
+  public interface EntityIterator extends java.util.Iterator<android.content.Entity> {
+    method public void close();
+    method public void reset();
   }
 
   public class Intent implements java.lang.Cloneable android.os.Parcelable {
     ctor public Intent();
     ctor public Intent(android.content.Intent);
-    ctor public Intent(java.lang.String);
-    ctor public Intent(java.lang.String, android.net.Uri);
-    ctor public Intent(android.content.Context, java.lang.Class<?>);
-    ctor public Intent(java.lang.String, android.net.Uri, android.content.Context, java.lang.Class<?>);
-    method public android.content.Intent addCategory(java.lang.String);
-    method public android.content.Intent addFlags(int);
-    method public java.lang.Object clone();
-    method public android.content.Intent cloneFilter();
-    method public static android.content.Intent createChooser(android.content.Intent, java.lang.CharSequence);
-    method public static android.content.Intent createChooser(android.content.Intent, java.lang.CharSequence, android.content.IntentSender);
+    ctor public Intent(String);
+    ctor public Intent(String, android.net.Uri);
+    ctor public Intent(android.content.Context, Class<?>);
+    ctor public Intent(String, android.net.Uri, android.content.Context, Class<?>);
+    method @NonNull public android.content.Intent addCategory(String);
+    method @NonNull public android.content.Intent addFlags(int);
+    method public Object clone();
+    method @NonNull public android.content.Intent cloneFilter();
+    method public static android.content.Intent createChooser(android.content.Intent, CharSequence);
+    method public static android.content.Intent createChooser(android.content.Intent, CharSequence, android.content.IntentSender);
     method public int describeContents();
-    method public int fillIn(android.content.Intent, int);
+    method public int fillIn(@NonNull android.content.Intent, int);
     method public boolean filterEquals(android.content.Intent);
     method public int filterHashCode();
-    method public java.lang.String getAction();
-    method public boolean[] getBooleanArrayExtra(java.lang.String);
-    method public boolean getBooleanExtra(java.lang.String, boolean);
-    method public android.os.Bundle getBundleExtra(java.lang.String);
-    method public byte[] getByteArrayExtra(java.lang.String);
-    method public byte getByteExtra(java.lang.String, byte);
+    method @Nullable public String getAction();
+    method @Nullable public boolean[] getBooleanArrayExtra(String);
+    method public boolean getBooleanExtra(String, boolean);
+    method @Nullable public android.os.Bundle getBundleExtra(String);
+    method @Nullable public byte[] getByteArrayExtra(String);
+    method public byte getByteExtra(String, byte);
     method public java.util.Set<java.lang.String> getCategories();
-    method public char[] getCharArrayExtra(java.lang.String);
-    method public char getCharExtra(java.lang.String, char);
-    method public java.lang.CharSequence[] getCharSequenceArrayExtra(java.lang.String);
-    method public java.util.ArrayList<java.lang.CharSequence> getCharSequenceArrayListExtra(java.lang.String);
-    method public java.lang.CharSequence getCharSequenceExtra(java.lang.String);
-    method public android.content.ClipData getClipData();
-    method public android.content.ComponentName getComponent();
-    method public android.net.Uri getData();
-    method public java.lang.String getDataString();
-    method public double[] getDoubleArrayExtra(java.lang.String);
-    method public double getDoubleExtra(java.lang.String, double);
-    method public android.os.Bundle getExtras();
+    method @Nullable public char[] getCharArrayExtra(String);
+    method public char getCharExtra(String, char);
+    method @Nullable public CharSequence[] getCharSequenceArrayExtra(String);
+    method @Nullable public java.util.ArrayList<java.lang.CharSequence> getCharSequenceArrayListExtra(String);
+    method @Nullable public CharSequence getCharSequenceExtra(String);
+    method @Nullable public android.content.ClipData getClipData();
+    method @Nullable public android.content.ComponentName getComponent();
+    method @Nullable public android.net.Uri getData();
+    method @Nullable public String getDataString();
+    method @Nullable public double[] getDoubleArrayExtra(String);
+    method public double getDoubleExtra(String, double);
+    method @Nullable public android.os.Bundle getExtras();
     method public int getFlags();
-    method public float[] getFloatArrayExtra(java.lang.String);
-    method public float getFloatExtra(java.lang.String, float);
-    method public int[] getIntArrayExtra(java.lang.String);
-    method public int getIntExtra(java.lang.String, int);
-    method public java.util.ArrayList<java.lang.Integer> getIntegerArrayListExtra(java.lang.String);
-    method public static deprecated android.content.Intent getIntent(java.lang.String) throws java.net.URISyntaxException;
-    method public static android.content.Intent getIntentOld(java.lang.String) throws java.net.URISyntaxException;
-    method public long[] getLongArrayExtra(java.lang.String);
-    method public long getLongExtra(java.lang.String, long);
-    method public java.lang.String getPackage();
-    method public android.os.Parcelable[] getParcelableArrayExtra(java.lang.String);
-    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(java.lang.String);
-    method public <T extends android.os.Parcelable> T getParcelableExtra(java.lang.String);
-    method public java.lang.String getScheme();
-    method public android.content.Intent getSelector();
-    method public java.io.Serializable getSerializableExtra(java.lang.String);
-    method public short[] getShortArrayExtra(java.lang.String);
-    method public short getShortExtra(java.lang.String, short);
-    method public android.graphics.Rect getSourceBounds();
-    method public java.lang.String[] getStringArrayExtra(java.lang.String);
-    method public java.util.ArrayList<java.lang.String> getStringArrayListExtra(java.lang.String);
-    method public java.lang.String getStringExtra(java.lang.String);
-    method public java.lang.String getType();
-    method public boolean hasCategory(java.lang.String);
-    method public boolean hasExtra(java.lang.String);
+    method @Nullable public float[] getFloatArrayExtra(String);
+    method public float getFloatExtra(String, float);
+    method @Nullable public int[] getIntArrayExtra(String);
+    method public int getIntExtra(String, int);
+    method @Nullable public java.util.ArrayList<java.lang.Integer> getIntegerArrayListExtra(String);
+    method @Deprecated public static android.content.Intent getIntent(String) throws java.net.URISyntaxException;
+    method public static android.content.Intent getIntentOld(String) throws java.net.URISyntaxException;
+    method @Nullable public long[] getLongArrayExtra(String);
+    method public long getLongExtra(String, long);
+    method @Nullable public String getPackage();
+    method @Nullable public android.os.Parcelable[] getParcelableArrayExtra(String);
+    method @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(String);
+    method @Nullable public <T extends android.os.Parcelable> T getParcelableExtra(String);
+    method @Nullable public String getScheme();
+    method @Nullable public android.content.Intent getSelector();
+    method @Nullable public java.io.Serializable getSerializableExtra(String);
+    method @Nullable public short[] getShortArrayExtra(String);
+    method public short getShortExtra(String, short);
+    method @Nullable public android.graphics.Rect getSourceBounds();
+    method @Nullable public String[] getStringArrayExtra(String);
+    method @Nullable public java.util.ArrayList<java.lang.String> getStringArrayListExtra(String);
+    method @Nullable public String getStringExtra(String);
+    method @Nullable public String getType();
+    method public boolean hasCategory(String);
+    method public boolean hasExtra(String);
     method public boolean hasFileDescriptors();
     method public static android.content.Intent makeMainActivity(android.content.ComponentName);
-    method public static android.content.Intent makeMainSelectorActivity(java.lang.String, java.lang.String);
+    method public static android.content.Intent makeMainSelectorActivity(String, String);
     method public static android.content.Intent makeRestartActivityTask(android.content.ComponentName);
-    method public static java.lang.String normalizeMimeType(java.lang.String);
-    method public static android.content.Intent parseIntent(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static android.content.Intent parseUri(java.lang.String, int) throws java.net.URISyntaxException;
-    method public android.content.Intent putCharSequenceArrayListExtra(java.lang.String, java.util.ArrayList<java.lang.CharSequence>);
-    method public android.content.Intent putExtra(java.lang.String, boolean);
-    method public android.content.Intent putExtra(java.lang.String, byte);
-    method public android.content.Intent putExtra(java.lang.String, char);
-    method public android.content.Intent putExtra(java.lang.String, short);
-    method public android.content.Intent putExtra(java.lang.String, int);
-    method public android.content.Intent putExtra(java.lang.String, long);
-    method public android.content.Intent putExtra(java.lang.String, float);
-    method public android.content.Intent putExtra(java.lang.String, double);
-    method public android.content.Intent putExtra(java.lang.String, java.lang.String);
-    method public android.content.Intent putExtra(java.lang.String, java.lang.CharSequence);
-    method public android.content.Intent putExtra(java.lang.String, android.os.Parcelable);
-    method public android.content.Intent putExtra(java.lang.String, android.os.Parcelable[]);
-    method public android.content.Intent putExtra(java.lang.String, java.io.Serializable);
-    method public android.content.Intent putExtra(java.lang.String, boolean[]);
-    method public android.content.Intent putExtra(java.lang.String, byte[]);
-    method public android.content.Intent putExtra(java.lang.String, short[]);
-    method public android.content.Intent putExtra(java.lang.String, char[]);
-    method public android.content.Intent putExtra(java.lang.String, int[]);
-    method public android.content.Intent putExtra(java.lang.String, long[]);
-    method public android.content.Intent putExtra(java.lang.String, float[]);
-    method public android.content.Intent putExtra(java.lang.String, double[]);
-    method public android.content.Intent putExtra(java.lang.String, java.lang.String[]);
-    method public android.content.Intent putExtra(java.lang.String, java.lang.CharSequence[]);
-    method public android.content.Intent putExtra(java.lang.String, android.os.Bundle);
-    method public android.content.Intent putExtras(android.content.Intent);
-    method public android.content.Intent putExtras(android.os.Bundle);
-    method public android.content.Intent putIntegerArrayListExtra(java.lang.String, java.util.ArrayList<java.lang.Integer>);
-    method public android.content.Intent putParcelableArrayListExtra(java.lang.String, java.util.ArrayList<? extends android.os.Parcelable>);
-    method public android.content.Intent putStringArrayListExtra(java.lang.String, java.util.ArrayList<java.lang.String>);
+    method @Nullable public static String normalizeMimeType(@Nullable String);
+    method @NonNull public static android.content.Intent parseIntent(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static android.content.Intent parseUri(String, int) throws java.net.URISyntaxException;
+    method @NonNull public android.content.Intent putCharSequenceArrayListExtra(String, @Nullable java.util.ArrayList<java.lang.CharSequence>);
+    method @NonNull public android.content.Intent putExtra(String, boolean);
+    method @NonNull public android.content.Intent putExtra(String, byte);
+    method @NonNull public android.content.Intent putExtra(String, char);
+    method @NonNull public android.content.Intent putExtra(String, short);
+    method @NonNull public android.content.Intent putExtra(String, int);
+    method @NonNull public android.content.Intent putExtra(String, long);
+    method @NonNull public android.content.Intent putExtra(String, float);
+    method @NonNull public android.content.Intent putExtra(String, double);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable String);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable CharSequence);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable android.os.Parcelable);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable android.os.Parcelable[]);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable java.io.Serializable);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable boolean[]);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable byte[]);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable short[]);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable char[]);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable int[]);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable long[]);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable float[]);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable double[]);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable String[]);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable CharSequence[]);
+    method @NonNull public android.content.Intent putExtra(String, @Nullable android.os.Bundle);
+    method @NonNull public android.content.Intent putExtras(@NonNull android.content.Intent);
+    method @NonNull public android.content.Intent putExtras(@NonNull android.os.Bundle);
+    method @NonNull public android.content.Intent putIntegerArrayListExtra(String, @Nullable java.util.ArrayList<java.lang.Integer>);
+    method @NonNull public android.content.Intent putParcelableArrayListExtra(String, @Nullable java.util.ArrayList<? extends android.os.Parcelable>);
+    method @NonNull public android.content.Intent putStringArrayListExtra(String, @Nullable java.util.ArrayList<java.lang.String>);
     method public void readFromParcel(android.os.Parcel);
-    method public void removeCategory(java.lang.String);
-    method public void removeExtra(java.lang.String);
+    method public void removeCategory(String);
+    method public void removeExtra(String);
     method public void removeFlags(int);
-    method public android.content.Intent replaceExtras(android.content.Intent);
-    method public android.content.Intent replaceExtras(android.os.Bundle);
-    method public android.content.ComponentName resolveActivity(android.content.pm.PackageManager);
-    method public android.content.pm.ActivityInfo resolveActivityInfo(android.content.pm.PackageManager, int);
-    method public java.lang.String resolveType(android.content.Context);
-    method public java.lang.String resolveType(android.content.ContentResolver);
-    method public java.lang.String resolveTypeIfNeeded(android.content.ContentResolver);
-    method public android.content.Intent setAction(java.lang.String);
-    method public android.content.Intent setClass(android.content.Context, java.lang.Class<?>);
-    method public android.content.Intent setClassName(android.content.Context, java.lang.String);
-    method public android.content.Intent setClassName(java.lang.String, java.lang.String);
-    method public void setClipData(android.content.ClipData);
-    method public android.content.Intent setComponent(android.content.ComponentName);
-    method public android.content.Intent setData(android.net.Uri);
-    method public android.content.Intent setDataAndNormalize(android.net.Uri);
-    method public android.content.Intent setDataAndType(android.net.Uri, java.lang.String);
-    method public android.content.Intent setDataAndTypeAndNormalize(android.net.Uri, java.lang.String);
-    method public void setExtrasClassLoader(java.lang.ClassLoader);
-    method public android.content.Intent setFlags(int);
-    method public android.content.Intent setPackage(java.lang.String);
-    method public void setSelector(android.content.Intent);
-    method public void setSourceBounds(android.graphics.Rect);
-    method public android.content.Intent setType(java.lang.String);
-    method public android.content.Intent setTypeAndNormalize(java.lang.String);
-    method public deprecated java.lang.String toURI();
-    method public java.lang.String toUri(int);
+    method @NonNull public android.content.Intent replaceExtras(@NonNull android.content.Intent);
+    method @NonNull public android.content.Intent replaceExtras(@Nullable android.os.Bundle);
+    method public android.content.ComponentName resolveActivity(@NonNull android.content.pm.PackageManager);
+    method public android.content.pm.ActivityInfo resolveActivityInfo(@NonNull android.content.pm.PackageManager, int);
+    method @Nullable public String resolveType(@NonNull android.content.Context);
+    method @Nullable public String resolveType(@NonNull android.content.ContentResolver);
+    method @Nullable public String resolveTypeIfNeeded(@NonNull android.content.ContentResolver);
+    method @NonNull public android.content.Intent setAction(@Nullable String);
+    method @NonNull public android.content.Intent setClass(@NonNull android.content.Context, @NonNull Class<?>);
+    method @NonNull public android.content.Intent setClassName(@NonNull android.content.Context, @NonNull String);
+    method @NonNull public android.content.Intent setClassName(@NonNull String, @NonNull String);
+    method public void setClipData(@Nullable android.content.ClipData);
+    method @NonNull public android.content.Intent setComponent(@Nullable android.content.ComponentName);
+    method @NonNull public android.content.Intent setData(@Nullable android.net.Uri);
+    method @NonNull public android.content.Intent setDataAndNormalize(@NonNull android.net.Uri);
+    method @NonNull public android.content.Intent setDataAndType(@Nullable android.net.Uri, @Nullable String);
+    method @NonNull public android.content.Intent setDataAndTypeAndNormalize(@NonNull android.net.Uri, @Nullable String);
+    method public void setExtrasClassLoader(@Nullable ClassLoader);
+    method @NonNull public android.content.Intent setFlags(int);
+    method @NonNull public android.content.Intent setPackage(@Nullable String);
+    method public void setSelector(@Nullable android.content.Intent);
+    method public void setSourceBounds(@Nullable android.graphics.Rect);
+    method @NonNull public android.content.Intent setType(@Nullable String);
+    method @NonNull public android.content.Intent setTypeAndNormalize(@Nullable String);
+    method @Deprecated public String toURI();
+    method public String toUri(int);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final java.lang.String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
-    field public static final java.lang.String ACTION_ALL_APPS = "android.intent.action.ALL_APPS";
-    field public static final java.lang.String ACTION_ANSWER = "android.intent.action.ANSWER";
-    field public static final java.lang.String ACTION_APPLICATION_PREFERENCES = "android.intent.action.APPLICATION_PREFERENCES";
-    field public static final java.lang.String ACTION_APPLICATION_RESTRICTIONS_CHANGED = "android.intent.action.APPLICATION_RESTRICTIONS_CHANGED";
-    field public static final java.lang.String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
-    field public static final java.lang.String ACTION_ASSIST = "android.intent.action.ASSIST";
-    field public static final java.lang.String ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA";
-    field public static final java.lang.String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";
-    field public static final java.lang.String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
-    field public static final java.lang.String ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY";
-    field public static final java.lang.String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
-    field public static final java.lang.String ACTION_BUG_REPORT = "android.intent.action.BUG_REPORT";
-    field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
-    field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
-    field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
-    field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
-    field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
-    field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
-    field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
-    field public static final java.lang.String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
-    field public static final java.lang.String ACTION_CREATE_SHORTCUT = "android.intent.action.CREATE_SHORTCUT";
-    field public static final java.lang.String ACTION_DATE_CHANGED = "android.intent.action.DATE_CHANGED";
-    field public static final java.lang.String ACTION_DEFAULT = "android.intent.action.VIEW";
-    field public static final java.lang.String ACTION_DEFINE = "android.intent.action.DEFINE";
-    field public static final java.lang.String ACTION_DELETE = "android.intent.action.DELETE";
-    field public static final deprecated java.lang.String ACTION_DEVICE_STORAGE_LOW = "android.intent.action.DEVICE_STORAGE_LOW";
-    field public static final deprecated java.lang.String ACTION_DEVICE_STORAGE_OK = "android.intent.action.DEVICE_STORAGE_OK";
-    field public static final java.lang.String ACTION_DIAL = "android.intent.action.DIAL";
-    field public static final java.lang.String ACTION_DOCK_EVENT = "android.intent.action.DOCK_EVENT";
-    field public static final java.lang.String ACTION_DREAMING_STARTED = "android.intent.action.DREAMING_STARTED";
-    field public static final java.lang.String ACTION_DREAMING_STOPPED = "android.intent.action.DREAMING_STOPPED";
-    field public static final java.lang.String ACTION_EDIT = "android.intent.action.EDIT";
-    field public static final java.lang.String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE";
-    field public static final java.lang.String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
-    field public static final java.lang.String ACTION_FACTORY_TEST = "android.intent.action.FACTORY_TEST";
-    field public static final java.lang.String ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT";
-    field public static final java.lang.String ACTION_GET_RESTRICTION_ENTRIES = "android.intent.action.GET_RESTRICTION_ENTRIES";
-    field public static final java.lang.String ACTION_GTALK_SERVICE_CONNECTED = "android.intent.action.GTALK_CONNECTED";
-    field public static final java.lang.String ACTION_GTALK_SERVICE_DISCONNECTED = "android.intent.action.GTALK_DISCONNECTED";
-    field public static final java.lang.String ACTION_HEADSET_PLUG = "android.intent.action.HEADSET_PLUG";
-    field public static final java.lang.String ACTION_INPUT_METHOD_CHANGED = "android.intent.action.INPUT_METHOD_CHANGED";
-    field public static final java.lang.String ACTION_INSERT = "android.intent.action.INSERT";
-    field public static final java.lang.String ACTION_INSERT_OR_EDIT = "android.intent.action.INSERT_OR_EDIT";
-    field public static final java.lang.String ACTION_INSTALL_FAILURE = "android.intent.action.INSTALL_FAILURE";
-    field public static final deprecated java.lang.String ACTION_INSTALL_PACKAGE = "android.intent.action.INSTALL_PACKAGE";
-    field public static final java.lang.String ACTION_LOCALE_CHANGED = "android.intent.action.LOCALE_CHANGED";
-    field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
-    field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
-    field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
-    field public static final java.lang.String ACTION_MANAGED_PROFILE_AVAILABLE = "android.intent.action.MANAGED_PROFILE_AVAILABLE";
-    field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
-    field public static final java.lang.String ACTION_MANAGED_PROFILE_UNAVAILABLE = "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
-    field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
-    field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
-    field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
-    field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
-    field public static final java.lang.String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON";
-    field public static final java.lang.String ACTION_MEDIA_CHECKING = "android.intent.action.MEDIA_CHECKING";
-    field public static final java.lang.String ACTION_MEDIA_EJECT = "android.intent.action.MEDIA_EJECT";
-    field public static final java.lang.String ACTION_MEDIA_MOUNTED = "android.intent.action.MEDIA_MOUNTED";
-    field public static final java.lang.String ACTION_MEDIA_NOFS = "android.intent.action.MEDIA_NOFS";
-    field public static final java.lang.String ACTION_MEDIA_REMOVED = "android.intent.action.MEDIA_REMOVED";
-    field public static final java.lang.String ACTION_MEDIA_SCANNER_FINISHED = "android.intent.action.MEDIA_SCANNER_FINISHED";
-    field public static final java.lang.String ACTION_MEDIA_SCANNER_SCAN_FILE = "android.intent.action.MEDIA_SCANNER_SCAN_FILE";
-    field public static final java.lang.String ACTION_MEDIA_SCANNER_STARTED = "android.intent.action.MEDIA_SCANNER_STARTED";
-    field public static final java.lang.String ACTION_MEDIA_SHARED = "android.intent.action.MEDIA_SHARED";
-    field public static final java.lang.String ACTION_MEDIA_UNMOUNTABLE = "android.intent.action.MEDIA_UNMOUNTABLE";
-    field public static final java.lang.String ACTION_MEDIA_UNMOUNTED = "android.intent.action.MEDIA_UNMOUNTED";
-    field public static final java.lang.String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED";
-    field public static final java.lang.String ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED";
-    field public static final java.lang.String ACTION_MY_PACKAGE_UNSUSPENDED = "android.intent.action.MY_PACKAGE_UNSUSPENDED";
-    field public static final java.lang.String ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
-    field public static final java.lang.String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
-    field public static final java.lang.String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
-    field public static final java.lang.String ACTION_PACKAGES_SUSPENDED = "android.intent.action.PACKAGES_SUSPENDED";
-    field public static final java.lang.String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
-    field public static final java.lang.String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
-    field public static final java.lang.String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
-    field public static final java.lang.String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
-    field public static final java.lang.String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH";
-    field public static final java.lang.String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
-    field public static final deprecated java.lang.String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
-    field public static final java.lang.String ACTION_PACKAGE_NEEDS_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_VERIFICATION";
-    field public static final java.lang.String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
-    field public static final java.lang.String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
-    field public static final java.lang.String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
-    field public static final java.lang.String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
-    field public static final java.lang.String ACTION_PASTE = "android.intent.action.PASTE";
-    field public static final java.lang.String ACTION_PICK = "android.intent.action.PICK";
-    field public static final java.lang.String ACTION_PICK_ACTIVITY = "android.intent.action.PICK_ACTIVITY";
-    field public static final java.lang.String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
-    field public static final java.lang.String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
-    field public static final java.lang.String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
-    field public static final java.lang.String ACTION_PROCESS_TEXT = "android.intent.action.PROCESS_TEXT";
-    field public static final java.lang.String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
-    field public static final java.lang.String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
-    field public static final java.lang.String ACTION_QUICK_VIEW = "android.intent.action.QUICK_VIEW";
-    field public static final java.lang.String ACTION_REBOOT = "android.intent.action.REBOOT";
-    field public static final java.lang.String ACTION_RUN = "android.intent.action.RUN";
-    field public static final java.lang.String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
-    field public static final java.lang.String ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON";
-    field public static final java.lang.String ACTION_SEARCH = "android.intent.action.SEARCH";
-    field public static final java.lang.String ACTION_SEARCH_LONG_PRESS = "android.intent.action.SEARCH_LONG_PRESS";
-    field public static final java.lang.String ACTION_SEND = "android.intent.action.SEND";
-    field public static final java.lang.String ACTION_SENDTO = "android.intent.action.SENDTO";
-    field public static final java.lang.String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
-    field public static final java.lang.String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
-    field public static final java.lang.String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
-    field public static final java.lang.String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
-    field public static final java.lang.String ACTION_SYNC = "android.intent.action.SYNC";
-    field public static final java.lang.String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
-    field public static final java.lang.String ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED";
-    field public static final java.lang.String ACTION_TIME_CHANGED = "android.intent.action.TIME_SET";
-    field public static final java.lang.String ACTION_TIME_TICK = "android.intent.action.TIME_TICK";
-    field public static final java.lang.String ACTION_TRANSLATE = "android.intent.action.TRANSLATE";
-    field public static final java.lang.String ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED";
-    field public static final deprecated java.lang.String ACTION_UMS_CONNECTED = "android.intent.action.UMS_CONNECTED";
-    field public static final deprecated java.lang.String ACTION_UMS_DISCONNECTED = "android.intent.action.UMS_DISCONNECTED";
-    field public static final deprecated java.lang.String ACTION_UNINSTALL_PACKAGE = "android.intent.action.UNINSTALL_PACKAGE";
-    field public static final java.lang.String ACTION_USER_BACKGROUND = "android.intent.action.USER_BACKGROUND";
-    field public static final java.lang.String ACTION_USER_FOREGROUND = "android.intent.action.USER_FOREGROUND";
-    field public static final java.lang.String ACTION_USER_INITIALIZE = "android.intent.action.USER_INITIALIZE";
-    field public static final java.lang.String ACTION_USER_PRESENT = "android.intent.action.USER_PRESENT";
-    field public static final java.lang.String ACTION_USER_UNLOCKED = "android.intent.action.USER_UNLOCKED";
-    field public static final java.lang.String ACTION_VIEW = "android.intent.action.VIEW";
-    field public static final java.lang.String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
-    field public static final deprecated java.lang.String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED";
-    field public static final java.lang.String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH";
-    field public static final java.lang.String CATEGORY_ALTERNATIVE = "android.intent.category.ALTERNATIVE";
-    field public static final java.lang.String CATEGORY_APP_BROWSER = "android.intent.category.APP_BROWSER";
-    field public static final java.lang.String CATEGORY_APP_CALCULATOR = "android.intent.category.APP_CALCULATOR";
-    field public static final java.lang.String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR";
-    field public static final java.lang.String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS";
-    field public static final java.lang.String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL";
-    field public static final java.lang.String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY";
-    field public static final java.lang.String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS";
-    field public static final java.lang.String CATEGORY_APP_MARKET = "android.intent.category.APP_MARKET";
-    field public static final java.lang.String CATEGORY_APP_MESSAGING = "android.intent.category.APP_MESSAGING";
-    field public static final java.lang.String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC";
-    field public static final java.lang.String CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE";
-    field public static final java.lang.String CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK";
-    field public static final java.lang.String CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE";
-    field public static final java.lang.String CATEGORY_DEFAULT = "android.intent.category.DEFAULT";
-    field public static final java.lang.String CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK";
-    field public static final java.lang.String CATEGORY_DEVELOPMENT_PREFERENCE = "android.intent.category.DEVELOPMENT_PREFERENCE";
-    field public static final java.lang.String CATEGORY_EMBED = "android.intent.category.EMBED";
-    field public static final java.lang.String CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST = "android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST";
-    field public static final java.lang.String CATEGORY_HE_DESK_DOCK = "android.intent.category.HE_DESK_DOCK";
-    field public static final java.lang.String CATEGORY_HOME = "android.intent.category.HOME";
-    field public static final java.lang.String CATEGORY_INFO = "android.intent.category.INFO";
-    field public static final java.lang.String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER";
-    field public static final java.lang.String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
-    field public static final java.lang.String CATEGORY_LE_DESK_DOCK = "android.intent.category.LE_DESK_DOCK";
-    field public static final java.lang.String CATEGORY_MONKEY = "android.intent.category.MONKEY";
-    field public static final java.lang.String CATEGORY_OPENABLE = "android.intent.category.OPENABLE";
-    field public static final java.lang.String CATEGORY_PREFERENCE = "android.intent.category.PREFERENCE";
-    field public static final java.lang.String CATEGORY_SAMPLE_CODE = "android.intent.category.SAMPLE_CODE";
-    field public static final java.lang.String CATEGORY_SECONDARY_HOME = "android.intent.category.SECONDARY_HOME";
-    field public static final java.lang.String CATEGORY_SELECTED_ALTERNATIVE = "android.intent.category.SELECTED_ALTERNATIVE";
-    field public static final java.lang.String CATEGORY_TAB = "android.intent.category.TAB";
-    field public static final java.lang.String CATEGORY_TEST = "android.intent.category.TEST";
-    field public static final java.lang.String CATEGORY_TYPED_OPENABLE = "android.intent.category.TYPED_OPENABLE";
-    field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
-    field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
-    field public static final java.lang.String CATEGORY_VR_HOME = "android.intent.category.VR_HOME";
+    field public static final String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
+    field public static final String ACTION_ALL_APPS = "android.intent.action.ALL_APPS";
+    field public static final String ACTION_ANSWER = "android.intent.action.ANSWER";
+    field public static final String ACTION_APPLICATION_PREFERENCES = "android.intent.action.APPLICATION_PREFERENCES";
+    field public static final String ACTION_APPLICATION_RESTRICTIONS_CHANGED = "android.intent.action.APPLICATION_RESTRICTIONS_CHANGED";
+    field public static final String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
+    field public static final String ACTION_ASSIST = "android.intent.action.ASSIST";
+    field public static final String ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA";
+    field public static final String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";
+    field public static final String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
+    field public static final String ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY";
+    field public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
+    field public static final String ACTION_BUG_REPORT = "android.intent.action.BUG_REPORT";
+    field public static final String ACTION_CALL = "android.intent.action.CALL";
+    field public static final String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
+    field public static final String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+    field public static final String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
+    field public static final String ACTION_CHOOSER = "android.intent.action.CHOOSER";
+    field public static final String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
+    field public static final String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
+    field public static final String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
+    field public static final String ACTION_CREATE_SHORTCUT = "android.intent.action.CREATE_SHORTCUT";
+    field public static final String ACTION_DATE_CHANGED = "android.intent.action.DATE_CHANGED";
+    field public static final String ACTION_DEFAULT = "android.intent.action.VIEW";
+    field public static final String ACTION_DEFINE = "android.intent.action.DEFINE";
+    field public static final String ACTION_DELETE = "android.intent.action.DELETE";
+    field @Deprecated public static final String ACTION_DEVICE_STORAGE_LOW = "android.intent.action.DEVICE_STORAGE_LOW";
+    field @Deprecated public static final String ACTION_DEVICE_STORAGE_OK = "android.intent.action.DEVICE_STORAGE_OK";
+    field public static final String ACTION_DIAL = "android.intent.action.DIAL";
+    field public static final String ACTION_DOCK_EVENT = "android.intent.action.DOCK_EVENT";
+    field public static final String ACTION_DREAMING_STARTED = "android.intent.action.DREAMING_STARTED";
+    field public static final String ACTION_DREAMING_STOPPED = "android.intent.action.DREAMING_STOPPED";
+    field public static final String ACTION_EDIT = "android.intent.action.EDIT";
+    field public static final String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE";
+    field public static final String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
+    field public static final String ACTION_FACTORY_TEST = "android.intent.action.FACTORY_TEST";
+    field public static final String ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT";
+    field public static final String ACTION_GET_RESTRICTION_ENTRIES = "android.intent.action.GET_RESTRICTION_ENTRIES";
+    field public static final String ACTION_GTALK_SERVICE_CONNECTED = "android.intent.action.GTALK_CONNECTED";
+    field public static final String ACTION_GTALK_SERVICE_DISCONNECTED = "android.intent.action.GTALK_DISCONNECTED";
+    field public static final String ACTION_HEADSET_PLUG = "android.intent.action.HEADSET_PLUG";
+    field public static final String ACTION_INPUT_METHOD_CHANGED = "android.intent.action.INPUT_METHOD_CHANGED";
+    field public static final String ACTION_INSERT = "android.intent.action.INSERT";
+    field public static final String ACTION_INSERT_OR_EDIT = "android.intent.action.INSERT_OR_EDIT";
+    field public static final String ACTION_INSTALL_FAILURE = "android.intent.action.INSTALL_FAILURE";
+    field @Deprecated public static final String ACTION_INSTALL_PACKAGE = "android.intent.action.INSTALL_PACKAGE";
+    field public static final String ACTION_LOCALE_CHANGED = "android.intent.action.LOCALE_CHANGED";
+    field public static final String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
+    field public static final String ACTION_MAIN = "android.intent.action.MAIN";
+    field public static final String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
+    field public static final String ACTION_MANAGED_PROFILE_AVAILABLE = "android.intent.action.MANAGED_PROFILE_AVAILABLE";
+    field public static final String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+    field public static final String ACTION_MANAGED_PROFILE_UNAVAILABLE = "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
+    field public static final String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
+    field public static final String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
+    field public static final String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
+    field public static final String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
+    field public static final String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON";
+    field public static final String ACTION_MEDIA_CHECKING = "android.intent.action.MEDIA_CHECKING";
+    field public static final String ACTION_MEDIA_EJECT = "android.intent.action.MEDIA_EJECT";
+    field public static final String ACTION_MEDIA_MOUNTED = "android.intent.action.MEDIA_MOUNTED";
+    field public static final String ACTION_MEDIA_NOFS = "android.intent.action.MEDIA_NOFS";
+    field public static final String ACTION_MEDIA_REMOVED = "android.intent.action.MEDIA_REMOVED";
+    field public static final String ACTION_MEDIA_SCANNER_FINISHED = "android.intent.action.MEDIA_SCANNER_FINISHED";
+    field public static final String ACTION_MEDIA_SCANNER_SCAN_FILE = "android.intent.action.MEDIA_SCANNER_SCAN_FILE";
+    field public static final String ACTION_MEDIA_SCANNER_STARTED = "android.intent.action.MEDIA_SCANNER_STARTED";
+    field public static final String ACTION_MEDIA_SHARED = "android.intent.action.MEDIA_SHARED";
+    field public static final String ACTION_MEDIA_UNMOUNTABLE = "android.intent.action.MEDIA_UNMOUNTABLE";
+    field public static final String ACTION_MEDIA_UNMOUNTED = "android.intent.action.MEDIA_UNMOUNTED";
+    field public static final String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED";
+    field public static final String ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED";
+    field public static final String ACTION_MY_PACKAGE_UNSUSPENDED = "android.intent.action.MY_PACKAGE_UNSUSPENDED";
+    field @Deprecated public static final String ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
+    field public static final String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
+    field public static final String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
+    field public static final String ACTION_PACKAGES_SUSPENDED = "android.intent.action.PACKAGES_SUSPENDED";
+    field public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
+    field public static final String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
+    field public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
+    field public static final String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
+    field public static final String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH";
+    field public static final String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
+    field @Deprecated public static final String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
+    field public static final String ACTION_PACKAGE_NEEDS_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_VERIFICATION";
+    field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
+    field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
+    field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
+    field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
+    field public static final String ACTION_PASTE = "android.intent.action.PASTE";
+    field public static final String ACTION_PERMISSION_USAGE_DETAILS = "android.intent.action.PERMISSION_USAGE_DETAILS";
+    field public static final String ACTION_PICK = "android.intent.action.PICK";
+    field public static final String ACTION_PICK_ACTIVITY = "android.intent.action.PICK_ACTIVITY";
+    field public static final String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
+    field public static final String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
+    field public static final String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
+    field public static final String ACTION_PROCESS_TEXT = "android.intent.action.PROCESS_TEXT";
+    field public static final String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
+    field public static final String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
+    field public static final String ACTION_QUICK_VIEW = "android.intent.action.QUICK_VIEW";
+    field public static final String ACTION_REBOOT = "android.intent.action.REBOOT";
+    field public static final String ACTION_RUN = "android.intent.action.RUN";
+    field public static final String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
+    field public static final String ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON";
+    field public static final String ACTION_SEARCH = "android.intent.action.SEARCH";
+    field public static final String ACTION_SEARCH_LONG_PRESS = "android.intent.action.SEARCH_LONG_PRESS";
+    field public static final String ACTION_SEND = "android.intent.action.SEND";
+    field public static final String ACTION_SENDTO = "android.intent.action.SENDTO";
+    field public static final String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
+    field public static final String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
+    field public static final String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
+    field public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
+    field public static final String ACTION_SYNC = "android.intent.action.SYNC";
+    field public static final String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
+    field public static final String ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED";
+    field public static final String ACTION_TIME_CHANGED = "android.intent.action.TIME_SET";
+    field public static final String ACTION_TIME_TICK = "android.intent.action.TIME_TICK";
+    field public static final String ACTION_TRANSLATE = "android.intent.action.TRANSLATE";
+    field public static final String ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED";
+    field @Deprecated public static final String ACTION_UMS_CONNECTED = "android.intent.action.UMS_CONNECTED";
+    field @Deprecated public static final String ACTION_UMS_DISCONNECTED = "android.intent.action.UMS_DISCONNECTED";
+    field @Deprecated public static final String ACTION_UNINSTALL_PACKAGE = "android.intent.action.UNINSTALL_PACKAGE";
+    field public static final String ACTION_USER_BACKGROUND = "android.intent.action.USER_BACKGROUND";
+    field public static final String ACTION_USER_FOREGROUND = "android.intent.action.USER_FOREGROUND";
+    field public static final String ACTION_USER_INITIALIZE = "android.intent.action.USER_INITIALIZE";
+    field public static final String ACTION_USER_PRESENT = "android.intent.action.USER_PRESENT";
+    field public static final String ACTION_USER_UNLOCKED = "android.intent.action.USER_UNLOCKED";
+    field public static final String ACTION_VIEW = "android.intent.action.VIEW";
+    field public static final String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
+    field @Deprecated public static final String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED";
+    field public static final String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH";
+    field public static final String CATEGORY_ALTERNATIVE = "android.intent.category.ALTERNATIVE";
+    field public static final String CATEGORY_APP_BROWSER = "android.intent.category.APP_BROWSER";
+    field public static final String CATEGORY_APP_CALCULATOR = "android.intent.category.APP_CALCULATOR";
+    field public static final String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR";
+    field public static final String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS";
+    field public static final String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL";
+    field public static final String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY";
+    field public static final String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS";
+    field public static final String CATEGORY_APP_MARKET = "android.intent.category.APP_MARKET";
+    field public static final String CATEGORY_APP_MESSAGING = "android.intent.category.APP_MESSAGING";
+    field public static final String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC";
+    field public static final String CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE";
+    field public static final String CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK";
+    field public static final String CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE";
+    field public static final String CATEGORY_DEFAULT = "android.intent.category.DEFAULT";
+    field public static final String CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK";
+    field public static final String CATEGORY_DEVELOPMENT_PREFERENCE = "android.intent.category.DEVELOPMENT_PREFERENCE";
+    field public static final String CATEGORY_EMBED = "android.intent.category.EMBED";
+    field public static final String CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST = "android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST";
+    field public static final String CATEGORY_HE_DESK_DOCK = "android.intent.category.HE_DESK_DOCK";
+    field public static final String CATEGORY_HOME = "android.intent.category.HOME";
+    field public static final String CATEGORY_INFO = "android.intent.category.INFO";
+    field public static final String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER";
+    field public static final String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
+    field public static final String CATEGORY_LE_DESK_DOCK = "android.intent.category.LE_DESK_DOCK";
+    field public static final String CATEGORY_MONKEY = "android.intent.category.MONKEY";
+    field public static final String CATEGORY_OPENABLE = "android.intent.category.OPENABLE";
+    field public static final String CATEGORY_PREFERENCE = "android.intent.category.PREFERENCE";
+    field public static final String CATEGORY_SAMPLE_CODE = "android.intent.category.SAMPLE_CODE";
+    field public static final String CATEGORY_SECONDARY_HOME = "android.intent.category.SECONDARY_HOME";
+    field public static final String CATEGORY_SELECTED_ALTERNATIVE = "android.intent.category.SELECTED_ALTERNATIVE";
+    field public static final String CATEGORY_TAB = "android.intent.category.TAB";
+    field public static final String CATEGORY_TEST = "android.intent.category.TEST";
+    field public static final String CATEGORY_TYPED_OPENABLE = "android.intent.category.TYPED_OPENABLE";
+    field public static final String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
+    field public static final String CATEGORY_VOICE = "android.intent.category.VOICE";
+    field public static final String CATEGORY_VR_HOME = "android.intent.category.VR_HOME";
     field public static final android.os.Parcelable.Creator<android.content.Intent> CREATOR;
-    field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
-    field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
-    field public static final deprecated java.lang.String EXTRA_ALLOW_REPLACE = "android.intent.extra.ALLOW_REPLACE";
-    field public static final java.lang.String EXTRA_ALTERNATE_INTENTS = "android.intent.extra.ALTERNATE_INTENTS";
-    field public static final java.lang.String EXTRA_ASSIST_CONTEXT = "android.intent.extra.ASSIST_CONTEXT";
-    field public static final java.lang.String EXTRA_ASSIST_INPUT_DEVICE_ID = "android.intent.extra.ASSIST_INPUT_DEVICE_ID";
-    field public static final java.lang.String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
-    field public static final java.lang.String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
-    field public static final java.lang.String EXTRA_ASSIST_UID = "android.intent.extra.ASSIST_UID";
-    field public static final java.lang.String EXTRA_AUTO_LAUNCH_SINGLE_CHOICE = "android.intent.extra.AUTO_LAUNCH_SINGLE_CHOICE";
-    field public static final java.lang.String EXTRA_BCC = "android.intent.extra.BCC";
-    field public static final java.lang.String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
-    field public static final java.lang.String EXTRA_CC = "android.intent.extra.CC";
-    field public static final deprecated java.lang.String EXTRA_CHANGED_COMPONENT_NAME = "android.intent.extra.changed_component_name";
-    field public static final java.lang.String EXTRA_CHANGED_COMPONENT_NAME_LIST = "android.intent.extra.changed_component_name_list";
-    field public static final java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
-    field public static final java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
-    field public static final java.lang.String EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER = "android.intent.extra.CHOOSER_REFINEMENT_INTENT_SENDER";
-    field public static final java.lang.String EXTRA_CHOOSER_TARGETS = "android.intent.extra.CHOOSER_TARGETS";
-    field public static final java.lang.String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT";
-    field public static final java.lang.String EXTRA_CHOSEN_COMPONENT_INTENT_SENDER = "android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER";
-    field public static final java.lang.String EXTRA_COMPONENT_NAME = "android.intent.extra.COMPONENT_NAME";
-    field public static final java.lang.String EXTRA_CONTENT_ANNOTATIONS = "android.intent.extra.CONTENT_ANNOTATIONS";
-    field public static final java.lang.String EXTRA_CONTENT_QUERY = "android.intent.extra.CONTENT_QUERY";
-    field public static final java.lang.String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
-    field public static final java.lang.String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE";
+    field public static final String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
+    field public static final String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
+    field @Deprecated public static final String EXTRA_ALLOW_REPLACE = "android.intent.extra.ALLOW_REPLACE";
+    field public static final String EXTRA_ALTERNATE_INTENTS = "android.intent.extra.ALTERNATE_INTENTS";
+    field public static final String EXTRA_ASSIST_CONTEXT = "android.intent.extra.ASSIST_CONTEXT";
+    field public static final String EXTRA_ASSIST_INPUT_DEVICE_ID = "android.intent.extra.ASSIST_INPUT_DEVICE_ID";
+    field public static final String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
+    field public static final String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
+    field public static final String EXTRA_ASSIST_UID = "android.intent.extra.ASSIST_UID";
+    field public static final String EXTRA_AUTO_LAUNCH_SINGLE_CHOICE = "android.intent.extra.AUTO_LAUNCH_SINGLE_CHOICE";
+    field public static final String EXTRA_BCC = "android.intent.extra.BCC";
+    field public static final String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
+    field public static final String EXTRA_CC = "android.intent.extra.CC";
+    field @Deprecated public static final String EXTRA_CHANGED_COMPONENT_NAME = "android.intent.extra.changed_component_name";
+    field public static final String EXTRA_CHANGED_COMPONENT_NAME_LIST = "android.intent.extra.changed_component_name_list";
+    field public static final String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
+    field public static final String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
+    field public static final String EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER = "android.intent.extra.CHOOSER_REFINEMENT_INTENT_SENDER";
+    field public static final String EXTRA_CHOOSER_TARGETS = "android.intent.extra.CHOOSER_TARGETS";
+    field public static final String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT";
+    field public static final String EXTRA_CHOSEN_COMPONENT_INTENT_SENDER = "android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER";
+    field public static final String EXTRA_COMPONENT_NAME = "android.intent.extra.COMPONENT_NAME";
+    field public static final String EXTRA_CONTENT_ANNOTATIONS = "android.intent.extra.CONTENT_ANNOTATIONS";
+    field public static final String EXTRA_CONTENT_QUERY = "android.intent.extra.CONTENT_QUERY";
+    field public static final String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
+    field public static final String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE";
     field public static final int EXTRA_DOCK_STATE_CAR = 2; // 0x2
     field public static final int EXTRA_DOCK_STATE_DESK = 1; // 0x1
     field public static final int EXTRA_DOCK_STATE_HE_DESK = 4; // 0x4
     field public static final int EXTRA_DOCK_STATE_LE_DESK = 3; // 0x3
     field public static final int EXTRA_DOCK_STATE_UNDOCKED = 0; // 0x0
-    field public static final java.lang.String EXTRA_DONT_KILL_APP = "android.intent.extra.DONT_KILL_APP";
-    field public static final java.lang.String EXTRA_EMAIL = "android.intent.extra.EMAIL";
-    field public static final java.lang.String EXTRA_EXCLUDE_COMPONENTS = "android.intent.extra.EXCLUDE_COMPONENTS";
-    field public static final java.lang.String EXTRA_FROM_STORAGE = "android.intent.extra.FROM_STORAGE";
-    field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
-    field public static final java.lang.String EXTRA_INDEX = "android.intent.extra.INDEX";
-    field public static final java.lang.String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
-    field public static final java.lang.String EXTRA_INSTALLER_PACKAGE_NAME = "android.intent.extra.INSTALLER_PACKAGE_NAME";
-    field public static final java.lang.String EXTRA_INTENT = "android.intent.extra.INTENT";
-    field public static final java.lang.String EXTRA_KEY_EVENT = "android.intent.extra.KEY_EVENT";
-    field public static final java.lang.String EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY";
-    field public static final java.lang.String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
-    field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
-    field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
-    field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
-    field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
-    field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
-    field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
-    field public static final java.lang.String EXTRA_QUICK_VIEW_FEATURES = "android.intent.extra.QUICK_VIEW_FEATURES";
-    field public static final java.lang.String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
-    field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
-    field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
-    field public static final java.lang.String EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token";
-    field public static final java.lang.String EXTRA_REPLACEMENT_EXTRAS = "android.intent.extra.REPLACEMENT_EXTRAS";
-    field public static final java.lang.String EXTRA_REPLACING = "android.intent.extra.REPLACING";
-    field public static final java.lang.String EXTRA_RESTRICTIONS_BUNDLE = "android.intent.extra.restrictions_bundle";
-    field public static final java.lang.String EXTRA_RESTRICTIONS_INTENT = "android.intent.extra.restrictions_intent";
-    field public static final java.lang.String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
-    field public static final java.lang.String EXTRA_RESULT_RECEIVER = "android.intent.extra.RESULT_RECEIVER";
-    field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
-    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
-    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
-    field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
-    field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
-    field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
-    field public static final java.lang.String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME";
-    field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
-    field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
-    field public static final java.lang.String EXTRA_SUSPENDED_PACKAGE_EXTRAS = "android.intent.extra.SUSPENDED_PACKAGE_EXTRAS";
-    field public static final java.lang.String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
-    field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT";
-    field public static final java.lang.String EXTRA_TITLE = "android.intent.extra.TITLE";
-    field public static final java.lang.String EXTRA_UID = "android.intent.extra.UID";
-    field public static final java.lang.String EXTRA_USER = "android.intent.extra.USER";
+    field public static final String EXTRA_DONT_KILL_APP = "android.intent.extra.DONT_KILL_APP";
+    field public static final String EXTRA_DURATION_MILLIS = "android.intent.extra.DURATION_MILLIS";
+    field public static final String EXTRA_EMAIL = "android.intent.extra.EMAIL";
+    field public static final String EXTRA_EXCLUDE_COMPONENTS = "android.intent.extra.EXCLUDE_COMPONENTS";
+    field public static final String EXTRA_FROM_STORAGE = "android.intent.extra.FROM_STORAGE";
+    field public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+    field public static final String EXTRA_INDEX = "android.intent.extra.INDEX";
+    field public static final String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
+    field public static final String EXTRA_INSTALLER_PACKAGE_NAME = "android.intent.extra.INSTALLER_PACKAGE_NAME";
+    field public static final String EXTRA_INTENT = "android.intent.extra.INTENT";
+    field public static final String EXTRA_KEY_EVENT = "android.intent.extra.KEY_EVENT";
+    field public static final String EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY";
+    field public static final String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
+    field public static final String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
+    field public static final String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
+    field public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
+    field public static final String EXTRA_PERMISSION_USAGE_PERMISSIONS = "android.intent.extra.PERMISSION_USAGE_PERMISSIONS";
+    field public static final String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
+    field public static final String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
+    field public static final String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
+    field public static final String EXTRA_QUICK_VIEW_FEATURES = "android.intent.extra.QUICK_VIEW_FEATURES";
+    field public static final String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
+    field public static final String EXTRA_REFERRER = "android.intent.extra.REFERRER";
+    field public static final String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
+    field public static final String EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token";
+    field public static final String EXTRA_REPLACEMENT_EXTRAS = "android.intent.extra.REPLACEMENT_EXTRAS";
+    field public static final String EXTRA_REPLACING = "android.intent.extra.REPLACING";
+    field public static final String EXTRA_RESTRICTIONS_BUNDLE = "android.intent.extra.restrictions_bundle";
+    field public static final String EXTRA_RESTRICTIONS_INTENT = "android.intent.extra.restrictions_intent";
+    field public static final String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
+    field public static final String EXTRA_RESULT_RECEIVER = "android.intent.extra.RESULT_RECEIVER";
+    field public static final String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
+    field @Deprecated public static final String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
+    field @Deprecated public static final String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
+    field public static final String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID";
+    field @Deprecated public static final String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
+    field @Deprecated public static final String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
+    field public static final String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
+    field public static final String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME";
+    field public static final String EXTRA_STREAM = "android.intent.extra.STREAM";
+    field public static final String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
+    field public static final String EXTRA_SUSPENDED_PACKAGE_EXTRAS = "android.intent.extra.SUSPENDED_PACKAGE_EXTRAS";
+    field public static final String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
+    field public static final String EXTRA_TEXT = "android.intent.extra.TEXT";
+    field public static final String EXTRA_TITLE = "android.intent.extra.TITLE";
+    field public static final String EXTRA_UID = "android.intent.extra.UID";
+    field public static final String EXTRA_USER = "android.intent.extra.USER";
     field public static final int FILL_IN_ACTION = 1; // 0x1
     field public static final int FILL_IN_CATEGORIES = 4; // 0x4
     field public static final int FILL_IN_CLIP_DATA = 128; // 0x80
@@ -10363,7 +10413,7 @@
     field public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 4194304; // 0x400000
     field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
     field public static final int FLAG_ACTIVITY_CLEAR_TOP = 67108864; // 0x4000000
-    field public static final deprecated int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 524288; // 0x80000
+    field @Deprecated public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 524288; // 0x80000
     field public static final int FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS = 8388608; // 0x800000
     field public static final int FLAG_ACTIVITY_FORWARD_RESULT = 33554432; // 0x2000000
     field public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 1048576; // 0x100000
@@ -10395,7 +10445,7 @@
     field public static final int FLAG_RECEIVER_REGISTERED_ONLY = 1073741824; // 0x40000000
     field public static final int FLAG_RECEIVER_REPLACE_PENDING = 536870912; // 0x20000000
     field public static final int FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS = 2097152; // 0x200000
-    field public static final java.lang.String METADATA_DOCK_HOME = "android.dock_home";
+    field public static final String METADATA_DOCK_HOME = "android.dock_home";
     field public static final int URI_ALLOW_UNSAFE = 4; // 0x4
     field public static final int URI_ANDROID_APP_SCHEME = 2; // 0x2
     field public static final int URI_INTENT_SCHEME = 1; // 0x1
@@ -10409,26 +10459,26 @@
   public static class Intent.ShortcutIconResource implements android.os.Parcelable {
     ctor public Intent.ShortcutIconResource();
     method public int describeContents();
-    method public static android.content.Intent.ShortcutIconResource fromContext(android.content.Context, int);
+    method public static android.content.Intent.ShortcutIconResource fromContext(android.content.Context, @AnyRes int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.Intent.ShortcutIconResource> CREATOR;
-    field public java.lang.String packageName;
-    field public java.lang.String resourceName;
+    field public String packageName;
+    field public String resourceName;
   }
 
   public class IntentFilter implements android.os.Parcelable {
     ctor public IntentFilter();
-    ctor public IntentFilter(java.lang.String);
-    ctor public IntentFilter(java.lang.String, java.lang.String) throws android.content.IntentFilter.MalformedMimeTypeException;
+    ctor public IntentFilter(String);
+    ctor public IntentFilter(String, String) throws android.content.IntentFilter.MalformedMimeTypeException;
     ctor public IntentFilter(android.content.IntentFilter);
     method public final java.util.Iterator<java.lang.String> actionsIterator();
-    method public final void addAction(java.lang.String);
-    method public final void addCategory(java.lang.String);
-    method public final void addDataAuthority(java.lang.String, java.lang.String);
-    method public final void addDataPath(java.lang.String, int);
-    method public final void addDataScheme(java.lang.String);
-    method public final void addDataSchemeSpecificPart(java.lang.String, int);
-    method public final void addDataType(java.lang.String) throws android.content.IntentFilter.MalformedMimeTypeException;
+    method public final void addAction(String);
+    method public final void addCategory(String);
+    method public final void addDataAuthority(String, String);
+    method public final void addDataPath(String, int);
+    method public final void addDataScheme(String);
+    method public final void addDataSchemeSpecificPart(String, int);
+    method public final void addDataType(String) throws android.content.IntentFilter.MalformedMimeTypeException;
     method public final java.util.Iterator<android.content.IntentFilter.AuthorityEntry> authoritiesIterator();
     method public final java.util.Iterator<java.lang.String> categoriesIterator();
     method public final int countActions();
@@ -10438,29 +10488,29 @@
     method public final int countDataSchemeSpecificParts();
     method public final int countDataSchemes();
     method public final int countDataTypes();
-    method public static android.content.IntentFilter create(java.lang.String, java.lang.String);
+    method public static android.content.IntentFilter create(String, String);
     method public final int describeContents();
-    method public void dump(android.util.Printer, java.lang.String);
-    method public final java.lang.String getAction(int);
-    method public final java.lang.String getCategory(int);
+    method public void dump(android.util.Printer, String);
+    method public final String getAction(int);
+    method public final String getCategory(int);
     method public final android.content.IntentFilter.AuthorityEntry getDataAuthority(int);
     method public final android.os.PatternMatcher getDataPath(int);
-    method public final java.lang.String getDataScheme(int);
+    method public final String getDataScheme(int);
     method public final android.os.PatternMatcher getDataSchemeSpecificPart(int);
-    method public final java.lang.String getDataType(int);
+    method public final String getDataType(int);
     method public final int getPriority();
-    method public final boolean hasAction(java.lang.String);
-    method public final boolean hasCategory(java.lang.String);
+    method public final boolean hasAction(String);
+    method public final boolean hasCategory(String);
     method public final boolean hasDataAuthority(android.net.Uri);
-    method public final boolean hasDataPath(java.lang.String);
-    method public final boolean hasDataScheme(java.lang.String);
-    method public final boolean hasDataSchemeSpecificPart(java.lang.String);
-    method public final boolean hasDataType(java.lang.String);
-    method public final int match(android.content.ContentResolver, android.content.Intent, boolean, java.lang.String);
-    method public final int match(java.lang.String, java.lang.String, java.lang.String, android.net.Uri, java.util.Set<java.lang.String>, java.lang.String);
-    method public final boolean matchAction(java.lang.String);
-    method public final java.lang.String matchCategories(java.util.Set<java.lang.String>);
-    method public final int matchData(java.lang.String, java.lang.String, android.net.Uri);
+    method public final boolean hasDataPath(String);
+    method public final boolean hasDataScheme(String);
+    method public final boolean hasDataSchemeSpecificPart(String);
+    method public final boolean hasDataType(String);
+    method public final int match(android.content.ContentResolver, android.content.Intent, boolean, String);
+    method public final int match(String, String, String, android.net.Uri, java.util.Set<java.lang.String>, String);
+    method public final boolean matchAction(String);
+    method public final String matchCategories(java.util.Set<java.lang.String>);
+    method public final int matchData(String, String, android.net.Uri);
     method public final int matchDataAuthority(android.net.Uri);
     method public final java.util.Iterator<android.os.PatternMatcher> pathsIterator();
     method public void readFromXml(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -10490,84 +10540,84 @@
   }
 
   public static final class IntentFilter.AuthorityEntry {
-    ctor public IntentFilter.AuthorityEntry(java.lang.String, java.lang.String);
-    method public java.lang.String getHost();
+    ctor public IntentFilter.AuthorityEntry(String, String);
+    method public String getHost();
     method public int getPort();
     method public int match(android.net.Uri);
   }
 
   public static class IntentFilter.MalformedMimeTypeException extends android.util.AndroidException {
     ctor public IntentFilter.MalformedMimeTypeException();
-    ctor public IntentFilter.MalformedMimeTypeException(java.lang.String);
+    ctor public IntentFilter.MalformedMimeTypeException(String);
   }
 
   public class IntentSender implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getCreatorPackage();
+    method public String getCreatorPackage();
     method public int getCreatorUid();
     method public android.os.UserHandle getCreatorUserHandle();
-    method public deprecated java.lang.String getTargetPackage();
+    method @Deprecated public String getTargetPackage();
     method public static android.content.IntentSender readIntentSenderOrNullFromParcel(android.os.Parcel);
     method public void sendIntent(android.content.Context, int, android.content.Intent, android.content.IntentSender.OnFinished, android.os.Handler) throws android.content.IntentSender.SendIntentException;
-    method public void sendIntent(android.content.Context, int, android.content.Intent, android.content.IntentSender.OnFinished, android.os.Handler, java.lang.String) throws android.content.IntentSender.SendIntentException;
+    method public void sendIntent(android.content.Context, int, android.content.Intent, android.content.IntentSender.OnFinished, android.os.Handler, String) throws android.content.IntentSender.SendIntentException;
     method public static void writeIntentSenderOrNullToParcel(android.content.IntentSender, android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.IntentSender> CREATOR;
   }
 
-  public static abstract interface IntentSender.OnFinished {
-    method public abstract void onSendFinished(android.content.IntentSender, android.content.Intent, int, java.lang.String, android.os.Bundle);
+  public static interface IntentSender.OnFinished {
+    method public void onSendFinished(android.content.IntentSender, android.content.Intent, int, String, android.os.Bundle);
   }
 
   public static class IntentSender.SendIntentException extends android.util.AndroidException {
     ctor public IntentSender.SendIntentException();
-    ctor public IntentSender.SendIntentException(java.lang.String);
-    ctor public IntentSender.SendIntentException(java.lang.Exception);
+    ctor public IntentSender.SendIntentException(String);
+    ctor public IntentSender.SendIntentException(Exception);
   }
 
-  public deprecated class Loader<D> {
-    ctor public Loader(android.content.Context);
-    method public void abandon();
-    method public boolean cancelLoad();
-    method public void commitContentChanged();
-    method public java.lang.String dataToString(D);
-    method public void deliverCancellation();
-    method public void deliverResult(D);
-    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public void forceLoad();
-    method public android.content.Context getContext();
-    method public int getId();
-    method public boolean isAbandoned();
-    method public boolean isReset();
-    method public boolean isStarted();
-    method protected void onAbandon();
-    method protected boolean onCancelLoad();
-    method public void onContentChanged();
-    method protected void onForceLoad();
-    method protected void onReset();
-    method protected void onStartLoading();
-    method protected void onStopLoading();
-    method public void registerListener(int, android.content.Loader.OnLoadCompleteListener<D>);
-    method public void registerOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
-    method public void reset();
-    method public void rollbackContentChanged();
-    method public final void startLoading();
-    method public void stopLoading();
-    method public boolean takeContentChanged();
-    method public void unregisterListener(android.content.Loader.OnLoadCompleteListener<D>);
-    method public void unregisterOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
+  @Deprecated public class Loader<D> {
+    ctor @Deprecated public Loader(android.content.Context);
+    method @Deprecated public void abandon();
+    method @Deprecated public boolean cancelLoad();
+    method @Deprecated public void commitContentChanged();
+    method @Deprecated public String dataToString(D);
+    method @Deprecated public void deliverCancellation();
+    method @Deprecated public void deliverResult(D);
+    method @Deprecated public void dump(String, java.io.FileDescriptor, java.io.PrintWriter, String[]);
+    method @Deprecated public void forceLoad();
+    method @Deprecated public android.content.Context getContext();
+    method @Deprecated public int getId();
+    method @Deprecated public boolean isAbandoned();
+    method @Deprecated public boolean isReset();
+    method @Deprecated public boolean isStarted();
+    method @Deprecated protected void onAbandon();
+    method @Deprecated protected boolean onCancelLoad();
+    method @Deprecated public void onContentChanged();
+    method @Deprecated protected void onForceLoad();
+    method @Deprecated protected void onReset();
+    method @Deprecated protected void onStartLoading();
+    method @Deprecated protected void onStopLoading();
+    method @Deprecated public void registerListener(int, android.content.Loader.OnLoadCompleteListener<D>);
+    method @Deprecated public void registerOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
+    method @Deprecated public void reset();
+    method @Deprecated public void rollbackContentChanged();
+    method @Deprecated public final void startLoading();
+    method @Deprecated public void stopLoading();
+    method @Deprecated public boolean takeContentChanged();
+    method @Deprecated public void unregisterListener(android.content.Loader.OnLoadCompleteListener<D>);
+    method @Deprecated public void unregisterOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
   }
 
-  public final deprecated class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
-    ctor public Loader.ForceLoadContentObserver();
+  @Deprecated public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
+    ctor @Deprecated public Loader.ForceLoadContentObserver();
   }
 
-  public static abstract deprecated interface Loader.OnLoadCanceledListener<D> {
-    method public abstract void onLoadCanceled(android.content.Loader<D>);
+  @Deprecated public static interface Loader.OnLoadCanceledListener<D> {
+    method @Deprecated public void onLoadCanceled(android.content.Loader<D>);
   }
 
-  public static abstract deprecated interface Loader.OnLoadCompleteListener<D> {
-    method public abstract void onLoadComplete(android.content.Loader<D>, D);
+  @Deprecated public static interface Loader.OnLoadCompleteListener<D> {
+    method @Deprecated public void onLoadComplete(android.content.Loader<D>, D);
   }
 
   public class MutableContextWrapper extends android.content.ContextWrapper {
@@ -10577,70 +10627,70 @@
 
   public class OperationApplicationException extends java.lang.Exception {
     ctor public OperationApplicationException();
-    ctor public OperationApplicationException(java.lang.String);
-    ctor public OperationApplicationException(java.lang.String, java.lang.Throwable);
-    ctor public OperationApplicationException(java.lang.Throwable);
+    ctor public OperationApplicationException(String);
+    ctor public OperationApplicationException(String, Throwable);
+    ctor public OperationApplicationException(Throwable);
     ctor public OperationApplicationException(int);
-    ctor public OperationApplicationException(java.lang.String, int);
+    ctor public OperationApplicationException(String, int);
     method public int getNumSuccessfulYieldPoints();
   }
 
   public class PeriodicSync implements android.os.Parcelable {
-    ctor public PeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle, long);
+    ctor public PeriodicSync(android.accounts.Account, String, android.os.Bundle, long);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.PeriodicSync> CREATOR;
     field public final android.accounts.Account account;
-    field public final java.lang.String authority;
+    field public final String authority;
     field public final android.os.Bundle extras;
     field public final long period;
   }
 
   public class QuickViewConstants {
-    field public static final java.lang.String FEATURE_DELETE = "android:delete";
-    field public static final java.lang.String FEATURE_DOWNLOAD = "android:download";
-    field public static final java.lang.String FEATURE_EDIT = "android:edit";
-    field public static final java.lang.String FEATURE_PRINT = "android:print";
-    field public static final java.lang.String FEATURE_SEND = "android:send";
-    field public static final java.lang.String FEATURE_VIEW = "android:view";
+    field public static final String FEATURE_DELETE = "android:delete";
+    field public static final String FEATURE_DOWNLOAD = "android:download";
+    field public static final String FEATURE_EDIT = "android:edit";
+    field public static final String FEATURE_PRINT = "android:print";
+    field public static final String FEATURE_SEND = "android:send";
+    field public static final String FEATURE_VIEW = "android:view";
   }
 
   public class ReceiverCallNotAllowedException extends android.util.AndroidRuntimeException {
-    ctor public ReceiverCallNotAllowedException(java.lang.String);
+    ctor public ReceiverCallNotAllowedException(String);
   }
 
   public class RestrictionEntry implements android.os.Parcelable {
-    ctor public RestrictionEntry(int, java.lang.String);
-    ctor public RestrictionEntry(java.lang.String, java.lang.String);
-    ctor public RestrictionEntry(java.lang.String, boolean);
-    ctor public RestrictionEntry(java.lang.String, java.lang.String[]);
-    ctor public RestrictionEntry(java.lang.String, int);
+    ctor public RestrictionEntry(int, String);
+    ctor public RestrictionEntry(String, String);
+    ctor public RestrictionEntry(String, boolean);
+    ctor public RestrictionEntry(String, String[]);
+    ctor public RestrictionEntry(String, int);
     ctor public RestrictionEntry(android.os.Parcel);
-    method public static android.content.RestrictionEntry createBundleArrayEntry(java.lang.String, android.content.RestrictionEntry[]);
-    method public static android.content.RestrictionEntry createBundleEntry(java.lang.String, android.content.RestrictionEntry[]);
+    method public static android.content.RestrictionEntry createBundleArrayEntry(String, android.content.RestrictionEntry[]);
+    method public static android.content.RestrictionEntry createBundleEntry(String, android.content.RestrictionEntry[]);
     method public int describeContents();
-    method public java.lang.String[] getAllSelectedStrings();
-    method public java.lang.String[] getChoiceEntries();
-    method public java.lang.String[] getChoiceValues();
-    method public java.lang.String getDescription();
+    method public String[] getAllSelectedStrings();
+    method public String[] getChoiceEntries();
+    method public String[] getChoiceValues();
+    method public String getDescription();
     method public int getIntValue();
-    method public java.lang.String getKey();
+    method public String getKey();
     method public android.content.RestrictionEntry[] getRestrictions();
     method public boolean getSelectedState();
-    method public java.lang.String getSelectedString();
-    method public java.lang.String getTitle();
+    method public String getSelectedString();
+    method public String getTitle();
     method public int getType();
-    method public void setAllSelectedStrings(java.lang.String[]);
-    method public void setChoiceEntries(java.lang.String[]);
-    method public void setChoiceEntries(android.content.Context, int);
-    method public void setChoiceValues(java.lang.String[]);
-    method public void setChoiceValues(android.content.Context, int);
-    method public void setDescription(java.lang.String);
+    method public void setAllSelectedStrings(String[]);
+    method public void setChoiceEntries(String[]);
+    method public void setChoiceEntries(android.content.Context, @ArrayRes int);
+    method public void setChoiceValues(String[]);
+    method public void setChoiceValues(android.content.Context, @ArrayRes int);
+    method public void setDescription(String);
     method public void setIntValue(int);
     method public void setRestrictions(android.content.RestrictionEntry[]);
     method public void setSelectedState(boolean);
-    method public void setSelectedString(java.lang.String);
-    method public void setTitle(java.lang.String);
+    method public void setSelectedString(String);
+    method public void setTitle(String);
     method public void setType(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.RestrictionEntry> CREATOR;
@@ -10658,32 +10708,32 @@
     method public static android.os.Bundle convertRestrictionsToBundle(java.util.List<android.content.RestrictionEntry>);
     method public android.content.Intent createLocalApprovalIntent();
     method public android.os.Bundle getApplicationRestrictions();
-    method public java.util.List<android.content.RestrictionEntry> getManifestRestrictions(java.lang.String);
+    method public java.util.List<android.content.RestrictionEntry> getManifestRestrictions(String);
     method public boolean hasRestrictionsProvider();
-    method public void notifyPermissionResponse(java.lang.String, android.os.PersistableBundle);
-    method public void requestPermission(java.lang.String, java.lang.String, android.os.PersistableBundle);
-    field public static final java.lang.String ACTION_PERMISSION_RESPONSE_RECEIVED = "android.content.action.PERMISSION_RESPONSE_RECEIVED";
-    field public static final java.lang.String ACTION_REQUEST_LOCAL_APPROVAL = "android.content.action.REQUEST_LOCAL_APPROVAL";
-    field public static final java.lang.String ACTION_REQUEST_PERMISSION = "android.content.action.REQUEST_PERMISSION";
-    field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.extra.PACKAGE_NAME";
-    field public static final java.lang.String EXTRA_REQUEST_BUNDLE = "android.content.extra.REQUEST_BUNDLE";
-    field public static final java.lang.String EXTRA_REQUEST_ID = "android.content.extra.REQUEST_ID";
-    field public static final java.lang.String EXTRA_REQUEST_TYPE = "android.content.extra.REQUEST_TYPE";
-    field public static final java.lang.String EXTRA_RESPONSE_BUNDLE = "android.content.extra.RESPONSE_BUNDLE";
-    field public static final java.lang.String META_DATA_APP_RESTRICTIONS = "android.content.APP_RESTRICTIONS";
-    field public static final java.lang.String REQUEST_KEY_APPROVE_LABEL = "android.request.approve_label";
-    field public static final java.lang.String REQUEST_KEY_DATA = "android.request.data";
-    field public static final java.lang.String REQUEST_KEY_DENY_LABEL = "android.request.deny_label";
-    field public static final java.lang.String REQUEST_KEY_ICON = "android.request.icon";
-    field public static final java.lang.String REQUEST_KEY_ID = "android.request.id";
-    field public static final java.lang.String REQUEST_KEY_MESSAGE = "android.request.mesg";
-    field public static final java.lang.String REQUEST_KEY_NEW_REQUEST = "android.request.new_request";
-    field public static final java.lang.String REQUEST_KEY_TITLE = "android.request.title";
-    field public static final java.lang.String REQUEST_TYPE_APPROVAL = "android.request.type.approval";
-    field public static final java.lang.String RESPONSE_KEY_ERROR_CODE = "android.response.errorcode";
-    field public static final java.lang.String RESPONSE_KEY_MESSAGE = "android.response.msg";
-    field public static final java.lang.String RESPONSE_KEY_RESPONSE_TIMESTAMP = "android.response.timestamp";
-    field public static final java.lang.String RESPONSE_KEY_RESULT = "android.response.result";
+    method public void notifyPermissionResponse(String, android.os.PersistableBundle);
+    method public void requestPermission(String, String, android.os.PersistableBundle);
+    field public static final String ACTION_PERMISSION_RESPONSE_RECEIVED = "android.content.action.PERMISSION_RESPONSE_RECEIVED";
+    field public static final String ACTION_REQUEST_LOCAL_APPROVAL = "android.content.action.REQUEST_LOCAL_APPROVAL";
+    field public static final String ACTION_REQUEST_PERMISSION = "android.content.action.REQUEST_PERMISSION";
+    field public static final String EXTRA_PACKAGE_NAME = "android.content.extra.PACKAGE_NAME";
+    field public static final String EXTRA_REQUEST_BUNDLE = "android.content.extra.REQUEST_BUNDLE";
+    field public static final String EXTRA_REQUEST_ID = "android.content.extra.REQUEST_ID";
+    field public static final String EXTRA_REQUEST_TYPE = "android.content.extra.REQUEST_TYPE";
+    field public static final String EXTRA_RESPONSE_BUNDLE = "android.content.extra.RESPONSE_BUNDLE";
+    field public static final String META_DATA_APP_RESTRICTIONS = "android.content.APP_RESTRICTIONS";
+    field public static final String REQUEST_KEY_APPROVE_LABEL = "android.request.approve_label";
+    field public static final String REQUEST_KEY_DATA = "android.request.data";
+    field public static final String REQUEST_KEY_DENY_LABEL = "android.request.deny_label";
+    field public static final String REQUEST_KEY_ICON = "android.request.icon";
+    field public static final String REQUEST_KEY_ID = "android.request.id";
+    field public static final String REQUEST_KEY_MESSAGE = "android.request.mesg";
+    field public static final String REQUEST_KEY_NEW_REQUEST = "android.request.new_request";
+    field public static final String REQUEST_KEY_TITLE = "android.request.title";
+    field public static final String REQUEST_TYPE_APPROVAL = "android.request.type.approval";
+    field public static final String RESPONSE_KEY_ERROR_CODE = "android.response.errorcode";
+    field public static final String RESPONSE_KEY_MESSAGE = "android.response.msg";
+    field public static final String RESPONSE_KEY_RESPONSE_TIMESTAMP = "android.response.timestamp";
+    field public static final String RESPONSE_KEY_RESULT = "android.response.result";
     field public static final int RESULT_APPROVED = 1; // 0x1
     field public static final int RESULT_DENIED = 2; // 0x2
     field public static final int RESULT_ERROR = 5; // 0x5
@@ -10696,69 +10746,69 @@
 
   public class SearchRecentSuggestionsProvider extends android.content.ContentProvider {
     ctor public SearchRecentSuggestionsProvider();
-    method public int delete(android.net.Uri, java.lang.String, java.lang.String[]);
-    method public java.lang.String getType(android.net.Uri);
+    method public int delete(android.net.Uri, String, String[]);
+    method public String getType(android.net.Uri);
     method public android.net.Uri insert(android.net.Uri, android.content.ContentValues);
     method public boolean onCreate();
-    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method protected void setupSuggestions(java.lang.String, int);
-    method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+    method public android.database.Cursor query(android.net.Uri, String[], String, String[], String);
+    method protected void setupSuggestions(String, int);
+    method public int update(android.net.Uri, android.content.ContentValues, String, String[]);
     field public static final int DATABASE_MODE_2LINES = 2; // 0x2
     field public static final int DATABASE_MODE_QUERIES = 1; // 0x1
   }
 
-  public abstract interface ServiceConnection {
+  public interface ServiceConnection {
     method public default void onBindingDied(android.content.ComponentName);
     method public default void onNullBinding(android.content.ComponentName);
-    method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder);
-    method public abstract void onServiceDisconnected(android.content.ComponentName);
+    method public void onServiceConnected(android.content.ComponentName, android.os.IBinder);
+    method public void onServiceDisconnected(android.content.ComponentName);
   }
 
-  public abstract interface SharedPreferences {
-    method public abstract boolean contains(java.lang.String);
-    method public abstract android.content.SharedPreferences.Editor edit();
-    method public abstract java.util.Map<java.lang.String, ?> getAll();
-    method public abstract boolean getBoolean(java.lang.String, boolean);
-    method public abstract float getFloat(java.lang.String, float);
-    method public abstract int getInt(java.lang.String, int);
-    method public abstract long getLong(java.lang.String, long);
-    method public abstract java.lang.String getString(java.lang.String, java.lang.String);
-    method public abstract java.util.Set<java.lang.String> getStringSet(java.lang.String, java.util.Set<java.lang.String>);
-    method public abstract void registerOnSharedPreferenceChangeListener(android.content.SharedPreferences.OnSharedPreferenceChangeListener);
-    method public abstract void unregisterOnSharedPreferenceChangeListener(android.content.SharedPreferences.OnSharedPreferenceChangeListener);
+  public interface SharedPreferences {
+    method public boolean contains(String);
+    method public android.content.SharedPreferences.Editor edit();
+    method public java.util.Map<java.lang.String,?> getAll();
+    method public boolean getBoolean(String, boolean);
+    method public float getFloat(String, float);
+    method public int getInt(String, int);
+    method public long getLong(String, long);
+    method @Nullable public String getString(String, @Nullable String);
+    method @Nullable public java.util.Set<java.lang.String> getStringSet(String, @Nullable java.util.Set<java.lang.String>);
+    method public void registerOnSharedPreferenceChangeListener(android.content.SharedPreferences.OnSharedPreferenceChangeListener);
+    method public void unregisterOnSharedPreferenceChangeListener(android.content.SharedPreferences.OnSharedPreferenceChangeListener);
   }
 
-  public static abstract interface SharedPreferences.Editor {
-    method public abstract void apply();
-    method public abstract android.content.SharedPreferences.Editor clear();
-    method public abstract boolean commit();
-    method public abstract android.content.SharedPreferences.Editor putBoolean(java.lang.String, boolean);
-    method public abstract android.content.SharedPreferences.Editor putFloat(java.lang.String, float);
-    method public abstract android.content.SharedPreferences.Editor putInt(java.lang.String, int);
-    method public abstract android.content.SharedPreferences.Editor putLong(java.lang.String, long);
-    method public abstract android.content.SharedPreferences.Editor putString(java.lang.String, java.lang.String);
-    method public abstract android.content.SharedPreferences.Editor putStringSet(java.lang.String, java.util.Set<java.lang.String>);
-    method public abstract android.content.SharedPreferences.Editor remove(java.lang.String);
+  public static interface SharedPreferences.Editor {
+    method public void apply();
+    method public android.content.SharedPreferences.Editor clear();
+    method public boolean commit();
+    method public android.content.SharedPreferences.Editor putBoolean(String, boolean);
+    method public android.content.SharedPreferences.Editor putFloat(String, float);
+    method public android.content.SharedPreferences.Editor putInt(String, int);
+    method public android.content.SharedPreferences.Editor putLong(String, long);
+    method public android.content.SharedPreferences.Editor putString(String, @Nullable String);
+    method public android.content.SharedPreferences.Editor putStringSet(String, @Nullable java.util.Set<java.lang.String>);
+    method public android.content.SharedPreferences.Editor remove(String);
   }
 
-  public static abstract interface SharedPreferences.OnSharedPreferenceChangeListener {
-    method public abstract void onSharedPreferenceChanged(android.content.SharedPreferences, java.lang.String);
+  public static interface SharedPreferences.OnSharedPreferenceChangeListener {
+    method public void onSharedPreferenceChanged(android.content.SharedPreferences, String);
   }
 
   public class SyncAdapterType implements android.os.Parcelable {
-    ctor public SyncAdapterType(java.lang.String, java.lang.String, boolean, boolean);
+    ctor public SyncAdapterType(String, String, boolean, boolean);
     ctor public SyncAdapterType(android.os.Parcel);
     method public boolean allowParallelSyncs();
     method public int describeContents();
-    method public java.lang.String getSettingsActivity();
+    method public String getSettingsActivity();
     method public boolean isAlwaysSyncable();
     method public boolean isUserVisible();
-    method public static android.content.SyncAdapterType newKey(java.lang.String, java.lang.String);
+    method public static android.content.SyncAdapterType newKey(String, String);
     method public boolean supportsUploading();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.SyncAdapterType> CREATOR;
-    field public final java.lang.String accountType;
-    field public final java.lang.String authority;
+    field public final String accountType;
+    field public final String authority;
     field public final boolean isKey;
   }
 
@@ -10771,7 +10821,7 @@
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public final android.accounts.Account account;
-    field public final java.lang.String authority;
+    field public final String authority;
     field public final long startTime;
   }
 
@@ -10792,7 +10842,7 @@
     method public android.content.SyncRequest.Builder setManual(boolean);
     method public android.content.SyncRequest.Builder setNoRetry(boolean);
     method public android.content.SyncRequest.Builder setRequiresCharging(boolean);
-    method public android.content.SyncRequest.Builder setSyncAdapter(android.accounts.Account, java.lang.String);
+    method public android.content.SyncRequest.Builder setSyncAdapter(android.accounts.Account, String);
     method public android.content.SyncRequest.Builder syncOnce();
     method public android.content.SyncRequest.Builder syncPeriodic(long, long);
   }
@@ -10805,7 +10855,7 @@
     method public boolean hasHardError();
     method public boolean hasSoftError();
     method public boolean madeSomeProgress();
-    method public java.lang.String toDebugString();
+    method public String toDebugString();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.content.SyncResult ALREADY_IN_PROGRESS;
     field public static final android.os.Parcelable.Creator<android.content.SyncResult> CREATOR;
@@ -10838,13 +10888,13 @@
     field public long numUpdates;
   }
 
-  public abstract interface SyncStatusObserver {
-    method public abstract void onStatusChanged(int);
+  public interface SyncStatusObserver {
+    method public void onStatusChanged(int);
   }
 
   public class UriMatcher {
     ctor public UriMatcher(int);
-    method public void addURI(java.lang.String, java.lang.String, int);
+    method public void addURI(String, String, int);
     method public int match(android.net.Uri);
     field public static final int NO_MATCH = -1; // 0xffffffff
   }
@@ -10868,7 +10918,7 @@
     ctor public ActivityInfo();
     ctor public ActivityInfo(android.content.pm.ActivityInfo);
     method public int describeContents();
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(android.util.Printer, String);
     method public final int getThemeResource();
     field public static final int COLOR_MODE_DEFAULT = 0; // 0x0
     field public static final int COLOR_MODE_HDR = 2; // 0x2
@@ -10940,13 +10990,13 @@
     field public int flags;
     field public int launchMode;
     field public int maxRecents;
-    field public java.lang.String parentActivityName;
-    field public java.lang.String permission;
+    field public String parentActivityName;
+    field public String permission;
     field public int persistableMode;
     field public int screenOrientation;
     field public int softInputMode;
-    field public java.lang.String targetActivity;
-    field public java.lang.String taskAffinity;
+    field public String targetActivity;
+    field public String taskAffinity;
     field public int theme;
     field public int uiOptions;
     field public android.content.pm.ActivityInfo.WindowLayout windowLayout;
@@ -10967,11 +11017,11 @@
     ctor public ApplicationInfo();
     ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
     method public int describeContents();
-    method public void dump(android.util.Printer, java.lang.String);
-    method public static java.lang.CharSequence getCategoryTitle(android.content.Context, int);
+    method public void dump(android.util.Printer, String);
+    method public static CharSequence getCategoryTitle(android.content.Context, int);
     method public boolean isProfileableByShell();
     method public boolean isVirtualPreload();
-    method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
+    method public CharSequence loadDescription(android.content.pm.PackageManager);
     field public static final int CATEGORY_AUDIO = 1; // 0x1
     field public static final int CATEGORY_GAME = 0; // 0x0
     field public static final int CATEGORY_IMAGE = 3; // 0x3
@@ -10994,7 +11044,7 @@
     field public static final int FLAG_HAS_CODE = 4; // 0x4
     field public static final int FLAG_INSTALLED = 8388608; // 0x800000
     field public static final int FLAG_IS_DATA_ONLY = 16777216; // 0x1000000
-    field public static final deprecated int FLAG_IS_GAME = 33554432; // 0x2000000
+    field @Deprecated public static final int FLAG_IS_GAME = 33554432; // 0x2000000
     field public static final int FLAG_KILL_AFTER_RESTORE = 65536; // 0x10000
     field public static final int FLAG_LARGE_HEAP = 1048576; // 0x100000
     field public static final int FLAG_MULTIARCH = -2147483648; // 0x80000000
@@ -11014,46 +11064,46 @@
     field public static final int FLAG_UPDATED_SYSTEM_APP = 128; // 0x80
     field public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 134217728; // 0x8000000
     field public static final int FLAG_VM_SAFE_MODE = 16384; // 0x4000
-    field public java.lang.String appComponentFactory;
-    field public java.lang.String backupAgentName;
+    field public String appComponentFactory;
+    field public String backupAgentName;
     field public int category;
-    field public java.lang.String className;
+    field public String className;
     field public int compatibleWidthLimitDp;
-    field public java.lang.String dataDir;
+    field public String dataDir;
     field public int descriptionRes;
-    field public java.lang.String deviceProtectedDataDir;
+    field public String deviceProtectedDataDir;
     field public boolean enabled;
     field public int flags;
     field public int largestWidthLimitDp;
-    field public java.lang.String manageSpaceActivityName;
+    field public String manageSpaceActivityName;
     field public int minSdkVersion;
-    field public java.lang.String nativeLibraryDir;
-    field public java.lang.String permission;
-    field public java.lang.String processName;
-    field public java.lang.String publicSourceDir;
+    field public String nativeLibraryDir;
+    field public String permission;
+    field public String processName;
+    field public String publicSourceDir;
     field public int requiresSmallestWidthDp;
-    field public java.lang.String[] sharedLibraryFiles;
-    field public java.lang.String sourceDir;
-    field public java.lang.String[] splitNames;
-    field public java.lang.String[] splitPublicSourceDirs;
-    field public java.lang.String[] splitSourceDirs;
+    field public String[] sharedLibraryFiles;
+    field public String sourceDir;
+    field public String[] splitNames;
+    field public String[] splitPublicSourceDirs;
+    field public String[] splitSourceDirs;
     field public java.util.UUID storageUuid;
     field public int targetSdkVersion;
-    field public java.lang.String taskAffinity;
+    field public String taskAffinity;
     field public int theme;
     field public int uiOptions;
     field public int uid;
   }
 
-  public static class ApplicationInfo.DisplayNameComparator implements java.util.Comparator {
+  public static class ApplicationInfo.DisplayNameComparator implements java.util.Comparator<android.content.pm.ApplicationInfo> {
     ctor public ApplicationInfo.DisplayNameComparator(android.content.pm.PackageManager);
     method public final int compare(android.content.pm.ApplicationInfo, android.content.pm.ApplicationInfo);
   }
 
   public final class ChangedPackages implements android.os.Parcelable {
-    ctor public ChangedPackages(int, java.util.List<java.lang.String>);
+    ctor public ChangedPackages(int, @NonNull java.util.List<java.lang.String>);
     method public int describeContents();
-    method public java.util.List<java.lang.String> getPackageNames();
+    method @NonNull public java.util.List<java.lang.String> getPackageNames();
     method public int getSequenceNumber();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.ChangedPackages> CREATOR;
@@ -11072,15 +11122,15 @@
     field public boolean directBootAware;
     field public boolean enabled;
     field public boolean exported;
-    field public java.lang.String processName;
-    field public java.lang.String splitName;
+    field public String processName;
+    field public String splitName;
   }
 
   public class ConfigurationInfo implements android.os.Parcelable {
     ctor public ConfigurationInfo();
     ctor public ConfigurationInfo(android.content.pm.ConfigurationInfo);
     method public int describeContents();
-    method public java.lang.String getGlEsVersion();
+    method public String getGlEsVersion();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.ConfigurationInfo> CREATOR;
     field public static final int GL_ES_VERSION_UNDEFINED = 0; // 0x0
@@ -11094,10 +11144,10 @@
   }
 
   public class CrossProfileApps {
-    method public android.graphics.drawable.Drawable getProfileSwitchingIconDrawable(android.os.UserHandle);
-    method public java.lang.CharSequence getProfileSwitchingLabel(android.os.UserHandle);
-    method public java.util.List<android.os.UserHandle> getTargetUserProfiles();
-    method public void startMainActivity(android.content.ComponentName, android.os.UserHandle);
+    method @NonNull public android.graphics.drawable.Drawable getProfileSwitchingIconDrawable(@NonNull android.os.UserHandle);
+    method @NonNull public CharSequence getProfileSwitchingLabel(@NonNull android.os.UserHandle);
+    method @NonNull public java.util.List<android.os.UserHandle> getTargetUserProfiles();
+    method public void startMainActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
   }
 
   public final class FeatureGroupInfo implements android.os.Parcelable {
@@ -11113,13 +11163,13 @@
     ctor public FeatureInfo();
     ctor public FeatureInfo(android.content.pm.FeatureInfo);
     method public int describeContents();
-    method public java.lang.String getGlEsVersion();
+    method public String getGlEsVersion();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.FeatureInfo> CREATOR;
     field public static final int FLAG_REQUIRED = 1; // 0x1
     field public static final int GL_ES_VERSION_UNDEFINED = 0; // 0x0
     field public int flags;
-    field public java.lang.String name;
+    field public String name;
     field public int reqGlEsVersion;
     field public int version;
   }
@@ -11129,29 +11179,29 @@
     ctor public InstrumentationInfo(android.content.pm.InstrumentationInfo);
     method public int describeContents();
     field public static final android.os.Parcelable.Creator<android.content.pm.InstrumentationInfo> CREATOR;
-    field public java.lang.String dataDir;
+    field public String dataDir;
     field public boolean functionalTest;
     field public boolean handleProfiling;
-    field public java.lang.String publicSourceDir;
-    field public java.lang.String sourceDir;
-    field public java.lang.String[] splitNames;
-    field public java.lang.String[] splitPublicSourceDirs;
-    field public java.lang.String[] splitSourceDirs;
-    field public java.lang.String targetPackage;
-    field public java.lang.String targetProcesses;
+    field public String publicSourceDir;
+    field public String sourceDir;
+    field public String[] splitNames;
+    field public String[] splitPublicSourceDirs;
+    field public String[] splitSourceDirs;
+    field public String targetPackage;
+    field public String targetProcesses;
   }
 
   public class LabeledIntent extends android.content.Intent {
-    ctor public LabeledIntent(android.content.Intent, java.lang.String, int, int);
-    ctor public LabeledIntent(android.content.Intent, java.lang.String, java.lang.CharSequence, int);
-    ctor public LabeledIntent(java.lang.String, int, int);
-    ctor public LabeledIntent(java.lang.String, java.lang.CharSequence, int);
+    ctor public LabeledIntent(android.content.Intent, String, int, int);
+    ctor public LabeledIntent(android.content.Intent, String, CharSequence, int);
+    ctor public LabeledIntent(String, int, int);
+    ctor public LabeledIntent(String, CharSequence, int);
     method public int getIconResource();
     method public int getLabelResource();
-    method public java.lang.CharSequence getNonLocalizedLabel();
-    method public java.lang.String getSourcePackage();
+    method public CharSequence getNonLocalizedLabel();
+    method public String getSourcePackage();
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
-    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
+    method public CharSequence loadLabel(android.content.pm.PackageManager);
     field public static final android.os.Parcelable.Creator<android.content.pm.LabeledIntent> CREATOR;
   }
 
@@ -11161,60 +11211,61 @@
     method public android.content.ComponentName getComponentName();
     method public long getFirstInstallTime();
     method public android.graphics.drawable.Drawable getIcon(int);
-    method public java.lang.CharSequence getLabel();
-    method public java.lang.String getName();
+    method public CharSequence getLabel();
+    method public String getName();
     method public android.os.UserHandle getUser();
   }
 
   public class LauncherApps {
-    method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
-    method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(String, android.os.UserHandle);
+    method public android.content.pm.ApplicationInfo getApplicationInfo(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
     method public java.util.List<android.os.UserHandle> getProfiles();
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
-    method public android.content.IntentSender getShortcutConfigActivityIntent(android.content.pm.LauncherActivityInfo);
-    method public java.util.List<android.content.pm.LauncherActivityInfo> getShortcutConfigActivityList(java.lang.String, android.os.UserHandle);
-    method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
-    method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
-    method public android.os.Bundle getSuspendedPackageLauncherExtras(java.lang.String, android.os.UserHandle);
+    method @Nullable public android.content.IntentSender getShortcutConfigActivityIntent(@NonNull android.content.pm.LauncherActivityInfo);
+    method public java.util.List<android.content.pm.LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String, @NonNull android.os.UserHandle);
+    method public android.graphics.drawable.Drawable getShortcutIconDrawable(@NonNull android.content.pm.ShortcutInfo, int);
+    method @Nullable public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(@NonNull android.content.pm.LauncherApps.ShortcutQuery, @NonNull android.os.UserHandle);
+    method @Nullable public android.os.Bundle getSuspendedPackageLauncherExtras(String, android.os.UserHandle);
     method public boolean hasShortcutHostPermission();
     method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
-    method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
-    method public void pinShortcuts(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
+    method public boolean isPackageEnabled(String, android.os.UserHandle);
+    method public void pinShortcuts(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull android.os.UserHandle);
     method public void registerCallback(android.content.pm.LauncherApps.Callback);
     method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
+    method public boolean shouldHideFromSuggestions(@NonNull String, @NonNull android.os.UserHandle);
     method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
     method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
-    method public void startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
-    method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
+    method public void startShortcut(@NonNull String, @NonNull String, @Nullable android.graphics.Rect, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
+    method public void startShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.graphics.Rect, @Nullable android.os.Bundle);
     method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
-    field public static final java.lang.String ACTION_CONFIRM_PIN_APPWIDGET = "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
-    field public static final java.lang.String ACTION_CONFIRM_PIN_SHORTCUT = "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
-    field public static final java.lang.String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
+    field public static final String ACTION_CONFIRM_PIN_APPWIDGET = "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
+    field public static final String ACTION_CONFIRM_PIN_SHORTCUT = "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
+    field public static final String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST";
   }
 
-  public static abstract class LauncherApps.Callback {
+  public abstract static class LauncherApps.Callback {
     ctor public LauncherApps.Callback();
-    method public abstract void onPackageAdded(java.lang.String, android.os.UserHandle);
-    method public abstract void onPackageChanged(java.lang.String, android.os.UserHandle);
-    method public abstract void onPackageRemoved(java.lang.String, android.os.UserHandle);
-    method public abstract void onPackagesAvailable(java.lang.String[], android.os.UserHandle, boolean);
-    method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
-    method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle, android.os.Bundle);
-    method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
-    method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
-    method public void onShortcutsChanged(java.lang.String, java.util.List<android.content.pm.ShortcutInfo>, android.os.UserHandle);
+    method public abstract void onPackageAdded(String, android.os.UserHandle);
+    method public abstract void onPackageChanged(String, android.os.UserHandle);
+    method public abstract void onPackageRemoved(String, android.os.UserHandle);
+    method public abstract void onPackagesAvailable(String[], android.os.UserHandle, boolean);
+    method public void onPackagesSuspended(String[], android.os.UserHandle);
+    method public void onPackagesSuspended(String[], android.os.UserHandle, @Nullable android.os.Bundle);
+    method public abstract void onPackagesUnavailable(String[], android.os.UserHandle, boolean);
+    method public void onPackagesUnsuspended(String[], android.os.UserHandle);
+    method public void onShortcutsChanged(@NonNull String, @NonNull java.util.List<android.content.pm.ShortcutInfo>, @NonNull android.os.UserHandle);
   }
 
   public static final class LauncherApps.PinItemRequest implements android.os.Parcelable {
-    method public boolean accept(android.os.Bundle);
+    method public boolean accept(@Nullable android.os.Bundle);
     method public boolean accept();
     method public int describeContents();
-    method public android.appwidget.AppWidgetProviderInfo getAppWidgetProviderInfo(android.content.Context);
-    method public android.os.Bundle getExtras();
+    method @Nullable public android.appwidget.AppWidgetProviderInfo getAppWidgetProviderInfo(android.content.Context);
+    method @Nullable public android.os.Bundle getExtras();
     method public int getRequestType();
-    method public android.content.pm.ShortcutInfo getShortcutInfo();
+    method @Nullable public android.content.pm.ShortcutInfo getShortcutInfo();
     method public boolean isValid();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.LauncherApps.PinItemRequest> CREATOR;
@@ -11224,11 +11275,11 @@
 
   public static class LauncherApps.ShortcutQuery {
     ctor public LauncherApps.ShortcutQuery();
-    method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
+    method public android.content.pm.LauncherApps.ShortcutQuery setActivity(@Nullable android.content.ComponentName);
     method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long);
-    method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
+    method public android.content.pm.LauncherApps.ShortcutQuery setPackage(@Nullable String);
     method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
-    method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
+    method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(@Nullable java.util.List<java.lang.String>);
     field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
     field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
     field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
@@ -11238,8 +11289,8 @@
 
   public final class ModuleInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getName();
-    method public java.lang.String getPackageName();
+    method @Nullable public String getName();
+    method @Nullable public String getPackageName();
     method public boolean isHidden();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.ModuleInfo> CREATOR;
@@ -11267,50 +11318,50 @@
     field public android.content.pm.InstrumentationInfo[] instrumentation;
     field public boolean isApex;
     field public long lastUpdateTime;
-    field public java.lang.String packageName;
+    field public String packageName;
     field public android.content.pm.PermissionInfo[] permissions;
     field public android.content.pm.ProviderInfo[] providers;
     field public android.content.pm.ActivityInfo[] receivers;
     field public android.content.pm.FeatureInfo[] reqFeatures;
-    field public deprecated java.lang.String[] requestedPermissions;
-    field public deprecated int[] requestedPermissionsFlags;
+    field @Deprecated public String[] requestedPermissions;
+    field @Deprecated public int[] requestedPermissionsFlags;
     field public android.content.pm.ServiceInfo[] services;
-    field public java.lang.String sharedUserId;
+    field public String sharedUserId;
     field public int sharedUserLabel;
-    field public deprecated android.content.pm.Signature[] signatures;
+    field @Deprecated public android.content.pm.Signature[] signatures;
     field public android.content.pm.SigningInfo signingInfo;
-    field public java.lang.String[] splitNames;
+    field public String[] splitNames;
     field public int[] splitRevisionCodes;
     field public android.content.pm.UsesPermissionInfo[] usesPermissions;
-    field public deprecated int versionCode;
-    field public java.lang.String versionName;
+    field @Deprecated public int versionCode;
+    field public String versionName;
   }
 
   public class PackageInstaller {
     method public void abandonSession(int);
-    method public int createSession(android.content.pm.PackageInstaller.SessionParams) throws java.io.IOException;
-    method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getAllSessions();
-    method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getMySessions();
-    method public android.content.pm.PackageInstaller.SessionInfo getSessionInfo(int);
-    method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getStagedSessions();
-    method public android.content.pm.PackageInstaller.Session openSession(int) throws java.io.IOException;
-    method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
-    method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler);
-    method public void uninstall(java.lang.String, android.content.IntentSender);
-    method public void uninstall(android.content.pm.VersionedPackage, android.content.IntentSender);
-    method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
-    method public void updateSessionAppIcon(int, android.graphics.Bitmap);
-    method public void updateSessionAppLabel(int, java.lang.CharSequence);
-    field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
-    field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
-    field public static final java.lang.String ACTION_SESSION_UPDATED = "android.content.pm.action.SESSION_UPDATED";
-    field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
-    field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
-    field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
-    field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
-    field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
-    field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
-    field public static final java.lang.String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH";
+    method public int createSession(@NonNull android.content.pm.PackageInstaller.SessionParams) throws java.io.IOException;
+    method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getAllSessions();
+    method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getMySessions();
+    method @Nullable public android.content.pm.PackageInstaller.SessionInfo getSessionInfo(int);
+    method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getStagedSessions();
+    method @NonNull public android.content.pm.PackageInstaller.Session openSession(int) throws java.io.IOException;
+    method public void registerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback);
+    method public void registerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback, @NonNull android.os.Handler);
+    method @RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES, android.Manifest.permission.REQUEST_DELETE_PACKAGES}) public void uninstall(@NonNull String, @NonNull android.content.IntentSender);
+    method @RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES, android.Manifest.permission.REQUEST_DELETE_PACKAGES}) public void uninstall(@NonNull android.content.pm.VersionedPackage, @NonNull android.content.IntentSender);
+    method public void unregisterSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback);
+    method public void updateSessionAppIcon(int, @Nullable android.graphics.Bitmap);
+    method public void updateSessionAppLabel(int, @Nullable CharSequence);
+    field public static final String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
+    field public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
+    field public static final String ACTION_SESSION_UPDATED = "android.content.pm.action.SESSION_UPDATED";
+    field public static final String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
+    field public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+    field public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION";
+    field public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
+    field public static final String EXTRA_STATUS = "android.content.pm.extra.STATUS";
+    field public static final String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
+    field public static final String EXTRA_STORAGE_PATH = "android.content.pm.extra.STORAGE_PATH";
     field public static final int STATUS_FAILURE = 1; // 0x1
     field public static final int STATUS_FAILURE_ABORTED = 3; // 0x3
     field public static final int STATUS_FAILURE_BLOCKED = 2; // 0x2
@@ -11326,22 +11377,22 @@
     method public void abandon();
     method public void addChildSessionId(int);
     method public void close();
-    method public void commit(android.content.IntentSender);
-    method public void fsync(java.io.OutputStream) throws java.io.IOException;
-    method public int[] getChildSessionIds();
-    method public java.lang.String[] getNames() throws java.io.IOException;
+    method public void commit(@NonNull android.content.IntentSender);
+    method public void fsync(@NonNull java.io.OutputStream) throws java.io.IOException;
+    method @NonNull public int[] getChildSessionIds();
+    method @NonNull public String[] getNames() throws java.io.IOException;
     method public int getParentSessionId();
     method public boolean isMultiPackage();
     method public boolean isStaged();
-    method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
-    method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
+    method @NonNull public java.io.InputStream openRead(@NonNull String) throws java.io.IOException;
+    method @NonNull public java.io.OutputStream openWrite(@NonNull String, long, long) throws java.io.IOException;
     method public void removeChildSessionId(int);
-    method public void removeSplit(java.lang.String) throws java.io.IOException;
+    method public void removeSplit(@NonNull String) throws java.io.IOException;
     method public void setStagingProgress(float);
-    method public void transfer(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public void transfer(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
   }
 
-  public static abstract class PackageInstaller.SessionCallback {
+  public abstract static class PackageInstaller.SessionCallback {
     ctor public PackageInstaller.SessionCallback();
     method public abstract void onActiveChanged(int, boolean);
     method public abstract void onBadgingChanged(int);
@@ -11351,21 +11402,21 @@
   }
 
   public static class PackageInstaller.SessionInfo implements android.os.Parcelable {
-    method public android.content.Intent createDetailsIntent();
+    method @Nullable public android.content.Intent createDetailsIntent();
     method public int describeContents();
-    method public android.graphics.Bitmap getAppIcon();
-    method public java.lang.CharSequence getAppLabel();
-    method public java.lang.String getAppPackageName();
+    method @Nullable public android.graphics.Bitmap getAppIcon();
+    method @Nullable public CharSequence getAppLabel();
+    method @Nullable public String getAppPackageName();
     method public int[] getChildSessionIds();
     method public int getInstallLocation();
     method public int getInstallReason();
-    method public java.lang.String getInstallerPackageName();
+    method @Nullable public String getInstallerPackageName();
     method public int getMode();
     method public int getOriginatingUid();
-    method public android.net.Uri getOriginatingUri();
+    method @Nullable public android.net.Uri getOriginatingUri();
     method public int getParentSessionId();
     method public float getProgress();
-    method public android.net.Uri getReferrerUri();
+    method @Nullable public android.net.Uri getReferrerUri();
     method public int getSessionId();
     method public long getSize();
     method public int getStagedSessionErrorCode();
@@ -11387,15 +11438,15 @@
   public static class PackageInstaller.SessionParams implements android.os.Parcelable {
     ctor public PackageInstaller.SessionParams(int);
     method public int describeContents();
-    method public void setAppIcon(android.graphics.Bitmap);
-    method public void setAppLabel(java.lang.CharSequence);
-    method public void setAppPackageName(java.lang.String);
+    method public void setAppIcon(@Nullable android.graphics.Bitmap);
+    method public void setAppLabel(@Nullable CharSequence);
+    method public void setAppPackageName(@Nullable String);
     method public void setInstallLocation(int);
     method public void setInstallReason(int);
     method public void setMultiPackage();
     method public void setOriginatingUid(int);
-    method public void setOriginatingUri(android.net.Uri);
-    method public void setReferrerUri(android.net.Uri);
+    method public void setOriginatingUri(@Nullable android.net.Uri);
+    method public void setReferrerUri(@Nullable android.net.Uri);
     method public void setSize(long);
     method public void setStaged();
     method public void writeToParcel(android.os.Parcel, int);
@@ -11408,44 +11459,44 @@
     ctor public PackageItemInfo();
     ctor public PackageItemInfo(android.content.pm.PackageItemInfo);
     ctor protected PackageItemInfo(android.os.Parcel);
-    method protected void dumpBack(android.util.Printer, java.lang.String);
-    method protected void dumpFront(android.util.Printer, java.lang.String);
+    method protected void dumpBack(android.util.Printer, String);
+    method protected void dumpFront(android.util.Printer, String);
     method public android.graphics.drawable.Drawable loadBanner(android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
-    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
+    method @NonNull public CharSequence loadLabel(@NonNull android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadLogo(android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadUnbadgedIcon(android.content.pm.PackageManager);
-    method public android.content.res.XmlResourceParser loadXmlMetaData(android.content.pm.PackageManager, java.lang.String);
+    method public android.content.res.XmlResourceParser loadXmlMetaData(android.content.pm.PackageManager, String);
     method public void writeToParcel(android.os.Parcel, int);
     field public int banner;
     field public int icon;
     field public int labelRes;
     field public int logo;
     field public android.os.Bundle metaData;
-    field public java.lang.String name;
-    field public java.lang.CharSequence nonLocalizedLabel;
-    field public java.lang.String packageName;
+    field public String name;
+    field public CharSequence nonLocalizedLabel;
+    field public String packageName;
   }
 
-  public static class PackageItemInfo.DisplayNameComparator implements java.util.Comparator {
+  public static class PackageItemInfo.DisplayNameComparator implements java.util.Comparator<android.content.pm.PackageItemInfo> {
     ctor public PackageItemInfo.DisplayNameComparator(android.content.pm.PackageManager);
     method public final int compare(android.content.pm.PackageItemInfo, android.content.pm.PackageItemInfo);
   }
 
   public abstract class PackageManager {
     ctor public PackageManager();
-    method public abstract deprecated void addPackageToPreferred(java.lang.String);
+    method @Deprecated public abstract void addPackageToPreferred(String);
     method public abstract boolean addPermission(android.content.pm.PermissionInfo);
     method public abstract boolean addPermissionAsync(android.content.pm.PermissionInfo);
-    method public abstract deprecated void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
+    method @Deprecated public abstract void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
     method public abstract boolean canRequestPackageInstalls();
-    method public abstract java.lang.String[] canonicalToCurrentPackageNames(java.lang.String[]);
-    method public abstract int checkPermission(java.lang.String, java.lang.String);
-    method public abstract int checkSignatures(java.lang.String, java.lang.String);
-    method public abstract int checkSignatures(int, int);
+    method public abstract String[] canonicalToCurrentPackageNames(String[]);
+    method @CheckResult public abstract int checkPermission(String, String);
+    method @CheckResult public abstract int checkSignatures(String, String);
+    method @CheckResult public abstract int checkSignatures(int, int);
     method public abstract void clearInstantAppCookie();
-    method public abstract deprecated void clearPackagePreferredActivities(java.lang.String);
-    method public abstract java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
+    method @Deprecated public abstract void clearPackagePreferredActivities(String);
+    method public abstract String[] currentToCanonicalPackageNames(String[]);
     method public abstract void extendVerificationTimeout(int, int, long);
     method public abstract android.graphics.drawable.Drawable getActivityBanner(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.graphics.drawable.Drawable getActivityBanner(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -11456,85 +11507,85 @@
     method public abstract android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
     method public abstract android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
-    method public abstract android.graphics.drawable.Drawable getApplicationBanner(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract int getApplicationEnabledSetting(java.lang.String);
+    method public abstract android.graphics.drawable.Drawable getApplicationBanner(String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract int getApplicationEnabledSetting(@NonNull String);
     method public abstract android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo);
-    method public abstract android.graphics.drawable.Drawable getApplicationIcon(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract java.lang.CharSequence getApplicationLabel(android.content.pm.ApplicationInfo);
+    method public abstract android.graphics.drawable.Drawable getApplicationIcon(String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.content.pm.ApplicationInfo getApplicationInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract CharSequence getApplicationLabel(android.content.pm.ApplicationInfo);
     method public abstract android.graphics.drawable.Drawable getApplicationLogo(android.content.pm.ApplicationInfo);
-    method public abstract android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.pm.ChangedPackages getChangedPackages(int);
-    method public abstract int getComponentEnabledSetting(android.content.ComponentName);
+    method public abstract android.graphics.drawable.Drawable getApplicationLogo(String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Nullable public abstract android.content.pm.ChangedPackages getChangedPackages(@IntRange(from=0) int);
+    method public abstract int getComponentEnabledSetting(@NonNull android.content.ComponentName);
     method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
-    method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
+    method public abstract android.graphics.drawable.Drawable getDrawable(String, @DrawableRes int, android.content.pm.ApplicationInfo);
     method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
-    method public java.util.List<android.content.pm.ModuleInfo> getInstalledModules(int);
+    method @NonNull public java.util.List<android.content.pm.ModuleInfo> getInstalledModules(int);
     method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
-    method public abstract java.lang.String getInstallerPackageName(java.lang.String);
-    method public abstract byte[] getInstantAppCookie();
+    method @Nullable public abstract String getInstallerPackageName(String);
+    method @NonNull public abstract byte[] getInstantAppCookie();
     method public abstract int getInstantAppCookieMaxBytes();
     method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
-    method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
-    method public android.content.pm.ModuleInfo getModuleInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract java.lang.String getNameForUid(int);
-    method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
-    method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Nullable public abstract android.content.Intent getLaunchIntentForPackage(@NonNull String);
+    method @Nullable public abstract android.content.Intent getLeanbackLaunchIntentForPackage(@NonNull String);
+    method public android.content.pm.ModuleInfo getModuleInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Nullable public abstract String getNameForUid(int);
+    method public android.content.pm.PackageInfo getPackageArchiveInfo(String, int);
+    method public abstract int[] getPackageGids(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract int[] getPackageGids(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.content.pm.PackageInfo getPackageInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.pm.PackageInstaller getPackageInstaller();
-    method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract java.lang.String[] getPackagesForUid(int);
-    method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
-    method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.pm.PermissionInfo getPermissionInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract deprecated int getPreferredActivities(java.util.List<android.content.IntentFilter>, java.util.List<android.content.ComponentName>, java.lang.String);
-    method public abstract deprecated java.util.List<android.content.pm.PackageInfo> getPreferredPackages(int);
+    method @NonNull public abstract android.content.pm.PackageInstaller getPackageInstaller();
+    method public abstract int getPackageUid(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Nullable public abstract String[] getPackagesForUid(int);
+    method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(String[], int);
+    method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.content.pm.PermissionInfo getPermissionInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public abstract int getPreferredActivities(@NonNull java.util.List<android.content.IntentFilter>, @NonNull java.util.List<android.content.ComponentName>, String);
+    method @Deprecated public abstract java.util.List<android.content.pm.PackageInfo> getPreferredPackages(int);
     method public abstract android.content.pm.ProviderInfo getProviderInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.ActivityInfo getReceiverInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.res.Resources getResourcesForActivity(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.content.res.Resources getResourcesForApplication(String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
-    method public android.os.Bundle getSuspendedPackageAppExtras();
+    method @NonNull public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
+    method @Nullable public android.os.Bundle getSuspendedPackageAppExtras();
     method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
-    method public abstract java.lang.String[] getSystemSharedLibraryNames();
-    method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
+    method public abstract String[] getSystemSharedLibraryNames();
+    method public abstract CharSequence getText(String, @StringRes int, android.content.pm.ApplicationInfo);
     method public abstract android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
     method public abstract android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle);
-    method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
-    method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
-    method public boolean hasSigningCertificate(java.lang.String, byte[], int);
+    method public abstract CharSequence getUserBadgedLabel(CharSequence, android.os.UserHandle);
+    method public abstract android.content.res.XmlResourceParser getXml(String, @XmlRes int, android.content.pm.ApplicationInfo);
+    method public boolean hasSigningCertificate(String, byte[], int);
     method public boolean hasSigningCertificate(int, byte[], int);
-    method public abstract boolean hasSystemFeature(java.lang.String);
-    method public abstract boolean hasSystemFeature(java.lang.String, int);
+    method public abstract boolean hasSystemFeature(String);
+    method public abstract boolean hasSystemFeature(String, int);
     method public abstract boolean isInstantApp();
-    method public abstract boolean isInstantApp(java.lang.String);
-    method public boolean isPackageSuspended(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract boolean isInstantApp(String);
+    method public boolean isPackageSuspended(String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isPackageSuspended();
-    method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
+    method @CheckResult public abstract boolean isPermissionRevokedByPolicy(@NonNull String, @NonNull String);
     method public abstract boolean isSafeMode();
     method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
-    method public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(java.lang.String, int, int);
-    method public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
+    method public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(String, int, int);
+    method public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(String, int);
     method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
-    method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivityOptions(android.content.ComponentName, android.content.Intent[], android.content.Intent, int);
+    method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivityOptions(@Nullable android.content.ComponentName, @Nullable android.content.Intent[], android.content.Intent, int);
     method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int);
     method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int);
-    method public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract deprecated void removePackageFromPreferred(java.lang.String);
-    method public abstract void removePermission(java.lang.String);
+    method public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public abstract void removePackageFromPreferred(String);
+    method public abstract void removePermission(String);
     method public abstract android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
-    method public abstract android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
+    method public abstract android.content.pm.ProviderInfo resolveContentProvider(String, int);
     method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
-    method public abstract void setApplicationCategoryHint(java.lang.String, int);
-    method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
-    method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
-    method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
-    method public abstract void updateInstantAppCookie(byte[]);
+    method public abstract void setApplicationCategoryHint(@NonNull String, int);
+    method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setApplicationEnabledSetting(@NonNull String, int, int);
+    method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setComponentEnabledSetting(@NonNull android.content.ComponentName, int, int);
+    method public abstract void setInstallerPackageName(String, String);
+    method public abstract void updateInstantAppCookie(@Nullable byte[]);
     method public abstract void verifyPendingInstall(int, int);
     field public static final int CERT_INPUT_RAW_X509 = 0; // 0x0
     field public static final int CERT_INPUT_SHA256 = 1; // 0x1
@@ -11544,116 +11595,121 @@
     field public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3; // 0x3
     field public static final int COMPONENT_ENABLED_STATE_ENABLED = 1; // 0x1
     field public static final int DONT_KILL_APP = 1; // 0x1
-    field public static final java.lang.String EXTRA_VERIFICATION_ID = "android.content.pm.extra.VERIFICATION_ID";
-    field public static final java.lang.String EXTRA_VERIFICATION_RESULT = "android.content.pm.extra.VERIFICATION_RESULT";
-    field public static final java.lang.String FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS = "android.software.activities_on_secondary_displays";
-    field public static final java.lang.String FEATURE_APP_WIDGETS = "android.software.app_widgets";
-    field public static final java.lang.String FEATURE_AUDIO_LOW_LATENCY = "android.hardware.audio.low_latency";
-    field public static final java.lang.String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
-    field public static final java.lang.String FEATURE_AUDIO_PRO = "android.hardware.audio.pro";
-    field public static final java.lang.String FEATURE_AUTOFILL = "android.software.autofill";
-    field public static final java.lang.String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
-    field public static final java.lang.String FEATURE_BACKUP = "android.software.backup";
-    field public static final java.lang.String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
-    field public static final java.lang.String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le";
-    field public static final java.lang.String FEATURE_CAMERA = "android.hardware.camera";
-    field public static final java.lang.String FEATURE_CAMERA_ANY = "android.hardware.camera.any";
-    field public static final java.lang.String FEATURE_CAMERA_AR = "android.hardware.camera.ar";
-    field public static final java.lang.String FEATURE_CAMERA_AUTOFOCUS = "android.hardware.camera.autofocus";
-    field public static final java.lang.String FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING = "android.hardware.camera.capability.manual_post_processing";
-    field public static final java.lang.String FEATURE_CAMERA_CAPABILITY_MANUAL_SENSOR = "android.hardware.camera.capability.manual_sensor";
-    field public static final java.lang.String FEATURE_CAMERA_CAPABILITY_RAW = "android.hardware.camera.capability.raw";
-    field public static final java.lang.String FEATURE_CAMERA_EXTERNAL = "android.hardware.camera.external";
-    field public static final java.lang.String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
-    field public static final java.lang.String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
-    field public static final java.lang.String FEATURE_CAMERA_LEVEL_FULL = "android.hardware.camera.level.full";
-    field public static final java.lang.String FEATURE_CANT_SAVE_STATE = "android.software.cant_save_state";
-    field public static final java.lang.String FEATURE_COMPANION_DEVICE_SETUP = "android.software.companion_device_setup";
-    field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
-    field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
-    field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
-    field public static final java.lang.String FEATURE_EMBEDDED = "android.hardware.type.embedded";
-    field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
-    field public static final java.lang.String FEATURE_FACE = "android.hardware.biometrics.face";
-    field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
-    field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
-    field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
-    field public static final java.lang.String FEATURE_FINGERPRINT = "android.hardware.biometrics.fingerprint";
-    field public static final java.lang.String FEATURE_FINGERPRINT_PRE_29 = "android.hardware.fingerprint";
-    field public static final java.lang.String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management";
-    field public static final java.lang.String FEATURE_GAMEPAD = "android.hardware.gamepad";
-    field public static final java.lang.String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
-    field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen";
-    field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods";
-    field public static final java.lang.String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
-    field public static final java.lang.String FEATURE_IRIS = "android.hardware.biometrics.iris";
-    field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback";
-    field public static final java.lang.String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
-    field public static final java.lang.String FEATURE_LIVE_TV = "android.software.live_tv";
-    field public static final java.lang.String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper";
-    field public static final java.lang.String FEATURE_LOCATION = "android.hardware.location";
-    field public static final java.lang.String FEATURE_LOCATION_GPS = "android.hardware.location.gps";
-    field public static final java.lang.String FEATURE_LOCATION_NETWORK = "android.hardware.location.network";
-    field public static final java.lang.String FEATURE_MANAGED_USERS = "android.software.managed_users";
-    field public static final java.lang.String FEATURE_MICROPHONE = "android.hardware.microphone";
-    field public static final java.lang.String FEATURE_MIDI = "android.software.midi";
-    field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
-    field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
-    field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION_NFCF = "android.hardware.nfc.hcef";
-    field public static final java.lang.String FEATURE_OPENGLES_EXTENSION_PACK = "android.hardware.opengles.aep";
-    field public static final java.lang.String FEATURE_PC = "android.hardware.type.pc";
-    field public static final java.lang.String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
-    field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
-    field public static final java.lang.String FEATURE_RAM_LOW = "android.hardware.ram.low";
-    field public static final java.lang.String FEATURE_RAM_NORMAL = "android.hardware.ram.normal";
-    field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
-    field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
-    field public static final java.lang.String FEATURE_SECURELY_REMOVES_USERS = "android.software.securely_removes_users";
-    field public static final java.lang.String FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer";
-    field public static final java.lang.String FEATURE_SENSOR_AMBIENT_TEMPERATURE = "android.hardware.sensor.ambient_temperature";
-    field public static final java.lang.String FEATURE_SENSOR_BAROMETER = "android.hardware.sensor.barometer";
-    field public static final java.lang.String FEATURE_SENSOR_COMPASS = "android.hardware.sensor.compass";
-    field public static final java.lang.String FEATURE_SENSOR_GYROSCOPE = "android.hardware.sensor.gyroscope";
-    field public static final java.lang.String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
-    field public static final java.lang.String FEATURE_SENSOR_HEART_RATE_ECG = "android.hardware.sensor.heartrate.ecg";
-    field public static final java.lang.String FEATURE_SENSOR_LIGHT = "android.hardware.sensor.light";
-    field public static final java.lang.String FEATURE_SENSOR_PROXIMITY = "android.hardware.sensor.proximity";
-    field public static final java.lang.String FEATURE_SENSOR_RELATIVE_HUMIDITY = "android.hardware.sensor.relative_humidity";
-    field public static final java.lang.String FEATURE_SENSOR_STEP_COUNTER = "android.hardware.sensor.stepcounter";
-    field public static final java.lang.String FEATURE_SENSOR_STEP_DETECTOR = "android.hardware.sensor.stepdetector";
-    field public static final java.lang.String FEATURE_SIP = "android.software.sip";
-    field public static final java.lang.String FEATURE_SIP_VOIP = "android.software.sip.voip";
-    field public static final java.lang.String FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
-    field public static final java.lang.String FEATURE_TELEPHONY = "android.hardware.telephony";
-    field public static final java.lang.String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
-    field public static final java.lang.String FEATURE_TELEPHONY_EUICC = "android.hardware.telephony.euicc";
-    field public static final java.lang.String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
-    field public static final java.lang.String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms";
-    field public static final deprecated java.lang.String FEATURE_TELEVISION = "android.hardware.type.television";
-    field public static final java.lang.String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
-    field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
-    field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct";
-    field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND = "android.hardware.touchscreen.multitouch.jazzhand";
-    field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
-    field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
-    field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
-    field public static final java.lang.String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
-    field public static final deprecated java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
-    field public static final java.lang.String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
-    field public static final java.lang.String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
-    field public static final java.lang.String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
-    field public static final java.lang.String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
-    field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
-    field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
-    field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
-    field public static final java.lang.String FEATURE_WIFI_AWARE = "android.hardware.wifi.aware";
-    field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
-    field public static final java.lang.String FEATURE_WIFI_PASSPOINT = "android.hardware.wifi.passpoint";
-    field public static final java.lang.String FEATURE_WIFI_RTT = "android.hardware.wifi.rtt";
+    field public static final String EXTRA_VERIFICATION_ID = "android.content.pm.extra.VERIFICATION_ID";
+    field public static final String EXTRA_VERIFICATION_RESULT = "android.content.pm.extra.VERIFICATION_RESULT";
+    field public static final String FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS = "android.software.activities_on_secondary_displays";
+    field public static final String FEATURE_APP_WIDGETS = "android.software.app_widgets";
+    field public static final String FEATURE_AUDIO_LOW_LATENCY = "android.hardware.audio.low_latency";
+    field public static final String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
+    field public static final String FEATURE_AUDIO_PRO = "android.hardware.audio.pro";
+    field public static final String FEATURE_AUTOFILL = "android.software.autofill";
+    field public static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
+    field public static final String FEATURE_BACKUP = "android.software.backup";
+    field public static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
+    field public static final String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le";
+    field public static final String FEATURE_CAMERA = "android.hardware.camera";
+    field public static final String FEATURE_CAMERA_ANY = "android.hardware.camera.any";
+    field public static final String FEATURE_CAMERA_AR = "android.hardware.camera.ar";
+    field public static final String FEATURE_CAMERA_AUTOFOCUS = "android.hardware.camera.autofocus";
+    field public static final String FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING = "android.hardware.camera.capability.manual_post_processing";
+    field public static final String FEATURE_CAMERA_CAPABILITY_MANUAL_SENSOR = "android.hardware.camera.capability.manual_sensor";
+    field public static final String FEATURE_CAMERA_CAPABILITY_RAW = "android.hardware.camera.capability.raw";
+    field public static final String FEATURE_CAMERA_EXTERNAL = "android.hardware.camera.external";
+    field public static final String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
+    field public static final String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
+    field public static final String FEATURE_CAMERA_LEVEL_FULL = "android.hardware.camera.level.full";
+    field public static final String FEATURE_CANT_SAVE_STATE = "android.software.cant_save_state";
+    field public static final String FEATURE_COMPANION_DEVICE_SETUP = "android.software.companion_device_setup";
+    field public static final String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
+    field public static final String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
+    field public static final String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+    field public static final String FEATURE_EMBEDDED = "android.hardware.type.embedded";
+    field public static final String FEATURE_ETHERNET = "android.hardware.ethernet";
+    field public static final String FEATURE_FACE = "android.hardware.biometrics.face";
+    field public static final String FEATURE_FAKETOUCH = "android.hardware.faketouch";
+    field public static final String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
+    field public static final String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
+    field public static final String FEATURE_FINGERPRINT = "android.hardware.biometrics.fingerprint";
+    field public static final String FEATURE_FINGERPRINT_PRE_29 = "android.hardware.fingerprint";
+    field public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management";
+    field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad";
+    field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
+    field public static final String FEATURE_HOME_SCREEN = "android.software.home_screen";
+    field public static final String FEATURE_INPUT_METHODS = "android.software.input_methods";
+    field public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
+    field public static final String FEATURE_IRIS = "android.hardware.biometrics.iris";
+    field public static final String FEATURE_LEANBACK = "android.software.leanback";
+    field public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
+    field public static final String FEATURE_LIVE_TV = "android.software.live_tv";
+    field public static final String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper";
+    field public static final String FEATURE_LOCATION = "android.hardware.location";
+    field public static final String FEATURE_LOCATION_GPS = "android.hardware.location.gps";
+    field public static final String FEATURE_LOCATION_NETWORK = "android.hardware.location.network";
+    field public static final String FEATURE_MANAGED_USERS = "android.software.managed_users";
+    field public static final String FEATURE_MICROPHONE = "android.hardware.microphone";
+    field public static final String FEATURE_MIDI = "android.software.midi";
+    field public static final String FEATURE_NFC = "android.hardware.nfc";
+    field public static final String FEATURE_NFC_BEAM = "android.sofware.nfc.beam";
+    field public static final String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
+    field public static final String FEATURE_NFC_HOST_CARD_EMULATION_NFCF = "android.hardware.nfc.hcef";
+    field public static final String FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE = "android.hardware.nfc.ese";
+    field public static final String FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC = "android.hardware.nfc.uicc";
+    field public static final String FEATURE_OPENGLES_EXTENSION_PACK = "android.hardware.opengles.aep";
+    field public static final String FEATURE_PC = "android.hardware.type.pc";
+    field public static final String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
+    field public static final String FEATURE_PRINTING = "android.software.print";
+    field public static final String FEATURE_RAM_LOW = "android.hardware.ram.low";
+    field public static final String FEATURE_RAM_NORMAL = "android.hardware.ram.normal";
+    field public static final String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
+    field public static final String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
+    field public static final String FEATURE_SECURELY_REMOVES_USERS = "android.software.securely_removes_users";
+    field public static final String FEATURE_SECURE_LOCK_SCREEN = "android.software.secure_lock_screen";
+    field public static final String FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer";
+    field public static final String FEATURE_SENSOR_AMBIENT_TEMPERATURE = "android.hardware.sensor.ambient_temperature";
+    field public static final String FEATURE_SENSOR_BAROMETER = "android.hardware.sensor.barometer";
+    field public static final String FEATURE_SENSOR_COMPASS = "android.hardware.sensor.compass";
+    field public static final String FEATURE_SENSOR_GYROSCOPE = "android.hardware.sensor.gyroscope";
+    field public static final String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
+    field public static final String FEATURE_SENSOR_HEART_RATE_ECG = "android.hardware.sensor.heartrate.ecg";
+    field public static final String FEATURE_SENSOR_LIGHT = "android.hardware.sensor.light";
+    field public static final String FEATURE_SENSOR_PROXIMITY = "android.hardware.sensor.proximity";
+    field public static final String FEATURE_SENSOR_RELATIVE_HUMIDITY = "android.hardware.sensor.relative_humidity";
+    field public static final String FEATURE_SENSOR_STEP_COUNTER = "android.hardware.sensor.stepcounter";
+    field public static final String FEATURE_SENSOR_STEP_DETECTOR = "android.hardware.sensor.stepdetector";
+    field public static final String FEATURE_SIP = "android.software.sip";
+    field public static final String FEATURE_SIP_VOIP = "android.software.sip.voip";
+    field public static final String FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
+    field public static final String FEATURE_TELEPHONY = "android.hardware.telephony";
+    field public static final String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
+    field public static final String FEATURE_TELEPHONY_EUICC = "android.hardware.telephony.euicc";
+    field public static final String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
+    field public static final String FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims";
+    field public static final String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms";
+    field @Deprecated public static final String FEATURE_TELEVISION = "android.hardware.type.television";
+    field public static final String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
+    field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
+    field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct";
+    field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND = "android.hardware.touchscreen.multitouch.jazzhand";
+    field public static final String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
+    field public static final String FEATURE_USB_HOST = "android.hardware.usb.host";
+    field public static final String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
+    field public static final String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
+    field @Deprecated public static final String FEATURE_VR_MODE = "android.software.vr.mode";
+    field public static final String FEATURE_VR_MODE_HIGH_PERFORMANCE = "android.hardware.vr.high_performance";
+    field public static final String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
+    field public static final String FEATURE_VULKAN_HARDWARE_LEVEL = "android.hardware.vulkan.level";
+    field public static final String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
+    field public static final String FEATURE_WATCH = "android.hardware.type.watch";
+    field public static final String FEATURE_WEBVIEW = "android.software.webview";
+    field public static final String FEATURE_WIFI = "android.hardware.wifi";
+    field public static final String FEATURE_WIFI_AWARE = "android.hardware.wifi.aware";
+    field public static final String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
+    field public static final String FEATURE_WIFI_PASSPOINT = "android.hardware.wifi.passpoint";
+    field public static final String FEATURE_WIFI_RTT = "android.hardware.wifi.rtt";
     field public static final int GET_ACTIVITIES = 1; // 0x1
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
-    field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
-    field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field @Deprecated public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
+    field @Deprecated public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
     field public static final int GET_GIDS = 256; // 0x100
     field public static final int GET_INSTRUMENTATION = 16; // 0x10
     field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -11664,9 +11720,9 @@
     field public static final int GET_RESOLVED_FILTER = 64; // 0x40
     field public static final int GET_SERVICES = 4; // 0x4
     field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
-    field public static final deprecated int GET_SIGNATURES = 64; // 0x40
+    field @Deprecated public static final int GET_SIGNATURES = 64; // 0x40
     field public static final int GET_SIGNING_CERTIFICATES = 134217728; // 0x8000000
-    field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+    field @Deprecated public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
     field public static final int INSTALL_REASON_DEVICE_RESTORE = 2; // 0x2
     field public static final int INSTALL_REASON_DEVICE_SETUP = 3; // 0x3
@@ -11699,32 +11755,32 @@
 
   public static class PackageManager.NameNotFoundException extends android.util.AndroidException {
     ctor public PackageManager.NameNotFoundException();
-    ctor public PackageManager.NameNotFoundException(java.lang.String);
+    ctor public PackageManager.NameNotFoundException(String);
   }
 
-  public deprecated class PackageStats implements android.os.Parcelable {
-    ctor public PackageStats(java.lang.String);
-    ctor public PackageStats(android.os.Parcel);
-    ctor public PackageStats(android.content.pm.PackageStats);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.content.pm.PackageStats> CREATOR;
-    field public long cacheSize;
-    field public long codeSize;
-    field public long dataSize;
-    field public long externalCacheSize;
-    field public long externalCodeSize;
-    field public long externalDataSize;
-    field public long externalMediaSize;
-    field public long externalObbSize;
-    field public java.lang.String packageName;
+  @Deprecated public class PackageStats implements android.os.Parcelable {
+    ctor @Deprecated public PackageStats(String);
+    ctor @Deprecated public PackageStats(android.os.Parcel);
+    ctor @Deprecated public PackageStats(android.content.pm.PackageStats);
+    method @Deprecated public int describeContents();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.content.pm.PackageStats> CREATOR;
+    field @Deprecated public long cacheSize;
+    field @Deprecated public long codeSize;
+    field @Deprecated public long dataSize;
+    field @Deprecated public long externalCacheSize;
+    field @Deprecated public long externalCodeSize;
+    field @Deprecated public long externalDataSize;
+    field @Deprecated public long externalMediaSize;
+    field @Deprecated public long externalObbSize;
+    field @Deprecated public String packageName;
   }
 
   public class PathPermission extends android.os.PatternMatcher {
-    ctor public PathPermission(java.lang.String, int, java.lang.String, java.lang.String);
+    ctor public PathPermission(String, int, String, String);
     ctor public PathPermission(android.os.Parcel);
-    method public java.lang.String getReadPermission();
-    method public java.lang.String getWritePermission();
+    method public String getReadPermission();
+    method public String getWritePermission();
     field public static final android.os.Parcelable.Creator<android.content.pm.PathPermission> CREATOR;
   }
 
@@ -11732,12 +11788,12 @@
     ctor public PermissionGroupInfo();
     ctor public PermissionGroupInfo(android.content.pm.PermissionGroupInfo);
     method public int describeContents();
-    method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
+    method public CharSequence loadDescription(android.content.pm.PackageManager);
     field public static final android.os.Parcelable.Creator<android.content.pm.PermissionGroupInfo> CREATOR;
     field public static final int FLAG_PERSONAL_INFO = 1; // 0x1
     field public int descriptionRes;
     field public int flags;
-    field public java.lang.CharSequence nonLocalizedDescription;
+    field public CharSequence nonLocalizedDescription;
     field public int priority;
   }
 
@@ -11747,7 +11803,7 @@
     method public int describeContents();
     method public int getProtection();
     method public int getProtectionFlags();
-    method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
+    method public CharSequence loadDescription(android.content.pm.PackageManager);
     field public static final android.os.Parcelable.Creator<android.content.pm.PermissionInfo> CREATOR;
     field public static final int FLAG_COSTS_MONEY = 1; // 0x1
     field public static final int FLAG_INSTALLED = 1073741824; // 0x40000000
@@ -11761,18 +11817,18 @@
     field public static final int PROTECTION_FLAG_PRIVILEGED = 16; // 0x10
     field public static final int PROTECTION_FLAG_RUNTIME_ONLY = 8192; // 0x2000
     field public static final int PROTECTION_FLAG_SETUP = 2048; // 0x800
-    field public static final deprecated int PROTECTION_FLAG_SYSTEM = 16; // 0x10
+    field @Deprecated public static final int PROTECTION_FLAG_SYSTEM = 16; // 0x10
     field public static final int PROTECTION_FLAG_VERIFIER = 512; // 0x200
-    field public static final deprecated int PROTECTION_MASK_BASE = 15; // 0xf
-    field public static final deprecated int PROTECTION_MASK_FLAGS = 65520; // 0xfff0
+    field @Deprecated public static final int PROTECTION_MASK_BASE = 15; // 0xf
+    field @Deprecated public static final int PROTECTION_MASK_FLAGS = 65520; // 0xfff0
     field public static final int PROTECTION_NORMAL = 0; // 0x0
     field public static final int PROTECTION_SIGNATURE = 2; // 0x2
-    field public static final deprecated int PROTECTION_SIGNATURE_OR_SYSTEM = 3; // 0x3
+    field @Deprecated public static final int PROTECTION_SIGNATURE_OR_SYSTEM = 3; // 0x3
     field public int descriptionRes;
     field public int flags;
-    field public java.lang.String group;
-    field public java.lang.CharSequence nonLocalizedDescription;
-    field public deprecated int protectionLevel;
+    field public String group;
+    field public CharSequence nonLocalizedDescription;
+    field @Deprecated public int protectionLevel;
     field public boolean usageInfoRequired;
   }
 
@@ -11780,29 +11836,29 @@
     ctor public ProviderInfo();
     ctor public ProviderInfo(android.content.pm.ProviderInfo);
     method public int describeContents();
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(android.util.Printer, String);
     field public static final android.os.Parcelable.Creator<android.content.pm.ProviderInfo> CREATOR;
     field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
-    field public java.lang.String authority;
+    field public String authority;
     field public int flags;
     field public boolean grantUriPermissions;
     field public int initOrder;
-    field public deprecated boolean isSyncable;
+    field @Deprecated public boolean isSyncable;
     field public boolean multiprocess;
     field public android.content.pm.PathPermission[] pathPermissions;
-    field public java.lang.String readPermission;
+    field public String readPermission;
     field public android.os.PatternMatcher[] uriPermissionPatterns;
-    field public java.lang.String writePermission;
+    field public String writePermission;
   }
 
   public class ResolveInfo implements android.os.Parcelable {
     ctor public ResolveInfo();
     ctor public ResolveInfo(android.content.pm.ResolveInfo);
     method public int describeContents();
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(android.util.Printer, String);
     method public final int getIconResource();
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
-    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
+    method public CharSequence loadLabel(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.ResolveInfo> CREATOR;
     field public android.content.pm.ActivityInfo activityInfo;
@@ -11812,16 +11868,16 @@
     field public boolean isInstantAppAvailable;
     field public int labelRes;
     field public int match;
-    field public java.lang.CharSequence nonLocalizedLabel;
+    field public CharSequence nonLocalizedLabel;
     field public int preferredOrder;
     field public int priority;
     field public android.content.pm.ProviderInfo providerInfo;
-    field public java.lang.String resolvePackageName;
+    field public String resolvePackageName;
     field public android.content.pm.ServiceInfo serviceInfo;
     field public int specificIndex;
   }
 
-  public static class ResolveInfo.DisplayNameComparator implements java.util.Comparator {
+  public static class ResolveInfo.DisplayNameComparator implements java.util.Comparator<android.content.pm.ResolveInfo> {
     ctor public ResolveInfo.DisplayNameComparator(android.content.pm.PackageManager);
     method public final int compare(android.content.pm.ResolveInfo, android.content.pm.ResolveInfo);
   }
@@ -11830,7 +11886,7 @@
     ctor public ServiceInfo();
     ctor public ServiceInfo(android.content.pm.ServiceInfo);
     method public int describeContents();
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(android.util.Printer, String);
     method public int getForegroundServiceType();
     field public static final android.os.Parcelable.Creator<android.content.pm.ServiceInfo> CREATOR;
     field public static final int FLAG_EXTERNAL_SERVICE = 4; // 0x4
@@ -11846,17 +11902,17 @@
     field public static final int FOREGROUND_SERVICE_TYPE_SYNC = 1; // 0x1
     field public static final int FOREGROUND_SERVICE_TYPE_UNSPECIFIED = 0; // 0x0
     field public int flags;
-    field public java.lang.String permission;
+    field public String permission;
   }
 
   public final class SharedLibraryInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public android.content.pm.VersionedPackage getDeclaringPackage();
-    method public java.util.List<android.content.pm.VersionedPackage> getDependentPackages();
-    method public long getLongVersion();
-    method public java.lang.String getName();
+    method @NonNull public android.content.pm.VersionedPackage getDeclaringPackage();
+    method @NonNull public java.util.List<android.content.pm.VersionedPackage> getDependentPackages();
+    method @IntRange(from=0xffffffff) public long getLongVersion();
+    method public String getName();
     method public int getType();
-    method public deprecated int getVersion();
+    method @Deprecated @IntRange(from=0xffffffff) public int getVersion();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.SharedLibraryInfo> CREATOR;
     field public static final int TYPE_BUILTIN = 0; // 0x0
@@ -11867,19 +11923,19 @@
 
   public final class ShortcutInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public android.content.ComponentName getActivity();
-    method public java.util.Set<java.lang.String> getCategories();
-    method public java.lang.CharSequence getDisabledMessage();
+    method @Nullable public android.content.ComponentName getActivity();
+    method @Nullable public java.util.Set<java.lang.String> getCategories();
+    method @Nullable public CharSequence getDisabledMessage();
     method public int getDisabledReason();
-    method public android.os.PersistableBundle getExtras();
-    method public java.lang.String getId();
-    method public android.content.Intent getIntent();
-    method public android.content.Intent[] getIntents();
+    method @Nullable public android.os.PersistableBundle getExtras();
+    method @NonNull public String getId();
+    method @Nullable public android.content.Intent getIntent();
+    method @Nullable public android.content.Intent[] getIntents();
     method public long getLastChangedTimestamp();
-    method public java.lang.CharSequence getLongLabel();
-    method public java.lang.String getPackage();
+    method @Nullable public CharSequence getLongLabel();
+    method @NonNull public String getPackage();
     method public int getRank();
-    method public java.lang.CharSequence getShortLabel();
+    method @Nullable public CharSequence getShortLabel();
     method public android.os.UserHandle getUserHandle();
     method public boolean hasKeyFieldsOnly();
     method public boolean isDeclaredInManifest();
@@ -11897,54 +11953,57 @@
     field public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102; // 0x66
     field public static final int DISABLED_REASON_UNKNOWN = 3; // 0x3
     field public static final int DISABLED_REASON_VERSION_LOWER = 100; // 0x64
-    field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
+    field public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
   }
 
   public static class ShortcutInfo.Builder {
-    ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String);
-    method public android.content.pm.ShortcutInfo build();
-    method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
-    method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
-    method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
-    method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
-    method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
-    method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
-    method public android.content.pm.ShortcutInfo.Builder setIntents(android.content.Intent[]);
-    method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
-    method public android.content.pm.ShortcutInfo.Builder setRank(int);
-    method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
+    ctor public ShortcutInfo.Builder(android.content.Context, String);
+    method @NonNull public android.content.pm.ShortcutInfo build();
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setActivity(@NonNull android.content.ComponentName);
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setDisabledMessage(@NonNull CharSequence);
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setExtras(@NonNull android.os.PersistableBundle);
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setIntent(@NonNull android.content.Intent);
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setIntents(@NonNull android.content.Intent[]);
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLabel(@NonNull CharSequence);
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLived();
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setPerson(@NonNull android.app.Person);
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setPersons(@NonNull android.app.Person[]);
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setRank(int);
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setShortLabel(@NonNull CharSequence);
   }
 
   public class ShortcutManager {
-    method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
-    method public android.content.Intent createShortcutResultIntent(android.content.pm.ShortcutInfo);
-    method public void disableShortcuts(java.util.List<java.lang.String>);
-    method public void disableShortcuts(java.util.List<java.lang.String>, java.lang.CharSequence);
-    method public void enableShortcuts(java.util.List<java.lang.String>);
-    method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
+    method public boolean addDynamicShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
+    method public android.content.Intent createShortcutResultIntent(@NonNull android.content.pm.ShortcutInfo);
+    method public void disableShortcuts(@NonNull java.util.List<java.lang.String>);
+    method public void disableShortcuts(@NonNull java.util.List<java.lang.String>, CharSequence);
+    method public void enableShortcuts(@NonNull java.util.List<java.lang.String>);
+    method @NonNull public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
     method public int getIconMaxHeight();
     method public int getIconMaxWidth();
-    method public java.util.List<android.content.pm.ShortcutInfo> getManifestShortcuts();
+    method @NonNull public java.util.List<android.content.pm.ShortcutInfo> getManifestShortcuts();
     method public int getMaxShortcutCountPerActivity();
-    method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
+    method @NonNull public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
     method public boolean isRateLimitingActive();
     method public boolean isRequestPinShortcutSupported();
     method public void removeAllDynamicShortcuts();
-    method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
-    method public void reportShortcutUsed(java.lang.String);
-    method public boolean requestPinShortcut(android.content.pm.ShortcutInfo, android.content.IntentSender);
-    method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
-    method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public void removeDynamicShortcuts(@NonNull java.util.List<java.lang.String>);
+    method public void reportShortcutUsed(String);
+    method public boolean requestPinShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.content.IntentSender);
+    method public boolean setDynamicShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
+    method public boolean updateShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
   }
 
   public class Signature implements android.os.Parcelable {
     ctor public Signature(byte[]);
-    ctor public Signature(java.lang.String);
+    ctor public Signature(String);
     method public int describeContents();
     method public byte[] toByteArray();
     method public char[] toChars();
     method public char[] toChars(char[], int[]);
-    method public java.lang.String toCharsString();
+    method public String toCharsString();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.Signature> CREATOR;
   }
@@ -11969,7 +12028,7 @@
     method public int getDataSharedWithThirdParty();
     method public int getDataUsedForMonetization();
     method public int getFlags();
-    method public java.lang.String getPermission();
+    method public String getPermission();
     field public static final android.os.Parcelable.Creator<android.content.pm.UsesPermissionInfo> CREATOR;
     field public static final int FLAG_REQUESTED_PERMISSION_GRANTED = 2; // 0x2
     field public static final int RETENTION_NOT_RETAINED = 1; // 0x1
@@ -11984,12 +12043,12 @@
   }
 
   public final class VersionedPackage implements android.os.Parcelable {
-    ctor public VersionedPackage(java.lang.String, int);
-    ctor public VersionedPackage(java.lang.String, long);
+    ctor public VersionedPackage(@NonNull String, int);
+    ctor public VersionedPackage(@NonNull String, long);
     method public int describeContents();
     method public long getLongVersionCode();
-    method public java.lang.String getPackageName();
-    method public deprecated int getVersionCode();
+    method @NonNull public String getPackageName();
+    method @Deprecated public int getVersionCode();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.VersionedPackage> CREATOR;
   }
@@ -12018,7 +12077,6 @@
 
   public static class AssetFileDescriptor.AutoCloseInputStream extends android.os.ParcelFileDescriptor.AutoCloseInputStream {
     ctor public AssetFileDescriptor.AutoCloseInputStream(android.content.res.AssetFileDescriptor) throws java.io.IOException;
-    method public void mark(int);
   }
 
   public static class AssetFileDescriptor.AutoCloseOutputStream extends android.os.ParcelFileDescriptor.AutoCloseOutputStream {
@@ -12027,15 +12085,15 @@
 
   public final class AssetManager implements java.lang.AutoCloseable {
     method public void close();
-    method public java.lang.String[] getLocales();
-    method public java.lang.String[] list(java.lang.String) throws java.io.IOException;
-    method public java.io.InputStream open(java.lang.String) throws java.io.IOException;
-    method public java.io.InputStream open(java.lang.String, int) throws java.io.IOException;
-    method public android.content.res.AssetFileDescriptor openFd(java.lang.String) throws java.io.IOException;
-    method public android.content.res.AssetFileDescriptor openNonAssetFd(java.lang.String) throws java.io.IOException;
-    method public android.content.res.AssetFileDescriptor openNonAssetFd(int, java.lang.String) throws java.io.IOException;
-    method public android.content.res.XmlResourceParser openXmlResourceParser(java.lang.String) throws java.io.IOException;
-    method public android.content.res.XmlResourceParser openXmlResourceParser(int, java.lang.String) throws java.io.IOException;
+    method public String[] getLocales();
+    method @Nullable public String[] list(@NonNull String) throws java.io.IOException;
+    method @NonNull public java.io.InputStream open(@NonNull String) throws java.io.IOException;
+    method @NonNull public java.io.InputStream open(@NonNull String, int) throws java.io.IOException;
+    method @NonNull public android.content.res.AssetFileDescriptor openFd(@NonNull String) throws java.io.IOException;
+    method @NonNull public android.content.res.AssetFileDescriptor openNonAssetFd(@NonNull String) throws java.io.IOException;
+    method @NonNull public android.content.res.AssetFileDescriptor openNonAssetFd(int, @NonNull String) throws java.io.IOException;
+    method @NonNull public android.content.res.XmlResourceParser openXmlResourceParser(@NonNull String) throws java.io.IOException;
+    method @NonNull public android.content.res.XmlResourceParser openXmlResourceParser(int, @NonNull String) throws java.io.IOException;
     field public static final int ACCESS_BUFFER = 3; // 0x3
     field public static final int ACCESS_RANDOM = 1; // 0x1
     field public static final int ACCESS_STREAMING = 2; // 0x2
@@ -12043,28 +12101,26 @@
   }
 
   public final class AssetManager.AssetInputStream extends java.io.InputStream {
-    method public void mark(int);
     method public int read() throws java.io.IOException;
-    method public void reset() throws java.io.IOException;
   }
 
   public class ColorStateList implements android.os.Parcelable {
-    ctor public ColorStateList(int[][], int[]);
-    method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    ctor public ColorStateList(int[][], @ColorInt int[]);
+    method @Deprecated @NonNull public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @NonNull public static android.content.res.ColorStateList createFromXml(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser, @Nullable android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
     method public int getChangingConfigurations();
-    method public int getColorForState(int[], int);
-    method public int getDefaultColor();
+    method public int getColorForState(@Nullable int[], int);
+    method @ColorInt public int getDefaultColor();
     method public boolean isOpaque();
     method public boolean isStateful();
-    method public static android.content.res.ColorStateList valueOf(int);
-    method public android.content.res.ColorStateList withAlpha(int);
+    method @NonNull public static android.content.res.ColorStateList valueOf(@ColorInt int);
+    method @NonNull public android.content.res.ColorStateList withAlpha(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR;
   }
 
-  public final class Configuration implements java.lang.Comparable android.os.Parcelable {
+  public final class Configuration implements java.lang.Comparable<android.content.res.Configuration> android.os.Parcelable {
     ctor public Configuration();
     ctor public Configuration(android.content.res.Configuration);
     method public int compareTo(android.content.res.Configuration);
@@ -12072,7 +12128,7 @@
     method public int diff(android.content.res.Configuration);
     method public boolean equals(android.content.res.Configuration);
     method public int getLayoutDirection();
-    method public android.os.LocaleList getLocales();
+    method @NonNull public android.os.LocaleList getLocales();
     method public boolean isLayoutSizeAtLeast(int);
     method public boolean isScreenHdr();
     method public boolean isScreenRound();
@@ -12080,11 +12136,11 @@
     method public static boolean needNewResources(int, int);
     method public void readFromParcel(android.os.Parcel);
     method public void setLayoutDirection(java.util.Locale);
-    method public void setLocale(java.util.Locale);
-    method public void setLocales(android.os.LocaleList);
+    method public void setLocale(@Nullable java.util.Locale);
+    method public void setLocales(@Nullable android.os.LocaleList);
     method public void setTo(android.content.res.Configuration);
     method public void setToDefaults();
-    method public int updateFrom(android.content.res.Configuration);
+    method public int updateFrom(@NonNull android.content.res.Configuration);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int COLOR_MODE_HDR_MASK = 12; // 0xc
     field public static final int COLOR_MODE_HDR_NO = 4; // 0x4
@@ -12119,7 +12175,7 @@
     field public static final int NAVIGATION_WHEEL = 4; // 0x4
     field public static final int ORIENTATION_LANDSCAPE = 2; // 0x2
     field public static final int ORIENTATION_PORTRAIT = 1; // 0x1
-    field public static final deprecated int ORIENTATION_SQUARE = 3; // 0x3
+    field @Deprecated public static final int ORIENTATION_SQUARE = 3; // 0x3
     field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
     field public static final int SCREENLAYOUT_LAYOUTDIR_LTR = 64; // 0x40
     field public static final int SCREENLAYOUT_LAYOUTDIR_MASK = 192; // 0xc0
@@ -12146,7 +12202,7 @@
     field public static final int SMALLEST_SCREEN_WIDTH_DP_UNDEFINED = 0; // 0x0
     field public static final int TOUCHSCREEN_FINGER = 3; // 0x3
     field public static final int TOUCHSCREEN_NOTOUCH = 1; // 0x1
-    field public static final deprecated int TOUCHSCREEN_STYLUS = 2; // 0x2
+    field @Deprecated public static final int TOUCHSCREEN_STYLUS = 2; // 0x2
     field public static final int TOUCHSCREEN_UNDEFINED = 0; // 0x0
     field public static final int UI_MODE_NIGHT_MASK = 48; // 0x30
     field public static final int UI_MODE_NIGHT_NO = 16; // 0x10
@@ -12167,7 +12223,7 @@
     field public int hardKeyboardHidden;
     field public int keyboard;
     field public int keyboardHidden;
-    field public deprecated java.util.Locale locale;
+    field @Deprecated public java.util.Locale locale;
     field public int mcc;
     field public int mnc;
     field public int navigation;
@@ -12186,128 +12242,130 @@
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.res.ObbInfo> CREATOR;
     field public static final int OBB_OVERLAY = 1; // 0x1
-    field public java.lang.String filename;
+    field public String filename;
     field public int flags;
-    field public java.lang.String packageName;
+    field public String packageName;
     field public int version;
   }
 
   public class ObbScanner {
-    method public static android.content.res.ObbInfo getObbInfo(java.lang.String) throws java.io.IOException;
+    method public static android.content.res.ObbInfo getObbInfo(String) throws java.io.IOException;
   }
 
   public class Resources {
-    ctor public deprecated Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
+    ctor @Deprecated public Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
     method public final void finishPreloading();
     method public final void flushLayoutCache();
-    method public android.content.res.XmlResourceParser getAnimation(int) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public android.content.res.XmlResourceParser getAnimation(@AnimatorRes @AnimRes int) throws android.content.res.Resources.NotFoundException;
     method public final android.content.res.AssetManager getAssets();
-    method public boolean getBoolean(int) throws android.content.res.Resources.NotFoundException;
-    method public deprecated int getColor(int) throws android.content.res.Resources.NotFoundException;
-    method public int getColor(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
-    method public deprecated android.content.res.ColorStateList getColorStateList(int) throws android.content.res.Resources.NotFoundException;
-    method public android.content.res.ColorStateList getColorStateList(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method public boolean getBoolean(@BoolRes int) throws android.content.res.Resources.NotFoundException;
+    method @Deprecated @ColorInt public int getColor(@ColorRes int) throws android.content.res.Resources.NotFoundException;
+    method @ColorInt public int getColor(@ColorRes int, @Nullable android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method @Deprecated @NonNull public android.content.res.ColorStateList getColorStateList(@ColorRes int) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public android.content.res.ColorStateList getColorStateList(@ColorRes int, @Nullable android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
     method public android.content.res.Configuration getConfiguration();
-    method public float getDimension(int) throws android.content.res.Resources.NotFoundException;
-    method public int getDimensionPixelOffset(int) throws android.content.res.Resources.NotFoundException;
-    method public int getDimensionPixelSize(int) throws android.content.res.Resources.NotFoundException;
+    method public float getDimension(@DimenRes int) throws android.content.res.Resources.NotFoundException;
+    method public int getDimensionPixelOffset(@DimenRes int) throws android.content.res.Resources.NotFoundException;
+    method public int getDimensionPixelSize(@DimenRes int) throws android.content.res.Resources.NotFoundException;
     method public android.util.DisplayMetrics getDisplayMetrics();
-    method public deprecated android.graphics.drawable.Drawable getDrawable(int) throws android.content.res.Resources.NotFoundException;
-    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);
-    method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException;
-    method public int getInteger(int) throws android.content.res.Resources.NotFoundException;
-    method public android.content.res.XmlResourceParser getLayout(int) throws android.content.res.Resources.NotFoundException;
-    method public deprecated android.graphics.Movie getMovie(int) throws android.content.res.Resources.NotFoundException;
-    method public java.lang.String getQuantityString(int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
-    method public java.lang.String getQuantityString(int, int) throws android.content.res.Resources.NotFoundException;
-    method public java.lang.CharSequence getQuantityText(int, int) throws android.content.res.Resources.NotFoundException;
-    method public java.lang.String getResourceEntryName(int) throws android.content.res.Resources.NotFoundException;
-    method public java.lang.String getResourceName(int) throws android.content.res.Resources.NotFoundException;
-    method public java.lang.String getResourcePackageName(int) throws android.content.res.Resources.NotFoundException;
-    method public java.lang.String getResourceTypeName(int) throws android.content.res.Resources.NotFoundException;
-    method public java.lang.String getString(int) throws android.content.res.Resources.NotFoundException;
-    method public java.lang.String getString(int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
-    method public java.lang.String[] getStringArray(int) throws android.content.res.Resources.NotFoundException;
+    method @Deprecated public android.graphics.drawable.Drawable getDrawable(@DrawableRes int) throws android.content.res.Resources.NotFoundException;
+    method public android.graphics.drawable.Drawable getDrawable(@DrawableRes int, @Nullable android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
+    method @Deprecated @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@DrawableRes int, int) throws android.content.res.Resources.NotFoundException;
+    method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@DrawableRes int, int, @Nullable android.content.res.Resources.Theme);
+    method public float getFloat(@DimenRes int);
+    method @NonNull public android.graphics.Typeface getFont(@FontRes int) throws android.content.res.Resources.NotFoundException;
+    method public float getFraction(@FractionRes int, int, int);
+    method public int getIdentifier(String, String, String);
+    method @NonNull public int[] getIntArray(@ArrayRes int) throws android.content.res.Resources.NotFoundException;
+    method public int getInteger(@IntegerRes int) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public android.content.res.XmlResourceParser getLayout(@LayoutRes int) throws android.content.res.Resources.NotFoundException;
+    method @Deprecated public android.graphics.Movie getMovie(@RawRes int) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public String getQuantityString(@PluralsRes int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public String getQuantityString(@PluralsRes int, int) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public CharSequence getQuantityText(@PluralsRes int, int) throws android.content.res.Resources.NotFoundException;
+    method public String getResourceEntryName(@AnyRes int) throws android.content.res.Resources.NotFoundException;
+    method public String getResourceName(@AnyRes int) throws android.content.res.Resources.NotFoundException;
+    method public String getResourcePackageName(@AnyRes int) throws android.content.res.Resources.NotFoundException;
+    method public String getResourceTypeName(@AnyRes int) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public String getString(@StringRes int) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public String getString(@StringRes int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public String[] getStringArray(@ArrayRes int) throws android.content.res.Resources.NotFoundException;
     method public static android.content.res.Resources getSystem();
-    method public java.lang.CharSequence getText(int) throws android.content.res.Resources.NotFoundException;
-    method public java.lang.CharSequence getText(int, java.lang.CharSequence);
-    method public java.lang.CharSequence[] getTextArray(int) throws android.content.res.Resources.NotFoundException;
-    method public void getValue(int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
-    method public void getValue(java.lang.String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
-    method public void getValueForDensity(int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
-    method public android.content.res.XmlResourceParser getXml(int) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public CharSequence getText(@StringRes int) throws android.content.res.Resources.NotFoundException;
+    method public CharSequence getText(@StringRes int, CharSequence);
+    method @NonNull public CharSequence[] getTextArray(@ArrayRes int) throws android.content.res.Resources.NotFoundException;
+    method public void getValue(@AnyRes int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
+    method public void getValue(String, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
+    method public void getValueForDensity(@AnyRes int, int, android.util.TypedValue, boolean) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public android.content.res.XmlResourceParser getXml(@XmlRes int) throws android.content.res.Resources.NotFoundException;
     method public final android.content.res.Resources.Theme newTheme();
-    method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, int[]);
-    method public android.content.res.TypedArray obtainTypedArray(int) throws android.content.res.Resources.NotFoundException;
-    method public java.io.InputStream openRawResource(int) throws android.content.res.Resources.NotFoundException;
-    method public java.io.InputStream openRawResource(int, android.util.TypedValue) throws android.content.res.Resources.NotFoundException;
-    method public android.content.res.AssetFileDescriptor openRawResourceFd(int) throws android.content.res.Resources.NotFoundException;
-    method public void parseBundleExtra(java.lang.String, android.util.AttributeSet, android.os.Bundle) throws org.xmlpull.v1.XmlPullParserException;
+    method public android.content.res.TypedArray obtainAttributes(android.util.AttributeSet, @StyleableRes int[]);
+    method @NonNull public android.content.res.TypedArray obtainTypedArray(@ArrayRes int) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public java.io.InputStream openRawResource(@RawRes int) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public java.io.InputStream openRawResource(@RawRes int, android.util.TypedValue) throws android.content.res.Resources.NotFoundException;
+    method public android.content.res.AssetFileDescriptor openRawResourceFd(@RawRes int) throws android.content.res.Resources.NotFoundException;
+    method public void parseBundleExtra(String, android.util.AttributeSet, android.os.Bundle) throws org.xmlpull.v1.XmlPullParserException;
     method public void parseBundleExtras(android.content.res.XmlResourceParser, android.os.Bundle) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public deprecated void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
+    method @Deprecated public void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
+    field @AnyRes public static final int ID_NULL = 0; // 0x0
   }
 
   public static class Resources.NotFoundException extends java.lang.RuntimeException {
     ctor public Resources.NotFoundException();
-    ctor public Resources.NotFoundException(java.lang.String);
-    ctor public Resources.NotFoundException(java.lang.String, java.lang.Exception);
+    ctor public Resources.NotFoundException(String);
+    ctor public Resources.NotFoundException(String, Exception);
   }
 
   public final class Resources.Theme {
     method public void applyStyle(int, boolean);
-    method public void dump(int, java.lang.String, java.lang.String);
+    method public void dump(int, String, String);
     method public int getChangingConfigurations();
-    method public android.graphics.drawable.Drawable getDrawable(int) throws android.content.res.Resources.NotFoundException;
+    method public android.graphics.drawable.Drawable getDrawable(@DrawableRes int) throws android.content.res.Resources.NotFoundException;
     method public android.content.res.Resources getResources();
-    method public android.content.res.TypedArray obtainStyledAttributes(int[]);
-    method public android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
-    method public android.content.res.TypedArray obtainStyledAttributes(android.util.AttributeSet, int[], int, int);
+    method @NonNull public android.content.res.TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[]);
+    method @NonNull public android.content.res.TypedArray obtainStyledAttributes(@StyleRes int, @NonNull @StyleableRes int[]) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public android.content.res.TypedArray obtainStyledAttributes(@Nullable android.util.AttributeSet, @NonNull @StyleableRes int[], @AttrRes int, @StyleRes int);
     method public boolean resolveAttribute(int, android.util.TypedValue, boolean);
     method public void setTo(android.content.res.Resources.Theme);
   }
 
   public class TypedArray {
-    method public boolean getBoolean(int, boolean);
+    method public boolean getBoolean(@StyleableRes int, boolean);
     method public int getChangingConfigurations();
-    method public int getColor(int, int);
-    method public android.content.res.ColorStateList getColorStateList(int);
-    method public float getDimension(int, float);
-    method public int getDimensionPixelOffset(int, int);
-    method public int getDimensionPixelSize(int, int);
-    method public android.graphics.drawable.Drawable getDrawable(int);
-    method public float getFloat(int, float);
-    method public android.graphics.Typeface getFont(int);
-    method public float getFraction(int, int, int, float);
+    method @ColorInt public int getColor(@StyleableRes int, @ColorInt int);
+    method @Nullable public android.content.res.ColorStateList getColorStateList(@StyleableRes int);
+    method public float getDimension(@StyleableRes int, float);
+    method public int getDimensionPixelOffset(@StyleableRes int, int);
+    method public int getDimensionPixelSize(@StyleableRes int, int);
+    method @Nullable public android.graphics.drawable.Drawable getDrawable(@StyleableRes int);
+    method public float getFloat(@StyleableRes int, float);
+    method @Nullable public android.graphics.Typeface getFont(@StyleableRes int);
+    method public float getFraction(@StyleableRes int, int, int, float);
     method public int getIndex(int);
     method public int getIndexCount();
-    method public int getInt(int, int);
-    method public int getInteger(int, int);
-    method public int getLayoutDimension(int, java.lang.String);
-    method public int getLayoutDimension(int, int);
-    method public java.lang.String getNonResourceString(int);
-    method public java.lang.String getPositionDescription();
-    method public int getResourceId(int, int);
+    method public int getInt(@StyleableRes int, int);
+    method public int getInteger(@StyleableRes int, int);
+    method public int getLayoutDimension(@StyleableRes int, String);
+    method public int getLayoutDimension(@StyleableRes int, int);
+    method public String getNonResourceString(@StyleableRes int);
+    method public String getPositionDescription();
+    method @AnyRes public int getResourceId(@StyleableRes int, int);
     method public android.content.res.Resources getResources();
-    method public java.lang.String getString(int);
-    method public java.lang.CharSequence getText(int);
-    method public java.lang.CharSequence[] getTextArray(int);
-    method public int getType(int);
-    method public boolean getValue(int, android.util.TypedValue);
-    method public boolean hasValue(int);
-    method public boolean hasValueOrEmpty(int);
+    method @StyleRes public int getSourceStyleResourceId(@StyleableRes int, @StyleRes int);
+    method @Nullable public String getString(@StyleableRes int);
+    method public CharSequence getText(@StyleableRes int);
+    method public CharSequence[] getTextArray(@StyleableRes int);
+    method public int getType(@StyleableRes int);
+    method public boolean getValue(@StyleableRes int, android.util.TypedValue);
+    method public boolean hasValue(@StyleableRes int);
+    method public boolean hasValueOrEmpty(@StyleableRes int);
     method public int length();
-    method public android.util.TypedValue peekValue(int);
+    method public android.util.TypedValue peekValue(@StyleableRes int);
     method public void recycle();
   }
 
-  public abstract interface XmlResourceParser implements android.util.AttributeSet java.lang.AutoCloseable org.xmlpull.v1.XmlPullParser {
-    method public abstract void close();
+  public interface XmlResourceParser extends org.xmlpull.v1.XmlPullParser android.util.AttributeSet java.lang.AutoCloseable {
+    method public void close();
   }
 
 }
@@ -12324,20 +12382,20 @@
     method protected void finalize();
     method public byte[] getBlob(int);
     method public int getColumnCount();
-    method public int getColumnIndex(java.lang.String);
-    method public int getColumnIndexOrThrow(java.lang.String);
-    method public java.lang.String getColumnName(int);
+    method public int getColumnIndex(String);
+    method public int getColumnIndexOrThrow(String);
+    method public String getColumnName(int);
     method public android.os.Bundle getExtras();
     method public android.net.Uri getNotificationUri();
     method public final int getPosition();
     method public int getType(int);
-    method protected deprecated java.lang.Object getUpdatedField(int);
+    method @Deprecated protected Object getUpdatedField(int);
     method public boolean getWantsAllOnMoveCalls();
     method public android.database.CursorWindow getWindow();
     method public final boolean isAfterLast();
     method public final boolean isBeforeFirst();
     method public boolean isClosed();
-    method protected deprecated boolean isFieldUpdated(int);
+    method @Deprecated protected boolean isFieldUpdated(int);
     method public final boolean isFirst();
     method public final boolean isLast();
     method public final boolean move(int);
@@ -12356,9 +12414,9 @@
     method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
     method public void unregisterContentObserver(android.database.ContentObserver);
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
-    field protected deprecated boolean mClosed;
-    field protected deprecated android.content.ContentResolver mContentResolver;
-    field protected deprecated int mPos;
+    field @Deprecated protected boolean mClosed;
+    field @Deprecated protected android.content.ContentResolver mContentResolver;
+    field @Deprecated protected int mPos;
   }
 
   protected static class AbstractCursor.SelfContentObserver extends android.database.ContentObserver {
@@ -12372,13 +12430,13 @@
     method public int getInt(int);
     method public long getLong(int);
     method public short getShort(int);
-    method public java.lang.String getString(int);
+    method public String getString(int);
     method public boolean hasWindow();
-    method public deprecated boolean isBlob(int);
-    method public deprecated boolean isFloat(int);
-    method public deprecated boolean isLong(int);
+    method @Deprecated public boolean isBlob(int);
+    method @Deprecated public boolean isFloat(int);
+    method @Deprecated public boolean isLong(int);
     method public boolean isNull(int);
-    method public deprecated boolean isString(int);
+    method @Deprecated public boolean isString(int);
     method public void setWindow(android.database.CursorWindow);
     field protected android.database.CursorWindow mWindow;
   }
@@ -12390,27 +12448,27 @@
     field public int sizeCopied;
   }
 
-  public class ContentObservable extends android.database.Observable {
+  public class ContentObservable extends android.database.Observable<android.database.ContentObserver> {
     ctor public ContentObservable();
-    method public deprecated void dispatchChange(boolean);
+    method @Deprecated public void dispatchChange(boolean);
     method public void dispatchChange(boolean, android.net.Uri);
-    method public deprecated void notifyChange(boolean);
+    method @Deprecated public void notifyChange(boolean);
     method public void registerObserver(android.database.ContentObserver);
   }
 
   public abstract class ContentObserver {
     ctor public ContentObserver(android.os.Handler);
     method public boolean deliverSelfNotifications();
-    method public final deprecated void dispatchChange(boolean);
+    method @Deprecated public final void dispatchChange(boolean);
     method public final void dispatchChange(boolean, android.net.Uri);
     method public void onChange(boolean);
     method public void onChange(boolean, android.net.Uri);
   }
 
-  public abstract interface CrossProcessCursor implements android.database.Cursor {
-    method public abstract void fillWindow(int, android.database.CursorWindow);
-    method public abstract android.database.CursorWindow getWindow();
-    method public abstract boolean onMove(int, int);
+  public interface CrossProcessCursor extends android.database.Cursor {
+    method public void fillWindow(int, android.database.CursorWindow);
+    method public android.database.CursorWindow getWindow();
+    method public boolean onMove(int, int);
   }
 
   public class CrossProcessCursorWrapper extends android.database.CursorWrapper implements android.database.CrossProcessCursor {
@@ -12420,48 +12478,48 @@
     method public boolean onMove(int, int);
   }
 
-  public abstract interface Cursor implements java.io.Closeable {
-    method public abstract void close();
-    method public abstract void copyStringToBuffer(int, android.database.CharArrayBuffer);
-    method public abstract deprecated void deactivate();
-    method public abstract byte[] getBlob(int);
-    method public abstract int getColumnCount();
-    method public abstract int getColumnIndex(java.lang.String);
-    method public abstract int getColumnIndexOrThrow(java.lang.String) throws java.lang.IllegalArgumentException;
-    method public abstract java.lang.String getColumnName(int);
-    method public abstract java.lang.String[] getColumnNames();
-    method public abstract int getCount();
-    method public abstract double getDouble(int);
-    method public abstract android.os.Bundle getExtras();
-    method public abstract float getFloat(int);
-    method public abstract int getInt(int);
-    method public abstract long getLong(int);
-    method public abstract android.net.Uri getNotificationUri();
-    method public abstract int getPosition();
-    method public abstract short getShort(int);
-    method public abstract java.lang.String getString(int);
-    method public abstract int getType(int);
-    method public abstract boolean getWantsAllOnMoveCalls();
-    method public abstract boolean isAfterLast();
-    method public abstract boolean isBeforeFirst();
-    method public abstract boolean isClosed();
-    method public abstract boolean isFirst();
-    method public abstract boolean isLast();
-    method public abstract boolean isNull(int);
-    method public abstract boolean move(int);
-    method public abstract boolean moveToFirst();
-    method public abstract boolean moveToLast();
-    method public abstract boolean moveToNext();
-    method public abstract boolean moveToPosition(int);
-    method public abstract boolean moveToPrevious();
-    method public abstract void registerContentObserver(android.database.ContentObserver);
-    method public abstract void registerDataSetObserver(android.database.DataSetObserver);
-    method public abstract deprecated boolean requery();
-    method public abstract android.os.Bundle respond(android.os.Bundle);
-    method public abstract void setExtras(android.os.Bundle);
-    method public abstract void setNotificationUri(android.content.ContentResolver, android.net.Uri);
-    method public abstract void unregisterContentObserver(android.database.ContentObserver);
-    method public abstract void unregisterDataSetObserver(android.database.DataSetObserver);
+  public interface Cursor extends java.io.Closeable {
+    method public void close();
+    method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
+    method @Deprecated public void deactivate();
+    method public byte[] getBlob(int);
+    method public int getColumnCount();
+    method public int getColumnIndex(String);
+    method public int getColumnIndexOrThrow(String) throws java.lang.IllegalArgumentException;
+    method public String getColumnName(int);
+    method public String[] getColumnNames();
+    method public int getCount();
+    method public double getDouble(int);
+    method public android.os.Bundle getExtras();
+    method public float getFloat(int);
+    method public int getInt(int);
+    method public long getLong(int);
+    method public android.net.Uri getNotificationUri();
+    method public int getPosition();
+    method public short getShort(int);
+    method public String getString(int);
+    method public int getType(int);
+    method public boolean getWantsAllOnMoveCalls();
+    method public boolean isAfterLast();
+    method public boolean isBeforeFirst();
+    method public boolean isClosed();
+    method public boolean isFirst();
+    method public boolean isLast();
+    method public boolean isNull(int);
+    method public boolean move(int);
+    method public boolean moveToFirst();
+    method public boolean moveToLast();
+    method public boolean moveToNext();
+    method public boolean moveToPosition(int);
+    method public boolean moveToPrevious();
+    method public void registerContentObserver(android.database.ContentObserver);
+    method public void registerDataSetObserver(android.database.DataSetObserver);
+    method @Deprecated public boolean requery();
+    method public android.os.Bundle respond(android.os.Bundle);
+    method public void setExtras(android.os.Bundle);
+    method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
+    method public void unregisterContentObserver(android.database.ContentObserver);
+    method public void unregisterDataSetObserver(android.database.DataSetObserver);
     field public static final int FIELD_TYPE_BLOB = 4; // 0x4
     field public static final int FIELD_TYPE_FLOAT = 2; // 0x2
     field public static final int FIELD_TYPE_INTEGER = 1; // 0x1
@@ -12471,28 +12529,26 @@
 
   public class CursorIndexOutOfBoundsException extends java.lang.IndexOutOfBoundsException {
     ctor public CursorIndexOutOfBoundsException(int, int);
-    ctor public CursorIndexOutOfBoundsException(java.lang.String);
+    ctor public CursorIndexOutOfBoundsException(String);
   }
 
-  public final class CursorJoiner implements java.lang.Iterable java.util.Iterator {
-    ctor public CursorJoiner(android.database.Cursor, java.lang.String[], android.database.Cursor, java.lang.String[]);
+  public final class CursorJoiner implements java.lang.Iterable<android.database.CursorJoiner.Result> java.util.Iterator<android.database.CursorJoiner.Result> {
+    ctor public CursorJoiner(android.database.Cursor, String[], android.database.Cursor, String[]);
     method public boolean hasNext();
     method public java.util.Iterator<android.database.CursorJoiner.Result> iterator();
     method public android.database.CursorJoiner.Result next();
   }
 
-  public static final class CursorJoiner.Result extends java.lang.Enum {
-    method public static android.database.CursorJoiner.Result valueOf(java.lang.String);
-    method public static final android.database.CursorJoiner.Result[] values();
+  public enum CursorJoiner.Result {
     enum_constant public static final android.database.CursorJoiner.Result BOTH;
     enum_constant public static final android.database.CursorJoiner.Result LEFT;
     enum_constant public static final android.database.CursorJoiner.Result RIGHT;
   }
 
   public class CursorWindow extends android.database.sqlite.SQLiteClosable implements android.os.Parcelable {
-    ctor public CursorWindow(java.lang.String);
-    ctor public CursorWindow(java.lang.String, long);
-    ctor public deprecated CursorWindow(boolean);
+    ctor public CursorWindow(String);
+    ctor public CursorWindow(String, long);
+    ctor @Deprecated public CursorWindow(boolean);
     method public boolean allocRow();
     method public void clear();
     method public void copyStringToBuffer(int, int, android.database.CharArrayBuffer);
@@ -12506,20 +12562,20 @@
     method public int getNumRows();
     method public short getShort(int, int);
     method public int getStartPosition();
-    method public java.lang.String getString(int, int);
+    method public String getString(int, int);
     method public int getType(int, int);
-    method public deprecated boolean isBlob(int, int);
-    method public deprecated boolean isFloat(int, int);
-    method public deprecated boolean isLong(int, int);
-    method public deprecated boolean isNull(int, int);
-    method public deprecated boolean isString(int, int);
+    method @Deprecated public boolean isBlob(int, int);
+    method @Deprecated public boolean isFloat(int, int);
+    method @Deprecated public boolean isLong(int, int);
+    method @Deprecated public boolean isNull(int, int);
+    method @Deprecated public boolean isString(int, int);
     method public static android.database.CursorWindow newFromParcel(android.os.Parcel);
     method protected void onAllReferencesReleased();
     method public boolean putBlob(byte[], int, int);
     method public boolean putDouble(double, int, int);
     method public boolean putLong(long, int, int);
     method public boolean putNull(int, int);
-    method public boolean putString(java.lang.String, int, int);
+    method public boolean putString(String, int, int);
     method public boolean setNumColumns(int);
     method public void setStartPosition(int);
     method public void writeToParcel(android.os.Parcel, int);
@@ -12530,13 +12586,13 @@
     ctor public CursorWrapper(android.database.Cursor);
     method public void close();
     method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
-    method public deprecated void deactivate();
+    method @Deprecated public void deactivate();
     method public byte[] getBlob(int);
     method public int getColumnCount();
-    method public int getColumnIndex(java.lang.String);
-    method public int getColumnIndexOrThrow(java.lang.String) throws java.lang.IllegalArgumentException;
-    method public java.lang.String getColumnName(int);
-    method public java.lang.String[] getColumnNames();
+    method public int getColumnIndex(String);
+    method public int getColumnIndexOrThrow(String) throws java.lang.IllegalArgumentException;
+    method public String getColumnName(int);
+    method public String[] getColumnNames();
     method public int getCount();
     method public double getDouble(int);
     method public android.os.Bundle getExtras();
@@ -12546,7 +12602,7 @@
     method public android.net.Uri getNotificationUri();
     method public int getPosition();
     method public short getShort(int);
-    method public java.lang.String getString(int);
+    method public String getString(int);
     method public int getType(int);
     method public boolean getWantsAllOnMoveCalls();
     method public android.database.Cursor getWrappedCursor();
@@ -12564,7 +12620,7 @@
     method public boolean moveToPrevious();
     method public void registerContentObserver(android.database.ContentObserver);
     method public void registerDataSetObserver(android.database.DataSetObserver);
-    method public deprecated boolean requery();
+    method @Deprecated public boolean requery();
     method public android.os.Bundle respond(android.os.Bundle);
     method public void setExtras(android.os.Bundle);
     method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
@@ -12572,7 +12628,7 @@
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
   }
 
-  public class DataSetObservable extends android.database.Observable {
+  public class DataSetObservable extends android.database.Observable<android.database.DataSetObserver> {
     ctor public DataSetObservable();
     method public void notifyChanged();
     method public void notifyInvalidated();
@@ -12584,59 +12640,59 @@
     method public void onInvalidated();
   }
 
-  public abstract interface DatabaseErrorHandler {
-    method public abstract void onCorruption(android.database.sqlite.SQLiteDatabase);
+  public interface DatabaseErrorHandler {
+    method public void onCorruption(android.database.sqlite.SQLiteDatabase);
   }
 
   public class DatabaseUtils {
     ctor public DatabaseUtils();
-    method public static void appendEscapedSQLString(java.lang.StringBuilder, java.lang.String);
-    method public static java.lang.String[] appendSelectionArgs(java.lang.String[], java.lang.String[]);
-    method public static final void appendValueToSql(java.lang.StringBuilder, java.lang.Object);
-    method public static void bindObjectToProgram(android.database.sqlite.SQLiteProgram, int, java.lang.Object);
-    method public static android.os.ParcelFileDescriptor blobFileDescriptorForQuery(android.database.sqlite.SQLiteDatabase, java.lang.String, java.lang.String[]);
-    method public static android.os.ParcelFileDescriptor blobFileDescriptorForQuery(android.database.sqlite.SQLiteStatement, java.lang.String[]);
-    method public static java.lang.String concatenateWhere(java.lang.String, java.lang.String);
-    method public static void createDbFromSqlStatements(android.content.Context, java.lang.String, int, java.lang.String);
-    method public static void cursorDoubleToContentValues(android.database.Cursor, java.lang.String, android.content.ContentValues, java.lang.String);
-    method public static void cursorDoubleToContentValuesIfPresent(android.database.Cursor, android.content.ContentValues, java.lang.String);
-    method public static void cursorDoubleToCursorValues(android.database.Cursor, java.lang.String, android.content.ContentValues);
-    method public static void cursorFloatToContentValuesIfPresent(android.database.Cursor, android.content.ContentValues, java.lang.String);
-    method public static void cursorIntToContentValues(android.database.Cursor, java.lang.String, android.content.ContentValues);
-    method public static void cursorIntToContentValues(android.database.Cursor, java.lang.String, android.content.ContentValues, java.lang.String);
-    method public static void cursorIntToContentValuesIfPresent(android.database.Cursor, android.content.ContentValues, java.lang.String);
-    method public static void cursorLongToContentValues(android.database.Cursor, java.lang.String, android.content.ContentValues);
-    method public static void cursorLongToContentValues(android.database.Cursor, java.lang.String, android.content.ContentValues, java.lang.String);
-    method public static void cursorLongToContentValuesIfPresent(android.database.Cursor, android.content.ContentValues, java.lang.String);
+    method public static void appendEscapedSQLString(StringBuilder, String);
+    method public static String[] appendSelectionArgs(String[], String[]);
+    method public static final void appendValueToSql(StringBuilder, Object);
+    method public static void bindObjectToProgram(android.database.sqlite.SQLiteProgram, int, Object);
+    method public static android.os.ParcelFileDescriptor blobFileDescriptorForQuery(android.database.sqlite.SQLiteDatabase, String, String[]);
+    method public static android.os.ParcelFileDescriptor blobFileDescriptorForQuery(android.database.sqlite.SQLiteStatement, String[]);
+    method public static String concatenateWhere(String, String);
+    method public static void createDbFromSqlStatements(android.content.Context, String, int, String);
+    method public static void cursorDoubleToContentValues(android.database.Cursor, String, android.content.ContentValues, String);
+    method public static void cursorDoubleToContentValuesIfPresent(android.database.Cursor, android.content.ContentValues, String);
+    method public static void cursorDoubleToCursorValues(android.database.Cursor, String, android.content.ContentValues);
+    method public static void cursorFloatToContentValuesIfPresent(android.database.Cursor, android.content.ContentValues, String);
+    method public static void cursorIntToContentValues(android.database.Cursor, String, android.content.ContentValues);
+    method public static void cursorIntToContentValues(android.database.Cursor, String, android.content.ContentValues, String);
+    method public static void cursorIntToContentValuesIfPresent(android.database.Cursor, android.content.ContentValues, String);
+    method public static void cursorLongToContentValues(android.database.Cursor, String, android.content.ContentValues);
+    method public static void cursorLongToContentValues(android.database.Cursor, String, android.content.ContentValues, String);
+    method public static void cursorLongToContentValuesIfPresent(android.database.Cursor, android.content.ContentValues, String);
     method public static void cursorRowToContentValues(android.database.Cursor, android.content.ContentValues);
-    method public static void cursorShortToContentValuesIfPresent(android.database.Cursor, android.content.ContentValues, java.lang.String);
-    method public static void cursorStringToContentValues(android.database.Cursor, java.lang.String, android.content.ContentValues);
-    method public static void cursorStringToContentValues(android.database.Cursor, java.lang.String, android.content.ContentValues, java.lang.String);
-    method public static void cursorStringToContentValuesIfPresent(android.database.Cursor, android.content.ContentValues, java.lang.String);
-    method public static void cursorStringToInsertHelper(android.database.Cursor, java.lang.String, android.database.DatabaseUtils.InsertHelper, int);
+    method public static void cursorShortToContentValuesIfPresent(android.database.Cursor, android.content.ContentValues, String);
+    method public static void cursorStringToContentValues(android.database.Cursor, String, android.content.ContentValues);
+    method public static void cursorStringToContentValues(android.database.Cursor, String, android.content.ContentValues, String);
+    method public static void cursorStringToContentValuesIfPresent(android.database.Cursor, android.content.ContentValues, String);
+    method public static void cursorStringToInsertHelper(android.database.Cursor, String, android.database.DatabaseUtils.InsertHelper, int);
     method public static void dumpCurrentRow(android.database.Cursor);
     method public static void dumpCurrentRow(android.database.Cursor, java.io.PrintStream);
-    method public static void dumpCurrentRow(android.database.Cursor, java.lang.StringBuilder);
-    method public static java.lang.String dumpCurrentRowToString(android.database.Cursor);
+    method public static void dumpCurrentRow(android.database.Cursor, StringBuilder);
+    method public static String dumpCurrentRowToString(android.database.Cursor);
     method public static void dumpCursor(android.database.Cursor);
     method public static void dumpCursor(android.database.Cursor, java.io.PrintStream);
-    method public static void dumpCursor(android.database.Cursor, java.lang.StringBuilder);
-    method public static java.lang.String dumpCursorToString(android.database.Cursor);
-    method public static java.lang.String getCollationKey(java.lang.String);
-    method public static java.lang.String getHexCollationKey(java.lang.String);
-    method public static int getSqlStatementType(java.lang.String);
-    method public static long longForQuery(android.database.sqlite.SQLiteDatabase, java.lang.String, java.lang.String[]);
-    method public static long longForQuery(android.database.sqlite.SQLiteStatement, java.lang.String[]);
-    method public static long queryNumEntries(android.database.sqlite.SQLiteDatabase, java.lang.String);
-    method public static long queryNumEntries(android.database.sqlite.SQLiteDatabase, java.lang.String, java.lang.String);
-    method public static long queryNumEntries(android.database.sqlite.SQLiteDatabase, java.lang.String, java.lang.String, java.lang.String[]);
+    method public static void dumpCursor(android.database.Cursor, StringBuilder);
+    method public static String dumpCursorToString(android.database.Cursor);
+    method public static String getCollationKey(String);
+    method public static String getHexCollationKey(String);
+    method public static int getSqlStatementType(String);
+    method public static long longForQuery(android.database.sqlite.SQLiteDatabase, String, String[]);
+    method public static long longForQuery(android.database.sqlite.SQLiteStatement, String[]);
+    method public static long queryNumEntries(android.database.sqlite.SQLiteDatabase, String);
+    method public static long queryNumEntries(android.database.sqlite.SQLiteDatabase, String, String);
+    method public static long queryNumEntries(android.database.sqlite.SQLiteDatabase, String, String, String[]);
     method public static final void readExceptionFromParcel(android.os.Parcel);
     method public static void readExceptionWithFileNotFoundExceptionFromParcel(android.os.Parcel) throws java.io.FileNotFoundException;
     method public static void readExceptionWithOperationApplicationExceptionFromParcel(android.os.Parcel) throws android.content.OperationApplicationException;
-    method public static java.lang.String sqlEscapeString(java.lang.String);
-    method public static java.lang.String stringForQuery(android.database.sqlite.SQLiteDatabase, java.lang.String, java.lang.String[]);
-    method public static java.lang.String stringForQuery(android.database.sqlite.SQLiteStatement, java.lang.String[]);
-    method public static final void writeExceptionToParcel(android.os.Parcel, java.lang.Exception);
+    method public static String sqlEscapeString(String);
+    method public static String stringForQuery(android.database.sqlite.SQLiteDatabase, String, String[]);
+    method public static String stringForQuery(android.database.sqlite.SQLiteStatement, String[]);
+    method public static final void writeExceptionToParcel(android.os.Parcel, Exception);
     field public static final int STATEMENT_ABORT = 6; // 0x6
     field public static final int STATEMENT_ATTACH = 3; // 0x3
     field public static final int STATEMENT_BEGIN = 4; // 0x4
@@ -12649,23 +12705,23 @@
     field public static final int STATEMENT_UPDATE = 2; // 0x2
   }
 
-  public static deprecated class DatabaseUtils.InsertHelper {
-    ctor public DatabaseUtils.InsertHelper(android.database.sqlite.SQLiteDatabase, java.lang.String);
-    method public void bind(int, double);
-    method public void bind(int, float);
-    method public void bind(int, long);
-    method public void bind(int, int);
-    method public void bind(int, boolean);
-    method public void bind(int, byte[]);
-    method public void bind(int, java.lang.String);
-    method public void bindNull(int);
-    method public void close();
-    method public long execute();
-    method public int getColumnIndex(java.lang.String);
-    method public long insert(android.content.ContentValues);
-    method public void prepareForInsert();
-    method public void prepareForReplace();
-    method public long replace(android.content.ContentValues);
+  @Deprecated public static class DatabaseUtils.InsertHelper {
+    ctor @Deprecated public DatabaseUtils.InsertHelper(android.database.sqlite.SQLiteDatabase, String);
+    method @Deprecated public void bind(int, double);
+    method @Deprecated public void bind(int, float);
+    method @Deprecated public void bind(int, long);
+    method @Deprecated public void bind(int, int);
+    method @Deprecated public void bind(int, boolean);
+    method @Deprecated public void bind(int, byte[]);
+    method @Deprecated public void bind(int, String);
+    method @Deprecated public void bindNull(int);
+    method @Deprecated public void close();
+    method @Deprecated public long execute();
+    method @Deprecated public int getColumnIndex(String);
+    method @Deprecated public long insert(android.content.ContentValues);
+    method @Deprecated public void prepareForInsert();
+    method @Deprecated public void prepareForReplace();
+    method @Deprecated public long replace(android.content.ContentValues);
   }
 
   public final class DefaultDatabaseErrorHandler implements android.database.DatabaseErrorHandler {
@@ -12674,37 +12730,37 @@
   }
 
   public class MatrixCursor extends android.database.AbstractCursor {
-    ctor public MatrixCursor(java.lang.String[], int);
-    ctor public MatrixCursor(java.lang.String[]);
-    method public void addRow(java.lang.Object[]);
-    method public void addRow(java.lang.Iterable<?>);
-    method public java.lang.String[] getColumnNames();
+    ctor public MatrixCursor(String[], int);
+    ctor public MatrixCursor(String[]);
+    method public void addRow(Object[]);
+    method public void addRow(Iterable<?>);
+    method public String[] getColumnNames();
     method public int getCount();
     method public double getDouble(int);
     method public float getFloat(int);
     method public int getInt(int);
     method public long getLong(int);
     method public short getShort(int);
-    method public java.lang.String getString(int);
+    method public String getString(int);
     method public boolean isNull(int);
     method public android.database.MatrixCursor.RowBuilder newRow();
   }
 
   public class MatrixCursor.RowBuilder {
-    method public android.database.MatrixCursor.RowBuilder add(java.lang.Object);
-    method public android.database.MatrixCursor.RowBuilder add(java.lang.String, java.lang.Object);
+    method public android.database.MatrixCursor.RowBuilder add(Object);
+    method public android.database.MatrixCursor.RowBuilder add(String, Object);
   }
 
   public class MergeCursor extends android.database.AbstractCursor {
     ctor public MergeCursor(android.database.Cursor[]);
-    method public java.lang.String[] getColumnNames();
+    method public String[] getColumnNames();
     method public int getCount();
     method public double getDouble(int);
     method public float getFloat(int);
     method public int getInt(int);
     method public long getLong(int);
     method public short getShort(int);
-    method public java.lang.String getString(int);
+    method public String getString(int);
     method public boolean isNull(int);
   }
 
@@ -12718,13 +12774,13 @@
 
   public class SQLException extends java.lang.RuntimeException {
     ctor public SQLException();
-    ctor public SQLException(java.lang.String);
-    ctor public SQLException(java.lang.String, java.lang.Throwable);
+    ctor public SQLException(String);
+    ctor public SQLException(String, Throwable);
   }
 
   public class StaleDataException extends java.lang.RuntimeException {
     ctor public StaleDataException();
-    ctor public StaleDataException(java.lang.String);
+    ctor public StaleDataException(String);
   }
 
 }
@@ -12733,27 +12789,27 @@
 
   public class SQLiteAbortException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteAbortException();
-    ctor public SQLiteAbortException(java.lang.String);
+    ctor public SQLiteAbortException(String);
   }
 
   public class SQLiteAccessPermException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteAccessPermException();
-    ctor public SQLiteAccessPermException(java.lang.String);
+    ctor public SQLiteAccessPermException(String);
   }
 
   public class SQLiteBindOrColumnIndexOutOfRangeException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteBindOrColumnIndexOutOfRangeException();
-    ctor public SQLiteBindOrColumnIndexOutOfRangeException(java.lang.String);
+    ctor public SQLiteBindOrColumnIndexOutOfRangeException(String);
   }
 
   public class SQLiteBlobTooBigException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteBlobTooBigException();
-    ctor public SQLiteBlobTooBigException(java.lang.String);
+    ctor public SQLiteBlobTooBigException(String);
   }
 
   public class SQLiteCantOpenDatabaseException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteCantOpenDatabaseException();
-    ctor public SQLiteCantOpenDatabaseException(java.lang.String);
+    ctor public SQLiteCantOpenDatabaseException(String);
   }
 
   public abstract class SQLiteClosable implements java.io.Closeable {
@@ -12761,32 +12817,32 @@
     method public void acquireReference();
     method public void close();
     method protected abstract void onAllReferencesReleased();
-    method protected deprecated void onAllReferencesReleasedFromContainer();
+    method @Deprecated protected void onAllReferencesReleasedFromContainer();
     method public void releaseReference();
-    method public deprecated void releaseReferenceFromContainer();
+    method @Deprecated public void releaseReferenceFromContainer();
   }
 
   public class SQLiteConstraintException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteConstraintException();
-    ctor public SQLiteConstraintException(java.lang.String);
+    ctor public SQLiteConstraintException(String);
   }
 
   public class SQLiteCursor extends android.database.AbstractWindowedCursor {
-    ctor public deprecated SQLiteCursor(android.database.sqlite.SQLiteDatabase, android.database.sqlite.SQLiteCursorDriver, java.lang.String, android.database.sqlite.SQLiteQuery);
-    ctor public SQLiteCursor(android.database.sqlite.SQLiteCursorDriver, java.lang.String, android.database.sqlite.SQLiteQuery);
-    method public java.lang.String[] getColumnNames();
+    ctor @Deprecated public SQLiteCursor(android.database.sqlite.SQLiteDatabase, android.database.sqlite.SQLiteCursorDriver, String, android.database.sqlite.SQLiteQuery);
+    ctor public SQLiteCursor(android.database.sqlite.SQLiteCursorDriver, String, android.database.sqlite.SQLiteQuery);
+    method public String[] getColumnNames();
     method public int getCount();
     method public android.database.sqlite.SQLiteDatabase getDatabase();
     method public void setFillWindowForwardOnly(boolean);
-    method public void setSelectionArguments(java.lang.String[]);
+    method public void setSelectionArguments(String[]);
   }
 
-  public abstract interface SQLiteCursorDriver {
-    method public abstract void cursorClosed();
-    method public abstract void cursorDeactivated();
-    method public abstract void cursorRequeried(android.database.Cursor);
-    method public abstract android.database.Cursor query(android.database.sqlite.SQLiteDatabase.CursorFactory, java.lang.String[]);
-    method public abstract void setBindArguments(java.lang.String[]);
+  public interface SQLiteCursorDriver {
+    method public void cursorClosed();
+    method public void cursorDeactivated();
+    method public void cursorRequeried(android.database.Cursor);
+    method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]);
+    method public void setBindArguments(String[]);
   }
 
   public final class SQLiteDatabase extends android.database.sqlite.SQLiteClosable {
@@ -12794,68 +12850,68 @@
     method public void beginTransactionNonExclusive();
     method public void beginTransactionWithListener(android.database.sqlite.SQLiteTransactionListener);
     method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener);
-    method public android.database.sqlite.SQLiteStatement compileStatement(java.lang.String) throws android.database.SQLException;
-    method public static android.database.sqlite.SQLiteDatabase create(android.database.sqlite.SQLiteDatabase.CursorFactory);
-    method public static android.database.sqlite.SQLiteDatabase createInMemory(android.database.sqlite.SQLiteDatabase.OpenParams);
-    method public int delete(java.lang.String, java.lang.String, java.lang.String[]);
-    method public static boolean deleteDatabase(java.io.File);
+    method public android.database.sqlite.SQLiteStatement compileStatement(String) throws android.database.SQLException;
+    method @NonNull public static android.database.sqlite.SQLiteDatabase create(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
+    method @NonNull public static android.database.sqlite.SQLiteDatabase createInMemory(@NonNull android.database.sqlite.SQLiteDatabase.OpenParams);
+    method public int delete(String, String, String[]);
+    method public static boolean deleteDatabase(@NonNull java.io.File);
     method public void disableWriteAheadLogging();
     method public boolean enableWriteAheadLogging();
     method public void endTransaction();
-    method public void execSQL(java.lang.String) throws android.database.SQLException;
-    method public void execSQL(java.lang.String, java.lang.Object[]) throws android.database.SQLException;
-    method public static java.lang.String findEditTable(java.lang.String);
-    method public java.util.List<android.util.Pair<java.lang.String, java.lang.String>> getAttachedDbs();
+    method public void execSQL(String) throws android.database.SQLException;
+    method public void execSQL(String, Object[]) throws android.database.SQLException;
+    method public static String findEditTable(String);
+    method public java.util.List<android.util.Pair<java.lang.String,java.lang.String>> getAttachedDbs();
     method public long getMaximumSize();
     method public long getPageSize();
-    method public java.lang.String getPath();
-    method public deprecated java.util.Map<java.lang.String, java.lang.String> getSyncedTables();
+    method public String getPath();
+    method @Deprecated public java.util.Map<java.lang.String,java.lang.String> getSyncedTables();
     method public int getVersion();
     method public boolean inTransaction();
-    method public long insert(java.lang.String, java.lang.String, android.content.ContentValues);
-    method public long insertOrThrow(java.lang.String, java.lang.String, android.content.ContentValues) throws android.database.SQLException;
-    method public long insertWithOnConflict(java.lang.String, java.lang.String, android.content.ContentValues, int);
+    method public long insert(String, String, android.content.ContentValues);
+    method public long insertOrThrow(String, String, android.content.ContentValues) throws android.database.SQLException;
+    method public long insertWithOnConflict(String, String, android.content.ContentValues, int);
     method public boolean isDatabaseIntegrityOk();
     method public boolean isDbLockedByCurrentThread();
-    method public deprecated boolean isDbLockedByOtherThreads();
+    method @Deprecated public boolean isDbLockedByOtherThreads();
     method public boolean isOpen();
     method public boolean isReadOnly();
     method public boolean isWriteAheadLoggingEnabled();
-    method public deprecated void markTableSyncable(java.lang.String, java.lang.String);
-    method public deprecated void markTableSyncable(java.lang.String, java.lang.String, java.lang.String);
+    method @Deprecated public void markTableSyncable(String, String);
+    method @Deprecated public void markTableSyncable(String, String, String);
     method public boolean needUpgrade(int);
     method protected void onAllReferencesReleased();
-    method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
-    method public static android.database.sqlite.SQLiteDatabase openDatabase(java.io.File, android.database.sqlite.SQLiteDatabase.OpenParams);
-    method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
-    method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.io.File, android.database.sqlite.SQLiteDatabase.CursorFactory);
-    method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory);
-    method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
-    method public android.database.Cursor query(boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public android.database.Cursor query(boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.os.CancellationSignal);
-    method public android.database.Cursor query(java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String);
-    method public android.database.Cursor query(java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public android.database.Cursor queryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public android.database.Cursor queryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.os.CancellationSignal);
-    method public android.database.Cursor rawQuery(java.lang.String, java.lang.String[]);
-    method public android.database.Cursor rawQuery(java.lang.String, java.lang.String[], android.os.CancellationSignal);
-    method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, java.lang.String, java.lang.String[], java.lang.String);
-    method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
+    method public static android.database.sqlite.SQLiteDatabase openDatabase(@NonNull String, @Nullable android.database.sqlite.SQLiteDatabase.CursorFactory, int);
+    method public static android.database.sqlite.SQLiteDatabase openDatabase(@NonNull java.io.File, @NonNull android.database.sqlite.SQLiteDatabase.OpenParams);
+    method public static android.database.sqlite.SQLiteDatabase openDatabase(@NonNull String, @Nullable android.database.sqlite.SQLiteDatabase.CursorFactory, int, @Nullable android.database.DatabaseErrorHandler);
+    method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(@NonNull java.io.File, @Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
+    method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(@NonNull String, @Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
+    method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(@NonNull String, @Nullable android.database.sqlite.SQLiteDatabase.CursorFactory, @Nullable android.database.DatabaseErrorHandler);
+    method public android.database.Cursor query(boolean, String, String[], String, String[], String, String, String, String);
+    method public android.database.Cursor query(boolean, String, String[], String, String[], String, String, String, String, android.os.CancellationSignal);
+    method public android.database.Cursor query(String, String[], String, String[], String, String, String);
+    method public android.database.Cursor query(String, String[], String, String[], String, String, String, String);
+    method public android.database.Cursor queryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, String, String[], String, String[], String, String, String, String);
+    method public android.database.Cursor queryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, String, String[], String, String[], String, String, String, String, android.os.CancellationSignal);
+    method public android.database.Cursor rawQuery(String, String[]);
+    method public android.database.Cursor rawQuery(String, String[], android.os.CancellationSignal);
+    method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, String, String[], String);
+    method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, String, String[], String, android.os.CancellationSignal);
     method public static int releaseMemory();
-    method public long replace(java.lang.String, java.lang.String, android.content.ContentValues);
-    method public long replaceOrThrow(java.lang.String, java.lang.String, android.content.ContentValues) throws android.database.SQLException;
+    method public long replace(String, String, android.content.ContentValues);
+    method public long replaceOrThrow(String, String, android.content.ContentValues) throws android.database.SQLException;
     method public void setForeignKeyConstraintsEnabled(boolean);
     method public void setLocale(java.util.Locale);
-    method public deprecated void setLockingEnabled(boolean);
+    method @Deprecated public void setLockingEnabled(boolean);
     method public void setMaxSqlCacheSize(int);
     method public long setMaximumSize(long);
     method public void setPageSize(long);
     method public void setTransactionSuccessful();
     method public void setVersion(int);
-    method public int update(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[]);
-    method public int updateWithOnConflict(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[], int);
-    method public void validateSql(java.lang.String, android.os.CancellationSignal);
-    method public deprecated boolean yieldIfContended();
+    method public int update(String, android.content.ContentValues, String, String[]);
+    method public int updateWithOnConflict(String, android.content.ContentValues, String, String[], int);
+    method public void validateSql(@NonNull String, @Nullable android.os.CancellationSignal);
+    method @Deprecated public boolean yieldIfContended();
     method public boolean yieldIfContendedSafely();
     method public boolean yieldIfContendedSafely(long);
     field public static final int CONFLICT_ABORT = 2; // 0x2
@@ -12873,83 +12929,83 @@
     field public static final int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000; // 0xc350
   }
 
-  public static abstract interface SQLiteDatabase.CursorFactory {
-    method public abstract android.database.Cursor newCursor(android.database.sqlite.SQLiteDatabase, android.database.sqlite.SQLiteCursorDriver, java.lang.String, android.database.sqlite.SQLiteQuery);
+  public static interface SQLiteDatabase.CursorFactory {
+    method public android.database.Cursor newCursor(android.database.sqlite.SQLiteDatabase, android.database.sqlite.SQLiteCursorDriver, String, android.database.sqlite.SQLiteQuery);
   }
 
   public static final class SQLiteDatabase.OpenParams {
-    method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
-    method public android.database.DatabaseErrorHandler getErrorHandler();
+    method @Nullable public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
+    method @Nullable public android.database.DatabaseErrorHandler getErrorHandler();
     method public long getIdleConnectionTimeout();
-    method public java.lang.String getJournalMode();
-    method public int getLookasideSlotCount();
-    method public int getLookasideSlotSize();
+    method @Nullable public String getJournalMode();
+    method @IntRange(from=0xffffffff) public int getLookasideSlotCount();
+    method @IntRange(from=0xffffffff) public int getLookasideSlotSize();
     method public int getOpenFlags();
-    method public java.lang.String getSynchronousMode();
+    method @Nullable public String getSynchronousMode();
   }
 
   public static final class SQLiteDatabase.OpenParams.Builder {
     ctor public SQLiteDatabase.OpenParams.Builder();
     ctor public SQLiteDatabase.OpenParams.Builder(android.database.sqlite.SQLiteDatabase.OpenParams);
-    method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder addOpenFlags(int);
-    method public android.database.sqlite.SQLiteDatabase.OpenParams build();
-    method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int);
-    method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
-    method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler);
-    method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long);
-    method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setJournalMode(java.lang.String);
-    method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int);
-    method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
-    method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setSynchronousMode(java.lang.String);
+    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder addOpenFlags(int);
+    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams build();
+    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int);
+    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
+    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(@Nullable android.database.DatabaseErrorHandler);
+    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(@IntRange(from=0) long);
+    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setJournalMode(@NonNull String);
+    method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(@IntRange(from=0) int, @IntRange(from=0) int);
+    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
+    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setSynchronousMode(@NonNull String);
   }
 
   public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteDatabaseCorruptException();
-    ctor public SQLiteDatabaseCorruptException(java.lang.String);
+    ctor public SQLiteDatabaseCorruptException(String);
   }
 
   public class SQLiteDatabaseLockedException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteDatabaseLockedException();
-    ctor public SQLiteDatabaseLockedException(java.lang.String);
+    ctor public SQLiteDatabaseLockedException(String);
   }
 
   public class SQLiteDatatypeMismatchException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteDatatypeMismatchException();
-    ctor public SQLiteDatatypeMismatchException(java.lang.String);
+    ctor public SQLiteDatatypeMismatchException(String);
   }
 
   public class SQLiteDiskIOException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteDiskIOException();
-    ctor public SQLiteDiskIOException(java.lang.String);
+    ctor public SQLiteDiskIOException(String);
   }
 
   public class SQLiteDoneException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteDoneException();
-    ctor public SQLiteDoneException(java.lang.String);
+    ctor public SQLiteDoneException(String);
   }
 
   public class SQLiteException extends android.database.SQLException {
     ctor public SQLiteException();
-    ctor public SQLiteException(java.lang.String);
-    ctor public SQLiteException(java.lang.String, java.lang.Throwable);
+    ctor public SQLiteException(String);
+    ctor public SQLiteException(String, Throwable);
   }
 
   public class SQLiteFullException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteFullException();
-    ctor public SQLiteFullException(java.lang.String);
+    ctor public SQLiteFullException(String);
   }
 
   public class SQLiteMisuseException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteMisuseException();
-    ctor public SQLiteMisuseException(java.lang.String);
+    ctor public SQLiteMisuseException(String);
   }
 
   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);
-    method public synchronized void close();
-    method public java.lang.String getDatabaseName();
+    ctor public SQLiteOpenHelper(@Nullable android.content.Context, @Nullable String, @Nullable android.database.sqlite.SQLiteDatabase.CursorFactory, int);
+    ctor public SQLiteOpenHelper(@Nullable android.content.Context, @Nullable String, @Nullable android.database.sqlite.SQLiteDatabase.CursorFactory, int, @Nullable android.database.DatabaseErrorHandler);
+    ctor public SQLiteOpenHelper(@Nullable android.content.Context, @Nullable String, int, @NonNull android.database.sqlite.SQLiteDatabase.OpenParams);
+    method public void close();
+    method public String getDatabaseName();
     method public android.database.sqlite.SQLiteDatabase getReadableDatabase();
     method public android.database.sqlite.SQLiteDatabase getWritableDatabase();
     method public void onConfigure(android.database.sqlite.SQLiteDatabase);
@@ -12957,26 +13013,26 @@
     method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int);
     method public void onOpen(android.database.sqlite.SQLiteDatabase);
     method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
-    method public void setIdleConnectionTimeout(long);
-    method public void setLookasideConfig(int, int);
-    method public void setOpenParams(android.database.sqlite.SQLiteDatabase.OpenParams);
+    method public void setIdleConnectionTimeout(@IntRange(from=0) long);
+    method public void setLookasideConfig(@IntRange(from=0) int, @IntRange(from=0) int);
+    method public void setOpenParams(@NonNull android.database.sqlite.SQLiteDatabase.OpenParams);
     method public void setWriteAheadLoggingEnabled(boolean);
   }
 
   public class SQLiteOutOfMemoryException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteOutOfMemoryException();
-    ctor public SQLiteOutOfMemoryException(java.lang.String);
+    ctor public SQLiteOutOfMemoryException(String);
   }
 
   public abstract class SQLiteProgram extends android.database.sqlite.SQLiteClosable {
-    method public void bindAllArgsAsStrings(java.lang.String[]);
+    method public void bindAllArgsAsStrings(String[]);
     method public void bindBlob(int, byte[]);
     method public void bindDouble(int, double);
     method public void bindLong(int, long);
     method public void bindNull(int);
-    method public void bindString(int, java.lang.String);
+    method public void bindString(int, String);
     method public void clearBindings();
-    method public final deprecated int getUniqueId();
+    method @Deprecated public final int getUniqueId();
     method protected void onAllReferencesReleased();
   }
 
@@ -12985,32 +13041,32 @@
 
   public class SQLiteQueryBuilder {
     ctor public SQLiteQueryBuilder();
-    method public static void appendColumns(java.lang.StringBuilder, java.lang.String[]);
-    method public void appendWhere(java.lang.CharSequence);
-    method public void appendWhereEscapeString(java.lang.String);
-    method public void appendWhereStandalone(java.lang.CharSequence);
-    method public java.lang.String buildQuery(java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public deprecated java.lang.String buildQuery(java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public static java.lang.String buildQueryString(boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public java.lang.String buildUnionQuery(java.lang.String[], java.lang.String, java.lang.String);
-    method public java.lang.String buildUnionSubQuery(java.lang.String, java.lang.String[], java.util.Set<java.lang.String>, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public deprecated java.lang.String buildUnionSubQuery(java.lang.String, java.lang.String[], java.util.Set<java.lang.String>, int, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, java.lang.String);
-    method public int delete(android.database.sqlite.SQLiteDatabase, java.lang.String, java.lang.String[]);
-    method public java.lang.String getTables();
-    method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String);
-    method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.os.CancellationSignal);
+    method public static void appendColumns(StringBuilder, String[]);
+    method public void appendWhere(@NonNull CharSequence);
+    method public void appendWhereEscapeString(@NonNull String);
+    method public void appendWhereStandalone(@NonNull CharSequence);
+    method public String buildQuery(String[], String, String, String, String, String);
+    method @Deprecated public String buildQuery(String[], String, String[], String, String, String, String);
+    method public static String buildQueryString(boolean, String, String[], String, String, String, String, String);
+    method public String buildUnionQuery(String[], String, String);
+    method public String buildUnionSubQuery(String, String[], java.util.Set<java.lang.String>, int, String, String, String, String);
+    method @Deprecated public String buildUnionSubQuery(String, String[], java.util.Set<java.lang.String>, int, String, String, String[], String, String);
+    method public int delete(@NonNull android.database.sqlite.SQLiteDatabase, @Nullable String, @Nullable String[]);
+    method public String getTables();
+    method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, String[], String, String[], String, String, String);
+    method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, String[], String, String[], String, String, String, String);
+    method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, String[], String, String[], String, String, String, String, android.os.CancellationSignal);
     method public void setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
     method public void setDistinct(boolean);
-    method public void setProjectionMap(java.util.Map<java.lang.String, java.lang.String>);
+    method public void setProjectionMap(java.util.Map<java.lang.String,java.lang.String>);
     method public void setStrict(boolean);
-    method public void setTables(java.lang.String);
-    method public int update(android.database.sqlite.SQLiteDatabase, android.content.ContentValues, java.lang.String, java.lang.String[]);
+    method public void setTables(String);
+    method public int update(@NonNull android.database.sqlite.SQLiteDatabase, @NonNull android.content.ContentValues, @Nullable String, @Nullable String[]);
   }
 
   public class SQLiteReadOnlyDatabaseException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteReadOnlyDatabaseException();
-    ctor public SQLiteReadOnlyDatabaseException(java.lang.String);
+    ctor public SQLiteReadOnlyDatabaseException(String);
   }
 
   public final class SQLiteStatement extends android.database.sqlite.SQLiteProgram {
@@ -13019,18 +13075,18 @@
     method public int executeUpdateDelete();
     method public android.os.ParcelFileDescriptor simpleQueryForBlobFileDescriptor();
     method public long simpleQueryForLong();
-    method public java.lang.String simpleQueryForString();
+    method public String simpleQueryForString();
   }
 
   public class SQLiteTableLockedException extends android.database.sqlite.SQLiteException {
     ctor public SQLiteTableLockedException();
-    ctor public SQLiteTableLockedException(java.lang.String);
+    ctor public SQLiteTableLockedException(String);
   }
 
-  public abstract interface SQLiteTransactionListener {
-    method public abstract void onBegin();
-    method public abstract void onCommit();
-    method public abstract void onRollback();
+  public interface SQLiteTransactionListener {
+    method public void onBegin();
+    method public void onCommit();
+    method public void onRollback();
   }
 
 }
@@ -13048,8 +13104,8 @@
   }
 
   public class DrmErrorEvent extends android.drm.DrmEvent {
-    ctor public DrmErrorEvent(int, int, java.lang.String);
-    ctor public DrmErrorEvent(int, int, java.lang.String, java.util.HashMap<java.lang.String, java.lang.Object>);
+    ctor public DrmErrorEvent(int, int, String);
+    ctor public DrmErrorEvent(int, int, String, java.util.HashMap<java.lang.String,java.lang.Object>);
     field public static final int TYPE_ACQUIRE_DRM_INFO_FAILED = 2008; // 0x7d8
     field public static final int TYPE_NOT_SUPPORTED = 2003; // 0x7d3
     field public static final int TYPE_NO_INTERNET_CONNECTION = 2005; // 0x7d5
@@ -13061,33 +13117,33 @@
   }
 
   public class DrmEvent {
-    ctor protected DrmEvent(int, int, java.lang.String, java.util.HashMap<java.lang.String, java.lang.Object>);
-    ctor protected DrmEvent(int, int, java.lang.String);
-    method public java.lang.Object getAttribute(java.lang.String);
-    method public java.lang.String getMessage();
+    ctor protected DrmEvent(int, int, String, java.util.HashMap<java.lang.String,java.lang.Object>);
+    ctor protected DrmEvent(int, int, String);
+    method public Object getAttribute(String);
+    method public String getMessage();
     method public int getType();
     method public int getUniqueId();
-    field public static final java.lang.String DRM_INFO_OBJECT = "drm_info_object";
-    field public static final java.lang.String DRM_INFO_STATUS_OBJECT = "drm_info_status_object";
+    field public static final String DRM_INFO_OBJECT = "drm_info_object";
+    field public static final String DRM_INFO_STATUS_OBJECT = "drm_info_status_object";
     field public static final int TYPE_ALL_RIGHTS_REMOVED = 1001; // 0x3e9
     field public static final int TYPE_DRM_INFO_PROCESSED = 1002; // 0x3ea
   }
 
   public class DrmInfo {
-    ctor public DrmInfo(int, byte[], java.lang.String);
-    ctor public DrmInfo(int, java.lang.String, java.lang.String);
-    method public java.lang.Object get(java.lang.String);
+    ctor public DrmInfo(int, byte[], String);
+    ctor public DrmInfo(int, String, String);
+    method public Object get(String);
     method public byte[] getData();
     method public int getInfoType();
-    method public java.lang.String getMimeType();
+    method public String getMimeType();
     method public java.util.Iterator<java.lang.Object> iterator();
     method public java.util.Iterator<java.lang.String> keyIterator();
-    method public void put(java.lang.String, java.lang.Object);
+    method public void put(String, Object);
   }
 
   public class DrmInfoEvent extends android.drm.DrmEvent {
-    ctor public DrmInfoEvent(int, int, java.lang.String);
-    ctor public DrmInfoEvent(int, int, java.lang.String, java.util.HashMap<java.lang.String, java.lang.Object>);
+    ctor public DrmInfoEvent(int, int, String);
+    ctor public DrmInfoEvent(int, int, String, java.util.HashMap<java.lang.String,java.lang.Object>);
     field public static final int TYPE_ACCOUNT_ALREADY_REGISTERED = 5; // 0x5
     field public static final int TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT = 1; // 0x1
     field public static final int TYPE_REMOVE_RIGHTS = 2; // 0x2
@@ -13097,15 +13153,15 @@
   }
 
   public class DrmInfoRequest {
-    ctor public DrmInfoRequest(int, java.lang.String);
-    method public java.lang.Object get(java.lang.String);
+    ctor public DrmInfoRequest(int, String);
+    method public Object get(String);
     method public int getInfoType();
-    method public java.lang.String getMimeType();
+    method public String getMimeType();
     method public java.util.Iterator<java.lang.Object> iterator();
     method public java.util.Iterator<java.lang.String> keyIterator();
-    method public void put(java.lang.String, java.lang.Object);
-    field public static final java.lang.String ACCOUNT_ID = "account_id";
-    field public static final java.lang.String SUBSCRIPTION_ID = "subscription_id";
+    method public void put(String, Object);
+    field public static final String ACCOUNT_ID = "account_id";
+    field public static final String SUBSCRIPTION_ID = "subscription_id";
     field public static final int TYPE_REGISTRATION_INFO = 1; // 0x1
     field public static final int TYPE_RIGHTS_ACQUISITION_INFO = 3; // 0x3
     field public static final int TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO = 4; // 0x4
@@ -13113,12 +13169,12 @@
   }
 
   public class DrmInfoStatus {
-    ctor public DrmInfoStatus(int, int, android.drm.ProcessedData, java.lang.String);
+    ctor public DrmInfoStatus(int, int, android.drm.ProcessedData, String);
     field public static final int STATUS_ERROR = 2; // 0x2
     field public static final int STATUS_OK = 1; // 0x1
     field public final android.drm.ProcessedData data;
     field public final int infoType;
-    field public final java.lang.String mimeType;
+    field public final String mimeType;
     field public final int statusCode;
   }
 
@@ -13126,68 +13182,68 @@
     ctor public DrmManagerClient(android.content.Context);
     method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
     method public int acquireRights(android.drm.DrmInfoRequest);
-    method public boolean canHandle(java.lang.String, java.lang.String);
-    method public boolean canHandle(android.net.Uri, java.lang.String);
-    method public int checkRightsStatus(java.lang.String);
+    method public boolean canHandle(String, String);
+    method public boolean canHandle(android.net.Uri, String);
+    method public int checkRightsStatus(String);
     method public int checkRightsStatus(android.net.Uri);
-    method public int checkRightsStatus(java.lang.String, int);
+    method public int checkRightsStatus(String, int);
     method public int checkRightsStatus(android.net.Uri, int);
     method public void close();
     method public android.drm.DrmConvertedStatus closeConvertSession(int);
     method public android.drm.DrmConvertedStatus convertData(int, byte[]);
-    method public java.lang.String[] getAvailableDrmEngines();
-    method public android.content.ContentValues getConstraints(java.lang.String, int);
+    method public String[] getAvailableDrmEngines();
+    method public android.content.ContentValues getConstraints(String, int);
     method public android.content.ContentValues getConstraints(android.net.Uri, int);
-    method public int getDrmObjectType(java.lang.String, java.lang.String);
-    method public int getDrmObjectType(android.net.Uri, java.lang.String);
-    method public android.content.ContentValues getMetadata(java.lang.String);
+    method public int getDrmObjectType(String, String);
+    method public int getDrmObjectType(android.net.Uri, String);
+    method public android.content.ContentValues getMetadata(String);
     method public android.content.ContentValues getMetadata(android.net.Uri);
-    method public java.lang.String getOriginalMimeType(java.lang.String);
-    method public java.lang.String getOriginalMimeType(android.net.Uri);
-    method public int openConvertSession(java.lang.String);
+    method public String getOriginalMimeType(String);
+    method public String getOriginalMimeType(android.net.Uri);
+    method public int openConvertSession(String);
     method public int processDrmInfo(android.drm.DrmInfo);
-    method public deprecated void release();
+    method @Deprecated public void release();
     method public int removeAllRights();
-    method public int removeRights(java.lang.String);
+    method public int removeRights(String);
     method public int removeRights(android.net.Uri);
-    method public int saveRights(android.drm.DrmRights, java.lang.String, java.lang.String) throws java.io.IOException;
-    method public synchronized void setOnErrorListener(android.drm.DrmManagerClient.OnErrorListener);
-    method public synchronized void setOnEventListener(android.drm.DrmManagerClient.OnEventListener);
-    method public synchronized void setOnInfoListener(android.drm.DrmManagerClient.OnInfoListener);
+    method public int saveRights(android.drm.DrmRights, String, String) throws java.io.IOException;
+    method public void setOnErrorListener(android.drm.DrmManagerClient.OnErrorListener);
+    method public void setOnEventListener(android.drm.DrmManagerClient.OnEventListener);
+    method public void setOnInfoListener(android.drm.DrmManagerClient.OnInfoListener);
     field public static final int ERROR_NONE = 0; // 0x0
     field public static final int ERROR_UNKNOWN = -2000; // 0xfffff830
   }
 
-  public static abstract interface DrmManagerClient.OnErrorListener {
-    method public abstract void onError(android.drm.DrmManagerClient, android.drm.DrmErrorEvent);
+  public static interface DrmManagerClient.OnErrorListener {
+    method public void onError(android.drm.DrmManagerClient, android.drm.DrmErrorEvent);
   }
 
-  public static abstract interface DrmManagerClient.OnEventListener {
-    method public abstract void onEvent(android.drm.DrmManagerClient, android.drm.DrmEvent);
+  public static interface DrmManagerClient.OnEventListener {
+    method public void onEvent(android.drm.DrmManagerClient, android.drm.DrmEvent);
   }
 
-  public static abstract interface DrmManagerClient.OnInfoListener {
-    method public abstract void onInfo(android.drm.DrmManagerClient, android.drm.DrmInfoEvent);
+  public static interface DrmManagerClient.OnInfoListener {
+    method public void onInfo(android.drm.DrmManagerClient, android.drm.DrmInfoEvent);
   }
 
   public class DrmRights {
-    ctor public DrmRights(java.lang.String, java.lang.String);
-    ctor public DrmRights(java.lang.String, java.lang.String, java.lang.String);
-    ctor public DrmRights(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    ctor public DrmRights(java.io.File, java.lang.String);
-    ctor public DrmRights(android.drm.ProcessedData, java.lang.String);
-    method public java.lang.String getAccountId();
+    ctor public DrmRights(String, String);
+    ctor public DrmRights(String, String, String);
+    ctor public DrmRights(String, String, String, String);
+    ctor public DrmRights(java.io.File, String);
+    ctor public DrmRights(android.drm.ProcessedData, String);
+    method public String getAccountId();
     method public byte[] getData();
-    method public java.lang.String getMimeType();
-    method public java.lang.String getSubscriptionId();
+    method public String getMimeType();
+    method public String getSubscriptionId();
   }
 
   public class DrmStore {
-    ctor public deprecated DrmStore();
+    ctor @Deprecated public DrmStore();
   }
 
   public static class DrmStore.Action {
-    ctor public deprecated DrmStore.Action();
+    ctor @Deprecated public DrmStore.Action();
     field public static final int DEFAULT = 0; // 0x0
     field public static final int DISPLAY = 7; // 0x7
     field public static final int EXECUTE = 6; // 0x6
@@ -13198,17 +13254,17 @@
     field public static final int TRANSFER = 3; // 0x3
   }
 
-  public static abstract interface DrmStore.ConstraintsColumns {
-    field public static final java.lang.String EXTENDED_METADATA = "extended_metadata";
-    field public static final java.lang.String LICENSE_AVAILABLE_TIME = "license_available_time";
-    field public static final java.lang.String LICENSE_EXPIRY_TIME = "license_expiry_time";
-    field public static final java.lang.String LICENSE_START_TIME = "license_start_time";
-    field public static final java.lang.String MAX_REPEAT_COUNT = "max_repeat_count";
-    field public static final java.lang.String REMAINING_REPEAT_COUNT = "remaining_repeat_count";
+  public static interface DrmStore.ConstraintsColumns {
+    field public static final String EXTENDED_METADATA = "extended_metadata";
+    field public static final String LICENSE_AVAILABLE_TIME = "license_available_time";
+    field public static final String LICENSE_EXPIRY_TIME = "license_expiry_time";
+    field public static final String LICENSE_START_TIME = "license_start_time";
+    field public static final String MAX_REPEAT_COUNT = "max_repeat_count";
+    field public static final String REMAINING_REPEAT_COUNT = "remaining_repeat_count";
   }
 
   public static class DrmStore.DrmObjectType {
-    ctor public deprecated DrmStore.DrmObjectType();
+    ctor @Deprecated public DrmStore.DrmObjectType();
     field public static final int CONTENT = 1; // 0x1
     field public static final int RIGHTS_OBJECT = 2; // 0x2
     field public static final int TRIGGER_OBJECT = 3; // 0x3
@@ -13216,7 +13272,7 @@
   }
 
   public static class DrmStore.Playback {
-    ctor public deprecated DrmStore.Playback();
+    ctor @Deprecated public DrmStore.Playback();
     field public static final int PAUSE = 2; // 0x2
     field public static final int RESUME = 3; // 0x3
     field public static final int START = 0; // 0x0
@@ -13224,7 +13280,7 @@
   }
 
   public static class DrmStore.RightsStatus {
-    ctor public deprecated DrmStore.RightsStatus();
+    ctor @Deprecated public DrmStore.RightsStatus();
     field public static final int RIGHTS_EXPIRED = 2; // 0x2
     field public static final int RIGHTS_INVALID = 1; // 0x1
     field public static final int RIGHTS_NOT_ACQUIRED = 3; // 0x3
@@ -13233,13 +13289,13 @@
 
   public class DrmSupportInfo {
     ctor public DrmSupportInfo();
-    method public void addFileSuffix(java.lang.String);
-    method public void addMimeType(java.lang.String);
-    method public deprecated java.lang.String getDescriprition();
-    method public java.lang.String getDescription();
+    method public void addFileSuffix(String);
+    method public void addMimeType(String);
+    method @Deprecated public String getDescriprition();
+    method public String getDescription();
     method public java.util.Iterator<java.lang.String> getFileSuffixIterator();
     method public java.util.Iterator<java.lang.String> getMimeTypeIterator();
-    method public void setDescription(java.lang.String);
+    method public void setDescription(String);
   }
 
   public class DrmUtils {
@@ -13248,15 +13304,15 @@
   }
 
   public static class DrmUtils.ExtendedMetadataParser {
-    method public java.lang.String get(java.lang.String);
+    method public String get(String);
     method public java.util.Iterator<java.lang.String> iterator();
     method public java.util.Iterator<java.lang.String> keyIterator();
   }
 
   public class ProcessedData {
-    method public java.lang.String getAccountId();
+    method public String getAccountId();
     method public byte[] getData();
-    method public java.lang.String getSubscriptionId();
+    method public String getSubscriptionId();
   }
 
 }
@@ -13266,7 +13322,7 @@
   public class Gesture implements android.os.Parcelable {
     ctor public Gesture();
     method public void addStroke(android.gesture.GestureStroke);
-    method public java.lang.Object clone();
+    method public Object clone();
     method public int describeContents();
     method public android.graphics.RectF getBoundingBox();
     method public long getID();
@@ -13284,24 +13340,24 @@
   }
 
   public final class GestureLibraries {
-    method public static android.gesture.GestureLibrary fromFile(java.lang.String);
+    method public static android.gesture.GestureLibrary fromFile(String);
     method public static android.gesture.GestureLibrary fromFile(java.io.File);
-    method public static android.gesture.GestureLibrary fromPrivateFile(android.content.Context, java.lang.String);
-    method public static android.gesture.GestureLibrary fromRawResource(android.content.Context, int);
+    method public static android.gesture.GestureLibrary fromPrivateFile(android.content.Context, String);
+    method public static android.gesture.GestureLibrary fromRawResource(android.content.Context, @RawRes int);
   }
 
   public abstract class GestureLibrary {
     ctor protected GestureLibrary();
-    method public void addGesture(java.lang.String, android.gesture.Gesture);
+    method public void addGesture(String, android.gesture.Gesture);
     method public java.util.Set<java.lang.String> getGestureEntries();
-    method public java.util.ArrayList<android.gesture.Gesture> getGestures(java.lang.String);
+    method public java.util.ArrayList<android.gesture.Gesture> getGestures(String);
     method public int getOrientationStyle();
     method public int getSequenceType();
     method public boolean isReadOnly();
     method public abstract boolean load();
     method public java.util.ArrayList<android.gesture.Prediction> recognize(android.gesture.Gesture);
-    method public void removeEntry(java.lang.String);
-    method public void removeGesture(java.lang.String, android.gesture.Gesture);
+    method public void removeEntry(String);
+    method public void removeGesture(String, android.gesture.Gesture);
     method public abstract boolean save();
     method public void setOrientationStyle(int);
     method public void setSequenceType(int);
@@ -13322,7 +13378,7 @@
     method public java.util.ArrayList<android.gesture.GesturePoint> getCurrentStroke();
     method public long getFadeOffset();
     method public android.gesture.Gesture getGesture();
-    method public int getGestureColor();
+    method @ColorInt public int getGestureColor();
     method public android.graphics.Path getGesturePath();
     method public android.graphics.Path getGesturePath(android.graphics.Path);
     method public float getGestureStrokeAngleThreshold();
@@ -13331,7 +13387,7 @@
     method public int getGestureStrokeType();
     method public float getGestureStrokeWidth();
     method public int getOrientation();
-    method public int getUncertainGestureColor();
+    method @ColorInt public int getUncertainGestureColor();
     method public boolean isEventsInterceptionEnabled();
     method public boolean isFadeEnabled();
     method public boolean isGestureVisible();
@@ -13346,7 +13402,7 @@
     method public void setFadeEnabled(boolean);
     method public void setFadeOffset(long);
     method public void setGesture(android.gesture.Gesture);
-    method public void setGestureColor(int);
+    method public void setGestureColor(@ColorInt int);
     method public void setGestureStrokeAngleThreshold(float);
     method public void setGestureStrokeLengthThreshold(float);
     method public void setGestureStrokeSquarenessTreshold(float);
@@ -13354,32 +13410,32 @@
     method public void setGestureStrokeWidth(float);
     method public void setGestureVisible(boolean);
     method public void setOrientation(int);
-    method public void setUncertainGestureColor(int);
+    method public void setUncertainGestureColor(@ColorInt int);
     field public static final int GESTURE_STROKE_TYPE_MULTIPLE = 1; // 0x1
     field public static final int GESTURE_STROKE_TYPE_SINGLE = 0; // 0x0
     field public static final int ORIENTATION_HORIZONTAL = 0; // 0x0
     field public static final int ORIENTATION_VERTICAL = 1; // 0x1
   }
 
-  public static abstract interface GestureOverlayView.OnGestureListener {
-    method public abstract void onGesture(android.gesture.GestureOverlayView, android.view.MotionEvent);
-    method public abstract void onGestureCancelled(android.gesture.GestureOverlayView, android.view.MotionEvent);
-    method public abstract void onGestureEnded(android.gesture.GestureOverlayView, android.view.MotionEvent);
-    method public abstract void onGestureStarted(android.gesture.GestureOverlayView, android.view.MotionEvent);
+  public static interface GestureOverlayView.OnGestureListener {
+    method public void onGesture(android.gesture.GestureOverlayView, android.view.MotionEvent);
+    method public void onGestureCancelled(android.gesture.GestureOverlayView, android.view.MotionEvent);
+    method public void onGestureEnded(android.gesture.GestureOverlayView, android.view.MotionEvent);
+    method public void onGestureStarted(android.gesture.GestureOverlayView, android.view.MotionEvent);
   }
 
-  public static abstract interface GestureOverlayView.OnGesturePerformedListener {
-    method public abstract void onGesturePerformed(android.gesture.GestureOverlayView, android.gesture.Gesture);
+  public static interface GestureOverlayView.OnGesturePerformedListener {
+    method public void onGesturePerformed(android.gesture.GestureOverlayView, android.gesture.Gesture);
   }
 
-  public static abstract interface GestureOverlayView.OnGesturingListener {
-    method public abstract void onGesturingEnded(android.gesture.GestureOverlayView);
-    method public abstract void onGesturingStarted(android.gesture.GestureOverlayView);
+  public static interface GestureOverlayView.OnGesturingListener {
+    method public void onGesturingEnded(android.gesture.GestureOverlayView);
+    method public void onGesturingStarted(android.gesture.GestureOverlayView);
   }
 
   public class GesturePoint {
     ctor public GesturePoint(float, float, long);
-    method public java.lang.Object clone();
+    method public Object clone();
     field public final long timestamp;
     field public final float x;
     field public final float y;
@@ -13387,17 +13443,17 @@
 
   public class GestureStore {
     ctor public GestureStore();
-    method public void addGesture(java.lang.String, android.gesture.Gesture);
+    method public void addGesture(String, android.gesture.Gesture);
     method public java.util.Set<java.lang.String> getGestureEntries();
-    method public java.util.ArrayList<android.gesture.Gesture> getGestures(java.lang.String);
+    method public java.util.ArrayList<android.gesture.Gesture> getGestures(String);
     method public int getOrientationStyle();
     method public int getSequenceType();
     method public boolean hasChanged();
     method public void load(java.io.InputStream) throws java.io.IOException;
     method public void load(java.io.InputStream, boolean) throws java.io.IOException;
     method public java.util.ArrayList<android.gesture.Prediction> recognize(android.gesture.Gesture);
-    method public void removeEntry(java.lang.String);
-    method public void removeGesture(java.lang.String, android.gesture.Gesture);
+    method public void removeEntry(String);
+    method public void removeGesture(String, android.gesture.Gesture);
     method public void save(java.io.OutputStream) throws java.io.IOException;
     method public void save(java.io.OutputStream, boolean) throws java.io.IOException;
     method public void setOrientationStyle(int);
@@ -13411,7 +13467,7 @@
   public class GestureStroke {
     ctor public GestureStroke(java.util.ArrayList<android.gesture.GesturePoint>);
     method public void clearPath();
-    method public java.lang.Object clone();
+    method public Object clone();
     method public android.gesture.OrientedBoundingBox computeOrientedBoundingBox();
     method public android.graphics.Path getPath();
     method public android.graphics.Path toPath(float, float, int);
@@ -13438,7 +13494,7 @@
   }
 
   public class Prediction {
-    field public final java.lang.String name;
+    field public final String name;
     field public double score;
   }
 
@@ -13447,40 +13503,40 @@
 package android.graphics {
 
   public final class Bitmap implements android.os.Parcelable {
-    method public boolean compress(android.graphics.Bitmap.CompressFormat, int, java.io.OutputStream);
+    method @WorkerThread public boolean compress(android.graphics.Bitmap.CompressFormat, int, java.io.OutputStream);
     method public android.graphics.Bitmap copy(android.graphics.Bitmap.Config, boolean);
     method public void copyPixelsFromBuffer(java.nio.Buffer);
     method public void copyPixelsToBuffer(java.nio.Buffer);
-    method public static android.graphics.Bitmap createBitmap(android.graphics.Bitmap);
-    method public static android.graphics.Bitmap createBitmap(android.graphics.Bitmap, int, int, int, int);
-    method public static android.graphics.Bitmap createBitmap(android.graphics.Bitmap, int, int, int, int, android.graphics.Matrix, boolean);
-    method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config);
-    method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config);
-    method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean);
-    method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace);
-    method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean);
-    method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace);
-    method public static android.graphics.Bitmap createBitmap(int[], int, int, int, int, android.graphics.Bitmap.Config);
-    method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, int, int, android.graphics.Bitmap.Config);
-    method public static android.graphics.Bitmap createBitmap(int[], int, int, android.graphics.Bitmap.Config);
-    method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, android.graphics.Bitmap.Config);
-    method public static android.graphics.Bitmap createBitmap(android.graphics.Picture);
-    method public static android.graphics.Bitmap createBitmap(android.graphics.Picture, int, int, android.graphics.Bitmap.Config);
-    method public static android.graphics.Bitmap createScaledBitmap(android.graphics.Bitmap, int, int, boolean);
+    method public static android.graphics.Bitmap createBitmap(@NonNull android.graphics.Bitmap);
+    method public static android.graphics.Bitmap createBitmap(@NonNull android.graphics.Bitmap, int, int, int, int);
+    method public static android.graphics.Bitmap createBitmap(@NonNull android.graphics.Bitmap, int, int, int, int, @Nullable android.graphics.Matrix, boolean);
+    method public static android.graphics.Bitmap createBitmap(int, int, @NonNull android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(@Nullable android.util.DisplayMetrics, int, int, @NonNull android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(int, int, @NonNull android.graphics.Bitmap.Config, boolean);
+    method public static android.graphics.Bitmap createBitmap(int, int, @NonNull android.graphics.Bitmap.Config, boolean, @NonNull android.graphics.ColorSpace);
+    method public static android.graphics.Bitmap createBitmap(@Nullable android.util.DisplayMetrics, int, int, @NonNull android.graphics.Bitmap.Config, boolean);
+    method public static android.graphics.Bitmap createBitmap(@Nullable android.util.DisplayMetrics, int, int, @NonNull android.graphics.Bitmap.Config, boolean, @NonNull android.graphics.ColorSpace);
+    method public static android.graphics.Bitmap createBitmap(@NonNull @ColorInt int[], int, int, int, int, @NonNull android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(@NonNull android.util.DisplayMetrics, @NonNull @ColorInt int[], int, int, int, int, @NonNull android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(@NonNull @ColorInt int[], int, int, android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(@Nullable android.util.DisplayMetrics, @NonNull @ColorInt int[], int, int, @NonNull android.graphics.Bitmap.Config);
+    method @NonNull public static android.graphics.Bitmap createBitmap(@NonNull android.graphics.Picture);
+    method @NonNull public static android.graphics.Bitmap createBitmap(@NonNull android.graphics.Picture, int, int, @NonNull android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createScaledBitmap(@NonNull android.graphics.Bitmap, int, int, boolean);
     method public int describeContents();
-    method public void eraseColor(int);
-    method public android.graphics.Bitmap extractAlpha();
-    method public android.graphics.Bitmap extractAlpha(android.graphics.Paint, int[]);
+    method public void eraseColor(@ColorInt int);
+    method @CheckResult public android.graphics.Bitmap extractAlpha();
+    method @CheckResult public android.graphics.Bitmap extractAlpha(android.graphics.Paint, int[]);
     method public int getAllocationByteCount();
     method public int getByteCount();
-    method public android.graphics.ColorSpace getColorSpace();
+    method @Nullable public android.graphics.ColorSpace getColorSpace();
     method public android.graphics.Bitmap.Config getConfig();
     method public int getDensity();
     method public int getGenerationId();
     method public int getHeight();
     method public byte[] getNinePatchChunk();
-    method public int getPixel(int, int);
-    method public void getPixels(int[], int, int, int, int, int, int);
+    method @ColorInt public int getPixel(int, int);
+    method public void getPixels(@ColorInt int[], int, int, int, int, int, int);
     method public int getRowBytes();
     method public int getScaledHeight(android.graphics.Canvas);
     method public int getScaledHeight(android.util.DisplayMetrics);
@@ -13503,29 +13559,25 @@
     method public void setHasAlpha(boolean);
     method public void setHasMipMap(boolean);
     method public void setHeight(int);
-    method public void setPixel(int, int, int);
-    method public void setPixels(int[], int, int, int, int, int, int);
+    method public void setPixel(int, int, @ColorInt int);
+    method public void setPixels(@ColorInt int[], int, int, int, int, int, int);
     method public void setPremultiplied(boolean);
     method public void setWidth(int);
-    method public static android.graphics.Bitmap wrapHardwareBuffer(android.hardware.HardwareBuffer, android.graphics.ColorSpace);
+    method @Nullable public static android.graphics.Bitmap wrapHardwareBuffer(@NonNull android.hardware.HardwareBuffer, @Nullable android.graphics.ColorSpace);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.graphics.Bitmap> CREATOR;
     field public static final int DENSITY_NONE = 0; // 0x0
   }
 
-  public static final class Bitmap.CompressFormat extends java.lang.Enum {
-    method public static android.graphics.Bitmap.CompressFormat valueOf(java.lang.String);
-    method public static final android.graphics.Bitmap.CompressFormat[] values();
+  public enum Bitmap.CompressFormat {
     enum_constant public static final android.graphics.Bitmap.CompressFormat JPEG;
     enum_constant public static final android.graphics.Bitmap.CompressFormat PNG;
     enum_constant public static final android.graphics.Bitmap.CompressFormat WEBP;
   }
 
-  public static final class Bitmap.Config extends java.lang.Enum {
-    method public static android.graphics.Bitmap.Config valueOf(java.lang.String);
-    method public static final android.graphics.Bitmap.Config[] values();
+  public enum Bitmap.Config {
     enum_constant public static final android.graphics.Bitmap.Config ALPHA_8;
-    enum_constant public static final deprecated android.graphics.Bitmap.Config ARGB_4444;
+    enum_constant @Deprecated public static final android.graphics.Bitmap.Config ARGB_4444;
     enum_constant public static final android.graphics.Bitmap.Config ARGB_8888;
     enum_constant public static final android.graphics.Bitmap.Config HARDWARE;
     enum_constant public static final android.graphics.Bitmap.Config RGBA_F16;
@@ -13536,41 +13588,41 @@
     ctor public BitmapFactory();
     method public static android.graphics.Bitmap decodeByteArray(byte[], int, int, android.graphics.BitmapFactory.Options);
     method public static android.graphics.Bitmap decodeByteArray(byte[], int, int);
-    method public static android.graphics.Bitmap decodeFile(java.lang.String, android.graphics.BitmapFactory.Options);
-    method public static android.graphics.Bitmap decodeFile(java.lang.String);
+    method public static android.graphics.Bitmap decodeFile(String, android.graphics.BitmapFactory.Options);
+    method public static android.graphics.Bitmap decodeFile(String);
     method public static android.graphics.Bitmap decodeFileDescriptor(java.io.FileDescriptor, android.graphics.Rect, android.graphics.BitmapFactory.Options);
     method public static android.graphics.Bitmap decodeFileDescriptor(java.io.FileDescriptor);
     method public static android.graphics.Bitmap decodeResource(android.content.res.Resources, int, android.graphics.BitmapFactory.Options);
     method public static android.graphics.Bitmap decodeResource(android.content.res.Resources, int);
-    method public static android.graphics.Bitmap decodeResourceStream(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, android.graphics.Rect, android.graphics.BitmapFactory.Options);
-    method public static android.graphics.Bitmap decodeStream(java.io.InputStream, android.graphics.Rect, android.graphics.BitmapFactory.Options);
+    method @Nullable public static android.graphics.Bitmap decodeResourceStream(@Nullable android.content.res.Resources, @Nullable android.util.TypedValue, @Nullable java.io.InputStream, @Nullable android.graphics.Rect, @Nullable android.graphics.BitmapFactory.Options);
+    method @Nullable public static android.graphics.Bitmap decodeStream(@Nullable java.io.InputStream, @Nullable android.graphics.Rect, @Nullable android.graphics.BitmapFactory.Options);
     method public static android.graphics.Bitmap decodeStream(java.io.InputStream);
   }
 
   public static class BitmapFactory.Options {
     ctor public BitmapFactory.Options();
-    method public deprecated void requestCancelDecode();
+    method @Deprecated public void requestCancelDecode();
     field public android.graphics.Bitmap inBitmap;
     field public int inDensity;
-    field public deprecated boolean inDither;
-    field public deprecated boolean inInputShareable;
+    field @Deprecated public boolean inDither;
+    field @Deprecated public boolean inInputShareable;
     field public boolean inJustDecodeBounds;
     field public boolean inMutable;
-    field public deprecated boolean inPreferQualityOverSpeed;
+    field @Deprecated public boolean inPreferQualityOverSpeed;
     field public android.graphics.ColorSpace inPreferredColorSpace;
     field public android.graphics.Bitmap.Config inPreferredConfig;
     field public boolean inPremultiplied;
-    field public deprecated boolean inPurgeable;
+    field @Deprecated public boolean inPurgeable;
     field public int inSampleSize;
     field public boolean inScaled;
     field public int inScreenDensity;
     field public int inTargetDensity;
     field public byte[] inTempStorage;
-    field public deprecated boolean mCancel;
+    field @Deprecated public boolean mCancel;
     field public android.graphics.ColorSpace outColorSpace;
     field public android.graphics.Bitmap.Config outConfig;
     field public int outHeight;
-    field public java.lang.String outMimeType;
+    field public String outMimeType;
     field public int outWidth;
   }
 
@@ -13582,17 +13634,15 @@
     method public static android.graphics.BitmapRegionDecoder newInstance(byte[], int, int, boolean) throws java.io.IOException;
     method public static android.graphics.BitmapRegionDecoder newInstance(java.io.FileDescriptor, boolean) throws java.io.IOException;
     method public static android.graphics.BitmapRegionDecoder newInstance(java.io.InputStream, boolean) throws java.io.IOException;
-    method public static android.graphics.BitmapRegionDecoder newInstance(java.lang.String, boolean) throws java.io.IOException;
+    method public static android.graphics.BitmapRegionDecoder newInstance(String, boolean) throws java.io.IOException;
     method public void recycle();
   }
 
   public class BitmapShader extends android.graphics.Shader {
-    ctor public BitmapShader(android.graphics.Bitmap, android.graphics.Shader.TileMode, android.graphics.Shader.TileMode);
+    ctor public BitmapShader(@NonNull android.graphics.Bitmap, @NonNull android.graphics.Shader.TileMode, @NonNull android.graphics.Shader.TileMode);
   }
 
-  public final class BlendMode extends java.lang.Enum {
-    method public static android.graphics.BlendMode valueOf(java.lang.String);
-    method public static final android.graphics.BlendMode[] values();
+  public enum BlendMode {
     enum_constant public static final android.graphics.BlendMode CLEAR;
     enum_constant public static final android.graphics.BlendMode COLOR;
     enum_constant public static final android.graphics.BlendMode COLOR_BURN;
@@ -13625,8 +13675,8 @@
   }
 
   public final class BlendModeColorFilter extends android.graphics.ColorFilter {
-    ctor public BlendModeColorFilter(int, android.graphics.BlendMode);
-    method public int getColor();
+    ctor public BlendModeColorFilter(@ColorInt int, @NonNull android.graphics.BlendMode);
+    method @ColorInt public int getColor();
     method public android.graphics.BlendMode getMode();
   }
 
@@ -13634,9 +13684,7 @@
     ctor public BlurMaskFilter(float, android.graphics.BlurMaskFilter.Blur);
   }
 
-  public static final class BlurMaskFilter.Blur extends java.lang.Enum {
-    method public static android.graphics.BlurMaskFilter.Blur valueOf(java.lang.String);
-    method public static final android.graphics.BlurMaskFilter.Blur[] values();
+  public enum BlurMaskFilter.Blur {
     enum_constant public static final android.graphics.BlurMaskFilter.Blur INNER;
     enum_constant public static final android.graphics.BlurMaskFilter.Blur NORMAL;
     enum_constant public static final android.graphics.BlurMaskFilter.Blur OUTER;
@@ -13663,199 +13711,196 @@
 
   public class Canvas {
     ctor public Canvas();
-    ctor public Canvas(android.graphics.Bitmap);
-    method public boolean clipOutPath(android.graphics.Path);
-    method public boolean clipOutRect(android.graphics.RectF);
-    method public boolean clipOutRect(android.graphics.Rect);
+    ctor public Canvas(@NonNull android.graphics.Bitmap);
+    method public boolean clipOutPath(@NonNull android.graphics.Path);
+    method public boolean clipOutRect(@NonNull android.graphics.RectF);
+    method public boolean clipOutRect(@NonNull android.graphics.Rect);
     method public boolean clipOutRect(float, float, float, float);
     method public boolean clipOutRect(int, int, int, int);
-    method public deprecated boolean clipPath(android.graphics.Path, android.graphics.Region.Op);
-    method public boolean clipPath(android.graphics.Path);
-    method public deprecated boolean clipRect(android.graphics.RectF, android.graphics.Region.Op);
-    method public deprecated boolean clipRect(android.graphics.Rect, android.graphics.Region.Op);
-    method public boolean clipRect(android.graphics.RectF);
-    method public boolean clipRect(android.graphics.Rect);
-    method public deprecated boolean clipRect(float, float, float, float, android.graphics.Region.Op);
+    method @Deprecated public boolean clipPath(@NonNull android.graphics.Path, @NonNull android.graphics.Region.Op);
+    method public boolean clipPath(@NonNull android.graphics.Path);
+    method @Deprecated public boolean clipRect(@NonNull android.graphics.RectF, @NonNull android.graphics.Region.Op);
+    method @Deprecated public boolean clipRect(@NonNull android.graphics.Rect, @NonNull android.graphics.Region.Op);
+    method public boolean clipRect(@NonNull android.graphics.RectF);
+    method public boolean clipRect(@NonNull android.graphics.Rect);
+    method @Deprecated public boolean clipRect(float, float, float, float, @NonNull android.graphics.Region.Op);
     method public boolean clipRect(float, float, float, float);
     method public boolean clipRect(int, int, int, int);
-    method public void concat(android.graphics.Matrix);
+    method public void concat(@Nullable android.graphics.Matrix);
     method public void disableZ();
     method public void drawARGB(int, int, int, int);
-    method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint);
-    method public void drawArc(float, float, float, float, float, float, boolean, android.graphics.Paint);
-    method public void drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint);
-    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint);
-    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint);
-    method public deprecated void drawBitmap(int[], int, int, float, float, int, int, boolean, android.graphics.Paint);
-    method public deprecated void drawBitmap(int[], int, int, int, int, int, int, boolean, android.graphics.Paint);
-    method public void drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint);
-    method public void drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint);
-    method public void drawCircle(float, float, float, android.graphics.Paint);
-    method public void drawColor(int);
-    method public deprecated void drawColor(int, android.graphics.PorterDuff.Mode);
-    method public void drawColor(int, android.graphics.BlendMode);
-    method public void drawDoubleRoundRect(android.graphics.RectF, float, float, android.graphics.RectF, float, float, android.graphics.Paint);
-    method public void drawDoubleRoundRect(android.graphics.RectF, float[], android.graphics.RectF, float[], android.graphics.Paint);
-    method public void drawLine(float, float, float, float, android.graphics.Paint);
-    method public void drawLines(float[], int, int, android.graphics.Paint);
-    method public void drawLines(float[], android.graphics.Paint);
-    method public void drawOval(android.graphics.RectF, android.graphics.Paint);
-    method public void drawOval(float, float, float, float, android.graphics.Paint);
-    method public void drawPaint(android.graphics.Paint);
-    method public void drawPath(android.graphics.Path, android.graphics.Paint);
-    method public void drawPicture(android.graphics.Picture);
-    method public void drawPicture(android.graphics.Picture, android.graphics.RectF);
-    method public void drawPicture(android.graphics.Picture, android.graphics.Rect);
-    method public void drawPoint(float, float, android.graphics.Paint);
-    method public void drawPoints(float[], int, int, android.graphics.Paint);
-    method public void drawPoints(float[], android.graphics.Paint);
-    method public deprecated void drawPosText(char[], int, int, float[], android.graphics.Paint);
-    method public deprecated void drawPosText(java.lang.String, float[], android.graphics.Paint);
+    method public void drawArc(@NonNull android.graphics.RectF, float, float, boolean, @NonNull android.graphics.Paint);
+    method public void drawArc(float, float, float, float, float, float, boolean, @NonNull android.graphics.Paint);
+    method public void drawBitmap(@NonNull android.graphics.Bitmap, float, float, @Nullable android.graphics.Paint);
+    method public void drawBitmap(@NonNull android.graphics.Bitmap, @Nullable android.graphics.Rect, @NonNull android.graphics.RectF, @Nullable android.graphics.Paint);
+    method public void drawBitmap(@NonNull android.graphics.Bitmap, @Nullable android.graphics.Rect, @NonNull android.graphics.Rect, @Nullable android.graphics.Paint);
+    method @Deprecated public void drawBitmap(@NonNull int[], int, int, float, float, int, int, boolean, @Nullable android.graphics.Paint);
+    method @Deprecated public void drawBitmap(@NonNull int[], int, int, int, int, int, int, boolean, @Nullable android.graphics.Paint);
+    method public void drawBitmap(@NonNull android.graphics.Bitmap, @NonNull android.graphics.Matrix, @Nullable android.graphics.Paint);
+    method public void drawBitmapMesh(@NonNull android.graphics.Bitmap, int, int, @NonNull float[], int, @Nullable int[], int, @Nullable android.graphics.Paint);
+    method public void drawCircle(float, float, float, @NonNull android.graphics.Paint);
+    method public void drawColor(@ColorInt int);
+    method @Deprecated public void drawColor(@ColorInt int, @NonNull android.graphics.PorterDuff.Mode);
+    method public void drawColor(@ColorInt int, @NonNull android.graphics.BlendMode);
+    method public void drawDoubleRoundRect(@NonNull android.graphics.RectF, float, float, @NonNull android.graphics.RectF, float, float, @NonNull android.graphics.Paint);
+    method public void drawDoubleRoundRect(@NonNull android.graphics.RectF, float[], @NonNull android.graphics.RectF, float[], @NonNull android.graphics.Paint);
+    method public void drawLine(float, float, float, float, @NonNull android.graphics.Paint);
+    method public void drawLines(@Size(multiple=4) @NonNull float[], int, int, @NonNull android.graphics.Paint);
+    method public void drawLines(@Size(multiple=4) @NonNull float[], @NonNull android.graphics.Paint);
+    method public void drawOval(@NonNull android.graphics.RectF, @NonNull android.graphics.Paint);
+    method public void drawOval(float, float, float, float, @NonNull android.graphics.Paint);
+    method public void drawPaint(@NonNull android.graphics.Paint);
+    method public void drawPath(@NonNull android.graphics.Path, @NonNull android.graphics.Paint);
+    method public void drawPicture(@NonNull android.graphics.Picture);
+    method public void drawPicture(@NonNull android.graphics.Picture, @NonNull android.graphics.RectF);
+    method public void drawPicture(@NonNull android.graphics.Picture, @NonNull android.graphics.Rect);
+    method public void drawPoint(float, float, @NonNull android.graphics.Paint);
+    method public void drawPoints(@Size(multiple=2) float[], int, int, @NonNull android.graphics.Paint);
+    method public void drawPoints(@Size(multiple=2) @NonNull float[], @NonNull android.graphics.Paint);
+    method @Deprecated public void drawPosText(@NonNull char[], int, int, @NonNull @Size(multiple=2) float[], @NonNull android.graphics.Paint);
+    method @Deprecated public void drawPosText(@NonNull String, @NonNull @Size(multiple=2) float[], @NonNull android.graphics.Paint);
     method public void drawRGB(int, int, int);
-    method public void drawRect(android.graphics.RectF, android.graphics.Paint);
-    method public void drawRect(android.graphics.Rect, android.graphics.Paint);
-    method public void drawRect(float, float, float, float, android.graphics.Paint);
-    method public void drawRenderNode(android.graphics.RenderNode);
-    method public void drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint);
-    method public void drawRoundRect(float, float, float, float, float, float, android.graphics.Paint);
-    method public void drawText(char[], int, int, float, float, android.graphics.Paint);
-    method public void drawText(java.lang.String, float, float, android.graphics.Paint);
-    method public void drawText(java.lang.String, int, int, float, float, android.graphics.Paint);
-    method public void drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint);
-    method public void drawTextOnPath(char[], int, int, android.graphics.Path, float, float, android.graphics.Paint);
-    method public void drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint);
-    method public void drawTextRun(char[], int, int, int, int, float, float, boolean, android.graphics.Paint);
-    method public void drawTextRun(java.lang.CharSequence, int, int, int, int, float, float, boolean, android.graphics.Paint);
-    method public void drawVertices(android.graphics.Canvas.VertexMode, int, float[], int, float[], int, int[], int, short[], int, int, android.graphics.Paint);
+    method public void drawRect(@NonNull android.graphics.RectF, @NonNull android.graphics.Paint);
+    method public void drawRect(@NonNull android.graphics.Rect, @NonNull android.graphics.Paint);
+    method public void drawRect(float, float, float, float, @NonNull android.graphics.Paint);
+    method public void drawRenderNode(@NonNull android.graphics.RenderNode);
+    method public void drawRoundRect(@NonNull android.graphics.RectF, float, float, @NonNull android.graphics.Paint);
+    method public void drawRoundRect(float, float, float, float, float, float, @NonNull android.graphics.Paint);
+    method public void drawText(@NonNull char[], int, int, float, float, @NonNull android.graphics.Paint);
+    method public void drawText(@NonNull String, float, float, @NonNull android.graphics.Paint);
+    method public void drawText(@NonNull String, int, int, float, float, @NonNull android.graphics.Paint);
+    method public void drawText(@NonNull CharSequence, int, int, float, float, @NonNull android.graphics.Paint);
+    method public void drawTextOnPath(@NonNull char[], int, int, @NonNull android.graphics.Path, float, float, @NonNull android.graphics.Paint);
+    method public void drawTextOnPath(@NonNull String, @NonNull android.graphics.Path, float, float, @NonNull android.graphics.Paint);
+    method public void drawTextRun(@NonNull char[], int, int, int, int, float, float, boolean, @NonNull android.graphics.Paint);
+    method public void drawTextRun(@NonNull CharSequence, int, int, int, int, float, float, boolean, @NonNull android.graphics.Paint);
+    method public void drawTextRun(@NonNull android.graphics.text.MeasuredText, int, int, int, int, float, float, boolean, @NonNull android.graphics.Paint);
+    method public void drawVertices(@NonNull android.graphics.Canvas.VertexMode, int, @NonNull float[], int, @Nullable float[], int, @Nullable int[], int, @Nullable short[], int, int, @NonNull android.graphics.Paint);
     method public void enableZ();
-    method public boolean getClipBounds(android.graphics.Rect);
-    method public final android.graphics.Rect getClipBounds();
+    method public boolean getClipBounds(@Nullable android.graphics.Rect);
+    method @NonNull public final android.graphics.Rect getClipBounds();
     method public int getDensity();
-    method public android.graphics.DrawFilter getDrawFilter();
+    method @Nullable public android.graphics.DrawFilter getDrawFilter();
     method public int getHeight();
-    method public deprecated void getMatrix(android.graphics.Matrix);
-    method public final deprecated android.graphics.Matrix getMatrix();
+    method @Deprecated public void getMatrix(@NonNull android.graphics.Matrix);
+    method @Deprecated @NonNull public final android.graphics.Matrix getMatrix();
     method public int getMaximumBitmapHeight();
     method public int getMaximumBitmapWidth();
     method public int getSaveCount();
     method public int getWidth();
     method public boolean isHardwareAccelerated();
     method public boolean isOpaque();
-    method public boolean quickReject(android.graphics.RectF, android.graphics.Canvas.EdgeType);
-    method public boolean quickReject(android.graphics.Path, android.graphics.Canvas.EdgeType);
-    method public boolean quickReject(float, float, float, float, android.graphics.Canvas.EdgeType);
+    method public boolean quickReject(@NonNull android.graphics.RectF, @NonNull android.graphics.Canvas.EdgeType);
+    method public boolean quickReject(@NonNull android.graphics.Path, @NonNull android.graphics.Canvas.EdgeType);
+    method public boolean quickReject(float, float, float, float, @NonNull android.graphics.Canvas.EdgeType);
     method public void restore();
     method public void restoreToCount(int);
     method public void rotate(float);
     method public final void rotate(float, float, float);
     method public int save();
-    method public deprecated int saveLayer(android.graphics.RectF, android.graphics.Paint, int);
-    method public int saveLayer(android.graphics.RectF, android.graphics.Paint);
-    method public deprecated int saveLayer(float, float, float, float, android.graphics.Paint, int);
-    method public int saveLayer(float, float, float, float, android.graphics.Paint);
-    method public deprecated int saveLayerAlpha(android.graphics.RectF, int, int);
-    method public int saveLayerAlpha(android.graphics.RectF, int);
-    method public deprecated int saveLayerAlpha(float, float, float, float, int, int);
+    method @Deprecated public int saveLayer(@Nullable android.graphics.RectF, @Nullable android.graphics.Paint, int);
+    method public int saveLayer(@Nullable android.graphics.RectF, @Nullable android.graphics.Paint);
+    method @Deprecated public int saveLayer(float, float, float, float, @Nullable android.graphics.Paint, int);
+    method public int saveLayer(float, float, float, float, @Nullable android.graphics.Paint);
+    method @Deprecated public int saveLayerAlpha(@Nullable android.graphics.RectF, int, int);
+    method public int saveLayerAlpha(@Nullable android.graphics.RectF, int);
+    method @Deprecated public int saveLayerAlpha(float, float, float, float, int, int);
     method public int saveLayerAlpha(float, float, float, float, int);
     method public void scale(float, float);
     method public final void scale(float, float, float, float);
-    method public void setBitmap(android.graphics.Bitmap);
+    method public void setBitmap(@Nullable android.graphics.Bitmap);
     method public void setDensity(int);
-    method public void setDrawFilter(android.graphics.DrawFilter);
-    method public void setMatrix(android.graphics.Matrix);
+    method public void setDrawFilter(@Nullable android.graphics.DrawFilter);
+    method public void setMatrix(@Nullable android.graphics.Matrix);
     method public void skew(float, float);
     method public void translate(float, float);
     field public static final int ALL_SAVE_FLAG = 31; // 0x1f
   }
 
-  public static final class Canvas.EdgeType extends java.lang.Enum {
-    method public static android.graphics.Canvas.EdgeType valueOf(java.lang.String);
-    method public static final android.graphics.Canvas.EdgeType[] values();
+  public enum Canvas.EdgeType {
     enum_constant public static final android.graphics.Canvas.EdgeType AA;
     enum_constant public static final android.graphics.Canvas.EdgeType BW;
   }
 
-  public static final class Canvas.VertexMode extends java.lang.Enum {
-    method public static android.graphics.Canvas.VertexMode valueOf(java.lang.String);
-    method public static final android.graphics.Canvas.VertexMode[] values();
+  public enum Canvas.VertexMode {
     enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLES;
     enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_FAN;
     enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_STRIP;
   }
 
-  public class Color {
+  @AnyThread public class Color {
     ctor public Color();
-    method public static int HSVToColor(float[]);
-    method public static int HSVToColor(int, float[]);
-    method public static void RGBToHSV(int, int, int, float[]);
+    method @ColorInt public static int HSVToColor(@Size(3) float[]);
+    method @ColorInt public static int HSVToColor(@IntRange(from=0, to=255) int, @Size(3) float[]);
+    method public static void RGBToHSV(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @Size(3) float[]);
     method public float alpha();
-    method public static float alpha(long);
-    method public static int alpha(int);
-    method public static int argb(int, int, int, int);
-    method public static int argb(float, float, float, float);
+    method public static float alpha(@ColorLong long);
+    method @IntRange(from=0, to=255) public static int alpha(int);
+    method @ColorInt public static int argb(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int);
+    method @ColorInt public static int argb(float, float, float, float);
     method public float blue();
-    method public static float blue(long);
-    method public static int blue(int);
-    method public static android.graphics.ColorSpace colorSpace(long);
-    method public static void colorToHSV(int, float[]);
-    method public android.graphics.Color convert(android.graphics.ColorSpace);
-    method public static long convert(int, android.graphics.ColorSpace);
-    method public static long convert(long, android.graphics.ColorSpace);
-    method public static long convert(float, float, float, float, android.graphics.ColorSpace, android.graphics.ColorSpace);
-    method public static long convert(long, android.graphics.ColorSpace.Connector);
-    method public static long convert(float, float, float, float, android.graphics.ColorSpace.Connector);
-    method public android.graphics.ColorSpace getColorSpace();
-    method public float getComponent(int);
-    method public int getComponentCount();
-    method public float[] getComponents();
-    method public float[] getComponents(float[]);
+    method public static float blue(@ColorLong long);
+    method @IntRange(from=0, to=255) public static int blue(int);
+    method @NonNull public static android.graphics.ColorSpace colorSpace(@ColorLong long);
+    method public static void colorToHSV(@ColorInt int, @Size(3) float[]);
+    method @NonNull public android.graphics.Color convert(@NonNull android.graphics.ColorSpace);
+    method @ColorLong public static long convert(@ColorInt int, @NonNull android.graphics.ColorSpace);
+    method @ColorLong public static long convert(@ColorLong long, @NonNull android.graphics.ColorSpace);
+    method @ColorLong public static long convert(float, float, float, float, @NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace);
+    method @ColorLong public static long convert(@ColorLong long, @NonNull android.graphics.ColorSpace.Connector);
+    method @ColorLong public static long convert(float, float, float, float, @NonNull android.graphics.ColorSpace.Connector);
+    method @NonNull public android.graphics.ColorSpace getColorSpace();
+    method public float getComponent(@IntRange(from=0, to=4) int);
+    method @IntRange(from=4, to=5) public int getComponentCount();
+    method @NonNull @Size(min=4, max=5) public float[] getComponents();
+    method @NonNull @Size(min=4) public float[] getComponents(@Nullable @Size(min=4) float[]);
     method public android.graphics.ColorSpace.Model getModel();
     method public float green();
-    method public static float green(long);
-    method public static int green(int);
-    method public static boolean isInColorSpace(long, android.graphics.ColorSpace);
+    method public static float green(@ColorLong long);
+    method @IntRange(from=0, to=255) public static int green(int);
+    method public static boolean isInColorSpace(@ColorLong long, @NonNull android.graphics.ColorSpace);
     method public boolean isSrgb();
-    method public static boolean isSrgb(long);
+    method public static boolean isSrgb(@ColorLong long);
     method public boolean isWideGamut();
-    method public static boolean isWideGamut(long);
+    method public static boolean isWideGamut(@ColorLong long);
     method public float luminance();
-    method public static float luminance(long);
-    method public static float luminance(int);
-    method public long pack();
-    method public static long pack(int);
-    method public static long pack(float, float, float);
-    method public static long pack(float, float, float, float);
-    method public static long pack(float, float, float, float, android.graphics.ColorSpace);
-    method public static int parseColor(java.lang.String);
+    method public static float luminance(@ColorLong long);
+    method public static float luminance(@ColorInt int);
+    method @ColorLong public long pack();
+    method @ColorLong public static long pack(@ColorInt int);
+    method @ColorLong public static long pack(float, float, float);
+    method @ColorLong public static long pack(float, float, float, float);
+    method @ColorLong public static long pack(float, float, float, float, @NonNull android.graphics.ColorSpace);
+    method @ColorInt public static int parseColor(@Size(min=1) String);
     method public float red();
-    method public static float red(long);
-    method public static int red(int);
-    method public static int rgb(int, int, int);
-    method public static int rgb(float, float, float);
-    method public int toArgb();
-    method public static int toArgb(long);
-    method public static android.graphics.Color valueOf(int);
-    method public static android.graphics.Color valueOf(long);
-    method public static android.graphics.Color valueOf(float, float, float);
-    method public static android.graphics.Color valueOf(float, float, float, float);
-    method public static android.graphics.Color valueOf(float, float, float, float, android.graphics.ColorSpace);
-    method public static android.graphics.Color valueOf(float[], android.graphics.ColorSpace);
-    field public static final int BLACK = -16777216; // 0xff000000
-    field public static final int BLUE = -16776961; // 0xff0000ff
-    field public static final int CYAN = -16711681; // 0xff00ffff
-    field public static final int DKGRAY = -12303292; // 0xff444444
-    field public static final int GRAY = -7829368; // 0xff888888
-    field public static final int GREEN = -16711936; // 0xff00ff00
-    field public static final int LTGRAY = -3355444; // 0xffcccccc
-    field public static final int MAGENTA = -65281; // 0xffff00ff
-    field public static final int RED = -65536; // 0xffff0000
-    field public static final int TRANSPARENT = 0; // 0x0
-    field public static final int WHITE = -1; // 0xffffffff
-    field public static final int YELLOW = -256; // 0xffffff00
+    method public static float red(@ColorLong long);
+    method @IntRange(from=0, to=255) public static int red(int);
+    method @ColorInt public static int rgb(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int);
+    method @ColorInt public static int rgb(float, float, float);
+    method @ColorInt public int toArgb();
+    method @ColorInt public static int toArgb(@ColorLong long);
+    method @NonNull public static android.graphics.Color valueOf(@ColorInt int);
+    method @NonNull public static android.graphics.Color valueOf(@ColorLong long);
+    method @NonNull public static android.graphics.Color valueOf(float, float, float);
+    method @NonNull public static android.graphics.Color valueOf(float, float, float, float);
+    method @NonNull public static android.graphics.Color valueOf(float, float, float, float, @NonNull android.graphics.ColorSpace);
+    method @NonNull public static android.graphics.Color valueOf(@NonNull @Size(min=4, max=5) float[], @NonNull android.graphics.ColorSpace);
+    field @ColorInt public static final int BLACK = -16777216; // 0xff000000
+    field @ColorInt public static final int BLUE = -16776961; // 0xff0000ff
+    field @ColorInt public static final int CYAN = -16711681; // 0xff00ffff
+    field @ColorInt public static final int DKGRAY = -12303292; // 0xff444444
+    field @ColorInt public static final int GRAY = -7829368; // 0xff888888
+    field @ColorInt public static final int GREEN = -16711936; // 0xff00ff00
+    field @ColorInt public static final int LTGRAY = -3355444; // 0xffcccccc
+    field @ColorInt public static final int MAGENTA = -65281; // 0xffff00ff
+    field @ColorInt public static final int RED = -65536; // 0xffff0000
+    field @ColorInt public static final int TRANSPARENT = 0; // 0x0
+    field @ColorInt public static final int WHITE = -1; // 0xffffffff
+    field @ColorInt public static final int YELLOW = -256; // 0xffffff00
   }
 
   public class ColorFilter {
-    ctor public deprecated ColorFilter();
+    ctor @Deprecated public ColorFilter();
   }
 
   public class ColorMatrix {
@@ -13877,34 +13922,34 @@
   }
 
   public class ColorMatrixColorFilter extends android.graphics.ColorFilter {
-    ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix);
-    ctor public ColorMatrixColorFilter(float[]);
+    ctor public ColorMatrixColorFilter(@NonNull android.graphics.ColorMatrix);
+    ctor public ColorMatrixColorFilter(@NonNull float[]);
     method public void getColorMatrix(android.graphics.ColorMatrix);
   }
 
-  public abstract class ColorSpace {
-    method public static android.graphics.ColorSpace adapt(android.graphics.ColorSpace, float[]);
-    method public static android.graphics.ColorSpace adapt(android.graphics.ColorSpace, float[], android.graphics.ColorSpace.Adaptation);
-    method public static float[] cctToIlluminantdXyz(int);
-    method public static float[] chromaticAdaptation(android.graphics.ColorSpace.Adaptation, float[], float[]);
-    method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace);
-    method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
-    method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace);
-    method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
-    method public float[] fromXyz(float, float, float);
-    method public abstract float[] fromXyz(float[]);
-    method public static android.graphics.ColorSpace get(android.graphics.ColorSpace.Named);
-    method public int getComponentCount();
-    method public int getId();
-    method public abstract float getMaxValue(int);
-    method public abstract float getMinValue(int);
-    method public android.graphics.ColorSpace.Model getModel();
-    method public java.lang.String getName();
+  @AnyThread public abstract class ColorSpace {
+    method @NonNull public static android.graphics.ColorSpace adapt(@NonNull android.graphics.ColorSpace, @NonNull @Size(min=2, max=3) float[]);
+    method @NonNull public static android.graphics.ColorSpace adapt(@NonNull android.graphics.ColorSpace, @NonNull @Size(min=2, max=3) float[], @NonNull android.graphics.ColorSpace.Adaptation);
+    method @NonNull @Size(3) public static float[] cctToIlluminantdXyz(@IntRange(from=1) int);
+    method @NonNull @Size(9) public static float[] chromaticAdaptation(@NonNull android.graphics.ColorSpace.Adaptation, @NonNull @Size(min=2, max=3) float[], @NonNull @Size(min=2, max=3) float[]);
+    method @NonNull public static android.graphics.ColorSpace.Connector connect(@NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace);
+    method @NonNull public static android.graphics.ColorSpace.Connector connect(@NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace.RenderIntent);
+    method @NonNull public static android.graphics.ColorSpace.Connector connect(@NonNull android.graphics.ColorSpace);
+    method @NonNull public static android.graphics.ColorSpace.Connector connect(@NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace.RenderIntent);
+    method @NonNull @Size(min=3) public float[] fromXyz(float, float, float);
+    method @NonNull @Size(min=3) public abstract float[] fromXyz(@NonNull @Size(min=3) float[]);
+    method @NonNull public static android.graphics.ColorSpace get(@NonNull android.graphics.ColorSpace.Named);
+    method @IntRange(from=1, to=4) public int getComponentCount();
+    method @IntRange(from=android.graphics.ColorSpace.MIN_ID, to=android.graphics.ColorSpace.MAX_ID) public int getId();
+    method public abstract float getMaxValue(@IntRange(from=0, to=3) int);
+    method public abstract float getMinValue(@IntRange(from=0, to=3) int);
+    method @NonNull public android.graphics.ColorSpace.Model getModel();
+    method @NonNull public String getName();
     method public boolean isSrgb();
     method public abstract boolean isWideGamut();
-    method public static android.graphics.ColorSpace match(float[], android.graphics.ColorSpace.Rgb.TransferParameters);
-    method public float[] toXyz(float, float, float);
-    method public abstract float[] toXyz(float[]);
+    method @Nullable public static android.graphics.ColorSpace match(@NonNull @Size(9) float[], @NonNull android.graphics.ColorSpace.Rgb.TransferParameters);
+    method @NonNull @Size(3) public float[] toXyz(float, float, float);
+    method @NonNull @Size(min=3) public abstract float[] toXyz(@NonNull @Size(min=3) float[]);
     field public static final float[] ILLUMINANT_A;
     field public static final float[] ILLUMINANT_B;
     field public static final float[] ILLUMINANT_C;
@@ -13918,35 +13963,29 @@
     field public static final int MIN_ID = -1; // 0xffffffff
   }
 
-  public static final class ColorSpace.Adaptation extends java.lang.Enum {
-    method public static android.graphics.ColorSpace.Adaptation valueOf(java.lang.String);
-    method public static final android.graphics.ColorSpace.Adaptation[] values();
+  public enum ColorSpace.Adaptation {
     enum_constant public static final android.graphics.ColorSpace.Adaptation BRADFORD;
     enum_constant public static final android.graphics.ColorSpace.Adaptation CIECAT02;
     enum_constant public static final android.graphics.ColorSpace.Adaptation VON_KRIES;
   }
 
-  public static class ColorSpace.Connector {
-    method public android.graphics.ColorSpace getDestination();
+  @AnyThread public static class ColorSpace.Connector {
+    method @NonNull public android.graphics.ColorSpace getDestination();
     method public android.graphics.ColorSpace.RenderIntent getRenderIntent();
-    method public android.graphics.ColorSpace getSource();
-    method public float[] transform(float, float, float);
-    method public float[] transform(float[]);
+    method @NonNull public android.graphics.ColorSpace getSource();
+    method @NonNull @Size(3) public float[] transform(float, float, float);
+    method @NonNull @Size(min=3) public float[] transform(@NonNull @Size(min=3) float[]);
   }
 
-  public static final class ColorSpace.Model extends java.lang.Enum {
-    method public int getComponentCount();
-    method public static android.graphics.ColorSpace.Model valueOf(java.lang.String);
-    method public static final android.graphics.ColorSpace.Model[] values();
+  public enum ColorSpace.Model {
+    method @IntRange(from=1, to=4) public int getComponentCount();
     enum_constant public static final android.graphics.ColorSpace.Model CMYK;
     enum_constant public static final android.graphics.ColorSpace.Model LAB;
     enum_constant public static final android.graphics.ColorSpace.Model RGB;
     enum_constant public static final android.graphics.ColorSpace.Model XYZ;
   }
 
-  public static final class ColorSpace.Named extends java.lang.Enum {
-    method public static android.graphics.ColorSpace.Named valueOf(java.lang.String);
-    method public static final android.graphics.ColorSpace.Named[] values();
+  public enum ColorSpace.Named {
     enum_constant public static final android.graphics.ColorSpace.Named ACES;
     enum_constant public static final android.graphics.ColorSpace.Named ACESCG;
     enum_constant public static final android.graphics.ColorSpace.Named ADOBE_RGB;
@@ -13965,42 +14004,40 @@
     enum_constant public static final android.graphics.ColorSpace.Named SRGB;
   }
 
-  public static final class ColorSpace.RenderIntent extends java.lang.Enum {
-    method public static android.graphics.ColorSpace.RenderIntent valueOf(java.lang.String);
-    method public static final android.graphics.ColorSpace.RenderIntent[] values();
+  public enum ColorSpace.RenderIntent {
     enum_constant public static final android.graphics.ColorSpace.RenderIntent ABSOLUTE;
     enum_constant public static final android.graphics.ColorSpace.RenderIntent PERCEPTUAL;
     enum_constant public static final android.graphics.ColorSpace.RenderIntent RELATIVE;
     enum_constant public static final android.graphics.ColorSpace.RenderIntent SATURATION;
   }
 
-  public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
-    ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
-    ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
-    ctor public ColorSpace.Rgb(java.lang.String, float[], android.graphics.ColorSpace.Rgb.TransferParameters);
-    ctor public ColorSpace.Rgb(java.lang.String, float[], float[], android.graphics.ColorSpace.Rgb.TransferParameters);
-    ctor public ColorSpace.Rgb(java.lang.String, float[], double);
-    ctor public ColorSpace.Rgb(java.lang.String, float[], float[], double);
-    method public float[] fromLinear(float, float, float);
-    method public float[] fromLinear(float[]);
-    method public float[] fromXyz(float[]);
-    method public java.util.function.DoubleUnaryOperator getEotf();
-    method public float[] getInverseTransform(float[]);
-    method public float[] getInverseTransform();
+  @AnyThread public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
+    ctor public ColorSpace.Rgb(@NonNull @Size(min=1) String, @NonNull @Size(9) float[], @NonNull java.util.function.DoubleUnaryOperator, @NonNull java.util.function.DoubleUnaryOperator);
+    ctor public ColorSpace.Rgb(@NonNull @Size(min=1) String, @NonNull @Size(min=6, max=9) float[], @NonNull @Size(min=2, max=3) float[], @NonNull java.util.function.DoubleUnaryOperator, @NonNull java.util.function.DoubleUnaryOperator, float, float);
+    ctor public ColorSpace.Rgb(@NonNull @Size(min=1) String, @NonNull @Size(9) float[], @NonNull android.graphics.ColorSpace.Rgb.TransferParameters);
+    ctor public ColorSpace.Rgb(@NonNull @Size(min=1) String, @NonNull @Size(min=6, max=9) float[], @NonNull @Size(min=2, max=3) float[], @NonNull android.graphics.ColorSpace.Rgb.TransferParameters);
+    ctor public ColorSpace.Rgb(@NonNull @Size(min=1) String, @NonNull @Size(9) float[], double);
+    ctor public ColorSpace.Rgb(@NonNull @Size(min=1) String, @NonNull @Size(min=6, max=9) float[], @NonNull @Size(min=2, max=3) float[], double);
+    method @NonNull @Size(3) public float[] fromLinear(float, float, float);
+    method @NonNull @Size(min=3) public float[] fromLinear(@NonNull @Size(min=3) float[]);
+    method @NonNull @Size(min=3) public float[] fromXyz(@NonNull @Size(min=3) float[]);
+    method @NonNull public java.util.function.DoubleUnaryOperator getEotf();
+    method @NonNull @Size(min=9) public float[] getInverseTransform(@NonNull @Size(min=9) float[]);
+    method @NonNull @Size(9) public float[] getInverseTransform();
     method public float getMaxValue(int);
     method public float getMinValue(int);
-    method public java.util.function.DoubleUnaryOperator getOetf();
-    method public float[] getPrimaries(float[]);
-    method public float[] getPrimaries();
-    method public android.graphics.ColorSpace.Rgb.TransferParameters getTransferParameters();
-    method public float[] getTransform(float[]);
-    method public float[] getTransform();
-    method public float[] getWhitePoint(float[]);
-    method public float[] getWhitePoint();
+    method @NonNull public java.util.function.DoubleUnaryOperator getOetf();
+    method @NonNull @Size(min=6) public float[] getPrimaries(@NonNull @Size(min=6) float[]);
+    method @NonNull @Size(6) public float[] getPrimaries();
+    method @Nullable public android.graphics.ColorSpace.Rgb.TransferParameters getTransferParameters();
+    method @NonNull @Size(min=9) public float[] getTransform(@NonNull @Size(min=9) float[]);
+    method @NonNull @Size(9) public float[] getTransform();
+    method @NonNull @Size(min=2) public float[] getWhitePoint(@NonNull @Size(min=2) float[]);
+    method @NonNull @Size(2) public float[] getWhitePoint();
     method public boolean isWideGamut();
-    method public float[] toLinear(float, float, float);
-    method public float[] toLinear(float[]);
-    method public float[] toXyz(float[]);
+    method @NonNull @Size(3) public float[] toLinear(float, float, float);
+    method @NonNull @Size(min=3) public float[] toLinear(@NonNull @Size(min=3) float[]);
+    method @NonNull @Size(min=3) public float[] toXyz(@NonNull @Size(min=3) float[]);
   }
 
   public static class ColorSpace.Rgb.TransferParameters {
@@ -14020,8 +14057,8 @@
   }
 
   public class ComposeShader extends android.graphics.Shader {
-    ctor public ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.Xfermode);
-    ctor public ComposeShader(android.graphics.Shader, android.graphics.Shader, android.graphics.PorterDuff.Mode);
+    ctor public ComposeShader(@NonNull android.graphics.Shader, @NonNull android.graphics.Shader, @NonNull android.graphics.Xfermode);
+    ctor public ComposeShader(@NonNull android.graphics.Shader, @NonNull android.graphics.Shader, @NonNull android.graphics.PorterDuff.Mode);
   }
 
   public class CornerPathEffect extends android.graphics.PathEffect {
@@ -14041,39 +14078,39 @@
   }
 
   public class EmbossMaskFilter extends android.graphics.MaskFilter {
-    ctor public deprecated EmbossMaskFilter(float[], float, float, float);
+    ctor @Deprecated public EmbossMaskFilter(float[], float, float, float);
   }
 
   public final class ImageDecoder implements java.lang.AutoCloseable {
     method public void close();
-    method public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, int);
-    method public static android.graphics.ImageDecoder.Source createSource(android.content.ContentResolver, android.net.Uri);
-    method public static android.graphics.ImageDecoder.Source createSource(android.content.res.AssetManager, java.lang.String);
-    method public static android.graphics.ImageDecoder.Source createSource(java.nio.ByteBuffer);
-    method public static android.graphics.ImageDecoder.Source createSource(java.io.File);
-    method public static android.graphics.ImageDecoder.Source createSource(java.util.concurrent.Callable<android.content.res.AssetFileDescriptor>);
-    method public static android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source, android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
-    method public static android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source) throws java.io.IOException;
-    method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
-    method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source) throws java.io.IOException;
+    method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull android.content.res.Resources, int);
+    method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull android.content.ContentResolver, @NonNull android.net.Uri);
+    method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull android.content.res.AssetManager, @NonNull String);
+    method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull java.nio.ByteBuffer);
+    method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull java.io.File);
+    method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull java.util.concurrent.Callable<android.content.res.AssetFileDescriptor>);
+    method @WorkerThread @NonNull public static android.graphics.Bitmap decodeBitmap(@NonNull android.graphics.ImageDecoder.Source, @NonNull android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
+    method @WorkerThread @NonNull public static android.graphics.Bitmap decodeBitmap(@NonNull android.graphics.ImageDecoder.Source) throws java.io.IOException;
+    method @WorkerThread @NonNull public static android.graphics.drawable.Drawable decodeDrawable(@NonNull android.graphics.ImageDecoder.Source, @NonNull android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
+    method @WorkerThread @NonNull public static android.graphics.drawable.Drawable decodeDrawable(@NonNull android.graphics.ImageDecoder.Source) throws java.io.IOException;
     method public int getAllocator();
-    method public android.graphics.Rect getCrop();
+    method @Nullable public android.graphics.Rect getCrop();
     method public int getMemorySizePolicy();
-    method public android.graphics.ImageDecoder.OnPartialImageListener getOnPartialImageListener();
-    method public android.graphics.PostProcessor getPostProcessor();
+    method @Nullable public android.graphics.ImageDecoder.OnPartialImageListener getOnPartialImageListener();
+    method @Nullable public android.graphics.PostProcessor getPostProcessor();
     method public boolean isDecodeAsAlphaMaskEnabled();
     method public boolean isMutableRequired();
     method public boolean isUnpremultipliedRequired();
     method public void setAllocator(int);
-    method public void setCrop(android.graphics.Rect);
+    method public void setCrop(@Nullable android.graphics.Rect);
     method public void setDecodeAsAlphaMaskEnabled(boolean);
     method public void setMemorySizePolicy(int);
     method public void setMutableRequired(boolean);
-    method public void setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
-    method public void setPostProcessor(android.graphics.PostProcessor);
+    method public void setOnPartialImageListener(@Nullable android.graphics.ImageDecoder.OnPartialImageListener);
+    method public void setPostProcessor(@Nullable android.graphics.PostProcessor);
     method public void setTargetColorSpace(android.graphics.ColorSpace);
-    method public void setTargetSampleSize(int);
-    method public void setTargetSize(int, int);
+    method public void setTargetSampleSize(@IntRange(from=1) int);
+    method public void setTargetSize(@Px @IntRange(from=1) int, @Px @IntRange(from=1) int);
     method public void setUnpremultipliedRequired(boolean);
     field public static final int ALLOCATOR_DEFAULT = 0; // 0x0
     field public static final int ALLOCATOR_HARDWARE = 3; // 0x3
@@ -14085,28 +14122,28 @@
 
   public static final class ImageDecoder.DecodeException extends java.io.IOException {
     method public int getError();
-    method public android.graphics.ImageDecoder.Source getSource();
+    method @NonNull public android.graphics.ImageDecoder.Source getSource();
     field public static final int SOURCE_EXCEPTION = 1; // 0x1
     field public static final int SOURCE_INCOMPLETE = 2; // 0x2
     field public static final int SOURCE_MALFORMED_DATA = 3; // 0x3
   }
 
   public static class ImageDecoder.ImageInfo {
-    method public android.graphics.ColorSpace getColorSpace();
-    method public java.lang.String getMimeType();
-    method public android.util.Size getSize();
+    method @Nullable public android.graphics.ColorSpace getColorSpace();
+    method @NonNull public String getMimeType();
+    method @NonNull public android.util.Size getSize();
     method public boolean isAnimated();
   }
 
-  public static abstract interface ImageDecoder.OnHeaderDecodedListener {
-    method public abstract void onHeaderDecoded(android.graphics.ImageDecoder, android.graphics.ImageDecoder.ImageInfo, android.graphics.ImageDecoder.Source);
+  public static interface ImageDecoder.OnHeaderDecodedListener {
+    method public void onHeaderDecoded(@NonNull android.graphics.ImageDecoder, @NonNull android.graphics.ImageDecoder.ImageInfo, @NonNull android.graphics.ImageDecoder.Source);
   }
 
-  public static abstract interface ImageDecoder.OnPartialImageListener {
-    method public abstract boolean onPartialImage(android.graphics.ImageDecoder.DecodeException);
+  public static interface ImageDecoder.OnPartialImageListener {
+    method public boolean onPartialImage(@NonNull android.graphics.ImageDecoder.DecodeException);
   }
 
-  public static abstract class ImageDecoder.Source {
+  public abstract static class ImageDecoder.Source {
   }
 
   public class ImageFormat {
@@ -14135,12 +14172,12 @@
   }
 
   public final class Insets {
-    method public static android.graphics.Insets add(android.graphics.Insets, android.graphics.Insets);
-    method public static android.graphics.Insets max(android.graphics.Insets, android.graphics.Insets);
-    method public static android.graphics.Insets min(android.graphics.Insets, android.graphics.Insets);
-    method public static android.graphics.Insets of(int, int, int, int);
-    method public static android.graphics.Insets of(android.graphics.Rect);
-    method public static android.graphics.Insets subtract(android.graphics.Insets, android.graphics.Insets);
+    method @NonNull public static android.graphics.Insets add(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
+    method @NonNull public static android.graphics.Insets max(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
+    method @NonNull public static android.graphics.Insets min(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
+    method @NonNull public static android.graphics.Insets of(int, int, int, int);
+    method @NonNull public static android.graphics.Insets of(@Nullable android.graphics.Rect);
+    method @NonNull public static android.graphics.Insets subtract(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
     field public static final android.graphics.Insets NONE;
     field public final int bottom;
     field public final int left;
@@ -14162,23 +14199,21 @@
     method public android.graphics.Interpolator.Result timeToValues(int, float[]);
   }
 
-  public static final class Interpolator.Result extends java.lang.Enum {
-    method public static android.graphics.Interpolator.Result valueOf(java.lang.String);
-    method public static final android.graphics.Interpolator.Result[] values();
+  public enum Interpolator.Result {
     enum_constant public static final android.graphics.Interpolator.Result FREEZE_END;
     enum_constant public static final android.graphics.Interpolator.Result FREEZE_START;
     enum_constant public static final android.graphics.Interpolator.Result NORMAL;
   }
 
   public class LightingColorFilter extends android.graphics.ColorFilter {
-    ctor public LightingColorFilter(int, int);
-    method public int getColorAdd();
-    method public int getColorMultiply();
+    ctor public LightingColorFilter(@ColorInt int, @ColorInt int);
+    method @ColorInt public int getColorAdd();
+    method @ColorInt public int getColorMultiply();
   }
 
   public class LinearGradient extends android.graphics.Shader {
-    ctor public LinearGradient(float, float, float, float, int[], float[], android.graphics.Shader.TileMode);
-    ctor public LinearGradient(float, float, float, float, int, int, android.graphics.Shader.TileMode);
+    ctor public LinearGradient(float, float, float, float, @NonNull @ColorInt int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
+    ctor public LinearGradient(float, float, float, float, @ColorInt int, @ColorInt int, @NonNull android.graphics.Shader.TileMode);
   }
 
   public class MaskFilter {
@@ -14233,7 +14268,7 @@
     method public void setSkew(float, float);
     method public void setTranslate(float, float);
     method public void setValues(float[]);
-    method public java.lang.String toShortString();
+    method public String toShortString();
     field public static final int MPERSP_0 = 6; // 0x6
     field public static final int MPERSP_1 = 7; // 0x7
     field public static final int MPERSP_2 = 8; // 0x8
@@ -14245,38 +14280,36 @@
     field public static final int MTRANS_Y = 5; // 0x5
   }
 
-  public static final class Matrix.ScaleToFit extends java.lang.Enum {
-    method public static android.graphics.Matrix.ScaleToFit valueOf(java.lang.String);
-    method public static final android.graphics.Matrix.ScaleToFit[] values();
+  public enum Matrix.ScaleToFit {
     enum_constant public static final android.graphics.Matrix.ScaleToFit CENTER;
     enum_constant public static final android.graphics.Matrix.ScaleToFit END;
     enum_constant public static final android.graphics.Matrix.ScaleToFit FILL;
     enum_constant public static final android.graphics.Matrix.ScaleToFit START;
   }
 
-  public deprecated class Movie {
-    method public static android.graphics.Movie decodeByteArray(byte[], int, int);
-    method public static android.graphics.Movie decodeFile(java.lang.String);
-    method public static android.graphics.Movie decodeStream(java.io.InputStream);
-    method public void draw(android.graphics.Canvas, float, float, android.graphics.Paint);
-    method public void draw(android.graphics.Canvas, float, float);
-    method public int duration();
-    method public int height();
-    method public boolean isOpaque();
-    method public boolean setTime(int);
-    method public int width();
+  @Deprecated public class Movie {
+    method @Deprecated public static android.graphics.Movie decodeByteArray(byte[], int, int);
+    method @Deprecated public static android.graphics.Movie decodeFile(String);
+    method @Deprecated public static android.graphics.Movie decodeStream(java.io.InputStream);
+    method @Deprecated public void draw(android.graphics.Canvas, float, float, android.graphics.Paint);
+    method @Deprecated public void draw(android.graphics.Canvas, float, float);
+    method @Deprecated public int duration();
+    method @Deprecated public int height();
+    method @Deprecated public boolean isOpaque();
+    method @Deprecated public boolean setTime(int);
+    method @Deprecated public int width();
   }
 
   public class NinePatch {
     ctor public NinePatch(android.graphics.Bitmap, byte[]);
-    ctor public NinePatch(android.graphics.Bitmap, byte[], java.lang.String);
+    ctor public NinePatch(android.graphics.Bitmap, byte[], String);
     method public void draw(android.graphics.Canvas, android.graphics.RectF);
     method public void draw(android.graphics.Canvas, android.graphics.Rect);
     method public void draw(android.graphics.Canvas, android.graphics.Rect, android.graphics.Paint);
     method public android.graphics.Bitmap getBitmap();
     method public int getDensity();
     method public int getHeight();
-    method public java.lang.String getName();
+    method public String getName();
     method public android.graphics.Paint getPaint();
     method public final android.graphics.Region getTransparentRegion(android.graphics.Rect);
     method public int getWidth();
@@ -14287,23 +14320,23 @@
 
   public final class Outline {
     ctor public Outline();
-    ctor public Outline(android.graphics.Outline);
+    ctor public Outline(@NonNull android.graphics.Outline);
     method public boolean canClip();
     method public float getAlpha();
     method public float getRadius();
-    method public boolean getRect(android.graphics.Rect);
+    method public boolean getRect(@NonNull android.graphics.Rect);
     method public boolean isEmpty();
     method public void offset(int, int);
-    method public void set(android.graphics.Outline);
-    method public void setAlpha(float);
-    method public void setConvexPath(android.graphics.Path);
+    method public void set(@NonNull android.graphics.Outline);
+    method public void setAlpha(@FloatRange(from=0.0, to=1.0) float);
+    method public void setConvexPath(@NonNull android.graphics.Path);
     method public void setEmpty();
     method public void setOval(int, int, int, int);
-    method public void setOval(android.graphics.Rect);
+    method public void setOval(@NonNull android.graphics.Rect);
     method public void setRect(int, int, int, int);
-    method public void setRect(android.graphics.Rect);
+    method public void setRect(@NonNull android.graphics.Rect);
     method public void setRoundRect(int, int, int, int, float);
-    method public void setRoundRect(android.graphics.Rect, float);
+    method public void setRoundRect(@NonNull android.graphics.Rect, float);
   }
 
   public class Paint {
@@ -14312,69 +14345,69 @@
     ctor public Paint(android.graphics.Paint);
     method public float ascent();
     method public int breakText(char[], int, int, float, float[]);
-    method public int breakText(java.lang.CharSequence, int, int, boolean, float, float[]);
-    method public int breakText(java.lang.String, boolean, float, float[]);
+    method public int breakText(CharSequence, int, int, boolean, float, float[]);
+    method public int breakText(String, boolean, float, float[]);
     method public void clearShadowLayer();
     method public float descent();
-    method public boolean equalsForTextMeasurement(android.graphics.Paint);
+    method public boolean equalsForTextMeasurement(@NonNull android.graphics.Paint);
     method public int getAlpha();
-    method public android.graphics.BlendMode getBlendMode();
-    method public int getColor();
+    method @Nullable public android.graphics.BlendMode getBlendMode();
+    method @ColorInt public int getColor();
     method public android.graphics.ColorFilter getColorFilter();
     method public boolean getFillPath(android.graphics.Path, android.graphics.Path);
     method public int getFlags();
-    method public java.lang.String getFontFeatureSettings();
+    method public String getFontFeatureSettings();
     method public float getFontMetrics(android.graphics.Paint.FontMetrics);
     method public android.graphics.Paint.FontMetrics getFontMetrics();
     method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt);
     method public android.graphics.Paint.FontMetricsInt getFontMetricsInt();
     method public float getFontSpacing();
-    method public java.lang.String getFontVariationSettings();
+    method public String getFontVariationSettings();
     method public int getHinting();
     method public int getHyphenEdit();
     method public float getLetterSpacing();
     method public android.graphics.MaskFilter getMaskFilter();
     method public int getOffsetForAdvance(char[], int, int, int, int, boolean, float);
-    method public int getOffsetForAdvance(java.lang.CharSequence, int, int, int, int, boolean, float);
+    method public int getOffsetForAdvance(CharSequence, int, int, int, int, boolean, float);
     method public android.graphics.PathEffect getPathEffect();
     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 float getRunAdvance(CharSequence, int, int, int, int, boolean, int);
     method public android.graphics.Shader getShader();
-    method public int getShadowLayerColor();
+    method @ColorInt public int getShadowLayerColor();
     method public float getShadowLayerDx();
     method public float getShadowLayerDy();
     method public float getShadowLayerRadius();
-    method public float getStrikeThruPosition();
-    method public float getStrikeThruThickness();
+    method @Px public float getStrikeThruPosition();
+    method @Px public float getStrikeThruThickness();
     method public android.graphics.Paint.Cap getStrokeCap();
     method public android.graphics.Paint.Join getStrokeJoin();
     method public float getStrokeMiter();
     method public float getStrokeWidth();
     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(String, int, int, android.graphics.Rect);
+    method public void getTextBounds(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 @NonNull public java.util.Locale getTextLocale();
+    method @NonNull @Size(min=1) 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 void getTextPath(String, int, int, float, float, android.graphics.Path);
+    method public float getTextRunAdvances(@NonNull char[], @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, boolean, @Nullable float[], @IntRange(from=0) int);
+    method public int getTextRunCursor(@NonNull char[], @IntRange(from=0) int, @IntRange(from=0) int, boolean, @IntRange(from=0) int, int);
+    method public int getTextRunCursor(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, boolean, @IntRange(from=0) int, int);
     method public float getTextScaleX();
     method public float getTextSize();
     method public float getTextSkewX();
     method public int getTextWidths(char[], int, int, float[]);
-    method public int getTextWidths(java.lang.CharSequence, int, int, float[]);
-    method public int getTextWidths(java.lang.String, int, int, float[]);
-    method public int getTextWidths(java.lang.String, float[]);
+    method public int getTextWidths(CharSequence, int, int, float[]);
+    method public int getTextWidths(String, int, int, float[]);
+    method public int getTextWidths(String, float[]);
     method public android.graphics.Typeface getTypeface();
-    method public float getUnderlinePosition();
-    method public float getUnderlineThickness();
+    method @Px public float getUnderlinePosition();
+    method @Px public float getUnderlineThickness();
     method public float getWordSpacing();
-    method public deprecated android.graphics.Xfermode getXfermode();
-    method public boolean hasGlyph(java.lang.String);
+    method @Deprecated public android.graphics.Xfermode getXfermode();
+    method public boolean hasGlyph(String);
     method public final boolean isAntiAlias();
     method public final boolean isDither();
     method public boolean isElegantTextHeight();
@@ -14385,24 +14418,24 @@
     method public final boolean isSubpixelText();
     method public final boolean isUnderlineText();
     method public float measureText(char[], int, int);
-    method public float measureText(java.lang.String, int, int);
-    method public float measureText(java.lang.String);
-    method public float measureText(java.lang.CharSequence, int, int);
+    method public float measureText(String, int, int);
+    method public float measureText(String);
+    method public float measureText(CharSequence, int, int);
     method public void reset();
     method public void set(android.graphics.Paint);
     method public void setARGB(int, int, int, int);
     method public void setAlpha(int);
     method public void setAntiAlias(boolean);
-    method public void setBlendMode(android.graphics.BlendMode);
-    method public void setColor(int);
+    method public void setBlendMode(@Nullable android.graphics.BlendMode);
+    method public void setColor(@ColorInt int);
     method public android.graphics.ColorFilter setColorFilter(android.graphics.ColorFilter);
     method public void setDither(boolean);
     method public void setElegantTextHeight(boolean);
     method public void setFakeBoldText(boolean);
     method public void setFilterBitmap(boolean);
     method public void setFlags(int);
-    method public void setFontFeatureSettings(java.lang.String);
-    method public boolean setFontVariationSettings(java.lang.String);
+    method public void setFontFeatureSettings(String);
+    method public boolean setFontVariationSettings(String);
     method public void setHinting(int);
     method public void setHyphenEdit(int);
     method public void setLetterSpacing(float);
@@ -14410,7 +14443,7 @@
     method public android.graphics.MaskFilter setMaskFilter(android.graphics.MaskFilter);
     method public android.graphics.PathEffect setPathEffect(android.graphics.PathEffect);
     method public android.graphics.Shader setShader(android.graphics.Shader);
-    method public void setShadowLayer(float, float, float, int);
+    method public void setShadowLayer(float, float, float, @ColorInt int);
     method public void setStrikeThruText(boolean);
     method public void setStrokeCap(android.graphics.Paint.Cap);
     method public void setStrokeJoin(android.graphics.Paint.Join);
@@ -14419,15 +14452,15 @@
     method public void setStyle(android.graphics.Paint.Style);
     method public void setSubpixelText(boolean);
     method public void setTextAlign(android.graphics.Paint.Align);
-    method public void setTextLocale(java.util.Locale);
-    method public void setTextLocales(android.os.LocaleList);
+    method public void setTextLocale(@NonNull java.util.Locale);
+    method public void setTextLocales(@NonNull @Size(min=1) android.os.LocaleList);
     method public void setTextScaleX(float);
     method public void setTextSize(float);
     method public void setTextSkewX(float);
     method public android.graphics.Typeface setTypeface(android.graphics.Typeface);
     method public void setUnderlineText(boolean);
     method public void setWordSpacing(float);
-    method public deprecated android.graphics.Xfermode setXfermode(android.graphics.Xfermode);
+    method @Deprecated 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
@@ -14447,17 +14480,13 @@
     field public static final int UNDERLINE_TEXT_FLAG = 8; // 0x8
   }
 
-  public static final class Paint.Align extends java.lang.Enum {
-    method public static android.graphics.Paint.Align valueOf(java.lang.String);
-    method public static final android.graphics.Paint.Align[] values();
+  public enum Paint.Align {
     enum_constant public static final android.graphics.Paint.Align CENTER;
     enum_constant public static final android.graphics.Paint.Align LEFT;
     enum_constant public static final android.graphics.Paint.Align RIGHT;
   }
 
-  public static final class Paint.Cap extends java.lang.Enum {
-    method public static android.graphics.Paint.Cap valueOf(java.lang.String);
-    method public static final android.graphics.Paint.Cap[] values();
+  public enum Paint.Cap {
     enum_constant public static final android.graphics.Paint.Cap BUTT;
     enum_constant public static final android.graphics.Paint.Cap ROUND;
     enum_constant public static final android.graphics.Paint.Cap SQUARE;
@@ -14481,17 +14510,13 @@
     field public int top;
   }
 
-  public static final class Paint.Join extends java.lang.Enum {
-    method public static android.graphics.Paint.Join valueOf(java.lang.String);
-    method public static final android.graphics.Paint.Join[] values();
+  public enum Paint.Join {
     enum_constant public static final android.graphics.Paint.Join BEVEL;
     enum_constant public static final android.graphics.Paint.Join MITER;
     enum_constant public static final android.graphics.Paint.Join ROUND;
   }
 
-  public static final class Paint.Style extends java.lang.Enum {
-    method public static android.graphics.Paint.Style valueOf(java.lang.String);
-    method public static final android.graphics.Paint.Style[] values();
+  public enum Paint.Style {
     enum_constant public static final android.graphics.Paint.Style FILL;
     enum_constant public static final android.graphics.Paint.Style FILL_AND_STROKE;
     enum_constant public static final android.graphics.Paint.Style STROKE;
@@ -14503,40 +14528,40 @@
 
   public class Path {
     ctor public Path();
-    ctor public Path(android.graphics.Path);
-    method public void addArc(android.graphics.RectF, float, float);
+    ctor public Path(@Nullable android.graphics.Path);
+    method public void addArc(@NonNull android.graphics.RectF, float, float);
     method public void addArc(float, float, float, float, float, float);
-    method public void addCircle(float, float, float, android.graphics.Path.Direction);
-    method public void addOval(android.graphics.RectF, android.graphics.Path.Direction);
-    method public void addOval(float, float, float, float, android.graphics.Path.Direction);
-    method public void addPath(android.graphics.Path, float, float);
-    method public void addPath(android.graphics.Path);
-    method public void addPath(android.graphics.Path, android.graphics.Matrix);
-    method public void addRect(android.graphics.RectF, android.graphics.Path.Direction);
-    method public void addRect(float, float, float, float, android.graphics.Path.Direction);
-    method public void addRoundRect(android.graphics.RectF, float, float, android.graphics.Path.Direction);
-    method public void addRoundRect(float, float, float, float, float, float, android.graphics.Path.Direction);
-    method public void addRoundRect(android.graphics.RectF, float[], android.graphics.Path.Direction);
-    method public void addRoundRect(float, float, float, float, float[], android.graphics.Path.Direction);
-    method public float[] approximate(float);
-    method public void arcTo(android.graphics.RectF, float, float, boolean);
-    method public void arcTo(android.graphics.RectF, float, float);
+    method public void addCircle(float, float, float, @NonNull android.graphics.Path.Direction);
+    method public void addOval(@NonNull android.graphics.RectF, @NonNull android.graphics.Path.Direction);
+    method public void addOval(float, float, float, float, @NonNull android.graphics.Path.Direction);
+    method public void addPath(@NonNull android.graphics.Path, float, float);
+    method public void addPath(@NonNull android.graphics.Path);
+    method public void addPath(@NonNull android.graphics.Path, @NonNull android.graphics.Matrix);
+    method public void addRect(@NonNull android.graphics.RectF, @NonNull android.graphics.Path.Direction);
+    method public void addRect(float, float, float, float, @NonNull android.graphics.Path.Direction);
+    method public void addRoundRect(@NonNull android.graphics.RectF, float, float, @NonNull android.graphics.Path.Direction);
+    method public void addRoundRect(float, float, float, float, float, float, @NonNull android.graphics.Path.Direction);
+    method public void addRoundRect(@NonNull android.graphics.RectF, @NonNull float[], @NonNull android.graphics.Path.Direction);
+    method public void addRoundRect(float, float, float, float, @NonNull float[], @NonNull android.graphics.Path.Direction);
+    method @NonNull @Size(min=6, multiple=3) public float[] approximate(@FloatRange(from=0) float);
+    method public void arcTo(@NonNull android.graphics.RectF, float, float, boolean);
+    method public void arcTo(@NonNull android.graphics.RectF, float, float);
     method public void arcTo(float, float, float, float, float, float, boolean);
     method public void close();
-    method public void computeBounds(android.graphics.RectF, boolean);
+    method public void computeBounds(@NonNull android.graphics.RectF, boolean);
     method public void cubicTo(float, float, float, float, float, float);
-    method public android.graphics.Path.FillType getFillType();
+    method @NonNull public android.graphics.Path.FillType getFillType();
     method public void incReserve(int);
     method public boolean isConvex();
     method public boolean isEmpty();
     method public boolean isInverseFillType();
-    method public boolean isRect(android.graphics.RectF);
+    method public boolean isRect(@Nullable android.graphics.RectF);
     method public void lineTo(float, float);
     method public void moveTo(float, float);
-    method public void offset(float, float, android.graphics.Path);
+    method public void offset(float, float, @Nullable android.graphics.Path);
     method public void offset(float, float);
-    method public boolean op(android.graphics.Path, android.graphics.Path.Op);
-    method public boolean op(android.graphics.Path, android.graphics.Path, android.graphics.Path.Op);
+    method public boolean op(@NonNull android.graphics.Path, @NonNull android.graphics.Path.Op);
+    method public boolean op(@NonNull android.graphics.Path, @NonNull android.graphics.Path, @NonNull android.graphics.Path.Op);
     method public void quadTo(float, float, float, float);
     method public void rCubicTo(float, float, float, float, float, float);
     method public void rLineTo(float, float);
@@ -14544,33 +14569,27 @@
     method public void rQuadTo(float, float, float, float);
     method public void reset();
     method public void rewind();
-    method public void set(android.graphics.Path);
-    method public void setFillType(android.graphics.Path.FillType);
+    method public void set(@NonNull android.graphics.Path);
+    method public void setFillType(@NonNull android.graphics.Path.FillType);
     method public void setLastPoint(float, float);
     method public void toggleInverseFillType();
-    method public void transform(android.graphics.Matrix, android.graphics.Path);
-    method public void transform(android.graphics.Matrix);
+    method public void transform(@NonNull android.graphics.Matrix, @Nullable android.graphics.Path);
+    method public void transform(@NonNull android.graphics.Matrix);
   }
 
-  public static final class Path.Direction extends java.lang.Enum {
-    method public static android.graphics.Path.Direction valueOf(java.lang.String);
-    method public static final android.graphics.Path.Direction[] values();
+  public enum Path.Direction {
     enum_constant public static final android.graphics.Path.Direction CCW;
     enum_constant public static final android.graphics.Path.Direction CW;
   }
 
-  public static final class Path.FillType extends java.lang.Enum {
-    method public static android.graphics.Path.FillType valueOf(java.lang.String);
-    method public static final android.graphics.Path.FillType[] values();
+  public enum Path.FillType {
     enum_constant public static final android.graphics.Path.FillType EVEN_ODD;
     enum_constant public static final android.graphics.Path.FillType INVERSE_EVEN_ODD;
     enum_constant public static final android.graphics.Path.FillType INVERSE_WINDING;
     enum_constant public static final android.graphics.Path.FillType WINDING;
   }
 
-  public static final class Path.Op extends java.lang.Enum {
-    method public static android.graphics.Path.Op valueOf(java.lang.String);
-    method public static final android.graphics.Path.Op[] values();
+  public enum Path.Op {
     enum_constant public static final android.graphics.Path.Op DIFFERENCE;
     enum_constant public static final android.graphics.Path.Op INTERSECT;
     enum_constant public static final android.graphics.Path.Op REVERSE_DIFFERENCE;
@@ -14582,9 +14601,7 @@
     ctor public PathDashPathEffect(android.graphics.Path, float, float, android.graphics.PathDashPathEffect.Style);
   }
 
-  public static final class PathDashPathEffect.Style extends java.lang.Enum {
-    method public static android.graphics.PathDashPathEffect.Style valueOf(java.lang.String);
-    method public static final android.graphics.PathDashPathEffect.Style[] values();
+  public enum PathDashPathEffect.Style {
     enum_constant public static final android.graphics.PathDashPathEffect.Style MORPH;
     enum_constant public static final android.graphics.PathDashPathEffect.Style ROTATE;
     enum_constant public static final android.graphics.PathDashPathEffect.Style TRANSLATE;
@@ -14611,8 +14628,8 @@
   public class Picture {
     ctor public Picture();
     ctor public Picture(android.graphics.Picture);
-    method public android.graphics.Canvas beginRecording(int, int);
-    method public void draw(android.graphics.Canvas);
+    method @NonNull public android.graphics.Canvas beginRecording(int, int);
+    method public void draw(@NonNull android.graphics.Canvas);
     method public void endRecording();
     method public int getHeight();
     method public int getWidth();
@@ -14623,26 +14640,26 @@
     ctor public PixelFormat();
     method public static boolean formatHasAlpha(int);
     method public static void getPixelFormatInfo(int, android.graphics.PixelFormat);
-    field public static final deprecated int A_8 = 8; // 0x8
-    field public static final deprecated int JPEG = 256; // 0x100
-    field public static final deprecated int LA_88 = 10; // 0xa
-    field public static final deprecated int L_8 = 9; // 0x9
+    field @Deprecated public static final int A_8 = 8; // 0x8
+    field @Deprecated public static final int JPEG = 256; // 0x100
+    field @Deprecated public static final int LA_88 = 10; // 0xa
+    field @Deprecated public static final int L_8 = 9; // 0x9
     field public static final int OPAQUE = -1; // 0xffffffff
     field public static final int RGBA_1010102 = 43; // 0x2b
-    field public static final deprecated int RGBA_4444 = 7; // 0x7
-    field public static final deprecated int RGBA_5551 = 6; // 0x6
+    field @Deprecated public static final int RGBA_4444 = 7; // 0x7
+    field @Deprecated public static final int RGBA_5551 = 6; // 0x6
     field public static final int RGBA_8888 = 1; // 0x1
     field public static final int RGBA_F16 = 22; // 0x16
     field public static final int RGBX_8888 = 2; // 0x2
-    field public static final deprecated int RGB_332 = 11; // 0xb
+    field @Deprecated public static final int RGB_332 = 11; // 0xb
     field public static final int RGB_565 = 4; // 0x4
     field public static final int RGB_888 = 3; // 0x3
     field public static final int TRANSLUCENT = -3; // 0xfffffffd
     field public static final int TRANSPARENT = -2; // 0xfffffffe
     field public static final int UNKNOWN = 0; // 0x0
-    field public static final deprecated int YCbCr_420_SP = 17; // 0x11
-    field public static final deprecated int YCbCr_422_I = 20; // 0x14
-    field public static final deprecated int YCbCr_422_SP = 16; // 0x10
+    field @Deprecated public static final int YCbCr_420_SP = 17; // 0x11
+    field @Deprecated public static final int YCbCr_422_I = 20; // 0x14
+    field @Deprecated public static final int YCbCr_422_SP = 16; // 0x10
     field public int bitsPerPixel;
     field public int bytesPerPixel;
   }
@@ -14650,12 +14667,12 @@
   public class Point implements android.os.Parcelable {
     ctor public Point();
     ctor public Point(int, int);
-    ctor public Point(android.graphics.Point);
+    ctor public Point(@NonNull android.graphics.Point);
     method public int describeContents();
     method public final boolean equals(int, int);
     method public final void negate();
     method public final void offset(int, int);
-    method public void readFromParcel(android.os.Parcel);
+    method public void readFromParcel(@NonNull android.os.Parcel);
     method public void set(int, int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.graphics.Point> CREATOR;
@@ -14666,16 +14683,16 @@
   public class PointF implements android.os.Parcelable {
     ctor public PointF();
     ctor public PointF(float, float);
-    ctor public PointF(android.graphics.Point);
+    ctor public PointF(@NonNull android.graphics.Point);
     method public int describeContents();
     method public final boolean equals(float, float);
     method public final float length();
     method public static float length(float, float);
     method public final void negate();
     method public final void offset(float, float);
-    method public void readFromParcel(android.os.Parcel);
+    method public void readFromParcel(@NonNull android.os.Parcel);
     method public final void set(float, float);
-    method public final void set(android.graphics.PointF);
+    method public final void set(@NonNull android.graphics.PointF);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.graphics.PointF> CREATOR;
     field public float x;
@@ -14686,9 +14703,7 @@
     ctor public PorterDuff();
   }
 
-  public static final class PorterDuff.Mode extends java.lang.Enum {
-    method public static android.graphics.PorterDuff.Mode valueOf(java.lang.String);
-    method public static final android.graphics.PorterDuff.Mode[] values();
+  public enum PorterDuff.Mode {
     enum_constant public static final android.graphics.PorterDuff.Mode ADD;
     enum_constant public static final android.graphics.PorterDuff.Mode CLEAR;
     enum_constant public static final android.graphics.PorterDuff.Mode DARKEN;
@@ -14709,58 +14724,60 @@
     enum_constant public static final android.graphics.PorterDuff.Mode XOR;
   }
 
-  public deprecated class PorterDuffColorFilter extends android.graphics.ColorFilter {
-    ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
+  @Deprecated public class PorterDuffColorFilter extends android.graphics.ColorFilter {
+    ctor @Deprecated public PorterDuffColorFilter(@ColorInt int, @NonNull android.graphics.PorterDuff.Mode);
   }
 
   public class PorterDuffXfermode extends android.graphics.Xfermode {
     ctor public PorterDuffXfermode(android.graphics.PorterDuff.Mode);
   }
 
-  public abstract interface PostProcessor {
-    method public abstract int onPostProcess(android.graphics.Canvas);
+  public interface PostProcessor {
+    method public int onPostProcess(@NonNull android.graphics.Canvas);
   }
 
   public class RadialGradient extends android.graphics.Shader {
-    ctor public RadialGradient(float, float, float, int[], float[], android.graphics.Shader.TileMode);
-    ctor public RadialGradient(float, float, float, int, int, android.graphics.Shader.TileMode);
+    ctor public RadialGradient(float, float, float, @NonNull @ColorInt int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
+    ctor public RadialGradient(float, float, float, @ColorInt int, @ColorInt int, @NonNull android.graphics.Shader.TileMode);
   }
 
   public final class RecordingCanvas extends android.graphics.Canvas {
+    method public final void drawPatch(@NonNull android.graphics.NinePatch, @NonNull android.graphics.Rect, @Nullable android.graphics.Paint);
+    method public final void drawPatch(@NonNull android.graphics.NinePatch, @NonNull android.graphics.RectF, @Nullable android.graphics.Paint);
   }
 
   public final class Rect implements android.os.Parcelable {
     ctor public Rect();
     ctor public Rect(int, int, int, int);
-    ctor public Rect(android.graphics.Rect);
+    ctor public Rect(@Nullable android.graphics.Rect);
     method public int centerX();
     method public int centerY();
     method public boolean contains(int, int);
     method public boolean contains(int, int, int, int);
-    method public boolean contains(android.graphics.Rect);
+    method public boolean contains(@NonNull android.graphics.Rect);
     method public int describeContents();
     method public float exactCenterX();
     method public float exactCenterY();
-    method public java.lang.String flattenToString();
+    method @NonNull public String flattenToString();
     method public int height();
     method public void inset(int, int);
-    method public boolean intersect(int, int, int, int);
-    method public boolean intersect(android.graphics.Rect);
+    method @CheckResult public boolean intersect(int, int, int, int);
+    method @CheckResult public boolean intersect(@NonNull android.graphics.Rect);
     method public boolean intersects(int, int, int, int);
-    method public static boolean intersects(android.graphics.Rect, android.graphics.Rect);
+    method public static boolean intersects(@NonNull android.graphics.Rect, @NonNull android.graphics.Rect);
     method public boolean isEmpty();
     method public void offset(int, int);
     method public void offsetTo(int, int);
-    method public void readFromParcel(android.os.Parcel);
+    method public void readFromParcel(@NonNull android.os.Parcel);
     method public void set(int, int, int, int);
-    method public void set(android.graphics.Rect);
+    method public void set(@NonNull android.graphics.Rect);
     method public void setEmpty();
-    method public boolean setIntersect(android.graphics.Rect, android.graphics.Rect);
+    method @CheckResult public boolean setIntersect(@NonNull android.graphics.Rect, @NonNull android.graphics.Rect);
     method public void sort();
-    method public java.lang.String toShortString();
-    method public static android.graphics.Rect unflattenFromString(java.lang.String);
+    method @NonNull public String toShortString();
+    method @Nullable public static android.graphics.Rect unflattenFromString(@Nullable String);
     method public void union(int, int, int, int);
-    method public void union(android.graphics.Rect);
+    method public void union(@NonNull android.graphics.Rect);
     method public void union(int, int);
     method public int width();
     method public void writeToParcel(android.os.Parcel, int);
@@ -14774,35 +14791,35 @@
   public class RectF implements android.os.Parcelable {
     ctor public RectF();
     ctor public RectF(float, float, float, float);
-    ctor public RectF(android.graphics.RectF);
-    ctor public RectF(android.graphics.Rect);
+    ctor public RectF(@Nullable android.graphics.RectF);
+    ctor public RectF(@Nullable android.graphics.Rect);
     method public final float centerX();
     method public final float centerY();
     method public boolean contains(float, float);
     method public boolean contains(float, float, float, float);
-    method public boolean contains(android.graphics.RectF);
+    method public boolean contains(@NonNull android.graphics.RectF);
     method public int describeContents();
     method public final float height();
     method public void inset(float, float);
     method public boolean intersect(float, float, float, float);
-    method public boolean intersect(android.graphics.RectF);
+    method public boolean intersect(@NonNull android.graphics.RectF);
     method public boolean intersects(float, float, float, float);
-    method public static boolean intersects(android.graphics.RectF, android.graphics.RectF);
+    method public static boolean intersects(@NonNull android.graphics.RectF, @NonNull android.graphics.RectF);
     method public final boolean isEmpty();
     method public void offset(float, float);
     method public void offsetTo(float, float);
-    method public void readFromParcel(android.os.Parcel);
-    method public void round(android.graphics.Rect);
-    method public void roundOut(android.graphics.Rect);
+    method public void readFromParcel(@NonNull android.os.Parcel);
+    method public void round(@NonNull android.graphics.Rect);
+    method public void roundOut(@NonNull android.graphics.Rect);
     method public void set(float, float, float, float);
-    method public void set(android.graphics.RectF);
-    method public void set(android.graphics.Rect);
+    method public void set(@NonNull android.graphics.RectF);
+    method public void set(@NonNull android.graphics.Rect);
     method public void setEmpty();
-    method public boolean setIntersect(android.graphics.RectF, android.graphics.RectF);
+    method public boolean setIntersect(@NonNull android.graphics.RectF, @NonNull android.graphics.RectF);
     method public void sort();
-    method public java.lang.String toShortString();
+    method @NonNull public String toShortString();
     method public void union(float, float, float, float);
-    method public void union(android.graphics.RectF);
+    method public void union(@NonNull android.graphics.RectF);
     method public void union(float, float);
     method public final float width();
     method public void writeToParcel(android.os.Parcel, int);
@@ -14815,43 +14832,41 @@
 
   public class Region implements android.os.Parcelable {
     ctor public Region();
-    ctor public Region(android.graphics.Region);
-    ctor public Region(android.graphics.Rect);
+    ctor public Region(@NonNull android.graphics.Region);
+    ctor public Region(@NonNull android.graphics.Rect);
     ctor public Region(int, int, int, int);
     method public boolean contains(int, int);
     method public int describeContents();
-    method public android.graphics.Path getBoundaryPath();
-    method public boolean getBoundaryPath(android.graphics.Path);
-    method public android.graphics.Rect getBounds();
-    method public boolean getBounds(android.graphics.Rect);
+    method @NonNull public android.graphics.Path getBoundaryPath();
+    method public boolean getBoundaryPath(@NonNull android.graphics.Path);
+    method @NonNull public android.graphics.Rect getBounds();
+    method public boolean getBounds(@NonNull android.graphics.Rect);
     method public boolean isComplex();
     method public boolean isEmpty();
     method public boolean isRect();
-    method public boolean op(android.graphics.Rect, android.graphics.Region.Op);
-    method public boolean op(int, int, int, int, android.graphics.Region.Op);
-    method public boolean op(android.graphics.Region, android.graphics.Region.Op);
-    method public boolean op(android.graphics.Rect, android.graphics.Region, android.graphics.Region.Op);
-    method public boolean op(android.graphics.Region, android.graphics.Region, android.graphics.Region.Op);
-    method public boolean quickContains(android.graphics.Rect);
+    method public boolean op(@NonNull android.graphics.Rect, @NonNull android.graphics.Region.Op);
+    method public boolean op(int, int, int, int, @NonNull android.graphics.Region.Op);
+    method public boolean op(@NonNull android.graphics.Region, @NonNull android.graphics.Region.Op);
+    method public boolean op(@NonNull android.graphics.Rect, @NonNull android.graphics.Region, @NonNull android.graphics.Region.Op);
+    method public boolean op(@NonNull android.graphics.Region, @NonNull android.graphics.Region, @NonNull android.graphics.Region.Op);
+    method public boolean quickContains(@NonNull android.graphics.Rect);
     method public boolean quickContains(int, int, int, int);
-    method public boolean quickReject(android.graphics.Rect);
+    method public boolean quickReject(@NonNull android.graphics.Rect);
     method public boolean quickReject(int, int, int, int);
     method public boolean quickReject(android.graphics.Region);
-    method public boolean set(android.graphics.Region);
-    method public boolean set(android.graphics.Rect);
+    method public boolean set(@NonNull android.graphics.Region);
+    method public boolean set(@NonNull android.graphics.Rect);
     method public boolean set(int, int, int, int);
     method public void setEmpty();
-    method public boolean setPath(android.graphics.Path, android.graphics.Region);
+    method public boolean setPath(@NonNull android.graphics.Path, @NonNull android.graphics.Region);
     method public void translate(int, int);
     method public void translate(int, int, android.graphics.Region);
-    method public final boolean union(android.graphics.Rect);
+    method public final boolean union(@NonNull android.graphics.Rect);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.graphics.Region> CREATOR;
   }
 
-  public static final class Region.Op extends java.lang.Enum {
-    method public static android.graphics.Region.Op valueOf(java.lang.String);
-    method public static final android.graphics.Region.Op[] values();
+  public enum Region.Op {
     enum_constant public static final android.graphics.Region.Op DIFFERENCE;
     enum_constant public static final android.graphics.Region.Op INTERSECT;
     enum_constant public static final android.graphics.Region.Op REPLACE;
@@ -14866,7 +14881,7 @@
   }
 
   public final class RenderNode {
-    ctor public RenderNode(java.lang.String);
+    ctor public RenderNode(@Nullable String);
     method public int computeApproximateMemoryUsage();
     method public void discardDisplayList();
     method public void endRecording();
@@ -14878,9 +14893,9 @@
     method public boolean getClipToOutline();
     method public float getElevation();
     method public int getHeight();
-    method public void getInverseMatrix(android.graphics.Matrix);
+    method public void getInverseMatrix(@NonNull android.graphics.Matrix);
     method public int getLeft();
-    method public void getMatrix(android.graphics.Matrix);
+    method public void getMatrix(@NonNull android.graphics.Matrix);
     method public float getPivotX();
     method public float getPivotY();
     method public int getRight();
@@ -14910,7 +14925,7 @@
     method public boolean setAmbientShadowColor(int);
     method public boolean setBottom(int);
     method public boolean setCameraDistance(float);
-    method public boolean setClipBounds(android.graphics.Rect);
+    method public boolean setClipBounds(@Nullable android.graphics.Rect);
     method public boolean setClipToBounds(boolean);
     method public boolean setClipToOutline(boolean);
     method public boolean setElevation(float);
@@ -14918,7 +14933,7 @@
     method public boolean setHasOverlappingRendering(boolean);
     method public boolean setLeft(int);
     method public boolean setLeftTopRightBottom(int, int, int, int);
-    method public boolean setOutline(android.graphics.Outline);
+    method public boolean setOutline(@Nullable android.graphics.Outline);
     method public boolean setPivotX(float);
     method public boolean setPivotY(float);
     method public boolean setProjectBackwards(boolean);
@@ -14934,20 +14949,18 @@
     method public boolean setTranslationX(float);
     method public boolean setTranslationY(float);
     method public boolean setTranslationZ(float);
-    method public boolean setUseCompositingLayer(boolean, android.graphics.Paint);
+    method public boolean setUseCompositingLayer(boolean, @Nullable android.graphics.Paint);
     method public android.graphics.RecordingCanvas startRecording(int, int);
     method public android.graphics.RecordingCanvas startRecording();
   }
 
   public class Shader {
-    ctor public deprecated Shader();
-    method public boolean getLocalMatrix(android.graphics.Matrix);
-    method public void setLocalMatrix(android.graphics.Matrix);
+    ctor @Deprecated public Shader();
+    method public boolean getLocalMatrix(@NonNull android.graphics.Matrix);
+    method public void setLocalMatrix(@Nullable android.graphics.Matrix);
   }
 
-  public static final class Shader.TileMode extends java.lang.Enum {
-    method public static android.graphics.Shader.TileMode valueOf(java.lang.String);
-    method public static final android.graphics.Shader.TileMode[] values();
+  public enum Shader.TileMode {
     enum_constant public static final android.graphics.Shader.TileMode CLAMP;
     enum_constant public static final android.graphics.Shader.TileMode MIRROR;
     enum_constant public static final android.graphics.Shader.TileMode REPEAT;
@@ -14969,35 +14982,35 @@
     method public void release();
     method public void releaseTexImage();
     method public void setDefaultBufferSize(int, int);
-    method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener);
-    method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener, android.os.Handler);
+    method public void setOnFrameAvailableListener(@Nullable android.graphics.SurfaceTexture.OnFrameAvailableListener);
+    method public void setOnFrameAvailableListener(@Nullable android.graphics.SurfaceTexture.OnFrameAvailableListener, @Nullable android.os.Handler);
     method public void updateTexImage();
   }
 
-  public static abstract interface SurfaceTexture.OnFrameAvailableListener {
-    method public abstract void onFrameAvailable(android.graphics.SurfaceTexture);
+  public static interface SurfaceTexture.OnFrameAvailableListener {
+    method public void onFrameAvailable(android.graphics.SurfaceTexture);
   }
 
-  public static deprecated class SurfaceTexture.OutOfResourcesException extends java.lang.Exception {
-    ctor public SurfaceTexture.OutOfResourcesException();
-    ctor public SurfaceTexture.OutOfResourcesException(java.lang.String);
+  @Deprecated public static class SurfaceTexture.OutOfResourcesException extends java.lang.Exception {
+    ctor @Deprecated public SurfaceTexture.OutOfResourcesException();
+    ctor @Deprecated public SurfaceTexture.OutOfResourcesException(String);
   }
 
   public class SweepGradient extends android.graphics.Shader {
-    ctor public SweepGradient(float, float, int[], float[]);
-    ctor public SweepGradient(float, float, int, int);
+    ctor public SweepGradient(float, float, @NonNull @ColorInt int[], @Nullable float[]);
+    ctor public SweepGradient(float, float, @ColorInt int, @ColorInt int);
   }
 
   public class Typeface {
-    method public static android.graphics.Typeface create(java.lang.String, int);
+    method public static android.graphics.Typeface create(String, int);
     method public static android.graphics.Typeface create(android.graphics.Typeface, int);
-    method public static android.graphics.Typeface create(android.graphics.Typeface, int, boolean);
-    method public static android.graphics.Typeface createFromAsset(android.content.res.AssetManager, java.lang.String);
-    method public static android.graphics.Typeface createFromFile(java.io.File);
-    method public static android.graphics.Typeface createFromFile(java.lang.String);
+    method @NonNull public static android.graphics.Typeface create(@Nullable android.graphics.Typeface, @IntRange(from=1, to=1000) int, boolean);
+    method public static android.graphics.Typeface createFromAsset(android.content.res.AssetManager, String);
+    method public static android.graphics.Typeface createFromFile(@Nullable java.io.File);
+    method public static android.graphics.Typeface createFromFile(@Nullable String);
     method public static android.graphics.Typeface defaultFromStyle(int);
     method public int getStyle();
-    method public int getWeight();
+    method @IntRange(from=0, to=1000) public int getWeight();
     method public final boolean isBold();
     method public final boolean isItalic();
     field public static final int BOLD = 1; // 0x1
@@ -15012,26 +15025,26 @@
   }
 
   public static final class Typeface.Builder {
-    ctor public Typeface.Builder(java.io.File);
-    ctor public Typeface.Builder(java.io.FileDescriptor);
-    ctor public Typeface.Builder(java.lang.String);
-    ctor public Typeface.Builder(android.content.res.AssetManager, java.lang.String);
+    ctor public Typeface.Builder(@NonNull java.io.File);
+    ctor public Typeface.Builder(@NonNull java.io.FileDescriptor);
+    ctor public Typeface.Builder(@NonNull String);
+    ctor public Typeface.Builder(@NonNull android.content.res.AssetManager, @NonNull String);
     method public android.graphics.Typeface build();
-    method public android.graphics.Typeface.Builder setFallback(java.lang.String);
-    method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String);
-    method public android.graphics.Typeface.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]);
+    method public android.graphics.Typeface.Builder setFallback(@Nullable String);
+    method public android.graphics.Typeface.Builder setFontVariationSettings(@Nullable String);
+    method public android.graphics.Typeface.Builder setFontVariationSettings(@Nullable android.graphics.fonts.FontVariationAxis[]);
     method public android.graphics.Typeface.Builder setItalic(boolean);
-    method public android.graphics.Typeface.Builder setTtcIndex(int);
-    method public android.graphics.Typeface.Builder setWeight(int);
+    method public android.graphics.Typeface.Builder setTtcIndex(@IntRange(from=0) int);
+    method public android.graphics.Typeface.Builder setWeight(@IntRange(from=1, to=1000) int);
   }
 
   public static class Typeface.CustomFallbackBuilder {
-    ctor public Typeface.CustomFallbackBuilder(android.graphics.fonts.FontFamily);
-    method public android.graphics.Typeface.CustomFallbackBuilder addCustomFallback(android.graphics.fonts.FontFamily);
+    ctor public Typeface.CustomFallbackBuilder(@NonNull android.graphics.fonts.FontFamily);
+    method public android.graphics.Typeface.CustomFallbackBuilder addCustomFallback(@NonNull android.graphics.fonts.FontFamily);
     method public android.graphics.Typeface build();
-    method public static int getMaxCustomFallbackCount();
-    method public android.graphics.Typeface.CustomFallbackBuilder setStyle(android.graphics.fonts.FontStyle);
-    method public android.graphics.Typeface.CustomFallbackBuilder setSystemFallback(java.lang.String);
+    method @IntRange(from=64) public static int getMaxCustomFallbackCount();
+    method public android.graphics.Typeface.CustomFallbackBuilder setStyle(@NonNull android.graphics.fonts.FontStyle);
+    method public android.graphics.Typeface.CustomFallbackBuilder setSystemFallback(@NonNull String);
   }
 
   public class Xfermode {
@@ -15060,28 +15073,28 @@
     method public android.graphics.drawable.Drawable getForeground();
     method public android.graphics.Path getIconMask();
     method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+    method public void invalidateDrawable(@NonNull android.graphics.drawable.Drawable);
+    method public void scheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable, long);
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
     method public void setDither(boolean);
     method public void setOpacity(int);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+    method public void unscheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable);
   }
 
-  public abstract interface Animatable {
-    method public abstract boolean isRunning();
-    method public abstract void start();
-    method public abstract void stop();
+  public interface Animatable {
+    method public boolean isRunning();
+    method public void start();
+    method public void stop();
   }
 
-  public abstract interface Animatable2 implements android.graphics.drawable.Animatable {
-    method public abstract void clearAnimationCallbacks();
-    method public abstract void registerAnimationCallback(android.graphics.drawable.Animatable2.AnimationCallback);
-    method public abstract boolean unregisterAnimationCallback(android.graphics.drawable.Animatable2.AnimationCallback);
+  public interface Animatable2 extends android.graphics.drawable.Animatable {
+    method public void clearAnimationCallbacks();
+    method public void registerAnimationCallback(@NonNull android.graphics.drawable.Animatable2.AnimationCallback);
+    method public boolean unregisterAnimationCallback(@NonNull android.graphics.drawable.Animatable2.AnimationCallback);
   }
 
-  public static abstract class Animatable2.AnimationCallback {
+  public abstract static class Animatable2.AnimationCallback {
     ctor public Animatable2.AnimationCallback();
     method public void onAnimationEnd(android.graphics.drawable.Drawable);
     method public void onAnimationStart(android.graphics.drawable.Drawable);
@@ -15090,25 +15103,25 @@
   public class AnimatedImageDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
     ctor public AnimatedImageDrawable();
     method public void clearAnimationCallbacks();
-    method public void draw(android.graphics.Canvas);
+    method public void draw(@NonNull android.graphics.Canvas);
     method public int getOpacity();
     method public int getRepeatCount();
     method public final boolean isAutoMirrored();
     method public boolean isRunning();
-    method public void registerAnimationCallback(android.graphics.drawable.Animatable2.AnimationCallback);
-    method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setRepeatCount(int);
+    method public void registerAnimationCallback(@NonNull android.graphics.drawable.Animatable2.AnimationCallback);
+    method public void setAlpha(@IntRange(from=0, to=255) int);
+    method public void setColorFilter(@Nullable android.graphics.ColorFilter);
+    method public void setRepeatCount(@IntRange(from=android.graphics.drawable.AnimatedImageDrawable.REPEAT_INFINITE) int);
     method public void start();
     method public void stop();
-    method public boolean unregisterAnimationCallback(android.graphics.drawable.Animatable2.AnimationCallback);
+    method public boolean unregisterAnimationCallback(@NonNull android.graphics.drawable.Animatable2.AnimationCallback);
     field public static final int REPEAT_INFINITE = -1; // 0xffffffff
   }
 
   public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
     ctor public AnimatedStateListDrawable();
-    method public void addState(int[], android.graphics.drawable.Drawable, int);
-    method public <T extends android.graphics.drawable.Drawable & android.graphics.drawable.Animatable> void addTransition(int, int, T, boolean);
+    method public void addState(@NonNull int[], @NonNull android.graphics.drawable.Drawable, int);
+    method public <T extends android.graphics.drawable.Drawable & android.graphics.drawable.Animatable> void addTransition(int, int, @NonNull T, boolean);
   }
 
   public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
@@ -15117,18 +15130,18 @@
     method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public boolean isRunning();
-    method public void registerAnimationCallback(android.graphics.drawable.Animatable2.AnimationCallback);
+    method public void registerAnimationCallback(@NonNull android.graphics.drawable.Animatable2.AnimationCallback);
     method public void reset();
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
     method public void start();
     method public void stop();
-    method public boolean unregisterAnimationCallback(android.graphics.drawable.Animatable2.AnimationCallback);
+    method public boolean unregisterAnimationCallback(@NonNull android.graphics.drawable.Animatable2.AnimationCallback);
   }
 
   public class AnimationDrawable extends android.graphics.drawable.DrawableContainer implements android.graphics.drawable.Animatable java.lang.Runnable {
     ctor public AnimationDrawable();
-    method public void addFrame(android.graphics.drawable.Drawable, int);
+    method public void addFrame(@NonNull android.graphics.drawable.Drawable, int);
     method public int getDuration(int);
     method public android.graphics.drawable.Drawable getFrame(int);
     method public int getNumberOfFrames();
@@ -15141,13 +15154,13 @@
   }
 
   public class BitmapDrawable extends android.graphics.drawable.Drawable {
-    ctor public deprecated BitmapDrawable();
-    ctor public deprecated BitmapDrawable(android.content.res.Resources);
-    ctor public deprecated BitmapDrawable(android.graphics.Bitmap);
+    ctor @Deprecated public BitmapDrawable();
+    ctor @Deprecated public BitmapDrawable(android.content.res.Resources);
+    ctor @Deprecated public BitmapDrawable(android.graphics.Bitmap);
     ctor public BitmapDrawable(android.content.res.Resources, android.graphics.Bitmap);
-    ctor public deprecated BitmapDrawable(java.lang.String);
-    ctor public BitmapDrawable(android.content.res.Resources, java.lang.String);
-    ctor public deprecated BitmapDrawable(java.io.InputStream);
+    ctor @Deprecated public BitmapDrawable(String);
+    ctor public BitmapDrawable(android.content.res.Resources, String);
+    ctor @Deprecated public BitmapDrawable(java.io.InputStream);
     ctor public BitmapDrawable(android.content.res.Resources, java.io.InputStream);
     method public void draw(android.graphics.Canvas);
     method public final android.graphics.Bitmap getBitmap();
@@ -15182,12 +15195,12 @@
 
   public class ColorDrawable extends android.graphics.drawable.Drawable {
     ctor public ColorDrawable();
-    ctor public ColorDrawable(int);
+    ctor public ColorDrawable(@ColorInt int);
     method public void draw(android.graphics.Canvas);
-    method public int getColor();
+    method @ColorInt public int getColor();
     method public int getOpacity();
     method public void setAlpha(int);
-    method public void setColor(int);
+    method public void setColor(@ColorInt int);
     method public void setColorFilter(android.graphics.ColorFilter);
   }
 
@@ -15196,56 +15209,56 @@
     ctor public ColorStateListDrawable(android.content.res.ColorStateList);
     method public void clearAlpha();
     method public void draw(android.graphics.Canvas);
-    method public android.content.res.ColorStateList getColorStateList();
+    method @NonNull public android.content.res.ColorStateList getColorStateList();
     method public int getOpacity();
     method public boolean hasFocusStateSpecified();
     method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
-    method public void setAlpha(int);
+    method public void scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long);
+    method public void setAlpha(@IntRange(from=0, to=255) int);
     method public void setColorFilter(android.graphics.ColorFilter);
     method public void setColorStateList(android.content.res.ColorStateList);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+    method public void unscheduleDrawable(android.graphics.drawable.Drawable, Runnable);
   }
 
   public abstract class Drawable {
     ctor public Drawable();
-    method public void applyTheme(android.content.res.Resources.Theme);
+    method public void applyTheme(@NonNull android.content.res.Resources.Theme);
     method public boolean canApplyTheme();
     method public void clearColorFilter();
-    method public final void copyBounds(android.graphics.Rect);
-    method public final android.graphics.Rect copyBounds();
-    method public static android.graphics.drawable.Drawable createFromPath(java.lang.String);
-    method public static android.graphics.drawable.Drawable createFromResourceStream(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, java.lang.String);
-    method public static deprecated android.graphics.drawable.Drawable createFromResourceStream(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, java.lang.String, android.graphics.BitmapFactory.Options);
-    method public static android.graphics.drawable.Drawable createFromStream(java.io.InputStream, java.lang.String);
-    method public static android.graphics.drawable.Drawable createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static android.graphics.drawable.Drawable createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static android.graphics.drawable.Drawable createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static android.graphics.drawable.Drawable createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public abstract void draw(android.graphics.Canvas);
-    method public int getAlpha();
-    method public final android.graphics.Rect getBounds();
-    method public android.graphics.drawable.Drawable.Callback getCallback();
+    method public final void copyBounds(@NonNull android.graphics.Rect);
+    method @NonNull public final android.graphics.Rect copyBounds();
+    method @Nullable public static android.graphics.drawable.Drawable createFromPath(String);
+    method public static android.graphics.drawable.Drawable createFromResourceStream(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, String);
+    method @Deprecated @Nullable public static android.graphics.drawable.Drawable createFromResourceStream(@Nullable android.content.res.Resources, @Nullable android.util.TypedValue, @Nullable java.io.InputStream, @Nullable String, @Nullable android.graphics.BitmapFactory.Options);
+    method public static android.graphics.drawable.Drawable createFromStream(java.io.InputStream, String);
+    method @NonNull public static android.graphics.drawable.Drawable createFromXml(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @NonNull public static android.graphics.drawable.Drawable createFromXml(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser, @Nullable android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @NonNull public static android.graphics.drawable.Drawable createFromXmlInner(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser, @NonNull android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @NonNull public static android.graphics.drawable.Drawable createFromXmlInner(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser, @NonNull android.util.AttributeSet, @Nullable android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public abstract void draw(@NonNull android.graphics.Canvas);
+    method @IntRange(from=0, to=255) public int getAlpha();
+    method @NonNull public final android.graphics.Rect getBounds();
+    method @Nullable public android.graphics.drawable.Drawable.Callback getCallback();
     method public int getChangingConfigurations();
-    method public android.graphics.ColorFilter getColorFilter();
-    method public android.graphics.drawable.Drawable.ConstantState getConstantState();
-    method public android.graphics.drawable.Drawable getCurrent();
-    method public android.graphics.Rect getDirtyBounds();
-    method public void getHotspotBounds(android.graphics.Rect);
+    method @Nullable public android.graphics.ColorFilter getColorFilter();
+    method @Nullable public android.graphics.drawable.Drawable.ConstantState getConstantState();
+    method @NonNull public android.graphics.drawable.Drawable getCurrent();
+    method @NonNull public android.graphics.Rect getDirtyBounds();
+    method public void getHotspotBounds(@NonNull android.graphics.Rect);
     method public int getIntrinsicHeight();
     method public int getIntrinsicWidth();
     method public int getLayoutDirection();
-    method public final int getLevel();
+    method @IntRange(from=0, to=10000) public final int getLevel();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
-    method public abstract deprecated int getOpacity();
-    method public android.graphics.Insets getOpticalInsets();
-    method public void getOutline(android.graphics.Outline);
-    method public boolean getPadding(android.graphics.Rect);
-    method public int[] getState();
-    method public android.graphics.Region getTransparentRegion();
-    method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @Deprecated public abstract int getOpacity();
+    method @NonNull public android.graphics.Insets getOpticalInsets();
+    method public void getOutline(@NonNull android.graphics.Outline);
+    method public boolean getPadding(@NonNull android.graphics.Rect);
+    method @NonNull public int[] getState();
+    method @Nullable public android.graphics.Region getTransparentRegion();
+    method public void inflate(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser, @NonNull android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void inflate(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser, @NonNull android.util.AttributeSet, @Nullable android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public void invalidateSelf();
     method public boolean isAutoMirrored();
     method public boolean isFilterBitmap();
@@ -15253,56 +15266,56 @@
     method public boolean isStateful();
     method public final boolean isVisible();
     method public void jumpToCurrentState();
-    method public android.graphics.drawable.Drawable mutate();
+    method @NonNull public android.graphics.drawable.Drawable mutate();
     method protected void onBoundsChange(android.graphics.Rect);
     method public boolean onLayoutDirectionChanged(int);
     method protected boolean onLevelChange(int);
     method protected boolean onStateChange(int[]);
     method public static int resolveOpacity(int, int);
-    method public void scheduleSelf(java.lang.Runnable, long);
-    method public abstract void setAlpha(int);
+    method public void scheduleSelf(@NonNull Runnable, long);
+    method public abstract void setAlpha(@IntRange(from=0, to=255) int);
     method public void setAutoMirrored(boolean);
     method public void setBounds(int, int, int, int);
-    method public void setBounds(android.graphics.Rect);
-    method public final void setCallback(android.graphics.drawable.Drawable.Callback);
+    method public void setBounds(@NonNull android.graphics.Rect);
+    method public final void setCallback(@Nullable android.graphics.drawable.Drawable.Callback);
     method public void setChangingConfigurations(int);
-    method public abstract void setColorFilter(android.graphics.ColorFilter);
-    method public deprecated void setColorFilter(int, android.graphics.PorterDuff.Mode);
-    method public deprecated void setDither(boolean);
+    method public abstract void setColorFilter(@Nullable android.graphics.ColorFilter);
+    method @Deprecated public void setColorFilter(@ColorInt int, @NonNull android.graphics.PorterDuff.Mode);
+    method @Deprecated public void setDither(boolean);
     method public void setFilterBitmap(boolean);
     method public void setHotspot(float, float);
     method public void setHotspotBounds(int, int, int, int);
     method public final boolean setLayoutDirection(int);
-    method public final boolean setLevel(int);
-    method public boolean setState(int[]);
-    method public void setTint(int);
-    method public void setTintList(android.content.res.ColorStateList);
-    method public void setTintMode(android.graphics.PorterDuff.Mode);
+    method public final boolean setLevel(@IntRange(from=0, to=10000) int);
+    method public boolean setState(@NonNull int[]);
+    method public void setTint(@ColorInt int);
+    method public void setTintList(@Nullable android.content.res.ColorStateList);
+    method public void setTintMode(@NonNull android.graphics.PorterDuff.Mode);
     method public boolean setVisible(boolean, boolean);
-    method public void unscheduleSelf(java.lang.Runnable);
+    method public void unscheduleSelf(@NonNull Runnable);
   }
 
-  public static abstract interface Drawable.Callback {
-    method public abstract void invalidateDrawable(android.graphics.drawable.Drawable);
-    method public abstract void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
-    method public abstract void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+  public static interface Drawable.Callback {
+    method public void invalidateDrawable(@NonNull android.graphics.drawable.Drawable);
+    method public void scheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable, long);
+    method public void unscheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable);
   }
 
-  public static abstract class Drawable.ConstantState {
+  public abstract static class Drawable.ConstantState {
     ctor public Drawable.ConstantState();
     method public boolean canApplyTheme();
     method public abstract int getChangingConfigurations();
-    method public abstract android.graphics.drawable.Drawable newDrawable();
-    method public android.graphics.drawable.Drawable newDrawable(android.content.res.Resources);
-    method public android.graphics.drawable.Drawable newDrawable(android.content.res.Resources, android.content.res.Resources.Theme);
+    method @NonNull public abstract android.graphics.drawable.Drawable newDrawable();
+    method @NonNull public android.graphics.drawable.Drawable newDrawable(@Nullable android.content.res.Resources);
+    method @NonNull public android.graphics.drawable.Drawable newDrawable(@Nullable android.content.res.Resources, @Nullable android.content.res.Resources.Theme);
   }
 
   public class DrawableContainer extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public DrawableContainer();
     method public void draw(android.graphics.Canvas);
     method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+    method public void invalidateDrawable(@NonNull android.graphics.drawable.Drawable);
+    method public void scheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable, long);
     method public boolean selectDrawable(int);
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
@@ -15310,12 +15323,12 @@
     method public void setDither(boolean);
     method public void setEnterFadeDuration(int);
     method public void setExitFadeDuration(int);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+    method public void unscheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable);
   }
 
-  public static abstract class DrawableContainer.DrawableContainerState extends android.graphics.drawable.Drawable.ConstantState {
+  public abstract static class DrawableContainer.DrawableContainerState extends android.graphics.drawable.Drawable.ConstantState {
     method public final int addChild(android.graphics.drawable.Drawable);
-    method public synchronized boolean canConstantState();
+    method public boolean canConstantState();
     method protected void computeConstantSize();
     method public int getChangingConfigurations();
     method public final android.graphics.drawable.Drawable getChild(int);
@@ -15339,25 +15352,25 @@
   }
 
   public abstract class DrawableWrapper extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
-    ctor public DrawableWrapper(android.graphics.drawable.Drawable);
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.drawable.Drawable getDrawable();
+    ctor public DrawableWrapper(@Nullable android.graphics.drawable.Drawable);
+    method public void draw(@NonNull android.graphics.Canvas);
+    method @Nullable public android.graphics.drawable.Drawable getDrawable();
     method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+    method public void invalidateDrawable(@NonNull android.graphics.drawable.Drawable);
+    method public void scheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable, long);
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setDrawable(android.graphics.drawable.Drawable);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+    method public void setColorFilter(@Nullable android.graphics.ColorFilter);
+    method public void setDrawable(@Nullable android.graphics.drawable.Drawable);
+    method public void unscheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable);
   }
 
   public class GradientDrawable extends android.graphics.drawable.Drawable {
     ctor public GradientDrawable();
-    ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]);
+    ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, @ColorInt int[]);
     method public void draw(android.graphics.Canvas);
-    method public android.content.res.ColorStateList getColor();
-    method public int[] getColors();
-    method public float[] getCornerRadii();
+    method @Nullable public android.content.res.ColorStateList getColor();
+    method @Nullable public int[] getColors();
+    method @Nullable public float[] getCornerRadii();
     method public float getCornerRadius();
     method public float getGradientCenterX();
     method public float getGradientCenterY();
@@ -15368,11 +15381,11 @@
     method public int getShape();
     method public boolean getUseLevel();
     method public void setAlpha(int);
-    method public void setColor(int);
-    method public void setColor(android.content.res.ColorStateList);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setColors(int[]);
-    method public void setCornerRadii(float[]);
+    method public void setColor(@ColorInt int);
+    method public void setColor(@Nullable android.content.res.ColorStateList);
+    method public void setColorFilter(@Nullable android.graphics.ColorFilter);
+    method public void setColors(@ColorInt int[]);
+    method public void setCornerRadii(@Nullable float[]);
     method public void setCornerRadius(float);
     method public void setDither(boolean);
     method public void setGradientCenter(float, float);
@@ -15381,9 +15394,9 @@
     method public void setOrientation(android.graphics.drawable.GradientDrawable.Orientation);
     method public void setShape(int);
     method public void setSize(int, int);
-    method public void setStroke(int, int);
+    method public void setStroke(int, @ColorInt int);
     method public void setStroke(int, android.content.res.ColorStateList);
-    method public void setStroke(int, int, float, float);
+    method public void setStroke(int, @ColorInt int, float, float);
     method public void setStroke(int, android.content.res.ColorStateList, float, float);
     method public void setUseLevel(boolean);
     field public static final int LINE = 2; // 0x2
@@ -15395,9 +15408,7 @@
     field public static final int SWEEP_GRADIENT = 2; // 0x2
   }
 
-  public static final class GradientDrawable.Orientation extends java.lang.Enum {
-    method public static android.graphics.drawable.GradientDrawable.Orientation valueOf(java.lang.String);
-    method public static final android.graphics.drawable.GradientDrawable.Orientation[] values();
+  public enum GradientDrawable.Orientation {
     enum_constant public static final android.graphics.drawable.GradientDrawable.Orientation BL_TR;
     enum_constant public static final android.graphics.drawable.GradientDrawable.Orientation BOTTOM_TOP;
     enum_constant public static final android.graphics.drawable.GradientDrawable.Orientation BR_TL;
@@ -15411,21 +15422,21 @@
   public final class Icon implements android.os.Parcelable {
     method public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap);
     method public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
-    method public static android.graphics.drawable.Icon createWithContentUri(java.lang.String);
+    method public static android.graphics.drawable.Icon createWithContentUri(String);
     method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
     method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
-    method public static android.graphics.drawable.Icon createWithFilePath(java.lang.String);
-    method public static android.graphics.drawable.Icon createWithResource(android.content.Context, int);
-    method public static android.graphics.drawable.Icon createWithResource(java.lang.String, int);
+    method public static android.graphics.drawable.Icon createWithFilePath(String);
+    method public static android.graphics.drawable.Icon createWithResource(android.content.Context, @DrawableRes int);
+    method public static android.graphics.drawable.Icon createWithResource(String, @DrawableRes int);
     method public int describeContents();
-    method public int getResId();
-    method public java.lang.String getResPackage();
+    method @IdRes public int getResId();
+    method @NonNull public String getResPackage();
     method public int getType();
-    method public android.net.Uri getUri();
+    method @NonNull public android.net.Uri getUri();
     method public android.graphics.drawable.Drawable loadDrawable(android.content.Context);
     method public void loadDrawableAsync(android.content.Context, android.os.Message);
     method public void loadDrawableAsync(android.content.Context, android.graphics.drawable.Icon.OnDrawableLoadedListener, android.os.Handler);
-    method public android.graphics.drawable.Icon setTint(int);
+    method public android.graphics.drawable.Icon setTint(@ColorInt int);
     method public android.graphics.drawable.Icon setTintList(android.content.res.ColorStateList);
     method public android.graphics.drawable.Icon setTintMode(android.graphics.PorterDuff.Mode);
     method public void writeToParcel(android.os.Parcel, int);
@@ -15437,19 +15448,19 @@
     field public static final int TYPE_URI = 4; // 0x4
   }
 
-  public static abstract interface Icon.OnDrawableLoadedListener {
-    method public abstract void onDrawableLoaded(android.graphics.drawable.Drawable);
+  public static interface Icon.OnDrawableLoadedListener {
+    method public void onDrawableLoaded(android.graphics.drawable.Drawable);
   }
 
   public class InsetDrawable extends android.graphics.drawable.DrawableWrapper {
-    ctor public InsetDrawable(android.graphics.drawable.Drawable, int);
-    ctor public InsetDrawable(android.graphics.drawable.Drawable, float);
-    ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int);
-    ctor public InsetDrawable(android.graphics.drawable.Drawable, float, float, float, float);
+    ctor public InsetDrawable(@Nullable android.graphics.drawable.Drawable, int);
+    ctor public InsetDrawable(@Nullable android.graphics.drawable.Drawable, float);
+    ctor public InsetDrawable(@Nullable android.graphics.drawable.Drawable, int, int, int, int);
+    ctor public InsetDrawable(@Nullable android.graphics.drawable.Drawable, float, float, float, float);
   }
 
   public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
-    ctor public LayerDrawable(android.graphics.drawable.Drawable[]);
+    ctor public LayerDrawable(@NonNull android.graphics.drawable.Drawable[]);
     method public int addLayer(android.graphics.drawable.Drawable);
     method public void draw(android.graphics.Canvas);
     method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
@@ -15474,8 +15485,8 @@
     method public int getRightPadding();
     method public int getStartPadding();
     method public int getTopPadding();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+    method public void invalidateDrawable(@NonNull android.graphics.drawable.Drawable);
+    method public void scheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable, long);
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
     method public void setDither(boolean);
@@ -15498,7 +15509,7 @@
     method public void setPadding(int, int, int, int);
     method public void setPaddingMode(int);
     method public void setPaddingRelative(int, int, int, int);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+    method public void unscheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable);
     field public static final int INSET_UNDEFINED = -2147483648; // 0x80000000
     field public static final int PADDING_MODE_NEST = 0; // 0x0
     field public static final int PADDING_MODE_STACK = 1; // 0x1
@@ -15510,18 +15521,18 @@
   }
 
   public class NinePatchDrawable extends android.graphics.drawable.Drawable {
-    ctor public deprecated NinePatchDrawable(android.graphics.Bitmap, byte[], android.graphics.Rect, java.lang.String);
-    ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.Bitmap, byte[], android.graphics.Rect, java.lang.String);
-    ctor public deprecated NinePatchDrawable(android.graphics.NinePatch);
-    ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.NinePatch);
+    ctor @Deprecated public NinePatchDrawable(android.graphics.Bitmap, byte[], android.graphics.Rect, String);
+    ctor public NinePatchDrawable(android.content.res.Resources, android.graphics.Bitmap, byte[], android.graphics.Rect, String);
+    ctor @Deprecated public NinePatchDrawable(@NonNull android.graphics.NinePatch);
+    ctor public NinePatchDrawable(@Nullable android.content.res.Resources, @NonNull android.graphics.NinePatch);
     method public void draw(android.graphics.Canvas);
     method public int getOpacity();
-    method public android.graphics.Paint getPaint();
+    method @NonNull public android.graphics.Paint getPaint();
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setColorFilter(@Nullable android.graphics.ColorFilter);
     method public void setDither(boolean);
-    method public void setTargetDensity(android.graphics.Canvas);
-    method public void setTargetDensity(android.util.DisplayMetrics);
+    method public void setTargetDensity(@NonNull android.graphics.Canvas);
+    method public void setTargetDensity(@NonNull android.util.DisplayMetrics);
     method public void setTargetDensity(int);
   }
 
@@ -15543,7 +15554,7 @@
   }
 
   public class RippleDrawable extends android.graphics.drawable.LayerDrawable {
-    ctor public RippleDrawable(android.content.res.ColorStateList, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+    ctor public RippleDrawable(@NonNull android.content.res.ColorStateList, @Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable);
     method public int getRadius();
     method public void setColor(android.content.res.ColorStateList);
     method public void setRadius(int);
@@ -15578,7 +15589,7 @@
     method public android.graphics.Paint getPaint();
     method public android.graphics.drawable.ShapeDrawable.ShaderFactory getShaderFactory();
     method public android.graphics.drawable.shapes.Shape getShape();
-    method protected boolean inflateTag(java.lang.String, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet);
+    method protected boolean inflateTag(String, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet);
     method protected void onDraw(android.graphics.drawable.shapes.Shape, android.graphics.Canvas, android.graphics.Paint);
     method public void setAlpha(int);
     method public void setColorFilter(android.graphics.ColorFilter);
@@ -15591,7 +15602,7 @@
     method public void setShape(android.graphics.drawable.shapes.Shape);
   }
 
-  public static abstract class ShapeDrawable.ShaderFactory {
+  public abstract static class ShapeDrawable.ShaderFactory {
     ctor public ShapeDrawable.ShaderFactory();
     method public abstract android.graphics.Shader resize(int, int);
   }
@@ -15639,7 +15650,7 @@
   }
 
   public class PathShape extends android.graphics.drawable.shapes.Shape {
-    ctor public PathShape(android.graphics.Path, float, float);
+    ctor public PathShape(@NonNull android.graphics.Path, float, float);
     method public android.graphics.drawable.shapes.PathShape clone() throws java.lang.CloneNotSupportedException;
     method public void draw(android.graphics.Canvas, android.graphics.Paint);
   }
@@ -15652,7 +15663,7 @@
   }
 
   public class RoundRectShape extends android.graphics.drawable.shapes.RectShape {
-    ctor public RoundRectShape(float[], android.graphics.RectF, float[]);
+    ctor public RoundRectShape(@Nullable float[], @Nullable android.graphics.RectF, @Nullable float[]);
     method public android.graphics.drawable.shapes.RoundRectShape clone() throws java.lang.CloneNotSupportedException;
   }
 
@@ -15661,7 +15672,7 @@
     method public android.graphics.drawable.shapes.Shape clone() throws java.lang.CloneNotSupportedException;
     method public abstract void draw(android.graphics.Canvas, android.graphics.Paint);
     method public final float getHeight();
-    method public void getOutline(android.graphics.Outline);
+    method public void getOutline(@NonNull android.graphics.Outline);
     method public final float getWidth();
     method public boolean hasAlpha();
     method protected void onResize(float, float);
@@ -15673,45 +15684,45 @@
 package android.graphics.fonts {
 
   public final class Font {
-    method public android.graphics.fonts.FontVariationAxis[] getAxes();
-    method public java.nio.ByteBuffer getBuffer();
-    method public java.io.File getFile();
-    method public android.os.LocaleList getLocaleList();
+    method @Nullable public android.graphics.fonts.FontVariationAxis[] getAxes();
+    method @NonNull public java.nio.ByteBuffer getBuffer();
+    method @Nullable public java.io.File getFile();
+    method @NonNull public android.os.LocaleList getLocaleList();
     method public android.graphics.fonts.FontStyle getStyle();
-    method public int getTtcIndex();
+    method @IntRange(from=0) public int getTtcIndex();
   }
 
   public static class Font.Builder {
-    ctor public Font.Builder(java.nio.ByteBuffer);
-    ctor public Font.Builder(java.io.File);
-    ctor public Font.Builder(java.io.FileDescriptor);
-    ctor public Font.Builder(java.io.FileDescriptor, long, long);
-    ctor public Font.Builder(android.content.res.AssetManager, java.lang.String);
-    ctor public Font.Builder(android.content.res.Resources, int);
-    method public android.graphics.fonts.Font build() throws java.io.IOException;
-    method public android.graphics.fonts.Font.Builder setFontVariationSettings(java.lang.String);
-    method public android.graphics.fonts.Font.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]);
-    method public android.graphics.fonts.Font.Builder setSlant(int);
-    method public android.graphics.fonts.Font.Builder setTtcIndex(int);
-    method public android.graphics.fonts.Font.Builder setWeight(int);
+    ctor public Font.Builder(@NonNull java.nio.ByteBuffer);
+    ctor public Font.Builder(@NonNull java.io.File);
+    ctor public Font.Builder(@NonNull java.io.FileDescriptor);
+    ctor public Font.Builder(@NonNull java.io.FileDescriptor, @IntRange(from=0) long, @IntRange(from=0xffffffff) long);
+    ctor public Font.Builder(@NonNull android.content.res.AssetManager, @NonNull String);
+    ctor public Font.Builder(@NonNull android.content.res.Resources, int);
+    method @Nullable public android.graphics.fonts.Font build() throws java.io.IOException;
+    method @NonNull public android.graphics.fonts.Font.Builder setFontVariationSettings(@Nullable String);
+    method @NonNull public android.graphics.fonts.Font.Builder setFontVariationSettings(@Nullable android.graphics.fonts.FontVariationAxis[]);
+    method @NonNull public android.graphics.fonts.Font.Builder setSlant(int);
+    method @NonNull public android.graphics.fonts.Font.Builder setTtcIndex(@IntRange(from=0) int);
+    method @NonNull public android.graphics.fonts.Font.Builder setWeight(@IntRange(from=android.graphics.fonts.FontStyle.FONT_WEIGHT_MIN, to=android.graphics.fonts.FontStyle.FONT_WEIGHT_MAX) int);
   }
 
   public final class FontFamily {
-    method public android.graphics.fonts.Font getFont(int);
+    method public android.graphics.fonts.Font getFont(@IntRange(from=0) int);
     method public int getSize();
   }
 
   public static class FontFamily.Builder {
-    ctor public FontFamily.Builder(android.graphics.fonts.Font);
-    method public android.graphics.fonts.FontFamily.Builder addFont(android.graphics.fonts.Font);
-    method public android.graphics.fonts.FontFamily build();
+    ctor public FontFamily.Builder(@NonNull android.graphics.fonts.Font);
+    method @NonNull public android.graphics.fonts.FontFamily.Builder addFont(@NonNull android.graphics.fonts.Font);
+    method @NonNull public android.graphics.fonts.FontFamily build();
   }
 
   public final class FontStyle {
     ctor public FontStyle();
     ctor public FontStyle(int, int);
     method public int getSlant();
-    method public int getWeight();
+    method @IntRange(from=0, to=1000) public int getWeight();
     field public static final int FONT_SLANT_ITALIC = 1; // 0x1
     field public static final int FONT_SLANT_UPRIGHT = 0; // 0x0
     field public static final int FONT_WEIGHT_BLACK = 900; // 0x384
@@ -15728,15 +15739,15 @@
   }
 
   public final class FontVariationAxis {
-    ctor public FontVariationAxis(java.lang.String, float);
-    method public static android.graphics.fonts.FontVariationAxis[] fromFontVariationSettings(java.lang.String);
+    ctor public FontVariationAxis(@NonNull String, float);
+    method @Nullable public static android.graphics.fonts.FontVariationAxis[] fromFontVariationSettings(@Nullable String);
     method public float getStyleValue();
-    method public java.lang.String getTag();
-    method public static java.lang.String toFontVariationSettings(android.graphics.fonts.FontVariationAxis[]);
+    method public String getTag();
+    method @NonNull public static String toFontVariationSettings(@Nullable android.graphics.fonts.FontVariationAxis[]);
   }
 
   public final class SystemFonts {
-    method public static java.util.Set<android.graphics.fonts.Font> getAvailableFonts();
+    method @NonNull public static java.util.Set<android.graphics.fonts.Font> getAvailableFonts();
   }
 
 }
@@ -15771,7 +15782,7 @@
   }
 
   public final class PdfRenderer implements java.lang.AutoCloseable {
-    ctor public PdfRenderer(android.os.ParcelFileDescriptor) throws java.io.IOException;
+    ctor public PdfRenderer(@NonNull android.os.ParcelFileDescriptor) throws java.io.IOException;
     method public void close();
     method public int getPageCount();
     method public android.graphics.pdf.PdfRenderer.Page openPage(int);
@@ -15783,7 +15794,7 @@
     method public int getHeight();
     method public int getIndex();
     method public int getWidth();
-    method public void render(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Matrix, int);
+    method public void render(@NonNull android.graphics.Bitmap, @Nullable android.graphics.Rect, @Nullable android.graphics.Matrix, int);
     field public static final int RENDER_MODE_FOR_DISPLAY = 1; // 0x1
     field public static final int RENDER_MODE_FOR_PRINT = 2; // 0x2
   }
@@ -15793,7 +15804,7 @@
 package android.graphics.text {
 
   public class LineBreaker {
-    method public android.graphics.text.LineBreaker.Result computeLineBreaks(android.graphics.text.MeasuredText, android.graphics.text.LineBreaker.ParagraphConstraints, int);
+    method public android.graphics.text.LineBreaker.Result computeLineBreaks(@NonNull android.graphics.text.MeasuredText, @NonNull android.graphics.text.LineBreaker.ParagraphConstraints, @IntRange(from=0) int);
     field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
     field public static final int BREAK_STRATEGY_HIGH_QUALITY = 1; // 0x1
     field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
@@ -15809,44 +15820,44 @@
     method public android.graphics.text.LineBreaker build();
     method public android.graphics.text.LineBreaker.Builder setBreakStrategy(int);
     method public android.graphics.text.LineBreaker.Builder setHyphenationFrequency(int);
-    method public android.graphics.text.LineBreaker.Builder setIndents(int[]);
+    method public android.graphics.text.LineBreaker.Builder setIndents(@Nullable int[]);
     method public android.graphics.text.LineBreaker.Builder setJustified(int);
   }
 
   public static class LineBreaker.ParagraphConstraints {
     ctor public LineBreaker.ParagraphConstraints();
-    method public int getDefaultTabStop();
-    method public float getFirstWidth();
-    method public int getFirstWidthLineCount();
-    method public int[] getTabStops();
-    method public float getWidth();
-    method public void setIndent(float, int);
-    method public void setTabStops(int[], int);
-    method public void setWidth(float);
+    method @Px @IntRange(from=0) public int getDefaultTabStop();
+    method @Px @FloatRange(from=0.0f) public float getFirstWidth();
+    method @Px @IntRange(from=0) public int getFirstWidthLineCount();
+    method @Nullable public int[] getTabStops();
+    method @Px @FloatRange(from=0.0f) public float getWidth();
+    method public void setIndent(@Px @FloatRange(from=0.0f) float, @Px @IntRange(from=0) int);
+    method public void setTabStops(@Nullable int[], @Px @IntRange(from=0) int);
+    method public void setWidth(@Px @FloatRange(from=0.0f) float);
   }
 
   public static class LineBreaker.Result {
-    method public float getLineAscent(int);
-    method public int getLineBreakOffset(int);
-    method public int getLineCount();
-    method public float getLineDescent(int);
+    method @Px public float getLineAscent(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getLineBreakOffset(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getLineCount();
+    method @Px public float getLineDescent(@IntRange(from=0) int);
     method public int getLineHyphenEdit(int);
-    method public float getLineWidth(int);
+    method @Px public float getLineWidth(@IntRange(from=0) int);
     method public boolean hasLineTab(int);
   }
 
   public class MeasuredText {
-    method public void getBounds(int, int, android.graphics.Rect);
-    method public float getCharWidthAt(int);
-    method public char[] getChars();
-    method public float getWidth(int, int);
+    method public void getBounds(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.Rect);
+    method @FloatRange(from=0.0f) @Px public float getCharWidthAt(@IntRange(from=0) int);
+    method @NonNull public char[] getChars();
+    method @FloatRange(from=0.0) @Px public float getWidth(@IntRange(from=0) int, @IntRange(from=0) int);
   }
 
   public static class MeasuredText.Builder {
-    ctor public MeasuredText.Builder(char[]);
-    ctor public MeasuredText.Builder(android.graphics.text.MeasuredText);
-    method public android.graphics.text.MeasuredText.Builder appendReplacementRun(android.graphics.Paint, int, float);
-    method public android.graphics.text.MeasuredText.Builder appendStyleRun(android.graphics.Paint, int, boolean);
+    ctor public MeasuredText.Builder(@NonNull char[]);
+    ctor public MeasuredText.Builder(@NonNull android.graphics.text.MeasuredText);
+    method public android.graphics.text.MeasuredText.Builder appendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @FloatRange(from=0) float);
+    method public android.graphics.text.MeasuredText.Builder appendStyleRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, boolean);
     method public android.graphics.text.MeasuredText build();
     method public android.graphics.text.MeasuredText.Builder setComputeHyphenation(boolean);
     method public android.graphics.text.MeasuredText.Builder setComputeLayout(boolean);
@@ -15856,258 +15867,258 @@
 
 package android.hardware {
 
-  public deprecated class Camera {
-    method public final void addCallbackBuffer(byte[]);
-    method public final void autoFocus(android.hardware.Camera.AutoFocusCallback);
-    method public final void cancelAutoFocus();
-    method public final boolean enableShutterSound(boolean);
-    method protected void finalize();
-    method public static void getCameraInfo(int, android.hardware.Camera.CameraInfo);
-    method public static int getNumberOfCameras();
-    method public android.hardware.Camera.Parameters getParameters();
-    method public final void lock();
-    method public static android.hardware.Camera open(int);
-    method public static android.hardware.Camera open();
-    method public final void reconnect() throws java.io.IOException;
-    method public final void release();
-    method public void setAutoFocusMoveCallback(android.hardware.Camera.AutoFocusMoveCallback);
-    method public final void setDisplayOrientation(int);
-    method public final void setErrorCallback(android.hardware.Camera.ErrorCallback);
-    method public final void setFaceDetectionListener(android.hardware.Camera.FaceDetectionListener);
-    method public final void setOneShotPreviewCallback(android.hardware.Camera.PreviewCallback);
-    method public void setParameters(android.hardware.Camera.Parameters);
-    method public final void setPreviewCallback(android.hardware.Camera.PreviewCallback);
-    method public final void setPreviewCallbackWithBuffer(android.hardware.Camera.PreviewCallback);
-    method public final void setPreviewDisplay(android.view.SurfaceHolder) throws java.io.IOException;
-    method public final void setPreviewTexture(android.graphics.SurfaceTexture) throws java.io.IOException;
-    method public final void setZoomChangeListener(android.hardware.Camera.OnZoomChangeListener);
-    method public final void startFaceDetection();
-    method public final void startPreview();
-    method public final void startSmoothZoom(int);
-    method public final void stopFaceDetection();
-    method public final void stopPreview();
-    method public final void stopSmoothZoom();
-    method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
-    method public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
-    method public final void unlock();
-    field public static final java.lang.String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
-    field public static final java.lang.String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
-    field public static final int CAMERA_ERROR_EVICTED = 2; // 0x2
-    field public static final int CAMERA_ERROR_SERVER_DIED = 100; // 0x64
-    field public static final int CAMERA_ERROR_UNKNOWN = 1; // 0x1
+  @Deprecated public class Camera {
+    method @Deprecated public final void addCallbackBuffer(byte[]);
+    method @Deprecated public final void autoFocus(android.hardware.Camera.AutoFocusCallback);
+    method @Deprecated public final void cancelAutoFocus();
+    method @Deprecated public final boolean enableShutterSound(boolean);
+    method @Deprecated protected void finalize();
+    method @Deprecated public static void getCameraInfo(int, android.hardware.Camera.CameraInfo);
+    method @Deprecated public static int getNumberOfCameras();
+    method @Deprecated public android.hardware.Camera.Parameters getParameters();
+    method @Deprecated public final void lock();
+    method @Deprecated public static android.hardware.Camera open(int);
+    method @Deprecated public static android.hardware.Camera open();
+    method @Deprecated public final void reconnect() throws java.io.IOException;
+    method @Deprecated public final void release();
+    method @Deprecated public void setAutoFocusMoveCallback(android.hardware.Camera.AutoFocusMoveCallback);
+    method @Deprecated public final void setDisplayOrientation(int);
+    method @Deprecated public final void setErrorCallback(android.hardware.Camera.ErrorCallback);
+    method @Deprecated public final void setFaceDetectionListener(android.hardware.Camera.FaceDetectionListener);
+    method @Deprecated public final void setOneShotPreviewCallback(android.hardware.Camera.PreviewCallback);
+    method @Deprecated public void setParameters(android.hardware.Camera.Parameters);
+    method @Deprecated public final void setPreviewCallback(android.hardware.Camera.PreviewCallback);
+    method @Deprecated public final void setPreviewCallbackWithBuffer(android.hardware.Camera.PreviewCallback);
+    method @Deprecated public final void setPreviewDisplay(android.view.SurfaceHolder) throws java.io.IOException;
+    method @Deprecated public final void setPreviewTexture(android.graphics.SurfaceTexture) throws java.io.IOException;
+    method @Deprecated public final void setZoomChangeListener(android.hardware.Camera.OnZoomChangeListener);
+    method @Deprecated public final void startFaceDetection();
+    method @Deprecated public final void startPreview();
+    method @Deprecated public final void startSmoothZoom(int);
+    method @Deprecated public final void stopFaceDetection();
+    method @Deprecated public final void stopPreview();
+    method @Deprecated public final void stopSmoothZoom();
+    method @Deprecated public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
+    method @Deprecated public final void takePicture(android.hardware.Camera.ShutterCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback, android.hardware.Camera.PictureCallback);
+    method @Deprecated public final void unlock();
+    field @Deprecated public static final String ACTION_NEW_PICTURE = "android.hardware.action.NEW_PICTURE";
+    field @Deprecated public static final String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO";
+    field @Deprecated public static final int CAMERA_ERROR_EVICTED = 2; // 0x2
+    field @Deprecated public static final int CAMERA_ERROR_SERVER_DIED = 100; // 0x64
+    field @Deprecated public static final int CAMERA_ERROR_UNKNOWN = 1; // 0x1
   }
 
-  public static deprecated class Camera.Area {
-    ctor public Camera.Area(android.graphics.Rect, int);
-    field public android.graphics.Rect rect;
-    field public int weight;
+  @Deprecated public static class Camera.Area {
+    ctor @Deprecated public Camera.Area(android.graphics.Rect, int);
+    field @Deprecated public android.graphics.Rect rect;
+    field @Deprecated public int weight;
   }
 
-  public static abstract deprecated interface Camera.AutoFocusCallback {
-    method public abstract void onAutoFocus(boolean, android.hardware.Camera);
+  @Deprecated public static interface Camera.AutoFocusCallback {
+    method @Deprecated public void onAutoFocus(boolean, android.hardware.Camera);
   }
 
-  public static abstract deprecated interface Camera.AutoFocusMoveCallback {
-    method public abstract void onAutoFocusMoving(boolean, android.hardware.Camera);
+  @Deprecated public static interface Camera.AutoFocusMoveCallback {
+    method @Deprecated public void onAutoFocusMoving(boolean, android.hardware.Camera);
   }
 
-  public static deprecated class Camera.CameraInfo {
-    ctor public Camera.CameraInfo();
-    field public static final int CAMERA_FACING_BACK = 0; // 0x0
-    field public static final int CAMERA_FACING_FRONT = 1; // 0x1
-    field public boolean canDisableShutterSound;
-    field public int facing;
-    field public int orientation;
+  @Deprecated public static class Camera.CameraInfo {
+    ctor @Deprecated public Camera.CameraInfo();
+    field @Deprecated public static final int CAMERA_FACING_BACK = 0; // 0x0
+    field @Deprecated public static final int CAMERA_FACING_FRONT = 1; // 0x1
+    field @Deprecated public boolean canDisableShutterSound;
+    field @Deprecated public int facing;
+    field @Deprecated public int orientation;
   }
 
-  public static abstract deprecated interface Camera.ErrorCallback {
-    method public abstract void onError(int, android.hardware.Camera);
+  @Deprecated public static interface Camera.ErrorCallback {
+    method @Deprecated public void onError(int, android.hardware.Camera);
   }
 
-  public static deprecated class Camera.Face {
-    ctor public Camera.Face();
-    field public int id;
-    field public android.graphics.Point leftEye;
-    field public android.graphics.Point mouth;
-    field public android.graphics.Rect rect;
-    field public android.graphics.Point rightEye;
-    field public int score;
+  @Deprecated public static class Camera.Face {
+    ctor @Deprecated public Camera.Face();
+    field @Deprecated public int id;
+    field @Deprecated public android.graphics.Point leftEye;
+    field @Deprecated public android.graphics.Point mouth;
+    field @Deprecated public android.graphics.Rect rect;
+    field @Deprecated public android.graphics.Point rightEye;
+    field @Deprecated public int score;
   }
 
-  public static abstract deprecated interface Camera.FaceDetectionListener {
-    method public abstract void onFaceDetection(android.hardware.Camera.Face[], android.hardware.Camera);
+  @Deprecated public static interface Camera.FaceDetectionListener {
+    method @Deprecated public void onFaceDetection(android.hardware.Camera.Face[], android.hardware.Camera);
   }
 
-  public static abstract deprecated interface Camera.OnZoomChangeListener {
-    method public abstract void onZoomChange(int, boolean, android.hardware.Camera);
+  @Deprecated public static interface Camera.OnZoomChangeListener {
+    method @Deprecated public void onZoomChange(int, boolean, android.hardware.Camera);
   }
 
-  public deprecated class Camera.Parameters {
-    method public java.lang.String flatten();
-    method public java.lang.String get(java.lang.String);
-    method public java.lang.String getAntibanding();
-    method public boolean getAutoExposureLock();
-    method public boolean getAutoWhiteBalanceLock();
-    method public java.lang.String getColorEffect();
-    method public int getExposureCompensation();
-    method public float getExposureCompensationStep();
-    method public java.lang.String getFlashMode();
-    method public float getFocalLength();
-    method public java.util.List<android.hardware.Camera.Area> getFocusAreas();
-    method public void getFocusDistances(float[]);
-    method public java.lang.String getFocusMode();
-    method public float getHorizontalViewAngle();
-    method public int getInt(java.lang.String);
-    method public int getJpegQuality();
-    method public int getJpegThumbnailQuality();
-    method public android.hardware.Camera.Size getJpegThumbnailSize();
-    method public int getMaxExposureCompensation();
-    method public int getMaxNumDetectedFaces();
-    method public int getMaxNumFocusAreas();
-    method public int getMaxNumMeteringAreas();
-    method public int getMaxZoom();
-    method public java.util.List<android.hardware.Camera.Area> getMeteringAreas();
-    method public int getMinExposureCompensation();
-    method public int getPictureFormat();
-    method public android.hardware.Camera.Size getPictureSize();
-    method public android.hardware.Camera.Size getPreferredPreviewSizeForVideo();
-    method public int getPreviewFormat();
-    method public void getPreviewFpsRange(int[]);
-    method public deprecated int getPreviewFrameRate();
-    method public android.hardware.Camera.Size getPreviewSize();
-    method public java.lang.String getSceneMode();
-    method public java.util.List<java.lang.String> getSupportedAntibanding();
-    method public java.util.List<java.lang.String> getSupportedColorEffects();
-    method public java.util.List<java.lang.String> getSupportedFlashModes();
-    method public java.util.List<java.lang.String> getSupportedFocusModes();
-    method public java.util.List<android.hardware.Camera.Size> getSupportedJpegThumbnailSizes();
-    method public java.util.List<java.lang.Integer> getSupportedPictureFormats();
-    method public java.util.List<android.hardware.Camera.Size> getSupportedPictureSizes();
-    method public java.util.List<java.lang.Integer> getSupportedPreviewFormats();
-    method public java.util.List<int[]> getSupportedPreviewFpsRange();
-    method public deprecated java.util.List<java.lang.Integer> getSupportedPreviewFrameRates();
-    method public java.util.List<android.hardware.Camera.Size> getSupportedPreviewSizes();
-    method public java.util.List<java.lang.String> getSupportedSceneModes();
-    method public java.util.List<android.hardware.Camera.Size> getSupportedVideoSizes();
-    method public java.util.List<java.lang.String> getSupportedWhiteBalance();
-    method public float getVerticalViewAngle();
-    method public boolean getVideoStabilization();
-    method public java.lang.String getWhiteBalance();
-    method public int getZoom();
-    method public java.util.List<java.lang.Integer> getZoomRatios();
-    method public boolean isAutoExposureLockSupported();
-    method public boolean isAutoWhiteBalanceLockSupported();
-    method public boolean isSmoothZoomSupported();
-    method public boolean isVideoSnapshotSupported();
-    method public boolean isVideoStabilizationSupported();
-    method public boolean isZoomSupported();
-    method public void remove(java.lang.String);
-    method public void removeGpsData();
-    method public void set(java.lang.String, java.lang.String);
-    method public void set(java.lang.String, int);
-    method public void setAntibanding(java.lang.String);
-    method public void setAutoExposureLock(boolean);
-    method public void setAutoWhiteBalanceLock(boolean);
-    method public void setColorEffect(java.lang.String);
-    method public void setExposureCompensation(int);
-    method public void setFlashMode(java.lang.String);
-    method public void setFocusAreas(java.util.List<android.hardware.Camera.Area>);
-    method public void setFocusMode(java.lang.String);
-    method public void setGpsAltitude(double);
-    method public void setGpsLatitude(double);
-    method public void setGpsLongitude(double);
-    method public void setGpsProcessingMethod(java.lang.String);
-    method public void setGpsTimestamp(long);
-    method public void setJpegQuality(int);
-    method public void setJpegThumbnailQuality(int);
-    method public void setJpegThumbnailSize(int, int);
-    method public void setMeteringAreas(java.util.List<android.hardware.Camera.Area>);
-    method public void setPictureFormat(int);
-    method public void setPictureSize(int, int);
-    method public void setPreviewFormat(int);
-    method public void setPreviewFpsRange(int, int);
-    method public deprecated void setPreviewFrameRate(int);
-    method public void setPreviewSize(int, int);
-    method public void setRecordingHint(boolean);
-    method public void setRotation(int);
-    method public void setSceneMode(java.lang.String);
-    method public void setVideoStabilization(boolean);
-    method public void setWhiteBalance(java.lang.String);
-    method public void setZoom(int);
-    method public void unflatten(java.lang.String);
-    field public static final java.lang.String ANTIBANDING_50HZ = "50hz";
-    field public static final java.lang.String ANTIBANDING_60HZ = "60hz";
-    field public static final java.lang.String ANTIBANDING_AUTO = "auto";
-    field public static final java.lang.String ANTIBANDING_OFF = "off";
-    field public static final java.lang.String EFFECT_AQUA = "aqua";
-    field public static final java.lang.String EFFECT_BLACKBOARD = "blackboard";
-    field public static final java.lang.String EFFECT_MONO = "mono";
-    field public static final java.lang.String EFFECT_NEGATIVE = "negative";
-    field public static final java.lang.String EFFECT_NONE = "none";
-    field public static final java.lang.String EFFECT_POSTERIZE = "posterize";
-    field public static final java.lang.String EFFECT_SEPIA = "sepia";
-    field public static final java.lang.String EFFECT_SOLARIZE = "solarize";
-    field public static final java.lang.String EFFECT_WHITEBOARD = "whiteboard";
-    field public static final java.lang.String FLASH_MODE_AUTO = "auto";
-    field public static final java.lang.String FLASH_MODE_OFF = "off";
-    field public static final java.lang.String FLASH_MODE_ON = "on";
-    field public static final java.lang.String FLASH_MODE_RED_EYE = "red-eye";
-    field public static final java.lang.String FLASH_MODE_TORCH = "torch";
-    field public static final int FOCUS_DISTANCE_FAR_INDEX = 2; // 0x2
-    field public static final int FOCUS_DISTANCE_NEAR_INDEX = 0; // 0x0
-    field public static final int FOCUS_DISTANCE_OPTIMAL_INDEX = 1; // 0x1
-    field public static final java.lang.String FOCUS_MODE_AUTO = "auto";
-    field public static final java.lang.String FOCUS_MODE_CONTINUOUS_PICTURE = "continuous-picture";
-    field public static final java.lang.String FOCUS_MODE_CONTINUOUS_VIDEO = "continuous-video";
-    field public static final java.lang.String FOCUS_MODE_EDOF = "edof";
-    field public static final java.lang.String FOCUS_MODE_FIXED = "fixed";
-    field public static final java.lang.String FOCUS_MODE_INFINITY = "infinity";
-    field public static final java.lang.String FOCUS_MODE_MACRO = "macro";
-    field public static final int PREVIEW_FPS_MAX_INDEX = 1; // 0x1
-    field public static final int PREVIEW_FPS_MIN_INDEX = 0; // 0x0
-    field public static final java.lang.String SCENE_MODE_ACTION = "action";
-    field public static final java.lang.String SCENE_MODE_AUTO = "auto";
-    field public static final java.lang.String SCENE_MODE_BARCODE = "barcode";
-    field public static final java.lang.String SCENE_MODE_BEACH = "beach";
-    field public static final java.lang.String SCENE_MODE_CANDLELIGHT = "candlelight";
-    field public static final java.lang.String SCENE_MODE_FIREWORKS = "fireworks";
-    field public static final java.lang.String SCENE_MODE_HDR = "hdr";
-    field public static final java.lang.String SCENE_MODE_LANDSCAPE = "landscape";
-    field public static final java.lang.String SCENE_MODE_NIGHT = "night";
-    field public static final java.lang.String SCENE_MODE_NIGHT_PORTRAIT = "night-portrait";
-    field public static final java.lang.String SCENE_MODE_PARTY = "party";
-    field public static final java.lang.String SCENE_MODE_PORTRAIT = "portrait";
-    field public static final java.lang.String SCENE_MODE_SNOW = "snow";
-    field public static final java.lang.String SCENE_MODE_SPORTS = "sports";
-    field public static final java.lang.String SCENE_MODE_STEADYPHOTO = "steadyphoto";
-    field public static final java.lang.String SCENE_MODE_SUNSET = "sunset";
-    field public static final java.lang.String SCENE_MODE_THEATRE = "theatre";
-    field public static final java.lang.String WHITE_BALANCE_AUTO = "auto";
-    field public static final java.lang.String WHITE_BALANCE_CLOUDY_DAYLIGHT = "cloudy-daylight";
-    field public static final java.lang.String WHITE_BALANCE_DAYLIGHT = "daylight";
-    field public static final java.lang.String WHITE_BALANCE_FLUORESCENT = "fluorescent";
-    field public static final java.lang.String WHITE_BALANCE_INCANDESCENT = "incandescent";
-    field public static final java.lang.String WHITE_BALANCE_SHADE = "shade";
-    field public static final java.lang.String WHITE_BALANCE_TWILIGHT = "twilight";
-    field public static final java.lang.String WHITE_BALANCE_WARM_FLUORESCENT = "warm-fluorescent";
+  @Deprecated public class Camera.Parameters {
+    method @Deprecated public String flatten();
+    method @Deprecated public String get(String);
+    method @Deprecated public String getAntibanding();
+    method @Deprecated public boolean getAutoExposureLock();
+    method @Deprecated public boolean getAutoWhiteBalanceLock();
+    method @Deprecated public String getColorEffect();
+    method @Deprecated public int getExposureCompensation();
+    method @Deprecated public float getExposureCompensationStep();
+    method @Deprecated public String getFlashMode();
+    method @Deprecated public float getFocalLength();
+    method @Deprecated public java.util.List<android.hardware.Camera.Area> getFocusAreas();
+    method @Deprecated public void getFocusDistances(float[]);
+    method @Deprecated public String getFocusMode();
+    method @Deprecated public float getHorizontalViewAngle();
+    method @Deprecated public int getInt(String);
+    method @Deprecated public int getJpegQuality();
+    method @Deprecated public int getJpegThumbnailQuality();
+    method @Deprecated public android.hardware.Camera.Size getJpegThumbnailSize();
+    method @Deprecated public int getMaxExposureCompensation();
+    method @Deprecated public int getMaxNumDetectedFaces();
+    method @Deprecated public int getMaxNumFocusAreas();
+    method @Deprecated public int getMaxNumMeteringAreas();
+    method @Deprecated public int getMaxZoom();
+    method @Deprecated public java.util.List<android.hardware.Camera.Area> getMeteringAreas();
+    method @Deprecated public int getMinExposureCompensation();
+    method @Deprecated public int getPictureFormat();
+    method @Deprecated public android.hardware.Camera.Size getPictureSize();
+    method @Deprecated public android.hardware.Camera.Size getPreferredPreviewSizeForVideo();
+    method @Deprecated public int getPreviewFormat();
+    method @Deprecated public void getPreviewFpsRange(int[]);
+    method @Deprecated public int getPreviewFrameRate();
+    method @Deprecated public android.hardware.Camera.Size getPreviewSize();
+    method @Deprecated public String getSceneMode();
+    method @Deprecated public java.util.List<java.lang.String> getSupportedAntibanding();
+    method @Deprecated public java.util.List<java.lang.String> getSupportedColorEffects();
+    method @Deprecated public java.util.List<java.lang.String> getSupportedFlashModes();
+    method @Deprecated public java.util.List<java.lang.String> getSupportedFocusModes();
+    method @Deprecated public java.util.List<android.hardware.Camera.Size> getSupportedJpegThumbnailSizes();
+    method @Deprecated public java.util.List<java.lang.Integer> getSupportedPictureFormats();
+    method @Deprecated public java.util.List<android.hardware.Camera.Size> getSupportedPictureSizes();
+    method @Deprecated public java.util.List<java.lang.Integer> getSupportedPreviewFormats();
+    method @Deprecated public java.util.List<int[]> getSupportedPreviewFpsRange();
+    method @Deprecated public java.util.List<java.lang.Integer> getSupportedPreviewFrameRates();
+    method @Deprecated public java.util.List<android.hardware.Camera.Size> getSupportedPreviewSizes();
+    method @Deprecated public java.util.List<java.lang.String> getSupportedSceneModes();
+    method @Deprecated public java.util.List<android.hardware.Camera.Size> getSupportedVideoSizes();
+    method @Deprecated public java.util.List<java.lang.String> getSupportedWhiteBalance();
+    method @Deprecated public float getVerticalViewAngle();
+    method @Deprecated public boolean getVideoStabilization();
+    method @Deprecated public String getWhiteBalance();
+    method @Deprecated public int getZoom();
+    method @Deprecated public java.util.List<java.lang.Integer> getZoomRatios();
+    method @Deprecated public boolean isAutoExposureLockSupported();
+    method @Deprecated public boolean isAutoWhiteBalanceLockSupported();
+    method @Deprecated public boolean isSmoothZoomSupported();
+    method @Deprecated public boolean isVideoSnapshotSupported();
+    method @Deprecated public boolean isVideoStabilizationSupported();
+    method @Deprecated public boolean isZoomSupported();
+    method @Deprecated public void remove(String);
+    method @Deprecated public void removeGpsData();
+    method @Deprecated public void set(String, String);
+    method @Deprecated public void set(String, int);
+    method @Deprecated public void setAntibanding(String);
+    method @Deprecated public void setAutoExposureLock(boolean);
+    method @Deprecated public void setAutoWhiteBalanceLock(boolean);
+    method @Deprecated public void setColorEffect(String);
+    method @Deprecated public void setExposureCompensation(int);
+    method @Deprecated public void setFlashMode(String);
+    method @Deprecated public void setFocusAreas(java.util.List<android.hardware.Camera.Area>);
+    method @Deprecated public void setFocusMode(String);
+    method @Deprecated public void setGpsAltitude(double);
+    method @Deprecated public void setGpsLatitude(double);
+    method @Deprecated public void setGpsLongitude(double);
+    method @Deprecated public void setGpsProcessingMethod(String);
+    method @Deprecated public void setGpsTimestamp(long);
+    method @Deprecated public void setJpegQuality(int);
+    method @Deprecated public void setJpegThumbnailQuality(int);
+    method @Deprecated public void setJpegThumbnailSize(int, int);
+    method @Deprecated public void setMeteringAreas(java.util.List<android.hardware.Camera.Area>);
+    method @Deprecated public void setPictureFormat(int);
+    method @Deprecated public void setPictureSize(int, int);
+    method @Deprecated public void setPreviewFormat(int);
+    method @Deprecated public void setPreviewFpsRange(int, int);
+    method @Deprecated public void setPreviewFrameRate(int);
+    method @Deprecated public void setPreviewSize(int, int);
+    method @Deprecated public void setRecordingHint(boolean);
+    method @Deprecated public void setRotation(int);
+    method @Deprecated public void setSceneMode(String);
+    method @Deprecated public void setVideoStabilization(boolean);
+    method @Deprecated public void setWhiteBalance(String);
+    method @Deprecated public void setZoom(int);
+    method @Deprecated public void unflatten(String);
+    field @Deprecated public static final String ANTIBANDING_50HZ = "50hz";
+    field @Deprecated public static final String ANTIBANDING_60HZ = "60hz";
+    field @Deprecated public static final String ANTIBANDING_AUTO = "auto";
+    field @Deprecated public static final String ANTIBANDING_OFF = "off";
+    field @Deprecated public static final String EFFECT_AQUA = "aqua";
+    field @Deprecated public static final String EFFECT_BLACKBOARD = "blackboard";
+    field @Deprecated public static final String EFFECT_MONO = "mono";
+    field @Deprecated public static final String EFFECT_NEGATIVE = "negative";
+    field @Deprecated public static final String EFFECT_NONE = "none";
+    field @Deprecated public static final String EFFECT_POSTERIZE = "posterize";
+    field @Deprecated public static final String EFFECT_SEPIA = "sepia";
+    field @Deprecated public static final String EFFECT_SOLARIZE = "solarize";
+    field @Deprecated public static final String EFFECT_WHITEBOARD = "whiteboard";
+    field @Deprecated public static final String FLASH_MODE_AUTO = "auto";
+    field @Deprecated public static final String FLASH_MODE_OFF = "off";
+    field @Deprecated public static final String FLASH_MODE_ON = "on";
+    field @Deprecated public static final String FLASH_MODE_RED_EYE = "red-eye";
+    field @Deprecated public static final String FLASH_MODE_TORCH = "torch";
+    field @Deprecated public static final int FOCUS_DISTANCE_FAR_INDEX = 2; // 0x2
+    field @Deprecated public static final int FOCUS_DISTANCE_NEAR_INDEX = 0; // 0x0
+    field @Deprecated public static final int FOCUS_DISTANCE_OPTIMAL_INDEX = 1; // 0x1
+    field @Deprecated public static final String FOCUS_MODE_AUTO = "auto";
+    field @Deprecated public static final String FOCUS_MODE_CONTINUOUS_PICTURE = "continuous-picture";
+    field @Deprecated public static final String FOCUS_MODE_CONTINUOUS_VIDEO = "continuous-video";
+    field @Deprecated public static final String FOCUS_MODE_EDOF = "edof";
+    field @Deprecated public static final String FOCUS_MODE_FIXED = "fixed";
+    field @Deprecated public static final String FOCUS_MODE_INFINITY = "infinity";
+    field @Deprecated public static final String FOCUS_MODE_MACRO = "macro";
+    field @Deprecated public static final int PREVIEW_FPS_MAX_INDEX = 1; // 0x1
+    field @Deprecated public static final int PREVIEW_FPS_MIN_INDEX = 0; // 0x0
+    field @Deprecated public static final String SCENE_MODE_ACTION = "action";
+    field @Deprecated public static final String SCENE_MODE_AUTO = "auto";
+    field @Deprecated public static final String SCENE_MODE_BARCODE = "barcode";
+    field @Deprecated public static final String SCENE_MODE_BEACH = "beach";
+    field @Deprecated public static final String SCENE_MODE_CANDLELIGHT = "candlelight";
+    field @Deprecated public static final String SCENE_MODE_FIREWORKS = "fireworks";
+    field @Deprecated public static final String SCENE_MODE_HDR = "hdr";
+    field @Deprecated public static final String SCENE_MODE_LANDSCAPE = "landscape";
+    field @Deprecated public static final String SCENE_MODE_NIGHT = "night";
+    field @Deprecated public static final String SCENE_MODE_NIGHT_PORTRAIT = "night-portrait";
+    field @Deprecated public static final String SCENE_MODE_PARTY = "party";
+    field @Deprecated public static final String SCENE_MODE_PORTRAIT = "portrait";
+    field @Deprecated public static final String SCENE_MODE_SNOW = "snow";
+    field @Deprecated public static final String SCENE_MODE_SPORTS = "sports";
+    field @Deprecated public static final String SCENE_MODE_STEADYPHOTO = "steadyphoto";
+    field @Deprecated public static final String SCENE_MODE_SUNSET = "sunset";
+    field @Deprecated public static final String SCENE_MODE_THEATRE = "theatre";
+    field @Deprecated public static final String WHITE_BALANCE_AUTO = "auto";
+    field @Deprecated public static final String WHITE_BALANCE_CLOUDY_DAYLIGHT = "cloudy-daylight";
+    field @Deprecated public static final String WHITE_BALANCE_DAYLIGHT = "daylight";
+    field @Deprecated public static final String WHITE_BALANCE_FLUORESCENT = "fluorescent";
+    field @Deprecated public static final String WHITE_BALANCE_INCANDESCENT = "incandescent";
+    field @Deprecated public static final String WHITE_BALANCE_SHADE = "shade";
+    field @Deprecated public static final String WHITE_BALANCE_TWILIGHT = "twilight";
+    field @Deprecated public static final String WHITE_BALANCE_WARM_FLUORESCENT = "warm-fluorescent";
   }
 
-  public static abstract deprecated interface Camera.PictureCallback {
-    method public abstract void onPictureTaken(byte[], android.hardware.Camera);
+  @Deprecated public static interface Camera.PictureCallback {
+    method @Deprecated public void onPictureTaken(byte[], android.hardware.Camera);
   }
 
-  public static abstract deprecated interface Camera.PreviewCallback {
-    method public abstract void onPreviewFrame(byte[], android.hardware.Camera);
+  @Deprecated public static interface Camera.PreviewCallback {
+    method @Deprecated public void onPreviewFrame(byte[], android.hardware.Camera);
   }
 
-  public static abstract deprecated interface Camera.ShutterCallback {
-    method public abstract void onShutter();
+  @Deprecated public static interface Camera.ShutterCallback {
+    method @Deprecated public void onShutter();
   }
 
-  public deprecated class Camera.Size {
-    ctor public Camera.Size(int, int);
-    field public int height;
-    field public int width;
+  @Deprecated public class Camera.Size {
+    ctor @Deprecated public Camera.Size(int, int);
+    field @Deprecated public int height;
+    field @Deprecated public int width;
   }
 
   public final class ConsumerIrManager {
@@ -16135,7 +16146,7 @@
 
   public final class HardwareBuffer implements java.lang.AutoCloseable android.os.Parcelable {
     method public void close();
-    method public static android.hardware.HardwareBuffer create(int, int, int, int, long);
+    method @NonNull public static android.hardware.HardwareBuffer create(int, int, int, int, long);
     method public int describeContents();
     method public int getFormat();
     method public int getHeight();
@@ -16180,13 +16191,13 @@
     method public int getMaxDelay();
     method public float getMaximumRange();
     method public int getMinDelay();
-    method public java.lang.String getName();
+    method public String getName();
     method public float getPower();
     method public int getReportingMode();
     method public float getResolution();
-    method public java.lang.String getStringType();
+    method public String getStringType();
     method public int getType();
-    method public java.lang.String getVendor();
+    method public String getVendor();
     method public int getVersion();
     method public boolean isAdditionalInfoSupported();
     method public boolean isDirectChannelTypeSupported(int);
@@ -16196,33 +16207,33 @@
     field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
     field public static final int REPORTING_MODE_ON_CHANGE = 1; // 0x1
     field public static final int REPORTING_MODE_SPECIAL_TRIGGER = 3; // 0x3
-    field public static final java.lang.String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
-    field public static final java.lang.String STRING_TYPE_ACCELEROMETER_UNCALIBRATED = "android.sensor.accelerometer_uncalibrated";
-    field public static final java.lang.String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
-    field public static final java.lang.String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
-    field public static final java.lang.String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR = "android.sensor.geomagnetic_rotation_vector";
-    field public static final java.lang.String STRING_TYPE_GRAVITY = "android.sensor.gravity";
-    field public static final java.lang.String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
-    field public static final java.lang.String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
-    field public static final java.lang.String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat";
-    field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
-    field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
-    field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
-    field public static final java.lang.String STRING_TYPE_LOW_LATENCY_OFFBODY_DETECT = "android.sensor.low_latency_offbody_detect";
-    field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
-    field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
-    field public static final java.lang.String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
-    field public static final deprecated java.lang.String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
-    field public static final java.lang.String STRING_TYPE_POSE_6DOF = "android.sensor.pose_6dof";
-    field public static final java.lang.String STRING_TYPE_PRESSURE = "android.sensor.pressure";
-    field public static final java.lang.String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
-    field public static final java.lang.String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
-    field public static final java.lang.String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
-    field public static final java.lang.String STRING_TYPE_SIGNIFICANT_MOTION = "android.sensor.significant_motion";
-    field public static final java.lang.String STRING_TYPE_STATIONARY_DETECT = "android.sensor.stationary_detect";
-    field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
-    field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
-    field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
+    field public static final String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
+    field public static final String STRING_TYPE_ACCELEROMETER_UNCALIBRATED = "android.sensor.accelerometer_uncalibrated";
+    field public static final String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
+    field public static final String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
+    field public static final String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR = "android.sensor.geomagnetic_rotation_vector";
+    field public static final String STRING_TYPE_GRAVITY = "android.sensor.gravity";
+    field public static final String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
+    field public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+    field public static final String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat";
+    field public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
+    field public static final String STRING_TYPE_LIGHT = "android.sensor.light";
+    field public static final String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
+    field public static final String STRING_TYPE_LOW_LATENCY_OFFBODY_DETECT = "android.sensor.low_latency_offbody_detect";
+    field public static final String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
+    field public static final String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
+    field public static final String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
+    field @Deprecated public static final String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+    field public static final String STRING_TYPE_POSE_6DOF = "android.sensor.pose_6dof";
+    field public static final String STRING_TYPE_PRESSURE = "android.sensor.pressure";
+    field public static final String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
+    field public static final String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
+    field public static final String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
+    field public static final String STRING_TYPE_SIGNIFICANT_MOTION = "android.sensor.significant_motion";
+    field public static final String STRING_TYPE_STATIONARY_DETECT = "android.sensor.stationary_detect";
+    field public static final String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
+    field public static final String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
+    field @Deprecated public static final String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
     field public static final int TYPE_ACCELEROMETER = 1; // 0x1
     field public static final int TYPE_ACCELEROMETER_UNCALIBRATED = 35; // 0x23
     field public static final int TYPE_ALL = -1; // 0xffffffff
@@ -16241,7 +16252,7 @@
     field public static final int TYPE_MAGNETIC_FIELD = 2; // 0x2
     field public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14; // 0xe
     field public static final int TYPE_MOTION_DETECT = 30; // 0x1e
-    field public static final deprecated int TYPE_ORIENTATION = 3; // 0x3
+    field @Deprecated public static final int TYPE_ORIENTATION = 3; // 0x3
     field public static final int TYPE_POSE_6DOF = 28; // 0x1c
     field public static final int TYPE_PRESSURE = 6; // 0x6
     field public static final int TYPE_PROXIMITY = 8; // 0x8
@@ -16251,7 +16262,7 @@
     field public static final int TYPE_STATIONARY_DETECT = 29; // 0x1d
     field public static final int TYPE_STEP_COUNTER = 19; // 0x13
     field public static final int TYPE_STEP_DETECTOR = 18; // 0x12
-    field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
+    field @Deprecated public static final int TYPE_TEMPERATURE = 7; // 0x7
   }
 
   public class SensorAdditionalInfo {
@@ -16296,18 +16307,18 @@
     method public void onSensorChanged(android.hardware.SensorEvent);
   }
 
-  public abstract interface SensorEventListener {
-    method public abstract void onAccuracyChanged(android.hardware.Sensor, int);
-    method public abstract void onSensorChanged(android.hardware.SensorEvent);
+  public interface SensorEventListener {
+    method public void onAccuracyChanged(android.hardware.Sensor, int);
+    method public void onSensorChanged(android.hardware.SensorEvent);
   }
 
-  public abstract interface SensorEventListener2 implements android.hardware.SensorEventListener {
-    method public abstract void onFlushCompleted(android.hardware.Sensor);
+  public interface SensorEventListener2 extends android.hardware.SensorEventListener {
+    method public void onFlushCompleted(android.hardware.Sensor);
   }
 
-  public abstract deprecated interface SensorListener {
-    method public abstract void onAccuracyChanged(int, int);
-    method public abstract void onSensorChanged(int, float[]);
+  @Deprecated public interface SensorListener {
+    method @Deprecated public void onAccuracyChanged(int, int);
+    method @Deprecated public void onSensorChanged(int, float[]);
   }
 
   public abstract class SensorManager {
@@ -16326,12 +16337,12 @@
     method public static boolean getRotationMatrix(float[], float[], float[], float[]);
     method public static void getRotationMatrixFromVector(float[], float[]);
     method public java.util.List<android.hardware.Sensor> getSensorList(int);
-    method public deprecated int getSensors();
+    method @Deprecated public int getSensors();
     method public boolean isDynamicSensorDiscoverySupported();
     method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
     method public void registerDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback, android.os.Handler);
-    method public deprecated boolean registerListener(android.hardware.SensorListener, int);
-    method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
+    method @Deprecated public boolean registerListener(android.hardware.SensorListener, int);
+    method @Deprecated public boolean registerListener(android.hardware.SensorListener, int, int);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, int);
     method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, android.os.Handler);
@@ -16339,8 +16350,8 @@
     method public static boolean remapCoordinateSystem(float[], int, int, float[]);
     method public boolean requestTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
     method public void unregisterDynamicSensorCallback(android.hardware.SensorManager.DynamicSensorCallback);
-    method public deprecated void unregisterListener(android.hardware.SensorListener);
-    method public deprecated void unregisterListener(android.hardware.SensorListener, int);
+    method @Deprecated public void unregisterListener(android.hardware.SensorListener);
+    method @Deprecated public void unregisterListener(android.hardware.SensorListener, int);
     method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
     method public void unregisterListener(android.hardware.SensorEventListener);
     field public static final int AXIS_MINUS_X = 129; // 0x81
@@ -16349,9 +16360,9 @@
     field public static final int AXIS_X = 1; // 0x1
     field public static final int AXIS_Y = 2; // 0x2
     field public static final int AXIS_Z = 3; // 0x3
-    field public static final deprecated int DATA_X = 0; // 0x0
-    field public static final deprecated int DATA_Y = 1; // 0x1
-    field public static final deprecated int DATA_Z = 2; // 0x2
+    field @Deprecated public static final int DATA_X = 0; // 0x0
+    field @Deprecated public static final int DATA_Y = 1; // 0x1
+    field @Deprecated public static final int DATA_Z = 2; // 0x2
     field public static final float GRAVITY_DEATH_STAR_I = 3.5303614E-7f;
     field public static final float GRAVITY_EARTH = 9.80665f;
     field public static final float GRAVITY_JUPITER = 23.12f;
@@ -16376,34 +16387,34 @@
     field public static final float MAGNETIC_FIELD_EARTH_MAX = 60.0f;
     field public static final float MAGNETIC_FIELD_EARTH_MIN = 30.0f;
     field public static final float PRESSURE_STANDARD_ATMOSPHERE = 1013.25f;
-    field public static final deprecated int RAW_DATA_INDEX = 3; // 0x3
-    field public static final deprecated int RAW_DATA_X = 3; // 0x3
-    field public static final deprecated int RAW_DATA_Y = 4; // 0x4
-    field public static final deprecated int RAW_DATA_Z = 5; // 0x5
-    field public static final deprecated int SENSOR_ACCELEROMETER = 2; // 0x2
-    field public static final deprecated int SENSOR_ALL = 127; // 0x7f
+    field @Deprecated public static final int RAW_DATA_INDEX = 3; // 0x3
+    field @Deprecated public static final int RAW_DATA_X = 3; // 0x3
+    field @Deprecated public static final int RAW_DATA_Y = 4; // 0x4
+    field @Deprecated public static final int RAW_DATA_Z = 5; // 0x5
+    field @Deprecated public static final int SENSOR_ACCELEROMETER = 2; // 0x2
+    field @Deprecated public static final int SENSOR_ALL = 127; // 0x7f
     field public static final int SENSOR_DELAY_FASTEST = 0; // 0x0
     field public static final int SENSOR_DELAY_GAME = 1; // 0x1
     field public static final int SENSOR_DELAY_NORMAL = 3; // 0x3
     field public static final int SENSOR_DELAY_UI = 2; // 0x2
-    field public static final deprecated int SENSOR_LIGHT = 16; // 0x10
-    field public static final deprecated int SENSOR_MAGNETIC_FIELD = 8; // 0x8
-    field public static final deprecated int SENSOR_MAX = 64; // 0x40
-    field public static final deprecated int SENSOR_MIN = 1; // 0x1
-    field public static final deprecated int SENSOR_ORIENTATION = 1; // 0x1
-    field public static final deprecated int SENSOR_ORIENTATION_RAW = 128; // 0x80
-    field public static final deprecated int SENSOR_PROXIMITY = 32; // 0x20
+    field @Deprecated public static final int SENSOR_LIGHT = 16; // 0x10
+    field @Deprecated public static final int SENSOR_MAGNETIC_FIELD = 8; // 0x8
+    field @Deprecated public static final int SENSOR_MAX = 64; // 0x40
+    field @Deprecated public static final int SENSOR_MIN = 1; // 0x1
+    field @Deprecated public static final int SENSOR_ORIENTATION = 1; // 0x1
+    field @Deprecated public static final int SENSOR_ORIENTATION_RAW = 128; // 0x80
+    field @Deprecated public static final int SENSOR_PROXIMITY = 32; // 0x20
     field public static final int SENSOR_STATUS_ACCURACY_HIGH = 3; // 0x3
     field public static final int SENSOR_STATUS_ACCURACY_LOW = 1; // 0x1
     field public static final int SENSOR_STATUS_ACCURACY_MEDIUM = 2; // 0x2
     field public static final int SENSOR_STATUS_NO_CONTACT = -1; // 0xffffffff
     field public static final int SENSOR_STATUS_UNRELIABLE = 0; // 0x0
-    field public static final deprecated int SENSOR_TEMPERATURE = 4; // 0x4
-    field public static final deprecated int SENSOR_TRICORDER = 64; // 0x40
+    field @Deprecated public static final int SENSOR_TEMPERATURE = 4; // 0x4
+    field @Deprecated public static final int SENSOR_TRICORDER = 64; // 0x40
     field public static final float STANDARD_GRAVITY = 9.80665f;
   }
 
-  public static abstract class SensorManager.DynamicSensorCallback {
+  public abstract static class SensorManager.DynamicSensorCallback {
     ctor public SensorManager.DynamicSensorCallback();
     method public void onDynamicSensorConnected(android.hardware.Sensor);
     method public void onDynamicSensorDisconnected(android.hardware.Sensor);
@@ -16425,16 +16436,16 @@
 package android.hardware.biometrics {
 
   public class BiometricManager {
-    method public int canAuthenticate();
-    field public static final int BIOMETRIC_ERROR_NO_BIOMETRICS = 11; // 0xb
+    method @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public int canAuthenticate();
+    field public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE = 1; // 0x1
+    field public static final int BIOMETRIC_ERROR_NONE_ENROLLED = 11; // 0xb
     field public static final int BIOMETRIC_ERROR_NO_HARDWARE = 12; // 0xc
-    field public static final int BIOMETRIC_ERROR_UNAVAILABLE = 1; // 0x1
     field public static final int BIOMETRIC_SUCCESS = 0; // 0x0
   }
 
   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);
+    method @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public void authenticate(@NonNull android.hardware.biometrics.BiometricPrompt.CryptoObject, @NonNull android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.biometrics.BiometricPrompt.AuthenticationCallback);
+    method @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public void authenticate(@NonNull android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.biometrics.BiometricPrompt.AuthenticationCallback);
     field public static final int BIOMETRIC_ACQUIRED_GOOD = 0; // 0x0
     field public static final int BIOMETRIC_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
     field public static final int BIOMETRIC_ACQUIRED_INSUFFICIENT = 2; // 0x2
@@ -16454,11 +16465,11 @@
     field public static final int BIOMETRIC_ERROR_VENDOR = 8; // 0x8
   }
 
-  public static abstract class BiometricPrompt.AuthenticationCallback {
+  public abstract static class BiometricPrompt.AuthenticationCallback {
     ctor public BiometricPrompt.AuthenticationCallback();
-    method public void onAuthenticationError(int, java.lang.CharSequence);
+    method public void onAuthenticationError(int, CharSequence);
     method public void onAuthenticationFailed();
-    method public void onAuthenticationHelp(int, java.lang.CharSequence);
+    method public void onAuthenticationHelp(int, CharSequence);
     method public void onAuthenticationSucceeded(android.hardware.biometrics.BiometricPrompt.AuthenticationResult);
   }
 
@@ -16469,16 +16480,17 @@
   public static class BiometricPrompt.Builder {
     ctor public BiometricPrompt.Builder(android.content.Context);
     method public android.hardware.biometrics.BiometricPrompt build();
-    method public android.hardware.biometrics.BiometricPrompt.Builder setDescription(java.lang.CharSequence);
-    method public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(java.lang.CharSequence, java.util.concurrent.Executor, android.content.DialogInterface.OnClickListener);
-    method public android.hardware.biometrics.BiometricPrompt.Builder setSubtitle(java.lang.CharSequence);
-    method public android.hardware.biometrics.BiometricPrompt.Builder setTitle(java.lang.CharSequence);
+    method public android.hardware.biometrics.BiometricPrompt.Builder setDescription(@NonNull CharSequence);
+    method public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(@NonNull CharSequence, @NonNull java.util.concurrent.Executor, @NonNull android.content.DialogInterface.OnClickListener);
+    method public android.hardware.biometrics.BiometricPrompt.Builder setRequireConfirmation(boolean);
+    method public android.hardware.biometrics.BiometricPrompt.Builder setSubtitle(@NonNull CharSequence);
+    method public android.hardware.biometrics.BiometricPrompt.Builder setTitle(@NonNull CharSequence);
   }
 
   public static final class BiometricPrompt.CryptoObject {
-    ctor public BiometricPrompt.CryptoObject(java.security.Signature);
-    ctor public BiometricPrompt.CryptoObject(javax.crypto.Cipher);
-    ctor public BiometricPrompt.CryptoObject(javax.crypto.Mac);
+    ctor public BiometricPrompt.CryptoObject(@NonNull java.security.Signature);
+    ctor public BiometricPrompt.CryptoObject(@NonNull javax.crypto.Cipher);
+    ctor public BiometricPrompt.CryptoObject(@NonNull javax.crypto.Mac);
     method public javax.crypto.Cipher getCipher();
     method public javax.crypto.Mac getMac();
     method public java.security.Signature getSignature();
@@ -16490,9 +16502,9 @@
 
   public class CameraAccessException extends android.util.AndroidException {
     ctor public CameraAccessException(int);
-    ctor public CameraAccessException(int, java.lang.String);
-    ctor public CameraAccessException(int, java.lang.String, java.lang.Throwable);
-    ctor public CameraAccessException(int, java.lang.Throwable);
+    ctor public CameraAccessException(int, String);
+    ctor public CameraAccessException(int, String, Throwable);
+    ctor public CameraAccessException(int, Throwable);
     method public final int getReason();
     field public static final int CAMERA_DISABLED = 1; // 0x1
     field public static final int CAMERA_DISCONNECTED = 2; // 0x2
@@ -16504,56 +16516,56 @@
   public abstract class CameraCaptureSession implements java.lang.AutoCloseable {
     ctor public CameraCaptureSession();
     method public abstract void abortCaptures() throws android.hardware.camera2.CameraAccessException;
-    method public abstract int capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
-    method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
-    method public int captureBurstRequests(java.util.List<android.hardware.camera2.CaptureRequest>, java.util.concurrent.Executor, android.hardware.camera2.CameraCaptureSession.CaptureCallback) throws android.hardware.camera2.CameraAccessException;
-    method public int captureSingleRequest(android.hardware.camera2.CaptureRequest, java.util.concurrent.Executor, android.hardware.camera2.CameraCaptureSession.CaptureCallback) throws android.hardware.camera2.CameraAccessException;
+    method public abstract int capture(@NonNull android.hardware.camera2.CaptureRequest, @Nullable android.hardware.camera2.CameraCaptureSession.CaptureCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract int captureBurst(@NonNull java.util.List<android.hardware.camera2.CaptureRequest>, @Nullable android.hardware.camera2.CameraCaptureSession.CaptureCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public int captureBurstRequests(@NonNull java.util.List<android.hardware.camera2.CaptureRequest>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraCaptureSession.CaptureCallback) throws android.hardware.camera2.CameraAccessException;
+    method public int captureSingleRequest(@NonNull android.hardware.camera2.CaptureRequest, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraCaptureSession.CaptureCallback) throws android.hardware.camera2.CameraAccessException;
     method public abstract void close();
     method public abstract void finalizeOutputConfigurations(java.util.List<android.hardware.camera2.params.OutputConfiguration>) throws android.hardware.camera2.CameraAccessException;
-    method public abstract android.hardware.camera2.CameraDevice getDevice();
-    method public abstract android.view.Surface getInputSurface();
+    method @NonNull public abstract android.hardware.camera2.CameraDevice getDevice();
+    method @Nullable public abstract android.view.Surface getInputSurface();
     method public abstract boolean isReprocessable();
-    method public abstract void prepare(android.view.Surface) throws android.hardware.camera2.CameraAccessException;
-    method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
-    method public int setRepeatingBurstRequests(java.util.List<android.hardware.camera2.CaptureRequest>, java.util.concurrent.Executor, android.hardware.camera2.CameraCaptureSession.CaptureCallback) throws android.hardware.camera2.CameraAccessException;
-    method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
-    method public int setSingleRepeatingRequest(android.hardware.camera2.CaptureRequest, java.util.concurrent.Executor, android.hardware.camera2.CameraCaptureSession.CaptureCallback) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void prepare(@NonNull android.view.Surface) throws android.hardware.camera2.CameraAccessException;
+    method public abstract int setRepeatingBurst(@NonNull java.util.List<android.hardware.camera2.CaptureRequest>, @Nullable android.hardware.camera2.CameraCaptureSession.CaptureCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public int setRepeatingBurstRequests(@NonNull java.util.List<android.hardware.camera2.CaptureRequest>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraCaptureSession.CaptureCallback) throws android.hardware.camera2.CameraAccessException;
+    method public abstract int setRepeatingRequest(@NonNull android.hardware.camera2.CaptureRequest, @Nullable android.hardware.camera2.CameraCaptureSession.CaptureCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public int setSingleRepeatingRequest(@NonNull android.hardware.camera2.CaptureRequest, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraCaptureSession.CaptureCallback) throws android.hardware.camera2.CameraAccessException;
     method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException;
     method public void updateOutputConfiguration(android.hardware.camera2.params.OutputConfiguration) throws android.hardware.camera2.CameraAccessException;
   }
 
-  public static abstract class CameraCaptureSession.CaptureCallback {
+  public abstract static class CameraCaptureSession.CaptureCallback {
     ctor public CameraCaptureSession.CaptureCallback();
-    method public void onCaptureBufferLost(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.view.Surface, long);
-    method public void onCaptureCompleted(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.TotalCaptureResult);
-    method public void onCaptureFailed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureFailure);
-    method public void onCaptureProgressed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
-    method public void onCaptureSequenceAborted(android.hardware.camera2.CameraCaptureSession, int);
-    method public void onCaptureSequenceCompleted(android.hardware.camera2.CameraCaptureSession, int, long);
-    method public void onCaptureStarted(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, long, long);
+    method public void onCaptureBufferLost(@NonNull android.hardware.camera2.CameraCaptureSession, @NonNull android.hardware.camera2.CaptureRequest, @NonNull android.view.Surface, long);
+    method public void onCaptureCompleted(@NonNull android.hardware.camera2.CameraCaptureSession, @NonNull android.hardware.camera2.CaptureRequest, @NonNull android.hardware.camera2.TotalCaptureResult);
+    method public void onCaptureFailed(@NonNull android.hardware.camera2.CameraCaptureSession, @NonNull android.hardware.camera2.CaptureRequest, @NonNull android.hardware.camera2.CaptureFailure);
+    method public void onCaptureProgressed(@NonNull android.hardware.camera2.CameraCaptureSession, @NonNull android.hardware.camera2.CaptureRequest, @NonNull android.hardware.camera2.CaptureResult);
+    method public void onCaptureSequenceAborted(@NonNull android.hardware.camera2.CameraCaptureSession, int);
+    method public void onCaptureSequenceCompleted(@NonNull android.hardware.camera2.CameraCaptureSession, int, long);
+    method public void onCaptureStarted(@NonNull android.hardware.camera2.CameraCaptureSession, @NonNull android.hardware.camera2.CaptureRequest, long, long);
   }
 
-  public static abstract class CameraCaptureSession.StateCallback {
+  public abstract static class CameraCaptureSession.StateCallback {
     ctor public CameraCaptureSession.StateCallback();
-    method public void onActive(android.hardware.camera2.CameraCaptureSession);
-    method public void onCaptureQueueEmpty(android.hardware.camera2.CameraCaptureSession);
-    method public void onClosed(android.hardware.camera2.CameraCaptureSession);
-    method public abstract void onConfigureFailed(android.hardware.camera2.CameraCaptureSession);
-    method public abstract void onConfigured(android.hardware.camera2.CameraCaptureSession);
-    method public void onReady(android.hardware.camera2.CameraCaptureSession);
-    method public void onSurfacePrepared(android.hardware.camera2.CameraCaptureSession, android.view.Surface);
+    method public void onActive(@NonNull android.hardware.camera2.CameraCaptureSession);
+    method public void onCaptureQueueEmpty(@NonNull android.hardware.camera2.CameraCaptureSession);
+    method public void onClosed(@NonNull android.hardware.camera2.CameraCaptureSession);
+    method public abstract void onConfigureFailed(@NonNull android.hardware.camera2.CameraCaptureSession);
+    method public abstract void onConfigured(@NonNull android.hardware.camera2.CameraCaptureSession);
+    method public void onReady(@NonNull android.hardware.camera2.CameraCaptureSession);
+    method public void onSurfacePrepared(@NonNull android.hardware.camera2.CameraCaptureSession, @NonNull android.view.Surface);
   }
 
-  public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
-    method public <T> T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
-    method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
-    method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
+  public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata<android.hardware.camera2.CameraCharacteristics.Key<?>> {
+    method @Nullable public <T> T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
+    method @NonNull public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
+    method @NonNull public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
     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 @NonNull 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();
-    method public android.hardware.camera2.params.RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(int);
+    method @NonNull public java.util.Set<java.lang.String> getPhysicalCameraIds();
+    method @Nullable public android.hardware.camera2.params.RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(int);
     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;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_MODES;
@@ -16593,7 +16605,7 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> LENS_POSE_REFERENCE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_ROTATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_TRANSLATION;
-    field public static final deprecated android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_RADIAL_DISTORTION;
+    field @Deprecated public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_RADIAL_DISTORTION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REPROCESS_MAX_CAPTURE_STALL;
@@ -16644,27 +16656,27 @@
   }
 
   public static final class CameraCharacteristics.Key<T> {
-    method public java.lang.String getName();
+    method @NonNull public String getName();
   }
 
   public abstract class CameraConstrainedHighSpeedCaptureSession extends android.hardware.camera2.CameraCaptureSession {
     ctor public CameraConstrainedHighSpeedCaptureSession();
-    method public abstract java.util.List<android.hardware.camera2.CaptureRequest> createHighSpeedRequestList(android.hardware.camera2.CaptureRequest) throws android.hardware.camera2.CameraAccessException;
+    method @NonNull public abstract java.util.List<android.hardware.camera2.CaptureRequest> createHighSpeedRequestList(@NonNull android.hardware.camera2.CaptureRequest) throws android.hardware.camera2.CameraAccessException;
   }
 
   public abstract class CameraDevice implements java.lang.AutoCloseable {
     method public abstract void close();
-    method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
-    method public android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int, java.util.Set<java.lang.String>) throws android.hardware.camera2.CameraAccessException;
-    method public abstract void createCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method @NonNull public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
+    method @NonNull public android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int, java.util.Set<java.lang.String>) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createCaptureSession(@NonNull java.util.List<android.view.Surface>, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public void createCaptureSession(android.hardware.camera2.params.SessionConfiguration) throws android.hardware.camera2.CameraAccessException;
-    method public abstract void createCaptureSessionByOutputConfigurations(java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
-    method public abstract void createConstrainedHighSpeedCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
-    method public abstract android.hardware.camera2.CaptureRequest.Builder createReprocessCaptureRequest(android.hardware.camera2.TotalCaptureResult) throws android.hardware.camera2.CameraAccessException;
-    method public abstract void createReprocessableCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
-    method public abstract void createReprocessableCaptureSessionByConfigurations(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
-    method public abstract java.lang.String getId();
-    method public boolean isSessionConfigurationSupported(android.hardware.camera2.params.SessionConfiguration) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createCaptureSessionByOutputConfigurations(java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createConstrainedHighSpeedCaptureSession(@NonNull java.util.List<android.view.Surface>, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method @NonNull public abstract android.hardware.camera2.CaptureRequest.Builder createReprocessCaptureRequest(@NonNull android.hardware.camera2.TotalCaptureResult) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createReprocessableCaptureSession(@NonNull android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.view.Surface>, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createReprocessableCaptureSessionByConfigurations(@NonNull android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method @NonNull public abstract String getId();
+    method public boolean isSessionConfigurationSupported(@NonNull android.hardware.camera2.params.SessionConfiguration) throws android.hardware.camera2.CameraAccessException;
     field public static final int TEMPLATE_MANUAL = 6; // 0x6
     field public static final int TEMPLATE_PREVIEW = 1; // 0x1
     field public static final int TEMPLATE_RECORD = 3; // 0x3
@@ -16673,12 +16685,12 @@
     field public static final int TEMPLATE_ZERO_SHUTTER_LAG = 5; // 0x5
   }
 
-  public static abstract class CameraDevice.StateCallback {
+  public abstract static class CameraDevice.StateCallback {
     ctor public CameraDevice.StateCallback();
-    method public void onClosed(android.hardware.camera2.CameraDevice);
-    method public abstract void onDisconnected(android.hardware.camera2.CameraDevice);
-    method public abstract void onError(android.hardware.camera2.CameraDevice, int);
-    method public abstract void onOpened(android.hardware.camera2.CameraDevice);
+    method public void onClosed(@NonNull android.hardware.camera2.CameraDevice);
+    method public abstract void onDisconnected(@NonNull android.hardware.camera2.CameraDevice);
+    method public abstract void onError(@NonNull android.hardware.camera2.CameraDevice, int);
+    method public abstract void onOpened(@NonNull android.hardware.camera2.CameraDevice);
     field public static final int ERROR_CAMERA_DEVICE = 4; // 0x4
     field public static final int ERROR_CAMERA_DISABLED = 3; // 0x3
     field public static final int ERROR_CAMERA_IN_USE = 1; // 0x1
@@ -16687,33 +16699,33 @@
   }
 
   public final class CameraManager {
-    method public android.hardware.camera2.CameraCharacteristics getCameraCharacteristics(java.lang.String) throws android.hardware.camera2.CameraAccessException;
-    method public java.lang.String[] getCameraIdList() throws android.hardware.camera2.CameraAccessException;
-    method public void openCamera(java.lang.String, android.hardware.camera2.CameraDevice.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
-    method public void openCamera(java.lang.String, java.util.concurrent.Executor, android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException;
-    method public void registerAvailabilityCallback(android.hardware.camera2.CameraManager.AvailabilityCallback, android.os.Handler);
-    method public void registerAvailabilityCallback(java.util.concurrent.Executor, android.hardware.camera2.CameraManager.AvailabilityCallback);
-    method public void registerTorchCallback(android.hardware.camera2.CameraManager.TorchCallback, android.os.Handler);
-    method public void registerTorchCallback(java.util.concurrent.Executor, android.hardware.camera2.CameraManager.TorchCallback);
-    method public void setTorchMode(java.lang.String, boolean) throws android.hardware.camera2.CameraAccessException;
-    method public void unregisterAvailabilityCallback(android.hardware.camera2.CameraManager.AvailabilityCallback);
-    method public void unregisterTorchCallback(android.hardware.camera2.CameraManager.TorchCallback);
+    method @NonNull public android.hardware.camera2.CameraCharacteristics getCameraCharacteristics(@NonNull String) throws android.hardware.camera2.CameraAccessException;
+    method @NonNull public String[] getCameraIdList() throws android.hardware.camera2.CameraAccessException;
+    method @RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String, @NonNull android.hardware.camera2.CameraDevice.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method @RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException;
+    method public void registerAvailabilityCallback(@NonNull android.hardware.camera2.CameraManager.AvailabilityCallback, @Nullable android.os.Handler);
+    method public void registerAvailabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraManager.AvailabilityCallback);
+    method public void registerTorchCallback(@NonNull android.hardware.camera2.CameraManager.TorchCallback, @Nullable android.os.Handler);
+    method public void registerTorchCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraManager.TorchCallback);
+    method public void setTorchMode(@NonNull String, boolean) throws android.hardware.camera2.CameraAccessException;
+    method public void unregisterAvailabilityCallback(@NonNull android.hardware.camera2.CameraManager.AvailabilityCallback);
+    method public void unregisterTorchCallback(@NonNull android.hardware.camera2.CameraManager.TorchCallback);
   }
 
-  public static abstract class CameraManager.AvailabilityCallback {
+  public abstract static class CameraManager.AvailabilityCallback {
     ctor public CameraManager.AvailabilityCallback();
-    method public void onCameraAvailable(java.lang.String);
-    method public void onCameraUnavailable(java.lang.String);
+    method public void onCameraAvailable(@NonNull String);
+    method public void onCameraUnavailable(@NonNull String);
   }
 
-  public static abstract class CameraManager.TorchCallback {
+  public abstract static class CameraManager.TorchCallback {
     ctor public CameraManager.TorchCallback();
-    method public void onTorchModeChanged(java.lang.String, boolean);
-    method public void onTorchModeUnavailable(java.lang.String);
+    method public void onTorchModeChanged(@NonNull String, boolean);
+    method public void onTorchModeUnavailable(@NonNull String);
   }
 
   public abstract class CameraMetadata<TKey> {
-    method public java.util.List<TKey> getKeys();
+    method @NonNull public java.util.List<TKey> getKeys();
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_OFF = 0; // 0x0
@@ -16799,7 +16811,7 @@
     field public static final int CONTROL_SCENE_MODE_FACE_PRIORITY = 1; // 0x1
     field public static final int CONTROL_SCENE_MODE_FIREWORKS = 12; // 0xc
     field public static final int CONTROL_SCENE_MODE_HDR = 18; // 0x12
-    field public static final deprecated int CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO = 17; // 0x11
+    field @Deprecated public static final int CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO = 17; // 0x11
     field public static final int CONTROL_SCENE_MODE_LANDSCAPE = 4; // 0x4
     field public static final int CONTROL_SCENE_MODE_NIGHT = 5; // 0x5
     field public static final int CONTROL_SCENE_MODE_NIGHT_PORTRAIT = 6; // 0x6
@@ -16930,18 +16942,18 @@
   public class CaptureFailure {
     method public long getFrameNumber();
     method public int getReason();
-    method public android.hardware.camera2.CaptureRequest getRequest();
+    method @NonNull public android.hardware.camera2.CaptureRequest getRequest();
     method public int getSequenceId();
     method public boolean wasImageCaptured();
     field public static final int REASON_ERROR = 0; // 0x0
     field public static final int REASON_FLUSHED = 1; // 0x1
   }
 
-  public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
+  public final class CaptureRequest extends android.hardware.camera2.CameraMetadata<android.hardware.camera2.CaptureRequest.Key<?>> implements android.os.Parcelable {
     method public int describeContents();
-    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
-    method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getKeys();
-    method public java.lang.Object getTag();
+    method @Nullable public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
+    method @NonNull public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getKeys();
+    method @Nullable public Object getTag();
     method public boolean isReprocess();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> BLACK_LEVEL_LOCK;
@@ -17004,25 +17016,25 @@
   }
 
   public static final class CaptureRequest.Builder {
-    method public void addTarget(android.view.Surface);
-    method public android.hardware.camera2.CaptureRequest build();
-    method public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
-    method public <T> T getPhysicalCameraKey(android.hardware.camera2.CaptureRequest.Key<T>, java.lang.String);
-    method public void removeTarget(android.view.Surface);
-    method public <T> void set(android.hardware.camera2.CaptureRequest.Key<T>, T);
-    method public <T> android.hardware.camera2.CaptureRequest.Builder setPhysicalCameraKey(android.hardware.camera2.CaptureRequest.Key<T>, T, java.lang.String);
-    method public void setTag(java.lang.Object);
+    method public void addTarget(@NonNull android.view.Surface);
+    method @NonNull public android.hardware.camera2.CaptureRequest build();
+    method @Nullable public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
+    method @Nullable public <T> T getPhysicalCameraKey(android.hardware.camera2.CaptureRequest.Key<T>, @NonNull String);
+    method public void removeTarget(@NonNull android.view.Surface);
+    method public <T> void set(@NonNull android.hardware.camera2.CaptureRequest.Key<T>, T);
+    method public <T> android.hardware.camera2.CaptureRequest.Builder setPhysicalCameraKey(@NonNull android.hardware.camera2.CaptureRequest.Key<T>, T, @NonNull String);
+    method public void setTag(@Nullable Object);
   }
 
   public static final class CaptureRequest.Key<T> {
-    method public java.lang.String getName();
+    method @NonNull public String getName();
   }
 
-  public class CaptureResult extends android.hardware.camera2.CameraMetadata {
-    method public <T> T get(android.hardware.camera2.CaptureResult.Key<T>);
+  public class CaptureResult extends android.hardware.camera2.CameraMetadata<android.hardware.camera2.CaptureResult.Key<?>> {
+    method @Nullable public <T> T get(android.hardware.camera2.CaptureResult.Key<T>);
     method public long getFrameNumber();
-    method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getKeys();
-    method public android.hardware.camera2.CaptureRequest getRequest();
+    method @NonNull public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getKeys();
+    method @NonNull public android.hardware.camera2.CaptureRequest getRequest();
     method public int getSequenceId();
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> BLACK_LEVEL_LOCK;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> COLOR_CORRECTION_ABERRATION_MODE;
@@ -17068,13 +17080,14 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_FILTER_DENSITY;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_FOCAL_LENGTH;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_FOCUS_DISTANCE;
-    field public static final android.hardware.camera2.CaptureResult.Key<android.util.Pair<java.lang.Float, java.lang.Float>> LENS_FOCUS_RANGE;
+    field public static final android.hardware.camera2.CaptureResult.Key<android.util.Pair<java.lang.Float,java.lang.Float>> LENS_FOCUS_RANGE;
     field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_INTRINSIC_CALIBRATION;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_POSE_ROTATION;
     field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_POSE_TRANSLATION;
-    field public static final deprecated android.hardware.camera2.CaptureResult.Key<float[]> LENS_RADIAL_DISTORTION;
+    field @Deprecated public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_RADIAL_DISTORTION;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_STATE;
+    field public static final android.hardware.camera2.CaptureResult.Key<java.lang.String> LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> NOISE_REDUCTION_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Byte> REQUEST_PIPELINE_DEPTH;
@@ -17085,7 +17098,7 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Long> SENSOR_FRAME_DURATION;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> SENSOR_GREEN_SPLIT;
     field public static final android.hardware.camera2.CaptureResult.Key<android.util.Rational[]> SENSOR_NEUTRAL_COLOR_POINT;
-    field public static final android.hardware.camera2.CaptureResult.Key<android.util.Pair<java.lang.Double, java.lang.Double>[]> SENSOR_NOISE_PROFILE;
+    field public static final android.hardware.camera2.CaptureResult.Key<android.util.Pair<java.lang.Double,java.lang.Double>[]> SENSOR_NOISE_PROFILE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Long> SENSOR_ROLLING_SHUTTER_SKEW;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> SENSOR_SENSITIVITY;
     field public static final android.hardware.camera2.CaptureResult.Key<int[]> SENSOR_TEST_PATTERN_DATA;
@@ -17108,26 +17121,26 @@
   }
 
   public static final class CaptureResult.Key<T> {
-    method public java.lang.String getName();
+    method @NonNull public String getName();
   }
 
   public final class DngCreator implements java.lang.AutoCloseable {
-    ctor public DngCreator(android.hardware.camera2.CameraCharacteristics, android.hardware.camera2.CaptureResult);
+    ctor public DngCreator(@NonNull android.hardware.camera2.CameraCharacteristics, @NonNull android.hardware.camera2.CaptureResult);
     method public void close();
-    method public android.hardware.camera2.DngCreator setDescription(java.lang.String);
-    method public android.hardware.camera2.DngCreator setLocation(android.location.Location);
-    method public android.hardware.camera2.DngCreator setOrientation(int);
-    method public android.hardware.camera2.DngCreator setThumbnail(android.graphics.Bitmap);
-    method public android.hardware.camera2.DngCreator setThumbnail(android.media.Image);
-    method public void writeByteBuffer(java.io.OutputStream, android.util.Size, java.nio.ByteBuffer, long) throws java.io.IOException;
-    method public void writeImage(java.io.OutputStream, android.media.Image) throws java.io.IOException;
-    method public void writeInputStream(java.io.OutputStream, android.util.Size, java.io.InputStream, long) throws java.io.IOException;
+    method @NonNull public android.hardware.camera2.DngCreator setDescription(@NonNull String);
+    method @NonNull public android.hardware.camera2.DngCreator setLocation(@NonNull android.location.Location);
+    method @NonNull public android.hardware.camera2.DngCreator setOrientation(int);
+    method @NonNull public android.hardware.camera2.DngCreator setThumbnail(@NonNull android.graphics.Bitmap);
+    method @NonNull public android.hardware.camera2.DngCreator setThumbnail(@NonNull android.media.Image);
+    method public void writeByteBuffer(@NonNull java.io.OutputStream, @NonNull android.util.Size, @NonNull java.nio.ByteBuffer, @IntRange(from=0) long) throws java.io.IOException;
+    method public void writeImage(@NonNull java.io.OutputStream, @NonNull android.media.Image) throws java.io.IOException;
+    method public void writeInputStream(@NonNull java.io.OutputStream, @NonNull android.util.Size, @NonNull java.io.InputStream, @IntRange(from=0) long) throws java.io.IOException;
     field public static final int MAX_THUMBNAIL_DIMENSION = 256; // 0x100
   }
 
   public final class TotalCaptureResult extends android.hardware.camera2.CaptureResult {
-    method public java.util.List<android.hardware.camera2.CaptureResult> getPartialResults();
-    method public java.util.Map<java.lang.String, android.hardware.camera2.CaptureResult> getPhysicalCameraResults();
+    method @NonNull public java.util.List<android.hardware.camera2.CaptureResult> getPartialResults();
+    method public java.util.Map<java.lang.String,android.hardware.camera2.CaptureResult> getPhysicalCameraResults();
   }
 
 }
@@ -17178,7 +17191,7 @@
   }
 
   public final class MandatoryStreamCombination {
-    method public java.lang.String getDescription();
+    method public String getDescription();
     method public java.util.List<android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation> getStreamsInformation();
     method public boolean isReprocessable();
   }
@@ -17215,42 +17228,42 @@
   }
 
   public final class OutputConfiguration implements android.os.Parcelable {
-    ctor public OutputConfiguration(android.view.Surface);
-    ctor public OutputConfiguration(int, android.view.Surface);
-    ctor public OutputConfiguration(android.util.Size, java.lang.Class<T>);
-    method public void addSurface(android.view.Surface);
+    ctor public OutputConfiguration(@NonNull android.view.Surface);
+    ctor public OutputConfiguration(int, @NonNull android.view.Surface);
+    ctor public OutputConfiguration(@NonNull android.util.Size, @NonNull Class<T>);
+    method public void addSurface(@NonNull android.view.Surface);
     method public int describeContents();
     method public void enableSurfaceSharing();
     method public int getMaxSharedSurfaceCount();
-    method public android.view.Surface getSurface();
+    method @Nullable public android.view.Surface getSurface();
     method public int getSurfaceGroupId();
-    method public java.util.List<android.view.Surface> getSurfaces();
-    method public void removeSurface(android.view.Surface);
-    method public void setPhysicalCameraId(java.lang.String);
+    method @NonNull public java.util.List<android.view.Surface> getSurfaces();
+    method public void removeSurface(@NonNull android.view.Surface);
+    method public void setPhysicalCameraId(@Nullable String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
     field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
   }
 
   public final class RecommendedStreamConfigurationMap {
-    method public java.util.Set<android.util.Size> getHighResolutionOutputSizes(int);
-    method public java.util.Set<android.util.Range<java.lang.Integer>> getHighSpeedVideoFpsRanges();
-    method public java.util.Set<android.util.Range<java.lang.Integer>> getHighSpeedVideoFpsRangesFor(android.util.Size);
-    method public java.util.Set<android.util.Size> getHighSpeedVideoSizes();
-    method public java.util.Set<android.util.Size> getHighSpeedVideoSizesFor(android.util.Range<java.lang.Integer>);
-    method public java.util.Set<java.lang.Integer> getInputFormats();
-    method public java.util.Set<android.util.Size> getInputSizes(int);
-    method public java.util.Set<java.lang.Integer> getOutputFormats();
-    method public long getOutputMinFrameDuration(int, android.util.Size);
-    method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
-    method public java.util.Set<android.util.Size> getOutputSizes(int);
-    method public <T> java.util.Set<android.util.Size> getOutputSizes(java.lang.Class<T>);
-    method public long getOutputStallDuration(int, android.util.Size);
-    method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+    method @Nullable public java.util.Set<android.util.Size> getHighResolutionOutputSizes(int);
+    method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getHighSpeedVideoFpsRanges();
+    method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getHighSpeedVideoFpsRangesFor(@NonNull android.util.Size);
+    method @Nullable public java.util.Set<android.util.Size> getHighSpeedVideoSizes();
+    method @Nullable public java.util.Set<android.util.Size> getHighSpeedVideoSizesFor(@NonNull android.util.Range<java.lang.Integer>);
+    method @Nullable public java.util.Set<java.lang.Integer> getInputFormats();
+    method @Nullable public java.util.Set<android.util.Size> getInputSizes(int);
+    method @NonNull public java.util.Set<java.lang.Integer> getOutputFormats();
+    method @IntRange(from=0) public long getOutputMinFrameDuration(int, @NonNull android.util.Size);
+    method public <T> long getOutputMinFrameDuration(@NonNull Class<T>, @NonNull android.util.Size);
+    method @Nullable public java.util.Set<android.util.Size> getOutputSizes(int);
+    method public <T> java.util.Set<android.util.Size> getOutputSizes(@NonNull Class<T>);
+    method @IntRange(from=0) public long getOutputStallDuration(int, @NonNull android.util.Size);
+    method public <T> long getOutputStallDuration(@NonNull Class<T>, @NonNull android.util.Size);
     method public int getRecommendedUseCase();
-    method public java.util.Set<java.lang.Integer> getValidOutputFormatsForInput(int);
+    method @Nullable public java.util.Set<java.lang.Integer> getValidOutputFormatsForInput(int);
     method public boolean isOutputSupportedFor(int);
-    method public boolean isOutputSupportedFor(android.view.Surface);
+    method public boolean isOutputSupportedFor(@NonNull android.view.Surface);
     field public static final int USECASE_PREVIEW = 0; // 0x0
     field public static final int USECASE_RAW = 5; // 0x5
     field public static final int USECASE_RECORD = 1; // 0x1
@@ -17275,7 +17288,7 @@
   }
 
   public final class SessionConfiguration implements android.os.Parcelable {
-    ctor public SessionConfiguration(int, java.util.List<android.hardware.camera2.params.OutputConfiguration>, java.util.concurrent.Executor, android.hardware.camera2.CameraCaptureSession.StateCallback);
+    ctor public SessionConfiguration(int, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback);
     method public int describeContents();
     method public java.util.concurrent.Executor getExecutor();
     method public android.hardware.camera2.params.InputConfiguration getInputConfiguration();
@@ -17283,7 +17296,7 @@
     method public android.hardware.camera2.CaptureRequest getSessionParameters();
     method public int getSessionType();
     method public android.hardware.camera2.CameraCaptureSession.StateCallback getStateCallback();
-    method public void setInputConfiguration(android.hardware.camera2.params.InputConfiguration);
+    method public void setInputConfiguration(@NonNull android.hardware.camera2.params.InputConfiguration);
     method public void setSessionParameters(android.hardware.camera2.CaptureRequest);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.SessionConfiguration> CREATOR;
@@ -17301,14 +17314,14 @@
     method public android.util.Size[] getInputSizes(int);
     method public int[] getOutputFormats();
     method public long getOutputMinFrameDuration(int, android.util.Size);
-    method public <T> long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
-    method public <T> android.util.Size[] getOutputSizes(java.lang.Class<T>);
+    method public <T> long getOutputMinFrameDuration(Class<T>, android.util.Size);
+    method public <T> android.util.Size[] getOutputSizes(Class<T>);
     method public android.util.Size[] getOutputSizes(int);
     method public long getOutputStallDuration(int, android.util.Size);
-    method public <T> long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+    method public <T> long getOutputStallDuration(Class<T>, android.util.Size);
     method public int[] getValidOutputFormatsForInput(int);
     method public boolean isOutputSupportedFor(int);
-    method public static <T> boolean isOutputSupportedFor(java.lang.Class<T>);
+    method public static <T> boolean isOutputSupportedFor(Class<T>);
     method public boolean isOutputSupportedFor(android.view.Surface);
   }
 
@@ -17330,14 +17343,14 @@
 package android.hardware.display {
 
   public final class DisplayManager {
-    method public android.hardware.display.VirtualDisplay createVirtualDisplay(java.lang.String, int, int, int, android.view.Surface, int);
-    method public android.hardware.display.VirtualDisplay createVirtualDisplay(java.lang.String, int, int, int, android.view.Surface, int, android.hardware.display.VirtualDisplay.Callback, android.os.Handler);
+    method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int);
+    method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int, @Nullable android.hardware.display.VirtualDisplay.Callback, @Nullable android.os.Handler);
     method public android.view.Display getDisplay(int);
     method public android.view.Display[] getDisplays();
-    method public android.view.Display[] getDisplays(java.lang.String);
+    method public android.view.Display[] getDisplays(String);
     method public void registerDisplayListener(android.hardware.display.DisplayManager.DisplayListener, android.os.Handler);
     method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
-    field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+    field public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
     field public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 16; // 0x10
     field public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 8; // 0x8
     field public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 2; // 0x2
@@ -17345,10 +17358,10 @@
     field public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 4; // 0x4
   }
 
-  public static abstract interface DisplayManager.DisplayListener {
-    method public abstract void onDisplayAdded(int);
-    method public abstract void onDisplayChanged(int);
-    method public abstract void onDisplayRemoved(int);
+  public static interface DisplayManager.DisplayListener {
+    method public void onDisplayAdded(int);
+    method public void onDisplayChanged(int);
+    method public void onDisplayRemoved(int);
   }
 
   public final class VirtualDisplay {
@@ -17359,7 +17372,7 @@
     method public void setSurface(android.view.Surface);
   }
 
-  public static abstract class VirtualDisplay.Callback {
+  public abstract static class VirtualDisplay.Callback {
     ctor public VirtualDisplay.Callback();
     method public void onPaused();
     method public void onResumed();
@@ -17370,10 +17383,10 @@
 
 package android.hardware.fingerprint {
 
-  public deprecated class FingerprintManager {
-    method public deprecated void authenticate(android.hardware.fingerprint.FingerprintManager.CryptoObject, android.os.CancellationSignal, int, android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, android.os.Handler);
-    method public deprecated boolean hasEnrolledFingerprints();
-    method public deprecated boolean isHardwareDetected();
+  @Deprecated public class FingerprintManager {
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.USE_BIOMETRIC, android.Manifest.permission.USE_FINGERPRINT}) public void authenticate(@Nullable android.hardware.fingerprint.FingerprintManager.CryptoObject, @Nullable android.os.CancellationSignal, int, @NonNull android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, @Nullable android.os.Handler);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
     field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
     field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
     field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
@@ -17393,25 +17406,25 @@
     field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
   }
 
-  public static abstract deprecated class FingerprintManager.AuthenticationCallback {
-    ctor public FingerprintManager.AuthenticationCallback();
-    method public void onAuthenticationError(int, java.lang.CharSequence);
-    method public void onAuthenticationFailed();
-    method public void onAuthenticationHelp(int, java.lang.CharSequence);
-    method public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintManager.AuthenticationResult);
+  @Deprecated public abstract static class FingerprintManager.AuthenticationCallback {
+    ctor @Deprecated public FingerprintManager.AuthenticationCallback();
+    method @Deprecated public void onAuthenticationError(int, CharSequence);
+    method @Deprecated public void onAuthenticationFailed();
+    method @Deprecated public void onAuthenticationHelp(int, CharSequence);
+    method @Deprecated public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintManager.AuthenticationResult);
   }
 
-  public static deprecated class FingerprintManager.AuthenticationResult {
-    method public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
+  @Deprecated public static class FingerprintManager.AuthenticationResult {
+    method @Deprecated public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
   }
 
-  public static final deprecated class FingerprintManager.CryptoObject {
-    ctor public FingerprintManager.CryptoObject(java.security.Signature);
-    ctor public FingerprintManager.CryptoObject(javax.crypto.Cipher);
-    ctor public FingerprintManager.CryptoObject(javax.crypto.Mac);
-    method public javax.crypto.Cipher getCipher();
-    method public javax.crypto.Mac getMac();
-    method public java.security.Signature getSignature();
+  @Deprecated public static final class FingerprintManager.CryptoObject {
+    ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull java.security.Signature);
+    ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher);
+    ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac);
+    method @Deprecated public javax.crypto.Cipher getCipher();
+    method @Deprecated public javax.crypto.Mac getMac();
+    method @Deprecated public java.security.Signature getSignature();
   }
 
 }
@@ -17423,14 +17436,14 @@
     method public int[] getInputDeviceIds();
     method public void registerInputDeviceListener(android.hardware.input.InputManager.InputDeviceListener, android.os.Handler);
     method public void unregisterInputDeviceListener(android.hardware.input.InputManager.InputDeviceListener);
-    field public static final java.lang.String ACTION_QUERY_KEYBOARD_LAYOUTS = "android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS";
-    field public static final java.lang.String META_DATA_KEYBOARD_LAYOUTS = "android.hardware.input.metadata.KEYBOARD_LAYOUTS";
+    field public static final String ACTION_QUERY_KEYBOARD_LAYOUTS = "android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS";
+    field public static final String META_DATA_KEYBOARD_LAYOUTS = "android.hardware.input.metadata.KEYBOARD_LAYOUTS";
   }
 
-  public static abstract interface InputManager.InputDeviceListener {
-    method public abstract void onInputDeviceAdded(int);
-    method public abstract void onInputDeviceChanged(int);
-    method public abstract void onInputDeviceRemoved(int);
+  public static interface InputManager.InputDeviceListener {
+    method public void onInputDeviceAdded(int);
+    method public void onInputDeviceChanged(int);
+    method public void onInputDeviceRemoved(int);
   }
 
 }
@@ -17439,12 +17452,12 @@
 
   public class UsbAccessory implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getDescription();
-    method public java.lang.String getManufacturer();
-    method public java.lang.String getModel();
-    method public java.lang.String getSerial();
-    method public java.lang.String getUri();
-    method public java.lang.String getVersion();
+    method @Nullable public String getDescription();
+    method @NonNull public String getManufacturer();
+    method @NonNull public String getModel();
+    method @Nullable public String getSerial();
+    method @Nullable public String getUri();
+    method @Nullable public String getVersion();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbAccessory> CREATOR;
   }
@@ -17452,10 +17465,10 @@
   public class UsbConfiguration implements android.os.Parcelable {
     method public int describeContents();
     method public int getId();
-    method public android.hardware.usb.UsbInterface getInterface(int);
+    method @NonNull public android.hardware.usb.UsbInterface getInterface(int);
     method public int getInterfaceCount();
     method public int getMaxPower();
-    method public java.lang.String getName();
+    method @Nullable public String getName();
     method public boolean isRemoteWakeup();
     method public boolean isSelfPowered();
     method public void writeToParcel(android.os.Parcel, int);
@@ -17501,23 +17514,23 @@
 
   public class UsbDevice implements android.os.Parcelable {
     method public int describeContents();
-    method public android.hardware.usb.UsbConfiguration getConfiguration(int);
+    method @NonNull public android.hardware.usb.UsbConfiguration getConfiguration(int);
     method public int getConfigurationCount();
     method public int getDeviceClass();
     method public int getDeviceId();
-    method public static int getDeviceId(java.lang.String);
-    method public java.lang.String getDeviceName();
-    method public static java.lang.String getDeviceName(int);
+    method public static int getDeviceId(String);
+    method @NonNull public String getDeviceName();
+    method public static String getDeviceName(int);
     method public int getDeviceProtocol();
     method public int getDeviceSubclass();
-    method public android.hardware.usb.UsbInterface getInterface(int);
+    method @NonNull public android.hardware.usb.UsbInterface getInterface(int);
     method public int getInterfaceCount();
-    method public java.lang.String getManufacturerName();
+    method @Nullable public String getManufacturerName();
     method public int getProductId();
-    method public java.lang.String getProductName();
-    method public java.lang.String getSerialNumber();
+    method @Nullable public String getProductName();
+    method @Nullable public String getSerialNumber();
     method public int getVendorId();
-    method public java.lang.String getVersion();
+    method @NonNull public String getVersion();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbDevice> CREATOR;
   }
@@ -17531,7 +17544,7 @@
     method public int controlTransfer(int, int, int, int, byte[], int, int, int);
     method public int getFileDescriptor();
     method public byte[] getRawDescriptors();
-    method public java.lang.String getSerial();
+    method public String getSerial();
     method public boolean releaseInterface(android.hardware.usb.UsbInterface);
     method public android.hardware.usb.UsbRequest requestWait();
     method public android.hardware.usb.UsbRequest requestWait(long) throws java.util.concurrent.TimeoutException;
@@ -17561,39 +17574,39 @@
     method public int getInterfaceClass();
     method public int getInterfaceProtocol();
     method public int getInterfaceSubclass();
-    method public java.lang.String getName();
+    method @Nullable public String getName();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbInterface> CREATOR;
   }
 
   public class UsbManager {
     method public android.hardware.usb.UsbAccessory[] getAccessoryList();
-    method public java.util.HashMap<java.lang.String, android.hardware.usb.UsbDevice> getDeviceList();
+    method public java.util.HashMap<java.lang.String,android.hardware.usb.UsbDevice> getDeviceList();
     method public boolean hasPermission(android.hardware.usb.UsbDevice);
     method public boolean hasPermission(android.hardware.usb.UsbAccessory);
     method public android.os.ParcelFileDescriptor openAccessory(android.hardware.usb.UsbAccessory);
     method public android.hardware.usb.UsbDeviceConnection openDevice(android.hardware.usb.UsbDevice);
     method public void requestPermission(android.hardware.usb.UsbDevice, android.app.PendingIntent);
     method public void requestPermission(android.hardware.usb.UsbAccessory, android.app.PendingIntent);
-    field public static final java.lang.String ACTION_USB_ACCESSORY_ATTACHED = "android.hardware.usb.action.USB_ACCESSORY_ATTACHED";
-    field public static final java.lang.String ACTION_USB_ACCESSORY_DETACHED = "android.hardware.usb.action.USB_ACCESSORY_DETACHED";
-    field public static final java.lang.String ACTION_USB_DEVICE_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED";
-    field public static final java.lang.String ACTION_USB_DEVICE_DETACHED = "android.hardware.usb.action.USB_DEVICE_DETACHED";
-    field public static final java.lang.String EXTRA_ACCESSORY = "accessory";
-    field public static final java.lang.String EXTRA_DEVICE = "device";
-    field public static final java.lang.String EXTRA_PERMISSION_GRANTED = "permission";
+    field public static final String ACTION_USB_ACCESSORY_ATTACHED = "android.hardware.usb.action.USB_ACCESSORY_ATTACHED";
+    field public static final String ACTION_USB_ACCESSORY_DETACHED = "android.hardware.usb.action.USB_ACCESSORY_DETACHED";
+    field public static final String ACTION_USB_DEVICE_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED";
+    field public static final String ACTION_USB_DEVICE_DETACHED = "android.hardware.usb.action.USB_DEVICE_DETACHED";
+    field public static final String EXTRA_ACCESSORY = "accessory";
+    field public static final String EXTRA_DEVICE = "device";
+    field public static final String EXTRA_PERMISSION_GRANTED = "permission";
   }
 
   public class UsbRequest {
     ctor public UsbRequest();
     method public boolean cancel();
     method public void close();
-    method public java.lang.Object getClientData();
+    method public Object getClientData();
     method public android.hardware.usb.UsbEndpoint getEndpoint();
     method public boolean initialize(android.hardware.usb.UsbDeviceConnection, android.hardware.usb.UsbEndpoint);
-    method public deprecated boolean queue(java.nio.ByteBuffer, int);
-    method public boolean queue(java.nio.ByteBuffer);
-    method public void setClientData(java.lang.Object);
+    method @Deprecated public boolean queue(java.nio.ByteBuffer, int);
+    method public boolean queue(@Nullable java.nio.ByteBuffer);
+    method public void setClientData(Object);
   }
 
 }
@@ -17602,47 +17615,47 @@
 
   public final class UCharacter implements android.icu.lang.UCharacterEnums.ECharacterCategory android.icu.lang.UCharacterEnums.ECharacterDirection {
     method public static int charCount(int);
-    method public static int codePointAt(java.lang.CharSequence, int);
+    method public static int codePointAt(CharSequence, int);
     method public static int codePointAt(char[], int);
     method public static int codePointAt(char[], int, int);
-    method public static int codePointBefore(java.lang.CharSequence, int);
+    method public static int codePointBefore(CharSequence, int);
     method public static int codePointBefore(char[], int);
     method public static int codePointBefore(char[], int, int);
-    method public static int codePointCount(java.lang.CharSequence, int, int);
+    method public static int codePointCount(CharSequence, int, int);
     method public static int codePointCount(char[], int, int);
     method public static int digit(int, int);
     method public static int digit(int);
     method public static int foldCase(int, boolean);
-    method public static java.lang.String foldCase(java.lang.String, boolean);
+    method public static String foldCase(String, boolean);
     method public static int foldCase(int, int);
-    method public static java.lang.String foldCase(java.lang.String, int);
+    method public static String foldCase(String, int);
     method public static char forDigit(int, int);
     method public static android.icu.util.VersionInfo getAge(int);
     method public static int getBidiPairedBracket(int);
-    method public static int getCharFromExtendedName(java.lang.String);
-    method public static int getCharFromName(java.lang.String);
-    method public static int getCharFromNameAlias(java.lang.String);
+    method public static int getCharFromExtendedName(String);
+    method public static int getCharFromName(String);
+    method public static int getCharFromNameAlias(String);
     method public static int getCodePoint(char, char);
     method public static int getCodePoint(char);
     method public static int getCombiningClass(int);
     method public static int getDirection(int);
     method public static byte getDirectionality(int);
-    method public static java.lang.String getExtendedName(int);
+    method public static String getExtendedName(int);
     method public static android.icu.util.ValueIterator getExtendedNameIterator();
     method public static int getHanNumericValue(int);
     method public static int getIntPropertyMaxValue(int);
     method public static int getIntPropertyMinValue(int);
     method public static int getIntPropertyValue(int, int);
     method public static int getMirror(int);
-    method public static java.lang.String getName(int);
-    method public static java.lang.String getName(java.lang.String, java.lang.String);
-    method public static java.lang.String getNameAlias(int);
+    method public static String getName(int);
+    method public static String getName(String, String);
+    method public static String getNameAlias(int);
     method public static android.icu.util.ValueIterator getNameIterator();
     method public static int getNumericValue(int);
-    method public static int getPropertyEnum(java.lang.CharSequence);
-    method public static java.lang.String getPropertyName(int, int);
-    method public static int getPropertyValueEnum(int, java.lang.CharSequence);
-    method public static java.lang.String getPropertyValueName(int, int, int);
+    method public static int getPropertyEnum(CharSequence);
+    method public static String getPropertyName(int, int);
+    method public static int getPropertyValueEnum(int, CharSequence);
+    method public static String getPropertyValueName(int, int, int);
     method public static int getType(int);
     method public static android.icu.util.RangeValueIterator getTypeIterator();
     method public static double getUnicodeNumericValue(int);
@@ -17658,7 +17671,7 @@
     method public static boolean isJavaIdentifierPart(int);
     method public static boolean isJavaIdentifierStart(int);
     method public static boolean isLegal(int);
-    method public static boolean isLegal(java.lang.String);
+    method public static boolean isLegal(String);
     method public static boolean isLetter(int);
     method public static boolean isLetterOrDigit(int);
     method public static boolean isLowSurrogate(char);
@@ -17679,26 +17692,26 @@
     method public static boolean isUpperCase(int);
     method public static boolean isValidCodePoint(int);
     method public static boolean isWhitespace(int);
-    method public static int offsetByCodePoints(java.lang.CharSequence, int, int);
+    method public static int offsetByCodePoints(CharSequence, int, int);
     method public static int offsetByCodePoints(char[], int, int, int, int);
     method public static int toChars(int, char[], int);
     method public static char[] toChars(int);
     method public static int toCodePoint(char, char);
     method public static int toLowerCase(int);
-    method public static java.lang.String toLowerCase(java.lang.String);
-    method public static java.lang.String toLowerCase(java.util.Locale, java.lang.String);
-    method public static java.lang.String toLowerCase(android.icu.util.ULocale, java.lang.String);
-    method public static java.lang.String toString(int);
+    method public static String toLowerCase(String);
+    method public static String toLowerCase(java.util.Locale, String);
+    method public static String toLowerCase(android.icu.util.ULocale, String);
+    method public static String toString(int);
     method public static int toTitleCase(int);
-    method public static java.lang.String toTitleCase(java.lang.String, android.icu.text.BreakIterator);
-    method public static java.lang.String toTitleCase(java.util.Locale, java.lang.String, android.icu.text.BreakIterator);
-    method public static java.lang.String toTitleCase(android.icu.util.ULocale, java.lang.String, android.icu.text.BreakIterator);
-    method public static java.lang.String toTitleCase(android.icu.util.ULocale, java.lang.String, android.icu.text.BreakIterator, int);
-    method public static java.lang.String toTitleCase(java.util.Locale, java.lang.String, android.icu.text.BreakIterator, int);
+    method public static String toTitleCase(String, android.icu.text.BreakIterator);
+    method public static String toTitleCase(java.util.Locale, String, android.icu.text.BreakIterator);
+    method public static String toTitleCase(android.icu.util.ULocale, String, android.icu.text.BreakIterator);
+    method public static String toTitleCase(android.icu.util.ULocale, String, android.icu.text.BreakIterator, int);
+    method public static String toTitleCase(java.util.Locale, String, android.icu.text.BreakIterator, int);
     method public static int toUpperCase(int);
-    method public static java.lang.String toUpperCase(java.lang.String);
-    method public static java.lang.String toUpperCase(java.util.Locale, java.lang.String);
-    method public static java.lang.String toUpperCase(android.icu.util.ULocale, java.lang.String);
+    method public static String toUpperCase(String);
+    method public static String toUpperCase(java.util.Locale, String);
+    method public static String toUpperCase(android.icu.util.ULocale, String);
     field public static final int FOLD_CASE_DEFAULT = 0; // 0x0
     field public static final int FOLD_CASE_EXCLUDE_SPECIAL_I = 1; // 0x1
     field public static final int MAX_CODE_POINT = 1114111; // 0x10ffff
@@ -17721,13 +17734,13 @@
     field public static final int TITLECASE_NO_LOWERCASE = 256; // 0x100
   }
 
-  public static abstract interface UCharacter.BidiPairedBracketType {
+  public static interface UCharacter.BidiPairedBracketType {
     field public static final int CLOSE = 2; // 0x2
     field public static final int NONE = 0; // 0x0
     field public static final int OPEN = 1; // 0x1
   }
 
-  public static abstract interface UCharacter.DecompositionType {
+  public static interface UCharacter.DecompositionType {
     field public static final int CANONICAL = 1; // 0x1
     field public static final int CIRCLE = 3; // 0x3
     field public static final int COMPAT = 2; // 0x2
@@ -17748,7 +17761,7 @@
     field public static final int WIDE = 17; // 0x11
   }
 
-  public static abstract interface UCharacter.EastAsianWidth {
+  public static interface UCharacter.EastAsianWidth {
     field public static final int AMBIGUOUS = 1; // 0x1
     field public static final int FULLWIDTH = 3; // 0x3
     field public static final int HALFWIDTH = 2; // 0x2
@@ -17757,7 +17770,7 @@
     field public static final int WIDE = 5; // 0x5
   }
 
-  public static abstract interface UCharacter.GraphemeClusterBreak {
+  public static interface UCharacter.GraphemeClusterBreak {
     field public static final int CONTROL = 1; // 0x1
     field public static final int CR = 2; // 0x2
     field public static final int EXTEND = 3; // 0x3
@@ -17778,7 +17791,7 @@
     field public static final int ZWJ = 17; // 0x11
   }
 
-  public static abstract interface UCharacter.HangulSyllableType {
+  public static interface UCharacter.HangulSyllableType {
     field public static final int LEADING_JAMO = 1; // 0x1
     field public static final int LVT_SYLLABLE = 5; // 0x5
     field public static final int LV_SYLLABLE = 4; // 0x4
@@ -17787,7 +17800,7 @@
     field public static final int VOWEL_JAMO = 2; // 0x2
   }
 
-  public static abstract interface UCharacter.IndicPositionalCategory {
+  public static interface UCharacter.IndicPositionalCategory {
     field public static final int BOTTOM = 1; // 0x1
     field public static final int BOTTOM_AND_LEFT = 2; // 0x2
     field public static final int BOTTOM_AND_RIGHT = 3; // 0x3
@@ -17805,7 +17818,7 @@
     field public static final int VISUAL_ORDER_LEFT = 14; // 0xe
   }
 
-  public static abstract interface UCharacter.IndicSyllabicCategory {
+  public static interface UCharacter.IndicSyllabicCategory {
     field public static final int AVAGRAHA = 1; // 0x1
     field public static final int BINDU = 2; // 0x2
     field public static final int BRAHMI_JOINING_NUMBER = 3; // 0x3
@@ -17844,7 +17857,7 @@
     field public static final int VOWEL_INDEPENDENT = 35; // 0x23
   }
 
-  public static abstract interface UCharacter.JoiningGroup {
+  public static interface UCharacter.JoiningGroup {
     field public static final int AFRICAN_FEH = 86; // 0x56
     field public static final int AFRICAN_NOON = 87; // 0x57
     field public static final int AFRICAN_QAF = 88; // 0x58
@@ -17950,7 +17963,7 @@
     field public static final int ZHAIN = 53; // 0x35
   }
 
-  public static abstract interface UCharacter.JoiningType {
+  public static interface UCharacter.JoiningType {
     field public static final int DUAL_JOINING = 2; // 0x2
     field public static final int JOIN_CAUSING = 1; // 0x1
     field public static final int LEFT_JOINING = 3; // 0x3
@@ -17959,7 +17972,7 @@
     field public static final int TRANSPARENT = 5; // 0x5
   }
 
-  public static abstract interface UCharacter.LineBreak {
+  public static interface UCharacter.LineBreak {
     field public static final int ALPHABETIC = 2; // 0x2
     field public static final int AMBIGUOUS = 1; // 0x1
     field public static final int BREAK_AFTER = 4; // 0x4
@@ -18006,14 +18019,14 @@
     field public static final int ZWSPACE = 28; // 0x1c
   }
 
-  public static abstract interface UCharacter.NumericType {
+  public static interface UCharacter.NumericType {
     field public static final int DECIMAL = 1; // 0x1
     field public static final int DIGIT = 2; // 0x2
     field public static final int NONE = 0; // 0x0
     field public static final int NUMERIC = 3; // 0x3
   }
 
-  public static abstract interface UCharacter.SentenceBreak {
+  public static interface UCharacter.SentenceBreak {
     field public static final int ATERM = 1; // 0x1
     field public static final int CLOSE = 2; // 0x2
     field public static final int CR = 11; // 0xb
@@ -18032,7 +18045,7 @@
   }
 
   public static final class UCharacter.UnicodeBlock extends java.lang.Character.Subset {
-    method public static android.icu.lang.UCharacter.UnicodeBlock forName(java.lang.String);
+    method public static android.icu.lang.UCharacter.UnicodeBlock forName(String);
     method public int getID();
     method public static android.icu.lang.UCharacter.UnicodeBlock getInstance(int);
     method public static android.icu.lang.UCharacter.UnicodeBlock of(int);
@@ -18627,14 +18640,14 @@
     field public static final int ZANABAZAR_SQUARE_ID = 280; // 0x118
   }
 
-  public static abstract interface UCharacter.VerticalOrientation {
+  public static interface UCharacter.VerticalOrientation {
     field public static final int ROTATED = 0; // 0x0
     field public static final int TRANSFORMED_ROTATED = 1; // 0x1
     field public static final int TRANSFORMED_UPRIGHT = 2; // 0x2
     field public static final int UPRIGHT = 3; // 0x3
   }
 
-  public static abstract interface UCharacter.WordBreak {
+  public static interface UCharacter.WordBreak {
     field public static final int ALETTER = 1; // 0x1
     field public static final int CR = 8; // 0x8
     field public static final int DOUBLE_QUOTE = 16; // 0x10
@@ -18661,17 +18674,17 @@
   }
 
   public final class UCharacterCategory implements android.icu.lang.UCharacterEnums.ECharacterCategory {
-    method public static java.lang.String toString(int);
+    method public static String toString(int);
   }
 
   public final class UCharacterDirection implements android.icu.lang.UCharacterEnums.ECharacterDirection {
-    method public static java.lang.String toString(int);
+    method public static String toString(int);
   }
 
   public class UCharacterEnums {
   }
 
-  public static abstract interface UCharacterEnums.ECharacterCategory {
+  public static interface UCharacterEnums.ECharacterCategory {
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 22; // 0x16
     field public static final byte CONTROL = 15; // 0xf
@@ -18707,7 +18720,7 @@
     field public static final byte UPPERCASE_LETTER = 1; // 0x1
   }
 
-  public static abstract interface UCharacterEnums.ECharacterDirection {
+  public static interface UCharacterEnums.ECharacterDirection {
     field public static final int ARABIC_NUMBER = 5; // 0x5
     field public static final int BLOCK_SEPARATOR = 7; // 0x7
     field public static final int BOUNDARY_NEUTRAL = 18; // 0x12
@@ -18753,7 +18766,7 @@
     field public static final int WHITE_SPACE_NEUTRAL = 9; // 0x9
   }
 
-  public abstract interface UProperty {
+  public interface UProperty {
     field public static final int AGE = 16384; // 0x4000
     field public static final int ALPHABETIC = 0; // 0x0
     field public static final int ASCII_HEX_DIGIT = 1; // 0x1
@@ -18867,7 +18880,7 @@
     field public static final int XID_START = 33; // 0x21
   }
 
-  public static abstract interface UProperty.NameChoice {
+  public static interface UProperty.NameChoice {
     field public static final int LONG = 1; // 0x1
     field public static final int SHORT = 0; // 0x0
   }
@@ -18876,13 +18889,13 @@
     method public static boolean breaksBetweenLetters(int);
     method public static int[] getCode(java.util.Locale);
     method public static int[] getCode(android.icu.util.ULocale);
-    method public static int[] getCode(java.lang.String);
-    method public static int getCodeFromName(java.lang.String);
-    method public static java.lang.String getName(int);
-    method public static java.lang.String getSampleString(int);
+    method public static int[] getCode(String);
+    method public static int getCodeFromName(String);
+    method public static String getName(int);
+    method public static String getSampleString(int);
     method public static int getScript(int);
     method public static int getScriptExtensions(int, java.util.BitSet);
-    method public static java.lang.String getShortName(int);
+    method public static String getShortName(int);
     method public static android.icu.lang.UScript.ScriptUsage getUsage(int);
     method public static boolean hasScript(int, int);
     method public static boolean isCased(int);
@@ -19080,9 +19093,7 @@
     field public static final int ZANABAZAR_SQUARE = 177; // 0xb1
   }
 
-  public static final class UScript.ScriptUsage extends java.lang.Enum {
-    method public static android.icu.lang.UScript.ScriptUsage valueOf(java.lang.String);
-    method public static final android.icu.lang.UScript.ScriptUsage[] values();
+  public enum UScript.ScriptUsage {
     enum_constant public static final android.icu.lang.UScript.ScriptUsage ASPIRATIONAL;
     enum_constant public static final android.icu.lang.UScript.ScriptUsage EXCLUDED;
     enum_constant public static final android.icu.lang.UScript.ScriptUsage LIMITED_USE;
@@ -19095,7 +19106,7 @@
 
 package android.icu.math {
 
-  public class BigDecimal extends java.lang.Number implements java.lang.Comparable java.io.Serializable {
+  public class BigDecimal extends java.lang.Number implements java.lang.Comparable<android.icu.math.BigDecimal> java.io.Serializable {
     ctor public BigDecimal(java.math.BigDecimal);
     ctor public BigDecimal(java.math.BigInteger);
     ctor public BigDecimal(java.math.BigInteger, int);
@@ -19104,7 +19115,7 @@
     ctor public BigDecimal(double);
     ctor public BigDecimal(int);
     ctor public BigDecimal(long);
-    ctor public BigDecimal(java.lang.String);
+    ctor public BigDecimal(String);
     method public android.icu.math.BigDecimal abs();
     method public android.icu.math.BigDecimal abs(android.icu.math.MathContext);
     method public android.icu.math.BigDecimal add(android.icu.math.BigDecimal);
@@ -19120,8 +19131,8 @@
     method public android.icu.math.BigDecimal divideInteger(android.icu.math.BigDecimal, android.icu.math.MathContext);
     method public double doubleValue();
     method public float floatValue();
-    method public java.lang.String format(int, int);
-    method public java.lang.String format(int, int, int, int, int, int);
+    method public String format(int, int);
+    method public String format(int, int, int, int, int, int);
     method public int intValue();
     method public int intValueExact();
     method public long longValue();
@@ -19197,71 +19208,69 @@
 
 package android.icu.text {
 
-  public final class AlphabeticIndex<V> implements java.lang.Iterable {
+  public final class AlphabeticIndex<V> implements java.lang.Iterable<android.icu.text.AlphabeticIndex.Bucket<V>> {
     ctor public AlphabeticIndex(android.icu.util.ULocale);
     ctor public AlphabeticIndex(java.util.Locale);
     ctor public AlphabeticIndex(android.icu.text.RuleBasedCollator);
     method public android.icu.text.AlphabeticIndex<V> addLabels(android.icu.text.UnicodeSet);
     method public android.icu.text.AlphabeticIndex<V> addLabels(android.icu.util.ULocale...);
     method public android.icu.text.AlphabeticIndex<V> addLabels(java.util.Locale...);
-    method public android.icu.text.AlphabeticIndex<V> addRecord(java.lang.CharSequence, V);
+    method public android.icu.text.AlphabeticIndex<V> addRecord(CharSequence, V);
     method public android.icu.text.AlphabeticIndex.ImmutableIndex<V> buildImmutableIndex();
     method public android.icu.text.AlphabeticIndex<V> clearRecords();
     method public int getBucketCount();
-    method public int getBucketIndex(java.lang.CharSequence);
+    method public int getBucketIndex(CharSequence);
     method public java.util.List<java.lang.String> getBucketLabels();
     method public android.icu.text.RuleBasedCollator getCollator();
-    method public java.lang.String getInflowLabel();
+    method public String getInflowLabel();
     method public int getMaxLabelCount();
-    method public java.lang.String getOverflowLabel();
+    method public String getOverflowLabel();
     method public int getRecordCount();
-    method public java.lang.String getUnderflowLabel();
+    method public String getUnderflowLabel();
     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Bucket<V>> iterator();
-    method public android.icu.text.AlphabeticIndex<V> setInflowLabel(java.lang.String);
+    method public android.icu.text.AlphabeticIndex<V> setInflowLabel(String);
     method public android.icu.text.AlphabeticIndex<V> setMaxLabelCount(int);
-    method public android.icu.text.AlphabeticIndex<V> setOverflowLabel(java.lang.String);
-    method public android.icu.text.AlphabeticIndex<V> setUnderflowLabel(java.lang.String);
+    method public android.icu.text.AlphabeticIndex<V> setOverflowLabel(String);
+    method public android.icu.text.AlphabeticIndex<V> setUnderflowLabel(String);
   }
 
-  public static class AlphabeticIndex.Bucket<V> implements java.lang.Iterable {
-    method public java.lang.String getLabel();
+  public static class AlphabeticIndex.Bucket<V> implements java.lang.Iterable<android.icu.text.AlphabeticIndex.Record<V>> {
+    method public String getLabel();
     method public android.icu.text.AlphabeticIndex.Bucket.LabelType getLabelType();
     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Record<V>> iterator();
     method public int size();
   }
 
-  public static final class AlphabeticIndex.Bucket.LabelType extends java.lang.Enum {
-    method public static android.icu.text.AlphabeticIndex.Bucket.LabelType valueOf(java.lang.String);
-    method public static final android.icu.text.AlphabeticIndex.Bucket.LabelType[] values();
+  public enum AlphabeticIndex.Bucket.LabelType {
     enum_constant public static final android.icu.text.AlphabeticIndex.Bucket.LabelType INFLOW;
     enum_constant public static final android.icu.text.AlphabeticIndex.Bucket.LabelType NORMAL;
     enum_constant public static final android.icu.text.AlphabeticIndex.Bucket.LabelType OVERFLOW;
     enum_constant public static final android.icu.text.AlphabeticIndex.Bucket.LabelType UNDERFLOW;
   }
 
-  public static final class AlphabeticIndex.ImmutableIndex<V> implements java.lang.Iterable {
+  public static final class AlphabeticIndex.ImmutableIndex<V> implements java.lang.Iterable<android.icu.text.AlphabeticIndex.Bucket<V>> {
     method public android.icu.text.AlphabeticIndex.Bucket<V> getBucket(int);
     method public int getBucketCount();
-    method public int getBucketIndex(java.lang.CharSequence);
+    method public int getBucketIndex(CharSequence);
     method public java.util.Iterator<android.icu.text.AlphabeticIndex.Bucket<V>> iterator();
   }
 
   public static class AlphabeticIndex.Record<V> {
     method public V getData();
-    method public java.lang.CharSequence getName();
+    method public CharSequence getName();
   }
 
   public class Bidi {
     ctor public Bidi();
     ctor public Bidi(int, int);
-    ctor public Bidi(java.lang.String, int);
+    ctor public Bidi(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 static byte getBaseDirection(CharSequence);
     method public int getBaseLevel();
     method public android.icu.text.BidiClassifier getCustomClassifier();
     method public int getCustomizedClass(int);
@@ -19285,7 +19294,7 @@
     method public int getRunLimit(int);
     method public int getRunStart(int);
     method public char[] getText();
-    method public java.lang.String getTextAsString();
+    method public String getTextAsString();
     method public int getVisualIndex(int);
     method public int[] getVisualMap();
     method public android.icu.text.BidiRun getVisualRun(int);
@@ -19298,19 +19307,19 @@
     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 void reorderVisually(byte[], int, Object[], int, int);
     method public static boolean requiresBidi(char[], int, int);
-    method public void setContext(java.lang.String, java.lang.String);
+    method public void setContext(String, 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(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);
+    method public String writeReordered(int);
+    method public static String writeReverse(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
@@ -19343,10 +19352,10 @@
   }
 
   public class BidiClassifier {
-    ctor public BidiClassifier(java.lang.Object);
+    ctor public BidiClassifier(Object);
     method public int classify(int);
-    method public java.lang.Object getContext();
-    method public void setContext(java.lang.Object);
+    method public Object getContext();
+    method public void setContext(Object);
   }
 
   public class BidiRun {
@@ -19361,11 +19370,11 @@
 
   public abstract class BreakIterator implements java.lang.Cloneable {
     ctor protected BreakIterator();
-    method public java.lang.Object clone();
+    method public Object clone();
     method public abstract int current();
     method public abstract int first();
     method public abstract int following(int);
-    method public static synchronized java.util.Locale[] getAvailableLocales();
+    method public static java.util.Locale[] getAvailableLocales();
     method public static android.icu.text.BreakIterator getCharacterInstance();
     method public static android.icu.text.BreakIterator getCharacterInstance(java.util.Locale);
     method public static android.icu.text.BreakIterator getCharacterInstance(android.icu.util.ULocale);
@@ -19390,8 +19399,8 @@
     method public abstract int next();
     method public int preceding(int);
     method public abstract int previous();
-    method public void setText(java.lang.String);
-    method public void setText(java.lang.CharSequence);
+    method public void setText(String);
+    method public void setText(CharSequence);
     method public abstract void setText(java.text.CharacterIterator);
     field public static final int DONE = -1; // 0xffffffff
     field public static final int KIND_CHARACTER = 0; // 0x0
@@ -19420,22 +19429,22 @@
   }
 
   public static final class CaseMap.Fold extends android.icu.text.CaseMap {
-    method public java.lang.String apply(java.lang.CharSequence);
-    method public <A extends java.lang.Appendable> A apply(java.lang.CharSequence, A, android.icu.text.Edits);
+    method public String apply(CharSequence);
+    method public <A extends java.lang.Appendable> A apply(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 java.lang.String apply(java.util.Locale, java.lang.CharSequence);
-    method public <A extends java.lang.Appendable> A apply(java.util.Locale, java.lang.CharSequence, A, android.icu.text.Edits);
+    method public String apply(java.util.Locale, CharSequence);
+    method public <A extends java.lang.Appendable> A apply(java.util.Locale, 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 android.icu.text.CaseMap.Title adjustToCased();
-    method public java.lang.String apply(java.util.Locale, android.icu.text.BreakIterator, java.lang.CharSequence);
-    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 String apply(java.util.Locale, android.icu.text.BreakIterator, CharSequence);
+    method public <A extends java.lang.Appendable> A apply(java.util.Locale, android.icu.text.BreakIterator, 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();
@@ -19444,8 +19453,8 @@
   }
 
   public static final class CaseMap.Upper extends android.icu.text.CaseMap {
-    method public java.lang.String apply(java.util.Locale, java.lang.CharSequence);
-    method public <A extends java.lang.Appendable> A apply(java.util.Locale, java.lang.CharSequence, A, android.icu.text.Edits);
+    method public String apply(java.util.Locale, CharSequence);
+    method public <A extends java.lang.Appendable> A apply(java.util.Locale, CharSequence, A, android.icu.text.Edits);
     method public android.icu.text.CaseMap.Upper omitUnchangedText();
   }
 
@@ -19458,7 +19467,7 @@
     method public void reset();
     method public static int secondaryOrder(int);
     method public void setOffset(int);
-    method public void setText(java.lang.String);
+    method public void setText(String);
     method public void setText(android.icu.text.UCharacterIterator);
     method public void setText(java.text.CharacterIterator);
     method public static int tertiaryOrder(int);
@@ -19466,12 +19475,12 @@
     field public static final int NULLORDER = -1; // 0xffffffff
   }
 
-  public final class CollationKey implements java.lang.Comparable {
-    ctor public CollationKey(java.lang.String, byte[]);
+  public final class CollationKey implements java.lang.Comparable<android.icu.text.CollationKey> {
+    ctor public CollationKey(String, byte[]);
     method public int compareTo(android.icu.text.CollationKey);
     method public boolean equals(android.icu.text.CollationKey);
     method public android.icu.text.CollationKey getBound(int, int);
-    method public java.lang.String getSourceString();
+    method public String getSourceString();
     method public android.icu.text.CollationKey merge(android.icu.text.CollationKey);
     method public byte[] toByteArray();
   }
@@ -19482,31 +19491,31 @@
     field public static final int UPPER_LONG = 2; // 0x2
   }
 
-  public abstract class Collator implements java.lang.Cloneable java.util.Comparator android.icu.util.Freezable {
+  public abstract class Collator implements java.lang.Cloneable java.util.Comparator<java.lang.Object> android.icu.util.Freezable<android.icu.text.Collator> {
     ctor protected Collator();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
+    method public Object clone() throws java.lang.CloneNotSupportedException;
     method public android.icu.text.Collator cloneAsThawed();
-    method public abstract int compare(java.lang.String, java.lang.String);
-    method public int compare(java.lang.Object, java.lang.Object);
-    method public boolean equals(java.lang.String, java.lang.String);
+    method public abstract int compare(String, String);
+    method public int compare(Object, Object);
+    method public boolean equals(String, String);
     method public android.icu.text.Collator freeze();
     method public static java.util.Locale[] getAvailableLocales();
     method public static final android.icu.util.ULocale[] getAvailableULocales();
-    method public abstract android.icu.text.CollationKey getCollationKey(java.lang.String);
+    method public abstract android.icu.text.CollationKey getCollationKey(String);
     method public int getDecomposition();
-    method public static java.lang.String getDisplayName(java.util.Locale, java.util.Locale);
-    method public static java.lang.String getDisplayName(android.icu.util.ULocale, android.icu.util.ULocale);
-    method public static java.lang.String getDisplayName(java.util.Locale);
-    method public static java.lang.String getDisplayName(android.icu.util.ULocale);
+    method public static String getDisplayName(java.util.Locale, java.util.Locale);
+    method public static String getDisplayName(android.icu.util.ULocale, android.icu.util.ULocale);
+    method public static String getDisplayName(java.util.Locale);
+    method public static String getDisplayName(android.icu.util.ULocale);
     method public static int[] getEquivalentReorderCodes(int);
-    method public static final android.icu.util.ULocale getFunctionalEquivalent(java.lang.String, android.icu.util.ULocale, boolean[]);
-    method public static final android.icu.util.ULocale getFunctionalEquivalent(java.lang.String, android.icu.util.ULocale);
+    method public static final android.icu.util.ULocale getFunctionalEquivalent(String, android.icu.util.ULocale, boolean[]);
+    method public static final android.icu.util.ULocale getFunctionalEquivalent(String, android.icu.util.ULocale);
     method public static final android.icu.text.Collator getInstance();
     method public static final android.icu.text.Collator getInstance(android.icu.util.ULocale);
     method public static final android.icu.text.Collator getInstance(java.util.Locale);
-    method public static final java.lang.String[] getKeywordValues(java.lang.String);
-    method public static final java.lang.String[] getKeywordValuesForLocale(java.lang.String, android.icu.util.ULocale, boolean);
-    method public static final java.lang.String[] getKeywords();
+    method public static final String[] getKeywordValues(String);
+    method public static final String[] getKeywordValuesForLocale(String, android.icu.util.ULocale, boolean);
+    method public static final String[] getKeywords();
     method public int getMaxVariable();
     method public int[] getReorderCodes();
     method public int getStrength();
@@ -19529,7 +19538,7 @@
     field public static final int TERTIARY = 2; // 0x2
   }
 
-  public static abstract interface Collator.ReorderCodes {
+  public static interface Collator.ReorderCodes {
     field public static final int CURRENCY = 4099; // 0x1003
     field public static final int DEFAULT = -1; // 0xffffffff
     field public static final int DIGIT = 4100; // 0x1004
@@ -19546,9 +19555,7 @@
     method public static android.icu.text.CompactDecimalFormat getInstance(java.util.Locale, android.icu.text.CompactDecimalFormat.CompactStyle);
   }
 
-  public static final class CompactDecimalFormat.CompactStyle extends java.lang.Enum {
-    method public static android.icu.text.CompactDecimalFormat.CompactStyle valueOf(java.lang.String);
-    method public static final android.icu.text.CompactDecimalFormat.CompactStyle[] values();
+  public enum CompactDecimalFormat.CompactStyle {
     enum_constant public static final android.icu.text.CompactDecimalFormat.CompactStyle LONG;
     enum_constant public static final android.icu.text.CompactDecimalFormat.CompactStyle SHORT;
   }
@@ -19557,24 +19564,24 @@
     ctor public CurrencyPluralInfo();
     ctor public CurrencyPluralInfo(java.util.Locale);
     ctor public CurrencyPluralInfo(android.icu.util.ULocale);
-    method public java.lang.Object clone();
-    method public java.lang.String getCurrencyPluralPattern(java.lang.String);
+    method public Object clone();
+    method public String getCurrencyPluralPattern(String);
     method public static android.icu.text.CurrencyPluralInfo getInstance();
     method public static android.icu.text.CurrencyPluralInfo getInstance(java.util.Locale);
     method public static android.icu.text.CurrencyPluralInfo getInstance(android.icu.util.ULocale);
     method public android.icu.util.ULocale getLocale();
     method public android.icu.text.PluralRules getPluralRules();
-    method public void setCurrencyPluralPattern(java.lang.String, java.lang.String);
+    method public void setCurrencyPluralPattern(String, String);
     method public void setLocale(android.icu.util.ULocale);
-    method public void setPluralRules(java.lang.String);
+    method public void setPluralRules(String);
   }
 
   public abstract class DateFormat extends android.icu.text.UFormat {
     ctor protected DateFormat();
-    method public final java.lang.StringBuffer format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition);
-    method public abstract java.lang.StringBuffer format(android.icu.util.Calendar, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.lang.StringBuffer format(java.util.Date, java.lang.StringBuffer, java.text.FieldPosition);
-    method public final java.lang.String format(java.util.Date);
+    method public final StringBuffer format(Object, StringBuffer, java.text.FieldPosition);
+    method public abstract StringBuffer format(android.icu.util.Calendar, StringBuffer, java.text.FieldPosition);
+    method public StringBuffer format(java.util.Date, StringBuffer, java.text.FieldPosition);
+    method public final String format(java.util.Date);
     method public static java.util.Locale[] getAvailableLocales();
     method public boolean getBooleanAttribute(android.icu.text.DateFormat.BooleanAttribute);
     method public android.icu.util.Calendar getCalendar();
@@ -19596,17 +19603,17 @@
     method public static final android.icu.text.DateFormat getInstance();
     method public static final android.icu.text.DateFormat getInstance(android.icu.util.Calendar, java.util.Locale);
     method public static final android.icu.text.DateFormat getInstance(android.icu.util.Calendar);
-    method public static final android.icu.text.DateFormat getInstanceForSkeleton(java.lang.String);
-    method public static final android.icu.text.DateFormat getInstanceForSkeleton(java.lang.String, java.util.Locale);
-    method public static final android.icu.text.DateFormat getInstanceForSkeleton(java.lang.String, android.icu.util.ULocale);
-    method public static final android.icu.text.DateFormat getInstanceForSkeleton(android.icu.util.Calendar, java.lang.String, java.util.Locale);
-    method public static final android.icu.text.DateFormat getInstanceForSkeleton(android.icu.util.Calendar, java.lang.String, android.icu.util.ULocale);
+    method public static final android.icu.text.DateFormat getInstanceForSkeleton(String);
+    method public static final android.icu.text.DateFormat getInstanceForSkeleton(String, java.util.Locale);
+    method public static final android.icu.text.DateFormat getInstanceForSkeleton(String, android.icu.util.ULocale);
+    method public static final android.icu.text.DateFormat getInstanceForSkeleton(android.icu.util.Calendar, String, java.util.Locale);
+    method public static final android.icu.text.DateFormat getInstanceForSkeleton(android.icu.util.Calendar, String, android.icu.util.ULocale);
     method public android.icu.text.NumberFormat getNumberFormat();
-    method public static final android.icu.text.DateFormat getPatternInstance(java.lang.String);
-    method public static final android.icu.text.DateFormat getPatternInstance(java.lang.String, java.util.Locale);
-    method public static final android.icu.text.DateFormat getPatternInstance(java.lang.String, android.icu.util.ULocale);
-    method public static final android.icu.text.DateFormat getPatternInstance(android.icu.util.Calendar, java.lang.String, java.util.Locale);
-    method public static final android.icu.text.DateFormat getPatternInstance(android.icu.util.Calendar, java.lang.String, android.icu.util.ULocale);
+    method public static final android.icu.text.DateFormat getPatternInstance(String);
+    method public static final android.icu.text.DateFormat getPatternInstance(String, java.util.Locale);
+    method public static final android.icu.text.DateFormat getPatternInstance(String, android.icu.util.ULocale);
+    method public static final android.icu.text.DateFormat getPatternInstance(android.icu.util.Calendar, String, java.util.Locale);
+    method public static final android.icu.text.DateFormat getPatternInstance(android.icu.util.Calendar, String, android.icu.util.ULocale);
     method public static final android.icu.text.DateFormat getTimeInstance();
     method public static final android.icu.text.DateFormat getTimeInstance(int);
     method public static final android.icu.text.DateFormat getTimeInstance(int, java.util.Locale);
@@ -19617,10 +19624,10 @@
     method public android.icu.util.TimeZone getTimeZone();
     method public boolean isCalendarLenient();
     method public boolean isLenient();
-    method public java.util.Date parse(java.lang.String) throws java.text.ParseException;
-    method public abstract void parse(java.lang.String, android.icu.util.Calendar, java.text.ParsePosition);
-    method public java.util.Date parse(java.lang.String, java.text.ParsePosition);
-    method public java.lang.Object parseObject(java.lang.String, java.text.ParsePosition);
+    method public java.util.Date parse(String) throws java.text.ParseException;
+    method public abstract void parse(String, android.icu.util.Calendar, java.text.ParsePosition);
+    method public java.util.Date parse(String, java.text.ParsePosition);
+    method public Object parseObject(String, java.text.ParsePosition);
     method public android.icu.text.DateFormat setBooleanAttribute(android.icu.text.DateFormat.BooleanAttribute, boolean);
     method public void setCalendar(android.icu.util.Calendar);
     method public void setCalendarLenient(boolean);
@@ -19628,18 +19635,18 @@
     method public void setLenient(boolean);
     method public void setNumberFormat(android.icu.text.NumberFormat);
     method public void setTimeZone(android.icu.util.TimeZone);
-    field public static final java.lang.String ABBR_GENERIC_TZ = "v";
-    field public static final java.lang.String ABBR_MONTH = "MMM";
-    field public static final java.lang.String ABBR_MONTH_DAY = "MMMd";
-    field public static final java.lang.String ABBR_MONTH_WEEKDAY_DAY = "MMMEd";
-    field public static final java.lang.String ABBR_QUARTER = "QQQ";
-    field public static final java.lang.String ABBR_SPECIFIC_TZ = "z";
-    field public static final java.lang.String ABBR_UTC_TZ = "ZZZZ";
-    field public static final java.lang.String ABBR_WEEKDAY = "E";
+    field public static final String ABBR_GENERIC_TZ = "v";
+    field public static final String ABBR_MONTH = "MMM";
+    field public static final String ABBR_MONTH_DAY = "MMMd";
+    field public static final String ABBR_MONTH_WEEKDAY_DAY = "MMMEd";
+    field public static final String ABBR_QUARTER = "QQQ";
+    field public static final String ABBR_SPECIFIC_TZ = "z";
+    field public static final String ABBR_UTC_TZ = "ZZZZ";
+    field public static final String ABBR_WEEKDAY = "E";
     field public static final int AM_PM_FIELD = 14; // 0xe
     field public static final int AM_PM_MIDNIGHT_NOON_FIELD = 35; // 0x23
     field public static final int DATE_FIELD = 3; // 0x3
-    field public static final java.lang.String DAY = "d";
+    field public static final String DAY = "d";
     field public static final int DAY_OF_WEEK_FIELD = 9; // 0x9
     field public static final int DAY_OF_WEEK_IN_MONTH_FIELD = 11; // 0xb
     field public static final int DAY_OF_YEAR_FIELD = 10; // 0xa
@@ -19650,35 +19657,35 @@
     field public static final int FLEXIBLE_DAY_PERIOD_FIELD = 36; // 0x24
     field public static final int FRACTIONAL_SECOND_FIELD = 8; // 0x8
     field public static final int FULL = 0; // 0x0
-    field public static final java.lang.String GENERIC_TZ = "vvvv";
-    field public static final java.lang.String HOUR = "j";
+    field public static final String GENERIC_TZ = "vvvv";
+    field public static final String HOUR = "j";
     field public static final int HOUR0_FIELD = 16; // 0x10
     field public static final int HOUR1_FIELD = 15; // 0xf
-    field public static final java.lang.String HOUR24 = "H";
-    field public static final java.lang.String HOUR24_MINUTE = "Hm";
-    field public static final java.lang.String HOUR24_MINUTE_SECOND = "Hms";
-    field public static final java.lang.String HOUR_MINUTE = "jm";
-    field public static final java.lang.String HOUR_MINUTE_SECOND = "jms";
+    field public static final String HOUR24 = "H";
+    field public static final String HOUR24_MINUTE = "Hm";
+    field public static final String HOUR24_MINUTE_SECOND = "Hms";
+    field public static final String HOUR_MINUTE = "jm";
+    field public static final String HOUR_MINUTE_SECOND = "jms";
     field public static final int HOUR_OF_DAY0_FIELD = 5; // 0x5
     field public static final int HOUR_OF_DAY1_FIELD = 4; // 0x4
     field public static final int JULIAN_DAY_FIELD = 21; // 0x15
-    field public static final java.lang.String LOCATION_TZ = "VVVV";
+    field public static final String LOCATION_TZ = "VVVV";
     field public static final int LONG = 1; // 0x1
     field public static final int MEDIUM = 2; // 0x2
     field public static final int MILLISECONDS_IN_DAY_FIELD = 22; // 0x16
     field public static final int MILLISECOND_FIELD = 8; // 0x8
-    field public static final java.lang.String MINUTE = "m";
+    field public static final String MINUTE = "m";
     field public static final int MINUTE_FIELD = 6; // 0x6
-    field public static final java.lang.String MINUTE_SECOND = "ms";
-    field public static final java.lang.String MONTH = "MMMM";
-    field public static final java.lang.String MONTH_DAY = "MMMMd";
+    field public static final String MINUTE_SECOND = "ms";
+    field public static final String MONTH = "MMMM";
+    field public static final String MONTH_DAY = "MMMMd";
     field public static final int MONTH_FIELD = 2; // 0x2
-    field public static final java.lang.String MONTH_WEEKDAY_DAY = "MMMMEEEEd";
+    field public static final String MONTH_WEEKDAY_DAY = "MMMMEEEEd";
     field public static final int NONE = -1; // 0xffffffff
-    field public static final java.lang.String NUM_MONTH = "M";
-    field public static final java.lang.String NUM_MONTH_DAY = "Md";
-    field public static final java.lang.String NUM_MONTH_WEEKDAY_DAY = "MEd";
-    field public static final java.lang.String QUARTER = "QQQQ";
+    field public static final String NUM_MONTH = "M";
+    field public static final String NUM_MONTH_DAY = "Md";
+    field public static final String NUM_MONTH_WEEKDAY_DAY = "MEd";
+    field public static final String QUARTER = "QQQQ";
     field public static final int QUARTER_FIELD = 27; // 0x1b
     field public static final int RELATIVE = 128; // 0x80
     field public static final int RELATIVE_DEFAULT = 130; // 0x82
@@ -19686,10 +19693,10 @@
     field public static final int RELATIVE_LONG = 129; // 0x81
     field public static final int RELATIVE_MEDIUM = 130; // 0x82
     field public static final int RELATIVE_SHORT = 131; // 0x83
-    field public static final java.lang.String SECOND = "s";
+    field public static final String SECOND = "s";
     field public static final int SECOND_FIELD = 7; // 0x7
     field public static final int SHORT = 3; // 0x3
-    field public static final java.lang.String SPECIFIC_TZ = "zzzz";
+    field public static final String SPECIFIC_TZ = "zzzz";
     field public static final int STANDALONE_DAY_FIELD = 25; // 0x19
     field public static final int STANDALONE_MONTH_FIELD = 26; // 0x1a
     field public static final int STANDALONE_QUARTER_FIELD = 28; // 0x1c
@@ -19700,31 +19707,29 @@
     field public static final int TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD = 31; // 0x1f
     field public static final int TIMEZONE_RFC_FIELD = 23; // 0x17
     field public static final int TIMEZONE_SPECIAL_FIELD = 29; // 0x1d
-    field public static final java.lang.String WEEKDAY = "EEEE";
+    field public static final String WEEKDAY = "EEEE";
     field public static final int WEEK_OF_MONTH_FIELD = 13; // 0xd
     field public static final int WEEK_OF_YEAR_FIELD = 12; // 0xc
-    field public static final java.lang.String YEAR = "y";
-    field public static final java.lang.String YEAR_ABBR_MONTH = "yMMM";
-    field public static final java.lang.String YEAR_ABBR_MONTH_DAY = "yMMMd";
-    field public static final java.lang.String YEAR_ABBR_MONTH_WEEKDAY_DAY = "yMMMEd";
-    field public static final java.lang.String YEAR_ABBR_QUARTER = "yQQQ";
+    field public static final String YEAR = "y";
+    field public static final String YEAR_ABBR_MONTH = "yMMM";
+    field public static final String YEAR_ABBR_MONTH_DAY = "yMMMd";
+    field public static final String YEAR_ABBR_MONTH_WEEKDAY_DAY = "yMMMEd";
+    field public static final String YEAR_ABBR_QUARTER = "yQQQ";
     field public static final int YEAR_FIELD = 1; // 0x1
-    field public static final java.lang.String YEAR_MONTH = "yMMMM";
-    field public static final java.lang.String YEAR_MONTH_DAY = "yMMMMd";
-    field public static final java.lang.String YEAR_MONTH_WEEKDAY_DAY = "yMMMMEEEEd";
+    field public static final String YEAR_MONTH = "yMMMM";
+    field public static final String YEAR_MONTH_DAY = "yMMMMd";
+    field public static final String YEAR_MONTH_WEEKDAY_DAY = "yMMMMEEEEd";
     field public static final int YEAR_NAME_FIELD = 30; // 0x1e
-    field public static final java.lang.String YEAR_NUM_MONTH = "yM";
-    field public static final java.lang.String YEAR_NUM_MONTH_DAY = "yMd";
-    field public static final java.lang.String YEAR_NUM_MONTH_WEEKDAY_DAY = "yMEd";
-    field public static final java.lang.String YEAR_QUARTER = "yQQQQ";
+    field public static final String YEAR_NUM_MONTH = "yM";
+    field public static final String YEAR_NUM_MONTH_DAY = "yMd";
+    field public static final String YEAR_NUM_MONTH_WEEKDAY_DAY = "yMEd";
+    field public static final String YEAR_QUARTER = "yQQQQ";
     field public static final int YEAR_WOY_FIELD = 18; // 0x12
     field protected android.icu.util.Calendar calendar;
     field protected android.icu.text.NumberFormat numberFormat;
   }
 
-  public static final class DateFormat.BooleanAttribute extends java.lang.Enum {
-    method public static android.icu.text.DateFormat.BooleanAttribute valueOf(java.lang.String);
-    method public static final android.icu.text.DateFormat.BooleanAttribute[] values();
+  public enum DateFormat.BooleanAttribute {
     enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_ALLOW_NUMERIC;
     enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_ALLOW_WHITESPACE;
     enum_constant public static final android.icu.text.DateFormat.BooleanAttribute PARSE_MULTIPLE_PATTERNS_FOR_MATCH;
@@ -19732,7 +19737,7 @@
   }
 
   public static class DateFormat.Field extends java.text.Format.Field {
-    ctor protected DateFormat.Field(java.lang.String, int);
+    ctor protected DateFormat.Field(String, int);
     method public int getCalendarField();
     method public static android.icu.text.DateFormat.Field ofCalendarField(int);
     field public static final android.icu.text.DateFormat.Field AM_PM;
@@ -19769,44 +19774,44 @@
     ctor public DateFormatSymbols(android.icu.util.ULocale);
     ctor public DateFormatSymbols(android.icu.util.Calendar, java.util.Locale);
     ctor public DateFormatSymbols(android.icu.util.Calendar, android.icu.util.ULocale);
-    ctor public DateFormatSymbols(java.lang.Class<? extends android.icu.util.Calendar>, java.util.Locale);
-    ctor public DateFormatSymbols(java.lang.Class<? extends android.icu.util.Calendar>, android.icu.util.ULocale);
+    ctor public DateFormatSymbols(Class<? extends android.icu.util.Calendar>, java.util.Locale);
+    ctor public DateFormatSymbols(Class<? extends android.icu.util.Calendar>, android.icu.util.ULocale);
     ctor public DateFormatSymbols(java.util.ResourceBundle, java.util.Locale);
     ctor public DateFormatSymbols(java.util.ResourceBundle, android.icu.util.ULocale);
-    method public java.lang.Object clone();
-    method public java.lang.String[] getAmPmStrings();
+    method public Object clone();
+    method public String[] getAmPmStrings();
     method public static java.util.Locale[] getAvailableLocales();
-    method public java.lang.String[] getEraNames();
-    method public java.lang.String[] getEras();
+    method public String[] getEraNames();
+    method public String[] getEras();
     method public static android.icu.text.DateFormatSymbols getInstance();
     method public static android.icu.text.DateFormatSymbols getInstance(java.util.Locale);
     method public static android.icu.text.DateFormatSymbols getInstance(android.icu.util.ULocale);
-    method public java.lang.String getLocalPatternChars();
-    method public java.lang.String[] getMonths();
-    method public java.lang.String[] getMonths(int, int);
-    method public java.lang.String[] getQuarters(int, int);
-    method public java.lang.String[] getShortMonths();
-    method public java.lang.String[] getShortWeekdays();
-    method public java.lang.String[] getWeekdays();
-    method public java.lang.String[] getWeekdays(int, int);
-    method public java.lang.String[] getYearNames(int, int);
-    method public java.lang.String[] getZodiacNames(int, int);
-    method public java.lang.String[][] getZoneStrings();
-    method protected void initializeData(android.icu.util.ULocale, java.lang.String);
-    method public void setAmPmStrings(java.lang.String[]);
-    method public void setEraNames(java.lang.String[]);
-    method public void setEras(java.lang.String[]);
-    method public void setLocalPatternChars(java.lang.String);
-    method public void setMonths(java.lang.String[]);
-    method public void setMonths(java.lang.String[], int, int);
-    method public void setQuarters(java.lang.String[], int, int);
-    method public void setShortMonths(java.lang.String[]);
-    method public void setShortWeekdays(java.lang.String[]);
-    method public void setWeekdays(java.lang.String[], int, int);
-    method public void setWeekdays(java.lang.String[]);
-    method public void setYearNames(java.lang.String[], int, int);
-    method public void setZodiacNames(java.lang.String[], int, int);
-    method public void setZoneStrings(java.lang.String[][]);
+    method public String getLocalPatternChars();
+    method public String[] getMonths();
+    method public String[] getMonths(int, int);
+    method public String[] getQuarters(int, int);
+    method public String[] getShortMonths();
+    method public String[] getShortWeekdays();
+    method public String[] getWeekdays();
+    method public String[] getWeekdays(int, int);
+    method public String[] getYearNames(int, int);
+    method public String[] getZodiacNames(int, int);
+    method public String[][] getZoneStrings();
+    method protected void initializeData(android.icu.util.ULocale, String);
+    method public void setAmPmStrings(String[]);
+    method public void setEraNames(String[]);
+    method public void setEras(String[]);
+    method public void setLocalPatternChars(String);
+    method public void setMonths(String[]);
+    method public void setMonths(String[], int, int);
+    method public void setQuarters(String[], int, int);
+    method public void setShortMonths(String[]);
+    method public void setShortWeekdays(String[]);
+    method public void setWeekdays(String[], int, int);
+    method public void setWeekdays(String[]);
+    method public void setYearNames(String[], int, int);
+    method public void setZodiacNames(String[], int, int);
+    method public void setZoneStrings(String[][]);
     field public static final int ABBREVIATED = 0; // 0x0
     field public static final int FORMAT = 0; // 0x0
     field public static final int NARROW = 2; // 0x2
@@ -19816,72 +19821,71 @@
   }
 
   public class DateIntervalFormat extends android.icu.text.UFormat {
-    method public synchronized java.lang.Object clone();
-    method public final java.lang.StringBuffer format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition);
-    method public final synchronized java.lang.StringBuffer format(android.icu.util.DateInterval, java.lang.StringBuffer, java.text.FieldPosition);
-    method public final synchronized java.lang.StringBuffer format(android.icu.util.Calendar, android.icu.util.Calendar, java.lang.StringBuffer, java.text.FieldPosition);
-    method public synchronized android.icu.text.DateFormat getDateFormat();
+    method public final StringBuffer format(Object, StringBuffer, java.text.FieldPosition);
+    method public final StringBuffer format(android.icu.util.DateInterval, StringBuffer, java.text.FieldPosition);
+    method public final StringBuffer format(android.icu.util.Calendar, android.icu.util.Calendar, StringBuffer, java.text.FieldPosition);
+    method public android.icu.text.DateFormat getDateFormat();
     method public android.icu.text.DateIntervalInfo getDateIntervalInfo();
-    method public static final android.icu.text.DateIntervalFormat getInstance(java.lang.String);
-    method public static final android.icu.text.DateIntervalFormat getInstance(java.lang.String, java.util.Locale);
-    method public static final android.icu.text.DateIntervalFormat getInstance(java.lang.String, android.icu.util.ULocale);
-    method public static final android.icu.text.DateIntervalFormat getInstance(java.lang.String, android.icu.text.DateIntervalInfo);
-    method public static final android.icu.text.DateIntervalFormat getInstance(java.lang.String, java.util.Locale, android.icu.text.DateIntervalInfo);
-    method public static final android.icu.text.DateIntervalFormat getInstance(java.lang.String, android.icu.util.ULocale, android.icu.text.DateIntervalInfo);
+    method public static final android.icu.text.DateIntervalFormat getInstance(String);
+    method public static final android.icu.text.DateIntervalFormat getInstance(String, java.util.Locale);
+    method public static final android.icu.text.DateIntervalFormat getInstance(String, android.icu.util.ULocale);
+    method public static final android.icu.text.DateIntervalFormat getInstance(String, android.icu.text.DateIntervalInfo);
+    method public static final android.icu.text.DateIntervalFormat getInstance(String, java.util.Locale, android.icu.text.DateIntervalInfo);
+    method public static final android.icu.text.DateIntervalFormat getInstance(String, android.icu.util.ULocale, android.icu.text.DateIntervalInfo);
     method public android.icu.util.TimeZone getTimeZone();
-    method public deprecated java.lang.Object parseObject(java.lang.String, java.text.ParsePosition);
+    method @Deprecated public Object parseObject(String, java.text.ParsePosition);
     method public void setDateIntervalInfo(android.icu.text.DateIntervalInfo);
     method public void setTimeZone(android.icu.util.TimeZone);
   }
 
-  public class DateIntervalInfo implements java.lang.Cloneable android.icu.util.Freezable java.io.Serializable {
+  public class DateIntervalInfo implements java.lang.Cloneable android.icu.util.Freezable<android.icu.text.DateIntervalInfo> java.io.Serializable {
     ctor public DateIntervalInfo(android.icu.util.ULocale);
     ctor public DateIntervalInfo(java.util.Locale);
-    method public java.lang.Object clone();
+    method public Object clone();
     method public android.icu.text.DateIntervalInfo cloneAsThawed();
     method public android.icu.text.DateIntervalInfo freeze();
     method public boolean getDefaultOrder();
-    method public java.lang.String getFallbackIntervalPattern();
-    method public android.icu.text.DateIntervalInfo.PatternInfo getIntervalPattern(java.lang.String, int);
+    method public String getFallbackIntervalPattern();
+    method public android.icu.text.DateIntervalInfo.PatternInfo getIntervalPattern(String, int);
     method public boolean isFrozen();
-    method public void setFallbackIntervalPattern(java.lang.String);
-    method public void setIntervalPattern(java.lang.String, int, java.lang.String);
+    method public void setFallbackIntervalPattern(String);
+    method public void setIntervalPattern(String, int, String);
   }
 
   public static final class DateIntervalInfo.PatternInfo implements java.lang.Cloneable java.io.Serializable {
-    ctor public DateIntervalInfo.PatternInfo(java.lang.String, java.lang.String, boolean);
+    ctor public DateIntervalInfo.PatternInfo(String, String, boolean);
     method public boolean firstDateInPtnIsLaterDate();
-    method public java.lang.String getFirstPart();
-    method public java.lang.String getSecondPart();
+    method public String getFirstPart();
+    method public String getSecondPart();
   }
 
-  public class DateTimePatternGenerator implements java.lang.Cloneable android.icu.util.Freezable {
+  public class DateTimePatternGenerator implements java.lang.Cloneable android.icu.util.Freezable<android.icu.text.DateTimePatternGenerator> {
     ctor protected DateTimePatternGenerator();
-    method public android.icu.text.DateTimePatternGenerator addPattern(java.lang.String, boolean, android.icu.text.DateTimePatternGenerator.PatternInfo);
-    method public java.lang.Object clone();
+    method public android.icu.text.DateTimePatternGenerator addPattern(String, boolean, android.icu.text.DateTimePatternGenerator.PatternInfo);
+    method public Object clone();
     method public android.icu.text.DateTimePatternGenerator cloneAsThawed();
     method public android.icu.text.DateTimePatternGenerator freeze();
-    method public java.lang.String getAppendItemFormat(int);
-    method public java.lang.String getAppendItemName(int);
-    method public java.lang.String getBaseSkeleton(java.lang.String);
+    method public String getAppendItemFormat(int);
+    method public String getAppendItemName(int);
+    method public String getBaseSkeleton(String);
     method public java.util.Set<java.lang.String> getBaseSkeletons(java.util.Set<java.lang.String>);
-    method public java.lang.String getBestPattern(java.lang.String);
-    method public java.lang.String getBestPattern(java.lang.String, int);
-    method public java.lang.String getDateTimeFormat();
-    method public java.lang.String getDecimal();
+    method public String getBestPattern(String);
+    method public String getBestPattern(String, int);
+    method public String getDateTimeFormat();
+    method public String getDecimal();
     method public static android.icu.text.DateTimePatternGenerator getEmptyInstance();
     method public static android.icu.text.DateTimePatternGenerator getInstance();
     method public static android.icu.text.DateTimePatternGenerator getInstance(android.icu.util.ULocale);
     method public static android.icu.text.DateTimePatternGenerator getInstance(java.util.Locale);
-    method public java.lang.String getSkeleton(java.lang.String);
-    method public java.util.Map<java.lang.String, java.lang.String> getSkeletons(java.util.Map<java.lang.String, java.lang.String>);
+    method public String getSkeleton(String);
+    method public java.util.Map<java.lang.String,java.lang.String> getSkeletons(java.util.Map<java.lang.String,java.lang.String>);
     method public boolean isFrozen();
-    method public java.lang.String replaceFieldTypes(java.lang.String, java.lang.String);
-    method public java.lang.String replaceFieldTypes(java.lang.String, java.lang.String, int);
-    method public void setAppendItemFormat(int, java.lang.String);
-    method public void setAppendItemName(int, java.lang.String);
-    method public void setDateTimeFormat(java.lang.String);
-    method public void setDecimal(java.lang.String);
+    method public String replaceFieldTypes(String, String);
+    method public String replaceFieldTypes(String, String, int);
+    method public void setAppendItemFormat(int, String);
+    method public void setAppendItemName(int, String);
+    method public void setDateTimeFormat(String);
+    method public void setDecimal(String);
     field public static final int DAY = 7; // 0x7
     field public static final int DAYPERIOD = 10; // 0xa
     field public static final int DAY_OF_WEEK_IN_MONTH = 9; // 0x9
@@ -19908,99 +19912,79 @@
     field public static final int BASE_CONFLICT = 1; // 0x1
     field public static final int CONFLICT = 2; // 0x2
     field public static final int OK = 0; // 0x0
-    field public java.lang.String conflictingPattern;
+    field public String conflictingPattern;
     field public int status;
   }
 
   public class DecimalFormat extends android.icu.text.NumberFormat {
     ctor public DecimalFormat();
-    ctor public DecimalFormat(java.lang.String);
-    ctor public DecimalFormat(java.lang.String, android.icu.text.DecimalFormatSymbols);
-    ctor public DecimalFormat(java.lang.String, android.icu.text.DecimalFormatSymbols, android.icu.text.CurrencyPluralInfo, int);
-    method public synchronized void applyLocalizedPattern(java.lang.String);
-    method public synchronized void applyPattern(java.lang.String);
-    method public synchronized boolean areSignificantDigitsUsed();
-    method public synchronized boolean equals(java.lang.Object);
-    method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
-    method public synchronized android.icu.util.Currency getCurrency();
-    method public synchronized android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
-    method public synchronized android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
-    method public synchronized android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
-    method public synchronized int getFormatWidth();
-    method public synchronized int getGroupingSize();
-    method public synchronized java.math.MathContext getMathContext();
-    method public synchronized android.icu.math.MathContext getMathContextICU();
-    method public synchronized int getMaximumFractionDigits();
-    method public synchronized int getMaximumIntegerDigits();
-    method public synchronized int getMaximumSignificantDigits();
-    method public synchronized byte getMinimumExponentDigits();
-    method public synchronized int getMinimumFractionDigits();
-    method public synchronized int getMinimumIntegerDigits();
-    method public synchronized int getMinimumSignificantDigits();
-    method public synchronized int getMultiplier();
-    method public synchronized java.lang.String getNegativePrefix();
-    method public synchronized java.lang.String getNegativeSuffix();
-    method public synchronized char getPadCharacter();
-    method public synchronized int getPadPosition();
-    method public deprecated int getParseMaxDigits();
-    method public synchronized java.lang.String getPositivePrefix();
-    method public synchronized java.lang.String getPositiveSuffix();
-    method public synchronized java.math.BigDecimal getRoundingIncrement();
-    method public synchronized int getRoundingMode();
-    method public synchronized int getSecondaryGroupingSize();
-    method public synchronized int hashCode();
-    method public synchronized boolean isDecimalPatternMatchRequired();
-    method public synchronized boolean isDecimalSeparatorAlwaysShown();
-    method public synchronized boolean isExponentSignAlwaysShown();
-    method public synchronized boolean isGroupingUsed();
-    method public synchronized boolean isParseBigDecimal();
-    method public synchronized boolean isParseIntegerOnly();
-    method public synchronized boolean isParseStrict();
-    method public synchronized boolean isScientificNotation();
-    method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
-    method public synchronized void setCurrency(android.icu.util.Currency);
-    method public synchronized void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
-    method public synchronized void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
-    method public synchronized void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
-    method public synchronized void setDecimalPatternMatchRequired(boolean);
-    method public synchronized void setDecimalSeparatorAlwaysShown(boolean);
-    method public synchronized void setExponentSignAlwaysShown(boolean);
-    method public synchronized void setFormatWidth(int);
-    method public synchronized void setGroupingSize(int);
-    method public synchronized void setGroupingUsed(boolean);
-    method public synchronized void setMathContext(java.math.MathContext);
-    method public synchronized void setMathContextICU(android.icu.math.MathContext);
-    method public synchronized void setMaximumFractionDigits(int);
-    method public synchronized void setMaximumIntegerDigits(int);
-    method public synchronized void setMaximumSignificantDigits(int);
-    method public synchronized void setMinimumExponentDigits(byte);
-    method public synchronized void setMinimumFractionDigits(int);
-    method public synchronized void setMinimumIntegerDigits(int);
-    method public synchronized void setMinimumSignificantDigits(int);
-    method public synchronized void setMultiplier(int);
-    method public synchronized void setNegativePrefix(java.lang.String);
-    method public synchronized void setNegativeSuffix(java.lang.String);
-    method public synchronized void setPadCharacter(char);
-    method public synchronized void setPadPosition(int);
-    method public synchronized void setParseBigDecimal(boolean);
-    method public synchronized void setParseIntegerOnly(boolean);
-    method public deprecated void setParseMaxDigits(int);
-    method public synchronized void setParseStrict(boolean);
-    method public synchronized void setPositivePrefix(java.lang.String);
-    method public synchronized void setPositiveSuffix(java.lang.String);
-    method public synchronized void setRoundingIncrement(java.math.BigDecimal);
-    method public synchronized void setRoundingIncrement(android.icu.math.BigDecimal);
-    method public synchronized void setRoundingIncrement(double);
-    method public synchronized void setRoundingMode(int);
-    method public synchronized void setScientificNotation(boolean);
-    method public synchronized void setSecondaryGroupingSize(int);
-    method public synchronized void setSignificantDigitsUsed(boolean);
-    method public synchronized java.lang.String toLocalizedPattern();
-    method public synchronized java.lang.String toPattern();
+    ctor public DecimalFormat(String);
+    ctor public DecimalFormat(String, android.icu.text.DecimalFormatSymbols);
+    ctor public DecimalFormat(String, android.icu.text.DecimalFormatSymbols, android.icu.text.CurrencyPluralInfo, int);
+    method public void applyLocalizedPattern(String);
+    method public void applyPattern(String);
+    method public boolean areSignificantDigitsUsed();
+    method public StringBuffer format(double, StringBuffer, java.text.FieldPosition);
+    method public StringBuffer format(long, StringBuffer, java.text.FieldPosition);
+    method public StringBuffer format(java.math.BigInteger, StringBuffer, java.text.FieldPosition);
+    method public StringBuffer format(java.math.BigDecimal, StringBuffer, java.text.FieldPosition);
+    method public StringBuffer format(android.icu.math.BigDecimal, StringBuffer, java.text.FieldPosition);
+    method public android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
+    method public android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
+    method public android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
+    method public int getFormatWidth();
+    method public int getGroupingSize();
+    method public java.math.MathContext getMathContext();
+    method public android.icu.math.MathContext getMathContextICU();
+    method public int getMaximumSignificantDigits();
+    method public byte getMinimumExponentDigits();
+    method public int getMinimumSignificantDigits();
+    method public int getMultiplier();
+    method public String getNegativePrefix();
+    method public String getNegativeSuffix();
+    method public char getPadCharacter();
+    method public int getPadPosition();
+    method @Deprecated public int getParseMaxDigits();
+    method public String getPositivePrefix();
+    method public String getPositiveSuffix();
+    method public java.math.BigDecimal getRoundingIncrement();
+    method public int getSecondaryGroupingSize();
+    method public boolean isDecimalPatternMatchRequired();
+    method public boolean isDecimalSeparatorAlwaysShown();
+    method public boolean isExponentSignAlwaysShown();
+    method public boolean isParseBigDecimal();
+    method public boolean isScientificNotation();
+    method public Number parse(String, java.text.ParsePosition);
+    method public void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
+    method public void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
+    method public void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
+    method public void setDecimalPatternMatchRequired(boolean);
+    method public void setDecimalSeparatorAlwaysShown(boolean);
+    method public void setExponentSignAlwaysShown(boolean);
+    method public void setFormatWidth(int);
+    method public void setGroupingSize(int);
+    method public void setMathContext(java.math.MathContext);
+    method public void setMathContextICU(android.icu.math.MathContext);
+    method public void setMaximumSignificantDigits(int);
+    method public void setMinimumExponentDigits(byte);
+    method public void setMinimumSignificantDigits(int);
+    method public void setMultiplier(int);
+    method public void setNegativePrefix(String);
+    method public void setNegativeSuffix(String);
+    method public void setPadCharacter(char);
+    method public void setPadPosition(int);
+    method public void setParseBigDecimal(boolean);
+    method @Deprecated public void setParseMaxDigits(int);
+    method public void setPositivePrefix(String);
+    method public void setPositiveSuffix(String);
+    method public void setRoundingIncrement(java.math.BigDecimal);
+    method public void setRoundingIncrement(android.icu.math.BigDecimal);
+    method public void setRoundingIncrement(double);
+    method public void setScientificNotation(boolean);
+    method public void setSecondaryGroupingSize(int);
+    method public void setSignificantDigitsUsed(boolean);
+    method public String toLocalizedPattern();
+    method public String toPattern();
     field public static final int PAD_AFTER_PREFIX = 1; // 0x1
     field public static final int PAD_AFTER_SUFFIX = 3; // 0x3
     field public static final int PAD_BEFORE_PREFIX = 0; // 0x0
@@ -20011,74 +19995,74 @@
     ctor public DecimalFormatSymbols();
     ctor public DecimalFormatSymbols(java.util.Locale);
     ctor public DecimalFormatSymbols(android.icu.util.ULocale);
-    method public java.lang.Object clone();
+    method public Object clone();
     method public static android.icu.text.DecimalFormatSymbols forNumberingSystem(java.util.Locale, android.icu.text.NumberingSystem);
     method public static android.icu.text.DecimalFormatSymbols forNumberingSystem(android.icu.util.ULocale, android.icu.text.NumberingSystem);
     method public static java.util.Locale[] getAvailableLocales();
     method public android.icu.util.Currency getCurrency();
-    method public java.lang.String getCurrencySymbol();
+    method public String getCurrencySymbol();
     method public char getDecimalSeparator();
-    method public java.lang.String getDecimalSeparatorString();
+    method public String getDecimalSeparatorString();
     method public char getDigit();
-    method public java.lang.String[] getDigitStrings();
+    method public String[] getDigitStrings();
     method public char[] getDigits();
-    method public java.lang.String getExponentMultiplicationSign();
-    method public java.lang.String getExponentSeparator();
+    method public String getExponentMultiplicationSign();
+    method public String getExponentSeparator();
     method public char getGroupingSeparator();
-    method public java.lang.String getGroupingSeparatorString();
-    method public java.lang.String getInfinity();
+    method public String getGroupingSeparatorString();
+    method public String getInfinity();
     method public static android.icu.text.DecimalFormatSymbols getInstance();
     method public static android.icu.text.DecimalFormatSymbols getInstance(java.util.Locale);
     method public static android.icu.text.DecimalFormatSymbols getInstance(android.icu.util.ULocale);
-    method public java.lang.String getInternationalCurrencySymbol();
+    method public String getInternationalCurrencySymbol();
     method public java.util.Locale getLocale();
     method public char getMinusSign();
-    method public java.lang.String getMinusSignString();
+    method public String getMinusSignString();
     method public char getMonetaryDecimalSeparator();
-    method public java.lang.String getMonetaryDecimalSeparatorString();
+    method public String getMonetaryDecimalSeparatorString();
     method public char getMonetaryGroupingSeparator();
-    method public java.lang.String getMonetaryGroupingSeparatorString();
-    method public java.lang.String getNaN();
+    method public String getMonetaryGroupingSeparatorString();
+    method public String getNaN();
     method public char getPadEscape();
-    method public java.lang.String getPatternForCurrencySpacing(int, boolean);
+    method public String getPatternForCurrencySpacing(int, boolean);
     method public char getPatternSeparator();
     method public char getPerMill();
-    method public java.lang.String getPerMillString();
+    method public String getPerMillString();
     method public char getPercent();
-    method public java.lang.String getPercentString();
+    method public String getPercentString();
     method public char getPlusSign();
-    method public java.lang.String getPlusSignString();
+    method public String getPlusSignString();
     method public char getSignificantDigit();
     method public android.icu.util.ULocale getULocale();
     method public char getZeroDigit();
     method public void setCurrency(android.icu.util.Currency);
-    method public void setCurrencySymbol(java.lang.String);
+    method public void setCurrencySymbol(String);
     method public void setDecimalSeparator(char);
-    method public void setDecimalSeparatorString(java.lang.String);
+    method public void setDecimalSeparatorString(String);
     method public void setDigit(char);
-    method public void setDigitStrings(java.lang.String[]);
-    method public void setExponentMultiplicationSign(java.lang.String);
-    method public void setExponentSeparator(java.lang.String);
+    method public void setDigitStrings(String[]);
+    method public void setExponentMultiplicationSign(String);
+    method public void setExponentSeparator(String);
     method public void setGroupingSeparator(char);
-    method public void setGroupingSeparatorString(java.lang.String);
-    method public void setInfinity(java.lang.String);
-    method public void setInternationalCurrencySymbol(java.lang.String);
+    method public void setGroupingSeparatorString(String);
+    method public void setInfinity(String);
+    method public void setInternationalCurrencySymbol(String);
     method public void setMinusSign(char);
-    method public void setMinusSignString(java.lang.String);
+    method public void setMinusSignString(String);
     method public void setMonetaryDecimalSeparator(char);
-    method public void setMonetaryDecimalSeparatorString(java.lang.String);
+    method public void setMonetaryDecimalSeparatorString(String);
     method public void setMonetaryGroupingSeparator(char);
-    method public void setMonetaryGroupingSeparatorString(java.lang.String);
-    method public void setNaN(java.lang.String);
+    method public void setMonetaryGroupingSeparatorString(String);
+    method public void setNaN(String);
     method public void setPadEscape(char);
-    method public void setPatternForCurrencySpacing(int, boolean, java.lang.String);
+    method public void setPatternForCurrencySpacing(int, boolean, String);
     method public void setPatternSeparator(char);
     method public void setPerMill(char);
-    method public void setPerMillString(java.lang.String);
+    method public void setPerMillString(String);
     method public void setPercent(char);
-    method public void setPercentString(java.lang.String);
+    method public void setPercentString(String);
     method public void setPlusSign(char);
-    method public void setPlusSignString(java.lang.String);
+    method public void setPlusSignString(String);
     method public void setSignificantDigit(char);
     method public void setZeroDigit(char);
     field public static final int CURRENCY_SPC_CURRENCY_MATCH = 0; // 0x0
@@ -20086,11 +20070,9 @@
     field public static final int CURRENCY_SPC_SURROUNDING_MATCH = 1; // 0x1
   }
 
-  public final class DisplayContext extends java.lang.Enum {
+  public enum DisplayContext {
     method public android.icu.text.DisplayContext.Type type();
     method public int value();
-    method public static android.icu.text.DisplayContext valueOf(java.lang.String);
-    method public static final android.icu.text.DisplayContext[] values();
     enum_constant public static final android.icu.text.DisplayContext CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE;
     enum_constant public static final android.icu.text.DisplayContext CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE;
     enum_constant public static final android.icu.text.DisplayContext CAPITALIZATION_FOR_STANDALONE;
@@ -20104,9 +20086,7 @@
     enum_constant public static final android.icu.text.DisplayContext SUBSTITUTE;
   }
 
-  public static final class DisplayContext.Type extends java.lang.Enum {
-    method public static android.icu.text.DisplayContext.Type valueOf(java.lang.String);
-    method public static final android.icu.text.DisplayContext.Type[] values();
+  public enum DisplayContext.Type {
     enum_constant public static final android.icu.text.DisplayContext.Type CAPITALIZATION;
     enum_constant public static final android.icu.text.DisplayContext.Type DIALECT_HANDLING;
     enum_constant public static final android.icu.text.DisplayContext.Type DISPLAY_LENGTH;
@@ -20144,10 +20124,10 @@
 
   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);
-    method public abstract java.lang.StringBuilder labelToUnicode(java.lang.CharSequence, java.lang.StringBuilder, android.icu.text.IDNA.Info);
-    method public abstract java.lang.StringBuilder nameToASCII(java.lang.CharSequence, java.lang.StringBuilder, android.icu.text.IDNA.Info);
-    method public abstract java.lang.StringBuilder nameToUnicode(java.lang.CharSequence, java.lang.StringBuilder, android.icu.text.IDNA.Info);
+    method public abstract StringBuilder labelToASCII(CharSequence, StringBuilder, android.icu.text.IDNA.Info);
+    method public abstract StringBuilder labelToUnicode(CharSequence, StringBuilder, android.icu.text.IDNA.Info);
+    method public abstract StringBuilder nameToASCII(CharSequence, StringBuilder, android.icu.text.IDNA.Info);
+    method public abstract StringBuilder nameToUnicode(CharSequence, StringBuilder, android.icu.text.IDNA.Info);
     field public static final int CHECK_BIDI = 4; // 0x4
     field public static final int CHECK_CONTEXTJ = 8; // 0x8
     field public static final int CHECK_CONTEXTO = 64; // 0x40
@@ -20157,9 +20137,7 @@
     field public static final int USE_STD3_RULES = 2; // 0x2
   }
 
-  public static final class IDNA.Error extends java.lang.Enum {
-    method public static android.icu.text.IDNA.Error valueOf(java.lang.String);
-    method public static final android.icu.text.IDNA.Error[] values();
+  public enum IDNA.Error {
     enum_constant public static final android.icu.text.IDNA.Error BIDI;
     enum_constant public static final android.icu.text.IDNA.Error CONTEXTJ;
     enum_constant public static final android.icu.text.IDNA.Error CONTEXTO_DIGITS;
@@ -20185,12 +20163,12 @@
   }
 
   public final class ListFormatter {
-    method public java.lang.String format(java.lang.Object...);
-    method public java.lang.String format(java.util.Collection<?>);
+    method public String format(java.lang.Object...);
+    method public String format(java.util.Collection<?>);
     method public static android.icu.text.ListFormatter getInstance(android.icu.util.ULocale);
     method public static android.icu.text.ListFormatter getInstance(java.util.Locale);
     method public static android.icu.text.ListFormatter getInstance();
-    method public java.lang.String getPatternForNumItems(int);
+    method public String getPatternForNumItems(int);
   }
 
   public abstract class LocaleDisplayNames {
@@ -20204,40 +20182,38 @@
     method public abstract android.icu.util.ULocale getLocale();
     method public java.util.List<android.icu.text.LocaleDisplayNames.UiListItem> getUiList(java.util.Set<android.icu.util.ULocale>, boolean, java.util.Comparator<java.lang.Object>);
     method public abstract java.util.List<android.icu.text.LocaleDisplayNames.UiListItem> getUiListCompareWholeItems(java.util.Set<android.icu.util.ULocale>, java.util.Comparator<android.icu.text.LocaleDisplayNames.UiListItem>);
-    method public abstract java.lang.String keyDisplayName(java.lang.String);
-    method public abstract java.lang.String keyValueDisplayName(java.lang.String, java.lang.String);
-    method public abstract java.lang.String languageDisplayName(java.lang.String);
-    method public abstract java.lang.String localeDisplayName(android.icu.util.ULocale);
-    method public abstract java.lang.String localeDisplayName(java.util.Locale);
-    method public abstract java.lang.String localeDisplayName(java.lang.String);
-    method public abstract java.lang.String regionDisplayName(java.lang.String);
-    method public abstract java.lang.String scriptDisplayName(java.lang.String);
-    method public abstract java.lang.String scriptDisplayName(int);
-    method public abstract java.lang.String variantDisplayName(java.lang.String);
+    method public abstract String keyDisplayName(String);
+    method public abstract String keyValueDisplayName(String, String);
+    method public abstract String languageDisplayName(String);
+    method public abstract String localeDisplayName(android.icu.util.ULocale);
+    method public abstract String localeDisplayName(java.util.Locale);
+    method public abstract String localeDisplayName(String);
+    method public abstract String regionDisplayName(String);
+    method public abstract String scriptDisplayName(String);
+    method public abstract String scriptDisplayName(int);
+    method public abstract String variantDisplayName(String);
   }
 
-  public static final class LocaleDisplayNames.DialectHandling extends java.lang.Enum {
-    method public static android.icu.text.LocaleDisplayNames.DialectHandling valueOf(java.lang.String);
-    method public static final android.icu.text.LocaleDisplayNames.DialectHandling[] values();
+  public enum LocaleDisplayNames.DialectHandling {
     enum_constant public static final android.icu.text.LocaleDisplayNames.DialectHandling DIALECT_NAMES;
     enum_constant public static final android.icu.text.LocaleDisplayNames.DialectHandling STANDARD_NAMES;
   }
 
   public static class LocaleDisplayNames.UiListItem {
-    ctor public LocaleDisplayNames.UiListItem(android.icu.util.ULocale, android.icu.util.ULocale, java.lang.String, java.lang.String);
+    ctor public LocaleDisplayNames.UiListItem(android.icu.util.ULocale, android.icu.util.ULocale, String, String);
     method public static java.util.Comparator<android.icu.text.LocaleDisplayNames.UiListItem> getComparator(java.util.Comparator<java.lang.Object>, boolean);
     field public final android.icu.util.ULocale minimized;
     field public final android.icu.util.ULocale modified;
-    field public final java.lang.String nameInDisplayLocale;
-    field public final java.lang.String nameInSelf;
+    field public final String nameInDisplayLocale;
+    field public final String nameInSelf;
   }
 
   public class MeasureFormat extends android.icu.text.UFormat {
-    method public final boolean equals(java.lang.Object);
-    method public java.lang.StringBuffer format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.lang.StringBuilder formatMeasurePerUnit(android.icu.util.Measure, android.icu.util.MeasureUnit, java.lang.StringBuilder, java.text.FieldPosition);
-    method public final java.lang.String formatMeasures(android.icu.util.Measure...);
-    method public java.lang.StringBuilder formatMeasures(java.lang.StringBuilder, java.text.FieldPosition, android.icu.util.Measure...);
+    method public final boolean equals(Object);
+    method public StringBuffer format(Object, StringBuffer, java.text.FieldPosition);
+    method public StringBuilder formatMeasurePerUnit(android.icu.util.Measure, android.icu.util.MeasureUnit, StringBuilder, java.text.FieldPosition);
+    method public final String formatMeasures(android.icu.util.Measure...);
+    method public StringBuilder formatMeasures(StringBuilder, java.text.FieldPosition, android.icu.util.Measure...);
     method public static android.icu.text.MeasureFormat getCurrencyFormat(android.icu.util.ULocale);
     method public static android.icu.text.MeasureFormat getCurrencyFormat(java.util.Locale);
     method public static android.icu.text.MeasureFormat getCurrencyFormat();
@@ -20247,15 +20223,13 @@
     method public static android.icu.text.MeasureFormat getInstance(java.util.Locale, android.icu.text.MeasureFormat.FormatWidth, android.icu.text.NumberFormat);
     method public final android.icu.util.ULocale getLocale();
     method public android.icu.text.NumberFormat getNumberFormat();
-    method public java.lang.String getUnitDisplayName(android.icu.util.MeasureUnit);
+    method public String getUnitDisplayName(android.icu.util.MeasureUnit);
     method public android.icu.text.MeasureFormat.FormatWidth getWidth();
     method public final int hashCode();
-    method public android.icu.util.Measure parseObject(java.lang.String, java.text.ParsePosition);
+    method public android.icu.util.Measure parseObject(String, java.text.ParsePosition);
   }
 
-  public static final class MeasureFormat.FormatWidth extends java.lang.Enum {
-    method public static android.icu.text.MeasureFormat.FormatWidth valueOf(java.lang.String);
-    method public static final android.icu.text.MeasureFormat.FormatWidth[] values();
+  public enum MeasureFormat.FormatWidth {
     enum_constant public static final android.icu.text.MeasureFormat.FormatWidth NARROW;
     enum_constant public static final android.icu.text.MeasureFormat.FormatWidth NUMERIC;
     enum_constant public static final android.icu.text.MeasureFormat.FormatWidth SHORT;
@@ -20263,54 +20237,54 @@
   }
 
   public class MessageFormat extends android.icu.text.UFormat {
-    ctor public MessageFormat(java.lang.String);
-    ctor public MessageFormat(java.lang.String, java.util.Locale);
-    ctor public MessageFormat(java.lang.String, android.icu.util.ULocale);
-    method public void applyPattern(java.lang.String);
-    method public void applyPattern(java.lang.String, android.icu.text.MessagePattern.ApostropheMode);
-    method public static java.lang.String autoQuoteApostrophe(java.lang.String);
-    method public final java.lang.StringBuffer format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition);
-    method public final java.lang.StringBuffer format(java.util.Map<java.lang.String, java.lang.Object>, java.lang.StringBuffer, java.text.FieldPosition);
-    method public static java.lang.String format(java.lang.String, java.lang.Object...);
-    method public static java.lang.String format(java.lang.String, java.util.Map<java.lang.String, java.lang.Object>);
-    method public final java.lang.StringBuffer format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition);
+    ctor public MessageFormat(String);
+    ctor public MessageFormat(String, java.util.Locale);
+    ctor public MessageFormat(String, android.icu.util.ULocale);
+    method public void applyPattern(String);
+    method public void applyPattern(String, android.icu.text.MessagePattern.ApostropheMode);
+    method public static String autoQuoteApostrophe(String);
+    method public final StringBuffer format(Object[], StringBuffer, java.text.FieldPosition);
+    method public final StringBuffer format(java.util.Map<java.lang.String,java.lang.Object>, StringBuffer, java.text.FieldPosition);
+    method public static String format(String, java.lang.Object...);
+    method public static String format(String, java.util.Map<java.lang.String,java.lang.Object>);
+    method public final StringBuffer format(Object, StringBuffer, java.text.FieldPosition);
     method public android.icu.text.MessagePattern.ApostropheMode getApostropheMode();
     method public java.util.Set<java.lang.String> getArgumentNames();
-    method public java.text.Format getFormatByArgumentName(java.lang.String);
+    method public java.text.Format getFormatByArgumentName(String);
     method public java.text.Format[] getFormats();
     method public java.text.Format[] getFormatsByArgumentIndex();
     method public java.util.Locale getLocale();
     method public android.icu.util.ULocale getULocale();
-    method public java.lang.Object[] parse(java.lang.String, java.text.ParsePosition);
-    method public java.lang.Object[] parse(java.lang.String) throws java.text.ParseException;
-    method public java.lang.Object parseObject(java.lang.String, java.text.ParsePosition);
-    method public java.util.Map<java.lang.String, java.lang.Object> parseToMap(java.lang.String, java.text.ParsePosition);
-    method public java.util.Map<java.lang.String, java.lang.Object> parseToMap(java.lang.String) throws java.text.ParseException;
+    method public Object[] parse(String, java.text.ParsePosition);
+    method public Object[] parse(String) throws java.text.ParseException;
+    method public Object parseObject(String, java.text.ParsePosition);
+    method public java.util.Map<java.lang.String,java.lang.Object> parseToMap(String, java.text.ParsePosition);
+    method public java.util.Map<java.lang.String,java.lang.Object> parseToMap(String) throws java.text.ParseException;
     method public void setFormat(int, java.text.Format);
     method public void setFormatByArgumentIndex(int, java.text.Format);
-    method public void setFormatByArgumentName(java.lang.String, java.text.Format);
+    method public void setFormatByArgumentName(String, java.text.Format);
     method public void setFormats(java.text.Format[]);
     method public void setFormatsByArgumentIndex(java.text.Format[]);
-    method public void setFormatsByArgumentName(java.util.Map<java.lang.String, java.text.Format>);
+    method public void setFormatsByArgumentName(java.util.Map<java.lang.String,java.text.Format>);
     method public void setLocale(java.util.Locale);
     method public void setLocale(android.icu.util.ULocale);
-    method public java.lang.String toPattern();
+    method public String toPattern();
     method public boolean usesNamedArguments();
   }
 
   public static class MessageFormat.Field extends java.text.Format.Field {
-    ctor protected MessageFormat.Field(java.lang.String);
+    ctor protected MessageFormat.Field(String);
     field public static final android.icu.text.MessageFormat.Field ARGUMENT;
   }
 
-  public final class MessagePattern implements java.lang.Cloneable android.icu.util.Freezable {
+  public final class MessagePattern implements java.lang.Cloneable android.icu.util.Freezable<android.icu.text.MessagePattern> {
     ctor public MessagePattern();
     ctor public MessagePattern(android.icu.text.MessagePattern.ApostropheMode);
-    ctor public MessagePattern(java.lang.String);
-    method public java.lang.String autoQuoteApostropheDeep();
+    ctor public MessagePattern(String);
+    method public String autoQuoteApostropheDeep();
     method public void clear();
     method public void clearPatternAndSetApostropheMode(android.icu.text.MessagePattern.ApostropheMode);
-    method public java.lang.Object clone();
+    method public Object clone();
     method public android.icu.text.MessagePattern cloneAsThawed();
     method public int countParts();
     method public android.icu.text.MessagePattern freeze();
@@ -20320,34 +20294,30 @@
     method public android.icu.text.MessagePattern.Part getPart(int);
     method public android.icu.text.MessagePattern.Part.Type getPartType(int);
     method public int getPatternIndex(int);
-    method public java.lang.String getPatternString();
+    method public String getPatternString();
     method public double getPluralOffset(int);
-    method public java.lang.String getSubstring(android.icu.text.MessagePattern.Part);
+    method public String getSubstring(android.icu.text.MessagePattern.Part);
     method public boolean hasNamedArguments();
     method public boolean hasNumberedArguments();
     method public boolean isFrozen();
-    method public android.icu.text.MessagePattern parse(java.lang.String);
-    method public android.icu.text.MessagePattern parseChoiceStyle(java.lang.String);
-    method public android.icu.text.MessagePattern parsePluralStyle(java.lang.String);
-    method public android.icu.text.MessagePattern parseSelectStyle(java.lang.String);
-    method public boolean partSubstringMatches(android.icu.text.MessagePattern.Part, java.lang.String);
-    method public static int validateArgumentName(java.lang.String);
+    method public android.icu.text.MessagePattern parse(String);
+    method public android.icu.text.MessagePattern parseChoiceStyle(String);
+    method public android.icu.text.MessagePattern parsePluralStyle(String);
+    method public android.icu.text.MessagePattern parseSelectStyle(String);
+    method public boolean partSubstringMatches(android.icu.text.MessagePattern.Part, String);
+    method public static int validateArgumentName(String);
     field public static final int ARG_NAME_NOT_NUMBER = -1; // 0xffffffff
     field public static final int ARG_NAME_NOT_VALID = -2; // 0xfffffffe
     field public static final double NO_NUMERIC_VALUE = -1.23456789E8;
   }
 
-  public static final class MessagePattern.ApostropheMode extends java.lang.Enum {
-    method public static android.icu.text.MessagePattern.ApostropheMode valueOf(java.lang.String);
-    method public static final android.icu.text.MessagePattern.ApostropheMode[] values();
+  public enum MessagePattern.ApostropheMode {
     enum_constant public static final android.icu.text.MessagePattern.ApostropheMode DOUBLE_OPTIONAL;
     enum_constant public static final android.icu.text.MessagePattern.ApostropheMode DOUBLE_REQUIRED;
   }
 
-  public static final class MessagePattern.ArgType extends java.lang.Enum {
+  public enum MessagePattern.ArgType {
     method public boolean hasPluralStyle();
-    method public static android.icu.text.MessagePattern.ArgType valueOf(java.lang.String);
-    method public static final android.icu.text.MessagePattern.ArgType[] values();
     enum_constant public static final android.icu.text.MessagePattern.ArgType CHOICE;
     enum_constant public static final android.icu.text.MessagePattern.ArgType NONE;
     enum_constant public static final android.icu.text.MessagePattern.ArgType PLURAL;
@@ -20365,10 +20335,8 @@
     method public int getValue();
   }
 
-  public static final class MessagePattern.Part.Type extends java.lang.Enum {
+  public enum MessagePattern.Part.Type {
     method public boolean hasNumericValue();
-    method public static android.icu.text.MessagePattern.Part.Type valueOf(java.lang.String);
-    method public static final android.icu.text.MessagePattern.Part.Type[] values();
     enum_constant public static final android.icu.text.MessagePattern.Part.Type ARG_DOUBLE;
     enum_constant public static final android.icu.text.MessagePattern.Part.Type ARG_INT;
     enum_constant public static final android.icu.text.MessagePattern.Part.Type ARG_LIMIT;
@@ -20386,12 +20354,12 @@
   }
 
   public final class Normalizer implements java.lang.Cloneable {
-    method public deprecated java.lang.Object clone();
+    method @Deprecated public Object clone();
     method public static int compare(char[], int, int, char[], int, int, int);
-    method public static int compare(java.lang.String, java.lang.String, int);
+    method public static int compare(String, String, int);
     method public static int compare(char[], char[], int);
     method public static int compare(int, int, int);
-    method public static int compare(int, java.lang.String, int);
+    method public static int compare(int, String, int);
     field public static final int COMPARE_CODE_POINT_ORDER = 32768; // 0x8000
     field public static final int COMPARE_IGNORE_CASE = 65536; // 0x10000
     field public static final int FOLD_CASE_DEFAULT = 0; // 0x0
@@ -20406,32 +20374,30 @@
   }
 
   public abstract class Normalizer2 {
-    method public abstract java.lang.StringBuilder append(java.lang.StringBuilder, java.lang.CharSequence);
+    method public abstract StringBuilder append(StringBuilder, CharSequence);
     method public int composePair(int, int);
     method public int getCombiningClass(int);
-    method public abstract java.lang.String getDecomposition(int);
-    method public static android.icu.text.Normalizer2 getInstance(java.io.InputStream, java.lang.String, android.icu.text.Normalizer2.Mode);
+    method public abstract String getDecomposition(int);
+    method public static android.icu.text.Normalizer2 getInstance(java.io.InputStream, String, android.icu.text.Normalizer2.Mode);
     method public static android.icu.text.Normalizer2 getNFCInstance();
     method public static android.icu.text.Normalizer2 getNFDInstance();
     method public static android.icu.text.Normalizer2 getNFKCCasefoldInstance();
     method public static android.icu.text.Normalizer2 getNFKCInstance();
     method public static android.icu.text.Normalizer2 getNFKDInstance();
-    method public java.lang.String getRawDecomposition(int);
+    method public String getRawDecomposition(int);
     method public abstract boolean hasBoundaryAfter(int);
     method public abstract boolean hasBoundaryBefore(int);
     method public abstract boolean isInert(int);
-    method public abstract boolean isNormalized(java.lang.CharSequence);
-    method public java.lang.String normalize(java.lang.CharSequence);
-    method public abstract java.lang.StringBuilder normalize(java.lang.CharSequence, java.lang.StringBuilder);
-    method public abstract java.lang.Appendable normalize(java.lang.CharSequence, java.lang.Appendable);
-    method public abstract java.lang.StringBuilder normalizeSecondAndAppend(java.lang.StringBuilder, java.lang.CharSequence);
-    method public abstract android.icu.text.Normalizer.QuickCheckResult quickCheck(java.lang.CharSequence);
-    method public abstract int spanQuickCheckYes(java.lang.CharSequence);
+    method public abstract boolean isNormalized(CharSequence);
+    method public String normalize(CharSequence);
+    method public abstract StringBuilder normalize(CharSequence, StringBuilder);
+    method public abstract Appendable normalize(CharSequence, Appendable);
+    method public abstract StringBuilder normalizeSecondAndAppend(StringBuilder, CharSequence);
+    method public abstract android.icu.text.Normalizer.QuickCheckResult quickCheck(CharSequence);
+    method public abstract int spanQuickCheckYes(CharSequence);
   }
 
-  public static final class Normalizer2.Mode extends java.lang.Enum {
-    method public static android.icu.text.Normalizer2.Mode valueOf(java.lang.String);
-    method public static final android.icu.text.Normalizer2.Mode[] values();
+  public enum Normalizer2.Mode {
     enum_constant public static final android.icu.text.Normalizer2.Mode COMPOSE;
     enum_constant public static final android.icu.text.Normalizer2.Mode COMPOSE_CONTIGUOUS;
     enum_constant public static final android.icu.text.Normalizer2.Mode DECOMPOSE;
@@ -20440,19 +20406,19 @@
 
   public abstract class NumberFormat extends android.icu.text.UFormat {
     ctor public NumberFormat();
-    method public java.lang.StringBuffer format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition);
-    method public final java.lang.String format(double);
-    method public final java.lang.String format(long);
-    method public final java.lang.String format(java.math.BigInteger);
-    method public final java.lang.String format(java.math.BigDecimal);
-    method public final java.lang.String format(android.icu.math.BigDecimal);
-    method public final java.lang.String format(android.icu.util.CurrencyAmount);
-    method public abstract java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
-    method public abstract java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
-    method public abstract java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
-    method public abstract java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
-    method public abstract java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.lang.StringBuffer format(android.icu.util.CurrencyAmount, java.lang.StringBuffer, java.text.FieldPosition);
+    method public StringBuffer format(Object, StringBuffer, java.text.FieldPosition);
+    method public final String format(double);
+    method public final String format(long);
+    method public final String format(java.math.BigInteger);
+    method public final String format(java.math.BigDecimal);
+    method public final String format(android.icu.math.BigDecimal);
+    method public final String format(android.icu.util.CurrencyAmount);
+    method public abstract StringBuffer format(double, StringBuffer, java.text.FieldPosition);
+    method public abstract StringBuffer format(long, StringBuffer, java.text.FieldPosition);
+    method public abstract StringBuffer format(java.math.BigInteger, StringBuffer, java.text.FieldPosition);
+    method public abstract StringBuffer format(java.math.BigDecimal, StringBuffer, java.text.FieldPosition);
+    method public abstract StringBuffer format(android.icu.math.BigDecimal, StringBuffer, java.text.FieldPosition);
+    method public StringBuffer format(android.icu.util.CurrencyAmount, StringBuffer, java.text.FieldPosition);
     method public static java.util.Locale[] getAvailableLocales();
     method public android.icu.text.DisplayContext getContext(android.icu.text.DisplayContext.Type);
     method public android.icu.util.Currency getCurrency();
@@ -20475,7 +20441,7 @@
     method public static final android.icu.text.NumberFormat getNumberInstance();
     method public static android.icu.text.NumberFormat getNumberInstance(java.util.Locale);
     method public static android.icu.text.NumberFormat getNumberInstance(android.icu.util.ULocale);
-    method protected static java.lang.String getPattern(android.icu.util.ULocale, int);
+    method protected static String getPattern(android.icu.util.ULocale, int);
     method public static final android.icu.text.NumberFormat getPercentInstance();
     method public static android.icu.text.NumberFormat getPercentInstance(java.util.Locale);
     method public static android.icu.text.NumberFormat getPercentInstance(android.icu.util.ULocale);
@@ -20486,10 +20452,10 @@
     method public boolean isGroupingUsed();
     method public boolean isParseIntegerOnly();
     method public boolean isParseStrict();
-    method public abstract java.lang.Number parse(java.lang.String, java.text.ParsePosition);
-    method public java.lang.Number parse(java.lang.String) throws java.text.ParseException;
-    method public android.icu.util.CurrencyAmount parseCurrency(java.lang.CharSequence, java.text.ParsePosition);
-    method public final java.lang.Object parseObject(java.lang.String, java.text.ParsePosition);
+    method public abstract Number parse(String, java.text.ParsePosition);
+    method public Number parse(String) throws java.text.ParseException;
+    method public android.icu.util.CurrencyAmount parseCurrency(CharSequence, java.text.ParsePosition);
+    method public final Object parseObject(String, java.text.ParsePosition);
     method public void setContext(android.icu.text.DisplayContext);
     method public void setCurrency(android.icu.util.Currency);
     method public void setGroupingUsed(boolean);
@@ -20515,7 +20481,7 @@
   }
 
   public static class NumberFormat.Field extends java.text.Format.Field {
-    ctor protected NumberFormat.Field(java.lang.String);
+    ctor protected NumberFormat.Field(String);
     field public static final android.icu.text.NumberFormat.Field CURRENCY;
     field public static final android.icu.text.NumberFormat.Field DECIMAL_SEPARATOR;
     field public static final android.icu.text.NumberFormat.Field EXPONENT;
@@ -20531,17 +20497,17 @@
 
   public class NumberingSystem {
     ctor public NumberingSystem();
-    method public static java.lang.String[] getAvailableNames();
-    method public java.lang.String getDescription();
-    method public static android.icu.text.NumberingSystem getInstance(int, boolean, java.lang.String);
+    method public static String[] getAvailableNames();
+    method public String getDescription();
+    method public static android.icu.text.NumberingSystem getInstance(int, boolean, String);
     method public static android.icu.text.NumberingSystem getInstance(java.util.Locale);
     method public static android.icu.text.NumberingSystem getInstance(android.icu.util.ULocale);
     method public static android.icu.text.NumberingSystem getInstance();
-    method public static android.icu.text.NumberingSystem getInstanceByName(java.lang.String);
-    method public java.lang.String getName();
+    method public static android.icu.text.NumberingSystem getInstanceByName(String);
+    method public String getName();
     method public int getRadix();
     method public boolean isAlgorithmic();
-    method public static boolean isValidDigitString(java.lang.String);
+    method public static boolean isValidDigitString(String);
     field public static final android.icu.text.NumberingSystem LATIN;
   }
 
@@ -20554,57 +20520,55 @@
     ctor public PluralFormat(java.util.Locale, android.icu.text.PluralRules);
     ctor public PluralFormat(android.icu.util.ULocale, android.icu.text.PluralRules.PluralType);
     ctor public PluralFormat(java.util.Locale, android.icu.text.PluralRules.PluralType);
-    ctor public PluralFormat(java.lang.String);
-    ctor public PluralFormat(android.icu.util.ULocale, java.lang.String);
-    ctor public PluralFormat(android.icu.text.PluralRules, java.lang.String);
-    ctor public PluralFormat(android.icu.util.ULocale, android.icu.text.PluralRules, java.lang.String);
-    ctor public PluralFormat(android.icu.util.ULocale, android.icu.text.PluralRules.PluralType, java.lang.String);
-    method public void applyPattern(java.lang.String);
+    ctor public PluralFormat(String);
+    ctor public PluralFormat(android.icu.util.ULocale, String);
+    ctor public PluralFormat(android.icu.text.PluralRules, String);
+    ctor public PluralFormat(android.icu.util.ULocale, android.icu.text.PluralRules, String);
+    ctor public PluralFormat(android.icu.util.ULocale, android.icu.text.PluralRules.PluralType, String);
+    method public void applyPattern(String);
     method public boolean equals(android.icu.text.PluralFormat);
-    method public final java.lang.String format(double);
-    method public java.lang.StringBuffer format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
-    method public java.lang.Object parseObject(java.lang.String, java.text.ParsePosition);
+    method public final String format(double);
+    method public StringBuffer format(Object, StringBuffer, java.text.FieldPosition);
+    method public Number parse(String, java.text.ParsePosition);
+    method public Object parseObject(String, java.text.ParsePosition);
     method public void setNumberFormat(android.icu.text.NumberFormat);
-    method public java.lang.String toPattern();
+    method public String toPattern();
   }
 
   public class PluralRules implements java.io.Serializable {
-    method public static android.icu.text.PluralRules createRules(java.lang.String);
+    method public static android.icu.text.PluralRules createRules(String);
     method public boolean equals(android.icu.text.PluralRules);
     method public static android.icu.text.PluralRules forLocale(android.icu.util.ULocale);
     method public static android.icu.text.PluralRules forLocale(java.util.Locale);
     method public static android.icu.text.PluralRules forLocale(android.icu.util.ULocale, android.icu.text.PluralRules.PluralType);
     method public static android.icu.text.PluralRules forLocale(java.util.Locale, android.icu.text.PluralRules.PluralType);
-    method public java.util.Collection<java.lang.Double> getAllKeywordValues(java.lang.String);
+    method public java.util.Collection<java.lang.Double> getAllKeywordValues(String);
     method public java.util.Set<java.lang.String> getKeywords();
-    method public java.util.Collection<java.lang.Double> getSamples(java.lang.String);
-    method public double getUniqueKeywordValue(java.lang.String);
-    method public static android.icu.text.PluralRules parseDescription(java.lang.String) throws java.text.ParseException;
-    method public java.lang.String select(double);
+    method public java.util.Collection<java.lang.Double> getSamples(String);
+    method public double getUniqueKeywordValue(String);
+    method public static android.icu.text.PluralRules parseDescription(String) throws java.text.ParseException;
+    method public String select(double);
     field public static final android.icu.text.PluralRules DEFAULT;
-    field public static final java.lang.String KEYWORD_FEW = "few";
-    field public static final java.lang.String KEYWORD_MANY = "many";
-    field public static final java.lang.String KEYWORD_ONE = "one";
-    field public static final java.lang.String KEYWORD_OTHER = "other";
-    field public static final java.lang.String KEYWORD_TWO = "two";
-    field public static final java.lang.String KEYWORD_ZERO = "zero";
+    field public static final String KEYWORD_FEW = "few";
+    field public static final String KEYWORD_MANY = "many";
+    field public static final String KEYWORD_ONE = "one";
+    field public static final String KEYWORD_OTHER = "other";
+    field public static final String KEYWORD_TWO = "two";
+    field public static final String KEYWORD_ZERO = "zero";
     field public static final double NO_UNIQUE_VALUE = -0.00123456777;
   }
 
-  public static final class PluralRules.PluralType extends java.lang.Enum {
-    method public static android.icu.text.PluralRules.PluralType valueOf(java.lang.String);
-    method public static final android.icu.text.PluralRules.PluralType[] values();
+  public enum PluralRules.PluralType {
     enum_constant public static final android.icu.text.PluralRules.PluralType CARDINAL;
     enum_constant public static final android.icu.text.PluralRules.PluralType ORDINAL;
   }
 
   public final class RelativeDateTimeFormatter {
-    method public java.lang.String combineDateAndTime(java.lang.String, java.lang.String);
-    method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
-    method public java.lang.String format(android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit);
-    method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit);
-    method public java.lang.String formatNumeric(double, android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit);
+    method public String combineDateAndTime(String, String);
+    method public String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
+    method public String format(android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit);
+    method public String format(double, android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit);
+    method public String formatNumeric(double, android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit);
     method public android.icu.text.DisplayContext getCapitalizationContext();
     method public android.icu.text.RelativeDateTimeFormatter.Style getFormatStyle();
     method public static android.icu.text.RelativeDateTimeFormatter getInstance();
@@ -20616,9 +20580,7 @@
     method public android.icu.text.NumberFormat getNumberFormat();
   }
 
-  public static final class RelativeDateTimeFormatter.AbsoluteUnit extends java.lang.Enum {
-    method public static android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit valueOf(java.lang.String);
-    method public static final android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit[] values();
+  public enum RelativeDateTimeFormatter.AbsoluteUnit {
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit DAY;
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit FRIDAY;
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit MONDAY;
@@ -20633,9 +20595,7 @@
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit YEAR;
   }
 
-  public static final class RelativeDateTimeFormatter.Direction extends java.lang.Enum {
-    method public static android.icu.text.RelativeDateTimeFormatter.Direction valueOf(java.lang.String);
-    method public static final android.icu.text.RelativeDateTimeFormatter.Direction[] values();
+  public enum RelativeDateTimeFormatter.Direction {
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.Direction LAST;
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.Direction LAST_2;
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.Direction NEXT;
@@ -20644,9 +20604,7 @@
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.Direction THIS;
   }
 
-  public static final class RelativeDateTimeFormatter.RelativeDateTimeUnit extends java.lang.Enum {
-    method public static android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit valueOf(java.lang.String);
-    method public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit[] values();
+  public enum RelativeDateTimeFormatter.RelativeDateTimeUnit {
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit DAY;
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit FRIDAY;
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit HOUR;
@@ -20664,9 +20622,7 @@
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit YEAR;
   }
 
-  public static final class RelativeDateTimeFormatter.RelativeUnit extends java.lang.Enum {
-    method public static android.icu.text.RelativeDateTimeFormatter.RelativeUnit valueOf(java.lang.String);
-    method public static final android.icu.text.RelativeDateTimeFormatter.RelativeUnit[] values();
+  public enum RelativeDateTimeFormatter.RelativeUnit {
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeUnit DAYS;
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeUnit HOURS;
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeUnit MINUTES;
@@ -20676,37 +20632,35 @@
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeUnit YEARS;
   }
 
-  public static final class RelativeDateTimeFormatter.Style extends java.lang.Enum {
-    method public static android.icu.text.RelativeDateTimeFormatter.Style valueOf(java.lang.String);
-    method public static final android.icu.text.RelativeDateTimeFormatter.Style[] values();
+  public enum RelativeDateTimeFormatter.Style {
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.Style LONG;
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.Style NARROW;
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.Style SHORT;
   }
 
-  public abstract interface Replaceable {
-    method public abstract int char32At(int);
-    method public abstract char charAt(int);
-    method public abstract void copy(int, int, int);
-    method public abstract void getChars(int, int, char[], int);
-    method public abstract boolean hasMetaData();
-    method public abstract int length();
-    method public abstract void replace(int, int, java.lang.String);
-    method public abstract void replace(int, int, char[], int, int);
+  public interface Replaceable {
+    method public int char32At(int);
+    method public char charAt(int);
+    method public void copy(int, int, int);
+    method public void getChars(int, int, char[], int);
+    method public boolean hasMetaData();
+    method public int length();
+    method public void replace(int, int, String);
+    method public void replace(int, int, char[], int, int);
   }
 
   public final class RuleBasedCollator extends android.icu.text.Collator {
-    ctor public RuleBasedCollator(java.lang.String) throws java.lang.Exception;
+    ctor public RuleBasedCollator(String) throws java.lang.Exception;
     method public android.icu.text.RuleBasedCollator cloneAsThawed();
-    method public int compare(java.lang.String, java.lang.String);
-    method public android.icu.text.CollationElementIterator getCollationElementIterator(java.lang.String);
+    method public int compare(String, String);
+    method public android.icu.text.CollationElementIterator getCollationElementIterator(String);
     method public android.icu.text.CollationElementIterator getCollationElementIterator(java.text.CharacterIterator);
     method public android.icu.text.CollationElementIterator getCollationElementIterator(android.icu.text.UCharacterIterator);
-    method public android.icu.text.CollationKey getCollationKey(java.lang.String);
+    method public android.icu.text.CollationKey getCollationKey(String);
     method public void getContractionsAndExpansions(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet, boolean) throws java.lang.Exception;
     method public boolean getNumericCollation();
-    method public java.lang.String getRules();
-    method public java.lang.String getRules(boolean);
+    method public String getRules();
+    method public String getRules(boolean);
     method public android.icu.util.VersionInfo getUCAVersion();
     method public int getVariableTop();
     method public android.icu.util.VersionInfo getVersion();
@@ -20732,9 +20686,9 @@
   }
 
   public final class ScientificNumberFormatter {
-    method public java.lang.String format(java.lang.Object);
-    method public static android.icu.text.ScientificNumberFormatter getMarkupInstance(android.icu.util.ULocale, java.lang.String, java.lang.String);
-    method public static android.icu.text.ScientificNumberFormatter getMarkupInstance(android.icu.text.DecimalFormat, java.lang.String, java.lang.String);
+    method public String format(Object);
+    method public static android.icu.text.ScientificNumberFormatter getMarkupInstance(android.icu.util.ULocale, String, String);
+    method public static android.icu.text.ScientificNumberFormatter getMarkupInstance(android.icu.text.DecimalFormat, String, String);
     method public static android.icu.text.ScientificNumberFormatter getSuperscriptInstance(android.icu.util.ULocale);
     method public static android.icu.text.ScientificNumberFormatter getSuperscriptInstance(android.icu.text.DecimalFormat);
   }
@@ -20748,7 +20702,7 @@
     method public abstract int getIndex();
     method public int getMatchLength();
     method public int getMatchStart();
-    method public java.lang.String getMatchedText();
+    method public String getMatchedText();
     method public java.text.CharacterIterator getTarget();
     method protected abstract int handleNext(int);
     method protected abstract int handlePrevious(int);
@@ -20770,57 +20724,55 @@
     field protected java.text.CharacterIterator targetText;
   }
 
-  public static final class SearchIterator.ElementComparisonType extends java.lang.Enum {
-    method public static android.icu.text.SearchIterator.ElementComparisonType valueOf(java.lang.String);
-    method public static final android.icu.text.SearchIterator.ElementComparisonType[] values();
+  public enum SearchIterator.ElementComparisonType {
     enum_constant public static final android.icu.text.SearchIterator.ElementComparisonType ANY_BASE_WEIGHT_IS_WILDCARD;
     enum_constant public static final android.icu.text.SearchIterator.ElementComparisonType PATTERN_BASE_WEIGHT_IS_WILDCARD;
     enum_constant public static final android.icu.text.SearchIterator.ElementComparisonType STANDARD_ELEMENT_COMPARISON;
   }
 
   public class SelectFormat extends java.text.Format {
-    ctor public SelectFormat(java.lang.String);
-    method public void applyPattern(java.lang.String);
-    method public final java.lang.String format(java.lang.String);
-    method public java.lang.StringBuffer format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.lang.Object parseObject(java.lang.String, java.text.ParsePosition);
-    method public java.lang.String toPattern();
+    ctor public SelectFormat(String);
+    method public void applyPattern(String);
+    method public final String format(String);
+    method public StringBuffer format(Object, StringBuffer, java.text.FieldPosition);
+    method public Object parseObject(String, java.text.ParsePosition);
+    method public String toPattern();
   }
 
   public class SimpleDateFormat extends android.icu.text.DateFormat {
     ctor public SimpleDateFormat();
-    ctor public SimpleDateFormat(java.lang.String);
-    ctor public SimpleDateFormat(java.lang.String, java.util.Locale);
-    ctor public SimpleDateFormat(java.lang.String, android.icu.util.ULocale);
-    ctor public SimpleDateFormat(java.lang.String, java.lang.String, android.icu.util.ULocale);
-    ctor public SimpleDateFormat(java.lang.String, android.icu.text.DateFormatSymbols);
-    method public void applyLocalizedPattern(java.lang.String);
-    method public void applyPattern(java.lang.String);
-    method public java.lang.StringBuffer format(android.icu.util.Calendar, java.lang.StringBuffer, java.text.FieldPosition);
+    ctor public SimpleDateFormat(String);
+    ctor public SimpleDateFormat(String, java.util.Locale);
+    ctor public SimpleDateFormat(String, android.icu.util.ULocale);
+    ctor public SimpleDateFormat(String, String, android.icu.util.ULocale);
+    ctor public SimpleDateFormat(String, android.icu.text.DateFormatSymbols);
+    method public void applyLocalizedPattern(String);
+    method public void applyPattern(String);
+    method public StringBuffer format(android.icu.util.Calendar, StringBuffer, java.text.FieldPosition);
     method public java.util.Date get2DigitYearStart();
     method public android.icu.text.DateFormatSymbols getDateFormatSymbols();
     method public android.icu.text.NumberFormat getNumberFormat(char);
     method protected android.icu.text.DateFormatSymbols getSymbols();
     method public android.icu.text.TimeZoneFormat getTimeZoneFormat();
-    method protected int matchQuarterString(java.lang.String, int, int, java.lang.String[], android.icu.util.Calendar);
-    method protected int matchString(java.lang.String, int, int, java.lang.String[], android.icu.util.Calendar);
-    method public void parse(java.lang.String, android.icu.util.Calendar, java.text.ParsePosition);
+    method protected int matchQuarterString(String, int, int, String[], android.icu.util.Calendar);
+    method protected int matchString(String, int, int, String[], android.icu.util.Calendar);
+    method public void parse(String, android.icu.util.Calendar, java.text.ParsePosition);
     method protected android.icu.text.DateFormat.Field patternCharToDateFormatField(char);
     method public void set2DigitYearStart(java.util.Date);
     method public void setDateFormatSymbols(android.icu.text.DateFormatSymbols);
-    method public void setNumberFormat(java.lang.String, android.icu.text.NumberFormat);
+    method public void setNumberFormat(String, android.icu.text.NumberFormat);
     method public void setTimeZoneFormat(android.icu.text.TimeZoneFormat);
-    method protected java.lang.String subFormat(char, int, int, java.text.FieldPosition, android.icu.text.DateFormatSymbols, android.icu.util.Calendar) throws java.lang.IllegalArgumentException;
-    method protected int subParse(java.lang.String, int, char, int, boolean, boolean, boolean[], android.icu.util.Calendar);
-    method public java.lang.String toLocalizedPattern();
-    method public java.lang.String toPattern();
-    method protected java.lang.String zeroPaddingNumber(long, int, int);
+    method protected String subFormat(char, int, int, java.text.FieldPosition, android.icu.text.DateFormatSymbols, android.icu.util.Calendar) throws java.lang.IllegalArgumentException;
+    method protected int subParse(String, int, char, int, boolean, boolean, boolean[], android.icu.util.Calendar);
+    method public String toLocalizedPattern();
+    method public String toPattern();
+    method protected String zeroPaddingNumber(long, int, int);
   }
 
   public class StringPrepParseException extends java.text.ParseException {
-    ctor public StringPrepParseException(java.lang.String, int);
-    ctor public StringPrepParseException(java.lang.String, int, java.lang.String, int);
-    ctor public StringPrepParseException(java.lang.String, int, java.lang.String, int, int);
+    ctor public StringPrepParseException(String, int);
+    ctor public StringPrepParseException(String, int, String, int);
+    ctor public StringPrepParseException(String, int, String, int, int);
     method public int getError();
     field public static final int ACE_PREFIX_ERROR = 6; // 0x6
     field public static final int BUFFER_OVERFLOW_ERROR = 9; // 0x9
@@ -20837,68 +20789,66 @@
   }
 
   public final class StringSearch extends android.icu.text.SearchIterator {
-    ctor public StringSearch(java.lang.String, java.text.CharacterIterator, android.icu.text.RuleBasedCollator, android.icu.text.BreakIterator);
-    ctor public StringSearch(java.lang.String, java.text.CharacterIterator, android.icu.text.RuleBasedCollator);
-    ctor public StringSearch(java.lang.String, java.text.CharacterIterator, java.util.Locale);
-    ctor public StringSearch(java.lang.String, java.text.CharacterIterator, android.icu.util.ULocale);
-    ctor public StringSearch(java.lang.String, java.lang.String);
+    ctor public StringSearch(String, java.text.CharacterIterator, android.icu.text.RuleBasedCollator, android.icu.text.BreakIterator);
+    ctor public StringSearch(String, java.text.CharacterIterator, android.icu.text.RuleBasedCollator);
+    ctor public StringSearch(String, java.text.CharacterIterator, java.util.Locale);
+    ctor public StringSearch(String, java.text.CharacterIterator, android.icu.util.ULocale);
+    ctor public StringSearch(String, String);
     method public android.icu.text.RuleBasedCollator getCollator();
     method public int getIndex();
-    method public java.lang.String getPattern();
+    method public String getPattern();
     method protected int handleNext(int);
     method protected int handlePrevious(int);
     method public boolean isCanonical();
     method public void setCanonical(boolean);
     method public void setCollator(android.icu.text.RuleBasedCollator);
-    method public void setPattern(java.lang.String);
+    method public void setPattern(String);
   }
 
-  public abstract interface SymbolTable {
-    method public abstract char[] lookup(java.lang.String);
-    method public abstract android.icu.text.UnicodeMatcher lookupMatcher(int);
-    method public abstract java.lang.String parseReference(java.lang.String, java.text.ParsePosition, int);
+  public interface SymbolTable {
+    method public char[] lookup(String);
+    method public android.icu.text.UnicodeMatcher lookupMatcher(int);
+    method public String parseReference(String, java.text.ParsePosition, int);
     field public static final char SYMBOL_REF = 36; // 0x0024 '$'
   }
 
-  public class TimeZoneFormat extends android.icu.text.UFormat implements android.icu.util.Freezable java.io.Serializable {
+  public class TimeZoneFormat extends android.icu.text.UFormat implements android.icu.util.Freezable<android.icu.text.TimeZoneFormat> java.io.Serializable {
     ctor protected TimeZoneFormat(android.icu.util.ULocale);
     method public android.icu.text.TimeZoneFormat cloneAsThawed();
-    method public final java.lang.String format(android.icu.text.TimeZoneFormat.Style, android.icu.util.TimeZone, long);
-    method public java.lang.String format(android.icu.text.TimeZoneFormat.Style, android.icu.util.TimeZone, long, android.icu.util.Output<android.icu.text.TimeZoneFormat.TimeType>);
-    method public java.lang.StringBuffer format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition);
-    method public final java.lang.String formatOffsetISO8601Basic(int, boolean, boolean, boolean);
-    method public final java.lang.String formatOffsetISO8601Extended(int, boolean, boolean, boolean);
-    method public java.lang.String formatOffsetLocalizedGMT(int);
-    method public java.lang.String formatOffsetShortLocalizedGMT(int);
+    method public final String format(android.icu.text.TimeZoneFormat.Style, android.icu.util.TimeZone, long);
+    method public String format(android.icu.text.TimeZoneFormat.Style, android.icu.util.TimeZone, long, android.icu.util.Output<android.icu.text.TimeZoneFormat.TimeType>);
+    method public StringBuffer format(Object, StringBuffer, java.text.FieldPosition);
+    method public final String formatOffsetISO8601Basic(int, boolean, boolean, boolean);
+    method public final String formatOffsetISO8601Extended(int, boolean, boolean, boolean);
+    method public String formatOffsetLocalizedGMT(int);
+    method public String formatOffsetShortLocalizedGMT(int);
     method public android.icu.text.TimeZoneFormat freeze();
     method public java.util.EnumSet<android.icu.text.TimeZoneFormat.ParseOption> getDefaultParseOptions();
-    method public java.lang.String getGMTOffsetDigits();
-    method public java.lang.String getGMTOffsetPattern(android.icu.text.TimeZoneFormat.GMTOffsetPatternType);
-    method public java.lang.String getGMTPattern();
-    method public java.lang.String getGMTZeroFormat();
+    method public String getGMTOffsetDigits();
+    method public String getGMTOffsetPattern(android.icu.text.TimeZoneFormat.GMTOffsetPatternType);
+    method public String getGMTPattern();
+    method public String getGMTZeroFormat();
     method public static android.icu.text.TimeZoneFormat getInstance(android.icu.util.ULocale);
     method public static android.icu.text.TimeZoneFormat getInstance(java.util.Locale);
     method public android.icu.text.TimeZoneNames getTimeZoneNames();
     method public boolean isFrozen();
-    method public android.icu.util.TimeZone parse(android.icu.text.TimeZoneFormat.Style, java.lang.String, java.text.ParsePosition, java.util.EnumSet<android.icu.text.TimeZoneFormat.ParseOption>, android.icu.util.Output<android.icu.text.TimeZoneFormat.TimeType>);
-    method public android.icu.util.TimeZone parse(android.icu.text.TimeZoneFormat.Style, java.lang.String, java.text.ParsePosition, android.icu.util.Output<android.icu.text.TimeZoneFormat.TimeType>);
-    method public final android.icu.util.TimeZone parse(java.lang.String, java.text.ParsePosition);
-    method public final android.icu.util.TimeZone parse(java.lang.String) throws java.text.ParseException;
-    method public java.lang.Object parseObject(java.lang.String, java.text.ParsePosition);
-    method public final int parseOffsetISO8601(java.lang.String, java.text.ParsePosition);
-    method public int parseOffsetLocalizedGMT(java.lang.String, java.text.ParsePosition);
-    method public int parseOffsetShortLocalizedGMT(java.lang.String, java.text.ParsePosition);
+    method public android.icu.util.TimeZone parse(android.icu.text.TimeZoneFormat.Style, String, java.text.ParsePosition, java.util.EnumSet<android.icu.text.TimeZoneFormat.ParseOption>, android.icu.util.Output<android.icu.text.TimeZoneFormat.TimeType>);
+    method public android.icu.util.TimeZone parse(android.icu.text.TimeZoneFormat.Style, String, java.text.ParsePosition, android.icu.util.Output<android.icu.text.TimeZoneFormat.TimeType>);
+    method public final android.icu.util.TimeZone parse(String, java.text.ParsePosition);
+    method public final android.icu.util.TimeZone parse(String) throws java.text.ParseException;
+    method public Object parseObject(String, java.text.ParsePosition);
+    method public final int parseOffsetISO8601(String, java.text.ParsePosition);
+    method public int parseOffsetLocalizedGMT(String, java.text.ParsePosition);
+    method public int parseOffsetShortLocalizedGMT(String, java.text.ParsePosition);
     method public android.icu.text.TimeZoneFormat setDefaultParseOptions(java.util.EnumSet<android.icu.text.TimeZoneFormat.ParseOption>);
-    method public android.icu.text.TimeZoneFormat setGMTOffsetDigits(java.lang.String);
-    method public android.icu.text.TimeZoneFormat setGMTOffsetPattern(android.icu.text.TimeZoneFormat.GMTOffsetPatternType, java.lang.String);
-    method public android.icu.text.TimeZoneFormat setGMTPattern(java.lang.String);
-    method public android.icu.text.TimeZoneFormat setGMTZeroFormat(java.lang.String);
+    method public android.icu.text.TimeZoneFormat setGMTOffsetDigits(String);
+    method public android.icu.text.TimeZoneFormat setGMTOffsetPattern(android.icu.text.TimeZoneFormat.GMTOffsetPatternType, String);
+    method public android.icu.text.TimeZoneFormat setGMTPattern(String);
+    method public android.icu.text.TimeZoneFormat setGMTZeroFormat(String);
     method public android.icu.text.TimeZoneFormat setTimeZoneNames(android.icu.text.TimeZoneNames);
   }
 
-  public static final class TimeZoneFormat.GMTOffsetPatternType extends java.lang.Enum {
-    method public static android.icu.text.TimeZoneFormat.GMTOffsetPatternType valueOf(java.lang.String);
-    method public static final android.icu.text.TimeZoneFormat.GMTOffsetPatternType[] values();
+  public enum TimeZoneFormat.GMTOffsetPatternType {
     enum_constant public static final android.icu.text.TimeZoneFormat.GMTOffsetPatternType NEGATIVE_H;
     enum_constant public static final android.icu.text.TimeZoneFormat.GMTOffsetPatternType NEGATIVE_HM;
     enum_constant public static final android.icu.text.TimeZoneFormat.GMTOffsetPatternType NEGATIVE_HMS;
@@ -20907,16 +20857,12 @@
     enum_constant public static final android.icu.text.TimeZoneFormat.GMTOffsetPatternType POSITIVE_HMS;
   }
 
-  public static final class TimeZoneFormat.ParseOption extends java.lang.Enum {
-    method public static android.icu.text.TimeZoneFormat.ParseOption valueOf(java.lang.String);
-    method public static final android.icu.text.TimeZoneFormat.ParseOption[] values();
+  public enum TimeZoneFormat.ParseOption {
     enum_constant public static final android.icu.text.TimeZoneFormat.ParseOption ALL_STYLES;
     enum_constant public static final android.icu.text.TimeZoneFormat.ParseOption TZ_DATABASE_ABBREVIATIONS;
   }
 
-  public static final class TimeZoneFormat.Style extends java.lang.Enum {
-    method public static android.icu.text.TimeZoneFormat.Style valueOf(java.lang.String);
-    method public static final android.icu.text.TimeZoneFormat.Style[] values();
+  public enum TimeZoneFormat.Style {
     enum_constant public static final android.icu.text.TimeZoneFormat.Style EXEMPLAR_LOCATION;
     enum_constant public static final android.icu.text.TimeZoneFormat.Style GENERIC_LOCATION;
     enum_constant public static final android.icu.text.TimeZoneFormat.Style GENERIC_LONG;
@@ -20939,9 +20885,7 @@
     enum_constant public static final android.icu.text.TimeZoneFormat.Style ZONE_ID_SHORT;
   }
 
-  public static final class TimeZoneFormat.TimeType extends java.lang.Enum {
-    method public static android.icu.text.TimeZoneFormat.TimeType valueOf(java.lang.String);
-    method public static final android.icu.text.TimeZoneFormat.TimeType[] values();
+  public enum TimeZoneFormat.TimeType {
     enum_constant public static final android.icu.text.TimeZoneFormat.TimeType DAYLIGHT;
     enum_constant public static final android.icu.text.TimeZoneFormat.TimeType STANDARD;
     enum_constant public static final android.icu.text.TimeZoneFormat.TimeType UNKNOWN;
@@ -20949,21 +20893,19 @@
 
   public abstract class TimeZoneNames implements java.io.Serializable {
     method public abstract java.util.Set<java.lang.String> getAvailableMetaZoneIDs();
-    method public abstract java.util.Set<java.lang.String> getAvailableMetaZoneIDs(java.lang.String);
-    method public final java.lang.String getDisplayName(java.lang.String, android.icu.text.TimeZoneNames.NameType, long);
-    method public java.lang.String getExemplarLocationName(java.lang.String);
+    method public abstract java.util.Set<java.lang.String> getAvailableMetaZoneIDs(String);
+    method public final String getDisplayName(String, android.icu.text.TimeZoneNames.NameType, long);
+    method public String getExemplarLocationName(String);
     method public static android.icu.text.TimeZoneNames getInstance(android.icu.util.ULocale);
     method public static android.icu.text.TimeZoneNames getInstance(java.util.Locale);
-    method public abstract java.lang.String getMetaZoneDisplayName(java.lang.String, android.icu.text.TimeZoneNames.NameType);
-    method public abstract java.lang.String getMetaZoneID(java.lang.String, long);
-    method public abstract java.lang.String getReferenceZoneID(java.lang.String, java.lang.String);
+    method public abstract String getMetaZoneDisplayName(String, android.icu.text.TimeZoneNames.NameType);
+    method public abstract String getMetaZoneID(String, long);
+    method public abstract String getReferenceZoneID(String, String);
     method public static android.icu.text.TimeZoneNames getTZDBInstance(android.icu.util.ULocale);
-    method public abstract java.lang.String getTimeZoneDisplayName(java.lang.String, android.icu.text.TimeZoneNames.NameType);
+    method public abstract String getTimeZoneDisplayName(String, android.icu.text.TimeZoneNames.NameType);
   }
 
-  public static final class TimeZoneNames.NameType extends java.lang.Enum {
-    method public static android.icu.text.TimeZoneNames.NameType valueOf(java.lang.String);
-    method public static final android.icu.text.TimeZoneNames.NameType[] values();
+  public enum TimeZoneNames.NameType {
     enum_constant public static final android.icu.text.TimeZoneNames.NameType EXEMPLAR_LOCATION;
     enum_constant public static final android.icu.text.TimeZoneNames.NameType LONG_DAYLIGHT;
     enum_constant public static final android.icu.text.TimeZoneNames.NameType LONG_GENERIC;
@@ -20974,31 +20916,31 @@
   }
 
   public abstract class Transliterator {
-    method public static final android.icu.text.Transliterator createFromRules(java.lang.String, java.lang.String, int);
+    method public static final android.icu.text.Transliterator createFromRules(String, String, int);
     method public void filteredTransliterate(android.icu.text.Replaceable, android.icu.text.Transliterator.Position, boolean);
     method public final void finishTransliteration(android.icu.text.Replaceable, android.icu.text.Transliterator.Position);
     method public static final java.util.Enumeration<java.lang.String> getAvailableIDs();
     method public static final java.util.Enumeration<java.lang.String> getAvailableSources();
-    method public static final java.util.Enumeration<java.lang.String> getAvailableTargets(java.lang.String);
-    method public static final java.util.Enumeration<java.lang.String> getAvailableVariants(java.lang.String, java.lang.String);
-    method public static final java.lang.String getDisplayName(java.lang.String);
-    method public static java.lang.String getDisplayName(java.lang.String, java.util.Locale);
-    method public static java.lang.String getDisplayName(java.lang.String, android.icu.util.ULocale);
+    method public static final java.util.Enumeration<java.lang.String> getAvailableTargets(String);
+    method public static final java.util.Enumeration<java.lang.String> getAvailableVariants(String, String);
+    method public static final String getDisplayName(String);
+    method public static String getDisplayName(String, java.util.Locale);
+    method public static String getDisplayName(String, android.icu.util.ULocale);
     method public android.icu.text.Transliterator[] getElements();
     method public final android.icu.text.UnicodeFilter getFilter();
-    method public final java.lang.String getID();
-    method public static final android.icu.text.Transliterator getInstance(java.lang.String);
-    method public static android.icu.text.Transliterator getInstance(java.lang.String, int);
+    method public final String getID();
+    method public static final android.icu.text.Transliterator getInstance(String);
+    method public static android.icu.text.Transliterator getInstance(String, int);
     method public final android.icu.text.Transliterator getInverse();
     method public final int getMaximumContextLength();
     method public final android.icu.text.UnicodeSet getSourceSet();
     method public android.icu.text.UnicodeSet getTargetSet();
     method public void setFilter(android.icu.text.UnicodeFilter);
-    method public java.lang.String toRules(boolean);
+    method public String toRules(boolean);
     method public final int transliterate(android.icu.text.Replaceable, int, int);
     method public final void transliterate(android.icu.text.Replaceable);
-    method public final java.lang.String transliterate(java.lang.String);
-    method public final void transliterate(android.icu.text.Replaceable, android.icu.text.Transliterator.Position, java.lang.String);
+    method public final String transliterate(String);
+    method public final void transliterate(android.icu.text.Replaceable, android.icu.text.Transliterator.Position, String);
     method public final void transliterate(android.icu.text.Replaceable, android.icu.text.Transliterator.Position, int);
     method public final void transliterate(android.icu.text.Replaceable, android.icu.text.Transliterator.Position);
     field public static final int FORWARD = 0; // 0x0
@@ -21020,21 +20962,21 @@
 
   public abstract class UCharacterIterator implements java.lang.Cloneable {
     ctor protected UCharacterIterator();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
+    method public Object clone() throws java.lang.CloneNotSupportedException;
     method public abstract int current();
     method public int currentCodePoint();
     method public java.text.CharacterIterator getCharacterIterator();
     method public abstract int getIndex();
     method public static final android.icu.text.UCharacterIterator getInstance(android.icu.text.Replaceable);
-    method public static final android.icu.text.UCharacterIterator getInstance(java.lang.String);
+    method public static final android.icu.text.UCharacterIterator getInstance(String);
     method public static final android.icu.text.UCharacterIterator getInstance(char[]);
     method public static final android.icu.text.UCharacterIterator getInstance(char[], int, int);
-    method public static final android.icu.text.UCharacterIterator getInstance(java.lang.StringBuffer);
+    method public static final android.icu.text.UCharacterIterator getInstance(StringBuffer);
     method public static final android.icu.text.UCharacterIterator getInstance(java.text.CharacterIterator);
     method public abstract int getLength();
     method public abstract int getText(char[], int);
     method public final int getText(char[]);
-    method public java.lang.String getText();
+    method public String getText();
     method public int moveCodePointIndex(int);
     method public int moveIndex(int);
     method public abstract int next();
@@ -21056,78 +20998,78 @@
     method public int matches(android.icu.text.Replaceable, int[], int, boolean);
   }
 
-  public abstract interface UnicodeMatcher {
-    method public abstract void addMatchSetTo(android.icu.text.UnicodeSet);
-    method public abstract int matches(android.icu.text.Replaceable, int[], int, boolean);
-    method public abstract boolean matchesIndexValue(int);
-    method public abstract java.lang.String toPattern(boolean);
+  public interface UnicodeMatcher {
+    method public void addMatchSetTo(android.icu.text.UnicodeSet);
+    method public int matches(android.icu.text.Replaceable, int[], int, boolean);
+    method public boolean matchesIndexValue(int);
+    method public String toPattern(boolean);
     field public static final char ETHER = 65535; // 0xffff '\uffff'
     field public static final int U_MATCH = 2; // 0x2
     field public static final int U_MISMATCH = 0; // 0x0
     field public static final int U_PARTIAL_MATCH = 1; // 0x1
   }
 
-  public class UnicodeSet extends android.icu.text.UnicodeFilter implements java.lang.Comparable android.icu.util.Freezable java.lang.Iterable {
+  public class UnicodeSet extends android.icu.text.UnicodeFilter implements java.lang.Comparable<android.icu.text.UnicodeSet> android.icu.util.Freezable<android.icu.text.UnicodeSet> java.lang.Iterable<java.lang.String> {
     ctor public UnicodeSet();
     ctor public UnicodeSet(android.icu.text.UnicodeSet);
     ctor public UnicodeSet(int, int);
     ctor public UnicodeSet(int...);
-    ctor public UnicodeSet(java.lang.String);
-    ctor public UnicodeSet(java.lang.String, boolean);
-    ctor public UnicodeSet(java.lang.String, int);
-    ctor public UnicodeSet(java.lang.String, java.text.ParsePosition, android.icu.text.SymbolTable);
-    ctor public UnicodeSet(java.lang.String, java.text.ParsePosition, android.icu.text.SymbolTable, int);
-    method public java.lang.StringBuffer _generatePattern(java.lang.StringBuffer, boolean);
-    method public java.lang.StringBuffer _generatePattern(java.lang.StringBuffer, boolean, boolean);
+    ctor public UnicodeSet(String);
+    ctor public UnicodeSet(String, boolean);
+    ctor public UnicodeSet(String, int);
+    ctor public UnicodeSet(String, java.text.ParsePosition, android.icu.text.SymbolTable);
+    ctor public UnicodeSet(String, java.text.ParsePosition, android.icu.text.SymbolTable, int);
+    method public StringBuffer _generatePattern(StringBuffer, boolean);
+    method public StringBuffer _generatePattern(StringBuffer, boolean, boolean);
     method public android.icu.text.UnicodeSet add(int, int);
     method public final android.icu.text.UnicodeSet add(int);
-    method public final android.icu.text.UnicodeSet add(java.lang.CharSequence);
-    method public android.icu.text.UnicodeSet add(java.lang.Iterable<?>);
+    method public final android.icu.text.UnicodeSet add(CharSequence);
+    method public android.icu.text.UnicodeSet add(Iterable<?>);
     method public android.icu.text.UnicodeSet addAll(int, int);
-    method public final android.icu.text.UnicodeSet addAll(java.lang.CharSequence);
+    method public final android.icu.text.UnicodeSet addAll(CharSequence);
     method public android.icu.text.UnicodeSet addAll(android.icu.text.UnicodeSet);
-    method public android.icu.text.UnicodeSet addAll(java.lang.Iterable<?>);
+    method public android.icu.text.UnicodeSet addAll(Iterable<?>);
     method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet addAll(T...);
     method public <T extends java.util.Collection<java.lang.String>> T addAllTo(T);
     method public void addMatchSetTo(android.icu.text.UnicodeSet);
     method public android.icu.text.UnicodeSet applyIntPropertyValue(int, int);
-    method public final android.icu.text.UnicodeSet applyPattern(java.lang.String);
-    method public android.icu.text.UnicodeSet applyPattern(java.lang.String, boolean);
-    method public android.icu.text.UnicodeSet applyPattern(java.lang.String, int);
-    method public android.icu.text.UnicodeSet applyPropertyAlias(java.lang.String, java.lang.String);
-    method public android.icu.text.UnicodeSet applyPropertyAlias(java.lang.String, java.lang.String, android.icu.text.SymbolTable);
+    method public final android.icu.text.UnicodeSet applyPattern(String);
+    method public android.icu.text.UnicodeSet applyPattern(String, boolean);
+    method public android.icu.text.UnicodeSet applyPattern(String, int);
+    method public android.icu.text.UnicodeSet applyPropertyAlias(String, String);
+    method public android.icu.text.UnicodeSet applyPropertyAlias(String, String, android.icu.text.SymbolTable);
     method public int charAt(int);
     method public android.icu.text.UnicodeSet clear();
-    method public java.lang.Object clone();
+    method public Object clone();
     method public android.icu.text.UnicodeSet cloneAsThawed();
     method public android.icu.text.UnicodeSet closeOver(int);
     method public android.icu.text.UnicodeSet compact();
     method public int compareTo(android.icu.text.UnicodeSet);
     method public int compareTo(android.icu.text.UnicodeSet, android.icu.text.UnicodeSet.ComparisonStyle);
-    method public int compareTo(java.lang.Iterable<java.lang.String>);
+    method public int compareTo(Iterable<java.lang.String>);
     method public android.icu.text.UnicodeSet complement(int, int);
     method public final android.icu.text.UnicodeSet complement(int);
     method public android.icu.text.UnicodeSet complement();
-    method public final android.icu.text.UnicodeSet complement(java.lang.CharSequence);
-    method public final android.icu.text.UnicodeSet complementAll(java.lang.CharSequence);
+    method public final android.icu.text.UnicodeSet complement(CharSequence);
+    method public final android.icu.text.UnicodeSet complementAll(CharSequence);
     method public android.icu.text.UnicodeSet complementAll(android.icu.text.UnicodeSet);
     method public boolean contains(int);
     method public boolean contains(int, int);
-    method public final boolean contains(java.lang.CharSequence);
+    method public final boolean contains(CharSequence);
     method public boolean containsAll(android.icu.text.UnicodeSet);
-    method public boolean containsAll(java.lang.String);
-    method public <T extends java.lang.CharSequence> boolean containsAll(java.lang.Iterable<T>);
+    method public boolean containsAll(String);
+    method public <T extends java.lang.CharSequence> boolean containsAll(Iterable<T>);
     method public boolean containsNone(int, int);
     method public boolean containsNone(android.icu.text.UnicodeSet);
-    method public boolean containsNone(java.lang.CharSequence);
-    method public <T extends java.lang.CharSequence> boolean containsNone(java.lang.Iterable<T>);
+    method public boolean containsNone(CharSequence);
+    method public <T extends java.lang.CharSequence> boolean containsNone(Iterable<T>);
     method public final boolean containsSome(int, int);
     method public final boolean containsSome(android.icu.text.UnicodeSet);
-    method public final boolean containsSome(java.lang.CharSequence);
-    method public final <T extends java.lang.CharSequence> boolean containsSome(java.lang.Iterable<T>);
+    method public final boolean containsSome(CharSequence);
+    method public final <T extends java.lang.CharSequence> boolean containsSome(Iterable<T>);
     method public android.icu.text.UnicodeSet freeze();
-    method public static android.icu.text.UnicodeSet from(java.lang.CharSequence);
-    method public static android.icu.text.UnicodeSet fromAll(java.lang.CharSequence);
+    method public static android.icu.text.UnicodeSet from(CharSequence);
+    method public static android.icu.text.UnicodeSet fromAll(CharSequence);
     method public int getRangeCount();
     method public int getRangeEnd(int);
     method public int getRangeStart(int);
@@ -21136,29 +21078,29 @@
     method public boolean isFrozen();
     method public java.util.Iterator<java.lang.String> iterator();
     method public boolean matchesIndexValue(int);
-    method public java.lang.Iterable<android.icu.text.UnicodeSet.EntryRange> ranges();
+    method public Iterable<android.icu.text.UnicodeSet.EntryRange> ranges();
     method public android.icu.text.UnicodeSet remove(int, int);
     method public final android.icu.text.UnicodeSet remove(int);
-    method public final android.icu.text.UnicodeSet remove(java.lang.CharSequence);
-    method public final android.icu.text.UnicodeSet removeAll(java.lang.CharSequence);
+    method public final android.icu.text.UnicodeSet remove(CharSequence);
+    method public final android.icu.text.UnicodeSet removeAll(CharSequence);
     method public android.icu.text.UnicodeSet removeAll(android.icu.text.UnicodeSet);
-    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet removeAll(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet removeAll(Iterable<T>);
     method public final android.icu.text.UnicodeSet removeAllStrings();
     method public android.icu.text.UnicodeSet retain(int, int);
     method public final android.icu.text.UnicodeSet retain(int);
-    method public final android.icu.text.UnicodeSet retain(java.lang.CharSequence);
-    method public final android.icu.text.UnicodeSet retainAll(java.lang.CharSequence);
+    method public final android.icu.text.UnicodeSet retain(CharSequence);
+    method public final android.icu.text.UnicodeSet retainAll(CharSequence);
     method public android.icu.text.UnicodeSet retainAll(android.icu.text.UnicodeSet);
-    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet retainAll(java.lang.Iterable<T>);
+    method public <T extends java.lang.CharSequence> android.icu.text.UnicodeSet retainAll(Iterable<T>);
     method public android.icu.text.UnicodeSet set(int, int);
     method public android.icu.text.UnicodeSet set(android.icu.text.UnicodeSet);
     method public int size();
-    method public int span(java.lang.CharSequence, android.icu.text.UnicodeSet.SpanCondition);
-    method public int span(java.lang.CharSequence, int, android.icu.text.UnicodeSet.SpanCondition);
-    method public int spanBack(java.lang.CharSequence, android.icu.text.UnicodeSet.SpanCondition);
-    method public int spanBack(java.lang.CharSequence, int, android.icu.text.UnicodeSet.SpanCondition);
+    method public int span(CharSequence, android.icu.text.UnicodeSet.SpanCondition);
+    method public int span(CharSequence, int, android.icu.text.UnicodeSet.SpanCondition);
+    method public int spanBack(CharSequence, android.icu.text.UnicodeSet.SpanCondition);
+    method public int spanBack(CharSequence, int, android.icu.text.UnicodeSet.SpanCondition);
     method public java.util.Collection<java.lang.String> strings();
-    method public java.lang.String toPattern(boolean);
+    method public String toPattern(boolean);
     field public static final int ADD_CASE_MAPPINGS = 4; // 0x4
     field public static final android.icu.text.UnicodeSet ALL_CODE_POINTS;
     field public static final int CASE = 2; // 0x2
@@ -21169,9 +21111,7 @@
     field public static final int MIN_VALUE = 0; // 0x0
   }
 
-  public static final class UnicodeSet.ComparisonStyle extends java.lang.Enum {
-    method public static android.icu.text.UnicodeSet.ComparisonStyle valueOf(java.lang.String);
-    method public static final android.icu.text.UnicodeSet.ComparisonStyle[] values();
+  public enum UnicodeSet.ComparisonStyle {
     enum_constant public static final android.icu.text.UnicodeSet.ComparisonStyle LEXICOGRAPHIC;
     enum_constant public static final android.icu.text.UnicodeSet.ComparisonStyle LONGER_FIRST;
     enum_constant public static final android.icu.text.UnicodeSet.ComparisonStyle SHORTER_FIRST;
@@ -21182,9 +21122,7 @@
     field public int codepointEnd;
   }
 
-  public static final class UnicodeSet.SpanCondition extends java.lang.Enum {
-    method public static android.icu.text.UnicodeSet.SpanCondition valueOf(java.lang.String);
-    method public static final android.icu.text.UnicodeSet.SpanCondition[] values();
+  public enum UnicodeSet.SpanCondition {
     enum_constant public static final android.icu.text.UnicodeSet.SpanCondition CONDITION_COUNT;
     enum_constant public static final android.icu.text.UnicodeSet.SpanCondition CONTAINED;
     enum_constant public static final android.icu.text.UnicodeSet.SpanCondition NOT_CONTAINED;
@@ -21194,7 +21132,7 @@
   public class UnicodeSetIterator {
     ctor public UnicodeSetIterator(android.icu.text.UnicodeSet);
     ctor public UnicodeSetIterator();
-    method public java.lang.String getString();
+    method public String getString();
     method public boolean next();
     method public boolean nextRange();
     method public void reset(android.icu.text.UnicodeSet);
@@ -21202,35 +21140,31 @@
     field public static int IS_STRING;
     field public int codepoint;
     field public int codepointEnd;
-    field public java.lang.String string;
+    field public String string;
   }
 
   public class UnicodeSetSpanner {
     ctor public UnicodeSetSpanner(android.icu.text.UnicodeSet);
-    method public int countIn(java.lang.CharSequence);
-    method public int countIn(java.lang.CharSequence, android.icu.text.UnicodeSetSpanner.CountMethod);
-    method public int countIn(java.lang.CharSequence, android.icu.text.UnicodeSetSpanner.CountMethod, android.icu.text.UnicodeSet.SpanCondition);
-    method public java.lang.String deleteFrom(java.lang.CharSequence);
-    method public java.lang.String deleteFrom(java.lang.CharSequence, android.icu.text.UnicodeSet.SpanCondition);
+    method public int countIn(CharSequence);
+    method public int countIn(CharSequence, android.icu.text.UnicodeSetSpanner.CountMethod);
+    method public int countIn(CharSequence, android.icu.text.UnicodeSetSpanner.CountMethod, android.icu.text.UnicodeSet.SpanCondition);
+    method public String deleteFrom(CharSequence);
+    method public String deleteFrom(CharSequence, android.icu.text.UnicodeSet.SpanCondition);
     method public android.icu.text.UnicodeSet getUnicodeSet();
-    method public java.lang.String replaceFrom(java.lang.CharSequence, java.lang.CharSequence);
-    method public java.lang.String replaceFrom(java.lang.CharSequence, java.lang.CharSequence, android.icu.text.UnicodeSetSpanner.CountMethod);
-    method public java.lang.String replaceFrom(java.lang.CharSequence, java.lang.CharSequence, android.icu.text.UnicodeSetSpanner.CountMethod, android.icu.text.UnicodeSet.SpanCondition);
-    method public java.lang.CharSequence trim(java.lang.CharSequence);
-    method public java.lang.CharSequence trim(java.lang.CharSequence, android.icu.text.UnicodeSetSpanner.TrimOption);
-    method public java.lang.CharSequence trim(java.lang.CharSequence, android.icu.text.UnicodeSetSpanner.TrimOption, android.icu.text.UnicodeSet.SpanCondition);
+    method public String replaceFrom(CharSequence, CharSequence);
+    method public String replaceFrom(CharSequence, CharSequence, android.icu.text.UnicodeSetSpanner.CountMethod);
+    method public String replaceFrom(CharSequence, CharSequence, android.icu.text.UnicodeSetSpanner.CountMethod, android.icu.text.UnicodeSet.SpanCondition);
+    method public CharSequence trim(CharSequence);
+    method public CharSequence trim(CharSequence, android.icu.text.UnicodeSetSpanner.TrimOption);
+    method public CharSequence trim(CharSequence, android.icu.text.UnicodeSetSpanner.TrimOption, android.icu.text.UnicodeSet.SpanCondition);
   }
 
-  public static final class UnicodeSetSpanner.CountMethod extends java.lang.Enum {
-    method public static android.icu.text.UnicodeSetSpanner.CountMethod valueOf(java.lang.String);
-    method public static final android.icu.text.UnicodeSetSpanner.CountMethod[] values();
+  public enum UnicodeSetSpanner.CountMethod {
     enum_constant public static final android.icu.text.UnicodeSetSpanner.CountMethod MIN_ELEMENTS;
     enum_constant public static final android.icu.text.UnicodeSetSpanner.CountMethod WHOLE_SPAN;
   }
 
-  public static final class UnicodeSetSpanner.TrimOption extends java.lang.Enum {
-    method public static android.icu.text.UnicodeSetSpanner.TrimOption valueOf(java.lang.String);
-    method public static final android.icu.text.UnicodeSetSpanner.TrimOption[] values();
+  public enum UnicodeSetSpanner.TrimOption {
     enum_constant public static final android.icu.text.UnicodeSetSpanner.TrimOption BOTH;
     enum_constant public static final android.icu.text.UnicodeSetSpanner.TrimOption LEADING;
     enum_constant public static final android.icu.text.UnicodeSetSpanner.TrimOption TRAILING;
@@ -21253,27 +21187,27 @@
     field public static final int BE = 0; // 0x0
   }
 
-  public abstract class Calendar implements java.lang.Cloneable java.lang.Comparable java.io.Serializable {
+  public abstract class Calendar implements java.lang.Cloneable java.lang.Comparable<android.icu.util.Calendar> java.io.Serializable {
     ctor protected Calendar();
     ctor protected Calendar(android.icu.util.TimeZone, java.util.Locale);
     ctor protected Calendar(android.icu.util.TimeZone, android.icu.util.ULocale);
     method public void add(int, int);
-    method public boolean after(java.lang.Object);
-    method public boolean before(java.lang.Object);
+    method public boolean after(Object);
+    method public boolean before(Object);
     method public final void clear();
     method public final void clear(int);
-    method public java.lang.Object clone();
+    method public Object clone();
     method public int compareTo(android.icu.util.Calendar);
     method protected void complete();
     method protected void computeFields();
     method protected final void computeGregorianFields(int);
     method protected int computeGregorianMonthStart(int, int);
     method protected int computeJulianDay();
-    method protected deprecated int computeMillisInDay();
+    method @Deprecated protected int computeMillisInDay();
     method protected void computeTime();
-    method protected deprecated int computeZoneOffset(long, int);
+    method @Deprecated protected int computeZoneOffset(long, int);
     method public int fieldDifference(java.util.Date, int);
-    method protected java.lang.String fieldName(int);
+    method protected String fieldName(int);
     method protected static final long floorDivide(long, long);
     method protected static final int floorDivide(int, int);
     method protected static final int floorDivide(int, int, int[]);
@@ -21284,8 +21218,8 @@
     method public static java.util.Locale[] getAvailableLocales();
     method public android.icu.text.DateFormat getDateTimeFormat(int, int, java.util.Locale);
     method public android.icu.text.DateFormat getDateTimeFormat(int, int, android.icu.util.ULocale);
-    method public java.lang.String getDisplayName(java.util.Locale);
-    method public java.lang.String getDisplayName(android.icu.util.ULocale);
+    method public String getDisplayName(java.util.Locale);
+    method public String getDisplayName(android.icu.util.ULocale);
     method public final int getFieldCount();
     method protected int[][][] getFieldResolutionTable();
     method public int getFirstDayOfWeek();
@@ -21300,7 +21234,7 @@
     method public static android.icu.util.Calendar getInstance(android.icu.util.ULocale);
     method public static android.icu.util.Calendar getInstance(android.icu.util.TimeZone, java.util.Locale);
     method public static android.icu.util.Calendar getInstance(android.icu.util.TimeZone, android.icu.util.ULocale);
-    method public static final java.lang.String[] getKeywordValuesForLocale(java.lang.String, android.icu.util.ULocale, boolean);
+    method public static final String[] getKeywordValuesForLocale(String, android.icu.util.ULocale, boolean);
     method public final int getLeastMaximum(int);
     method protected int getLimit(int, int);
     method public final int getMaximum(int);
@@ -21312,18 +21246,18 @@
     method public final java.util.Date getTime();
     method public long getTimeInMillis();
     method public android.icu.util.TimeZone getTimeZone();
-    method public java.lang.String getType();
+    method public String getType();
     method public android.icu.util.Calendar.WeekData getWeekData();
-    method public static android.icu.util.Calendar.WeekData getWeekDataForRegion(java.lang.String);
+    method public static android.icu.util.Calendar.WeekData getWeekDataForRegion(String);
     method protected static final int gregorianMonthLength(int, int);
     method protected static final int gregorianPreviousMonthLength(int, int);
     method protected void handleComputeFields(int);
     method protected int handleComputeJulianDay(int);
     method protected abstract int handleComputeMonthStart(int, int, boolean);
     method protected int[] handleCreateFields();
-    method protected android.icu.text.DateFormat handleGetDateFormat(java.lang.String, java.util.Locale);
-    method protected android.icu.text.DateFormat handleGetDateFormat(java.lang.String, java.lang.String, java.util.Locale);
-    method protected android.icu.text.DateFormat handleGetDateFormat(java.lang.String, android.icu.util.ULocale);
+    method protected android.icu.text.DateFormat handleGetDateFormat(String, java.util.Locale);
+    method protected android.icu.text.DateFormat handleGetDateFormat(String, String, java.util.Locale);
+    method protected android.icu.text.DateFormat handleGetDateFormat(String, android.icu.util.ULocale);
     method protected abstract int handleGetExtendedYear();
     method protected abstract int handleGetLimit(int, int);
     method protected int handleGetMonthLength(int, int);
@@ -21370,7 +21304,7 @@
     field public static final int AM_PM = 9; // 0x9
     field public static final int APRIL = 3; // 0x3
     field public static final int AUGUST = 7; // 0x7
-    field protected static final deprecated int BASE_FIELD_COUNT = 23; // 0x17
+    field @Deprecated protected static final int BASE_FIELD_COUNT = 23; // 0x17
     field public static final int DATE = 5; // 0x5
     field public static final int DAY_OF_MONTH = 5; // 0x5
     field public static final int DAY_OF_WEEK = 7; // 0x7
@@ -21398,7 +21332,7 @@
     field public static final int MARCH = 2; // 0x2
     field protected static final int MAXIMUM = 3; // 0x3
     field protected static final java.util.Date MAX_DATE;
-    field protected static final deprecated int MAX_FIELD_COUNT = 32; // 0x20
+    field @Deprecated protected static final int MAX_FIELD_COUNT = 32; // 0x20
     field protected static final int MAX_JULIAN = 2130706432; // 0x7f000000
     field protected static final long MAX_MILLIS = 183882168921600000L; // 0x28d47dbbf19b000L
     field public static final int MAY = 4; // 0x4
@@ -21463,7 +21397,7 @@
     ctor public ChineseCalendar(android.icu.util.ULocale);
     ctor public ChineseCalendar(android.icu.util.TimeZone, android.icu.util.ULocale);
     method protected int handleComputeMonthStart(int, int, boolean);
-    method protected android.icu.text.DateFormat handleGetDateFormat(java.lang.String, java.lang.String, android.icu.util.ULocale);
+    method protected android.icu.text.DateFormat handleGetDateFormat(String, String, android.icu.util.ULocale);
     method protected int handleGetExtendedYear();
     method protected int handleGetLimit(int, int);
   }
@@ -21478,8 +21412,10 @@
     ctor public CopticCalendar(int, int, int);
     ctor public CopticCalendar(java.util.Date);
     ctor public CopticCalendar(int, int, int, int, int, int);
-    method protected deprecated void handleComputeFields(int);
-    method protected deprecated int handleGetExtendedYear();
+    method @Deprecated protected void handleComputeFields(int);
+    method protected int handleComputeMonthStart(int, int, boolean);
+    method @Deprecated protected int handleGetExtendedYear();
+    method protected int handleGetLimit(int, int);
     field public static final int AMSHIR = 5; // 0x5
     field public static final int BABA = 1; // 0x1
     field public static final int BARAMHAT = 6; // 0x6
@@ -21496,50 +21432,48 @@
   }
 
   public class Currency extends android.icu.util.MeasureUnit {
-    ctor protected Currency(java.lang.String);
+    ctor protected Currency(String);
     method public static android.icu.util.Currency fromJavaCurrency(java.util.Currency);
     method public static java.util.Set<android.icu.util.Currency> getAvailableCurrencies();
-    method public static java.lang.String[] getAvailableCurrencyCodes(android.icu.util.ULocale, java.util.Date);
-    method public static java.lang.String[] getAvailableCurrencyCodes(java.util.Locale, java.util.Date);
+    method public static String[] getAvailableCurrencyCodes(android.icu.util.ULocale, java.util.Date);
+    method public static String[] getAvailableCurrencyCodes(java.util.Locale, java.util.Date);
     method public static java.util.Locale[] getAvailableLocales();
     method public static android.icu.util.ULocale[] getAvailableULocales();
-    method public java.lang.String getCurrencyCode();
+    method public String getCurrencyCode();
     method public int getDefaultFractionDigits();
     method public int getDefaultFractionDigits(android.icu.util.Currency.CurrencyUsage);
-    method public java.lang.String getDisplayName();
-    method public java.lang.String getDisplayName(java.util.Locale);
+    method public String getDisplayName();
+    method public String getDisplayName(java.util.Locale);
     method public static android.icu.util.Currency getInstance(java.util.Locale);
     method public static android.icu.util.Currency getInstance(android.icu.util.ULocale);
-    method public static android.icu.util.Currency getInstance(java.lang.String);
-    method public static final java.lang.String[] getKeywordValuesForLocale(java.lang.String, android.icu.util.ULocale, boolean);
-    method public java.lang.String getName(java.util.Locale, int, boolean[]);
-    method public java.lang.String getName(android.icu.util.ULocale, int, boolean[]);
-    method public java.lang.String getName(java.util.Locale, int, java.lang.String, boolean[]);
-    method public java.lang.String getName(android.icu.util.ULocale, int, java.lang.String, boolean[]);
+    method public static android.icu.util.Currency getInstance(String);
+    method public static final String[] getKeywordValuesForLocale(String, android.icu.util.ULocale, boolean);
+    method public String getName(java.util.Locale, int, boolean[]);
+    method public String getName(android.icu.util.ULocale, int, boolean[]);
+    method public String getName(java.util.Locale, int, String, boolean[]);
+    method public String getName(android.icu.util.ULocale, int, String, boolean[]);
     method public int getNumericCode();
     method public double getRoundingIncrement();
     method public double getRoundingIncrement(android.icu.util.Currency.CurrencyUsage);
-    method public java.lang.String getSymbol();
-    method public java.lang.String getSymbol(java.util.Locale);
-    method public java.lang.String getSymbol(android.icu.util.ULocale);
-    method public static boolean isAvailable(java.lang.String, java.util.Date, java.util.Date);
+    method public String getSymbol();
+    method public String getSymbol(java.util.Locale);
+    method public String getSymbol(android.icu.util.ULocale);
+    method public static boolean isAvailable(String, java.util.Date, java.util.Date);
     method public java.util.Currency toJavaCurrency();
     field public static final int LONG_NAME = 1; // 0x1
     field public static final int PLURAL_LONG_NAME = 2; // 0x2
     field public static final int SYMBOL_NAME = 0; // 0x0
   }
 
-  public static final class Currency.CurrencyUsage extends java.lang.Enum {
-    method public static android.icu.util.Currency.CurrencyUsage valueOf(java.lang.String);
-    method public static final android.icu.util.Currency.CurrencyUsage[] values();
+  public enum Currency.CurrencyUsage {
     enum_constant public static final android.icu.util.Currency.CurrencyUsage CASH;
     enum_constant public static final android.icu.util.Currency.CurrencyUsage STANDARD;
   }
 
   public class CurrencyAmount extends android.icu.util.Measure {
-    ctor public CurrencyAmount(java.lang.Number, android.icu.util.Currency);
+    ctor public CurrencyAmount(Number, android.icu.util.Currency);
     ctor public CurrencyAmount(double, android.icu.util.Currency);
-    ctor public CurrencyAmount(java.lang.Number, java.util.Currency);
+    ctor public CurrencyAmount(Number, java.util.Currency);
     ctor public CurrencyAmount(double, java.util.Currency);
     method public android.icu.util.Currency getCurrency();
   }
@@ -21560,9 +21494,10 @@
     ctor public EthiopicCalendar(int, int, int);
     ctor public EthiopicCalendar(java.util.Date);
     ctor public EthiopicCalendar(int, int, int, int, int, int);
-    method protected deprecated void handleComputeFields(int);
-    method protected deprecated int handleGetExtendedYear();
-    method protected deprecated int handleGetLimit(int, int);
+    method @Deprecated protected void handleComputeFields(int);
+    method protected int handleComputeMonthStart(int, int, boolean);
+    method @Deprecated protected int handleGetExtendedYear();
+    method @Deprecated protected int handleGetLimit(int, int);
     method public boolean isAmeteAlemEra();
     method public void setAmeteAlemEra(boolean);
     field public static final int GENBOT = 8; // 0x8
@@ -21580,10 +21515,10 @@
     field public static final int YEKATIT = 5; // 0x5
   }
 
-  public abstract interface Freezable<T> implements java.lang.Cloneable {
-    method public abstract T cloneAsThawed();
-    method public abstract T freeze();
-    method public abstract boolean isFrozen();
+  public interface Freezable<T> extends java.lang.Cloneable {
+    method public T cloneAsThawed();
+    method public T freeze();
+    method public boolean isFrozen();
   }
 
   public class GregorianCalendar extends android.icu.util.Calendar {
@@ -21621,7 +21556,7 @@
     method protected int handleComputeMonthStart(int, int, boolean);
     method protected int handleGetExtendedYear();
     method protected int handleGetLimit(int, int);
-    method protected deprecated void validateField(int);
+    method @Deprecated protected void validateField(int);
     field public static final int ADAR = 6; // 0x6
     field public static final int ADAR_1 = 5; // 0x5
     field public static final int AV = 11; // 0xb
@@ -21639,15 +21574,15 @@
 
   public class ICUUncheckedIOException extends java.lang.RuntimeException {
     ctor public ICUUncheckedIOException();
-    ctor public ICUUncheckedIOException(java.lang.String);
-    ctor public ICUUncheckedIOException(java.lang.Throwable);
-    ctor public ICUUncheckedIOException(java.lang.String, java.lang.Throwable);
+    ctor public ICUUncheckedIOException(String);
+    ctor public ICUUncheckedIOException(Throwable);
+    ctor public ICUUncheckedIOException(String, Throwable);
   }
 
   public class IllformedLocaleException extends java.lang.RuntimeException {
     ctor public IllformedLocaleException();
-    ctor public IllformedLocaleException(java.lang.String);
-    ctor public IllformedLocaleException(java.lang.String, int);
+    ctor public IllformedLocaleException(String);
+    ctor public IllformedLocaleException(String, int);
     method public int getErrorIndex();
   }
 
@@ -21708,9 +21643,7 @@
     field public static final int SHAWWAL = 9; // 0x9
   }
 
-  public static final class IslamicCalendar.CalculationType extends java.lang.Enum {
-    method public static android.icu.util.IslamicCalendar.CalculationType valueOf(java.lang.String);
-    method public static final android.icu.util.IslamicCalendar.CalculationType[] values();
+  public enum IslamicCalendar.CalculationType {
     enum_constant public static final android.icu.util.IslamicCalendar.CalculationType ISLAMIC;
     enum_constant public static final android.icu.util.IslamicCalendar.CalculationType ISLAMIC_CIVIL;
     enum_constant public static final android.icu.util.IslamicCalendar.CalculationType ISLAMIC_TBLA;
@@ -21728,7 +21661,7 @@
     ctor public JapaneseCalendar(int, int, int, int);
     ctor public JapaneseCalendar(int, int, int);
     ctor public JapaneseCalendar(int, int, int, int, int, int);
-    field public static final int CURRENT_ERA;
+    field @Deprecated public static final int CURRENT_ERA;
     field public static final int HEISEI;
     field public static final int MEIJI;
     field public static final int SHOWA;
@@ -21737,7 +21670,7 @@
 
   public final class LocaleData {
     method public static android.icu.util.VersionInfo getCLDRVersion();
-    method public java.lang.String getDelimiter(int);
+    method public String getDelimiter(int);
     method public static android.icu.util.LocaleData getInstance(android.icu.util.ULocale);
     method public static android.icu.util.LocaleData getInstance();
     method public static android.icu.util.LocaleData.MeasurementSystem getMeasurementSystem(android.icu.util.ULocale);
@@ -21762,17 +21695,17 @@
   }
 
   public class Measure {
-    ctor public Measure(java.lang.Number, android.icu.util.MeasureUnit);
-    method public java.lang.Number getNumber();
+    ctor public Measure(Number, android.icu.util.MeasureUnit);
+    method public Number getNumber();
     method public android.icu.util.MeasureUnit getUnit();
   }
 
   public class MeasureUnit implements java.io.Serializable {
-    method public static synchronized java.util.Set<android.icu.util.MeasureUnit> getAvailable(java.lang.String);
-    method public static synchronized java.util.Set<android.icu.util.MeasureUnit> getAvailable();
-    method public static synchronized java.util.Set<java.lang.String> getAvailableTypes();
-    method public java.lang.String getSubtype();
-    method public java.lang.String getType();
+    method public static java.util.Set<android.icu.util.MeasureUnit> getAvailable(String);
+    method public static java.util.Set<android.icu.util.MeasureUnit> getAvailable();
+    method public static java.util.Set<java.lang.String> getAvailableTypes();
+    method public String getSubtype();
+    method public String getType();
     field public static final android.icu.util.MeasureUnit ACRE;
     field public static final android.icu.util.MeasureUnit ACRE_FOOT;
     field public static final android.icu.util.MeasureUnit AMPERE;
@@ -21916,9 +21849,9 @@
     field public T value;
   }
 
-  public abstract interface RangeValueIterator {
-    method public abstract boolean next(android.icu.util.RangeValueIterator.Element);
-    method public abstract void reset();
+  public interface RangeValueIterator {
+    method public boolean next(android.icu.util.RangeValueIterator.Element);
+    method public void reset();
   }
 
   public static class RangeValueIterator.Element {
@@ -21946,44 +21879,44 @@
     method public static android.icu.util.TimeUnit[] values();
   }
 
-  public abstract class TimeZone implements java.lang.Cloneable android.icu.util.Freezable java.io.Serializable {
+  public abstract class TimeZone implements java.lang.Cloneable android.icu.util.Freezable<android.icu.util.TimeZone> java.io.Serializable {
     ctor public TimeZone();
-    method public java.lang.Object clone();
+    method public Object clone();
     method public android.icu.util.TimeZone cloneAsThawed();
-    method public static int countEquivalentIDs(java.lang.String);
+    method public static int countEquivalentIDs(String);
     method public android.icu.util.TimeZone freeze();
-    method public static java.util.Set<java.lang.String> getAvailableIDs(android.icu.util.TimeZone.SystemTimeZoneType, java.lang.String, java.lang.Integer);
-    method public static java.lang.String[] getAvailableIDs(int);
-    method public static java.lang.String[] getAvailableIDs(java.lang.String);
-    method public static java.lang.String[] getAvailableIDs();
-    method public static java.lang.String getCanonicalID(java.lang.String);
-    method public static java.lang.String getCanonicalID(java.lang.String, boolean[]);
+    method public static java.util.Set<java.lang.String> getAvailableIDs(android.icu.util.TimeZone.SystemTimeZoneType, String, Integer);
+    method public static String[] getAvailableIDs(int);
+    method public static String[] getAvailableIDs(String);
+    method public static String[] getAvailableIDs();
+    method public static String getCanonicalID(String);
+    method public static String getCanonicalID(String, boolean[]);
     method public int getDSTSavings();
     method public static android.icu.util.TimeZone getDefault();
-    method public final java.lang.String getDisplayName();
-    method public final java.lang.String getDisplayName(java.util.Locale);
-    method public final java.lang.String getDisplayName(android.icu.util.ULocale);
-    method public final java.lang.String getDisplayName(boolean, int);
-    method public java.lang.String getDisplayName(boolean, int, java.util.Locale);
-    method public java.lang.String getDisplayName(boolean, int, android.icu.util.ULocale);
-    method public static java.lang.String getEquivalentID(java.lang.String, int);
-    method public static android.icu.util.TimeZone getFrozenTimeZone(java.lang.String);
-    method public java.lang.String getID();
-    method public static java.lang.String getIDForWindowsID(java.lang.String, java.lang.String);
+    method public final String getDisplayName();
+    method public final String getDisplayName(java.util.Locale);
+    method public final String getDisplayName(android.icu.util.ULocale);
+    method public final String getDisplayName(boolean, int);
+    method public String getDisplayName(boolean, int, java.util.Locale);
+    method public String getDisplayName(boolean, int, android.icu.util.ULocale);
+    method public static String getEquivalentID(String, int);
+    method public static android.icu.util.TimeZone getFrozenTimeZone(String);
+    method public String getID();
+    method public static String getIDForWindowsID(String, String);
     method public abstract int getOffset(int, int, int, int, int, int);
     method public int getOffset(long);
     method public void getOffset(long, boolean, int[]);
     method public abstract int getRawOffset();
-    method public static java.lang.String getRegion(java.lang.String);
-    method public static java.lang.String getTZDataVersion();
-    method public static android.icu.util.TimeZone getTimeZone(java.lang.String);
-    method public static android.icu.util.TimeZone getTimeZone(java.lang.String, int);
-    method public static java.lang.String getWindowsID(java.lang.String);
+    method public static String getRegion(String);
+    method public static String getTZDataVersion();
+    method public static android.icu.util.TimeZone getTimeZone(String);
+    method public static android.icu.util.TimeZone getTimeZone(String, int);
+    method public static String getWindowsID(String);
     method public boolean hasSameRules(android.icu.util.TimeZone);
     method public abstract boolean inDaylightTime(java.util.Date);
     method public boolean isFrozen();
     method public boolean observesDaylightTime();
-    method public void setID(java.lang.String);
+    method public void setID(String);
     method public abstract void setRawOffset(int);
     method public abstract boolean useDaylightTime();
     field public static final int GENERIC_LOCATION = 7; // 0x7
@@ -21998,111 +21931,109 @@
     field public static final int TIMEZONE_ICU = 0; // 0x0
     field public static final int TIMEZONE_JDK = 1; // 0x1
     field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
-    field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
+    field public static final String UNKNOWN_ZONE_ID = "Etc/Unknown";
   }
 
-  public static final class TimeZone.SystemTimeZoneType extends java.lang.Enum {
-    method public static android.icu.util.TimeZone.SystemTimeZoneType valueOf(java.lang.String);
-    method public static final android.icu.util.TimeZone.SystemTimeZoneType[] values();
+  public enum TimeZone.SystemTimeZoneType {
     enum_constant public static final android.icu.util.TimeZone.SystemTimeZoneType ANY;
     enum_constant public static final android.icu.util.TimeZone.SystemTimeZoneType CANONICAL;
     enum_constant public static final android.icu.util.TimeZone.SystemTimeZoneType CANONICAL_LOCATION;
   }
 
-  public final class ULocale implements java.lang.Comparable java.io.Serializable {
-    ctor public ULocale(java.lang.String);
-    ctor public ULocale(java.lang.String, java.lang.String);
-    ctor public ULocale(java.lang.String, java.lang.String, java.lang.String);
-    method public static android.icu.util.ULocale acceptLanguage(java.lang.String, android.icu.util.ULocale[], boolean[]);
+  public final class ULocale implements java.lang.Comparable<android.icu.util.ULocale> java.io.Serializable {
+    ctor public ULocale(String);
+    ctor public ULocale(String, String);
+    ctor public ULocale(String, String, String);
+    method public static android.icu.util.ULocale acceptLanguage(String, android.icu.util.ULocale[], boolean[]);
     method public static android.icu.util.ULocale acceptLanguage(android.icu.util.ULocale[], android.icu.util.ULocale[], boolean[]);
-    method public static android.icu.util.ULocale acceptLanguage(java.lang.String, boolean[]);
+    method public static android.icu.util.ULocale acceptLanguage(String, boolean[]);
     method public static android.icu.util.ULocale acceptLanguage(android.icu.util.ULocale[], boolean[]);
     method public static android.icu.util.ULocale addLikelySubtags(android.icu.util.ULocale);
-    method public static java.lang.String canonicalize(java.lang.String);
-    method public java.lang.Object clone();
+    method public static String canonicalize(String);
+    method public Object clone();
     method public int compareTo(android.icu.util.ULocale);
-    method public static android.icu.util.ULocale createCanonical(java.lang.String);
-    method public static android.icu.util.ULocale forLanguageTag(java.lang.String);
+    method public static android.icu.util.ULocale createCanonical(String);
+    method public static android.icu.util.ULocale forLanguageTag(String);
     method public static android.icu.util.ULocale forLocale(java.util.Locale);
     method public static android.icu.util.ULocale[] getAvailableLocales();
-    method public java.lang.String getBaseName();
-    method public static java.lang.String getBaseName(java.lang.String);
-    method public java.lang.String getCharacterOrientation();
-    method public java.lang.String getCountry();
-    method public static java.lang.String getCountry(java.lang.String);
+    method public String getBaseName();
+    method public static String getBaseName(String);
+    method public String getCharacterOrientation();
+    method public String getCountry();
+    method public static String getCountry(String);
     method public static android.icu.util.ULocale getDefault();
     method public static android.icu.util.ULocale getDefault(android.icu.util.ULocale.Category);
-    method public java.lang.String getDisplayCountry();
-    method public java.lang.String getDisplayCountry(android.icu.util.ULocale);
-    method public static java.lang.String getDisplayCountry(java.lang.String, java.lang.String);
-    method public static java.lang.String getDisplayCountry(java.lang.String, android.icu.util.ULocale);
-    method public static java.lang.String getDisplayKeyword(java.lang.String);
-    method public static java.lang.String getDisplayKeyword(java.lang.String, java.lang.String);
-    method public static java.lang.String getDisplayKeyword(java.lang.String, android.icu.util.ULocale);
-    method public java.lang.String getDisplayKeywordValue(java.lang.String);
-    method public java.lang.String getDisplayKeywordValue(java.lang.String, android.icu.util.ULocale);
-    method public static java.lang.String getDisplayKeywordValue(java.lang.String, java.lang.String, java.lang.String);
-    method public static java.lang.String getDisplayKeywordValue(java.lang.String, java.lang.String, android.icu.util.ULocale);
-    method public java.lang.String getDisplayLanguage();
-    method public java.lang.String getDisplayLanguage(android.icu.util.ULocale);
-    method public static java.lang.String getDisplayLanguage(java.lang.String, java.lang.String);
-    method public static java.lang.String getDisplayLanguage(java.lang.String, android.icu.util.ULocale);
-    method public java.lang.String getDisplayLanguageWithDialect();
-    method public java.lang.String getDisplayLanguageWithDialect(android.icu.util.ULocale);
-    method public static java.lang.String getDisplayLanguageWithDialect(java.lang.String, java.lang.String);
-    method public static java.lang.String getDisplayLanguageWithDialect(java.lang.String, android.icu.util.ULocale);
-    method public java.lang.String getDisplayName();
-    method public java.lang.String getDisplayName(android.icu.util.ULocale);
-    method public static java.lang.String getDisplayName(java.lang.String, java.lang.String);
-    method public static java.lang.String getDisplayName(java.lang.String, android.icu.util.ULocale);
-    method public java.lang.String getDisplayNameWithDialect();
-    method public java.lang.String getDisplayNameWithDialect(android.icu.util.ULocale);
-    method public static java.lang.String getDisplayNameWithDialect(java.lang.String, java.lang.String);
-    method public static java.lang.String getDisplayNameWithDialect(java.lang.String, android.icu.util.ULocale);
-    method public java.lang.String getDisplayScript();
-    method public java.lang.String getDisplayScript(android.icu.util.ULocale);
-    method public static java.lang.String getDisplayScript(java.lang.String, java.lang.String);
-    method public static java.lang.String getDisplayScript(java.lang.String, android.icu.util.ULocale);
-    method public java.lang.String getDisplayVariant();
-    method public java.lang.String getDisplayVariant(android.icu.util.ULocale);
-    method public static java.lang.String getDisplayVariant(java.lang.String, java.lang.String);
-    method public static java.lang.String getDisplayVariant(java.lang.String, android.icu.util.ULocale);
-    method public java.lang.String getExtension(char);
+    method public String getDisplayCountry();
+    method public String getDisplayCountry(android.icu.util.ULocale);
+    method public static String getDisplayCountry(String, String);
+    method public static String getDisplayCountry(String, android.icu.util.ULocale);
+    method public static String getDisplayKeyword(String);
+    method public static String getDisplayKeyword(String, String);
+    method public static String getDisplayKeyword(String, android.icu.util.ULocale);
+    method public String getDisplayKeywordValue(String);
+    method public String getDisplayKeywordValue(String, android.icu.util.ULocale);
+    method public static String getDisplayKeywordValue(String, String, String);
+    method public static String getDisplayKeywordValue(String, String, android.icu.util.ULocale);
+    method public String getDisplayLanguage();
+    method public String getDisplayLanguage(android.icu.util.ULocale);
+    method public static String getDisplayLanguage(String, String);
+    method public static String getDisplayLanguage(String, android.icu.util.ULocale);
+    method public String getDisplayLanguageWithDialect();
+    method public String getDisplayLanguageWithDialect(android.icu.util.ULocale);
+    method public static String getDisplayLanguageWithDialect(String, String);
+    method public static String getDisplayLanguageWithDialect(String, android.icu.util.ULocale);
+    method public String getDisplayName();
+    method public String getDisplayName(android.icu.util.ULocale);
+    method public static String getDisplayName(String, String);
+    method public static String getDisplayName(String, android.icu.util.ULocale);
+    method public String getDisplayNameWithDialect();
+    method public String getDisplayNameWithDialect(android.icu.util.ULocale);
+    method public static String getDisplayNameWithDialect(String, String);
+    method public static String getDisplayNameWithDialect(String, android.icu.util.ULocale);
+    method public String getDisplayScript();
+    method public String getDisplayScript(android.icu.util.ULocale);
+    method public static String getDisplayScript(String, String);
+    method public static String getDisplayScript(String, android.icu.util.ULocale);
+    method public String getDisplayVariant();
+    method public String getDisplayVariant(android.icu.util.ULocale);
+    method public static String getDisplayVariant(String, String);
+    method public static String getDisplayVariant(String, android.icu.util.ULocale);
+    method public String getExtension(char);
     method public java.util.Set<java.lang.Character> getExtensionKeys();
-    method public static java.lang.String getFallback(java.lang.String);
+    method public static String getFallback(String);
     method public android.icu.util.ULocale getFallback();
-    method public java.lang.String getISO3Country();
-    method public static java.lang.String getISO3Country(java.lang.String);
-    method public java.lang.String getISO3Language();
-    method public static java.lang.String getISO3Language(java.lang.String);
-    method public static java.lang.String[] getISOCountries();
-    method public static java.lang.String[] getISOLanguages();
-    method public java.lang.String getKeywordValue(java.lang.String);
-    method public static java.lang.String getKeywordValue(java.lang.String, java.lang.String);
+    method public String getISO3Country();
+    method public static String getISO3Country(String);
+    method public String getISO3Language();
+    method public static String getISO3Language(String);
+    method public static String[] getISOCountries();
+    method public static String[] getISOLanguages();
+    method public String getKeywordValue(String);
+    method public static String getKeywordValue(String, String);
     method public java.util.Iterator<java.lang.String> getKeywords();
-    method public static java.util.Iterator<java.lang.String> getKeywords(java.lang.String);
-    method public java.lang.String getLanguage();
-    method public static java.lang.String getLanguage(java.lang.String);
-    method public java.lang.String getLineOrientation();
-    method public java.lang.String getName();
-    method public static java.lang.String getName(java.lang.String);
-    method public java.lang.String getScript();
-    method public static java.lang.String getScript(java.lang.String);
+    method public static java.util.Iterator<java.lang.String> getKeywords(String);
+    method public String getLanguage();
+    method public static String getLanguage(String);
+    method public String getLineOrientation();
+    method public String getName();
+    method public static String getName(String);
+    method public String getScript();
+    method public static String getScript(String);
     method public java.util.Set<java.lang.String> getUnicodeLocaleAttributes();
     method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
-    method public java.lang.String getUnicodeLocaleType(java.lang.String);
-    method public java.lang.String getVariant();
-    method public static java.lang.String getVariant(java.lang.String);
+    method public String getUnicodeLocaleType(String);
+    method public String getVariant();
+    method public static String getVariant(String);
     method public boolean isRightToLeft();
     method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale);
-    method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String);
-    method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String);
-    method public java.lang.String toLanguageTag();
-    method public static java.lang.String toLegacyKey(java.lang.String);
-    method public static java.lang.String toLegacyType(java.lang.String, java.lang.String);
+    method public android.icu.util.ULocale setKeywordValue(String, String);
+    method public static String setKeywordValue(String, String, String);
+    method public String toLanguageTag();
+    method public static String toLegacyKey(String);
+    method public static String toLegacyType(String, String);
     method public java.util.Locale toLocale();
-    method public static java.lang.String toUnicodeLocaleKey(java.lang.String);
-    method public static java.lang.String toUnicodeLocaleType(java.lang.String, java.lang.String);
+    method public static String toUnicodeLocaleKey(String);
+    method public static String toUnicodeLocaleType(String, String);
     field public static final android.icu.util.ULocale CANADA;
     field public static final android.icu.util.ULocale CANADA_FRENCH;
     field public static final android.icu.util.ULocale CHINA;
@@ -22131,24 +22062,22 @@
 
   public static final class ULocale.Builder {
     ctor public ULocale.Builder();
-    method public android.icu.util.ULocale.Builder addUnicodeLocaleAttribute(java.lang.String);
+    method public android.icu.util.ULocale.Builder addUnicodeLocaleAttribute(String);
     method public android.icu.util.ULocale build();
     method public android.icu.util.ULocale.Builder clear();
     method public android.icu.util.ULocale.Builder clearExtensions();
-    method public android.icu.util.ULocale.Builder removeUnicodeLocaleAttribute(java.lang.String);
-    method public android.icu.util.ULocale.Builder setExtension(char, java.lang.String);
-    method public android.icu.util.ULocale.Builder setLanguage(java.lang.String);
-    method public android.icu.util.ULocale.Builder setLanguageTag(java.lang.String);
+    method public android.icu.util.ULocale.Builder removeUnicodeLocaleAttribute(String);
+    method public android.icu.util.ULocale.Builder setExtension(char, String);
+    method public android.icu.util.ULocale.Builder setLanguage(String);
+    method public android.icu.util.ULocale.Builder setLanguageTag(String);
     method public android.icu.util.ULocale.Builder setLocale(android.icu.util.ULocale);
-    method public android.icu.util.ULocale.Builder setRegion(java.lang.String);
-    method public android.icu.util.ULocale.Builder setScript(java.lang.String);
-    method public android.icu.util.ULocale.Builder setUnicodeLocaleKeyword(java.lang.String, java.lang.String);
-    method public android.icu.util.ULocale.Builder setVariant(java.lang.String);
+    method public android.icu.util.ULocale.Builder setRegion(String);
+    method public android.icu.util.ULocale.Builder setScript(String);
+    method public android.icu.util.ULocale.Builder setUnicodeLocaleKeyword(String, String);
+    method public android.icu.util.ULocale.Builder setVariant(String);
   }
 
-  public static final class ULocale.Category extends java.lang.Enum {
-    method public static android.icu.util.ULocale.Category valueOf(java.lang.String);
-    method public static final android.icu.util.ULocale.Category[] values();
+  public enum ULocale.Category {
     enum_constant public static final android.icu.util.ULocale.Category DISPLAY;
     enum_constant public static final android.icu.util.ULocale.Category FORMAT;
   }
@@ -22173,7 +22102,7 @@
     field public static final int JAVA_TIME = 0; // 0x0
     field public static final int MAC_OLD_TIME = 5; // 0x5
     field public static final int MAC_TIME = 6; // 0x6
-    field public static final deprecated int MAX_SCALE = 10; // 0xa
+    field @Deprecated public static final int MAX_SCALE = 10; // 0xa
     field public static final int TO_MAX_VALUE = 5; // 0x5
     field public static final int TO_MIN_VALUE = 4; // 0x4
     field public static final int UNITS_VALUE = 0; // 0x0
@@ -22182,21 +22111,21 @@
     field public static final int WINDOWS_FILE_TIME = 3; // 0x3
   }
 
-  public abstract interface ValueIterator {
-    method public abstract boolean next(android.icu.util.ValueIterator.Element);
-    method public abstract void reset();
-    method public abstract void setRange(int, int);
+  public interface ValueIterator {
+    method public boolean next(android.icu.util.ValueIterator.Element);
+    method public void reset();
+    method public void setRange(int, int);
   }
 
   public static final class ValueIterator.Element {
     ctor public ValueIterator.Element();
     field public int integer;
-    field public java.lang.Object value;
+    field public Object value;
   }
 
-  public final class VersionInfo implements java.lang.Comparable {
+  public final class VersionInfo implements java.lang.Comparable<android.icu.util.VersionInfo> {
     method public int compareTo(android.icu.util.VersionInfo);
-    method public static android.icu.util.VersionInfo getInstance(java.lang.String);
+    method public static android.icu.util.VersionInfo getInstance(String);
     method public static android.icu.util.VersionInfo getInstance(int, int, int, int);
     method public static android.icu.util.VersionInfo getInstance(int, int, int);
     method public static android.icu.util.VersionInfo getInstance(int, int);
@@ -22255,9 +22184,9 @@
 
   public abstract class AbstractInputMethodService.AbstractInputMethodImpl implements android.view.inputmethod.InputMethod {
     ctor public AbstractInputMethodService.AbstractInputMethodImpl();
-    method public void createSession(android.view.inputmethod.InputMethod.SessionCallback);
-    method public void revokeSession(android.view.inputmethod.InputMethodSession);
-    method public void setSessionEnabled(android.view.inputmethod.InputMethodSession, boolean);
+    method @MainThread public void createSession(android.view.inputmethod.InputMethod.SessionCallback);
+    method @MainThread public void revokeSession(android.view.inputmethod.InputMethodSession);
+    method @MainThread public void setSessionEnabled(android.view.inputmethod.InputMethodSession, boolean);
   }
 
   public abstract class AbstractInputMethodService.AbstractInputMethodSessionImpl implements android.view.inputmethod.InputMethodSession {
@@ -22283,17 +22212,17 @@
 
   public class InputMethodService extends android.inputmethodservice.AbstractInputMethodService {
     ctor public InputMethodService();
-    method public deprecated boolean enableHardwareAcceleration();
+    method @Deprecated public boolean enableHardwareAcceleration();
     method public int getBackDisposition();
     method public int getCandidatesHiddenVisibility();
     method public android.view.inputmethod.InputBinding getCurrentInputBinding();
     method public android.view.inputmethod.InputConnection getCurrentInputConnection();
     method public android.view.inputmethod.EditorInfo getCurrentInputEditorInfo();
     method public boolean getCurrentInputStarted();
-    method public deprecated int getInputMethodWindowRecommendedHeight();
+    method @Deprecated public int getInputMethodWindowRecommendedHeight();
     method public android.view.LayoutInflater getLayoutInflater();
     method public int getMaxWidth();
-    method public java.lang.CharSequence getTextForImeAction(int);
+    method public CharSequence getTextForImeAction(int);
     method public android.app.Dialog getWindow();
     method public void hideStatusIcon();
     method public void hideWindow();
@@ -22301,7 +22230,7 @@
     method public boolean isFullscreenMode();
     method public boolean isInputViewShown();
     method public boolean isShowInputRequested();
-    method public void onAppPrivateCommand(java.lang.String, android.os.Bundle);
+    method public void onAppPrivateCommand(String, android.os.Bundle);
     method public void onBindInput();
     method public void onComputeInsets(android.inputmethodservice.InputMethodService.Insets);
     method public void onConfigureWindow(android.view.Window, boolean, boolean);
@@ -22313,7 +22242,7 @@
     method protected void onCurrentInputMethodSubtypeChanged(android.view.inputmethod.InputMethodSubtype);
     method public void onDisplayCompletions(android.view.inputmethod.CompletionInfo[]);
     method public boolean onEvaluateFullscreenMode();
-    method public boolean onEvaluateInputViewShown();
+    method @CallSuper public boolean onEvaluateInputViewShown();
     method public boolean onExtractTextContextMenuItem(int);
     method public void onExtractedCursorMovement(int, int);
     method public void onExtractedSelectionChanged(int, int);
@@ -22332,13 +22261,13 @@
     method public void onStartInput(android.view.inputmethod.EditorInfo, boolean);
     method public void onStartInputView(android.view.inputmethod.EditorInfo, boolean);
     method public void onUnbindInput();
-    method public deprecated void onUpdateCursor(android.graphics.Rect);
+    method @Deprecated public void onUpdateCursor(android.graphics.Rect);
     method public void onUpdateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
     method public void onUpdateExtractedText(int, android.view.inputmethod.ExtractedText);
     method public void onUpdateExtractingViews(android.view.inputmethod.EditorInfo);
     method public void onUpdateExtractingVisibility(android.view.inputmethod.EditorInfo);
     method public void onUpdateSelection(int, int, int, int, int, int);
-    method public void onViewClicked(boolean);
+    method @Deprecated public void onViewClicked(boolean);
     method public void onWindowHidden();
     method public void onWindowShown();
     method public void requestHideSelf(int);
@@ -22353,35 +22282,35 @@
     method public void setExtractViewShown(boolean);
     method public void setInputView(android.view.View);
     method public final boolean shouldOfferSwitchingToNextInputMethod();
-    method public void showStatusIcon(int);
+    method public void showStatusIcon(@DrawableRes int);
     method public void showWindow(boolean);
-    method public void switchInputMethod(java.lang.String);
-    method public final void switchInputMethod(java.lang.String, android.view.inputmethod.InputMethodSubtype);
+    method public void switchInputMethod(String);
+    method public final void switchInputMethod(String, android.view.inputmethod.InputMethodSubtype);
     method public final boolean switchToNextInputMethod(boolean);
     method public final boolean switchToPreviousInputMethod();
     method public void updateFullscreenMode();
     method public void updateInputViewShown();
     field public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3; // 0x3
     field public static final int BACK_DISPOSITION_DEFAULT = 0; // 0x0
-    field public static final deprecated int BACK_DISPOSITION_WILL_DISMISS = 2; // 0x2
-    field public static final deprecated int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // 0x1
+    field @Deprecated public static final int BACK_DISPOSITION_WILL_DISMISS = 2; // 0x2
+    field @Deprecated public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // 0x1
   }
 
   public class InputMethodService.InputMethodImpl extends android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl {
     ctor public InputMethodService.InputMethodImpl();
-    method public void attachToken(android.os.IBinder);
-    method public void bindInput(android.view.inputmethod.InputBinding);
-    method public void changeInputMethodSubtype(android.view.inputmethod.InputMethodSubtype);
-    method public void hideSoftInput(int, android.os.ResultReceiver);
-    method public void restartInput(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
-    method public void showSoftInput(int, android.os.ResultReceiver);
-    method public void startInput(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
-    method public void unbindInput();
+    method @MainThread public void attachToken(android.os.IBinder);
+    method @MainThread public void bindInput(android.view.inputmethod.InputBinding);
+    method @MainThread public void changeInputMethodSubtype(android.view.inputmethod.InputMethodSubtype);
+    method @MainThread public void hideSoftInput(int, android.os.ResultReceiver);
+    method @MainThread public void restartInput(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
+    method @MainThread public void showSoftInput(int, android.os.ResultReceiver);
+    method @MainThread public void startInput(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
+    method @MainThread public void unbindInput();
   }
 
   public class InputMethodService.InputMethodSessionImpl extends android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl {
     ctor public InputMethodService.InputMethodSessionImpl();
-    method public void appPrivateCommand(java.lang.String, android.os.Bundle);
+    method public void appPrivateCommand(String, android.os.Bundle);
     method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
     method public void finishInput();
     method public void toggleSoftInput(int, int);
@@ -22404,122 +22333,122 @@
     field public int visibleTopInsets;
   }
 
-  public deprecated class Keyboard {
-    ctor public Keyboard(android.content.Context, int);
-    ctor public Keyboard(android.content.Context, int, int, int, int);
-    ctor public Keyboard(android.content.Context, int, int);
-    ctor public Keyboard(android.content.Context, int, java.lang.CharSequence, int, int);
-    method protected android.inputmethodservice.Keyboard.Key createKeyFromXml(android.content.res.Resources, android.inputmethodservice.Keyboard.Row, int, int, android.content.res.XmlResourceParser);
-    method protected android.inputmethodservice.Keyboard.Row createRowFromXml(android.content.res.Resources, android.content.res.XmlResourceParser);
-    method public int getHeight();
-    method protected int getHorizontalGap();
-    method protected int getKeyHeight();
-    method protected int getKeyWidth();
-    method public java.util.List<android.inputmethodservice.Keyboard.Key> getKeys();
-    method public int getMinWidth();
-    method public java.util.List<android.inputmethodservice.Keyboard.Key> getModifierKeys();
-    method public int[] getNearestKeys(int, int);
-    method public int getShiftKeyIndex();
-    method protected int getVerticalGap();
-    method public boolean isShifted();
-    method protected void setHorizontalGap(int);
-    method protected void setKeyHeight(int);
-    method protected void setKeyWidth(int);
-    method public boolean setShifted(boolean);
-    method protected void setVerticalGap(int);
-    field public static final int EDGE_BOTTOM = 8; // 0x8
-    field public static final int EDGE_LEFT = 1; // 0x1
-    field public static final int EDGE_RIGHT = 2; // 0x2
-    field public static final int EDGE_TOP = 4; // 0x4
-    field public static final int KEYCODE_ALT = -6; // 0xfffffffa
-    field public static final int KEYCODE_CANCEL = -3; // 0xfffffffd
-    field public static final int KEYCODE_DELETE = -5; // 0xfffffffb
-    field public static final int KEYCODE_DONE = -4; // 0xfffffffc
-    field public static final int KEYCODE_MODE_CHANGE = -2; // 0xfffffffe
-    field public static final int KEYCODE_SHIFT = -1; // 0xffffffff
+  @Deprecated public class Keyboard {
+    ctor @Deprecated public Keyboard(android.content.Context, int);
+    ctor @Deprecated public Keyboard(android.content.Context, @XmlRes int, int, int, int);
+    ctor @Deprecated public Keyboard(android.content.Context, @XmlRes int, int);
+    ctor @Deprecated public Keyboard(android.content.Context, int, CharSequence, int, int);
+    method @Deprecated protected android.inputmethodservice.Keyboard.Key createKeyFromXml(android.content.res.Resources, android.inputmethodservice.Keyboard.Row, int, int, android.content.res.XmlResourceParser);
+    method @Deprecated protected android.inputmethodservice.Keyboard.Row createRowFromXml(android.content.res.Resources, android.content.res.XmlResourceParser);
+    method @Deprecated public int getHeight();
+    method @Deprecated protected int getHorizontalGap();
+    method @Deprecated protected int getKeyHeight();
+    method @Deprecated protected int getKeyWidth();
+    method @Deprecated public java.util.List<android.inputmethodservice.Keyboard.Key> getKeys();
+    method @Deprecated public int getMinWidth();
+    method @Deprecated public java.util.List<android.inputmethodservice.Keyboard.Key> getModifierKeys();
+    method @Deprecated public int[] getNearestKeys(int, int);
+    method @Deprecated public int getShiftKeyIndex();
+    method @Deprecated protected int getVerticalGap();
+    method @Deprecated public boolean isShifted();
+    method @Deprecated protected void setHorizontalGap(int);
+    method @Deprecated protected void setKeyHeight(int);
+    method @Deprecated protected void setKeyWidth(int);
+    method @Deprecated public boolean setShifted(boolean);
+    method @Deprecated protected void setVerticalGap(int);
+    field @Deprecated public static final int EDGE_BOTTOM = 8; // 0x8
+    field @Deprecated public static final int EDGE_LEFT = 1; // 0x1
+    field @Deprecated public static final int EDGE_RIGHT = 2; // 0x2
+    field @Deprecated public static final int EDGE_TOP = 4; // 0x4
+    field @Deprecated public static final int KEYCODE_ALT = -6; // 0xfffffffa
+    field @Deprecated public static final int KEYCODE_CANCEL = -3; // 0xfffffffd
+    field @Deprecated public static final int KEYCODE_DELETE = -5; // 0xfffffffb
+    field @Deprecated public static final int KEYCODE_DONE = -4; // 0xfffffffc
+    field @Deprecated public static final int KEYCODE_MODE_CHANGE = -2; // 0xfffffffe
+    field @Deprecated public static final int KEYCODE_SHIFT = -1; // 0xffffffff
   }
 
-  public static class Keyboard.Key {
-    ctor public Keyboard.Key(android.inputmethodservice.Keyboard.Row);
-    ctor public Keyboard.Key(android.content.res.Resources, android.inputmethodservice.Keyboard.Row, int, int, android.content.res.XmlResourceParser);
-    method public int[] getCurrentDrawableState();
-    method public boolean isInside(int, int);
-    method public void onPressed();
-    method public void onReleased(boolean);
-    method public int squaredDistanceFrom(int, int);
-    field public int[] codes;
-    field public int edgeFlags;
-    field public int gap;
-    field public int height;
-    field public android.graphics.drawable.Drawable icon;
-    field public android.graphics.drawable.Drawable iconPreview;
-    field public java.lang.CharSequence label;
-    field public boolean modifier;
-    field public boolean on;
-    field public java.lang.CharSequence popupCharacters;
-    field public int popupResId;
-    field public boolean pressed;
-    field public boolean repeatable;
-    field public boolean sticky;
-    field public java.lang.CharSequence text;
-    field public int width;
-    field public int x;
-    field public int y;
+  @Deprecated public static class Keyboard.Key {
+    ctor @Deprecated public Keyboard.Key(android.inputmethodservice.Keyboard.Row);
+    ctor @Deprecated public Keyboard.Key(android.content.res.Resources, android.inputmethodservice.Keyboard.Row, int, int, android.content.res.XmlResourceParser);
+    method @Deprecated public int[] getCurrentDrawableState();
+    method @Deprecated public boolean isInside(int, int);
+    method @Deprecated public void onPressed();
+    method @Deprecated public void onReleased(boolean);
+    method @Deprecated public int squaredDistanceFrom(int, int);
+    field @Deprecated public int[] codes;
+    field @Deprecated public int edgeFlags;
+    field @Deprecated public int gap;
+    field @Deprecated public int height;
+    field @Deprecated public android.graphics.drawable.Drawable icon;
+    field @Deprecated public android.graphics.drawable.Drawable iconPreview;
+    field @Deprecated public CharSequence label;
+    field @Deprecated public boolean modifier;
+    field @Deprecated public boolean on;
+    field @Deprecated public CharSequence popupCharacters;
+    field @Deprecated public int popupResId;
+    field @Deprecated public boolean pressed;
+    field @Deprecated public boolean repeatable;
+    field @Deprecated public boolean sticky;
+    field @Deprecated public CharSequence text;
+    field @Deprecated public int width;
+    field @Deprecated public int x;
+    field @Deprecated public int y;
   }
 
-  public static class Keyboard.Row {
-    ctor public Keyboard.Row(android.inputmethodservice.Keyboard);
-    ctor public Keyboard.Row(android.content.res.Resources, android.inputmethodservice.Keyboard, android.content.res.XmlResourceParser);
-    field public int defaultHeight;
-    field public int defaultHorizontalGap;
-    field public int defaultWidth;
-    field public int mode;
-    field public int rowEdgeFlags;
-    field public int verticalGap;
+  @Deprecated public static class Keyboard.Row {
+    ctor @Deprecated public Keyboard.Row(android.inputmethodservice.Keyboard);
+    ctor @Deprecated public Keyboard.Row(android.content.res.Resources, android.inputmethodservice.Keyboard, android.content.res.XmlResourceParser);
+    field @Deprecated public int defaultHeight;
+    field @Deprecated public int defaultHorizontalGap;
+    field @Deprecated public int defaultWidth;
+    field @Deprecated public int mode;
+    field @Deprecated public int rowEdgeFlags;
+    field @Deprecated public int verticalGap;
   }
 
-  public deprecated class KeyboardView extends android.view.View implements android.view.View.OnClickListener {
-    ctor public KeyboardView(android.content.Context, android.util.AttributeSet);
-    ctor public KeyboardView(android.content.Context, android.util.AttributeSet, int);
-    ctor public KeyboardView(android.content.Context, android.util.AttributeSet, int, int);
-    method public void closing();
-    method public android.inputmethodservice.Keyboard getKeyboard();
-    method protected android.inputmethodservice.KeyboardView.OnKeyboardActionListener getOnKeyboardActionListener();
-    method public boolean handleBack();
-    method public void invalidateAllKeys();
-    method public void invalidateKey(int);
-    method public boolean isPreviewEnabled();
-    method public boolean isProximityCorrectionEnabled();
-    method public boolean isShifted();
+  @Deprecated public class KeyboardView extends android.view.View implements android.view.View.OnClickListener {
+    ctor @Deprecated public KeyboardView(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public KeyboardView(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public KeyboardView(android.content.Context, android.util.AttributeSet, int, int);
+    method @Deprecated public void closing();
+    method @Deprecated public android.inputmethodservice.Keyboard getKeyboard();
+    method @Deprecated protected android.inputmethodservice.KeyboardView.OnKeyboardActionListener getOnKeyboardActionListener();
+    method @Deprecated public boolean handleBack();
+    method @Deprecated public void invalidateAllKeys();
+    method @Deprecated public void invalidateKey(int);
+    method @Deprecated public boolean isPreviewEnabled();
+    method @Deprecated public boolean isProximityCorrectionEnabled();
+    method @Deprecated public boolean isShifted();
     method public void onClick(android.view.View);
-    method public void onDetachedFromWindow();
-    method public void onDraw(android.graphics.Canvas);
-    method protected boolean onLongPress(android.inputmethodservice.Keyboard.Key);
-    method public void onMeasure(int, int);
-    method public void onSizeChanged(int, int, int, int);
-    method public void setKeyboard(android.inputmethodservice.Keyboard);
-    method public void setOnKeyboardActionListener(android.inputmethodservice.KeyboardView.OnKeyboardActionListener);
-    method public void setPopupOffset(int, int);
-    method public void setPopupParent(android.view.View);
-    method public void setPreviewEnabled(boolean);
-    method public void setProximityCorrectionEnabled(boolean);
-    method public boolean setShifted(boolean);
-    method public void setVerticalCorrection(int);
-    method protected void swipeDown();
-    method protected void swipeLeft();
-    method protected void swipeRight();
-    method protected void swipeUp();
+    method @Deprecated public void onDetachedFromWindow();
+    method @Deprecated public void onDraw(android.graphics.Canvas);
+    method @Deprecated protected boolean onLongPress(android.inputmethodservice.Keyboard.Key);
+    method @Deprecated public void onMeasure(int, int);
+    method @Deprecated public void onSizeChanged(int, int, int, int);
+    method @Deprecated public void setKeyboard(android.inputmethodservice.Keyboard);
+    method @Deprecated public void setOnKeyboardActionListener(android.inputmethodservice.KeyboardView.OnKeyboardActionListener);
+    method @Deprecated public void setPopupOffset(int, int);
+    method @Deprecated public void setPopupParent(android.view.View);
+    method @Deprecated public void setPreviewEnabled(boolean);
+    method @Deprecated public void setProximityCorrectionEnabled(boolean);
+    method @Deprecated public boolean setShifted(boolean);
+    method @Deprecated public void setVerticalCorrection(int);
+    method @Deprecated protected void swipeDown();
+    method @Deprecated protected void swipeLeft();
+    method @Deprecated protected void swipeRight();
+    method @Deprecated protected void swipeUp();
   }
 
-  public static abstract interface KeyboardView.OnKeyboardActionListener {
-    method public abstract void onKey(int, int[]);
-    method public abstract void onPress(int);
-    method public abstract void onRelease(int);
-    method public abstract void onText(java.lang.CharSequence);
-    method public abstract void swipeDown();
-    method public abstract void swipeLeft();
-    method public abstract void swipeRight();
-    method public abstract void swipeUp();
+  @Deprecated public static interface KeyboardView.OnKeyboardActionListener {
+    method @Deprecated public void onKey(int, int[]);
+    method @Deprecated public void onPress(int);
+    method @Deprecated public void onRelease(int);
+    method @Deprecated public void onText(CharSequence);
+    method @Deprecated public void swipeDown();
+    method @Deprecated public void swipeLeft();
+    method @Deprecated public void swipeRight();
+    method @Deprecated public void swipeUp();
   }
 
 }
@@ -22531,44 +22460,44 @@
     method public void clearLatitude();
     method public void clearLongitude();
     method public int describeContents();
-    method public java.lang.String getAddressLine(int);
-    method public java.lang.String getAdminArea();
-    method public java.lang.String getCountryCode();
-    method public java.lang.String getCountryName();
+    method public String getAddressLine(int);
+    method public String getAdminArea();
+    method public String getCountryCode();
+    method public String getCountryName();
     method public android.os.Bundle getExtras();
-    method public java.lang.String getFeatureName();
+    method public String getFeatureName();
     method public double getLatitude();
     method public java.util.Locale getLocale();
-    method public java.lang.String getLocality();
+    method public String getLocality();
     method public double getLongitude();
     method public int getMaxAddressLineIndex();
-    method public java.lang.String getPhone();
-    method public java.lang.String getPostalCode();
-    method public java.lang.String getPremises();
-    method public java.lang.String getSubAdminArea();
-    method public java.lang.String getSubLocality();
-    method public java.lang.String getSubThoroughfare();
-    method public java.lang.String getThoroughfare();
-    method public java.lang.String getUrl();
+    method public String getPhone();
+    method public String getPostalCode();
+    method public String getPremises();
+    method public String getSubAdminArea();
+    method public String getSubLocality();
+    method public String getSubThoroughfare();
+    method public String getThoroughfare();
+    method public String getUrl();
     method public boolean hasLatitude();
     method public boolean hasLongitude();
-    method public void setAddressLine(int, java.lang.String);
-    method public void setAdminArea(java.lang.String);
-    method public void setCountryCode(java.lang.String);
-    method public void setCountryName(java.lang.String);
+    method public void setAddressLine(int, String);
+    method public void setAdminArea(String);
+    method public void setCountryCode(String);
+    method public void setCountryName(String);
     method public void setExtras(android.os.Bundle);
-    method public void setFeatureName(java.lang.String);
+    method public void setFeatureName(String);
     method public void setLatitude(double);
-    method public void setLocality(java.lang.String);
+    method public void setLocality(String);
     method public void setLongitude(double);
-    method public void setPhone(java.lang.String);
-    method public void setPostalCode(java.lang.String);
-    method public void setPremises(java.lang.String);
-    method public void setSubAdminArea(java.lang.String);
-    method public void setSubLocality(java.lang.String);
-    method public void setSubThoroughfare(java.lang.String);
-    method public void setThoroughfare(java.lang.String);
-    method public void setUrl(java.lang.String);
+    method public void setPhone(String);
+    method public void setPostalCode(String);
+    method public void setPremises(String);
+    method public void setSubAdminArea(String);
+    method public void setSubLocality(String);
+    method public void setSubThoroughfare(String);
+    method public void setThoroughfare(String);
+    method public void setUrl(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.Address> CREATOR;
   }
@@ -22614,8 +22543,8 @@
     ctor public Geocoder(android.content.Context, java.util.Locale);
     ctor public Geocoder(android.content.Context);
     method public java.util.List<android.location.Address> getFromLocation(double, double, int) throws java.io.IOException;
-    method public java.util.List<android.location.Address> getFromLocationName(java.lang.String, int) throws java.io.IOException;
-    method public java.util.List<android.location.Address> getFromLocationName(java.lang.String, int, double, double, double, double) throws java.io.IOException;
+    method public java.util.List<android.location.Address> getFromLocationName(String, int) throws java.io.IOException;
+    method public java.util.List<android.location.Address> getFromLocationName(String, int, double, double, double, double) throws java.io.IOException;
     method public static boolean isPresent();
   }
 
@@ -22647,11 +22576,12 @@
     method public int getAccumulatedDeltaRangeState();
     method public double getAccumulatedDeltaRangeUncertaintyMeters();
     method public double getAutomaticGainControlLevelDb();
-    method public deprecated long getCarrierCycles();
+    method @Deprecated public long getCarrierCycles();
     method public float getCarrierFrequencyHz();
-    method public deprecated double getCarrierPhase();
-    method public deprecated double getCarrierPhaseUncertainty();
+    method @Deprecated public double getCarrierPhase();
+    method @Deprecated public double getCarrierPhaseUncertainty();
     method public double getCn0DbHz();
+    method public int getCodeType();
     method public int getConstellationType();
     method public int getMultipathIndicator();
     method public double getPseudorangeRateMetersPerSecond();
@@ -22663,10 +22593,11 @@
     method public int getSvid();
     method public double getTimeOffsetNanos();
     method public boolean hasAutomaticGainControlLevelDb();
-    method public deprecated boolean hasCarrierCycles();
+    method @Deprecated public boolean hasCarrierCycles();
     method public boolean hasCarrierFrequencyHz();
-    method public deprecated boolean hasCarrierPhase();
-    method public deprecated boolean hasCarrierPhaseUncertainty();
+    method @Deprecated public boolean hasCarrierPhase();
+    method @Deprecated public boolean hasCarrierPhaseUncertainty();
+    method public boolean hasCodeType();
     method public boolean hasSnrInDb();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
@@ -22675,6 +22606,21 @@
     field public static final int ADR_STATE_RESET = 2; // 0x2
     field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
     field public static final int ADR_STATE_VALID = 1; // 0x1
+    field public static final int CODE_TYPE_A = 0; // 0x0
+    field public static final int CODE_TYPE_B = 1; // 0x1
+    field public static final int CODE_TYPE_C = 2; // 0x2
+    field public static final int CODE_TYPE_CODELESS = 13; // 0xd
+    field public static final int CODE_TYPE_I = 3; // 0x3
+    field public static final int CODE_TYPE_L = 4; // 0x4
+    field public static final int CODE_TYPE_M = 5; // 0x5
+    field public static final int CODE_TYPE_P = 6; // 0x6
+    field public static final int CODE_TYPE_Q = 7; // 0x7
+    field public static final int CODE_TYPE_S = 8; // 0x8
+    field public static final int CODE_TYPE_UNKNOWN = -1; // 0xffffffff
+    field public static final int CODE_TYPE_W = 9; // 0x9
+    field public static final int CODE_TYPE_X = 10; // 0xa
+    field public static final int CODE_TYPE_Y = 11; // 0xb
+    field public static final int CODE_TYPE_Z = 12; // 0xc
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
     field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
     field public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; // 0x2
@@ -22700,13 +22646,13 @@
 
   public final class GnssMeasurementsEvent implements android.os.Parcelable {
     method public int describeContents();
-    method public android.location.GnssClock getClock();
-    method public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
+    method @NonNull public android.location.GnssClock getClock();
+    method @NonNull public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
   }
 
-  public static abstract class GnssMeasurementsEvent.Callback {
+  public abstract static class GnssMeasurementsEvent.Callback {
     ctor public GnssMeasurementsEvent.Callback();
     method public void onGnssMeasurementsReceived(android.location.GnssMeasurementsEvent);
     method public void onStatusChanged(int);
@@ -22718,7 +22664,7 @@
 
   public final class GnssNavigationMessage implements android.os.Parcelable {
     method public int describeContents();
-    method public byte[] getData();
+    method @NonNull public byte[] getData();
     method public int getMessageId();
     method public int getStatus();
     method public int getSubmessageId();
@@ -22741,7 +22687,7 @@
     field public static final int TYPE_UNKNOWN = 0; // 0x0
   }
 
-  public static abstract class GnssNavigationMessage.Callback {
+  public abstract static class GnssNavigationMessage.Callback {
     ctor public GnssNavigationMessage.Callback();
     method public void onGnssNavigationMessageReceived(android.location.GnssNavigationMessage);
     method public void onStatusChanged(int);
@@ -22771,7 +22717,7 @@
     field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
   }
 
-  public static abstract class GnssStatus.Callback {
+  public abstract static class GnssStatus.Callback {
     ctor public GnssStatus.Callback();
     method public void onFirstFix(int);
     method public void onSatelliteStatusChanged(android.location.GnssStatus);
@@ -22779,44 +22725,44 @@
     method public void onStopped();
   }
 
-  public final deprecated class GpsSatellite {
-    method public float getAzimuth();
-    method public float getElevation();
-    method public int getPrn();
-    method public float getSnr();
-    method public boolean hasAlmanac();
-    method public boolean hasEphemeris();
-    method public boolean usedInFix();
+  @Deprecated public final class GpsSatellite {
+    method @Deprecated public float getAzimuth();
+    method @Deprecated public float getElevation();
+    method @Deprecated public int getPrn();
+    method @Deprecated public float getSnr();
+    method @Deprecated public boolean hasAlmanac();
+    method @Deprecated public boolean hasEphemeris();
+    method @Deprecated public boolean usedInFix();
   }
 
-  public final deprecated class GpsStatus {
-    method public int getMaxSatellites();
-    method public java.lang.Iterable<android.location.GpsSatellite> getSatellites();
-    method public int getTimeToFirstFix();
-    field public static final int GPS_EVENT_FIRST_FIX = 3; // 0x3
-    field public static final int GPS_EVENT_SATELLITE_STATUS = 4; // 0x4
-    field public static final int GPS_EVENT_STARTED = 1; // 0x1
-    field public static final int GPS_EVENT_STOPPED = 2; // 0x2
+  @Deprecated public final class GpsStatus {
+    method @Deprecated public int getMaxSatellites();
+    method @Deprecated public Iterable<android.location.GpsSatellite> getSatellites();
+    method @Deprecated public int getTimeToFirstFix();
+    field @Deprecated public static final int GPS_EVENT_FIRST_FIX = 3; // 0x3
+    field @Deprecated public static final int GPS_EVENT_SATELLITE_STATUS = 4; // 0x4
+    field @Deprecated public static final int GPS_EVENT_STARTED = 1; // 0x1
+    field @Deprecated public static final int GPS_EVENT_STOPPED = 2; // 0x2
   }
 
-  public static abstract deprecated interface GpsStatus.Listener {
-    method public abstract void onGpsStatusChanged(int);
+  @Deprecated public static interface GpsStatus.Listener {
+    method @Deprecated public void onGpsStatusChanged(int);
   }
 
-  public static abstract deprecated interface GpsStatus.NmeaListener {
-    method public abstract void onNmeaReceived(long, java.lang.String);
+  @Deprecated public static interface GpsStatus.NmeaListener {
+    method @Deprecated public void onNmeaReceived(long, String);
   }
 
   public class Location implements android.os.Parcelable {
-    ctor public Location(java.lang.String);
+    ctor public Location(String);
     ctor public Location(android.location.Location);
     method public float bearingTo(android.location.Location);
-    method public static java.lang.String convert(double, int);
-    method public static double convert(java.lang.String);
+    method public static String convert(double, int);
+    method public static double convert(String);
     method public int describeContents();
     method public static void distanceBetween(double, double, double, double, float[]);
     method public float distanceTo(android.location.Location);
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(android.util.Printer, String);
     method public float getAccuracy();
     method public double getAltitude();
     method public float getBearing();
@@ -22825,7 +22771,7 @@
     method public android.os.Bundle getExtras();
     method public double getLatitude();
     method public double getLongitude();
-    method public java.lang.String getProvider();
+    method public String getProvider();
     method public float getSpeed();
     method public float getSpeedAccuracyMetersPerSecond();
     method public long getTime();
@@ -22838,10 +22784,10 @@
     method public boolean hasSpeedAccuracy();
     method public boolean hasVerticalAccuracy();
     method public boolean isFromMockProvider();
-    method public deprecated void removeAccuracy();
-    method public deprecated void removeAltitude();
-    method public deprecated void removeBearing();
-    method public deprecated void removeSpeed();
+    method @Deprecated public void removeAccuracy();
+    method @Deprecated public void removeAltitude();
+    method @Deprecated public void removeBearing();
+    method @Deprecated public void removeSpeed();
     method public void reset();
     method public void set(android.location.Location);
     method public void setAccuracy(float);
@@ -22852,7 +22798,7 @@
     method public void setExtras(android.os.Bundle);
     method public void setLatitude(double);
     method public void setLongitude(double);
-    method public void setProvider(java.lang.String);
+    method public void setProvider(String);
     method public void setSpeed(float);
     method public void setSpeedAccuracyMetersPerSecond(float);
     method public void setTime(long);
@@ -22864,77 +22810,77 @@
     field public static final int FORMAT_SECONDS = 2; // 0x2
   }
 
-  public abstract interface LocationListener {
-    method public abstract void onLocationChanged(android.location.Location);
-    method public abstract void onProviderDisabled(java.lang.String);
-    method public abstract void onProviderEnabled(java.lang.String);
-    method public abstract deprecated void onStatusChanged(java.lang.String, int, android.os.Bundle);
+  public interface LocationListener {
+    method public void onLocationChanged(android.location.Location);
+    method public void onProviderDisabled(String);
+    method public void onProviderEnabled(String);
+    method @Deprecated public void onStatusChanged(String, int, android.os.Bundle);
   }
 
   public class LocationManager {
-    method public deprecated boolean addGpsStatusListener(android.location.GpsStatus.Listener);
-    method public deprecated boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
-    method public boolean addNmeaListener(android.location.OnNmeaMessageListener);
-    method public boolean addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler);
-    method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
-    method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
-    method public deprecated void clearTestProviderEnabled(java.lang.String);
-    method public deprecated void clearTestProviderLocation(java.lang.String);
-    method public deprecated void clearTestProviderStatus(java.lang.String);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(android.location.OnNmeaMessageListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
+    method public void addTestProvider(String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
+    method @Deprecated public void clearTestProviderEnabled(String);
+    method @Deprecated public void clearTestProviderLocation(String);
+    method @Deprecated public void clearTestProviderStatus(String);
     method public java.util.List<java.lang.String> getAllProviders();
-    method public java.lang.String getBestProvider(android.location.Criteria, boolean);
-    method public java.lang.String getGnssHardwareModelName();
+    method public String getBestProvider(android.location.Criteria, boolean);
+    method @Nullable public String getGnssHardwareModelName();
     method public int getGnssYearOfHardware();
-    method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
-    method public android.location.Location getLastKnownLocation(java.lang.String);
-    method public android.location.LocationProvider getProvider(java.lang.String);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(String);
+    method public android.location.LocationProvider getProvider(String);
     method public java.util.List<java.lang.String> getProviders(boolean);
     method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
     method public boolean isLocationEnabled();
-    method public boolean isProviderEnabled(java.lang.String);
-    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
-    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+    method public boolean isProviderEnabled(String);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback);
-    method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback, android.os.Handler);
-    method public boolean registerGnssStatusCallback(android.location.GnssStatus.Callback);
-    method public boolean registerGnssStatusCallback(android.location.GnssStatus.Callback, android.os.Handler);
-    method public deprecated void removeGpsStatusListener(android.location.GpsStatus.Listener);
-    method public deprecated void removeNmeaListener(android.location.GpsStatus.NmeaListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback, android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(android.location.GnssStatus.Callback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(android.location.GnssStatus.Callback, android.os.Handler);
+    method @Deprecated public void removeGpsStatusListener(android.location.GpsStatus.Listener);
+    method @Deprecated public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
     method public void removeNmeaListener(android.location.OnNmeaMessageListener);
-    method public void removeProximityAlert(android.app.PendingIntent);
-    method public void removeTestProvider(java.lang.String);
-    method public void removeUpdates(android.location.LocationListener);
+    method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeProximityAlert(android.app.PendingIntent);
+    method public void removeTestProvider(String);
+    method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeUpdates(android.location.LocationListener);
     method public void removeUpdates(android.app.PendingIntent);
-    method public void requestLocationUpdates(java.lang.String, long, float, android.location.LocationListener);
-    method public void requestLocationUpdates(java.lang.String, long, float, android.location.LocationListener, android.os.Looper);
-    method public void requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper);
-    method public void requestLocationUpdates(java.lang.String, long, float, android.app.PendingIntent);
-    method public void requestLocationUpdates(long, float, android.location.Criteria, android.app.PendingIntent);
-    method public void requestSingleUpdate(java.lang.String, android.location.LocationListener, android.os.Looper);
-    method public void requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper);
-    method public void requestSingleUpdate(java.lang.String, android.app.PendingIntent);
-    method public void requestSingleUpdate(android.location.Criteria, android.app.PendingIntent);
-    method public boolean sendExtraCommand(java.lang.String, java.lang.String, android.os.Bundle);
-    method public void setTestProviderEnabled(java.lang.String, boolean);
-    method public void setTestProviderLocation(java.lang.String, android.location.Location);
-    method public deprecated void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(String, long, float, android.location.LocationListener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(String, long, float, android.app.PendingIntent);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, android.location.Criteria, android.app.PendingIntent);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(String, android.location.LocationListener, android.os.Looper);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(String, android.app.PendingIntent);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(android.location.Criteria, android.app.PendingIntent);
+    method public boolean sendExtraCommand(String, String, android.os.Bundle);
+    method public void setTestProviderEnabled(String, boolean);
+    method public void setTestProviderLocation(String, android.location.Location);
+    method @Deprecated public void setTestProviderStatus(String, int, android.os.Bundle, long);
     method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
     method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback);
     method public void unregisterGnssStatusCallback(android.location.GnssStatus.Callback);
-    field public static final java.lang.String GPS_PROVIDER = "gps";
-    field public static final java.lang.String KEY_LOCATION_CHANGED = "location";
-    field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
-    field public static final java.lang.String KEY_PROXIMITY_ENTERING = "entering";
-    field public static final deprecated java.lang.String KEY_STATUS_CHANGED = "status";
-    field public static final java.lang.String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
-    field public static final java.lang.String NETWORK_PROVIDER = "network";
-    field public static final java.lang.String PASSIVE_PROVIDER = "passive";
-    field public static final java.lang.String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
+    field public static final String GPS_PROVIDER = "gps";
+    field public static final String KEY_LOCATION_CHANGED = "location";
+    field public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
+    field public static final String KEY_PROXIMITY_ENTERING = "entering";
+    field @Deprecated public static final String KEY_STATUS_CHANGED = "status";
+    field public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
+    field public static final String NETWORK_PROVIDER = "network";
+    field public static final String PASSIVE_PROVIDER = "passive";
+    field public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
   }
 
   public class LocationProvider {
     method public int getAccuracy();
-    method public java.lang.String getName();
+    method public String getName();
     method public int getPowerRequirement();
     method public boolean hasMonetaryCost();
     method public boolean meetsCriteria(android.location.Criteria);
@@ -22944,27 +22890,27 @@
     method public boolean supportsAltitude();
     method public boolean supportsBearing();
     method public boolean supportsSpeed();
-    field public static final deprecated int AVAILABLE = 2; // 0x2
-    field public static final deprecated int OUT_OF_SERVICE = 0; // 0x0
-    field public static final deprecated int TEMPORARILY_UNAVAILABLE = 1; // 0x1
+    field @Deprecated public static final int AVAILABLE = 2; // 0x2
+    field @Deprecated public static final int OUT_OF_SERVICE = 0; // 0x0
+    field @Deprecated public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
   }
 
-  public abstract interface OnNmeaMessageListener {
-    method public abstract void onNmeaMessage(java.lang.String, long);
+  public interface OnNmeaMessageListener {
+    method public void onNmeaMessage(String, long);
   }
 
   public abstract class SettingInjectorService extends android.app.Service {
-    ctor public SettingInjectorService(java.lang.String);
+    ctor public SettingInjectorService(String);
     method public final android.os.IBinder onBind(android.content.Intent);
     method protected abstract boolean onGetEnabled();
-    method protected abstract java.lang.String onGetSummary();
+    method protected abstract String onGetSummary();
     method public final void onStart(android.content.Intent, int);
     method public final int onStartCommand(android.content.Intent, int, int);
     method public static final void refreshSettings(android.content.Context);
-    field public static final java.lang.String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged";
-    field public static final java.lang.String ACTION_SERVICE_INTENT = "android.location.SettingInjectorService";
-    field public static final java.lang.String ATTRIBUTES_NAME = "injected-location-setting";
-    field public static final java.lang.String META_DATA_NAME = "android.location.SettingInjectorService";
+    field public static final String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged";
+    field public static final String ACTION_SERVICE_INTENT = "android.location.SettingInjectorService";
+    field public static final String ATTRIBUTES_NAME = "injected-location-setting";
+    field public static final String META_DATA_NAME = "android.location.SettingInjectorService";
   }
 
 }
@@ -22972,9 +22918,9 @@
 package android.media {
 
   public class AsyncPlayer {
-    ctor public AsyncPlayer(java.lang.String);
-    method public deprecated void play(android.content.Context, android.net.Uri, boolean, int);
-    method public void play(android.content.Context, android.net.Uri, boolean, android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
+    ctor public AsyncPlayer(String);
+    method @Deprecated public void play(android.content.Context, android.net.Uri, boolean, int);
+    method public void play(@NonNull android.content.Context, @NonNull android.net.Uri, boolean, @NonNull android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
     method public void stop();
   }
 
@@ -22993,7 +22939,7 @@
     field public static final android.os.Parcelable.Creator<android.media.AudioAttributes> CREATOR;
     field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
     field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
-    field public static final deprecated int FLAG_LOW_LATENCY = 256; // 0x100
+    field @Deprecated public static final int FLAG_LOW_LATENCY = 256; // 0x100
     field public static final int USAGE_ALARM = 4; // 0x4
     field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
     field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
@@ -23029,14 +22975,14 @@
   }
 
   public final class AudioDeviceInfo {
-    method public java.lang.String getAddress();
-    method public int[] getChannelCounts();
-    method public int[] getChannelIndexMasks();
-    method public int[] getChannelMasks();
-    method public int[] getEncodings();
+    method @NonNull public String getAddress();
+    method @NonNull public int[] getChannelCounts();
+    method @NonNull public int[] getChannelIndexMasks();
+    method @NonNull public int[] getChannelMasks();
+    method @NonNull public int[] getEncodings();
     method public int getId();
-    method public java.lang.CharSequence getProductName();
-    method public int[] getSampleRates();
+    method public CharSequence getProductName();
+    method @NonNull public int[] getSampleRates();
     method public int getType();
     method public boolean isSink();
     method public boolean isSource();
@@ -23068,22 +23014,22 @@
 
   public final class AudioFocusRequest {
     method public boolean acceptsDelayedFocusGain();
-    method public android.media.AudioAttributes getAudioAttributes();
+    method @NonNull public android.media.AudioAttributes getAudioAttributes();
     method public int getFocusGain();
     method public boolean willPauseWhenDucked();
   }
 
   public static final class AudioFocusRequest.Builder {
     ctor public AudioFocusRequest.Builder(int);
-    ctor public AudioFocusRequest.Builder(android.media.AudioFocusRequest);
+    ctor public AudioFocusRequest.Builder(@NonNull android.media.AudioFocusRequest);
     method public android.media.AudioFocusRequest build();
-    method public android.media.AudioFocusRequest.Builder setAcceptsDelayedFocusGain(boolean);
-    method public android.media.AudioFocusRequest.Builder setAudioAttributes(android.media.AudioAttributes);
-    method public android.media.AudioFocusRequest.Builder setFocusGain(int);
-    method public android.media.AudioFocusRequest.Builder setForceDucking(boolean);
-    method public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener);
-    method public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler);
-    method public android.media.AudioFocusRequest.Builder setWillPauseWhenDucked(boolean);
+    method @NonNull public android.media.AudioFocusRequest.Builder setAcceptsDelayedFocusGain(boolean);
+    method @NonNull public android.media.AudioFocusRequest.Builder setAudioAttributes(@NonNull android.media.AudioAttributes);
+    method @NonNull public android.media.AudioFocusRequest.Builder setFocusGain(int);
+    method @NonNull public android.media.AudioFocusRequest.Builder setForceDucking(boolean);
+    method @NonNull public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(@NonNull android.media.AudioManager.OnAudioFocusChangeListener);
+    method @NonNull public android.media.AudioFocusRequest.Builder setOnAudioFocusChangeListener(@NonNull android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.os.Handler);
+    method @NonNull public android.media.AudioFocusRequest.Builder setWillPauseWhenDucked(boolean);
   }
 
   public final class AudioFormat implements android.os.Parcelable {
@@ -23092,13 +23038,13 @@
     method public int getChannelIndexMask();
     method public int getChannelMask();
     method public int getEncoding();
-    method public int getFrameSizeInBytes();
+    method @IntRange(from=1) public int getFrameSizeInBytes();
     method public int getSampleRate();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
-    field public static final deprecated int CHANNEL_CONFIGURATION_INVALID = 0; // 0x0
-    field public static final deprecated int CHANNEL_CONFIGURATION_MONO = 2; // 0x2
-    field public static final deprecated int CHANNEL_CONFIGURATION_STEREO = 3; // 0x3
+    field @Deprecated public static final int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
+    field @Deprecated public static final int CHANNEL_CONFIGURATION_INVALID = 0; // 0x0
+    field @Deprecated public static final int CHANNEL_CONFIGURATION_MONO = 2; // 0x2
+    field @Deprecated public static final int CHANNEL_CONFIGURATION_STEREO = 3; // 0x3
     field public static final int CHANNEL_INVALID = 0; // 0x0
     field public static final int CHANNEL_IN_BACK = 32; // 0x20
     field public static final int CHANNEL_IN_BACK_PROCESSED = 512; // 0x200
@@ -23118,7 +23064,7 @@
     field public static final int CHANNEL_IN_Y_AXIS = 4096; // 0x1000
     field public static final int CHANNEL_IN_Z_AXIS = 8192; // 0x2000
     field public static final int CHANNEL_OUT_5POINT1 = 252; // 0xfc
-    field public static final deprecated int CHANNEL_OUT_7POINT1 = 1020; // 0x3fc
+    field @Deprecated public static final int CHANNEL_OUT_7POINT1 = 1020; // 0x3fc
     field public static final int CHANNEL_OUT_7POINT1_SURROUND = 6396; // 0x18fc
     field public static final int CHANNEL_OUT_BACK_CENTER = 1024; // 0x400
     field public static final int CHANNEL_OUT_BACK_LEFT = 64; // 0x40
@@ -23164,87 +23110,87 @@
     ctor public AudioFormat.Builder();
     ctor public AudioFormat.Builder(android.media.AudioFormat);
     method public android.media.AudioFormat build();
-    method public android.media.AudioFormat.Builder setChannelIndexMask(int);
-    method public android.media.AudioFormat.Builder setChannelMask(int);
+    method @NonNull public android.media.AudioFormat.Builder setChannelIndexMask(int);
+    method @NonNull public android.media.AudioFormat.Builder setChannelMask(int);
     method public android.media.AudioFormat.Builder setEncoding(int) throws java.lang.IllegalArgumentException;
     method public android.media.AudioFormat.Builder setSampleRate(int) throws java.lang.IllegalArgumentException;
   }
 
   public class AudioManager {
-    method public deprecated int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener);
-    method public int abandonAudioFocusRequest(android.media.AudioFocusRequest);
+    method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener);
+    method public int abandonAudioFocusRequest(@NonNull android.media.AudioFocusRequest);
     method public void adjustStreamVolume(int, int, int);
     method public void adjustSuggestedStreamVolume(int, int, int);
     method public void adjustVolume(int, int);
     method public void dispatchMediaKeyEvent(android.view.KeyEvent);
     method public int generateAudioSessionId();
-    method public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations();
-    method public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations();
+    method @NonNull public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations();
+    method @NonNull public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations();
     method public android.media.AudioDeviceInfo[] getDevices(int);
     method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException;
     method public int getMode();
-    method public java.lang.String getParameters(java.lang.String);
-    method public java.lang.String getProperty(java.lang.String);
+    method public String getParameters(String);
+    method public String getProperty(String);
     method public int getRingerMode();
-    method public deprecated int getRouting(int);
+    method @Deprecated public int getRouting(int);
     method public int getStreamMaxVolume(int);
     method public int getStreamMinVolume(int);
     method public int getStreamVolume(int);
     method public float getStreamVolumeDb(int, int, int);
-    method public deprecated int getVibrateSetting(int);
-    method public deprecated boolean isBluetoothA2dpOn();
+    method @Deprecated public int getVibrateSetting(int);
+    method @Deprecated public boolean isBluetoothA2dpOn();
     method public boolean isBluetoothScoAvailableOffCall();
     method public boolean isBluetoothScoOn();
     method public static boolean isHapticPlaybackSupported();
     method public boolean isMicrophoneMute();
     method public boolean isMusicActive();
-    method public static boolean isOffloadedPlaybackSupported(android.media.AudioFormat);
+    method public static boolean isOffloadedPlaybackSupported(@NonNull android.media.AudioFormat);
     method public boolean isSpeakerphoneOn();
     method public boolean isStreamMute(int);
     method public boolean isVolumeFixed();
-    method public deprecated boolean isWiredHeadsetOn();
+    method @Deprecated public boolean isWiredHeadsetOn();
     method public void loadSoundEffects();
     method public void playSoundEffect(int);
     method public void playSoundEffect(int, float);
     method public void registerAudioDeviceCallback(android.media.AudioDeviceCallback, android.os.Handler);
-    method public void registerAudioPlaybackCallback(android.media.AudioManager.AudioPlaybackCallback, android.os.Handler);
-    method public void registerAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback, android.os.Handler);
-    method public deprecated void registerMediaButtonEventReceiver(android.content.ComponentName);
-    method public deprecated void registerMediaButtonEventReceiver(android.app.PendingIntent);
-    method public deprecated void registerRemoteControlClient(android.media.RemoteControlClient);
-    method public deprecated boolean registerRemoteController(android.media.RemoteController);
-    method public deprecated int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
-    method public int requestAudioFocus(android.media.AudioFocusRequest);
-    method public deprecated void setBluetoothA2dpOn(boolean);
+    method public void registerAudioPlaybackCallback(@NonNull android.media.AudioManager.AudioPlaybackCallback, android.os.Handler);
+    method public void registerAudioRecordingCallback(@NonNull android.media.AudioManager.AudioRecordingCallback, android.os.Handler);
+    method @Deprecated public void registerMediaButtonEventReceiver(android.content.ComponentName);
+    method @Deprecated public void registerMediaButtonEventReceiver(android.app.PendingIntent);
+    method @Deprecated public void registerRemoteControlClient(android.media.RemoteControlClient);
+    method @Deprecated public boolean registerRemoteController(android.media.RemoteController);
+    method @Deprecated public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
+    method public int requestAudioFocus(@NonNull android.media.AudioFocusRequest);
+    method @Deprecated public void setBluetoothA2dpOn(boolean);
     method public void setBluetoothScoOn(boolean);
     method public void setMicrophoneMute(boolean);
     method public void setMode(int);
-    method public void setParameters(java.lang.String);
+    method public void setParameters(String);
     method public void setRingerMode(int);
-    method public deprecated void setRouting(int, int, int);
+    method @Deprecated public void setRouting(int, int, int);
     method public void setSpeakerphoneOn(boolean);
-    method public deprecated void setStreamMute(int, boolean);
-    method public deprecated void setStreamSolo(int, boolean);
+    method @Deprecated public void setStreamMute(int, boolean);
+    method @Deprecated public void setStreamSolo(int, boolean);
     method public void setStreamVolume(int, int, int);
-    method public deprecated void setVibrateSetting(int, int);
-    method public deprecated void setWiredHeadsetOn(boolean);
-    method public deprecated boolean shouldVibrate(int);
+    method @Deprecated public void setVibrateSetting(int, int);
+    method @Deprecated public void setWiredHeadsetOn(boolean);
+    method @Deprecated public boolean shouldVibrate(int);
     method public void startBluetoothSco();
     method public void stopBluetoothSco();
     method public void unloadSoundEffects();
     method public void unregisterAudioDeviceCallback(android.media.AudioDeviceCallback);
-    method public void unregisterAudioPlaybackCallback(android.media.AudioManager.AudioPlaybackCallback);
-    method public void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback);
-    method public deprecated void unregisterMediaButtonEventReceiver(android.content.ComponentName);
-    method public deprecated void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
-    method public deprecated void unregisterRemoteControlClient(android.media.RemoteControlClient);
-    method public deprecated void unregisterRemoteController(android.media.RemoteController);
-    field public static final java.lang.String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
-    field public static final java.lang.String ACTION_HDMI_AUDIO_PLUG = "android.media.action.HDMI_AUDIO_PLUG";
-    field public static final java.lang.String ACTION_HEADSET_PLUG = "android.intent.action.HEADSET_PLUG";
-    field public static final java.lang.String ACTION_MICROPHONE_MUTE_CHANGED = "android.media.action.MICROPHONE_MUTE_CHANGED";
-    field public static final deprecated java.lang.String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
-    field public static final java.lang.String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
+    method public void unregisterAudioPlaybackCallback(@NonNull android.media.AudioManager.AudioPlaybackCallback);
+    method public void unregisterAudioRecordingCallback(@NonNull android.media.AudioManager.AudioRecordingCallback);
+    method @Deprecated public void unregisterMediaButtonEventReceiver(android.content.ComponentName);
+    method @Deprecated public void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
+    method @Deprecated public void unregisterRemoteControlClient(android.media.RemoteControlClient);
+    method @Deprecated public void unregisterRemoteController(android.media.RemoteController);
+    field public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
+    field public static final String ACTION_HDMI_AUDIO_PLUG = "android.media.action.HDMI_AUDIO_PLUG";
+    field public static final String ACTION_HEADSET_PLUG = "android.intent.action.HEADSET_PLUG";
+    field public static final String ACTION_MICROPHONE_MUTE_CHANGED = "android.media.action.MICROPHONE_MUTE_CHANGED";
+    field @Deprecated public static final String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
+    field public static final String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
     field public static final int ADJUST_LOWER = -1; // 0xffffffff
     field public static final int ADJUST_MUTE = -100; // 0xffffff9c
     field public static final int ADJUST_RAISE = 1; // 0x1
@@ -23265,14 +23211,14 @@
     field public static final int AUDIO_SESSION_ID_GENERATE = 0; // 0x0
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa
-    field public static final java.lang.String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
-    field public static final java.lang.String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
-    field public static final java.lang.String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
-    field public static final java.lang.String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
-    field public static final java.lang.String EXTRA_SCO_AUDIO_PREVIOUS_STATE = "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
-    field public static final java.lang.String EXTRA_SCO_AUDIO_STATE = "android.media.extra.SCO_AUDIO_STATE";
-    field public static final deprecated java.lang.String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING";
-    field public static final deprecated java.lang.String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE";
+    field public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
+    field public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
+    field public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
+    field public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
+    field public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE = "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
+    field public static final String EXTRA_SCO_AUDIO_STATE = "android.media.extra.SCO_AUDIO_STATE";
+    field @Deprecated public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING";
+    field @Deprecated public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE";
     field public static final int FLAG_ALLOW_RINGER_MODES = 2; // 0x2
     field public static final int FLAG_PLAY_SOUND = 4; // 0x4
     field public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 8; // 0x8
@@ -23297,23 +23243,23 @@
     field public static final int MODE_IN_COMMUNICATION = 3; // 0x3
     field public static final int MODE_NORMAL = 0; // 0x0
     field public static final int MODE_RINGTONE = 1; // 0x1
-    field public static final deprecated int NUM_STREAMS = 5; // 0x5
-    field public static final java.lang.String PROPERTY_OUTPUT_FRAMES_PER_BUFFER = "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
-    field public static final java.lang.String PROPERTY_OUTPUT_SAMPLE_RATE = "android.media.property.OUTPUT_SAMPLE_RATE";
-    field public static final java.lang.String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED = "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
-    field public static final java.lang.String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
-    field public static final java.lang.String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
-    field public static final java.lang.String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
+    field @Deprecated public static final int NUM_STREAMS = 5; // 0x5
+    field public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER = "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
+    field public static final String PROPERTY_OUTPUT_SAMPLE_RATE = "android.media.property.OUTPUT_SAMPLE_RATE";
+    field public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED = "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
+    field public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
+    field public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
+    field public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
     field public static final int RINGER_MODE_NORMAL = 2; // 0x2
     field public static final int RINGER_MODE_SILENT = 0; // 0x0
     field public static final int RINGER_MODE_VIBRATE = 1; // 0x1
-    field public static final deprecated int ROUTE_ALL = -1; // 0xffffffff
-    field public static final deprecated int ROUTE_BLUETOOTH = 4; // 0x4
-    field public static final deprecated int ROUTE_BLUETOOTH_A2DP = 16; // 0x10
-    field public static final deprecated int ROUTE_BLUETOOTH_SCO = 4; // 0x4
-    field public static final deprecated int ROUTE_EARPIECE = 1; // 0x1
-    field public static final deprecated int ROUTE_HEADSET = 8; // 0x8
-    field public static final deprecated int ROUTE_SPEAKER = 2; // 0x2
+    field @Deprecated public static final int ROUTE_ALL = -1; // 0xffffffff
+    field @Deprecated public static final int ROUTE_BLUETOOTH = 4; // 0x4
+    field @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = 16; // 0x10
+    field @Deprecated public static final int ROUTE_BLUETOOTH_SCO = 4; // 0x4
+    field @Deprecated public static final int ROUTE_EARPIECE = 1; // 0x1
+    field @Deprecated public static final int ROUTE_HEADSET = 8; // 0x8
+    field @Deprecated public static final int ROUTE_SPEAKER = 2; // 0x2
     field public static final int SCO_AUDIO_STATE_CONNECTED = 1; // 0x1
     field public static final int SCO_AUDIO_STATE_CONNECTING = 2; // 0x2
     field public static final int SCO_AUDIO_STATE_DISCONNECTED = 0; // 0x0
@@ -23327,26 +23273,26 @@
     field public static final int STREAM_SYSTEM = 1; // 0x1
     field public static final int STREAM_VOICE_CALL = 0; // 0x0
     field public static final int USE_DEFAULT_STREAM_TYPE = -2147483648; // 0x80000000
-    field public static final deprecated java.lang.String VIBRATE_SETTING_CHANGED_ACTION = "android.media.VIBRATE_SETTING_CHANGED";
-    field public static final deprecated int VIBRATE_SETTING_OFF = 0; // 0x0
-    field public static final deprecated int VIBRATE_SETTING_ON = 1; // 0x1
-    field public static final deprecated int VIBRATE_SETTING_ONLY_SILENT = 2; // 0x2
-    field public static final deprecated int VIBRATE_TYPE_NOTIFICATION = 1; // 0x1
-    field public static final deprecated int VIBRATE_TYPE_RINGER = 0; // 0x0
+    field @Deprecated public static final String VIBRATE_SETTING_CHANGED_ACTION = "android.media.VIBRATE_SETTING_CHANGED";
+    field @Deprecated public static final int VIBRATE_SETTING_OFF = 0; // 0x0
+    field @Deprecated public static final int VIBRATE_SETTING_ON = 1; // 0x1
+    field @Deprecated public static final int VIBRATE_SETTING_ONLY_SILENT = 2; // 0x2
+    field @Deprecated public static final int VIBRATE_TYPE_NOTIFICATION = 1; // 0x1
+    field @Deprecated public static final int VIBRATE_TYPE_RINGER = 0; // 0x0
   }
 
-  public static abstract class AudioManager.AudioPlaybackCallback {
+  public abstract static class AudioManager.AudioPlaybackCallback {
     ctor public AudioManager.AudioPlaybackCallback();
     method public void onPlaybackConfigChanged(java.util.List<android.media.AudioPlaybackConfiguration>);
   }
 
-  public static abstract class AudioManager.AudioRecordingCallback {
+  public abstract static class AudioManager.AudioRecordingCallback {
     ctor public AudioManager.AudioRecordingCallback();
     method public void onRecordingConfigChanged(java.util.List<android.media.AudioRecordingConfiguration>);
   }
 
-  public static abstract interface AudioManager.OnAudioFocusChangeListener {
-    method public abstract void onAudioFocusChange(int);
+  public static interface AudioManager.OnAudioFocusChangeListener {
+    method public void onAudioFocusChange(int);
   }
 
   public final class AudioPlaybackConfiguration implements android.os.Parcelable {
@@ -23357,7 +23303,7 @@
   }
 
   public final class AudioPresentation {
-    method public java.util.Map<java.util.Locale, java.lang.String> getLabels();
+    method public java.util.Map<java.util.Locale,java.lang.String> getLabels();
     method public java.util.Locale getLocale();
     method public int getMasteringIndication();
     method public int getPresentationId();
@@ -23374,30 +23320,30 @@
 
   public static class AudioPresentation.Builder {
     ctor public AudioPresentation.Builder(int);
-    method public android.media.AudioPresentation build();
-    method public android.media.AudioPresentation.Builder setHasAudioDescription(boolean);
-    method public android.media.AudioPresentation.Builder setHasDialogueEnhancement(boolean);
-    method public android.media.AudioPresentation.Builder setHasSpokenSubtitles(boolean);
-    method public android.media.AudioPresentation.Builder setLabels(java.util.Map<android.icu.util.ULocale, java.lang.String>);
-    method public android.media.AudioPresentation.Builder setLocale(android.icu.util.ULocale);
-    method public android.media.AudioPresentation.Builder setMasteringIndication(int);
-    method public android.media.AudioPresentation.Builder setProgramId(int);
+    method @NonNull public android.media.AudioPresentation build();
+    method @NonNull public android.media.AudioPresentation.Builder setHasAudioDescription(boolean);
+    method @NonNull public android.media.AudioPresentation.Builder setHasDialogueEnhancement(boolean);
+    method @NonNull public android.media.AudioPresentation.Builder setHasSpokenSubtitles(boolean);
+    method @NonNull public android.media.AudioPresentation.Builder setLabels(@NonNull java.util.Map<android.icu.util.ULocale,java.lang.String>);
+    method @NonNull public android.media.AudioPresentation.Builder setLocale(android.icu.util.ULocale);
+    method @NonNull public android.media.AudioPresentation.Builder setMasteringIndication(int);
+    method @NonNull public android.media.AudioPresentation.Builder setProgramId(int);
   }
 
   public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting {
     ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
-    method public deprecated void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
+    method @Deprecated public void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
     method protected void finalize();
     method public java.util.List<android.media.MicrophoneInfo> getActiveMicrophones() throws java.io.IOException;
-    method public android.media.AudioRecordingConfiguration getActiveRecordingConfiguration();
+    method @Nullable public android.media.AudioRecordingConfiguration getActiveRecordingConfiguration();
     method public int getAudioFormat();
     method public int getAudioSessionId();
     method public int getAudioSource();
     method public int getBufferSizeInFrames();
     method public int getChannelConfiguration();
     method public int getChannelCount();
-    method public android.media.AudioFormat getFormat();
+    method @NonNull public android.media.AudioFormat getFormat();
     method public android.os.PersistableBundle getMetrics();
     method public static int getMinBufferSize(int, int, int);
     method public int getNotificationMarkerPosition();
@@ -23407,18 +23353,18 @@
     method public android.media.AudioDeviceInfo getRoutedDevice();
     method public int getSampleRate();
     method public int getState();
-    method public int getTimestamp(android.media.AudioTimestamp, int);
-    method public int read(byte[], int, int);
-    method public int read(byte[], int, int, int);
-    method public int read(short[], int, int);
-    method public int read(short[], int, int, int);
-    method public int read(float[], int, int, int);
-    method public int read(java.nio.ByteBuffer, int);
-    method public int read(java.nio.ByteBuffer, int, int);
-    method public void registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback);
+    method public int getTimestamp(@NonNull android.media.AudioTimestamp, int);
+    method public int read(@NonNull byte[], int, int);
+    method public int read(@NonNull byte[], int, int, int);
+    method public int read(@NonNull short[], int, int);
+    method public int read(@NonNull short[], int, int, int);
+    method public int read(@NonNull float[], int, int, int);
+    method public int read(@NonNull java.nio.ByteBuffer, int);
+    method public int read(@NonNull java.nio.ByteBuffer, int, int);
+    method public void registerAudioRecordingCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioRecordingCallback);
     method public void release();
     method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
-    method public deprecated void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
+    method @Deprecated public void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
     method public int setNotificationMarkerPosition(int);
     method public int setPositionNotificationPeriod(int);
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
@@ -23427,7 +23373,7 @@
     method public void startRecording() throws java.lang.IllegalStateException;
     method public void startRecording(android.media.MediaSyncEvent) throws java.lang.IllegalStateException;
     method public void stop() throws java.lang.IllegalStateException;
-    method public void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback);
+    method public void unregisterAudioRecordingCallback(@NonNull android.media.AudioManager.AudioRecordingCallback);
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
     field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa
@@ -23444,27 +23390,27 @@
   public static class AudioRecord.Builder {
     ctor public AudioRecord.Builder();
     method public android.media.AudioRecord build() throws java.lang.UnsupportedOperationException;
-    method public android.media.AudioRecord.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioRecord.Builder setAudioFormat(@NonNull android.media.AudioFormat) throws java.lang.IllegalArgumentException;
     method public android.media.AudioRecord.Builder setAudioSource(int) throws java.lang.IllegalArgumentException;
     method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
   }
 
   public static final class AudioRecord.MetricsConstants {
-    field public static final java.lang.String CHANNELS = "android.media.audiorecord.channels";
-    field public static final java.lang.String ENCODING = "android.media.audiorecord.encoding";
-    field public static final java.lang.String LATENCY = "android.media.audiorecord.latency";
-    field public static final java.lang.String SAMPLERATE = "android.media.audiorecord.samplerate";
-    field public static final java.lang.String SOURCE = "android.media.audiorecord.source";
+    field public static final String CHANNELS = "android.media.audiorecord.channels";
+    field public static final String ENCODING = "android.media.audiorecord.encoding";
+    field public static final String LATENCY = "android.media.audiorecord.latency";
+    field public static final String SAMPLERATE = "android.media.audiorecord.samplerate";
+    field public static final String SOURCE = "android.media.audiorecord.source";
   }
 
-  public static abstract interface AudioRecord.OnRecordPositionUpdateListener {
-    method public abstract void onMarkerReached(android.media.AudioRecord);
-    method public abstract void onPeriodicNotification(android.media.AudioRecord);
+  public static interface AudioRecord.OnRecordPositionUpdateListener {
+    method public void onMarkerReached(android.media.AudioRecord);
+    method public void onPeriodicNotification(android.media.AudioRecord);
   }
 
-  public static abstract deprecated interface AudioRecord.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener {
-    method public abstract void onRoutingChanged(android.media.AudioRecord);
-    method public default void onRoutingChanged(android.media.AudioRouting);
+  @Deprecated public static interface AudioRecord.OnRoutingChangedListener extends android.media.AudioRouting.OnRoutingChangedListener {
+    method @Deprecated public void onRoutingChanged(android.media.AudioRecord);
+    method @Deprecated public default void onRoutingChanged(android.media.AudioRouting);
   }
 
   public final class AudioRecordingConfiguration implements android.os.Parcelable {
@@ -23473,31 +23419,31 @@
     method public int getAudioSource();
     method public int getClientAudioSessionId();
     method public int getClientAudioSource();
-    method public java.util.List<android.media.audiofx.AudioEffect.Descriptor> getClientEffects();
+    method @NonNull public java.util.List<android.media.audiofx.AudioEffect.Descriptor> getClientEffects();
     method public android.media.AudioFormat getClientFormat();
-    method public java.util.List<android.media.audiofx.AudioEffect.Descriptor> getEffects();
+    method @NonNull public java.util.List<android.media.audiofx.AudioEffect.Descriptor> getEffects();
     method public android.media.AudioFormat getFormat();
     method public boolean isClientSilenced();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.media.AudioRecordingConfiguration> CREATOR;
   }
 
-  public abstract interface AudioRecordingMonitor {
-    method public abstract android.media.AudioRecordingConfiguration getActiveRecordingConfiguration();
-    method public abstract void registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback);
-    method public abstract void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback);
+  public interface AudioRecordingMonitor {
+    method @Nullable public android.media.AudioRecordingConfiguration getActiveRecordingConfiguration();
+    method public void registerAudioRecordingCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioRecordingCallback);
+    method public void unregisterAudioRecordingCallback(@NonNull android.media.AudioManager.AudioRecordingCallback);
   }
 
-  public abstract interface AudioRouting {
-    method public abstract void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
-    method public abstract android.media.AudioDeviceInfo getPreferredDevice();
-    method public abstract android.media.AudioDeviceInfo getRoutedDevice();
-    method public abstract void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
-    method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
+  public interface AudioRouting {
+    method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
+    method public android.media.AudioDeviceInfo getPreferredDevice();
+    method public android.media.AudioDeviceInfo getRoutedDevice();
+    method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
+    method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
   }
 
-  public static abstract interface AudioRouting.OnRoutingChangedListener {
-    method public abstract void onRoutingChanged(android.media.AudioRouting);
+  public static interface AudioRouting.OnRoutingChangedListener {
+    method public void onRoutingChanged(android.media.AudioRouting);
   }
 
   public final class AudioTimestamp {
@@ -23509,34 +23455,35 @@
   }
 
   public class AudioTrack implements android.media.AudioRouting android.media.VolumeAutomation {
-    ctor public deprecated AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
-    ctor public deprecated AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
+    ctor @Deprecated public AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
+    ctor @Deprecated public AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
     ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
-    method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
+    method @Deprecated public void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
     method public int attachAuxEffect(int);
-    method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
+    method @NonNull public android.media.VolumeShaper createVolumeShaper(@NonNull android.media.VolumeShaper.Configuration);
+    method public static void deprecateStreamTypeForPlayback(int, String, String) throws java.lang.IllegalArgumentException;
     method protected void finalize();
     method public void flush();
-    method public android.media.AudioAttributes getAudioAttributes();
+    method @NonNull public android.media.AudioAttributes getAudioAttributes();
     method public int getAudioFormat();
     method public int getAudioSessionId();
     method public int getBufferCapacityInFrames();
     method public int getBufferSizeInFrames();
     method public int getChannelConfiguration();
     method public int getChannelCount();
-    method public android.media.AudioFormat getFormat();
+    method @NonNull public android.media.AudioFormat getFormat();
     method public static float getMaxVolume();
     method public android.os.PersistableBundle getMetrics();
     method public static int getMinBufferSize(int, int, int);
     method public static float getMinVolume();
-    method protected deprecated int getNativeFrameCount();
+    method @Deprecated protected int getNativeFrameCount();
     method public static int getNativeOutputSampleRate(int);
     method public int getNotificationMarkerPosition();
     method public int getPerformanceMode();
     method public int getPlayState();
     method public int getPlaybackHeadPosition();
-    method public android.media.PlaybackParams getPlaybackParams();
+    method @NonNull public android.media.PlaybackParams getPlaybackParams();
     method public int getPlaybackRate();
     method public int getPositionNotificationPeriod();
     method public android.media.AudioDeviceInfo getPreferredDevice();
@@ -23546,38 +23493,38 @@
     method public int getStreamType();
     method public boolean getTimestamp(android.media.AudioTimestamp);
     method public int getUnderrunCount();
-    method public static boolean isDirectPlaybackSupported(android.media.AudioFormat, android.media.AudioAttributes);
+    method public static boolean isDirectPlaybackSupported(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
     method public void pause() throws java.lang.IllegalStateException;
     method public void play() throws java.lang.IllegalStateException;
-    method public void registerStreamEventCallback(java.util.concurrent.Executor, android.media.AudioTrack.StreamEventCallback);
+    method public void registerStreamEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioTrack.StreamEventCallback);
     method public void release();
     method public int reloadStaticData();
     method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
-    method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
+    method @Deprecated public void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
     method public int setAuxEffectSendLevel(float);
     method public int setBufferSizeInFrames(int);
     method public int setLoopPoints(int, int, int);
     method public int setNotificationMarkerPosition(int);
     method public int setPlaybackHeadPosition(int);
-    method public void setPlaybackParams(android.media.PlaybackParams);
+    method public void setPlaybackParams(@NonNull android.media.PlaybackParams);
     method public void setPlaybackPositionUpdateListener(android.media.AudioTrack.OnPlaybackPositionUpdateListener);
     method public void setPlaybackPositionUpdateListener(android.media.AudioTrack.OnPlaybackPositionUpdateListener, android.os.Handler);
     method public int setPlaybackRate(int);
     method public int setPositionNotificationPeriod(int);
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
-    method public int setPresentation(android.media.AudioPresentation);
-    method protected deprecated void setState(int);
-    method public deprecated int setStereoVolume(float, float);
+    method public int setPresentation(@NonNull android.media.AudioPresentation);
+    method @Deprecated protected void setState(int);
+    method @Deprecated public int setStereoVolume(float, float);
     method public int setVolume(float);
     method public void stop() throws java.lang.IllegalStateException;
-    method public void unregisterStreamEventCallback(android.media.AudioTrack.StreamEventCallback);
-    method public int write(byte[], int, int);
-    method public int write(byte[], int, int, int);
-    method public int write(short[], int, int);
-    method public int write(short[], int, int, int);
-    method public int write(float[], int, int, int);
-    method public int write(java.nio.ByteBuffer, int, int);
-    method public int write(java.nio.ByteBuffer, int, int, long);
+    method public void unregisterStreamEventCallback(@NonNull android.media.AudioTrack.StreamEventCallback);
+    method public int write(@NonNull byte[], int, int);
+    method public int write(@NonNull byte[], int, int, int);
+    method public int write(@NonNull short[], int, int);
+    method public int write(@NonNull short[], int, int, int);
+    method public int write(@NonNull float[], int, int, int);
+    method public int write(@NonNull java.nio.ByteBuffer, int, int);
+    method public int write(@NonNull java.nio.ByteBuffer, int, int, long);
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
     field public static final int ERROR_DEAD_OBJECT = -6; // 0xfffffffa
@@ -23600,35 +23547,35 @@
 
   public static class AudioTrack.Builder {
     ctor public AudioTrack.Builder();
-    method public android.media.AudioTrack build() throws java.lang.UnsupportedOperationException;
-    method public android.media.AudioTrack.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
-    method public android.media.AudioTrack.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
-    method public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
-    method public android.media.AudioTrack.Builder setOffloadedPlayback(boolean);
-    method public android.media.AudioTrack.Builder setPerformanceMode(int);
-    method public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
-    method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
+    method @NonNull public android.media.AudioTrack build() throws java.lang.UnsupportedOperationException;
+    method @NonNull public android.media.AudioTrack.Builder setAudioAttributes(@NonNull android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
+    method @NonNull public android.media.AudioTrack.Builder setAudioFormat(@NonNull android.media.AudioFormat) throws java.lang.IllegalArgumentException;
+    method @NonNull public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+    method @NonNull public android.media.AudioTrack.Builder setOffloadedPlayback(boolean);
+    method @NonNull public android.media.AudioTrack.Builder setPerformanceMode(int);
+    method @NonNull public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
+    method @NonNull public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
   }
 
   public static final class AudioTrack.MetricsConstants {
-    field public static final java.lang.String CHANNELMASK = "android.media.audiorecord.channelmask";
-    field public static final java.lang.String CONTENTTYPE = "android.media.audiotrack.type";
-    field public static final java.lang.String SAMPLERATE = "android.media.audiorecord.samplerate";
-    field public static final java.lang.String STREAMTYPE = "android.media.audiotrack.streamtype";
-    field public static final java.lang.String USAGE = "android.media.audiotrack.usage";
+    field public static final String CHANNELMASK = "android.media.audiorecord.channelmask";
+    field public static final String CONTENTTYPE = "android.media.audiotrack.type";
+    field public static final String SAMPLERATE = "android.media.audiorecord.samplerate";
+    field public static final String STREAMTYPE = "android.media.audiotrack.streamtype";
+    field public static final String USAGE = "android.media.audiotrack.usage";
   }
 
-  public static abstract interface AudioTrack.OnPlaybackPositionUpdateListener {
-    method public abstract void onMarkerReached(android.media.AudioTrack);
-    method public abstract void onPeriodicNotification(android.media.AudioTrack);
+  public static interface AudioTrack.OnPlaybackPositionUpdateListener {
+    method public void onMarkerReached(android.media.AudioTrack);
+    method public void onPeriodicNotification(android.media.AudioTrack);
   }
 
-  public static abstract deprecated interface AudioTrack.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener {
-    method public abstract void onRoutingChanged(android.media.AudioTrack);
-    method public default void onRoutingChanged(android.media.AudioRouting);
+  @Deprecated public static interface AudioTrack.OnRoutingChangedListener extends android.media.AudioRouting.OnRoutingChangedListener {
+    method @Deprecated public void onRoutingChanged(android.media.AudioTrack);
+    method @Deprecated public default void onRoutingChanged(android.media.AudioRouting);
   }
 
-  public static abstract class AudioTrack.StreamEventCallback {
+  public abstract static class AudioTrack.StreamEventCallback {
     ctor public AudioTrack.StreamEventCallback();
     method public void onDataRequest(android.media.AudioTrack, int);
     method public void onPresentationEnded(android.media.AudioTrack);
@@ -23639,11 +23586,11 @@
     method public android.media.DataSourceCallback getDataSourceCallback();
   }
 
-  public static class CallbackDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase {
+  public static class CallbackDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase<android.media.CallbackDataSourceDesc.Builder> {
     ctor public CallbackDataSourceDesc.Builder();
     ctor public CallbackDataSourceDesc.Builder(android.media.CallbackDataSourceDesc);
-    method public android.media.CallbackDataSourceDesc build();
-    method public android.media.CallbackDataSourceDesc.Builder setDataSource(android.media.DataSourceCallback);
+    method @NonNull public android.media.CallbackDataSourceDesc build();
+    method @NonNull public android.media.CallbackDataSourceDesc.Builder setDataSource(@NonNull android.media.DataSourceCallback);
   }
 
   public class CamcorderProfile {
@@ -23706,20 +23653,20 @@
 
   public class DataSourceDesc {
     method public long getEndPosition();
-    method public java.lang.String getMediaId();
+    method public String getMediaId();
     method public long getStartPosition();
     field public static final long LONG_MAX_TIME_MS = 576460752303423L; // 0x20c49ba5e353fL
     field public static final long POSITION_UNKNOWN = 576460752303423L; // 0x20c49ba5e353fL
   }
 
   protected static class DataSourceDesc.BuilderBase<T extends android.media.DataSourceDesc.BuilderBase> {
-    method public T setEndPosition(long);
-    method public T setMediaId(java.lang.String);
-    method public T setStartPosition(long);
+    method @NonNull public T setEndPosition(long);
+    method @NonNull public T setMediaId(String);
+    method @NonNull public T setStartPosition(long);
   }
 
   public final class DeniedByServerException extends android.media.MediaDrmException {
-    ctor public DeniedByServerException(java.lang.String);
+    ctor public DeniedByServerException(String);
   }
 
   public abstract class DrmInitData {
@@ -23728,29 +23675,29 @@
 
   public static final class DrmInitData.SchemeInitData {
     field public final byte[] data;
-    field public final java.lang.String mimeType;
+    field public final String mimeType;
   }
 
   public class ExifInterface {
-    ctor public ExifInterface(java.io.File) throws java.io.IOException;
-    ctor public ExifInterface(java.lang.String) throws java.io.IOException;
-    ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
-    ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+    ctor public ExifInterface(@NonNull java.io.File) throws java.io.IOException;
+    ctor public ExifInterface(@NonNull String) throws java.io.IOException;
+    ctor public ExifInterface(@NonNull java.io.FileDescriptor) throws java.io.IOException;
+    ctor public ExifInterface(@NonNull java.io.InputStream) throws java.io.IOException;
     method public double getAltitude(double);
-    method public java.lang.String getAttribute(java.lang.String);
-    method public double getAttributeDouble(java.lang.String, double);
-    method public int getAttributeInt(java.lang.String, int);
-    method public long[] getAttributeRange(java.lang.String);
+    method @Nullable public String getAttribute(@NonNull String);
+    method public double getAttributeDouble(@NonNull String, double);
+    method public int getAttributeInt(@NonNull String, int);
+    method @Nullable public long[] getAttributeRange(@NonNull String);
     method public boolean getLatLong(float[]);
     method public byte[] getThumbnail();
     method public android.graphics.Bitmap getThumbnailBitmap();
     method public byte[] getThumbnailBytes();
-    method public long[] getThumbnailRange();
-    method public boolean hasAttribute(java.lang.String);
+    method @Nullable public long[] getThumbnailRange();
+    method public boolean hasAttribute(String);
     method public boolean hasThumbnail();
     method public boolean isThumbnailCompressed();
     method public void saveAttributes() throws java.io.IOException;
-    method public void setAttribute(java.lang.String, java.lang.String);
+    method public void setAttribute(@NonNull String, @Nullable String);
     field public static final int ORIENTATION_FLIP_HORIZONTAL = 2; // 0x2
     field public static final int ORIENTATION_FLIP_VERTICAL = 4; // 0x4
     field public static final int ORIENTATION_NORMAL = 1; // 0x1
@@ -23760,144 +23707,144 @@
     field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
     field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
     field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
-    field public static final deprecated java.lang.String TAG_APERTURE = "FNumber";
-    field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
-    field public static final java.lang.String TAG_ARTIST = "Artist";
-    field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
-    field public static final java.lang.String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
-    field public static final java.lang.String TAG_CFA_PATTERN = "CFAPattern";
-    field public static final java.lang.String TAG_COLOR_SPACE = "ColorSpace";
-    field public static final java.lang.String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
-    field public static final java.lang.String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
-    field public static final java.lang.String TAG_COMPRESSION = "Compression";
-    field public static final java.lang.String TAG_CONTRAST = "Contrast";
-    field public static final java.lang.String TAG_COPYRIGHT = "Copyright";
-    field public static final java.lang.String TAG_CUSTOM_RENDERED = "CustomRendered";
-    field public static final java.lang.String TAG_DATETIME = "DateTime";
-    field public static final java.lang.String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
-    field public static final java.lang.String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
-    field public static final java.lang.String TAG_DEFAULT_CROP_SIZE = "DefaultCropSize";
-    field public static final java.lang.String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
-    field public static final java.lang.String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
-    field public static final java.lang.String TAG_DNG_VERSION = "DNGVersion";
-    field public static final java.lang.String TAG_EXIF_VERSION = "ExifVersion";
-    field public static final java.lang.String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
-    field public static final java.lang.String TAG_EXPOSURE_INDEX = "ExposureIndex";
-    field public static final java.lang.String TAG_EXPOSURE_MODE = "ExposureMode";
-    field public static final java.lang.String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
-    field public static final java.lang.String TAG_EXPOSURE_TIME = "ExposureTime";
-    field public static final java.lang.String TAG_FILE_SOURCE = "FileSource";
-    field public static final java.lang.String TAG_FLASH = "Flash";
-    field public static final java.lang.String TAG_FLASHPIX_VERSION = "FlashpixVersion";
-    field public static final java.lang.String TAG_FLASH_ENERGY = "FlashEnergy";
-    field public static final java.lang.String TAG_FOCAL_LENGTH = "FocalLength";
-    field public static final java.lang.String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
-    field public static final java.lang.String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
-    field public static final java.lang.String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
-    field public static final java.lang.String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
-    field public static final java.lang.String TAG_F_NUMBER = "FNumber";
-    field public static final java.lang.String TAG_GAIN_CONTROL = "GainControl";
-    field public static final java.lang.String TAG_GPS_ALTITUDE = "GPSAltitude";
-    field public static final java.lang.String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
-    field public static final java.lang.String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
-    field public static final java.lang.String TAG_GPS_DATESTAMP = "GPSDateStamp";
-    field public static final java.lang.String TAG_GPS_DEST_BEARING = "GPSDestBearing";
-    field public static final java.lang.String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
-    field public static final java.lang.String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
-    field public static final java.lang.String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
-    field public static final java.lang.String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
-    field public static final java.lang.String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
-    field public static final java.lang.String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
-    field public static final java.lang.String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
-    field public static final java.lang.String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
-    field public static final java.lang.String TAG_GPS_DOP = "GPSDOP";
-    field public static final java.lang.String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
-    field public static final java.lang.String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
-    field public static final java.lang.String TAG_GPS_LATITUDE = "GPSLatitude";
-    field public static final java.lang.String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
-    field public static final java.lang.String TAG_GPS_LONGITUDE = "GPSLongitude";
-    field public static final java.lang.String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
-    field public static final java.lang.String TAG_GPS_MAP_DATUM = "GPSMapDatum";
-    field public static final java.lang.String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
-    field public static final java.lang.String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
-    field public static final java.lang.String TAG_GPS_SATELLITES = "GPSSatellites";
-    field public static final java.lang.String TAG_GPS_SPEED = "GPSSpeed";
-    field public static final java.lang.String TAG_GPS_SPEED_REF = "GPSSpeedRef";
-    field public static final java.lang.String TAG_GPS_STATUS = "GPSStatus";
-    field public static final java.lang.String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
-    field public static final java.lang.String TAG_GPS_TRACK = "GPSTrack";
-    field public static final java.lang.String TAG_GPS_TRACK_REF = "GPSTrackRef";
-    field public static final java.lang.String TAG_GPS_VERSION_ID = "GPSVersionID";
-    field public static final java.lang.String TAG_IMAGE_DESCRIPTION = "ImageDescription";
-    field public static final java.lang.String TAG_IMAGE_LENGTH = "ImageLength";
-    field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
-    field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
-    field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
-    field public static final deprecated java.lang.String TAG_ISO = "ISOSpeedRatings";
-    field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
-    field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
-    field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
-    field public static final java.lang.String TAG_LIGHT_SOURCE = "LightSource";
-    field public static final java.lang.String TAG_MAKE = "Make";
-    field public static final java.lang.String TAG_MAKER_NOTE = "MakerNote";
-    field public static final java.lang.String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
-    field public static final java.lang.String TAG_METERING_MODE = "MeteringMode";
-    field public static final java.lang.String TAG_MODEL = "Model";
-    field public static final java.lang.String TAG_NEW_SUBFILE_TYPE = "NewSubfileType";
-    field public static final java.lang.String TAG_OECF = "OECF";
-    field public static final java.lang.String TAG_ORF_ASPECT_FRAME = "AspectFrame";
-    field public static final java.lang.String TAG_ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
-    field public static final java.lang.String TAG_ORF_PREVIEW_IMAGE_START = "PreviewImageStart";
-    field public static final java.lang.String TAG_ORF_THUMBNAIL_IMAGE = "ThumbnailImage";
-    field public static final java.lang.String TAG_ORIENTATION = "Orientation";
-    field public static final java.lang.String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
-    field public static final java.lang.String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
-    field public static final java.lang.String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
-    field public static final java.lang.String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
-    field public static final java.lang.String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
-    field public static final java.lang.String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
-    field public static final java.lang.String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
-    field public static final java.lang.String TAG_RESOLUTION_UNIT = "ResolutionUnit";
-    field public static final java.lang.String TAG_ROWS_PER_STRIP = "RowsPerStrip";
-    field public static final java.lang.String TAG_RW2_ISO = "ISO";
-    field public static final java.lang.String TAG_RW2_JPG_FROM_RAW = "JpgFromRaw";
-    field public static final java.lang.String TAG_RW2_SENSOR_BOTTOM_BORDER = "SensorBottomBorder";
-    field public static final java.lang.String TAG_RW2_SENSOR_LEFT_BORDER = "SensorLeftBorder";
-    field public static final java.lang.String TAG_RW2_SENSOR_RIGHT_BORDER = "SensorRightBorder";
-    field public static final java.lang.String TAG_RW2_SENSOR_TOP_BORDER = "SensorTopBorder";
-    field public static final java.lang.String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
-    field public static final java.lang.String TAG_SATURATION = "Saturation";
-    field public static final java.lang.String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
-    field public static final java.lang.String TAG_SCENE_TYPE = "SceneType";
-    field public static final java.lang.String TAG_SENSING_METHOD = "SensingMethod";
-    field public static final java.lang.String TAG_SHARPNESS = "Sharpness";
-    field public static final java.lang.String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
-    field public static final java.lang.String TAG_SOFTWARE = "Software";
-    field public static final java.lang.String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
-    field public static final java.lang.String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
-    field public static final java.lang.String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
-    field public static final java.lang.String TAG_STRIP_OFFSETS = "StripOffsets";
-    field public static final java.lang.String TAG_SUBFILE_TYPE = "SubfileType";
-    field public static final java.lang.String TAG_SUBJECT_AREA = "SubjectArea";
-    field public static final java.lang.String TAG_SUBJECT_DISTANCE = "SubjectDistance";
-    field public static final java.lang.String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
-    field public static final java.lang.String TAG_SUBJECT_LOCATION = "SubjectLocation";
-    field public static final java.lang.String TAG_SUBSEC_TIME = "SubSecTime";
-    field public static final deprecated java.lang.String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
-    field public static final java.lang.String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
-    field public static final deprecated java.lang.String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
-    field public static final java.lang.String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
-    field public static final java.lang.String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
-    field public static final java.lang.String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
-    field public static final java.lang.String TAG_TRANSFER_FUNCTION = "TransferFunction";
-    field public static final java.lang.String TAG_USER_COMMENT = "UserComment";
-    field public static final java.lang.String TAG_WHITE_BALANCE = "WhiteBalance";
-    field public static final java.lang.String TAG_WHITE_POINT = "WhitePoint";
-    field public static final java.lang.String TAG_X_RESOLUTION = "XResolution";
-    field public static final java.lang.String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
-    field public static final java.lang.String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
-    field public static final java.lang.String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
-    field public static final java.lang.String TAG_Y_RESOLUTION = "YResolution";
+    field @Deprecated public static final String TAG_APERTURE = "FNumber";
+    field public static final String TAG_APERTURE_VALUE = "ApertureValue";
+    field public static final String TAG_ARTIST = "Artist";
+    field public static final String TAG_BITS_PER_SAMPLE = "BitsPerSample";
+    field public static final String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
+    field public static final String TAG_CFA_PATTERN = "CFAPattern";
+    field public static final String TAG_COLOR_SPACE = "ColorSpace";
+    field public static final String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
+    field public static final String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
+    field public static final String TAG_COMPRESSION = "Compression";
+    field public static final String TAG_CONTRAST = "Contrast";
+    field public static final String TAG_COPYRIGHT = "Copyright";
+    field public static final String TAG_CUSTOM_RENDERED = "CustomRendered";
+    field public static final String TAG_DATETIME = "DateTime";
+    field public static final String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+    field public static final String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
+    field public static final String TAG_DEFAULT_CROP_SIZE = "DefaultCropSize";
+    field public static final String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
+    field public static final String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+    field public static final String TAG_DNG_VERSION = "DNGVersion";
+    field public static final String TAG_EXIF_VERSION = "ExifVersion";
+    field public static final String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+    field public static final String TAG_EXPOSURE_INDEX = "ExposureIndex";
+    field public static final String TAG_EXPOSURE_MODE = "ExposureMode";
+    field public static final String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
+    field public static final String TAG_EXPOSURE_TIME = "ExposureTime";
+    field public static final String TAG_FILE_SOURCE = "FileSource";
+    field public static final String TAG_FLASH = "Flash";
+    field public static final String TAG_FLASHPIX_VERSION = "FlashpixVersion";
+    field public static final String TAG_FLASH_ENERGY = "FlashEnergy";
+    field public static final String TAG_FOCAL_LENGTH = "FocalLength";
+    field public static final String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
+    field public static final String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
+    field public static final String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
+    field public static final String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
+    field public static final String TAG_F_NUMBER = "FNumber";
+    field public static final String TAG_GAIN_CONTROL = "GainControl";
+    field public static final String TAG_GPS_ALTITUDE = "GPSAltitude";
+    field public static final String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
+    field public static final String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
+    field public static final String TAG_GPS_DATESTAMP = "GPSDateStamp";
+    field public static final String TAG_GPS_DEST_BEARING = "GPSDestBearing";
+    field public static final String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
+    field public static final String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
+    field public static final String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
+    field public static final String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
+    field public static final String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
+    field public static final String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
+    field public static final String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
+    field public static final String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
+    field public static final String TAG_GPS_DOP = "GPSDOP";
+    field public static final String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
+    field public static final String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
+    field public static final String TAG_GPS_LATITUDE = "GPSLatitude";
+    field public static final String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
+    field public static final String TAG_GPS_LONGITUDE = "GPSLongitude";
+    field public static final String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
+    field public static final String TAG_GPS_MAP_DATUM = "GPSMapDatum";
+    field public static final String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
+    field public static final String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
+    field public static final String TAG_GPS_SATELLITES = "GPSSatellites";
+    field public static final String TAG_GPS_SPEED = "GPSSpeed";
+    field public static final String TAG_GPS_SPEED_REF = "GPSSpeedRef";
+    field public static final String TAG_GPS_STATUS = "GPSStatus";
+    field public static final String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
+    field public static final String TAG_GPS_TRACK = "GPSTrack";
+    field public static final String TAG_GPS_TRACK_REF = "GPSTrackRef";
+    field public static final String TAG_GPS_VERSION_ID = "GPSVersionID";
+    field public static final String TAG_IMAGE_DESCRIPTION = "ImageDescription";
+    field public static final String TAG_IMAGE_LENGTH = "ImageLength";
+    field public static final String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
+    field public static final String TAG_IMAGE_WIDTH = "ImageWidth";
+    field public static final String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
+    field @Deprecated public static final String TAG_ISO = "ISOSpeedRatings";
+    field public static final String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
+    field public static final String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
+    field public static final String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
+    field public static final String TAG_LIGHT_SOURCE = "LightSource";
+    field public static final String TAG_MAKE = "Make";
+    field public static final String TAG_MAKER_NOTE = "MakerNote";
+    field public static final String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
+    field public static final String TAG_METERING_MODE = "MeteringMode";
+    field public static final String TAG_MODEL = "Model";
+    field public static final String TAG_NEW_SUBFILE_TYPE = "NewSubfileType";
+    field public static final String TAG_OECF = "OECF";
+    field public static final String TAG_ORF_ASPECT_FRAME = "AspectFrame";
+    field public static final String TAG_ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
+    field public static final String TAG_ORF_PREVIEW_IMAGE_START = "PreviewImageStart";
+    field public static final String TAG_ORF_THUMBNAIL_IMAGE = "ThumbnailImage";
+    field public static final String TAG_ORIENTATION = "Orientation";
+    field public static final String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
+    field public static final String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
+    field public static final String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
+    field public static final String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
+    field public static final String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
+    field public static final String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
+    field public static final String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
+    field public static final String TAG_RESOLUTION_UNIT = "ResolutionUnit";
+    field public static final String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+    field public static final String TAG_RW2_ISO = "ISO";
+    field public static final String TAG_RW2_JPG_FROM_RAW = "JpgFromRaw";
+    field public static final String TAG_RW2_SENSOR_BOTTOM_BORDER = "SensorBottomBorder";
+    field public static final String TAG_RW2_SENSOR_LEFT_BORDER = "SensorLeftBorder";
+    field public static final String TAG_RW2_SENSOR_RIGHT_BORDER = "SensorRightBorder";
+    field public static final String TAG_RW2_SENSOR_TOP_BORDER = "SensorTopBorder";
+    field public static final String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
+    field public static final String TAG_SATURATION = "Saturation";
+    field public static final String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
+    field public static final String TAG_SCENE_TYPE = "SceneType";
+    field public static final String TAG_SENSING_METHOD = "SensingMethod";
+    field public static final String TAG_SHARPNESS = "Sharpness";
+    field public static final String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
+    field public static final String TAG_SOFTWARE = "Software";
+    field public static final String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
+    field public static final String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
+    field public static final String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
+    field public static final String TAG_STRIP_OFFSETS = "StripOffsets";
+    field public static final String TAG_SUBFILE_TYPE = "SubfileType";
+    field public static final String TAG_SUBJECT_AREA = "SubjectArea";
+    field public static final String TAG_SUBJECT_DISTANCE = "SubjectDistance";
+    field public static final String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
+    field public static final String TAG_SUBJECT_LOCATION = "SubjectLocation";
+    field public static final String TAG_SUBSEC_TIME = "SubSecTime";
+    field @Deprecated public static final String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
+    field public static final String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
+    field @Deprecated public static final String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
+    field public static final String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
+    field public static final String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
+    field public static final String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
+    field public static final String TAG_TRANSFER_FUNCTION = "TransferFunction";
+    field public static final String TAG_USER_COMMENT = "UserComment";
+    field public static final String TAG_WHITE_BALANCE = "WhiteBalance";
+    field public static final String TAG_WHITE_POINT = "WhitePoint";
+    field public static final String TAG_X_RESOLUTION = "XResolution";
+    field public static final String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
+    field public static final String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
+    field public static final String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
+    field public static final String TAG_Y_RESOLUTION = "YResolution";
     field public static final int WHITEBALANCE_AUTO = 0; // 0x0
     field public static final int WHITEBALANCE_MANUAL = 1; // 0x1
   }
@@ -23925,19 +23872,19 @@
     field public static final long FD_LENGTH_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL
   }
 
-  public static class FileDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase {
+  public static class FileDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase<android.media.FileDataSourceDesc.Builder> {
     ctor public FileDataSourceDesc.Builder();
     ctor public FileDataSourceDesc.Builder(android.media.FileDataSourceDesc);
-    method public android.media.FileDataSourceDesc build();
-    method public android.media.FileDataSourceDesc.Builder setDataSource(android.os.ParcelFileDescriptor);
-    method public android.media.FileDataSourceDesc.Builder setDataSource(android.os.ParcelFileDescriptor, long, long);
+    method @NonNull public android.media.FileDataSourceDesc build();
+    method @NonNull public android.media.FileDataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor);
+    method @NonNull public android.media.FileDataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor, long, long);
   }
 
   public abstract class Image implements java.lang.AutoCloseable {
     method public abstract void close();
     method public android.graphics.Rect getCropRect();
     method public abstract int getFormat();
-    method public android.hardware.HardwareBuffer getHardwareBuffer();
+    method @Nullable public android.hardware.HardwareBuffer getHardwareBuffer();
     method public abstract int getHeight();
     method public abstract android.media.Image.Plane[] getPlanes();
     method public abstract long getTimestamp();
@@ -23946,7 +23893,7 @@
     method public void setTimestamp(long);
   }
 
-  public static abstract class Image.Plane {
+  public abstract static class Image.Plane {
     method public abstract java.nio.ByteBuffer getBuffer();
     method public abstract int getPixelStride();
     method public abstract int getRowStride();
@@ -23963,11 +23910,12 @@
     method public android.view.Surface getSurface();
     method public int getWidth();
     method public static android.media.ImageReader newInstance(int, int, int, int);
+    method public static android.media.ImageReader newInstance(int, int, int, int, long);
     method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
   }
 
-  public static abstract interface ImageReader.OnImageAvailableListener {
-    method public abstract void onImageAvailable(android.media.ImageReader);
+  public static interface ImageReader.OnImageAvailableListener {
+    method public void onImageAvailable(android.media.ImageReader);
   }
 
   public class ImageWriter implements java.lang.AutoCloseable {
@@ -23976,22 +23924,23 @@
     method public int getFormat();
     method public int getMaxImages();
     method public static android.media.ImageWriter newInstance(android.view.Surface, int);
+    method public static android.media.ImageWriter newInstance(android.view.Surface, int, int);
     method public void queueInputImage(android.media.Image);
     method public void setOnImageReleasedListener(android.media.ImageWriter.OnImageReleasedListener, android.os.Handler);
   }
 
-  public static abstract interface ImageWriter.OnImageReleasedListener {
-    method public abstract void onImageReleased(android.media.ImageWriter);
+  public static interface ImageWriter.OnImageReleasedListener {
+    method public void onImageReleased(android.media.ImageWriter);
   }
 
   public class JetPlayer {
     method public boolean clearQueue();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
+    method public Object clone() throws java.lang.CloneNotSupportedException;
     method public boolean closeJetFile();
     method protected void finalize();
     method public static android.media.JetPlayer getJetPlayer();
     method public static int getMaxTracks();
-    method public boolean loadJetFile(java.lang.String);
+    method public boolean loadJetFile(String);
     method public boolean loadJetFile(android.content.res.AssetFileDescriptor);
     method public boolean pause();
     method public boolean play();
@@ -24006,11 +23955,11 @@
     method public boolean triggerClip(int);
   }
 
-  public static abstract interface JetPlayer.OnJetEventListener {
-    method public abstract void onJetEvent(android.media.JetPlayer, short, byte, byte, byte, byte);
-    method public abstract void onJetNumQueuedSegmentUpdate(android.media.JetPlayer, int);
-    method public abstract void onJetPauseUpdate(android.media.JetPlayer, int);
-    method public abstract void onJetUserIdUpdate(android.media.JetPlayer, int, int);
+  public static interface JetPlayer.OnJetEventListener {
+    method public void onJetEvent(android.media.JetPlayer, short, byte, byte, byte, byte);
+    method public void onJetNumQueuedSegmentUpdate(android.media.JetPlayer, int);
+    method public void onJetPauseUpdate(android.media.JetPlayer, int);
+    method public void onJetUserIdUpdate(android.media.JetPlayer, int, int);
   }
 
   public class MediaActionSound {
@@ -24031,29 +23980,29 @@
     method protected void finalize();
     method public static boolean isSystemIdSupported(int);
     method public android.media.MediaCas.Session openSession() throws android.media.MediaCasException;
-    method public void processEmm(byte[], int, int) throws android.media.MediaCasException;
-    method public void processEmm(byte[]) throws android.media.MediaCasException;
-    method public void provision(java.lang.String) throws android.media.MediaCasException;
-    method public void refreshEntitlements(int, byte[]) throws android.media.MediaCasException;
-    method public void sendEvent(int, int, byte[]) throws android.media.MediaCasException;
-    method public void setEventListener(android.media.MediaCas.EventListener, android.os.Handler);
-    method public void setPrivateData(byte[]) throws android.media.MediaCasException;
+    method public void processEmm(@NonNull byte[], int, int) throws android.media.MediaCasException;
+    method public void processEmm(@NonNull byte[]) throws android.media.MediaCasException;
+    method public void provision(@NonNull String) throws android.media.MediaCasException;
+    method public void refreshEntitlements(int, @Nullable byte[]) throws android.media.MediaCasException;
+    method public void sendEvent(int, int, @Nullable byte[]) throws android.media.MediaCasException;
+    method public void setEventListener(@Nullable android.media.MediaCas.EventListener, @Nullable android.os.Handler);
+    method public void setPrivateData(@NonNull byte[]) throws android.media.MediaCasException;
   }
 
-  public static abstract interface MediaCas.EventListener {
-    method public abstract void onEvent(android.media.MediaCas, int, int, byte[]);
+  public static interface MediaCas.EventListener {
+    method public void onEvent(android.media.MediaCas, int, int, @Nullable byte[]);
   }
 
   public static class MediaCas.PluginDescriptor {
-    method public java.lang.String getName();
+    method @NonNull public String getName();
     method public int getSystemId();
   }
 
   public final class MediaCas.Session implements java.lang.AutoCloseable {
     method public void close();
-    method public void processEcm(byte[], int, int) throws android.media.MediaCasException;
-    method public void processEcm(byte[]) throws android.media.MediaCasException;
-    method public void setPrivateData(byte[]) throws android.media.MediaCasException;
+    method public void processEcm(@NonNull byte[], int, int) throws android.media.MediaCasException;
+    method public void processEcm(@NonNull byte[]) throws android.media.MediaCasException;
+    method public void setPrivateData(@NonNull byte[]) throws android.media.MediaCasException;
   }
 
   public class MediaCasException extends java.lang.Exception {
@@ -24072,46 +24021,47 @@
   }
 
   public class MediaCasStateException extends java.lang.IllegalStateException {
-    method public java.lang.String getDiagnosticInfo();
+    method @NonNull public String getDiagnosticInfo();
   }
 
   public final class MediaCodec {
-    method public void configure(android.media.MediaFormat, android.view.Surface, android.media.MediaCrypto, int);
-    method public void configure(android.media.MediaFormat, android.view.Surface, int, android.media.MediaDescrambler);
-    method public static android.media.MediaCodec createByCodecName(java.lang.String) throws java.io.IOException;
-    method public static android.media.MediaCodec createDecoderByType(java.lang.String) throws java.io.IOException;
-    method public static android.media.MediaCodec createEncoderByType(java.lang.String) throws java.io.IOException;
-    method public android.view.Surface createInputSurface();
-    method public static android.view.Surface createPersistentInputSurface();
+    method public void configure(@Nullable android.media.MediaFormat, @Nullable android.view.Surface, @Nullable android.media.MediaCrypto, int);
+    method public void configure(@Nullable android.media.MediaFormat, @Nullable android.view.Surface, int, @Nullable android.media.MediaDescrambler);
+    method @NonNull public static android.media.MediaCodec createByCodecName(@NonNull String) throws java.io.IOException;
+    method @NonNull public static android.media.MediaCodec createDecoderByType(@NonNull String) throws java.io.IOException;
+    method @NonNull public static android.media.MediaCodec createEncoderByType(@NonNull String) throws java.io.IOException;
+    method @NonNull public android.view.Surface createInputSurface();
+    method @NonNull public static android.view.Surface createPersistentInputSurface();
     method public int dequeueInputBuffer(long);
-    method public int dequeueOutputBuffer(android.media.MediaCodec.BufferInfo, long);
+    method public int dequeueOutputBuffer(@NonNull android.media.MediaCodec.BufferInfo, long);
     method protected void finalize();
     method public void flush();
-    method public android.media.MediaCodecInfo getCodecInfo();
-    method public java.nio.ByteBuffer getInputBuffer(int);
-    method public deprecated java.nio.ByteBuffer[] getInputBuffers();
-    method public android.media.MediaFormat getInputFormat();
-    method public android.media.Image getInputImage(int);
+    method @NonNull public String getCanonicalName();
+    method @NonNull public android.media.MediaCodecInfo getCodecInfo();
+    method @Nullable public java.nio.ByteBuffer getInputBuffer(int);
+    method @Deprecated @NonNull public java.nio.ByteBuffer[] getInputBuffers();
+    method @NonNull public android.media.MediaFormat getInputFormat();
+    method @Nullable public android.media.Image getInputImage(int);
     method public android.os.PersistableBundle getMetrics();
-    method public java.lang.String getName();
-    method public java.nio.ByteBuffer getOutputBuffer(int);
-    method public deprecated java.nio.ByteBuffer[] getOutputBuffers();
-    method public android.media.MediaFormat getOutputFormat();
-    method public android.media.MediaFormat getOutputFormat(int);
-    method public android.media.Image getOutputImage(int);
+    method @NonNull public String getName();
+    method @Nullable public java.nio.ByteBuffer getOutputBuffer(int);
+    method @Deprecated @NonNull public java.nio.ByteBuffer[] getOutputBuffers();
+    method @NonNull public android.media.MediaFormat getOutputFormat();
+    method @NonNull public android.media.MediaFormat getOutputFormat(int);
+    method @Nullable public android.media.Image getOutputImage(int);
     method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException;
-    method public void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
+    method public void queueSecureInputBuffer(int, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
     method public void release();
     method public void releaseOutputBuffer(int, boolean);
     method public void releaseOutputBuffer(int, long);
     method public void reset();
-    method public void setAudioPresentation(android.media.AudioPresentation);
-    method public void setCallback(android.media.MediaCodec.Callback, android.os.Handler);
-    method public void setCallback(android.media.MediaCodec.Callback);
-    method public void setInputSurface(android.view.Surface);
-    method public void setOnFrameRenderedListener(android.media.MediaCodec.OnFrameRenderedListener, android.os.Handler);
-    method public void setOutputSurface(android.view.Surface);
-    method public void setParameters(android.os.Bundle);
+    method public void setAudioPresentation(@NonNull android.media.AudioPresentation);
+    method public void setCallback(@Nullable android.media.MediaCodec.Callback, @Nullable android.os.Handler);
+    method public void setCallback(@Nullable android.media.MediaCodec.Callback);
+    method public void setInputSurface(@NonNull android.view.Surface);
+    method public void setOnFrameRenderedListener(@Nullable android.media.MediaCodec.OnFrameRenderedListener, @Nullable android.os.Handler);
+    method public void setOutputSurface(@NonNull android.view.Surface);
+    method public void setParameters(@Nullable android.os.Bundle);
     method public void setVideoScalingMode(int);
     method public void signalEndOfInputStream();
     method public void start();
@@ -24120,18 +24070,18 @@
     field public static final int BUFFER_FLAG_END_OF_STREAM = 4; // 0x4
     field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1
     field public static final int BUFFER_FLAG_PARTIAL_FRAME = 8; // 0x8
-    field public static final deprecated int BUFFER_FLAG_SYNC_FRAME = 1; // 0x1
+    field @Deprecated public static final int BUFFER_FLAG_SYNC_FRAME = 1; // 0x1
     field public static final int CONFIGURE_FLAG_ENCODE = 1; // 0x1
     field public static final int CRYPTO_MODE_AES_CBC = 2; // 0x2
     field public static final int CRYPTO_MODE_AES_CTR = 1; // 0x1
     field public static final int CRYPTO_MODE_UNENCRYPTED = 0; // 0x0
-    field public static final deprecated int INFO_OUTPUT_BUFFERS_CHANGED = -3; // 0xfffffffd
+    field @Deprecated public static final int INFO_OUTPUT_BUFFERS_CHANGED = -3; // 0xfffffffd
     field public static final int INFO_OUTPUT_FORMAT_CHANGED = -2; // 0xfffffffe
     field public static final int INFO_TRY_AGAIN_LATER = -1; // 0xffffffff
-    field public static final java.lang.String PARAMETER_KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
-    field public static final java.lang.String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
-    field public static final java.lang.String PARAMETER_KEY_SUSPEND = "drop-input-frames";
-    field public static final java.lang.String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
+    field public static final String PARAMETER_KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
+    field public static final String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
+    field public static final String PARAMETER_KEY_SUSPEND = "drop-input-frames";
+    field public static final String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
   }
@@ -24145,16 +24095,16 @@
     field public int size;
   }
 
-  public static abstract class MediaCodec.Callback {
+  public abstract static class MediaCodec.Callback {
     ctor public MediaCodec.Callback();
-    method public abstract void onError(android.media.MediaCodec, android.media.MediaCodec.CodecException);
-    method public abstract void onInputBufferAvailable(android.media.MediaCodec, int);
-    method public abstract void onOutputBufferAvailable(android.media.MediaCodec, int, android.media.MediaCodec.BufferInfo);
-    method public abstract void onOutputFormatChanged(android.media.MediaCodec, android.media.MediaFormat);
+    method public abstract void onError(@NonNull android.media.MediaCodec, @NonNull android.media.MediaCodec.CodecException);
+    method public abstract void onInputBufferAvailable(@NonNull android.media.MediaCodec, int);
+    method public abstract void onOutputBufferAvailable(@NonNull android.media.MediaCodec, int, @NonNull android.media.MediaCodec.BufferInfo);
+    method public abstract void onOutputFormatChanged(@NonNull android.media.MediaCodec, @NonNull android.media.MediaFormat);
   }
 
   public static final class MediaCodec.CodecException extends java.lang.IllegalStateException {
-    method public java.lang.String getDiagnosticInfo();
+    method @NonNull public String getDiagnosticInfo();
     method public int getErrorCode();
     method public boolean isRecoverable();
     method public boolean isTransient();
@@ -24163,10 +24113,13 @@
   }
 
   public static final class MediaCodec.CryptoException extends java.lang.RuntimeException {
-    ctor public MediaCodec.CryptoException(int, java.lang.String);
+    ctor public MediaCodec.CryptoException(int, @Nullable String);
     method public int getErrorCode();
+    field public static final int ERROR_FRAME_TOO_LARGE = 8; // 0x8
     field public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; // 0x4
+    field public static final int ERROR_INSUFFICIENT_SECURITY = 7; // 0x7
     field public static final int ERROR_KEY_EXPIRED = 2; // 0x2
+    field public static final int ERROR_LOST_STATE = 9; // 0x9
     field public static final int ERROR_NO_KEY = 1; // 0x1
     field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3
     field public static final int ERROR_SESSION_NOT_OPENED = 5; // 0x5
@@ -24175,7 +24128,7 @@
 
   public static final class MediaCodec.CryptoInfo {
     ctor public MediaCodec.CryptoInfo();
-    method public void set(int, int[], int[], byte[], byte[], int);
+    method public void set(int, @NonNull int[], @NonNull int[], @NonNull byte[], @NonNull byte[], int);
     method public void setPattern(android.media.MediaCodec.CryptoInfo.Pattern);
     field public byte[] iv;
     field public byte[] key;
@@ -24193,27 +24146,32 @@
   }
 
   public static final class MediaCodec.MetricsConstants {
-    field public static final java.lang.String CODEC = "android.media.mediacodec.codec";
-    field public static final java.lang.String ENCODER = "android.media.mediacodec.encoder";
-    field public static final java.lang.String HEIGHT = "android.media.mediacodec.height";
-    field public static final java.lang.String MIME_TYPE = "android.media.mediacodec.mime";
-    field public static final java.lang.String MODE = "android.media.mediacodec.mode";
-    field public static final java.lang.String MODE_AUDIO = "audio";
-    field public static final java.lang.String MODE_VIDEO = "video";
-    field public static final java.lang.String ROTATION = "android.media.mediacodec.rotation";
-    field public static final java.lang.String SECURE = "android.media.mediacodec.secure";
-    field public static final java.lang.String WIDTH = "android.media.mediacodec.width";
+    field public static final String CODEC = "android.media.mediacodec.codec";
+    field public static final String ENCODER = "android.media.mediacodec.encoder";
+    field public static final String HEIGHT = "android.media.mediacodec.height";
+    field public static final String MIME_TYPE = "android.media.mediacodec.mime";
+    field public static final String MODE = "android.media.mediacodec.mode";
+    field public static final String MODE_AUDIO = "audio";
+    field public static final String MODE_VIDEO = "video";
+    field public static final String ROTATION = "android.media.mediacodec.rotation";
+    field public static final String SECURE = "android.media.mediacodec.secure";
+    field public static final String WIDTH = "android.media.mediacodec.width";
   }
 
-  public static abstract interface MediaCodec.OnFrameRenderedListener {
-    method public abstract void onFrameRendered(android.media.MediaCodec, long, long);
+  public static interface MediaCodec.OnFrameRenderedListener {
+    method public void onFrameRendered(@NonNull android.media.MediaCodec, long, long);
   }
 
   public final class MediaCodecInfo {
-    method public android.media.MediaCodecInfo.CodecCapabilities getCapabilitiesForType(java.lang.String);
-    method public java.lang.String getName();
-    method public java.lang.String[] getSupportedTypes();
+    method @NonNull public String getCanonicalName();
+    method public android.media.MediaCodecInfo.CodecCapabilities getCapabilitiesForType(String);
+    method @NonNull public String getName();
+    method public String[] getSupportedTypes();
+    method public boolean isAlias();
     method public boolean isEncoder();
+    method public boolean isHardwareAccelerated();
+    method public boolean isSoftwareOnly();
+    method public boolean isVendor();
   }
 
   public static final class MediaCodecInfo.AudioCapabilities {
@@ -24226,73 +24184,76 @@
 
   public static final class MediaCodecInfo.CodecCapabilities {
     ctor public MediaCodecInfo.CodecCapabilities();
-    method public static android.media.MediaCodecInfo.CodecCapabilities createFromProfileLevel(java.lang.String, int, int);
+    method public static android.media.MediaCodecInfo.CodecCapabilities createFromProfileLevel(String, int, int);
     method public android.media.MediaCodecInfo.AudioCapabilities getAudioCapabilities();
     method public android.media.MediaFormat getDefaultFormat();
     method public android.media.MediaCodecInfo.EncoderCapabilities getEncoderCapabilities();
     method public int getMaxSupportedInstances();
-    method public java.lang.String getMimeType();
+    method public String getMimeType();
     method public android.media.MediaCodecInfo.VideoCapabilities getVideoCapabilities();
-    method public boolean isFeatureRequired(java.lang.String);
-    method public boolean isFeatureSupported(java.lang.String);
+    method public boolean isFeatureRequired(String);
+    method public boolean isFeatureSupported(String);
     method public boolean isFormatSupported(android.media.MediaFormat);
-    field public static final deprecated int COLOR_Format12bitRGB444 = 3; // 0x3
-    field public static final deprecated int COLOR_Format16bitARGB1555 = 5; // 0x5
-    field public static final deprecated int COLOR_Format16bitARGB4444 = 4; // 0x4
-    field public static final deprecated int COLOR_Format16bitBGR565 = 7; // 0x7
+    field @Deprecated public static final int COLOR_Format12bitRGB444 = 3; // 0x3
+    field @Deprecated public static final int COLOR_Format16bitARGB1555 = 5; // 0x5
+    field @Deprecated public static final int COLOR_Format16bitARGB4444 = 4; // 0x4
+    field @Deprecated public static final int COLOR_Format16bitBGR565 = 7; // 0x7
     field public static final int COLOR_Format16bitRGB565 = 6; // 0x6
-    field public static final deprecated int COLOR_Format18BitBGR666 = 41; // 0x29
-    field public static final deprecated int COLOR_Format18bitARGB1665 = 9; // 0x9
-    field public static final deprecated int COLOR_Format18bitRGB666 = 8; // 0x8
-    field public static final deprecated int COLOR_Format19bitARGB1666 = 10; // 0xa
-    field public static final deprecated int COLOR_Format24BitABGR6666 = 43; // 0x2b
-    field public static final deprecated int COLOR_Format24BitARGB6666 = 42; // 0x2a
-    field public static final deprecated int COLOR_Format24bitARGB1887 = 13; // 0xd
+    field @Deprecated public static final int COLOR_Format18BitBGR666 = 41; // 0x29
+    field @Deprecated public static final int COLOR_Format18bitARGB1665 = 9; // 0x9
+    field @Deprecated public static final int COLOR_Format18bitRGB666 = 8; // 0x8
+    field @Deprecated public static final int COLOR_Format19bitARGB1666 = 10; // 0xa
+    field @Deprecated public static final int COLOR_Format24BitABGR6666 = 43; // 0x2b
+    field @Deprecated public static final int COLOR_Format24BitARGB6666 = 42; // 0x2a
+    field @Deprecated public static final int COLOR_Format24bitARGB1887 = 13; // 0xd
     field public static final int COLOR_Format24bitBGR888 = 12; // 0xc
-    field public static final deprecated int COLOR_Format24bitRGB888 = 11; // 0xb
-    field public static final deprecated int COLOR_Format25bitARGB1888 = 14; // 0xe
+    field @Deprecated public static final int COLOR_Format24bitRGB888 = 11; // 0xb
+    field @Deprecated public static final int COLOR_Format25bitARGB1888 = 14; // 0xe
     field public static final int COLOR_Format32bitABGR8888 = 2130747392; // 0x7f00a000
-    field public static final deprecated int COLOR_Format32bitARGB8888 = 16; // 0x10
-    field public static final deprecated int COLOR_Format32bitBGRA8888 = 15; // 0xf
-    field public static final deprecated int COLOR_Format8bitRGB332 = 2; // 0x2
-    field public static final deprecated int COLOR_FormatCbYCrY = 27; // 0x1b
-    field public static final deprecated int COLOR_FormatCrYCbY = 28; // 0x1c
+    field @Deprecated public static final int COLOR_Format32bitARGB8888 = 16; // 0x10
+    field @Deprecated public static final int COLOR_Format32bitBGRA8888 = 15; // 0xf
+    field @Deprecated public static final int COLOR_Format8bitRGB332 = 2; // 0x2
+    field @Deprecated public static final int COLOR_FormatCbYCrY = 27; // 0x1b
+    field @Deprecated public static final int COLOR_FormatCrYCbY = 28; // 0x1c
     field public static final int COLOR_FormatL16 = 36; // 0x24
-    field public static final deprecated int COLOR_FormatL2 = 33; // 0x21
-    field public static final deprecated int COLOR_FormatL24 = 37; // 0x25
-    field public static final deprecated int COLOR_FormatL32 = 38; // 0x26
-    field public static final deprecated int COLOR_FormatL4 = 34; // 0x22
+    field @Deprecated public static final int COLOR_FormatL2 = 33; // 0x21
+    field @Deprecated public static final int COLOR_FormatL24 = 37; // 0x25
+    field @Deprecated public static final int COLOR_FormatL32 = 38; // 0x26
+    field @Deprecated public static final int COLOR_FormatL4 = 34; // 0x22
     field public static final int COLOR_FormatL8 = 35; // 0x23
-    field public static final deprecated int COLOR_FormatMonochrome = 1; // 0x1
+    field @Deprecated public static final int COLOR_FormatMonochrome = 1; // 0x1
     field public static final int COLOR_FormatRGBAFlexible = 2134288520; // 0x7f36a888
     field public static final int COLOR_FormatRGBFlexible = 2134292616; // 0x7f36b888
     field public static final int COLOR_FormatRawBayer10bit = 31; // 0x1f
     field public static final int COLOR_FormatRawBayer8bit = 30; // 0x1e
     field public static final int COLOR_FormatRawBayer8bitcompressed = 32; // 0x20
     field public static final int COLOR_FormatSurface = 2130708361; // 0x7f000789
-    field public static final deprecated int COLOR_FormatYCbYCr = 25; // 0x19
-    field public static final deprecated int COLOR_FormatYCrYCb = 26; // 0x1a
-    field public static final deprecated int COLOR_FormatYUV411PackedPlanar = 18; // 0x12
-    field public static final deprecated int COLOR_FormatYUV411Planar = 17; // 0x11
+    field @Deprecated public static final int COLOR_FormatYCbYCr = 25; // 0x19
+    field @Deprecated public static final int COLOR_FormatYCrYCb = 26; // 0x1a
+    field @Deprecated public static final int COLOR_FormatYUV411PackedPlanar = 18; // 0x12
+    field @Deprecated public static final int COLOR_FormatYUV411Planar = 17; // 0x11
     field public static final int COLOR_FormatYUV420Flexible = 2135033992; // 0x7f420888
-    field public static final deprecated int COLOR_FormatYUV420PackedPlanar = 20; // 0x14
-    field public static final deprecated int COLOR_FormatYUV420PackedSemiPlanar = 39; // 0x27
-    field public static final deprecated int COLOR_FormatYUV420Planar = 19; // 0x13
-    field public static final deprecated int COLOR_FormatYUV420SemiPlanar = 21; // 0x15
+    field @Deprecated public static final int COLOR_FormatYUV420PackedPlanar = 20; // 0x14
+    field @Deprecated public static final int COLOR_FormatYUV420PackedSemiPlanar = 39; // 0x27
+    field @Deprecated public static final int COLOR_FormatYUV420Planar = 19; // 0x13
+    field @Deprecated public static final int COLOR_FormatYUV420SemiPlanar = 21; // 0x15
     field public static final int COLOR_FormatYUV422Flexible = 2135042184; // 0x7f422888
-    field public static final deprecated int COLOR_FormatYUV422PackedPlanar = 23; // 0x17
-    field public static final deprecated int COLOR_FormatYUV422PackedSemiPlanar = 40; // 0x28
-    field public static final deprecated int COLOR_FormatYUV422Planar = 22; // 0x16
-    field public static final deprecated int COLOR_FormatYUV422SemiPlanar = 24; // 0x18
+    field @Deprecated public static final int COLOR_FormatYUV422PackedPlanar = 23; // 0x17
+    field @Deprecated public static final int COLOR_FormatYUV422PackedSemiPlanar = 40; // 0x28
+    field @Deprecated public static final int COLOR_FormatYUV422Planar = 22; // 0x16
+    field @Deprecated public static final int COLOR_FormatYUV422SemiPlanar = 24; // 0x18
     field public static final int COLOR_FormatYUV444Flexible = 2135181448; // 0x7f444888
-    field public static final deprecated int COLOR_FormatYUV444Interleaved = 29; // 0x1d
-    field public static final deprecated int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00
-    field public static final deprecated int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
-    field public static final java.lang.String FEATURE_AdaptivePlayback = "adaptive-playback";
-    field public static final java.lang.String FEATURE_IntraRefresh = "intra-refresh";
-    field public static final java.lang.String FEATURE_PartialFrame = "partial-frame";
-    field public static final java.lang.String FEATURE_SecurePlayback = "secure-playback";
-    field public static final java.lang.String FEATURE_TunneledPlayback = "tunneled-playback";
+    field @Deprecated public static final int COLOR_FormatYUV444Interleaved = 29; // 0x1d
+    field @Deprecated public static final int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00
+    field @Deprecated public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
+    field public static final String FEATURE_AdaptivePlayback = "adaptive-playback";
+    field public static final String FEATURE_DynamicTimestamp = "dynamic-timestamp";
+    field public static final String FEATURE_FrameParsing = "frame-parsing";
+    field public static final String FEATURE_IntraRefresh = "intra-refresh";
+    field public static final String FEATURE_MultipleFrames = "multiple-frames";
+    field public static final String FEATURE_PartialFrame = "partial-frame";
+    field public static final String FEATURE_SecurePlayback = "secure-playback";
+    field public static final String FEATURE_TunneledPlayback = "tunneled-playback";
     field public int[] colorFormats;
     field public android.media.MediaCodecInfo.CodecProfileLevel[] profileLevels;
   }
@@ -24311,6 +24272,33 @@
     field public static final int AACObjectSSR = 3; // 0x3
     field public static final int AACObjectScalable = 6; // 0x6
     field public static final int AACObjectXHE = 42; // 0x2a
+    field public static final int AV1Level2 = 1; // 0x1
+    field public static final int AV1Level21 = 2; // 0x2
+    field public static final int AV1Level22 = 4; // 0x4
+    field public static final int AV1Level23 = 8; // 0x8
+    field public static final int AV1Level3 = 16; // 0x10
+    field public static final int AV1Level31 = 32; // 0x20
+    field public static final int AV1Level32 = 64; // 0x40
+    field public static final int AV1Level33 = 128; // 0x80
+    field public static final int AV1Level4 = 256; // 0x100
+    field public static final int AV1Level41 = 512; // 0x200
+    field public static final int AV1Level42 = 1024; // 0x400
+    field public static final int AV1Level43 = 2048; // 0x800
+    field public static final int AV1Level5 = 4096; // 0x1000
+    field public static final int AV1Level51 = 8192; // 0x2000
+    field public static final int AV1Level52 = 16384; // 0x4000
+    field public static final int AV1Level53 = 32768; // 0x8000
+    field public static final int AV1Level6 = 65536; // 0x10000
+    field public static final int AV1Level61 = 131072; // 0x20000
+    field public static final int AV1Level62 = 262144; // 0x40000
+    field public static final int AV1Level63 = 524288; // 0x80000
+    field public static final int AV1Level7 = 1048576; // 0x100000
+    field public static final int AV1Level71 = 2097152; // 0x200000
+    field public static final int AV1Level72 = 4194304; // 0x400000
+    field public static final int AV1Level73 = 8388608; // 0x800000
+    field public static final int AV1Profile0 = 1; // 0x1
+    field public static final int AV1Profile1 = 2; // 0x2
+    field public static final int AV1Profile2 = 4; // 0x4
     field public static final int AVCLevel1 = 1; // 0x1
     field public static final int AVCLevel11 = 4; // 0x4
     field public static final int AVCLevel12 = 8; // 0x8
@@ -24328,6 +24316,9 @@
     field public static final int AVCLevel5 = 16384; // 0x4000
     field public static final int AVCLevel51 = 32768; // 0x8000
     field public static final int AVCLevel52 = 65536; // 0x10000
+    field public static final int AVCLevel6 = 131072; // 0x20000
+    field public static final int AVCLevel61 = 262144; // 0x40000
+    field public static final int AVCLevel62 = 524288; // 0x80000
     field public static final int AVCProfileBaseline = 1; // 0x1
     field public static final int AVCProfileConstrainedBaseline = 65536; // 0x10000
     field public static final int AVCProfileConstrainedHigh = 524288; // 0x80000
@@ -24483,41 +24474,101 @@
 
   public static final class MediaCodecInfo.VideoCapabilities {
     method public boolean areSizeAndRateSupported(int, int, double);
-    method public android.util.Range<java.lang.Double> getAchievableFrameRatesFor(int, int);
+    method @Nullable public android.util.Range<java.lang.Double> getAchievableFrameRatesFor(int, int);
     method public android.util.Range<java.lang.Integer> getBitrateRange();
     method public int getHeightAlignment();
     method public android.util.Range<java.lang.Integer> getSupportedFrameRates();
     method public android.util.Range<java.lang.Double> getSupportedFrameRatesFor(int, int);
     method public android.util.Range<java.lang.Integer> getSupportedHeights();
     method public android.util.Range<java.lang.Integer> getSupportedHeightsFor(int);
+    method @Nullable public java.util.List<android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint> getSupportedPerformancePoints();
     method public android.util.Range<java.lang.Integer> getSupportedWidths();
     method public android.util.Range<java.lang.Integer> getSupportedWidthsFor(int);
     method public int getWidthAlignment();
     method public boolean isSizeSupported(int, int);
   }
 
+  public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
+    method public boolean covers(@NonNull android.media.MediaFormat);
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_24;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_240;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_25;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_30;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_50;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_60;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_100;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_120;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_200;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_24;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_240;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_25;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_30;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_50;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_60;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_24;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_25;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_30;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_48;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_50;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_60;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_100;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_120;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_200;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_24;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_240;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_25;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_30;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50;
+    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60;
+    field public final int frameRate;
+    field public final int height;
+    field public final int width;
+  }
+
   public final class MediaCodecList {
     ctor public MediaCodecList(int);
-    method public java.lang.String findDecoderForFormat(android.media.MediaFormat);
-    method public java.lang.String findEncoderForFormat(android.media.MediaFormat);
-    method public static deprecated int getCodecCount();
-    method public static deprecated android.media.MediaCodecInfo getCodecInfoAt(int);
+    method public String findDecoderForFormat(android.media.MediaFormat);
+    method public String findEncoderForFormat(android.media.MediaFormat);
+    method @Deprecated public static int getCodecCount();
+    method @Deprecated public static android.media.MediaCodecInfo getCodecInfoAt(int);
     method public android.media.MediaCodecInfo[] getCodecInfos();
     field public static final int ALL_CODECS = 1; // 0x1
     field public static final int REGULAR_CODECS = 0; // 0x0
   }
 
+  public class MediaController2 implements java.lang.AutoCloseable {
+    ctor public MediaController2(@NonNull android.content.Context, @NonNull android.media.Session2Token);
+    ctor public MediaController2(@NonNull android.content.Context, @NonNull android.media.Session2Token, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaController2.ControllerCallback);
+    method public void cancelSessionCommand(@NonNull Object);
+    method public void close();
+    method public android.media.Session2Token getConnectedSessionToken();
+    method public boolean isPlaybackActive();
+    method @NonNull public Object sendSessionCommand(@NonNull android.media.Session2Command, @Nullable android.os.Bundle);
+  }
+
+  public abstract static class MediaController2.ControllerCallback {
+    ctor public MediaController2.ControllerCallback();
+    method public void onCommandResult(@NonNull android.media.MediaController2, @NonNull Object, @NonNull android.media.Session2Command, @NonNull android.media.Session2Command.Result);
+    method public void onConnected(@NonNull android.media.MediaController2, @NonNull android.media.Session2CommandGroup);
+    method public void onDisconnected(@NonNull android.media.MediaController2);
+    method public void onPlaybackActiveChanged(@NonNull android.media.MediaController2, boolean);
+    method @Nullable public android.media.Session2Command.Result onSessionCommand(@NonNull android.media.MediaController2, @NonNull android.media.Session2Command, @Nullable android.os.Bundle);
+  }
+
   public final class MediaCrypto {
-    ctor public MediaCrypto(java.util.UUID, byte[]) throws android.media.MediaCryptoException;
+    ctor public MediaCrypto(@NonNull java.util.UUID, @NonNull byte[]) throws android.media.MediaCryptoException;
     method protected void finalize();
-    method public static boolean isCryptoSchemeSupported(java.util.UUID);
+    method public static boolean isCryptoSchemeSupported(@NonNull java.util.UUID);
     method public void release();
-    method public boolean requiresSecureDecoderComponent(java.lang.String);
-    method public void setMediaDrmSession(byte[]) throws android.media.MediaCryptoException;
+    method public boolean requiresSecureDecoderComponent(@NonNull String);
+    method public void setMediaDrmSession(@NonNull byte[]) throws android.media.MediaCryptoException;
   }
 
   public final class MediaCryptoException extends java.lang.Exception {
-    ctor public MediaCryptoException(java.lang.String);
+    ctor public MediaCryptoException(@Nullable String);
   }
 
   public abstract class MediaDataSource implements java.io.Closeable {
@@ -24529,10 +24580,10 @@
   public final class MediaDescrambler implements java.lang.AutoCloseable {
     ctor public MediaDescrambler(int) throws android.media.MediaCasException.UnsupportedCasException;
     method public void close();
-    method public int descramble(java.nio.ByteBuffer, java.nio.ByteBuffer, android.media.MediaCodec.CryptoInfo);
+    method public int descramble(@NonNull java.nio.ByteBuffer, @NonNull java.nio.ByteBuffer, @NonNull android.media.MediaCodec.CryptoInfo);
     method protected void finalize();
-    method public boolean requiresSecureDecoderComponent(java.lang.String);
-    method public void setMediaCasSession(android.media.MediaCas.Session);
+    method public boolean requiresSecureDecoderComponent(@NonNull String);
+    method public void setMediaCasSession(@NonNull android.media.MediaCas.Session);
     field public static final byte SCRAMBLE_CONTROL_EVEN_KEY = 2; // 0x2
     field public static final byte SCRAMBLE_CONTROL_ODD_KEY = 3; // 0x3
     field public static final byte SCRAMBLE_CONTROL_RESERVED = 1; // 0x1
@@ -24542,14 +24593,14 @@
 
   public class MediaDescription implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.CharSequence getDescription();
-    method public android.os.Bundle getExtras();
-    method public android.graphics.Bitmap getIconBitmap();
-    method public android.net.Uri getIconUri();
-    method public java.lang.String getMediaId();
-    method public android.net.Uri getMediaUri();
-    method public java.lang.CharSequence getSubtitle();
-    method public java.lang.CharSequence getTitle();
+    method @Nullable public CharSequence getDescription();
+    method @Nullable public android.os.Bundle getExtras();
+    method @Nullable public android.graphics.Bitmap getIconBitmap();
+    method @Nullable public android.net.Uri getIconUri();
+    method @Nullable public String getMediaId();
+    method @Nullable public android.net.Uri getMediaUri();
+    method @Nullable public CharSequence getSubtitle();
+    method @Nullable public CharSequence getTitle();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final long BT_FOLDER_TYPE_ALBUMS = 2L; // 0x2L
     field public static final long BT_FOLDER_TYPE_ARTISTS = 3L; // 0x3L
@@ -24559,66 +24610,68 @@
     field public static final long BT_FOLDER_TYPE_TITLES = 1L; // 0x1L
     field public static final long BT_FOLDER_TYPE_YEARS = 6L; // 0x6L
     field public static final android.os.Parcelable.Creator<android.media.MediaDescription> CREATOR;
-    field public static final java.lang.String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
+    field public static final String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
   }
 
   public static class MediaDescription.Builder {
     ctor public MediaDescription.Builder();
     method public android.media.MediaDescription build();
-    method public android.media.MediaDescription.Builder setDescription(java.lang.CharSequence);
-    method public android.media.MediaDescription.Builder setExtras(android.os.Bundle);
-    method public android.media.MediaDescription.Builder setIconBitmap(android.graphics.Bitmap);
-    method public android.media.MediaDescription.Builder setIconUri(android.net.Uri);
-    method public android.media.MediaDescription.Builder setMediaId(java.lang.String);
-    method public android.media.MediaDescription.Builder setMediaUri(android.net.Uri);
-    method public android.media.MediaDescription.Builder setSubtitle(java.lang.CharSequence);
-    method public android.media.MediaDescription.Builder setTitle(java.lang.CharSequence);
+    method public android.media.MediaDescription.Builder setDescription(@Nullable CharSequence);
+    method public android.media.MediaDescription.Builder setExtras(@Nullable android.os.Bundle);
+    method public android.media.MediaDescription.Builder setIconBitmap(@Nullable android.graphics.Bitmap);
+    method public android.media.MediaDescription.Builder setIconUri(@Nullable android.net.Uri);
+    method public android.media.MediaDescription.Builder setMediaId(@Nullable String);
+    method public android.media.MediaDescription.Builder setMediaUri(@Nullable android.net.Uri);
+    method public android.media.MediaDescription.Builder setSubtitle(@Nullable CharSequence);
+    method public android.media.MediaDescription.Builder setTitle(@Nullable CharSequence);
   }
 
   public final class MediaDrm implements java.lang.AutoCloseable {
-    ctor public MediaDrm(java.util.UUID) throws android.media.UnsupportedSchemeException;
+    ctor public MediaDrm(@NonNull java.util.UUID) throws android.media.UnsupportedSchemeException;
     method public void close();
-    method public void closeSession(byte[]);
-    method public int getConnectedHdcpLevel();
-    method public android.media.MediaDrm.CryptoSession getCryptoSession(byte[], java.lang.String, java.lang.String);
-    method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>) throws android.media.NotProvisionedException;
-    method public int getMaxHdcpLevel();
+    method public void closeSession(@NonNull byte[]);
+    method @android.media.MediaDrm.HdcpLevel public int getConnectedHdcpLevel();
+    method public android.media.MediaDrm.CryptoSession getCryptoSession(@NonNull byte[], @NonNull String, @NonNull String);
+    method @NonNull public android.media.MediaDrm.KeyRequest getKeyRequest(@NonNull byte[], @Nullable byte[], @Nullable String, int, @Nullable java.util.HashMap<java.lang.String,java.lang.String>) throws android.media.NotProvisionedException;
+    method @android.media.MediaDrm.HdcpLevel public int getMaxHdcpLevel();
     method public static int getMaxSecurityLevel();
     method public int getMaxSessionCount();
     method public android.os.PersistableBundle getMetrics();
-    method public java.util.List<byte[]> getOfflineLicenseKeySetIds();
-    method public int getOfflineLicenseState(byte[]);
+    method @NonNull public java.util.List<byte[]> getOfflineLicenseKeySetIds();
+    method public int getOfflineLicenseState(@NonNull byte[]);
     method public int getOpenSessionCount();
-    method public byte[] getPropertyByteArray(java.lang.String);
-    method public java.lang.String getPropertyString(java.lang.String);
-    method public android.media.MediaDrm.ProvisionRequest getProvisionRequest();
-    method public byte[] getSecureStop(byte[]);
-    method public java.util.List<byte[]> getSecureStopIds();
-    method public java.util.List<byte[]> getSecureStops();
-    method public int getSecurityLevel(byte[]);
-    method public static boolean isCryptoSchemeSupported(java.util.UUID);
-    method public static boolean isCryptoSchemeSupported(java.util.UUID, java.lang.String);
-    method public byte[] openSession() throws android.media.NotProvisionedException, android.media.ResourceBusyException;
-    method public byte[] openSession(int) throws android.media.NotProvisionedException, android.media.ResourceBusyException;
-    method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.NotProvisionedException;
-    method public void provideProvisionResponse(byte[]) throws android.media.DeniedByServerException;
-    method public java.util.HashMap<java.lang.String, java.lang.String> queryKeyStatus(byte[]);
-    method public deprecated void release();
-    method public deprecated void releaseAllSecureStops();
-    method public void releaseSecureStops(byte[]);
+    method @NonNull public byte[] getPropertyByteArray(String);
+    method @NonNull public String getPropertyString(@NonNull String);
+    method @NonNull public android.media.MediaDrm.ProvisionRequest getProvisionRequest();
+    method @NonNull public byte[] getSecureStop(@NonNull byte[]);
+    method @NonNull public java.util.List<byte[]> getSecureStopIds();
+    method @NonNull public java.util.List<byte[]> getSecureStops();
+    method @android.media.MediaDrm.SecurityLevel public int getSecurityLevel(@NonNull byte[]);
+    method public static boolean isCryptoSchemeSupported(@NonNull java.util.UUID);
+    method public static boolean isCryptoSchemeSupported(@NonNull java.util.UUID, @NonNull String);
+    method public static boolean isCryptoSchemeSupported(@NonNull java.util.UUID, @NonNull String, @android.media.MediaDrm.SecurityLevel int);
+    method @NonNull public byte[] openSession() throws android.media.NotProvisionedException, android.media.ResourceBusyException;
+    method @NonNull public byte[] openSession(@android.media.MediaDrm.SecurityLevel int) throws android.media.NotProvisionedException, android.media.ResourceBusyException;
+    method @Nullable public byte[] provideKeyResponse(@NonNull byte[], @NonNull byte[]) throws android.media.DeniedByServerException, android.media.NotProvisionedException;
+    method public void provideProvisionResponse(@NonNull byte[]) throws android.media.DeniedByServerException;
+    method @NonNull public java.util.HashMap<java.lang.String,java.lang.String> queryKeyStatus(@NonNull byte[]);
+    method @Deprecated public void release();
+    method @Deprecated public void releaseAllSecureStops();
+    method public void releaseSecureStops(@NonNull byte[]);
     method public void removeAllSecureStops();
-    method public void removeKeys(byte[]);
-    method public void removeOfflineLicense(byte[]);
-    method public void removeSecureStop(byte[]);
-    method public void restoreKeys(byte[], byte[]);
-    method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
-    method public void setOnExpirationUpdateListener(android.media.MediaDrm.OnExpirationUpdateListener, android.os.Handler);
-    method public void setOnKeyStatusChangeListener(android.media.MediaDrm.OnKeyStatusChangeListener, android.os.Handler);
-    method public void setPropertyByteArray(java.lang.String, byte[]);
-    method public void setPropertyString(java.lang.String, java.lang.String);
-    field public static final deprecated int EVENT_KEY_EXPIRED = 3; // 0x3
+    method public void removeKeys(@NonNull byte[]);
+    method public void removeOfflineLicense(@NonNull byte[]);
+    method public void removeSecureStop(@NonNull byte[]);
+    method public void restoreKeys(@NonNull byte[], @NonNull byte[]);
+    method public void setOnEventListener(@Nullable android.media.MediaDrm.OnEventListener);
+    method public void setOnExpirationUpdateListener(@Nullable android.media.MediaDrm.OnExpirationUpdateListener, @Nullable android.os.Handler);
+    method public void setOnKeyStatusChangeListener(@Nullable android.media.MediaDrm.OnKeyStatusChangeListener, @Nullable android.os.Handler);
+    method public void setOnSessionLostStateListener(@Nullable android.media.MediaDrm.OnSessionLostStateListener, @Nullable android.os.Handler);
+    method public void setPropertyByteArray(@NonNull String, @NonNull byte[]);
+    method public void setPropertyString(@NonNull String, @NonNull String);
+    field @Deprecated public static final int EVENT_KEY_EXPIRED = 3; // 0x3
     field public static final int EVENT_KEY_REQUIRED = 2; // 0x2
-    field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1
+    field @Deprecated public static final int EVENT_PROVISION_REQUIRED = 1; // 0x1
     field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
     field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
     field public static final int HDCP_LEVEL_UNKNOWN = 0; // 0x0
@@ -24628,17 +24681,18 @@
     field public static final int HDCP_V2 = 3; // 0x3
     field public static final int HDCP_V2_1 = 4; // 0x4
     field public static final int HDCP_V2_2 = 5; // 0x5
+    field public static final int HDCP_V2_3 = 6; // 0x6
     field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
     field public static final int KEY_TYPE_RELEASE = 3; // 0x3
     field public static final int KEY_TYPE_STREAMING = 1; // 0x1
     field public static final int OFFLINE_LICENSE_INACTIVE = 2; // 0x2
     field public static final int OFFLINE_LICENSE_STATE_UNKNOWN = 0; // 0x0
     field public static final int OFFLINE_LICENSE_USABLE = 1; // 0x1
-    field public static final java.lang.String PROPERTY_ALGORITHMS = "algorithms";
-    field public static final java.lang.String PROPERTY_DESCRIPTION = "description";
-    field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
-    field public static final java.lang.String PROPERTY_VENDOR = "vendor";
-    field public static final java.lang.String PROPERTY_VERSION = "version";
+    field public static final String PROPERTY_ALGORITHMS = "algorithms";
+    field public static final String PROPERTY_DESCRIPTION = "description";
+    field public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
+    field public static final String PROPERTY_VENDOR = "vendor";
+    field public static final String PROPERTY_VERSION = "version";
     field public static final int SECURITY_LEVEL_HW_SECURE_ALL = 5; // 0x5
     field public static final int SECURITY_LEVEL_HW_SECURE_CRYPTO = 3; // 0x3
     field public static final int SECURITY_LEVEL_HW_SECURE_DECODE = 4; // 0x4
@@ -24648,18 +24702,18 @@
   }
 
   public final class MediaDrm.CryptoSession {
-    method public byte[] decrypt(byte[], byte[], byte[]);
-    method public byte[] encrypt(byte[], byte[], byte[]);
-    method public byte[] sign(byte[], byte[]);
-    method public boolean verify(byte[], byte[], byte[]);
+    method @NonNull public byte[] decrypt(@NonNull byte[], @NonNull byte[], @NonNull byte[]);
+    method @NonNull public byte[] encrypt(@NonNull byte[], @NonNull byte[], @NonNull byte[]);
+    method @NonNull public byte[] sign(@NonNull byte[], @NonNull byte[]);
+    method public boolean verify(@NonNull byte[], @NonNull byte[], @NonNull byte[]);
   }
 
-  public static abstract class MediaDrm.HdcpLevel implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.media.MediaDrm.HDCP_LEVEL_UNKNOWN, android.media.MediaDrm.HDCP_NONE, android.media.MediaDrm.HDCP_V1, android.media.MediaDrm.HDCP_V2, android.media.MediaDrm.HDCP_V2_1, android.media.MediaDrm.HDCP_V2_2, android.media.MediaDrm.HDCP_V2_3, android.media.MediaDrm.HDCP_NO_DIGITAL_OUTPUT}) public static @interface MediaDrm.HdcpLevel {
   }
 
   public static final class MediaDrm.KeyRequest {
-    method public byte[] getData();
-    method public java.lang.String getDefaultUrl();
+    method @NonNull public byte[] getData();
+    method @NonNull public String getDefaultUrl();
     method public int getRequestType();
     field public static final int REQUEST_TYPE_INITIAL = 0; // 0x0
     field public static final int REQUEST_TYPE_NONE = 3; // 0x3
@@ -24669,7 +24723,7 @@
   }
 
   public static final class MediaDrm.KeyStatus {
-    method public byte[] getKeyId();
+    method @NonNull public byte[] getKeyId();
     method public int getStatusCode();
     field public static final int STATUS_EXPIRED = 1; // 0x1
     field public static final int STATUS_INTERNAL_ERROR = 4; // 0x4
@@ -24679,105 +24733,115 @@
   }
 
   public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
-    method public java.lang.String getDiagnosticInfo();
+    method @NonNull public String getDiagnosticInfo();
   }
 
   public static final class MediaDrm.MetricsConstants {
-    field public static final java.lang.String CLOSE_SESSION_ERROR_COUNT = "drm.mediadrm.close_session.error.count";
-    field public static final java.lang.String CLOSE_SESSION_ERROR_LIST = "drm.mediadrm.close_session.error.list";
-    field public static final java.lang.String CLOSE_SESSION_OK_COUNT = "drm.mediadrm.close_session.ok.count";
-    field public static final java.lang.String EVENT_KEY_EXPIRED_COUNT = "drm.mediadrm.event.KEY_EXPIRED.count";
-    field public static final java.lang.String EVENT_KEY_NEEDED_COUNT = "drm.mediadrm.event.KEY_NEEDED.count";
-    field public static final java.lang.String EVENT_PROVISION_REQUIRED_COUNT = "drm.mediadrm.event.PROVISION_REQUIRED.count";
-    field public static final java.lang.String EVENT_SESSION_RECLAIMED_COUNT = "drm.mediadrm.event.SESSION_RECLAIMED.count";
-    field public static final java.lang.String EVENT_VENDOR_DEFINED_COUNT = "drm.mediadrm.event.VENDOR_DEFINED.count";
-    field public static final java.lang.String GET_DEVICE_UNIQUE_ID_ERROR_COUNT = "drm.mediadrm.get_device_unique_id.error.count";
-    field public static final java.lang.String GET_DEVICE_UNIQUE_ID_ERROR_LIST = "drm.mediadrm.get_device_unique_id.error.list";
-    field public static final java.lang.String GET_DEVICE_UNIQUE_ID_OK_COUNT = "drm.mediadrm.get_device_unique_id.ok.count";
-    field public static final java.lang.String GET_KEY_REQUEST_ERROR_COUNT = "drm.mediadrm.get_key_request.error.count";
-    field public static final java.lang.String GET_KEY_REQUEST_ERROR_LIST = "drm.mediadrm.get_key_request.error.list";
-    field public static final java.lang.String GET_KEY_REQUEST_OK_COUNT = "drm.mediadrm.get_key_request.ok.count";
-    field public static final java.lang.String GET_KEY_REQUEST_OK_TIME_MICROS = "drm.mediadrm.get_key_request.ok.average_time_micros";
-    field public static final java.lang.String GET_PROVISION_REQUEST_ERROR_COUNT = "drm.mediadrm.get_provision_request.error.count";
-    field public static final java.lang.String GET_PROVISION_REQUEST_ERROR_LIST = "drm.mediadrm.get_provision_request.error.list";
-    field public static final java.lang.String GET_PROVISION_REQUEST_OK_COUNT = "drm.mediadrm.get_provision_request.ok.count";
-    field public static final java.lang.String KEY_STATUS_EXPIRED_COUNT = "drm.mediadrm.key_status.EXPIRED.count";
-    field public static final java.lang.String KEY_STATUS_INTERNAL_ERROR_COUNT = "drm.mediadrm.key_status.INTERNAL_ERROR.count";
-    field public static final java.lang.String KEY_STATUS_OUTPUT_NOT_ALLOWED_COUNT = "drm.mediadrm.key_status_change.OUTPUT_NOT_ALLOWED.count";
-    field public static final java.lang.String KEY_STATUS_PENDING_COUNT = "drm.mediadrm.key_status_change.PENDING.count";
-    field public static final java.lang.String KEY_STATUS_USABLE_COUNT = "drm.mediadrm.key_status_change.USABLE.count";
-    field public static final java.lang.String OPEN_SESSION_ERROR_COUNT = "drm.mediadrm.open_session.error.count";
-    field public static final java.lang.String OPEN_SESSION_ERROR_LIST = "drm.mediadrm.open_session.error.list";
-    field public static final java.lang.String OPEN_SESSION_OK_COUNT = "drm.mediadrm.open_session.ok.count";
-    field public static final java.lang.String PROVIDE_KEY_RESPONSE_ERROR_COUNT = "drm.mediadrm.provide_key_response.error.count";
-    field public static final java.lang.String PROVIDE_KEY_RESPONSE_ERROR_LIST = "drm.mediadrm.provide_key_response.error.list";
-    field public static final java.lang.String PROVIDE_KEY_RESPONSE_OK_COUNT = "drm.mediadrm.provide_key_response.ok.count";
-    field public static final java.lang.String PROVIDE_KEY_RESPONSE_OK_TIME_MICROS = "drm.mediadrm.provide_key_response.ok.average_time_micros";
-    field public static final java.lang.String PROVIDE_PROVISION_RESPONSE_ERROR_COUNT = "drm.mediadrm.provide_provision_response.error.count";
-    field public static final java.lang.String PROVIDE_PROVISION_RESPONSE_ERROR_LIST = "drm.mediadrm.provide_provision_response.error.list";
-    field public static final java.lang.String PROVIDE_PROVISION_RESPONSE_OK_COUNT = "drm.mediadrm.provide_provision_response.ok.count";
-    field public static final java.lang.String SESSION_END_TIMES_MS = "drm.mediadrm.session_end_times_ms";
-    field public static final java.lang.String SESSION_START_TIMES_MS = "drm.mediadrm.session_start_times_ms";
+    field public static final String CLOSE_SESSION_ERROR_COUNT = "drm.mediadrm.close_session.error.count";
+    field public static final String CLOSE_SESSION_ERROR_LIST = "drm.mediadrm.close_session.error.list";
+    field public static final String CLOSE_SESSION_OK_COUNT = "drm.mediadrm.close_session.ok.count";
+    field public static final String EVENT_KEY_EXPIRED_COUNT = "drm.mediadrm.event.KEY_EXPIRED.count";
+    field public static final String EVENT_KEY_NEEDED_COUNT = "drm.mediadrm.event.KEY_NEEDED.count";
+    field public static final String EVENT_PROVISION_REQUIRED_COUNT = "drm.mediadrm.event.PROVISION_REQUIRED.count";
+    field public static final String EVENT_SESSION_RECLAIMED_COUNT = "drm.mediadrm.event.SESSION_RECLAIMED.count";
+    field public static final String EVENT_VENDOR_DEFINED_COUNT = "drm.mediadrm.event.VENDOR_DEFINED.count";
+    field public static final String GET_DEVICE_UNIQUE_ID_ERROR_COUNT = "drm.mediadrm.get_device_unique_id.error.count";
+    field public static final String GET_DEVICE_UNIQUE_ID_ERROR_LIST = "drm.mediadrm.get_device_unique_id.error.list";
+    field public static final String GET_DEVICE_UNIQUE_ID_OK_COUNT = "drm.mediadrm.get_device_unique_id.ok.count";
+    field public static final String GET_KEY_REQUEST_ERROR_COUNT = "drm.mediadrm.get_key_request.error.count";
+    field public static final String GET_KEY_REQUEST_ERROR_LIST = "drm.mediadrm.get_key_request.error.list";
+    field public static final String GET_KEY_REQUEST_OK_COUNT = "drm.mediadrm.get_key_request.ok.count";
+    field public static final String GET_KEY_REQUEST_OK_TIME_MICROS = "drm.mediadrm.get_key_request.ok.average_time_micros";
+    field public static final String GET_PROVISION_REQUEST_ERROR_COUNT = "drm.mediadrm.get_provision_request.error.count";
+    field public static final String GET_PROVISION_REQUEST_ERROR_LIST = "drm.mediadrm.get_provision_request.error.list";
+    field public static final String GET_PROVISION_REQUEST_OK_COUNT = "drm.mediadrm.get_provision_request.ok.count";
+    field public static final String KEY_STATUS_EXPIRED_COUNT = "drm.mediadrm.key_status.EXPIRED.count";
+    field public static final String KEY_STATUS_INTERNAL_ERROR_COUNT = "drm.mediadrm.key_status.INTERNAL_ERROR.count";
+    field public static final String KEY_STATUS_OUTPUT_NOT_ALLOWED_COUNT = "drm.mediadrm.key_status_change.OUTPUT_NOT_ALLOWED.count";
+    field public static final String KEY_STATUS_PENDING_COUNT = "drm.mediadrm.key_status_change.PENDING.count";
+    field public static final String KEY_STATUS_USABLE_COUNT = "drm.mediadrm.key_status_change.USABLE.count";
+    field public static final String OPEN_SESSION_ERROR_COUNT = "drm.mediadrm.open_session.error.count";
+    field public static final String OPEN_SESSION_ERROR_LIST = "drm.mediadrm.open_session.error.list";
+    field public static final String OPEN_SESSION_OK_COUNT = "drm.mediadrm.open_session.ok.count";
+    field public static final String PROVIDE_KEY_RESPONSE_ERROR_COUNT = "drm.mediadrm.provide_key_response.error.count";
+    field public static final String PROVIDE_KEY_RESPONSE_ERROR_LIST = "drm.mediadrm.provide_key_response.error.list";
+    field public static final String PROVIDE_KEY_RESPONSE_OK_COUNT = "drm.mediadrm.provide_key_response.ok.count";
+    field public static final String PROVIDE_KEY_RESPONSE_OK_TIME_MICROS = "drm.mediadrm.provide_key_response.ok.average_time_micros";
+    field public static final String PROVIDE_PROVISION_RESPONSE_ERROR_COUNT = "drm.mediadrm.provide_provision_response.error.count";
+    field public static final String PROVIDE_PROVISION_RESPONSE_ERROR_LIST = "drm.mediadrm.provide_provision_response.error.list";
+    field public static final String PROVIDE_PROVISION_RESPONSE_OK_COUNT = "drm.mediadrm.provide_provision_response.ok.count";
+    field public static final String SESSION_END_TIMES_MS = "drm.mediadrm.session_end_times_ms";
+    field public static final String SESSION_START_TIMES_MS = "drm.mediadrm.session_start_times_ms";
   }
 
-  public static abstract interface MediaDrm.OnEventListener {
-    method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
+  public static interface MediaDrm.OnEventListener {
+    method public void onEvent(@NonNull android.media.MediaDrm, @Nullable byte[], int, int, @Nullable byte[]);
   }
 
-  public static abstract interface MediaDrm.OnExpirationUpdateListener {
-    method public abstract void onExpirationUpdate(android.media.MediaDrm, byte[], long);
+  public static interface MediaDrm.OnExpirationUpdateListener {
+    method public void onExpirationUpdate(@NonNull android.media.MediaDrm, @NonNull byte[], long);
   }
 
-  public static abstract interface MediaDrm.OnKeyStatusChangeListener {
-    method public abstract void onKeyStatusChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean);
+  public static interface MediaDrm.OnKeyStatusChangeListener {
+    method public void onKeyStatusChange(@NonNull android.media.MediaDrm, @NonNull byte[], @NonNull java.util.List<android.media.MediaDrm.KeyStatus>, boolean);
+  }
+
+  public static interface MediaDrm.OnSessionLostStateListener {
+    method public void onSessionLostState(@NonNull android.media.MediaDrm, @NonNull byte[]);
   }
 
   public static final class MediaDrm.ProvisionRequest {
-    method public byte[] getData();
-    method public java.lang.String getDefaultUrl();
+    method @NonNull public byte[] getData();
+    method @NonNull public String getDefaultUrl();
   }
 
-  public static abstract class MediaDrm.SecurityLevel implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.media.MediaDrm.SECURITY_LEVEL_UNKNOWN, android.media.MediaDrm.SECURITY_LEVEL_SW_SECURE_CRYPTO, android.media.MediaDrm.SECURITY_LEVEL_SW_SECURE_DECODE, android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_CRYPTO, android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_DECODE, android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_ALL}) public static @interface MediaDrm.SecurityLevel {
+  }
+
+  public static final class MediaDrm.SessionException extends java.lang.RuntimeException {
+    ctor public MediaDrm.SessionException(int, @Nullable String);
+    method public int getErrorCode();
+    field public static final int ERROR_RESOURCE_CONTENTION = 1; // 0x1
   }
 
   public class MediaDrmException extends java.lang.Exception {
-    ctor public MediaDrmException(java.lang.String);
+    ctor public MediaDrmException(String);
   }
 
   public class MediaDrmResetException extends java.lang.IllegalStateException {
-    ctor public MediaDrmResetException(java.lang.String);
+    ctor public MediaDrmResetException(String);
   }
 
   public final class MediaExtractor {
     ctor public MediaExtractor();
     method public boolean advance();
     method protected void finalize();
-    method public java.util.List<android.media.AudioPresentation> getAudioPresentations(int);
+    method @NonNull public java.util.List<android.media.AudioPresentation> getAudioPresentations(int);
     method public long getCachedDuration();
     method public android.media.MediaExtractor.CasInfo getCasInfo(int);
     method public android.media.DrmInitData getDrmInitData();
     method public android.os.PersistableBundle getMetrics();
-    method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
-    method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
+    method @Nullable public java.util.Map<java.util.UUID,byte[]> getPsshInfo();
+    method public boolean getSampleCryptoInfo(@NonNull android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
     method public long getSampleSize();
     method public long getSampleTime();
     method public int getSampleTrackIndex();
     method public int getTrackCount();
-    method public android.media.MediaFormat getTrackFormat(int);
+    method @NonNull public android.media.MediaFormat getTrackFormat(int);
     method public boolean hasCacheReachedEndOfStream();
-    method public int readSampleData(java.nio.ByteBuffer, int);
+    method public int readSampleData(@NonNull java.nio.ByteBuffer, int);
     method public void release();
     method public void seekTo(long, int);
     method public void selectTrack(int);
-    method public void setDataSource(android.media.MediaDataSource) throws java.io.IOException;
-    method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
-    method public void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
-    method public void setDataSource(java.lang.String) throws java.io.IOException;
-    method public void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException;
-    method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException;
-    method public void setMediaCas(android.media.MediaCas);
+    method public void setDataSource(@NonNull android.media.MediaDataSource) throws java.io.IOException;
+    method public void setDataSource(@NonNull android.content.Context, @NonNull android.net.Uri, @Nullable java.util.Map<java.lang.String,java.lang.String>) throws java.io.IOException;
+    method public void setDataSource(@NonNull String, @Nullable java.util.Map<java.lang.String,java.lang.String>) throws java.io.IOException;
+    method public void setDataSource(@NonNull String) throws java.io.IOException;
+    method public void setDataSource(@NonNull android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void setDataSource(@NonNull java.io.FileDescriptor) throws java.io.IOException;
+    method public void setDataSource(@NonNull java.io.FileDescriptor, long, long) throws java.io.IOException;
+    method public void setMediaCas(@NonNull android.media.MediaCas);
     method public void unselectTrack(int);
     field public static final int SAMPLE_FLAG_ENCRYPTED = 2; // 0x2
     field public static final int SAMPLE_FLAG_PARTIAL_FRAME = 4; // 0x4
@@ -24788,49 +24852,49 @@
   }
 
   public static final class MediaExtractor.CasInfo {
-    method public byte[] getPrivateData();
+    method @Nullable public byte[] getPrivateData();
     method public android.media.MediaCas.Session getSession();
     method public int getSystemId();
   }
 
   public static final class MediaExtractor.MetricsConstants {
-    field public static final java.lang.String FORMAT = "android.media.mediaextractor.fmt";
-    field public static final java.lang.String MIME_TYPE = "android.media.mediaextractor.mime";
-    field public static final java.lang.String TRACKS = "android.media.mediaextractor.ntrk";
+    field public static final String FORMAT = "android.media.mediaextractor.fmt";
+    field public static final String MIME_TYPE = "android.media.mediaextractor.mime";
+    field public static final String TRACKS = "android.media.mediaextractor.ntrk";
   }
 
   public final class MediaFormat {
     ctor public MediaFormat();
-    ctor public MediaFormat(android.media.MediaFormat);
-    method public boolean containsFeature(java.lang.String);
-    method public boolean containsKey(java.lang.String);
-    method public static android.media.MediaFormat createAudioFormat(java.lang.String, int, int);
-    method public static android.media.MediaFormat createSubtitleFormat(java.lang.String, java.lang.String);
-    method public static android.media.MediaFormat createVideoFormat(java.lang.String, int, int);
-    method public java.nio.ByteBuffer getByteBuffer(java.lang.String);
-    method public java.nio.ByteBuffer getByteBuffer(java.lang.String, java.nio.ByteBuffer);
-    method public boolean getFeatureEnabled(java.lang.String);
-    method public java.util.Set<java.lang.String> getFeatures();
-    method public float getFloat(java.lang.String);
-    method public float getFloat(java.lang.String, float);
-    method public int getInteger(java.lang.String);
-    method public int getInteger(java.lang.String, int);
-    method public java.util.Set<java.lang.String> getKeys();
-    method public long getLong(java.lang.String);
-    method public long getLong(java.lang.String, long);
-    method public java.lang.Number getNumber(java.lang.String);
-    method public java.lang.Number getNumber(java.lang.String, java.lang.Number);
-    method public java.lang.String getString(java.lang.String);
-    method public java.lang.String getString(java.lang.String, java.lang.String);
-    method public int getValueTypeForKey(java.lang.String);
-    method public void removeFeature(java.lang.String);
-    method public void removeKey(java.lang.String);
-    method public void setByteBuffer(java.lang.String, java.nio.ByteBuffer);
-    method public void setFeatureEnabled(java.lang.String, boolean);
-    method public void setFloat(java.lang.String, float);
-    method public void setInteger(java.lang.String, int);
-    method public void setLong(java.lang.String, long);
-    method public void setString(java.lang.String, java.lang.String);
+    ctor public MediaFormat(@NonNull android.media.MediaFormat);
+    method public boolean containsFeature(@NonNull String);
+    method public boolean containsKey(@NonNull String);
+    method @NonNull public static android.media.MediaFormat createAudioFormat(@NonNull String, int, int);
+    method @NonNull public static android.media.MediaFormat createSubtitleFormat(@NonNull String, String);
+    method @NonNull public static android.media.MediaFormat createVideoFormat(@NonNull String, int, int);
+    method @Nullable public java.nio.ByteBuffer getByteBuffer(@NonNull String);
+    method @NonNull public java.nio.ByteBuffer getByteBuffer(@NonNull String, @NonNull java.nio.ByteBuffer);
+    method public boolean getFeatureEnabled(@NonNull String);
+    method @NonNull public java.util.Set<java.lang.String> getFeatures();
+    method public float getFloat(@NonNull String);
+    method public float getFloat(@NonNull String, float);
+    method public int getInteger(@NonNull String);
+    method public int getInteger(@NonNull String, int);
+    method @NonNull public java.util.Set<java.lang.String> getKeys();
+    method public long getLong(@NonNull String);
+    method public long getLong(@NonNull String, long);
+    method @Nullable public Number getNumber(@NonNull String);
+    method @NonNull public Number getNumber(@NonNull String, @NonNull Number);
+    method @Nullable public String getString(@NonNull String);
+    method @NonNull public String getString(@NonNull String, @NonNull String);
+    method public int getValueTypeForKey(@NonNull String);
+    method public void removeFeature(@NonNull String);
+    method public void removeKey(@NonNull String);
+    method public void setByteBuffer(@NonNull String, @Nullable java.nio.ByteBuffer);
+    method public void setFeatureEnabled(@NonNull String, boolean);
+    method public void setFloat(@NonNull String, float);
+    method public void setInteger(@NonNull String, int);
+    method public void setLong(@NonNull String, long);
+    method public void setString(@NonNull String, @Nullable String);
     field public static final int COLOR_RANGE_FULL = 1; // 0x1
     field public static final int COLOR_RANGE_LIMITED = 2; // 0x2
     field public static final int COLOR_STANDARD_BT2020 = 6; // 0x6
@@ -24841,96 +24905,97 @@
     field public static final int COLOR_TRANSFER_LINEAR = 1; // 0x1
     field public static final int COLOR_TRANSFER_SDR_VIDEO = 3; // 0x3
     field public static final int COLOR_TRANSFER_ST2084 = 6; // 0x6
-    field public static final java.lang.String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level";
-    field public static final java.lang.String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level";
-    field public static final java.lang.String KEY_AAC_DRC_EFFECT_TYPE = "aac-drc-effect-type";
-    field public static final java.lang.String KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression";
-    field public static final java.lang.String KEY_AAC_DRC_TARGET_REFERENCE_LEVEL = "aac-target-ref-level";
-    field public static final java.lang.String KEY_AAC_ENCODED_TARGET_LEVEL = "aac-encoded-target-level";
-    field public static final java.lang.String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
-    field public static final java.lang.String KEY_AAC_PROFILE = "aac-profile";
-    field public static final java.lang.String KEY_AAC_SBR_MODE = "aac-sbr-mode";
-    field public static final java.lang.String KEY_AUDIO_SESSION_ID = "audio-session-id";
-    field public static final java.lang.String KEY_BITRATE_MODE = "bitrate-mode";
-    field public static final java.lang.String KEY_BIT_RATE = "bitrate";
-    field public static final java.lang.String KEY_CAPTURE_RATE = "capture-rate";
-    field public static final java.lang.String KEY_CHANNEL_COUNT = "channel-count";
-    field public static final java.lang.String KEY_CHANNEL_MASK = "channel-mask";
-    field public static final java.lang.String KEY_COLOR_FORMAT = "color-format";
-    field public static final java.lang.String KEY_COLOR_RANGE = "color-range";
-    field public static final java.lang.String KEY_COLOR_STANDARD = "color-standard";
-    field public static final java.lang.String KEY_COLOR_TRANSFER = "color-transfer";
-    field public static final java.lang.String KEY_COMPLEXITY = "complexity";
-    field public static final java.lang.String KEY_DURATION = "durationUs";
-    field public static final java.lang.String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
-    field public static final java.lang.String KEY_FRAME_RATE = "frame-rate";
-    field public static final java.lang.String KEY_GRID_COLUMNS = "grid-cols";
-    field public static final java.lang.String KEY_GRID_ROWS = "grid-rows";
-    field public static final java.lang.String KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
-    field public static final java.lang.String KEY_HDR_STATIC_INFO = "hdr-static-info";
-    field public static final java.lang.String KEY_HEIGHT = "height";
-    field public static final java.lang.String KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
-    field public static final java.lang.String KEY_IS_ADTS = "is-adts";
-    field public static final java.lang.String KEY_IS_AUTOSELECT = "is-autoselect";
-    field public static final java.lang.String KEY_IS_DEFAULT = "is-default";
-    field public static final java.lang.String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
-    field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
-    field public static final java.lang.String KEY_LANGUAGE = "language";
-    field public static final java.lang.String KEY_LATENCY = "latency";
-    field public static final java.lang.String KEY_LEVEL = "level";
-    field public static final java.lang.String KEY_MAX_HEIGHT = "max-height";
-    field public static final java.lang.String KEY_MAX_INPUT_SIZE = "max-input-size";
-    field public static final java.lang.String KEY_MAX_WIDTH = "max-width";
-    field public static final java.lang.String KEY_MIME = "mime";
-    field public static final java.lang.String KEY_OPERATING_RATE = "operating-rate";
-    field public static final java.lang.String KEY_OUTPUT_REORDER_DEPTH = "output-reorder-depth";
-    field public static final java.lang.String KEY_PCM_ENCODING = "pcm-encoding";
-    field public static final java.lang.String KEY_PRIORITY = "priority";
-    field public static final java.lang.String KEY_PROFILE = "profile";
-    field public static final java.lang.String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
-    field public static final java.lang.String KEY_QUALITY = "quality";
-    field public static final java.lang.String KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
-    field public static final java.lang.String KEY_ROTATION = "rotation-degrees";
-    field public static final java.lang.String KEY_SAMPLE_RATE = "sample-rate";
-    field public static final java.lang.String KEY_SLICE_HEIGHT = "slice-height";
-    field public static final java.lang.String KEY_STRIDE = "stride";
-    field public static final java.lang.String KEY_TEMPORAL_LAYERING = "ts-schema";
-    field public static final java.lang.String KEY_TILE_HEIGHT = "tile-height";
-    field public static final java.lang.String KEY_TILE_WIDTH = "tile-width";
-    field public static final java.lang.String KEY_TRACK_ID = "track-id";
-    field public static final java.lang.String KEY_WIDTH = "width";
-    field public static final java.lang.String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
-    field public static final java.lang.String MIMETYPE_AUDIO_AC3 = "audio/ac3";
-    field public static final java.lang.String MIMETYPE_AUDIO_AC4 = "audio/ac4";
-    field public static final java.lang.String MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
-    field public static final java.lang.String MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
-    field public static final java.lang.String MIMETYPE_AUDIO_EAC3 = "audio/eac3";
-    field public static final java.lang.String MIMETYPE_AUDIO_EAC3_JOC = "audio/eac3-joc";
-    field public static final java.lang.String MIMETYPE_AUDIO_FLAC = "audio/flac";
-    field public static final java.lang.String MIMETYPE_AUDIO_G711_ALAW = "audio/g711-alaw";
-    field public static final java.lang.String MIMETYPE_AUDIO_G711_MLAW = "audio/g711-mlaw";
-    field public static final java.lang.String MIMETYPE_AUDIO_MPEG = "audio/mpeg";
-    field public static final java.lang.String MIMETYPE_AUDIO_MSGSM = "audio/gsm";
-    field public static final java.lang.String MIMETYPE_AUDIO_OPUS = "audio/opus";
-    field public static final java.lang.String MIMETYPE_AUDIO_QCELP = "audio/qcelp";
-    field public static final java.lang.String MIMETYPE_AUDIO_RAW = "audio/raw";
-    field public static final java.lang.String MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
-    field public static final java.lang.String MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
-    field public static final java.lang.String MIMETYPE_IMAGE_ANDROID_HEIC = "image/vnd.android.heic";
-    field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
-    field public static final java.lang.String MIMETYPE_TEXT_CEA_708 = "text/cea-708";
-    field public static final java.lang.String MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
-    field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
-    field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
-    field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
-    field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp";
-    field public static final java.lang.String MIMETYPE_VIDEO_HEVC = "video/hevc";
-    field public static final java.lang.String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
-    field public static final java.lang.String MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
-    field public static final java.lang.String MIMETYPE_VIDEO_RAW = "video/raw";
-    field public static final java.lang.String MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
-    field public static final java.lang.String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
-    field public static final java.lang.String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
+    field public static final String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level";
+    field public static final String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level";
+    field public static final String KEY_AAC_DRC_EFFECT_TYPE = "aac-drc-effect-type";
+    field public static final String KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression";
+    field public static final String KEY_AAC_DRC_TARGET_REFERENCE_LEVEL = "aac-target-ref-level";
+    field public static final String KEY_AAC_ENCODED_TARGET_LEVEL = "aac-encoded-target-level";
+    field public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
+    field public static final String KEY_AAC_PROFILE = "aac-profile";
+    field public static final String KEY_AAC_SBR_MODE = "aac-sbr-mode";
+    field public static final String KEY_AUDIO_SESSION_ID = "audio-session-id";
+    field public static final String KEY_BITRATE_MODE = "bitrate-mode";
+    field public static final String KEY_BIT_RATE = "bitrate";
+    field public static final String KEY_CAPTURE_RATE = "capture-rate";
+    field public static final String KEY_CHANNEL_COUNT = "channel-count";
+    field public static final String KEY_CHANNEL_MASK = "channel-mask";
+    field public static final String KEY_COLOR_FORMAT = "color-format";
+    field public static final String KEY_COLOR_RANGE = "color-range";
+    field public static final String KEY_COLOR_STANDARD = "color-standard";
+    field public static final String KEY_COLOR_TRANSFER = "color-transfer";
+    field public static final String KEY_COMPLEXITY = "complexity";
+    field public static final String KEY_DURATION = "durationUs";
+    field public static final String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
+    field public static final String KEY_FRAME_RATE = "frame-rate";
+    field public static final String KEY_GRID_COLUMNS = "grid-cols";
+    field public static final String KEY_GRID_ROWS = "grid-rows";
+    field public static final String KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
+    field public static final String KEY_HDR_STATIC_INFO = "hdr-static-info";
+    field public static final String KEY_HEIGHT = "height";
+    field public static final String KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
+    field public static final String KEY_IS_ADTS = "is-adts";
+    field public static final String KEY_IS_AUTOSELECT = "is-autoselect";
+    field public static final String KEY_IS_DEFAULT = "is-default";
+    field public static final String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
+    field public static final String KEY_I_FRAME_INTERVAL = "i-frame-interval";
+    field public static final String KEY_LANGUAGE = "language";
+    field public static final String KEY_LATENCY = "latency";
+    field public static final String KEY_LEVEL = "level";
+    field public static final String KEY_MAX_HEIGHT = "max-height";
+    field public static final String KEY_MAX_INPUT_SIZE = "max-input-size";
+    field public static final String KEY_MAX_WIDTH = "max-width";
+    field public static final String KEY_MIME = "mime";
+    field public static final String KEY_OPERATING_RATE = "operating-rate";
+    field public static final String KEY_OUTPUT_REORDER_DEPTH = "output-reorder-depth";
+    field public static final String KEY_PCM_ENCODING = "pcm-encoding";
+    field public static final String KEY_PRIORITY = "priority";
+    field public static final String KEY_PROFILE = "profile";
+    field public static final String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
+    field public static final String KEY_QUALITY = "quality";
+    field public static final String KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
+    field public static final String KEY_ROTATION = "rotation-degrees";
+    field public static final String KEY_SAMPLE_RATE = "sample-rate";
+    field public static final String KEY_SLICE_HEIGHT = "slice-height";
+    field public static final String KEY_STRIDE = "stride";
+    field public static final String KEY_TEMPORAL_LAYERING = "ts-schema";
+    field public static final String KEY_TILE_HEIGHT = "tile-height";
+    field public static final String KEY_TILE_WIDTH = "tile-width";
+    field public static final String KEY_TRACK_ID = "track-id";
+    field public static final String KEY_WIDTH = "width";
+    field public static final String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
+    field public static final String MIMETYPE_AUDIO_AC3 = "audio/ac3";
+    field public static final String MIMETYPE_AUDIO_AC4 = "audio/ac4";
+    field public static final String MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
+    field public static final String MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
+    field public static final String MIMETYPE_AUDIO_EAC3 = "audio/eac3";
+    field public static final String MIMETYPE_AUDIO_EAC3_JOC = "audio/eac3-joc";
+    field public static final String MIMETYPE_AUDIO_FLAC = "audio/flac";
+    field public static final String MIMETYPE_AUDIO_G711_ALAW = "audio/g711-alaw";
+    field public static final String MIMETYPE_AUDIO_G711_MLAW = "audio/g711-mlaw";
+    field public static final String MIMETYPE_AUDIO_MPEG = "audio/mpeg";
+    field public static final String MIMETYPE_AUDIO_MSGSM = "audio/gsm";
+    field public static final String MIMETYPE_AUDIO_OPUS = "audio/opus";
+    field public static final String MIMETYPE_AUDIO_QCELP = "audio/qcelp";
+    field public static final String MIMETYPE_AUDIO_RAW = "audio/raw";
+    field public static final String MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
+    field public static final String MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
+    field public static final String MIMETYPE_IMAGE_ANDROID_HEIC = "image/vnd.android.heic";
+    field public static final String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
+    field public static final String MIMETYPE_TEXT_CEA_708 = "text/cea-708";
+    field public static final String MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+    field public static final String MIMETYPE_TEXT_VTT = "text/vtt";
+    field public static final String MIMETYPE_VIDEO_AV1 = "video/av01";
+    field public static final String MIMETYPE_VIDEO_AVC = "video/avc";
+    field public static final String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
+    field public static final String MIMETYPE_VIDEO_H263 = "video/3gpp";
+    field public static final String MIMETYPE_VIDEO_HEVC = "video/hevc";
+    field public static final String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
+    field public static final String MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
+    field public static final String MIMETYPE_VIDEO_RAW = "video/raw";
+    field public static final String MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
+    field public static final String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
+    field public static final String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
     field public static final int TYPE_BYTE_BUFFER = 5; // 0x5
     field public static final int TYPE_FLOAT = 3; // 0x3
     field public static final int TYPE_INTEGER = 1; // 0x1
@@ -24939,100 +25004,119 @@
     field public static final int TYPE_STRING = 4; // 0x4
   }
 
-  public final class MediaMetadata implements android.os.Parcelable {
-    method public boolean containsKey(java.lang.String);
+  public final class MediaItem2 implements android.os.Parcelable {
     method public int describeContents();
-    method public android.graphics.Bitmap getBitmap(java.lang.String);
-    method public android.media.MediaDescription getDescription();
-    method public long getLong(java.lang.String);
-    method public android.media.Rating getRating(java.lang.String);
-    method public java.lang.String getString(java.lang.String);
-    method public java.lang.CharSequence getText(java.lang.String);
+    method public long getEndPosition();
+    method @Nullable public android.media.MediaMetadata getMetadata();
+    method public long getStartPosition();
+    method public void setMetadata(@Nullable android.media.MediaMetadata);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.MediaItem2> CREATOR;
+    field public static final long POSITION_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL
+  }
+
+  public static class MediaItem2.Builder {
+    ctor public MediaItem2.Builder();
+    method @NonNull public android.media.MediaItem2 build();
+    method @NonNull public android.media.MediaItem2.Builder setEndPosition(long);
+    method @NonNull public android.media.MediaItem2.Builder setMetadata(@Nullable android.media.MediaMetadata);
+    method @NonNull public android.media.MediaItem2.Builder setStartPosition(long);
+  }
+
+  public final class MediaMetadata implements android.os.Parcelable {
+    method public boolean containsKey(String);
+    method public int describeContents();
+    method public android.graphics.Bitmap getBitmap(String);
+    method @NonNull public android.media.MediaDescription getDescription();
+    method public long getLong(String);
+    method public android.media.Rating getRating(String);
+    method public String getString(String);
+    method public CharSequence getText(String);
     method public java.util.Set<java.lang.String> keySet();
     method public int size();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.media.MediaMetadata> CREATOR;
-    field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
-    field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
-    field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
-    field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
-    field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART";
-    field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
-    field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
-    field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
-    field public static final java.lang.String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE";
-    field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
-    field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
-    field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
-    field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
-    field public static final java.lang.String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
-    field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
-    field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
-    field public static final java.lang.String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
-    field public static final java.lang.String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
-    field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
-    field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
-    field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
-    field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
-    field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
-    field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
-    field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+    field public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+    field public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+    field public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+    field public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+    field public static final String METADATA_KEY_ART = "android.media.metadata.ART";
+    field public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+    field public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+    field public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+    field public static final String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE";
+    field public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+    field public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+    field public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
+    field public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+    field public static final String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
+    field public static final String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
+    field public static final String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
+    field public static final String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
+    field public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
+    field public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+    field public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+    field public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+    field public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
+    field public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+    field public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
+    field public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+    field public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+    field public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+    field public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+    field public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
   }
 
   public static final class MediaMetadata.Builder {
     ctor public MediaMetadata.Builder();
     ctor public MediaMetadata.Builder(android.media.MediaMetadata);
     method public android.media.MediaMetadata build();
-    method public android.media.MediaMetadata.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
-    method public android.media.MediaMetadata.Builder putLong(java.lang.String, long);
-    method public android.media.MediaMetadata.Builder putRating(java.lang.String, android.media.Rating);
-    method public android.media.MediaMetadata.Builder putString(java.lang.String, java.lang.String);
-    method public android.media.MediaMetadata.Builder putText(java.lang.String, java.lang.CharSequence);
+    method public android.media.MediaMetadata.Builder putBitmap(String, android.graphics.Bitmap);
+    method public android.media.MediaMetadata.Builder putLong(String, long);
+    method public android.media.MediaMetadata.Builder putRating(String, android.media.Rating);
+    method public android.media.MediaMetadata.Builder putString(String, String);
+    method public android.media.MediaMetadata.Builder putText(String, CharSequence);
   }
 
-  public abstract deprecated class MediaMetadataEditor {
-    method public synchronized void addEditableKey(int);
-    method public abstract void apply();
-    method public synchronized void clear();
-    method public synchronized android.graphics.Bitmap getBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
-    method public synchronized int[] getEditableKeys();
-    method public synchronized long getLong(int, long) throws java.lang.IllegalArgumentException;
-    method public synchronized java.lang.Object getObject(int, java.lang.Object) throws java.lang.IllegalArgumentException;
-    method public synchronized java.lang.String getString(int, java.lang.String) throws java.lang.IllegalArgumentException;
-    method public synchronized android.media.MediaMetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
-    method public synchronized android.media.MediaMetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
-    method public synchronized android.media.MediaMetadataEditor putObject(int, java.lang.Object) throws java.lang.IllegalArgumentException;
-    method public synchronized android.media.MediaMetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
-    method public synchronized void removeEditableKeys();
-    field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
-    field public static final int RATING_KEY_BY_OTHERS = 101; // 0x65
-    field public static final int RATING_KEY_BY_USER = 268435457; // 0x10000001
+  @Deprecated public abstract class MediaMetadataEditor {
+    method @Deprecated public void addEditableKey(int);
+    method @Deprecated public abstract void apply();
+    method @Deprecated public void clear();
+    method @Deprecated public android.graphics.Bitmap getBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+    method @Deprecated public int[] getEditableKeys();
+    method @Deprecated public long getLong(int, long) throws java.lang.IllegalArgumentException;
+    method @Deprecated public Object getObject(int, Object) throws java.lang.IllegalArgumentException;
+    method @Deprecated public String getString(int, String) throws java.lang.IllegalArgumentException;
+    method @Deprecated public android.media.MediaMetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+    method @Deprecated public android.media.MediaMetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
+    method @Deprecated public android.media.MediaMetadataEditor putObject(int, Object) throws java.lang.IllegalArgumentException;
+    method @Deprecated public android.media.MediaMetadataEditor putString(int, String) throws java.lang.IllegalArgumentException;
+    method @Deprecated public void removeEditableKeys();
+    field @Deprecated public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
+    field @Deprecated public static final int RATING_KEY_BY_OTHERS = 101; // 0x65
+    field @Deprecated public static final int RATING_KEY_BY_USER = 268435457; // 0x10000001
   }
 
   public class MediaMetadataRetriever implements java.lang.AutoCloseable {
     ctor public MediaMetadataRetriever();
     method public void close();
-    method public java.lang.String extractMetadata(int);
+    method public String extractMetadata(int);
     method public byte[] getEmbeddedPicture();
-    method public android.graphics.Bitmap getFrameAtIndex(int, android.media.MediaMetadataRetriever.BitmapParams);
+    method public android.graphics.Bitmap getFrameAtIndex(int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
     method public android.graphics.Bitmap getFrameAtIndex(int);
     method public android.graphics.Bitmap getFrameAtTime(long, int);
     method public android.graphics.Bitmap getFrameAtTime(long);
     method public android.graphics.Bitmap getFrameAtTime();
-    method public java.util.List<android.graphics.Bitmap> getFramesAtIndex(int, int, android.media.MediaMetadataRetriever.BitmapParams);
-    method public java.util.List<android.graphics.Bitmap> getFramesAtIndex(int, int);
-    method public android.graphics.Bitmap getImageAtIndex(int, android.media.MediaMetadataRetriever.BitmapParams);
+    method @NonNull public java.util.List<android.graphics.Bitmap> getFramesAtIndex(int, int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
+    method @NonNull public java.util.List<android.graphics.Bitmap> getFramesAtIndex(int, int);
+    method public android.graphics.Bitmap getImageAtIndex(int, @NonNull android.media.MediaMetadataRetriever.BitmapParams);
     method public android.graphics.Bitmap getImageAtIndex(int);
-    method public android.graphics.Bitmap getPrimaryImage(android.media.MediaMetadataRetriever.BitmapParams);
+    method public android.graphics.Bitmap getPrimaryImage(@NonNull android.media.MediaMetadataRetriever.BitmapParams);
     method public android.graphics.Bitmap getPrimaryImage();
     method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
     method public void release();
-    method public void setDataSource(java.lang.String) throws java.lang.IllegalArgumentException;
-    method public void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.lang.IllegalArgumentException;
+    method public void setDataSource(String) throws java.lang.IllegalArgumentException;
+    method public void setDataSource(String, java.util.Map<java.lang.String,java.lang.String>) throws java.lang.IllegalArgumentException;
     method public void setDataSource(java.io.FileDescriptor, long, long) throws java.lang.IllegalArgumentException;
     method public void setDataSource(java.io.FileDescriptor) throws java.lang.IllegalArgumentException;
     method public void setDataSource(android.content.Context, android.net.Uri) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
@@ -25076,21 +25160,21 @@
 
   public static final class MediaMetadataRetriever.BitmapParams {
     ctor public MediaMetadataRetriever.BitmapParams();
-    method public android.graphics.Bitmap.Config getActualConfig();
-    method public android.graphics.Bitmap.Config getPreferredConfig();
-    method public void setPreferredConfig(android.graphics.Bitmap.Config);
+    method @NonNull public android.graphics.Bitmap.Config getActualConfig();
+    method @NonNull public android.graphics.Bitmap.Config getPreferredConfig();
+    method public void setPreferredConfig(@NonNull android.graphics.Bitmap.Config);
   }
 
   public final class MediaMuxer {
-    ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
-    ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException;
-    method public int addTrack(android.media.MediaFormat);
+    ctor public MediaMuxer(@NonNull String, int) throws java.io.IOException;
+    ctor public MediaMuxer(@NonNull java.io.FileDescriptor, int) throws java.io.IOException;
+    method public int addTrack(@NonNull android.media.MediaFormat);
     method public void release();
     method public void setLocation(float, float);
     method public void setOrientationHint(int);
     method public void start();
     method public void stop();
-    method public void writeSampleData(int, java.nio.ByteBuffer, android.media.MediaCodec.BufferInfo);
+    method public void writeSampleData(int, @NonNull java.nio.ByteBuffer, @NonNull android.media.MediaCodec.BufferInfo);
   }
 
   public static final class MediaMuxer.OutputFormat {
@@ -25104,10 +25188,10 @@
   public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
     ctor public MediaPlayer();
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
-    method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public void addTimedTextSource(java.io.FileDescriptor, long, long, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void addTimedTextSource(String, String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void addTimedTextSource(android.content.Context, android.net.Uri, String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void addTimedTextSource(java.io.FileDescriptor, String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void addTimedTextSource(java.io.FileDescriptor, long, long, String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void attachAuxEffect(int);
     method public void clearOnMediaTimeDiscontinuityListener();
     method public void clearOnSubtitleDataListener();
@@ -25116,22 +25200,23 @@
     method public static android.media.MediaPlayer create(android.content.Context, android.net.Uri, android.view.SurfaceHolder, android.media.AudioAttributes, int);
     method public static android.media.MediaPlayer create(android.content.Context, int);
     method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
-    method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
+    method @NonNull public android.media.VolumeShaper createVolumeShaper(@NonNull android.media.VolumeShaper.Configuration);
+    method public static void deprecateStreamTypeForPlayback(int, String, String) throws java.lang.IllegalArgumentException;
     method public void deselectTrack(int) throws java.lang.IllegalStateException;
     method protected void finalize();
     method public int getAudioSessionId();
     method public int getCurrentPosition();
     method public android.media.MediaPlayer.DrmInfo getDrmInfo();
-    method public java.lang.String getDrmPropertyString(java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
+    method @NonNull public String getDrmPropertyString(@NonNull String) throws android.media.MediaPlayer.NoDrmSchemeException;
     method public int getDuration();
-    method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
+    method @NonNull public android.media.MediaDrm.KeyRequest getKeyRequest(@Nullable byte[], @Nullable byte[], @Nullable String, int, @Nullable java.util.Map<java.lang.String,java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
     method public android.os.PersistableBundle getMetrics();
-    method public android.media.PlaybackParams getPlaybackParams();
+    method @NonNull public android.media.PlaybackParams getPlaybackParams();
     method public android.media.AudioDeviceInfo getPreferredDevice();
     method public android.media.AudioDeviceInfo getRoutedDevice();
     method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
-    method public android.media.SyncParams getSyncParams();
-    method public android.media.MediaTimestamp getTimestamp();
+    method @NonNull public android.media.SyncParams getSyncParams();
+    method @Nullable public android.media.MediaTimestamp getTimestamp();
     method public android.media.MediaPlayer.TrackInfo[] getTrackInfo() throws java.lang.IllegalStateException;
     method public int getVideoHeight();
     method public int getVideoWidth();
@@ -25140,30 +25225,30 @@
     method public void pause() throws java.lang.IllegalStateException;
     method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
     method public void prepareAsync() throws java.lang.IllegalStateException;
-    method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningNetworkErrorException, android.media.MediaPlayer.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
-    method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
+    method public void prepareDrm(@NonNull java.util.UUID) throws android.media.MediaPlayer.ProvisioningNetworkErrorException, android.media.MediaPlayer.ProvisioningServerErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException;
+    method public byte[] provideKeyResponse(@Nullable byte[], @NonNull byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
     method public void release();
     method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
     method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public void reset();
-    method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException;
+    method public void restoreKeys(@NonNull byte[]) throws android.media.MediaPlayer.NoDrmSchemeException;
     method public void seekTo(long, int);
     method public void seekTo(int) throws java.lang.IllegalStateException;
     method public void selectTrack(int) throws java.lang.IllegalStateException;
     method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
     method public void setAudioSessionId(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public deprecated void setAudioStreamType(int);
+    method @Deprecated public void setAudioStreamType(int);
     method public void setAuxEffectSendLevel(float);
-    method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
-    method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>, java.util.List<java.net.HttpCookie>) throws java.io.IOException;
-    method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
-    method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
-    method public void setDataSource(android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void setDataSource(@NonNull android.content.Context, @NonNull android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
+    method public void setDataSource(@NonNull android.content.Context, @NonNull android.net.Uri, @Nullable java.util.Map<java.lang.String,java.lang.String>, @Nullable java.util.List<java.net.HttpCookie>) throws java.io.IOException;
+    method public void setDataSource(@NonNull android.content.Context, @NonNull android.net.Uri, @Nullable java.util.Map<java.lang.String,java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
+    method public void setDataSource(String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
+    method public void setDataSource(@NonNull android.content.res.AssetFileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDisplay(android.view.SurfaceHolder);
-    method public void setDrmPropertyString(java.lang.String, java.lang.String) throws android.media.MediaPlayer.NoDrmSchemeException;
+    method public void setDrmPropertyString(@NonNull String, @NonNull String) throws android.media.MediaPlayer.NoDrmSchemeException;
     method public void setLooping(boolean);
     method public void setNextMediaPlayer(android.media.MediaPlayer);
     method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener);
@@ -25175,20 +25260,20 @@
     method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener, android.os.Handler);
     method public void setOnErrorListener(android.media.MediaPlayer.OnErrorListener);
     method public void setOnInfoListener(android.media.MediaPlayer.OnInfoListener);
-    method public void setOnMediaTimeDiscontinuityListener(android.media.MediaPlayer.OnMediaTimeDiscontinuityListener, android.os.Handler);
-    method public void setOnMediaTimeDiscontinuityListener(android.media.MediaPlayer.OnMediaTimeDiscontinuityListener);
+    method public void setOnMediaTimeDiscontinuityListener(@NonNull android.media.MediaPlayer.OnMediaTimeDiscontinuityListener, @NonNull android.os.Handler);
+    method public void setOnMediaTimeDiscontinuityListener(@NonNull android.media.MediaPlayer.OnMediaTimeDiscontinuityListener);
     method public void setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener);
     method public void setOnSeekCompleteListener(android.media.MediaPlayer.OnSeekCompleteListener);
-    method public void setOnSubtitleDataListener(android.media.MediaPlayer.OnSubtitleDataListener, android.os.Handler);
-    method public void setOnSubtitleDataListener(android.media.MediaPlayer.OnSubtitleDataListener);
+    method public void setOnSubtitleDataListener(@NonNull android.media.MediaPlayer.OnSubtitleDataListener, @NonNull android.os.Handler);
+    method public void setOnSubtitleDataListener(@NonNull android.media.MediaPlayer.OnSubtitleDataListener);
     method public void setOnTimedMetaDataAvailableListener(android.media.MediaPlayer.OnTimedMetaDataAvailableListener);
     method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
     method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
-    method public void setPlaybackParams(android.media.PlaybackParams);
+    method public void setPlaybackParams(@NonNull android.media.PlaybackParams);
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
     method public void setScreenOnWhilePlaying(boolean);
     method public void setSurface(android.view.Surface);
-    method public void setSyncParams(android.media.SyncParams);
+    method public void setSyncParams(@NonNull android.media.SyncParams);
     method public void setVideoScalingMode(int);
     method public void setVolume(float, float);
     method public void setWakeMode(android.content.Context, int);
@@ -25214,7 +25299,7 @@
     field public static final int MEDIA_INFO_VIDEO_NOT_PLAYING = 805; // 0x325
     field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
     field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
-    field public static final deprecated java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+    field @Deprecated public static final String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
     field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3
     field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1
     field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2
@@ -25228,97 +25313,97 @@
   }
 
   public static final class MediaPlayer.DrmInfo {
-    method public java.util.Map<java.util.UUID, byte[]> getPssh();
+    method public java.util.Map<java.util.UUID,byte[]> getPssh();
     method public java.util.UUID[] getSupportedSchemes();
   }
 
   public static final class MediaPlayer.MetricsConstants {
-    field public static final java.lang.String CODEC_AUDIO = "android.media.mediaplayer.audio.codec";
-    field public static final java.lang.String CODEC_VIDEO = "android.media.mediaplayer.video.codec";
-    field public static final java.lang.String DURATION = "android.media.mediaplayer.durationMs";
-    field public static final java.lang.String ERRORS = "android.media.mediaplayer.err";
-    field public static final java.lang.String ERROR_CODE = "android.media.mediaplayer.errcode";
-    field public static final java.lang.String FRAMES = "android.media.mediaplayer.frames";
-    field public static final java.lang.String FRAMES_DROPPED = "android.media.mediaplayer.dropped";
-    field public static final java.lang.String HEIGHT = "android.media.mediaplayer.height";
-    field public static final java.lang.String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime";
-    field public static final java.lang.String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime";
-    field public static final java.lang.String PLAYING = "android.media.mediaplayer.playingMs";
-    field public static final java.lang.String WIDTH = "android.media.mediaplayer.width";
+    field public static final String CODEC_AUDIO = "android.media.mediaplayer.audio.codec";
+    field public static final String CODEC_VIDEO = "android.media.mediaplayer.video.codec";
+    field public static final String DURATION = "android.media.mediaplayer.durationMs";
+    field public static final String ERRORS = "android.media.mediaplayer.err";
+    field public static final String ERROR_CODE = "android.media.mediaplayer.errcode";
+    field public static final String FRAMES = "android.media.mediaplayer.frames";
+    field public static final String FRAMES_DROPPED = "android.media.mediaplayer.dropped";
+    field public static final String HEIGHT = "android.media.mediaplayer.height";
+    field public static final String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime";
+    field public static final String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime";
+    field public static final String PLAYING = "android.media.mediaplayer.playingMs";
+    field public static final String WIDTH = "android.media.mediaplayer.width";
   }
 
   public static final class MediaPlayer.NoDrmSchemeException extends android.media.MediaDrmException {
-    ctor public MediaPlayer.NoDrmSchemeException(java.lang.String);
+    ctor public MediaPlayer.NoDrmSchemeException(String);
   }
 
-  public static abstract interface MediaPlayer.OnBufferingUpdateListener {
-    method public abstract void onBufferingUpdate(android.media.MediaPlayer, int);
+  public static interface MediaPlayer.OnBufferingUpdateListener {
+    method public void onBufferingUpdate(android.media.MediaPlayer, int);
   }
 
-  public static abstract interface MediaPlayer.OnCompletionListener {
-    method public abstract void onCompletion(android.media.MediaPlayer);
+  public static interface MediaPlayer.OnCompletionListener {
+    method public void onCompletion(android.media.MediaPlayer);
   }
 
-  public static abstract interface MediaPlayer.OnDrmConfigHelper {
-    method public abstract void onDrmConfig(android.media.MediaPlayer);
+  public static interface MediaPlayer.OnDrmConfigHelper {
+    method public void onDrmConfig(android.media.MediaPlayer);
   }
 
-  public static abstract interface MediaPlayer.OnDrmInfoListener {
-    method public abstract void onDrmInfo(android.media.MediaPlayer, android.media.MediaPlayer.DrmInfo);
+  public static interface MediaPlayer.OnDrmInfoListener {
+    method public void onDrmInfo(android.media.MediaPlayer, android.media.MediaPlayer.DrmInfo);
   }
 
-  public static abstract interface MediaPlayer.OnDrmPreparedListener {
-    method public abstract void onDrmPrepared(android.media.MediaPlayer, int);
+  public static interface MediaPlayer.OnDrmPreparedListener {
+    method public void onDrmPrepared(android.media.MediaPlayer, int);
   }
 
-  public static abstract interface MediaPlayer.OnErrorListener {
-    method public abstract boolean onError(android.media.MediaPlayer, int, int);
+  public static interface MediaPlayer.OnErrorListener {
+    method public boolean onError(android.media.MediaPlayer, int, int);
   }
 
-  public static abstract interface MediaPlayer.OnInfoListener {
-    method public abstract boolean onInfo(android.media.MediaPlayer, int, int);
+  public static interface MediaPlayer.OnInfoListener {
+    method public boolean onInfo(android.media.MediaPlayer, int, int);
   }
 
-  public static abstract interface MediaPlayer.OnMediaTimeDiscontinuityListener {
-    method public abstract void onMediaTimeDiscontinuity(android.media.MediaPlayer, android.media.MediaTimestamp);
+  public static interface MediaPlayer.OnMediaTimeDiscontinuityListener {
+    method public void onMediaTimeDiscontinuity(@NonNull android.media.MediaPlayer, @NonNull android.media.MediaTimestamp);
   }
 
-  public static abstract interface MediaPlayer.OnPreparedListener {
-    method public abstract void onPrepared(android.media.MediaPlayer);
+  public static interface MediaPlayer.OnPreparedListener {
+    method public void onPrepared(android.media.MediaPlayer);
   }
 
-  public static abstract interface MediaPlayer.OnSeekCompleteListener {
-    method public abstract void onSeekComplete(android.media.MediaPlayer);
+  public static interface MediaPlayer.OnSeekCompleteListener {
+    method public void onSeekComplete(android.media.MediaPlayer);
   }
 
-  public static abstract interface MediaPlayer.OnSubtitleDataListener {
-    method public abstract void onSubtitleData(android.media.MediaPlayer, android.media.SubtitleData);
+  public static interface MediaPlayer.OnSubtitleDataListener {
+    method public void onSubtitleData(@NonNull android.media.MediaPlayer, @NonNull android.media.SubtitleData);
   }
 
-  public static abstract interface MediaPlayer.OnTimedMetaDataAvailableListener {
-    method public abstract void onTimedMetaDataAvailable(android.media.MediaPlayer, android.media.TimedMetaData);
+  public static interface MediaPlayer.OnTimedMetaDataAvailableListener {
+    method public void onTimedMetaDataAvailable(android.media.MediaPlayer, android.media.TimedMetaData);
   }
 
-  public static abstract interface MediaPlayer.OnTimedTextListener {
-    method public abstract void onTimedText(android.media.MediaPlayer, android.media.TimedText);
+  public static interface MediaPlayer.OnTimedTextListener {
+    method public void onTimedText(android.media.MediaPlayer, android.media.TimedText);
   }
 
-  public static abstract interface MediaPlayer.OnVideoSizeChangedListener {
-    method public abstract void onVideoSizeChanged(android.media.MediaPlayer, int, int);
+  public static interface MediaPlayer.OnVideoSizeChangedListener {
+    method public void onVideoSizeChanged(android.media.MediaPlayer, int, int);
   }
 
   public static final class MediaPlayer.ProvisioningNetworkErrorException extends android.media.MediaDrmException {
-    ctor public MediaPlayer.ProvisioningNetworkErrorException(java.lang.String);
+    ctor public MediaPlayer.ProvisioningNetworkErrorException(String);
   }
 
   public static final class MediaPlayer.ProvisioningServerErrorException extends android.media.MediaDrmException {
-    ctor public MediaPlayer.ProvisioningServerErrorException(java.lang.String);
+    ctor public MediaPlayer.ProvisioningServerErrorException(String);
   }
 
   public static class MediaPlayer.TrackInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.media.MediaFormat getFormat();
-    method public java.lang.String getLanguage();
+    method public String getLanguage();
     method public int getTrackType();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int MEDIA_TRACK_TYPE_AUDIO = 2; // 0x2
@@ -25332,57 +25417,65 @@
   public class MediaPlayer2 implements android.media.AudioRouting java.lang.AutoCloseable {
     ctor public MediaPlayer2(android.content.Context);
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
-    method public java.lang.Object attachAuxEffect(int);
-    method public boolean cancelCommand(java.lang.Object);
-    method public java.lang.Object clearNextDataSources();
+    method public Object attachAuxEffect(int);
+    method public boolean cancelCommand(@NonNull Object);
+    method public void clearDrmEventCallback();
+    method public Object clearNextDataSources();
     method public void clearPendingCommands();
     method public void close();
-    method public java.lang.Object deselectTrack(android.media.DataSourceDesc, int);
-    method public android.media.AudioAttributes getAudioAttributes();
+    method public Object deselectTrack(int);
+    method public Object deselectTrack(@NonNull android.media.DataSourceDesc, int);
+    method @NonNull public android.media.AudioAttributes getAudioAttributes();
     method public int getAudioSessionId();
-    method public long getBufferedPosition(android.media.DataSourceDesc);
-    method public android.media.DataSourceDesc getCurrentDataSource();
+    method public long getBufferedPosition();
+    method public long getBufferedPosition(@NonNull android.media.DataSourceDesc);
+    method @Nullable public android.media.DataSourceDesc getCurrentDataSource();
     method public long getCurrentPosition();
-    method public long getDuration(android.media.DataSourceDesc);
+    method public long getDuration();
+    method public long getDuration(@NonNull android.media.DataSourceDesc);
     method public float getMaxPlayerVolume();
     method public android.os.PersistableBundle getMetrics();
-    method public android.media.PlaybackParams getPlaybackParams();
+    method @NonNull public android.media.PlaybackParams getPlaybackParams();
     method public float getPlayerVolume();
     method public android.media.AudioDeviceInfo getPreferredDevice();
     method public android.media.AudioDeviceInfo getRoutedDevice();
-    method public int getSelectedTrack(android.media.DataSourceDesc, int);
+    method public int getSelectedTrack(int);
+    method public int getSelectedTrack(@NonNull android.media.DataSourceDesc, int);
     method public int getState();
-    method public android.media.SyncParams getSyncParams();
-    method public android.media.MediaTimestamp getTimestamp();
-    method public java.util.List<android.media.MediaPlayer2.TrackInfo> getTrackInfo(android.media.DataSourceDesc);
+    method @NonNull public android.media.SyncParams getSyncParams();
+    method @Nullable public android.media.MediaTimestamp getTimestamp();
+    method @NonNull public java.util.List<android.media.MediaPlayer2.TrackInfo> getTrackInfo();
+    method @NonNull public java.util.List<android.media.MediaPlayer2.TrackInfo> getTrackInfo(@NonNull android.media.DataSourceDesc);
     method public android.media.VideoSize getVideoSize();
     method public boolean isLooping();
-    method public java.lang.Object loopCurrent(boolean);
-    method public java.lang.Object notifyWhenCommandLabelReached(java.lang.Object);
-    method public java.lang.Object pause();
-    method public java.lang.Object play();
-    method public java.lang.Object prepare();
-    method public void registerEventCallback(java.util.concurrent.Executor, android.media.MediaPlayer2.EventCallback);
+    method public Object loopCurrent(boolean);
+    method public Object notifyWhenCommandLabelReached(@NonNull Object);
+    method public Object pause();
+    method public Object play();
+    method public Object prepare();
+    method public void registerEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaPlayer2.EventCallback);
     method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public void reset();
-    method public java.lang.Object seekTo(long);
-    method public java.lang.Object seekTo(long, int);
-    method public java.lang.Object selectTrack(android.media.DataSourceDesc, int);
-    method public java.lang.Object setAudioAttributes(android.media.AudioAttributes);
-    method public java.lang.Object setAudioSessionId(int);
-    method public java.lang.Object setAuxEffectSendLevel(float);
-    method public java.lang.Object setDataSource(android.media.DataSourceDesc);
-    method public java.lang.Object setDisplay(android.view.SurfaceHolder);
-    method public java.lang.Object setNextDataSource(android.media.DataSourceDesc);
-    method public java.lang.Object setNextDataSources(java.util.List<android.media.DataSourceDesc>);
-    method public java.lang.Object setPlaybackParams(android.media.PlaybackParams);
-    method public java.lang.Object setPlayerVolume(float);
+    method public Object seekTo(long);
+    method public Object seekTo(long, int);
+    method public Object selectTrack(int);
+    method public Object selectTrack(@NonNull android.media.DataSourceDesc, int);
+    method public Object setAudioAttributes(@NonNull android.media.AudioAttributes);
+    method public Object setAudioSessionId(int);
+    method public Object setAuxEffectSendLevel(float);
+    method public Object setDataSource(@NonNull android.media.DataSourceDesc);
+    method public Object setDisplay(android.view.SurfaceHolder);
+    method public void setDrmEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaPlayer2.DrmEventCallback);
+    method public Object setNextDataSource(@NonNull android.media.DataSourceDesc);
+    method public Object setNextDataSources(@NonNull java.util.List<android.media.DataSourceDesc>);
+    method public Object setPlaybackParams(@NonNull android.media.PlaybackParams);
+    method public Object setPlayerVolume(float);
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
-    method public java.lang.Object setScreenOnWhilePlaying(boolean);
-    method public java.lang.Object setSurface(android.view.Surface);
-    method public java.lang.Object setSyncParams(android.media.SyncParams);
-    method public java.lang.Object setWakeLock(android.os.PowerManager.WakeLock);
-    method public java.lang.Object skipToNext();
+    method public Object setScreenOnWhilePlaying(boolean);
+    method public Object setSurface(android.view.Surface);
+    method public Object setSyncParams(@NonNull android.media.SyncParams);
+    method public Object setWakeLock(@NonNull android.os.PowerManager.WakeLock);
+    method public Object skipToNext();
     method public void unregisterEventCallback(android.media.MediaPlayer2.EventCallback);
     field public static final int CALL_COMPLETED_ATTACH_AUX_EFFECT = 1; // 0x1
     field public static final int CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES = 30; // 0x1e
@@ -25451,36 +25544,67 @@
     field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0
   }
 
+  public static class MediaPlayer2.DrmEventCallback {
+    ctor public MediaPlayer2.DrmEventCallback();
+    method public void onDrmConfig(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm);
+    method public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaPlayer2.DrmInfo);
+    method public byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest);
+    method public void onDrmPrepared(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, @Nullable byte[]);
+  }
+
+  public static final class MediaPlayer2.DrmInfo {
+    method public java.util.Map<java.util.UUID,byte[]> getPssh();
+    method public java.util.List<java.util.UUID> getSupportedSchemes();
+  }
+
+  public static final class MediaPlayer2.DrmPreparationInfo {
+  }
+
+  public static final class MediaPlayer2.DrmPreparationInfo.Builder {
+    ctor public MediaPlayer2.DrmPreparationInfo.Builder();
+    method public android.media.MediaPlayer2.DrmPreparationInfo build();
+    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(@Nullable byte[]);
+    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(@Nullable byte[]);
+    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int);
+    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(@Nullable String);
+    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(@Nullable java.util.Map<java.lang.String,java.lang.String>);
+    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(@NonNull java.util.UUID);
+  }
+
   public static class MediaPlayer2.EventCallback {
     ctor public MediaPlayer2.EventCallback();
-    method public void onCallCompleted(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
-    method public void onCommandLabelReached(android.media.MediaPlayer2, java.lang.Object);
-    method public void onError(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
-    method public void onInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
-    method public void onMediaTimeDiscontinuity(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaTimestamp);
-    method public void onSubtitleData(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.SubtitleData);
-    method public void onTimedMetaDataAvailable(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.TimedMetaData);
-    method public void onVideoSizeChanged(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.VideoSize);
+    method public void onCallCompleted(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, int);
+    method public void onCommandLabelReached(@NonNull android.media.MediaPlayer2, @NonNull Object);
+    method public void onError(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, int);
+    method public void onInfo(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, int);
+    method public void onMediaTimeDiscontinuity(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaTimestamp);
+    method public void onSubtitleData(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.SubtitleData);
+    method public void onTimedMetaDataAvailable(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.TimedMetaData);
+    method public void onVideoSizeChanged(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.VideoSize);
   }
 
   public static final class MediaPlayer2.MetricsConstants {
-    field public static final java.lang.String CODEC_AUDIO = "android.media.mediaplayer.audio.codec";
-    field public static final java.lang.String CODEC_VIDEO = "android.media.mediaplayer.video.codec";
-    field public static final java.lang.String DURATION = "android.media.mediaplayer.durationMs";
-    field public static final java.lang.String ERRORS = "android.media.mediaplayer.err";
-    field public static final java.lang.String ERROR_CODE = "android.media.mediaplayer.errcode";
-    field public static final java.lang.String FRAMES = "android.media.mediaplayer.frames";
-    field public static final java.lang.String FRAMES_DROPPED = "android.media.mediaplayer.dropped";
-    field public static final java.lang.String HEIGHT = "android.media.mediaplayer.height";
-    field public static final java.lang.String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime";
-    field public static final java.lang.String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime";
-    field public static final java.lang.String PLAYING = "android.media.mediaplayer.playingMs";
-    field public static final java.lang.String WIDTH = "android.media.mediaplayer.width";
+    field public static final String CODEC_AUDIO = "android.media.mediaplayer.audio.codec";
+    field public static final String CODEC_VIDEO = "android.media.mediaplayer.video.codec";
+    field public static final String DURATION = "android.media.mediaplayer.durationMs";
+    field public static final String ERRORS = "android.media.mediaplayer.err";
+    field public static final String ERROR_CODE = "android.media.mediaplayer.errcode";
+    field public static final String FRAMES = "android.media.mediaplayer.frames";
+    field public static final String FRAMES_DROPPED = "android.media.mediaplayer.dropped";
+    field public static final String HEIGHT = "android.media.mediaplayer.height";
+    field public static final String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime";
+    field public static final String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime";
+    field public static final String PLAYING = "android.media.mediaplayer.playingMs";
+    field public static final String WIDTH = "android.media.mediaplayer.width";
+  }
+
+  public static final class MediaPlayer2.NoDrmSchemeException extends android.media.MediaDrmException {
+    ctor public MediaPlayer2.NoDrmSchemeException(String);
   }
 
   public static class MediaPlayer2.TrackInfo {
     method public android.media.MediaFormat getFormat();
-    method public java.lang.String getLanguage();
+    method public String getLanguage();
     method public int getTrackType();
     field public static final int MEDIA_TRACK_TYPE_AUDIO = 2; // 0x2
     field public static final int MEDIA_TRACK_TYPE_METADATA = 5; // 0x5
@@ -25494,7 +25618,7 @@
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
     method protected void finalize();
     method public java.util.List<android.media.MicrophoneInfo> getActiveMicrophones() throws java.io.IOException;
-    method public android.media.AudioRecordingConfiguration getActiveRecordingConfiguration();
+    method @Nullable public android.media.AudioRecordingConfiguration getActiveRecordingConfiguration();
     method public static final int getAudioSourceMax();
     method public int getMaxAmplitude() throws java.lang.IllegalStateException;
     method public android.os.PersistableBundle getMetrics();
@@ -25503,7 +25627,7 @@
     method public android.view.Surface getSurface();
     method public void pause() throws java.lang.IllegalStateException;
     method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
-    method public void registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback);
+    method public void registerAudioRecordingCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioRecordingCallback);
     method public void release();
     method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
     method public void reset();
@@ -25513,9 +25637,9 @@
     method public void setAudioEncodingBitRate(int);
     method public void setAudioSamplingRate(int);
     method public void setAudioSource(int) throws java.lang.IllegalStateException;
-    method public deprecated void setCamera(android.hardware.Camera);
+    method @Deprecated public void setCamera(android.hardware.Camera);
     method public void setCaptureRate(double);
-    method public void setInputSurface(android.view.Surface);
+    method public void setInputSurface(@NonNull android.view.Surface);
     method public void setLocation(float, float);
     method public void setMaxDuration(int) throws java.lang.IllegalArgumentException;
     method public void setMaxFileSize(long) throws java.lang.IllegalArgumentException;
@@ -25526,7 +25650,7 @@
     method public void setOrientationHint(int);
     method public void setOutputFile(java.io.FileDescriptor) throws java.lang.IllegalStateException;
     method public void setOutputFile(java.io.File);
-    method public void setOutputFile(java.lang.String) throws java.lang.IllegalStateException;
+    method public void setOutputFile(String) throws java.lang.IllegalStateException;
     method public void setOutputFormat(int) throws java.lang.IllegalStateException;
     method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
     method public void setPreviewDisplay(android.view.Surface);
@@ -25539,7 +25663,7 @@
     method public void setVideoSource(int) throws java.lang.IllegalStateException;
     method public void start() throws java.lang.IllegalStateException;
     method public void stop() throws java.lang.IllegalStateException;
-    method public void unregisterAudioRecordingCallback(android.media.AudioManager.AudioRecordingCallback);
+    method public void unregisterAudioRecordingCallback(@NonNull android.media.AudioManager.AudioRecordingCallback);
     field public static final int MEDIA_ERROR_SERVER_DIED = 100; // 0x64
     field public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1; // 0x1
     field public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800; // 0x320
@@ -25564,40 +25688,41 @@
     field public static final int CAMCORDER = 5; // 0x5
     field public static final int DEFAULT = 0; // 0x0
     field public static final int MIC = 1; // 0x1
-    field public static final int REMOTE_SUBMIX = 8; // 0x8
+    field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public static final int REMOTE_SUBMIX = 8; // 0x8
     field public static final int UNPROCESSED = 9; // 0x9
     field public static final int VOICE_CALL = 4; // 0x4
     field public static final int VOICE_COMMUNICATION = 7; // 0x7
     field public static final int VOICE_DOWNLINK = 3; // 0x3
+    field public static final int VOICE_PERFORMANCE = 10; // 0xa
     field public static final int VOICE_RECOGNITION = 6; // 0x6
     field public static final int VOICE_UPLINK = 2; // 0x2
   }
 
   public static final class MediaRecorder.MetricsConstants {
-    field public static final java.lang.String AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate";
-    field public static final java.lang.String AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels";
-    field public static final java.lang.String AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate";
-    field public static final java.lang.String AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale";
-    field public static final java.lang.String CAPTURE_FPS = "android.media.mediarecorder.capture-fps";
-    field public static final java.lang.String CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable";
-    field public static final java.lang.String FRAMERATE = "android.media.mediarecorder.frame-rate";
-    field public static final java.lang.String HEIGHT = "android.media.mediarecorder.height";
-    field public static final java.lang.String MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale";
-    field public static final java.lang.String ROTATION = "android.media.mediarecorder.rotation";
-    field public static final java.lang.String VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate";
-    field public static final java.lang.String VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval";
-    field public static final java.lang.String VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level";
-    field public static final java.lang.String VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile";
-    field public static final java.lang.String VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale";
-    field public static final java.lang.String WIDTH = "android.media.mediarecorder.width";
+    field public static final String AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate";
+    field public static final String AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels";
+    field public static final String AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate";
+    field public static final String AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale";
+    field public static final String CAPTURE_FPS = "android.media.mediarecorder.capture-fps";
+    field public static final String CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable";
+    field public static final String FRAMERATE = "android.media.mediarecorder.frame-rate";
+    field public static final String HEIGHT = "android.media.mediarecorder.height";
+    field public static final String MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale";
+    field public static final String ROTATION = "android.media.mediarecorder.rotation";
+    field public static final String VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate";
+    field public static final String VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval";
+    field public static final String VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level";
+    field public static final String VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile";
+    field public static final String VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale";
+    field public static final String WIDTH = "android.media.mediarecorder.width";
   }
 
-  public static abstract interface MediaRecorder.OnErrorListener {
-    method public abstract void onError(android.media.MediaRecorder, int, int);
+  public static interface MediaRecorder.OnErrorListener {
+    method public void onError(android.media.MediaRecorder, int, int);
   }
 
-  public static abstract interface MediaRecorder.OnInfoListener {
-    method public abstract void onInfo(android.media.MediaRecorder, int, int);
+  public static interface MediaRecorder.OnInfoListener {
+    method public void onInfo(android.media.MediaRecorder, int, int);
   }
 
   public final class MediaRecorder.OutputFormat {
@@ -25608,7 +25733,7 @@
     field public static final int MPEG_2_TS = 8; // 0x8
     field public static final int MPEG_4 = 2; // 0x2
     field public static final int OGG = 11; // 0xb
-    field public static final deprecated int RAW_AMR = 3; // 0x3
+    field @Deprecated public static final int RAW_AMR = 3; // 0x3
     field public static final int THREE_GPP = 1; // 0x1
     field public static final int WEBM = 9; // 0x9
   }
@@ -25633,7 +25758,7 @@
     method public void addCallback(int, android.media.MediaRouter.Callback, int);
     method public void addUserRoute(android.media.MediaRouter.UserRouteInfo);
     method public void clearUserRoutes();
-    method public android.media.MediaRouter.RouteCategory createRouteCategory(java.lang.CharSequence, boolean);
+    method public android.media.MediaRouter.RouteCategory createRouteCategory(CharSequence, boolean);
     method public android.media.MediaRouter.RouteCategory createRouteCategory(int, boolean);
     method public android.media.MediaRouter.UserRouteInfo createUserRoute(android.media.MediaRouter.RouteCategory);
     method public android.media.MediaRouter.RouteCategory getCategoryAt(int);
@@ -25644,7 +25769,7 @@
     method public android.media.MediaRouter.RouteInfo getSelectedRoute(int);
     method public void removeCallback(android.media.MediaRouter.Callback);
     method public void removeUserRoute(android.media.MediaRouter.UserRouteInfo);
-    method public void selectRoute(int, android.media.MediaRouter.RouteInfo);
+    method public void selectRoute(int, @NonNull android.media.MediaRouter.RouteInfo);
     field public static final int CALLBACK_FLAG_PERFORM_ACTIVE_SCAN = 1; // 0x1
     field public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 2; // 0x2
     field public static final int ROUTE_TYPE_LIVE_AUDIO = 1; // 0x1
@@ -25652,7 +25777,7 @@
     field public static final int ROUTE_TYPE_USER = 8388608; // 0x800000
   }
 
-  public static abstract class MediaRouter.Callback {
+  public abstract static class MediaRouter.Callback {
     ctor public MediaRouter.Callback();
     method public abstract void onRouteAdded(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
     method public abstract void onRouteChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo);
@@ -25666,8 +25791,8 @@
   }
 
   public static class MediaRouter.RouteCategory {
-    method public java.lang.CharSequence getName();
-    method public java.lang.CharSequence getName(android.content.Context);
+    method public CharSequence getName();
+    method public CharSequence getName(android.content.Context);
     method public java.util.List<android.media.MediaRouter.RouteInfo> getRoutes(java.util.List<android.media.MediaRouter.RouteInfo>);
     method public int getSupportedTypes();
     method public boolean isGroupable();
@@ -25681,23 +25806,23 @@
     method public void removeRoute(android.media.MediaRouter.RouteInfo);
     method public void removeRoute(int);
     method public void setIconDrawable(android.graphics.drawable.Drawable);
-    method public void setIconResource(int);
+    method public void setIconResource(@DrawableRes int);
   }
 
   public static class MediaRouter.RouteInfo {
     method public android.media.MediaRouter.RouteCategory getCategory();
-    method public java.lang.CharSequence getDescription();
+    method public CharSequence getDescription();
     method public int getDeviceType();
     method public android.media.MediaRouter.RouteGroup getGroup();
     method public android.graphics.drawable.Drawable getIconDrawable();
-    method public java.lang.CharSequence getName();
-    method public java.lang.CharSequence getName(android.content.Context);
+    method public CharSequence getName();
+    method public CharSequence getName(android.content.Context);
     method public int getPlaybackStream();
     method public int getPlaybackType();
     method public android.view.Display getPresentationDisplay();
-    method public java.lang.CharSequence getStatus();
+    method public CharSequence getStatus();
     method public int getSupportedTypes();
-    method public java.lang.Object getTag();
+    method public Object getTag();
     method public int getVolume();
     method public int getVolumeHandling();
     method public int getVolumeMax();
@@ -25705,7 +25830,7 @@
     method public boolean isEnabled();
     method public void requestSetVolume(int);
     method public void requestUpdateVolume(int);
-    method public void setTag(java.lang.Object);
+    method public void setTag(Object);
     field public static final int DEVICE_TYPE_BLUETOOTH = 3; // 0x3
     field public static final int DEVICE_TYPE_SPEAKER = 2; // 0x2
     field public static final int DEVICE_TYPE_TV = 1; // 0x1
@@ -25730,22 +25855,22 @@
 
   public static class MediaRouter.UserRouteInfo extends android.media.MediaRouter.RouteInfo {
     method public android.media.RemoteControlClient getRemoteControlClient();
-    method public void setDescription(java.lang.CharSequence);
+    method public void setDescription(CharSequence);
     method public void setIconDrawable(android.graphics.drawable.Drawable);
-    method public void setIconResource(int);
-    method public void setName(java.lang.CharSequence);
+    method public void setIconResource(@DrawableRes int);
+    method public void setName(CharSequence);
     method public void setName(int);
     method public void setPlaybackStream(int);
     method public void setPlaybackType(int);
     method public void setRemoteControlClient(android.media.RemoteControlClient);
-    method public void setStatus(java.lang.CharSequence);
+    method public void setStatus(CharSequence);
     method public void setVolume(int);
     method public void setVolumeCallback(android.media.MediaRouter.VolumeCallback);
     method public void setVolumeHandling(int);
     method public void setVolumeMax(int);
   }
 
-  public static abstract class MediaRouter.VolumeCallback {
+  public abstract static class MediaRouter.VolumeCallback {
     ctor public MediaRouter.VolumeCallback();
     method public abstract void onVolumeSetRequest(android.media.MediaRouter.RouteInfo, int);
     method public abstract void onVolumeUpdateRequest(android.media.MediaRouter.RouteInfo, int);
@@ -25755,48 +25880,98 @@
     ctor public MediaScannerConnection(android.content.Context, android.media.MediaScannerConnection.MediaScannerConnectionClient);
     method public void connect();
     method public void disconnect();
-    method public synchronized boolean isConnected();
+    method public boolean isConnected();
     method public void onServiceConnected(android.content.ComponentName, android.os.IBinder);
     method public void onServiceDisconnected(android.content.ComponentName);
-    method public void scanFile(java.lang.String, java.lang.String);
-    method public static void scanFile(android.content.Context, java.lang.String[], java.lang.String[], android.media.MediaScannerConnection.OnScanCompletedListener);
+    method public void scanFile(String, String);
+    method public static void scanFile(android.content.Context, String[], String[], android.media.MediaScannerConnection.OnScanCompletedListener);
   }
 
-  public static abstract interface MediaScannerConnection.MediaScannerConnectionClient implements android.media.MediaScannerConnection.OnScanCompletedListener {
-    method public abstract void onMediaScannerConnected();
+  public static interface MediaScannerConnection.MediaScannerConnectionClient extends android.media.MediaScannerConnection.OnScanCompletedListener {
+    method public void onMediaScannerConnected();
   }
 
-  public static abstract interface MediaScannerConnection.OnScanCompletedListener {
-    method public abstract void onScanCompleted(java.lang.String, android.net.Uri);
+  public static interface MediaScannerConnection.OnScanCompletedListener {
+    method public void onScanCompleted(String, android.net.Uri);
+  }
+
+  public class MediaSession2 implements java.lang.AutoCloseable {
+    method public void broadcastSessionCommand(@NonNull android.media.Session2Command, @Nullable android.os.Bundle);
+    method public void cancelSessionCommand(@NonNull android.media.MediaSession2.ControllerInfo, @NonNull Object);
+    method public void close();
+    method @NonNull public String getSessionId();
+    method @NonNull public android.media.Session2Token getSessionToken();
+    method public boolean isPlaybackActive();
+    method @NonNull public Object sendSessionCommand(@NonNull android.media.MediaSession2.ControllerInfo, @NonNull android.media.Session2Command, @Nullable android.os.Bundle);
+    method public void setPlaybackActive(boolean);
+  }
+
+  public static final class MediaSession2.Builder {
+    ctor public MediaSession2.Builder(@NonNull android.content.Context);
+    method @NonNull public android.media.MediaSession2 build();
+    method @NonNull public android.media.MediaSession2.Builder setId(@NonNull String);
+    method @NonNull public android.media.MediaSession2.Builder setSessionActivity(@Nullable android.app.PendingIntent);
+    method @NonNull public android.media.MediaSession2.Builder setSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaSession2.SessionCallback);
+  }
+
+  public static final class MediaSession2.ControllerInfo {
+    method @NonNull public String getPackageName();
+    method @NonNull public android.media.session.MediaSessionManager.RemoteUserInfo getRemoteUserInfo();
+    method public int getUid();
+  }
+
+  public abstract static class MediaSession2.SessionCallback {
+    ctor public MediaSession2.SessionCallback();
+    method public void onCommandResult(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo, @NonNull Object, @NonNull android.media.Session2Command, @NonNull android.media.Session2Command.Result);
+    method @Nullable public android.media.Session2CommandGroup onConnect(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo);
+    method public void onDisconnected(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo);
+    method @Nullable public android.media.Session2Command.Result onSessionCommand(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo, @NonNull android.media.Session2Command, @Nullable android.os.Bundle);
+  }
+
+  public abstract class MediaSession2Service extends android.app.Service {
+    ctor public MediaSession2Service();
+    method public final void addSession(@NonNull android.media.MediaSession2);
+    method @NonNull public final java.util.List<android.media.MediaSession2> getSessions();
+    method @CallSuper @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
+    method @NonNull public abstract android.media.MediaSession2 onGetPrimarySession();
+    method @Nullable public abstract android.media.MediaSession2Service.MediaNotification onUpdateNotification(@NonNull android.media.MediaSession2);
+    method public final void removeSession(@NonNull android.media.MediaSession2);
+    field public static final String SERVICE_INTERFACE = "android.media.MediaSession2Service";
+  }
+
+  public static class MediaSession2Service.MediaNotification {
+    ctor public MediaSession2Service.MediaNotification(int, @NonNull android.app.Notification);
+    method @NonNull public android.app.Notification getNotification();
+    method public int getNotificationId();
   }
 
   public final class MediaSync {
     ctor public MediaSync();
-    method public android.view.Surface createInputSurface();
+    method @NonNull public android.view.Surface createInputSurface();
     method protected void finalize();
     method public void flush();
-    method public android.media.PlaybackParams getPlaybackParams();
-    method public android.media.SyncParams getSyncParams();
-    method public android.media.MediaTimestamp getTimestamp();
-    method public void queueAudio(java.nio.ByteBuffer, int, long);
+    method @NonNull public android.media.PlaybackParams getPlaybackParams();
+    method @NonNull public android.media.SyncParams getSyncParams();
+    method @Nullable public android.media.MediaTimestamp getTimestamp();
+    method public void queueAudio(@NonNull java.nio.ByteBuffer, int, long);
     method public void release();
-    method public void setAudioTrack(android.media.AudioTrack);
-    method public void setCallback(android.media.MediaSync.Callback, android.os.Handler);
-    method public void setOnErrorListener(android.media.MediaSync.OnErrorListener, android.os.Handler);
-    method public void setPlaybackParams(android.media.PlaybackParams);
-    method public void setSurface(android.view.Surface);
-    method public void setSyncParams(android.media.SyncParams);
+    method public void setAudioTrack(@Nullable android.media.AudioTrack);
+    method public void setCallback(@Nullable android.media.MediaSync.Callback, @Nullable android.os.Handler);
+    method public void setOnErrorListener(@Nullable android.media.MediaSync.OnErrorListener, @Nullable android.os.Handler);
+    method public void setPlaybackParams(@NonNull android.media.PlaybackParams);
+    method public void setSurface(@Nullable android.view.Surface);
+    method public void setSyncParams(@NonNull android.media.SyncParams);
     field public static final int MEDIASYNC_ERROR_AUDIOTRACK_FAIL = 1; // 0x1
     field public static final int MEDIASYNC_ERROR_SURFACE_FAIL = 2; // 0x2
   }
 
-  public static abstract class MediaSync.Callback {
+  public abstract static class MediaSync.Callback {
     ctor public MediaSync.Callback();
-    method public abstract void onAudioBufferConsumed(android.media.MediaSync, java.nio.ByteBuffer, int);
+    method public abstract void onAudioBufferConsumed(@NonNull android.media.MediaSync, @NonNull java.nio.ByteBuffer, int);
   }
 
-  public static abstract interface MediaSync.OnErrorListener {
-    method public abstract void onError(android.media.MediaSync, int, int);
+  public static interface MediaSync.OnErrorListener {
+    method public void onError(@NonNull android.media.MediaSync, int, int);
   }
 
   public class MediaSyncEvent {
@@ -25811,17 +25986,17 @@
   public final class MediaTimestamp {
     method public long getAnchorMediaTimeUs();
     method public long getAnchorSystemNanoTime();
-    method public deprecated long getAnchorSytemNanoTime();
+    method @Deprecated public long getAnchorSytemNanoTime();
     method public float getMediaClockRate();
     field public static final android.media.MediaTimestamp TIMESTAMP_UNKNOWN;
   }
 
   public final class MicrophoneInfo {
-    method public java.lang.String getAddress();
-    method public java.util.List<android.util.Pair<java.lang.Integer, java.lang.Integer>> getChannelMapping();
-    method public java.lang.String getDescription();
+    method @NonNull public String getAddress();
+    method public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getChannelMapping();
+    method public String getDescription();
     method public int getDirectionality();
-    method public java.util.List<android.util.Pair<java.lang.Float, java.lang.Float>> getFrequencyResponse();
+    method public java.util.List<android.util.Pair<java.lang.Float,java.lang.Float>> getFrequencyResponse();
     method public int getGroup();
     method public int getId();
     method public int getIndexInTheGroup();
@@ -25859,7 +26034,7 @@
   }
 
   public final class NotProvisionedException extends android.media.MediaDrmException {
-    ctor public NotProvisionedException(java.lang.String);
+    ctor public NotProvisionedException(String);
   }
 
   public final class PlaybackParams implements android.os.Parcelable {
@@ -25903,102 +26078,102 @@
     field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
   }
 
-  public deprecated class RemoteControlClient {
-    ctor public RemoteControlClient(android.app.PendingIntent);
-    ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper);
-    method public android.media.RemoteControlClient.MetadataEditor editMetadata(boolean);
-    method public android.media.session.MediaSession getMediaSession();
-    method public void setMetadataUpdateListener(android.media.RemoteControlClient.OnMetadataUpdateListener);
-    method public void setOnGetPlaybackPositionListener(android.media.RemoteControlClient.OnGetPlaybackPositionListener);
-    method public void setPlaybackPositionUpdateListener(android.media.RemoteControlClient.OnPlaybackPositionUpdateListener);
-    method public void setPlaybackState(int);
-    method public void setPlaybackState(int, long, float);
-    method public void setTransportControlFlags(int);
-    field public static final int FLAG_KEY_MEDIA_FAST_FORWARD = 64; // 0x40
-    field public static final int FLAG_KEY_MEDIA_NEXT = 128; // 0x80
-    field public static final int FLAG_KEY_MEDIA_PAUSE = 16; // 0x10
-    field public static final int FLAG_KEY_MEDIA_PLAY = 4; // 0x4
-    field public static final int FLAG_KEY_MEDIA_PLAY_PAUSE = 8; // 0x8
-    field public static final int FLAG_KEY_MEDIA_POSITION_UPDATE = 256; // 0x100
-    field public static final int FLAG_KEY_MEDIA_PREVIOUS = 1; // 0x1
-    field public static final int FLAG_KEY_MEDIA_RATING = 512; // 0x200
-    field public static final int FLAG_KEY_MEDIA_REWIND = 2; // 0x2
-    field public static final int FLAG_KEY_MEDIA_STOP = 32; // 0x20
-    field public static final int PLAYSTATE_BUFFERING = 8; // 0x8
-    field public static final int PLAYSTATE_ERROR = 9; // 0x9
-    field public static final int PLAYSTATE_FAST_FORWARDING = 4; // 0x4
-    field public static final int PLAYSTATE_PAUSED = 2; // 0x2
-    field public static final int PLAYSTATE_PLAYING = 3; // 0x3
-    field public static final int PLAYSTATE_REWINDING = 5; // 0x5
-    field public static final int PLAYSTATE_SKIPPING_BACKWARDS = 7; // 0x7
-    field public static final int PLAYSTATE_SKIPPING_FORWARDS = 6; // 0x6
-    field public static final int PLAYSTATE_STOPPED = 1; // 0x1
+  @Deprecated public class RemoteControlClient {
+    ctor @Deprecated public RemoteControlClient(android.app.PendingIntent);
+    ctor @Deprecated public RemoteControlClient(android.app.PendingIntent, android.os.Looper);
+    method @Deprecated public android.media.RemoteControlClient.MetadataEditor editMetadata(boolean);
+    method @Deprecated public android.media.session.MediaSession getMediaSession();
+    method @Deprecated public void setMetadataUpdateListener(android.media.RemoteControlClient.OnMetadataUpdateListener);
+    method @Deprecated public void setOnGetPlaybackPositionListener(android.media.RemoteControlClient.OnGetPlaybackPositionListener);
+    method @Deprecated public void setPlaybackPositionUpdateListener(android.media.RemoteControlClient.OnPlaybackPositionUpdateListener);
+    method @Deprecated public void setPlaybackState(int);
+    method @Deprecated public void setPlaybackState(int, long, float);
+    method @Deprecated public void setTransportControlFlags(int);
+    field @Deprecated public static final int FLAG_KEY_MEDIA_FAST_FORWARD = 64; // 0x40
+    field @Deprecated public static final int FLAG_KEY_MEDIA_NEXT = 128; // 0x80
+    field @Deprecated public static final int FLAG_KEY_MEDIA_PAUSE = 16; // 0x10
+    field @Deprecated public static final int FLAG_KEY_MEDIA_PLAY = 4; // 0x4
+    field @Deprecated public static final int FLAG_KEY_MEDIA_PLAY_PAUSE = 8; // 0x8
+    field @Deprecated public static final int FLAG_KEY_MEDIA_POSITION_UPDATE = 256; // 0x100
+    field @Deprecated public static final int FLAG_KEY_MEDIA_PREVIOUS = 1; // 0x1
+    field @Deprecated public static final int FLAG_KEY_MEDIA_RATING = 512; // 0x200
+    field @Deprecated public static final int FLAG_KEY_MEDIA_REWIND = 2; // 0x2
+    field @Deprecated public static final int FLAG_KEY_MEDIA_STOP = 32; // 0x20
+    field @Deprecated public static final int PLAYSTATE_BUFFERING = 8; // 0x8
+    field @Deprecated public static final int PLAYSTATE_ERROR = 9; // 0x9
+    field @Deprecated public static final int PLAYSTATE_FAST_FORWARDING = 4; // 0x4
+    field @Deprecated public static final int PLAYSTATE_PAUSED = 2; // 0x2
+    field @Deprecated public static final int PLAYSTATE_PLAYING = 3; // 0x3
+    field @Deprecated public static final int PLAYSTATE_REWINDING = 5; // 0x5
+    field @Deprecated public static final int PLAYSTATE_SKIPPING_BACKWARDS = 7; // 0x7
+    field @Deprecated public static final int PLAYSTATE_SKIPPING_FORWARDS = 6; // 0x6
+    field @Deprecated public static final int PLAYSTATE_STOPPED = 1; // 0x1
   }
 
-  public deprecated class RemoteControlClient.MetadataEditor extends android.media.MediaMetadataEditor {
-    method public synchronized void apply();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public synchronized android.media.RemoteControlClient.MetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
-    method public synchronized android.media.RemoteControlClient.MetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
-    method public synchronized android.media.RemoteControlClient.MetadataEditor putObject(int, java.lang.Object) throws java.lang.IllegalArgumentException;
-    method public synchronized android.media.RemoteControlClient.MetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
-    field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
+  @Deprecated public class RemoteControlClient.MetadataEditor extends android.media.MediaMetadataEditor {
+    method @Deprecated public void apply();
+    method public Object clone() throws java.lang.CloneNotSupportedException;
+    method @Deprecated public android.media.RemoteControlClient.MetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+    method @Deprecated public android.media.RemoteControlClient.MetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
+    method @Deprecated public android.media.RemoteControlClient.MetadataEditor putObject(int, Object) throws java.lang.IllegalArgumentException;
+    method @Deprecated public android.media.RemoteControlClient.MetadataEditor putString(int, String) throws java.lang.IllegalArgumentException;
+    field @Deprecated public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
   }
 
-  public static abstract interface RemoteControlClient.OnGetPlaybackPositionListener {
-    method public abstract long onGetPlaybackPosition();
+  @Deprecated public static interface RemoteControlClient.OnGetPlaybackPositionListener {
+    method @Deprecated public long onGetPlaybackPosition();
   }
 
-  public static abstract interface RemoteControlClient.OnMetadataUpdateListener {
-    method public abstract void onMetadataUpdate(int, java.lang.Object);
+  @Deprecated public static interface RemoteControlClient.OnMetadataUpdateListener {
+    method @Deprecated public void onMetadataUpdate(int, Object);
   }
 
-  public static abstract interface RemoteControlClient.OnPlaybackPositionUpdateListener {
-    method public abstract void onPlaybackPositionUpdate(long);
+  @Deprecated public static interface RemoteControlClient.OnPlaybackPositionUpdateListener {
+    method @Deprecated public void onPlaybackPositionUpdate(long);
   }
 
-  public final deprecated class RemoteController {
-    ctor public RemoteController(android.content.Context, android.media.RemoteController.OnClientUpdateListener) throws java.lang.IllegalArgumentException;
-    ctor public RemoteController(android.content.Context, android.media.RemoteController.OnClientUpdateListener, android.os.Looper) throws java.lang.IllegalArgumentException;
-    method public boolean clearArtworkConfiguration();
-    method public android.media.RemoteController.MetadataEditor editMetadata();
-    method public long getEstimatedMediaPosition();
-    method public boolean seekTo(long) throws java.lang.IllegalArgumentException;
-    method public boolean sendMediaKeyEvent(android.view.KeyEvent) throws java.lang.IllegalArgumentException;
-    method public boolean setArtworkConfiguration(int, int) throws java.lang.IllegalArgumentException;
-    method public boolean setSynchronizationMode(int) throws java.lang.IllegalArgumentException;
-    field public static final int POSITION_SYNCHRONIZATION_CHECK = 1; // 0x1
-    field public static final int POSITION_SYNCHRONIZATION_NONE = 0; // 0x0
+  @Deprecated public final class RemoteController {
+    ctor @Deprecated public RemoteController(android.content.Context, android.media.RemoteController.OnClientUpdateListener) throws java.lang.IllegalArgumentException;
+    ctor @Deprecated public RemoteController(android.content.Context, android.media.RemoteController.OnClientUpdateListener, android.os.Looper) throws java.lang.IllegalArgumentException;
+    method @Deprecated public boolean clearArtworkConfiguration();
+    method @Deprecated public android.media.RemoteController.MetadataEditor editMetadata();
+    method @Deprecated public long getEstimatedMediaPosition();
+    method @Deprecated public boolean seekTo(long) throws java.lang.IllegalArgumentException;
+    method @Deprecated public boolean sendMediaKeyEvent(android.view.KeyEvent) throws java.lang.IllegalArgumentException;
+    method @Deprecated public boolean setArtworkConfiguration(int, int) throws java.lang.IllegalArgumentException;
+    method @Deprecated public boolean setSynchronizationMode(int) throws java.lang.IllegalArgumentException;
+    field @Deprecated public static final int POSITION_SYNCHRONIZATION_CHECK = 1; // 0x1
+    field @Deprecated public static final int POSITION_SYNCHRONIZATION_NONE = 0; // 0x0
   }
 
-  public class RemoteController.MetadataEditor extends android.media.MediaMetadataEditor {
-    method public synchronized void apply();
+  @Deprecated public class RemoteController.MetadataEditor extends android.media.MediaMetadataEditor {
+    method @Deprecated public void apply();
   }
 
-  public static abstract interface RemoteController.OnClientUpdateListener {
-    method public abstract void onClientChange(boolean);
-    method public abstract void onClientMetadataUpdate(android.media.RemoteController.MetadataEditor);
-    method public abstract void onClientPlaybackStateUpdate(int);
-    method public abstract void onClientPlaybackStateUpdate(int, long, long, float);
-    method public abstract void onClientTransportControlUpdate(int);
+  @Deprecated public static interface RemoteController.OnClientUpdateListener {
+    method @Deprecated public void onClientChange(boolean);
+    method @Deprecated public void onClientMetadataUpdate(android.media.RemoteController.MetadataEditor);
+    method @Deprecated public void onClientPlaybackStateUpdate(int);
+    method @Deprecated public void onClientPlaybackStateUpdate(int, long, long, float);
+    method @Deprecated public void onClientTransportControlUpdate(int);
   }
 
   public final class ResourceBusyException extends android.media.MediaDrmException {
-    ctor public ResourceBusyException(java.lang.String);
+    ctor public ResourceBusyException(String);
   }
 
   public class Ringtone {
     method protected void finalize();
     method public android.media.AudioAttributes getAudioAttributes();
-    method public deprecated int getStreamType();
-    method public java.lang.String getTitle(android.content.Context);
+    method @Deprecated public int getStreamType();
+    method public String getTitle(android.content.Context);
     method public float getVolume();
     method public boolean isLooping();
     method public boolean isPlaying();
     method public void play();
     method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
     method public void setLooping(boolean);
-    method public deprecated void setStreamType(int);
+    method @Deprecated public void setStreamType(int);
     method public void setVolume(float);
     method public void stop();
   }
@@ -26010,7 +26185,7 @@
     method public android.database.Cursor getCursor();
     method public static int getDefaultType(android.net.Uri);
     method public static android.net.Uri getDefaultUri(int);
-    method public deprecated boolean getIncludeDrm();
+    method @Deprecated public boolean getIncludeDrm();
     method public android.media.Ringtone getRingtone(int);
     method public static android.media.Ringtone getRingtone(android.content.Context, android.net.Uri);
     method public int getRingtonePosition(android.net.Uri);
@@ -26019,21 +26194,21 @@
     method public static android.net.Uri getValidRingtoneUri(android.content.Context);
     method public int inferStreamType();
     method public static boolean isDefault(android.net.Uri);
-    method public static android.content.res.AssetFileDescriptor openDefaultRingtoneUri(android.content.Context, android.net.Uri) throws java.io.FileNotFoundException;
+    method @Nullable public static android.content.res.AssetFileDescriptor openDefaultRingtoneUri(@NonNull android.content.Context, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
     method public static void setActualDefaultRingtoneUri(android.content.Context, int, android.net.Uri);
-    method public deprecated void setIncludeDrm(boolean);
+    method @Deprecated public void setIncludeDrm(boolean);
     method public void setStopPreviousRingtone(boolean);
     method public void setType(int);
     method public void stopPreviousRingtone();
-    field public static final java.lang.String ACTION_RINGTONE_PICKER = "android.intent.action.RINGTONE_PICKER";
-    field public static final java.lang.String EXTRA_RINGTONE_DEFAULT_URI = "android.intent.extra.ringtone.DEFAULT_URI";
-    field public static final java.lang.String EXTRA_RINGTONE_EXISTING_URI = "android.intent.extra.ringtone.EXISTING_URI";
-    field public static final deprecated java.lang.String EXTRA_RINGTONE_INCLUDE_DRM = "android.intent.extra.ringtone.INCLUDE_DRM";
-    field public static final java.lang.String EXTRA_RINGTONE_PICKED_URI = "android.intent.extra.ringtone.PICKED_URI";
-    field public static final java.lang.String EXTRA_RINGTONE_SHOW_DEFAULT = "android.intent.extra.ringtone.SHOW_DEFAULT";
-    field public static final java.lang.String EXTRA_RINGTONE_SHOW_SILENT = "android.intent.extra.ringtone.SHOW_SILENT";
-    field public static final java.lang.String EXTRA_RINGTONE_TITLE = "android.intent.extra.ringtone.TITLE";
-    field public static final java.lang.String EXTRA_RINGTONE_TYPE = "android.intent.extra.ringtone.TYPE";
+    field public static final String ACTION_RINGTONE_PICKER = "android.intent.action.RINGTONE_PICKER";
+    field public static final String EXTRA_RINGTONE_DEFAULT_URI = "android.intent.extra.ringtone.DEFAULT_URI";
+    field public static final String EXTRA_RINGTONE_EXISTING_URI = "android.intent.extra.ringtone.EXISTING_URI";
+    field @Deprecated public static final String EXTRA_RINGTONE_INCLUDE_DRM = "android.intent.extra.ringtone.INCLUDE_DRM";
+    field public static final String EXTRA_RINGTONE_PICKED_URI = "android.intent.extra.ringtone.PICKED_URI";
+    field public static final String EXTRA_RINGTONE_SHOW_DEFAULT = "android.intent.extra.ringtone.SHOW_DEFAULT";
+    field public static final String EXTRA_RINGTONE_SHOW_SILENT = "android.intent.extra.ringtone.SHOW_SILENT";
+    field public static final String EXTRA_RINGTONE_TITLE = "android.intent.extra.ringtone.TITLE";
+    field public static final String EXTRA_RINGTONE_TYPE = "android.intent.extra.ringtone.TYPE";
     field public static final int ID_COLUMN_INDEX = 0; // 0x0
     field public static final int TITLE_COLUMN_INDEX = 1; // 0x1
     field public static final int TYPE_ALARM = 4; // 0x4
@@ -26043,12 +26218,66 @@
     field public static final int URI_COLUMN_INDEX = 2; // 0x2
   }
 
+  public final class Session2Command implements android.os.Parcelable {
+    ctor public Session2Command(int);
+    ctor public Session2Command(@NonNull String, @Nullable android.os.Bundle);
+    method public int describeContents();
+    method public int getCommandCode();
+    method @Nullable public String getCustomCommand();
+    method @Nullable public android.os.Bundle getExtras();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int COMMAND_CODE_CUSTOM = 0; // 0x0
+    field public static final android.os.Parcelable.Creator<android.media.Session2Command> CREATOR;
+    field public static final int RESULT_ERROR_UNKNOWN_ERROR = -1; // 0xffffffff
+    field public static final int RESULT_INFO_SKIPPED = 1; // 0x1
+    field public static final int RESULT_SUCCESS = 0; // 0x0
+  }
+
+  public static final class Session2Command.Result {
+    ctor public Session2Command.Result(int, @Nullable android.os.Bundle);
+    method public int getResultCode();
+    method @Nullable public android.os.Bundle getResultData();
+  }
+
+  public final class Session2CommandGroup implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.Set<android.media.Session2Command> getCommands();
+    method public boolean hasCommand(@NonNull android.media.Session2Command);
+    method public boolean hasCommand(int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.Session2CommandGroup> CREATOR;
+  }
+
+  public static final class Session2CommandGroup.Builder {
+    ctor public Session2CommandGroup.Builder();
+    ctor public Session2CommandGroup.Builder(@NonNull android.media.Session2CommandGroup);
+    method @NonNull public android.media.Session2CommandGroup.Builder addCommand(@NonNull android.media.Session2Command);
+    method @NonNull public android.media.Session2CommandGroup.Builder addCommand(int);
+    method @NonNull public android.media.Session2CommandGroup build();
+    method @NonNull public android.media.Session2CommandGroup.Builder removeCommand(@NonNull android.media.Session2Command);
+    method @NonNull public android.media.Session2CommandGroup.Builder removeCommand(int);
+  }
+
+  public final class Session2Token implements android.os.Parcelable {
+    ctor public Session2Token(@NonNull android.content.Context, @NonNull android.content.ComponentName);
+    method public int describeContents();
+    method @NonNull public String getPackageName();
+    method @Nullable public String getServiceName();
+    method public int getType();
+    method public int getUid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.Session2Token> CREATOR;
+    field public static final int TYPE_SESSION = 0; // 0x0
+    field public static final int TYPE_SESSION_SERVICE = 1; // 0x1
+  }
+
   public class SoundPool {
-    ctor public deprecated SoundPool(int, int, int);
+    ctor @Deprecated public SoundPool(int, int, int);
     method public final void autoPause();
     method public final void autoResume();
+    method public static void deprecateStreamTypeForPlayback(int, String, String) throws java.lang.IllegalArgumentException;
     method protected void finalize();
-    method public int load(java.lang.String, int);
+    method public int load(String, int);
     method public int load(android.content.Context, int, int);
     method public int load(android.content.res.AssetFileDescriptor, int);
     method public int load(java.io.FileDescriptor, long, long, int);
@@ -26072,12 +26301,12 @@
     method public android.media.SoundPool.Builder setMaxStreams(int) throws java.lang.IllegalArgumentException;
   }
 
-  public static abstract interface SoundPool.OnLoadCompleteListener {
-    method public abstract void onLoadComplete(android.media.SoundPool, int, int);
+  public static interface SoundPool.OnLoadCompleteListener {
+    method public void onLoadComplete(android.media.SoundPool, int, int);
   }
 
   public final class SubtitleData {
-    method public byte[] getData();
+    method @NonNull public byte[] getData();
     method public long getDurationUs();
     method public long getStartTimeUs();
     method public int getTrackIndex();
@@ -26105,12 +26334,12 @@
 
   public class ThumbnailUtils {
     ctor public ThumbnailUtils();
-    method public static deprecated android.graphics.Bitmap createAudioThumbnail(java.lang.String, int);
-    method public static android.graphics.Bitmap createAudioThumbnail(java.io.File, android.util.Size, android.os.CancellationSignal) throws java.io.IOException;
-    method public static deprecated android.graphics.Bitmap createImageThumbnail(java.lang.String, int);
-    method public static android.graphics.Bitmap createImageThumbnail(java.io.File, android.util.Size, android.os.CancellationSignal) throws java.io.IOException;
-    method public static deprecated android.graphics.Bitmap createVideoThumbnail(java.lang.String, int);
-    method public static android.graphics.Bitmap createVideoThumbnail(java.io.File, android.util.Size, android.os.CancellationSignal) throws java.io.IOException;
+    method @Deprecated @Nullable public static android.graphics.Bitmap createAudioThumbnail(@NonNull String, int);
+    method @NonNull public static android.graphics.Bitmap createAudioThumbnail(@NonNull java.io.File, @NonNull android.util.Size, @Nullable android.os.CancellationSignal) throws java.io.IOException;
+    method @Deprecated @Nullable public static android.graphics.Bitmap createImageThumbnail(@NonNull String, int);
+    method @NonNull public static android.graphics.Bitmap createImageThumbnail(@NonNull java.io.File, @NonNull android.util.Size, @Nullable android.os.CancellationSignal) throws java.io.IOException;
+    method @Deprecated @Nullable public static android.graphics.Bitmap createVideoThumbnail(@NonNull String, int);
+    method @NonNull public static android.graphics.Bitmap createVideoThumbnail(@NonNull java.io.File, @NonNull android.util.Size, @Nullable android.os.CancellationSignal) throws java.io.IOException;
     method public static android.graphics.Bitmap extractThumbnail(android.graphics.Bitmap, int, int);
     method public static android.graphics.Bitmap extractThumbnail(android.graphics.Bitmap, int, int, int);
     field public static final int OPTIONS_RECYCLE_INPUT = 2; // 0x2
@@ -26123,7 +26352,7 @@
 
   public final class TimedText {
     method public android.graphics.Rect getBounds();
-    method public java.lang.String getText();
+    method public String getText();
   }
 
   public class ToneGenerator {
@@ -26238,22 +26467,22 @@
   }
 
   public final class UnsupportedSchemeException extends android.media.MediaDrmException {
-    ctor public UnsupportedSchemeException(java.lang.String);
+    ctor public UnsupportedSchemeException(String);
   }
 
   public class UriDataSourceDesc extends android.media.DataSourceDesc {
     method public android.content.Context getContext();
     method public java.util.List<java.net.HttpCookie> getCookies();
-    method public java.util.Map<java.lang.String, java.lang.String> getHeaders();
+    method public java.util.Map<java.lang.String,java.lang.String> getHeaders();
     method public android.net.Uri getUri();
   }
 
-  public static class UriDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase {
+  public static class UriDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase<android.media.UriDataSourceDesc.Builder> {
     ctor public UriDataSourceDesc.Builder();
     ctor public UriDataSourceDesc.Builder(android.media.UriDataSourceDesc);
-    method public android.media.UriDataSourceDesc build();
-    method public android.media.UriDataSourceDesc.Builder setDataSource(android.content.Context, android.net.Uri);
-    method public android.media.UriDataSourceDesc.Builder setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>, java.util.List<java.net.HttpCookie>);
+    method @NonNull public android.media.UriDataSourceDesc build();
+    method @NonNull public android.media.UriDataSourceDesc.Builder setDataSource(@NonNull android.content.Context, @NonNull android.net.Uri);
+    method @NonNull public android.media.UriDataSourceDesc.Builder setDataSource(@NonNull android.content.Context, @NonNull android.net.Uri, @Nullable java.util.Map<java.lang.String,java.lang.String>, @Nullable java.util.List<java.net.HttpCookie>);
   }
 
   public final class VideoSize {
@@ -26261,8 +26490,8 @@
     method public int getWidth();
   }
 
-  public abstract interface VolumeAutomation {
-    method public abstract android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
+  public interface VolumeAutomation {
+    method @NonNull public android.media.VolumeShaper createVolumeShaper(@NonNull android.media.VolumeShaper.Configuration);
   }
 
   public abstract class VolumeProvider {
@@ -26279,11 +26508,11 @@
   }
 
   public final class VolumeShaper implements java.lang.AutoCloseable {
-    method public void apply(android.media.VolumeShaper.Operation);
+    method public void apply(@NonNull android.media.VolumeShaper.Operation);
     method public void close();
     method protected void finalize();
     method public float getVolume();
-    method public void replace(android.media.VolumeShaper.Configuration, android.media.VolumeShaper.Operation, boolean);
+    method public void replace(@NonNull android.media.VolumeShaper.Configuration, @NonNull android.media.VolumeShaper.Operation, boolean);
   }
 
   public static final class VolumeShaper.Configuration implements android.os.Parcelable {
@@ -26307,15 +26536,15 @@
 
   public static final class VolumeShaper.Configuration.Builder {
     ctor public VolumeShaper.Configuration.Builder();
-    ctor public VolumeShaper.Configuration.Builder(android.media.VolumeShaper.Configuration);
-    method public android.media.VolumeShaper.Configuration build();
-    method public android.media.VolumeShaper.Configuration.Builder invertVolumes();
-    method public android.media.VolumeShaper.Configuration.Builder reflectTimes();
-    method public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
-    method public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
-    method public android.media.VolumeShaper.Configuration.Builder setCurve(float[], float[]);
-    method public android.media.VolumeShaper.Configuration.Builder setDuration(long);
-    method public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
+    ctor public VolumeShaper.Configuration.Builder(@NonNull android.media.VolumeShaper.Configuration);
+    method @NonNull public android.media.VolumeShaper.Configuration build();
+    method @NonNull public android.media.VolumeShaper.Configuration.Builder invertVolumes();
+    method @NonNull public android.media.VolumeShaper.Configuration.Builder reflectTimes();
+    method @NonNull public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
+    method @NonNull public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
+    method @NonNull public android.media.VolumeShaper.Configuration.Builder setCurve(@NonNull float[], @NonNull float[]);
+    method @NonNull public android.media.VolumeShaper.Configuration.Builder setDuration(long);
+    method @NonNull public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
   }
 
   public static final class VolumeShaper.Operation implements android.os.Parcelable {
@@ -26346,16 +26575,16 @@
     method public void setControlStatusListener(android.media.audiofx.AudioEffect.OnControlStatusChangeListener);
     method public void setEnableStatusListener(android.media.audiofx.AudioEffect.OnEnableStatusChangeListener);
     method public int setEnabled(boolean) throws java.lang.IllegalStateException;
-    field public static final java.lang.String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION = "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION";
-    field public static final java.lang.String ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL = "android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL";
-    field public static final java.lang.String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION = "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION";
+    field public static final String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION = "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION";
+    field public static final String ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL = "android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL";
+    field public static final String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION = "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION";
     field public static final int ALREADY_EXISTS = -2; // 0xfffffffe
     field public static final int CONTENT_TYPE_GAME = 2; // 0x2
     field public static final int CONTENT_TYPE_MOVIE = 1; // 0x1
     field public static final int CONTENT_TYPE_MUSIC = 0; // 0x0
     field public static final int CONTENT_TYPE_VOICE = 3; // 0x3
-    field public static final java.lang.String EFFECT_AUXILIARY = "Auxiliary";
-    field public static final java.lang.String EFFECT_INSERT = "Insert";
+    field public static final String EFFECT_AUXILIARY = "Auxiliary";
+    field public static final String EFFECT_INSERT = "Insert";
     field public static final java.util.UUID EFFECT_TYPE_AEC;
     field public static final java.util.UUID EFFECT_TYPE_AGC;
     field public static final java.util.UUID EFFECT_TYPE_BASS_BOOST;
@@ -26372,31 +26601,28 @@
     field public static final int ERROR_INVALID_OPERATION = -5; // 0xfffffffb
     field public static final int ERROR_NO_INIT = -3; // 0xfffffffd
     field public static final int ERROR_NO_MEMORY = -6; // 0xfffffffa
-    field public static final java.lang.String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION";
-    field public static final java.lang.String EXTRA_CONTENT_TYPE = "android.media.extra.CONTENT_TYPE";
-    field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME";
+    field public static final String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION";
+    field public static final String EXTRA_CONTENT_TYPE = "android.media.extra.CONTENT_TYPE";
+    field public static final String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME";
     field public static final int SUCCESS = 0; // 0x0
   }
 
-  public static final class AudioEffect.Descriptor implements android.os.Parcelable {
+  public static class AudioEffect.Descriptor {
     ctor public AudioEffect.Descriptor();
-    ctor public AudioEffect.Descriptor(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.media.audiofx.AudioEffect.Descriptor> CREATOR;
-    field public java.lang.String connectMode;
-    field public java.lang.String implementor;
-    field public java.lang.String name;
+    ctor public AudioEffect.Descriptor(String, String, String, String, String);
+    field public String connectMode;
+    field public String implementor;
+    field public String name;
     field public java.util.UUID type;
     field public java.util.UUID uuid;
   }
 
-  public static abstract interface AudioEffect.OnControlStatusChangeListener {
-    method public abstract void onControlStatusChange(android.media.audiofx.AudioEffect, boolean);
+  public static interface AudioEffect.OnControlStatusChangeListener {
+    method public void onControlStatusChange(android.media.audiofx.AudioEffect, boolean);
   }
 
-  public static abstract interface AudioEffect.OnEnableStatusChangeListener {
-    method public abstract void onEnableStatusChange(android.media.audiofx.AudioEffect, boolean);
+  public static interface AudioEffect.OnEnableStatusChangeListener {
+    method public void onEnableStatusChange(android.media.audiofx.AudioEffect, boolean);
   }
 
   public class AutomaticGainControl extends android.media.audiofx.AudioEffect {
@@ -26416,19 +26642,19 @@
     field public static final int PARAM_STRENGTH_SUPPORTED = 0; // 0x0
   }
 
-  public static abstract interface BassBoost.OnParameterChangeListener {
-    method public abstract void onParameterChange(android.media.audiofx.BassBoost, int, int, short);
+  public static interface BassBoost.OnParameterChangeListener {
+    method public void onParameterChange(android.media.audiofx.BassBoost, int, int, short);
   }
 
   public static class BassBoost.Settings {
     ctor public BassBoost.Settings();
-    ctor public BassBoost.Settings(java.lang.String);
+    ctor public BassBoost.Settings(String);
     field public short strength;
   }
 
   public final class DynamicsProcessing extends android.media.audiofx.AudioEffect {
     ctor public DynamicsProcessing(int);
-    ctor public DynamicsProcessing(int, int, android.media.audiofx.DynamicsProcessing.Config);
+    ctor public DynamicsProcessing(int, int, @Nullable android.media.audiofx.DynamicsProcessing.Config);
     method public android.media.audiofx.DynamicsProcessing.Channel getChannelByChannelIndex(int);
     method public int getChannelCount();
     method public android.media.audiofx.DynamicsProcessing.Config getConfig();
@@ -26658,13 +26884,13 @@
     field public static final int PARAM_ROOM_LEVEL = 0; // 0x0
   }
 
-  public static abstract interface EnvironmentalReverb.OnParameterChangeListener {
-    method public abstract void onParameterChange(android.media.audiofx.EnvironmentalReverb, int, int, int);
+  public static interface EnvironmentalReverb.OnParameterChangeListener {
+    method public void onParameterChange(android.media.audiofx.EnvironmentalReverb, int, int, int);
   }
 
   public static class EnvironmentalReverb.Settings {
     ctor public EnvironmentalReverb.Settings();
-    ctor public EnvironmentalReverb.Settings(java.lang.String);
+    ctor public EnvironmentalReverb.Settings(String);
     field public short decayHFRatio;
     field public int decayTime;
     field public short density;
@@ -26687,7 +26913,7 @@
     method public short getCurrentPreset() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
     method public short getNumberOfBands() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
     method public short getNumberOfPresets() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
-    method public java.lang.String getPresetName(short);
+    method public String getPresetName(short);
     method public android.media.audiofx.Equalizer.Settings getProperties() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
     method public void setBandLevel(short, short) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
     method public void setParameterListener(android.media.audiofx.Equalizer.OnParameterChangeListener);
@@ -26705,13 +26931,13 @@
     field public static final int PARAM_STRING_SIZE_MAX = 32; // 0x20
   }
 
-  public static abstract interface Equalizer.OnParameterChangeListener {
-    method public abstract void onParameterChange(android.media.audiofx.Equalizer, int, int, int, int);
+  public static interface Equalizer.OnParameterChangeListener {
+    method public void onParameterChange(android.media.audiofx.Equalizer, int, int, int, int);
   }
 
   public static class Equalizer.Settings {
     ctor public Equalizer.Settings();
-    ctor public Equalizer.Settings(java.lang.String);
+    ctor public Equalizer.Settings(String);
     field public short[] bandLevels;
     field public short curPreset;
     field public short numBands;
@@ -26746,13 +26972,13 @@
     field public static final short PRESET_SMALLROOM = 1; // 0x1
   }
 
-  public static abstract interface PresetReverb.OnParameterChangeListener {
-    method public abstract void onParameterChange(android.media.audiofx.PresetReverb, int, int, short);
+  public static interface PresetReverb.OnParameterChangeListener {
+    method public void onParameterChange(android.media.audiofx.PresetReverb, int, int, short);
   }
 
   public static class PresetReverb.Settings {
     ctor public PresetReverb.Settings();
-    ctor public PresetReverb.Settings(java.lang.String);
+    ctor public PresetReverb.Settings(String);
     field public short preset;
   }
 
@@ -26776,13 +27002,13 @@
     field public static final int VIRTUALIZATION_MODE_TRANSAURAL = 3; // 0x3
   }
 
-  public static abstract interface Virtualizer.OnParameterChangeListener {
-    method public abstract void onParameterChange(android.media.audiofx.Virtualizer, int, int, short);
+  public static interface Virtualizer.OnParameterChangeListener {
+    method public void onParameterChange(android.media.audiofx.Virtualizer, int, int, short);
   }
 
   public static class Virtualizer.Settings {
     ctor public Virtualizer.Settings();
-    ctor public Virtualizer.Settings(java.lang.String);
+    ctor public Virtualizer.Settings(String);
     field public short strength;
   }
 
@@ -26828,9 +27054,9 @@
     field public int mRms;
   }
 
-  public static abstract interface Visualizer.OnDataCaptureListener {
-    method public abstract void onFftDataCapture(android.media.audiofx.Visualizer, byte[], int);
-    method public abstract void onWaveFormDataCapture(android.media.audiofx.Visualizer, byte[], int);
+  public static interface Visualizer.OnDataCaptureListener {
+    method public void onFftDataCapture(android.media.audiofx.Visualizer, byte[], int);
+    method public void onWaveFormDataCapture(android.media.audiofx.Visualizer, byte[], int);
   }
 
 }
@@ -26841,18 +27067,18 @@
     ctor public MediaBrowser(android.content.Context, android.content.ComponentName, android.media.browse.MediaBrowser.ConnectionCallback, android.os.Bundle);
     method public void connect();
     method public void disconnect();
-    method public android.os.Bundle getExtras();
-    method public void getItem(java.lang.String, android.media.browse.MediaBrowser.ItemCallback);
-    method public java.lang.String getRoot();
-    method public android.content.ComponentName getServiceComponent();
-    method public android.media.session.MediaSession.Token getSessionToken();
+    method @Nullable public android.os.Bundle getExtras();
+    method public void getItem(@NonNull String, @NonNull android.media.browse.MediaBrowser.ItemCallback);
+    method @NonNull public String getRoot();
+    method @NonNull public android.content.ComponentName getServiceComponent();
+    method @NonNull public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isConnected();
-    method public void subscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
-    method public void subscribe(java.lang.String, android.os.Bundle, android.media.browse.MediaBrowser.SubscriptionCallback);
-    method public void unsubscribe(java.lang.String);
-    method public void unsubscribe(java.lang.String, android.media.browse.MediaBrowser.SubscriptionCallback);
-    field public static final java.lang.String EXTRA_PAGE = "android.media.browse.extra.PAGE";
-    field public static final java.lang.String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
+    method public void subscribe(@NonNull String, @NonNull android.media.browse.MediaBrowser.SubscriptionCallback);
+    method public void subscribe(@NonNull String, @NonNull android.os.Bundle, @NonNull android.media.browse.MediaBrowser.SubscriptionCallback);
+    method public void unsubscribe(@NonNull String);
+    method public void unsubscribe(@NonNull String, @NonNull android.media.browse.MediaBrowser.SubscriptionCallback);
+    field public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
+    field public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
   }
 
   public static class MediaBrowser.ConnectionCallback {
@@ -26862,18 +27088,18 @@
     method public void onConnectionSuspended();
   }
 
-  public static abstract class MediaBrowser.ItemCallback {
+  public abstract static class MediaBrowser.ItemCallback {
     ctor public MediaBrowser.ItemCallback();
-    method public void onError(java.lang.String);
+    method public void onError(@NonNull String);
     method public void onItemLoaded(android.media.browse.MediaBrowser.MediaItem);
   }
 
   public static class MediaBrowser.MediaItem implements android.os.Parcelable {
-    ctor public MediaBrowser.MediaItem(android.media.MediaDescription, int);
+    ctor public MediaBrowser.MediaItem(@NonNull android.media.MediaDescription, int);
     method public int describeContents();
-    method public android.media.MediaDescription getDescription();
+    method @NonNull public android.media.MediaDescription getDescription();
     method public int getFlags();
-    method public java.lang.String getMediaId();
+    method @Nullable public String getMediaId();
     method public boolean isBrowsable();
     method public boolean isPlayable();
     method public void writeToParcel(android.os.Parcel, int);
@@ -26882,12 +27108,12 @@
     field public static final int FLAG_PLAYABLE = 2; // 0x2
   }
 
-  public static abstract class MediaBrowser.SubscriptionCallback {
+  public abstract static class MediaBrowser.SubscriptionCallback {
     ctor public MediaBrowser.SubscriptionCallback();
-    method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
-    method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>, android.os.Bundle);
-    method public void onError(java.lang.String);
-    method public void onError(java.lang.String, android.os.Bundle);
+    method public void onChildrenLoaded(@NonNull String, @NonNull java.util.List<android.media.browse.MediaBrowser.MediaItem>);
+    method public void onChildrenLoaded(@NonNull String, @NonNull java.util.List<android.media.browse.MediaBrowser.MediaItem>, @NonNull android.os.Bundle);
+    method public void onError(@NonNull String);
+    method public void onError(@NonNull String, @NonNull android.os.Bundle);
   }
 
 }
@@ -26897,9 +27123,9 @@
   public abstract class Effect {
     ctor public Effect();
     method public abstract void apply(int, int, int, int);
-    method public abstract java.lang.String getName();
+    method public abstract String getName();
     method public abstract void release();
-    method public abstract void setParameter(java.lang.String, java.lang.Object);
+    method public abstract void setParameter(String, Object);
     method public void setUpdateListener(android.media.effect.EffectUpdateListener);
   }
 
@@ -26910,39 +27136,39 @@
   }
 
   public class EffectFactory {
-    method public android.media.effect.Effect createEffect(java.lang.String);
-    method public static boolean isEffectSupported(java.lang.String);
-    field public static final java.lang.String EFFECT_AUTOFIX = "android.media.effect.effects.AutoFixEffect";
-    field public static final java.lang.String EFFECT_BACKDROPPER = "android.media.effect.effects.BackDropperEffect";
-    field public static final java.lang.String EFFECT_BITMAPOVERLAY = "android.media.effect.effects.BitmapOverlayEffect";
-    field public static final java.lang.String EFFECT_BLACKWHITE = "android.media.effect.effects.BlackWhiteEffect";
-    field public static final java.lang.String EFFECT_BRIGHTNESS = "android.media.effect.effects.BrightnessEffect";
-    field public static final java.lang.String EFFECT_CONTRAST = "android.media.effect.effects.ContrastEffect";
-    field public static final java.lang.String EFFECT_CROP = "android.media.effect.effects.CropEffect";
-    field public static final java.lang.String EFFECT_CROSSPROCESS = "android.media.effect.effects.CrossProcessEffect";
-    field public static final java.lang.String EFFECT_DOCUMENTARY = "android.media.effect.effects.DocumentaryEffect";
-    field public static final java.lang.String EFFECT_DUOTONE = "android.media.effect.effects.DuotoneEffect";
-    field public static final java.lang.String EFFECT_FILLLIGHT = "android.media.effect.effects.FillLightEffect";
-    field public static final java.lang.String EFFECT_FISHEYE = "android.media.effect.effects.FisheyeEffect";
-    field public static final java.lang.String EFFECT_FLIP = "android.media.effect.effects.FlipEffect";
-    field public static final java.lang.String EFFECT_GRAIN = "android.media.effect.effects.GrainEffect";
-    field public static final java.lang.String EFFECT_GRAYSCALE = "android.media.effect.effects.GrayscaleEffect";
-    field public static final java.lang.String EFFECT_LOMOISH = "android.media.effect.effects.LomoishEffect";
-    field public static final java.lang.String EFFECT_NEGATIVE = "android.media.effect.effects.NegativeEffect";
-    field public static final java.lang.String EFFECT_POSTERIZE = "android.media.effect.effects.PosterizeEffect";
-    field public static final java.lang.String EFFECT_REDEYE = "android.media.effect.effects.RedEyeEffect";
-    field public static final java.lang.String EFFECT_ROTATE = "android.media.effect.effects.RotateEffect";
-    field public static final java.lang.String EFFECT_SATURATE = "android.media.effect.effects.SaturateEffect";
-    field public static final java.lang.String EFFECT_SEPIA = "android.media.effect.effects.SepiaEffect";
-    field public static final java.lang.String EFFECT_SHARPEN = "android.media.effect.effects.SharpenEffect";
-    field public static final java.lang.String EFFECT_STRAIGHTEN = "android.media.effect.effects.StraightenEffect";
-    field public static final java.lang.String EFFECT_TEMPERATURE = "android.media.effect.effects.ColorTemperatureEffect";
-    field public static final java.lang.String EFFECT_TINT = "android.media.effect.effects.TintEffect";
-    field public static final java.lang.String EFFECT_VIGNETTE = "android.media.effect.effects.VignetteEffect";
+    method public android.media.effect.Effect createEffect(String);
+    method public static boolean isEffectSupported(String);
+    field public static final String EFFECT_AUTOFIX = "android.media.effect.effects.AutoFixEffect";
+    field public static final String EFFECT_BACKDROPPER = "android.media.effect.effects.BackDropperEffect";
+    field public static final String EFFECT_BITMAPOVERLAY = "android.media.effect.effects.BitmapOverlayEffect";
+    field public static final String EFFECT_BLACKWHITE = "android.media.effect.effects.BlackWhiteEffect";
+    field public static final String EFFECT_BRIGHTNESS = "android.media.effect.effects.BrightnessEffect";
+    field public static final String EFFECT_CONTRAST = "android.media.effect.effects.ContrastEffect";
+    field public static final String EFFECT_CROP = "android.media.effect.effects.CropEffect";
+    field public static final String EFFECT_CROSSPROCESS = "android.media.effect.effects.CrossProcessEffect";
+    field public static final String EFFECT_DOCUMENTARY = "android.media.effect.effects.DocumentaryEffect";
+    field public static final String EFFECT_DUOTONE = "android.media.effect.effects.DuotoneEffect";
+    field public static final String EFFECT_FILLLIGHT = "android.media.effect.effects.FillLightEffect";
+    field public static final String EFFECT_FISHEYE = "android.media.effect.effects.FisheyeEffect";
+    field public static final String EFFECT_FLIP = "android.media.effect.effects.FlipEffect";
+    field public static final String EFFECT_GRAIN = "android.media.effect.effects.GrainEffect";
+    field public static final String EFFECT_GRAYSCALE = "android.media.effect.effects.GrayscaleEffect";
+    field public static final String EFFECT_LOMOISH = "android.media.effect.effects.LomoishEffect";
+    field public static final String EFFECT_NEGATIVE = "android.media.effect.effects.NegativeEffect";
+    field public static final String EFFECT_POSTERIZE = "android.media.effect.effects.PosterizeEffect";
+    field public static final String EFFECT_REDEYE = "android.media.effect.effects.RedEyeEffect";
+    field public static final String EFFECT_ROTATE = "android.media.effect.effects.RotateEffect";
+    field public static final String EFFECT_SATURATE = "android.media.effect.effects.SaturateEffect";
+    field public static final String EFFECT_SEPIA = "android.media.effect.effects.SepiaEffect";
+    field public static final String EFFECT_SHARPEN = "android.media.effect.effects.SharpenEffect";
+    field public static final String EFFECT_STRAIGHTEN = "android.media.effect.effects.StraightenEffect";
+    field public static final String EFFECT_TEMPERATURE = "android.media.effect.effects.ColorTemperatureEffect";
+    field public static final String EFFECT_TINT = "android.media.effect.effects.TintEffect";
+    field public static final String EFFECT_VIGNETTE = "android.media.effect.effects.VignetteEffect";
   }
 
-  public abstract interface EffectUpdateListener {
-    method public abstract void onEffectUpdated(android.media.effect.Effect, java.lang.Object);
+  public interface EffectUpdateListener {
+    method public void onEffectUpdated(android.media.effect.Effect, Object);
   }
 
 }
@@ -26972,20 +27198,20 @@
     method public boolean isPrivate();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.media.midi.MidiDeviceInfo> CREATOR;
-    field public static final java.lang.String PROPERTY_BLUETOOTH_DEVICE = "bluetooth_device";
-    field public static final java.lang.String PROPERTY_MANUFACTURER = "manufacturer";
-    field public static final java.lang.String PROPERTY_NAME = "name";
-    field public static final java.lang.String PROPERTY_PRODUCT = "product";
-    field public static final java.lang.String PROPERTY_SERIAL_NUMBER = "serial_number";
-    field public static final java.lang.String PROPERTY_USB_DEVICE = "usb_device";
-    field public static final java.lang.String PROPERTY_VERSION = "version";
+    field public static final String PROPERTY_BLUETOOTH_DEVICE = "bluetooth_device";
+    field public static final String PROPERTY_MANUFACTURER = "manufacturer";
+    field public static final String PROPERTY_NAME = "name";
+    field public static final String PROPERTY_PRODUCT = "product";
+    field public static final String PROPERTY_SERIAL_NUMBER = "serial_number";
+    field public static final String PROPERTY_USB_DEVICE = "usb_device";
+    field public static final String PROPERTY_VERSION = "version";
     field public static final int TYPE_BLUETOOTH = 3; // 0x3
     field public static final int TYPE_USB = 1; // 0x1
     field public static final int TYPE_VIRTUAL = 2; // 0x2
   }
 
   public static final class MidiDeviceInfo.PortInfo {
-    method public java.lang.String getName();
+    method public String getName();
     method public int getPortNumber();
     method public int getType();
     field public static final int TYPE_INPUT = 1; // 0x1
@@ -27000,7 +27226,7 @@
     method public void onClose();
     method public void onDeviceStatusChanged(android.media.midi.MidiDeviceStatus);
     method public abstract android.media.midi.MidiReceiver[] onGetInputPortReceivers();
-    field public static final java.lang.String SERVICE_INTERFACE = "android.media.midi.MidiDeviceService";
+    field public static final String SERVICE_INTERFACE = "android.media.midi.MidiDeviceService";
   }
 
   public final class MidiDeviceStatus implements android.os.Parcelable {
@@ -27033,8 +27259,8 @@
     method public void onDeviceStatusChanged(android.media.midi.MidiDeviceStatus);
   }
 
-  public static abstract interface MidiManager.OnDeviceOpenedListener {
-    method public abstract void onDeviceOpened(android.media.midi.MidiDevice);
+  public static interface MidiManager.OnDeviceOpenedListener {
+    method public void onDeviceOpened(android.media.midi.MidiDevice);
   }
 
   public final class MidiOutputPort extends android.media.midi.MidiSender implements java.io.Closeable {
@@ -27068,20 +27294,20 @@
 package android.media.projection {
 
   public final class MediaProjection {
-    method public android.hardware.display.VirtualDisplay createVirtualDisplay(java.lang.String, int, int, int, int, android.view.Surface, android.hardware.display.VirtualDisplay.Callback, android.os.Handler);
+    method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, int, @Nullable android.view.Surface, @Nullable android.hardware.display.VirtualDisplay.Callback, @Nullable android.os.Handler);
     method public void registerCallback(android.media.projection.MediaProjection.Callback, android.os.Handler);
     method public void stop();
     method public void unregisterCallback(android.media.projection.MediaProjection.Callback);
   }
 
-  public static abstract class MediaProjection.Callback {
+  public abstract static class MediaProjection.Callback {
     ctor public MediaProjection.Callback();
     method public void onStop();
   }
 
   public final class MediaProjectionManager {
     method public android.content.Intent createScreenCaptureIntent();
-    method public android.media.projection.MediaProjection getMediaProjection(int, android.content.Intent);
+    method public android.media.projection.MediaProjection getMediaProjection(int, @NonNull android.content.Intent);
   }
 
 }
@@ -27089,46 +27315,49 @@
 package android.media.session {
 
   public final class MediaController {
-    ctor public MediaController(android.content.Context, android.media.session.MediaSession.Token);
+    ctor public MediaController(@NonNull android.content.Context, @NonNull android.media.session.MediaSession.Token);
     method public void adjustVolume(int, int);
-    method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
-    method public android.os.Bundle getExtras();
+    method public boolean dispatchMediaButtonEvent(@NonNull android.view.KeyEvent);
+    method @Nullable public android.os.Bundle getExtras();
     method public long getFlags();
-    method public android.media.MediaMetadata getMetadata();
-    method public java.lang.String getPackageName();
-    method public android.media.session.MediaController.PlaybackInfo getPlaybackInfo();
-    method public android.media.session.PlaybackState getPlaybackState();
-    method public java.util.List<android.media.session.MediaSession.QueueItem> getQueue();
-    method public java.lang.CharSequence getQueueTitle();
+    method @Nullable public android.media.MediaMetadata getMetadata();
+    method public String getPackageName();
+    method @Nullable public android.media.session.MediaController.PlaybackInfo getPlaybackInfo();
+    method @Nullable public android.media.session.PlaybackState getPlaybackState();
+    method @Nullable public java.util.List<android.media.session.MediaSession.QueueItem> getQueue();
+    method @Nullable public CharSequence getQueueTitle();
     method public int getRatingType();
-    method public android.app.PendingIntent getSessionActivity();
-    method public android.media.session.MediaSession.Token getSessionToken();
-    method public android.media.session.MediaController.TransportControls getTransportControls();
-    method public void registerCallback(android.media.session.MediaController.Callback);
-    method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler);
-    method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+    method @Nullable public android.app.PendingIntent getSessionActivity();
+    method @NonNull public android.media.session.MediaSession.Token getSessionToken();
+    method @NonNull public android.media.session.MediaController.TransportControls getTransportControls();
+    method public void registerCallback(@NonNull android.media.session.MediaController.Callback);
+    method public void registerCallback(@NonNull android.media.session.MediaController.Callback, @Nullable android.os.Handler);
+    method public void sendCommand(@NonNull String, @Nullable android.os.Bundle, @Nullable android.os.ResultReceiver);
     method public void setVolumeTo(int, int);
-    method public void unregisterCallback(android.media.session.MediaController.Callback);
+    method public void unregisterCallback(@NonNull android.media.session.MediaController.Callback);
   }
 
-  public static abstract class MediaController.Callback {
+  public abstract static class MediaController.Callback {
     ctor public MediaController.Callback();
     method public void onAudioInfoChanged(android.media.session.MediaController.PlaybackInfo);
-    method public void onExtrasChanged(android.os.Bundle);
-    method public void onMetadataChanged(android.media.MediaMetadata);
-    method public void onPlaybackStateChanged(android.media.session.PlaybackState);
-    method public void onQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>);
-    method public void onQueueTitleChanged(java.lang.CharSequence);
+    method public void onExtrasChanged(@Nullable android.os.Bundle);
+    method public void onMetadataChanged(@Nullable android.media.MediaMetadata);
+    method public void onPlaybackStateChanged(@Nullable android.media.session.PlaybackState);
+    method public void onQueueChanged(@Nullable java.util.List<android.media.session.MediaSession.QueueItem>);
+    method public void onQueueTitleChanged(@Nullable CharSequence);
     method public void onSessionDestroyed();
-    method public void onSessionEvent(java.lang.String, android.os.Bundle);
+    method public void onSessionEvent(@NonNull String, @Nullable android.os.Bundle);
   }
 
-  public static final class MediaController.PlaybackInfo {
+  public static final class MediaController.PlaybackInfo implements android.os.Parcelable {
+    method public int describeContents();
     method public android.media.AudioAttributes getAudioAttributes();
     method public int getCurrentVolume();
     method public int getMaxVolume();
     method public int getPlaybackType();
     method public int getVolumeControl();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.session.MediaController.PlaybackInfo> CREATOR;
     field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
     field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
   }
@@ -27137,17 +27366,17 @@
     method public void fastForward();
     method public void pause();
     method public void play();
-    method public void playFromMediaId(java.lang.String, android.os.Bundle);
-    method public void playFromSearch(java.lang.String, android.os.Bundle);
+    method public void playFromMediaId(String, android.os.Bundle);
+    method public void playFromSearch(String, android.os.Bundle);
     method public void playFromUri(android.net.Uri, android.os.Bundle);
     method public void prepare();
-    method public void prepareFromMediaId(java.lang.String, android.os.Bundle);
-    method public void prepareFromSearch(java.lang.String, android.os.Bundle);
+    method public void prepareFromMediaId(String, android.os.Bundle);
+    method public void prepareFromSearch(String, android.os.Bundle);
     method public void prepareFromUri(android.net.Uri, android.os.Bundle);
     method public void rewind();
     method public void seekTo(long);
-    method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
-    method public void sendCustomAction(java.lang.String, android.os.Bundle);
+    method public void sendCustomAction(@NonNull android.media.session.PlaybackState.CustomAction, @Nullable android.os.Bundle);
+    method public void sendCustomAction(@NonNull String, @Nullable android.os.Bundle);
     method public void setRating(android.media.Rating);
     method public void skipToNext();
     method public void skipToPrevious();
@@ -27156,49 +27385,49 @@
   }
 
   public final class MediaSession {
-    ctor public MediaSession(android.content.Context, java.lang.String);
-    method public android.media.session.MediaController getController();
-    method public android.media.session.MediaSessionManager.RemoteUserInfo getCurrentControllerInfo();
-    method public android.media.session.MediaSession.Token getSessionToken();
+    ctor public MediaSession(@NonNull android.content.Context, @NonNull String);
+    method @NonNull public android.media.session.MediaController getController();
+    method @NonNull public android.media.session.MediaSessionManager.RemoteUserInfo getCurrentControllerInfo();
+    method @NonNull public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isActive();
     method public void release();
-    method public void sendSessionEvent(java.lang.String, android.os.Bundle);
+    method public void sendSessionEvent(@NonNull String, @Nullable android.os.Bundle);
     method public void setActive(boolean);
-    method public void setCallback(android.media.session.MediaSession.Callback);
-    method public void setCallback(android.media.session.MediaSession.Callback, android.os.Handler);
-    method public void setExtras(android.os.Bundle);
+    method public void setCallback(@Nullable android.media.session.MediaSession.Callback);
+    method public void setCallback(@Nullable android.media.session.MediaSession.Callback, @Nullable android.os.Handler);
+    method public void setExtras(@Nullable android.os.Bundle);
     method public void setFlags(int);
-    method public void setMediaButtonReceiver(android.app.PendingIntent);
-    method public void setMetadata(android.media.MediaMetadata);
-    method public void setPlaybackState(android.media.session.PlaybackState);
+    method public void setMediaButtonReceiver(@Nullable android.app.PendingIntent);
+    method public void setMetadata(@Nullable android.media.MediaMetadata);
+    method public void setPlaybackState(@Nullable android.media.session.PlaybackState);
     method public void setPlaybackToLocal(android.media.AudioAttributes);
-    method public void setPlaybackToRemote(android.media.VolumeProvider);
-    method public void setQueue(java.util.List<android.media.session.MediaSession.QueueItem>);
-    method public void setQueueTitle(java.lang.CharSequence);
+    method public void setPlaybackToRemote(@NonNull android.media.VolumeProvider);
+    method public void setQueue(@Nullable java.util.List<android.media.session.MediaSession.QueueItem>);
+    method public void setQueueTitle(@Nullable CharSequence);
     method public void setRatingType(int);
-    method public void setSessionActivity(android.app.PendingIntent);
-    field public static final deprecated int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
-    field public static final deprecated int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
+    method public void setSessionActivity(@Nullable android.app.PendingIntent);
+    field @Deprecated public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field @Deprecated public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
 
-  public static abstract class MediaSession.Callback {
+  public abstract static class MediaSession.Callback {
     ctor public MediaSession.Callback();
-    method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
-    method public void onCustomAction(java.lang.String, android.os.Bundle);
+    method public void onCommand(@NonNull String, @Nullable android.os.Bundle, @Nullable android.os.ResultReceiver);
+    method public void onCustomAction(@NonNull String, @Nullable android.os.Bundle);
     method public void onFastForward();
-    method public boolean onMediaButtonEvent(android.content.Intent);
+    method public boolean onMediaButtonEvent(@NonNull android.content.Intent);
     method public void onPause();
     method public void onPlay();
-    method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
-    method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
+    method public void onPlayFromMediaId(String, android.os.Bundle);
+    method public void onPlayFromSearch(String, android.os.Bundle);
     method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
     method public void onPrepare();
-    method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
-    method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
+    method public void onPrepareFromMediaId(String, android.os.Bundle);
+    method public void onPrepareFromSearch(String, android.os.Bundle);
     method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
     method public void onRewind();
     method public void onSeekTo(long);
-    method public void onSetRating(android.media.Rating);
+    method public void onSetRating(@NonNull android.media.Rating);
     method public void onSkipToNext();
     method public void onSkipToPrevious();
     method public void onSkipToQueueItem(long);
@@ -27222,21 +27451,29 @@
   }
 
   public final class MediaSessionManager {
-    method public void addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName);
-    method public void addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName, android.os.Handler);
-    method public java.util.List<android.media.session.MediaController> getActiveSessions(android.content.ComponentName);
-    method public boolean isTrustedForMediaControl(android.media.session.MediaSessionManager.RemoteUserInfo);
-    method public void removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
+    method public void addOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, @Nullable android.content.ComponentName);
+    method public void addOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, @Nullable android.content.ComponentName, @Nullable android.os.Handler);
+    method public void addOnSession2TokensChangedListener(@NonNull android.media.session.MediaSessionManager.OnSession2TokensChangedListener);
+    method public void addOnSession2TokensChangedListener(@NonNull android.media.session.MediaSessionManager.OnSession2TokensChangedListener, @NonNull android.os.Handler);
+    method @NonNull public java.util.List<android.media.session.MediaController> getActiveSessions(@Nullable android.content.ComponentName);
+    method @NonNull public java.util.List<android.media.Session2Token> getSession2Tokens();
+    method public boolean isTrustedForMediaControl(@NonNull android.media.session.MediaSessionManager.RemoteUserInfo);
+    method public void notifySession2Created(@NonNull android.media.Session2Token);
+    method public void removeOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
+    method public void removeOnSession2TokensChangedListener(@NonNull android.media.session.MediaSessionManager.OnSession2TokensChangedListener);
   }
 
-  public static abstract interface MediaSessionManager.OnActiveSessionsChangedListener {
-    method public abstract void onActiveSessionsChanged(java.util.List<android.media.session.MediaController>);
+  public static interface MediaSessionManager.OnActiveSessionsChangedListener {
+    method public void onActiveSessionsChanged(@Nullable java.util.List<android.media.session.MediaController>);
+  }
+
+  public static interface MediaSessionManager.OnSession2TokensChangedListener {
+    method public void onSession2TokensChanged(@NonNull java.util.List<android.media.Session2Token>);
   }
 
   public static final class MediaSessionManager.RemoteUserInfo {
-    ctor public MediaSessionManager.RemoteUserInfo(java.lang.String, int, int);
-    ctor public MediaSessionManager.RemoteUserInfo(java.lang.String, int, int, android.os.IBinder);
-    method public java.lang.String getPackageName();
+    ctor public MediaSessionManager.RemoteUserInfo(@NonNull String, int, int);
+    method public String getPackageName();
     method public int getPid();
     method public int getUid();
   }
@@ -27247,8 +27484,8 @@
     method public long getActiveQueueItemId();
     method public long getBufferedPosition();
     method public java.util.List<android.media.session.PlaybackState.CustomAction> getCustomActions();
-    method public java.lang.CharSequence getErrorMessage();
-    method public android.os.Bundle getExtras();
+    method public CharSequence getErrorMessage();
+    method @Nullable public android.os.Bundle getExtras();
     method public long getLastPositionUpdateTime();
     method public float getPlaybackSpeed();
     method public long getPosition();
@@ -27291,13 +27528,13 @@
   public static final class PlaybackState.Builder {
     ctor public PlaybackState.Builder();
     ctor public PlaybackState.Builder(android.media.session.PlaybackState);
-    method public android.media.session.PlaybackState.Builder addCustomAction(java.lang.String, java.lang.String, int);
+    method public android.media.session.PlaybackState.Builder addCustomAction(String, String, int);
     method public android.media.session.PlaybackState.Builder addCustomAction(android.media.session.PlaybackState.CustomAction);
     method public android.media.session.PlaybackState build();
     method public android.media.session.PlaybackState.Builder setActions(long);
     method public android.media.session.PlaybackState.Builder setActiveQueueItemId(long);
     method public android.media.session.PlaybackState.Builder setBufferedPosition(long);
-    method public android.media.session.PlaybackState.Builder setErrorMessage(java.lang.CharSequence);
+    method public android.media.session.PlaybackState.Builder setErrorMessage(CharSequence);
     method public android.media.session.PlaybackState.Builder setExtras(android.os.Bundle);
     method public android.media.session.PlaybackState.Builder setState(int, long, float, long);
     method public android.media.session.PlaybackState.Builder setState(int, long, float);
@@ -27305,16 +27542,16 @@
 
   public static final class PlaybackState.CustomAction implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getAction();
+    method public String getAction();
     method public android.os.Bundle getExtras();
     method public int getIcon();
-    method public java.lang.CharSequence getName();
+    method public CharSequence getName();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState.CustomAction> CREATOR;
   }
 
   public static final class PlaybackState.CustomAction.Builder {
-    ctor public PlaybackState.CustomAction.Builder(java.lang.String, java.lang.CharSequence, int);
+    ctor public PlaybackState.CustomAction.Builder(String, CharSequence, @DrawableRes int);
     method public android.media.session.PlaybackState.CustomAction build();
     method public android.media.session.PlaybackState.CustomAction.Builder setExtras(android.os.Bundle);
   }
@@ -27324,14 +27561,14 @@
 package android.media.tv {
 
   public final class TvContentRating {
-    method public boolean contains(android.media.tv.TvContentRating);
-    method public static android.media.tv.TvContentRating createRating(java.lang.String, java.lang.String, java.lang.String, java.lang.String...);
-    method public java.lang.String flattenToString();
-    method public java.lang.String getDomain();
-    method public java.lang.String getMainRating();
-    method public java.lang.String getRatingSystem();
+    method public boolean contains(@NonNull android.media.tv.TvContentRating);
+    method public static android.media.tv.TvContentRating createRating(String, String, String, java.lang.String...);
+    method public String flattenToString();
+    method public String getDomain();
+    method public String getMainRating();
+    method public String getRatingSystem();
     method public java.util.List<java.lang.String> getSubRatings();
-    method public static android.media.tv.TvContentRating unflattenFromString(java.lang.String);
+    method public static android.media.tv.TvContentRating unflattenFromString(String);
     field public static final android.media.tv.TvContentRating UNRATED;
   }
 
@@ -27339,9 +27576,9 @@
     method public static android.net.Uri buildChannelLogoUri(long);
     method public static android.net.Uri buildChannelLogoUri(android.net.Uri);
     method public static android.net.Uri buildChannelUri(long);
-    method public static android.net.Uri buildChannelUriForPassthroughInput(java.lang.String);
-    method public static android.net.Uri buildChannelsUriForInput(java.lang.String);
-    method public static java.lang.String buildInputId(android.content.ComponentName);
+    method public static android.net.Uri buildChannelUriForPassthroughInput(String);
+    method public static android.net.Uri buildChannelsUriForInput(@Nullable String);
+    method public static String buildInputId(android.content.ComponentName);
     method public static android.net.Uri buildPreviewProgramUri(long);
     method public static android.net.Uri buildPreviewProgramsUriForChannel(long);
     method public static android.net.Uri buildPreviewProgramsUriForChannel(android.net.Uri);
@@ -27352,107 +27589,107 @@
     method public static android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
     method public static android.net.Uri buildRecordedProgramUri(long);
     method public static android.net.Uri buildWatchNextProgramUri(long);
-    method public static boolean isChannelUri(android.net.Uri);
-    method public static boolean isChannelUriForPassthroughInput(android.net.Uri);
-    method public static boolean isChannelUriForTunerInput(android.net.Uri);
-    method public static boolean isProgramUri(android.net.Uri);
-    method public static boolean isRecordedProgramUri(android.net.Uri);
+    method public static boolean isChannelUri(@NonNull android.net.Uri);
+    method public static boolean isChannelUriForPassthroughInput(@NonNull android.net.Uri);
+    method public static boolean isChannelUriForTunerInput(@NonNull android.net.Uri);
+    method public static boolean isProgramUri(@NonNull android.net.Uri);
+    method public static boolean isRecordedProgramUri(@NonNull android.net.Uri);
     method public static void requestChannelBrowsable(android.content.Context, long);
-    field public static final java.lang.String ACTION_INITIALIZE_PROGRAMS = "android.media.tv.action.INITIALIZE_PROGRAMS";
-    field public static final java.lang.String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
-    field public static final java.lang.String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
-    field public static final java.lang.String ACTION_REQUEST_CHANNEL_BROWSABLE = "android.media.tv.action.REQUEST_CHANNEL_BROWSABLE";
-    field public static final java.lang.String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
-    field public static final java.lang.String AUTHORITY = "android.media.tv";
-    field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
-    field public static final java.lang.String EXTRA_PREVIEW_PROGRAM_ID = "android.media.tv.extra.PREVIEW_PROGRAM_ID";
-    field public static final java.lang.String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
+    field public static final String ACTION_INITIALIZE_PROGRAMS = "android.media.tv.action.INITIALIZE_PROGRAMS";
+    field public static final String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
+    field public static final String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
+    field public static final String ACTION_REQUEST_CHANNEL_BROWSABLE = "android.media.tv.action.REQUEST_CHANNEL_BROWSABLE";
+    field public static final String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
+    field public static final String AUTHORITY = "android.media.tv";
+    field public static final String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+    field public static final String EXTRA_PREVIEW_PROGRAM_ID = "android.media.tv.extra.PREVIEW_PROGRAM_ID";
+    field public static final String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
   }
 
-  public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
-    field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
+  public static interface TvContract.BaseTvColumns extends android.provider.BaseColumns {
+    field public static final String COLUMN_PACKAGE_NAME = "package_name";
   }
 
   public static final class TvContract.Channels implements android.media.tv.TvContract.BaseTvColumns {
-    method public static java.lang.String getVideoResolution(java.lang.String);
-    field public static final java.lang.String COLUMN_APP_LINK_COLOR = "app_link_color";
-    field public static final java.lang.String COLUMN_APP_LINK_ICON_URI = "app_link_icon_uri";
-    field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
-    field public static final java.lang.String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri";
-    field public static final java.lang.String COLUMN_APP_LINK_TEXT = "app_link_text";
-    field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
-    field public static final java.lang.String COLUMN_DESCRIPTION = "description";
-    field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name";
-    field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number";
-    field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
-    field public static final java.lang.String COLUMN_LOCKED = "locked";
-    field public static final java.lang.String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
-    field public static final java.lang.String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SERVICE_ID = "service_id";
-    field public static final java.lang.String COLUMN_SERVICE_TYPE = "service_type";
-    field public static final java.lang.String COLUMN_TRANSIENT = "transient";
-    field public static final java.lang.String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
-    field public static final java.lang.String COLUMN_TYPE = "type";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_FORMAT = "video_format";
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/channel";
+    method @Nullable public static String getVideoResolution(String);
+    field public static final String COLUMN_APP_LINK_COLOR = "app_link_color";
+    field public static final String COLUMN_APP_LINK_ICON_URI = "app_link_icon_uri";
+    field public static final String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+    field public static final String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri";
+    field public static final String COLUMN_APP_LINK_TEXT = "app_link_text";
+    field public static final String COLUMN_BROWSABLE = "browsable";
+    field public static final String COLUMN_DESCRIPTION = "description";
+    field public static final String COLUMN_DISPLAY_NAME = "display_name";
+    field public static final String COLUMN_DISPLAY_NUMBER = "display_number";
+    field public static final String COLUMN_INPUT_ID = "input_id";
+    field public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final String COLUMN_LOCKED = "locked";
+    field public static final String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
+    field public static final String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
+    field public static final String COLUMN_SEARCHABLE = "searchable";
+    field public static final String COLUMN_SERVICE_ID = "service_id";
+    field public static final String COLUMN_SERVICE_TYPE = "service_type";
+    field public static final String COLUMN_TRANSIENT = "transient";
+    field public static final String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
+    field public static final String COLUMN_TYPE = "type";
+    field public static final String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final String COLUMN_VIDEO_FORMAT = "video_format";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/channel";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String SERVICE_TYPE_AUDIO = "SERVICE_TYPE_AUDIO";
-    field public static final java.lang.String SERVICE_TYPE_AUDIO_VIDEO = "SERVICE_TYPE_AUDIO_VIDEO";
-    field public static final java.lang.String SERVICE_TYPE_OTHER = "SERVICE_TYPE_OTHER";
-    field public static final java.lang.String TYPE_1SEG = "TYPE_1SEG";
-    field public static final java.lang.String TYPE_ATSC_C = "TYPE_ATSC_C";
-    field public static final java.lang.String TYPE_ATSC_M_H = "TYPE_ATSC_M_H";
-    field public static final java.lang.String TYPE_ATSC_T = "TYPE_ATSC_T";
-    field public static final java.lang.String TYPE_CMMB = "TYPE_CMMB";
-    field public static final java.lang.String TYPE_DTMB = "TYPE_DTMB";
-    field public static final java.lang.String TYPE_DVB_C = "TYPE_DVB_C";
-    field public static final java.lang.String TYPE_DVB_C2 = "TYPE_DVB_C2";
-    field public static final java.lang.String TYPE_DVB_H = "TYPE_DVB_H";
-    field public static final java.lang.String TYPE_DVB_S = "TYPE_DVB_S";
-    field public static final java.lang.String TYPE_DVB_S2 = "TYPE_DVB_S2";
-    field public static final java.lang.String TYPE_DVB_SH = "TYPE_DVB_SH";
-    field public static final java.lang.String TYPE_DVB_T = "TYPE_DVB_T";
-    field public static final java.lang.String TYPE_DVB_T2 = "TYPE_DVB_T2";
-    field public static final java.lang.String TYPE_ISDB_C = "TYPE_ISDB_C";
-    field public static final java.lang.String TYPE_ISDB_S = "TYPE_ISDB_S";
-    field public static final java.lang.String TYPE_ISDB_T = "TYPE_ISDB_T";
-    field public static final java.lang.String TYPE_ISDB_TB = "TYPE_ISDB_TB";
-    field public static final java.lang.String TYPE_NTSC = "TYPE_NTSC";
-    field public static final java.lang.String TYPE_OTHER = "TYPE_OTHER";
-    field public static final java.lang.String TYPE_PAL = "TYPE_PAL";
-    field public static final java.lang.String TYPE_PREVIEW = "TYPE_PREVIEW";
-    field public static final java.lang.String TYPE_SECAM = "TYPE_SECAM";
-    field public static final java.lang.String TYPE_S_DMB = "TYPE_S_DMB";
-    field public static final java.lang.String TYPE_T_DMB = "TYPE_T_DMB";
-    field public static final java.lang.String VIDEO_FORMAT_1080I = "VIDEO_FORMAT_1080I";
-    field public static final java.lang.String VIDEO_FORMAT_1080P = "VIDEO_FORMAT_1080P";
-    field public static final java.lang.String VIDEO_FORMAT_2160P = "VIDEO_FORMAT_2160P";
-    field public static final java.lang.String VIDEO_FORMAT_240P = "VIDEO_FORMAT_240P";
-    field public static final java.lang.String VIDEO_FORMAT_360P = "VIDEO_FORMAT_360P";
-    field public static final java.lang.String VIDEO_FORMAT_4320P = "VIDEO_FORMAT_4320P";
-    field public static final java.lang.String VIDEO_FORMAT_480I = "VIDEO_FORMAT_480I";
-    field public static final java.lang.String VIDEO_FORMAT_480P = "VIDEO_FORMAT_480P";
-    field public static final java.lang.String VIDEO_FORMAT_576I = "VIDEO_FORMAT_576I";
-    field public static final java.lang.String VIDEO_FORMAT_576P = "VIDEO_FORMAT_576P";
-    field public static final java.lang.String VIDEO_FORMAT_720P = "VIDEO_FORMAT_720P";
-    field public static final java.lang.String VIDEO_RESOLUTION_ED = "VIDEO_RESOLUTION_ED";
-    field public static final java.lang.String VIDEO_RESOLUTION_FHD = "VIDEO_RESOLUTION_FHD";
-    field public static final java.lang.String VIDEO_RESOLUTION_HD = "VIDEO_RESOLUTION_HD";
-    field public static final java.lang.String VIDEO_RESOLUTION_SD = "VIDEO_RESOLUTION_SD";
-    field public static final java.lang.String VIDEO_RESOLUTION_UHD = "VIDEO_RESOLUTION_UHD";
+    field public static final String SERVICE_TYPE_AUDIO = "SERVICE_TYPE_AUDIO";
+    field public static final String SERVICE_TYPE_AUDIO_VIDEO = "SERVICE_TYPE_AUDIO_VIDEO";
+    field public static final String SERVICE_TYPE_OTHER = "SERVICE_TYPE_OTHER";
+    field public static final String TYPE_1SEG = "TYPE_1SEG";
+    field public static final String TYPE_ATSC_C = "TYPE_ATSC_C";
+    field public static final String TYPE_ATSC_M_H = "TYPE_ATSC_M_H";
+    field public static final String TYPE_ATSC_T = "TYPE_ATSC_T";
+    field public static final String TYPE_CMMB = "TYPE_CMMB";
+    field public static final String TYPE_DTMB = "TYPE_DTMB";
+    field public static final String TYPE_DVB_C = "TYPE_DVB_C";
+    field public static final String TYPE_DVB_C2 = "TYPE_DVB_C2";
+    field public static final String TYPE_DVB_H = "TYPE_DVB_H";
+    field public static final String TYPE_DVB_S = "TYPE_DVB_S";
+    field public static final String TYPE_DVB_S2 = "TYPE_DVB_S2";
+    field public static final String TYPE_DVB_SH = "TYPE_DVB_SH";
+    field public static final String TYPE_DVB_T = "TYPE_DVB_T";
+    field public static final String TYPE_DVB_T2 = "TYPE_DVB_T2";
+    field public static final String TYPE_ISDB_C = "TYPE_ISDB_C";
+    field public static final String TYPE_ISDB_S = "TYPE_ISDB_S";
+    field public static final String TYPE_ISDB_T = "TYPE_ISDB_T";
+    field public static final String TYPE_ISDB_TB = "TYPE_ISDB_TB";
+    field public static final String TYPE_NTSC = "TYPE_NTSC";
+    field public static final String TYPE_OTHER = "TYPE_OTHER";
+    field public static final String TYPE_PAL = "TYPE_PAL";
+    field public static final String TYPE_PREVIEW = "TYPE_PREVIEW";
+    field public static final String TYPE_SECAM = "TYPE_SECAM";
+    field public static final String TYPE_S_DMB = "TYPE_S_DMB";
+    field public static final String TYPE_T_DMB = "TYPE_T_DMB";
+    field public static final String VIDEO_FORMAT_1080I = "VIDEO_FORMAT_1080I";
+    field public static final String VIDEO_FORMAT_1080P = "VIDEO_FORMAT_1080P";
+    field public static final String VIDEO_FORMAT_2160P = "VIDEO_FORMAT_2160P";
+    field public static final String VIDEO_FORMAT_240P = "VIDEO_FORMAT_240P";
+    field public static final String VIDEO_FORMAT_360P = "VIDEO_FORMAT_360P";
+    field public static final String VIDEO_FORMAT_4320P = "VIDEO_FORMAT_4320P";
+    field public static final String VIDEO_FORMAT_480I = "VIDEO_FORMAT_480I";
+    field public static final String VIDEO_FORMAT_480P = "VIDEO_FORMAT_480P";
+    field public static final String VIDEO_FORMAT_576I = "VIDEO_FORMAT_576I";
+    field public static final String VIDEO_FORMAT_576P = "VIDEO_FORMAT_576P";
+    field public static final String VIDEO_FORMAT_720P = "VIDEO_FORMAT_720P";
+    field public static final String VIDEO_RESOLUTION_ED = "VIDEO_RESOLUTION_ED";
+    field public static final String VIDEO_RESOLUTION_FHD = "VIDEO_RESOLUTION_FHD";
+    field public static final String VIDEO_RESOLUTION_HD = "VIDEO_RESOLUTION_HD";
+    field public static final String VIDEO_RESOLUTION_SD = "VIDEO_RESOLUTION_SD";
+    field public static final String VIDEO_RESOLUTION_UHD = "VIDEO_RESOLUTION_UHD";
   }
 
   public static final class TvContract.Channels.Logo {
-    field public static final java.lang.String CONTENT_DIRECTORY = "logo";
+    field public static final String CONTENT_DIRECTORY = "logo";
   }
 
   public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BaseTvColumns {
@@ -27464,55 +27701,55 @@
     field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
     field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
     field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
-    field public static final java.lang.String COLUMN_AUTHOR = "author";
-    field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
-    field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
-    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
-    field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
-    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
-    field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
-    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
-    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
-    field public static final java.lang.String COLUMN_INTENT_URI = "intent_uri";
-    field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
-    field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
-    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
-    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
-    field public static final java.lang.String COLUMN_LIVE = "live";
-    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
-    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
-    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
-    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
-    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
-    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
-    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
-    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
-    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
-    field public static final java.lang.String COLUMN_SERIES_ID = "series_id";
-    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
-    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
-    field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
-    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_TRANSIENT = "transient";
-    field public static final java.lang.String COLUMN_TYPE = "type";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
-    field public static final java.lang.String COLUMN_WEIGHT = "weight";
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
+    field public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final String COLUMN_AUTHOR = "author";
+    field public static final String COLUMN_AVAILABILITY = "availability";
+    field public static final String COLUMN_BROWSABLE = "browsable";
+    field public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final String COLUMN_CONTENT_ID = "content_id";
+    field public static final String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final String COLUMN_INTENT_URI = "intent_uri";
+    field public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
+    field public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
+    field public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final String COLUMN_ITEM_COUNT = "item_count";
+    field public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+    field public static final String COLUMN_LIVE = "live";
+    field public static final String COLUMN_LOGO_URI = "logo_uri";
+    field public static final String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final String COLUMN_OFFER_PRICE = "offer_price";
+    field public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+    field public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+    field public static final String COLUMN_RELEASE_DATE = "release_date";
+    field public static final String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final String COLUMN_SEARCHABLE = "searchable";
+    field public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final String COLUMN_SEASON_TITLE = "season_title";
+    field public static final String COLUMN_SERIES_ID = "series_id";
+    field public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final String COLUMN_STARTING_PRICE = "starting_price";
+    field public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+    field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final String COLUMN_TITLE = "title";
+    field public static final String COLUMN_TRANSIENT = "transient";
+    field public static final String COLUMN_TYPE = "type";
+    field public static final String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final String COLUMN_WEIGHT = "weight";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
     field public static final android.net.Uri CONTENT_URI;
     field public static final int INTERACTION_TYPE_FANS = 3; // 0x3
     field public static final int INTERACTION_TYPE_FOLLOWERS = 2; // 0x2
@@ -27539,39 +27776,39 @@
   }
 
   public static final class TvContract.Programs implements android.media.tv.TvContract.BaseTvColumns {
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
-    field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
-    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
-    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
-    field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
-    field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
-    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
-    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
-    field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
-    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
-    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
-    field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
-    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
-    field public static final java.lang.String COLUMN_SERIES_ID = "series_id";
-    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
-    field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
-    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/program";
+    field public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field @Deprecated public static final String COLUMN_EPISODE_NUMBER = "episode_number";
+    field public static final String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
+    field public static final String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final String COLUMN_SEARCHABLE = "searchable";
+    field public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field @Deprecated public static final String COLUMN_SEASON_NUMBER = "season_number";
+    field public static final String COLUMN_SEASON_TITLE = "season_title";
+    field public static final String COLUMN_SERIES_ID = "series_id";
+    field public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final String COLUMN_TITLE = "title";
+    field public static final String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/program";
     field public static final android.net.Uri CONTENT_URI;
     field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2
     field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0
@@ -27579,64 +27816,64 @@
   }
 
   public static final class TvContract.Programs.Genres {
-    method public static java.lang.String[] decode(java.lang.String);
-    method public static java.lang.String encode(java.lang.String...);
-    method public static boolean isCanonical(java.lang.String);
-    field public static final java.lang.String ANIMAL_WILDLIFE = "ANIMAL_WILDLIFE";
-    field public static final java.lang.String ARTS = "ARTS";
-    field public static final java.lang.String COMEDY = "COMEDY";
-    field public static final java.lang.String DRAMA = "DRAMA";
-    field public static final java.lang.String EDUCATION = "EDUCATION";
-    field public static final java.lang.String ENTERTAINMENT = "ENTERTAINMENT";
-    field public static final java.lang.String FAMILY_KIDS = "FAMILY_KIDS";
-    field public static final java.lang.String GAMING = "GAMING";
-    field public static final java.lang.String LIFE_STYLE = "LIFE_STYLE";
-    field public static final java.lang.String MOVIES = "MOVIES";
-    field public static final java.lang.String MUSIC = "MUSIC";
-    field public static final java.lang.String NEWS = "NEWS";
-    field public static final java.lang.String PREMIER = "PREMIER";
-    field public static final java.lang.String SHOPPING = "SHOPPING";
-    field public static final java.lang.String SPORTS = "SPORTS";
-    field public static final java.lang.String TECH_SCIENCE = "TECH_SCIENCE";
-    field public static final java.lang.String TRAVEL = "TRAVEL";
+    method public static String[] decode(@NonNull String);
+    method public static String encode(@NonNull java.lang.String...);
+    method public static boolean isCanonical(String);
+    field public static final String ANIMAL_WILDLIFE = "ANIMAL_WILDLIFE";
+    field public static final String ARTS = "ARTS";
+    field public static final String COMEDY = "COMEDY";
+    field public static final String DRAMA = "DRAMA";
+    field public static final String EDUCATION = "EDUCATION";
+    field public static final String ENTERTAINMENT = "ENTERTAINMENT";
+    field public static final String FAMILY_KIDS = "FAMILY_KIDS";
+    field public static final String GAMING = "GAMING";
+    field public static final String LIFE_STYLE = "LIFE_STYLE";
+    field public static final String MOVIES = "MOVIES";
+    field public static final String MUSIC = "MUSIC";
+    field public static final String NEWS = "NEWS";
+    field public static final String PREMIER = "PREMIER";
+    field public static final String SHOPPING = "SHOPPING";
+    field public static final String SPORTS = "SPORTS";
+    field public static final String TECH_SCIENCE = "TECH_SCIENCE";
+    field public static final String TRAVEL = "TRAVEL";
   }
 
   public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseTvColumns {
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
-    field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
-    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
-    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
-    field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
-    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
-    field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
-    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
-    field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
-    field public static final java.lang.String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
-    field public static final java.lang.String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
-    field public static final java.lang.String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
-    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
-    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
-    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
-    field public static final java.lang.String COLUMN_SERIES_ID = "series_id";
-    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
-    field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
-    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
+    field public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+    field public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final String COLUMN_INPUT_ID = "input_id";
+    field public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
+    field public static final String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
+    field public static final String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
+    field public static final String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis";
+    field public static final String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final String COLUMN_SEARCHABLE = "searchable";
+    field public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final String COLUMN_SEASON_TITLE = "season_title";
+    field public static final String COLUMN_SERIES_ID = "series_id";
+    field public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final String COLUMN_TITLE = "title";
+    field public static final String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
     field public static final android.net.Uri CONTENT_URI;
     field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2
     field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0
@@ -27652,55 +27889,55 @@
     field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
     field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
     field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
-    field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
-    field public static final java.lang.String COLUMN_AUTHOR = "author";
-    field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
-    field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
-    field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
-    field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
-    field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
-    field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
-    field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
-    field public static final java.lang.String COLUMN_INTENT_URI = "intent_uri";
-    field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
-    field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
-    field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
-    field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
-    field public static final java.lang.String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
-    field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
-    field public static final java.lang.String COLUMN_LIVE = "live";
-    field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
-    field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
-    field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
-    field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
-    field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
-    field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
-    field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
-    field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
-    field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-    field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
-    field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
-    field public static final java.lang.String COLUMN_SEASON_TITLE = "season_title";
-    field public static final java.lang.String COLUMN_SERIES_ID = "series_id";
-    field public static final java.lang.String COLUMN_SHORT_DESCRIPTION = "short_description";
-    field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
-    field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
-    field public static final java.lang.String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_TRANSIENT = "transient";
-    field public static final java.lang.String COLUMN_TYPE = "type";
-    field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final java.lang.String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final java.lang.String COLUMN_VIDEO_WIDTH = "video_width";
-    field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
+    field public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final String COLUMN_AUTHOR = "author";
+    field public static final String COLUMN_AVAILABILITY = "availability";
+    field public static final String COLUMN_BROWSABLE = "browsable";
+    field public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final String COLUMN_CONTENT_ID = "content_id";
+    field public static final String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final String COLUMN_DURATION_MILLIS = "duration_millis";
+    field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final String COLUMN_INTENT_URI = "intent_uri";
+    field public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
+    field public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
+    field public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+    field public static final String COLUMN_ITEM_COUNT = "item_count";
+    field public static final String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
+    field public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+    field public static final String COLUMN_LIVE = "live";
+    field public static final String COLUMN_LOGO_URI = "logo_uri";
+    field public static final String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final String COLUMN_OFFER_PRICE = "offer_price";
+    field public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+    field public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+    field public static final String COLUMN_RELEASE_DATE = "release_date";
+    field public static final String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final String COLUMN_SEARCHABLE = "searchable";
+    field public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final String COLUMN_SEASON_TITLE = "season_title";
+    field public static final String COLUMN_SERIES_ID = "series_id";
+    field public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final String COLUMN_STARTING_PRICE = "starting_price";
+    field public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+    field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final String COLUMN_TITLE = "title";
+    field public static final String COLUMN_TRANSIENT = "transient";
+    field public static final String COLUMN_TYPE = "type";
+    field public static final String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
     field public static final android.net.Uri CONTENT_URI;
     field public static final int INTERACTION_TYPE_FANS = 3; // 0x3
     field public static final int INTERACTION_TYPE_FOLLOWERS = 2; // 0x2
@@ -27732,23 +27969,23 @@
 
   public final class TvInputInfo implements android.os.Parcelable {
     method public boolean canRecord();
-    method public deprecated android.content.Intent createSettingsIntent();
+    method @Deprecated public android.content.Intent createSettingsIntent();
     method public android.content.Intent createSetupIntent();
     method public int describeContents();
     method public android.os.Bundle getExtras();
-    method public java.lang.String getId();
-    method public java.lang.String getParentId();
+    method public String getId();
+    method public String getParentId();
     method public android.content.pm.ServiceInfo getServiceInfo();
     method public int getTunerCount();
     method public int getType();
     method public boolean isHidden(android.content.Context);
     method public boolean isPassthroughInput();
-    method public java.lang.CharSequence loadCustomLabel(android.content.Context);
-    method public android.graphics.drawable.Drawable loadIcon(android.content.Context);
-    method public java.lang.CharSequence loadLabel(android.content.Context);
-    method public void writeToParcel(android.os.Parcel, int);
+    method public CharSequence loadCustomLabel(android.content.Context);
+    method public android.graphics.drawable.Drawable loadIcon(@NonNull android.content.Context);
+    method public CharSequence loadLabel(@NonNull android.content.Context);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.media.tv.TvInputInfo> CREATOR;
-    field public static final java.lang.String EXTRA_INPUT_ID = "android.media.tv.extra.INPUT_ID";
+    field public static final String EXTRA_INPUT_ID = "android.media.tv.extra.INPUT_ID";
     field public static final int TYPE_COMPONENT = 1004; // 0x3ec
     field public static final int TYPE_COMPOSITE = 1001; // 0x3e9
     field public static final int TYPE_DISPLAY_PORT = 1008; // 0x3f0
@@ -27771,23 +28008,23 @@
 
   public final class TvInputManager {
     method public java.util.List<android.media.tv.TvContentRating> getBlockedRatings();
-    method public int getInputState(java.lang.String);
-    method public android.media.tv.TvInputInfo getTvInputInfo(java.lang.String);
+    method public int getInputState(@NonNull String);
+    method @Nullable public android.media.tv.TvInputInfo getTvInputInfo(@NonNull String);
     method public java.util.List<android.media.tv.TvInputInfo> getTvInputList();
     method public boolean isParentalControlsEnabled();
-    method public boolean isRatingBlocked(android.media.tv.TvContentRating);
-    method public void registerCallback(android.media.tv.TvInputManager.TvInputCallback, android.os.Handler);
-    method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
-    method public void updateTvInputInfo(android.media.tv.TvInputInfo);
-    field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
-    field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
-    field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
-    field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
-    field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
+    method public boolean isRatingBlocked(@NonNull android.media.tv.TvContentRating);
+    method public void registerCallback(@NonNull android.media.tv.TvInputManager.TvInputCallback, @NonNull android.os.Handler);
+    method public void unregisterCallback(@NonNull android.media.tv.TvInputManager.TvInputCallback);
+    method public void updateTvInputInfo(@NonNull android.media.tv.TvInputInfo);
+    field public static final String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
+    field public static final String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
+    field public static final String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
+    field public static final String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
+    field public static final String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
     field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
     field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
     field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
-    field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
+    field public static final String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
     field public static final int RECORDING_ERROR_INSUFFICIENT_SPACE = 1; // 0x1
     field public static final int RECORDING_ERROR_RESOURCE_BUSY = 2; // 0x2
     field public static final int RECORDING_ERROR_UNKNOWN = 0; // 0x0
@@ -27803,57 +28040,57 @@
     field public static final int VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL = 2; // 0x2
   }
 
-  public static abstract class TvInputManager.TvInputCallback {
+  public abstract static class TvInputManager.TvInputCallback {
     ctor public TvInputManager.TvInputCallback();
-    method public void onInputAdded(java.lang.String);
-    method public void onInputRemoved(java.lang.String);
-    method public void onInputStateChanged(java.lang.String, int);
-    method public void onInputUpdated(java.lang.String);
+    method public void onInputAdded(String);
+    method public void onInputRemoved(String);
+    method public void onInputStateChanged(String, int);
+    method public void onInputUpdated(String);
     method public void onTvInputInfoUpdated(android.media.tv.TvInputInfo);
   }
 
   public abstract class TvInputService extends android.app.Service {
     ctor public TvInputService();
     method public final android.os.IBinder onBind(android.content.Intent);
-    method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String);
-    method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
-    field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
+    method @Nullable public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(String);
+    method @Nullable public abstract android.media.tv.TvInputService.Session onCreateSession(String);
+    field public static final String SERVICE_INTERFACE = "android.media.tv.TvInputService";
+    field public static final String SERVICE_META_DATA = "android.media.tv.input";
   }
 
-  public static abstract class TvInputService.HardwareSession extends android.media.tv.TvInputService.Session {
+  public abstract static class TvInputService.HardwareSession extends android.media.tv.TvInputService.Session {
     ctor public TvInputService.HardwareSession(android.content.Context);
-    method public abstract java.lang.String getHardwareInputId();
+    method public abstract String getHardwareInputId();
     method public void onHardwareVideoAvailable();
     method public void onHardwareVideoUnavailable(int);
     method public final boolean onSetSurface(android.view.Surface);
   }
 
-  public static abstract class TvInputService.RecordingSession {
+  public abstract static class TvInputService.RecordingSession {
     ctor public TvInputService.RecordingSession(android.content.Context);
     method public void notifyError(int);
     method public void notifyRecordingStopped(android.net.Uri);
     method public void notifyTuned(android.net.Uri);
-    method public void onAppPrivateCommand(java.lang.String, android.os.Bundle);
+    method public void onAppPrivateCommand(@NonNull String, android.os.Bundle);
     method public abstract void onRelease();
-    method public abstract void onStartRecording(android.net.Uri);
+    method public abstract void onStartRecording(@Nullable android.net.Uri);
     method public abstract void onStopRecording();
     method public abstract void onTune(android.net.Uri);
     method public void onTune(android.net.Uri, android.os.Bundle);
   }
 
-  public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
+  public abstract static class TvInputService.Session implements android.view.KeyEvent.Callback {
     ctor public TvInputService.Session(android.content.Context);
     method public void layoutSurface(int, int, int, int);
     method public void notifyChannelRetuned(android.net.Uri);
     method public void notifyContentAllowed();
-    method public void notifyContentBlocked(android.media.tv.TvContentRating);
+    method public void notifyContentBlocked(@NonNull android.media.tv.TvContentRating);
     method public void notifyTimeShiftStatusChanged(int);
-    method public void notifyTrackSelected(int, java.lang.String);
+    method public void notifyTrackSelected(int, String);
     method public void notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>);
     method public void notifyVideoAvailable();
     method public void notifyVideoUnavailable(int);
-    method public void onAppPrivateCommand(java.lang.String, android.os.Bundle);
+    method public void onAppPrivateCommand(@NonNull String, android.os.Bundle);
     method public android.view.View onCreateOverlayView();
     method public boolean onGenericMotionEvent(android.view.MotionEvent);
     method public boolean onKeyDown(int, android.view.KeyEvent);
@@ -27862,10 +28099,10 @@
     method public boolean onKeyUp(int, android.view.KeyEvent);
     method public void onOverlayViewSizeChanged(int, int);
     method public abstract void onRelease();
-    method public boolean onSelectTrack(int, java.lang.String);
+    method public boolean onSelectTrack(int, @Nullable String);
     method public abstract void onSetCaptionEnabled(boolean);
-    method public abstract void onSetStreamVolume(float);
-    method public abstract boolean onSetSurface(android.view.Surface);
+    method public abstract void onSetStreamVolume(@FloatRange(from=0.0, to=1.0) float);
+    method public abstract boolean onSetSurface(@Nullable android.view.Surface);
     method public void onSurfaceChanged(int, int, int);
     method public long onTimeShiftGetCurrentPosition();
     method public long onTimeShiftGetStartPosition();
@@ -27883,19 +28120,19 @@
   }
 
   public class TvRecordingClient {
-    ctor public TvRecordingClient(android.content.Context, java.lang.String, android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
+    ctor public TvRecordingClient(android.content.Context, String, @NonNull android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
     method public void release();
-    method public void sendAppPrivateCommand(java.lang.String, android.os.Bundle);
-    method public void startRecording(android.net.Uri);
+    method public void sendAppPrivateCommand(@NonNull String, android.os.Bundle);
+    method public void startRecording(@Nullable android.net.Uri);
     method public void stopRecording();
-    method public void tune(java.lang.String, android.net.Uri);
-    method public void tune(java.lang.String, android.net.Uri, android.os.Bundle);
+    method public void tune(String, android.net.Uri);
+    method public void tune(String, android.net.Uri, android.os.Bundle);
   }
 
-  public static abstract class TvRecordingClient.RecordingCallback {
+  public abstract static class TvRecordingClient.RecordingCallback {
     ctor public TvRecordingClient.RecordingCallback();
-    method public void onConnectionFailed(java.lang.String);
-    method public void onDisconnected(java.lang.String);
+    method public void onConnectionFailed(String);
+    method public void onDisconnected(String);
     method public void onError(int);
     method public void onRecordingStopped(android.net.Uri);
     method public void onTuned(android.net.Uri);
@@ -27905,10 +28142,10 @@
     method public int describeContents();
     method public int getAudioChannelCount();
     method public int getAudioSampleRate();
-    method public java.lang.CharSequence getDescription();
+    method public CharSequence getDescription();
     method public android.os.Bundle getExtra();
-    method public java.lang.String getId();
-    method public java.lang.String getLanguage();
+    method public String getId();
+    method public String getLanguage();
     method public int getType();
     method public byte getVideoActiveFormatDescription();
     method public float getVideoFrameRate();
@@ -27923,13 +28160,13 @@
   }
 
   public static final class TvTrackInfo.Builder {
-    ctor public TvTrackInfo.Builder(int, java.lang.String);
+    ctor public TvTrackInfo.Builder(int, @NonNull String);
     method public android.media.tv.TvTrackInfo build();
     method public android.media.tv.TvTrackInfo.Builder setAudioChannelCount(int);
     method public android.media.tv.TvTrackInfo.Builder setAudioSampleRate(int);
-    method public android.media.tv.TvTrackInfo.Builder setDescription(java.lang.CharSequence);
+    method public android.media.tv.TvTrackInfo.Builder setDescription(CharSequence);
     method public android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle);
-    method public android.media.tv.TvTrackInfo.Builder setLanguage(java.lang.String);
+    method public android.media.tv.TvTrackInfo.Builder setLanguage(String);
     method public android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte);
     method public android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float);
     method public android.media.tv.TvTrackInfo.Builder setVideoHeight(int);
@@ -27942,51 +28179,51 @@
     ctor public TvView(android.content.Context, android.util.AttributeSet);
     ctor public TvView(android.content.Context, android.util.AttributeSet, int);
     method public boolean dispatchUnhandledInputEvent(android.view.InputEvent);
-    method public java.lang.String getSelectedTrack(int);
+    method public String getSelectedTrack(int);
     method public java.util.List<android.media.tv.TvTrackInfo> getTracks(int);
     method public boolean onUnhandledInputEvent(android.view.InputEvent);
     method public void reset();
-    method public void selectTrack(int, java.lang.String);
-    method public void sendAppPrivateCommand(java.lang.String, android.os.Bundle);
-    method public void setCallback(android.media.tv.TvView.TvInputCallback);
+    method public void selectTrack(int, String);
+    method public void sendAppPrivateCommand(@NonNull String, android.os.Bundle);
+    method public void setCallback(@Nullable android.media.tv.TvView.TvInputCallback);
     method public void setCaptionEnabled(boolean);
     method public void setOnUnhandledInputEventListener(android.media.tv.TvView.OnUnhandledInputEventListener);
-    method public void setStreamVolume(float);
-    method public void setTimeShiftPositionCallback(android.media.tv.TvView.TimeShiftPositionCallback);
+    method public void setStreamVolume(@FloatRange(from=0.0, to=1.0) float);
+    method public void setTimeShiftPositionCallback(@Nullable android.media.tv.TvView.TimeShiftPositionCallback);
     method public void setZOrderMediaOverlay(boolean);
     method public void setZOrderOnTop(boolean);
     method public void timeShiftPause();
-    method public void timeShiftPlay(java.lang.String, android.net.Uri);
+    method public void timeShiftPlay(String, android.net.Uri);
     method public void timeShiftResume();
     method public void timeShiftSeekTo(long);
-    method public void timeShiftSetPlaybackParams(android.media.PlaybackParams);
-    method public void tune(java.lang.String, android.net.Uri);
-    method public void tune(java.lang.String, android.net.Uri, android.os.Bundle);
+    method public void timeShiftSetPlaybackParams(@NonNull android.media.PlaybackParams);
+    method public void tune(@NonNull String, android.net.Uri);
+    method public void tune(String, android.net.Uri, android.os.Bundle);
   }
 
-  public static abstract interface TvView.OnUnhandledInputEventListener {
-    method public abstract boolean onUnhandledInputEvent(android.view.InputEvent);
+  public static interface TvView.OnUnhandledInputEventListener {
+    method public boolean onUnhandledInputEvent(android.view.InputEvent);
   }
 
-  public static abstract class TvView.TimeShiftPositionCallback {
+  public abstract static class TvView.TimeShiftPositionCallback {
     ctor public TvView.TimeShiftPositionCallback();
-    method public void onTimeShiftCurrentPositionChanged(java.lang.String, long);
-    method public void onTimeShiftStartPositionChanged(java.lang.String, long);
+    method public void onTimeShiftCurrentPositionChanged(String, long);
+    method public void onTimeShiftStartPositionChanged(String, long);
   }
 
-  public static abstract class TvView.TvInputCallback {
+  public abstract static class TvView.TvInputCallback {
     ctor public TvView.TvInputCallback();
-    method public void onChannelRetuned(java.lang.String, android.net.Uri);
-    method public void onConnectionFailed(java.lang.String);
-    method public void onContentAllowed(java.lang.String);
-    method public void onContentBlocked(java.lang.String, android.media.tv.TvContentRating);
-    method public void onDisconnected(java.lang.String);
-    method public void onTimeShiftStatusChanged(java.lang.String, int);
-    method public void onTrackSelected(java.lang.String, int, java.lang.String);
-    method public void onTracksChanged(java.lang.String, java.util.List<android.media.tv.TvTrackInfo>);
-    method public void onVideoAvailable(java.lang.String);
-    method public void onVideoSizeChanged(java.lang.String, int, int);
-    method public void onVideoUnavailable(java.lang.String, int);
+    method public void onChannelRetuned(String, android.net.Uri);
+    method public void onConnectionFailed(String);
+    method public void onContentAllowed(String);
+    method public void onContentBlocked(String, android.media.tv.TvContentRating);
+    method public void onDisconnected(String);
+    method public void onTimeShiftStatusChanged(String, int);
+    method public void onTrackSelected(String, int, String);
+    method public void onTracksChanged(String, java.util.List<android.media.tv.TvTrackInfo>);
+    method public void onVideoAvailable(String);
+    method public void onVideoSizeChanged(String, int, int);
+    method public void onVideoUnavailable(String, int);
   }
 
 }
@@ -28098,37 +28335,37 @@
   }
 
   public final class MtpDevice {
-    ctor public MtpDevice(android.hardware.usb.UsbDevice);
+    ctor public MtpDevice(@NonNull android.hardware.usb.UsbDevice);
     method public void close();
     method public boolean deleteObject(int);
     method public int getDeviceId();
-    method public android.mtp.MtpDeviceInfo getDeviceInfo();
-    method public java.lang.String getDeviceName();
-    method public byte[] getObject(int, int);
-    method public int[] getObjectHandles(int, int, int);
-    method public android.mtp.MtpObjectInfo getObjectInfo(int);
+    method @Nullable public android.mtp.MtpDeviceInfo getDeviceInfo();
+    method @NonNull public String getDeviceName();
+    method @Nullable public byte[] getObject(int, int);
+    method @Nullable public int[] getObjectHandles(int, int, int);
+    method @Nullable public android.mtp.MtpObjectInfo getObjectInfo(int);
     method public long getParent(int);
-    method public long getPartialObject(int, long, long, byte[]) throws java.io.IOException;
-    method public long getPartialObject64(int, long, long, byte[]) throws java.io.IOException;
+    method public long getPartialObject(int, long, long, @NonNull byte[]) throws java.io.IOException;
+    method public long getPartialObject64(int, long, long, @NonNull byte[]) throws java.io.IOException;
     method public long getStorageId(int);
-    method public int[] getStorageIds();
-    method public android.mtp.MtpStorageInfo getStorageInfo(int);
-    method public byte[] getThumbnail(int);
-    method public boolean importFile(int, java.lang.String);
-    method public boolean importFile(int, android.os.ParcelFileDescriptor);
-    method public boolean open(android.hardware.usb.UsbDeviceConnection);
-    method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal) throws java.io.IOException;
-    method public boolean sendObject(int, long, android.os.ParcelFileDescriptor);
-    method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
+    method @Nullable public int[] getStorageIds();
+    method @Nullable public android.mtp.MtpStorageInfo getStorageInfo(int);
+    method @Nullable public byte[] getThumbnail(int);
+    method public boolean importFile(int, @NonNull String);
+    method public boolean importFile(int, @NonNull android.os.ParcelFileDescriptor);
+    method public boolean open(@NonNull android.hardware.usb.UsbDeviceConnection);
+    method @NonNull public android.mtp.MtpEvent readEvent(@Nullable android.os.CancellationSignal) throws java.io.IOException;
+    method public boolean sendObject(int, long, @NonNull android.os.ParcelFileDescriptor);
+    method @Nullable public android.mtp.MtpObjectInfo sendObjectInfo(@NonNull android.mtp.MtpObjectInfo);
   }
 
   public class MtpDeviceInfo {
-    method public final int[] getEventsSupported();
-    method public final java.lang.String getManufacturer();
-    method public final java.lang.String getModel();
-    method public final int[] getOperationsSupported();
-    method public final java.lang.String getSerialNumber();
-    method public final java.lang.String getVersion();
+    method @NonNull public final int[] getEventsSupported();
+    method @NonNull public final String getManufacturer();
+    method @NonNull public final String getModel();
+    method @NonNull public final int[] getOperationsSupported();
+    method @NonNull public final String getSerialNumber();
+    method @NonNull public final String getVersion();
     method public boolean isEventSupported(int);
     method public boolean isOperationSupported(int);
   }
@@ -28178,8 +28415,8 @@
     method public long getImagePixHeightLong();
     method public int getImagePixWidth();
     method public long getImagePixWidthLong();
-    method public java.lang.String getKeywords();
-    method public java.lang.String getName();
+    method @NonNull public String getKeywords();
+    method @NonNull public String getName();
     method public int getObjectHandle();
     method public int getParent();
     method public int getProtectionStatus();
@@ -28208,8 +28445,8 @@
     method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(long);
     method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(long);
     method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(long);
-    method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
-    method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
+    method public android.mtp.MtpObjectInfo.Builder setKeywords(@NonNull String);
+    method public android.mtp.MtpObjectInfo.Builder setName(@NonNull String);
     method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
     method public android.mtp.MtpObjectInfo.Builder setParent(int);
     method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
@@ -28222,11 +28459,11 @@
   }
 
   public final class MtpStorageInfo {
-    method public java.lang.String getDescription();
+    method @NonNull public String getDescription();
     method public long getFreeSpace();
     method public long getMaxCapacity();
     method public int getStorageId();
-    method public java.lang.String getVolumeIdentifier();
+    method @NonNull public String getVolumeIdentifier();
   }
 
 }
@@ -28243,79 +28480,80 @@
 
   public class ConnectivityManager {
     method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
-    method public boolean bindProcessToNetwork(android.net.Network);
-    method public android.net.Network getActiveNetwork();
-    method public deprecated android.net.NetworkInfo getActiveNetworkInfo();
-    method public deprecated android.net.NetworkInfo[] getAllNetworkInfo();
-    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);
-    method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
-    method public deprecated android.net.NetworkInfo getNetworkInfo(int);
-    method public deprecated android.net.NetworkInfo getNetworkInfo(android.net.Network);
-    method public deprecated int getNetworkPreference();
-    method public byte[] getNetworkWatchlistConfigHash();
-    method public static deprecated android.net.Network getProcessDefaultNetwork();
+    method public boolean bindProcessToNetwork(@Nullable android.net.Network);
+    method public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public android.net.Network getActiveNetwork();
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @NonNull public android.net.Network[] getAllNetworks();
+    method @Deprecated public boolean getBackgroundDataSetting();
+    method @Nullable public android.net.Network getBoundNetworkForProcess();
+    method public int getConnectionOwnerUid(int, @NonNull java.net.InetSocketAddress, @NonNull java.net.InetSocketAddress);
+    method @Nullable public android.net.ProxyInfo getDefaultProxy();
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public android.net.LinkProperties getLinkProperties(@Nullable android.net.Network);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getMultipathPreference(@Nullable android.net.Network);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public android.net.NetworkCapabilities getNetworkCapabilities(@Nullable android.net.Network);
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(int);
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(@Nullable android.net.Network);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getNetworkPreference();
+    method @Nullable public byte[] getNetworkWatchlistConfigHash();
+    method @Deprecated @Nullable public static android.net.Network getProcessDefaultNetwork();
     method public int getRestrictBackgroundStatus();
-    method public boolean isActiveNetworkMetered();
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public boolean isActiveNetworkMetered();
     method public boolean isDefaultNetworkActive();
-    method public static deprecated boolean isNetworkTypeValid(int);
-    method public void registerDefaultNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
-    method public void registerDefaultNetworkCallback(android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
-    method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
-    method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
-    method public void registerNetworkCallback(android.net.NetworkRequest, android.app.PendingIntent);
-    method public void releaseNetworkRequest(android.app.PendingIntent);
-    method public void removeDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
-    method public deprecated void reportBadNetwork(android.net.Network);
-    method public void reportNetworkConnectivity(android.net.Network, boolean);
-    method public boolean requestBandwidthUpdate(android.net.Network);
-    method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
-    method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
-    method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, int);
-    method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler, int);
-    method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
-    method public deprecated void setNetworkPreference(int);
-    method public static deprecated boolean setProcessDefaultNetwork(android.net.Network);
-    method public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
-    method public void unregisterNetworkCallback(android.app.PendingIntent);
-    field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
-    field public static final java.lang.String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
-    field public static final java.lang.String ACTION_RESTRICT_BACKGROUND_CHANGED = "android.net.conn.RESTRICT_BACKGROUND_CHANGED";
-    field public static final deprecated java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
-    field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
-    field public static final java.lang.String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
-    field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
-    field public static final deprecated java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
-    field public static final deprecated java.lang.String EXTRA_IS_FAILOVER = "isFailover";
-    field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK";
-    field public static final deprecated java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
-    field public static final java.lang.String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST";
-    field public static final java.lang.String EXTRA_NETWORK_TYPE = "networkType";
-    field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
-    field public static final deprecated java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
-    field public static final java.lang.String EXTRA_REASON = "reason";
+    method @Deprecated public static boolean isNetworkTypeValid(int);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
+    method public void releaseNetworkRequest(@NonNull android.app.PendingIntent);
+    method public void removeDefaultNetworkActiveListener(@NonNull android.net.ConnectivityManager.OnNetworkActiveListener);
+    method @Deprecated public void reportBadNetwork(@Nullable android.net.Network);
+    method public void reportNetworkConnectivity(@Nullable android.net.Network, boolean);
+    method public boolean requestBandwidthUpdate(@NonNull android.net.Network);
+    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
+    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int);
+    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler, int);
+    method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
+    method @Deprecated public void setNetworkPreference(int);
+    method @Deprecated public static boolean setProcessDefaultNetwork(@Nullable android.net.Network);
+    method public void unregisterNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
+    method public void unregisterNetworkCallback(@NonNull android.app.PendingIntent);
+    field @Deprecated public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
+    field public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
+    field public static final String ACTION_RESTRICT_BACKGROUND_CHANGED = "android.net.conn.RESTRICT_BACKGROUND_CHANGED";
+    field @Deprecated public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
+    field @Deprecated public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
+    field public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
+    field public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
+    field @Deprecated public static final String EXTRA_EXTRA_INFO = "extraInfo";
+    field @Deprecated public static final String EXTRA_IS_FAILOVER = "isFailover";
+    field public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
+    field @Deprecated public static final String EXTRA_NETWORK_INFO = "networkInfo";
+    field public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST";
+    field public static final String EXTRA_NETWORK_TYPE = "networkType";
+    field public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity";
+    field @Deprecated public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
+    field public static final String EXTRA_REASON = "reason";
     field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
     field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
     field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
     field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
     field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
     field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
-    field public static final deprecated int TYPE_BLUETOOTH = 7; // 0x7
-    field public static final deprecated int TYPE_DUMMY = 8; // 0x8
-    field public static final deprecated int TYPE_ETHERNET = 9; // 0x9
-    field public static final deprecated int TYPE_MOBILE = 0; // 0x0
-    field public static final deprecated int TYPE_MOBILE_DUN = 4; // 0x4
-    field public static final deprecated int TYPE_MOBILE_HIPRI = 5; // 0x5
-    field public static final deprecated int TYPE_MOBILE_MMS = 2; // 0x2
-    field public static final deprecated int TYPE_MOBILE_SUPL = 3; // 0x3
-    field public static final deprecated int TYPE_VPN = 17; // 0x11
-    field public static final deprecated int TYPE_WIFI = 1; // 0x1
-    field public static final deprecated int TYPE_WIMAX = 6; // 0x6
+    field @Deprecated public static final int TYPE_BLUETOOTH = 7; // 0x7
+    field @Deprecated public static final int TYPE_DUMMY = 8; // 0x8
+    field @Deprecated public static final int TYPE_ETHERNET = 9; // 0x9
+    field @Deprecated public static final int TYPE_MOBILE = 0; // 0x0
+    field @Deprecated public static final int TYPE_MOBILE_DUN = 4; // 0x4
+    field @Deprecated public static final int TYPE_MOBILE_HIPRI = 5; // 0x5
+    field @Deprecated public static final int TYPE_MOBILE_MMS = 2; // 0x2
+    field @Deprecated public static final int TYPE_MOBILE_SUPL = 3; // 0x3
+    field @Deprecated public static final int TYPE_VPN = 17; // 0x11
+    field @Deprecated public static final int TYPE_WIFI = 1; // 0x1
+    field @Deprecated public static final int TYPE_WIMAX = 6; // 0x6
   }
 
   public static class ConnectivityManager.NetworkCallback {
@@ -28329,8 +28567,8 @@
     method public void onUnavailable();
   }
 
-  public static abstract interface ConnectivityManager.OnNetworkActiveListener {
-    method public abstract void onNetworkActive();
+  public static interface ConnectivityManager.OnNetworkActiveListener {
+    method public void onNetworkActive();
   }
 
   public class Credentials {
@@ -28353,9 +28591,31 @@
     field public int serverAddress;
   }
 
+  public final class DnsResolver {
+    method public static android.net.DnsResolver getInstance();
+    method public void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.RawAnswerListener) throws android.system.ErrnoException;
+    method public void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.RawAnswerListener) throws android.system.ErrnoException;
+    method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.InetAddressAnswerListener) throws android.system.ErrnoException;
+    field public static final int CLASS_IN = 1; // 0x1
+    field public static final int FLAG_EMPTY = 0; // 0x0
+    field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
+    field public static final int FLAG_NO_CACHE_STORE = 2; // 0x2
+    field public static final int FLAG_NO_RETRY = 1; // 0x1
+    field public static final int TYPE_A = 1; // 0x1
+    field public static final int TYPE_AAAA = 28; // 0x1c
+  }
+
+  public static interface DnsResolver.InetAddressAnswerListener {
+    method public void onAnswer(@NonNull java.util.List<java.net.InetAddress>);
+  }
+
+  public static interface DnsResolver.RawAnswerListener {
+    method public void onAnswer(@Nullable byte[]);
+  }
+
   public class InetAddresses {
-    method public static boolean isNumericAddress(java.lang.String);
-    method public static java.net.InetAddress parseNumericAddress(java.lang.String);
+    method public static boolean isNumericAddress(String);
+    method public static java.net.InetAddress parseNumericAddress(String);
   }
 
   public final class IpPrefix implements android.os.Parcelable {
@@ -28369,34 +28629,34 @@
   }
 
   public final class IpSecAlgorithm implements android.os.Parcelable {
-    ctor public IpSecAlgorithm(java.lang.String, byte[]);
-    ctor public IpSecAlgorithm(java.lang.String, byte[], int);
+    ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[]);
+    ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[], int);
     method public int describeContents();
-    method public byte[] getKey();
-    method public java.lang.String getName();
+    method @NonNull public byte[] getKey();
+    method @NonNull public String getName();
     method public int getTruncationLengthBits();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final java.lang.String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
-    field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
-    field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
-    field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
-    field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)";
-    field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)";
+    field public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
+    field public static final String AUTH_HMAC_MD5 = "hmac(md5)";
+    field public static final String AUTH_HMAC_SHA1 = "hmac(sha1)";
+    field public static final String AUTH_HMAC_SHA256 = "hmac(sha256)";
+    field public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
+    field public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
     field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
-    field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)";
+    field public static final String CRYPT_AES_CBC = "cbc(aes)";
   }
 
   public final class IpSecManager {
-    method public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
-    method public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
-    method public void applyTransportModeTransform(java.net.Socket, int, android.net.IpSecTransform) throws java.io.IOException;
-    method public void applyTransportModeTransform(java.net.DatagramSocket, int, android.net.IpSecTransform) throws java.io.IOException;
-    method public void applyTransportModeTransform(java.io.FileDescriptor, int, android.net.IpSecTransform) throws java.io.IOException;
-    method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
-    method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
-    method public void removeTransportModeTransforms(java.net.Socket) throws java.io.IOException;
-    method public void removeTransportModeTransforms(java.net.DatagramSocket) throws java.io.IOException;
-    method public void removeTransportModeTransforms(java.io.FileDescriptor) throws java.io.IOException;
+    method @NonNull public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(@NonNull java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
+    method @NonNull public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(@NonNull java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    method public void applyTransportModeTransform(@NonNull java.net.Socket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+    method public void applyTransportModeTransform(@NonNull java.net.DatagramSocket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+    method public void applyTransportModeTransform(@NonNull java.io.FileDescriptor, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+    method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+    method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+    method public void removeTransportModeTransforms(@NonNull java.net.Socket) throws java.io.IOException;
+    method public void removeTransportModeTransforms(@NonNull java.net.DatagramSocket) throws java.io.IOException;
+    method public void removeTransportModeTransforms(@NonNull java.io.FileDescriptor) throws java.io.IOException;
     field public static final int DIRECTION_IN = 0; // 0x0
     field public static final int DIRECTION_OUT = 1; // 0x1
   }
@@ -28424,12 +28684,12 @@
   }
 
   public static class IpSecTransform.Builder {
-    ctor public IpSecTransform.Builder(android.content.Context);
-    method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress, android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
-    method public android.net.IpSecTransform.Builder setAuthenticatedEncryption(android.net.IpSecAlgorithm);
-    method public android.net.IpSecTransform.Builder setAuthentication(android.net.IpSecAlgorithm);
-    method public android.net.IpSecTransform.Builder setEncryption(android.net.IpSecAlgorithm);
-    method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
+    ctor public IpSecTransform.Builder(@NonNull android.content.Context);
+    method @NonNull public android.net.IpSecTransform buildTransportModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    method @NonNull public android.net.IpSecTransform.Builder setAuthenticatedEncryption(@NonNull android.net.IpSecAlgorithm);
+    method @NonNull public android.net.IpSecTransform.Builder setAuthentication(@NonNull android.net.IpSecAlgorithm);
+    method @NonNull public android.net.IpSecTransform.Builder setEncryption(@NonNull android.net.IpSecAlgorithm);
+    method @NonNull public android.net.IpSecTransform.Builder setIpv4Encapsulation(@NonNull android.net.IpSecManager.UdpEncapsulationSocket, int);
   }
 
   public class LinkAddress implements android.os.Parcelable {
@@ -28445,12 +28705,12 @@
   public final class LinkProperties implements android.os.Parcelable {
     method public int describeContents();
     method public java.util.List<java.net.InetAddress> getDnsServers();
-    method public java.lang.String getDomains();
+    method public String getDomains();
     method public android.net.ProxyInfo getHttpProxy();
-    method public java.lang.String getInterfaceName();
+    method @Nullable public String getInterfaceName();
     method public java.util.List<android.net.LinkAddress> getLinkAddresses();
     method public int getMtu();
-    method public java.lang.String getPrivateDnsServerName();
+    method @Nullable public String getPrivateDnsServerName();
     method public java.util.List<android.net.RouteInfo> getRoutes();
     method public boolean isPrivateDnsActive();
     method public void writeToParcel(android.os.Parcel, int);
@@ -28458,7 +28718,7 @@
   }
 
   public class LocalServerSocket implements java.io.Closeable {
-    ctor public LocalServerSocket(java.lang.String) throws java.io.IOException;
+    ctor public LocalServerSocket(String) throws java.io.IOException;
     ctor public LocalServerSocket(java.io.FileDescriptor) throws java.io.IOException;
     method public android.net.LocalSocket accept() throws java.io.IOException;
     method public void close() throws java.io.IOException;
@@ -28483,9 +28743,9 @@
     method public android.net.LocalSocketAddress getRemoteSocketAddress();
     method public int getSendBufferSize() throws java.io.IOException;
     method public int getSoTimeout() throws java.io.IOException;
-    method public synchronized boolean isBound();
+    method public boolean isBound();
     method public boolean isClosed();
-    method public synchronized boolean isConnected();
+    method public boolean isConnected();
     method public boolean isInputShutdown();
     method public boolean isOutputShutdown();
     method public void setFileDescriptorsForSend(java.io.FileDescriptor[]);
@@ -28500,15 +28760,13 @@
   }
 
   public class LocalSocketAddress {
-    ctor public LocalSocketAddress(java.lang.String, android.net.LocalSocketAddress.Namespace);
-    ctor public LocalSocketAddress(java.lang.String);
-    method public java.lang.String getName();
+    ctor public LocalSocketAddress(String, android.net.LocalSocketAddress.Namespace);
+    ctor public LocalSocketAddress(String);
+    method public String getName();
     method public android.net.LocalSocketAddress.Namespace getNamespace();
   }
 
-  public static final class LocalSocketAddress.Namespace extends java.lang.Enum {
-    method public static android.net.LocalSocketAddress.Namespace valueOf(java.lang.String);
-    method public static final android.net.LocalSocketAddress.Namespace[] values();
+  public enum LocalSocketAddress.Namespace {
     enum_constant public static final android.net.LocalSocketAddress.Namespace ABSTRACT;
     enum_constant public static final android.net.LocalSocketAddress.Namespace FILESYSTEM;
     enum_constant public static final android.net.LocalSocketAddress.Namespace RESERVED;
@@ -28516,12 +28774,12 @@
 
   public final class MacAddress implements android.os.Parcelable {
     method public int describeContents();
-    method public static android.net.MacAddress fromBytes(byte[]);
-    method public static android.net.MacAddress fromString(java.lang.String);
+    method @NonNull public static android.net.MacAddress fromBytes(@NonNull byte[]);
+    method @NonNull public static android.net.MacAddress fromString(@NonNull String);
     method public int getAddressType();
     method public boolean isLocallyAssigned();
-    method public byte[] toByteArray();
-    method public java.lang.String toOuiString();
+    method @NonNull public byte[] toByteArray();
+    method @NonNull public String toOuiString();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.net.MacAddress BROADCAST_ADDRESS;
     field public static final android.os.Parcelable.Creator<android.net.MacAddress> CREATOR;
@@ -28531,14 +28789,14 @@
   }
 
   public class MailTo {
-    method public java.lang.String getBody();
-    method public java.lang.String getCc();
-    method public java.util.Map<java.lang.String, java.lang.String> getHeaders();
-    method public java.lang.String getSubject();
-    method public java.lang.String getTo();
-    method public static boolean isMailTo(java.lang.String);
-    method public static android.net.MailTo parse(java.lang.String) throws android.net.ParseException;
-    field public static final java.lang.String MAILTO_SCHEME = "mailto:";
+    method public String getBody();
+    method public String getCc();
+    method public java.util.Map<java.lang.String,java.lang.String> getHeaders();
+    method public String getSubject();
+    method public String getTo();
+    method public static boolean isMailTo(String);
+    method public static android.net.MailTo parse(String) throws android.net.ParseException;
+    field public static final String MAILTO_SCHEME = "mailto:";
   }
 
   public class Network implements android.os.Parcelable {
@@ -28547,8 +28805,8 @@
     method public void bindSocket(java.io.FileDescriptor) throws java.io.IOException;
     method public int describeContents();
     method public static android.net.Network fromNetworkHandle(long);
-    method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
-    method public java.net.InetAddress getByName(java.lang.String) throws java.net.UnknownHostException;
+    method public java.net.InetAddress[] getAllByName(String) throws java.net.UnknownHostException;
+    method public java.net.InetAddress getByName(String) throws java.net.UnknownHostException;
     method public long getNetworkHandle();
     method public javax.net.SocketFactory getSocketFactory();
     method public java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
@@ -28562,7 +28820,7 @@
     method public int describeContents();
     method public int getLinkDownstreamBandwidthKbps();
     method public int getLinkUpstreamBandwidthKbps();
-    method public android.net.TransportInfo getTransportInfo();
+    method @Nullable public android.net.TransportInfo getTransportInfo();
     method public boolean hasCapability(int);
     method public boolean hasTransport(int);
     method public void writeToParcel(android.os.Parcel, int);
@@ -28598,52 +28856,48 @@
     field public static final int TRANSPORT_WIFI_AWARE = 5; // 0x5
   }
 
-  public deprecated class NetworkInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method public deprecated android.net.NetworkInfo.DetailedState getDetailedState();
-    method public deprecated java.lang.String getExtraInfo();
-    method public deprecated java.lang.String getReason();
-    method public deprecated android.net.NetworkInfo.State getState();
-    method public deprecated int getSubtype();
-    method public deprecated java.lang.String getSubtypeName();
-    method public deprecated int getType();
-    method public deprecated java.lang.String getTypeName();
-    method public deprecated boolean isAvailable();
-    method public deprecated boolean isConnected();
-    method public deprecated boolean isConnectedOrConnecting();
-    method public deprecated boolean isFailover();
-    method public deprecated boolean isRoaming();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
+  @Deprecated public class NetworkInfo implements android.os.Parcelable {
+    method @Deprecated public int describeContents();
+    method @Deprecated public android.net.NetworkInfo.DetailedState getDetailedState();
+    method @Deprecated public String getExtraInfo();
+    method @Deprecated public String getReason();
+    method @Deprecated public android.net.NetworkInfo.State getState();
+    method @Deprecated public int getSubtype();
+    method @Deprecated public String getSubtypeName();
+    method @Deprecated public int getType();
+    method @Deprecated public String getTypeName();
+    method @Deprecated public boolean isAvailable();
+    method @Deprecated public boolean isConnected();
+    method @Deprecated public boolean isConnectedOrConnecting();
+    method @Deprecated public boolean isFailover();
+    method @Deprecated public boolean isRoaming();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
   }
 
-  public static final deprecated class NetworkInfo.DetailedState extends java.lang.Enum {
-    method public static android.net.NetworkInfo.DetailedState valueOf(java.lang.String);
-    method public static final android.net.NetworkInfo.DetailedState[] values();
-    enum_constant public static final android.net.NetworkInfo.DetailedState AUTHENTICATING;
-    enum_constant public static final android.net.NetworkInfo.DetailedState BLOCKED;
-    enum_constant public static final android.net.NetworkInfo.DetailedState CAPTIVE_PORTAL_CHECK;
-    enum_constant public static final android.net.NetworkInfo.DetailedState CONNECTED;
-    enum_constant public static final android.net.NetworkInfo.DetailedState CONNECTING;
-    enum_constant public static final android.net.NetworkInfo.DetailedState DISCONNECTED;
-    enum_constant public static final android.net.NetworkInfo.DetailedState DISCONNECTING;
-    enum_constant public static final android.net.NetworkInfo.DetailedState FAILED;
-    enum_constant public static final android.net.NetworkInfo.DetailedState IDLE;
-    enum_constant public static final android.net.NetworkInfo.DetailedState OBTAINING_IPADDR;
-    enum_constant public static final android.net.NetworkInfo.DetailedState SCANNING;
-    enum_constant public static final android.net.NetworkInfo.DetailedState SUSPENDED;
-    enum_constant public static final android.net.NetworkInfo.DetailedState VERIFYING_POOR_LINK;
+  @Deprecated public enum NetworkInfo.DetailedState {
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState AUTHENTICATING;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState BLOCKED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CAPTIVE_PORTAL_CHECK;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTING;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTING;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState FAILED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState IDLE;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState OBTAINING_IPADDR;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SCANNING;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SUSPENDED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState VERIFYING_POOR_LINK;
   }
 
-  public static final deprecated class NetworkInfo.State extends java.lang.Enum {
-    method public static android.net.NetworkInfo.State valueOf(java.lang.String);
-    method public static final android.net.NetworkInfo.State[] values();
-    enum_constant public static final android.net.NetworkInfo.State CONNECTED;
-    enum_constant public static final android.net.NetworkInfo.State CONNECTING;
-    enum_constant public static final android.net.NetworkInfo.State DISCONNECTED;
-    enum_constant public static final android.net.NetworkInfo.State DISCONNECTING;
-    enum_constant public static final android.net.NetworkInfo.State SUSPENDED;
-    enum_constant public static final android.net.NetworkInfo.State UNKNOWN;
+  @Deprecated public enum NetworkInfo.State {
+    enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTING;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTING;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.State SUSPENDED;
+    enum_constant @Deprecated public static final android.net.NetworkInfo.State UNKNOWN;
   }
 
   public class NetworkRequest implements android.os.Parcelable {
@@ -28661,7 +28915,7 @@
     method public android.net.NetworkRequest build();
     method public android.net.NetworkRequest.Builder removeCapability(int);
     method public android.net.NetworkRequest.Builder removeTransportType(int);
-    method public android.net.NetworkRequest.Builder setNetworkSpecifier(java.lang.String);
+    method public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
     method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
   }
 
@@ -28669,26 +28923,26 @@
   }
 
   public class ParseException extends java.lang.RuntimeException {
-    field public java.lang.String response;
+    field public String response;
   }
 
   public final class Proxy {
     ctor public Proxy();
-    method public static deprecated java.lang.String getDefaultHost();
-    method public static deprecated int getDefaultPort();
-    method public static deprecated java.lang.String getHost(android.content.Context);
-    method public static deprecated int getPort(android.content.Context);
-    field public static final deprecated java.lang.String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
-    field public static final java.lang.String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
+    method @Deprecated public static String getDefaultHost();
+    method @Deprecated public static int getDefaultPort();
+    method @Deprecated public static String getHost(android.content.Context);
+    method @Deprecated public static int getPort(android.content.Context);
+    field @Deprecated public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
+    field public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
   }
 
   public class ProxyInfo implements android.os.Parcelable {
-    method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int);
-    method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int, java.util.List<java.lang.String>);
+    method public static android.net.ProxyInfo buildDirectProxy(String, int);
+    method public static android.net.ProxyInfo buildDirectProxy(String, int, java.util.List<java.lang.String>);
     method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
     method public int describeContents();
-    method public java.lang.String[] getExclusionList();
-    method public java.lang.String getHost();
+    method public String[] getExclusionList();
+    method public String getHost();
     method public android.net.Uri getPacFileUrl();
     method public int getPort();
     method public void writeToParcel(android.os.Parcel, int);
@@ -28699,31 +28953,32 @@
     method public int describeContents();
     method public android.net.IpPrefix getDestination();
     method public java.net.InetAddress getGateway();
-    method public java.lang.String getInterface();
+    method public String getInterface();
+    method public boolean hasGateway();
     method public boolean isDefaultRoute();
     method public boolean matches(java.net.InetAddress);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.RouteInfo> CREATOR;
   }
 
-  public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
-    ctor public deprecated SSLCertificateSocketFactory(int);
-    method public java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException;
-    method public java.net.Socket createSocket(java.net.InetAddress, int, java.net.InetAddress, int) throws java.io.IOException;
-    method public java.net.Socket createSocket(java.net.InetAddress, int) throws java.io.IOException;
-    method public java.net.Socket createSocket(java.lang.String, int, java.net.InetAddress, int) throws java.io.IOException;
-    method public java.net.Socket createSocket(java.lang.String, int) throws java.io.IOException;
-    method public static javax.net.SocketFactory getDefault(int);
-    method public static javax.net.ssl.SSLSocketFactory getDefault(int, android.net.SSLSessionCache);
-    method public java.lang.String[] getDefaultCipherSuites();
-    method public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache);
-    method public byte[] getNpnSelectedProtocol(java.net.Socket);
-    method public java.lang.String[] getSupportedCipherSuites();
-    method public void setHostname(java.net.Socket, java.lang.String);
-    method public void setKeyManagers(javax.net.ssl.KeyManager[]);
-    method public void setNpnProtocols(byte[][]);
-    method public void setTrustManagers(javax.net.ssl.TrustManager[]);
-    method public void setUseSessionTickets(java.net.Socket, boolean);
+  @Deprecated public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
+    ctor @Deprecated public SSLCertificateSocketFactory(int);
+    method @Deprecated public java.net.Socket createSocket(java.net.Socket, String, int, boolean) throws java.io.IOException;
+    method @Deprecated public java.net.Socket createSocket(java.net.InetAddress, int, java.net.InetAddress, int) throws java.io.IOException;
+    method @Deprecated public java.net.Socket createSocket(java.net.InetAddress, int) throws java.io.IOException;
+    method @Deprecated public java.net.Socket createSocket(String, int, java.net.InetAddress, int) throws java.io.IOException;
+    method @Deprecated public java.net.Socket createSocket(String, int) throws java.io.IOException;
+    method @Deprecated public static javax.net.SocketFactory getDefault(int);
+    method @Deprecated public static javax.net.ssl.SSLSocketFactory getDefault(int, android.net.SSLSessionCache);
+    method @Deprecated public String[] getDefaultCipherSuites();
+    method @Deprecated public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache);
+    method @Deprecated public byte[] getNpnSelectedProtocol(java.net.Socket);
+    method @Deprecated public String[] getSupportedCipherSuites();
+    method @Deprecated public void setHostname(java.net.Socket, String);
+    method @Deprecated public void setKeyManagers(javax.net.ssl.KeyManager[]);
+    method @Deprecated public void setNpnProtocols(byte[][]);
+    method @Deprecated public void setTrustManagers(javax.net.ssl.TrustManager[]);
+    method @Deprecated public void setUseSessionTickets(java.net.Socket, boolean);
   }
 
   public final class SSLSessionCache {
@@ -28731,6 +28986,29 @@
     ctor public SSLSessionCache(android.content.Context);
   }
 
+  public abstract class SocketKeepalive implements java.lang.AutoCloseable {
+    method public final void close();
+    method public final void start(@IntRange(from=0xa, to=0xe10) int);
+    method public final void stop();
+    field public static final int ERROR_HARDWARE_ERROR = -31; // 0xffffffe1
+    field public static final int ERROR_HARDWARE_UNSUPPORTED = -30; // 0xffffffe2
+    field public static final int ERROR_INVALID_INTERVAL = -24; // 0xffffffe8
+    field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
+    field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
+    field public static final int ERROR_INVALID_NETWORK = -20; // 0xffffffec
+    field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
+    field public static final int ERROR_INVALID_SOCKET = -25; // 0xffffffe7
+    field public static final int ERROR_SOCKET_NOT_IDLE = -26; // 0xffffffe6
+  }
+
+  public static class SocketKeepalive.Callback {
+    ctor public SocketKeepalive.Callback();
+    method public void onDataReceived();
+    method public void onError(int);
+    method public void onStarted();
+    method public void onStopped();
+  }
+
   public class TrafficStats {
     ctor public TrafficStats();
     method public static void clearThreadStatsTag();
@@ -28748,16 +29026,16 @@
     method public static long getTotalTxPackets();
     method public static long getUidRxBytes(int);
     method public static long getUidRxPackets(int);
-    method public static deprecated long getUidTcpRxBytes(int);
-    method public static deprecated long getUidTcpRxSegments(int);
-    method public static deprecated long getUidTcpTxBytes(int);
-    method public static deprecated long getUidTcpTxSegments(int);
+    method @Deprecated public static long getUidTcpRxBytes(int);
+    method @Deprecated public static long getUidTcpRxSegments(int);
+    method @Deprecated public static long getUidTcpTxBytes(int);
+    method @Deprecated public static long getUidTcpTxSegments(int);
     method public static long getUidTxBytes(int);
     method public static long getUidTxPackets(int);
-    method public static deprecated long getUidUdpRxBytes(int);
-    method public static deprecated long getUidUdpRxPackets(int);
-    method public static deprecated long getUidUdpTxBytes(int);
-    method public static deprecated long getUidUdpTxPackets(int);
+    method @Deprecated public static long getUidUdpRxBytes(int);
+    method @Deprecated public static long getUidUdpRxPackets(int);
+    method @Deprecated public static long getUidUdpTxBytes(int);
+    method @Deprecated public static long getUidUdpTxPackets(int);
     method public static void incrementOperationCount(int);
     method public static void incrementOperationCount(int, int);
     method public static void setThreadStatsTag(int);
@@ -28771,47 +29049,47 @@
     field public static final int UNSUPPORTED = -1; // 0xffffffff
   }
 
-  public abstract interface TransportInfo {
+  public interface TransportInfo {
   }
 
-  public abstract class Uri implements java.lang.Comparable android.os.Parcelable {
+  public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable {
     method public abstract android.net.Uri.Builder buildUpon();
     method public int compareTo(android.net.Uri);
-    method public static java.lang.String decode(java.lang.String);
-    method public static java.lang.String encode(java.lang.String);
-    method public static java.lang.String encode(java.lang.String, java.lang.String);
+    method public static String decode(String);
+    method public static String encode(String);
+    method public static String encode(String, String);
     method public static android.net.Uri fromFile(java.io.File);
-    method public static android.net.Uri fromParts(java.lang.String, java.lang.String, java.lang.String);
-    method public abstract java.lang.String getAuthority();
-    method public boolean getBooleanQueryParameter(java.lang.String, boolean);
-    method public abstract java.lang.String getEncodedAuthority();
-    method public abstract java.lang.String getEncodedFragment();
-    method public abstract java.lang.String getEncodedPath();
-    method public abstract java.lang.String getEncodedQuery();
-    method public abstract java.lang.String getEncodedSchemeSpecificPart();
-    method public abstract java.lang.String getEncodedUserInfo();
-    method public abstract java.lang.String getFragment();
-    method public abstract java.lang.String getHost();
-    method public abstract java.lang.String getLastPathSegment();
-    method public abstract java.lang.String getPath();
+    method public static android.net.Uri fromParts(String, String, String);
+    method @Nullable public abstract String getAuthority();
+    method public boolean getBooleanQueryParameter(String, boolean);
+    method @Nullable public abstract String getEncodedAuthority();
+    method @Nullable public abstract String getEncodedFragment();
+    method @Nullable public abstract String getEncodedPath();
+    method @Nullable public abstract String getEncodedQuery();
+    method public abstract String getEncodedSchemeSpecificPart();
+    method @Nullable public abstract String getEncodedUserInfo();
+    method @Nullable public abstract String getFragment();
+    method @Nullable public abstract String getHost();
+    method @Nullable public abstract String getLastPathSegment();
+    method @Nullable public abstract String getPath();
     method public abstract java.util.List<java.lang.String> getPathSegments();
     method public abstract int getPort();
-    method public abstract java.lang.String getQuery();
-    method public java.lang.String getQueryParameter(java.lang.String);
+    method @Nullable public abstract String getQuery();
+    method @Nullable public String getQueryParameter(String);
     method public java.util.Set<java.lang.String> getQueryParameterNames();
-    method public java.util.List<java.lang.String> getQueryParameters(java.lang.String);
-    method public abstract java.lang.String getScheme();
-    method public abstract java.lang.String getSchemeSpecificPart();
-    method public abstract java.lang.String getUserInfo();
+    method public java.util.List<java.lang.String> getQueryParameters(String);
+    method @Nullable public abstract String getScheme();
+    method public abstract String getSchemeSpecificPart();
+    method @Nullable public abstract String getUserInfo();
     method public boolean isAbsolute();
     method public abstract boolean isHierarchical();
     method public boolean isOpaque();
     method public abstract boolean isRelative();
     method public android.net.Uri normalizeScheme();
-    method public static android.net.Uri parse(java.lang.String);
-    method public java.lang.String toSafeString();
-    method public abstract java.lang.String toString();
-    method public static android.net.Uri withAppendedPath(android.net.Uri, java.lang.String);
+    method public static android.net.Uri parse(String);
+    method public String toSafeString();
+    method public abstract String toString();
+    method public static android.net.Uri withAppendedPath(android.net.Uri, String);
     method public static void writeToParcel(android.os.Parcel, android.net.Uri);
     field public static final android.os.Parcelable.Creator<android.net.Uri> CREATOR;
     field public static final android.net.Uri EMPTY;
@@ -28819,28 +29097,28 @@
 
   public static final class Uri.Builder {
     ctor public Uri.Builder();
-    method public android.net.Uri.Builder appendEncodedPath(java.lang.String);
-    method public android.net.Uri.Builder appendPath(java.lang.String);
-    method public android.net.Uri.Builder appendQueryParameter(java.lang.String, java.lang.String);
-    method public android.net.Uri.Builder authority(java.lang.String);
+    method public android.net.Uri.Builder appendEncodedPath(String);
+    method public android.net.Uri.Builder appendPath(String);
+    method public android.net.Uri.Builder appendQueryParameter(String, String);
+    method public android.net.Uri.Builder authority(String);
     method public android.net.Uri build();
     method public android.net.Uri.Builder clearQuery();
-    method public android.net.Uri.Builder encodedAuthority(java.lang.String);
-    method public android.net.Uri.Builder encodedFragment(java.lang.String);
-    method public android.net.Uri.Builder encodedOpaquePart(java.lang.String);
-    method public android.net.Uri.Builder encodedPath(java.lang.String);
-    method public android.net.Uri.Builder encodedQuery(java.lang.String);
-    method public android.net.Uri.Builder fragment(java.lang.String);
-    method public android.net.Uri.Builder opaquePart(java.lang.String);
-    method public android.net.Uri.Builder path(java.lang.String);
-    method public android.net.Uri.Builder query(java.lang.String);
-    method public android.net.Uri.Builder scheme(java.lang.String);
+    method public android.net.Uri.Builder encodedAuthority(String);
+    method public android.net.Uri.Builder encodedFragment(String);
+    method public android.net.Uri.Builder encodedOpaquePart(String);
+    method public android.net.Uri.Builder encodedPath(String);
+    method public android.net.Uri.Builder encodedQuery(String);
+    method public android.net.Uri.Builder fragment(String);
+    method public android.net.Uri.Builder opaquePart(String);
+    method public android.net.Uri.Builder path(String);
+    method public android.net.Uri.Builder query(String);
+    method public android.net.Uri.Builder scheme(String);
   }
 
   public class UrlQuerySanitizer {
     ctor public UrlQuerySanitizer();
-    ctor public UrlQuerySanitizer(java.lang.String);
-    method protected void addSanitizedEntry(java.lang.String, java.lang.String);
+    ctor public UrlQuerySanitizer(String);
+    method protected void addSanitizedEntry(String, String);
     method protected void clear();
     method protected int decodeHexDigit(char);
     method public static final android.net.UrlQuerySanitizer.ValueSanitizer getAllButNulAndAngleBracketsLegal();
@@ -28850,7 +29128,7 @@
     method public boolean getAllowUnregisteredParamaters();
     method public static final android.net.UrlQuerySanitizer.ValueSanitizer getAmpAndSpaceLegal();
     method public static final android.net.UrlQuerySanitizer.ValueSanitizer getAmpLegal();
-    method public android.net.UrlQuerySanitizer.ValueSanitizer getEffectiveValueSanitizer(java.lang.String);
+    method public android.net.UrlQuerySanitizer.ValueSanitizer getEffectiveValueSanitizer(String);
     method public java.util.List<android.net.UrlQuerySanitizer.ParameterValuePair> getParameterList();
     method public java.util.Set<java.lang.String> getParameterSet();
     method public boolean getPreferFirstRepeatedParameter();
@@ -28858,24 +29136,24 @@
     method public android.net.UrlQuerySanitizer.ValueSanitizer getUnregisteredParameterValueSanitizer();
     method public static final android.net.UrlQuerySanitizer.ValueSanitizer getUrlAndSpaceLegal();
     method public static final android.net.UrlQuerySanitizer.ValueSanitizer getUrlLegal();
-    method public java.lang.String getValue(java.lang.String);
-    method public android.net.UrlQuerySanitizer.ValueSanitizer getValueSanitizer(java.lang.String);
-    method public boolean hasParameter(java.lang.String);
+    method public String getValue(String);
+    method public android.net.UrlQuerySanitizer.ValueSanitizer getValueSanitizer(String);
+    method public boolean hasParameter(String);
     method protected boolean isHexDigit(char);
-    method protected void parseEntry(java.lang.String, java.lang.String);
-    method public void parseQuery(java.lang.String);
-    method public void parseUrl(java.lang.String);
-    method public void registerParameter(java.lang.String, android.net.UrlQuerySanitizer.ValueSanitizer);
-    method public void registerParameters(java.lang.String[], android.net.UrlQuerySanitizer.ValueSanitizer);
+    method protected void parseEntry(String, String);
+    method public void parseQuery(String);
+    method public void parseUrl(String);
+    method public void registerParameter(String, android.net.UrlQuerySanitizer.ValueSanitizer);
+    method public void registerParameters(String[], android.net.UrlQuerySanitizer.ValueSanitizer);
     method public void setAllowUnregisteredParamaters(boolean);
     method public void setPreferFirstRepeatedParameter(boolean);
     method public void setUnregisteredParameterValueSanitizer(android.net.UrlQuerySanitizer.ValueSanitizer);
-    method public java.lang.String unescape(java.lang.String);
+    method public String unescape(String);
   }
 
   public static class UrlQuerySanitizer.IllegalCharacterValueSanitizer implements android.net.UrlQuerySanitizer.ValueSanitizer {
     ctor public UrlQuerySanitizer.IllegalCharacterValueSanitizer(int);
-    method public java.lang.String sanitize(java.lang.String);
+    method public String sanitize(String);
     field public static final int ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL = 1439; // 0x59f
     field public static final int ALL_BUT_NUL_LEGAL = 1535; // 0x5ff
     field public static final int ALL_BUT_WHITESPACE_LEGAL = 1532; // 0x5fc
@@ -28901,17 +29179,19 @@
   }
 
   public class UrlQuerySanitizer.ParameterValuePair {
-    ctor public UrlQuerySanitizer.ParameterValuePair(java.lang.String, java.lang.String);
-    field public java.lang.String mParameter;
-    field public java.lang.String mValue;
+    ctor public UrlQuerySanitizer.ParameterValuePair(String, String);
+    field public String mParameter;
+    field public String mValue;
   }
 
-  public static abstract interface UrlQuerySanitizer.ValueSanitizer {
-    method public abstract java.lang.String sanitize(java.lang.String);
+  public static interface UrlQuerySanitizer.ValueSanitizer {
+    method public String sanitize(String);
   }
 
   public class VpnService extends android.app.Service {
     ctor public VpnService();
+    method public final boolean isAlwaysOn();
+    method public final boolean isLockdownEnabled();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onRevoke();
     method public static android.content.Intent prepare(android.content.Context);
@@ -28919,28 +29199,28 @@
     method public boolean protect(java.net.Socket);
     method public boolean protect(java.net.DatagramSocket);
     method public boolean setUnderlyingNetworks(android.net.Network[]);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.net.VpnService";
-    field public static final java.lang.String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
+    field public static final String SERVICE_INTERFACE = "android.net.VpnService";
+    field public static final String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
   }
 
   public class VpnService.Builder {
     ctor public VpnService.Builder();
     method public android.net.VpnService.Builder addAddress(java.net.InetAddress, int);
-    method public android.net.VpnService.Builder addAddress(java.lang.String, int);
-    method public android.net.VpnService.Builder addAllowedApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.net.VpnService.Builder addDisallowedApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public android.net.VpnService.Builder addAddress(String, int);
+    method public android.net.VpnService.Builder addAllowedApplication(String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public android.net.VpnService.Builder addDisallowedApplication(String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.net.VpnService.Builder addDnsServer(java.net.InetAddress);
-    method public android.net.VpnService.Builder addDnsServer(java.lang.String);
+    method public android.net.VpnService.Builder addDnsServer(String);
     method public android.net.VpnService.Builder addRoute(java.net.InetAddress, int);
-    method public android.net.VpnService.Builder addRoute(java.lang.String, int);
-    method public android.net.VpnService.Builder addSearchDomain(java.lang.String);
+    method public android.net.VpnService.Builder addRoute(String, int);
+    method public android.net.VpnService.Builder addSearchDomain(String);
     method public android.net.VpnService.Builder allowBypass();
     method public android.net.VpnService.Builder allowFamily(int);
     method public android.os.ParcelFileDescriptor establish();
     method public android.net.VpnService.Builder setBlocking(boolean);
     method public android.net.VpnService.Builder setConfigureIntent(android.app.PendingIntent);
     method public android.net.VpnService.Builder setMtu(int);
-    method public android.net.VpnService.Builder setSession(java.lang.String);
+    method public android.net.VpnService.Builder setSession(String);
     method public android.net.VpnService.Builder setUnderlyingNetworks(android.net.Network[]);
   }
 
@@ -28952,26 +29232,26 @@
     method public void close() throws java.io.IOException;
     method public void delete() throws java.io.IOException;
     method public void flush();
-    method public java.net.CacheResponse get(java.net.URI, java.lang.String, java.util.Map<java.lang.String, java.util.List<java.lang.String>>) throws java.io.IOException;
+    method public java.net.CacheResponse get(java.net.URI, String, java.util.Map<java.lang.String,java.util.List<java.lang.String>>) throws java.io.IOException;
     method public int getHitCount();
     method public static android.net.http.HttpResponseCache getInstalled();
     method public int getNetworkCount();
     method public int getRequestCount();
-    method public static synchronized android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
+    method public static android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
     method public long maxSize();
     method public java.net.CacheRequest put(java.net.URI, java.net.URLConnection) throws java.io.IOException;
     method public long size();
   }
 
   public class SslCertificate {
-    ctor public deprecated SslCertificate(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    ctor public deprecated SslCertificate(java.lang.String, java.lang.String, java.util.Date, java.util.Date);
+    ctor @Deprecated public SslCertificate(String, String, String, String);
+    ctor @Deprecated public SslCertificate(String, String, java.util.Date, java.util.Date);
     ctor public SslCertificate(java.security.cert.X509Certificate);
     method public android.net.http.SslCertificate.DName getIssuedBy();
     method public android.net.http.SslCertificate.DName getIssuedTo();
-    method public deprecated java.lang.String getValidNotAfter();
+    method @Deprecated public String getValidNotAfter();
     method public java.util.Date getValidNotAfterDate();
-    method public deprecated java.lang.String getValidNotBefore();
+    method @Deprecated public String getValidNotBefore();
     method public java.util.Date getValidNotBeforeDate();
     method public java.security.cert.X509Certificate getX509Certificate();
     method public static android.net.http.SslCertificate restoreState(android.os.Bundle);
@@ -28979,36 +29259,36 @@
   }
 
   public class SslCertificate.DName {
-    ctor public SslCertificate.DName(java.lang.String);
-    method public java.lang.String getCName();
-    method public java.lang.String getDName();
-    method public java.lang.String getOName();
-    method public java.lang.String getUName();
+    ctor public SslCertificate.DName(String);
+    method public String getCName();
+    method public String getDName();
+    method public String getOName();
+    method public String getUName();
   }
 
   public class SslError {
-    ctor public deprecated SslError(int, android.net.http.SslCertificate);
-    ctor public deprecated SslError(int, java.security.cert.X509Certificate);
-    ctor public SslError(int, android.net.http.SslCertificate, java.lang.String);
-    ctor public SslError(int, java.security.cert.X509Certificate, java.lang.String);
+    ctor @Deprecated public SslError(int, android.net.http.SslCertificate);
+    ctor @Deprecated public SslError(int, java.security.cert.X509Certificate);
+    ctor public SslError(int, android.net.http.SslCertificate, String);
+    ctor public SslError(int, java.security.cert.X509Certificate, String);
     method public boolean addError(int);
     method public android.net.http.SslCertificate getCertificate();
     method public int getPrimaryError();
-    method public java.lang.String getUrl();
+    method public String getUrl();
     method public boolean hasError(int);
     field public static final int SSL_DATE_INVALID = 4; // 0x4
     field public static final int SSL_EXPIRED = 1; // 0x1
     field public static final int SSL_IDMISMATCH = 2; // 0x2
     field public static final int SSL_INVALID = 5; // 0x5
-    field public static final deprecated int SSL_MAX_ERROR = 6; // 0x6
+    field @Deprecated public static final int SSL_MAX_ERROR = 6; // 0x6
     field public static final int SSL_NOTYETVALID = 0; // 0x0
     field public static final int SSL_UNTRUSTED = 3; // 0x3
   }
 
   public class X509TrustManagerExtensions {
     ctor public X509TrustManagerExtensions(javax.net.ssl.X509TrustManager) throws java.lang.IllegalArgumentException;
-    method public java.util.List<java.security.cert.X509Certificate> checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, java.lang.String) throws java.security.cert.CertificateException;
-    method public boolean isSameTrustConfiguration(java.lang.String, java.lang.String);
+    method public java.util.List<java.security.cert.X509Certificate> checkServerTrusted(java.security.cert.X509Certificate[], String, String) throws java.security.cert.CertificateException;
+    method public boolean isSameTrustConfiguration(String, String);
     method public boolean isUserAddedCertificate(java.security.cert.X509Certificate);
   }
 
@@ -29017,13 +29297,13 @@
 package android.net.nsd {
 
   public final class NsdManager {
-    method public void discoverServices(java.lang.String, int, android.net.nsd.NsdManager.DiscoveryListener);
+    method public void discoverServices(String, int, android.net.nsd.NsdManager.DiscoveryListener);
     method public void registerService(android.net.nsd.NsdServiceInfo, int, android.net.nsd.NsdManager.RegistrationListener);
     method public void resolveService(android.net.nsd.NsdServiceInfo, android.net.nsd.NsdManager.ResolveListener);
     method public void stopServiceDiscovery(android.net.nsd.NsdManager.DiscoveryListener);
     method public void unregisterService(android.net.nsd.NsdManager.RegistrationListener);
-    field public static final java.lang.String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED";
-    field public static final java.lang.String EXTRA_NSD_STATE = "nsd_state";
+    field public static final String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED";
+    field public static final String EXTRA_NSD_STATE = "nsd_state";
     field public static final int FAILURE_ALREADY_ACTIVE = 3; // 0x3
     field public static final int FAILURE_INTERNAL_ERROR = 0; // 0x0
     field public static final int FAILURE_MAX_LIMIT = 4; // 0x4
@@ -29032,41 +29312,41 @@
     field public static final int PROTOCOL_DNS_SD = 1; // 0x1
   }
 
-  public static abstract interface NsdManager.DiscoveryListener {
-    method public abstract void onDiscoveryStarted(java.lang.String);
-    method public abstract void onDiscoveryStopped(java.lang.String);
-    method public abstract void onServiceFound(android.net.nsd.NsdServiceInfo);
-    method public abstract void onServiceLost(android.net.nsd.NsdServiceInfo);
-    method public abstract void onStartDiscoveryFailed(java.lang.String, int);
-    method public abstract void onStopDiscoveryFailed(java.lang.String, int);
+  public static interface NsdManager.DiscoveryListener {
+    method public void onDiscoveryStarted(String);
+    method public void onDiscoveryStopped(String);
+    method public void onServiceFound(android.net.nsd.NsdServiceInfo);
+    method public void onServiceLost(android.net.nsd.NsdServiceInfo);
+    method public void onStartDiscoveryFailed(String, int);
+    method public void onStopDiscoveryFailed(String, int);
   }
 
-  public static abstract interface NsdManager.RegistrationListener {
-    method public abstract void onRegistrationFailed(android.net.nsd.NsdServiceInfo, int);
-    method public abstract void onServiceRegistered(android.net.nsd.NsdServiceInfo);
-    method public abstract void onServiceUnregistered(android.net.nsd.NsdServiceInfo);
-    method public abstract void onUnregistrationFailed(android.net.nsd.NsdServiceInfo, int);
+  public static interface NsdManager.RegistrationListener {
+    method public void onRegistrationFailed(android.net.nsd.NsdServiceInfo, int);
+    method public void onServiceRegistered(android.net.nsd.NsdServiceInfo);
+    method public void onServiceUnregistered(android.net.nsd.NsdServiceInfo);
+    method public void onUnregistrationFailed(android.net.nsd.NsdServiceInfo, int);
   }
 
-  public static abstract interface NsdManager.ResolveListener {
-    method public abstract void onResolveFailed(android.net.nsd.NsdServiceInfo, int);
-    method public abstract void onServiceResolved(android.net.nsd.NsdServiceInfo);
+  public static interface NsdManager.ResolveListener {
+    method public void onResolveFailed(android.net.nsd.NsdServiceInfo, int);
+    method public void onServiceResolved(android.net.nsd.NsdServiceInfo);
   }
 
   public final class NsdServiceInfo implements android.os.Parcelable {
     ctor public NsdServiceInfo();
     method public int describeContents();
-    method public java.util.Map<java.lang.String, byte[]> getAttributes();
+    method public java.util.Map<java.lang.String,byte[]> getAttributes();
     method public java.net.InetAddress getHost();
     method public int getPort();
-    method public java.lang.String getServiceName();
-    method public java.lang.String getServiceType();
-    method public void removeAttribute(java.lang.String);
-    method public void setAttribute(java.lang.String, java.lang.String);
+    method public String getServiceName();
+    method public String getServiceType();
+    method public void removeAttribute(String);
+    method public void setAttribute(String, String);
     method public void setHost(java.net.InetAddress);
     method public void setPort(int);
-    method public void setServiceName(java.lang.String);
-    method public void setServiceType(java.lang.String);
+    method public void setServiceName(String);
+    method public void setServiceType(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.nsd.NsdServiceInfo> CREATOR;
   }
@@ -29076,15 +29356,15 @@
 package android.net.rtp {
 
   public class AudioCodec {
-    method public static android.net.rtp.AudioCodec getCodec(int, java.lang.String, java.lang.String);
+    method public static android.net.rtp.AudioCodec getCodec(int, String, String);
     method public static android.net.rtp.AudioCodec[] getCodecs();
     field public static final android.net.rtp.AudioCodec AMR;
     field public static final android.net.rtp.AudioCodec GSM;
     field public static final android.net.rtp.AudioCodec GSM_EFR;
     field public static final android.net.rtp.AudioCodec PCMA;
     field public static final android.net.rtp.AudioCodec PCMU;
-    field public final java.lang.String fmtp;
-    field public final java.lang.String rtpmap;
+    field public final String fmtp;
+    field public final String rtpmap;
     field public final int type;
   }
 
@@ -29134,7 +29414,7 @@
   public class SipAudioCall {
     ctor public SipAudioCall(android.content.Context, android.net.sip.SipProfile);
     method public void answerCall(int) throws android.net.sip.SipException;
-    method public void attachCall(android.net.sip.SipSession, java.lang.String) throws android.net.sip.SipException;
+    method public void attachCall(android.net.sip.SipSession, String) throws android.net.sip.SipException;
     method public void close();
     method public void continueCall(int) throws android.net.sip.SipException;
     method public void endCall() throws android.net.sip.SipException;
@@ -29163,14 +29443,14 @@
     method public void onCallHeld(android.net.sip.SipAudioCall);
     method public void onCalling(android.net.sip.SipAudioCall);
     method public void onChanged(android.net.sip.SipAudioCall);
-    method public void onError(android.net.sip.SipAudioCall, int, java.lang.String);
+    method public void onError(android.net.sip.SipAudioCall, int, String);
     method public void onReadyToCall(android.net.sip.SipAudioCall);
     method public void onRinging(android.net.sip.SipAudioCall, android.net.sip.SipProfile);
     method public void onRingingBack(android.net.sip.SipAudioCall);
   }
 
   public class SipErrorCode {
-    method public static java.lang.String toString(int);
+    method public static String toString(int);
     field public static final int CLIENT_ERROR = -4; // 0xfffffffc
     field public static final int CROSS_DOMAIN_AUTHENTICATION = -11; // 0xfffffff5
     field public static final int DATA_CONNECTION_LOST = -10; // 0xfffffff6
@@ -29188,87 +29468,87 @@
 
   public class SipException extends java.lang.Exception {
     ctor public SipException();
-    ctor public SipException(java.lang.String);
-    ctor public SipException(java.lang.String, java.lang.Throwable);
+    ctor public SipException(String);
+    ctor public SipException(String, Throwable);
   }
 
   public class SipManager {
-    method public void close(java.lang.String) throws android.net.sip.SipException;
+    method public void close(String) throws android.net.sip.SipException;
     method public android.net.sip.SipSession createSipSession(android.net.sip.SipProfile, android.net.sip.SipSession.Listener) throws android.net.sip.SipException;
-    method public static java.lang.String getCallId(android.content.Intent);
-    method public static java.lang.String getOfferSessionDescription(android.content.Intent);
+    method public static String getCallId(android.content.Intent);
+    method public static String getOfferSessionDescription(android.content.Intent);
     method public android.net.sip.SipSession getSessionFor(android.content.Intent) throws android.net.sip.SipException;
     method public static boolean isApiSupported(android.content.Context);
     method public static boolean isIncomingCallIntent(android.content.Intent);
-    method public boolean isOpened(java.lang.String) throws android.net.sip.SipException;
-    method public boolean isRegistered(java.lang.String) throws android.net.sip.SipException;
+    method public boolean isOpened(String) throws android.net.sip.SipException;
+    method public boolean isRegistered(String) throws android.net.sip.SipException;
     method public static boolean isSipWifiOnly(android.content.Context);
     method public static boolean isVoipSupported(android.content.Context);
     method public android.net.sip.SipAudioCall makeAudioCall(android.net.sip.SipProfile, android.net.sip.SipProfile, android.net.sip.SipAudioCall.Listener, int) throws android.net.sip.SipException;
-    method public android.net.sip.SipAudioCall makeAudioCall(java.lang.String, java.lang.String, android.net.sip.SipAudioCall.Listener, int) throws android.net.sip.SipException;
+    method public android.net.sip.SipAudioCall makeAudioCall(String, String, android.net.sip.SipAudioCall.Listener, int) throws android.net.sip.SipException;
     method public static android.net.sip.SipManager newInstance(android.content.Context);
     method public void open(android.net.sip.SipProfile) throws android.net.sip.SipException;
     method public void open(android.net.sip.SipProfile, android.app.PendingIntent, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
     method public void register(android.net.sip.SipProfile, int, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
-    method public void setRegistrationListener(java.lang.String, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
+    method public void setRegistrationListener(String, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
     method public android.net.sip.SipAudioCall takeAudioCall(android.content.Intent, android.net.sip.SipAudioCall.Listener) throws android.net.sip.SipException;
     method public void unregister(android.net.sip.SipProfile, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
-    field public static final java.lang.String EXTRA_CALL_ID = "android:sipCallID";
-    field public static final java.lang.String EXTRA_OFFER_SD = "android:sipOfferSD";
+    field public static final String EXTRA_CALL_ID = "android:sipCallID";
+    field public static final String EXTRA_OFFER_SD = "android:sipOfferSD";
     field public static final int INCOMING_CALL_RESULT_CODE = 101; // 0x65
   }
 
   public class SipProfile implements java.lang.Cloneable android.os.Parcelable java.io.Serializable {
     method public int describeContents();
-    method public java.lang.String getAuthUserName();
+    method public String getAuthUserName();
     method public boolean getAutoRegistration();
-    method public java.lang.String getDisplayName();
-    method public java.lang.String getPassword();
+    method public String getDisplayName();
+    method public String getPassword();
     method public int getPort();
-    method public java.lang.String getProfileName();
-    method public java.lang.String getProtocol();
-    method public java.lang.String getProxyAddress();
+    method public String getProfileName();
+    method public String getProtocol();
+    method public String getProxyAddress();
     method public boolean getSendKeepAlive();
-    method public java.lang.String getSipDomain();
-    method public java.lang.String getUriString();
-    method public java.lang.String getUserName();
+    method public String getSipDomain();
+    method public String getUriString();
+    method public String getUserName();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.sip.SipProfile> CREATOR;
   }
 
   public static class SipProfile.Builder {
     ctor public SipProfile.Builder(android.net.sip.SipProfile);
-    ctor public SipProfile.Builder(java.lang.String) throws java.text.ParseException;
-    ctor public SipProfile.Builder(java.lang.String, java.lang.String) throws java.text.ParseException;
+    ctor public SipProfile.Builder(String) throws java.text.ParseException;
+    ctor public SipProfile.Builder(String, String) throws java.text.ParseException;
     method public android.net.sip.SipProfile build();
-    method public android.net.sip.SipProfile.Builder setAuthUserName(java.lang.String);
+    method public android.net.sip.SipProfile.Builder setAuthUserName(String);
     method public android.net.sip.SipProfile.Builder setAutoRegistration(boolean);
-    method public android.net.sip.SipProfile.Builder setDisplayName(java.lang.String);
-    method public android.net.sip.SipProfile.Builder setOutboundProxy(java.lang.String);
-    method public android.net.sip.SipProfile.Builder setPassword(java.lang.String);
+    method public android.net.sip.SipProfile.Builder setDisplayName(String);
+    method public android.net.sip.SipProfile.Builder setOutboundProxy(String);
+    method public android.net.sip.SipProfile.Builder setPassword(String);
     method public android.net.sip.SipProfile.Builder setPort(int) throws java.lang.IllegalArgumentException;
-    method public android.net.sip.SipProfile.Builder setProfileName(java.lang.String);
-    method public android.net.sip.SipProfile.Builder setProtocol(java.lang.String) throws java.lang.IllegalArgumentException;
+    method public android.net.sip.SipProfile.Builder setProfileName(String);
+    method public android.net.sip.SipProfile.Builder setProtocol(String) throws java.lang.IllegalArgumentException;
     method public android.net.sip.SipProfile.Builder setSendKeepAlive(boolean);
   }
 
-  public abstract interface SipRegistrationListener {
-    method public abstract void onRegistering(java.lang.String);
-    method public abstract void onRegistrationDone(java.lang.String, long);
-    method public abstract void onRegistrationFailed(java.lang.String, int, java.lang.String);
+  public interface SipRegistrationListener {
+    method public void onRegistering(String);
+    method public void onRegistrationDone(String, long);
+    method public void onRegistrationFailed(String, int, String);
   }
 
   public final class SipSession {
-    method public void answerCall(java.lang.String, int);
-    method public void changeCall(java.lang.String, int);
+    method public void answerCall(String, int);
+    method public void changeCall(String, int);
     method public void endCall();
-    method public java.lang.String getCallId();
-    method public java.lang.String getLocalIp();
+    method public String getCallId();
+    method public String getLocalIp();
     method public android.net.sip.SipProfile getLocalProfile();
     method public android.net.sip.SipProfile getPeerProfile();
     method public int getState();
     method public boolean isInCall();
-    method public void makeCall(android.net.sip.SipProfile, java.lang.String, int);
+    method public void makeCall(android.net.sip.SipProfile, String, int);
     method public void register(int);
     method public void setListener(android.net.sip.SipSession.Listener);
     method public void unregister();
@@ -29277,21 +29557,21 @@
   public static class SipSession.Listener {
     ctor public SipSession.Listener();
     method public void onCallBusy(android.net.sip.SipSession);
-    method public void onCallChangeFailed(android.net.sip.SipSession, int, java.lang.String);
+    method public void onCallChangeFailed(android.net.sip.SipSession, int, String);
     method public void onCallEnded(android.net.sip.SipSession);
-    method public void onCallEstablished(android.net.sip.SipSession, java.lang.String);
+    method public void onCallEstablished(android.net.sip.SipSession, String);
     method public void onCalling(android.net.sip.SipSession);
-    method public void onError(android.net.sip.SipSession, int, java.lang.String);
+    method public void onError(android.net.sip.SipSession, int, String);
     method public void onRegistering(android.net.sip.SipSession);
     method public void onRegistrationDone(android.net.sip.SipSession, int);
-    method public void onRegistrationFailed(android.net.sip.SipSession, int, java.lang.String);
+    method public void onRegistrationFailed(android.net.sip.SipSession, int, String);
     method public void onRegistrationTimeout(android.net.sip.SipSession);
-    method public void onRinging(android.net.sip.SipSession, android.net.sip.SipProfile, java.lang.String);
+    method public void onRinging(android.net.sip.SipSession, android.net.sip.SipProfile, String);
     method public void onRingingBack(android.net.sip.SipSession);
   }
 
   public static class SipSession.State {
-    method public static java.lang.String toString(int);
+    method public static String toString(int);
     field public static final int DEREGISTERING = 2; // 0x2
     field public static final int INCOMING_CALL = 3; // 0x3
     field public static final int INCOMING_CALL_ANSWERING = 4; // 0x4
@@ -29310,13 +29590,13 @@
 package android.net.ssl {
 
   public class SSLEngines {
-    method public static boolean isSupportedEngine(javax.net.ssl.SSLEngine);
-    method public static void setUseSessionTickets(javax.net.ssl.SSLEngine, boolean);
+    method public static boolean isSupportedEngine(@NonNull javax.net.ssl.SSLEngine);
+    method public static void setUseSessionTickets(@NonNull javax.net.ssl.SSLEngine, boolean);
   }
 
   public class SSLSockets {
-    method public static boolean isSupportedSocket(javax.net.ssl.SSLSocket);
-    method public static void setUseSessionTickets(javax.net.ssl.SSLSocket, boolean);
+    method public static boolean isSupportedSocket(@NonNull javax.net.ssl.SSLSocket);
+    method public static void setUseSessionTickets(@NonNull javax.net.ssl.SSLSocket, boolean);
   }
 
 }
@@ -29328,29 +29608,27 @@
     method public boolean is80211mcResponder();
     method public boolean isPasspointNetwork();
     method public void writeToParcel(android.os.Parcel, int);
-    field public java.lang.String BSSID;
+    field public String BSSID;
     field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3
     field public static final int CHANNEL_WIDTH_20MHZ = 0; // 0x0
     field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1
     field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2
     field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4
-    field public java.lang.String SSID;
-    field public java.lang.String capabilities;
+    field public String SSID;
+    field public String capabilities;
     field public int centerFreq0;
     field public int centerFreq1;
     field public int channelWidth;
     field public int frequency;
     field public int level;
-    field public java.lang.CharSequence operatorFriendlyName;
+    field public CharSequence operatorFriendlyName;
     field public long timestamp;
-    field public java.lang.CharSequence venueName;
+    field public CharSequence venueName;
   }
 
-  public final class SupplicantState extends java.lang.Enum implements android.os.Parcelable {
+  public enum SupplicantState implements android.os.Parcelable {
     method public int describeContents();
     method public static boolean isValidState(android.net.wifi.SupplicantState);
-    method public static android.net.wifi.SupplicantState valueOf(java.lang.String);
-    method public static final android.net.wifi.SupplicantState[] values();
     method public void writeToParcel(android.os.Parcel, int);
     enum_constant public static final android.net.wifi.SupplicantState ASSOCIATED;
     enum_constant public static final android.net.wifi.SupplicantState ASSOCIATING;
@@ -29367,127 +29645,128 @@
     enum_constant public static final android.net.wifi.SupplicantState UNINITIALIZED;
   }
 
-  public deprecated class WifiConfiguration implements android.os.Parcelable {
-    ctor public WifiConfiguration();
+  @Deprecated public class WifiConfiguration implements android.os.Parcelable {
+    ctor @Deprecated public WifiConfiguration();
     method public int describeContents();
-    method public android.net.ProxyInfo getHttpProxy();
-    method public boolean isPasspoint();
-    method public void setHttpProxy(android.net.ProxyInfo);
+    method @Deprecated public android.net.ProxyInfo getHttpProxy();
+    method @Deprecated @NonNull public android.net.MacAddress getRandomizedMacAddress();
+    method @Deprecated public boolean isPasspoint();
+    method @Deprecated public void setHttpProxy(android.net.ProxyInfo);
     method public void writeToParcel(android.os.Parcel, int);
-    field public java.lang.String BSSID;
-    field public java.lang.String FQDN;
-    field public java.lang.String SSID;
-    field public java.util.BitSet allowedAuthAlgorithms;
-    field public java.util.BitSet allowedGroupCiphers;
-    field public java.util.BitSet allowedGroupMgmtCiphers;
-    field public java.util.BitSet allowedKeyManagement;
-    field public java.util.BitSet allowedPairwiseCiphers;
-    field public java.util.BitSet allowedProtocols;
-    field public java.util.BitSet allowedSuiteBCiphers;
-    field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
-    field public boolean hiddenSSID;
-    field public boolean isHomeProviderNetwork;
-    field public int networkId;
-    field public java.lang.String preSharedKey;
-    field public deprecated int priority;
-    field public java.lang.String providerFriendlyName;
-    field public long[] roamingConsortiumIds;
-    field public int status;
-    field public deprecated java.lang.String[] wepKeys;
-    field public deprecated int wepTxKeyIndex;
+    field @Deprecated public String BSSID;
+    field @Deprecated public String FQDN;
+    field @Deprecated public String SSID;
+    field @Deprecated public java.util.BitSet allowedAuthAlgorithms;
+    field @Deprecated public java.util.BitSet allowedGroupCiphers;
+    field @Deprecated public java.util.BitSet allowedGroupManagementCiphers;
+    field @Deprecated public java.util.BitSet allowedKeyManagement;
+    field @Deprecated public java.util.BitSet allowedPairwiseCiphers;
+    field @Deprecated public java.util.BitSet allowedProtocols;
+    field @Deprecated public java.util.BitSet allowedSuiteBCiphers;
+    field @Deprecated public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
+    field @Deprecated public boolean hiddenSSID;
+    field @Deprecated public boolean isHomeProviderNetwork;
+    field @Deprecated public int networkId;
+    field @Deprecated public String preSharedKey;
+    field @Deprecated public int priority;
+    field @Deprecated public String providerFriendlyName;
+    field @Deprecated public long[] roamingConsortiumIds;
+    field @Deprecated public int status;
+    field @Deprecated public String[] wepKeys;
+    field @Deprecated public int wepTxKeyIndex;
   }
 
-  public static class WifiConfiguration.AuthAlgorithm {
-    field public static final int LEAP = 2; // 0x2
-    field public static final int OPEN = 0; // 0x0
-    field public static final deprecated int SHARED = 1; // 0x1
-    field public static final java.lang.String[] strings;
-    field public static final java.lang.String varName = "auth_alg";
+  @Deprecated public static class WifiConfiguration.AuthAlgorithm {
+    field @Deprecated public static final int LEAP = 2; // 0x2
+    field @Deprecated public static final int OPEN = 0; // 0x0
+    field @Deprecated public static final int SHARED = 1; // 0x1
+    field @Deprecated public static final String[] strings;
+    field @Deprecated public static final String varName = "auth_alg";
   }
 
-  public static class WifiConfiguration.GroupCipher {
-    field public static final int CCMP = 3; // 0x3
-    field public static final int GCMP_256 = 5; // 0x5
-    field public static final int TKIP = 2; // 0x2
-    field public static final deprecated int WEP104 = 1; // 0x1
-    field public static final deprecated int WEP40 = 0; // 0x0
-    field public static final java.lang.String[] strings;
-    field public static final java.lang.String varName = "group";
+  @Deprecated public static class WifiConfiguration.GroupCipher {
+    field @Deprecated public static final int CCMP = 3; // 0x3
+    field @Deprecated public static final int GCMP_256 = 5; // 0x5
+    field @Deprecated public static final int TKIP = 2; // 0x2
+    field @Deprecated public static final int WEP104 = 1; // 0x1
+    field @Deprecated public static final int WEP40 = 0; // 0x0
+    field @Deprecated public static final String[] strings;
+    field @Deprecated public static final String varName = "group";
   }
 
-  public static class WifiConfiguration.GroupMgmtCipher {
-    field public static final int BIP_CMAC_256 = 0; // 0x0
-    field public static final int BIP_GMAC_128 = 1; // 0x1
-    field public static final int BIP_GMAC_256 = 2; // 0x2
+  @Deprecated public static class WifiConfiguration.GroupMgmtCipher {
+    field @Deprecated public static final int BIP_CMAC_256 = 0; // 0x0
+    field @Deprecated public static final int BIP_GMAC_128 = 1; // 0x1
+    field @Deprecated public static final int BIP_GMAC_256 = 2; // 0x2
   }
 
-  public static class WifiConfiguration.KeyMgmt {
-    field public static final int IEEE8021X = 3; // 0x3
-    field public static final int NONE = 0; // 0x0
-    field public static final int OWE = 9; // 0x9
-    field public static final int SAE = 8; // 0x8
-    field public static final int SUITE_B_192 = 10; // 0xa
-    field public static final int WPA_EAP = 2; // 0x2
-    field public static final int WPA_PSK = 1; // 0x1
-    field public static final java.lang.String[] strings;
-    field public static final java.lang.String varName = "key_mgmt";
+  @Deprecated public static class WifiConfiguration.KeyMgmt {
+    field @Deprecated public static final int IEEE8021X = 3; // 0x3
+    field @Deprecated public static final int NONE = 0; // 0x0
+    field @Deprecated public static final int OWE = 9; // 0x9
+    field @Deprecated public static final int SAE = 8; // 0x8
+    field @Deprecated public static final int SUITE_B_192 = 10; // 0xa
+    field @Deprecated public static final int WPA_EAP = 2; // 0x2
+    field @Deprecated public static final int WPA_PSK = 1; // 0x1
+    field @Deprecated public static final String[] strings;
+    field @Deprecated public static final String varName = "key_mgmt";
   }
 
-  public static class WifiConfiguration.PairwiseCipher {
-    field public static final int CCMP = 2; // 0x2
-    field public static final int GCMP_256 = 3; // 0x3
-    field public static final int NONE = 0; // 0x0
-    field public static final deprecated int TKIP = 1; // 0x1
-    field public static final java.lang.String[] strings;
-    field public static final java.lang.String varName = "pairwise";
+  @Deprecated public static class WifiConfiguration.PairwiseCipher {
+    field @Deprecated public static final int CCMP = 2; // 0x2
+    field @Deprecated public static final int GCMP_256 = 3; // 0x3
+    field @Deprecated public static final int NONE = 0; // 0x0
+    field @Deprecated public static final int TKIP = 1; // 0x1
+    field @Deprecated public static final String[] strings;
+    field @Deprecated public static final String varName = "pairwise";
   }
 
-  public static class WifiConfiguration.Protocol {
-    field public static final int RSN = 1; // 0x1
-    field public static final deprecated int WPA = 0; // 0x0
-    field public static final java.lang.String[] strings;
-    field public static final java.lang.String varName = "proto";
+  @Deprecated public static class WifiConfiguration.Protocol {
+    field @Deprecated public static final int RSN = 1; // 0x1
+    field @Deprecated public static final int WPA = 0; // 0x0
+    field @Deprecated public static final String[] strings;
+    field @Deprecated public static final String varName = "proto";
   }
 
-  public static class WifiConfiguration.Status {
-    field public static final int CURRENT = 0; // 0x0
-    field public static final int DISABLED = 1; // 0x1
-    field public static final int ENABLED = 2; // 0x2
-    field public static final java.lang.String[] strings;
+  @Deprecated public static class WifiConfiguration.Status {
+    field @Deprecated public static final int CURRENT = 0; // 0x0
+    field @Deprecated public static final int DISABLED = 1; // 0x1
+    field @Deprecated public static final int ENABLED = 2; // 0x2
+    field @Deprecated public static final String[] strings;
   }
 
   public class WifiEnterpriseConfig implements android.os.Parcelable {
     ctor public WifiEnterpriseConfig();
     ctor public WifiEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
     method public int describeContents();
-    method public java.lang.String getAltSubjectMatch();
-    method public java.lang.String getAnonymousIdentity();
-    method public java.security.cert.X509Certificate getCaCertificate();
-    method public java.security.cert.X509Certificate[] getCaCertificates();
+    method public String getAltSubjectMatch();
+    method public String getAnonymousIdentity();
+    method @Nullable public java.security.cert.X509Certificate getCaCertificate();
+    method @Nullable public java.security.cert.X509Certificate[] getCaCertificates();
     method public java.security.cert.X509Certificate getClientCertificate();
-    method public java.security.cert.X509Certificate[] getClientCertificateChain();
-    method public java.lang.String getDomainSuffixMatch();
+    method @Nullable public java.security.cert.X509Certificate[] getClientCertificateChain();
+    method public String getDomainSuffixMatch();
     method public int getEapMethod();
-    method public java.lang.String getIdentity();
-    method public java.lang.String getPassword();
+    method public String getIdentity();
+    method public String getPassword();
     method public int getPhase2Method();
-    method public java.lang.String getPlmn();
-    method public java.lang.String getRealm();
-    method public deprecated java.lang.String getSubjectMatch();
-    method public void setAltSubjectMatch(java.lang.String);
-    method public void setAnonymousIdentity(java.lang.String);
-    method public void setCaCertificate(java.security.cert.X509Certificate);
-    method public void setCaCertificates(java.security.cert.X509Certificate[]);
+    method public String getPlmn();
+    method public String getRealm();
+    method @Deprecated public String getSubjectMatch();
+    method public void setAltSubjectMatch(String);
+    method public void setAnonymousIdentity(String);
+    method public void setCaCertificate(@Nullable java.security.cert.X509Certificate);
+    method public void setCaCertificates(@Nullable java.security.cert.X509Certificate[]);
     method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
     method public void setClientKeyEntryWithCertificateChain(java.security.PrivateKey, java.security.cert.X509Certificate[]);
-    method public void setDomainSuffixMatch(java.lang.String);
+    method public void setDomainSuffixMatch(String);
     method public void setEapMethod(int);
-    method public void setIdentity(java.lang.String);
-    method public void setPassword(java.lang.String);
+    method public void setIdentity(String);
+    method public void setPassword(String);
     method public void setPhase2Method(int);
-    method public void setPlmn(java.lang.String);
-    method public void setRealm(java.lang.String);
-    method public deprecated void setSubjectMatch(java.lang.String);
+    method public void setPlmn(String);
+    method public void setRealm(String);
+    method @Deprecated public void setSubjectMatch(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.wifi.WifiEnterpriseConfig> CREATOR;
   }
@@ -29517,110 +29796,112 @@
 
   public class WifiInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getBSSID();
+    method public String getBSSID();
     method public static android.net.NetworkInfo.DetailedState getDetailedStateOf(android.net.wifi.SupplicantState);
     method public int getFrequency();
     method public boolean getHiddenSSID();
     method public int getIpAddress();
     method public int getLinkSpeed();
-    method public java.lang.String getMacAddress();
+    method public String getMacAddress();
     method public int getNetworkId();
     method public int getRssi();
-    method public java.lang.String getSSID();
+    method public int getRxLinkSpeedMbps();
+    method public String getSSID();
     method public android.net.wifi.SupplicantState getSupplicantState();
+    method public int getTxLinkSpeedMbps();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final java.lang.String FREQUENCY_UNITS = "MHz";
-    field public static final java.lang.String LINK_SPEED_UNITS = "Mbps";
+    field public static final String FREQUENCY_UNITS = "MHz";
+    field public static final String LINK_SPEED_UNITS = "Mbps";
   }
 
   public class WifiManager {
-    method public deprecated int addNetwork(android.net.wifi.WifiConfiguration);
-    method public int addNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>);
+    method @Deprecated public int addNetwork(android.net.wifi.WifiConfiguration);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int addNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>);
     method public void addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
     method public static int calculateSignalLevel(int, int);
-    method public deprecated void cancelWps(android.net.wifi.WifiManager.WpsCallback);
+    method @Deprecated public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
     method public static int compareSignalLevel(int, int);
-    method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(java.lang.String);
-    method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, java.lang.String);
-    method public deprecated android.net.wifi.WifiManager.WifiLock createWifiLock(java.lang.String);
-    method public deprecated boolean disableNetwork(int);
-    method public deprecated boolean disconnect();
-    method public deprecated boolean enableNetwork(int, boolean);
-    method public deprecated java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
+    method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(String);
+    method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, String);
+    method @Deprecated public android.net.wifi.WifiManager.WifiLock createWifiLock(String);
+    method @Deprecated public boolean disableNetwork(int);
+    method @Deprecated public boolean disconnect();
+    method @Deprecated public boolean enableNetwork(int, boolean);
+    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
     method public android.net.wifi.WifiInfo getConnectionInfo();
     method public android.net.DhcpInfo getDhcpInfo();
     method public int getMaxNumberOfNetworkSuggestionsPerApp();
-    method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
+    method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", "android.permission.NETWORK_SETUP_WIZARD"}) public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
     method public int getWifiState();
     method public boolean is5GHzBandSupported();
     method public boolean isDeviceToApRttSupported();
-    method public boolean isDppSupported();
+    method public boolean isEasyConnectSupported();
     method public boolean isEnhancedPowerReportingSupported();
     method public boolean isOweSupported();
     method public boolean isP2pSupported();
     method public boolean isPreferredNetworkOffloadSupported();
-    method public deprecated boolean isScanAlwaysAvailable();
+    method @Deprecated public boolean isScanAlwaysAvailable();
     method public boolean isTdlsSupported();
     method public boolean isWifiEnabled();
     method public boolean isWpa3SaeSupported();
     method public boolean isWpa3SuiteBSupported();
-    method public deprecated boolean pingSupplicant();
-    method public deprecated boolean reassociate();
-    method public deprecated boolean reconnect();
-    method public deprecated boolean removeNetwork(int);
-    method public int removeNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>);
-    method public void removePasspointConfiguration(java.lang.String);
-    method public deprecated boolean saveConfiguration();
+    method @Deprecated public boolean pingSupplicant();
+    method @Deprecated public boolean reassociate();
+    method @Deprecated public boolean reconnect();
+    method @Deprecated public boolean removeNetwork(int);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int removeNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>);
+    method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", "android.permission.NETWORK_SETUP_WIZARD"}) public void removePasspointConfiguration(String);
+    method @Deprecated public boolean saveConfiguration();
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
-    method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
-    method public deprecated boolean setWifiEnabled(boolean);
-    method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, android.os.Handler);
-    method public deprecated boolean startScan();
-    method public deprecated void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
-    method public deprecated int updateNetwork(android.net.wifi.WifiConfiguration);
-    field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
-    field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
-    field public static final java.lang.String ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION = "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION";
-    field public static final deprecated int ERROR_AUTHENTICATING = 1; // 0x1
-    field public static final deprecated java.lang.String EXTRA_BSSID = "bssid";
-    field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
-    field public static final java.lang.String EXTRA_NETWORK_SUGGESTION = "android.net.wifi.extra.NETWORK_SUGGESTION";
-    field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
-    field public static final deprecated java.lang.String EXTRA_NEW_STATE = "newState";
-    field public static final java.lang.String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
-    field public static final java.lang.String EXTRA_RESULTS_UPDATED = "resultsUpdated";
-    field public static final deprecated java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
-    field public static final deprecated java.lang.String EXTRA_SUPPLICANT_ERROR = "supplicantError";
-    field public static final deprecated java.lang.String EXTRA_WIFI_INFO = "wifiInfo";
-    field public static final java.lang.String EXTRA_WIFI_STATE = "wifi_state";
-    field public static final java.lang.String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
-    field public static final java.lang.String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
-    field public static final java.lang.String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
-    field public static final java.lang.String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
+    method public void setTdlsEnabledWithMacAddress(String, boolean);
+    method @Deprecated public boolean setWifiEnabled(boolean);
+    method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, @Nullable android.os.Handler);
+    method @Deprecated public boolean startScan();
+    method @Deprecated public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
+    method @Deprecated public int updateNetwork(android.net.wifi.WifiConfiguration);
+    field public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
+    field public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
+    field public static final String ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION = "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION";
+    field @Deprecated public static final int ERROR_AUTHENTICATING = 1; // 0x1
+    field @Deprecated public static final String EXTRA_BSSID = "bssid";
+    field public static final String EXTRA_NETWORK_INFO = "networkInfo";
+    field public static final String EXTRA_NETWORK_SUGGESTION = "android.net.wifi.extra.NETWORK_SUGGESTION";
+    field public static final String EXTRA_NEW_RSSI = "newRssi";
+    field @Deprecated public static final String EXTRA_NEW_STATE = "newState";
+    field public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
+    field public static final String EXTRA_RESULTS_UPDATED = "resultsUpdated";
+    field @Deprecated public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
+    field @Deprecated public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
+    field @Deprecated public static final String EXTRA_WIFI_INFO = "wifiInfo";
+    field public static final String EXTRA_WIFI_STATE = "wifi_state";
+    field public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
+    field public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
+    field public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
+    field public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
     field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 3; // 0x3
     field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 4; // 0x4
     field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED = 2; // 0x2
     field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL = 1; // 0x1
     field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5; // 0x5
     field public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0; // 0x0
-    field public static final deprecated java.lang.String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
-    field public static final deprecated java.lang.String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
-    field public static final deprecated int WIFI_MODE_FULL = 1; // 0x1
+    field @Deprecated public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
+    field @Deprecated public static final String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
+    field @Deprecated public static final int WIFI_MODE_FULL = 1; // 0x1
     field public static final int WIFI_MODE_FULL_HIGH_PERF = 3; // 0x3
     field public static final int WIFI_MODE_FULL_LOW_LATENCY = 4; // 0x4
-    field public static final deprecated int WIFI_MODE_SCAN_ONLY = 2; // 0x2
-    field public static final java.lang.String WIFI_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_STATE_CHANGED";
+    field @Deprecated public static final int WIFI_MODE_SCAN_ONLY = 2; // 0x2
+    field public static final String WIFI_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_STATE_CHANGED";
     field public static final int WIFI_STATE_DISABLED = 1; // 0x1
     field public static final int WIFI_STATE_DISABLING = 0; // 0x0
     field public static final int WIFI_STATE_ENABLED = 3; // 0x3
     field public static final int WIFI_STATE_ENABLING = 2; // 0x2
     field public static final int WIFI_STATE_UNKNOWN = 4; // 0x4
-    field public static final deprecated int WPS_AUTH_FAILURE = 6; // 0x6
-    field public static final deprecated int WPS_OVERLAP_ERROR = 3; // 0x3
-    field public static final deprecated int WPS_TIMED_OUT = 7; // 0x7
-    field public static final deprecated int WPS_TKIP_ONLY_PROHIBITED = 5; // 0x5
-    field public static final deprecated int WPS_WEP_PROHIBITED = 4; // 0x4
+    field @Deprecated public static final int WPS_AUTH_FAILURE = 6; // 0x6
+    field @Deprecated public static final int WPS_OVERLAP_ERROR = 3; // 0x3
+    field @Deprecated public static final int WPS_TIMED_OUT = 7; // 0x7
+    field @Deprecated public static final int WPS_TKIP_ONLY_PROHIBITED = 5; // 0x5
+    field @Deprecated public static final int WPS_WEP_PROHIBITED = 4; // 0x4
   }
 
   public static class WifiManager.LocalOnlyHotspotCallback {
@@ -29646,9 +29927,6 @@
     method public void setReferenceCounted(boolean);
   }
 
-  public static abstract class WifiManager.NetworkSuggestionsStatusCode implements java.lang.annotation.Annotation {
-  }
-
   public class WifiManager.WifiLock {
     method public void acquire();
     method public boolean isHeld();
@@ -29657,31 +29935,31 @@
     method public void setWorkSource(android.os.WorkSource);
   }
 
-  public static abstract deprecated class WifiManager.WpsCallback {
-    ctor public WifiManager.WpsCallback();
-    method public abstract deprecated void onFailed(int);
-    method public abstract deprecated void onStarted(java.lang.String);
-    method public abstract deprecated void onSucceeded();
+  @Deprecated public abstract static class WifiManager.WpsCallback {
+    ctor @Deprecated public WifiManager.WpsCallback();
+    method @Deprecated public abstract void onFailed(int);
+    method @Deprecated public abstract void onStarted(String);
+    method @Deprecated public abstract void onSucceeded();
   }
 
   public class WifiNetworkConfigBuilder {
     ctor public WifiNetworkConfigBuilder();
     method public android.net.NetworkSpecifier buildNetworkSpecifier();
     method public android.net.wifi.WifiNetworkSuggestion buildNetworkSuggestion();
-    method public android.net.wifi.WifiNetworkConfigBuilder setBssid(android.net.MacAddress);
-    method public android.net.wifi.WifiNetworkConfigBuilder setBssidPattern(android.net.MacAddress, android.net.MacAddress);
+    method public android.net.wifi.WifiNetworkConfigBuilder setBssid(@NonNull android.net.MacAddress);
+    method public android.net.wifi.WifiNetworkConfigBuilder setBssidPattern(@NonNull android.net.MacAddress, @NonNull android.net.MacAddress);
     method public android.net.wifi.WifiNetworkConfigBuilder setIsAppInteractionRequired();
     method public android.net.wifi.WifiNetworkConfigBuilder setIsEnhancedOpen();
     method public android.net.wifi.WifiNetworkConfigBuilder setIsHiddenSsid();
     method public android.net.wifi.WifiNetworkConfigBuilder setIsMetered();
     method public android.net.wifi.WifiNetworkConfigBuilder setIsUserInteractionRequired();
     method public android.net.wifi.WifiNetworkConfigBuilder setPriority(int);
-    method public android.net.wifi.WifiNetworkConfigBuilder setSsid(java.lang.String);
-    method public android.net.wifi.WifiNetworkConfigBuilder setSsidPattern(android.os.PatternMatcher);
-    method public android.net.wifi.WifiNetworkConfigBuilder setWpa2EnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
-    method public android.net.wifi.WifiNetworkConfigBuilder setWpa2Passphrase(java.lang.String);
-    method public android.net.wifi.WifiNetworkConfigBuilder setWpa3EnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
-    method public android.net.wifi.WifiNetworkConfigBuilder setWpa3Passphrase(java.lang.String);
+    method public android.net.wifi.WifiNetworkConfigBuilder setSsid(@NonNull String);
+    method public android.net.wifi.WifiNetworkConfigBuilder setSsidPattern(@NonNull android.os.PatternMatcher);
+    method public android.net.wifi.WifiNetworkConfigBuilder setWpa2EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+    method public android.net.wifi.WifiNetworkConfigBuilder setWpa2Passphrase(@NonNull String);
+    method public android.net.wifi.WifiNetworkConfigBuilder setWpa3EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
+    method public android.net.wifi.WifiNetworkConfigBuilder setWpa3Passphrase(@NonNull String);
   }
 
   public final class WifiNetworkSuggestion implements android.os.Parcelable {
@@ -29695,14 +29973,14 @@
     ctor public WpsInfo(android.net.wifi.WpsInfo);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
-    field public java.lang.String BSSID;
+    field public String BSSID;
     field public static final android.os.Parcelable.Creator<android.net.wifi.WpsInfo> CREATOR;
     field public static final int DISPLAY = 1; // 0x1
     field public static final int INVALID = 4; // 0x4
     field public static final int KEYPAD = 2; // 0x2
     field public static final int LABEL = 3; // 0x3
     field public static final int PBC = 0; // 0x0
-    field public java.lang.String pin;
+    field public String pin;
     field public int setup;
   }
 
@@ -29727,9 +30005,9 @@
 
   public class DiscoverySession implements java.lang.AutoCloseable {
     method public void close();
-    method public deprecated android.net.NetworkSpecifier createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle);
-    method public deprecated android.net.NetworkSpecifier createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String);
-    method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
+    method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierOpen(@NonNull android.net.wifi.aware.PeerHandle);
+    method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(@NonNull android.net.wifi.aware.PeerHandle, @NonNull String);
+    method public void sendMessage(@NonNull android.net.wifi.aware.PeerHandle, int, @Nullable byte[]);
   }
 
   public class DiscoverySessionCallback {
@@ -29737,13 +30015,13 @@
     method public void onMessageReceived(android.net.wifi.aware.PeerHandle, byte[]);
     method public void onMessageSendFailed(int);
     method public void onMessageSendSucceeded(int);
-    method public void onPublishStarted(android.net.wifi.aware.PublishDiscoverySession);
+    method public void onPublishStarted(@NonNull android.net.wifi.aware.PublishDiscoverySession);
     method public void onServiceDiscovered(android.net.wifi.aware.PeerHandle, byte[], java.util.List<byte[]>);
     method public void onServiceDiscoveredWithinRange(android.net.wifi.aware.PeerHandle, byte[], java.util.List<byte[]>, int);
     method public void onSessionConfigFailed();
     method public void onSessionConfigUpdated();
     method public void onSessionTerminated();
-    method public void onSubscribeStarted(android.net.wifi.aware.SubscribeDiscoverySession);
+    method public void onSubscribeStarted(@NonNull android.net.wifi.aware.SubscribeDiscoverySession);
   }
 
   public class IdentityChangedListener {
@@ -29751,7 +30029,10 @@
     method public void onIdentityChanged(byte[]);
   }
 
-  public class PeerHandle {
+  public final class PeerHandle implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.aware.PeerHandle> CREATOR;
   }
 
   public final class PublishConfig implements android.os.Parcelable {
@@ -29765,17 +30046,17 @@
   public static final class PublishConfig.Builder {
     ctor public PublishConfig.Builder();
     method public android.net.wifi.aware.PublishConfig build();
-    method public android.net.wifi.aware.PublishConfig.Builder setMatchFilter(java.util.List<byte[]>);
+    method public android.net.wifi.aware.PublishConfig.Builder setMatchFilter(@Nullable java.util.List<byte[]>);
     method public android.net.wifi.aware.PublishConfig.Builder setPublishType(int);
     method public android.net.wifi.aware.PublishConfig.Builder setRangingEnabled(boolean);
-    method public android.net.wifi.aware.PublishConfig.Builder setServiceName(java.lang.String);
-    method public android.net.wifi.aware.PublishConfig.Builder setServiceSpecificInfo(byte[]);
+    method public android.net.wifi.aware.PublishConfig.Builder setServiceName(@NonNull String);
+    method public android.net.wifi.aware.PublishConfig.Builder setServiceSpecificInfo(@Nullable byte[]);
     method public android.net.wifi.aware.PublishConfig.Builder setTerminateNotificationEnabled(boolean);
     method public android.net.wifi.aware.PublishConfig.Builder setTtlSec(int);
   }
 
   public class PublishDiscoverySession extends android.net.wifi.aware.DiscoverySession {
-    method public void updatePublish(android.net.wifi.aware.PublishConfig);
+    method public void updatePublish(@NonNull android.net.wifi.aware.PublishConfig);
   }
 
   public final class SubscribeConfig implements android.os.Parcelable {
@@ -29789,51 +30070,55 @@
   public static final class SubscribeConfig.Builder {
     ctor public SubscribeConfig.Builder();
     method public android.net.wifi.aware.SubscribeConfig build();
-    method public android.net.wifi.aware.SubscribeConfig.Builder setMatchFilter(java.util.List<byte[]>);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setMatchFilter(@Nullable java.util.List<byte[]>);
     method public android.net.wifi.aware.SubscribeConfig.Builder setMaxDistanceMm(int);
     method public android.net.wifi.aware.SubscribeConfig.Builder setMinDistanceMm(int);
-    method public android.net.wifi.aware.SubscribeConfig.Builder setServiceName(java.lang.String);
-    method public android.net.wifi.aware.SubscribeConfig.Builder setServiceSpecificInfo(byte[]);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setServiceName(@NonNull String);
+    method public android.net.wifi.aware.SubscribeConfig.Builder setServiceSpecificInfo(@Nullable byte[]);
     method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeType(int);
     method public android.net.wifi.aware.SubscribeConfig.Builder setTerminateNotificationEnabled(boolean);
     method public android.net.wifi.aware.SubscribeConfig.Builder setTtlSec(int);
   }
 
   public class SubscribeDiscoverySession extends android.net.wifi.aware.DiscoverySession {
-    method public void updateSubscribe(android.net.wifi.aware.SubscribeConfig);
+    method public void updateSubscribe(@NonNull android.net.wifi.aware.SubscribeConfig);
   }
 
   public class WifiAwareManager {
-    method public void attach(android.net.wifi.aware.AttachCallback, android.os.Handler);
-    method public void attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler);
+    method public void attach(@NonNull android.net.wifi.aware.AttachCallback, @Nullable android.os.Handler);
+    method public void attach(@NonNull android.net.wifi.aware.AttachCallback, @NonNull android.net.wifi.aware.IdentityChangedListener, @Nullable android.os.Handler);
     method public android.net.wifi.aware.Characteristics getCharacteristics();
     method public boolean isAvailable();
-    field public static final java.lang.String ACTION_WIFI_AWARE_STATE_CHANGED = "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED";
+    field public static final String ACTION_WIFI_AWARE_STATE_CHANGED = "android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED";
     field public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0; // 0x0
     field public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; // 0x1
   }
 
   public static class WifiAwareManager.NetworkSpecifierBuilder {
     ctor public WifiAwareManager.NetworkSpecifierBuilder();
-    method public android.net.NetworkSpecifier build();
-    method public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setDiscoverySession(android.net.wifi.aware.DiscoverySession);
-    method public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPeerHandle(android.net.wifi.aware.PeerHandle);
-    method public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPskPassphrase(java.lang.String);
+    method @NonNull public android.net.NetworkSpecifier build();
+    method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setDiscoverySession(@NonNull android.net.wifi.aware.DiscoverySession);
+    method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPeerHandle(@NonNull android.net.wifi.aware.PeerHandle);
+    method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPort(int);
+    method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPskPassphrase(@NonNull String);
+    method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setTransportProtocol(int);
   }
 
   public final class WifiAwareNetworkInfo implements android.os.Parcelable android.net.TransportInfo {
     method public int describeContents();
-    method public java.net.Inet6Address getPeerIpv6Addr();
+    method @Nullable public java.net.Inet6Address getPeerIpv6Addr();
+    method public int getPort();
+    method public int getTransportProtocol();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.wifi.aware.WifiAwareNetworkInfo> CREATOR;
   }
 
   public class WifiAwareSession implements java.lang.AutoCloseable {
     method public void close();
-    method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, byte[]);
-    method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, byte[], java.lang.String);
-    method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
-    method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
+    method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, @NonNull byte[]);
+    method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, @NonNull byte[], @NonNull String);
+    method public void publish(@NonNull android.net.wifi.aware.PublishConfig, @NonNull android.net.wifi.aware.DiscoverySessionCallback, @Nullable android.os.Handler);
+    method public void subscribe(@NonNull android.net.wifi.aware.SubscribeConfig, @NonNull android.net.wifi.aware.DiscoverySessionCallback, @Nullable android.os.Handler);
   }
 
 }
@@ -29841,7 +30126,7 @@
 package android.net.wifi.hotspot2 {
 
   public final class ConfigParser {
-    method public static android.net.wifi.hotspot2.PasspointConfiguration parsePasspointConfig(java.lang.String, byte[]);
+    method public static android.net.wifi.hotspot2.PasspointConfiguration parsePasspointConfig(String, byte[]);
   }
 
   public final class PasspointConfiguration implements android.os.Parcelable {
@@ -29861,7 +30146,7 @@
 package android.net.wifi.hotspot2.omadm {
 
   public final class PpsMoParser {
-    method public static android.net.wifi.hotspot2.PasspointConfiguration parseMoText(java.lang.String);
+    method public static android.net.wifi.hotspot2.PasspointConfiguration parseMoText(String);
   }
 
 }
@@ -29876,14 +30161,14 @@
     method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
     method public java.security.cert.X509Certificate[] getClientCertificateChain();
     method public java.security.PrivateKey getClientPrivateKey();
-    method public java.lang.String getRealm();
+    method public String getRealm();
     method public android.net.wifi.hotspot2.pps.Credential.SimCredential getSimCredential();
     method public android.net.wifi.hotspot2.pps.Credential.UserCredential getUserCredential();
     method public void setCaCertificate(java.security.cert.X509Certificate);
     method public void setCertCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
     method public void setClientCertificateChain(java.security.cert.X509Certificate[]);
     method public void setClientPrivateKey(java.security.PrivateKey);
-    method public void setRealm(java.lang.String);
+    method public void setRealm(String);
     method public void setSimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
     method public void setUserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
     method public void writeToParcel(android.os.Parcel, int);
@@ -29895,9 +30180,9 @@
     ctor public Credential.CertificateCredential(android.net.wifi.hotspot2.pps.Credential.CertificateCredential);
     method public int describeContents();
     method public byte[] getCertSha256Fingerprint();
-    method public java.lang.String getCertType();
+    method public String getCertType();
     method public void setCertSha256Fingerprint(byte[]);
-    method public void setCertType(java.lang.String);
+    method public void setCertType(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.CertificateCredential> CREATOR;
   }
@@ -29907,9 +30192,9 @@
     ctor public Credential.SimCredential(android.net.wifi.hotspot2.pps.Credential.SimCredential);
     method public int describeContents();
     method public int getEapType();
-    method public java.lang.String getImsi();
+    method public String getImsi();
     method public void setEapType(int);
-    method public void setImsi(java.lang.String);
+    method public void setImsi(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.SimCredential> CREATOR;
   }
@@ -29919,13 +30204,13 @@
     ctor public Credential.UserCredential(android.net.wifi.hotspot2.pps.Credential.UserCredential);
     method public int describeContents();
     method public int getEapType();
-    method public java.lang.String getNonEapInnerMethod();
-    method public java.lang.String getPassword();
-    method public java.lang.String getUsername();
+    method public String getNonEapInnerMethod();
+    method public String getPassword();
+    method public String getUsername();
     method public void setEapType(int);
-    method public void setNonEapInnerMethod(java.lang.String);
-    method public void setPassword(java.lang.String);
-    method public void setUsername(java.lang.String);
+    method public void setNonEapInnerMethod(String);
+    method public void setPassword(String);
+    method public void setUsername(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.Credential.UserCredential> CREATOR;
   }
@@ -29934,11 +30219,11 @@
     ctor public HomeSp();
     ctor public HomeSp(android.net.wifi.hotspot2.pps.HomeSp);
     method public int describeContents();
-    method public java.lang.String getFqdn();
-    method public java.lang.String getFriendlyName();
+    method public String getFqdn();
+    method public String getFriendlyName();
     method public long[] getRoamingConsortiumOis();
-    method public void setFqdn(java.lang.String);
-    method public void setFriendlyName(java.lang.String);
+    method public void setFqdn(String);
+    method public void setFriendlyName(String);
     method public void setRoamingConsortiumOis(long[]);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
@@ -29957,7 +30242,7 @@
     field public static final int GROUP_OWNER_BAND_2GHZ = 1; // 0x1
     field public static final int GROUP_OWNER_BAND_5GHZ = 2; // 0x2
     field public static final int GROUP_OWNER_BAND_AUTO = 0; // 0x0
-    field public java.lang.String deviceAddress;
+    field public String deviceAddress;
     field public int groupOwnerIntent;
     field public android.net.wifi.WpsInfo wps;
   }
@@ -29967,9 +30252,10 @@
     method public android.net.wifi.p2p.WifiP2pConfig build();
     method public android.net.wifi.p2p.WifiP2pConfig.Builder enablePersistentMode(boolean);
     method public android.net.wifi.p2p.WifiP2pConfig.Builder setDeviceAddress(android.net.MacAddress);
-    method public android.net.wifi.p2p.WifiP2pConfig.Builder setGroupOwnerBand(int);
-    method public android.net.wifi.p2p.WifiP2pConfig.Builder setNetworkName(java.lang.String);
-    method public android.net.wifi.p2p.WifiP2pConfig.Builder setPassphrase(java.lang.String);
+    method public android.net.wifi.p2p.WifiP2pConfig.Builder setGroupOperatingBand(int);
+    method public android.net.wifi.p2p.WifiP2pConfig.Builder setGroupOperatingFrequency(int);
+    method public android.net.wifi.p2p.WifiP2pConfig.Builder setNetworkName(String);
+    method public android.net.wifi.p2p.WifiP2pConfig.Builder setPassphrase(String);
   }
 
   public class WifiP2pDevice implements android.os.Parcelable {
@@ -29988,10 +30274,10 @@
     field public static final int FAILED = 2; // 0x2
     field public static final int INVITED = 1; // 0x1
     field public static final int UNAVAILABLE = 4; // 0x4
-    field public java.lang.String deviceAddress;
-    field public java.lang.String deviceName;
-    field public java.lang.String primaryDeviceType;
-    field public java.lang.String secondaryDeviceType;
+    field public String deviceAddress;
+    field public String deviceName;
+    field public String primaryDeviceType;
+    field public String secondaryDeviceType;
     field public int status;
   }
 
@@ -29999,7 +30285,7 @@
     ctor public WifiP2pDeviceList();
     ctor public WifiP2pDeviceList(android.net.wifi.p2p.WifiP2pDeviceList);
     method public int describeContents();
-    method public android.net.wifi.p2p.WifiP2pDevice get(java.lang.String);
+    method public android.net.wifi.p2p.WifiP2pDevice get(String);
     method public java.util.Collection<android.net.wifi.p2p.WifiP2pDevice> getDeviceList();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pDeviceList> CREATOR;
@@ -30010,10 +30296,11 @@
     ctor public WifiP2pGroup(android.net.wifi.p2p.WifiP2pGroup);
     method public int describeContents();
     method public java.util.Collection<android.net.wifi.p2p.WifiP2pDevice> getClientList();
-    method public java.lang.String getInterface();
-    method public java.lang.String getNetworkName();
+    method public int getFrequency();
+    method public String getInterface();
+    method public String getNetworkName();
     method public android.net.wifi.p2p.WifiP2pDevice getOwner();
-    method public java.lang.String getPassphrase();
+    method public String getPassphrase();
     method public boolean isGroupOwner();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pGroup> CREATOR;
@@ -30031,103 +30318,103 @@
   }
 
   public class WifiP2pManager {
-    method public void addLocalService(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void addLocalService(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void addServiceRequest(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceRequest, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void cancelConnect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void clearLocalServices(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void clearServiceRequests(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
-    method public void connect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener);
-    method public void createGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
-    method public void createGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener);
-    method public void discoverPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
-    method public void discoverServices(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void connect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void createGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void createGroup(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pConfig, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void discoverPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void discoverServices(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public android.net.wifi.p2p.WifiP2pManager.Channel initialize(android.content.Context, android.os.Looper, android.net.wifi.p2p.WifiP2pManager.ChannelListener);
     method public void removeGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void removeLocalService(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void removeServiceRequest(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceRequest, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method public void requestConnectionInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener);
-    method public void requestDiscoveryState(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.DiscoveryStateListener);
-    method public void requestGroupInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.GroupInfoListener);
-    method public void requestNetworkInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.NetworkInfoListener);
-    method public void requestP2pState(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.P2pStateListener);
-    method public void requestPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.PeerListListener);
+    method public void requestDiscoveryState(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pManager.DiscoveryStateListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void requestGroupInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.GroupInfoListener);
+    method public void requestNetworkInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pManager.NetworkInfoListener);
+    method public void requestP2pState(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pManager.P2pStateListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void requestPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.PeerListListener);
     method public void setDnsSdResponseListeners(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener, android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener);
     method public void setServiceResponseListener(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ServiceResponseListener);
     method public void setUpnpServiceResponseListener(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.UpnpServiceResponseListener);
     method public void stopPeerDiscovery(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
     field public static final int BUSY = 2; // 0x2
     field public static final int ERROR = 0; // 0x0
-    field public static final java.lang.String EXTRA_DISCOVERY_STATE = "discoveryState";
-    field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
-    field public static final java.lang.String EXTRA_P2P_DEVICE_LIST = "wifiP2pDeviceList";
-    field public static final java.lang.String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice";
-    field public static final java.lang.String EXTRA_WIFI_P2P_GROUP = "p2pGroupInfo";
-    field public static final java.lang.String EXTRA_WIFI_P2P_INFO = "wifiP2pInfo";
-    field public static final java.lang.String EXTRA_WIFI_STATE = "wifi_p2p_state";
+    field public static final String EXTRA_DISCOVERY_STATE = "discoveryState";
+    field public static final String EXTRA_NETWORK_INFO = "networkInfo";
+    field public static final String EXTRA_P2P_DEVICE_LIST = "wifiP2pDeviceList";
+    field public static final String EXTRA_WIFI_P2P_DEVICE = "wifiP2pDevice";
+    field public static final String EXTRA_WIFI_P2P_GROUP = "p2pGroupInfo";
+    field public static final String EXTRA_WIFI_P2P_INFO = "wifiP2pInfo";
+    field public static final String EXTRA_WIFI_STATE = "wifi_p2p_state";
     field public static final int NO_SERVICE_REQUESTS = 3; // 0x3
     field public static final int P2P_UNSUPPORTED = 1; // 0x1
-    field public static final java.lang.String WIFI_P2P_CONNECTION_CHANGED_ACTION = "android.net.wifi.p2p.CONNECTION_STATE_CHANGE";
-    field public static final java.lang.String WIFI_P2P_DISCOVERY_CHANGED_ACTION = "android.net.wifi.p2p.DISCOVERY_STATE_CHANGE";
+    field public static final String WIFI_P2P_CONNECTION_CHANGED_ACTION = "android.net.wifi.p2p.CONNECTION_STATE_CHANGE";
+    field public static final String WIFI_P2P_DISCOVERY_CHANGED_ACTION = "android.net.wifi.p2p.DISCOVERY_STATE_CHANGE";
     field public static final int WIFI_P2P_DISCOVERY_STARTED = 2; // 0x2
     field public static final int WIFI_P2P_DISCOVERY_STOPPED = 1; // 0x1
-    field public static final java.lang.String WIFI_P2P_PEERS_CHANGED_ACTION = "android.net.wifi.p2p.PEERS_CHANGED";
-    field public static final java.lang.String WIFI_P2P_STATE_CHANGED_ACTION = "android.net.wifi.p2p.STATE_CHANGED";
+    field public static final String WIFI_P2P_PEERS_CHANGED_ACTION = "android.net.wifi.p2p.PEERS_CHANGED";
+    field public static final String WIFI_P2P_STATE_CHANGED_ACTION = "android.net.wifi.p2p.STATE_CHANGED";
     field public static final int WIFI_P2P_STATE_DISABLED = 1; // 0x1
     field public static final int WIFI_P2P_STATE_ENABLED = 2; // 0x2
-    field public static final java.lang.String WIFI_P2P_THIS_DEVICE_CHANGED_ACTION = "android.net.wifi.p2p.THIS_DEVICE_CHANGED";
+    field public static final String WIFI_P2P_THIS_DEVICE_CHANGED_ACTION = "android.net.wifi.p2p.THIS_DEVICE_CHANGED";
   }
 
-  public static abstract interface WifiP2pManager.ActionListener {
-    method public abstract void onFailure(int);
-    method public abstract void onSuccess();
+  public static interface WifiP2pManager.ActionListener {
+    method public void onFailure(int);
+    method public void onSuccess();
   }
 
   public static class WifiP2pManager.Channel implements java.lang.AutoCloseable {
     method public void close();
   }
 
-  public static abstract interface WifiP2pManager.ChannelListener {
-    method public abstract void onChannelDisconnected();
+  public static interface WifiP2pManager.ChannelListener {
+    method public void onChannelDisconnected();
   }
 
-  public static abstract interface WifiP2pManager.ConnectionInfoListener {
-    method public abstract void onConnectionInfoAvailable(android.net.wifi.p2p.WifiP2pInfo);
+  public static interface WifiP2pManager.ConnectionInfoListener {
+    method public void onConnectionInfoAvailable(android.net.wifi.p2p.WifiP2pInfo);
   }
 
-  public static abstract interface WifiP2pManager.DiscoveryStateListener {
-    method public abstract void onDiscoveryStateAvailable(int);
+  public static interface WifiP2pManager.DiscoveryStateListener {
+    method public void onDiscoveryStateAvailable(int);
   }
 
-  public static abstract interface WifiP2pManager.DnsSdServiceResponseListener {
-    method public abstract void onDnsSdServiceAvailable(java.lang.String, java.lang.String, android.net.wifi.p2p.WifiP2pDevice);
+  public static interface WifiP2pManager.DnsSdServiceResponseListener {
+    method public void onDnsSdServiceAvailable(String, String, android.net.wifi.p2p.WifiP2pDevice);
   }
 
-  public static abstract interface WifiP2pManager.DnsSdTxtRecordListener {
-    method public abstract void onDnsSdTxtRecordAvailable(java.lang.String, java.util.Map<java.lang.String, java.lang.String>, android.net.wifi.p2p.WifiP2pDevice);
+  public static interface WifiP2pManager.DnsSdTxtRecordListener {
+    method public void onDnsSdTxtRecordAvailable(String, java.util.Map<java.lang.String,java.lang.String>, android.net.wifi.p2p.WifiP2pDevice);
   }
 
-  public static abstract interface WifiP2pManager.GroupInfoListener {
-    method public abstract void onGroupInfoAvailable(android.net.wifi.p2p.WifiP2pGroup);
+  public static interface WifiP2pManager.GroupInfoListener {
+    method public void onGroupInfoAvailable(android.net.wifi.p2p.WifiP2pGroup);
   }
 
-  public static abstract interface WifiP2pManager.NetworkInfoListener {
-    method public abstract void onNetworkInfoAvailable(android.net.NetworkInfo);
+  public static interface WifiP2pManager.NetworkInfoListener {
+    method public void onNetworkInfoAvailable(android.net.NetworkInfo);
   }
 
-  public static abstract interface WifiP2pManager.P2pStateListener {
-    method public abstract void onP2pStateAvailable(int);
+  public static interface WifiP2pManager.P2pStateListener {
+    method public void onP2pStateAvailable(int);
   }
 
-  public static abstract interface WifiP2pManager.PeerListListener {
-    method public abstract void onPeersAvailable(android.net.wifi.p2p.WifiP2pDeviceList);
+  public static interface WifiP2pManager.PeerListListener {
+    method public void onPeersAvailable(android.net.wifi.p2p.WifiP2pDeviceList);
   }
 
-  public static abstract interface WifiP2pManager.ServiceResponseListener {
-    method public abstract void onServiceAvailable(int, byte[], android.net.wifi.p2p.WifiP2pDevice);
+  public static interface WifiP2pManager.ServiceResponseListener {
+    method public void onServiceAvailable(int, byte[], android.net.wifi.p2p.WifiP2pDevice);
   }
 
-  public static abstract interface WifiP2pManager.UpnpServiceResponseListener {
-    method public abstract void onUpnpServiceAvailable(java.util.List<java.lang.String>, android.net.wifi.p2p.WifiP2pDevice);
+  public static interface WifiP2pManager.UpnpServiceResponseListener {
+    method public void onUpnpServiceAvailable(java.util.List<java.lang.String>, android.net.wifi.p2p.WifiP2pDevice);
   }
 
 }
@@ -30135,13 +30422,13 @@
 package android.net.wifi.p2p.nsd {
 
   public class WifiP2pDnsSdServiceInfo extends android.net.wifi.p2p.nsd.WifiP2pServiceInfo {
-    method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo newInstance(java.lang.String, java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
+    method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo newInstance(String, String, java.util.Map<java.lang.String,java.lang.String>);
   }
 
   public class WifiP2pDnsSdServiceRequest extends android.net.wifi.p2p.nsd.WifiP2pServiceRequest {
     method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance();
-    method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance(java.lang.String);
-    method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance(java.lang.String, java.lang.String);
+    method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance(String);
+    method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance(String, String);
   }
 
   public class WifiP2pServiceInfo implements android.os.Parcelable {
@@ -30155,18 +30442,18 @@
 
   public class WifiP2pServiceRequest implements android.os.Parcelable {
     method public int describeContents();
-    method public static android.net.wifi.p2p.nsd.WifiP2pServiceRequest newInstance(int, java.lang.String);
+    method public static android.net.wifi.p2p.nsd.WifiP2pServiceRequest newInstance(int, String);
     method public static android.net.wifi.p2p.nsd.WifiP2pServiceRequest newInstance(int);
     method public void writeToParcel(android.os.Parcel, int);
   }
 
   public class WifiP2pUpnpServiceInfo extends android.net.wifi.p2p.nsd.WifiP2pServiceInfo {
-    method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo newInstance(java.lang.String, java.lang.String, java.util.List<java.lang.String>);
+    method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo newInstance(String, String, java.util.List<java.lang.String>);
   }
 
   public class WifiP2pUpnpServiceRequest extends android.net.wifi.p2p.nsd.WifiP2pServiceRequest {
     method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest newInstance();
-    method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest newInstance(java.lang.String);
+    method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest newInstance(String);
   }
 
 }
@@ -30182,10 +30469,10 @@
 
   public static final class RangingRequest.Builder {
     ctor public RangingRequest.Builder();
-    method public android.net.wifi.rtt.RangingRequest.Builder addAccessPoint(android.net.wifi.ScanResult);
-    method public android.net.wifi.rtt.RangingRequest.Builder addAccessPoints(java.util.List<android.net.wifi.ScanResult>);
-    method public android.net.wifi.rtt.RangingRequest.Builder addWifiAwarePeer(android.net.MacAddress);
-    method public android.net.wifi.rtt.RangingRequest.Builder addWifiAwarePeer(android.net.wifi.aware.PeerHandle);
+    method public android.net.wifi.rtt.RangingRequest.Builder addAccessPoint(@NonNull android.net.wifi.ScanResult);
+    method public android.net.wifi.rtt.RangingRequest.Builder addAccessPoints(@NonNull java.util.List<android.net.wifi.ScanResult>);
+    method public android.net.wifi.rtt.RangingRequest.Builder addWifiAwarePeer(@NonNull android.net.MacAddress);
+    method public android.net.wifi.rtt.RangingRequest.Builder addWifiAwarePeer(@NonNull android.net.wifi.aware.PeerHandle);
     method public android.net.wifi.rtt.RangingRequest build();
   }
 
@@ -30193,10 +30480,10 @@
     method public int describeContents();
     method public int getDistanceMm();
     method public int getDistanceStdDevMm();
-    method public android.net.MacAddress getMacAddress();
+    method @Nullable public android.net.MacAddress getMacAddress();
     method public int getNumAttemptedMeasurements();
     method public int getNumSuccessfulMeasurements();
-    method public android.net.wifi.aware.PeerHandle getPeerHandle();
+    method @Nullable public android.net.wifi.aware.PeerHandle getPeerHandle();
     method public long getRangingTimestampMillis();
     method public int getRssi();
     method public int getStatus();
@@ -30210,15 +30497,15 @@
   public abstract class RangingResultCallback {
     ctor public RangingResultCallback();
     method public abstract void onRangingFailure(int);
-    method public abstract void onRangingResults(java.util.List<android.net.wifi.rtt.RangingResult>);
+    method public abstract void onRangingResults(@NonNull java.util.List<android.net.wifi.rtt.RangingResult>);
     field public static final int STATUS_CODE_FAIL = 1; // 0x1
     field public static final int STATUS_CODE_FAIL_RTT_NOT_AVAILABLE = 2; // 0x2
   }
 
   public class WifiRttManager {
     method public boolean isAvailable();
-    method public void startRanging(android.net.wifi.rtt.RangingRequest, java.util.concurrent.Executor, android.net.wifi.rtt.RangingResultCallback);
-    field public static final java.lang.String ACTION_WIFI_RTT_STATE_CHANGED = "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED";
+    method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.ACCESS_WIFI_STATE}) public void startRanging(@NonNull android.net.wifi.rtt.RangingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.rtt.RangingResultCallback);
+    field public static final String ACTION_WIFI_RTT_STATE_CHANGED = "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED";
   }
 
 }
@@ -30227,8 +30514,8 @@
 
   public class FormatException extends java.lang.Exception {
     ctor public FormatException();
-    ctor public FormatException(java.lang.String);
-    ctor public FormatException(java.lang.String, java.lang.Throwable);
+    ctor public FormatException(String);
+    ctor public FormatException(String, Throwable);
   }
 
   public final class NdefMessage implements android.os.Parcelable {
@@ -30245,20 +30532,20 @@
 
   public final class NdefRecord implements android.os.Parcelable {
     ctor public NdefRecord(short, byte[], byte[], byte[]);
-    ctor public deprecated NdefRecord(byte[]) throws android.nfc.FormatException;
-    method public static android.nfc.NdefRecord createApplicationRecord(java.lang.String);
-    method public static android.nfc.NdefRecord createExternal(java.lang.String, java.lang.String, byte[]);
-    method public static android.nfc.NdefRecord createMime(java.lang.String, byte[]);
-    method public static android.nfc.NdefRecord createTextRecord(java.lang.String, java.lang.String);
+    ctor @Deprecated public NdefRecord(byte[]) throws android.nfc.FormatException;
+    method public static android.nfc.NdefRecord createApplicationRecord(String);
+    method public static android.nfc.NdefRecord createExternal(String, String, byte[]);
+    method public static android.nfc.NdefRecord createMime(String, byte[]);
+    method public static android.nfc.NdefRecord createTextRecord(String, String);
     method public static android.nfc.NdefRecord createUri(android.net.Uri);
-    method public static android.nfc.NdefRecord createUri(java.lang.String);
+    method public static android.nfc.NdefRecord createUri(String);
     method public int describeContents();
     method public byte[] getId();
     method public byte[] getPayload();
     method public short getTnf();
     method public byte[] getType();
-    method public deprecated byte[] toByteArray();
-    method public java.lang.String toMimeType();
+    method @Deprecated public byte[] toByteArray();
+    method public String toMimeType();
     method public android.net.Uri toUri();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.nfc.NdefRecord> CREATOR;
@@ -30280,34 +30567,35 @@
 
   public final class NfcAdapter {
     method public void disableForegroundDispatch(android.app.Activity);
-    method public deprecated void disableForegroundNdefPush(android.app.Activity);
+    method @Deprecated public void disableForegroundNdefPush(android.app.Activity);
     method public void disableReaderMode(android.app.Activity);
-    method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], java.lang.String[][]);
-    method public deprecated void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
+    method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]);
+    method @Deprecated public void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
     method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
+    method @NonNull public java.util.List<java.lang.String> getSupportedOffHostSecureElements();
     method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
-    method public boolean invokeBeam(android.app.Activity);
+    method @Deprecated public boolean invokeBeam(android.app.Activity);
     method public boolean isEnabled();
-    method public boolean isNdefPushEnabled();
-    method public void setBeamPushUris(android.net.Uri[], android.app.Activity);
-    method public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
-    method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
-    method public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...);
-    method public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...);
-    field public static final java.lang.String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
-    field public static final java.lang.String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
-    field public static final java.lang.String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
-    field public static final java.lang.String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
-    field public static final java.lang.String ACTION_TRANSACTION_DETECTED = "android.nfc.action.TRANSACTION_DETECTED";
-    field public static final java.lang.String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE";
-    field public static final java.lang.String EXTRA_AID = "android.nfc.extra.AID";
-    field public static final java.lang.String EXTRA_DATA = "android.nfc.extra.DATA";
-    field public static final java.lang.String EXTRA_ID = "android.nfc.extra.ID";
-    field public static final java.lang.String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
-    field public static final java.lang.String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
-    field public static final java.lang.String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME";
-    field public static final java.lang.String EXTRA_TAG = "android.nfc.extra.TAG";
+    method @Deprecated public boolean isNdefPushEnabled();
+    method @Deprecated public void setBeamPushUris(android.net.Uri[], android.app.Activity);
+    method @Deprecated public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
+    method @Deprecated public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
+    method @Deprecated public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...);
+    method @Deprecated public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...);
+    field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
+    field public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
+    field public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
+    field public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
+    field @RequiresPermission(android.Manifest.permission.NFC_TRANSACTION_EVENT) public static final String ACTION_TRANSACTION_DETECTED = "android.nfc.action.TRANSACTION_DETECTED";
+    field public static final String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE";
+    field public static final String EXTRA_AID = "android.nfc.extra.AID";
+    field public static final String EXTRA_DATA = "android.nfc.extra.DATA";
+    field public static final String EXTRA_ID = "android.nfc.extra.ID";
+    field public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
+    field public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
+    field public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME";
+    field public static final String EXTRA_TAG = "android.nfc.extra.TAG";
     field public static final int FLAG_READER_NFC_A = 1; // 0x1
     field public static final int FLAG_READER_NFC_B = 2; // 0x2
     field public static final int FLAG_READER_NFC_BARCODE = 16; // 0x10
@@ -30321,24 +30609,24 @@
     field public static final int STATE_TURNING_ON = 2; // 0x2
   }
 
-  public static abstract interface NfcAdapter.CreateBeamUrisCallback {
-    method public abstract android.net.Uri[] createBeamUris(android.nfc.NfcEvent);
+  @Deprecated public static interface NfcAdapter.CreateBeamUrisCallback {
+    method @Deprecated public android.net.Uri[] createBeamUris(android.nfc.NfcEvent);
   }
 
-  public static abstract interface NfcAdapter.CreateNdefMessageCallback {
-    method public abstract android.nfc.NdefMessage createNdefMessage(android.nfc.NfcEvent);
+  @Deprecated public static interface NfcAdapter.CreateNdefMessageCallback {
+    method @Deprecated public android.nfc.NdefMessage createNdefMessage(android.nfc.NfcEvent);
   }
 
-  public static abstract interface NfcAdapter.OnNdefPushCompleteCallback {
-    method public abstract void onNdefPushComplete(android.nfc.NfcEvent);
+  @Deprecated public static interface NfcAdapter.OnNdefPushCompleteCallback {
+    method @Deprecated public void onNdefPushComplete(android.nfc.NfcEvent);
   }
 
-  public static abstract interface NfcAdapter.OnTagRemovedListener {
-    method public abstract void onTagRemoved();
+  public static interface NfcAdapter.OnTagRemovedListener {
+    method public void onTagRemoved();
   }
 
-  public static abstract interface NfcAdapter.ReaderCallback {
-    method public abstract void onTagDiscovered(android.nfc.Tag);
+  public static interface NfcAdapter.ReaderCallback {
+    method public void onTagDiscovered(android.nfc.Tag);
   }
 
   public final class NfcEvent {
@@ -30354,14 +30642,14 @@
   public final class Tag implements android.os.Parcelable {
     method public int describeContents();
     method public byte[] getId();
-    method public java.lang.String[] getTechList();
+    method public String[] getTechList();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.nfc.Tag> CREATOR;
   }
 
   public class TagLostException extends java.io.IOException {
     ctor public TagLostException();
-    ctor public TagLostException(java.lang.String);
+    ctor public TagLostException(String);
   }
 
 }
@@ -30369,22 +30657,24 @@
 package android.nfc.cardemulation {
 
   public final class CardEmulation {
-    method public boolean categoryAllowsForegroundPreference(java.lang.String);
-    method public java.util.List<java.lang.String> getAidsForService(android.content.ComponentName, java.lang.String);
-    method public static synchronized android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter);
-    method public int getSelectionModeForCategory(java.lang.String);
-    method public boolean isDefaultServiceForAid(android.content.ComponentName, java.lang.String);
-    method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String);
-    method public boolean registerAidsForService(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
-    method public boolean removeAidsForService(android.content.ComponentName, java.lang.String);
+    method public boolean categoryAllowsForegroundPreference(String);
+    method public java.util.List<java.lang.String> getAidsForService(android.content.ComponentName, String);
+    method public static android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter);
+    method public int getSelectionModeForCategory(String);
+    method public boolean isDefaultServiceForAid(android.content.ComponentName, String);
+    method public boolean isDefaultServiceForCategory(android.content.ComponentName, String);
+    method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
+    method public boolean removeAidsForService(android.content.ComponentName, String);
+    method public boolean setOffHostForService(android.content.ComponentName, String);
     method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
     method public boolean supportsAidPrefixRegistration();
+    method public boolean unsetOffHostForService(android.content.ComponentName);
     method public boolean unsetPreferredService(android.app.Activity);
-    field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
-    field public static final java.lang.String CATEGORY_OTHER = "other";
-    field public static final java.lang.String CATEGORY_PAYMENT = "payment";
-    field public static final java.lang.String EXTRA_CATEGORY = "category";
-    field public static final java.lang.String EXTRA_SERVICE_COMPONENT = "component";
+    field public static final String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
+    field public static final String CATEGORY_OTHER = "other";
+    field public static final String CATEGORY_PAYMENT = "payment";
+    field public static final String EXTRA_CATEGORY = "category";
+    field public static final String EXTRA_SERVICE_COMPONENT = "component";
     field public static final int SELECTION_MODE_ALWAYS_ASK = 1; // 0x1
     field public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; // 0x2
     field public static final int SELECTION_MODE_PREFER_DEFAULT = 0; // 0x0
@@ -30399,8 +30689,8 @@
     method public final void sendResponseApdu(byte[]);
     field public static final int DEACTIVATION_DESELECTED = 1; // 0x1
     field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
-    field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_APDU_SERVICE";
-    field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";
+    field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_APDU_SERVICE";
+    field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";
   }
 
   public abstract class HostNfcFService extends android.app.Service {
@@ -30410,25 +30700,25 @@
     method public abstract byte[] processNfcFPacket(byte[], android.os.Bundle);
     method public final void sendResponsePacket(byte[]);
     field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
-    field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_NFCF_SERVICE";
-    field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.host_nfcf_service";
+    field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_NFCF_SERVICE";
+    field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_nfcf_service";
   }
 
   public final class NfcFCardEmulation {
     method public boolean disableService(android.app.Activity) throws java.lang.RuntimeException;
     method public boolean enableService(android.app.Activity, android.content.ComponentName) throws java.lang.RuntimeException;
-    method public static synchronized android.nfc.cardemulation.NfcFCardEmulation getInstance(android.nfc.NfcAdapter);
-    method public java.lang.String getNfcid2ForService(android.content.ComponentName) throws java.lang.RuntimeException;
-    method public java.lang.String getSystemCodeForService(android.content.ComponentName) throws java.lang.RuntimeException;
-    method public boolean registerSystemCodeForService(android.content.ComponentName, java.lang.String) throws java.lang.RuntimeException;
-    method public boolean setNfcid2ForService(android.content.ComponentName, java.lang.String) throws java.lang.RuntimeException;
+    method public static android.nfc.cardemulation.NfcFCardEmulation getInstance(android.nfc.NfcAdapter);
+    method public String getNfcid2ForService(android.content.ComponentName) throws java.lang.RuntimeException;
+    method public String getSystemCodeForService(android.content.ComponentName) throws java.lang.RuntimeException;
+    method public boolean registerSystemCodeForService(android.content.ComponentName, String) throws java.lang.RuntimeException;
+    method public boolean setNfcid2ForService(android.content.ComponentName, String) throws java.lang.RuntimeException;
     method public boolean unregisterSystemCodeForService(android.content.ComponentName) throws java.lang.RuntimeException;
   }
 
   public abstract class OffHostApduService extends android.app.Service {
     ctor public OffHostApduService();
-    field public static final java.lang.String SERVICE_INTERFACE = "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE";
-    field public static final java.lang.String SERVICE_META_DATA = "android.nfc.cardemulation.off_host_apdu_service";
+    field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE";
+    field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.off_host_apdu_service";
   }
 
 }
@@ -30436,11 +30726,15 @@
 package android.nfc.tech {
 
   public final class IsoDep implements android.nfc.tech.TagTechnology {
+    method public void close() throws java.io.IOException;
+    method public void connect() throws java.io.IOException;
     method public static android.nfc.tech.IsoDep get(android.nfc.Tag);
     method public byte[] getHiLayerResponse();
     method public byte[] getHistoricalBytes();
     method public int getMaxTransceiveLength();
+    method public android.nfc.Tag getTag();
     method public int getTimeout();
+    method public boolean isConnected();
     method public boolean isExtendedLengthApduSupported();
     method public void setTimeout(int);
     method public byte[] transceive(byte[]) throws java.io.IOException;
@@ -30450,6 +30744,8 @@
     method public boolean authenticateSectorWithKeyA(int, byte[]) throws java.io.IOException;
     method public boolean authenticateSectorWithKeyB(int, byte[]) throws java.io.IOException;
     method public int blockToSector(int);
+    method public void close() throws java.io.IOException;
+    method public void connect() throws java.io.IOException;
     method public void decrement(int, int) throws java.io.IOException;
     method public static android.nfc.tech.MifareClassic get(android.nfc.Tag);
     method public int getBlockCount();
@@ -30457,9 +30753,11 @@
     method public int getMaxTransceiveLength();
     method public int getSectorCount();
     method public int getSize();
+    method public android.nfc.Tag getTag();
     method public int getTimeout();
     method public int getType();
     method public void increment(int, int) throws java.io.IOException;
+    method public boolean isConnected();
     method public byte[] readBlock(int) throws java.io.IOException;
     method public void restore(int) throws java.io.IOException;
     method public int sectorToBlock(int);
@@ -30482,10 +30780,14 @@
   }
 
   public final class MifareUltralight implements android.nfc.tech.TagTechnology {
+    method public void close() throws java.io.IOException;
+    method public void connect() throws java.io.IOException;
     method public static android.nfc.tech.MifareUltralight get(android.nfc.Tag);
     method public int getMaxTransceiveLength();
+    method public android.nfc.Tag getTag();
     method public int getTimeout();
     method public int getType();
+    method public boolean isConnected();
     method public byte[] readPages(int) throws java.io.IOException;
     method public void setTimeout(int);
     method public byte[] transceive(byte[]) throws java.io.IOException;
@@ -30498,75 +30800,103 @@
 
   public final class Ndef implements android.nfc.tech.TagTechnology {
     method public boolean canMakeReadOnly();
+    method public void close() throws java.io.IOException;
+    method public void connect() throws java.io.IOException;
     method public static android.nfc.tech.Ndef get(android.nfc.Tag);
     method public android.nfc.NdefMessage getCachedNdefMessage();
     method public int getMaxSize();
     method public android.nfc.NdefMessage getNdefMessage() throws android.nfc.FormatException, java.io.IOException;
-    method public java.lang.String getType();
+    method public android.nfc.Tag getTag();
+    method public String getType();
+    method public boolean isConnected();
     method public boolean isWritable();
     method public boolean makeReadOnly() throws java.io.IOException;
     method public void writeNdefMessage(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException;
-    field public static final java.lang.String MIFARE_CLASSIC = "com.nxp.ndef.mifareclassic";
-    field public static final java.lang.String NFC_FORUM_TYPE_1 = "org.nfcforum.ndef.type1";
-    field public static final java.lang.String NFC_FORUM_TYPE_2 = "org.nfcforum.ndef.type2";
-    field public static final java.lang.String NFC_FORUM_TYPE_3 = "org.nfcforum.ndef.type3";
-    field public static final java.lang.String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4";
+    field public static final String MIFARE_CLASSIC = "com.nxp.ndef.mifareclassic";
+    field public static final String NFC_FORUM_TYPE_1 = "org.nfcforum.ndef.type1";
+    field public static final String NFC_FORUM_TYPE_2 = "org.nfcforum.ndef.type2";
+    field public static final String NFC_FORUM_TYPE_3 = "org.nfcforum.ndef.type3";
+    field public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4";
   }
 
   public final class NdefFormatable implements android.nfc.tech.TagTechnology {
+    method public void close() throws java.io.IOException;
+    method public void connect() throws java.io.IOException;
     method public void format(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException;
     method public void formatReadOnly(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException;
     method public static android.nfc.tech.NdefFormatable get(android.nfc.Tag);
+    method public android.nfc.Tag getTag();
+    method public boolean isConnected();
   }
 
   public final class NfcA implements android.nfc.tech.TagTechnology {
+    method public void close() throws java.io.IOException;
+    method public void connect() throws java.io.IOException;
     method public static android.nfc.tech.NfcA get(android.nfc.Tag);
     method public byte[] getAtqa();
     method public int getMaxTransceiveLength();
     method public short getSak();
+    method public android.nfc.Tag getTag();
     method public int getTimeout();
+    method public boolean isConnected();
     method public void setTimeout(int);
     method public byte[] transceive(byte[]) throws java.io.IOException;
   }
 
   public final class NfcB implements android.nfc.tech.TagTechnology {
+    method public void close() throws java.io.IOException;
+    method public void connect() throws java.io.IOException;
     method public static android.nfc.tech.NfcB get(android.nfc.Tag);
     method public byte[] getApplicationData();
     method public int getMaxTransceiveLength();
     method public byte[] getProtocolInfo();
+    method public android.nfc.Tag getTag();
+    method public boolean isConnected();
     method public byte[] transceive(byte[]) throws java.io.IOException;
   }
 
   public final class NfcBarcode implements android.nfc.tech.TagTechnology {
+    method public void close() throws java.io.IOException;
+    method public void connect() throws java.io.IOException;
     method public static android.nfc.tech.NfcBarcode get(android.nfc.Tag);
     method public byte[] getBarcode();
+    method public android.nfc.Tag getTag();
     method public int getType();
+    method public boolean isConnected();
     field public static final int TYPE_KOVIO = 1; // 0x1
     field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
   }
 
   public final class NfcF implements android.nfc.tech.TagTechnology {
+    method public void close() throws java.io.IOException;
+    method public void connect() throws java.io.IOException;
     method public static android.nfc.tech.NfcF get(android.nfc.Tag);
     method public byte[] getManufacturer();
     method public int getMaxTransceiveLength();
     method public byte[] getSystemCode();
+    method public android.nfc.Tag getTag();
     method public int getTimeout();
+    method public boolean isConnected();
     method public void setTimeout(int);
     method public byte[] transceive(byte[]) throws java.io.IOException;
   }
 
   public final class NfcV implements android.nfc.tech.TagTechnology {
+    method public void close() throws java.io.IOException;
+    method public void connect() throws java.io.IOException;
     method public static android.nfc.tech.NfcV get(android.nfc.Tag);
     method public byte getDsfId();
     method public int getMaxTransceiveLength();
     method public byte getResponseFlags();
+    method public android.nfc.Tag getTag();
+    method public boolean isConnected();
     method public byte[] transceive(byte[]) throws java.io.IOException;
   }
 
-  public abstract interface TagTechnology implements java.io.Closeable {
-    method public abstract void connect() throws java.io.IOException;
-    method public abstract android.nfc.Tag getTag();
-    method public abstract boolean isConnected();
+  public interface TagTechnology extends java.io.Closeable {
+    method public void connect() throws java.io.IOException;
+    method public android.nfc.Tag getTag();
+    method public boolean isConnected();
   }
 
 }
@@ -30582,8 +30912,8 @@
     method public static android.opengl.EGLContext eglCreateContext(android.opengl.EGLDisplay, android.opengl.EGLConfig, android.opengl.EGLContext, int[], int);
     method public static android.opengl.EGLSurface eglCreatePbufferFromClientBuffer(android.opengl.EGLDisplay, int, int, android.opengl.EGLConfig, int[], int);
     method public static android.opengl.EGLSurface eglCreatePbufferSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int[], int);
-    method public static deprecated android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
-    method public static android.opengl.EGLSurface eglCreateWindowSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.lang.Object, int[], int);
+    method @Deprecated public static android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
+    method public static android.opengl.EGLSurface eglCreateWindowSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, Object, int[], int);
     method public static boolean eglDestroyContext(android.opengl.EGLDisplay, android.opengl.EGLContext);
     method public static boolean eglDestroySurface(android.opengl.EGLDisplay, android.opengl.EGLSurface);
     method public static boolean eglGetConfigAttrib(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
@@ -30597,7 +30927,7 @@
     method public static boolean eglMakeCurrent(android.opengl.EGLDisplay, android.opengl.EGLSurface, android.opengl.EGLSurface, android.opengl.EGLContext);
     method public static int eglQueryAPI();
     method public static boolean eglQueryContext(android.opengl.EGLDisplay, android.opengl.EGLContext, int, int[], int);
-    method public static java.lang.String eglQueryString(android.opengl.EGLDisplay, int);
+    method public static String eglQueryString(android.opengl.EGLDisplay, int);
     method public static boolean eglQuerySurface(android.opengl.EGLDisplay, android.opengl.EGLSurface, int, int[], int);
     method public static boolean eglReleaseTexImage(android.opengl.EGLDisplay, android.opengl.EGLSurface, int);
     method public static boolean eglReleaseThread();
@@ -30807,9 +31137,9 @@
   }
 
   public abstract class EGLObjectHandle {
-    ctor protected deprecated EGLObjectHandle(int);
+    ctor @Deprecated protected EGLObjectHandle(int);
     ctor protected EGLObjectHandle(long);
-    method public deprecated int getHandle();
+    method @Deprecated public int getHandle();
     method public long getNativeHandle();
   }
 
@@ -30914,7 +31244,7 @@
     method public static int glGetError();
     method public static void glGetIntegerv(int, int[], int);
     method public static void glGetIntegerv(int, java.nio.IntBuffer);
-    method public static java.lang.String glGetString(int);
+    method public static String glGetString(int);
     method public static void glHint(int, int);
     method public static void glLightModelf(int, float);
     method public static void glLightModelfv(int, float[], int);
@@ -31663,7 +31993,7 @@
     ctor public GLES20();
     method public static void glActiveTexture(int);
     method public static void glAttachShader(int, int);
-    method public static void glBindAttribLocation(int, int, java.lang.String);
+    method public static void glBindAttribLocation(int, int, String);
     method public static void glBindBuffer(int, int);
     method public static void glBindFramebuffer(int, int);
     method public static void glBindRenderbuffer(int, int);
@@ -31725,14 +32055,14 @@
     method public static void glGenTextures(int, java.nio.IntBuffer);
     method public static void glGenerateMipmap(int);
     method public static void glGetActiveAttrib(int, int, int, int[], int, int[], int, int[], int, byte[], int);
-    method public static java.lang.String glGetActiveAttrib(int, int, int[], int, int[], int);
-    method public static java.lang.String glGetActiveAttrib(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
+    method public static String glGetActiveAttrib(int, int, int[], int, int[], int);
+    method public static String glGetActiveAttrib(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static void glGetActiveUniform(int, int, int, int[], int, int[], int, int[], int, byte[], int);
-    method public static java.lang.String glGetActiveUniform(int, int, int[], int, int[], int);
-    method public static java.lang.String glGetActiveUniform(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
+    method public static String glGetActiveUniform(int, int, int[], int, int[], int);
+    method public static String glGetActiveUniform(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static void glGetAttachedShaders(int, int, int[], int, int[], int);
     method public static void glGetAttachedShaders(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
-    method public static int glGetAttribLocation(int, java.lang.String);
+    method public static int glGetAttribLocation(int, String);
     method public static void glGetBooleanv(int, boolean[], int);
     method public static void glGetBooleanv(int, java.nio.IntBuffer);
     method public static void glGetBufferParameteriv(int, int, int[], int);
@@ -31744,24 +32074,24 @@
     method public static void glGetFramebufferAttachmentParameteriv(int, int, int, java.nio.IntBuffer);
     method public static void glGetIntegerv(int, int[], int);
     method public static void glGetIntegerv(int, java.nio.IntBuffer);
-    method public static java.lang.String glGetProgramInfoLog(int);
+    method public static String glGetProgramInfoLog(int);
     method public static void glGetProgramiv(int, int, int[], int);
     method public static void glGetProgramiv(int, int, java.nio.IntBuffer);
     method public static void glGetRenderbufferParameteriv(int, int, int[], int);
     method public static void glGetRenderbufferParameteriv(int, int, java.nio.IntBuffer);
-    method public static java.lang.String glGetShaderInfoLog(int);
+    method public static String glGetShaderInfoLog(int);
     method public static void glGetShaderPrecisionFormat(int, int, int[], int, int[], int);
     method public static void glGetShaderPrecisionFormat(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static void glGetShaderSource(int, int, int[], int, byte[], int);
-    method public static java.lang.String glGetShaderSource(int);
+    method public static String glGetShaderSource(int);
     method public static void glGetShaderiv(int, int, int[], int);
     method public static void glGetShaderiv(int, int, java.nio.IntBuffer);
-    method public static java.lang.String glGetString(int);
+    method public static String glGetString(int);
     method public static void glGetTexParameterfv(int, int, float[], int);
     method public static void glGetTexParameterfv(int, int, java.nio.FloatBuffer);
     method public static void glGetTexParameteriv(int, int, int[], int);
     method public static void glGetTexParameteriv(int, int, java.nio.IntBuffer);
-    method public static int glGetUniformLocation(int, java.lang.String);
+    method public static int glGetUniformLocation(int, String);
     method public static void glGetUniformfv(int, int, float[], int);
     method public static void glGetUniformfv(int, int, java.nio.FloatBuffer);
     method public static void glGetUniformiv(int, int, int[], int);
@@ -31789,7 +32119,7 @@
     method public static void glScissor(int, int, int, int);
     method public static void glShaderBinary(int, int[], int, int, java.nio.Buffer, int);
     method public static void glShaderBinary(int, java.nio.IntBuffer, int, java.nio.Buffer, int);
-    method public static void glShaderSource(int, java.lang.String);
+    method public static void glShaderSource(int, String);
     method public static void glStencilFunc(int, int, int);
     method public static void glStencilFuncSeparate(int, int, int, int);
     method public static void glStencilMask(int);
@@ -32072,7 +32402,7 @@
     field public static final int GL_STENCIL_CLEAR_VALUE = 2961; // 0xb91
     field public static final int GL_STENCIL_FAIL = 2964; // 0xb94
     field public static final int GL_STENCIL_FUNC = 2962; // 0xb92
-    field public static final deprecated int GL_STENCIL_INDEX = 6401; // 0x1901
+    field @Deprecated public static final int GL_STENCIL_INDEX = 6401; // 0x1901
     field public static final int GL_STENCIL_INDEX8 = 36168; // 0x8d48
     field public static final int GL_STENCIL_PASS_DEPTH_FAIL = 2965; // 0xb95
     field public static final int GL_STENCIL_PASS_DEPTH_PASS = 2966; // 0xb96
@@ -32210,7 +32540,7 @@
     method public static void glGenVertexArrays(int, java.nio.IntBuffer);
     method public static void glGetActiveUniformBlockName(int, int, int, int[], int, byte[], int);
     method public static void glGetActiveUniformBlockName(int, int, java.nio.Buffer, java.nio.Buffer);
-    method public static java.lang.String glGetActiveUniformBlockName(int, int);
+    method public static String glGetActiveUniformBlockName(int, int);
     method public static void glGetActiveUniformBlockiv(int, int, int, int[], int);
     method public static void glGetActiveUniformBlockiv(int, int, int, java.nio.IntBuffer);
     method public static void glGetActiveUniformsiv(int, int, int[], int, int, int[], int);
@@ -32218,7 +32548,7 @@
     method public static void glGetBufferParameteri64v(int, int, long[], int);
     method public static void glGetBufferParameteri64v(int, int, java.nio.LongBuffer);
     method public static java.nio.Buffer glGetBufferPointerv(int, int);
-    method public static int glGetFragDataLocation(int, java.lang.String);
+    method public static int glGetFragDataLocation(int, String);
     method public static void glGetInteger64i_v(int, int, long[], int);
     method public static void glGetInteger64i_v(int, int, java.nio.LongBuffer);
     method public static void glGetInteger64v(int, long[], int);
@@ -32237,17 +32567,17 @@
     method public static void glGetSamplerParameterfv(int, int, java.nio.FloatBuffer);
     method public static void glGetSamplerParameteriv(int, int, int[], int);
     method public static void glGetSamplerParameteriv(int, int, java.nio.IntBuffer);
-    method public static java.lang.String glGetStringi(int, int);
+    method public static String glGetStringi(int, int);
     method public static void glGetSynciv(long, int, int, int[], int, int[], int);
     method public static void glGetSynciv(long, int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static void glGetTransformFeedbackVarying(int, int, int, int[], int, int[], int, int[], int, byte[], int);
-    method public static deprecated void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method @Deprecated public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
     method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
-    method public static java.lang.String glGetTransformFeedbackVarying(int, int, int[], int, int[], int);
-    method public static java.lang.String glGetTransformFeedbackVarying(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
-    method public static int glGetUniformBlockIndex(int, java.lang.String);
-    method public static void glGetUniformIndices(int, java.lang.String[], int[], int);
-    method public static void glGetUniformIndices(int, java.lang.String[], java.nio.IntBuffer);
+    method public static String glGetTransformFeedbackVarying(int, int, int[], int, int[], int);
+    method public static String glGetTransformFeedbackVarying(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
+    method public static int glGetUniformBlockIndex(int, String);
+    method public static void glGetUniformIndices(int, String[], int[], int);
+    method public static void glGetUniformIndices(int, String[], java.nio.IntBuffer);
     method public static void glGetUniformuiv(int, int, int[], int);
     method public static void glGetUniformuiv(int, int, java.nio.IntBuffer);
     method public static void glGetVertexAttribIiv(int, int, int[], int);
@@ -32283,7 +32613,7 @@
     method public static void glTexStorage3D(int, int, int, int, int, int);
     method public static void glTexSubImage3D(int, int, int, int, int, int, int, int, int, int, java.nio.Buffer);
     method public static void glTexSubImage3D(int, int, int, int, int, int, int, int, int, int, int);
-    method public static void glTransformFeedbackVaryings(int, java.lang.String[], int);
+    method public static void glTransformFeedbackVaryings(int, String[], int);
     method public static void glUniform1ui(int, int);
     method public static void glUniform1uiv(int, int, int[], int);
     method public static void glUniform1uiv(int, int, java.nio.IntBuffer);
@@ -32632,7 +32962,7 @@
     method public static void glBindImageTexture(int, int, int, boolean, int, int, int);
     method public static void glBindProgramPipeline(int);
     method public static void glBindVertexBuffer(int, int, long, int);
-    method public static int glCreateShaderProgramv(int, java.lang.String[]);
+    method public static int glCreateShaderProgramv(int, String[]);
     method public static void glDeleteProgramPipelines(int, int[], int);
     method public static void glDeleteProgramPipelines(int, java.nio.IntBuffer);
     method public static void glDispatchCompute(int, int, int);
@@ -32650,12 +32980,12 @@
     method public static void glGetMultisamplefv(int, int, java.nio.FloatBuffer);
     method public static void glGetProgramInterfaceiv(int, int, int, int[], int);
     method public static void glGetProgramInterfaceiv(int, int, int, java.nio.IntBuffer);
-    method public static java.lang.String glGetProgramPipelineInfoLog(int);
+    method public static String glGetProgramPipelineInfoLog(int);
     method public static void glGetProgramPipelineiv(int, int, int[], int);
     method public static void glGetProgramPipelineiv(int, int, java.nio.IntBuffer);
-    method public static int glGetProgramResourceIndex(int, int, java.lang.String);
-    method public static int glGetProgramResourceLocation(int, int, java.lang.String);
-    method public static java.lang.String glGetProgramResourceName(int, int, int);
+    method public static int glGetProgramResourceIndex(int, int, String);
+    method public static int glGetProgramResourceLocation(int, int, String);
+    method public static String glGetProgramResourceName(int, int, int);
     method public static void glGetProgramResourceiv(int, int, int, int, int[], int, int, int[], int, int[], int);
     method public static void glGetProgramResourceiv(int, int, int, int, java.nio.IntBuffer, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static void glGetTexLevelParameterfv(int, int, int, float[], int);
@@ -32913,17 +33243,17 @@
     method public static void glDebugMessageCallbackKHR(android.opengl.GLES31Ext.DebugProcKHR);
     method public static void glDebugMessageControlKHR(int, int, int, int, int[], int, boolean);
     method public static void glDebugMessageControlKHR(int, int, int, int, java.nio.IntBuffer, boolean);
-    method public static void glDebugMessageInsertKHR(int, int, int, int, java.lang.String);
+    method public static void glDebugMessageInsertKHR(int, int, int, int, String);
     method public static void glDisableiEXT(int, int);
     method public static void glEnableiEXT(int, int);
     method public static void glFramebufferTextureEXT(int, int, int, int);
     method public static android.opengl.GLES31Ext.DebugProcKHR glGetDebugMessageCallbackKHR();
     method public static int glGetDebugMessageLogKHR(int, int, int[], int, int[], int, int[], int, int[], int, int[], int, byte[], int);
     method public static int glGetDebugMessageLogKHR(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
-    method public static java.lang.String[] glGetDebugMessageLogKHR(int, int[], int, int[], int, int[], int, int[], int);
-    method public static java.lang.String[] glGetDebugMessageLogKHR(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer);
-    method public static java.lang.String glGetObjectLabelKHR(int, int);
-    method public static java.lang.String glGetObjectPtrLabelKHR(long);
+    method public static String[] glGetDebugMessageLogKHR(int, int[], int, int[], int, int[], int, int[], int);
+    method public static String[] glGetDebugMessageLogKHR(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer);
+    method public static String glGetObjectLabelKHR(int, int);
+    method public static String glGetObjectPtrLabelKHR(long);
     method public static void glGetSamplerParameterIivEXT(int, int, int[], int);
     method public static void glGetSamplerParameterIivEXT(int, int, java.nio.IntBuffer);
     method public static void glGetSamplerParameterIuivEXT(int, int, int[], int);
@@ -32934,12 +33264,12 @@
     method public static void glGetTexParameterIuivEXT(int, int, java.nio.IntBuffer);
     method public static boolean glIsEnablediEXT(int, int);
     method public static void glMinSampleShadingOES(float);
-    method public static void glObjectLabelKHR(int, int, int, java.lang.String);
-    method public static void glObjectPtrLabelKHR(long, java.lang.String);
+    method public static void glObjectLabelKHR(int, int, int, String);
+    method public static void glObjectPtrLabelKHR(long, String);
     method public static void glPatchParameteriEXT(int, int);
     method public static void glPopDebugGroupKHR();
     method public static void glPrimitiveBoundingBoxEXT(float, float, float, float, float, float, float, float);
-    method public static void glPushDebugGroupKHR(int, int, int, java.lang.String);
+    method public static void glPushDebugGroupKHR(int, int, int, String);
     method public static void glSamplerParameterIivEXT(int, int, int[], int);
     method public static void glSamplerParameterIivEXT(int, int, java.nio.IntBuffer);
     method public static void glSamplerParameterIuivEXT(int, int, int[], int);
@@ -33153,8 +33483,8 @@
     field public static final int GL_VERTEX_ARRAY_KHR = 32884; // 0x8074
   }
 
-  public static abstract interface GLES31Ext.DebugProcKHR {
-    method public abstract void onMessage(int, int, int, int, java.lang.String);
+  public static interface GLES31Ext.DebugProcKHR {
+    method public void onMessage(int, int, int, int, String);
   }
 
   public class GLES32 extends android.opengl.GLES31 {
@@ -33168,7 +33498,7 @@
     method public static void glDebugMessageCallback(android.opengl.GLES32.DebugProc);
     method public static void glDebugMessageControl(int, int, int, int, int[], int, boolean);
     method public static void glDebugMessageControl(int, int, int, int, java.nio.IntBuffer, boolean);
-    method public static void glDebugMessageInsert(int, int, int, int, int, java.lang.String);
+    method public static void glDebugMessageInsert(int, int, int, int, int, String);
     method public static void glDisablei(int, int);
     method public static void glDrawElementsBaseVertex(int, int, int, java.nio.Buffer, int);
     method public static void glDrawElementsInstancedBaseVertex(int, int, int, java.nio.Buffer, int, int);
@@ -33178,11 +33508,11 @@
     method public static void glFramebufferTexture(int, int, int, int);
     method public static int glGetDebugMessageLog(int, int, int[], int, int[], int, int[], int, int[], int, int[], int, byte[], int);
     method public static int glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
-    method public static java.lang.String[] glGetDebugMessageLog(int, int[], int, int[], int, int[], int, int[], int);
-    method public static java.lang.String[] glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer);
+    method public static String[] glGetDebugMessageLog(int, int[], int, int[], int, int[], int, int[], int);
+    method public static String[] glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static int glGetGraphicsResetStatus();
-    method public static java.lang.String glGetObjectLabel(int, int);
-    method public static java.lang.String glGetObjectPtrLabel(long);
+    method public static String glGetObjectLabel(int, int);
+    method public static String glGetObjectPtrLabel(long);
     method public static long glGetPointerv(int);
     method public static void glGetSamplerParameterIiv(int, int, int[], int);
     method public static void glGetSamplerParameterIiv(int, int, java.nio.IntBuffer);
@@ -33200,12 +33530,12 @@
     method public static void glGetnUniformuiv(int, int, int, java.nio.IntBuffer);
     method public static boolean glIsEnabledi(int, int);
     method public static void glMinSampleShading(float);
-    method public static void glObjectLabel(int, int, int, java.lang.String);
-    method public static void glObjectPtrLabel(long, java.lang.String);
+    method public static void glObjectLabel(int, int, int, String);
+    method public static void glObjectPtrLabel(long, String);
     method public static void glPatchParameteri(int, int);
     method public static void glPopDebugGroup();
     method public static void glPrimitiveBoundingBox(float, float, float, float, float, float, float, float);
-    method public static void glPushDebugGroup(int, int, int, java.lang.String);
+    method public static void glPushDebugGroup(int, int, int, String);
     method public static void glReadnPixels(int, int, int, int, int, int, int, java.nio.Buffer);
     method public static void glSamplerParameterIiv(int, int, int[], int);
     method public static void glSamplerParameterIiv(int, int, java.nio.IntBuffer);
@@ -33426,13 +33756,13 @@
     field public static final int GL_VERTEX_ARRAY = 32884; // 0x8074
   }
 
-  public static abstract interface GLES32.DebugProc {
-    method public abstract void onMessage(int, int, int, int, java.lang.String);
+  public static interface GLES32.DebugProc {
+    method public void onMessage(int, int, int, int, String);
   }
 
   public class GLException extends java.lang.RuntimeException {
     ctor public GLException(int);
-    ctor public GLException(int, java.lang.String);
+    ctor public GLException(int, String);
   }
 
   public class GLSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback2 {
@@ -33443,7 +33773,7 @@
     method public int getRenderMode();
     method public void onPause();
     method public void onResume();
-    method public void queueEvent(java.lang.Runnable);
+    method public void queueEvent(Runnable);
     method public void requestRender();
     method public void setDebugFlags(int);
     method public void setEGLConfigChooser(android.opengl.GLSurfaceView.EGLConfigChooser);
@@ -33459,40 +33789,40 @@
     method public void surfaceChanged(android.view.SurfaceHolder, int, int, int);
     method public void surfaceCreated(android.view.SurfaceHolder);
     method public void surfaceDestroyed(android.view.SurfaceHolder);
-    method public deprecated void surfaceRedrawNeeded(android.view.SurfaceHolder);
+    method @Deprecated public void surfaceRedrawNeeded(android.view.SurfaceHolder);
     field public static final int DEBUG_CHECK_GL_ERROR = 1; // 0x1
     field public static final int DEBUG_LOG_GL_CALLS = 2; // 0x2
     field public static final int RENDERMODE_CONTINUOUSLY = 1; // 0x1
     field public static final int RENDERMODE_WHEN_DIRTY = 0; // 0x0
   }
 
-  public static abstract interface GLSurfaceView.EGLConfigChooser {
-    method public abstract javax.microedition.khronos.egl.EGLConfig chooseConfig(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay);
+  public static interface GLSurfaceView.EGLConfigChooser {
+    method public javax.microedition.khronos.egl.EGLConfig chooseConfig(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay);
   }
 
-  public static abstract interface GLSurfaceView.EGLContextFactory {
-    method public abstract javax.microedition.khronos.egl.EGLContext createContext(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig);
-    method public abstract void destroyContext(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLContext);
+  public static interface GLSurfaceView.EGLContextFactory {
+    method public javax.microedition.khronos.egl.EGLContext createContext(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig);
+    method public void destroyContext(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLContext);
   }
 
-  public static abstract interface GLSurfaceView.EGLWindowSurfaceFactory {
-    method public abstract javax.microedition.khronos.egl.EGLSurface createWindowSurface(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object);
-    method public abstract void destroySurface(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface);
+  public static interface GLSurfaceView.EGLWindowSurfaceFactory {
+    method public javax.microedition.khronos.egl.EGLSurface createWindowSurface(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, Object);
+    method public void destroySurface(javax.microedition.khronos.egl.EGL10, javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface);
   }
 
-  public static abstract interface GLSurfaceView.GLWrapper {
-    method public abstract javax.microedition.khronos.opengles.GL wrap(javax.microedition.khronos.opengles.GL);
+  public static interface GLSurfaceView.GLWrapper {
+    method public javax.microedition.khronos.opengles.GL wrap(javax.microedition.khronos.opengles.GL);
   }
 
-  public static abstract interface GLSurfaceView.Renderer {
-    method public abstract void onDrawFrame(javax.microedition.khronos.opengles.GL10);
-    method public abstract void onSurfaceChanged(javax.microedition.khronos.opengles.GL10, int, int);
-    method public abstract void onSurfaceCreated(javax.microedition.khronos.opengles.GL10, javax.microedition.khronos.egl.EGLConfig);
+  public static interface GLSurfaceView.Renderer {
+    method public void onDrawFrame(javax.microedition.khronos.opengles.GL10);
+    method public void onSurfaceChanged(javax.microedition.khronos.opengles.GL10, int, int);
+    method public void onSurfaceCreated(javax.microedition.khronos.opengles.GL10, javax.microedition.khronos.egl.EGLConfig);
   }
 
   public class GLU {
     ctor public GLU();
-    method public static java.lang.String gluErrorString(int);
+    method public static String gluErrorString(int);
     method public static void gluLookAt(javax.microedition.khronos.opengles.GL10, float, float, float, float, float, float, float, float, float);
     method public static void gluOrtho2D(javax.microedition.khronos.opengles.GL10, float, float, float, float);
     method public static void gluPerspective(javax.microedition.khronos.opengles.GL10, float, float, float, float);
@@ -33501,7 +33831,7 @@
   }
 
   public final class GLUtils {
-    method public static java.lang.String getEGLErrorString(int);
+    method public static String getEGLErrorString(int);
     method public static int getInternalFormat(android.graphics.Bitmap);
     method public static int getType(android.graphics.Bitmap);
     method public static void texImage2D(int, int, int, android.graphics.Bitmap, int);
@@ -33512,7 +33842,7 @@
   }
 
   public class Matrix {
-    ctor public deprecated Matrix();
+    ctor @Deprecated public Matrix();
     method public static void frustumM(float[], int, float, float, float, float, float, float);
     method public static boolean invertM(float[], int, float[], int);
     method public static float length(float, float, float);
@@ -33547,70 +33877,68 @@
   public abstract class AsyncTask<Params, Progress, Result> {
     ctor public AsyncTask();
     method public final boolean cancel(boolean);
-    method protected abstract Result doInBackground(Params...);
-    method public final android.os.AsyncTask<Params, Progress, Result> execute(Params...);
-    method public static void execute(java.lang.Runnable);
-    method public final android.os.AsyncTask<Params, Progress, Result> executeOnExecutor(java.util.concurrent.Executor, Params...);
+    method @WorkerThread protected abstract Result doInBackground(Params...);
+    method @MainThread public final android.os.AsyncTask<Params,Progress,Result> execute(Params...);
+    method @MainThread public static void execute(Runnable);
+    method @MainThread public final android.os.AsyncTask<Params,Progress,Result> executeOnExecutor(java.util.concurrent.Executor, Params...);
     method public final Result get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
     method public final Result get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
     method public final android.os.AsyncTask.Status getStatus();
     method public final boolean isCancelled();
-    method protected void onCancelled(Result);
-    method protected void onCancelled();
-    method protected void onPostExecute(Result);
-    method protected void onPreExecute();
-    method protected void onProgressUpdate(Progress...);
-    method protected final void publishProgress(Progress...);
+    method @MainThread protected void onCancelled(Result);
+    method @MainThread protected void onCancelled();
+    method @MainThread protected void onPostExecute(Result);
+    method @MainThread protected void onPreExecute();
+    method @MainThread protected void onProgressUpdate(Progress...);
+    method @WorkerThread protected final void publishProgress(Progress...);
     field public static final java.util.concurrent.Executor SERIAL_EXECUTOR;
     field public static final java.util.concurrent.Executor THREAD_POOL_EXECUTOR;
   }
 
-  public static final class AsyncTask.Status extends java.lang.Enum {
-    method public static android.os.AsyncTask.Status valueOf(java.lang.String);
-    method public static final android.os.AsyncTask.Status[] values();
+  public enum AsyncTask.Status {
     enum_constant public static final android.os.AsyncTask.Status FINISHED;
     enum_constant public static final android.os.AsyncTask.Status PENDING;
     enum_constant public static final android.os.AsyncTask.Status RUNNING;
   }
 
   public class BadParcelableException extends android.util.AndroidRuntimeException {
-    ctor public BadParcelableException(java.lang.String);
-    ctor public BadParcelableException(java.lang.Exception);
+    ctor public BadParcelableException(String);
+    ctor public BadParcelableException(Exception);
   }
 
   public class BaseBundle {
     method public void clear();
-    method public boolean containsKey(java.lang.String);
-    method public java.lang.Object get(java.lang.String);
-    method public boolean getBoolean(java.lang.String);
-    method public boolean getBoolean(java.lang.String, boolean);
-    method public boolean[] getBooleanArray(java.lang.String);
-    method public double getDouble(java.lang.String);
-    method public double getDouble(java.lang.String, double);
-    method public double[] getDoubleArray(java.lang.String);
-    method public int getInt(java.lang.String);
-    method public int getInt(java.lang.String, int);
-    method public int[] getIntArray(java.lang.String);
-    method public long getLong(java.lang.String);
-    method public long getLong(java.lang.String, long);
-    method public long[] getLongArray(java.lang.String);
-    method public java.lang.String getString(java.lang.String);
-    method public java.lang.String getString(java.lang.String, java.lang.String);
-    method public java.lang.String[] getStringArray(java.lang.String);
+    method public boolean containsKey(String);
+    method @Nullable public Object get(String);
+    method public boolean getBoolean(String);
+    method public boolean getBoolean(String, boolean);
+    method @Nullable public boolean[] getBooleanArray(@Nullable String);
+    method public double getDouble(String);
+    method public double getDouble(String, double);
+    method @Nullable public double[] getDoubleArray(@Nullable String);
+    method public int getInt(String);
+    method public int getInt(String, int);
+    method @Nullable public int[] getIntArray(@Nullable String);
+    method public long getLong(String);
+    method public long getLong(String, long);
+    method @Nullable public long[] getLongArray(@Nullable String);
+    method @Nullable public String getString(@Nullable String);
+    method public String getString(@Nullable String, String);
+    method @Nullable public String[] getStringArray(@Nullable String);
     method public boolean isEmpty();
     method public java.util.Set<java.lang.String> keySet();
     method public void putAll(android.os.PersistableBundle);
-    method public void putBoolean(java.lang.String, boolean);
-    method public void putBooleanArray(java.lang.String, boolean[]);
-    method public void putDouble(java.lang.String, double);
-    method public void putDoubleArray(java.lang.String, double[]);
-    method public void putInt(java.lang.String, int);
-    method public void putIntArray(java.lang.String, int[]);
-    method public void putLong(java.lang.String, long);
-    method public void putLongArray(java.lang.String, long[]);
-    method public void putString(java.lang.String, java.lang.String);
-    method public void putStringArray(java.lang.String, java.lang.String[]);
-    method public void remove(java.lang.String);
+    method public void putBoolean(@Nullable String, boolean);
+    method public void putBooleanArray(@Nullable String, @Nullable boolean[]);
+    method public void putDouble(@Nullable String, double);
+    method public void putDoubleArray(@Nullable String, @Nullable double[]);
+    method public void putInt(@Nullable String, int);
+    method public void putIntArray(@Nullable String, @Nullable int[]);
+    method public void putLong(@Nullable String, long);
+    method public void putLongArray(@Nullable String, @Nullable long[]);
+    method public void putString(@Nullable String, @Nullable String);
+    method public void putStringArray(@Nullable String, @Nullable String[]);
+    method public void remove(String);
     method public int size();
   }
 
@@ -33619,8 +33947,8 @@
     method public int getIntProperty(int);
     method public long getLongProperty(int);
     method public boolean isCharging();
-    field public static final java.lang.String ACTION_CHARGING = "android.os.action.CHARGING";
-    field public static final java.lang.String ACTION_DISCHARGING = "android.os.action.DISCHARGING";
+    field public static final String ACTION_CHARGING = "android.os.action.CHARGING";
+    field public static final String ACTION_DISCHARGING = "android.os.action.DISCHARGING";
     field public static final int BATTERY_HEALTH_COLD = 7; // 0x7
     field public static final int BATTERY_HEALTH_DEAD = 4; // 0x4
     field public static final int BATTERY_HEALTH_GOOD = 2; // 0x2
@@ -33642,92 +33970,93 @@
     field public static final int BATTERY_STATUS_FULL = 5; // 0x5
     field public static final int BATTERY_STATUS_NOT_CHARGING = 4; // 0x4
     field public static final int BATTERY_STATUS_UNKNOWN = 1; // 0x1
-    field public static final java.lang.String EXTRA_BATTERY_LOW = "battery_low";
-    field public static final java.lang.String EXTRA_HEALTH = "health";
-    field public static final java.lang.String EXTRA_ICON_SMALL = "icon-small";
-    field public static final java.lang.String EXTRA_LEVEL = "level";
-    field public static final java.lang.String EXTRA_PLUGGED = "plugged";
-    field public static final java.lang.String EXTRA_PRESENT = "present";
-    field public static final java.lang.String EXTRA_SCALE = "scale";
-    field public static final java.lang.String EXTRA_STATUS = "status";
-    field public static final java.lang.String EXTRA_TECHNOLOGY = "technology";
-    field public static final java.lang.String EXTRA_TEMPERATURE = "temperature";
-    field public static final java.lang.String EXTRA_VOLTAGE = "voltage";
+    field public static final String EXTRA_BATTERY_LOW = "battery_low";
+    field public static final String EXTRA_HEALTH = "health";
+    field public static final String EXTRA_ICON_SMALL = "icon-small";
+    field public static final String EXTRA_LEVEL = "level";
+    field public static final String EXTRA_PLUGGED = "plugged";
+    field public static final String EXTRA_PRESENT = "present";
+    field public static final String EXTRA_SCALE = "scale";
+    field public static final String EXTRA_STATUS = "status";
+    field public static final String EXTRA_TECHNOLOGY = "technology";
+    field public static final String EXTRA_TEMPERATURE = "temperature";
+    field public static final String EXTRA_VOLTAGE = "voltage";
   }
 
   public class Binder implements android.os.IBinder {
     ctor public Binder();
-    ctor public Binder(java.lang.String);
-    method public void attachInterface(android.os.IInterface, java.lang.String);
+    ctor public Binder(@Nullable String);
+    method public void attachInterface(@Nullable android.os.IInterface, @Nullable String);
     method public static final long clearCallingIdentity();
-    method public void dump(java.io.FileDescriptor, java.lang.String[]);
-    method protected void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public void dumpAsync(java.io.FileDescriptor, java.lang.String[]);
+    method public void dump(@NonNull java.io.FileDescriptor, @Nullable String[]);
+    method protected void dump(@NonNull java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[]);
+    method public void dumpAsync(@NonNull java.io.FileDescriptor, @Nullable String[]);
     method public static final void flushPendingCommands();
     method public static final int getCallingPid();
     method public static final int getCallingUid();
-    method public static final android.os.UserHandle getCallingUserHandle();
-    method public java.lang.String getInterfaceDescriptor();
+    method public static final int getCallingUidOrThrow();
+    method @NonNull public static final android.os.UserHandle getCallingUserHandle();
+    method @Nullable public String getInterfaceDescriptor();
     method public boolean isBinderAlive();
     method public static final void joinThreadPool();
-    method public void linkToDeath(android.os.IBinder.DeathRecipient, int);
-    method protected boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
+    method public void linkToDeath(@NonNull android.os.IBinder.DeathRecipient, int);
+    method protected boolean onTransact(int, @NonNull android.os.Parcel, @Nullable android.os.Parcel, int) throws android.os.RemoteException;
     method public boolean pingBinder();
-    method public android.os.IInterface queryLocalInterface(java.lang.String);
+    method @Nullable public android.os.IInterface queryLocalInterface(@NonNull String);
     method public static final void restoreCallingIdentity(long);
-    method public final boolean transact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
-    method public boolean unlinkToDeath(android.os.IBinder.DeathRecipient, int);
+    method public final boolean transact(int, @NonNull android.os.Parcel, @Nullable android.os.Parcel, int) throws android.os.RemoteException;
+    method public boolean unlinkToDeath(@NonNull android.os.IBinder.DeathRecipient, int);
   }
 
   public class Build {
     ctor public Build();
-    method public static java.util.List<android.os.Build.Partition> getFingerprintedPartitions();
-    method public static java.lang.String getRadioVersion();
-    method public static java.lang.String getSerial();
-    field public static final java.lang.String BOARD;
-    field public static final java.lang.String BOOTLOADER;
-    field public static final java.lang.String BRAND;
-    field public static final deprecated java.lang.String CPU_ABI;
-    field public static final deprecated java.lang.String CPU_ABI2;
-    field public static final java.lang.String DEVICE;
-    field public static final java.lang.String DISPLAY;
-    field public static final java.lang.String FINGERPRINT;
-    field public static final java.lang.String HARDWARE;
-    field public static final java.lang.String HOST;
-    field public static final java.lang.String ID;
-    field public static final java.lang.String MANUFACTURER;
-    field public static final java.lang.String MODEL;
-    field public static final java.lang.String PRODUCT;
-    field public static final deprecated java.lang.String RADIO;
-    field public static final deprecated java.lang.String SERIAL;
-    field public static final java.lang.String[] SUPPORTED_32_BIT_ABIS;
-    field public static final java.lang.String[] SUPPORTED_64_BIT_ABIS;
-    field public static final java.lang.String[] SUPPORTED_ABIS;
-    field public static final java.lang.String TAGS;
+    method @NonNull public static java.util.List<android.os.Build.Partition> getFingerprintedPartitions();
+    method public static String getRadioVersion();
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public static String getSerial();
+    field public static final String BOARD;
+    field public static final String BOOTLOADER;
+    field public static final String BRAND;
+    field @Deprecated public static final String CPU_ABI;
+    field @Deprecated public static final String CPU_ABI2;
+    field public static final String DEVICE;
+    field public static final String DISPLAY;
+    field public static final String FINGERPRINT;
+    field public static final String HARDWARE;
+    field public static final String HOST;
+    field public static final String ID;
+    field public static final String MANUFACTURER;
+    field public static final String MODEL;
+    field public static final String PRODUCT;
+    field @Deprecated public static final String RADIO;
+    field @Deprecated public static final String SERIAL;
+    field public static final String[] SUPPORTED_32_BIT_ABIS;
+    field public static final String[] SUPPORTED_64_BIT_ABIS;
+    field public static final String[] SUPPORTED_ABIS;
+    field public static final String TAGS;
     field public static final long TIME;
-    field public static final java.lang.String TYPE;
-    field public static final java.lang.String UNKNOWN = "unknown";
-    field public static final java.lang.String USER;
+    field public static final String TYPE;
+    field public static final String UNKNOWN = "unknown";
+    field public static final String USER;
   }
 
   public static class Build.Partition {
     ctor public Build.Partition();
     method public long getBuildTimeMillis();
-    method public java.lang.String getFingerprint();
-    method public java.lang.String getName();
-    field public static final java.lang.String PARTITION_NAME_SYSTEM = "system";
+    method @NonNull public String getFingerprint();
+    method @NonNull public String getName();
+    field public static final String PARTITION_NAME_SYSTEM = "system";
   }
 
   public static class Build.VERSION {
     ctor public Build.VERSION();
-    field public static final java.lang.String BASE_OS;
-    field public static final java.lang.String CODENAME;
-    field public static final java.lang.String INCREMENTAL;
+    field public static final String BASE_OS;
+    field public static final String CODENAME;
+    field public static final String INCREMENTAL;
     field public static final int PREVIEW_SDK_INT;
-    field public static final java.lang.String RELEASE;
-    field public static final deprecated java.lang.String SDK;
+    field public static final String RELEASE;
+    field @Deprecated public static final String SDK;
     field public static final int SDK_INT;
-    field public static final java.lang.String SECURITY_PATCH;
+    field public static final String SECURITY_PATCH;
   }
 
   public static class Build.VERSION_CODES {
@@ -33766,68 +34095,67 @@
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
     ctor public Bundle();
-    ctor public Bundle(java.lang.ClassLoader);
+    ctor public Bundle(ClassLoader);
     ctor public Bundle(int);
     ctor public Bundle(android.os.Bundle);
     ctor public Bundle(android.os.PersistableBundle);
-    method public java.lang.Object clone();
+    method public Object clone();
     method public android.os.Bundle deepCopy();
     method public int describeContents();
-    method public android.os.IBinder getBinder(java.lang.String);
-    method public android.os.Bundle getBundle(java.lang.String);
-    method public byte getByte(java.lang.String);
-    method public java.lang.Byte getByte(java.lang.String, byte);
-    method public byte[] getByteArray(java.lang.String);
-    method public char getChar(java.lang.String);
-    method public char getChar(java.lang.String, char);
-    method public char[] getCharArray(java.lang.String);
-    method public java.lang.CharSequence getCharSequence(java.lang.String);
-    method public java.lang.CharSequence getCharSequence(java.lang.String, java.lang.CharSequence);
-    method public java.lang.CharSequence[] getCharSequenceArray(java.lang.String);
-    method public java.util.ArrayList<java.lang.CharSequence> getCharSequenceArrayList(java.lang.String);
-    method public java.lang.ClassLoader getClassLoader();
-    method public float getFloat(java.lang.String);
-    method public float getFloat(java.lang.String, float);
-    method public float[] getFloatArray(java.lang.String);
-    method public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(java.lang.String);
-    method public <T extends android.os.Parcelable> T getParcelable(java.lang.String);
-    method public android.os.Parcelable[] getParcelableArray(java.lang.String);
-    method public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
-    method public java.io.Serializable getSerializable(java.lang.String);
-    method public short getShort(java.lang.String);
-    method public short getShort(java.lang.String, short);
-    method public short[] getShortArray(java.lang.String);
-    method public android.util.Size getSize(java.lang.String);
-    method public android.util.SizeF getSizeF(java.lang.String);
-    method public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(java.lang.String);
-    method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String);
+    method @Nullable public android.os.IBinder getBinder(@Nullable String);
+    method @Nullable public android.os.Bundle getBundle(@Nullable String);
+    method public byte getByte(String);
+    method public Byte getByte(String, byte);
+    method @Nullable public byte[] getByteArray(@Nullable String);
+    method public char getChar(String);
+    method public char getChar(String, char);
+    method @Nullable public char[] getCharArray(@Nullable String);
+    method @Nullable public CharSequence getCharSequence(@Nullable String);
+    method public CharSequence getCharSequence(@Nullable String, CharSequence);
+    method @Nullable public CharSequence[] getCharSequenceArray(@Nullable String);
+    method @Nullable public java.util.ArrayList<java.lang.CharSequence> getCharSequenceArrayList(@Nullable String);
+    method public ClassLoader getClassLoader();
+    method public float getFloat(String);
+    method public float getFloat(String, float);
+    method @Nullable public float[] getFloatArray(@Nullable String);
+    method @Nullable public java.util.ArrayList<java.lang.Integer> getIntegerArrayList(@Nullable String);
+    method @Nullable public <T extends android.os.Parcelable> T getParcelable(@Nullable String);
+    method @Nullable public android.os.Parcelable[] getParcelableArray(@Nullable String);
+    method @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayList(@Nullable String);
+    method @Nullable public java.io.Serializable getSerializable(@Nullable String);
+    method public short getShort(String);
+    method public short getShort(String, short);
+    method @Nullable public short[] getShortArray(@Nullable String);
+    method @Nullable public android.util.Size getSize(@Nullable String);
+    method @Nullable public android.util.SizeF getSizeF(@Nullable String);
+    method @Nullable public <T extends android.os.Parcelable> android.util.SparseArray<T> getSparseParcelableArray(@Nullable String);
+    method @Nullable public java.util.ArrayList<java.lang.String> getStringArrayList(@Nullable String);
     method public boolean hasFileDescriptors();
     method public void putAll(android.os.Bundle);
-    method public void putBinder(java.lang.String, android.os.IBinder);
-    method public void putBundle(java.lang.String, android.os.Bundle);
-    method public void putByte(java.lang.String, byte);
-    method public void putByteArray(java.lang.String, byte[]);
-    method public void putChar(java.lang.String, char);
-    method public void putCharArray(java.lang.String, char[]);
-    method public void putCharSequence(java.lang.String, java.lang.CharSequence);
-    method public void putCharSequenceArray(java.lang.String, java.lang.CharSequence[]);
-    method public void putCharSequenceArrayList(java.lang.String, java.util.ArrayList<java.lang.CharSequence>);
-    method public void putFloat(java.lang.String, float);
-    method public void putFloatArray(java.lang.String, float[]);
-    method public void putIntegerArrayList(java.lang.String, java.util.ArrayList<java.lang.Integer>);
-    method public void putParcelable(java.lang.String, android.os.Parcelable);
-    method public void putParcelableArray(java.lang.String, android.os.Parcelable[]);
-    method public void putParcelableArrayList(java.lang.String, java.util.ArrayList<? extends android.os.Parcelable>);
-    method public void putSerializable(java.lang.String, java.io.Serializable);
-    method public void putShort(java.lang.String, short);
-    method public void putShortArray(java.lang.String, short[]);
-    method public void putSize(java.lang.String, android.util.Size);
-    method public void putSizeF(java.lang.String, android.util.SizeF);
-    method public void putSparseParcelableArray(java.lang.String, android.util.SparseArray<? extends android.os.Parcelable>);
-    method public void putStringArrayList(java.lang.String, java.util.ArrayList<java.lang.String>);
+    method public void putBinder(@Nullable String, @Nullable android.os.IBinder);
+    method public void putBundle(@Nullable String, @Nullable android.os.Bundle);
+    method public void putByte(@Nullable String, byte);
+    method public void putByteArray(@Nullable String, @Nullable byte[]);
+    method public void putChar(@Nullable String, char);
+    method public void putCharArray(@Nullable String, @Nullable char[]);
+    method public void putCharSequence(@Nullable String, @Nullable CharSequence);
+    method public void putCharSequenceArray(@Nullable String, @Nullable CharSequence[]);
+    method public void putCharSequenceArrayList(@Nullable String, @Nullable java.util.ArrayList<java.lang.CharSequence>);
+    method public void putFloat(@Nullable String, float);
+    method public void putFloatArray(@Nullable String, @Nullable float[]);
+    method public void putIntegerArrayList(@Nullable String, @Nullable java.util.ArrayList<java.lang.Integer>);
+    method public void putParcelable(@Nullable String, @Nullable android.os.Parcelable);
+    method public void putParcelableArray(@Nullable String, @Nullable android.os.Parcelable[]);
+    method public void putParcelableArrayList(@Nullable String, @Nullable java.util.ArrayList<? extends android.os.Parcelable>);
+    method public void putSerializable(@Nullable String, @Nullable java.io.Serializable);
+    method public void putShort(@Nullable String, short);
+    method public void putShortArray(@Nullable String, @Nullable short[]);
+    method public void putSize(@Nullable String, @Nullable android.util.Size);
+    method public void putSizeF(@Nullable String, @Nullable android.util.SizeF);
+    method public void putSparseParcelableArray(@Nullable String, @Nullable android.util.SparseArray<? extends android.os.Parcelable>);
+    method public void putStringArrayList(@Nullable String, @Nullable java.util.ArrayList<java.lang.String>);
     method public void readFromParcel(android.os.Parcel);
-    method public void setClassLoader(java.lang.ClassLoader);
-    method public synchronized java.lang.String toString();
+    method public void setClassLoader(ClassLoader);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.Bundle> CREATOR;
     field public static final android.os.Bundle EMPTY;
@@ -33841,8 +34169,8 @@
     method public void throwIfCanceled();
   }
 
-  public static abstract interface CancellationSignal.OnCancelListener {
-    method public abstract void onCancel();
+  public static interface CancellationSignal.OnCancelListener {
+    method public void onCancel();
   }
 
   public class ConditionVariable {
@@ -33856,10 +34184,10 @@
 
   public abstract class CountDownTimer {
     ctor public CountDownTimer(long, long);
-    method public final synchronized void cancel();
+    method public final void cancel();
     method public abstract void onFinish();
     method public abstract void onTick(long);
-    method public final synchronized android.os.CountDownTimer start();
+    method public final android.os.CountDownTimer start();
   }
 
   public final class CpuUsageInfo implements android.os.Parcelable {
@@ -33872,7 +34200,7 @@
 
   public class DeadObjectException extends android.os.RemoteException {
     ctor public DeadObjectException();
-    ctor public DeadObjectException(java.lang.String);
+    ctor public DeadObjectException(String);
   }
 
   public class DeadSystemException extends android.os.DeadObjectException {
@@ -33880,69 +34208,69 @@
   }
 
   public final class Debug {
-    method public static void attachJvmtiAgent(java.lang.String, java.lang.String, java.lang.ClassLoader) throws java.io.IOException;
-    method public static deprecated void changeDebugPort(int);
-    method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
-    method public static boolean dumpService(java.lang.String, java.io.FileDescriptor, java.lang.String[]);
+    method public static void attachJvmtiAgent(@NonNull String, @Nullable String, @Nullable ClassLoader) throws java.io.IOException;
+    method @Deprecated public static void changeDebugPort(int);
+    method public static void dumpHprofData(String) throws java.io.IOException;
+    method public static boolean dumpService(String, java.io.FileDescriptor, String[]);
     method public static void enableEmulatorTraceOutput();
     method public static int getBinderDeathObjectCount();
     method public static int getBinderLocalObjectCount();
     method public static int getBinderProxyObjectCount();
     method public static int getBinderReceivedTransactions();
     method public static int getBinderSentTransactions();
-    method public static deprecated int getGlobalAllocCount();
-    method public static deprecated int getGlobalAllocSize();
-    method public static deprecated int getGlobalClassInitCount();
-    method public static deprecated int getGlobalClassInitTime();
-    method public static deprecated int getGlobalExternalAllocCount();
-    method public static deprecated int getGlobalExternalAllocSize();
-    method public static deprecated int getGlobalExternalFreedCount();
-    method public static deprecated int getGlobalExternalFreedSize();
-    method public static deprecated int getGlobalFreedCount();
-    method public static deprecated int getGlobalFreedSize();
-    method public static deprecated int getGlobalGcInvocationCount();
+    method @Deprecated public static int getGlobalAllocCount();
+    method @Deprecated public static int getGlobalAllocSize();
+    method @Deprecated public static int getGlobalClassInitCount();
+    method @Deprecated public static int getGlobalClassInitTime();
+    method @Deprecated public static int getGlobalExternalAllocCount();
+    method @Deprecated public static int getGlobalExternalAllocSize();
+    method @Deprecated public static int getGlobalExternalFreedCount();
+    method @Deprecated public static int getGlobalExternalFreedSize();
+    method @Deprecated public static int getGlobalFreedCount();
+    method @Deprecated public static int getGlobalFreedSize();
+    method @Deprecated public static int getGlobalGcInvocationCount();
     method public static int getLoadedClassCount();
     method public static void getMemoryInfo(android.os.Debug.MemoryInfo);
     method public static long getNativeHeapAllocatedSize();
     method public static long getNativeHeapFreeSize();
     method public static long getNativeHeapSize();
     method public static long getPss();
-    method public static java.lang.String getRuntimeStat(java.lang.String);
-    method public static java.util.Map<java.lang.String, java.lang.String> getRuntimeStats();
-    method public static deprecated int getThreadAllocCount();
-    method public static deprecated int getThreadAllocSize();
-    method public static deprecated int getThreadExternalAllocCount();
-    method public static deprecated int getThreadExternalAllocSize();
-    method public static deprecated int getThreadGcInvocationCount();
+    method public static String getRuntimeStat(String);
+    method public static java.util.Map<java.lang.String,java.lang.String> getRuntimeStats();
+    method @Deprecated public static int getThreadAllocCount();
+    method @Deprecated public static int getThreadAllocSize();
+    method @Deprecated public static int getThreadExternalAllocCount();
+    method @Deprecated public static int getThreadExternalAllocSize();
+    method @Deprecated public static int getThreadGcInvocationCount();
     method public static boolean isDebuggerConnected();
     method public static void printLoadedClasses(int);
-    method public static deprecated void resetAllCounts();
-    method public static deprecated void resetGlobalAllocCount();
-    method public static deprecated void resetGlobalAllocSize();
-    method public static deprecated void resetGlobalClassInitCount();
-    method public static deprecated void resetGlobalClassInitTime();
-    method public static deprecated void resetGlobalExternalAllocCount();
-    method public static deprecated void resetGlobalExternalAllocSize();
-    method public static deprecated void resetGlobalExternalFreedCount();
-    method public static deprecated void resetGlobalExternalFreedSize();
-    method public static deprecated void resetGlobalFreedCount();
-    method public static deprecated void resetGlobalFreedSize();
-    method public static deprecated void resetGlobalGcInvocationCount();
-    method public static deprecated void resetThreadAllocCount();
-    method public static deprecated void resetThreadAllocSize();
-    method public static deprecated void resetThreadExternalAllocCount();
-    method public static deprecated void resetThreadExternalAllocSize();
-    method public static deprecated void resetThreadGcInvocationCount();
-    method public static deprecated int setAllocationLimit(int);
-    method public static deprecated int setGlobalAllocationLimit(int);
-    method public static deprecated void startAllocCounting();
+    method @Deprecated public static void resetAllCounts();
+    method @Deprecated public static void resetGlobalAllocCount();
+    method @Deprecated public static void resetGlobalAllocSize();
+    method @Deprecated public static void resetGlobalClassInitCount();
+    method @Deprecated public static void resetGlobalClassInitTime();
+    method @Deprecated public static void resetGlobalExternalAllocCount();
+    method @Deprecated public static void resetGlobalExternalAllocSize();
+    method @Deprecated public static void resetGlobalExternalFreedCount();
+    method @Deprecated public static void resetGlobalExternalFreedSize();
+    method @Deprecated public static void resetGlobalFreedCount();
+    method @Deprecated public static void resetGlobalFreedSize();
+    method @Deprecated public static void resetGlobalGcInvocationCount();
+    method @Deprecated public static void resetThreadAllocCount();
+    method @Deprecated public static void resetThreadAllocSize();
+    method @Deprecated public static void resetThreadExternalAllocCount();
+    method @Deprecated public static void resetThreadExternalAllocSize();
+    method @Deprecated public static void resetThreadGcInvocationCount();
+    method @Deprecated public static int setAllocationLimit(int);
+    method @Deprecated public static int setGlobalAllocationLimit(int);
+    method @Deprecated public static void startAllocCounting();
     method public static void startMethodTracing();
-    method public static void startMethodTracing(java.lang.String);
-    method public static void startMethodTracing(java.lang.String, int);
-    method public static void startMethodTracing(java.lang.String, int, int);
-    method public static void startMethodTracingSampling(java.lang.String, int, int);
+    method public static void startMethodTracing(String);
+    method public static void startMethodTracing(String, int);
+    method public static void startMethodTracing(String, int, int);
+    method public static void startMethodTracingSampling(String, int, int);
     method public static void startNativeTracing();
-    method public static deprecated void stopAllocCounting();
+    method @Deprecated public static void stopAllocCounting();
     method public static void stopMethodTracing();
     method public static void stopNativeTracing();
     method public static long threadCpuTimeNanos();
@@ -33951,22 +34279,22 @@
     field public static final int SHOW_CLASSLOADER = 2; // 0x2
     field public static final int SHOW_FULL_DETAIL = 1; // 0x1
     field public static final int SHOW_INITIALIZED = 4; // 0x4
-    field public static final deprecated int TRACE_COUNT_ALLOCS = 1; // 0x1
+    field @Deprecated public static final int TRACE_COUNT_ALLOCS = 1; // 0x1
   }
 
-  public static deprecated class Debug.InstructionCount {
-    ctor public Debug.InstructionCount();
-    method public boolean collect();
-    method public int globalMethodInvocations();
-    method public int globalTotal();
-    method public boolean resetAndStart();
+  @Deprecated public static class Debug.InstructionCount {
+    ctor @Deprecated public Debug.InstructionCount();
+    method @Deprecated public boolean collect();
+    method @Deprecated public int globalMethodInvocations();
+    method @Deprecated public int globalTotal();
+    method @Deprecated public boolean resetAndStart();
   }
 
   public static class Debug.MemoryInfo implements android.os.Parcelable {
     ctor public Debug.MemoryInfo();
     method public int describeContents();
-    method public java.lang.String getMemoryStat(java.lang.String);
-    method public java.util.Map<java.lang.String, java.lang.String> getMemoryStats();
+    method public String getMemoryStat(String);
+    method public java.util.Map<java.lang.String,java.lang.String> getMemoryStats();
     method public int getTotalPrivateClean();
     method public int getTotalPrivateDirty();
     method public int getTotalPss();
@@ -33989,31 +34317,31 @@
 
   public class DropBoxManager {
     ctor protected DropBoxManager();
-    method public void addData(java.lang.String, byte[], int);
-    method public void addFile(java.lang.String, java.io.File, int) throws java.io.IOException;
-    method public void addText(java.lang.String, java.lang.String);
-    method public android.os.DropBoxManager.Entry getNextEntry(java.lang.String, long);
-    method public boolean isTagEnabled(java.lang.String);
-    field public static final java.lang.String ACTION_DROPBOX_ENTRY_ADDED = "android.intent.action.DROPBOX_ENTRY_ADDED";
-    field public static final java.lang.String EXTRA_TAG = "tag";
-    field public static final java.lang.String EXTRA_TIME = "time";
+    method public void addData(String, byte[], int);
+    method public void addFile(String, java.io.File, int) throws java.io.IOException;
+    method public void addText(String, String);
+    method @RequiresPermission(allOf={android.Manifest.permission.READ_LOGS, android.Manifest.permission.PACKAGE_USAGE_STATS}) @Nullable public android.os.DropBoxManager.Entry getNextEntry(String, long);
+    method public boolean isTagEnabled(String);
+    field public static final String ACTION_DROPBOX_ENTRY_ADDED = "android.intent.action.DROPBOX_ENTRY_ADDED";
+    field public static final String EXTRA_TAG = "tag";
+    field public static final String EXTRA_TIME = "time";
     field public static final int IS_EMPTY = 1; // 0x1
     field public static final int IS_GZIPPED = 4; // 0x4
     field public static final int IS_TEXT = 2; // 0x2
   }
 
   public static class DropBoxManager.Entry implements java.io.Closeable android.os.Parcelable {
-    ctor public DropBoxManager.Entry(java.lang.String, long);
-    ctor public DropBoxManager.Entry(java.lang.String, long, java.lang.String);
-    ctor public DropBoxManager.Entry(java.lang.String, long, byte[], int);
-    ctor public DropBoxManager.Entry(java.lang.String, long, android.os.ParcelFileDescriptor, int);
-    ctor public DropBoxManager.Entry(java.lang.String, long, java.io.File, int) throws java.io.IOException;
+    ctor public DropBoxManager.Entry(String, long);
+    ctor public DropBoxManager.Entry(String, long, String);
+    ctor public DropBoxManager.Entry(String, long, byte[], int);
+    ctor public DropBoxManager.Entry(String, long, android.os.ParcelFileDescriptor, int);
+    ctor public DropBoxManager.Entry(String, long, java.io.File, int) throws java.io.IOException;
     method public void close();
     method public int describeContents();
     method public int getFlags();
     method public java.io.InputStream getInputStream() throws java.io.IOException;
-    method public java.lang.String getTag();
-    method public java.lang.String getText(int);
+    method public String getTag();
+    method public String getText(int);
     method public long getTimeMillis();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.DropBoxManager.Entry> CREATOR;
@@ -34024,45 +34352,45 @@
     method public static java.io.File getDataDirectory();
     method public static java.io.File getDownloadCacheDirectory();
     method public static java.io.File getExternalStorageDirectory();
-    method public static java.io.File getExternalStoragePublicDirectory(java.lang.String);
-    method public static java.lang.String getExternalStorageState();
-    method public static java.lang.String getExternalStorageState(java.io.File);
+    method public static java.io.File getExternalStoragePublicDirectory(String);
+    method public static String getExternalStorageState();
+    method public static String getExternalStorageState(java.io.File);
     method public static java.io.File getRootDirectory();
-    method public static deprecated java.lang.String getStorageState(java.io.File);
+    method @Deprecated public static String getStorageState(java.io.File);
     method public static boolean isExternalStorageEmulated();
     method public static boolean isExternalStorageEmulated(java.io.File);
     method public static boolean isExternalStorageRemovable();
     method public static boolean isExternalStorageRemovable(java.io.File);
-    field public static java.lang.String DIRECTORY_ALARMS;
-    field public static java.lang.String DIRECTORY_AUDIOBOOKS;
-    field public static java.lang.String DIRECTORY_DCIM;
-    field public static java.lang.String DIRECTORY_DOCUMENTS;
-    field public static java.lang.String DIRECTORY_DOWNLOADS;
-    field public static java.lang.String DIRECTORY_MOVIES;
-    field public static java.lang.String DIRECTORY_MUSIC;
-    field public static java.lang.String DIRECTORY_NOTIFICATIONS;
-    field public static java.lang.String DIRECTORY_PICTURES;
-    field public static java.lang.String DIRECTORY_PODCASTS;
-    field public static java.lang.String DIRECTORY_RINGTONES;
-    field public static java.lang.String DIRECTORY_SCREENSHOTS;
-    field public static final java.lang.String MEDIA_BAD_REMOVAL = "bad_removal";
-    field public static final java.lang.String MEDIA_CHECKING = "checking";
-    field public static final java.lang.String MEDIA_EJECTING = "ejecting";
-    field public static final java.lang.String MEDIA_MOUNTED = "mounted";
-    field public static final java.lang.String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
-    field public static final java.lang.String MEDIA_NOFS = "nofs";
-    field public static final java.lang.String MEDIA_REMOVED = "removed";
-    field public static final java.lang.String MEDIA_SHARED = "shared";
-    field public static final java.lang.String MEDIA_UNKNOWN = "unknown";
-    field public static final java.lang.String MEDIA_UNMOUNTABLE = "unmountable";
-    field public static final java.lang.String MEDIA_UNMOUNTED = "unmounted";
+    field public static String DIRECTORY_ALARMS;
+    field public static String DIRECTORY_AUDIOBOOKS;
+    field public static String DIRECTORY_DCIM;
+    field public static String DIRECTORY_DOCUMENTS;
+    field public static String DIRECTORY_DOWNLOADS;
+    field public static String DIRECTORY_MOVIES;
+    field public static String DIRECTORY_MUSIC;
+    field public static String DIRECTORY_NOTIFICATIONS;
+    field public static String DIRECTORY_PICTURES;
+    field public static String DIRECTORY_PODCASTS;
+    field public static String DIRECTORY_RINGTONES;
+    field public static String DIRECTORY_SCREENSHOTS;
+    field public static final String MEDIA_BAD_REMOVAL = "bad_removal";
+    field public static final String MEDIA_CHECKING = "checking";
+    field public static final String MEDIA_EJECTING = "ejecting";
+    field public static final String MEDIA_MOUNTED = "mounted";
+    field public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
+    field public static final String MEDIA_NOFS = "nofs";
+    field public static final String MEDIA_REMOVED = "removed";
+    field public static final String MEDIA_SHARED = "shared";
+    field public static final String MEDIA_UNKNOWN = "unknown";
+    field public static final String MEDIA_UNMOUNTABLE = "unmountable";
+    field public static final String MEDIA_UNMOUNTED = "unmounted";
   }
 
   public abstract class FileObserver {
-    ctor public FileObserver(java.lang.String);
-    ctor public FileObserver(java.lang.String, int);
+    ctor public FileObserver(String);
+    ctor public FileObserver(String, int);
     method protected void finalize();
-    method public abstract void onEvent(int, java.lang.String);
+    method public abstract void onEvent(int, @Nullable String);
     method public void startWatching();
     method public void stopWatching();
     field public static final int ACCESS = 1; // 0x1
@@ -34081,22 +34409,22 @@
   }
 
   public class FileUriExposedException extends java.lang.RuntimeException {
-    ctor public FileUriExposedException(java.lang.String);
+    ctor public FileUriExposedException(String);
   }
 
   public class FileUtils {
-    method public static void closeQuietly(java.lang.AutoCloseable);
-    method public static void closeQuietly(java.io.FileDescriptor);
-    method public static long copy(java.io.File, java.io.File) throws java.io.IOException;
-    method public static long copy(java.io.File, java.io.File, android.os.CancellationSignal, java.util.concurrent.Executor, android.os.FileUtils.ProgressListener) throws java.io.IOException;
-    method public static long copy(java.io.InputStream, java.io.OutputStream) throws java.io.IOException;
-    method public static long copy(java.io.InputStream, java.io.OutputStream, android.os.CancellationSignal, java.util.concurrent.Executor, android.os.FileUtils.ProgressListener) throws java.io.IOException;
-    method public static long copy(java.io.FileDescriptor, java.io.FileDescriptor) throws java.io.IOException;
-    method public static long copy(java.io.FileDescriptor, java.io.FileDescriptor, android.os.CancellationSignal, java.util.concurrent.Executor, android.os.FileUtils.ProgressListener) throws java.io.IOException;
+    method public static void closeQuietly(@Nullable AutoCloseable);
+    method public static void closeQuietly(@Nullable java.io.FileDescriptor);
+    method public static long copy(@NonNull java.io.File, @NonNull java.io.File) throws java.io.IOException;
+    method public static long copy(@NonNull java.io.File, @NonNull java.io.File, @Nullable android.os.CancellationSignal, @Nullable java.util.concurrent.Executor, @Nullable android.os.FileUtils.ProgressListener) throws java.io.IOException;
+    method public static long copy(@NonNull java.io.InputStream, @NonNull java.io.OutputStream) throws java.io.IOException;
+    method public static long copy(@NonNull java.io.InputStream, @NonNull java.io.OutputStream, @Nullable android.os.CancellationSignal, @Nullable java.util.concurrent.Executor, @Nullable android.os.FileUtils.ProgressListener) throws java.io.IOException;
+    method public static long copy(@NonNull java.io.FileDescriptor, @NonNull java.io.FileDescriptor) throws java.io.IOException;
+    method public static long copy(@NonNull java.io.FileDescriptor, @NonNull java.io.FileDescriptor, @Nullable android.os.CancellationSignal, @Nullable java.util.concurrent.Executor, @Nullable android.os.FileUtils.ProgressListener) throws java.io.IOException;
   }
 
-  public static abstract interface FileUtils.ProgressListener {
-    method public abstract void onProgress(long);
+  public static interface FileUtils.ProgressListener {
+    method public void onProgress(long);
   }
 
   public class Handler {
@@ -34104,32 +34432,32 @@
     ctor public Handler(android.os.Handler.Callback);
     ctor public Handler(android.os.Looper);
     ctor public Handler(android.os.Looper, android.os.Handler.Callback);
-    method public static android.os.Handler createAsync(android.os.Looper);
-    method public static android.os.Handler createAsync(android.os.Looper, android.os.Handler.Callback);
+    method @NonNull public static android.os.Handler createAsync(@NonNull android.os.Looper);
+    method @NonNull public static android.os.Handler createAsync(@NonNull android.os.Looper, @NonNull android.os.Handler.Callback);
     method public void dispatchMessage(android.os.Message);
-    method public final void dump(android.util.Printer, java.lang.String);
+    method public final void dump(android.util.Printer, String);
     method public final android.os.Looper getLooper();
-    method public java.lang.String getMessageName(android.os.Message);
+    method public String getMessageName(android.os.Message);
     method public void handleMessage(android.os.Message);
-    method public final boolean hasCallbacks(java.lang.Runnable);
+    method public final boolean hasCallbacks(Runnable);
     method public final boolean hasMessages(int);
-    method public final boolean hasMessages(int, java.lang.Object);
+    method public final boolean hasMessages(int, Object);
     method public final android.os.Message obtainMessage();
     method public final android.os.Message obtainMessage(int);
-    method public final android.os.Message obtainMessage(int, java.lang.Object);
+    method public final android.os.Message obtainMessage(int, Object);
     method public final android.os.Message obtainMessage(int, int, int);
-    method public final android.os.Message obtainMessage(int, int, int, java.lang.Object);
-    method public final boolean post(java.lang.Runnable);
-    method public final boolean postAtFrontOfQueue(java.lang.Runnable);
-    method public final boolean postAtTime(java.lang.Runnable, long);
-    method public final boolean postAtTime(java.lang.Runnable, java.lang.Object, long);
-    method public final boolean postDelayed(java.lang.Runnable, long);
-    method public final boolean postDelayed(java.lang.Runnable, java.lang.Object, long);
-    method public final void removeCallbacks(java.lang.Runnable);
-    method public final void removeCallbacks(java.lang.Runnable, java.lang.Object);
-    method public final void removeCallbacksAndMessages(java.lang.Object);
+    method public final android.os.Message obtainMessage(int, int, int, Object);
+    method public final boolean post(Runnable);
+    method public final boolean postAtFrontOfQueue(Runnable);
+    method public final boolean postAtTime(Runnable, long);
+    method public final boolean postAtTime(Runnable, Object, long);
+    method public final boolean postDelayed(Runnable, long);
+    method public final boolean postDelayed(Runnable, Object, long);
+    method public final void removeCallbacks(Runnable);
+    method public final void removeCallbacks(Runnable, Object);
+    method public final void removeCallbacksAndMessages(Object);
     method public final void removeMessages(int);
-    method public final void removeMessages(int, java.lang.Object);
+    method public final void removeMessages(int, Object);
     method public final boolean sendEmptyMessage(int);
     method public final boolean sendEmptyMessageAtTime(int, long);
     method public final boolean sendEmptyMessageDelayed(int, long);
@@ -34139,13 +34467,13 @@
     method public final boolean sendMessageDelayed(android.os.Message, long);
   }
 
-  public static abstract interface Handler.Callback {
-    method public abstract boolean handleMessage(android.os.Message);
+  public static interface Handler.Callback {
+    method public boolean handleMessage(android.os.Message);
   }
 
   public class HandlerThread extends java.lang.Thread {
-    ctor public HandlerThread(java.lang.String);
-    ctor public HandlerThread(java.lang.String, int);
+    ctor public HandlerThread(String);
+    ctor public HandlerThread(String, int);
     method public android.os.Looper getLooper();
     method public int getThreadId();
     method protected void onLooperPrepared();
@@ -34154,9 +34482,9 @@
   }
 
   public class HardwarePropertiesManager {
-    method public android.os.CpuUsageInfo[] getCpuUsages();
-    method public float[] getDeviceTemperatures(int, int);
-    method public float[] getFanSpeeds();
+    method @NonNull public android.os.CpuUsageInfo[] getCpuUsages();
+    method @NonNull public float[] getDeviceTemperatures(int, int);
+    method @NonNull public float[] getFanSpeeds();
     field public static final int DEVICE_TEMPERATURE_BATTERY = 2; // 0x2
     field public static final int DEVICE_TEMPERATURE_CPU = 0; // 0x0
     field public static final int DEVICE_TEMPERATURE_GPU = 1; // 0x1
@@ -34168,16 +34496,16 @@
     field public static final float UNDEFINED_TEMPERATURE = -3.4028235E38f;
   }
 
-  public abstract interface IBinder {
-    method public abstract void dump(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
-    method public abstract void dumpAsync(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
-    method public abstract java.lang.String getInterfaceDescriptor() throws android.os.RemoteException;
-    method public abstract boolean isBinderAlive();
-    method public abstract void linkToDeath(android.os.IBinder.DeathRecipient, int) throws android.os.RemoteException;
-    method public abstract boolean pingBinder();
-    method public abstract android.os.IInterface queryLocalInterface(java.lang.String);
-    method public abstract boolean transact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
-    method public abstract boolean unlinkToDeath(android.os.IBinder.DeathRecipient, int);
+  public interface IBinder {
+    method public void dump(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
+    method public void dumpAsync(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
+    method @Nullable public String getInterfaceDescriptor() throws android.os.RemoteException;
+    method public boolean isBinderAlive();
+    method public void linkToDeath(@NonNull android.os.IBinder.DeathRecipient, int) throws android.os.RemoteException;
+    method public boolean pingBinder();
+    method @Nullable public android.os.IInterface queryLocalInterface(@NonNull String);
+    method public boolean transact(int, @NonNull android.os.Parcel, @Nullable android.os.Parcel, int) throws android.os.RemoteException;
+    method public boolean unlinkToDeath(@NonNull android.os.IBinder.DeathRecipient, int);
     field public static final int DUMP_TRANSACTION = 1598311760; // 0x5f444d50
     field public static final int FIRST_CALL_TRANSACTION = 1; // 0x1
     field public static final int FLAG_ONEWAY = 1; // 0x1
@@ -34188,55 +34516,55 @@
     field public static final int TWEET_TRANSACTION = 1599362900; // 0x5f545754
   }
 
-  public static abstract interface IBinder.DeathRecipient {
-    method public abstract void binderDied();
+  public static interface IBinder.DeathRecipient {
+    method public void binderDied();
   }
 
-  public abstract interface IInterface {
-    method public abstract android.os.IBinder asBinder();
+  public interface IInterface {
+    method public android.os.IBinder asBinder();
   }
 
   public final class LocaleList implements android.os.Parcelable {
-    ctor public LocaleList(java.util.Locale...);
+    ctor public LocaleList(@NonNull java.util.Locale...);
     method public int describeContents();
-    method public static android.os.LocaleList forLanguageTags(java.lang.String);
+    method @NonNull public static android.os.LocaleList forLanguageTags(@Nullable String);
     method public java.util.Locale get(int);
-    method public static android.os.LocaleList getAdjustedDefault();
-    method public static android.os.LocaleList getDefault();
-    method public static android.os.LocaleList getEmptyLocaleList();
-    method public java.util.Locale getFirstMatch(java.lang.String[]);
-    method public int indexOf(java.util.Locale);
+    method @NonNull @Size(min=1) public static android.os.LocaleList getAdjustedDefault();
+    method @NonNull @Size(min=1) public static android.os.LocaleList getDefault();
+    method @NonNull public static android.os.LocaleList getEmptyLocaleList();
+    method @Nullable public java.util.Locale getFirstMatch(String[]);
+    method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale);
     method public boolean isEmpty();
-    method public static void setDefault(android.os.LocaleList);
-    method public int size();
-    method public java.lang.String toLanguageTags();
+    method public static void setDefault(@NonNull @Size(min=1) android.os.LocaleList);
+    method @IntRange(from=0) public int size();
+    method @NonNull public String toLanguageTags();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.LocaleList> CREATOR;
   }
 
   public final class Looper {
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(@NonNull android.util.Printer, @NonNull String);
     method public static android.os.Looper getMainLooper();
-    method public android.os.MessageQueue getQueue();
-    method public java.lang.Thread getThread();
+    method @NonNull public android.os.MessageQueue getQueue();
+    method @NonNull public Thread getThread();
     method public boolean isCurrentThread();
     method public static void loop();
-    method public static android.os.Looper myLooper();
-    method public static android.os.MessageQueue myQueue();
+    method @Nullable public static android.os.Looper myLooper();
+    method @NonNull public static android.os.MessageQueue myQueue();
     method public static void prepare();
     method public static void prepareMainLooper();
     method public void quit();
     method public void quitSafely();
-    method public void setMessageLogging(android.util.Printer);
+    method public void setMessageLogging(@Nullable android.util.Printer);
   }
 
   public class MemoryFile {
-    ctor public MemoryFile(java.lang.String, int) throws java.io.IOException;
-    method public deprecated synchronized boolean allowPurging(boolean) throws java.io.IOException;
+    ctor public MemoryFile(String, int) throws java.io.IOException;
+    method @Deprecated public boolean allowPurging(boolean) throws java.io.IOException;
     method public void close();
     method public java.io.InputStream getInputStream();
     method public java.io.OutputStream getOutputStream();
-    method public deprecated boolean isPurgingAllowed();
+    method @Deprecated public boolean isPurgingAllowed();
     method public int length();
     method public int readBytes(byte[], int, int, int) throws java.io.IOException;
     method public void writeBytes(byte[], int, int, int) throws java.io.IOException;
@@ -34246,7 +34574,7 @@
     ctor public Message();
     method public void copyFrom(android.os.Message);
     method public int describeContents();
-    method public java.lang.Runnable getCallback();
+    method public Runnable getCallback();
     method public android.os.Bundle getData();
     method public android.os.Handler getTarget();
     method public long getWhen();
@@ -34254,11 +34582,11 @@
     method public static android.os.Message obtain();
     method public static android.os.Message obtain(android.os.Message);
     method public static android.os.Message obtain(android.os.Handler);
-    method public static android.os.Message obtain(android.os.Handler, java.lang.Runnable);
+    method public static android.os.Message obtain(android.os.Handler, Runnable);
     method public static android.os.Message obtain(android.os.Handler, int);
-    method public static android.os.Message obtain(android.os.Handler, int, java.lang.Object);
+    method public static android.os.Message obtain(android.os.Handler, int, Object);
     method public static android.os.Message obtain(android.os.Handler, int, int, int);
-    method public static android.os.Message obtain(android.os.Handler, int, int, int, java.lang.Object);
+    method public static android.os.Message obtain(android.os.Handler, int, int, int, Object);
     method public android.os.Bundle peekData();
     method public void recycle();
     method public void sendToTarget();
@@ -34269,26 +34597,26 @@
     field public static final android.os.Parcelable.Creator<android.os.Message> CREATOR;
     field public int arg1;
     field public int arg2;
-    field public java.lang.Object obj;
+    field public Object obj;
     field public android.os.Messenger replyTo;
     field public int sendingUid;
     field public int what;
   }
 
   public final class MessageQueue {
-    method public void addIdleHandler(android.os.MessageQueue.IdleHandler);
-    method public void addOnFileDescriptorEventListener(java.io.FileDescriptor, int, android.os.MessageQueue.OnFileDescriptorEventListener);
+    method public void addIdleHandler(@NonNull android.os.MessageQueue.IdleHandler);
+    method public void addOnFileDescriptorEventListener(@NonNull java.io.FileDescriptor, int, @NonNull android.os.MessageQueue.OnFileDescriptorEventListener);
     method public boolean isIdle();
-    method public void removeIdleHandler(android.os.MessageQueue.IdleHandler);
-    method public void removeOnFileDescriptorEventListener(java.io.FileDescriptor);
+    method public void removeIdleHandler(@NonNull android.os.MessageQueue.IdleHandler);
+    method public void removeOnFileDescriptorEventListener(@NonNull java.io.FileDescriptor);
   }
 
-  public static abstract interface MessageQueue.IdleHandler {
-    method public abstract boolean queueIdle();
+  public static interface MessageQueue.IdleHandler {
+    method public boolean queueIdle();
   }
 
-  public static abstract interface MessageQueue.OnFileDescriptorEventListener {
-    method public abstract int onFileDescriptorEvents(java.io.FileDescriptor, int);
+  public static interface MessageQueue.OnFileDescriptorEventListener {
+    method public int onFileDescriptorEvents(@NonNull java.io.FileDescriptor, int);
     field public static final int EVENT_ERROR = 4; // 0x4
     field public static final int EVENT_INPUT = 1; // 0x1
     field public static final int EVENT_OUTPUT = 2; // 0x2
@@ -34312,122 +34640,126 @@
 
   public class OperationCanceledException extends java.lang.RuntimeException {
     ctor public OperationCanceledException();
-    ctor public OperationCanceledException(java.lang.String);
+    ctor public OperationCanceledException(String);
   }
 
   public final class Parcel {
     method public void appendFrom(android.os.Parcel, int, int);
-    method public android.os.IBinder[] createBinderArray();
-    method public java.util.ArrayList<android.os.IBinder> createBinderArrayList();
-    method public boolean[] createBooleanArray();
-    method public byte[] createByteArray();
-    method public char[] createCharArray();
-    method public double[] createDoubleArray();
-    method public float[] createFloatArray();
-    method public int[] createIntArray();
-    method public long[] createLongArray();
-    method public java.lang.String[] createStringArray();
-    method public java.util.ArrayList<java.lang.String> createStringArrayList();
-    method public <T> T[] createTypedArray(android.os.Parcelable.Creator<T>);
-    method public <T> java.util.ArrayList<T> createTypedArrayList(android.os.Parcelable.Creator<T>);
+    method @Nullable public android.os.IBinder[] createBinderArray();
+    method @Nullable public java.util.ArrayList<android.os.IBinder> createBinderArrayList();
+    method @Nullable public boolean[] createBooleanArray();
+    method @Nullable public byte[] createByteArray();
+    method @Nullable public char[] createCharArray();
+    method @Nullable public double[] createDoubleArray();
+    method @Nullable public float[] createFloatArray();
+    method @Nullable public int[] createIntArray();
+    method @Nullable public long[] createLongArray();
+    method @Nullable public String[] createStringArray();
+    method @Nullable public java.util.ArrayList<java.lang.String> createStringArrayList();
+    method @Nullable public <T> T[] createTypedArray(@NonNull android.os.Parcelable.Creator<T>);
+    method @Nullable public <T> java.util.ArrayList<T> createTypedArrayList(@NonNull android.os.Parcelable.Creator<T>);
+    method @Nullable public <T extends android.os.Parcelable> android.util.ArrayMap<java.lang.String,T> createTypedArrayMap(@NonNull android.os.Parcelable.Creator<T>);
+    method @Nullable public <T extends android.os.Parcelable> android.util.SparseArray<T> createTypedSparseArray(@NonNull android.os.Parcelable.Creator<T>);
     method public int dataAvail();
     method public int dataCapacity();
     method public int dataPosition();
     method public int dataSize();
-    method public void enforceInterface(java.lang.String);
+    method public void enforceInterface(String);
     method public boolean hasFileDescriptors();
     method public byte[] marshall();
-    method public static android.os.Parcel obtain();
-    method public java.lang.Object[] readArray(java.lang.ClassLoader);
-    method public java.util.ArrayList readArrayList(java.lang.ClassLoader);
-    method public void readBinderArray(android.os.IBinder[]);
-    method public void readBinderList(java.util.List<android.os.IBinder>);
+    method @NonNull public static android.os.Parcel obtain();
+    method @Nullable public Object[] readArray(@Nullable ClassLoader);
+    method @Nullable public java.util.ArrayList readArrayList(@Nullable ClassLoader);
+    method public void readBinderArray(@NonNull android.os.IBinder[]);
+    method public void readBinderList(@NonNull java.util.List<android.os.IBinder>);
     method public boolean readBoolean();
-    method public void readBooleanArray(boolean[]);
-    method public android.os.Bundle readBundle();
-    method public android.os.Bundle readBundle(java.lang.ClassLoader);
+    method public void readBooleanArray(@NonNull boolean[]);
+    method @Nullable public android.os.Bundle readBundle();
+    method @Nullable public android.os.Bundle readBundle(@Nullable ClassLoader);
     method public byte readByte();
-    method public void readByteArray(byte[]);
-    method public void readCharArray(char[]);
+    method public void readByteArray(@NonNull byte[]);
+    method public void readCharArray(@NonNull char[]);
     method public double readDouble();
-    method public void readDoubleArray(double[]);
+    method public void readDoubleArray(@NonNull double[]);
     method public void readException();
-    method public void readException(int, java.lang.String);
+    method public void readException(int, String);
     method public android.os.ParcelFileDescriptor readFileDescriptor();
     method public float readFloat();
-    method public void readFloatArray(float[]);
-    method public java.util.HashMap readHashMap(java.lang.ClassLoader);
+    method public void readFloatArray(@NonNull float[]);
+    method @Nullable public java.util.HashMap readHashMap(@Nullable ClassLoader);
     method public int readInt();
-    method public void readIntArray(int[]);
-    method public void readList(java.util.List, java.lang.ClassLoader);
+    method public void readIntArray(@NonNull int[]);
+    method public void readList(@NonNull java.util.List, @Nullable ClassLoader);
     method public long readLong();
-    method public void readLongArray(long[]);
-    method public void readMap(java.util.Map, java.lang.ClassLoader);
-    method public <T extends android.os.Parcelable> T readParcelable(java.lang.ClassLoader);
-    method public android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader);
-    method public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(java.util.List<T>, java.lang.ClassLoader);
-    method public android.os.PersistableBundle readPersistableBundle();
-    method public android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader);
-    method public java.io.Serializable readSerializable();
-    method public android.util.Size readSize();
-    method public android.util.SizeF readSizeF();
-    method public android.util.SparseArray readSparseArray(java.lang.ClassLoader);
-    method public android.util.SparseBooleanArray readSparseBooleanArray();
-    method public java.lang.String readString();
-    method public void readStringArray(java.lang.String[]);
-    method public void readStringList(java.util.List<java.lang.String>);
+    method public void readLongArray(@NonNull long[]);
+    method public void readMap(@NonNull java.util.Map, @Nullable ClassLoader);
+    method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader);
+    method @Nullable public android.os.Parcelable[] readParcelableArray(@Nullable ClassLoader);
+    method @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader);
+    method @Nullable public android.os.PersistableBundle readPersistableBundle();
+    method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
+    method @Nullable public java.io.Serializable readSerializable();
+    method @NonNull public android.util.Size readSize();
+    method @NonNull public android.util.SizeF readSizeF();
+    method @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader);
+    method @Nullable public android.util.SparseBooleanArray readSparseBooleanArray();
+    method @Nullable public String readString();
+    method public void readStringArray(@NonNull String[]);
+    method public void readStringList(@NonNull java.util.List<java.lang.String>);
     method public android.os.IBinder readStrongBinder();
-    method public <T> void readTypedArray(T[], android.os.Parcelable.Creator<T>);
-    method public <T> void readTypedList(java.util.List<T>, android.os.Parcelable.Creator<T>);
-    method public <T> T readTypedObject(android.os.Parcelable.Creator<T>);
-    method public java.lang.Object readValue(java.lang.ClassLoader);
+    method public <T> void readTypedArray(@NonNull T[], @NonNull android.os.Parcelable.Creator<T>);
+    method public <T> void readTypedList(@NonNull java.util.List<T>, @NonNull android.os.Parcelable.Creator<T>);
+    method @Nullable public <T> T readTypedObject(@NonNull android.os.Parcelable.Creator<T>);
+    method @Nullable public Object readValue(@Nullable ClassLoader);
     method public void recycle();
     method public void setDataCapacity(int);
     method public void setDataPosition(int);
     method public void setDataSize(int);
-    method public void unmarshall(byte[], int, int);
-    method public void writeArray(java.lang.Object[]);
-    method public void writeBinderArray(android.os.IBinder[]);
-    method public void writeBinderList(java.util.List<android.os.IBinder>);
+    method public void unmarshall(@NonNull byte[], int, int);
+    method public void writeArray(@Nullable Object[]);
+    method public void writeBinderArray(@Nullable android.os.IBinder[]);
+    method public void writeBinderList(@Nullable java.util.List<android.os.IBinder>);
     method public void writeBoolean(boolean);
-    method public void writeBooleanArray(boolean[]);
-    method public void writeBundle(android.os.Bundle);
+    method public void writeBooleanArray(@Nullable boolean[]);
+    method public void writeBundle(@Nullable android.os.Bundle);
     method public void writeByte(byte);
-    method public void writeByteArray(byte[]);
-    method public void writeByteArray(byte[], int, int);
-    method public void writeCharArray(char[]);
+    method public void writeByteArray(@Nullable byte[]);
+    method public void writeByteArray(@Nullable byte[], int, int);
+    method public void writeCharArray(@Nullable char[]);
     method public void writeDouble(double);
-    method public void writeDoubleArray(double[]);
-    method public void writeException(java.lang.Exception);
-    method public void writeFileDescriptor(java.io.FileDescriptor);
+    method public void writeDoubleArray(@Nullable double[]);
+    method public void writeException(@NonNull Exception);
+    method public void writeFileDescriptor(@NonNull java.io.FileDescriptor);
     method public void writeFloat(float);
-    method public void writeFloatArray(float[]);
+    method public void writeFloatArray(@Nullable float[]);
     method public void writeInt(int);
-    method public void writeIntArray(int[]);
-    method public void writeInterfaceToken(java.lang.String);
-    method public void writeList(java.util.List);
+    method public void writeIntArray(@Nullable int[]);
+    method public void writeInterfaceToken(String);
+    method public void writeList(@Nullable java.util.List);
     method public void writeLong(long);
-    method public void writeLongArray(long[]);
-    method public void writeMap(java.util.Map);
+    method public void writeLongArray(@Nullable long[]);
+    method public void writeMap(@Nullable java.util.Map);
     method public void writeNoException();
-    method public void writeParcelable(android.os.Parcelable, int);
-    method public <T extends android.os.Parcelable> void writeParcelableArray(T[], int);
-    method public <T extends android.os.Parcelable> void writeParcelableList(java.util.List<T>, int);
-    method public void writePersistableBundle(android.os.PersistableBundle);
-    method public void writeSerializable(java.io.Serializable);
-    method public void writeSize(android.util.Size);
-    method public void writeSizeF(android.util.SizeF);
-    method public void writeSparseArray(android.util.SparseArray<java.lang.Object>);
-    method public void writeSparseBooleanArray(android.util.SparseBooleanArray);
-    method public void writeString(java.lang.String);
-    method public void writeStringArray(java.lang.String[]);
-    method public void writeStringList(java.util.List<java.lang.String>);
+    method public void writeParcelable(@Nullable android.os.Parcelable, int);
+    method public <T extends android.os.Parcelable> void writeParcelableArray(@Nullable T[], int);
+    method public <T extends android.os.Parcelable> void writeParcelableList(@Nullable java.util.List<T>, int);
+    method public void writePersistableBundle(@Nullable android.os.PersistableBundle);
+    method public void writeSerializable(@Nullable java.io.Serializable);
+    method public void writeSize(@NonNull android.util.Size);
+    method public void writeSizeF(@NonNull android.util.SizeF);
+    method public <T> void writeSparseArray(@Nullable android.util.SparseArray<T>);
+    method public void writeSparseBooleanArray(@Nullable android.util.SparseBooleanArray);
+    method public void writeString(@Nullable String);
+    method public void writeStringArray(@Nullable String[]);
+    method public void writeStringList(@Nullable java.util.List<java.lang.String>);
     method public void writeStrongBinder(android.os.IBinder);
     method public void writeStrongInterface(android.os.IInterface);
-    method public <T extends android.os.Parcelable> void writeTypedArray(T[], int);
-    method public <T extends android.os.Parcelable> void writeTypedList(java.util.List<T>);
-    method public <T extends android.os.Parcelable> void writeTypedObject(T, int);
-    method public void writeValue(java.lang.Object);
+    method public <T extends android.os.Parcelable> void writeTypedArray(@Nullable T[], int);
+    method public <T extends android.os.Parcelable> void writeTypedArrayMap(@Nullable android.util.ArrayMap<java.lang.String,T>, int);
+    method public <T extends android.os.Parcelable> void writeTypedList(@Nullable java.util.List<T>);
+    method public <T extends android.os.Parcelable> void writeTypedObject(@Nullable T, int);
+    method public <T extends android.os.Parcelable> void writeTypedSparseArray(@Nullable android.util.SparseArray<T>, int);
+    method public void writeValue(@Nullable Object);
     field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR;
   }
 
@@ -34437,7 +34769,7 @@
     method public boolean canDetectErrors();
     method public void checkError() throws java.io.IOException;
     method public void close() throws java.io.IOException;
-    method public void closeWithError(java.lang.String) throws java.io.IOException;
+    method public void closeWithError(String) throws java.io.IOException;
     method public static android.os.ParcelFileDescriptor[] createPipe() throws java.io.IOException;
     method public static android.os.ParcelFileDescriptor[] createReliablePipe() throws java.io.IOException;
     method public static android.os.ParcelFileDescriptor[] createReliableSocketPair() throws java.io.IOException;
@@ -34454,7 +34786,7 @@
     method public long getStatSize();
     method public static android.os.ParcelFileDescriptor open(java.io.File, int) throws java.io.FileNotFoundException;
     method public static android.os.ParcelFileDescriptor open(java.io.File, int, android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener) throws java.io.IOException;
-    method public static int parseMode(java.lang.String);
+    method public static int parseMode(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.ParcelFileDescriptor> CREATOR;
     field public static final int MODE_APPEND = 33554432; // 0x2000000
@@ -34462,8 +34794,8 @@
     field public static final int MODE_READ_ONLY = 268435456; // 0x10000000
     field public static final int MODE_READ_WRITE = 805306368; // 0x30000000
     field public static final int MODE_TRUNCATE = 67108864; // 0x4000000
-    field public static final deprecated int MODE_WORLD_READABLE = 1; // 0x1
-    field public static final deprecated int MODE_WORLD_WRITEABLE = 2; // 0x2
+    field @Deprecated public static final int MODE_WORLD_READABLE = 1; // 0x1
+    field @Deprecated public static final int MODE_WORLD_WRITEABLE = 2; // 0x2
     field public static final int MODE_WRITE_ONLY = 536870912; // 0x20000000
   }
 
@@ -34479,47 +34811,47 @@
     ctor public ParcelFileDescriptor.FileDescriptorDetachedException();
   }
 
-  public static abstract interface ParcelFileDescriptor.OnCloseListener {
-    method public abstract void onClose(java.io.IOException);
+  public static interface ParcelFileDescriptor.OnCloseListener {
+    method public void onClose(java.io.IOException);
   }
 
   public class ParcelFormatException extends java.lang.RuntimeException {
     ctor public ParcelFormatException();
-    ctor public ParcelFormatException(java.lang.String);
+    ctor public ParcelFormatException(String);
   }
 
   public final class ParcelUuid implements android.os.Parcelable {
     ctor public ParcelUuid(java.util.UUID);
     method public int describeContents();
-    method public static android.os.ParcelUuid fromString(java.lang.String);
+    method public static android.os.ParcelUuid fromString(String);
     method public java.util.UUID getUuid();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.ParcelUuid> CREATOR;
   }
 
-  public abstract interface Parcelable {
-    method public abstract int describeContents();
-    method public abstract void writeToParcel(android.os.Parcel, int);
+  public interface Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONTENTS_FILE_DESCRIPTOR = 1; // 0x1
     field public static final int PARCELABLE_WRITE_RETURN_VALUE = 1; // 0x1
   }
 
-  public static abstract interface Parcelable.ClassLoaderCreator<T> implements android.os.Parcelable.Creator {
-    method public abstract T createFromParcel(android.os.Parcel, java.lang.ClassLoader);
+  public static interface Parcelable.ClassLoaderCreator<T> extends android.os.Parcelable.Creator<T> {
+    method public T createFromParcel(android.os.Parcel, ClassLoader);
   }
 
-  public static abstract interface Parcelable.Creator<T> {
-    method public abstract T createFromParcel(android.os.Parcel);
-    method public abstract T[] newArray(int);
+  public static interface Parcelable.Creator<T> {
+    method public T createFromParcel(android.os.Parcel);
+    method public T[] newArray(int);
   }
 
   public class PatternMatcher implements android.os.Parcelable {
-    ctor public PatternMatcher(java.lang.String, int);
+    ctor public PatternMatcher(String, int);
     ctor public PatternMatcher(android.os.Parcel);
     method public int describeContents();
-    method public final java.lang.String getPath();
+    method public final String getPath();
     method public final int getType();
-    method public boolean match(java.lang.String);
+    method public boolean match(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.PatternMatcher> CREATOR;
     field public static final int PATTERN_ADVANCED_GLOB = 3; // 0x3
@@ -34532,12 +34864,11 @@
     ctor public PersistableBundle();
     ctor public PersistableBundle(int);
     ctor public PersistableBundle(android.os.PersistableBundle);
-    method public java.lang.Object clone();
+    method public Object clone();
     method public android.os.PersistableBundle deepCopy();
     method public int describeContents();
-    method public android.os.PersistableBundle getPersistableBundle(java.lang.String);
-    method public void putPersistableBundle(java.lang.String, android.os.PersistableBundle);
-    method public synchronized java.lang.String toString();
+    method @Nullable public android.os.PersistableBundle getPersistableBundle(@Nullable String);
+    method public void putPersistableBundle(@Nullable String, @Nullable android.os.PersistableBundle);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.PersistableBundle> CREATOR;
     field public static final android.os.PersistableBundle EMPTY;
@@ -34547,20 +34878,20 @@
     method public int getCurrentThermalStatus();
     method public int getLocationPowerSaveMode();
     method public boolean isDeviceIdleMode();
-    method public boolean isIgnoringBatteryOptimizations(java.lang.String);
+    method public boolean isIgnoringBatteryOptimizations(String);
     method public boolean isInteractive();
     method public boolean isPowerSaveMode();
-    method public deprecated boolean isScreenOn();
+    method @Deprecated public boolean isScreenOn();
     method public boolean isSustainedPerformanceModeSupported();
     method public boolean isWakeLockLevelSupported(int);
-    method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
-    method public void reboot(java.lang.String);
-    method public void registerThermalStatusCallback(android.os.PowerManager.ThermalStatusCallback, java.util.concurrent.Executor);
+    method public android.os.PowerManager.WakeLock newWakeLock(int, String);
+    method public void reboot(String);
+    method public void registerThermalStatusCallback(@NonNull android.os.PowerManager.ThermalStatusCallback, @NonNull java.util.concurrent.Executor);
     method public void unregisterThermalStatusCallback(android.os.PowerManager.ThermalStatusCallback);
     field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
-    field public static final java.lang.String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
-    field public static final java.lang.String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
-    field public static final deprecated int FULL_WAKE_LOCK = 26; // 0x1a
+    field public static final String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
+    field public static final String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
+    field @Deprecated public static final int FULL_WAKE_LOCK = 26; // 0x1a
     field public static final int LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF = 2; // 0x2
     field public static final int LOCATION_MODE_FOREGROUND_ONLY = 3; // 0x3
     field public static final int LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF = 1; // 0x1
@@ -34569,8 +34900,8 @@
     field public static final int PARTIAL_WAKE_LOCK = 1; // 0x1
     field public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32; // 0x20
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
-    field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
-    field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+    field @Deprecated public static final int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
+    field @Deprecated public static final int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
     field public static final int THERMAL_STATUS_CRITICAL = 4; // 0x4
     field public static final int THERMAL_STATUS_EMERGENCY = 5; // 0x5
     field public static final int THERMAL_STATUS_LIGHT = 1; // 0x1
@@ -34580,7 +34911,7 @@
     field public static final int THERMAL_STATUS_SHUTDOWN = 6; // 0x6
   }
 
-  public static abstract class PowerManager.ThermalStatusCallback {
+  public abstract static class PowerManager.ThermalStatusCallback {
     ctor public PowerManager.ThermalStatusCallback();
     method public void onStatusChange(int);
   }
@@ -34599,11 +34930,11 @@
     ctor public Process();
     method public static final long getElapsedCpuTime();
     method public static final int[] getExclusiveCores();
-    method public static final int getGidForName(java.lang.String);
+    method public static final int getGidForName(String);
     method public static final long getStartElapsedRealtime();
     method public static final long getStartUptimeMillis();
     method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
-    method public static final int getUidForName(java.lang.String);
+    method public static final int getUidForName(String);
     method public static final boolean is64Bit();
     method public static boolean isApplicationUid(int);
     method public static final boolean isIsolated();
@@ -34615,11 +34946,14 @@
     method public static final void sendSignal(int, int);
     method public static final void setThreadPriority(int, int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
     method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
-    method public static final deprecated boolean supportsProcesses();
+    method @Deprecated public static final boolean supportsProcesses();
+    field public static final int BLUETOOTH_UID = 1002; // 0x3ea
     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 ROOT_UID = 0; // 0x0
+    field public static final int SHELL_UID = 2000; // 0x7d0
     field public static final int SIGNAL_KILL = 9; // 0x9
     field public static final int SIGNAL_QUIT = 3; // 0x3
     field public static final int SIGNAL_USR1 = 10; // 0xa
@@ -34647,36 +34981,36 @@
   }
 
   public class RecoverySystem {
-    method public static void installPackage(android.content.Context, java.io.File) throws java.io.IOException;
+    method @RequiresPermission("android.permission.RECOVERY") public static void installPackage(android.content.Context, java.io.File) throws java.io.IOException;
     method public static void rebootWipeCache(android.content.Context) throws java.io.IOException;
     method public static void rebootWipeUserData(android.content.Context) throws java.io.IOException;
     method public static void verifyPackage(java.io.File, android.os.RecoverySystem.ProgressListener, java.io.File) throws java.security.GeneralSecurityException, java.io.IOException;
   }
 
-  public static abstract interface RecoverySystem.ProgressListener {
-    method public abstract void onProgress(int);
+  public static interface RecoverySystem.ProgressListener {
+    method public void onProgress(int);
   }
 
   public class RemoteCallbackList<E extends android.os.IInterface> {
     ctor public RemoteCallbackList();
     method public int beginBroadcast();
     method public void finishBroadcast();
-    method public java.lang.Object getBroadcastCookie(int);
+    method public Object getBroadcastCookie(int);
     method public E getBroadcastItem(int);
-    method public java.lang.Object getRegisteredCallbackCookie(int);
+    method public Object getRegisteredCallbackCookie(int);
     method public int getRegisteredCallbackCount();
     method public E getRegisteredCallbackItem(int);
     method public void kill();
     method public void onCallbackDied(E);
-    method public void onCallbackDied(E, java.lang.Object);
+    method public void onCallbackDied(E, Object);
     method public boolean register(E);
-    method public boolean register(E, java.lang.Object);
+    method public boolean register(E, Object);
     method public boolean unregister(E);
   }
 
   public class RemoteException extends android.util.AndroidException {
     ctor public RemoteException();
-    ctor public RemoteException(java.lang.String);
+    ctor public RemoteException(String);
   }
 
   public class ResultReceiver implements android.os.Parcelable {
@@ -34690,32 +35024,32 @@
 
   public final class SharedMemory implements java.io.Closeable android.os.Parcelable {
     method public void close();
-    method public static android.os.SharedMemory create(java.lang.String, int) throws android.system.ErrnoException;
+    method @NonNull public static android.os.SharedMemory create(@Nullable String, int) throws android.system.ErrnoException;
     method public int describeContents();
     method public int getSize();
-    method public java.nio.ByteBuffer map(int, int, int) throws android.system.ErrnoException;
-    method public java.nio.ByteBuffer mapReadOnly() throws android.system.ErrnoException;
-    method public java.nio.ByteBuffer mapReadWrite() throws android.system.ErrnoException;
+    method @NonNull public java.nio.ByteBuffer map(int, int, int) throws android.system.ErrnoException;
+    method @NonNull public java.nio.ByteBuffer mapReadOnly() throws android.system.ErrnoException;
+    method @NonNull public java.nio.ByteBuffer mapReadWrite() throws android.system.ErrnoException;
     method public boolean setProtect(int);
-    method public static void unmap(java.nio.ByteBuffer);
-    method public void writeToParcel(android.os.Parcel, int);
+    method public static void unmap(@NonNull java.nio.ByteBuffer);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.SharedMemory> CREATOR;
   }
 
   public class StatFs {
-    ctor public StatFs(java.lang.String);
-    method public deprecated int getAvailableBlocks();
+    ctor public StatFs(String);
+    method @Deprecated public int getAvailableBlocks();
     method public long getAvailableBlocksLong();
     method public long getAvailableBytes();
-    method public deprecated int getBlockCount();
+    method @Deprecated public int getBlockCount();
     method public long getBlockCountLong();
-    method public deprecated int getBlockSize();
+    method @Deprecated public int getBlockSize();
     method public long getBlockSizeLong();
-    method public deprecated int getFreeBlocks();
+    method @Deprecated public int getFreeBlocks();
     method public long getFreeBlocksLong();
     method public long getFreeBytes();
     method public long getTotalBytes();
-    method public void restat(java.lang.String);
+    method public void restat(String);
   }
 
   public final class StrictMode {
@@ -34724,17 +35058,17 @@
     method public static void enableDefaults();
     method public static android.os.StrictMode.ThreadPolicy getThreadPolicy();
     method public static android.os.StrictMode.VmPolicy getVmPolicy();
-    method public static void noteSlowCall(java.lang.String);
+    method public static void noteSlowCall(String);
     method public static void setThreadPolicy(android.os.StrictMode.ThreadPolicy);
     method public static void setVmPolicy(android.os.StrictMode.VmPolicy);
   }
 
-  public static abstract interface StrictMode.OnThreadViolationListener {
-    method public abstract void onThreadViolation(android.os.strictmode.Violation);
+  public static interface StrictMode.OnThreadViolationListener {
+    method public void onThreadViolation(android.os.strictmode.Violation);
   }
 
-  public static abstract interface StrictMode.OnVmViolationListener {
-    method public abstract void onVmViolation(android.os.strictmode.Violation);
+  public static interface StrictMode.OnVmViolationListener {
+    method public void onVmViolation(android.os.strictmode.Violation);
   }
 
   public static final class StrictMode.ThreadPolicy {
@@ -34757,7 +35091,7 @@
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDialog();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDropBox();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyFlashScreen();
-    method public android.os.StrictMode.ThreadPolicy.Builder penaltyListener(java.util.concurrent.Executor, android.os.StrictMode.OnThreadViolationListener);
+    method public android.os.StrictMode.ThreadPolicy.Builder penaltyListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.StrictMode.OnThreadViolationListener);
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyLog();
     method public android.os.StrictMode.ThreadPolicy.Builder permitAll();
     method public android.os.StrictMode.ThreadPolicy.Builder permitCustomSlowCalls();
@@ -34792,10 +35126,10 @@
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
-    method public android.os.StrictMode.VmPolicy.Builder penaltyListener(java.util.concurrent.Executor, android.os.StrictMode.OnVmViolationListener);
+    method public android.os.StrictMode.VmPolicy.Builder penaltyListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.StrictMode.OnVmViolationListener);
     method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
     method public android.os.StrictMode.VmPolicy.Builder permitNonSdkApiUsage();
-    method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
+    method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(Class, int);
   }
 
   public final class SystemClock {
@@ -34810,16 +35144,16 @@
   public class TestLooperManager {
     method public void execute(android.os.Message);
     method public android.os.MessageQueue getMessageQueue();
-    method public boolean hasMessages(android.os.Handler, java.lang.Object, int);
-    method public boolean hasMessages(android.os.Handler, java.lang.Object, java.lang.Runnable);
+    method public boolean hasMessages(android.os.Handler, Object, int);
+    method public boolean hasMessages(android.os.Handler, Object, Runnable);
     method public android.os.Message next();
     method public void recycle(android.os.Message);
     method public void release();
   }
 
   public abstract class TokenWatcher {
-    ctor public TokenWatcher(android.os.Handler, java.lang.String);
-    method public void acquire(android.os.IBinder, java.lang.String);
+    ctor public TokenWatcher(android.os.Handler, String);
+    method public void acquire(android.os.IBinder, String);
     method public abstract void acquired();
     method public void cleanup(android.os.IBinder, boolean);
     method public void dump();
@@ -34830,17 +35164,17 @@
   }
 
   public final class Trace {
-    method public static void beginAsyncSection(java.lang.String, int);
-    method public static void beginSection(java.lang.String);
-    method public static void endAsyncSection(java.lang.String, int);
+    method public static void beginAsyncSection(@NonNull String, int);
+    method public static void beginSection(@NonNull String);
+    method public static void endAsyncSection(@NonNull String, int);
     method public static void endSection();
     method public static boolean isEnabled();
-    method public static void setCounter(java.lang.String, long);
+    method public static void setCounter(@NonNull String, long);
   }
 
   public class TransactionTooLargeException extends android.os.RemoteException {
     ctor public TransactionTooLargeException();
-    ctor public TransactionTooLargeException(java.lang.String);
+    ctor public TransactionTooLargeException(String);
   }
 
   public final class UserHandle implements android.os.Parcelable {
@@ -34854,17 +35188,17 @@
   }
 
   public class UserManager {
-    method public static android.content.Intent createUserCreationIntent(java.lang.String, java.lang.String, java.lang.String, android.os.PersistableBundle);
-    method public android.os.Bundle getApplicationRestrictions(java.lang.String);
+    method public static android.content.Intent createUserCreationIntent(@Nullable String, @Nullable String, @Nullable String, @Nullable android.os.PersistableBundle);
+    method @WorkerThread public android.os.Bundle getApplicationRestrictions(String);
     method public long getSerialNumberForUser(android.os.UserHandle);
     method public int getUserCount();
     method public long getUserCreationTime(android.os.UserHandle);
     method public android.os.UserHandle getUserForSerialNumber(long);
-    method public java.lang.String getUserName();
+    method public String getUserName();
     method public java.util.List<android.os.UserHandle> getUserProfiles();
     method public android.os.Bundle getUserRestrictions();
     method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
-    method public boolean hasUserRestriction(java.lang.String);
+    method public boolean hasUserRestriction(String);
     method public boolean isDemoUser();
     method public boolean isQuietModeEnabled(android.os.UserHandle);
     method public boolean isSystemUser();
@@ -34873,67 +35207,67 @@
     method public boolean isUserRunningOrStopping(android.os.UserHandle);
     method public boolean isUserUnlocked();
     method public boolean isUserUnlocked(android.os.UserHandle);
-    method public boolean requestQuietModeEnabled(boolean, android.os.UserHandle);
-    method public deprecated boolean setRestrictionsChallenge(java.lang.String);
-    method public deprecated void setUserRestriction(java.lang.String, boolean);
-    method public deprecated void setUserRestrictions(android.os.Bundle);
-    method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
+    method public boolean requestQuietModeEnabled(boolean, @NonNull android.os.UserHandle);
+    method @Deprecated public boolean setRestrictionsChallenge(String);
+    method @Deprecated public void setUserRestriction(String, boolean);
+    method @Deprecated public void setUserRestrictions(android.os.Bundle);
+    method @Deprecated public void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
     method public static boolean supportsMultipleUsers();
-    field public static final java.lang.String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking";
-    field public static final java.lang.String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile";
-    field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
-    field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
-    field public static final java.lang.String DISALLOW_AIRPLANE_MODE = "no_airplane_mode";
-    field public static final java.lang.String DISALLOW_AMBIENT_DISPLAY = "no_ambient_display";
-    field public static final java.lang.String DISALLOW_APPS_CONTROL = "no_control_apps";
-    field public static final java.lang.String DISALLOW_AUTOFILL = "no_autofill";
-    field public static final java.lang.String DISALLOW_BLUETOOTH = "no_bluetooth";
-    field public static final java.lang.String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing";
-    field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
-    field public static final java.lang.String DISALLOW_CONFIG_BRIGHTNESS = "no_config_brightness";
-    field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
-    field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
-    field public static final java.lang.String DISALLOW_CONFIG_DATE_TIME = "no_config_date_time";
-    field public static final java.lang.String DISALLOW_CONFIG_LOCALE = "no_config_locale";
-    field public static final java.lang.String DISALLOW_CONFIG_LOCATION = "no_config_location";
-    field public static final java.lang.String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
-    field public static final java.lang.String DISALLOW_CONFIG_PRIVATE_DNS = "disallow_config_private_dns";
-    field public static final java.lang.String DISALLOW_CONFIG_SCREEN_TIMEOUT = "no_config_screen_timeout";
-    field public static final java.lang.String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
-    field public static final java.lang.String DISALLOW_CONFIG_VPN = "no_config_vpn";
-    field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
-    field public static final java.lang.String DISALLOW_CONTENT_CAPTURE = "no_content_capture";
-    field public static final java.lang.String DISALLOW_CREATE_WINDOWS = "no_create_windows";
-    field public static final java.lang.String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";
-    field public static final java.lang.String DISALLOW_DATA_ROAMING = "no_data_roaming";
-    field public static final java.lang.String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
-    field public static final java.lang.String DISALLOW_FACTORY_RESET = "no_factory_reset";
-    field public static final java.lang.String DISALLOW_FUN = "no_fun";
-    field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps";
-    field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
-    field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY = "no_install_unknown_sources_globally";
-    field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
-    field public static final java.lang.String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
-    field public static final java.lang.String DISALLOW_NETWORK_RESET = "no_network_reset";
-    field public static final java.lang.String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
-    field public static final java.lang.String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
-    field public static final java.lang.String DISALLOW_PRINTING = "no_printing";
-    field public static final java.lang.String DISALLOW_REMOVE_MANAGED_PROFILE = "no_remove_managed_profile";
-    field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
-    field public static final java.lang.String DISALLOW_SAFE_BOOT = "no_safe_boot";
-    field public static final java.lang.String DISALLOW_SET_USER_ICON = "no_set_user_icon";
-    field public static final java.lang.String DISALLOW_SET_WALLPAPER = "no_set_wallpaper";
-    field public static final java.lang.String DISALLOW_SHARE_INTO_MANAGED_PROFILE = "no_sharing_into_profile";
-    field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
-    field public static final java.lang.String DISALLOW_SMS = "no_sms";
-    field public static final java.lang.String DISALLOW_SYSTEM_ERROR_DIALOGS = "no_system_error_dialogs";
-    field public static final java.lang.String DISALLOW_UNIFIED_PASSWORD = "no_unified_password";
-    field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
-    field public static final java.lang.String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
-    field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
-    field public static final java.lang.String DISALLOW_USER_SWITCH = "no_user_switch";
-    field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
-    field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
+    field public static final String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking";
+    field public static final String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile";
+    field public static final String DISALLOW_ADD_USER = "no_add_user";
+    field public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
+    field public static final String DISALLOW_AIRPLANE_MODE = "no_airplane_mode";
+    field public static final String DISALLOW_AMBIENT_DISPLAY = "no_ambient_display";
+    field public static final String DISALLOW_APPS_CONTROL = "no_control_apps";
+    field public static final String DISALLOW_AUTOFILL = "no_autofill";
+    field public static final String DISALLOW_BLUETOOTH = "no_bluetooth";
+    field public static final String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing";
+    field public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
+    field public static final String DISALLOW_CONFIG_BRIGHTNESS = "no_config_brightness";
+    field public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
+    field public static final String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
+    field public static final String DISALLOW_CONFIG_DATE_TIME = "no_config_date_time";
+    field public static final String DISALLOW_CONFIG_LOCALE = "no_config_locale";
+    field public static final String DISALLOW_CONFIG_LOCATION = "no_config_location";
+    field public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
+    field public static final String DISALLOW_CONFIG_PRIVATE_DNS = "disallow_config_private_dns";
+    field public static final String DISALLOW_CONFIG_SCREEN_TIMEOUT = "no_config_screen_timeout";
+    field public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
+    field public static final String DISALLOW_CONFIG_VPN = "no_config_vpn";
+    field public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi";
+    field public static final String DISALLOW_CONTENT_CAPTURE = "no_content_capture";
+    field public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows";
+    field public static final String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";
+    field public static final String DISALLOW_DATA_ROAMING = "no_data_roaming";
+    field public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
+    field public static final String DISALLOW_FACTORY_RESET = "no_factory_reset";
+    field public static final String DISALLOW_FUN = "no_fun";
+    field public static final String DISALLOW_INSTALL_APPS = "no_install_apps";
+    field public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
+    field public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY = "no_install_unknown_sources_globally";
+    field public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
+    field public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
+    field public static final String DISALLOW_NETWORK_RESET = "no_network_reset";
+    field public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
+    field public static final String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
+    field public static final String DISALLOW_PRINTING = "no_printing";
+    field public static final String DISALLOW_REMOVE_MANAGED_PROFILE = "no_remove_managed_profile";
+    field public static final String DISALLOW_REMOVE_USER = "no_remove_user";
+    field public static final String DISALLOW_SAFE_BOOT = "no_safe_boot";
+    field public static final String DISALLOW_SET_USER_ICON = "no_set_user_icon";
+    field public static final String DISALLOW_SET_WALLPAPER = "no_set_wallpaper";
+    field public static final String DISALLOW_SHARE_INTO_MANAGED_PROFILE = "no_sharing_into_profile";
+    field public static final String DISALLOW_SHARE_LOCATION = "no_share_location";
+    field public static final String DISALLOW_SMS = "no_sms";
+    field public static final String DISALLOW_SYSTEM_ERROR_DIALOGS = "no_system_error_dialogs";
+    field public static final String DISALLOW_UNIFIED_PASSWORD = "no_unified_password";
+    field public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
+    field public static final String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
+    field public static final String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
+    field public static final String DISALLOW_USER_SWITCH = "no_user_switch";
+    field public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps";
+    field public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
     field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
     field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
     field public static final int USER_OPERATION_ERROR_CURRENT_USER = 4; // 0x4
@@ -34959,15 +35293,15 @@
   }
 
   public abstract class Vibrator {
-    method public abstract void cancel();
+    method @RequiresPermission(android.Manifest.permission.VIBRATE) public abstract void cancel();
     method public abstract boolean hasAmplitudeControl();
     method public abstract boolean hasVibrator();
-    method public deprecated void vibrate(long);
-    method public deprecated void vibrate(long, android.media.AudioAttributes);
-    method public deprecated void vibrate(long[], int);
-    method public deprecated void vibrate(long[], int, android.media.AudioAttributes);
-    method public void vibrate(android.os.VibrationEffect);
-    method public void vibrate(android.os.VibrationEffect, android.media.AudioAttributes);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(long);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(long, android.media.AudioAttributes);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(long[], int);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(long[], int, android.media.AudioAttributes);
+    method @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(android.os.VibrationEffect);
+    method @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(android.os.VibrationEffect, android.media.AudioAttributes);
   }
 
   public class WorkSource implements android.os.Parcelable {
@@ -34988,14 +35322,14 @@
 package android.os.health {
 
   public class HealthStats {
-    method public java.lang.String getDataType();
+    method public String getDataType();
     method public long getMeasurement(int);
     method public int getMeasurementKeyAt(int);
     method public int getMeasurementKeyCount();
-    method public java.util.Map<java.lang.String, java.lang.Long> getMeasurements(int);
+    method public java.util.Map<java.lang.String,java.lang.Long> getMeasurements(int);
     method public int getMeasurementsKeyAt(int);
     method public int getMeasurementsKeyCount();
-    method public java.util.Map<java.lang.String, android.os.health.HealthStats> getStats(int);
+    method public java.util.Map<java.lang.String,android.os.health.HealthStats> getStats(int);
     method public int getStatsKeyAt(int);
     method public int getStatsKeyCount();
     method public android.os.health.TimerStat getTimer(int);
@@ -35003,7 +35337,7 @@
     method public int getTimerKeyAt(int);
     method public int getTimerKeyCount();
     method public long getTimerTime(int);
-    method public java.util.Map<java.lang.String, android.os.health.TimerStat> getTimers(int);
+    method public java.util.Map<java.lang.String,android.os.health.TimerStat> getTimers(int);
     method public int getTimersKeyAt(int);
     method public int getTimersKeyCount();
     method public boolean hasMeasurement(int);
@@ -35067,7 +35401,7 @@
     field public static final int MEASUREMENT_BLUETOOTH_TX_MS = 10022; // 0x2726
     field public static final int MEASUREMENT_BLUETOOTH_TX_PACKETS = 10059; // 0x274b
     field public static final int MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT = 10046; // 0x273e
-    field public static final deprecated int MEASUREMENT_CPU_POWER_MAMS = 10064; // 0x2750
+    field @Deprecated public static final int MEASUREMENT_CPU_POWER_MAMS = 10064; // 0x2750
     field public static final int MEASUREMENT_MOBILE_IDLE_MS = 10024; // 0x2728
     field public static final int MEASUREMENT_MOBILE_POWER_MAMS = 10027; // 0x272b
     field public static final int MEASUREMENT_MOBILE_RX_BYTES = 10048; // 0x2740
@@ -35129,7 +35463,7 @@
 
   public abstract class OnObbStateChangeListener {
     ctor public OnObbStateChangeListener();
-    method public void onObbStateChange(java.lang.String, int);
+    method public void onObbStateChange(String, int);
     field public static final int ERROR_ALREADY_MOUNTED = 24; // 0x18
     field public static final int ERROR_COULD_NOT_MOUNT = 21; // 0x15
     field public static final int ERROR_COULD_NOT_UNMOUNT = 22; // 0x16
@@ -35141,45 +35475,45 @@
   }
 
   public class StorageManager {
-    method public void allocateBytes(java.util.UUID, long) throws java.io.IOException;
-    method public void allocateBytes(java.io.FileDescriptor, long) throws java.io.IOException;
-    method public long getAllocatableBytes(java.util.UUID) throws java.io.IOException;
-    method public long getCacheQuotaBytes(java.util.UUID) throws java.io.IOException;
-    method public long getCacheSizeBytes(java.util.UUID) throws java.io.IOException;
-    method public java.lang.String getMountedObbPath(java.lang.String);
-    method public android.os.storage.StorageVolume getPrimaryStorageVolume();
-    method public android.os.storage.StorageVolume getStorageVolume(java.io.File);
-    method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
-    method public java.util.UUID getUuidForPath(java.io.File) throws java.io.IOException;
-    method public boolean isAllocationSupported(java.io.FileDescriptor);
+    method @WorkerThread public void allocateBytes(@NonNull java.util.UUID, long) throws java.io.IOException;
+    method @WorkerThread public void allocateBytes(java.io.FileDescriptor, long) throws java.io.IOException;
+    method @WorkerThread public long getAllocatableBytes(@NonNull java.util.UUID) throws java.io.IOException;
+    method @WorkerThread public long getCacheQuotaBytes(@NonNull java.util.UUID) throws java.io.IOException;
+    method @WorkerThread public long getCacheSizeBytes(@NonNull java.util.UUID) throws java.io.IOException;
+    method public String getMountedObbPath(String);
+    method @NonNull public android.os.storage.StorageVolume getPrimaryStorageVolume();
+    method @Nullable public android.os.storage.StorageVolume getStorageVolume(java.io.File);
+    method @NonNull public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
+    method @NonNull public java.util.UUID getUuidForPath(@NonNull java.io.File) throws java.io.IOException;
+    method public boolean isAllocationSupported(@NonNull java.io.FileDescriptor);
     method public boolean isCacheBehaviorGroup(java.io.File) throws java.io.IOException;
     method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException;
     method public boolean isEncrypted(java.io.File);
-    method public boolean isObbMounted(java.lang.String);
-    method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
-    method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler) throws java.io.IOException;
+    method public boolean isObbMounted(String);
+    method public boolean mountObb(String, String, android.os.storage.OnObbStateChangeListener);
+    method @NonNull public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler) throws java.io.IOException;
     method public void setCacheBehaviorGroup(java.io.File, boolean) throws java.io.IOException;
     method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
-    method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
-    field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
-    field public static final java.lang.String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES";
-    field public static final java.lang.String EXTRA_UUID = "android.os.storage.extra.UUID";
+    method public boolean unmountObb(String, boolean, android.os.storage.OnObbStateChangeListener);
+    field public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
+    field public static final String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES";
+    field public static final String EXTRA_UUID = "android.os.storage.extra.UUID";
     field public static final java.util.UUID UUID_DEFAULT;
   }
 
   public final class StorageVolume implements android.os.Parcelable {
-    method public deprecated android.content.Intent createAccessIntent(java.lang.String);
-    method public android.content.Intent createOpenDocumentTreeIntent();
+    method @Deprecated @Nullable public android.content.Intent createAccessIntent(String);
+    method @NonNull public android.content.Intent createOpenDocumentTreeIntent();
     method public int describeContents();
-    method public java.lang.String getDescription(android.content.Context);
-    method public java.lang.String getState();
-    method public java.lang.String getUuid();
+    method public String getDescription(android.content.Context);
+    method public String getState();
+    method @Nullable public String getUuid();
     method public boolean isEmulated();
     method public boolean isPrimary();
     method public boolean isRemovable();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.storage.StorageVolume> CREATOR;
-    field public static final java.lang.String EXTRA_STORAGE_VOLUME = "android.os.storage.extra.STORAGE_VOLUME";
+    field public static final String EXTRA_STORAGE_VOLUME = "android.os.storage.extra.STORAGE_VOLUME";
   }
 
 }
@@ -35251,412 +35585,412 @@
 
 package android.preference {
 
-  public deprecated class CheckBoxPreference extends android.preference.TwoStatePreference {
-    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public CheckBoxPreference(android.content.Context, android.util.AttributeSet);
-    ctor public CheckBoxPreference(android.content.Context);
+  @Deprecated public class CheckBoxPreference extends android.preference.TwoStatePreference {
+    ctor @Deprecated public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public CheckBoxPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor @Deprecated public CheckBoxPreference(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public CheckBoxPreference(android.content.Context);
   }
 
-  public abstract deprecated class DialogPreference extends android.preference.Preference implements android.content.DialogInterface.OnClickListener android.content.DialogInterface.OnDismissListener android.preference.PreferenceManager.OnActivityDestroyListener {
-    ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public DialogPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public DialogPreference(android.content.Context, android.util.AttributeSet);
-    ctor public DialogPreference(android.content.Context);
-    method public android.app.Dialog getDialog();
-    method public android.graphics.drawable.Drawable getDialogIcon();
-    method public int getDialogLayoutResource();
-    method public java.lang.CharSequence getDialogMessage();
-    method public java.lang.CharSequence getDialogTitle();
-    method public java.lang.CharSequence getNegativeButtonText();
-    method public java.lang.CharSequence getPositiveButtonText();
-    method public void onActivityDestroy();
-    method protected void onBindDialogView(android.view.View);
-    method public void onClick(android.content.DialogInterface, int);
-    method protected android.view.View onCreateDialogView();
-    method protected void onDialogClosed(boolean);
-    method public void onDismiss(android.content.DialogInterface);
-    method protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder);
-    method public void setDialogIcon(android.graphics.drawable.Drawable);
-    method public void setDialogIcon(int);
-    method public void setDialogLayoutResource(int);
-    method public void setDialogMessage(java.lang.CharSequence);
-    method public void setDialogMessage(int);
-    method public void setDialogTitle(java.lang.CharSequence);
-    method public void setDialogTitle(int);
-    method public void setNegativeButtonText(java.lang.CharSequence);
-    method public void setNegativeButtonText(int);
-    method public void setPositiveButtonText(java.lang.CharSequence);
-    method public void setPositiveButtonText(int);
-    method protected void showDialog(android.os.Bundle);
+  @Deprecated public abstract class DialogPreference extends android.preference.Preference implements android.content.DialogInterface.OnClickListener android.content.DialogInterface.OnDismissListener android.preference.PreferenceManager.OnActivityDestroyListener {
+    ctor @Deprecated public DialogPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor @Deprecated public DialogPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public DialogPreference(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public DialogPreference(android.content.Context);
+    method @Deprecated public android.app.Dialog getDialog();
+    method @Deprecated public android.graphics.drawable.Drawable getDialogIcon();
+    method @Deprecated public int getDialogLayoutResource();
+    method @Deprecated public CharSequence getDialogMessage();
+    method @Deprecated public CharSequence getDialogTitle();
+    method @Deprecated public CharSequence getNegativeButtonText();
+    method @Deprecated public CharSequence getPositiveButtonText();
+    method @Deprecated public void onActivityDestroy();
+    method @Deprecated @CallSuper protected void onBindDialogView(android.view.View);
+    method @Deprecated public void onClick(android.content.DialogInterface, int);
+    method @Deprecated protected android.view.View onCreateDialogView();
+    method @Deprecated protected void onDialogClosed(boolean);
+    method @Deprecated public void onDismiss(android.content.DialogInterface);
+    method @Deprecated protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder);
+    method @Deprecated public void setDialogIcon(android.graphics.drawable.Drawable);
+    method @Deprecated public void setDialogIcon(@DrawableRes int);
+    method @Deprecated public void setDialogLayoutResource(int);
+    method @Deprecated public void setDialogMessage(CharSequence);
+    method @Deprecated public void setDialogMessage(int);
+    method @Deprecated public void setDialogTitle(CharSequence);
+    method @Deprecated public void setDialogTitle(int);
+    method @Deprecated public void setNegativeButtonText(CharSequence);
+    method @Deprecated public void setNegativeButtonText(@StringRes int);
+    method @Deprecated public void setPositiveButtonText(CharSequence);
+    method @Deprecated public void setPositiveButtonText(@StringRes int);
+    method @Deprecated protected void showDialog(android.os.Bundle);
   }
 
-  public deprecated class EditTextPreference extends android.preference.DialogPreference {
-    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public EditTextPreference(android.content.Context, android.util.AttributeSet);
-    ctor public EditTextPreference(android.content.Context);
-    method public android.widget.EditText getEditText();
-    method public java.lang.String getText();
-    method protected void onAddEditTextToDialogView(android.view.View, android.widget.EditText);
-    method public void setText(java.lang.String);
+  @Deprecated public class EditTextPreference extends android.preference.DialogPreference {
+    ctor @Deprecated public EditTextPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor @Deprecated public EditTextPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public EditTextPreference(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public EditTextPreference(android.content.Context);
+    method @Deprecated public android.widget.EditText getEditText();
+    method @Deprecated public String getText();
+    method @Deprecated protected void onAddEditTextToDialogView(android.view.View, android.widget.EditText);
+    method @Deprecated public void setText(String);
   }
 
-  public deprecated class ListPreference extends android.preference.DialogPreference {
-    ctor public ListPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public ListPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public ListPreference(android.content.Context, android.util.AttributeSet);
-    ctor public ListPreference(android.content.Context);
-    method public int findIndexOfValue(java.lang.String);
-    method public java.lang.CharSequence[] getEntries();
-    method public java.lang.CharSequence getEntry();
-    method public java.lang.CharSequence[] getEntryValues();
-    method public java.lang.String getValue();
-    method public void setEntries(java.lang.CharSequence[]);
-    method public void setEntries(int);
-    method public void setEntryValues(java.lang.CharSequence[]);
-    method public void setEntryValues(int);
-    method public void setValue(java.lang.String);
-    method public void setValueIndex(int);
+  @Deprecated public class ListPreference extends android.preference.DialogPreference {
+    ctor @Deprecated public ListPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor @Deprecated public ListPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public ListPreference(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public ListPreference(android.content.Context);
+    method @Deprecated public int findIndexOfValue(String);
+    method @Deprecated public CharSequence[] getEntries();
+    method @Deprecated public CharSequence getEntry();
+    method @Deprecated public CharSequence[] getEntryValues();
+    method @Deprecated public String getValue();
+    method @Deprecated public void setEntries(CharSequence[]);
+    method @Deprecated public void setEntries(@ArrayRes int);
+    method @Deprecated public void setEntryValues(CharSequence[]);
+    method @Deprecated public void setEntryValues(@ArrayRes int);
+    method @Deprecated public void setValue(String);
+    method @Deprecated public void setValueIndex(int);
   }
 
-  public deprecated class MultiSelectListPreference extends android.preference.DialogPreference {
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet);
-    ctor public MultiSelectListPreference(android.content.Context);
-    method public int findIndexOfValue(java.lang.String);
-    method public java.lang.CharSequence[] getEntries();
-    method public java.lang.CharSequence[] getEntryValues();
-    method public java.util.Set<java.lang.String> getValues();
-    method public void setEntries(java.lang.CharSequence[]);
-    method public void setEntries(int);
-    method public void setEntryValues(java.lang.CharSequence[]);
-    method public void setEntryValues(int);
-    method public void setValues(java.util.Set<java.lang.String>);
+  @Deprecated public class MultiSelectListPreference extends android.preference.DialogPreference {
+    ctor @Deprecated public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor @Deprecated public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public MultiSelectListPreference(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public MultiSelectListPreference(android.content.Context);
+    method @Deprecated public int findIndexOfValue(String);
+    method @Deprecated public CharSequence[] getEntries();
+    method @Deprecated public CharSequence[] getEntryValues();
+    method @Deprecated public java.util.Set<java.lang.String> getValues();
+    method @Deprecated public void setEntries(CharSequence[]);
+    method @Deprecated public void setEntries(@ArrayRes int);
+    method @Deprecated public void setEntryValues(CharSequence[]);
+    method @Deprecated public void setEntryValues(@ArrayRes int);
+    method @Deprecated public void setValues(java.util.Set<java.lang.String>);
   }
 
-  public deprecated class Preference implements java.lang.Comparable {
-    ctor public Preference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public Preference(android.content.Context, android.util.AttributeSet, int);
-    ctor public Preference(android.content.Context, android.util.AttributeSet);
-    ctor public Preference(android.content.Context);
-    method protected boolean callChangeListener(java.lang.Object);
-    method public int compareTo(android.preference.Preference);
-    method protected android.preference.Preference findPreferenceInHierarchy(java.lang.String);
-    method public android.content.Context getContext();
-    method public java.lang.String getDependency();
-    method public android.content.SharedPreferences.Editor getEditor();
-    method public android.os.Bundle getExtras();
-    method public java.lang.String getFragment();
-    method public android.graphics.drawable.Drawable getIcon();
-    method public android.content.Intent getIntent();
-    method public java.lang.String getKey();
-    method public int getLayoutResource();
-    method public android.preference.Preference.OnPreferenceChangeListener getOnPreferenceChangeListener();
-    method public android.preference.Preference.OnPreferenceClickListener getOnPreferenceClickListener();
-    method public int getOrder();
-    method public android.preference.PreferenceGroup getParent();
-    method protected boolean getPersistedBoolean(boolean);
-    method protected float getPersistedFloat(float);
-    method protected int getPersistedInt(int);
-    method protected long getPersistedLong(long);
-    method protected java.lang.String getPersistedString(java.lang.String);
-    method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
-    method public android.preference.PreferenceDataStore getPreferenceDataStore();
-    method public android.preference.PreferenceManager getPreferenceManager();
-    method public android.content.SharedPreferences getSharedPreferences();
-    method public boolean getShouldDisableView();
-    method public java.lang.CharSequence getSummary();
-    method public java.lang.CharSequence getTitle();
-    method public int getTitleRes();
-    method public android.view.View getView(android.view.View, android.view.ViewGroup);
-    method public int getWidgetLayoutResource();
-    method public boolean hasKey();
-    method public boolean isEnabled();
-    method public boolean isIconSpaceReserved();
-    method public boolean isPersistent();
-    method public boolean isRecycleEnabled();
-    method public boolean isSelectable();
-    method public boolean isSingleLineTitle();
-    method protected void notifyChanged();
-    method public void notifyDependencyChange(boolean);
-    method protected void notifyHierarchyChanged();
-    method protected void onAttachedToActivity();
-    method protected void onAttachedToHierarchy(android.preference.PreferenceManager);
-    method protected void onBindView(android.view.View);
-    method protected void onClick();
-    method protected android.view.View onCreateView(android.view.ViewGroup);
-    method public void onDependencyChanged(android.preference.Preference, boolean);
-    method protected java.lang.Object onGetDefaultValue(android.content.res.TypedArray, int);
-    method public void onParentChanged(android.preference.Preference, boolean);
-    method protected void onPrepareForRemoval();
-    method protected void onRestoreInstanceState(android.os.Parcelable);
-    method protected android.os.Parcelable onSaveInstanceState();
-    method protected void onSetInitialValue(boolean, java.lang.Object);
-    method public android.os.Bundle peekExtras();
-    method protected boolean persistBoolean(boolean);
-    method protected boolean persistFloat(float);
-    method protected boolean persistInt(int);
-    method protected boolean persistLong(long);
-    method protected boolean persistString(java.lang.String);
-    method public boolean persistStringSet(java.util.Set<java.lang.String>);
-    method public void restoreHierarchyState(android.os.Bundle);
-    method public void saveHierarchyState(android.os.Bundle);
-    method public void setDefaultValue(java.lang.Object);
-    method public void setDependency(java.lang.String);
-    method public void setEnabled(boolean);
-    method public void setFragment(java.lang.String);
-    method public void setIcon(android.graphics.drawable.Drawable);
-    method public void setIcon(int);
-    method public void setIconSpaceReserved(boolean);
-    method public void setIntent(android.content.Intent);
-    method public void setKey(java.lang.String);
-    method public void setLayoutResource(int);
-    method public void setOnPreferenceChangeListener(android.preference.Preference.OnPreferenceChangeListener);
-    method public void setOnPreferenceClickListener(android.preference.Preference.OnPreferenceClickListener);
-    method public void setOrder(int);
-    method public void setPersistent(boolean);
-    method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
-    method public void setRecycleEnabled(boolean);
-    method public void setSelectable(boolean);
-    method public void setShouldDisableView(boolean);
-    method public void setSingleLineTitle(boolean);
-    method public void setSummary(java.lang.CharSequence);
-    method public void setSummary(int);
-    method public void setTitle(java.lang.CharSequence);
-    method public void setTitle(int);
-    method public void setWidgetLayoutResource(int);
-    method public boolean shouldCommit();
-    method public boolean shouldDisableDependents();
-    method protected boolean shouldPersist();
-    field public static final int DEFAULT_ORDER = 2147483647; // 0x7fffffff
+  @Deprecated public class Preference implements java.lang.Comparable<android.preference.Preference> {
+    ctor @Deprecated public Preference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor @Deprecated public Preference(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public Preference(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public Preference(android.content.Context);
+    method @Deprecated protected boolean callChangeListener(Object);
+    method @Deprecated public int compareTo(android.preference.Preference);
+    method @Deprecated protected android.preference.Preference findPreferenceInHierarchy(String);
+    method @Deprecated public android.content.Context getContext();
+    method @Deprecated public String getDependency();
+    method @Deprecated public android.content.SharedPreferences.Editor getEditor();
+    method @Deprecated public android.os.Bundle getExtras();
+    method @Deprecated public String getFragment();
+    method @Deprecated public android.graphics.drawable.Drawable getIcon();
+    method @Deprecated public android.content.Intent getIntent();
+    method @Deprecated public String getKey();
+    method @Deprecated @LayoutRes public int getLayoutResource();
+    method @Deprecated public android.preference.Preference.OnPreferenceChangeListener getOnPreferenceChangeListener();
+    method @Deprecated public android.preference.Preference.OnPreferenceClickListener getOnPreferenceClickListener();
+    method @Deprecated public int getOrder();
+    method @Deprecated @Nullable public android.preference.PreferenceGroup getParent();
+    method @Deprecated protected boolean getPersistedBoolean(boolean);
+    method @Deprecated protected float getPersistedFloat(float);
+    method @Deprecated protected int getPersistedInt(int);
+    method @Deprecated protected long getPersistedLong(long);
+    method @Deprecated protected String getPersistedString(String);
+    method @Deprecated public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
+    method @Deprecated @Nullable public android.preference.PreferenceDataStore getPreferenceDataStore();
+    method @Deprecated public android.preference.PreferenceManager getPreferenceManager();
+    method @Deprecated public android.content.SharedPreferences getSharedPreferences();
+    method @Deprecated public boolean getShouldDisableView();
+    method @Deprecated public CharSequence getSummary();
+    method @Deprecated public CharSequence getTitle();
+    method @Deprecated @StringRes public int getTitleRes();
+    method @Deprecated public android.view.View getView(android.view.View, android.view.ViewGroup);
+    method @Deprecated @LayoutRes public int getWidgetLayoutResource();
+    method @Deprecated public boolean hasKey();
+    method @Deprecated public boolean isEnabled();
+    method @Deprecated public boolean isIconSpaceReserved();
+    method @Deprecated public boolean isPersistent();
+    method @Deprecated public boolean isRecycleEnabled();
+    method @Deprecated public boolean isSelectable();
+    method @Deprecated public boolean isSingleLineTitle();
+    method @Deprecated protected void notifyChanged();
+    method @Deprecated public void notifyDependencyChange(boolean);
+    method @Deprecated protected void notifyHierarchyChanged();
+    method @Deprecated protected void onAttachedToActivity();
+    method @Deprecated protected void onAttachedToHierarchy(android.preference.PreferenceManager);
+    method @Deprecated @CallSuper protected void onBindView(android.view.View);
+    method @Deprecated protected void onClick();
+    method @Deprecated @CallSuper protected android.view.View onCreateView(android.view.ViewGroup);
+    method @Deprecated public void onDependencyChanged(android.preference.Preference, boolean);
+    method @Deprecated protected Object onGetDefaultValue(android.content.res.TypedArray, int);
+    method @Deprecated public void onParentChanged(android.preference.Preference, boolean);
+    method @Deprecated @CallSuper protected void onPrepareForRemoval();
+    method @Deprecated protected void onRestoreInstanceState(android.os.Parcelable);
+    method @Deprecated protected android.os.Parcelable onSaveInstanceState();
+    method @Deprecated protected void onSetInitialValue(boolean, Object);
+    method @Deprecated public android.os.Bundle peekExtras();
+    method @Deprecated protected boolean persistBoolean(boolean);
+    method @Deprecated protected boolean persistFloat(float);
+    method @Deprecated protected boolean persistInt(int);
+    method @Deprecated protected boolean persistLong(long);
+    method @Deprecated protected boolean persistString(String);
+    method @Deprecated public boolean persistStringSet(java.util.Set<java.lang.String>);
+    method @Deprecated public void restoreHierarchyState(android.os.Bundle);
+    method @Deprecated public void saveHierarchyState(android.os.Bundle);
+    method @Deprecated public void setDefaultValue(Object);
+    method @Deprecated public void setDependency(String);
+    method @Deprecated public void setEnabled(boolean);
+    method @Deprecated public void setFragment(String);
+    method @Deprecated public void setIcon(android.graphics.drawable.Drawable);
+    method @Deprecated public void setIcon(@DrawableRes int);
+    method @Deprecated public void setIconSpaceReserved(boolean);
+    method @Deprecated public void setIntent(android.content.Intent);
+    method @Deprecated public void setKey(String);
+    method @Deprecated public void setLayoutResource(@LayoutRes int);
+    method @Deprecated public void setOnPreferenceChangeListener(android.preference.Preference.OnPreferenceChangeListener);
+    method @Deprecated public void setOnPreferenceClickListener(android.preference.Preference.OnPreferenceClickListener);
+    method @Deprecated public void setOrder(int);
+    method @Deprecated public void setPersistent(boolean);
+    method @Deprecated public void setPreferenceDataStore(android.preference.PreferenceDataStore);
+    method @Deprecated @CallSuper public void setRecycleEnabled(boolean);
+    method @Deprecated public void setSelectable(boolean);
+    method @Deprecated public void setShouldDisableView(boolean);
+    method @Deprecated public void setSingleLineTitle(boolean);
+    method @Deprecated public void setSummary(CharSequence);
+    method @Deprecated public void setSummary(@StringRes int);
+    method @Deprecated public void setTitle(CharSequence);
+    method @Deprecated public void setTitle(@StringRes int);
+    method @Deprecated public void setWidgetLayoutResource(@LayoutRes int);
+    method @Deprecated public boolean shouldCommit();
+    method @Deprecated public boolean shouldDisableDependents();
+    method @Deprecated protected boolean shouldPersist();
+    field @Deprecated public static final int DEFAULT_ORDER = 2147483647; // 0x7fffffff
   }
 
-  public static deprecated class Preference.BaseSavedState extends android.view.AbsSavedState {
-    ctor public Preference.BaseSavedState(android.os.Parcel);
-    ctor public Preference.BaseSavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.preference.Preference.BaseSavedState> CREATOR;
+  @Deprecated public static class Preference.BaseSavedState extends android.view.AbsSavedState {
+    ctor @Deprecated public Preference.BaseSavedState(android.os.Parcel);
+    ctor @Deprecated public Preference.BaseSavedState(android.os.Parcelable);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.preference.Preference.BaseSavedState> CREATOR;
   }
 
-  public static abstract deprecated interface Preference.OnPreferenceChangeListener {
-    method public abstract boolean onPreferenceChange(android.preference.Preference, java.lang.Object);
+  @Deprecated public static interface Preference.OnPreferenceChangeListener {
+    method @Deprecated public boolean onPreferenceChange(android.preference.Preference, Object);
   }
 
-  public static abstract deprecated interface Preference.OnPreferenceClickListener {
-    method public abstract boolean onPreferenceClick(android.preference.Preference);
+  @Deprecated public static interface Preference.OnPreferenceClickListener {
+    method @Deprecated public boolean onPreferenceClick(android.preference.Preference);
   }
 
-  public abstract deprecated class PreferenceActivity extends android.app.ListActivity implements android.preference.PreferenceFragment.OnPreferenceStartFragmentCallback {
-    ctor public PreferenceActivity();
-    method public deprecated void addPreferencesFromIntent(android.content.Intent);
-    method public deprecated void addPreferencesFromResource(int);
-    method public deprecated android.preference.Preference findPreference(java.lang.CharSequence);
-    method public void finishPreferencePanel(android.app.Fragment, int, android.content.Intent);
-    method public deprecated android.preference.PreferenceManager getPreferenceManager();
-    method public deprecated android.preference.PreferenceScreen getPreferenceScreen();
-    method public boolean hasHeaders();
-    method public void invalidateHeaders();
-    method public boolean isMultiPane();
-    method protected boolean isValidFragment(java.lang.String);
-    method public void loadHeadersFromResource(int, java.util.List<android.preference.PreferenceActivity.Header>);
-    method public void onBuildHeaders(java.util.List<android.preference.PreferenceActivity.Header>);
-    method public android.content.Intent onBuildStartFragmentIntent(java.lang.String, android.os.Bundle, int, int);
-    method public android.preference.PreferenceActivity.Header onGetInitialHeader();
-    method public android.preference.PreferenceActivity.Header onGetNewHeader();
-    method public void onHeaderClick(android.preference.PreferenceActivity.Header, int);
-    method public boolean onIsHidingHeaders();
-    method public boolean onIsMultiPane();
-    method public boolean onPreferenceStartFragment(android.preference.PreferenceFragment, android.preference.Preference);
-    method public deprecated boolean onPreferenceTreeClick(android.preference.PreferenceScreen, android.preference.Preference);
-    method public void setListFooter(android.view.View);
-    method public void setParentTitle(java.lang.CharSequence, java.lang.CharSequence, android.view.View.OnClickListener);
-    method public deprecated void setPreferenceScreen(android.preference.PreferenceScreen);
-    method public void showBreadCrumbs(java.lang.CharSequence, java.lang.CharSequence);
-    method public void startPreferenceFragment(android.app.Fragment, boolean);
-    method public void startPreferencePanel(java.lang.String, android.os.Bundle, int, java.lang.CharSequence, android.app.Fragment, int);
-    method public void startWithFragment(java.lang.String, android.os.Bundle, android.app.Fragment, int);
-    method public void startWithFragment(java.lang.String, android.os.Bundle, android.app.Fragment, int, int, int);
-    method public void switchToHeader(java.lang.String, android.os.Bundle);
-    method public void switchToHeader(android.preference.PreferenceActivity.Header);
-    field public static final java.lang.String EXTRA_NO_HEADERS = ":android:no_headers";
-    field public static final java.lang.String EXTRA_SHOW_FRAGMENT = ":android:show_fragment";
-    field public static final java.lang.String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":android:show_fragment_args";
-    field public static final java.lang.String EXTRA_SHOW_FRAGMENT_SHORT_TITLE = ":android:show_fragment_short_title";
-    field public static final java.lang.String EXTRA_SHOW_FRAGMENT_TITLE = ":android:show_fragment_title";
-    field public static final long HEADER_ID_UNDEFINED = -1L; // 0xffffffffffffffffL
+  @Deprecated public abstract class PreferenceActivity extends android.app.ListActivity implements android.preference.PreferenceFragment.OnPreferenceStartFragmentCallback {
+    ctor @Deprecated public PreferenceActivity();
+    method @Deprecated public void addPreferencesFromIntent(android.content.Intent);
+    method @Deprecated public void addPreferencesFromResource(int);
+    method @Deprecated public android.preference.Preference findPreference(CharSequence);
+    method @Deprecated public void finishPreferencePanel(android.app.Fragment, int, android.content.Intent);
+    method @Deprecated public android.preference.PreferenceManager getPreferenceManager();
+    method @Deprecated public android.preference.PreferenceScreen getPreferenceScreen();
+    method @Deprecated public boolean hasHeaders();
+    method @Deprecated public void invalidateHeaders();
+    method @Deprecated public boolean isMultiPane();
+    method @Deprecated protected boolean isValidFragment(String);
+    method @Deprecated public void loadHeadersFromResource(@XmlRes int, java.util.List<android.preference.PreferenceActivity.Header>);
+    method @Deprecated public void onBuildHeaders(java.util.List<android.preference.PreferenceActivity.Header>);
+    method @Deprecated public android.content.Intent onBuildStartFragmentIntent(String, android.os.Bundle, @StringRes int, int);
+    method @Deprecated public android.preference.PreferenceActivity.Header onGetInitialHeader();
+    method @Deprecated public android.preference.PreferenceActivity.Header onGetNewHeader();
+    method @Deprecated public void onHeaderClick(android.preference.PreferenceActivity.Header, int);
+    method @Deprecated public boolean onIsHidingHeaders();
+    method @Deprecated public boolean onIsMultiPane();
+    method @Deprecated public boolean onPreferenceStartFragment(android.preference.PreferenceFragment, android.preference.Preference);
+    method @Deprecated public boolean onPreferenceTreeClick(android.preference.PreferenceScreen, android.preference.Preference);
+    method @Deprecated public void setListFooter(android.view.View);
+    method @Deprecated public void setParentTitle(CharSequence, CharSequence, android.view.View.OnClickListener);
+    method @Deprecated public void setPreferenceScreen(android.preference.PreferenceScreen);
+    method @Deprecated public void showBreadCrumbs(CharSequence, CharSequence);
+    method @Deprecated public void startPreferenceFragment(android.app.Fragment, boolean);
+    method @Deprecated public void startPreferencePanel(String, android.os.Bundle, @StringRes int, CharSequence, android.app.Fragment, int);
+    method @Deprecated public void startWithFragment(String, android.os.Bundle, android.app.Fragment, int);
+    method @Deprecated public void startWithFragment(String, android.os.Bundle, android.app.Fragment, int, @StringRes int, @StringRes int);
+    method @Deprecated public void switchToHeader(String, android.os.Bundle);
+    method @Deprecated public void switchToHeader(android.preference.PreferenceActivity.Header);
+    field @Deprecated public static final String EXTRA_NO_HEADERS = ":android:no_headers";
+    field @Deprecated public static final String EXTRA_SHOW_FRAGMENT = ":android:show_fragment";
+    field @Deprecated public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":android:show_fragment_args";
+    field @Deprecated public static final String EXTRA_SHOW_FRAGMENT_SHORT_TITLE = ":android:show_fragment_short_title";
+    field @Deprecated public static final String EXTRA_SHOW_FRAGMENT_TITLE = ":android:show_fragment_title";
+    field @Deprecated public static final long HEADER_ID_UNDEFINED = -1L; // 0xffffffffffffffffL
   }
 
-  public static final deprecated class PreferenceActivity.Header implements android.os.Parcelable {
-    ctor public PreferenceActivity.Header();
-    method public int describeContents();
-    method public java.lang.CharSequence getBreadCrumbShortTitle(android.content.res.Resources);
-    method public java.lang.CharSequence getBreadCrumbTitle(android.content.res.Resources);
-    method public java.lang.CharSequence getSummary(android.content.res.Resources);
-    method public java.lang.CharSequence getTitle(android.content.res.Resources);
-    method public void readFromParcel(android.os.Parcel);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.preference.PreferenceActivity.Header> CREATOR;
-    field public java.lang.CharSequence breadCrumbShortTitle;
-    field public int breadCrumbShortTitleRes;
-    field public java.lang.CharSequence breadCrumbTitle;
-    field public int breadCrumbTitleRes;
-    field public android.os.Bundle extras;
-    field public java.lang.String fragment;
-    field public android.os.Bundle fragmentArguments;
-    field public int iconRes;
-    field public long id;
-    field public android.content.Intent intent;
-    field public java.lang.CharSequence summary;
-    field public int summaryRes;
-    field public java.lang.CharSequence title;
-    field public int titleRes;
+  @Deprecated public static final class PreferenceActivity.Header implements android.os.Parcelable {
+    ctor @Deprecated public PreferenceActivity.Header();
+    method @Deprecated public int describeContents();
+    method @Deprecated public CharSequence getBreadCrumbShortTitle(android.content.res.Resources);
+    method @Deprecated public CharSequence getBreadCrumbTitle(android.content.res.Resources);
+    method @Deprecated public CharSequence getSummary(android.content.res.Resources);
+    method @Deprecated public CharSequence getTitle(android.content.res.Resources);
+    method @Deprecated public void readFromParcel(android.os.Parcel);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.preference.PreferenceActivity.Header> CREATOR;
+    field @Deprecated public CharSequence breadCrumbShortTitle;
+    field @Deprecated @StringRes public int breadCrumbShortTitleRes;
+    field @Deprecated public CharSequence breadCrumbTitle;
+    field @Deprecated @StringRes public int breadCrumbTitleRes;
+    field @Deprecated public android.os.Bundle extras;
+    field @Deprecated public String fragment;
+    field @Deprecated public android.os.Bundle fragmentArguments;
+    field @Deprecated public int iconRes;
+    field @Deprecated public long id;
+    field @Deprecated public android.content.Intent intent;
+    field @Deprecated public CharSequence summary;
+    field @Deprecated @StringRes public int summaryRes;
+    field @Deprecated public CharSequence title;
+    field @Deprecated @StringRes public int titleRes;
   }
 
-  public deprecated class PreferenceCategory extends android.preference.PreferenceGroup {
-    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet, int);
-    ctor public PreferenceCategory(android.content.Context, android.util.AttributeSet);
-    ctor public PreferenceCategory(android.content.Context);
+  @Deprecated public class PreferenceCategory extends android.preference.PreferenceGroup {
+    ctor @Deprecated public PreferenceCategory(android.content.Context, android.util.AttributeSet, int, int);
+    ctor @Deprecated public PreferenceCategory(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public PreferenceCategory(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public PreferenceCategory(android.content.Context);
   }
 
-  public abstract deprecated interface PreferenceDataStore {
-    method public default boolean getBoolean(java.lang.String, boolean);
-    method public default float getFloat(java.lang.String, float);
-    method public default int getInt(java.lang.String, int);
-    method public default long getLong(java.lang.String, long);
-    method public default java.lang.String getString(java.lang.String, java.lang.String);
-    method public default java.util.Set<java.lang.String> getStringSet(java.lang.String, java.util.Set<java.lang.String>);
-    method public default void putBoolean(java.lang.String, boolean);
-    method public default void putFloat(java.lang.String, float);
-    method public default void putInt(java.lang.String, int);
-    method public default void putLong(java.lang.String, long);
-    method public default void putString(java.lang.String, java.lang.String);
-    method public default void putStringSet(java.lang.String, java.util.Set<java.lang.String>);
+  @Deprecated public interface PreferenceDataStore {
+    method @Deprecated public default boolean getBoolean(String, boolean);
+    method @Deprecated public default float getFloat(String, float);
+    method @Deprecated public default int getInt(String, int);
+    method @Deprecated public default long getLong(String, long);
+    method @Deprecated @Nullable public default String getString(String, @Nullable String);
+    method @Deprecated @Nullable public default java.util.Set<java.lang.String> getStringSet(String, @Nullable java.util.Set<java.lang.String>);
+    method @Deprecated public default void putBoolean(String, boolean);
+    method @Deprecated public default void putFloat(String, float);
+    method @Deprecated public default void putInt(String, int);
+    method @Deprecated public default void putLong(String, long);
+    method @Deprecated public default void putString(String, @Nullable String);
+    method @Deprecated public default void putStringSet(String, @Nullable java.util.Set<java.lang.String>);
   }
 
-  public abstract deprecated class PreferenceFragment extends android.app.Fragment {
-    ctor public PreferenceFragment();
-    method public void addPreferencesFromIntent(android.content.Intent);
-    method public void addPreferencesFromResource(int);
-    method public android.preference.Preference findPreference(java.lang.CharSequence);
-    method public android.preference.PreferenceManager getPreferenceManager();
-    method public android.preference.PreferenceScreen getPreferenceScreen();
-    method public boolean onPreferenceTreeClick(android.preference.PreferenceScreen, android.preference.Preference);
-    method public void setPreferenceScreen(android.preference.PreferenceScreen);
+  @Deprecated public abstract class PreferenceFragment extends android.app.Fragment {
+    ctor @Deprecated public PreferenceFragment();
+    method @Deprecated public void addPreferencesFromIntent(android.content.Intent);
+    method @Deprecated public void addPreferencesFromResource(@XmlRes int);
+    method @Deprecated public android.preference.Preference findPreference(CharSequence);
+    method @Deprecated public android.preference.PreferenceManager getPreferenceManager();
+    method @Deprecated public android.preference.PreferenceScreen getPreferenceScreen();
+    method @Deprecated public boolean onPreferenceTreeClick(android.preference.PreferenceScreen, android.preference.Preference);
+    method @Deprecated public void setPreferenceScreen(android.preference.PreferenceScreen);
   }
 
-  public static abstract deprecated interface PreferenceFragment.OnPreferenceStartFragmentCallback {
-    method public abstract boolean onPreferenceStartFragment(android.preference.PreferenceFragment, android.preference.Preference);
+  @Deprecated public static interface PreferenceFragment.OnPreferenceStartFragmentCallback {
+    method @Deprecated public boolean onPreferenceStartFragment(android.preference.PreferenceFragment, android.preference.Preference);
   }
 
-  public abstract deprecated class PreferenceGroup extends android.preference.Preference {
-    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet, int);
-    ctor public PreferenceGroup(android.content.Context, android.util.AttributeSet);
-    method public void addItemFromInflater(android.preference.Preference);
-    method public boolean addPreference(android.preference.Preference);
-    method protected void dispatchRestoreInstanceState(android.os.Bundle);
-    method protected void dispatchSaveInstanceState(android.os.Bundle);
-    method public android.preference.Preference findPreference(java.lang.CharSequence);
-    method public android.preference.Preference getPreference(int);
-    method public int getPreferenceCount();
-    method protected boolean isOnSameScreenAsChildren();
-    method public boolean isOrderingAsAdded();
-    method protected boolean onPrepareAddPreference(android.preference.Preference);
-    method public void removeAll();
-    method public boolean removePreference(android.preference.Preference);
-    method public void setOrderingAsAdded(boolean);
+  @Deprecated public abstract class PreferenceGroup extends android.preference.Preference {
+    ctor @Deprecated public PreferenceGroup(android.content.Context, android.util.AttributeSet, int, int);
+    ctor @Deprecated public PreferenceGroup(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public PreferenceGroup(android.content.Context, android.util.AttributeSet);
+    method @Deprecated public void addItemFromInflater(android.preference.Preference);
+    method @Deprecated public boolean addPreference(android.preference.Preference);
+    method @Deprecated protected void dispatchRestoreInstanceState(android.os.Bundle);
+    method @Deprecated protected void dispatchSaveInstanceState(android.os.Bundle);
+    method @Deprecated public android.preference.Preference findPreference(CharSequence);
+    method @Deprecated public android.preference.Preference getPreference(int);
+    method @Deprecated public int getPreferenceCount();
+    method @Deprecated protected boolean isOnSameScreenAsChildren();
+    method @Deprecated public boolean isOrderingAsAdded();
+    method @Deprecated protected boolean onPrepareAddPreference(android.preference.Preference);
+    method @Deprecated public void removeAll();
+    method @Deprecated public boolean removePreference(android.preference.Preference);
+    method @Deprecated public void setOrderingAsAdded(boolean);
   }
 
-  public deprecated class PreferenceManager {
-    method public android.preference.PreferenceScreen createPreferenceScreen(android.content.Context);
-    method public android.preference.Preference findPreference(java.lang.CharSequence);
-    method public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
-    method public static java.lang.String getDefaultSharedPreferencesName(android.content.Context);
-    method public android.preference.PreferenceDataStore getPreferenceDataStore();
-    method public android.content.SharedPreferences getSharedPreferences();
-    method public int getSharedPreferencesMode();
-    method public java.lang.String getSharedPreferencesName();
-    method public boolean isStorageDefault();
-    method public boolean isStorageDeviceProtected();
-    method public static void setDefaultValues(android.content.Context, int, boolean);
-    method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
-    method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
-    method public void setSharedPreferencesMode(int);
-    method public void setSharedPreferencesName(java.lang.String);
-    method public void setStorageDefault();
-    method public void setStorageDeviceProtected();
-    field public static final java.lang.String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
-    field public static final java.lang.String METADATA_KEY_PREFERENCES = "android.preference";
+  @Deprecated public class PreferenceManager {
+    method @Deprecated public android.preference.PreferenceScreen createPreferenceScreen(android.content.Context);
+    method @Deprecated @Nullable public android.preference.Preference findPreference(CharSequence);
+    method @Deprecated public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
+    method @Deprecated public static String getDefaultSharedPreferencesName(android.content.Context);
+    method @Deprecated @Nullable public android.preference.PreferenceDataStore getPreferenceDataStore();
+    method @Deprecated public android.content.SharedPreferences getSharedPreferences();
+    method @Deprecated public int getSharedPreferencesMode();
+    method @Deprecated public String getSharedPreferencesName();
+    method @Deprecated public boolean isStorageDefault();
+    method @Deprecated public boolean isStorageDeviceProtected();
+    method @Deprecated public static void setDefaultValues(android.content.Context, @XmlRes int, boolean);
+    method @Deprecated public static void setDefaultValues(android.content.Context, String, int, int, boolean);
+    method @Deprecated public void setPreferenceDataStore(android.preference.PreferenceDataStore);
+    method @Deprecated public void setSharedPreferencesMode(int);
+    method @Deprecated public void setSharedPreferencesName(String);
+    method @Deprecated public void setStorageDefault();
+    method @Deprecated public void setStorageDeviceProtected();
+    field @Deprecated public static final String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
+    field @Deprecated public static final String METADATA_KEY_PREFERENCES = "android.preference";
   }
 
-  public static abstract deprecated interface PreferenceManager.OnActivityDestroyListener {
-    method public abstract void onActivityDestroy();
+  @Deprecated public static interface PreferenceManager.OnActivityDestroyListener {
+    method @Deprecated public void onActivityDestroy();
   }
 
-  public static abstract deprecated interface PreferenceManager.OnActivityResultListener {
-    method public abstract boolean onActivityResult(int, int, android.content.Intent);
+  @Deprecated public static interface PreferenceManager.OnActivityResultListener {
+    method @Deprecated public boolean onActivityResult(int, int, android.content.Intent);
   }
 
-  public static abstract deprecated interface PreferenceManager.OnActivityStopListener {
-    method public abstract void onActivityStop();
+  @Deprecated public static interface PreferenceManager.OnActivityStopListener {
+    method @Deprecated public void onActivityStop();
   }
 
-  public final deprecated class PreferenceScreen extends android.preference.PreferenceGroup implements android.widget.AdapterView.OnItemClickListener android.content.DialogInterface.OnDismissListener {
-    method public void bind(android.widget.ListView);
-    method public android.app.Dialog getDialog();
-    method public android.widget.ListAdapter getRootAdapter();
-    method protected android.widget.ListAdapter onCreateRootAdapter();
-    method public void onDismiss(android.content.DialogInterface);
-    method public void onItemClick(android.widget.AdapterView, android.view.View, int, long);
+  @Deprecated public final class PreferenceScreen extends android.preference.PreferenceGroup implements android.widget.AdapterView.OnItemClickListener android.content.DialogInterface.OnDismissListener {
+    method @Deprecated public void bind(android.widget.ListView);
+    method @Deprecated public android.app.Dialog getDialog();
+    method @Deprecated public android.widget.ListAdapter getRootAdapter();
+    method @Deprecated protected android.widget.ListAdapter onCreateRootAdapter();
+    method @Deprecated public void onDismiss(android.content.DialogInterface);
+    method @Deprecated public void onItemClick(android.widget.AdapterView, android.view.View, int, long);
   }
 
-  public deprecated class RingtonePreference extends android.preference.Preference implements android.preference.PreferenceManager.OnActivityResultListener {
-    ctor public RingtonePreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public RingtonePreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public RingtonePreference(android.content.Context, android.util.AttributeSet);
-    ctor public RingtonePreference(android.content.Context);
-    method public int getRingtoneType();
-    method public boolean getShowDefault();
-    method public boolean getShowSilent();
-    method public boolean onActivityResult(int, int, android.content.Intent);
-    method protected void onPrepareRingtonePickerIntent(android.content.Intent);
-    method protected android.net.Uri onRestoreRingtone();
-    method protected void onSaveRingtone(android.net.Uri);
-    method public void setRingtoneType(int);
-    method public void setShowDefault(boolean);
-    method public void setShowSilent(boolean);
+  @Deprecated public class RingtonePreference extends android.preference.Preference implements android.preference.PreferenceManager.OnActivityResultListener {
+    ctor @Deprecated public RingtonePreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor @Deprecated public RingtonePreference(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public RingtonePreference(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public RingtonePreference(android.content.Context);
+    method @Deprecated public int getRingtoneType();
+    method @Deprecated public boolean getShowDefault();
+    method @Deprecated public boolean getShowSilent();
+    method @Deprecated public boolean onActivityResult(int, int, android.content.Intent);
+    method @Deprecated protected void onPrepareRingtonePickerIntent(android.content.Intent);
+    method @Deprecated protected android.net.Uri onRestoreRingtone();
+    method @Deprecated protected void onSaveRingtone(android.net.Uri);
+    method @Deprecated public void setRingtoneType(int);
+    method @Deprecated public void setShowDefault(boolean);
+    method @Deprecated public void setShowSilent(boolean);
   }
 
-  public deprecated class SwitchPreference extends android.preference.TwoStatePreference {
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet);
-    ctor public SwitchPreference(android.content.Context);
-    method public java.lang.CharSequence getSwitchTextOff();
-    method public java.lang.CharSequence getSwitchTextOn();
-    method public void setSwitchTextOff(java.lang.CharSequence);
-    method public void setSwitchTextOff(int);
-    method public void setSwitchTextOn(java.lang.CharSequence);
-    method public void setSwitchTextOn(int);
+  @Deprecated public class SwitchPreference extends android.preference.TwoStatePreference {
+    ctor @Deprecated public SwitchPreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor @Deprecated public SwitchPreference(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public SwitchPreference(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public SwitchPreference(android.content.Context);
+    method @Deprecated public CharSequence getSwitchTextOff();
+    method @Deprecated public CharSequence getSwitchTextOn();
+    method @Deprecated public void setSwitchTextOff(CharSequence);
+    method @Deprecated public void setSwitchTextOff(@StringRes int);
+    method @Deprecated public void setSwitchTextOn(CharSequence);
+    method @Deprecated public void setSwitchTextOn(@StringRes int);
   }
 
-  public abstract deprecated class TwoStatePreference extends android.preference.Preference {
-    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public TwoStatePreference(android.content.Context, android.util.AttributeSet);
-    ctor public TwoStatePreference(android.content.Context);
-    method public boolean getDisableDependentsState();
-    method public java.lang.CharSequence getSummaryOff();
-    method public java.lang.CharSequence getSummaryOn();
-    method public boolean isChecked();
-    method public void setChecked(boolean);
-    method public void setDisableDependentsState(boolean);
-    method public void setSummaryOff(java.lang.CharSequence);
-    method public void setSummaryOff(int);
-    method public void setSummaryOn(java.lang.CharSequence);
-    method public void setSummaryOn(int);
+  @Deprecated public abstract class TwoStatePreference extends android.preference.Preference {
+    ctor @Deprecated public TwoStatePreference(android.content.Context, android.util.AttributeSet, int, int);
+    ctor @Deprecated public TwoStatePreference(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public TwoStatePreference(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public TwoStatePreference(android.content.Context);
+    method @Deprecated public boolean getDisableDependentsState();
+    method @Deprecated public CharSequence getSummaryOff();
+    method @Deprecated public CharSequence getSummaryOn();
+    method @Deprecated public boolean isChecked();
+    method @Deprecated public void setChecked(boolean);
+    method @Deprecated public void setDisableDependentsState(boolean);
+    method @Deprecated public void setSummaryOff(CharSequence);
+    method @Deprecated public void setSummaryOff(@StringRes int);
+    method @Deprecated public void setSummaryOn(CharSequence);
+    method @Deprecated public void setSummaryOn(@StringRes int);
   }
 
 }
@@ -35664,10 +35998,10 @@
 package android.print {
 
   public final class PageRange implements android.os.Parcelable {
-    ctor public PageRange(int, int);
+    ctor public PageRange(@IntRange(from=0) int, @IntRange(from=0) int);
     method public int describeContents();
-    method public int getEnd();
-    method public int getStart();
+    method @IntRange(from=0) public int getEnd();
+    method @IntRange(from=0) public int getStart();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.print.PageRange ALL_PAGES;
     field public static final android.os.Parcelable.Creator<android.print.PageRange> CREATOR;
@@ -35675,11 +36009,11 @@
 
   public final class PrintAttributes implements android.os.Parcelable {
     method public int describeContents();
-    method public int getColorMode();
-    method public int getDuplexMode();
-    method public android.print.PrintAttributes.MediaSize getMediaSize();
-    method public android.print.PrintAttributes.Margins getMinMargins();
-    method public android.print.PrintAttributes.Resolution getResolution();
+    method @IntRange(from=0) public int getColorMode();
+    method @IntRange(from=0) public int getDuplexMode();
+    method @Nullable public android.print.PrintAttributes.MediaSize getMediaSize();
+    method @Nullable public android.print.PrintAttributes.Margins getMinMargins();
+    method @Nullable public android.print.PrintAttributes.Resolution getResolution();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int COLOR_MODE_COLOR = 2; // 0x2
     field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1
@@ -35691,12 +36025,12 @@
 
   public static final class PrintAttributes.Builder {
     ctor public PrintAttributes.Builder();
-    method public android.print.PrintAttributes build();
-    method public android.print.PrintAttributes.Builder setColorMode(int);
-    method public android.print.PrintAttributes.Builder setDuplexMode(int);
-    method public android.print.PrintAttributes.Builder setMediaSize(android.print.PrintAttributes.MediaSize);
-    method public android.print.PrintAttributes.Builder setMinMargins(android.print.PrintAttributes.Margins);
-    method public android.print.PrintAttributes.Builder setResolution(android.print.PrintAttributes.Resolution);
+    method @NonNull public android.print.PrintAttributes build();
+    method @NonNull public android.print.PrintAttributes.Builder setColorMode(int);
+    method @NonNull public android.print.PrintAttributes.Builder setDuplexMode(int);
+    method @NonNull public android.print.PrintAttributes.Builder setMediaSize(@NonNull android.print.PrintAttributes.MediaSize);
+    method @NonNull public android.print.PrintAttributes.Builder setMinMargins(@NonNull android.print.PrintAttributes.Margins);
+    method @NonNull public android.print.PrintAttributes.Builder setResolution(@NonNull android.print.PrintAttributes.Resolution);
   }
 
   public static final class PrintAttributes.Margins {
@@ -35709,13 +36043,13 @@
   }
 
   public static final class PrintAttributes.MediaSize {
-    ctor public PrintAttributes.MediaSize(java.lang.String, java.lang.String, int, int);
-    method public android.print.PrintAttributes.MediaSize asLandscape();
-    method public android.print.PrintAttributes.MediaSize asPortrait();
-    method public int getHeightMils();
-    method public java.lang.String getId();
-    method public java.lang.String getLabel(android.content.pm.PackageManager);
-    method public int getWidthMils();
+    ctor public PrintAttributes.MediaSize(@NonNull String, @NonNull String, @IntRange(from=1) int, @IntRange(from=1) int);
+    method @NonNull public android.print.PrintAttributes.MediaSize asLandscape();
+    method @NonNull public android.print.PrintAttributes.MediaSize asPortrait();
+    method @IntRange(from=1) public int getHeightMils();
+    method @NonNull public String getId();
+    method @NonNull public String getLabel(@NonNull android.content.pm.PackageManager);
+    method @IntRange(from=1) public int getWidthMils();
     method public boolean isPortrait();
     field public static final android.print.PrintAttributes.MediaSize ISO_A0;
     field public static final android.print.PrintAttributes.MediaSize ISO_A1;
@@ -35803,11 +36137,11 @@
   }
 
   public static final class PrintAttributes.Resolution {
-    ctor public PrintAttributes.Resolution(java.lang.String, java.lang.String, int, int);
-    method public int getHorizontalDpi();
-    method public java.lang.String getId();
-    method public java.lang.String getLabel();
-    method public int getVerticalDpi();
+    ctor public PrintAttributes.Resolution(@NonNull String, @NonNull String, @IntRange(from=1) int, @IntRange(from=1) int);
+    method @IntRange(from=1) public int getHorizontalDpi();
+    method @NonNull public String getId();
+    method @NonNull public String getLabel();
+    method @IntRange(from=1) public int getVerticalDpi();
   }
 
   public abstract class PrintDocumentAdapter {
@@ -35816,27 +36150,27 @@
     method public abstract void onLayout(android.print.PrintAttributes, android.print.PrintAttributes, android.os.CancellationSignal, android.print.PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle);
     method public void onStart();
     method public abstract void onWrite(android.print.PageRange[], android.os.ParcelFileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback);
-    field public static final java.lang.String EXTRA_PRINT_PREVIEW = "EXTRA_PRINT_PREVIEW";
+    field public static final String EXTRA_PRINT_PREVIEW = "EXTRA_PRINT_PREVIEW";
   }
 
-  public static abstract class PrintDocumentAdapter.LayoutResultCallback {
+  public abstract static class PrintDocumentAdapter.LayoutResultCallback {
     method public void onLayoutCancelled();
-    method public void onLayoutFailed(java.lang.CharSequence);
+    method public void onLayoutFailed(CharSequence);
     method public void onLayoutFinished(android.print.PrintDocumentInfo, boolean);
   }
 
-  public static abstract class PrintDocumentAdapter.WriteResultCallback {
+  public abstract static class PrintDocumentAdapter.WriteResultCallback {
     method public void onWriteCancelled();
-    method public void onWriteFailed(java.lang.CharSequence);
+    method public void onWriteFailed(CharSequence);
     method public void onWriteFinished(android.print.PageRange[]);
   }
 
   public final class PrintDocumentInfo implements android.os.Parcelable {
     method public int describeContents();
     method public int getContentType();
-    method public long getDataSize();
-    method public java.lang.String getName();
-    method public int getPageCount();
+    method @IntRange(from=0) public long getDataSize();
+    method @NonNull public String getName();
+    method @IntRange(from=0xffffffff) public int getPageCount();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONTENT_TYPE_DOCUMENT = 0; // 0x0
     field public static final int CONTENT_TYPE_PHOTO = 1; // 0x1
@@ -35846,16 +36180,16 @@
   }
 
   public static final class PrintDocumentInfo.Builder {
-    ctor public PrintDocumentInfo.Builder(java.lang.String);
-    method public android.print.PrintDocumentInfo build();
-    method public android.print.PrintDocumentInfo.Builder setContentType(int);
-    method public android.print.PrintDocumentInfo.Builder setPageCount(int);
+    ctor public PrintDocumentInfo.Builder(@NonNull String);
+    method @NonNull public android.print.PrintDocumentInfo build();
+    method @NonNull public android.print.PrintDocumentInfo.Builder setContentType(int);
+    method @NonNull public android.print.PrintDocumentInfo.Builder setPageCount(@IntRange(from=0xffffffff) int);
   }
 
   public final class PrintJob {
     method public void cancel();
-    method public android.print.PrintJobId getId();
-    method public android.print.PrintJobInfo getInfo();
+    method @Nullable public android.print.PrintJobId getId();
+    method @NonNull public android.print.PrintJobInfo getInfo();
     method public boolean isBlocked();
     method public boolean isCancelled();
     method public boolean isCompleted();
@@ -35873,17 +36207,17 @@
 
   public final class PrintJobInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public int getAdvancedIntOption(java.lang.String);
-    method public java.lang.String getAdvancedStringOption(java.lang.String);
-    method public android.print.PrintAttributes getAttributes();
-    method public int getCopies();
+    method public int getAdvancedIntOption(String);
+    method public String getAdvancedStringOption(String);
+    method @NonNull public android.print.PrintAttributes getAttributes();
+    method @IntRange(from=0) public int getCopies();
     method public long getCreationTime();
-    method public android.print.PrintJobId getId();
-    method public java.lang.String getLabel();
-    method public android.print.PageRange[] getPages();
-    method public android.print.PrinterId getPrinterId();
+    method @Nullable public android.print.PrintJobId getId();
+    method @NonNull public String getLabel();
+    method @Nullable public android.print.PageRange[] getPages();
+    method @Nullable public android.print.PrinterId getPrinterId();
     method public int getState();
-    method public boolean hasAdvancedOption(java.lang.String);
+    method public boolean hasAdvancedOption(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.print.PrintJobInfo> CREATOR;
     field public static final int STATE_BLOCKED = 4; // 0x4
@@ -35896,55 +36230,55 @@
   }
 
   public static final class PrintJobInfo.Builder {
-    ctor public PrintJobInfo.Builder(android.print.PrintJobInfo);
-    method public android.print.PrintJobInfo build();
-    method public void putAdvancedOption(java.lang.String, java.lang.String);
-    method public void putAdvancedOption(java.lang.String, int);
-    method public void setAttributes(android.print.PrintAttributes);
-    method public void setCopies(int);
-    method public void setPages(android.print.PageRange[]);
+    ctor public PrintJobInfo.Builder(@Nullable android.print.PrintJobInfo);
+    method @NonNull public android.print.PrintJobInfo build();
+    method public void putAdvancedOption(@NonNull String, @Nullable String);
+    method public void putAdvancedOption(@NonNull String, int);
+    method public void setAttributes(@NonNull android.print.PrintAttributes);
+    method public void setCopies(@IntRange(from=1) int);
+    method public void setPages(@NonNull android.print.PageRange[]);
   }
 
   public final class PrintManager {
-    method public java.util.List<android.print.PrintJob> getPrintJobs();
-    method public android.print.PrintJob print(java.lang.String, android.print.PrintDocumentAdapter, android.print.PrintAttributes);
+    method @NonNull public java.util.List<android.print.PrintJob> getPrintJobs();
+    method @NonNull public android.print.PrintJob print(@NonNull String, @NonNull android.print.PrintDocumentAdapter, @Nullable android.print.PrintAttributes);
   }
 
   public final class PrinterCapabilitiesInfo implements android.os.Parcelable {
     method public int describeContents();
     method public int getColorModes();
-    method public android.print.PrintAttributes getDefaults();
+    method @NonNull public android.print.PrintAttributes getDefaults();
     method public int getDuplexModes();
-    method public java.util.List<android.print.PrintAttributes.MediaSize> getMediaSizes();
-    method public android.print.PrintAttributes.Margins getMinMargins();
-    method public java.util.List<android.print.PrintAttributes.Resolution> getResolutions();
+    method @NonNull public java.util.List<android.print.PrintAttributes.MediaSize> getMediaSizes();
+    method @NonNull public android.print.PrintAttributes.Margins getMinMargins();
+    method @NonNull public java.util.List<android.print.PrintAttributes.Resolution> getResolutions();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.print.PrinterCapabilitiesInfo> CREATOR;
   }
 
   public static final class PrinterCapabilitiesInfo.Builder {
-    ctor public PrinterCapabilitiesInfo.Builder(android.print.PrinterId);
-    method public android.print.PrinterCapabilitiesInfo.Builder addMediaSize(android.print.PrintAttributes.MediaSize, boolean);
-    method public android.print.PrinterCapabilitiesInfo.Builder addResolution(android.print.PrintAttributes.Resolution, boolean);
-    method public android.print.PrinterCapabilitiesInfo build();
-    method public android.print.PrinterCapabilitiesInfo.Builder setColorModes(int, int);
-    method public android.print.PrinterCapabilitiesInfo.Builder setDuplexModes(int, int);
-    method public android.print.PrinterCapabilitiesInfo.Builder setMinMargins(android.print.PrintAttributes.Margins);
+    ctor public PrinterCapabilitiesInfo.Builder(@NonNull android.print.PrinterId);
+    method @NonNull public android.print.PrinterCapabilitiesInfo.Builder addMediaSize(@NonNull android.print.PrintAttributes.MediaSize, boolean);
+    method @NonNull public android.print.PrinterCapabilitiesInfo.Builder addResolution(@NonNull android.print.PrintAttributes.Resolution, boolean);
+    method @NonNull public android.print.PrinterCapabilitiesInfo build();
+    method @NonNull public android.print.PrinterCapabilitiesInfo.Builder setColorModes(int, int);
+    method @NonNull public android.print.PrinterCapabilitiesInfo.Builder setDuplexModes(int, int);
+    method @NonNull public android.print.PrinterCapabilitiesInfo.Builder setMinMargins(@NonNull android.print.PrintAttributes.Margins);
   }
 
   public final class PrinterId implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getLocalId();
+    method @NonNull public String getLocalId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.print.PrinterId> CREATOR;
   }
 
   public final class PrinterInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public android.print.PrinterCapabilitiesInfo getCapabilities();
-    method public java.lang.String getDescription();
-    method public android.print.PrinterId getId();
-    method public java.lang.String getName();
+    method @Nullable public android.print.PrinterCapabilitiesInfo getCapabilities();
+    method @Nullable public String getDescription();
+    method @NonNull public android.print.PrinterId getId();
+    method @NonNull public String getName();
     method public int getStatus();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.print.PrinterInfo> CREATOR;
@@ -35954,16 +36288,16 @@
   }
 
   public static final class PrinterInfo.Builder {
-    ctor public PrinterInfo.Builder(android.print.PrinterId, java.lang.String, int);
-    ctor public PrinterInfo.Builder(android.print.PrinterInfo);
-    method public android.print.PrinterInfo build();
-    method public android.print.PrinterInfo.Builder setCapabilities(android.print.PrinterCapabilitiesInfo);
-    method public android.print.PrinterInfo.Builder setDescription(java.lang.String);
-    method public android.print.PrinterInfo.Builder setHasCustomPrinterIcon(boolean);
-    method public android.print.PrinterInfo.Builder setIconResourceId(int);
-    method public android.print.PrinterInfo.Builder setInfoIntent(android.app.PendingIntent);
-    method public android.print.PrinterInfo.Builder setName(java.lang.String);
-    method public android.print.PrinterInfo.Builder setStatus(int);
+    ctor public PrinterInfo.Builder(@NonNull android.print.PrinterId, @NonNull String, int);
+    ctor public PrinterInfo.Builder(@NonNull android.print.PrinterInfo);
+    method @NonNull public android.print.PrinterInfo build();
+    method @NonNull public android.print.PrinterInfo.Builder setCapabilities(@NonNull android.print.PrinterCapabilitiesInfo);
+    method @NonNull public android.print.PrinterInfo.Builder setDescription(@NonNull String);
+    method @NonNull public android.print.PrinterInfo.Builder setHasCustomPrinterIcon(boolean);
+    method @NonNull public android.print.PrinterInfo.Builder setIconResourceId(@DrawableRes int);
+    method @NonNull public android.print.PrinterInfo.Builder setInfoIntent(@NonNull android.app.PendingIntent);
+    method @NonNull public android.print.PrinterInfo.Builder setName(@NonNull String);
+    method @NonNull public android.print.PrinterInfo.Builder setStatus(int);
   }
 
 }
@@ -35971,11 +36305,11 @@
 package android.print.pdf {
 
   public class PrintedPdfDocument extends android.graphics.pdf.PdfDocument {
-    ctor public PrintedPdfDocument(android.content.Context, android.print.PrintAttributes);
-    method public android.graphics.Rect getPageContentRect();
-    method public int getPageHeight();
-    method public int getPageWidth();
-    method public android.graphics.pdf.PdfDocument.Page startPage(int);
+    ctor public PrintedPdfDocument(@NonNull android.content.Context, @NonNull android.print.PrintAttributes);
+    method @NonNull public android.graphics.Rect getPageContentRect();
+    method @IntRange(from=0) public int getPageHeight();
+    method @IntRange(from=0) public int getPageWidth();
+    method @NonNull public android.graphics.pdf.PdfDocument.Page startPage(@IntRange(from=0) int);
   }
 
 }
@@ -35983,74 +36317,74 @@
 package android.printservice {
 
   public final class CustomPrinterIconCallback {
-    method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
+    method public boolean onCustomPrinterIconLoaded(@Nullable android.graphics.drawable.Icon);
   }
 
   public final class PrintDocument {
-    method public android.os.ParcelFileDescriptor getData();
-    method public android.print.PrintDocumentInfo getInfo();
+    method @Nullable public android.os.ParcelFileDescriptor getData();
+    method @NonNull public android.print.PrintDocumentInfo getInfo();
   }
 
   public final class PrintJob {
-    method public boolean block(java.lang.String);
-    method public boolean cancel();
-    method public boolean complete();
-    method public boolean fail(java.lang.String);
-    method public int getAdvancedIntOption(java.lang.String);
-    method public java.lang.String getAdvancedStringOption(java.lang.String);
-    method public android.printservice.PrintDocument getDocument();
-    method public android.print.PrintJobId getId();
-    method public android.print.PrintJobInfo getInfo();
-    method public java.lang.String getTag();
-    method public boolean hasAdvancedOption(java.lang.String);
-    method public boolean isBlocked();
-    method public boolean isCancelled();
-    method public boolean isCompleted();
-    method public boolean isFailed();
-    method public boolean isQueued();
-    method public boolean isStarted();
-    method public void setProgress(float);
-    method public void setStatus(java.lang.CharSequence);
-    method public void setStatus(int);
-    method public boolean setTag(java.lang.String);
-    method public boolean start();
+    method @MainThread public boolean block(@Nullable String);
+    method @MainThread public boolean cancel();
+    method @MainThread public boolean complete();
+    method @MainThread public boolean fail(@Nullable String);
+    method @MainThread public int getAdvancedIntOption(String);
+    method @MainThread public String getAdvancedStringOption(String);
+    method @MainThread @NonNull public android.printservice.PrintDocument getDocument();
+    method @MainThread public android.print.PrintJobId getId();
+    method @MainThread @NonNull public android.print.PrintJobInfo getInfo();
+    method @MainThread @Nullable public String getTag();
+    method @MainThread public boolean hasAdvancedOption(String);
+    method @MainThread public boolean isBlocked();
+    method @MainThread public boolean isCancelled();
+    method @MainThread public boolean isCompleted();
+    method @MainThread public boolean isFailed();
+    method @MainThread public boolean isQueued();
+    method @MainThread public boolean isStarted();
+    method @MainThread public void setProgress(@FloatRange(from=0.0, to=1.0) float);
+    method @MainThread public void setStatus(@Nullable CharSequence);
+    method @MainThread public void setStatus(@StringRes int);
+    method @MainThread public boolean setTag(@NonNull String);
+    method @MainThread public boolean start();
   }
 
   public abstract class PrintService extends android.app.Service {
     ctor public PrintService();
     method protected final void attachBaseContext(android.content.Context);
-    method public final android.print.PrinterId generatePrinterId(java.lang.String);
+    method @NonNull public final android.print.PrinterId generatePrinterId(String);
     method public final java.util.List<android.printservice.PrintJob> getActivePrintJobs();
     method public final android.os.IBinder onBind(android.content.Intent);
     method protected void onConnected();
-    method protected abstract android.printservice.PrinterDiscoverySession onCreatePrinterDiscoverySession();
+    method @Nullable protected abstract android.printservice.PrinterDiscoverySession onCreatePrinterDiscoverySession();
     method protected void onDisconnected();
     method protected abstract void onPrintJobQueued(android.printservice.PrintJob);
     method protected abstract void onRequestCancelPrintJob(android.printservice.PrintJob);
-    field public static final java.lang.String EXTRA_CAN_SELECT_PRINTER = "android.printservice.extra.CAN_SELECT_PRINTER";
-    field public static final java.lang.String EXTRA_PRINTER_INFO = "android.intent.extra.print.EXTRA_PRINTER_INFO";
-    field public static final java.lang.String EXTRA_PRINT_DOCUMENT_INFO = "android.printservice.extra.PRINT_DOCUMENT_INFO";
-    field public static final java.lang.String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
-    field public static final java.lang.String EXTRA_SELECT_PRINTER = "android.printservice.extra.SELECT_PRINTER";
-    field public static final java.lang.String SERVICE_INTERFACE = "android.printservice.PrintService";
-    field public static final java.lang.String SERVICE_META_DATA = "android.printservice";
+    field public static final String EXTRA_CAN_SELECT_PRINTER = "android.printservice.extra.CAN_SELECT_PRINTER";
+    field public static final String EXTRA_PRINTER_INFO = "android.intent.extra.print.EXTRA_PRINTER_INFO";
+    field public static final String EXTRA_PRINT_DOCUMENT_INFO = "android.printservice.extra.PRINT_DOCUMENT_INFO";
+    field public static final String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
+    field public static final String EXTRA_SELECT_PRINTER = "android.printservice.extra.SELECT_PRINTER";
+    field public static final String SERVICE_INTERFACE = "android.printservice.PrintService";
+    field public static final String SERVICE_META_DATA = "android.printservice";
   }
 
   public abstract class PrinterDiscoverySession {
     ctor public PrinterDiscoverySession();
-    method public final void addPrinters(java.util.List<android.print.PrinterInfo>);
-    method public final java.util.List<android.print.PrinterInfo> getPrinters();
-    method public final java.util.List<android.print.PrinterId> getTrackedPrinters();
+    method public final void addPrinters(@NonNull java.util.List<android.print.PrinterInfo>);
+    method @NonNull public final java.util.List<android.print.PrinterInfo> getPrinters();
+    method @NonNull public final java.util.List<android.print.PrinterId> getTrackedPrinters();
     method public final boolean isDestroyed();
     method public final boolean isPrinterDiscoveryStarted();
     method public abstract void onDestroy();
-    method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.os.CancellationSignal, android.printservice.CustomPrinterIconCallback);
-    method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
-    method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
+    method public void onRequestCustomPrinterIcon(@NonNull android.print.PrinterId, @NonNull android.os.CancellationSignal, @NonNull android.printservice.CustomPrinterIconCallback);
+    method public abstract void onStartPrinterDiscovery(@NonNull java.util.List<android.print.PrinterId>);
+    method public abstract void onStartPrinterStateTracking(@NonNull android.print.PrinterId);
     method public abstract void onStopPrinterDiscovery();
-    method public abstract void onStopPrinterStateTracking(android.print.PrinterId);
-    method public abstract void onValidatePrinters(java.util.List<android.print.PrinterId>);
-    method public final void removePrinters(java.util.List<android.print.PrinterId>);
+    method public abstract void onStopPrinterStateTracking(@NonNull android.print.PrinterId);
+    method public abstract void onValidatePrinters(@NonNull java.util.List<android.print.PrinterId>);
+    method public final void removePrinters(@NonNull java.util.List<android.print.PrinterId>);
   }
 
 }
@@ -36059,97 +36393,97 @@
 
   public final class AlarmClock {
     ctor public AlarmClock();
-    field public static final java.lang.String ACTION_DISMISS_ALARM = "android.intent.action.DISMISS_ALARM";
-    field public static final java.lang.String ACTION_DISMISS_TIMER = "android.intent.action.DISMISS_TIMER";
-    field public static final java.lang.String ACTION_SET_ALARM = "android.intent.action.SET_ALARM";
-    field public static final java.lang.String ACTION_SET_TIMER = "android.intent.action.SET_TIMER";
-    field public static final java.lang.String ACTION_SHOW_ALARMS = "android.intent.action.SHOW_ALARMS";
-    field public static final java.lang.String ACTION_SHOW_TIMERS = "android.intent.action.SHOW_TIMERS";
-    field public static final java.lang.String ACTION_SNOOZE_ALARM = "android.intent.action.SNOOZE_ALARM";
-    field public static final java.lang.String ALARM_SEARCH_MODE_ALL = "android.all";
-    field public static final java.lang.String ALARM_SEARCH_MODE_LABEL = "android.label";
-    field public static final java.lang.String ALARM_SEARCH_MODE_NEXT = "android.next";
-    field public static final java.lang.String ALARM_SEARCH_MODE_TIME = "android.time";
-    field public static final java.lang.String EXTRA_ALARM_SEARCH_MODE = "android.intent.extra.alarm.SEARCH_MODE";
-    field public static final java.lang.String EXTRA_ALARM_SNOOZE_DURATION = "android.intent.extra.alarm.SNOOZE_DURATION";
-    field public static final java.lang.String EXTRA_DAYS = "android.intent.extra.alarm.DAYS";
-    field public static final java.lang.String EXTRA_HOUR = "android.intent.extra.alarm.HOUR";
-    field public static final java.lang.String EXTRA_IS_PM = "android.intent.extra.alarm.IS_PM";
-    field public static final java.lang.String EXTRA_LENGTH = "android.intent.extra.alarm.LENGTH";
-    field public static final java.lang.String EXTRA_MESSAGE = "android.intent.extra.alarm.MESSAGE";
-    field public static final java.lang.String EXTRA_MINUTES = "android.intent.extra.alarm.MINUTES";
-    field public static final java.lang.String EXTRA_RINGTONE = "android.intent.extra.alarm.RINGTONE";
-    field public static final java.lang.String EXTRA_SKIP_UI = "android.intent.extra.alarm.SKIP_UI";
-    field public static final java.lang.String EXTRA_VIBRATE = "android.intent.extra.alarm.VIBRATE";
-    field public static final java.lang.String VALUE_RINGTONE_SILENT = "silent";
+    field public static final String ACTION_DISMISS_ALARM = "android.intent.action.DISMISS_ALARM";
+    field public static final String ACTION_DISMISS_TIMER = "android.intent.action.DISMISS_TIMER";
+    field public static final String ACTION_SET_ALARM = "android.intent.action.SET_ALARM";
+    field public static final String ACTION_SET_TIMER = "android.intent.action.SET_TIMER";
+    field public static final String ACTION_SHOW_ALARMS = "android.intent.action.SHOW_ALARMS";
+    field public static final String ACTION_SHOW_TIMERS = "android.intent.action.SHOW_TIMERS";
+    field public static final String ACTION_SNOOZE_ALARM = "android.intent.action.SNOOZE_ALARM";
+    field public static final String ALARM_SEARCH_MODE_ALL = "android.all";
+    field public static final String ALARM_SEARCH_MODE_LABEL = "android.label";
+    field public static final String ALARM_SEARCH_MODE_NEXT = "android.next";
+    field public static final String ALARM_SEARCH_MODE_TIME = "android.time";
+    field public static final String EXTRA_ALARM_SEARCH_MODE = "android.intent.extra.alarm.SEARCH_MODE";
+    field public static final String EXTRA_ALARM_SNOOZE_DURATION = "android.intent.extra.alarm.SNOOZE_DURATION";
+    field public static final String EXTRA_DAYS = "android.intent.extra.alarm.DAYS";
+    field public static final String EXTRA_HOUR = "android.intent.extra.alarm.HOUR";
+    field public static final String EXTRA_IS_PM = "android.intent.extra.alarm.IS_PM";
+    field public static final String EXTRA_LENGTH = "android.intent.extra.alarm.LENGTH";
+    field public static final String EXTRA_MESSAGE = "android.intent.extra.alarm.MESSAGE";
+    field public static final String EXTRA_MINUTES = "android.intent.extra.alarm.MINUTES";
+    field public static final String EXTRA_RINGTONE = "android.intent.extra.alarm.RINGTONE";
+    field public static final String EXTRA_SKIP_UI = "android.intent.extra.alarm.SKIP_UI";
+    field public static final String EXTRA_VIBRATE = "android.intent.extra.alarm.VIBRATE";
+    field public static final String VALUE_RINGTONE_SILENT = "silent";
   }
 
-  public abstract interface BaseColumns {
-    field public static final java.lang.String _COUNT = "_count";
-    field public static final java.lang.String _ID = "_id";
+  public interface BaseColumns {
+    field public static final String _COUNT = "_count";
+    field public static final String _ID = "_id";
   }
 
   public class BlockedNumberContract {
     method public static boolean canCurrentUserBlockNumbers(android.content.Context);
-    method public static boolean isBlocked(android.content.Context, java.lang.String);
-    method public static int unblock(android.content.Context, java.lang.String);
-    field public static final java.lang.String AUTHORITY = "com.android.blockednumber";
+    method @WorkerThread public static boolean isBlocked(android.content.Context, String);
+    method @WorkerThread public static int unblock(android.content.Context, String);
+    field public static final String AUTHORITY = "com.android.blockednumber";
     field public static final android.net.Uri AUTHORITY_URI;
   }
 
   public static class BlockedNumberContract.BlockedNumbers {
-    field public static final java.lang.String COLUMN_E164_NUMBER = "e164_number";
-    field public static final java.lang.String COLUMN_ID = "_id";
-    field public static final java.lang.String COLUMN_ORIGINAL_NUMBER = "original_number";
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_number";
+    field public static final String COLUMN_E164_NUMBER = "e164_number";
+    field public static final String COLUMN_ID = "_id";
+    field public static final String COLUMN_ORIGINAL_NUMBER = "original_number";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_number";
     field public static final android.net.Uri CONTENT_URI;
   }
 
   public class Browser {
     ctor public Browser();
-    method public static final void sendString(android.content.Context, java.lang.String);
-    field public static final java.lang.String EXTRA_APPLICATION_ID = "com.android.browser.application_id";
-    field public static final java.lang.String EXTRA_CREATE_NEW_TAB = "create_new_tab";
-    field public static final java.lang.String EXTRA_HEADERS = "com.android.browser.headers";
-    field public static final java.lang.String INITIAL_ZOOM_LEVEL = "browser.initialZoomLevel";
+    method public static final void sendString(android.content.Context, String);
+    field public static final String EXTRA_APPLICATION_ID = "com.android.browser.application_id";
+    field public static final String EXTRA_CREATE_NEW_TAB = "create_new_tab";
+    field public static final String EXTRA_HEADERS = "com.android.browser.headers";
+    field public static final String INITIAL_ZOOM_LEVEL = "browser.initialZoomLevel";
   }
 
   public final class CalendarContract {
-    method public static boolean startViewCalendarEventInManagedProfile(android.content.Context, long, long, long, boolean, int);
-    field public static final java.lang.String ACCOUNT_TYPE_LOCAL = "LOCAL";
-    field public static final java.lang.String ACTION_EVENT_REMINDER = "android.intent.action.EVENT_REMINDER";
-    field public static final java.lang.String ACTION_HANDLE_CUSTOM_EVENT = "android.provider.calendar.action.HANDLE_CUSTOM_EVENT";
-    field public static final java.lang.String ACTION_VIEW_WORK_CALENDAR_EVENT = "android.provider.calendar.action.VIEW_WORK_CALENDAR_EVENT";
-    field public static final java.lang.String AUTHORITY = "com.android.calendar";
-    field public static final java.lang.String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
+    method public static boolean startViewCalendarEventInManagedProfile(@NonNull android.content.Context, long, long, long, boolean, int);
+    field public static final String ACCOUNT_TYPE_LOCAL = "LOCAL";
+    field public static final String ACTION_EVENT_REMINDER = "android.intent.action.EVENT_REMINDER";
+    field public static final String ACTION_HANDLE_CUSTOM_EVENT = "android.provider.calendar.action.HANDLE_CUSTOM_EVENT";
+    field public static final String ACTION_VIEW_WORK_CALENDAR_EVENT = "android.provider.calendar.action.VIEW_WORK_CALENDAR_EVENT";
+    field public static final String AUTHORITY = "com.android.calendar";
+    field public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String EXTRA_CUSTOM_APP_URI = "customAppUri";
-    field public static final java.lang.String EXTRA_EVENT_ALL_DAY = "allDay";
-    field public static final java.lang.String EXTRA_EVENT_BEGIN_TIME = "beginTime";
-    field public static final java.lang.String EXTRA_EVENT_END_TIME = "endTime";
-    field public static final java.lang.String EXTRA_EVENT_ID = "id";
+    field public static final String EXTRA_CUSTOM_APP_URI = "customAppUri";
+    field public static final String EXTRA_EVENT_ALL_DAY = "allDay";
+    field public static final String EXTRA_EVENT_BEGIN_TIME = "beginTime";
+    field public static final String EXTRA_EVENT_END_TIME = "endTime";
+    field public static final String EXTRA_EVENT_ID = "id";
   }
 
   public static final class CalendarContract.Attendees implements android.provider.BaseColumns android.provider.CalendarContract.AttendeesColumns android.provider.CalendarContract.EventsColumns {
-    method public static android.database.Cursor query(android.content.ContentResolver, long, java.lang.String[]);
+    method public static android.database.Cursor query(android.content.ContentResolver, long, String[]);
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  protected static abstract interface CalendarContract.AttendeesColumns {
-    field public static final java.lang.String ATTENDEE_EMAIL = "attendeeEmail";
-    field public static final java.lang.String ATTENDEE_IDENTITY = "attendeeIdentity";
-    field public static final java.lang.String ATTENDEE_ID_NAMESPACE = "attendeeIdNamespace";
-    field public static final java.lang.String ATTENDEE_NAME = "attendeeName";
-    field public static final java.lang.String ATTENDEE_RELATIONSHIP = "attendeeRelationship";
-    field public static final java.lang.String ATTENDEE_STATUS = "attendeeStatus";
+  protected static interface CalendarContract.AttendeesColumns {
+    field public static final String ATTENDEE_EMAIL = "attendeeEmail";
+    field public static final String ATTENDEE_IDENTITY = "attendeeIdentity";
+    field public static final String ATTENDEE_ID_NAMESPACE = "attendeeIdNamespace";
+    field public static final String ATTENDEE_NAME = "attendeeName";
+    field public static final String ATTENDEE_RELATIONSHIP = "attendeeRelationship";
+    field public static final String ATTENDEE_STATUS = "attendeeStatus";
     field public static final int ATTENDEE_STATUS_ACCEPTED = 1; // 0x1
     field public static final int ATTENDEE_STATUS_DECLINED = 2; // 0x2
     field public static final int ATTENDEE_STATUS_INVITED = 3; // 0x3
     field public static final int ATTENDEE_STATUS_NONE = 0; // 0x0
     field public static final int ATTENDEE_STATUS_TENTATIVE = 4; // 0x4
-    field public static final java.lang.String ATTENDEE_TYPE = "attendeeType";
-    field public static final java.lang.String EVENT_ID = "event_id";
+    field public static final String ATTENDEE_TYPE = "attendeeType";
+    field public static final String EVENT_ID = "event_id";
     field public static final int RELATIONSHIP_ATTENDEE = 1; // 0x1
     field public static final int RELATIONSHIP_NONE = 0; // 0x0
     field public static final int RELATIONSHIP_ORGANIZER = 2; // 0x2
@@ -36166,45 +36500,45 @@
     field public static final android.net.Uri CONTENT_URI_BY_INSTANCE;
   }
 
-  protected static abstract interface CalendarContract.CalendarAlertsColumns {
-    field public static final java.lang.String ALARM_TIME = "alarmTime";
-    field public static final java.lang.String BEGIN = "begin";
-    field public static final java.lang.String CREATION_TIME = "creationTime";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "begin ASC,title ASC";
-    field public static final java.lang.String END = "end";
-    field public static final java.lang.String EVENT_ID = "event_id";
-    field public static final java.lang.String MINUTES = "minutes";
-    field public static final java.lang.String NOTIFY_TIME = "notifyTime";
-    field public static final java.lang.String RECEIVED_TIME = "receivedTime";
-    field public static final java.lang.String STATE = "state";
+  protected static interface CalendarContract.CalendarAlertsColumns {
+    field public static final String ALARM_TIME = "alarmTime";
+    field public static final String BEGIN = "begin";
+    field public static final String CREATION_TIME = "creationTime";
+    field public static final String DEFAULT_SORT_ORDER = "begin ASC,title ASC";
+    field public static final String END = "end";
+    field public static final String EVENT_ID = "event_id";
+    field public static final String MINUTES = "minutes";
+    field public static final String NOTIFY_TIME = "notifyTime";
+    field public static final String RECEIVED_TIME = "receivedTime";
+    field public static final String STATE = "state";
     field public static final int STATE_DISMISSED = 2; // 0x2
     field public static final int STATE_FIRED = 1; // 0x1
     field public static final int STATE_SCHEDULED = 0; // 0x0
   }
 
   public static final class CalendarContract.CalendarCache implements android.provider.CalendarContract.CalendarCacheColumns {
-    field public static final java.lang.String KEY_TIMEZONE_INSTANCES = "timezoneInstances";
-    field public static final java.lang.String KEY_TIMEZONE_INSTANCES_PREVIOUS = "timezoneInstancesPrevious";
-    field public static final java.lang.String KEY_TIMEZONE_TYPE = "timezoneType";
-    field public static final java.lang.String TIMEZONE_TYPE_AUTO = "auto";
-    field public static final java.lang.String TIMEZONE_TYPE_HOME = "home";
+    field public static final String KEY_TIMEZONE_INSTANCES = "timezoneInstances";
+    field public static final String KEY_TIMEZONE_INSTANCES_PREVIOUS = "timezoneInstancesPrevious";
+    field public static final String KEY_TIMEZONE_TYPE = "timezoneType";
+    field public static final String TIMEZONE_TYPE_AUTO = "auto";
+    field public static final String TIMEZONE_TYPE_HOME = "home";
     field public static final android.net.Uri URI;
   }
 
-  protected static abstract interface CalendarContract.CalendarCacheColumns {
-    field public static final java.lang.String KEY = "key";
-    field public static final java.lang.String VALUE = "value";
+  protected static interface CalendarContract.CalendarCacheColumns {
+    field public static final String KEY = "key";
+    field public static final String VALUE = "value";
   }
 
-  protected static abstract interface CalendarContract.CalendarColumns {
-    field public static final java.lang.String ALLOWED_ATTENDEE_TYPES = "allowedAttendeeTypes";
-    field public static final java.lang.String ALLOWED_AVAILABILITY = "allowedAvailability";
-    field public static final java.lang.String ALLOWED_REMINDERS = "allowedReminders";
-    field public static final java.lang.String CALENDAR_ACCESS_LEVEL = "calendar_access_level";
-    field public static final java.lang.String CALENDAR_COLOR = "calendar_color";
-    field public static final java.lang.String CALENDAR_COLOR_KEY = "calendar_color_index";
-    field public static final java.lang.String CALENDAR_DISPLAY_NAME = "calendar_displayName";
-    field public static final java.lang.String CALENDAR_TIME_ZONE = "calendar_timezone";
+  protected static interface CalendarContract.CalendarColumns {
+    field public static final String ALLOWED_ATTENDEE_TYPES = "allowedAttendeeTypes";
+    field public static final String ALLOWED_AVAILABILITY = "allowedAvailability";
+    field public static final String ALLOWED_REMINDERS = "allowedReminders";
+    field public static final String CALENDAR_ACCESS_LEVEL = "calendar_access_level";
+    field public static final String CALENDAR_COLOR = "calendar_color";
+    field public static final String CALENDAR_COLOR_KEY = "calendar_color_index";
+    field public static final String CALENDAR_DISPLAY_NAME = "calendar_displayName";
+    field public static final String CALENDAR_TIME_ZONE = "calendar_timezone";
     field public static final int CAL_ACCESS_CONTRIBUTOR = 500; // 0x1f4
     field public static final int CAL_ACCESS_EDITOR = 600; // 0x258
     field public static final int CAL_ACCESS_FREEBUSY = 100; // 0x64
@@ -36214,13 +36548,13 @@
     field public static final int CAL_ACCESS_READ = 200; // 0xc8
     field public static final int CAL_ACCESS_RESPOND = 300; // 0x12c
     field public static final int CAL_ACCESS_ROOT = 800; // 0x320
-    field public static final java.lang.String CAN_MODIFY_TIME_ZONE = "canModifyTimeZone";
-    field public static final java.lang.String CAN_ORGANIZER_RESPOND = "canOrganizerRespond";
-    field public static final java.lang.String IS_PRIMARY = "isPrimary";
-    field public static final java.lang.String MAX_REMINDERS = "maxReminders";
-    field public static final java.lang.String OWNER_ACCOUNT = "ownerAccount";
-    field public static final java.lang.String SYNC_EVENTS = "sync_events";
-    field public static final java.lang.String VISIBLE = "visible";
+    field public static final String CAN_MODIFY_TIME_ZONE = "canModifyTimeZone";
+    field public static final String CAN_ORGANIZER_RESPOND = "canOrganizerRespond";
+    field public static final String IS_PRIMARY = "isPrimary";
+    field public static final String MAX_REMINDERS = "maxReminders";
+    field public static final String OWNER_ACCOUNT = "ownerAccount";
+    field public static final String SYNC_EVENTS = "sync_events";
+    field public static final String VISIBLE = "visible";
   }
 
   public static final class CalendarContract.CalendarEntity implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.SyncColumns {
@@ -36228,47 +36562,47 @@
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  protected static abstract interface CalendarContract.CalendarSyncColumns {
-    field public static final java.lang.String CAL_SYNC1 = "cal_sync1";
-    field public static final java.lang.String CAL_SYNC10 = "cal_sync10";
-    field public static final java.lang.String CAL_SYNC2 = "cal_sync2";
-    field public static final java.lang.String CAL_SYNC3 = "cal_sync3";
-    field public static final java.lang.String CAL_SYNC4 = "cal_sync4";
-    field public static final java.lang.String CAL_SYNC5 = "cal_sync5";
-    field public static final java.lang.String CAL_SYNC6 = "cal_sync6";
-    field public static final java.lang.String CAL_SYNC7 = "cal_sync7";
-    field public static final java.lang.String CAL_SYNC8 = "cal_sync8";
-    field public static final java.lang.String CAL_SYNC9 = "cal_sync9";
+  protected static interface CalendarContract.CalendarSyncColumns {
+    field public static final String CAL_SYNC1 = "cal_sync1";
+    field public static final String CAL_SYNC10 = "cal_sync10";
+    field public static final String CAL_SYNC2 = "cal_sync2";
+    field public static final String CAL_SYNC3 = "cal_sync3";
+    field public static final String CAL_SYNC4 = "cal_sync4";
+    field public static final String CAL_SYNC5 = "cal_sync5";
+    field public static final String CAL_SYNC6 = "cal_sync6";
+    field public static final String CAL_SYNC7 = "cal_sync7";
+    field public static final String CAL_SYNC8 = "cal_sync8";
+    field public static final String CAL_SYNC9 = "cal_sync9";
   }
 
   public static final class CalendarContract.Calendars implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.SyncColumns {
-    field public static final java.lang.String CALENDAR_LOCATION = "calendar_location";
+    field public static final String CALENDAR_LOCATION = "calendar_location";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "calendar_displayName";
+    field public static final String DEFAULT_SORT_ORDER = "calendar_displayName";
     field public static final android.net.Uri ENTERPRISE_CONTENT_URI;
-    field public static final java.lang.String NAME = "name";
+    field public static final String NAME = "name";
   }
 
   public static final class CalendarContract.Colors implements android.provider.CalendarContract.ColorsColumns {
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  protected static abstract interface CalendarContract.ColorsColumns implements android.provider.SyncStateContract.Columns {
-    field public static final java.lang.String COLOR = "color";
-    field public static final java.lang.String COLOR_KEY = "color_index";
-    field public static final java.lang.String COLOR_TYPE = "color_type";
+  protected static interface CalendarContract.ColorsColumns extends android.provider.SyncStateContract.Columns {
+    field public static final String COLOR = "color";
+    field public static final String COLOR_KEY = "color_index";
+    field public static final String COLOR_TYPE = "color_type";
     field public static final int TYPE_CALENDAR = 0; // 0x0
     field public static final int TYPE_EVENT = 1; // 0x1
   }
 
   public static final class CalendarContract.EventDays implements android.provider.CalendarContract.EventDaysColumns {
-    method public static android.database.Cursor query(android.content.ContentResolver, int, int, java.lang.String[]);
+    method public static android.database.Cursor query(android.content.ContentResolver, int, int, String[]);
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  protected static abstract interface CalendarContract.EventDaysColumns {
-    field public static final java.lang.String ENDDAY = "endDay";
-    field public static final java.lang.String STARTDAY = "startDay";
+  protected static interface CalendarContract.EventDaysColumns {
+    field public static final String ENDDAY = "endDay";
+    field public static final String STARTDAY = "startDay";
   }
 
   public static final class CalendarContract.Events implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.EventsColumns android.provider.CalendarContract.SyncColumns {
@@ -36277,66 +36611,66 @@
     field public static final android.net.Uri ENTERPRISE_CONTENT_URI;
   }
 
-  protected static abstract interface CalendarContract.EventsColumns {
+  protected static interface CalendarContract.EventsColumns {
     field public static final int ACCESS_CONFIDENTIAL = 1; // 0x1
     field public static final int ACCESS_DEFAULT = 0; // 0x0
-    field public static final java.lang.String ACCESS_LEVEL = "accessLevel";
+    field public static final String ACCESS_LEVEL = "accessLevel";
     field public static final int ACCESS_PRIVATE = 2; // 0x2
     field public static final int ACCESS_PUBLIC = 3; // 0x3
-    field public static final java.lang.String ALL_DAY = "allDay";
-    field public static final java.lang.String AVAILABILITY = "availability";
+    field public static final String ALL_DAY = "allDay";
+    field public static final String AVAILABILITY = "availability";
     field public static final int AVAILABILITY_BUSY = 0; // 0x0
     field public static final int AVAILABILITY_FREE = 1; // 0x1
     field public static final int AVAILABILITY_TENTATIVE = 2; // 0x2
-    field public static final java.lang.String CALENDAR_ID = "calendar_id";
-    field public static final java.lang.String CAN_INVITE_OTHERS = "canInviteOthers";
-    field public static final java.lang.String CUSTOM_APP_PACKAGE = "customAppPackage";
-    field public static final java.lang.String CUSTOM_APP_URI = "customAppUri";
-    field public static final java.lang.String DESCRIPTION = "description";
-    field public static final java.lang.String DISPLAY_COLOR = "displayColor";
-    field public static final java.lang.String DTEND = "dtend";
-    field public static final java.lang.String DTSTART = "dtstart";
-    field public static final java.lang.String DURATION = "duration";
-    field public static final java.lang.String EVENT_COLOR = "eventColor";
-    field public static final java.lang.String EVENT_COLOR_KEY = "eventColor_index";
-    field public static final java.lang.String EVENT_END_TIMEZONE = "eventEndTimezone";
-    field public static final java.lang.String EVENT_LOCATION = "eventLocation";
-    field public static final java.lang.String EVENT_TIMEZONE = "eventTimezone";
-    field public static final java.lang.String EXDATE = "exdate";
-    field public static final java.lang.String EXRULE = "exrule";
-    field public static final java.lang.String GUESTS_CAN_INVITE_OTHERS = "guestsCanInviteOthers";
-    field public static final java.lang.String GUESTS_CAN_MODIFY = "guestsCanModify";
-    field public static final java.lang.String GUESTS_CAN_SEE_GUESTS = "guestsCanSeeGuests";
-    field public static final java.lang.String HAS_ALARM = "hasAlarm";
-    field public static final java.lang.String HAS_ATTENDEE_DATA = "hasAttendeeData";
-    field public static final java.lang.String HAS_EXTENDED_PROPERTIES = "hasExtendedProperties";
-    field public static final java.lang.String IS_ORGANIZER = "isOrganizer";
-    field public static final java.lang.String LAST_DATE = "lastDate";
-    field public static final java.lang.String LAST_SYNCED = "lastSynced";
-    field public static final java.lang.String ORGANIZER = "organizer";
-    field public static final java.lang.String ORIGINAL_ALL_DAY = "originalAllDay";
-    field public static final java.lang.String ORIGINAL_ID = "original_id";
-    field public static final java.lang.String ORIGINAL_INSTANCE_TIME = "originalInstanceTime";
-    field public static final java.lang.String ORIGINAL_SYNC_ID = "original_sync_id";
-    field public static final java.lang.String RDATE = "rdate";
-    field public static final java.lang.String RRULE = "rrule";
-    field public static final java.lang.String SELF_ATTENDEE_STATUS = "selfAttendeeStatus";
-    field public static final java.lang.String STATUS = "eventStatus";
+    field public static final String CALENDAR_ID = "calendar_id";
+    field public static final String CAN_INVITE_OTHERS = "canInviteOthers";
+    field public static final String CUSTOM_APP_PACKAGE = "customAppPackage";
+    field public static final String CUSTOM_APP_URI = "customAppUri";
+    field public static final String DESCRIPTION = "description";
+    field public static final String DISPLAY_COLOR = "displayColor";
+    field public static final String DTEND = "dtend";
+    field public static final String DTSTART = "dtstart";
+    field public static final String DURATION = "duration";
+    field public static final String EVENT_COLOR = "eventColor";
+    field public static final String EVENT_COLOR_KEY = "eventColor_index";
+    field public static final String EVENT_END_TIMEZONE = "eventEndTimezone";
+    field public static final String EVENT_LOCATION = "eventLocation";
+    field public static final String EVENT_TIMEZONE = "eventTimezone";
+    field public static final String EXDATE = "exdate";
+    field public static final String EXRULE = "exrule";
+    field public static final String GUESTS_CAN_INVITE_OTHERS = "guestsCanInviteOthers";
+    field public static final String GUESTS_CAN_MODIFY = "guestsCanModify";
+    field public static final String GUESTS_CAN_SEE_GUESTS = "guestsCanSeeGuests";
+    field public static final String HAS_ALARM = "hasAlarm";
+    field public static final String HAS_ATTENDEE_DATA = "hasAttendeeData";
+    field public static final String HAS_EXTENDED_PROPERTIES = "hasExtendedProperties";
+    field public static final String IS_ORGANIZER = "isOrganizer";
+    field public static final String LAST_DATE = "lastDate";
+    field public static final String LAST_SYNCED = "lastSynced";
+    field public static final String ORGANIZER = "organizer";
+    field public static final String ORIGINAL_ALL_DAY = "originalAllDay";
+    field public static final String ORIGINAL_ID = "original_id";
+    field public static final String ORIGINAL_INSTANCE_TIME = "originalInstanceTime";
+    field public static final String ORIGINAL_SYNC_ID = "original_sync_id";
+    field public static final String RDATE = "rdate";
+    field public static final String RRULE = "rrule";
+    field public static final String SELF_ATTENDEE_STATUS = "selfAttendeeStatus";
+    field public static final String STATUS = "eventStatus";
     field public static final int STATUS_CANCELED = 2; // 0x2
     field public static final int STATUS_CONFIRMED = 1; // 0x1
     field public static final int STATUS_TENTATIVE = 0; // 0x0
-    field public static final java.lang.String SYNC_DATA1 = "sync_data1";
-    field public static final java.lang.String SYNC_DATA10 = "sync_data10";
-    field public static final java.lang.String SYNC_DATA2 = "sync_data2";
-    field public static final java.lang.String SYNC_DATA3 = "sync_data3";
-    field public static final java.lang.String SYNC_DATA4 = "sync_data4";
-    field public static final java.lang.String SYNC_DATA5 = "sync_data5";
-    field public static final java.lang.String SYNC_DATA6 = "sync_data6";
-    field public static final java.lang.String SYNC_DATA7 = "sync_data7";
-    field public static final java.lang.String SYNC_DATA8 = "sync_data8";
-    field public static final java.lang.String SYNC_DATA9 = "sync_data9";
-    field public static final java.lang.String TITLE = "title";
-    field public static final java.lang.String UID_2445 = "uid2445";
+    field public static final String SYNC_DATA1 = "sync_data1";
+    field public static final String SYNC_DATA10 = "sync_data10";
+    field public static final String SYNC_DATA2 = "sync_data2";
+    field public static final String SYNC_DATA3 = "sync_data3";
+    field public static final String SYNC_DATA4 = "sync_data4";
+    field public static final String SYNC_DATA5 = "sync_data5";
+    field public static final String SYNC_DATA6 = "sync_data6";
+    field public static final String SYNC_DATA7 = "sync_data7";
+    field public static final String SYNC_DATA8 = "sync_data8";
+    field public static final String SYNC_DATA9 = "sync_data9";
+    field public static final String TITLE = "title";
+    field public static final String UID_2445 = "uid2445";
   }
 
   public static final class CalendarContract.EventsEntity implements android.provider.BaseColumns android.provider.CalendarContract.EventsColumns android.provider.CalendarContract.SyncColumns {
@@ -36349,57 +36683,57 @@
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  protected static abstract interface CalendarContract.ExtendedPropertiesColumns {
-    field public static final java.lang.String EVENT_ID = "event_id";
-    field public static final java.lang.String NAME = "name";
-    field public static final java.lang.String VALUE = "value";
+  protected static interface CalendarContract.ExtendedPropertiesColumns {
+    field public static final String EVENT_ID = "event_id";
+    field public static final String NAME = "name";
+    field public static final String VALUE = "value";
   }
 
   public static final class CalendarContract.Instances implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.EventsColumns {
-    method public static android.database.Cursor query(android.content.ContentResolver, java.lang.String[], long, long);
-    method public static android.database.Cursor query(android.content.ContentResolver, java.lang.String[], long, long, java.lang.String);
-    field public static final java.lang.String BEGIN = "begin";
+    method public static android.database.Cursor query(android.content.ContentResolver, String[], long, long);
+    method public static android.database.Cursor query(android.content.ContentResolver, String[], long, long, String);
+    field public static final String BEGIN = "begin";
     field public static final android.net.Uri CONTENT_BY_DAY_URI;
     field public static final android.net.Uri CONTENT_SEARCH_BY_DAY_URI;
     field public static final android.net.Uri CONTENT_SEARCH_URI;
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String END = "end";
-    field public static final java.lang.String END_DAY = "endDay";
-    field public static final java.lang.String END_MINUTE = "endMinute";
+    field public static final String END = "end";
+    field public static final String END_DAY = "endDay";
+    field public static final String END_MINUTE = "endMinute";
     field public static final android.net.Uri ENTERPRISE_CONTENT_BY_DAY_URI;
     field public static final android.net.Uri ENTERPRISE_CONTENT_SEARCH_BY_DAY_URI;
     field public static final android.net.Uri ENTERPRISE_CONTENT_SEARCH_URI;
     field public static final android.net.Uri ENTERPRISE_CONTENT_URI;
-    field public static final java.lang.String EVENT_ID = "event_id";
-    field public static final java.lang.String START_DAY = "startDay";
-    field public static final java.lang.String START_MINUTE = "startMinute";
+    field public static final String EVENT_ID = "event_id";
+    field public static final String START_DAY = "startDay";
+    field public static final String START_MINUTE = "startMinute";
   }
 
   public static final class CalendarContract.Reminders implements android.provider.BaseColumns android.provider.CalendarContract.EventsColumns android.provider.CalendarContract.RemindersColumns {
-    method public static android.database.Cursor query(android.content.ContentResolver, long, java.lang.String[]);
+    method public static android.database.Cursor query(android.content.ContentResolver, long, String[]);
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  protected static abstract interface CalendarContract.RemindersColumns {
-    field public static final java.lang.String EVENT_ID = "event_id";
-    field public static final java.lang.String METHOD = "method";
+  protected static interface CalendarContract.RemindersColumns {
+    field public static final String EVENT_ID = "event_id";
+    field public static final String METHOD = "method";
     field public static final int METHOD_ALARM = 4; // 0x4
     field public static final int METHOD_ALERT = 1; // 0x1
     field public static final int METHOD_DEFAULT = 0; // 0x0
     field public static final int METHOD_EMAIL = 2; // 0x2
     field public static final int METHOD_SMS = 3; // 0x3
-    field public static final java.lang.String MINUTES = "minutes";
+    field public static final String MINUTES = "minutes";
     field public static final int MINUTES_DEFAULT = -1; // 0xffffffff
   }
 
-  protected static abstract interface CalendarContract.SyncColumns implements android.provider.CalendarContract.CalendarSyncColumns {
-    field public static final java.lang.String ACCOUNT_NAME = "account_name";
-    field public static final java.lang.String ACCOUNT_TYPE = "account_type";
-    field public static final java.lang.String CAN_PARTIALLY_UPDATE = "canPartiallyUpdate";
-    field public static final java.lang.String DELETED = "deleted";
-    field public static final java.lang.String DIRTY = "dirty";
-    field public static final java.lang.String MUTATORS = "mutators";
-    field public static final java.lang.String _SYNC_ID = "_sync_id";
+  protected static interface CalendarContract.SyncColumns extends android.provider.CalendarContract.CalendarSyncColumns {
+    field public static final String ACCOUNT_NAME = "account_name";
+    field public static final String ACCOUNT_TYPE = "account_type";
+    field public static final String CAN_PARTIALLY_UPDATE = "canPartiallyUpdate";
+    field public static final String DELETED = "deleted";
+    field public static final String DIRTY = "dirty";
+    field public static final String MUTATORS = "mutators";
+    field public static final String _SYNC_ID = "_sync_id";
   }
 
   public static final class CalendarContract.SyncState implements android.provider.SyncStateContract.Columns {
@@ -36408,16 +36742,16 @@
 
   public class CallLog {
     ctor public CallLog();
-    field public static final java.lang.String AUTHORITY = "call_log";
+    field public static final String AUTHORITY = "call_log";
     field public static final android.net.Uri CONTENT_URI;
   }
 
   public static class CallLog.Calls implements android.provider.BaseColumns {
     ctor public CallLog.Calls();
-    method public static java.lang.String getLastOutgoingCall(android.content.Context);
+    method public static String getLastOutgoingCall(android.content.Context);
     field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
     field public static final int BLOCKED_TYPE = 6; // 0x6
-    field public static final java.lang.String BLOCK_REASON = "block_reason";
+    field public static final String BLOCK_REASON = "block_reason";
     field public static final int BLOCK_REASON_BLOCKED_NUMBER = 3; // 0x3
     field public static final int BLOCK_REASON_CALL_SCREENING_SERVICE = 1; // 0x1
     field public static final int BLOCK_REASON_DIRECT_TO_VOICEMAIL = 2; // 0x2
@@ -36426,399 +36760,399 @@
     field public static final int BLOCK_REASON_PAY_PHONE = 6; // 0x6
     field public static final int BLOCK_REASON_RESTRICTED_NUMBER = 5; // 0x5
     field public static final int BLOCK_REASON_UNKNOWN_NUMBER = 4; // 0x4
-    field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
-    field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
-    field public static final java.lang.String CACHED_MATCHED_NUMBER = "matched_number";
-    field public static final java.lang.String CACHED_NAME = "name";
-    field public static final java.lang.String CACHED_NORMALIZED_NUMBER = "normalized_number";
-    field public static final java.lang.String CACHED_NUMBER_LABEL = "numberlabel";
-    field public static final java.lang.String CACHED_NUMBER_TYPE = "numbertype";
-    field public static final java.lang.String CACHED_PHOTO_ID = "photo_id";
-    field public static final java.lang.String CACHED_PHOTO_URI = "photo_uri";
-    field public static final java.lang.String CALL_ID_APP_NAME = "call_id_app_name";
-    field public static final java.lang.String CALL_ID_DESCRIPTION = "call_id_description";
-    field public static final java.lang.String CALL_ID_DETAILS = "call_id_details";
-    field public static final java.lang.String CALL_ID_NAME = "call_id_name";
-    field public static final java.lang.String CALL_ID_NUISANCE_CONFIDENCE = "call_id_nuisance_confidence";
-    field public static final java.lang.String CALL_ID_PACKAGE_NAME = "call_id_package_name";
-    field public static final java.lang.String CALL_SCREENING_APP_NAME = "call_screening_app_name";
-    field public static final java.lang.String CALL_SCREENING_COMPONENT_NAME = "call_screening_component_name";
+    field public static final String CACHED_FORMATTED_NUMBER = "formatted_number";
+    field public static final String CACHED_LOOKUP_URI = "lookup_uri";
+    field public static final String CACHED_MATCHED_NUMBER = "matched_number";
+    field public static final String CACHED_NAME = "name";
+    field public static final String CACHED_NORMALIZED_NUMBER = "normalized_number";
+    field public static final String CACHED_NUMBER_LABEL = "numberlabel";
+    field public static final String CACHED_NUMBER_TYPE = "numbertype";
+    field public static final String CACHED_PHOTO_ID = "photo_id";
+    field public static final String CACHED_PHOTO_URI = "photo_uri";
+    field public static final String CALL_ID_APP_NAME = "call_id_app_name";
+    field public static final String CALL_ID_DESCRIPTION = "call_id_description";
+    field public static final String CALL_ID_DETAILS = "call_id_details";
+    field public static final String CALL_ID_NAME = "call_id_name";
+    field public static final String CALL_ID_NUISANCE_CONFIDENCE = "call_id_nuisance_confidence";
+    field public static final String CALL_ID_PACKAGE_NAME = "call_id_package_name";
+    field public static final String CALL_SCREENING_APP_NAME = "call_screening_app_name";
+    field public static final String CALL_SCREENING_COMPONENT_NAME = "call_screening_component_name";
     field public static final android.net.Uri CONTENT_FILTER_URI;
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/calls";
     field public static final android.net.Uri CONTENT_URI;
     field public static final android.net.Uri CONTENT_URI_WITH_VOICEMAIL;
-    field public static final java.lang.String COUNTRY_ISO = "countryiso";
-    field public static final java.lang.String DATA_USAGE = "data_usage";
-    field public static final java.lang.String DATE = "date";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
-    field public static final java.lang.String DURATION = "duration";
-    field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
-    field public static final java.lang.String FEATURES = "features";
+    field public static final String COUNTRY_ISO = "countryiso";
+    field public static final String DATA_USAGE = "data_usage";
+    field public static final String DATE = "date";
+    field public static final String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final String DURATION = "duration";
+    field public static final String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
+    field public static final String FEATURES = "features";
     field public static final int FEATURES_HD_CALL = 4; // 0x4
     field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
     field public static final int FEATURES_RTT = 32; // 0x20
     field public static final int FEATURES_VIDEO = 1; // 0x1
     field public static final int FEATURES_WIFI = 8; // 0x8
-    field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
+    field public static final String GEOCODED_LOCATION = "geocoded_location";
     field public static final int INCOMING_TYPE = 1; // 0x1
-    field public static final java.lang.String IS_READ = "is_read";
-    field public static final java.lang.String LAST_MODIFIED = "last_modified";
-    field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
+    field public static final String IS_READ = "is_read";
+    field public static final String LAST_MODIFIED = "last_modified";
+    field public static final String LIMIT_PARAM_KEY = "limit";
     field public static final int MISSED_TYPE = 3; // 0x3
-    field public static final java.lang.String NEW = "new";
-    field public static final java.lang.String NUMBER = "number";
-    field public static final java.lang.String NUMBER_PRESENTATION = "presentation";
-    field public static final java.lang.String OFFSET_PARAM_KEY = "offset";
+    field public static final String NEW = "new";
+    field public static final String NUMBER = "number";
+    field public static final String NUMBER_PRESENTATION = "presentation";
+    field public static final String OFFSET_PARAM_KEY = "offset";
     field public static final int OUTGOING_TYPE = 2; // 0x2
-    field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
-    field public static final java.lang.String PHONE_ACCOUNT_ID = "subscription_id";
-    field public static final java.lang.String POST_DIAL_DIGITS = "post_dial_digits";
+    field public static final String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
+    field public static final String PHONE_ACCOUNT_ID = "subscription_id";
+    field public static final String POST_DIAL_DIGITS = "post_dial_digits";
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
     field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
     field public static final int REJECTED_TYPE = 5; // 0x5
-    field public static final java.lang.String TRANSCRIPTION = "transcription";
-    field public static final java.lang.String TYPE = "type";
-    field public static final java.lang.String VIA_NUMBER = "via_number";
+    field public static final String TRANSCRIPTION = "transcription";
+    field public static final String TYPE = "type";
+    field public static final String VIA_NUMBER = "via_number";
     field public static final int VOICEMAIL_TYPE = 4; // 0x4
-    field public static final java.lang.String VOICEMAIL_URI = "voicemail_uri";
+    field public static final String VOICEMAIL_URI = "voicemail_uri";
   }
 
-  public deprecated class Contacts {
-    field public static final deprecated java.lang.String AUTHORITY = "contacts";
-    field public static final deprecated android.net.Uri CONTENT_URI;
-    field public static final deprecated int KIND_EMAIL = 1; // 0x1
-    field public static final deprecated int KIND_IM = 3; // 0x3
-    field public static final deprecated int KIND_ORGANIZATION = 4; // 0x4
-    field public static final deprecated int KIND_PHONE = 5; // 0x5
-    field public static final deprecated int KIND_POSTAL = 2; // 0x2
+  @Deprecated public class Contacts {
+    field @Deprecated public static final String AUTHORITY = "contacts";
+    field @Deprecated public static final android.net.Uri CONTENT_URI;
+    field @Deprecated public static final int KIND_EMAIL = 1; // 0x1
+    field @Deprecated public static final int KIND_IM = 3; // 0x3
+    field @Deprecated public static final int KIND_ORGANIZATION = 4; // 0x4
+    field @Deprecated public static final int KIND_PHONE = 5; // 0x5
+    field @Deprecated public static final int KIND_POSTAL = 2; // 0x2
   }
 
-  public static final deprecated class Contacts.ContactMethods implements android.provider.BaseColumns android.provider.Contacts.ContactMethodsColumns android.provider.Contacts.PeopleColumns {
-    method public deprecated void addPostalLocation(android.content.Context, long, double, double);
-    method public static deprecated java.lang.Object decodeImProtocol(java.lang.String);
-    method public static deprecated java.lang.String encodeCustomImProtocol(java.lang.String);
-    method public static deprecated java.lang.String encodePredefinedImProtocol(int);
-    method public static deprecated java.lang.CharSequence getDisplayLabel(android.content.Context, int, int, java.lang.CharSequence);
-    field public static final deprecated java.lang.String CONTENT_EMAIL_ITEM_TYPE = "vnd.android.cursor.item/email";
-    field public static final deprecated java.lang.String CONTENT_EMAIL_TYPE = "vnd.android.cursor.dir/email";
-    field public static final deprecated android.net.Uri CONTENT_EMAIL_URI;
-    field public static final deprecated java.lang.String CONTENT_IM_ITEM_TYPE = "vnd.android.cursor.item/jabber-im";
-    field public static final deprecated java.lang.String CONTENT_POSTAL_ITEM_TYPE = "vnd.android.cursor.item/postal-address";
-    field public static final deprecated java.lang.String CONTENT_POSTAL_TYPE = "vnd.android.cursor.dir/postal-address";
-    field public static final deprecated java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contact-methods";
-    field public static final deprecated android.net.Uri CONTENT_URI;
-    field public static final deprecated java.lang.String DEFAULT_SORT_ORDER = "name ASC";
-    field public static final deprecated java.lang.String PERSON_ID = "person";
-    field public static final deprecated java.lang.String POSTAL_LOCATION_LATITUDE = "data";
-    field public static final deprecated java.lang.String POSTAL_LOCATION_LONGITUDE = "aux_data";
-    field public static final deprecated int PROTOCOL_AIM = 0; // 0x0
-    field public static final deprecated int PROTOCOL_GOOGLE_TALK = 5; // 0x5
-    field public static final deprecated int PROTOCOL_ICQ = 6; // 0x6
-    field public static final deprecated int PROTOCOL_JABBER = 7; // 0x7
-    field public static final deprecated int PROTOCOL_MSN = 1; // 0x1
-    field public static final deprecated int PROTOCOL_QQ = 4; // 0x4
-    field public static final deprecated int PROTOCOL_SKYPE = 3; // 0x3
-    field public static final deprecated int PROTOCOL_YAHOO = 2; // 0x2
+  @Deprecated public static final class Contacts.ContactMethods implements android.provider.BaseColumns android.provider.Contacts.ContactMethodsColumns android.provider.Contacts.PeopleColumns {
+    method @Deprecated public void addPostalLocation(android.content.Context, long, double, double);
+    method @Deprecated public static Object decodeImProtocol(String);
+    method @Deprecated public static String encodeCustomImProtocol(String);
+    method @Deprecated public static String encodePredefinedImProtocol(int);
+    method @Deprecated public static CharSequence getDisplayLabel(android.content.Context, int, int, CharSequence);
+    field @Deprecated public static final String CONTENT_EMAIL_ITEM_TYPE = "vnd.android.cursor.item/email";
+    field @Deprecated public static final String CONTENT_EMAIL_TYPE = "vnd.android.cursor.dir/email";
+    field @Deprecated public static final android.net.Uri CONTENT_EMAIL_URI;
+    field @Deprecated public static final String CONTENT_IM_ITEM_TYPE = "vnd.android.cursor.item/jabber-im";
+    field @Deprecated public static final String CONTENT_POSTAL_ITEM_TYPE = "vnd.android.cursor.item/postal-address";
+    field @Deprecated public static final String CONTENT_POSTAL_TYPE = "vnd.android.cursor.dir/postal-address";
+    field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact-methods";
+    field @Deprecated public static final android.net.Uri CONTENT_URI;
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "name ASC";
+    field @Deprecated public static final String PERSON_ID = "person";
+    field @Deprecated public static final String POSTAL_LOCATION_LATITUDE = "data";
+    field @Deprecated public static final String POSTAL_LOCATION_LONGITUDE = "aux_data";
+    field @Deprecated public static final int PROTOCOL_AIM = 0; // 0x0
+    field @Deprecated public static final int PROTOCOL_GOOGLE_TALK = 5; // 0x5
+    field @Deprecated public static final int PROTOCOL_ICQ = 6; // 0x6
+    field @Deprecated public static final int PROTOCOL_JABBER = 7; // 0x7
+    field @Deprecated public static final int PROTOCOL_MSN = 1; // 0x1
+    field @Deprecated public static final int PROTOCOL_QQ = 4; // 0x4
+    field @Deprecated public static final int PROTOCOL_SKYPE = 3; // 0x3
+    field @Deprecated public static final int PROTOCOL_YAHOO = 2; // 0x2
   }
 
-  public static abstract deprecated interface Contacts.ContactMethodsColumns {
-    field public static final deprecated java.lang.String AUX_DATA = "aux_data";
-    field public static final deprecated java.lang.String DATA = "data";
-    field public static final deprecated java.lang.String ISPRIMARY = "isprimary";
-    field public static final deprecated java.lang.String KIND = "kind";
-    field public static final deprecated java.lang.String LABEL = "label";
-    field public static final deprecated java.lang.String TYPE = "type";
-    field public static final deprecated int TYPE_CUSTOM = 0; // 0x0
-    field public static final deprecated int TYPE_HOME = 1; // 0x1
-    field public static final deprecated int TYPE_OTHER = 3; // 0x3
-    field public static final deprecated int TYPE_WORK = 2; // 0x2
+  @Deprecated public static interface Contacts.ContactMethodsColumns {
+    field @Deprecated public static final String AUX_DATA = "aux_data";
+    field @Deprecated public static final String DATA = "data";
+    field @Deprecated public static final String ISPRIMARY = "isprimary";
+    field @Deprecated public static final String KIND = "kind";
+    field @Deprecated public static final String LABEL = "label";
+    field @Deprecated public static final String TYPE = "type";
+    field @Deprecated public static final int TYPE_CUSTOM = 0; // 0x0
+    field @Deprecated public static final int TYPE_HOME = 1; // 0x1
+    field @Deprecated public static final int TYPE_OTHER = 3; // 0x3
+    field @Deprecated public static final int TYPE_WORK = 2; // 0x2
   }
 
-  public static final deprecated class Contacts.Extensions implements android.provider.BaseColumns android.provider.Contacts.ExtensionsColumns {
-    field public static final deprecated java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_extensions";
-    field public static final deprecated java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contact_extensions";
-    field public static final deprecated android.net.Uri CONTENT_URI;
-    field public static final deprecated java.lang.String DEFAULT_SORT_ORDER = "person, name ASC";
-    field public static final deprecated java.lang.String PERSON_ID = "person";
+  @Deprecated public static final class Contacts.Extensions implements android.provider.BaseColumns android.provider.Contacts.ExtensionsColumns {
+    field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_extensions";
+    field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_extensions";
+    field @Deprecated public static final android.net.Uri CONTENT_URI;
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "person, name ASC";
+    field @Deprecated public static final String PERSON_ID = "person";
   }
 
-  public static abstract deprecated interface Contacts.ExtensionsColumns {
-    field public static final deprecated java.lang.String NAME = "name";
-    field public static final deprecated java.lang.String VALUE = "value";
+  @Deprecated public static interface Contacts.ExtensionsColumns {
+    field @Deprecated public static final String NAME = "name";
+    field @Deprecated public static final String VALUE = "value";
   }
 
-  public static final deprecated class Contacts.GroupMembership implements android.provider.BaseColumns android.provider.Contacts.GroupsColumns {
-    field public static final deprecated java.lang.String CONTENT_DIRECTORY = "groupmembership";
-    field public static final deprecated java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contactsgroupmembership";
-    field public static final deprecated java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroupmembership";
-    field public static final deprecated android.net.Uri CONTENT_URI;
-    field public static final deprecated java.lang.String DEFAULT_SORT_ORDER = "group_id ASC";
-    field public static final deprecated java.lang.String GROUP_ID = "group_id";
-    field public static final deprecated java.lang.String GROUP_SYNC_ACCOUNT = "group_sync_account";
-    field public static final deprecated java.lang.String GROUP_SYNC_ACCOUNT_TYPE = "group_sync_account_type";
-    field public static final deprecated java.lang.String GROUP_SYNC_ID = "group_sync_id";
-    field public static final deprecated java.lang.String PERSON_ID = "person";
-    field public static final deprecated android.net.Uri RAW_CONTENT_URI;
+  @Deprecated public static final class Contacts.GroupMembership implements android.provider.BaseColumns android.provider.Contacts.GroupsColumns {
+    field @Deprecated public static final String CONTENT_DIRECTORY = "groupmembership";
+    field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contactsgroupmembership";
+    field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroupmembership";
+    field @Deprecated public static final android.net.Uri CONTENT_URI;
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "group_id ASC";
+    field @Deprecated public static final String GROUP_ID = "group_id";
+    field @Deprecated public static final String GROUP_SYNC_ACCOUNT = "group_sync_account";
+    field @Deprecated public static final String GROUP_SYNC_ACCOUNT_TYPE = "group_sync_account_type";
+    field @Deprecated public static final String GROUP_SYNC_ID = "group_sync_id";
+    field @Deprecated public static final String PERSON_ID = "person";
+    field @Deprecated public static final android.net.Uri RAW_CONTENT_URI;
   }
 
-  public static final deprecated class Contacts.Groups implements android.provider.BaseColumns android.provider.Contacts.GroupsColumns {
-    field public static final deprecated java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contactsgroup";
-    field public static final deprecated java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroup";
-    field public static final deprecated android.net.Uri CONTENT_URI;
-    field public static final deprecated java.lang.String DEFAULT_SORT_ORDER = "name ASC";
-    field public static final deprecated android.net.Uri DELETED_CONTENT_URI;
-    field public static final deprecated java.lang.String GROUP_ANDROID_STARRED = "Starred in Android";
-    field public static final deprecated java.lang.String GROUP_MY_CONTACTS = "Contacts";
+  @Deprecated public static final class Contacts.Groups implements android.provider.BaseColumns android.provider.Contacts.GroupsColumns {
+    field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contactsgroup";
+    field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroup";
+    field @Deprecated public static final android.net.Uri CONTENT_URI;
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "name ASC";
+    field @Deprecated public static final android.net.Uri DELETED_CONTENT_URI;
+    field @Deprecated public static final String GROUP_ANDROID_STARRED = "Starred in Android";
+    field @Deprecated public static final String GROUP_MY_CONTACTS = "Contacts";
   }
 
-  public static abstract deprecated interface Contacts.GroupsColumns {
-    field public static final deprecated java.lang.String NAME = "name";
-    field public static final deprecated java.lang.String NOTES = "notes";
-    field public static final deprecated java.lang.String SHOULD_SYNC = "should_sync";
-    field public static final deprecated java.lang.String SYSTEM_ID = "system_id";
+  @Deprecated public static interface Contacts.GroupsColumns {
+    field @Deprecated public static final String NAME = "name";
+    field @Deprecated public static final String NOTES = "notes";
+    field @Deprecated public static final String SHOULD_SYNC = "should_sync";
+    field @Deprecated public static final String SYSTEM_ID = "system_id";
   }
 
-  public static final deprecated class Contacts.Intents {
-    ctor public deprecated Contacts.Intents();
-    field public static final deprecated java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
-    field public static final deprecated java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
-    field public static final deprecated java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
-    field public static final deprecated java.lang.String SEARCH_SUGGESTION_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
-    field public static final deprecated java.lang.String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
-    field public static final deprecated java.lang.String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
-    field public static final deprecated java.lang.String SHOW_OR_CREATE_CONTACT = "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
+  @Deprecated public static final class Contacts.Intents {
+    ctor @Deprecated public Contacts.Intents();
+    field @Deprecated public static final String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
+    field @Deprecated public static final String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
+    field @Deprecated public static final String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
+    field @Deprecated public static final String SEARCH_SUGGESTION_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
+    field @Deprecated public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
+    field @Deprecated public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
+    field @Deprecated public static final String SHOW_OR_CREATE_CONTACT = "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
   }
 
-  public static final deprecated class Contacts.Intents.Insert {
-    ctor public deprecated Contacts.Intents.Insert();
-    field public static final deprecated java.lang.String ACTION = "android.intent.action.INSERT";
-    field public static final deprecated java.lang.String COMPANY = "company";
-    field public static final deprecated java.lang.String EMAIL = "email";
-    field public static final deprecated java.lang.String EMAIL_ISPRIMARY = "email_isprimary";
-    field public static final deprecated java.lang.String EMAIL_TYPE = "email_type";
-    field public static final deprecated java.lang.String FULL_MODE = "full_mode";
-    field public static final deprecated java.lang.String IM_HANDLE = "im_handle";
-    field public static final deprecated java.lang.String IM_ISPRIMARY = "im_isprimary";
-    field public static final deprecated java.lang.String IM_PROTOCOL = "im_protocol";
-    field public static final deprecated java.lang.String JOB_TITLE = "job_title";
-    field public static final deprecated java.lang.String NAME = "name";
-    field public static final deprecated java.lang.String NOTES = "notes";
-    field public static final deprecated java.lang.String PHONE = "phone";
-    field public static final deprecated java.lang.String PHONETIC_NAME = "phonetic_name";
-    field public static final deprecated java.lang.String PHONE_ISPRIMARY = "phone_isprimary";
-    field public static final deprecated java.lang.String PHONE_TYPE = "phone_type";
-    field public static final deprecated java.lang.String POSTAL = "postal";
-    field public static final deprecated java.lang.String POSTAL_ISPRIMARY = "postal_isprimary";
-    field public static final deprecated java.lang.String POSTAL_TYPE = "postal_type";
-    field public static final deprecated java.lang.String SECONDARY_EMAIL = "secondary_email";
-    field public static final deprecated java.lang.String SECONDARY_EMAIL_TYPE = "secondary_email_type";
-    field public static final deprecated java.lang.String SECONDARY_PHONE = "secondary_phone";
-    field public static final deprecated java.lang.String SECONDARY_PHONE_TYPE = "secondary_phone_type";
-    field public static final deprecated java.lang.String TERTIARY_EMAIL = "tertiary_email";
-    field public static final deprecated java.lang.String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
-    field public static final deprecated java.lang.String TERTIARY_PHONE = "tertiary_phone";
-    field public static final deprecated java.lang.String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
+  @Deprecated public static final class Contacts.Intents.Insert {
+    ctor @Deprecated public Contacts.Intents.Insert();
+    field @Deprecated public static final String ACTION = "android.intent.action.INSERT";
+    field @Deprecated public static final String COMPANY = "company";
+    field @Deprecated public static final String EMAIL = "email";
+    field @Deprecated public static final String EMAIL_ISPRIMARY = "email_isprimary";
+    field @Deprecated public static final String EMAIL_TYPE = "email_type";
+    field @Deprecated public static final String FULL_MODE = "full_mode";
+    field @Deprecated public static final String IM_HANDLE = "im_handle";
+    field @Deprecated public static final String IM_ISPRIMARY = "im_isprimary";
+    field @Deprecated public static final String IM_PROTOCOL = "im_protocol";
+    field @Deprecated public static final String JOB_TITLE = "job_title";
+    field @Deprecated public static final String NAME = "name";
+    field @Deprecated public static final String NOTES = "notes";
+    field @Deprecated public static final String PHONE = "phone";
+    field @Deprecated public static final String PHONETIC_NAME = "phonetic_name";
+    field @Deprecated public static final String PHONE_ISPRIMARY = "phone_isprimary";
+    field @Deprecated public static final String PHONE_TYPE = "phone_type";
+    field @Deprecated public static final String POSTAL = "postal";
+    field @Deprecated public static final String POSTAL_ISPRIMARY = "postal_isprimary";
+    field @Deprecated public static final String POSTAL_TYPE = "postal_type";
+    field @Deprecated public static final String SECONDARY_EMAIL = "secondary_email";
+    field @Deprecated public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
+    field @Deprecated public static final String SECONDARY_PHONE = "secondary_phone";
+    field @Deprecated public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
+    field @Deprecated public static final String TERTIARY_EMAIL = "tertiary_email";
+    field @Deprecated public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
+    field @Deprecated public static final String TERTIARY_PHONE = "tertiary_phone";
+    field @Deprecated public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
   }
 
-  public static final deprecated class Contacts.Intents.UI {
-    ctor public deprecated Contacts.Intents.UI();
-    field public static final deprecated java.lang.String FILTER_CONTACTS_ACTION = "com.android.contacts.action.FILTER_CONTACTS";
-    field public static final deprecated java.lang.String FILTER_TEXT_EXTRA_KEY = "com.android.contacts.extra.FILTER_TEXT";
-    field public static final deprecated java.lang.String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";
-    field public static final deprecated java.lang.String LIST_ALL_CONTACTS_ACTION = "com.android.contacts.action.LIST_ALL_CONTACTS";
-    field public static final deprecated java.lang.String LIST_CONTACTS_WITH_PHONES_ACTION = "com.android.contacts.action.LIST_CONTACTS_WITH_PHONES";
-    field public static final deprecated java.lang.String LIST_DEFAULT = "com.android.contacts.action.LIST_DEFAULT";
-    field public static final deprecated java.lang.String LIST_FREQUENT_ACTION = "com.android.contacts.action.LIST_FREQUENT";
-    field public static final deprecated java.lang.String LIST_GROUP_ACTION = "com.android.contacts.action.LIST_GROUP";
-    field public static final deprecated java.lang.String LIST_STARRED_ACTION = "com.android.contacts.action.LIST_STARRED";
-    field public static final deprecated java.lang.String LIST_STREQUENT_ACTION = "com.android.contacts.action.LIST_STREQUENT";
-    field public static final deprecated java.lang.String TITLE_EXTRA_KEY = "com.android.contacts.extra.TITLE_EXTRA";
+  @Deprecated public static final class Contacts.Intents.UI {
+    ctor @Deprecated public Contacts.Intents.UI();
+    field @Deprecated public static final String FILTER_CONTACTS_ACTION = "com.android.contacts.action.FILTER_CONTACTS";
+    field @Deprecated public static final String FILTER_TEXT_EXTRA_KEY = "com.android.contacts.extra.FILTER_TEXT";
+    field @Deprecated public static final String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";
+    field @Deprecated public static final String LIST_ALL_CONTACTS_ACTION = "com.android.contacts.action.LIST_ALL_CONTACTS";
+    field @Deprecated public static final String LIST_CONTACTS_WITH_PHONES_ACTION = "com.android.contacts.action.LIST_CONTACTS_WITH_PHONES";
+    field @Deprecated public static final String LIST_DEFAULT = "com.android.contacts.action.LIST_DEFAULT";
+    field @Deprecated public static final String LIST_FREQUENT_ACTION = "com.android.contacts.action.LIST_FREQUENT";
+    field @Deprecated public static final String LIST_GROUP_ACTION = "com.android.contacts.action.LIST_GROUP";
+    field @Deprecated public static final String LIST_STARRED_ACTION = "com.android.contacts.action.LIST_STARRED";
+    field @Deprecated public static final String LIST_STREQUENT_ACTION = "com.android.contacts.action.LIST_STREQUENT";
+    field @Deprecated public static final String TITLE_EXTRA_KEY = "com.android.contacts.extra.TITLE_EXTRA";
   }
 
-  public static abstract deprecated interface Contacts.OrganizationColumns {
-    field public static final deprecated java.lang.String COMPANY = "company";
-    field public static final deprecated java.lang.String ISPRIMARY = "isprimary";
-    field public static final deprecated java.lang.String LABEL = "label";
-    field public static final deprecated java.lang.String PERSON_ID = "person";
-    field public static final deprecated java.lang.String TITLE = "title";
-    field public static final deprecated java.lang.String TYPE = "type";
-    field public static final deprecated int TYPE_CUSTOM = 0; // 0x0
-    field public static final deprecated int TYPE_OTHER = 2; // 0x2
-    field public static final deprecated int TYPE_WORK = 1; // 0x1
+  @Deprecated public static interface Contacts.OrganizationColumns {
+    field @Deprecated public static final String COMPANY = "company";
+    field @Deprecated public static final String ISPRIMARY = "isprimary";
+    field @Deprecated public static final String LABEL = "label";
+    field @Deprecated public static final String PERSON_ID = "person";
+    field @Deprecated public static final String TITLE = "title";
+    field @Deprecated public static final String TYPE = "type";
+    field @Deprecated public static final int TYPE_CUSTOM = 0; // 0x0
+    field @Deprecated public static final int TYPE_OTHER = 2; // 0x2
+    field @Deprecated public static final int TYPE_WORK = 1; // 0x1
   }
 
-  public static final deprecated class Contacts.Organizations implements android.provider.BaseColumns android.provider.Contacts.OrganizationColumns {
-    method public static deprecated java.lang.CharSequence getDisplayLabel(android.content.Context, int, java.lang.CharSequence);
-    field public static final deprecated java.lang.String CONTENT_DIRECTORY = "organizations";
-    field public static final deprecated android.net.Uri CONTENT_URI;
-    field public static final deprecated java.lang.String DEFAULT_SORT_ORDER = "company, title, isprimary ASC";
+  @Deprecated public static final class Contacts.Organizations implements android.provider.BaseColumns android.provider.Contacts.OrganizationColumns {
+    method @Deprecated public static CharSequence getDisplayLabel(android.content.Context, int, CharSequence);
+    field @Deprecated public static final String CONTENT_DIRECTORY = "organizations";
+    field @Deprecated public static final android.net.Uri CONTENT_URI;
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "company, title, isprimary ASC";
   }
 
-  public static final deprecated class Contacts.People implements android.provider.BaseColumns android.provider.Contacts.PeopleColumns android.provider.Contacts.PhonesColumns android.provider.Contacts.PresenceColumns {
-    method public static deprecated android.net.Uri addToGroup(android.content.ContentResolver, long, java.lang.String);
-    method public static deprecated android.net.Uri addToGroup(android.content.ContentResolver, long, long);
-    method public static deprecated android.net.Uri addToMyContactsGroup(android.content.ContentResolver, long);
-    method public static deprecated android.net.Uri createPersonInMyContactsGroup(android.content.ContentResolver, android.content.ContentValues);
-    method public static deprecated android.graphics.Bitmap loadContactPhoto(android.content.Context, android.net.Uri, int, android.graphics.BitmapFactory.Options);
-    method public static deprecated void markAsContacted(android.content.ContentResolver, long);
-    method public static deprecated java.io.InputStream openContactPhotoInputStream(android.content.ContentResolver, android.net.Uri);
-    method public static deprecated android.database.Cursor queryGroups(android.content.ContentResolver, long);
-    method public static deprecated void setPhotoData(android.content.ContentResolver, android.net.Uri, byte[]);
-    field public static final deprecated android.net.Uri CONTENT_FILTER_URI;
-    field public static final deprecated java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person";
-    field public static final deprecated java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/person";
-    field public static final deprecated android.net.Uri CONTENT_URI;
-    field public static final deprecated java.lang.String DEFAULT_SORT_ORDER = "name ASC";
-    field public static final deprecated android.net.Uri DELETED_CONTENT_URI;
-    field public static final deprecated java.lang.String PRIMARY_EMAIL_ID = "primary_email";
-    field public static final deprecated java.lang.String PRIMARY_ORGANIZATION_ID = "primary_organization";
-    field public static final deprecated java.lang.String PRIMARY_PHONE_ID = "primary_phone";
+  @Deprecated public static final class Contacts.People implements android.provider.BaseColumns android.provider.Contacts.PeopleColumns android.provider.Contacts.PhonesColumns android.provider.Contacts.PresenceColumns {
+    method @Deprecated public static android.net.Uri addToGroup(android.content.ContentResolver, long, String);
+    method @Deprecated public static android.net.Uri addToGroup(android.content.ContentResolver, long, long);
+    method @Deprecated public static android.net.Uri addToMyContactsGroup(android.content.ContentResolver, long);
+    method @Deprecated public static android.net.Uri createPersonInMyContactsGroup(android.content.ContentResolver, android.content.ContentValues);
+    method @Deprecated public static android.graphics.Bitmap loadContactPhoto(android.content.Context, android.net.Uri, int, android.graphics.BitmapFactory.Options);
+    method @Deprecated public static void markAsContacted(android.content.ContentResolver, long);
+    method @Deprecated public static java.io.InputStream openContactPhotoInputStream(android.content.ContentResolver, android.net.Uri);
+    method @Deprecated public static android.database.Cursor queryGroups(android.content.ContentResolver, long);
+    method @Deprecated public static void setPhotoData(android.content.ContentResolver, android.net.Uri, byte[]);
+    field @Deprecated public static final android.net.Uri CONTENT_FILTER_URI;
+    field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person";
+    field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person";
+    field @Deprecated public static final android.net.Uri CONTENT_URI;
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "name ASC";
+    field @Deprecated public static final android.net.Uri DELETED_CONTENT_URI;
+    field @Deprecated public static final String PRIMARY_EMAIL_ID = "primary_email";
+    field @Deprecated public static final String PRIMARY_ORGANIZATION_ID = "primary_organization";
+    field @Deprecated public static final String PRIMARY_PHONE_ID = "primary_phone";
   }
 
-  public static final deprecated class Contacts.People.ContactMethods implements android.provider.BaseColumns android.provider.Contacts.ContactMethodsColumns android.provider.Contacts.PeopleColumns {
-    field public static final deprecated java.lang.String CONTENT_DIRECTORY = "contact_methods";
-    field public static final deprecated java.lang.String DEFAULT_SORT_ORDER = "data ASC";
+  @Deprecated public static final class Contacts.People.ContactMethods implements android.provider.BaseColumns android.provider.Contacts.ContactMethodsColumns android.provider.Contacts.PeopleColumns {
+    field @Deprecated public static final String CONTENT_DIRECTORY = "contact_methods";
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "data ASC";
   }
 
-  public static deprecated class Contacts.People.Extensions implements android.provider.BaseColumns android.provider.Contacts.ExtensionsColumns {
-    field public static final deprecated java.lang.String CONTENT_DIRECTORY = "extensions";
-    field public static final deprecated java.lang.String DEFAULT_SORT_ORDER = "name ASC";
-    field public static final deprecated java.lang.String PERSON_ID = "person";
+  @Deprecated public static class Contacts.People.Extensions implements android.provider.BaseColumns android.provider.Contacts.ExtensionsColumns {
+    field @Deprecated public static final String CONTENT_DIRECTORY = "extensions";
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "name ASC";
+    field @Deprecated public static final String PERSON_ID = "person";
   }
 
-  public static final deprecated class Contacts.People.Phones implements android.provider.BaseColumns android.provider.Contacts.PeopleColumns android.provider.Contacts.PhonesColumns {
-    field public static final deprecated java.lang.String CONTENT_DIRECTORY = "phones";
-    field public static final deprecated java.lang.String DEFAULT_SORT_ORDER = "number ASC";
+  @Deprecated public static final class Contacts.People.Phones implements android.provider.BaseColumns android.provider.Contacts.PeopleColumns android.provider.Contacts.PhonesColumns {
+    field @Deprecated public static final String CONTENT_DIRECTORY = "phones";
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "number ASC";
   }
 
-  public static abstract deprecated interface Contacts.PeopleColumns {
-    field public static final deprecated java.lang.String CUSTOM_RINGTONE = "custom_ringtone";
-    field public static final deprecated java.lang.String DISPLAY_NAME = "display_name";
-    field public static final deprecated java.lang.String LAST_TIME_CONTACTED = "last_time_contacted";
-    field public static final deprecated java.lang.String NAME = "name";
-    field public static final deprecated java.lang.String NOTES = "notes";
-    field public static final deprecated java.lang.String PHONETIC_NAME = "phonetic_name";
-    field public static final deprecated java.lang.String PHOTO_VERSION = "photo_version";
-    field public static final deprecated java.lang.String SEND_TO_VOICEMAIL = "send_to_voicemail";
-    field public static final deprecated java.lang.String STARRED = "starred";
-    field public static final deprecated java.lang.String TIMES_CONTACTED = "times_contacted";
+  @Deprecated public static interface Contacts.PeopleColumns {
+    field @Deprecated public static final String CUSTOM_RINGTONE = "custom_ringtone";
+    field @Deprecated public static final String DISPLAY_NAME = "display_name";
+    field @Deprecated public static final String LAST_TIME_CONTACTED = "last_time_contacted";
+    field @Deprecated public static final String NAME = "name";
+    field @Deprecated public static final String NOTES = "notes";
+    field @Deprecated public static final String PHONETIC_NAME = "phonetic_name";
+    field @Deprecated public static final String PHOTO_VERSION = "photo_version";
+    field @Deprecated public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
+    field @Deprecated public static final String STARRED = "starred";
+    field @Deprecated public static final String TIMES_CONTACTED = "times_contacted";
   }
 
-  public static final deprecated class Contacts.Phones implements android.provider.BaseColumns android.provider.Contacts.PeopleColumns android.provider.Contacts.PhonesColumns {
-    method public static deprecated java.lang.CharSequence getDisplayLabel(android.content.Context, int, java.lang.CharSequence, java.lang.CharSequence[]);
-    method public static deprecated java.lang.CharSequence getDisplayLabel(android.content.Context, int, java.lang.CharSequence);
-    field public static final deprecated android.net.Uri CONTENT_FILTER_URL;
-    field public static final deprecated java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone";
-    field public static final deprecated java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/phone";
-    field public static final deprecated android.net.Uri CONTENT_URI;
-    field public static final deprecated java.lang.String DEFAULT_SORT_ORDER = "name ASC";
-    field public static final deprecated java.lang.String PERSON_ID = "person";
+  @Deprecated public static final class Contacts.Phones implements android.provider.BaseColumns android.provider.Contacts.PeopleColumns android.provider.Contacts.PhonesColumns {
+    method @Deprecated public static CharSequence getDisplayLabel(android.content.Context, int, CharSequence, CharSequence[]);
+    method @Deprecated public static CharSequence getDisplayLabel(android.content.Context, int, CharSequence);
+    field @Deprecated public static final android.net.Uri CONTENT_FILTER_URL;
+    field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone";
+    field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone";
+    field @Deprecated public static final android.net.Uri CONTENT_URI;
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "name ASC";
+    field @Deprecated public static final String PERSON_ID = "person";
   }
 
-  public static abstract deprecated interface Contacts.PhonesColumns {
-    field public static final deprecated java.lang.String ISPRIMARY = "isprimary";
-    field public static final deprecated java.lang.String LABEL = "label";
-    field public static final deprecated java.lang.String NUMBER = "number";
-    field public static final deprecated java.lang.String NUMBER_KEY = "number_key";
-    field public static final deprecated java.lang.String TYPE = "type";
-    field public static final deprecated int TYPE_CUSTOM = 0; // 0x0
-    field public static final deprecated int TYPE_FAX_HOME = 5; // 0x5
-    field public static final deprecated int TYPE_FAX_WORK = 4; // 0x4
-    field public static final deprecated int TYPE_HOME = 1; // 0x1
-    field public static final deprecated int TYPE_MOBILE = 2; // 0x2
-    field public static final deprecated int TYPE_OTHER = 7; // 0x7
-    field public static final deprecated int TYPE_PAGER = 6; // 0x6
-    field public static final deprecated int TYPE_WORK = 3; // 0x3
+  @Deprecated public static interface Contacts.PhonesColumns {
+    field @Deprecated public static final String ISPRIMARY = "isprimary";
+    field @Deprecated public static final String LABEL = "label";
+    field @Deprecated public static final String NUMBER = "number";
+    field @Deprecated public static final String NUMBER_KEY = "number_key";
+    field @Deprecated public static final String TYPE = "type";
+    field @Deprecated public static final int TYPE_CUSTOM = 0; // 0x0
+    field @Deprecated public static final int TYPE_FAX_HOME = 5; // 0x5
+    field @Deprecated public static final int TYPE_FAX_WORK = 4; // 0x4
+    field @Deprecated public static final int TYPE_HOME = 1; // 0x1
+    field @Deprecated public static final int TYPE_MOBILE = 2; // 0x2
+    field @Deprecated public static final int TYPE_OTHER = 7; // 0x7
+    field @Deprecated public static final int TYPE_PAGER = 6; // 0x6
+    field @Deprecated public static final int TYPE_WORK = 3; // 0x3
   }
 
-  public static final deprecated class Contacts.Photos implements android.provider.BaseColumns android.provider.Contacts.PhotosColumns {
-    field public static final deprecated java.lang.String CONTENT_DIRECTORY = "photo";
-    field public static final deprecated android.net.Uri CONTENT_URI;
-    field public static final deprecated java.lang.String DEFAULT_SORT_ORDER = "person ASC";
+  @Deprecated public static final class Contacts.Photos implements android.provider.BaseColumns android.provider.Contacts.PhotosColumns {
+    field @Deprecated public static final String CONTENT_DIRECTORY = "photo";
+    field @Deprecated public static final android.net.Uri CONTENT_URI;
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "person ASC";
   }
 
-  public static abstract deprecated interface Contacts.PhotosColumns {
-    field public static final deprecated java.lang.String DATA = "data";
-    field public static final deprecated java.lang.String DOWNLOAD_REQUIRED = "download_required";
-    field public static final deprecated java.lang.String EXISTS_ON_SERVER = "exists_on_server";
-    field public static final deprecated java.lang.String LOCAL_VERSION = "local_version";
-    field public static final deprecated java.lang.String PERSON_ID = "person";
-    field public static final deprecated java.lang.String SYNC_ERROR = "sync_error";
+  @Deprecated public static interface Contacts.PhotosColumns {
+    field @Deprecated public static final String DATA = "data";
+    field @Deprecated public static final String DOWNLOAD_REQUIRED = "download_required";
+    field @Deprecated public static final String EXISTS_ON_SERVER = "exists_on_server";
+    field @Deprecated public static final String LOCAL_VERSION = "local_version";
+    field @Deprecated public static final String PERSON_ID = "person";
+    field @Deprecated public static final String SYNC_ERROR = "sync_error";
   }
 
-  public static abstract deprecated interface Contacts.PresenceColumns {
-    field public static final int AVAILABLE = 5; // 0x5
-    field public static final int AWAY = 2; // 0x2
-    field public static final int DO_NOT_DISTURB = 4; // 0x4
-    field public static final int IDLE = 3; // 0x3
-    field public static final deprecated java.lang.String IM_ACCOUNT = "im_account";
-    field public static final deprecated java.lang.String IM_HANDLE = "im_handle";
-    field public static final deprecated java.lang.String IM_PROTOCOL = "im_protocol";
-    field public static final int INVISIBLE = 1; // 0x1
-    field public static final int OFFLINE = 0; // 0x0
-    field public static final java.lang.String PRESENCE_CUSTOM_STATUS = "status";
-    field public static final java.lang.String PRESENCE_STATUS = "mode";
-    field public static final java.lang.String PRIORITY = "priority";
+  @Deprecated public static interface Contacts.PresenceColumns {
+    field @Deprecated public static final int AVAILABLE = 5; // 0x5
+    field @Deprecated public static final int AWAY = 2; // 0x2
+    field @Deprecated public static final int DO_NOT_DISTURB = 4; // 0x4
+    field @Deprecated public static final int IDLE = 3; // 0x3
+    field @Deprecated public static final String IM_ACCOUNT = "im_account";
+    field @Deprecated public static final String IM_HANDLE = "im_handle";
+    field @Deprecated public static final String IM_PROTOCOL = "im_protocol";
+    field @Deprecated public static final int INVISIBLE = 1; // 0x1
+    field @Deprecated public static final int OFFLINE = 0; // 0x0
+    field @Deprecated public static final String PRESENCE_CUSTOM_STATUS = "status";
+    field @Deprecated public static final String PRESENCE_STATUS = "mode";
+    field @Deprecated public static final String PRIORITY = "priority";
   }
 
-  public static final deprecated class Contacts.Settings implements android.provider.BaseColumns android.provider.Contacts.SettingsColumns {
-    method public static deprecated java.lang.String getSetting(android.content.ContentResolver, java.lang.String, java.lang.String);
-    method public static deprecated void setSetting(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String);
-    field public static final deprecated java.lang.String CONTENT_DIRECTORY = "settings";
-    field public static final deprecated android.net.Uri CONTENT_URI;
-    field public static final deprecated java.lang.String DEFAULT_SORT_ORDER = "key ASC";
-    field public static final deprecated java.lang.String SYNC_EVERYTHING = "syncEverything";
+  @Deprecated public static final class Contacts.Settings implements android.provider.BaseColumns android.provider.Contacts.SettingsColumns {
+    method @Deprecated public static String getSetting(android.content.ContentResolver, String, String);
+    method @Deprecated public static void setSetting(android.content.ContentResolver, String, String, String);
+    field @Deprecated public static final String CONTENT_DIRECTORY = "settings";
+    field @Deprecated public static final android.net.Uri CONTENT_URI;
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "key ASC";
+    field @Deprecated public static final String SYNC_EVERYTHING = "syncEverything";
   }
 
-  public static abstract deprecated interface Contacts.SettingsColumns {
-    field public static final deprecated java.lang.String KEY = "key";
-    field public static final deprecated java.lang.String VALUE = "value";
-    field public static final deprecated java.lang.String _SYNC_ACCOUNT = "_sync_account";
-    field public static final deprecated java.lang.String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
+  @Deprecated public static interface Contacts.SettingsColumns {
+    field @Deprecated public static final String KEY = "key";
+    field @Deprecated public static final String VALUE = "value";
+    field @Deprecated public static final String _SYNC_ACCOUNT = "_sync_account";
+    field @Deprecated public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
   }
 
   public final class ContactsContract {
     ctor public ContactsContract();
     method public static boolean isProfileId(long);
-    field public static final java.lang.String AUTHORITY = "com.android.contacts";
+    field public static final String AUTHORITY = "com.android.contacts";
     field public static final android.net.Uri AUTHORITY_URI;
-    field public static final java.lang.String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
-    field public static final java.lang.String DEFERRED_SNIPPETING = "deferred_snippeting";
-    field public static final java.lang.String DEFERRED_SNIPPETING_QUERY = "deferred_snippeting_query";
-    field public static final java.lang.String DIRECTORY_PARAM_KEY = "directory";
-    field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
-    field public static final java.lang.String PRIMARY_ACCOUNT_NAME = "name_for_primary_account";
-    field public static final java.lang.String PRIMARY_ACCOUNT_TYPE = "type_for_primary_account";
-    field public static final java.lang.String REMOVE_DUPLICATE_ENTRIES = "remove_duplicate_entries";
-    field public static final java.lang.String STREQUENT_PHONE_ONLY = "strequent_phone_only";
+    field public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
+    field public static final String DEFERRED_SNIPPETING = "deferred_snippeting";
+    field public static final String DEFERRED_SNIPPETING_QUERY = "deferred_snippeting_query";
+    field public static final String DIRECTORY_PARAM_KEY = "directory";
+    field public static final String LIMIT_PARAM_KEY = "limit";
+    field public static final String PRIMARY_ACCOUNT_NAME = "name_for_primary_account";
+    field public static final String PRIMARY_ACCOUNT_TYPE = "type_for_primary_account";
+    field public static final String REMOVE_DUPLICATE_ENTRIES = "remove_duplicate_entries";
+    field public static final String STREQUENT_PHONE_ONLY = "strequent_phone_only";
   }
 
   public static final class ContactsContract.AggregationExceptions implements android.provider.BaseColumns {
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/aggregation_exception";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/aggregation_exception";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/aggregation_exception";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/aggregation_exception";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String RAW_CONTACT_ID1 = "raw_contact_id1";
-    field public static final java.lang.String RAW_CONTACT_ID2 = "raw_contact_id2";
-    field public static final java.lang.String TYPE = "type";
+    field public static final String RAW_CONTACT_ID1 = "raw_contact_id1";
+    field public static final String RAW_CONTACT_ID2 = "raw_contact_id2";
+    field public static final String TYPE = "type";
     field public static final int TYPE_AUTOMATIC = 0; // 0x0
     field public static final int TYPE_KEEP_SEPARATE = 2; // 0x2
     field public static final int TYPE_KEEP_TOGETHER = 1; // 0x1
   }
 
-  protected static abstract interface ContactsContract.BaseSyncColumns {
-    field public static final java.lang.String SYNC1 = "sync1";
-    field public static final java.lang.String SYNC2 = "sync2";
-    field public static final java.lang.String SYNC3 = "sync3";
-    field public static final java.lang.String SYNC4 = "sync4";
+  protected static interface ContactsContract.BaseSyncColumns {
+    field public static final String SYNC1 = "sync1";
+    field public static final String SYNC2 = "sync2";
+    field public static final String SYNC3 = "sync3";
+    field public static final String SYNC4 = "sync4";
   }
 
   public static final class ContactsContract.CommonDataKinds {
   }
 
-  public static abstract interface ContactsContract.CommonDataKinds.BaseTypes {
+  public static interface ContactsContract.CommonDataKinds.BaseTypes {
     field public static final int TYPE_CUSTOM = 0; // 0x0
   }
 
@@ -36827,42 +37161,42 @@
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final android.net.Uri CONTENT_URI;
     field public static final android.net.Uri ENTERPRISE_CONTENT_FILTER_URI;
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
   }
 
-  protected static abstract interface ContactsContract.CommonDataKinds.CommonColumns implements android.provider.ContactsContract.CommonDataKinds.BaseTypes {
-    field public static final java.lang.String DATA = "data1";
-    field public static final java.lang.String LABEL = "data3";
-    field public static final java.lang.String TYPE = "data2";
+  protected static interface ContactsContract.CommonDataKinds.CommonColumns extends android.provider.ContactsContract.CommonDataKinds.BaseTypes {
+    field public static final String DATA = "data1";
+    field public static final String LABEL = "data3";
+    field public static final String TYPE = "data2";
   }
 
   public static final class ContactsContract.CommonDataKinds.Contactables implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
     ctor public ContactsContract.CommonDataKinds.Contactables();
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
   }
 
   public static final class ContactsContract.CommonDataKinds.Email implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
-    method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
+    method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
     method public static int getTypeLabelResource(int);
-    field public static final java.lang.String ADDRESS = "data1";
+    field public static final String ADDRESS = "data1";
     field public static final android.net.Uri CONTENT_FILTER_URI;
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email_v2";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email_v2";
     field public static final android.net.Uri CONTENT_LOOKUP_URI;
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/email_v2";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/email_v2";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DISPLAY_NAME = "data4";
+    field public static final String DISPLAY_NAME = "data4";
     field public static final android.net.Uri ENTERPRISE_CONTENT_FILTER_URI;
     field public static final android.net.Uri ENTERPRISE_CONTENT_LOOKUP_URI;
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
     field public static final int TYPE_HOME = 1; // 0x1
     field public static final int TYPE_MOBILE = 4; // 0x4
     field public static final int TYPE_OTHER = 3; // 0x3
@@ -36870,47 +37204,47 @@
   }
 
   public static final class ContactsContract.CommonDataKinds.Event implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
-    method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
-    method public static int getTypeResource(java.lang.Integer);
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_event";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String START_DATE = "data1";
+    method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
+    method public static int getTypeResource(Integer);
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_event";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String START_DATE = "data1";
     field public static final int TYPE_ANNIVERSARY = 1; // 0x1
     field public static final int TYPE_BIRTHDAY = 3; // 0x3
     field public static final int TYPE_OTHER = 2; // 0x2
   }
 
   public static final class ContactsContract.CommonDataKinds.GroupMembership implements android.provider.ContactsContract.DataColumnsWithJoins {
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group_membership";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String GROUP_ROW_ID = "data1";
-    field public static final java.lang.String GROUP_SOURCE_ID = "group_sourceid";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group_membership";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String GROUP_ROW_ID = "data1";
+    field public static final String GROUP_SOURCE_ID = "group_sourceid";
   }
 
   public static final class ContactsContract.CommonDataKinds.Identity implements android.provider.ContactsContract.DataColumnsWithJoins {
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/identity";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String IDENTITY = "data1";
-    field public static final java.lang.String NAMESPACE = "data2";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/identity";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String IDENTITY = "data1";
+    field public static final String NAMESPACE = "data2";
   }
 
   public static final class ContactsContract.CommonDataKinds.Im implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
-    method public static java.lang.CharSequence getProtocolLabel(android.content.res.Resources, int, java.lang.CharSequence);
+    method public static CharSequence getProtocolLabel(android.content.res.Resources, int, CharSequence);
     method public static int getProtocolLabelResource(int);
-    method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
+    method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
     method public static int getTypeLabelResource(int);
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im";
-    field public static final java.lang.String CUSTOM_PROTOCOL = "data6";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String PROTOCOL = "data5";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im";
+    field public static final String CUSTOM_PROTOCOL = "data6";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String PROTOCOL = "data5";
     field public static final int PROTOCOL_AIM = 0; // 0x0
     field public static final int PROTOCOL_CUSTOM = -1; // 0xffffffff
     field public static final int PROTOCOL_GOOGLE_TALK = 5; // 0x5
@@ -36927,61 +37261,61 @@
   }
 
   public static final class ContactsContract.CommonDataKinds.Nickname implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/nickname";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String NAME = "data1";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/nickname";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String NAME = "data1";
     field public static final int TYPE_DEFAULT = 1; // 0x1
     field public static final int TYPE_INITIALS = 5; // 0x5
     field public static final int TYPE_MAIDEN_NAME = 3; // 0x3
-    field public static final deprecated int TYPE_MAINDEN_NAME = 3; // 0x3
+    field @Deprecated public static final int TYPE_MAINDEN_NAME = 3; // 0x3
     field public static final int TYPE_OTHER_NAME = 2; // 0x2
     field public static final int TYPE_SHORT_NAME = 4; // 0x4
   }
 
   public static final class ContactsContract.CommonDataKinds.Note implements android.provider.ContactsContract.DataColumnsWithJoins {
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/note";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String NOTE = "data1";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/note";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String NOTE = "data1";
   }
 
   public static final class ContactsContract.CommonDataKinds.Organization implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
-    method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
+    method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
     method public static int getTypeLabelResource(int);
-    field public static final java.lang.String COMPANY = "data1";
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/organization";
-    field public static final java.lang.String DEPARTMENT = "data5";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String JOB_DESCRIPTION = "data6";
-    field public static final java.lang.String OFFICE_LOCATION = "data9";
-    field public static final java.lang.String PHONETIC_NAME = "data8";
-    field public static final java.lang.String PHONETIC_NAME_STYLE = "data10";
-    field public static final java.lang.String SYMBOL = "data7";
-    field public static final java.lang.String TITLE = "data4";
+    field public static final String COMPANY = "data1";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/organization";
+    field public static final String DEPARTMENT = "data5";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String JOB_DESCRIPTION = "data6";
+    field public static final String OFFICE_LOCATION = "data9";
+    field public static final String PHONETIC_NAME = "data8";
+    field public static final String PHONETIC_NAME_STYLE = "data10";
+    field public static final String SYMBOL = "data7";
+    field public static final String TITLE = "data4";
     field public static final int TYPE_OTHER = 2; // 0x2
     field public static final int TYPE_WORK = 1; // 0x1
   }
 
   public static final class ContactsContract.CommonDataKinds.Phone implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
-    method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
+    method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
     method public static int getTypeLabelResource(int);
     field public static final android.net.Uri CONTENT_FILTER_URI;
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone_v2";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/phone_v2";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone_v2";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone_v2";
     field public static final android.net.Uri CONTENT_URI;
     field public static final android.net.Uri ENTERPRISE_CONTENT_FILTER_URI;
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String NORMALIZED_NUMBER = "data4";
-    field public static final java.lang.String NUMBER = "data1";
-    field public static final java.lang.String SEARCH_DISPLAY_NAME_KEY = "search_display_name";
-    field public static final java.lang.String SEARCH_PHONE_NUMBER_KEY = "search_phone_number";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String NORMALIZED_NUMBER = "data4";
+    field public static final String NUMBER = "data1";
+    field public static final String SEARCH_DISPLAY_NAME_KEY = "search_display_name";
+    field public static final String SEARCH_PHONE_NUMBER_KEY = "search_phone_number";
     field public static final int TYPE_ASSISTANT = 19; // 0x13
     field public static final int TYPE_CALLBACK = 8; // 0x8
     field public static final int TYPE_CAR = 9; // 0x9
@@ -37005,22 +37339,22 @@
   }
 
   public static final class ContactsContract.CommonDataKinds.Photo implements android.provider.ContactsContract.DataColumnsWithJoins {
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String PHOTO = "data15";
-    field public static final java.lang.String PHOTO_FILE_ID = "data14";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String PHOTO = "data15";
+    field public static final String PHOTO_FILE_ID = "data14";
   }
 
   public static final class ContactsContract.CommonDataKinds.Relation implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
-    method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
+    method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
     method public static int getTypeLabelResource(int);
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/relation";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String NAME = "data1";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/relation";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String NAME = "data1";
     field public static final int TYPE_ASSISTANT = 1; // 0x1
     field public static final int TYPE_BROTHER = 2; // 0x2
     field public static final int TYPE_CHILD = 3; // 0x3
@@ -37038,63 +37372,63 @@
   }
 
   public static final class ContactsContract.CommonDataKinds.SipAddress implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
-    method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
+    method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
     method public static int getTypeLabelResource(int);
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sip_address";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String SIP_ADDRESS = "data1";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sip_address";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String SIP_ADDRESS = "data1";
     field public static final int TYPE_HOME = 1; // 0x1
     field public static final int TYPE_OTHER = 3; // 0x3
     field public static final int TYPE_WORK = 2; // 0x2
   }
 
   public static final class ContactsContract.CommonDataKinds.StructuredName implements android.provider.ContactsContract.DataColumnsWithJoins {
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name";
-    field public static final java.lang.String DISPLAY_NAME = "data1";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String FAMILY_NAME = "data3";
-    field public static final java.lang.String FULL_NAME_STYLE = "data10";
-    field public static final java.lang.String GIVEN_NAME = "data2";
-    field public static final java.lang.String MIDDLE_NAME = "data5";
-    field public static final java.lang.String PHONETIC_FAMILY_NAME = "data9";
-    field public static final java.lang.String PHONETIC_GIVEN_NAME = "data7";
-    field public static final java.lang.String PHONETIC_MIDDLE_NAME = "data8";
-    field public static final java.lang.String PHONETIC_NAME_STYLE = "data11";
-    field public static final java.lang.String PREFIX = "data4";
-    field public static final java.lang.String SUFFIX = "data6";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name";
+    field public static final String DISPLAY_NAME = "data1";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String FAMILY_NAME = "data3";
+    field public static final String FULL_NAME_STYLE = "data10";
+    field public static final String GIVEN_NAME = "data2";
+    field public static final String MIDDLE_NAME = "data5";
+    field public static final String PHONETIC_FAMILY_NAME = "data9";
+    field public static final String PHONETIC_GIVEN_NAME = "data7";
+    field public static final String PHONETIC_MIDDLE_NAME = "data8";
+    field public static final String PHONETIC_NAME_STYLE = "data11";
+    field public static final String PREFIX = "data4";
+    field public static final String SUFFIX = "data6";
   }
 
   public static final class ContactsContract.CommonDataKinds.StructuredPostal implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
-    method public static java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
+    method public static CharSequence getTypeLabel(android.content.res.Resources, int, CharSequence);
     method public static int getTypeLabelResource(int);
-    field public static final java.lang.String CITY = "data7";
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/postal-address_v2";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/postal-address_v2";
+    field public static final String CITY = "data7";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/postal-address_v2";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/postal-address_v2";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String COUNTRY = "data10";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String FORMATTED_ADDRESS = "data1";
-    field public static final java.lang.String NEIGHBORHOOD = "data6";
-    field public static final java.lang.String POBOX = "data5";
-    field public static final java.lang.String POSTCODE = "data9";
-    field public static final java.lang.String REGION = "data8";
-    field public static final java.lang.String STREET = "data4";
+    field public static final String COUNTRY = "data10";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String FORMATTED_ADDRESS = "data1";
+    field public static final String NEIGHBORHOOD = "data6";
+    field public static final String POBOX = "data5";
+    field public static final String POSTCODE = "data9";
+    field public static final String REGION = "data8";
+    field public static final String STREET = "data4";
     field public static final int TYPE_HOME = 1; // 0x1
     field public static final int TYPE_OTHER = 3; // 0x3
     field public static final int TYPE_WORK = 2; // 0x2
   }
 
   public static final class ContactsContract.CommonDataKinds.Website implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/website";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/website";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
     field public static final int TYPE_BLOG = 2; // 0x2
     field public static final int TYPE_FTP = 6; // 0x6
     field public static final int TYPE_HOME = 4; // 0x4
@@ -37102,168 +37436,168 @@
     field public static final int TYPE_OTHER = 7; // 0x7
     field public static final int TYPE_PROFILE = 3; // 0x3
     field public static final int TYPE_WORK = 5; // 0x5
-    field public static final java.lang.String URL = "data1";
+    field public static final String URL = "data1";
   }
 
-  protected static abstract interface ContactsContract.ContactNameColumns {
-    field public static final java.lang.String DISPLAY_NAME_ALTERNATIVE = "display_name_alt";
-    field public static final java.lang.String DISPLAY_NAME_PRIMARY = "display_name";
-    field public static final java.lang.String DISPLAY_NAME_SOURCE = "display_name_source";
-    field public static final java.lang.String PHONETIC_NAME = "phonetic_name";
-    field public static final java.lang.String PHONETIC_NAME_STYLE = "phonetic_name_style";
-    field public static final java.lang.String SORT_KEY_ALTERNATIVE = "sort_key_alt";
-    field public static final java.lang.String SORT_KEY_PRIMARY = "sort_key";
+  protected static interface ContactsContract.ContactNameColumns {
+    field public static final String DISPLAY_NAME_ALTERNATIVE = "display_name_alt";
+    field public static final String DISPLAY_NAME_PRIMARY = "display_name";
+    field public static final String DISPLAY_NAME_SOURCE = "display_name_source";
+    field public static final String PHONETIC_NAME = "phonetic_name";
+    field public static final String PHONETIC_NAME_STYLE = "phonetic_name_style";
+    field public static final String SORT_KEY_ALTERNATIVE = "sort_key_alt";
+    field public static final String SORT_KEY_PRIMARY = "sort_key";
   }
 
-  protected static abstract interface ContactsContract.ContactOptionsColumns {
-    field public static final java.lang.String CUSTOM_RINGTONE = "custom_ringtone";
-    field public static final deprecated java.lang.String LAST_TIME_CONTACTED = "last_time_contacted";
-    field public static final java.lang.String PINNED = "pinned";
-    field public static final java.lang.String SEND_TO_VOICEMAIL = "send_to_voicemail";
-    field public static final java.lang.String STARRED = "starred";
-    field public static final deprecated java.lang.String TIMES_CONTACTED = "times_contacted";
+  protected static interface ContactsContract.ContactOptionsColumns {
+    field public static final String CUSTOM_RINGTONE = "custom_ringtone";
+    field @Deprecated public static final String LAST_TIME_CONTACTED = "last_time_contacted";
+    field public static final String PINNED = "pinned";
+    field public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
+    field public static final String STARRED = "starred";
+    field @Deprecated public static final String TIMES_CONTACTED = "times_contacted";
   }
 
-  protected static abstract interface ContactsContract.ContactStatusColumns {
-    field public static final java.lang.String CONTACT_CHAT_CAPABILITY = "contact_chat_capability";
-    field public static final java.lang.String CONTACT_PRESENCE = "contact_presence";
-    field public static final java.lang.String CONTACT_STATUS = "contact_status";
-    field public static final java.lang.String CONTACT_STATUS_ICON = "contact_status_icon";
-    field public static final java.lang.String CONTACT_STATUS_LABEL = "contact_status_label";
-    field public static final java.lang.String CONTACT_STATUS_RES_PACKAGE = "contact_status_res_package";
-    field public static final java.lang.String CONTACT_STATUS_TIMESTAMP = "contact_status_ts";
+  protected static interface ContactsContract.ContactStatusColumns {
+    field public static final String CONTACT_CHAT_CAPABILITY = "contact_chat_capability";
+    field public static final String CONTACT_PRESENCE = "contact_presence";
+    field public static final String CONTACT_STATUS = "contact_status";
+    field public static final String CONTACT_STATUS_ICON = "contact_status_icon";
+    field public static final String CONTACT_STATUS_LABEL = "contact_status_label";
+    field public static final String CONTACT_STATUS_RES_PACKAGE = "contact_status_res_package";
+    field public static final String CONTACT_STATUS_TIMESTAMP = "contact_status_ts";
   }
 
   public static class ContactsContract.Contacts implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns {
     method public static android.net.Uri getLookupUri(android.content.ContentResolver, android.net.Uri);
-    method public static android.net.Uri getLookupUri(long, java.lang.String);
+    method public static android.net.Uri getLookupUri(long, String);
     method public static boolean isEnterpriseContactId(long);
     method public static android.net.Uri lookupContact(android.content.ContentResolver, android.net.Uri);
-    method public static deprecated void markAsContacted(android.content.ContentResolver, long);
+    method @Deprecated public static void markAsContacted(android.content.ContentResolver, long);
     method public static java.io.InputStream openContactPhotoInputStream(android.content.ContentResolver, android.net.Uri, boolean);
     method public static java.io.InputStream openContactPhotoInputStream(android.content.ContentResolver, android.net.Uri);
     field public static final android.net.Uri CONTENT_FILTER_URI;
-    field public static final deprecated android.net.Uri CONTENT_FREQUENT_URI;
+    field @Deprecated public static final android.net.Uri CONTENT_FREQUENT_URI;
     field public static final android.net.Uri CONTENT_GROUP_URI;
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact";
     field public static final android.net.Uri CONTENT_LOOKUP_URI;
     field public static final android.net.Uri CONTENT_MULTI_VCARD_URI;
     field public static final android.net.Uri CONTENT_STREQUENT_FILTER_URI;
     field public static final android.net.Uri CONTENT_STREQUENT_URI;
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contact";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String CONTENT_VCARD_TYPE = "text/x-vcard";
+    field public static final String CONTENT_VCARD_TYPE = "text/x-vcard";
     field public static final android.net.Uri CONTENT_VCARD_URI;
     field public static final android.net.Uri ENTERPRISE_CONTENT_FILTER_URI;
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String QUERY_PARAMETER_VCARD_NO_PHOTO = "no_photo";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String QUERY_PARAMETER_VCARD_NO_PHOTO = "no_photo";
   }
 
   public static final class ContactsContract.Contacts.AggregationSuggestions implements android.provider.BaseColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns {
-    field public static final java.lang.String CONTENT_DIRECTORY = "suggestions";
+    field public static final String CONTENT_DIRECTORY = "suggestions";
   }
 
   public static final class ContactsContract.Contacts.AggregationSuggestions.Builder {
     ctor public ContactsContract.Contacts.AggregationSuggestions.Builder();
-    method public android.provider.ContactsContract.Contacts.AggregationSuggestions.Builder addNameParameter(java.lang.String);
+    method public android.provider.ContactsContract.Contacts.AggregationSuggestions.Builder addNameParameter(String);
     method public android.net.Uri build();
     method public android.provider.ContactsContract.Contacts.AggregationSuggestions.Builder setContactId(long);
     method public android.provider.ContactsContract.Contacts.AggregationSuggestions.Builder setLimit(int);
   }
 
   public static final class ContactsContract.Contacts.Data implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns {
-    field public static final java.lang.String CONTENT_DIRECTORY = "data";
+    field public static final String CONTENT_DIRECTORY = "data";
   }
 
   public static final class ContactsContract.Contacts.Entity implements android.provider.BaseColumns android.provider.ContactsContract.BaseSyncColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.DataUsageStatColumns android.provider.ContactsContract.RawContactsColumns android.provider.ContactsContract.StatusColumns android.provider.ContactsContract.SyncColumns {
-    field public static final java.lang.String CONTENT_DIRECTORY = "entities";
-    field public static final java.lang.String DATA_ID = "data_id";
-    field public static final java.lang.String RAW_CONTACT_ID = "raw_contact_id";
+    field public static final String CONTENT_DIRECTORY = "entities";
+    field public static final String DATA_ID = "data_id";
+    field public static final String RAW_CONTACT_ID = "raw_contact_id";
   }
 
   public static final class ContactsContract.Contacts.Photo implements android.provider.BaseColumns android.provider.ContactsContract.DataColumnsWithJoins {
-    field public static final java.lang.String CONTENT_DIRECTORY = "photo";
-    field public static final java.lang.String DISPLAY_PHOTO = "display_photo";
-    field public static final java.lang.String PHOTO = "data15";
-    field public static final java.lang.String PHOTO_FILE_ID = "data14";
+    field public static final String CONTENT_DIRECTORY = "photo";
+    field public static final String DISPLAY_PHOTO = "display_photo";
+    field public static final String PHOTO = "data15";
+    field public static final String PHOTO_FILE_ID = "data14";
   }
 
-  protected static abstract interface ContactsContract.ContactsColumns {
-    field public static final java.lang.String CONTACT_LAST_UPDATED_TIMESTAMP = "contact_last_updated_timestamp";
-    field public static final java.lang.String DISPLAY_NAME = "display_name";
-    field public static final java.lang.String HAS_PHONE_NUMBER = "has_phone_number";
-    field public static final java.lang.String IN_DEFAULT_DIRECTORY = "in_default_directory";
-    field public static final java.lang.String IN_VISIBLE_GROUP = "in_visible_group";
-    field public static final java.lang.String IS_USER_PROFILE = "is_user_profile";
-    field public static final java.lang.String LOOKUP_KEY = "lookup";
-    field public static final java.lang.String NAME_RAW_CONTACT_ID = "name_raw_contact_id";
-    field public static final java.lang.String PHOTO_FILE_ID = "photo_file_id";
-    field public static final java.lang.String PHOTO_ID = "photo_id";
-    field public static final java.lang.String PHOTO_THUMBNAIL_URI = "photo_thumb_uri";
-    field public static final java.lang.String PHOTO_URI = "photo_uri";
+  protected static interface ContactsContract.ContactsColumns {
+    field public static final String CONTACT_LAST_UPDATED_TIMESTAMP = "contact_last_updated_timestamp";
+    field public static final String DISPLAY_NAME = "display_name";
+    field public static final String HAS_PHONE_NUMBER = "has_phone_number";
+    field public static final String IN_DEFAULT_DIRECTORY = "in_default_directory";
+    field public static final String IN_VISIBLE_GROUP = "in_visible_group";
+    field public static final String IS_USER_PROFILE = "is_user_profile";
+    field public static final String LOOKUP_KEY = "lookup";
+    field public static final String NAME_RAW_CONTACT_ID = "name_raw_contact_id";
+    field public static final String PHOTO_FILE_ID = "photo_file_id";
+    field public static final String PHOTO_ID = "photo_id";
+    field public static final String PHOTO_THUMBNAIL_URI = "photo_thumb_uri";
+    field public static final String PHOTO_URI = "photo_uri";
   }
 
   public static final class ContactsContract.Data implements android.provider.ContactsContract.DataColumnsWithJoins {
     method public static android.net.Uri getContactLookupUri(android.content.ContentResolver, android.net.Uri);
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/data";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/data";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
-    field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
-    field public static final java.lang.String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+    field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+    field public static final String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
   }
 
-  protected static abstract interface ContactsContract.DataColumns {
-    field public static final java.lang.String CARRIER_PRESENCE = "carrier_presence";
+  protected static interface ContactsContract.DataColumns {
+    field public static final String CARRIER_PRESENCE = "carrier_presence";
     field public static final int CARRIER_PRESENCE_VT_CAPABLE = 1; // 0x1
-    field public static final java.lang.String DATA1 = "data1";
-    field public static final java.lang.String DATA10 = "data10";
-    field public static final java.lang.String DATA11 = "data11";
-    field public static final java.lang.String DATA12 = "data12";
-    field public static final java.lang.String DATA13 = "data13";
-    field public static final java.lang.String DATA14 = "data14";
-    field public static final java.lang.String DATA15 = "data15";
-    field public static final java.lang.String DATA2 = "data2";
-    field public static final java.lang.String DATA3 = "data3";
-    field public static final java.lang.String DATA4 = "data4";
-    field public static final java.lang.String DATA5 = "data5";
-    field public static final java.lang.String DATA6 = "data6";
-    field public static final java.lang.String DATA7 = "data7";
-    field public static final java.lang.String DATA8 = "data8";
-    field public static final java.lang.String DATA9 = "data9";
-    field public static final java.lang.String DATA_VERSION = "data_version";
-    field public static final java.lang.String IS_PRIMARY = "is_primary";
-    field public static final java.lang.String IS_READ_ONLY = "is_read_only";
-    field public static final java.lang.String IS_SUPER_PRIMARY = "is_super_primary";
-    field public static final java.lang.String MIMETYPE = "mimetype";
-    field public static final java.lang.String PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME = "preferred_phone_account_component_name";
-    field public static final java.lang.String PREFERRED_PHONE_ACCOUNT_ID = "preferred_phone_account_id";
-    field public static final java.lang.String RAW_CONTACT_ID = "raw_contact_id";
-    field public static final java.lang.String RES_PACKAGE = "res_package";
-    field public static final java.lang.String SYNC1 = "data_sync1";
-    field public static final java.lang.String SYNC2 = "data_sync2";
-    field public static final java.lang.String SYNC3 = "data_sync3";
-    field public static final java.lang.String SYNC4 = "data_sync4";
+    field public static final String DATA1 = "data1";
+    field public static final String DATA10 = "data10";
+    field public static final String DATA11 = "data11";
+    field public static final String DATA12 = "data12";
+    field public static final String DATA13 = "data13";
+    field public static final String DATA14 = "data14";
+    field public static final String DATA15 = "data15";
+    field public static final String DATA2 = "data2";
+    field public static final String DATA3 = "data3";
+    field public static final String DATA4 = "data4";
+    field public static final String DATA5 = "data5";
+    field public static final String DATA6 = "data6";
+    field public static final String DATA7 = "data7";
+    field public static final String DATA8 = "data8";
+    field public static final String DATA9 = "data9";
+    field public static final String DATA_VERSION = "data_version";
+    field public static final String IS_PRIMARY = "is_primary";
+    field public static final String IS_READ_ONLY = "is_read_only";
+    field public static final String IS_SUPER_PRIMARY = "is_super_primary";
+    field public static final String MIMETYPE = "mimetype";
+    field public static final String PREFERRED_PHONE_ACCOUNT_COMPONENT_NAME = "preferred_phone_account_component_name";
+    field public static final String PREFERRED_PHONE_ACCOUNT_ID = "preferred_phone_account_id";
+    field public static final String RAW_CONTACT_ID = "raw_contact_id";
+    field public static final String RES_PACKAGE = "res_package";
+    field public static final String SYNC1 = "data_sync1";
+    field public static final String SYNC2 = "data_sync2";
+    field public static final String SYNC3 = "data_sync3";
+    field public static final String SYNC4 = "data_sync4";
   }
 
-  protected static abstract interface ContactsContract.DataColumnsWithJoins implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.DataUsageStatColumns android.provider.ContactsContract.RawContactsColumns android.provider.ContactsContract.StatusColumns {
+  protected static interface ContactsContract.DataColumnsWithJoins extends android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.DataUsageStatColumns android.provider.ContactsContract.RawContactsColumns android.provider.ContactsContract.StatusColumns {
   }
 
-  public static final deprecated class ContactsContract.DataUsageFeedback {
-    ctor public ContactsContract.DataUsageFeedback();
-    field public static final android.net.Uri DELETE_USAGE_URI;
-    field public static final android.net.Uri FEEDBACK_URI;
-    field public static final java.lang.String USAGE_TYPE = "type";
-    field public static final java.lang.String USAGE_TYPE_CALL = "call";
-    field public static final java.lang.String USAGE_TYPE_LONG_TEXT = "long_text";
-    field public static final java.lang.String USAGE_TYPE_SHORT_TEXT = "short_text";
+  @Deprecated public static final class ContactsContract.DataUsageFeedback {
+    ctor @Deprecated public ContactsContract.DataUsageFeedback();
+    field @Deprecated public static final android.net.Uri DELETE_USAGE_URI;
+    field @Deprecated public static final android.net.Uri FEEDBACK_URI;
+    field @Deprecated public static final String USAGE_TYPE = "type";
+    field @Deprecated public static final String USAGE_TYPE_CALL = "call";
+    field @Deprecated public static final String USAGE_TYPE_LONG_TEXT = "long_text";
+    field @Deprecated public static final String USAGE_TYPE_SHORT_TEXT = "short_text";
   }
 
-  protected static abstract interface ContactsContract.DataUsageStatColumns {
-    field public static final deprecated java.lang.String LAST_TIME_USED = "last_time_used";
-    field public static final deprecated java.lang.String TIMES_USED = "times_used";
+  protected static interface ContactsContract.DataUsageStatColumns {
+    field @Deprecated public static final String LAST_TIME_USED = "last_time_used";
+    field @Deprecated public static final String TIMES_USED = "times_used";
   }
 
   public static final class ContactsContract.DeletedContacts implements android.provider.ContactsContract.DeletedContactsColumns {
@@ -37271,46 +37605,46 @@
     field public static final long DAYS_KEPT_MILLISECONDS = 2592000000L; // 0x9a7ec800L
   }
 
-  protected static abstract interface ContactsContract.DeletedContactsColumns {
-    field public static final java.lang.String CONTACT_DELETED_TIMESTAMP = "contact_deleted_timestamp";
-    field public static final java.lang.String CONTACT_ID = "contact_id";
+  protected static interface ContactsContract.DeletedContactsColumns {
+    field public static final String CONTACT_DELETED_TIMESTAMP = "contact_deleted_timestamp";
+    field public static final String CONTACT_ID = "contact_id";
   }
 
   public static final class ContactsContract.Directory implements android.provider.BaseColumns {
     method public static boolean isEnterpriseDirectoryId(long);
     method public static boolean isRemoteDirectoryId(long);
     method public static void notifyDirectoryChange(android.content.ContentResolver);
-    field public static final java.lang.String ACCOUNT_NAME = "accountName";
-    field public static final java.lang.String ACCOUNT_TYPE = "accountType";
-    field public static final java.lang.String CALLER_PACKAGE_PARAM_KEY = "callerPackage";
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_directory";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contact_directories";
+    field public static final String ACCOUNT_NAME = "accountName";
+    field public static final String ACCOUNT_TYPE = "accountType";
+    field public static final String CALLER_PACKAGE_PARAM_KEY = "callerPackage";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_directory";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_directories";
     field public static final android.net.Uri CONTENT_URI;
     field public static final long DEFAULT = 0L; // 0x0L
-    field public static final java.lang.String DIRECTORY_AUTHORITY = "authority";
-    field public static final java.lang.String DISPLAY_NAME = "displayName";
+    field public static final String DIRECTORY_AUTHORITY = "authority";
+    field public static final String DISPLAY_NAME = "displayName";
     field public static final android.net.Uri ENTERPRISE_CONTENT_URI;
     field public static final long ENTERPRISE_DEFAULT = 1000000000L; // 0x3b9aca00L
     field public static final long ENTERPRISE_LOCAL_INVISIBLE = 1000000001L; // 0x3b9aca01L
-    field public static final java.lang.String EXPORT_SUPPORT = "exportSupport";
+    field public static final String EXPORT_SUPPORT = "exportSupport";
     field public static final int EXPORT_SUPPORT_ANY_ACCOUNT = 2; // 0x2
     field public static final int EXPORT_SUPPORT_NONE = 0; // 0x0
     field public static final int EXPORT_SUPPORT_SAME_ACCOUNT_ONLY = 1; // 0x1
     field public static final long LOCAL_INVISIBLE = 1L; // 0x1L
-    field public static final java.lang.String PACKAGE_NAME = "packageName";
-    field public static final java.lang.String PHOTO_SUPPORT = "photoSupport";
+    field public static final String PACKAGE_NAME = "packageName";
+    field public static final String PHOTO_SUPPORT = "photoSupport";
     field public static final int PHOTO_SUPPORT_FULL = 3; // 0x3
     field public static final int PHOTO_SUPPORT_FULL_SIZE_ONLY = 2; // 0x2
     field public static final int PHOTO_SUPPORT_NONE = 0; // 0x0
     field public static final int PHOTO_SUPPORT_THUMBNAIL_ONLY = 1; // 0x1
-    field public static final java.lang.String SHORTCUT_SUPPORT = "shortcutSupport";
+    field public static final String SHORTCUT_SUPPORT = "shortcutSupport";
     field public static final int SHORTCUT_SUPPORT_DATA_ITEMS_ONLY = 1; // 0x1
     field public static final int SHORTCUT_SUPPORT_FULL = 2; // 0x2
     field public static final int SHORTCUT_SUPPORT_NONE = 0; // 0x0
-    field public static final java.lang.String TYPE_RESOURCE_ID = "typeResourceId";
+    field public static final String TYPE_RESOURCE_ID = "typeResourceId";
   }
 
-  public static abstract interface ContactsContract.DisplayNameSources {
+  public static interface ContactsContract.DisplayNameSources {
     field public static final int EMAIL = 10; // 0xa
     field public static final int NICKNAME = 35; // 0x23
     field public static final int ORGANIZATION = 30; // 0x1e
@@ -37323,11 +37657,11 @@
   public static final class ContactsContract.DisplayPhoto {
     field public static final android.net.Uri CONTENT_MAX_DIMENSIONS_URI;
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DISPLAY_MAX_DIM = "display_max_dim";
-    field public static final java.lang.String THUMBNAIL_MAX_DIM = "thumbnail_max_dim";
+    field public static final String DISPLAY_MAX_DIM = "display_max_dim";
+    field public static final String THUMBNAIL_MAX_DIM = "thumbnail_max_dim";
   }
 
-  public static abstract interface ContactsContract.FullNameStyle {
+  public static interface ContactsContract.FullNameStyle {
     field public static final int CHINESE = 3; // 0x3
     field public static final int CJK = 2; // 0x2
     field public static final int JAPANESE = 4; // 0x4
@@ -37338,98 +37672,98 @@
 
   public static final class ContactsContract.Groups implements android.provider.BaseColumns android.provider.ContactsContract.GroupsColumns android.provider.ContactsContract.SyncColumns {
     method public static android.content.EntityIterator newEntityIterator(android.database.Cursor);
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group";
     field public static final android.net.Uri CONTENT_SUMMARY_URI;
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/group";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/group";
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  protected static abstract interface ContactsContract.GroupsColumns {
-    field public static final java.lang.String AUTO_ADD = "auto_add";
-    field public static final java.lang.String DATA_SET = "data_set";
-    field public static final java.lang.String DELETED = "deleted";
-    field public static final java.lang.String FAVORITES = "favorites";
-    field public static final java.lang.String GROUP_IS_READ_ONLY = "group_is_read_only";
-    field public static final java.lang.String GROUP_VISIBLE = "group_visible";
-    field public static final java.lang.String NOTES = "notes";
-    field public static final java.lang.String RES_PACKAGE = "res_package";
-    field public static final java.lang.String SHOULD_SYNC = "should_sync";
-    field public static final java.lang.String SUMMARY_COUNT = "summ_count";
-    field public static final java.lang.String SUMMARY_WITH_PHONES = "summ_phones";
-    field public static final java.lang.String SYSTEM_ID = "system_id";
-    field public static final java.lang.String TITLE = "title";
-    field public static final java.lang.String TITLE_RES = "title_res";
+  protected static interface ContactsContract.GroupsColumns {
+    field public static final String AUTO_ADD = "auto_add";
+    field public static final String DATA_SET = "data_set";
+    field public static final String DELETED = "deleted";
+    field public static final String FAVORITES = "favorites";
+    field public static final String GROUP_IS_READ_ONLY = "group_is_read_only";
+    field public static final String GROUP_VISIBLE = "group_visible";
+    field public static final String NOTES = "notes";
+    field public static final String RES_PACKAGE = "res_package";
+    field public static final String SHOULD_SYNC = "should_sync";
+    field public static final String SUMMARY_COUNT = "summ_count";
+    field public static final String SUMMARY_WITH_PHONES = "summ_phones";
+    field public static final String SYSTEM_ID = "system_id";
+    field public static final String TITLE = "title";
+    field public static final String TITLE_RES = "title_res";
   }
 
   public static final class ContactsContract.Intents {
     ctor public ContactsContract.Intents();
-    field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
-    field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
-    field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
-    field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
-    field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
-    field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
-    field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_NAME = "android.provider.extra.RECIPIENT_CONTACT_NAME";
-    field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_URI = "android.provider.extra.RECIPIENT_CONTACT_URI";
-    field public static final java.lang.String INVITE_CONTACT = "com.android.contacts.action.INVITE_CONTACT";
-    field public static final java.lang.String METADATA_ACCOUNT_TYPE = "android.provider.account_type";
-    field public static final java.lang.String METADATA_MIMETYPE = "android.provider.mimetype";
-    field public static final java.lang.String SEARCH_SUGGESTION_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
-    field public static final java.lang.String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
-    field public static final java.lang.String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
-    field public static final java.lang.String SHOW_OR_CREATE_CONTACT = "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
+    field public static final String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
+    field public static final String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
+    field public static final String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
+    field public static final String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
+    field public static final String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
+    field public static final String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
+    field public static final String EXTRA_RECIPIENT_CONTACT_NAME = "android.provider.extra.RECIPIENT_CONTACT_NAME";
+    field public static final String EXTRA_RECIPIENT_CONTACT_URI = "android.provider.extra.RECIPIENT_CONTACT_URI";
+    field public static final String INVITE_CONTACT = "com.android.contacts.action.INVITE_CONTACT";
+    field public static final String METADATA_ACCOUNT_TYPE = "android.provider.account_type";
+    field public static final String METADATA_MIMETYPE = "android.provider.mimetype";
+    field public static final String SEARCH_SUGGESTION_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
+    field public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
+    field public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED = "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
+    field public static final String SHOW_OR_CREATE_CONTACT = "com.android.contacts.action.SHOW_OR_CREATE_CONTACT";
   }
 
   public static final class ContactsContract.Intents.Insert {
     ctor public ContactsContract.Intents.Insert();
-    field public static final java.lang.String ACTION = "android.intent.action.INSERT";
-    field public static final java.lang.String COMPANY = "company";
-    field public static final java.lang.String DATA = "data";
-    field public static final java.lang.String EMAIL = "email";
-    field public static final java.lang.String EMAIL_ISPRIMARY = "email_isprimary";
-    field public static final java.lang.String EMAIL_TYPE = "email_type";
-    field public static final java.lang.String EXTRA_ACCOUNT = "android.provider.extra.ACCOUNT";
-    field public static final java.lang.String EXTRA_DATA_SET = "android.provider.extra.DATA_SET";
-    field public static final java.lang.String FULL_MODE = "full_mode";
-    field public static final java.lang.String IM_HANDLE = "im_handle";
-    field public static final java.lang.String IM_ISPRIMARY = "im_isprimary";
-    field public static final java.lang.String IM_PROTOCOL = "im_protocol";
-    field public static final java.lang.String JOB_TITLE = "job_title";
-    field public static final java.lang.String NAME = "name";
-    field public static final java.lang.String NOTES = "notes";
-    field public static final java.lang.String PHONE = "phone";
-    field public static final java.lang.String PHONETIC_NAME = "phonetic_name";
-    field public static final java.lang.String PHONE_ISPRIMARY = "phone_isprimary";
-    field public static final java.lang.String PHONE_TYPE = "phone_type";
-    field public static final java.lang.String POSTAL = "postal";
-    field public static final java.lang.String POSTAL_ISPRIMARY = "postal_isprimary";
-    field public static final java.lang.String POSTAL_TYPE = "postal_type";
-    field public static final java.lang.String SECONDARY_EMAIL = "secondary_email";
-    field public static final java.lang.String SECONDARY_EMAIL_TYPE = "secondary_email_type";
-    field public static final java.lang.String SECONDARY_PHONE = "secondary_phone";
-    field public static final java.lang.String SECONDARY_PHONE_TYPE = "secondary_phone_type";
-    field public static final java.lang.String TERTIARY_EMAIL = "tertiary_email";
-    field public static final java.lang.String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
-    field public static final java.lang.String TERTIARY_PHONE = "tertiary_phone";
-    field public static final java.lang.String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
+    field public static final String ACTION = "android.intent.action.INSERT";
+    field public static final String COMPANY = "company";
+    field public static final String DATA = "data";
+    field public static final String EMAIL = "email";
+    field public static final String EMAIL_ISPRIMARY = "email_isprimary";
+    field public static final String EMAIL_TYPE = "email_type";
+    field public static final String EXTRA_ACCOUNT = "android.provider.extra.ACCOUNT";
+    field public static final String EXTRA_DATA_SET = "android.provider.extra.DATA_SET";
+    field public static final String FULL_MODE = "full_mode";
+    field public static final String IM_HANDLE = "im_handle";
+    field public static final String IM_ISPRIMARY = "im_isprimary";
+    field public static final String IM_PROTOCOL = "im_protocol";
+    field public static final String JOB_TITLE = "job_title";
+    field public static final String NAME = "name";
+    field public static final String NOTES = "notes";
+    field public static final String PHONE = "phone";
+    field public static final String PHONETIC_NAME = "phonetic_name";
+    field public static final String PHONE_ISPRIMARY = "phone_isprimary";
+    field public static final String PHONE_TYPE = "phone_type";
+    field public static final String POSTAL = "postal";
+    field public static final String POSTAL_ISPRIMARY = "postal_isprimary";
+    field public static final String POSTAL_TYPE = "postal_type";
+    field public static final String SECONDARY_EMAIL = "secondary_email";
+    field public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
+    field public static final String SECONDARY_PHONE = "secondary_phone";
+    field public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
+    field public static final String TERTIARY_EMAIL = "tertiary_email";
+    field public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
+    field public static final String TERTIARY_PHONE = "tertiary_phone";
+    field public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
   }
 
   public static final class ContactsContract.PhoneLookup implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.PhoneLookupColumns {
     field public static final android.net.Uri CONTENT_FILTER_URI;
     field public static final android.net.Uri ENTERPRISE_CONTENT_FILTER_URI;
-    field public static final java.lang.String QUERY_PARAMETER_SIP_ADDRESS = "sip";
+    field public static final String QUERY_PARAMETER_SIP_ADDRESS = "sip";
   }
 
-  protected static abstract interface ContactsContract.PhoneLookupColumns {
-    field public static final java.lang.String CONTACT_ID = "contact_id";
-    field public static final java.lang.String DATA_ID = "data_id";
-    field public static final java.lang.String LABEL = "label";
-    field public static final java.lang.String NORMALIZED_NUMBER = "normalized_number";
-    field public static final java.lang.String NUMBER = "number";
-    field public static final java.lang.String TYPE = "type";
+  protected static interface ContactsContract.PhoneLookupColumns {
+    field public static final String CONTACT_ID = "contact_id";
+    field public static final String DATA_ID = "data_id";
+    field public static final String LABEL = "label";
+    field public static final String NORMALIZED_NUMBER = "normalized_number";
+    field public static final String NUMBER = "number";
+    field public static final String TYPE = "type";
   }
 
-  public static abstract interface ContactsContract.PhoneticNameStyle {
+  public static interface ContactsContract.PhoneticNameStyle {
     field public static final int JAPANESE = 4; // 0x4
     field public static final int KOREAN = 5; // 0x5
     field public static final int PINYIN = 3; // 0x3
@@ -37444,16 +37778,16 @@
     field public static final int UNPINNED = 0; // 0x0
   }
 
-  public static final deprecated class ContactsContract.Presence extends android.provider.ContactsContract.StatusUpdates {
-    ctor public ContactsContract.Presence();
+  @Deprecated public static final class ContactsContract.Presence extends android.provider.ContactsContract.StatusUpdates {
+    ctor @Deprecated public ContactsContract.Presence();
   }
 
-  protected static abstract interface ContactsContract.PresenceColumns {
-    field public static final java.lang.String CUSTOM_PROTOCOL = "custom_protocol";
-    field public static final java.lang.String DATA_ID = "presence_data_id";
-    field public static final java.lang.String IM_ACCOUNT = "im_account";
-    field public static final java.lang.String IM_HANDLE = "im_handle";
-    field public static final java.lang.String PROTOCOL = "protocol";
+  protected static interface ContactsContract.PresenceColumns {
+    field public static final String CUSTOM_PROTOCOL = "custom_protocol";
+    field public static final String DATA_ID = "presence_data_id";
+    field public static final String IM_ACCOUNT = "im_account";
+    field public static final String IM_HANDLE = "im_handle";
+    field public static final String PROTOCOL = "protocol";
   }
 
   public static final class ContactsContract.Profile implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns {
@@ -37465,18 +37799,18 @@
 
   public static final class ContactsContract.ProfileSyncState implements android.provider.SyncStateContract.Columns {
     method public static byte[] get(android.content.ContentProviderClient, android.accounts.Account) throws android.os.RemoteException;
-    method public static android.util.Pair<android.net.Uri, byte[]> getWithUri(android.content.ContentProviderClient, android.accounts.Account) throws android.os.RemoteException;
+    method public static android.util.Pair<android.net.Uri,byte[]> getWithUri(android.content.ContentProviderClient, android.accounts.Account) throws android.os.RemoteException;
     method public static android.content.ContentProviderOperation newSetOperation(android.accounts.Account, byte[]);
     method public static void set(android.content.ContentProviderClient, android.accounts.Account, byte[]) throws android.os.RemoteException;
-    field public static final java.lang.String CONTENT_DIRECTORY = "syncstate";
+    field public static final String CONTENT_DIRECTORY = "syncstate";
     field public static final android.net.Uri CONTENT_URI;
   }
 
   public static final class ContactsContract.ProviderStatus {
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
-    field public static final java.lang.String STATUS = "status";
+    field public static final String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
+    field public static final String STATUS = "status";
     field public static final int STATUS_BUSY = 1; // 0x1
     field public static final int STATUS_EMPTY = 2; // 0x2
     field public static final int STATUS_NORMAL = 0; // 0x0
@@ -37484,14 +37818,14 @@
 
   public static final class ContactsContract.QuickContact {
     ctor public ContactsContract.QuickContact();
-    method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, int, java.lang.String[]);
-    method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, int, java.lang.String[]);
-    method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, java.lang.String[], java.lang.String);
-    method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, java.lang.String[], java.lang.String);
-    field public static final java.lang.String ACTION_QUICK_CONTACT = "android.provider.action.QUICK_CONTACT";
-    field public static final java.lang.String EXTRA_EXCLUDE_MIMES = "android.provider.extra.EXCLUDE_MIMES";
-    field public static final java.lang.String EXTRA_MODE = "android.provider.extra.MODE";
-    field public static final java.lang.String EXTRA_PRIORITIZED_MIMETYPE = "android.provider.extra.PRIORITIZED_MIMETYPE";
+    method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, int, String[]);
+    method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, int, String[]);
+    method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, String[], String);
+    method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, String[], String);
+    field public static final String ACTION_QUICK_CONTACT = "android.provider.action.QUICK_CONTACT";
+    field public static final String EXTRA_EXCLUDE_MIMES = "android.provider.extra.EXCLUDE_MIMES";
+    field public static final String EXTRA_MODE = "android.provider.extra.MODE";
+    field public static final String EXTRA_PRIORITIZED_MIMETYPE = "android.provider.extra.PRIORITIZED_MIMETYPE";
     field public static final int MODE_LARGE = 3; // 0x3
     field public static final int MODE_MEDIUM = 2; // 0x2
     field public static final int MODE_SMALL = 1; // 0x1
@@ -37502,186 +37836,186 @@
     method public static android.content.EntityIterator newEntityIterator(android.database.Cursor);
     field public static final int AGGREGATION_MODE_DEFAULT = 0; // 0x0
     field public static final int AGGREGATION_MODE_DISABLED = 3; // 0x3
-    field public static final deprecated int AGGREGATION_MODE_IMMEDIATE = 1; // 0x1
+    field @Deprecated public static final int AGGREGATION_MODE_IMMEDIATE = 1; // 0x1
     field public static final int AGGREGATION_MODE_SUSPENDED = 2; // 0x2
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/raw_contact";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/raw_contact";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact";
     field public static final android.net.Uri CONTENT_URI;
   }
 
   public static final class ContactsContract.RawContacts.Data implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns {
-    field public static final java.lang.String CONTENT_DIRECTORY = "data";
+    field public static final String CONTENT_DIRECTORY = "data";
   }
 
   public static final class ContactsContract.RawContacts.DisplayPhoto {
-    field public static final java.lang.String CONTENT_DIRECTORY = "display_photo";
+    field public static final String CONTENT_DIRECTORY = "display_photo";
   }
 
   public static final class ContactsContract.RawContacts.Entity implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns {
-    field public static final java.lang.String CONTENT_DIRECTORY = "entity";
-    field public static final java.lang.String DATA_ID = "data_id";
+    field public static final String CONTENT_DIRECTORY = "entity";
+    field public static final String DATA_ID = "data_id";
   }
 
-  protected static abstract interface ContactsContract.RawContactsColumns {
-    field public static final java.lang.String ACCOUNT_TYPE_AND_DATA_SET = "account_type_and_data_set";
-    field public static final java.lang.String AGGREGATION_MODE = "aggregation_mode";
-    field public static final java.lang.String BACKUP_ID = "backup_id";
-    field public static final java.lang.String CONTACT_ID = "contact_id";
-    field public static final java.lang.String DATA_SET = "data_set";
-    field public static final java.lang.String DELETED = "deleted";
-    field public static final java.lang.String METADATA_DIRTY = "metadata_dirty";
-    field public static final java.lang.String RAW_CONTACT_IS_READ_ONLY = "raw_contact_is_read_only";
-    field public static final java.lang.String RAW_CONTACT_IS_USER_PROFILE = "raw_contact_is_user_profile";
+  protected static interface ContactsContract.RawContactsColumns {
+    field public static final String ACCOUNT_TYPE_AND_DATA_SET = "account_type_and_data_set";
+    field public static final String AGGREGATION_MODE = "aggregation_mode";
+    field public static final String BACKUP_ID = "backup_id";
+    field public static final String CONTACT_ID = "contact_id";
+    field public static final String DATA_SET = "data_set";
+    field public static final String DELETED = "deleted";
+    field public static final String METADATA_DIRTY = "metadata_dirty";
+    field public static final String RAW_CONTACT_IS_READ_ONLY = "raw_contact_is_read_only";
+    field public static final String RAW_CONTACT_IS_USER_PROFILE = "raw_contact_is_user_profile";
   }
 
   public static final class ContactsContract.RawContactsEntity implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.RawContactsColumns {
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact_entity";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact_entity";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DATA_ID = "data_id";
+    field public static final String DATA_ID = "data_id";
     field public static final android.net.Uri PROFILE_CONTENT_URI;
   }
 
   public static class ContactsContract.SearchSnippets {
     ctor public ContactsContract.SearchSnippets();
-    field public static final java.lang.String DEFERRED_SNIPPETING_KEY = "deferred_snippeting";
-    field public static final java.lang.String SNIPPET = "snippet";
+    field public static final String DEFERRED_SNIPPETING_KEY = "deferred_snippeting";
+    field public static final String SNIPPET = "snippet";
   }
 
   public static final class ContactsContract.Settings implements android.provider.ContactsContract.SettingsColumns {
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/setting";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/setting";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/setting";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/setting";
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  protected static abstract interface ContactsContract.SettingsColumns {
-    field public static final java.lang.String ACCOUNT_NAME = "account_name";
-    field public static final java.lang.String ACCOUNT_TYPE = "account_type";
-    field public static final java.lang.String ANY_UNSYNCED = "any_unsynced";
-    field public static final java.lang.String DATA_SET = "data_set";
-    field public static final java.lang.String SHOULD_SYNC = "should_sync";
-    field public static final java.lang.String UNGROUPED_COUNT = "summ_count";
-    field public static final java.lang.String UNGROUPED_VISIBLE = "ungrouped_visible";
-    field public static final java.lang.String UNGROUPED_WITH_PHONES = "summ_phones";
+  protected static interface ContactsContract.SettingsColumns {
+    field public static final String ACCOUNT_NAME = "account_name";
+    field public static final String ACCOUNT_TYPE = "account_type";
+    field public static final String ANY_UNSYNCED = "any_unsynced";
+    field public static final String DATA_SET = "data_set";
+    field public static final String SHOULD_SYNC = "should_sync";
+    field public static final String UNGROUPED_COUNT = "summ_count";
+    field public static final String UNGROUPED_VISIBLE = "ungrouped_visible";
+    field public static final String UNGROUPED_WITH_PHONES = "summ_phones";
   }
 
-  protected static abstract interface ContactsContract.StatusColumns {
+  protected static interface ContactsContract.StatusColumns {
     field public static final int AVAILABLE = 5; // 0x5
     field public static final int AWAY = 2; // 0x2
     field public static final int CAPABILITY_HAS_CAMERA = 4; // 0x4
     field public static final int CAPABILITY_HAS_VIDEO = 2; // 0x2
     field public static final int CAPABILITY_HAS_VOICE = 1; // 0x1
-    field public static final java.lang.String CHAT_CAPABILITY = "chat_capability";
+    field public static final String CHAT_CAPABILITY = "chat_capability";
     field public static final int DO_NOT_DISTURB = 4; // 0x4
     field public static final int IDLE = 3; // 0x3
     field public static final int INVISIBLE = 1; // 0x1
     field public static final int OFFLINE = 0; // 0x0
-    field public static final java.lang.String PRESENCE = "mode";
-    field public static final deprecated java.lang.String PRESENCE_CUSTOM_STATUS = "status";
-    field public static final deprecated java.lang.String PRESENCE_STATUS = "mode";
-    field public static final java.lang.String STATUS = "status";
-    field public static final java.lang.String STATUS_ICON = "status_icon";
-    field public static final java.lang.String STATUS_LABEL = "status_label";
-    field public static final java.lang.String STATUS_RES_PACKAGE = "status_res_package";
-    field public static final java.lang.String STATUS_TIMESTAMP = "status_ts";
+    field public static final String PRESENCE = "mode";
+    field @Deprecated public static final String PRESENCE_CUSTOM_STATUS = "status";
+    field @Deprecated public static final String PRESENCE_STATUS = "mode";
+    field public static final String STATUS = "status";
+    field public static final String STATUS_ICON = "status_icon";
+    field public static final String STATUS_LABEL = "status_label";
+    field public static final String STATUS_RES_PACKAGE = "status_res_package";
+    field public static final String STATUS_TIMESTAMP = "status_ts";
   }
 
   public static class ContactsContract.StatusUpdates implements android.provider.ContactsContract.PresenceColumns android.provider.ContactsContract.StatusColumns {
     method public static final int getPresenceIconResourceId(int);
     method public static final int getPresencePrecedence(int);
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/status-update";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/status-update";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/status-update";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/status-update";
     field public static final android.net.Uri CONTENT_URI;
     field public static final android.net.Uri PROFILE_CONTENT_URI;
   }
 
-  protected static abstract interface ContactsContract.SyncColumns implements android.provider.ContactsContract.BaseSyncColumns {
-    field public static final java.lang.String ACCOUNT_NAME = "account_name";
-    field public static final java.lang.String ACCOUNT_TYPE = "account_type";
-    field public static final java.lang.String DIRTY = "dirty";
-    field public static final java.lang.String SOURCE_ID = "sourceid";
-    field public static final java.lang.String VERSION = "version";
+  protected static interface ContactsContract.SyncColumns extends android.provider.ContactsContract.BaseSyncColumns {
+    field public static final String ACCOUNT_NAME = "account_name";
+    field public static final String ACCOUNT_TYPE = "account_type";
+    field public static final String DIRTY = "dirty";
+    field public static final String SOURCE_ID = "sourceid";
+    field public static final String VERSION = "version";
   }
 
   public static final class ContactsContract.SyncState implements android.provider.SyncStateContract.Columns {
     method public static byte[] get(android.content.ContentProviderClient, android.accounts.Account) throws android.os.RemoteException;
-    method public static android.util.Pair<android.net.Uri, byte[]> getWithUri(android.content.ContentProviderClient, android.accounts.Account) throws android.os.RemoteException;
+    method public static android.util.Pair<android.net.Uri,byte[]> getWithUri(android.content.ContentProviderClient, android.accounts.Account) throws android.os.RemoteException;
     method public static android.content.ContentProviderOperation newSetOperation(android.accounts.Account, byte[]);
     method public static void set(android.content.ContentProviderClient, android.accounts.Account, byte[]) throws android.os.RemoteException;
-    field public static final java.lang.String CONTENT_DIRECTORY = "syncstate";
+    field public static final String CONTENT_DIRECTORY = "syncstate";
     field public static final android.net.Uri CONTENT_URI;
   }
 
   public final class DocumentsContract {
-    method public static android.net.Uri buildChildDocumentsUri(java.lang.String, java.lang.String);
-    method public static android.net.Uri buildChildDocumentsUriUsingTree(android.net.Uri, java.lang.String);
-    method public static android.net.Uri buildDocumentUri(java.lang.String, java.lang.String);
-    method public static android.net.Uri buildDocumentUriUsingTree(android.net.Uri, java.lang.String);
-    method public static android.net.Uri buildRecentDocumentsUri(java.lang.String, java.lang.String);
-    method public static android.net.Uri buildRootUri(java.lang.String, java.lang.String);
-    method public static android.net.Uri buildRootsUri(java.lang.String);
-    method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
-    method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
+    method public static android.net.Uri buildChildDocumentsUri(String, String);
+    method public static android.net.Uri buildChildDocumentsUriUsingTree(android.net.Uri, String);
+    method public static android.net.Uri buildDocumentUri(String, String);
+    method public static android.net.Uri buildDocumentUriUsingTree(android.net.Uri, String);
+    method public static android.net.Uri buildRecentDocumentsUri(String, String);
+    method public static android.net.Uri buildRootUri(String, String);
+    method public static android.net.Uri buildRootsUri(String);
+    method public static android.net.Uri buildSearchDocumentsUri(String, String, String);
+    method public static android.net.Uri buildTreeDocumentUri(String, String);
     method public static android.net.Uri copyDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static deprecated android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static android.net.Uri createDocument(android.content.ContentInterface, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
-    method public static deprecated android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+    method @Deprecated public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+    method public static android.net.Uri createDocument(android.content.ContentInterface, android.net.Uri, String, String) throws java.io.FileNotFoundException;
+    method @Deprecated public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, String, String) throws java.io.FileNotFoundException;
     method public static android.content.IntentSender createWebLinkIntent(android.content.ContentInterface, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
-    method public static deprecated android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
+    method @Deprecated public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
     method public static boolean deleteDocument(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static deprecated boolean deleteDocument(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
+    method @Deprecated public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
     method public static void ejectRoot(android.content.ContentInterface, android.net.Uri);
-    method public static deprecated void ejectRoot(android.content.ContentResolver, android.net.Uri);
+    method @Deprecated public static void ejectRoot(android.content.ContentResolver, android.net.Uri);
     method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static deprecated android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static java.lang.String getDocumentId(android.net.Uri);
-    method public static android.os.Bundle getDocumentMetadata(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static deprecated android.os.Bundle getDocumentMetadata(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
+    method @Deprecated public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
+    method public static String getDocumentId(android.net.Uri);
+    method @Nullable public static android.os.Bundle getDocumentMetadata(@NonNull android.content.ContentInterface, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
+    method @Deprecated public static android.os.Bundle getDocumentMetadata(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
     method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentInterface, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public static deprecated android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public static java.lang.String getRootId(android.net.Uri);
-    method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
-    method public static java.lang.String getTreeDocumentId(android.net.Uri);
-    method public static boolean isChildDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static deprecated boolean isChildDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
-    method public static boolean isRootUri(android.content.Context, android.net.Uri);
-    method public static boolean isRootsUri(android.content.Context, android.net.Uri);
+    method @Deprecated public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method public static String getRootId(android.net.Uri);
+    method public static String getSearchDocumentsQuery(android.net.Uri);
+    method public static String getTreeDocumentId(android.net.Uri);
+    method public static boolean isChildDocument(@NonNull android.content.ContentInterface, @NonNull android.net.Uri, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
+    method @Deprecated public static boolean isChildDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+    method public static boolean isDocumentUri(android.content.Context, @Nullable android.net.Uri);
+    method public static boolean isRootUri(@NonNull android.content.Context, @Nullable android.net.Uri);
+    method public static boolean isRootsUri(@NonNull android.content.Context, @Nullable android.net.Uri);
     method public static boolean isTreeUri(android.net.Uri);
     method public static android.net.Uri moveDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static deprecated android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+    method @Deprecated public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
     method public static boolean removeDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static deprecated boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
-    method public static android.net.Uri renameDocument(android.content.ContentInterface, android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
-    method public static deprecated android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
-    field public static final java.lang.String ACTION_DOCUMENT_SETTINGS = "android.provider.action.DOCUMENT_SETTINGS";
-    field public static final java.lang.String EXTRA_ERROR = "error";
-    field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
-    field public static final java.lang.String EXTRA_INFO = "info";
-    field public static final java.lang.String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI";
-    field public static final java.lang.String EXTRA_LOADING = "loading";
-    field public static final java.lang.String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
-    field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT";
-    field public static final java.lang.String METADATA_EXIF = "android:documentExif";
-    field public static final java.lang.String METADATA_TREE_COUNT = "android:metadataTreeCount";
-    field public static final java.lang.String METADATA_TREE_SIZE = "android:metadataTreeSize";
-    field public static final java.lang.String METADATA_TYPES = "android:documentMetadataTypes";
-    field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
-    field public static final java.lang.String QUERY_ARG_DISPLAY_NAME = "android:query-arg-display-name";
-    field public static final java.lang.String QUERY_ARG_EXCLUDE_MEDIA = "android:query-arg-exclude-media";
-    field public static final java.lang.String QUERY_ARG_FILE_SIZE_OVER = "android:query-arg-file-size-over";
-    field public static final java.lang.String QUERY_ARG_LAST_MODIFIED_AFTER = "android:query-arg-last-modified-after";
-    field public static final java.lang.String QUERY_ARG_MIME_TYPES = "android:query-arg-mime-types";
+    method @Deprecated public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+    method public static android.net.Uri renameDocument(android.content.ContentInterface, android.net.Uri, String) throws java.io.FileNotFoundException;
+    method @Deprecated public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, String) throws java.io.FileNotFoundException;
+    field public static final String ACTION_DOCUMENT_SETTINGS = "android.provider.action.DOCUMENT_SETTINGS";
+    field public static final String EXTRA_ERROR = "error";
+    field public static final String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
+    field public static final String EXTRA_INFO = "info";
+    field public static final String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI";
+    field public static final String EXTRA_LOADING = "loading";
+    field public static final String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
+    field public static final String EXTRA_PROMPT = "android.provider.extra.PROMPT";
+    field public static final String METADATA_EXIF = "android:documentExif";
+    field public static final String METADATA_TREE_COUNT = "android:metadataTreeCount";
+    field public static final String METADATA_TREE_SIZE = "android:metadataTreeSize";
+    field public static final String METADATA_TYPES = "android:documentMetadataTypes";
+    field public static final String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
+    field public static final String QUERY_ARG_DISPLAY_NAME = "android:query-arg-display-name";
+    field public static final String QUERY_ARG_EXCLUDE_MEDIA = "android:query-arg-exclude-media";
+    field public static final String QUERY_ARG_FILE_SIZE_OVER = "android:query-arg-file-size-over";
+    field public static final String QUERY_ARG_LAST_MODIFIED_AFTER = "android:query-arg-last-modified-after";
+    field public static final String QUERY_ARG_MIME_TYPES = "android:query-arg-mime-types";
   }
 
   public static final class DocumentsContract.Document {
-    field public static final java.lang.String COLUMN_DISPLAY_NAME = "_display_name";
-    field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
-    field public static final java.lang.String COLUMN_FLAGS = "flags";
-    field public static final java.lang.String COLUMN_ICON = "icon";
-    field public static final java.lang.String COLUMN_LAST_MODIFIED = "last_modified";
-    field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
-    field public static final java.lang.String COLUMN_SIZE = "_size";
-    field public static final java.lang.String COLUMN_SUMMARY = "summary";
+    field public static final String COLUMN_DISPLAY_NAME = "_display_name";
+    field public static final String COLUMN_DOCUMENT_ID = "document_id";
+    field public static final String COLUMN_FLAGS = "flags";
+    field public static final String COLUMN_ICON = "icon";
+    field public static final String COLUMN_LAST_MODIFIED = "last_modified";
+    field public static final String COLUMN_MIME_TYPE = "mime_type";
+    field public static final String COLUMN_SIZE = "_size";
+    field public static final String COLUMN_SUMMARY = "summary";
     field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10
     field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20
     field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
@@ -37697,28 +38031,29 @@
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
     field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
     field public static final int FLAG_WEB_LINKABLE = 4096; // 0x1000
-    field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
+    field public static final String MIME_TYPE_DIR = "vnd.android.document/directory";
   }
 
   public static final class DocumentsContract.Path implements android.os.Parcelable {
-    ctor public DocumentsContract.Path(java.lang.String, java.util.List<java.lang.String>);
+    ctor public DocumentsContract.Path(@Nullable String, java.util.List<java.lang.String>);
     method public int describeContents();
     method public java.util.List<java.lang.String> getPath();
-    method public java.lang.String getRootId();
+    method @Nullable public String getRootId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.provider.DocumentsContract.Path> CREATOR;
   }
 
   public static final class DocumentsContract.Root {
-    field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
-    field public static final java.lang.String COLUMN_CAPACITY_BYTES = "capacity_bytes";
-    field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
-    field public static final java.lang.String COLUMN_FLAGS = "flags";
-    field public static final java.lang.String COLUMN_ICON = "icon";
-    field public static final java.lang.String COLUMN_MIME_TYPES = "mime_types";
-    field public static final java.lang.String COLUMN_ROOT_ID = "root_id";
-    field public static final java.lang.String COLUMN_SUMMARY = "summary";
-    field public static final java.lang.String COLUMN_TITLE = "title";
+    field public static final String COLUMN_AVAILABLE_BYTES = "available_bytes";
+    field public static final String COLUMN_CAPACITY_BYTES = "capacity_bytes";
+    field public static final String COLUMN_DOCUMENT_ID = "document_id";
+    field public static final String COLUMN_FLAGS = "flags";
+    field public static final String COLUMN_ICON = "icon";
+    field public static final String COLUMN_MIME_TYPES = "mime_types";
+    field public static final String COLUMN_QUERY_ARGS = "query_args";
+    field public static final String COLUMN_ROOT_ID = "root_id";
+    field public static final String COLUMN_SUMMARY = "summary";
+    field public static final String COLUMN_TITLE = "title";
     field public static final int FLAG_EMPTY = 64; // 0x40
     field public static final int FLAG_LOCAL_ONLY = 2; // 0x2
     field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
@@ -37726,80 +38061,80 @@
     field public static final int FLAG_SUPPORTS_IS_CHILD = 16; // 0x10
     field public static final int FLAG_SUPPORTS_RECENTS = 4; // 0x4
     field public static final int FLAG_SUPPORTS_SEARCH = 8; // 0x8
-    field public static final java.lang.String MIME_TYPE_ITEM = "vnd.android.document/root";
+    field public static final String MIME_TYPE_ITEM = "vnd.android.document/root";
   }
 
   public abstract class DocumentsProvider extends android.content.ContentProvider {
     ctor public DocumentsProvider();
-    method public java.lang.String copyDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
-    method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
-    method public android.content.IntentSender createWebLinkIntent(java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
-    method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
-    method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
-    method public void ejectRoot(java.lang.String);
-    method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
-    method public android.os.Bundle getDocumentMetadata(java.lang.String) throws java.io.FileNotFoundException;
-    method public java.lang.String[] getDocumentStreamTypes(java.lang.String, java.lang.String);
-    method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException;
-    method public final java.lang.String getType(android.net.Uri);
+    method public String copyDocument(String, String) throws java.io.FileNotFoundException;
+    method public String createDocument(String, String, String) throws java.io.FileNotFoundException;
+    method public android.content.IntentSender createWebLinkIntent(String, @Nullable android.os.Bundle) throws java.io.FileNotFoundException;
+    method public final int delete(android.net.Uri, String, String[]);
+    method public void deleteDocument(String) throws java.io.FileNotFoundException;
+    method public void ejectRoot(String);
+    method public android.provider.DocumentsContract.Path findDocumentPath(@Nullable String, String) throws java.io.FileNotFoundException;
+    method @Nullable public android.os.Bundle getDocumentMetadata(@NonNull String) throws java.io.FileNotFoundException;
+    method public String[] getDocumentStreamTypes(String, String);
+    method public String getDocumentType(String) throws java.io.FileNotFoundException;
+    method public final String getType(android.net.Uri);
     method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
-    method public boolean isChildDocument(java.lang.String, java.lang.String);
-    method public java.lang.String moveDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
-    method public final android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
-    method public final android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public abstract android.os.ParcelFileDescriptor openDocument(java.lang.String, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public android.content.res.AssetFileDescriptor openDocumentThumbnail(java.lang.String, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public final android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
-    method public final android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
-    method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public android.content.res.AssetFileDescriptor openTypedDocument(java.lang.String, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
-    method public abstract android.database.Cursor queryChildDocuments(java.lang.String, java.lang.String[], java.lang.String) throws java.io.FileNotFoundException;
-    method public android.database.Cursor queryChildDocuments(java.lang.String, java.lang.String[], android.os.Bundle) throws java.io.FileNotFoundException;
-    method public abstract android.database.Cursor queryDocument(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
-    method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
-    method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[], android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
-    method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
-    method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String[], android.os.Bundle) throws java.io.FileNotFoundException;
-    method public void removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
-    method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
-    method public final void revokeDocumentPermission(java.lang.String);
-    method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+    method public boolean isChildDocument(String, String);
+    method public String moveDocument(String, String, String) throws java.io.FileNotFoundException;
+    method public final android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, String) throws java.io.FileNotFoundException;
+    method public final android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method public abstract android.os.ParcelFileDescriptor openDocument(String, String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method public android.content.res.AssetFileDescriptor openDocumentThumbnail(String, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method public final android.os.ParcelFileDescriptor openFile(android.net.Uri, String) throws java.io.FileNotFoundException;
+    method public final android.os.ParcelFileDescriptor openFile(android.net.Uri, String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, String, android.os.Bundle) throws java.io.FileNotFoundException;
+    method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method public android.content.res.AssetFileDescriptor openTypedDocument(String, String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method public final android.database.Cursor query(android.net.Uri, String[], String, String[], String);
+    method public final android.database.Cursor query(android.net.Uri, String[], android.os.Bundle, android.os.CancellationSignal);
+    method public abstract android.database.Cursor queryChildDocuments(String, String[], String) throws java.io.FileNotFoundException;
+    method public android.database.Cursor queryChildDocuments(String, @Nullable String[], @Nullable android.os.Bundle) throws java.io.FileNotFoundException;
+    method public abstract android.database.Cursor queryDocument(String, String[]) throws java.io.FileNotFoundException;
+    method public android.database.Cursor queryRecentDocuments(String, String[]) throws java.io.FileNotFoundException;
+    method public android.database.Cursor queryRecentDocuments(String, String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
+    method public abstract android.database.Cursor queryRoots(String[]) throws java.io.FileNotFoundException;
+    method public android.database.Cursor querySearchDocuments(String, String, String[]) throws java.io.FileNotFoundException;
+    method public android.database.Cursor querySearchDocuments(@NonNull String, @Nullable String[], @NonNull android.os.Bundle) throws java.io.FileNotFoundException;
+    method public void removeDocument(String, String) throws java.io.FileNotFoundException;
+    method public String renameDocument(String, String) throws java.io.FileNotFoundException;
+    method public final void revokeDocumentPermission(String);
+    method public final int update(android.net.Uri, android.content.ContentValues, String, String[]);
   }
 
   public final class FontRequest {
-    ctor public FontRequest(java.lang.String, java.lang.String, java.lang.String);
-    ctor public FontRequest(java.lang.String, java.lang.String, java.lang.String, java.util.List<java.util.List<byte[]>>);
+    ctor public FontRequest(@NonNull String, @NonNull String, @NonNull String);
+    ctor public FontRequest(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.List<java.util.List<byte[]>>);
     method public java.util.List<java.util.List<byte[]>> getCertificates();
-    method public java.lang.String getProviderAuthority();
-    method public java.lang.String getProviderPackage();
-    method public java.lang.String getQuery();
+    method public String getProviderAuthority();
+    method public String getProviderPackage();
+    method public String getQuery();
   }
 
   public class FontsContract {
-    method public static android.graphics.Typeface buildTypeface(android.content.Context, android.os.CancellationSignal, android.provider.FontsContract.FontInfo[]);
-    method public static android.provider.FontsContract.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal, android.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public static void requestFonts(android.content.Context, android.provider.FontRequest, android.os.Handler, android.os.CancellationSignal, android.provider.FontsContract.FontRequestCallback);
+    method public static android.graphics.Typeface buildTypeface(@NonNull android.content.Context, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontsContract.FontInfo[]);
+    method @NonNull public static android.provider.FontsContract.FontFamilyResult fetchFonts(@NonNull android.content.Context, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static void requestFonts(@NonNull android.content.Context, @NonNull android.provider.FontRequest, @NonNull android.os.Handler, @Nullable android.os.CancellationSignal, @NonNull android.provider.FontsContract.FontRequestCallback);
   }
 
   public static final class FontsContract.Columns implements android.provider.BaseColumns {
-    field public static final java.lang.String FILE_ID = "file_id";
-    field public static final java.lang.String ITALIC = "font_italic";
-    field public static final java.lang.String RESULT_CODE = "result_code";
+    field public static final String FILE_ID = "file_id";
+    field public static final String ITALIC = "font_italic";
+    field public static final String RESULT_CODE = "result_code";
     field public static final int RESULT_CODE_FONT_NOT_FOUND = 1; // 0x1
     field public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; // 0x2
     field public static final int RESULT_CODE_MALFORMED_QUERY = 3; // 0x3
     field public static final int RESULT_CODE_OK = 0; // 0x0
-    field public static final java.lang.String TTC_INDEX = "font_ttc_index";
-    field public static final java.lang.String VARIATION_SETTINGS = "font_variation_settings";
-    field public static final java.lang.String WEIGHT = "font_weight";
+    field public static final String TTC_INDEX = "font_ttc_index";
+    field public static final String VARIATION_SETTINGS = "font_variation_settings";
+    field public static final String WEIGHT = "font_weight";
   }
 
   public static class FontsContract.FontFamilyResult {
-    method public android.provider.FontsContract.FontInfo[] getFonts();
+    method @NonNull public android.provider.FontsContract.FontInfo[] getFonts();
     method public int getStatusCode();
     field public static final int STATUS_OK = 0; // 0x0
     field public static final int STATUS_REJECTED = 3; // 0x3
@@ -37808,11 +38143,11 @@
   }
 
   public static class FontsContract.FontInfo {
-    method public android.graphics.fonts.FontVariationAxis[] getAxes();
+    method @Nullable public android.graphics.fonts.FontVariationAxis[] getAxes();
     method public int getResultCode();
-    method public int getTtcIndex();
-    method public android.net.Uri getUri();
-    method public int getWeight();
+    method @IntRange(from=0) public int getTtcIndex();
+    method @NonNull public android.net.Uri getUri();
+    method @IntRange(from=1, to=1000) public int getWeight();
     method public boolean isItalic();
   }
 
@@ -37828,395 +38163,406 @@
     field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
   }
 
-  public final deprecated class LiveFolders implements android.provider.BaseColumns {
-    field public static final java.lang.String ACTION_CREATE_LIVE_FOLDER = "android.intent.action.CREATE_LIVE_FOLDER";
-    field public static final java.lang.String DESCRIPTION = "description";
-    field public static final int DISPLAY_MODE_GRID = 1; // 0x1
-    field public static final int DISPLAY_MODE_LIST = 2; // 0x2
-    field public static final java.lang.String EXTRA_LIVE_FOLDER_BASE_INTENT = "android.intent.extra.livefolder.BASE_INTENT";
-    field public static final java.lang.String EXTRA_LIVE_FOLDER_DISPLAY_MODE = "android.intent.extra.livefolder.DISPLAY_MODE";
-    field public static final java.lang.String EXTRA_LIVE_FOLDER_ICON = "android.intent.extra.livefolder.ICON";
-    field public static final java.lang.String EXTRA_LIVE_FOLDER_NAME = "android.intent.extra.livefolder.NAME";
-    field public static final java.lang.String ICON_BITMAP = "icon_bitmap";
-    field public static final java.lang.String ICON_PACKAGE = "icon_package";
-    field public static final java.lang.String ICON_RESOURCE = "icon_resource";
-    field public static final java.lang.String INTENT = "intent";
-    field public static final java.lang.String NAME = "name";
+  @Deprecated public final class LiveFolders implements android.provider.BaseColumns {
+    field @Deprecated public static final String ACTION_CREATE_LIVE_FOLDER = "android.intent.action.CREATE_LIVE_FOLDER";
+    field @Deprecated public static final String DESCRIPTION = "description";
+    field @Deprecated public static final int DISPLAY_MODE_GRID = 1; // 0x1
+    field @Deprecated public static final int DISPLAY_MODE_LIST = 2; // 0x2
+    field @Deprecated public static final String EXTRA_LIVE_FOLDER_BASE_INTENT = "android.intent.extra.livefolder.BASE_INTENT";
+    field @Deprecated public static final String EXTRA_LIVE_FOLDER_DISPLAY_MODE = "android.intent.extra.livefolder.DISPLAY_MODE";
+    field @Deprecated public static final String EXTRA_LIVE_FOLDER_ICON = "android.intent.extra.livefolder.ICON";
+    field @Deprecated public static final String EXTRA_LIVE_FOLDER_NAME = "android.intent.extra.livefolder.NAME";
+    field @Deprecated public static final String ICON_BITMAP = "icon_bitmap";
+    field @Deprecated public static final String ICON_PACKAGE = "icon_package";
+    field @Deprecated public static final String ICON_RESOURCE = "icon_resource";
+    field @Deprecated public static final String INTENT = "intent";
+    field @Deprecated public static final String NAME = "name";
   }
 
   public final class MediaStore {
     ctor public MediaStore();
-    method public static android.net.Uri createPending(android.content.Context, android.provider.MediaStore.PendingParams);
-    method public static java.util.Set<java.lang.String> getAllVolumeNames(android.content.Context);
+    method @NonNull public static android.net.Uri createPending(@NonNull android.content.Context, @NonNull android.provider.MediaStore.PendingParams);
+    method @NonNull public static java.util.Set<java.lang.String> getAllVolumeNames(android.content.Context);
     method public static android.net.Uri getDocumentUri(android.content.Context, android.net.Uri);
     method public static android.net.Uri getMediaScannerUri();
     method public static android.net.Uri getMediaUri(android.content.Context, android.net.Uri);
-    method public static java.lang.String getVersion(android.content.Context);
-    method public static java.lang.String getVolumeName(android.net.Uri);
-    method public static android.provider.MediaStore.PendingSession openPending(android.content.Context, android.net.Uri);
-    method public static android.net.Uri setIncludePending(android.net.Uri);
-    method public static android.net.Uri setRequireOriginal(android.net.Uri);
-    field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
-    field public static final java.lang.String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
-    field public static final java.lang.String ACTION_REVIEW = "android.provider.action.REVIEW";
-    field public static final java.lang.String ACTION_REVIEW_SECURE = "android.provider.action.REVIEW_SECURE";
-    field public static final java.lang.String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
-    field public static final java.lang.String AUTHORITY = "media";
+    method public static String getVersion(android.content.Context);
+    method @NonNull public static String getVolumeName(@NonNull android.net.Uri);
+    method @NonNull public static android.provider.MediaStore.PendingSession openPending(@NonNull android.content.Context, @NonNull android.net.Uri);
+    method @NonNull public static android.net.Uri setIncludePending(@NonNull android.net.Uri);
+    method @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
+    method @NonNull public static android.net.Uri setRequireOriginal(@NonNull android.net.Uri);
+    method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
+    method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri, long);
+    method public static void untrash(@NonNull android.content.Context, @NonNull android.net.Uri);
+    field public static final String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
+    field public static final String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
+    field public static final String ACTION_REVIEW = "android.provider.action.REVIEW";
+    field public static final String ACTION_REVIEW_SECURE = "android.provider.action.REVIEW_SECURE";
+    field public static final String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
+    field public static final String AUTHORITY = "media";
     field public static final android.net.Uri AUTHORITY_URI;
-    field public static final java.lang.String EXTRA_BRIGHTNESS = "android.provider.extra.BRIGHTNESS";
-    field public static final java.lang.String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
-    field public static final java.lang.String EXTRA_FINISH_ON_COMPLETION = "android.intent.extra.finishOnCompletion";
-    field public static final java.lang.String EXTRA_FULL_SCREEN = "android.intent.extra.fullScreen";
-    field public static final java.lang.String EXTRA_MEDIA_ALBUM = "android.intent.extra.album";
-    field public static final java.lang.String EXTRA_MEDIA_ARTIST = "android.intent.extra.artist";
-    field public static final java.lang.String EXTRA_MEDIA_FOCUS = "android.intent.extra.focus";
-    field public static final java.lang.String EXTRA_MEDIA_GENRE = "android.intent.extra.genre";
-    field public static final java.lang.String EXTRA_MEDIA_PLAYLIST = "android.intent.extra.playlist";
-    field public static final java.lang.String EXTRA_MEDIA_RADIO_CHANNEL = "android.intent.extra.radio_channel";
-    field public static final java.lang.String EXTRA_MEDIA_TITLE = "android.intent.extra.title";
-    field public static final java.lang.String EXTRA_OUTPUT = "output";
-    field public static final java.lang.String EXTRA_SCREEN_ORIENTATION = "android.intent.extra.screenOrientation";
-    field public static final java.lang.String EXTRA_SHOW_ACTION_ICONS = "android.intent.extra.showActionIcons";
-    field public static final java.lang.String EXTRA_SIZE_LIMIT = "android.intent.extra.sizeLimit";
-    field public static final java.lang.String EXTRA_VIDEO_QUALITY = "android.intent.extra.videoQuality";
-    field public static final java.lang.String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH = "android.media.action.MEDIA_PLAY_FROM_SEARCH";
-    field public static final java.lang.String INTENT_ACTION_MEDIA_SEARCH = "android.intent.action.MEDIA_SEARCH";
-    field public static final deprecated java.lang.String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
-    field public static final java.lang.String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
-    field public static final java.lang.String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE = "android.media.action.STILL_IMAGE_CAMERA_SECURE";
-    field public static final java.lang.String INTENT_ACTION_TEXT_OPEN_FROM_SEARCH = "android.media.action.TEXT_OPEN_FROM_SEARCH";
-    field public static final java.lang.String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
-    field public static final java.lang.String INTENT_ACTION_VIDEO_PLAY_FROM_SEARCH = "android.media.action.VIDEO_PLAY_FROM_SEARCH";
-    field public static final java.lang.String MEDIA_IGNORE_FILENAME = ".nomedia";
-    field public static final java.lang.String MEDIA_SCANNER_VOLUME = "volume";
-    field public static final java.lang.String META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE = "android.media.still_image_camera_preview_service";
-    field public static final java.lang.String UNKNOWN_STRING = "<unknown>";
+    field public static final String EXTRA_BRIGHTNESS = "android.provider.extra.BRIGHTNESS";
+    field public static final String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
+    field public static final String EXTRA_FINISH_ON_COMPLETION = "android.intent.extra.finishOnCompletion";
+    field public static final String EXTRA_FULL_SCREEN = "android.intent.extra.fullScreen";
+    field public static final String EXTRA_MEDIA_ALBUM = "android.intent.extra.album";
+    field public static final String EXTRA_MEDIA_ARTIST = "android.intent.extra.artist";
+    field public static final String EXTRA_MEDIA_FOCUS = "android.intent.extra.focus";
+    field public static final String EXTRA_MEDIA_GENRE = "android.intent.extra.genre";
+    field public static final String EXTRA_MEDIA_PLAYLIST = "android.intent.extra.playlist";
+    field public static final String EXTRA_MEDIA_RADIO_CHANNEL = "android.intent.extra.radio_channel";
+    field public static final String EXTRA_MEDIA_TITLE = "android.intent.extra.title";
+    field public static final String EXTRA_OUTPUT = "output";
+    field public static final String EXTRA_SCREEN_ORIENTATION = "android.intent.extra.screenOrientation";
+    field public static final String EXTRA_SHOW_ACTION_ICONS = "android.intent.extra.showActionIcons";
+    field public static final String EXTRA_SIZE_LIMIT = "android.intent.extra.sizeLimit";
+    field public static final String EXTRA_VIDEO_QUALITY = "android.intent.extra.videoQuality";
+    field public static final String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH = "android.media.action.MEDIA_PLAY_FROM_SEARCH";
+    field public static final String INTENT_ACTION_MEDIA_SEARCH = "android.intent.action.MEDIA_SEARCH";
+    field @Deprecated public static final String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
+    field public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
+    field public static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE = "android.media.action.STILL_IMAGE_CAMERA_SECURE";
+    field public static final String INTENT_ACTION_TEXT_OPEN_FROM_SEARCH = "android.media.action.TEXT_OPEN_FROM_SEARCH";
+    field public static final String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
+    field public static final String INTENT_ACTION_VIDEO_PLAY_FROM_SEARCH = "android.media.action.VIDEO_PLAY_FROM_SEARCH";
+    field public static final String MEDIA_IGNORE_FILENAME = ".nomedia";
+    field public static final String MEDIA_SCANNER_VOLUME = "volume";
+    field public static final String META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE = "android.media.still_image_camera_preview_service";
+    field public static final String UNKNOWN_STRING = "<unknown>";
+    field public static final String VOLUME_EXTERNAL = "external";
+    field public static final String VOLUME_INTERNAL = "internal";
   }
 
   public static final class MediaStore.Audio {
     ctor public MediaStore.Audio();
-    method public static java.lang.String keyFor(java.lang.String);
+    method public static String keyFor(String);
   }
 
-  public static abstract interface MediaStore.Audio.AlbumColumns {
-    field public static final java.lang.String ALBUM = "album";
-    field public static final deprecated java.lang.String ALBUM_ART = "album_art";
-    field public static final java.lang.String ALBUM_ID = "album_id";
-    field public static final java.lang.String ALBUM_KEY = "album_key";
-    field public static final java.lang.String ARTIST = "artist";
-    field public static final java.lang.String FIRST_YEAR = "minyear";
-    field public static final java.lang.String LAST_YEAR = "maxyear";
-    field public static final java.lang.String NUMBER_OF_SONGS = "numsongs";
-    field public static final java.lang.String NUMBER_OF_SONGS_FOR_ARTIST = "numsongs_by_artist";
+  public static interface MediaStore.Audio.AlbumColumns {
+    field public static final String ALBUM = "album";
+    field @Deprecated public static final String ALBUM_ART = "album_art";
+    field public static final String ALBUM_ID = "album_id";
+    field public static final String ALBUM_KEY = "album_key";
+    field public static final String ARTIST = "artist";
+    field public static final String FIRST_YEAR = "minyear";
+    field public static final String LAST_YEAR = "maxyear";
+    field public static final String NUMBER_OF_SONGS = "numsongs";
+    field public static final String NUMBER_OF_SONGS_FOR_ARTIST = "numsongs_by_artist";
   }
 
   public static final class MediaStore.Audio.Albums implements android.provider.BaseColumns android.provider.MediaStore.Audio.AlbumColumns {
     ctor public MediaStore.Audio.Albums();
-    method public static android.net.Uri getContentUri(java.lang.String);
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/albums";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "album_key";
-    field public static final java.lang.String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/album";
+    method public static android.net.Uri getContentUri(String);
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/albums";
+    field public static final String DEFAULT_SORT_ORDER = "album_key";
+    field public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/album";
     field public static final android.net.Uri EXTERNAL_CONTENT_URI;
     field public static final android.net.Uri INTERNAL_CONTENT_URI;
   }
 
-  public static abstract interface MediaStore.Audio.ArtistColumns {
-    field public static final java.lang.String ARTIST = "artist";
-    field public static final java.lang.String ARTIST_KEY = "artist_key";
-    field public static final java.lang.String NUMBER_OF_ALBUMS = "number_of_albums";
-    field public static final java.lang.String NUMBER_OF_TRACKS = "number_of_tracks";
+  public static interface MediaStore.Audio.ArtistColumns {
+    field public static final String ARTIST = "artist";
+    field public static final String ARTIST_KEY = "artist_key";
+    field public static final String NUMBER_OF_ALBUMS = "number_of_albums";
+    field public static final String NUMBER_OF_TRACKS = "number_of_tracks";
   }
 
   public static final class MediaStore.Audio.Artists implements android.provider.BaseColumns android.provider.MediaStore.Audio.ArtistColumns {
     ctor public MediaStore.Audio.Artists();
-    method public static android.net.Uri getContentUri(java.lang.String);
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/artists";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "artist_key";
-    field public static final java.lang.String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/artist";
+    method public static android.net.Uri getContentUri(String);
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/artists";
+    field public static final String DEFAULT_SORT_ORDER = "artist_key";
+    field public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/artist";
     field public static final android.net.Uri EXTERNAL_CONTENT_URI;
     field public static final android.net.Uri INTERNAL_CONTENT_URI;
   }
 
   public static final class MediaStore.Audio.Artists.Albums implements android.provider.MediaStore.Audio.AlbumColumns {
     ctor public MediaStore.Audio.Artists.Albums();
-    method public static android.net.Uri getContentUri(java.lang.String, long);
+    method public static android.net.Uri getContentUri(String, long);
   }
 
-  public static abstract interface MediaStore.Audio.AudioColumns implements android.provider.MediaStore.MediaColumns {
-    field public static final java.lang.String ALBUM = "album";
-    field public static final java.lang.String ALBUM_ID = "album_id";
-    field public static final java.lang.String ALBUM_KEY = "album_key";
-    field public static final java.lang.String ARTIST = "artist";
-    field public static final java.lang.String ARTIST_ID = "artist_id";
-    field public static final java.lang.String ARTIST_KEY = "artist_key";
-    field public static final java.lang.String BOOKMARK = "bookmark";
-    field public static final java.lang.String COMPOSER = "composer";
-    field public static final java.lang.String DURATION = "duration";
-    field public static final java.lang.String IS_ALARM = "is_alarm";
-    field public static final java.lang.String IS_AUDIOBOOK = "is_audiobook";
-    field public static final java.lang.String IS_MUSIC = "is_music";
-    field public static final java.lang.String IS_NOTIFICATION = "is_notification";
-    field public static final java.lang.String IS_PODCAST = "is_podcast";
-    field public static final java.lang.String IS_RINGTONE = "is_ringtone";
-    field public static final java.lang.String TITLE_KEY = "title_key";
-    field public static final java.lang.String TRACK = "track";
-    field public static final java.lang.String YEAR = "year";
+  public static interface MediaStore.Audio.AudioColumns extends android.provider.MediaStore.MediaColumns {
+    field public static final String ALBUM = "album";
+    field public static final String ALBUM_ID = "album_id";
+    field public static final String ALBUM_KEY = "album_key";
+    field public static final String ARTIST = "artist";
+    field public static final String ARTIST_ID = "artist_id";
+    field public static final String ARTIST_KEY = "artist_key";
+    field public static final String BOOKMARK = "bookmark";
+    field public static final String COMPOSER = "composer";
+    field public static final String DURATION = "duration";
+    field public static final String IS_ALARM = "is_alarm";
+    field public static final String IS_AUDIOBOOK = "is_audiobook";
+    field public static final String IS_MUSIC = "is_music";
+    field public static final String IS_NOTIFICATION = "is_notification";
+    field public static final String IS_PODCAST = "is_podcast";
+    field public static final String IS_RINGTONE = "is_ringtone";
+    field public static final String TITLE_KEY = "title_key";
+    field public static final String TRACK = "track";
+    field public static final String YEAR = "year";
   }
 
   public static final class MediaStore.Audio.Genres implements android.provider.BaseColumns android.provider.MediaStore.Audio.GenresColumns {
     ctor public MediaStore.Audio.Genres();
-    method public static android.net.Uri getContentUri(java.lang.String);
-    method public static android.net.Uri getContentUriForAudioId(java.lang.String, int);
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/genre";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "name";
-    field public static final java.lang.String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/genre";
+    method public static android.net.Uri getContentUri(String);
+    method public static android.net.Uri getContentUriForAudioId(String, int);
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/genre";
+    field public static final String DEFAULT_SORT_ORDER = "name";
+    field public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/genre";
     field public static final android.net.Uri EXTERNAL_CONTENT_URI;
     field public static final android.net.Uri INTERNAL_CONTENT_URI;
   }
 
   public static final class MediaStore.Audio.Genres.Members implements android.provider.MediaStore.Audio.AudioColumns {
     ctor public MediaStore.Audio.Genres.Members();
-    method public static android.net.Uri getContentUri(java.lang.String, long);
-    field public static final java.lang.String AUDIO_ID = "audio_id";
-    field public static final java.lang.String CONTENT_DIRECTORY = "members";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "title_key";
-    field public static final java.lang.String GENRE_ID = "genre_id";
+    method public static android.net.Uri getContentUri(String, long);
+    field public static final String AUDIO_ID = "audio_id";
+    field public static final String CONTENT_DIRECTORY = "members";
+    field public static final String DEFAULT_SORT_ORDER = "title_key";
+    field public static final String GENRE_ID = "genre_id";
   }
 
-  public static abstract interface MediaStore.Audio.GenresColumns {
-    field public static final java.lang.String NAME = "name";
+  public static interface MediaStore.Audio.GenresColumns {
+    field public static final String NAME = "name";
   }
 
   public static final class MediaStore.Audio.Media implements android.provider.MediaStore.Audio.AudioColumns {
     ctor public MediaStore.Audio.Media();
-    method public static android.net.Uri getContentUri(java.lang.String);
-    method public static deprecated android.net.Uri getContentUriForPath(java.lang.String);
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "title_key";
-    field public static final java.lang.String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/audio";
+    method public static android.net.Uri getContentUri(String);
+    method @Deprecated @Nullable public static android.net.Uri getContentUriForPath(@NonNull String);
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
+    field public static final String DEFAULT_SORT_ORDER = "title_key";
+    field public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/audio";
     field public static final android.net.Uri EXTERNAL_CONTENT_URI;
-    field public static final java.lang.String EXTRA_MAX_BYTES = "android.provider.MediaStore.extra.MAX_BYTES";
+    field public static final String EXTRA_MAX_BYTES = "android.provider.MediaStore.extra.MAX_BYTES";
     field public static final android.net.Uri INTERNAL_CONTENT_URI;
-    field public static final java.lang.String RECORD_SOUND_ACTION = "android.provider.MediaStore.RECORD_SOUND";
+    field public static final String RECORD_SOUND_ACTION = "android.provider.MediaStore.RECORD_SOUND";
   }
 
   public static final class MediaStore.Audio.Playlists implements android.provider.BaseColumns android.provider.MediaStore.Audio.PlaylistsColumns {
     ctor public MediaStore.Audio.Playlists();
-    method public static android.net.Uri getContentUri(java.lang.String);
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/playlist";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "name";
-    field public static final java.lang.String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/playlist";
+    method public static android.net.Uri getContentUri(String);
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/playlist";
+    field public static final String DEFAULT_SORT_ORDER = "name";
+    field public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/playlist";
     field public static final android.net.Uri EXTERNAL_CONTENT_URI;
     field public static final android.net.Uri INTERNAL_CONTENT_URI;
   }
 
   public static final class MediaStore.Audio.Playlists.Members implements android.provider.MediaStore.Audio.AudioColumns {
     ctor public MediaStore.Audio.Playlists.Members();
-    method public static android.net.Uri getContentUri(java.lang.String, long);
+    method public static android.net.Uri getContentUri(String, long);
     method public static boolean moveItem(android.content.ContentResolver, long, int, int);
-    field public static final java.lang.String AUDIO_ID = "audio_id";
-    field public static final java.lang.String CONTENT_DIRECTORY = "members";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "play_order";
-    field public static final java.lang.String PLAYLIST_ID = "playlist_id";
-    field public static final java.lang.String PLAY_ORDER = "play_order";
-    field public static final java.lang.String _ID = "_id";
+    field public static final String AUDIO_ID = "audio_id";
+    field public static final String CONTENT_DIRECTORY = "members";
+    field public static final String DEFAULT_SORT_ORDER = "play_order";
+    field public static final String PLAYLIST_ID = "playlist_id";
+    field public static final String PLAY_ORDER = "play_order";
+    field public static final String _ID = "_id";
   }
 
-  public static abstract interface MediaStore.Audio.PlaylistsColumns {
-    field public static final deprecated java.lang.String DATA = "_data";
-    field public static final java.lang.String DATE_ADDED = "date_added";
-    field public static final java.lang.String DATE_MODIFIED = "date_modified";
-    field public static final java.lang.String NAME = "name";
+  public static interface MediaStore.Audio.PlaylistsColumns {
+    field @Deprecated public static final String DATA = "_data";
+    field public static final String DATE_ADDED = "date_added";
+    field public static final String DATE_MODIFIED = "date_modified";
+    field public static final String NAME = "name";
   }
 
   public static final class MediaStore.Audio.Radio {
-    field public static final java.lang.String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/radio";
+    field public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/radio";
   }
 
-  public static abstract interface MediaStore.DownloadColumns implements android.provider.MediaStore.MediaColumns {
-    field public static final java.lang.String DOWNLOAD_URI = "download_uri";
-    field public static final java.lang.String REFERER_URI = "referer_uri";
+  public static interface MediaStore.DownloadColumns extends android.provider.MediaStore.MediaColumns {
+    field public static final String DESCRIPTION = "description";
+    field public static final String DOWNLOAD_URI = "download_uri";
+    field public static final String REFERER_URI = "referer_uri";
   }
 
   public static final class MediaStore.Downloads implements android.provider.MediaStore.DownloadColumns {
-    method public static android.net.Uri getContentUri(java.lang.String);
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/download";
+    method public static android.net.Uri getContentUri(String);
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/download";
     field public static final android.net.Uri EXTERNAL_CONTENT_URI;
     field public static final android.net.Uri INTERNAL_CONTENT_URI;
   }
 
   public static final class MediaStore.Files {
     ctor public MediaStore.Files();
-    method public static android.net.Uri getContentUri(java.lang.String);
-    method public static android.net.Uri getContentUri(java.lang.String, long);
+    method public static android.net.Uri getContentUri(String);
+    method public static android.net.Uri getContentUri(String, long);
   }
 
-  public static abstract interface MediaStore.Files.FileColumns implements android.provider.MediaStore.MediaColumns {
-    field public static final java.lang.String MEDIA_TYPE = "media_type";
+  public static interface MediaStore.Files.FileColumns extends android.provider.MediaStore.MediaColumns {
+    field public static final String MEDIA_TYPE = "media_type";
     field public static final int MEDIA_TYPE_AUDIO = 2; // 0x2
     field public static final int MEDIA_TYPE_IMAGE = 1; // 0x1
     field public static final int MEDIA_TYPE_NONE = 0; // 0x0
     field public static final int MEDIA_TYPE_PLAYLIST = 4; // 0x4
     field public static final int MEDIA_TYPE_VIDEO = 3; // 0x3
-    field public static final java.lang.String MIME_TYPE = "mime_type";
-    field public static final java.lang.String PARENT = "parent";
-    field public static final java.lang.String TITLE = "title";
+    field public static final String MIME_TYPE = "mime_type";
+    field public static final String PARENT = "parent";
+    field public static final String TITLE = "title";
   }
 
   public static final class MediaStore.Images {
     ctor public MediaStore.Images();
   }
 
-  public static abstract interface MediaStore.Images.ImageColumns implements android.provider.MediaStore.MediaColumns {
-    field public static final java.lang.String BUCKET_DISPLAY_NAME = "bucket_display_name";
-    field public static final java.lang.String BUCKET_ID = "bucket_id";
-    field public static final java.lang.String DATE_TAKEN = "datetaken";
-    field public static final java.lang.String DESCRIPTION = "description";
-    field public static final java.lang.String IS_PRIVATE = "isprivate";
-    field public static final deprecated java.lang.String LATITUDE = "latitude";
-    field public static final deprecated java.lang.String LONGITUDE = "longitude";
-    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 deprecated java.lang.String PICASA_ID = "picasa_id";
+  public static interface MediaStore.Images.ImageColumns extends android.provider.MediaStore.MediaColumns {
+    field public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
+    field public static final String BUCKET_ID = "bucket_id";
+    field public static final String DATE_TAKEN = "datetaken";
+    field public static final String DESCRIPTION = "description";
+    field public static final String IS_PRIVATE = "isprivate";
+    field @Deprecated public static final String LATITUDE = "latitude";
+    field @Deprecated public static final String LONGITUDE = "longitude";
+    field @Deprecated public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
+    field public static final String ORIENTATION = "orientation";
+    field @Deprecated public static final String PICASA_ID = "picasa_id";
+    field public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id";
   }
 
   public static final class MediaStore.Images.Media implements android.provider.MediaStore.Images.ImageColumns {
     ctor public MediaStore.Images.Media();
     method public static android.graphics.Bitmap getBitmap(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException, java.io.IOException;
-    method public static android.net.Uri getContentUri(java.lang.String);
-    method public static java.lang.String insertImage(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
-    method public static java.lang.String insertImage(android.content.ContentResolver, android.graphics.Bitmap, java.lang.String, java.lang.String);
-    method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[]);
-    method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String);
-    method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/image";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "bucket_display_name";
+    method public static android.net.Uri getContentUri(String);
+    method public static String insertImage(android.content.ContentResolver, String, String, String) throws java.io.FileNotFoundException;
+    method public static String insertImage(android.content.ContentResolver, android.graphics.Bitmap, String, String);
+    method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, String[]);
+    method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, String[], String, String);
+    method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, String[], String, String[], String);
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/image";
+    field public static final String DEFAULT_SORT_ORDER = "bucket_display_name";
     field public static final android.net.Uri EXTERNAL_CONTENT_URI;
     field public static final android.net.Uri INTERNAL_CONTENT_URI;
   }
 
-  public static class MediaStore.Images.Thumbnails implements android.provider.BaseColumns {
-    ctor public MediaStore.Images.Thumbnails();
-    method public static deprecated void cancelThumbnailRequest(android.content.ContentResolver, long);
-    method public static deprecated void cancelThumbnailRequest(android.content.ContentResolver, long, long);
-    method public static android.net.Uri getContentUri(java.lang.String);
-    method public static deprecated android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, int, android.graphics.BitmapFactory.Options);
-    method public static deprecated android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, long, int, android.graphics.BitmapFactory.Options);
-    method public static final android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[]);
-    method public static final android.database.Cursor queryMiniThumbnail(android.content.ContentResolver, long, int, java.lang.String[]);
-    method public static final android.database.Cursor queryMiniThumbnails(android.content.ContentResolver, android.net.Uri, int, java.lang.String[]);
-    field public static final deprecated java.lang.String DATA = "_data";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "image_id ASC";
-    field public static final android.net.Uri EXTERNAL_CONTENT_URI;
-    field public static final int FULL_SCREEN_KIND = 2; // 0x2
-    field public static final java.lang.String HEIGHT = "height";
-    field public static final java.lang.String IMAGE_ID = "image_id";
-    field public static final android.net.Uri INTERNAL_CONTENT_URI;
-    field public static final java.lang.String KIND = "kind";
-    field public static final int MICRO_KIND = 3; // 0x3
-    field public static final int MINI_KIND = 1; // 0x1
-    field public static final java.lang.String THUMB_DATA = "thumb_data";
-    field public static final java.lang.String WIDTH = "width";
+  @Deprecated public static class MediaStore.Images.Thumbnails implements android.provider.BaseColumns {
+    ctor @Deprecated public MediaStore.Images.Thumbnails();
+    method @Deprecated public static void cancelThumbnailRequest(android.content.ContentResolver, long);
+    method @Deprecated public static void cancelThumbnailRequest(android.content.ContentResolver, long, long);
+    method @Deprecated public static android.net.Uri getContentUri(String);
+    method @Deprecated public static android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, int, android.graphics.BitmapFactory.Options);
+    method @Deprecated public static android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, long, int, android.graphics.BitmapFactory.Options);
+    method @Deprecated public static final android.database.Cursor query(android.content.ContentResolver, android.net.Uri, String[]);
+    method @Deprecated public static final android.database.Cursor queryMiniThumbnail(android.content.ContentResolver, long, int, String[]);
+    method @Deprecated public static final android.database.Cursor queryMiniThumbnails(android.content.ContentResolver, android.net.Uri, int, String[]);
+    field @Deprecated public static final String DATA = "_data";
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "image_id ASC";
+    field @Deprecated public static final android.net.Uri EXTERNAL_CONTENT_URI;
+    field @Deprecated public static final int FULL_SCREEN_KIND = 2; // 0x2
+    field @Deprecated public static final String HEIGHT = "height";
+    field @Deprecated public static final String IMAGE_ID = "image_id";
+    field @Deprecated public static final android.net.Uri INTERNAL_CONTENT_URI;
+    field @Deprecated public static final String KIND = "kind";
+    field @Deprecated public static final int MICRO_KIND = 3; // 0x3
+    field @Deprecated public static final int MINI_KIND = 1; // 0x1
+    field @Deprecated public static final String THUMB_DATA = "thumb_data";
+    field @Deprecated public static final String WIDTH = "width";
   }
 
-  public static abstract interface MediaStore.MediaColumns implements android.provider.BaseColumns {
-    field public static final deprecated java.lang.String DATA = "_data";
-    field public static final java.lang.String DATE_ADDED = "date_added";
-    field public static final java.lang.String DATE_MODIFIED = "date_modified";
-    field public static final java.lang.String DISPLAY_NAME = "_display_name";
-    field public static final java.lang.String HASH = "_hash";
-    field public static final java.lang.String HEIGHT = "height";
-    field public static final java.lang.String IS_PENDING = "is_pending";
-    field public static final java.lang.String MIME_TYPE = "mime_type";
-    field public static final java.lang.String OWNER_PACKAGE_NAME = "owner_package_name";
-    field public static final java.lang.String SIZE = "_size";
-    field public static final java.lang.String TITLE = "title";
-    field public static final java.lang.String WIDTH = "width";
+  public static interface MediaStore.MediaColumns extends android.provider.BaseColumns {
+    field @Deprecated public static final String DATA = "_data";
+    field public static final String DATE_ADDED = "date_added";
+    field public static final String DATE_EXPIRES = "date_expires";
+    field public static final String DATE_MODIFIED = "date_modified";
+    field public static final String DISPLAY_NAME = "_display_name";
+    field public static final String HASH = "_hash";
+    field public static final String HEIGHT = "height";
+    field public static final String IS_PENDING = "is_pending";
+    field public static final String IS_TRASHED = "is_trashed";
+    field public static final String MIME_TYPE = "mime_type";
+    field public static final String OWNER_PACKAGE_NAME = "owner_package_name";
+    field public static final String SIZE = "_size";
+    field public static final String TITLE = "title";
+    field public static final String WIDTH = "width";
   }
 
   public static class MediaStore.PendingParams {
-    ctor public MediaStore.PendingParams(android.net.Uri, java.lang.String, java.lang.String);
-    method public void setDownloadUri(android.net.Uri);
-    method public void setPrimaryDirectory(java.lang.String);
-    method public void setRefererUri(android.net.Uri);
-    method public void setSecondaryDirectory(java.lang.String);
+    ctor public MediaStore.PendingParams(@NonNull android.net.Uri, @NonNull String, @NonNull String);
+    method public void setDownloadUri(@Nullable android.net.Uri);
+    method public void setPrimaryDirectory(@Nullable String);
+    method public void setRefererUri(@Nullable android.net.Uri);
+    method public void setSecondaryDirectory(@Nullable String);
   }
 
   public static class MediaStore.PendingSession implements java.lang.AutoCloseable {
     method public void abandon();
     method public void close();
-    method public void notifyProgress(int);
-    method public android.os.ParcelFileDescriptor open() throws java.io.FileNotFoundException;
-    method public java.io.OutputStream openOutputStream() throws java.io.FileNotFoundException;
-    method public android.net.Uri publish();
+    method public void notifyProgress(@IntRange(from=0, to=100) int);
+    method @NonNull public android.os.ParcelFileDescriptor open() throws java.io.FileNotFoundException;
+    method @NonNull public java.io.OutputStream openOutputStream() throws java.io.FileNotFoundException;
+    method @NonNull public android.net.Uri publish();
   }
 
   public static final class MediaStore.Video {
     ctor public MediaStore.Video();
-    method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[]);
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "_display_name";
+    method public static android.database.Cursor query(android.content.ContentResolver, android.net.Uri, String[]);
+    field public static final String DEFAULT_SORT_ORDER = "_display_name";
   }
 
   public static final class MediaStore.Video.Media implements android.provider.MediaStore.Video.VideoColumns {
     ctor public MediaStore.Video.Media();
-    method public static android.net.Uri getContentUri(java.lang.String);
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/video";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "title";
+    method public static android.net.Uri getContentUri(String);
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/video";
+    field public static final String DEFAULT_SORT_ORDER = "title";
     field public static final android.net.Uri EXTERNAL_CONTENT_URI;
     field public static final android.net.Uri INTERNAL_CONTENT_URI;
   }
 
-  public static class MediaStore.Video.Thumbnails implements android.provider.BaseColumns {
-    ctor public MediaStore.Video.Thumbnails();
-    method public static deprecated void cancelThumbnailRequest(android.content.ContentResolver, long);
-    method public static deprecated void cancelThumbnailRequest(android.content.ContentResolver, long, long);
-    method public static android.net.Uri getContentUri(java.lang.String);
-    method public static deprecated android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, int, android.graphics.BitmapFactory.Options);
-    method public static deprecated android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, long, int, android.graphics.BitmapFactory.Options);
-    field public static final deprecated java.lang.String DATA = "_data";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "video_id ASC";
-    field public static final android.net.Uri EXTERNAL_CONTENT_URI;
-    field public static final int FULL_SCREEN_KIND = 2; // 0x2
-    field public static final java.lang.String HEIGHT = "height";
-    field public static final android.net.Uri INTERNAL_CONTENT_URI;
-    field public static final java.lang.String KIND = "kind";
-    field public static final int MICRO_KIND = 3; // 0x3
-    field public static final int MINI_KIND = 1; // 0x1
-    field public static final java.lang.String VIDEO_ID = "video_id";
-    field public static final java.lang.String WIDTH = "width";
+  @Deprecated public static class MediaStore.Video.Thumbnails implements android.provider.BaseColumns {
+    ctor @Deprecated public MediaStore.Video.Thumbnails();
+    method @Deprecated public static void cancelThumbnailRequest(android.content.ContentResolver, long);
+    method @Deprecated public static void cancelThumbnailRequest(android.content.ContentResolver, long, long);
+    method @Deprecated public static android.net.Uri getContentUri(String);
+    method @Deprecated public static android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, int, android.graphics.BitmapFactory.Options);
+    method @Deprecated public static android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, long, int, android.graphics.BitmapFactory.Options);
+    field @Deprecated public static final String DATA = "_data";
+    field @Deprecated public static final String DEFAULT_SORT_ORDER = "video_id ASC";
+    field @Deprecated public static final android.net.Uri EXTERNAL_CONTENT_URI;
+    field @Deprecated public static final int FULL_SCREEN_KIND = 2; // 0x2
+    field @Deprecated public static final String HEIGHT = "height";
+    field @Deprecated public static final android.net.Uri INTERNAL_CONTENT_URI;
+    field @Deprecated public static final String KIND = "kind";
+    field @Deprecated public static final int MICRO_KIND = 3; // 0x3
+    field @Deprecated public static final int MINI_KIND = 1; // 0x1
+    field @Deprecated public static final String VIDEO_ID = "video_id";
+    field @Deprecated public static final String WIDTH = "width";
   }
 
-  public static abstract interface MediaStore.Video.VideoColumns implements android.provider.MediaStore.MediaColumns {
-    field public static final java.lang.String ALBUM = "album";
-    field public static final java.lang.String ARTIST = "artist";
-    field public static final java.lang.String BOOKMARK = "bookmark";
-    field public static final java.lang.String BUCKET_DISPLAY_NAME = "bucket_display_name";
-    field public static final java.lang.String BUCKET_ID = "bucket_id";
-    field public static final java.lang.String CATEGORY = "category";
-    field public static final java.lang.String DATE_TAKEN = "datetaken";
-    field public static final java.lang.String DESCRIPTION = "description";
-    field public static final java.lang.String DURATION = "duration";
-    field public static final java.lang.String IS_PRIVATE = "isprivate";
-    field public static final java.lang.String LANGUAGE = "language";
-    field public static final deprecated java.lang.String LATITUDE = "latitude";
-    field public static final deprecated java.lang.String LONGITUDE = "longitude";
-    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";
+  public static interface MediaStore.Video.VideoColumns extends android.provider.MediaStore.MediaColumns {
+    field public static final String ALBUM = "album";
+    field public static final String ARTIST = "artist";
+    field public static final String BOOKMARK = "bookmark";
+    field public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
+    field public static final String BUCKET_ID = "bucket_id";
+    field public static final String CATEGORY = "category";
+    field public static final String DATE_TAKEN = "datetaken";
+    field public static final String DESCRIPTION = "description";
+    field public static final String DURATION = "duration";
+    field public static final String IS_PRIVATE = "isprivate";
+    field public static final String LANGUAGE = "language";
+    field @Deprecated public static final String LATITUDE = "latitude";
+    field @Deprecated public static final String LONGITUDE = "longitude";
+    field @Deprecated public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
+    field public static final String RESOLUTION = "resolution";
+    field public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id";
+    field public static final String TAGS = "tags";
   }
 
-  public abstract interface OpenableColumns {
-    field public static final java.lang.String DISPLAY_NAME = "_display_name";
-    field public static final java.lang.String SIZE = "_size";
+  public interface OpenableColumns {
+    field public static final String DISPLAY_NAME = "_display_name";
+    field public static final String SIZE = "_size";
   }
 
   public class SearchRecentSuggestions {
-    ctor public SearchRecentSuggestions(android.content.Context, java.lang.String, int);
+    ctor public SearchRecentSuggestions(android.content.Context, String, int);
     method public void clearHistory();
-    method public void saveRecentQuery(java.lang.String, java.lang.String);
+    method public void saveRecentQuery(String, String);
     method protected void truncateHistory(android.content.ContentResolver, int);
-    field public static final java.lang.String[] QUERIES_PROJECTION_1LINE;
-    field public static final java.lang.String[] QUERIES_PROJECTION_2LINE;
+    field public static final String[] QUERIES_PROJECTION_1LINE;
+    field public static final String[] QUERIES_PROJECTION_2LINE;
     field public static final int QUERIES_PROJECTION_DATE_INDEX = 1; // 0x1
     field public static final int QUERIES_PROJECTION_DISPLAY1_INDEX = 3; // 0x3
     field public static final int QUERIES_PROJECTION_DISPLAY2_INDEX = 4; // 0x4
@@ -38226,404 +38572,404 @@
   public final class Settings {
     ctor public Settings();
     method public static boolean canDrawOverlays(android.content.Context);
-    field public static final java.lang.String ACTION_ACCESSIBILITY_SETTINGS = "android.settings.ACCESSIBILITY_SETTINGS";
-    field public static final java.lang.String ACTION_ADD_ACCOUNT = "android.settings.ADD_ACCOUNT_SETTINGS";
-    field public static final java.lang.String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS";
-    field public static final java.lang.String ACTION_APN_SETTINGS = "android.settings.APN_SETTINGS";
-    field public static final java.lang.String ACTION_APPLICATION_DETAILS_SETTINGS = "android.settings.APPLICATION_DETAILS_SETTINGS";
-    field public static final java.lang.String ACTION_APPLICATION_DEVELOPMENT_SETTINGS = "android.settings.APPLICATION_DEVELOPMENT_SETTINGS";
-    field public static final java.lang.String ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS";
-    field public static final java.lang.String ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS";
-    field public static final java.lang.String ACTION_APP_SEARCH_SETTINGS = "android.settings.APP_SEARCH_SETTINGS";
-    field public static final java.lang.String ACTION_APP_USAGE_SETTINGS = "android.settings.action.APP_USAGE_SETTINGS";
-    field public static final java.lang.String ACTION_BATTERY_SAVER_SETTINGS = "android.settings.BATTERY_SAVER_SETTINGS";
-    field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
-    field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
-    field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
-    field public static final java.lang.String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
-    field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
-    field public static final java.lang.String ACTION_DATA_USAGE_SETTINGS = "android.settings.DATA_USAGE_SETTINGS";
-    field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
-    field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
-    field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
-    field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
-    field public static final java.lang.String ACTION_FINGERPRINT_ENROLL = "android.settings.FINGERPRINT_ENROLL";
-    field public static final java.lang.String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS";
-    field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS";
-    field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS";
-    field public static final java.lang.String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS";
-    field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
-    field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
-    field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
-    field public static final java.lang.String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
-    field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
-    field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
-    field public static final java.lang.String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
-    field public static final java.lang.String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
-    field public static final java.lang.String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
-    field public static final java.lang.String ACTION_MANAGE_UNKNOWN_APP_SOURCES = "android.settings.MANAGE_UNKNOWN_APP_SOURCES";
-    field public static final java.lang.String ACTION_MANAGE_WRITE_SETTINGS = "android.settings.action.MANAGE_WRITE_SETTINGS";
-    field public static final java.lang.String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS";
-    field public static final java.lang.String ACTION_NETWORK_OPERATOR_SETTINGS = "android.settings.NETWORK_OPERATOR_SETTINGS";
-    field public static final java.lang.String ACTION_NFCSHARING_SETTINGS = "android.settings.NFCSHARING_SETTINGS";
-    field public static final java.lang.String ACTION_NFC_PAYMENT_SETTINGS = "android.settings.NFC_PAYMENT_SETTINGS";
-    field public static final java.lang.String ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS";
-    field public static final java.lang.String ACTION_NIGHT_DISPLAY_SETTINGS = "android.settings.NIGHT_DISPLAY_SETTINGS";
-    field public static final java.lang.String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
-    field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
-    field public static final java.lang.String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
-    field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
-    field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
-    field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
-    field public static final java.lang.String ACTION_REQUEST_SET_AUTOFILL_SERVICE = "android.settings.REQUEST_SET_AUTOFILL_SERVICE";
-    field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
-    field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
-    field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
-    field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
-    field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
-    field public static final deprecated java.lang.String ACTION_STORAGE_VOLUME_ACCESS_SETTINGS = "android.settings.STORAGE_VOLUME_ACCESS_SETTINGS";
-    field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
-    field public static final java.lang.String ACTION_USAGE_ACCESS_SETTINGS = "android.settings.USAGE_ACCESS_SETTINGS";
-    field public static final java.lang.String ACTION_USER_DICTIONARY_SETTINGS = "android.settings.USER_DICTIONARY_SETTINGS";
-    field public static final java.lang.String ACTION_VOICE_CONTROL_AIRPLANE_MODE = "android.settings.VOICE_CONTROL_AIRPLANE_MODE";
-    field public static final java.lang.String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
-    field public static final java.lang.String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
-    field public static final java.lang.String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
-    field public static final java.lang.String ACTION_VPN_SETTINGS = "android.settings.VPN_SETTINGS";
-    field public static final java.lang.String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS";
-    field public static final java.lang.String ACTION_WEBVIEW_SETTINGS = "android.settings.WEBVIEW_SETTINGS";
-    field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
-    field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
-    field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS";
-    field public static final java.lang.String ACTION_ZEN_MODE_PRIORITY_SETTINGS = "android.settings.ZEN_MODE_PRIORITY_SETTINGS";
-    field public static final java.lang.String AUTHORITY = "settings";
-    field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types";
-    field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
-    field public static final java.lang.String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
-    field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
-    field public static final java.lang.String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
-    field public static final java.lang.String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
-    field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
-    field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
-    field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
-    field public static final java.lang.String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
-    field public static final java.lang.String INTENT_CATEGORY_USAGE_ACCESS_CONFIG = "android.intent.category.USAGE_ACCESS_CONFIG";
-    field public static final java.lang.String METADATA_USAGE_ACCESS_REASON = "android.settings.metadata.USAGE_ACCESS_REASON";
+    field public static final String ACTION_ACCESSIBILITY_SETTINGS = "android.settings.ACCESSIBILITY_SETTINGS";
+    field public static final String ACTION_ADD_ACCOUNT = "android.settings.ADD_ACCOUNT_SETTINGS";
+    field public static final String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS";
+    field public static final String ACTION_APN_SETTINGS = "android.settings.APN_SETTINGS";
+    field public static final String ACTION_APPLICATION_DETAILS_SETTINGS = "android.settings.APPLICATION_DETAILS_SETTINGS";
+    field public static final String ACTION_APPLICATION_DEVELOPMENT_SETTINGS = "android.settings.APPLICATION_DEVELOPMENT_SETTINGS";
+    field public static final String ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS";
+    field public static final String ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS";
+    field public static final String ACTION_APP_SEARCH_SETTINGS = "android.settings.APP_SEARCH_SETTINGS";
+    field public static final String ACTION_APP_USAGE_SETTINGS = "android.settings.action.APP_USAGE_SETTINGS";
+    field public static final String ACTION_BATTERY_SAVER_SETTINGS = "android.settings.BATTERY_SAVER_SETTINGS";
+    field public static final String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
+    field public static final String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
+    field public static final String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
+    field public static final String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
+    field public static final String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
+    field public static final String ACTION_DATA_USAGE_SETTINGS = "android.settings.DATA_USAGE_SETTINGS";
+    field public static final String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
+    field public static final String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
+    field public static final String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
+    field public static final String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
+    field public static final String ACTION_FINGERPRINT_ENROLL = "android.settings.FINGERPRINT_ENROLL";
+    field public static final String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS";
+    field public static final String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS";
+    field public static final String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS";
+    field public static final String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS";
+    field public static final String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
+    field public static final String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
+    field public static final String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
+    field public static final String ACTION_LOCALE_SETTINGS = "android.settings.LOCALE_SETTINGS";
+    field public static final String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
+    field public static final String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
+    field public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
+    field public static final String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
+    field public static final String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
+    field public static final String ACTION_MANAGE_UNKNOWN_APP_SOURCES = "android.settings.MANAGE_UNKNOWN_APP_SOURCES";
+    field public static final String ACTION_MANAGE_WRITE_SETTINGS = "android.settings.action.MANAGE_WRITE_SETTINGS";
+    field public static final String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS";
+    field public static final String ACTION_NETWORK_OPERATOR_SETTINGS = "android.settings.NETWORK_OPERATOR_SETTINGS";
+    field public static final String ACTION_NFCSHARING_SETTINGS = "android.settings.NFCSHARING_SETTINGS";
+    field public static final String ACTION_NFC_PAYMENT_SETTINGS = "android.settings.NFC_PAYMENT_SETTINGS";
+    field public static final String ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS";
+    field public static final String ACTION_NIGHT_DISPLAY_SETTINGS = "android.settings.NIGHT_DISPLAY_SETTINGS";
+    field public static final String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
+    field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
+    field public static final String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
+    field public static final String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
+    field public static final String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
+    field public static final String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+    field public static final String ACTION_REQUEST_SET_AUTOFILL_SERVICE = "android.settings.REQUEST_SET_AUTOFILL_SERVICE";
+    field public static final String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
+    field public static final String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
+    field public static final String ACTION_SETTINGS = "android.settings.SETTINGS";
+    field public static final String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
+    field public static final String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
+    field @Deprecated public static final String ACTION_STORAGE_VOLUME_ACCESS_SETTINGS = "android.settings.STORAGE_VOLUME_ACCESS_SETTINGS";
+    field public static final String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
+    field public static final String ACTION_USAGE_ACCESS_SETTINGS = "android.settings.USAGE_ACCESS_SETTINGS";
+    field public static final String ACTION_USER_DICTIONARY_SETTINGS = "android.settings.USER_DICTIONARY_SETTINGS";
+    field public static final String ACTION_VOICE_CONTROL_AIRPLANE_MODE = "android.settings.VOICE_CONTROL_AIRPLANE_MODE";
+    field public static final String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
+    field public static final String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
+    field public static final String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
+    field public static final String ACTION_VPN_SETTINGS = "android.settings.VPN_SETTINGS";
+    field public static final String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS";
+    field public static final String ACTION_WEBVIEW_SETTINGS = "android.settings.WEBVIEW_SETTINGS";
+    field public static final String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
+    field public static final String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
+    field public static final String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS";
+    field public static final String ACTION_ZEN_MODE_PRIORITY_SETTINGS = "android.settings.ZEN_MODE_PRIORITY_SETTINGS";
+    field public static final String AUTHORITY = "settings";
+    field public static final String EXTRA_ACCOUNT_TYPES = "account_types";
+    field public static final String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
+    field public static final String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
+    field public static final String EXTRA_AUTHORITIES = "authorities";
+    field public static final String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
+    field public static final String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
+    field public static final String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
+    field public static final String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
+    field public static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
+    field public static final String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
+    field public static final String INTENT_CATEGORY_USAGE_ACCESS_CONFIG = "android.intent.category.USAGE_ACCESS_CONFIG";
+    field public static final String METADATA_USAGE_ACCESS_REASON = "android.settings.metadata.USAGE_ACCESS_REASON";
   }
 
   public static final class Settings.Global extends android.provider.Settings.NameValueTable {
     ctor public Settings.Global();
-    method public static float getFloat(android.content.ContentResolver, java.lang.String, float);
-    method public static float getFloat(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
-    method public static int getInt(android.content.ContentResolver, java.lang.String, int);
-    method public static int getInt(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
-    method public static long getLong(android.content.ContentResolver, java.lang.String, long);
-    method public static long getLong(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
-    method public static java.lang.String getString(android.content.ContentResolver, java.lang.String);
-    method public static android.net.Uri getUriFor(java.lang.String);
-    method public static boolean putFloat(android.content.ContentResolver, java.lang.String, float);
-    method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
-    method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
-    method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
-    field public static final java.lang.String ADB_ENABLED = "adb_enabled";
-    field public static final java.lang.String AIRPLANE_MODE_ON = "airplane_mode_on";
-    field public static final java.lang.String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
-    field public static final java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
-    field public static final java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
-    field public static final java.lang.String AUTO_TIME = "auto_time";
-    field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
-    field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on";
-    field public static final java.lang.String BOOT_COUNT = "boot_count";
-    field public static final java.lang.String CONTACT_METADATA_SYNC_ENABLED = "contact_metadata_sync_enabled";
+    method public static float getFloat(android.content.ContentResolver, String, float);
+    method public static float getFloat(android.content.ContentResolver, String) throws android.provider.Settings.SettingNotFoundException;
+    method public static int getInt(android.content.ContentResolver, String, int);
+    method public static int getInt(android.content.ContentResolver, String) throws android.provider.Settings.SettingNotFoundException;
+    method public static long getLong(android.content.ContentResolver, String, long);
+    method public static long getLong(android.content.ContentResolver, String) throws android.provider.Settings.SettingNotFoundException;
+    method public static String getString(android.content.ContentResolver, String);
+    method public static android.net.Uri getUriFor(String);
+    method public static boolean putFloat(android.content.ContentResolver, String, float);
+    method public static boolean putInt(android.content.ContentResolver, String, int);
+    method public static boolean putLong(android.content.ContentResolver, String, long);
+    method public static boolean putString(android.content.ContentResolver, String, String);
+    field public static final String ADB_ENABLED = "adb_enabled";
+    field public static final String AIRPLANE_MODE_ON = "airplane_mode_on";
+    field public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
+    field public static final String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
+    field public static final String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
+    field public static final String AUTO_TIME = "auto_time";
+    field public static final String AUTO_TIME_ZONE = "auto_time_zone";
+    field public static final String BLUETOOTH_ON = "bluetooth_on";
+    field public static final String BOOT_COUNT = "boot_count";
+    field public static final String CONTACT_METADATA_SYNC_ENABLED = "contact_metadata_sync_enabled";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DATA_ROAMING = "data_roaming";
-    field public static final java.lang.String DEBUG_APP = "debug_app";
-    field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
-    field public static final java.lang.String DEVICE_NAME = "device_name";
-    field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
-    field public static final java.lang.String HTTP_PROXY = "http_proxy";
-    field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
-    field public static final java.lang.String MODE_RINGER = "mode_ringer";
-    field public static final java.lang.String NETWORK_PREFERENCE = "network_preference";
-    field public static final java.lang.String RADIO_BLUETOOTH = "bluetooth";
-    field public static final java.lang.String RADIO_CELL = "cell";
-    field public static final java.lang.String RADIO_NFC = "nfc";
-    field public static final java.lang.String RADIO_WIFI = "wifi";
-    field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
-    field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
-    field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
-    field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
-    field public static final java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
-    field public static final java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
-    field public static final java.lang.String WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN = "wifi_device_owner_configs_lockdown";
-    field public static final java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
-    field public static final java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
-    field public static final deprecated java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
-    field public static final java.lang.String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay";
-    field public static final java.lang.String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
-    field public static final java.lang.String WIFI_ON = "wifi_on";
-    field public static final java.lang.String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
+    field public static final String DATA_ROAMING = "data_roaming";
+    field public static final String DEBUG_APP = "debug_app";
+    field public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+    field public static final String DEVICE_NAME = "device_name";
+    field public static final String DEVICE_PROVISIONED = "device_provisioned";
+    field public static final String HTTP_PROXY = "http_proxy";
+    field @Deprecated public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+    field public static final String MODE_RINGER = "mode_ringer";
+    field public static final String NETWORK_PREFERENCE = "network_preference";
+    field public static final String RADIO_BLUETOOTH = "bluetooth";
+    field public static final String RADIO_CELL = "cell";
+    field public static final String RADIO_NFC = "nfc";
+    field public static final String RADIO_WIFI = "wifi";
+    field @Deprecated public static final String SHOW_PROCESSES = "show_processes";
+    field public static final String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
+    field public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
+    field public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
+    field public static final String USE_GOOGLE_MAIL = "use_google_mail";
+    field public static final String WAIT_FOR_DEBUGGER = "wait_for_debugger";
+    field public static final String WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN = "wifi_device_owner_configs_lockdown";
+    field public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
+    field public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
+    field @Deprecated public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
+    field public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay";
+    field public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
+    field public static final String WIFI_ON = "wifi_on";
+    field public static final String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
     field public static final int WIFI_SLEEP_POLICY_DEFAULT = 0; // 0x0
     field public static final int WIFI_SLEEP_POLICY_NEVER = 2; // 0x2
     field public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; // 0x1
-    field public static final java.lang.String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
-    field public static final java.lang.String WINDOW_ANIMATION_SCALE = "window_animation_scale";
+    field public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
+    field public static final String WINDOW_ANIMATION_SCALE = "window_animation_scale";
   }
 
   public static class Settings.NameValueTable implements android.provider.BaseColumns {
     ctor public Settings.NameValueTable();
-    method public static android.net.Uri getUriFor(android.net.Uri, java.lang.String);
-    method protected static boolean putString(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
-    field public static final java.lang.String NAME = "name";
-    field public static final java.lang.String VALUE = "value";
+    method public static android.net.Uri getUriFor(android.net.Uri, String);
+    method protected static boolean putString(android.content.ContentResolver, android.net.Uri, String, String);
+    field public static final String NAME = "name";
+    field public static final String VALUE = "value";
   }
 
   public static final class Settings.Panel {
-    field public static final java.lang.String ACTION_INTERNET_CONNECTIVITY = "android.settings.panel.action.INTERNET_CONNECTIVITY";
-    field public static final java.lang.String ACTION_VOLUME = "android.settings.panel.action.VOLUME";
+    field public static final String ACTION_INTERNET_CONNECTIVITY = "android.settings.panel.action.INTERNET_CONNECTIVITY";
+    field public static final String ACTION_VOLUME = "android.settings.panel.action.VOLUME";
   }
 
   public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
     ctor public Settings.Secure();
-    method public static float getFloat(android.content.ContentResolver, java.lang.String, float);
-    method public static float getFloat(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
-    method public static int getInt(android.content.ContentResolver, java.lang.String, int);
-    method public static int getInt(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
-    method public static long getLong(android.content.ContentResolver, java.lang.String, long);
-    method public static long getLong(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
-    method public static java.lang.String getString(android.content.ContentResolver, java.lang.String);
-    method public static android.net.Uri getUriFor(java.lang.String);
-    method public static deprecated boolean isLocationProviderEnabled(android.content.ContentResolver, java.lang.String);
-    method public static boolean putFloat(android.content.ContentResolver, java.lang.String, float);
-    method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
-    method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
-    method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
-    method public static deprecated void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean);
-    field public static final java.lang.String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED = "accessibility_display_inversion_enabled";
-    field public static final java.lang.String ACCESSIBILITY_ENABLED = "accessibility_enabled";
-    field public static final deprecated java.lang.String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
-    field public static final deprecated java.lang.String ADB_ENABLED = "adb_enabled";
-    field public static final java.lang.String ALLOWED_GEOLOCATION_ORIGINS = "allowed_geolocation_origins";
-    field public static final deprecated java.lang.String ALLOW_MOCK_LOCATION = "mock_location";
-    field public static final java.lang.String ANDROID_ID = "android_id";
-    field public static final deprecated java.lang.String BACKGROUND_DATA = "background_data";
-    field public static final deprecated java.lang.String BLUETOOTH_ON = "bluetooth_on";
+    method public static float getFloat(android.content.ContentResolver, String, float);
+    method public static float getFloat(android.content.ContentResolver, String) throws android.provider.Settings.SettingNotFoundException;
+    method public static int getInt(android.content.ContentResolver, String, int);
+    method public static int getInt(android.content.ContentResolver, String) throws android.provider.Settings.SettingNotFoundException;
+    method public static long getLong(android.content.ContentResolver, String, long);
+    method public static long getLong(android.content.ContentResolver, String) throws android.provider.Settings.SettingNotFoundException;
+    method public static String getString(android.content.ContentResolver, String);
+    method public static android.net.Uri getUriFor(String);
+    method @Deprecated public static boolean isLocationProviderEnabled(android.content.ContentResolver, String);
+    method public static boolean putFloat(android.content.ContentResolver, String, float);
+    method public static boolean putInt(android.content.ContentResolver, String, int);
+    method public static boolean putLong(android.content.ContentResolver, String, long);
+    method public static boolean putString(android.content.ContentResolver, String, String);
+    method @Deprecated public static void setLocationProviderEnabled(android.content.ContentResolver, String, boolean);
+    field public static final String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED = "accessibility_display_inversion_enabled";
+    field public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
+    field @Deprecated public static final String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
+    field @Deprecated public static final String ADB_ENABLED = "adb_enabled";
+    field public static final String ALLOWED_GEOLOCATION_ORIGINS = "allowed_geolocation_origins";
+    field @Deprecated public static final String ALLOW_MOCK_LOCATION = "mock_location";
+    field public static final String ANDROID_ID = "android_id";
+    field @Deprecated public static final String BACKGROUND_DATA = "background_data";
+    field @Deprecated public static final String BLUETOOTH_ON = "bluetooth_on";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final deprecated java.lang.String DATA_ROAMING = "data_roaming";
-    field public static final java.lang.String DEFAULT_INPUT_METHOD = "default_input_method";
-    field public static final deprecated java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
-    field public static final deprecated java.lang.String DEVICE_PROVISIONED = "device_provisioned";
-    field public static final java.lang.String ENABLED_ACCESSIBILITY_SERVICES = "enabled_accessibility_services";
-    field public static final java.lang.String ENABLED_INPUT_METHODS = "enabled_input_methods";
-    field public static final deprecated java.lang.String HTTP_PROXY = "http_proxy";
-    field public static final java.lang.String INPUT_METHOD_SELECTOR_VISIBILITY = "input_method_selector_visibility";
-    field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
-    field public static final deprecated java.lang.String LOCATION_MODE = "location_mode";
-    field public static final deprecated int LOCATION_MODE_BATTERY_SAVING = 2; // 0x2
-    field public static final deprecated int LOCATION_MODE_HIGH_ACCURACY = 3; // 0x3
-    field public static final deprecated int LOCATION_MODE_OFF = 0; // 0x0
-    field public static final deprecated int LOCATION_MODE_SENSORS_ONLY = 1; // 0x1
-    field public static final deprecated java.lang.String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
-    field public static final deprecated java.lang.String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
-    field public static final deprecated java.lang.String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
-    field public static final deprecated java.lang.String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern";
-    field public static final deprecated java.lang.String LOGGING_ID = "logging_id";
-    field public static final deprecated java.lang.String NETWORK_PREFERENCE = "network_preference";
-    field public static final java.lang.String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
-    field public static final java.lang.String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
-    field public static final java.lang.String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
-    field public static final java.lang.String RTT_CALLING_MODE = "rtt_calling_mode";
-    field public static final java.lang.String SELECTED_INPUT_METHOD_SUBTYPE = "selected_input_method_subtype";
-    field public static final java.lang.String SETTINGS_CLASSNAME = "settings_classname";
-    field public static final java.lang.String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
-    field public static final java.lang.String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled";
-    field public static final deprecated java.lang.String TTS_DEFAULT_COUNTRY = "tts_default_country";
-    field public static final deprecated java.lang.String TTS_DEFAULT_LANG = "tts_default_lang";
-    field public static final java.lang.String TTS_DEFAULT_PITCH = "tts_default_pitch";
-    field public static final java.lang.String TTS_DEFAULT_RATE = "tts_default_rate";
-    field public static final java.lang.String TTS_DEFAULT_SYNTH = "tts_default_synth";
-    field public static final deprecated java.lang.String TTS_DEFAULT_VARIANT = "tts_default_variant";
-    field public static final java.lang.String TTS_ENABLED_PLUGINS = "tts_enabled_plugins";
-    field public static final deprecated java.lang.String TTS_USE_DEFAULTS = "tts_use_defaults";
-    field public static final deprecated java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
-    field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
-    field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
-    field public static final deprecated java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
-    field public static final deprecated java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
-    field public static final deprecated java.lang.String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay";
-    field public static final deprecated java.lang.String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
-    field public static final deprecated java.lang.String WIFI_ON = "wifi_on";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE = "wifi_watchdog_acceptable_packet_loss_percentage";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_AP_COUNT = "wifi_watchdog_ap_count";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS = "wifi_watchdog_background_check_delay_ms";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED = "wifi_watchdog_background_check_enabled";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS = "wifi_watchdog_background_check_timeout_ms";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = "wifi_watchdog_initial_ignored_ping_count";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_MAX_AP_CHECKS = "wifi_watchdog_max_ap_checks";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_WATCH_LIST = "wifi_watchdog_watch_list";
+    field @Deprecated public static final String DATA_ROAMING = "data_roaming";
+    field public static final String DEFAULT_INPUT_METHOD = "default_input_method";
+    field @Deprecated public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+    field @Deprecated public static final String DEVICE_PROVISIONED = "device_provisioned";
+    field public static final String ENABLED_ACCESSIBILITY_SERVICES = "enabled_accessibility_services";
+    field public static final String ENABLED_INPUT_METHODS = "enabled_input_methods";
+    field @Deprecated public static final String HTTP_PROXY = "http_proxy";
+    field public static final String INPUT_METHOD_SELECTOR_VISIBILITY = "input_method_selector_visibility";
+    field @Deprecated public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+    field @Deprecated public static final String LOCATION_MODE = "location_mode";
+    field @Deprecated public static final int LOCATION_MODE_BATTERY_SAVING = 2; // 0x2
+    field @Deprecated public static final int LOCATION_MODE_HIGH_ACCURACY = 3; // 0x3
+    field @Deprecated public static final int LOCATION_MODE_OFF = 0; // 0x0
+    field @Deprecated public static final int LOCATION_MODE_SENSORS_ONLY = 1; // 0x1
+    field @Deprecated public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
+    field @Deprecated public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
+    field @Deprecated public static final String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
+    field @Deprecated public static final String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern";
+    field @Deprecated public static final String LOGGING_ID = "logging_id";
+    field @Deprecated public static final String NETWORK_PREFERENCE = "network_preference";
+    field public static final String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
+    field public static final String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
+    field public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
+    field public static final String RTT_CALLING_MODE = "rtt_calling_mode";
+    field public static final String SELECTED_INPUT_METHOD_SUBTYPE = "selected_input_method_subtype";
+    field public static final String SETTINGS_CLASSNAME = "settings_classname";
+    field public static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
+    field public static final String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled";
+    field @Deprecated public static final String TTS_DEFAULT_COUNTRY = "tts_default_country";
+    field @Deprecated public static final String TTS_DEFAULT_LANG = "tts_default_lang";
+    field public static final String TTS_DEFAULT_PITCH = "tts_default_pitch";
+    field public static final String TTS_DEFAULT_RATE = "tts_default_rate";
+    field public static final String TTS_DEFAULT_SYNTH = "tts_default_synth";
+    field @Deprecated public static final String TTS_DEFAULT_VARIANT = "tts_default_variant";
+    field public static final String TTS_ENABLED_PLUGINS = "tts_enabled_plugins";
+    field @Deprecated public static final String TTS_USE_DEFAULTS = "tts_use_defaults";
+    field @Deprecated public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
+    field @Deprecated public static final String USE_GOOGLE_MAIL = "use_google_mail";
+    field @Deprecated public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
+    field @Deprecated public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
+    field @Deprecated public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
+    field @Deprecated public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay";
+    field @Deprecated public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
+    field @Deprecated public static final String WIFI_ON = "wifi_on";
+    field @Deprecated public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE = "wifi_watchdog_acceptable_packet_loss_percentage";
+    field @Deprecated public static final String WIFI_WATCHDOG_AP_COUNT = "wifi_watchdog_ap_count";
+    field @Deprecated public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS = "wifi_watchdog_background_check_delay_ms";
+    field @Deprecated public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED = "wifi_watchdog_background_check_enabled";
+    field @Deprecated public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS = "wifi_watchdog_background_check_timeout_ms";
+    field @Deprecated public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = "wifi_watchdog_initial_ignored_ping_count";
+    field @Deprecated public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = "wifi_watchdog_max_ap_checks";
+    field @Deprecated public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
+    field @Deprecated public static final String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count";
+    field @Deprecated public static final String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms";
+    field @Deprecated public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms";
+    field @Deprecated public static final String WIFI_WATCHDOG_WATCH_LIST = "wifi_watchdog_watch_list";
   }
 
   public static class Settings.SettingNotFoundException extends android.util.AndroidException {
-    ctor public Settings.SettingNotFoundException(java.lang.String);
+    ctor public Settings.SettingNotFoundException(String);
   }
 
   public static final class Settings.System extends android.provider.Settings.NameValueTable {
     ctor public Settings.System();
     method public static boolean canWrite(android.content.Context);
     method public static void getConfiguration(android.content.ContentResolver, android.content.res.Configuration);
-    method public static float getFloat(android.content.ContentResolver, java.lang.String, float);
-    method public static float getFloat(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
-    method public static int getInt(android.content.ContentResolver, java.lang.String, int);
-    method public static int getInt(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
-    method public static long getLong(android.content.ContentResolver, java.lang.String, long);
-    method public static long getLong(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
-    method public static deprecated boolean getShowGTalkServiceStatus(android.content.ContentResolver);
-    method public static java.lang.String getString(android.content.ContentResolver, java.lang.String);
-    method public static android.net.Uri getUriFor(java.lang.String);
+    method public static float getFloat(android.content.ContentResolver, String, float);
+    method public static float getFloat(android.content.ContentResolver, String) throws android.provider.Settings.SettingNotFoundException;
+    method public static int getInt(android.content.ContentResolver, String, int);
+    method public static int getInt(android.content.ContentResolver, String) throws android.provider.Settings.SettingNotFoundException;
+    method public static long getLong(android.content.ContentResolver, String, long);
+    method public static long getLong(android.content.ContentResolver, String) throws android.provider.Settings.SettingNotFoundException;
+    method @Deprecated public static boolean getShowGTalkServiceStatus(android.content.ContentResolver);
+    method public static String getString(android.content.ContentResolver, String);
+    method public static android.net.Uri getUriFor(String);
     method public static boolean putConfiguration(android.content.ContentResolver, android.content.res.Configuration);
-    method public static boolean putFloat(android.content.ContentResolver, java.lang.String, float);
-    method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
-    method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
-    method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
-    method public static deprecated void setShowGTalkServiceStatus(android.content.ContentResolver, boolean);
-    field public static final java.lang.String ACCELEROMETER_ROTATION = "accelerometer_rotation";
-    field public static final deprecated java.lang.String ADB_ENABLED = "adb_enabled";
-    field public static final deprecated java.lang.String AIRPLANE_MODE_ON = "airplane_mode_on";
-    field public static final deprecated java.lang.String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
-    field public static final java.lang.String ALARM_ALERT = "alarm_alert";
-    field public static final deprecated java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
-    field public static final deprecated java.lang.String ANDROID_ID = "android_id";
-    field public static final deprecated java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
-    field public static final deprecated java.lang.String AUTO_TIME = "auto_time";
-    field public static final deprecated java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
-    field public static final java.lang.String BLUETOOTH_DISCOVERABILITY = "bluetooth_discoverability";
-    field public static final java.lang.String BLUETOOTH_DISCOVERABILITY_TIMEOUT = "bluetooth_discoverability_timeout";
-    field public static final deprecated java.lang.String BLUETOOTH_ON = "bluetooth_on";
+    method public static boolean putFloat(android.content.ContentResolver, String, float);
+    method public static boolean putInt(android.content.ContentResolver, String, int);
+    method public static boolean putLong(android.content.ContentResolver, String, long);
+    method public static boolean putString(android.content.ContentResolver, String, String);
+    method @Deprecated public static void setShowGTalkServiceStatus(android.content.ContentResolver, boolean);
+    field public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
+    field @Deprecated public static final String ADB_ENABLED = "adb_enabled";
+    field @Deprecated public static final String AIRPLANE_MODE_ON = "airplane_mode_on";
+    field @Deprecated public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
+    field public static final String ALARM_ALERT = "alarm_alert";
+    field @Deprecated public static final String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
+    field @Deprecated public static final String ANDROID_ID = "android_id";
+    field @Deprecated public static final String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
+    field @Deprecated public static final String AUTO_TIME = "auto_time";
+    field @Deprecated public static final String AUTO_TIME_ZONE = "auto_time_zone";
+    field public static final String BLUETOOTH_DISCOVERABILITY = "bluetooth_discoverability";
+    field public static final String BLUETOOTH_DISCOVERABILITY_TIMEOUT = "bluetooth_discoverability_timeout";
+    field @Deprecated public static final String BLUETOOTH_ON = "bluetooth_on";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final deprecated java.lang.String DATA_ROAMING = "data_roaming";
-    field public static final java.lang.String DATE_FORMAT = "date_format";
-    field public static final deprecated java.lang.String DEBUG_APP = "debug_app";
+    field @Deprecated public static final String DATA_ROAMING = "data_roaming";
+    field public static final String DATE_FORMAT = "date_format";
+    field @Deprecated public static final String DEBUG_APP = "debug_app";
     field public static final android.net.Uri DEFAULT_ALARM_ALERT_URI;
     field public static final android.net.Uri DEFAULT_NOTIFICATION_URI;
     field public static final android.net.Uri DEFAULT_RINGTONE_URI;
-    field public static final deprecated java.lang.String DEVICE_PROVISIONED = "device_provisioned";
-    field public static final deprecated java.lang.String DIM_SCREEN = "dim_screen";
-    field public static final java.lang.String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
-    field public static final java.lang.String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
-    field public static final java.lang.String END_BUTTON_BEHAVIOR = "end_button_behavior";
-    field public static final java.lang.String FONT_SCALE = "font_scale";
-    field public static final java.lang.String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
-    field public static final deprecated java.lang.String HTTP_PROXY = "http_proxy";
-    field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
-    field public static final deprecated java.lang.String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
-    field public static final deprecated java.lang.String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
-    field public static final deprecated java.lang.String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
-    field public static final deprecated java.lang.String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern";
-    field public static final deprecated java.lang.String LOGGING_ID = "logging_id";
-    field public static final deprecated java.lang.String MODE_RINGER = "mode_ringer";
-    field public static final java.lang.String MODE_RINGER_STREAMS_AFFECTED = "mode_ringer_streams_affected";
-    field public static final java.lang.String MUTE_STREAMS_AFFECTED = "mute_streams_affected";
-    field public static final deprecated java.lang.String NETWORK_PREFERENCE = "network_preference";
-    field public static final deprecated java.lang.String NEXT_ALARM_FORMATTED = "next_alarm_formatted";
-    field public static final java.lang.String NOTIFICATION_SOUND = "notification_sound";
-    field public static final deprecated java.lang.String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
-    field public static final deprecated java.lang.String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
-    field public static final deprecated java.lang.String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
-    field public static final deprecated java.lang.String RADIO_BLUETOOTH = "bluetooth";
-    field public static final deprecated java.lang.String RADIO_CELL = "cell";
-    field public static final deprecated java.lang.String RADIO_NFC = "nfc";
-    field public static final deprecated java.lang.String RADIO_WIFI = "wifi";
-    field public static final java.lang.String RINGTONE = "ringtone";
-    field public static final java.lang.String SCREEN_BRIGHTNESS = "screen_brightness";
-    field public static final java.lang.String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
+    field @Deprecated public static final String DEVICE_PROVISIONED = "device_provisioned";
+    field @Deprecated public static final String DIM_SCREEN = "dim_screen";
+    field public static final String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
+    field public static final String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
+    field public static final String END_BUTTON_BEHAVIOR = "end_button_behavior";
+    field public static final String FONT_SCALE = "font_scale";
+    field public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
+    field @Deprecated public static final String HTTP_PROXY = "http_proxy";
+    field @Deprecated public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+    field @Deprecated public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
+    field @Deprecated public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
+    field @Deprecated public static final String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
+    field @Deprecated public static final String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern";
+    field @Deprecated public static final String LOGGING_ID = "logging_id";
+    field @Deprecated public static final String MODE_RINGER = "mode_ringer";
+    field public static final String MODE_RINGER_STREAMS_AFFECTED = "mode_ringer_streams_affected";
+    field public static final String MUTE_STREAMS_AFFECTED = "mute_streams_affected";
+    field @Deprecated public static final String NETWORK_PREFERENCE = "network_preference";
+    field @Deprecated public static final String NEXT_ALARM_FORMATTED = "next_alarm_formatted";
+    field public static final String NOTIFICATION_SOUND = "notification_sound";
+    field @Deprecated public static final String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
+    field @Deprecated public static final String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
+    field @Deprecated public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
+    field @Deprecated public static final String RADIO_BLUETOOTH = "bluetooth";
+    field @Deprecated public static final String RADIO_CELL = "cell";
+    field @Deprecated public static final String RADIO_NFC = "nfc";
+    field @Deprecated public static final String RADIO_WIFI = "wifi";
+    field public static final String RINGTONE = "ringtone";
+    field public static final String SCREEN_BRIGHTNESS = "screen_brightness";
+    field public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
     field public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1; // 0x1
     field public static final int SCREEN_BRIGHTNESS_MODE_MANUAL = 0; // 0x0
-    field public static final java.lang.String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
-    field public static final deprecated java.lang.String SETTINGS_CLASSNAME = "settings_classname";
-    field public static final java.lang.String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run";
-    field public static final java.lang.String SHOW_GTALK_SERVICE_STATUS = "SHOW_GTALK_SERVICE_STATUS";
-    field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
-    field public static final deprecated java.lang.String SHOW_WEB_SUGGESTIONS = "show_web_suggestions";
-    field public static final java.lang.String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
-    field public static final deprecated java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
-    field public static final java.lang.String TEXT_AUTO_CAPS = "auto_caps";
-    field public static final java.lang.String TEXT_AUTO_PUNCTUATE = "auto_punctuate";
-    field public static final java.lang.String TEXT_AUTO_REPLACE = "auto_replace";
-    field public static final java.lang.String TEXT_SHOW_PASSWORD = "show_password";
-    field public static final java.lang.String TIME_12_24 = "time_12_24";
-    field public static final deprecated java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
-    field public static final deprecated java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
-    field public static final java.lang.String USER_ROTATION = "user_rotation";
-    field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
-    field public static final java.lang.String VIBRATE_ON = "vibrate_on";
-    field public static final java.lang.String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
-    field public static final deprecated java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
-    field public static final deprecated java.lang.String WALLPAPER_ACTIVITY = "wallpaper_activity";
-    field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
-    field public static final deprecated java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
-    field public static final deprecated java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
-    field public static final deprecated java.lang.String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay";
-    field public static final deprecated java.lang.String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
-    field public static final deprecated java.lang.String WIFI_ON = "wifi_on";
-    field public static final deprecated java.lang.String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
-    field public static final deprecated int WIFI_SLEEP_POLICY_DEFAULT = 0; // 0x0
-    field public static final deprecated int WIFI_SLEEP_POLICY_NEVER = 2; // 0x2
-    field public static final deprecated int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; // 0x1
-    field public static final deprecated java.lang.String WIFI_STATIC_DNS1 = "wifi_static_dns1";
-    field public static final deprecated java.lang.String WIFI_STATIC_DNS2 = "wifi_static_dns2";
-    field public static final deprecated java.lang.String WIFI_STATIC_GATEWAY = "wifi_static_gateway";
-    field public static final deprecated java.lang.String WIFI_STATIC_IP = "wifi_static_ip";
-    field public static final deprecated java.lang.String WIFI_STATIC_NETMASK = "wifi_static_netmask";
-    field public static final deprecated java.lang.String WIFI_USE_STATIC_IP = "wifi_use_static_ip";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE = "wifi_watchdog_acceptable_packet_loss_percentage";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_AP_COUNT = "wifi_watchdog_ap_count";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS = "wifi_watchdog_background_check_delay_ms";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED = "wifi_watchdog_background_check_enabled";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS = "wifi_watchdog_background_check_timeout_ms";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = "wifi_watchdog_initial_ignored_ping_count";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_MAX_AP_CHECKS = "wifi_watchdog_max_ap_checks";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms";
-    field public static final deprecated java.lang.String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms";
-    field public static final deprecated java.lang.String WINDOW_ANIMATION_SCALE = "window_animation_scale";
+    field public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
+    field @Deprecated public static final String SETTINGS_CLASSNAME = "settings_classname";
+    field public static final String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run";
+    field public static final String SHOW_GTALK_SERVICE_STATUS = "SHOW_GTALK_SERVICE_STATUS";
+    field @Deprecated public static final String SHOW_PROCESSES = "show_processes";
+    field @Deprecated public static final String SHOW_WEB_SUGGESTIONS = "show_web_suggestions";
+    field public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
+    field @Deprecated public static final String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
+    field public static final String TEXT_AUTO_CAPS = "auto_caps";
+    field public static final String TEXT_AUTO_PUNCTUATE = "auto_punctuate";
+    field public static final String TEXT_AUTO_REPLACE = "auto_replace";
+    field public static final String TEXT_SHOW_PASSWORD = "show_password";
+    field public static final String TIME_12_24 = "time_12_24";
+    field @Deprecated public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
+    field @Deprecated public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
+    field public static final String USER_ROTATION = "user_rotation";
+    field @Deprecated public static final String USE_GOOGLE_MAIL = "use_google_mail";
+    field public static final String VIBRATE_ON = "vibrate_on";
+    field public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
+    field @Deprecated public static final String WAIT_FOR_DEBUGGER = "wait_for_debugger";
+    field @Deprecated public static final String WALLPAPER_ACTIVITY = "wallpaper_activity";
+    field @Deprecated public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
+    field @Deprecated public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
+    field @Deprecated public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
+    field @Deprecated public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay";
+    field @Deprecated public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
+    field @Deprecated public static final String WIFI_ON = "wifi_on";
+    field @Deprecated public static final String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
+    field @Deprecated public static final int WIFI_SLEEP_POLICY_DEFAULT = 0; // 0x0
+    field @Deprecated public static final int WIFI_SLEEP_POLICY_NEVER = 2; // 0x2
+    field @Deprecated public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; // 0x1
+    field @Deprecated public static final String WIFI_STATIC_DNS1 = "wifi_static_dns1";
+    field @Deprecated public static final String WIFI_STATIC_DNS2 = "wifi_static_dns2";
+    field @Deprecated public static final String WIFI_STATIC_GATEWAY = "wifi_static_gateway";
+    field @Deprecated public static final String WIFI_STATIC_IP = "wifi_static_ip";
+    field @Deprecated public static final String WIFI_STATIC_NETMASK = "wifi_static_netmask";
+    field @Deprecated public static final String WIFI_USE_STATIC_IP = "wifi_use_static_ip";
+    field @Deprecated public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE = "wifi_watchdog_acceptable_packet_loss_percentage";
+    field @Deprecated public static final String WIFI_WATCHDOG_AP_COUNT = "wifi_watchdog_ap_count";
+    field @Deprecated public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS = "wifi_watchdog_background_check_delay_ms";
+    field @Deprecated public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED = "wifi_watchdog_background_check_enabled";
+    field @Deprecated public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS = "wifi_watchdog_background_check_timeout_ms";
+    field @Deprecated public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = "wifi_watchdog_initial_ignored_ping_count";
+    field @Deprecated public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = "wifi_watchdog_max_ap_checks";
+    field @Deprecated public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
+    field @Deprecated public static final String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count";
+    field @Deprecated public static final String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms";
+    field @Deprecated public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms";
+    field @Deprecated public static final String WINDOW_ANIMATION_SCALE = "window_animation_scale";
   }
 
   public class SettingsSlicesContract {
-    field public static final java.lang.String AUTHORITY = "android.settings.slices";
+    field public static final String AUTHORITY = "android.settings.slices";
     field public static final android.net.Uri BASE_URI;
-    field public static final java.lang.String KEY_AIRPLANE_MODE = "airplane_mode";
-    field public static final java.lang.String KEY_BATTERY_SAVER = "battery_saver";
-    field public static final java.lang.String KEY_BLUETOOTH = "bluetooth";
-    field public static final java.lang.String KEY_LOCATION = "location";
-    field public static final java.lang.String KEY_WIFI = "wifi";
-    field public static final java.lang.String PATH_SETTING_ACTION = "action";
-    field public static final java.lang.String PATH_SETTING_INTENT = "intent";
+    field public static final String KEY_AIRPLANE_MODE = "airplane_mode";
+    field public static final String KEY_BATTERY_SAVER = "battery_saver";
+    field public static final String KEY_BLUETOOTH = "bluetooth";
+    field public static final String KEY_LOCATION = "location";
+    field public static final String KEY_WIFI = "wifi";
+    field public static final String PATH_SETTING_ACTION = "action";
+    field public static final String PATH_SETTING_INTENT = "intent";
   }
 
   public class SyncStateContract {
     ctor public SyncStateContract();
   }
 
-  public static abstract interface SyncStateContract.Columns implements android.provider.BaseColumns {
-    field public static final java.lang.String ACCOUNT_NAME = "account_name";
-    field public static final java.lang.String ACCOUNT_TYPE = "account_type";
-    field public static final java.lang.String DATA = "data";
+  public static interface SyncStateContract.Columns extends android.provider.BaseColumns {
+    field public static final String ACCOUNT_NAME = "account_name";
+    field public static final String ACCOUNT_TYPE = "account_type";
+    field public static final String DATA = "data";
   }
 
   public static class SyncStateContract.Constants implements android.provider.SyncStateContract.Columns {
     ctor public SyncStateContract.Constants();
-    field public static final java.lang.String CONTENT_DIRECTORY = "syncstate";
+    field public static final String CONTENT_DIRECTORY = "syncstate";
   }
 
   public static final class SyncStateContract.Helpers {
     ctor public SyncStateContract.Helpers();
     method public static byte[] get(android.content.ContentProviderClient, android.net.Uri, android.accounts.Account) throws android.os.RemoteException;
-    method public static android.util.Pair<android.net.Uri, byte[]> getWithUri(android.content.ContentProviderClient, android.net.Uri, android.accounts.Account) throws android.os.RemoteException;
+    method public static android.util.Pair<android.net.Uri,byte[]> getWithUri(android.content.ContentProviderClient, android.net.Uri, android.accounts.Account) throws android.os.RemoteException;
     method public static android.net.Uri insert(android.content.ContentProviderClient, android.net.Uri, android.accounts.Account, byte[]) throws android.os.RemoteException;
     method public static android.content.ContentProviderOperation newSetOperation(android.net.Uri, android.accounts.Account, byte[]);
     method public static android.content.ContentProviderOperation newUpdateOperation(android.net.Uri, byte[]);
@@ -38634,153 +38980,154 @@
   public final class Telephony {
   }
 
-  public static abstract interface Telephony.BaseMmsColumns implements android.provider.BaseColumns {
-    field public static final java.lang.String CONTENT_CLASS = "ct_cls";
-    field public static final java.lang.String CONTENT_LOCATION = "ct_l";
-    field public static final java.lang.String CONTENT_TYPE = "ct_t";
-    field public static final java.lang.String CREATOR = "creator";
-    field public static final java.lang.String DATE = "date";
-    field public static final java.lang.String DATE_SENT = "date_sent";
-    field public static final java.lang.String DELIVERY_REPORT = "d_rpt";
-    field public static final java.lang.String DELIVERY_TIME = "d_tm";
-    field public static final java.lang.String EXPIRY = "exp";
-    field public static final java.lang.String LOCKED = "locked";
-    field public static final java.lang.String MESSAGE_BOX = "msg_box";
+  public static interface Telephony.BaseMmsColumns extends android.provider.BaseColumns {
+    field public static final String CONTENT_CLASS = "ct_cls";
+    field public static final String CONTENT_LOCATION = "ct_l";
+    field public static final String CONTENT_TYPE = "ct_t";
+    field public static final String CREATOR = "creator";
+    field public static final String DATE = "date";
+    field public static final String DATE_SENT = "date_sent";
+    field public static final String DELIVERY_REPORT = "d_rpt";
+    field public static final String DELIVERY_TIME = "d_tm";
+    field public static final String EXPIRY = "exp";
+    field public static final String LOCKED = "locked";
+    field public static final String MESSAGE_BOX = "msg_box";
     field public static final int MESSAGE_BOX_ALL = 0; // 0x0
     field public static final int MESSAGE_BOX_DRAFTS = 3; // 0x3
     field public static final int MESSAGE_BOX_FAILED = 5; // 0x5
     field public static final int MESSAGE_BOX_INBOX = 1; // 0x1
     field public static final int MESSAGE_BOX_OUTBOX = 4; // 0x4
     field public static final int MESSAGE_BOX_SENT = 2; // 0x2
-    field public static final java.lang.String MESSAGE_CLASS = "m_cls";
-    field public static final java.lang.String MESSAGE_ID = "m_id";
-    field public static final java.lang.String MESSAGE_SIZE = "m_size";
-    field public static final java.lang.String MESSAGE_TYPE = "m_type";
-    field public static final java.lang.String MMS_VERSION = "v";
-    field public static final java.lang.String PRIORITY = "pri";
-    field public static final java.lang.String READ = "read";
-    field public static final java.lang.String READ_REPORT = "rr";
-    field public static final java.lang.String READ_STATUS = "read_status";
-    field public static final java.lang.String REPORT_ALLOWED = "rpt_a";
-    field public static final java.lang.String RESPONSE_STATUS = "resp_st";
-    field public static final java.lang.String RESPONSE_TEXT = "resp_txt";
-    field public static final java.lang.String RETRIEVE_STATUS = "retr_st";
-    field public static final java.lang.String RETRIEVE_TEXT = "retr_txt";
-    field public static final java.lang.String RETRIEVE_TEXT_CHARSET = "retr_txt_cs";
-    field public static final java.lang.String SEEN = "seen";
-    field public static final java.lang.String STATUS = "st";
-    field public static final java.lang.String SUBJECT = "sub";
-    field public static final java.lang.String SUBJECT_CHARSET = "sub_cs";
-    field public static final java.lang.String SUBSCRIPTION_ID = "sub_id";
-    field public static final java.lang.String TEXT_ONLY = "text_only";
-    field public static final java.lang.String THREAD_ID = "thread_id";
-    field public static final java.lang.String TRANSACTION_ID = "tr_id";
+    field public static final String MESSAGE_CLASS = "m_cls";
+    field public static final String MESSAGE_ID = "m_id";
+    field public static final String MESSAGE_SIZE = "m_size";
+    field public static final String MESSAGE_TYPE = "m_type";
+    field public static final String MMS_VERSION = "v";
+    field public static final String PRIORITY = "pri";
+    field public static final String READ = "read";
+    field public static final String READ_REPORT = "rr";
+    field public static final String READ_STATUS = "read_status";
+    field public static final String REPORT_ALLOWED = "rpt_a";
+    field public static final String RESPONSE_STATUS = "resp_st";
+    field public static final String RESPONSE_TEXT = "resp_txt";
+    field public static final String RETRIEVE_STATUS = "retr_st";
+    field public static final String RETRIEVE_TEXT = "retr_txt";
+    field public static final String RETRIEVE_TEXT_CHARSET = "retr_txt_cs";
+    field public static final String SEEN = "seen";
+    field public static final String STATUS = "st";
+    field public static final String SUBJECT = "sub";
+    field public static final String SUBJECT_CHARSET = "sub_cs";
+    field public static final String SUBSCRIPTION_ID = "sub_id";
+    field public static final String TEXT_ONLY = "text_only";
+    field public static final String THREAD_ID = "thread_id";
+    field public static final String TRANSACTION_ID = "tr_id";
   }
 
-  public static abstract interface Telephony.CanonicalAddressesColumns implements android.provider.BaseColumns {
-    field public static final java.lang.String ADDRESS = "address";
+  public static interface Telephony.CanonicalAddressesColumns extends android.provider.BaseColumns {
+    field public static final String ADDRESS = "address";
   }
 
   public static final class Telephony.CarrierId implements android.provider.BaseColumns {
     method public static android.net.Uri getPreciseCarrierIdUriForSubscriptionId(int);
     method public static android.net.Uri getUriForSubscriptionId(int);
-    field public static final java.lang.String CARRIER_ID = "carrier_id";
-    field public static final java.lang.String CARRIER_NAME = "carrier_name";
+    field public static final String CARRIER_ID = "carrier_id";
+    field public static final String CARRIER_NAME = "carrier_name";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String PRECISE_CARRIER_ID = "precise_carrier_id";
-    field public static final java.lang.String PRECISE_CARRIER_ID_NAME = "precise_carrier_id_name";
+    field public static final String PRECISE_CARRIER_ID = "precise_carrier_id";
+    field public static final String PRECISE_CARRIER_ID_NAME = "precise_carrier_id_name";
   }
 
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
-    field public static final java.lang.String APN = "apn";
-    field public static final java.lang.String AUTH_TYPE = "authtype";
-    field public static final deprecated java.lang.String BEARER = "bearer";
-    field public static final java.lang.String CARRIER_ENABLED = "carrier_enabled";
-    field public static final java.lang.String CARRIER_ID = "carrier_id";
+    field public static final String APN = "apn";
+    field public static final String AUTH_TYPE = "authtype";
+    field @Deprecated public static final String BEARER = "bearer";
+    field public static final String CARRIER_ENABLED = "carrier_enabled";
+    field public static final String CARRIER_ID = "carrier_id";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String CURRENT = "current";
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "name ASC";
-    field public static final deprecated java.lang.String MCC = "mcc";
-    field public static final java.lang.String MMSC = "mmsc";
-    field public static final java.lang.String MMSPORT = "mmsport";
-    field public static final java.lang.String MMSPROXY = "mmsproxy";
-    field public static final deprecated java.lang.String MNC = "mnc";
-    field public static final deprecated java.lang.String MVNO_MATCH_DATA = "mvno_match_data";
-    field public static final deprecated java.lang.String MVNO_TYPE = "mvno_type";
-    field public static final java.lang.String NAME = "name";
-    field public static final java.lang.String NETWORK_TYPE_BITMASK = "network_type_bitmask";
-    field public static final deprecated java.lang.String NUMERIC = "numeric";
-    field public static final java.lang.String PASSWORD = "password";
-    field public static final java.lang.String PORT = "port";
-    field public static final java.lang.String PROTOCOL = "protocol";
-    field public static final java.lang.String PROXY = "proxy";
-    field public static final java.lang.String ROAMING_PROTOCOL = "roaming_protocol";
-    field public static final java.lang.String SERVER = "server";
+    field public static final String CURRENT = "current";
+    field public static final String DEFAULT_SORT_ORDER = "name ASC";
+    field @Deprecated public static final String MCC = "mcc";
+    field public static final String MMSC = "mmsc";
+    field public static final String MMSPORT = "mmsport";
+    field public static final String MMSPROXY = "mmsproxy";
+    field @Deprecated public static final String MNC = "mnc";
+    field @Deprecated public static final String MVNO_MATCH_DATA = "mvno_match_data";
+    field @Deprecated public static final String MVNO_TYPE = "mvno_type";
+    field public static final String NAME = "name";
+    field public static final String NETWORK_TYPE_BITMASK = "network_type_bitmask";
+    field @Deprecated public static final String NUMERIC = "numeric";
+    field public static final String PASSWORD = "password";
+    field public static final String PORT = "port";
+    field public static final String PROTOCOL = "protocol";
+    field public static final String PROXY = "proxy";
+    field public static final String ROAMING_PROTOCOL = "roaming_protocol";
+    field public static final String SERVER = "server";
     field public static final android.net.Uri SIM_APN_URI;
-    field public static final java.lang.String SUBSCRIPTION_ID = "sub_id";
-    field public static final java.lang.String TYPE = "type";
-    field public static final java.lang.String USER = "user";
+    field public static final String SUBSCRIPTION_ID = "sub_id";
+    field public static final String TYPE = "type";
+    field public static final String USER = "user";
   }
 
   public static final class Telephony.Mms implements android.provider.Telephony.BaseMmsColumns {
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final String DEFAULT_SORT_ORDER = "date DESC";
     field public static final android.net.Uri REPORT_REQUEST_URI;
     field public static final android.net.Uri REPORT_STATUS_URI;
   }
 
   public static final class Telephony.Mms.Addr implements android.provider.BaseColumns {
-    field public static final java.lang.String ADDRESS = "address";
-    field public static final java.lang.String CHARSET = "charset";
-    field public static final java.lang.String CONTACT_ID = "contact_id";
-    field public static final java.lang.String MSG_ID = "msg_id";
-    field public static final java.lang.String TYPE = "type";
+    field public static final String ADDRESS = "address";
+    field public static final String CHARSET = "charset";
+    field public static final String CONTACT_ID = "contact_id";
+    field public static final String MSG_ID = "msg_id";
+    field public static final String TYPE = "type";
   }
 
   public static final class Telephony.Mms.Draft implements android.provider.Telephony.BaseMmsColumns {
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final String DEFAULT_SORT_ORDER = "date DESC";
   }
 
   public static final class Telephony.Mms.Inbox implements android.provider.Telephony.BaseMmsColumns {
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final String DEFAULT_SORT_ORDER = "date DESC";
   }
 
   public static final class Telephony.Mms.Intents {
-    field public static final java.lang.String CONTENT_CHANGED_ACTION = "android.intent.action.CONTENT_CHANGED";
-    field public static final java.lang.String DELETED_CONTENTS = "deleted_contents";
+    field public static final String CONTENT_CHANGED_ACTION = "android.intent.action.CONTENT_CHANGED";
+    field public static final String DELETED_CONTENTS = "deleted_contents";
   }
 
   public static final class Telephony.Mms.Outbox implements android.provider.Telephony.BaseMmsColumns {
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final String DEFAULT_SORT_ORDER = "date DESC";
   }
 
   public static final class Telephony.Mms.Part implements android.provider.BaseColumns {
-    field public static final java.lang.String CHARSET = "chset";
-    field public static final java.lang.String CONTENT_DISPOSITION = "cd";
-    field public static final java.lang.String CONTENT_ID = "cid";
-    field public static final java.lang.String CONTENT_LOCATION = "cl";
-    field public static final java.lang.String CONTENT_TYPE = "ct";
-    field public static final java.lang.String CT_START = "ctt_s";
-    field public static final java.lang.String CT_TYPE = "ctt_t";
-    field public static final java.lang.String FILENAME = "fn";
-    field public static final java.lang.String MSG_ID = "mid";
-    field public static final java.lang.String NAME = "name";
-    field public static final java.lang.String SEQ = "seq";
-    field public static final java.lang.String TEXT = "text";
-    field public static final java.lang.String _DATA = "_data";
+    field public static final String CHARSET = "chset";
+    field public static final String CONTENT_DISPOSITION = "cd";
+    field public static final String CONTENT_ID = "cid";
+    field public static final String CONTENT_LOCATION = "cl";
+    field public static final String CONTENT_TYPE = "ct";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final String CT_START = "ctt_s";
+    field public static final String CT_TYPE = "ctt_t";
+    field public static final String FILENAME = "fn";
+    field public static final String MSG_ID = "mid";
+    field public static final String NAME = "name";
+    field public static final String SEQ = "seq";
+    field public static final String TEXT = "text";
+    field public static final String _DATA = "_data";
   }
 
   public static final class Telephony.Mms.Rate {
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String SENT_TIME = "sent_time";
+    field public static final String SENT_TIME = "sent_time";
   }
 
   public static final class Telephony.Mms.Sent implements android.provider.Telephony.BaseMmsColumns {
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final String DEFAULT_SORT_ORDER = "date DESC";
   }
 
   public static final class Telephony.MmsSms implements android.provider.BaseColumns {
@@ -38801,97 +39148,97 @@
     field public static final int NO_ERROR = 0; // 0x0
     field public static final android.net.Uri SEARCH_URI;
     field public static final int SMS_PROTO = 0; // 0x0
-    field public static final java.lang.String TYPE_DISCRIMINATOR_COLUMN = "transport_type";
+    field public static final String TYPE_DISCRIMINATOR_COLUMN = "transport_type";
   }
 
   public static final class Telephony.MmsSms.PendingMessages implements android.provider.BaseColumns {
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DUE_TIME = "due_time";
-    field public static final java.lang.String ERROR_CODE = "err_code";
-    field public static final java.lang.String ERROR_TYPE = "err_type";
-    field public static final java.lang.String LAST_TRY = "last_try";
-    field public static final java.lang.String MSG_ID = "msg_id";
-    field public static final java.lang.String MSG_TYPE = "msg_type";
-    field public static final java.lang.String PROTO_TYPE = "proto_type";
-    field public static final java.lang.String RETRY_INDEX = "retry_index";
-    field public static final java.lang.String SUBSCRIPTION_ID = "pending_sub_id";
+    field public static final String DUE_TIME = "due_time";
+    field public static final String ERROR_CODE = "err_code";
+    field public static final String ERROR_TYPE = "err_type";
+    field public static final String LAST_TRY = "last_try";
+    field public static final String MSG_ID = "msg_id";
+    field public static final String MSG_TYPE = "msg_type";
+    field public static final String PROTO_TYPE = "proto_type";
+    field public static final String RETRY_INDEX = "retry_index";
+    field public static final String SUBSCRIPTION_ID = "pending_sub_id";
   }
 
   public static final class Telephony.ServiceStateTable {
     method public static android.net.Uri getUriForSubscriptionId(int);
-    method public static android.net.Uri getUriForSubscriptionIdAndField(int, java.lang.String);
-    field public static final java.lang.String AUTHORITY = "service-state";
+    method public static android.net.Uri getUriForSubscriptionIdAndField(int, String);
+    field public static final String AUTHORITY = "service-state";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
-    field public static final java.lang.String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric";
-    field public static final java.lang.String VOICE_REG_STATE = "voice_reg_state";
+    field public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
+    field public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric";
+    field public static final String VOICE_REG_STATE = "voice_reg_state";
   }
 
   public static final class Telephony.Sms implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
-    method public static java.lang.String getDefaultSmsPackage(android.content.Context);
+    method public static String getDefaultSmsPackage(android.content.Context);
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final String DEFAULT_SORT_ORDER = "date DESC";
   }
 
   public static final class Telephony.Sms.Conversations implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
-    field public static final java.lang.String MESSAGE_COUNT = "msg_count";
-    field public static final java.lang.String SNIPPET = "snippet";
+    field public static final String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final String MESSAGE_COUNT = "msg_count";
+    field public static final String SNIPPET = "snippet";
   }
 
   public static final class Telephony.Sms.Draft implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final String DEFAULT_SORT_ORDER = "date DESC";
   }
 
   public static final class Telephony.Sms.Inbox implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final String DEFAULT_SORT_ORDER = "date DESC";
   }
 
   public static final class Telephony.Sms.Intents {
     method public static android.telephony.SmsMessage[] getMessagesFromIntent(android.content.Intent);
-    field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.provider.Telephony.ACTION_CHANGE_DEFAULT";
-    field public static final java.lang.String ACTION_DEFAULT_SMS_PACKAGE_CHANGED = "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED";
-    field public static final java.lang.String ACTION_EXTERNAL_PROVIDER_CHANGE = "android.provider.action.EXTERNAL_PROVIDER_CHANGE";
-    field public static final java.lang.String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
-    field public static final java.lang.String EXTRA_IS_DEFAULT_SMS_APP = "android.provider.extra.IS_DEFAULT_SMS_APP";
-    field public static final java.lang.String EXTRA_PACKAGE_NAME = "package";
+    field public static final String ACTION_CHANGE_DEFAULT = "android.provider.Telephony.ACTION_CHANGE_DEFAULT";
+    field public static final String ACTION_DEFAULT_SMS_PACKAGE_CHANGED = "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED";
+    field public static final String ACTION_EXTERNAL_PROVIDER_CHANGE = "android.provider.action.EXTERNAL_PROVIDER_CHANGE";
+    field public static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
+    field public static final String EXTRA_IS_DEFAULT_SMS_APP = "android.provider.extra.IS_DEFAULT_SMS_APP";
+    field public static final String EXTRA_PACKAGE_NAME = "package";
     field public static final int RESULT_SMS_DUPLICATED = 5; // 0x5
     field public static final int RESULT_SMS_GENERIC_ERROR = 2; // 0x2
     field public static final int RESULT_SMS_HANDLED = 1; // 0x1
     field public static final int RESULT_SMS_OUT_OF_MEMORY = 3; // 0x3
     field public static final int RESULT_SMS_UNSUPPORTED = 4; // 0x4
-    field public static final deprecated java.lang.String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE";
-    field public static final java.lang.String SIM_FULL_ACTION = "android.provider.Telephony.SIM_FULL";
-    field public static final java.lang.String SMS_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_CB_RECEIVED";
-    field public static final java.lang.String SMS_DELIVER_ACTION = "android.provider.Telephony.SMS_DELIVER";
-    field public static final java.lang.String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
-    field public static final java.lang.String SMS_REJECTED_ACTION = "android.provider.Telephony.SMS_REJECTED";
-    field public static final java.lang.String SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION = "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED";
-    field public static final java.lang.String WAP_PUSH_DELIVER_ACTION = "android.provider.Telephony.WAP_PUSH_DELIVER";
-    field public static final java.lang.String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
+    field @Deprecated public static final String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE";
+    field public static final String SIM_FULL_ACTION = "android.provider.Telephony.SIM_FULL";
+    field public static final String SMS_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_CB_RECEIVED";
+    field public static final String SMS_DELIVER_ACTION = "android.provider.Telephony.SMS_DELIVER";
+    field public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
+    field public static final String SMS_REJECTED_ACTION = "android.provider.Telephony.SMS_REJECTED";
+    field public static final String SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION = "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED";
+    field public static final String WAP_PUSH_DELIVER_ACTION = "android.provider.Telephony.WAP_PUSH_DELIVER";
+    field public static final String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
   }
 
   public static final class Telephony.Sms.Outbox implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final String DEFAULT_SORT_ORDER = "date DESC";
   }
 
   public static final class Telephony.Sms.Sent implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns {
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final String DEFAULT_SORT_ORDER = "date DESC";
   }
 
-  public static abstract interface Telephony.TextBasedSmsColumns {
-    field public static final java.lang.String ADDRESS = "address";
-    field public static final java.lang.String BODY = "body";
-    field public static final java.lang.String CREATOR = "creator";
-    field public static final java.lang.String DATE = "date";
-    field public static final java.lang.String DATE_SENT = "date_sent";
-    field public static final java.lang.String ERROR_CODE = "error_code";
-    field public static final java.lang.String LOCKED = "locked";
+  public static interface Telephony.TextBasedSmsColumns {
+    field public static final String ADDRESS = "address";
+    field public static final String BODY = "body";
+    field public static final String CREATOR = "creator";
+    field public static final String DATE = "date";
+    field public static final String DATE_SENT = "date_sent";
+    field public static final String ERROR_CODE = "error_code";
+    field public static final String LOCKED = "locked";
     field public static final int MESSAGE_TYPE_ALL = 0; // 0x0
     field public static final int MESSAGE_TYPE_DRAFT = 3; // 0x3
     field public static final int MESSAGE_TYPE_FAILED = 5; // 0x5
@@ -38899,25 +39246,25 @@
     field public static final int MESSAGE_TYPE_OUTBOX = 4; // 0x4
     field public static final int MESSAGE_TYPE_QUEUED = 6; // 0x6
     field public static final int MESSAGE_TYPE_SENT = 2; // 0x2
-    field public static final java.lang.String PERSON = "person";
-    field public static final java.lang.String PROTOCOL = "protocol";
-    field public static final java.lang.String READ = "read";
-    field public static final java.lang.String REPLY_PATH_PRESENT = "reply_path_present";
-    field public static final java.lang.String SEEN = "seen";
-    field public static final java.lang.String SERVICE_CENTER = "service_center";
-    field public static final java.lang.String STATUS = "status";
+    field public static final String PERSON = "person";
+    field public static final String PROTOCOL = "protocol";
+    field public static final String READ = "read";
+    field public static final String REPLY_PATH_PRESENT = "reply_path_present";
+    field public static final String SEEN = "seen";
+    field public static final String SERVICE_CENTER = "service_center";
+    field public static final String STATUS = "status";
     field public static final int STATUS_COMPLETE = 0; // 0x0
     field public static final int STATUS_FAILED = 64; // 0x40
     field public static final int STATUS_NONE = -1; // 0xffffffff
     field public static final int STATUS_PENDING = 32; // 0x20
-    field public static final java.lang.String SUBJECT = "subject";
-    field public static final java.lang.String SUBSCRIPTION_ID = "sub_id";
-    field public static final java.lang.String THREAD_ID = "thread_id";
-    field public static final java.lang.String TYPE = "type";
+    field public static final String SUBJECT = "subject";
+    field public static final String SUBSCRIPTION_ID = "sub_id";
+    field public static final String THREAD_ID = "thread_id";
+    field public static final String TYPE = "type";
   }
 
   public static final class Telephony.Threads implements android.provider.Telephony.ThreadsColumns {
-    method public static long getOrCreateThreadId(android.content.Context, java.lang.String);
+    method public static long getOrCreateThreadId(android.content.Context, String);
     method public static long getOrCreateThreadId(android.content.Context, java.util.Set<java.lang.String>);
     field public static final int BROADCAST_THREAD = 1; // 0x1
     field public static final int COMMON_THREAD = 0; // 0x0
@@ -38925,56 +39272,56 @@
     field public static final android.net.Uri OBSOLETE_THREADS_URI;
   }
 
-  public static abstract interface Telephony.ThreadsColumns implements android.provider.BaseColumns {
-    field public static final java.lang.String ARCHIVED = "archived";
-    field public static final java.lang.String DATE = "date";
-    field public static final java.lang.String ERROR = "error";
-    field public static final java.lang.String HAS_ATTACHMENT = "has_attachment";
-    field public static final java.lang.String MESSAGE_COUNT = "message_count";
-    field public static final java.lang.String READ = "read";
-    field public static final java.lang.String RECIPIENT_IDS = "recipient_ids";
-    field public static final java.lang.String SNIPPET = "snippet";
-    field public static final java.lang.String SNIPPET_CHARSET = "snippet_cs";
-    field public static final java.lang.String TYPE = "type";
+  public static interface Telephony.ThreadsColumns extends android.provider.BaseColumns {
+    field public static final String ARCHIVED = "archived";
+    field public static final String DATE = "date";
+    field public static final String ERROR = "error";
+    field public static final String HAS_ATTACHMENT = "has_attachment";
+    field public static final String MESSAGE_COUNT = "message_count";
+    field public static final String READ = "read";
+    field public static final String RECIPIENT_IDS = "recipient_ids";
+    field public static final String SNIPPET = "snippet";
+    field public static final String SNIPPET_CHARSET = "snippet_cs";
+    field public static final String TYPE = "type";
   }
 
   public class UserDictionary {
     ctor public UserDictionary();
-    field public static final java.lang.String AUTHORITY = "user_dictionary";
+    field public static final String AUTHORITY = "user_dictionary";
     field public static final android.net.Uri CONTENT_URI;
   }
 
   public static class UserDictionary.Words implements android.provider.BaseColumns {
     ctor public UserDictionary.Words();
-    method public static deprecated void addWord(android.content.Context, java.lang.String, int, int);
-    method public static void addWord(android.content.Context, java.lang.String, int, java.lang.String, java.util.Locale);
-    field public static final java.lang.String APP_ID = "appid";
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.userword";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.userword";
+    method @Deprecated public static void addWord(android.content.Context, String, int, int);
+    method public static void addWord(android.content.Context, String, int, String, java.util.Locale);
+    field public static final String APP_ID = "appid";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.userword";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.userword";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "frequency DESC";
-    field public static final java.lang.String FREQUENCY = "frequency";
-    field public static final java.lang.String LOCALE = "locale";
-    field public static final deprecated int LOCALE_TYPE_ALL = 0; // 0x0
-    field public static final deprecated int LOCALE_TYPE_CURRENT = 1; // 0x1
-    field public static final java.lang.String SHORTCUT = "shortcut";
-    field public static final java.lang.String WORD = "word";
-    field public static final java.lang.String _ID = "_id";
+    field public static final String DEFAULT_SORT_ORDER = "frequency DESC";
+    field public static final String FREQUENCY = "frequency";
+    field public static final String LOCALE = "locale";
+    field @Deprecated public static final int LOCALE_TYPE_ALL = 0; // 0x0
+    field @Deprecated public static final int LOCALE_TYPE_CURRENT = 1; // 0x1
+    field public static final String SHORTCUT = "shortcut";
+    field public static final String WORD = "word";
+    field public static final String _ID = "_id";
   }
 
   public class VoicemailContract {
-    field public static final java.lang.String ACTION_FETCH_VOICEMAIL = "android.intent.action.FETCH_VOICEMAIL";
-    field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
-    field public static final java.lang.String ACTION_SYNC_VOICEMAIL = "android.provider.action.SYNC_VOICEMAIL";
-    field public static final java.lang.String AUTHORITY = "com.android.voicemail";
-    field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.provider.extra.PHONE_ACCOUNT_HANDLE";
-    field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
-    field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package";
+    field public static final String ACTION_FETCH_VOICEMAIL = "android.intent.action.FETCH_VOICEMAIL";
+    field public static final String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
+    field public static final String ACTION_SYNC_VOICEMAIL = "android.provider.action.SYNC_VOICEMAIL";
+    field public static final String AUTHORITY = "com.android.voicemail";
+    field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.provider.extra.PHONE_ACCOUNT_HANDLE";
+    field public static final String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
+    field public static final String PARAM_KEY_SOURCE_PACKAGE = "source_package";
   }
 
   public static final class VoicemailContract.Status implements android.provider.BaseColumns {
-    method public static android.net.Uri buildSourceUri(java.lang.String);
-    field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
+    method public static android.net.Uri buildSourceUri(String);
+    field public static final String CONFIGURATION_STATE = "configuration_state";
     field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
     field public static final int CONFIGURATION_STATE_CONFIGURING = 3; // 0x3
     field public static final int CONFIGURATION_STATE_DISABLED = 5; // 0x5
@@ -38982,7 +39329,7 @@
     field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
     field public static final int CONFIGURATION_STATE_OK = 0; // 0x0
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DATA_CHANNEL_STATE = "data_channel_state";
+    field public static final String DATA_CHANNEL_STATE = "data_channel_state";
     field public static final int DATA_CHANNEL_STATE_BAD_CONFIGURATION = 3; // 0x3
     field public static final int DATA_CHANNEL_STATE_COMMUNICATION_ERROR = 4; // 0x4
     field public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1; // 0x1
@@ -38990,48 +39337,48 @@
     field public static final int DATA_CHANNEL_STATE_OK = 0; // 0x0
     field public static final int DATA_CHANNEL_STATE_SERVER_CONNECTION_ERROR = 6; // 0x6
     field public static final int DATA_CHANNEL_STATE_SERVER_ERROR = 5; // 0x5
-    field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemail.source.status";
-    field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail.source.status";
-    field public static final java.lang.String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
+    field public static final String DIR_TYPE = "vnd.android.cursor.dir/voicemail.source.status";
+    field public static final String ITEM_TYPE = "vnd.android.cursor.item/voicemail.source.status";
+    field public static final String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
     field public static final int NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING = 2; // 0x2
     field public static final int NOTIFICATION_CHANNEL_STATE_NO_CONNECTION = 1; // 0x1
     field public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; // 0x0
-    field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name";
-    field public static final java.lang.String PHONE_ACCOUNT_ID = "phone_account_id";
-    field public static final java.lang.String QUOTA_OCCUPIED = "quota_occupied";
-    field public static final java.lang.String QUOTA_TOTAL = "quota_total";
+    field public static final String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name";
+    field public static final String PHONE_ACCOUNT_ID = "phone_account_id";
+    field public static final String QUOTA_OCCUPIED = "quota_occupied";
+    field public static final String QUOTA_TOTAL = "quota_total";
     field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff
-    field public static final java.lang.String SETTINGS_URI = "settings_uri";
-    field public static final java.lang.String SOURCE_PACKAGE = "source_package";
-    field public static final java.lang.String SOURCE_TYPE = "source_type";
-    field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
+    field public static final String SETTINGS_URI = "settings_uri";
+    field public static final String SOURCE_PACKAGE = "source_package";
+    field public static final String SOURCE_TYPE = "source_type";
+    field public static final String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
   }
 
   public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
-    method public static android.net.Uri buildSourceUri(java.lang.String);
-    field public static final java.lang.String ARCHIVED = "archived";
-    field public static final java.lang.String BACKED_UP = "backed_up";
+    method public static android.net.Uri buildSourceUri(String);
+    field public static final String ARCHIVED = "archived";
+    field public static final String BACKED_UP = "backed_up";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DATE = "date";
-    field public static final java.lang.String DELETED = "deleted";
-    field public static final java.lang.String DIRTY = "dirty";
+    field public static final String DATE = "date";
+    field public static final String DELETED = "deleted";
+    field public static final String DIRTY = "dirty";
     field public static final int DIRTY_RETAIN = -1; // 0xffffffff
-    field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
-    field public static final java.lang.String DURATION = "duration";
-    field public static final java.lang.String HAS_CONTENT = "has_content";
-    field public static final java.lang.String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
-    field public static final java.lang.String IS_READ = "is_read";
-    field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
-    field public static final java.lang.String LAST_MODIFIED = "last_modified";
-    field public static final java.lang.String MIME_TYPE = "mime_type";
-    field public static final java.lang.String NEW = "new";
-    field public static final java.lang.String NUMBER = "number";
-    field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
-    field public static final java.lang.String PHONE_ACCOUNT_ID = "subscription_id";
-    field public static final java.lang.String RESTORED = "restored";
-    field public static final java.lang.String SOURCE_DATA = "source_data";
-    field public static final java.lang.String SOURCE_PACKAGE = "source_package";
-    field public static final java.lang.String TRANSCRIPTION = "transcription";
+    field public static final String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
+    field public static final String DURATION = "duration";
+    field public static final String HAS_CONTENT = "has_content";
+    field public static final String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
+    field public static final String IS_READ = "is_read";
+    field public static final String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
+    field public static final String LAST_MODIFIED = "last_modified";
+    field public static final String MIME_TYPE = "mime_type";
+    field public static final String NEW = "new";
+    field public static final String NUMBER = "number";
+    field public static final String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
+    field public static final String PHONE_ACCOUNT_ID = "subscription_id";
+    field public static final String RESTORED = "restored";
+    field public static final String SOURCE_DATA = "source_data";
+    field public static final String SOURCE_PACKAGE = "source_package";
+    field public static final String TRANSCRIPTION = "transcription";
   }
 
 }
@@ -39039,57 +39386,57 @@
 package android.renderscript {
 
   public class Allocation extends android.renderscript.BaseObj {
-    method public void copy1DRangeFrom(int, int, java.lang.Object);
+    method public void copy1DRangeFrom(int, int, Object);
     method public void copy1DRangeFrom(int, int, int[]);
     method public void copy1DRangeFrom(int, int, short[]);
     method public void copy1DRangeFrom(int, int, byte[]);
     method public void copy1DRangeFrom(int, int, float[]);
     method public void copy1DRangeFrom(int, int, android.renderscript.Allocation, int);
-    method public void copy1DRangeFromUnchecked(int, int, java.lang.Object);
+    method public void copy1DRangeFromUnchecked(int, int, Object);
     method public void copy1DRangeFromUnchecked(int, int, int[]);
     method public void copy1DRangeFromUnchecked(int, int, short[]);
     method public void copy1DRangeFromUnchecked(int, int, byte[]);
     method public void copy1DRangeFromUnchecked(int, int, float[]);
-    method public void copy1DRangeTo(int, int, java.lang.Object);
+    method public void copy1DRangeTo(int, int, Object);
     method public void copy1DRangeTo(int, int, int[]);
     method public void copy1DRangeTo(int, int, short[]);
     method public void copy1DRangeTo(int, int, byte[]);
     method public void copy1DRangeTo(int, int, float[]);
-    method public void copy1DRangeToUnchecked(int, int, java.lang.Object);
+    method public void copy1DRangeToUnchecked(int, int, Object);
     method public void copy1DRangeToUnchecked(int, int, int[]);
     method public void copy1DRangeToUnchecked(int, int, short[]);
     method public void copy1DRangeToUnchecked(int, int, byte[]);
     method public void copy1DRangeToUnchecked(int, int, float[]);
-    method public void copy2DRangeFrom(int, int, int, int, java.lang.Object);
+    method public void copy2DRangeFrom(int, int, int, int, Object);
     method public void copy2DRangeFrom(int, int, int, int, byte[]);
     method public void copy2DRangeFrom(int, int, int, int, short[]);
     method public void copy2DRangeFrom(int, int, int, int, int[]);
     method public void copy2DRangeFrom(int, int, int, int, float[]);
     method public void copy2DRangeFrom(int, int, int, int, android.renderscript.Allocation, int, int);
     method public void copy2DRangeFrom(int, int, android.graphics.Bitmap);
-    method public void copy2DRangeTo(int, int, int, int, java.lang.Object);
+    method public void copy2DRangeTo(int, int, int, int, Object);
     method public void copy2DRangeTo(int, int, int, int, byte[]);
     method public void copy2DRangeTo(int, int, int, int, short[]);
     method public void copy2DRangeTo(int, int, int, int, int[]);
     method public void copy2DRangeTo(int, int, int, int, float[]);
-    method public void copy3DRangeFrom(int, int, int, int, int, int, java.lang.Object);
+    method public void copy3DRangeFrom(int, int, int, int, int, int, Object);
     method public void copy3DRangeFrom(int, int, int, int, int, int, android.renderscript.Allocation, int, int, int);
-    method public void copy3DRangeTo(int, int, int, int, int, int, java.lang.Object);
+    method public void copy3DRangeTo(int, int, int, int, int, int, Object);
     method public void copyFrom(android.renderscript.BaseObj[]);
-    method public void copyFrom(java.lang.Object);
+    method public void copyFrom(Object);
     method public void copyFrom(int[]);
     method public void copyFrom(short[]);
     method public void copyFrom(byte[]);
     method public void copyFrom(float[]);
     method public void copyFrom(android.graphics.Bitmap);
     method public void copyFrom(android.renderscript.Allocation);
-    method public void copyFromUnchecked(java.lang.Object);
+    method public void copyFromUnchecked(Object);
     method public void copyFromUnchecked(int[]);
     method public void copyFromUnchecked(short[]);
     method public void copyFromUnchecked(byte[]);
     method public void copyFromUnchecked(float[]);
     method public void copyTo(android.graphics.Bitmap);
-    method public void copyTo(java.lang.Object);
+    method public void copyTo(Object);
     method public void copyTo(byte[]);
     method public void copyTo(short[]);
     method public void copyTo(int[]);
@@ -39103,7 +39450,7 @@
     method public static android.renderscript.Allocation createFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap);
     method public static android.renderscript.Allocation createFromBitmapResource(android.renderscript.RenderScript, android.content.res.Resources, int, android.renderscript.Allocation.MipmapControl, int);
     method public static android.renderscript.Allocation createFromBitmapResource(android.renderscript.RenderScript, android.content.res.Resources, int);
-    method public static android.renderscript.Allocation createFromString(android.renderscript.RenderScript, java.lang.String, int);
+    method public static android.renderscript.Allocation createFromString(android.renderscript.RenderScript, String, int);
     method public static android.renderscript.Allocation createSized(android.renderscript.RenderScript, android.renderscript.Element, int, int);
     method public static android.renderscript.Allocation createSized(android.renderscript.RenderScript, android.renderscript.Element, int);
     method public static android.renderscript.Allocation createTyped(android.renderscript.RenderScript, android.renderscript.Type, android.renderscript.Allocation.MipmapControl, int);
@@ -39120,7 +39467,7 @@
     method public int getUsage();
     method public void ioReceive();
     method public void ioSend();
-    method public deprecated synchronized void resize(int);
+    method @Deprecated public void resize(int);
     method public void setAutoPadding(boolean);
     method public void setFromFieldPacker(int, android.renderscript.FieldPacker);
     method public void setFromFieldPacker(int, int, android.renderscript.FieldPacker);
@@ -39138,23 +39485,21 @@
     field public static final int USAGE_SHARED = 128; // 0x80
   }
 
-  public static final class Allocation.MipmapControl extends java.lang.Enum {
-    method public static android.renderscript.Allocation.MipmapControl valueOf(java.lang.String);
-    method public static final android.renderscript.Allocation.MipmapControl[] values();
+  public enum Allocation.MipmapControl {
     enum_constant public static final android.renderscript.Allocation.MipmapControl MIPMAP_FULL;
     enum_constant public static final android.renderscript.Allocation.MipmapControl MIPMAP_NONE;
     enum_constant public static final android.renderscript.Allocation.MipmapControl MIPMAP_ON_SYNC_TO_TEXTURE;
   }
 
-  public static abstract interface Allocation.OnBufferAvailableListener {
-    method public abstract void onBufferAvailable(android.renderscript.Allocation);
+  public static interface Allocation.OnBufferAvailableListener {
+    method public void onBufferAvailable(android.renderscript.Allocation);
   }
 
   public class AllocationAdapter extends android.renderscript.Allocation {
     method public static android.renderscript.AllocationAdapter create1D(android.renderscript.RenderScript, android.renderscript.Allocation);
     method public static android.renderscript.AllocationAdapter create2D(android.renderscript.RenderScript, android.renderscript.Allocation);
     method public static android.renderscript.AllocationAdapter createTyped(android.renderscript.RenderScript, android.renderscript.Allocation, android.renderscript.Type);
-    method public synchronized void resize(int);
+    method public void resize(int);
     method public void setFace(android.renderscript.Type.CubemapFace);
     method public void setLOD(int);
     method public void setX(int);
@@ -39164,8 +39509,8 @@
 
   public class BaseObj {
     method public void destroy();
-    method public java.lang.String getName();
-    method public void setName(java.lang.String);
+    method public String getName();
+    method public void setName(String);
   }
 
   public class Byte2 {
@@ -39250,7 +39595,7 @@
     method public static android.renderscript.Element I8_2(android.renderscript.RenderScript);
     method public static android.renderscript.Element I8_3(android.renderscript.RenderScript);
     method public static android.renderscript.Element I8_4(android.renderscript.RenderScript);
-    method public static deprecated android.renderscript.Element MATRIX4X4(android.renderscript.RenderScript);
+    method @Deprecated public static android.renderscript.Element MATRIX4X4(android.renderscript.RenderScript);
     method public static android.renderscript.Element MATRIX_2X2(android.renderscript.RenderScript);
     method public static android.renderscript.Element MATRIX_3X3(android.renderscript.RenderScript);
     method public static android.renderscript.Element MATRIX_4X4(android.renderscript.RenderScript);
@@ -39292,7 +39637,7 @@
     method public android.renderscript.Element getSubElement(int);
     method public int getSubElementArraySize(int);
     method public int getSubElementCount();
-    method public java.lang.String getSubElementName(int);
+    method public String getSubElementName(int);
     method public int getSubElementOffsetBytes(int);
     method public int getVectorSize();
     method public boolean isCompatible(android.renderscript.Element);
@@ -39301,14 +39646,12 @@
 
   public static class Element.Builder {
     ctor public Element.Builder(android.renderscript.RenderScript);
-    method public android.renderscript.Element.Builder add(android.renderscript.Element, java.lang.String, int);
-    method public android.renderscript.Element.Builder add(android.renderscript.Element, java.lang.String);
+    method public android.renderscript.Element.Builder add(android.renderscript.Element, String, int);
+    method public android.renderscript.Element.Builder add(android.renderscript.Element, String);
     method public android.renderscript.Element create();
   }
 
-  public static final class Element.DataKind extends java.lang.Enum {
-    method public static android.renderscript.Element.DataKind valueOf(java.lang.String);
-    method public static final android.renderscript.Element.DataKind[] values();
+  public enum Element.DataKind {
     enum_constant public static final android.renderscript.Element.DataKind PIXEL_A;
     enum_constant public static final android.renderscript.Element.DataKind PIXEL_DEPTH;
     enum_constant public static final android.renderscript.Element.DataKind PIXEL_L;
@@ -39319,9 +39662,7 @@
     enum_constant public static final android.renderscript.Element.DataKind USER;
   }
 
-  public static final class Element.DataType extends java.lang.Enum {
-    method public static android.renderscript.Element.DataType valueOf(java.lang.String);
-    method public static final android.renderscript.Element.DataType[] values();
+  public enum Element.DataType {
     enum_constant public static final android.renderscript.Element.DataType BOOLEAN;
     enum_constant public static final android.renderscript.Element.DataType FLOAT_16;
     enum_constant public static final android.renderscript.Element.DataType FLOAT_32;
@@ -39577,19 +39918,19 @@
   }
 
   public class RSDriverException extends android.renderscript.RSRuntimeException {
-    ctor public RSDriverException(java.lang.String);
+    ctor public RSDriverException(String);
   }
 
   public class RSIllegalArgumentException extends android.renderscript.RSRuntimeException {
-    ctor public RSIllegalArgumentException(java.lang.String);
+    ctor public RSIllegalArgumentException(String);
   }
 
   public class RSInvalidStateException extends android.renderscript.RSRuntimeException {
-    ctor public RSInvalidStateException(java.lang.String);
+    ctor public RSInvalidStateException(String);
   }
 
   public class RSRuntimeException extends java.lang.RuntimeException {
-    ctor public RSRuntimeException(java.lang.String);
+    ctor public RSRuntimeException(String);
   }
 
   public class RenderScript {
@@ -39614,17 +39955,13 @@
     field public static final int CREATE_FLAG_NONE = 0; // 0x0
   }
 
-  public static final class RenderScript.ContextType extends java.lang.Enum {
-    method public static android.renderscript.RenderScript.ContextType valueOf(java.lang.String);
-    method public static final android.renderscript.RenderScript.ContextType[] values();
+  public enum RenderScript.ContextType {
     enum_constant public static final android.renderscript.RenderScript.ContextType DEBUG;
     enum_constant public static final android.renderscript.RenderScript.ContextType NORMAL;
     enum_constant public static final android.renderscript.RenderScript.ContextType PROFILE;
   }
 
-  public static final class RenderScript.Priority extends java.lang.Enum {
-    method public static android.renderscript.RenderScript.Priority valueOf(java.lang.String);
-    method public static final android.renderscript.RenderScript.Priority[] values();
+  public enum RenderScript.Priority {
     enum_constant public static final android.renderscript.RenderScript.Priority LOW;
     enum_constant public static final android.renderscript.RenderScript.Priority NORMAL;
   }
@@ -39632,7 +39969,7 @@
   public static class RenderScript.RSErrorHandler implements java.lang.Runnable {
     ctor public RenderScript.RSErrorHandler();
     method public void run();
-    field protected java.lang.String mErrorMessage;
+    field protected String mErrorMessage;
     field protected int mErrorNum;
   }
 
@@ -39671,9 +40008,7 @@
     method public void setWrapT(android.renderscript.Sampler.Value);
   }
 
-  public static final class Sampler.Value extends java.lang.Enum {
-    method public static android.renderscript.Sampler.Value valueOf(java.lang.String);
-    method public static final android.renderscript.Sampler.Value[] values();
+  public enum Sampler.Value {
     enum_constant public static final android.renderscript.Sampler.Value CLAMP;
     enum_constant public static final android.renderscript.Sampler.Value LINEAR;
     enum_constant public static final android.renderscript.Sampler.Value LINEAR_MIP_LINEAR;
@@ -39701,7 +40036,7 @@
     method protected void invoke(int);
     method protected void invoke(int, android.renderscript.FieldPacker);
     method protected void reduce(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.Script.LaunchOptions);
-    method public void setTimeZone(java.lang.String);
+    method public void setTimeZone(String);
     method public void setVar(int, float);
     method public void setVar(int, double);
     method public void setVar(int, int);
@@ -39753,26 +40088,26 @@
     ctor protected ScriptC(int, android.renderscript.RenderScript);
     ctor protected ScriptC(long, android.renderscript.RenderScript);
     ctor protected ScriptC(android.renderscript.RenderScript, android.content.res.Resources, int);
-    ctor protected ScriptC(android.renderscript.RenderScript, java.lang.String, byte[], byte[]);
+    ctor protected ScriptC(android.renderscript.RenderScript, String, byte[], byte[]);
   }
 
   public final class ScriptGroup extends android.renderscript.BaseObj {
-    method public java.lang.Object[] execute(java.lang.Object...);
-    method public deprecated void execute();
-    method public deprecated void setInput(android.renderscript.Script.KernelID, android.renderscript.Allocation);
-    method public deprecated void setOutput(android.renderscript.Script.KernelID, android.renderscript.Allocation);
+    method public Object[] execute(java.lang.Object...);
+    method @Deprecated public void execute();
+    method @Deprecated public void setInput(android.renderscript.Script.KernelID, android.renderscript.Allocation);
+    method @Deprecated public void setOutput(android.renderscript.Script.KernelID, android.renderscript.Allocation);
   }
 
   public static final class ScriptGroup.Binding {
-    ctor public ScriptGroup.Binding(android.renderscript.Script.FieldID, java.lang.Object);
+    ctor public ScriptGroup.Binding(android.renderscript.Script.FieldID, Object);
   }
 
-  public static final deprecated class ScriptGroup.Builder {
-    ctor public ScriptGroup.Builder(android.renderscript.RenderScript);
-    method public android.renderscript.ScriptGroup.Builder addConnection(android.renderscript.Type, android.renderscript.Script.KernelID, android.renderscript.Script.FieldID);
-    method public android.renderscript.ScriptGroup.Builder addConnection(android.renderscript.Type, android.renderscript.Script.KernelID, android.renderscript.Script.KernelID);
-    method public android.renderscript.ScriptGroup.Builder addKernel(android.renderscript.Script.KernelID);
-    method public android.renderscript.ScriptGroup create();
+  @Deprecated public static final class ScriptGroup.Builder {
+    ctor @Deprecated public ScriptGroup.Builder(android.renderscript.RenderScript);
+    method @Deprecated public android.renderscript.ScriptGroup.Builder addConnection(android.renderscript.Type, android.renderscript.Script.KernelID, android.renderscript.Script.FieldID);
+    method @Deprecated public android.renderscript.ScriptGroup.Builder addConnection(android.renderscript.Type, android.renderscript.Script.KernelID, android.renderscript.Script.KernelID);
+    method @Deprecated public android.renderscript.ScriptGroup.Builder addKernel(android.renderscript.Script.KernelID);
+    method @Deprecated public android.renderscript.ScriptGroup create();
   }
 
   public static final class ScriptGroup.Builder2 {
@@ -39780,7 +40115,7 @@
     method public android.renderscript.ScriptGroup.Input addInput();
     method public android.renderscript.ScriptGroup.Closure addInvoke(android.renderscript.Script.InvokeID, java.lang.Object...);
     method public android.renderscript.ScriptGroup.Closure addKernel(android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object...);
-    method public android.renderscript.ScriptGroup create(java.lang.String, android.renderscript.ScriptGroup.Future...);
+    method public android.renderscript.ScriptGroup create(String, android.renderscript.ScriptGroup.Future...);
   }
 
   public static final class ScriptGroup.Closure extends android.renderscript.BaseObj {
@@ -39975,7 +40310,7 @@
   }
 
   public final class ScriptIntrinsicColorMatrix extends android.renderscript.ScriptIntrinsic {
-    method public static deprecated android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript, android.renderscript.Element);
+    method @Deprecated public static android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript, android.renderscript.Element);
     method public static android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript);
     method public void forEach(android.renderscript.Allocation, android.renderscript.Allocation);
     method public void forEach(android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.Script.LaunchOptions);
@@ -40098,18 +40433,16 @@
     method public android.renderscript.Type.Builder setZ(int);
   }
 
-  public static final class Type.CubemapFace extends java.lang.Enum {
-    method public static android.renderscript.Type.CubemapFace valueOf(java.lang.String);
-    method public static final android.renderscript.Type.CubemapFace[] values();
+  public enum Type.CubemapFace {
     enum_constant public static final android.renderscript.Type.CubemapFace NEGATIVE_X;
     enum_constant public static final android.renderscript.Type.CubemapFace NEGATIVE_Y;
     enum_constant public static final android.renderscript.Type.CubemapFace NEGATIVE_Z;
     enum_constant public static final android.renderscript.Type.CubemapFace POSITIVE_X;
     enum_constant public static final android.renderscript.Type.CubemapFace POSITIVE_Y;
     enum_constant public static final android.renderscript.Type.CubemapFace POSITIVE_Z;
-    enum_constant public static final deprecated android.renderscript.Type.CubemapFace POSITVE_X;
-    enum_constant public static final deprecated android.renderscript.Type.CubemapFace POSITVE_Y;
-    enum_constant public static final deprecated android.renderscript.Type.CubemapFace POSITVE_Z;
+    enum_constant @Deprecated public static final android.renderscript.Type.CubemapFace POSITVE_X;
+    enum_constant @Deprecated public static final android.renderscript.Type.CubemapFace POSITVE_Y;
+    enum_constant @Deprecated public static final android.renderscript.Type.CubemapFace POSITVE_Z;
   }
 
 }
@@ -40117,10 +40450,10 @@
 package android.sax {
 
   public class Element {
-    method public android.sax.Element getChild(java.lang.String);
-    method public android.sax.Element getChild(java.lang.String, java.lang.String);
-    method public android.sax.Element requireChild(java.lang.String);
-    method public android.sax.Element requireChild(java.lang.String, java.lang.String);
+    method public android.sax.Element getChild(String);
+    method public android.sax.Element getChild(String, String);
+    method public android.sax.Element requireChild(String);
+    method public android.sax.Element requireChild(String, String);
     method public void setElementListener(android.sax.ElementListener);
     method public void setEndElementListener(android.sax.EndElementListener);
     method public void setEndTextElementListener(android.sax.EndTextElementListener);
@@ -40128,28 +40461,28 @@
     method public void setTextElementListener(android.sax.TextElementListener);
   }
 
-  public abstract interface ElementListener implements android.sax.EndElementListener android.sax.StartElementListener {
+  public interface ElementListener extends android.sax.StartElementListener android.sax.EndElementListener {
   }
 
-  public abstract interface EndElementListener {
-    method public abstract void end();
+  public interface EndElementListener {
+    method public void end();
   }
 
-  public abstract interface EndTextElementListener {
-    method public abstract void end(java.lang.String);
+  public interface EndTextElementListener {
+    method public void end(String);
   }
 
   public class RootElement extends android.sax.Element {
-    ctor public RootElement(java.lang.String, java.lang.String);
-    ctor public RootElement(java.lang.String);
+    ctor public RootElement(String, String);
+    ctor public RootElement(String);
     method public org.xml.sax.ContentHandler getContentHandler();
   }
 
-  public abstract interface StartElementListener {
-    method public abstract void start(org.xml.sax.Attributes);
+  public interface StartElementListener {
+    method public void start(org.xml.sax.Attributes);
   }
 
-  public abstract interface TextElementListener implements android.sax.EndTextElementListener android.sax.StartElementListener {
+  public interface TextElementListener extends android.sax.StartElementListener android.sax.EndTextElementListener {
   }
 
 }
@@ -40158,44 +40491,44 @@
 
   public final class Channel implements java.nio.channels.Channel {
     method public void close();
-    method public byte[] getSelectResponse();
-    method public android.se.omapi.Session getSession();
+    method @Nullable public byte[] getSelectResponse();
+    method @NonNull public android.se.omapi.Session getSession();
     method public boolean isBasicChannel();
     method public boolean isOpen();
     method public boolean selectNext() throws java.io.IOException;
-    method public byte[] transmit(byte[]) throws java.io.IOException;
+    method @NonNull public byte[] transmit(@NonNull byte[]) throws java.io.IOException;
   }
 
   public final class Reader {
     method public void closeSessions();
-    method public java.lang.String getName();
-    method public android.se.omapi.SEService getSEService();
+    method @NonNull public String getName();
+    method @NonNull public android.se.omapi.SEService getSEService();
     method public boolean isSecureElementPresent();
-    method public android.se.omapi.Session openSession() throws java.io.IOException;
+    method @NonNull public android.se.omapi.Session openSession() throws java.io.IOException;
   }
 
   public final class SEService {
-    ctor public SEService(android.content.Context, java.util.concurrent.Executor, android.se.omapi.SEService.OnConnectedListener);
-    method public android.se.omapi.Reader[] getReaders();
-    method public java.lang.String getVersion();
+    ctor public SEService(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, @NonNull android.se.omapi.SEService.OnConnectedListener);
+    method @NonNull public android.se.omapi.Reader[] getReaders();
+    method @NonNull public String getVersion();
     method public boolean isConnected();
     method public void shutdown();
   }
 
-  public static abstract interface SEService.OnConnectedListener {
-    method public abstract void onConnected();
+  public static interface SEService.OnConnectedListener {
+    method public void onConnected();
   }
 
   public final class Session {
     method public void close();
     method public void closeChannels();
-    method public byte[] getATR();
-    method public android.se.omapi.Reader getReader();
+    method @Nullable public byte[] getATR();
+    method @NonNull public android.se.omapi.Reader getReader();
     method public boolean isClosed();
-    method public android.se.omapi.Channel openBasicChannel(byte[], byte) throws java.io.IOException;
-    method public android.se.omapi.Channel openBasicChannel(byte[]) throws java.io.IOException;
-    method public android.se.omapi.Channel openLogicalChannel(byte[], byte) throws java.io.IOException;
-    method public android.se.omapi.Channel openLogicalChannel(byte[]) throws java.io.IOException;
+    method @Nullable public android.se.omapi.Channel openBasicChannel(@Nullable byte[], @Nullable byte) throws java.io.IOException;
+    method @Nullable public android.se.omapi.Channel openBasicChannel(@Nullable byte[]) throws java.io.IOException;
+    method @Nullable public android.se.omapi.Channel openLogicalChannel(@Nullable byte[], @Nullable byte) throws java.io.IOException;
+    method @Nullable public android.se.omapi.Channel openLogicalChannel(@Nullable byte[]) throws java.io.IOException;
   }
 
 }
@@ -40209,107 +40542,107 @@
 
   public class ConfirmationAlreadyPresentingException extends java.lang.Exception {
     ctor public ConfirmationAlreadyPresentingException();
-    ctor public ConfirmationAlreadyPresentingException(java.lang.String);
+    ctor public ConfirmationAlreadyPresentingException(String);
   }
 
   public abstract class ConfirmationCallback {
     ctor public ConfirmationCallback();
     method public void onCanceled();
-    method public void onConfirmed(byte[]);
+    method public void onConfirmed(@NonNull byte[]);
     method public void onDismissed();
-    method public void onError(java.lang.Throwable);
+    method public void onError(Throwable);
   }
 
   public class ConfirmationNotAvailableException extends java.lang.Exception {
     ctor public ConfirmationNotAvailableException();
-    ctor public ConfirmationNotAvailableException(java.lang.String);
+    ctor public ConfirmationNotAvailableException(String);
   }
 
   public class ConfirmationPrompt {
     method public void cancelPrompt();
     method public static boolean isSupported(android.content.Context);
-    method public void presentPrompt(java.util.concurrent.Executor, android.security.ConfirmationCallback) throws android.security.ConfirmationAlreadyPresentingException, android.security.ConfirmationNotAvailableException;
+    method public void presentPrompt(@NonNull java.util.concurrent.Executor, @NonNull android.security.ConfirmationCallback) throws android.security.ConfirmationAlreadyPresentingException, android.security.ConfirmationNotAvailableException;
   }
 
   public static final class ConfirmationPrompt.Builder {
     ctor public ConfirmationPrompt.Builder(android.content.Context);
     method public android.security.ConfirmationPrompt build();
     method public android.security.ConfirmationPrompt.Builder setExtraData(byte[]);
-    method public android.security.ConfirmationPrompt.Builder setPromptText(java.lang.CharSequence);
+    method public android.security.ConfirmationPrompt.Builder setPromptText(CharSequence);
   }
 
   public final class KeyChain {
     ctor public KeyChain();
-    method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String);
-    method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], android.net.Uri, java.lang.String);
-    method public static android.content.Intent createInstallIntent();
-    method public static java.security.cert.X509Certificate[] getCertificateChain(android.content.Context, java.lang.String) throws java.lang.InterruptedException, android.security.KeyChainException;
-    method public static java.security.PrivateKey getPrivateKey(android.content.Context, java.lang.String) throws java.lang.InterruptedException, android.security.KeyChainException;
-    method public static deprecated boolean isBoundKeyAlgorithm(java.lang.String);
-    method public static boolean isKeyAlgorithmSupported(java.lang.String);
-    field public static final java.lang.String ACTION_KEYCHAIN_CHANGED = "android.security.action.KEYCHAIN_CHANGED";
-    field public static final java.lang.String ACTION_KEY_ACCESS_CHANGED = "android.security.action.KEY_ACCESS_CHANGED";
-    field public static final deprecated java.lang.String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED";
-    field public static final java.lang.String ACTION_TRUST_STORE_CHANGED = "android.security.action.TRUST_STORE_CHANGED";
-    field public static final java.lang.String EXTRA_CERTIFICATE = "CERT";
-    field public static final java.lang.String EXTRA_KEY_ACCESSIBLE = "android.security.extra.KEY_ACCESSIBLE";
-    field public static final java.lang.String EXTRA_KEY_ALIAS = "android.security.extra.KEY_ALIAS";
-    field public static final java.lang.String EXTRA_NAME = "name";
-    field public static final java.lang.String EXTRA_PKCS12 = "PKCS12";
+    method public static void choosePrivateKeyAlias(@NonNull android.app.Activity, @NonNull android.security.KeyChainAliasCallback, @Nullable String[], @Nullable java.security.Principal[], @Nullable String, int, @Nullable String);
+    method public static void choosePrivateKeyAlias(@NonNull android.app.Activity, @NonNull android.security.KeyChainAliasCallback, @Nullable String[], @Nullable java.security.Principal[], @Nullable android.net.Uri, @Nullable String);
+    method @NonNull public static android.content.Intent createInstallIntent();
+    method @Nullable @WorkerThread public static java.security.cert.X509Certificate[] getCertificateChain(@NonNull android.content.Context, @NonNull String) throws java.lang.InterruptedException, android.security.KeyChainException;
+    method @Nullable @WorkerThread public static java.security.PrivateKey getPrivateKey(@NonNull android.content.Context, @NonNull String) throws java.lang.InterruptedException, android.security.KeyChainException;
+    method @Deprecated public static boolean isBoundKeyAlgorithm(@NonNull String);
+    method public static boolean isKeyAlgorithmSupported(@NonNull String);
+    field public static final String ACTION_KEYCHAIN_CHANGED = "android.security.action.KEYCHAIN_CHANGED";
+    field public static final String ACTION_KEY_ACCESS_CHANGED = "android.security.action.KEY_ACCESS_CHANGED";
+    field @Deprecated public static final String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED";
+    field public static final String ACTION_TRUST_STORE_CHANGED = "android.security.action.TRUST_STORE_CHANGED";
+    field public static final String EXTRA_CERTIFICATE = "CERT";
+    field public static final String EXTRA_KEY_ACCESSIBLE = "android.security.extra.KEY_ACCESSIBLE";
+    field public static final String EXTRA_KEY_ALIAS = "android.security.extra.KEY_ALIAS";
+    field public static final String EXTRA_NAME = "name";
+    field public static final String EXTRA_PKCS12 = "PKCS12";
   }
 
-  public abstract interface KeyChainAliasCallback {
-    method public abstract void alias(java.lang.String);
+  public interface KeyChainAliasCallback {
+    method public void alias(@Nullable String);
   }
 
   public class KeyChainException extends java.lang.Exception {
     ctor public KeyChainException();
-    ctor public KeyChainException(java.lang.String);
-    ctor public KeyChainException(java.lang.String, java.lang.Throwable);
-    ctor public KeyChainException(java.lang.Throwable);
+    ctor public KeyChainException(String);
+    ctor public KeyChainException(String, Throwable);
+    ctor public KeyChainException(Throwable);
   }
 
-  public final deprecated class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
-    method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
-    method public android.content.Context getContext();
-    method public java.util.Date getEndDate();
-    method public int getKeySize();
-    method public java.lang.String getKeyType();
-    method public java.lang.String getKeystoreAlias();
-    method public java.math.BigInteger getSerialNumber();
-    method public java.util.Date getStartDate();
-    method public javax.security.auth.x500.X500Principal getSubjectDN();
-    method public boolean isEncryptionRequired();
+  @Deprecated public final class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
+    method @Deprecated @NonNull public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
+    method @Deprecated public android.content.Context getContext();
+    method @Deprecated @NonNull public java.util.Date getEndDate();
+    method @Deprecated public int getKeySize();
+    method @Deprecated @Nullable public String getKeyType();
+    method @Deprecated public String getKeystoreAlias();
+    method @Deprecated @NonNull public java.math.BigInteger getSerialNumber();
+    method @Deprecated @NonNull public java.util.Date getStartDate();
+    method @Deprecated @NonNull public javax.security.auth.x500.X500Principal getSubjectDN();
+    method @Deprecated public boolean isEncryptionRequired();
   }
 
-  public static final deprecated class KeyPairGeneratorSpec.Builder {
-    ctor public KeyPairGeneratorSpec.Builder(android.content.Context);
-    method public android.security.KeyPairGeneratorSpec build();
-    method public android.security.KeyPairGeneratorSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
-    method public android.security.KeyPairGeneratorSpec.Builder setAlias(java.lang.String);
-    method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired();
-    method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int);
-    method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger);
-    method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal);
+  @Deprecated public static final class KeyPairGeneratorSpec.Builder {
+    ctor @Deprecated public KeyPairGeneratorSpec.Builder(@NonNull android.content.Context);
+    method @Deprecated @NonNull public android.security.KeyPairGeneratorSpec build();
+    method @Deprecated public android.security.KeyPairGeneratorSpec.Builder setAlgorithmParameterSpec(@NonNull java.security.spec.AlgorithmParameterSpec);
+    method @Deprecated @NonNull public android.security.KeyPairGeneratorSpec.Builder setAlias(@NonNull String);
+    method @Deprecated @NonNull public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired();
+    method @Deprecated @NonNull public android.security.KeyPairGeneratorSpec.Builder setEndDate(@NonNull java.util.Date);
+    method @Deprecated @NonNull public android.security.KeyPairGeneratorSpec.Builder setKeySize(int);
+    method @Deprecated @NonNull public android.security.KeyPairGeneratorSpec.Builder setKeyType(@NonNull String) throws java.security.NoSuchAlgorithmException;
+    method @Deprecated @NonNull public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(@NonNull java.math.BigInteger);
+    method @Deprecated @NonNull public android.security.KeyPairGeneratorSpec.Builder setStartDate(@NonNull java.util.Date);
+    method @Deprecated @NonNull public android.security.KeyPairGeneratorSpec.Builder setSubject(@NonNull javax.security.auth.x500.X500Principal);
   }
 
-  public final deprecated class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
-    method public boolean isEncryptionRequired();
+  @Deprecated public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
+    method @Deprecated public boolean isEncryptionRequired();
   }
 
-  public static final deprecated class KeyStoreParameter.Builder {
-    ctor public KeyStoreParameter.Builder(android.content.Context);
-    method public android.security.KeyStoreParameter build();
-    method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
+  @Deprecated public static final class KeyStoreParameter.Builder {
+    ctor @Deprecated public KeyStoreParameter.Builder(@NonNull android.content.Context);
+    method @Deprecated @NonNull public android.security.KeyStoreParameter build();
+    method @Deprecated @NonNull public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
   }
 
   public class NetworkSecurityPolicy {
     method public static android.security.NetworkSecurityPolicy getInstance();
     method public boolean isCleartextTrafficPermitted();
-    method public boolean isCleartextTrafficPermitted(java.lang.String);
+    method public boolean isCleartextTrafficPermitted(String);
   }
 
 }
@@ -40318,29 +40651,29 @@
 
   public class KeyExpiredException extends java.security.InvalidKeyException {
     ctor public KeyExpiredException();
-    ctor public KeyExpiredException(java.lang.String);
-    ctor public KeyExpiredException(java.lang.String, java.lang.Throwable);
+    ctor public KeyExpiredException(String);
+    ctor public KeyExpiredException(String, Throwable);
   }
 
   public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
-    method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
+    method @Nullable public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
     method public byte[] getAttestationChallenge();
-    method public java.lang.String[] getBlockModes();
-    method public java.util.Date getCertificateNotAfter();
-    method public java.util.Date getCertificateNotBefore();
-    method public java.math.BigInteger getCertificateSerialNumber();
-    method public javax.security.auth.x500.X500Principal getCertificateSubject();
-    method public java.lang.String[] getDigests();
-    method public java.lang.String[] getEncryptionPaddings();
+    method @NonNull public String[] getBlockModes();
+    method @NonNull public java.util.Date getCertificateNotAfter();
+    method @NonNull public java.util.Date getCertificateNotBefore();
+    method @NonNull public java.math.BigInteger getCertificateSerialNumber();
+    method @NonNull public javax.security.auth.x500.X500Principal getCertificateSubject();
+    method @NonNull public String[] getDigests();
+    method @NonNull public String[] getEncryptionPaddings();
     method public int getKeySize();
-    method public java.util.Date getKeyValidityForConsumptionEnd();
-    method public java.util.Date getKeyValidityForOriginationEnd();
-    method public java.util.Date getKeyValidityStart();
-    method public java.lang.String getKeystoreAlias();
+    method @Nullable public java.util.Date getKeyValidityForConsumptionEnd();
+    method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
+    method @Nullable public java.util.Date getKeyValidityStart();
+    method @NonNull public String getKeystoreAlias();
     method public int getPurposes();
-    method public java.lang.String[] getSignaturePaddings();
+    method @NonNull public String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
-    method public boolean isDigestsSpecified();
+    method @NonNull public boolean isDigestsSpecified();
     method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isStrongBoxBacked();
@@ -40352,46 +40685,46 @@
   }
 
   public static final class KeyGenParameterSpec.Builder {
-    ctor public KeyGenParameterSpec.Builder(java.lang.String, int);
-    method public android.security.keystore.KeyGenParameterSpec build();
-    method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setAttestationChallenge(byte[]);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(java.util.Date);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotBefore(java.util.Date);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSerialNumber(java.math.BigInteger);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setIsStrongBoxBacked(boolean);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setUserConfirmationRequired(boolean);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setUserPresenceRequired(boolean);
+    ctor public KeyGenParameterSpec.Builder(@NonNull String, int);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec build();
+    method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(@NonNull java.security.spec.AlgorithmParameterSpec);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setAttestationChallenge(byte[]);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(@NonNull java.util.Date);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotBefore(@NonNull java.util.Date);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSerialNumber(@NonNull java.math.BigInteger);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(@NonNull javax.security.auth.x500.X500Principal);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setInvalidatedByBiometricEnrollment(boolean);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setIsStrongBoxBacked(boolean);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(@IntRange(from=0xffffffff) int);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserConfirmationRequired(boolean);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserPresenceRequired(boolean);
   }
 
   public class KeyInfo implements java.security.spec.KeySpec {
-    method public java.lang.String[] getBlockModes();
-    method public java.lang.String[] getDigests();
-    method public java.lang.String[] getEncryptionPaddings();
+    method @NonNull public String[] getBlockModes();
+    method @NonNull public String[] getDigests();
+    method @NonNull public String[] getEncryptionPaddings();
     method public int getKeySize();
-    method public java.util.Date getKeyValidityForConsumptionEnd();
-    method public java.util.Date getKeyValidityForOriginationEnd();
-    method public java.util.Date getKeyValidityStart();
-    method public java.lang.String getKeystoreAlias();
+    method @Nullable public java.util.Date getKeyValidityForConsumptionEnd();
+    method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
+    method @Nullable public java.util.Date getKeyValidityStart();
+    method public String getKeystoreAlias();
     method public int getOrigin();
     method public int getPurposes();
-    method public java.lang.String[] getSignaturePaddings();
+    method @NonNull public String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isInsideSecureHardware();
     method public boolean isInvalidatedByBiometricEnrollment();
@@ -40404,41 +40737,41 @@
 
   public class KeyNotYetValidException extends java.security.InvalidKeyException {
     ctor public KeyNotYetValidException();
-    ctor public KeyNotYetValidException(java.lang.String);
-    ctor public KeyNotYetValidException(java.lang.String, java.lang.Throwable);
+    ctor public KeyNotYetValidException(String);
+    ctor public KeyNotYetValidException(String, Throwable);
   }
 
   public class KeyPermanentlyInvalidatedException extends java.security.InvalidKeyException {
     ctor public KeyPermanentlyInvalidatedException();
-    ctor public KeyPermanentlyInvalidatedException(java.lang.String);
-    ctor public KeyPermanentlyInvalidatedException(java.lang.String, java.lang.Throwable);
+    ctor public KeyPermanentlyInvalidatedException(String);
+    ctor public KeyPermanentlyInvalidatedException(String, Throwable);
   }
 
   public abstract class KeyProperties {
-    field public static final java.lang.String BLOCK_MODE_CBC = "CBC";
-    field public static final java.lang.String BLOCK_MODE_CTR = "CTR";
-    field public static final java.lang.String BLOCK_MODE_ECB = "ECB";
-    field public static final java.lang.String BLOCK_MODE_GCM = "GCM";
-    field public static final java.lang.String DIGEST_MD5 = "MD5";
-    field public static final java.lang.String DIGEST_NONE = "NONE";
-    field public static final java.lang.String DIGEST_SHA1 = "SHA-1";
-    field public static final java.lang.String DIGEST_SHA224 = "SHA-224";
-    field public static final java.lang.String DIGEST_SHA256 = "SHA-256";
-    field public static final java.lang.String DIGEST_SHA384 = "SHA-384";
-    field public static final java.lang.String DIGEST_SHA512 = "SHA-512";
-    field public static final java.lang.String ENCRYPTION_PADDING_NONE = "NoPadding";
-    field public static final java.lang.String ENCRYPTION_PADDING_PKCS7 = "PKCS7Padding";
-    field public static final java.lang.String ENCRYPTION_PADDING_RSA_OAEP = "OAEPPadding";
-    field public static final java.lang.String ENCRYPTION_PADDING_RSA_PKCS1 = "PKCS1Padding";
-    field public static final deprecated java.lang.String KEY_ALGORITHM_3DES = "DESede";
-    field public static final java.lang.String KEY_ALGORITHM_AES = "AES";
-    field public static final java.lang.String KEY_ALGORITHM_EC = "EC";
-    field public static final java.lang.String KEY_ALGORITHM_HMAC_SHA1 = "HmacSHA1";
-    field public static final java.lang.String KEY_ALGORITHM_HMAC_SHA224 = "HmacSHA224";
-    field public static final java.lang.String KEY_ALGORITHM_HMAC_SHA256 = "HmacSHA256";
-    field public static final java.lang.String KEY_ALGORITHM_HMAC_SHA384 = "HmacSHA384";
-    field public static final java.lang.String KEY_ALGORITHM_HMAC_SHA512 = "HmacSHA512";
-    field public static final java.lang.String KEY_ALGORITHM_RSA = "RSA";
+    field public static final String BLOCK_MODE_CBC = "CBC";
+    field public static final String BLOCK_MODE_CTR = "CTR";
+    field public static final String BLOCK_MODE_ECB = "ECB";
+    field public static final String BLOCK_MODE_GCM = "GCM";
+    field public static final String DIGEST_MD5 = "MD5";
+    field public static final String DIGEST_NONE = "NONE";
+    field public static final String DIGEST_SHA1 = "SHA-1";
+    field public static final String DIGEST_SHA224 = "SHA-224";
+    field public static final String DIGEST_SHA256 = "SHA-256";
+    field public static final String DIGEST_SHA384 = "SHA-384";
+    field public static final String DIGEST_SHA512 = "SHA-512";
+    field public static final String ENCRYPTION_PADDING_NONE = "NoPadding";
+    field public static final String ENCRYPTION_PADDING_PKCS7 = "PKCS7Padding";
+    field public static final String ENCRYPTION_PADDING_RSA_OAEP = "OAEPPadding";
+    field public static final String ENCRYPTION_PADDING_RSA_PKCS1 = "PKCS1Padding";
+    field @Deprecated public static final String KEY_ALGORITHM_3DES = "DESede";
+    field public static final String KEY_ALGORITHM_AES = "AES";
+    field public static final String KEY_ALGORITHM_EC = "EC";
+    field public static final String KEY_ALGORITHM_HMAC_SHA1 = "HmacSHA1";
+    field public static final String KEY_ALGORITHM_HMAC_SHA224 = "HmacSHA224";
+    field public static final String KEY_ALGORITHM_HMAC_SHA256 = "HmacSHA256";
+    field public static final String KEY_ALGORITHM_HMAC_SHA384 = "HmacSHA384";
+    field public static final String KEY_ALGORITHM_HMAC_SHA512 = "HmacSHA512";
+    field public static final String KEY_ALGORITHM_RSA = "RSA";
     field public static final int ORIGIN_GENERATED = 1; // 0x1
     field public static final int ORIGIN_IMPORTED = 2; // 0x2
     field public static final int ORIGIN_SECURELY_IMPORTED = 8; // 0x8
@@ -40448,19 +40781,19 @@
     field public static final int PURPOSE_SIGN = 4; // 0x4
     field public static final int PURPOSE_VERIFY = 8; // 0x8
     field public static final int PURPOSE_WRAP_KEY = 32; // 0x20
-    field public static final java.lang.String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
-    field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS";
+    field public static final String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
+    field public static final String SIGNATURE_PADDING_RSA_PSS = "PSS";
   }
 
   public final class KeyProtection implements java.security.KeyStore.ProtectionParameter {
-    method public java.lang.String[] getBlockModes();
-    method public java.lang.String[] getDigests();
-    method public java.lang.String[] getEncryptionPaddings();
-    method public java.util.Date getKeyValidityForConsumptionEnd();
-    method public java.util.Date getKeyValidityForOriginationEnd();
-    method public java.util.Date getKeyValidityStart();
+    method @NonNull public String[] getBlockModes();
+    method @NonNull public String[] getDigests();
+    method @NonNull public String[] getEncryptionPaddings();
+    method @Nullable public java.util.Date getKeyValidityForConsumptionEnd();
+    method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
+    method @Nullable public java.util.Date getKeyValidityStart();
     method public int getPurposes();
-    method public java.lang.String[] getSignaturePaddings();
+    method @NonNull public String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isDigestsSpecified();
     method public boolean isInvalidatedByBiometricEnrollment();
@@ -40474,57 +40807,57 @@
 
   public static final class KeyProtection.Builder {
     ctor public KeyProtection.Builder(int);
-    method public android.security.keystore.KeyProtection build();
-    method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
-    method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
-    method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
-    method public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
-    method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
-    method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
-    method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
-    method public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
-    method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
-    method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
-    method public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
-    method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
-    method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
-    method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
-    method public android.security.keystore.KeyProtection.Builder setUserConfirmationRequired(boolean);
-    method public android.security.keystore.KeyProtection.Builder setUserPresenceRequired(boolean);
+    method @NonNull public android.security.keystore.KeyProtection build();
+    method @NonNull public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setInvalidatedByBiometricEnrollment(boolean);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(@IntRange(from=0xffffffff) int);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setUserConfirmationRequired(boolean);
+    method @NonNull public android.security.keystore.KeyProtection.Builder setUserPresenceRequired(boolean);
   }
 
   public class SecureKeyImportUnavailableException extends java.security.ProviderException {
     ctor public SecureKeyImportUnavailableException();
-    ctor public SecureKeyImportUnavailableException(java.lang.String);
-    ctor public SecureKeyImportUnavailableException(java.lang.String, java.lang.Throwable);
-    ctor public SecureKeyImportUnavailableException(java.lang.Throwable);
+    ctor public SecureKeyImportUnavailableException(String);
+    ctor public SecureKeyImportUnavailableException(String, Throwable);
+    ctor public SecureKeyImportUnavailableException(Throwable);
   }
 
   public class StrongBoxUnavailableException extends java.security.ProviderException {
     ctor public StrongBoxUnavailableException();
-    ctor public StrongBoxUnavailableException(java.lang.String);
-    ctor public StrongBoxUnavailableException(java.lang.String, java.lang.Throwable);
-    ctor public StrongBoxUnavailableException(java.lang.Throwable);
+    ctor public StrongBoxUnavailableException(String);
+    ctor public StrongBoxUnavailableException(String, Throwable);
+    ctor public StrongBoxUnavailableException(Throwable);
   }
 
   public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
     ctor public UserNotAuthenticatedException();
-    ctor public UserNotAuthenticatedException(java.lang.String);
-    ctor public UserNotAuthenticatedException(java.lang.String, java.lang.Throwable);
+    ctor public UserNotAuthenticatedException(String);
+    ctor public UserNotAuthenticatedException(String, Throwable);
   }
 
   public class UserPresenceUnavailableException extends java.security.InvalidKeyException {
     ctor public UserPresenceUnavailableException();
-    ctor public UserPresenceUnavailableException(java.lang.String);
-    ctor public UserPresenceUnavailableException(java.lang.String, java.lang.Throwable);
+    ctor public UserPresenceUnavailableException(String);
+    ctor public UserPresenceUnavailableException(String, Throwable);
   }
 
   public class WrappedKeyEntry implements java.security.KeyStore.Entry {
-    ctor public WrappedKeyEntry(byte[], java.lang.String, java.lang.String, java.security.spec.AlgorithmParameterSpec);
+    ctor public WrappedKeyEntry(byte[], String, String, java.security.spec.AlgorithmParameterSpec);
     method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
-    method public java.lang.String getTransformation();
+    method public String getTransformation();
     method public byte[] getWrappedKeyBytes();
-    method public java.lang.String getWrappingKeyAlias();
+    method public String getWrappingKeyAlias();
   }
 
 }
@@ -40533,14 +40866,14 @@
 
   public abstract class AutofillService extends android.app.Service {
     ctor public AutofillService();
-    method public final android.service.autofill.FillEventHistory getFillEventHistory();
+    method @Nullable public final android.service.autofill.FillEventHistory getFillEventHistory();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
-    method public abstract void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback);
-    method public abstract void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
-    field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
+    method public abstract void onFillRequest(@NonNull android.service.autofill.FillRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback);
+    method public abstract void onSaveRequest(@NonNull android.service.autofill.SaveRequest, @NonNull android.service.autofill.SaveCallback);
+    field public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
+    field public static final String SERVICE_META_DATA = "android.autofill";
   }
 
   public final class BatchUpdates implements android.os.Parcelable {
@@ -40552,8 +40885,8 @@
   public static class BatchUpdates.Builder {
     ctor public BatchUpdates.Builder();
     method public android.service.autofill.BatchUpdates build();
-    method public android.service.autofill.BatchUpdates.Builder transformChild(int, android.service.autofill.Transformation);
-    method public android.service.autofill.BatchUpdates.Builder updateTemplate(android.widget.RemoteViews);
+    method public android.service.autofill.BatchUpdates.Builder transformChild(int, @NonNull android.service.autofill.Transformation);
+    method public android.service.autofill.BatchUpdates.Builder updateTemplate(@NonNull android.widget.RemoteViews);
   }
 
   public final class CharSequenceTransformation implements android.os.Parcelable android.service.autofill.Transformation {
@@ -40563,8 +40896,8 @@
   }
 
   public static class CharSequenceTransformation.Builder {
-    ctor public CharSequenceTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, java.lang.String);
-    method public android.service.autofill.CharSequenceTransformation.Builder addField(android.view.autofill.AutofillId, java.util.regex.Pattern, java.lang.String);
+    ctor public CharSequenceTransformation.Builder(@NonNull android.view.autofill.AutofillId, @NonNull java.util.regex.Pattern, @NonNull String);
+    method public android.service.autofill.CharSequenceTransformation.Builder addField(@NonNull android.view.autofill.AutofillId, @NonNull java.util.regex.Pattern, @NonNull String);
     method public android.service.autofill.CharSequenceTransformation build();
   }
 
@@ -40575,10 +40908,10 @@
   }
 
   public static class CustomDescription.Builder {
-    ctor public CustomDescription.Builder(android.widget.RemoteViews);
-    method public android.service.autofill.CustomDescription.Builder addChild(int, android.service.autofill.Transformation);
-    method public android.service.autofill.CustomDescription.Builder addOnClickAction(int, android.service.autofill.OnClickAction);
-    method public android.service.autofill.CustomDescription.Builder batchUpdate(android.service.autofill.Validator, android.service.autofill.BatchUpdates);
+    ctor public CustomDescription.Builder(@NonNull android.widget.RemoteViews);
+    method public android.service.autofill.CustomDescription.Builder addChild(int, @NonNull android.service.autofill.Transformation);
+    method public android.service.autofill.CustomDescription.Builder addOnClickAction(int, @NonNull android.service.autofill.OnClickAction);
+    method public android.service.autofill.CustomDescription.Builder batchUpdate(@NonNull android.service.autofill.Validator, @NonNull android.service.autofill.BatchUpdates);
     method public android.service.autofill.CustomDescription build();
   }
 
@@ -40589,43 +40922,43 @@
   }
 
   public static final class Dataset.Builder {
-    ctor public Dataset.Builder(android.widget.RemoteViews);
+    ctor public Dataset.Builder(@NonNull android.widget.RemoteViews);
     ctor public Dataset.Builder();
-    method public android.service.autofill.Dataset build();
-    method public android.service.autofill.Dataset.Builder setAuthentication(android.content.IntentSender);
-    method public android.service.autofill.Dataset.Builder setId(java.lang.String);
-    method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue);
-    method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, android.widget.RemoteViews);
-    method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern);
-    method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern, android.widget.RemoteViews);
+    method @NonNull public android.service.autofill.Dataset build();
+    method @NonNull public android.service.autofill.Dataset.Builder setAuthentication(@Nullable android.content.IntentSender);
+    method @NonNull public android.service.autofill.Dataset.Builder setId(@Nullable String);
+    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue);
+    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @NonNull android.widget.RemoteViews);
+    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern);
+    method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.widget.RemoteViews);
   }
 
   public final class DateTransformation implements android.os.Parcelable android.service.autofill.Transformation {
-    ctor public DateTransformation(android.view.autofill.AutofillId, android.icu.text.DateFormat);
+    ctor public DateTransformation(@NonNull android.view.autofill.AutofillId, @NonNull android.icu.text.DateFormat);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.DateTransformation> CREATOR;
   }
 
   public final class DateValueSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
-    ctor public DateValueSanitizer(android.icu.text.DateFormat);
+    ctor public DateValueSanitizer(@NonNull android.icu.text.DateFormat);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.DateValueSanitizer> CREATOR;
   }
 
   public final class FieldClassification {
-    method public java.util.List<android.service.autofill.FieldClassification.Match> getMatches();
+    method @NonNull public java.util.List<android.service.autofill.FieldClassification.Match> getMatches();
   }
 
   public static final class FieldClassification.Match {
-    method public java.lang.String getCategoryId();
+    method @NonNull public String getCategoryId();
     method public float getScore();
   }
 
   public final class FillCallback {
-    method public void onFailure(java.lang.CharSequence);
-    method public void onSuccess(android.service.autofill.FillResponse);
+    method public void onFailure(@Nullable CharSequence);
+    method public void onSuccess(@Nullable android.service.autofill.FillResponse);
   }
 
   public final class FillContext implements android.os.Parcelable {
@@ -40638,20 +40971,20 @@
 
   public final class FillEventHistory implements android.os.Parcelable {
     method public int describeContents();
-    method public deprecated android.os.Bundle getClientState();
-    method public java.util.List<android.service.autofill.FillEventHistory.Event> getEvents();
+    method @Deprecated @Nullable public android.os.Bundle getClientState();
+    method @Nullable public java.util.List<android.service.autofill.FillEventHistory.Event> getEvents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.FillEventHistory> CREATOR;
   }
 
   public static final class FillEventHistory.Event {
-    method public java.util.Map<android.view.autofill.AutofillId, java.lang.String> getChangedFields();
-    method public android.os.Bundle getClientState();
-    method public java.lang.String getDatasetId();
-    method public java.util.Map<android.view.autofill.AutofillId, android.service.autofill.FieldClassification> getFieldsClassification();
-    method public java.util.Set<java.lang.String> getIgnoredDatasetIds();
-    method public java.util.Map<android.view.autofill.AutofillId, java.util.Set<java.lang.String>> getManuallyEnteredField();
-    method public java.util.Set<java.lang.String> getSelectedDatasetIds();
+    method @NonNull public java.util.Map<android.view.autofill.AutofillId,java.lang.String> getChangedFields();
+    method @Nullable public android.os.Bundle getClientState();
+    method @Nullable public String getDatasetId();
+    method @NonNull public java.util.Map<android.view.autofill.AutofillId,android.service.autofill.FieldClassification> getFieldsClassification();
+    method @NonNull public java.util.Set<java.lang.String> getIgnoredDatasetIds();
+    method @NonNull public java.util.Map<android.view.autofill.AutofillId,java.util.Set<java.lang.String>> getManuallyEnteredField();
+    method @NonNull public java.util.Set<java.lang.String> getSelectedDatasetIds();
     method public int getType();
     field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2
     field public static final int TYPE_CONTEXT_COMMITTED = 4; // 0x4
@@ -40662,8 +40995,8 @@
 
   public final class FillRequest implements android.os.Parcelable {
     method public int describeContents();
-    method public android.os.Bundle getClientState();
-    method public java.util.List<android.service.autofill.FillContext> getFillContexts();
+    method @Nullable public android.os.Bundle getClientState();
+    method @NonNull public java.util.List<android.service.autofill.FillContext> getFillContexts();
     method public int getFlags();
     method public int getId();
     method public void writeToParcel(android.os.Parcel, int);
@@ -40682,18 +41015,18 @@
 
   public static final class FillResponse.Builder {
     ctor public FillResponse.Builder();
-    method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
+    method @NonNull public android.service.autofill.FillResponse.Builder addDataset(@Nullable android.service.autofill.Dataset);
     method public android.service.autofill.FillResponse build();
     method public android.service.autofill.FillResponse.Builder disableAutofill(long);
-    method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
-    method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
-    method public android.service.autofill.FillResponse.Builder setFieldClassificationIds(android.view.autofill.AutofillId...);
+    method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews);
+    method public android.service.autofill.FillResponse.Builder setClientState(@Nullable android.os.Bundle);
+    method public android.service.autofill.FillResponse.Builder setFieldClassificationIds(@NonNull android.view.autofill.AutofillId...);
     method public android.service.autofill.FillResponse.Builder setFlags(int);
-    method public android.service.autofill.FillResponse.Builder setFooter(android.widget.RemoteViews);
-    method public android.service.autofill.FillResponse.Builder setHeader(android.widget.RemoteViews);
+    method public android.service.autofill.FillResponse.Builder setFooter(@NonNull android.widget.RemoteViews);
+    method public android.service.autofill.FillResponse.Builder setHeader(@NonNull android.widget.RemoteViews);
     method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...);
-    method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
-    method public android.service.autofill.FillResponse.Builder setUserData(android.service.autofill.UserData);
+    method @NonNull public android.service.autofill.FillResponse.Builder setSaveInfo(@NonNull android.service.autofill.SaveInfo);
+    method public android.service.autofill.FillResponse.Builder setUserData(@NonNull android.service.autofill.UserData);
   }
 
   public final class ImageTransformation implements android.os.Parcelable android.service.autofill.Transformation {
@@ -40703,37 +41036,37 @@
   }
 
   public static class ImageTransformation.Builder {
-    ctor public deprecated ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int);
-    ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int, java.lang.CharSequence);
-    method public deprecated android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int);
-    method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int, java.lang.CharSequence);
+    ctor @Deprecated public ImageTransformation.Builder(@NonNull android.view.autofill.AutofillId, @NonNull java.util.regex.Pattern, @DrawableRes int);
+    ctor public ImageTransformation.Builder(@NonNull android.view.autofill.AutofillId, @NonNull java.util.regex.Pattern, @DrawableRes int, @NonNull CharSequence);
+    method @Deprecated public android.service.autofill.ImageTransformation.Builder addOption(@NonNull java.util.regex.Pattern, @DrawableRes int);
+    method public android.service.autofill.ImageTransformation.Builder addOption(@NonNull java.util.regex.Pattern, @DrawableRes int, @NonNull CharSequence);
     method public android.service.autofill.ImageTransformation build();
   }
 
   public final class LuhnChecksumValidator implements android.os.Parcelable android.service.autofill.Validator {
-    ctor public LuhnChecksumValidator(android.view.autofill.AutofillId...);
+    ctor public LuhnChecksumValidator(@NonNull android.view.autofill.AutofillId...);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.LuhnChecksumValidator> CREATOR;
   }
 
-  public abstract interface OnClickAction {
+  public interface OnClickAction {
   }
 
   public final class RegexValidator implements android.os.Parcelable android.service.autofill.Validator {
-    ctor public RegexValidator(android.view.autofill.AutofillId, java.util.regex.Pattern);
+    ctor public RegexValidator(@NonNull android.view.autofill.AutofillId, @NonNull java.util.regex.Pattern);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.RegexValidator> CREATOR;
   }
 
-  public abstract interface Sanitizer {
+  public interface Sanitizer {
   }
 
   public final class SaveCallback {
-    method public void onFailure(java.lang.CharSequence);
+    method public void onFailure(CharSequence);
     method public void onSuccess();
-    method public void onSuccess(android.content.IntentSender);
+    method public void onSuccess(@NonNull android.content.IntentSender);
   }
 
   public final class SaveInfo implements android.os.Parcelable {
@@ -40754,43 +41087,43 @@
   }
 
   public static final class SaveInfo.Builder {
-    ctor public SaveInfo.Builder(int, android.view.autofill.AutofillId[]);
+    ctor public SaveInfo.Builder(int, @NonNull android.view.autofill.AutofillId[]);
     ctor public SaveInfo.Builder(int);
-    method public android.service.autofill.SaveInfo.Builder addSanitizer(android.service.autofill.Sanitizer, android.view.autofill.AutofillId...);
+    method @NonNull public android.service.autofill.SaveInfo.Builder addSanitizer(@NonNull android.service.autofill.Sanitizer, @NonNull android.view.autofill.AutofillId...);
     method public android.service.autofill.SaveInfo build();
-    method public android.service.autofill.SaveInfo.Builder setCustomDescription(android.service.autofill.CustomDescription);
-    method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
-    method public android.service.autofill.SaveInfo.Builder setFlags(int);
-    method public android.service.autofill.SaveInfo.Builder setNegativeAction(int, android.content.IntentSender);
-    method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
-    method public android.service.autofill.SaveInfo.Builder setTriggerId(android.view.autofill.AutofillId);
-    method public android.service.autofill.SaveInfo.Builder setValidator(android.service.autofill.Validator);
+    method @NonNull public android.service.autofill.SaveInfo.Builder setCustomDescription(@NonNull android.service.autofill.CustomDescription);
+    method @NonNull public android.service.autofill.SaveInfo.Builder setDescription(@Nullable CharSequence);
+    method @NonNull public android.service.autofill.SaveInfo.Builder setFlags(int);
+    method @NonNull public android.service.autofill.SaveInfo.Builder setNegativeAction(int, @Nullable android.content.IntentSender);
+    method @NonNull public android.service.autofill.SaveInfo.Builder setOptionalIds(@NonNull android.view.autofill.AutofillId[]);
+    method @NonNull public android.service.autofill.SaveInfo.Builder setTriggerId(@NonNull android.view.autofill.AutofillId);
+    method @NonNull public android.service.autofill.SaveInfo.Builder setValidator(@NonNull android.service.autofill.Validator);
   }
 
   public final class SaveRequest implements android.os.Parcelable {
     method public int describeContents();
-    method public android.os.Bundle getClientState();
-    method public java.util.List<java.lang.String> getDatasetIds();
-    method public java.util.List<android.service.autofill.FillContext> getFillContexts();
+    method @Nullable public android.os.Bundle getClientState();
+    method @Nullable public java.util.List<java.lang.String> getDatasetIds();
+    method @NonNull public java.util.List<android.service.autofill.FillContext> getFillContexts();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
   }
 
   public final class TextValueSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
-    ctor public TextValueSanitizer(java.util.regex.Pattern, java.lang.String);
+    ctor public TextValueSanitizer(@NonNull java.util.regex.Pattern, @NonNull String);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.TextValueSanitizer> CREATOR;
   }
 
-  public abstract interface Transformation {
+  public interface Transformation {
   }
 
   public final class UserData implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getFieldClassificationAlgorithm();
-    method public java.lang.String getFieldClassificationAlgorithmForCategory(java.lang.String);
-    method public java.lang.String getId();
+    method @Nullable public String getFieldClassificationAlgorithm();
+    method @Nullable public String getFieldClassificationAlgorithmForCategory(@NonNull String);
+    method public String getId();
     method public static int getMaxCategoryCount();
     method public static int getMaxFieldClassificationIdsSize();
     method public static int getMaxUserDataSize();
@@ -40801,20 +41134,20 @@
   }
 
   public static final class UserData.Builder {
-    ctor public UserData.Builder(java.lang.String, java.lang.String, java.lang.String);
-    method public android.service.autofill.UserData.Builder add(java.lang.String, java.lang.String);
+    ctor public UserData.Builder(@NonNull String, @NonNull String, @NonNull String);
+    method public android.service.autofill.UserData.Builder add(@NonNull String, @NonNull String);
     method public android.service.autofill.UserData build();
-    method public android.service.autofill.UserData.Builder setFieldClassificationAlgorithm(java.lang.String, android.os.Bundle);
-    method public android.service.autofill.UserData.Builder setFieldClassificationAlgorithmForCategory(java.lang.String, java.lang.String, android.os.Bundle);
+    method public android.service.autofill.UserData.Builder setFieldClassificationAlgorithm(@Nullable String, @Nullable android.os.Bundle);
+    method public android.service.autofill.UserData.Builder setFieldClassificationAlgorithmForCategory(@NonNull String, @Nullable String, @Nullable android.os.Bundle);
   }
 
-  public abstract interface Validator {
+  public interface Validator {
   }
 
   public final class Validators {
-    method public static android.service.autofill.Validator and(android.service.autofill.Validator...);
-    method public static android.service.autofill.Validator not(android.service.autofill.Validator);
-    method public static android.service.autofill.Validator or(android.service.autofill.Validator...);
+    method @NonNull public static android.service.autofill.Validator and(@NonNull android.service.autofill.Validator...);
+    method @NonNull public static android.service.autofill.Validator not(@NonNull android.service.autofill.Validator);
+    method @NonNull public static android.service.autofill.Validator or(@NonNull android.service.autofill.Validator...);
   }
 
   public final class VisibilitySetterAction implements android.service.autofill.OnClickAction android.os.Parcelable {
@@ -40824,9 +41157,9 @@
   }
 
   public static class VisibilitySetterAction.Builder {
-    ctor public VisibilitySetterAction.Builder(int, int);
+    ctor public VisibilitySetterAction.Builder(@IdRes int, int);
     method public android.service.autofill.VisibilitySetterAction build();
-    method public android.service.autofill.VisibilitySetterAction.Builder setVisibility(int, int);
+    method public android.service.autofill.VisibilitySetterAction.Builder setVisibility(@IdRes int, int);
   }
 
 }
@@ -40834,35 +41167,35 @@
 package android.service.carrier {
 
   public class CarrierIdentifier implements android.os.Parcelable {
-    ctor public CarrierIdentifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    ctor public CarrierIdentifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, int, int);
-    ctor public CarrierIdentifier(byte[], java.lang.String, java.lang.String);
+    ctor public CarrierIdentifier(String, String, @Nullable String, @Nullable String, @Nullable String, @Nullable String);
+    ctor public CarrierIdentifier(String, String, @Nullable String, @Nullable String, @Nullable String, @Nullable String, int, int);
+    ctor public CarrierIdentifier(byte[], @Nullable String, @Nullable String);
     method public int describeContents();
     method public int getCarrierId();
-    method public java.lang.String getGid1();
-    method public java.lang.String getGid2();
-    method public java.lang.String getImsi();
-    method public java.lang.String getMcc();
-    method public java.lang.String getMnc();
+    method @Nullable public String getGid1();
+    method @Nullable public String getGid2();
+    method @Nullable public String getImsi();
+    method public String getMcc();
+    method public String getMnc();
     method public int getPreciseCarrierId();
-    method public java.lang.String getSpn();
+    method @Nullable public String getSpn();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.carrier.CarrierIdentifier> CREATOR;
   }
 
   public abstract class CarrierMessagingService extends android.app.Service {
     ctor public CarrierMessagingService();
-    method public android.os.IBinder onBind(android.content.Intent);
-    method public void onDownloadMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
-    method public deprecated void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
-    method public void onReceiveTextSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
-    method public deprecated void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
-    method public void onSendDataSms(byte[], int, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
-    method public void onSendMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMmsResult>);
-    method public deprecated void onSendMultipartTextSms(java.util.List<java.lang.String>, int, java.lang.String, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMultipartSmsResult>);
-    method public void onSendMultipartTextSms(java.util.List<java.lang.String>, int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMultipartSmsResult>);
-    method public deprecated void onSendTextSms(java.lang.String, int, java.lang.String, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
-    method public void onSendTextSms(java.lang.String, int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
+    method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
+    method public void onDownloadMms(@NonNull android.net.Uri, int, @NonNull android.net.Uri, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
+    method @Deprecated public void onFilterSms(@NonNull android.service.carrier.MessagePdu, @NonNull String, int, int, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+    method public void onReceiveTextSms(@NonNull android.service.carrier.MessagePdu, @NonNull String, int, int, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
+    method @Deprecated public void onSendDataSms(@NonNull byte[], int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
+    method public void onSendDataSms(@NonNull byte[], int, @NonNull String, int, int, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
+    method public void onSendMms(@NonNull android.net.Uri, int, @Nullable android.net.Uri, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMmsResult>);
+    method @Deprecated public void onSendMultipartTextSms(@NonNull java.util.List<java.lang.String>, int, @NonNull String, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMultipartSmsResult>);
+    method public void onSendMultipartTextSms(@NonNull java.util.List<java.lang.String>, int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMultipartSmsResult>);
+    method @Deprecated public void onSendTextSms(@NonNull String, int, @NonNull String, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
+    method public void onSendTextSms(@NonNull String, int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
     field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
     field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
@@ -40873,22 +41206,22 @@
     field public static final int SEND_STATUS_ERROR = 2; // 0x2
     field public static final int SEND_STATUS_OK = 0; // 0x0
     field public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService";
+    field public static final String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService";
   }
 
-  public static abstract interface CarrierMessagingService.ResultCallback<T> {
-    method public abstract void onReceiveResult(T) throws android.os.RemoteException;
+  public static interface CarrierMessagingService.ResultCallback<T> {
+    method public void onReceiveResult(@NonNull T) throws android.os.RemoteException;
   }
 
   public static final class CarrierMessagingService.SendMmsResult {
-    ctor public CarrierMessagingService.SendMmsResult(int, byte[]);
-    method public byte[] getSendConfPdu();
+    ctor public CarrierMessagingService.SendMmsResult(int, @Nullable byte[]);
+    method @Nullable public byte[] getSendConfPdu();
     method public int getSendStatus();
   }
 
   public static final class CarrierMessagingService.SendMultipartSmsResult {
-    ctor public CarrierMessagingService.SendMultipartSmsResult(int, int[]);
-    method public int[] getMessageRefs();
+    ctor public CarrierMessagingService.SendMultipartSmsResult(int, @Nullable int[]);
+    method @Nullable public int[] getMessageRefs();
     method public int getSendStatus();
   }
 
@@ -40901,15 +41234,15 @@
   public abstract class CarrierService extends android.app.Service {
     ctor public CarrierService();
     method public final void notifyCarrierNetworkChange(boolean);
-    method public android.os.IBinder onBind(android.content.Intent);
+    method @CallSuper public android.os.IBinder onBind(android.content.Intent);
     method public abstract android.os.PersistableBundle onLoadConfig(android.service.carrier.CarrierIdentifier);
-    field public static final java.lang.String CARRIER_SERVICE_INTERFACE = "android.service.carrier.CarrierService";
+    field public static final String CARRIER_SERVICE_INTERFACE = "android.service.carrier.CarrierService";
   }
 
   public final class MessagePdu implements android.os.Parcelable {
-    ctor public MessagePdu(java.util.List<byte[]>);
+    ctor public MessagePdu(@NonNull java.util.List<byte[]>);
     method public int describeContents();
-    method public java.util.List<byte[]> getPdus();
+    method @NonNull public java.util.List<byte[]> getPdus();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.carrier.MessagePdu> CREATOR;
   }
@@ -40919,13 +41252,13 @@
 package android.service.chooser {
 
   public final class ChooserTarget implements android.os.Parcelable {
-    ctor public ChooserTarget(java.lang.CharSequence, android.graphics.drawable.Icon, float, android.content.ComponentName, android.os.Bundle);
+    ctor public ChooserTarget(CharSequence, android.graphics.drawable.Icon, float, android.content.ComponentName, @Nullable android.os.Bundle);
     method public int describeContents();
     method public android.content.ComponentName getComponentName();
     method public android.graphics.drawable.Icon getIcon();
     method public android.os.Bundle getIntentExtras();
     method public float getScore();
-    method public java.lang.CharSequence getTitle();
+    method public CharSequence getTitle();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.chooser.ChooserTarget> CREATOR;
   }
@@ -40934,9 +41267,9 @@
     ctor public ChooserTargetService();
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract java.util.List<android.service.chooser.ChooserTarget> onGetChooserTargets(android.content.ComponentName, android.content.IntentFilter);
-    field public static final java.lang.String BIND_PERMISSION = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
-    field public static final java.lang.String META_DATA_NAME = "android.service.chooser.chooser_target_service";
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
+    field public static final String BIND_PERMISSION = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
+    field public static final String META_DATA_NAME = "android.service.chooser.chooser_target_service";
+    field public static final String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
   }
 
 }
@@ -40952,7 +41285,7 @@
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public boolean dispatchTouchEvent(android.view.MotionEvent);
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
-    method public <T extends android.view.View> T findViewById(int);
+    method public <T extends android.view.View> T findViewById(@IdRes int);
     method public final void finish();
     method public android.view.Window getWindow();
     method public android.view.WindowManager getWindowManager();
@@ -40980,16 +41313,16 @@
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
-    method public final <T extends android.view.View> T requireViewById(int);
-    method public void setContentView(int);
+    method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
+    method public void setContentView(@LayoutRes int);
     method public void setContentView(android.view.View);
     method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public void setFullscreen(boolean);
     method public void setInteractive(boolean);
     method public void setScreenBright(boolean);
     method public final void wakeUp();
-    field public static final java.lang.String DREAM_META_DATA = "android.service.dream";
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.dreams.DreamService";
+    field public static final String DREAM_META_DATA = "android.service.dream";
+    field public static final String SERVICE_INTERFACE = "android.service.dreams.DreamService";
   }
 
 }
@@ -41005,28 +41338,28 @@
 
   public abstract class MediaBrowserService extends android.app.Service {
     ctor public MediaBrowserService();
-    method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
     method public final android.os.Bundle getBrowserRootHints();
     method public final android.media.session.MediaSessionManager.RemoteUserInfo getCurrentBrowserInfo();
-    method public android.media.session.MediaSession.Token getSessionToken();
-    method public void notifyChildrenChanged(java.lang.String);
-    method public void notifyChildrenChanged(java.lang.String, android.os.Bundle);
+    method @Nullable public android.media.session.MediaSession.Token getSessionToken();
+    method public void notifyChildrenChanged(@NonNull String);
+    method public void notifyChildrenChanged(@NonNull String, @NonNull android.os.Bundle);
     method public android.os.IBinder onBind(android.content.Intent);
-    method public abstract android.service.media.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
-    method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
-    method public void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, android.os.Bundle);
-    method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>);
+    method @Nullable public abstract android.service.media.MediaBrowserService.BrowserRoot onGetRoot(@NonNull String, int, @Nullable android.os.Bundle);
+    method public abstract void onLoadChildren(@NonNull String, @NonNull android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
+    method public void onLoadChildren(@NonNull String, @NonNull android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>, @NonNull android.os.Bundle);
+    method public void onLoadItem(String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>);
     method public void setSessionToken(android.media.session.MediaSession.Token);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
+    field public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
   }
 
   public static final class MediaBrowserService.BrowserRoot {
-    ctor public MediaBrowserService.BrowserRoot(java.lang.String, android.os.Bundle);
+    ctor public MediaBrowserService.BrowserRoot(@NonNull String, @Nullable android.os.Bundle);
     method public android.os.Bundle getExtras();
-    method public java.lang.String getRootId();
-    field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
-    field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT";
-    field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
+    method public String getRootId();
+    field public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+    field public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
+    field public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
   }
 
   public class MediaBrowserService.Result<T> {
@@ -41039,20 +41372,20 @@
 package android.service.notification {
 
   public final class Condition implements android.os.Parcelable {
-    ctor public Condition(android.net.Uri, java.lang.String, int);
-    ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int);
+    ctor public Condition(android.net.Uri, String, int);
+    ctor public Condition(android.net.Uri, String, String, String, int, int, int);
     ctor public Condition(android.os.Parcel);
     method public android.service.notification.Condition copy();
     method public int describeContents();
-    method public static boolean isValidId(android.net.Uri, java.lang.String);
+    method public static boolean isValidId(android.net.Uri, String);
     method public static android.net.Uri.Builder newId(android.content.Context);
-    method public static java.lang.String relevanceToString(int);
-    method public static java.lang.String stateToString(int);
+    method public static String relevanceToString(int);
+    method public static String stateToString(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.notification.Condition> CREATOR;
     field public static final int FLAG_RELEVANT_ALWAYS = 2; // 0x2
     field public static final int FLAG_RELEVANT_NOW = 1; // 0x1
-    field public static final java.lang.String SCHEME = "condition";
+    field public static final String SCHEME = "condition";
     field public static final int STATE_ERROR = 3; // 0x3
     field public static final int STATE_FALSE = 0; // 0x0
     field public static final int STATE_TRUE = 1; // 0x1
@@ -41060,52 +41393,52 @@
     field public final int flags;
     field public final int icon;
     field public final android.net.Uri id;
-    field public final java.lang.String line1;
-    field public final java.lang.String line2;
+    field public final String line1;
+    field public final String line2;
     field public final int state;
-    field public final java.lang.String summary;
+    field public final String summary;
   }
 
-  public abstract deprecated class ConditionProviderService extends android.app.Service {
-    ctor public ConditionProviderService();
-    method public final deprecated void notifyCondition(android.service.notification.Condition);
-    method public final deprecated void notifyConditions(android.service.notification.Condition...);
-    method public android.os.IBinder onBind(android.content.Intent);
-    method public abstract void onConnected();
-    method public void onRequestConditions(int);
-    method public abstract void onSubscribe(android.net.Uri);
-    method public abstract void onUnsubscribe(android.net.Uri);
-    method public static final void requestRebind(android.content.ComponentName);
-    method public final void requestUnbind();
-    field public static final deprecated java.lang.String EXTRA_RULE_ID = "android.service.notification.extra.RULE_ID";
-    field public static final deprecated java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
-    field public static final deprecated java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
-    field public static final deprecated java.lang.String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
+  @Deprecated public abstract class ConditionProviderService extends android.app.Service {
+    ctor @Deprecated public ConditionProviderService();
+    method @Deprecated public final void notifyCondition(android.service.notification.Condition);
+    method @Deprecated public final void notifyConditions(android.service.notification.Condition...);
+    method @Deprecated public android.os.IBinder onBind(android.content.Intent);
+    method @Deprecated public abstract void onConnected();
+    method @Deprecated public void onRequestConditions(int);
+    method @Deprecated public abstract void onSubscribe(android.net.Uri);
+    method @Deprecated public abstract void onUnsubscribe(android.net.Uri);
+    method @Deprecated public static final void requestRebind(android.content.ComponentName);
+    method @Deprecated public final void requestUnbind();
+    field @Deprecated public static final String EXTRA_RULE_ID = "android.service.notification.extra.RULE_ID";
+    field @Deprecated public static final String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
+    field @Deprecated public static final String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
+    field @Deprecated public static final String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
+    field @Deprecated public static final String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
 
   public abstract class NotificationListenerService extends android.app.Service {
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
-    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 @Deprecated public final void cancelNotification(String, String, int);
+    method public final void cancelNotification(String);
+    method public final void cancelNotifications(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 android.service.notification.StatusBarNotification[] getActiveNotifications(String[]);
     method public final int getCurrentInterruptionFilter();
     method public final int getCurrentListenerHints();
     method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
-    method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String, android.os.UserHandle);
-    method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String, android.os.UserHandle);
+    method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(@NonNull String, @NonNull android.os.UserHandle);
+    method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(@NonNull String, @NonNull android.os.UserHandle);
     method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onInterruptionFilterChanged(int);
     method public void onListenerConnected();
     method public void onListenerDisconnected();
     method public void onListenerHintsChanged(int);
-    method public void onNotificationChannelGroupModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannelGroup, int);
-    method public void onNotificationChannelModified(java.lang.String, android.os.UserHandle, android.app.NotificationChannel, int);
+    method public void onNotificationChannelGroupModified(String, android.os.UserHandle, android.app.NotificationChannelGroup, int);
+    method public void onNotificationChannelModified(String, android.os.UserHandle, android.app.NotificationChannel, int);
     method public void onNotificationPosted(android.service.notification.StatusBarNotification);
     method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
     method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
@@ -41116,9 +41449,9 @@
     method public final void requestListenerHints(int);
     method public static void requestRebind(android.content.ComponentName);
     method public final void requestUnbind();
-    method public final void setNotificationsShown(java.lang.String[]);
-    method public final void snoozeNotification(java.lang.String, long);
-    method public final void updateNotificationChannel(java.lang.String, android.os.UserHandle, android.app.NotificationChannel);
+    method public final void setNotificationsShown(String[]);
+    method public final void snoozeNotification(String, long);
+    method public final void updateNotificationChannel(@NonNull String, @NonNull android.os.UserHandle, @NonNull android.app.NotificationChannel);
     field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
     field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
     field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
@@ -41149,9 +41482,9 @@
     field public static final int REASON_TIMEOUT = 19; // 0x13
     field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
     field public static final int REASON_USER_STOPPED = 6; // 0x6
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
-    field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
-    field public static final deprecated int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
+    field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
+    field @Deprecated public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
+    field @Deprecated public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
   }
 
   public static class NotificationListenerService.Ranking {
@@ -41159,10 +41492,10 @@
     method public boolean canShowBadge();
     method public android.app.NotificationChannel getChannel();
     method public int getImportance();
-    method public java.lang.CharSequence getImportanceExplanation();
-    method public java.lang.String getKey();
+    method public CharSequence getImportanceExplanation();
+    method public String getKey();
     method public long getLastAudiblyAlertedMillis();
-    method public java.lang.String getOverrideGroupKey();
+    method public String getOverrideGroupKey();
     method public int getRank();
     method public int getSuppressedVisualEffects();
     method public int getUserSentiment();
@@ -41176,33 +41509,33 @@
 
   public static class NotificationListenerService.RankingMap implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String[] getOrderedKeys();
-    method public boolean getRanking(java.lang.String, android.service.notification.NotificationListenerService.Ranking);
+    method public String[] getOrderedKeys();
+    method public boolean getRanking(String, android.service.notification.NotificationListenerService.Ranking);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.notification.NotificationListenerService.RankingMap> CREATOR;
   }
 
   public class StatusBarNotification implements android.os.Parcelable {
-    ctor public deprecated StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
+    ctor @Deprecated public StatusBarNotification(String, String, int, String, int, int, int, android.app.Notification, android.os.UserHandle, long);
     ctor public StatusBarNotification(android.os.Parcel);
     method public android.service.notification.StatusBarNotification clone();
     method public int describeContents();
-    method public java.lang.String getGroupKey();
+    method public String getGroupKey();
     method public int getId();
-    method public java.lang.String getKey();
+    method public String getKey();
     method public android.app.Notification getNotification();
-    method public java.lang.String getOpPkg();
-    method public java.lang.String getOverrideGroupKey();
-    method public java.lang.String getPackageName();
+    method public String getOpPkg();
+    method public String getOverrideGroupKey();
+    method public String getPackageName();
     method public long getPostTime();
-    method public java.lang.String getTag();
+    method public String getTag();
     method public int getUid();
     method public android.os.UserHandle getUser();
-    method public deprecated int getUserId();
+    method @Deprecated public int getUserId();
     method public boolean isClearable();
     method public boolean isGroup();
     method public boolean isOngoing();
-    method public void setOverrideGroupKey(java.lang.String);
+    method public void setOverrideGroupKey(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.notification.StatusBarNotification> CREATOR;
   }
@@ -41268,16 +41601,16 @@
 
   public final class Tile implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.CharSequence getContentDescription();
+    method public CharSequence getContentDescription();
     method public android.graphics.drawable.Icon getIcon();
-    method public java.lang.CharSequence getLabel();
+    method public CharSequence getLabel();
     method public int getState();
-    method public java.lang.CharSequence getSubtitle();
-    method public void setContentDescription(java.lang.CharSequence);
+    method @Nullable public CharSequence getSubtitle();
+    method public void setContentDescription(CharSequence);
     method public void setIcon(android.graphics.drawable.Icon);
-    method public void setLabel(java.lang.CharSequence);
+    method public void setLabel(CharSequence);
     method public void setState(int);
-    method public void setSubtitle(java.lang.CharSequence);
+    method public void setSubtitle(@Nullable CharSequence);
     method public void updateTile();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.quicksettings.Tile> CREATOR;
@@ -41300,10 +41633,10 @@
     method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
     method public final void showDialog(android.app.Dialog);
     method public final void startActivityAndCollapse(android.content.Intent);
-    method public final void unlockAndRun(java.lang.Runnable);
-    field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
-    field public static final java.lang.String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
-    field public static final java.lang.String META_DATA_ACTIVE_TILE = "android.service.quicksettings.ACTIVE_TILE";
+    method public final void unlockAndRun(Runnable);
+    field public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+    field public static final String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
+    field public static final String META_DATA_ACTIVE_TILE = "android.service.quicksettings.ACTIVE_TILE";
   }
 
 }
@@ -41313,7 +41646,7 @@
   public abstract class RestrictionsReceiver extends android.content.BroadcastReceiver {
     ctor public RestrictionsReceiver();
     method public void onReceive(android.content.Context, android.content.Intent);
-    method public abstract void onRequestPermission(android.content.Context, java.lang.String, java.lang.String, java.lang.String, android.os.PersistableBundle);
+    method public abstract void onRequestPermission(android.content.Context, String, String, String, android.os.PersistableBundle);
   }
 
 }
@@ -41324,13 +41657,13 @@
     ctor public SpellCheckerService();
     method public abstract android.service.textservice.SpellCheckerService.Session createSession();
     method public final android.os.IBinder onBind(android.content.Intent);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.textservice.SpellCheckerService";
+    field public static final String SERVICE_INTERFACE = "android.service.textservice.SpellCheckerService";
   }
 
-  public static abstract class SpellCheckerService.Session {
+  public abstract static class SpellCheckerService.Session {
     ctor public SpellCheckerService.Session();
     method public android.os.Bundle getBundle();
-    method public java.lang.String getLocale();
+    method public String getLocale();
     method public void onCancel();
     method public void onClose();
     method public abstract void onCreate();
@@ -41360,41 +41693,48 @@
     field public static final int STATE_KEYPHRASE_UNSUPPORTED = -1; // 0xffffffff
   }
 
-  public static abstract class AlwaysOnHotwordDetector.Callback {
+  public abstract static class AlwaysOnHotwordDetector.Callback {
     ctor public AlwaysOnHotwordDetector.Callback();
     method public abstract void onAvailabilityChanged(int);
-    method public abstract void onDetected(android.service.voice.AlwaysOnHotwordDetector.EventPayload);
+    method public abstract void onDetected(@NonNull android.service.voice.AlwaysOnHotwordDetector.EventPayload);
     method public abstract void onError();
     method public abstract void onRecognitionPaused();
     method public abstract void onRecognitionResumed();
   }
 
   public static class AlwaysOnHotwordDetector.EventPayload {
-    method public android.media.AudioFormat getCaptureAudioFormat();
-    method public byte[] getTriggerAudio();
+    method @Nullable public android.media.AudioFormat getCaptureAudioFormat();
+    method @Nullable public byte[] getTriggerAudio();
   }
 
   public class VoiceInteractionService extends android.app.Service {
     ctor public VoiceInteractionService();
-    method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(java.lang.String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
+    method public final void clearTranscription(boolean);
+    method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
     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 @Nullable public java.util.Set<java.lang.String> onGetSupportedVoiceActions(@NonNull java.util.Set<java.lang.String>);
     method public void onLaunchVoiceAssistFromKeyguard();
     method public void onReady();
     method public void onShutdown();
     method public void setDisabledShowContext(int);
+    method public final void setTranscription(@NonNull String);
+    method public final void setVoiceState(int);
     method public void showSession(android.os.Bundle, int);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
-    field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
+    field public static final String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
+    field public static final String SERVICE_META_DATA = "android.voice_interaction";
+    field public static final int VOICE_STATE_CONDITIONAL_LISTENING = 1; // 0x1
+    field public static final int VOICE_STATE_FULFILLING = 3; // 0x3
+    field public static final int VOICE_STATE_LISTENING = 2; // 0x2
+    field public static final int VOICE_STATE_NONE = 0; // 0x0
   }
 
   public class VoiceInteractionSession implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback {
     ctor public VoiceInteractionSession(android.content.Context);
     ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
     method public void closeSystemDialogs();
-    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public void dump(String, java.io.FileDescriptor, java.io.PrintWriter, String[]);
     method public void finish();
     method public android.content.Context getContext();
     method public int getDisabledShowContext();
@@ -41402,7 +41742,7 @@
     method public int getUserDisabledShowContext();
     method public android.app.Dialog getWindow();
     method public void hide();
-    method public void onAssistStructureFailure(java.lang.Throwable);
+    method public void onAssistStructureFailure(Throwable);
     method public void onBackPressed();
     method public void onCancelRequest(android.service.voice.VoiceInteractionSession.Request);
     method public void onCloseSystemDialogs();
@@ -41411,10 +41751,10 @@
     method public void onCreate();
     method public android.view.View onCreateContentView();
     method public void onDestroy();
-    method public boolean[] onGetSupportedCommands(java.lang.String[]);
-    method public void onHandleAssist(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent);
-    method public void onHandleAssistSecondary(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent, int, int);
-    method public void onHandleScreenshot(android.graphics.Bitmap);
+    method public boolean[] onGetSupportedCommands(String[]);
+    method public void onHandleAssist(@Nullable android.os.Bundle, @Nullable android.app.assist.AssistStructure, @Nullable android.app.assist.AssistContent);
+    method public void onHandleAssistSecondary(@Nullable android.os.Bundle, @Nullable android.app.assist.AssistStructure, @Nullable android.app.assist.AssistContent, int, int);
+    method public void onHandleScreenshot(@Nullable android.graphics.Bitmap);
     method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
@@ -41443,6 +41783,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_AUTOMOTIVE_SYSTEM_UI = 128; // 0x80
     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
@@ -41450,26 +41791,26 @@
   }
 
   public static final class VoiceInteractionSession.AbortVoiceRequest extends android.service.voice.VoiceInteractionSession.Request {
-    method public deprecated java.lang.CharSequence getMessage();
-    method public android.app.VoiceInteractor.Prompt getVoicePrompt();
+    method @Deprecated @Nullable public CharSequence getMessage();
+    method @Nullable public android.app.VoiceInteractor.Prompt getVoicePrompt();
     method public void sendAbortResult(android.os.Bundle);
   }
 
   public static final class VoiceInteractionSession.CommandRequest extends android.service.voice.VoiceInteractionSession.Request {
-    method public java.lang.String getCommand();
+    method public String getCommand();
     method public void sendIntermediateResult(android.os.Bundle);
     method public void sendResult(android.os.Bundle);
   }
 
   public static final class VoiceInteractionSession.CompleteVoiceRequest extends android.service.voice.VoiceInteractionSession.Request {
-    method public deprecated java.lang.CharSequence getMessage();
-    method public android.app.VoiceInteractor.Prompt getVoicePrompt();
+    method @Deprecated @Nullable public CharSequence getMessage();
+    method @Nullable public android.app.VoiceInteractor.Prompt getVoicePrompt();
     method public void sendCompleteResult(android.os.Bundle);
   }
 
   public static final class VoiceInteractionSession.ConfirmationRequest extends android.service.voice.VoiceInteractionSession.Request {
-    method public deprecated java.lang.CharSequence getPrompt();
-    method public android.app.VoiceInteractor.Prompt getVoicePrompt();
+    method @Deprecated @Nullable public CharSequence getPrompt();
+    method @Nullable public android.app.VoiceInteractor.Prompt getVoicePrompt();
     method public void sendConfirmationResult(boolean, android.os.Bundle);
   }
 
@@ -41485,15 +41826,15 @@
 
   public static final class VoiceInteractionSession.PickOptionRequest extends android.service.voice.VoiceInteractionSession.Request {
     method public android.app.VoiceInteractor.PickOptionRequest.Option[] getOptions();
-    method public deprecated java.lang.CharSequence getPrompt();
-    method public android.app.VoiceInteractor.Prompt getVoicePrompt();
+    method @Deprecated @Nullable public CharSequence getPrompt();
+    method @Nullable public android.app.VoiceInteractor.Prompt getVoicePrompt();
     method public void sendIntermediatePickOptionResult(android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle);
     method public void sendPickOptionResult(android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle);
   }
 
   public static class VoiceInteractionSession.Request {
     method public void cancel();
-    method public java.lang.String getCallingPackage();
+    method public String getCallingPackage();
     method public int getCallingUid();
     method public android.os.Bundle getExtras();
     method public boolean isActive();
@@ -41511,10 +41852,10 @@
 
   public abstract class VrListenerService extends android.app.Service {
     ctor public VrListenerService();
-    method public static final boolean isVrModePackageEnabled(android.content.Context, android.content.ComponentName);
+    method public static final boolean isVrModePackageEnabled(@NonNull android.content.Context, @NonNull android.content.ComponentName);
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onCurrentVrActivityChanged(android.content.ComponentName);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
+    field public static final String SERVICE_INTERFACE = "android.service.vr.VrListenerService";
   }
 
 }
@@ -41525,13 +41866,13 @@
     ctor public WallpaperService();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract android.service.wallpaper.WallpaperService.Engine onCreateEngine();
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.wallpaper.WallpaperService";
-    field public static final java.lang.String SERVICE_META_DATA = "android.service.wallpaper";
+    field public static final String SERVICE_INTERFACE = "android.service.wallpaper.WallpaperService";
+    field public static final String SERVICE_META_DATA = "android.service.wallpaper";
   }
 
   public class WallpaperService.Engine {
     ctor public WallpaperService.Engine();
-    method protected void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method protected void dump(String, java.io.FileDescriptor, java.io.PrintWriter, String[]);
     method public int getDesiredMinimumHeight();
     method public int getDesiredMinimumWidth();
     method public android.content.Context getDisplayContext();
@@ -41540,8 +41881,8 @@
     method public boolean isVisible();
     method public void notifyColorsChanged();
     method public void onApplyWindowInsets(android.view.WindowInsets);
-    method public android.os.Bundle onCommand(java.lang.String, int, int, int, android.os.Bundle, boolean);
-    method public android.app.WallpaperColors onComputeColors();
+    method public android.os.Bundle onCommand(String, int, int, int, android.os.Bundle, boolean);
+    method @Nullable public android.app.WallpaperColors onComputeColors();
     method public void onCreate(android.view.SurfaceHolder);
     method public void onDesiredSizeChanged(int, int);
     method public void onDestroy();
@@ -41560,16 +41901,16 @@
 
 package android.speech {
 
-  public abstract interface RecognitionListener {
-    method public abstract void onBeginningOfSpeech();
-    method public abstract void onBufferReceived(byte[]);
-    method public abstract void onEndOfSpeech();
-    method public abstract void onError(int);
-    method public abstract void onEvent(int, android.os.Bundle);
-    method public abstract void onPartialResults(android.os.Bundle);
-    method public abstract void onReadyForSpeech(android.os.Bundle);
-    method public abstract void onResults(android.os.Bundle);
-    method public abstract void onRmsChanged(float);
+  public interface RecognitionListener {
+    method public void onBeginningOfSpeech();
+    method public void onBufferReceived(byte[]);
+    method public void onEndOfSpeech();
+    method public void onError(int);
+    method public void onEvent(int, android.os.Bundle);
+    method public void onPartialResults(android.os.Bundle);
+    method public void onReadyForSpeech(android.os.Bundle);
+    method public void onResults(android.os.Bundle);
+    method public void onRmsChanged(float);
   }
 
   public abstract class RecognitionService extends android.app.Service {
@@ -41578,8 +41919,8 @@
     method protected abstract void onCancel(android.speech.RecognitionService.Callback);
     method protected abstract void onStartListening(android.content.Intent, android.speech.RecognitionService.Callback);
     method protected abstract void onStopListening(android.speech.RecognitionService.Callback);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.speech.RecognitionService";
-    field public static final java.lang.String SERVICE_META_DATA = "android.speech";
+    field public static final String SERVICE_INTERFACE = "android.speech.RecognitionService";
+    field public static final String SERVICE_META_DATA = "android.speech";
   }
 
   public class RecognitionService.Callback {
@@ -41596,33 +41937,33 @@
 
   public class RecognizerIntent {
     method public static final android.content.Intent getVoiceDetailsIntent(android.content.Context);
-    field public static final java.lang.String ACTION_GET_LANGUAGE_DETAILS = "android.speech.action.GET_LANGUAGE_DETAILS";
-    field public static final java.lang.String ACTION_RECOGNIZE_SPEECH = "android.speech.action.RECOGNIZE_SPEECH";
-    field public static final java.lang.String ACTION_VOICE_SEARCH_HANDS_FREE = "android.speech.action.VOICE_SEARCH_HANDS_FREE";
-    field public static final java.lang.String ACTION_WEB_SEARCH = "android.speech.action.WEB_SEARCH";
-    field public static final java.lang.String DETAILS_META_DATA = "android.speech.DETAILS";
-    field public static final java.lang.String EXTRA_CALLING_PACKAGE = "calling_package";
-    field public static final java.lang.String EXTRA_CONFIDENCE_SCORES = "android.speech.extra.CONFIDENCE_SCORES";
-    field public static final java.lang.String EXTRA_LANGUAGE = "android.speech.extra.LANGUAGE";
-    field public static final java.lang.String EXTRA_LANGUAGE_MODEL = "android.speech.extra.LANGUAGE_MODEL";
-    field public static final java.lang.String EXTRA_LANGUAGE_PREFERENCE = "android.speech.extra.LANGUAGE_PREFERENCE";
-    field public static final java.lang.String EXTRA_MAX_RESULTS = "android.speech.extra.MAX_RESULTS";
-    field public static final java.lang.String EXTRA_ONLY_RETURN_LANGUAGE_PREFERENCE = "android.speech.extra.ONLY_RETURN_LANGUAGE_PREFERENCE";
-    field public static final java.lang.String EXTRA_ORIGIN = "android.speech.extra.ORIGIN";
-    field public static final java.lang.String EXTRA_PARTIAL_RESULTS = "android.speech.extra.PARTIAL_RESULTS";
-    field public static final java.lang.String EXTRA_PREFER_OFFLINE = "android.speech.extra.PREFER_OFFLINE";
-    field public static final java.lang.String EXTRA_PROMPT = "android.speech.extra.PROMPT";
-    field public static final java.lang.String EXTRA_RESULTS = "android.speech.extra.RESULTS";
-    field public static final java.lang.String EXTRA_RESULTS_PENDINGINTENT = "android.speech.extra.RESULTS_PENDINGINTENT";
-    field public static final java.lang.String EXTRA_RESULTS_PENDINGINTENT_BUNDLE = "android.speech.extra.RESULTS_PENDINGINTENT_BUNDLE";
-    field public static final java.lang.String EXTRA_SECURE = "android.speech.extras.EXTRA_SECURE";
-    field public static final java.lang.String EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS";
-    field public static final java.lang.String EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_MINIMUM_LENGTH_MILLIS";
-    field public static final java.lang.String EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS";
-    field public static final java.lang.String EXTRA_SUPPORTED_LANGUAGES = "android.speech.extra.SUPPORTED_LANGUAGES";
-    field public static final java.lang.String EXTRA_WEB_SEARCH_ONLY = "android.speech.extra.WEB_SEARCH_ONLY";
-    field public static final java.lang.String LANGUAGE_MODEL_FREE_FORM = "free_form";
-    field public static final java.lang.String LANGUAGE_MODEL_WEB_SEARCH = "web_search";
+    field public static final String ACTION_GET_LANGUAGE_DETAILS = "android.speech.action.GET_LANGUAGE_DETAILS";
+    field public static final String ACTION_RECOGNIZE_SPEECH = "android.speech.action.RECOGNIZE_SPEECH";
+    field public static final String ACTION_VOICE_SEARCH_HANDS_FREE = "android.speech.action.VOICE_SEARCH_HANDS_FREE";
+    field public static final String ACTION_WEB_SEARCH = "android.speech.action.WEB_SEARCH";
+    field public static final String DETAILS_META_DATA = "android.speech.DETAILS";
+    field public static final String EXTRA_CALLING_PACKAGE = "calling_package";
+    field public static final String EXTRA_CONFIDENCE_SCORES = "android.speech.extra.CONFIDENCE_SCORES";
+    field public static final String EXTRA_LANGUAGE = "android.speech.extra.LANGUAGE";
+    field public static final String EXTRA_LANGUAGE_MODEL = "android.speech.extra.LANGUAGE_MODEL";
+    field public static final String EXTRA_LANGUAGE_PREFERENCE = "android.speech.extra.LANGUAGE_PREFERENCE";
+    field public static final String EXTRA_MAX_RESULTS = "android.speech.extra.MAX_RESULTS";
+    field public static final String EXTRA_ONLY_RETURN_LANGUAGE_PREFERENCE = "android.speech.extra.ONLY_RETURN_LANGUAGE_PREFERENCE";
+    field public static final String EXTRA_ORIGIN = "android.speech.extra.ORIGIN";
+    field public static final String EXTRA_PARTIAL_RESULTS = "android.speech.extra.PARTIAL_RESULTS";
+    field public static final String EXTRA_PREFER_OFFLINE = "android.speech.extra.PREFER_OFFLINE";
+    field public static final String EXTRA_PROMPT = "android.speech.extra.PROMPT";
+    field public static final String EXTRA_RESULTS = "android.speech.extra.RESULTS";
+    field public static final String EXTRA_RESULTS_PENDINGINTENT = "android.speech.extra.RESULTS_PENDINGINTENT";
+    field public static final String EXTRA_RESULTS_PENDINGINTENT_BUNDLE = "android.speech.extra.RESULTS_PENDINGINTENT_BUNDLE";
+    field public static final String EXTRA_SECURE = "android.speech.extras.EXTRA_SECURE";
+    field public static final String EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS";
+    field public static final String EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_MINIMUM_LENGTH_MILLIS";
+    field public static final String EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS";
+    field public static final String EXTRA_SUPPORTED_LANGUAGES = "android.speech.extra.SUPPORTED_LANGUAGES";
+    field public static final String EXTRA_WEB_SEARCH_ONLY = "android.speech.extra.WEB_SEARCH_ONLY";
+    field public static final String LANGUAGE_MODEL_FREE_FORM = "free_form";
+    field public static final String LANGUAGE_MODEL_WEB_SEARCH = "web_search";
     field public static final int RESULT_AUDIO_ERROR = 5; // 0x5
     field public static final int RESULT_CLIENT_ERROR = 2; // 0x2
     field public static final int RESULT_NETWORK_ERROR = 4; // 0x4
@@ -41631,13 +41972,13 @@
   }
 
   public class RecognizerResultsIntent {
-    field public static final java.lang.String ACTION_VOICE_SEARCH_RESULTS = "android.speech.action.VOICE_SEARCH_RESULTS";
-    field public static final java.lang.String EXTRA_VOICE_SEARCH_RESULT_HTML = "android.speech.extras.VOICE_SEARCH_RESULT_HTML";
-    field public static final java.lang.String EXTRA_VOICE_SEARCH_RESULT_HTML_BASE_URLS = "android.speech.extras.VOICE_SEARCH_RESULT_HTML_BASE_URLS";
-    field public static final java.lang.String EXTRA_VOICE_SEARCH_RESULT_HTTP_HEADERS = "android.speech.extras.EXTRA_VOICE_SEARCH_RESULT_HTTP_HEADERS";
-    field public static final java.lang.String EXTRA_VOICE_SEARCH_RESULT_STRINGS = "android.speech.extras.VOICE_SEARCH_RESULT_STRINGS";
-    field public static final java.lang.String EXTRA_VOICE_SEARCH_RESULT_URLS = "android.speech.extras.VOICE_SEARCH_RESULT_URLS";
-    field public static final java.lang.String URI_SCHEME_INLINE = "inline";
+    field public static final String ACTION_VOICE_SEARCH_RESULTS = "android.speech.action.VOICE_SEARCH_RESULTS";
+    field public static final String EXTRA_VOICE_SEARCH_RESULT_HTML = "android.speech.extras.VOICE_SEARCH_RESULT_HTML";
+    field public static final String EXTRA_VOICE_SEARCH_RESULT_HTML_BASE_URLS = "android.speech.extras.VOICE_SEARCH_RESULT_HTML_BASE_URLS";
+    field public static final String EXTRA_VOICE_SEARCH_RESULT_HTTP_HEADERS = "android.speech.extras.EXTRA_VOICE_SEARCH_RESULT_HTTP_HEADERS";
+    field public static final String EXTRA_VOICE_SEARCH_RESULT_STRINGS = "android.speech.extras.VOICE_SEARCH_RESULT_STRINGS";
+    field public static final String EXTRA_VOICE_SEARCH_RESULT_URLS = "android.speech.extras.VOICE_SEARCH_RESULT_URLS";
+    field public static final String URI_SCHEME_INLINE = "inline";
   }
 
   public class SpeechRecognizer {
@@ -41649,7 +41990,7 @@
     method public void setRecognitionListener(android.speech.RecognitionListener);
     method public void startListening(android.content.Intent);
     method public void stopListening();
-    field public static final java.lang.String CONFIDENCE_SCORES = "confidence_scores";
+    field public static final String CONFIDENCE_SCORES = "confidence_scores";
     field public static final int ERROR_AUDIO = 3; // 0x3
     field public static final int ERROR_CLIENT = 5; // 0x5
     field public static final int ERROR_INSUFFICIENT_PERMISSIONS = 9; // 0x9
@@ -41659,82 +42000,82 @@
     field public static final int ERROR_RECOGNIZER_BUSY = 8; // 0x8
     field public static final int ERROR_SERVER = 4; // 0x4
     field public static final int ERROR_SPEECH_TIMEOUT = 6; // 0x6
-    field public static final java.lang.String RESULTS_RECOGNITION = "results_recognition";
+    field public static final String RESULTS_RECOGNITION = "results_recognition";
   }
 
 }
 
 package android.speech.tts {
 
-  public abstract interface SynthesisCallback {
-    method public abstract int audioAvailable(byte[], int, int);
-    method public abstract int done();
-    method public abstract void error();
-    method public abstract void error(int);
-    method public abstract int getMaxBufferSize();
-    method public abstract boolean hasFinished();
-    method public abstract boolean hasStarted();
+  public interface SynthesisCallback {
+    method public int audioAvailable(byte[], int, int);
+    method public int done();
+    method public void error();
+    method public void error(int);
+    method public int getMaxBufferSize();
+    method public boolean hasFinished();
+    method public boolean hasStarted();
     method public default void rangeStart(int, int, int);
-    method public abstract int start(int, int, int);
+    method public int start(int, int, @IntRange(from=1, to=2) int);
   }
 
   public final class SynthesisRequest {
-    ctor public SynthesisRequest(java.lang.String, android.os.Bundle);
-    ctor public SynthesisRequest(java.lang.CharSequence, android.os.Bundle);
+    ctor public SynthesisRequest(String, android.os.Bundle);
+    ctor public SynthesisRequest(CharSequence, android.os.Bundle);
     method public int getCallerUid();
-    method public java.lang.CharSequence getCharSequenceText();
-    method public java.lang.String getCountry();
-    method public java.lang.String getLanguage();
+    method public CharSequence getCharSequenceText();
+    method public String getCountry();
+    method public String getLanguage();
     method public android.os.Bundle getParams();
     method public int getPitch();
     method public int getSpeechRate();
-    method public deprecated java.lang.String getText();
-    method public java.lang.String getVariant();
-    method public java.lang.String getVoiceName();
+    method @Deprecated public String getText();
+    method public String getVariant();
+    method public String getVoiceName();
   }
 
   public class TextToSpeech {
     ctor public TextToSpeech(android.content.Context, android.speech.tts.TextToSpeech.OnInitListener);
-    ctor public TextToSpeech(android.content.Context, android.speech.tts.TextToSpeech.OnInitListener, java.lang.String);
-    method public int addEarcon(java.lang.String, java.lang.String, int);
-    method public deprecated int addEarcon(java.lang.String, java.lang.String);
-    method public int addEarcon(java.lang.String, java.io.File);
-    method public int addSpeech(java.lang.String, java.lang.String, int);
-    method public int addSpeech(java.lang.CharSequence, java.lang.String, int);
-    method public int addSpeech(java.lang.String, java.lang.String);
-    method public int addSpeech(java.lang.CharSequence, java.io.File);
-    method public deprecated boolean areDefaultsEnforced();
+    ctor public TextToSpeech(android.content.Context, android.speech.tts.TextToSpeech.OnInitListener, String);
+    method public int addEarcon(String, String, @RawRes int);
+    method @Deprecated public int addEarcon(String, String);
+    method public int addEarcon(String, java.io.File);
+    method public int addSpeech(String, String, @RawRes int);
+    method public int addSpeech(CharSequence, String, @RawRes int);
+    method public int addSpeech(String, String);
+    method public int addSpeech(CharSequence, java.io.File);
+    method @Deprecated public boolean areDefaultsEnforced();
     method public java.util.Set<java.util.Locale> getAvailableLanguages();
-    method public java.lang.String getDefaultEngine();
-    method public deprecated java.util.Locale getDefaultLanguage();
+    method public String getDefaultEngine();
+    method @Deprecated public java.util.Locale getDefaultLanguage();
     method public android.speech.tts.Voice getDefaultVoice();
     method public java.util.List<android.speech.tts.TextToSpeech.EngineInfo> getEngines();
-    method public deprecated java.util.Set<java.lang.String> getFeatures(java.util.Locale);
-    method public deprecated java.util.Locale getLanguage();
+    method @Deprecated public java.util.Set<java.lang.String> getFeatures(java.util.Locale);
+    method @Deprecated public java.util.Locale getLanguage();
     method public static int getMaxSpeechInputLength();
     method public android.speech.tts.Voice getVoice();
     method public java.util.Set<android.speech.tts.Voice> getVoices();
     method public int isLanguageAvailable(java.util.Locale);
     method public boolean isSpeaking();
-    method public int playEarcon(java.lang.String, int, android.os.Bundle, java.lang.String);
-    method public deprecated int playEarcon(java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>);
-    method public deprecated int playSilence(long, int, java.util.HashMap<java.lang.String, java.lang.String>);
-    method public int playSilentUtterance(long, int, java.lang.String);
+    method public int playEarcon(String, int, android.os.Bundle, String);
+    method @Deprecated public int playEarcon(String, int, java.util.HashMap<java.lang.String,java.lang.String>);
+    method @Deprecated public int playSilence(long, int, java.util.HashMap<java.lang.String,java.lang.String>);
+    method public int playSilentUtterance(long, int, String);
     method public int setAudioAttributes(android.media.AudioAttributes);
-    method public deprecated int setEngineByPackageName(java.lang.String);
+    method @Deprecated public int setEngineByPackageName(String);
     method public int setLanguage(java.util.Locale);
-    method public deprecated int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
+    method @Deprecated public int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
     method public int setOnUtteranceProgressListener(android.speech.tts.UtteranceProgressListener);
     method public int setPitch(float);
     method public int setSpeechRate(float);
     method public int setVoice(android.speech.tts.Voice);
     method public void shutdown();
-    method public int speak(java.lang.CharSequence, int, android.os.Bundle, java.lang.String);
-    method public deprecated int speak(java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>);
+    method public int speak(CharSequence, int, android.os.Bundle, String);
+    method @Deprecated public int speak(String, int, java.util.HashMap<java.lang.String,java.lang.String>);
     method public int stop();
-    method public int synthesizeToFile(java.lang.CharSequence, android.os.Bundle, java.io.File, java.lang.String);
-    method public deprecated int synthesizeToFile(java.lang.String, java.util.HashMap<java.lang.String, java.lang.String>, java.lang.String);
-    field public static final java.lang.String ACTION_TTS_QUEUE_PROCESSING_COMPLETED = "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED";
+    method public int synthesizeToFile(CharSequence, android.os.Bundle, java.io.File, String);
+    method @Deprecated public int synthesizeToFile(String, java.util.HashMap<java.lang.String,java.lang.String>, String);
+    field public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED = "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED";
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_INVALID_REQUEST = -8; // 0xfffffff8
     field public static final int ERROR_NETWORK = -6; // 0xfffffffa
@@ -41756,87 +42097,87 @@
 
   public class TextToSpeech.Engine {
     ctor public TextToSpeech.Engine();
-    field public static final java.lang.String ACTION_CHECK_TTS_DATA = "android.speech.tts.engine.CHECK_TTS_DATA";
-    field public static final java.lang.String ACTION_GET_SAMPLE_TEXT = "android.speech.tts.engine.GET_SAMPLE_TEXT";
-    field public static final java.lang.String ACTION_INSTALL_TTS_DATA = "android.speech.tts.engine.INSTALL_TTS_DATA";
-    field public static final java.lang.String ACTION_TTS_DATA_INSTALLED = "android.speech.tts.engine.TTS_DATA_INSTALLED";
-    field public static final deprecated int CHECK_VOICE_DATA_BAD_DATA = -1; // 0xffffffff
+    field public static final String ACTION_CHECK_TTS_DATA = "android.speech.tts.engine.CHECK_TTS_DATA";
+    field public static final String ACTION_GET_SAMPLE_TEXT = "android.speech.tts.engine.GET_SAMPLE_TEXT";
+    field public static final String ACTION_INSTALL_TTS_DATA = "android.speech.tts.engine.INSTALL_TTS_DATA";
+    field public static final String ACTION_TTS_DATA_INSTALLED = "android.speech.tts.engine.TTS_DATA_INSTALLED";
+    field @Deprecated public static final int CHECK_VOICE_DATA_BAD_DATA = -1; // 0xffffffff
     field public static final int CHECK_VOICE_DATA_FAIL = 0; // 0x0
-    field public static final deprecated int CHECK_VOICE_DATA_MISSING_DATA = -2; // 0xfffffffe
-    field public static final deprecated int CHECK_VOICE_DATA_MISSING_VOLUME = -3; // 0xfffffffd
+    field @Deprecated public static final int CHECK_VOICE_DATA_MISSING_DATA = -2; // 0xfffffffe
+    field @Deprecated public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3; // 0xfffffffd
     field public static final int CHECK_VOICE_DATA_PASS = 1; // 0x1
     field public static final int DEFAULT_STREAM = 3; // 0x3
-    field public static final java.lang.String EXTRA_AVAILABLE_VOICES = "availableVoices";
-    field public static final deprecated java.lang.String EXTRA_CHECK_VOICE_DATA_FOR = "checkVoiceDataFor";
-    field public static final java.lang.String EXTRA_SAMPLE_TEXT = "sampleText";
-    field public static final deprecated java.lang.String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
-    field public static final java.lang.String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices";
-    field public static final deprecated java.lang.String EXTRA_VOICE_DATA_FILES = "dataFiles";
-    field public static final deprecated java.lang.String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
-    field public static final deprecated java.lang.String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
-    field public static final java.lang.String INTENT_ACTION_TTS_SERVICE = "android.intent.action.TTS_SERVICE";
-    field public static final deprecated java.lang.String KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedTts";
-    field public static final java.lang.String KEY_FEATURE_NETWORK_RETRIES_COUNT = "networkRetriesCount";
-    field public static final deprecated java.lang.String KEY_FEATURE_NETWORK_SYNTHESIS = "networkTts";
-    field public static final java.lang.String KEY_FEATURE_NETWORK_TIMEOUT_MS = "networkTimeoutMs";
-    field public static final java.lang.String KEY_FEATURE_NOT_INSTALLED = "notInstalled";
-    field public static final java.lang.String KEY_PARAM_PAN = "pan";
-    field public static final java.lang.String KEY_PARAM_SESSION_ID = "sessionId";
-    field public static final java.lang.String KEY_PARAM_STREAM = "streamType";
-    field public static final java.lang.String KEY_PARAM_UTTERANCE_ID = "utteranceId";
-    field public static final java.lang.String KEY_PARAM_VOLUME = "volume";
-    field public static final java.lang.String SERVICE_META_DATA = "android.speech.tts";
+    field public static final String EXTRA_AVAILABLE_VOICES = "availableVoices";
+    field @Deprecated public static final String EXTRA_CHECK_VOICE_DATA_FOR = "checkVoiceDataFor";
+    field public static final String EXTRA_SAMPLE_TEXT = "sampleText";
+    field @Deprecated public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
+    field public static final String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices";
+    field @Deprecated public static final String EXTRA_VOICE_DATA_FILES = "dataFiles";
+    field @Deprecated public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
+    field @Deprecated public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
+    field public static final String INTENT_ACTION_TTS_SERVICE = "android.intent.action.TTS_SERVICE";
+    field @Deprecated public static final String KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedTts";
+    field public static final String KEY_FEATURE_NETWORK_RETRIES_COUNT = "networkRetriesCount";
+    field @Deprecated public static final String KEY_FEATURE_NETWORK_SYNTHESIS = "networkTts";
+    field public static final String KEY_FEATURE_NETWORK_TIMEOUT_MS = "networkTimeoutMs";
+    field public static final String KEY_FEATURE_NOT_INSTALLED = "notInstalled";
+    field public static final String KEY_PARAM_PAN = "pan";
+    field public static final String KEY_PARAM_SESSION_ID = "sessionId";
+    field public static final String KEY_PARAM_STREAM = "streamType";
+    field public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId";
+    field public static final String KEY_PARAM_VOLUME = "volume";
+    field public static final String SERVICE_META_DATA = "android.speech.tts";
   }
 
   public static class TextToSpeech.EngineInfo {
     ctor public TextToSpeech.EngineInfo();
     field public int icon;
-    field public java.lang.String label;
-    field public java.lang.String name;
+    field public String label;
+    field public String name;
   }
 
-  public static abstract interface TextToSpeech.OnInitListener {
-    method public abstract void onInit(int);
+  public static interface TextToSpeech.OnInitListener {
+    method public void onInit(int);
   }
 
-  public static abstract deprecated interface TextToSpeech.OnUtteranceCompletedListener {
-    method public abstract void onUtteranceCompleted(java.lang.String);
+  @Deprecated public static interface TextToSpeech.OnUtteranceCompletedListener {
+    method @Deprecated public void onUtteranceCompleted(String);
   }
 
   public abstract class TextToSpeechService extends android.app.Service {
     ctor public TextToSpeechService();
     method public android.os.IBinder onBind(android.content.Intent);
-    method public java.lang.String onGetDefaultVoiceNameFor(java.lang.String, java.lang.String, java.lang.String);
-    method protected java.util.Set<java.lang.String> onGetFeaturesForLanguage(java.lang.String, java.lang.String, java.lang.String);
-    method protected abstract java.lang.String[] onGetLanguage();
+    method public String onGetDefaultVoiceNameFor(String, String, String);
+    method protected java.util.Set<java.lang.String> onGetFeaturesForLanguage(String, String, String);
+    method protected abstract String[] onGetLanguage();
     method public java.util.List<android.speech.tts.Voice> onGetVoices();
-    method protected abstract int onIsLanguageAvailable(java.lang.String, java.lang.String, java.lang.String);
-    method public int onIsValidVoiceName(java.lang.String);
-    method protected abstract int onLoadLanguage(java.lang.String, java.lang.String, java.lang.String);
-    method public int onLoadVoice(java.lang.String);
+    method protected abstract int onIsLanguageAvailable(String, String, String);
+    method public int onIsValidVoiceName(String);
+    method protected abstract int onLoadLanguage(String, String, String);
+    method public int onLoadVoice(String);
     method protected abstract void onStop();
     method protected abstract void onSynthesizeText(android.speech.tts.SynthesisRequest, android.speech.tts.SynthesisCallback);
   }
 
   public abstract class UtteranceProgressListener {
     ctor public UtteranceProgressListener();
-    method public void onAudioAvailable(java.lang.String, byte[]);
-    method public void onBeginSynthesis(java.lang.String, int, int, int);
-    method public abstract void onDone(java.lang.String);
-    method public abstract deprecated void onError(java.lang.String);
-    method public void onError(java.lang.String, int);
-    method public void onRangeStart(java.lang.String, int, int, int);
-    method public abstract void onStart(java.lang.String);
-    method public void onStop(java.lang.String, boolean);
+    method public void onAudioAvailable(String, byte[]);
+    method public void onBeginSynthesis(String, int, int, int);
+    method public abstract void onDone(String);
+    method @Deprecated public abstract void onError(String);
+    method public void onError(String, int);
+    method public void onRangeStart(String, int, int, int);
+    method public abstract void onStart(String);
+    method public void onStop(String, boolean);
   }
 
   public class Voice implements android.os.Parcelable {
-    ctor public Voice(java.lang.String, java.util.Locale, int, int, boolean, java.util.Set<java.lang.String>);
+    ctor public Voice(String, java.util.Locale, int, int, boolean, java.util.Set<java.lang.String>);
     method public int describeContents();
     method public java.util.Set<java.lang.String> getFeatures();
     method public int getLatency();
     method public java.util.Locale getLocale();
-    method public java.lang.String getName();
+    method public String getName();
     method public int getQuality();
     method public boolean isNetworkConnectionRequired();
     method public void writeToParcel(android.os.Parcel, int);
@@ -41858,8 +42199,8 @@
 package android.system {
 
   public final class ErrnoException extends java.lang.Exception {
-    ctor public ErrnoException(java.lang.String, int);
-    ctor public ErrnoException(java.lang.String, int, java.lang.Throwable);
+    ctor public ErrnoException(String, int);
+    ctor public ErrnoException(String, int, Throwable);
     field public final int errno;
   }
 
@@ -41870,17 +42211,17 @@
 
   public final class Os {
     method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
-    method public static boolean access(java.lang.String, int) throws android.system.ErrnoException;
+    method public static boolean access(String, int) throws android.system.ErrnoException;
     method public static void bind(java.io.FileDescriptor, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
-    method public static void chmod(java.lang.String, int) throws android.system.ErrnoException;
-    method public static void chown(java.lang.String, int, int) throws android.system.ErrnoException;
+    method public static void chmod(String, int) throws android.system.ErrnoException;
+    method public static void chown(String, int, int) throws android.system.ErrnoException;
     method public static void close(java.io.FileDescriptor) throws android.system.ErrnoException;
     method public static void connect(java.io.FileDescriptor, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
     method public static java.io.FileDescriptor dup(java.io.FileDescriptor) throws android.system.ErrnoException;
     method public static java.io.FileDescriptor dup2(java.io.FileDescriptor, int) throws android.system.ErrnoException;
-    method public static java.lang.String[] environ();
-    method public static void execv(java.lang.String, java.lang.String[]) throws android.system.ErrnoException;
-    method public static void execve(java.lang.String, java.lang.String[], java.lang.String[]) throws android.system.ErrnoException;
+    method public static String[] environ();
+    method public static void execv(String, String[]) throws android.system.ErrnoException;
+    method public static void execve(String, String[], String[]) throws android.system.ErrnoException;
     method public static void fchmod(java.io.FileDescriptor, int) throws android.system.ErrnoException;
     method public static void fchown(java.io.FileDescriptor, int, int) throws android.system.ErrnoException;
     method public static void fdatasync(java.io.FileDescriptor) throws android.system.ErrnoException;
@@ -41888,9 +42229,9 @@
     method public static android.system.StructStatVfs fstatvfs(java.io.FileDescriptor) throws android.system.ErrnoException;
     method public static void fsync(java.io.FileDescriptor) throws android.system.ErrnoException;
     method public static void ftruncate(java.io.FileDescriptor, long) throws android.system.ErrnoException;
-    method public static java.lang.String gai_strerror(int);
+    method public static String gai_strerror(int);
     method public static int getegid();
-    method public static java.lang.String getenv(java.lang.String);
+    method public static String getenv(String);
     method public static int geteuid();
     method public static int getgid();
     method public static java.net.SocketAddress getpeername(java.io.FileDescriptor) throws android.system.ErrnoException;
@@ -41899,27 +42240,27 @@
     method public static java.net.SocketAddress getsockname(java.io.FileDescriptor) throws android.system.ErrnoException;
     method public static int gettid();
     method public static int getuid();
-    method public static byte[] getxattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
-    method public static java.lang.String if_indextoname(int);
-    method public static int if_nametoindex(java.lang.String);
-    method public static java.net.InetAddress inet_pton(int, java.lang.String);
+    method public static byte[] getxattr(String, String) throws android.system.ErrnoException;
+    method public static String if_indextoname(int);
+    method public static int if_nametoindex(String);
+    method public static java.net.InetAddress inet_pton(int, String);
     method public static boolean isatty(java.io.FileDescriptor);
     method public static void kill(int, int) throws android.system.ErrnoException;
-    method public static void lchown(java.lang.String, int, int) throws android.system.ErrnoException;
-    method public static void link(java.lang.String, java.lang.String) throws android.system.ErrnoException;
+    method public static void lchown(String, int, int) throws android.system.ErrnoException;
+    method public static void link(String, String) throws android.system.ErrnoException;
     method public static void listen(java.io.FileDescriptor, int) throws android.system.ErrnoException;
-    method public static java.lang.String[] listxattr(java.lang.String) throws android.system.ErrnoException;
+    method public static String[] listxattr(String) throws android.system.ErrnoException;
     method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException;
-    method public static android.system.StructStat lstat(java.lang.String) throws android.system.ErrnoException;
+    method public static android.system.StructStat lstat(String) throws android.system.ErrnoException;
     method public static void mincore(long, long, byte[]) throws android.system.ErrnoException;
-    method public static void mkdir(java.lang.String, int) throws android.system.ErrnoException;
-    method public static void mkfifo(java.lang.String, int) throws android.system.ErrnoException;
+    method public static void mkdir(String, int) throws android.system.ErrnoException;
+    method public static void mkfifo(String, int) throws android.system.ErrnoException;
     method public static void mlock(long, long) throws android.system.ErrnoException;
     method public static long mmap(long, long, int, int, java.io.FileDescriptor, long) throws android.system.ErrnoException;
     method public static void msync(long, long, int) throws android.system.ErrnoException;
     method public static void munlock(long, long) throws android.system.ErrnoException;
     method public static void munmap(long, long) throws android.system.ErrnoException;
-    method public static java.io.FileDescriptor open(java.lang.String, int, int) throws android.system.ErrnoException;
+    method public static java.io.FileDescriptor open(String, int, int) throws android.system.ErrnoException;
     method public static java.io.FileDescriptor[] pipe() throws android.system.ErrnoException;
     method public static int poll(android.system.StructPollfd[], int) throws android.system.ErrnoException;
     method public static void posix_fallocate(java.io.FileDescriptor, long, long) throws android.system.ErrnoException;
@@ -41930,41 +42271,41 @@
     method public static int pwrite(java.io.FileDescriptor, byte[], int, int, long) throws android.system.ErrnoException, java.io.InterruptedIOException;
     method public static int read(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
     method public static int read(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
-    method public static java.lang.String readlink(java.lang.String) throws android.system.ErrnoException;
-    method public static int readv(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static String readlink(String) throws android.system.ErrnoException;
+    method public static int readv(java.io.FileDescriptor, Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
     method public static int recvfrom(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static int recvfrom(java.io.FileDescriptor, byte[], int, int, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
-    method public static void remove(java.lang.String) throws android.system.ErrnoException;
-    method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
-    method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
+    method public static void remove(String) throws android.system.ErrnoException;
+    method public static void removexattr(String, String) throws android.system.ErrnoException;
+    method public static void rename(String, String) throws android.system.ErrnoException;
     method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
     method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
     method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
-    method public static deprecated void setegid(int) throws android.system.ErrnoException;
-    method public static void setenv(java.lang.String, java.lang.String, boolean) throws android.system.ErrnoException;
-    method public static deprecated void seteuid(int) throws android.system.ErrnoException;
-    method public static deprecated void setgid(int) throws android.system.ErrnoException;
+    method @Deprecated public static void setegid(int) throws android.system.ErrnoException;
+    method public static void setenv(String, String, boolean) throws android.system.ErrnoException;
+    method @Deprecated public static void seteuid(int) throws android.system.ErrnoException;
+    method @Deprecated public static void setgid(int) throws android.system.ErrnoException;
     method public static int setsid() throws android.system.ErrnoException;
     method public static void setsockoptInt(java.io.FileDescriptor, int, int, int) throws android.system.ErrnoException;
-    method public static deprecated void setuid(int) throws android.system.ErrnoException;
-    method public static void setxattr(java.lang.String, java.lang.String, byte[], int) throws android.system.ErrnoException;
+    method @Deprecated public static void setuid(int) throws android.system.ErrnoException;
+    method public static void setxattr(String, String, byte[], int) throws android.system.ErrnoException;
     method public static void shutdown(java.io.FileDescriptor, int) throws android.system.ErrnoException;
     method public static java.io.FileDescriptor socket(int, int, int) throws android.system.ErrnoException;
     method public static void socketpair(int, int, int, java.io.FileDescriptor, java.io.FileDescriptor) throws android.system.ErrnoException;
-    method public static android.system.StructStat stat(java.lang.String) throws android.system.ErrnoException;
-    method public static android.system.StructStatVfs statvfs(java.lang.String) throws android.system.ErrnoException;
-    method public static java.lang.String strerror(int);
-    method public static java.lang.String strsignal(int);
-    method public static void symlink(java.lang.String, java.lang.String) throws android.system.ErrnoException;
+    method public static android.system.StructStat stat(String) throws android.system.ErrnoException;
+    method public static android.system.StructStatVfs statvfs(String) throws android.system.ErrnoException;
+    method public static String strerror(int);
+    method public static String strsignal(int);
+    method public static void symlink(String, String) throws android.system.ErrnoException;
     method public static long sysconf(int);
     method public static void tcdrain(java.io.FileDescriptor) throws android.system.ErrnoException;
     method public static void tcsendbreak(java.io.FileDescriptor, int) throws android.system.ErrnoException;
     method public static int umask(int);
     method public static android.system.StructUtsname uname();
-    method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
+    method public static void unsetenv(String) throws android.system.ErrnoException;
     method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
     method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
-    method public static int writev(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int writev(java.io.FileDescriptor, Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
   }
 
   public final class OsConstants {
@@ -41982,10 +42323,12 @@
     method public static boolean WIFSTOPPED(int);
     method public static int WSTOPSIG(int);
     method public static int WTERMSIG(int);
-    method public static java.lang.String errnoName(int);
-    method public static java.lang.String gaiName(int);
+    method public static String errnoName(int);
+    method public static String gaiName(int);
     field public static final int AF_INET;
     field public static final int AF_INET6;
+    field public static final int AF_NETLINK;
+    field public static final int AF_PACKET;
     field public static final int AF_UNIX;
     field public static final int AF_UNSPEC;
     field public static final int AI_ADDRCONFIG;
@@ -41995,6 +42338,7 @@
     field public static final int AI_NUMERICSERV;
     field public static final int AI_PASSIVE;
     field public static final int AI_V4MAPPED;
+    field public static final int ARPHRD_ETHER;
     field public static final int CAP_AUDIT_CONTROL;
     field public static final int CAP_AUDIT_WRITE;
     field public static final int CAP_BLOCK_SUSPEND;
@@ -42118,6 +42462,10 @@
     field public static final int ESPIPE;
     field public static final int ESRCH;
     field public static final int ESTALE;
+    field public static final int ETH_P_ALL;
+    field public static final int ETH_P_ARP;
+    field public static final int ETH_P_IP;
+    field public static final int ETH_P_IPV6;
     field public static final int ETIME;
     field public static final int ETIMEDOUT;
     field public static final int ETXTBSY;
@@ -42215,6 +42563,8 @@
     field public static final int MS_ASYNC;
     field public static final int MS_INVALIDATE;
     field public static final int MS_SYNC;
+    field public static final int NETLINK_INET_DIAG;
+    field public static final int NETLINK_ROUTE;
     field public static final int NI_DGRAM;
     field public static final int NI_NAMEREQD;
     field public static final int NI_NOFQDN;
@@ -42251,6 +42601,7 @@
     field public static final int PR_GET_DUMPABLE;
     field public static final int PR_SET_DUMPABLE;
     field public static final int PR_SET_NO_NEW_PRIVS;
+    field public static final int RTMGRP_NEIGH;
     field public static final int RT_SCOPE_HOST;
     field public static final int RT_SCOPE_LINK;
     field public static final int RT_SCOPE_NOWHERE;
@@ -42467,7 +42818,7 @@
     field public short events;
     field public java.io.FileDescriptor fd;
     field public short revents;
-    field public java.lang.Object userData;
+    field public Object userData;
   }
 
   public final class StructStat {
@@ -42506,7 +42857,7 @@
     field public final long f_namemax;
   }
 
-  public final class StructTimespec implements java.lang.Comparable {
+  public final class StructTimespec implements java.lang.Comparable<android.system.StructTimespec> {
     ctor public StructTimespec(long, long);
     method public int compareTo(android.system.StructTimespec);
     field public final long tv_nsec;
@@ -42514,12 +42865,12 @@
   }
 
   public final class StructUtsname {
-    ctor public StructUtsname(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    field public final java.lang.String machine;
-    field public final java.lang.String nodename;
-    field public final java.lang.String release;
-    field public final java.lang.String sysname;
-    field public final java.lang.String version;
+    ctor public StructUtsname(String, String, String, String, String);
+    field public final String machine;
+    field public final String nodename;
+    field public final String release;
+    field public final String sysname;
+    field public final String version;
   }
 
 }
@@ -42536,8 +42887,8 @@
     method public java.util.List<android.telecom.Call> getConferenceableCalls();
     method public android.telecom.Call.Details getDetails();
     method public android.telecom.Call getParent();
-    method public java.lang.String getRemainingPostDialSequence();
-    method public android.telecom.Call.RttCall getRttCall();
+    method public String getRemainingPostDialSequence();
+    method @Nullable public android.telecom.Call.RttCall getRttCall();
     method public int getState();
     method public android.telecom.InCallService.VideoCall getVideoCall();
     method public void handoverTo(android.telecom.PhoneAccountHandle, int, android.os.Bundle);
@@ -42551,11 +42902,11 @@
     method public void putExtras(android.os.Bundle);
     method public void registerCallback(android.telecom.Call.Callback);
     method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
-    method public void reject(boolean, java.lang.String);
+    method public void reject(boolean, String);
     method public void removeExtras(java.util.List<java.lang.String>);
     method public void removeExtras(java.lang.String...);
     method public void respondToRttRequest(int, boolean);
-    method public void sendCallEvent(java.lang.String, android.os.Bundle);
+    method public void sendCallEvent(String, android.os.Bundle);
     method public void sendRttRequest();
     method public void splitFromConference();
     method public void stopDtmfTone();
@@ -42563,9 +42914,9 @@
     method public void swapConference();
     method public void unhold();
     method public void unregisterCallback(android.telecom.Call.Callback);
-    field public static final deprecated java.lang.String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
-    field public static final java.lang.String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
-    field public static final java.lang.String EXTRA_SUGGESTED_PHONE_ACCOUNTS = "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS";
+    field @Deprecated public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
+    field public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
+    field public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS = "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS";
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_CONNECTING = 9; // 0x9
     field public static final int STATE_DIALING = 1; // 0x1
@@ -42578,18 +42929,18 @@
     field public static final int STATE_SELECT_PHONE_ACCOUNT = 8; // 0x8
   }
 
-  public static abstract class Call.Callback {
+  public abstract static class Call.Callback {
     ctor public Call.Callback();
     method public void onCallDestroyed(android.telecom.Call);
     method public void onCannedTextResponsesLoaded(android.telecom.Call, java.util.List<java.lang.String>);
     method public void onChildrenChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
     method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
-    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
+    method public void onConnectionEvent(android.telecom.Call, String, android.os.Bundle);
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
     method public void onHandoverComplete(android.telecom.Call);
     method public void onHandoverFailed(android.telecom.Call, int);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
-    method public void onPostDialWait(android.telecom.Call, java.lang.String);
+    method public void onPostDialWait(android.telecom.Call, String);
     method public void onRttInitiationFailure(android.telecom.Call, int);
     method public void onRttModeChanged(android.telecom.Call, int);
     method public void onRttRequest(android.telecom.Call, int);
@@ -42606,12 +42957,13 @@
   public static class Call.Details {
     method public static boolean can(int, int);
     method public boolean can(int);
-    method public static java.lang.String capabilitiesToString(int);
+    method public static String capabilitiesToString(int);
     method public android.telecom.PhoneAccountHandle getAccountHandle();
     method public int getCallCapabilities();
-    method public android.telecom.CallIdentification getCallIdentification();
+    method public int getCallDirection();
+    method @Nullable public android.telecom.CallIdentification getCallIdentification();
     method public int getCallProperties();
-    method public java.lang.String getCallerDisplayName();
+    method public String getCallerDisplayName();
     method public int getCallerDisplayNamePresentation();
     method public final long getConnectTimeMillis();
     method public long getCreationTimeMillis();
@@ -42625,7 +42977,7 @@
     method public int getVideoState();
     method public static boolean hasProperty(int, int);
     method public boolean hasProperty(int);
-    method public static java.lang.String propertiesToString(int);
+    method public static String propertiesToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
     field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
@@ -42645,6 +42997,9 @@
     field public static final int CAPABILITY_SUPPORT_DEFLECT = 16777216; // 0x1000000
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final int DIRECTION_INCOMING = 0; // 0x0
+    field public static final int DIRECTION_OUTGOING = 1; // 0x1
+    field public static final int DIRECTION_UNKNOWN = -1; // 0xffffffff
     field public static final int PROPERTY_CONFERENCE = 1; // 0x1
     field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
     field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
@@ -42661,10 +43016,10 @@
 
   public static final class Call.RttCall {
     method public int getRttAudioMode();
-    method public java.lang.String read();
-    method public java.lang.String readImmediately() throws java.io.IOException;
+    method public String read();
+    method public String readImmediately() throws java.io.IOException;
     method public void setRttMode(int);
-    method public void write(java.lang.String) throws java.io.IOException;
+    method public void write(String) throws java.io.IOException;
     field public static final int RTT_MODE_FULL = 1; // 0x1
     field public static final int RTT_MODE_HCO = 2; // 0x2
     field public static final int RTT_MODE_VCO = 3; // 0x3
@@ -42672,7 +43027,7 @@
 
   public final class CallAudioState implements android.os.Parcelable {
     ctor public CallAudioState(boolean, int, int);
-    method public static java.lang.String audioRouteToString(int);
+    method public static String audioRouteToString(int);
     method public int describeContents();
     method public android.bluetooth.BluetoothDevice getActiveBluetoothDevice();
     method public int getRoute();
@@ -42690,13 +43045,13 @@
 
   public final class CallIdentification implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getCallScreeningAppName();
-    method public java.lang.String getCallScreeningPackageName();
-    method public java.lang.String getDescription();
-    method public java.lang.String getDetails();
-    method public java.lang.String getName();
+    method @NonNull public String getCallScreeningAppName();
+    method @NonNull public String getCallScreeningPackageName();
+    method @Nullable public String getDescription();
+    method @Nullable public String getDetails();
+    method @Nullable public String getName();
     method public int getNuisanceConfidence();
-    method public android.graphics.drawable.Icon getPhoto();
+    method @Nullable public android.graphics.drawable.Icon getPhoto();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONFIDENCE_LIKELY_NOT_NUISANCE = -1; // 0xffffffff
     field public static final int CONFIDENCE_LIKELY_NUISANCE = 1; // 0x1
@@ -42709,31 +43064,40 @@
   public static class CallIdentification.Builder {
     ctor public CallIdentification.Builder();
     method public android.telecom.CallIdentification build();
-    method public android.telecom.CallIdentification.Builder setDescription(java.lang.String);
-    method public android.telecom.CallIdentification.Builder setDetails(java.lang.String);
-    method public android.telecom.CallIdentification.Builder setName(java.lang.String);
+    method public android.telecom.CallIdentification.Builder setDescription(@Nullable String);
+    method public android.telecom.CallIdentification.Builder setDetails(@Nullable String);
+    method public android.telecom.CallIdentification.Builder setName(@Nullable String);
     method public android.telecom.CallIdentification.Builder setNuisanceConfidence(int);
-    method public android.telecom.CallIdentification.Builder setPhoto(android.graphics.drawable.Icon);
+    method public android.telecom.CallIdentification.Builder setPhoto(@Nullable android.graphics.drawable.Icon);
   }
 
   public abstract class CallRedirectionService extends android.app.Service {
     ctor public CallRedirectionService();
     method public final void cancelCall();
     method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+    method public abstract void onPlaceCall(@NonNull android.net.Uri, @NonNull android.telecom.PhoneAccountHandle, boolean);
     method public final boolean onUnbind(android.content.Intent);
     method public final void placeCallUnmodified();
-    method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallRedirectionService";
+    method public final void redirectCall(@NonNull android.net.Uri, @NonNull android.telecom.PhoneAccountHandle, boolean);
+    field public static final String SERVICE_INTERFACE = "android.telecom.CallRedirectionService";
   }
 
   public abstract class CallScreeningService extends android.app.Service {
     ctor public CallScreeningService();
     method public android.os.IBinder onBind(android.content.Intent);
-    method public abstract void onScreenCall(android.telecom.Call.Details);
-    method public final void provideCallIdentification(android.telecom.Call.Details, android.telecom.CallIdentification);
-    method public final void respondToCall(android.telecom.Call.Details, android.telecom.CallScreeningService.CallResponse);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
+    method public abstract void onScreenCall(@NonNull android.telecom.Call.Details);
+    method public final void provideCallIdentification(@NonNull android.telecom.Call.Details, @NonNull android.telecom.CallIdentification);
+    method public final void respondToCall(@NonNull android.telecom.Call.Details, @NonNull android.telecom.CallScreeningService.CallResponse);
+    field public static final String ACTION_NUISANCE_CALL_STATUS_CHANGED = "android.telecom.action.NUISANCE_CALL_STATUS_CHANGED";
+    field public static final int CALL_DURATION_LONG = 4; // 0x4
+    field public static final int CALL_DURATION_MEDIUM = 3; // 0x3
+    field public static final int CALL_DURATION_SHORT = 2; // 0x2
+    field public static final int CALL_DURATION_VERY_SHORT = 1; // 0x1
+    field public static final String EXTRA_CALL_DURATION = "android.telecom.extra.CALL_DURATION";
+    field public static final String EXTRA_CALL_HANDLE = "android.telecom.extra.CALL_HANDLE";
+    field public static final String EXTRA_CALL_TYPE = "android.telecom.extra.CALL_TYPE";
+    field public static final String EXTRA_IS_NUISANCE = "android.telecom.extra.IS_NUISANCE";
+    field public static final String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
   }
 
   public static class CallScreeningService.CallResponse {
@@ -42781,7 +43145,7 @@
     method public void onStopDtmfTone();
     method public void onSwap();
     method public void onUnhold();
-    method public final void putExtras(android.os.Bundle);
+    method public final void putExtras(@NonNull android.os.Bundle);
     method public final void removeConnection(android.telecom.Connection);
     method public final void removeExtras(java.util.List<java.lang.String>);
     method public final void removeExtras(java.lang.String...);
@@ -42793,7 +43157,7 @@
     method public final void setConnectionTime(long);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final void setExtras(@Nullable android.os.Bundle);
     method public final void setOnHold();
     method public final void setStatusHints(android.telecom.StatusHints);
     method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
@@ -42806,7 +43170,7 @@
 
   public abstract class Connection extends android.telecom.Conferenceable {
     ctor public Connection();
-    method public static java.lang.String capabilitiesToString(int);
+    method public static String capabilitiesToString(int);
     method public static android.telecom.Connection createCanceledConnection();
     method public static android.telecom.Connection createFailedConnection(android.telecom.DisconnectCause);
     method public final void destroy();
@@ -42814,7 +43178,7 @@
     method public final int getAddressPresentation();
     method public final boolean getAudioModeIsVoip();
     method public final android.telecom.CallAudioState getCallAudioState();
-    method public final java.lang.String getCallerDisplayName();
+    method public final String getCallerDisplayName();
     method public final int getCallerDisplayNamePresentation();
     method public final android.telecom.Conference getConference();
     method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
@@ -42825,13 +43189,13 @@
     method public final int getState();
     method public final android.telecom.StatusHints getStatusHints();
     method public final android.telecom.Connection.VideoProvider getVideoProvider();
-    method public void handleRttUpgradeResponse(android.telecom.Connection.RttTextStream);
+    method public void handleRttUpgradeResponse(@Nullable android.telecom.Connection.RttTextStream);
     method public final boolean isRingbackRequested();
     method public void onAbort();
     method public void onAnswer(int);
     method public void onAnswer();
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
-    method public void onCallEvent(java.lang.String, android.os.Bundle);
+    method public void onCallEvent(String, android.os.Bundle);
     method public void onDeflect(android.net.Uri);
     method public void onDisconnect();
     method public void onExtrasChanged(android.os.Bundle);
@@ -42841,21 +43205,21 @@
     method public void onPostDialContinue(boolean);
     method public void onPullExternalCall();
     method public void onReject();
-    method public void onReject(java.lang.String);
+    method public void onReject(String);
     method public void onSeparate();
     method public void onShowIncomingCallUi();
     method public void onSilence();
-    method public void onStartRtt(android.telecom.Connection.RttTextStream);
+    method public void onStartRtt(@NonNull android.telecom.Connection.RttTextStream);
     method public void onStateChanged(int);
     method public void onStopDtmfTone();
     method public void onStopRtt();
     method public void onUnhold();
-    method public static java.lang.String propertiesToString(int);
-    method public final void putExtras(android.os.Bundle);
+    method public static String propertiesToString(int);
+    method public final void putExtras(@NonNull android.os.Bundle);
     method public final void removeExtras(java.util.List<java.lang.String>);
     method public final void removeExtras(java.lang.String...);
-    method public void requestBluetoothAudio(android.bluetooth.BluetoothDevice);
-    method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
+    method public void requestBluetoothAudio(@NonNull android.bluetooth.BluetoothDevice);
+    method public void sendConnectionEvent(String, android.os.Bundle);
     method public final void sendRemoteRttRequest();
     method public final void sendRttInitiationFailure(int);
     method public final void sendRttInitiationSuccess();
@@ -42864,31 +43228,31 @@
     method public final void setAddress(android.net.Uri, int);
     method public final void setAudioModeIsVoip(boolean);
     method public final void setAudioRoute(int);
-    method public final void setCallerDisplayName(java.lang.String, int);
+    method public final void setCallerDisplayName(String, int);
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
     method public final void setConnectionCapabilities(int);
     method public final void setConnectionProperties(int);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final void setExtras(@Nullable android.os.Bundle);
     method public final void setInitialized();
     method public final void setInitializing();
     method public final void setNextPostDialChar(char);
     method public final void setOnHold();
-    method public final void setPostDialWait(java.lang.String);
+    method public final void setPostDialWait(String);
     method public final void setPulling();
     method public final void setRingbackRequested(boolean);
     method public final void setRinging();
     method public final void setStatusHints(android.telecom.StatusHints);
     method public final void setVideoProvider(android.telecom.Connection.VideoProvider);
     method public final void setVideoState(int);
-    method public static java.lang.String stateToString(int);
+    method public static String stateToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
     field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
     field public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 4194304; // 0x400000
-    field public static final deprecated int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
+    field @Deprecated public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
     field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
@@ -42905,14 +43269,16 @@
     field public static final int CAPABILITY_SUPPORT_DEFLECT = 33554432; // 0x2000000
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
-    field public static final java.lang.String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
-    field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
-    field public static final java.lang.String EXTRA_ANSWERING_DROPS_FG_CALL = "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
-    field public static final java.lang.String EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME = "android.telecom.extra.ANSWERING_DROPS_FG_CALL_APP_NAME";
-    field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
-    field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
-    field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
-    field public static final java.lang.String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE";
+    field public static final String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
+    field public static final String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
+    field public static final String EVENT_RTT_AUDIO_INDICATION_CHANGED = "android.telecom.event.RTT_AUDIO_INDICATION_CHANGED";
+    field public static final String EXTRA_ANSWERING_DROPS_FG_CALL = "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
+    field public static final String EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME = "android.telecom.extra.ANSWERING_DROPS_FG_CALL_APP_NAME";
+    field public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
+    field public static final String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
+    field public static final String EXTRA_IS_RTT_AUDIO_PRESENT = "android.telecom.extra.IS_RTT_AUDIO_PRESENT";
+    field public static final String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+    field public static final String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE";
     field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
     field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
     field public static final int PROPERTY_IS_RTT = 256; // 0x100
@@ -42936,12 +43302,12 @@
   }
 
   public static final class Connection.RttTextStream {
-    method public java.lang.String read() throws java.io.IOException;
-    method public java.lang.String readImmediately() throws java.io.IOException;
-    method public void write(java.lang.String) throws java.io.IOException;
+    method public String read() throws java.io.IOException;
+    method public String readImmediately() throws java.io.IOException;
+    method public void write(String) throws java.io.IOException;
   }
 
-  public static abstract class Connection.VideoProvider {
+  public abstract static class Connection.VideoProvider {
     ctor public Connection.VideoProvider();
     method public void changeCameraCapabilities(android.telecom.VideoProfile.CameraCapabilities);
     method public void changePeerDimensions(int, int);
@@ -42951,7 +43317,7 @@
     method public abstract void onRequestConnectionDataUsage();
     method public abstract void onSendSessionModifyRequest(android.telecom.VideoProfile, android.telecom.VideoProfile);
     method public abstract void onSendSessionModifyResponse(android.telecom.VideoProfile);
-    method public abstract void onSetCamera(java.lang.String);
+    method public abstract void onSetCamera(String);
     method public abstract void onSetDeviceOrientation(int);
     method public abstract void onSetDisplaySurface(android.view.Surface);
     method public abstract void onSetPauseImage(android.net.Uri);
@@ -43011,19 +43377,19 @@
     method public void onHandoverFailed(android.telecom.ConnectionRequest, int);
     method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
     method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
+    field public static final String SERVICE_INTERFACE = "android.telecom.ConnectionService";
   }
 
   public final class DisconnectCause implements android.os.Parcelable {
     ctor public DisconnectCause(int);
-    ctor public DisconnectCause(int, java.lang.String);
-    ctor public DisconnectCause(int, java.lang.CharSequence, java.lang.CharSequence, java.lang.String);
-    ctor public DisconnectCause(int, java.lang.CharSequence, java.lang.CharSequence, java.lang.String, int);
+    ctor public DisconnectCause(int, String);
+    ctor public DisconnectCause(int, CharSequence, CharSequence, String);
+    ctor public DisconnectCause(int, CharSequence, CharSequence, String, int);
     method public int describeContents();
     method public int getCode();
-    method public java.lang.CharSequence getDescription();
-    method public java.lang.CharSequence getLabel();
-    method public java.lang.String getReason();
+    method public CharSequence getDescription();
+    method public CharSequence getLabel();
+    method public String getReason();
     method public int getTone();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ANSWERED_ELSEWHERE = 11; // 0xb
@@ -43043,10 +43409,10 @@
   }
 
   public class GatewayInfo implements android.os.Parcelable {
-    ctor public GatewayInfo(java.lang.String, android.net.Uri, android.net.Uri);
+    ctor public GatewayInfo(String, android.net.Uri, android.net.Uri);
     method public int describeContents();
     method public android.net.Uri getGatewayAddress();
-    method public java.lang.String getGatewayProviderPackageName();
+    method public String getGatewayProviderPackageName();
     method public android.net.Uri getOriginalAddress();
     method public boolean isEmpty();
     method public void writeToParcel(android.os.Parcel, int);
@@ -43064,15 +43430,15 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onCallRemoved(android.telecom.Call);
     method public void onCanAddCallChanged(boolean);
-    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
+    method public void onConnectionEvent(android.telecom.Call, String, android.os.Bundle);
     method public void onSilenceRinger();
-    method public final void requestBluetoothAudio(android.bluetooth.BluetoothDevice);
+    method public final void requestBluetoothAudio(@NonNull android.bluetooth.BluetoothDevice);
     method public final void setAudioRoute(int);
     method public final void setMuted(boolean);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
+    field public static final String SERVICE_INTERFACE = "android.telecom.InCallService";
   }
 
-  public static abstract class InCallService.VideoCall {
+  public abstract static class InCallService.VideoCall {
     ctor public InCallService.VideoCall();
     method public abstract void registerCallback(android.telecom.InCallService.VideoCall.Callback);
     method public abstract void registerCallback(android.telecom.InCallService.VideoCall.Callback, android.os.Handler);
@@ -43080,7 +43446,7 @@
     method public abstract void requestCameraCapabilities();
     method public abstract void sendSessionModifyRequest(android.telecom.VideoProfile);
     method public abstract void sendSessionModifyResponse(android.telecom.VideoProfile);
-    method public abstract void setCamera(java.lang.String);
+    method public abstract void setCamera(String);
     method public abstract void setDeviceOrientation(int);
     method public abstract void setDisplaySurface(android.view.Surface);
     method public abstract void setPauseImage(android.net.Uri);
@@ -43089,7 +43455,7 @@
     method public abstract void unregisterCallback(android.telecom.InCallService.VideoCall.Callback);
   }
 
-  public static abstract class InCallService.VideoCall.Callback {
+  public abstract static class InCallService.VideoCall.Callback {
     ctor public InCallService.VideoCall.Callback();
     method public abstract void onCallDataUsageChanged(long);
     method public abstract void onCallSessionEvent(int);
@@ -43101,7 +43467,7 @@
   }
 
   public final class PhoneAccount implements android.os.Parcelable {
-    method public static android.telecom.PhoneAccount.Builder builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence);
+    method public static android.telecom.PhoneAccount.Builder builder(android.telecom.PhoneAccountHandle, CharSequence);
     method public int describeContents();
     method public android.telecom.PhoneAccountHandle getAccountHandle();
     method public android.net.Uri getAddress();
@@ -43109,13 +43475,13 @@
     method public android.os.Bundle getExtras();
     method public int getHighlightColor();
     method public android.graphics.drawable.Icon getIcon();
-    method public java.lang.CharSequence getLabel();
-    method public java.lang.CharSequence getShortDescription();
+    method public CharSequence getLabel();
+    method public CharSequence getShortDescription();
     method public android.net.Uri getSubscriptionAddress();
     method public java.util.List<java.lang.String> getSupportedUriSchemes();
     method public boolean hasCapabilities(int);
     method public boolean isEnabled();
-    method public boolean supportsUriScheme(java.lang.String);
+    method public boolean supportsUriScheme(String);
     method public android.telecom.PhoneAccount.Builder toBuilder();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CAPABILITY_CALL_PROVIDER = 2; // 0x2
@@ -43129,39 +43495,39 @@
     field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
     field public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 256; // 0x100
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
-    field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
-    field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
-    field public static final java.lang.String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
-    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
-    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
+    field public static final String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
+    field public static final String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+    field public static final String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
+    field public static final String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
+    field public static final String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
     field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
     field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
-    field public static final java.lang.String SCHEME_SIP = "sip";
-    field public static final java.lang.String SCHEME_TEL = "tel";
-    field public static final java.lang.String SCHEME_VOICEMAIL = "voicemail";
+    field public static final String SCHEME_SIP = "sip";
+    field public static final String SCHEME_TEL = "tel";
+    field public static final String SCHEME_VOICEMAIL = "voicemail";
   }
 
   public static class PhoneAccount.Builder {
-    ctor public PhoneAccount.Builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence);
+    ctor public PhoneAccount.Builder(android.telecom.PhoneAccountHandle, CharSequence);
     ctor public PhoneAccount.Builder(android.telecom.PhoneAccount);
-    method public android.telecom.PhoneAccount.Builder addSupportedUriScheme(java.lang.String);
+    method public android.telecom.PhoneAccount.Builder addSupportedUriScheme(String);
     method public android.telecom.PhoneAccount build();
     method public android.telecom.PhoneAccount.Builder setAddress(android.net.Uri);
     method public android.telecom.PhoneAccount.Builder setCapabilities(int);
     method public android.telecom.PhoneAccount.Builder setExtras(android.os.Bundle);
     method public android.telecom.PhoneAccount.Builder setHighlightColor(int);
     method public android.telecom.PhoneAccount.Builder setIcon(android.graphics.drawable.Icon);
-    method public android.telecom.PhoneAccount.Builder setShortDescription(java.lang.CharSequence);
+    method public android.telecom.PhoneAccount.Builder setShortDescription(CharSequence);
     method public android.telecom.PhoneAccount.Builder setSubscriptionAddress(android.net.Uri);
     method public android.telecom.PhoneAccount.Builder setSupportedUriSchemes(java.util.List<java.lang.String>);
   }
 
   public final class PhoneAccountHandle implements android.os.Parcelable {
-    ctor public PhoneAccountHandle(android.content.ComponentName, java.lang.String);
-    ctor public PhoneAccountHandle(android.content.ComponentName, java.lang.String, android.os.UserHandle);
+    ctor public PhoneAccountHandle(@NonNull android.content.ComponentName, @NonNull String);
+    ctor public PhoneAccountHandle(@NonNull android.content.ComponentName, @NonNull String, @NonNull android.os.UserHandle);
     method public int describeContents();
     method public android.content.ComponentName getComponentName();
-    method public java.lang.String getId();
+    method public String getId();
     method public android.os.UserHandle getUserHandle();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccountHandle> CREATOR;
@@ -43203,7 +43569,7 @@
     method public void unregisterCallback(android.telecom.RemoteConference.Callback);
   }
 
-  public static abstract class RemoteConference.Callback {
+  public abstract static class RemoteConference.Callback {
     ctor public RemoteConference.Callback();
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
@@ -43212,7 +43578,7 @@
     method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
     method public void onDestroyed(android.telecom.RemoteConference);
     method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
-    method public void onExtrasChanged(android.telecom.RemoteConference, android.os.Bundle);
+    method public void onExtrasChanged(android.telecom.RemoteConference, @Nullable android.os.Bundle);
     method public void onStateChanged(android.telecom.RemoteConference, int, int);
   }
 
@@ -43222,7 +43588,7 @@
     method public void disconnect();
     method public android.net.Uri getAddress();
     method public int getAddressPresentation();
-    method public java.lang.CharSequence getCallerDisplayName();
+    method public CharSequence getCallerDisplayName();
     method public int getCallerDisplayNamePresentation();
     method public android.telecom.RemoteConference getConference();
     method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
@@ -43249,20 +43615,20 @@
     method public void unregisterCallback(android.telecom.RemoteConnection.Callback);
   }
 
-  public static abstract class RemoteConnection.Callback {
+  public abstract static class RemoteConnection.Callback {
     ctor public RemoteConnection.Callback();
     method public void onAddressChanged(android.telecom.RemoteConnection, android.net.Uri, int);
-    method public void onCallerDisplayNameChanged(android.telecom.RemoteConnection, java.lang.String, int);
+    method public void onCallerDisplayNameChanged(android.telecom.RemoteConnection, String, int);
     method public void onConferenceChanged(android.telecom.RemoteConnection, android.telecom.RemoteConference);
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
-    method public void onConnectionEvent(android.telecom.RemoteConnection, java.lang.String, android.os.Bundle);
+    method public void onConnectionEvent(android.telecom.RemoteConnection, String, android.os.Bundle);
     method public void onConnectionPropertiesChanged(android.telecom.RemoteConnection, int);
     method public void onDestroyed(android.telecom.RemoteConnection);
     method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
-    method public void onExtrasChanged(android.telecom.RemoteConnection, android.os.Bundle);
+    method public void onExtrasChanged(android.telecom.RemoteConnection, @Nullable android.os.Bundle);
     method public void onPostDialChar(android.telecom.RemoteConnection, char);
-    method public void onPostDialWait(android.telecom.RemoteConnection, java.lang.String);
+    method public void onPostDialWait(android.telecom.RemoteConnection, String);
     method public void onRingbackRequested(android.telecom.RemoteConnection, boolean);
     method public void onStateChanged(android.telecom.RemoteConnection, int);
     method public void onStatusHintsChanged(android.telecom.RemoteConnection, android.telecom.StatusHints);
@@ -43277,7 +43643,7 @@
     method public void requestCameraCapabilities();
     method public void sendSessionModifyRequest(android.telecom.VideoProfile, android.telecom.VideoProfile);
     method public void sendSessionModifyResponse(android.telecom.VideoProfile);
-    method public void setCamera(java.lang.String);
+    method public void setCamera(String);
     method public void setDeviceOrientation(int);
     method public void setDisplaySurface(android.view.Surface);
     method public void setPauseImage(android.net.Uri);
@@ -43286,7 +43652,7 @@
     method public void unregisterCallback(android.telecom.RemoteConnection.VideoProvider.Callback);
   }
 
-  public static abstract class RemoteConnection.VideoProvider.Callback {
+  public abstract static class RemoteConnection.VideoProvider.Callback {
     ctor public RemoteConnection.VideoProvider.Callback();
     method public void onCallDataUsageChanged(android.telecom.RemoteConnection.VideoProvider, long);
     method public void onCallSessionEvent(android.telecom.RemoteConnection.VideoProvider, int);
@@ -43298,86 +43664,88 @@
   }
 
   public final class StatusHints implements android.os.Parcelable {
-    ctor public StatusHints(java.lang.CharSequence, android.graphics.drawable.Icon, android.os.Bundle);
+    ctor public StatusHints(CharSequence, android.graphics.drawable.Icon, android.os.Bundle);
     method public int describeContents();
     method public android.os.Bundle getExtras();
     method public android.graphics.drawable.Icon getIcon();
-    method public java.lang.CharSequence getLabel();
+    method public CharSequence getLabel();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telecom.StatusHints> CREATOR;
   }
 
   public class TelecomManager {
     method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
-    method public void acceptRingingCall();
-    method public void acceptRingingCall(int);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall();
+    method @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(int);
     method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
-    method public void cancelMissedCallsNotification();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void cancelMissedCallsNotification();
     method public android.content.Intent createManageBlockedNumbersIntent();
-    method public boolean endCall();
-    method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
-    method public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
-    method public java.lang.String getDefaultDialerPackage();
-    method public android.telecom.PhoneAccountHandle getDefaultOutgoingPhoneAccount(java.lang.String);
-    method public java.lang.String getLine1Number(android.telecom.PhoneAccountHandle);
+    method @RequiresPermission(android.Manifest.permission.ANSWER_PHONE_CALLS) public boolean endCall();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
+    method public String getDefaultDialerPackage();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telecom.PhoneAccountHandle getDefaultOutgoingPhoneAccount(String);
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1Number(android.telecom.PhoneAccountHandle);
     method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
-    method public java.util.List<android.telecom.PhoneAccountHandle> getSelfManagedPhoneAccounts();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getSelfManagedPhoneAccounts();
     method public android.telecom.PhoneAccountHandle getSimCallManager();
-    method public java.lang.String getSystemDialerPackage();
-    method public java.lang.String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
-    method public boolean handleMmi(java.lang.String);
-    method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
-    method public boolean isInCall();
-    method public boolean isInManagedCall();
+    method public String getSystemDialerPackage();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telecom.PhoneAccountHandle getUserSelectedOutgoingPhoneAccount();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String, android.telecom.PhoneAccountHandle);
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isInCall();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isInManagedCall();
     method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle);
     method public boolean isOutgoingCallPermitted(android.telecom.PhoneAccountHandle);
-    method public boolean isTtySupported();
-    method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
-    method public void placeCall(android.net.Uri, android.os.Bundle);
+    method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public boolean isTtySupported();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, String);
+    method @RequiresPermission(anyOf={android.Manifest.permission.CALL_PHONE, android.Manifest.permission.MANAGE_OWN_CALLS}) public void placeCall(android.net.Uri, android.os.Bundle);
     method public void registerPhoneAccount(android.telecom.PhoneAccount);
-    method public void showInCallScreen(boolean);
-    method public void silenceRinger();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void reportNuisanceCallStatus(@NonNull android.net.Uri, boolean);
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void showInCallScreen(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger();
     method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
-    field public static final java.lang.String ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER";
-    field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
-    field public static final java.lang.String ACTION_CONFIGURE_PHONE_ACCOUNT = "android.telecom.action.CONFIGURE_PHONE_ACCOUNT";
-    field public static final java.lang.String ACTION_DEFAULT_CALL_SCREENING_APP_CHANGED = "android.telecom.action.DEFAULT_CALL_SCREENING_APP_CHANGED";
-    field public static final java.lang.String ACTION_DEFAULT_DIALER_CHANGED = "android.telecom.action.DEFAULT_DIALER_CHANGED";
-    field public static final deprecated java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
-    field public static final java.lang.String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED";
-    field public static final java.lang.String ACTION_PHONE_ACCOUNT_UNREGISTERED = "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED";
-    field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
-    field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
-    field public static final java.lang.String ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION";
-    field public static final java.lang.String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
+    field public static final String ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER";
+    field public static final String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
+    field public static final String ACTION_CONFIGURE_PHONE_ACCOUNT = "android.telecom.action.CONFIGURE_PHONE_ACCOUNT";
+    field public static final String ACTION_DEFAULT_CALL_SCREENING_APP_CHANGED = "android.telecom.action.DEFAULT_CALL_SCREENING_APP_CHANGED";
+    field public static final String ACTION_DEFAULT_DIALER_CHANGED = "android.telecom.action.DEFAULT_DIALER_CHANGED";
+    field @Deprecated public static final String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
+    field public static final String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED";
+    field public static final String ACTION_PHONE_ACCOUNT_UNREGISTERED = "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED";
+    field public static final String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
+    field public static final String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
+    field public static final String ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION";
+    field public static final String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
-    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_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME = "android.telecom.extra.DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME";
-    field public static final java.lang.String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS";
-    field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS";
-    field public static final java.lang.String EXTRA_INCOMING_VIDEO_STATE = "android.telecom.extra.INCOMING_VIDEO_STATE";
-    field public static final java.lang.String EXTRA_IS_DEFAULT_CALL_SCREENING_APP = "android.telecom.extra.IS_DEFAULT_CALL_SCREENING_APP";
-    field public static final java.lang.String EXTRA_IS_ENABLED = "android.telecom.extra.IS_ENABLED";
-    field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT";
-    field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
-    field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
-    field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
-    field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
-    field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
-    field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
-    field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
-    field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
-    field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
-    field public static final java.lang.String METADATA_INCLUDE_SELF_MANAGED_CALLS = "android.telecom.INCLUDE_SELF_MANAGED_CALLS";
-    field public static final java.lang.String METADATA_IN_CALL_SERVICE_CAR_MODE_UI = "android.telecom.IN_CALL_SERVICE_CAR_MODE_UI";
-    field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
-    field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
+    field public static final String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
+    field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
+    field public static final String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
+    field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telecom.extra.CALL_NETWORK_TYPE";
+    field public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
+    field public static final String EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME = "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME";
+    field public static final String EXTRA_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME = "android.telecom.extra.DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME";
+    field public static final String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS";
+    field public static final String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS";
+    field public static final String EXTRA_INCOMING_VIDEO_STATE = "android.telecom.extra.INCOMING_VIDEO_STATE";
+    field public static final String EXTRA_IS_DEFAULT_CALL_SCREENING_APP = "android.telecom.extra.IS_DEFAULT_CALL_SCREENING_APP";
+    field public static final String EXTRA_IS_ENABLED = "android.telecom.extra.IS_ENABLED";
+    field public static final String EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT";
+    field public static final String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
+    field public static final String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
+    field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+    field public static final String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
+    field public static final String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
+    field public static final String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
+    field public static final String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
+    field public static final String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
+    field public static final String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
+    field public static final String METADATA_INCLUDE_SELF_MANAGED_CALLS = "android.telecom.INCLUDE_SELF_MANAGED_CALLS";
+    field public static final String METADATA_IN_CALL_SERVICE_CAR_MODE_UI = "android.telecom.IN_CALL_SERVICE_CAR_MODE_UI";
+    field public static final String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
+    field public static final String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
@@ -43396,7 +43764,7 @@
     method public static boolean isReceptionEnabled(int);
     method public static boolean isTransmissionEnabled(int);
     method public static boolean isVideo(int);
-    method public static java.lang.String videoStateToString(int);
+    method public static String videoStateToString(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telecom.VideoProfile> CREATOR;
     field public static final int QUALITY_DEFAULT = 4; // 0x4
@@ -43543,182 +43911,182 @@
   }
 
   public class CarrierConfigManager {
-    method public android.os.PersistableBundle getConfig();
-    method public android.os.PersistableBundle getConfigForSubId(int);
+    method @Nullable public android.os.PersistableBundle getConfig();
+    method @Nullable public android.os.PersistableBundle getConfigForSubId(int);
     method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle);
     method public void notifyConfigChangedForSubId(int);
-    field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
+    field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
     field public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
-    field public static final java.lang.String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
-    field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
-    field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
-    field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
-    field public static final java.lang.String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
-    field public static final java.lang.String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
-    field public static final java.lang.String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
-    field public static final java.lang.String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
-    field public static final java.lang.String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
-    field public static final java.lang.String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
-    field public static final java.lang.String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
-    field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
-    field public static final java.lang.String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
-    field public static final java.lang.String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool";
-    field public static final java.lang.String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool";
-    field public static final java.lang.String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool";
-    field public static final java.lang.String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array";
-    field public static final java.lang.String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
-    field public static final java.lang.String KEY_CARRIER_CALL_SCREENING_APP_STRING = "call_screening_app";
-    field public static final java.lang.String KEY_CARRIER_CONFIG_VERSION_STRING = "carrier_config_version_string";
-    field public static final java.lang.String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings";
-    field public static final java.lang.String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT = "carrier_default_wfc_ims_mode_int";
-    field public static final java.lang.String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT = "carrier_default_wfc_ims_roaming_mode_int";
-    field public static final java.lang.String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL = "carrier_force_disable_etws_cmas_test_bool";
-    field public static final java.lang.String KEY_CARRIER_IMS_GBA_REQUIRED_BOOL = "carrier_ims_gba_required_bool";
-    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL = "carrier_instant_lettering_available_bool";
-    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING = "carrier_instant_lettering_encoding_string";
-    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING = "carrier_instant_lettering_escaped_chars_string";
-    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING = "carrier_instant_lettering_invalid_chars_string";
-    field public static final java.lang.String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT = "carrier_instant_lettering_length_limit_int";
-    field public static final java.lang.String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
-    field public static final java.lang.String KEY_CARRIER_NAME_STRING = "carrier_name_string";
-    field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
-    field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
-    field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
-    field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
-    field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
-    field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
-    field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
-    field public static final deprecated java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
-    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
-    field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
-    field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
-    field public static final java.lang.String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
-    field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
-    field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
-    field public static final java.lang.String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int";
-    field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
-    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool";
-    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
-    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
-    field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
-    field public static final java.lang.String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING = "config_ims_package_override_string";
-    field public static final java.lang.String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string";
-    field public static final java.lang.String KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL = "config_telephony_use_own_number_for_voicemail_bool";
-    field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
-    field public static final java.lang.String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
-    field public static final java.lang.String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
-    field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
-    field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
-    field public static final java.lang.String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
-    field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
-    field public static final java.lang.String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool";
-    field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
-    field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
-    field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
-    field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
-    field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
-    field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
-    field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
-    field public static final java.lang.String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool";
-    field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
-    field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
-    field public static final java.lang.String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
-    field public static final java.lang.String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array";
-    field public static final java.lang.String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool";
-    field public static final java.lang.String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
-    field public static final java.lang.String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
-    field public static final java.lang.String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
-    field public static final java.lang.String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
-    field public static final java.lang.String KEY_HIDE_PRESET_APN_DETAILS_BOOL = "hide_preset_apn_details_bool";
-    field public static final java.lang.String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
-    field public static final java.lang.String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
-    field public static final java.lang.String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int";
-    field public static final java.lang.String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
-    field public static final java.lang.String KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL = "is_ims_conference_size_enforced_bool";
-    field public static final java.lang.String KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL = "mdn_is_additional_voicemail_number_bool";
-    field public static final java.lang.String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
-    field public static final java.lang.String KEY_MMS_ALIAS_MAX_CHARS_INT = "aliasMaxChars";
-    field public static final java.lang.String KEY_MMS_ALIAS_MIN_CHARS_INT = "aliasMinChars";
-    field public static final java.lang.String KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL = "allowAttachAudio";
-    field public static final java.lang.String KEY_MMS_APPEND_TRANSACTION_ID_BOOL = "enabledTransID";
-    field public static final java.lang.String KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING = "emailGatewayNumber";
-    field public static final java.lang.String KEY_MMS_GROUP_MMS_ENABLED_BOOL = "enableGroupMms";
-    field public static final java.lang.String KEY_MMS_HTTP_PARAMS_STRING = "httpParams";
-    field public static final java.lang.String KEY_MMS_HTTP_SOCKET_TIMEOUT_INT = "httpSocketTimeout";
-    field public static final java.lang.String KEY_MMS_MAX_IMAGE_HEIGHT_INT = "maxImageHeight";
-    field public static final java.lang.String KEY_MMS_MAX_IMAGE_WIDTH_INT = "maxImageWidth";
-    field public static final java.lang.String KEY_MMS_MAX_MESSAGE_SIZE_INT = "maxMessageSize";
-    field public static final java.lang.String KEY_MMS_MESSAGE_TEXT_MAX_SIZE_INT = "maxMessageTextSize";
-    field public static final java.lang.String KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL = "enableMMSDeliveryReports";
-    field public static final java.lang.String KEY_MMS_MMS_ENABLED_BOOL = "enabledMMS";
-    field public static final java.lang.String KEY_MMS_MMS_READ_REPORT_ENABLED_BOOL = "enableMMSReadReports";
-    field public static final java.lang.String KEY_MMS_MULTIPART_SMS_ENABLED_BOOL = "enableMultipartSMS";
-    field public static final java.lang.String KEY_MMS_NAI_SUFFIX_STRING = "naiSuffix";
-    field public static final java.lang.String KEY_MMS_NOTIFY_WAP_MMSC_ENABLED_BOOL = "enabledNotifyWapMMSC";
-    field public static final java.lang.String KEY_MMS_RECIPIENT_LIMIT_INT = "recipientLimit";
-    field public static final java.lang.String KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL = "sendMultipartSmsAsSeparateMessages";
-    field public static final java.lang.String KEY_MMS_SHOW_CELL_BROADCAST_APP_LINKS_BOOL = "config_cellBroadcastAppLinks";
-    field public static final java.lang.String KEY_MMS_SMS_DELIVERY_REPORT_ENABLED_BOOL = "enableSMSDeliveryReports";
-    field public static final java.lang.String KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT = "smsToMmsTextLengthThreshold";
-    field public static final java.lang.String KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT = "smsToMmsTextThreshold";
-    field public static final java.lang.String KEY_MMS_SUBJECT_MAX_LENGTH_INT = "maxSubjectLength";
-    field public static final java.lang.String KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL = "supportHttpCharsetHeader";
-    field public static final java.lang.String KEY_MMS_SUPPORT_MMS_CONTENT_DISPOSITION_BOOL = "supportMmsContentDisposition";
-    field public static final java.lang.String KEY_MMS_UA_PROF_TAG_NAME_STRING = "uaProfTagName";
-    field public static final java.lang.String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl";
-    field public static final java.lang.String KEY_MMS_USER_AGENT_STRING = "userAgent";
-    field public static final java.lang.String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int";
-    field public static final java.lang.String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array";
-    field public static final java.lang.String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
-    field public static final java.lang.String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT = "opportunistic_network_entry_threshold_rsrp_int";
-    field public static final java.lang.String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT = "opportunistic_network_entry_threshold_rssnr_int";
-    field public static final java.lang.String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int";
-    field public static final java.lang.String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int";
-    field public static final java.lang.String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
-    field public static final java.lang.String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array";
-    field public static final java.lang.String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string";
-    field public static final java.lang.String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
-    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";
-    field public static final java.lang.String KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL = "show_signal_strength_in_sim_status_bool";
-    field public static final java.lang.String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
-    field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
-    field public static final java.lang.String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
-    field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
-    field public static final java.lang.String KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL = "support_clir_network_default_bool";
-    field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
-    field public static final java.lang.String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool";
-    field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
-    field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
-    field public static final java.lang.String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL = "treat_downgraded_video_calls_as_video_calls_bool";
-    field public static final java.lang.String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
-    field public static final java.lang.String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
-    field public static final java.lang.String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
-    field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
-    field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
-    field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
-    field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
-    field public static final java.lang.String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
-    field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
-    field public static final java.lang.String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
-    field public static final java.lang.String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
-    field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
-    field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
-    field public static final java.lang.String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
-    field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
-    field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
+    field public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
+    field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
+    field public static final String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
+    field public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
+    field public static final String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
+    field public static final String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
+    field public static final String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
+    field public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
+    field public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
+    field public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
+    field public static final String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
+    field public static final String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
+    field public static final String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
+    field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool";
+    field public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool";
+    field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool";
+    field public static final String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array";
+    field public static final String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
+    field public static final String KEY_CARRIER_CALL_SCREENING_APP_STRING = "call_screening_app";
+    field public static final String KEY_CARRIER_CONFIG_VERSION_STRING = "carrier_config_version_string";
+    field public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings";
+    field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT = "carrier_default_wfc_ims_mode_int";
+    field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT = "carrier_default_wfc_ims_roaming_mode_int";
+    field public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL = "carrier_force_disable_etws_cmas_test_bool";
+    field public static final String KEY_CARRIER_IMS_GBA_REQUIRED_BOOL = "carrier_ims_gba_required_bool";
+    field public static final String KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL = "carrier_instant_lettering_available_bool";
+    field public static final String KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING = "carrier_instant_lettering_encoding_string";
+    field public static final String KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING = "carrier_instant_lettering_escaped_chars_string";
+    field public static final String KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING = "carrier_instant_lettering_invalid_chars_string";
+    field public static final String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT = "carrier_instant_lettering_length_limit_int";
+    field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
+    field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
+    field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
+    field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
+    field public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
+    field public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
+    field public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
+    field public static final String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
+    field public static final String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
+    field @Deprecated public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    field public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
+    field public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
+    field public static final String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
+    field public static final String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
+    field public static final String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
+    field public static final String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
+    field public static final String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int";
+    field public static final String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
+    field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool";
+    field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
+    field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
+    field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING = "ci_action_on_sys_update_intent_string";
+    field public static final String KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING = "config_ims_package_override_string";
+    field public static final String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string";
+    field public static final String KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL = "config_telephony_use_own_number_for_voicemail_bool";
+    field public static final String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
+    field public static final String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
+    field public static final String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
+    field public static final String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
+    field public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
+    field public static final String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
+    field public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+    field public static final String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool";
+    field public static final String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
+    field public static final String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
+    field public static final String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
+    field public static final String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
+    field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
+    field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
+    field public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
+    field public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool";
+    field public static final String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
+    field public static final String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
+    field public static final String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
+    field public static final String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array";
+    field public static final String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool";
+    field public static final String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
+    field public static final String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
+    field public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
+    field public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
+    field public static final String KEY_HIDE_PRESET_APN_DETAILS_BOOL = "hide_preset_apn_details_bool";
+    field public static final String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
+    field public static final String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
+    field public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int";
+    field public static final String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
+    field public static final String KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL = "is_ims_conference_size_enforced_bool";
+    field public static final String KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL = "mdn_is_additional_voicemail_number_bool";
+    field public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
+    field public static final String KEY_MMS_ALIAS_MAX_CHARS_INT = "aliasMaxChars";
+    field public static final String KEY_MMS_ALIAS_MIN_CHARS_INT = "aliasMinChars";
+    field public static final String KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL = "allowAttachAudio";
+    field public static final String KEY_MMS_APPEND_TRANSACTION_ID_BOOL = "enabledTransID";
+    field public static final String KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING = "emailGatewayNumber";
+    field public static final String KEY_MMS_GROUP_MMS_ENABLED_BOOL = "enableGroupMms";
+    field public static final String KEY_MMS_HTTP_PARAMS_STRING = "httpParams";
+    field public static final String KEY_MMS_HTTP_SOCKET_TIMEOUT_INT = "httpSocketTimeout";
+    field public static final String KEY_MMS_MAX_IMAGE_HEIGHT_INT = "maxImageHeight";
+    field public static final String KEY_MMS_MAX_IMAGE_WIDTH_INT = "maxImageWidth";
+    field public static final String KEY_MMS_MAX_MESSAGE_SIZE_INT = "maxMessageSize";
+    field public static final String KEY_MMS_MESSAGE_TEXT_MAX_SIZE_INT = "maxMessageTextSize";
+    field public static final String KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL = "enableMMSDeliveryReports";
+    field public static final String KEY_MMS_MMS_ENABLED_BOOL = "enabledMMS";
+    field public static final String KEY_MMS_MMS_READ_REPORT_ENABLED_BOOL = "enableMMSReadReports";
+    field public static final String KEY_MMS_MULTIPART_SMS_ENABLED_BOOL = "enableMultipartSMS";
+    field public static final String KEY_MMS_NAI_SUFFIX_STRING = "naiSuffix";
+    field public static final String KEY_MMS_NOTIFY_WAP_MMSC_ENABLED_BOOL = "enabledNotifyWapMMSC";
+    field public static final String KEY_MMS_RECIPIENT_LIMIT_INT = "recipientLimit";
+    field public static final String KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL = "sendMultipartSmsAsSeparateMessages";
+    field public static final String KEY_MMS_SHOW_CELL_BROADCAST_APP_LINKS_BOOL = "config_cellBroadcastAppLinks";
+    field public static final String KEY_MMS_SMS_DELIVERY_REPORT_ENABLED_BOOL = "enableSMSDeliveryReports";
+    field public static final String KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT = "smsToMmsTextLengthThreshold";
+    field public static final String KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT = "smsToMmsTextThreshold";
+    field public static final String KEY_MMS_SUBJECT_MAX_LENGTH_INT = "maxSubjectLength";
+    field public static final String KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL = "supportHttpCharsetHeader";
+    field public static final String KEY_MMS_SUPPORT_MMS_CONTENT_DISPOSITION_BOOL = "supportMmsContentDisposition";
+    field public static final String KEY_MMS_UA_PROF_TAG_NAME_STRING = "uaProfTagName";
+    field public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl";
+    field public static final String KEY_MMS_USER_AGENT_STRING = "userAgent";
+    field public static final String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int";
+    field public static final String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array";
+    field public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
+    field public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT = "opportunistic_network_entry_threshold_rsrp_int";
+    field public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT = "opportunistic_network_entry_threshold_rssnr_int";
+    field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int";
+    field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int";
+    field public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
+    field public static final String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array";
+    field public static final String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string";
+    field public static final String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
+    field @Deprecated public static final String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
+    field public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
+    field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
+    field public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool";
+    field public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
+    field public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
+    field public static final String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
+    field public static final String KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL = "show_signal_strength_in_sim_status_bool";
+    field public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
+    field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
+    field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
+    field public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
+    field public static final String KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL = "support_clir_network_default_bool";
+    field public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
+    field public static final String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool";
+    field public static final String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
+    field public static final String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
+    field public static final String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL = "treat_downgraded_video_calls_as_video_calls_bool";
+    field public static final String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
+    field public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
+    field public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
+    field public static final String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
+    field public static final String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
+    field public static final String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
+    field public static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
+    field public static final String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
+    field public static final String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
+    field public static final String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
+    field public static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
+    field public static final String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
+    field public static final String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
+    field public static final String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
+    field public static final String KEY_VVM_TYPE_STRING = "vvm_type_string";
+    field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
 
   public abstract class CellIdentity implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.CharSequence getOperatorAlphaLong();
-    method public java.lang.CharSequence getOperatorAlphaShort();
-    method public void writeToParcel(android.os.Parcel, int);
+    method @Nullable public CharSequence getOperatorAlphaLong();
+    method @Nullable public CharSequence getOperatorAlphaShort();
+    method @CallSuper public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentity> CREATOR;
   }
 
@@ -43737,12 +44105,12 @@
     method public int getBsic();
     method public int getCid();
     method public int getLac();
-    method public deprecated int getMcc();
-    method public java.lang.String getMccString();
-    method public deprecated int getMnc();
-    method public java.lang.String getMncString();
-    method public java.lang.String getMobileNetworkOperator();
-    method public deprecated int getPsc();
+    method @Deprecated public int getMcc();
+    method public String getMccString();
+    method @Deprecated public int getMnc();
+    method public String getMncString();
+    method @Nullable public String getMobileNetworkOperator();
+    method @Deprecated public int getPsc();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityGsm> CREATOR;
   }
@@ -43751,11 +44119,11 @@
     method public int getBandwidth();
     method public int getCi();
     method public int getEarfcn();
-    method public deprecated int getMcc();
-    method public java.lang.String getMccString();
-    method public deprecated int getMnc();
-    method public java.lang.String getMncString();
-    method public java.lang.String getMobileNetworkOperator();
+    method @Deprecated public int getMcc();
+    method public String getMccString();
+    method @Deprecated public int getMnc();
+    method public String getMncString();
+    method @Nullable public String getMobileNetworkOperator();
     method public int getPci();
     method public int getTac();
     method public void writeToParcel(android.os.Parcel, int);
@@ -43764,8 +44132,8 @@
 
   public final class CellIdentityNr extends android.telephony.CellIdentity {
     method public int getChannelNumber();
-    method public java.lang.String getMccString();
-    method public java.lang.String getMncString();
+    method public String getMccString();
+    method public String getMncString();
     method public int getPci();
     method public int getTac();
     method public void writeToParcel(android.os.Parcel, int);
@@ -43776,9 +44144,9 @@
     method public int getCid();
     method public int getCpid();
     method public int getLac();
-    method public java.lang.String getMccString();
-    method public java.lang.String getMncString();
-    method public java.lang.String getMobileNetworkOperator();
+    method public String getMccString();
+    method public String getMncString();
+    method @Nullable public String getMobileNetworkOperator();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityTdscdma> CREATOR;
   }
@@ -43786,11 +44154,11 @@
   public final class CellIdentityWcdma extends android.telephony.CellIdentity {
     method public int getCid();
     method public int getLac();
-    method public deprecated int getMcc();
-    method public java.lang.String getMccString();
-    method public deprecated int getMnc();
-    method public java.lang.String getMncString();
-    method public java.lang.String getMobileNetworkOperator();
+    method @Deprecated public int getMcc();
+    method public String getMccString();
+    method @Deprecated public int getMnc();
+    method public String getMncString();
+    method @Nullable public String getMobileNetworkOperator();
     method public int getPsc();
     method public int getUarfcn();
     method public void writeToParcel(android.os.Parcel, int);
@@ -43852,7 +44220,7 @@
   }
 
   public abstract class CellSignalStrength {
-    method public abstract boolean equals(java.lang.Object);
+    method public abstract boolean equals(Object);
     method public abstract int getAsuLevel();
     method public abstract int getDbm();
     method public abstract int getLevel();
@@ -43883,6 +44251,7 @@
   public final class CellSignalStrengthGsm extends android.telephony.CellSignalStrength implements android.os.Parcelable {
     method public int describeContents();
     method public int getAsuLevel();
+    method public int getBitErrorRate();
     method public int getDbm();
     method public int getLevel();
     method public int getTimingAdvance();
@@ -43944,26 +44313,26 @@
   }
 
   public class MbmsDownloadSession implements java.lang.AutoCloseable {
-    method public void addProgressListener(android.telephony.mbms.DownloadRequest, java.util.concurrent.Executor, android.telephony.mbms.DownloadProgressListener);
-    method public void addStatusListener(android.telephony.mbms.DownloadRequest, java.util.concurrent.Executor, android.telephony.mbms.DownloadStatusListener);
-    method public void cancelDownload(android.telephony.mbms.DownloadRequest);
+    method public void addProgressListener(@NonNull android.telephony.mbms.DownloadRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.mbms.DownloadProgressListener);
+    method public void addStatusListener(@NonNull android.telephony.mbms.DownloadRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.mbms.DownloadStatusListener);
+    method public void cancelDownload(@NonNull android.telephony.mbms.DownloadRequest);
     method public void close();
-    method public static android.telephony.MbmsDownloadSession create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsDownloadSessionCallback);
-    method public static android.telephony.MbmsDownloadSession create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsDownloadSessionCallback);
-    method public void download(android.telephony.mbms.DownloadRequest);
-    method public java.io.File getTempFileRootDirectory();
-    method public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads();
-    method public void removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener);
-    method public void removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener);
+    method public static android.telephony.MbmsDownloadSession create(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.mbms.MbmsDownloadSessionCallback);
+    method @Nullable public static android.telephony.MbmsDownloadSession create(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, int, @NonNull android.telephony.mbms.MbmsDownloadSessionCallback);
+    method public void download(@NonNull android.telephony.mbms.DownloadRequest);
+    method @Nullable public java.io.File getTempFileRootDirectory();
+    method @NonNull public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads();
+    method public void removeProgressListener(@NonNull android.telephony.mbms.DownloadRequest, @NonNull android.telephony.mbms.DownloadProgressListener);
+    method public void removeStatusListener(@NonNull android.telephony.mbms.DownloadRequest, @NonNull android.telephony.mbms.DownloadStatusListener);
     method public void requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo);
-    method public void requestUpdateFileServices(java.util.List<java.lang.String>);
+    method public void requestUpdateFileServices(@NonNull java.util.List<java.lang.String>);
     method public void resetDownloadKnowledge(android.telephony.mbms.DownloadRequest);
-    method public void setTempFileRootDirectory(java.io.File);
-    field public static final java.lang.String DEFAULT_TOP_LEVEL_TEMP_DIRECTORY = "androidMbmsTempFileRoot";
-    field public static final java.lang.String EXTRA_MBMS_COMPLETED_FILE_URI = "android.telephony.extra.MBMS_COMPLETED_FILE_URI";
-    field public static final java.lang.String EXTRA_MBMS_DOWNLOAD_REQUEST = "android.telephony.extra.MBMS_DOWNLOAD_REQUEST";
-    field public static final java.lang.String EXTRA_MBMS_DOWNLOAD_RESULT = "android.telephony.extra.MBMS_DOWNLOAD_RESULT";
-    field public static final java.lang.String EXTRA_MBMS_FILE_INFO = "android.telephony.extra.MBMS_FILE_INFO";
+    method public void setTempFileRootDirectory(@NonNull java.io.File);
+    field public static final String DEFAULT_TOP_LEVEL_TEMP_DIRECTORY = "androidMbmsTempFileRoot";
+    field public static final String EXTRA_MBMS_COMPLETED_FILE_URI = "android.telephony.extra.MBMS_COMPLETED_FILE_URI";
+    field public static final String EXTRA_MBMS_DOWNLOAD_REQUEST = "android.telephony.extra.MBMS_DOWNLOAD_REQUEST";
+    field public static final String EXTRA_MBMS_DOWNLOAD_RESULT = "android.telephony.extra.MBMS_DOWNLOAD_RESULT";
+    field public static final String EXTRA_MBMS_FILE_INFO = "android.telephony.extra.MBMS_FILE_INFO";
     field public static final int RESULT_CANCELLED = 2; // 0x2
     field public static final int RESULT_DOWNLOAD_FAILURE = 6; // 0x6
     field public static final int RESULT_EXPIRED = 3; // 0x3
@@ -43981,36 +44350,36 @@
 
   public class MbmsGroupCallSession implements java.lang.AutoCloseable {
     method public void close();
-    method public static android.telephony.MbmsGroupCallSession create(android.content.Context, int, java.util.concurrent.Executor, 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(long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, java.util.concurrent.Executor, android.telephony.mbms.GroupCallCallback);
+    method @Nullable public static android.telephony.MbmsGroupCallSession create(@NonNull android.content.Context, int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.mbms.MbmsGroupCallSessionCallback);
+    method public static android.telephony.MbmsGroupCallSession create(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.mbms.MbmsGroupCallSessionCallback);
+    method @Nullable public android.telephony.mbms.GroupCall startGroupCall(long, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.concurrent.Executor, @NonNull 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);
-    method public static android.telephony.MbmsStreamingSession create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsStreamingSessionCallback);
+    method @Nullable public static android.telephony.MbmsStreamingSession create(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, int, @NonNull android.telephony.mbms.MbmsStreamingSessionCallback);
+    method public static android.telephony.MbmsStreamingSession create(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.mbms.MbmsStreamingSessionCallback);
     method public void requestUpdateStreamingServices(java.util.List<java.lang.String>);
-    method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, java.util.concurrent.Executor, android.telephony.mbms.StreamingServiceCallback);
+    method @Nullable public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, @NonNull java.util.concurrent.Executor, android.telephony.mbms.StreamingServiceCallback);
   }
 
-  public deprecated class NeighboringCellInfo implements android.os.Parcelable {
-    ctor public deprecated NeighboringCellInfo();
-    ctor public deprecated NeighboringCellInfo(int, int);
-    ctor public NeighboringCellInfo(int, java.lang.String, int);
-    ctor public NeighboringCellInfo(android.os.Parcel);
-    method public int describeContents();
-    method public int getCid();
-    method public int getLac();
-    method public int getNetworkType();
-    method public int getPsc();
-    method public int getRssi();
-    method public deprecated void setCid(int);
-    method public deprecated void setRssi(int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telephony.NeighboringCellInfo> CREATOR;
-    field public static final int UNKNOWN_CID = -1; // 0xffffffff
-    field public static final int UNKNOWN_RSSI = 99; // 0x63
+  @Deprecated public class NeighboringCellInfo implements android.os.Parcelable {
+    ctor @Deprecated public NeighboringCellInfo();
+    ctor @Deprecated public NeighboringCellInfo(int, int);
+    ctor @Deprecated public NeighboringCellInfo(int, String, int);
+    ctor @Deprecated public NeighboringCellInfo(android.os.Parcel);
+    method @Deprecated public int describeContents();
+    method @Deprecated public int getCid();
+    method @Deprecated public int getLac();
+    method @Deprecated public int getNetworkType();
+    method @Deprecated public int getPsc();
+    method @Deprecated public int getRssi();
+    method @Deprecated public void setCid(int);
+    method @Deprecated public void setRssi(int);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.telephony.NeighboringCellInfo> CREATOR;
+    field @Deprecated public static final int UNKNOWN_CID = -1; // 0xffffffff
+    field @Deprecated public static final int UNKNOWN_RSSI = 99; // 0x63
   }
 
   public class NetworkScan {
@@ -44043,58 +44412,58 @@
 
   public class PhoneNumberFormattingTextWatcher implements android.text.TextWatcher {
     ctor public PhoneNumberFormattingTextWatcher();
-    ctor public PhoneNumberFormattingTextWatcher(java.lang.String);
-    method public synchronized void afterTextChanged(android.text.Editable);
-    method public void beforeTextChanged(java.lang.CharSequence, int, int, int);
-    method public void onTextChanged(java.lang.CharSequence, int, int, int);
+    ctor public PhoneNumberFormattingTextWatcher(String);
+    method public void afterTextChanged(android.text.Editable);
+    method public void beforeTextChanged(CharSequence, int, int, int);
+    method public void onTextChanged(CharSequence, int, int, int);
   }
 
   public class PhoneNumberUtils {
     ctor public PhoneNumberUtils();
     method public static void addTtsSpan(android.text.Spannable, int, int);
-    method public static deprecated java.lang.String calledPartyBCDFragmentToString(byte[], int, int);
-    method public static java.lang.String calledPartyBCDFragmentToString(byte[], int, int, int);
-    method public static deprecated java.lang.String calledPartyBCDToString(byte[], int, int);
-    method public static java.lang.String calledPartyBCDToString(byte[], int, int, int);
-    method public static boolean compare(java.lang.String, java.lang.String);
-    method public static boolean compare(android.content.Context, java.lang.String, java.lang.String);
-    method public static java.lang.String convertKeypadLettersToDigits(java.lang.String);
-    method public static android.text.style.TtsSpan createTtsSpan(java.lang.String);
-    method public static java.lang.CharSequence createTtsSpannable(java.lang.CharSequence);
-    method public static java.lang.String extractNetworkPortion(java.lang.String);
-    method public static java.lang.String extractPostDialPortion(java.lang.String);
-    method public static deprecated void formatJapaneseNumber(android.text.Editable);
-    method public static deprecated void formatNanpNumber(android.text.Editable);
-    method public static deprecated java.lang.String formatNumber(java.lang.String);
-    method public static deprecated void formatNumber(android.text.Editable, int);
-    method public static java.lang.String formatNumber(java.lang.String, java.lang.String);
-    method public static java.lang.String formatNumber(java.lang.String, java.lang.String, java.lang.String);
-    method public static java.lang.String formatNumberToE164(java.lang.String, java.lang.String);
-    method public static java.lang.String formatNumberToRFC3966(java.lang.String, java.lang.String);
-    method public static deprecated int getFormatTypeForLocale(java.util.Locale);
-    method public static java.lang.String getNumberFromIntent(android.content.Intent, android.content.Context);
-    method public static java.lang.String getStrippedReversed(java.lang.String);
+    method @Deprecated public static String calledPartyBCDFragmentToString(byte[], int, int);
+    method public static String calledPartyBCDFragmentToString(byte[], int, int, int);
+    method @Deprecated public static String calledPartyBCDToString(byte[], int, int);
+    method public static String calledPartyBCDToString(byte[], int, int, int);
+    method public static boolean compare(String, String);
+    method public static boolean compare(android.content.Context, String, String);
+    method public static String convertKeypadLettersToDigits(String);
+    method public static android.text.style.TtsSpan createTtsSpan(String);
+    method public static CharSequence createTtsSpannable(CharSequence);
+    method public static String extractNetworkPortion(String);
+    method public static String extractPostDialPortion(String);
+    method @Deprecated public static void formatJapaneseNumber(android.text.Editable);
+    method @Deprecated public static void formatNanpNumber(android.text.Editable);
+    method @Deprecated public static String formatNumber(String);
+    method @Deprecated public static void formatNumber(android.text.Editable, int);
+    method public static String formatNumber(String, String);
+    method public static String formatNumber(String, String, String);
+    method public static String formatNumberToE164(String, String);
+    method public static String formatNumberToRFC3966(String, String);
+    method @Deprecated public static int getFormatTypeForLocale(java.util.Locale);
+    method public static String getNumberFromIntent(android.content.Intent, android.content.Context);
+    method public static String getStrippedReversed(String);
     method public static final boolean is12Key(char);
     method public static final boolean isDialable(char);
-    method public static deprecated boolean isEmergencyNumber(java.lang.String);
-    method public static boolean isGlobalPhoneNumber(java.lang.String);
+    method @Deprecated public static boolean isEmergencyNumber(String);
+    method public static boolean isGlobalPhoneNumber(String);
     method public static boolean isISODigit(char);
-    method public static deprecated boolean isLocalEmergencyNumber(android.content.Context, java.lang.String);
+    method @Deprecated public static boolean isLocalEmergencyNumber(android.content.Context, String);
     method public static final boolean isNonSeparator(char);
     method public static final boolean isReallyDialable(char);
     method public static final boolean isStartsPostDial(char);
-    method public static boolean isVoiceMailNumber(java.lang.String);
-    method public static boolean isWellFormedSmsAddress(java.lang.String);
-    method public static byte[] networkPortionToCalledPartyBCD(java.lang.String);
-    method public static byte[] networkPortionToCalledPartyBCDWithLength(java.lang.String);
-    method public static java.lang.String normalizeNumber(java.lang.String);
-    method public static deprecated byte[] numberToCalledPartyBCD(java.lang.String);
-    method public static byte[] numberToCalledPartyBCD(java.lang.String, int);
-    method public static java.lang.String replaceUnicodeDigits(java.lang.String);
-    method public static java.lang.String stringFromStringAndTOA(java.lang.String, int);
-    method public static java.lang.String stripSeparators(java.lang.String);
-    method public static java.lang.String toCallerIDMinMatch(java.lang.String);
-    method public static int toaFromString(java.lang.String);
+    method public static boolean isVoiceMailNumber(String);
+    method public static boolean isWellFormedSmsAddress(String);
+    method public static byte[] networkPortionToCalledPartyBCD(String);
+    method public static byte[] networkPortionToCalledPartyBCDWithLength(String);
+    method public static String normalizeNumber(String);
+    method @Deprecated public static byte[] numberToCalledPartyBCD(String);
+    method public static byte[] numberToCalledPartyBCD(String, int);
+    method public static String replaceUnicodeDigits(String);
+    method public static String stringFromStringAndTOA(String, int);
+    method public static String stripSeparators(String);
+    method public static String toCallerIDMinMatch(String);
+    method public static int toaFromString(String);
     field public static final int BCD_EXTENDED_TYPE_CALLED_PARTY = 2; // 0x2
     field public static final int BCD_EXTENDED_TYPE_EF_ADN = 1; // 0x1
     field public static final int FORMAT_JAPAN = 2; // 0x2
@@ -44109,9 +44478,9 @@
 
   public class PhoneStateListener {
     ctor public PhoneStateListener();
-    ctor public PhoneStateListener(java.util.concurrent.Executor);
+    ctor public PhoneStateListener(@NonNull java.util.concurrent.Executor);
     method public void onCallForwardingIndicatorChanged(boolean);
-    method public void onCallStateChanged(int, java.lang.String);
+    method public void onCallStateChanged(int, String);
     method public void onCellInfoChanged(java.util.List<android.telephony.CellInfo>);
     method public void onCellLocationChanged(android.telephony.CellLocation);
     method public void onDataActivity(int);
@@ -44119,7 +44488,7 @@
     method public void onDataConnectionStateChanged(int, int);
     method public void onMessageWaitingIndicatorChanged(boolean);
     method public void onServiceStateChanged(android.telephony.ServiceState);
-    method public deprecated void onSignalStrengthChanged(int);
+    method @Deprecated public void onSignalStrengthChanged(int);
     method public void onSignalStrengthsChanged(android.telephony.SignalStrength);
     method public void onUserMobileDataStateChanged(boolean);
     field public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8
@@ -44132,7 +44501,7 @@
     field public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4
     field public static final int LISTEN_NONE = 0; // 0x0
     field public static final int LISTEN_SERVICE_STATE = 1; // 0x1
-    field public static final deprecated int LISTEN_SIGNAL_STRENGTH = 2; // 0x2
+    field @Deprecated public static final int LISTEN_SIGNAL_STRENGTH = 2; // 0x2
     field public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100
     field public static final int LISTEN_USER_MOBILE_DATA_STATE = 524288; // 0x80000
   }
@@ -44159,13 +44528,13 @@
     method public int getChannelNumber();
     method public int getDuplexMode();
     method public boolean getIsManualSelection();
-    method public java.lang.String getOperatorAlphaLong();
-    method public java.lang.String getOperatorAlphaShort();
-    method public java.lang.String getOperatorNumeric();
+    method public String getOperatorAlphaLong();
+    method public String getOperatorAlphaShort();
+    method public String getOperatorNumeric();
     method public boolean getRoaming();
     method public int getState();
     method public void setIsManualSelection(boolean);
-    method public void setOperatorName(java.lang.String, java.lang.String, java.lang.String);
+    method public void setOperatorName(String, String, String);
     method public void setRoaming(boolean);
     method public void setState(int);
     method public void setStateOff();
@@ -44184,67 +44553,68 @@
 
   public class SignalStrength implements android.os.Parcelable {
     method public int describeContents();
-    method public int getCdmaDbm();
-    method public int getCdmaEcio();
-    method public int getEvdoDbm();
-    method public int getEvdoEcio();
-    method public int getEvdoSnr();
-    method public int getGsmBitErrorRate();
-    method public int getGsmSignalStrength();
+    method @Deprecated public int getCdmaDbm();
+    method @Deprecated public int getCdmaEcio();
+    method @NonNull public java.util.List<android.telephony.CellSignalStrength> getCellSignalStrengths();
+    method @Deprecated public int getEvdoDbm();
+    method @Deprecated public int getEvdoEcio();
+    method @Deprecated public int getEvdoSnr();
+    method @Deprecated public int getGsmBitErrorRate();
+    method @Deprecated public int getGsmSignalStrength();
     method public int getLevel();
-    method public boolean isGsm();
+    method @Deprecated public boolean isGsm();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int INVALID = 2147483647; // 0x7fffffff
   }
 
   public final class SmsManager {
-    method public java.lang.String createAppSpecificSmsToken(android.app.PendingIntent);
-    method public java.util.ArrayList<java.lang.String> divideMessage(java.lang.String);
-    method public void downloadMultimediaMessage(android.content.Context, java.lang.String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
+    method public String createAppSpecificSmsToken(android.app.PendingIntent);
+    method public java.util.ArrayList<java.lang.String> divideMessage(String);
+    method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
     method public android.os.Bundle getCarrierConfigValues();
     method public static android.telephony.SmsManager getDefault();
     method public static int getDefaultSmsSubscriptionId();
     method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
     method public int getSubscriptionId();
-    method public void injectSmsPdu(byte[], java.lang.String, android.app.PendingIntent);
-    method public void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
-    method public void sendMultimediaMessage(android.content.Context, android.net.Uri, java.lang.String, android.os.Bundle, android.app.PendingIntent);
-    method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
-    method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
-    method public void sendTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
-    field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
-    field public static final java.lang.String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
-    field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
-    field public static final java.lang.String MMS_CONFIG_ALIAS_MAX_CHARS = "aliasMaxChars";
-    field public static final java.lang.String MMS_CONFIG_ALIAS_MIN_CHARS = "aliasMinChars";
-    field public static final java.lang.String MMS_CONFIG_ALLOW_ATTACH_AUDIO = "allowAttachAudio";
-    field public static final java.lang.String MMS_CONFIG_APPEND_TRANSACTION_ID = "enabledTransID";
-    field public static final java.lang.String MMS_CONFIG_EMAIL_GATEWAY_NUMBER = "emailGatewayNumber";
-    field public static final java.lang.String MMS_CONFIG_GROUP_MMS_ENABLED = "enableGroupMms";
-    field public static final java.lang.String MMS_CONFIG_HTTP_PARAMS = "httpParams";
-    field public static final java.lang.String MMS_CONFIG_HTTP_SOCKET_TIMEOUT = "httpSocketTimeout";
-    field public static final java.lang.String MMS_CONFIG_MAX_IMAGE_HEIGHT = "maxImageHeight";
-    field public static final java.lang.String MMS_CONFIG_MAX_IMAGE_WIDTH = "maxImageWidth";
-    field public static final java.lang.String MMS_CONFIG_MAX_MESSAGE_SIZE = "maxMessageSize";
-    field public static final java.lang.String MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE = "maxMessageTextSize";
-    field public static final java.lang.String MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED = "enableMMSDeliveryReports";
-    field public static final java.lang.String MMS_CONFIG_MMS_ENABLED = "enabledMMS";
-    field public static final java.lang.String MMS_CONFIG_MMS_READ_REPORT_ENABLED = "enableMMSReadReports";
-    field public static final java.lang.String MMS_CONFIG_MULTIPART_SMS_ENABLED = "enableMultipartSMS";
-    field public static final java.lang.String MMS_CONFIG_NAI_SUFFIX = "naiSuffix";
-    field public static final java.lang.String MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED = "enabledNotifyWapMMSC";
-    field public static final java.lang.String MMS_CONFIG_RECIPIENT_LIMIT = "recipientLimit";
-    field public static final java.lang.String MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES = "sendMultipartSmsAsSeparateMessages";
-    field public static final java.lang.String MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS = "config_cellBroadcastAppLinks";
-    field public static final java.lang.String MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED = "enableSMSDeliveryReports";
-    field public static final java.lang.String MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD = "smsToMmsTextLengthThreshold";
-    field public static final java.lang.String MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD = "smsToMmsTextThreshold";
-    field public static final java.lang.String MMS_CONFIG_SUBJECT_MAX_LENGTH = "maxSubjectLength";
-    field public static final java.lang.String MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER = "supportHttpCharsetHeader";
-    field public static final java.lang.String MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION = "supportMmsContentDisposition";
-    field public static final java.lang.String MMS_CONFIG_UA_PROF_TAG_NAME = "uaProfTagName";
-    field public static final java.lang.String MMS_CONFIG_UA_PROF_URL = "uaProfUrl";
-    field public static final java.lang.String MMS_CONFIG_USER_AGENT = "userAgent";
+    method public void injectSmsPdu(byte[], String, android.app.PendingIntent);
+    method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
+    method public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent);
+    method public void sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
+    method public void sendTextMessage(String, String, String, android.app.PendingIntent, android.app.PendingIntent);
+    method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.SEND_SMS}) public void sendTextMessageWithoutPersisting(String, String, String, android.app.PendingIntent, android.app.PendingIntent);
+    field public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
+    field public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
+    field public static final String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
+    field public static final String MMS_CONFIG_ALIAS_MAX_CHARS = "aliasMaxChars";
+    field public static final String MMS_CONFIG_ALIAS_MIN_CHARS = "aliasMinChars";
+    field public static final String MMS_CONFIG_ALLOW_ATTACH_AUDIO = "allowAttachAudio";
+    field public static final String MMS_CONFIG_APPEND_TRANSACTION_ID = "enabledTransID";
+    field public static final String MMS_CONFIG_EMAIL_GATEWAY_NUMBER = "emailGatewayNumber";
+    field public static final String MMS_CONFIG_GROUP_MMS_ENABLED = "enableGroupMms";
+    field public static final String MMS_CONFIG_HTTP_PARAMS = "httpParams";
+    field public static final String MMS_CONFIG_HTTP_SOCKET_TIMEOUT = "httpSocketTimeout";
+    field public static final String MMS_CONFIG_MAX_IMAGE_HEIGHT = "maxImageHeight";
+    field public static final String MMS_CONFIG_MAX_IMAGE_WIDTH = "maxImageWidth";
+    field public static final String MMS_CONFIG_MAX_MESSAGE_SIZE = "maxMessageSize";
+    field public static final String MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE = "maxMessageTextSize";
+    field public static final String MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED = "enableMMSDeliveryReports";
+    field public static final String MMS_CONFIG_MMS_ENABLED = "enabledMMS";
+    field public static final String MMS_CONFIG_MMS_READ_REPORT_ENABLED = "enableMMSReadReports";
+    field public static final String MMS_CONFIG_MULTIPART_SMS_ENABLED = "enableMultipartSMS";
+    field public static final String MMS_CONFIG_NAI_SUFFIX = "naiSuffix";
+    field public static final String MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED = "enabledNotifyWapMMSC";
+    field public static final String MMS_CONFIG_RECIPIENT_LIMIT = "recipientLimit";
+    field public static final String MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES = "sendMultipartSmsAsSeparateMessages";
+    field public static final String MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS = "config_cellBroadcastAppLinks";
+    field public static final String MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED = "enableSMSDeliveryReports";
+    field public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD = "smsToMmsTextLengthThreshold";
+    field public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD = "smsToMmsTextThreshold";
+    field public static final String MMS_CONFIG_SUBJECT_MAX_LENGTH = "maxSubjectLength";
+    field public static final String MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER = "supportHttpCharsetHeader";
+    field public static final String MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION = "supportMmsContentDisposition";
+    field public static final String MMS_CONFIG_UA_PROF_TAG_NAME = "uaProfTagName";
+    field public static final String MMS_CONFIG_UA_PROF_URL = "uaProfUrl";
+    field public static final String MMS_CONFIG_USER_AGENT = "userAgent";
     field public static final int MMS_ERROR_CONFIGURATION_ERROR = 7; // 0x7
     field public static final int MMS_ERROR_HTTP_FAILURE = 4; // 0x4
     field public static final int MMS_ERROR_INVALID_APN = 2; // 0x2
@@ -44268,29 +44638,29 @@
   }
 
   public class SmsMessage {
-    method public static int[] calculateLength(java.lang.CharSequence, boolean);
-    method public static int[] calculateLength(java.lang.String, boolean);
-    method public static deprecated android.telephony.SmsMessage createFromPdu(byte[]);
-    method public static android.telephony.SmsMessage createFromPdu(byte[], java.lang.String);
-    method public java.lang.String getDisplayMessageBody();
-    method public java.lang.String getDisplayOriginatingAddress();
-    method public java.lang.String getEmailBody();
-    method public java.lang.String getEmailFrom();
+    method public static int[] calculateLength(CharSequence, boolean);
+    method public static int[] calculateLength(String, boolean);
+    method @Deprecated public static android.telephony.SmsMessage createFromPdu(byte[]);
+    method public static android.telephony.SmsMessage createFromPdu(byte[], String);
+    method public String getDisplayMessageBody();
+    method public String getDisplayOriginatingAddress();
+    method public String getEmailBody();
+    method public String getEmailFrom();
     method public int getIndexOnIcc();
-    method public deprecated int getIndexOnSim();
-    method public java.lang.String getMessageBody();
+    method @Deprecated public int getIndexOnSim();
+    method public String getMessageBody();
     method public android.telephony.SmsMessage.MessageClass getMessageClass();
-    method public java.lang.String getOriginatingAddress();
+    method @Nullable public String getOriginatingAddress();
     method public byte[] getPdu();
     method public int getProtocolIdentifier();
-    method public java.lang.String getPseudoSubject();
-    method public java.lang.String getServiceCenterAddress();
+    method public String getPseudoSubject();
+    method public String getServiceCenterAddress();
     method public int getStatus();
     method public int getStatusOnIcc();
-    method public deprecated int getStatusOnSim();
-    method public static android.telephony.SmsMessage.SubmitPdu getSubmitPdu(java.lang.String, java.lang.String, java.lang.String, boolean);
-    method public static android.telephony.SmsMessage.SubmitPdu getSubmitPdu(java.lang.String, java.lang.String, short, byte[], boolean);
-    method public static int getTPLayerLengthForPDU(java.lang.String);
+    method @Deprecated public int getStatusOnSim();
+    method public static android.telephony.SmsMessage.SubmitPdu getSubmitPdu(String, String, String, boolean);
+    method public static android.telephony.SmsMessage.SubmitPdu getSubmitPdu(String, String, short, byte[], boolean);
+    method public static int getTPLayerLengthForPDU(String);
     method public long getTimestampMillis();
     method public byte[] getUserData();
     method public boolean isCphsMwiMessage();
@@ -44305,17 +44675,15 @@
     field public static final int ENCODING_7BIT = 1; // 0x1
     field public static final int ENCODING_8BIT = 2; // 0x2
     field public static final int ENCODING_UNKNOWN = 0; // 0x0
-    field public static final java.lang.String FORMAT_3GPP = "3gpp";
-    field public static final java.lang.String FORMAT_3GPP2 = "3gpp2";
+    field public static final String FORMAT_3GPP = "3gpp";
+    field public static final String FORMAT_3GPP2 = "3gpp2";
     field public static final int MAX_USER_DATA_BYTES = 140; // 0x8c
     field public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; // 0x86
     field public static final int MAX_USER_DATA_SEPTETS = 160; // 0xa0
     field public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; // 0x99
   }
 
-  public static final class SmsMessage.MessageClass extends java.lang.Enum {
-    method public static android.telephony.SmsMessage.MessageClass valueOf(java.lang.String);
-    method public static final android.telephony.SmsMessage.MessageClass[] values();
+  public enum SmsMessage.MessageClass {
     enum_constant public static final android.telephony.SmsMessage.MessageClass CLASS_0;
     enum_constant public static final android.telephony.SmsMessage.MessageClass CLASS_1;
     enum_constant public static final android.telephony.SmsMessage.MessageClass CLASS_2;
@@ -44332,20 +44700,21 @@
     method public android.graphics.Bitmap createIconBitmap(android.content.Context);
     method public int describeContents();
     method public int getCarrierId();
-    method public java.lang.CharSequence getCarrierName();
-    method public java.lang.String getCountryIso();
+    method public CharSequence getCarrierName();
+    method public String getCountryIso();
     method public int getDataRoaming();
-    method public java.lang.CharSequence getDisplayName();
-    method public java.lang.String getGroupUuid();
-    method public java.lang.String getIccId();
+    method public CharSequence getDisplayName();
+    method public String getGroupUuid();
+    method public String getIccId();
     method public int getIconTint();
-    method public deprecated int getMcc();
-    method public java.lang.String getMccString();
-    method public deprecated int getMnc();
-    method public java.lang.String getMncString();
-    method public java.lang.String getNumber();
+    method @Deprecated public int getMcc();
+    method public String getMccString();
+    method @Deprecated public int getMnc();
+    method public String getMncString();
+    method public String getNumber();
     method public int getSimSlotIndex();
     method public int getSubscriptionId();
+    method public int getSubscriptionType();
     method public boolean isEmbedded();
     method public boolean isOpportunistic();
     method public void writeToParcel(android.os.Parcel, int);
@@ -44353,49 +44722,51 @@
   }
 
   public class SubscriptionManager {
-    method public void addOnOpportunisticSubscriptionsChangedListener(java.util.concurrent.Executor, android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
+    method public void addOnOpportunisticSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
     method public void addOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
     method public boolean canManageSubscription(android.telephony.SubscriptionInfo);
-    method public static deprecated android.telephony.SubscriptionManager from(android.content.Context);
+    method @Deprecated public static android.telephony.SubscriptionManager from(android.content.Context);
     method public java.util.List<android.telephony.SubscriptionInfo> getAccessibleSubscriptionInfoList();
-    method public android.telephony.SubscriptionInfo getActiveSubscriptionInfo(int);
-    method public int getActiveSubscriptionInfoCount();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfo(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getActiveSubscriptionInfoCount();
     method public int getActiveSubscriptionInfoCountMax();
-    method public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
-    method public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
     method public static int getDefaultDataSubscriptionId();
     method public static int getDefaultSmsSubscriptionId();
     method public static int getDefaultSubscriptionId();
     method public static int getDefaultVoiceSubscriptionId();
-    method public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions();
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions();
     method public static int getSlotIndex(int);
-    method public int[] getSubscriptionIds(int);
-    method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
-    method public java.util.List<android.telephony.SubscriptionInfo> getSubscriptionsInGroup(int);
-    method public boolean isActiveSubscriptionId(int);
+    method @Nullable public int[] getSubscriptionIds(int);
+    method @NonNull public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getSubscriptionsInGroup(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isActiveSubscriptionId(int);
     method public boolean isNetworkRoaming(int);
     method public static boolean isUsableSubscriptionId(int);
     method public static boolean isValidSubscriptionId(int);
     method public void removeOnOpportunisticSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
-    method public boolean removeSubscriptionsFromGroup(int[]);
-    method public boolean setMetered(boolean, int);
-    method public boolean setOpportunistic(boolean, int);
-    method public java.lang.String setSubscriptionGroup(int[]);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean removeSubscriptionsFromGroup(@NonNull int[]);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setMetered(boolean, int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String setSubscriptionGroup(@NonNull int[]);
     method public void setSubscriptionOverrideCongested(int, boolean, long);
     method public void setSubscriptionOverrideUnmetered(int, boolean, long);
-    method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
-    method public void switchToSubscription(int, android.app.PendingIntent);
-    field public static final java.lang.String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED";
-    field public static final java.lang.String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED";
-    field public static final java.lang.String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
-    field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
+    method public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>);
+    method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, android.app.PendingIntent);
+    field public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED";
+    field public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED";
+    field public static final String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
+    field public static final String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
     field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
     field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
     field public static final int DEFAULT_SUBSCRIPTION_ID = 2147483647; // 0x7fffffff
-    field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
+    field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
     field public static final int INVALID_SIM_SLOT_INDEX = -1; // 0xffffffff
     field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
+    field public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0; // 0x0
+    field public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1; // 0x1
   }
 
   public static class SubscriptionManager.OnOpportunisticSubscriptionsChangedListener {
@@ -44415,8 +44786,8 @@
     method public long getDataLimitBytes();
     method public long getDataUsageBytes();
     method public long getDataUsageTime();
-    method public java.lang.CharSequence getSummary();
-    method public java.lang.CharSequence getTitle();
+    method @Nullable public CharSequence getSummary();
+    method @Nullable public CharSequence getTitle();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final long BYTES_UNKNOWN = -1L; // 0xffffffffffffffffL
     field public static final long BYTES_UNLIMITED = 9223372036854775807L; // 0x7fffffffffffffffL
@@ -44434,114 +44805,114 @@
     method public static android.telephony.SubscriptionPlan.Builder createRecurring(java.time.ZonedDateTime, java.time.Period);
     method public android.telephony.SubscriptionPlan.Builder setDataLimit(long, int);
     method public android.telephony.SubscriptionPlan.Builder setDataUsage(long, long);
-    method public android.telephony.SubscriptionPlan.Builder setSummary(java.lang.CharSequence);
-    method public android.telephony.SubscriptionPlan.Builder setTitle(java.lang.CharSequence);
+    method public android.telephony.SubscriptionPlan.Builder setSummary(@Nullable CharSequence);
+    method public android.telephony.SubscriptionPlan.Builder setTitle(@Nullable CharSequence);
   }
 
   public class TelephonyManager {
     method public boolean canChangeDtmfToneLength();
-    method public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
+    method @Nullable public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
     method public android.telephony.TelephonyManager createForSubscriptionId(int);
-    method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
+    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo();
     method public int getCallState();
-    method public android.os.PersistableBundle getCarrierConfig();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @WorkerThread public android.os.PersistableBundle getCarrierConfig();
     method public int getCarrierIdFromSimMccMnc();
-    method public deprecated android.telephony.CellLocation getCellLocation();
-    method public java.util.Map<java.lang.Integer, java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList();
-    method public java.util.Map<java.lang.Integer, java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList(int);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.CellLocation getCellLocation();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList(int);
     method public int getDataActivity();
-    method public int getDataNetworkType();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getDataNetworkType();
     method public int getDataState();
-    method public deprecated java.lang.String getDeviceId();
-    method public deprecated java.lang.String getDeviceId(int);
-    method public java.lang.String getDeviceSoftwareVersion();
-    method public java.lang.String[] getForbiddenPlmns();
-    method public java.lang.String getGroupIdLevel1();
-    method public java.lang.String getIccAuthentication(int, int, java.lang.String);
-    method public java.lang.String getImei();
-    method public java.lang.String getImei(int);
-    method public java.lang.String getLine1Number();
-    method public java.lang.String getManufacturerCode();
-    method public java.lang.String getManufacturerCode(int);
-    method public java.lang.String getMeid();
-    method public java.lang.String getMeid(int);
-    method public java.lang.String getMmsUAProfUrl();
-    method public java.lang.String getMmsUserAgent();
-    method public java.lang.String getNai();
-    method public java.lang.String getNetworkCountryIso();
-    method public java.lang.String getNetworkOperator();
-    method public java.lang.String getNetworkOperatorName();
-    method public java.lang.String getNetworkSpecifier();
+    method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId();
+    method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String[] getForbiddenPlmns();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getGroupIdLevel1();
+    method public String getIccAuthentication(int, int, String);
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getImei();
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getImei(int);
+    method @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_PHONE_NUMBERS}) public String getLine1Number();
+    method public String getManufacturerCode();
+    method public String getManufacturerCode(int);
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid();
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid(int);
+    method public String getMmsUAProfUrl();
+    method public String getMmsUserAgent();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getNai();
+    method public String getNetworkCountryIso();
+    method public String getNetworkOperator();
+    method public String getNetworkOperatorName();
+    method public String getNetworkSpecifier();
     method public int getNetworkType();
     method public int getPhoneCount();
     method public int getPhoneType();
     method public int getPreferredOpportunisticDataSubscription();
-    method public android.telephony.ServiceState getServiceState();
-    method public android.telephony.SignalStrength getSignalStrength();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.ServiceState getServiceState();
+    method @Nullable public android.telephony.SignalStrength getSignalStrength();
     method public int getSimCarrierId();
-    method public java.lang.CharSequence getSimCarrierIdName();
-    method public java.lang.String getSimCountryIso();
-    method public java.lang.String getSimOperator();
-    method public java.lang.String getSimOperatorName();
+    method @Nullable public CharSequence getSimCarrierIdName();
+    method public String getSimCountryIso();
+    method public String getSimOperator();
+    method public String getSimOperatorName();
     method public int getSimPreciseCarrierId();
-    method public java.lang.CharSequence getSimPreciseCarrierIdName();
-    method public java.lang.String getSimSerialNumber();
+    method @Nullable public CharSequence getSimPreciseCarrierIdName();
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSimSerialNumber();
     method public int getSimState();
     method public int getSimState(int);
-    method public java.lang.String getSubscriberId();
-    method public java.lang.String getTypeAllocationCode();
-    method public java.lang.String getTypeAllocationCode(int);
-    method public java.lang.String getVisualVoicemailPackageName();
-    method public java.lang.String getVoiceMailAlphaTag();
-    method public java.lang.String getVoiceMailNumber();
-    method public int getVoiceNetworkType();
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSubscriberId();
+    method public String getTypeAllocationCode();
+    method public String getTypeAllocationCode(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVisualVoicemailPackageName();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getVoiceNetworkType();
     method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
     method public boolean hasCarrierPrivileges();
     method public boolean hasIccCard();
     method public boolean iccCloseLogicalChannel(int);
-    method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
-    method public deprecated android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
-    method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String, int);
-    method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
-    method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+    method public byte[] iccExchangeSimIO(int, int, int, int, int, String);
+    method @Deprecated public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String);
+    method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(String, int);
+    method public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
+    method public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
     method public boolean isConcurrentVoiceAndDataSupported();
-    method public boolean isCurrentEmergencyNumber(java.lang.String);
-    method public boolean isDataEnabled();
-    method public boolean isDataRoamingEnabled();
+    method public boolean isCurrentEmergencyNumber(@NonNull String);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean isDataEnabled();
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isNetworkRoaming();
     method public boolean isSmsCapable();
-    method public deprecated boolean isTtyModeSupported();
+    method @Deprecated public boolean isTtyModeSupported();
     method public boolean isVoiceCapable();
     method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
     method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
-    method public void requestCellInfoUpdate(java.util.concurrent.Executor, android.telephony.TelephonyManager.CellInfoCallback);
-    method public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback);
-    method public void sendDialerSpecialCode(java.lang.String);
-    method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
-    method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
-    method public void sendVisualVoicemailSms(java.lang.String, int, java.lang.String, android.app.PendingIntent);
-    method public void setDataEnabled(boolean);
-    method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
-    method public void setNetworkSelectionModeAutomatic();
-    method public boolean setNetworkSelectionModeManual(java.lang.String, boolean);
-    method public boolean setOperatorBrandOverride(java.lang.String);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback);
+    method public void sendDialerSpecialCode(String);
+    method public String sendEnvelopeWithStatus(String);
+    method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
+    method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
+    method public boolean setLine1NumberForDisplay(String, String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setNetworkSelectionModeAutomatic();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setNetworkSelectionModeManual(String, boolean);
+    method public boolean setOperatorBrandOverride(String);
     method public boolean setPreferredNetworkTypeToGlobal();
     method public boolean setPreferredOpportunisticDataSubscription(int);
     method public void setVisualVoicemailSmsFilterSettings(android.telephony.VisualVoicemailSmsFilterSettings);
-    method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
-    method public deprecated void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
-    method public deprecated void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
+    method public boolean setVoiceMailNumber(String, String);
+    method @Deprecated public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
+    method @Deprecated public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
     method public boolean updateAvailableNetworks(java.util.List<android.telephony.AvailableNetworkInfo>);
-    field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
-    field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
-    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 java.lang.String ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED";
+    field public static final String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
+    field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
+    field public static final String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
+    field public static final String ACTION_SECRET_CODE = "android.telephony.action.SECRET_CODE";
+    field public static final String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
+    field public static final String ACTION_SMS_APP_SERVICE = "android.telephony.action.SMS_APP_SERVICE";
+    field public static final String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED";
+    field public static final String ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED";
     field public static final int APPTYPE_CSIM = 4; // 0x4
     field public static final int APPTYPE_ISIM = 5; // 0x5
     field public static final int APPTYPE_RUIM = 3; // 0x3
@@ -44565,24 +44936,25 @@
     field public static final int DATA_CONNECTING = 1; // 0x1
     field public static final int DATA_DISCONNECTED = 0; // 0x0
     field public static final int DATA_SUSPENDED = 3; // 0x3
-    field public static final java.lang.String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT";
-    field public static final java.lang.String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID";
-    field public static final java.lang.String EXTRA_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME";
-    field public static final java.lang.String EXTRA_HIDE_PUBLIC_SETTINGS = "android.telephony.extra.HIDE_PUBLIC_SETTINGS";
-    field public static final java.lang.String EXTRA_INCOMING_NUMBER = "incoming_number";
-    field public static final java.lang.String EXTRA_IS_REFRESH = "android.telephony.extra.IS_REFRESH";
-    field public static final java.lang.String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
-    field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT";
-    field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telephony.extra.PHONE_ACCOUNT_HANDLE";
-    field public static final java.lang.String EXTRA_PRECISE_CARRIER_ID = "android.telephony.extra.PRECISE_CARRIER_ID";
-    field public static final java.lang.String EXTRA_PRECISE_CARRIER_NAME = "android.telephony.extra.PRECISE_CARRIER_NAME";
-    field public static final java.lang.String EXTRA_STATE = "state";
-    field public static final java.lang.String EXTRA_STATE_IDLE;
-    field public static final java.lang.String EXTRA_STATE_OFFHOOK;
-    field public static final java.lang.String EXTRA_STATE_RINGING;
-    field public static final java.lang.String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
-    field public static final java.lang.String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
-    field public static final java.lang.String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
+    field public static final int DATA_UNKNOWN = -1; // 0xffffffff
+    field public static final String EXTRA_CALL_VOICEMAIL_INTENT = "android.telephony.extra.CALL_VOICEMAIL_INTENT";
+    field public static final String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID";
+    field public static final String EXTRA_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME";
+    field public static final String EXTRA_HIDE_PUBLIC_SETTINGS = "android.telephony.extra.HIDE_PUBLIC_SETTINGS";
+    field public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
+    field public static final String EXTRA_IS_REFRESH = "android.telephony.extra.IS_REFRESH";
+    field public static final String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
+    field public static final String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT";
+    field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telephony.extra.PHONE_ACCOUNT_HANDLE";
+    field public static final String EXTRA_PRECISE_CARRIER_ID = "android.telephony.extra.PRECISE_CARRIER_ID";
+    field public static final String EXTRA_PRECISE_CARRIER_NAME = "android.telephony.extra.PRECISE_CARRIER_NAME";
+    field public static final String EXTRA_STATE = "state";
+    field public static final String EXTRA_STATE_IDLE;
+    field public static final String EXTRA_STATE_OFFHOOK;
+    field public static final String EXTRA_STATE_RINGING;
+    field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
+    field public static final String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
+    field public static final String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
     field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
     field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
     field public static final int NETWORK_TYPE_EDGE = 2; // 0x2
@@ -44620,26 +44992,29 @@
     field public static final int UNKNOWN_CARRIER_ID = -1; // 0xffffffff
     field public static final int USSD_ERROR_SERVICE_UNAVAIL = -2; // 0xfffffffe
     field public static final int USSD_RETURN_FAILURE = -1; // 0xffffffff
-    field public static final java.lang.String VVM_TYPE_CVVM = "vvm_type_cvvm";
-    field public static final java.lang.String VVM_TYPE_OMTP = "vvm_type_omtp";
+    field public static final String VVM_TYPE_CVVM = "vvm_type_cvvm";
+    field public static final String VVM_TYPE_OMTP = "vvm_type_omtp";
   }
 
-  public static abstract class TelephonyManager.CellInfoCallback {
+  public abstract static class TelephonyManager.CellInfoCallback {
     ctor public TelephonyManager.CellInfoCallback();
-    method public abstract void onCellInfo(java.util.List<android.telephony.CellInfo>);
+    method public abstract void onCellInfo(@NonNull java.util.List<android.telephony.CellInfo>);
+    method public void onError(int, @Nullable Throwable);
+    field public static final int ERROR_MODEM_ERROR = 2; // 0x2
+    field public static final int ERROR_TIMEOUT = 1; // 0x1
   }
 
-  public static abstract class TelephonyManager.UssdResponseCallback {
+  public abstract static class TelephonyManager.UssdResponseCallback {
     ctor public TelephonyManager.UssdResponseCallback();
-    method public void onReceiveUssdResponse(android.telephony.TelephonyManager, java.lang.String, java.lang.CharSequence);
-    method public void onReceiveUssdResponseFailed(android.telephony.TelephonyManager, java.lang.String, int);
+    method public void onReceiveUssdResponse(android.telephony.TelephonyManager, String, CharSequence);
+    method public void onReceiveUssdResponseFailed(android.telephony.TelephonyManager, String, int);
   }
 
   public final class TelephonyScanManager {
     ctor public TelephonyScanManager();
   }
 
-  public static abstract class TelephonyScanManager.NetworkScanCallback {
+  public abstract static class TelephonyScanManager.NetworkScanCallback {
     ctor public TelephonyScanManager.NetworkScanCallback();
     method public void onComplete();
     method public void onError(int);
@@ -44649,11 +45024,11 @@
   public abstract class VisualVoicemailService extends android.app.Service {
     ctor public VisualVoicemailService();
     method public android.os.IBinder onBind(android.content.Intent);
-    method public abstract void onCellServiceConnected(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
-    method public abstract void onSimRemoved(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
-    method public abstract void onSmsReceived(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telephony.VisualVoicemailSms);
-    method public abstract void onStopped(android.telephony.VisualVoicemailService.VisualVoicemailTask);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService";
+    method @MainThread public abstract void onCellServiceConnected(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+    method @MainThread public abstract void onSimRemoved(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+    method @MainThread public abstract void onSmsReceived(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telephony.VisualVoicemailSms);
+    method @MainThread public abstract void onStopped(android.telephony.VisualVoicemailService.VisualVoicemailTask);
+    field public static final String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService";
   }
 
   public static class VisualVoicemailService.VisualVoicemailTask {
@@ -44663,9 +45038,9 @@
   public final class VisualVoicemailSms implements android.os.Parcelable {
     method public int describeContents();
     method public android.os.Bundle getFields();
-    method public java.lang.String getMessageBody();
+    method public String getMessageBody();
     method public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
-    method public java.lang.String getPrefix();
+    method public String getPrefix();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSms> CREATOR;
   }
@@ -44676,7 +45051,7 @@
     field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSmsFilterSettings> CREATOR;
     field public static final int DESTINATION_PORT_ANY = -1; // 0xffffffff
     field public static final int DESTINATION_PORT_DATA_SMS = -2; // 0xfffffffe
-    field public final java.lang.String clientPrefix;
+    field public final String clientPrefix;
     field public final int destinationPort;
     field public final java.util.List<java.lang.String> originatingNumbers;
   }
@@ -44684,7 +45059,7 @@
   public static class VisualVoicemailSmsFilterSettings.Builder {
     ctor public VisualVoicemailSmsFilterSettings.Builder();
     method public android.telephony.VisualVoicemailSmsFilterSettings build();
-    method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setClientPrefix(java.lang.String);
+    method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setClientPrefix(String);
     method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setDestinationPort(int);
     method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setOriginatingNumbers(java.util.List<java.lang.String>);
   }
@@ -44714,28 +45089,28 @@
 
   public class ApnSetting implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getApnName();
+    method public String getApnName();
     method public int getApnTypeBitmask();
     method public int getAuthType();
     method public int getCarrierId();
-    method public java.lang.String getEntryName();
+    method public String getEntryName();
     method public int getId();
-    method public deprecated java.net.InetAddress getMmsProxyAddress();
-    method public java.lang.String getMmsProxyAddressAsString();
+    method @Deprecated public java.net.InetAddress getMmsProxyAddress();
+    method public String getMmsProxyAddressAsString();
     method public int getMmsProxyPort();
     method public android.net.Uri getMmsc();
     method public int getMvnoType();
     method public int getNetworkTypeBitmask();
-    method public java.lang.String getOperatorNumeric();
-    method public java.lang.String getPassword();
+    method public String getOperatorNumeric();
+    method public String getPassword();
     method public int getProtocol();
-    method public deprecated java.net.InetAddress getProxyAddress();
-    method public java.lang.String getProxyAddressAsString();
+    method @Deprecated public java.net.InetAddress getProxyAddress();
+    method public String getProxyAddressAsString();
     method public int getProxyPort();
     method public int getRoamingProtocol();
-    method public java.lang.String getUser();
+    method public String getUser();
     method public boolean isEnabled();
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int AUTH_TYPE_CHAP = 2; // 0x2
     field public static final int AUTH_TYPE_NONE = 0; // 0x0
     field public static final int AUTH_TYPE_PAP = 1; // 0x1
@@ -44748,7 +45123,9 @@
     field public static final int PROTOCOL_IP = 0; // 0x0
     field public static final int PROTOCOL_IPV4V6 = 2; // 0x2
     field public static final int PROTOCOL_IPV6 = 1; // 0x1
+    field public static final int PROTOCOL_NON_IP = 4; // 0x4
     field public static final int PROTOCOL_PPP = 3; // 0x3
+    field public static final int PROTOCOL_UNSTRUCTURED = 5; // 0x5
     field public static final int TYPE_CBS = 128; // 0x80
     field public static final int TYPE_DEFAULT = 17; // 0x11
     field public static final int TYPE_DUN = 8; // 0x8
@@ -44764,46 +45141,51 @@
   public static class ApnSetting.Builder {
     ctor public ApnSetting.Builder();
     method public android.telephony.data.ApnSetting build();
-    method public android.telephony.data.ApnSetting.Builder setApnName(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setApnName(String);
     method public android.telephony.data.ApnSetting.Builder setApnTypeBitmask(int);
     method public android.telephony.data.ApnSetting.Builder setAuthType(int);
     method public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean);
     method public android.telephony.data.ApnSetting.Builder setCarrierId(int);
-    method public android.telephony.data.ApnSetting.Builder setEntryName(java.lang.String);
-    method public deprecated android.telephony.data.ApnSetting.Builder setMmsProxyAddress(java.net.InetAddress);
-    method public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setEntryName(String);
+    method @Deprecated public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(java.net.InetAddress);
+    method public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(String);
     method public android.telephony.data.ApnSetting.Builder setMmsProxyPort(int);
     method public android.telephony.data.ApnSetting.Builder setMmsc(android.net.Uri);
     method public android.telephony.data.ApnSetting.Builder setMvnoType(int);
     method public android.telephony.data.ApnSetting.Builder setNetworkTypeBitmask(int);
-    method public android.telephony.data.ApnSetting.Builder setOperatorNumeric(java.lang.String);
-    method public android.telephony.data.ApnSetting.Builder setPassword(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setOperatorNumeric(String);
+    method public android.telephony.data.ApnSetting.Builder setPassword(String);
     method public android.telephony.data.ApnSetting.Builder setProtocol(int);
-    method public deprecated android.telephony.data.ApnSetting.Builder setProxyAddress(java.net.InetAddress);
-    method public android.telephony.data.ApnSetting.Builder setProxyAddress(java.lang.String);
+    method @Deprecated public android.telephony.data.ApnSetting.Builder setProxyAddress(java.net.InetAddress);
+    method public android.telephony.data.ApnSetting.Builder setProxyAddress(String);
     method public android.telephony.data.ApnSetting.Builder setProxyPort(int);
     method public android.telephony.data.ApnSetting.Builder setRoamingProtocol(int);
-    method public android.telephony.data.ApnSetting.Builder setUser(java.lang.String);
+    method public android.telephony.data.ApnSetting.Builder setUser(String);
   }
 
 }
 
 package android.telephony.emergency {
 
-  public final class EmergencyNumber implements java.lang.Comparable android.os.Parcelable {
-    method public int compareTo(android.telephony.emergency.EmergencyNumber);
+  public final class EmergencyNumber implements java.lang.Comparable<android.telephony.emergency.EmergencyNumber> android.os.Parcelable {
+    method public int compareTo(@NonNull android.telephony.emergency.EmergencyNumber);
     method public int describeContents();
-    method public java.lang.String getCountryIso();
+    method public String getCountryIso();
+    method public int getEmergencyCallRouting();
     method public int getEmergencyNumberSourceBitmask();
     method public java.util.List<java.lang.Integer> getEmergencyNumberSources();
     method public java.util.List<java.lang.Integer> getEmergencyServiceCategories();
     method public int getEmergencyServiceCategoryBitmask();
-    method public java.lang.String getMnc();
-    method public java.lang.String getNumber();
+    method @NonNull public java.util.List<java.lang.String> getEmergencyUrns();
+    method public String getMnc();
+    method public String getNumber();
     method public boolean isFromSources(int);
     method public boolean isInEmergencyServiceCategories(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.emergency.EmergencyNumber> CREATOR;
+    field public static final int EMERGENCY_CALL_ROUTING_EMERGENCY = 1; // 0x1
+    field public static final int EMERGENCY_CALL_ROUTING_NORMAL = 2; // 0x2
+    field public static final int EMERGENCY_CALL_ROUTING_UNKNOWN = 0; // 0x0
     field public static final int EMERGENCY_NUMBER_SOURCE_DATABASE = 16; // 0x10
     field public static final int EMERGENCY_NUMBER_SOURCE_DEFAULT = 8; // 0x8
     field public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = 4; // 0x4
@@ -44825,37 +45207,39 @@
 
   public final class DownloadableSubscription implements android.os.Parcelable {
     method public int describeContents();
-    method public static android.telephony.euicc.DownloadableSubscription forActivationCode(java.lang.String);
-    method public java.lang.String getConfirmationCode();
-    method public java.lang.String getEncodedActivationCode();
+    method public static android.telephony.euicc.DownloadableSubscription forActivationCode(String);
+    method @Nullable public String getConfirmationCode();
+    method @Nullable public String getEncodedActivationCode();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.euicc.DownloadableSubscription> CREATOR;
   }
 
   public final class EuiccInfo implements android.os.Parcelable {
-    ctor public EuiccInfo(java.lang.String);
+    ctor public EuiccInfo(@Nullable String);
     method public int describeContents();
-    method public java.lang.String getOsVersion();
+    method @Nullable public String getOsVersion();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.euicc.EuiccInfo> CREATOR;
   }
 
   public class EuiccManager {
-    method public void deleteSubscription(int, android.app.PendingIntent);
-    method public void downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent);
-    method public java.lang.String getEid();
-    method public android.telephony.euicc.EuiccInfo getEuiccInfo();
+    method public android.telephony.euicc.EuiccManager createForCardId(int);
+    method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void deleteSubscription(int, android.app.PendingIntent);
+    method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent);
+    method @Nullable public String getEid();
+    method @Nullable public android.telephony.euicc.EuiccInfo getEuiccInfo();
     method public boolean isEnabled();
     method public void startResolutionActivity(android.app.Activity, int, android.content.Intent, android.app.PendingIntent) throws android.content.IntentSender.SendIntentException;
-    method public void switchToSubscription(int, android.app.PendingIntent);
-    field public static final java.lang.String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
-    field public static final java.lang.String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
+    method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, android.app.PendingIntent);
+    method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void updateSubscriptionNickname(int, String, android.app.PendingIntent);
+    field public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
+    field public static final String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
     field public static final int EMBEDDED_SUBSCRIPTION_RESULT_ERROR = 2; // 0x2
     field public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0; // 0x0
     field public static final int EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR = 1; // 0x1
-    field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE";
-    field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
-    field public static final java.lang.String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon";
+    field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE";
+    field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
+    field public static final String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon";
   }
 
 }
@@ -44873,79 +45257,76 @@
     method public void setStateInvalid();
   }
 
-  public final deprecated class SmsManager {
-    method public deprecated java.util.ArrayList<java.lang.String> divideMessage(java.lang.String);
-    method public static deprecated android.telephony.gsm.SmsManager getDefault();
-    method public deprecated void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
-    method public deprecated void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
-    method public deprecated void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
-    field public static final deprecated int RESULT_ERROR_GENERIC_FAILURE = 1; // 0x1
-    field public static final deprecated int RESULT_ERROR_NO_SERVICE = 4; // 0x4
-    field public static final deprecated int RESULT_ERROR_NULL_PDU = 3; // 0x3
-    field public static final deprecated int RESULT_ERROR_RADIO_OFF = 2; // 0x2
-    field public static final deprecated int STATUS_ON_SIM_FREE = 0; // 0x0
-    field public static final deprecated int STATUS_ON_SIM_READ = 1; // 0x1
-    field public static final deprecated int STATUS_ON_SIM_SENT = 5; // 0x5
-    field public static final deprecated int STATUS_ON_SIM_UNREAD = 3; // 0x3
-    field public static final deprecated int STATUS_ON_SIM_UNSENT = 7; // 0x7
+  @Deprecated public final class SmsManager {
+    method @Deprecated public java.util.ArrayList<java.lang.String> divideMessage(String);
+    method @Deprecated public static android.telephony.gsm.SmsManager getDefault();
+    method @Deprecated public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
+    method @Deprecated public void sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
+    method @Deprecated public void sendTextMessage(String, String, String, android.app.PendingIntent, android.app.PendingIntent);
+    field @Deprecated public static final int RESULT_ERROR_GENERIC_FAILURE = 1; // 0x1
+    field @Deprecated public static final int RESULT_ERROR_NO_SERVICE = 4; // 0x4
+    field @Deprecated public static final int RESULT_ERROR_NULL_PDU = 3; // 0x3
+    field @Deprecated public static final int RESULT_ERROR_RADIO_OFF = 2; // 0x2
+    field @Deprecated public static final int STATUS_ON_SIM_FREE = 0; // 0x0
+    field @Deprecated public static final int STATUS_ON_SIM_READ = 1; // 0x1
+    field @Deprecated public static final int STATUS_ON_SIM_SENT = 5; // 0x5
+    field @Deprecated public static final int STATUS_ON_SIM_UNREAD = 3; // 0x3
+    field @Deprecated public static final int STATUS_ON_SIM_UNSENT = 7; // 0x7
   }
 
-  public deprecated class SmsMessage {
-    ctor public deprecated SmsMessage();
-    method public static deprecated int[] calculateLength(java.lang.CharSequence, boolean);
-    method public static deprecated int[] calculateLength(java.lang.String, boolean);
-    method public static deprecated android.telephony.gsm.SmsMessage createFromPdu(byte[]);
-    method public deprecated java.lang.String getDisplayMessageBody();
-    method public deprecated java.lang.String getDisplayOriginatingAddress();
-    method public deprecated java.lang.String getEmailBody();
-    method public deprecated java.lang.String getEmailFrom();
-    method public deprecated int getIndexOnSim();
-    method public deprecated java.lang.String getMessageBody();
-    method public deprecated android.telephony.gsm.SmsMessage.MessageClass getMessageClass();
-    method public deprecated java.lang.String getOriginatingAddress();
-    method public deprecated byte[] getPdu();
-    method public deprecated int getProtocolIdentifier();
-    method public deprecated java.lang.String getPseudoSubject();
-    method public deprecated java.lang.String getServiceCenterAddress();
-    method public deprecated int getStatus();
-    method public deprecated int getStatusOnSim();
-    method public static deprecated android.telephony.gsm.SmsMessage.SubmitPdu getSubmitPdu(java.lang.String, java.lang.String, java.lang.String, boolean);
-    method public static deprecated android.telephony.gsm.SmsMessage.SubmitPdu getSubmitPdu(java.lang.String, java.lang.String, short, byte[], boolean);
-    method public static deprecated int getTPLayerLengthForPDU(java.lang.String);
-    method public deprecated long getTimestampMillis();
-    method public deprecated byte[] getUserData();
-    method public deprecated boolean isCphsMwiMessage();
-    method public deprecated boolean isEmail();
-    method public deprecated boolean isMWIClearMessage();
-    method public deprecated boolean isMWISetMessage();
-    method public deprecated boolean isMwiDontStore();
-    method public deprecated boolean isReplace();
-    method public deprecated boolean isReplyPathPresent();
-    method public deprecated boolean isStatusReportMessage();
-    field public static final deprecated int ENCODING_16BIT = 3; // 0x3
-    field public static final deprecated int ENCODING_7BIT = 1; // 0x1
-    field public static final deprecated int ENCODING_8BIT = 2; // 0x2
-    field public static final deprecated int ENCODING_UNKNOWN = 0; // 0x0
-    field public static final deprecated int MAX_USER_DATA_BYTES = 140; // 0x8c
-    field public static final deprecated int MAX_USER_DATA_SEPTETS = 160; // 0xa0
-    field public static final deprecated int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; // 0x99
+  @Deprecated public class SmsMessage {
+    ctor @Deprecated public SmsMessage();
+    method @Deprecated public static int[] calculateLength(CharSequence, boolean);
+    method @Deprecated public static int[] calculateLength(String, boolean);
+    method @Deprecated public static android.telephony.gsm.SmsMessage createFromPdu(byte[]);
+    method @Deprecated public String getDisplayMessageBody();
+    method @Deprecated public String getDisplayOriginatingAddress();
+    method @Deprecated public String getEmailBody();
+    method @Deprecated public String getEmailFrom();
+    method @Deprecated public int getIndexOnSim();
+    method @Deprecated public String getMessageBody();
+    method @Deprecated public android.telephony.gsm.SmsMessage.MessageClass getMessageClass();
+    method @Deprecated public String getOriginatingAddress();
+    method @Deprecated public byte[] getPdu();
+    method @Deprecated public int getProtocolIdentifier();
+    method @Deprecated public String getPseudoSubject();
+    method @Deprecated public String getServiceCenterAddress();
+    method @Deprecated public int getStatus();
+    method @Deprecated public int getStatusOnSim();
+    method @Deprecated public static android.telephony.gsm.SmsMessage.SubmitPdu getSubmitPdu(String, String, String, boolean);
+    method @Deprecated public static android.telephony.gsm.SmsMessage.SubmitPdu getSubmitPdu(String, String, short, byte[], boolean);
+    method @Deprecated public static int getTPLayerLengthForPDU(String);
+    method @Deprecated public long getTimestampMillis();
+    method @Deprecated public byte[] getUserData();
+    method @Deprecated public boolean isCphsMwiMessage();
+    method @Deprecated public boolean isEmail();
+    method @Deprecated public boolean isMWIClearMessage();
+    method @Deprecated public boolean isMWISetMessage();
+    method @Deprecated public boolean isMwiDontStore();
+    method @Deprecated public boolean isReplace();
+    method @Deprecated public boolean isReplyPathPresent();
+    method @Deprecated public boolean isStatusReportMessage();
+    field @Deprecated public static final int ENCODING_16BIT = 3; // 0x3
+    field @Deprecated public static final int ENCODING_7BIT = 1; // 0x1
+    field @Deprecated public static final int ENCODING_8BIT = 2; // 0x2
+    field @Deprecated public static final int ENCODING_UNKNOWN = 0; // 0x0
+    field @Deprecated public static final int MAX_USER_DATA_BYTES = 140; // 0x8c
+    field @Deprecated public static final int MAX_USER_DATA_SEPTETS = 160; // 0xa0
+    field @Deprecated public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; // 0x99
   }
 
-  public static final deprecated class SmsMessage.MessageClass extends java.lang.Enum {
-    method public static android.telephony.gsm.SmsMessage.MessageClass valueOf(java.lang.String);
-    method public static final android.telephony.gsm.SmsMessage.MessageClass[] values();
-    enum_constant public static final android.telephony.gsm.SmsMessage.MessageClass CLASS_0;
-    enum_constant public static final android.telephony.gsm.SmsMessage.MessageClass CLASS_1;
-    enum_constant public static final android.telephony.gsm.SmsMessage.MessageClass CLASS_2;
-    enum_constant public static final android.telephony.gsm.SmsMessage.MessageClass CLASS_3;
-    enum_constant public static final android.telephony.gsm.SmsMessage.MessageClass UNKNOWN;
+  @Deprecated public enum SmsMessage.MessageClass {
+    enum_constant @Deprecated public static final android.telephony.gsm.SmsMessage.MessageClass CLASS_0;
+    enum_constant @Deprecated public static final android.telephony.gsm.SmsMessage.MessageClass CLASS_1;
+    enum_constant @Deprecated public static final android.telephony.gsm.SmsMessage.MessageClass CLASS_2;
+    enum_constant @Deprecated public static final android.telephony.gsm.SmsMessage.MessageClass CLASS_3;
+    enum_constant @Deprecated public static final android.telephony.gsm.SmsMessage.MessageClass UNKNOWN;
   }
 
-  public static deprecated class SmsMessage.SubmitPdu {
-    ctor public deprecated SmsMessage.SubmitPdu();
-    method public deprecated java.lang.String toString();
-    field public deprecated byte[] encodedMessage;
-    field public deprecated byte[] encodedScAddress;
+  @Deprecated public static class SmsMessage.SubmitPdu {
+    ctor @Deprecated public SmsMessage.SubmitPdu();
+    field @Deprecated public byte[] encodedMessage;
+    field @Deprecated public byte[] encodedScAddress;
   }
 
 }
@@ -44960,7 +45341,7 @@
   public final class DownloadRequest implements android.os.Parcelable {
     method public int describeContents();
     method public android.net.Uri getDestinationUri();
-    method public java.lang.String getFileServiceId();
+    method public String getFileServiceId();
     method public static int getMaxAppIntentSize();
     method public static int getMaxDestinationUriSize();
     method public android.net.Uri getSourceUri();
@@ -44971,7 +45352,7 @@
   }
 
   public static class DownloadRequest.Builder {
-    ctor public DownloadRequest.Builder(android.net.Uri, android.net.Uri);
+    ctor public DownloadRequest.Builder(@NonNull android.net.Uri, @NonNull android.net.Uri);
     method public android.telephony.mbms.DownloadRequest build();
     method public static android.telephony.mbms.DownloadRequest.Builder fromDownloadRequest(android.telephony.mbms.DownloadRequest);
     method public static android.telephony.mbms.DownloadRequest.Builder fromSerializedRequest(byte[]);
@@ -44987,7 +45368,7 @@
 
   public final class FileInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getMimeType();
+    method public String getMimeType();
     method public android.net.Uri getUri();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.mbms.FileInfo> CREATOR;
@@ -45003,7 +45384,7 @@
   public class GroupCall implements java.lang.AutoCloseable {
     method public void close();
     method public long getTmgi();
-    method public void updateGroupCall(java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>);
+    method public void updateGroupCall(@NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>);
     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
@@ -45015,10 +45396,10 @@
     field public static final int STATE_STOPPED = 1; // 0x1
   }
 
-  public abstract interface GroupCallCallback {
-    method public abstract void onBroadcastSignalStrengthUpdated(int);
-    method public abstract void onError(int, java.lang.String);
-    method public abstract void onGroupCallStateChanged(int, int);
+  public interface GroupCallCallback {
+    method public void onBroadcastSignalStrengthUpdated(@IntRange(from=0xffffffff, to=4) int);
+    method public void onError(int, @Nullable String);
+    method public void onGroupCallStateChanged(int, int);
     field public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; // 0xffffffff
   }
 
@@ -45029,7 +45410,7 @@
 
   public class MbmsDownloadSessionCallback {
     ctor public MbmsDownloadSessionCallback();
-    method public void onError(int, java.lang.String);
+    method public void onError(int, String);
     method public void onFileServicesUpdated(java.util.List<android.telephony.mbms.FileServiceInfo>);
     method public void onMiddlewareReady();
   }
@@ -45075,26 +45456,26 @@
     field public static final int ERROR_UNABLE_TO_START_SERVICE = 302; // 0x12e
   }
 
-  public abstract interface MbmsGroupCallSessionCallback {
-    method public abstract void onAvailableSaisUpdated(java.util.List<java.lang.Integer>, java.util.List<java.util.List<java.lang.Integer>>);
-    method public abstract void onError(int, java.lang.String);
-    method public abstract void onMiddlewareReady();
-    method public abstract void onServiceInterfaceAvailable(java.lang.String, int);
+  public interface MbmsGroupCallSessionCallback {
+    method public void onAvailableSaisUpdated(@NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.util.List<java.lang.Integer>>);
+    method public void onError(int, @Nullable String);
+    method public void onMiddlewareReady();
+    method public void onServiceInterfaceAvailable(@NonNull String, int);
   }
 
   public class MbmsStreamingSessionCallback {
     ctor public MbmsStreamingSessionCallback();
-    method public void onError(int, java.lang.String);
+    method public void onError(int, @Nullable String);
     method public void onMiddlewareReady();
     method public void onStreamingServicesUpdated(java.util.List<android.telephony.mbms.StreamingServiceInfo>);
   }
 
   public class ServiceInfo {
     method public java.util.List<java.util.Locale> getLocales();
-    method public java.lang.CharSequence getNameForLocale(java.util.Locale);
-    method public java.util.Set<java.util.Locale> getNamedContentLocales();
-    method public java.lang.String getServiceClassName();
-    method public java.lang.String getServiceId();
+    method @NonNull public CharSequence getNameForLocale(@NonNull java.util.Locale);
+    method @NonNull public java.util.Set<java.util.Locale> getNamedContentLocales();
+    method public String getServiceClassName();
+    method public String getServiceId();
     method public java.util.Date getSessionEndTime();
     method public java.util.Date getSessionStartTime();
   }
@@ -45102,7 +45483,7 @@
   public class StreamingService implements java.lang.AutoCloseable {
     method public void close();
     method public android.telephony.mbms.StreamingServiceInfo getInfo();
-    method public android.net.Uri getPlaybackUri();
+    method @Nullable public android.net.Uri getPlaybackUri();
     field public static final int BROADCAST_METHOD = 1; // 0x1
     field public static final int REASON_BY_USER_REQUEST = 1; // 0x1
     field public static final int REASON_END_OF_SESSION = 2; // 0x2
@@ -45120,7 +45501,7 @@
   public class StreamingServiceCallback {
     ctor public StreamingServiceCallback();
     method public void onBroadcastSignalStrengthUpdated(int);
-    method public void onError(int, java.lang.String);
+    method public void onError(int, @Nullable String);
     method public void onMediaDescriptionUpdated();
     method public void onStreamMethodUpdated(int);
     method public void onStreamStateUpdated(int, int);
@@ -45141,37 +45522,37 @@
     method public char charAt(int);
     method public void getChars(int, int, char[], int);
     method public int length();
-    method public static android.text.AlteredCharSequence make(java.lang.CharSequence, char[], int, int);
-    method public java.lang.CharSequence subSequence(int, int);
+    method public static android.text.AlteredCharSequence make(CharSequence, char[], int, int);
+    method public CharSequence subSequence(int, int);
   }
 
-  public deprecated class AndroidCharacter {
-    ctor public AndroidCharacter();
-    method public static void getDirectionalities(char[], byte[], int);
-    method public static int getEastAsianWidth(char);
-    method public static void getEastAsianWidths(char[], int, int, byte[]);
-    method public static char getMirror(char);
-    method public static boolean mirror(char[], int, int);
-    field public static final int EAST_ASIAN_WIDTH_AMBIGUOUS = 1; // 0x1
-    field public static final int EAST_ASIAN_WIDTH_FULL_WIDTH = 3; // 0x3
-    field public static final int EAST_ASIAN_WIDTH_HALF_WIDTH = 2; // 0x2
-    field public static final int EAST_ASIAN_WIDTH_NARROW = 4; // 0x4
-    field public static final int EAST_ASIAN_WIDTH_NEUTRAL = 0; // 0x0
-    field public static final int EAST_ASIAN_WIDTH_WIDE = 5; // 0x5
+  @Deprecated public class AndroidCharacter {
+    ctor @Deprecated public AndroidCharacter();
+    method @Deprecated public static void getDirectionalities(char[], byte[], int);
+    method @Deprecated public static int getEastAsianWidth(char);
+    method @Deprecated public static void getEastAsianWidths(char[], int, int, byte[]);
+    method @Deprecated public static char getMirror(char);
+    method @Deprecated public static boolean mirror(char[], int, int);
+    field @Deprecated public static final int EAST_ASIAN_WIDTH_AMBIGUOUS = 1; // 0x1
+    field @Deprecated public static final int EAST_ASIAN_WIDTH_FULL_WIDTH = 3; // 0x3
+    field @Deprecated public static final int EAST_ASIAN_WIDTH_HALF_WIDTH = 2; // 0x2
+    field @Deprecated public static final int EAST_ASIAN_WIDTH_NARROW = 4; // 0x4
+    field @Deprecated public static final int EAST_ASIAN_WIDTH_NEUTRAL = 0; // 0x0
+    field @Deprecated public static final int EAST_ASIAN_WIDTH_WIDE = 5; // 0x5
   }
 
   public class Annotation implements android.text.ParcelableSpan {
-    ctor public Annotation(java.lang.String, java.lang.String);
+    ctor public Annotation(String, String);
     ctor public Annotation(android.os.Parcel);
     method public int describeContents();
-    method public java.lang.String getKey();
+    method public String getKey();
     method public int getSpanTypeId();
-    method public java.lang.String getValue();
+    method public String getValue();
     method public void writeToParcel(android.os.Parcel, int);
   }
 
   public class AutoText {
-    method public static java.lang.String get(java.lang.CharSequence, int, int, android.view.View);
+    method public static String get(CharSequence, int, int, android.view.View);
     method public static int getSize(android.view.View);
   }
 
@@ -45180,17 +45561,17 @@
     method public static android.text.BidiFormatter getInstance(boolean);
     method public static android.text.BidiFormatter getInstance(java.util.Locale);
     method public boolean getStereoReset();
-    method public boolean isRtl(java.lang.String);
-    method public boolean isRtl(java.lang.CharSequence);
+    method public boolean isRtl(String);
+    method public boolean isRtl(CharSequence);
     method public boolean isRtlContext();
-    method public java.lang.String unicodeWrap(java.lang.String, android.text.TextDirectionHeuristic, boolean);
-    method public java.lang.CharSequence unicodeWrap(java.lang.CharSequence, android.text.TextDirectionHeuristic, boolean);
-    method public java.lang.String unicodeWrap(java.lang.String, android.text.TextDirectionHeuristic);
-    method public java.lang.CharSequence unicodeWrap(java.lang.CharSequence, android.text.TextDirectionHeuristic);
-    method public java.lang.String unicodeWrap(java.lang.String, boolean);
-    method public java.lang.CharSequence unicodeWrap(java.lang.CharSequence, boolean);
-    method public java.lang.String unicodeWrap(java.lang.String);
-    method public java.lang.CharSequence unicodeWrap(java.lang.CharSequence);
+    method @Nullable public String unicodeWrap(@Nullable String, android.text.TextDirectionHeuristic, boolean);
+    method @Nullable public CharSequence unicodeWrap(@Nullable CharSequence, android.text.TextDirectionHeuristic, boolean);
+    method public String unicodeWrap(String, android.text.TextDirectionHeuristic);
+    method public CharSequence unicodeWrap(CharSequence, android.text.TextDirectionHeuristic);
+    method public String unicodeWrap(String, boolean);
+    method public CharSequence unicodeWrap(CharSequence, boolean);
+    method public String unicodeWrap(String);
+    method public CharSequence unicodeWrap(CharSequence);
   }
 
   public static final class BidiFormatter.Builder {
@@ -45203,8 +45584,8 @@
   }
 
   public class BoringLayout extends android.text.Layout implements android.text.TextUtils.EllipsizeCallback {
-    ctor public BoringLayout(java.lang.CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean);
-    ctor public BoringLayout(java.lang.CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean, android.text.TextUtils.TruncateAt, int);
+    ctor public BoringLayout(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean);
+    ctor public BoringLayout(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean, android.text.TextUtils.TruncateAt, int);
     method public void ellipsized(int, int);
     method public int getBottomPadding();
     method public int getEllipsisCount(int);
@@ -45217,12 +45598,12 @@
     method public int getLineTop(int);
     method public int getParagraphDirection(int);
     method public int getTopPadding();
-    method public static android.text.BoringLayout.Metrics isBoring(java.lang.CharSequence, android.text.TextPaint);
-    method public static android.text.BoringLayout.Metrics isBoring(java.lang.CharSequence, android.text.TextPaint, android.text.BoringLayout.Metrics);
-    method public static android.text.BoringLayout make(java.lang.CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean);
-    method public static android.text.BoringLayout make(java.lang.CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean, android.text.TextUtils.TruncateAt, int);
-    method public android.text.BoringLayout replaceOrMake(java.lang.CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean);
-    method public android.text.BoringLayout replaceOrMake(java.lang.CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean, android.text.TextUtils.TruncateAt, int);
+    method public static android.text.BoringLayout.Metrics isBoring(CharSequence, android.text.TextPaint);
+    method public static android.text.BoringLayout.Metrics isBoring(CharSequence, android.text.TextPaint, android.text.BoringLayout.Metrics);
+    method public static android.text.BoringLayout make(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean);
+    method public static android.text.BoringLayout make(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean, android.text.TextUtils.TruncateAt, int);
+    method public android.text.BoringLayout replaceOrMake(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean);
+    method public android.text.BoringLayout replaceOrMake(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean, android.text.TextUtils.TruncateAt, int);
   }
 
   public static class BoringLayout.Metrics extends android.graphics.Paint.FontMetricsInt {
@@ -45230,17 +45611,17 @@
     field public int width;
   }
 
-  public abstract deprecated class ClipboardManager {
-    ctor public ClipboardManager();
-    method public abstract java.lang.CharSequence getText();
-    method public abstract boolean hasText();
-    method public abstract void setText(java.lang.CharSequence);
+  @Deprecated public abstract class ClipboardManager {
+    ctor @Deprecated public ClipboardManager();
+    method @Deprecated public abstract CharSequence getText();
+    method @Deprecated public abstract boolean hasText();
+    method @Deprecated public abstract void setText(CharSequence);
   }
 
   public class DynamicLayout extends android.text.Layout {
-    ctor public deprecated DynamicLayout(java.lang.CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, boolean);
-    ctor public deprecated DynamicLayout(java.lang.CharSequence, java.lang.CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, boolean);
-    ctor public deprecated DynamicLayout(java.lang.CharSequence, java.lang.CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, boolean, android.text.TextUtils.TruncateAt, int);
+    ctor @Deprecated public DynamicLayout(@NonNull CharSequence, @NonNull android.text.TextPaint, @IntRange(from=0) int, @NonNull android.text.Layout.Alignment, @FloatRange(from=0.0) float, float, boolean);
+    ctor @Deprecated public DynamicLayout(@NonNull CharSequence, @NonNull CharSequence, @NonNull android.text.TextPaint, @IntRange(from=0) int, @NonNull android.text.Layout.Alignment, @FloatRange(from=0.0) float, float, boolean);
+    ctor @Deprecated public DynamicLayout(@NonNull CharSequence, @NonNull CharSequence, @NonNull android.text.TextPaint, @IntRange(from=0) int, @NonNull android.text.Layout.Alignment, @FloatRange(from=0.0) float, float, boolean, @Nullable android.text.TextUtils.TruncateAt, @IntRange(from=0) int);
     method public int getBottomPadding();
     method public int getEllipsisCount(int);
     method public int getEllipsisStart(int);
@@ -45255,54 +45636,54 @@
   }
 
   public static final class DynamicLayout.Builder {
-    method public android.text.DynamicLayout build();
-    method public static android.text.DynamicLayout.Builder obtain(java.lang.CharSequence, android.text.TextPaint, int);
-    method public android.text.DynamicLayout.Builder setAlignment(android.text.Layout.Alignment);
-    method public android.text.DynamicLayout.Builder setBreakStrategy(int);
-    method public android.text.DynamicLayout.Builder setDisplayText(java.lang.CharSequence);
-    method public android.text.DynamicLayout.Builder setEllipsize(android.text.TextUtils.TruncateAt);
-    method public android.text.DynamicLayout.Builder setEllipsizedWidth(int);
-    method public android.text.DynamicLayout.Builder setHyphenationFrequency(int);
-    method public android.text.DynamicLayout.Builder setIncludePad(boolean);
-    method public android.text.DynamicLayout.Builder setJustificationMode(int);
-    method public android.text.DynamicLayout.Builder setLineSpacing(float, float);
-    method public android.text.DynamicLayout.Builder setTextDirection(android.text.TextDirectionHeuristic);
-    method public android.text.DynamicLayout.Builder setUseLineSpacingFromFallbacks(boolean);
+    method @NonNull public android.text.DynamicLayout build();
+    method @NonNull public static android.text.DynamicLayout.Builder obtain(@NonNull CharSequence, @NonNull android.text.TextPaint, @IntRange(from=0) int);
+    method @NonNull public android.text.DynamicLayout.Builder setAlignment(@NonNull android.text.Layout.Alignment);
+    method @NonNull public android.text.DynamicLayout.Builder setBreakStrategy(int);
+    method @NonNull public android.text.DynamicLayout.Builder setDisplayText(@NonNull CharSequence);
+    method public android.text.DynamicLayout.Builder setEllipsize(@Nullable android.text.TextUtils.TruncateAt);
+    method @NonNull public android.text.DynamicLayout.Builder setEllipsizedWidth(@IntRange(from=0) int);
+    method @NonNull public android.text.DynamicLayout.Builder setHyphenationFrequency(int);
+    method @NonNull public android.text.DynamicLayout.Builder setIncludePad(boolean);
+    method @NonNull public android.text.DynamicLayout.Builder setJustificationMode(int);
+    method @NonNull public android.text.DynamicLayout.Builder setLineSpacing(float, @FloatRange(from=0.0) float);
+    method @NonNull public android.text.DynamicLayout.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic);
+    method @NonNull public android.text.DynamicLayout.Builder setUseLineSpacingFromFallbacks(boolean);
   }
 
-  public abstract interface Editable implements java.lang.Appendable java.lang.CharSequence android.text.GetChars android.text.Spannable {
-    method public abstract android.text.Editable append(java.lang.CharSequence);
-    method public abstract android.text.Editable append(java.lang.CharSequence, int, int);
-    method public abstract android.text.Editable append(char);
-    method public abstract void clear();
-    method public abstract void clearSpans();
-    method public abstract android.text.Editable delete(int, int);
-    method public abstract android.text.InputFilter[] getFilters();
-    method public abstract android.text.Editable insert(int, java.lang.CharSequence, int, int);
-    method public abstract android.text.Editable insert(int, java.lang.CharSequence);
-    method public abstract android.text.Editable replace(int, int, java.lang.CharSequence, int, int);
-    method public abstract android.text.Editable replace(int, int, java.lang.CharSequence);
-    method public abstract void setFilters(android.text.InputFilter[]);
+  public interface Editable extends java.lang.CharSequence java.lang.Appendable android.text.GetChars android.text.Spannable {
+    method public android.text.Editable append(CharSequence);
+    method public android.text.Editable append(CharSequence, int, int);
+    method public android.text.Editable append(char);
+    method public void clear();
+    method public void clearSpans();
+    method public android.text.Editable delete(int, int);
+    method public android.text.InputFilter[] getFilters();
+    method public android.text.Editable insert(int, CharSequence, int, int);
+    method public android.text.Editable insert(int, CharSequence);
+    method public android.text.Editable replace(int, int, CharSequence, int, int);
+    method public android.text.Editable replace(int, int, CharSequence);
+    method public void setFilters(android.text.InputFilter[]);
   }
 
   public static class Editable.Factory {
     ctor public Editable.Factory();
     method public static android.text.Editable.Factory getInstance();
-    method public android.text.Editable newEditable(java.lang.CharSequence);
+    method public android.text.Editable newEditable(CharSequence);
   }
 
-  public abstract interface GetChars implements java.lang.CharSequence {
-    method public abstract void getChars(int, int, char[], int);
+  public interface GetChars extends java.lang.CharSequence {
+    method public void getChars(int, int, char[], int);
   }
 
   public class Html {
-    method public static java.lang.String escapeHtml(java.lang.CharSequence);
-    method public static deprecated android.text.Spanned fromHtml(java.lang.String);
-    method public static android.text.Spanned fromHtml(java.lang.String, int);
-    method public static deprecated android.text.Spanned fromHtml(java.lang.String, android.text.Html.ImageGetter, android.text.Html.TagHandler);
-    method public static android.text.Spanned fromHtml(java.lang.String, int, android.text.Html.ImageGetter, android.text.Html.TagHandler);
-    method public static deprecated java.lang.String toHtml(android.text.Spanned);
-    method public static java.lang.String toHtml(android.text.Spanned, int);
+    method public static String escapeHtml(CharSequence);
+    method @Deprecated public static android.text.Spanned fromHtml(String);
+    method public static android.text.Spanned fromHtml(String, int);
+    method @Deprecated public static android.text.Spanned fromHtml(String, android.text.Html.ImageGetter, android.text.Html.TagHandler);
+    method public static android.text.Spanned fromHtml(String, int, android.text.Html.ImageGetter, android.text.Html.TagHandler);
+    method @Deprecated public static String toHtml(android.text.Spanned);
+    method public static String toHtml(android.text.Spanned, int);
     field public static final int FROM_HTML_MODE_COMPACT = 63; // 0x3f
     field public static final int FROM_HTML_MODE_LEGACY = 0; // 0x0
     field public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256; // 0x100
@@ -45316,12 +45697,12 @@
     field public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1; // 0x1
   }
 
-  public static abstract interface Html.ImageGetter {
-    method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String);
+  public static interface Html.ImageGetter {
+    method public android.graphics.drawable.Drawable getDrawable(String);
   }
 
-  public static abstract interface Html.TagHandler {
-    method public abstract void handleTag(boolean, java.lang.String, android.text.Editable, org.xml.sax.XMLReader);
+  public static interface Html.TagHandler {
+    method public void handleTag(boolean, String, android.text.Editable, org.xml.sax.XMLReader);
   }
 
   public class Hyphenator {
@@ -45340,23 +45721,23 @@
     field public static final int START_HYPHEN_EDIT_NO_EDIT = 0; // 0x0
   }
 
-  public abstract interface InputFilter {
-    method public abstract java.lang.CharSequence filter(java.lang.CharSequence, int, int, android.text.Spanned, int, int);
+  public interface InputFilter {
+    method public CharSequence filter(CharSequence, int, int, android.text.Spanned, int, int);
   }
 
   public static class InputFilter.AllCaps implements android.text.InputFilter {
     ctor public InputFilter.AllCaps();
-    ctor public InputFilter.AllCaps(java.util.Locale);
-    method public java.lang.CharSequence filter(java.lang.CharSequence, int, int, android.text.Spanned, int, int);
+    ctor public InputFilter.AllCaps(@NonNull java.util.Locale);
+    method public CharSequence filter(CharSequence, int, int, android.text.Spanned, int, int);
   }
 
   public static class InputFilter.LengthFilter implements android.text.InputFilter {
     ctor public InputFilter.LengthFilter(int);
-    method public java.lang.CharSequence filter(java.lang.CharSequence, int, int, android.text.Spanned, int, int);
+    method public CharSequence filter(CharSequence, int, int, android.text.Spanned, int, int);
     method public int getMax();
   }
 
-  public abstract interface InputType {
+  public interface InputType {
     field public static final int TYPE_CLASS_DATETIME = 4; // 0x4
     field public static final int TYPE_CLASS_NUMBER = 2; // 0x2
     field public static final int TYPE_CLASS_PHONE = 3; // 0x3
@@ -45398,14 +45779,14 @@
   }
 
   public abstract class Layout {
-    ctor protected Layout(java.lang.CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float);
+    ctor protected Layout(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float);
     method public void draw(android.graphics.Canvas);
     method public void draw(android.graphics.Canvas, android.graphics.Path, android.graphics.Paint, int);
     method public final android.text.Layout.Alignment getAlignment();
     method public abstract int getBottomPadding();
-    method public void getCursorPath(int, android.graphics.Path, java.lang.CharSequence);
-    method public static float getDesiredWidth(java.lang.CharSequence, android.text.TextPaint);
-    method public static float getDesiredWidth(java.lang.CharSequence, int, int, android.text.TextPaint);
+    method public void getCursorPath(int, android.graphics.Path, CharSequence);
+    method public static float getDesiredWidth(CharSequence, android.text.TextPaint);
+    method public static float getDesiredWidth(CharSequence, int, int, android.text.TextPaint);
     method public abstract int getEllipsisCount(int);
     method public abstract int getEllipsisStart(int);
     method public int getEllipsizedWidth();
@@ -45441,7 +45822,7 @@
     method public void getSelectionPath(int, int, android.graphics.Path);
     method public final float getSpacingAdd();
     method public final float getSpacingMultiplier();
-    method public final java.lang.CharSequence getText();
+    method public final CharSequence getText();
     method public abstract int getTopPadding();
     method public final int getWidth();
     method public final void increaseWidthTo(int);
@@ -45461,9 +45842,7 @@
     field public static final int JUSTIFICATION_MODE_NONE = 0; // 0x0
   }
 
-  public static final class Layout.Alignment extends java.lang.Enum {
-    method public static android.text.Layout.Alignment valueOf(java.lang.String);
-    method public static final android.text.Layout.Alignment[] values();
+  public enum Layout.Alignment {
     enum_constant public static final android.text.Layout.Alignment ALIGN_CENTER;
     enum_constant public static final android.text.Layout.Alignment ALIGN_NORMAL;
     enum_constant public static final android.text.Layout.Alignment ALIGN_OPPOSITE;
@@ -45473,7 +45852,7 @@
   }
 
   public abstract class LoginFilter implements android.text.InputFilter {
-    method public java.lang.CharSequence filter(java.lang.CharSequence, int, int, android.text.Spanned, int, int);
+    method public CharSequence filter(CharSequence, int, int, android.text.Spanned, int, int);
     method public abstract boolean isAllowed(char);
     method public void onInvalidCharacter(char);
     method public void onStart();
@@ -45498,51 +45877,51 @@
     method public boolean isAllowed(char);
   }
 
-  public abstract interface NoCopySpan {
+  public interface NoCopySpan {
   }
 
   public static class NoCopySpan.Concrete implements android.text.NoCopySpan {
     ctor public NoCopySpan.Concrete();
   }
 
-  public abstract interface ParcelableSpan implements android.os.Parcelable {
-    method public abstract int getSpanTypeId();
+  public interface ParcelableSpan extends android.os.Parcelable {
+    method public int getSpanTypeId();
   }
 
   public class PrecomputedText implements android.text.Spannable {
     method public char charAt(int);
-    method public static android.text.PrecomputedText create(java.lang.CharSequence, android.text.PrecomputedText.Params);
-    method public void getBounds(int, int, android.graphics.Rect);
-    method public int getParagraphCount();
-    method public int getParagraphEnd(int);
-    method public int getParagraphStart(int);
-    method public android.text.PrecomputedText.Params getParams();
-    method public int getSpanEnd(java.lang.Object);
-    method public int getSpanFlags(java.lang.Object);
-    method public int getSpanStart(java.lang.Object);
-    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
-    method public float getWidth(int, int);
+    method public static android.text.PrecomputedText create(@NonNull CharSequence, @NonNull android.text.PrecomputedText.Params);
+    method public void getBounds(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.Rect);
+    method @IntRange(from=0) public int getParagraphCount();
+    method @IntRange(from=0) public int getParagraphEnd(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getParagraphStart(@IntRange(from=0) int);
+    method @NonNull public android.text.PrecomputedText.Params getParams();
+    method public int getSpanEnd(Object);
+    method public int getSpanFlags(Object);
+    method public int getSpanStart(Object);
+    method public <T> T[] getSpans(int, int, Class<T>);
+    method @FloatRange(from=0) public float getWidth(@IntRange(from=0) int, @IntRange(from=0) int);
     method public int length();
-    method public int nextSpanTransition(int, int, java.lang.Class);
-    method public void removeSpan(java.lang.Object);
-    method public void setSpan(java.lang.Object, int, int, int);
-    method public java.lang.CharSequence subSequence(int, int);
+    method public int nextSpanTransition(int, int, Class);
+    method public void removeSpan(Object);
+    method public void setSpan(Object, int, int, int);
+    method public CharSequence subSequence(int, int);
   }
 
   public static final class PrecomputedText.Params {
     method public int getBreakStrategy();
     method public int getHyphenationFrequency();
-    method public android.text.TextDirectionHeuristic getTextDirection();
-    method public android.text.TextPaint getTextPaint();
+    method @NonNull public android.text.TextDirectionHeuristic getTextDirection();
+    method @NonNull public android.text.TextPaint getTextPaint();
   }
 
   public static class PrecomputedText.Params.Builder {
-    ctor public PrecomputedText.Params.Builder(android.text.TextPaint);
-    ctor public PrecomputedText.Params.Builder(android.text.PrecomputedText.Params);
-    method public android.text.PrecomputedText.Params build();
+    ctor public PrecomputedText.Params.Builder(@NonNull android.text.TextPaint);
+    ctor public PrecomputedText.Params.Builder(@NonNull android.text.PrecomputedText.Params);
+    method @NonNull public android.text.PrecomputedText.Params build();
     method public android.text.PrecomputedText.Params.Builder setBreakStrategy(int);
     method public android.text.PrecomputedText.Params.Builder setHyphenationFrequency(int);
-    method public android.text.PrecomputedText.Params.Builder setTextDirection(android.text.TextDirectionHeuristic);
+    method public android.text.PrecomputedText.Params.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic);
   }
 
   public class Selection {
@@ -45553,8 +45932,8 @@
     method public static boolean extendToLeftEdge(android.text.Spannable, android.text.Layout);
     method public static boolean extendToRightEdge(android.text.Spannable, android.text.Layout);
     method public static boolean extendUp(android.text.Spannable, android.text.Layout);
-    method public static final int getSelectionEnd(java.lang.CharSequence);
-    method public static final int getSelectionStart(java.lang.CharSequence);
+    method public static final int getSelectionEnd(CharSequence);
+    method public static final int getSelectionStart(CharSequence);
     method public static boolean moveDown(android.text.Spannable, android.text.Layout);
     method public static boolean moveLeft(android.text.Spannable, android.text.Layout);
     method public static boolean moveRight(android.text.Spannable, android.text.Layout);
@@ -45565,42 +45944,51 @@
     method public static final void selectAll(android.text.Spannable);
     method public static void setSelection(android.text.Spannable, int, int);
     method public static final void setSelection(android.text.Spannable, int);
-    field public static final java.lang.Object SELECTION_END;
-    field public static final java.lang.Object SELECTION_START;
+    field public static final Object SELECTION_END;
+    field public static final Object SELECTION_START;
   }
 
-  public abstract interface SpanWatcher implements android.text.NoCopySpan {
-    method public abstract void onSpanAdded(android.text.Spannable, java.lang.Object, int, int);
-    method public abstract void onSpanChanged(android.text.Spannable, java.lang.Object, int, int, int, int);
-    method public abstract void onSpanRemoved(android.text.Spannable, java.lang.Object, int, int);
+  public interface SpanWatcher extends android.text.NoCopySpan {
+    method public void onSpanAdded(android.text.Spannable, Object, int, int);
+    method public void onSpanChanged(android.text.Spannable, Object, int, int, int, int);
+    method public void onSpanRemoved(android.text.Spannable, Object, int, int);
   }
 
-  public abstract interface Spannable implements android.text.Spanned {
-    method public abstract void removeSpan(java.lang.Object);
-    method public abstract void setSpan(java.lang.Object, int, int, int);
+  public interface Spannable extends android.text.Spanned {
+    method public void removeSpan(Object);
+    method public void setSpan(Object, int, int, int);
   }
 
   public static class Spannable.Factory {
     ctor public Spannable.Factory();
     method public static android.text.Spannable.Factory getInstance();
-    method public android.text.Spannable newSpannable(java.lang.CharSequence);
+    method public android.text.Spannable newSpannable(CharSequence);
   }
 
   public class SpannableString implements java.lang.CharSequence android.text.GetChars android.text.Spannable {
-    ctor public SpannableString(java.lang.CharSequence);
-    method public void removeSpan(java.lang.Object);
-    method public void setSpan(java.lang.Object, int, int, int);
-    method public final java.lang.CharSequence subSequence(int, int);
-    method public static android.text.SpannableString valueOf(java.lang.CharSequence);
+    ctor public SpannableString(CharSequence);
+    method public final char charAt(int);
+    method public final void getChars(int, int, char[], int);
+    method public int getSpanEnd(Object);
+    method public int getSpanFlags(Object);
+    method public int getSpanStart(Object);
+    method public <T> T[] getSpans(int, int, Class<T>);
+    method public final int length();
+    method public int nextSpanTransition(int, int, Class);
+    method public void removeSpan(Object);
+    method public void setSpan(Object, int, int, int);
+    method public final CharSequence subSequence(int, int);
+    method public final String toString();
+    method public static android.text.SpannableString valueOf(CharSequence);
   }
 
   public class SpannableStringBuilder implements java.lang.Appendable java.lang.CharSequence android.text.Editable android.text.GetChars android.text.Spannable {
     ctor public SpannableStringBuilder();
-    ctor public SpannableStringBuilder(java.lang.CharSequence);
-    ctor public SpannableStringBuilder(java.lang.CharSequence, int, int);
-    method public android.text.SpannableStringBuilder append(java.lang.CharSequence);
-    method public android.text.SpannableStringBuilder append(java.lang.CharSequence, java.lang.Object, int);
-    method public android.text.SpannableStringBuilder append(java.lang.CharSequence, int, int);
+    ctor public SpannableStringBuilder(CharSequence);
+    ctor public SpannableStringBuilder(CharSequence, int, int);
+    method public android.text.SpannableStringBuilder append(CharSequence);
+    method public android.text.SpannableStringBuilder append(CharSequence, Object, int);
+    method public android.text.SpannableStringBuilder append(CharSequence, int, int);
     method public android.text.SpannableStringBuilder append(char);
     method public char charAt(int);
     method public void clear();
@@ -45608,31 +45996,31 @@
     method public android.text.SpannableStringBuilder delete(int, int);
     method public void getChars(int, int, char[], int);
     method public android.text.InputFilter[] getFilters();
-    method public int getSpanEnd(java.lang.Object);
-    method public int getSpanFlags(java.lang.Object);
-    method public int getSpanStart(java.lang.Object);
-    method public <T> T[] getSpans(int, int, java.lang.Class<T>);
-    method public deprecated int getTextRunCursor(int, int, int, int, int, android.graphics.Paint);
+    method public int getSpanEnd(Object);
+    method public int getSpanFlags(Object);
+    method public int getSpanStart(Object);
+    method public <T> T[] getSpans(int, int, @Nullable Class<T>);
+    method @Deprecated public int getTextRunCursor(int, int, int, int, int, android.graphics.Paint);
     method public int getTextWatcherDepth();
-    method public android.text.SpannableStringBuilder insert(int, java.lang.CharSequence, int, int);
-    method public android.text.SpannableStringBuilder insert(int, java.lang.CharSequence);
+    method public android.text.SpannableStringBuilder insert(int, CharSequence, int, int);
+    method public android.text.SpannableStringBuilder insert(int, CharSequence);
     method public int length();
-    method public int nextSpanTransition(int, int, java.lang.Class);
-    method public void removeSpan(java.lang.Object);
-    method public android.text.SpannableStringBuilder replace(int, int, java.lang.CharSequence);
-    method public android.text.SpannableStringBuilder replace(int, int, java.lang.CharSequence, int, int);
+    method public int nextSpanTransition(int, int, Class);
+    method public void removeSpan(Object);
+    method public android.text.SpannableStringBuilder replace(int, int, CharSequence);
+    method public android.text.SpannableStringBuilder replace(int, int, CharSequence, int, int);
     method public void setFilters(android.text.InputFilter[]);
-    method public void setSpan(java.lang.Object, int, int, int);
-    method public java.lang.CharSequence subSequence(int, int);
-    method public static android.text.SpannableStringBuilder valueOf(java.lang.CharSequence);
+    method public void setSpan(Object, int, int, int);
+    method public CharSequence subSequence(int, int);
+    method public static android.text.SpannableStringBuilder valueOf(CharSequence);
   }
 
-  public abstract interface Spanned implements java.lang.CharSequence {
-    method public abstract int getSpanEnd(java.lang.Object);
-    method public abstract int getSpanFlags(java.lang.Object);
-    method public abstract int getSpanStart(java.lang.Object);
-    method public abstract <T> T[] getSpans(int, int, java.lang.Class<T>);
-    method public abstract int nextSpanTransition(int, int, java.lang.Class);
+  public interface Spanned extends java.lang.CharSequence {
+    method public int getSpanEnd(Object);
+    method public int getSpanFlags(Object);
+    method public int getSpanStart(Object);
+    method public <T> T[] getSpans(int, int, Class<T>);
+    method public int nextSpanTransition(int, int, Class);
     field public static final int SPAN_COMPOSING = 256; // 0x100
     field public static final int SPAN_EXCLUSIVE_EXCLUSIVE = 33; // 0x21
     field public static final int SPAN_EXCLUSIVE_INCLUSIVE = 34; // 0x22
@@ -45652,15 +46040,23 @@
   }
 
   public final class SpannedString implements java.lang.CharSequence android.text.GetChars android.text.Spanned {
-    ctor public SpannedString(java.lang.CharSequence);
-    method public java.lang.CharSequence subSequence(int, int);
-    method public static android.text.SpannedString valueOf(java.lang.CharSequence);
+    ctor public SpannedString(CharSequence);
+    method public final char charAt(int);
+    method public final void getChars(int, int, char[], int);
+    method public int getSpanEnd(Object);
+    method public int getSpanFlags(Object);
+    method public int getSpanStart(Object);
+    method public <T> T[] getSpans(int, int, Class<T>);
+    method public final int length();
+    method public int nextSpanTransition(int, int, Class);
+    method public CharSequence subSequence(int, int);
+    method public static android.text.SpannedString valueOf(CharSequence);
   }
 
   public class StaticLayout extends android.text.Layout {
-    ctor public deprecated StaticLayout(java.lang.CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, boolean);
-    ctor public deprecated StaticLayout(java.lang.CharSequence, int, int, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, boolean);
-    ctor public deprecated StaticLayout(java.lang.CharSequence, int, int, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, boolean, android.text.TextUtils.TruncateAt, int);
+    ctor @Deprecated public StaticLayout(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, boolean);
+    ctor @Deprecated public StaticLayout(CharSequence, int, int, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, boolean);
+    ctor @Deprecated public StaticLayout(CharSequence, int, int, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, boolean, android.text.TextUtils.TruncateAt, int);
     method public int getBottomPadding();
     method public int getEllipsisCount(int);
     method public int getEllipsisStart(int);
@@ -45675,26 +46071,26 @@
   }
 
   public static final class StaticLayout.Builder {
-    method public android.text.StaticLayout build();
-    method public static android.text.StaticLayout.Builder obtain(java.lang.CharSequence, int, int, android.text.TextPaint, int);
-    method public android.text.StaticLayout.Builder setAlignment(android.text.Layout.Alignment);
-    method public android.text.StaticLayout.Builder setBreakStrategy(int);
-    method public android.text.StaticLayout.Builder setEllipsize(android.text.TextUtils.TruncateAt);
-    method public android.text.StaticLayout.Builder setEllipsizedWidth(int);
-    method public android.text.StaticLayout.Builder setHyphenationFrequency(int);
-    method public android.text.StaticLayout.Builder setIncludePad(boolean);
-    method public android.text.StaticLayout.Builder setIndents(int[], int[]);
-    method public android.text.StaticLayout.Builder setJustificationMode(int);
-    method public android.text.StaticLayout.Builder setLineSpacing(float, float);
-    method public android.text.StaticLayout.Builder setMaxLines(int);
-    method public android.text.StaticLayout.Builder setText(java.lang.CharSequence);
-    method public android.text.StaticLayout.Builder setTextDirection(android.text.TextDirectionHeuristic);
-    method public android.text.StaticLayout.Builder setUseLineSpacingFromFallbacks(boolean);
+    method @NonNull public android.text.StaticLayout build();
+    method @NonNull public static android.text.StaticLayout.Builder obtain(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.text.TextPaint, @IntRange(from=0) int);
+    method @NonNull public android.text.StaticLayout.Builder setAlignment(@NonNull android.text.Layout.Alignment);
+    method @NonNull public android.text.StaticLayout.Builder setBreakStrategy(int);
+    method @NonNull public android.text.StaticLayout.Builder setEllipsize(@Nullable android.text.TextUtils.TruncateAt);
+    method @NonNull public android.text.StaticLayout.Builder setEllipsizedWidth(@IntRange(from=0) int);
+    method @NonNull public android.text.StaticLayout.Builder setHyphenationFrequency(int);
+    method @NonNull public android.text.StaticLayout.Builder setIncludePad(boolean);
+    method @NonNull public android.text.StaticLayout.Builder setIndents(@Nullable int[], @Nullable int[]);
+    method @NonNull public android.text.StaticLayout.Builder setJustificationMode(int);
+    method @NonNull public android.text.StaticLayout.Builder setLineSpacing(float, @FloatRange(from=0.0) float);
+    method @NonNull public android.text.StaticLayout.Builder setMaxLines(@IntRange(from=0) int);
+    method public android.text.StaticLayout.Builder setText(CharSequence);
+    method @NonNull public android.text.StaticLayout.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic);
+    method @NonNull public android.text.StaticLayout.Builder setUseLineSpacingFromFallbacks(boolean);
   }
 
-  public abstract interface TextDirectionHeuristic {
-    method public abstract boolean isRtl(char[], int, int);
-    method public abstract boolean isRtl(java.lang.CharSequence, int, int);
+  public interface TextDirectionHeuristic {
+    method public boolean isRtl(char[], int, int);
+    method public boolean isRtl(CharSequence, int, int);
   }
 
   public class TextDirectionHeuristics {
@@ -45713,55 +46109,55 @@
     ctor public TextPaint(android.graphics.Paint);
     method public void set(android.text.TextPaint);
     field public int baselineShift;
-    field public int bgColor;
+    field @ColorInt public int bgColor;
     field public float density;
     field public int[] drawableState;
-    field public int linkColor;
-    field public int underlineColor;
-    field public float underlineThickness;
+    field @ColorInt public int linkColor;
+    field @ColorInt public int underlineColor;
+    field @Px public float underlineThickness;
   }
 
   public class TextUtils {
-    method public static deprecated java.lang.CharSequence commaEllipsize(java.lang.CharSequence, android.text.TextPaint, float, java.lang.String, java.lang.String);
-    method public static java.lang.CharSequence concat(java.lang.CharSequence...);
-    method public static void copySpansFrom(android.text.Spanned, int, int, java.lang.Class, android.text.Spannable, int);
-    method public static void dumpSpans(java.lang.CharSequence, android.util.Printer, java.lang.String);
-    method public static java.lang.CharSequence ellipsize(java.lang.CharSequence, android.text.TextPaint, float, android.text.TextUtils.TruncateAt);
-    method public static java.lang.CharSequence ellipsize(java.lang.CharSequence, android.text.TextPaint, float, android.text.TextUtils.TruncateAt, boolean, android.text.TextUtils.EllipsizeCallback);
-    method public static boolean equals(java.lang.CharSequence, java.lang.CharSequence);
-    method public static java.lang.CharSequence expandTemplate(java.lang.CharSequence, java.lang.CharSequence...);
-    method public static int getCapsMode(java.lang.CharSequence, int, int);
-    method public static void getChars(java.lang.CharSequence, int, int, char[], int);
+    method @Deprecated public static CharSequence commaEllipsize(CharSequence, android.text.TextPaint, float, String, String);
+    method public static CharSequence concat(java.lang.CharSequence...);
+    method public static void copySpansFrom(android.text.Spanned, int, int, Class, android.text.Spannable, int);
+    method public static void dumpSpans(CharSequence, android.util.Printer, String);
+    method public static CharSequence ellipsize(CharSequence, android.text.TextPaint, float, android.text.TextUtils.TruncateAt);
+    method public static CharSequence ellipsize(CharSequence, android.text.TextPaint, float, android.text.TextUtils.TruncateAt, boolean, @Nullable android.text.TextUtils.EllipsizeCallback);
+    method public static boolean equals(CharSequence, CharSequence);
+    method public static CharSequence expandTemplate(CharSequence, java.lang.CharSequence...);
+    method public static int getCapsMode(CharSequence, int, int);
+    method public static void getChars(CharSequence, int, int, char[], int);
     method public static int getLayoutDirectionFromLocale(java.util.Locale);
-    method public static int getOffsetAfter(java.lang.CharSequence, int);
-    method public static int getOffsetBefore(java.lang.CharSequence, int);
-    method public static deprecated java.lang.CharSequence getReverse(java.lang.CharSequence, int, int);
-    method public static int getTrimmedLength(java.lang.CharSequence);
-    method public static java.lang.String htmlEncode(java.lang.String);
-    method public static int indexOf(java.lang.CharSequence, char);
-    method public static int indexOf(java.lang.CharSequence, char, int);
-    method public static int indexOf(java.lang.CharSequence, char, int, int);
-    method public static int indexOf(java.lang.CharSequence, java.lang.CharSequence);
-    method public static int indexOf(java.lang.CharSequence, java.lang.CharSequence, int);
-    method public static int indexOf(java.lang.CharSequence, java.lang.CharSequence, int, int);
-    method public static boolean isDigitsOnly(java.lang.CharSequence);
-    method public static boolean isEmpty(java.lang.CharSequence);
-    method public static boolean isGraphic(java.lang.CharSequence);
-    method public static deprecated boolean isGraphic(char);
-    method public static java.lang.String join(java.lang.CharSequence, java.lang.Object[]);
-    method public static java.lang.String join(java.lang.CharSequence, java.lang.Iterable);
-    method public static int lastIndexOf(java.lang.CharSequence, char);
-    method public static int lastIndexOf(java.lang.CharSequence, char, int);
-    method public static int lastIndexOf(java.lang.CharSequence, char, int, int);
-    method public static java.lang.CharSequence listEllipsize(android.content.Context, java.util.List<java.lang.CharSequence>, java.lang.String, android.text.TextPaint, float, int);
-    method public static java.lang.CharSequence makeSafeForPresentation(java.lang.String, int, float, int);
-    method public static boolean regionMatches(java.lang.CharSequence, int, java.lang.CharSequence, int, int);
-    method public static java.lang.CharSequence replace(java.lang.CharSequence, java.lang.String[], java.lang.CharSequence[]);
-    method public static java.lang.String[] split(java.lang.String, java.lang.String);
-    method public static java.lang.String[] split(java.lang.String, java.util.regex.Pattern);
-    method public static java.lang.CharSequence stringOrSpannedString(java.lang.CharSequence);
-    method public static java.lang.String substring(java.lang.CharSequence, int, int);
-    method public static void writeToParcel(java.lang.CharSequence, android.os.Parcel, int);
+    method public static int getOffsetAfter(CharSequence, int);
+    method public static int getOffsetBefore(CharSequence, int);
+    method @Deprecated public static CharSequence getReverse(CharSequence, int, int);
+    method public static int getTrimmedLength(CharSequence);
+    method public static String htmlEncode(String);
+    method public static int indexOf(CharSequence, char);
+    method public static int indexOf(CharSequence, char, int);
+    method public static int indexOf(CharSequence, char, int, int);
+    method public static int indexOf(CharSequence, CharSequence);
+    method public static int indexOf(CharSequence, CharSequence, int);
+    method public static int indexOf(CharSequence, CharSequence, int, int);
+    method public static boolean isDigitsOnly(CharSequence);
+    method public static boolean isEmpty(@Nullable CharSequence);
+    method public static boolean isGraphic(CharSequence);
+    method @Deprecated public static boolean isGraphic(char);
+    method public static String join(@NonNull CharSequence, @NonNull Object[]);
+    method public static String join(@NonNull CharSequence, @NonNull Iterable);
+    method public static int lastIndexOf(CharSequence, char);
+    method public static int lastIndexOf(CharSequence, char, int);
+    method public static int lastIndexOf(CharSequence, char, int, int);
+    method public static CharSequence listEllipsize(@Nullable android.content.Context, @Nullable java.util.List<java.lang.CharSequence>, @NonNull String, @NonNull android.text.TextPaint, @FloatRange(from=0.0, fromInclusive=false) float, @PluralsRes int);
+    method @NonNull public static CharSequence makeSafeForPresentation(@NonNull String, @IntRange(from=0) int, @FloatRange(from=0) float, int);
+    method public static boolean regionMatches(CharSequence, int, CharSequence, int, int);
+    method public static CharSequence replace(CharSequence, String[], CharSequence[]);
+    method public static String[] split(String, String);
+    method public static String[] split(String, java.util.regex.Pattern);
+    method public static CharSequence stringOrSpannedString(CharSequence);
+    method public static String substring(CharSequence, int, int);
+    method public static void writeToParcel(@Nullable CharSequence, @NonNull android.os.Parcel, int);
     field public static final int CAP_MODE_CHARACTERS = 4096; // 0x1000
     field public static final int CAP_MODE_SENTENCES = 16384; // 0x4000
     field public static final int CAP_MODE_WORDS = 8192; // 0x2000
@@ -45771,35 +46167,33 @@
     field public static final int SAFE_STRING_FLAG_TRIM = 1; // 0x1
   }
 
-  public static abstract interface TextUtils.EllipsizeCallback {
-    method public abstract void ellipsized(int, int);
+  public static interface TextUtils.EllipsizeCallback {
+    method public void ellipsized(int, int);
   }
 
-  public static class TextUtils.SimpleStringSplitter implements java.util.Iterator android.text.TextUtils.StringSplitter {
+  public static class TextUtils.SimpleStringSplitter implements java.util.Iterator<java.lang.String> android.text.TextUtils.StringSplitter {
     ctor public TextUtils.SimpleStringSplitter(char);
     method public boolean hasNext();
     method public java.util.Iterator<java.lang.String> iterator();
-    method public java.lang.String next();
-    method public void setString(java.lang.String);
+    method public String next();
+    method public void setString(String);
   }
 
-  public static abstract interface TextUtils.StringSplitter implements java.lang.Iterable {
-    method public abstract void setString(java.lang.String);
+  public static interface TextUtils.StringSplitter extends java.lang.Iterable<java.lang.String> {
+    method public void setString(String);
   }
 
-  public static final class TextUtils.TruncateAt extends java.lang.Enum {
-    method public static android.text.TextUtils.TruncateAt valueOf(java.lang.String);
-    method public static final android.text.TextUtils.TruncateAt[] values();
+  public enum TextUtils.TruncateAt {
     enum_constant public static final android.text.TextUtils.TruncateAt END;
     enum_constant public static final android.text.TextUtils.TruncateAt MARQUEE;
     enum_constant public static final android.text.TextUtils.TruncateAt MIDDLE;
     enum_constant public static final android.text.TextUtils.TruncateAt START;
   }
 
-  public abstract interface TextWatcher implements android.text.NoCopySpan {
-    method public abstract void afterTextChanged(android.text.Editable);
-    method public abstract void beforeTextChanged(java.lang.CharSequence, int, int, int);
-    method public abstract void onTextChanged(java.lang.CharSequence, int, int, int);
+  public interface TextWatcher extends android.text.NoCopySpan {
+    method public void afterTextChanged(android.text.Editable);
+    method public void beforeTextChanged(CharSequence, int, int, int);
+    method public void onTextChanged(CharSequence, int, int, int);
   }
 
 }
@@ -45808,10 +46202,10 @@
 
   public class DateFormat {
     ctor public DateFormat();
-    method public static java.lang.CharSequence format(java.lang.CharSequence, long);
-    method public static java.lang.CharSequence format(java.lang.CharSequence, java.util.Date);
-    method public static java.lang.CharSequence format(java.lang.CharSequence, java.util.Calendar);
-    method public static java.lang.String getBestDateTimePattern(java.util.Locale, java.lang.String);
+    method public static CharSequence format(CharSequence, long);
+    method public static CharSequence format(CharSequence, java.util.Date);
+    method public static CharSequence format(CharSequence, java.util.Calendar);
+    method public static String getBestDateTimePattern(java.util.Locale, String);
     method public static java.text.DateFormat getDateFormat(android.content.Context);
     method public static char[] getDateFormatOrder(android.content.Context);
     method public static java.text.DateFormat getLongDateFormat(android.content.Context);
@@ -45822,136 +46216,136 @@
 
   public class DateUtils {
     ctor public DateUtils();
-    method public static java.lang.String formatDateRange(android.content.Context, long, long, int);
+    method public static String formatDateRange(android.content.Context, long, long, int);
     method public static java.util.Formatter formatDateRange(android.content.Context, java.util.Formatter, long, long, int);
-    method public static java.util.Formatter formatDateRange(android.content.Context, java.util.Formatter, long, long, int, java.lang.String);
-    method public static java.lang.String formatDateTime(android.content.Context, long, int);
-    method public static java.lang.String formatElapsedTime(long);
-    method public static java.lang.String formatElapsedTime(java.lang.StringBuilder, long);
-    method public static final java.lang.CharSequence formatSameDayTime(long, long, int, int);
-    method public static deprecated java.lang.String getAMPMString(int);
-    method public static deprecated java.lang.String getDayOfWeekString(int, int);
-    method public static deprecated java.lang.String getMonthString(int, int);
-    method public static java.lang.CharSequence getRelativeDateTimeString(android.content.Context, long, long, long, int);
-    method public static java.lang.CharSequence getRelativeTimeSpanString(long);
-    method public static java.lang.CharSequence getRelativeTimeSpanString(long, long, long);
-    method public static java.lang.CharSequence getRelativeTimeSpanString(long, long, long, int);
-    method public static java.lang.CharSequence getRelativeTimeSpanString(android.content.Context, long, boolean);
-    method public static java.lang.CharSequence getRelativeTimeSpanString(android.content.Context, long);
+    method public static java.util.Formatter formatDateRange(android.content.Context, java.util.Formatter, long, long, int, String);
+    method public static String formatDateTime(android.content.Context, long, int);
+    method public static String formatElapsedTime(long);
+    method public static String formatElapsedTime(StringBuilder, long);
+    method public static final CharSequence formatSameDayTime(long, long, int, int);
+    method @Deprecated public static String getAMPMString(int);
+    method @Deprecated public static String getDayOfWeekString(int, int);
+    method @Deprecated public static String getMonthString(int, int);
+    method public static CharSequence getRelativeDateTimeString(android.content.Context, long, long, long, int);
+    method public static CharSequence getRelativeTimeSpanString(long);
+    method public static CharSequence getRelativeTimeSpanString(long, long, long);
+    method public static CharSequence getRelativeTimeSpanString(long, long, long, int);
+    method public static CharSequence getRelativeTimeSpanString(android.content.Context, long, boolean);
+    method public static CharSequence getRelativeTimeSpanString(android.content.Context, long);
     method public static boolean isToday(long);
-    field public static final deprecated java.lang.String ABBREV_MONTH_FORMAT = "%b";
-    field public static final java.lang.String ABBREV_WEEKDAY_FORMAT = "%a";
+    field @Deprecated public static final String ABBREV_MONTH_FORMAT = "%b";
+    field public static final String ABBREV_WEEKDAY_FORMAT = "%a";
     field public static final long DAY_IN_MILLIS = 86400000L; // 0x5265c00L
-    field public static final deprecated int FORMAT_12HOUR = 64; // 0x40
-    field public static final deprecated int FORMAT_24HOUR = 128; // 0x80
+    field @Deprecated public static final int FORMAT_12HOUR = 64; // 0x40
+    field @Deprecated public static final int FORMAT_24HOUR = 128; // 0x80
     field public static final int FORMAT_ABBREV_ALL = 524288; // 0x80000
     field public static final int FORMAT_ABBREV_MONTH = 65536; // 0x10000
     field public static final int FORMAT_ABBREV_RELATIVE = 262144; // 0x40000
     field public static final int FORMAT_ABBREV_TIME = 16384; // 0x4000
     field public static final int FORMAT_ABBREV_WEEKDAY = 32768; // 0x8000
-    field public static final deprecated int FORMAT_CAP_AMPM = 256; // 0x100
-    field public static final deprecated int FORMAT_CAP_MIDNIGHT = 4096; // 0x1000
-    field public static final deprecated int FORMAT_CAP_NOON = 1024; // 0x400
-    field public static final deprecated int FORMAT_CAP_NOON_MIDNIGHT = 5120; // 0x1400
+    field @Deprecated public static final int FORMAT_CAP_AMPM = 256; // 0x100
+    field @Deprecated public static final int FORMAT_CAP_MIDNIGHT = 4096; // 0x1000
+    field @Deprecated public static final int FORMAT_CAP_NOON = 1024; // 0x400
+    field @Deprecated public static final int FORMAT_CAP_NOON_MIDNIGHT = 5120; // 0x1400
     field public static final int FORMAT_NO_MIDNIGHT = 2048; // 0x800
     field public static final int FORMAT_NO_MONTH_DAY = 32; // 0x20
     field public static final int FORMAT_NO_NOON = 512; // 0x200
-    field public static final deprecated int FORMAT_NO_NOON_MIDNIGHT = 2560; // 0xa00
+    field @Deprecated public static final int FORMAT_NO_NOON_MIDNIGHT = 2560; // 0xa00
     field public static final int FORMAT_NO_YEAR = 8; // 0x8
     field public static final int FORMAT_NUMERIC_DATE = 131072; // 0x20000
     field public static final int FORMAT_SHOW_DATE = 16; // 0x10
     field public static final int FORMAT_SHOW_TIME = 1; // 0x1
     field public static final int FORMAT_SHOW_WEEKDAY = 2; // 0x2
     field public static final int FORMAT_SHOW_YEAR = 4; // 0x4
-    field public static final deprecated int FORMAT_UTC = 8192; // 0x2000
+    field @Deprecated public static final int FORMAT_UTC = 8192; // 0x2000
     field public static final long HOUR_IN_MILLIS = 3600000L; // 0x36ee80L
-    field public static final deprecated java.lang.String HOUR_MINUTE_24 = "%H:%M";
-    field public static final deprecated int LENGTH_LONG = 10; // 0xa
-    field public static final deprecated int LENGTH_MEDIUM = 20; // 0x14
-    field public static final deprecated int LENGTH_SHORT = 30; // 0x1e
-    field public static final deprecated int LENGTH_SHORTER = 40; // 0x28
-    field public static final deprecated int LENGTH_SHORTEST = 50; // 0x32
+    field @Deprecated public static final String HOUR_MINUTE_24 = "%H:%M";
+    field @Deprecated public static final int LENGTH_LONG = 10; // 0xa
+    field @Deprecated public static final int LENGTH_MEDIUM = 20; // 0x14
+    field @Deprecated public static final int LENGTH_SHORT = 30; // 0x1e
+    field @Deprecated public static final int LENGTH_SHORTER = 40; // 0x28
+    field @Deprecated public static final int LENGTH_SHORTEST = 50; // 0x32
     field public static final long MINUTE_IN_MILLIS = 60000L; // 0xea60L
-    field public static final java.lang.String MONTH_DAY_FORMAT = "%-d";
-    field public static final java.lang.String MONTH_FORMAT = "%B";
-    field public static final java.lang.String NUMERIC_MONTH_FORMAT = "%m";
+    field public static final String MONTH_DAY_FORMAT = "%-d";
+    field public static final String MONTH_FORMAT = "%B";
+    field public static final String NUMERIC_MONTH_FORMAT = "%m";
     field public static final long SECOND_IN_MILLIS = 1000L; // 0x3e8L
-    field public static final java.lang.String WEEKDAY_FORMAT = "%A";
+    field public static final String WEEKDAY_FORMAT = "%A";
     field public static final long WEEK_IN_MILLIS = 604800000L; // 0x240c8400L
-    field public static final java.lang.String YEAR_FORMAT = "%Y";
-    field public static final java.lang.String YEAR_FORMAT_TWO_DIGITS = "%g";
+    field public static final String YEAR_FORMAT = "%Y";
+    field public static final String YEAR_FORMAT_TWO_DIGITS = "%g";
     field public static final long YEAR_IN_MILLIS = 31449600000L; // 0x7528ad000L
-    field public static final deprecated int[] sameMonthTable;
-    field public static final deprecated int[] sameYearTable;
+    field @Deprecated public static final int[] sameMonthTable;
+    field @Deprecated public static final int[] sameYearTable;
   }
 
   public final class Formatter {
     ctor public Formatter();
-    method public static java.lang.String formatFileSize(android.content.Context, long);
-    method public static deprecated java.lang.String formatIpAddress(int);
-    method public static java.lang.String formatShortFileSize(android.content.Context, long);
+    method public static String formatFileSize(@Nullable android.content.Context, long);
+    method @Deprecated public static String formatIpAddress(int);
+    method public static String formatShortFileSize(@Nullable android.content.Context, long);
   }
 
-  public deprecated class Time {
-    ctor public Time(java.lang.String);
-    ctor public Time();
-    ctor public Time(android.text.format.Time);
-    method public boolean after(android.text.format.Time);
-    method public boolean before(android.text.format.Time);
-    method public void clear(java.lang.String);
-    method public static int compare(android.text.format.Time, android.text.format.Time);
-    method public java.lang.String format(java.lang.String);
-    method public java.lang.String format2445();
-    method public java.lang.String format3339(boolean);
-    method public int getActualMaximum(int);
-    method public static java.lang.String getCurrentTimezone();
-    method public static int getJulianDay(long, long);
-    method public static int getJulianMondayFromWeeksSinceEpoch(int);
-    method public int getWeekNumber();
-    method public static int getWeeksSinceEpochFromJulianDay(int, int);
-    method public static boolean isEpoch(android.text.format.Time);
-    method public long normalize(boolean);
-    method public boolean parse(java.lang.String);
-    method public boolean parse3339(java.lang.String);
-    method public void set(long);
-    method public void set(android.text.format.Time);
-    method public void set(int, int, int, int, int, int);
-    method public void set(int, int, int);
-    method public long setJulianDay(int);
-    method public void setToNow();
-    method public void switchTimezone(java.lang.String);
-    method public long toMillis(boolean);
-    field public static final int EPOCH_JULIAN_DAY = 2440588; // 0x253d8c
-    field public static final int FRIDAY = 5; // 0x5
-    field public static final int HOUR = 3; // 0x3
-    field public static final int MINUTE = 2; // 0x2
-    field public static final int MONDAY = 1; // 0x1
-    field public static final int MONDAY_BEFORE_JULIAN_EPOCH = 2440585; // 0x253d89
-    field public static final int MONTH = 5; // 0x5
-    field public static final int MONTH_DAY = 4; // 0x4
-    field public static final int SATURDAY = 6; // 0x6
-    field public static final int SECOND = 1; // 0x1
-    field public static final int SUNDAY = 0; // 0x0
-    field public static final int THURSDAY = 4; // 0x4
-    field public static final java.lang.String TIMEZONE_UTC = "UTC";
-    field public static final int TUESDAY = 2; // 0x2
-    field public static final int WEDNESDAY = 3; // 0x3
-    field public static final int WEEK_DAY = 7; // 0x7
-    field public static final int WEEK_NUM = 9; // 0x9
-    field public static final int YEAR = 6; // 0x6
-    field public static final int YEAR_DAY = 8; // 0x8
-    field public boolean allDay;
-    field public long gmtoff;
-    field public int hour;
-    field public int isDst;
-    field public int minute;
-    field public int month;
-    field public int monthDay;
-    field public int second;
-    field public java.lang.String timezone;
-    field public int weekDay;
-    field public int year;
-    field public int yearDay;
+  @Deprecated public class Time {
+    ctor @Deprecated public Time(String);
+    ctor @Deprecated public Time();
+    ctor @Deprecated public Time(android.text.format.Time);
+    method @Deprecated public boolean after(android.text.format.Time);
+    method @Deprecated public boolean before(android.text.format.Time);
+    method @Deprecated public void clear(String);
+    method @Deprecated public static int compare(android.text.format.Time, android.text.format.Time);
+    method @Deprecated public String format(String);
+    method @Deprecated public String format2445();
+    method @Deprecated public String format3339(boolean);
+    method @Deprecated public int getActualMaximum(int);
+    method @Deprecated public static String getCurrentTimezone();
+    method @Deprecated public static int getJulianDay(long, long);
+    method @Deprecated public static int getJulianMondayFromWeeksSinceEpoch(int);
+    method @Deprecated public int getWeekNumber();
+    method @Deprecated public static int getWeeksSinceEpochFromJulianDay(int, int);
+    method @Deprecated public static boolean isEpoch(android.text.format.Time);
+    method @Deprecated public long normalize(boolean);
+    method @Deprecated public boolean parse(String);
+    method @Deprecated public boolean parse3339(String);
+    method @Deprecated public void set(long);
+    method @Deprecated public void set(android.text.format.Time);
+    method @Deprecated public void set(int, int, int, int, int, int);
+    method @Deprecated public void set(int, int, int);
+    method @Deprecated public long setJulianDay(int);
+    method @Deprecated public void setToNow();
+    method @Deprecated public void switchTimezone(String);
+    method @Deprecated public long toMillis(boolean);
+    field @Deprecated public static final int EPOCH_JULIAN_DAY = 2440588; // 0x253d8c
+    field @Deprecated public static final int FRIDAY = 5; // 0x5
+    field @Deprecated public static final int HOUR = 3; // 0x3
+    field @Deprecated public static final int MINUTE = 2; // 0x2
+    field @Deprecated public static final int MONDAY = 1; // 0x1
+    field @Deprecated public static final int MONDAY_BEFORE_JULIAN_EPOCH = 2440585; // 0x253d89
+    field @Deprecated public static final int MONTH = 5; // 0x5
+    field @Deprecated public static final int MONTH_DAY = 4; // 0x4
+    field @Deprecated public static final int SATURDAY = 6; // 0x6
+    field @Deprecated public static final int SECOND = 1; // 0x1
+    field @Deprecated public static final int SUNDAY = 0; // 0x0
+    field @Deprecated public static final int THURSDAY = 4; // 0x4
+    field @Deprecated public static final String TIMEZONE_UTC = "UTC";
+    field @Deprecated public static final int TUESDAY = 2; // 0x2
+    field @Deprecated public static final int WEDNESDAY = 3; // 0x3
+    field @Deprecated public static final int WEEK_DAY = 7; // 0x7
+    field @Deprecated public static final int WEEK_NUM = 9; // 0x9
+    field @Deprecated public static final int YEAR = 6; // 0x6
+    field @Deprecated public static final int YEAR_DAY = 8; // 0x8
+    field @Deprecated public boolean allDay;
+    field @Deprecated public long gmtoff;
+    field @Deprecated public int hour;
+    field @Deprecated public int isDst;
+    field @Deprecated public int minute;
+    field @Deprecated public int month;
+    field @Deprecated public int monthDay;
+    field @Deprecated public int second;
+    field @Deprecated public String timezone;
+    field @Deprecated public int weekDay;
+    field @Deprecated public int year;
+    field @Deprecated public int yearDay;
   }
 
 }
@@ -45998,29 +46392,29 @@
   }
 
   public class CharacterPickerDialog extends android.app.Dialog implements android.widget.AdapterView.OnItemClickListener android.view.View.OnClickListener {
-    ctor public CharacterPickerDialog(android.content.Context, android.view.View, android.text.Editable, java.lang.String, boolean);
+    ctor public CharacterPickerDialog(android.content.Context, android.view.View, android.text.Editable, String, boolean);
     method public void onClick(android.view.View);
     method public void onItemClick(android.widget.AdapterView, android.view.View, int, long);
   }
 
   public class DateKeyListener extends android.text.method.NumberKeyListener {
-    ctor public deprecated DateKeyListener();
-    ctor public DateKeyListener(java.util.Locale);
-    method protected char[] getAcceptedChars();
+    ctor @Deprecated public DateKeyListener();
+    ctor public DateKeyListener(@Nullable java.util.Locale);
+    method @NonNull protected char[] getAcceptedChars();
     method public int getInputType();
-    method public static deprecated android.text.method.DateKeyListener getInstance();
-    method public static android.text.method.DateKeyListener getInstance(java.util.Locale);
-    field public static final deprecated char[] CHARACTERS;
+    method @Deprecated @NonNull public static android.text.method.DateKeyListener getInstance();
+    method @NonNull public static android.text.method.DateKeyListener getInstance(@Nullable java.util.Locale);
+    field @Deprecated public static final char[] CHARACTERS;
   }
 
   public class DateTimeKeyListener extends android.text.method.NumberKeyListener {
-    ctor public deprecated DateTimeKeyListener();
-    ctor public DateTimeKeyListener(java.util.Locale);
-    method protected char[] getAcceptedChars();
+    ctor @Deprecated public DateTimeKeyListener();
+    ctor public DateTimeKeyListener(@Nullable java.util.Locale);
+    method @NonNull protected char[] getAcceptedChars();
     method public int getInputType();
-    method public static deprecated android.text.method.DateTimeKeyListener getInstance();
-    method public static android.text.method.DateTimeKeyListener getInstance(java.util.Locale);
-    field public static final deprecated char[] CHARACTERS;
+    method @Deprecated @NonNull public static android.text.method.DateTimeKeyListener getInstance();
+    method @NonNull public static android.text.method.DateTimeKeyListener getInstance(@Nullable java.util.Locale);
+    field @Deprecated public static final char[] CHARACTERS;
   }
 
   public class DialerKeyListener extends android.text.method.NumberKeyListener {
@@ -46032,17 +46426,17 @@
   }
 
   public class DigitsKeyListener extends android.text.method.NumberKeyListener {
-    ctor public deprecated DigitsKeyListener();
-    ctor public deprecated DigitsKeyListener(boolean, boolean);
-    ctor public DigitsKeyListener(java.util.Locale);
-    ctor public DigitsKeyListener(java.util.Locale, boolean, boolean);
+    ctor @Deprecated public DigitsKeyListener();
+    ctor @Deprecated public DigitsKeyListener(boolean, boolean);
+    ctor public DigitsKeyListener(@Nullable java.util.Locale);
+    ctor public DigitsKeyListener(@Nullable java.util.Locale, boolean, boolean);
     method protected char[] getAcceptedChars();
     method public int getInputType();
-    method public static deprecated android.text.method.DigitsKeyListener getInstance();
-    method public static deprecated android.text.method.DigitsKeyListener getInstance(boolean, boolean);
-    method public static android.text.method.DigitsKeyListener getInstance(java.util.Locale);
-    method public static android.text.method.DigitsKeyListener getInstance(java.util.Locale, boolean, boolean);
-    method public static android.text.method.DigitsKeyListener getInstance(java.lang.String);
+    method @Deprecated @NonNull public static android.text.method.DigitsKeyListener getInstance();
+    method @Deprecated @NonNull public static android.text.method.DigitsKeyListener getInstance(boolean, boolean);
+    method @NonNull public static android.text.method.DigitsKeyListener getInstance(@Nullable java.util.Locale);
+    method @NonNull public static android.text.method.DigitsKeyListener getInstance(@Nullable java.util.Locale, boolean, boolean);
+    method @NonNull public static android.text.method.DigitsKeyListener getInstance(@NonNull String);
   }
 
   public class HideReturnsTransformationMethod extends android.text.method.ReplacementTransformationMethod {
@@ -46052,12 +46446,12 @@
     method protected char[] getReplacement();
   }
 
-  public abstract interface KeyListener {
-    method public abstract void clearMetaKeyState(android.view.View, android.text.Editable, int);
-    method public abstract int getInputType();
-    method public abstract boolean onKeyDown(android.view.View, android.text.Editable, int, android.view.KeyEvent);
-    method public abstract boolean onKeyOther(android.view.View, android.text.Editable, android.view.KeyEvent);
-    method public abstract boolean onKeyUp(android.view.View, android.text.Editable, int, android.view.KeyEvent);
+  public interface KeyListener {
+    method public void clearMetaKeyState(android.view.View, android.text.Editable, int);
+    method public int getInputType();
+    method public boolean onKeyDown(android.view.View, android.text.Editable, int, android.view.KeyEvent);
+    method public boolean onKeyOther(android.view.View, android.text.Editable, android.view.KeyEvent);
+    method public boolean onKeyUp(android.view.View, android.text.Editable, int, android.view.KeyEvent);
   }
 
   public class LinkMovementMethod extends android.text.method.ScrollingMovementMethod {
@@ -46072,16 +46466,16 @@
     method public void clearMetaKeyState(android.view.View, android.text.Editable, int);
     method public static void clearMetaKeyState(android.text.Editable, int);
     method public long clearMetaKeyState(long, int);
-    method public static final int getMetaState(java.lang.CharSequence);
-    method public static final int getMetaState(java.lang.CharSequence, android.view.KeyEvent);
-    method public static final int getMetaState(java.lang.CharSequence, int);
-    method public static final int getMetaState(java.lang.CharSequence, int, android.view.KeyEvent);
+    method public static final int getMetaState(CharSequence);
+    method public static final int getMetaState(CharSequence, android.view.KeyEvent);
+    method public static final int getMetaState(CharSequence, int);
+    method public static final int getMetaState(CharSequence, int, android.view.KeyEvent);
     method public static final int getMetaState(long);
     method public static final int getMetaState(long, int);
     method public static long handleKeyDown(long, int, android.view.KeyEvent);
     method public static long handleKeyUp(long, int, android.view.KeyEvent);
-    method public static boolean isMetaTracker(java.lang.CharSequence, java.lang.Object);
-    method public static boolean isSelectingMetaTracker(java.lang.CharSequence, java.lang.Object);
+    method public static boolean isMetaTracker(CharSequence, Object);
+    method public static boolean isSelectingMetaTracker(CharSequence, Object);
     method public boolean onKeyDown(android.view.View, android.text.Editable, int, android.view.KeyEvent);
     method public boolean onKeyUp(android.view.View, android.text.Editable, int, android.view.KeyEvent);
     method protected static void resetLockedMeta(android.text.Spannable);
@@ -46095,31 +46489,31 @@
     field public static final int META_SYM_ON = 4; // 0x4
   }
 
-  public abstract interface MovementMethod {
-    method public abstract boolean canSelectArbitrarily();
-    method public abstract void initialize(android.widget.TextView, android.text.Spannable);
-    method public abstract boolean onGenericMotionEvent(android.widget.TextView, android.text.Spannable, android.view.MotionEvent);
-    method public abstract boolean onKeyDown(android.widget.TextView, android.text.Spannable, int, android.view.KeyEvent);
-    method public abstract boolean onKeyOther(android.widget.TextView, android.text.Spannable, android.view.KeyEvent);
-    method public abstract boolean onKeyUp(android.widget.TextView, android.text.Spannable, int, android.view.KeyEvent);
-    method public abstract void onTakeFocus(android.widget.TextView, android.text.Spannable, int);
-    method public abstract boolean onTouchEvent(android.widget.TextView, android.text.Spannable, android.view.MotionEvent);
-    method public abstract boolean onTrackballEvent(android.widget.TextView, android.text.Spannable, android.view.MotionEvent);
+  public interface MovementMethod {
+    method public boolean canSelectArbitrarily();
+    method public void initialize(android.widget.TextView, android.text.Spannable);
+    method public boolean onGenericMotionEvent(android.widget.TextView, android.text.Spannable, android.view.MotionEvent);
+    method public boolean onKeyDown(android.widget.TextView, android.text.Spannable, int, android.view.KeyEvent);
+    method public boolean onKeyOther(android.widget.TextView, android.text.Spannable, android.view.KeyEvent);
+    method public boolean onKeyUp(android.widget.TextView, android.text.Spannable, int, android.view.KeyEvent);
+    method public void onTakeFocus(android.widget.TextView, android.text.Spannable, int);
+    method public boolean onTouchEvent(android.widget.TextView, android.text.Spannable, android.view.MotionEvent);
+    method public boolean onTrackballEvent(android.widget.TextView, android.text.Spannable, android.view.MotionEvent);
   }
 
   public class MultiTapKeyListener extends android.text.method.BaseKeyListener implements android.text.SpanWatcher {
     ctor public MultiTapKeyListener(android.text.method.TextKeyListener.Capitalize, boolean);
     method public int getInputType();
     method public static android.text.method.MultiTapKeyListener getInstance(boolean, android.text.method.TextKeyListener.Capitalize);
-    method public void onSpanAdded(android.text.Spannable, java.lang.Object, int, int);
-    method public void onSpanChanged(android.text.Spannable, java.lang.Object, int, int, int, int);
-    method public void onSpanRemoved(android.text.Spannable, java.lang.Object, int, int);
+    method public void onSpanAdded(android.text.Spannable, Object, int, int);
+    method public void onSpanChanged(android.text.Spannable, Object, int, int, int, int);
+    method public void onSpanRemoved(android.text.Spannable, Object, int, int);
   }
 
   public abstract class NumberKeyListener extends android.text.method.BaseKeyListener implements android.text.InputFilter {
     ctor public NumberKeyListener();
-    method public java.lang.CharSequence filter(java.lang.CharSequence, int, int, android.text.Spanned, int, int);
-    method protected abstract char[] getAcceptedChars();
+    method public CharSequence filter(CharSequence, int, int, android.text.Spanned, int, int);
+    method @NonNull protected abstract char[] getAcceptedChars();
     method protected int lookup(android.view.KeyEvent, android.text.Spannable);
     method protected static boolean ok(char[], char);
   }
@@ -46127,11 +46521,11 @@
   public class PasswordTransformationMethod implements android.text.TextWatcher android.text.method.TransformationMethod {
     ctor public PasswordTransformationMethod();
     method public void afterTextChanged(android.text.Editable);
-    method public void beforeTextChanged(java.lang.CharSequence, int, int, int);
+    method public void beforeTextChanged(CharSequence, int, int, int);
     method public static android.text.method.PasswordTransformationMethod getInstance();
-    method public java.lang.CharSequence getTransformation(java.lang.CharSequence, android.view.View);
-    method public void onFocusChanged(android.view.View, java.lang.CharSequence, boolean, int, android.graphics.Rect);
-    method public void onTextChanged(java.lang.CharSequence, int, int, int);
+    method public CharSequence getTransformation(CharSequence, android.view.View);
+    method public void onFocusChanged(android.view.View, CharSequence, boolean, int, android.graphics.Rect);
+    method public void onTextChanged(CharSequence, int, int, int);
   }
 
   public class QwertyKeyListener extends android.text.method.BaseKeyListener {
@@ -46139,15 +46533,15 @@
     method public int getInputType();
     method public static android.text.method.QwertyKeyListener getInstance(boolean, android.text.method.TextKeyListener.Capitalize);
     method public static android.text.method.QwertyKeyListener getInstanceForFullKeyboard();
-    method public static void markAsReplaced(android.text.Spannable, int, int, java.lang.String);
+    method public static void markAsReplaced(android.text.Spannable, int, int, String);
   }
 
   public abstract class ReplacementTransformationMethod implements android.text.method.TransformationMethod {
     ctor public ReplacementTransformationMethod();
     method protected abstract char[] getOriginal();
     method protected abstract char[] getReplacement();
-    method public java.lang.CharSequence getTransformation(java.lang.CharSequence, android.view.View);
-    method public void onFocusChanged(android.view.View, java.lang.CharSequence, boolean, int, android.graphics.Rect);
+    method public CharSequence getTransformation(CharSequence, android.view.View);
+    method public void onFocusChanged(android.view.View, CharSequence, boolean, int, android.graphics.Rect);
   }
 
   public class ScrollingMovementMethod extends android.text.method.BaseMovementMethod implements android.text.method.MovementMethod {
@@ -46168,16 +46562,14 @@
     method public int getInputType();
     method public static android.text.method.TextKeyListener getInstance(boolean, android.text.method.TextKeyListener.Capitalize);
     method public static android.text.method.TextKeyListener getInstance();
-    method public void onSpanAdded(android.text.Spannable, java.lang.Object, int, int);
-    method public void onSpanChanged(android.text.Spannable, java.lang.Object, int, int, int, int);
-    method public void onSpanRemoved(android.text.Spannable, java.lang.Object, int, int);
+    method public void onSpanAdded(android.text.Spannable, Object, int, int);
+    method public void onSpanChanged(android.text.Spannable, Object, int, int, int, int);
+    method public void onSpanRemoved(android.text.Spannable, Object, int, int);
     method public void release();
-    method public static boolean shouldCap(android.text.method.TextKeyListener.Capitalize, java.lang.CharSequence, int);
+    method public static boolean shouldCap(android.text.method.TextKeyListener.Capitalize, CharSequence, int);
   }
 
-  public static final class TextKeyListener.Capitalize extends java.lang.Enum {
-    method public static android.text.method.TextKeyListener.Capitalize valueOf(java.lang.String);
-    method public static final android.text.method.TextKeyListener.Capitalize[] values();
+  public enum TextKeyListener.Capitalize {
     enum_constant public static final android.text.method.TextKeyListener.Capitalize CHARACTERS;
     enum_constant public static final android.text.method.TextKeyListener.Capitalize NONE;
     enum_constant public static final android.text.method.TextKeyListener.Capitalize SENTENCES;
@@ -46185,13 +46577,13 @@
   }
 
   public class TimeKeyListener extends android.text.method.NumberKeyListener {
-    ctor public deprecated TimeKeyListener();
-    ctor public TimeKeyListener(java.util.Locale);
-    method protected char[] getAcceptedChars();
+    ctor @Deprecated public TimeKeyListener();
+    ctor public TimeKeyListener(@Nullable java.util.Locale);
+    method @NonNull protected char[] getAcceptedChars();
     method public int getInputType();
-    method public static deprecated android.text.method.TimeKeyListener getInstance();
-    method public static android.text.method.TimeKeyListener getInstance(java.util.Locale);
-    field public static final deprecated char[] CHARACTERS;
+    method @Deprecated @NonNull public static android.text.method.TimeKeyListener getInstance();
+    method @NonNull public static android.text.method.TimeKeyListener getInstance(@Nullable java.util.Locale);
+    field @Deprecated public static final char[] CHARACTERS;
   }
 
   public class Touch {
@@ -46201,9 +46593,9 @@
     method public static void scrollTo(android.widget.TextView, android.text.Layout, int, int);
   }
 
-  public abstract interface TransformationMethod {
-    method public abstract java.lang.CharSequence getTransformation(java.lang.CharSequence, android.view.View);
-    method public abstract void onFocusChanged(android.view.View, java.lang.CharSequence, boolean, int, android.graphics.Rect);
+  public interface TransformationMethod {
+    method public CharSequence getTransformation(CharSequence, android.view.View);
+    method public void onFocusChanged(android.view.View, CharSequence, boolean, int, android.graphics.Rect);
   }
 
 }
@@ -46213,53 +46605,53 @@
   public class AbsoluteSizeSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
     ctor public AbsoluteSizeSpan(int);
     ctor public AbsoluteSizeSpan(int, boolean);
-    ctor public AbsoluteSizeSpan(android.os.Parcel);
+    ctor public AbsoluteSizeSpan(@NonNull android.os.Parcel);
     method public int describeContents();
     method public boolean getDip();
     method public int getSize();
     method public int getSpanTypeId();
-    method public void updateDrawState(android.text.TextPaint);
-    method public void updateMeasureState(android.text.TextPaint);
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void updateDrawState(@NonNull android.text.TextPaint);
+    method public void updateMeasureState(@NonNull android.text.TextPaint);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
   }
 
-  public abstract interface AlignmentSpan implements android.text.style.ParagraphStyle {
-    method public abstract android.text.Layout.Alignment getAlignment();
+  public interface AlignmentSpan extends android.text.style.ParagraphStyle {
+    method public android.text.Layout.Alignment getAlignment();
   }
 
   public static class AlignmentSpan.Standard implements android.text.style.AlignmentSpan android.text.ParcelableSpan {
-    ctor public AlignmentSpan.Standard(android.text.Layout.Alignment);
-    ctor public AlignmentSpan.Standard(android.os.Parcel);
+    ctor public AlignmentSpan.Standard(@NonNull android.text.Layout.Alignment);
+    ctor public AlignmentSpan.Standard(@NonNull android.os.Parcel);
     method public int describeContents();
     method public android.text.Layout.Alignment getAlignment();
     method public int getSpanTypeId();
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
   }
 
   public class BackgroundColorSpan extends android.text.style.CharacterStyle implements android.text.ParcelableSpan android.text.style.UpdateAppearance {
-    ctor public BackgroundColorSpan(int);
-    ctor public BackgroundColorSpan(android.os.Parcel);
+    ctor public BackgroundColorSpan(@ColorInt int);
+    ctor public BackgroundColorSpan(@NonNull android.os.Parcel);
     method public int describeContents();
-    method public int getBackgroundColor();
+    method @ColorInt public int getBackgroundColor();
     method public int getSpanTypeId();
-    method public void updateDrawState(android.text.TextPaint);
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void updateDrawState(@NonNull android.text.TextPaint);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
   }
 
   public class BulletSpan implements android.text.style.LeadingMarginSpan android.text.ParcelableSpan {
     ctor public BulletSpan();
     ctor public BulletSpan(int);
-    ctor public BulletSpan(int, int);
-    ctor public BulletSpan(int, int, int);
-    ctor public BulletSpan(android.os.Parcel);
+    ctor public BulletSpan(int, @ColorInt int);
+    ctor public BulletSpan(int, @ColorInt int, @IntRange(from=0) int);
+    ctor public BulletSpan(@NonNull android.os.Parcel);
     method public int describeContents();
-    method public void drawLeadingMargin(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, java.lang.CharSequence, int, int, boolean, android.text.Layout);
+    method public void drawLeadingMargin(@NonNull android.graphics.Canvas, @NonNull android.graphics.Paint, int, int, int, int, int, @NonNull CharSequence, int, int, boolean, @Nullable android.text.Layout);
     method public int getBulletRadius();
     method public int getColor();
     method public int getGapWidth();
     method public int getLeadingMargin(boolean);
     method public int getSpanTypeId();
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int STANDARD_GAP_WIDTH = 2; // 0x2
   }
 
@@ -46272,24 +46664,24 @@
 
   public abstract class ClickableSpan extends android.text.style.CharacterStyle implements android.text.style.UpdateAppearance {
     ctor public ClickableSpan();
-    method public abstract void onClick(android.view.View);
-    method public void updateDrawState(android.text.TextPaint);
+    method public abstract void onClick(@NonNull android.view.View);
+    method public void updateDrawState(@NonNull android.text.TextPaint);
   }
 
   public class DrawableMarginSpan implements android.text.style.LeadingMarginSpan android.text.style.LineHeightSpan {
-    ctor public DrawableMarginSpan(android.graphics.drawable.Drawable);
-    ctor public DrawableMarginSpan(android.graphics.drawable.Drawable, int);
-    method public void chooseHeight(java.lang.CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt);
-    method public void drawLeadingMargin(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, java.lang.CharSequence, int, int, boolean, android.text.Layout);
+    ctor public DrawableMarginSpan(@NonNull android.graphics.drawable.Drawable);
+    ctor public DrawableMarginSpan(@NonNull android.graphics.drawable.Drawable, int);
+    method public void chooseHeight(@NonNull CharSequence, int, int, int, int, @NonNull android.graphics.Paint.FontMetricsInt);
+    method public void drawLeadingMargin(@NonNull android.graphics.Canvas, @NonNull android.graphics.Paint, int, int, int, int, int, @NonNull CharSequence, int, int, boolean, @NonNull android.text.Layout);
     method public int getLeadingMargin(boolean);
   }
 
   public abstract class DynamicDrawableSpan extends android.text.style.ReplacementSpan {
     ctor public DynamicDrawableSpan();
     ctor protected DynamicDrawableSpan(int);
-    method public void draw(android.graphics.Canvas, java.lang.CharSequence, int, int, float, int, int, int, android.graphics.Paint);
+    method public void draw(@NonNull android.graphics.Canvas, CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, float, int, int, int, @NonNull android.graphics.Paint);
     method public abstract android.graphics.drawable.Drawable getDrawable();
-    method public int getSize(android.graphics.Paint, java.lang.CharSequence, int, int, android.graphics.Paint.FontMetricsInt);
+    method public int getSize(@NonNull android.graphics.Paint, CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.graphics.Paint.FontMetricsInt);
     method public int getVerticalAlignment();
     field public static final int ALIGN_BASELINE = 1; // 0x1
     field public static final int ALIGN_BOTTOM = 0; // 0x0
@@ -46299,57 +46691,57 @@
   public class EasyEditSpan implements android.text.ParcelableSpan {
     ctor public EasyEditSpan();
     ctor public EasyEditSpan(android.app.PendingIntent);
-    ctor public EasyEditSpan(android.os.Parcel);
+    ctor public EasyEditSpan(@NonNull android.os.Parcel);
     method public int describeContents();
     method public int getSpanTypeId();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final java.lang.String EXTRA_TEXT_CHANGED_TYPE = "android.text.style.EXTRA_TEXT_CHANGED_TYPE";
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final String EXTRA_TEXT_CHANGED_TYPE = "android.text.style.EXTRA_TEXT_CHANGED_TYPE";
     field public static final int TEXT_DELETED = 1; // 0x1
     field public static final int TEXT_MODIFIED = 2; // 0x2
   }
 
   public class ForegroundColorSpan extends android.text.style.CharacterStyle implements android.text.ParcelableSpan android.text.style.UpdateAppearance {
-    ctor public ForegroundColorSpan(int);
-    ctor public ForegroundColorSpan(android.os.Parcel);
+    ctor public ForegroundColorSpan(@ColorInt int);
+    ctor public ForegroundColorSpan(@NonNull android.os.Parcel);
     method public int describeContents();
-    method public int getForegroundColor();
+    method @ColorInt public int getForegroundColor();
     method public int getSpanTypeId();
-    method public void updateDrawState(android.text.TextPaint);
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void updateDrawState(@NonNull android.text.TextPaint);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
   }
 
   public class IconMarginSpan implements android.text.style.LeadingMarginSpan android.text.style.LineHeightSpan {
-    ctor public IconMarginSpan(android.graphics.Bitmap);
-    ctor public IconMarginSpan(android.graphics.Bitmap, int);
-    method public void chooseHeight(java.lang.CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt);
-    method public void drawLeadingMargin(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, java.lang.CharSequence, int, int, boolean, android.text.Layout);
+    ctor public IconMarginSpan(@NonNull android.graphics.Bitmap);
+    ctor public IconMarginSpan(@NonNull android.graphics.Bitmap, @IntRange(from=0) int);
+    method public void chooseHeight(CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt);
+    method public void drawLeadingMargin(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, CharSequence, int, int, boolean, android.text.Layout);
     method public int getLeadingMargin(boolean);
   }
 
   public class ImageSpan extends android.text.style.DynamicDrawableSpan {
-    ctor public deprecated ImageSpan(android.graphics.Bitmap);
-    ctor public deprecated ImageSpan(android.graphics.Bitmap, int);
-    ctor public ImageSpan(android.content.Context, android.graphics.Bitmap);
-    ctor public ImageSpan(android.content.Context, android.graphics.Bitmap, int);
-    ctor public ImageSpan(android.graphics.drawable.Drawable);
-    ctor public ImageSpan(android.graphics.drawable.Drawable, int);
-    ctor public ImageSpan(android.graphics.drawable.Drawable, java.lang.String);
-    ctor public ImageSpan(android.graphics.drawable.Drawable, java.lang.String, int);
-    ctor public ImageSpan(android.content.Context, android.net.Uri);
-    ctor public ImageSpan(android.content.Context, android.net.Uri, int);
-    ctor public ImageSpan(android.content.Context, int);
-    ctor public ImageSpan(android.content.Context, int, int);
+    ctor @Deprecated public ImageSpan(@NonNull android.graphics.Bitmap);
+    ctor @Deprecated public ImageSpan(@NonNull android.graphics.Bitmap, int);
+    ctor public ImageSpan(@NonNull android.content.Context, @NonNull android.graphics.Bitmap);
+    ctor public ImageSpan(@NonNull android.content.Context, @NonNull android.graphics.Bitmap, int);
+    ctor public ImageSpan(@NonNull android.graphics.drawable.Drawable);
+    ctor public ImageSpan(@NonNull android.graphics.drawable.Drawable, int);
+    ctor public ImageSpan(@NonNull android.graphics.drawable.Drawable, @NonNull String);
+    ctor public ImageSpan(@NonNull android.graphics.drawable.Drawable, @NonNull String, int);
+    ctor public ImageSpan(@NonNull android.content.Context, @NonNull android.net.Uri);
+    ctor public ImageSpan(@NonNull android.content.Context, @NonNull android.net.Uri, int);
+    ctor public ImageSpan(@NonNull android.content.Context, @DrawableRes int);
+    ctor public ImageSpan(@NonNull android.content.Context, @DrawableRes int, int);
     method public android.graphics.drawable.Drawable getDrawable();
-    method public java.lang.String getSource();
+    method @Nullable public String getSource();
   }
 
-  public abstract interface LeadingMarginSpan implements android.text.style.ParagraphStyle {
-    method public abstract void drawLeadingMargin(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, java.lang.CharSequence, int, int, boolean, android.text.Layout);
-    method public abstract int getLeadingMargin(boolean);
+  public interface LeadingMarginSpan extends android.text.style.ParagraphStyle {
+    method public void drawLeadingMargin(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, CharSequence, int, int, boolean, android.text.Layout);
+    method public int getLeadingMargin(boolean);
   }
 
-  public static abstract interface LeadingMarginSpan.LeadingMarginSpan2 implements android.text.style.LeadingMarginSpan android.text.style.WrapTogetherSpan {
-    method public abstract int getLeadingMarginLineCount();
+  public static interface LeadingMarginSpan.LeadingMarginSpan2 extends android.text.style.LeadingMarginSpan android.text.style.WrapTogetherSpan {
+    method public int getLeadingMarginLineCount();
   }
 
   public static class LeadingMarginSpan.Standard implements android.text.style.LeadingMarginSpan android.text.ParcelableSpan {
@@ -46357,51 +46749,51 @@
     ctor public LeadingMarginSpan.Standard(int);
     ctor public LeadingMarginSpan.Standard(android.os.Parcel);
     method public int describeContents();
-    method public void drawLeadingMargin(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, java.lang.CharSequence, int, int, boolean, android.text.Layout);
+    method public void drawLeadingMargin(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, CharSequence, int, int, boolean, android.text.Layout);
     method public int getLeadingMargin(boolean);
     method public int getSpanTypeId();
     method public void writeToParcel(android.os.Parcel, int);
   }
 
-  public abstract interface LineBackgroundSpan implements android.text.style.ParagraphStyle {
-    method public abstract void drawBackground(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, java.lang.CharSequence, int, int, int);
+  public interface LineBackgroundSpan extends android.text.style.ParagraphStyle {
+    method public void drawBackground(@NonNull android.graphics.Canvas, @NonNull android.graphics.Paint, @Px int, @Px int, @Px int, @Px int, @Px int, @NonNull CharSequence, int, int, int);
   }
 
   public static class LineBackgroundSpan.Standard implements android.text.style.LineBackgroundSpan android.text.ParcelableSpan {
-    ctor public LineBackgroundSpan.Standard(int);
-    ctor public LineBackgroundSpan.Standard(android.os.Parcel);
+    ctor public LineBackgroundSpan.Standard(@ColorInt int);
+    ctor public LineBackgroundSpan.Standard(@NonNull android.os.Parcel);
     method public int describeContents();
-    method public void drawBackground(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, java.lang.CharSequence, int, int, int);
-    method public final int getColor();
+    method public void drawBackground(@NonNull android.graphics.Canvas, @NonNull android.graphics.Paint, @Px int, @Px int, @Px int, @Px int, @Px int, @NonNull CharSequence, int, int, int);
+    method @ColorInt public final int getColor();
     method public int getSpanTypeId();
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
   }
 
-  public abstract interface LineHeightSpan implements android.text.style.ParagraphStyle android.text.style.WrapTogetherSpan {
-    method public abstract void chooseHeight(java.lang.CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt);
+  public interface LineHeightSpan extends android.text.style.ParagraphStyle android.text.style.WrapTogetherSpan {
+    method public void chooseHeight(CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt);
   }
 
   public static class LineHeightSpan.Standard implements android.text.style.LineHeightSpan android.text.ParcelableSpan {
-    ctor public LineHeightSpan.Standard(int);
+    ctor public LineHeightSpan.Standard(@Px @IntRange(from=1) int);
     ctor public LineHeightSpan.Standard(android.os.Parcel);
-    method public void chooseHeight(java.lang.CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt);
+    method public void chooseHeight(@NonNull CharSequence, int, int, int, int, @NonNull android.graphics.Paint.FontMetricsInt);
     method public int describeContents();
-    method public int getHeight();
+    method @Px public int getHeight();
     method public int getSpanTypeId();
     method public void writeToParcel(android.os.Parcel, int);
   }
 
-  public static abstract interface LineHeightSpan.WithDensity implements android.text.style.LineHeightSpan {
-    method public abstract void chooseHeight(java.lang.CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt, android.text.TextPaint);
+  public static interface LineHeightSpan.WithDensity extends android.text.style.LineHeightSpan {
+    method public void chooseHeight(CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt, android.text.TextPaint);
   }
 
   public class LocaleSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
-    ctor public LocaleSpan(java.util.Locale);
-    ctor public LocaleSpan(android.os.LocaleList);
+    ctor public LocaleSpan(@Nullable java.util.Locale);
+    ctor public LocaleSpan(@NonNull android.os.LocaleList);
     ctor public LocaleSpan(android.os.Parcel);
     method public int describeContents();
-    method public java.util.Locale getLocale();
-    method public android.os.LocaleList getLocales();
+    method @Nullable public java.util.Locale getLocale();
+    method @NonNull public android.os.LocaleList getLocales();
     method public int getSpanTypeId();
     method public void updateDrawState(android.text.TextPaint);
     method public void updateMeasureState(android.text.TextPaint);
@@ -46417,72 +46809,72 @@
   public abstract class MetricAffectingSpan extends android.text.style.CharacterStyle implements android.text.style.UpdateLayout {
     ctor public MetricAffectingSpan();
     method public android.text.style.MetricAffectingSpan getUnderlying();
-    method public abstract void updateMeasureState(android.text.TextPaint);
+    method public abstract void updateMeasureState(@NonNull android.text.TextPaint);
   }
 
-  public abstract interface ParagraphStyle {
+  public interface ParagraphStyle {
   }
 
   public class QuoteSpan implements android.text.style.LeadingMarginSpan android.text.ParcelableSpan {
     ctor public QuoteSpan();
-    ctor public QuoteSpan(int);
-    ctor public QuoteSpan(int, int, int);
-    ctor public QuoteSpan(android.os.Parcel);
+    ctor public QuoteSpan(@ColorInt int);
+    ctor public QuoteSpan(@ColorInt int, @IntRange(from=0) int, @IntRange(from=0) int);
+    ctor public QuoteSpan(@NonNull android.os.Parcel);
     method public int describeContents();
-    method public void drawLeadingMargin(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, java.lang.CharSequence, int, int, boolean, android.text.Layout);
-    method public int getColor();
+    method public void drawLeadingMargin(@NonNull android.graphics.Canvas, @NonNull android.graphics.Paint, int, int, int, int, int, @NonNull CharSequence, int, int, boolean, @NonNull android.text.Layout);
+    method @ColorInt public int getColor();
     method public int getGapWidth();
     method public int getLeadingMargin(boolean);
     method public int getSpanTypeId();
     method public int getStripeWidth();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final int STANDARD_COLOR = -16776961; // 0xff0000ff
+    field @ColorInt public static final int STANDARD_COLOR = -16776961; // 0xff0000ff
     field public static final int STANDARD_GAP_WIDTH_PX = 2; // 0x2
     field public static final int STANDARD_STRIPE_WIDTH_PX = 2; // 0x2
   }
 
   public class RelativeSizeSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
-    ctor public RelativeSizeSpan(float);
-    ctor public RelativeSizeSpan(android.os.Parcel);
+    ctor public RelativeSizeSpan(@FloatRange(from=0) float);
+    ctor public RelativeSizeSpan(@NonNull android.os.Parcel);
     method public int describeContents();
     method public float getSizeChange();
     method public int getSpanTypeId();
-    method public void updateDrawState(android.text.TextPaint);
-    method public void updateMeasureState(android.text.TextPaint);
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void updateDrawState(@NonNull android.text.TextPaint);
+    method public void updateMeasureState(@NonNull android.text.TextPaint);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
   }
 
   public abstract class ReplacementSpan extends android.text.style.MetricAffectingSpan {
     ctor public ReplacementSpan();
-    method public abstract void draw(android.graphics.Canvas, java.lang.CharSequence, int, int, float, int, int, int, android.graphics.Paint);
-    method public abstract int getSize(android.graphics.Paint, java.lang.CharSequence, int, int, android.graphics.Paint.FontMetricsInt);
+    method public abstract void draw(@NonNull android.graphics.Canvas, CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, float, int, int, int, @NonNull android.graphics.Paint);
+    method public abstract int getSize(@NonNull android.graphics.Paint, CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.graphics.Paint.FontMetricsInt);
     method public void updateDrawState(android.text.TextPaint);
     method public void updateMeasureState(android.text.TextPaint);
   }
 
   public class ScaleXSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
-    ctor public ScaleXSpan(float);
-    ctor public ScaleXSpan(android.os.Parcel);
+    ctor public ScaleXSpan(@FloatRange(from=0) float);
+    ctor public ScaleXSpan(@NonNull android.os.Parcel);
     method public int describeContents();
     method public float getScaleX();
     method public int getSpanTypeId();
     method public void updateDrawState(android.text.TextPaint);
     method public void updateMeasureState(android.text.TextPaint);
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
   }
 
   public class StrikethroughSpan extends android.text.style.CharacterStyle implements android.text.ParcelableSpan android.text.style.UpdateAppearance {
     ctor public StrikethroughSpan();
-    ctor public StrikethroughSpan(android.os.Parcel);
+    ctor public StrikethroughSpan(@NonNull android.os.Parcel);
     method public int describeContents();
     method public int getSpanTypeId();
-    method public void updateDrawState(android.text.TextPaint);
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void updateDrawState(@NonNull android.text.TextPaint);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
   }
 
   public class StyleSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
     ctor public StyleSpan(int);
-    ctor public StyleSpan(android.os.Parcel);
+    ctor public StyleSpan(@NonNull android.os.Parcel);
     method public int describeContents();
     method public int getSpanTypeId();
     method public int getStyle();
@@ -46493,68 +46885,68 @@
 
   public class SubscriptSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
     ctor public SubscriptSpan();
-    ctor public SubscriptSpan(android.os.Parcel);
+    ctor public SubscriptSpan(@NonNull android.os.Parcel);
     method public int describeContents();
     method public int getSpanTypeId();
-    method public void updateDrawState(android.text.TextPaint);
-    method public void updateMeasureState(android.text.TextPaint);
+    method public void updateDrawState(@NonNull android.text.TextPaint);
+    method public void updateMeasureState(@NonNull android.text.TextPaint);
     method public void writeToParcel(android.os.Parcel, int);
   }
 
   public class SuggestionSpan extends android.text.style.CharacterStyle implements android.text.ParcelableSpan {
-    ctor public SuggestionSpan(android.content.Context, java.lang.String[], int);
-    ctor public SuggestionSpan(java.util.Locale, java.lang.String[], int);
-    ctor public SuggestionSpan(android.content.Context, java.util.Locale, java.lang.String[], int, java.lang.Class<?>);
+    ctor public SuggestionSpan(android.content.Context, String[], int);
+    ctor public SuggestionSpan(java.util.Locale, String[], int);
+    ctor public SuggestionSpan(android.content.Context, java.util.Locale, String[], int, Class<?>);
     ctor public SuggestionSpan(android.os.Parcel);
     method public int describeContents();
     method public int getFlags();
-    method public deprecated java.lang.String getLocale();
-    method public java.util.Locale getLocaleObject();
+    method @Deprecated @NonNull public String getLocale();
+    method @Nullable public java.util.Locale getLocaleObject();
     method public int getSpanTypeId();
-    method public java.lang.String[] getSuggestions();
-    method public int getUnderlineColor();
+    method public String[] getSuggestions();
+    method @ColorInt public int getUnderlineColor();
     method public void setFlags(int);
     method public void updateDrawState(android.text.TextPaint);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final java.lang.String ACTION_SUGGESTION_PICKED = "android.text.style.SUGGESTION_PICKED";
+    field @Deprecated public static final String ACTION_SUGGESTION_PICKED = "android.text.style.SUGGESTION_PICKED";
     field public static final android.os.Parcelable.Creator<android.text.style.SuggestionSpan> CREATOR;
     field public static final int FLAG_AUTO_CORRECTION = 4; // 0x4
     field public static final int FLAG_EASY_CORRECT = 1; // 0x1
     field public static final int FLAG_MISSPELLED = 2; // 0x2
     field public static final int SUGGESTIONS_MAX_SIZE = 5; // 0x5
-    field public static final java.lang.String SUGGESTION_SPAN_PICKED_AFTER = "after";
-    field public static final java.lang.String SUGGESTION_SPAN_PICKED_BEFORE = "before";
-    field public static final java.lang.String SUGGESTION_SPAN_PICKED_HASHCODE = "hashcode";
+    field @Deprecated public static final String SUGGESTION_SPAN_PICKED_AFTER = "after";
+    field @Deprecated public static final String SUGGESTION_SPAN_PICKED_BEFORE = "before";
+    field @Deprecated public static final String SUGGESTION_SPAN_PICKED_HASHCODE = "hashcode";
   }
 
   public class SuperscriptSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
     ctor public SuperscriptSpan();
-    ctor public SuperscriptSpan(android.os.Parcel);
+    ctor public SuperscriptSpan(@NonNull android.os.Parcel);
     method public int describeContents();
     method public int getSpanTypeId();
-    method public void updateDrawState(android.text.TextPaint);
-    method public void updateMeasureState(android.text.TextPaint);
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void updateDrawState(@NonNull android.text.TextPaint);
+    method public void updateMeasureState(@NonNull android.text.TextPaint);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
   }
 
-  public abstract interface TabStopSpan implements android.text.style.ParagraphStyle {
-    method public abstract int getTabStop();
+  public interface TabStopSpan extends android.text.style.ParagraphStyle {
+    method public int getTabStop();
   }
 
   public static class TabStopSpan.Standard implements android.text.style.TabStopSpan {
-    ctor public TabStopSpan.Standard(int);
+    ctor public TabStopSpan.Standard(@IntRange(from=0) int);
     method public int getTabStop();
   }
 
   public class TextAppearanceSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
     ctor public TextAppearanceSpan(android.content.Context, int);
     ctor public TextAppearanceSpan(android.content.Context, int, int);
-    ctor public TextAppearanceSpan(java.lang.String, int, int, android.content.res.ColorStateList, android.content.res.ColorStateList);
+    ctor public TextAppearanceSpan(String, int, int, android.content.res.ColorStateList, android.content.res.ColorStateList);
     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 String getFamily();
+    method @Nullable public String getFontFeatureSettings();
+    method @Nullable public String getFontVariationSettings();
     method public android.content.res.ColorStateList getLinkTextColor();
     method public int getShadowColor();
     method public float getShadowDx();
@@ -46563,10 +46955,10 @@
     method public int getSpanTypeId();
     method public android.content.res.ColorStateList getTextColor();
     method public int getTextFontWeight();
-    method public android.os.LocaleList getTextLocales();
+    method @Nullable public android.os.LocaleList getTextLocales();
     method public int getTextSize();
     method public int getTextStyle();
-    method public android.graphics.Typeface getTypeface();
+    method @Nullable public android.graphics.Typeface getTypeface();
     method public boolean isElegantTextHeight();
     method public void updateDrawState(android.text.TextPaint);
     method public void updateMeasureState(android.text.TextPaint);
@@ -46574,58 +46966,58 @@
   }
 
   public class TtsSpan implements android.text.ParcelableSpan {
-    ctor public TtsSpan(java.lang.String, android.os.PersistableBundle);
+    ctor public TtsSpan(String, android.os.PersistableBundle);
     ctor public TtsSpan(android.os.Parcel);
     method public int describeContents();
     method public android.os.PersistableBundle getArgs();
     method public int getSpanTypeId();
-    method public java.lang.String getType();
+    method public String getType();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final java.lang.String ANIMACY_ANIMATE = "android.animate";
-    field public static final java.lang.String ANIMACY_INANIMATE = "android.inanimate";
-    field public static final java.lang.String ARG_ANIMACY = "android.arg.animacy";
-    field public static final java.lang.String ARG_CASE = "android.arg.case";
-    field public static final java.lang.String ARG_COUNTRY_CODE = "android.arg.country_code";
-    field public static final java.lang.String ARG_CURRENCY = "android.arg.money";
-    field public static final java.lang.String ARG_DAY = "android.arg.day";
-    field public static final java.lang.String ARG_DENOMINATOR = "android.arg.denominator";
-    field public static final java.lang.String ARG_DIGITS = "android.arg.digits";
-    field public static final java.lang.String ARG_DOMAIN = "android.arg.domain";
-    field public static final java.lang.String ARG_EXTENSION = "android.arg.extension";
-    field public static final java.lang.String ARG_FRACTIONAL_PART = "android.arg.fractional_part";
-    field public static final java.lang.String ARG_FRAGMENT_ID = "android.arg.fragment_id";
-    field public static final java.lang.String ARG_GENDER = "android.arg.gender";
-    field public static final java.lang.String ARG_HOURS = "android.arg.hours";
-    field public static final java.lang.String ARG_INTEGER_PART = "android.arg.integer_part";
-    field public static final java.lang.String ARG_MINUTES = "android.arg.minutes";
-    field public static final java.lang.String ARG_MONTH = "android.arg.month";
-    field public static final java.lang.String ARG_MULTIPLICITY = "android.arg.multiplicity";
-    field public static final java.lang.String ARG_NUMBER = "android.arg.number";
-    field public static final java.lang.String ARG_NUMBER_PARTS = "android.arg.number_parts";
-    field public static final java.lang.String ARG_NUMERATOR = "android.arg.numerator";
-    field public static final java.lang.String ARG_PASSWORD = "android.arg.password";
-    field public static final java.lang.String ARG_PATH = "android.arg.path";
-    field public static final java.lang.String ARG_PORT = "android.arg.port";
-    field public static final java.lang.String ARG_PROTOCOL = "android.arg.protocol";
-    field public static final java.lang.String ARG_QUANTITY = "android.arg.quantity";
-    field public static final java.lang.String ARG_QUERY_STRING = "android.arg.query_string";
-    field public static final java.lang.String ARG_TEXT = "android.arg.text";
-    field public static final java.lang.String ARG_UNIT = "android.arg.unit";
-    field public static final java.lang.String ARG_USERNAME = "android.arg.username";
-    field public static final java.lang.String ARG_VERBATIM = "android.arg.verbatim";
-    field public static final java.lang.String ARG_WEEKDAY = "android.arg.weekday";
-    field public static final java.lang.String ARG_YEAR = "android.arg.year";
-    field public static final java.lang.String CASE_ABLATIVE = "android.ablative";
-    field public static final java.lang.String CASE_ACCUSATIVE = "android.accusative";
-    field public static final java.lang.String CASE_DATIVE = "android.dative";
-    field public static final java.lang.String CASE_GENITIVE = "android.genitive";
-    field public static final java.lang.String CASE_INSTRUMENTAL = "android.instrumental";
-    field public static final java.lang.String CASE_LOCATIVE = "android.locative";
-    field public static final java.lang.String CASE_NOMINATIVE = "android.nominative";
-    field public static final java.lang.String CASE_VOCATIVE = "android.vocative";
-    field public static final java.lang.String GENDER_FEMALE = "android.female";
-    field public static final java.lang.String GENDER_MALE = "android.male";
-    field public static final java.lang.String GENDER_NEUTRAL = "android.neutral";
+    field public static final String ANIMACY_ANIMATE = "android.animate";
+    field public static final String ANIMACY_INANIMATE = "android.inanimate";
+    field public static final String ARG_ANIMACY = "android.arg.animacy";
+    field public static final String ARG_CASE = "android.arg.case";
+    field public static final String ARG_COUNTRY_CODE = "android.arg.country_code";
+    field public static final String ARG_CURRENCY = "android.arg.money";
+    field public static final String ARG_DAY = "android.arg.day";
+    field public static final String ARG_DENOMINATOR = "android.arg.denominator";
+    field public static final String ARG_DIGITS = "android.arg.digits";
+    field public static final String ARG_DOMAIN = "android.arg.domain";
+    field public static final String ARG_EXTENSION = "android.arg.extension";
+    field public static final String ARG_FRACTIONAL_PART = "android.arg.fractional_part";
+    field public static final String ARG_FRAGMENT_ID = "android.arg.fragment_id";
+    field public static final String ARG_GENDER = "android.arg.gender";
+    field public static final String ARG_HOURS = "android.arg.hours";
+    field public static final String ARG_INTEGER_PART = "android.arg.integer_part";
+    field public static final String ARG_MINUTES = "android.arg.minutes";
+    field public static final String ARG_MONTH = "android.arg.month";
+    field public static final String ARG_MULTIPLICITY = "android.arg.multiplicity";
+    field public static final String ARG_NUMBER = "android.arg.number";
+    field public static final String ARG_NUMBER_PARTS = "android.arg.number_parts";
+    field public static final String ARG_NUMERATOR = "android.arg.numerator";
+    field public static final String ARG_PASSWORD = "android.arg.password";
+    field public static final String ARG_PATH = "android.arg.path";
+    field public static final String ARG_PORT = "android.arg.port";
+    field public static final String ARG_PROTOCOL = "android.arg.protocol";
+    field public static final String ARG_QUANTITY = "android.arg.quantity";
+    field public static final String ARG_QUERY_STRING = "android.arg.query_string";
+    field public static final String ARG_TEXT = "android.arg.text";
+    field public static final String ARG_UNIT = "android.arg.unit";
+    field public static final String ARG_USERNAME = "android.arg.username";
+    field public static final String ARG_VERBATIM = "android.arg.verbatim";
+    field public static final String ARG_WEEKDAY = "android.arg.weekday";
+    field public static final String ARG_YEAR = "android.arg.year";
+    field public static final String CASE_ABLATIVE = "android.ablative";
+    field public static final String CASE_ACCUSATIVE = "android.accusative";
+    field public static final String CASE_DATIVE = "android.dative";
+    field public static final String CASE_GENITIVE = "android.genitive";
+    field public static final String CASE_INSTRUMENTAL = "android.instrumental";
+    field public static final String CASE_LOCATIVE = "android.locative";
+    field public static final String CASE_NOMINATIVE = "android.nominative";
+    field public static final String CASE_VOCATIVE = "android.vocative";
+    field public static final String GENDER_FEMALE = "android.female";
+    field public static final String GENDER_MALE = "android.male";
+    field public static final String GENDER_NEUTRAL = "android.neutral";
     field public static final int MONTH_APRIL = 3; // 0x3
     field public static final int MONTH_AUGUST = 7; // 0x7
     field public static final int MONTH_DECEMBER = 11; // 0xb
@@ -46638,22 +47030,22 @@
     field public static final int MONTH_NOVEMBER = 10; // 0xa
     field public static final int MONTH_OCTOBER = 9; // 0x9
     field public static final int MONTH_SEPTEMBER = 8; // 0x8
-    field public static final java.lang.String MULTIPLICITY_DUAL = "android.dual";
-    field public static final java.lang.String MULTIPLICITY_PLURAL = "android.plural";
-    field public static final java.lang.String MULTIPLICITY_SINGLE = "android.single";
-    field public static final java.lang.String TYPE_CARDINAL = "android.type.cardinal";
-    field public static final java.lang.String TYPE_DATE = "android.type.date";
-    field public static final java.lang.String TYPE_DECIMAL = "android.type.decimal";
-    field public static final java.lang.String TYPE_DIGITS = "android.type.digits";
-    field public static final java.lang.String TYPE_ELECTRONIC = "android.type.electronic";
-    field public static final java.lang.String TYPE_FRACTION = "android.type.fraction";
-    field public static final java.lang.String TYPE_MEASURE = "android.type.measure";
-    field public static final java.lang.String TYPE_MONEY = "android.type.money";
-    field public static final java.lang.String TYPE_ORDINAL = "android.type.ordinal";
-    field public static final java.lang.String TYPE_TELEPHONE = "android.type.telephone";
-    field public static final java.lang.String TYPE_TEXT = "android.type.text";
-    field public static final java.lang.String TYPE_TIME = "android.type.time";
-    field public static final java.lang.String TYPE_VERBATIM = "android.type.verbatim";
+    field public static final String MULTIPLICITY_DUAL = "android.dual";
+    field public static final String MULTIPLICITY_PLURAL = "android.plural";
+    field public static final String MULTIPLICITY_SINGLE = "android.single";
+    field public static final String TYPE_CARDINAL = "android.type.cardinal";
+    field public static final String TYPE_DATE = "android.type.date";
+    field public static final String TYPE_DECIMAL = "android.type.decimal";
+    field public static final String TYPE_DIGITS = "android.type.digits";
+    field public static final String TYPE_ELECTRONIC = "android.type.electronic";
+    field public static final String TYPE_FRACTION = "android.type.fraction";
+    field public static final String TYPE_MEASURE = "android.type.measure";
+    field public static final String TYPE_MONEY = "android.type.money";
+    field public static final String TYPE_ORDINAL = "android.type.ordinal";
+    field public static final String TYPE_TELEPHONE = "android.type.telephone";
+    field public static final String TYPE_TEXT = "android.type.text";
+    field public static final String TYPE_TIME = "android.type.time";
+    field public static final String TYPE_VERBATIM = "android.type.verbatim";
     field public static final int WEEKDAY_FRIDAY = 6; // 0x6
     field public static final int WEEKDAY_MONDAY = 2; // 0x2
     field public static final int WEEKDAY_SATURDAY = 7; // 0x7
@@ -46664,175 +47056,175 @@
   }
 
   public static class TtsSpan.Builder<C extends android.text.style.TtsSpan.Builder<?>> {
-    ctor public TtsSpan.Builder(java.lang.String);
+    ctor public TtsSpan.Builder(String);
     method public android.text.style.TtsSpan build();
-    method public C setIntArgument(java.lang.String, int);
-    method public C setLongArgument(java.lang.String, long);
-    method public C setStringArgument(java.lang.String, java.lang.String);
+    method public C setIntArgument(String, int);
+    method public C setLongArgument(String, long);
+    method public C setStringArgument(String, String);
   }
 
-  public static class TtsSpan.CardinalBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+  public static class TtsSpan.CardinalBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.CardinalBuilder> {
     ctor public TtsSpan.CardinalBuilder();
     ctor public TtsSpan.CardinalBuilder(long);
-    ctor public TtsSpan.CardinalBuilder(java.lang.String);
+    ctor public TtsSpan.CardinalBuilder(String);
     method public android.text.style.TtsSpan.CardinalBuilder setNumber(long);
-    method public android.text.style.TtsSpan.CardinalBuilder setNumber(java.lang.String);
+    method public android.text.style.TtsSpan.CardinalBuilder setNumber(String);
   }
 
-  public static class TtsSpan.DateBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+  public static class TtsSpan.DateBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.DateBuilder> {
     ctor public TtsSpan.DateBuilder();
-    ctor public TtsSpan.DateBuilder(java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer);
+    ctor public TtsSpan.DateBuilder(Integer, Integer, Integer, Integer);
     method public android.text.style.TtsSpan.DateBuilder setDay(int);
     method public android.text.style.TtsSpan.DateBuilder setMonth(int);
     method public android.text.style.TtsSpan.DateBuilder setWeekday(int);
     method public android.text.style.TtsSpan.DateBuilder setYear(int);
   }
 
-  public static class TtsSpan.DecimalBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+  public static class TtsSpan.DecimalBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.DecimalBuilder> {
     ctor public TtsSpan.DecimalBuilder();
     ctor public TtsSpan.DecimalBuilder(double, int, int);
-    ctor public TtsSpan.DecimalBuilder(java.lang.String, java.lang.String);
+    ctor public TtsSpan.DecimalBuilder(String, String);
     method public android.text.style.TtsSpan.DecimalBuilder setArgumentsFromDouble(double, int, int);
-    method public android.text.style.TtsSpan.DecimalBuilder setFractionalPart(java.lang.String);
+    method public android.text.style.TtsSpan.DecimalBuilder setFractionalPart(String);
     method public android.text.style.TtsSpan.DecimalBuilder setIntegerPart(long);
-    method public android.text.style.TtsSpan.DecimalBuilder setIntegerPart(java.lang.String);
+    method public android.text.style.TtsSpan.DecimalBuilder setIntegerPart(String);
   }
 
-  public static class TtsSpan.DigitsBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+  public static class TtsSpan.DigitsBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.DigitsBuilder> {
     ctor public TtsSpan.DigitsBuilder();
-    ctor public TtsSpan.DigitsBuilder(java.lang.String);
-    method public android.text.style.TtsSpan.DigitsBuilder setDigits(java.lang.String);
+    ctor public TtsSpan.DigitsBuilder(String);
+    method public android.text.style.TtsSpan.DigitsBuilder setDigits(String);
   }
 
-  public static class TtsSpan.ElectronicBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+  public static class TtsSpan.ElectronicBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.ElectronicBuilder> {
     ctor public TtsSpan.ElectronicBuilder();
-    method public android.text.style.TtsSpan.ElectronicBuilder setDomain(java.lang.String);
-    method public android.text.style.TtsSpan.ElectronicBuilder setEmailArguments(java.lang.String, java.lang.String);
-    method public android.text.style.TtsSpan.ElectronicBuilder setFragmentId(java.lang.String);
-    method public android.text.style.TtsSpan.ElectronicBuilder setPassword(java.lang.String);
-    method public android.text.style.TtsSpan.ElectronicBuilder setPath(java.lang.String);
+    method public android.text.style.TtsSpan.ElectronicBuilder setDomain(String);
+    method public android.text.style.TtsSpan.ElectronicBuilder setEmailArguments(String, String);
+    method public android.text.style.TtsSpan.ElectronicBuilder setFragmentId(String);
+    method public android.text.style.TtsSpan.ElectronicBuilder setPassword(String);
+    method public android.text.style.TtsSpan.ElectronicBuilder setPath(String);
     method public android.text.style.TtsSpan.ElectronicBuilder setPort(int);
-    method public android.text.style.TtsSpan.ElectronicBuilder setProtocol(java.lang.String);
-    method public android.text.style.TtsSpan.ElectronicBuilder setQueryString(java.lang.String);
-    method public android.text.style.TtsSpan.ElectronicBuilder setUsername(java.lang.String);
+    method public android.text.style.TtsSpan.ElectronicBuilder setProtocol(String);
+    method public android.text.style.TtsSpan.ElectronicBuilder setQueryString(String);
+    method public android.text.style.TtsSpan.ElectronicBuilder setUsername(String);
   }
 
-  public static class TtsSpan.FractionBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+  public static class TtsSpan.FractionBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.FractionBuilder> {
     ctor public TtsSpan.FractionBuilder();
     ctor public TtsSpan.FractionBuilder(long, long, long);
     method public android.text.style.TtsSpan.FractionBuilder setDenominator(long);
-    method public android.text.style.TtsSpan.FractionBuilder setDenominator(java.lang.String);
+    method public android.text.style.TtsSpan.FractionBuilder setDenominator(String);
     method public android.text.style.TtsSpan.FractionBuilder setIntegerPart(long);
-    method public android.text.style.TtsSpan.FractionBuilder setIntegerPart(java.lang.String);
+    method public android.text.style.TtsSpan.FractionBuilder setIntegerPart(String);
     method public android.text.style.TtsSpan.FractionBuilder setNumerator(long);
-    method public android.text.style.TtsSpan.FractionBuilder setNumerator(java.lang.String);
+    method public android.text.style.TtsSpan.FractionBuilder setNumerator(String);
   }
 
-  public static class TtsSpan.MeasureBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+  public static class TtsSpan.MeasureBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.MeasureBuilder> {
     ctor public TtsSpan.MeasureBuilder();
     method public android.text.style.TtsSpan.MeasureBuilder setDenominator(long);
-    method public android.text.style.TtsSpan.MeasureBuilder setDenominator(java.lang.String);
-    method public android.text.style.TtsSpan.MeasureBuilder setFractionalPart(java.lang.String);
+    method public android.text.style.TtsSpan.MeasureBuilder setDenominator(String);
+    method public android.text.style.TtsSpan.MeasureBuilder setFractionalPart(String);
     method public android.text.style.TtsSpan.MeasureBuilder setIntegerPart(long);
-    method public android.text.style.TtsSpan.MeasureBuilder setIntegerPart(java.lang.String);
+    method public android.text.style.TtsSpan.MeasureBuilder setIntegerPart(String);
     method public android.text.style.TtsSpan.MeasureBuilder setNumber(long);
-    method public android.text.style.TtsSpan.MeasureBuilder setNumber(java.lang.String);
+    method public android.text.style.TtsSpan.MeasureBuilder setNumber(String);
     method public android.text.style.TtsSpan.MeasureBuilder setNumerator(long);
-    method public android.text.style.TtsSpan.MeasureBuilder setNumerator(java.lang.String);
-    method public android.text.style.TtsSpan.MeasureBuilder setUnit(java.lang.String);
+    method public android.text.style.TtsSpan.MeasureBuilder setNumerator(String);
+    method public android.text.style.TtsSpan.MeasureBuilder setUnit(String);
   }
 
-  public static class TtsSpan.MoneyBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+  public static class TtsSpan.MoneyBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.MoneyBuilder> {
     ctor public TtsSpan.MoneyBuilder();
-    method public android.text.style.TtsSpan.MoneyBuilder setCurrency(java.lang.String);
-    method public android.text.style.TtsSpan.MoneyBuilder setFractionalPart(java.lang.String);
+    method public android.text.style.TtsSpan.MoneyBuilder setCurrency(String);
+    method public android.text.style.TtsSpan.MoneyBuilder setFractionalPart(String);
     method public android.text.style.TtsSpan.MoneyBuilder setIntegerPart(long);
-    method public android.text.style.TtsSpan.MoneyBuilder setIntegerPart(java.lang.String);
-    method public android.text.style.TtsSpan.MoneyBuilder setQuantity(java.lang.String);
+    method public android.text.style.TtsSpan.MoneyBuilder setIntegerPart(String);
+    method public android.text.style.TtsSpan.MoneyBuilder setQuantity(String);
   }
 
-  public static class TtsSpan.OrdinalBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+  public static class TtsSpan.OrdinalBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.OrdinalBuilder> {
     ctor public TtsSpan.OrdinalBuilder();
     ctor public TtsSpan.OrdinalBuilder(long);
-    ctor public TtsSpan.OrdinalBuilder(java.lang.String);
+    ctor public TtsSpan.OrdinalBuilder(String);
     method public android.text.style.TtsSpan.OrdinalBuilder setNumber(long);
-    method public android.text.style.TtsSpan.OrdinalBuilder setNumber(java.lang.String);
+    method public android.text.style.TtsSpan.OrdinalBuilder setNumber(String);
   }
 
-  public static class TtsSpan.SemioticClassBuilder<C extends android.text.style.TtsSpan.SemioticClassBuilder<?>> extends android.text.style.TtsSpan.Builder {
-    ctor public TtsSpan.SemioticClassBuilder(java.lang.String);
-    method public C setAnimacy(java.lang.String);
-    method public C setCase(java.lang.String);
-    method public C setGender(java.lang.String);
-    method public C setMultiplicity(java.lang.String);
+  public static class TtsSpan.SemioticClassBuilder<C extends android.text.style.TtsSpan.SemioticClassBuilder<?>> extends android.text.style.TtsSpan.Builder<C> {
+    ctor public TtsSpan.SemioticClassBuilder(String);
+    method public C setAnimacy(String);
+    method public C setCase(String);
+    method public C setGender(String);
+    method public C setMultiplicity(String);
   }
 
-  public static class TtsSpan.TelephoneBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+  public static class TtsSpan.TelephoneBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.TelephoneBuilder> {
     ctor public TtsSpan.TelephoneBuilder();
-    ctor public TtsSpan.TelephoneBuilder(java.lang.String);
-    method public android.text.style.TtsSpan.TelephoneBuilder setCountryCode(java.lang.String);
-    method public android.text.style.TtsSpan.TelephoneBuilder setExtension(java.lang.String);
-    method public android.text.style.TtsSpan.TelephoneBuilder setNumberParts(java.lang.String);
+    ctor public TtsSpan.TelephoneBuilder(String);
+    method public android.text.style.TtsSpan.TelephoneBuilder setCountryCode(String);
+    method public android.text.style.TtsSpan.TelephoneBuilder setExtension(String);
+    method public android.text.style.TtsSpan.TelephoneBuilder setNumberParts(String);
   }
 
-  public static class TtsSpan.TextBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+  public static class TtsSpan.TextBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.TextBuilder> {
     ctor public TtsSpan.TextBuilder();
-    ctor public TtsSpan.TextBuilder(java.lang.String);
-    method public android.text.style.TtsSpan.TextBuilder setText(java.lang.String);
+    ctor public TtsSpan.TextBuilder(String);
+    method public android.text.style.TtsSpan.TextBuilder setText(String);
   }
 
-  public static class TtsSpan.TimeBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+  public static class TtsSpan.TimeBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.TimeBuilder> {
     ctor public TtsSpan.TimeBuilder();
     ctor public TtsSpan.TimeBuilder(int, int);
     method public android.text.style.TtsSpan.TimeBuilder setHours(int);
     method public android.text.style.TtsSpan.TimeBuilder setMinutes(int);
   }
 
-  public static class TtsSpan.VerbatimBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+  public static class TtsSpan.VerbatimBuilder extends android.text.style.TtsSpan.SemioticClassBuilder<android.text.style.TtsSpan.VerbatimBuilder> {
     ctor public TtsSpan.VerbatimBuilder();
-    ctor public TtsSpan.VerbatimBuilder(java.lang.String);
-    method public android.text.style.TtsSpan.VerbatimBuilder setVerbatim(java.lang.String);
+    ctor public TtsSpan.VerbatimBuilder(String);
+    method public android.text.style.TtsSpan.VerbatimBuilder setVerbatim(String);
   }
 
   public class TypefaceSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
-    ctor public TypefaceSpan(java.lang.String);
-    ctor public TypefaceSpan(android.graphics.Typeface);
-    ctor public TypefaceSpan(android.os.Parcel);
+    ctor public TypefaceSpan(@Nullable String);
+    ctor public TypefaceSpan(@NonNull android.graphics.Typeface);
+    ctor public TypefaceSpan(@NonNull android.os.Parcel);
     method public int describeContents();
-    method public java.lang.String getFamily();
+    method @Nullable public String getFamily();
     method public int getSpanTypeId();
-    method public android.graphics.Typeface getTypeface();
-    method public void updateDrawState(android.text.TextPaint);
-    method public void updateMeasureState(android.text.TextPaint);
-    method public void writeToParcel(android.os.Parcel, int);
+    method @Nullable public android.graphics.Typeface getTypeface();
+    method public void updateDrawState(@NonNull android.text.TextPaint);
+    method public void updateMeasureState(@NonNull android.text.TextPaint);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
   }
 
   public class URLSpan extends android.text.style.ClickableSpan implements android.text.ParcelableSpan {
-    ctor public URLSpan(java.lang.String);
-    ctor public URLSpan(android.os.Parcel);
+    ctor public URLSpan(String);
+    ctor public URLSpan(@NonNull android.os.Parcel);
     method public int describeContents();
     method public int getSpanTypeId();
-    method public java.lang.String getURL();
+    method public String getURL();
     method public void onClick(android.view.View);
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
   }
 
   public class UnderlineSpan extends android.text.style.CharacterStyle implements android.text.ParcelableSpan android.text.style.UpdateAppearance {
     ctor public UnderlineSpan();
-    ctor public UnderlineSpan(android.os.Parcel);
+    ctor public UnderlineSpan(@NonNull android.os.Parcel);
     method public int describeContents();
     method public int getSpanTypeId();
-    method public void updateDrawState(android.text.TextPaint);
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void updateDrawState(@NonNull android.text.TextPaint);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
   }
 
-  public abstract interface UpdateAppearance {
+  public interface UpdateAppearance {
   }
 
-  public abstract interface UpdateLayout implements android.text.style.UpdateAppearance {
+  public interface UpdateLayout extends android.text.style.UpdateAppearance {
   }
 
-  public abstract interface WrapTogetherSpan implements android.text.style.ParagraphStyle {
+  public interface WrapTogetherSpan extends android.text.style.ParagraphStyle {
   }
 
 }
@@ -46841,19 +47233,19 @@
 
   public class Linkify {
     ctor public Linkify();
-    method public static final boolean addLinks(android.text.Spannable, int);
-    method public static final boolean addLinks(android.text.Spannable, int, android.text.util.Linkify.UrlSpanFactory);
-    method public static final boolean addLinks(android.widget.TextView, int);
-    method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String);
-    method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
-    method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
-    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String);
-    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
-    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
-    method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter, android.text.util.Linkify.UrlSpanFactory);
+    method public static final boolean addLinks(@NonNull android.text.Spannable, int);
+    method public static final boolean addLinks(@NonNull android.text.Spannable, int, @Nullable java.util.function.Function<java.lang.String,android.text.style.URLSpan>);
+    method public static final boolean addLinks(@NonNull android.widget.TextView, int);
+    method public static final void addLinks(@NonNull android.widget.TextView, @NonNull java.util.regex.Pattern, @Nullable String);
+    method public static final void addLinks(@NonNull android.widget.TextView, @NonNull java.util.regex.Pattern, @Nullable String, @Nullable android.text.util.Linkify.MatchFilter, @Nullable android.text.util.Linkify.TransformFilter);
+    method public static final void addLinks(@NonNull android.widget.TextView, @NonNull java.util.regex.Pattern, @Nullable String, @Nullable String[], @Nullable android.text.util.Linkify.MatchFilter, @Nullable android.text.util.Linkify.TransformFilter);
+    method public static final boolean addLinks(@NonNull android.text.Spannable, @NonNull java.util.regex.Pattern, @Nullable String);
+    method public static final boolean addLinks(@NonNull android.text.Spannable, @NonNull java.util.regex.Pattern, @Nullable String, @Nullable android.text.util.Linkify.MatchFilter, @Nullable android.text.util.Linkify.TransformFilter);
+    method public static final boolean addLinks(@NonNull android.text.Spannable, @NonNull java.util.regex.Pattern, @Nullable String, @Nullable String[], @Nullable android.text.util.Linkify.MatchFilter, @Nullable android.text.util.Linkify.TransformFilter);
+    method public static final boolean addLinks(@NonNull android.text.Spannable, @NonNull java.util.regex.Pattern, @Nullable String, @Nullable String[], @Nullable android.text.util.Linkify.MatchFilter, @Nullable android.text.util.Linkify.TransformFilter, @Nullable java.util.function.Function<java.lang.String,android.text.style.URLSpan>);
     field public static final int ALL = 15; // 0xf
     field public static final int EMAIL_ADDRESSES = 2; // 0x2
-    field public static final deprecated int MAP_ADDRESSES = 8; // 0x8
+    field @Deprecated public static final int MAP_ADDRESSES = 8; // 0x8
     field public static final int PHONE_NUMBERS = 4; // 0x4
     field public static final int WEB_URLS = 1; // 0x1
     field public static final android.text.util.Linkify.MatchFilter sPhoneNumberMatchFilter;
@@ -46861,39 +47253,34 @@
     field public static final android.text.util.Linkify.MatchFilter sUrlMatchFilter;
   }
 
-  public static abstract interface Linkify.MatchFilter {
-    method public abstract boolean acceptMatch(java.lang.CharSequence, int, int);
+  public static interface Linkify.MatchFilter {
+    method public boolean acceptMatch(CharSequence, int, int);
   }
 
-  public static abstract interface Linkify.TransformFilter {
-    method public abstract java.lang.String transformUrl(java.util.regex.Matcher, java.lang.String);
-  }
-
-  public static class Linkify.UrlSpanFactory {
-    ctor public Linkify.UrlSpanFactory();
-    method public android.text.style.URLSpan create(java.lang.String);
+  public static interface Linkify.TransformFilter {
+    method public String transformUrl(java.util.regex.Matcher, String);
   }
 
   public class Rfc822Token {
-    ctor public Rfc822Token(java.lang.String, java.lang.String, java.lang.String);
-    method public java.lang.String getAddress();
-    method public java.lang.String getComment();
-    method public java.lang.String getName();
-    method public static java.lang.String quoteComment(java.lang.String);
-    method public static java.lang.String quoteName(java.lang.String);
-    method public static java.lang.String quoteNameIfNecessary(java.lang.String);
-    method public void setAddress(java.lang.String);
-    method public void setComment(java.lang.String);
-    method public void setName(java.lang.String);
+    ctor public Rfc822Token(@Nullable String, @Nullable String, @Nullable String);
+    method @Nullable public String getAddress();
+    method @Nullable public String getComment();
+    method @Nullable public String getName();
+    method public static String quoteComment(String);
+    method public static String quoteName(String);
+    method public static String quoteNameIfNecessary(String);
+    method public void setAddress(@Nullable String);
+    method public void setComment(@Nullable String);
+    method public void setName(@Nullable String);
   }
 
   public class Rfc822Tokenizer implements android.widget.MultiAutoCompleteTextView.Tokenizer {
     ctor public Rfc822Tokenizer();
-    method public int findTokenEnd(java.lang.CharSequence, int);
-    method public int findTokenStart(java.lang.CharSequence, int);
-    method public java.lang.CharSequence terminateToken(java.lang.CharSequence);
-    method public static void tokenize(java.lang.CharSequence, java.util.Collection<android.text.util.Rfc822Token>);
-    method public static android.text.util.Rfc822Token[] tokenize(java.lang.CharSequence);
+    method public int findTokenEnd(CharSequence, int);
+    method public int findTokenStart(CharSequence, int);
+    method public CharSequence terminateToken(CharSequence);
+    method public static void tokenize(CharSequence, java.util.Collection<android.text.util.Rfc822Token>);
+    method public static android.text.util.Rfc822Token[] tokenize(CharSequence);
   }
 
 }
@@ -46923,7 +47310,7 @@
     method public void captureEndValues(android.transition.TransitionValues);
     method public void captureStartValues(android.transition.TransitionValues);
     method public boolean getResizeClip();
-    method public deprecated void setReparent(boolean);
+    method @Deprecated public void setReparent(boolean);
     method public void setResizeClip(boolean);
   }
 
@@ -46996,14 +47383,14 @@
   public final class Scene {
     ctor public Scene(android.view.ViewGroup);
     ctor public Scene(android.view.ViewGroup, android.view.View);
-    ctor public deprecated Scene(android.view.ViewGroup, android.view.ViewGroup);
+    ctor @Deprecated public Scene(android.view.ViewGroup, android.view.ViewGroup);
     method public void enter();
     method public void exit();
-    method public static android.transition.Scene getCurrentScene(android.view.ViewGroup);
+    method @Nullable public static android.transition.Scene getCurrentScene(@NonNull android.view.ViewGroup);
     method public static android.transition.Scene getSceneForLayout(android.view.ViewGroup, int, android.content.Context);
     method public android.view.ViewGroup getSceneRoot();
-    method public void setEnterAction(java.lang.Runnable);
-    method public void setExitAction(java.lang.Runnable);
+    method public void setEnterAction(Runnable);
+    method public void setExitAction(Runnable);
   }
 
   public class SidePropagation extends android.transition.VisibilityPropagation {
@@ -47026,8 +47413,8 @@
     ctor public Transition(android.content.Context, android.util.AttributeSet);
     method public android.transition.Transition addListener(android.transition.Transition.TransitionListener);
     method public android.transition.Transition addTarget(int);
-    method public android.transition.Transition addTarget(java.lang.String);
-    method public android.transition.Transition addTarget(java.lang.Class);
+    method public android.transition.Transition addTarget(String);
+    method public android.transition.Transition addTarget(Class);
     method public android.transition.Transition addTarget(android.view.View);
     method public boolean canRemoveViews();
     method public abstract void captureEndValues(android.transition.TransitionValues);
@@ -47036,16 +47423,16 @@
     method public android.animation.Animator createAnimator(android.view.ViewGroup, android.transition.TransitionValues, android.transition.TransitionValues);
     method public android.transition.Transition excludeChildren(int, boolean);
     method public android.transition.Transition excludeChildren(android.view.View, boolean);
-    method public android.transition.Transition excludeChildren(java.lang.Class, boolean);
+    method public android.transition.Transition excludeChildren(Class, boolean);
     method public android.transition.Transition excludeTarget(int, boolean);
-    method public android.transition.Transition excludeTarget(java.lang.String, boolean);
+    method public android.transition.Transition excludeTarget(String, boolean);
     method public android.transition.Transition excludeTarget(android.view.View, boolean);
-    method public android.transition.Transition excludeTarget(java.lang.Class, boolean);
+    method public android.transition.Transition excludeTarget(Class, boolean);
     method public long getDuration();
     method public android.graphics.Rect getEpicenter();
     method public android.transition.Transition.EpicenterCallback getEpicenterCallback();
     method public android.animation.TimeInterpolator getInterpolator();
-    method public java.lang.String getName();
+    method public String getName();
     method public android.transition.PathMotion getPathMotion();
     method public android.transition.TransitionPropagation getPropagation();
     method public long getStartDelay();
@@ -47053,14 +47440,14 @@
     method public java.util.List<java.lang.String> getTargetNames();
     method public java.util.List<java.lang.Class> getTargetTypes();
     method public java.util.List<android.view.View> getTargets();
-    method public java.lang.String[] getTransitionProperties();
+    method public String[] getTransitionProperties();
     method public android.transition.TransitionValues getTransitionValues(android.view.View, boolean);
-    method public boolean isTransitionRequired(android.transition.TransitionValues, android.transition.TransitionValues);
+    method public boolean isTransitionRequired(@Nullable android.transition.TransitionValues, @Nullable android.transition.TransitionValues);
     method public android.transition.Transition removeListener(android.transition.Transition.TransitionListener);
     method public android.transition.Transition removeTarget(int);
-    method public android.transition.Transition removeTarget(java.lang.String);
+    method public android.transition.Transition removeTarget(String);
     method public android.transition.Transition removeTarget(android.view.View);
-    method public android.transition.Transition removeTarget(java.lang.Class);
+    method public android.transition.Transition removeTarget(Class);
     method public android.transition.Transition setDuration(long);
     method public void setEpicenterCallback(android.transition.Transition.EpicenterCallback);
     method public android.transition.Transition setInterpolator(android.animation.TimeInterpolator);
@@ -47074,23 +47461,23 @@
     field public static final int MATCH_NAME = 2; // 0x2
   }
 
-  public static abstract class Transition.EpicenterCallback {
+  public abstract static class Transition.EpicenterCallback {
     ctor public Transition.EpicenterCallback();
     method public abstract android.graphics.Rect onGetEpicenter(android.transition.Transition);
   }
 
-  public static abstract interface Transition.TransitionListener {
-    method public abstract void onTransitionCancel(android.transition.Transition);
-    method public abstract void onTransitionEnd(android.transition.Transition);
-    method public abstract void onTransitionPause(android.transition.Transition);
-    method public abstract void onTransitionResume(android.transition.Transition);
-    method public abstract void onTransitionStart(android.transition.Transition);
+  public static interface Transition.TransitionListener {
+    method public void onTransitionCancel(android.transition.Transition);
+    method public void onTransitionEnd(android.transition.Transition);
+    method public void onTransitionPause(android.transition.Transition);
+    method public void onTransitionResume(android.transition.Transition);
+    method public void onTransitionStart(android.transition.Transition);
   }
 
   public class TransitionInflater {
     method public static android.transition.TransitionInflater from(android.content.Context);
-    method public android.transition.Transition inflateTransition(int);
-    method public android.transition.TransitionManager inflateTransitionManager(int, android.view.ViewGroup);
+    method public android.transition.Transition inflateTransition(@TransitionRes int);
+    method public android.transition.TransitionManager inflateTransitionManager(@TransitionRes int, android.view.ViewGroup);
   }
 
   public abstract class TransitionListenerAdapter implements android.transition.Transition.TransitionListener {
@@ -47117,7 +47504,7 @@
   public abstract class TransitionPropagation {
     ctor public TransitionPropagation();
     method public abstract void captureValues(android.transition.TransitionValues);
-    method public abstract java.lang.String[] getPropagationProperties();
+    method public abstract String[] getPropagationProperties();
     method public abstract long getStartDelay(android.view.ViewGroup, android.transition.Transition, android.transition.TransitionValues, android.transition.TransitionValues);
   }
 
@@ -47127,8 +47514,8 @@
     method public android.transition.TransitionSet addListener(android.transition.Transition.TransitionListener);
     method public android.transition.TransitionSet addTarget(android.view.View);
     method public android.transition.TransitionSet addTarget(int);
-    method public android.transition.TransitionSet addTarget(java.lang.String);
-    method public android.transition.TransitionSet addTarget(java.lang.Class);
+    method public android.transition.TransitionSet addTarget(String);
+    method public android.transition.TransitionSet addTarget(Class);
     method public android.transition.TransitionSet addTransition(android.transition.Transition);
     method public void captureEndValues(android.transition.TransitionValues);
     method public void captureStartValues(android.transition.TransitionValues);
@@ -47139,8 +47526,8 @@
     method public android.transition.TransitionSet removeListener(android.transition.Transition.TransitionListener);
     method public android.transition.TransitionSet removeTarget(int);
     method public android.transition.TransitionSet removeTarget(android.view.View);
-    method public android.transition.TransitionSet removeTarget(java.lang.Class);
-    method public android.transition.TransitionSet removeTarget(java.lang.String);
+    method public android.transition.TransitionSet removeTarget(Class);
+    method public android.transition.TransitionSet removeTarget(String);
     method public android.transition.TransitionSet removeTransition(android.transition.Transition);
     method public android.transition.TransitionSet setDuration(long);
     method public android.transition.TransitionSet setInterpolator(android.animation.TimeInterpolator);
@@ -47151,10 +47538,10 @@
   }
 
   public class TransitionValues {
-    ctor public deprecated TransitionValues();
-    ctor public TransitionValues(android.view.View);
-    field public final java.util.Map<java.lang.String, java.lang.Object> values;
-    field public android.view.View view;
+    ctor @Deprecated public TransitionValues();
+    ctor public TransitionValues(@NonNull android.view.View);
+    field @NonNull public final java.util.Map<java.lang.String,java.lang.Object> values;
+    field @NonNull public android.view.View view;
   }
 
   public abstract class Visibility extends android.transition.Transition {
@@ -47176,7 +47563,7 @@
   public abstract class VisibilityPropagation extends android.transition.TransitionPropagation {
     ctor public VisibilityPropagation();
     method public void captureValues(android.transition.TransitionValues);
-    method public java.lang.String[] getPropagationProperties();
+    method public String[] getPropagationProperties();
     method public int getViewVisibility(android.transition.TransitionValues);
     method public int getViewX(android.transition.TransitionValues);
     method public int getViewY(android.transition.TransitionValues);
@@ -47188,38 +47575,38 @@
 
   public class AndroidException extends java.lang.Exception {
     ctor public AndroidException();
-    ctor public AndroidException(java.lang.String);
-    ctor public AndroidException(java.lang.String, java.lang.Throwable);
-    ctor public AndroidException(java.lang.Exception);
+    ctor public AndroidException(String);
+    ctor public AndroidException(String, Throwable);
+    ctor public AndroidException(Exception);
   }
 
   public class AndroidRuntimeException extends java.lang.RuntimeException {
     ctor public AndroidRuntimeException();
-    ctor public AndroidRuntimeException(java.lang.String);
-    ctor public AndroidRuntimeException(java.lang.String, java.lang.Throwable);
-    ctor public AndroidRuntimeException(java.lang.Exception);
+    ctor public AndroidRuntimeException(String);
+    ctor public AndroidRuntimeException(String, Throwable);
+    ctor public AndroidRuntimeException(Exception);
   }
 
-  public final class ArrayMap<K, V> implements java.util.Map {
+  public final class ArrayMap<K, V> implements java.util.Map<K,V> {
     ctor public ArrayMap();
     ctor public ArrayMap(int);
-    ctor public ArrayMap(android.util.ArrayMap<K, V>);
+    ctor public ArrayMap(android.util.ArrayMap<K,V>);
     method public void clear();
     method public boolean containsAll(java.util.Collection<?>);
-    method public boolean containsKey(java.lang.Object);
-    method public boolean containsValue(java.lang.Object);
+    method public boolean containsKey(Object);
+    method public boolean containsValue(Object);
     method public void ensureCapacity(int);
-    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
-    method public V get(java.lang.Object);
-    method public int indexOfKey(java.lang.Object);
-    method public int indexOfValue(java.lang.Object);
+    method public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
+    method public V get(Object);
+    method public int indexOfKey(Object);
+    method public int indexOfValue(Object);
     method public boolean isEmpty();
     method public K keyAt(int);
     method public java.util.Set<K> keySet();
     method public V put(K, V);
-    method public void putAll(android.util.ArrayMap<? extends K, ? extends V>);
-    method public void putAll(java.util.Map<? extends K, ? extends V>);
-    method public V remove(java.lang.Object);
+    method public void putAll(android.util.ArrayMap<? extends K,? extends V>);
+    method public void putAll(java.util.Map<? extends K,? extends V>);
+    method public V remove(Object);
     method public boolean removeAll(java.util.Collection<?>);
     method public V removeAt(int);
     method public boolean retainAll(java.util.Collection<?>);
@@ -47229,7 +47616,7 @@
     method public java.util.Collection<V> values();
   }
 
-  public final class ArraySet<E> implements java.util.Collection java.util.Set {
+  public final class ArraySet<E> implements java.util.Collection<E> java.util.Set<E> {
     ctor public ArraySet();
     ctor public ArraySet(int);
     ctor public ArraySet(android.util.ArraySet<E>);
@@ -47238,19 +47625,19 @@
     method public void addAll(android.util.ArraySet<? extends E>);
     method public boolean addAll(java.util.Collection<? extends E>);
     method public void clear();
-    method public boolean contains(java.lang.Object);
+    method public boolean contains(Object);
     method public boolean containsAll(java.util.Collection<?>);
     method public void ensureCapacity(int);
-    method public int indexOf(java.lang.Object);
+    method public int indexOf(Object);
     method public boolean isEmpty();
     method public java.util.Iterator<E> iterator();
-    method public boolean remove(java.lang.Object);
+    method public boolean remove(Object);
     method public boolean removeAll(android.util.ArraySet<? extends E>);
     method public boolean removeAll(java.util.Collection<?>);
     method public E removeAt(int);
     method public boolean retainAll(java.util.Collection<?>);
     method public int size();
-    method public java.lang.Object[] toArray();
+    method public Object[] toArray();
     method public <T> T[] toArray(T[]);
     method public E valueAt(int);
   }
@@ -47266,40 +47653,40 @@
     method public java.io.FileOutputStream startWrite() throws java.io.IOException;
   }
 
-  public abstract interface AttributeSet {
-    method public abstract boolean getAttributeBooleanValue(java.lang.String, java.lang.String, boolean);
-    method public abstract boolean getAttributeBooleanValue(int, boolean);
-    method public abstract int getAttributeCount();
-    method public abstract float getAttributeFloatValue(java.lang.String, java.lang.String, float);
-    method public abstract float getAttributeFloatValue(int, float);
-    method public abstract int getAttributeIntValue(java.lang.String, java.lang.String, int);
-    method public abstract int getAttributeIntValue(int, int);
-    method public abstract int getAttributeListValue(java.lang.String, java.lang.String, java.lang.String[], int);
-    method public abstract int getAttributeListValue(int, java.lang.String[], int);
-    method public abstract java.lang.String getAttributeName(int);
-    method public abstract int getAttributeNameResource(int);
-    method public default java.lang.String getAttributeNamespace(int);
-    method public abstract int getAttributeResourceValue(java.lang.String, java.lang.String, int);
-    method public abstract int getAttributeResourceValue(int, int);
-    method public abstract int getAttributeUnsignedIntValue(java.lang.String, java.lang.String, int);
-    method public abstract int getAttributeUnsignedIntValue(int, int);
-    method public abstract java.lang.String getAttributeValue(int);
-    method public abstract java.lang.String getAttributeValue(java.lang.String, java.lang.String);
-    method public abstract java.lang.String getClassAttribute();
-    method public abstract java.lang.String getIdAttribute();
-    method public abstract int getIdAttributeResourceValue(int);
-    method public abstract java.lang.String getPositionDescription();
-    method public abstract int getStyleAttribute();
+  public interface AttributeSet {
+    method public boolean getAttributeBooleanValue(String, String, boolean);
+    method public boolean getAttributeBooleanValue(int, boolean);
+    method public int getAttributeCount();
+    method public float getAttributeFloatValue(String, String, float);
+    method public float getAttributeFloatValue(int, float);
+    method public int getAttributeIntValue(String, String, int);
+    method public int getAttributeIntValue(int, int);
+    method public int getAttributeListValue(String, String, String[], int);
+    method public int getAttributeListValue(int, String[], int);
+    method public String getAttributeName(int);
+    method public int getAttributeNameResource(int);
+    method public default String getAttributeNamespace(int);
+    method public int getAttributeResourceValue(String, String, int);
+    method public int getAttributeResourceValue(int, int);
+    method public int getAttributeUnsignedIntValue(String, String, int);
+    method public int getAttributeUnsignedIntValue(int, int);
+    method public String getAttributeValue(int);
+    method public String getAttributeValue(String, String);
+    method public String getClassAttribute();
+    method public String getIdAttribute();
+    method public int getIdAttributeResourceValue(int);
+    method public String getPositionDescription();
+    method public int getStyleAttribute();
   }
 
   public class Base64 {
-    method public static byte[] decode(java.lang.String, int);
+    method public static byte[] decode(String, int);
     method public static byte[] decode(byte[], int);
     method public static byte[] decode(byte[], int, int, int);
     method public static byte[] encode(byte[], int);
     method public static byte[] encode(byte[], int, int, int);
-    method public static java.lang.String encodeToString(byte[], int);
-    method public static java.lang.String encodeToString(byte[], int, int, int);
+    method public static String encodeToString(byte[], int);
+    method public static String encodeToString(byte[], int, int, int);
     field public static final int CRLF = 4; // 0x4
     field public static final int DEFAULT = 0; // 0x0
     field public static final int NO_CLOSE = 16; // 0x10
@@ -47309,13 +47696,12 @@
   }
 
   public class Base64DataException extends java.io.IOException {
-    ctor public Base64DataException(java.lang.String);
+    ctor public Base64DataException(String);
   }
 
   public class Base64InputStream extends java.io.FilterInputStream {
     ctor public Base64InputStream(java.io.InputStream, int);
     method public int available();
-    method public void mark(int);
     method public void reset();
   }
 
@@ -47323,16 +47709,16 @@
     ctor public Base64OutputStream(java.io.OutputStream, int);
   }
 
-  public final deprecated class Config {
-    field public static final deprecated boolean DEBUG = false;
-    field public static final deprecated boolean LOGD = true;
-    field public static final deprecated boolean LOGV = false;
-    field public static final deprecated boolean PROFILE = false;
-    field public static final deprecated boolean RELEASE = true;
+  @Deprecated public final class Config {
+    field @Deprecated public static final boolean DEBUG = false;
+    field @Deprecated public static final boolean LOGD = true;
+    field @Deprecated public static final boolean LOGV = false;
+    field @Deprecated public static final boolean PROFILE = false;
+    field @Deprecated public static final boolean RELEASE = true;
   }
 
   public class DebugUtils {
-    method public static boolean isObjectSelected(java.lang.Object);
+    method public static boolean isObjectSelected(Object);
   }
 
   public class DisplayMetrics {
@@ -47369,108 +47755,108 @@
   }
 
   public class EventLog {
-    method public static int getTagCode(java.lang.String);
-    method public static java.lang.String getTagName(int);
+    method public static int getTagCode(String);
+    method public static String getTagName(int);
     method public static void readEvents(int[], java.util.Collection<android.util.EventLog.Event>) throws java.io.IOException;
     method public static int writeEvent(int, int);
     method public static int writeEvent(int, long);
     method public static int writeEvent(int, float);
-    method public static int writeEvent(int, java.lang.String);
+    method public static int writeEvent(int, String);
     method public static int writeEvent(int, java.lang.Object...);
   }
 
   public static final class EventLog.Event {
-    method public synchronized java.lang.Object getData();
+    method public Object getData();
     method public int getProcessId();
     method public int getTag();
     method public int getThreadId();
     method public long getTimeNanos();
   }
 
-  public deprecated class EventLogTags {
-    ctor public EventLogTags() throws java.io.IOException;
-    ctor public EventLogTags(java.io.BufferedReader) throws java.io.IOException;
-    method public android.util.EventLogTags.Description get(java.lang.String);
-    method public android.util.EventLogTags.Description get(int);
+  @Deprecated public class EventLogTags {
+    ctor @Deprecated public EventLogTags() throws java.io.IOException;
+    ctor @Deprecated public EventLogTags(java.io.BufferedReader) throws java.io.IOException;
+    method @Deprecated public android.util.EventLogTags.Description get(String);
+    method @Deprecated public android.util.EventLogTags.Description get(int);
   }
 
-  public static class EventLogTags.Description {
-    field public final java.lang.String mName;
-    field public final int mTag;
+  @Deprecated public static class EventLogTags.Description {
+    field @Deprecated public final String mName;
+    field @Deprecated public final int mTag;
   }
 
-  public deprecated class FloatMath {
+  @Deprecated public class FloatMath {
   }
 
-  public abstract class FloatProperty<T> extends android.util.Property {
-    ctor public FloatProperty(java.lang.String);
-    method public final void set(T, java.lang.Float);
+  public abstract class FloatProperty<T> extends android.util.Property<T,java.lang.Float> {
+    ctor public FloatProperty(String);
+    method public final void set(T, Float);
     method public abstract void setValue(T, float);
   }
 
-  public final class Half extends java.lang.Number implements java.lang.Comparable {
-    ctor public Half(short);
+  public final class Half extends java.lang.Number implements java.lang.Comparable<android.util.Half> {
+    ctor public Half(@HalfFloat short);
     ctor public Half(float);
     ctor public Half(double);
-    ctor public Half(java.lang.String) throws java.lang.NumberFormatException;
-    method public static short abs(short);
-    method public static short ceil(short);
-    method public static int compare(short, short);
-    method public int compareTo(android.util.Half);
-    method public static short copySign(short, short);
+    ctor public Half(@NonNull String) throws java.lang.NumberFormatException;
+    method @HalfFloat public static short abs(@HalfFloat short);
+    method @HalfFloat public static short ceil(@HalfFloat short);
+    method public static int compare(@HalfFloat short, @HalfFloat short);
+    method public int compareTo(@NonNull android.util.Half);
+    method @HalfFloat public static short copySign(@HalfFloat short, @HalfFloat short);
     method public double doubleValue();
-    method public static boolean equals(short, short);
+    method public static boolean equals(@HalfFloat short, @HalfFloat short);
     method public float floatValue();
-    method public static short floor(short);
-    method public static int getExponent(short);
-    method public static int getSign(short);
-    method public static int getSignificand(short);
-    method public static boolean greater(short, short);
-    method public static boolean greaterEquals(short, short);
-    method public static int halfToIntBits(short);
-    method public static int halfToRawIntBits(short);
-    method public static short halfToShortBits(short);
-    method public short halfValue();
-    method public static int hashCode(short);
-    method public static short intBitsToHalf(int);
+    method @HalfFloat public static short floor(@HalfFloat short);
+    method public static int getExponent(@HalfFloat short);
+    method public static int getSign(@HalfFloat short);
+    method public static int getSignificand(@HalfFloat short);
+    method public static boolean greater(@HalfFloat short, @HalfFloat short);
+    method public static boolean greaterEquals(@HalfFloat short, @HalfFloat short);
+    method public static int halfToIntBits(@HalfFloat short);
+    method public static int halfToRawIntBits(@HalfFloat short);
+    method @HalfFloat public static short halfToShortBits(@HalfFloat short);
+    method @HalfFloat public short halfValue();
+    method public static int hashCode(@HalfFloat short);
+    method @HalfFloat public static short intBitsToHalf(int);
     method public int intValue();
-    method public static boolean isInfinite(short);
+    method public static boolean isInfinite(@HalfFloat short);
     method public boolean isNaN();
-    method public static boolean isNaN(short);
-    method public static boolean isNormalized(short);
-    method public static boolean less(short, short);
-    method public static boolean lessEquals(short, short);
+    method public static boolean isNaN(@HalfFloat short);
+    method public static boolean isNormalized(@HalfFloat short);
+    method public static boolean less(@HalfFloat short, @HalfFloat short);
+    method public static boolean lessEquals(@HalfFloat short, @HalfFloat short);
     method public long longValue();
-    method public static short max(short, short);
-    method public static short min(short, short);
-    method public static short parseHalf(java.lang.String) throws java.lang.NumberFormatException;
-    method public static short round(short);
-    method public static float toFloat(short);
-    method public static short toHalf(float);
-    method public static java.lang.String toHexString(short);
-    method public static java.lang.String toString(short);
-    method public static short trunc(short);
-    method public static android.util.Half valueOf(short);
-    method public static android.util.Half valueOf(float);
-    method public static android.util.Half valueOf(java.lang.String);
-    field public static final short EPSILON = 5120; // 0x1400
-    field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
+    method @HalfFloat public static short max(@HalfFloat short, @HalfFloat short);
+    method @HalfFloat public static short min(@HalfFloat short, @HalfFloat short);
+    method @HalfFloat public static short parseHalf(@NonNull String) throws java.lang.NumberFormatException;
+    method @HalfFloat public static short round(@HalfFloat short);
+    method public static float toFloat(@HalfFloat short);
+    method @HalfFloat public static short toHalf(float);
+    method @NonNull public static String toHexString(@HalfFloat short);
+    method @NonNull public static String toString(@HalfFloat short);
+    method @HalfFloat public static short trunc(@HalfFloat short);
+    method @NonNull public static android.util.Half valueOf(@HalfFloat short);
+    method @NonNull public static android.util.Half valueOf(float);
+    method @NonNull public static android.util.Half valueOf(@NonNull String);
+    field @HalfFloat public static final short EPSILON = 5120; // 0x1400
+    field @HalfFloat public static final short LOWEST_VALUE = -1025; // 0xfffffbff
     field public static final int MAX_EXPONENT = 15; // 0xf
-    field public static final short MAX_VALUE = 31743; // 0x7bff
+    field @HalfFloat public static final short MAX_VALUE = 31743; // 0x7bff
     field public static final int MIN_EXPONENT = -14; // 0xfffffff2
-    field public static final short MIN_NORMAL = 1024; // 0x400
-    field public static final short MIN_VALUE = 1; // 0x1
-    field public static final short NEGATIVE_INFINITY = -1024; // 0xfffffc00
-    field public static final short NEGATIVE_ZERO = -32768; // 0xffff8000
-    field public static final short NaN = 32256; // 0x7e00
-    field public static final short POSITIVE_INFINITY = 31744; // 0x7c00
-    field public static final short POSITIVE_ZERO = 0; // 0x0
+    field @HalfFloat public static final short MIN_NORMAL = 1024; // 0x400
+    field @HalfFloat public static final short MIN_VALUE = 1; // 0x1
+    field @HalfFloat public static final short NEGATIVE_INFINITY = -1024; // 0xfffffc00
+    field @HalfFloat public static final short NEGATIVE_ZERO = -32768; // 0xffff8000
+    field @HalfFloat public static final short NaN = 32256; // 0x7e00
+    field @HalfFloat public static final short POSITIVE_INFINITY = 31744; // 0x7c00
+    field @HalfFloat public static final short POSITIVE_ZERO = 0; // 0x0
     field public static final int SIZE = 16; // 0x10
   }
 
-  public abstract class IntProperty<T> extends android.util.Property {
-    ctor public IntProperty(java.lang.String);
-    method public final void set(T, java.lang.Integer);
+  public abstract class IntProperty<T> extends android.util.Property<T,java.lang.Integer> {
+    ctor public IntProperty(String);
+    method public final void set(T, Integer);
     method public abstract void setValue(T, int);
   }
 
@@ -47487,17 +47873,15 @@
     method public double nextDouble() throws java.io.IOException;
     method public int nextInt() throws java.io.IOException;
     method public long nextLong() throws java.io.IOException;
-    method public java.lang.String nextName() throws java.io.IOException;
+    method public String nextName() throws java.io.IOException;
     method public void nextNull() throws java.io.IOException;
-    method public java.lang.String nextString() throws java.io.IOException;
+    method public String nextString() throws java.io.IOException;
     method public android.util.JsonToken peek() throws java.io.IOException;
     method public void setLenient(boolean);
     method public void skipValue() throws java.io.IOException;
   }
 
-  public final class JsonToken extends java.lang.Enum {
-    method public static android.util.JsonToken valueOf(java.lang.String);
-    method public static final android.util.JsonToken[] values();
+  public enum JsonToken {
     enum_constant public static final android.util.JsonToken BEGIN_ARRAY;
     enum_constant public static final android.util.JsonToken BEGIN_OBJECT;
     enum_constant public static final android.util.JsonToken BOOLEAN;
@@ -47519,15 +47903,15 @@
     method public android.util.JsonWriter endObject() throws java.io.IOException;
     method public void flush() throws java.io.IOException;
     method public boolean isLenient();
-    method public android.util.JsonWriter name(java.lang.String) throws java.io.IOException;
+    method public android.util.JsonWriter name(String) throws java.io.IOException;
     method public android.util.JsonWriter nullValue() throws java.io.IOException;
-    method public void setIndent(java.lang.String);
+    method public void setIndent(String);
     method public void setLenient(boolean);
-    method public android.util.JsonWriter value(java.lang.String) throws java.io.IOException;
+    method public android.util.JsonWriter value(String) throws java.io.IOException;
     method public android.util.JsonWriter value(boolean) throws java.io.IOException;
     method public android.util.JsonWriter value(double) throws java.io.IOException;
     method public android.util.JsonWriter value(long) throws java.io.IOException;
-    method public android.util.JsonWriter value(java.lang.Number) throws java.io.IOException;
+    method public android.util.JsonWriter value(Number) throws java.io.IOException;
   }
 
   public final class LayoutDirection {
@@ -47538,23 +47922,23 @@
   }
 
   public final class Log {
-    method public static int d(java.lang.String, java.lang.String);
-    method public static int d(java.lang.String, java.lang.String, java.lang.Throwable);
-    method public static int e(java.lang.String, java.lang.String);
-    method public static int e(java.lang.String, java.lang.String, java.lang.Throwable);
-    method public static java.lang.String getStackTraceString(java.lang.Throwable);
-    method public static int i(java.lang.String, java.lang.String);
-    method public static int i(java.lang.String, java.lang.String, java.lang.Throwable);
-    method public static boolean isLoggable(java.lang.String, int);
-    method public static int println(int, java.lang.String, java.lang.String);
-    method public static int v(java.lang.String, java.lang.String);
-    method public static int v(java.lang.String, java.lang.String, java.lang.Throwable);
-    method public static int w(java.lang.String, java.lang.String);
-    method public static int w(java.lang.String, java.lang.String, java.lang.Throwable);
-    method public static int w(java.lang.String, java.lang.Throwable);
-    method public static int wtf(java.lang.String, java.lang.String);
-    method public static int wtf(java.lang.String, java.lang.Throwable);
-    method public static int wtf(java.lang.String, java.lang.String, java.lang.Throwable);
+    method public static int d(@Nullable String, @NonNull String);
+    method public static int d(@Nullable String, @Nullable String, @Nullable Throwable);
+    method public static int e(@Nullable String, @NonNull String);
+    method public static int e(@Nullable String, @Nullable String, @Nullable Throwable);
+    method @NonNull public static String getStackTraceString(@Nullable Throwable);
+    method public static int i(@Nullable String, @NonNull String);
+    method public static int i(@Nullable String, @Nullable String, @Nullable Throwable);
+    method public static boolean isLoggable(@Nullable @Size(max=23, apis="..23") String, int);
+    method public static int println(int, @Nullable String, @NonNull String);
+    method public static int v(@Nullable String, @NonNull String);
+    method public static int v(@Nullable String, @Nullable String, @Nullable Throwable);
+    method public static int w(@Nullable String, @NonNull String);
+    method public static int w(@Nullable String, @Nullable String, @Nullable Throwable);
+    method public static int w(@Nullable String, @Nullable Throwable);
+    method public static int wtf(@Nullable String, @Nullable String);
+    method public static int wtf(@Nullable String, @NonNull Throwable);
+    method public static int wtf(@Nullable String, @Nullable String, @Nullable Throwable);
     field public static final int ASSERT = 7; // 0x7
     field public static final int DEBUG = 3; // 0x3
     field public static final int ERROR = 6; // 0x6
@@ -47564,8 +47948,8 @@
   }
 
   public class LogPrinter implements android.util.Printer {
-    ctor public LogPrinter(int, java.lang.String);
-    method public void println(java.lang.String);
+    ctor public LogPrinter(int, String);
+    method public void println(String);
   }
 
   public class LongSparseArray<E> implements java.lang.Cloneable {
@@ -47591,27 +47975,27 @@
   public class LruCache<K, V> {
     ctor public LruCache(int);
     method protected V create(K);
-    method public final synchronized int createCount();
+    method public final int createCount();
     method protected void entryRemoved(boolean, K, V, V);
     method public final void evictAll();
-    method public final synchronized int evictionCount();
+    method public final int evictionCount();
     method public final V get(K);
-    method public final synchronized int hitCount();
-    method public final synchronized int maxSize();
-    method public final synchronized int missCount();
+    method public final int hitCount();
+    method public final int maxSize();
+    method public final int missCount();
     method public final V put(K, V);
-    method public final synchronized int putCount();
+    method public final int putCount();
     method public final V remove(K);
     method public void resize(int);
-    method public final synchronized int size();
+    method public final int size();
     method protected int sizeOf(K, V);
-    method public final synchronized java.util.Map<K, V> snapshot();
-    method public final synchronized java.lang.String toString();
+    method public final java.util.Map<K,V> snapshot();
+    method public final String toString();
     method public void trimToSize(int);
   }
 
   public final class MalformedJsonException extends java.io.IOException {
-    ctor public MalformedJsonException(java.lang.String);
+    ctor public MalformedJsonException(String);
   }
 
   public class MonthDisplayHelper {
@@ -47632,92 +48016,92 @@
     method public void previousMonth();
   }
 
-  public final deprecated class MutableBoolean {
-    ctor public MutableBoolean(boolean);
-    field public boolean value;
+  @Deprecated public final class MutableBoolean {
+    ctor @Deprecated public MutableBoolean(boolean);
+    field @Deprecated public boolean value;
   }
 
-  public final deprecated class MutableByte {
-    ctor public MutableByte(byte);
-    field public byte value;
+  @Deprecated public final class MutableByte {
+    ctor @Deprecated public MutableByte(byte);
+    field @Deprecated public byte value;
   }
 
-  public final deprecated class MutableChar {
-    ctor public MutableChar(char);
-    field public char value;
+  @Deprecated public final class MutableChar {
+    ctor @Deprecated public MutableChar(char);
+    field @Deprecated public char value;
   }
 
-  public final deprecated class MutableDouble {
-    ctor public MutableDouble(double);
-    field public double value;
+  @Deprecated public final class MutableDouble {
+    ctor @Deprecated public MutableDouble(double);
+    field @Deprecated public double value;
   }
 
-  public final deprecated class MutableFloat {
-    ctor public MutableFloat(float);
-    field public float value;
+  @Deprecated public final class MutableFloat {
+    ctor @Deprecated public MutableFloat(float);
+    field @Deprecated public float value;
   }
 
-  public final deprecated class MutableInt {
-    ctor public MutableInt(int);
-    field public int value;
+  @Deprecated public final class MutableInt {
+    ctor @Deprecated public MutableInt(int);
+    field @Deprecated public int value;
   }
 
-  public final deprecated class MutableLong {
-    ctor public MutableLong(long);
-    field public long value;
+  @Deprecated public final class MutableLong {
+    ctor @Deprecated public MutableLong(long);
+    field @Deprecated public long value;
   }
 
-  public final deprecated class MutableShort {
-    ctor public MutableShort(short);
-    field public short value;
+  @Deprecated public final class MutableShort {
+    ctor @Deprecated public MutableShort(short);
+    field @Deprecated public short value;
   }
 
   public class NoSuchPropertyException extends java.lang.RuntimeException {
-    ctor public NoSuchPropertyException(java.lang.String);
+    ctor public NoSuchPropertyException(String);
   }
 
   public class Pair<F, S> {
     ctor public Pair(F, S);
-    method public static <A, B> android.util.Pair<A, B> create(A, B);
+    method public static <A, B> android.util.Pair<A,B> create(A, B);
     field public final F first;
     field public final S second;
   }
 
   public class Patterns {
-    method public static final java.lang.String concatGroups(java.util.regex.Matcher);
-    method public static final java.lang.String digitsAndPlusOnly(java.util.regex.Matcher);
+    method public static final String concatGroups(java.util.regex.Matcher);
+    method public static final String digitsAndPlusOnly(java.util.regex.Matcher);
     field public static final java.util.regex.Pattern DOMAIN_NAME;
     field public static final java.util.regex.Pattern EMAIL_ADDRESS;
-    field public static final deprecated java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
+    field @Deprecated public static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
     field public static final java.util.regex.Pattern IP_ADDRESS;
     field public static final java.util.regex.Pattern PHONE;
-    field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN;
-    field public static final deprecated java.lang.String TOP_LEVEL_DOMAIN_STR = "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(biz|b[abdefghijmnorstvwyz])|(cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(edu|e[cegrstu])|f[ijkmor]|(gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(info|int|i[delmnoqrst])|(jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(name|net|n[acefgilopruz])|(org|om)|(pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)|y[et]|z[amw])";
-    field public static final deprecated java.lang.String TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL = "(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(?:\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)|y[et]|z[amw]))";
+    field @Deprecated public static final java.util.regex.Pattern TOP_LEVEL_DOMAIN;
+    field @Deprecated public static final String TOP_LEVEL_DOMAIN_STR = "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(biz|b[abdefghijmnorstvwyz])|(cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(edu|e[cegrstu])|f[ijkmor]|(gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(info|int|i[delmnoqrst])|(jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(name|net|n[acefgilopruz])|(org|om)|(pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)|y[et]|z[amw])";
+    field @Deprecated public static final String TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL = "(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(?:\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)|y[et]|z[amw]))";
     field public static final java.util.regex.Pattern WEB_URL;
   }
 
   public class PrintStreamPrinter implements android.util.Printer {
     ctor public PrintStreamPrinter(java.io.PrintStream);
-    method public void println(java.lang.String);
+    method public void println(String);
   }
 
   public class PrintWriterPrinter implements android.util.Printer {
     ctor public PrintWriterPrinter(java.io.PrintWriter);
-    method public void println(java.lang.String);
+    method public void println(String);
   }
 
-  public abstract interface Printer {
-    method public abstract void println(java.lang.String);
+  public interface Printer {
+    method public void println(String);
   }
 
   public abstract class Property<T, V> {
-    ctor public Property(java.lang.Class<V>, java.lang.String);
+    ctor public Property(Class<V>, String);
     method public abstract V get(T);
-    method public java.lang.String getName();
-    method public java.lang.Class<V> getType();
+    method public String getName();
+    method public Class<V> getType();
     method public boolean isReadOnly();
-    method public static <T, V> android.util.Property<T, V> of(java.lang.Class<T>, java.lang.Class<V>, java.lang.String);
+    method public static <T, V> android.util.Property<T,V> of(Class<T>, Class<V>, String);
     method public void set(T, V);
   }
 
@@ -47736,7 +48120,7 @@
     method public android.util.Range<T> intersect(T, T);
   }
 
-  public final class Rational extends java.lang.Number implements java.lang.Comparable {
+  public final class Rational extends java.lang.Number implements java.lang.Comparable<android.util.Rational> {
     ctor public Rational(int, int);
     method public int compareTo(android.util.Rational);
     method public double doubleValue();
@@ -47749,7 +48133,7 @@
     method public boolean isNaN();
     method public boolean isZero();
     method public long longValue();
-    method public static android.util.Rational parseRational(java.lang.String) throws java.lang.NumberFormatException;
+    method public static android.util.Rational parseRational(String) throws java.lang.NumberFormatException;
     field public static final android.util.Rational NEGATIVE_INFINITY;
     field public static final android.util.Rational NaN;
     field public static final android.util.Rational POSITIVE_INFINITY;
@@ -47760,14 +48144,14 @@
     ctor public Size(int, int);
     method public int getHeight();
     method public int getWidth();
-    method public static android.util.Size parseSize(java.lang.String) throws java.lang.NumberFormatException;
+    method public static android.util.Size parseSize(String) throws java.lang.NumberFormatException;
   }
 
   public final class SizeF {
     ctor public SizeF(float, float);
     method public float getHeight();
     method public float getWidth();
-    method public static android.util.SizeF parseSizeF(java.lang.String) throws java.lang.NumberFormatException;
+    method public static android.util.SizeF parseSizeF(String) throws java.lang.NumberFormatException;
   }
 
   public class SparseArray<E> implements java.lang.Cloneable {
@@ -47848,7 +48232,7 @@
   }
 
   public class StateSet {
-    method public static java.lang.String dump(int[]);
+    method public static String dump(int[]);
     method public static boolean isWildCard(int[]);
     method public static boolean stateSetMatches(int[], int[]);
     method public static boolean stateSetMatches(int[], int);
@@ -47864,32 +48248,32 @@
   }
 
   public class StringBuilderPrinter implements android.util.Printer {
-    ctor public StringBuilderPrinter(java.lang.StringBuilder);
-    method public void println(java.lang.String);
+    ctor public StringBuilderPrinter(StringBuilder);
+    method public void println(String);
   }
 
   public class TimeFormatException extends java.lang.RuntimeException {
   }
 
   public class TimeUtils {
-    method public static java.util.TimeZone getTimeZone(int, boolean, long, java.lang.String);
-    method public static java.lang.String getTimeZoneDatabaseVersion();
-    method public static java.util.List<java.lang.String> getTimeZoneIdsForCountryCode(java.lang.String);
+    method public static java.util.TimeZone getTimeZone(int, boolean, long, String);
+    method public static String getTimeZoneDatabaseVersion();
+    method @Nullable public static java.util.List<java.lang.String> getTimeZoneIdsForCountryCode(@NonNull String);
   }
 
   public class TimingLogger {
-    ctor public TimingLogger(java.lang.String, java.lang.String);
-    method public void addSplit(java.lang.String);
+    ctor public TimingLogger(String, String);
+    method public void addSplit(String);
     method public void dumpToLog();
-    method public void reset(java.lang.String, java.lang.String);
+    method public void reset(String, String);
     method public void reset();
   }
 
   public class TypedValue {
     ctor public TypedValue();
     method public static float applyDimension(int, float, android.util.DisplayMetrics);
-    method public final java.lang.CharSequence coerceToString();
-    method public static final java.lang.String coerceToString(int, int);
+    method public final CharSequence coerceToString();
+    method public static final String coerceToString(int, int);
     method public static float complexToDimension(int, android.util.DisplayMetrics);
     method public static int complexToDimensionPixelOffset(int, android.util.DisplayMetrics);
     method public static int complexToDimensionPixelSize(int, android.util.DisplayMetrics);
@@ -47945,25 +48329,24 @@
     field public int changingConfigurations;
     field public int data;
     field public int density;
-    field public int resourceId;
-    field public java.lang.CharSequence string;
+    field @AnyRes public int resourceId;
+    field public int sourceStyleResourceId;
+    field public CharSequence string;
     field public int type;
   }
 
   public class Xml {
     method public static android.util.AttributeSet asAttributeSet(org.xmlpull.v1.XmlPullParser);
-    method public static android.util.Xml.Encoding findEncodingByName(java.lang.String) throws java.io.UnsupportedEncodingException;
+    method public static android.util.Xml.Encoding findEncodingByName(String) throws java.io.UnsupportedEncodingException;
     method public static org.xmlpull.v1.XmlPullParser newPullParser();
     method public static org.xmlpull.v1.XmlSerializer newSerializer();
-    method public static void parse(java.lang.String, org.xml.sax.ContentHandler) throws org.xml.sax.SAXException;
+    method public static void parse(String, org.xml.sax.ContentHandler) throws org.xml.sax.SAXException;
     method public static void parse(java.io.Reader, org.xml.sax.ContentHandler) throws java.io.IOException, org.xml.sax.SAXException;
     method public static void parse(java.io.InputStream, android.util.Xml.Encoding, org.xml.sax.ContentHandler) throws java.io.IOException, org.xml.sax.SAXException;
-    field public static java.lang.String FEATURE_RELAXED;
+    field public static String FEATURE_RELAXED;
   }
 
-  public static final class Xml.Encoding extends java.lang.Enum {
-    method public static android.util.Xml.Encoding valueOf(java.lang.String);
-    method public static final android.util.Xml.Encoding[] values();
+  public enum Xml.Encoding {
     enum_constant public static final android.util.Xml.Encoding ISO_8859_1;
     enum_constant public static final android.util.Xml.Encoding US_ASCII;
     enum_constant public static final android.util.Xml.Encoding UTF_16;
@@ -47977,7 +48360,7 @@
   public abstract class AbsSavedState implements android.os.Parcelable {
     ctor protected AbsSavedState(android.os.Parcelable);
     ctor protected AbsSavedState(android.os.Parcel);
-    ctor protected AbsSavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor protected AbsSavedState(android.os.Parcel, ClassLoader);
     method public int describeContents();
     method public final android.os.Parcelable getSuperState();
     method public void writeToParcel(android.os.Parcel, int);
@@ -47991,9 +48374,9 @@
     method public abstract android.view.View getCustomView();
     method public abstract android.view.Menu getMenu();
     method public abstract android.view.MenuInflater getMenuInflater();
-    method public abstract java.lang.CharSequence getSubtitle();
-    method public java.lang.Object getTag();
-    method public abstract java.lang.CharSequence getTitle();
+    method public abstract CharSequence getSubtitle();
+    method public Object getTag();
+    method public abstract CharSequence getTitle();
     method public boolean getTitleOptionalHint();
     method public int getType();
     method public void hide(long);
@@ -48002,11 +48385,11 @@
     method public boolean isTitleOptional();
     method public void onWindowFocusChanged(boolean);
     method public abstract void setCustomView(android.view.View);
-    method public abstract void setSubtitle(java.lang.CharSequence);
-    method public abstract void setSubtitle(int);
-    method public void setTag(java.lang.Object);
-    method public abstract void setTitle(java.lang.CharSequence);
-    method public abstract void setTitle(int);
+    method public abstract void setSubtitle(CharSequence);
+    method public abstract void setSubtitle(@StringRes int);
+    method public void setTag(Object);
+    method public abstract void setTitle(CharSequence);
+    method public abstract void setTitle(@StringRes int);
     method public void setTitleOptionalHint(boolean);
     method public void setType(int);
     field public static final int DEFAULT_HIDE_DURATION = -1; // 0xffffffff
@@ -48014,14 +48397,14 @@
     field public static final int TYPE_PRIMARY = 0; // 0x0
   }
 
-  public static abstract interface ActionMode.Callback {
-    method public abstract boolean onActionItemClicked(android.view.ActionMode, android.view.MenuItem);
-    method public abstract boolean onCreateActionMode(android.view.ActionMode, android.view.Menu);
-    method public abstract void onDestroyActionMode(android.view.ActionMode);
-    method public abstract boolean onPrepareActionMode(android.view.ActionMode, android.view.Menu);
+  public static interface ActionMode.Callback {
+    method public boolean onActionItemClicked(android.view.ActionMode, android.view.MenuItem);
+    method public boolean onCreateActionMode(android.view.ActionMode, android.view.Menu);
+    method public void onDestroyActionMode(android.view.ActionMode);
+    method public boolean onPrepareActionMode(android.view.ActionMode, android.view.Menu);
   }
 
-  public static abstract class ActionMode.Callback2 implements android.view.ActionMode.Callback {
+  public abstract static class ActionMode.Callback2 implements android.view.ActionMode.Callback {
     ctor public ActionMode.Callback2();
     method public void onGetContentRect(android.view.ActionMode, android.view.View, android.graphics.Rect);
   }
@@ -48030,7 +48413,7 @@
     ctor public ActionProvider(android.content.Context);
     method public boolean hasSubMenu();
     method public boolean isVisible();
-    method public abstract deprecated android.view.View onCreateActionView();
+    method @Deprecated public abstract android.view.View onCreateActionView();
     method public android.view.View onCreateActionView(android.view.MenuItem);
     method public boolean onPerformDefaultAction();
     method public void onPrepareSubMenu(android.view.SubMenu);
@@ -48039,8 +48422,8 @@
     method public void setVisibilityListener(android.view.ActionProvider.VisibilityListener);
   }
 
-  public static abstract interface ActionProvider.VisibilityListener {
-    method public abstract void onActionProviderVisibilityChanged(boolean);
+  public static interface ActionProvider.VisibilityListener {
+    method public void onActionProviderVisibilityChanged(boolean);
   }
 
   public final class Choreographer {
@@ -48050,30 +48433,30 @@
     method public void removeFrameCallback(android.view.Choreographer.FrameCallback);
   }
 
-  public static abstract interface Choreographer.FrameCallback {
-    method public abstract void doFrame(long);
+  public static interface Choreographer.FrameCallback {
+    method public void doFrame(long);
   }
 
-  public abstract interface CollapsibleActionView {
-    method public abstract void onActionViewCollapsed();
-    method public abstract void onActionViewExpanded();
+  public interface CollapsibleActionView {
+    method public void onActionViewCollapsed();
+    method public void onActionViewExpanded();
   }
 
-  public abstract interface ContextMenu implements android.view.Menu {
-    method public abstract void clearHeader();
-    method public abstract android.view.ContextMenu setHeaderIcon(int);
-    method public abstract android.view.ContextMenu setHeaderIcon(android.graphics.drawable.Drawable);
-    method public abstract android.view.ContextMenu setHeaderTitle(int);
-    method public abstract android.view.ContextMenu setHeaderTitle(java.lang.CharSequence);
-    method public abstract android.view.ContextMenu setHeaderView(android.view.View);
+  public interface ContextMenu extends android.view.Menu {
+    method public void clearHeader();
+    method public android.view.ContextMenu setHeaderIcon(@DrawableRes int);
+    method public android.view.ContextMenu setHeaderIcon(android.graphics.drawable.Drawable);
+    method public android.view.ContextMenu setHeaderTitle(@StringRes int);
+    method public android.view.ContextMenu setHeaderTitle(CharSequence);
+    method public android.view.ContextMenu setHeaderView(android.view.View);
   }
 
-  public static abstract interface ContextMenu.ContextMenuInfo {
+  public static interface ContextMenu.ContextMenuInfo {
   }
 
   public class ContextThemeWrapper extends android.content.ContextWrapper {
     ctor public ContextThemeWrapper();
-    ctor public ContextThemeWrapper(android.content.Context, int);
+    ctor public ContextThemeWrapper(android.content.Context, @StyleRes int);
     ctor public ContextThemeWrapper(android.content.Context, android.content.res.Resources.Theme);
     method public void applyOverrideConfiguration(android.content.res.Configuration);
     method protected void onApplyThemeResource(android.content.res.Resources.Theme, int, boolean);
@@ -48082,16 +48465,16 @@
   public final class Display {
     method public long getAppVsyncOffsetNanos();
     method public void getCurrentSizeRange(android.graphics.Point, android.graphics.Point);
-    method public android.view.DisplayCutout getCutout();
+    method @Nullable public android.view.DisplayCutout getCutout();
     method public int getDisplayId();
     method public int getFlags();
     method public android.view.Display.HdrCapabilities getHdrCapabilities();
-    method public deprecated int getHeight();
+    method @Deprecated public int getHeight();
     method public void getMetrics(android.util.DisplayMetrics);
     method public android.view.Display.Mode getMode();
-    method public java.lang.String getName();
-    method public deprecated int getOrientation();
-    method public deprecated int getPixelFormat();
+    method public String getName();
+    method @Deprecated public int getOrientation();
+    method @Deprecated public int getPixelFormat();
     method public long getPresentationDeadlineNanos();
     method public void getRealMetrics(android.util.DisplayMetrics);
     method public void getRealSize(android.graphics.Point);
@@ -48101,8 +48484,8 @@
     method public void getSize(android.graphics.Point);
     method public int getState();
     method public android.view.Display.Mode[] getSupportedModes();
-    method public deprecated float[] getSupportedRefreshRates();
-    method public deprecated int getWidth();
+    method @Deprecated public float[] getSupportedRefreshRates();
+    method @Deprecated public int getWidth();
     method public boolean isHdr();
     method public boolean isValid();
     method public boolean isWideColorGamut();
@@ -48132,6 +48515,7 @@
     field public static final android.os.Parcelable.Creator<android.view.Display.HdrCapabilities> CREATOR;
     field public static final int HDR_TYPE_DOLBY_VISION = 1; // 0x1
     field public static final int HDR_TYPE_HDR10 = 2; // 0x2
+    field public static final int HDR_TYPE_HDR10_PLUS = 4; // 0x4
     field public static final int HDR_TYPE_HLG = 3; // 0x3
     field public static final float INVALID_LUMINANCE = -1.0f;
   }
@@ -48147,13 +48531,13 @@
   }
 
   public final class DisplayCutout {
-    ctor public DisplayCutout(android.graphics.Insets, android.graphics.Rect, android.graphics.Rect, android.graphics.Rect, android.graphics.Rect);
-    ctor public deprecated DisplayCutout(android.graphics.Rect, java.util.List<android.graphics.Rect>);
-    method public android.graphics.Rect getBoundingRectBottom();
-    method public android.graphics.Rect getBoundingRectLeft();
-    method public android.graphics.Rect getBoundingRectRight();
-    method public android.graphics.Rect getBoundingRectTop();
-    method public java.util.List<android.graphics.Rect> getBoundingRects();
+    ctor public DisplayCutout(@NonNull android.graphics.Insets, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect);
+    ctor @Deprecated public DisplayCutout(@Nullable android.graphics.Rect, @Nullable java.util.List<android.graphics.Rect>);
+    method @NonNull public android.graphics.Rect getBoundingRectBottom();
+    method @NonNull public android.graphics.Rect getBoundingRectLeft();
+    method @NonNull public android.graphics.Rect getBoundingRectRight();
+    method @NonNull public android.graphics.Rect getBoundingRectTop();
+    method @NonNull public java.util.List<android.graphics.Rect> getBoundingRects();
     method public int getSafeInsetBottom();
     method public int getSafeInsetLeft();
     method public int getSafeInsetRight();
@@ -48172,7 +48556,7 @@
     method public int getAction();
     method public android.content.ClipData getClipData();
     method public android.content.ClipDescription getClipDescription();
-    method public java.lang.Object getLocalState();
+    method public Object getLocalState();
     method public boolean getResult();
     method public float getX();
     method public float getY();
@@ -48190,7 +48574,7 @@
     method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
     method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
     method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
-    method public android.view.View findNextKeyboardNavigationCluster(android.view.View, android.view.View, int);
+    method public android.view.View findNextKeyboardNavigationCluster(@NonNull android.view.View, @Nullable android.view.View, int);
     method public static android.view.FocusFinder getInstance();
   }
 
@@ -48222,8 +48606,8 @@
   }
 
   public class GestureDetector {
-    ctor public deprecated GestureDetector(android.view.GestureDetector.OnGestureListener, android.os.Handler);
-    ctor public deprecated GestureDetector(android.view.GestureDetector.OnGestureListener);
+    ctor @Deprecated public GestureDetector(android.view.GestureDetector.OnGestureListener, android.os.Handler);
+    ctor @Deprecated public GestureDetector(android.view.GestureDetector.OnGestureListener);
     ctor public GestureDetector(android.content.Context, android.view.GestureDetector.OnGestureListener);
     ctor public GestureDetector(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler);
     ctor public GestureDetector(android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler, boolean);
@@ -48235,23 +48619,23 @@
     method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener);
   }
 
-  public static abstract interface GestureDetector.OnContextClickListener {
-    method public abstract boolean onContextClick(android.view.MotionEvent);
+  public static interface GestureDetector.OnContextClickListener {
+    method public boolean onContextClick(android.view.MotionEvent);
   }
 
-  public static abstract interface GestureDetector.OnDoubleTapListener {
-    method public abstract boolean onDoubleTap(android.view.MotionEvent);
-    method public abstract boolean onDoubleTapEvent(android.view.MotionEvent);
-    method public abstract boolean onSingleTapConfirmed(android.view.MotionEvent);
+  public static interface GestureDetector.OnDoubleTapListener {
+    method public boolean onDoubleTap(android.view.MotionEvent);
+    method public boolean onDoubleTapEvent(android.view.MotionEvent);
+    method public boolean onSingleTapConfirmed(android.view.MotionEvent);
   }
 
-  public static abstract interface GestureDetector.OnGestureListener {
-    method public abstract boolean onDown(android.view.MotionEvent);
-    method public abstract boolean onFling(android.view.MotionEvent, android.view.MotionEvent, float, float);
-    method public abstract void onLongPress(android.view.MotionEvent);
-    method public abstract boolean onScroll(android.view.MotionEvent, android.view.MotionEvent, float, float);
-    method public abstract void onShowPress(android.view.MotionEvent);
-    method public abstract boolean onSingleTapUp(android.view.MotionEvent);
+  public static interface GestureDetector.OnGestureListener {
+    method public boolean onDown(android.view.MotionEvent);
+    method public boolean onFling(android.view.MotionEvent, android.view.MotionEvent, float, float);
+    method public void onLongPress(android.view.MotionEvent);
+    method public boolean onScroll(android.view.MotionEvent, android.view.MotionEvent, float, float);
+    method public void onShowPress(android.view.MotionEvent);
+    method public boolean onSingleTapUp(android.view.MotionEvent);
   }
 
   public static class GestureDetector.SimpleOnGestureListener implements android.view.GestureDetector.OnContextClickListener android.view.GestureDetector.OnDoubleTapListener android.view.GestureDetector.OnGestureListener {
@@ -48324,15 +48708,15 @@
 
   public class InflateException extends java.lang.RuntimeException {
     ctor public InflateException();
-    ctor public InflateException(java.lang.String, java.lang.Throwable);
-    ctor public InflateException(java.lang.String);
-    ctor public InflateException(java.lang.Throwable);
+    ctor public InflateException(String, Throwable);
+    ctor public InflateException(String);
+    ctor public InflateException(Throwable);
   }
 
   public final class InputDevice implements android.os.Parcelable {
     method public int describeContents();
     method public int getControllerNumber();
-    method public java.lang.String getDescriptor();
+    method public String getDescriptor();
     method public static android.view.InputDevice getDevice(int);
     method public static int[] getDeviceIds();
     method public int getId();
@@ -48341,7 +48725,7 @@
     method public android.view.InputDevice.MotionRange getMotionRange(int);
     method public android.view.InputDevice.MotionRange getMotionRange(int, int);
     method public java.util.List<android.view.InputDevice.MotionRange> getMotionRanges();
-    method public java.lang.String getName();
+    method public String getName();
     method public int getProductId();
     method public int getSources();
     method public int getVendorId();
@@ -48356,15 +48740,15 @@
     field public static final int KEYBOARD_TYPE_ALPHABETIC = 2; // 0x2
     field public static final int KEYBOARD_TYPE_NONE = 0; // 0x0
     field public static final int KEYBOARD_TYPE_NON_ALPHABETIC = 1; // 0x1
-    field public static final deprecated int MOTION_RANGE_ORIENTATION = 8; // 0x8
-    field public static final deprecated int MOTION_RANGE_PRESSURE = 2; // 0x2
-    field public static final deprecated int MOTION_RANGE_SIZE = 3; // 0x3
-    field public static final deprecated int MOTION_RANGE_TOOL_MAJOR = 6; // 0x6
-    field public static final deprecated int MOTION_RANGE_TOOL_MINOR = 7; // 0x7
-    field public static final deprecated int MOTION_RANGE_TOUCH_MAJOR = 4; // 0x4
-    field public static final deprecated int MOTION_RANGE_TOUCH_MINOR = 5; // 0x5
-    field public static final deprecated int MOTION_RANGE_X = 0; // 0x0
-    field public static final deprecated int MOTION_RANGE_Y = 1; // 0x1
+    field @Deprecated public static final int MOTION_RANGE_ORIENTATION = 8; // 0x8
+    field @Deprecated public static final int MOTION_RANGE_PRESSURE = 2; // 0x2
+    field @Deprecated public static final int MOTION_RANGE_SIZE = 3; // 0x3
+    field @Deprecated public static final int MOTION_RANGE_TOOL_MAJOR = 6; // 0x6
+    field @Deprecated public static final int MOTION_RANGE_TOOL_MINOR = 7; // 0x7
+    field @Deprecated public static final int MOTION_RANGE_TOUCH_MAJOR = 4; // 0x4
+    field @Deprecated public static final int MOTION_RANGE_TOUCH_MINOR = 5; // 0x5
+    field @Deprecated public static final int MOTION_RANGE_X = 0; // 0x0
+    field @Deprecated public static final int MOTION_RANGE_Y = 1; // 0x1
     field public static final int SOURCE_ANY = -256; // 0xffffff00
     field public static final int SOURCE_BLUETOOTH_STYLUS = 49154; // 0xc002
     field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
@@ -48415,9 +48799,9 @@
   public final class InputQueue {
   }
 
-  public static abstract interface InputQueue.Callback {
-    method public abstract void onInputQueueCreated(android.view.InputQueue);
-    method public abstract void onInputQueueDestroyed(android.view.InputQueue);
+  public static interface InputQueue.Callback {
+    method public void onInputQueueCreated(android.view.InputQueue);
+    method public void onInputQueueDestroyed(android.view.InputQueue);
   }
 
   public class KeyCharacterMap implements android.os.Parcelable {
@@ -48428,7 +48812,7 @@
     method public static int getDeadChar(int, int);
     method public char getDisplayLabel(int);
     method public android.view.KeyEvent[] getEvents(char[]);
-    method public deprecated boolean getKeyData(int, android.view.KeyCharacterMap.KeyData);
+    method @Deprecated public boolean getKeyData(int, android.view.KeyCharacterMap.KeyData);
     method public int getKeyboardType();
     method public char getMatch(int, char[]);
     method public char getMatch(int, char[], int);
@@ -48438,7 +48822,7 @@
     method public static android.view.KeyCharacterMap load(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ALPHA = 3; // 0x3
-    field public static final deprecated int BUILT_IN_KEYBOARD = 0; // 0x0
+    field @Deprecated public static final int BUILT_IN_KEYBOARD = 0; // 0x0
     field public static final int COMBINING_ACCENT = -2147483648; // 0x80000000
     field public static final int COMBINING_ACCENT_MASK = 2147483647; // 0x7fffffff
     field public static final android.os.Parcelable.Creator<android.view.KeyCharacterMap> CREATOR;
@@ -48453,16 +48837,16 @@
     field public static final int VIRTUAL_KEYBOARD = -1; // 0xffffffff
   }
 
-  public static deprecated class KeyCharacterMap.KeyData {
-    ctor public KeyCharacterMap.KeyData();
-    field public static final int META_LENGTH = 4; // 0x4
-    field public char displayLabel;
-    field public char[] meta;
-    field public char number;
+  @Deprecated public static class KeyCharacterMap.KeyData {
+    ctor @Deprecated public KeyCharacterMap.KeyData();
+    field @Deprecated public static final int META_LENGTH = 4; // 0x4
+    field @Deprecated public char displayLabel;
+    field @Deprecated public char[] meta;
+    field @Deprecated public char number;
   }
 
   public static class KeyCharacterMap.UnavailableException extends android.util.AndroidRuntimeException {
-    ctor public KeyCharacterMap.UnavailableException(java.lang.String);
+    ctor public KeyCharacterMap.UnavailableException(String);
   }
 
   public class KeyEvent extends android.view.InputEvent implements android.os.Parcelable {
@@ -48472,17 +48856,17 @@
     ctor public KeyEvent(long, long, int, int, int, int, int, int);
     ctor public KeyEvent(long, long, int, int, int, int, int, int, int);
     ctor public KeyEvent(long, long, int, int, int, int, int, int, int, int);
-    ctor public KeyEvent(long, java.lang.String, int, int);
+    ctor public KeyEvent(long, String, int, int);
     ctor public KeyEvent(android.view.KeyEvent);
-    ctor public deprecated KeyEvent(android.view.KeyEvent, long, int);
+    ctor @Deprecated public KeyEvent(android.view.KeyEvent, long, int);
     method public static android.view.KeyEvent changeAction(android.view.KeyEvent, int);
     method public static android.view.KeyEvent changeFlags(android.view.KeyEvent, int);
     method public static android.view.KeyEvent changeTimeRepeat(android.view.KeyEvent, long, int);
     method public static android.view.KeyEvent changeTimeRepeat(android.view.KeyEvent, long, int, int);
-    method public final deprecated boolean dispatch(android.view.KeyEvent.Callback);
-    method public final boolean dispatch(android.view.KeyEvent.Callback, android.view.KeyEvent.DispatcherState, java.lang.Object);
+    method @Deprecated public final boolean dispatch(android.view.KeyEvent.Callback);
+    method public final boolean dispatch(android.view.KeyEvent.Callback, android.view.KeyEvent.DispatcherState, Object);
     method public final int getAction();
-    method public final deprecated java.lang.String getCharacters();
+    method @Deprecated public final String getCharacters();
     method public static int getDeadChar(int, int);
     method public final int getDeviceId();
     method public char getDisplayLabel();
@@ -48491,7 +48875,7 @@
     method public final int getFlags();
     method public final android.view.KeyCharacterMap getKeyCharacterMap();
     method public final int getKeyCode();
-    method public deprecated boolean getKeyData(android.view.KeyCharacterMap.KeyData);
+    method @Deprecated public boolean getKeyData(android.view.KeyCharacterMap.KeyData);
     method public char getMatch(char[]);
     method public char getMatch(char[], int);
     method public static int getMaxKeyCode();
@@ -48523,8 +48907,8 @@
     method public final boolean isSymPressed();
     method public final boolean isSystem();
     method public final boolean isTracking();
-    method public static int keyCodeFromString(java.lang.String);
-    method public static java.lang.String keyCodeToString(int);
+    method public static int keyCodeFromString(@NonNull String);
+    method public static String keyCodeToString(int);
     method public static boolean metaStateHasModifiers(int, int);
     method public static boolean metaStateHasNoModifiers(int);
     method public static int normalizeMetaState(int);
@@ -48532,7 +48916,7 @@
     method public final void startTracking();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_DOWN = 0; // 0x0
-    field public static final deprecated int ACTION_MULTIPLE = 2; // 0x2
+    field @Deprecated public static final int ACTION_MULTIPLE = 2; // 0x2
     field public static final int ACTION_UP = 1; // 0x1
     field public static final android.os.Parcelable.Creator<android.view.KeyEvent> CREATOR;
     field public static final int FLAG_CANCELED = 32; // 0x20
@@ -48545,7 +48929,7 @@
     field public static final int FLAG_SOFT_KEYBOARD = 2; // 0x2
     field public static final int FLAG_TRACKING = 512; // 0x200
     field public static final int FLAG_VIRTUAL_HARD_KEY = 64; // 0x40
-    field public static final deprecated int FLAG_WOKE_HERE = 1; // 0x1
+    field @Deprecated public static final int FLAG_WOKE_HERE = 1; // 0x1
     field public static final int KEYCODE_0 = 7; // 0x7
     field public static final int KEYCODE_1 = 8; // 0x8
     field public static final int KEYCODE_11 = 227; // 0xe3
@@ -48835,7 +49219,7 @@
     field public static final int KEYCODE_ZENKAKU_HANKAKU = 211; // 0xd3
     field public static final int KEYCODE_ZOOM_IN = 168; // 0xa8
     field public static final int KEYCODE_ZOOM_OUT = 169; // 0xa9
-    field public static final deprecated int MAX_KEYCODE = 84; // 0x54
+    field @Deprecated public static final int MAX_KEYCODE = 84; // 0x54
     field public static final int META_ALT_LEFT_ON = 16; // 0x10
     field public static final int META_ALT_MASK = 50; // 0x32
     field public static final int META_ALT_ON = 2; // 0x2
@@ -48859,11 +49243,11 @@
     field public static final int META_SYM_ON = 4; // 0x4
   }
 
-  public static abstract interface KeyEvent.Callback {
-    method public abstract boolean onKeyDown(int, android.view.KeyEvent);
-    method public abstract boolean onKeyLongPress(int, android.view.KeyEvent);
-    method public abstract boolean onKeyMultiple(int, int, android.view.KeyEvent);
-    method public abstract boolean onKeyUp(int, android.view.KeyEvent);
+  public static interface KeyEvent.Callback {
+    method public boolean onKeyDown(int, android.view.KeyEvent);
+    method public boolean onKeyLongPress(int, android.view.KeyEvent);
+    method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
+    method public boolean onKeyUp(int, android.view.KeyEvent);
   }
 
   public static class KeyEvent.DispatcherState {
@@ -48872,28 +49256,28 @@
     method public boolean isTracking(android.view.KeyEvent);
     method public void performedLongPress(android.view.KeyEvent);
     method public void reset();
-    method public void reset(java.lang.Object);
-    method public void startTracking(android.view.KeyEvent, java.lang.Object);
+    method public void reset(Object);
+    method public void startTracking(android.view.KeyEvent, Object);
   }
 
   public final class KeyboardShortcutGroup implements android.os.Parcelable {
-    ctor public KeyboardShortcutGroup(java.lang.CharSequence, java.util.List<android.view.KeyboardShortcutInfo>);
-    ctor public KeyboardShortcutGroup(java.lang.CharSequence);
+    ctor public KeyboardShortcutGroup(@Nullable CharSequence, @NonNull java.util.List<android.view.KeyboardShortcutInfo>);
+    ctor public KeyboardShortcutGroup(@Nullable CharSequence);
     method public void addItem(android.view.KeyboardShortcutInfo);
     method public int describeContents();
     method public java.util.List<android.view.KeyboardShortcutInfo> getItems();
-    method public java.lang.CharSequence getLabel();
+    method public CharSequence getLabel();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutGroup> CREATOR;
   }
 
   public final class KeyboardShortcutInfo implements android.os.Parcelable {
-    ctor public KeyboardShortcutInfo(java.lang.CharSequence, int, int);
-    ctor public KeyboardShortcutInfo(java.lang.CharSequence, char, int);
+    ctor public KeyboardShortcutInfo(CharSequence, int, int);
+    ctor public KeyboardShortcutInfo(CharSequence, char, int);
     method public int describeContents();
     method public char getBaseCharacter();
     method public int getKeycode();
-    method public java.lang.CharSequence getLabel();
+    method @Nullable public CharSequence getLabel();
     method public int getModifiers();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.KeyboardShortcutInfo> CREATOR;
@@ -48903,61 +49287,61 @@
     ctor protected LayoutInflater(android.content.Context);
     ctor protected LayoutInflater(android.view.LayoutInflater, android.content.Context);
     method public abstract android.view.LayoutInflater cloneInContext(android.content.Context);
-    method public final android.view.View createView(java.lang.String, java.lang.String, android.util.AttributeSet) throws java.lang.ClassNotFoundException, android.view.InflateException;
+    method public final android.view.View createView(String, String, android.util.AttributeSet) throws java.lang.ClassNotFoundException, android.view.InflateException;
     method public static android.view.LayoutInflater from(android.content.Context);
     method public android.content.Context getContext();
     method public final android.view.LayoutInflater.Factory getFactory();
     method public final android.view.LayoutInflater.Factory2 getFactory2();
     method public android.view.LayoutInflater.Filter getFilter();
-    method public android.view.View inflate(int, android.view.ViewGroup);
-    method public android.view.View inflate(org.xmlpull.v1.XmlPullParser, android.view.ViewGroup);
-    method public android.view.View inflate(int, android.view.ViewGroup, boolean);
-    method public android.view.View inflate(org.xmlpull.v1.XmlPullParser, android.view.ViewGroup, boolean);
-    method protected android.view.View onCreateView(java.lang.String, android.util.AttributeSet) throws java.lang.ClassNotFoundException;
-    method protected android.view.View onCreateView(android.view.View, java.lang.String, android.util.AttributeSet) throws java.lang.ClassNotFoundException;
+    method public android.view.View inflate(@LayoutRes int, @Nullable android.view.ViewGroup);
+    method public android.view.View inflate(org.xmlpull.v1.XmlPullParser, @Nullable android.view.ViewGroup);
+    method public android.view.View inflate(@LayoutRes int, @Nullable android.view.ViewGroup, boolean);
+    method public android.view.View inflate(org.xmlpull.v1.XmlPullParser, @Nullable android.view.ViewGroup, boolean);
+    method protected android.view.View onCreateView(String, android.util.AttributeSet) throws java.lang.ClassNotFoundException;
+    method protected android.view.View onCreateView(android.view.View, String, android.util.AttributeSet) throws java.lang.ClassNotFoundException;
     method public void setFactory(android.view.LayoutInflater.Factory);
     method public void setFactory2(android.view.LayoutInflater.Factory2);
     method public void setFilter(android.view.LayoutInflater.Filter);
   }
 
-  public static abstract interface LayoutInflater.Factory {
-    method public abstract android.view.View onCreateView(java.lang.String, android.content.Context, android.util.AttributeSet);
+  public static interface LayoutInflater.Factory {
+    method @Nullable public android.view.View onCreateView(@NonNull String, @NonNull android.content.Context, @NonNull android.util.AttributeSet);
   }
 
-  public static abstract interface LayoutInflater.Factory2 implements android.view.LayoutInflater.Factory {
-    method public abstract android.view.View onCreateView(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet);
+  public static interface LayoutInflater.Factory2 extends android.view.LayoutInflater.Factory {
+    method @Nullable public android.view.View onCreateView(@Nullable android.view.View, @NonNull String, @NonNull android.content.Context, @NonNull android.util.AttributeSet);
   }
 
-  public static abstract interface LayoutInflater.Filter {
-    method public abstract boolean onLoadClass(java.lang.Class);
+  public static interface LayoutInflater.Filter {
+    method public boolean onLoadClass(Class);
   }
 
-  public abstract interface Menu {
-    method public abstract android.view.MenuItem add(java.lang.CharSequence);
-    method public abstract android.view.MenuItem add(int);
-    method public abstract android.view.MenuItem add(int, int, int, java.lang.CharSequence);
-    method public abstract android.view.MenuItem add(int, int, int, int);
-    method public abstract int addIntentOptions(int, int, int, android.content.ComponentName, android.content.Intent[], android.content.Intent, int, android.view.MenuItem[]);
-    method public abstract android.view.SubMenu addSubMenu(java.lang.CharSequence);
-    method public abstract android.view.SubMenu addSubMenu(int);
-    method public abstract android.view.SubMenu addSubMenu(int, int, int, java.lang.CharSequence);
-    method public abstract android.view.SubMenu addSubMenu(int, int, int, int);
-    method public abstract void clear();
-    method public abstract void close();
-    method public abstract android.view.MenuItem findItem(int);
-    method public abstract android.view.MenuItem getItem(int);
-    method public abstract boolean hasVisibleItems();
-    method public abstract boolean isShortcutKey(int, android.view.KeyEvent);
-    method public abstract boolean performIdentifierAction(int, int);
-    method public abstract boolean performShortcut(int, android.view.KeyEvent, int);
-    method public abstract void removeGroup(int);
-    method public abstract void removeItem(int);
-    method public abstract void setGroupCheckable(int, boolean, boolean);
+  public interface Menu {
+    method public android.view.MenuItem add(CharSequence);
+    method public android.view.MenuItem add(@StringRes int);
+    method public android.view.MenuItem add(int, int, int, CharSequence);
+    method public android.view.MenuItem add(int, int, int, @StringRes int);
+    method public int addIntentOptions(int, int, int, android.content.ComponentName, android.content.Intent[], android.content.Intent, int, android.view.MenuItem[]);
+    method public android.view.SubMenu addSubMenu(CharSequence);
+    method public android.view.SubMenu addSubMenu(@StringRes int);
+    method public android.view.SubMenu addSubMenu(int, int, int, CharSequence);
+    method public android.view.SubMenu addSubMenu(int, int, int, @StringRes int);
+    method public void clear();
+    method public void close();
+    method public android.view.MenuItem findItem(int);
+    method public android.view.MenuItem getItem(int);
+    method public boolean hasVisibleItems();
+    method public boolean isShortcutKey(int, android.view.KeyEvent);
+    method public boolean performIdentifierAction(int, int);
+    method public boolean performShortcut(int, android.view.KeyEvent, int);
+    method public void removeGroup(int);
+    method public void removeItem(int);
+    method public void setGroupCheckable(int, boolean, boolean);
     method public default void setGroupDividerEnabled(boolean);
-    method public abstract void setGroupEnabled(int, boolean);
-    method public abstract void setGroupVisible(int, boolean);
-    method public abstract void setQwertyMode(boolean);
-    method public abstract int size();
+    method public void setGroupEnabled(int, boolean);
+    method public void setGroupVisible(int, boolean);
+    method public void setQwertyMode(boolean);
+    method public int size();
     field public static final int CATEGORY_ALTERNATIVE = 262144; // 0x40000
     field public static final int CATEGORY_CONTAINER = 65536; // 0x10000
     field public static final int CATEGORY_SECONDARY = 196608; // 0x30000
@@ -48972,64 +49356,64 @@
 
   public class MenuInflater {
     ctor public MenuInflater(android.content.Context);
-    method public void inflate(int, android.view.Menu);
+    method public void inflate(@MenuRes int, android.view.Menu);
   }
 
-  public abstract interface MenuItem {
-    method public abstract boolean collapseActionView();
-    method public abstract boolean expandActionView();
-    method public abstract android.view.ActionProvider getActionProvider();
-    method public abstract android.view.View getActionView();
+  public interface MenuItem {
+    method public boolean collapseActionView();
+    method public boolean expandActionView();
+    method public android.view.ActionProvider getActionProvider();
+    method public android.view.View getActionView();
     method public default int getAlphabeticModifiers();
-    method public abstract char getAlphabeticShortcut();
-    method public default java.lang.CharSequence getContentDescription();
-    method public abstract int getGroupId();
-    method public abstract android.graphics.drawable.Drawable getIcon();
-    method public default android.content.res.ColorStateList getIconTintList();
-    method public default android.graphics.PorterDuff.Mode getIconTintMode();
-    method public abstract android.content.Intent getIntent();
-    method public abstract int getItemId();
-    method public abstract android.view.ContextMenu.ContextMenuInfo getMenuInfo();
+    method public char getAlphabeticShortcut();
+    method public default CharSequence getContentDescription();
+    method public int getGroupId();
+    method public android.graphics.drawable.Drawable getIcon();
+    method @Nullable public default android.content.res.ColorStateList getIconTintList();
+    method @Nullable public default android.graphics.PorterDuff.Mode getIconTintMode();
+    method public android.content.Intent getIntent();
+    method public int getItemId();
+    method public android.view.ContextMenu.ContextMenuInfo getMenuInfo();
     method public default int getNumericModifiers();
-    method public abstract char getNumericShortcut();
-    method public abstract int getOrder();
-    method public abstract android.view.SubMenu getSubMenu();
-    method public abstract java.lang.CharSequence getTitle();
-    method public abstract java.lang.CharSequence getTitleCondensed();
-    method public default java.lang.CharSequence getTooltipText();
-    method public abstract boolean hasSubMenu();
-    method public abstract boolean isActionViewExpanded();
-    method public abstract boolean isCheckable();
-    method public abstract boolean isChecked();
-    method public abstract boolean isEnabled();
-    method public abstract boolean isVisible();
-    method public abstract android.view.MenuItem setActionProvider(android.view.ActionProvider);
-    method public abstract android.view.MenuItem setActionView(android.view.View);
-    method public abstract android.view.MenuItem setActionView(int);
-    method public abstract android.view.MenuItem setAlphabeticShortcut(char);
+    method public char getNumericShortcut();
+    method public int getOrder();
+    method public android.view.SubMenu getSubMenu();
+    method public CharSequence getTitle();
+    method public CharSequence getTitleCondensed();
+    method public default CharSequence getTooltipText();
+    method public boolean hasSubMenu();
+    method public boolean isActionViewExpanded();
+    method public boolean isCheckable();
+    method public boolean isChecked();
+    method public boolean isEnabled();
+    method public boolean isVisible();
+    method public android.view.MenuItem setActionProvider(android.view.ActionProvider);
+    method public android.view.MenuItem setActionView(android.view.View);
+    method public android.view.MenuItem setActionView(@LayoutRes int);
+    method public android.view.MenuItem setAlphabeticShortcut(char);
     method public default android.view.MenuItem setAlphabeticShortcut(char, int);
-    method public abstract android.view.MenuItem setCheckable(boolean);
-    method public abstract android.view.MenuItem setChecked(boolean);
-    method public default android.view.MenuItem setContentDescription(java.lang.CharSequence);
-    method public abstract android.view.MenuItem setEnabled(boolean);
-    method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
-    method public abstract android.view.MenuItem setIcon(int);
-    method public default android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
-    method public default android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
-    method public abstract android.view.MenuItem setIntent(android.content.Intent);
-    method public abstract android.view.MenuItem setNumericShortcut(char);
+    method public android.view.MenuItem setCheckable(boolean);
+    method public android.view.MenuItem setChecked(boolean);
+    method public default android.view.MenuItem setContentDescription(CharSequence);
+    method public android.view.MenuItem setEnabled(boolean);
+    method public android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
+    method public android.view.MenuItem setIcon(@DrawableRes int);
+    method public default android.view.MenuItem setIconTintList(@Nullable android.content.res.ColorStateList);
+    method public default android.view.MenuItem setIconTintMode(@Nullable android.graphics.PorterDuff.Mode);
+    method public android.view.MenuItem setIntent(android.content.Intent);
+    method public android.view.MenuItem setNumericShortcut(char);
     method public default android.view.MenuItem setNumericShortcut(char, int);
-    method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
-    method public abstract android.view.MenuItem setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener);
-    method public abstract android.view.MenuItem setShortcut(char, char);
+    method public android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
+    method public android.view.MenuItem setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener);
+    method public android.view.MenuItem setShortcut(char, char);
     method public default android.view.MenuItem setShortcut(char, char, int, int);
-    method public abstract void setShowAsAction(int);
-    method public abstract android.view.MenuItem setShowAsActionFlags(int);
-    method public abstract android.view.MenuItem setTitle(java.lang.CharSequence);
-    method public abstract android.view.MenuItem setTitle(int);
-    method public abstract android.view.MenuItem setTitleCondensed(java.lang.CharSequence);
-    method public default android.view.MenuItem setTooltipText(java.lang.CharSequence);
-    method public abstract android.view.MenuItem setVisible(boolean);
+    method public void setShowAsAction(int);
+    method public android.view.MenuItem setShowAsActionFlags(int);
+    method public android.view.MenuItem setTitle(CharSequence);
+    method public android.view.MenuItem setTitle(@StringRes int);
+    method public android.view.MenuItem setTitleCondensed(CharSequence);
+    method public default android.view.MenuItem setTooltipText(CharSequence);
+    method public android.view.MenuItem setVisible(boolean);
     field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
     field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
     field public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
@@ -49037,21 +49421,21 @@
     field public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
   }
 
-  public static abstract interface MenuItem.OnActionExpandListener {
-    method public abstract boolean onMenuItemActionCollapse(android.view.MenuItem);
-    method public abstract boolean onMenuItemActionExpand(android.view.MenuItem);
+  public static interface MenuItem.OnActionExpandListener {
+    method public boolean onMenuItemActionCollapse(android.view.MenuItem);
+    method public boolean onMenuItemActionExpand(android.view.MenuItem);
   }
 
-  public static abstract interface MenuItem.OnMenuItemClickListener {
-    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  public static interface MenuItem.OnMenuItemClickListener {
+    method public boolean onMenuItemClick(android.view.MenuItem);
   }
 
   public final class MotionEvent extends android.view.InputEvent implements android.os.Parcelable {
-    method public static java.lang.String actionToString(int);
+    method public static String actionToString(int);
     method public void addBatch(long, float, float, float, float, int);
     method public void addBatch(long, android.view.MotionEvent.PointerCoords[], int);
-    method public static int axisFromString(java.lang.String);
-    method public static java.lang.String axisToString(int);
+    method public static int axisFromString(String);
+    method public static String axisToString(int);
     method public int findPointerIndex(int);
     method public int getAction();
     method public int getActionButton();
@@ -49060,6 +49444,7 @@
     method public float getAxisValue(int);
     method public float getAxisValue(int, int);
     method public int getButtonState();
+    method public int getClassification();
     method public int getDeviceId();
     method public long getDownTime();
     method public int getEdgeFlags();
@@ -49121,9 +49506,9 @@
     method public float getYPrecision();
     method public boolean isButtonPressed(int);
     method public static android.view.MotionEvent obtain(long, long, int, int, android.view.MotionEvent.PointerProperties[], android.view.MotionEvent.PointerCoords[], int, int, float, float, int, int, int, int);
-    method public static deprecated android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent.PointerCoords[], int, float, float, int, int, int, int);
+    method @Deprecated public static android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent.PointerCoords[], int, float, float, int, int, int, int);
     method public static android.view.MotionEvent obtain(long, long, int, float, float, float, float, int, float, float, int, int);
-    method public static deprecated android.view.MotionEvent obtain(long, long, int, int, float, float, float, float, int, float, float, int, int);
+    method @Deprecated public static android.view.MotionEvent obtain(long, long, int, int, float, float, float, float, int, float, float, int, int);
     method public static android.view.MotionEvent obtain(long, long, int, float, float, int);
     method public static android.view.MotionEvent obtain(android.view.MotionEvent);
     method public static android.view.MotionEvent obtainNoHistory(android.view.MotionEvent);
@@ -49145,15 +49530,15 @@
     field public static final int ACTION_MASK = 255; // 0xff
     field public static final int ACTION_MOVE = 2; // 0x2
     field public static final int ACTION_OUTSIDE = 4; // 0x4
-    field public static final deprecated int ACTION_POINTER_1_DOWN = 5; // 0x5
-    field public static final deprecated int ACTION_POINTER_1_UP = 6; // 0x6
-    field public static final deprecated int ACTION_POINTER_2_DOWN = 261; // 0x105
-    field public static final deprecated int ACTION_POINTER_2_UP = 262; // 0x106
-    field public static final deprecated int ACTION_POINTER_3_DOWN = 517; // 0x205
-    field public static final deprecated int ACTION_POINTER_3_UP = 518; // 0x206
+    field @Deprecated public static final int ACTION_POINTER_1_DOWN = 5; // 0x5
+    field @Deprecated public static final int ACTION_POINTER_1_UP = 6; // 0x6
+    field @Deprecated public static final int ACTION_POINTER_2_DOWN = 261; // 0x105
+    field @Deprecated public static final int ACTION_POINTER_2_UP = 262; // 0x106
+    field @Deprecated public static final int ACTION_POINTER_3_DOWN = 517; // 0x205
+    field @Deprecated public static final int ACTION_POINTER_3_UP = 518; // 0x206
     field public static final int ACTION_POINTER_DOWN = 5; // 0x5
-    field public static final deprecated int ACTION_POINTER_ID_MASK = 65280; // 0xff00
-    field public static final deprecated int ACTION_POINTER_ID_SHIFT = 8; // 0x8
+    field @Deprecated public static final int ACTION_POINTER_ID_MASK = 65280; // 0xff00
+    field @Deprecated public static final int ACTION_POINTER_ID_SHIFT = 8; // 0x8
     field public static final int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
     field public static final int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
     field public static final int ACTION_POINTER_UP = 6; // 0x6
@@ -49211,6 +49596,9 @@
     field public static final int BUTTON_STYLUS_PRIMARY = 32; // 0x20
     field public static final int BUTTON_STYLUS_SECONDARY = 64; // 0x40
     field public static final int BUTTON_TERTIARY = 4; // 0x4
+    field public static final int CLASSIFICATION_AMBIGUOUS_GESTURE = 1; // 0x1
+    field public static final int CLASSIFICATION_DEEP_PRESS = 2; // 0x2
+    field public static final int CLASSIFICATION_NONE = 0; // 0x0
     field public static final android.os.Parcelable.Creator<android.view.MotionEvent> CREATOR;
     field public static final int EDGE_BOTTOM = 2; // 0x2
     field public static final int EDGE_LEFT = 4; // 0x4
@@ -49262,24 +49650,24 @@
     field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff
   }
 
-  public abstract deprecated class OrientationListener implements android.hardware.SensorListener {
-    ctor public OrientationListener(android.content.Context);
-    ctor public OrientationListener(android.content.Context, int);
-    method public void disable();
-    method public void enable();
-    method public void onAccuracyChanged(int, int);
-    method public abstract void onOrientationChanged(int);
-    method public void onSensorChanged(int, float[]);
-    field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff
+  @Deprecated public abstract class OrientationListener implements android.hardware.SensorListener {
+    ctor @Deprecated public OrientationListener(android.content.Context);
+    ctor @Deprecated public OrientationListener(android.content.Context, int);
+    method @Deprecated public void disable();
+    method @Deprecated public void enable();
+    method @Deprecated public void onAccuracyChanged(int, int);
+    method @Deprecated public abstract void onOrientationChanged(int);
+    method @Deprecated public void onSensorChanged(int, float[]);
+    field @Deprecated public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff
   }
 
   public final class PixelCopy {
-    method public static void request(android.view.SurfaceView, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
-    method public static void request(android.view.SurfaceView, android.graphics.Rect, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
-    method public static void request(android.view.Surface, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
-    method public static void request(android.view.Surface, android.graphics.Rect, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
-    method public static void request(android.view.Window, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
-    method public static void request(android.view.Window, android.graphics.Rect, android.graphics.Bitmap, android.view.PixelCopy.OnPixelCopyFinishedListener, android.os.Handler);
+    method public static void request(@NonNull android.view.SurfaceView, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
+    method public static void request(@NonNull android.view.SurfaceView, @Nullable android.graphics.Rect, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
+    method public static void request(@NonNull android.view.Surface, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
+    method public static void request(@NonNull android.view.Surface, @Nullable android.graphics.Rect, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
+    method public static void request(@NonNull android.view.Window, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
+    method public static void request(@NonNull android.view.Window, @Nullable android.graphics.Rect, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
     field public static final int ERROR_DESTINATION_INVALID = 5; // 0x5
     field public static final int ERROR_SOURCE_INVALID = 4; // 0x4
     field public static final int ERROR_SOURCE_NO_DATA = 3; // 0x3
@@ -49288,15 +49676,15 @@
     field public static final int SUCCESS = 0; // 0x0
   }
 
-  public static abstract interface PixelCopy.OnPixelCopyFinishedListener {
-    method public abstract void onPixelCopyFinished(int);
+  public static interface PixelCopy.OnPixelCopyFinishedListener {
+    method public void onPixelCopyFinished(int);
   }
 
   public final class PointerIcon implements android.os.Parcelable {
-    method public static android.view.PointerIcon create(android.graphics.Bitmap, float, float);
+    method public static android.view.PointerIcon create(@NonNull android.graphics.Bitmap, float, float);
     method public int describeContents();
-    method public static android.view.PointerIcon getSystemIcon(android.content.Context, int);
-    method public static android.view.PointerIcon load(android.content.res.Resources, int);
+    method public static android.view.PointerIcon getSystemIcon(@NonNull android.content.Context, int);
+    method public static android.view.PointerIcon load(@NonNull android.content.res.Resources, @XmlRes int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.PointerIcon> CREATOR;
     field public static final int TYPE_ALIAS = 1010; // 0x3f2
@@ -49346,10 +49734,10 @@
     method public void setStylusScaleEnabled(boolean);
   }
 
-  public static abstract interface ScaleGestureDetector.OnScaleGestureListener {
-    method public abstract boolean onScale(android.view.ScaleGestureDetector);
-    method public abstract boolean onScaleBegin(android.view.ScaleGestureDetector);
-    method public abstract void onScaleEnd(android.view.ScaleGestureDetector);
+  public static interface ScaleGestureDetector.OnScaleGestureListener {
+    method public boolean onScale(android.view.ScaleGestureDetector);
+    method public boolean onScaleBegin(android.view.ScaleGestureDetector);
+    method public void onScaleEnd(android.view.ScaleGestureDetector);
   }
 
   public static class ScaleGestureDetector.SimpleOnScaleGestureListener implements android.view.ScaleGestureDetector.OnScaleGestureListener {
@@ -49373,19 +49761,20 @@
     field public static final int NAVIGATION_UP = 2; // 0x2
   }
 
-  public abstract interface SubMenu implements android.view.Menu {
-    method public abstract void clearHeader();
-    method public abstract android.view.MenuItem getItem();
-    method public abstract android.view.SubMenu setHeaderIcon(int);
-    method public abstract android.view.SubMenu setHeaderIcon(android.graphics.drawable.Drawable);
-    method public abstract android.view.SubMenu setHeaderTitle(int);
-    method public abstract android.view.SubMenu setHeaderTitle(java.lang.CharSequence);
-    method public abstract android.view.SubMenu setHeaderView(android.view.View);
-    method public abstract android.view.SubMenu setIcon(int);
-    method public abstract android.view.SubMenu setIcon(android.graphics.drawable.Drawable);
+  public interface SubMenu extends android.view.Menu {
+    method public void clearHeader();
+    method public android.view.MenuItem getItem();
+    method public android.view.SubMenu setHeaderIcon(@DrawableRes int);
+    method public android.view.SubMenu setHeaderIcon(android.graphics.drawable.Drawable);
+    method public android.view.SubMenu setHeaderTitle(@StringRes int);
+    method public android.view.SubMenu setHeaderTitle(CharSequence);
+    method public android.view.SubMenu setHeaderView(android.view.View);
+    method public android.view.SubMenu setIcon(@DrawableRes int);
+    method public android.view.SubMenu setIcon(android.graphics.drawable.Drawable);
   }
 
   public class Surface implements android.os.Parcelable {
+    ctor public Surface(android.view.SurfaceControl);
     ctor public Surface(android.graphics.SurfaceTexture);
     method public int describeContents();
     method public boolean isValid();
@@ -49393,7 +49782,7 @@
     method public android.graphics.Canvas lockHardwareCanvas();
     method public void readFromParcel(android.os.Parcel);
     method public void release();
-    method public deprecated void unlockCanvas(android.graphics.Canvas);
+    method @Deprecated public void unlockCanvas(android.graphics.Canvas);
     method public void unlockCanvasAndPost(android.graphics.Canvas);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.Surface> CREATOR;
@@ -49405,44 +49794,76 @@
 
   public static class Surface.OutOfResourcesException extends java.lang.RuntimeException {
     ctor public Surface.OutOfResourcesException();
-    ctor public Surface.OutOfResourcesException(java.lang.String);
+    ctor public Surface.OutOfResourcesException(String);
   }
 
-  public abstract interface SurfaceHolder {
-    method public abstract void addCallback(android.view.SurfaceHolder.Callback);
-    method public abstract android.view.Surface getSurface();
-    method public abstract android.graphics.Rect getSurfaceFrame();
-    method public abstract boolean isCreating();
-    method public abstract android.graphics.Canvas lockCanvas();
-    method public abstract android.graphics.Canvas lockCanvas(android.graphics.Rect);
+  public final class SurfaceControl implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean isValid();
+    method public void readFromParcel(android.os.Parcel);
+    method public void release();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.SurfaceControl> CREATOR;
+  }
+
+  public static class SurfaceControl.Builder {
+    ctor public SurfaceControl.Builder();
+    method public android.view.SurfaceControl build();
+    method public android.view.SurfaceControl.Builder setBufferSize(@IntRange(from=0) int, @IntRange(from=0) int);
+    method @NonNull public android.view.SurfaceControl.Builder setFormat(int);
+    method public android.view.SurfaceControl.Builder setName(String);
+    method @NonNull public android.view.SurfaceControl.Builder setOpaque(boolean);
+    method @NonNull public android.view.SurfaceControl.Builder setParent(@Nullable android.view.SurfaceControl);
+  }
+
+  public static class SurfaceControl.Transaction implements java.io.Closeable {
+    ctor public SurfaceControl.Transaction();
+    method public void apply();
+    method public void close();
+    method @NonNull public android.view.SurfaceControl.Transaction merge(@NonNull android.view.SurfaceControl.Transaction);
+    method @NonNull public android.view.SurfaceControl.Transaction reparent(@NonNull android.view.SurfaceControl, @Nullable android.view.SurfaceControl);
+    method @NonNull public android.view.SurfaceControl.Transaction setAlpha(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0, to=1.0) float);
+    method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int);
+    method @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int);
+    method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int);
+    method @NonNull public android.view.SurfaceControl.Transaction setVisibility(@NonNull android.view.SurfaceControl, boolean);
+  }
+
+  public interface SurfaceHolder {
+    method public void addCallback(android.view.SurfaceHolder.Callback);
+    method public android.view.Surface getSurface();
+    method public android.graphics.Rect getSurfaceFrame();
+    method public boolean isCreating();
+    method public android.graphics.Canvas lockCanvas();
+    method public android.graphics.Canvas lockCanvas(android.graphics.Rect);
     method public default android.graphics.Canvas lockHardwareCanvas();
-    method public abstract void removeCallback(android.view.SurfaceHolder.Callback);
-    method public abstract void setFixedSize(int, int);
-    method public abstract void setFormat(int);
-    method public abstract void setKeepScreenOn(boolean);
-    method public abstract void setSizeFromLayout();
-    method public abstract deprecated void setType(int);
-    method public abstract void unlockCanvasAndPost(android.graphics.Canvas);
-    field public static final deprecated int SURFACE_TYPE_GPU = 2; // 0x2
-    field public static final deprecated int SURFACE_TYPE_HARDWARE = 1; // 0x1
-    field public static final deprecated int SURFACE_TYPE_NORMAL = 0; // 0x0
-    field public static final deprecated int SURFACE_TYPE_PUSH_BUFFERS = 3; // 0x3
+    method public void removeCallback(android.view.SurfaceHolder.Callback);
+    method public void setFixedSize(int, int);
+    method public void setFormat(int);
+    method public void setKeepScreenOn(boolean);
+    method public void setSizeFromLayout();
+    method @Deprecated public void setType(int);
+    method public void unlockCanvasAndPost(android.graphics.Canvas);
+    field @Deprecated public static final int SURFACE_TYPE_GPU = 2; // 0x2
+    field @Deprecated public static final int SURFACE_TYPE_HARDWARE = 1; // 0x1
+    field @Deprecated public static final int SURFACE_TYPE_NORMAL = 0; // 0x0
+    field @Deprecated public static final int SURFACE_TYPE_PUSH_BUFFERS = 3; // 0x3
   }
 
   public static class SurfaceHolder.BadSurfaceTypeException extends java.lang.RuntimeException {
     ctor public SurfaceHolder.BadSurfaceTypeException();
-    ctor public SurfaceHolder.BadSurfaceTypeException(java.lang.String);
+    ctor public SurfaceHolder.BadSurfaceTypeException(String);
   }
 
-  public static abstract interface SurfaceHolder.Callback {
-    method public abstract void surfaceChanged(android.view.SurfaceHolder, int, int, int);
-    method public abstract void surfaceCreated(android.view.SurfaceHolder);
-    method public abstract void surfaceDestroyed(android.view.SurfaceHolder);
+  public static interface SurfaceHolder.Callback {
+    method public void surfaceChanged(android.view.SurfaceHolder, int, int, int);
+    method public void surfaceCreated(android.view.SurfaceHolder);
+    method public void surfaceDestroyed(android.view.SurfaceHolder);
   }
 
-  public static abstract interface SurfaceHolder.Callback2 implements android.view.SurfaceHolder.Callback {
-    method public abstract void surfaceRedrawNeeded(android.view.SurfaceHolder);
-    method public default void surfaceRedrawNeededAsync(android.view.SurfaceHolder, java.lang.Runnable);
+  public static interface SurfaceHolder.Callback2 extends android.view.SurfaceHolder.Callback {
+    method public void surfaceRedrawNeeded(android.view.SurfaceHolder);
+    method public default void surfaceRedrawNeededAsync(android.view.SurfaceHolder, Runnable);
   }
 
   public class SurfaceView extends android.view.View {
@@ -49452,6 +49873,7 @@
     ctor public SurfaceView(android.content.Context, android.util.AttributeSet, int, int);
     method public boolean gatherTransparentRegion(android.graphics.Region);
     method public android.view.SurfaceHolder getHolder();
+    method public android.view.SurfaceControl getSurfaceControl();
     method public void setSecure(boolean);
     method public void setZOrderMediaOverlay(boolean);
     method public void setZOrderOnTop(boolean);
@@ -49481,18 +49903,18 @@
     method public void unlockCanvasAndPost(android.graphics.Canvas);
   }
 
-  public static abstract interface TextureView.SurfaceTextureListener {
-    method public abstract void onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int);
-    method public abstract boolean onSurfaceTextureDestroyed(android.graphics.SurfaceTexture);
-    method public abstract void onSurfaceTextureSizeChanged(android.graphics.SurfaceTexture, int, int);
-    method public abstract void onSurfaceTextureUpdated(android.graphics.SurfaceTexture);
+  public static interface TextureView.SurfaceTextureListener {
+    method public void onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int);
+    method public boolean onSurfaceTextureDestroyed(android.graphics.SurfaceTexture);
+    method public void onSurfaceTextureSizeChanged(android.graphics.SurfaceTexture, int, int);
+    method public void onSurfaceTextureUpdated(android.graphics.SurfaceTexture);
   }
 
   public class TouchDelegate {
     ctor public TouchDelegate(android.graphics.Rect, android.view.View);
-    method public android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo getTouchDelegateInfo();
-    method public boolean onTouchEvent(android.view.MotionEvent);
-    method public boolean onTouchExplorationHoverEvent(android.view.MotionEvent);
+    method @NonNull public android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo getTouchDelegateInfo();
+    method public boolean onTouchEvent(@NonNull android.view.MotionEvent);
+    method public boolean onTouchExplorationHoverEvent(@NonNull android.view.MotionEvent);
     field public static final int ABOVE = 1; // 0x1
     field public static final int BELOW = 2; // 0x2
     field public static final int TO_LEFT = 4; // 0x4
@@ -49512,30 +49934,30 @@
     method public void recycle();
   }
 
-  public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
+  @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
     ctor public View(android.content.Context);
-    ctor public View(android.content.Context, android.util.AttributeSet);
-    ctor public View(android.content.Context, android.util.AttributeSet, int);
-    ctor public View(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public View(android.content.Context, @Nullable android.util.AttributeSet);
+    ctor public View(android.content.Context, @Nullable android.util.AttributeSet, int);
+    ctor public View(android.content.Context, @Nullable android.util.AttributeSet, int, int);
     method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
-    method public void addExtraDataToAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
+    method public void addExtraDataToAccessibilityNodeInfo(@NonNull android.view.accessibility.AccessibilityNodeInfo, @NonNull String, @Nullable android.os.Bundle);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int);
     method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
-    method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
+    method public void addKeyboardNavigationClusters(@NonNull java.util.Collection<android.view.View>, int);
     method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
     method public void addOnUnhandledKeyEventListener(android.view.View.OnUnhandledKeyEventListener);
     method public void addTouchables(java.util.ArrayList<android.view.View>);
     method public android.view.ViewPropertyAnimator animate();
-    method public void announceForAccessibility(java.lang.CharSequence);
+    method public void announceForAccessibility(CharSequence);
     method public void autofill(android.view.autofill.AutofillValue);
-    method public void autofill(android.util.SparseArray<android.view.autofill.AutofillValue>);
+    method public void autofill(@NonNull android.util.SparseArray<android.view.autofill.AutofillValue>);
     method protected boolean awakenScrollBars();
     method protected boolean awakenScrollBars(int);
     method protected boolean awakenScrollBars(int, boolean);
     method public void bringToFront();
-    method public deprecated void buildDrawingCache();
-    method public deprecated void buildDrawingCache(boolean);
+    method @Deprecated public void buildDrawingCache();
+    method @Deprecated public void buildDrawingCache(boolean);
     method public void buildLayer();
     method public boolean callOnClick();
     method public boolean canResolveLayoutDirection();
@@ -49560,7 +49982,7 @@
     method protected int computeVerticalScrollRange();
     method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo();
     method public void createContextMenu(android.view.ContextMenu);
-    method public deprecated void destroyDrawingCache();
+    method @Deprecated public void destroyDrawingCache();
     method public android.view.WindowInsets dispatchApplyWindowInsets(android.view.WindowInsets);
     method public boolean dispatchCapturedPointerEvent(android.view.MotionEvent);
     method public void dispatchConfigurationChanged(android.content.res.Configuration);
@@ -49568,7 +49990,7 @@
     method public boolean dispatchDragEvent(android.view.DragEvent);
     method protected void dispatchDraw(android.graphics.Canvas);
     method public void dispatchDrawableHotspotChanged(float, float);
-    method public void dispatchFinishTemporaryDetach();
+    method @CallSuper public void dispatchFinishTemporaryDetach();
     method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
     method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
     method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
@@ -49579,117 +50001,117 @@
     method public boolean dispatchNestedFling(float, float, boolean);
     method public boolean dispatchNestedPreFling(float, float);
     method public boolean dispatchNestedPrePerformAccessibilityAction(int, android.os.Bundle);
-    method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
-    method public boolean dispatchNestedScroll(int, int, int, int, int[]);
+    method public boolean dispatchNestedPreScroll(int, int, @Nullable @Size(2) int[], @Nullable @Size(2) int[]);
+    method public boolean dispatchNestedScroll(int, int, int, int, @Nullable @Size(2) int[]);
     method public void dispatchPointerCaptureChanged(boolean);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public void dispatchProvideAutofillStructure(android.view.ViewStructure, int);
+    method public void dispatchProvideAutofillStructure(@NonNull android.view.ViewStructure, int);
     method public void dispatchProvideStructure(android.view.ViewStructure);
     method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSetActivated(boolean);
     method protected void dispatchSetPressed(boolean);
     method protected void dispatchSetSelected(boolean);
-    method public void dispatchStartTemporaryDetach();
+    method @CallSuper public void dispatchStartTemporaryDetach();
     method public void dispatchSystemUiVisibilityChanged(int);
     method public boolean dispatchTouchEvent(android.view.MotionEvent);
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
     method public boolean dispatchUnhandledMove(android.view.View, int);
-    method protected void dispatchVisibilityChanged(android.view.View, int);
+    method protected void dispatchVisibilityChanged(@NonNull android.view.View, int);
     method public void dispatchWindowFocusChanged(boolean);
     method public void dispatchWindowSystemUiVisiblityChanged(int);
     method public void dispatchWindowVisibilityChanged(int);
-    method public void draw(android.graphics.Canvas);
-    method public void drawableHotspotChanged(float, float);
-    method protected void drawableStateChanged();
+    method @CallSuper public void draw(android.graphics.Canvas);
+    method @CallSuper public void drawableHotspotChanged(float, float);
+    method @CallSuper protected void drawableStateChanged();
     method public android.view.View findFocus();
-    method public final <T extends android.view.View> T findViewById(int);
-    method public final <T extends android.view.View> T findViewWithTag(java.lang.Object);
-    method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
-    method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
+    method public final <T extends android.view.View> T findViewById(@IdRes int);
+    method public final <T extends android.view.View> T findViewWithTag(Object);
+    method public void findViewsWithText(java.util.ArrayList<android.view.View>, CharSequence, int);
+    method @Deprecated protected boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
     method public void forceHasOverlappingRendering(boolean);
     method public void forceLayout();
     method public static int generateViewId();
-    method public java.lang.CharSequence getAccessibilityClassName();
+    method public CharSequence getAccessibilityClassName();
     method public android.view.View.AccessibilityDelegate getAccessibilityDelegate();
     method public int getAccessibilityLiveRegion();
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
-    method public java.lang.CharSequence getAccessibilityPaneTitle();
+    method @Nullable public CharSequence getAccessibilityPaneTitle();
     method public int getAccessibilityTraversalAfter();
     method public int getAccessibilityTraversalBefore();
-    method public float getAlpha();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getAlpha();
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
-    method public java.lang.String[] getAutofillHints();
+    method @android.view.ViewDebug.ExportedProperty @Nullable public String[] getAutofillHints();
     method public final android.view.autofill.AutofillId getAutofillId();
     method public int getAutofillType();
-    method public android.view.autofill.AutofillValue getAutofillValue();
+    method @Nullable public android.view.autofill.AutofillValue getAutofillValue();
     method public android.graphics.drawable.Drawable getBackground();
-    method public android.content.res.ColorStateList getBackgroundTintList();
-    method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
-    method public int getBaseline();
-    method public final int getBottom();
+    method @Nullable public android.content.res.ColorStateList getBackgroundTintList();
+    method @Nullable public android.graphics.PorterDuff.Mode getBackgroundTintMode();
+    method @android.view.ViewDebug.ExportedProperty(category="layout") public int getBaseline();
+    method @android.view.ViewDebug.CapturedViewProperty public final int getBottom();
     method protected float getBottomFadingEdgeStrength();
     method protected int getBottomPaddingOffset();
     method public float getCameraDistance();
     method public android.graphics.Rect getClipBounds();
     method public boolean getClipBounds(android.graphics.Rect);
     method public final boolean getClipToOutline();
-    method public final android.view.contentcapture.ContentCaptureSession getContentCaptureSession();
-    method public java.lang.CharSequence getContentDescription();
-    method public final android.content.Context getContext();
+    method @Nullable public final android.view.contentcapture.ContentCaptureSession getContentCaptureSession();
+    method @android.view.ViewDebug.ExportedProperty(category="accessibility") public CharSequence getContentDescription();
+    method @android.view.ViewDebug.CapturedViewProperty public final android.content.Context getContext();
     method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo();
-    method public final boolean getDefaultFocusHighlightEnabled();
+    method @android.view.ViewDebug.ExportedProperty(category="focus") public final boolean getDefaultFocusHighlightEnabled();
     method public static int getDefaultSize(int, int);
     method public android.view.Display getDisplay();
     method public final int[] getDrawableState();
-    method public deprecated android.graphics.Bitmap getDrawingCache();
-    method public deprecated android.graphics.Bitmap getDrawingCache(boolean);
-    method public deprecated int getDrawingCacheBackgroundColor();
-    method public deprecated int getDrawingCacheQuality();
+    method @Deprecated public android.graphics.Bitmap getDrawingCache();
+    method @Deprecated public android.graphics.Bitmap getDrawingCache(boolean);
+    method @Deprecated @ColorInt public int getDrawingCacheBackgroundColor();
+    method @Deprecated public int getDrawingCacheQuality();
     method public void getDrawingRect(android.graphics.Rect);
     method public long getDrawingTime();
-    method public float getElevation();
-    method public boolean getFilterTouchesWhenObscured();
-    method public boolean getFitsSystemWindows();
-    method public int getFocusable();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getElevation();
+    method @android.view.ViewDebug.ExportedProperty public boolean getFilterTouchesWhenObscured();
+    method @android.view.ViewDebug.ExportedProperty public boolean getFitsSystemWindows();
+    method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.NOT_FOCUSABLE, to="NOT_FOCUSABLE"), @android.view.ViewDebug.IntToString(from=android.view.View.FOCUSABLE, to="FOCUSABLE"), @android.view.ViewDebug.IntToString(from=android.view.View.FOCUSABLE_AUTO, to="FOCUSABLE_AUTO")}, category="focus") public int getFocusable();
     method public java.util.ArrayList<android.view.View> getFocusables(int);
     method public void getFocusedRect(android.graphics.Rect);
     method public android.graphics.drawable.Drawable getForeground();
     method public int getForegroundGravity();
-    method public android.content.res.ColorStateList getForegroundTintList();
-    method public android.graphics.PorterDuff.Mode getForegroundTintMode();
+    method @Nullable public android.content.res.ColorStateList getForegroundTintList();
+    method @Nullable public android.graphics.PorterDuff.Mode getForegroundTintMode();
     method public boolean getGlobalVisibleRect(android.graphics.Rect, android.graphics.Point);
     method public final boolean getGlobalVisibleRect(android.graphics.Rect);
     method public android.os.Handler getHandler();
     method public final boolean getHasOverlappingRendering();
-    method public final int getHeight();
+    method @android.view.ViewDebug.ExportedProperty(category="layout") public final int getHeight();
     method public void getHitRect(android.graphics.Rect);
     method public int getHorizontalFadingEdgeLength();
     method protected int getHorizontalScrollbarHeight();
-    method public int getId();
-    method public int getImportantForAccessibility();
-    method public int getImportantForAutofill();
-    method public int getImportantForContentCapture();
+    method @android.view.ViewDebug.CapturedViewProperty @IdRes public int getId();
+    method @android.view.ViewDebug.ExportedProperty(category="accessibility", mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, to="noHideDescendants")}) public int getImportantForAccessibility();
+    method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, to="yesExcludeDescendants"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, to="noExcludeDescendants")}) public int getImportantForAutofill();
+    method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to="auto"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_YES, to="yes"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_NO, to="no"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, to="yesExcludeDescendants"), @android.view.ViewDebug.IntToString(from=android.view.View.IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, to="noExcludeDescendants")}) public int getImportantForContentCapture();
     method public boolean getKeepScreenOn();
     method public android.view.KeyEvent.DispatcherState getKeyDispatcherState();
-    method public int getLabelFor();
+    method @android.view.ViewDebug.ExportedProperty(category="accessibility") public int getLabelFor();
     method public int getLayerType();
-    method public int getLayoutDirection();
-    method public android.view.ViewGroup.LayoutParams getLayoutParams();
-    method public final int getLeft();
+    method @android.view.ViewDebug.ExportedProperty(category="layout", mapping={@android.view.ViewDebug.IntToString(from=android.view.View.LAYOUT_DIRECTION_LTR, to="RESOLVED_DIRECTION_LTR"), @android.view.ViewDebug.IntToString(from=android.view.View.LAYOUT_DIRECTION_RTL, to="RESOLVED_DIRECTION_RTL")}) public int getLayoutDirection();
+    method @android.view.ViewDebug.ExportedProperty(deepExport=true, prefix="layout_") public android.view.ViewGroup.LayoutParams getLayoutParams();
+    method @android.view.ViewDebug.CapturedViewProperty public final int getLeft();
     method protected float getLeftFadingEdgeStrength();
     method protected int getLeftPaddingOffset();
     method public final boolean getLocalVisibleRect(android.graphics.Rect);
-    method public void getLocationInWindow(int[]);
-    method public void getLocationOnScreen(int[]);
+    method public void getLocationInWindow(@Size(2) int[]);
+    method public void getLocationOnScreen(@Size(2) int[]);
     method public android.graphics.Matrix getMatrix();
     method public final int getMeasuredHeight();
-    method public final int getMeasuredHeightAndState();
+    method @android.view.ViewDebug.ExportedProperty(category="measurement", flagMapping={@android.view.ViewDebug.FlagToString(mask=android.view.View.MEASURED_STATE_MASK, equals=android.view.View.MEASURED_STATE_TOO_SMALL, name="MEASURED_STATE_TOO_SMALL")}) public final int getMeasuredHeightAndState();
     method public final int getMeasuredState();
     method public final int getMeasuredWidth();
-    method public final int getMeasuredWidthAndState();
+    method @android.view.ViewDebug.ExportedProperty(category="measurement", flagMapping={@android.view.ViewDebug.FlagToString(mask=android.view.View.MEASURED_STATE_MASK, equals=android.view.View.MEASURED_STATE_TOO_SMALL, name="MEASURED_STATE_TOO_SMALL")}) public final int getMeasuredWidthAndState();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
     method public int getNextClusterForwardId();
@@ -49699,9 +50121,9 @@
     method public int getNextFocusRightId();
     method public int getNextFocusUpId();
     method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
-    method public int getOutlineAmbientShadowColor();
+    method @ColorInt public int getOutlineAmbientShadowColor();
     method public android.view.ViewOutlineProvider getOutlineProvider();
-    method public int getOutlineSpotShadowColor();
+    method @ColorInt public int getOutlineSpotShadowColor();
     method public int getOverScrollMode();
     method public android.view.ViewOverlay getOverlay();
     method public int getPaddingBottom();
@@ -49712,141 +50134,141 @@
     method public int getPaddingTop();
     method public final android.view.ViewParent getParent();
     method public android.view.ViewParent getParentForAccessibility();
-    method public float getPivotX();
-    method public float getPivotY();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getPivotX();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getPivotY();
     method public android.view.PointerIcon getPointerIcon();
     method public android.content.res.Resources getResources();
     method public final boolean getRevealOnFocusHint();
-    method public final int getRight();
+    method @android.view.ViewDebug.CapturedViewProperty public final int getRight();
     method protected float getRightFadingEdgeStrength();
     method protected int getRightPaddingOffset();
     method public android.view.View getRootView();
     method public android.view.WindowInsets getRootWindowInsets();
-    method public float getRotation();
-    method public float getRotationX();
-    method public float getRotationY();
-    method public float getScaleX();
-    method public float getScaleY();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getRotation();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getRotationX();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getRotationY();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getScaleX();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getScaleY();
     method public int getScrollBarDefaultDelayBeforeFade();
     method public int getScrollBarFadeDuration();
     method public int getScrollBarSize();
-    method public int getScrollBarStyle();
+    method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.SCROLLBARS_INSIDE_OVERLAY, to="INSIDE_OVERLAY"), @android.view.ViewDebug.IntToString(from=android.view.View.SCROLLBARS_INSIDE_INSET, to="INSIDE_INSET"), @android.view.ViewDebug.IntToString(from=android.view.View.SCROLLBARS_OUTSIDE_OVERLAY, to="OUTSIDE_OVERLAY"), @android.view.ViewDebug.IntToString(from=android.view.View.SCROLLBARS_OUTSIDE_INSET, to="OUTSIDE_INSET")}) public int getScrollBarStyle();
     method public int getScrollIndicators();
     method public final int getScrollX();
     method public final int getScrollY();
-    method public int getSolidColor();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") @ColorInt public int getSolidColor();
     method public android.animation.StateListAnimator getStateListAnimator();
     method protected int getSuggestedMinimumHeight();
     method protected int getSuggestedMinimumWidth();
     method public int getSystemUiVisibility();
-    method public java.lang.Object getTag();
-    method public java.lang.Object getTag(int);
-    method public int getTextAlignment();
-    method public int getTextDirection();
-    method public java.lang.CharSequence getTooltipText();
-    method public final int getTop();
+    method @android.view.ViewDebug.ExportedProperty public Object getTag();
+    method public Object getTag(int);
+    method @android.view.ViewDebug.ExportedProperty(category="text", mapping={@android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_INHERIT, to="INHERIT"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_GRAVITY, to="GRAVITY"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_TEXT_START, to="TEXT_START"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_TEXT_END, to="TEXT_END"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_CENTER, to="CENTER"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_VIEW_START, to="VIEW_START"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_ALIGNMENT_VIEW_END, to="VIEW_END")}) public int getTextAlignment();
+    method @android.view.ViewDebug.ExportedProperty(category="text", mapping={@android.view.ViewDebug.IntToString(from=android.view.View.TEXT_DIRECTION_INHERIT, to="INHERIT"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_DIRECTION_FIRST_STRONG, to="FIRST_STRONG"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_DIRECTION_ANY_RTL, to="ANY_RTL"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_DIRECTION_LTR, to="LTR"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_DIRECTION_RTL, to="RTL"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_DIRECTION_LOCALE, to="LOCALE"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_DIRECTION_FIRST_STRONG_LTR, to="FIRST_STRONG_LTR"), @android.view.ViewDebug.IntToString(from=android.view.View.TEXT_DIRECTION_FIRST_STRONG_RTL, to="FIRST_STRONG_RTL")}) public int getTextDirection();
+    method @Nullable public CharSequence getTooltipText();
+    method @android.view.ViewDebug.CapturedViewProperty public final int getTop();
     method protected float getTopFadingEdgeStrength();
     method protected int getTopPaddingOffset();
     method public android.view.TouchDelegate getTouchDelegate();
     method public java.util.ArrayList<android.view.View> getTouchables();
-    method public float getTransitionAlpha();
-    method public java.lang.String getTransitionName();
-    method public float getTranslationX();
-    method public float getTranslationY();
-    method public float getTranslationZ();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getTransitionAlpha();
+    method @android.view.ViewDebug.ExportedProperty public String getTransitionName();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getTranslationX();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getTranslationY();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getTranslationZ();
     method public long getUniqueDrawingId();
     method public int getVerticalFadingEdgeLength();
     method public int getVerticalScrollbarPosition();
     method public int getVerticalScrollbarWidth();
     method public android.view.ViewTreeObserver getViewTreeObserver();
-    method public int getVisibility();
-    method public final int getWidth();
+    method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.VISIBLE, to="VISIBLE"), @android.view.ViewDebug.IntToString(from=android.view.View.INVISIBLE, to="INVISIBLE"), @android.view.ViewDebug.IntToString(from=android.view.View.GONE, to="GONE")}) public int getVisibility();
+    method @android.view.ViewDebug.ExportedProperty(category="layout") public final int getWidth();
     method protected int getWindowAttachCount();
     method public android.view.WindowId getWindowId();
     method public int getWindowSystemUiVisibility();
     method public android.os.IBinder getWindowToken();
     method public int getWindowVisibility();
     method public void getWindowVisibleDisplayFrame(android.graphics.Rect);
-    method public float getX();
-    method public float getY();
-    method public float getZ();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getX();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getY();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getZ();
     method public boolean hasExplicitFocusable();
-    method public boolean hasFocus();
+    method @android.view.ViewDebug.ExportedProperty(category="focus") public boolean hasFocus();
     method public boolean hasFocusable();
     method public boolean hasNestedScrollingParent();
     method public boolean hasOnClickListeners();
-    method public boolean hasOverlappingRendering();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public boolean hasOverlappingRendering();
     method public boolean hasPointerCapture();
-    method public boolean hasTransientState();
+    method @android.view.ViewDebug.ExportedProperty(category="layout") public boolean hasTransientState();
     method public boolean hasWindowFocus();
-    method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
-    method public deprecated void invalidate(android.graphics.Rect);
-    method public deprecated void invalidate(int, int, int, int);
+    method public static android.view.View inflate(android.content.Context, @LayoutRes int, android.view.ViewGroup);
+    method @Deprecated public void invalidate(android.graphics.Rect);
+    method @Deprecated public void invalidate(int, int, int, int);
     method public void invalidate();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
+    method public void invalidateDrawable(@NonNull android.graphics.drawable.Drawable);
     method public void invalidateOutline();
     method public boolean isAccessibilityFocused();
     method public boolean isAccessibilityHeading();
-    method public boolean isActivated();
+    method @android.view.ViewDebug.ExportedProperty public boolean isActivated();
     method public boolean isAttachedToWindow();
-    method public boolean isClickable();
+    method @android.view.ViewDebug.ExportedProperty public boolean isClickable();
     method public boolean isContextClickable();
     method public boolean isDirty();
-    method public deprecated boolean isDrawingCacheEnabled();
+    method @Deprecated @android.view.ViewDebug.ExportedProperty(category="drawing") public boolean isDrawingCacheEnabled();
     method public boolean isDuplicateParentStateEnabled();
-    method public boolean isEnabled();
-    method public final boolean isFocusable();
-    method public final boolean isFocusableInTouchMode();
-    method public boolean isFocused();
-    method public final boolean isFocusedByDefault();
-    method public boolean isForceDarkAllowed();
-    method public boolean isHapticFeedbackEnabled();
-    method public boolean isHardwareAccelerated();
+    method @android.view.ViewDebug.ExportedProperty public boolean isEnabled();
+    method @android.view.ViewDebug.ExportedProperty(category="focus") public final boolean isFocusable();
+    method @android.view.ViewDebug.ExportedProperty(category="focus") public final boolean isFocusableInTouchMode();
+    method @android.view.ViewDebug.ExportedProperty(category="focus") public boolean isFocused();
+    method @android.view.ViewDebug.ExportedProperty(category="focus") public final boolean isFocusedByDefault();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public boolean isForceDarkAllowed();
+    method @android.view.ViewDebug.ExportedProperty public boolean isHapticFeedbackEnabled();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public boolean isHardwareAccelerated();
     method public boolean isHorizontalFadingEdgeEnabled();
     method public boolean isHorizontalScrollBarEnabled();
-    method public boolean isHovered();
+    method @android.view.ViewDebug.ExportedProperty public boolean isHovered();
     method public boolean isImportantForAccessibility();
     method public final boolean isImportantForAutofill();
     method public final boolean isImportantForContentCapture();
     method public boolean isInEditMode();
     method public boolean isInLayout();
-    method public boolean isInTouchMode();
-    method public final boolean isKeyboardNavigationCluster();
+    method @android.view.ViewDebug.ExportedProperty public boolean isInTouchMode();
+    method @android.view.ViewDebug.ExportedProperty(category="focus") public final boolean isKeyboardNavigationCluster();
     method public boolean isLaidOut();
     method public boolean isLayoutDirectionResolved();
     method public boolean isLayoutRequested();
     method public boolean isLongClickable();
     method public boolean isNestedScrollingEnabled();
-    method public boolean isOpaque();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public boolean isOpaque();
     method protected boolean isPaddingOffsetRequired();
     method public boolean isPaddingRelative();
     method public boolean isPivotSet();
-    method public boolean isPressed();
+    method @android.view.ViewDebug.ExportedProperty public boolean isPressed();
     method public boolean isSaveEnabled();
     method public boolean isSaveFromParentEnabled();
     method public boolean isScreenReaderFocusable();
     method public boolean isScrollContainer();
     method public boolean isScrollbarFadingEnabled();
-    method public boolean isSelected();
+    method @android.view.ViewDebug.ExportedProperty public boolean isSelected();
     method public boolean isShown();
-    method public boolean isSoundEffectsEnabled();
+    method @android.view.ViewDebug.ExportedProperty public boolean isSoundEffectsEnabled();
     method public final boolean isTemporarilyDetached();
     method public boolean isTextAlignmentResolved();
     method public boolean isTextDirectionResolved();
     method public boolean isVerticalFadingEdgeEnabled();
     method public boolean isVerticalScrollBarEnabled();
     method public boolean isVisibleToUserForAutofill(int);
-    method public void jumpDrawablesToCurrentState();
+    method @CallSuper public void jumpDrawablesToCurrentState();
     method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
     method public void layout(int, int, int, int);
     method public final void measure(int, int);
     method protected static int[] mergeDrawableStates(int[], int[]);
     method public void offsetLeftAndRight(int);
     method public void offsetTopAndBottom(int);
-    method protected void onAnimationEnd();
-    method protected void onAnimationStart();
+    method @CallSuper protected void onAnimationEnd();
+    method @CallSuper protected void onAnimationStart();
     method public android.view.WindowInsets onApplyWindowInsets(android.view.WindowInsets);
-    method protected void onAttachedToWindow();
+    method @CallSuper protected void onAttachedToWindow();
     method public void onCancelPendingInputEvents();
     method public boolean onCapturedPointerEvent(android.view.MotionEvent);
     method public boolean onCheckIsTextEditor();
@@ -49854,21 +50276,21 @@
     method protected void onCreateContextMenu(android.view.ContextMenu);
     method protected int[] onCreateDrawableState(int);
     method public android.view.inputmethod.InputConnection onCreateInputConnection(android.view.inputmethod.EditorInfo);
-    method protected void onDetachedFromWindow();
+    method @CallSuper protected void onDetachedFromWindow();
     method protected void onDisplayHint(int);
     method public boolean onDragEvent(android.view.DragEvent);
     method protected void onDraw(android.graphics.Canvas);
     method public void onDrawForeground(android.graphics.Canvas);
     method protected final void onDrawScrollBars(android.graphics.Canvas);
     method public boolean onFilterTouchEventForSecurity(android.view.MotionEvent);
-    method protected void onFinishInflate();
+    method @CallSuper protected void onFinishInflate();
     method public void onFinishTemporaryDetach();
-    method protected void onFocusChanged(boolean, int, android.graphics.Rect);
+    method @CallSuper protected void onFocusChanged(boolean, int, @Nullable android.graphics.Rect);
     method public boolean onGenericMotionEvent(android.view.MotionEvent);
     method public void onHoverChanged(boolean);
     method public boolean onHoverEvent(android.view.MotionEvent);
-    method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public void onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo);
+    method @CallSuper public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method @CallSuper public void onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo);
     method public boolean onKeyDown(int, android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
@@ -49878,17 +50300,17 @@
     method protected void onLayout(boolean, int, int, int, int);
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
-    method public void onPointerCaptureChange(boolean);
-    method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method @CallSuper public void onPointerCaptureChange(boolean);
+    method @CallSuper public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public void onProvideAutofillStructure(android.view.ViewStructure, int);
     method public void onProvideAutofillVirtualStructure(android.view.ViewStructure, int);
-    method public void onProvideContentCaptureStructure(android.view.ViewStructure, int);
+    method public void onProvideContentCaptureStructure(@NonNull android.view.ViewStructure, int);
     method public void onProvideStructure(android.view.ViewStructure);
     method public void onProvideVirtualStructure(android.view.ViewStructure);
     method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
-    method protected void onRestoreInstanceState(android.os.Parcelable);
+    method @CallSuper protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
-    method protected android.os.Parcelable onSaveInstanceState();
+    method @CallSuper @Nullable protected android.os.Parcelable onSaveInstanceState();
     method public void onScreenStateChanged(int);
     method protected void onScrollChanged(int, int, int, int);
     method protected boolean onSetAlpha(int);
@@ -49896,8 +50318,8 @@
     method public void onStartTemporaryDetach();
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
-    method public void onVisibilityAggregated(boolean);
-    method protected void onVisibilityChanged(android.view.View, int);
+    method @CallSuper public void onVisibilityAggregated(boolean);
+    method protected void onVisibilityChanged(@NonNull android.view.View, int);
     method public void onWindowFocusChanged(boolean);
     method public void onWindowSystemUiVisibilityChanged(int);
     method protected void onWindowVisibilityChanged(int);
@@ -49911,75 +50333,75 @@
     method public boolean performLongClick();
     method public boolean performLongClick(float, float);
     method public void playSoundEffect(int);
-    method public boolean post(java.lang.Runnable);
-    method public boolean postDelayed(java.lang.Runnable, long);
+    method public boolean post(Runnable);
+    method public boolean postDelayed(Runnable, long);
     method public void postInvalidate();
     method public void postInvalidate(int, int, int, int);
     method public void postInvalidateDelayed(long);
     method public void postInvalidateDelayed(long, int, int, int, int);
     method public void postInvalidateOnAnimation();
     method public void postInvalidateOnAnimation(int, int, int, int);
-    method public void postOnAnimation(java.lang.Runnable);
-    method public void postOnAnimationDelayed(java.lang.Runnable, long);
+    method public void postOnAnimation(Runnable);
+    method public void postOnAnimationDelayed(Runnable, long);
     method public void refreshDrawableState();
     method public void releasePointerCapture();
-    method public boolean removeCallbacks(java.lang.Runnable);
+    method public boolean removeCallbacks(Runnable);
     method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
     method public void removeOnUnhandledKeyEventListener(android.view.View.OnUnhandledKeyEventListener);
     method public void requestApplyInsets();
-    method public deprecated void requestFitSystemWindows();
+    method @Deprecated public void requestFitSystemWindows();
     method public final boolean requestFocus();
     method public final boolean requestFocus(int);
     method public boolean requestFocus(int, android.graphics.Rect);
     method public final boolean requestFocusFromTouch();
-    method public void requestLayout();
+    method @CallSuper public void requestLayout();
     method public void requestPointerCapture();
     method public boolean requestRectangleOnScreen(android.graphics.Rect);
     method public boolean requestRectangleOnScreen(android.graphics.Rect, boolean);
     method public final void requestUnbufferedDispatch(android.view.MotionEvent);
-    method public final <T extends android.view.View> T requireViewById(int);
+    method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
     method public void resetPivot();
     method public static int resolveSize(int, int);
     method public static int resolveSizeAndState(int, int, int);
     method public boolean restoreDefaultFocus();
     method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>);
     method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+    method public void scheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable, long);
     method public void scrollBy(int, int);
     method public void scrollTo(int, int);
     method public void sendAccessibilityEvent(int);
     method public void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent);
-    method public void setAccessibilityDelegate(android.view.View.AccessibilityDelegate);
+    method public void setAccessibilityDelegate(@Nullable android.view.View.AccessibilityDelegate);
     method public void setAccessibilityHeading(boolean);
     method public void setAccessibilityLiveRegion(int);
-    method public void setAccessibilityPaneTitle(java.lang.CharSequence);
+    method public void setAccessibilityPaneTitle(@Nullable CharSequence);
     method public void setAccessibilityTraversalAfter(int);
     method public void setAccessibilityTraversalBefore(int);
     method public void setActivated(boolean);
-    method public void setAlpha(float);
+    method public void setAlpha(@FloatRange(from=0.0, to=1.0) float);
     method public void setAnimation(android.view.animation.Animation);
-    method public void setAnimationMatrix(android.graphics.Matrix);
-    method public void setAutofillHints(java.lang.String...);
-    method public void setAutofillId(android.view.autofill.AutofillId);
+    method public void setAnimationMatrix(@Nullable android.graphics.Matrix);
+    method public void setAutofillHints(@Nullable java.lang.String...);
+    method public void setAutofillId(@Nullable android.view.autofill.AutofillId);
     method public void setBackground(android.graphics.drawable.Drawable);
-    method public void setBackgroundColor(int);
-    method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setBackgroundResource(int);
-    method public void setBackgroundTintList(android.content.res.ColorStateList);
-    method public void setBackgroundTintMode(android.graphics.PorterDuff.Mode);
+    method public void setBackgroundColor(@ColorInt int);
+    method @Deprecated public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setBackgroundResource(@DrawableRes int);
+    method public void setBackgroundTintList(@Nullable android.content.res.ColorStateList);
+    method public void setBackgroundTintMode(@Nullable android.graphics.PorterDuff.Mode);
     method public final void setBottom(int);
     method public void setCameraDistance(float);
     method public void setClickable(boolean);
     method public void setClipBounds(android.graphics.Rect);
     method public void setClipToOutline(boolean);
-    method public void setContentCaptureSession(android.view.contentcapture.ContentCaptureSession);
-    method public void setContentDescription(java.lang.CharSequence);
+    method public void setContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSession);
+    method public void setContentDescription(CharSequence);
     method public void setContextClickable(boolean);
     method public void setDefaultFocusHighlightEnabled(boolean);
-    method public deprecated void setDrawingCacheBackgroundColor(int);
-    method public deprecated void setDrawingCacheEnabled(boolean);
-    method public deprecated void setDrawingCacheQuality(int);
+    method @Deprecated public void setDrawingCacheBackgroundColor(@ColorInt int);
+    method @Deprecated public void setDrawingCacheEnabled(boolean);
+    method @Deprecated public void setDrawingCacheQuality(int);
     method public void setDuplicateParentStateEnabled(boolean);
     method public void setElevation(float);
     method public void setEnabled(boolean);
@@ -49993,22 +50415,22 @@
     method public void setForceDarkAllowed(boolean);
     method public void setForeground(android.graphics.drawable.Drawable);
     method public void setForegroundGravity(int);
-    method public void setForegroundTintList(android.content.res.ColorStateList);
-    method public void setForegroundTintMode(android.graphics.PorterDuff.Mode);
+    method public void setForegroundTintList(@Nullable android.content.res.ColorStateList);
+    method public void setForegroundTintMode(@Nullable android.graphics.PorterDuff.Mode);
     method public void setHapticFeedbackEnabled(boolean);
     method public void setHasTransientState(boolean);
     method public void setHorizontalFadingEdgeEnabled(boolean);
     method public void setHorizontalScrollBarEnabled(boolean);
     method public void setHovered(boolean);
-    method public void setId(int);
+    method public void setId(@IdRes int);
     method public void setImportantForAccessibility(int);
     method public void setImportantForAutofill(int);
     method public void setImportantForContentCapture(int);
     method public void setKeepScreenOn(boolean);
     method public void setKeyboardNavigationCluster(boolean);
-    method public void setLabelFor(int);
-    method public void setLayerPaint(android.graphics.Paint);
-    method public void setLayerType(int, android.graphics.Paint);
+    method public void setLabelFor(@IdRes int);
+    method public void setLayerPaint(@Nullable android.graphics.Paint);
+    method public void setLayerType(int, @Nullable android.graphics.Paint);
     method public void setLayoutDirection(int);
     method public void setLayoutParams(android.view.ViewGroup.LayoutParams);
     method public final void setLeft(int);
@@ -50026,21 +50448,21 @@
     method public void setNextFocusUpId(int);
     method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
     method public void setOnCapturedPointerListener(android.view.View.OnCapturedPointerListener);
-    method public void setOnClickListener(android.view.View.OnClickListener);
-    method public void setOnContextClickListener(android.view.View.OnContextClickListener);
+    method public void setOnClickListener(@Nullable android.view.View.OnClickListener);
+    method public void setOnContextClickListener(@Nullable android.view.View.OnContextClickListener);
     method public void setOnCreateContextMenuListener(android.view.View.OnCreateContextMenuListener);
     method public void setOnDragListener(android.view.View.OnDragListener);
     method public void setOnFocusChangeListener(android.view.View.OnFocusChangeListener);
     method public void setOnGenericMotionListener(android.view.View.OnGenericMotionListener);
     method public void setOnHoverListener(android.view.View.OnHoverListener);
     method public void setOnKeyListener(android.view.View.OnKeyListener);
-    method public void setOnLongClickListener(android.view.View.OnLongClickListener);
+    method public void setOnLongClickListener(@Nullable android.view.View.OnLongClickListener);
     method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
     method public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
     method public void setOnTouchListener(android.view.View.OnTouchListener);
-    method public void setOutlineAmbientShadowColor(int);
+    method public void setOutlineAmbientShadowColor(@ColorInt int);
     method public void setOutlineProvider(android.view.ViewOutlineProvider);
-    method public void setOutlineSpotShadowColor(int);
+    method public void setOutlineSpotShadowColor(@ColorInt int);
     method public void setOverScrollMode(int);
     method public void setPadding(int, int, int, int);
     method public void setPaddingRelative(int, int, int, int);
@@ -50072,15 +50494,15 @@
     method public void setSoundEffectsEnabled(boolean);
     method public void setStateListAnimator(android.animation.StateListAnimator);
     method public void setSystemUiVisibility(int);
-    method public void setTag(java.lang.Object);
-    method public void setTag(int, java.lang.Object);
+    method public void setTag(Object);
+    method public void setTag(int, Object);
     method public void setTextAlignment(int);
     method public void setTextDirection(int);
-    method public void setTooltipText(java.lang.CharSequence);
+    method public void setTooltipText(@Nullable CharSequence);
     method public final void setTop(int);
     method public void setTouchDelegate(android.view.TouchDelegate);
     method public void setTransitionAlpha(float);
-    method public final void setTransitionName(java.lang.String);
+    method public final void setTransitionName(String);
     method public void setTranslationX(float);
     method public void setTranslationY(float);
     method public void setTranslationZ(float);
@@ -50088,7 +50510,7 @@
     method public void setVerticalScrollBarEnabled(boolean);
     method public void setVerticalScrollbarPosition(int);
     method public void setVisibility(int);
-    method public deprecated void setWillNotCacheDrawing(boolean);
+    method @Deprecated public void setWillNotCacheDrawing(boolean);
     method public void setWillNotDraw(boolean);
     method public void setX(float);
     method public void setY(float);
@@ -50098,36 +50520,36 @@
     method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
     method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int);
     method public void startAnimation(android.view.animation.Animation);
-    method public final deprecated boolean startDrag(android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int);
-    method public final boolean startDragAndDrop(android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int);
+    method @Deprecated public final boolean startDrag(android.content.ClipData, android.view.View.DragShadowBuilder, Object, int);
+    method public final boolean startDragAndDrop(android.content.ClipData, android.view.View.DragShadowBuilder, Object, int);
     method public boolean startNestedScroll(int);
     method public void stopNestedScroll();
     method public void transformMatrixToGlobal(android.graphics.Matrix);
     method public void transformMatrixToLocal(android.graphics.Matrix);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+    method public void unscheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable);
     method public final void updateDragShadow(android.view.View.DragShadowBuilder);
-    method protected boolean verifyDrawable(android.graphics.drawable.Drawable);
-    method public deprecated boolean willNotCacheDrawing();
-    method public boolean willNotDraw();
+    method @CallSuper protected boolean verifyDrawable(@NonNull android.graphics.drawable.Drawable);
+    method @Deprecated @android.view.ViewDebug.ExportedProperty(category="drawing") public boolean willNotCacheDrawing();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public boolean willNotDraw();
     field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
     field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
     field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
-    field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA;
+    field public static final android.util.Property<android.view.View,java.lang.Float> ALPHA;
     field public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 1; // 0x1
-    field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate";
-    field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay";
-    field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth";
-    field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = "creditCardExpirationYear";
-    field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber";
-    field public static final java.lang.String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode";
-    field public static final java.lang.String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress";
-    field public static final java.lang.String AUTOFILL_HINT_NAME = "name";
-    field public static final java.lang.String AUTOFILL_HINT_PASSWORD = "password";
-    field public static final java.lang.String AUTOFILL_HINT_PHONE = "phone";
-    field public static final java.lang.String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress";
-    field public static final java.lang.String AUTOFILL_HINT_POSTAL_CODE = "postalCode";
-    field public static final java.lang.String AUTOFILL_HINT_USERNAME = "username";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = "creditCardExpirationYear";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode";
+    field public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress";
+    field public static final String AUTOFILL_HINT_NAME = "name";
+    field public static final String AUTOFILL_HINT_PASSWORD = "password";
+    field public static final String AUTOFILL_HINT_PHONE = "phone";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress";
+    field public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode";
+    field public static final String AUTOFILL_HINT_USERNAME = "username";
     field public static final int AUTOFILL_TYPE_DATE = 4; // 0x4
     field public static final int AUTOFILL_TYPE_LIST = 3; // 0x3
     field public static final int AUTOFILL_TYPE_NONE = 0; // 0x0
@@ -50139,9 +50561,9 @@
     field public static final int DRAG_FLAG_GLOBAL_URI_READ = 1; // 0x1
     field public static final int DRAG_FLAG_GLOBAL_URI_WRITE = 2; // 0x2
     field public static final int DRAG_FLAG_OPAQUE = 512; // 0x200
-    field public static final deprecated int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
-    field public static final deprecated int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
-    field public static final deprecated int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000
+    field @Deprecated public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
+    field @Deprecated public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
+    field @Deprecated public static final int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000
     field protected static final int[] EMPTY_STATE_SET;
     field protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET;
     field protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
@@ -50217,11 +50639,11 @@
     field protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
     field protected static final int[] PRESSED_STATE_SET;
     field protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET;
-    field public static final android.util.Property<android.view.View, java.lang.Float> ROTATION;
-    field public static final android.util.Property<android.view.View, java.lang.Float> ROTATION_X;
-    field public static final android.util.Property<android.view.View, java.lang.Float> ROTATION_Y;
-    field public static final android.util.Property<android.view.View, java.lang.Float> SCALE_X;
-    field public static final android.util.Property<android.view.View, java.lang.Float> SCALE_Y;
+    field public static final android.util.Property<android.view.View,java.lang.Float> ROTATION;
+    field public static final android.util.Property<android.view.View,java.lang.Float> ROTATION_X;
+    field public static final android.util.Property<android.view.View,java.lang.Float> ROTATION_Y;
+    field public static final android.util.Property<android.view.View,java.lang.Float> SCALE_X;
+    field public static final android.util.Property<android.view.View,java.lang.Float> SCALE_Y;
     field public static final int SCREEN_STATE_OFF = 0; // 0x0
     field public static final int SCREEN_STATE_ON = 1; // 0x1
     field public static final int SCROLLBARS_INSIDE_INSET = 16777216; // 0x1000000
@@ -50243,8 +50665,8 @@
     field protected static final int[] SELECTED_STATE_SET;
     field protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET;
     field public static final int SOUND_EFFECTS_ENABLED = 134217728; // 0x8000000
-    field public static final deprecated int STATUS_BAR_HIDDEN = 1; // 0x1
-    field public static final deprecated int STATUS_BAR_VISIBLE = 0; // 0x0
+    field @Deprecated public static final int STATUS_BAR_HIDDEN = 1; // 0x1
+    field @Deprecated public static final int STATUS_BAR_VISIBLE = 0; // 0x0
     field public static final int SYSTEM_UI_FLAG_FULLSCREEN = 4; // 0x4
     field public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2; // 0x2
     field public static final int SYSTEM_UI_FLAG_IMMERSIVE = 2048; // 0x800
@@ -50272,20 +50694,20 @@
     field public static final int TEXT_DIRECTION_LOCALE = 5; // 0x5
     field public static final int TEXT_DIRECTION_LTR = 3; // 0x3
     field public static final int TEXT_DIRECTION_RTL = 4; // 0x4
-    field public static final android.util.Property<android.view.View, java.lang.Float> TRANSLATION_X;
-    field public static final android.util.Property<android.view.View, java.lang.Float> TRANSLATION_Y;
-    field public static final android.util.Property<android.view.View, java.lang.Float> TRANSLATION_Z;
-    field protected static final java.lang.String VIEW_LOG_TAG = "View";
+    field public static final android.util.Property<android.view.View,java.lang.Float> TRANSLATION_X;
+    field public static final android.util.Property<android.view.View,java.lang.Float> TRANSLATION_Y;
+    field public static final android.util.Property<android.view.View,java.lang.Float> TRANSLATION_Z;
+    field protected static final String VIEW_LOG_TAG = "View";
     field public static final int VISIBLE = 0; // 0x0
     field protected static final int[] WINDOW_FOCUSED_STATE_SET;
-    field public static final android.util.Property<android.view.View, java.lang.Float> X;
-    field public static final android.util.Property<android.view.View, java.lang.Float> Y;
-    field public static final android.util.Property<android.view.View, java.lang.Float> Z;
+    field public static final android.util.Property<android.view.View,java.lang.Float> X;
+    field public static final android.util.Property<android.view.View,java.lang.Float> Y;
+    field public static final android.util.Property<android.view.View,java.lang.Float> Z;
   }
 
   public static class View.AccessibilityDelegate {
     ctor public View.AccessibilityDelegate();
-    method public void addExtraDataToAccessibilityNodeInfo(android.view.View, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
+    method public void addExtraDataToAccessibilityNodeInfo(@NonNull android.view.View, @NonNull android.view.accessibility.AccessibilityNodeInfo, @NonNull String, @Nullable android.os.Bundle);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider(android.view.View);
     method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
@@ -50299,7 +50721,7 @@
 
   public static class View.BaseSavedState extends android.view.AbsSavedState {
     ctor public View.BaseSavedState(android.os.Parcel);
-    ctor public View.BaseSavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public View.BaseSavedState(android.os.Parcel, ClassLoader);
     ctor public View.BaseSavedState(android.os.Parcelable);
     field public static final android.os.Parcelable.Creator<android.view.View.BaseSavedState> CREATOR;
   }
@@ -50316,80 +50738,80 @@
     ctor public View.MeasureSpec();
     method public static int getMode(int);
     method public static int getSize(int);
-    method public static int makeMeasureSpec(int, int);
-    method public static java.lang.String toString(int);
+    method public static int makeMeasureSpec(@IntRange(from=0, to=0x40000000 - 1) int, int);
+    method public static String toString(int);
     field public static final int AT_MOST = -2147483648; // 0x80000000
     field public static final int EXACTLY = 1073741824; // 0x40000000
     field public static final int UNSPECIFIED = 0; // 0x0
   }
 
-  public static abstract interface View.OnApplyWindowInsetsListener {
-    method public abstract android.view.WindowInsets onApplyWindowInsets(android.view.View, android.view.WindowInsets);
+  public static interface View.OnApplyWindowInsetsListener {
+    method public android.view.WindowInsets onApplyWindowInsets(android.view.View, android.view.WindowInsets);
   }
 
-  public static abstract interface View.OnAttachStateChangeListener {
-    method public abstract void onViewAttachedToWindow(android.view.View);
-    method public abstract void onViewDetachedFromWindow(android.view.View);
+  public static interface View.OnAttachStateChangeListener {
+    method public void onViewAttachedToWindow(android.view.View);
+    method public void onViewDetachedFromWindow(android.view.View);
   }
 
-  public static abstract interface View.OnCapturedPointerListener {
-    method public abstract boolean onCapturedPointer(android.view.View, android.view.MotionEvent);
+  public static interface View.OnCapturedPointerListener {
+    method public boolean onCapturedPointer(android.view.View, android.view.MotionEvent);
   }
 
-  public static abstract interface View.OnClickListener {
-    method public abstract void onClick(android.view.View);
+  public static interface View.OnClickListener {
+    method public void onClick(android.view.View);
   }
 
-  public static abstract interface View.OnContextClickListener {
-    method public abstract boolean onContextClick(android.view.View);
+  public static interface View.OnContextClickListener {
+    method public boolean onContextClick(android.view.View);
   }
 
-  public static abstract interface View.OnCreateContextMenuListener {
-    method public abstract void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
+  public static interface View.OnCreateContextMenuListener {
+    method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
   }
 
-  public static abstract interface View.OnDragListener {
-    method public abstract boolean onDrag(android.view.View, android.view.DragEvent);
+  public static interface View.OnDragListener {
+    method public boolean onDrag(android.view.View, android.view.DragEvent);
   }
 
-  public static abstract interface View.OnFocusChangeListener {
-    method public abstract void onFocusChange(android.view.View, boolean);
+  public static interface View.OnFocusChangeListener {
+    method public void onFocusChange(android.view.View, boolean);
   }
 
-  public static abstract interface View.OnGenericMotionListener {
-    method public abstract boolean onGenericMotion(android.view.View, android.view.MotionEvent);
+  public static interface View.OnGenericMotionListener {
+    method public boolean onGenericMotion(android.view.View, android.view.MotionEvent);
   }
 
-  public static abstract interface View.OnHoverListener {
-    method public abstract boolean onHover(android.view.View, android.view.MotionEvent);
+  public static interface View.OnHoverListener {
+    method public boolean onHover(android.view.View, android.view.MotionEvent);
   }
 
-  public static abstract interface View.OnKeyListener {
-    method public abstract boolean onKey(android.view.View, int, android.view.KeyEvent);
+  public static interface View.OnKeyListener {
+    method public boolean onKey(android.view.View, int, android.view.KeyEvent);
   }
 
-  public static abstract interface View.OnLayoutChangeListener {
-    method public abstract void onLayoutChange(android.view.View, int, int, int, int, int, int, int, int);
+  public static interface View.OnLayoutChangeListener {
+    method public void onLayoutChange(android.view.View, int, int, int, int, int, int, int, int);
   }
 
-  public static abstract interface View.OnLongClickListener {
-    method public abstract boolean onLongClick(android.view.View);
+  public static interface View.OnLongClickListener {
+    method public boolean onLongClick(android.view.View);
   }
 
-  public static abstract interface View.OnScrollChangeListener {
-    method public abstract void onScrollChange(android.view.View, int, int, int, int);
+  public static interface View.OnScrollChangeListener {
+    method public void onScrollChange(android.view.View, int, int, int, int);
   }
 
-  public static abstract interface View.OnSystemUiVisibilityChangeListener {
-    method public abstract void onSystemUiVisibilityChange(int);
+  public static interface View.OnSystemUiVisibilityChangeListener {
+    method public void onSystemUiVisibilityChange(int);
   }
 
-  public static abstract interface View.OnTouchListener {
-    method public abstract boolean onTouch(android.view.View, android.view.MotionEvent);
+  public static interface View.OnTouchListener {
+    method public boolean onTouch(android.view.View, android.view.MotionEvent);
   }
 
-  public static abstract interface View.OnUnhandledKeyEventListener {
-    method public abstract boolean onUnhandledKeyEvent(android.view.View, android.view.KeyEvent);
+  public static interface View.OnUnhandledKeyEventListener {
+    method public boolean onUnhandledKeyEvent(android.view.View, android.view.KeyEvent);
   }
 
   public final class ViewAnimationUtils {
@@ -50397,20 +50819,20 @@
   }
 
   public class ViewConfiguration {
-    ctor public deprecated ViewConfiguration();
+    ctor @Deprecated public ViewConfiguration();
     method public static android.view.ViewConfiguration get(android.content.Context);
     method public static long getDefaultActionModeHideDuration();
     method public static int getDoubleTapTimeout();
-    method public static deprecated int getEdgeSlop();
-    method public static deprecated int getFadingEdgeLength();
-    method public static deprecated long getGlobalActionKeyTimeout();
+    method @Deprecated public static int getEdgeSlop();
+    method @Deprecated public static int getFadingEdgeLength();
+    method @Deprecated public static long getGlobalActionKeyTimeout();
     method public static int getJumpTapTimeout();
     method public static int getKeyRepeatDelay();
     method public static int getKeyRepeatTimeout();
     method public static int getLongPressTimeout();
-    method public static deprecated int getMaximumDrawingCacheSize();
-    method public static deprecated int getMaximumFlingVelocity();
-    method public static deprecated int getMinimumFlingVelocity();
+    method @Deprecated public static int getMaximumDrawingCacheSize();
+    method @Deprecated public static int getMaximumFlingVelocity();
+    method @Deprecated public static int getMinimumFlingVelocity();
     method public static int getPressedStateDuration();
     method public int getScaledDoubleTapSlop();
     method public int getScaledEdgeSlop();
@@ -50428,12 +50850,12 @@
     method public float getScaledVerticalScrollFactor();
     method public int getScaledWindowTouchSlop();
     method public static int getScrollBarFadeDuration();
-    method public static deprecated int getScrollBarSize();
+    method @Deprecated public static int getScrollBarSize();
     method public static int getScrollDefaultDelay();
     method public static float getScrollFriction();
     method public static int getTapTimeout();
-    method public static deprecated int getTouchSlop();
-    method public static deprecated int getWindowTouchSlop();
+    method @Deprecated public static int getTouchSlop();
+    method @Deprecated public static int getWindowTouchSlop();
     method public static long getZoomControlsTimeout();
     method public boolean hasPermanentMenuKey();
     method public boolean shouldShowMenuShortcutsWhenKeyboardPresent();
@@ -50441,54 +50863,66 @@
 
   public class ViewDebug {
     ctor public ViewDebug();
-    method public static void dumpCapturedView(java.lang.String, java.lang.Object);
-    method public static deprecated void startHierarchyTracing(java.lang.String, android.view.View);
-    method public static deprecated void startRecyclerTracing(java.lang.String, android.view.View);
-    method public static deprecated void stopHierarchyTracing();
-    method public static deprecated void stopRecyclerTracing();
-    method public static deprecated void trace(android.view.View, android.view.ViewDebug.RecyclerTraceType, int...);
-    method public static deprecated void trace(android.view.View, android.view.ViewDebug.HierarchyTraceType);
-    field public static final deprecated boolean TRACE_HIERARCHY = false;
-    field public static final deprecated boolean TRACE_RECYCLER = false;
+    method public static void dumpCapturedView(String, Object);
+    method @Deprecated public static void startHierarchyTracing(String, android.view.View);
+    method @Deprecated public static void startRecyclerTracing(String, android.view.View);
+    method @Deprecated public static void stopHierarchyTracing();
+    method @Deprecated public static void stopRecyclerTracing();
+    method @Deprecated public static void trace(android.view.View, android.view.ViewDebug.RecyclerTraceType, int...);
+    method @Deprecated public static void trace(android.view.View, android.view.ViewDebug.HierarchyTraceType);
+    field @Deprecated public static final boolean TRACE_HIERARCHY = false;
+    field @Deprecated public static final boolean TRACE_RECYCLER = false;
   }
 
-  public static abstract class ViewDebug.CapturedViewProperty implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface ViewDebug.CapturedViewProperty {
+    method public abstract boolean retrieveReturn() default false;
   }
 
-  public static abstract class ViewDebug.ExportedProperty implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface ViewDebug.ExportedProperty {
+    method public abstract String category() default "";
+    method public abstract boolean deepExport() default false;
+    method public abstract android.view.ViewDebug.FlagToString[] flagMapping() default {};
+    method public abstract boolean formatToHexString() default false;
+    method public abstract boolean hasAdjacentMapping() default false;
+    method public abstract android.view.ViewDebug.IntToString[] indexMapping() default {};
+    method public abstract android.view.ViewDebug.IntToString[] mapping() default {};
+    method public abstract String prefix() default "";
+    method public abstract boolean resolveId() default false;
   }
 
-  public static abstract class ViewDebug.FlagToString implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface ViewDebug.FlagToString {
+    method public abstract int equals();
+    method public abstract int mask();
+    method public abstract String name();
+    method public abstract boolean outputIf() default true;
   }
 
-  public static final deprecated class ViewDebug.HierarchyTraceType extends java.lang.Enum {
-    method public static android.view.ViewDebug.HierarchyTraceType valueOf(java.lang.String);
-    method public static final android.view.ViewDebug.HierarchyTraceType[] values();
-    enum_constant public static final android.view.ViewDebug.HierarchyTraceType BUILD_CACHE;
-    enum_constant public static final android.view.ViewDebug.HierarchyTraceType DRAW;
-    enum_constant public static final android.view.ViewDebug.HierarchyTraceType INVALIDATE;
-    enum_constant public static final android.view.ViewDebug.HierarchyTraceType INVALIDATE_CHILD;
-    enum_constant public static final android.view.ViewDebug.HierarchyTraceType INVALIDATE_CHILD_IN_PARENT;
-    enum_constant public static final android.view.ViewDebug.HierarchyTraceType ON_LAYOUT;
-    enum_constant public static final android.view.ViewDebug.HierarchyTraceType ON_MEASURE;
-    enum_constant public static final android.view.ViewDebug.HierarchyTraceType REQUEST_LAYOUT;
+  @Deprecated public enum ViewDebug.HierarchyTraceType {
+    enum_constant @Deprecated public static final android.view.ViewDebug.HierarchyTraceType BUILD_CACHE;
+    enum_constant @Deprecated public static final android.view.ViewDebug.HierarchyTraceType DRAW;
+    enum_constant @Deprecated public static final android.view.ViewDebug.HierarchyTraceType INVALIDATE;
+    enum_constant @Deprecated public static final android.view.ViewDebug.HierarchyTraceType INVALIDATE_CHILD;
+    enum_constant @Deprecated public static final android.view.ViewDebug.HierarchyTraceType INVALIDATE_CHILD_IN_PARENT;
+    enum_constant @Deprecated public static final android.view.ViewDebug.HierarchyTraceType ON_LAYOUT;
+    enum_constant @Deprecated public static final android.view.ViewDebug.HierarchyTraceType ON_MEASURE;
+    enum_constant @Deprecated public static final android.view.ViewDebug.HierarchyTraceType REQUEST_LAYOUT;
   }
 
-  public static abstract class ViewDebug.IntToString implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface ViewDebug.IntToString {
+    method public abstract int from();
+    method public abstract String to();
   }
 
-  public static final deprecated class ViewDebug.RecyclerTraceType extends java.lang.Enum {
-    method public static android.view.ViewDebug.RecyclerTraceType valueOf(java.lang.String);
-    method public static final android.view.ViewDebug.RecyclerTraceType[] values();
-    enum_constant public static final android.view.ViewDebug.RecyclerTraceType BIND_VIEW;
-    enum_constant public static final android.view.ViewDebug.RecyclerTraceType MOVE_FROM_ACTIVE_TO_SCRAP_HEAP;
-    enum_constant public static final android.view.ViewDebug.RecyclerTraceType MOVE_TO_SCRAP_HEAP;
-    enum_constant public static final android.view.ViewDebug.RecyclerTraceType NEW_VIEW;
-    enum_constant public static final android.view.ViewDebug.RecyclerTraceType RECYCLE_FROM_ACTIVE_HEAP;
-    enum_constant public static final android.view.ViewDebug.RecyclerTraceType RECYCLE_FROM_SCRAP_HEAP;
+  @Deprecated public enum ViewDebug.RecyclerTraceType {
+    enum_constant @Deprecated public static final android.view.ViewDebug.RecyclerTraceType BIND_VIEW;
+    enum_constant @Deprecated public static final android.view.ViewDebug.RecyclerTraceType MOVE_FROM_ACTIVE_TO_SCRAP_HEAP;
+    enum_constant @Deprecated public static final android.view.ViewDebug.RecyclerTraceType MOVE_TO_SCRAP_HEAP;
+    enum_constant @Deprecated public static final android.view.ViewDebug.RecyclerTraceType NEW_VIEW;
+    enum_constant @Deprecated public static final android.view.ViewDebug.RecyclerTraceType RECYCLE_FROM_ACTIVE_HEAP;
+    enum_constant @Deprecated public static final android.view.ViewDebug.RecyclerTraceType RECYCLE_FROM_SCRAP_HEAP;
   }
 
-  public abstract class ViewGroup extends android.view.View implements android.view.ViewManager android.view.ViewParent {
+  @UiThread public abstract class ViewGroup extends android.view.View implements android.view.ViewManager android.view.ViewParent {
     ctor public ViewGroup(android.content.Context);
     ctor public ViewGroup(android.content.Context, android.util.AttributeSet);
     ctor public ViewGroup(android.content.Context, android.util.AttributeSet, int);
@@ -50534,9 +50968,9 @@
     method public static int getChildMeasureSpec(int, int, int);
     method protected boolean getChildStaticTransformation(android.view.View, android.view.animation.Transformation);
     method public boolean getChildVisibleRect(android.view.View, android.graphics.Rect, android.graphics.Point);
-    method public boolean getClipChildren();
-    method public boolean getClipToPadding();
-    method public int getDescendantFocusability();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public boolean getClipChildren();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") public boolean getClipToPadding();
+    method @android.view.ViewDebug.ExportedProperty(category="focus", mapping={@android.view.ViewDebug.IntToString(from=android.view.ViewGroup.FOCUS_BEFORE_DESCENDANTS, to="FOCUS_BEFORE_DESCENDANTS"), @android.view.ViewDebug.IntToString(from=android.view.ViewGroup.FOCUS_AFTER_DESCENDANTS, to="FOCUS_AFTER_DESCENDANTS"), @android.view.ViewDebug.IntToString(from=android.view.ViewGroup.FOCUS_BLOCK_DESCENDANTS, to="FOCUS_BLOCK_DESCENDANTS")}) public int getDescendantFocusability();
     method public android.view.View getFocusedChild();
     method public android.view.animation.LayoutAnimationController getLayoutAnimation();
     method public android.view.animation.Animation.AnimationListener getLayoutAnimationListener();
@@ -50544,15 +50978,15 @@
     method public android.animation.LayoutTransition getLayoutTransition();
     method public int getNestedScrollAxes();
     method public android.view.ViewGroupOverlay getOverlay();
-    method public deprecated int getPersistentDrawingCache();
-    method public boolean getTouchscreenBlocksFocus();
+    method @Deprecated @android.view.ViewDebug.ExportedProperty(category="drawing", mapping={@android.view.ViewDebug.IntToString(from=android.view.ViewGroup.PERSISTENT_NO_CACHE, to="NONE"), @android.view.ViewDebug.IntToString(from=android.view.ViewGroup.PERSISTENT_ANIMATION_CACHE, to="ANIMATION"), @android.view.ViewDebug.IntToString(from=android.view.ViewGroup.PERSISTENT_SCROLLING_CACHE, to="SCROLLING"), @android.view.ViewDebug.IntToString(from=android.view.ViewGroup.PERSISTENT_ALL_CACHES, to="ALL")}) public int getPersistentDrawingCache();
+    method @android.view.ViewDebug.ExportedProperty(category="focus") public boolean getTouchscreenBlocksFocus();
     method public int indexOfChild(android.view.View);
-    method public final deprecated void invalidateChild(android.view.View, android.graphics.Rect);
-    method public deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
-    method public deprecated boolean isAlwaysDrawnWithCacheEnabled();
-    method public deprecated boolean isAnimationCacheEnabled();
-    method protected boolean isChildrenDrawingOrderEnabled();
-    method protected deprecated boolean isChildrenDrawnWithCacheEnabled();
+    method @Deprecated public final void invalidateChild(android.view.View, android.graphics.Rect);
+    method @Deprecated public android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
+    method @Deprecated public boolean isAlwaysDrawnWithCacheEnabled();
+    method @Deprecated public boolean isAnimationCacheEnabled();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") protected boolean isChildrenDrawingOrderEnabled();
+    method @Deprecated protected boolean isChildrenDrawnWithCacheEnabled();
     method public boolean isLayoutSuppressed();
     method public boolean isMotionEventSplittingEnabled();
     method public boolean isTransitionGroup();
@@ -50594,11 +51028,11 @@
     method public void requestTransparentRegion(android.view.View);
     method public void scheduleLayoutAnimation();
     method public void setAddStatesFromChildren(boolean);
-    method public deprecated void setAlwaysDrawnWithCacheEnabled(boolean);
-    method public deprecated void setAnimationCacheEnabled(boolean);
-    method protected deprecated void setChildrenDrawingCacheEnabled(boolean);
+    method @Deprecated public void setAlwaysDrawnWithCacheEnabled(boolean);
+    method @Deprecated public void setAnimationCacheEnabled(boolean);
+    method @Deprecated protected void setChildrenDrawingCacheEnabled(boolean);
     method protected void setChildrenDrawingOrderEnabled(boolean);
-    method protected deprecated void setChildrenDrawnWithCacheEnabled(boolean);
+    method @Deprecated protected void setChildrenDrawnWithCacheEnabled(boolean);
     method public void setClipChildren(boolean);
     method public void setClipToPadding(boolean);
     method public void setDescendantFocusability(int);
@@ -50608,7 +51042,7 @@
     method public void setLayoutTransition(android.animation.LayoutTransition);
     method public void setMotionEventSplittingEnabled(boolean);
     method public void setOnHierarchyChangeListener(android.view.ViewGroup.OnHierarchyChangeListener);
-    method public deprecated void setPersistentDrawingCache(int);
+    method @Deprecated public void setPersistentDrawingCache(int);
     method protected void setStaticTransformationsEnabled(boolean);
     method public void setTouchscreenBlocksFocus(boolean);
     method public void setTransitionGroup(boolean);
@@ -50627,10 +51061,10 @@
     field public static final int FOCUS_BLOCK_DESCENDANTS = 393216; // 0x60000
     field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
     field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
-    field public static final deprecated int PERSISTENT_ALL_CACHES = 3; // 0x3
-    field public static final deprecated int PERSISTENT_ANIMATION_CACHE = 1; // 0x1
-    field public static final deprecated int PERSISTENT_NO_CACHE = 0; // 0x0
-    field public static final deprecated int PERSISTENT_SCROLLING_CACHE = 2; // 0x2
+    field @Deprecated public static final int PERSISTENT_ALL_CACHES = 3; // 0x3
+    field @Deprecated public static final int PERSISTENT_ANIMATION_CACHE = 1; // 0x1
+    field @Deprecated public static final int PERSISTENT_NO_CACHE = 0; // 0x0
+    field @Deprecated public static final int PERSISTENT_SCROLLING_CACHE = 2; // 0x2
   }
 
   public static class ViewGroup.LayoutParams {
@@ -50639,12 +51073,12 @@
     ctor public ViewGroup.LayoutParams(android.view.ViewGroup.LayoutParams);
     method public void resolveLayoutDirection(int);
     method protected void setBaseAttributes(android.content.res.TypedArray, int, int);
-    field public static final deprecated int FILL_PARENT = -1; // 0xffffffff
+    field @Deprecated public static final int FILL_PARENT = -1; // 0xffffffff
     field public static final int MATCH_PARENT = -1; // 0xffffffff
     field public static final int WRAP_CONTENT = -2; // 0xfffffffe
-    field public int height;
+    field @android.view.ViewDebug.ExportedProperty(category="layout", mapping={@android.view.ViewDebug.IntToString(from=android.view.ViewGroup.LayoutParams.MATCH_PARENT, to="MATCH_PARENT"), @android.view.ViewDebug.IntToString(from=android.view.ViewGroup.LayoutParams.WRAP_CONTENT, to="WRAP_CONTENT")}) public int height;
     field public android.view.animation.LayoutAnimationController.AnimationParameters layoutAnimationParameters;
-    field public int width;
+    field @android.view.ViewDebug.ExportedProperty(category="layout", mapping={@android.view.ViewDebug.IntToString(from=android.view.ViewGroup.LayoutParams.MATCH_PARENT, to="MATCH_PARENT"), @android.view.ViewDebug.IntToString(from=android.view.ViewGroup.LayoutParams.WRAP_CONTENT, to="WRAP_CONTENT")}) public int width;
   }
 
   public static class ViewGroup.MarginLayoutParams extends android.view.ViewGroup.LayoutParams {
@@ -50660,26 +51094,26 @@
     method public void setMarginEnd(int);
     method public void setMarginStart(int);
     method public void setMargins(int, int, int, int);
-    field public int bottomMargin;
-    field public int leftMargin;
-    field public int rightMargin;
-    field public int topMargin;
+    field @android.view.ViewDebug.ExportedProperty(category="layout") public int bottomMargin;
+    field @android.view.ViewDebug.ExportedProperty(category="layout") public int leftMargin;
+    field @android.view.ViewDebug.ExportedProperty(category="layout") public int rightMargin;
+    field @android.view.ViewDebug.ExportedProperty(category="layout") public int topMargin;
   }
 
-  public static abstract interface ViewGroup.OnHierarchyChangeListener {
-    method public abstract void onChildViewAdded(android.view.View, android.view.View);
-    method public abstract void onChildViewRemoved(android.view.View, android.view.View);
+  public static interface ViewGroup.OnHierarchyChangeListener {
+    method public void onChildViewAdded(android.view.View, android.view.View);
+    method public void onChildViewRemoved(android.view.View, android.view.View);
   }
 
   public class ViewGroupOverlay extends android.view.ViewOverlay {
-    method public void add(android.view.View);
-    method public void remove(android.view.View);
+    method public void add(@NonNull android.view.View);
+    method public void remove(@NonNull android.view.View);
   }
 
-  public abstract interface ViewManager {
-    method public abstract void addView(android.view.View, android.view.ViewGroup.LayoutParams);
-    method public abstract void removeView(android.view.View);
-    method public abstract void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams);
+  public interface ViewManager {
+    method public void addView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public void removeView(android.view.View);
+    method public void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams);
   }
 
   public abstract class ViewOutlineProvider {
@@ -50691,57 +51125,57 @@
   }
 
   public class ViewOverlay {
-    method public void add(android.graphics.drawable.Drawable);
+    method public void add(@NonNull android.graphics.drawable.Drawable);
     method public void clear();
-    method public void remove(android.graphics.drawable.Drawable);
+    method public void remove(@NonNull android.graphics.drawable.Drawable);
   }
 
-  public abstract interface ViewParent {
-    method public abstract void bringChildToFront(android.view.View);
-    method public abstract boolean canResolveLayoutDirection();
-    method public abstract boolean canResolveTextAlignment();
-    method public abstract boolean canResolveTextDirection();
-    method public abstract void childDrawableStateChanged(android.view.View);
-    method public abstract void childHasTransientStateChanged(android.view.View, boolean);
-    method public abstract void clearChildFocus(android.view.View);
-    method public abstract void createContextMenu(android.view.ContextMenu);
-    method public abstract android.view.View focusSearch(android.view.View, int);
-    method public abstract void focusableViewAvailable(android.view.View);
-    method public abstract boolean getChildVisibleRect(android.view.View, android.graphics.Rect, android.graphics.Point);
-    method public abstract int getLayoutDirection();
-    method public abstract android.view.ViewParent getParent();
-    method public abstract android.view.ViewParent getParentForAccessibility();
-    method public abstract int getTextAlignment();
-    method public abstract int getTextDirection();
-    method public abstract deprecated void invalidateChild(android.view.View, android.graphics.Rect);
-    method public abstract deprecated android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
-    method public abstract boolean isLayoutDirectionResolved();
-    method public abstract boolean isLayoutRequested();
-    method public abstract boolean isTextAlignmentResolved();
-    method public abstract boolean isTextDirectionResolved();
-    method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
-    method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
-    method public default void onDescendantInvalidated(android.view.View, android.view.View);
-    method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
-    method public abstract boolean onNestedPreFling(android.view.View, float, float);
-    method public abstract boolean onNestedPrePerformAccessibilityAction(android.view.View, int, android.os.Bundle);
-    method public abstract void onNestedPreScroll(android.view.View, int, int, int[]);
-    method public abstract void onNestedScroll(android.view.View, int, int, int, int);
-    method public abstract void onNestedScrollAccepted(android.view.View, android.view.View, int);
-    method public abstract boolean onStartNestedScroll(android.view.View, android.view.View, int);
-    method public abstract void onStopNestedScroll(android.view.View);
-    method public abstract void recomputeViewAttributes(android.view.View);
-    method public abstract void requestChildFocus(android.view.View, android.view.View);
-    method public abstract boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean);
-    method public abstract void requestDisallowInterceptTouchEvent(boolean);
-    method public abstract void requestFitSystemWindows();
-    method public abstract void requestLayout();
-    method public abstract boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
-    method public abstract void requestTransparentRegion(android.view.View);
-    method public abstract boolean showContextMenuForChild(android.view.View);
-    method public abstract boolean showContextMenuForChild(android.view.View, float, float);
-    method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
-    method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
+  public interface ViewParent {
+    method public void bringChildToFront(android.view.View);
+    method public boolean canResolveLayoutDirection();
+    method public boolean canResolveTextAlignment();
+    method public boolean canResolveTextDirection();
+    method public void childDrawableStateChanged(android.view.View);
+    method public void childHasTransientStateChanged(android.view.View, boolean);
+    method public void clearChildFocus(android.view.View);
+    method public void createContextMenu(android.view.ContextMenu);
+    method public android.view.View focusSearch(android.view.View, int);
+    method public void focusableViewAvailable(android.view.View);
+    method public boolean getChildVisibleRect(android.view.View, android.graphics.Rect, android.graphics.Point);
+    method public int getLayoutDirection();
+    method public android.view.ViewParent getParent();
+    method public android.view.ViewParent getParentForAccessibility();
+    method public int getTextAlignment();
+    method public int getTextDirection();
+    method @Deprecated public void invalidateChild(android.view.View, android.graphics.Rect);
+    method @Deprecated public android.view.ViewParent invalidateChildInParent(int[], android.graphics.Rect);
+    method public boolean isLayoutDirectionResolved();
+    method public boolean isLayoutRequested();
+    method public boolean isTextAlignmentResolved();
+    method public boolean isTextDirectionResolved();
+    method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
+    method public void notifySubtreeAccessibilityStateChanged(android.view.View, @NonNull android.view.View, int);
+    method public default void onDescendantInvalidated(@NonNull android.view.View, @NonNull android.view.View);
+    method public boolean onNestedFling(android.view.View, float, float, boolean);
+    method public boolean onNestedPreFling(android.view.View, float, float);
+    method public boolean onNestedPrePerformAccessibilityAction(android.view.View, int, android.os.Bundle);
+    method public void onNestedPreScroll(android.view.View, int, int, int[]);
+    method public void onNestedScroll(android.view.View, int, int, int, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, int);
+    method public void onStopNestedScroll(android.view.View);
+    method public void recomputeViewAttributes(android.view.View);
+    method public void requestChildFocus(android.view.View, android.view.View);
+    method public boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean);
+    method public void requestDisallowInterceptTouchEvent(boolean);
+    method public void requestFitSystemWindows();
+    method public void requestLayout();
+    method public boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public void requestTransparentRegion(android.view.View);
+    method public boolean showContextMenuForChild(android.view.View);
+    method public boolean showContextMenuForChild(android.view.View, float, float);
+    method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
+    method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
   }
 
   public class ViewPropertyAnimator {
@@ -50773,9 +51207,9 @@
     method public android.view.ViewPropertyAnimator translationYBy(float);
     method public android.view.ViewPropertyAnimator translationZ(float);
     method public android.view.ViewPropertyAnimator translationZBy(float);
-    method public android.view.ViewPropertyAnimator withEndAction(java.lang.Runnable);
+    method public android.view.ViewPropertyAnimator withEndAction(Runnable);
     method public android.view.ViewPropertyAnimator withLayer();
-    method public android.view.ViewPropertyAnimator withStartAction(java.lang.Runnable);
+    method public android.view.ViewPropertyAnimator withStartAction(Runnable);
     method public android.view.ViewPropertyAnimator x(float);
     method public android.view.ViewPropertyAnimator xBy(float);
     method public android.view.ViewPropertyAnimator y(float);
@@ -50789,31 +51223,31 @@
     method public abstract int addChildCount(int);
     method public abstract void asyncCommit();
     method public abstract android.view.ViewStructure asyncNewChild(int);
-    method public abstract android.view.autofill.AutofillId getAutofillId();
+    method @Nullable public abstract android.view.autofill.AutofillId getAutofillId();
     method public abstract int getChildCount();
     method public abstract android.os.Bundle getExtras();
-    method public abstract java.lang.CharSequence getHint();
-    method public abstract java.lang.CharSequence getText();
+    method public abstract CharSequence getHint();
+    method public abstract CharSequence getText();
     method public abstract int getTextSelectionEnd();
     method public abstract int getTextSelectionStart();
     method public abstract boolean hasExtras();
     method public abstract android.view.ViewStructure newChild(int);
-    method public abstract android.view.ViewStructure.HtmlInfo.Builder newHtmlInfoBuilder(java.lang.String);
+    method public abstract android.view.ViewStructure.HtmlInfo.Builder newHtmlInfoBuilder(@NonNull String);
     method public abstract void setAccessibilityFocused(boolean);
     method public abstract void setActivated(boolean);
     method public abstract void setAlpha(float);
-    method public abstract void setAutofillHints(java.lang.String[]);
-    method public abstract void setAutofillId(android.view.autofill.AutofillId);
-    method public abstract void setAutofillId(android.view.autofill.AutofillId, int);
-    method public abstract void setAutofillOptions(java.lang.CharSequence[]);
+    method public abstract void setAutofillHints(@Nullable String[]);
+    method public abstract void setAutofillId(@NonNull android.view.autofill.AutofillId);
+    method public abstract void setAutofillId(@NonNull android.view.autofill.AutofillId, int);
+    method public abstract void setAutofillOptions(CharSequence[]);
     method public abstract void setAutofillType(int);
     method public abstract void setAutofillValue(android.view.autofill.AutofillValue);
     method public abstract void setCheckable(boolean);
     method public abstract void setChecked(boolean);
     method public abstract void setChildCount(int);
-    method public abstract void setClassName(java.lang.String);
+    method public abstract void setClassName(String);
     method public abstract void setClickable(boolean);
-    method public abstract void setContentDescription(java.lang.CharSequence);
+    method public abstract void setContentDescription(CharSequence);
     method public abstract void setContextClickable(boolean);
     method public abstract void setDataIsSensitive(boolean);
     method public abstract void setDimens(int, int, int, int, int, int);
@@ -50821,9 +51255,9 @@
     method public abstract void setEnabled(boolean);
     method public abstract void setFocusable(boolean);
     method public abstract void setFocused(boolean);
-    method public abstract void setHint(java.lang.CharSequence);
-    method public abstract void setHtmlInfo(android.view.ViewStructure.HtmlInfo);
-    method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String);
+    method public abstract void setHint(CharSequence);
+    method public abstract void setHtmlInfo(@NonNull android.view.ViewStructure.HtmlInfo);
+    method public abstract void setId(int, String, String, String);
     method public void setImportantForAutofill(int);
     method public abstract void setInputType(int);
     method public abstract void setLocaleList(android.os.LocaleList);
@@ -50833,46 +51267,46 @@
     method public void setMinTextEms(int);
     method public abstract void setOpaque(boolean);
     method public abstract void setSelected(boolean);
-    method public abstract void setText(java.lang.CharSequence);
-    method public abstract void setText(java.lang.CharSequence, int, int);
-    method public void setTextIdEntry(java.lang.String);
+    method public abstract void setText(CharSequence);
+    method public abstract void setText(CharSequence, int, int);
+    method public void setTextIdEntry(@NonNull String);
     method public abstract void setTextLines(int[], int[]);
     method public abstract void setTextStyle(float, int, int, int);
     method public abstract void setTransformation(android.graphics.Matrix);
     method public abstract void setVisibility(int);
-    method public abstract void setWebDomain(java.lang.String);
+    method public abstract void setWebDomain(@Nullable String);
   }
 
-  public static abstract class ViewStructure.HtmlInfo {
+  public abstract static class ViewStructure.HtmlInfo {
     ctor public ViewStructure.HtmlInfo();
-    method public abstract java.util.List<android.util.Pair<java.lang.String, java.lang.String>> getAttributes();
-    method public abstract java.lang.String getTag();
+    method @Nullable public abstract java.util.List<android.util.Pair<java.lang.String,java.lang.String>> getAttributes();
+    method @NonNull public abstract String getTag();
   }
 
-  public static abstract class ViewStructure.HtmlInfo.Builder {
+  public abstract static class ViewStructure.HtmlInfo.Builder {
     ctor public ViewStructure.HtmlInfo.Builder();
-    method public abstract android.view.ViewStructure.HtmlInfo.Builder addAttribute(java.lang.String, java.lang.String);
+    method public abstract android.view.ViewStructure.HtmlInfo.Builder addAttribute(@NonNull String, @NonNull String);
     method public abstract android.view.ViewStructure.HtmlInfo build();
   }
 
-  public final class ViewStub extends android.view.View {
+  @android.widget.RemoteViews.RemoteView public final class ViewStub extends android.view.View {
     ctor public ViewStub(android.content.Context);
-    ctor public ViewStub(android.content.Context, int);
+    ctor public ViewStub(android.content.Context, @LayoutRes int);
     ctor public ViewStub(android.content.Context, android.util.AttributeSet);
     ctor public ViewStub(android.content.Context, android.util.AttributeSet, int);
     ctor public ViewStub(android.content.Context, android.util.AttributeSet, int, int);
-    method public int getInflatedId();
+    method @IdRes public int getInflatedId();
     method public android.view.LayoutInflater getLayoutInflater();
-    method public int getLayoutResource();
+    method @LayoutRes public int getLayoutResource();
     method public android.view.View inflate();
-    method public void setInflatedId(int);
+    method public void setInflatedId(@IdRes int);
     method public void setLayoutInflater(android.view.LayoutInflater);
-    method public void setLayoutResource(int);
+    method public void setLayoutResource(@LayoutRes int);
     method public void setOnInflateListener(android.view.ViewStub.OnInflateListener);
   }
 
-  public static abstract interface ViewStub.OnInflateListener {
-    method public abstract void onInflate(android.view.ViewStub, android.view.View);
+  public static interface ViewStub.OnInflateListener {
+    method public void onInflate(android.view.ViewStub, android.view.View);
   }
 
   public final class ViewTreeObserver {
@@ -50888,8 +51322,8 @@
     method public void dispatchOnGlobalLayout();
     method public boolean dispatchOnPreDraw();
     method public boolean isAlive();
-    method public void registerFrameCommitCallback(java.lang.Runnable);
-    method public deprecated void removeGlobalOnLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener);
+    method public void registerFrameCommitCallback(@NonNull Runnable);
+    method @Deprecated public void removeGlobalOnLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener);
     method public void removeOnDrawListener(android.view.ViewTreeObserver.OnDrawListener);
     method public void removeOnGlobalFocusChangeListener(android.view.ViewTreeObserver.OnGlobalFocusChangeListener);
     method public void removeOnGlobalLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener);
@@ -50898,51 +51332,51 @@
     method public void removeOnTouchModeChangeListener(android.view.ViewTreeObserver.OnTouchModeChangeListener);
     method public void removeOnWindowAttachListener(android.view.ViewTreeObserver.OnWindowAttachListener);
     method public void removeOnWindowFocusChangeListener(android.view.ViewTreeObserver.OnWindowFocusChangeListener);
-    method public boolean unregisterFrameCommitCallback(java.lang.Runnable);
+    method public boolean unregisterFrameCommitCallback(@NonNull Runnable);
   }
 
-  public static abstract interface ViewTreeObserver.OnDrawListener {
-    method public abstract void onDraw();
+  public static interface ViewTreeObserver.OnDrawListener {
+    method public void onDraw();
   }
 
-  public static abstract interface ViewTreeObserver.OnGlobalFocusChangeListener {
-    method public abstract void onGlobalFocusChanged(android.view.View, android.view.View);
+  public static interface ViewTreeObserver.OnGlobalFocusChangeListener {
+    method public void onGlobalFocusChanged(android.view.View, android.view.View);
   }
 
-  public static abstract interface ViewTreeObserver.OnGlobalLayoutListener {
-    method public abstract void onGlobalLayout();
+  public static interface ViewTreeObserver.OnGlobalLayoutListener {
+    method public void onGlobalLayout();
   }
 
-  public static abstract interface ViewTreeObserver.OnPreDrawListener {
-    method public abstract boolean onPreDraw();
+  public static interface ViewTreeObserver.OnPreDrawListener {
+    method public boolean onPreDraw();
   }
 
-  public static abstract interface ViewTreeObserver.OnScrollChangedListener {
-    method public abstract void onScrollChanged();
+  public static interface ViewTreeObserver.OnScrollChangedListener {
+    method public void onScrollChanged();
   }
 
-  public static abstract interface ViewTreeObserver.OnTouchModeChangeListener {
-    method public abstract void onTouchModeChanged(boolean);
+  public static interface ViewTreeObserver.OnTouchModeChangeListener {
+    method public void onTouchModeChanged(boolean);
   }
 
-  public static abstract interface ViewTreeObserver.OnWindowAttachListener {
-    method public abstract void onWindowAttached();
-    method public abstract void onWindowDetached();
+  public static interface ViewTreeObserver.OnWindowAttachListener {
+    method public void onWindowAttached();
+    method public void onWindowDetached();
   }
 
-  public static abstract interface ViewTreeObserver.OnWindowFocusChangeListener {
-    method public abstract void onWindowFocusChanged(boolean);
+  public static interface ViewTreeObserver.OnWindowFocusChangeListener {
+    method public void onWindowFocusChanged(boolean);
   }
 
   public abstract class Window {
     ctor public Window(android.content.Context);
     method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public void addFlags(int);
-    method public final void addOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener, android.os.Handler);
+    method public final void addOnFrameMetricsAvailableListener(@NonNull android.view.Window.OnFrameMetricsAvailableListener, android.os.Handler);
     method public void clearFlags(int);
     method public abstract void closeAllPanels();
     method public abstract void closePanel(int);
-    method public <T extends android.view.View> T findViewById(int);
+    method public <T extends android.view.View> T findViewById(@IdRes int);
     method public boolean getAllowEnterTransitionOverlap();
     method public boolean getAllowReturnTransitionOverlap();
     method public final android.view.WindowManager.LayoutParams getAttributes();
@@ -50951,18 +51385,18 @@
     method public final android.view.Window getContainer();
     method public android.transition.Scene getContentScene();
     method public final android.content.Context getContext();
-    method public abstract android.view.View getCurrentFocus();
-    method public abstract android.view.View getDecorView();
+    method @Nullable public abstract android.view.View getCurrentFocus();
+    method @NonNull public abstract android.view.View getDecorView();
     method public static int getDefaultFeatures(android.content.Context);
     method public android.transition.Transition getEnterTransition();
     method public android.transition.Transition getExitTransition();
     method protected final int getFeatures();
     method protected final int getForcedWindowFlags();
-    method public abstract android.view.LayoutInflater getLayoutInflater();
+    method @NonNull public abstract android.view.LayoutInflater getLayoutInflater();
     method protected final int getLocalFeatures();
     method public android.media.session.MediaController getMediaController();
-    method public abstract int getNavigationBarColor();
-    method public int getNavigationBarDividerColor();
+    method @ColorInt public abstract int getNavigationBarColor();
+    method @ColorInt public int getNavigationBarDividerColor();
     method public android.transition.Transition getReenterTransition();
     method public android.transition.Transition getReturnTransition();
     method public android.transition.Transition getSharedElementEnterTransition();
@@ -50970,7 +51404,7 @@
     method public android.transition.Transition getSharedElementReenterTransition();
     method public android.transition.Transition getSharedElementReturnTransition();
     method public boolean getSharedElementsUseOverlay();
-    method public abstract int getStatusBarColor();
+    method @ColorInt public abstract int getStatusBarColor();
     method public long getTransitionBackgroundFadeDuration();
     method public android.transition.TransitionManager getTransitionManager();
     method public abstract int getVolumeControlStream();
@@ -50995,21 +51429,21 @@
     method public abstract boolean performPanelShortcut(int, int, android.view.KeyEvent, int);
     method public final void removeOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener);
     method public boolean requestFeature(int);
-    method public final <T extends android.view.View> T requireViewById(int);
+    method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
     method public abstract void restoreHierarchyState(android.os.Bundle);
     method public abstract android.os.Bundle saveHierarchyState();
     method public void setAllowEnterTransitionOverlap(boolean);
     method public void setAllowReturnTransitionOverlap(boolean);
     method public void setAttributes(android.view.WindowManager.LayoutParams);
     method public abstract void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setBackgroundDrawableResource(int);
+    method public void setBackgroundDrawableResource(@DrawableRes int);
     method public void setCallback(android.view.Window.Callback);
     method public abstract void setChildDrawable(int, android.graphics.drawable.Drawable);
     method public abstract void setChildInt(int, int);
     method public void setClipToOutline(boolean);
     method public void setColorMode(int);
     method public void setContainer(android.view.Window);
-    method public abstract void setContentView(int);
+    method public abstract void setContentView(@LayoutRes int);
     method public abstract void setContentView(android.view.View);
     method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public abstract void setDecorCaptionShade(int);
@@ -51020,19 +51454,19 @@
     method public void setExitTransition(android.transition.Transition);
     method public abstract void setFeatureDrawable(int, android.graphics.drawable.Drawable);
     method public abstract void setFeatureDrawableAlpha(int, int);
-    method public abstract void setFeatureDrawableResource(int, int);
+    method public abstract void setFeatureDrawableResource(int, @DrawableRes int);
     method public abstract void setFeatureDrawableUri(int, android.net.Uri);
     method public abstract void setFeatureInt(int, int);
     method public void setFlags(int, int);
     method public void setFormat(int);
     method public void setGravity(int);
-    method public void setIcon(int);
+    method public void setIcon(@DrawableRes int);
     method public void setLayout(int, int);
     method public void setLocalFocus(boolean, boolean);
-    method public void setLogo(int);
+    method public void setLogo(@DrawableRes int);
     method public void setMediaController(android.media.session.MediaController);
-    method public abstract void setNavigationBarColor(int);
-    method public void setNavigationBarDividerColor(int);
+    method public abstract void setNavigationBarColor(@ColorInt int);
+    method public void setNavigationBarDividerColor(@ColorInt int);
     method public void setReenterTransition(android.transition.Transition);
     method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
     method public final void setRestrictedCaptionAreaListener(android.view.Window.OnRestrictedCaptionAreaChangedListener);
@@ -51043,19 +51477,19 @@
     method public void setSharedElementReturnTransition(android.transition.Transition);
     method public void setSharedElementsUseOverlay(boolean);
     method public void setSoftInputMode(int);
-    method public abstract void setStatusBarColor(int);
+    method public abstract void setStatusBarColor(@ColorInt int);
     method public void setSustainedPerformanceMode(boolean);
-    method public abstract void setTitle(java.lang.CharSequence);
-    method public abstract deprecated void setTitleColor(int);
+    method public abstract void setTitle(CharSequence);
+    method @Deprecated public abstract void setTitleColor(@ColorInt int);
     method public void setTransitionBackgroundFadeDuration(long);
     method public void setTransitionManager(android.transition.TransitionManager);
     method public void setType(int);
     method public void setUiOptions(int);
     method public void setUiOptions(int, int);
     method public abstract void setVolumeControlStream(int);
-    method public void setWindowAnimations(int);
-    method public void setWindowManager(android.view.WindowManager, android.os.IBinder, java.lang.String);
-    method public void setWindowManager(android.view.WindowManager, android.os.IBinder, java.lang.String, boolean);
+    method public void setWindowAnimations(@StyleRes int);
+    method public void setWindowManager(android.view.WindowManager, android.os.IBinder, String);
+    method public void setWindowManager(android.view.WindowManager, android.os.IBinder, String, boolean);
     method public abstract boolean superDispatchGenericMotionEvent(android.view.MotionEvent);
     method public abstract boolean superDispatchKeyEvent(android.view.KeyEvent);
     method public abstract boolean superDispatchKeyShortcutEvent(android.view.KeyEvent);
@@ -51068,7 +51502,7 @@
     field public static final int DECOR_CAPTION_SHADE_AUTO = 0; // 0x0
     field public static final int DECOR_CAPTION_SHADE_DARK = 2; // 0x2
     field public static final int DECOR_CAPTION_SHADE_LIGHT = 1; // 0x1
-    field protected static final deprecated int DEFAULT_FEATURES = 65; // 0x41
+    field @Deprecated protected static final int DEFAULT_FEATURES = 65; // 0x41
     field public static final int FEATURE_ACTION_BAR = 8; // 0x8
     field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
     field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
@@ -51076,60 +51510,60 @@
     field public static final int FEATURE_CONTENT_TRANSITIONS = 12; // 0xc
     field public static final int FEATURE_CONTEXT_MENU = 6; // 0x6
     field public static final int FEATURE_CUSTOM_TITLE = 7; // 0x7
-    field public static final deprecated int FEATURE_INDETERMINATE_PROGRESS = 5; // 0x5
+    field @Deprecated public static final int FEATURE_INDETERMINATE_PROGRESS = 5; // 0x5
     field public static final int FEATURE_LEFT_ICON = 3; // 0x3
     field public static final int FEATURE_NO_TITLE = 1; // 0x1
     field public static final int FEATURE_OPTIONS_PANEL = 0; // 0x0
-    field public static final deprecated int FEATURE_PROGRESS = 2; // 0x2
+    field @Deprecated public static final int FEATURE_PROGRESS = 2; // 0x2
     field public static final int FEATURE_RIGHT_ICON = 4; // 0x4
     field public static final int FEATURE_SWIPE_TO_DISMISS = 11; // 0xb
     field public static final int ID_ANDROID_CONTENT = 16908290; // 0x1020002
-    field public static final java.lang.String NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME = "android:navigation:background";
-    field public static final deprecated int PROGRESS_END = 10000; // 0x2710
-    field public static final deprecated int PROGRESS_INDETERMINATE_OFF = -4; // 0xfffffffc
-    field public static final deprecated int PROGRESS_INDETERMINATE_ON = -3; // 0xfffffffd
-    field public static final deprecated int PROGRESS_SECONDARY_END = 30000; // 0x7530
-    field public static final deprecated int PROGRESS_SECONDARY_START = 20000; // 0x4e20
-    field public static final deprecated int PROGRESS_START = 0; // 0x0
-    field public static final deprecated int PROGRESS_VISIBILITY_OFF = -2; // 0xfffffffe
-    field public static final deprecated int PROGRESS_VISIBILITY_ON = -1; // 0xffffffff
-    field public static final java.lang.String STATUS_BAR_BACKGROUND_TRANSITION_NAME = "android:status:background";
+    field public static final String NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME = "android:navigation:background";
+    field @Deprecated public static final int PROGRESS_END = 10000; // 0x2710
+    field @Deprecated public static final int PROGRESS_INDETERMINATE_OFF = -4; // 0xfffffffc
+    field @Deprecated public static final int PROGRESS_INDETERMINATE_ON = -3; // 0xfffffffd
+    field @Deprecated public static final int PROGRESS_SECONDARY_END = 30000; // 0x7530
+    field @Deprecated public static final int PROGRESS_SECONDARY_START = 20000; // 0x4e20
+    field @Deprecated public static final int PROGRESS_START = 0; // 0x0
+    field @Deprecated public static final int PROGRESS_VISIBILITY_OFF = -2; // 0xfffffffe
+    field @Deprecated public static final int PROGRESS_VISIBILITY_ON = -1; // 0xffffffff
+    field public static final String STATUS_BAR_BACKGROUND_TRANSITION_NAME = "android:status:background";
   }
 
-  public static abstract interface Window.Callback {
-    method public abstract boolean dispatchGenericMotionEvent(android.view.MotionEvent);
-    method public abstract boolean dispatchKeyEvent(android.view.KeyEvent);
-    method public abstract boolean dispatchKeyShortcutEvent(android.view.KeyEvent);
-    method public abstract boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public abstract boolean dispatchTouchEvent(android.view.MotionEvent);
-    method public abstract boolean dispatchTrackballEvent(android.view.MotionEvent);
-    method public abstract void onActionModeFinished(android.view.ActionMode);
-    method public abstract void onActionModeStarted(android.view.ActionMode);
-    method public abstract void onAttachedToWindow();
-    method public abstract void onContentChanged();
-    method public abstract boolean onCreatePanelMenu(int, android.view.Menu);
-    method public abstract android.view.View onCreatePanelView(int);
-    method public abstract void onDetachedFromWindow();
-    method public abstract boolean onMenuItemSelected(int, android.view.MenuItem);
-    method public abstract boolean onMenuOpened(int, android.view.Menu);
-    method public abstract void onPanelClosed(int, android.view.Menu);
+  public static interface Window.Callback {
+    method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
+    method public boolean dispatchKeyEvent(android.view.KeyEvent);
+    method public boolean dispatchKeyShortcutEvent(android.view.KeyEvent);
+    method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public boolean dispatchTouchEvent(android.view.MotionEvent);
+    method public boolean dispatchTrackballEvent(android.view.MotionEvent);
+    method public void onActionModeFinished(android.view.ActionMode);
+    method public void onActionModeStarted(android.view.ActionMode);
+    method public void onAttachedToWindow();
+    method public void onContentChanged();
+    method public boolean onCreatePanelMenu(int, @NonNull android.view.Menu);
+    method @Nullable public android.view.View onCreatePanelView(int);
+    method public void onDetachedFromWindow();
+    method public boolean onMenuItemSelected(int, @NonNull android.view.MenuItem);
+    method public boolean onMenuOpened(int, @NonNull android.view.Menu);
+    method public void onPanelClosed(int, @NonNull android.view.Menu);
     method public default void onPointerCaptureChanged(boolean);
-    method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
-    method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu, int);
-    method public abstract boolean onSearchRequested();
-    method public abstract boolean onSearchRequested(android.view.SearchEvent);
-    method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
-    method public abstract void onWindowFocusChanged(boolean);
-    method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
-    method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
+    method public boolean onPreparePanel(int, @Nullable android.view.View, @NonNull android.view.Menu);
+    method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, @Nullable android.view.Menu, int);
+    method public boolean onSearchRequested();
+    method public boolean onSearchRequested(android.view.SearchEvent);
+    method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
+    method public void onWindowFocusChanged(boolean);
+    method @Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
+    method @Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
   }
 
-  public static abstract interface Window.OnFrameMetricsAvailableListener {
-    method public abstract void onFrameMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
+  public static interface Window.OnFrameMetricsAvailableListener {
+    method public void onFrameMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
   }
 
-  public static abstract interface Window.OnRestrictedCaptionAreaChangedListener {
-    method public abstract void onRestrictedCaptionAreaChanged(android.graphics.Rect);
+  public static interface Window.OnRestrictedCaptionAreaChangedListener {
+    method public void onRestrictedCaptionAreaChanged(android.graphics.Rect);
   }
 
   public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable {
@@ -51155,7 +51589,7 @@
     field public static final android.os.Parcelable.Creator<android.view.WindowId> CREATOR;
   }
 
-  public static abstract class WindowId.FocusObserver {
+  public abstract static class WindowId.FocusObserver {
     ctor public WindowId.FocusObserver();
     method public abstract void onFocusGained(android.view.WindowId);
     method public abstract void onFocusLost(android.view.WindowId);
@@ -51163,52 +51597,52 @@
 
   public final class WindowInsets {
     ctor public WindowInsets(android.view.WindowInsets);
-    method public android.view.WindowInsets consumeDisplayCutout();
-    method public android.view.WindowInsets consumeStableInsets();
-    method public android.view.WindowInsets consumeSystemWindowInsets();
-    method public android.view.DisplayCutout getDisplayCutout();
+    method @NonNull public android.view.WindowInsets consumeDisplayCutout();
+    method @NonNull public android.view.WindowInsets consumeStableInsets();
+    method @NonNull public android.view.WindowInsets consumeSystemWindowInsets();
+    method @Nullable public android.view.DisplayCutout getDisplayCutout();
     method public int getStableInsetBottom();
     method public int getStableInsetLeft();
     method public int getStableInsetRight();
     method public int getStableInsetTop();
-    method public android.graphics.Insets getStableInsets();
+    method @NonNull public android.graphics.Insets getStableInsets();
     method public int getSystemWindowInsetBottom();
     method public int getSystemWindowInsetLeft();
     method public int getSystemWindowInsetRight();
     method public int getSystemWindowInsetTop();
-    method public android.graphics.Insets getSystemWindowInsets();
+    method @NonNull public android.graphics.Insets getSystemWindowInsets();
     method public boolean hasInsets();
     method public boolean hasStableInsets();
     method public boolean hasSystemWindowInsets();
-    method public android.view.WindowInsets inset(int, int, int, int);
+    method @NonNull public android.view.WindowInsets inset(int, int, int, int);
     method public boolean isConsumed();
     method public boolean isRound();
-    method public deprecated android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
-    method public deprecated android.view.WindowInsets replaceSystemWindowInsets(android.graphics.Rect);
+    method @Deprecated @NonNull public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
+    method @Deprecated @NonNull public android.view.WindowInsets replaceSystemWindowInsets(android.graphics.Rect);
   }
 
   public static class WindowInsets.Builder {
     ctor public WindowInsets.Builder();
     ctor public WindowInsets.Builder(android.view.WindowInsets);
-    method public android.view.WindowInsets build();
-    method public android.view.WindowInsets.Builder setDisplayCutout(android.view.DisplayCutout);
-    method public android.view.WindowInsets.Builder setStableInsets(android.graphics.Insets);
-    method public android.view.WindowInsets.Builder setSystemWindowInsets(android.graphics.Insets);
+    method @NonNull public android.view.WindowInsets build();
+    method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
+    method @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets);
+    method @NonNull public android.view.WindowInsets.Builder setSystemWindowInsets(@NonNull android.graphics.Insets);
   }
 
-  public abstract interface WindowManager implements android.view.ViewManager {
-    method public abstract android.view.Display getDefaultDisplay();
-    method public abstract void removeViewImmediate(android.view.View);
+  public interface WindowManager extends android.view.ViewManager {
+    method public android.view.Display getDefaultDisplay();
+    method public void removeViewImmediate(android.view.View);
   }
 
   public static class WindowManager.BadTokenException extends java.lang.RuntimeException {
     ctor public WindowManager.BadTokenException();
-    ctor public WindowManager.BadTokenException(java.lang.String);
+    ctor public WindowManager.BadTokenException(String);
   }
 
   public static class WindowManager.InvalidDisplayException extends java.lang.RuntimeException {
     ctor public WindowManager.InvalidDisplayException();
-    ctor public WindowManager.InvalidDisplayException(java.lang.String);
+    ctor public WindowManager.InvalidDisplayException(String);
   }
 
   public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
@@ -51220,13 +51654,13 @@
     ctor public WindowManager.LayoutParams(int, int, int, int, int, int, int);
     ctor public WindowManager.LayoutParams(android.os.Parcel);
     method public final int copyFrom(android.view.WindowManager.LayoutParams);
-    method public java.lang.String debug(java.lang.String);
+    method public String debug(String);
     method public int describeContents();
     method public int getColorMode();
-    method public final java.lang.CharSequence getTitle();
+    method public final CharSequence getTitle();
     method public static boolean mayUseInputMethod(int);
     method public void setColorMode(int);
-    method public final void setTitle(java.lang.CharSequence);
+    method public final void setTitle(CharSequence);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ALPHA_CHANGED = 128; // 0x80
     field public static final int ANIMATION_CHANGED = 16; // 0x10
@@ -51241,10 +51675,10 @@
     field public static final int FLAGS_CHANGED = 4; // 0x4
     field public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 1; // 0x1
     field public static final int FLAG_ALT_FOCUSABLE_IM = 131072; // 0x20000
-    field public static final deprecated int FLAG_BLUR_BEHIND = 4; // 0x4
+    field @Deprecated public static final int FLAG_BLUR_BEHIND = 4; // 0x4
     field public static final int FLAG_DIM_BEHIND = 2; // 0x2
-    field public static final deprecated int FLAG_DISMISS_KEYGUARD = 4194304; // 0x400000
-    field public static final deprecated int FLAG_DITHER = 4096; // 0x1000
+    field @Deprecated public static final int FLAG_DISMISS_KEYGUARD = 4194304; // 0x400000
+    field @Deprecated public static final int FLAG_DITHER = 4096; // 0x1000
     field public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = -2147483648; // 0x80000000
     field public static final int FLAG_FORCE_NOT_FULLSCREEN = 2048; // 0x800
     field public static final int FLAG_FULLSCREEN = 1024; // 0x400
@@ -51263,12 +51697,12 @@
     field public static final int FLAG_SCALED = 16384; // 0x4000
     field public static final int FLAG_SECURE = 8192; // 0x2000
     field public static final int FLAG_SHOW_WALLPAPER = 1048576; // 0x100000
-    field public static final deprecated int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
+    field @Deprecated public static final int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
     field public static final int FLAG_SPLIT_TOUCH = 8388608; // 0x800000
-    field public static final deprecated int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
+    field @Deprecated public static final int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
     field public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000
     field public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000
-    field public static final deprecated int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
+    field @Deprecated public static final int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
     field public static final int FLAG_WATCH_OUTSIDE_TOUCH = 262144; // 0x40000
     field public static final int FORMAT_CHANGED = 8; // 0x8
     field public static final int LAST_APPLICATION_WINDOW = 99; // 0x63
@@ -51279,10 +51713,10 @@
     field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER = 2; // 0x2
     field public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 1; // 0x1
     field public static final int MEMORY_TYPE_CHANGED = 256; // 0x100
-    field public static final deprecated int MEMORY_TYPE_GPU = 2; // 0x2
-    field public static final deprecated int MEMORY_TYPE_HARDWARE = 1; // 0x1
-    field public static final deprecated int MEMORY_TYPE_NORMAL = 0; // 0x0
-    field public static final deprecated int MEMORY_TYPE_PUSH_BUFFERS = 3; // 0x3
+    field @Deprecated public static final int MEMORY_TYPE_GPU = 2; // 0x2
+    field @Deprecated public static final int MEMORY_TYPE_HARDWARE = 1; // 0x1
+    field @Deprecated public static final int MEMORY_TYPE_NORMAL = 0; // 0x0
+    field @Deprecated public static final int MEMORY_TYPE_PUSH_BUFFERS = 3; // 0x3
     field public static final int ROTATION_ANIMATION_CHANGED = 4096; // 0x1000
     field public static final int ROTATION_ANIMATION_CROSSFADE = 1; // 0x1
     field public static final int ROTATION_ANIMATION_JUMPCUT = 2; // 0x2
@@ -51319,43 +51753,43 @@
     field public static final int TYPE_INPUT_METHOD = 2011; // 0x7db
     field public static final int TYPE_INPUT_METHOD_DIALOG = 2012; // 0x7dc
     field public static final int TYPE_KEYGUARD_DIALOG = 2009; // 0x7d9
-    field public static final deprecated int TYPE_PHONE = 2002; // 0x7d2
-    field public static final deprecated int TYPE_PRIORITY_PHONE = 2007; // 0x7d7
+    field @Deprecated public static final int TYPE_PHONE = 2002; // 0x7d2
+    field @Deprecated public static final int TYPE_PRIORITY_PHONE = 2007; // 0x7d7
     field public static final int TYPE_PRIVATE_PRESENTATION = 2030; // 0x7ee
     field public static final int TYPE_SEARCH_BAR = 2001; // 0x7d1
     field public static final int TYPE_STATUS_BAR = 2000; // 0x7d0
     field public static final int TYPE_STATUS_BAR_PANEL = 2014; // 0x7de
-    field public static final deprecated int TYPE_SYSTEM_ALERT = 2003; // 0x7d3
+    field @Deprecated public static final int TYPE_SYSTEM_ALERT = 2003; // 0x7d3
     field public static final int TYPE_SYSTEM_DIALOG = 2008; // 0x7d8
-    field public static final deprecated int TYPE_SYSTEM_ERROR = 2010; // 0x7da
-    field public static final deprecated int TYPE_SYSTEM_OVERLAY = 2006; // 0x7d6
-    field public static final deprecated int TYPE_TOAST = 2005; // 0x7d5
+    field @Deprecated public static final int TYPE_SYSTEM_ERROR = 2010; // 0x7da
+    field @Deprecated public static final int TYPE_SYSTEM_OVERLAY = 2006; // 0x7d6
+    field @Deprecated public static final int TYPE_TOAST = 2005; // 0x7d5
     field public static final int TYPE_WALLPAPER = 2013; // 0x7dd
     field public float alpha;
     field public float buttonBrightness;
     field public float dimAmount;
-    field public int flags;
+    field @android.view.ViewDebug.ExportedProperty(flagMapping={@android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON, equals=android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON, name="ALLOW_LOCK_WHILE_SCREEN_ON"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND, equals=android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND, name="DIM_BEHIND"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND, equals=android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND, name="BLUR_BEHIND"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, equals=android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, name="NOT_FOCUSABLE"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, equals=android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, name="NOT_TOUCHABLE"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, equals=android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, name="NOT_TOUCH_MODAL"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING, equals=android.view.WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING, name="TOUCHABLE_WHEN_WAKING"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, equals=android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, name="KEEP_SCREEN_ON"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, equals=android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, name="LAYOUT_IN_SCREEN"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, equals=android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, name="LAYOUT_NO_LIMITS"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN, equals=android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN, name="FULLSCREEN"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, equals=android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, name="FORCE_NOT_FULLSCREEN"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_DITHER, equals=android.view.WindowManager.LayoutParams.FLAG_DITHER, name="DITHER"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_SECURE, equals=android.view.WindowManager.LayoutParams.FLAG_SECURE, name="SECURE"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_SCALED, equals=android.view.WindowManager.LayoutParams.FLAG_SCALED, name="SCALED"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES, equals=android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES, name="IGNORE_CHEEK_PRESSES"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR, equals=android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR, name="LAYOUT_INSET_DECOR"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, equals=android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, name="ALT_FOCUSABLE_IM"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, equals=android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, name="WATCH_OUTSIDE_TOUCH"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED, equals=android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED, name="SHOW_WHEN_LOCKED"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER, equals=android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER, name="SHOW_WALLPAPER"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON, equals=android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON, name="TURN_SCREEN_ON"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD, equals=android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD, name="DISMISS_KEYGUARD"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, equals=android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, name="SPLIT_TOUCH"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, equals=android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, name="HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN, equals=android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN, name="LOCAL_FOCUS_MODE"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, equals=android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, name="TRANSLUCENT_STATUS"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, equals=android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, name="TRANSLUCENT_NAVIGATION"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE, equals=android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE, name="LOCAL_FOCUS_MODE"), @android.view.ViewDebug.FlagToString(mask=0x20000000, equals=0x20000000, name="FLAG_SLIPPERY"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR, equals=android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR, name="FLAG_LAYOUT_ATTACHED_IN_DECOR"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, equals=android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, name="DRAWS_SYSTEM_BAR_BACKGROUNDS")}, formatToHexString=true) public int flags;
     field public int format;
     field public int gravity;
     field public float horizontalMargin;
-    field public float horizontalWeight;
+    field @android.view.ViewDebug.ExportedProperty public float horizontalWeight;
     field public int layoutInDisplayCutoutMode;
-    field public deprecated int memoryType;
-    field public java.lang.String packageName;
+    field @Deprecated public int memoryType;
+    field public String packageName;
     field public int preferredDisplayModeId;
-    field public deprecated float preferredRefreshRate;
+    field @Deprecated public float preferredRefreshRate;
     field public int rotationAnimation;
     field public float screenBrightness;
     field public int screenOrientation;
     field public int softInputMode;
     field public int systemUiVisibility;
     field public android.os.IBinder token;
-    field public int type;
+    field @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION, to="BASE_APPLICATION"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION, to="APPLICATION"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING, to="APPLICATION_STARTING"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION, to="DRAWN_APPLICATION"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, to="APPLICATION_PANEL"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA, to="APPLICATION_MEDIA"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL, to="APPLICATION_SUB_PANEL"), @android.view.ViewDebug.IntToString(from=0x3ed, to="APPLICATION_ABOVE_SUB_PANEL"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG, to="APPLICATION_ATTACHED_DIALOG"), @android.view.ViewDebug.IntToString(from=0x3ec, to="APPLICATION_MEDIA_OVERLAY"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR, to="STATUS_BAR"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR, to="SEARCH_BAR"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_PHONE, to="PHONE"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, to="SYSTEM_ALERT"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_TOAST, to="TOAST"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, to="SYSTEM_OVERLAY"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE, to="PRIORITY_PHONE"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG, to="SYSTEM_DIALOG"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, to="KEYGUARD_DIALOG"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, to="SYSTEM_ERROR"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD, to="INPUT_METHOD"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG, to="INPUT_METHOD_DIALOG"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_WALLPAPER, to="WALLPAPER"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, to="STATUS_BAR_PANEL"), @android.view.ViewDebug.IntToString(from=0x7df, to="SECURE_SYSTEM_OVERLAY"), @android.view.ViewDebug.IntToString(from=0x7e0, to="DRAG"), @android.view.ViewDebug.IntToString(from=0x7e1, to="STATUS_BAR_SUB_PANEL"), @android.view.ViewDebug.IntToString(from=0x7e2, to="POINTER"), @android.view.ViewDebug.IntToString(from=0x7e3, to="NAVIGATION_BAR"), @android.view.ViewDebug.IntToString(from=0x7e4, to="VOLUME_OVERLAY"), @android.view.ViewDebug.IntToString(from=0x7e5, to="BOOT_PROGRESS"), @android.view.ViewDebug.IntToString(from=0x7e6, to="INPUT_CONSUMER"), @android.view.ViewDebug.IntToString(from=0x7e7, to="DREAM"), @android.view.ViewDebug.IntToString(from=0x7e8, to="NAVIGATION_BAR_PANEL"), @android.view.ViewDebug.IntToString(from=0x7ea, to="DISPLAY_OVERLAY"), @android.view.ViewDebug.IntToString(from=0x7eb, to="MAGNIFICATION_OVERLAY"), @android.view.ViewDebug.IntToString(from=0x7f5, to="PRESENTATION"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION, to="PRIVATE_PRESENTATION"), @android.view.ViewDebug.IntToString(from=0x7ef, to="VOICE_INTERACTION"), @android.view.ViewDebug.IntToString(from=0x7f1, to="VOICE_INTERACTION_STARTING"), @android.view.ViewDebug.IntToString(from=0x7f2, to="DOCK_DIVIDER"), @android.view.ViewDebug.IntToString(from=0x7f3, to="QS_DIALOG"), @android.view.ViewDebug.IntToString(from=0x7f4, to="SCREENSHOT"), @android.view.ViewDebug.IntToString(from=android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, to="APPLICATION_OVERLAY")}) public int type;
     field public float verticalMargin;
-    field public float verticalWeight;
+    field @android.view.ViewDebug.ExportedProperty public float verticalWeight;
     field public int windowAnimations;
-    field public int x;
-    field public int y;
+    field @android.view.ViewDebug.ExportedProperty public int x;
+    field @android.view.ViewDebug.ExportedProperty public int y;
   }
 
 }
@@ -51365,13 +51799,13 @@
   public final class AccessibilityEvent extends android.view.accessibility.AccessibilityRecord implements android.os.Parcelable {
     method public void appendRecord(android.view.accessibility.AccessibilityRecord);
     method public int describeContents();
-    method public static java.lang.String eventTypeToString(int);
+    method public static String eventTypeToString(int);
     method public int getAction();
     method public int getContentChangeTypes();
     method public long getEventTime();
     method public int getEventType();
     method public int getMovementGranularity();
-    method public java.lang.CharSequence getPackageName();
+    method public CharSequence getPackageName();
     method public android.view.accessibility.AccessibilityRecord getRecord(int);
     method public int getRecordCount();
     method public int getWindowChanges();
@@ -51384,7 +51818,7 @@
     method public void setEventTime(long);
     method public void setEventType(int);
     method public void setMovementGranularity(int);
-    method public void setPackageName(java.lang.CharSequence);
+    method public void setPackageName(CharSequence);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
     field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10
@@ -51395,7 +51829,7 @@
     field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
     field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityEvent> CREATOR;
     field public static final int INVALID_POSITION = -1; // 0xffffffff
-    field public static final deprecated int MAX_TEXT_LENGTH = 500; // 0x1f4
+    field @Deprecated public static final int MAX_TEXT_LENGTH = 500; // 0x1f4
     field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
     field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
     field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
@@ -51435,18 +51869,18 @@
     field public static final int WINDOWS_CHANGE_TITLE = 4; // 0x4
   }
 
-  public abstract interface AccessibilityEventSource {
-    method public abstract void sendAccessibilityEvent(int);
-    method public abstract void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent);
+  public interface AccessibilityEventSource {
+    method public void sendAccessibilityEvent(int);
+    method public void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent);
   }
 
   public final class AccessibilityManager {
     method public void addAccessibilityRequestPreparer(android.view.accessibility.AccessibilityRequestPreparer);
-    method public boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
-    method public void addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, android.os.Handler);
-    method public boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
-    method public void addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, android.os.Handler);
-    method public deprecated java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
+    method public boolean addAccessibilityStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
+    method public void addAccessibilityStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, @Nullable android.os.Handler);
+    method public boolean addTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
+    method public void addTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, @Nullable android.os.Handler);
+    method @Deprecated public java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
     method public int getRecommendedTimeoutMillis(int, int);
@@ -51455,66 +51889,66 @@
     method public boolean isEnabled();
     method public boolean isTouchExplorationEnabled();
     method public void removeAccessibilityRequestPreparer(android.view.accessibility.AccessibilityRequestPreparer);
-    method public boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
-    method public boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
+    method public boolean removeAccessibilityStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
+    method public boolean removeTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
     method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     field public static final int FLAG_CONTENT_CONTROLS = 4; // 0x4
     field public static final int FLAG_CONTENT_ICONS = 1; // 0x1
     field public static final int FLAG_CONTENT_TEXT = 2; // 0x2
   }
 
-  public static abstract interface AccessibilityManager.AccessibilityStateChangeListener {
-    method public abstract void onAccessibilityStateChanged(boolean);
+  public static interface AccessibilityManager.AccessibilityStateChangeListener {
+    method public void onAccessibilityStateChanged(boolean);
   }
 
-  public static abstract interface AccessibilityManager.TouchExplorationStateChangeListener {
-    method public abstract void onTouchExplorationStateChanged(boolean);
+  public static interface AccessibilityManager.TouchExplorationStateChangeListener {
+    method public void onTouchExplorationStateChanged(boolean);
   }
 
   public class AccessibilityNodeInfo implements android.os.Parcelable {
     method public void addAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
-    method public deprecated void addAction(int);
+    method @Deprecated public void addAction(int);
     method public void addChild(android.view.View);
     method public void addChild(android.view.View, int);
     method public boolean canOpenPopup();
     method public int describeContents();
-    method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String);
-    method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(java.lang.String);
+    method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String);
+    method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public android.view.accessibility.AccessibilityNodeInfo focusSearch(int);
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getActionList();
-    method public deprecated int getActions();
+    method @Deprecated public int getActions();
     method public java.util.List<java.lang.String> getAvailableExtraData();
     method public void getBoundsInParent(android.graphics.Rect);
     method public void getBoundsInScreen(android.graphics.Rect);
     method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
     method public int getChildCount();
-    method public java.lang.CharSequence getClassName();
+    method public CharSequence getClassName();
     method public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo getCollectionInfo();
     method public android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo getCollectionItemInfo();
-    method public java.lang.CharSequence getContentDescription();
+    method public CharSequence getContentDescription();
     method public int getDrawingOrder();
-    method public java.lang.CharSequence getError();
+    method public CharSequence getError();
     method public android.os.Bundle getExtras();
-    method public java.lang.CharSequence getHintText();
+    method public CharSequence getHintText();
     method public int getInputType();
     method public android.view.accessibility.AccessibilityNodeInfo getLabelFor();
     method public android.view.accessibility.AccessibilityNodeInfo getLabeledBy();
     method public int getLiveRegion();
     method public int getMaxTextLength();
     method public int getMovementGranularities();
-    method public java.lang.CharSequence getPackageName();
-    method public java.lang.CharSequence getPaneTitle();
+    method public CharSequence getPackageName();
+    method @Nullable public CharSequence getPaneTitle();
     method public android.view.accessibility.AccessibilityNodeInfo getParent();
     method public android.view.accessibility.AccessibilityNodeInfo.RangeInfo getRangeInfo();
-    method public java.lang.CharSequence getText();
+    method public CharSequence getText();
     method public int getTextSelectionEnd();
     method public int getTextSelectionStart();
-    method public java.lang.CharSequence getTooltipText();
-    method public android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo getTouchDelegateInfo();
+    method @Nullable public CharSequence getTooltipText();
+    method @Nullable public android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo getTouchDelegateInfo();
     method public android.view.accessibility.AccessibilityNodeInfo getTraversalAfter();
     method public android.view.accessibility.AccessibilityNodeInfo getTraversalBefore();
-    method public java.lang.String getViewIdResourceName();
+    method public String getViewIdResourceName();
     method public android.view.accessibility.AccessibilityWindowInfo getWindow();
     method public int getWindowId();
     method public boolean isAccessibilityFocused();
@@ -51547,8 +51981,8 @@
     method public boolean performAction(int, android.os.Bundle);
     method public void recycle();
     method public boolean refresh();
-    method public boolean refreshWithExtraData(java.lang.String, android.os.Bundle);
-    method public deprecated void removeAction(int);
+    method public boolean refreshWithExtraData(String, android.os.Bundle);
+    method @Deprecated public void removeAction(int);
     method public boolean removeAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
     method public boolean removeChild(android.view.View);
     method public boolean removeChild(android.view.View, int);
@@ -51559,22 +51993,22 @@
     method public void setCanOpenPopup(boolean);
     method public void setCheckable(boolean);
     method public void setChecked(boolean);
-    method public void setClassName(java.lang.CharSequence);
-    method public deprecated void setClickable(boolean);
+    method public void setClassName(CharSequence);
+    method @Deprecated public void setClickable(boolean);
     method public void setCollectionInfo(android.view.accessibility.AccessibilityNodeInfo.CollectionInfo);
     method public void setCollectionItemInfo(android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo);
-    method public void setContentDescription(java.lang.CharSequence);
+    method public void setContentDescription(CharSequence);
     method public void setContentInvalid(boolean);
-    method public deprecated void setContextClickable(boolean);
-    method public deprecated void setDismissable(boolean);
+    method @Deprecated public void setContextClickable(boolean);
+    method @Deprecated public void setDismissable(boolean);
     method public void setDrawingOrder(int);
     method public void setEditable(boolean);
     method public void setEnabled(boolean);
-    method public void setError(java.lang.CharSequence);
-    method public deprecated void setFocusable(boolean);
+    method public void setError(CharSequence);
+    method @Deprecated public void setFocusable(boolean);
     method public void setFocused(boolean);
     method public void setHeading(boolean);
-    method public void setHintText(java.lang.CharSequence);
+    method public void setHintText(CharSequence);
     method public void setImportantForAccessibility(boolean);
     method public void setInputType(int);
     method public void setLabelFor(android.view.View);
@@ -51582,46 +52016,46 @@
     method public void setLabeledBy(android.view.View);
     method public void setLabeledBy(android.view.View, int);
     method public void setLiveRegion(int);
-    method public deprecated void setLongClickable(boolean);
+    method @Deprecated public void setLongClickable(boolean);
     method public void setMaxTextLength(int);
     method public void setMovementGranularities(int);
     method public void setMultiLine(boolean);
-    method public void setPackageName(java.lang.CharSequence);
-    method public void setPaneTitle(java.lang.CharSequence);
+    method public void setPackageName(CharSequence);
+    method public void setPaneTitle(@Nullable CharSequence);
     method public void setParent(android.view.View);
     method public void setParent(android.view.View, int);
     method public void setPassword(boolean);
     method public void setRangeInfo(android.view.accessibility.AccessibilityNodeInfo.RangeInfo);
     method public void setScreenReaderFocusable(boolean);
-    method public deprecated void setScrollable(boolean);
+    method @Deprecated public void setScrollable(boolean);
     method public void setSelected(boolean);
     method public void setShowingHintText(boolean);
     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 setText(CharSequence);
     method public void setTextEntryKey(boolean);
     method public void setTextSelection(int, int);
-    method public void setTooltipText(java.lang.CharSequence);
-    method public void setTouchDelegateInfo(android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo);
+    method public void setTooltipText(@Nullable CharSequence);
+    method public void setTouchDelegateInfo(@NonNull android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo);
     method public void setTraversalAfter(android.view.View);
     method public void setTraversalAfter(android.view.View, int);
     method public void setTraversalBefore(android.view.View);
     method public void setTraversalBefore(android.view.View, int);
-    method public void setViewIdResourceName(java.lang.String);
+    method public void setViewIdResourceName(String);
     method public void setVisibleToUser(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
-    field public static final java.lang.String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
-    field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
-    field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
-    field public static final java.lang.String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
-    field public static final java.lang.String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
-    field public static final java.lang.String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
-    field public static final java.lang.String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
-    field public static final java.lang.String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
-    field public static final java.lang.String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
-    field public static final java.lang.String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
-    field public static final java.lang.String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+    field public static final String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
+    field public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
+    field public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
+    field public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+    field public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
+    field public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
+    field public static final String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
+    field public static final String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
+    field public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
+    field public static final String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+    field public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
     field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
     field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
     field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
@@ -51644,9 +52078,9 @@
     field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
     field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
     field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo> CREATOR;
-    field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
-    field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
-    field public static final java.lang.String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
+    field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
+    field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
+    field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
     field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
     field public static final int FOCUS_INPUT = 1; // 0x1
     field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
@@ -51657,9 +52091,9 @@
   }
 
   public static final class AccessibilityNodeInfo.AccessibilityAction {
-    ctor public AccessibilityNodeInfo.AccessibilityAction(int, java.lang.CharSequence);
+    ctor public AccessibilityNodeInfo.AccessibilityAction(int, @Nullable CharSequence);
     method public int getId();
-    method public java.lang.CharSequence getLabel();
+    method public CharSequence getLabel();
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_ACCESSIBILITY_FOCUS;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CLEAR_ACCESSIBILITY_FOCUS;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CLEAR_FOCUS;
@@ -51716,7 +52150,7 @@
     method public int getColumnSpan();
     method public int getRowIndex();
     method public int getRowSpan();
-    method public deprecated boolean isHeading();
+    method @Deprecated public boolean isHeading();
     method public boolean isSelected();
     method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean);
     method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean, boolean);
@@ -51734,20 +52168,20 @@
   }
 
   public static final class AccessibilityNodeInfo.TouchDelegateInfo implements android.os.Parcelable {
-    ctor public AccessibilityNodeInfo.TouchDelegateInfo(java.util.Map<android.graphics.Region, android.view.View>);
+    ctor public AccessibilityNodeInfo.TouchDelegateInfo(@NonNull java.util.Map<android.graphics.Region,android.view.View>);
     method public int describeContents();
-    method public android.graphics.Region getRegionAt(int);
+    method @NonNull public android.graphics.Region getRegionAt(int);
     method public int getRegionCount();
-    method public android.view.accessibility.AccessibilityNodeInfo getTargetForRegion(android.graphics.Region);
+    method @Nullable public android.view.accessibility.AccessibilityNodeInfo getTargetForRegion(@NonNull android.graphics.Region);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo> CREATOR;
   }
 
   public abstract class AccessibilityNodeProvider {
     ctor public AccessibilityNodeProvider();
-    method public void addExtraDataToAccessibilityNodeInfo(int, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
+    method public void addExtraDataToAccessibilityNodeInfo(int, android.view.accessibility.AccessibilityNodeInfo, String, android.os.Bundle);
     method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo(int);
-    method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String, int);
+    method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String, int);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method public boolean performAction(int, int, android.os.Bundle);
     field public static final int HOST_VIEW_ID = -1; // 0xffffffff
@@ -51755,9 +52189,9 @@
 
   public class AccessibilityRecord {
     method public int getAddedCount();
-    method public java.lang.CharSequence getBeforeText();
-    method public java.lang.CharSequence getClassName();
-    method public java.lang.CharSequence getContentDescription();
+    method public CharSequence getBeforeText();
+    method public CharSequence getClassName();
+    method public CharSequence getContentDescription();
     method public int getCurrentItemIndex();
     method public int getFromIndex();
     method public int getItemCount();
@@ -51782,10 +52216,10 @@
     method public static android.view.accessibility.AccessibilityRecord obtain();
     method public void recycle();
     method public void setAddedCount(int);
-    method public void setBeforeText(java.lang.CharSequence);
+    method public void setBeforeText(CharSequence);
     method public void setChecked(boolean);
-    method public void setClassName(java.lang.CharSequence);
-    method public void setContentDescription(java.lang.CharSequence);
+    method public void setClassName(CharSequence);
+    method public void setContentDescription(CharSequence);
     method public void setCurrentItemIndex(int);
     method public void setEnabled(boolean);
     method public void setFromIndex(int);
@@ -51802,14 +52236,14 @@
     method public void setScrollY(int);
     method public void setScrollable(boolean);
     method public void setSource(android.view.View);
-    method public void setSource(android.view.View, int);
+    method public void setSource(@Nullable android.view.View, int);
     method public void setToIndex(int);
   }
 
   public abstract class AccessibilityRequestPreparer {
     ctor public AccessibilityRequestPreparer(android.view.View, int);
-    method public android.view.View getView();
-    method public abstract void onPrepareExtraData(int, java.lang.String, android.os.Bundle, android.os.Message);
+    method @Nullable public android.view.View getView();
+    method public abstract void onPrepareExtraData(int, String, android.os.Bundle, android.os.Message);
     field public static final int REQUEST_TYPE_EXTRA_DATA = 1; // 0x1
   }
 
@@ -51823,7 +52257,7 @@
     method public int getLayer();
     method public android.view.accessibility.AccessibilityWindowInfo getParent();
     method public android.view.accessibility.AccessibilityNodeInfo getRoot();
-    method public java.lang.CharSequence getTitle();
+    method @Nullable public CharSequence getTitle();
     method public int getType();
     method public boolean isAccessibilityFocused();
     method public boolean isActive();
@@ -51842,16 +52276,16 @@
   }
 
   public class CaptioningManager {
-    method public void addCaptioningChangeListener(android.view.accessibility.CaptioningManager.CaptioningChangeListener);
+    method public void addCaptioningChangeListener(@NonNull android.view.accessibility.CaptioningManager.CaptioningChangeListener);
     method public final float getFontScale();
-    method public final java.util.Locale getLocale();
-    method public android.view.accessibility.CaptioningManager.CaptionStyle getUserStyle();
+    method @Nullable public final java.util.Locale getLocale();
+    method @NonNull public android.view.accessibility.CaptioningManager.CaptionStyle getUserStyle();
     method public final boolean isEnabled();
-    method public void removeCaptioningChangeListener(android.view.accessibility.CaptioningManager.CaptioningChangeListener);
+    method public void removeCaptioningChangeListener(@NonNull android.view.accessibility.CaptioningManager.CaptioningChangeListener);
   }
 
   public static final class CaptioningManager.CaptionStyle {
-    method public android.graphics.Typeface getTypeface();
+    method @Nullable public android.graphics.Typeface getTypeface();
     method public boolean hasBackgroundColor();
     method public boolean hasEdgeColor();
     method public boolean hasEdgeType();
@@ -51870,12 +52304,12 @@
     field public final int windowColor;
   }
 
-  public static abstract class CaptioningManager.CaptioningChangeListener {
+  public abstract static class CaptioningManager.CaptioningChangeListener {
     ctor public CaptioningManager.CaptioningChangeListener();
     method public void onEnabledChanged(boolean);
     method public void onFontScaleChanged(float);
-    method public void onLocaleChanged(java.util.Locale);
-    method public void onUserStyleChanged(android.view.accessibility.CaptioningManager.CaptionStyle);
+    method public void onLocaleChanged(@Nullable java.util.Locale);
+    method public void onUserStyleChanged(@NonNull android.view.accessibility.CaptioningManager.CaptionStyle);
   }
 
 }
@@ -51909,8 +52343,8 @@
     method protected android.view.animation.Animation clone() throws java.lang.CloneNotSupportedException;
     method public long computeDurationHint();
     method protected void ensureInterpolator();
-    method public int getBackgroundColor();
-    method public deprecated boolean getDetachWallpaper();
+    method @ColorInt public int getBackgroundColor();
+    method @Deprecated public boolean getDetachWallpaper();
     method public long getDuration();
     method public boolean getFillAfter();
     method public boolean getFillBefore();
@@ -51934,13 +52368,13 @@
     method public void restrictDuration(long);
     method public void scaleCurrentDuration(float);
     method public void setAnimationListener(android.view.animation.Animation.AnimationListener);
-    method public void setBackgroundColor(int);
-    method public deprecated void setDetachWallpaper(boolean);
+    method public void setBackgroundColor(@ColorInt int);
+    method @Deprecated public void setDetachWallpaper(boolean);
     method public void setDuration(long);
     method public void setFillAfter(boolean);
     method public void setFillBefore(boolean);
     method public void setFillEnabled(boolean);
-    method public void setInterpolator(android.content.Context, int);
+    method public void setInterpolator(android.content.Context, @AnimRes @InterpolatorRes int);
     method public void setInterpolator(android.view.animation.Interpolator);
     method public void setRepeatCount(int);
     method public void setRepeatMode(int);
@@ -51963,10 +52397,10 @@
     field public static final int ZORDER_TOP = 1; // 0x1
   }
 
-  public static abstract interface Animation.AnimationListener {
-    method public abstract void onAnimationEnd(android.view.animation.Animation);
-    method public abstract void onAnimationRepeat(android.view.animation.Animation);
-    method public abstract void onAnimationStart(android.view.animation.Animation);
+  public static interface Animation.AnimationListener {
+    method public void onAnimationEnd(android.view.animation.Animation);
+    method public void onAnimationRepeat(android.view.animation.Animation);
+    method public void onAnimationStart(android.view.animation.Animation);
   }
 
   protected static class Animation.Description {
@@ -51986,9 +52420,9 @@
   public class AnimationUtils {
     ctor public AnimationUtils();
     method public static long currentAnimationTimeMillis();
-    method public static android.view.animation.Animation loadAnimation(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
-    method public static android.view.animation.Interpolator loadInterpolator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
-    method public static android.view.animation.LayoutAnimationController loadLayoutAnimation(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
+    method public static android.view.animation.Animation loadAnimation(android.content.Context, @AnimRes int) throws android.content.res.Resources.NotFoundException;
+    method public static android.view.animation.Interpolator loadInterpolator(android.content.Context, @AnimRes @InterpolatorRes int) throws android.content.res.Resources.NotFoundException;
+    method public static android.view.animation.LayoutAnimationController loadLayoutAnimation(android.content.Context, @AnimRes int) throws android.content.res.Resources.NotFoundException;
     method public static android.view.animation.Animation makeInAnimation(android.content.Context, boolean);
     method public static android.view.animation.Animation makeInChildBottomAnimation(android.content.Context);
     method public static android.view.animation.Animation makeOutAnimation(android.content.Context, boolean);
@@ -52063,7 +52497,7 @@
     field public int rowsCount;
   }
 
-  public abstract interface Interpolator implements android.animation.TimeInterpolator {
+  public interface Interpolator extends android.animation.TimeInterpolator {
   }
 
   public class LayoutAnimationController {
@@ -52078,10 +52512,10 @@
     method public int getOrder();
     method protected int getTransformedIndex(android.view.animation.LayoutAnimationController.AnimationParameters);
     method public boolean isDone();
-    method public void setAnimation(android.content.Context, int);
+    method public void setAnimation(android.content.Context, @AnimRes int);
     method public void setAnimation(android.view.animation.Animation);
     method public void setDelay(float);
-    method public void setInterpolator(android.content.Context, int);
+    method public void setInterpolator(android.content.Context, @InterpolatorRes int);
     method public void setInterpolator(android.view.animation.Interpolator);
     method public void setOrder(int);
     method public void start();
@@ -52143,9 +52577,9 @@
     method public android.graphics.Matrix getMatrix();
     method public int getTransformationType();
     method public void set(android.view.animation.Transformation);
-    method public void setAlpha(float);
+    method public void setAlpha(@FloatRange(from=0.0, to=1.0) float);
     method public void setTransformationType(int);
-    method public java.lang.String toShortString();
+    method public String toShortString();
     field public static final int TYPE_ALPHA = 1; // 0x1
     field public static final int TYPE_BOTH = 3; // 0x3
     field public static final int TYPE_IDENTITY = 0; // 0x0
@@ -52175,40 +52609,40 @@
     method public void cancel();
     method public void commit();
     method public void disableAutofillServices();
-    method public android.content.ComponentName getAutofillServiceComponentName();
-    method public java.util.List<java.lang.String> getAvailableFieldClassificationAlgorithms();
-    method public java.lang.String getDefaultFieldClassificationAlgorithm();
-    method public android.view.autofill.AutofillId getNextAutofillId();
-    method public android.service.autofill.UserData getUserData();
-    method public java.lang.String getUserDataId();
+    method @Nullable public android.content.ComponentName getAutofillServiceComponentName();
+    method @NonNull public java.util.List<java.lang.String> getAvailableFieldClassificationAlgorithms();
+    method @Nullable public String getDefaultFieldClassificationAlgorithm();
+    method @Nullable public android.view.autofill.AutofillId getNextAutofillId();
+    method @Nullable public android.service.autofill.UserData getUserData();
+    method @Nullable public String getUserDataId();
     method public boolean hasEnabledAutofillServices();
     method public boolean isAutofillSupported();
     method public boolean isEnabled();
     method public boolean isFieldClassificationEnabled();
     method public void notifyValueChanged(android.view.View);
     method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
-    method public void notifyViewClicked(android.view.View);
-    method public void notifyViewClicked(android.view.View, int);
-    method public void notifyViewEntered(android.view.View);
-    method public void notifyViewEntered(android.view.View, int, android.graphics.Rect);
-    method public void notifyViewExited(android.view.View);
-    method public void notifyViewExited(android.view.View, int);
-    method public void notifyViewVisibilityChanged(android.view.View, boolean);
-    method public void notifyViewVisibilityChanged(android.view.View, int, boolean);
-    method public void registerCallback(android.view.autofill.AutofillManager.AutofillCallback);
-    method public void requestAutofill(android.view.View);
-    method public void requestAutofill(android.view.View, int, android.graphics.Rect);
-    method public void setUserData(android.service.autofill.UserData);
-    method public void unregisterCallback(android.view.autofill.AutofillManager.AutofillCallback);
-    field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
-    field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
-    field public static final java.lang.String EXTRA_CLIENT_STATE = "android.view.autofill.extra.CLIENT_STATE";
+    method public void notifyViewClicked(@NonNull android.view.View);
+    method public void notifyViewClicked(@NonNull android.view.View, int);
+    method public void notifyViewEntered(@NonNull android.view.View);
+    method public void notifyViewEntered(@NonNull android.view.View, int, @NonNull android.graphics.Rect);
+    method public void notifyViewExited(@NonNull android.view.View);
+    method public void notifyViewExited(@NonNull android.view.View, int);
+    method public void notifyViewVisibilityChanged(@NonNull android.view.View, boolean);
+    method public void notifyViewVisibilityChanged(@NonNull android.view.View, int, boolean);
+    method public void registerCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback);
+    method public void requestAutofill(@NonNull android.view.View);
+    method public void requestAutofill(@NonNull android.view.View, int, @NonNull android.graphics.Rect);
+    method public void setUserData(@Nullable android.service.autofill.UserData);
+    method public void unregisterCallback(@Nullable android.view.autofill.AutofillManager.AutofillCallback);
+    field public static final String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
+    field public static final String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
+    field public static final String EXTRA_CLIENT_STATE = "android.view.autofill.extra.CLIENT_STATE";
   }
 
-  public static abstract class AutofillManager.AutofillCallback {
+  public abstract static class AutofillManager.AutofillCallback {
     ctor public AutofillManager.AutofillCallback();
-    method public void onAutofillEvent(android.view.View, int);
-    method public void onAutofillEvent(android.view.View, int, int);
+    method public void onAutofillEvent(@NonNull android.view.View, int);
+    method public void onAutofillEvent(@NonNull android.view.View, int, int);
     field public static final int EVENT_INPUT_HIDDEN = 2; // 0x2
     field public static final int EVENT_INPUT_SHOWN = 1; // 0x1
     field public static final int EVENT_INPUT_UNAVAILABLE = 3; // 0x3
@@ -52218,11 +52652,11 @@
     method public int describeContents();
     method public static android.view.autofill.AutofillValue forDate(long);
     method public static android.view.autofill.AutofillValue forList(int);
-    method public static android.view.autofill.AutofillValue forText(java.lang.CharSequence);
+    method public static android.view.autofill.AutofillValue forText(@Nullable CharSequence);
     method public static android.view.autofill.AutofillValue forToggle(boolean);
     method public long getDateValue();
     method public int getListValue();
-    method public java.lang.CharSequence getTextValue();
+    method @NonNull public CharSequence getTextValue();
     method public boolean getToggleValue();
     method public boolean isDate();
     method public boolean isList();
@@ -52245,26 +52679,29 @@
   public static final class ContentCaptureContext.Builder {
     ctor public ContentCaptureContext.Builder();
     method public android.view.contentcapture.ContentCaptureContext build();
-    method public android.view.contentcapture.ContentCaptureContext.Builder setExtras(android.os.Bundle);
-    method public android.view.contentcapture.ContentCaptureContext.Builder setUri(android.net.Uri);
+    method @NonNull public android.view.contentcapture.ContentCaptureContext.Builder setAction(@NonNull String);
+    method @NonNull public android.view.contentcapture.ContentCaptureContext.Builder setExtras(@NonNull android.os.Bundle);
+    method @NonNull public android.view.contentcapture.ContentCaptureContext.Builder setUri(@NonNull android.net.Uri);
   }
 
   public final class ContentCaptureManager {
-    method public android.content.ComponentName getServiceComponentName();
+    method @Nullable public android.content.ComponentName getServiceComponentName();
     method public boolean isContentCaptureEnabled();
-    method public void removeUserData(android.view.contentcapture.UserDataRemovalRequest);
+    method public void removeUserData(@NonNull android.view.contentcapture.UserDataRemovalRequest);
     method public void setContentCaptureEnabled(boolean);
   }
 
   public abstract class ContentCaptureSession implements java.lang.AutoCloseable {
     method public void close();
-    method public final android.view.contentcapture.ContentCaptureSession createContentCaptureSession(android.view.contentcapture.ContentCaptureContext);
+    method @NonNull public final android.view.contentcapture.ContentCaptureSession createContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureContext);
     method public final void destroy();
     method public final android.view.contentcapture.ContentCaptureSessionId getContentCaptureSessionId();
-    method public final void notifyViewAppeared(android.view.ViewStructure);
-    method public final void notifyViewDisappeared(android.view.autofill.AutofillId);
-    method public final void notifyViewTextChanged(android.view.autofill.AutofillId, java.lang.CharSequence, int);
-    field public static final int FLAG_USER_INPUT = 1; // 0x1
+    method @NonNull public android.view.autofill.AutofillId newAutofillId(@NonNull android.view.autofill.AutofillId, long);
+    method @NonNull public final android.view.ViewStructure newVirtualViewStructure(@NonNull android.view.autofill.AutofillId, long);
+    method public final void notifyViewAppeared(@NonNull android.view.ViewStructure);
+    method public final void notifyViewDisappeared(@NonNull android.view.autofill.AutofillId);
+    method public final void notifyViewTextChanged(@NonNull android.view.autofill.AutofillId, @Nullable CharSequence, int);
+    method public final void notifyViewsDisappeared(@NonNull android.view.autofill.AutofillId, @NonNull long[]);
   }
 
   public final class ContentCaptureSessionId implements android.os.Parcelable {
@@ -52281,9 +52718,9 @@
 
   public static final class UserDataRemovalRequest.Builder {
     ctor public UserDataRemovalRequest.Builder();
-    method public android.view.contentcapture.UserDataRemovalRequest.Builder addUri(android.net.Uri, boolean);
-    method public android.view.contentcapture.UserDataRemovalRequest build();
-    method public android.view.contentcapture.UserDataRemovalRequest.Builder forEverything();
+    method public android.view.contentcapture.UserDataRemovalRequest.Builder addUri(@NonNull android.net.Uri, boolean);
+    method @NonNull public android.view.contentcapture.UserDataRemovalRequest build();
+    method @NonNull public android.view.contentcapture.UserDataRemovalRequest.Builder forEverything();
   }
 
 }
@@ -52294,11 +52731,11 @@
     ctor public BaseInputConnection(android.view.View, boolean);
     method public boolean beginBatchEdit();
     method public boolean clearMetaKeyStates(int);
-    method public void closeConnection();
+    method @CallSuper public void closeConnection();
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
-    method public boolean commitText(java.lang.CharSequence, int);
+    method public boolean commitText(CharSequence, int);
     method public boolean deleteSurroundingText(int, int);
     method public boolean deleteSurroundingTextInCodePoints(int, int);
     method public boolean endBatchEdit();
@@ -52309,40 +52746,40 @@
     method public android.text.Editable getEditable();
     method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
     method public android.os.Handler getHandler();
-    method public java.lang.CharSequence getSelectedText(int);
-    method public java.lang.CharSequence getTextAfterCursor(int, int);
-    method public java.lang.CharSequence getTextBeforeCursor(int, int);
+    method public CharSequence getSelectedText(int);
+    method public CharSequence getTextAfterCursor(int, int);
+    method public CharSequence getTextBeforeCursor(int, int);
     method public boolean performContextMenuAction(int);
     method public boolean performEditorAction(int);
-    method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
+    method public boolean performPrivateCommand(String, android.os.Bundle);
     method public static final void removeComposingSpans(android.text.Spannable);
     method public boolean reportFullscreenMode(boolean);
     method public boolean requestCursorUpdates(int);
     method public boolean sendKeyEvent(android.view.KeyEvent);
     method public boolean setComposingRegion(int, int);
     method public static void setComposingSpans(android.text.Spannable);
-    method public boolean setComposingText(java.lang.CharSequence, int);
+    method public boolean setComposingText(CharSequence, int);
     method public boolean setSelection(int, int);
   }
 
   public final class CompletionInfo implements android.os.Parcelable {
-    ctor public CompletionInfo(long, int, java.lang.CharSequence);
-    ctor public CompletionInfo(long, int, java.lang.CharSequence, java.lang.CharSequence);
+    ctor public CompletionInfo(long, int, CharSequence);
+    ctor public CompletionInfo(long, int, CharSequence, CharSequence);
     method public int describeContents();
     method public long getId();
-    method public java.lang.CharSequence getLabel();
+    method public CharSequence getLabel();
     method public int getPosition();
-    method public java.lang.CharSequence getText();
+    method public CharSequence getText();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.inputmethod.CompletionInfo> CREATOR;
   }
 
   public final class CorrectionInfo implements android.os.Parcelable {
-    ctor public CorrectionInfo(int, java.lang.CharSequence, java.lang.CharSequence);
+    ctor public CorrectionInfo(int, CharSequence, CharSequence);
     method public int describeContents();
-    method public java.lang.CharSequence getNewText();
+    method public CharSequence getNewText();
     method public int getOffset();
-    method public java.lang.CharSequence getOldText();
+    method public CharSequence getOldText();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.inputmethod.CorrectionInfo> CREATOR;
   }
@@ -52352,7 +52789,7 @@
     method public int describeContents();
     method public android.graphics.RectF getCharacterBounds(int);
     method public int getCharacterBoundsFlags(int);
-    method public java.lang.CharSequence getComposingText();
+    method public CharSequence getComposingText();
     method public int getComposingTextStart();
     method public float getInsertionMarkerBaseline();
     method public float getInsertionMarkerBottom();
@@ -52374,7 +52811,7 @@
     method public android.view.inputmethod.CursorAnchorInfo.Builder addCharacterBounds(int, float, float, float, float, int);
     method public android.view.inputmethod.CursorAnchorInfo build();
     method public void reset();
-    method public android.view.inputmethod.CursorAnchorInfo.Builder setComposingText(int, java.lang.CharSequence);
+    method public android.view.inputmethod.CursorAnchorInfo.Builder setComposingText(int, CharSequence);
     method public android.view.inputmethod.CursorAnchorInfo.Builder setInsertionMarkerLocation(float, float, float, float, int);
     method public android.view.inputmethod.CursorAnchorInfo.Builder setMatrix(android.graphics.Matrix);
     method public android.view.inputmethod.CursorAnchorInfo.Builder setSelectionRange(int, int);
@@ -52383,7 +52820,7 @@
   public class EditorInfo implements android.text.InputType android.os.Parcelable {
     ctor public EditorInfo();
     method public int describeContents();
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(android.util.Printer, String);
     method public final void makeCompatible(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.inputmethod.EditorInfo> CREATOR;
@@ -52406,21 +52843,21 @@
     field public static final int IME_MASK_ACTION = 255; // 0xff
     field public static final int IME_NULL = 0; // 0x0
     field public int actionId;
-    field public java.lang.CharSequence actionLabel;
-    field public java.lang.String[] contentMimeTypes;
+    field public CharSequence actionLabel;
+    field @Nullable public String[] contentMimeTypes;
     field public android.os.Bundle extras;
     field public int fieldId;
-    field public java.lang.String fieldName;
-    field public android.os.LocaleList hintLocales;
-    field public java.lang.CharSequence hintText;
+    field public String fieldName;
+    field @Nullable public android.os.LocaleList hintLocales;
+    field public CharSequence hintText;
     field public int imeOptions;
     field public int initialCapsMode;
     field public int initialSelEnd;
     field public int initialSelStart;
     field public int inputType;
-    field public java.lang.CharSequence label;
-    field public java.lang.String packageName;
-    field public java.lang.String privateImeOptions;
+    field public CharSequence label;
+    field public String packageName;
+    field public String privateImeOptions;
   }
 
   public class ExtractedText implements android.os.Parcelable {
@@ -52431,13 +52868,13 @@
     field public static final int FLAG_SELECTING = 2; // 0x2
     field public static final int FLAG_SINGLE_LINE = 1; // 0x1
     field public int flags;
-    field public java.lang.CharSequence hint;
+    field public CharSequence hint;
     field public int partialEndOffset;
     field public int partialStartOffset;
     field public int selectionEnd;
     field public int selectionStart;
     field public int startOffset;
-    field public java.lang.CharSequence text;
+    field public CharSequence text;
   }
 
   public class ExtractedTextRequest implements android.os.Parcelable {
@@ -52463,33 +52900,33 @@
     field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputBinding> CREATOR;
   }
 
-  public abstract interface InputConnection {
-    method public abstract boolean beginBatchEdit();
-    method public abstract boolean clearMetaKeyStates(int);
-    method public abstract void closeConnection();
-    method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
-    method public abstract boolean commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle);
-    method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
-    method public abstract boolean commitText(java.lang.CharSequence, int);
-    method public abstract boolean deleteSurroundingText(int, int);
-    method public abstract boolean deleteSurroundingTextInCodePoints(int, int);
-    method public abstract boolean endBatchEdit();
-    method public abstract boolean finishComposingText();
-    method public abstract int getCursorCapsMode(int);
-    method public abstract android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
-    method public abstract android.os.Handler getHandler();
-    method public abstract java.lang.CharSequence getSelectedText(int);
-    method public abstract java.lang.CharSequence getTextAfterCursor(int, int);
-    method public abstract java.lang.CharSequence getTextBeforeCursor(int, int);
-    method public abstract boolean performContextMenuAction(int);
-    method public abstract boolean performEditorAction(int);
-    method public abstract boolean performPrivateCommand(java.lang.String, android.os.Bundle);
-    method public abstract boolean reportFullscreenMode(boolean);
-    method public abstract boolean requestCursorUpdates(int);
-    method public abstract boolean sendKeyEvent(android.view.KeyEvent);
-    method public abstract boolean setComposingRegion(int, int);
-    method public abstract boolean setComposingText(java.lang.CharSequence, int);
-    method public abstract boolean setSelection(int, int);
+  public interface InputConnection {
+    method public boolean beginBatchEdit();
+    method public boolean clearMetaKeyStates(int);
+    method public void closeConnection();
+    method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+    method public boolean commitContent(@NonNull android.view.inputmethod.InputContentInfo, int, @Nullable android.os.Bundle);
+    method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
+    method public boolean commitText(CharSequence, int);
+    method public boolean deleteSurroundingText(int, int);
+    method public boolean deleteSurroundingTextInCodePoints(int, int);
+    method public boolean endBatchEdit();
+    method public boolean finishComposingText();
+    method public int getCursorCapsMode(int);
+    method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+    method public android.os.Handler getHandler();
+    method public CharSequence getSelectedText(int);
+    method public CharSequence getTextAfterCursor(int, int);
+    method public CharSequence getTextBeforeCursor(int, int);
+    method public boolean performContextMenuAction(int);
+    method public boolean performEditorAction(int);
+    method public boolean performPrivateCommand(String, android.os.Bundle);
+    method public boolean reportFullscreenMode(boolean);
+    method public boolean requestCursorUpdates(int);
+    method public boolean sendKeyEvent(android.view.KeyEvent);
+    method public boolean setComposingRegion(int, int);
+    method public boolean setComposingText(CharSequence, int);
+    method public boolean setSelection(int, int);
     field public static final int CURSOR_UPDATE_IMMEDIATE = 1; // 0x1
     field public static final int CURSOR_UPDATE_MONITOR = 2; // 0x2
     field public static final int GET_EXTRACTED_TEXT_MONITOR = 1; // 0x1
@@ -52505,7 +52942,7 @@
     method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
     method public boolean commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle);
     method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
-    method public boolean commitText(java.lang.CharSequence, int);
+    method public boolean commitText(CharSequence, int);
     method public boolean deleteSurroundingText(int, int);
     method public boolean deleteSurroundingTextInCodePoints(int, int);
     method public boolean endBatchEdit();
@@ -52513,116 +52950,116 @@
     method public int getCursorCapsMode(int);
     method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
     method public android.os.Handler getHandler();
-    method public java.lang.CharSequence getSelectedText(int);
-    method public java.lang.CharSequence getTextAfterCursor(int, int);
-    method public java.lang.CharSequence getTextBeforeCursor(int, int);
+    method public CharSequence getSelectedText(int);
+    method public CharSequence getTextAfterCursor(int, int);
+    method public CharSequence getTextBeforeCursor(int, int);
     method public boolean performContextMenuAction(int);
     method public boolean performEditorAction(int);
-    method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
+    method public boolean performPrivateCommand(String, android.os.Bundle);
     method public boolean reportFullscreenMode(boolean);
     method public boolean requestCursorUpdates(int);
     method public boolean sendKeyEvent(android.view.KeyEvent);
     method public boolean setComposingRegion(int, int);
-    method public boolean setComposingText(java.lang.CharSequence, int);
+    method public boolean setComposingText(CharSequence, int);
     method public boolean setSelection(int, int);
     method public void setTarget(android.view.inputmethod.InputConnection);
   }
 
   public final class InputContentInfo implements android.os.Parcelable {
-    ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription);
-    ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription, android.net.Uri);
+    ctor public InputContentInfo(@NonNull android.net.Uri, @NonNull android.content.ClipDescription);
+    ctor public InputContentInfo(@NonNull android.net.Uri, @NonNull android.content.ClipDescription, @Nullable android.net.Uri);
     method public int describeContents();
-    method public android.net.Uri getContentUri();
-    method public android.content.ClipDescription getDescription();
-    method public android.net.Uri getLinkUri();
+    method @NonNull public android.net.Uri getContentUri();
+    method @NonNull public android.content.ClipDescription getDescription();
+    method @Nullable public android.net.Uri getLinkUri();
     method public void releasePermission();
     method public void requestPermission();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputContentInfo> CREATOR;
   }
 
-  public abstract interface InputMethod {
-    method public abstract void attachToken(android.os.IBinder);
-    method public abstract void bindInput(android.view.inputmethod.InputBinding);
-    method public abstract void changeInputMethodSubtype(android.view.inputmethod.InputMethodSubtype);
-    method public abstract void createSession(android.view.inputmethod.InputMethod.SessionCallback);
-    method public abstract void hideSoftInput(int, android.os.ResultReceiver);
-    method public abstract void restartInput(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
-    method public abstract void revokeSession(android.view.inputmethod.InputMethodSession);
-    method public abstract void setSessionEnabled(android.view.inputmethod.InputMethodSession, boolean);
-    method public abstract void showSoftInput(int, android.os.ResultReceiver);
-    method public abstract void startInput(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
-    method public abstract void unbindInput();
-    field public static final java.lang.String SERVICE_INTERFACE = "android.view.InputMethod";
-    field public static final java.lang.String SERVICE_META_DATA = "android.view.im";
+  public interface InputMethod {
+    method @MainThread public void attachToken(android.os.IBinder);
+    method @MainThread public void bindInput(android.view.inputmethod.InputBinding);
+    method @MainThread public void changeInputMethodSubtype(android.view.inputmethod.InputMethodSubtype);
+    method @MainThread public void createSession(android.view.inputmethod.InputMethod.SessionCallback);
+    method @MainThread public void hideSoftInput(int, android.os.ResultReceiver);
+    method @MainThread public void restartInput(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
+    method @MainThread public void revokeSession(android.view.inputmethod.InputMethodSession);
+    method @MainThread public void setSessionEnabled(android.view.inputmethod.InputMethodSession, boolean);
+    method @MainThread public void showSoftInput(int, android.os.ResultReceiver);
+    method @MainThread public void startInput(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo);
+    method @MainThread public void unbindInput();
+    field public static final String SERVICE_INTERFACE = "android.view.InputMethod";
+    field public static final String SERVICE_META_DATA = "android.view.im";
     field public static final int SHOW_EXPLICIT = 1; // 0x1
     field public static final int SHOW_FORCED = 2; // 0x2
   }
 
-  public static abstract interface InputMethod.SessionCallback {
-    method public abstract void sessionCreated(android.view.inputmethod.InputMethodSession);
+  public static interface InputMethod.SessionCallback {
+    method public void sessionCreated(android.view.inputmethod.InputMethodSession);
   }
 
   public final class InputMethodInfo implements android.os.Parcelable {
     ctor public InputMethodInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    ctor public InputMethodInfo(java.lang.String, java.lang.String, java.lang.CharSequence, java.lang.String);
+    ctor public InputMethodInfo(String, String, CharSequence, String);
     method public int describeContents();
-    method public void dump(android.util.Printer, java.lang.String);
+    method public void dump(android.util.Printer, String);
     method public android.content.ComponentName getComponent();
-    method public java.lang.String getId();
+    method public String getId();
     method public int getIsDefaultResourceId();
-    method public java.lang.String getPackageName();
+    method public String getPackageName();
     method public android.content.pm.ServiceInfo getServiceInfo();
-    method public java.lang.String getServiceName();
-    method public java.lang.String getSettingsActivity();
+    method public String getServiceName();
+    method public String getSettingsActivity();
     method public android.view.inputmethod.InputMethodSubtype getSubtypeAt(int);
     method public int getSubtypeCount();
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
-    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
+    method public CharSequence loadLabel(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputMethodInfo> CREATOR;
   }
 
   public final class InputMethodManager {
-    method public void dispatchKeyEventFromInputMethod(android.view.View, android.view.KeyEvent);
+    method public void dispatchKeyEventFromInputMethod(@Nullable android.view.View, @NonNull android.view.KeyEvent);
     method public void displayCompletions(android.view.View, android.view.inputmethod.CompletionInfo[]);
     method public android.view.inputmethod.InputMethodSubtype getCurrentInputMethodSubtype();
     method public java.util.List<android.view.inputmethod.InputMethodInfo> getEnabledInputMethodList();
     method public java.util.List<android.view.inputmethod.InputMethodSubtype> getEnabledInputMethodSubtypeList(android.view.inputmethod.InputMethodInfo, boolean);
     method public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodList();
     method public android.view.inputmethod.InputMethodSubtype getLastInputMethodSubtype();
-    method public java.util.Map<android.view.inputmethod.InputMethodInfo, java.util.List<android.view.inputmethod.InputMethodSubtype>> getShortcutInputMethodsAndSubtypes();
-    method public deprecated void hideSoftInputFromInputMethod(android.os.IBinder, int);
+    method public java.util.Map<android.view.inputmethod.InputMethodInfo,java.util.List<android.view.inputmethod.InputMethodSubtype>> getShortcutInputMethodsAndSubtypes();
+    method @Deprecated public void hideSoftInputFromInputMethod(android.os.IBinder, int);
     method public boolean hideSoftInputFromWindow(android.os.IBinder, int);
     method public boolean hideSoftInputFromWindow(android.os.IBinder, int, android.os.ResultReceiver);
-    method public deprecated void hideStatusIcon(android.os.IBinder);
+    method @Deprecated public void hideStatusIcon(android.os.IBinder);
     method public boolean isAcceptingText();
     method public boolean isActive(android.view.View);
     method public boolean isActive();
     method public boolean isFullscreenMode();
-    method public deprecated boolean isWatchingCursor(android.view.View);
+    method @Deprecated public boolean isWatchingCursor(android.view.View);
     method public void restartInput(android.view.View);
-    method public void sendAppPrivateCommand(android.view.View, java.lang.String, android.os.Bundle);
-    method public void setAdditionalInputMethodSubtypes(java.lang.String, android.view.inputmethod.InputMethodSubtype[]);
-    method public boolean setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype);
-    method public deprecated void setInputMethod(android.os.IBinder, java.lang.String);
-    method public deprecated void setInputMethodAndSubtype(android.os.IBinder, java.lang.String, android.view.inputmethod.InputMethodSubtype);
-    method public deprecated boolean shouldOfferSwitchingToNextInputMethod(android.os.IBinder);
-    method public void showInputMethodAndSubtypeEnabler(java.lang.String);
+    method public void sendAppPrivateCommand(android.view.View, String, android.os.Bundle);
+    method @Deprecated public void setAdditionalInputMethodSubtypes(String, android.view.inputmethod.InputMethodSubtype[]);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype);
+    method @Deprecated public void setInputMethod(android.os.IBinder, String);
+    method @Deprecated public void setInputMethodAndSubtype(@NonNull android.os.IBinder, String, android.view.inputmethod.InputMethodSubtype);
+    method @Deprecated public boolean shouldOfferSwitchingToNextInputMethod(android.os.IBinder);
+    method public void showInputMethodAndSubtypeEnabler(String);
     method public void showInputMethodPicker();
     method public boolean showSoftInput(android.view.View, int);
     method public boolean showSoftInput(android.view.View, int, android.os.ResultReceiver);
-    method public deprecated void showSoftInputFromInputMethod(android.os.IBinder, int);
-    method public deprecated void showStatusIcon(android.os.IBinder, java.lang.String, int);
-    method public deprecated boolean switchToLastInputMethod(android.os.IBinder);
-    method public deprecated boolean switchToNextInputMethod(android.os.IBinder, boolean);
+    method @Deprecated public void showSoftInputFromInputMethod(android.os.IBinder, int);
+    method @Deprecated public void showStatusIcon(android.os.IBinder, String, @DrawableRes int);
+    method @Deprecated public boolean switchToLastInputMethod(android.os.IBinder);
+    method @Deprecated public boolean switchToNextInputMethod(android.os.IBinder, boolean);
     method public void toggleSoftInput(int, int);
     method public void toggleSoftInputFromWindow(android.os.IBinder, int, int);
-    method public deprecated void updateCursor(android.view.View, int, int, int, int);
+    method @Deprecated public void updateCursor(android.view.View, int, int, int, int);
     method public void updateCursorAnchorInfo(android.view.View, android.view.inputmethod.CursorAnchorInfo);
     method public void updateExtractedText(android.view.View, int, android.view.inputmethod.ExtractedText);
     method public void updateSelection(android.view.View, int, int, int, int);
-    method public void viewClicked(android.view.View);
+    method @Deprecated public void viewClicked(android.view.View);
     field public static final int HIDE_IMPLICIT_ONLY = 1; // 0x1
     field public static final int HIDE_NOT_ALWAYS = 2; // 0x2
     field public static final int RESULT_HIDDEN = 3; // 0x3
@@ -52633,37 +53070,37 @@
     field public static final int SHOW_IMPLICIT = 1; // 0x1
   }
 
-  public abstract interface InputMethodSession {
-    method public abstract void appPrivateCommand(java.lang.String, android.os.Bundle);
-    method public abstract void dispatchGenericMotionEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
-    method public abstract void dispatchKeyEvent(int, android.view.KeyEvent, android.view.inputmethod.InputMethodSession.EventCallback);
-    method public abstract void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
-    method public abstract void displayCompletions(android.view.inputmethod.CompletionInfo[]);
-    method public abstract void finishInput();
-    method public abstract void toggleSoftInput(int, int);
-    method public abstract void updateCursor(android.graphics.Rect);
-    method public abstract void updateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
-    method public abstract void updateExtractedText(int, android.view.inputmethod.ExtractedText);
-    method public abstract void updateSelection(int, int, int, int, int, int);
-    method public abstract void viewClicked(boolean);
+  public interface InputMethodSession {
+    method public void appPrivateCommand(String, android.os.Bundle);
+    method public void dispatchGenericMotionEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
+    method public void dispatchKeyEvent(int, android.view.KeyEvent, android.view.inputmethod.InputMethodSession.EventCallback);
+    method public void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
+    method public void displayCompletions(android.view.inputmethod.CompletionInfo[]);
+    method public void finishInput();
+    method public void toggleSoftInput(int, int);
+    method public void updateCursor(android.graphics.Rect);
+    method public void updateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
+    method public void updateExtractedText(int, android.view.inputmethod.ExtractedText);
+    method public void updateSelection(int, int, int, int, int, int);
+    method public void viewClicked(boolean);
   }
 
-  public static abstract interface InputMethodSession.EventCallback {
-    method public abstract void finishedEvent(int, boolean);
+  public static interface InputMethodSession.EventCallback {
+    method public void finishedEvent(int, boolean);
   }
 
   public final class InputMethodSubtype implements android.os.Parcelable {
-    ctor public deprecated InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean);
-    ctor public deprecated InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean, int);
-    method public boolean containsExtraValueKey(java.lang.String);
+    ctor @Deprecated public InputMethodSubtype(int, int, String, String, String, boolean, boolean);
+    ctor @Deprecated public InputMethodSubtype(int, int, String, String, String, boolean, boolean, int);
+    method public boolean containsExtraValueKey(String);
     method public int describeContents();
-    method public java.lang.CharSequence getDisplayName(android.content.Context, java.lang.String, android.content.pm.ApplicationInfo);
-    method public java.lang.String getExtraValue();
-    method public java.lang.String getExtraValueOf(java.lang.String);
+    method @NonNull public CharSequence getDisplayName(android.content.Context, String, android.content.pm.ApplicationInfo);
+    method public String getExtraValue();
+    method public String getExtraValueOf(String);
     method public int getIconResId();
-    method public java.lang.String getLanguageTag();
-    method public deprecated java.lang.String getLocale();
-    method public java.lang.String getMode();
+    method @NonNull public String getLanguageTag();
+    method @Deprecated @NonNull public String getLocale();
+    method public String getMode();
     method public int getNameResId();
     method public boolean isAsciiCapable();
     method public boolean isAuxiliary();
@@ -52677,13 +53114,13 @@
     method public android.view.inputmethod.InputMethodSubtype build();
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setIsAsciiCapable(boolean);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setIsAuxiliary(boolean);
-    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setLanguageTag(java.lang.String);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setLanguageTag(String);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setOverridesImplicitlyEnabledSubtype(boolean);
-    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeExtraValue(java.lang.String);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeExtraValue(String);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeIconResId(int);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeId(int);
-    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeLocale(java.lang.String);
-    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeMode(java.lang.String);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeLocale(String);
+    method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeMode(String);
     method public android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder setSubtypeNameResId(int);
   }
 
@@ -52691,10 +53128,10 @@
 
 package android.view.inspector {
 
-  public abstract interface InspectionCompanion<T> {
-    method public default java.lang.String getNodeName();
-    method public abstract void mapProperties(android.view.inspector.PropertyMapper);
-    method public abstract void readProperties(T, android.view.inspector.PropertyReader);
+  public interface InspectionCompanion<T> {
+    method @Nullable public default String getNodeName();
+    method public void mapProperties(@NonNull android.view.inspector.PropertyMapper);
+    method public void readProperties(@NonNull T, @NonNull android.view.inspector.PropertyReader);
   }
 
   public static class InspectionCompanion.UninitializedPropertyMapException extends java.lang.RuntimeException {
@@ -52702,122 +53139,118 @@
   }
 
   public final class IntEnumMapping {
-    method public java.lang.String nameOf(int);
+    method @Nullable public String get(int);
   }
 
   public static final class IntEnumMapping.Builder {
     ctor public IntEnumMapping.Builder();
-    method public android.view.inspector.IntEnumMapping.Builder addValue(java.lang.String, int);
-    method public android.view.inspector.IntEnumMapping build();
-    method public void clear();
+    method @NonNull public android.view.inspector.IntEnumMapping.Builder addValue(@NonNull String, int);
+    method @NonNull public android.view.inspector.IntEnumMapping build();
   }
 
   public final class IntFlagMapping {
-    method public java.lang.String[] namesOf(int);
+    method @NonNull public java.util.Set<java.lang.String> get(int);
   }
 
   public static final class IntFlagMapping.Builder {
     ctor public IntFlagMapping.Builder();
-    method public android.view.inspector.IntFlagMapping.Builder addFlag(java.lang.String, int);
-    method public android.view.inspector.IntFlagMapping.Builder addFlag(java.lang.String, int, int);
-    method public android.view.inspector.IntFlagMapping build();
-    method public void clear();
+    method @NonNull public android.view.inspector.IntFlagMapping.Builder addFlag(@NonNull String, int);
+    method @NonNull public android.view.inspector.IntFlagMapping.Builder addFlag(@NonNull String, int, int);
+    method @NonNull public android.view.inspector.IntFlagMapping build();
   }
 
-  public abstract interface PropertyMapper {
-    method public abstract int mapBoolean(java.lang.String, int);
-    method public abstract int mapByte(java.lang.String, int);
-    method public abstract int mapChar(java.lang.String, int);
-    method public abstract int mapColor(java.lang.String, int);
-    method public abstract int mapDouble(java.lang.String, int);
-    method public abstract int mapFloat(java.lang.String, int);
-    method public abstract int mapGravity(java.lang.String, int);
-    method public abstract int mapInt(java.lang.String, int);
-    method public abstract int mapIntEnum(java.lang.String, int, android.view.inspector.IntEnumMapping);
-    method public abstract int mapIntFlag(java.lang.String, int, android.view.inspector.IntFlagMapping);
-    method public abstract int mapLong(java.lang.String, int);
-    method public abstract int mapObject(java.lang.String, int);
-    method public abstract int mapShort(java.lang.String, int);
+  public interface PropertyMapper {
+    method public int mapBoolean(@NonNull String, @AttrRes int);
+    method public int mapByte(@NonNull String, @AttrRes int);
+    method public int mapChar(@NonNull String, @AttrRes int);
+    method public int mapColor(@NonNull String, @AttrRes int);
+    method public int mapDouble(@NonNull String, @AttrRes int);
+    method public int mapFloat(@NonNull String, @AttrRes int);
+    method public int mapGravity(@NonNull String, @AttrRes int);
+    method public int mapInt(@NonNull String, @AttrRes int);
+    method public int mapIntEnum(@NonNull String, @AttrRes int, @NonNull android.view.inspector.IntEnumMapping);
+    method public int mapIntFlag(@NonNull String, @AttrRes int, @NonNull android.view.inspector.IntFlagMapping);
+    method public int mapLong(@NonNull String, @AttrRes int);
+    method public int mapObject(@NonNull String, @AttrRes int);
+    method public int mapShort(@NonNull String, @AttrRes int);
   }
 
   public static class PropertyMapper.PropertyConflictException extends java.lang.RuntimeException {
-    ctor public PropertyMapper.PropertyConflictException(java.lang.String, java.lang.String, java.lang.String);
+    ctor public PropertyMapper.PropertyConflictException(@NonNull String, @NonNull String, @NonNull String);
   }
 
-  public abstract interface PropertyReader {
-    method public abstract void readBoolean(int, boolean);
-    method public abstract void readByte(int, byte);
-    method public abstract void readChar(int, char);
-    method public abstract void readColor(int, int);
-    method public abstract void readColor(int, long);
-    method public abstract void readColor(int, android.graphics.Color);
-    method public abstract void readDouble(int, double);
-    method public abstract void readFloat(int, float);
-    method public abstract void readGravity(int, int);
-    method public abstract void readInt(int, int);
-    method public abstract void readIntEnum(int, int);
-    method public abstract void readIntFlag(int, int);
-    method public abstract void readLong(int, long);
-    method public abstract void readObject(int, java.lang.Object);
-    method public abstract void readShort(int, short);
+  public interface PropertyReader {
+    method public void readBoolean(int, boolean);
+    method public void readByte(int, byte);
+    method public void readChar(int, char);
+    method public void readColor(int, @ColorInt int);
+    method public void readColor(int, @ColorLong long);
+    method public void readColor(int, @Nullable android.graphics.Color);
+    method public void readDouble(int, double);
+    method public void readFloat(int, float);
+    method public void readGravity(int, int);
+    method public void readInt(int, int);
+    method public void readIntEnum(int, int);
+    method public void readIntFlag(int, int);
+    method public void readLong(int, long);
+    method public void readObject(int, @Nullable Object);
+    method public void readShort(int, short);
   }
 
   public static class PropertyReader.PropertyTypeMismatchException extends java.lang.RuntimeException {
-    ctor public PropertyReader.PropertyTypeMismatchException(int, java.lang.String, java.lang.String, java.lang.String);
-    ctor public PropertyReader.PropertyTypeMismatchException(int, java.lang.String, java.lang.String);
+    ctor public PropertyReader.PropertyTypeMismatchException(int, @NonNull String, @NonNull String, @Nullable String);
+    ctor public PropertyReader.PropertyTypeMismatchException(int, @NonNull String, @NonNull String);
   }
 
 }
 
 package android.view.textclassifier {
 
-  public final class ConversationActions implements android.os.Parcelable {
-    ctor public ConversationActions(java.util.List<android.view.textclassifier.ConversationActions.ConversationAction>, java.lang.String);
+  public final class ConversationAction implements android.os.Parcelable {
     method public int describeContents();
-    method public java.util.List<android.view.textclassifier.ConversationActions.ConversationAction> getConversationActions();
-    method public java.lang.String getId();
+    method @Nullable public android.app.RemoteAction getAction();
+    method @FloatRange(from=0, to=1) public float getConfidenceScore();
+    method @NonNull public android.os.Bundle getExtras();
+    method @Nullable public CharSequence getTextReply();
+    method @NonNull public String getType();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationAction> CREATOR;
+    field public static final String TYPE_CALL_PHONE = "call_phone";
+    field public static final String TYPE_CREATE_REMINDER = "create_reminder";
+    field public static final String TYPE_OPEN_URL = "open_url";
+    field public static final String TYPE_SEND_EMAIL = "send_email";
+    field public static final String TYPE_SEND_SMS = "send_sms";
+    field public static final String TYPE_SHARE_LOCATION = "share_location";
+    field public static final String TYPE_TEXT_REPLY = "text_reply";
+    field public static final String TYPE_TRACK_FLIGHT = "track_flight";
+    field public static final String TYPE_VIEW_CALENDAR = "view_calendar";
+    field public static final String TYPE_VIEW_MAP = "view_map";
+  }
+
+  public static final class ConversationAction.Builder {
+    ctor public ConversationAction.Builder(@NonNull String);
+    method @NonNull public android.view.textclassifier.ConversationAction build();
+    method @NonNull public android.view.textclassifier.ConversationAction.Builder setAction(@Nullable android.app.RemoteAction);
+    method @NonNull public android.view.textclassifier.ConversationAction.Builder setConfidenceScore(@FloatRange(from=0, to=1) float);
+    method @NonNull public android.view.textclassifier.ConversationAction.Builder setExtras(@Nullable android.os.Bundle);
+    method @NonNull public android.view.textclassifier.ConversationAction.Builder setTextReply(@Nullable CharSequence);
+  }
+
+  public final class ConversationActions implements android.os.Parcelable {
+    ctor public ConversationActions(@NonNull java.util.List<android.view.textclassifier.ConversationAction>, @Nullable String);
+    method public int describeContents();
+    method @NonNull public java.util.List<android.view.textclassifier.ConversationAction> getConversationActions();
+    method @Nullable public String getId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions> CREATOR;
-    field public static final java.lang.String HINT_FOR_IN_APP = "in_app";
-    field public static final java.lang.String HINT_FOR_NOTIFICATION = "notification";
-    field public static final java.lang.String TYPE_CALL_PHONE = "call_phone";
-    field public static final java.lang.String TYPE_CREATE_REMINDER = "create_reminder";
-    field public static final java.lang.String TYPE_OPEN_URL = "open_url";
-    field public static final java.lang.String TYPE_SEND_EMAIL = "send_email";
-    field public static final java.lang.String TYPE_SEND_SMS = "send_sms";
-    field public static final java.lang.String TYPE_SHARE_LOCATION = "share_location";
-    field public static final java.lang.String TYPE_TEXT_REPLY = "text_reply";
-    field public static final java.lang.String TYPE_TRACK_FLIGHT = "track_flight";
-    field public static final java.lang.String TYPE_VIEW_CALENDAR = "view_calendar";
-    field public static final java.lang.String TYPE_VIEW_MAP = "view_map";
-  }
-
-  public static final class ConversationActions.ConversationAction implements android.os.Parcelable {
-    method public int describeContents();
-    method public android.app.RemoteAction getAction();
-    method public float getConfidenceScore();
-    method public android.os.Bundle getExtras();
-    method public java.lang.CharSequence getTextReply();
-    method public java.lang.String getType();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions.ConversationAction> CREATOR;
-  }
-
-  public static final class ConversationActions.ConversationAction.Builder {
-    ctor public ConversationActions.ConversationAction.Builder(java.lang.String);
-    method public android.view.textclassifier.ConversationActions.ConversationAction build();
-    method public android.view.textclassifier.ConversationActions.ConversationAction.Builder setAction(android.app.RemoteAction);
-    method public android.view.textclassifier.ConversationActions.ConversationAction.Builder setConfidenceScore(float);
-    method public android.view.textclassifier.ConversationActions.ConversationAction.Builder setExtras(android.os.Bundle);
-    method public android.view.textclassifier.ConversationActions.ConversationAction.Builder setTextReply(java.lang.CharSequence);
   }
 
   public static final class ConversationActions.Message implements android.os.Parcelable {
     method public int describeContents();
-    method public android.app.Person getAuthor();
-    method public android.os.Bundle getExtras();
-    method public java.time.ZonedDateTime getReferenceTime();
-    method public java.lang.CharSequence getText();
+    method @NonNull public android.app.Person getAuthor();
+    method @NonNull public android.os.Bundle getExtras();
+    method @Nullable public java.time.ZonedDateTime getReferenceTime();
+    method @Nullable public CharSequence getText();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions.Message> CREATOR;
     field public static final android.app.Person PERSON_USER_LOCAL;
@@ -52825,74 +53258,60 @@
   }
 
   public static final class ConversationActions.Message.Builder {
-    ctor public ConversationActions.Message.Builder(android.app.Person);
-    method public android.view.textclassifier.ConversationActions.Message build();
-    method public android.view.textclassifier.ConversationActions.Message.Builder setExtras(android.os.Bundle);
-    method public android.view.textclassifier.ConversationActions.Message.Builder setReferenceTime(java.time.ZonedDateTime);
-    method public android.view.textclassifier.ConversationActions.Message.Builder setText(java.lang.CharSequence);
+    ctor public ConversationActions.Message.Builder(@NonNull android.app.Person);
+    method @NonNull public android.view.textclassifier.ConversationActions.Message build();
+    method @NonNull public android.view.textclassifier.ConversationActions.Message.Builder setExtras(@Nullable android.os.Bundle);
+    method @NonNull public android.view.textclassifier.ConversationActions.Message.Builder setReferenceTime(@Nullable java.time.ZonedDateTime);
+    method @NonNull public android.view.textclassifier.ConversationActions.Message.Builder setText(@Nullable CharSequence);
   }
 
   public static final class ConversationActions.Request implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getCallingPackageName();
-    method public java.util.List<android.view.textclassifier.ConversationActions.Message> getConversation();
-    method public java.lang.String getConversationId();
-    method public java.util.List<java.lang.String> getHints();
-    method public int getMaxSuggestions();
-    method public android.view.textclassifier.ConversationActions.TypeConfig getTypeConfig();
+    method @Nullable public String getCallingPackageName();
+    method @NonNull public java.util.List<android.view.textclassifier.ConversationActions.Message> getConversation();
+    method @Nullable public String getConversationId();
+    method @Nullable public java.util.List<java.lang.String> getHints();
+    method @IntRange(from=0) public int getMaxSuggestions();
+    method @NonNull public android.view.textclassifier.TextClassifier.EntityConfig getTypeConfig();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions.Request> CREATOR;
+    field public static final String HINT_FOR_IN_APP = "in_app";
+    field public static final String HINT_FOR_NOTIFICATION = "notification";
   }
 
   public static final class ConversationActions.Request.Builder {
-    ctor public ConversationActions.Request.Builder(java.util.List<android.view.textclassifier.ConversationActions.Message>);
-    method public android.view.textclassifier.ConversationActions.Request build();
-    method public android.view.textclassifier.ConversationActions.Request.Builder setConversationId(java.lang.String);
-    method public android.view.textclassifier.ConversationActions.Request.Builder setHints(java.util.List<java.lang.String>);
-    method public android.view.textclassifier.ConversationActions.Request.Builder setMaxSuggestions(int);
-    method public android.view.textclassifier.ConversationActions.Request.Builder setTypeConfig(android.view.textclassifier.ConversationActions.TypeConfig);
-  }
-
-  public static final class ConversationActions.TypeConfig implements android.os.Parcelable {
-    method public int describeContents();
-    method public java.util.Collection<java.lang.String> resolveTypes(java.util.Collection<java.lang.String>);
-    method public boolean shouldIncludeTypesFromTextClassifier();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions.TypeConfig> CREATOR;
-  }
-
-  public static final class ConversationActions.TypeConfig.Builder {
-    ctor public ConversationActions.TypeConfig.Builder();
-    method public android.view.textclassifier.ConversationActions.TypeConfig build();
-    method public android.view.textclassifier.ConversationActions.TypeConfig.Builder includeTypesFromTextClassifier(boolean);
-    method public android.view.textclassifier.ConversationActions.TypeConfig.Builder setExcludedTypes(java.util.Collection<java.lang.String>);
-    method public android.view.textclassifier.ConversationActions.TypeConfig.Builder setIncludedTypes(java.util.Collection<java.lang.String>);
+    ctor public ConversationActions.Request.Builder(@NonNull java.util.List<android.view.textclassifier.ConversationActions.Message>);
+    method @NonNull public android.view.textclassifier.ConversationActions.Request build();
+    method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setConversationId(@Nullable String);
+    method public android.view.textclassifier.ConversationActions.Request.Builder setHints(@Nullable java.util.List<java.lang.String>);
+    method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setMaxSuggestions(@IntRange(from=0) int);
+    method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setTypeConfig(@Nullable android.view.textclassifier.TextClassifier.EntityConfig);
   }
 
   public final class SelectionEvent implements android.os.Parcelable {
-    method public static android.view.textclassifier.SelectionEvent createSelectionActionEvent(int, int, int);
-    method public static android.view.textclassifier.SelectionEvent createSelectionActionEvent(int, int, int, android.view.textclassifier.TextClassification);
-    method public static android.view.textclassifier.SelectionEvent createSelectionModifiedEvent(int, int);
-    method public static android.view.textclassifier.SelectionEvent createSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification);
-    method public static android.view.textclassifier.SelectionEvent createSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection);
-    method public static android.view.textclassifier.SelectionEvent createSelectionStartedEvent(int, int);
+    method @NonNull public static android.view.textclassifier.SelectionEvent createSelectionActionEvent(int, int, int);
+    method @NonNull public static android.view.textclassifier.SelectionEvent createSelectionActionEvent(int, int, int, @NonNull android.view.textclassifier.TextClassification);
+    method @NonNull public static android.view.textclassifier.SelectionEvent createSelectionModifiedEvent(int, int);
+    method @NonNull public static android.view.textclassifier.SelectionEvent createSelectionModifiedEvent(int, int, @NonNull android.view.textclassifier.TextClassification);
+    method @NonNull public static android.view.textclassifier.SelectionEvent createSelectionModifiedEvent(int, int, @NonNull android.view.textclassifier.TextSelection);
+    method @NonNull public static android.view.textclassifier.SelectionEvent createSelectionStartedEvent(int, int);
     method public int describeContents();
     method public long getDurationSincePreviousEvent();
     method public long getDurationSinceSessionStart();
     method public int getEnd();
-    method public java.lang.String getEntityType();
+    method @NonNull public String getEntityType();
     method public int getEventIndex();
     method public long getEventTime();
     method public int getEventType();
     method public int getInvocationMethod();
-    method public java.lang.String getPackageName();
-    method public java.lang.String getResultId();
-    method public android.view.textclassifier.TextClassificationSessionId getSessionId();
+    method @NonNull public String getPackageName();
+    method @Nullable public String getResultId();
+    method @Nullable public android.view.textclassifier.TextClassificationSessionId getSessionId();
     method public int getSmartEnd();
     method public int getSmartStart();
     method public int getStart();
-    method public java.lang.String getWidgetType();
-    method public java.lang.String getWidgetVersion();
+    method @NonNull public String getWidgetType();
+    method @Nullable public String getWidgetVersion();
     method public static boolean isTerminal(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_ABANDON = 107; // 0x6b
@@ -52920,79 +53339,79 @@
   public final class TextClassification implements android.os.Parcelable {
     method public int describeContents();
     method public java.util.List<android.app.RemoteAction> getActions();
-    method public float getConfidenceScore(java.lang.String);
-    method public java.lang.String getEntity(int);
-    method public int getEntityCount();
-    method public android.os.Bundle getExtras();
-    method public deprecated android.graphics.drawable.Drawable getIcon();
-    method public java.lang.String getId();
-    method public deprecated android.content.Intent getIntent();
-    method public deprecated java.lang.CharSequence getLabel();
-    method public deprecated android.view.View.OnClickListener getOnClickListener();
-    method public java.lang.String getText();
+    method @FloatRange(from=0.0, to=1.0) public float getConfidenceScore(String);
+    method @NonNull public String getEntity(int);
+    method @IntRange(from=0) public int getEntityCount();
+    method @NonNull public android.os.Bundle getExtras();
+    method @Deprecated @Nullable public android.graphics.drawable.Drawable getIcon();
+    method @Nullable public String getId();
+    method @Deprecated @Nullable public android.content.Intent getIntent();
+    method @Deprecated @Nullable public CharSequence getLabel();
+    method @Deprecated @Nullable public android.view.View.OnClickListener getOnClickListener();
+    method @Nullable public String getText();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassification> CREATOR;
   }
 
   public static final class TextClassification.Builder {
     ctor public TextClassification.Builder();
-    method public android.view.textclassifier.TextClassification.Builder addAction(android.app.RemoteAction);
-    method public android.view.textclassifier.TextClassification build();
-    method public android.view.textclassifier.TextClassification.Builder setEntityType(java.lang.String, float);
-    method public android.view.textclassifier.TextClassification.Builder setExtras(android.os.Bundle);
-    method public deprecated android.view.textclassifier.TextClassification.Builder setIcon(android.graphics.drawable.Drawable);
-    method public android.view.textclassifier.TextClassification.Builder setId(java.lang.String);
-    method public deprecated android.view.textclassifier.TextClassification.Builder setIntent(android.content.Intent);
-    method public deprecated android.view.textclassifier.TextClassification.Builder setLabel(java.lang.String);
-    method public deprecated android.view.textclassifier.TextClassification.Builder setOnClickListener(android.view.View.OnClickListener);
-    method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
+    method @NonNull public android.view.textclassifier.TextClassification.Builder addAction(@NonNull android.app.RemoteAction);
+    method @NonNull public android.view.textclassifier.TextClassification build();
+    method @NonNull public android.view.textclassifier.TextClassification.Builder setEntityType(@NonNull String, @FloatRange(from=0.0, to=1.0) float);
+    method @NonNull public android.view.textclassifier.TextClassification.Builder setExtras(@Nullable android.os.Bundle);
+    method @Deprecated @NonNull public android.view.textclassifier.TextClassification.Builder setIcon(@Nullable android.graphics.drawable.Drawable);
+    method @NonNull public android.view.textclassifier.TextClassification.Builder setId(@Nullable String);
+    method @Deprecated @NonNull public android.view.textclassifier.TextClassification.Builder setIntent(@Nullable android.content.Intent);
+    method @Deprecated @NonNull public android.view.textclassifier.TextClassification.Builder setLabel(@Nullable String);
+    method @Deprecated @NonNull public android.view.textclassifier.TextClassification.Builder setOnClickListener(@Nullable android.view.View.OnClickListener);
+    method @NonNull public android.view.textclassifier.TextClassification.Builder setText(@Nullable String);
   }
 
   public static final class TextClassification.Request implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getCallingPackageName();
-    method public android.os.LocaleList getDefaultLocales();
-    method public int getEndIndex();
-    method public android.os.Bundle getExtras();
-    method public java.time.ZonedDateTime getReferenceTime();
-    method public int getStartIndex();
-    method public java.lang.CharSequence getText();
+    method @Nullable public String getCallingPackageName();
+    method @Nullable public android.os.LocaleList getDefaultLocales();
+    method @IntRange(from=0) public int getEndIndex();
+    method @NonNull public android.os.Bundle getExtras();
+    method @Nullable public java.time.ZonedDateTime getReferenceTime();
+    method @IntRange(from=0) public int getStartIndex();
+    method @NonNull public CharSequence getText();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassification.Request> CREATOR;
   }
 
   public static final class TextClassification.Request.Builder {
-    ctor public TextClassification.Request.Builder(java.lang.CharSequence, int, int);
-    method public android.view.textclassifier.TextClassification.Request build();
-    method public android.view.textclassifier.TextClassification.Request.Builder setDefaultLocales(android.os.LocaleList);
-    method public android.view.textclassifier.TextClassification.Request.Builder setExtras(android.os.Bundle);
-    method public android.view.textclassifier.TextClassification.Request.Builder setReferenceTime(java.time.ZonedDateTime);
+    ctor public TextClassification.Request.Builder(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int);
+    method @NonNull public android.view.textclassifier.TextClassification.Request build();
+    method @NonNull public android.view.textclassifier.TextClassification.Request.Builder setDefaultLocales(@Nullable android.os.LocaleList);
+    method @NonNull public android.view.textclassifier.TextClassification.Request.Builder setExtras(@Nullable android.os.Bundle);
+    method @NonNull public android.view.textclassifier.TextClassification.Request.Builder setReferenceTime(@Nullable java.time.ZonedDateTime);
   }
 
   public final class TextClassificationContext implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getPackageName();
-    method public java.lang.String getWidgetType();
-    method public java.lang.String getWidgetVersion();
+    method @NonNull public String getPackageName();
+    method @NonNull public String getWidgetType();
+    method @Nullable public String getWidgetVersion();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassificationContext> CREATOR;
   }
 
   public static final class TextClassificationContext.Builder {
-    ctor public TextClassificationContext.Builder(java.lang.String, java.lang.String);
-    method public android.view.textclassifier.TextClassificationContext build();
-    method public android.view.textclassifier.TextClassificationContext.Builder setWidgetVersion(java.lang.String);
+    ctor public TextClassificationContext.Builder(@NonNull String, @NonNull String);
+    method @NonNull public android.view.textclassifier.TextClassificationContext build();
+    method public android.view.textclassifier.TextClassificationContext.Builder setWidgetVersion(@Nullable String);
   }
 
   public final class TextClassificationManager {
-    method public android.view.textclassifier.TextClassifier createTextClassificationSession(android.view.textclassifier.TextClassificationContext);
-    method public android.view.textclassifier.TextClassifier getTextClassifier();
-    method public void setTextClassificationSessionFactory(android.view.textclassifier.TextClassificationSessionFactory);
-    method public void setTextClassifier(android.view.textclassifier.TextClassifier);
+    method @NonNull public android.view.textclassifier.TextClassifier createTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationContext);
+    method @NonNull public android.view.textclassifier.TextClassifier getTextClassifier();
+    method public void setTextClassificationSessionFactory(@Nullable android.view.textclassifier.TextClassificationSessionFactory);
+    method public void setTextClassifier(@Nullable android.view.textclassifier.TextClassifier);
   }
 
-  public abstract interface TextClassificationSessionFactory {
-    method public abstract android.view.textclassifier.TextClassifier createTextClassificationSession(android.view.textclassifier.TextClassificationContext);
+  public interface TextClassificationSessionFactory {
+    method @NonNull public android.view.textclassifier.TextClassifier createTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationContext);
   }
 
   public final class TextClassificationSessionId implements android.os.Parcelable {
@@ -53001,71 +53420,81 @@
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassificationSessionId> CREATOR;
   }
 
-  public abstract interface TextClassifier {
-    method public default android.view.textclassifier.TextClassification classifyText(android.view.textclassifier.TextClassification.Request);
-    method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
+  public interface TextClassifier {
+    method @WorkerThread @NonNull public default android.view.textclassifier.TextClassification classifyText(@NonNull android.view.textclassifier.TextClassification.Request);
+    method @WorkerThread @NonNull public default android.view.textclassifier.TextClassification classifyText(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.os.LocaleList);
     method public default void destroy();
-    method public default android.view.textclassifier.TextLanguage detectLanguage(android.view.textclassifier.TextLanguage.Request);
-    method public default android.view.textclassifier.TextLinks generateLinks(android.view.textclassifier.TextLinks.Request);
-    method public default int getMaxGenerateLinksTextLength();
+    method @WorkerThread @NonNull public default android.view.textclassifier.TextLanguage detectLanguage(@NonNull android.view.textclassifier.TextLanguage.Request);
+    method @WorkerThread @NonNull public default android.view.textclassifier.TextLinks generateLinks(@NonNull android.view.textclassifier.TextLinks.Request);
+    method @WorkerThread public default int getMaxGenerateLinksTextLength();
     method public default boolean isDestroyed();
-    method public default void onSelectionEvent(android.view.textclassifier.SelectionEvent);
-    method public default void onTextClassifierEvent(android.view.textclassifier.TextClassifierEvent);
-    method public default android.view.textclassifier.ConversationActions suggestConversationActions(android.view.textclassifier.ConversationActions.Request);
-    method public default android.view.textclassifier.TextSelection suggestSelection(android.view.textclassifier.TextSelection.Request);
-    method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
-    field public static final java.lang.String EXTRA_FROM_TEXT_CLASSIFIER = "android.view.textclassifier.extra.FROM_TEXT_CLASSIFIER";
-    field public static final java.lang.String HINT_TEXT_IS_EDITABLE = "android.text_is_editable";
-    field public static final java.lang.String HINT_TEXT_IS_NOT_EDITABLE = "android.text_is_not_editable";
+    method public default void onSelectionEvent(@NonNull android.view.textclassifier.SelectionEvent);
+    method public default void onTextClassifierEvent(@NonNull android.view.textclassifier.TextClassifierEvent);
+    method @WorkerThread public default android.view.textclassifier.ConversationActions suggestConversationActions(@NonNull android.view.textclassifier.ConversationActions.Request);
+    method @WorkerThread @NonNull public default android.view.textclassifier.TextSelection suggestSelection(@NonNull android.view.textclassifier.TextSelection.Request);
+    method @WorkerThread @NonNull public default android.view.textclassifier.TextSelection suggestSelection(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.os.LocaleList);
+    field public static final String EXTRA_FROM_TEXT_CLASSIFIER = "android.view.textclassifier.extra.FROM_TEXT_CLASSIFIER";
+    field public static final String HINT_TEXT_IS_EDITABLE = "android.text_is_editable";
+    field public static final String HINT_TEXT_IS_NOT_EDITABLE = "android.text_is_not_editable";
     field public static final android.view.textclassifier.TextClassifier NO_OP;
-    field public static final java.lang.String TYPE_ADDRESS = "address";
-    field public static final java.lang.String TYPE_DATE = "date";
-    field public static final java.lang.String TYPE_DATE_TIME = "datetime";
-    field public static final java.lang.String TYPE_EMAIL = "email";
-    field public static final java.lang.String TYPE_FLIGHT_NUMBER = "flight";
-    field public static final java.lang.String TYPE_OTHER = "other";
-    field public static final java.lang.String TYPE_PHONE = "phone";
-    field public static final java.lang.String TYPE_UNKNOWN = "";
-    field public static final java.lang.String TYPE_URL = "url";
-    field public static final java.lang.String WIDGET_TYPE_CUSTOM_EDITTEXT = "customedit";
-    field public static final java.lang.String WIDGET_TYPE_CUSTOM_TEXTVIEW = "customview";
-    field public static final java.lang.String WIDGET_TYPE_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
-    field public static final java.lang.String WIDGET_TYPE_EDITTEXT = "edittext";
-    field public static final java.lang.String WIDGET_TYPE_EDIT_WEBVIEW = "edit-webview";
-    field public static final java.lang.String WIDGET_TYPE_NOTIFICATION = "notification";
-    field public static final java.lang.String WIDGET_TYPE_TEXTVIEW = "textview";
-    field public static final java.lang.String WIDGET_TYPE_UNKNOWN = "unknown";
-    field public static final java.lang.String WIDGET_TYPE_UNSELECTABLE_TEXTVIEW = "nosel-textview";
-    field public static final java.lang.String WIDGET_TYPE_WEBVIEW = "webview";
+    field public static final String TYPE_ADDRESS = "address";
+    field public static final String TYPE_DATE = "date";
+    field public static final String TYPE_DATE_TIME = "datetime";
+    field public static final String TYPE_EMAIL = "email";
+    field public static final String TYPE_FLIGHT_NUMBER = "flight";
+    field public static final String TYPE_OTHER = "other";
+    field public static final String TYPE_PHONE = "phone";
+    field public static final String TYPE_UNKNOWN = "";
+    field public static final String TYPE_URL = "url";
+    field public static final String WIDGET_TYPE_CUSTOM_EDITTEXT = "customedit";
+    field public static final String WIDGET_TYPE_CUSTOM_TEXTVIEW = "customview";
+    field public static final String WIDGET_TYPE_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
+    field public static final String WIDGET_TYPE_EDITTEXT = "edittext";
+    field public static final String WIDGET_TYPE_EDIT_WEBVIEW = "edit-webview";
+    field public static final String WIDGET_TYPE_NOTIFICATION = "notification";
+    field public static final String WIDGET_TYPE_TEXTVIEW = "textview";
+    field public static final String WIDGET_TYPE_UNKNOWN = "unknown";
+    field public static final String WIDGET_TYPE_UNSELECTABLE_TEXTVIEW = "nosel-textview";
+    field public static final String WIDGET_TYPE_WEBVIEW = "webview";
   }
 
   public static final class TextClassifier.EntityConfig implements android.os.Parcelable {
-    method public static android.view.textclassifier.TextClassifier.EntityConfig create(java.util.Collection<java.lang.String>, java.util.Collection<java.lang.String>, java.util.Collection<java.lang.String>);
-    method public static android.view.textclassifier.TextClassifier.EntityConfig createWithExplicitEntityList(java.util.Collection<java.lang.String>);
-    method public static android.view.textclassifier.TextClassifier.EntityConfig createWithHints(java.util.Collection<java.lang.String>);
+    method @Deprecated public static android.view.textclassifier.TextClassifier.EntityConfig create(@Nullable java.util.Collection<java.lang.String>, @Nullable java.util.Collection<java.lang.String>, @Nullable java.util.Collection<java.lang.String>);
+    method @Deprecated public static android.view.textclassifier.TextClassifier.EntityConfig createWithExplicitEntityList(@Nullable java.util.Collection<java.lang.String>);
+    method @Deprecated public static android.view.textclassifier.TextClassifier.EntityConfig createWithHints(@Nullable java.util.Collection<java.lang.String>);
     method public int describeContents();
     method public java.util.Collection<java.lang.String> getHints();
-    method public java.util.Collection<java.lang.String> resolveEntityListModifications(java.util.Collection<java.lang.String>);
+    method public java.util.Collection<java.lang.String> resolveEntityListModifications(@NonNull java.util.Collection<java.lang.String>);
+    method public boolean shouldIncludeTypesFromTextClassifier();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifier.EntityConfig> CREATOR;
   }
 
+  public static final class TextClassifier.EntityConfig.Builder {
+    ctor public TextClassifier.EntityConfig.Builder();
+    method @NonNull public android.view.textclassifier.TextClassifier.EntityConfig build();
+    method @NonNull public android.view.textclassifier.TextClassifier.EntityConfig.Builder includeTypesFromTextClassifier(boolean);
+    method @NonNull public android.view.textclassifier.TextClassifier.EntityConfig.Builder setExcludedTypes(@Nullable java.util.Collection<java.lang.String>);
+    method public android.view.textclassifier.TextClassifier.EntityConfig.Builder setHints(java.util.Collection<java.lang.String>);
+    method @NonNull public android.view.textclassifier.TextClassifier.EntityConfig.Builder setIncludedTypes(@Nullable java.util.Collection<java.lang.String>);
+  }
+
   public final class TextClassifierEvent implements android.os.Parcelable {
     method public int describeContents();
-    method public int[] getActionIndices();
-    method public java.lang.String getEntityType();
+    method @NonNull public int[] getActionIndices();
+    method @Nullable public String getEntityType();
     method public int getEventCategory();
-    method public android.view.textclassifier.TextClassificationContext getEventContext();
+    method @Nullable public android.view.textclassifier.TextClassificationContext getEventContext();
     method public int getEventIndex();
     method public long getEventTime();
     method public int getEventType();
-    method public android.os.Bundle getExtras();
-    method public java.lang.String getLanguage();
+    method @NonNull public android.os.Bundle getExtras();
+    method @Nullable public String getLanguage();
     method public int getRelativeSuggestedWordEndIndex();
     method public int getRelativeSuggestedWordStartIndex();
     method public int getRelativeWordEndIndex();
     method public int getRelativeWordStartIndex();
-    method public java.lang.String getResultId();
+    method @Nullable public String getResultId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CATEGORY_CONVERSATION_ACTIONS = 3; // 0x3
     field public static final int CATEGORY_LANGUAGE_DETECTION = 4; // 0x4
@@ -53073,6 +53502,7 @@
     field public static final int CATEGORY_SELECTION = 1; // 0x1
     field public static final int CATEGORY_UNDEFINED = 0; // 0x0
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent> CREATOR;
+    field public static final int TYPE_ACTIONS_GENERATED = 20; // 0x14
     field public static final int TYPE_ACTIONS_SHOWN = 6; // 0x6
     field public static final int TYPE_AUTO_SELECTION = 5; // 0x5
     field public static final int TYPE_COPY_ACTION = 9; // 0x9
@@ -53097,60 +53527,60 @@
 
   public static final class TextClassifierEvent.Builder {
     ctor public TextClassifierEvent.Builder(int, int);
-    method public android.view.textclassifier.TextClassifierEvent build();
-    method public android.view.textclassifier.TextClassifierEvent.Builder setActionIndices(int...);
-    method public android.view.textclassifier.TextClassifierEvent.Builder setEntityType(java.lang.String);
-    method public android.view.textclassifier.TextClassifierEvent.Builder setEventContext(android.view.textclassifier.TextClassificationContext);
-    method public android.view.textclassifier.TextClassifierEvent.Builder setEventIndex(int);
-    method public android.view.textclassifier.TextClassifierEvent.Builder setEventTime(long);
-    method public android.view.textclassifier.TextClassifierEvent.Builder setExtras(android.os.Bundle);
-    method public android.view.textclassifier.TextClassifierEvent.Builder setLanguage(java.lang.String);
-    method public android.view.textclassifier.TextClassifierEvent.Builder setRelativeSuggestedWordEndIndex(int);
-    method public android.view.textclassifier.TextClassifierEvent.Builder setRelativeSuggestedWordStartIndex(int);
-    method public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordEndIndex(int);
-    method public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordStartIndex(int);
-    method public android.view.textclassifier.TextClassifierEvent.Builder setResultId(java.lang.String);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent build();
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setActionIndices(@NonNull int...);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEntityType(@Nullable String);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventContext(@Nullable android.view.textclassifier.TextClassificationContext);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventIndex(int);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventTime(long);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setExtras(@NonNull android.os.Bundle);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setLanguage(@Nullable String);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeSuggestedWordEndIndex(int);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeSuggestedWordStartIndex(int);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordEndIndex(int);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordStartIndex(int);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setResultId(@Nullable String);
   }
 
   public final class TextLanguage implements android.os.Parcelable {
     method public int describeContents();
-    method public float getConfidenceScore(android.icu.util.ULocale);
-    method public android.os.Bundle getExtras();
-    method public java.lang.String getId();
-    method public android.icu.util.ULocale getLocale(int);
-    method public int getLocaleHypothesisCount();
+    method @FloatRange(from=0.0, to=1.0) public float getConfidenceScore(@NonNull android.icu.util.ULocale);
+    method @NonNull public android.os.Bundle getExtras();
+    method @Nullable public String getId();
+    method @NonNull public android.icu.util.ULocale getLocale(int);
+    method @IntRange(from=0) public int getLocaleHypothesisCount();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextLanguage> CREATOR;
   }
 
   public static final class TextLanguage.Builder {
     ctor public TextLanguage.Builder();
-    method public android.view.textclassifier.TextLanguage build();
-    method public android.view.textclassifier.TextLanguage.Builder putLocale(android.icu.util.ULocale, float);
-    method public android.view.textclassifier.TextLanguage.Builder setExtras(android.os.Bundle);
-    method public android.view.textclassifier.TextLanguage.Builder setId(java.lang.String);
+    method @NonNull public android.view.textclassifier.TextLanguage build();
+    method @NonNull public android.view.textclassifier.TextLanguage.Builder putLocale(@NonNull android.icu.util.ULocale, @FloatRange(from=0.0, to=1.0) float);
+    method @NonNull public android.view.textclassifier.TextLanguage.Builder setExtras(@NonNull android.os.Bundle);
+    method @NonNull public android.view.textclassifier.TextLanguage.Builder setId(@Nullable String);
   }
 
   public static final class TextLanguage.Request implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getCallingPackageName();
-    method public android.os.Bundle getExtras();
-    method public java.lang.CharSequence getText();
+    method @Nullable public String getCallingPackageName();
+    method @NonNull public android.os.Bundle getExtras();
+    method @NonNull public CharSequence getText();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextLanguage.Request> CREATOR;
   }
 
   public static final class TextLanguage.Request.Builder {
-    ctor public TextLanguage.Request.Builder(java.lang.CharSequence);
-    method public android.view.textclassifier.TextLanguage.Request build();
-    method public android.view.textclassifier.TextLanguage.Request.Builder setExtras(android.os.Bundle);
+    ctor public TextLanguage.Request.Builder(@NonNull CharSequence);
+    method @NonNull public android.view.textclassifier.TextLanguage.Request build();
+    method @NonNull public android.view.textclassifier.TextLanguage.Request.Builder setExtras(@NonNull android.os.Bundle);
   }
 
   public final class TextLinks implements android.os.Parcelable {
-    method public int apply(android.text.Spannable, int, java.util.function.Function<android.view.textclassifier.TextLinks.TextLink, android.view.textclassifier.TextLinks.TextLinkSpan>);
+    method public int apply(@NonNull android.text.Spannable, int, @Nullable java.util.function.Function<android.view.textclassifier.TextLinks.TextLink,android.view.textclassifier.TextLinks.TextLinkSpan>);
     method public int describeContents();
-    method public android.os.Bundle getExtras();
-    method public java.util.Collection<android.view.textclassifier.TextLinks.TextLink> getLinks();
+    method @NonNull public android.os.Bundle getExtras();
+    method @NonNull public java.util.Collection<android.view.textclassifier.TextLinks.TextLink> getLinks();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int APPLY_STRATEGY_IGNORE = 0; // 0x0
     field public static final int APPLY_STRATEGY_REPLACE = 1; // 0x1
@@ -53163,38 +53593,38 @@
   }
 
   public static final class TextLinks.Builder {
-    ctor public TextLinks.Builder(java.lang.String);
-    method public android.view.textclassifier.TextLinks.Builder addLink(int, int, java.util.Map<java.lang.String, java.lang.Float>);
-    method public android.view.textclassifier.TextLinks.Builder addLink(int, int, java.util.Map<java.lang.String, java.lang.Float>, android.os.Bundle);
-    method public android.view.textclassifier.TextLinks build();
-    method public android.view.textclassifier.TextLinks.Builder clearTextLinks();
-    method public android.view.textclassifier.TextLinks.Builder setExtras(android.os.Bundle);
+    ctor public TextLinks.Builder(@NonNull String);
+    method @NonNull public android.view.textclassifier.TextLinks.Builder addLink(int, int, @NonNull java.util.Map<java.lang.String,java.lang.Float>);
+    method @NonNull public android.view.textclassifier.TextLinks.Builder addLink(int, int, @NonNull java.util.Map<java.lang.String,java.lang.Float>, @NonNull android.os.Bundle);
+    method @NonNull public android.view.textclassifier.TextLinks build();
+    method @NonNull public android.view.textclassifier.TextLinks.Builder clearTextLinks();
+    method public android.view.textclassifier.TextLinks.Builder setExtras(@Nullable android.os.Bundle);
   }
 
   public static final class TextLinks.Request implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getCallingPackageName();
-    method public android.os.LocaleList getDefaultLocales();
-    method public android.view.textclassifier.TextClassifier.EntityConfig getEntityConfig();
-    method public android.os.Bundle getExtras();
-    method public java.lang.CharSequence getText();
+    method @Nullable public String getCallingPackageName();
+    method @Nullable public android.os.LocaleList getDefaultLocales();
+    method @Nullable public android.view.textclassifier.TextClassifier.EntityConfig getEntityConfig();
+    method @NonNull public android.os.Bundle getExtras();
+    method @NonNull public CharSequence getText();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextLinks.Request> CREATOR;
   }
 
   public static final class TextLinks.Request.Builder {
-    ctor public TextLinks.Request.Builder(java.lang.CharSequence);
-    method public android.view.textclassifier.TextLinks.Request build();
-    method public android.view.textclassifier.TextLinks.Request.Builder setDefaultLocales(android.os.LocaleList);
-    method public android.view.textclassifier.TextLinks.Request.Builder setEntityConfig(android.view.textclassifier.TextClassifier.EntityConfig);
-    method public android.view.textclassifier.TextLinks.Request.Builder setExtras(android.os.Bundle);
+    ctor public TextLinks.Request.Builder(@NonNull CharSequence);
+    method @NonNull public android.view.textclassifier.TextLinks.Request build();
+    method @NonNull public android.view.textclassifier.TextLinks.Request.Builder setDefaultLocales(@Nullable android.os.LocaleList);
+    method @NonNull public android.view.textclassifier.TextLinks.Request.Builder setEntityConfig(@Nullable android.view.textclassifier.TextClassifier.EntityConfig);
+    method public android.view.textclassifier.TextLinks.Request.Builder setExtras(@Nullable android.os.Bundle);
   }
 
   public static final class TextLinks.TextLink implements android.os.Parcelable {
     method public int describeContents();
-    method public float getConfidenceScore(java.lang.String);
+    method @FloatRange(from=0.0, to=1.0) public float getConfidenceScore(String);
     method public int getEnd();
-    method public java.lang.String getEntity(int);
+    method @NonNull public String getEntity(int);
     method public int getEntityCount();
     method public android.os.Bundle getExtras();
     method public int getStart();
@@ -53203,18 +53633,18 @@
   }
 
   public static class TextLinks.TextLinkSpan extends android.text.style.ClickableSpan {
-    ctor public TextLinks.TextLinkSpan(android.view.textclassifier.TextLinks.TextLink);
+    ctor public TextLinks.TextLinkSpan(@NonNull android.view.textclassifier.TextLinks.TextLink);
     method public final android.view.textclassifier.TextLinks.TextLink getTextLink();
     method public void onClick(android.view.View);
   }
 
   public final class TextSelection implements android.os.Parcelable {
     method public int describeContents();
-    method public float getConfidenceScore(java.lang.String);
-    method public java.lang.String getEntity(int);
-    method public int getEntityCount();
-    method public android.os.Bundle getExtras();
-    method public java.lang.String getId();
+    method @FloatRange(from=0.0, to=1.0) public float getConfidenceScore(String);
+    method @NonNull public String getEntity(int);
+    method @IntRange(from=0) public int getEntityCount();
+    method @NonNull public android.os.Bundle getExtras();
+    method @Nullable public String getId();
     method public int getSelectionEndIndex();
     method public int getSelectionStartIndex();
     method public void writeToParcel(android.os.Parcel, int);
@@ -53222,30 +53652,30 @@
   }
 
   public static final class TextSelection.Builder {
-    ctor public TextSelection.Builder(int, int);
-    method public android.view.textclassifier.TextSelection build();
-    method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
-    method public android.view.textclassifier.TextSelection.Builder setExtras(android.os.Bundle);
-    method public android.view.textclassifier.TextSelection.Builder setId(java.lang.String);
+    ctor public TextSelection.Builder(@IntRange(from=0) int, @IntRange(from=0) int);
+    method @NonNull public android.view.textclassifier.TextSelection build();
+    method @NonNull public android.view.textclassifier.TextSelection.Builder setEntityType(@NonNull String, @FloatRange(from=0.0, to=1.0) float);
+    method public android.view.textclassifier.TextSelection.Builder setExtras(@Nullable android.os.Bundle);
+    method @NonNull public android.view.textclassifier.TextSelection.Builder setId(@Nullable String);
   }
 
   public static final class TextSelection.Request implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getCallingPackageName();
-    method public android.os.LocaleList getDefaultLocales();
-    method public int getEndIndex();
-    method public android.os.Bundle getExtras();
-    method public int getStartIndex();
-    method public java.lang.CharSequence getText();
+    method @Nullable public String getCallingPackageName();
+    method @Nullable public android.os.LocaleList getDefaultLocales();
+    method @IntRange(from=0) public int getEndIndex();
+    method @NonNull public android.os.Bundle getExtras();
+    method @IntRange(from=0) public int getStartIndex();
+    method @NonNull public CharSequence getText();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextSelection.Request> CREATOR;
   }
 
   public static final class TextSelection.Request.Builder {
-    ctor public TextSelection.Request.Builder(java.lang.CharSequence, int, int);
-    method public android.view.textclassifier.TextSelection.Request build();
-    method public android.view.textclassifier.TextSelection.Request.Builder setDefaultLocales(android.os.LocaleList);
-    method public android.view.textclassifier.TextSelection.Request.Builder setExtras(android.os.Bundle);
+    ctor public TextSelection.Request.Builder(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int);
+    method @NonNull public android.view.textclassifier.TextSelection.Request build();
+    method @NonNull public android.view.textclassifier.TextSelection.Request.Builder setDefaultLocales(@Nullable android.os.LocaleList);
+    method public android.view.textclassifier.TextSelection.Request.Builder setExtras(@Nullable android.os.Bundle);
   }
 
 }
@@ -53267,14 +53697,14 @@
   public final class SpellCheckerInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.content.ComponentName getComponent();
-    method public java.lang.String getId();
-    method public java.lang.String getPackageName();
+    method public String getId();
+    method public String getPackageName();
     method public android.content.pm.ServiceInfo getServiceInfo();
-    method public java.lang.String getSettingsActivity();
+    method public String getSettingsActivity();
     method public android.view.textservice.SpellCheckerSubtype getSubtypeAt(int);
     method public int getSubtypeCount();
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
-    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
+    method public CharSequence loadLabel(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textservice.SpellCheckerInfo> CREATOR;
   }
@@ -53284,39 +53714,39 @@
     method public void close();
     method public void getSentenceSuggestions(android.view.textservice.TextInfo[], int);
     method public android.view.textservice.SpellCheckerInfo getSpellChecker();
-    method public deprecated void getSuggestions(android.view.textservice.TextInfo, int);
-    method public deprecated void getSuggestions(android.view.textservice.TextInfo[], int, boolean);
+    method @Deprecated public void getSuggestions(android.view.textservice.TextInfo, int);
+    method @Deprecated public void getSuggestions(android.view.textservice.TextInfo[], int, boolean);
     method public boolean isSessionDisconnected();
-    field public static final java.lang.String SERVICE_META_DATA = "android.view.textservice.scs";
+    field public static final String SERVICE_META_DATA = "android.view.textservice.scs";
   }
 
-  public static abstract interface SpellCheckerSession.SpellCheckerSessionListener {
-    method public abstract void onGetSentenceSuggestions(android.view.textservice.SentenceSuggestionsInfo[]);
-    method public abstract void onGetSuggestions(android.view.textservice.SuggestionsInfo[]);
+  public static interface SpellCheckerSession.SpellCheckerSessionListener {
+    method public void onGetSentenceSuggestions(android.view.textservice.SentenceSuggestionsInfo[]);
+    method public void onGetSuggestions(android.view.textservice.SuggestionsInfo[]);
   }
 
   public final class SpellCheckerSubtype implements android.os.Parcelable {
-    ctor public deprecated SpellCheckerSubtype(int, java.lang.String, java.lang.String);
-    method public boolean containsExtraValueKey(java.lang.String);
+    ctor @Deprecated public SpellCheckerSubtype(int, String, String);
+    method public boolean containsExtraValueKey(String);
     method public int describeContents();
-    method public java.lang.CharSequence getDisplayName(android.content.Context, java.lang.String, android.content.pm.ApplicationInfo);
-    method public java.lang.String getExtraValue();
-    method public java.lang.String getExtraValueOf(java.lang.String);
-    method public java.lang.String getLanguageTag();
-    method public deprecated java.lang.String getLocale();
+    method public CharSequence getDisplayName(android.content.Context, String, android.content.pm.ApplicationInfo);
+    method public String getExtraValue();
+    method public String getExtraValueOf(String);
+    method @NonNull public String getLanguageTag();
+    method @Deprecated @NonNull public String getLocale();
     method public int getNameResId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textservice.SpellCheckerSubtype> CREATOR;
   }
 
   public final class SuggestionsInfo implements android.os.Parcelable {
-    ctor public SuggestionsInfo(int, java.lang.String[]);
-    ctor public SuggestionsInfo(int, java.lang.String[], int, int);
+    ctor public SuggestionsInfo(int, String[]);
+    ctor public SuggestionsInfo(int, String[], int, int);
     ctor public SuggestionsInfo(android.os.Parcel);
     method public int describeContents();
     method public int getCookie();
     method public int getSequence();
-    method public java.lang.String getSuggestionAt(int);
+    method public String getSuggestionAt(int);
     method public int getSuggestionsAttributes();
     method public int getSuggestionsCount();
     method public void setCookieAndSequence(int, int);
@@ -53328,15 +53758,15 @@
   }
 
   public final class TextInfo implements android.os.Parcelable {
-    ctor public TextInfo(java.lang.String);
-    ctor public TextInfo(java.lang.String, int, int);
-    ctor public TextInfo(java.lang.CharSequence, int, int, int, int);
+    ctor public TextInfo(String);
+    ctor public TextInfo(String, int, int);
+    ctor public TextInfo(CharSequence, int, int, int, int);
     ctor public TextInfo(android.os.Parcel);
     method public int describeContents();
-    method public java.lang.CharSequence getCharSequence();
+    method public CharSequence getCharSequence();
     method public int getCookie();
     method public int getSequence();
-    method public java.lang.String getText();
+    method public String getText();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textservice.TextInfo> CREATOR;
   }
@@ -53352,25 +53782,23 @@
   public abstract class ClientCertRequest {
     ctor public ClientCertRequest();
     method public abstract void cancel();
-    method public abstract java.lang.String getHost();
-    method public abstract java.lang.String[] getKeyTypes();
+    method public abstract String getHost();
+    method @Nullable public abstract String[] getKeyTypes();
     method public abstract int getPort();
-    method public abstract java.security.Principal[] getPrincipals();
+    method @Nullable public abstract java.security.Principal[] getPrincipals();
     method public abstract void ignore();
     method public abstract void proceed(java.security.PrivateKey, java.security.cert.X509Certificate[]);
   }
 
   public class ConsoleMessage {
-    ctor public ConsoleMessage(java.lang.String, java.lang.String, int, android.webkit.ConsoleMessage.MessageLevel);
+    ctor public ConsoleMessage(String, String, int, android.webkit.ConsoleMessage.MessageLevel);
     method public int lineNumber();
-    method public java.lang.String message();
+    method public String message();
     method public android.webkit.ConsoleMessage.MessageLevel messageLevel();
-    method public java.lang.String sourceId();
+    method public String sourceId();
   }
 
-  public static final class ConsoleMessage.MessageLevel extends java.lang.Enum {
-    method public static android.webkit.ConsoleMessage.MessageLevel valueOf(java.lang.String);
-    method public static final android.webkit.ConsoleMessage.MessageLevel[] values();
+  public enum ConsoleMessage.MessageLevel {
     enum_constant public static final android.webkit.ConsoleMessage.MessageLevel DEBUG;
     enum_constant public static final android.webkit.ConsoleMessage.MessageLevel ERROR;
     enum_constant public static final android.webkit.ConsoleMessage.MessageLevel LOG;
@@ -53379,72 +53807,73 @@
   }
 
   public abstract class CookieManager {
-    ctor public deprecated CookieManager();
+    ctor @Deprecated public CookieManager();
     method public abstract boolean acceptCookie();
     method public abstract boolean acceptThirdPartyCookies(android.webkit.WebView);
     method public static boolean allowFileSchemeCookies();
     method public abstract void flush();
-    method public abstract java.lang.String getCookie(java.lang.String);
+    method public abstract String getCookie(String);
     method public static android.webkit.CookieManager getInstance();
     method public abstract boolean hasCookies();
-    method public abstract deprecated void removeAllCookie();
-    method public abstract void removeAllCookies(android.webkit.ValueCallback<java.lang.Boolean>);
-    method public abstract deprecated void removeExpiredCookie();
-    method public abstract deprecated void removeSessionCookie();
-    method public abstract void removeSessionCookies(android.webkit.ValueCallback<java.lang.Boolean>);
+    method @Deprecated public abstract void removeAllCookie();
+    method public abstract void removeAllCookies(@Nullable android.webkit.ValueCallback<java.lang.Boolean>);
+    method @Deprecated public abstract void removeExpiredCookie();
+    method @Deprecated public abstract void removeSessionCookie();
+    method public abstract void removeSessionCookies(@Nullable android.webkit.ValueCallback<java.lang.Boolean>);
     method public abstract void setAcceptCookie(boolean);
     method public static void setAcceptFileSchemeCookies(boolean);
     method public abstract void setAcceptThirdPartyCookies(android.webkit.WebView, boolean);
-    method public abstract void setCookie(java.lang.String, java.lang.String);
-    method public abstract void setCookie(java.lang.String, java.lang.String, android.webkit.ValueCallback<java.lang.Boolean>);
+    method public abstract void setCookie(String, String);
+    method public abstract void setCookie(String, String, @Nullable android.webkit.ValueCallback<java.lang.Boolean>);
   }
 
-  public final deprecated class CookieSyncManager implements java.lang.Runnable {
-    method public static android.webkit.CookieSyncManager createInstance(android.content.Context);
-    method public static android.webkit.CookieSyncManager getInstance();
-    method public deprecated void resetSync();
-    method public deprecated void startSync();
-    method public deprecated void stopSync();
-    method public deprecated void sync();
-    method protected deprecated void syncFromRamToFlash();
+  @Deprecated public final class CookieSyncManager implements java.lang.Runnable {
+    method @Deprecated public static android.webkit.CookieSyncManager createInstance(android.content.Context);
+    method @Deprecated public static android.webkit.CookieSyncManager getInstance();
+    method @Deprecated public void resetSync();
+    method @Deprecated public void run();
+    method @Deprecated public void startSync();
+    method @Deprecated public void stopSync();
+    method @Deprecated public void sync();
+    method @Deprecated protected void syncFromRamToFlash();
   }
 
   public class DateSorter {
     ctor public DateSorter(android.content.Context);
     method public long getBoundary(int);
     method public int getIndex(long);
-    method public java.lang.String getLabel(int);
+    method public String getLabel(int);
     field public static final int DAY_COUNT = 5; // 0x5
   }
 
-  public abstract interface DownloadListener {
-    method public abstract void onDownloadStart(java.lang.String, java.lang.String, java.lang.String, java.lang.String, long);
+  public interface DownloadListener {
+    method public void onDownloadStart(String, String, String, String, long);
   }
 
   public class GeolocationPermissions {
-    method public void allow(java.lang.String);
-    method public void clear(java.lang.String);
+    method public void allow(String);
+    method public void clear(String);
     method public void clearAll();
-    method public void getAllowed(java.lang.String, android.webkit.ValueCallback<java.lang.Boolean>);
+    method public void getAllowed(String, android.webkit.ValueCallback<java.lang.Boolean>);
     method public static android.webkit.GeolocationPermissions getInstance();
     method public void getOrigins(android.webkit.ValueCallback<java.util.Set<java.lang.String>>);
   }
 
-  public static abstract interface GeolocationPermissions.Callback {
-    method public abstract void invoke(java.lang.String, boolean, boolean);
+  public static interface GeolocationPermissions.Callback {
+    method public void invoke(String, boolean, boolean);
   }
 
   public class HttpAuthHandler extends android.os.Handler {
     method public void cancel();
-    method public void proceed(java.lang.String, java.lang.String);
+    method public void proceed(String, String);
     method public boolean useHttpAuthUsernamePassword();
   }
 
-  public abstract class JavascriptInterface implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface JavascriptInterface {
   }
 
   public class JsPromptResult extends android.webkit.JsResult {
-    method public void confirm(java.lang.String);
+    method public void confirm(String);
   }
 
   public class JsResult {
@@ -53453,39 +53882,39 @@
   }
 
   public class MimeTypeMap {
-    method public java.lang.String getExtensionFromMimeType(java.lang.String);
-    method public static java.lang.String getFileExtensionFromUrl(java.lang.String);
-    method public java.lang.String getMimeTypeFromExtension(java.lang.String);
+    method @Nullable public String getExtensionFromMimeType(String);
+    method public static String getFileExtensionFromUrl(String);
+    method @Nullable public String getMimeTypeFromExtension(String);
     method public static android.webkit.MimeTypeMap getSingleton();
-    method public boolean hasExtension(java.lang.String);
-    method public boolean hasMimeType(java.lang.String);
+    method public boolean hasExtension(String);
+    method public boolean hasMimeType(String);
   }
 
   public abstract class PermissionRequest {
     ctor public PermissionRequest();
     method public abstract void deny();
     method public abstract android.net.Uri getOrigin();
-    method public abstract java.lang.String[] getResources();
-    method public abstract void grant(java.lang.String[]);
-    field public static final java.lang.String RESOURCE_AUDIO_CAPTURE = "android.webkit.resource.AUDIO_CAPTURE";
-    field public static final java.lang.String RESOURCE_MIDI_SYSEX = "android.webkit.resource.MIDI_SYSEX";
-    field public static final java.lang.String RESOURCE_PROTECTED_MEDIA_ID = "android.webkit.resource.PROTECTED_MEDIA_ID";
-    field public static final java.lang.String RESOURCE_VIDEO_CAPTURE = "android.webkit.resource.VIDEO_CAPTURE";
+    method public abstract String[] getResources();
+    method public abstract void grant(String[]);
+    field public static final String RESOURCE_AUDIO_CAPTURE = "android.webkit.resource.AUDIO_CAPTURE";
+    field public static final String RESOURCE_MIDI_SYSEX = "android.webkit.resource.MIDI_SYSEX";
+    field public static final String RESOURCE_PROTECTED_MEDIA_ID = "android.webkit.resource.PROTECTED_MEDIA_ID";
+    field public static final String RESOURCE_VIDEO_CAPTURE = "android.webkit.resource.VIDEO_CAPTURE";
   }
 
-  public abstract interface PluginStub {
-    method public abstract android.view.View getEmbeddedView(int, android.content.Context);
-    method public abstract android.view.View getFullScreenView(int, android.content.Context);
+  public interface PluginStub {
+    method public android.view.View getEmbeddedView(int, android.content.Context);
+    method public android.view.View getFullScreenView(int, android.content.Context);
   }
 
   public abstract class RenderProcessGoneDetail {
-    ctor public deprecated RenderProcessGoneDetail();
+    ctor @Deprecated public RenderProcessGoneDetail();
     method public abstract boolean didCrash();
     method public abstract int rendererPriorityAtExit();
   }
 
   public abstract class SafeBrowsingResponse {
-    ctor public deprecated SafeBrowsingResponse();
+    ctor @Deprecated public SafeBrowsingResponse();
     method public abstract void backToSafety(boolean);
     method public abstract void proceed(boolean);
     method public abstract void showInterstitial(boolean);
@@ -53493,14 +53922,14 @@
 
   public class ServiceWorkerClient {
     ctor public ServiceWorkerClient();
-    method public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebResourceRequest);
+    method @Nullable public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebResourceRequest);
   }
 
   public abstract class 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);
+    ctor @Deprecated public ServiceWorkerController();
+    method @NonNull public static android.webkit.ServiceWorkerController getInstance();
+    method @NonNull public abstract android.webkit.ServiceWorkerWebSettings getServiceWorkerWebSettings();
+    method public abstract void setServiceWorkerClient(@Nullable android.webkit.ServiceWorkerClient);
   }
 
   public abstract class ServiceWorkerWebSettings {
@@ -53521,7 +53950,7 @@
   }
 
   public class TracingConfig {
-    method public java.util.List<java.lang.String> getCustomIncludedCategories();
+    method @NonNull public java.util.List<java.lang.String> getCustomIncludedCategories();
     method public int getPredefinedCategories();
     method public int getTracingMode();
     field public static final int CATEGORIES_ALL = 1; // 0x1
@@ -53546,90 +53975,90 @@
   }
 
   public abstract class TracingController {
-    ctor public deprecated TracingController();
-    method public static android.webkit.TracingController getInstance();
+    ctor @Deprecated public TracingController();
+    method @NonNull public static android.webkit.TracingController getInstance();
     method public abstract boolean isTracing();
-    method public abstract void start(android.webkit.TracingConfig);
-    method public abstract boolean stop(java.io.OutputStream, java.util.concurrent.Executor);
+    method public abstract void start(@NonNull android.webkit.TracingConfig);
+    method public abstract boolean stop(@Nullable java.io.OutputStream, @NonNull java.util.concurrent.Executor);
   }
 
   public final class URLUtil {
     ctor public URLUtil();
-    method public static java.lang.String composeSearchUrl(java.lang.String, java.lang.String, java.lang.String);
+    method public static String composeSearchUrl(String, String, String);
     method public static byte[] decode(byte[]) throws java.lang.IllegalArgumentException;
-    method public static java.lang.String guessFileName(java.lang.String, java.lang.String, java.lang.String);
-    method public static java.lang.String guessUrl(java.lang.String);
-    method public static boolean isAboutUrl(java.lang.String);
-    method public static boolean isAssetUrl(java.lang.String);
-    method public static boolean isContentUrl(java.lang.String);
-    method public static deprecated boolean isCookielessProxyUrl(java.lang.String);
-    method public static boolean isDataUrl(java.lang.String);
-    method public static boolean isFileUrl(java.lang.String);
-    method public static boolean isHttpUrl(java.lang.String);
-    method public static boolean isHttpsUrl(java.lang.String);
-    method public static boolean isJavaScriptUrl(java.lang.String);
-    method public static boolean isNetworkUrl(java.lang.String);
-    method public static boolean isValidUrl(java.lang.String);
-    method public static java.lang.String stripAnchor(java.lang.String);
+    method public static String guessFileName(String, @Nullable String, @Nullable String);
+    method public static String guessUrl(String);
+    method public static boolean isAboutUrl(String);
+    method public static boolean isAssetUrl(String);
+    method public static boolean isContentUrl(String);
+    method @Deprecated public static boolean isCookielessProxyUrl(String);
+    method public static boolean isDataUrl(String);
+    method public static boolean isFileUrl(String);
+    method public static boolean isHttpUrl(String);
+    method public static boolean isHttpsUrl(String);
+    method public static boolean isJavaScriptUrl(String);
+    method public static boolean isNetworkUrl(String);
+    method public static boolean isValidUrl(String);
+    method public static String stripAnchor(String);
   }
 
-  public abstract interface ValueCallback<T> {
-    method public abstract void onReceiveValue(T);
+  public interface ValueCallback<T> {
+    method public void onReceiveValue(T);
   }
 
   public abstract class WebBackForwardList implements java.lang.Cloneable java.io.Serializable {
     ctor public WebBackForwardList();
     method protected abstract android.webkit.WebBackForwardList clone();
     method public abstract int getCurrentIndex();
-    method public abstract android.webkit.WebHistoryItem getCurrentItem();
+    method @Nullable public abstract android.webkit.WebHistoryItem getCurrentItem();
     method public abstract android.webkit.WebHistoryItem getItemAtIndex(int);
     method public abstract int getSize();
   }
 
   public class WebChromeClient {
     ctor public WebChromeClient();
-    method public android.graphics.Bitmap getDefaultVideoPoster();
-    method public android.view.View getVideoLoadingProgressView();
+    method @Nullable public android.graphics.Bitmap getDefaultVideoPoster();
+    method @Nullable public android.view.View getVideoLoadingProgressView();
     method public void getVisitedHistory(android.webkit.ValueCallback<java.lang.String[]>);
     method public void onCloseWindow(android.webkit.WebView);
-    method public deprecated void onConsoleMessage(java.lang.String, int, java.lang.String);
+    method @Deprecated public void onConsoleMessage(String, int, String);
     method public boolean onConsoleMessage(android.webkit.ConsoleMessage);
     method public boolean onCreateWindow(android.webkit.WebView, boolean, boolean, android.os.Message);
-    method public deprecated void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
+    method @Deprecated public void onExceededDatabaseQuota(String, String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
     method public void onGeolocationPermissionsHidePrompt();
-    method public void onGeolocationPermissionsShowPrompt(java.lang.String, android.webkit.GeolocationPermissions.Callback);
+    method public void onGeolocationPermissionsShowPrompt(String, android.webkit.GeolocationPermissions.Callback);
     method public void onHideCustomView();
-    method public boolean onJsAlert(android.webkit.WebView, java.lang.String, java.lang.String, android.webkit.JsResult);
-    method public boolean onJsBeforeUnload(android.webkit.WebView, java.lang.String, java.lang.String, android.webkit.JsResult);
-    method public boolean onJsConfirm(android.webkit.WebView, java.lang.String, java.lang.String, android.webkit.JsResult);
-    method public boolean onJsPrompt(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String, android.webkit.JsPromptResult);
-    method public deprecated boolean onJsTimeout();
+    method public boolean onJsAlert(android.webkit.WebView, String, String, android.webkit.JsResult);
+    method public boolean onJsBeforeUnload(android.webkit.WebView, String, String, android.webkit.JsResult);
+    method public boolean onJsConfirm(android.webkit.WebView, String, String, android.webkit.JsResult);
+    method public boolean onJsPrompt(android.webkit.WebView, String, String, String, android.webkit.JsPromptResult);
+    method @Deprecated public boolean onJsTimeout();
     method public void onPermissionRequest(android.webkit.PermissionRequest);
     method public void onPermissionRequestCanceled(android.webkit.PermissionRequest);
     method public void onProgressChanged(android.webkit.WebView, int);
-    method public deprecated void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
+    method @Deprecated public void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
     method public void onReceivedIcon(android.webkit.WebView, android.graphics.Bitmap);
-    method public void onReceivedTitle(android.webkit.WebView, java.lang.String);
-    method public void onReceivedTouchIconUrl(android.webkit.WebView, java.lang.String, boolean);
+    method public void onReceivedTitle(android.webkit.WebView, String);
+    method public void onReceivedTouchIconUrl(android.webkit.WebView, String, boolean);
     method public void onRequestFocus(android.webkit.WebView);
     method public void onShowCustomView(android.view.View, android.webkit.WebChromeClient.CustomViewCallback);
-    method public deprecated void onShowCustomView(android.view.View, int, android.webkit.WebChromeClient.CustomViewCallback);
+    method @Deprecated public void onShowCustomView(android.view.View, int, android.webkit.WebChromeClient.CustomViewCallback);
     method public boolean onShowFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams);
   }
 
-  public static abstract interface WebChromeClient.CustomViewCallback {
-    method public abstract void onCustomViewHidden();
+  public static interface WebChromeClient.CustomViewCallback {
+    method public void onCustomViewHidden();
   }
 
-  public static abstract class WebChromeClient.FileChooserParams {
+  public abstract static class WebChromeClient.FileChooserParams {
     ctor public WebChromeClient.FileChooserParams();
     method public abstract android.content.Intent createIntent();
-    method public abstract java.lang.String[] getAcceptTypes();
-    method public abstract java.lang.String getFilenameHint();
+    method public abstract String[] getAcceptTypes();
+    method @Nullable public abstract String getFilenameHint();
     method public abstract int getMode();
-    method public abstract java.lang.CharSequence getTitle();
+    method @Nullable public abstract CharSequence getTitle();
     method public abstract boolean isCaptureEnabled();
-    method public static android.net.Uri[] parseResult(int, android.content.Intent);
+    method @Nullable public static android.net.Uri[] parseResult(int, android.content.Intent);
     field public static final int MODE_OPEN = 0; // 0x0
     field public static final int MODE_OPEN_MULTIPLE = 1; // 0x1
     field public static final int MODE_SAVE = 3; // 0x3
@@ -53638,32 +54067,32 @@
   public abstract class WebHistoryItem implements java.lang.Cloneable {
     ctor public WebHistoryItem();
     method protected abstract android.webkit.WebHistoryItem clone();
-    method public abstract android.graphics.Bitmap getFavicon();
-    method public abstract java.lang.String getOriginalUrl();
-    method public abstract java.lang.String getTitle();
-    method public abstract java.lang.String getUrl();
+    method @Nullable public abstract android.graphics.Bitmap getFavicon();
+    method public abstract String getOriginalUrl();
+    method public abstract String getTitle();
+    method public abstract String getUrl();
   }
 
-  public abstract deprecated class WebIconDatabase {
-    ctor public WebIconDatabase();
-    method public abstract void close();
-    method public static android.webkit.WebIconDatabase getInstance();
-    method public abstract void open(java.lang.String);
-    method public abstract void releaseIconForPageUrl(java.lang.String);
-    method public abstract void removeAllIcons();
-    method public abstract void requestIconForPageUrl(java.lang.String, android.webkit.WebIconDatabase.IconListener);
-    method public abstract void retainIconForPageUrl(java.lang.String);
+  @Deprecated public abstract class WebIconDatabase {
+    ctor @Deprecated public WebIconDatabase();
+    method @Deprecated public abstract void close();
+    method @Deprecated public static android.webkit.WebIconDatabase getInstance();
+    method @Deprecated public abstract void open(String);
+    method @Deprecated public abstract void releaseIconForPageUrl(String);
+    method @Deprecated public abstract void removeAllIcons();
+    method @Deprecated public abstract void requestIconForPageUrl(String, android.webkit.WebIconDatabase.IconListener);
+    method @Deprecated public abstract void retainIconForPageUrl(String);
   }
 
-  public static abstract deprecated interface WebIconDatabase.IconListener {
-    method public abstract void onReceivedIcon(java.lang.String, android.graphics.Bitmap);
+  @Deprecated public static interface WebIconDatabase.IconListener {
+    method @Deprecated public void onReceivedIcon(String, android.graphics.Bitmap);
   }
 
   public class WebMessage {
-    ctor public WebMessage(java.lang.String);
-    ctor public WebMessage(java.lang.String, android.webkit.WebMessagePort[]);
-    method public java.lang.String getData();
-    method public android.webkit.WebMessagePort[] getPorts();
+    ctor public WebMessage(String);
+    ctor public WebMessage(String, android.webkit.WebMessagePort[]);
+    method public String getData();
+    method @Nullable public android.webkit.WebMessagePort[] getPorts();
   }
 
   public abstract class WebMessagePort {
@@ -53673,44 +54102,44 @@
     method public abstract void setWebMessageCallback(android.webkit.WebMessagePort.WebMessageCallback, android.os.Handler);
   }
 
-  public static abstract class WebMessagePort.WebMessageCallback {
+  public abstract static class WebMessagePort.WebMessageCallback {
     ctor public WebMessagePort.WebMessageCallback();
     method public void onMessage(android.webkit.WebMessagePort, android.webkit.WebMessage);
   }
 
   public abstract class WebResourceError {
-    method public abstract java.lang.CharSequence getDescription();
+    method public abstract CharSequence getDescription();
     method public abstract int getErrorCode();
   }
 
-  public abstract interface WebResourceRequest {
-    method public abstract java.lang.String getMethod();
-    method public abstract java.util.Map<java.lang.String, java.lang.String> getRequestHeaders();
-    method public abstract android.net.Uri getUrl();
-    method public abstract boolean hasGesture();
-    method public abstract boolean isForMainFrame();
-    method public abstract boolean isRedirect();
+  public interface WebResourceRequest {
+    method public String getMethod();
+    method public java.util.Map<java.lang.String,java.lang.String> getRequestHeaders();
+    method public android.net.Uri getUrl();
+    method public boolean hasGesture();
+    method public boolean isForMainFrame();
+    method public boolean isRedirect();
   }
 
   public class WebResourceResponse {
-    ctor public WebResourceResponse(java.lang.String, java.lang.String, java.io.InputStream);
-    ctor public WebResourceResponse(java.lang.String, java.lang.String, int, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.io.InputStream);
+    ctor public WebResourceResponse(String, String, java.io.InputStream);
+    ctor public WebResourceResponse(String, String, int, @NonNull String, java.util.Map<java.lang.String,java.lang.String>, java.io.InputStream);
     method public java.io.InputStream getData();
-    method public java.lang.String getEncoding();
-    method public java.lang.String getMimeType();
-    method public java.lang.String getReasonPhrase();
-    method public java.util.Map<java.lang.String, java.lang.String> getResponseHeaders();
+    method public String getEncoding();
+    method public String getMimeType();
+    method public String getReasonPhrase();
+    method public java.util.Map<java.lang.String,java.lang.String> getResponseHeaders();
     method public int getStatusCode();
     method public void setData(java.io.InputStream);
-    method public void setEncoding(java.lang.String);
-    method public void setMimeType(java.lang.String);
-    method public void setResponseHeaders(java.util.Map<java.lang.String, java.lang.String>);
-    method public void setStatusCodeAndReasonPhrase(int, java.lang.String);
+    method public void setEncoding(String);
+    method public void setMimeType(String);
+    method public void setResponseHeaders(java.util.Map<java.lang.String,java.lang.String>);
+    method public void setStatusCodeAndReasonPhrase(int, @NonNull String);
   }
 
   public abstract class WebSettings {
     ctor public WebSettings();
-    method public abstract deprecated boolean enableSmoothTransition();
+    method @Deprecated public abstract boolean enableSmoothTransition();
     method public abstract boolean getAllowContentAccess();
     method public abstract boolean getAllowFileAccess();
     method public abstract boolean getAllowFileAccessFromFileURLs();
@@ -53719,24 +54148,24 @@
     method public abstract boolean getBlockNetworkLoads();
     method public abstract boolean getBuiltInZoomControls();
     method public abstract int getCacheMode();
-    method public abstract java.lang.String getCursiveFontFamily();
+    method public abstract String getCursiveFontFamily();
     method public abstract boolean getDatabaseEnabled();
-    method public abstract deprecated java.lang.String getDatabasePath();
+    method @Deprecated public abstract String getDatabasePath();
     method public abstract int getDefaultFixedFontSize();
     method public abstract int getDefaultFontSize();
-    method public abstract java.lang.String getDefaultTextEncodingName();
-    method public static java.lang.String getDefaultUserAgent(android.content.Context);
-    method public abstract deprecated android.webkit.WebSettings.ZoomDensity getDefaultZoom();
+    method public abstract String getDefaultTextEncodingName();
+    method public static String getDefaultUserAgent(android.content.Context);
+    method @Deprecated public abstract android.webkit.WebSettings.ZoomDensity getDefaultZoom();
     method public abstract int getDisabledActionModeMenuItems();
     method public abstract boolean getDisplayZoomControls();
     method public abstract boolean getDomStorageEnabled();
-    method public abstract java.lang.String getFantasyFontFamily();
-    method public abstract java.lang.String getFixedFontFamily();
+    method public abstract String getFantasyFontFamily();
+    method public abstract String getFixedFontFamily();
     method public int getForceDarkMode();
     method public abstract boolean getJavaScriptCanOpenWindowsAutomatically();
     method public abstract boolean getJavaScriptEnabled();
     method public abstract android.webkit.WebSettings.LayoutAlgorithm getLayoutAlgorithm();
-    method public abstract deprecated boolean getLightTouchEnabled();
+    method @Deprecated public abstract boolean getLightTouchEnabled();
     method public abstract boolean getLoadWithOverviewMode();
     method public abstract boolean getLoadsImagesAutomatically();
     method public abstract boolean getMediaPlaybackRequiresUserGesture();
@@ -53744,48 +54173,48 @@
     method public abstract int getMinimumLogicalFontSize();
     method public abstract int getMixedContentMode();
     method public abstract boolean getOffscreenPreRaster();
-    method public abstract deprecated android.webkit.WebSettings.PluginState getPluginState();
+    method @Deprecated public abstract android.webkit.WebSettings.PluginState getPluginState();
     method public abstract boolean getSafeBrowsingEnabled();
-    method public abstract java.lang.String getSansSerifFontFamily();
-    method public abstract deprecated boolean getSaveFormData();
-    method public abstract deprecated boolean getSavePassword();
-    method public abstract java.lang.String getSerifFontFamily();
-    method public abstract java.lang.String getStandardFontFamily();
-    method public deprecated synchronized android.webkit.WebSettings.TextSize getTextSize();
+    method public abstract String getSansSerifFontFamily();
+    method @Deprecated public abstract boolean getSaveFormData();
+    method @Deprecated public abstract boolean getSavePassword();
+    method public abstract String getSerifFontFamily();
+    method public abstract String getStandardFontFamily();
+    method @Deprecated public android.webkit.WebSettings.TextSize getTextSize();
     method public abstract int getTextZoom();
     method public abstract boolean getUseWideViewPort();
-    method public abstract java.lang.String getUserAgentString();
+    method public abstract String getUserAgentString();
     method public abstract void setAllowContentAccess(boolean);
     method public abstract void setAllowFileAccess(boolean);
     method public abstract void setAllowFileAccessFromFileURLs(boolean);
     method public abstract void setAllowUniversalAccessFromFileURLs(boolean);
     method public abstract void setAppCacheEnabled(boolean);
-    method public abstract deprecated void setAppCacheMaxSize(long);
-    method public abstract void setAppCachePath(java.lang.String);
+    method @Deprecated public abstract void setAppCacheMaxSize(long);
+    method public abstract void setAppCachePath(String);
     method public abstract void setBlockNetworkImage(boolean);
     method public abstract void setBlockNetworkLoads(boolean);
     method public abstract void setBuiltInZoomControls(boolean);
     method public abstract void setCacheMode(int);
-    method public abstract void setCursiveFontFamily(java.lang.String);
+    method public abstract void setCursiveFontFamily(String);
     method public abstract void setDatabaseEnabled(boolean);
-    method public abstract deprecated void setDatabasePath(java.lang.String);
+    method @Deprecated public abstract void setDatabasePath(String);
     method public abstract void setDefaultFixedFontSize(int);
     method public abstract void setDefaultFontSize(int);
-    method public abstract void setDefaultTextEncodingName(java.lang.String);
-    method public abstract deprecated void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
+    method public abstract void setDefaultTextEncodingName(String);
+    method @Deprecated public abstract void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
     method public abstract void setDisabledActionModeMenuItems(int);
     method public abstract void setDisplayZoomControls(boolean);
     method public abstract void setDomStorageEnabled(boolean);
-    method public abstract deprecated void setEnableSmoothTransition(boolean);
-    method public abstract void setFantasyFontFamily(java.lang.String);
-    method public abstract void setFixedFontFamily(java.lang.String);
+    method @Deprecated public abstract void setEnableSmoothTransition(boolean);
+    method public abstract void setFantasyFontFamily(String);
+    method public abstract void setFixedFontFamily(String);
     method public void setForceDarkMode(int);
-    method public abstract deprecated void setGeolocationDatabasePath(java.lang.String);
+    method @Deprecated public abstract void setGeolocationDatabasePath(String);
     method public abstract void setGeolocationEnabled(boolean);
     method public abstract void setJavaScriptCanOpenWindowsAutomatically(boolean);
     method public abstract void setJavaScriptEnabled(boolean);
     method public abstract void setLayoutAlgorithm(android.webkit.WebSettings.LayoutAlgorithm);
-    method public abstract deprecated void setLightTouchEnabled(boolean);
+    method @Deprecated public abstract void setLightTouchEnabled(boolean);
     method public abstract void setLoadWithOverviewMode(boolean);
     method public abstract void setLoadsImagesAutomatically(boolean);
     method public abstract void setMediaPlaybackRequiresUserGesture(boolean);
@@ -53794,20 +54223,20 @@
     method public abstract void setMixedContentMode(int);
     method public abstract void setNeedInitialFocus(boolean);
     method public abstract void setOffscreenPreRaster(boolean);
-    method public abstract deprecated void setPluginState(android.webkit.WebSettings.PluginState);
-    method public abstract deprecated void setRenderPriority(android.webkit.WebSettings.RenderPriority);
+    method @Deprecated public abstract void setPluginState(android.webkit.WebSettings.PluginState);
+    method @Deprecated public abstract void setRenderPriority(android.webkit.WebSettings.RenderPriority);
     method public abstract void setSafeBrowsingEnabled(boolean);
-    method public abstract void setSansSerifFontFamily(java.lang.String);
-    method public abstract deprecated void setSaveFormData(boolean);
-    method public abstract deprecated void setSavePassword(boolean);
-    method public abstract void setSerifFontFamily(java.lang.String);
-    method public abstract void setStandardFontFamily(java.lang.String);
+    method public abstract void setSansSerifFontFamily(String);
+    method @Deprecated public abstract void setSaveFormData(boolean);
+    method @Deprecated public abstract void setSavePassword(boolean);
+    method public abstract void setSerifFontFamily(String);
+    method public abstract void setStandardFontFamily(String);
     method public abstract void setSupportMultipleWindows(boolean);
     method public abstract void setSupportZoom(boolean);
-    method public deprecated synchronized void setTextSize(android.webkit.WebSettings.TextSize);
+    method @Deprecated public void setTextSize(android.webkit.WebSettings.TextSize);
     method public abstract void setTextZoom(int);
     method public abstract void setUseWideViewPort(boolean);
-    method public abstract void setUserAgentString(java.lang.String);
+    method public abstract void setUserAgentString(@Nullable String);
     method public abstract boolean supportMultipleWindows();
     method public abstract boolean supportZoom();
     field public static final int FORCE_DARK_AUTO = 0; // 0x0
@@ -53816,7 +54245,7 @@
     field public static final int LOAD_CACHE_ELSE_NETWORK = 1; // 0x1
     field public static final int LOAD_CACHE_ONLY = 3; // 0x3
     field public static final int LOAD_DEFAULT = -1; // 0xffffffff
-    field public static final deprecated int LOAD_NORMAL = 0; // 0x0
+    field @Deprecated public static final int LOAD_NORMAL = 0; // 0x0
     field public static final int LOAD_NO_CACHE = 2; // 0x2
     field public static final int MENU_ITEM_NONE = 0; // 0x0
     field public static final int MENU_ITEM_PROCESS_TEXT = 4; // 0x4
@@ -53827,44 +54256,34 @@
     field public static final int MIXED_CONTENT_NEVER_ALLOW = 1; // 0x1
   }
 
-  public static final class WebSettings.LayoutAlgorithm extends java.lang.Enum {
-    method public static android.webkit.WebSettings.LayoutAlgorithm valueOf(java.lang.String);
-    method public static final android.webkit.WebSettings.LayoutAlgorithm[] values();
-    enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
+  public enum WebSettings.LayoutAlgorithm {
+    enum_constant @Deprecated public static final android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
     enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NORMAL;
-    enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm SINGLE_COLUMN;
+    enum_constant @Deprecated public static final android.webkit.WebSettings.LayoutAlgorithm SINGLE_COLUMN;
     enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm TEXT_AUTOSIZING;
   }
 
-  public static final class WebSettings.PluginState extends java.lang.Enum {
-    method public static android.webkit.WebSettings.PluginState valueOf(java.lang.String);
-    method public static final android.webkit.WebSettings.PluginState[] values();
+  public enum WebSettings.PluginState {
     enum_constant public static final android.webkit.WebSettings.PluginState OFF;
     enum_constant public static final android.webkit.WebSettings.PluginState ON;
     enum_constant public static final android.webkit.WebSettings.PluginState ON_DEMAND;
   }
 
-  public static final class WebSettings.RenderPriority extends java.lang.Enum {
-    method public static android.webkit.WebSettings.RenderPriority valueOf(java.lang.String);
-    method public static final android.webkit.WebSettings.RenderPriority[] values();
+  public enum WebSettings.RenderPriority {
     enum_constant public static final android.webkit.WebSettings.RenderPriority HIGH;
     enum_constant public static final android.webkit.WebSettings.RenderPriority LOW;
     enum_constant public static final android.webkit.WebSettings.RenderPriority NORMAL;
   }
 
-  public static final deprecated class WebSettings.TextSize extends java.lang.Enum {
-    method public static android.webkit.WebSettings.TextSize valueOf(java.lang.String);
-    method public static final android.webkit.WebSettings.TextSize[] values();
-    enum_constant public static final android.webkit.WebSettings.TextSize LARGER;
-    enum_constant public static final android.webkit.WebSettings.TextSize LARGEST;
-    enum_constant public static final android.webkit.WebSettings.TextSize NORMAL;
-    enum_constant public static final android.webkit.WebSettings.TextSize SMALLER;
-    enum_constant public static final android.webkit.WebSettings.TextSize SMALLEST;
+  @Deprecated public enum WebSettings.TextSize {
+    enum_constant @Deprecated public static final android.webkit.WebSettings.TextSize LARGER;
+    enum_constant @Deprecated public static final android.webkit.WebSettings.TextSize LARGEST;
+    enum_constant @Deprecated public static final android.webkit.WebSettings.TextSize NORMAL;
+    enum_constant @Deprecated public static final android.webkit.WebSettings.TextSize SMALLER;
+    enum_constant @Deprecated public static final android.webkit.WebSettings.TextSize SMALLEST;
   }
 
-  public static final class WebSettings.ZoomDensity extends java.lang.Enum {
-    method public static android.webkit.WebSettings.ZoomDensity valueOf(java.lang.String);
-    method public static final android.webkit.WebSettings.ZoomDensity[] values();
+  public enum WebSettings.ZoomDensity {
     enum_constant public static final android.webkit.WebSettings.ZoomDensity CLOSE;
     enum_constant public static final android.webkit.WebSettings.ZoomDensity FAR;
     enum_constant public static final android.webkit.WebSettings.ZoomDensity MEDIUM;
@@ -53872,22 +54291,22 @@
 
   public class WebStorage {
     method public void deleteAllData();
-    method public void deleteOrigin(java.lang.String);
+    method public void deleteOrigin(String);
     method public static android.webkit.WebStorage getInstance();
     method public void getOrigins(android.webkit.ValueCallback<java.util.Map>);
-    method public void getQuotaForOrigin(java.lang.String, android.webkit.ValueCallback<java.lang.Long>);
-    method public void getUsageForOrigin(java.lang.String, android.webkit.ValueCallback<java.lang.Long>);
-    method public deprecated void setQuotaForOrigin(java.lang.String, long);
+    method public void getQuotaForOrigin(String, android.webkit.ValueCallback<java.lang.Long>);
+    method public void getUsageForOrigin(String, android.webkit.ValueCallback<java.lang.Long>);
+    method @Deprecated public void setQuotaForOrigin(String, long);
   }
 
   public static class WebStorage.Origin {
-    method public java.lang.String getOrigin();
+    method public String getOrigin();
     method public long getQuota();
     method public long getUsage();
   }
 
-  public static abstract deprecated interface WebStorage.QuotaUpdater {
-    method public abstract void updateQuota(long);
+  @Deprecated public static interface WebStorage.QuotaUpdater {
+    method @Deprecated public void updateQuota(long);
   }
 
   public class WebView extends android.widget.AbsoluteLayout implements android.view.ViewGroup.OnHierarchyChangeListener android.view.ViewTreeObserver.OnGlobalFocusChangeListener {
@@ -53895,108 +54314,112 @@
     ctor public WebView(android.content.Context, android.util.AttributeSet);
     ctor public WebView(android.content.Context, android.util.AttributeSet, int);
     ctor public WebView(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public deprecated WebView(android.content.Context, android.util.AttributeSet, int, boolean);
-    method public void addJavascriptInterface(java.lang.Object, java.lang.String);
+    ctor @Deprecated public WebView(android.content.Context, android.util.AttributeSet, int, boolean);
+    method public void addJavascriptInterface(Object, String);
     method public boolean canGoBack();
     method public boolean canGoBackOrForward(int);
     method public boolean canGoForward();
-    method public deprecated boolean canZoomIn();
-    method public deprecated boolean canZoomOut();
-    method public deprecated android.graphics.Picture capturePicture();
+    method @Deprecated public boolean canZoomIn();
+    method @Deprecated public boolean canZoomOut();
+    method @Deprecated public android.graphics.Picture capturePicture();
     method public void clearCache(boolean);
-    method public static void clearClientCertPreferences(java.lang.Runnable);
+    method public static void clearClientCertPreferences(@Nullable Runnable);
     method public void clearFormData();
     method public void clearHistory();
     method public void clearMatches();
     method public void clearSslPreferences();
-    method public deprecated void clearView();
+    method @Deprecated public void clearView();
     method public android.webkit.WebBackForwardList copyBackForwardList();
-    method public deprecated android.print.PrintDocumentAdapter createPrintDocumentAdapter();
-    method public android.print.PrintDocumentAdapter createPrintDocumentAdapter(java.lang.String);
+    method @Deprecated public android.print.PrintDocumentAdapter createPrintDocumentAdapter();
+    method public android.print.PrintDocumentAdapter createPrintDocumentAdapter(String);
     method public android.webkit.WebMessagePort[] createWebMessageChannel();
     method public void destroy();
     method public static void disableWebView();
     method public void documentHasImages(android.os.Message);
     method public static void enableSlowWholeDocumentDraw();
-    method public void evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>);
-    method public static deprecated java.lang.String findAddress(java.lang.String);
-    method public deprecated int findAll(java.lang.String);
-    method public void findAllAsync(java.lang.String);
+    method public void evaluateJavascript(String, @Nullable android.webkit.ValueCallback<java.lang.String>);
+    method @Deprecated @Nullable public static String findAddress(String);
+    method @Deprecated public int findAll(String);
+    method public void findAllAsync(String);
     method public void findNext(boolean);
     method public void flingScroll(int, int);
-    method public deprecated void freeMemory();
-    method public android.net.http.SslCertificate getCertificate();
-    method public int getContentHeight();
-    method public static android.content.pm.PackageInfo getCurrentWebViewPackage();
+    method @Deprecated public void freeMemory();
+    method @Nullable public android.net.http.SslCertificate getCertificate();
+    method @android.view.ViewDebug.ExportedProperty(category="webview") public int getContentHeight();
+    method @Nullable public static android.content.pm.PackageInfo getCurrentWebViewPackage();
     method public android.graphics.Bitmap getFavicon();
     method public android.webkit.WebView.HitTestResult getHitTestResult();
-    method public deprecated java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
-    method public java.lang.String getOriginalUrl();
+    method @Deprecated @Nullable public String[] getHttpAuthUsernamePassword(String, String);
+    method @android.view.ViewDebug.ExportedProperty(category="webview") public String getOriginalUrl();
     method public int getProgress();
     method public boolean getRendererPriorityWaivedWhenNotVisible();
     method public int getRendererRequestedPriority();
-    method public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
-    method public deprecated float getScale();
+    method @NonNull public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
+    method @Deprecated @android.view.ViewDebug.ExportedProperty(category="webview") public float getScale();
     method public android.webkit.WebSettings getSettings();
-    method public android.view.textclassifier.TextClassifier getTextClassifier();
-    method public java.lang.String getTitle();
-    method public java.lang.String getUrl();
-    method public android.webkit.WebChromeClient getWebChromeClient();
-    method public static java.lang.ClassLoader getWebViewClassLoader();
+    method @NonNull public android.view.textclassifier.TextClassifier getTextClassifier();
+    method @android.view.ViewDebug.ExportedProperty(category="webview") public String getTitle();
+    method @android.view.ViewDebug.ExportedProperty(category="webview") public String getUrl();
+    method @Nullable public android.webkit.WebChromeClient getWebChromeClient();
+    method @NonNull public static ClassLoader getWebViewClassLoader();
     method public android.webkit.WebViewClient getWebViewClient();
-    method public android.os.Looper getWebViewLooper();
+    method @NonNull public android.os.Looper getWebViewLooper();
+    method @Nullable public android.webkit.WebViewRenderer getWebViewRenderer();
+    method @Nullable public android.webkit.WebViewRendererClient getWebViewRendererClient();
     method public void goBack();
     method public void goBackOrForward(int);
     method public void goForward();
     method public void invokeZoomPicker();
     method public boolean isPrivateBrowsingEnabled();
-    method public void loadData(java.lang.String, java.lang.String, java.lang.String);
-    method public void loadDataWithBaseURL(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public void loadUrl(java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
-    method public void loadUrl(java.lang.String);
-    method public deprecated void onChildViewAdded(android.view.View, android.view.View);
-    method public deprecated void onChildViewRemoved(android.view.View, android.view.View);
-    method public deprecated void onGlobalFocusChanged(android.view.View, android.view.View);
+    method public void loadData(String, @Nullable String, @Nullable String);
+    method public void loadDataWithBaseURL(@Nullable String, String, @Nullable String, @Nullable String, @Nullable String);
+    method public void loadUrl(String, java.util.Map<java.lang.String,java.lang.String>);
+    method public void loadUrl(String);
+    method @Deprecated public void onChildViewAdded(android.view.View, android.view.View);
+    method @Deprecated public void onChildViewRemoved(android.view.View, android.view.View);
+    method @Deprecated public void onGlobalFocusChanged(android.view.View, android.view.View);
     method public void onPause();
     method public void onResume();
-    method public deprecated boolean overlayHorizontalScrollbar();
-    method public deprecated boolean overlayVerticalScrollbar();
+    method @Deprecated public boolean overlayHorizontalScrollbar();
+    method @Deprecated public boolean overlayVerticalScrollbar();
     method public boolean pageDown(boolean);
     method public boolean pageUp(boolean);
     method public void pauseTimers();
-    method public void postUrl(java.lang.String, byte[]);
+    method public void postUrl(String, byte[]);
     method public void postVisualStateCallback(long, android.webkit.WebView.VisualStateCallback);
     method public void postWebMessage(android.webkit.WebMessage, android.net.Uri);
     method public void reload();
-    method public void removeJavascriptInterface(java.lang.String);
-    method public void requestFocusNodeHref(android.os.Message);
+    method public void removeJavascriptInterface(@NonNull String);
+    method public void requestFocusNodeHref(@Nullable android.os.Message);
     method public void requestImageRef(android.os.Message);
-    method public android.webkit.WebBackForwardList restoreState(android.os.Bundle);
+    method @Nullable public android.webkit.WebBackForwardList restoreState(android.os.Bundle);
     method public void resumeTimers();
-    method public deprecated void savePassword(java.lang.String, java.lang.String, java.lang.String);
-    method public android.webkit.WebBackForwardList saveState(android.os.Bundle);
-    method public void saveWebArchive(java.lang.String);
-    method public void saveWebArchive(java.lang.String, boolean, android.webkit.ValueCallback<java.lang.String>);
-    method public deprecated void setCertificate(android.net.http.SslCertificate);
-    method public static void setDataDirectorySuffix(java.lang.String);
+    method @Deprecated public void savePassword(String, String, String);
+    method @Nullable public android.webkit.WebBackForwardList saveState(android.os.Bundle);
+    method public void saveWebArchive(String);
+    method public void saveWebArchive(String, boolean, @Nullable android.webkit.ValueCallback<java.lang.String>);
+    method @Deprecated public void setCertificate(android.net.http.SslCertificate);
+    method public static void setDataDirectorySuffix(String);
     method public void setDownloadListener(android.webkit.DownloadListener);
     method public void setFindListener(android.webkit.WebView.FindListener);
-    method public deprecated void setHorizontalScrollbarOverlay(boolean);
-    method public deprecated void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method @Deprecated public void setHorizontalScrollbarOverlay(boolean);
+    method @Deprecated public void setHttpAuthUsernamePassword(String, String, String, String);
     method public void setInitialScale(int);
-    method public deprecated void setMapTrackballToArrowKeys(boolean);
+    method @Deprecated public void setMapTrackballToArrowKeys(boolean);
     method public void setNetworkAvailable(boolean);
-    method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
+    method @Deprecated public void setPictureListener(android.webkit.WebView.PictureListener);
     method public void setRendererPriorityPolicy(int, boolean);
-    method public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
-    method public void setTextClassifier(android.view.textclassifier.TextClassifier);
-    method public deprecated void setVerticalScrollbarOverlay(boolean);
+    method public static void setSafeBrowsingWhitelist(@NonNull java.util.List<java.lang.String>, @Nullable android.webkit.ValueCallback<java.lang.Boolean>);
+    method public void setTextClassifier(@Nullable android.view.textclassifier.TextClassifier);
+    method @Deprecated public void setVerticalScrollbarOverlay(boolean);
     method public void setWebChromeClient(android.webkit.WebChromeClient);
     method public static void setWebContentsDebuggingEnabled(boolean);
     method public void setWebViewClient(android.webkit.WebViewClient);
-    method public deprecated boolean shouldDelayChildPressedState();
-    method public deprecated boolean showFindDialog(java.lang.String, boolean);
-    method public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
+    method public void setWebViewRendererClient(@NonNull java.util.concurrent.Executor, @NonNull android.webkit.WebViewRendererClient);
+    method public void setWebViewRendererClient(@Nullable android.webkit.WebViewRendererClient);
+    method @Deprecated public boolean shouldDelayChildPressedState();
+    method @Deprecated public boolean showFindDialog(@Nullable String, boolean);
+    method public static void startSafeBrowsing(@NonNull android.content.Context, @Nullable android.webkit.ValueCallback<java.lang.Boolean>);
     method public void stopLoading();
     method public void zoomBy(float);
     method public boolean zoomIn();
@@ -54004,23 +54427,23 @@
     field public static final int RENDERER_PRIORITY_BOUND = 1; // 0x1
     field public static final int RENDERER_PRIORITY_IMPORTANT = 2; // 0x2
     field public static final int RENDERER_PRIORITY_WAIVED = 0; // 0x0
-    field public static final java.lang.String SCHEME_GEO = "geo:0,0?q=";
-    field public static final java.lang.String SCHEME_MAILTO = "mailto:";
-    field public static final java.lang.String SCHEME_TEL = "tel:";
+    field public static final String SCHEME_GEO = "geo:0,0?q=";
+    field public static final String SCHEME_MAILTO = "mailto:";
+    field public static final String SCHEME_TEL = "tel:";
   }
 
-  public static abstract interface WebView.FindListener {
-    method public abstract void onFindResultReceived(int, int, boolean);
+  public static interface WebView.FindListener {
+    method public void onFindResultReceived(int, int, boolean);
   }
 
   public static class WebView.HitTestResult {
-    method public java.lang.String getExtra();
+    method @Nullable public String getExtra();
     method public int getType();
-    field public static final deprecated int ANCHOR_TYPE = 1; // 0x1
+    field @Deprecated public static final int ANCHOR_TYPE = 1; // 0x1
     field public static final int EDIT_TEXT_TYPE = 9; // 0x9
     field public static final int EMAIL_TYPE = 4; // 0x4
     field public static final int GEO_TYPE = 3; // 0x3
-    field public static final deprecated int IMAGE_ANCHOR_TYPE = 6; // 0x6
+    field @Deprecated public static final int IMAGE_ANCHOR_TYPE = 6; // 0x6
     field public static final int IMAGE_TYPE = 5; // 0x5
     field public static final int PHONE_TYPE = 2; // 0x2
     field public static final int SRC_ANCHOR_TYPE = 7; // 0x7
@@ -54028,45 +54451,45 @@
     field public static final int UNKNOWN_TYPE = 0; // 0x0
   }
 
-  public static abstract deprecated interface WebView.PictureListener {
-    method public abstract deprecated void onNewPicture(android.webkit.WebView, android.graphics.Picture);
+  @Deprecated public static interface WebView.PictureListener {
+    method @Deprecated public void onNewPicture(android.webkit.WebView, @Nullable android.graphics.Picture);
   }
 
-  public static abstract class WebView.VisualStateCallback {
+  public abstract static class WebView.VisualStateCallback {
     ctor public WebView.VisualStateCallback();
     method public abstract void onComplete(long);
   }
 
   public class WebView.WebViewTransport {
     ctor public WebView.WebViewTransport();
-    method public synchronized android.webkit.WebView getWebView();
-    method public synchronized void setWebView(android.webkit.WebView);
+    method public android.webkit.WebView getWebView();
+    method public void setWebView(android.webkit.WebView);
   }
 
   public class WebViewClient {
     ctor public WebViewClient();
-    method public void doUpdateVisitedHistory(android.webkit.WebView, java.lang.String, boolean);
+    method public void doUpdateVisitedHistory(android.webkit.WebView, String, boolean);
     method public void onFormResubmission(android.webkit.WebView, android.os.Message, android.os.Message);
-    method public void onLoadResource(android.webkit.WebView, java.lang.String);
-    method public void onPageCommitVisible(android.webkit.WebView, java.lang.String);
-    method public void onPageFinished(android.webkit.WebView, java.lang.String);
-    method public void onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
+    method public void onLoadResource(android.webkit.WebView, String);
+    method public void onPageCommitVisible(android.webkit.WebView, String);
+    method public void onPageFinished(android.webkit.WebView, String);
+    method public void onPageStarted(android.webkit.WebView, String, android.graphics.Bitmap);
     method public void onReceivedClientCertRequest(android.webkit.WebView, android.webkit.ClientCertRequest);
-    method public deprecated void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
+    method @Deprecated public void onReceivedError(android.webkit.WebView, int, String, String);
     method public void onReceivedError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceError);
-    method public void onReceivedHttpAuthRequest(android.webkit.WebView, android.webkit.HttpAuthHandler, java.lang.String, java.lang.String);
+    method public void onReceivedHttpAuthRequest(android.webkit.WebView, android.webkit.HttpAuthHandler, String, String);
     method public void onReceivedHttpError(android.webkit.WebView, android.webkit.WebResourceRequest, android.webkit.WebResourceResponse);
-    method public void onReceivedLoginRequest(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String);
+    method public void onReceivedLoginRequest(android.webkit.WebView, String, @Nullable String, String);
     method public void onReceivedSslError(android.webkit.WebView, android.webkit.SslErrorHandler, android.net.http.SslError);
     method public boolean onRenderProcessGone(android.webkit.WebView, android.webkit.RenderProcessGoneDetail);
     method public void onSafeBrowsingHit(android.webkit.WebView, android.webkit.WebResourceRequest, int, android.webkit.SafeBrowsingResponse);
     method public void onScaleChanged(android.webkit.WebView, float, float);
-    method public deprecated void onTooManyRedirects(android.webkit.WebView, android.os.Message, android.os.Message);
+    method @Deprecated public void onTooManyRedirects(android.webkit.WebView, android.os.Message, android.os.Message);
     method public void onUnhandledKeyEvent(android.webkit.WebView, android.view.KeyEvent);
-    method public deprecated android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView, java.lang.String);
-    method public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView, android.webkit.WebResourceRequest);
+    method @Deprecated @Nullable public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView, String);
+    method @Nullable public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView, android.webkit.WebResourceRequest);
     method public boolean shouldOverrideKeyEvent(android.webkit.WebView, android.view.KeyEvent);
-    method public deprecated boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
+    method @Deprecated public boolean shouldOverrideUrlLoading(android.webkit.WebView, String);
     method public boolean shouldOverrideUrlLoading(android.webkit.WebView, android.webkit.WebResourceRequest);
     field public static final int ERROR_AUTHENTICATION = -4; // 0xfffffffc
     field public static final int ERROR_BAD_URL = -12; // 0xfffffff4
@@ -54092,41 +54515,51 @@
   }
 
   public abstract class WebViewDatabase {
-    ctor public deprecated WebViewDatabase();
-    method public abstract deprecated void clearFormData();
+    ctor @Deprecated public WebViewDatabase();
+    method @Deprecated public abstract void clearFormData();
     method public abstract void clearHttpAuthUsernamePassword();
-    method public abstract deprecated void clearUsernamePassword();
-    method public abstract java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
+    method @Deprecated public abstract void clearUsernamePassword();
+    method @Nullable public abstract String[] getHttpAuthUsernamePassword(String, String);
     method public static android.webkit.WebViewDatabase getInstance(android.content.Context);
-    method public abstract deprecated boolean hasFormData();
+    method @Deprecated public abstract boolean hasFormData();
     method public abstract boolean hasHttpAuthUsernamePassword();
-    method public abstract deprecated boolean hasUsernamePassword();
-    method public abstract void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method @Deprecated public abstract boolean hasUsernamePassword();
+    method public abstract void setHttpAuthUsernamePassword(String, String, String, String);
   }
 
-  public deprecated class WebViewFragment extends android.app.Fragment {
-    ctor public WebViewFragment();
-    method public android.webkit.WebView getWebView();
+  @Deprecated public class WebViewFragment extends android.app.Fragment {
+    ctor @Deprecated public WebViewFragment();
+    method @Deprecated public android.webkit.WebView getWebView();
+  }
+
+  public abstract class WebViewRenderer {
+    method public abstract boolean terminate();
+  }
+
+  public abstract class WebViewRendererClient {
+    ctor public WebViewRendererClient();
+    method public abstract void onRendererResponsive(@NonNull android.webkit.WebView, @Nullable android.webkit.WebViewRenderer);
+    method public abstract void onRendererUnresponsive(@NonNull android.webkit.WebView, @Nullable android.webkit.WebViewRenderer);
   }
 
 }
 
 package android.widget {
 
-  public abstract class AbsListView extends android.widget.AdapterView implements android.widget.Filter.FilterListener android.text.TextWatcher android.view.ViewTreeObserver.OnGlobalLayoutListener android.view.ViewTreeObserver.OnTouchModeChangeListener {
+  public abstract class AbsListView extends android.widget.AdapterView<android.widget.ListAdapter> implements android.widget.Filter.FilterListener android.text.TextWatcher android.view.ViewTreeObserver.OnGlobalLayoutListener android.view.ViewTreeObserver.OnTouchModeChangeListener {
     ctor public AbsListView(android.content.Context);
     ctor public AbsListView(android.content.Context, android.util.AttributeSet);
     ctor public AbsListView(android.content.Context, android.util.AttributeSet, int);
     ctor public AbsListView(android.content.Context, android.util.AttributeSet, int, int);
     method public void afterTextChanged(android.text.Editable);
-    method public void beforeTextChanged(java.lang.CharSequence, int, int, int);
+    method public void beforeTextChanged(CharSequence, int, int, int);
     method public boolean canScrollList(int);
     method public void clearChoices();
     method public void clearTextFilter();
     method public void deferNotifyDataSetChanged();
     method public void fling(int);
     method public android.widget.AbsListView.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method public int getCacheColorHint();
+    method @android.view.ViewDebug.ExportedProperty(category="drawing") @ColorInt public int getCacheColorHint();
     method public int getCheckedItemCount();
     method public long[] getCheckedItemIds();
     method public int getCheckedItemPosition();
@@ -54136,21 +54569,21 @@
     method public int getListPaddingLeft();
     method public int getListPaddingRight();
     method public int getListPaddingTop();
-    method public android.view.View getSelectedView();
+    method @android.view.ViewDebug.ExportedProperty public android.view.View getSelectedView();
     method public android.graphics.drawable.Drawable getSelector();
-    method public java.lang.CharSequence getTextFilter();
+    method public CharSequence getTextFilter();
     method public int getTranscriptMode();
     method protected void handleDataChanged();
     method public boolean hasTextFilter();
     method public void invalidateViews();
     method public boolean isFastScrollAlwaysVisible();
-    method public boolean isFastScrollEnabled();
+    method @android.view.ViewDebug.ExportedProperty public boolean isFastScrollEnabled();
     method protected boolean isInFilterMode();
     method public boolean isItemChecked(int);
-    method public boolean isScrollingCacheEnabled();
-    method public boolean isSmoothScrollbarEnabled();
-    method public boolean isStackFromBottom();
-    method public boolean isTextFilterEnabled();
+    method @android.view.ViewDebug.ExportedProperty public boolean isScrollingCacheEnabled();
+    method @android.view.ViewDebug.ExportedProperty public boolean isSmoothScrollbarEnabled();
+    method @android.view.ViewDebug.ExportedProperty public boolean isStackFromBottom();
+    method @android.view.ViewDebug.ExportedProperty public boolean isTextFilterEnabled();
     method protected void layoutChildren();
     method public void onFilterComplete(int);
     method public void onGlobalLayout();
@@ -54159,20 +54592,20 @@
     method public void onRemoteAdapterDisconnected();
     method public void onRestoreInstanceState(android.os.Parcelable);
     method public android.os.Parcelable onSaveInstanceState();
-    method public void onTextChanged(java.lang.CharSequence, int, int, int);
+    method public void onTextChanged(CharSequence, int, int, int);
     method public void onTouchModeChanged(boolean);
     method public int pointToPosition(int, int);
     method public long pointToRowId(int, int);
     method public void reclaimViews(java.util.List<android.view.View>);
     method public void scrollListBy(int);
     method public void setAdapter(android.widget.ListAdapter);
-    method public void setCacheColorHint(int);
+    method public void setCacheColorHint(@ColorInt int);
     method public void setChoiceMode(int);
     method public void setDrawSelectorOnTop(boolean);
     method public void setFastScrollAlwaysVisible(boolean);
     method public void setFastScrollEnabled(boolean);
     method public void setFastScrollStyle(int);
-    method public void setFilterText(java.lang.String);
+    method public void setFilterText(String);
     method public void setFriction(float);
     method public void setItemChecked(int, boolean);
     method public void setMultiChoiceModeListener(android.widget.AbsListView.MultiChoiceModeListener);
@@ -54182,7 +54615,7 @@
     method public void setScrollIndicators(android.view.View, android.view.View);
     method public void setScrollingCacheEnabled(boolean);
     method public void setSelectionFromTop(int, int);
-    method public void setSelector(int);
+    method public void setSelector(@DrawableRes int);
     method public void setSelector(android.graphics.drawable.Drawable);
     method public void setSmoothScrollbarEnabled(boolean);
     method public void setStackFromBottom(boolean);
@@ -54194,7 +54627,7 @@
     method public void smoothScrollToPosition(int, int);
     method public void smoothScrollToPositionFromTop(int, int, int);
     method public void smoothScrollToPositionFromTop(int, int);
-    method public boolean verifyDrawable(android.graphics.drawable.Drawable);
+    method public boolean verifyDrawable(@NonNull android.graphics.drawable.Drawable);
     field public static final int CHOICE_MODE_MULTIPLE = 2; // 0x2
     field public static final int CHOICE_MODE_MULTIPLE_MODAL = 3; // 0x3
     field public static final int CHOICE_MODE_NONE = 0; // 0x0
@@ -54211,24 +54644,24 @@
     ctor public AbsListView.LayoutParams(android.view.ViewGroup.LayoutParams);
   }
 
-  public static abstract interface AbsListView.MultiChoiceModeListener implements android.view.ActionMode.Callback {
-    method public abstract void onItemCheckedStateChanged(android.view.ActionMode, int, long, boolean);
+  public static interface AbsListView.MultiChoiceModeListener extends android.view.ActionMode.Callback {
+    method public void onItemCheckedStateChanged(android.view.ActionMode, int, long, boolean);
   }
 
-  public static abstract interface AbsListView.OnScrollListener {
-    method public abstract void onScroll(android.widget.AbsListView, int, int, int);
-    method public abstract void onScrollStateChanged(android.widget.AbsListView, int);
+  public static interface AbsListView.OnScrollListener {
+    method public void onScroll(android.widget.AbsListView, int, int, int);
+    method public void onScrollStateChanged(android.widget.AbsListView, int);
     field public static final int SCROLL_STATE_FLING = 2; // 0x2
     field public static final int SCROLL_STATE_IDLE = 0; // 0x0
     field public static final int SCROLL_STATE_TOUCH_SCROLL = 1; // 0x1
   }
 
-  public static abstract interface AbsListView.RecyclerListener {
-    method public abstract void onMovedToScrapHeap(android.view.View);
+  public static interface AbsListView.RecyclerListener {
+    method public void onMovedToScrapHeap(android.view.View);
   }
 
-  public static abstract interface AbsListView.SelectionBoundsAdjuster {
-    method public abstract void adjustListItemSelectionBounds(android.graphics.Rect);
+  public static interface AbsListView.SelectionBoundsAdjuster {
+    method public void adjustListItemSelectionBounds(android.graphics.Rect);
   }
 
   public abstract class AbsSeekBar extends android.widget.ProgressBar {
@@ -54240,23 +54673,23 @@
     method public boolean getSplitTrack();
     method public android.graphics.drawable.Drawable getThumb();
     method public int getThumbOffset();
-    method public android.content.res.ColorStateList getThumbTintList();
-    method public android.graphics.PorterDuff.Mode getThumbTintMode();
+    method @Nullable public android.content.res.ColorStateList getThumbTintList();
+    method @Nullable public android.graphics.PorterDuff.Mode getThumbTintMode();
     method public android.graphics.drawable.Drawable getTickMark();
-    method public android.content.res.ColorStateList getTickMarkTintList();
-    method public android.graphics.PorterDuff.Mode getTickMarkTintMode();
+    method @Nullable public android.content.res.ColorStateList getTickMarkTintList();
+    method @Nullable public android.graphics.PorterDuff.Mode getTickMarkTintMode();
     method public void setKeyProgressIncrement(int);
     method public void setSplitTrack(boolean);
     method public void setThumb(android.graphics.drawable.Drawable);
     method public void setThumbOffset(int);
-    method public void setThumbTintList(android.content.res.ColorStateList);
-    method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
+    method public void setThumbTintList(@Nullable android.content.res.ColorStateList);
+    method public void setThumbTintMode(@Nullable android.graphics.PorterDuff.Mode);
     method public void setTickMark(android.graphics.drawable.Drawable);
-    method public void setTickMarkTintList(android.content.res.ColorStateList);
-    method public void setTickMarkTintMode(android.graphics.PorterDuff.Mode);
+    method public void setTickMarkTintList(@Nullable android.content.res.ColorStateList);
+    method public void setTickMarkTintMode(@Nullable android.graphics.PorterDuff.Mode);
   }
 
-  public abstract class AbsSpinner extends android.widget.AdapterView {
+  public abstract class AbsSpinner extends android.widget.AdapterView<android.widget.SpinnerAdapter> {
     ctor public AbsSpinner(android.content.Context);
     ctor public AbsSpinner(android.content.Context, android.util.AttributeSet);
     ctor public AbsSpinner(android.content.Context, android.util.AttributeSet, int);
@@ -54271,20 +54704,20 @@
     method public void setSelection(int);
   }
 
-  public deprecated class AbsoluteLayout extends android.view.ViewGroup {
-    ctor public AbsoluteLayout(android.content.Context);
-    ctor public AbsoluteLayout(android.content.Context, android.util.AttributeSet);
-    ctor public AbsoluteLayout(android.content.Context, android.util.AttributeSet, int);
-    ctor public AbsoluteLayout(android.content.Context, android.util.AttributeSet, int, int);
+  @Deprecated @android.widget.RemoteViews.RemoteView public class AbsoluteLayout extends android.view.ViewGroup {
+    ctor @Deprecated public AbsoluteLayout(android.content.Context);
+    ctor @Deprecated public AbsoluteLayout(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public AbsoluteLayout(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public AbsoluteLayout(android.content.Context, android.util.AttributeSet, int, int);
   }
 
-  public static class AbsoluteLayout.LayoutParams extends android.view.ViewGroup.LayoutParams {
-    ctor public AbsoluteLayout.LayoutParams(int, int, int, int);
-    ctor public AbsoluteLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public AbsoluteLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    method public java.lang.String debug(java.lang.String);
-    field public int x;
-    field public int y;
+  @Deprecated public static class AbsoluteLayout.LayoutParams extends android.view.ViewGroup.LayoutParams {
+    ctor @Deprecated public AbsoluteLayout.LayoutParams(int, int, int, int);
+    ctor @Deprecated public AbsoluteLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public AbsoluteLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    method @Deprecated public String debug(String);
+    field @Deprecated public int x;
+    field @Deprecated public int y;
   }
 
   public class ActionMenuView extends android.widget.LinearLayout {
@@ -54295,15 +54728,15 @@
     method public android.widget.ActionMenuView.LayoutParams generateLayoutParams(android.util.AttributeSet);
     method protected android.widget.ActionMenuView.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
     method public android.view.Menu getMenu();
-    method public android.graphics.drawable.Drawable getOverflowIcon();
+    method @Nullable public android.graphics.drawable.Drawable getOverflowIcon();
     method public int getPopupTheme();
     method public boolean hideOverflowMenu();
     method public boolean isOverflowMenuShowing();
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onDetachedFromWindow();
     method public void setOnMenuItemClickListener(android.widget.ActionMenuView.OnMenuItemClickListener);
-    method public void setOverflowIcon(android.graphics.drawable.Drawable);
-    method public void setPopupTheme(int);
+    method public void setOverflowIcon(@Nullable android.graphics.drawable.Drawable);
+    method public void setPopupTheme(@StyleRes int);
     method public boolean showOverflowMenu();
   }
 
@@ -54314,22 +54747,22 @@
     ctor public ActionMenuView.LayoutParams(int, int);
   }
 
-  public static abstract interface ActionMenuView.OnMenuItemClickListener {
-    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  public static interface ActionMenuView.OnMenuItemClickListener {
+    method public boolean onMenuItemClick(android.view.MenuItem);
   }
 
-  public abstract interface Adapter {
-    method public default java.lang.CharSequence[] getAutofillOptions();
-    method public abstract int getCount();
-    method public abstract java.lang.Object getItem(int);
-    method public abstract long getItemId(int);
-    method public abstract int getItemViewType(int);
-    method public abstract android.view.View getView(int, android.view.View, android.view.ViewGroup);
-    method public abstract int getViewTypeCount();
-    method public abstract boolean hasStableIds();
-    method public abstract boolean isEmpty();
-    method public abstract void registerDataSetObserver(android.database.DataSetObserver);
-    method public abstract void unregisterDataSetObserver(android.database.DataSetObserver);
+  public interface Adapter {
+    method @Nullable public default CharSequence[] getAutofillOptions();
+    method public int getCount();
+    method public Object getItem(int);
+    method public long getItemId(int);
+    method public int getItemViewType(int);
+    method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
+    method public int getViewTypeCount();
+    method public boolean hasStableIds();
+    method public boolean isEmpty();
+    method public void registerDataSetObserver(android.database.DataSetObserver);
+    method public void unregisterDataSetObserver(android.database.DataSetObserver);
     field public static final int IGNORE_ITEM_VIEW_TYPE = -1; // 0xffffffff
     field public static final int NO_SELECTION = -2147483648; // 0x80000000
   }
@@ -54340,26 +54773,26 @@
     ctor public AdapterView(android.content.Context, android.util.AttributeSet, int);
     ctor public AdapterView(android.content.Context, android.util.AttributeSet, int, int);
     method public abstract T getAdapter();
-    method public int getCount();
+    method @android.view.ViewDebug.CapturedViewProperty public int getCount();
     method public android.view.View getEmptyView();
     method public int getFirstVisiblePosition();
-    method public java.lang.Object getItemAtPosition(int);
+    method public Object getItemAtPosition(int);
     method public long getItemIdAtPosition(int);
     method public int getLastVisiblePosition();
-    method public final android.widget.AdapterView.OnItemClickListener getOnItemClickListener();
+    method @Nullable public final android.widget.AdapterView.OnItemClickListener getOnItemClickListener();
     method public final android.widget.AdapterView.OnItemLongClickListener getOnItemLongClickListener();
-    method public final android.widget.AdapterView.OnItemSelectedListener getOnItemSelectedListener();
+    method @Nullable public final android.widget.AdapterView.OnItemSelectedListener getOnItemSelectedListener();
     method public int getPositionForView(android.view.View);
-    method public java.lang.Object getSelectedItem();
-    method public long getSelectedItemId();
-    method public int getSelectedItemPosition();
+    method public Object getSelectedItem();
+    method @android.view.ViewDebug.CapturedViewProperty public long getSelectedItemId();
+    method @android.view.ViewDebug.CapturedViewProperty public int getSelectedItemPosition();
     method public abstract android.view.View getSelectedView();
     method public boolean performItemClick(android.view.View, int, long);
     method public abstract void setAdapter(T);
     method public void setEmptyView(android.view.View);
-    method public void setOnItemClickListener(android.widget.AdapterView.OnItemClickListener);
+    method public void setOnItemClickListener(@Nullable android.widget.AdapterView.OnItemClickListener);
     method public void setOnItemLongClickListener(android.widget.AdapterView.OnItemLongClickListener);
-    method public void setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
+    method public void setOnItemSelectedListener(@Nullable android.widget.AdapterView.OnItemSelectedListener);
     method public abstract void setSelection(int);
     field public static final int INVALID_POSITION = -1; // 0xffffffff
     field public static final long INVALID_ROW_ID = -9223372036854775808L; // 0x8000000000000000L
@@ -54374,20 +54807,20 @@
     field public android.view.View targetView;
   }
 
-  public static abstract interface AdapterView.OnItemClickListener {
-    method public abstract void onItemClick(android.widget.AdapterView<?>, android.view.View, int, long);
+  public static interface AdapterView.OnItemClickListener {
+    method public void onItemClick(android.widget.AdapterView<?>, android.view.View, int, long);
   }
 
-  public static abstract interface AdapterView.OnItemLongClickListener {
-    method public abstract boolean onItemLongClick(android.widget.AdapterView<?>, android.view.View, int, long);
+  public static interface AdapterView.OnItemLongClickListener {
+    method public boolean onItemLongClick(android.widget.AdapterView<?>, android.view.View, int, long);
   }
 
-  public static abstract interface AdapterView.OnItemSelectedListener {
-    method public abstract void onItemSelected(android.widget.AdapterView<?>, android.view.View, int, long);
-    method public abstract void onNothingSelected(android.widget.AdapterView<?>);
+  public static interface AdapterView.OnItemSelectedListener {
+    method public void onItemSelected(android.widget.AdapterView<?>, android.view.View, int, long);
+    method public void onNothingSelected(android.widget.AdapterView<?>);
   }
 
-  public abstract class AdapterViewAnimator extends android.widget.AdapterView implements android.widget.Advanceable {
+  public abstract class AdapterViewAnimator extends android.widget.AdapterView<android.widget.Adapter> implements android.widget.Advanceable {
     ctor public AdapterViewAnimator(android.content.Context);
     ctor public AdapterViewAnimator(android.content.Context, android.util.AttributeSet);
     ctor public AdapterViewAnimator(android.content.Context, android.util.AttributeSet, int);
@@ -54418,7 +54851,7 @@
     method public void showPrevious();
   }
 
-  public class AdapterViewFlipper extends android.widget.AdapterViewAnimator {
+  @android.widget.RemoteViews.RemoteView public class AdapterViewFlipper extends android.widget.AdapterViewAnimator {
     ctor public AdapterViewFlipper(android.content.Context);
     ctor public AdapterViewFlipper(android.content.Context, android.util.AttributeSet);
     ctor public AdapterViewFlipper(android.content.Context, android.util.AttributeSet, int);
@@ -54432,56 +54865,56 @@
     method public void stopFlipping();
   }
 
-  public abstract interface Advanceable {
-    method public abstract void advance();
-    method public abstract void fyiWillBeAdvancedByHostKThx();
+  public interface Advanceable {
+    method public void advance();
+    method public void fyiWillBeAdvancedByHostKThx();
   }
 
   public class AlphabetIndexer extends android.database.DataSetObserver implements android.widget.SectionIndexer {
-    ctor public AlphabetIndexer(android.database.Cursor, int, java.lang.CharSequence);
-    method protected int compare(java.lang.String, java.lang.String);
+    ctor public AlphabetIndexer(android.database.Cursor, int, CharSequence);
+    method protected int compare(String, String);
     method public int getPositionForSection(int);
     method public int getSectionForPosition(int);
-    method public java.lang.Object[] getSections();
+    method public Object[] getSections();
     method public void setCursor(android.database.Cursor);
-    field protected java.lang.CharSequence mAlphabet;
+    field protected CharSequence mAlphabet;
     field protected int mColumnIndex;
     field protected android.database.Cursor mDataCursor;
   }
 
-  public deprecated class AnalogClock extends android.view.View {
-    ctor public AnalogClock(android.content.Context);
-    ctor public AnalogClock(android.content.Context, android.util.AttributeSet);
-    ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int);
-    ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
+  @Deprecated @android.widget.RemoteViews.RemoteView public class AnalogClock extends android.view.View {
+    ctor @Deprecated public AnalogClock(android.content.Context);
+    ctor @Deprecated public AnalogClock(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public AnalogClock(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public AnalogClock(android.content.Context, android.util.AttributeSet, int, int);
   }
 
   public class ArrayAdapter<T> extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
-    ctor public ArrayAdapter(android.content.Context, int);
-    ctor public ArrayAdapter(android.content.Context, int, int);
-    ctor public ArrayAdapter(android.content.Context, int, T[]);
-    ctor public ArrayAdapter(android.content.Context, int, int, T[]);
-    ctor public ArrayAdapter(android.content.Context, int, java.util.List<T>);
-    ctor public ArrayAdapter(android.content.Context, int, int, java.util.List<T>);
-    method public void add(T);
-    method public void addAll(java.util.Collection<? extends T>);
+    ctor public ArrayAdapter(@NonNull android.content.Context, @LayoutRes int);
+    ctor public ArrayAdapter(@NonNull android.content.Context, @LayoutRes int, @IdRes int);
+    ctor public ArrayAdapter(@NonNull android.content.Context, @LayoutRes int, @NonNull T[]);
+    ctor public ArrayAdapter(@NonNull android.content.Context, @LayoutRes int, @IdRes int, @NonNull T[]);
+    ctor public ArrayAdapter(@NonNull android.content.Context, @LayoutRes int, @NonNull java.util.List<T>);
+    ctor public ArrayAdapter(@NonNull android.content.Context, @LayoutRes int, @IdRes int, @NonNull java.util.List<T>);
+    method public void add(@Nullable T);
+    method public void addAll(@NonNull java.util.Collection<? extends T>);
     method public void addAll(T...);
     method public void clear();
-    method public static android.widget.ArrayAdapter<java.lang.CharSequence> createFromResource(android.content.Context, int, int);
-    method public android.content.Context getContext();
+    method @NonNull public static android.widget.ArrayAdapter<java.lang.CharSequence> createFromResource(@NonNull android.content.Context, @ArrayRes int, @LayoutRes int);
+    method @NonNull public android.content.Context getContext();
     method public int getCount();
-    method public android.content.res.Resources.Theme getDropDownViewTheme();
-    method public android.widget.Filter getFilter();
-    method public T getItem(int);
+    method @Nullable public android.content.res.Resources.Theme getDropDownViewTheme();
+    method @NonNull public android.widget.Filter getFilter();
+    method @Nullable public T getItem(int);
     method public long getItemId(int);
-    method public int getPosition(T);
-    method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
-    method public void insert(T, int);
-    method public void remove(T);
-    method public void setDropDownViewResource(int);
-    method public void setDropDownViewTheme(android.content.res.Resources.Theme);
+    method public int getPosition(@Nullable T);
+    method @NonNull public android.view.View getView(int, @Nullable android.view.View, @NonNull android.view.ViewGroup);
+    method public void insert(@Nullable T, int);
+    method public void remove(@Nullable T);
+    method public void setDropDownViewResource(@LayoutRes int);
+    method public void setDropDownViewTheme(@Nullable android.content.res.Resources.Theme);
     method public void setNotifyOnChange(boolean);
-    method public void sort(java.util.Comparator<? super T>);
+    method public void sort(@NonNull java.util.Comparator<? super T>);
   }
 
   public class AutoCompleteTextView extends android.widget.EditText implements android.widget.Filter.FilterListener {
@@ -54491,11 +54924,11 @@
     ctor public AutoCompleteTextView(android.content.Context, android.util.AttributeSet, int, int);
     ctor public AutoCompleteTextView(android.content.Context, android.util.AttributeSet, int, int, android.content.res.Resources.Theme);
     method public void clearListSelection();
-    method protected java.lang.CharSequence convertSelectionToString(java.lang.Object);
+    method protected CharSequence convertSelectionToString(Object);
     method public void dismissDropDown();
     method public boolean enoughToFilter();
     method public android.widget.ListAdapter getAdapter();
-    method public java.lang.CharSequence getCompletionHint();
+    method public CharSequence getCompletionHint();
     method public int getDropDownAnchor();
     method public android.graphics.drawable.Drawable getDropDownBackground();
     method public int getDropDownHeight();
@@ -54503,8 +54936,8 @@
     method public int getDropDownVerticalOffset();
     method public int getDropDownWidth();
     method protected android.widget.Filter getFilter();
-    method public deprecated android.widget.AdapterView.OnItemClickListener getItemClickListener();
-    method public deprecated android.widget.AdapterView.OnItemSelectedListener getItemSelectedListener();
+    method @Deprecated public android.widget.AdapterView.OnItemClickListener getItemClickListener();
+    method @Deprecated public android.widget.AdapterView.OnItemSelectedListener getItemSelectedListener();
     method public int getListSelection();
     method public android.widget.AdapterView.OnItemClickListener getOnItemClickListener();
     method public android.widget.AdapterView.OnItemSelectedListener getOnItemSelectedListener();
@@ -54514,14 +54947,14 @@
     method public boolean isPopupShowing();
     method public void onFilterComplete(int);
     method public void performCompletion();
-    method protected void performFiltering(java.lang.CharSequence, int);
+    method protected void performFiltering(CharSequence, int);
     method public void performValidation();
-    method protected void replaceText(java.lang.CharSequence);
+    method protected void replaceText(CharSequence);
     method public <T extends android.widget.ListAdapter & android.widget.Filterable> void setAdapter(T);
-    method public void setCompletionHint(java.lang.CharSequence);
+    method public void setCompletionHint(CharSequence);
     method public void setDropDownAnchor(int);
     method public void setDropDownBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setDropDownBackgroundResource(int);
+    method public void setDropDownBackgroundResource(@DrawableRes int);
     method public void setDropDownHeight(int);
     method public void setDropDownHorizontalOffset(int);
     method public void setDropDownVerticalOffset(int);
@@ -54530,19 +54963,19 @@
     method public void setOnDismissListener(android.widget.AutoCompleteTextView.OnDismissListener);
     method public void setOnItemClickListener(android.widget.AdapterView.OnItemClickListener);
     method public void setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
-    method public void setText(java.lang.CharSequence, boolean);
+    method public void setText(CharSequence, boolean);
     method public void setThreshold(int);
     method public void setValidator(android.widget.AutoCompleteTextView.Validator);
     method public void showDropDown();
   }
 
-  public static abstract interface AutoCompleteTextView.OnDismissListener {
-    method public abstract void onDismiss();
+  public static interface AutoCompleteTextView.OnDismissListener {
+    method public void onDismiss();
   }
 
-  public static abstract interface AutoCompleteTextView.Validator {
-    method public abstract java.lang.CharSequence fixText(java.lang.CharSequence);
-    method public abstract boolean isValid(java.lang.CharSequence);
+  public static interface AutoCompleteTextView.Validator {
+    method public CharSequence fixText(CharSequence);
+    method public boolean isValid(CharSequence);
   }
 
   public abstract class BaseAdapter implements android.widget.ListAdapter android.widget.SpinnerAdapter {
@@ -54557,7 +54990,7 @@
     method public void notifyDataSetChanged();
     method public void notifyDataSetInvalidated();
     method public void registerDataSetObserver(android.database.DataSetObserver);
-    method public void setAutofillOptions(java.lang.CharSequence...);
+    method public void setAutofillOptions(@Nullable java.lang.CharSequence...);
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
   }
 
@@ -54579,7 +55012,7 @@
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
   }
 
-  public class Button extends android.widget.TextView {
+  @android.widget.RemoteViews.RemoteView public class Button extends android.widget.TextView {
     ctor public Button(android.content.Context);
     ctor public Button(android.content.Context, android.util.AttributeSet);
     ctor public Button(android.content.Context, android.util.AttributeSet, int);
@@ -54587,45 +55020,45 @@
   }
 
   public class CalendarView extends android.widget.FrameLayout {
-    ctor public CalendarView(android.content.Context);
-    ctor public CalendarView(android.content.Context, android.util.AttributeSet);
-    ctor public CalendarView(android.content.Context, android.util.AttributeSet, int);
-    ctor public CalendarView(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public CalendarView(@NonNull android.content.Context);
+    ctor public CalendarView(@NonNull android.content.Context, @Nullable android.util.AttributeSet);
+    ctor public CalendarView(@NonNull android.content.Context, @Nullable android.util.AttributeSet, @AttrRes int);
+    ctor public CalendarView(@NonNull android.content.Context, @Nullable android.util.AttributeSet, @AttrRes int, @StyleRes int);
     method public long getDate();
-    method public int getDateTextAppearance();
+    method @StyleRes public int getDateTextAppearance();
     method public int getFirstDayOfWeek();
-    method public deprecated int getFocusedMonthDateColor();
+    method @Deprecated @ColorInt public int getFocusedMonthDateColor();
     method public long getMaxDate();
     method public long getMinDate();
-    method public deprecated android.graphics.drawable.Drawable getSelectedDateVerticalBar();
-    method public deprecated int getSelectedWeekBackgroundColor();
-    method public deprecated boolean getShowWeekNumber();
-    method public deprecated int getShownWeekCount();
-    method public deprecated int getUnfocusedMonthDateColor();
-    method public int getWeekDayTextAppearance();
-    method public deprecated int getWeekNumberColor();
-    method public deprecated int getWeekSeparatorLineColor();
+    method @Deprecated public android.graphics.drawable.Drawable getSelectedDateVerticalBar();
+    method @Deprecated @ColorInt public int getSelectedWeekBackgroundColor();
+    method @Deprecated public boolean getShowWeekNumber();
+    method @Deprecated public int getShownWeekCount();
+    method @Deprecated @ColorInt public int getUnfocusedMonthDateColor();
+    method @StyleRes public int getWeekDayTextAppearance();
+    method @Deprecated @ColorInt public int getWeekNumberColor();
+    method @Deprecated @ColorInt public int getWeekSeparatorLineColor();
     method public void setDate(long);
     method public void setDate(long, boolean, boolean);
-    method public void setDateTextAppearance(int);
+    method public void setDateTextAppearance(@StyleRes int);
     method public void setFirstDayOfWeek(int);
-    method public deprecated void setFocusedMonthDateColor(int);
+    method @Deprecated public void setFocusedMonthDateColor(@ColorInt int);
     method public void setMaxDate(long);
     method public void setMinDate(long);
     method public void setOnDateChangeListener(android.widget.CalendarView.OnDateChangeListener);
-    method public deprecated void setSelectedDateVerticalBar(int);
-    method public deprecated void setSelectedDateVerticalBar(android.graphics.drawable.Drawable);
-    method public deprecated void setSelectedWeekBackgroundColor(int);
-    method public deprecated void setShowWeekNumber(boolean);
-    method public deprecated void setShownWeekCount(int);
-    method public deprecated void setUnfocusedMonthDateColor(int);
-    method public void setWeekDayTextAppearance(int);
-    method public deprecated void setWeekNumberColor(int);
-    method public deprecated void setWeekSeparatorLineColor(int);
+    method @Deprecated public void setSelectedDateVerticalBar(@DrawableRes int);
+    method @Deprecated public void setSelectedDateVerticalBar(android.graphics.drawable.Drawable);
+    method @Deprecated public void setSelectedWeekBackgroundColor(@ColorInt int);
+    method @Deprecated public void setShowWeekNumber(boolean);
+    method @Deprecated public void setShownWeekCount(int);
+    method @Deprecated public void setUnfocusedMonthDateColor(@ColorInt int);
+    method public void setWeekDayTextAppearance(@StyleRes int);
+    method @Deprecated public void setWeekNumberColor(@ColorInt int);
+    method @Deprecated public void setWeekSeparatorLineColor(@ColorInt int);
   }
 
-  public static abstract interface CalendarView.OnDateChangeListener {
-    method public abstract void onSelectedDayChange(android.widget.CalendarView, int, int, int);
+  public static interface CalendarView.OnDateChangeListener {
+    method public void onSelectedDayChange(@NonNull android.widget.CalendarView, int, int, int);
   }
 
   public class CheckBox extends android.widget.CompoundButton {
@@ -54635,10 +55068,10 @@
     ctor public CheckBox(android.content.Context, android.util.AttributeSet, int, int);
   }
 
-  public abstract interface Checkable {
-    method public abstract boolean isChecked();
-    method public abstract void setChecked(boolean);
-    method public abstract void toggle();
+  public interface Checkable {
+    method public boolean isChecked();
+    method public void setChecked(boolean);
+    method public void toggle();
   }
 
   public class CheckedTextView extends android.widget.TextView implements android.widget.Checkable {
@@ -54647,37 +55080,37 @@
     ctor public CheckedTextView(android.content.Context, android.util.AttributeSet, int);
     ctor public CheckedTextView(android.content.Context, android.util.AttributeSet, int, int);
     method public android.graphics.drawable.Drawable getCheckMarkDrawable();
-    method public android.content.res.ColorStateList getCheckMarkTintList();
-    method public android.graphics.PorterDuff.Mode getCheckMarkTintMode();
-    method public boolean isChecked();
-    method public void setCheckMarkDrawable(int);
-    method public void setCheckMarkDrawable(android.graphics.drawable.Drawable);
-    method public void setCheckMarkTintList(android.content.res.ColorStateList);
-    method public void setCheckMarkTintMode(android.graphics.PorterDuff.Mode);
+    method @Nullable public android.content.res.ColorStateList getCheckMarkTintList();
+    method @Nullable public android.graphics.PorterDuff.Mode getCheckMarkTintMode();
+    method @android.view.ViewDebug.ExportedProperty public boolean isChecked();
+    method public void setCheckMarkDrawable(@DrawableRes int);
+    method public void setCheckMarkDrawable(@Nullable android.graphics.drawable.Drawable);
+    method public void setCheckMarkTintList(@Nullable android.content.res.ColorStateList);
+    method public void setCheckMarkTintMode(@Nullable android.graphics.PorterDuff.Mode);
     method public void setChecked(boolean);
     method public void toggle();
   }
 
-  public class Chronometer extends android.widget.TextView {
+  @android.widget.RemoteViews.RemoteView public class Chronometer extends android.widget.TextView {
     ctor public Chronometer(android.content.Context);
     ctor public Chronometer(android.content.Context, android.util.AttributeSet);
     ctor public Chronometer(android.content.Context, android.util.AttributeSet, int);
     ctor public Chronometer(android.content.Context, android.util.AttributeSet, int, int);
     method public long getBase();
-    method public java.lang.String getFormat();
+    method public String getFormat();
     method public android.widget.Chronometer.OnChronometerTickListener getOnChronometerTickListener();
     method public boolean isCountDown();
     method public boolean isTheFinalCountDown();
     method public void setBase(long);
     method public void setCountDown(boolean);
-    method public void setFormat(java.lang.String);
+    method public void setFormat(String);
     method public void setOnChronometerTickListener(android.widget.Chronometer.OnChronometerTickListener);
     method public void start();
     method public void stop();
   }
 
-  public static abstract interface Chronometer.OnChronometerTickListener {
-    method public abstract void onChronometerTick(android.widget.Chronometer);
+  public static interface Chronometer.OnChronometerTickListener {
+    method public void onChronometerTick(android.widget.Chronometer);
   }
 
   public abstract class CompoundButton extends android.widget.Button implements android.widget.Checkable {
@@ -54685,47 +55118,47 @@
     ctor public CompoundButton(android.content.Context, android.util.AttributeSet);
     ctor public CompoundButton(android.content.Context, android.util.AttributeSet, int);
     ctor public CompoundButton(android.content.Context, android.util.AttributeSet, int, int);
-    method public android.graphics.drawable.Drawable getButtonDrawable();
-    method public android.content.res.ColorStateList getButtonTintList();
-    method public android.graphics.PorterDuff.Mode getButtonTintMode();
-    method public boolean isChecked();
-    method public void setButtonDrawable(int);
-    method public void setButtonDrawable(android.graphics.drawable.Drawable);
-    method public void setButtonTintList(android.content.res.ColorStateList);
-    method public void setButtonTintMode(android.graphics.PorterDuff.Mode);
+    method @Nullable public android.graphics.drawable.Drawable getButtonDrawable();
+    method @Nullable public android.content.res.ColorStateList getButtonTintList();
+    method @Nullable public android.graphics.PorterDuff.Mode getButtonTintMode();
+    method @android.view.ViewDebug.ExportedProperty public boolean isChecked();
+    method public void setButtonDrawable(@DrawableRes int);
+    method public void setButtonDrawable(@Nullable android.graphics.drawable.Drawable);
+    method public void setButtonTintList(@Nullable android.content.res.ColorStateList);
+    method public void setButtonTintMode(@Nullable android.graphics.PorterDuff.Mode);
     method public void setChecked(boolean);
-    method public void setOnCheckedChangeListener(android.widget.CompoundButton.OnCheckedChangeListener);
+    method public void setOnCheckedChangeListener(@Nullable android.widget.CompoundButton.OnCheckedChangeListener);
     method public void toggle();
   }
 
-  public static abstract interface CompoundButton.OnCheckedChangeListener {
-    method public abstract void onCheckedChanged(android.widget.CompoundButton, boolean);
+  public static interface CompoundButton.OnCheckedChangeListener {
+    method public void onCheckedChanged(android.widget.CompoundButton, boolean);
   }
 
   public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
-    ctor public deprecated CursorAdapter(android.content.Context, android.database.Cursor);
+    ctor @Deprecated public CursorAdapter(android.content.Context, android.database.Cursor);
     ctor public CursorAdapter(android.content.Context, android.database.Cursor, boolean);
     ctor public CursorAdapter(android.content.Context, android.database.Cursor, int);
     method public abstract void bindView(android.view.View, android.content.Context, android.database.Cursor);
     method public void changeCursor(android.database.Cursor);
-    method public java.lang.CharSequence convertToString(android.database.Cursor);
+    method public CharSequence convertToString(android.database.Cursor);
     method public int getCount();
     method public android.database.Cursor getCursor();
     method public android.content.res.Resources.Theme getDropDownViewTheme();
     method public android.widget.Filter getFilter();
     method public android.widget.FilterQueryProvider getFilterQueryProvider();
-    method public java.lang.Object getItem(int);
+    method public Object getItem(int);
     method public long getItemId(int);
     method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
-    method protected deprecated void init(android.content.Context, android.database.Cursor, boolean);
+    method @Deprecated protected void init(android.content.Context, android.database.Cursor, boolean);
     method public android.view.View newDropDownView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
     method public abstract android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
     method protected void onContentChanged();
-    method public android.database.Cursor runQueryOnBackgroundThread(java.lang.CharSequence);
+    method @WorkerThread public android.database.Cursor runQueryOnBackgroundThread(CharSequence);
     method public void setDropDownViewTheme(android.content.res.Resources.Theme);
     method public void setFilterQueryProvider(android.widget.FilterQueryProvider);
     method public android.database.Cursor swapCursor(android.database.Cursor);
-    field public static final deprecated int FLAG_AUTO_REQUERY = 1; // 0x1
+    field @Deprecated public static final int FLAG_AUTO_REQUERY = 1; // 0x1
     field public static final int FLAG_REGISTER_CONTENT_OBSERVER = 2; // 0x2
   }
 
@@ -54735,7 +55168,7 @@
     method protected abstract void bindChildView(android.view.View, android.content.Context, android.database.Cursor, boolean);
     method protected abstract void bindGroupView(android.view.View, android.content.Context, android.database.Cursor, boolean);
     method public void changeCursor(android.database.Cursor);
-    method public java.lang.String convertToString(android.database.Cursor);
+    method public String convertToString(android.database.Cursor);
     method public android.database.Cursor getChild(int, int);
     method public long getChildId(int, int);
     method public android.view.View getChildView(int, int, boolean, android.view.View, android.view.ViewGroup);
@@ -54753,7 +55186,7 @@
     method protected abstract android.view.View newChildView(android.content.Context, android.database.Cursor, boolean, android.view.ViewGroup);
     method protected abstract android.view.View newGroupView(android.content.Context, android.database.Cursor, boolean, android.view.ViewGroup);
     method public void notifyDataSetChanged(boolean);
-    method public android.database.Cursor runQueryOnBackgroundThread(java.lang.CharSequence);
+    method public android.database.Cursor runQueryOnBackgroundThread(CharSequence);
     method public void setChildrenCursor(int, android.database.Cursor);
     method public void setFilterQueryProvider(android.widget.FilterQueryProvider);
     method public void setGroupCursor(android.database.Cursor);
@@ -54764,69 +55197,69 @@
     ctor public DatePicker(android.content.Context, android.util.AttributeSet);
     ctor public DatePicker(android.content.Context, android.util.AttributeSet, int);
     ctor public DatePicker(android.content.Context, android.util.AttributeSet, int, int);
-    method public deprecated android.widget.CalendarView getCalendarView();
-    method public deprecated boolean getCalendarViewShown();
+    method @Deprecated public android.widget.CalendarView getCalendarView();
+    method @Deprecated public boolean getCalendarViewShown();
     method public int getDayOfMonth();
     method public int getFirstDayOfWeek();
     method public long getMaxDate();
     method public long getMinDate();
     method public int getMonth();
-    method public deprecated boolean getSpinnersShown();
+    method @Deprecated public boolean getSpinnersShown();
     method public int getYear();
     method public void init(int, int, int, android.widget.DatePicker.OnDateChangedListener);
-    method public deprecated void setCalendarViewShown(boolean);
+    method @Deprecated public void setCalendarViewShown(boolean);
     method public void setFirstDayOfWeek(int);
     method public void setMaxDate(long);
     method public void setMinDate(long);
     method public void setOnDateChangedListener(android.widget.DatePicker.OnDateChangedListener);
-    method public deprecated void setSpinnersShown(boolean);
+    method @Deprecated public void setSpinnersShown(boolean);
     method public void updateDate(int, int, int);
   }
 
-  public static abstract interface DatePicker.OnDateChangedListener {
-    method public abstract void onDateChanged(android.widget.DatePicker, int, int, int);
+  public static interface DatePicker.OnDateChangedListener {
+    method public void onDateChanged(android.widget.DatePicker, int, int, int);
   }
 
-  public deprecated class DialerFilter extends android.widget.RelativeLayout {
-    ctor public DialerFilter(android.content.Context);
-    ctor public DialerFilter(android.content.Context, android.util.AttributeSet);
-    method public void append(java.lang.String);
-    method public void clearText();
-    method public java.lang.CharSequence getDigits();
-    method public java.lang.CharSequence getFilterText();
-    method public java.lang.CharSequence getLetters();
-    method public int getMode();
-    method public boolean isQwertyKeyboard();
-    method protected void onModeChange(int, int);
-    method public void removeFilterWatcher(android.text.TextWatcher);
-    method public void setDigitsWatcher(android.text.TextWatcher);
-    method public void setFilterWatcher(android.text.TextWatcher);
-    method public void setLettersWatcher(android.text.TextWatcher);
-    method public void setMode(int);
-    field public static final int DIGITS_AND_LETTERS = 1; // 0x1
-    field public static final int DIGITS_AND_LETTERS_NO_DIGITS = 2; // 0x2
-    field public static final int DIGITS_AND_LETTERS_NO_LETTERS = 3; // 0x3
-    field public static final int DIGITS_ONLY = 4; // 0x4
-    field public static final int LETTERS_ONLY = 5; // 0x5
+  @Deprecated public class DialerFilter extends android.widget.RelativeLayout {
+    ctor @Deprecated public DialerFilter(android.content.Context);
+    ctor @Deprecated public DialerFilter(android.content.Context, android.util.AttributeSet);
+    method @Deprecated public void append(String);
+    method @Deprecated public void clearText();
+    method @Deprecated public CharSequence getDigits();
+    method @Deprecated public CharSequence getFilterText();
+    method @Deprecated public CharSequence getLetters();
+    method @Deprecated public int getMode();
+    method @Deprecated public boolean isQwertyKeyboard();
+    method @Deprecated protected void onModeChange(int, int);
+    method @Deprecated public void removeFilterWatcher(android.text.TextWatcher);
+    method @Deprecated public void setDigitsWatcher(android.text.TextWatcher);
+    method @Deprecated public void setFilterWatcher(android.text.TextWatcher);
+    method @Deprecated public void setLettersWatcher(android.text.TextWatcher);
+    method @Deprecated public void setMode(int);
+    field @Deprecated public static final int DIGITS_AND_LETTERS = 1; // 0x1
+    field @Deprecated public static final int DIGITS_AND_LETTERS_NO_DIGITS = 2; // 0x2
+    field @Deprecated public static final int DIGITS_AND_LETTERS_NO_LETTERS = 3; // 0x3
+    field @Deprecated public static final int DIGITS_ONLY = 4; // 0x4
+    field @Deprecated public static final int LETTERS_ONLY = 5; // 0x5
   }
 
-  public deprecated class DigitalClock extends android.widget.TextView {
-    ctor public DigitalClock(android.content.Context);
-    ctor public DigitalClock(android.content.Context, android.util.AttributeSet);
+  @Deprecated public class DigitalClock extends android.widget.TextView {
+    ctor @Deprecated public DigitalClock(android.content.Context);
+    ctor @Deprecated public DigitalClock(android.content.Context, android.util.AttributeSet);
   }
 
   public class EdgeEffect {
     ctor public EdgeEffect(android.content.Context);
     method public boolean draw(android.graphics.Canvas);
     method public void finish();
-    method public int getColor();
+    method @ColorInt public int getColor();
     method public int getMaxHeight();
     method public boolean isFinished();
     method public void onAbsorb(int);
     method public void onPull(float);
     method public void onPull(float, float);
     method public void onRelease();
-    method public void setColor(int);
+    method public void setColor(@ColorInt int);
     method public void setSize(int, int);
   }
 
@@ -54842,25 +55275,25 @@
     method public void setSelection(int);
   }
 
-  public abstract interface ExpandableListAdapter {
-    method public abstract boolean areAllItemsEnabled();
-    method public abstract java.lang.Object getChild(int, int);
-    method public abstract long getChildId(int, int);
-    method public abstract android.view.View getChildView(int, int, boolean, android.view.View, android.view.ViewGroup);
-    method public abstract int getChildrenCount(int);
-    method public abstract long getCombinedChildId(long, long);
-    method public abstract long getCombinedGroupId(long);
-    method public abstract java.lang.Object getGroup(int);
-    method public abstract int getGroupCount();
-    method public abstract long getGroupId(int);
-    method public abstract android.view.View getGroupView(int, boolean, android.view.View, android.view.ViewGroup);
-    method public abstract boolean hasStableIds();
-    method public abstract boolean isChildSelectable(int, int);
-    method public abstract boolean isEmpty();
-    method public abstract void onGroupCollapsed(int);
-    method public abstract void onGroupExpanded(int);
-    method public abstract void registerDataSetObserver(android.database.DataSetObserver);
-    method public abstract void unregisterDataSetObserver(android.database.DataSetObserver);
+  public interface ExpandableListAdapter {
+    method public boolean areAllItemsEnabled();
+    method public Object getChild(int, int);
+    method public long getChildId(int, int);
+    method public android.view.View getChildView(int, int, boolean, android.view.View, android.view.ViewGroup);
+    method public int getChildrenCount(int);
+    method public long getCombinedChildId(long, long);
+    method public long getCombinedGroupId(long);
+    method public Object getGroup(int);
+    method public int getGroupCount();
+    method public long getGroupId(int);
+    method public android.view.View getGroupView(int, boolean, android.view.View, android.view.ViewGroup);
+    method public boolean hasStableIds();
+    method public boolean isChildSelectable(int, int);
+    method public boolean isEmpty();
+    method public void onGroupCollapsed(int);
+    method public void onGroupExpanded(int);
+    method public void registerDataSetObserver(android.database.DataSetObserver);
+    method public void unregisterDataSetObserver(android.database.DataSetObserver);
   }
 
   public class ExpandableListView extends android.widget.ListView {
@@ -54910,97 +55343,97 @@
     field public android.view.View targetView;
   }
 
-  public static abstract interface ExpandableListView.OnChildClickListener {
-    method public abstract boolean onChildClick(android.widget.ExpandableListView, android.view.View, int, int, long);
+  public static interface ExpandableListView.OnChildClickListener {
+    method public boolean onChildClick(android.widget.ExpandableListView, android.view.View, int, int, long);
   }
 
-  public static abstract interface ExpandableListView.OnGroupClickListener {
-    method public abstract boolean onGroupClick(android.widget.ExpandableListView, android.view.View, int, long);
+  public static interface ExpandableListView.OnGroupClickListener {
+    method public boolean onGroupClick(android.widget.ExpandableListView, android.view.View, int, long);
   }
 
-  public static abstract interface ExpandableListView.OnGroupCollapseListener {
-    method public abstract void onGroupCollapse(int);
+  public static interface ExpandableListView.OnGroupCollapseListener {
+    method public void onGroupCollapse(int);
   }
 
-  public static abstract interface ExpandableListView.OnGroupExpandListener {
-    method public abstract void onGroupExpand(int);
+  public static interface ExpandableListView.OnGroupExpandListener {
+    method public void onGroupExpand(int);
   }
 
   public abstract class Filter {
     ctor public Filter();
-    method public java.lang.CharSequence convertResultToString(java.lang.Object);
-    method public final void filter(java.lang.CharSequence);
-    method public final void filter(java.lang.CharSequence, android.widget.Filter.FilterListener);
-    method protected abstract android.widget.Filter.FilterResults performFiltering(java.lang.CharSequence);
-    method protected abstract void publishResults(java.lang.CharSequence, android.widget.Filter.FilterResults);
+    method public CharSequence convertResultToString(Object);
+    method public final void filter(CharSequence);
+    method public final void filter(CharSequence, android.widget.Filter.FilterListener);
+    method protected abstract android.widget.Filter.FilterResults performFiltering(CharSequence);
+    method protected abstract void publishResults(CharSequence, android.widget.Filter.FilterResults);
   }
 
-  public static abstract interface Filter.FilterListener {
-    method public abstract void onFilterComplete(int);
+  public static interface Filter.FilterListener {
+    method public void onFilterComplete(int);
   }
 
   protected static class Filter.FilterResults {
     ctor public Filter.FilterResults();
     field public int count;
-    field public java.lang.Object values;
+    field public Object values;
   }
 
-  public abstract interface FilterQueryProvider {
-    method public abstract android.database.Cursor runQuery(java.lang.CharSequence);
+  public interface FilterQueryProvider {
+    method public android.database.Cursor runQuery(CharSequence);
   }
 
-  public abstract interface Filterable {
-    method public abstract android.widget.Filter getFilter();
+  public interface Filterable {
+    method public android.widget.Filter getFilter();
   }
 
-  public class FrameLayout extends android.view.ViewGroup {
-    ctor public FrameLayout(android.content.Context);
-    ctor public FrameLayout(android.content.Context, android.util.AttributeSet);
-    ctor public FrameLayout(android.content.Context, android.util.AttributeSet, int);
-    ctor public FrameLayout(android.content.Context, android.util.AttributeSet, int, int);
+  @android.widget.RemoteViews.RemoteView public class FrameLayout extends android.view.ViewGroup {
+    ctor public FrameLayout(@NonNull android.content.Context);
+    ctor public FrameLayout(@NonNull android.content.Context, @Nullable android.util.AttributeSet);
+    ctor public FrameLayout(@NonNull android.content.Context, @Nullable android.util.AttributeSet, @AttrRes int);
+    ctor public FrameLayout(@NonNull android.content.Context, @Nullable android.util.AttributeSet, @AttrRes int, @StyleRes int);
     method protected android.widget.FrameLayout.LayoutParams generateDefaultLayoutParams();
     method public android.widget.FrameLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method public deprecated boolean getConsiderGoneChildrenWhenMeasuring();
+    method @Deprecated public boolean getConsiderGoneChildrenWhenMeasuring();
     method public boolean getMeasureAllChildren();
     method public void setMeasureAllChildren(boolean);
   }
 
   public static class FrameLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
-    ctor public FrameLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public FrameLayout.LayoutParams(@NonNull android.content.Context, @Nullable android.util.AttributeSet);
     ctor public FrameLayout.LayoutParams(int, int);
     ctor public FrameLayout.LayoutParams(int, int, int);
-    ctor public FrameLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public FrameLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public FrameLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
+    ctor public FrameLayout.LayoutParams(@NonNull android.view.ViewGroup.LayoutParams);
+    ctor public FrameLayout.LayoutParams(@NonNull android.view.ViewGroup.MarginLayoutParams);
+    ctor public FrameLayout.LayoutParams(@NonNull android.widget.FrameLayout.LayoutParams);
     field public static final int UNSPECIFIED_GRAVITY = -1; // 0xffffffff
     field public int gravity;
   }
 
-  public deprecated class Gallery extends android.widget.AbsSpinner implements android.view.GestureDetector.OnGestureListener {
-    ctor public Gallery(android.content.Context);
-    ctor public Gallery(android.content.Context, android.util.AttributeSet);
-    ctor public Gallery(android.content.Context, android.util.AttributeSet, int);
-    ctor public Gallery(android.content.Context, android.util.AttributeSet, int, int);
-    method public boolean onDown(android.view.MotionEvent);
-    method public boolean onFling(android.view.MotionEvent, android.view.MotionEvent, float, float);
-    method public void onLongPress(android.view.MotionEvent);
-    method public boolean onScroll(android.view.MotionEvent, android.view.MotionEvent, float, float);
-    method public void onShowPress(android.view.MotionEvent);
-    method public boolean onSingleTapUp(android.view.MotionEvent);
-    method public void setAnimationDuration(int);
-    method public void setCallbackDuringFling(boolean);
-    method public void setGravity(int);
-    method public void setSpacing(int);
-    method public void setUnselectedAlpha(float);
+  @Deprecated public class Gallery extends android.widget.AbsSpinner implements android.view.GestureDetector.OnGestureListener {
+    ctor @Deprecated public Gallery(android.content.Context);
+    ctor @Deprecated public Gallery(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public Gallery(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public Gallery(android.content.Context, android.util.AttributeSet, int, int);
+    method @Deprecated public boolean onDown(android.view.MotionEvent);
+    method @Deprecated public boolean onFling(android.view.MotionEvent, android.view.MotionEvent, float, float);
+    method @Deprecated public void onLongPress(@NonNull android.view.MotionEvent);
+    method @Deprecated public boolean onScroll(android.view.MotionEvent, android.view.MotionEvent, float, float);
+    method @Deprecated public void onShowPress(android.view.MotionEvent);
+    method @Deprecated public boolean onSingleTapUp(android.view.MotionEvent);
+    method @Deprecated public void setAnimationDuration(int);
+    method @Deprecated public void setCallbackDuringFling(boolean);
+    method @Deprecated public void setGravity(int);
+    method @Deprecated public void setSpacing(int);
+    method @Deprecated public void setUnselectedAlpha(float);
   }
 
-  public static class Gallery.LayoutParams extends android.view.ViewGroup.LayoutParams {
-    ctor public Gallery.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public Gallery.LayoutParams(int, int);
-    ctor public Gallery.LayoutParams(android.view.ViewGroup.LayoutParams);
+  @Deprecated public static class Gallery.LayoutParams extends android.view.ViewGroup.LayoutParams {
+    ctor @Deprecated public Gallery.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public Gallery.LayoutParams(int, int);
+    ctor @Deprecated public Gallery.LayoutParams(android.view.ViewGroup.LayoutParams);
   }
 
-  public class GridLayout extends android.view.ViewGroup {
+  @android.widget.RemoteViews.RemoteView public class GridLayout extends android.view.ViewGroup {
     ctor public GridLayout(android.content.Context);
     ctor public GridLayout(android.content.Context, android.util.AttributeSet);
     ctor public GridLayout(android.content.Context, android.util.AttributeSet, int);
@@ -55046,7 +55479,7 @@
     field public static final int VERTICAL = 1; // 0x1
   }
 
-  public static abstract class GridLayout.Alignment {
+  public abstract static class GridLayout.Alignment {
   }
 
   public static class GridLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
@@ -55064,7 +55497,7 @@
   public static class GridLayout.Spec {
   }
 
-  public class GridView extends android.widget.AbsListView {
+  @android.widget.RemoteViews.RemoteView public class GridView extends android.widget.AbsListView {
     ctor public GridView(android.content.Context);
     ctor public GridView(android.content.Context, android.util.AttributeSet);
     ctor public GridView(android.content.Context, android.util.AttributeSet, int);
@@ -55073,7 +55506,7 @@
     method public int getColumnWidth();
     method public int getGravity();
     method public int getHorizontalSpacing();
-    method public int getNumColumns();
+    method @android.view.ViewDebug.ExportedProperty public int getNumColumns();
     method public int getRequestedColumnWidth();
     method public int getRequestedHorizontalSpacing();
     method public int getStretchMode();
@@ -55100,7 +55533,7 @@
     method public android.widget.Filter getFilter();
     method public int getFootersCount();
     method public int getHeadersCount();
-    method public java.lang.Object getItem(int);
+    method public Object getItem(int);
     method public long getItemId(int);
     method public int getItemViewType(int);
     method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
@@ -55115,11 +55548,11 @@
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
   }
 
-  public abstract interface HeterogeneousExpandableList {
-    method public abstract int getChildType(int, int);
-    method public abstract int getChildTypeCount();
-    method public abstract int getGroupType(int);
-    method public abstract int getGroupTypeCount();
+  public interface HeterogeneousExpandableList {
+    method public int getChildType(int, int);
+    method public int getChildTypeCount();
+    method public int getGroupType(int);
+    method public int getGroupTypeCount();
   }
 
   public class HorizontalScrollView extends android.widget.FrameLayout {
@@ -55142,7 +55575,7 @@
     method public final void smoothScrollTo(int, int);
   }
 
-  public class ImageButton extends android.widget.ImageView {
+  @android.widget.RemoteViews.RemoteView public class ImageButton extends android.widget.ImageView {
     ctor public ImageButton(android.content.Context);
     ctor public ImageButton(android.content.Context, android.util.AttributeSet);
     ctor public ImageButton(android.content.Context, android.util.AttributeSet, int);
@@ -55153,16 +55586,16 @@
     ctor public ImageSwitcher(android.content.Context);
     ctor public ImageSwitcher(android.content.Context, android.util.AttributeSet);
     method public void setImageDrawable(android.graphics.drawable.Drawable);
-    method public void setImageResource(int);
+    method public void setImageResource(@DrawableRes int);
     method public void setImageURI(android.net.Uri);
   }
 
-  public class ImageView extends android.view.View {
+  @android.widget.RemoteViews.RemoteView public class ImageView extends android.view.View {
     ctor public ImageView(android.content.Context);
-    ctor public ImageView(android.content.Context, android.util.AttributeSet);
-    ctor public ImageView(android.content.Context, android.util.AttributeSet, int);
-    ctor public ImageView(android.content.Context, android.util.AttributeSet, int, int);
-    method public void animateTransform(android.graphics.Matrix);
+    ctor public ImageView(android.content.Context, @Nullable android.util.AttributeSet);
+    ctor public ImageView(android.content.Context, @Nullable android.util.AttributeSet, int);
+    ctor public ImageView(android.content.Context, @Nullable android.util.AttributeSet, int, int);
+    method public void animateTransform(@Nullable android.graphics.Matrix);
     method public final void clearColorFilter();
     method public boolean getAdjustViewBounds();
     method public boolean getBaselineAlignBottom();
@@ -55171,14 +55604,14 @@
     method public android.graphics.drawable.Drawable getDrawable();
     method public int getImageAlpha();
     method public android.graphics.Matrix getImageMatrix();
-    method public android.content.res.ColorStateList getImageTintList();
-    method public android.graphics.PorterDuff.Mode getImageTintMode();
+    method @Nullable public android.content.res.ColorStateList getImageTintList();
+    method @Nullable public android.graphics.PorterDuff.Mode getImageTintMode();
     method public int getMaxHeight();
     method public int getMaxWidth();
     method public android.widget.ImageView.ScaleType getScaleType();
     method public int[] onCreateDrawableState(int);
     method public void setAdjustViewBounds(boolean);
-    method public deprecated void setAlpha(int);
+    method @Deprecated public void setAlpha(int);
     method public void setBaseline(int);
     method public void setBaselineAlignBottom(boolean);
     method public final void setColorFilter(int, android.graphics.PorterDuff.Mode);
@@ -55188,23 +55621,21 @@
     method protected boolean setFrame(int, int, int, int);
     method public void setImageAlpha(int);
     method public void setImageBitmap(android.graphics.Bitmap);
-    method public void setImageDrawable(android.graphics.drawable.Drawable);
-    method public void setImageIcon(android.graphics.drawable.Icon);
+    method public void setImageDrawable(@Nullable android.graphics.drawable.Drawable);
+    method public void setImageIcon(@Nullable android.graphics.drawable.Icon);
     method public void setImageLevel(int);
     method public void setImageMatrix(android.graphics.Matrix);
-    method public void setImageResource(int);
+    method public void setImageResource(@DrawableRes int);
     method public void setImageState(int[], boolean);
-    method public void setImageTintList(android.content.res.ColorStateList);
-    method public void setImageTintMode(android.graphics.PorterDuff.Mode);
-    method public void setImageURI(android.net.Uri);
+    method public void setImageTintList(@Nullable android.content.res.ColorStateList);
+    method public void setImageTintMode(@Nullable android.graphics.PorterDuff.Mode);
+    method public void setImageURI(@Nullable android.net.Uri);
     method public void setMaxHeight(int);
     method public void setMaxWidth(int);
     method public void setScaleType(android.widget.ImageView.ScaleType);
   }
 
-  public static final class ImageView.ScaleType extends java.lang.Enum {
-    method public static android.widget.ImageView.ScaleType valueOf(java.lang.String);
-    method public static final android.widget.ImageView.ScaleType[] values();
+  public enum ImageView.ScaleType {
     enum_constant public static final android.widget.ImageView.ScaleType CENTER;
     enum_constant public static final android.widget.ImageView.ScaleType CENTER_CROP;
     enum_constant public static final android.widget.ImageView.ScaleType CENTER_INSIDE;
@@ -55215,10 +55646,10 @@
     enum_constant public static final android.widget.ImageView.ScaleType MATRIX;
   }
 
-  public class LinearLayout extends android.view.ViewGroup {
+  @android.widget.RemoteViews.RemoteView public class LinearLayout extends android.view.ViewGroup {
     ctor public LinearLayout(android.content.Context);
-    ctor public LinearLayout(android.content.Context, android.util.AttributeSet);
-    ctor public LinearLayout(android.content.Context, android.util.AttributeSet, int);
+    ctor public LinearLayout(android.content.Context, @Nullable android.util.AttributeSet);
+    ctor public LinearLayout(android.content.Context, @Nullable android.util.AttributeSet, int);
     ctor public LinearLayout(android.content.Context, android.util.AttributeSet, int, int);
     method protected android.widget.LinearLayout.LayoutParams generateDefaultLayoutParams();
     method public android.widget.LinearLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
@@ -55258,51 +55689,51 @@
     ctor public LinearLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
     ctor public LinearLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
     ctor public LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams);
-    method public java.lang.String debug(java.lang.String);
-    field public int gravity;
-    field public float weight;
+    method public String debug(String);
+    field @android.view.ViewDebug.ExportedProperty(category="layout", mapping={@android.view.ViewDebug.IntToString(from=0xffffffff, to="NONE"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.NO_GRAVITY, to="NONE"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.TOP, to="TOP"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.BOTTOM, to="BOTTOM"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.LEFT, to="LEFT"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.RIGHT, to="RIGHT"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.START, to="START"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.END, to="END"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.CENTER_VERTICAL, to="CENTER_VERTICAL"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.FILL_VERTICAL, to="FILL_VERTICAL"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.CENTER_HORIZONTAL, to="CENTER_HORIZONTAL"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.FILL_HORIZONTAL, to="FILL_HORIZONTAL"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.CENTER, to="CENTER"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.FILL, to="FILL")}) public int gravity;
+    field @android.view.ViewDebug.ExportedProperty(category="layout") public float weight;
   }
 
-  public abstract interface ListAdapter implements android.widget.Adapter {
-    method public abstract boolean areAllItemsEnabled();
-    method public abstract boolean isEnabled(int);
+  public interface ListAdapter extends android.widget.Adapter {
+    method public boolean areAllItemsEnabled();
+    method public boolean isEnabled(int);
   }
 
   public class ListPopupWindow {
-    ctor public ListPopupWindow(android.content.Context);
-    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet);
-    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int);
-    ctor public ListPopupWindow(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public ListPopupWindow(@NonNull android.content.Context);
+    ctor public ListPopupWindow(@NonNull android.content.Context, @Nullable android.util.AttributeSet);
+    ctor public ListPopupWindow(@NonNull android.content.Context, @Nullable android.util.AttributeSet, @AttrRes int);
+    ctor public ListPopupWindow(@NonNull android.content.Context, @Nullable android.util.AttributeSet, @AttrRes int, @StyleRes int);
     method public void clearListSelection();
     method public android.view.View.OnTouchListener createDragToOpenListener(android.view.View);
     method public void dismiss();
-    method public android.view.View getAnchorView();
-    method public int getAnimationStyle();
-    method public android.graphics.drawable.Drawable getBackground();
+    method @Nullable public android.view.View getAnchorView();
+    method @StyleRes public int getAnimationStyle();
+    method @Nullable public android.graphics.drawable.Drawable getBackground();
     method public int getHeight();
     method public int getHorizontalOffset();
     method public int getInputMethodMode();
-    method public android.widget.ListView getListView();
+    method @Nullable public android.widget.ListView getListView();
     method public int getPromptPosition();
-    method public java.lang.Object getSelectedItem();
+    method @Nullable public Object getSelectedItem();
     method public long getSelectedItemId();
     method public int getSelectedItemPosition();
-    method public android.view.View getSelectedView();
+    method @Nullable public android.view.View getSelectedView();
     method public int getSoftInputMode();
     method public int getVerticalOffset();
     method public int getWidth();
     method public boolean isInputMethodNotNeeded();
     method public boolean isModal();
     method public boolean isShowing();
-    method public boolean onKeyDown(int, android.view.KeyEvent);
-    method public boolean onKeyPreIme(int, android.view.KeyEvent);
-    method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public boolean onKeyDown(int, @NonNull android.view.KeyEvent);
+    method public boolean onKeyPreIme(int, @NonNull android.view.KeyEvent);
+    method public boolean onKeyUp(int, @NonNull android.view.KeyEvent);
     method public boolean performItemClick(int);
     method public void postShow();
-    method public void setAdapter(android.widget.ListAdapter);
-    method public void setAnchorView(android.view.View);
-    method public void setAnimationStyle(int);
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setAdapter(@Nullable android.widget.ListAdapter);
+    method public void setAnchorView(@Nullable android.view.View);
+    method public void setAnimationStyle(@StyleRes int);
+    method public void setBackgroundDrawable(@Nullable android.graphics.drawable.Drawable);
     method public void setContentWidth(int);
     method public void setDropDownGravity(int);
     method public void setHeight(int);
@@ -55310,11 +55741,11 @@
     method public void setInputMethodMode(int);
     method public void setListSelector(android.graphics.drawable.Drawable);
     method public void setModal(boolean);
-    method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener);
-    method public void setOnItemClickListener(android.widget.AdapterView.OnItemClickListener);
-    method public void setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener);
+    method public void setOnDismissListener(@Nullable android.widget.PopupWindow.OnDismissListener);
+    method public void setOnItemClickListener(@Nullable android.widget.AdapterView.OnItemClickListener);
+    method public void setOnItemSelectedListener(@Nullable android.widget.AdapterView.OnItemSelectedListener);
     method public void setPromptPosition(int);
-    method public void setPromptView(android.view.View);
+    method public void setPromptView(@Nullable android.view.View);
     method public void setSelection(int);
     method public void setSoftInputMode(int);
     method public void setVerticalOffset(int);
@@ -55330,20 +55761,20 @@
     field public static final int WRAP_CONTENT = -2; // 0xfffffffe
   }
 
-  public class ListView extends android.widget.AbsListView {
+  @android.widget.RemoteViews.RemoteView public class ListView extends android.widget.AbsListView {
     ctor public ListView(android.content.Context);
     ctor public ListView(android.content.Context, android.util.AttributeSet);
     ctor public ListView(android.content.Context, android.util.AttributeSet, int);
     ctor public ListView(android.content.Context, android.util.AttributeSet, int, int);
-    method public void addFooterView(android.view.View, java.lang.Object, boolean);
+    method public void addFooterView(android.view.View, Object, boolean);
     method public void addFooterView(android.view.View);
-    method public void addHeaderView(android.view.View, java.lang.Object, boolean);
+    method public void addHeaderView(android.view.View, Object, boolean);
     method public void addHeaderView(android.view.View);
     method public boolean areFooterDividersEnabled();
     method public boolean areHeaderDividersEnabled();
     method public android.widget.ListAdapter getAdapter();
-    method public deprecated long[] getCheckItemIds();
-    method public android.graphics.drawable.Drawable getDivider();
+    method @Deprecated public long[] getCheckItemIds();
+    method @Nullable public android.graphics.drawable.Drawable getDivider();
     method public int getDividerHeight();
     method public int getFooterViewsCount();
     method public int getHeaderViewsCount();
@@ -55353,7 +55784,7 @@
     method public android.graphics.drawable.Drawable getOverscrollHeader();
     method public boolean removeFooterView(android.view.View);
     method public boolean removeHeaderView(android.view.View);
-    method public void setDivider(android.graphics.drawable.Drawable);
+    method public void setDivider(@Nullable android.graphics.drawable.Drawable);
     method public void setDividerHeight(int);
     method public void setFooterDividersEnabled(boolean);
     method public void setHeaderDividersEnabled(boolean);
@@ -55367,30 +55798,30 @@
 
   public class ListView.FixedViewInfo {
     ctor public ListView.FixedViewInfo();
-    field public java.lang.Object data;
+    field public Object data;
     field public boolean isSelectable;
     field public android.view.View view;
   }
 
-  public final class Magnifier {
-    ctor public deprecated Magnifier(android.view.View);
+  @UiThread public final class Magnifier {
+    ctor @Deprecated public Magnifier(@NonNull android.view.View);
     method public void dismiss();
-    method public float getCornerRadius();
-    method public int getDefaultHorizontalSourceToMagnifierOffset();
-    method public int getDefaultVerticalSourceToMagnifierOffset();
-    method public float getElevation();
-    method public int getHeight();
-    method public android.graphics.drawable.Drawable getOverlay();
-    method public android.graphics.Point getPosition();
-    method public int getSourceHeight();
-    method public android.graphics.Point getSourcePosition();
-    method public int getSourceWidth();
-    method public int getWidth();
+    method @Px public float getCornerRadius();
+    method @Px public int getDefaultHorizontalSourceToMagnifierOffset();
+    method @Px public int getDefaultVerticalSourceToMagnifierOffset();
+    method @Px public float getElevation();
+    method @Px public int getHeight();
+    method @Nullable public android.graphics.drawable.Drawable getOverlay();
+    method @Nullable public android.graphics.Point getPosition();
+    method @Px public int getSourceHeight();
+    method @Nullable public android.graphics.Point getSourcePosition();
+    method @Px public int getSourceWidth();
+    method @Px public int getWidth();
     method public float getZoom();
-    method public boolean isForcePositionWithinWindowSystemInsetsBounds();
-    method public void setZoom(float);
-    method public void show(float, float);
-    method public void show(float, float, float, float);
+    method public boolean isClippingEnabled();
+    method public void setZoom(@FloatRange(from=0.0f) float);
+    method public void show(@FloatRange(from=0) float, @FloatRange(from=0) float);
+    method public void show(@FloatRange(from=0) float, @FloatRange(from=0) float, float, float);
     method public void update();
     field public static final int SOURCE_BOUND_MAX_IN_SURFACE = 0; // 0x0
     field public static final int SOURCE_BOUND_MAX_IN_VIEW = 1; // 0x1
@@ -55398,16 +55829,16 @@
   }
 
   public static class Magnifier.Builder {
-    ctor public Magnifier.Builder(android.view.View);
-    method public android.widget.Magnifier build();
-    method public android.widget.Magnifier.Builder setCornerRadius(float);
-    method public android.widget.Magnifier.Builder setDefaultSourceToMagnifierOffset(int, int);
-    method public android.widget.Magnifier.Builder setElevation(float);
-    method public android.widget.Magnifier.Builder setForcePositionWithinWindowSystemInsetsBounds(boolean);
-    method public android.widget.Magnifier.Builder setOverlay(android.graphics.drawable.Drawable);
-    method public android.widget.Magnifier.Builder setSize(int, int);
-    method public android.widget.Magnifier.Builder setSourceBounds(int, int, int, int);
-    method public android.widget.Magnifier.Builder setZoom(float);
+    ctor public Magnifier.Builder(@NonNull android.view.View);
+    method @NonNull public android.widget.Magnifier build();
+    method @NonNull public android.widget.Magnifier.Builder setClippingEnabled(boolean);
+    method @NonNull public android.widget.Magnifier.Builder setCornerRadius(@Px @FloatRange(from=0) float);
+    method @NonNull public android.widget.Magnifier.Builder setDefaultSourceToMagnifierOffset(@Px int, @Px int);
+    method @NonNull public android.widget.Magnifier.Builder setElevation(@Px @FloatRange(from=0) float);
+    method @NonNull public android.widget.Magnifier.Builder setOverlay(@Nullable android.graphics.drawable.Drawable);
+    method @NonNull public android.widget.Magnifier.Builder setSize(@Px @IntRange(from=0) int, @Px @IntRange(from=0) int);
+    method @NonNull public android.widget.Magnifier.Builder setSourceBounds(int, int, int, int);
+    method @NonNull public android.widget.Magnifier.Builder setZoom(@FloatRange(from=0.0f) float);
   }
 
   public class MediaController extends android.widget.FrameLayout {
@@ -55424,18 +55855,18 @@
     method public void show(int);
   }
 
-  public static abstract interface MediaController.MediaPlayerControl {
-    method public abstract boolean canPause();
-    method public abstract boolean canSeekBackward();
-    method public abstract boolean canSeekForward();
-    method public abstract int getAudioSessionId();
-    method public abstract int getBufferPercentage();
-    method public abstract int getCurrentPosition();
-    method public abstract int getDuration();
-    method public abstract boolean isPlaying();
-    method public abstract void pause();
-    method public abstract void seekTo(int);
-    method public abstract void start();
+  public static interface MediaController.MediaPlayerControl {
+    method public boolean canPause();
+    method public boolean canSeekBackward();
+    method public boolean canSeekForward();
+    method public int getAudioSessionId();
+    method public int getBufferPercentage();
+    method public int getCurrentPosition();
+    method public int getDuration();
+    method public boolean isPlaying();
+    method public void pause();
+    method public void seekTo(int);
+    method public void start();
   }
 
   public class MultiAutoCompleteTextView extends android.widget.AutoCompleteTextView {
@@ -55443,21 +55874,21 @@
     ctor public MultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet);
     ctor public MultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int);
     ctor public MultiAutoCompleteTextView(android.content.Context, android.util.AttributeSet, int, int);
-    method protected void performFiltering(java.lang.CharSequence, int, int, int);
+    method protected void performFiltering(CharSequence, int, int, int);
     method public void setTokenizer(android.widget.MultiAutoCompleteTextView.Tokenizer);
   }
 
   public static class MultiAutoCompleteTextView.CommaTokenizer implements android.widget.MultiAutoCompleteTextView.Tokenizer {
     ctor public MultiAutoCompleteTextView.CommaTokenizer();
-    method public int findTokenEnd(java.lang.CharSequence, int);
-    method public int findTokenStart(java.lang.CharSequence, int);
-    method public java.lang.CharSequence terminateToken(java.lang.CharSequence);
+    method public int findTokenEnd(CharSequence, int);
+    method public int findTokenStart(CharSequence, int);
+    method public CharSequence terminateToken(CharSequence);
   }
 
-  public static abstract interface MultiAutoCompleteTextView.Tokenizer {
-    method public abstract int findTokenEnd(java.lang.CharSequence, int);
-    method public abstract int findTokenStart(java.lang.CharSequence, int);
-    method public abstract java.lang.CharSequence terminateToken(java.lang.CharSequence);
+  public static interface MultiAutoCompleteTextView.Tokenizer {
+    method public int findTokenEnd(CharSequence, int);
+    method public int findTokenStart(CharSequence, int);
+    method public CharSequence terminateToken(CharSequence);
   }
 
   public class NumberPicker extends android.widget.LinearLayout {
@@ -55465,44 +55896,44 @@
     ctor public NumberPicker(android.content.Context, android.util.AttributeSet);
     ctor public NumberPicker(android.content.Context, android.util.AttributeSet, int);
     ctor public NumberPicker(android.content.Context, android.util.AttributeSet, int, int);
-    method public java.lang.String[] getDisplayedValues();
+    method public String[] getDisplayedValues();
     method public int getMaxValue();
     method public int getMinValue();
     method public int getSelectionDividerHeight();
     method public int getValue();
     method public boolean getWrapSelectorWheel();
-    method public void setDisplayedValues(java.lang.String[]);
+    method public void setDisplayedValues(String[]);
     method public void setFormatter(android.widget.NumberPicker.Formatter);
     method public void setMaxValue(int);
     method public void setMinValue(int);
     method public void setOnLongPressUpdateInterval(long);
     method public void setOnScrollListener(android.widget.NumberPicker.OnScrollListener);
     method public void setOnValueChangedListener(android.widget.NumberPicker.OnValueChangeListener);
-    method public void setSelectionDividerHeight(int);
+    method public void setSelectionDividerHeight(@IntRange(from=0) @Px int);
     method public void setValue(int);
     method public void setWrapSelectorWheel(boolean);
   }
 
-  public static abstract interface NumberPicker.Formatter {
-    method public abstract java.lang.String format(int);
+  public static interface NumberPicker.Formatter {
+    method public String format(int);
   }
 
-  public static abstract interface NumberPicker.OnScrollListener {
-    method public abstract void onScrollStateChange(android.widget.NumberPicker, int);
+  public static interface NumberPicker.OnScrollListener {
+    method public void onScrollStateChange(android.widget.NumberPicker, int);
     field public static final int SCROLL_STATE_FLING = 2; // 0x2
     field public static final int SCROLL_STATE_IDLE = 0; // 0x0
     field public static final int SCROLL_STATE_TOUCH_SCROLL = 1; // 0x1
   }
 
-  public static abstract interface NumberPicker.OnValueChangeListener {
-    method public abstract void onValueChange(android.widget.NumberPicker, int, int);
+  public static interface NumberPicker.OnValueChangeListener {
+    method public void onValueChange(android.widget.NumberPicker, int, int);
   }
 
   public class OverScroller {
     ctor public OverScroller(android.content.Context);
     ctor public OverScroller(android.content.Context, android.view.animation.Interpolator);
-    ctor public deprecated OverScroller(android.content.Context, android.view.animation.Interpolator, float, float);
-    ctor public deprecated OverScroller(android.content.Context, android.view.animation.Interpolator, float, float, boolean);
+    ctor @Deprecated public OverScroller(android.content.Context, android.view.animation.Interpolator, float, float);
+    ctor @Deprecated public OverScroller(android.content.Context, android.view.animation.Interpolator, float, float, boolean);
     method public void abortAnimation();
     method public boolean computeScrollOffset();
     method public void fling(int, int, int, int, int, int, int, int);
@@ -55534,19 +55965,19 @@
     method public int getGravity();
     method public android.view.Menu getMenu();
     method public android.view.MenuInflater getMenuInflater();
-    method public void inflate(int);
+    method public void inflate(@MenuRes int);
     method public void setGravity(int);
     method public void setOnDismissListener(android.widget.PopupMenu.OnDismissListener);
     method public void setOnMenuItemClickListener(android.widget.PopupMenu.OnMenuItemClickListener);
     method public void show();
   }
 
-  public static abstract interface PopupMenu.OnDismissListener {
-    method public abstract void onDismiss(android.widget.PopupMenu);
+  public static interface PopupMenu.OnDismissListener {
+    method public void onDismiss(android.widget.PopupMenu);
   }
 
-  public static abstract interface PopupMenu.OnMenuItemClickListener {
-    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  public static interface PopupMenu.OnMenuItemClickListener {
+    method public boolean onMenuItemClick(android.view.MenuItem);
   }
 
   public class PopupWindow {
@@ -55564,13 +55995,13 @@
     method public android.graphics.drawable.Drawable getBackground();
     method public android.view.View getContentView();
     method public float getElevation();
-    method public android.transition.Transition getEnterTransition();
-    method public android.transition.Transition getExitTransition();
+    method @Nullable public android.transition.Transition getEnterTransition();
+    method @Nullable public android.transition.Transition getExitTransition();
     method public int getHeight();
     method public int getInputMethodMode();
-    method public int getMaxAvailableHeight(android.view.View);
-    method public int getMaxAvailableHeight(android.view.View, int);
-    method public int getMaxAvailableHeight(android.view.View, int, boolean);
+    method public int getMaxAvailableHeight(@NonNull android.view.View);
+    method public int getMaxAvailableHeight(@NonNull android.view.View, int);
+    method public int getMaxAvailableHeight(@NonNull android.view.View, int, boolean);
     method public boolean getOverlapAnchor();
     method public int getSoftInputMode();
     method public int getWidth();
@@ -55589,8 +56020,8 @@
     method public void setClippingEnabled(boolean);
     method public void setContentView(android.view.View);
     method public void setElevation(float);
-    method public void setEnterTransition(android.transition.Transition);
-    method public void setExitTransition(android.transition.Transition);
+    method public void setEnterTransition(@Nullable android.transition.Transition);
+    method public void setExitTransition(@Nullable android.transition.Transition);
     method public void setFocusable(boolean);
     method public void setHeight(int);
     method public void setIgnoreCheekPress();
@@ -55603,7 +56034,7 @@
     method public void setTouchInterceptor(android.view.View.OnTouchListener);
     method public void setTouchable(boolean);
     method public void setWidth(int);
-    method public deprecated void setWindowLayoutMode(int, int);
+    method @Deprecated public void setWindowLayoutMode(int, int);
     method public void setWindowLayoutType(int);
     method public void showAsDropDown(android.view.View);
     method public void showAsDropDown(android.view.View, int, int);
@@ -55620,58 +56051,56 @@
     field public static final int INPUT_METHOD_NOT_NEEDED = 2; // 0x2
   }
 
-  public static abstract interface PopupWindow.OnDismissListener {
-    method public abstract void onDismiss();
+  public static interface PopupWindow.OnDismissListener {
+    method public void onDismiss();
   }
 
-  public class ProgressBar extends android.view.View {
+  @android.widget.RemoteViews.RemoteView public class ProgressBar extends android.view.View {
     ctor public ProgressBar(android.content.Context);
     ctor public ProgressBar(android.content.Context, android.util.AttributeSet);
     ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int);
     ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int, int);
     method public android.graphics.drawable.Drawable getIndeterminateDrawable();
-    method public android.content.res.ColorStateList getIndeterminateTintList();
-    method public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
+    method @Nullable public android.content.res.ColorStateList getIndeterminateTintList();
+    method @Nullable public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
     method public android.view.animation.Interpolator getInterpolator();
-    method public synchronized int getMax();
-    method public synchronized int getMin();
-    method public synchronized int getProgress();
-    method public android.content.res.ColorStateList getProgressBackgroundTintList();
-    method public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
+    method @android.view.ViewDebug.ExportedProperty(category="progress") public int getMax();
+    method @android.view.ViewDebug.ExportedProperty(category="progress") public int getMin();
+    method @android.view.ViewDebug.ExportedProperty(category="progress") public int getProgress();
+    method @Nullable public android.content.res.ColorStateList getProgressBackgroundTintList();
+    method @Nullable public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
     method public android.graphics.drawable.Drawable getProgressDrawable();
-    method public android.content.res.ColorStateList getProgressTintList();
-    method public android.graphics.PorterDuff.Mode getProgressTintMode();
-    method public synchronized int getSecondaryProgress();
-    method public android.content.res.ColorStateList getSecondaryProgressTintList();
-    method public android.graphics.PorterDuff.Mode getSecondaryProgressTintMode();
-    method public final synchronized void incrementProgressBy(int);
-    method public final synchronized void incrementSecondaryProgressBy(int);
+    method @Nullable public android.content.res.ColorStateList getProgressTintList();
+    method @Nullable public android.graphics.PorterDuff.Mode getProgressTintMode();
+    method @android.view.ViewDebug.ExportedProperty(category="progress") public int getSecondaryProgress();
+    method @Nullable public android.content.res.ColorStateList getSecondaryProgressTintList();
+    method @Nullable public android.graphics.PorterDuff.Mode getSecondaryProgressTintMode();
+    method public final void incrementProgressBy(int);
+    method public final void incrementSecondaryProgressBy(int);
     method public boolean isAnimating();
-    method public synchronized boolean isIndeterminate();
-    method protected synchronized void onDraw(android.graphics.Canvas);
-    method protected synchronized void onMeasure(int, int);
+    method @android.view.ViewDebug.ExportedProperty(category="progress") public boolean isIndeterminate();
     method public void onRestoreInstanceState(android.os.Parcelable);
     method public android.os.Parcelable onSaveInstanceState();
-    method public synchronized void setIndeterminate(boolean);
+    method public void setIndeterminate(boolean);
     method public void setIndeterminateDrawable(android.graphics.drawable.Drawable);
     method public void setIndeterminateDrawableTiled(android.graphics.drawable.Drawable);
-    method public void setIndeterminateTintList(android.content.res.ColorStateList);
-    method public void setIndeterminateTintMode(android.graphics.PorterDuff.Mode);
-    method public void setInterpolator(android.content.Context, int);
+    method public void setIndeterminateTintList(@Nullable android.content.res.ColorStateList);
+    method public void setIndeterminateTintMode(@Nullable android.graphics.PorterDuff.Mode);
+    method public void setInterpolator(android.content.Context, @InterpolatorRes int);
     method public void setInterpolator(android.view.animation.Interpolator);
-    method public synchronized void setMax(int);
-    method public synchronized void setMin(int);
-    method public synchronized void setProgress(int);
+    method public void setMax(int);
+    method public void setMin(int);
+    method public void setProgress(int);
     method public void setProgress(int, boolean);
-    method public void setProgressBackgroundTintList(android.content.res.ColorStateList);
-    method public void setProgressBackgroundTintMode(android.graphics.PorterDuff.Mode);
+    method public void setProgressBackgroundTintList(@Nullable android.content.res.ColorStateList);
+    method public void setProgressBackgroundTintMode(@Nullable android.graphics.PorterDuff.Mode);
     method public void setProgressDrawable(android.graphics.drawable.Drawable);
     method public void setProgressDrawableTiled(android.graphics.drawable.Drawable);
-    method public void setProgressTintList(android.content.res.ColorStateList);
-    method public void setProgressTintMode(android.graphics.PorterDuff.Mode);
-    method public synchronized void setSecondaryProgress(int);
-    method public void setSecondaryProgressTintList(android.content.res.ColorStateList);
-    method public void setSecondaryProgressTintMode(android.graphics.PorterDuff.Mode);
+    method public void setProgressTintList(@Nullable android.content.res.ColorStateList);
+    method public void setProgressTintMode(@Nullable android.graphics.PorterDuff.Mode);
+    method public void setSecondaryProgress(int);
+    method public void setSecondaryProgressTintList(@Nullable android.content.res.ColorStateList);
+    method public void setSecondaryProgressTintMode(@Nullable android.graphics.PorterDuff.Mode);
   }
 
   public class QuickContactBadge extends android.widget.ImageView implements android.view.View.OnClickListener {
@@ -55679,18 +56108,18 @@
     ctor public QuickContactBadge(android.content.Context, android.util.AttributeSet);
     ctor public QuickContactBadge(android.content.Context, android.util.AttributeSet, int);
     ctor public QuickContactBadge(android.content.Context, android.util.AttributeSet, int, int);
-    method public void assignContactFromEmail(java.lang.String, boolean);
-    method public void assignContactFromEmail(java.lang.String, boolean, android.os.Bundle);
-    method public void assignContactFromPhone(java.lang.String, boolean);
-    method public void assignContactFromPhone(java.lang.String, boolean, android.os.Bundle);
+    method public void assignContactFromEmail(String, boolean);
+    method public void assignContactFromEmail(String, boolean, android.os.Bundle);
+    method public void assignContactFromPhone(String, boolean);
+    method public void assignContactFromPhone(String, boolean, android.os.Bundle);
     method public void assignContactUri(android.net.Uri);
     method public void onClick(android.view.View);
-    method public void setExcludeMimes(java.lang.String[]);
+    method public void setExcludeMimes(String[]);
     method public void setImageToDefault();
     method public void setMode(int);
     method public void setOverlay(android.graphics.drawable.Drawable);
-    method public void setPrioritizedMimeType(java.lang.String);
-    field protected java.lang.String[] mExcludeMimes;
+    method public void setPrioritizedMimeType(String);
+    field protected String[] mExcludeMimes;
   }
 
   public class RadioButton extends android.widget.CompoundButton {
@@ -55703,10 +56132,10 @@
   public class RadioGroup extends android.widget.LinearLayout {
     ctor public RadioGroup(android.content.Context);
     ctor public RadioGroup(android.content.Context, android.util.AttributeSet);
-    method public void check(int);
+    method public void check(@IdRes int);
     method public void clearCheck();
     method public android.widget.RadioGroup.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method public int getCheckedRadioButtonId();
+    method @IdRes public int getCheckedRadioButtonId();
     method public void setOnCheckedChangeListener(android.widget.RadioGroup.OnCheckedChangeListener);
   }
 
@@ -55718,8 +56147,8 @@
     ctor public RadioGroup.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
   }
 
-  public static abstract interface RadioGroup.OnCheckedChangeListener {
-    method public abstract void onCheckedChanged(android.widget.RadioGroup, int);
+  public static interface RadioGroup.OnCheckedChangeListener {
+    method public void onCheckedChanged(android.widget.RadioGroup, @IdRes int);
   }
 
   public class RatingBar extends android.widget.AbsSeekBar {
@@ -55739,11 +56168,11 @@
     method public void setStepSize(float);
   }
 
-  public static abstract interface RatingBar.OnRatingBarChangeListener {
-    method public abstract void onRatingChanged(android.widget.RatingBar, float, boolean);
+  public static interface RatingBar.OnRatingBarChangeListener {
+    method public void onRatingChanged(android.widget.RatingBar, float, boolean);
   }
 
-  public class RelativeLayout extends android.view.ViewGroup {
+  @android.widget.RemoteViews.RemoteView public class RelativeLayout extends android.view.ViewGroup {
     ctor public RelativeLayout(android.content.Context);
     ctor public RelativeLayout(android.content.Context, android.util.AttributeSet);
     ctor public RelativeLayout(android.content.Context, android.util.AttributeSet, int);
@@ -55787,91 +56216,91 @@
     ctor public RelativeLayout.LayoutParams(android.widget.RelativeLayout.LayoutParams);
     method public void addRule(int);
     method public void addRule(int, int);
-    method public java.lang.String debug(java.lang.String);
+    method public String debug(String);
     method public int getRule(int);
     method public int[] getRules();
     method public void removeRule(int);
-    field public boolean alignWithParent;
+    field @android.view.ViewDebug.ExportedProperty(category="layout") public boolean alignWithParent;
   }
 
   public class RemoteViews implements android.view.LayoutInflater.Filter android.os.Parcelable {
-    ctor public RemoteViews(java.lang.String, int);
+    ctor public RemoteViews(String, int);
     ctor public RemoteViews(android.widget.RemoteViews, android.widget.RemoteViews);
     ctor public RemoteViews(android.widget.RemoteViews);
     ctor public RemoteViews(android.os.Parcel);
     method public void addView(int, android.widget.RemoteViews);
     method public android.view.View apply(android.content.Context, android.view.ViewGroup);
-    method public deprecated android.widget.RemoteViews clone();
+    method @Deprecated public android.widget.RemoteViews clone();
     method public int describeContents();
     method public int getLayoutId();
-    method public java.lang.String getPackage();
-    method public boolean onLoadClass(java.lang.Class);
+    method public String getPackage();
+    method public boolean onLoadClass(Class);
     method public void reapply(android.content.Context, android.view.View);
     method public void removeAllViews(int);
     method public void setAccessibilityTraversalAfter(int, int);
     method public void setAccessibilityTraversalBefore(int, int);
-    method public void setBitmap(int, java.lang.String, android.graphics.Bitmap);
-    method public void setBoolean(int, java.lang.String, boolean);
-    method public void setBundle(int, java.lang.String, android.os.Bundle);
-    method public void setByte(int, java.lang.String, byte);
-    method public void setChar(int, java.lang.String, char);
-    method public void setCharSequence(int, java.lang.String, java.lang.CharSequence);
-    method public void setChronometer(int, long, java.lang.String, boolean);
+    method public void setBitmap(int, String, android.graphics.Bitmap);
+    method public void setBoolean(int, String, boolean);
+    method public void setBundle(int, String, android.os.Bundle);
+    method public void setByte(int, String, byte);
+    method public void setChar(int, String, char);
+    method public void setCharSequence(int, String, CharSequence);
+    method public void setChronometer(int, long, String, boolean);
     method public void setChronometerCountDown(int, boolean);
-    method public void setContentDescription(int, java.lang.CharSequence);
+    method public void setContentDescription(int, CharSequence);
     method public void setDisplayedChild(int, int);
-    method public void setDouble(int, java.lang.String, double);
+    method public void setDouble(int, String, double);
     method public void setEmptyView(int, int);
-    method public void setFloat(int, java.lang.String, float);
-    method public void setIcon(int, java.lang.String, android.graphics.drawable.Icon);
+    method public void setFloat(int, String, float);
+    method public void setIcon(int, String, android.graphics.drawable.Icon);
     method public void setImageViewBitmap(int, android.graphics.Bitmap);
     method public void setImageViewIcon(int, android.graphics.drawable.Icon);
     method public void setImageViewResource(int, int);
     method public void setImageViewUri(int, android.net.Uri);
-    method public void setInt(int, java.lang.String, int);
-    method public void setIntent(int, java.lang.String, android.content.Intent);
+    method public void setInt(int, String, int);
+    method public void setIntent(int, String, android.content.Intent);
     method public void setLabelFor(int, int);
-    method public void setLightBackgroundLayoutId(int);
-    method public void setLong(int, java.lang.String, long);
+    method public void setLightBackgroundLayoutId(@LayoutRes int);
+    method public void setLong(int, String, long);
     method public void setOnClickFillInIntent(int, android.content.Intent);
     method public void setOnClickPendingIntent(int, android.app.PendingIntent);
     method public void setOnClickResponse(int, android.widget.RemoteViews.RemoteResponse);
     method public void setPendingIntentTemplate(int, android.app.PendingIntent);
     method public void setProgressBar(int, int, int, boolean);
     method public void setRelativeScrollPosition(int, int);
-    method public deprecated void setRemoteAdapter(int, int, android.content.Intent);
+    method @Deprecated public void setRemoteAdapter(int, int, android.content.Intent);
     method public void setRemoteAdapter(int, android.content.Intent);
     method public void setScrollPosition(int, int);
-    method public void setShort(int, java.lang.String, short);
-    method public void setString(int, java.lang.String, java.lang.String);
-    method public void setTextColor(int, int);
+    method public void setShort(int, String, short);
+    method public void setString(int, String, String);
+    method public void setTextColor(int, @ColorInt int);
     method public void setTextViewCompoundDrawables(int, int, int, int, int);
     method public void setTextViewCompoundDrawablesRelative(int, int, int, int, int);
-    method public void setTextViewText(int, java.lang.CharSequence);
+    method public void setTextViewText(int, CharSequence);
     method public void setTextViewTextSize(int, int, float);
-    method public void setUri(int, java.lang.String, android.net.Uri);
+    method public void setUri(int, String, android.net.Uri);
     method public void setViewPadding(int, int, int, int, int);
     method public void setViewVisibility(int, int);
     method public void showNext(int);
     method public void showPrevious(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.widget.RemoteViews> CREATOR;
-    field public static final java.lang.String EXTRA_SHARED_ELEMENT_BOUNDS = "android.widget.extra.SHARED_ELEMENT_BOUNDS";
+    field public static final String EXTRA_SHARED_ELEMENT_BOUNDS = "android.widget.extra.SHARED_ELEMENT_BOUNDS";
   }
 
   public static class RemoteViews.ActionException extends java.lang.RuntimeException {
-    ctor public RemoteViews.ActionException(java.lang.Exception);
-    ctor public RemoteViews.ActionException(java.lang.String);
+    ctor public RemoteViews.ActionException(Exception);
+    ctor public RemoteViews.ActionException(String);
   }
 
   public static class RemoteViews.RemoteResponse {
     ctor public RemoteViews.RemoteResponse();
-    method public android.widget.RemoteViews.RemoteResponse addSharedElement(int, java.lang.String);
+    method public android.widget.RemoteViews.RemoteResponse addSharedElement(int, String);
     method public static android.widget.RemoteViews.RemoteResponse fromFillInIntent(android.content.Intent);
     method public static android.widget.RemoteViews.RemoteResponse fromPendingIntent(android.app.PendingIntent);
   }
 
-  public static abstract class RemoteViews.RemoteView implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface RemoteViews.RemoteView {
   }
 
   public abstract class RemoteViewsService extends android.app.Service {
@@ -55880,20 +56309,20 @@
     method public abstract android.widget.RemoteViewsService.RemoteViewsFactory onGetViewFactory(android.content.Intent);
   }
 
-  public static abstract interface RemoteViewsService.RemoteViewsFactory {
-    method public abstract int getCount();
-    method public abstract long getItemId(int);
-    method public abstract android.widget.RemoteViews getLoadingView();
-    method public abstract android.widget.RemoteViews getViewAt(int);
-    method public abstract int getViewTypeCount();
-    method public abstract boolean hasStableIds();
-    method public abstract void onCreate();
-    method public abstract void onDataSetChanged();
-    method public abstract void onDestroy();
+  public static interface RemoteViewsService.RemoteViewsFactory {
+    method public int getCount();
+    method public long getItemId(int);
+    method public android.widget.RemoteViews getLoadingView();
+    method public android.widget.RemoteViews getViewAt(int);
+    method public int getViewTypeCount();
+    method public boolean hasStableIds();
+    method public void onCreate();
+    method public void onDataSetChanged();
+    method public void onDestroy();
   }
 
   public abstract class ResourceCursorAdapter extends android.widget.CursorAdapter {
-    ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor);
+    ctor @Deprecated public ResourceCursorAdapter(android.content.Context, int, android.database.Cursor);
     ctor public ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, boolean);
     ctor public ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, int);
     method public android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
@@ -55963,8 +56392,8 @@
     method public int getImeOptions();
     method public int getInputType();
     method public int getMaxWidth();
-    method public java.lang.CharSequence getQuery();
-    method public java.lang.CharSequence getQueryHint();
+    method public CharSequence getQuery();
+    method @Nullable public CharSequence getQueryHint();
     method public android.widget.CursorAdapter getSuggestionsAdapter();
     method public boolean isIconfiedByDefault();
     method public boolean isIconified();
@@ -55982,32 +56411,32 @@
     method public void setOnQueryTextListener(android.widget.SearchView.OnQueryTextListener);
     method public void setOnSearchClickListener(android.view.View.OnClickListener);
     method public void setOnSuggestionListener(android.widget.SearchView.OnSuggestionListener);
-    method public void setQuery(java.lang.CharSequence, boolean);
-    method public void setQueryHint(java.lang.CharSequence);
+    method public void setQuery(CharSequence, boolean);
+    method public void setQueryHint(@Nullable CharSequence);
     method public void setQueryRefinementEnabled(boolean);
     method public void setSearchableInfo(android.app.SearchableInfo);
     method public void setSubmitButtonEnabled(boolean);
     method public void setSuggestionsAdapter(android.widget.CursorAdapter);
   }
 
-  public static abstract interface SearchView.OnCloseListener {
-    method public abstract boolean onClose();
+  public static interface SearchView.OnCloseListener {
+    method public boolean onClose();
   }
 
-  public static abstract interface SearchView.OnQueryTextListener {
-    method public abstract boolean onQueryTextChange(java.lang.String);
-    method public abstract boolean onQueryTextSubmit(java.lang.String);
+  public static interface SearchView.OnQueryTextListener {
+    method public boolean onQueryTextChange(String);
+    method public boolean onQueryTextSubmit(String);
   }
 
-  public static abstract interface SearchView.OnSuggestionListener {
-    method public abstract boolean onSuggestionClick(int);
-    method public abstract boolean onSuggestionSelect(int);
+  public static interface SearchView.OnSuggestionListener {
+    method public boolean onSuggestionClick(int);
+    method public boolean onSuggestionSelect(int);
   }
 
-  public abstract interface SectionIndexer {
-    method public abstract int getPositionForSection(int);
-    method public abstract int getSectionForPosition(int);
-    method public abstract java.lang.Object[] getSections();
+  public interface SectionIndexer {
+    method public int getPositionForSection(int);
+    method public int getSectionForPosition(int);
+    method public Object[] getSections();
   }
 
   public class SeekBar extends android.widget.AbsSeekBar {
@@ -56018,31 +56447,31 @@
     method public void setOnSeekBarChangeListener(android.widget.SeekBar.OnSeekBarChangeListener);
   }
 
-  public static abstract interface SeekBar.OnSeekBarChangeListener {
-    method public abstract void onProgressChanged(android.widget.SeekBar, int, boolean);
-    method public abstract void onStartTrackingTouch(android.widget.SeekBar);
-    method public abstract void onStopTrackingTouch(android.widget.SeekBar);
+  public static interface SeekBar.OnSeekBarChangeListener {
+    method public void onProgressChanged(android.widget.SeekBar, int, boolean);
+    method public void onStartTrackingTouch(android.widget.SeekBar);
+    method public void onStopTrackingTouch(android.widget.SeekBar);
   }
 
   public class ShareActionProvider extends android.view.ActionProvider {
     ctor public ShareActionProvider(android.content.Context);
     method public android.view.View onCreateActionView();
     method public void setOnShareTargetSelectedListener(android.widget.ShareActionProvider.OnShareTargetSelectedListener);
-    method public void setShareHistoryFileName(java.lang.String);
+    method public void setShareHistoryFileName(String);
     method public void setShareIntent(android.content.Intent);
-    field public static final java.lang.String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
+    field public static final String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
   }
 
-  public static abstract interface ShareActionProvider.OnShareTargetSelectedListener {
-    method public abstract boolean onShareTargetSelected(android.widget.ShareActionProvider, android.content.Intent);
+  public static interface ShareActionProvider.OnShareTargetSelectedListener {
+    method public boolean onShareTargetSelected(android.widget.ShareActionProvider, android.content.Intent);
   }
 
   public class SimpleAdapter extends android.widget.BaseAdapter implements android.widget.Filterable android.widget.ThemedSpinnerAdapter {
-    ctor public SimpleAdapter(android.content.Context, java.util.List<? extends java.util.Map<java.lang.String, ?>>, int, java.lang.String[], int[]);
+    ctor public SimpleAdapter(android.content.Context, java.util.List<? extends java.util.Map<java.lang.String,?>>, @LayoutRes int, String[], @IdRes int[]);
     method public int getCount();
     method public android.content.res.Resources.Theme getDropDownViewTheme();
     method public android.widget.Filter getFilter();
-    method public java.lang.Object getItem(int);
+    method public Object getItem(int);
     method public long getItemId(int);
     method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
     method public android.widget.SimpleAdapter.ViewBinder getViewBinder();
@@ -56050,62 +56479,62 @@
     method public void setDropDownViewTheme(android.content.res.Resources.Theme);
     method public void setViewBinder(android.widget.SimpleAdapter.ViewBinder);
     method public void setViewImage(android.widget.ImageView, int);
-    method public void setViewImage(android.widget.ImageView, java.lang.String);
-    method public void setViewText(android.widget.TextView, java.lang.String);
+    method public void setViewImage(android.widget.ImageView, String);
+    method public void setViewText(android.widget.TextView, String);
   }
 
-  public static abstract interface SimpleAdapter.ViewBinder {
-    method public abstract boolean setViewValue(android.view.View, java.lang.Object, java.lang.String);
+  public static interface SimpleAdapter.ViewBinder {
+    method public boolean setViewValue(android.view.View, Object, String);
   }
 
   public class SimpleCursorAdapter extends android.widget.ResourceCursorAdapter {
-    ctor public deprecated SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[]);
-    ctor public SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[], int);
+    ctor @Deprecated public SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, String[], int[]);
+    ctor public SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, String[], int[], int);
     method public void bindView(android.view.View, android.content.Context, android.database.Cursor);
-    method public void changeCursorAndColumns(android.database.Cursor, java.lang.String[], int[]);
+    method public void changeCursorAndColumns(android.database.Cursor, String[], int[]);
     method public android.widget.SimpleCursorAdapter.CursorToStringConverter getCursorToStringConverter();
     method public int getStringConversionColumn();
     method public android.widget.SimpleCursorAdapter.ViewBinder getViewBinder();
     method public void setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter);
     method public void setStringConversionColumn(int);
     method public void setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder);
-    method public void setViewImage(android.widget.ImageView, java.lang.String);
-    method public void setViewText(android.widget.TextView, java.lang.String);
+    method public void setViewImage(android.widget.ImageView, String);
+    method public void setViewText(android.widget.TextView, String);
   }
 
-  public static abstract interface SimpleCursorAdapter.CursorToStringConverter {
-    method public abstract java.lang.CharSequence convertToString(android.database.Cursor);
+  public static interface SimpleCursorAdapter.CursorToStringConverter {
+    method public CharSequence convertToString(android.database.Cursor);
   }
 
-  public static abstract interface SimpleCursorAdapter.ViewBinder {
-    method public abstract boolean setViewValue(android.view.View, android.database.Cursor, int);
+  public static interface SimpleCursorAdapter.ViewBinder {
+    method public boolean setViewValue(android.view.View, android.database.Cursor, int);
   }
 
   public abstract class SimpleCursorTreeAdapter extends android.widget.ResourceCursorTreeAdapter {
-    ctor public SimpleCursorTreeAdapter(android.content.Context, android.database.Cursor, int, int, java.lang.String[], int[], int, int, java.lang.String[], int[]);
-    ctor public SimpleCursorTreeAdapter(android.content.Context, android.database.Cursor, int, int, java.lang.String[], int[], int, java.lang.String[], int[]);
-    ctor public SimpleCursorTreeAdapter(android.content.Context, android.database.Cursor, int, java.lang.String[], int[], int, java.lang.String[], int[]);
+    ctor public SimpleCursorTreeAdapter(android.content.Context, android.database.Cursor, int, int, String[], int[], int, int, String[], int[]);
+    ctor public SimpleCursorTreeAdapter(android.content.Context, android.database.Cursor, int, int, String[], int[], int, String[], int[]);
+    ctor public SimpleCursorTreeAdapter(android.content.Context, android.database.Cursor, int, String[], int[], int, String[], int[]);
     method protected void bindChildView(android.view.View, android.content.Context, android.database.Cursor, boolean);
     method protected void bindGroupView(android.view.View, android.content.Context, android.database.Cursor, boolean);
     method public android.widget.SimpleCursorTreeAdapter.ViewBinder getViewBinder();
     method public void setViewBinder(android.widget.SimpleCursorTreeAdapter.ViewBinder);
-    method protected void setViewImage(android.widget.ImageView, java.lang.String);
-    method public void setViewText(android.widget.TextView, java.lang.String);
+    method protected void setViewImage(android.widget.ImageView, String);
+    method public void setViewText(android.widget.TextView, String);
   }
 
-  public static abstract interface SimpleCursorTreeAdapter.ViewBinder {
-    method public abstract boolean setViewValue(android.view.View, android.database.Cursor, int);
+  public static interface SimpleCursorTreeAdapter.ViewBinder {
+    method public boolean setViewValue(android.view.View, android.database.Cursor, int);
   }
 
   public class SimpleExpandableListAdapter extends android.widget.BaseExpandableListAdapter {
-    ctor public SimpleExpandableListAdapter(android.content.Context, java.util.List<? extends java.util.Map<java.lang.String, ?>>, int, java.lang.String[], int[], java.util.List<? extends java.util.List<? extends java.util.Map<java.lang.String, ?>>>, int, java.lang.String[], int[]);
-    ctor public SimpleExpandableListAdapter(android.content.Context, java.util.List<? extends java.util.Map<java.lang.String, ?>>, int, int, java.lang.String[], int[], java.util.List<? extends java.util.List<? extends java.util.Map<java.lang.String, ?>>>, int, java.lang.String[], int[]);
-    ctor public SimpleExpandableListAdapter(android.content.Context, java.util.List<? extends java.util.Map<java.lang.String, ?>>, int, int, java.lang.String[], int[], java.util.List<? extends java.util.List<? extends java.util.Map<java.lang.String, ?>>>, int, int, java.lang.String[], int[]);
-    method public java.lang.Object getChild(int, int);
+    ctor public SimpleExpandableListAdapter(android.content.Context, java.util.List<? extends java.util.Map<java.lang.String,?>>, int, String[], int[], java.util.List<? extends java.util.List<? extends java.util.Map<java.lang.String,?>>>, int, String[], int[]);
+    ctor public SimpleExpandableListAdapter(android.content.Context, java.util.List<? extends java.util.Map<java.lang.String,?>>, int, int, String[], int[], java.util.List<? extends java.util.List<? extends java.util.Map<java.lang.String,?>>>, int, String[], int[]);
+    ctor public SimpleExpandableListAdapter(android.content.Context, java.util.List<? extends java.util.Map<java.lang.String,?>>, int, int, String[], int[], java.util.List<? extends java.util.List<? extends java.util.Map<java.lang.String,?>>>, int, int, String[], int[]);
+    method public Object getChild(int, int);
     method public long getChildId(int, int);
     method public android.view.View getChildView(int, int, boolean, android.view.View, android.view.ViewGroup);
     method public int getChildrenCount(int);
-    method public java.lang.Object getGroup(int);
+    method public Object getGroup(int);
     method public int getGroupCount();
     method public long getGroupId(int);
     method public android.view.View getGroupView(int, boolean, android.view.View, android.view.ViewGroup);
@@ -56115,40 +56544,40 @@
     method public android.view.View newGroupView(boolean, android.view.ViewGroup);
   }
 
-  public deprecated class SlidingDrawer extends android.view.ViewGroup {
-    ctor public SlidingDrawer(android.content.Context, android.util.AttributeSet);
-    ctor public SlidingDrawer(android.content.Context, android.util.AttributeSet, int);
-    ctor public SlidingDrawer(android.content.Context, android.util.AttributeSet, int, int);
-    method public void animateClose();
-    method public void animateOpen();
-    method public void animateToggle();
-    method public void close();
-    method public android.view.View getContent();
-    method public android.view.View getHandle();
-    method public boolean isMoving();
-    method public boolean isOpened();
-    method public void lock();
-    method public void open();
-    method public void setOnDrawerCloseListener(android.widget.SlidingDrawer.OnDrawerCloseListener);
-    method public void setOnDrawerOpenListener(android.widget.SlidingDrawer.OnDrawerOpenListener);
-    method public void setOnDrawerScrollListener(android.widget.SlidingDrawer.OnDrawerScrollListener);
-    method public void toggle();
-    method public void unlock();
-    field public static final int ORIENTATION_HORIZONTAL = 0; // 0x0
-    field public static final int ORIENTATION_VERTICAL = 1; // 0x1
+  @Deprecated public class SlidingDrawer extends android.view.ViewGroup {
+    ctor @Deprecated public SlidingDrawer(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public SlidingDrawer(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public SlidingDrawer(android.content.Context, android.util.AttributeSet, int, int);
+    method @Deprecated public void animateClose();
+    method @Deprecated public void animateOpen();
+    method @Deprecated public void animateToggle();
+    method @Deprecated public void close();
+    method @Deprecated public android.view.View getContent();
+    method @Deprecated public android.view.View getHandle();
+    method @Deprecated public boolean isMoving();
+    method @Deprecated public boolean isOpened();
+    method @Deprecated public void lock();
+    method @Deprecated public void open();
+    method @Deprecated public void setOnDrawerCloseListener(android.widget.SlidingDrawer.OnDrawerCloseListener);
+    method @Deprecated public void setOnDrawerOpenListener(android.widget.SlidingDrawer.OnDrawerOpenListener);
+    method @Deprecated public void setOnDrawerScrollListener(android.widget.SlidingDrawer.OnDrawerScrollListener);
+    method @Deprecated public void toggle();
+    method @Deprecated public void unlock();
+    field @Deprecated public static final int ORIENTATION_HORIZONTAL = 0; // 0x0
+    field @Deprecated public static final int ORIENTATION_VERTICAL = 1; // 0x1
   }
 
-  public static abstract interface SlidingDrawer.OnDrawerCloseListener {
-    method public abstract void onDrawerClosed();
+  @Deprecated public static interface SlidingDrawer.OnDrawerCloseListener {
+    method @Deprecated public void onDrawerClosed();
   }
 
-  public static abstract interface SlidingDrawer.OnDrawerOpenListener {
-    method public abstract void onDrawerOpened();
+  @Deprecated public static interface SlidingDrawer.OnDrawerOpenListener {
+    method @Deprecated public void onDrawerOpened();
   }
 
-  public static abstract interface SlidingDrawer.OnDrawerScrollListener {
-    method public abstract void onScrollEnded();
-    method public abstract void onScrollStarted();
+  @Deprecated public static interface SlidingDrawer.OnDrawerScrollListener {
+    method @Deprecated public void onScrollEnded();
+    method @Deprecated public void onScrollStarted();
   }
 
   public final class Space extends android.view.View {
@@ -56172,25 +56601,25 @@
     method public int getGravity();
     method public android.graphics.drawable.Drawable getPopupBackground();
     method public android.content.Context getPopupContext();
-    method public java.lang.CharSequence getPrompt();
+    method public CharSequence getPrompt();
     method public void onClick(android.content.DialogInterface, int);
     method public void setDropDownHorizontalOffset(int);
     method public void setDropDownVerticalOffset(int);
     method public void setDropDownWidth(int);
     method public void setGravity(int);
     method public void setPopupBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setPopupBackgroundResource(int);
-    method public void setPrompt(java.lang.CharSequence);
+    method public void setPopupBackgroundResource(@DrawableRes int);
+    method public void setPrompt(CharSequence);
     method public void setPromptId(int);
     field public static final int MODE_DIALOG = 0; // 0x0
     field public static final int MODE_DROPDOWN = 1; // 0x1
   }
 
-  public abstract interface SpinnerAdapter implements android.widget.Adapter {
-    method public abstract android.view.View getDropDownView(int, android.view.View, android.view.ViewGroup);
+  public interface SpinnerAdapter extends android.widget.Adapter {
+    method public android.view.View getDropDownView(int, android.view.View, android.view.ViewGroup);
   }
 
-  public class StackView extends android.widget.AdapterViewAnimator {
+  @android.widget.RemoteViews.RemoteView public class StackView extends android.widget.AdapterViewAnimator {
     ctor public StackView(android.content.Context);
     ctor public StackView(android.content.Context, android.util.AttributeSet);
     ctor public StackView(android.content.Context, android.util.AttributeSet, int);
@@ -56206,34 +56635,34 @@
     method public boolean getSplitTrack();
     method public int getSwitchMinWidth();
     method public int getSwitchPadding();
-    method public java.lang.CharSequence getTextOff();
-    method public java.lang.CharSequence getTextOn();
+    method public CharSequence getTextOff();
+    method public CharSequence getTextOn();
     method public android.graphics.drawable.Drawable getThumbDrawable();
     method public int getThumbTextPadding();
-    method public android.content.res.ColorStateList getThumbTintList();
-    method public android.graphics.PorterDuff.Mode getThumbTintMode();
+    method @Nullable public android.content.res.ColorStateList getThumbTintList();
+    method @Nullable public android.graphics.PorterDuff.Mode getThumbTintMode();
     method public android.graphics.drawable.Drawable getTrackDrawable();
-    method public android.content.res.ColorStateList getTrackTintList();
-    method public android.graphics.PorterDuff.Mode getTrackTintMode();
+    method @Nullable public android.content.res.ColorStateList getTrackTintList();
+    method @Nullable public android.graphics.PorterDuff.Mode getTrackTintMode();
     method public void onMeasure(int, int);
     method public void setShowText(boolean);
     method public void setSplitTrack(boolean);
     method public void setSwitchMinWidth(int);
     method public void setSwitchPadding(int);
-    method public void setSwitchTextAppearance(android.content.Context, int);
+    method public void setSwitchTextAppearance(android.content.Context, @StyleRes int);
     method public void setSwitchTypeface(android.graphics.Typeface, int);
     method public void setSwitchTypeface(android.graphics.Typeface);
-    method public void setTextOff(java.lang.CharSequence);
-    method public void setTextOn(java.lang.CharSequence);
+    method public void setTextOff(CharSequence);
+    method public void setTextOn(CharSequence);
     method public void setThumbDrawable(android.graphics.drawable.Drawable);
-    method public void setThumbResource(int);
+    method public void setThumbResource(@DrawableRes int);
     method public void setThumbTextPadding(int);
-    method public void setThumbTintList(android.content.res.ColorStateList);
-    method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
+    method public void setThumbTintList(@Nullable android.content.res.ColorStateList);
+    method public void setThumbTintMode(@Nullable android.graphics.PorterDuff.Mode);
     method public void setTrackDrawable(android.graphics.drawable.Drawable);
-    method public void setTrackResource(int);
-    method public void setTrackTintList(android.content.res.ColorStateList);
-    method public void setTrackTintMode(android.graphics.PorterDuff.Mode);
+    method public void setTrackResource(@DrawableRes int);
+    method public void setTrackTintList(@Nullable android.content.res.ColorStateList);
+    method public void setTrackTintMode(@Nullable android.graphics.PorterDuff.Mode);
   }
 
   public class TabHost extends android.widget.FrameLayout implements android.view.ViewTreeObserver.OnTouchModeChangeListener {
@@ -56243,36 +56672,36 @@
     ctor public TabHost(android.content.Context, android.util.AttributeSet, int, int);
     method public void addTab(android.widget.TabHost.TabSpec);
     method public void clearAllTabs();
-    method public int getCurrentTab();
-    method public java.lang.String getCurrentTabTag();
-    method public android.view.View getCurrentTabView();
+    method @Nullable public int getCurrentTab();
+    method @Nullable public String getCurrentTabTag();
+    method @Nullable public android.view.View getCurrentTabView();
     method public android.view.View getCurrentView();
     method public android.widget.FrameLayout getTabContentView();
     method public android.widget.TabWidget getTabWidget();
-    method public android.widget.TabHost.TabSpec newTabSpec(java.lang.String);
+    method @NonNull public android.widget.TabHost.TabSpec newTabSpec(@NonNull String);
     method public void onTouchModeChanged(boolean);
     method public void setCurrentTab(int);
-    method public void setCurrentTabByTag(java.lang.String);
+    method public void setCurrentTabByTag(String);
     method public void setOnTabChangedListener(android.widget.TabHost.OnTabChangeListener);
     method public void setup();
     method public void setup(android.app.LocalActivityManager);
   }
 
-  public static abstract interface TabHost.OnTabChangeListener {
-    method public abstract void onTabChanged(java.lang.String);
+  public static interface TabHost.OnTabChangeListener {
+    method public void onTabChanged(String);
   }
 
-  public static abstract interface TabHost.TabContentFactory {
-    method public abstract android.view.View createTabContent(java.lang.String);
+  public static interface TabHost.TabContentFactory {
+    method public android.view.View createTabContent(String);
   }
 
   public class TabHost.TabSpec {
-    method public java.lang.String getTag();
+    method @NonNull public String getTag();
     method public android.widget.TabHost.TabSpec setContent(int);
     method public android.widget.TabHost.TabSpec setContent(android.widget.TabHost.TabContentFactory);
     method public android.widget.TabHost.TabSpec setContent(android.content.Intent);
-    method public android.widget.TabHost.TabSpec setIndicator(java.lang.CharSequence);
-    method public android.widget.TabHost.TabSpec setIndicator(java.lang.CharSequence, android.graphics.drawable.Drawable);
+    method public android.widget.TabHost.TabSpec setIndicator(CharSequence);
+    method public android.widget.TabHost.TabSpec setIndicator(CharSequence, android.graphics.drawable.Drawable);
     method public android.widget.TabHost.TabSpec setIndicator(android.view.View);
   }
 
@@ -56284,17 +56713,17 @@
     method public void dispatchDraw(android.graphics.Canvas);
     method public void focusCurrentTab(int);
     method public android.view.View getChildTabViewAt(int);
-    method public android.graphics.drawable.Drawable getLeftStripDrawable();
-    method public android.graphics.drawable.Drawable getRightStripDrawable();
+    method @Nullable public android.graphics.drawable.Drawable getLeftStripDrawable();
+    method @Nullable public android.graphics.drawable.Drawable getRightStripDrawable();
     method public int getTabCount();
     method public boolean isStripEnabled();
     method public void onFocusChange(android.view.View, boolean);
     method public void setCurrentTab(int);
-    method public void setDividerDrawable(int);
-    method public void setLeftStripDrawable(android.graphics.drawable.Drawable);
-    method public void setLeftStripDrawable(int);
-    method public void setRightStripDrawable(android.graphics.drawable.Drawable);
-    method public void setRightStripDrawable(int);
+    method public void setDividerDrawable(@DrawableRes int);
+    method public void setLeftStripDrawable(@Nullable android.graphics.drawable.Drawable);
+    method public void setLeftStripDrawable(@DrawableRes int);
+    method public void setRightStripDrawable(@Nullable android.graphics.drawable.Drawable);
+    method public void setRightStripDrawable(@DrawableRes int);
     method public void setStripEnabled(boolean);
   }
 
@@ -56339,41 +56768,41 @@
     ctor public TableRow.LayoutParams(int);
     ctor public TableRow.LayoutParams(android.view.ViewGroup.LayoutParams);
     ctor public TableRow.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    field public int column;
-    field public int span;
+    field @android.view.ViewDebug.ExportedProperty(category="layout") public int column;
+    field @android.view.ViewDebug.ExportedProperty(category="layout") public int span;
   }
 
-  public class TextClock extends android.widget.TextView {
+  @android.widget.RemoteViews.RemoteView public class TextClock extends android.widget.TextView {
     ctor public TextClock(android.content.Context);
     ctor public TextClock(android.content.Context, android.util.AttributeSet);
     ctor public TextClock(android.content.Context, android.util.AttributeSet, int);
     ctor public TextClock(android.content.Context, android.util.AttributeSet, int, int);
-    method public java.lang.CharSequence getFormat12Hour();
-    method public java.lang.CharSequence getFormat24Hour();
-    method public java.lang.String getTimeZone();
+    method @android.view.ViewDebug.ExportedProperty public CharSequence getFormat12Hour();
+    method @android.view.ViewDebug.ExportedProperty public CharSequence getFormat24Hour();
+    method public String getTimeZone();
     method public boolean is24HourModeEnabled();
-    method public void setFormat12Hour(java.lang.CharSequence);
-    method public void setFormat24Hour(java.lang.CharSequence);
-    method public void setTimeZone(java.lang.String);
-    field public static final deprecated java.lang.CharSequence DEFAULT_FORMAT_12_HOUR;
-    field public static final deprecated java.lang.CharSequence DEFAULT_FORMAT_24_HOUR;
+    method public void setFormat12Hour(CharSequence);
+    method public void setFormat24Hour(CharSequence);
+    method public void setTimeZone(String);
+    field @Deprecated public static final CharSequence DEFAULT_FORMAT_12_HOUR;
+    field @Deprecated public static final CharSequence DEFAULT_FORMAT_24_HOUR;
   }
 
   public class TextSwitcher extends android.widget.ViewSwitcher {
     ctor public TextSwitcher(android.content.Context);
     ctor public TextSwitcher(android.content.Context, android.util.AttributeSet);
-    method public void setCurrentText(java.lang.CharSequence);
-    method public void setText(java.lang.CharSequence);
+    method public void setCurrentText(CharSequence);
+    method public void setText(CharSequence);
   }
 
-  public class TextView extends android.view.View implements android.view.ViewTreeObserver.OnPreDrawListener {
+  @android.widget.RemoteViews.RemoteView public class TextView extends android.view.View implements android.view.ViewTreeObserver.OnPreDrawListener {
     ctor public TextView(android.content.Context);
-    ctor public TextView(android.content.Context, android.util.AttributeSet);
-    ctor public TextView(android.content.Context, android.util.AttributeSet, int);
-    ctor public TextView(android.content.Context, android.util.AttributeSet, int, int);
+    ctor public TextView(android.content.Context, @Nullable android.util.AttributeSet);
+    ctor public TextView(android.content.Context, @Nullable android.util.AttributeSet, int);
+    ctor public TextView(android.content.Context, @Nullable android.util.AttributeSet, int, int);
     method public void addTextChangedListener(android.text.TextWatcher);
-    method public final void append(java.lang.CharSequence);
-    method public void append(java.lang.CharSequence, int, int);
+    method public final void append(CharSequence);
+    method public void append(CharSequence, int, int);
     method public void beginBatchEdit();
     method public boolean bringPointIntoView(int);
     method public void clearComposingText();
@@ -56391,38 +56820,38 @@
     method public int getCompoundDrawablePadding();
     method public android.content.res.ColorStateList getCompoundDrawableTintList();
     method public android.graphics.PorterDuff.Mode getCompoundDrawableTintMode();
-    method public android.graphics.drawable.Drawable[] getCompoundDrawables();
-    method public android.graphics.drawable.Drawable[] getCompoundDrawablesRelative();
+    method @NonNull public android.graphics.drawable.Drawable[] getCompoundDrawables();
+    method @NonNull public android.graphics.drawable.Drawable[] getCompoundDrawablesRelative();
     method public int getCompoundPaddingBottom();
     method public int getCompoundPaddingEnd();
     method public int getCompoundPaddingLeft();
     method public int getCompoundPaddingRight();
     method public int getCompoundPaddingStart();
     method public int getCompoundPaddingTop();
-    method public final int getCurrentHintTextColor();
-    method public final int getCurrentTextColor();
+    method @ColorInt public final int getCurrentHintTextColor();
+    method @ColorInt public final int getCurrentTextColor();
     method public android.view.ActionMode.Callback getCustomInsertionActionModeCallback();
     method public android.view.ActionMode.Callback getCustomSelectionActionModeCallback();
     method protected boolean getDefaultEditable();
     method protected android.text.method.MovementMethod getDefaultMovementMethod();
     method public android.text.Editable getEditableText();
-    method public android.text.TextUtils.TruncateAt getEllipsize();
-    method public java.lang.CharSequence getError();
+    method @android.view.ViewDebug.ExportedProperty public android.text.TextUtils.TruncateAt getEllipsize();
+    method public CharSequence getError();
     method public int getExtendedPaddingBottom();
     method public int getExtendedPaddingTop();
     method public android.text.InputFilter[] getFilters();
     method public int getFirstBaselineToTopHeight();
-    method public java.lang.String getFontFeatureSettings();
-    method public java.lang.String getFontVariationSettings();
+    method @Nullable public String getFontFeatureSettings();
+    method @Nullable public String getFontVariationSettings();
     method public boolean getFreezesText();
     method public int getGravity();
-    method public int getHighlightColor();
-    method public java.lang.CharSequence getHint();
+    method @ColorInt public int getHighlightColor();
+    method @android.view.ViewDebug.CapturedViewProperty public CharSequence getHint();
     method public final android.content.res.ColorStateList getHintTextColors();
     method public int getHyphenationFrequency();
     method public int getImeActionId();
-    method public java.lang.CharSequence getImeActionLabel();
-    method public android.os.LocaleList getImeHintLocales();
+    method public CharSequence getImeActionLabel();
+    method @Nullable public android.os.LocaleList getImeHintLocales();
     method public int getImeOptions();
     method public boolean getIncludeFontPadding();
     method public android.os.Bundle getInputExtras(boolean);
@@ -56452,27 +56881,27 @@
     method public int getOffsetForPosition(float, float);
     method public android.text.TextPaint getPaint();
     method public int getPaintFlags();
-    method public java.lang.String getPrivateImeOptions();
-    method public int getSelectionEnd();
-    method public int getSelectionStart();
-    method public int getShadowColor();
+    method public String getPrivateImeOptions();
+    method @android.view.ViewDebug.ExportedProperty(category="text") public int getSelectionEnd();
+    method @android.view.ViewDebug.ExportedProperty(category="text") public int getSelectionStart();
+    method @ColorInt public int getShadowColor();
     method public float getShadowDx();
     method public float getShadowDy();
     method public float getShadowRadius();
     method public final boolean getShowSoftInputOnFocus();
-    method public java.lang.CharSequence getText();
-    method public android.view.textclassifier.TextClassifier getTextClassifier();
+    method @android.view.ViewDebug.CapturedViewProperty public CharSequence getText();
+    method @NonNull public android.view.textclassifier.TextClassifier getTextClassifier();
     method public final android.content.res.ColorStateList getTextColors();
-    method public android.graphics.drawable.Drawable getTextCursorDrawable();
+    method @Nullable public android.graphics.drawable.Drawable getTextCursorDrawable();
     method public android.text.TextDirectionHeuristic getTextDirectionHeuristic();
-    method public java.util.Locale getTextLocale();
-    method public android.os.LocaleList getTextLocales();
-    method public android.text.PrecomputedText.Params getTextMetricsParams();
+    method @NonNull public java.util.Locale getTextLocale();
+    method @NonNull @Size(min=1) public android.os.LocaleList getTextLocales();
+    method @NonNull public android.text.PrecomputedText.Params getTextMetricsParams();
     method public float getTextScaleX();
-    method public android.graphics.drawable.Drawable getTextSelectHandle();
-    method public android.graphics.drawable.Drawable getTextSelectHandleLeft();
-    method public android.graphics.drawable.Drawable getTextSelectHandleRight();
-    method public float getTextSize();
+    method @Nullable public android.graphics.drawable.Drawable getTextSelectHandle();
+    method @Nullable public android.graphics.drawable.Drawable getTextSelectHandleLeft();
+    method @Nullable public android.graphics.drawable.Drawable getTextSelectHandleRight();
+    method @android.view.ViewDebug.ExportedProperty(category="text") public float getTextSize();
     method public int getTotalPaddingBottom();
     method public int getTotalPaddingEnd();
     method public int getTotalPaddingLeft();
@@ -56487,7 +56916,7 @@
     method public boolean isCursorVisible();
     method public boolean isElegantTextHeight();
     method public boolean isFallbackLineSpacing();
-    method public final boolean isHorizontallyScrolling();
+    method public final boolean isHorizontallyScrollable();
     method public boolean isInputMethodTarget();
     method public boolean isSingleLine();
     method public boolean isSuggestionsEnabled();
@@ -56500,28 +56929,28 @@
     method public void onEditorAction(int);
     method public void onEndBatchEdit();
     method public boolean onPreDraw();
-    method public boolean onPrivateIMECommand(java.lang.String, android.os.Bundle);
+    method public boolean onPrivateIMECommand(String, android.os.Bundle);
     method public void onRestoreInstanceState(android.os.Parcelable);
     method public android.os.Parcelable onSaveInstanceState();
     method protected void onSelectionChanged(int, int);
-    method protected void onTextChanged(java.lang.CharSequence, int, int, int);
+    method protected void onTextChanged(CharSequence, int, int, int);
     method public boolean onTextContextMenuItem(int);
     method public void removeTextChangedListener(android.text.TextWatcher);
     method public void setAllCaps(boolean);
     method public final void setAutoLinkMask(int);
     method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int);
-    method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int);
+    method public void setAutoSizeTextTypeUniformWithPresetSizes(@NonNull int[], int);
     method public void setAutoSizeTextTypeWithDefaults(int);
     method public void setBreakStrategy(int);
     method public void setCompoundDrawablePadding(int);
-    method public void setCompoundDrawableTintList(android.content.res.ColorStateList);
-    method public void setCompoundDrawableTintMode(android.graphics.PorterDuff.Mode);
-    method public void setCompoundDrawables(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
-    method public void setCompoundDrawablesRelative(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
-    method public void setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int, int);
-    method public void setCompoundDrawablesRelativeWithIntrinsicBounds(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
-    method public void setCompoundDrawablesWithIntrinsicBounds(int, int, int, int);
-    method public void setCompoundDrawablesWithIntrinsicBounds(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+    method public void setCompoundDrawableTintList(@Nullable android.content.res.ColorStateList);
+    method public void setCompoundDrawableTintMode(@Nullable android.graphics.PorterDuff.Mode);
+    method public void setCompoundDrawables(@Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable);
+    method public void setCompoundDrawablesRelative(@Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable);
+    method public void setCompoundDrawablesRelativeWithIntrinsicBounds(@DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
+    method public void setCompoundDrawablesRelativeWithIntrinsicBounds(@Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable);
+    method public void setCompoundDrawablesWithIntrinsicBounds(@DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
+    method public void setCompoundDrawablesWithIntrinsicBounds(@Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable, @Nullable android.graphics.drawable.Drawable);
     method public void setCursorVisible(boolean);
     method public void setCustomInsertionActionModeCallback(android.view.ActionMode.Callback);
     method public void setCustomSelectionActionModeCallback(android.view.ActionMode.Callback);
@@ -56529,39 +56958,39 @@
     method public void setElegantTextHeight(boolean);
     method public void setEllipsize(android.text.TextUtils.TruncateAt);
     method public void setEms(int);
-    method public void setError(java.lang.CharSequence);
-    method public void setError(java.lang.CharSequence, android.graphics.drawable.Drawable);
+    method public void setError(CharSequence);
+    method public void setError(CharSequence, android.graphics.drawable.Drawable);
     method public void setExtractedText(android.view.inputmethod.ExtractedText);
     method public void setFallbackLineSpacing(boolean);
     method public void setFilters(android.text.InputFilter[]);
-    method public void setFirstBaselineToTopHeight(int);
-    method public void setFontFeatureSettings(java.lang.String);
-    method public boolean setFontVariationSettings(java.lang.String);
+    method public void setFirstBaselineToTopHeight(@Px @IntRange(from=0) int);
+    method public void setFontFeatureSettings(@Nullable String);
+    method public boolean setFontVariationSettings(@Nullable String);
     method protected boolean setFrame(int, int, int, int);
     method public void setFreezesText(boolean);
     method public void setGravity(int);
     method public void setHeight(int);
-    method public void setHighlightColor(int);
-    method public final void setHint(java.lang.CharSequence);
-    method public final void setHint(int);
-    method public final void setHintTextColor(int);
+    method public void setHighlightColor(@ColorInt int);
+    method public final void setHint(CharSequence);
+    method public final void setHint(@StringRes int);
+    method public final void setHintTextColor(@ColorInt int);
     method public final void setHintTextColor(android.content.res.ColorStateList);
     method public void setHorizontallyScrolling(boolean);
     method public void setHyphenationFrequency(int);
-    method public void setImeActionLabel(java.lang.CharSequence, int);
-    method public void setImeHintLocales(android.os.LocaleList);
+    method public void setImeActionLabel(CharSequence, int);
+    method public void setImeHintLocales(@Nullable android.os.LocaleList);
     method public void setImeOptions(int);
     method public void setIncludeFontPadding(boolean);
-    method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void setInputExtras(@XmlRes int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public void setInputType(int);
     method public void setJustificationMode(int);
     method public void setKeyListener(android.text.method.KeyListener);
-    method public void setLastBaselineToBottomHeight(int);
+    method public void setLastBaselineToBottomHeight(@Px @IntRange(from=0) int);
     method public void setLetterSpacing(float);
-    method public void setLineHeight(int);
+    method public void setLineHeight(@Px @IntRange(from=0) int);
     method public void setLineSpacing(float, float);
     method public void setLines(int);
-    method public final void setLinkTextColor(int);
+    method public final void setLinkTextColor(@ColorInt int);
     method public final void setLinkTextColor(android.content.res.ColorStateList);
     method public final void setLinksClickable(boolean);
     method public void setMarqueeRepeatLimit(int);
@@ -56576,7 +57005,7 @@
     method public final void setMovementMethod(android.text.method.MovementMethod);
     method public void setOnEditorActionListener(android.widget.TextView.OnEditorActionListener);
     method public void setPaintFlags(int);
-    method public void setPrivateImeOptions(java.lang.String);
+    method public void setPrivateImeOptions(String);
     method public void setRawInputType(int);
     method public void setScroller(android.widget.Scroller);
     method public void setSelectAllOnFocus(boolean);
@@ -56585,60 +57014,58 @@
     method public void setSingleLine();
     method public void setSingleLine(boolean);
     method public final void setSpannableFactory(android.text.Spannable.Factory);
-    method public final void setText(java.lang.CharSequence);
-    method public void setText(java.lang.CharSequence, android.widget.TextView.BufferType);
+    method public final void setText(CharSequence);
+    method public void setText(CharSequence, android.widget.TextView.BufferType);
     method public final void setText(char[], int, int);
-    method public final void setText(int);
-    method public final void setText(int, android.widget.TextView.BufferType);
-    method public void setTextAppearance(int);
-    method public deprecated void setTextAppearance(android.content.Context, int);
-    method public void setTextClassifier(android.view.textclassifier.TextClassifier);
-    method public void setTextColor(int);
+    method public final void setText(@StringRes int);
+    method public final void setText(@StringRes int, android.widget.TextView.BufferType);
+    method public void setTextAppearance(@StyleRes int);
+    method @Deprecated public void setTextAppearance(android.content.Context, @StyleRes int);
+    method public void setTextClassifier(@Nullable android.view.textclassifier.TextClassifier);
+    method public void setTextColor(@ColorInt int);
     method public void setTextColor(android.content.res.ColorStateList);
-    method public void setTextCursorDrawable(android.graphics.drawable.Drawable);
-    method public void setTextCursorDrawable(int);
+    method public void setTextCursorDrawable(@Nullable android.graphics.drawable.Drawable);
+    method public void setTextCursorDrawable(@DrawableRes int);
     method public void setTextIsSelectable(boolean);
-    method public final void setTextKeepState(java.lang.CharSequence);
-    method public final void setTextKeepState(java.lang.CharSequence, android.widget.TextView.BufferType);
-    method public void setTextLocale(java.util.Locale);
-    method public void setTextLocales(android.os.LocaleList);
-    method public void setTextMetricsParams(android.text.PrecomputedText.Params);
+    method public final void setTextKeepState(CharSequence);
+    method public final void setTextKeepState(CharSequence, android.widget.TextView.BufferType);
+    method public void setTextLocale(@NonNull java.util.Locale);
+    method public void setTextLocales(@NonNull @Size(min=1) android.os.LocaleList);
+    method public void setTextMetricsParams(@NonNull android.text.PrecomputedText.Params);
     method public void setTextScaleX(float);
-    method public void setTextSelectHandle(android.graphics.drawable.Drawable);
-    method public void setTextSelectHandle(int);
-    method public void setTextSelectHandleLeft(android.graphics.drawable.Drawable);
-    method public void setTextSelectHandleLeft(int);
-    method public void setTextSelectHandleRight(android.graphics.drawable.Drawable);
-    method public void setTextSelectHandleRight(int);
+    method public void setTextSelectHandle(@NonNull android.graphics.drawable.Drawable);
+    method public void setTextSelectHandle(@DrawableRes int);
+    method public void setTextSelectHandleLeft(@NonNull android.graphics.drawable.Drawable);
+    method public void setTextSelectHandleLeft(@DrawableRes int);
+    method public void setTextSelectHandleRight(@NonNull android.graphics.drawable.Drawable);
+    method public void setTextSelectHandleRight(@DrawableRes int);
     method public void setTextSize(float);
     method public void setTextSize(int, float);
     method public final void setTransformationMethod(android.text.method.TransformationMethod);
-    method public void setTypeface(android.graphics.Typeface, int);
-    method public void setTypeface(android.graphics.Typeface);
+    method public void setTypeface(@Nullable android.graphics.Typeface, int);
+    method public void setTypeface(@Nullable android.graphics.Typeface);
     method public void setWidth(int);
     field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
     field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
   }
 
-  public static final class TextView.BufferType extends java.lang.Enum {
-    method public static android.widget.TextView.BufferType valueOf(java.lang.String);
-    method public static final android.widget.TextView.BufferType[] values();
+  public enum TextView.BufferType {
     enum_constant public static final android.widget.TextView.BufferType EDITABLE;
     enum_constant public static final android.widget.TextView.BufferType NORMAL;
     enum_constant public static final android.widget.TextView.BufferType SPANNABLE;
   }
 
-  public static abstract interface TextView.OnEditorActionListener {
-    method public abstract boolean onEditorAction(android.widget.TextView, int, android.view.KeyEvent);
+  public static interface TextView.OnEditorActionListener {
+    method public boolean onEditorAction(android.widget.TextView, int, android.view.KeyEvent);
   }
 
   public static class TextView.SavedState extends android.view.View.BaseSavedState {
     field public static final android.os.Parcelable.Creator<android.widget.TextView.SavedState> CREATOR;
   }
 
-  public abstract interface ThemedSpinnerAdapter implements android.widget.SpinnerAdapter {
-    method public abstract android.content.res.Resources.Theme getDropDownViewTheme();
-    method public abstract void setDropDownViewTheme(android.content.res.Resources.Theme);
+  public interface ThemedSpinnerAdapter extends android.widget.SpinnerAdapter {
+    method @Nullable public android.content.res.Resources.Theme getDropDownViewTheme();
+    method public void setDropDownViewTheme(@Nullable android.content.res.Resources.Theme);
   }
 
   public class TimePicker extends android.widget.FrameLayout {
@@ -56646,22 +57073,22 @@
     ctor public TimePicker(android.content.Context, android.util.AttributeSet);
     ctor public TimePicker(android.content.Context, android.util.AttributeSet, int);
     ctor public TimePicker(android.content.Context, android.util.AttributeSet, int, int);
-    method public deprecated java.lang.Integer getCurrentHour();
-    method public deprecated java.lang.Integer getCurrentMinute();
+    method @Deprecated @NonNull public Integer getCurrentHour();
+    method @Deprecated @NonNull public Integer getCurrentMinute();
     method public int getHour();
     method public int getMinute();
     method public boolean is24HourView();
-    method public deprecated void setCurrentHour(java.lang.Integer);
-    method public deprecated void setCurrentMinute(java.lang.Integer);
-    method public void setHour(int);
-    method public void setIs24HourView(java.lang.Boolean);
-    method public void setMinute(int);
+    method @Deprecated public void setCurrentHour(@NonNull Integer);
+    method @Deprecated public void setCurrentMinute(@NonNull Integer);
+    method public void setHour(@IntRange(from=0, to=23) int);
+    method public void setIs24HourView(@NonNull Boolean);
+    method public void setMinute(@IntRange(from=0, to=59) int);
     method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
     method public boolean validateInput();
   }
 
-  public static abstract interface TimePicker.OnTimeChangedListener {
-    method public abstract void onTimeChanged(android.widget.TimePicker, int, int);
+  public static interface TimePicker.OnTimeChangedListener {
+    method public void onTimeChanged(android.widget.TimePicker, int, int);
   }
 
   public class Toast {
@@ -56674,13 +57101,13 @@
     method public android.view.View getView();
     method public int getXOffset();
     method public int getYOffset();
-    method public static android.widget.Toast makeText(android.content.Context, java.lang.CharSequence, int);
-    method public static android.widget.Toast makeText(android.content.Context, int, int) throws android.content.res.Resources.NotFoundException;
+    method public static android.widget.Toast makeText(android.content.Context, CharSequence, int);
+    method public static android.widget.Toast makeText(android.content.Context, @StringRes int, int) throws android.content.res.Resources.NotFoundException;
     method public void setDuration(int);
     method public void setGravity(int, int, int);
     method public void setMargin(float, float);
-    method public void setText(int);
-    method public void setText(java.lang.CharSequence);
+    method public void setText(@StringRes int);
+    method public void setText(CharSequence);
     method public void setView(android.view.View);
     method public void show();
     field public static final int LENGTH_LONG = 1; // 0x1
@@ -56692,11 +57119,11 @@
     ctor public ToggleButton(android.content.Context, android.util.AttributeSet, int);
     ctor public ToggleButton(android.content.Context, android.util.AttributeSet);
     ctor public ToggleButton(android.content.Context);
-    method public java.lang.CharSequence getTextOff();
-    method public java.lang.CharSequence getTextOn();
+    method public CharSequence getTextOff();
+    method public CharSequence getTextOn();
     method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setTextOff(java.lang.CharSequence);
-    method public void setTextOn(java.lang.CharSequence);
+    method public void setTextOff(CharSequence);
+    method public void setTextOn(CharSequence);
   }
 
   public class Toolbar extends android.view.ViewGroup {
@@ -56709,8 +57136,8 @@
     method protected android.widget.Toolbar.LayoutParams generateDefaultLayoutParams();
     method public android.widget.Toolbar.LayoutParams generateLayoutParams(android.util.AttributeSet);
     method protected android.widget.Toolbar.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public java.lang.CharSequence getCollapseContentDescription();
-    method public android.graphics.drawable.Drawable getCollapseIcon();
+    method @Nullable public CharSequence getCollapseContentDescription();
+    method @Nullable public android.graphics.drawable.Drawable getCollapseIcon();
     method public int getContentInsetEnd();
     method public int getContentInsetEndWithActions();
     method public int getContentInsetLeft();
@@ -56722,60 +57149,60 @@
     method public int getCurrentContentInsetRight();
     method public int getCurrentContentInsetStart();
     method public android.graphics.drawable.Drawable getLogo();
-    method public java.lang.CharSequence getLogoDescription();
+    method public CharSequence getLogoDescription();
     method public android.view.Menu getMenu();
-    method public java.lang.CharSequence getNavigationContentDescription();
-    method public android.graphics.drawable.Drawable getNavigationIcon();
-    method public android.graphics.drawable.Drawable getOverflowIcon();
+    method @Nullable public CharSequence getNavigationContentDescription();
+    method @Nullable public android.graphics.drawable.Drawable getNavigationIcon();
+    method @Nullable public android.graphics.drawable.Drawable getOverflowIcon();
     method public int getPopupTheme();
-    method public java.lang.CharSequence getSubtitle();
-    method public java.lang.CharSequence getTitle();
+    method public CharSequence getSubtitle();
+    method public CharSequence getTitle();
     method public int getTitleMarginBottom();
     method public int getTitleMarginEnd();
     method public int getTitleMarginStart();
     method public int getTitleMarginTop();
     method public boolean hasExpandedActionView();
     method public boolean hideOverflowMenu();
-    method public void inflateMenu(int);
+    method public void inflateMenu(@MenuRes int);
     method public boolean isOverflowMenuShowing();
-    method public void setCollapseContentDescription(int);
-    method public void setCollapseContentDescription(java.lang.CharSequence);
-    method public void setCollapseIcon(int);
-    method public void setCollapseIcon(android.graphics.drawable.Drawable);
+    method public void setCollapseContentDescription(@StringRes int);
+    method public void setCollapseContentDescription(@Nullable CharSequence);
+    method public void setCollapseIcon(@DrawableRes int);
+    method public void setCollapseIcon(@Nullable android.graphics.drawable.Drawable);
     method public void setContentInsetEndWithActions(int);
     method public void setContentInsetStartWithNavigation(int);
     method public void setContentInsetsAbsolute(int, int);
     method public void setContentInsetsRelative(int, int);
-    method public void setLogo(int);
+    method public void setLogo(@DrawableRes int);
     method public void setLogo(android.graphics.drawable.Drawable);
-    method public void setLogoDescription(int);
-    method public void setLogoDescription(java.lang.CharSequence);
-    method public void setNavigationContentDescription(int);
-    method public void setNavigationContentDescription(java.lang.CharSequence);
-    method public void setNavigationIcon(int);
-    method public void setNavigationIcon(android.graphics.drawable.Drawable);
+    method public void setLogoDescription(@StringRes int);
+    method public void setLogoDescription(CharSequence);
+    method public void setNavigationContentDescription(@StringRes int);
+    method public void setNavigationContentDescription(@Nullable CharSequence);
+    method public void setNavigationIcon(@DrawableRes int);
+    method public void setNavigationIcon(@Nullable android.graphics.drawable.Drawable);
     method public void setNavigationOnClickListener(android.view.View.OnClickListener);
     method public void setOnMenuItemClickListener(android.widget.Toolbar.OnMenuItemClickListener);
-    method public void setOverflowIcon(android.graphics.drawable.Drawable);
-    method public void setPopupTheme(int);
-    method public void setSubtitle(int);
-    method public void setSubtitle(java.lang.CharSequence);
-    method public void setSubtitleTextAppearance(android.content.Context, int);
-    method public void setSubtitleTextColor(int);
-    method public void setTitle(int);
-    method public void setTitle(java.lang.CharSequence);
+    method public void setOverflowIcon(@Nullable android.graphics.drawable.Drawable);
+    method public void setPopupTheme(@StyleRes int);
+    method public void setSubtitle(@StringRes int);
+    method public void setSubtitle(CharSequence);
+    method public void setSubtitleTextAppearance(android.content.Context, @StyleRes int);
+    method public void setSubtitleTextColor(@ColorInt int);
+    method public void setTitle(@StringRes int);
+    method public void setTitle(CharSequence);
     method public void setTitleMargin(int, int, int, int);
     method public void setTitleMarginBottom(int);
     method public void setTitleMarginEnd(int);
     method public void setTitleMarginStart(int);
     method public void setTitleMarginTop(int);
-    method public void setTitleTextAppearance(android.content.Context, int);
-    method public void setTitleTextColor(int);
+    method public void setTitleTextAppearance(android.content.Context, @StyleRes int);
+    method public void setTitleTextColor(@ColorInt int);
     method public boolean showOverflowMenu();
   }
 
   public static class Toolbar.LayoutParams extends android.app.ActionBar.LayoutParams {
-    ctor public Toolbar.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public Toolbar.LayoutParams(@NonNull android.content.Context, android.util.AttributeSet);
     ctor public Toolbar.LayoutParams(int, int);
     ctor public Toolbar.LayoutParams(int, int, int);
     ctor public Toolbar.LayoutParams(int);
@@ -56785,17 +57212,17 @@
     ctor public Toolbar.LayoutParams(android.view.ViewGroup.LayoutParams);
   }
 
-  public static abstract interface Toolbar.OnMenuItemClickListener {
-    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  public static interface Toolbar.OnMenuItemClickListener {
+    method public boolean onMenuItemClick(android.view.MenuItem);
   }
 
-  public deprecated class TwoLineListItem extends android.widget.RelativeLayout {
-    ctor public TwoLineListItem(android.content.Context);
-    ctor public TwoLineListItem(android.content.Context, android.util.AttributeSet);
-    ctor public TwoLineListItem(android.content.Context, android.util.AttributeSet, int);
-    ctor public TwoLineListItem(android.content.Context, android.util.AttributeSet, int, int);
-    method public android.widget.TextView getText1();
-    method public android.widget.TextView getText2();
+  @Deprecated public class TwoLineListItem extends android.widget.RelativeLayout {
+    ctor @Deprecated public TwoLineListItem(android.content.Context);
+    ctor @Deprecated public TwoLineListItem(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public TwoLineListItem(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public TwoLineListItem(android.content.Context, android.util.AttributeSet, int, int);
+    method @Deprecated public android.widget.TextView getText1();
+    method @Deprecated public android.widget.TextView getText2();
   }
 
   public class VideoView extends android.view.SurfaceView implements android.widget.MediaController.MediaPlayerControl {
@@ -56816,16 +57243,16 @@
     method public int resolveAdjustedSize(int, int);
     method public void resume();
     method public void seekTo(int);
-    method public void setAudioAttributes(android.media.AudioAttributes);
+    method public void setAudioAttributes(@NonNull android.media.AudioAttributes);
     method public void setAudioFocusRequest(int);
     method public void setMediaController(android.widget.MediaController);
     method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener);
     method public void setOnErrorListener(android.media.MediaPlayer.OnErrorListener);
     method public void setOnInfoListener(android.media.MediaPlayer.OnInfoListener);
     method public void setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener);
-    method public void setVideoPath(java.lang.String);
+    method public void setVideoPath(String);
     method public void setVideoURI(android.net.Uri);
-    method public void setVideoURI(android.net.Uri, java.util.Map<java.lang.String, java.lang.String>);
+    method public void setVideoURI(android.net.Uri, java.util.Map<java.lang.String,java.lang.String>);
     method public void start();
     method public void stopPlayback();
     method public void suspend();
@@ -56842,14 +57269,14 @@
     method public void setAnimateFirstView(boolean);
     method public void setDisplayedChild(int);
     method public void setInAnimation(android.view.animation.Animation);
-    method public void setInAnimation(android.content.Context, int);
+    method public void setInAnimation(android.content.Context, @AnimRes int);
     method public void setOutAnimation(android.view.animation.Animation);
-    method public void setOutAnimation(android.content.Context, int);
+    method public void setOutAnimation(android.content.Context, @AnimRes int);
     method public void showNext();
     method public void showPrevious();
   }
 
-  public class ViewFlipper extends android.widget.ViewAnimator {
+  @android.widget.RemoteViews.RemoteView public class ViewFlipper extends android.widget.ViewAnimator {
     ctor public ViewFlipper(android.content.Context);
     ctor public ViewFlipper(android.content.Context, android.util.AttributeSet);
     method public boolean isAutoStart();
@@ -56868,42 +57295,42 @@
     method public void setFactory(android.widget.ViewSwitcher.ViewFactory);
   }
 
-  public static abstract interface ViewSwitcher.ViewFactory {
-    method public abstract android.view.View makeView();
+  public static interface ViewSwitcher.ViewFactory {
+    method public android.view.View makeView();
   }
 
-  public abstract interface WrapperListAdapter implements android.widget.ListAdapter {
-    method public abstract android.widget.ListAdapter getWrappedAdapter();
+  public interface WrapperListAdapter extends android.widget.ListAdapter {
+    method public android.widget.ListAdapter getWrappedAdapter();
   }
 
-  public deprecated class ZoomButton extends android.widget.ImageButton implements android.view.View.OnLongClickListener {
-    ctor public ZoomButton(android.content.Context);
-    ctor public ZoomButton(android.content.Context, android.util.AttributeSet);
-    ctor public ZoomButton(android.content.Context, android.util.AttributeSet, int);
-    ctor public ZoomButton(android.content.Context, android.util.AttributeSet, int, int);
-    method public boolean onLongClick(android.view.View);
-    method public void setZoomSpeed(long);
+  @Deprecated public class ZoomButton extends android.widget.ImageButton implements android.view.View.OnLongClickListener {
+    ctor @Deprecated public ZoomButton(android.content.Context);
+    ctor @Deprecated public ZoomButton(android.content.Context, android.util.AttributeSet);
+    ctor @Deprecated public ZoomButton(android.content.Context, android.util.AttributeSet, int);
+    ctor @Deprecated public ZoomButton(android.content.Context, android.util.AttributeSet, int, int);
+    method @Deprecated public boolean onLongClick(android.view.View);
+    method @Deprecated public void setZoomSpeed(long);
   }
 
-  public deprecated class ZoomButtonsController implements android.view.View.OnTouchListener {
-    ctor public ZoomButtonsController(android.view.View);
-    method public android.view.ViewGroup getContainer();
-    method public android.view.View getZoomControls();
-    method public boolean isAutoDismissed();
-    method public boolean isVisible();
+  @Deprecated public class ZoomButtonsController implements android.view.View.OnTouchListener {
+    ctor @Deprecated public ZoomButtonsController(android.view.View);
+    method @Deprecated public android.view.ViewGroup getContainer();
+    method @Deprecated public android.view.View getZoomControls();
+    method @Deprecated public boolean isAutoDismissed();
+    method @Deprecated public boolean isVisible();
     method public boolean onTouch(android.view.View, android.view.MotionEvent);
-    method public void setAutoDismissed(boolean);
-    method public void setFocusable(boolean);
-    method public void setOnZoomListener(android.widget.ZoomButtonsController.OnZoomListener);
-    method public void setVisible(boolean);
-    method public void setZoomInEnabled(boolean);
-    method public void setZoomOutEnabled(boolean);
-    method public void setZoomSpeed(long);
+    method @Deprecated public void setAutoDismissed(boolean);
+    method @Deprecated public void setFocusable(boolean);
+    method @Deprecated public void setOnZoomListener(android.widget.ZoomButtonsController.OnZoomListener);
+    method @Deprecated public void setVisible(boolean);
+    method @Deprecated public void setZoomInEnabled(boolean);
+    method @Deprecated public void setZoomOutEnabled(boolean);
+    method @Deprecated public void setZoomSpeed(long);
   }
 
-  public static abstract interface ZoomButtonsController.OnZoomListener {
-    method public abstract void onVisibilityChanged(boolean);
-    method public abstract void onZoom(boolean);
+  @Deprecated public static interface ZoomButtonsController.OnZoomListener {
+    method @Deprecated public void onVisibilityChanged(boolean);
+    method @Deprecated public void onZoom(boolean);
   }
 
   public class ZoomControls extends android.widget.LinearLayout {
@@ -56922,10 +57349,14 @@
 
 package dalvik.annotation {
 
-  public abstract deprecated class TestTarget implements java.lang.annotation.Annotation {
+  @Deprecated @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.ANNOTATION_TYPE}) public @interface TestTarget {
+    method @Deprecated public abstract String conceptName() default "";
+    method @Deprecated public abstract Class<?>[] methodArgs() default {};
+    method @Deprecated public abstract String methodName() default "";
   }
 
-  public abstract deprecated class TestTargetClass implements java.lang.annotation.Annotation {
+  @Deprecated @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public @interface TestTargetClass {
+    method @Deprecated public abstract Class<?> value();
   }
 
 }
@@ -56937,7 +57368,7 @@
     field public static final int MAXIMUM_VALUE;
   }
 
-  public abstract interface Opcodes {
+  public interface Opcodes {
     field public static final int OP_ADD_DOUBLE = 171; // 0xab
     field public static final int OP_ADD_DOUBLE_2ADDR = 203; // 0xcb
     field public static final int OP_ADD_FLOAT = 166; // 0xa6
@@ -56969,7 +57400,7 @@
     field public static final int OP_APUT_SHORT = 81; // 0x51
     field public static final int OP_APUT_WIDE = 76; // 0x4c
     field public static final int OP_ARRAY_LENGTH = 33; // 0x21
-    field public static final deprecated int OP_BREAKPOINT = 236; // 0xec
+    field @Deprecated public static final int OP_BREAKPOINT = 236; // 0xec
     field public static final int OP_CHECK_CAST = 31; // 0x1f
     field public static final int OP_CHECK_CAST_JUMBO = 511; // 0x1ff
     field public static final int OP_CMPG_DOUBLE = 48; // 0x30
@@ -57004,8 +57435,8 @@
     field public static final int OP_DOUBLE_TO_FLOAT = 140; // 0x8c
     field public static final int OP_DOUBLE_TO_INT = 138; // 0x8a
     field public static final int OP_DOUBLE_TO_LONG = 139; // 0x8b
-    field public static final deprecated int OP_EXECUTE_INLINE = 238; // 0xee
-    field public static final deprecated int OP_EXECUTE_INLINE_RANGE = 239; // 0xef
+    field @Deprecated public static final int OP_EXECUTE_INLINE = 238; // 0xee
+    field @Deprecated public static final int OP_EXECUTE_INLINE_RANGE = 239; // 0xef
     field public static final int OP_FILLED_NEW_ARRAY = 36; // 0x24
     field public static final int OP_FILLED_NEW_ARRAY_JUMBO = 1535; // 0x5ff
     field public static final int OP_FILLED_NEW_ARRAY_RANGE = 37; // 0x25
@@ -57038,14 +57469,14 @@
     field public static final int OP_IGET_JUMBO = 1791; // 0x6ff
     field public static final int OP_IGET_OBJECT = 84; // 0x54
     field public static final int OP_IGET_OBJECT_JUMBO = 2303; // 0x8ff
-    field public static final deprecated int OP_IGET_OBJECT_QUICK = 244; // 0xf4
-    field public static final deprecated int OP_IGET_QUICK = 242; // 0xf2
+    field @Deprecated public static final int OP_IGET_OBJECT_QUICK = 244; // 0xf4
+    field @Deprecated public static final int OP_IGET_QUICK = 242; // 0xf2
     field public static final int OP_IGET_SHORT = 88; // 0x58
     field public static final int OP_IGET_SHORT_JUMBO = 3327; // 0xcff
     field public static final int OP_IGET_WIDE = 83; // 0x53
     field public static final int OP_IGET_WIDE_JUMBO = 2047; // 0x7ff
-    field public static final deprecated int OP_IGET_WIDE_QUICK = 243; // 0xf3
-    field public static final deprecated int OP_IGET_WIDE_VOLATILE = 232; // 0xe8
+    field @Deprecated public static final int OP_IGET_WIDE_QUICK = 243; // 0xf3
+    field @Deprecated public static final int OP_IGET_WIDE_VOLATILE = 232; // 0xe8
     field public static final int OP_INSTANCE_OF = 32; // 0x20
     field public static final int OP_INSTANCE_OF_JUMBO = 767; // 0x2ff
     field public static final int OP_INT_TO_BYTE = 141; // 0x8d
@@ -57057,7 +57488,7 @@
     field public static final int OP_INVOKE_CUSTOM = 252; // 0xfc
     field public static final int OP_INVOKE_CUSTOM_RANGE = 253; // 0xfd
     field public static final int OP_INVOKE_DIRECT = 112; // 0x70
-    field public static final deprecated int OP_INVOKE_DIRECT_EMPTY = 240; // 0xf0
+    field @Deprecated public static final int OP_INVOKE_DIRECT_EMPTY = 240; // 0xf0
     field public static final int OP_INVOKE_DIRECT_JUMBO = 9471; // 0x24ff
     field public static final int OP_INVOKE_DIRECT_RANGE = 118; // 0x76
     field public static final int OP_INVOKE_INTERFACE = 114; // 0x72
@@ -57070,13 +57501,13 @@
     field public static final int OP_INVOKE_STATIC_RANGE = 119; // 0x77
     field public static final int OP_INVOKE_SUPER = 111; // 0x6f
     field public static final int OP_INVOKE_SUPER_JUMBO = 9215; // 0x23ff
-    field public static final deprecated int OP_INVOKE_SUPER_QUICK = 250; // 0xfa
-    field public static final deprecated int OP_INVOKE_SUPER_QUICK_RANGE = 251; // 0xfb
+    field @Deprecated public static final int OP_INVOKE_SUPER_QUICK = 250; // 0xfa
+    field @Deprecated public static final int OP_INVOKE_SUPER_QUICK_RANGE = 251; // 0xfb
     field public static final int OP_INVOKE_SUPER_RANGE = 117; // 0x75
     field public static final int OP_INVOKE_VIRTUAL = 110; // 0x6e
     field public static final int OP_INVOKE_VIRTUAL_JUMBO = 8959; // 0x22ff
-    field public static final deprecated int OP_INVOKE_VIRTUAL_QUICK = 248; // 0xf8
-    field public static final deprecated int OP_INVOKE_VIRTUAL_QUICK_RANGE = 249; // 0xf9
+    field @Deprecated public static final int OP_INVOKE_VIRTUAL_QUICK = 248; // 0xf8
+    field @Deprecated public static final int OP_INVOKE_VIRTUAL_QUICK_RANGE = 249; // 0xf9
     field public static final int OP_INVOKE_VIRTUAL_RANGE = 116; // 0x74
     field public static final int OP_IPUT = 89; // 0x59
     field public static final int OP_IPUT_BOOLEAN = 92; // 0x5c
@@ -57088,14 +57519,14 @@
     field public static final int OP_IPUT_JUMBO = 3583; // 0xdff
     field public static final int OP_IPUT_OBJECT = 91; // 0x5b
     field public static final int OP_IPUT_OBJECT_JUMBO = 4095; // 0xfff
-    field public static final deprecated int OP_IPUT_OBJECT_QUICK = 247; // 0xf7
-    field public static final deprecated int OP_IPUT_QUICK = 245; // 0xf5
+    field @Deprecated public static final int OP_IPUT_OBJECT_QUICK = 247; // 0xf7
+    field @Deprecated public static final int OP_IPUT_QUICK = 245; // 0xf5
     field public static final int OP_IPUT_SHORT = 95; // 0x5f
     field public static final int OP_IPUT_SHORT_JUMBO = 5119; // 0x13ff
     field public static final int OP_IPUT_WIDE = 90; // 0x5a
     field public static final int OP_IPUT_WIDE_JUMBO = 3839; // 0xeff
-    field public static final deprecated int OP_IPUT_WIDE_QUICK = 246; // 0xf6
-    field public static final deprecated int OP_IPUT_WIDE_VOLATILE = 233; // 0xe9
+    field @Deprecated public static final int OP_IPUT_WIDE_QUICK = 246; // 0xf6
+    field @Deprecated public static final int OP_IPUT_WIDE_VOLATILE = 233; // 0xe9
     field public static final int OP_LONG_TO_DOUBLE = 134; // 0x86
     field public static final int OP_LONG_TO_FLOAT = 133; // 0x85
     field public static final int OP_LONG_TO_INT = 132; // 0x84
@@ -57172,7 +57603,7 @@
     field public static final int OP_SGET_SHORT_JUMBO = 6911; // 0x1aff
     field public static final int OP_SGET_WIDE = 97; // 0x61
     field public static final int OP_SGET_WIDE_JUMBO = 5631; // 0x15ff
-    field public static final deprecated int OP_SGET_WIDE_VOLATILE = 234; // 0xea
+    field @Deprecated public static final int OP_SGET_WIDE_VOLATILE = 234; // 0xea
     field public static final int OP_SHL_INT = 152; // 0x98
     field public static final int OP_SHL_INT_2ADDR = 184; // 0xb8
     field public static final int OP_SHL_INT_LIT8 = 224; // 0xe0
@@ -57198,7 +57629,7 @@
     field public static final int OP_SPUT_SHORT_JUMBO = 8703; // 0x21ff
     field public static final int OP_SPUT_WIDE = 104; // 0x68
     field public static final int OP_SPUT_WIDE_JUMBO = 7423; // 0x1cff
-    field public static final deprecated int OP_SPUT_WIDE_VOLATILE = 235; // 0xeb
+    field @Deprecated public static final int OP_SPUT_WIDE_VOLATILE = 235; // 0xeb
     field public static final int OP_SUB_DOUBLE = 172; // 0xac
     field public static final int OP_SUB_DOUBLE_2ADDR = 204; // 0xcc
     field public static final int OP_SUB_FLOAT = 167; // 0xa7
@@ -57208,7 +57639,7 @@
     field public static final int OP_SUB_LONG = 156; // 0x9c
     field public static final int OP_SUB_LONG_2ADDR = 188; // 0xbc
     field public static final int OP_THROW = 39; // 0x27
-    field public static final deprecated int OP_THROW_VERIFICATION_ERROR = 237; // 0xed
+    field @Deprecated public static final int OP_THROW_VERIFICATION_ERROR = 237; // 0xed
     field public static final int OP_USHR_INT = 154; // 0x9a
     field public static final int OP_USHR_INT_2ADDR = 186; // 0xba
     field public static final int OP_USHR_INT_LIT8 = 226; // 0xe2
@@ -57227,42 +57658,41 @@
 package dalvik.system {
 
   public class BaseDexClassLoader extends java.lang.ClassLoader {
-    ctor public BaseDexClassLoader(java.lang.String, java.io.File, java.lang.String, java.lang.ClassLoader);
-    method public java.lang.String findLibrary(java.lang.String);
-    method protected java.util.Enumeration<java.net.URL> findResources(java.lang.String);
-    method protected synchronized java.lang.Package getPackage(java.lang.String);
+    ctor public BaseDexClassLoader(String, java.io.File, String, ClassLoader);
+    method public String findLibrary(String);
+    method protected java.util.Enumeration<java.net.URL> findResources(String);
   }
 
   public final class DelegateLastClassLoader extends dalvik.system.PathClassLoader {
-    ctor public DelegateLastClassLoader(java.lang.String, java.lang.ClassLoader);
-    ctor public DelegateLastClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader);
-    ctor public DelegateLastClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader, boolean);
+    ctor public DelegateLastClassLoader(String, ClassLoader);
+    ctor public DelegateLastClassLoader(String, String, ClassLoader);
+    ctor public DelegateLastClassLoader(String, String, ClassLoader, boolean);
   }
 
   public class DexClassLoader extends dalvik.system.BaseDexClassLoader {
-    ctor public DexClassLoader(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader);
+    ctor public DexClassLoader(String, String, String, ClassLoader);
   }
 
-  public final deprecated class DexFile {
-    ctor public deprecated DexFile(java.io.File) throws java.io.IOException;
-    ctor public deprecated DexFile(java.lang.String) throws java.io.IOException;
-    method public void close() throws java.io.IOException;
-    method public java.util.Enumeration<java.lang.String> entries();
-    method public java.lang.String getName();
-    method public static boolean isDexOptNeeded(java.lang.String) throws java.io.FileNotFoundException, java.io.IOException;
-    method public java.lang.Class loadClass(java.lang.String, java.lang.ClassLoader);
-    method public static deprecated dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
+  @Deprecated public final class DexFile {
+    ctor @Deprecated public DexFile(java.io.File) throws java.io.IOException;
+    ctor @Deprecated public DexFile(String) throws java.io.IOException;
+    method @Deprecated public void close() throws java.io.IOException;
+    method @Deprecated public java.util.Enumeration<java.lang.String> entries();
+    method @Deprecated public String getName();
+    method @Deprecated public static boolean isDexOptNeeded(String) throws java.io.FileNotFoundException, java.io.IOException;
+    method @Deprecated public Class loadClass(String, ClassLoader);
+    method @Deprecated public static dalvik.system.DexFile loadDex(String, String, int) throws java.io.IOException;
   }
 
   public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
-    ctor public InMemoryDexClassLoader(java.nio.ByteBuffer[], java.lang.String, java.lang.ClassLoader);
-    ctor public InMemoryDexClassLoader(java.nio.ByteBuffer[], java.lang.ClassLoader);
-    ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
+    ctor public InMemoryDexClassLoader(@NonNull java.nio.ByteBuffer[], @Nullable String, @Nullable ClassLoader);
+    ctor public InMemoryDexClassLoader(@NonNull java.nio.ByteBuffer[], @Nullable ClassLoader);
+    ctor public InMemoryDexClassLoader(@NonNull java.nio.ByteBuffer, @Nullable ClassLoader);
   }
 
   public class PathClassLoader extends dalvik.system.BaseDexClassLoader {
-    ctor public PathClassLoader(java.lang.String, java.lang.ClassLoader);
-    ctor public PathClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader);
+    ctor public PathClassLoader(String, ClassLoader);
+    ctor public PathClassLoader(String, String, ClassLoader);
   }
 
 }
@@ -57304,9 +57734,7 @@
     field public static final int TIBETAN = 16384; // 0x4000
   }
 
-  public static class NumericShaper.Range extends java.lang.Enum {
-    method public static java.awt.font.NumericShaper.Range valueOf(java.lang.String);
-    method public static final java.awt.font.NumericShaper.Range[] values();
+  public enum NumericShaper.Range {
     enum_constant public static final java.awt.font.NumericShaper.Range ARABIC;
     enum_constant public static final java.awt.font.NumericShaper.Range BALINESE;
     enum_constant public static final java.awt.font.NumericShaper.Range BENGALI;
@@ -57345,7 +57773,7 @@
   }
 
   public final class TextAttribute extends java.text.AttributedCharacterIterator.Attribute {
-    ctor protected TextAttribute(java.lang.String);
+    ctor protected TextAttribute(String);
     field public static final java.awt.font.TextAttribute BACKGROUND;
     field public static final java.awt.font.TextAttribute BIDI_EMBEDDING;
     field public static final java.awt.font.TextAttribute CHAR_REPLACEMENT;
@@ -57355,56 +57783,56 @@
     field public static final java.awt.font.TextAttribute INPUT_METHOD_HIGHLIGHT;
     field public static final java.awt.font.TextAttribute INPUT_METHOD_UNDERLINE;
     field public static final java.awt.font.TextAttribute JUSTIFICATION;
-    field public static final java.lang.Float JUSTIFICATION_FULL;
-    field public static final java.lang.Float JUSTIFICATION_NONE;
+    field public static final Float JUSTIFICATION_FULL;
+    field public static final Float JUSTIFICATION_NONE;
     field public static final java.awt.font.TextAttribute KERNING;
-    field public static final java.lang.Integer KERNING_ON;
+    field public static final Integer KERNING_ON;
     field public static final java.awt.font.TextAttribute LIGATURES;
-    field public static final java.lang.Integer LIGATURES_ON;
+    field public static final Integer LIGATURES_ON;
     field public static final java.awt.font.TextAttribute NUMERIC_SHAPING;
     field public static final java.awt.font.TextAttribute POSTURE;
-    field public static final java.lang.Float POSTURE_OBLIQUE;
-    field public static final java.lang.Float POSTURE_REGULAR;
+    field public static final Float POSTURE_OBLIQUE;
+    field public static final Float POSTURE_REGULAR;
     field public static final java.awt.font.TextAttribute RUN_DIRECTION;
-    field public static final java.lang.Boolean RUN_DIRECTION_LTR;
-    field public static final java.lang.Boolean RUN_DIRECTION_RTL;
+    field public static final Boolean RUN_DIRECTION_LTR;
+    field public static final Boolean RUN_DIRECTION_RTL;
     field public static final java.awt.font.TextAttribute SIZE;
     field public static final java.awt.font.TextAttribute STRIKETHROUGH;
-    field public static final java.lang.Boolean STRIKETHROUGH_ON;
+    field public static final Boolean STRIKETHROUGH_ON;
     field public static final java.awt.font.TextAttribute SUPERSCRIPT;
-    field public static final java.lang.Integer SUPERSCRIPT_SUB;
-    field public static final java.lang.Integer SUPERSCRIPT_SUPER;
+    field public static final Integer SUPERSCRIPT_SUB;
+    field public static final Integer SUPERSCRIPT_SUPER;
     field public static final java.awt.font.TextAttribute SWAP_COLORS;
-    field public static final java.lang.Boolean SWAP_COLORS_ON;
+    field public static final Boolean SWAP_COLORS_ON;
     field public static final java.awt.font.TextAttribute TRACKING;
-    field public static final java.lang.Float TRACKING_LOOSE;
-    field public static final java.lang.Float TRACKING_TIGHT;
+    field public static final Float TRACKING_LOOSE;
+    field public static final Float TRACKING_TIGHT;
     field public static final java.awt.font.TextAttribute TRANSFORM;
     field public static final java.awt.font.TextAttribute UNDERLINE;
-    field public static final java.lang.Integer UNDERLINE_LOW_DASHED;
-    field public static final java.lang.Integer UNDERLINE_LOW_DOTTED;
-    field public static final java.lang.Integer UNDERLINE_LOW_GRAY;
-    field public static final java.lang.Integer UNDERLINE_LOW_ONE_PIXEL;
-    field public static final java.lang.Integer UNDERLINE_LOW_TWO_PIXEL;
-    field public static final java.lang.Integer UNDERLINE_ON;
+    field public static final Integer UNDERLINE_LOW_DASHED;
+    field public static final Integer UNDERLINE_LOW_DOTTED;
+    field public static final Integer UNDERLINE_LOW_GRAY;
+    field public static final Integer UNDERLINE_LOW_ONE_PIXEL;
+    field public static final Integer UNDERLINE_LOW_TWO_PIXEL;
+    field public static final Integer UNDERLINE_ON;
     field public static final java.awt.font.TextAttribute WEIGHT;
-    field public static final java.lang.Float WEIGHT_BOLD;
-    field public static final java.lang.Float WEIGHT_DEMIBOLD;
-    field public static final java.lang.Float WEIGHT_DEMILIGHT;
-    field public static final java.lang.Float WEIGHT_EXTRABOLD;
-    field public static final java.lang.Float WEIGHT_EXTRA_LIGHT;
-    field public static final java.lang.Float WEIGHT_HEAVY;
-    field public static final java.lang.Float WEIGHT_LIGHT;
-    field public static final java.lang.Float WEIGHT_MEDIUM;
-    field public static final java.lang.Float WEIGHT_REGULAR;
-    field public static final java.lang.Float WEIGHT_SEMIBOLD;
-    field public static final java.lang.Float WEIGHT_ULTRABOLD;
+    field public static final Float WEIGHT_BOLD;
+    field public static final Float WEIGHT_DEMIBOLD;
+    field public static final Float WEIGHT_DEMILIGHT;
+    field public static final Float WEIGHT_EXTRABOLD;
+    field public static final Float WEIGHT_EXTRA_LIGHT;
+    field public static final Float WEIGHT_HEAVY;
+    field public static final Float WEIGHT_LIGHT;
+    field public static final Float WEIGHT_MEDIUM;
+    field public static final Float WEIGHT_REGULAR;
+    field public static final Float WEIGHT_SEMIBOLD;
+    field public static final Float WEIGHT_ULTRABOLD;
     field public static final java.awt.font.TextAttribute WIDTH;
-    field public static final java.lang.Float WIDTH_CONDENSED;
-    field public static final java.lang.Float WIDTH_EXTENDED;
-    field public static final java.lang.Float WIDTH_REGULAR;
-    field public static final java.lang.Float WIDTH_SEMI_CONDENSED;
-    field public static final java.lang.Float WIDTH_SEMI_EXTENDED;
+    field public static final Float WIDTH_CONDENSED;
+    field public static final Float WIDTH_EXTENDED;
+    field public static final Float WIDTH_REGULAR;
+    field public static final Float WIDTH_SEMI_CONDENSED;
+    field public static final Float WIDTH_SEMI_EXTENDED;
   }
 
 }
@@ -57412,45 +57840,45 @@
 package java.beans {
 
   public class IndexedPropertyChangeEvent extends java.beans.PropertyChangeEvent {
-    ctor public IndexedPropertyChangeEvent(java.lang.Object, java.lang.String, java.lang.Object, java.lang.Object, int);
+    ctor public IndexedPropertyChangeEvent(Object, String, Object, Object, int);
     method public int getIndex();
   }
 
   public class PropertyChangeEvent extends java.util.EventObject {
-    ctor public PropertyChangeEvent(java.lang.Object, java.lang.String, java.lang.Object, java.lang.Object);
-    method public java.lang.Object getNewValue();
-    method public java.lang.Object getOldValue();
-    method public java.lang.Object getPropagationId();
-    method public java.lang.String getPropertyName();
-    method public void setPropagationId(java.lang.Object);
+    ctor public PropertyChangeEvent(Object, String, Object, Object);
+    method public Object getNewValue();
+    method public Object getOldValue();
+    method public Object getPropagationId();
+    method public String getPropertyName();
+    method public void setPropagationId(Object);
   }
 
-  public abstract interface PropertyChangeListener implements java.util.EventListener {
-    method public abstract void propertyChange(java.beans.PropertyChangeEvent);
+  public interface PropertyChangeListener extends java.util.EventListener {
+    method public void propertyChange(java.beans.PropertyChangeEvent);
   }
 
-  public class PropertyChangeListenerProxy extends java.util.EventListenerProxy implements java.beans.PropertyChangeListener {
-    ctor public PropertyChangeListenerProxy(java.lang.String, java.beans.PropertyChangeListener);
-    method public java.lang.String getPropertyName();
+  public class PropertyChangeListenerProxy extends java.util.EventListenerProxy<java.beans.PropertyChangeListener> implements java.beans.PropertyChangeListener {
+    ctor public PropertyChangeListenerProxy(String, java.beans.PropertyChangeListener);
+    method public String getPropertyName();
     method public void propertyChange(java.beans.PropertyChangeEvent);
   }
 
   public class PropertyChangeSupport implements java.io.Serializable {
-    ctor public PropertyChangeSupport(java.lang.Object);
+    ctor public PropertyChangeSupport(Object);
     method public void addPropertyChangeListener(java.beans.PropertyChangeListener);
-    method public void addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener);
-    method public void fireIndexedPropertyChange(java.lang.String, int, java.lang.Object, java.lang.Object);
-    method public void fireIndexedPropertyChange(java.lang.String, int, int, int);
-    method public void fireIndexedPropertyChange(java.lang.String, int, boolean, boolean);
-    method public void firePropertyChange(java.lang.String, java.lang.Object, java.lang.Object);
-    method public void firePropertyChange(java.lang.String, int, int);
-    method public void firePropertyChange(java.lang.String, boolean, boolean);
+    method public void addPropertyChangeListener(String, java.beans.PropertyChangeListener);
+    method public void fireIndexedPropertyChange(String, int, Object, Object);
+    method public void fireIndexedPropertyChange(String, int, int, int);
+    method public void fireIndexedPropertyChange(String, int, boolean, boolean);
+    method public void firePropertyChange(String, Object, Object);
+    method public void firePropertyChange(String, int, int);
+    method public void firePropertyChange(String, boolean, boolean);
     method public void firePropertyChange(java.beans.PropertyChangeEvent);
     method public java.beans.PropertyChangeListener[] getPropertyChangeListeners();
-    method public java.beans.PropertyChangeListener[] getPropertyChangeListeners(java.lang.String);
-    method public boolean hasListeners(java.lang.String);
+    method public java.beans.PropertyChangeListener[] getPropertyChangeListeners(String);
+    method public boolean hasListeners(String);
     method public void removePropertyChangeListener(java.beans.PropertyChangeListener);
-    method public void removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener);
+    method public void removePropertyChangeListener(String, java.beans.PropertyChangeListener);
   }
 
 }
@@ -57460,10 +57888,6 @@
   public class BufferedInputStream extends java.io.FilterInputStream {
     ctor public BufferedInputStream(java.io.InputStream);
     ctor public BufferedInputStream(java.io.InputStream, int);
-    method public synchronized int available() throws java.io.IOException;
-    method public synchronized int read() throws java.io.IOException;
-    method public synchronized int read(byte[], int, int) throws java.io.IOException;
-    method public synchronized long skip(long) throws java.io.IOException;
     field protected volatile byte[] buf;
     field protected int count;
     field protected int marklimit;
@@ -57474,9 +57898,6 @@
   public class BufferedOutputStream extends java.io.FilterOutputStream {
     ctor public BufferedOutputStream(java.io.OutputStream);
     ctor public BufferedOutputStream(java.io.OutputStream, int);
-    method public synchronized void flush() throws java.io.IOException;
-    method public synchronized void write(int) throws java.io.IOException;
-    method public synchronized void write(byte[], int, int) throws java.io.IOException;
     field protected byte[] buf;
     field protected int count;
   }
@@ -57487,7 +57908,7 @@
     method public void close() throws java.io.IOException;
     method public java.util.stream.Stream<java.lang.String> lines();
     method public int read(char[], int, int) throws java.io.IOException;
-    method public java.lang.String readLine() throws java.io.IOException;
+    method public String readLine() throws java.io.IOException;
   }
 
   public class BufferedWriter extends java.io.Writer {
@@ -57502,12 +57923,11 @@
   public class ByteArrayInputStream extends java.io.InputStream {
     ctor public ByteArrayInputStream(byte[]);
     ctor public ByteArrayInputStream(byte[], int, int);
-    method public synchronized int available();
-    method public void mark(int);
-    method public synchronized int read();
-    method public synchronized int read(byte[], int, int);
-    method public synchronized void reset();
-    method public synchronized long skip(long);
+    method public int available();
+    method public int read();
+    method public int read(byte[], int, int);
+    method public void reset();
+    method public long skip(long);
     field protected byte[] buf;
     field protected int count;
     field protected int mark;
@@ -57517,15 +57937,14 @@
   public class ByteArrayOutputStream extends java.io.OutputStream {
     ctor public ByteArrayOutputStream();
     ctor public ByteArrayOutputStream(int);
-    method public synchronized void reset();
-    method public synchronized int size();
-    method public synchronized byte[] toByteArray();
-    method public synchronized java.lang.String toString();
-    method public synchronized java.lang.String toString(java.lang.String) throws java.io.UnsupportedEncodingException;
-    method public deprecated synchronized java.lang.String toString(int);
-    method public synchronized void write(int);
-    method public synchronized void write(byte[], int, int);
-    method public synchronized void writeTo(java.io.OutputStream) throws java.io.IOException;
+    method public void reset();
+    method public int size();
+    method public byte[] toByteArray();
+    method @NonNull public String toString(@NonNull String) throws java.io.UnsupportedEncodingException;
+    method @Deprecated @NonNull public String toString(int);
+    method public void write(int);
+    method public void write(byte[], int, int);
+    method public void writeTo(@NonNull java.io.OutputStream) throws java.io.IOException;
     field protected byte[] buf;
     field protected int count;
   }
@@ -57544,8 +57963,8 @@
   public class CharArrayWriter extends java.io.Writer {
     ctor public CharArrayWriter();
     ctor public CharArrayWriter(int);
-    method public java.io.CharArrayWriter append(java.lang.CharSequence);
-    method public java.io.CharArrayWriter append(java.lang.CharSequence, int, int);
+    method public java.io.CharArrayWriter append(CharSequence);
+    method public java.io.CharArrayWriter append(CharSequence, int, int);
     method public java.io.CharArrayWriter append(char);
     method public void close();
     method public void flush();
@@ -57554,7 +57973,7 @@
     method public char[] toCharArray();
     method public void write(int);
     method public void write(char[], int, int);
-    method public void write(java.lang.String, int, int);
+    method public void write(String, int, int);
     method public void writeTo(java.io.Writer) throws java.io.IOException;
     field protected char[] buf;
     field protected int count;
@@ -57562,41 +57981,41 @@
 
   public class CharConversionException extends java.io.IOException {
     ctor public CharConversionException();
-    ctor public CharConversionException(java.lang.String);
+    ctor public CharConversionException(String);
   }
 
-  public abstract interface Closeable implements java.lang.AutoCloseable {
-    method public abstract void close() throws java.io.IOException;
+  public interface Closeable extends java.lang.AutoCloseable {
+    method public void close() throws java.io.IOException;
   }
 
   public final class Console implements java.io.Flushable {
     method public void flush();
-    method public java.io.Console format(java.lang.String, java.lang.Object...);
-    method public java.io.Console printf(java.lang.String, java.lang.Object...);
-    method public java.lang.String readLine(java.lang.String, java.lang.Object...);
-    method public java.lang.String readLine();
-    method public char[] readPassword(java.lang.String, java.lang.Object...);
+    method public java.io.Console format(String, java.lang.Object...);
+    method public java.io.Console printf(String, java.lang.Object...);
+    method public String readLine(String, java.lang.Object...);
+    method public String readLine();
+    method public char[] readPassword(String, java.lang.Object...);
     method public char[] readPassword();
     method public java.io.Reader reader();
     method public java.io.PrintWriter writer();
   }
 
-  public abstract interface DataInput {
-    method public abstract boolean readBoolean() throws java.io.IOException;
-    method public abstract byte readByte() throws java.io.IOException;
-    method public abstract char readChar() throws java.io.IOException;
-    method public abstract double readDouble() throws java.io.IOException;
-    method public abstract float readFloat() throws java.io.IOException;
-    method public abstract void readFully(byte[]) throws java.io.IOException;
-    method public abstract void readFully(byte[], int, int) throws java.io.IOException;
-    method public abstract int readInt() throws java.io.IOException;
-    method public abstract java.lang.String readLine() throws java.io.IOException;
-    method public abstract long readLong() throws java.io.IOException;
-    method public abstract short readShort() throws java.io.IOException;
-    method public abstract java.lang.String readUTF() throws java.io.IOException;
-    method public abstract int readUnsignedByte() throws java.io.IOException;
-    method public abstract int readUnsignedShort() throws java.io.IOException;
-    method public abstract int skipBytes(int) throws java.io.IOException;
+  public interface DataInput {
+    method public boolean readBoolean() throws java.io.IOException;
+    method public byte readByte() throws java.io.IOException;
+    method public char readChar() throws java.io.IOException;
+    method public double readDouble() throws java.io.IOException;
+    method public float readFloat() throws java.io.IOException;
+    method public void readFully(byte[]) throws java.io.IOException;
+    method public void readFully(byte[], int, int) throws java.io.IOException;
+    method public int readInt() throws java.io.IOException;
+    method public String readLine() throws java.io.IOException;
+    method public long readLong() throws java.io.IOException;
+    method public short readShort() throws java.io.IOException;
+    method public String readUTF() throws java.io.IOException;
+    method public int readUnsignedByte() throws java.io.IOException;
+    method public int readUnsignedShort() throws java.io.IOException;
+    method public int skipBytes(int) throws java.io.IOException;
   }
 
   public class DataInputStream extends java.io.FilterInputStream implements java.io.DataInput {
@@ -57611,86 +58030,84 @@
     method public final void readFully(byte[]) throws java.io.IOException;
     method public final void readFully(byte[], int, int) throws java.io.IOException;
     method public final int readInt() throws java.io.IOException;
-    method public final deprecated java.lang.String readLine() throws java.io.IOException;
+    method @Deprecated public final String readLine() throws java.io.IOException;
     method public final long readLong() throws java.io.IOException;
     method public final short readShort() throws java.io.IOException;
-    method public final java.lang.String readUTF() throws java.io.IOException;
-    method public static final java.lang.String readUTF(java.io.DataInput) throws java.io.IOException;
+    method public final String readUTF() throws java.io.IOException;
+    method public static final String readUTF(java.io.DataInput) throws java.io.IOException;
     method public final int readUnsignedByte() throws java.io.IOException;
     method public final int readUnsignedShort() throws java.io.IOException;
     method public final int skipBytes(int) throws java.io.IOException;
   }
 
-  public abstract interface DataOutput {
-    method public abstract void write(int) throws java.io.IOException;
-    method public abstract void write(byte[]) throws java.io.IOException;
-    method public abstract void write(byte[], int, int) throws java.io.IOException;
-    method public abstract void writeBoolean(boolean) throws java.io.IOException;
-    method public abstract void writeByte(int) throws java.io.IOException;
-    method public abstract void writeBytes(java.lang.String) throws java.io.IOException;
-    method public abstract void writeChar(int) throws java.io.IOException;
-    method public abstract void writeChars(java.lang.String) throws java.io.IOException;
-    method public abstract void writeDouble(double) throws java.io.IOException;
-    method public abstract void writeFloat(float) throws java.io.IOException;
-    method public abstract void writeInt(int) throws java.io.IOException;
-    method public abstract void writeLong(long) throws java.io.IOException;
-    method public abstract void writeShort(int) throws java.io.IOException;
-    method public abstract void writeUTF(java.lang.String) throws java.io.IOException;
+  public interface DataOutput {
+    method public void write(int) throws java.io.IOException;
+    method public void write(byte[]) throws java.io.IOException;
+    method public void write(byte[], int, int) throws java.io.IOException;
+    method public void writeBoolean(boolean) throws java.io.IOException;
+    method public void writeByte(int) throws java.io.IOException;
+    method public void writeBytes(String) throws java.io.IOException;
+    method public void writeChar(int) throws java.io.IOException;
+    method public void writeChars(String) throws java.io.IOException;
+    method public void writeDouble(double) throws java.io.IOException;
+    method public void writeFloat(float) throws java.io.IOException;
+    method public void writeInt(int) throws java.io.IOException;
+    method public void writeLong(long) throws java.io.IOException;
+    method public void writeShort(int) throws java.io.IOException;
+    method public void writeUTF(String) throws java.io.IOException;
   }
 
   public class DataOutputStream extends java.io.FilterOutputStream implements java.io.DataOutput {
     ctor public DataOutputStream(java.io.OutputStream);
     method public final int size();
-    method public synchronized void write(int) throws java.io.IOException;
-    method public synchronized void write(byte[], int, int) throws java.io.IOException;
     method public final void writeBoolean(boolean) throws java.io.IOException;
     method public final void writeByte(int) throws java.io.IOException;
-    method public final void writeBytes(java.lang.String) throws java.io.IOException;
+    method public final void writeBytes(String) throws java.io.IOException;
     method public final void writeChar(int) throws java.io.IOException;
-    method public final void writeChars(java.lang.String) throws java.io.IOException;
+    method public final void writeChars(String) throws java.io.IOException;
     method public final void writeDouble(double) throws java.io.IOException;
     method public final void writeFloat(float) throws java.io.IOException;
     method public final void writeInt(int) throws java.io.IOException;
     method public final void writeLong(long) throws java.io.IOException;
     method public final void writeShort(int) throws java.io.IOException;
-    method public final void writeUTF(java.lang.String) throws java.io.IOException;
+    method public final void writeUTF(String) throws java.io.IOException;
     field protected int written;
   }
 
   public class EOFException extends java.io.IOException {
     ctor public EOFException();
-    ctor public EOFException(java.lang.String);
+    ctor public EOFException(String);
   }
 
-  public abstract interface Externalizable implements java.io.Serializable {
-    method public abstract void readExternal(java.io.ObjectInput) throws java.lang.ClassNotFoundException, java.io.IOException;
-    method public abstract void writeExternal(java.io.ObjectOutput) throws java.io.IOException;
+  public interface Externalizable extends java.io.Serializable {
+    method public void readExternal(java.io.ObjectInput) throws java.lang.ClassNotFoundException, java.io.IOException;
+    method public void writeExternal(java.io.ObjectOutput) throws java.io.IOException;
   }
 
-  public class File implements java.lang.Comparable java.io.Serializable {
-    ctor public File(java.lang.String);
-    ctor public File(java.lang.String, java.lang.String);
-    ctor public File(java.io.File, java.lang.String);
-    ctor public File(java.net.URI);
+  public class File implements java.lang.Comparable<java.io.File> java.io.Serializable {
+    ctor public File(@NonNull String);
+    ctor public File(@Nullable String, @NonNull String);
+    ctor public File(@Nullable java.io.File, @NonNull String);
+    ctor public File(@NonNull java.net.URI);
     method public boolean canExecute();
     method public boolean canRead();
     method public boolean canWrite();
-    method public int compareTo(java.io.File);
+    method public int compareTo(@NonNull java.io.File);
     method public boolean createNewFile() throws java.io.IOException;
-    method public static java.io.File createTempFile(java.lang.String, java.lang.String, java.io.File) throws java.io.IOException;
-    method public static java.io.File createTempFile(java.lang.String, java.lang.String) throws java.io.IOException;
+    method @NonNull public static java.io.File createTempFile(@NonNull String, @Nullable String, @Nullable java.io.File) throws java.io.IOException;
+    method @NonNull public static java.io.File createTempFile(@NonNull String, @Nullable String) throws java.io.IOException;
     method public boolean delete();
     method public void deleteOnExit();
     method public boolean exists();
-    method public java.io.File getAbsoluteFile();
-    method public java.lang.String getAbsolutePath();
-    method public java.io.File getCanonicalFile() throws java.io.IOException;
-    method public java.lang.String getCanonicalPath() throws java.io.IOException;
+    method @NonNull public java.io.File getAbsoluteFile();
+    method @NonNull public String getAbsolutePath();
+    method @NonNull public java.io.File getCanonicalFile() throws java.io.IOException;
+    method @NonNull public String getCanonicalPath() throws java.io.IOException;
     method public long getFreeSpace();
-    method public java.lang.String getName();
-    method public java.lang.String getParent();
-    method public java.io.File getParentFile();
-    method public java.lang.String getPath();
+    method @NonNull public String getName();
+    method @Nullable public String getParent();
+    method @Nullable public java.io.File getParentFile();
+    method @NonNull public String getPath();
     method public long getTotalSpace();
     method public long getUsableSpace();
     method public boolean isAbsolute();
@@ -57699,15 +58116,15 @@
     method public boolean isHidden();
     method public long lastModified();
     method public long length();
-    method public java.lang.String[] list();
-    method public java.lang.String[] list(java.io.FilenameFilter);
+    method public String[] list();
+    method public String[] list(@Nullable java.io.FilenameFilter);
     method public java.io.File[] listFiles();
-    method public java.io.File[] listFiles(java.io.FilenameFilter);
-    method public java.io.File[] listFiles(java.io.FileFilter);
+    method public java.io.File[] listFiles(@Nullable java.io.FilenameFilter);
+    method public java.io.File[] listFiles(@Nullable java.io.FileFilter);
     method public static java.io.File[] listRoots();
     method public boolean mkdir();
     method public boolean mkdirs();
-    method public boolean renameTo(java.io.File);
+    method public boolean renameTo(@NonNull java.io.File);
     method public boolean setExecutable(boolean, boolean);
     method public boolean setExecutable(boolean);
     method public boolean setLastModified(long);
@@ -57716,12 +58133,12 @@
     method public boolean setReadable(boolean);
     method public boolean setWritable(boolean, boolean);
     method public boolean setWritable(boolean);
-    method public java.nio.file.Path toPath();
-    method public java.net.URI toURI();
-    method public deprecated java.net.URL toURL() throws java.net.MalformedURLException;
-    field public static final java.lang.String pathSeparator;
+    method @NonNull public java.nio.file.Path toPath();
+    method @NonNull public java.net.URI toURI();
+    method @Deprecated @NonNull public java.net.URL toURL() throws java.net.MalformedURLException;
+    field @NonNull public static final String pathSeparator;
     field public static final char pathSeparatorChar;
-    field public static final java.lang.String separator;
+    field @NonNull public static final String separator;
     field public static final char separatorChar;
   }
 
@@ -57734,12 +58151,12 @@
     field public static final java.io.FileDescriptor out;
   }
 
-  public abstract interface FileFilter {
-    method public abstract boolean accept(java.io.File);
+  @java.lang.FunctionalInterface public interface FileFilter {
+    method public boolean accept(java.io.File);
   }
 
   public class FileInputStream extends java.io.InputStream {
-    ctor public FileInputStream(java.lang.String) throws java.io.FileNotFoundException;
+    ctor public FileInputStream(String) throws java.io.FileNotFoundException;
     ctor public FileInputStream(java.io.File) throws java.io.FileNotFoundException;
     ctor public FileInputStream(java.io.FileDescriptor);
     method protected void finalize() throws java.io.IOException;
@@ -57750,12 +58167,12 @@
 
   public class FileNotFoundException extends java.io.IOException {
     ctor public FileNotFoundException();
-    ctor public FileNotFoundException(java.lang.String);
+    ctor public FileNotFoundException(String);
   }
 
   public class FileOutputStream extends java.io.OutputStream {
-    ctor public FileOutputStream(java.lang.String) throws java.io.FileNotFoundException;
-    ctor public FileOutputStream(java.lang.String, boolean) throws java.io.FileNotFoundException;
+    ctor public FileOutputStream(String) throws java.io.FileNotFoundException;
+    ctor public FileOutputStream(String, boolean) throws java.io.FileNotFoundException;
     ctor public FileOutputStream(java.io.File) throws java.io.FileNotFoundException;
     ctor public FileOutputStream(java.io.File, boolean) throws java.io.FileNotFoundException;
     ctor public FileOutputStream(java.io.FileDescriptor);
@@ -57766,27 +58183,27 @@
   }
 
   public final class FilePermission extends java.security.Permission implements java.io.Serializable {
-    ctor public FilePermission(java.lang.String, java.lang.String);
-    method public java.lang.String getActions();
+    ctor public FilePermission(String, String);
+    method public String getActions();
     method public boolean implies(java.security.Permission);
   }
 
   public class FileReader extends java.io.InputStreamReader {
-    ctor public FileReader(java.lang.String) throws java.io.FileNotFoundException;
+    ctor public FileReader(String) throws java.io.FileNotFoundException;
     ctor public FileReader(java.io.File) throws java.io.FileNotFoundException;
     ctor public FileReader(java.io.FileDescriptor);
   }
 
   public class FileWriter extends java.io.OutputStreamWriter {
-    ctor public FileWriter(java.lang.String) throws java.io.IOException;
-    ctor public FileWriter(java.lang.String, boolean) throws java.io.IOException;
+    ctor public FileWriter(String) throws java.io.IOException;
+    ctor public FileWriter(String, boolean) throws java.io.IOException;
     ctor public FileWriter(java.io.File) throws java.io.IOException;
     ctor public FileWriter(java.io.File, boolean) throws java.io.IOException;
     ctor public FileWriter(java.io.FileDescriptor);
   }
 
-  public abstract interface FilenameFilter {
-    method public abstract boolean accept(java.io.File, java.lang.String);
+  @java.lang.FunctionalInterface public interface FilenameFilter {
+    method public boolean accept(java.io.File, String);
   }
 
   public class FilterInputStream extends java.io.InputStream {
@@ -57816,66 +58233,64 @@
     field protected java.io.Writer out;
   }
 
-  public abstract interface Flushable {
-    method public abstract void flush() throws java.io.IOException;
+  public interface Flushable {
+    method public void flush() throws java.io.IOException;
   }
 
   public class IOError extends java.lang.Error {
-    ctor public IOError(java.lang.Throwable);
+    ctor public IOError(Throwable);
   }
 
   public class IOException extends java.lang.Exception {
     ctor public IOException();
-    ctor public IOException(java.lang.String);
-    ctor public IOException(java.lang.String, java.lang.Throwable);
-    ctor public IOException(java.lang.Throwable);
+    ctor public IOException(String);
+    ctor public IOException(String, Throwable);
+    ctor public IOException(Throwable);
   }
 
   public abstract class InputStream implements java.io.Closeable {
     ctor public InputStream();
     method public int available() throws java.io.IOException;
     method public void close() throws java.io.IOException;
-    method public synchronized void mark(int);
+    method public void mark(int);
     method public boolean markSupported();
     method public abstract int read() throws java.io.IOException;
     method public int read(byte[]) throws java.io.IOException;
     method public int read(byte[], int, int) throws java.io.IOException;
-    method public synchronized void reset() throws java.io.IOException;
+    method public void reset() throws java.io.IOException;
     method public long skip(long) throws java.io.IOException;
   }
 
   public class InputStreamReader extends java.io.Reader {
     ctor public InputStreamReader(java.io.InputStream);
-    ctor public InputStreamReader(java.io.InputStream, java.lang.String) throws java.io.UnsupportedEncodingException;
+    ctor public InputStreamReader(java.io.InputStream, String) throws java.io.UnsupportedEncodingException;
     ctor public InputStreamReader(java.io.InputStream, java.nio.charset.Charset);
     ctor public InputStreamReader(java.io.InputStream, java.nio.charset.CharsetDecoder);
     method public void close() throws java.io.IOException;
-    method public java.lang.String getEncoding();
+    method public String getEncoding();
     method public int read(char[], int, int) throws java.io.IOException;
   }
 
   public class InterruptedIOException extends java.io.IOException {
     ctor public InterruptedIOException();
-    ctor public InterruptedIOException(java.lang.String);
+    ctor public InterruptedIOException(String);
     field public int bytesTransferred;
   }
 
   public class InvalidClassException extends java.io.ObjectStreamException {
-    ctor public InvalidClassException(java.lang.String);
-    ctor public InvalidClassException(java.lang.String, java.lang.String);
-    field public java.lang.String classname;
+    ctor public InvalidClassException(String);
+    ctor public InvalidClassException(String, String);
+    field public String classname;
   }
 
   public class InvalidObjectException extends java.io.ObjectStreamException {
-    ctor public InvalidObjectException(java.lang.String);
+    ctor public InvalidObjectException(String);
   }
 
-  public deprecated class LineNumberInputStream extends java.io.FilterInputStream {
-    ctor public LineNumberInputStream(java.io.InputStream);
-    method public int getLineNumber();
-    method public void mark(int);
-    method public void reset() throws java.io.IOException;
-    method public void setLineNumber(int);
+  @Deprecated public class LineNumberInputStream extends java.io.FilterInputStream {
+    ctor @Deprecated public LineNumberInputStream(java.io.InputStream);
+    method @Deprecated public int getLineNumber();
+    method @Deprecated public void setLineNumber(int);
   }
 
   public class LineNumberReader extends java.io.BufferedReader {
@@ -57886,23 +58301,23 @@
   }
 
   public class NotActiveException extends java.io.ObjectStreamException {
-    ctor public NotActiveException(java.lang.String);
+    ctor public NotActiveException(String);
     ctor public NotActiveException();
   }
 
   public class NotSerializableException extends java.io.ObjectStreamException {
-    ctor public NotSerializableException(java.lang.String);
+    ctor public NotSerializableException(String);
     ctor public NotSerializableException();
   }
 
-  public abstract interface ObjectInput implements java.lang.AutoCloseable java.io.DataInput {
-    method public abstract int available() throws java.io.IOException;
-    method public abstract void close() throws java.io.IOException;
-    method public abstract int read() throws java.io.IOException;
-    method public abstract int read(byte[]) throws java.io.IOException;
-    method public abstract int read(byte[], int, int) throws java.io.IOException;
-    method public abstract java.lang.Object readObject() throws java.lang.ClassNotFoundException, java.io.IOException;
-    method public abstract long skip(long) throws java.io.IOException;
+  public interface ObjectInput extends java.io.DataInput java.lang.AutoCloseable {
+    method public int available() throws java.io.IOException;
+    method public void close() throws java.io.IOException;
+    method public int read() throws java.io.IOException;
+    method public int read(byte[]) throws java.io.IOException;
+    method public int read(byte[], int, int) throws java.io.IOException;
+    method public Object readObject() throws java.lang.ClassNotFoundException, java.io.IOException;
+    method public long skip(long) throws java.io.IOException;
   }
 
   public class ObjectInputStream extends java.io.InputStream implements java.io.ObjectInput java.io.ObjectStreamConstants {
@@ -57921,106 +58336,106 @@
     method public void readFully(byte[]) throws java.io.IOException;
     method public void readFully(byte[], int, int) throws java.io.IOException;
     method public int readInt() throws java.io.IOException;
-    method public deprecated java.lang.String readLine() throws java.io.IOException;
+    method @Deprecated public String readLine() throws java.io.IOException;
     method public long readLong() throws java.io.IOException;
-    method public final java.lang.Object readObject() throws java.lang.ClassNotFoundException, java.io.IOException;
-    method protected java.lang.Object readObjectOverride() throws java.lang.ClassNotFoundException, java.io.IOException;
+    method public final Object readObject() throws java.lang.ClassNotFoundException, java.io.IOException;
+    method protected Object readObjectOverride() throws java.lang.ClassNotFoundException, java.io.IOException;
     method public short readShort() throws java.io.IOException;
     method protected void readStreamHeader() throws java.io.IOException, java.io.StreamCorruptedException;
-    method public java.lang.String readUTF() throws java.io.IOException;
-    method public java.lang.Object readUnshared() throws java.lang.ClassNotFoundException, java.io.IOException;
+    method public String readUTF() throws java.io.IOException;
+    method public Object readUnshared() throws java.lang.ClassNotFoundException, java.io.IOException;
     method public int readUnsignedByte() throws java.io.IOException;
     method public int readUnsignedShort() throws java.io.IOException;
     method public void registerValidation(java.io.ObjectInputValidation, int) throws java.io.InvalidObjectException, java.io.NotActiveException;
-    method protected java.lang.Class<?> resolveClass(java.io.ObjectStreamClass) throws java.lang.ClassNotFoundException, java.io.IOException;
-    method protected java.lang.Object resolveObject(java.lang.Object) throws java.io.IOException;
-    method protected java.lang.Class<?> resolveProxyClass(java.lang.String[]) throws java.lang.ClassNotFoundException, java.io.IOException;
+    method protected Class<?> resolveClass(java.io.ObjectStreamClass) throws java.lang.ClassNotFoundException, java.io.IOException;
+    method protected Object resolveObject(Object) throws java.io.IOException;
+    method protected Class<?> resolveProxyClass(String[]) throws java.lang.ClassNotFoundException, java.io.IOException;
     method public int skipBytes(int) throws java.io.IOException;
   }
 
-  public static abstract class ObjectInputStream.GetField {
+  public abstract static class ObjectInputStream.GetField {
     ctor public ObjectInputStream.GetField();
-    method public abstract boolean defaulted(java.lang.String) throws java.io.IOException;
-    method public abstract boolean get(java.lang.String, boolean) throws java.io.IOException;
-    method public abstract byte get(java.lang.String, byte) throws java.io.IOException;
-    method public abstract char get(java.lang.String, char) throws java.io.IOException;
-    method public abstract short get(java.lang.String, short) throws java.io.IOException;
-    method public abstract int get(java.lang.String, int) throws java.io.IOException;
-    method public abstract long get(java.lang.String, long) throws java.io.IOException;
-    method public abstract float get(java.lang.String, float) throws java.io.IOException;
-    method public abstract double get(java.lang.String, double) throws java.io.IOException;
-    method public abstract java.lang.Object get(java.lang.String, java.lang.Object) throws java.io.IOException;
+    method public abstract boolean defaulted(String) throws java.io.IOException;
+    method public abstract boolean get(String, boolean) throws java.io.IOException;
+    method public abstract byte get(String, byte) throws java.io.IOException;
+    method public abstract char get(String, char) throws java.io.IOException;
+    method public abstract short get(String, short) throws java.io.IOException;
+    method public abstract int get(String, int) throws java.io.IOException;
+    method public abstract long get(String, long) throws java.io.IOException;
+    method public abstract float get(String, float) throws java.io.IOException;
+    method public abstract double get(String, double) throws java.io.IOException;
+    method public abstract Object get(String, Object) throws java.io.IOException;
     method public abstract java.io.ObjectStreamClass getObjectStreamClass();
   }
 
-  public abstract interface ObjectInputValidation {
-    method public abstract void validateObject() throws java.io.InvalidObjectException;
+  public interface ObjectInputValidation {
+    method public void validateObject() throws java.io.InvalidObjectException;
   }
 
-  public abstract interface ObjectOutput implements java.lang.AutoCloseable java.io.DataOutput {
-    method public abstract void close() throws java.io.IOException;
-    method public abstract void flush() throws java.io.IOException;
-    method public abstract void writeObject(java.lang.Object) throws java.io.IOException;
+  public interface ObjectOutput extends java.io.DataOutput java.lang.AutoCloseable {
+    method public void close() throws java.io.IOException;
+    method public void flush() throws java.io.IOException;
+    method public void writeObject(Object) throws java.io.IOException;
   }
 
   public class ObjectOutputStream extends java.io.OutputStream implements java.io.ObjectOutput java.io.ObjectStreamConstants {
     ctor public ObjectOutputStream(java.io.OutputStream) throws java.io.IOException;
     ctor protected ObjectOutputStream() throws java.io.IOException, java.lang.SecurityException;
-    method protected void annotateClass(java.lang.Class<?>) throws java.io.IOException;
-    method protected void annotateProxyClass(java.lang.Class<?>) throws java.io.IOException;
+    method protected void annotateClass(Class<?>) throws java.io.IOException;
+    method protected void annotateProxyClass(Class<?>) throws java.io.IOException;
     method public void defaultWriteObject() throws java.io.IOException;
     method protected void drain() throws java.io.IOException;
     method protected boolean enableReplaceObject(boolean) throws java.lang.SecurityException;
     method public java.io.ObjectOutputStream.PutField putFields() throws java.io.IOException;
-    method protected java.lang.Object replaceObject(java.lang.Object) throws java.io.IOException;
+    method protected Object replaceObject(Object) throws java.io.IOException;
     method public void reset() throws java.io.IOException;
     method public void useProtocolVersion(int) throws java.io.IOException;
     method public void write(int) throws java.io.IOException;
     method public void writeBoolean(boolean) throws java.io.IOException;
     method public void writeByte(int) throws java.io.IOException;
-    method public void writeBytes(java.lang.String) throws java.io.IOException;
+    method public void writeBytes(String) throws java.io.IOException;
     method public void writeChar(int) throws java.io.IOException;
-    method public void writeChars(java.lang.String) throws java.io.IOException;
+    method public void writeChars(String) throws java.io.IOException;
     method protected void writeClassDescriptor(java.io.ObjectStreamClass) throws java.io.IOException;
     method public void writeDouble(double) throws java.io.IOException;
     method public void writeFields() throws java.io.IOException;
     method public void writeFloat(float) throws java.io.IOException;
     method public void writeInt(int) throws java.io.IOException;
     method public void writeLong(long) throws java.io.IOException;
-    method public final void writeObject(java.lang.Object) throws java.io.IOException;
-    method protected void writeObjectOverride(java.lang.Object) throws java.io.IOException;
+    method public final void writeObject(Object) throws java.io.IOException;
+    method protected void writeObjectOverride(Object) throws java.io.IOException;
     method public void writeShort(int) throws java.io.IOException;
     method protected void writeStreamHeader() throws java.io.IOException;
-    method public void writeUTF(java.lang.String) throws java.io.IOException;
-    method public void writeUnshared(java.lang.Object) throws java.io.IOException;
+    method public void writeUTF(String) throws java.io.IOException;
+    method public void writeUnshared(Object) throws java.io.IOException;
   }
 
-  public static abstract class ObjectOutputStream.PutField {
+  public abstract static class ObjectOutputStream.PutField {
     ctor public ObjectOutputStream.PutField();
-    method public abstract void put(java.lang.String, boolean);
-    method public abstract void put(java.lang.String, byte);
-    method public abstract void put(java.lang.String, char);
-    method public abstract void put(java.lang.String, short);
-    method public abstract void put(java.lang.String, int);
-    method public abstract void put(java.lang.String, long);
-    method public abstract void put(java.lang.String, float);
-    method public abstract void put(java.lang.String, double);
-    method public abstract void put(java.lang.String, java.lang.Object);
-    method public abstract deprecated void write(java.io.ObjectOutput) throws java.io.IOException;
+    method public abstract void put(String, boolean);
+    method public abstract void put(String, byte);
+    method public abstract void put(String, char);
+    method public abstract void put(String, short);
+    method public abstract void put(String, int);
+    method public abstract void put(String, long);
+    method public abstract void put(String, float);
+    method public abstract void put(String, double);
+    method public abstract void put(String, Object);
+    method @Deprecated public abstract void write(java.io.ObjectOutput) throws java.io.IOException;
   }
 
   public class ObjectStreamClass implements java.io.Serializable {
-    method public java.lang.Class<?> forClass();
-    method public java.io.ObjectStreamField getField(java.lang.String);
+    method public Class<?> forClass();
+    method public java.io.ObjectStreamField getField(String);
     method public java.io.ObjectStreamField[] getFields();
-    method public java.lang.String getName();
+    method public String getName();
     method public long getSerialVersionUID();
-    method public static java.io.ObjectStreamClass lookup(java.lang.Class<?>);
-    method public static java.io.ObjectStreamClass lookupAny(java.lang.Class<?>);
+    method public static java.io.ObjectStreamClass lookup(Class<?>);
+    method public static java.io.ObjectStreamClass lookupAny(Class<?>);
     field public static final java.io.ObjectStreamField[] NO_FIELDS;
   }
 
-  public abstract interface ObjectStreamConstants {
+  public interface ObjectStreamConstants {
     field public static final int PROTOCOL_VERSION_1 = 1; // 0x1
     field public static final int PROTOCOL_VERSION_2 = 2; // 0x2
     field public static final byte SC_BLOCK_DATA = 8; // 0x8
@@ -58053,19 +58468,19 @@
   }
 
   public abstract class ObjectStreamException extends java.io.IOException {
-    ctor protected ObjectStreamException(java.lang.String);
+    ctor protected ObjectStreamException(String);
     ctor protected ObjectStreamException();
   }
 
-  public class ObjectStreamField implements java.lang.Comparable {
-    ctor public ObjectStreamField(java.lang.String, java.lang.Class<?>);
-    ctor public ObjectStreamField(java.lang.String, java.lang.Class<?>, boolean);
-    method public int compareTo(java.lang.Object);
-    method public java.lang.String getName();
+  public class ObjectStreamField implements java.lang.Comparable<java.lang.Object> {
+    ctor public ObjectStreamField(String, Class<?>);
+    ctor public ObjectStreamField(String, Class<?>, boolean);
+    method public int compareTo(Object);
+    method public String getName();
     method public int getOffset();
-    method public java.lang.Class<?> getType();
+    method public Class<?> getType();
     method public char getTypeCode();
-    method public java.lang.String getTypeString();
+    method public String getTypeString();
     method public boolean isPrimitive();
     method public boolean isUnshared();
     method protected void setOffset(int);
@@ -58086,13 +58501,13 @@
   }
 
   public class OutputStreamWriter extends java.io.Writer {
-    ctor public OutputStreamWriter(java.io.OutputStream, java.lang.String) throws java.io.UnsupportedEncodingException;
+    ctor public OutputStreamWriter(java.io.OutputStream, String) throws java.io.UnsupportedEncodingException;
     ctor public OutputStreamWriter(java.io.OutputStream);
     ctor public OutputStreamWriter(java.io.OutputStream, java.nio.charset.Charset);
     ctor public OutputStreamWriter(java.io.OutputStream, java.nio.charset.CharsetEncoder);
     method public void close() throws java.io.IOException;
     method public void flush() throws java.io.IOException;
-    method public java.lang.String getEncoding();
+    method public String getEncoding();
     method public void write(char[], int, int) throws java.io.IOException;
   }
 
@@ -58101,11 +58516,9 @@
     ctor public PipedInputStream(java.io.PipedOutputStream, int) throws java.io.IOException;
     ctor public PipedInputStream();
     ctor public PipedInputStream(int);
-    method public synchronized int available() throws java.io.IOException;
     method public void connect(java.io.PipedOutputStream) throws java.io.IOException;
-    method public synchronized int read() throws java.io.IOException;
-    method public synchronized int read(byte[], int, int) throws java.io.IOException;
-    method protected synchronized void receive(int) throws java.io.IOException;
+    method public int read() throws java.io.IOException;
+    method protected void receive(int) throws java.io.IOException;
     field protected static final int PIPE_SIZE = 1024; // 0x400
     field protected byte[] buffer;
     field protected int in;
@@ -58115,8 +58528,7 @@
   public class PipedOutputStream extends java.io.OutputStream {
     ctor public PipedOutputStream(java.io.PipedInputStream) throws java.io.IOException;
     ctor public PipedOutputStream();
-    method public synchronized void connect(java.io.PipedInputStream) throws java.io.IOException;
-    method public synchronized void flush() throws java.io.IOException;
+    method public void connect(java.io.PipedInputStream) throws java.io.IOException;
     method public void write(int) throws java.io.IOException;
   }
 
@@ -58127,37 +58539,35 @@
     ctor public PipedReader(int);
     method public void close() throws java.io.IOException;
     method public void connect(java.io.PipedWriter) throws java.io.IOException;
-    method public synchronized int read() throws java.io.IOException;
-    method public synchronized int read(char[], int, int) throws java.io.IOException;
-    method public synchronized boolean ready() throws java.io.IOException;
+    method public int read(char[], int, int) throws java.io.IOException;
   }
 
   public class PipedWriter extends java.io.Writer {
     ctor public PipedWriter(java.io.PipedReader) throws java.io.IOException;
     ctor public PipedWriter();
     method public void close() throws java.io.IOException;
-    method public synchronized void connect(java.io.PipedReader) throws java.io.IOException;
-    method public synchronized void flush() throws java.io.IOException;
+    method public void connect(java.io.PipedReader) throws java.io.IOException;
+    method public void flush() throws java.io.IOException;
     method public void write(char[], int, int) throws java.io.IOException;
   }
 
   public class PrintStream extends java.io.FilterOutputStream implements java.lang.Appendable java.io.Closeable {
     ctor public PrintStream(java.io.OutputStream);
     ctor public PrintStream(java.io.OutputStream, boolean);
-    ctor public PrintStream(java.io.OutputStream, boolean, java.lang.String) throws java.io.UnsupportedEncodingException;
-    ctor public PrintStream(java.lang.String) throws java.io.FileNotFoundException;
-    ctor public PrintStream(java.lang.String, java.lang.String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+    ctor public PrintStream(java.io.OutputStream, boolean, String) throws java.io.UnsupportedEncodingException;
+    ctor public PrintStream(String) throws java.io.FileNotFoundException;
+    ctor public PrintStream(String, String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
     ctor public PrintStream(java.io.File) throws java.io.FileNotFoundException;
-    ctor public PrintStream(java.io.File, java.lang.String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
-    method public java.io.PrintStream append(java.lang.CharSequence);
-    method public java.io.PrintStream append(java.lang.CharSequence, int, int);
+    ctor public PrintStream(java.io.File, String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+    method public java.io.PrintStream append(CharSequence);
+    method public java.io.PrintStream append(CharSequence, int, int);
     method public java.io.PrintStream append(char);
     method public boolean checkError();
     method protected void clearError();
     method public void close();
     method public void flush();
-    method public java.io.PrintStream format(java.lang.String, java.lang.Object...);
-    method public java.io.PrintStream format(java.util.Locale, java.lang.String, java.lang.Object...);
+    method public java.io.PrintStream format(String, java.lang.Object...);
+    method public java.io.PrintStream format(java.util.Locale, String, java.lang.Object...);
     method public void print(boolean);
     method public void print(char);
     method public void print(int);
@@ -58165,10 +58575,10 @@
     method public void print(float);
     method public void print(double);
     method public void print(char[]);
-    method public void print(java.lang.String);
-    method public void print(java.lang.Object);
-    method public java.io.PrintStream printf(java.lang.String, java.lang.Object...);
-    method public java.io.PrintStream printf(java.util.Locale, java.lang.String, java.lang.Object...);
+    method public void print(String);
+    method public void print(Object);
+    method public java.io.PrintStream printf(String, java.lang.Object...);
+    method public java.io.PrintStream printf(java.util.Locale, String, java.lang.Object...);
     method public void println();
     method public void println(boolean);
     method public void println(char);
@@ -58177,31 +58587,31 @@
     method public void println(float);
     method public void println(double);
     method public void println(char[]);
-    method public void println(java.lang.String);
-    method public void println(java.lang.Object);
+    method public void println(String);
+    method public void println(Object);
     method protected void setError();
     method public void write(int);
     method public void write(byte[], int, int);
   }
 
   public class PrintWriter extends java.io.Writer {
-    ctor public PrintWriter(java.io.Writer);
-    ctor public PrintWriter(java.io.Writer, boolean);
-    ctor public PrintWriter(java.io.OutputStream);
-    ctor public PrintWriter(java.io.OutputStream, boolean);
-    ctor public PrintWriter(java.lang.String) throws java.io.FileNotFoundException;
-    ctor public PrintWriter(java.lang.String, java.lang.String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
-    ctor public PrintWriter(java.io.File) throws java.io.FileNotFoundException;
-    ctor public PrintWriter(java.io.File, java.lang.String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
-    method public java.io.PrintWriter append(java.lang.CharSequence);
-    method public java.io.PrintWriter append(java.lang.CharSequence, int, int);
-    method public java.io.PrintWriter append(char);
+    ctor public PrintWriter(@NonNull java.io.Writer);
+    ctor public PrintWriter(@NonNull java.io.Writer, boolean);
+    ctor public PrintWriter(@NonNull java.io.OutputStream);
+    ctor public PrintWriter(@NonNull java.io.OutputStream, boolean);
+    ctor public PrintWriter(@NonNull String) throws java.io.FileNotFoundException;
+    ctor public PrintWriter(@NonNull String, @NonNull String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+    ctor public PrintWriter(@NonNull java.io.File) throws java.io.FileNotFoundException;
+    ctor public PrintWriter(@NonNull java.io.File, @NonNull String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+    method @NonNull public java.io.PrintWriter append(@Nullable CharSequence);
+    method @NonNull public java.io.PrintWriter append(@Nullable CharSequence, int, int);
+    method @NonNull public java.io.PrintWriter append(char);
     method public boolean checkError();
     method protected void clearError();
     method public void close();
     method public void flush();
-    method public java.io.PrintWriter format(java.lang.String, java.lang.Object...);
-    method public java.io.PrintWriter format(java.util.Locale, java.lang.String, java.lang.Object...);
+    method @NonNull public java.io.PrintWriter format(@NonNull String, java.lang.Object...);
+    method @NonNull public java.io.PrintWriter format(@Nullable java.util.Locale, @NonNull String, java.lang.Object...);
     method public void print(boolean);
     method public void print(char);
     method public void print(int);
@@ -58209,10 +58619,10 @@
     method public void print(float);
     method public void print(double);
     method public void print(char[]);
-    method public void print(java.lang.String);
-    method public void print(java.lang.Object);
-    method public java.io.PrintWriter printf(java.lang.String, java.lang.Object...);
-    method public java.io.PrintWriter printf(java.util.Locale, java.lang.String, java.lang.Object...);
+    method public void print(@Nullable String);
+    method public void print(@Nullable Object);
+    method @NonNull public java.io.PrintWriter printf(@NonNull String, java.lang.Object...);
+    method @NonNull public java.io.PrintWriter printf(@Nullable java.util.Locale, @NonNull String, java.lang.Object...);
     method public void println();
     method public void println(boolean);
     method public void println(char);
@@ -58221,21 +58631,20 @@
     method public void println(float);
     method public void println(double);
     method public void println(char[]);
-    method public void println(java.lang.String);
-    method public void println(java.lang.Object);
+    method public void println(@Nullable String);
+    method public void println(@Nullable Object);
     method protected void setError();
     method public void write(int);
     method public void write(char[], int, int);
     method public void write(char[]);
-    method public void write(java.lang.String, int, int);
-    method public void write(java.lang.String);
+    method public void write(@NonNull String, int, int);
+    method public void write(@NonNull String);
     field protected java.io.Writer out;
   }
 
   public class PushbackInputStream extends java.io.FilterInputStream {
     ctor public PushbackInputStream(java.io.InputStream, int);
     ctor public PushbackInputStream(java.io.InputStream);
-    method public synchronized void close() throws java.io.IOException;
     method public void unread(int) throws java.io.IOException;
     method public void unread(byte[], int, int) throws java.io.IOException;
     method public void unread(byte[]) throws java.io.IOException;
@@ -58252,8 +58661,8 @@
   }
 
   public class RandomAccessFile implements java.io.Closeable java.io.DataInput java.io.DataOutput {
-    ctor public RandomAccessFile(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
-    ctor public RandomAccessFile(java.io.File, java.lang.String) throws java.io.FileNotFoundException;
+    ctor public RandomAccessFile(String, String) throws java.io.FileNotFoundException;
+    ctor public RandomAccessFile(java.io.File, String) throws java.io.FileNotFoundException;
     method public void close() throws java.io.IOException;
     method public final java.nio.channels.FileChannel getChannel();
     method public final java.io.FileDescriptor getFD() throws java.io.IOException;
@@ -58270,10 +58679,10 @@
     method public final void readFully(byte[]) throws java.io.IOException;
     method public final void readFully(byte[], int, int) throws java.io.IOException;
     method public final int readInt() throws java.io.IOException;
-    method public final java.lang.String readLine() throws java.io.IOException;
+    method public final String readLine() throws java.io.IOException;
     method public final long readLong() throws java.io.IOException;
     method public final short readShort() throws java.io.IOException;
-    method public final java.lang.String readUTF() throws java.io.IOException;
+    method public final String readUTF() throws java.io.IOException;
     method public final int readUnsignedByte() throws java.io.IOException;
     method public final int readUnsignedShort() throws java.io.IOException;
     method public void seek(long) throws java.io.IOException;
@@ -58284,20 +58693,20 @@
     method public void write(byte[], int, int) throws java.io.IOException;
     method public final void writeBoolean(boolean) throws java.io.IOException;
     method public final void writeByte(int) throws java.io.IOException;
-    method public final void writeBytes(java.lang.String) throws java.io.IOException;
+    method public final void writeBytes(String) throws java.io.IOException;
     method public final void writeChar(int) throws java.io.IOException;
-    method public final void writeChars(java.lang.String) throws java.io.IOException;
+    method public final void writeChars(String) throws java.io.IOException;
     method public final void writeDouble(double) throws java.io.IOException;
     method public final void writeFloat(float) throws java.io.IOException;
     method public final void writeInt(int) throws java.io.IOException;
     method public final void writeLong(long) throws java.io.IOException;
     method public final void writeShort(int) throws java.io.IOException;
-    method public final void writeUTF(java.lang.String) throws java.io.IOException;
+    method public final void writeUTF(String) throws java.io.IOException;
   }
 
   public abstract class Reader implements java.io.Closeable java.lang.Readable {
     ctor protected Reader();
-    ctor protected Reader(java.lang.Object);
+    ctor protected Reader(Object);
     method public void mark(int) throws java.io.IOException;
     method public boolean markSupported();
     method public int read(java.nio.CharBuffer) throws java.io.IOException;
@@ -58307,7 +58716,7 @@
     method public boolean ready() throws java.io.IOException;
     method public void reset() throws java.io.IOException;
     method public long skip(long) throws java.io.IOException;
-    field protected java.lang.Object lock;
+    field protected Object lock;
   }
 
   public class SequenceInputStream extends java.io.InputStream {
@@ -58316,21 +58725,21 @@
     method public int read() throws java.io.IOException;
   }
 
-  public abstract interface Serializable {
+  public interface Serializable {
   }
 
   public final class SerializablePermission extends java.security.BasicPermission {
-    ctor public SerializablePermission(java.lang.String);
-    ctor public SerializablePermission(java.lang.String, java.lang.String);
+    ctor public SerializablePermission(String);
+    ctor public SerializablePermission(String, String);
   }
 
   public class StreamCorruptedException extends java.io.ObjectStreamException {
-    ctor public StreamCorruptedException(java.lang.String);
+    ctor public StreamCorruptedException(String);
     ctor public StreamCorruptedException();
   }
 
   public class StreamTokenizer {
-    ctor public deprecated StreamTokenizer(java.io.InputStream);
+    ctor @Deprecated public StreamTokenizer(java.io.InputStream);
     ctor public StreamTokenizer(java.io.Reader);
     method public void commentChar(int);
     method public void eolIsSignificant(boolean);
@@ -58352,24 +58761,24 @@
     field public static final int TT_NUMBER = -2; // 0xfffffffe
     field public static final int TT_WORD = -3; // 0xfffffffd
     field public double nval;
-    field public java.lang.String sval;
+    field public String sval;
     field public int ttype;
   }
 
-  public deprecated class StringBufferInputStream extends java.io.InputStream {
-    ctor public StringBufferInputStream(java.lang.String);
-    method public synchronized int available();
-    method public synchronized int read();
-    method public synchronized int read(byte[], int, int);
-    method public synchronized void reset();
-    method public synchronized long skip(long);
-    field protected java.lang.String buffer;
-    field protected int count;
-    field protected int pos;
+  @Deprecated public class StringBufferInputStream extends java.io.InputStream {
+    ctor @Deprecated public StringBufferInputStream(String);
+    method @Deprecated public int available();
+    method @Deprecated public int read();
+    method @Deprecated public int read(byte[], int, int);
+    method @Deprecated public void reset();
+    method @Deprecated public long skip(long);
+    field @Deprecated protected String buffer;
+    field @Deprecated protected int count;
+    field @Deprecated protected int pos;
   }
 
   public class StringReader extends java.io.Reader {
-    ctor public StringReader(java.lang.String);
+    ctor public StringReader(String);
     method public void close();
     method public int read(char[], int, int) throws java.io.IOException;
   }
@@ -58377,56 +58786,55 @@
   public class StringWriter extends java.io.Writer {
     ctor public StringWriter();
     ctor public StringWriter(int);
-    method public java.io.StringWriter append(java.lang.CharSequence);
-    method public java.io.StringWriter append(java.lang.CharSequence, int, int);
+    method public java.io.StringWriter append(CharSequence);
+    method public java.io.StringWriter append(CharSequence, int, int);
     method public java.io.StringWriter append(char);
     method public void close() throws java.io.IOException;
     method public void flush();
-    method public java.lang.StringBuffer getBuffer();
+    method public StringBuffer getBuffer();
     method public void write(int);
     method public void write(char[], int, int);
-    method public void write(java.lang.String);
-    method public void write(java.lang.String, int, int);
+    method public void write(String);
+    method public void write(String, int, int);
   }
 
   public class SyncFailedException extends java.io.IOException {
-    ctor public SyncFailedException(java.lang.String);
+    ctor public SyncFailedException(String);
   }
 
   public class UTFDataFormatException extends java.io.IOException {
     ctor public UTFDataFormatException();
-    ctor public UTFDataFormatException(java.lang.String);
+    ctor public UTFDataFormatException(String);
   }
 
   public class UncheckedIOException extends java.lang.RuntimeException {
-    ctor public UncheckedIOException(java.lang.String, java.io.IOException);
+    ctor public UncheckedIOException(String, java.io.IOException);
     ctor public UncheckedIOException(java.io.IOException);
     method public java.io.IOException getCause();
   }
 
   public class UnsupportedEncodingException extends java.io.IOException {
     ctor public UnsupportedEncodingException();
-    ctor public UnsupportedEncodingException(java.lang.String);
+    ctor public UnsupportedEncodingException(String);
   }
 
   public class WriteAbortedException extends java.io.ObjectStreamException {
-    ctor public WriteAbortedException(java.lang.String, java.lang.Exception);
-    method public java.lang.Throwable getCause();
-    field public java.lang.Exception detail;
+    ctor public WriteAbortedException(String, Exception);
+    field public Exception detail;
   }
 
   public abstract class Writer implements java.lang.Appendable java.io.Closeable java.io.Flushable {
     ctor protected Writer();
-    ctor protected Writer(java.lang.Object);
-    method public java.io.Writer append(java.lang.CharSequence) throws java.io.IOException;
-    method public java.io.Writer append(java.lang.CharSequence, int, int) throws java.io.IOException;
+    ctor protected Writer(Object);
+    method public java.io.Writer append(CharSequence) throws java.io.IOException;
+    method public java.io.Writer append(CharSequence, int, int) throws java.io.IOException;
     method public java.io.Writer append(char) throws java.io.IOException;
     method public void write(int) throws java.io.IOException;
     method public void write(char[]) throws java.io.IOException;
     method public abstract void write(char[], int, int) throws java.io.IOException;
-    method public void write(java.lang.String) throws java.io.IOException;
-    method public void write(java.lang.String, int, int) throws java.io.IOException;
-    field protected java.lang.Object lock;
+    method public void write(String) throws java.io.IOException;
+    method public void write(String, int, int) throws java.io.IOException;
+    field protected Object lock;
   }
 
 }
@@ -58435,129 +58843,129 @@
 
   public class AbstractMethodError extends java.lang.IncompatibleClassChangeError {
     ctor public AbstractMethodError();
-    ctor public AbstractMethodError(java.lang.String);
+    ctor public AbstractMethodError(String);
   }
 
-  public abstract interface Appendable {
-    method public abstract java.lang.Appendable append(java.lang.CharSequence) throws java.io.IOException;
-    method public abstract java.lang.Appendable append(java.lang.CharSequence, int, int) throws java.io.IOException;
-    method public abstract java.lang.Appendable append(char) throws java.io.IOException;
+  public interface Appendable {
+    method @NonNull public Appendable append(@Nullable CharSequence) throws java.io.IOException;
+    method @NonNull public Appendable append(@Nullable CharSequence, int, int) throws java.io.IOException;
+    method @NonNull public Appendable append(char) throws java.io.IOException;
   }
 
   public class ArithmeticException extends java.lang.RuntimeException {
     ctor public ArithmeticException();
-    ctor public ArithmeticException(java.lang.String);
+    ctor public ArithmeticException(String);
   }
 
   public class ArrayIndexOutOfBoundsException extends java.lang.IndexOutOfBoundsException {
     ctor public ArrayIndexOutOfBoundsException();
     ctor public ArrayIndexOutOfBoundsException(int);
-    ctor public ArrayIndexOutOfBoundsException(java.lang.String);
+    ctor public ArrayIndexOutOfBoundsException(String);
   }
 
   public class ArrayStoreException extends java.lang.RuntimeException {
     ctor public ArrayStoreException();
-    ctor public ArrayStoreException(java.lang.String);
+    ctor public ArrayStoreException(String);
   }
 
   public class AssertionError extends java.lang.Error {
     ctor public AssertionError();
-    ctor public AssertionError(java.lang.Object);
+    ctor public AssertionError(Object);
     ctor public AssertionError(boolean);
     ctor public AssertionError(char);
     ctor public AssertionError(int);
     ctor public AssertionError(long);
     ctor public AssertionError(float);
     ctor public AssertionError(double);
-    ctor public AssertionError(java.lang.String, java.lang.Throwable);
+    ctor public AssertionError(String, Throwable);
   }
 
-  public abstract interface AutoCloseable {
-    method public abstract void close() throws java.lang.Exception;
+  public interface AutoCloseable {
+    method public void close() throws java.lang.Exception;
   }
 
-  public final class Boolean implements java.lang.Comparable java.io.Serializable {
+  public final class Boolean implements java.lang.Comparable<java.lang.Boolean> java.io.Serializable {
     ctor public Boolean(boolean);
-    ctor public Boolean(java.lang.String);
+    ctor public Boolean(@Nullable String);
     method public boolean booleanValue();
     method public static int compare(boolean, boolean);
-    method public int compareTo(java.lang.Boolean);
-    method public static boolean getBoolean(java.lang.String);
+    method public int compareTo(@NonNull Boolean);
+    method public static boolean getBoolean(@NonNull String);
     method public static int hashCode(boolean);
     method public static boolean logicalAnd(boolean, boolean);
     method public static boolean logicalOr(boolean, boolean);
     method public static boolean logicalXor(boolean, boolean);
-    method public static boolean parseBoolean(java.lang.String);
-    method public static java.lang.String toString(boolean);
-    method public static java.lang.Boolean valueOf(boolean);
-    method public static java.lang.Boolean valueOf(java.lang.String);
-    field public static final java.lang.Boolean FALSE;
-    field public static final java.lang.Boolean TRUE;
-    field public static final java.lang.Class<java.lang.Boolean> TYPE;
+    method public static boolean parseBoolean(@Nullable String);
+    method @NonNull public static String toString(boolean);
+    method @NonNull public static Boolean valueOf(boolean);
+    method @NonNull public static Boolean valueOf(@Nullable String);
+    field public static final Boolean FALSE;
+    field public static final Boolean TRUE;
+    field public static final Class<java.lang.Boolean> TYPE;
   }
 
   public class BootstrapMethodError extends java.lang.LinkageError {
     ctor public BootstrapMethodError();
-    ctor public BootstrapMethodError(java.lang.String);
-    ctor public BootstrapMethodError(java.lang.String, java.lang.Throwable);
-    ctor public BootstrapMethodError(java.lang.Throwable);
+    ctor public BootstrapMethodError(String);
+    ctor public BootstrapMethodError(String, Throwable);
+    ctor public BootstrapMethodError(Throwable);
   }
 
-  public final class Byte extends java.lang.Number implements java.lang.Comparable {
+  public final class Byte extends java.lang.Number implements java.lang.Comparable<java.lang.Byte> {
     ctor public Byte(byte);
-    ctor public Byte(java.lang.String) throws java.lang.NumberFormatException;
+    ctor public Byte(@NonNull String) throws java.lang.NumberFormatException;
     method public static int compare(byte, byte);
-    method public int compareTo(java.lang.Byte);
-    method public static java.lang.Byte decode(java.lang.String) throws java.lang.NumberFormatException;
+    method public int compareTo(@NonNull Byte);
+    method @NonNull public static Byte decode(@NonNull String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
     method public static int hashCode(byte);
     method public int intValue();
     method public long longValue();
-    method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException;
-    method public static byte parseByte(java.lang.String) throws java.lang.NumberFormatException;
-    method public static java.lang.String toString(byte);
+    method public static byte parseByte(@NonNull String, int) throws java.lang.NumberFormatException;
+    method public static byte parseByte(@NonNull String) throws java.lang.NumberFormatException;
+    method @NonNull public static String toString(byte);
     method public static int toUnsignedInt(byte);
     method public static long toUnsignedLong(byte);
-    method public static java.lang.Byte valueOf(byte);
-    method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
-    method public static java.lang.Byte valueOf(java.lang.String) throws java.lang.NumberFormatException;
+    method @NonNull public static Byte valueOf(byte);
+    method @NonNull public static Byte valueOf(@NonNull String, int) throws java.lang.NumberFormatException;
+    method @NonNull public static Byte valueOf(@NonNull String) throws java.lang.NumberFormatException;
     field public static final int BYTES = 1; // 0x1
     field public static final byte MAX_VALUE = 127; // 0x7f
     field public static final byte MIN_VALUE = -128; // 0xffffff80
     field public static final int SIZE = 8; // 0x8
-    field public static final java.lang.Class<java.lang.Byte> TYPE;
+    field public static final Class<java.lang.Byte> TYPE;
   }
 
-  public abstract interface CharSequence {
-    method public abstract char charAt(int);
-    method public default java.util.stream.IntStream chars();
-    method public default java.util.stream.IntStream codePoints();
-    method public abstract int length();
-    method public abstract java.lang.CharSequence subSequence(int, int);
-    method public abstract java.lang.String toString();
+  public interface CharSequence {
+    method public char charAt(int);
+    method @NonNull public default java.util.stream.IntStream chars();
+    method @NonNull public default java.util.stream.IntStream codePoints();
+    method public int length();
+    method @NonNull public CharSequence subSequence(int, int);
+    method @NonNull public String toString();
   }
 
-  public final class Character implements java.lang.Comparable java.io.Serializable {
+  public final class Character implements java.lang.Comparable<java.lang.Character> java.io.Serializable {
     ctor public Character(char);
     method public static int charCount(int);
     method public char charValue();
-    method public static int codePointAt(java.lang.CharSequence, int);
+    method public static int codePointAt(@NonNull CharSequence, int);
     method public static int codePointAt(char[], int);
     method public static int codePointAt(char[], int, int);
-    method public static int codePointBefore(java.lang.CharSequence, int);
+    method public static int codePointBefore(@NonNull CharSequence, int);
     method public static int codePointBefore(char[], int);
     method public static int codePointBefore(char[], int, int);
-    method public static int codePointCount(java.lang.CharSequence, int, int);
+    method public static int codePointCount(@NonNull CharSequence, int, int);
     method public static int codePointCount(char[], int, int);
     method public static int compare(char, char);
-    method public int compareTo(java.lang.Character);
+    method public int compareTo(@NonNull Character);
     method public static int digit(char, int);
     method public static int digit(int, int);
     method public static char forDigit(int, int);
     method public static byte getDirectionality(char);
     method public static byte getDirectionality(int);
-    method public static java.lang.String getName(int);
+    method @Nullable public static String getName(int);
     method public static int getNumericValue(char);
     method public static int getNumericValue(int);
     method public static int getType(char);
@@ -58580,8 +58988,8 @@
     method public static boolean isJavaIdentifierPart(int);
     method public static boolean isJavaIdentifierStart(char);
     method public static boolean isJavaIdentifierStart(int);
-    method public static deprecated boolean isJavaLetter(char);
-    method public static deprecated boolean isJavaLetterOrDigit(char);
+    method @Deprecated public static boolean isJavaLetter(char);
+    method @Deprecated public static boolean isJavaLetterOrDigit(char);
     method public static boolean isLetter(char);
     method public static boolean isLetter(int);
     method public static boolean isLetterOrDigit(char);
@@ -58591,7 +58999,7 @@
     method public static boolean isLowerCase(int);
     method public static boolean isMirrored(char);
     method public static boolean isMirrored(int);
-    method public static deprecated boolean isSpace(char);
+    method @Deprecated public static boolean isSpace(char);
     method public static boolean isSpaceChar(char);
     method public static boolean isSpaceChar(int);
     method public static boolean isSupplementaryCodePoint(int);
@@ -58609,7 +59017,7 @@
     method public static boolean isWhitespace(char);
     method public static boolean isWhitespace(int);
     method public static char lowSurrogate(int);
-    method public static int offsetByCodePoints(java.lang.CharSequence, int, int);
+    method public static int offsetByCodePoints(@NonNull CharSequence, int, int);
     method public static int offsetByCodePoints(char[], int, int, int, int);
     method public static char reverseBytes(char);
     method public static int toChars(int, char[], int);
@@ -58617,12 +59025,12 @@
     method public static int toCodePoint(char, char);
     method public static char toLowerCase(char);
     method public static int toLowerCase(int);
-    method public static java.lang.String toString(char);
+    method @NonNull public static String toString(char);
     method public static char toTitleCase(char);
     method public static int toTitleCase(int);
     method public static char toUpperCase(char);
     method public static int toUpperCase(int);
-    method public static java.lang.Character valueOf(char);
+    method @NonNull public static Character valueOf(char);
     field public static final int BYTES = 2; // 0x2
     field public static final byte COMBINING_SPACING_MARK = 8; // 0x8
     field public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
@@ -58686,22 +59094,22 @@
     field public static final byte START_PUNCTUATION = 21; // 0x15
     field public static final byte SURROGATE = 19; // 0x13
     field public static final byte TITLECASE_LETTER = 3; // 0x3
-    field public static final java.lang.Class<java.lang.Character> TYPE;
+    field public static final Class<java.lang.Character> TYPE;
     field public static final byte UNASSIGNED = 0; // 0x0
     field public static final byte UPPERCASE_LETTER = 1; // 0x1
   }
 
   public static class Character.Subset {
-    ctor protected Character.Subset(java.lang.String);
-    method public final boolean equals(java.lang.Object);
+    ctor protected Character.Subset(@NonNull String);
+    method public final boolean equals(@Nullable Object);
     method public final int hashCode();
-    method public final java.lang.String toString();
+    method @NonNull public final String toString();
   }
 
   public static final class Character.UnicodeBlock extends java.lang.Character.Subset {
-    method public static java.lang.Character.UnicodeBlock forName(java.lang.String);
-    method public static java.lang.Character.UnicodeBlock of(char);
-    method public static java.lang.Character.UnicodeBlock of(int);
+    method @NonNull public static java.lang.Character.UnicodeBlock forName(@NonNull String);
+    method @Nullable public static java.lang.Character.UnicodeBlock of(char);
+    method @Nullable public static java.lang.Character.UnicodeBlock of(int);
     field public static final java.lang.Character.UnicodeBlock AEGEAN_NUMBERS;
     field public static final java.lang.Character.UnicodeBlock ALCHEMICAL_SYMBOLS;
     field public static final java.lang.Character.UnicodeBlock ALPHABETIC_PRESENTATION_FORMS;
@@ -58894,7 +59302,7 @@
     field public static final java.lang.Character.UnicodeBlock SUPPLEMENTAL_PUNCTUATION;
     field public static final java.lang.Character.UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_A;
     field public static final java.lang.Character.UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_B;
-    field public static final deprecated java.lang.Character.UnicodeBlock SURROGATES_AREA;
+    field @Deprecated public static final java.lang.Character.UnicodeBlock SURROGATES_AREA;
     field public static final java.lang.Character.UnicodeBlock SYLOTI_NAGRI;
     field public static final java.lang.Character.UnicodeBlock SYRIAC;
     field public static final java.lang.Character.UnicodeBlock TAGALOG;
@@ -58925,11 +59333,9 @@
     field public static final java.lang.Character.UnicodeBlock YI_SYLLABLES;
   }
 
-  public static final class Character.UnicodeScript extends java.lang.Enum {
-    method public static java.lang.Character.UnicodeScript forName(java.lang.String);
-    method public static java.lang.Character.UnicodeScript of(int);
-    method public static java.lang.Character.UnicodeScript valueOf(java.lang.String);
-    method public static final java.lang.Character.UnicodeScript[] values();
+  public enum Character.UnicodeScript {
+    method @NonNull public static java.lang.Character.UnicodeScript forName(@NonNull String);
+    method @NonNull public static java.lang.Character.UnicodeScript of(int);
     enum_constant public static final java.lang.Character.UnicodeScript ARABIC;
     enum_constant public static final java.lang.Character.UnicodeScript ARMENIAN;
     enum_constant public static final java.lang.Character.UnicodeScript AVESTAN;
@@ -59036,152 +59442,151 @@
   }
 
   public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
-    method public <U> java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
-    method public T cast(java.lang.Object);
+    method @NonNull public <U> Class<? extends U> asSubclass(@NonNull Class<U>);
+    method @Nullable public T cast(@Nullable Object);
     method public boolean desiredAssertionStatus();
-    method public static java.lang.Class<?> forName(java.lang.String) throws java.lang.ClassNotFoundException;
-    method public static java.lang.Class<?> forName(java.lang.String, boolean, java.lang.ClassLoader) throws java.lang.ClassNotFoundException;
-    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
+    method @NonNull public static Class<?> forName(@NonNull String) throws java.lang.ClassNotFoundException;
+    method @NonNull public static Class<?> forName(@NonNull String, boolean, @Nullable ClassLoader) throws java.lang.ClassNotFoundException;
+    method @Nullable public <A extends java.lang.annotation.Annotation> A getAnnotation(@NonNull Class<A>);
     method public java.lang.annotation.Annotation[] getAnnotations();
-    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
-    method public java.lang.String getCanonicalName();
-    method public java.lang.ClassLoader getClassLoader();
-    method public java.lang.Class<?>[] getClasses();
-    method public java.lang.Class<?> getComponentType();
-    method public java.lang.reflect.Constructor<T> getConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
+    method @NonNull public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(@NonNull Class<A>);
+    method @Nullable public String getCanonicalName();
+    method @Nullable public ClassLoader getClassLoader();
+    method public Class<?>[] getClasses();
+    method @Nullable public Class<?> getComponentType();
+    method @NonNull public java.lang.reflect.Constructor<T> getConstructor(Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
     method public java.lang.reflect.Constructor<?>[] getConstructors() throws java.lang.SecurityException;
-    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
+    method @Nullable public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(@NonNull Class<A>);
     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
-    method public java.lang.Class<?>[] getDeclaredClasses();
-    method public java.lang.reflect.Constructor<T> getDeclaredConstructor(java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
+    method public Class<?>[] getDeclaredClasses();
+    method @NonNull public java.lang.reflect.Constructor<T> getDeclaredConstructor(Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
     method public java.lang.reflect.Constructor<?>[] getDeclaredConstructors() throws java.lang.SecurityException;
-    method public java.lang.reflect.Field getDeclaredField(java.lang.String) throws java.lang.NoSuchFieldException;
+    method @NonNull public java.lang.reflect.Field getDeclaredField(@NonNull String) throws java.lang.NoSuchFieldException;
     method public java.lang.reflect.Field[] getDeclaredFields();
-    method public java.lang.reflect.Method getDeclaredMethod(java.lang.String, java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
+    method @NonNull public java.lang.reflect.Method getDeclaredMethod(@NonNull String, Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
     method public java.lang.reflect.Method[] getDeclaredMethods() throws java.lang.SecurityException;
-    method public java.lang.Class<?> getDeclaringClass();
-    method public java.lang.Class<?> getEnclosingClass();
-    method public java.lang.reflect.Constructor<?> getEnclosingConstructor();
-    method public java.lang.reflect.Method getEnclosingMethod();
+    method @Nullable public Class<?> getDeclaringClass();
+    method @Nullable public Class<?> getEnclosingClass();
+    method @Nullable public java.lang.reflect.Constructor<?> getEnclosingConstructor();
+    method @Nullable public java.lang.reflect.Method getEnclosingMethod();
     method public T[] getEnumConstants();
-    method public java.lang.reflect.Field getField(java.lang.String) throws java.lang.NoSuchFieldException;
+    method @NonNull public java.lang.reflect.Field getField(@NonNull String) throws java.lang.NoSuchFieldException;
     method public java.lang.reflect.Field[] getFields() throws java.lang.SecurityException;
     method public java.lang.reflect.Type[] getGenericInterfaces();
-    method public java.lang.reflect.Type getGenericSuperclass();
-    method public java.lang.Class<?>[] getInterfaces();
-    method public java.lang.reflect.Method getMethod(java.lang.String, java.lang.Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
+    method @Nullable public java.lang.reflect.Type getGenericSuperclass();
+    method public Class<?>[] getInterfaces();
+    method @NonNull public java.lang.reflect.Method getMethod(@NonNull String, Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
     method public java.lang.reflect.Method[] getMethods() throws java.lang.SecurityException;
     method public int getModifiers();
-    method public java.lang.String getName();
-    method public java.lang.Package getPackage();
-    method public java.security.ProtectionDomain getProtectionDomain();
-    method public java.net.URL getResource(java.lang.String);
-    method public java.io.InputStream getResourceAsStream(java.lang.String);
-    method public java.lang.Object[] getSigners();
-    method public java.lang.String getSimpleName();
-    method public java.lang.Class<? super T> getSuperclass();
-    method public synchronized java.lang.reflect.TypeVariable<java.lang.Class<T>>[] getTypeParameters();
+    method @NonNull public String getName();
+    method @Nullable public Package getPackage();
+    method @Nullable public java.security.ProtectionDomain getProtectionDomain();
+    method @Nullable public java.net.URL getResource(@NonNull String);
+    method @Nullable public java.io.InputStream getResourceAsStream(@NonNull String);
+    method public Object[] getSigners();
+    method @NonNull public String getSimpleName();
+    method @Nullable public Class<? super T> getSuperclass();
+    method public java.lang.reflect.TypeVariable<java.lang.Class<T>>[] getTypeParameters();
     method public boolean isAnnotation();
     method public boolean isAnonymousClass();
     method public boolean isArray();
-    method public boolean isAssignableFrom(java.lang.Class<?>);
+    method public boolean isAssignableFrom(@NonNull Class<?>);
     method public boolean isEnum();
-    method public boolean isInstance(java.lang.Object);
+    method public boolean isInstance(@Nullable Object);
     method public boolean isInterface();
     method public boolean isLocalClass();
     method public boolean isMemberClass();
     method public boolean isPrimitive();
     method public boolean isSynthetic();
-    method public T newInstance() throws java.lang.IllegalAccessException, java.lang.InstantiationException;
-    method public java.lang.String toGenericString();
+    method @NonNull public T newInstance() throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method @NonNull public String toGenericString();
   }
 
   public class ClassCastException extends java.lang.RuntimeException {
     ctor public ClassCastException();
-    ctor public ClassCastException(java.lang.String);
+    ctor public ClassCastException(String);
   }
 
   public class ClassCircularityError extends java.lang.LinkageError {
     ctor public ClassCircularityError();
-    ctor public ClassCircularityError(java.lang.String);
+    ctor public ClassCircularityError(String);
   }
 
   public class ClassFormatError extends java.lang.LinkageError {
     ctor public ClassFormatError();
-    ctor public ClassFormatError(java.lang.String);
+    ctor public ClassFormatError(String);
   }
 
   public abstract class ClassLoader {
-    ctor protected ClassLoader(java.lang.ClassLoader);
+    ctor protected ClassLoader(ClassLoader);
     ctor protected ClassLoader();
     method public void clearAssertionStatus();
-    method protected final deprecated java.lang.Class<?> defineClass(byte[], int, int) throws java.lang.ClassFormatError;
-    method protected final java.lang.Class<?> defineClass(java.lang.String, byte[], int, int) throws java.lang.ClassFormatError;
-    method protected final java.lang.Class<?> defineClass(java.lang.String, byte[], int, int, java.security.ProtectionDomain) throws java.lang.ClassFormatError;
-    method protected final java.lang.Class<?> defineClass(java.lang.String, java.nio.ByteBuffer, java.security.ProtectionDomain) throws java.lang.ClassFormatError;
-    method protected java.lang.Package definePackage(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.net.URL) throws java.lang.IllegalArgumentException;
-    method protected java.lang.Class<?> findClass(java.lang.String) throws java.lang.ClassNotFoundException;
-    method protected java.lang.String findLibrary(java.lang.String);
-    method protected final java.lang.Class<?> findLoadedClass(java.lang.String);
-    method protected java.net.URL findResource(java.lang.String);
-    method protected java.util.Enumeration<java.net.URL> findResources(java.lang.String) throws java.io.IOException;
-    method protected final java.lang.Class<?> findSystemClass(java.lang.String) throws java.lang.ClassNotFoundException;
-    method protected java.lang.Package getPackage(java.lang.String);
-    method protected java.lang.Package[] getPackages();
-    method public final java.lang.ClassLoader getParent();
-    method public java.net.URL getResource(java.lang.String);
-    method public java.io.InputStream getResourceAsStream(java.lang.String);
-    method public java.util.Enumeration<java.net.URL> getResources(java.lang.String) throws java.io.IOException;
-    method public static java.lang.ClassLoader getSystemClassLoader();
-    method public static java.net.URL getSystemResource(java.lang.String);
-    method public static java.io.InputStream getSystemResourceAsStream(java.lang.String);
-    method public static java.util.Enumeration<java.net.URL> getSystemResources(java.lang.String) throws java.io.IOException;
-    method public java.lang.Class<?> loadClass(java.lang.String) throws java.lang.ClassNotFoundException;
-    method protected java.lang.Class<?> loadClass(java.lang.String, boolean) throws java.lang.ClassNotFoundException;
+    method @Deprecated protected final Class<?> defineClass(byte[], int, int) throws java.lang.ClassFormatError;
+    method protected final Class<?> defineClass(String, byte[], int, int) throws java.lang.ClassFormatError;
+    method protected final Class<?> defineClass(String, byte[], int, int, java.security.ProtectionDomain) throws java.lang.ClassFormatError;
+    method protected final Class<?> defineClass(String, java.nio.ByteBuffer, java.security.ProtectionDomain) throws java.lang.ClassFormatError;
+    method protected Package definePackage(String, String, String, String, String, String, String, java.net.URL) throws java.lang.IllegalArgumentException;
+    method protected Class<?> findClass(String) throws java.lang.ClassNotFoundException;
+    method protected String findLibrary(String);
+    method protected final Class<?> findLoadedClass(String);
+    method protected java.net.URL findResource(String);
+    method protected java.util.Enumeration<java.net.URL> findResources(String) throws java.io.IOException;
+    method protected final Class<?> findSystemClass(String) throws java.lang.ClassNotFoundException;
+    method protected Package getPackage(String);
+    method protected Package[] getPackages();
+    method public final ClassLoader getParent();
+    method public java.net.URL getResource(String);
+    method public java.io.InputStream getResourceAsStream(String);
+    method public java.util.Enumeration<java.net.URL> getResources(String) throws java.io.IOException;
+    method public static ClassLoader getSystemClassLoader();
+    method public static java.net.URL getSystemResource(String);
+    method public static java.io.InputStream getSystemResourceAsStream(String);
+    method public static java.util.Enumeration<java.net.URL> getSystemResources(String) throws java.io.IOException;
+    method public Class<?> loadClass(String) throws java.lang.ClassNotFoundException;
+    method protected Class<?> loadClass(String, boolean) throws java.lang.ClassNotFoundException;
     method protected static boolean registerAsParallelCapable();
-    method protected final void resolveClass(java.lang.Class<?>);
-    method public void setClassAssertionStatus(java.lang.String, boolean);
+    method protected final void resolveClass(Class<?>);
+    method public void setClassAssertionStatus(String, boolean);
     method public void setDefaultAssertionStatus(boolean);
-    method public void setPackageAssertionStatus(java.lang.String, boolean);
-    method protected final void setSigners(java.lang.Class<?>, java.lang.Object[]);
+    method public void setPackageAssertionStatus(String, boolean);
+    method protected final void setSigners(Class<?>, Object[]);
   }
 
   public class ClassNotFoundException extends java.lang.ReflectiveOperationException {
     ctor public ClassNotFoundException();
-    ctor public ClassNotFoundException(java.lang.String);
-    ctor public ClassNotFoundException(java.lang.String, java.lang.Throwable);
-    method public java.lang.Throwable getCause();
-    method public java.lang.Throwable getException();
+    ctor public ClassNotFoundException(String);
+    ctor public ClassNotFoundException(String, Throwable);
+    method public Throwable getException();
   }
 
   public class CloneNotSupportedException extends java.lang.Exception {
     ctor public CloneNotSupportedException();
-    ctor public CloneNotSupportedException(java.lang.String);
+    ctor public CloneNotSupportedException(String);
   }
 
-  public abstract interface Cloneable {
+  public interface Cloneable {
   }
 
-  public abstract interface Comparable<T> {
-    method public abstract int compareTo(T);
+  public interface Comparable<T> {
+    method public int compareTo(T);
   }
 
   public final class Compiler {
-    method public static java.lang.Object command(java.lang.Object);
-    method public static boolean compileClass(java.lang.Class<?>);
-    method public static boolean compileClasses(java.lang.String);
+    method public static Object command(Object);
+    method public static boolean compileClass(Class<?>);
+    method public static boolean compileClasses(String);
     method public static void disable();
     method public static void enable();
   }
 
-  public abstract class Deprecated implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PACKAGE, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.TYPE}) public @interface Deprecated {
   }
 
-  public final class Double extends java.lang.Number implements java.lang.Comparable {
+  public final class Double extends java.lang.Number implements java.lang.Comparable<java.lang.Double> {
     ctor public Double(double);
-    ctor public Double(java.lang.String) throws java.lang.NumberFormatException;
+    ctor public Double(@NonNull String) throws java.lang.NumberFormatException;
     method public static int compare(double, double);
-    method public int compareTo(java.lang.Double);
+    method public int compareTo(@NonNull Double);
     method public static long doubleToLongBits(double);
     method public static long doubleToRawLongBits(double);
     method public double doubleValue();
@@ -59197,12 +59602,12 @@
     method public long longValue();
     method public static double max(double, double);
     method public static double min(double, double);
-    method public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
+    method public static double parseDouble(@NonNull String) throws java.lang.NumberFormatException;
     method public static double sum(double, double);
-    method public static java.lang.String toHexString(double);
-    method public static java.lang.String toString(double);
-    method public static java.lang.Double valueOf(java.lang.String) throws java.lang.NumberFormatException;
-    method public static java.lang.Double valueOf(double);
+    method @NonNull public static String toHexString(double);
+    method @NonNull public static String toString(double);
+    method @NonNull public static Double valueOf(@NonNull String) throws java.lang.NumberFormatException;
+    method @NonNull public static Double valueOf(double);
     field public static final int BYTES = 8; // 0x8
     field public static final int MAX_EXPONENT = 1023; // 0x3ff
     field public static final double MAX_VALUE = 1.7976931348623157E308;
@@ -59213,58 +59618,57 @@
     field public static final double NaN = (0.0/0.0);
     field public static final double POSITIVE_INFINITY = (1.0/0.0);
     field public static final int SIZE = 64; // 0x40
-    field public static final java.lang.Class<java.lang.Double> TYPE;
+    field public static final Class<java.lang.Double> TYPE;
   }
 
-  public abstract class Enum<E extends java.lang.Enum<E>> implements java.lang.Comparable java.io.Serializable {
-    ctor protected Enum(java.lang.String, int);
-    method protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException;
+  public abstract class Enum<E extends java.lang.Enum<E>> implements java.lang.Comparable<E> java.io.Serializable {
+    ctor protected Enum(@NonNull String, int);
+    method @NonNull protected final Object clone() throws java.lang.CloneNotSupportedException;
     method public final int compareTo(E);
-    method public final boolean equals(java.lang.Object);
+    method public final boolean equals(@Nullable Object);
     method protected final void finalize();
-    method public final java.lang.Class<E> getDeclaringClass();
+    method @NonNull public final Class<E> getDeclaringClass();
     method public final int hashCode();
-    method public final java.lang.String name();
+    method @NonNull public final String name();
     method public final int ordinal();
-    method public static <T extends java.lang.Enum<T>> T valueOf(java.lang.Class<T>, java.lang.String);
+    method @NonNull public static <T extends java.lang.Enum<T>> T valueOf(@NonNull Class<T>, @NonNull String);
   }
 
   public class EnumConstantNotPresentException extends java.lang.RuntimeException {
-    ctor public EnumConstantNotPresentException(java.lang.Class<? extends java.lang.Enum>, java.lang.String);
-    method public java.lang.String constantName();
-    method public java.lang.Class<? extends java.lang.Enum> enumType();
+    ctor public EnumConstantNotPresentException(Class<? extends java.lang.Enum>, String);
+    method public String constantName();
+    method public Class<? extends java.lang.Enum> enumType();
   }
 
   public class Error extends java.lang.Throwable {
     ctor public Error();
-    ctor public Error(java.lang.String);
-    ctor public Error(java.lang.String, java.lang.Throwable);
-    ctor public Error(java.lang.Throwable);
-    ctor protected Error(java.lang.String, java.lang.Throwable, boolean, boolean);
+    ctor public Error(String);
+    ctor public Error(String, Throwable);
+    ctor public Error(Throwable);
+    ctor protected Error(String, Throwable, boolean, boolean);
   }
 
   public class Exception extends java.lang.Throwable {
     ctor public Exception();
-    ctor public Exception(java.lang.String);
-    ctor public Exception(java.lang.String, java.lang.Throwable);
-    ctor public Exception(java.lang.Throwable);
-    ctor protected Exception(java.lang.String, java.lang.Throwable, boolean, boolean);
+    ctor public Exception(String);
+    ctor public Exception(String, Throwable);
+    ctor public Exception(Throwable);
+    ctor protected Exception(String, Throwable, boolean, boolean);
   }
 
   public class ExceptionInInitializerError extends java.lang.LinkageError {
     ctor public ExceptionInInitializerError();
-    ctor public ExceptionInInitializerError(java.lang.Throwable);
-    ctor public ExceptionInInitializerError(java.lang.String);
-    method public java.lang.Throwable getCause();
-    method public java.lang.Throwable getException();
+    ctor public ExceptionInInitializerError(Throwable);
+    ctor public ExceptionInInitializerError(String);
+    method public Throwable getException();
   }
 
-  public final class Float extends java.lang.Number implements java.lang.Comparable {
+  public final class Float extends java.lang.Number implements java.lang.Comparable<java.lang.Float> {
     ctor public Float(float);
     ctor public Float(double);
-    ctor public Float(java.lang.String) throws java.lang.NumberFormatException;
+    ctor public Float(@NonNull String) throws java.lang.NumberFormatException;
     method public static int compare(float, float);
-    method public int compareTo(java.lang.Float);
+    method public int compareTo(@NonNull Float);
     method public double doubleValue();
     method public static int floatToIntBits(float);
     method public static int floatToRawIntBits(float);
@@ -59280,12 +59684,12 @@
     method public long longValue();
     method public static float max(float, float);
     method public static float min(float, float);
-    method public static float parseFloat(java.lang.String) throws java.lang.NumberFormatException;
+    method public static float parseFloat(@NonNull String) throws java.lang.NumberFormatException;
     method public static float sum(float, float);
-    method public static java.lang.String toHexString(float);
-    method public static java.lang.String toString(float);
-    method public static java.lang.Float valueOf(java.lang.String) throws java.lang.NumberFormatException;
-    method public static java.lang.Float valueOf(float);
+    method @NonNull public static String toHexString(float);
+    method @NonNull public static String toString(float);
+    method @NonNull public static Float valueOf(@NonNull String) throws java.lang.NumberFormatException;
+    method @NonNull public static Float valueOf(float);
     field public static final int BYTES = 4; // 0x4
     field public static final int MAX_EXPONENT = 127; // 0x7f
     field public static final float MAX_VALUE = 3.4028235E38f;
@@ -59296,85 +59700,85 @@
     field public static final float NaN = (0.0f/0.0f);
     field public static final float POSITIVE_INFINITY = (1.0f/0.0f);
     field public static final int SIZE = 32; // 0x20
-    field public static final java.lang.Class<java.lang.Float> TYPE;
+    field public static final Class<java.lang.Float> TYPE;
   }
 
-  public abstract class FunctionalInterface implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public @interface FunctionalInterface {
   }
 
   public class IllegalAccessError extends java.lang.IncompatibleClassChangeError {
     ctor public IllegalAccessError();
-    ctor public IllegalAccessError(java.lang.String);
+    ctor public IllegalAccessError(String);
   }
 
   public class IllegalAccessException extends java.lang.ReflectiveOperationException {
     ctor public IllegalAccessException();
-    ctor public IllegalAccessException(java.lang.String);
+    ctor public IllegalAccessException(String);
   }
 
   public class IllegalArgumentException extends java.lang.RuntimeException {
     ctor public IllegalArgumentException();
-    ctor public IllegalArgumentException(java.lang.String);
-    ctor public IllegalArgumentException(java.lang.String, java.lang.Throwable);
-    ctor public IllegalArgumentException(java.lang.Throwable);
+    ctor public IllegalArgumentException(String);
+    ctor public IllegalArgumentException(String, Throwable);
+    ctor public IllegalArgumentException(Throwable);
   }
 
   public class IllegalMonitorStateException extends java.lang.RuntimeException {
     ctor public IllegalMonitorStateException();
-    ctor public IllegalMonitorStateException(java.lang.String);
+    ctor public IllegalMonitorStateException(String);
   }
 
   public class IllegalStateException extends java.lang.RuntimeException {
     ctor public IllegalStateException();
-    ctor public IllegalStateException(java.lang.String);
-    ctor public IllegalStateException(java.lang.String, java.lang.Throwable);
-    ctor public IllegalStateException(java.lang.Throwable);
+    ctor public IllegalStateException(String);
+    ctor public IllegalStateException(String, Throwable);
+    ctor public IllegalStateException(Throwable);
   }
 
   public class IllegalThreadStateException extends java.lang.IllegalArgumentException {
     ctor public IllegalThreadStateException();
-    ctor public IllegalThreadStateException(java.lang.String);
+    ctor public IllegalThreadStateException(String);
   }
 
   public class IncompatibleClassChangeError extends java.lang.LinkageError {
     ctor public IncompatibleClassChangeError();
-    ctor public IncompatibleClassChangeError(java.lang.String);
+    ctor public IncompatibleClassChangeError(String);
   }
 
   public class IndexOutOfBoundsException extends java.lang.RuntimeException {
     ctor public IndexOutOfBoundsException();
-    ctor public IndexOutOfBoundsException(java.lang.String);
+    ctor public IndexOutOfBoundsException(String);
   }
 
-  public class InheritableThreadLocal<T> extends java.lang.ThreadLocal {
+  public class InheritableThreadLocal<T> extends java.lang.ThreadLocal<T> {
     ctor public InheritableThreadLocal();
     method protected T childValue(T);
   }
 
   public class InstantiationError extends java.lang.IncompatibleClassChangeError {
     ctor public InstantiationError();
-    ctor public InstantiationError(java.lang.String);
+    ctor public InstantiationError(String);
   }
 
   public class InstantiationException extends java.lang.ReflectiveOperationException {
     ctor public InstantiationException();
-    ctor public InstantiationException(java.lang.String);
+    ctor public InstantiationException(String);
   }
 
-  public final class Integer extends java.lang.Number implements java.lang.Comparable {
+  public final class Integer extends java.lang.Number implements java.lang.Comparable<java.lang.Integer> {
     ctor public Integer(int);
-    ctor public Integer(java.lang.String) throws java.lang.NumberFormatException;
+    ctor public Integer(@NonNull String) throws java.lang.NumberFormatException;
     method public static int bitCount(int);
     method public static int compare(int, int);
-    method public int compareTo(java.lang.Integer);
+    method public int compareTo(@NonNull Integer);
     method public static int compareUnsigned(int, int);
-    method public static java.lang.Integer decode(java.lang.String) throws java.lang.NumberFormatException;
+    method @NonNull public static Integer decode(@NonNull String) throws java.lang.NumberFormatException;
     method public static int divideUnsigned(int, int);
     method public double doubleValue();
     method public float floatValue();
-    method public static java.lang.Integer getInteger(java.lang.String);
-    method public static java.lang.Integer getInteger(java.lang.String, int);
-    method public static java.lang.Integer getInteger(java.lang.String, java.lang.Integer);
+    method @Nullable public static Integer getInteger(@NonNull String);
+    method @Nullable public static Integer getInteger(@NonNull String, int);
+    method @Nullable public static Integer getInteger(@NonNull String, @Nullable Integer);
     method public static int hashCode(int);
     method public static int highestOneBit(int);
     method public int intValue();
@@ -59384,10 +59788,10 @@
     method public static int min(int, int);
     method public static int numberOfLeadingZeros(int);
     method public static int numberOfTrailingZeros(int);
-    method public static int parseInt(java.lang.String, int) throws java.lang.NumberFormatException;
-    method public static int parseInt(java.lang.String) throws java.lang.NumberFormatException;
-    method public static int parseUnsignedInt(java.lang.String, int) throws java.lang.NumberFormatException;
-    method public static int parseUnsignedInt(java.lang.String) throws java.lang.NumberFormatException;
+    method public static int parseInt(@NonNull String, int) throws java.lang.NumberFormatException;
+    method public static int parseInt(@NonNull String) throws java.lang.NumberFormatException;
+    method public static int parseUnsignedInt(@NonNull String, int) throws java.lang.NumberFormatException;
+    method public static int parseUnsignedInt(@NonNull String) throws java.lang.NumberFormatException;
     method public static int remainderUnsigned(int, int);
     method public static int reverse(int);
     method public static int reverseBytes(int);
@@ -59395,62 +59799,62 @@
     method public static int rotateRight(int, int);
     method public static int signum(int);
     method public static int sum(int, int);
-    method public static java.lang.String toBinaryString(int);
-    method public static java.lang.String toHexString(int);
-    method public static java.lang.String toOctalString(int);
-    method public static java.lang.String toString(int, int);
-    method public static java.lang.String toString(int);
+    method @NonNull public static String toBinaryString(int);
+    method @NonNull public static String toHexString(int);
+    method @NonNull public static String toOctalString(int);
+    method @NonNull public static String toString(int, int);
+    method @NonNull public static String toString(int);
     method public static long toUnsignedLong(int);
-    method public static java.lang.String toUnsignedString(int, int);
-    method public static java.lang.String toUnsignedString(int);
-    method public static java.lang.Integer valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
-    method public static java.lang.Integer valueOf(java.lang.String) throws java.lang.NumberFormatException;
-    method public static java.lang.Integer valueOf(int);
+    method @NonNull public static String toUnsignedString(int, int);
+    method @NonNull public static String toUnsignedString(int);
+    method @NonNull public static Integer valueOf(@NonNull String, int) throws java.lang.NumberFormatException;
+    method @NonNull public static Integer valueOf(@NonNull String) throws java.lang.NumberFormatException;
+    method @NonNull public static Integer valueOf(int);
     field public static final int BYTES = 4; // 0x4
     field public static final int MAX_VALUE = 2147483647; // 0x7fffffff
     field public static final int MIN_VALUE = -2147483648; // 0x80000000
     field public static final int SIZE = 32; // 0x20
-    field public static final java.lang.Class<java.lang.Integer> TYPE;
+    field public static final Class<java.lang.Integer> TYPE;
   }
 
   public class InternalError extends java.lang.VirtualMachineError {
     ctor public InternalError();
-    ctor public InternalError(java.lang.String);
-    ctor public InternalError(java.lang.String, java.lang.Throwable);
-    ctor public InternalError(java.lang.Throwable);
+    ctor public InternalError(String);
+    ctor public InternalError(String, Throwable);
+    ctor public InternalError(Throwable);
   }
 
   public class InterruptedException extends java.lang.Exception {
     ctor public InterruptedException();
-    ctor public InterruptedException(java.lang.String);
+    ctor public InterruptedException(String);
   }
 
-  public abstract interface Iterable<T> {
-    method public default void forEach(java.util.function.Consumer<? super T>);
-    method public abstract java.util.Iterator<T> iterator();
-    method public default java.util.Spliterator<T> spliterator();
+  public interface Iterable<T> {
+    method public default void forEach(@NonNull java.util.function.Consumer<? super T>);
+    method @NonNull public java.util.Iterator<T> iterator();
+    method @NonNull public default java.util.Spliterator<T> spliterator();
   }
 
   public class LinkageError extends java.lang.Error {
     ctor public LinkageError();
-    ctor public LinkageError(java.lang.String);
-    ctor public LinkageError(java.lang.String, java.lang.Throwable);
+    ctor public LinkageError(String);
+    ctor public LinkageError(String, Throwable);
   }
 
-  public final class Long extends java.lang.Number implements java.lang.Comparable {
+  public final class Long extends java.lang.Number implements java.lang.Comparable<java.lang.Long> {
     ctor public Long(long);
-    ctor public Long(java.lang.String) throws java.lang.NumberFormatException;
+    ctor public Long(@NonNull String) throws java.lang.NumberFormatException;
     method public static int bitCount(long);
     method public static int compare(long, long);
-    method public int compareTo(java.lang.Long);
+    method public int compareTo(@NonNull Long);
     method public static int compareUnsigned(long, long);
-    method public static java.lang.Long decode(java.lang.String) throws java.lang.NumberFormatException;
+    method @NonNull public static Long decode(@NonNull String) throws java.lang.NumberFormatException;
     method public static long divideUnsigned(long, long);
     method public double doubleValue();
     method public float floatValue();
-    method public static java.lang.Long getLong(java.lang.String);
-    method public static java.lang.Long getLong(java.lang.String, long);
-    method public static java.lang.Long getLong(java.lang.String, java.lang.Long);
+    method @Nullable public static Long getLong(@NonNull String);
+    method @Nullable public static Long getLong(@NonNull String, long);
+    method @Nullable public static Long getLong(@NonNull String, @Nullable Long);
     method public static int hashCode(long);
     method public static long highestOneBit(long);
     method public int intValue();
@@ -59460,10 +59864,10 @@
     method public static long min(long, long);
     method public static int numberOfLeadingZeros(long);
     method public static int numberOfTrailingZeros(long);
-    method public static long parseLong(java.lang.String, int) throws java.lang.NumberFormatException;
-    method public static long parseLong(java.lang.String) throws java.lang.NumberFormatException;
-    method public static long parseUnsignedLong(java.lang.String, int) throws java.lang.NumberFormatException;
-    method public static long parseUnsignedLong(java.lang.String) throws java.lang.NumberFormatException;
+    method public static long parseLong(@NonNull String, int) throws java.lang.NumberFormatException;
+    method public static long parseLong(@NonNull String) throws java.lang.NumberFormatException;
+    method public static long parseUnsignedLong(@NonNull String, int) throws java.lang.NumberFormatException;
+    method public static long parseUnsignedLong(@NonNull String) throws java.lang.NumberFormatException;
     method public static long remainderUnsigned(long, long);
     method public static long reverse(long);
     method public static long reverseBytes(long);
@@ -59471,21 +59875,21 @@
     method public static long rotateRight(long, int);
     method public static int signum(long);
     method public static long sum(long, long);
-    method public static java.lang.String toBinaryString(long);
-    method public static java.lang.String toHexString(long);
-    method public static java.lang.String toOctalString(long);
-    method public static java.lang.String toString(long, int);
-    method public static java.lang.String toString(long);
-    method public static java.lang.String toUnsignedString(long, int);
-    method public static java.lang.String toUnsignedString(long);
-    method public static java.lang.Long valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
-    method public static java.lang.Long valueOf(java.lang.String) throws java.lang.NumberFormatException;
-    method public static java.lang.Long valueOf(long);
+    method @NonNull public static String toBinaryString(long);
+    method @NonNull public static String toHexString(long);
+    method @NonNull public static String toOctalString(long);
+    method @NonNull public static String toString(long, int);
+    method @NonNull public static String toString(long);
+    method @NonNull public static String toUnsignedString(long, int);
+    method @NonNull public static String toUnsignedString(long);
+    method @NonNull public static Long valueOf(@NonNull String, int) throws java.lang.NumberFormatException;
+    method @NonNull public static Long valueOf(@NonNull String) throws java.lang.NumberFormatException;
+    method @NonNull public static Long valueOf(long);
     field public static final int BYTES = 8; // 0x8
     field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
     field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
     field public static final int SIZE = 64; // 0x40
-    field public static final java.lang.Class<java.lang.Long> TYPE;
+    field public static final Class<java.lang.Long> TYPE;
   }
 
   public final class Math {
@@ -59568,37 +59972,37 @@
 
   public class NegativeArraySizeException extends java.lang.RuntimeException {
     ctor public NegativeArraySizeException();
-    ctor public NegativeArraySizeException(java.lang.String);
+    ctor public NegativeArraySizeException(String);
   }
 
   public class NoClassDefFoundError extends java.lang.LinkageError {
     ctor public NoClassDefFoundError();
-    ctor public NoClassDefFoundError(java.lang.String);
+    ctor public NoClassDefFoundError(String);
   }
 
   public class NoSuchFieldError extends java.lang.IncompatibleClassChangeError {
     ctor public NoSuchFieldError();
-    ctor public NoSuchFieldError(java.lang.String);
+    ctor public NoSuchFieldError(String);
   }
 
   public class NoSuchFieldException extends java.lang.ReflectiveOperationException {
     ctor public NoSuchFieldException();
-    ctor public NoSuchFieldException(java.lang.String);
+    ctor public NoSuchFieldException(String);
   }
 
   public class NoSuchMethodError extends java.lang.IncompatibleClassChangeError {
     ctor public NoSuchMethodError();
-    ctor public NoSuchMethodError(java.lang.String);
+    ctor public NoSuchMethodError(String);
   }
 
   public class NoSuchMethodException extends java.lang.ReflectiveOperationException {
     ctor public NoSuchMethodException();
-    ctor public NoSuchMethodException(java.lang.String);
+    ctor public NoSuchMethodException(String);
   }
 
   public class NullPointerException extends java.lang.RuntimeException {
     ctor public NullPointerException();
-    ctor public NullPointerException(java.lang.String);
+    ctor public NullPointerException(String);
   }
 
   public abstract class Number implements java.io.Serializable {
@@ -59613,19 +60017,19 @@
 
   public class NumberFormatException extends java.lang.IllegalArgumentException {
     ctor public NumberFormatException();
-    ctor public NumberFormatException(java.lang.String);
+    ctor public NumberFormatException(String);
   }
 
   public class Object {
     ctor public Object();
-    method protected java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method public boolean equals(java.lang.Object);
+    method @NonNull protected Object clone() throws java.lang.CloneNotSupportedException;
+    method public boolean equals(@Nullable Object);
     method protected void finalize() throws java.lang.Throwable;
-    method public final java.lang.Class<?> getClass();
+    method @NonNull public final Class<?> getClass();
     method public int hashCode();
     method public final void notify();
     method public final void notifyAll();
-    method public java.lang.String toString();
+    method @NonNull public String toString();
     method public final void wait(long) throws java.lang.InterruptedException;
     method public final void wait(long, int) throws java.lang.InterruptedException;
     method public final void wait() throws java.lang.InterruptedException;
@@ -59633,29 +60037,29 @@
 
   public class OutOfMemoryError extends java.lang.VirtualMachineError {
     ctor public OutOfMemoryError();
-    ctor public OutOfMemoryError(java.lang.String);
+    ctor public OutOfMemoryError(String);
   }
 
-  public abstract class Override implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public @interface Override {
   }
 
   public class Package implements java.lang.reflect.AnnotatedElement {
-    method public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A getAnnotation(Class<A>);
     method public java.lang.annotation.Annotation[] getAnnotations();
-    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A>);
-    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(Class<A>);
+    method public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(Class<A>);
     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
-    method public <A extends java.lang.annotation.Annotation> A[] getDeclaredAnnotationsByType(java.lang.Class<A>);
-    method public java.lang.String getImplementationTitle();
-    method public java.lang.String getImplementationVendor();
-    method public java.lang.String getImplementationVersion();
-    method public java.lang.String getName();
-    method public static java.lang.Package getPackage(java.lang.String);
-    method public static java.lang.Package[] getPackages();
-    method public java.lang.String getSpecificationTitle();
-    method public java.lang.String getSpecificationVendor();
-    method public java.lang.String getSpecificationVersion();
-    method public boolean isCompatibleWith(java.lang.String) throws java.lang.NumberFormatException;
+    method public <A extends java.lang.annotation.Annotation> A[] getDeclaredAnnotationsByType(Class<A>);
+    method public String getImplementationTitle();
+    method public String getImplementationVendor();
+    method public String getImplementationVersion();
+    method public String getName();
+    method public static Package getPackage(String);
+    method public static Package[] getPackages();
+    method public String getSpecificationTitle();
+    method public String getSpecificationVendor();
+    method public String getSpecificationVersion();
+    method public boolean isCompatibleWith(String) throws java.lang.NumberFormatException;
     method public boolean isSealed();
     method public boolean isSealed(java.net.URL);
   }
@@ -59663,7 +60067,7 @@
   public abstract class Process {
     ctor public Process();
     method public abstract void destroy();
-    method public java.lang.Process destroyForcibly();
+    method public Process destroyForcibly();
     method public abstract int exitValue();
     method public abstract java.io.InputStream getErrorStream();
     method public abstract java.io.InputStream getInputStream();
@@ -59676,28 +60080,28 @@
   public final class ProcessBuilder {
     ctor public ProcessBuilder(java.util.List<java.lang.String>);
     ctor public ProcessBuilder(java.lang.String...);
-    method public java.lang.ProcessBuilder command(java.util.List<java.lang.String>);
-    method public java.lang.ProcessBuilder command(java.lang.String...);
+    method public ProcessBuilder command(java.util.List<java.lang.String>);
+    method public ProcessBuilder command(java.lang.String...);
     method public java.util.List<java.lang.String> command();
     method public java.io.File directory();
-    method public java.lang.ProcessBuilder directory(java.io.File);
-    method public java.util.Map<java.lang.String, java.lang.String> environment();
-    method public java.lang.ProcessBuilder inheritIO();
-    method public java.lang.ProcessBuilder redirectError(java.lang.ProcessBuilder.Redirect);
-    method public java.lang.ProcessBuilder redirectError(java.io.File);
+    method public ProcessBuilder directory(java.io.File);
+    method public java.util.Map<java.lang.String,java.lang.String> environment();
+    method public ProcessBuilder inheritIO();
+    method public ProcessBuilder redirectError(java.lang.ProcessBuilder.Redirect);
+    method public ProcessBuilder redirectError(java.io.File);
     method public java.lang.ProcessBuilder.Redirect redirectError();
     method public boolean redirectErrorStream();
-    method public java.lang.ProcessBuilder redirectErrorStream(boolean);
-    method public java.lang.ProcessBuilder redirectInput(java.lang.ProcessBuilder.Redirect);
-    method public java.lang.ProcessBuilder redirectInput(java.io.File);
+    method public ProcessBuilder redirectErrorStream(boolean);
+    method public ProcessBuilder redirectInput(java.lang.ProcessBuilder.Redirect);
+    method public ProcessBuilder redirectInput(java.io.File);
     method public java.lang.ProcessBuilder.Redirect redirectInput();
-    method public java.lang.ProcessBuilder redirectOutput(java.lang.ProcessBuilder.Redirect);
-    method public java.lang.ProcessBuilder redirectOutput(java.io.File);
+    method public ProcessBuilder redirectOutput(java.lang.ProcessBuilder.Redirect);
+    method public ProcessBuilder redirectOutput(java.io.File);
     method public java.lang.ProcessBuilder.Redirect redirectOutput();
-    method public java.lang.Process start() throws java.io.IOException;
+    method public Process start() throws java.io.IOException;
   }
 
-  public static abstract class ProcessBuilder.Redirect {
+  public abstract static class ProcessBuilder.Redirect {
     method public static java.lang.ProcessBuilder.Redirect appendTo(java.io.File);
     method public java.io.File file();
     method public static java.lang.ProcessBuilder.Redirect from(java.io.File);
@@ -59707,9 +60111,7 @@
     field public static final java.lang.ProcessBuilder.Redirect PIPE;
   }
 
-  public static final class ProcessBuilder.Redirect.Type extends java.lang.Enum {
-    method public static java.lang.ProcessBuilder.Redirect.Type valueOf(java.lang.String);
-    method public static final java.lang.ProcessBuilder.Redirect.Type[] values();
+  public enum ProcessBuilder.Redirect.Type {
     enum_constant public static final java.lang.ProcessBuilder.Redirect.Type APPEND;
     enum_constant public static final java.lang.ProcessBuilder.Redirect.Type INHERIT;
     enum_constant public static final java.lang.ProcessBuilder.Redirect.Type PIPE;
@@ -59717,43 +60119,43 @@
     enum_constant public static final java.lang.ProcessBuilder.Redirect.Type WRITE;
   }
 
-  public abstract interface Readable {
-    method public abstract int read(java.nio.CharBuffer) throws java.io.IOException;
+  public interface Readable {
+    method public int read(java.nio.CharBuffer) throws java.io.IOException;
   }
 
   public class ReflectiveOperationException extends java.lang.Exception {
     ctor public ReflectiveOperationException();
-    ctor public ReflectiveOperationException(java.lang.String);
-    ctor public ReflectiveOperationException(java.lang.String, java.lang.Throwable);
-    ctor public ReflectiveOperationException(java.lang.Throwable);
+    ctor public ReflectiveOperationException(String);
+    ctor public ReflectiveOperationException(String, Throwable);
+    ctor public ReflectiveOperationException(Throwable);
   }
 
-  public abstract interface Runnable {
-    method public abstract void run();
+  @java.lang.FunctionalInterface public interface Runnable {
+    method public void run();
   }
 
   public class Runtime {
-    method public void addShutdownHook(java.lang.Thread);
+    method public void addShutdownHook(Thread);
     method public int availableProcessors();
-    method public java.lang.Process exec(java.lang.String) throws java.io.IOException;
-    method public java.lang.Process exec(java.lang.String, java.lang.String[]) throws java.io.IOException;
-    method public java.lang.Process exec(java.lang.String, java.lang.String[], java.io.File) throws java.io.IOException;
-    method public java.lang.Process exec(java.lang.String[]) throws java.io.IOException;
-    method public java.lang.Process exec(java.lang.String[], java.lang.String[]) throws java.io.IOException;
-    method public java.lang.Process exec(java.lang.String[], java.lang.String[], java.io.File) throws java.io.IOException;
+    method public Process exec(String) throws java.io.IOException;
+    method public Process exec(String, String[]) throws java.io.IOException;
+    method public Process exec(String, String[], java.io.File) throws java.io.IOException;
+    method public Process exec(String[]) throws java.io.IOException;
+    method public Process exec(String[], String[]) throws java.io.IOException;
+    method public Process exec(String[], String[], java.io.File) throws java.io.IOException;
     method public void exit(int);
     method public long freeMemory();
     method public void gc();
-    method public deprecated java.io.InputStream getLocalizedInputStream(java.io.InputStream);
-    method public deprecated java.io.OutputStream getLocalizedOutputStream(java.io.OutputStream);
-    method public static java.lang.Runtime getRuntime();
+    method @Deprecated public java.io.InputStream getLocalizedInputStream(java.io.InputStream);
+    method @Deprecated public java.io.OutputStream getLocalizedOutputStream(java.io.OutputStream);
+    method public static Runtime getRuntime();
     method public void halt(int);
-    method public void load(java.lang.String);
-    method public void loadLibrary(java.lang.String);
+    method public void load(String);
+    method public void loadLibrary(String);
     method public long maxMemory();
-    method public boolean removeShutdownHook(java.lang.Thread);
+    method public boolean removeShutdownHook(Thread);
     method public void runFinalization();
-    method public static deprecated void runFinalizersOnExit(boolean);
+    method @Deprecated public static void runFinalizersOnExit(boolean);
     method public long totalMemory();
     method public void traceInstructions(boolean);
     method public void traceMethodCalls(boolean);
@@ -59761,111 +60163,111 @@
 
   public class RuntimeException extends java.lang.Exception {
     ctor public RuntimeException();
-    ctor public RuntimeException(java.lang.String);
-    ctor public RuntimeException(java.lang.String, java.lang.Throwable);
-    ctor public RuntimeException(java.lang.Throwable);
-    ctor protected RuntimeException(java.lang.String, java.lang.Throwable, boolean, boolean);
+    ctor public RuntimeException(String);
+    ctor public RuntimeException(String, Throwable);
+    ctor public RuntimeException(Throwable);
+    ctor protected RuntimeException(String, Throwable, boolean, boolean);
   }
 
   public final class RuntimePermission extends java.security.BasicPermission {
-    ctor public RuntimePermission(java.lang.String);
-    ctor public RuntimePermission(java.lang.String, java.lang.String);
+    ctor public RuntimePermission(String);
+    ctor public RuntimePermission(String, String);
   }
 
-  public abstract class SafeVarargs implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.METHOD}) public @interface SafeVarargs {
   }
 
   public class SecurityException extends java.lang.RuntimeException {
     ctor public SecurityException();
-    ctor public SecurityException(java.lang.String);
-    ctor public SecurityException(java.lang.String, java.lang.Throwable);
-    ctor public SecurityException(java.lang.Throwable);
+    ctor public SecurityException(String);
+    ctor public SecurityException(String, Throwable);
+    ctor public SecurityException(Throwable);
   }
 
   public class SecurityManager {
     ctor public SecurityManager();
-    method public void checkAccept(java.lang.String, int);
-    method public void checkAccess(java.lang.Thread);
-    method public void checkAccess(java.lang.ThreadGroup);
+    method public void checkAccept(String, int);
+    method public void checkAccess(Thread);
+    method public void checkAccess(ThreadGroup);
     method public void checkAwtEventQueueAccess();
-    method public void checkConnect(java.lang.String, int);
-    method public void checkConnect(java.lang.String, int, java.lang.Object);
+    method public void checkConnect(String, int);
+    method public void checkConnect(String, int, Object);
     method public void checkCreateClassLoader();
-    method public void checkDelete(java.lang.String);
-    method public void checkExec(java.lang.String);
+    method public void checkDelete(String);
+    method public void checkExec(String);
     method public void checkExit(int);
-    method public void checkLink(java.lang.String);
+    method public void checkLink(String);
     method public void checkListen(int);
-    method public void checkMemberAccess(java.lang.Class<?>, int);
+    method public void checkMemberAccess(Class<?>, int);
     method public void checkMulticast(java.net.InetAddress);
-    method public deprecated void checkMulticast(java.net.InetAddress, byte);
-    method public void checkPackageAccess(java.lang.String);
-    method public void checkPackageDefinition(java.lang.String);
+    method @Deprecated public void checkMulticast(java.net.InetAddress, byte);
+    method public void checkPackageAccess(String);
+    method public void checkPackageDefinition(String);
     method public void checkPermission(java.security.Permission);
-    method public void checkPermission(java.security.Permission, java.lang.Object);
+    method public void checkPermission(java.security.Permission, Object);
     method public void checkPrintJobAccess();
     method public void checkPropertiesAccess();
-    method public void checkPropertyAccess(java.lang.String);
+    method public void checkPropertyAccess(String);
     method public void checkRead(java.io.FileDescriptor);
-    method public void checkRead(java.lang.String);
-    method public void checkRead(java.lang.String, java.lang.Object);
-    method public void checkSecurityAccess(java.lang.String);
+    method public void checkRead(String);
+    method public void checkRead(String, Object);
+    method public void checkSecurityAccess(String);
     method public void checkSetFactory();
     method public void checkSystemClipboardAccess();
-    method public boolean checkTopLevelWindow(java.lang.Object);
+    method public boolean checkTopLevelWindow(Object);
     method public void checkWrite(java.io.FileDescriptor);
-    method public void checkWrite(java.lang.String);
-    method protected deprecated int classDepth(java.lang.String);
-    method protected deprecated int classLoaderDepth();
-    method protected deprecated java.lang.ClassLoader currentClassLoader();
-    method protected deprecated java.lang.Class<?> currentLoadedClass();
-    method protected java.lang.Class[] getClassContext();
-    method public deprecated boolean getInCheck();
-    method public java.lang.Object getSecurityContext();
-    method public java.lang.ThreadGroup getThreadGroup();
-    method protected deprecated boolean inClass(java.lang.String);
-    method protected deprecated boolean inClassLoader();
-    field protected deprecated boolean inCheck;
+    method public void checkWrite(String);
+    method @Deprecated protected int classDepth(String);
+    method @Deprecated protected int classLoaderDepth();
+    method @Deprecated protected ClassLoader currentClassLoader();
+    method @Deprecated protected Class<?> currentLoadedClass();
+    method protected Class[] getClassContext();
+    method @Deprecated public boolean getInCheck();
+    method public Object getSecurityContext();
+    method public ThreadGroup getThreadGroup();
+    method @Deprecated protected boolean inClass(String);
+    method @Deprecated protected boolean inClassLoader();
+    field @Deprecated protected boolean inCheck;
   }
 
-  public final class Short extends java.lang.Number implements java.lang.Comparable {
+  public final class Short extends java.lang.Number implements java.lang.Comparable<java.lang.Short> {
     ctor public Short(short);
-    ctor public Short(java.lang.String) throws java.lang.NumberFormatException;
+    ctor public Short(String) throws java.lang.NumberFormatException;
     method public static int compare(short, short);
-    method public int compareTo(java.lang.Short);
-    method public static java.lang.Short decode(java.lang.String) throws java.lang.NumberFormatException;
+    method public int compareTo(Short);
+    method public static Short decode(String) throws java.lang.NumberFormatException;
     method public double doubleValue();
     method public float floatValue();
     method public static int hashCode(short);
     method public int intValue();
     method public long longValue();
-    method public static short parseShort(java.lang.String, int) throws java.lang.NumberFormatException;
-    method public static short parseShort(java.lang.String) throws java.lang.NumberFormatException;
+    method public static short parseShort(String, int) throws java.lang.NumberFormatException;
+    method public static short parseShort(String) throws java.lang.NumberFormatException;
     method public static short reverseBytes(short);
-    method public static java.lang.String toString(short);
+    method public static String toString(short);
     method public static int toUnsignedInt(short);
     method public static long toUnsignedLong(short);
-    method public static java.lang.Short valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
-    method public static java.lang.Short valueOf(java.lang.String) throws java.lang.NumberFormatException;
-    method public static java.lang.Short valueOf(short);
+    method public static Short valueOf(String, int) throws java.lang.NumberFormatException;
+    method public static Short valueOf(String) throws java.lang.NumberFormatException;
+    method public static Short valueOf(short);
     field public static final int BYTES = 2; // 0x2
     field public static final short MAX_VALUE = 32767; // 0x7fff
     field public static final short MIN_VALUE = -32768; // 0xffff8000
     field public static final int SIZE = 16; // 0x10
-    field public static final java.lang.Class<java.lang.Short> TYPE;
+    field public static final Class<java.lang.Short> TYPE;
   }
 
   public class StackOverflowError extends java.lang.VirtualMachineError {
     ctor public StackOverflowError();
-    ctor public StackOverflowError(java.lang.String);
+    ctor public StackOverflowError(String);
   }
 
   public final class StackTraceElement implements java.io.Serializable {
-    ctor public StackTraceElement(java.lang.String, java.lang.String, java.lang.String, int);
-    method public java.lang.String getClassName();
-    method public java.lang.String getFileName();
+    ctor public StackTraceElement(String, String, String, int);
+    method public String getClassName();
+    method public String getFileName();
     method public int getLineNumber();
-    method public java.lang.String getMethodName();
+    method public String getMethodName();
     method public boolean isNativeMethod();
   }
 
@@ -59941,224 +60343,239 @@
     field public static final double PI = 3.141592653589793;
   }
 
-  public final class String implements java.lang.CharSequence java.lang.Comparable java.io.Serializable {
+  public final class String implements java.lang.CharSequence java.lang.Comparable<java.lang.String> java.io.Serializable {
     ctor public String();
-    ctor public String(java.lang.String);
+    ctor public String(@NonNull String);
     ctor public String(char[]);
     ctor public String(char[], int, int);
     ctor public String(int[], int, int);
-    ctor public deprecated String(byte[], int, int, int);
-    ctor public deprecated String(byte[], int);
-    ctor public String(byte[], int, int, java.lang.String) throws java.io.UnsupportedEncodingException;
-    ctor public String(byte[], int, int, java.nio.charset.Charset);
-    ctor public String(byte[], java.lang.String) throws java.io.UnsupportedEncodingException;
-    ctor public String(byte[], java.nio.charset.Charset);
+    ctor @Deprecated public String(byte[], int, int, int);
+    ctor @Deprecated public String(byte[], int);
+    ctor public String(byte[], int, int, @NonNull String) throws java.io.UnsupportedEncodingException;
+    ctor public String(byte[], int, int, @NonNull java.nio.charset.Charset);
+    ctor public String(byte[], @NonNull String) throws java.io.UnsupportedEncodingException;
+    ctor public String(byte[], @NonNull java.nio.charset.Charset);
     ctor public String(byte[], int, int);
     ctor public String(byte[]);
-    ctor public String(java.lang.StringBuffer);
-    ctor public String(java.lang.StringBuilder);
+    ctor public String(@NonNull StringBuffer);
+    ctor public String(@NonNull StringBuilder);
     method public char charAt(int);
     method public int codePointAt(int);
     method public int codePointBefore(int);
     method public int codePointCount(int, int);
-    method public int compareTo(java.lang.String);
-    method public int compareToIgnoreCase(java.lang.String);
-    method public java.lang.String concat(java.lang.String);
-    method public boolean contains(java.lang.CharSequence);
-    method public boolean contentEquals(java.lang.StringBuffer);
-    method public boolean contentEquals(java.lang.CharSequence);
-    method public static java.lang.String copyValueOf(char[], int, int);
-    method public static java.lang.String copyValueOf(char[]);
-    method public boolean endsWith(java.lang.String);
-    method public boolean equalsIgnoreCase(java.lang.String);
-    method public static java.lang.String format(java.lang.String, java.lang.Object...);
-    method public static java.lang.String format(java.util.Locale, java.lang.String, java.lang.Object...);
-    method public deprecated void getBytes(int, int, byte[], int);
-    method public byte[] getBytes(java.lang.String) throws java.io.UnsupportedEncodingException;
-    method public byte[] getBytes(java.nio.charset.Charset);
+    method public int compareTo(@NonNull String);
+    method public int compareToIgnoreCase(@NonNull String);
+    method @NonNull public String concat(@NonNull String);
+    method public boolean contains(@NonNull CharSequence);
+    method public boolean contentEquals(@NonNull StringBuffer);
+    method public boolean contentEquals(@NonNull CharSequence);
+    method @NonNull public static String copyValueOf(char[], int, int);
+    method @NonNull public static String copyValueOf(char[]);
+    method public boolean endsWith(@NonNull String);
+    method public boolean equalsIgnoreCase(@Nullable String);
+    method @NonNull public static String format(@NonNull String, java.lang.Object...);
+    method @NonNull public static String format(@NonNull java.util.Locale, @NonNull String, java.lang.Object...);
+    method @Deprecated public void getBytes(int, int, byte[], int);
+    method public byte[] getBytes(@NonNull String) throws java.io.UnsupportedEncodingException;
+    method public byte[] getBytes(@NonNull java.nio.charset.Charset);
     method public byte[] getBytes();
     method public void getChars(int, int, char[], int);
     method public int indexOf(int);
     method public int indexOf(int, int);
-    method public int indexOf(java.lang.String);
-    method public int indexOf(java.lang.String, int);
-    method public java.lang.String intern();
+    method public int indexOf(@NonNull String);
+    method public int indexOf(@NonNull String, int);
+    method @NonNull public String intern();
     method public boolean isEmpty();
-    method public static java.lang.String join(java.lang.CharSequence, java.lang.CharSequence...);
-    method public static java.lang.String join(java.lang.CharSequence, java.lang.Iterable<? extends java.lang.CharSequence>);
+    method @NonNull public static String join(@NonNull CharSequence, java.lang.CharSequence...);
+    method @NonNull public static String join(@NonNull CharSequence, @NonNull Iterable<? extends java.lang.CharSequence>);
     method public int lastIndexOf(int);
     method public int lastIndexOf(int, int);
-    method public int lastIndexOf(java.lang.String);
-    method public int lastIndexOf(java.lang.String, int);
+    method public int lastIndexOf(@NonNull String);
+    method public int lastIndexOf(@NonNull String, int);
     method public int length();
-    method public boolean matches(java.lang.String);
+    method public boolean matches(@NonNull String);
     method public int offsetByCodePoints(int, int);
-    method public boolean regionMatches(int, java.lang.String, int, int);
-    method public boolean regionMatches(boolean, int, java.lang.String, int, int);
-    method public java.lang.String replace(char, char);
-    method public java.lang.String replace(java.lang.CharSequence, java.lang.CharSequence);
-    method public java.lang.String replaceAll(java.lang.String, java.lang.String);
-    method public java.lang.String replaceFirst(java.lang.String, java.lang.String);
-    method public java.lang.String[] split(java.lang.String, int);
-    method public java.lang.String[] split(java.lang.String);
-    method public boolean startsWith(java.lang.String, int);
-    method public boolean startsWith(java.lang.String);
-    method public java.lang.CharSequence subSequence(int, int);
-    method public java.lang.String substring(int);
-    method public java.lang.String substring(int, int);
+    method public boolean regionMatches(int, @NonNull String, int, int);
+    method public boolean regionMatches(boolean, int, @NonNull String, int, int);
+    method @NonNull public String replace(char, char);
+    method @NonNull public String replace(@NonNull CharSequence, @NonNull CharSequence);
+    method @NonNull public String replaceAll(@NonNull String, @NonNull String);
+    method @NonNull public String replaceFirst(@NonNull String, @NonNull String);
+    method public String[] split(@NonNull String, int);
+    method public String[] split(@NonNull String);
+    method public boolean startsWith(@NonNull String, int);
+    method public boolean startsWith(@NonNull String);
+    method @NonNull public CharSequence subSequence(int, int);
+    method @NonNull public String substring(int);
+    method @NonNull public String substring(int, int);
     method public char[] toCharArray();
-    method public java.lang.String toLowerCase(java.util.Locale);
-    method public java.lang.String toLowerCase();
-    method public java.lang.String toUpperCase(java.util.Locale);
-    method public java.lang.String toUpperCase();
-    method public java.lang.String trim();
-    method public static java.lang.String valueOf(java.lang.Object);
-    method public static java.lang.String valueOf(char[]);
-    method public static java.lang.String valueOf(char[], int, int);
-    method public static java.lang.String valueOf(boolean);
-    method public static java.lang.String valueOf(char);
-    method public static java.lang.String valueOf(int);
-    method public static java.lang.String valueOf(long);
-    method public static java.lang.String valueOf(float);
-    method public static java.lang.String valueOf(double);
+    method @NonNull public String toLowerCase(@NonNull java.util.Locale);
+    method @NonNull public String toLowerCase();
+    method @NonNull public String toUpperCase(@NonNull java.util.Locale);
+    method @NonNull public String toUpperCase();
+    method @NonNull public String trim();
+    method @NonNull public static String valueOf(@Nullable Object);
+    method @NonNull public static String valueOf(char[]);
+    method @NonNull public static String valueOf(char[], int, int);
+    method @NonNull public static String valueOf(boolean);
+    method @NonNull public static String valueOf(char);
+    method @NonNull public static String valueOf(int);
+    method @NonNull public static String valueOf(long);
+    method @NonNull public static String valueOf(float);
+    method @NonNull public static String valueOf(double);
     field public static final java.util.Comparator<java.lang.String> CASE_INSENSITIVE_ORDER;
   }
 
   public final class StringBuffer implements java.lang.Appendable java.lang.CharSequence java.io.Serializable {
     ctor public StringBuffer();
     ctor public StringBuffer(int);
-    ctor public StringBuffer(java.lang.String);
-    ctor public StringBuffer(java.lang.CharSequence);
-    method public synchronized java.lang.StringBuffer append(java.lang.Object);
-    method public synchronized java.lang.StringBuffer append(java.lang.String);
-    method public synchronized java.lang.StringBuffer append(java.lang.StringBuffer);
-    method public synchronized java.lang.StringBuffer append(java.lang.CharSequence);
-    method public synchronized java.lang.StringBuffer append(java.lang.CharSequence, int, int);
-    method public synchronized java.lang.StringBuffer append(char[]);
-    method public synchronized java.lang.StringBuffer append(char[], int, int);
-    method public synchronized java.lang.StringBuffer append(boolean);
-    method public synchronized java.lang.StringBuffer append(char);
-    method public synchronized java.lang.StringBuffer append(int);
-    method public synchronized java.lang.StringBuffer append(long);
-    method public synchronized java.lang.StringBuffer append(float);
-    method public synchronized java.lang.StringBuffer append(double);
-    method public synchronized java.lang.StringBuffer appendCodePoint(int);
-    method public synchronized int capacity();
-    method public synchronized char charAt(int);
-    method public synchronized int codePointAt(int);
-    method public synchronized int codePointBefore(int);
-    method public synchronized int codePointCount(int, int);
-    method public synchronized java.lang.StringBuffer delete(int, int);
-    method public synchronized java.lang.StringBuffer deleteCharAt(int);
-    method public synchronized void ensureCapacity(int);
-    method public synchronized void getChars(int, int, char[], int);
-    method public int indexOf(java.lang.String);
-    method public synchronized int indexOf(java.lang.String, int);
-    method public synchronized java.lang.StringBuffer insert(int, char[], int, int);
-    method public synchronized java.lang.StringBuffer insert(int, java.lang.Object);
-    method public synchronized java.lang.StringBuffer insert(int, java.lang.String);
-    method public synchronized java.lang.StringBuffer insert(int, char[]);
-    method public java.lang.StringBuffer insert(int, java.lang.CharSequence);
-    method public synchronized java.lang.StringBuffer insert(int, java.lang.CharSequence, int, int);
-    method public java.lang.StringBuffer insert(int, boolean);
-    method public synchronized java.lang.StringBuffer insert(int, char);
-    method public java.lang.StringBuffer insert(int, int);
-    method public java.lang.StringBuffer insert(int, long);
-    method public java.lang.StringBuffer insert(int, float);
-    method public java.lang.StringBuffer insert(int, double);
-    method public int lastIndexOf(java.lang.String);
-    method public synchronized int lastIndexOf(java.lang.String, int);
-    method public synchronized int length();
-    method public synchronized int offsetByCodePoints(int, int);
-    method public synchronized java.lang.StringBuffer replace(int, int, java.lang.String);
-    method public synchronized java.lang.StringBuffer reverse();
-    method public synchronized void setCharAt(int, char);
-    method public synchronized void setLength(int);
-    method public synchronized java.lang.CharSequence subSequence(int, int);
-    method public synchronized java.lang.String substring(int);
-    method public synchronized java.lang.String substring(int, int);
-    method public synchronized java.lang.String toString();
-    method public synchronized void trimToSize();
+    ctor public StringBuffer(@NonNull String);
+    ctor public StringBuffer(@NonNull CharSequence);
+    method @NonNull public StringBuffer append(@Nullable Object);
+    method @NonNull public StringBuffer append(@Nullable String);
+    method @NonNull public StringBuffer append(@Nullable StringBuffer);
+    method @NonNull public StringBuffer append(@Nullable CharSequence);
+    method @NonNull public StringBuffer append(@Nullable CharSequence, int, int);
+    method @NonNull public StringBuffer append(char[]);
+    method @NonNull public StringBuffer append(char[], int, int);
+    method @NonNull public StringBuffer append(boolean);
+    method @NonNull public StringBuffer append(char);
+    method @NonNull public StringBuffer append(int);
+    method @NonNull public StringBuffer append(long);
+    method @NonNull public StringBuffer append(float);
+    method @NonNull public StringBuffer append(double);
+    method @NonNull public StringBuffer appendCodePoint(int);
+    method public int capacity();
+    method public char charAt(int);
+    method public int codePointAt(int);
+    method public int codePointBefore(int);
+    method public int codePointCount(int, int);
+    method @NonNull public StringBuffer delete(int, int);
+    method @NonNull public StringBuffer deleteCharAt(int);
+    method public void ensureCapacity(int);
+    method public void getChars(int, int, char[], int);
+    method public int indexOf(@NonNull String);
+    method public int indexOf(@NonNull String, int);
+    method @NonNull public StringBuffer insert(int, char[], int, int);
+    method @NonNull public StringBuffer insert(int, @Nullable Object);
+    method @NonNull public StringBuffer insert(int, @Nullable String);
+    method @NonNull public StringBuffer insert(int, char[]);
+    method @NonNull public StringBuffer insert(int, @Nullable CharSequence);
+    method @NonNull public StringBuffer insert(int, @Nullable CharSequence, int, int);
+    method @NonNull public StringBuffer insert(int, boolean);
+    method @NonNull public StringBuffer insert(int, char);
+    method @NonNull public StringBuffer insert(int, int);
+    method @NonNull public StringBuffer insert(int, long);
+    method @NonNull public StringBuffer insert(int, float);
+    method @NonNull public StringBuffer insert(int, double);
+    method public int lastIndexOf(@NonNull String);
+    method public int lastIndexOf(@NonNull String, int);
+    method public int length();
+    method public int offsetByCodePoints(int, int);
+    method @NonNull public StringBuffer replace(int, int, @NonNull String);
+    method @NonNull public StringBuffer reverse();
+    method public void setCharAt(int, char);
+    method public void setLength(int);
+    method @NonNull public CharSequence subSequence(int, int);
+    method @NonNull public String substring(int);
+    method @NonNull public String substring(int, int);
+    method public void trimToSize();
   }
 
   public final class StringBuilder implements java.lang.Appendable java.lang.CharSequence java.io.Serializable {
     ctor public StringBuilder();
     ctor public StringBuilder(int);
-    ctor public StringBuilder(java.lang.String);
-    ctor public StringBuilder(java.lang.CharSequence);
-    method public java.lang.StringBuilder append(java.lang.Object);
-    method public java.lang.StringBuilder append(java.lang.String);
-    method public java.lang.StringBuilder append(java.lang.StringBuffer);
-    method public java.lang.StringBuilder append(java.lang.CharSequence);
-    method public java.lang.StringBuilder append(java.lang.CharSequence, int, int);
-    method public java.lang.StringBuilder append(char[]);
-    method public java.lang.StringBuilder append(char[], int, int);
-    method public java.lang.StringBuilder append(boolean);
-    method public java.lang.StringBuilder append(char);
-    method public java.lang.StringBuilder append(int);
-    method public java.lang.StringBuilder append(long);
-    method public java.lang.StringBuilder append(float);
-    method public java.lang.StringBuilder append(double);
-    method public java.lang.StringBuilder appendCodePoint(int);
-    method public java.lang.StringBuilder delete(int, int);
-    method public java.lang.StringBuilder deleteCharAt(int);
-    method public int indexOf(java.lang.String);
-    method public int indexOf(java.lang.String, int);
-    method public java.lang.StringBuilder insert(int, char[], int, int);
-    method public java.lang.StringBuilder insert(int, java.lang.Object);
-    method public java.lang.StringBuilder insert(int, java.lang.String);
-    method public java.lang.StringBuilder insert(int, char[]);
-    method public java.lang.StringBuilder insert(int, java.lang.CharSequence);
-    method public java.lang.StringBuilder insert(int, java.lang.CharSequence, int, int);
-    method public java.lang.StringBuilder insert(int, boolean);
-    method public java.lang.StringBuilder insert(int, char);
-    method public java.lang.StringBuilder insert(int, int);
-    method public java.lang.StringBuilder insert(int, long);
-    method public java.lang.StringBuilder insert(int, float);
-    method public java.lang.StringBuilder insert(int, double);
-    method public int lastIndexOf(java.lang.String);
-    method public int lastIndexOf(java.lang.String, int);
-    method public java.lang.StringBuilder replace(int, int, java.lang.String);
-    method public java.lang.StringBuilder reverse();
+    ctor public StringBuilder(@NonNull String);
+    ctor public StringBuilder(@NonNull CharSequence);
+    method @NonNull public StringBuilder append(@Nullable Object);
+    method @NonNull public StringBuilder append(@Nullable String);
+    method @NonNull public StringBuilder append(@Nullable StringBuffer);
+    method @NonNull public StringBuilder append(@Nullable CharSequence);
+    method @NonNull public StringBuilder append(@Nullable CharSequence, int, int);
+    method @NonNull public StringBuilder append(char[]);
+    method @NonNull public StringBuilder append(char[], int, int);
+    method @NonNull public StringBuilder append(boolean);
+    method @NonNull public StringBuilder append(char);
+    method @NonNull public StringBuilder append(int);
+    method @NonNull public StringBuilder append(long);
+    method @NonNull public StringBuilder append(float);
+    method @NonNull public StringBuilder append(double);
+    method @NonNull public StringBuilder appendCodePoint(int);
+    method public int capacity();
+    method public char charAt(int);
+    method public int codePointAt(int);
+    method public int codePointBefore(int);
+    method public int codePointCount(int, int);
+    method @NonNull public StringBuilder delete(int, int);
+    method @NonNull public StringBuilder deleteCharAt(int);
+    method public void ensureCapacity(int);
+    method public void getChars(int, int, char[], int);
+    method public int indexOf(@NonNull String);
+    method public int indexOf(@NonNull String, int);
+    method @NonNull public StringBuilder insert(int, char[], int, int);
+    method @NonNull public StringBuilder insert(int, @Nullable Object);
+    method @NonNull public StringBuilder insert(int, @Nullable String);
+    method @NonNull public StringBuilder insert(int, char[]);
+    method @NonNull public StringBuilder insert(int, @Nullable CharSequence);
+    method @NonNull public StringBuilder insert(int, @Nullable CharSequence, int, int);
+    method @NonNull public StringBuilder insert(int, boolean);
+    method @NonNull public StringBuilder insert(int, char);
+    method @NonNull public StringBuilder insert(int, int);
+    method @NonNull public StringBuilder insert(int, long);
+    method @NonNull public StringBuilder insert(int, float);
+    method @NonNull public StringBuilder insert(int, double);
+    method public int lastIndexOf(@NonNull String);
+    method public int lastIndexOf(@NonNull String, int);
+    method public int length();
+    method public int offsetByCodePoints(int, int);
+    method @NonNull public StringBuilder replace(int, int, @NonNull String);
+    method @NonNull public StringBuilder reverse();
+    method public void setCharAt(int, char);
+    method public void setLength(int);
+    method public CharSequence subSequence(int, int);
+    method public String substring(int);
+    method public String substring(int, int);
+    method public void trimToSize();
   }
 
   public class StringIndexOutOfBoundsException extends java.lang.IndexOutOfBoundsException {
     ctor public StringIndexOutOfBoundsException();
-    ctor public StringIndexOutOfBoundsException(java.lang.String);
+    ctor public StringIndexOutOfBoundsException(String);
     ctor public StringIndexOutOfBoundsException(int);
   }
 
-  public abstract class SuppressWarnings implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public @interface SuppressWarnings {
+    method public abstract String[] value();
   }
 
   public final class System {
-    method public static void arraycopy(java.lang.Object, int, java.lang.Object, int, int);
-    method public static java.lang.String clearProperty(java.lang.String);
-    method public static java.io.Console console();
+    method public static void arraycopy(@NonNull Object, int, @NonNull Object, int, int);
+    method @Nullable public static String clearProperty(@NonNull String);
+    method @Nullable public static java.io.Console console();
     method public static long currentTimeMillis();
     method public static void exit(int);
     method public static void gc();
-    method public static java.util.Properties getProperties();
-    method public static java.lang.String getProperty(java.lang.String);
-    method public static java.lang.String getProperty(java.lang.String, java.lang.String);
-    method public static java.lang.SecurityManager getSecurityManager();
-    method public static java.lang.String getenv(java.lang.String);
-    method public static java.util.Map<java.lang.String, java.lang.String> getenv();
-    method public static int identityHashCode(java.lang.Object);
-    method public static java.nio.channels.Channel inheritedChannel() throws java.io.IOException;
-    method public static java.lang.String lineSeparator();
-    method public static void load(java.lang.String);
-    method public static void loadLibrary(java.lang.String);
-    method public static java.lang.String mapLibraryName(java.lang.String);
+    method @NonNull public static java.util.Properties getProperties();
+    method @Nullable public static String getProperty(@NonNull String);
+    method @Nullable public static String getProperty(@NonNull String, @Nullable String);
+    method @Nullable public static SecurityManager getSecurityManager();
+    method @Nullable public static String getenv(@NonNull String);
+    method @NonNull public static java.util.Map<java.lang.String,java.lang.String> getenv();
+    method public static int identityHashCode(@Nullable Object);
+    method @Nullable public static java.nio.channels.Channel inheritedChannel() throws java.io.IOException;
+    method @NonNull public static String lineSeparator();
+    method public static void load(@NonNull String);
+    method public static void loadLibrary(@NonNull String);
+    method @NonNull public static String mapLibraryName(@NonNull String);
     method public static long nanoTime();
     method public static void runFinalization();
-    method public static deprecated void runFinalizersOnExit(boolean);
-    method public static void setErr(java.io.PrintStream);
-    method public static void setIn(java.io.InputStream);
-    method public static void setOut(java.io.PrintStream);
-    method public static void setProperties(java.util.Properties);
-    method public static java.lang.String setProperty(java.lang.String, java.lang.String);
-    method public static void setSecurityManager(java.lang.SecurityManager);
+    method @Deprecated public static void runFinalizersOnExit(boolean);
+    method public static void setErr(@Nullable java.io.PrintStream);
+    method public static void setIn(@Nullable java.io.InputStream);
+    method public static void setOut(@Nullable java.io.PrintStream);
+    method public static void setProperties(@Nullable java.util.Properties);
+    method @Nullable public static String setProperty(@NonNull String, @Nullable String);
+    method public static void setSecurityManager(@Nullable SecurityManager);
     field public static final java.io.PrintStream err;
     field public static final java.io.InputStream in;
     field public static final java.io.PrintStream out;
@@ -60166,31 +60583,31 @@
 
   public class Thread implements java.lang.Runnable {
     ctor public Thread();
-    ctor public Thread(java.lang.Runnable);
-    ctor public Thread(java.lang.ThreadGroup, java.lang.Runnable);
-    ctor public Thread(java.lang.String);
-    ctor public Thread(java.lang.ThreadGroup, java.lang.String);
-    ctor public Thread(java.lang.Runnable, java.lang.String);
-    ctor public Thread(java.lang.ThreadGroup, java.lang.Runnable, java.lang.String);
-    ctor public Thread(java.lang.ThreadGroup, java.lang.Runnable, java.lang.String, long);
+    ctor public Thread(@Nullable Runnable);
+    ctor public Thread(@Nullable ThreadGroup, @Nullable Runnable);
+    ctor public Thread(@NonNull String);
+    ctor public Thread(@Nullable ThreadGroup, @NonNull String);
+    ctor public Thread(@Nullable Runnable, @NonNull String);
+    ctor public Thread(@Nullable ThreadGroup, @Nullable Runnable, @NonNull String);
+    ctor public Thread(@Nullable ThreadGroup, @Nullable Runnable, @NonNull String, long);
     method public static int activeCount();
     method public final void checkAccess();
-    method public deprecated int countStackFrames();
-    method public static java.lang.Thread currentThread();
-    method public deprecated void destroy();
+    method @Deprecated public int countStackFrames();
+    method @NonNull public static Thread currentThread();
+    method @Deprecated public void destroy();
     method public static void dumpStack();
-    method public static int enumerate(java.lang.Thread[]);
-    method public static java.util.Map<java.lang.Thread, java.lang.StackTraceElement[]> getAllStackTraces();
-    method public java.lang.ClassLoader getContextClassLoader();
-    method public static java.lang.Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler();
+    method public static int enumerate(Thread[]);
+    method @NonNull public static java.util.Map<java.lang.Thread,java.lang.StackTraceElement[]> getAllStackTraces();
+    method @Nullable public ClassLoader getContextClassLoader();
+    method @Nullable public static java.lang.Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler();
     method public long getId();
-    method public final java.lang.String getName();
+    method @NonNull public final String getName();
     method public final int getPriority();
-    method public java.lang.StackTraceElement[] getStackTrace();
-    method public java.lang.Thread.State getState();
-    method public final java.lang.ThreadGroup getThreadGroup();
-    method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
-    method public static boolean holdsLock(java.lang.Object);
+    method public StackTraceElement[] getStackTrace();
+    method @NonNull public java.lang.Thread.State getState();
+    method @Nullable public final ThreadGroup getThreadGroup();
+    method @Nullable public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
+    method public static boolean holdsLock(@NonNull Object);
     method public void interrupt();
     method public static boolean interrupted();
     method public final boolean isAlive();
@@ -60199,29 +60616,27 @@
     method public final void join(long) throws java.lang.InterruptedException;
     method public final void join(long, int) throws java.lang.InterruptedException;
     method public final void join() throws java.lang.InterruptedException;
-    method public final deprecated void resume();
+    method @Deprecated public final void resume();
     method public void run();
-    method public void setContextClassLoader(java.lang.ClassLoader);
+    method public void setContextClassLoader(@Nullable ClassLoader);
     method public final void setDaemon(boolean);
-    method public static void setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler);
-    method public final synchronized void setName(java.lang.String);
+    method public static void setDefaultUncaughtExceptionHandler(@Nullable java.lang.Thread.UncaughtExceptionHandler);
+    method public final void setName(@NonNull String);
     method public final void setPriority(int);
-    method public void setUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler);
+    method public void setUncaughtExceptionHandler(@Nullable java.lang.Thread.UncaughtExceptionHandler);
     method public static void sleep(long) throws java.lang.InterruptedException;
     method public static void sleep(long, int) throws java.lang.InterruptedException;
-    method public synchronized void start();
-    method public final deprecated void stop();
-    method public final deprecated synchronized void stop(java.lang.Throwable);
-    method public final deprecated void suspend();
+    method public void start();
+    method @Deprecated public final void stop();
+    method @Deprecated public final void stop(@Nullable Throwable);
+    method @Deprecated public final void suspend();
     method public static void yield();
     field public static final int MAX_PRIORITY = 10; // 0xa
     field public static final int MIN_PRIORITY = 1; // 0x1
     field public static final int NORM_PRIORITY = 5; // 0x5
   }
 
-  public static final class Thread.State extends java.lang.Enum {
-    method public static java.lang.Thread.State valueOf(java.lang.String);
-    method public static final java.lang.Thread.State[] values();
+  public enum Thread.State {
     enum_constant public static final java.lang.Thread.State BLOCKED;
     enum_constant public static final java.lang.Thread.State NEW;
     enum_constant public static final java.lang.Thread.State RUNNABLE;
@@ -60230,8 +60645,8 @@
     enum_constant public static final java.lang.Thread.State WAITING;
   }
 
-  public static abstract interface Thread.UncaughtExceptionHandler {
-    method public abstract void uncaughtException(java.lang.Thread, java.lang.Throwable);
+  @java.lang.FunctionalInterface public static interface Thread.UncaughtExceptionHandler {
+    method public void uncaughtException(@NonNull Thread, @NonNull Throwable);
   }
 
   public class ThreadDeath extends java.lang.Error {
@@ -60239,134 +60654,132 @@
   }
 
   public class ThreadGroup implements java.lang.Thread.UncaughtExceptionHandler {
-    ctor public ThreadGroup(java.lang.String);
-    ctor public ThreadGroup(java.lang.ThreadGroup, java.lang.String);
+    ctor public ThreadGroup(String);
+    ctor public ThreadGroup(ThreadGroup, String);
     method public int activeCount();
     method public int activeGroupCount();
-    method public deprecated boolean allowThreadSuspension(boolean);
+    method @Deprecated public boolean allowThreadSuspension(boolean);
     method public final void checkAccess();
     method public final void destroy();
-    method public int enumerate(java.lang.Thread[]);
-    method public int enumerate(java.lang.Thread[], boolean);
-    method public int enumerate(java.lang.ThreadGroup[]);
-    method public int enumerate(java.lang.ThreadGroup[], boolean);
+    method public int enumerate(Thread[]);
+    method public int enumerate(Thread[], boolean);
+    method public int enumerate(ThreadGroup[]);
+    method public int enumerate(ThreadGroup[], boolean);
     method public final int getMaxPriority();
-    method public final java.lang.String getName();
-    method public final java.lang.ThreadGroup getParent();
+    method public final String getName();
+    method public final ThreadGroup getParent();
     method public final void interrupt();
     method public final boolean isDaemon();
-    method public synchronized boolean isDestroyed();
+    method public boolean isDestroyed();
     method public void list();
-    method public final boolean parentOf(java.lang.ThreadGroup);
-    method public final deprecated void resume();
+    method public final boolean parentOf(ThreadGroup);
+    method @Deprecated public final void resume();
     method public final void setDaemon(boolean);
     method public final void setMaxPriority(int);
-    method public final deprecated void stop();
-    method public final deprecated void suspend();
-    method public void uncaughtException(java.lang.Thread, java.lang.Throwable);
+    method @Deprecated public final void stop();
+    method @Deprecated public final void suspend();
+    method public void uncaughtException(Thread, Throwable);
   }
 
   public class ThreadLocal<T> {
     ctor public ThreadLocal();
-    method public T get();
-    method protected T initialValue();
+    method @Nullable public T get();
+    method @Nullable protected T initialValue();
     method public void remove();
     method public void set(T);
-    method public static <S> java.lang.ThreadLocal<S> withInitial(java.util.function.Supplier<? extends S>);
+    method @NonNull public static <S> ThreadLocal<S> withInitial(@NonNull java.util.function.Supplier<? extends S>);
   }
 
   public class Throwable implements java.io.Serializable {
     ctor public Throwable();
-    ctor public Throwable(java.lang.String);
-    ctor public Throwable(java.lang.String, java.lang.Throwable);
-    ctor public Throwable(java.lang.Throwable);
-    ctor protected Throwable(java.lang.String, java.lang.Throwable, boolean, boolean);
-    method public final synchronized void addSuppressed(java.lang.Throwable);
-    method public synchronized java.lang.Throwable fillInStackTrace();
-    method public synchronized java.lang.Throwable getCause();
-    method public java.lang.String getLocalizedMessage();
-    method public java.lang.String getMessage();
-    method public java.lang.StackTraceElement[] getStackTrace();
-    method public final synchronized java.lang.Throwable[] getSuppressed();
-    method public synchronized java.lang.Throwable initCause(java.lang.Throwable);
+    ctor public Throwable(@Nullable String);
+    ctor public Throwable(@Nullable String, @Nullable Throwable);
+    ctor public Throwable(@Nullable Throwable);
+    ctor protected Throwable(@Nullable String, @Nullable Throwable, boolean, boolean);
+    method public final void addSuppressed(@NonNull Throwable);
+    method @NonNull public Throwable fillInStackTrace();
+    method @Nullable public Throwable getCause();
+    method @Nullable public String getLocalizedMessage();
+    method @Nullable public String getMessage();
+    method public StackTraceElement[] getStackTrace();
+    method public final Throwable[] getSuppressed();
+    method @NonNull public Throwable initCause(@Nullable Throwable);
     method public void printStackTrace();
-    method public void printStackTrace(java.io.PrintStream);
-    method public void printStackTrace(java.io.PrintWriter);
-    method public void setStackTrace(java.lang.StackTraceElement[]);
+    method public void printStackTrace(@NonNull java.io.PrintStream);
+    method public void printStackTrace(@NonNull java.io.PrintWriter);
+    method public void setStackTrace(StackTraceElement[]);
   }
 
   public class TypeNotPresentException extends java.lang.RuntimeException {
-    ctor public TypeNotPresentException(java.lang.String, java.lang.Throwable);
-    method public java.lang.String typeName();
+    ctor public TypeNotPresentException(String, Throwable);
+    method public String typeName();
   }
 
   public class UnknownError extends java.lang.VirtualMachineError {
     ctor public UnknownError();
-    ctor public UnknownError(java.lang.String);
+    ctor public UnknownError(String);
   }
 
   public class UnsatisfiedLinkError extends java.lang.LinkageError {
     ctor public UnsatisfiedLinkError();
-    ctor public UnsatisfiedLinkError(java.lang.String);
+    ctor public UnsatisfiedLinkError(String);
   }
 
   public class UnsupportedClassVersionError extends java.lang.ClassFormatError {
     ctor public UnsupportedClassVersionError();
-    ctor public UnsupportedClassVersionError(java.lang.String);
+    ctor public UnsupportedClassVersionError(String);
   }
 
   public class UnsupportedOperationException extends java.lang.RuntimeException {
     ctor public UnsupportedOperationException();
-    ctor public UnsupportedOperationException(java.lang.String);
-    ctor public UnsupportedOperationException(java.lang.String, java.lang.Throwable);
-    ctor public UnsupportedOperationException(java.lang.Throwable);
+    ctor public UnsupportedOperationException(String);
+    ctor public UnsupportedOperationException(String, Throwable);
+    ctor public UnsupportedOperationException(Throwable);
   }
 
   public class VerifyError extends java.lang.LinkageError {
     ctor public VerifyError();
-    ctor public VerifyError(java.lang.String);
+    ctor public VerifyError(String);
   }
 
   public abstract class VirtualMachineError extends java.lang.Error {
     ctor public VirtualMachineError();
-    ctor public VirtualMachineError(java.lang.String);
-    ctor public VirtualMachineError(java.lang.String, java.lang.Throwable);
-    ctor public VirtualMachineError(java.lang.Throwable);
+    ctor public VirtualMachineError(String);
+    ctor public VirtualMachineError(String, Throwable);
+    ctor public VirtualMachineError(Throwable);
   }
 
   public final class Void {
-    field public static final java.lang.Class<java.lang.Void> TYPE;
+    field public static final Class<java.lang.Void> TYPE;
   }
 
 }
 
 package java.lang.annotation {
 
-  public abstract interface Annotation {
-    method public abstract java.lang.Class<? extends java.lang.annotation.Annotation> annotationType();
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract int hashCode();
-    method public abstract java.lang.String toString();
+  public interface Annotation {
+    method public Class<? extends java.lang.annotation.Annotation> annotationType();
+    method public boolean equals(Object);
+    method public int hashCode();
+    method public String toString();
   }
 
   public class AnnotationFormatError extends java.lang.Error {
-    ctor public AnnotationFormatError(java.lang.String);
-    ctor public AnnotationFormatError(java.lang.String, java.lang.Throwable);
-    ctor public AnnotationFormatError(java.lang.Throwable);
+    ctor public AnnotationFormatError(String);
+    ctor public AnnotationFormatError(String, Throwable);
+    ctor public AnnotationFormatError(Throwable);
   }
 
   public class AnnotationTypeMismatchException extends java.lang.RuntimeException {
-    ctor public AnnotationTypeMismatchException(java.lang.reflect.Method, java.lang.String);
+    ctor public AnnotationTypeMismatchException(java.lang.reflect.Method, String);
     method public java.lang.reflect.Method element();
-    method public java.lang.String foundType();
+    method public String foundType();
   }
 
-  public abstract class Documented implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target(java.lang.annotation.ElementType.ANNOTATION_TYPE) public @interface Documented {
   }
 
-  public final class ElementType extends java.lang.Enum {
-    method public static java.lang.annotation.ElementType valueOf(java.lang.String);
-    method public static final java.lang.annotation.ElementType[] values();
+  public enum ElementType {
     enum_constant public static final java.lang.annotation.ElementType ANNOTATION_TYPE;
     enum_constant public static final java.lang.annotation.ElementType CONSTRUCTOR;
     enum_constant public static final java.lang.annotation.ElementType FIELD;
@@ -60380,32 +60793,33 @@
   }
 
   public class IncompleteAnnotationException extends java.lang.RuntimeException {
-    ctor public IncompleteAnnotationException(java.lang.Class<? extends java.lang.annotation.Annotation>, java.lang.String);
-    method public java.lang.Class<? extends java.lang.annotation.Annotation> annotationType();
-    method public java.lang.String elementName();
+    ctor public IncompleteAnnotationException(Class<? extends java.lang.annotation.Annotation>, String);
+    method public Class<? extends java.lang.annotation.Annotation> annotationType();
+    method public String elementName();
   }
 
-  public abstract class Inherited implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target(java.lang.annotation.ElementType.ANNOTATION_TYPE) public @interface Inherited {
   }
 
-  public abstract class Native implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target(java.lang.annotation.ElementType.FIELD) public @interface Native {
   }
 
-  public abstract class Repeatable implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target(java.lang.annotation.ElementType.ANNOTATION_TYPE) public @interface Repeatable {
+    method public abstract Class<? extends java.lang.annotation.Annotation> value();
   }
 
-  public abstract class Retention implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target(java.lang.annotation.ElementType.ANNOTATION_TYPE) public @interface Retention {
+    method public abstract java.lang.annotation.RetentionPolicy value();
   }
 
-  public final class RetentionPolicy extends java.lang.Enum {
-    method public static java.lang.annotation.RetentionPolicy valueOf(java.lang.String);
-    method public static final java.lang.annotation.RetentionPolicy[] values();
+  public enum RetentionPolicy {
     enum_constant public static final java.lang.annotation.RetentionPolicy CLASS;
     enum_constant public static final java.lang.annotation.RetentionPolicy RUNTIME;
     enum_constant public static final java.lang.annotation.RetentionPolicy SOURCE;
   }
 
-  public abstract class Target implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target(java.lang.annotation.ElementType.ANNOTATION_TYPE) public @interface Target {
+    method public abstract java.lang.annotation.ElementType[] value();
   }
 
 }
@@ -60429,40 +60843,40 @@
 
   public class LambdaConversionException extends java.lang.Exception {
     ctor public LambdaConversionException();
-    ctor public LambdaConversionException(java.lang.String);
-    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable);
-    ctor public LambdaConversionException(java.lang.Throwable);
-    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable, boolean, boolean);
+    ctor public LambdaConversionException(String);
+    ctor public LambdaConversionException(String, Throwable);
+    ctor public LambdaConversionException(Throwable);
+    ctor public LambdaConversionException(String, Throwable, boolean, boolean);
   }
 
   public abstract class MethodHandle {
-    method public java.lang.invoke.MethodHandle asCollector(java.lang.Class<?>, int);
+    method public java.lang.invoke.MethodHandle asCollector(Class<?>, int);
     method public java.lang.invoke.MethodHandle asFixedArity();
-    method public java.lang.invoke.MethodHandle asSpreader(java.lang.Class<?>, int);
+    method public java.lang.invoke.MethodHandle asSpreader(Class<?>, int);
     method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
-    method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
-    method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
-    method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
-    method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
-    method public java.lang.Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
-    method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
+    method public java.lang.invoke.MethodHandle asVarargsCollector(Class<?>);
+    method public java.lang.invoke.MethodHandle bindTo(Object);
+    method public final Object invoke(java.lang.Object...) throws java.lang.Throwable;
+    method public final Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+    method public Object invokeWithArguments(java.lang.Object...) throws java.lang.Throwable;
+    method public Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
     method public boolean isVarargsCollector();
     method public java.lang.invoke.MethodType type();
   }
 
-  public abstract interface MethodHandleInfo {
-    method public abstract java.lang.Class<?> getDeclaringClass();
-    method public abstract java.lang.invoke.MethodType getMethodType();
-    method public abstract int getModifiers();
-    method public abstract java.lang.String getName();
-    method public abstract int getReferenceKind();
+  public interface MethodHandleInfo {
+    method public Class<?> getDeclaringClass();
+    method public java.lang.invoke.MethodType getMethodType();
+    method public int getModifiers();
+    method public String getName();
+    method public int getReferenceKind();
     method public default boolean isVarArgs();
     method public static boolean refKindIsField(int);
     method public static boolean refKindIsValid(int);
-    method public static java.lang.String refKindName(int);
-    method public static java.lang.String referenceKindToString(int);
-    method public abstract <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandles.Lookup);
-    method public static java.lang.String toString(int, java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType);
+    method public static String refKindName(int);
+    method public static String referenceKindToString(int);
+    method public <T extends java.lang.reflect.Member> T reflectAs(Class<T>, java.lang.invoke.MethodHandles.Lookup);
+    method public static String toString(int, Class<?>, String, java.lang.invoke.MethodType);
     field public static final int REF_getField = 1; // 0x1
     field public static final int REF_getStatic = 2; // 0x2
     field public static final int REF_invokeInterface = 9; // 0x9
@@ -60475,49 +60889,49 @@
   }
 
   public class MethodHandles {
-    method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
-    method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
-    method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle arrayElementGetter(Class<?>) throws java.lang.IllegalArgumentException;
+    method public static java.lang.invoke.MethodHandle arrayElementSetter(Class<?>) throws java.lang.IllegalArgumentException;
+    method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle);
-    method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
+    method public static java.lang.invoke.MethodHandle constant(Class<?>, Object);
     method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
-    method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
+    method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, Class<?>...);
     method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
     method public static java.lang.invoke.MethodHandle explicitCastArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType);
     method public static java.lang.invoke.MethodHandle filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...);
     method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
-    method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodHandle identity(Class<?>);
     method public static java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...);
     method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
     method public static java.lang.invoke.MethodHandles.Lookup lookup();
     method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
     method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
-    method public static <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandle);
+    method public static <T extends java.lang.reflect.Member> T reflectAs(Class<T>, java.lang.invoke.MethodHandle);
     method public static java.lang.invoke.MethodHandle spreadInvoker(java.lang.invoke.MethodType, int);
-    method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
+    method public static java.lang.invoke.MethodHandle throwException(Class<?>, Class<? extends java.lang.Throwable>);
   }
 
   public static final class MethodHandles.Lookup {
-    method public java.lang.invoke.MethodHandle bind(java.lang.Object, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
-    method public java.lang.invoke.MethodHandle findConstructor(java.lang.Class<?>, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
-    method public java.lang.invoke.MethodHandle findGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
-    method public java.lang.invoke.MethodHandle findSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
-    method public java.lang.invoke.MethodHandle findSpecial(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
-    method public java.lang.invoke.MethodHandle findStatic(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
-    method public java.lang.invoke.MethodHandle findStaticGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
-    method public java.lang.invoke.MethodHandle findStaticSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
-    method public java.lang.invoke.MethodHandle findVirtual(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
-    method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
-    method public java.lang.Class<?> lookupClass();
+    method public java.lang.invoke.MethodHandle bind(Object, String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findConstructor(Class<?>, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findGetter(Class<?>, String, Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSetter(Class<?>, String, Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSpecial(Class<?>, String, java.lang.invoke.MethodType, Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStatic(Class<?>, String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStaticGetter(Class<?>, String, Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findStaticSetter(Class<?>, String, Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findVirtual(Class<?>, String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandles.Lookup in(Class<?>);
+    method public Class<?> lookupClass();
     method public int lookupModes();
     method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
     method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
     method public java.lang.invoke.MethodHandle unreflectSetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
-    method public java.lang.invoke.MethodHandle unreflectSpecial(java.lang.reflect.Method, java.lang.Class<?>) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectSpecial(java.lang.reflect.Method, Class<?>) throws java.lang.IllegalAccessException;
     field public static final int PACKAGE = 8; // 0x8
     field public static final int PRIVATE = 2; // 0x2
     field public static final int PROTECTED = 4; // 0x4
@@ -60525,32 +60939,32 @@
   }
 
   public final class MethodType implements java.io.Serializable {
-    method public java.lang.invoke.MethodType appendParameterTypes(java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType appendParameterTypes(Class<?>...);
     method public java.lang.invoke.MethodType appendParameterTypes(java.util.List<java.lang.Class<?>>);
-    method public java.lang.invoke.MethodType changeParameterType(int, java.lang.Class<?>);
-    method public java.lang.invoke.MethodType changeReturnType(java.lang.Class<?>);
+    method public java.lang.invoke.MethodType changeParameterType(int, Class<?>);
+    method public java.lang.invoke.MethodType changeReturnType(Class<?>);
     method public java.lang.invoke.MethodType dropParameterTypes(int, int);
     method public java.lang.invoke.MethodType erase();
-    method public static java.lang.invoke.MethodType fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) throws java.lang.IllegalArgumentException, java.lang.TypeNotPresentException;
+    method public static java.lang.invoke.MethodType fromMethodDescriptorString(String, ClassLoader) throws java.lang.IllegalArgumentException, java.lang.TypeNotPresentException;
     method public java.lang.invoke.MethodType generic();
     method public static java.lang.invoke.MethodType genericMethodType(int, boolean);
     method public static java.lang.invoke.MethodType genericMethodType(int);
     method public boolean hasPrimitives();
     method public boolean hasWrappers();
-    method public java.lang.invoke.MethodType insertParameterTypes(int, java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType insertParameterTypes(int, Class<?>...);
     method public java.lang.invoke.MethodType insertParameterTypes(int, java.util.List<java.lang.Class<?>>);
-    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>[]);
-    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.util.List<java.lang.Class<?>>);
-    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>, java.lang.Class<?>...);
-    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>);
-    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>);
-    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.invoke.MethodType);
-    method public java.lang.Class<?>[] parameterArray();
+    method public static java.lang.invoke.MethodType methodType(Class<?>, Class<?>[]);
+    method public static java.lang.invoke.MethodType methodType(Class<?>, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodType methodType(Class<?>, Class<?>, Class<?>...);
+    method public static java.lang.invoke.MethodType methodType(Class<?>);
+    method public static java.lang.invoke.MethodType methodType(Class<?>, Class<?>);
+    method public static java.lang.invoke.MethodType methodType(Class<?>, java.lang.invoke.MethodType);
+    method public Class<?>[] parameterArray();
     method public int parameterCount();
     method public java.util.List<java.lang.Class<?>> parameterList();
-    method public java.lang.Class<?> parameterType(int);
-    method public java.lang.Class<?> returnType();
-    method public java.lang.String toMethodDescriptorString();
+    method public Class<?> parameterType(int);
+    method public Class<?> returnType();
+    method public String toMethodDescriptorString();
     method public java.lang.invoke.MethodType unwrap();
     method public java.lang.invoke.MethodType wrap();
   }
@@ -60573,14 +60987,14 @@
 
   public class WrongMethodTypeException extends java.lang.RuntimeException {
     ctor public WrongMethodTypeException();
-    ctor public WrongMethodTypeException(java.lang.String);
+    ctor public WrongMethodTypeException(String);
   }
 
 }
 
 package java.lang.ref {
 
-  public class PhantomReference<T> extends java.lang.ref.Reference {
+  public class PhantomReference<T> extends java.lang.ref.Reference<T> {
     ctor public PhantomReference(T, java.lang.ref.ReferenceQueue<? super T>);
   }
 
@@ -60589,7 +61003,7 @@
     method public boolean enqueue();
     method public T get();
     method public boolean isEnqueued();
-    method public static void reachabilityFence(java.lang.Object);
+    method public static void reachabilityFence(Object);
   }
 
   public class ReferenceQueue<T> {
@@ -60599,12 +61013,12 @@
     method public java.lang.ref.Reference<? extends T> remove() throws java.lang.InterruptedException;
   }
 
-  public class SoftReference<T> extends java.lang.ref.Reference {
+  public class SoftReference<T> extends java.lang.ref.Reference<T> {
     ctor public SoftReference(T);
     ctor public SoftReference(T, java.lang.ref.ReferenceQueue<? super T>);
   }
 
-  public class WeakReference<T> extends java.lang.ref.Reference {
+  public class WeakReference<T> extends java.lang.ref.Reference<T> {
     ctor public WeakReference(T);
     ctor public WeakReference(T, java.lang.ref.ReferenceQueue<? super T>);
   }
@@ -60615,7 +61029,7 @@
 
   public class AccessibleObject implements java.lang.reflect.AnnotatedElement {
     ctor protected AccessibleObject();
-    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
+    method @Nullable public <T extends java.lang.annotation.Annotation> T getAnnotation(@NonNull Class<T>);
     method public java.lang.annotation.Annotation[] getAnnotations();
     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public boolean isAccessible();
@@ -60623,118 +61037,117 @@
     method public void setAccessible(boolean) throws java.lang.SecurityException;
   }
 
-  public abstract interface AnnotatedElement {
-    method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
-    method public abstract java.lang.annotation.Annotation[] getAnnotations();
-    method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
-    method public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(java.lang.Class<T>);
-    method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
-    method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
-    method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
+  public interface AnnotatedElement {
+    method @Nullable public <T extends java.lang.annotation.Annotation> T getAnnotation(@NonNull Class<T>);
+    method public java.lang.annotation.Annotation[] getAnnotations();
+    method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(@NonNull Class<T>);
+    method @Nullable public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(@NonNull Class<T>);
+    method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
+    method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(@NonNull Class<T>);
+    method public default boolean isAnnotationPresent(@NonNull Class<? extends java.lang.annotation.Annotation>);
   }
 
   public final class Array {
-    method public static java.lang.Object get(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static boolean getBoolean(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static byte getByte(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static char getChar(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static double getDouble(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static float getFloat(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static int getInt(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static int getLength(java.lang.Object);
-    method public static long getLong(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static short getShort(java.lang.Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static java.lang.Object newInstance(java.lang.Class<?>, int) throws java.lang.NegativeArraySizeException;
-    method public static java.lang.Object newInstance(java.lang.Class<?>, int...) throws java.lang.IllegalArgumentException, java.lang.NegativeArraySizeException;
-    method public static void set(java.lang.Object, int, java.lang.Object) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static void setBoolean(java.lang.Object, int, boolean);
-    method public static void setByte(java.lang.Object, int, byte) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static void setChar(java.lang.Object, int, char) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static void setDouble(java.lang.Object, int, double) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static void setFloat(java.lang.Object, int, float) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static void setInt(java.lang.Object, int, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static void setLong(java.lang.Object, int, long) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
-    method public static void setShort(java.lang.Object, int, short) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method @Nullable public static Object get(@NonNull Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static boolean getBoolean(@NonNull Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static byte getByte(@NonNull Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static char getChar(@NonNull Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static double getDouble(@NonNull Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static float getFloat(@NonNull Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static int getInt(@NonNull Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static int getLength(@NonNull Object);
+    method public static long getLong(@NonNull Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static short getShort(@NonNull Object, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method @NonNull public static Object newInstance(@NonNull Class<?>, int) throws java.lang.NegativeArraySizeException;
+    method @NonNull public static Object newInstance(@NonNull Class<?>, int...) throws java.lang.IllegalArgumentException, java.lang.NegativeArraySizeException;
+    method public static void set(@NonNull Object, int, @Nullable Object) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static void setBoolean(@NonNull Object, int, boolean);
+    method public static void setByte(@NonNull Object, int, byte) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static void setChar(@NonNull Object, int, char) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static void setDouble(@NonNull Object, int, double) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static void setFloat(@NonNull Object, int, float) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static void setInt(@NonNull Object, int, int) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static void setLong(@NonNull Object, int, long) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
+    method public static void setShort(@NonNull Object, int, short) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException;
   }
 
   public final class Constructor<T> extends java.lang.reflect.Executable {
-    method public java.lang.Class<T> getDeclaringClass();
-    method public java.lang.Class<?>[] getExceptionTypes();
+    method @NonNull public Class<T> getDeclaringClass();
+    method public Class<?>[] getExceptionTypes();
     method public int getModifiers();
-    method public java.lang.String getName();
+    method @NonNull public String getName();
     method public java.lang.annotation.Annotation[][] getParameterAnnotations();
-    method public java.lang.Class<?>[] getParameterTypes();
+    method public Class<?>[] getParameterTypes();
     method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters();
-    method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
-    method public java.lang.String toGenericString();
+    method @NonNull public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
+    method @NonNull public String toGenericString();
   }
 
   public abstract class Executable extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
-    method public abstract java.lang.Class<?>[] getExceptionTypes();
+    method public abstract Class<?>[] getExceptionTypes();
     method public java.lang.reflect.Type[] getGenericExceptionTypes();
     method public java.lang.reflect.Type[] getGenericParameterTypes();
     method public abstract java.lang.annotation.Annotation[][] getParameterAnnotations();
     method public int getParameterCount();
-    method public abstract java.lang.Class<?>[] getParameterTypes();
+    method public abstract Class<?>[] getParameterTypes();
     method public java.lang.reflect.Parameter[] getParameters();
-    method public final boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
+    method public final boolean isAnnotationPresent(@NonNull Class<? extends java.lang.annotation.Annotation>);
     method public boolean isSynthetic();
     method public boolean isVarArgs();
-    method public abstract java.lang.String toGenericString();
+    method @NonNull public abstract String toGenericString();
   }
 
   public final class Field extends java.lang.reflect.AccessibleObject implements java.lang.reflect.Member {
-    method public java.lang.Object get(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public boolean getBoolean(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public byte getByte(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public char getChar(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public java.lang.Class<?> getDeclaringClass();
-    method public double getDouble(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public float getFloat(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public java.lang.reflect.Type getGenericType();
-    method public int getInt(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public long getLong(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method @Nullable public Object get(@Nullable Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method public boolean getBoolean(@Nullable Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method public byte getByte(@Nullable Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method public char getChar(@Nullable Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method @NonNull public Class<?> getDeclaringClass();
+    method public double getDouble(@Nullable Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method public float getFloat(@Nullable Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method @NonNull public java.lang.reflect.Type getGenericType();
+    method public int getInt(@Nullable Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method public long getLong(@Nullable Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
     method public int getModifiers();
-    method public java.lang.String getName();
-    method public short getShort(java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public java.lang.Class<?> getType();
+    method @NonNull public String getName();
+    method public short getShort(@Nullable Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method @NonNull public Class<?> getType();
     method public boolean isEnumConstant();
     method public boolean isSynthetic();
-    method public void set(java.lang.Object, java.lang.Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public void setBoolean(java.lang.Object, boolean) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public void setByte(java.lang.Object, byte) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public void setChar(java.lang.Object, char) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public void setDouble(java.lang.Object, double) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public void setFloat(java.lang.Object, float) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public void setInt(java.lang.Object, int) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public void setLong(java.lang.Object, long) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public void setShort(java.lang.Object, short) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
-    method public java.lang.String toGenericString();
+    method public void set(@Nullable Object, @Nullable Object) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method public void setBoolean(@Nullable Object, boolean) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method public void setByte(@Nullable Object, byte) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method public void setChar(@Nullable Object, char) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method public void setDouble(@Nullable Object, double) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method public void setFloat(@Nullable Object, float) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method public void setInt(@Nullable Object, int) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method public void setLong(@Nullable Object, long) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method public void setShort(@Nullable Object, short) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+    method @NonNull public String toGenericString();
   }
 
-  public abstract interface GenericArrayType implements java.lang.reflect.Type {
-    method public abstract java.lang.reflect.Type getGenericComponentType();
+  public interface GenericArrayType extends java.lang.reflect.Type {
+    method @NonNull public java.lang.reflect.Type getGenericComponentType();
   }
 
-  public abstract interface GenericDeclaration implements java.lang.reflect.AnnotatedElement {
-    method public abstract java.lang.reflect.TypeVariable<?>[] getTypeParameters();
+  public interface GenericDeclaration extends java.lang.reflect.AnnotatedElement {
+    method @NonNull public java.lang.reflect.TypeVariable<?>[] getTypeParameters();
   }
 
   public class GenericSignatureFormatError extends java.lang.ClassFormatError {
     ctor public GenericSignatureFormatError();
-    ctor public GenericSignatureFormatError(java.lang.String);
+    ctor public GenericSignatureFormatError(String);
   }
 
-  public abstract interface InvocationHandler {
-    method public abstract java.lang.Object invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) throws java.lang.Throwable;
+  public interface InvocationHandler {
+    method public Object invoke(Object, java.lang.reflect.Method, Object[]) throws java.lang.Throwable;
   }
 
   public class InvocationTargetException extends java.lang.ReflectiveOperationException {
     ctor protected InvocationTargetException();
-    ctor public InvocationTargetException(java.lang.Throwable);
-    ctor public InvocationTargetException(java.lang.Throwable, java.lang.String);
-    method public java.lang.Throwable getCause();
-    method public java.lang.Throwable getTargetException();
+    ctor public InvocationTargetException(Throwable);
+    ctor public InvocationTargetException(Throwable, String);
+    method public Throwable getTargetException();
   }
 
   public class MalformedParameterizedTypeException extends java.lang.RuntimeException {
@@ -60743,33 +61156,33 @@
 
   public class MalformedParametersException extends java.lang.RuntimeException {
     ctor public MalformedParametersException();
-    ctor public MalformedParametersException(java.lang.String);
+    ctor public MalformedParametersException(String);
   }
 
-  public abstract interface Member {
-    method public abstract java.lang.Class<?> getDeclaringClass();
-    method public abstract int getModifiers();
-    method public abstract java.lang.String getName();
-    method public abstract boolean isSynthetic();
+  public interface Member {
+    method @NonNull public Class<?> getDeclaringClass();
+    method public int getModifiers();
+    method @NonNull public String getName();
+    method public boolean isSynthetic();
     field public static final int DECLARED = 1; // 0x1
     field public static final int PUBLIC = 0; // 0x0
   }
 
   public final class Method extends java.lang.reflect.Executable {
-    method public java.lang.Class<?> getDeclaringClass();
-    method public java.lang.Object getDefaultValue();
-    method public java.lang.Class<?>[] getExceptionTypes();
-    method public java.lang.reflect.Type getGenericReturnType();
+    method @NonNull public Class<?> getDeclaringClass();
+    method @Nullable public Object getDefaultValue();
+    method @NonNull public Class<?>[] getExceptionTypes();
+    method @NonNull public java.lang.reflect.Type getGenericReturnType();
     method public int getModifiers();
-    method public java.lang.String getName();
-    method public java.lang.annotation.Annotation[][] getParameterAnnotations();
-    method public java.lang.Class<?>[] getParameterTypes();
-    method public java.lang.Class<?> getReturnType();
-    method public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters();
-    method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
+    method @NonNull public String getName();
+    method @NonNull public java.lang.annotation.Annotation[][] getParameterAnnotations();
+    method @NonNull public Class<?>[] getParameterTypes();
+    method @NonNull public Class<?> getReturnType();
+    method @NonNull public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters();
+    method @Nullable public Object invoke(@Nullable Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
     method public boolean isBridge();
     method public boolean isDefault();
-    method public java.lang.String toGenericString();
+    method @NonNull public String toGenericString();
   }
 
   public class Modifier {
@@ -60792,7 +61205,7 @@
     method public static boolean isVolatile(int);
     method public static int methodModifiers();
     method public static int parameterModifiers();
-    method public static java.lang.String toString(int);
+    method public static String toString(int);
     field public static final int ABSTRACT = 1024; // 0x400
     field public static final int FINAL = 16; // 0x10
     field public static final int INTERFACE = 512; // 0x200
@@ -60808,73 +61221,72 @@
   }
 
   public final class Parameter implements java.lang.reflect.AnnotatedElement {
-    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
+    method @Nullable public <T extends java.lang.annotation.Annotation> T getAnnotation(@NonNull Class<T>);
     method public java.lang.annotation.Annotation[] getAnnotations();
     method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
-    method public java.lang.reflect.Executable getDeclaringExecutable();
+    method @NonNull public java.lang.reflect.Executable getDeclaringExecutable();
     method public int getModifiers();
-    method public java.lang.String getName();
-    method public java.lang.reflect.Type getParameterizedType();
-    method public java.lang.Class<?> getType();
+    method @NonNull public String getName();
+    method @NonNull public java.lang.reflect.Type getParameterizedType();
+    method @NonNull public Class<?> getType();
     method public boolean isImplicit();
     method public boolean isNamePresent();
     method public boolean isSynthetic();
     method public boolean isVarArgs();
   }
 
-  public abstract interface ParameterizedType implements java.lang.reflect.Type {
-    method public abstract java.lang.reflect.Type[] getActualTypeArguments();
-    method public abstract java.lang.reflect.Type getOwnerType();
-    method public abstract java.lang.reflect.Type getRawType();
+  public interface ParameterizedType extends java.lang.reflect.Type {
+    method public java.lang.reflect.Type[] getActualTypeArguments();
+    method @Nullable public java.lang.reflect.Type getOwnerType();
+    method @NonNull public java.lang.reflect.Type getRawType();
   }
 
   public class Proxy implements java.io.Serializable {
-    ctor protected Proxy(java.lang.reflect.InvocationHandler);
-    method public static java.lang.reflect.InvocationHandler getInvocationHandler(java.lang.Object) throws java.lang.IllegalArgumentException;
-    method public static java.lang.Class<?> getProxyClass(java.lang.ClassLoader, java.lang.Class<?>...) throws java.lang.IllegalArgumentException;
-    method public static boolean isProxyClass(java.lang.Class<?>);
-    method public static java.lang.Object newProxyInstance(java.lang.ClassLoader, java.lang.Class<?>[], java.lang.reflect.InvocationHandler) throws java.lang.IllegalArgumentException;
+    ctor protected Proxy(@NonNull java.lang.reflect.InvocationHandler);
+    method @NonNull public static java.lang.reflect.InvocationHandler getInvocationHandler(@NonNull Object) throws java.lang.IllegalArgumentException;
+    method @NonNull public static Class<?> getProxyClass(@Nullable ClassLoader, Class<?>...) throws java.lang.IllegalArgumentException;
+    method public static boolean isProxyClass(@NonNull Class<?>);
+    method @NonNull public static Object newProxyInstance(@Nullable ClassLoader, Class<?>[], @NonNull java.lang.reflect.InvocationHandler) throws java.lang.IllegalArgumentException;
     field protected java.lang.reflect.InvocationHandler h;
   }
 
   public final class ReflectPermission extends java.security.BasicPermission {
-    ctor public ReflectPermission(java.lang.String);
-    ctor public ReflectPermission(java.lang.String, java.lang.String);
+    ctor public ReflectPermission(String);
+    ctor public ReflectPermission(String, String);
   }
 
-  public abstract interface Type {
-    method public default java.lang.String getTypeName();
+  public interface Type {
+    method @NonNull public default String getTypeName();
   }
 
-  public abstract interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> implements java.lang.reflect.Type {
-    method public abstract java.lang.reflect.Type[] getBounds();
-    method public abstract D getGenericDeclaration();
-    method public abstract java.lang.String getName();
+  public interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> extends java.lang.reflect.Type {
+    method public java.lang.reflect.Type[] getBounds();
+    method @NonNull public D getGenericDeclaration();
+    method @NonNull public String getName();
   }
 
   public class UndeclaredThrowableException extends java.lang.RuntimeException {
-    ctor public UndeclaredThrowableException(java.lang.Throwable);
-    ctor public UndeclaredThrowableException(java.lang.Throwable, java.lang.String);
-    method public java.lang.Throwable getCause();
-    method public java.lang.Throwable getUndeclaredThrowable();
+    ctor public UndeclaredThrowableException(Throwable);
+    ctor public UndeclaredThrowableException(Throwable, String);
+    method public Throwable getUndeclaredThrowable();
   }
 
-  public abstract interface WildcardType implements java.lang.reflect.Type {
-    method public abstract java.lang.reflect.Type[] getLowerBounds();
-    method public abstract java.lang.reflect.Type[] getUpperBounds();
+  public interface WildcardType extends java.lang.reflect.Type {
+    method public java.lang.reflect.Type[] getLowerBounds();
+    method public java.lang.reflect.Type[] getUpperBounds();
   }
 
 }
 
 package java.math {
 
-  public class BigDecimal extends java.lang.Number implements java.lang.Comparable java.io.Serializable {
+  public class BigDecimal extends java.lang.Number implements java.lang.Comparable<java.math.BigDecimal> java.io.Serializable {
     ctor public BigDecimal(char[], int, int);
     ctor public BigDecimal(char[], int, int, java.math.MathContext);
     ctor public BigDecimal(char[]);
     ctor public BigDecimal(char[], java.math.MathContext);
-    ctor public BigDecimal(java.lang.String);
-    ctor public BigDecimal(java.lang.String, java.math.MathContext);
+    ctor public BigDecimal(String);
+    ctor public BigDecimal(String, java.math.MathContext);
     ctor public BigDecimal(double);
     ctor public BigDecimal(double, java.math.MathContext);
     ctor public BigDecimal(java.math.BigInteger);
@@ -60935,8 +61347,8 @@
     method public java.math.BigDecimal subtract(java.math.BigDecimal, java.math.MathContext);
     method public java.math.BigInteger toBigInteger();
     method public java.math.BigInteger toBigIntegerExact();
-    method public java.lang.String toEngineeringString();
-    method public java.lang.String toPlainString();
+    method public String toEngineeringString();
+    method public String toPlainString();
     method public java.math.BigDecimal ulp();
     method public java.math.BigInteger unscaledValue();
     method public static java.math.BigDecimal valueOf(long, int);
@@ -60955,63 +61367,63 @@
     field public static final java.math.BigDecimal ZERO;
   }
 
-  public class BigInteger extends java.lang.Number implements java.lang.Comparable java.io.Serializable {
-    ctor public BigInteger(int, java.util.Random);
-    ctor public BigInteger(int, int, java.util.Random);
-    ctor public BigInteger(java.lang.String);
-    ctor public BigInteger(java.lang.String, int);
+  public class BigInteger extends java.lang.Number implements java.lang.Comparable<java.math.BigInteger> java.io.Serializable {
+    ctor public BigInteger(int, @NonNull java.util.Random);
+    ctor public BigInteger(int, int, @NonNull java.util.Random);
+    ctor public BigInteger(@NonNull String);
+    ctor public BigInteger(@NonNull String, int);
     ctor public BigInteger(int, byte[]);
     ctor public BigInteger(byte[]);
-    method public java.math.BigInteger abs();
-    method public java.math.BigInteger add(java.math.BigInteger);
-    method public java.math.BigInteger and(java.math.BigInteger);
-    method public java.math.BigInteger andNot(java.math.BigInteger);
+    method @NonNull public java.math.BigInteger abs();
+    method @NonNull public java.math.BigInteger add(@NonNull java.math.BigInteger);
+    method @NonNull public java.math.BigInteger and(@NonNull java.math.BigInteger);
+    method @NonNull public java.math.BigInteger andNot(@NonNull java.math.BigInteger);
     method public int bitCount();
     method public int bitLength();
-    method public java.math.BigInteger clearBit(int);
-    method public int compareTo(java.math.BigInteger);
-    method public java.math.BigInteger divide(java.math.BigInteger);
-    method public java.math.BigInteger[] divideAndRemainder(java.math.BigInteger);
+    method @NonNull public java.math.BigInteger clearBit(int);
+    method public int compareTo(@NonNull java.math.BigInteger);
+    method @NonNull public java.math.BigInteger divide(@NonNull java.math.BigInteger);
+    method @NonNull public java.math.BigInteger[] divideAndRemainder(@NonNull java.math.BigInteger);
     method public double doubleValue();
-    method public java.math.BigInteger flipBit(int);
+    method @NonNull public java.math.BigInteger flipBit(int);
     method public float floatValue();
-    method public java.math.BigInteger gcd(java.math.BigInteger);
+    method @NonNull public java.math.BigInteger gcd(@NonNull java.math.BigInteger);
     method public int getLowestSetBit();
     method public int intValue();
     method public boolean isProbablePrime(int);
     method public long longValue();
-    method public java.math.BigInteger max(java.math.BigInteger);
-    method public java.math.BigInteger min(java.math.BigInteger);
-    method public java.math.BigInteger mod(java.math.BigInteger);
-    method public java.math.BigInteger modInverse(java.math.BigInteger);
-    method public java.math.BigInteger modPow(java.math.BigInteger, java.math.BigInteger);
-    method public java.math.BigInteger multiply(java.math.BigInteger);
-    method public java.math.BigInteger negate();
-    method public java.math.BigInteger nextProbablePrime();
-    method public java.math.BigInteger not();
-    method public java.math.BigInteger or(java.math.BigInteger);
-    method public java.math.BigInteger pow(int);
-    method public static java.math.BigInteger probablePrime(int, java.util.Random);
-    method public java.math.BigInteger remainder(java.math.BigInteger);
-    method public java.math.BigInteger setBit(int);
-    method public java.math.BigInteger shiftLeft(int);
-    method public java.math.BigInteger shiftRight(int);
+    method @NonNull public java.math.BigInteger max(@NonNull java.math.BigInteger);
+    method @NonNull public java.math.BigInteger min(@NonNull java.math.BigInteger);
+    method @NonNull public java.math.BigInteger mod(@NonNull java.math.BigInteger);
+    method @NonNull public java.math.BigInteger modInverse(@NonNull java.math.BigInteger);
+    method @NonNull public java.math.BigInteger modPow(@NonNull java.math.BigInteger, @NonNull java.math.BigInteger);
+    method @NonNull public java.math.BigInteger multiply(@NonNull java.math.BigInteger);
+    method @NonNull public java.math.BigInteger negate();
+    method @NonNull public java.math.BigInteger nextProbablePrime();
+    method @NonNull public java.math.BigInteger not();
+    method @NonNull public java.math.BigInteger or(@NonNull java.math.BigInteger);
+    method @NonNull public java.math.BigInteger pow(int);
+    method @NonNull public static java.math.BigInteger probablePrime(int, @NonNull java.util.Random);
+    method @NonNull public java.math.BigInteger remainder(@NonNull java.math.BigInteger);
+    method @NonNull public java.math.BigInteger setBit(int);
+    method @NonNull public java.math.BigInteger shiftLeft(int);
+    method @NonNull public java.math.BigInteger shiftRight(int);
     method public int signum();
-    method public java.math.BigInteger subtract(java.math.BigInteger);
+    method @NonNull public java.math.BigInteger subtract(@NonNull java.math.BigInteger);
     method public boolean testBit(int);
     method public byte[] toByteArray();
-    method public java.lang.String toString(int);
-    method public static java.math.BigInteger valueOf(long);
-    method public java.math.BigInteger xor(java.math.BigInteger);
-    field public static final java.math.BigInteger ONE;
-    field public static final java.math.BigInteger TEN;
-    field public static final java.math.BigInteger ZERO;
+    method @NonNull public String toString(int);
+    method @NonNull public static java.math.BigInteger valueOf(long);
+    method @NonNull public java.math.BigInteger xor(@NonNull java.math.BigInteger);
+    field @NonNull public static final java.math.BigInteger ONE;
+    field @NonNull public static final java.math.BigInteger TEN;
+    field @NonNull public static final java.math.BigInteger ZERO;
   }
 
   public final class MathContext implements java.io.Serializable {
     ctor public MathContext(int);
     ctor public MathContext(int, java.math.RoundingMode);
-    ctor public MathContext(java.lang.String);
+    ctor public MathContext(String);
     method public int getPrecision();
     method public java.math.RoundingMode getRoundingMode();
     field public static final java.math.MathContext DECIMAL128;
@@ -61020,10 +61432,8 @@
     field public static final java.math.MathContext UNLIMITED;
   }
 
-  public final class RoundingMode extends java.lang.Enum {
-    method public static java.math.RoundingMode valueOf(java.lang.String);
+  public enum RoundingMode {
     method public static java.math.RoundingMode valueOf(int);
-    method public static final java.math.RoundingMode[] values();
     enum_constant public static final java.math.RoundingMode CEILING;
     enum_constant public static final java.math.RoundingMode DOWN;
     enum_constant public static final java.math.RoundingMode FLOOR;
@@ -61041,29 +61451,27 @@
   public abstract class Authenticator {
     ctor public Authenticator();
     method protected java.net.PasswordAuthentication getPasswordAuthentication();
-    method protected final java.lang.String getRequestingHost();
+    method protected final String getRequestingHost();
     method protected final int getRequestingPort();
-    method protected final java.lang.String getRequestingPrompt();
-    method protected final java.lang.String getRequestingProtocol();
-    method protected final java.lang.String getRequestingScheme();
+    method protected final String getRequestingPrompt();
+    method protected final String getRequestingProtocol();
+    method protected final String getRequestingScheme();
     method protected final java.net.InetAddress getRequestingSite();
     method protected java.net.URL getRequestingURL();
     method protected java.net.Authenticator.RequestorType getRequestorType();
-    method public static java.net.PasswordAuthentication requestPasswordAuthentication(java.net.InetAddress, int, java.lang.String, java.lang.String, java.lang.String);
-    method public static java.net.PasswordAuthentication requestPasswordAuthentication(java.lang.String, java.net.InetAddress, int, java.lang.String, java.lang.String, java.lang.String);
-    method public static java.net.PasswordAuthentication requestPasswordAuthentication(java.lang.String, java.net.InetAddress, int, java.lang.String, java.lang.String, java.lang.String, java.net.URL, java.net.Authenticator.RequestorType);
-    method public static synchronized void setDefault(java.net.Authenticator);
+    method public static java.net.PasswordAuthentication requestPasswordAuthentication(java.net.InetAddress, int, String, String, String);
+    method public static java.net.PasswordAuthentication requestPasswordAuthentication(String, java.net.InetAddress, int, String, String, String);
+    method public static java.net.PasswordAuthentication requestPasswordAuthentication(String, java.net.InetAddress, int, String, String, String, java.net.URL, java.net.Authenticator.RequestorType);
+    method public static void setDefault(java.net.Authenticator);
   }
 
-  public static final class Authenticator.RequestorType extends java.lang.Enum {
-    method public static java.net.Authenticator.RequestorType valueOf(java.lang.String);
-    method public static final java.net.Authenticator.RequestorType[] values();
+  public enum Authenticator.RequestorType {
     enum_constant public static final java.net.Authenticator.RequestorType PROXY;
     enum_constant public static final java.net.Authenticator.RequestorType SERVER;
   }
 
   public class BindException extends java.net.SocketException {
-    ctor public BindException(java.lang.String);
+    ctor public BindException(String);
     ctor public BindException();
   }
 
@@ -61076,55 +61484,55 @@
   public abstract class CacheResponse {
     ctor public CacheResponse();
     method public abstract java.io.InputStream getBody() throws java.io.IOException;
-    method public abstract java.util.Map<java.lang.String, java.util.List<java.lang.String>> getHeaders() throws java.io.IOException;
+    method public abstract java.util.Map<java.lang.String,java.util.List<java.lang.String>> getHeaders() throws java.io.IOException;
   }
 
   public class ConnectException extends java.net.SocketException {
-    ctor public ConnectException(java.lang.String);
+    ctor public ConnectException(String);
     ctor public ConnectException();
   }
 
   public abstract class ContentHandler {
     ctor public ContentHandler();
-    method public abstract java.lang.Object getContent(java.net.URLConnection) throws java.io.IOException;
-    method public java.lang.Object getContent(java.net.URLConnection, java.lang.Class[]) throws java.io.IOException;
+    method public abstract Object getContent(java.net.URLConnection) throws java.io.IOException;
+    method public Object getContent(java.net.URLConnection, Class[]) throws java.io.IOException;
   }
 
-  public abstract interface ContentHandlerFactory {
-    method public abstract java.net.ContentHandler createContentHandler(java.lang.String);
+  public interface ContentHandlerFactory {
+    method public java.net.ContentHandler createContentHandler(String);
   }
 
   public abstract class CookieHandler {
     ctor public CookieHandler();
-    method public abstract java.util.Map<java.lang.String, java.util.List<java.lang.String>> get(java.net.URI, java.util.Map<java.lang.String, java.util.List<java.lang.String>>) throws java.io.IOException;
-    method public static synchronized java.net.CookieHandler getDefault();
-    method public abstract void put(java.net.URI, java.util.Map<java.lang.String, java.util.List<java.lang.String>>) throws java.io.IOException;
-    method public static synchronized void setDefault(java.net.CookieHandler);
+    method public abstract java.util.Map<java.lang.String,java.util.List<java.lang.String>> get(java.net.URI, java.util.Map<java.lang.String,java.util.List<java.lang.String>>) throws java.io.IOException;
+    method public static java.net.CookieHandler getDefault();
+    method public abstract void put(java.net.URI, java.util.Map<java.lang.String,java.util.List<java.lang.String>>) throws java.io.IOException;
+    method public static void setDefault(java.net.CookieHandler);
   }
 
   public class CookieManager extends java.net.CookieHandler {
     ctor public CookieManager();
     ctor public CookieManager(java.net.CookieStore, java.net.CookiePolicy);
-    method public java.util.Map<java.lang.String, java.util.List<java.lang.String>> get(java.net.URI, java.util.Map<java.lang.String, java.util.List<java.lang.String>>) throws java.io.IOException;
+    method public java.util.Map<java.lang.String,java.util.List<java.lang.String>> get(java.net.URI, java.util.Map<java.lang.String,java.util.List<java.lang.String>>) throws java.io.IOException;
     method public java.net.CookieStore getCookieStore();
-    method public void put(java.net.URI, java.util.Map<java.lang.String, java.util.List<java.lang.String>>) throws java.io.IOException;
+    method public void put(java.net.URI, java.util.Map<java.lang.String,java.util.List<java.lang.String>>) throws java.io.IOException;
     method public void setCookiePolicy(java.net.CookiePolicy);
   }
 
-  public abstract interface CookiePolicy {
-    method public abstract boolean shouldAccept(java.net.URI, java.net.HttpCookie);
+  public interface CookiePolicy {
+    method public boolean shouldAccept(java.net.URI, java.net.HttpCookie);
     field public static final java.net.CookiePolicy ACCEPT_ALL;
     field public static final java.net.CookiePolicy ACCEPT_NONE;
     field public static final java.net.CookiePolicy ACCEPT_ORIGINAL_SERVER;
   }
 
-  public abstract interface CookieStore {
-    method public abstract void add(java.net.URI, java.net.HttpCookie);
-    method public abstract java.util.List<java.net.HttpCookie> get(java.net.URI);
-    method public abstract java.util.List<java.net.HttpCookie> getCookies();
-    method public abstract java.util.List<java.net.URI> getURIs();
-    method public abstract boolean remove(java.net.URI, java.net.HttpCookie);
-    method public abstract boolean removeAll();
+  public interface CookieStore {
+    method public void add(java.net.URI, java.net.HttpCookie);
+    method public java.util.List<java.net.HttpCookie> get(java.net.URI);
+    method public java.util.List<java.net.HttpCookie> getCookies();
+    method public java.util.List<java.net.URI> getURIs();
+    method public boolean remove(java.net.URI, java.net.HttpCookie);
+    method public boolean removeAll();
   }
 
   public final class DatagramPacket {
@@ -61134,18 +61542,18 @@
     ctor public DatagramPacket(byte[], int, int, java.net.SocketAddress);
     ctor public DatagramPacket(byte[], int, java.net.InetAddress, int);
     ctor public DatagramPacket(byte[], int, java.net.SocketAddress);
-    method public synchronized java.net.InetAddress getAddress();
-    method public synchronized byte[] getData();
-    method public synchronized int getLength();
-    method public synchronized int getOffset();
-    method public synchronized int getPort();
-    method public synchronized java.net.SocketAddress getSocketAddress();
-    method public synchronized void setAddress(java.net.InetAddress);
-    method public synchronized void setData(byte[], int, int);
-    method public synchronized void setData(byte[]);
-    method public synchronized void setLength(int);
-    method public synchronized void setPort(int);
-    method public synchronized void setSocketAddress(java.net.SocketAddress);
+    method public java.net.InetAddress getAddress();
+    method public byte[] getData();
+    method public int getLength();
+    method public int getOffset();
+    method public int getPort();
+    method public java.net.SocketAddress getSocketAddress();
+    method public void setAddress(java.net.InetAddress);
+    method public void setData(byte[], int, int);
+    method public void setData(byte[]);
+    method public void setLength(int);
+    method public void setPort(int);
+    method public void setSocketAddress(java.net.SocketAddress);
   }
 
   public class DatagramSocket implements java.io.Closeable {
@@ -61154,36 +61562,36 @@
     ctor public DatagramSocket(java.net.SocketAddress) throws java.net.SocketException;
     ctor public DatagramSocket(int) throws java.net.SocketException;
     ctor public DatagramSocket(int, java.net.InetAddress) throws java.net.SocketException;
-    method public synchronized void bind(java.net.SocketAddress) throws java.net.SocketException;
+    method public void bind(java.net.SocketAddress) throws java.net.SocketException;
     method public void close();
     method public void connect(java.net.InetAddress, int);
     method public void connect(java.net.SocketAddress) throws java.net.SocketException;
     method public void disconnect();
-    method public synchronized boolean getBroadcast() throws java.net.SocketException;
+    method public boolean getBroadcast() throws java.net.SocketException;
     method public java.nio.channels.DatagramChannel getChannel();
     method public java.net.InetAddress getInetAddress();
     method public java.net.InetAddress getLocalAddress();
     method public int getLocalPort();
     method public java.net.SocketAddress getLocalSocketAddress();
     method public int getPort();
-    method public synchronized int getReceiveBufferSize() throws java.net.SocketException;
+    method public int getReceiveBufferSize() throws java.net.SocketException;
     method public java.net.SocketAddress getRemoteSocketAddress();
-    method public synchronized boolean getReuseAddress() throws java.net.SocketException;
-    method public synchronized int getSendBufferSize() throws java.net.SocketException;
-    method public synchronized int getSoTimeout() throws java.net.SocketException;
-    method public synchronized int getTrafficClass() throws java.net.SocketException;
+    method public boolean getReuseAddress() throws java.net.SocketException;
+    method public int getSendBufferSize() throws java.net.SocketException;
+    method public int getSoTimeout() throws java.net.SocketException;
+    method public int getTrafficClass() throws java.net.SocketException;
     method public boolean isBound();
     method public boolean isClosed();
     method public boolean isConnected();
-    method public synchronized void receive(java.net.DatagramPacket) throws java.io.IOException;
+    method public void receive(java.net.DatagramPacket) throws java.io.IOException;
     method public void send(java.net.DatagramPacket) throws java.io.IOException;
-    method public synchronized void setBroadcast(boolean) throws java.net.SocketException;
-    method public static synchronized void setDatagramSocketImplFactory(java.net.DatagramSocketImplFactory) throws java.io.IOException;
-    method public synchronized void setReceiveBufferSize(int) throws java.net.SocketException;
-    method public synchronized void setReuseAddress(boolean) throws java.net.SocketException;
-    method public synchronized void setSendBufferSize(int) throws java.net.SocketException;
-    method public synchronized void setSoTimeout(int) throws java.net.SocketException;
-    method public synchronized void setTrafficClass(int) throws java.net.SocketException;
+    method public void setBroadcast(boolean) throws java.net.SocketException;
+    method public static void setDatagramSocketImplFactory(java.net.DatagramSocketImplFactory) throws java.io.IOException;
+    method public void setReceiveBufferSize(int) throws java.net.SocketException;
+    method public void setReuseAddress(boolean) throws java.net.SocketException;
+    method public void setSendBufferSize(int) throws java.net.SocketException;
+    method public void setSoTimeout(int) throws java.net.SocketException;
+    method public void setTrafficClass(int) throws java.net.SocketException;
   }
 
   public abstract class DatagramSocketImpl implements java.net.SocketOptions {
@@ -61195,7 +61603,7 @@
     method protected void disconnect();
     method protected java.io.FileDescriptor getFileDescriptor();
     method protected int getLocalPort();
-    method protected abstract deprecated byte getTTL() throws java.io.IOException;
+    method @Deprecated protected abstract byte getTTL() throws java.io.IOException;
     method protected abstract int getTimeToLive() throws java.io.IOException;
     method protected abstract void join(java.net.InetAddress) throws java.io.IOException;
     method protected abstract void joinGroup(java.net.SocketAddress, java.net.NetworkInterface) throws java.io.IOException;
@@ -61205,56 +61613,56 @@
     method protected abstract int peekData(java.net.DatagramPacket) throws java.io.IOException;
     method protected abstract void receive(java.net.DatagramPacket) throws java.io.IOException;
     method protected abstract void send(java.net.DatagramPacket) throws java.io.IOException;
-    method protected abstract deprecated void setTTL(byte) throws java.io.IOException;
+    method @Deprecated protected abstract void setTTL(byte) throws java.io.IOException;
     method protected abstract void setTimeToLive(int) throws java.io.IOException;
     field protected java.io.FileDescriptor fd;
     field protected int localPort;
   }
 
-  public abstract interface DatagramSocketImplFactory {
-    method public abstract java.net.DatagramSocketImpl createDatagramSocketImpl();
+  public interface DatagramSocketImplFactory {
+    method public java.net.DatagramSocketImpl createDatagramSocketImpl();
   }
 
-  public abstract interface FileNameMap {
-    method public abstract java.lang.String getContentTypeFor(java.lang.String);
+  public interface FileNameMap {
+    method public String getContentTypeFor(String);
   }
 
   public final class HttpCookie implements java.lang.Cloneable {
-    ctor public HttpCookie(java.lang.String, java.lang.String);
-    method public java.lang.Object clone();
-    method public static boolean domainMatches(java.lang.String, java.lang.String);
-    method public java.lang.String getComment();
-    method public java.lang.String getCommentURL();
+    ctor public HttpCookie(String, String);
+    method public Object clone();
+    method public static boolean domainMatches(String, String);
+    method public String getComment();
+    method public String getCommentURL();
     method public boolean getDiscard();
-    method public java.lang.String getDomain();
+    method public String getDomain();
     method public long getMaxAge();
-    method public java.lang.String getName();
-    method public java.lang.String getPath();
-    method public java.lang.String getPortlist();
+    method public String getName();
+    method public String getPath();
+    method public String getPortlist();
     method public boolean getSecure();
-    method public java.lang.String getValue();
+    method public String getValue();
     method public int getVersion();
     method public boolean hasExpired();
     method public boolean isHttpOnly();
-    method public static java.util.List<java.net.HttpCookie> parse(java.lang.String);
-    method public void setComment(java.lang.String);
-    method public void setCommentURL(java.lang.String);
+    method public static java.util.List<java.net.HttpCookie> parse(String);
+    method public void setComment(String);
+    method public void setCommentURL(String);
     method public void setDiscard(boolean);
-    method public void setDomain(java.lang.String);
+    method public void setDomain(String);
     method public void setHttpOnly(boolean);
     method public void setMaxAge(long);
-    method public void setPath(java.lang.String);
-    method public void setPortlist(java.lang.String);
+    method public void setPath(String);
+    method public void setPortlist(String);
     method public void setSecure(boolean);
-    method public void setValue(java.lang.String);
+    method public void setValue(String);
     method public void setVersion(int);
   }
 
   public class HttpRetryException extends java.io.IOException {
-    ctor public HttpRetryException(java.lang.String, int);
-    ctor public HttpRetryException(java.lang.String, int, java.lang.String);
-    method public java.lang.String getLocation();
-    method public java.lang.String getReason();
+    ctor public HttpRetryException(String, int);
+    ctor public HttpRetryException(String, int, String);
+    method public String getLocation();
+    method public String getReason();
     method public int responseCode();
   }
 
@@ -61264,15 +61672,15 @@
     method public java.io.InputStream getErrorStream();
     method public static boolean getFollowRedirects();
     method public boolean getInstanceFollowRedirects();
-    method public java.lang.String getRequestMethod();
+    method public String getRequestMethod();
     method public int getResponseCode() throws java.io.IOException;
-    method public java.lang.String getResponseMessage() throws java.io.IOException;
+    method public String getResponseMessage() throws java.io.IOException;
     method public void setChunkedStreamingMode(int);
     method public void setFixedLengthStreamingMode(int);
     method public void setFixedLengthStreamingMode(long);
     method public static void setFollowRedirects(boolean);
     method public void setInstanceFollowRedirects(boolean);
-    method public void setRequestMethod(java.lang.String) throws java.net.ProtocolException;
+    method public void setRequestMethod(String) throws java.net.ProtocolException;
     method public abstract boolean usingProxy();
     field public static final int HTTP_ACCEPTED = 202; // 0xca
     field public static final int HTTP_BAD_GATEWAY = 502; // 0x1f6
@@ -61304,7 +61712,7 @@
     field public static final int HTTP_REQ_TOO_LONG = 414; // 0x19e
     field public static final int HTTP_RESET = 205; // 0xcd
     field public static final int HTTP_SEE_OTHER = 303; // 0x12f
-    field public static final deprecated int HTTP_SERVER_ERROR = 500; // 0x1f4
+    field @Deprecated public static final int HTTP_SERVER_ERROR = 500; // 0x1f4
     field public static final int HTTP_UNAUTHORIZED = 401; // 0x191
     field public static final int HTTP_UNAVAILABLE = 503; // 0x1f7
     field public static final int HTTP_UNSUPPORTED_TYPE = 415; // 0x19f
@@ -61314,16 +61722,16 @@
     field protected int fixedContentLength;
     field protected long fixedContentLengthLong;
     field protected boolean instanceFollowRedirects;
-    field protected java.lang.String method;
+    field protected String method;
     field protected int responseCode;
-    field protected java.lang.String responseMessage;
+    field protected String responseMessage;
   }
 
   public final class IDN {
-    method public static java.lang.String toASCII(java.lang.String, int);
-    method public static java.lang.String toASCII(java.lang.String);
-    method public static java.lang.String toUnicode(java.lang.String, int);
-    method public static java.lang.String toUnicode(java.lang.String);
+    method public static String toASCII(String, int);
+    method public static String toASCII(String);
+    method public static String toUnicode(String, int);
+    method public static String toUnicode(String);
     field public static final int ALLOW_UNASSIGNED = 1; // 0x1
     field public static final int USE_STD3_ASCII_RULES = 2; // 0x2
   }
@@ -61332,8 +61740,8 @@
   }
 
   public final class Inet6Address extends java.net.InetAddress {
-    method public static java.net.Inet6Address getByAddress(java.lang.String, byte[], java.net.NetworkInterface) throws java.net.UnknownHostException;
-    method public static java.net.Inet6Address getByAddress(java.lang.String, byte[], int) throws java.net.UnknownHostException;
+    method public static java.net.Inet6Address getByAddress(String, byte[], java.net.NetworkInterface) throws java.net.UnknownHostException;
+    method public static java.net.Inet6Address getByAddress(String, byte[], int) throws java.net.UnknownHostException;
     method public int getScopeId();
     method public java.net.NetworkInterface getScopedInterface();
     method public boolean isIPv4CompatibleAddress();
@@ -61341,13 +61749,13 @@
 
   public class InetAddress implements java.io.Serializable {
     method public byte[] getAddress();
-    method public static java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
-    method public static java.net.InetAddress getByAddress(java.lang.String, byte[]) throws java.net.UnknownHostException;
+    method public static java.net.InetAddress[] getAllByName(String) throws java.net.UnknownHostException;
+    method public static java.net.InetAddress getByAddress(String, byte[]) throws java.net.UnknownHostException;
     method public static java.net.InetAddress getByAddress(byte[]) throws java.net.UnknownHostException;
-    method public static java.net.InetAddress getByName(java.lang.String) throws java.net.UnknownHostException;
-    method public java.lang.String getCanonicalHostName();
-    method public java.lang.String getHostAddress();
-    method public java.lang.String getHostName();
+    method public static java.net.InetAddress getByName(String) throws java.net.UnknownHostException;
+    method public String getCanonicalHostName();
+    method public String getHostAddress();
+    method public String getHostName();
     method public static java.net.InetAddress getLocalHost() throws java.net.UnknownHostException;
     method public static java.net.InetAddress getLoopbackAddress();
     method public boolean isAnyLocalAddress();
@@ -61367,12 +61775,12 @@
   public class InetSocketAddress extends java.net.SocketAddress {
     ctor public InetSocketAddress(int);
     ctor public InetSocketAddress(java.net.InetAddress, int);
-    ctor public InetSocketAddress(java.lang.String, int);
-    method public static java.net.InetSocketAddress createUnresolved(java.lang.String, int);
-    method public final boolean equals(java.lang.Object);
+    ctor public InetSocketAddress(String, int);
+    method public static java.net.InetSocketAddress createUnresolved(String, int);
+    method public final boolean equals(Object);
     method public final java.net.InetAddress getAddress();
-    method public final java.lang.String getHostName();
-    method public final java.lang.String getHostString();
+    method public final String getHostName();
+    method public final String getHostString();
     method public final int getPort();
     method public final int hashCode();
     method public final boolean isUnresolved();
@@ -61388,7 +61796,7 @@
     ctor protected JarURLConnection(java.net.URL) throws java.net.MalformedURLException;
     method public java.util.jar.Attributes getAttributes() throws java.io.IOException;
     method public java.security.cert.Certificate[] getCertificates() throws java.io.IOException;
-    method public java.lang.String getEntryName();
+    method public String getEntryName();
     method public java.util.jar.JarEntry getJarEntry() throws java.io.IOException;
     method public abstract java.util.jar.JarFile getJarFile() throws java.io.IOException;
     method public java.net.URL getJarFileURL();
@@ -61399,7 +61807,7 @@
 
   public class MalformedURLException extends java.io.IOException {
     ctor public MalformedURLException();
-    ctor public MalformedURLException(java.lang.String);
+    ctor public MalformedURLException(String);
   }
 
   public class MulticastSocket extends java.net.DatagramSocket {
@@ -61409,36 +61817,36 @@
     method public java.net.InetAddress getInterface() throws java.net.SocketException;
     method public boolean getLoopbackMode() throws java.net.SocketException;
     method public java.net.NetworkInterface getNetworkInterface() throws java.net.SocketException;
-    method public deprecated byte getTTL() throws java.io.IOException;
+    method @Deprecated public byte getTTL() throws java.io.IOException;
     method public int getTimeToLive() throws java.io.IOException;
     method public void joinGroup(java.net.InetAddress) throws java.io.IOException;
     method public void joinGroup(java.net.SocketAddress, java.net.NetworkInterface) throws java.io.IOException;
     method public void leaveGroup(java.net.InetAddress) throws java.io.IOException;
     method public void leaveGroup(java.net.SocketAddress, java.net.NetworkInterface) throws java.io.IOException;
-    method public deprecated void send(java.net.DatagramPacket, byte) throws java.io.IOException;
+    method @Deprecated public void send(java.net.DatagramPacket, byte) throws java.io.IOException;
     method public void setInterface(java.net.InetAddress) throws java.net.SocketException;
     method public void setLoopbackMode(boolean) throws java.net.SocketException;
     method public void setNetworkInterface(java.net.NetworkInterface) throws java.net.SocketException;
-    method public deprecated void setTTL(byte) throws java.io.IOException;
+    method @Deprecated public void setTTL(byte) throws java.io.IOException;
     method public void setTimeToLive(int) throws java.io.IOException;
   }
 
   public final class NetPermission extends java.security.BasicPermission {
-    ctor public NetPermission(java.lang.String);
-    ctor public NetPermission(java.lang.String, java.lang.String);
+    ctor public NetPermission(String);
+    ctor public NetPermission(String, String);
   }
 
   public final class NetworkInterface {
     method public static java.net.NetworkInterface getByIndex(int) throws java.net.SocketException;
     method public static java.net.NetworkInterface getByInetAddress(java.net.InetAddress) throws java.net.SocketException;
-    method public static java.net.NetworkInterface getByName(java.lang.String) throws java.net.SocketException;
-    method public java.lang.String getDisplayName();
+    method public static java.net.NetworkInterface getByName(String) throws java.net.SocketException;
+    method public String getDisplayName();
     method public byte[] getHardwareAddress() throws java.net.SocketException;
     method public int getIndex();
     method public java.util.Enumeration<java.net.InetAddress> getInetAddresses();
     method public java.util.List<java.net.InterfaceAddress> getInterfaceAddresses();
     method public int getMTU() throws java.net.SocketException;
-    method public java.lang.String getName();
+    method public String getName();
     method public static java.util.Enumeration<java.net.NetworkInterface> getNetworkInterfaces() throws java.net.SocketException;
     method public java.net.NetworkInterface getParent();
     method public java.util.Enumeration<java.net.NetworkInterface> getSubInterfaces();
@@ -61450,42 +61858,40 @@
   }
 
   public class NoRouteToHostException extends java.net.SocketException {
-    ctor public NoRouteToHostException(java.lang.String);
+    ctor public NoRouteToHostException(String);
     ctor public NoRouteToHostException();
   }
 
   public final class PasswordAuthentication {
-    ctor public PasswordAuthentication(java.lang.String, char[]);
+    ctor public PasswordAuthentication(String, char[]);
     method public char[] getPassword();
-    method public java.lang.String getUserName();
+    method public String getUserName();
   }
 
   public class PortUnreachableException extends java.net.SocketException {
-    ctor public PortUnreachableException(java.lang.String);
+    ctor public PortUnreachableException(String);
     ctor public PortUnreachableException();
   }
 
   public class ProtocolException extends java.io.IOException {
-    ctor public ProtocolException(java.lang.String);
+    ctor public ProtocolException(String);
     ctor public ProtocolException();
   }
 
-  public abstract interface ProtocolFamily {
-    method public abstract java.lang.String name();
+  public interface ProtocolFamily {
+    method public String name();
   }
 
   public class Proxy {
     ctor public Proxy(java.net.Proxy.Type, java.net.SocketAddress);
     method public java.net.SocketAddress address();
-    method public final boolean equals(java.lang.Object);
+    method public final boolean equals(Object);
     method public final int hashCode();
     method public java.net.Proxy.Type type();
     field public static final java.net.Proxy NO_PROXY;
   }
 
-  public static final class Proxy.Type extends java.lang.Enum {
-    method public static java.net.Proxy.Type valueOf(java.lang.String);
-    method public static final java.net.Proxy.Type[] values();
+  public enum Proxy.Type {
     enum_constant public static final java.net.Proxy.Type DIRECT;
     enum_constant public static final java.net.Proxy.Type HTTP;
     enum_constant public static final java.net.Proxy.Type SOCKS;
@@ -61501,15 +61907,15 @@
 
   public abstract class ResponseCache {
     ctor public ResponseCache();
-    method public abstract java.net.CacheResponse get(java.net.URI, java.lang.String, java.util.Map<java.lang.String, java.util.List<java.lang.String>>) throws java.io.IOException;
-    method public static synchronized java.net.ResponseCache getDefault();
+    method public abstract java.net.CacheResponse get(java.net.URI, String, java.util.Map<java.lang.String,java.util.List<java.lang.String>>) throws java.io.IOException;
+    method public static java.net.ResponseCache getDefault();
     method public abstract java.net.CacheRequest put(java.net.URI, java.net.URLConnection) throws java.io.IOException;
-    method public static synchronized void setDefault(java.net.ResponseCache);
+    method public static void setDefault(java.net.ResponseCache);
   }
 
   public abstract class SecureCacheResponse extends java.net.CacheResponse {
     ctor public SecureCacheResponse();
-    method public abstract java.lang.String getCipherSuite();
+    method public abstract String getCipherSuite();
     method public abstract java.util.List<java.security.cert.Certificate> getLocalCertificateChain();
     method public abstract java.security.Principal getLocalPrincipal();
     method public abstract java.security.Principal getPeerPrincipal() throws javax.net.ssl.SSLPeerUnverifiedException;
@@ -61529,31 +61935,31 @@
     method public java.net.InetAddress getInetAddress();
     method public int getLocalPort();
     method public java.net.SocketAddress getLocalSocketAddress();
-    method public synchronized int getReceiveBufferSize() throws java.net.SocketException;
+    method public int getReceiveBufferSize() throws java.net.SocketException;
     method public boolean getReuseAddress() throws java.net.SocketException;
-    method public synchronized int getSoTimeout() throws java.io.IOException;
+    method public int getSoTimeout() throws java.io.IOException;
     method protected final void implAccept(java.net.Socket) throws java.io.IOException;
     method public boolean isBound();
     method public boolean isClosed();
     method public void setPerformancePreferences(int, int, int);
-    method public synchronized void setReceiveBufferSize(int) throws java.net.SocketException;
+    method public void setReceiveBufferSize(int) throws java.net.SocketException;
     method public void setReuseAddress(boolean) throws java.net.SocketException;
-    method public synchronized void setSoTimeout(int) throws java.net.SocketException;
-    method public static synchronized void setSocketFactory(java.net.SocketImplFactory) throws java.io.IOException;
+    method public void setSoTimeout(int) throws java.net.SocketException;
+    method public static void setSocketFactory(java.net.SocketImplFactory) throws java.io.IOException;
   }
 
   public class Socket implements java.io.Closeable {
     ctor public Socket();
     ctor public Socket(java.net.Proxy);
     ctor protected Socket(java.net.SocketImpl) throws java.net.SocketException;
-    ctor public Socket(java.lang.String, int) throws java.io.IOException, java.net.UnknownHostException;
+    ctor public Socket(String, int) throws java.io.IOException, java.net.UnknownHostException;
     ctor public Socket(java.net.InetAddress, int) throws java.io.IOException;
-    ctor public Socket(java.lang.String, int, java.net.InetAddress, int) throws java.io.IOException;
+    ctor public Socket(String, int, java.net.InetAddress, int) throws java.io.IOException;
     ctor public Socket(java.net.InetAddress, int, java.net.InetAddress, int) throws java.io.IOException;
-    ctor public deprecated Socket(java.lang.String, int, boolean) throws java.io.IOException;
-    ctor public deprecated Socket(java.net.InetAddress, int, boolean) throws java.io.IOException;
+    ctor @Deprecated public Socket(String, int, boolean) throws java.io.IOException;
+    ctor @Deprecated public Socket(java.net.InetAddress, int, boolean) throws java.io.IOException;
     method public void bind(java.net.SocketAddress) throws java.io.IOException;
-    method public synchronized void close() throws java.io.IOException;
+    method public void close() throws java.io.IOException;
     method public void connect(java.net.SocketAddress) throws java.io.IOException;
     method public void connect(java.net.SocketAddress, int) throws java.io.IOException;
     method public java.nio.channels.SocketChannel getChannel();
@@ -61566,12 +61972,12 @@
     method public boolean getOOBInline() throws java.net.SocketException;
     method public java.io.OutputStream getOutputStream() throws java.io.IOException;
     method public int getPort();
-    method public synchronized int getReceiveBufferSize() throws java.net.SocketException;
+    method public int getReceiveBufferSize() throws java.net.SocketException;
     method public java.net.SocketAddress getRemoteSocketAddress();
     method public boolean getReuseAddress() throws java.net.SocketException;
-    method public synchronized int getSendBufferSize() throws java.net.SocketException;
+    method public int getSendBufferSize() throws java.net.SocketException;
     method public int getSoLinger() throws java.net.SocketException;
-    method public synchronized int getSoTimeout() throws java.net.SocketException;
+    method public int getSoTimeout() throws java.net.SocketException;
     method public boolean getTcpNoDelay() throws java.net.SocketException;
     method public int getTrafficClass() throws java.net.SocketException;
     method public boolean isBound();
@@ -61583,12 +61989,12 @@
     method public void setKeepAlive(boolean) throws java.net.SocketException;
     method public void setOOBInline(boolean) throws java.net.SocketException;
     method public void setPerformancePreferences(int, int, int);
-    method public synchronized void setReceiveBufferSize(int) throws java.net.SocketException;
+    method public void setReceiveBufferSize(int) throws java.net.SocketException;
     method public void setReuseAddress(boolean) throws java.net.SocketException;
-    method public synchronized void setSendBufferSize(int) throws java.net.SocketException;
+    method public void setSendBufferSize(int) throws java.net.SocketException;
     method public void setSoLinger(boolean, int) throws java.net.SocketException;
-    method public synchronized void setSoTimeout(int) throws java.net.SocketException;
-    method public static synchronized void setSocketImplFactory(java.net.SocketImplFactory) throws java.io.IOException;
+    method public void setSoTimeout(int) throws java.net.SocketException;
+    method public static void setSocketImplFactory(java.net.SocketImplFactory) throws java.io.IOException;
     method public void setTcpNoDelay(boolean) throws java.net.SocketException;
     method public void setTrafficClass(int) throws java.net.SocketException;
     method public void shutdownInput() throws java.io.IOException;
@@ -61600,7 +62006,7 @@
   }
 
   public class SocketException extends java.io.IOException {
-    ctor public SocketException(java.lang.String);
+    ctor public SocketException(String);
     ctor public SocketException();
   }
 
@@ -61610,7 +62016,7 @@
     method protected abstract int available() throws java.io.IOException;
     method protected abstract void bind(java.net.InetAddress, int) throws java.io.IOException;
     method protected abstract void close() throws java.io.IOException;
-    method protected abstract void connect(java.lang.String, int) throws java.io.IOException;
+    method protected abstract void connect(String, int) throws java.io.IOException;
     method protected abstract void connect(java.net.InetAddress, int) throws java.io.IOException;
     method protected abstract void connect(java.net.SocketAddress, int) throws java.io.IOException;
     method protected abstract void create(boolean) throws java.io.IOException;
@@ -61632,18 +62038,18 @@
     field protected int port;
   }
 
-  public abstract interface SocketImplFactory {
-    method public abstract java.net.SocketImpl createSocketImpl();
+  public interface SocketImplFactory {
+    method public java.net.SocketImpl createSocketImpl();
   }
 
-  public abstract interface SocketOption<T> {
-    method public abstract java.lang.String name();
-    method public abstract java.lang.Class<T> type();
+  public interface SocketOption<T> {
+    method public String name();
+    method public Class<T> type();
   }
 
-  public abstract interface SocketOptions {
-    method public abstract java.lang.Object getOption(int) throws java.net.SocketException;
-    method public abstract void setOption(int, java.lang.Object) throws java.net.SocketException;
+  public interface SocketOptions {
+    method public Object getOption(int) throws java.net.SocketException;
+    method public void setOption(int, Object) throws java.net.SocketException;
     field public static final int IP_MULTICAST_IF = 16; // 0x10
     field public static final int IP_MULTICAST_IF2 = 31; // 0x1f
     field public static final int IP_MULTICAST_LOOP = 18; // 0x12
@@ -61661,19 +62067,17 @@
   }
 
   public final class SocketPermission extends java.security.Permission implements java.io.Serializable {
-    ctor public SocketPermission(java.lang.String, java.lang.String);
-    method public java.lang.String getActions();
+    ctor public SocketPermission(String, String);
+    method public String getActions();
     method public boolean implies(java.security.Permission);
   }
 
   public class SocketTimeoutException extends java.io.InterruptedIOException {
-    ctor public SocketTimeoutException(java.lang.String);
+    ctor public SocketTimeoutException(String);
     ctor public SocketTimeoutException();
   }
 
-  public final class StandardProtocolFamily extends java.lang.Enum implements java.net.ProtocolFamily {
-    method public static java.net.StandardProtocolFamily valueOf(java.lang.String);
-    method public static final java.net.StandardProtocolFamily[] values();
+  public enum StandardProtocolFamily implements java.net.ProtocolFamily {
     enum_constant public static final java.net.StandardProtocolFamily INET;
     enum_constant public static final java.net.StandardProtocolFamily INET6;
   }
@@ -61692,142 +62096,141 @@
     field public static final java.net.SocketOption<java.lang.Boolean> TCP_NODELAY;
   }
 
-  public final class URI implements java.lang.Comparable java.io.Serializable {
-    ctor public URI(java.lang.String) throws java.net.URISyntaxException;
-    ctor public URI(java.lang.String, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String) throws java.net.URISyntaxException;
-    ctor public URI(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws java.net.URISyntaxException;
-    ctor public URI(java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws java.net.URISyntaxException;
-    ctor public URI(java.lang.String, java.lang.String, java.lang.String) throws java.net.URISyntaxException;
+  public final class URI implements java.lang.Comparable<java.net.URI> java.io.Serializable {
+    ctor public URI(String) throws java.net.URISyntaxException;
+    ctor public URI(String, String, String, int, String, String, String) throws java.net.URISyntaxException;
+    ctor public URI(String, String, String, String, String) throws java.net.URISyntaxException;
+    ctor public URI(String, String, String, String) throws java.net.URISyntaxException;
+    ctor public URI(String, String, String) throws java.net.URISyntaxException;
     method public int compareTo(java.net.URI);
-    method public static java.net.URI create(java.lang.String);
-    method public java.lang.String getAuthority();
-    method public java.lang.String getFragment();
-    method public java.lang.String getHost();
-    method public java.lang.String getPath();
+    method public static java.net.URI create(String);
+    method public String getAuthority();
+    method public String getFragment();
+    method public String getHost();
+    method public String getPath();
     method public int getPort();
-    method public java.lang.String getQuery();
-    method public java.lang.String getRawAuthority();
-    method public java.lang.String getRawFragment();
-    method public java.lang.String getRawPath();
-    method public java.lang.String getRawQuery();
-    method public java.lang.String getRawSchemeSpecificPart();
-    method public java.lang.String getRawUserInfo();
-    method public java.lang.String getScheme();
-    method public java.lang.String getSchemeSpecificPart();
-    method public java.lang.String getUserInfo();
+    method public String getQuery();
+    method public String getRawAuthority();
+    method public String getRawFragment();
+    method public String getRawPath();
+    method public String getRawQuery();
+    method public String getRawSchemeSpecificPart();
+    method public String getRawUserInfo();
+    method public String getScheme();
+    method public String getSchemeSpecificPart();
+    method public String getUserInfo();
     method public boolean isAbsolute();
     method public boolean isOpaque();
     method public java.net.URI normalize();
     method public java.net.URI parseServerAuthority() throws java.net.URISyntaxException;
     method public java.net.URI relativize(java.net.URI);
     method public java.net.URI resolve(java.net.URI);
-    method public java.net.URI resolve(java.lang.String);
-    method public java.lang.String toASCIIString();
+    method public java.net.URI resolve(String);
+    method public String toASCIIString();
     method public java.net.URL toURL() throws java.net.MalformedURLException;
   }
 
   public class URISyntaxException extends java.lang.Exception {
-    ctor public URISyntaxException(java.lang.String, java.lang.String, int);
-    ctor public URISyntaxException(java.lang.String, java.lang.String);
+    ctor public URISyntaxException(String, String, int);
+    ctor public URISyntaxException(String, String);
     method public int getIndex();
-    method public java.lang.String getInput();
-    method public java.lang.String getReason();
+    method public String getInput();
+    method public String getReason();
   }
 
   public final class URL implements java.io.Serializable {
-    ctor public URL(java.lang.String, java.lang.String, int, java.lang.String) throws java.net.MalformedURLException;
-    ctor public URL(java.lang.String, java.lang.String, java.lang.String) throws java.net.MalformedURLException;
-    ctor public URL(java.lang.String, java.lang.String, int, java.lang.String, java.net.URLStreamHandler) throws java.net.MalformedURLException;
-    ctor public URL(java.lang.String) throws java.net.MalformedURLException;
-    ctor public URL(java.net.URL, java.lang.String) throws java.net.MalformedURLException;
-    ctor public URL(java.net.URL, java.lang.String, java.net.URLStreamHandler) throws java.net.MalformedURLException;
-    method public java.lang.String getAuthority();
-    method public java.lang.Object getContent() throws java.io.IOException;
-    method public java.lang.Object getContent(java.lang.Class[]) throws java.io.IOException;
+    ctor public URL(String, String, int, String) throws java.net.MalformedURLException;
+    ctor public URL(String, String, String) throws java.net.MalformedURLException;
+    ctor public URL(String, String, int, String, java.net.URLStreamHandler) throws java.net.MalformedURLException;
+    ctor public URL(String) throws java.net.MalformedURLException;
+    ctor public URL(java.net.URL, String) throws java.net.MalformedURLException;
+    ctor public URL(java.net.URL, String, java.net.URLStreamHandler) throws java.net.MalformedURLException;
+    method public String getAuthority();
+    method public Object getContent() throws java.io.IOException;
+    method public Object getContent(Class[]) throws java.io.IOException;
     method public int getDefaultPort();
-    method public java.lang.String getFile();
-    method public java.lang.String getHost();
-    method public java.lang.String getPath();
+    method public String getFile();
+    method public String getHost();
+    method public String getPath();
     method public int getPort();
-    method public java.lang.String getProtocol();
-    method public java.lang.String getQuery();
-    method public java.lang.String getRef();
-    method public java.lang.String getUserInfo();
-    method public synchronized int hashCode();
+    method public String getProtocol();
+    method public String getQuery();
+    method public String getRef();
+    method public String getUserInfo();
     method public java.net.URLConnection openConnection() throws java.io.IOException;
     method public java.net.URLConnection openConnection(java.net.Proxy) throws java.io.IOException;
     method public java.io.InputStream openStream() throws java.io.IOException;
     method public boolean sameFile(java.net.URL);
     method public static void setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory);
-    method public java.lang.String toExternalForm();
+    method public String toExternalForm();
     method public java.net.URI toURI() throws java.net.URISyntaxException;
   }
 
   public class URLClassLoader extends java.security.SecureClassLoader implements java.io.Closeable {
-    ctor public URLClassLoader(java.net.URL[], java.lang.ClassLoader);
+    ctor public URLClassLoader(java.net.URL[], ClassLoader);
     ctor public URLClassLoader(java.net.URL[]);
-    ctor public URLClassLoader(java.net.URL[], java.lang.ClassLoader, java.net.URLStreamHandlerFactory);
+    ctor public URLClassLoader(java.net.URL[], ClassLoader, java.net.URLStreamHandlerFactory);
     method protected void addURL(java.net.URL);
     method public void close() throws java.io.IOException;
-    method protected java.lang.Package definePackage(java.lang.String, java.util.jar.Manifest, java.net.URL) throws java.lang.IllegalArgumentException;
-    method public java.net.URL findResource(java.lang.String);
-    method public java.util.Enumeration<java.net.URL> findResources(java.lang.String) throws java.io.IOException;
+    method protected Package definePackage(String, java.util.jar.Manifest, java.net.URL) throws java.lang.IllegalArgumentException;
+    method public java.net.URL findResource(String);
+    method public java.util.Enumeration<java.net.URL> findResources(String) throws java.io.IOException;
     method public java.net.URL[] getURLs();
-    method public static java.net.URLClassLoader newInstance(java.net.URL[], java.lang.ClassLoader);
+    method public static java.net.URLClassLoader newInstance(java.net.URL[], ClassLoader);
     method public static java.net.URLClassLoader newInstance(java.net.URL[]);
   }
 
   public abstract class URLConnection {
     ctor protected URLConnection(java.net.URL);
-    method public void addRequestProperty(java.lang.String, java.lang.String);
+    method public void addRequestProperty(String, String);
     method public abstract void connect() throws java.io.IOException;
     method public boolean getAllowUserInteraction();
     method public int getConnectTimeout();
-    method public java.lang.Object getContent() throws java.io.IOException;
-    method public java.lang.Object getContent(java.lang.Class[]) throws java.io.IOException;
-    method public java.lang.String getContentEncoding();
+    method public Object getContent() throws java.io.IOException;
+    method public Object getContent(Class[]) throws java.io.IOException;
+    method public String getContentEncoding();
     method public int getContentLength();
     method public long getContentLengthLong();
-    method public java.lang.String getContentType();
+    method public String getContentType();
     method public long getDate();
     method public static boolean getDefaultAllowUserInteraction();
-    method public static deprecated java.lang.String getDefaultRequestProperty(java.lang.String);
+    method @Deprecated public static String getDefaultRequestProperty(String);
     method public boolean getDefaultUseCaches();
     method public boolean getDoInput();
     method public boolean getDoOutput();
     method public long getExpiration();
-    method public static synchronized java.net.FileNameMap getFileNameMap();
-    method public java.lang.String getHeaderField(java.lang.String);
-    method public java.lang.String getHeaderField(int);
-    method public long getHeaderFieldDate(java.lang.String, long);
-    method public int getHeaderFieldInt(java.lang.String, int);
-    method public java.lang.String getHeaderFieldKey(int);
-    method public long getHeaderFieldLong(java.lang.String, long);
-    method public java.util.Map<java.lang.String, java.util.List<java.lang.String>> getHeaderFields();
+    method public static java.net.FileNameMap getFileNameMap();
+    method public String getHeaderField(String);
+    method public String getHeaderField(int);
+    method public long getHeaderFieldDate(String, long);
+    method public int getHeaderFieldInt(String, int);
+    method public String getHeaderFieldKey(int);
+    method public long getHeaderFieldLong(String, long);
+    method public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getHeaderFields();
     method public long getIfModifiedSince();
     method public java.io.InputStream getInputStream() throws java.io.IOException;
     method public long getLastModified();
     method public java.io.OutputStream getOutputStream() throws java.io.IOException;
     method public java.security.Permission getPermission() throws java.io.IOException;
     method public int getReadTimeout();
-    method public java.util.Map<java.lang.String, java.util.List<java.lang.String>> getRequestProperties();
-    method public java.lang.String getRequestProperty(java.lang.String);
+    method public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getRequestProperties();
+    method public String getRequestProperty(String);
     method public java.net.URL getURL();
     method public boolean getUseCaches();
-    method public static java.lang.String guessContentTypeFromName(java.lang.String);
-    method public static java.lang.String guessContentTypeFromStream(java.io.InputStream) throws java.io.IOException;
+    method public static String guessContentTypeFromName(String);
+    method public static String guessContentTypeFromStream(java.io.InputStream) throws java.io.IOException;
     method public void setAllowUserInteraction(boolean);
     method public void setConnectTimeout(int);
-    method public static synchronized void setContentHandlerFactory(java.net.ContentHandlerFactory);
+    method public static void setContentHandlerFactory(java.net.ContentHandlerFactory);
     method public static void setDefaultAllowUserInteraction(boolean);
-    method public static deprecated void setDefaultRequestProperty(java.lang.String, java.lang.String);
+    method @Deprecated public static void setDefaultRequestProperty(String, String);
     method public void setDefaultUseCaches(boolean);
     method public void setDoInput(boolean);
     method public void setDoOutput(boolean);
     method public static void setFileNameMap(java.net.FileNameMap);
     method public void setIfModifiedSince(long);
     method public void setReadTimeout(int);
-    method public void setRequestProperty(java.lang.String, java.lang.String);
+    method public void setRequestProperty(String, String);
     method public void setUseCaches(boolean);
     field protected boolean allowUserInteraction;
     field protected boolean connected;
@@ -61840,43 +62243,43 @@
 
   public class URLDecoder {
     ctor public URLDecoder();
-    method public static deprecated java.lang.String decode(java.lang.String);
-    method public static java.lang.String decode(java.lang.String, java.lang.String) throws java.io.UnsupportedEncodingException;
+    method @Deprecated public static String decode(String);
+    method public static String decode(String, String) throws java.io.UnsupportedEncodingException;
   }
 
   public class URLEncoder {
-    method public static deprecated java.lang.String encode(java.lang.String);
-    method public static java.lang.String encode(java.lang.String, java.lang.String) throws java.io.UnsupportedEncodingException;
+    method @Deprecated public static String encode(String);
+    method public static String encode(String, String) throws java.io.UnsupportedEncodingException;
   }
 
   public abstract class URLStreamHandler {
     ctor public URLStreamHandler();
     method protected boolean equals(java.net.URL, java.net.URL);
     method protected int getDefaultPort();
-    method protected synchronized java.net.InetAddress getHostAddress(java.net.URL);
+    method protected java.net.InetAddress getHostAddress(java.net.URL);
     method protected int hashCode(java.net.URL);
     method protected boolean hostsEqual(java.net.URL, java.net.URL);
     method protected abstract java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
     method protected java.net.URLConnection openConnection(java.net.URL, java.net.Proxy) throws java.io.IOException;
-    method protected void parseURL(java.net.URL, java.lang.String, int, int);
+    method protected void parseURL(java.net.URL, String, int, int);
     method protected boolean sameFile(java.net.URL, java.net.URL);
-    method protected void setURL(java.net.URL, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method protected deprecated void setURL(java.net.URL, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String);
-    method protected java.lang.String toExternalForm(java.net.URL);
+    method protected void setURL(java.net.URL, String, String, int, String, String, String, String, String);
+    method @Deprecated protected void setURL(java.net.URL, String, String, int, String, String);
+    method protected String toExternalForm(java.net.URL);
   }
 
-  public abstract interface URLStreamHandlerFactory {
-    method public abstract java.net.URLStreamHandler createURLStreamHandler(java.lang.String);
+  public interface URLStreamHandlerFactory {
+    method public java.net.URLStreamHandler createURLStreamHandler(String);
   }
 
   public class UnknownHostException extends java.io.IOException {
-    ctor public UnknownHostException(java.lang.String);
+    ctor public UnknownHostException(String);
     ctor public UnknownHostException();
   }
 
   public class UnknownServiceException extends java.io.IOException {
     ctor public UnknownServiceException();
-    ctor public UnknownServiceException(java.lang.String);
+    ctor public UnknownServiceException(String);
   }
 
 }
@@ -61884,7 +62287,7 @@
 package java.nio {
 
   public abstract class Buffer {
-    method public abstract java.lang.Object array();
+    method public abstract Object array();
     method public abstract int arrayOffset();
     method public final int capacity();
     method public final java.nio.Buffer clear();
@@ -61911,25 +62314,25 @@
     ctor public BufferUnderflowException();
   }
 
-  public abstract class ByteBuffer extends java.nio.Buffer implements java.lang.Comparable {
-    method public static java.nio.ByteBuffer allocate(int);
-    method public static java.nio.ByteBuffer allocateDirect(int);
+  public abstract class ByteBuffer extends java.nio.Buffer implements java.lang.Comparable<java.nio.ByteBuffer> {
+    method @NonNull public static java.nio.ByteBuffer allocate(int);
+    method @NonNull public static java.nio.ByteBuffer allocateDirect(int);
     method public final byte[] array();
     method public final int arrayOffset();
-    method public abstract java.nio.CharBuffer asCharBuffer();
-    method public abstract java.nio.DoubleBuffer asDoubleBuffer();
-    method public abstract java.nio.FloatBuffer asFloatBuffer();
-    method public abstract java.nio.IntBuffer asIntBuffer();
-    method public abstract java.nio.LongBuffer asLongBuffer();
-    method public abstract java.nio.ByteBuffer asReadOnlyBuffer();
-    method public abstract java.nio.ShortBuffer asShortBuffer();
-    method public abstract java.nio.ByteBuffer compact();
-    method public int compareTo(java.nio.ByteBuffer);
-    method public abstract java.nio.ByteBuffer duplicate();
+    method @NonNull public abstract java.nio.CharBuffer asCharBuffer();
+    method @NonNull public abstract java.nio.DoubleBuffer asDoubleBuffer();
+    method @NonNull public abstract java.nio.FloatBuffer asFloatBuffer();
+    method @NonNull public abstract java.nio.IntBuffer asIntBuffer();
+    method @NonNull public abstract java.nio.LongBuffer asLongBuffer();
+    method @NonNull public abstract java.nio.ByteBuffer asReadOnlyBuffer();
+    method @NonNull public abstract java.nio.ShortBuffer asShortBuffer();
+    method @NonNull public abstract java.nio.ByteBuffer compact();
+    method public int compareTo(@NonNull java.nio.ByteBuffer);
+    method @NonNull public abstract java.nio.ByteBuffer duplicate();
     method public abstract byte get();
     method public abstract byte get(int);
-    method public java.nio.ByteBuffer get(byte[], int, int);
-    method public java.nio.ByteBuffer get(byte[]);
+    method @NonNull public java.nio.ByteBuffer get(byte[], int, int);
+    method @NonNull public java.nio.ByteBuffer get(byte[]);
     method public abstract char getChar();
     method public abstract char getChar(int);
     method public abstract double getDouble();
@@ -61943,28 +62346,28 @@
     method public abstract short getShort();
     method public abstract short getShort(int);
     method public final boolean hasArray();
-    method public final java.nio.ByteOrder order();
-    method public final java.nio.ByteBuffer order(java.nio.ByteOrder);
-    method public abstract java.nio.ByteBuffer put(byte);
-    method public abstract java.nio.ByteBuffer put(int, byte);
-    method public java.nio.ByteBuffer put(java.nio.ByteBuffer);
-    method public java.nio.ByteBuffer put(byte[], int, int);
-    method public final java.nio.ByteBuffer put(byte[]);
-    method public abstract java.nio.ByteBuffer putChar(char);
-    method public abstract java.nio.ByteBuffer putChar(int, char);
-    method public abstract java.nio.ByteBuffer putDouble(double);
-    method public abstract java.nio.ByteBuffer putDouble(int, double);
-    method public abstract java.nio.ByteBuffer putFloat(float);
-    method public abstract java.nio.ByteBuffer putFloat(int, float);
-    method public abstract java.nio.ByteBuffer putInt(int);
-    method public abstract java.nio.ByteBuffer putInt(int, int);
-    method public abstract java.nio.ByteBuffer putLong(long);
-    method public abstract java.nio.ByteBuffer putLong(int, long);
-    method public abstract java.nio.ByteBuffer putShort(short);
-    method public abstract java.nio.ByteBuffer putShort(int, short);
-    method public abstract java.nio.ByteBuffer slice();
-    method public static java.nio.ByteBuffer wrap(byte[], int, int);
-    method public static java.nio.ByteBuffer wrap(byte[]);
+    method @NonNull public final java.nio.ByteOrder order();
+    method @NonNull public final java.nio.ByteBuffer order(@NonNull java.nio.ByteOrder);
+    method @NonNull public abstract java.nio.ByteBuffer put(byte);
+    method @NonNull public abstract java.nio.ByteBuffer put(int, byte);
+    method @NonNull public java.nio.ByteBuffer put(@NonNull java.nio.ByteBuffer);
+    method @NonNull public java.nio.ByteBuffer put(byte[], int, int);
+    method @NonNull public final java.nio.ByteBuffer put(byte[]);
+    method @NonNull public abstract java.nio.ByteBuffer putChar(char);
+    method @NonNull public abstract java.nio.ByteBuffer putChar(int, char);
+    method @NonNull public abstract java.nio.ByteBuffer putDouble(double);
+    method @NonNull public abstract java.nio.ByteBuffer putDouble(int, double);
+    method @NonNull public abstract java.nio.ByteBuffer putFloat(float);
+    method @NonNull public abstract java.nio.ByteBuffer putFloat(int, float);
+    method @NonNull public abstract java.nio.ByteBuffer putInt(int);
+    method @NonNull public abstract java.nio.ByteBuffer putInt(int, int);
+    method @NonNull public abstract java.nio.ByteBuffer putLong(long);
+    method @NonNull public abstract java.nio.ByteBuffer putLong(int, long);
+    method @NonNull public abstract java.nio.ByteBuffer putShort(short);
+    method @NonNull public abstract java.nio.ByteBuffer putShort(int, short);
+    method @NonNull public abstract java.nio.ByteBuffer slice();
+    method @NonNull public static java.nio.ByteBuffer wrap(byte[], int, int);
+    method @NonNull public static java.nio.ByteBuffer wrap(byte[]);
   }
 
   public final class ByteOrder {
@@ -61973,10 +62376,10 @@
     field public static final java.nio.ByteOrder LITTLE_ENDIAN;
   }
 
-  public abstract class CharBuffer extends java.nio.Buffer implements java.lang.Appendable java.lang.CharSequence java.lang.Comparable java.lang.Readable {
+  public abstract class CharBuffer extends java.nio.Buffer implements java.lang.Appendable java.lang.CharSequence java.lang.Comparable<java.nio.CharBuffer> java.lang.Readable {
     method public static java.nio.CharBuffer allocate(int);
-    method public java.nio.CharBuffer append(java.lang.CharSequence);
-    method public java.nio.CharBuffer append(java.lang.CharSequence, int, int);
+    method public java.nio.CharBuffer append(CharSequence);
+    method public java.nio.CharBuffer append(CharSequence, int, int);
     method public java.nio.CharBuffer append(char);
     method public final char[] array();
     method public final int arrayOffset();
@@ -61997,18 +62400,18 @@
     method public java.nio.CharBuffer put(java.nio.CharBuffer);
     method public java.nio.CharBuffer put(char[], int, int);
     method public final java.nio.CharBuffer put(char[]);
-    method public java.nio.CharBuffer put(java.lang.String, int, int);
-    method public final java.nio.CharBuffer put(java.lang.String);
+    method public java.nio.CharBuffer put(String, int, int);
+    method public final java.nio.CharBuffer put(String);
     method public int read(java.nio.CharBuffer) throws java.io.IOException;
     method public abstract java.nio.CharBuffer slice();
     method public abstract java.nio.CharBuffer subSequence(int, int);
     method public static java.nio.CharBuffer wrap(char[], int, int);
     method public static java.nio.CharBuffer wrap(char[]);
-    method public static java.nio.CharBuffer wrap(java.lang.CharSequence, int, int);
-    method public static java.nio.CharBuffer wrap(java.lang.CharSequence);
+    method public static java.nio.CharBuffer wrap(CharSequence, int, int);
+    method public static java.nio.CharBuffer wrap(CharSequence);
   }
 
-  public abstract class DoubleBuffer extends java.nio.Buffer implements java.lang.Comparable {
+  public abstract class DoubleBuffer extends java.nio.Buffer implements java.lang.Comparable<java.nio.DoubleBuffer> {
     method public static java.nio.DoubleBuffer allocate(int);
     method public final double[] array();
     method public final int arrayOffset();
@@ -62032,7 +62435,7 @@
     method public static java.nio.DoubleBuffer wrap(double[]);
   }
 
-  public abstract class FloatBuffer extends java.nio.Buffer implements java.lang.Comparable {
+  public abstract class FloatBuffer extends java.nio.Buffer implements java.lang.Comparable<java.nio.FloatBuffer> {
     method public static java.nio.FloatBuffer allocate(int);
     method public final float[] array();
     method public final int arrayOffset();
@@ -62056,7 +62459,7 @@
     method public static java.nio.FloatBuffer wrap(float[]);
   }
 
-  public abstract class IntBuffer extends java.nio.Buffer implements java.lang.Comparable {
+  public abstract class IntBuffer extends java.nio.Buffer implements java.lang.Comparable<java.nio.IntBuffer> {
     method public static java.nio.IntBuffer allocate(int);
     method public final int[] array();
     method public final int arrayOffset();
@@ -62084,7 +62487,7 @@
     ctor public InvalidMarkException();
   }
 
-  public abstract class LongBuffer extends java.nio.Buffer implements java.lang.Comparable {
+  public abstract class LongBuffer extends java.nio.Buffer implements java.lang.Comparable<java.nio.LongBuffer> {
     method public static java.nio.LongBuffer allocate(int);
     method public final long[] array();
     method public final int arrayOffset();
@@ -62118,7 +62521,7 @@
     ctor public ReadOnlyBufferException();
   }
 
-  public abstract class ShortBuffer extends java.nio.Buffer implements java.lang.Comparable {
+  public abstract class ShortBuffer extends java.nio.Buffer implements java.lang.Comparable<java.nio.ShortBuffer> {
     method public static java.nio.ShortBuffer allocate(int);
     method public final short[] array();
     method public final int arrayOffset();
@@ -62158,14 +62561,14 @@
     ctor public AlreadyConnectedException();
   }
 
-  public abstract interface AsynchronousByteChannel implements java.nio.channels.AsynchronousChannel {
-    method public abstract <A> void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
-    method public abstract <A> void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
+  public interface AsynchronousByteChannel extends java.nio.channels.AsynchronousChannel {
+    method public <A> void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer,? super A>);
+    method public java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer);
+    method public <A> void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer,? super A>);
+    method public java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer);
   }
 
-  public abstract interface AsynchronousChannel implements java.nio.channels.Channel {
+  public interface AsynchronousChannel extends java.nio.channels.Channel {
   }
 
   public abstract class AsynchronousChannelGroup {
@@ -62188,25 +62591,25 @@
   public abstract class AsynchronousFileChannel implements java.nio.channels.AsynchronousChannel {
     ctor protected AsynchronousFileChannel();
     method public abstract void force(boolean) throws java.io.IOException;
-    method public abstract <A> void lock(long, long, boolean, A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
-    method public final <A> void lock(A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock, ? super A>);
+    method public abstract <A> void lock(long, long, boolean, A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock,? super A>);
+    method public final <A> void lock(A, java.nio.channels.CompletionHandler<java.nio.channels.FileLock,? super A>);
     method public abstract java.util.concurrent.Future<java.nio.channels.FileLock> lock(long, long, boolean);
     method public final java.util.concurrent.Future<java.nio.channels.FileLock> lock();
     method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.util.concurrent.ExecutorService, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public static java.nio.channels.AsynchronousFileChannel open(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract <A> void read(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void read(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer,? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> read(java.nio.ByteBuffer, long);
     method public abstract long size() throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousFileChannel truncate(long) throws java.io.IOException;
     method public abstract java.nio.channels.FileLock tryLock(long, long, boolean) throws java.io.IOException;
     method public final java.nio.channels.FileLock tryLock() throws java.io.IOException;
-    method public abstract <A> void write(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer, long, A, java.nio.channels.CompletionHandler<java.lang.Integer,? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Integer> write(java.nio.ByteBuffer, long);
   }
 
   public abstract class AsynchronousServerSocketChannel implements java.nio.channels.AsynchronousChannel java.nio.channels.NetworkChannel {
     ctor protected AsynchronousServerSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
-    method public abstract <A> void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel, ? super A>);
+    method public abstract <A> void accept(A, java.nio.channels.CompletionHandler<java.nio.channels.AsynchronousSocketChannel,? super A>);
     method public abstract java.util.concurrent.Future<java.nio.channels.AsynchronousSocketChannel> accept();
     method public final java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
@@ -62219,32 +62622,32 @@
   public abstract class AsynchronousSocketChannel implements java.nio.channels.AsynchronousByteChannel java.nio.channels.NetworkChannel {
     ctor protected AsynchronousSocketChannel(java.nio.channels.spi.AsynchronousChannelProvider);
     method public abstract java.nio.channels.AsynchronousSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
-    method public abstract <A> void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void, ? super A>);
+    method public abstract <A> void connect(java.net.SocketAddress, A, java.nio.channels.CompletionHandler<java.lang.Void,? super A>);
     method public abstract java.util.concurrent.Future<java.lang.Void> connect(java.net.SocketAddress);
     method public abstract java.net.SocketAddress getRemoteAddress() throws java.io.IOException;
     method public static java.nio.channels.AsynchronousSocketChannel open(java.nio.channels.AsynchronousChannelGroup) throws java.io.IOException;
     method public static java.nio.channels.AsynchronousSocketChannel open() throws java.io.IOException;
     method public final java.nio.channels.spi.AsynchronousChannelProvider provider();
-    method public abstract <A> void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public final <A> void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public abstract <A> void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
+    method public abstract <A> void read(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer,? super A>);
+    method public final <A> void read(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer,? super A>);
+    method public abstract <A> void read(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long,? super A>);
     method public abstract <T> java.nio.channels.AsynchronousSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousSocketChannel shutdownInput() throws java.io.IOException;
     method public abstract java.nio.channels.AsynchronousSocketChannel shutdownOutput() throws java.io.IOException;
-    method public abstract <A> void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public final <A> void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer, ? super A>);
-    method public abstract <A> void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long, ? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Integer,? super A>);
+    method public final <A> void write(java.nio.ByteBuffer, A, java.nio.channels.CompletionHandler<java.lang.Integer,? super A>);
+    method public abstract <A> void write(java.nio.ByteBuffer[], int, int, long, java.util.concurrent.TimeUnit, A, java.nio.channels.CompletionHandler<java.lang.Long,? super A>);
   }
 
-  public abstract interface ByteChannel implements java.nio.channels.ReadableByteChannel java.nio.channels.WritableByteChannel {
+  public interface ByteChannel extends java.nio.channels.ReadableByteChannel java.nio.channels.WritableByteChannel {
   }
 
   public class CancelledKeyException extends java.lang.IllegalStateException {
     ctor public CancelledKeyException();
   }
 
-  public abstract interface Channel implements java.io.Closeable {
-    method public abstract boolean isOpen();
+  public interface Channel extends java.io.Closeable {
+    method public boolean isOpen();
   }
 
   public final class Channels {
@@ -62255,9 +62658,9 @@
     method public static java.io.OutputStream newOutputStream(java.nio.channels.WritableByteChannel);
     method public static java.io.OutputStream newOutputStream(java.nio.channels.AsynchronousByteChannel);
     method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.nio.charset.CharsetDecoder, int);
-    method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, java.lang.String);
+    method public static java.io.Reader newReader(java.nio.channels.ReadableByteChannel, String);
     method public static java.io.Writer newWriter(java.nio.channels.WritableByteChannel, java.nio.charset.CharsetEncoder, int);
-    method public static java.io.Writer newWriter(java.nio.channels.WritableByteChannel, java.lang.String);
+    method public static java.io.Writer newWriter(java.nio.channels.WritableByteChannel, String);
   }
 
   public class ClosedByInterruptException extends java.nio.channels.AsynchronousCloseException {
@@ -62272,9 +62675,9 @@
     ctor public ClosedSelectorException();
   }
 
-  public abstract interface CompletionHandler<V, A> {
-    method public abstract void completed(V, A);
-    method public abstract void failed(java.lang.Throwable, A);
+  public interface CompletionHandler<V, A> {
+    method public void completed(V, A);
+    method public void failed(Throwable, A);
   }
 
   public class ConnectionPendingException extends java.lang.IllegalStateException {
@@ -62337,16 +62740,16 @@
     method public final long position();
     method public abstract void release() throws java.io.IOException;
     method public final long size();
-    method public final java.lang.String toString();
+    method public final String toString();
   }
 
   public class FileLockInterruptionException extends java.io.IOException {
     ctor public FileLockInterruptionException();
   }
 
-  public abstract interface GatheringByteChannel implements java.nio.channels.WritableByteChannel {
-    method public abstract long write(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
-    method public abstract long write(java.nio.ByteBuffer[]) throws java.io.IOException;
+  public interface GatheringByteChannel extends java.nio.channels.WritableByteChannel {
+    method public long write(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
+    method public long write(java.nio.ByteBuffer[]) throws java.io.IOException;
   }
 
   public class IllegalBlockingModeException extends java.lang.IllegalStateException {
@@ -62365,7 +62768,7 @@
     ctor public InterruptedByTimeoutException();
   }
 
-  public abstract interface InterruptibleChannel implements java.nio.channels.Channel {
+  public interface InterruptibleChannel extends java.nio.channels.Channel {
   }
 
   public abstract class MembershipKey {
@@ -62380,17 +62783,17 @@
     method public abstract java.nio.channels.MembershipKey unblock(java.net.InetAddress);
   }
 
-  public abstract interface MulticastChannel implements java.nio.channels.NetworkChannel {
-    method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
-    method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
+  public interface MulticastChannel extends java.nio.channels.NetworkChannel {
+    method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
+    method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
   }
 
-  public abstract interface NetworkChannel implements java.nio.channels.Channel {
-    method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
-    method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
-    method public abstract <T> T getOption(java.net.SocketOption<T>) throws java.io.IOException;
-    method public abstract <T> java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
-    method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions();
+  public interface NetworkChannel extends java.nio.channels.Channel {
+    method public java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
+    method public java.net.SocketAddress getLocalAddress() throws java.io.IOException;
+    method public <T> T getOption(java.net.SocketOption<T>) throws java.io.IOException;
+    method public <T> java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
+    method public java.util.Set<java.net.SocketOption<?>> supportedOptions();
   }
 
   public class NoConnectionPendingException extends java.lang.IllegalStateException {
@@ -62424,12 +62827,12 @@
     method public abstract java.nio.channels.Pipe.SourceChannel source();
   }
 
-  public static abstract class Pipe.SinkChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.GatheringByteChannel java.nio.channels.WritableByteChannel {
+  public abstract static class Pipe.SinkChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.GatheringByteChannel java.nio.channels.WritableByteChannel {
     ctor protected Pipe.SinkChannel(java.nio.channels.spi.SelectorProvider);
     method public final int validOps();
   }
 
-  public static abstract class Pipe.SourceChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ReadableByteChannel java.nio.channels.ScatteringByteChannel {
+  public abstract static class Pipe.SourceChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ReadableByteChannel java.nio.channels.ScatteringByteChannel {
     ctor protected Pipe.SourceChannel(java.nio.channels.spi.SelectorProvider);
     method public final int validOps();
   }
@@ -62438,39 +62841,39 @@
     ctor public ReadPendingException();
   }
 
-  public abstract interface ReadableByteChannel implements java.nio.channels.Channel {
-    method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
+  public interface ReadableByteChannel extends java.nio.channels.Channel {
+    method public int read(java.nio.ByteBuffer) throws java.io.IOException;
   }
 
-  public abstract interface ScatteringByteChannel implements java.nio.channels.ReadableByteChannel {
-    method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
-    method public abstract long read(java.nio.ByteBuffer[]) throws java.io.IOException;
+  public interface ScatteringByteChannel extends java.nio.channels.ReadableByteChannel {
+    method public long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
+    method public long read(java.nio.ByteBuffer[]) throws java.io.IOException;
   }
 
-  public abstract interface SeekableByteChannel implements java.nio.channels.ByteChannel {
-    method public abstract long position() throws java.io.IOException;
-    method public abstract java.nio.channels.SeekableByteChannel position(long) throws java.io.IOException;
-    method public abstract long size() throws java.io.IOException;
-    method public abstract java.nio.channels.SeekableByteChannel truncate(long) throws java.io.IOException;
+  public interface SeekableByteChannel extends java.nio.channels.ByteChannel {
+    method public long position() throws java.io.IOException;
+    method public java.nio.channels.SeekableByteChannel position(long) throws java.io.IOException;
+    method public long size() throws java.io.IOException;
+    method public java.nio.channels.SeekableByteChannel truncate(long) throws java.io.IOException;
   }
 
   public abstract class SelectableChannel extends java.nio.channels.spi.AbstractInterruptibleChannel implements java.nio.channels.Channel {
     ctor protected SelectableChannel();
-    method public abstract java.lang.Object blockingLock();
+    method public abstract Object blockingLock();
     method public abstract java.nio.channels.SelectableChannel configureBlocking(boolean) throws java.io.IOException;
     method public abstract boolean isBlocking();
     method public abstract boolean isRegistered();
     method public abstract java.nio.channels.SelectionKey keyFor(java.nio.channels.Selector);
     method public abstract java.nio.channels.spi.SelectorProvider provider();
-    method public abstract java.nio.channels.SelectionKey register(java.nio.channels.Selector, int, java.lang.Object) throws java.nio.channels.ClosedChannelException;
+    method public abstract java.nio.channels.SelectionKey register(java.nio.channels.Selector, int, Object) throws java.nio.channels.ClosedChannelException;
     method public final java.nio.channels.SelectionKey register(java.nio.channels.Selector, int) throws java.nio.channels.ClosedChannelException;
     method public abstract int validOps();
   }
 
   public abstract class SelectionKey {
     ctor protected SelectionKey();
-    method public final java.lang.Object attach(java.lang.Object);
-    method public final java.lang.Object attachment();
+    method public final Object attach(Object);
+    method public final Object attachment();
     method public abstract void cancel();
     method public abstract java.nio.channels.SelectableChannel channel();
     method public abstract int interestOps();
@@ -62543,8 +62946,8 @@
     ctor public UnsupportedAddressTypeException();
   }
 
-  public abstract interface WritableByteChannel implements java.nio.channels.Channel {
-    method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
+  public interface WritableByteChannel extends java.nio.channels.Channel {
+    method public int write(java.nio.ByteBuffer) throws java.io.IOException;
   }
 
   public class WritePendingException extends java.lang.IllegalStateException {
@@ -62566,7 +62969,7 @@
 
   public abstract class AbstractSelectableChannel extends java.nio.channels.SelectableChannel {
     ctor protected AbstractSelectableChannel(java.nio.channels.spi.SelectorProvider);
-    method public final java.lang.Object blockingLock();
+    method public final Object blockingLock();
     method public final java.nio.channels.SelectableChannel configureBlocking(boolean) throws java.io.IOException;
     method protected final void implCloseChannel() throws java.io.IOException;
     method protected abstract void implCloseSelectableChannel() throws java.io.IOException;
@@ -62575,7 +62978,7 @@
     method public final boolean isRegistered();
     method public final java.nio.channels.SelectionKey keyFor(java.nio.channels.Selector);
     method public final java.nio.channels.spi.SelectorProvider provider();
-    method public final java.nio.channels.SelectionKey register(java.nio.channels.Selector, int, java.lang.Object) throws java.nio.channels.ClosedChannelException;
+    method public final java.nio.channels.SelectionKey register(java.nio.channels.Selector, int, Object) throws java.nio.channels.ClosedChannelException;
   }
 
   public abstract class AbstractSelectionKey extends java.nio.channels.SelectionKey {
@@ -62594,7 +62997,7 @@
     method protected abstract void implCloseSelector() throws java.io.IOException;
     method public final boolean isOpen();
     method public final java.nio.channels.spi.SelectorProvider provider();
-    method protected abstract java.nio.channels.SelectionKey register(java.nio.channels.spi.AbstractSelectableChannel, int, java.lang.Object);
+    method protected abstract java.nio.channels.SelectionKey register(java.nio.channels.spi.AbstractSelectableChannel, int, Object);
   }
 
   public abstract class AsynchronousChannelProvider {
@@ -62626,28 +63029,28 @@
     ctor public CharacterCodingException();
   }
 
-  public abstract class Charset implements java.lang.Comparable {
-    ctor protected Charset(java.lang.String, java.lang.String[]);
+  public abstract class Charset implements java.lang.Comparable<java.nio.charset.Charset> {
+    ctor protected Charset(String, String[]);
     method public final java.util.Set<java.lang.String> aliases();
-    method public static java.util.SortedMap<java.lang.String, java.nio.charset.Charset> availableCharsets();
+    method public static java.util.SortedMap<java.lang.String,java.nio.charset.Charset> availableCharsets();
     method public boolean canEncode();
     method public final int compareTo(java.nio.charset.Charset);
     method public abstract boolean contains(java.nio.charset.Charset);
     method public final java.nio.CharBuffer decode(java.nio.ByteBuffer);
     method public static java.nio.charset.Charset defaultCharset();
-    method public java.lang.String displayName();
-    method public java.lang.String displayName(java.util.Locale);
+    method public String displayName();
+    method public String displayName(java.util.Locale);
     method public final java.nio.ByteBuffer encode(java.nio.CharBuffer);
-    method public final java.nio.ByteBuffer encode(java.lang.String);
-    method public final boolean equals(java.lang.Object);
-    method public static java.nio.charset.Charset forName(java.lang.String);
+    method public final java.nio.ByteBuffer encode(String);
+    method public final boolean equals(Object);
+    method public static java.nio.charset.Charset forName(String);
     method public final int hashCode();
     method public final boolean isRegistered();
-    method public static boolean isSupported(java.lang.String);
-    method public final java.lang.String name();
+    method public static boolean isSupported(String);
+    method public final String name();
     method public abstract java.nio.charset.CharsetDecoder newDecoder();
     method public abstract java.nio.charset.CharsetEncoder newEncoder();
-    method public final java.lang.String toString();
+    method public final String toString();
   }
 
   public abstract class CharsetDecoder {
@@ -62662,7 +63065,7 @@
     method protected java.nio.charset.CoderResult implFlush(java.nio.CharBuffer);
     method protected void implOnMalformedInput(java.nio.charset.CodingErrorAction);
     method protected void implOnUnmappableCharacter(java.nio.charset.CodingErrorAction);
-    method protected void implReplaceWith(java.lang.String);
+    method protected void implReplaceWith(String);
     method protected void implReset();
     method public boolean isAutoDetecting();
     method public boolean isCharsetDetected();
@@ -62670,8 +63073,8 @@
     method public final float maxCharsPerByte();
     method public final java.nio.charset.CharsetDecoder onMalformedInput(java.nio.charset.CodingErrorAction);
     method public final java.nio.charset.CharsetDecoder onUnmappableCharacter(java.nio.charset.CodingErrorAction);
-    method public final java.nio.charset.CharsetDecoder replaceWith(java.lang.String);
-    method public final java.lang.String replacement();
+    method public final java.nio.charset.CharsetDecoder replaceWith(String);
+    method public final String replacement();
     method public final java.nio.charset.CharsetDecoder reset();
     method public java.nio.charset.CodingErrorAction unmappableCharacterAction();
   }
@@ -62681,7 +63084,7 @@
     ctor protected CharsetEncoder(java.nio.charset.Charset, float, float);
     method public final float averageBytesPerChar();
     method public boolean canEncode(char);
-    method public boolean canEncode(java.lang.CharSequence);
+    method public boolean canEncode(CharSequence);
     method public final java.nio.charset.Charset charset();
     method public final java.nio.charset.CoderResult encode(java.nio.CharBuffer, java.nio.ByteBuffer, boolean);
     method public final java.nio.ByteBuffer encode(java.nio.CharBuffer) throws java.nio.charset.CharacterCodingException;
@@ -62704,7 +63107,7 @@
   }
 
   public class CoderMalfunctionError extends java.lang.Error {
-    ctor public CoderMalfunctionError(java.lang.Exception);
+    ctor public CoderMalfunctionError(Exception);
   }
 
   public class CoderResult {
@@ -62728,8 +63131,8 @@
   }
 
   public class IllegalCharsetNameException extends java.lang.IllegalArgumentException {
-    ctor public IllegalCharsetNameException(java.lang.String);
-    method public java.lang.String getCharsetName();
+    ctor public IllegalCharsetNameException(String);
+    method public String getCharsetName();
   }
 
   public class MalformedInputException extends java.nio.charset.CharacterCodingException {
@@ -62752,8 +63155,8 @@
   }
 
   public class UnsupportedCharsetException extends java.lang.IllegalArgumentException {
-    ctor public UnsupportedCharsetException(java.lang.String);
-    method public java.lang.String getCharsetName();
+    ctor public UnsupportedCharsetException(String);
+    method public String getCharsetName();
   }
 
 }
@@ -62762,7 +63165,7 @@
 
   public abstract class CharsetProvider {
     ctor protected CharsetProvider();
-    method public abstract java.nio.charset.Charset charsetForName(java.lang.String);
+    method public abstract java.nio.charset.Charset charsetForName(String);
     method public abstract java.util.Iterator<java.nio.charset.Charset> charsets();
   }
 
@@ -62771,20 +63174,18 @@
 package java.nio.file {
 
   public class AccessDeniedException extends java.nio.file.FileSystemException {
-    ctor public AccessDeniedException(java.lang.String);
-    ctor public AccessDeniedException(java.lang.String, java.lang.String, java.lang.String);
+    ctor public AccessDeniedException(String);
+    ctor public AccessDeniedException(String, String, String);
   }
 
-  public final class AccessMode extends java.lang.Enum {
-    method public static java.nio.file.AccessMode valueOf(java.lang.String);
-    method public static final java.nio.file.AccessMode[] values();
+  public enum AccessMode {
     enum_constant public static final java.nio.file.AccessMode EXECUTE;
     enum_constant public static final java.nio.file.AccessMode READ;
     enum_constant public static final java.nio.file.AccessMode WRITE;
   }
 
   public class AtomicMoveNotSupportedException extends java.nio.file.FileSystemException {
-    ctor public AtomicMoveNotSupportedException(java.lang.String, java.lang.String, java.lang.String);
+    ctor public AtomicMoveNotSupportedException(String, String, String);
   }
 
   public class ClosedDirectoryStreamException extends java.lang.IllegalStateException {
@@ -62799,7 +63200,7 @@
     ctor public ClosedWatchServiceException();
   }
 
-  public abstract interface CopyOption {
+  public interface CopyOption {
   }
 
   public final class DirectoryIteratorException extends java.util.ConcurrentModificationException {
@@ -62808,42 +63209,42 @@
   }
 
   public class DirectoryNotEmptyException extends java.nio.file.FileSystemException {
-    ctor public DirectoryNotEmptyException(java.lang.String);
+    ctor public DirectoryNotEmptyException(String);
   }
 
-  public abstract interface DirectoryStream<T> implements java.io.Closeable java.lang.Iterable {
+  public interface DirectoryStream<T> extends java.io.Closeable java.lang.Iterable<T> {
   }
 
-  public static abstract interface DirectoryStream.Filter<T> {
-    method public abstract boolean accept(T) throws java.io.IOException;
+  @java.lang.FunctionalInterface public static interface DirectoryStream.Filter<T> {
+    method public boolean accept(T) throws java.io.IOException;
   }
 
   public class FileAlreadyExistsException extends java.nio.file.FileSystemException {
-    ctor public FileAlreadyExistsException(java.lang.String);
-    ctor public FileAlreadyExistsException(java.lang.String, java.lang.String, java.lang.String);
+    ctor public FileAlreadyExistsException(String);
+    ctor public FileAlreadyExistsException(String, String, String);
   }
 
   public abstract class FileStore {
     ctor protected FileStore();
-    method public abstract java.lang.Object getAttribute(java.lang.String) throws java.io.IOException;
-    method public abstract <V extends java.nio.file.attribute.FileStoreAttributeView> V getFileStoreAttributeView(java.lang.Class<V>);
+    method public abstract Object getAttribute(String) throws java.io.IOException;
+    method public abstract <V extends java.nio.file.attribute.FileStoreAttributeView> V getFileStoreAttributeView(Class<V>);
     method public abstract long getTotalSpace() throws java.io.IOException;
     method public abstract long getUnallocatedSpace() throws java.io.IOException;
     method public abstract long getUsableSpace() throws java.io.IOException;
     method public abstract boolean isReadOnly();
-    method public abstract java.lang.String name();
-    method public abstract boolean supportsFileAttributeView(java.lang.Class<? extends java.nio.file.attribute.FileAttributeView>);
-    method public abstract boolean supportsFileAttributeView(java.lang.String);
-    method public abstract java.lang.String type();
+    method public abstract String name();
+    method public abstract boolean supportsFileAttributeView(Class<? extends java.nio.file.attribute.FileAttributeView>);
+    method public abstract boolean supportsFileAttributeView(String);
+    method public abstract String type();
   }
 
   public abstract class FileSystem implements java.io.Closeable {
     ctor protected FileSystem();
-    method public abstract java.lang.Iterable<java.nio.file.FileStore> getFileStores();
-    method public abstract java.nio.file.Path getPath(java.lang.String, java.lang.String...);
-    method public abstract java.nio.file.PathMatcher getPathMatcher(java.lang.String);
-    method public abstract java.lang.Iterable<java.nio.file.Path> getRootDirectories();
-    method public abstract java.lang.String getSeparator();
+    method public abstract Iterable<java.nio.file.FileStore> getFileStores();
+    method public abstract java.nio.file.Path getPath(String, java.lang.String...);
+    method public abstract java.nio.file.PathMatcher getPathMatcher(String);
+    method public abstract Iterable<java.nio.file.Path> getRootDirectories();
+    method public abstract String getSeparator();
     method public abstract java.nio.file.attribute.UserPrincipalLookupService getUserPrincipalLookupService();
     method public abstract boolean isOpen();
     method public abstract boolean isReadOnly();
@@ -62854,54 +63255,50 @@
 
   public class FileSystemAlreadyExistsException extends java.lang.RuntimeException {
     ctor public FileSystemAlreadyExistsException();
-    ctor public FileSystemAlreadyExistsException(java.lang.String);
+    ctor public FileSystemAlreadyExistsException(String);
   }
 
   public class FileSystemException extends java.io.IOException {
-    ctor public FileSystemException(java.lang.String);
-    ctor public FileSystemException(java.lang.String, java.lang.String, java.lang.String);
-    method public java.lang.String getFile();
-    method public java.lang.String getOtherFile();
-    method public java.lang.String getReason();
+    ctor public FileSystemException(String);
+    ctor public FileSystemException(String, String, String);
+    method public String getFile();
+    method public String getOtherFile();
+    method public String getReason();
   }
 
   public class FileSystemLoopException extends java.nio.file.FileSystemException {
-    ctor public FileSystemLoopException(java.lang.String);
+    ctor public FileSystemLoopException(String);
   }
 
   public class FileSystemNotFoundException extends java.lang.RuntimeException {
     ctor public FileSystemNotFoundException();
-    ctor public FileSystemNotFoundException(java.lang.String);
+    ctor public FileSystemNotFoundException(String);
   }
 
   public final class FileSystems {
     method public static java.nio.file.FileSystem getDefault();
     method public static java.nio.file.FileSystem getFileSystem(java.net.URI);
-    method public static java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
-    method public static java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String, ?>, java.lang.ClassLoader) throws java.io.IOException;
-    method public static java.nio.file.FileSystem newFileSystem(java.nio.file.Path, java.lang.ClassLoader) throws java.io.IOException;
+    method public static java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String,?>) throws java.io.IOException;
+    method public static java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String,?>, ClassLoader) throws java.io.IOException;
+    method public static java.nio.file.FileSystem newFileSystem(java.nio.file.Path, ClassLoader) throws java.io.IOException;
   }
 
-  public final class FileVisitOption extends java.lang.Enum {
-    method public static java.nio.file.FileVisitOption valueOf(java.lang.String);
-    method public static final java.nio.file.FileVisitOption[] values();
+  public enum FileVisitOption {
     enum_constant public static final java.nio.file.FileVisitOption FOLLOW_LINKS;
   }
 
-  public final class FileVisitResult extends java.lang.Enum {
-    method public static java.nio.file.FileVisitResult valueOf(java.lang.String);
-    method public static final java.nio.file.FileVisitResult[] values();
+  public enum FileVisitResult {
     enum_constant public static final java.nio.file.FileVisitResult CONTINUE;
     enum_constant public static final java.nio.file.FileVisitResult SKIP_SIBLINGS;
     enum_constant public static final java.nio.file.FileVisitResult SKIP_SUBTREE;
     enum_constant public static final java.nio.file.FileVisitResult TERMINATE;
   }
 
-  public abstract interface FileVisitor<T> {
-    method public abstract java.nio.file.FileVisitResult postVisitDirectory(T, java.io.IOException) throws java.io.IOException;
-    method public abstract java.nio.file.FileVisitResult preVisitDirectory(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
-    method public abstract java.nio.file.FileVisitResult visitFile(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
-    method public abstract java.nio.file.FileVisitResult visitFileFailed(T, java.io.IOException) throws java.io.IOException;
+  public interface FileVisitor<T> {
+    method public java.nio.file.FileVisitResult postVisitDirectory(T, java.io.IOException) throws java.io.IOException;
+    method public java.nio.file.FileVisitResult preVisitDirectory(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
+    method public java.nio.file.FileVisitResult visitFile(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
+    method public java.nio.file.FileVisitResult visitFileFailed(T, java.io.IOException) throws java.io.IOException;
   }
 
   public final class Files {
@@ -62913,16 +63310,16 @@
     method public static java.nio.file.Path createFile(java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public static java.nio.file.Path createLink(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
     method public static java.nio.file.Path createSymbolicLink(java.nio.file.Path, java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempDirectory(java.nio.file.Path, java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempDirectory(java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempFile(java.nio.file.Path, java.lang.String, java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public static java.nio.file.Path createTempFile(java.lang.String, java.lang.String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
+    method public static java.nio.file.Path createTempDirectory(java.nio.file.Path, String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
+    method public static java.nio.file.Path createTempDirectory(String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
+    method public static java.nio.file.Path createTempFile(java.nio.file.Path, String, String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
+    method public static java.nio.file.Path createTempFile(String, String, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public static void delete(java.nio.file.Path) throws java.io.IOException;
     method public static boolean deleteIfExists(java.nio.file.Path) throws java.io.IOException;
     method public static boolean exists(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static java.util.stream.Stream<java.nio.file.Path> find(java.nio.file.Path, int, java.util.function.BiPredicate<java.nio.file.Path, java.nio.file.attribute.BasicFileAttributes>, java.nio.file.FileVisitOption...) throws java.io.IOException;
-    method public static java.lang.Object getAttribute(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
+    method public static java.util.stream.Stream<java.nio.file.Path> find(java.nio.file.Path, int, java.util.function.BiPredicate<java.nio.file.Path,java.nio.file.attribute.BasicFileAttributes>, java.nio.file.FileVisitOption...) throws java.io.IOException;
+    method public static Object getAttribute(java.nio.file.Path, String, java.nio.file.LinkOption...) throws java.io.IOException;
+    method public static <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.nio.file.Path, Class<V>, java.nio.file.LinkOption...);
     method public static java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
     method public static java.nio.file.attribute.FileTime getLastModifiedTime(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
     method public static java.nio.file.attribute.UserPrincipal getOwner(java.nio.file.Path, java.nio.file.LinkOption...) throws java.io.IOException;
@@ -62946,19 +63343,19 @@
     method public static java.nio.channels.SeekableByteChannel newByteChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public static java.nio.channels.SeekableByteChannel newByteChannel(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
     method public static java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path, java.lang.String) throws java.io.IOException;
+    method public static java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path, String) throws java.io.IOException;
     method public static java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path, java.nio.file.DirectoryStream.Filter<? super java.nio.file.Path>) throws java.io.IOException;
     method public static java.io.InputStream newInputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
     method public static java.io.OutputStream newOutputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
     method public static boolean notExists(java.nio.file.Path, java.nio.file.LinkOption...);
-    method public static java.lang.String probeContentType(java.nio.file.Path) throws java.io.IOException;
+    method public static String probeContentType(java.nio.file.Path) throws java.io.IOException;
     method public static byte[] readAllBytes(java.nio.file.Path) throws java.io.IOException;
     method public static java.util.List<java.lang.String> readAllLines(java.nio.file.Path, java.nio.charset.Charset) throws java.io.IOException;
     method public static java.util.List<java.lang.String> readAllLines(java.nio.file.Path) throws java.io.IOException;
-    method public static <A extends java.nio.file.attribute.BasicFileAttributes> A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public static java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
+    method public static <A extends java.nio.file.attribute.BasicFileAttributes> A readAttributes(java.nio.file.Path, Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
+    method public static java.util.Map<java.lang.String,java.lang.Object> readAttributes(java.nio.file.Path, String, java.nio.file.LinkOption...) throws java.io.IOException;
     method public static java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
-    method public static java.nio.file.Path setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
+    method public static java.nio.file.Path setAttribute(java.nio.file.Path, String, Object, java.nio.file.LinkOption...) throws java.io.IOException;
     method public static java.nio.file.Path setLastModifiedTime(java.nio.file.Path, java.nio.file.attribute.FileTime) throws java.io.IOException;
     method public static java.nio.file.Path setOwner(java.nio.file.Path, java.nio.file.attribute.UserPrincipal) throws java.io.IOException;
     method public static java.nio.file.Path setPosixFilePermissions(java.nio.file.Path, java.util.Set<java.nio.file.attribute.PosixFilePermission>) throws java.io.IOException;
@@ -62968,110 +63365,108 @@
     method public static java.nio.file.Path walkFileTree(java.nio.file.Path, java.util.Set<java.nio.file.FileVisitOption>, int, java.nio.file.FileVisitor<? super java.nio.file.Path>) throws java.io.IOException;
     method public static java.nio.file.Path walkFileTree(java.nio.file.Path, java.nio.file.FileVisitor<? super java.nio.file.Path>) throws java.io.IOException;
     method public static java.nio.file.Path write(java.nio.file.Path, byte[], java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.nio.file.Path write(java.nio.file.Path, java.lang.Iterable<? extends java.lang.CharSequence>, java.nio.charset.Charset, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public static java.nio.file.Path write(java.nio.file.Path, java.lang.Iterable<? extends java.lang.CharSequence>, java.nio.file.OpenOption...) throws java.io.IOException;
+    method public static java.nio.file.Path write(java.nio.file.Path, Iterable<? extends java.lang.CharSequence>, java.nio.charset.Charset, java.nio.file.OpenOption...) throws java.io.IOException;
+    method public static java.nio.file.Path write(java.nio.file.Path, Iterable<? extends java.lang.CharSequence>, java.nio.file.OpenOption...) throws java.io.IOException;
   }
 
   public class InvalidPathException extends java.lang.IllegalArgumentException {
-    ctor public InvalidPathException(java.lang.String, java.lang.String, int);
-    ctor public InvalidPathException(java.lang.String, java.lang.String);
+    ctor public InvalidPathException(String, String, int);
+    ctor public InvalidPathException(String, String);
     method public int getIndex();
-    method public java.lang.String getInput();
-    method public java.lang.String getReason();
+    method public String getInput();
+    method public String getReason();
   }
 
-  public final class LinkOption extends java.lang.Enum implements java.nio.file.CopyOption java.nio.file.OpenOption {
-    method public static java.nio.file.LinkOption valueOf(java.lang.String);
-    method public static final java.nio.file.LinkOption[] values();
+  public enum LinkOption implements java.nio.file.CopyOption java.nio.file.OpenOption {
     enum_constant public static final java.nio.file.LinkOption NOFOLLOW_LINKS;
   }
 
   public final class LinkPermission extends java.security.BasicPermission {
-    ctor public LinkPermission(java.lang.String);
-    ctor public LinkPermission(java.lang.String, java.lang.String);
+    ctor public LinkPermission(String);
+    ctor public LinkPermission(String, String);
   }
 
   public class NoSuchFileException extends java.nio.file.FileSystemException {
-    ctor public NoSuchFileException(java.lang.String);
-    ctor public NoSuchFileException(java.lang.String, java.lang.String, java.lang.String);
+    ctor public NoSuchFileException(String);
+    ctor public NoSuchFileException(String, String, String);
   }
 
   public class NotDirectoryException extends java.nio.file.FileSystemException {
-    ctor public NotDirectoryException(java.lang.String);
+    ctor public NotDirectoryException(String);
   }
 
   public class NotLinkException extends java.nio.file.FileSystemException {
-    ctor public NotLinkException(java.lang.String);
-    ctor public NotLinkException(java.lang.String, java.lang.String, java.lang.String);
+    ctor public NotLinkException(String);
+    ctor public NotLinkException(String, String, String);
   }
 
-  public abstract interface OpenOption {
+  public interface OpenOption {
   }
 
-  public abstract interface Path implements java.lang.Comparable java.lang.Iterable java.nio.file.Watchable {
-    method public abstract int compareTo(java.nio.file.Path);
-    method public abstract boolean endsWith(java.nio.file.Path);
-    method public abstract boolean endsWith(java.lang.String);
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract java.nio.file.Path getFileName();
-    method public abstract java.nio.file.FileSystem getFileSystem();
-    method public abstract java.nio.file.Path getName(int);
-    method public abstract int getNameCount();
-    method public abstract java.nio.file.Path getParent();
-    method public abstract java.nio.file.Path getRoot();
-    method public abstract int hashCode();
-    method public abstract boolean isAbsolute();
-    method public abstract java.util.Iterator<java.nio.file.Path> iterator();
-    method public abstract java.nio.file.Path normalize();
-    method public abstract java.nio.file.Path relativize(java.nio.file.Path);
-    method public abstract java.nio.file.Path resolve(java.nio.file.Path);
-    method public abstract java.nio.file.Path resolve(java.lang.String);
-    method public abstract java.nio.file.Path resolveSibling(java.nio.file.Path);
-    method public abstract java.nio.file.Path resolveSibling(java.lang.String);
-    method public abstract boolean startsWith(java.nio.file.Path);
-    method public abstract boolean startsWith(java.lang.String);
-    method public abstract java.nio.file.Path subpath(int, int);
-    method public abstract java.nio.file.Path toAbsolutePath();
-    method public abstract java.io.File toFile();
-    method public abstract java.nio.file.Path toRealPath(java.nio.file.LinkOption...) throws java.io.IOException;
-    method public abstract java.lang.String toString();
-    method public abstract java.net.URI toUri();
+  public interface Path extends java.lang.Comparable<java.nio.file.Path> java.lang.Iterable<java.nio.file.Path> java.nio.file.Watchable {
+    method public int compareTo(java.nio.file.Path);
+    method public boolean endsWith(java.nio.file.Path);
+    method public boolean endsWith(String);
+    method public boolean equals(Object);
+    method public java.nio.file.Path getFileName();
+    method public java.nio.file.FileSystem getFileSystem();
+    method public java.nio.file.Path getName(int);
+    method public int getNameCount();
+    method public java.nio.file.Path getParent();
+    method public java.nio.file.Path getRoot();
+    method public int hashCode();
+    method public boolean isAbsolute();
+    method public java.util.Iterator<java.nio.file.Path> iterator();
+    method public java.nio.file.Path normalize();
+    method public java.nio.file.Path relativize(java.nio.file.Path);
+    method public java.nio.file.Path resolve(java.nio.file.Path);
+    method public java.nio.file.Path resolve(String);
+    method public java.nio.file.Path resolveSibling(java.nio.file.Path);
+    method public java.nio.file.Path resolveSibling(String);
+    method public boolean startsWith(java.nio.file.Path);
+    method public boolean startsWith(String);
+    method public java.nio.file.Path subpath(int, int);
+    method public java.nio.file.Path toAbsolutePath();
+    method public java.io.File toFile();
+    method public java.nio.file.Path toRealPath(java.nio.file.LinkOption...) throws java.io.IOException;
+    method public String toString();
+    method public java.net.URI toUri();
   }
 
-  public abstract interface PathMatcher {
-    method public abstract boolean matches(java.nio.file.Path);
+  @java.lang.FunctionalInterface public interface PathMatcher {
+    method public boolean matches(java.nio.file.Path);
   }
 
   public final class Paths {
-    method public static java.nio.file.Path get(java.lang.String, java.lang.String...);
+    method public static java.nio.file.Path get(String, java.lang.String...);
     method public static java.nio.file.Path get(java.net.URI);
   }
 
   public class ProviderMismatchException extends java.lang.IllegalArgumentException {
     ctor public ProviderMismatchException();
-    ctor public ProviderMismatchException(java.lang.String);
+    ctor public ProviderMismatchException(String);
   }
 
   public class ProviderNotFoundException extends java.lang.RuntimeException {
     ctor public ProviderNotFoundException();
-    ctor public ProviderNotFoundException(java.lang.String);
+    ctor public ProviderNotFoundException(String);
   }
 
   public class ReadOnlyFileSystemException extends java.lang.UnsupportedOperationException {
     ctor public ReadOnlyFileSystemException();
   }
 
-  public abstract interface SecureDirectoryStream<T> implements java.nio.file.DirectoryStream {
-    method public abstract void deleteDirectory(T) throws java.io.IOException;
-    method public abstract void deleteFile(T) throws java.io.IOException;
-    method public abstract <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.lang.Class<V>);
-    method public abstract <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(T, java.lang.Class<V>, java.nio.file.LinkOption...);
-    method public abstract void move(T, java.nio.file.SecureDirectoryStream<T>, T) throws java.io.IOException;
-    method public abstract java.nio.channels.SeekableByteChannel newByteChannel(T, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.SecureDirectoryStream<T> newDirectoryStream(T, java.nio.file.LinkOption...) throws java.io.IOException;
+  public interface SecureDirectoryStream<T> extends java.nio.file.DirectoryStream<T> {
+    method public void deleteDirectory(T) throws java.io.IOException;
+    method public void deleteFile(T) throws java.io.IOException;
+    method public <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(Class<V>);
+    method public <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(T, Class<V>, java.nio.file.LinkOption...);
+    method public void move(T, java.nio.file.SecureDirectoryStream<T>, T) throws java.io.IOException;
+    method public java.nio.channels.SeekableByteChannel newByteChannel(T, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
+    method public java.nio.file.SecureDirectoryStream<T> newDirectoryStream(T, java.nio.file.LinkOption...) throws java.io.IOException;
   }
 
-  public class SimpleFileVisitor<T> implements java.nio.file.FileVisitor {
+  public class SimpleFileVisitor<T> implements java.nio.file.FileVisitor<T> {
     ctor protected SimpleFileVisitor();
     method public java.nio.file.FileVisitResult postVisitDirectory(T, java.io.IOException) throws java.io.IOException;
     method public java.nio.file.FileVisitResult preVisitDirectory(T, java.nio.file.attribute.BasicFileAttributes) throws java.io.IOException;
@@ -63079,17 +63474,13 @@
     method public java.nio.file.FileVisitResult visitFileFailed(T, java.io.IOException) throws java.io.IOException;
   }
 
-  public final class StandardCopyOption extends java.lang.Enum implements java.nio.file.CopyOption {
-    method public static java.nio.file.StandardCopyOption valueOf(java.lang.String);
-    method public static final java.nio.file.StandardCopyOption[] values();
+  public enum StandardCopyOption implements java.nio.file.CopyOption {
     enum_constant public static final java.nio.file.StandardCopyOption ATOMIC_MOVE;
     enum_constant public static final java.nio.file.StandardCopyOption COPY_ATTRIBUTES;
     enum_constant public static final java.nio.file.StandardCopyOption REPLACE_EXISTING;
   }
 
-  public final class StandardOpenOption extends java.lang.Enum implements java.nio.file.OpenOption {
-    method public static java.nio.file.StandardOpenOption valueOf(java.lang.String);
-    method public static final java.nio.file.StandardOpenOption[] values();
+  public enum StandardOpenOption implements java.nio.file.OpenOption {
     enum_constant public static final java.nio.file.StandardOpenOption APPEND;
     enum_constant public static final java.nio.file.StandardOpenOption CREATE;
     enum_constant public static final java.nio.file.StandardOpenOption CREATE_NEW;
@@ -63109,38 +63500,38 @@
     field public static final java.nio.file.WatchEvent.Kind<java.lang.Object> OVERFLOW;
   }
 
-  public abstract interface WatchEvent<T> {
-    method public abstract T context();
-    method public abstract int count();
-    method public abstract java.nio.file.WatchEvent.Kind<T> kind();
+  public interface WatchEvent<T> {
+    method public T context();
+    method public int count();
+    method public java.nio.file.WatchEvent.Kind<T> kind();
   }
 
-  public static abstract interface WatchEvent.Kind<T> {
-    method public abstract java.lang.String name();
-    method public abstract java.lang.Class<T> type();
+  public static interface WatchEvent.Kind<T> {
+    method public String name();
+    method public Class<T> type();
   }
 
-  public static abstract interface WatchEvent.Modifier {
-    method public abstract java.lang.String name();
+  public static interface WatchEvent.Modifier {
+    method public String name();
   }
 
-  public abstract interface WatchKey {
-    method public abstract void cancel();
-    method public abstract boolean isValid();
-    method public abstract java.util.List<java.nio.file.WatchEvent<?>> pollEvents();
-    method public abstract boolean reset();
-    method public abstract java.nio.file.Watchable watchable();
+  public interface WatchKey {
+    method public void cancel();
+    method public boolean isValid();
+    method public java.util.List<java.nio.file.WatchEvent<?>> pollEvents();
+    method public boolean reset();
+    method public java.nio.file.Watchable watchable();
   }
 
-  public abstract interface WatchService implements java.io.Closeable {
-    method public abstract java.nio.file.WatchKey poll();
-    method public abstract java.nio.file.WatchKey poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract java.nio.file.WatchKey take() throws java.lang.InterruptedException;
+  public interface WatchService extends java.io.Closeable {
+    method public java.nio.file.WatchKey poll();
+    method public java.nio.file.WatchKey poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public java.nio.file.WatchKey take() throws java.lang.InterruptedException;
   }
 
-  public abstract interface Watchable {
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>[], java.nio.file.WatchEvent.Modifier...) throws java.io.IOException;
-    method public abstract java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>...) throws java.io.IOException;
+  public interface Watchable {
+    method public java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>[], java.nio.file.WatchEvent.Modifier...) throws java.io.IOException;
+    method public java.nio.file.WatchKey register(java.nio.file.WatchService, java.nio.file.WatchEvent.Kind<?>...) throws java.io.IOException;
   }
 
 }
@@ -63166,18 +63557,14 @@
     method public java.nio.file.attribute.AclEntry.Builder setType(java.nio.file.attribute.AclEntryType);
   }
 
-  public final class AclEntryFlag extends java.lang.Enum {
-    method public static java.nio.file.attribute.AclEntryFlag valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.AclEntryFlag[] values();
+  public enum AclEntryFlag {
     enum_constant public static final java.nio.file.attribute.AclEntryFlag DIRECTORY_INHERIT;
     enum_constant public static final java.nio.file.attribute.AclEntryFlag FILE_INHERIT;
     enum_constant public static final java.nio.file.attribute.AclEntryFlag INHERIT_ONLY;
     enum_constant public static final java.nio.file.attribute.AclEntryFlag NO_PROPAGATE_INHERIT;
   }
 
-  public final class AclEntryPermission extends java.lang.Enum {
-    method public static java.nio.file.attribute.AclEntryPermission valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.AclEntryPermission[] values();
+  public enum AclEntryPermission {
     enum_constant public static final java.nio.file.attribute.AclEntryPermission APPEND_DATA;
     enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE;
     enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE_CHILD;
@@ -63197,73 +63584,71 @@
     field public static final java.nio.file.attribute.AclEntryPermission LIST_DIRECTORY;
   }
 
-  public final class AclEntryType extends java.lang.Enum {
-    method public static java.nio.file.attribute.AclEntryType valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.AclEntryType[] values();
+  public enum AclEntryType {
     enum_constant public static final java.nio.file.attribute.AclEntryType ALARM;
     enum_constant public static final java.nio.file.attribute.AclEntryType ALLOW;
     enum_constant public static final java.nio.file.attribute.AclEntryType AUDIT;
     enum_constant public static final java.nio.file.attribute.AclEntryType DENY;
   }
 
-  public abstract interface AclFileAttributeView implements java.nio.file.attribute.FileOwnerAttributeView {
-    method public abstract java.util.List<java.nio.file.attribute.AclEntry> getAcl() throws java.io.IOException;
-    method public abstract void setAcl(java.util.List<java.nio.file.attribute.AclEntry>) throws java.io.IOException;
+  public interface AclFileAttributeView extends java.nio.file.attribute.FileOwnerAttributeView {
+    method public java.util.List<java.nio.file.attribute.AclEntry> getAcl() throws java.io.IOException;
+    method public void setAcl(java.util.List<java.nio.file.attribute.AclEntry>) throws java.io.IOException;
   }
 
-  public abstract interface AttributeView {
-    method public abstract java.lang.String name();
+  public interface AttributeView {
+    method public String name();
   }
 
-  public abstract interface BasicFileAttributeView implements java.nio.file.attribute.FileAttributeView {
-    method public abstract java.nio.file.attribute.BasicFileAttributes readAttributes() throws java.io.IOException;
-    method public abstract void setTimes(java.nio.file.attribute.FileTime, java.nio.file.attribute.FileTime, java.nio.file.attribute.FileTime) throws java.io.IOException;
+  public interface BasicFileAttributeView extends java.nio.file.attribute.FileAttributeView {
+    method public java.nio.file.attribute.BasicFileAttributes readAttributes() throws java.io.IOException;
+    method public void setTimes(java.nio.file.attribute.FileTime, java.nio.file.attribute.FileTime, java.nio.file.attribute.FileTime) throws java.io.IOException;
   }
 
-  public abstract interface BasicFileAttributes {
-    method public abstract java.nio.file.attribute.FileTime creationTime();
-    method public abstract java.lang.Object fileKey();
-    method public abstract boolean isDirectory();
-    method public abstract boolean isOther();
-    method public abstract boolean isRegularFile();
-    method public abstract boolean isSymbolicLink();
-    method public abstract java.nio.file.attribute.FileTime lastAccessTime();
-    method public abstract java.nio.file.attribute.FileTime lastModifiedTime();
-    method public abstract long size();
+  public interface BasicFileAttributes {
+    method public java.nio.file.attribute.FileTime creationTime();
+    method public Object fileKey();
+    method public boolean isDirectory();
+    method public boolean isOther();
+    method public boolean isRegularFile();
+    method public boolean isSymbolicLink();
+    method public java.nio.file.attribute.FileTime lastAccessTime();
+    method public java.nio.file.attribute.FileTime lastModifiedTime();
+    method public long size();
   }
 
-  public abstract interface DosFileAttributeView implements java.nio.file.attribute.BasicFileAttributeView {
-    method public abstract java.nio.file.attribute.DosFileAttributes readAttributes() throws java.io.IOException;
-    method public abstract void setArchive(boolean) throws java.io.IOException;
-    method public abstract void setHidden(boolean) throws java.io.IOException;
-    method public abstract void setReadOnly(boolean) throws java.io.IOException;
-    method public abstract void setSystem(boolean) throws java.io.IOException;
+  public interface DosFileAttributeView extends java.nio.file.attribute.BasicFileAttributeView {
+    method public java.nio.file.attribute.DosFileAttributes readAttributes() throws java.io.IOException;
+    method public void setArchive(boolean) throws java.io.IOException;
+    method public void setHidden(boolean) throws java.io.IOException;
+    method public void setReadOnly(boolean) throws java.io.IOException;
+    method public void setSystem(boolean) throws java.io.IOException;
   }
 
-  public abstract interface DosFileAttributes implements java.nio.file.attribute.BasicFileAttributes {
-    method public abstract boolean isArchive();
-    method public abstract boolean isHidden();
-    method public abstract boolean isReadOnly();
-    method public abstract boolean isSystem();
+  public interface DosFileAttributes extends java.nio.file.attribute.BasicFileAttributes {
+    method public boolean isArchive();
+    method public boolean isHidden();
+    method public boolean isReadOnly();
+    method public boolean isSystem();
   }
 
-  public abstract interface FileAttribute<T> {
-    method public abstract java.lang.String name();
-    method public abstract T value();
+  public interface FileAttribute<T> {
+    method public String name();
+    method public T value();
   }
 
-  public abstract interface FileAttributeView implements java.nio.file.attribute.AttributeView {
+  public interface FileAttributeView extends java.nio.file.attribute.AttributeView {
   }
 
-  public abstract interface FileOwnerAttributeView implements java.nio.file.attribute.FileAttributeView {
-    method public abstract java.nio.file.attribute.UserPrincipal getOwner() throws java.io.IOException;
-    method public abstract void setOwner(java.nio.file.attribute.UserPrincipal) throws java.io.IOException;
+  public interface FileOwnerAttributeView extends java.nio.file.attribute.FileAttributeView {
+    method public java.nio.file.attribute.UserPrincipal getOwner() throws java.io.IOException;
+    method public void setOwner(java.nio.file.attribute.UserPrincipal) throws java.io.IOException;
   }
 
-  public abstract interface FileStoreAttributeView implements java.nio.file.attribute.AttributeView {
+  public interface FileStoreAttributeView extends java.nio.file.attribute.AttributeView {
   }
 
-  public final class FileTime implements java.lang.Comparable {
+  public final class FileTime implements java.lang.Comparable<java.nio.file.attribute.FileTime> {
     method public int compareTo(java.nio.file.attribute.FileTime);
     method public static java.nio.file.attribute.FileTime from(long, java.util.concurrent.TimeUnit);
     method public static java.nio.file.attribute.FileTime from(java.time.Instant);
@@ -63273,24 +63658,22 @@
     method public long toMillis();
   }
 
-  public abstract interface GroupPrincipal implements java.nio.file.attribute.UserPrincipal {
+  public interface GroupPrincipal extends java.nio.file.attribute.UserPrincipal {
   }
 
-  public abstract interface PosixFileAttributeView implements java.nio.file.attribute.BasicFileAttributeView java.nio.file.attribute.FileOwnerAttributeView {
-    method public abstract java.nio.file.attribute.PosixFileAttributes readAttributes() throws java.io.IOException;
-    method public abstract void setGroup(java.nio.file.attribute.GroupPrincipal) throws java.io.IOException;
-    method public abstract void setPermissions(java.util.Set<java.nio.file.attribute.PosixFilePermission>) throws java.io.IOException;
+  public interface PosixFileAttributeView extends java.nio.file.attribute.BasicFileAttributeView java.nio.file.attribute.FileOwnerAttributeView {
+    method public java.nio.file.attribute.PosixFileAttributes readAttributes() throws java.io.IOException;
+    method public void setGroup(java.nio.file.attribute.GroupPrincipal) throws java.io.IOException;
+    method public void setPermissions(java.util.Set<java.nio.file.attribute.PosixFilePermission>) throws java.io.IOException;
   }
 
-  public abstract interface PosixFileAttributes implements java.nio.file.attribute.BasicFileAttributes {
-    method public abstract java.nio.file.attribute.GroupPrincipal group();
-    method public abstract java.nio.file.attribute.UserPrincipal owner();
-    method public abstract java.util.Set<java.nio.file.attribute.PosixFilePermission> permissions();
+  public interface PosixFileAttributes extends java.nio.file.attribute.BasicFileAttributes {
+    method public java.nio.file.attribute.GroupPrincipal group();
+    method public java.nio.file.attribute.UserPrincipal owner();
+    method public java.util.Set<java.nio.file.attribute.PosixFilePermission> permissions();
   }
 
-  public final class PosixFilePermission extends java.lang.Enum {
-    method public static java.nio.file.attribute.PosixFilePermission valueOf(java.lang.String);
-    method public static final java.nio.file.attribute.PosixFilePermission[] values();
+  public enum PosixFilePermission {
     enum_constant public static final java.nio.file.attribute.PosixFilePermission GROUP_EXECUTE;
     enum_constant public static final java.nio.file.attribute.PosixFilePermission GROUP_READ;
     enum_constant public static final java.nio.file.attribute.PosixFilePermission GROUP_WRITE;
@@ -63304,30 +63687,30 @@
 
   public final class PosixFilePermissions {
     method public static java.nio.file.attribute.FileAttribute<java.util.Set<java.nio.file.attribute.PosixFilePermission>> asFileAttribute(java.util.Set<java.nio.file.attribute.PosixFilePermission>);
-    method public static java.util.Set<java.nio.file.attribute.PosixFilePermission> fromString(java.lang.String);
-    method public static java.lang.String toString(java.util.Set<java.nio.file.attribute.PosixFilePermission>);
+    method public static java.util.Set<java.nio.file.attribute.PosixFilePermission> fromString(String);
+    method public static String toString(java.util.Set<java.nio.file.attribute.PosixFilePermission>);
   }
 
-  public abstract interface UserDefinedFileAttributeView implements java.nio.file.attribute.FileAttributeView {
-    method public abstract void delete(java.lang.String) throws java.io.IOException;
-    method public abstract java.util.List<java.lang.String> list() throws java.io.IOException;
-    method public abstract int read(java.lang.String, java.nio.ByteBuffer) throws java.io.IOException;
-    method public abstract int size(java.lang.String) throws java.io.IOException;
-    method public abstract int write(java.lang.String, java.nio.ByteBuffer) throws java.io.IOException;
+  public interface UserDefinedFileAttributeView extends java.nio.file.attribute.FileAttributeView {
+    method public void delete(String) throws java.io.IOException;
+    method public java.util.List<java.lang.String> list() throws java.io.IOException;
+    method public int read(String, java.nio.ByteBuffer) throws java.io.IOException;
+    method public int size(String) throws java.io.IOException;
+    method public int write(String, java.nio.ByteBuffer) throws java.io.IOException;
   }
 
-  public abstract interface UserPrincipal implements java.security.Principal {
+  public interface UserPrincipal extends java.security.Principal {
   }
 
   public abstract class UserPrincipalLookupService {
     ctor protected UserPrincipalLookupService();
-    method public abstract java.nio.file.attribute.GroupPrincipal lookupPrincipalByGroupName(java.lang.String) throws java.io.IOException;
-    method public abstract java.nio.file.attribute.UserPrincipal lookupPrincipalByName(java.lang.String) throws java.io.IOException;
+    method public abstract java.nio.file.attribute.GroupPrincipal lookupPrincipalByGroupName(String) throws java.io.IOException;
+    method public abstract java.nio.file.attribute.UserPrincipal lookupPrincipalByName(String) throws java.io.IOException;
   }
 
   public class UserPrincipalNotFoundException extends java.io.IOException {
-    ctor public UserPrincipalNotFoundException(java.lang.String);
-    method public java.lang.String getName();
+    ctor public UserPrincipalNotFoundException(String);
+    method public String getName();
   }
 
 }
@@ -63343,11 +63726,11 @@
     method public void createSymbolicLink(java.nio.file.Path, java.nio.file.Path, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public abstract void delete(java.nio.file.Path) throws java.io.IOException;
     method public boolean deleteIfExists(java.nio.file.Path) throws java.io.IOException;
-    method public abstract <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.nio.file.Path, java.lang.Class<V>, java.nio.file.LinkOption...);
+    method public abstract <V extends java.nio.file.attribute.FileAttributeView> V getFileAttributeView(java.nio.file.Path, Class<V>, java.nio.file.LinkOption...);
     method public abstract java.nio.file.FileStore getFileStore(java.nio.file.Path) throws java.io.IOException;
     method public abstract java.nio.file.FileSystem getFileSystem(java.net.URI);
     method public abstract java.nio.file.Path getPath(java.net.URI);
-    method public abstract java.lang.String getScheme();
+    method public abstract String getScheme();
     method public static java.util.List<java.nio.file.spi.FileSystemProvider> installedProviders();
     method public abstract boolean isHidden(java.nio.file.Path) throws java.io.IOException;
     method public abstract boolean isSameFile(java.nio.file.Path, java.nio.file.Path) throws java.io.IOException;
@@ -63356,19 +63739,19 @@
     method public abstract java.nio.channels.SeekableByteChannel newByteChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
     method public abstract java.nio.file.DirectoryStream<java.nio.file.Path> newDirectoryStream(java.nio.file.Path, java.nio.file.DirectoryStream.Filter<? super java.nio.file.Path>) throws java.io.IOException;
     method public java.nio.channels.FileChannel newFileChannel(java.nio.file.Path, java.util.Set<? extends java.nio.file.OpenOption>, java.nio.file.attribute.FileAttribute<?>...) throws java.io.IOException;
-    method public abstract java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
-    method public java.nio.file.FileSystem newFileSystem(java.nio.file.Path, java.util.Map<java.lang.String, ?>) throws java.io.IOException;
+    method public abstract java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map<java.lang.String,?>) throws java.io.IOException;
+    method public java.nio.file.FileSystem newFileSystem(java.nio.file.Path, java.util.Map<java.lang.String,?>) throws java.io.IOException;
     method public java.io.InputStream newInputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
     method public java.io.OutputStream newOutputStream(java.nio.file.Path, java.nio.file.OpenOption...) throws java.io.IOException;
-    method public abstract <A extends java.nio.file.attribute.BasicFileAttributes> A readAttributes(java.nio.file.Path, java.lang.Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
-    method public abstract java.util.Map<java.lang.String, java.lang.Object> readAttributes(java.nio.file.Path, java.lang.String, java.nio.file.LinkOption...) throws java.io.IOException;
+    method public abstract <A extends java.nio.file.attribute.BasicFileAttributes> A readAttributes(java.nio.file.Path, Class<A>, java.nio.file.LinkOption...) throws java.io.IOException;
+    method public abstract java.util.Map<java.lang.String,java.lang.Object> readAttributes(java.nio.file.Path, String, java.nio.file.LinkOption...) throws java.io.IOException;
     method public java.nio.file.Path readSymbolicLink(java.nio.file.Path) throws java.io.IOException;
-    method public abstract void setAttribute(java.nio.file.Path, java.lang.String, java.lang.Object, java.nio.file.LinkOption...) throws java.io.IOException;
+    method public abstract void setAttribute(java.nio.file.Path, String, Object, java.nio.file.LinkOption...) throws java.io.IOException;
   }
 
   public abstract class FileTypeDetector {
     ctor protected FileTypeDetector();
-    method public abstract java.lang.String probeContentType(java.nio.file.Path) throws java.io.IOException;
+    method public abstract String probeContentType(java.nio.file.Path) throws java.io.IOException;
   }
 
 }
@@ -63383,8 +63766,8 @@
   }
 
   public class AccessControlException extends java.lang.SecurityException {
-    ctor public AccessControlException(java.lang.String);
-    ctor public AccessControlException(java.lang.String, java.security.Permission);
+    ctor public AccessControlException(String);
+    ctor public AccessControlException(String, java.security.Permission);
     method public java.security.Permission getPermission();
   }
 
@@ -63399,19 +63782,19 @@
     method public static java.security.AccessControlContext getContext();
   }
 
-  public abstract interface AlgorithmConstraints {
-    method public abstract boolean permits(java.util.Set<java.security.CryptoPrimitive>, java.lang.String, java.security.AlgorithmParameters);
-    method public abstract boolean permits(java.util.Set<java.security.CryptoPrimitive>, java.security.Key);
-    method public abstract boolean permits(java.util.Set<java.security.CryptoPrimitive>, java.lang.String, java.security.Key, java.security.AlgorithmParameters);
+  public interface AlgorithmConstraints {
+    method public boolean permits(java.util.Set<java.security.CryptoPrimitive>, String, java.security.AlgorithmParameters);
+    method public boolean permits(java.util.Set<java.security.CryptoPrimitive>, java.security.Key);
+    method public boolean permits(java.util.Set<java.security.CryptoPrimitive>, String, java.security.Key, java.security.AlgorithmParameters);
   }
 
   public class AlgorithmParameterGenerator {
-    ctor protected AlgorithmParameterGenerator(java.security.AlgorithmParameterGeneratorSpi, java.security.Provider, java.lang.String);
+    ctor protected AlgorithmParameterGenerator(java.security.AlgorithmParameterGeneratorSpi, java.security.Provider, String);
     method public final java.security.AlgorithmParameters generateParameters();
-    method public final java.lang.String getAlgorithm();
-    method public static java.security.AlgorithmParameterGenerator getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static java.security.AlgorithmParameterGenerator getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static java.security.AlgorithmParameterGenerator getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public final String getAlgorithm();
+    method public static java.security.AlgorithmParameterGenerator getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static java.security.AlgorithmParameterGenerator getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static java.security.AlgorithmParameterGenerator getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
     method public final void init(int);
     method public final void init(int, java.security.SecureRandom);
@@ -63427,61 +63810,61 @@
   }
 
   public class AlgorithmParameters {
-    ctor protected AlgorithmParameters(java.security.AlgorithmParametersSpi, java.security.Provider, java.lang.String);
-    method public final java.lang.String getAlgorithm();
+    ctor protected AlgorithmParameters(java.security.AlgorithmParametersSpi, java.security.Provider, String);
+    method public final String getAlgorithm();
     method public final byte[] getEncoded() throws java.io.IOException;
-    method public final byte[] getEncoded(java.lang.String) throws java.io.IOException;
-    method public static java.security.AlgorithmParameters getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static java.security.AlgorithmParameters getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final <T extends java.security.spec.AlgorithmParameterSpec> T getParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
+    method public final byte[] getEncoded(String) throws java.io.IOException;
+    method public static java.security.AlgorithmParameters getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static java.security.AlgorithmParameters getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static java.security.AlgorithmParameters getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public final <T extends java.security.spec.AlgorithmParameterSpec> T getParameterSpec(Class<T>) throws java.security.spec.InvalidParameterSpecException;
     method public final java.security.Provider getProvider();
     method public final void init(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
     method public final void init(byte[]) throws java.io.IOException;
-    method public final void init(byte[], java.lang.String) throws java.io.IOException;
-    method public final java.lang.String toString();
+    method public final void init(byte[], String) throws java.io.IOException;
+    method public final String toString();
   }
 
   public abstract class AlgorithmParametersSpi {
     ctor public AlgorithmParametersSpi();
     method protected abstract byte[] engineGetEncoded() throws java.io.IOException;
-    method protected abstract byte[] engineGetEncoded(java.lang.String) throws java.io.IOException;
-    method protected abstract <T extends java.security.spec.AlgorithmParameterSpec> T engineGetParameterSpec(java.lang.Class<T>) throws java.security.spec.InvalidParameterSpecException;
+    method protected abstract byte[] engineGetEncoded(String) throws java.io.IOException;
+    method protected abstract <T extends java.security.spec.AlgorithmParameterSpec> T engineGetParameterSpec(Class<T>) throws java.security.spec.InvalidParameterSpecException;
     method protected abstract void engineInit(java.security.spec.AlgorithmParameterSpec) throws java.security.spec.InvalidParameterSpecException;
     method protected abstract void engineInit(byte[]) throws java.io.IOException;
-    method protected abstract void engineInit(byte[], java.lang.String) throws java.io.IOException;
-    method protected abstract java.lang.String engineToString();
+    method protected abstract void engineInit(byte[], String) throws java.io.IOException;
+    method protected abstract String engineToString();
   }
 
   public final class AllPermission extends java.security.Permission {
     ctor public AllPermission();
-    ctor public AllPermission(java.lang.String, java.lang.String);
-    method public java.lang.String getActions();
+    ctor public AllPermission(String, String);
+    method public String getActions();
     method public boolean implies(java.security.Permission);
   }
 
   public abstract class AuthProvider extends java.security.Provider {
-    ctor protected AuthProvider(java.lang.String, double, java.lang.String);
+    ctor protected AuthProvider(String, double, String);
     method public abstract void login(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler) throws javax.security.auth.login.LoginException;
     method public abstract void logout() throws javax.security.auth.login.LoginException;
     method public abstract void setCallbackHandler(javax.security.auth.callback.CallbackHandler);
   }
 
   public abstract class BasicPermission extends java.security.Permission implements java.io.Serializable {
-    ctor public BasicPermission(java.lang.String);
-    ctor public BasicPermission(java.lang.String, java.lang.String);
-    method public java.lang.String getActions();
+    ctor public BasicPermission(String);
+    ctor public BasicPermission(String, String);
+    method public String getActions();
     method public boolean implies(java.security.Permission);
   }
 
-  public abstract deprecated interface Certificate {
-    method public abstract void decode(java.io.InputStream) throws java.io.IOException, java.security.KeyException;
-    method public abstract void encode(java.io.OutputStream) throws java.io.IOException, java.security.KeyException;
-    method public abstract java.lang.String getFormat();
-    method public abstract java.security.Principal getGuarantor();
-    method public abstract java.security.Principal getPrincipal();
-    method public abstract java.security.PublicKey getPublicKey();
-    method public abstract java.lang.String toString(boolean);
+  @Deprecated public interface Certificate {
+    method @Deprecated public void decode(java.io.InputStream) throws java.io.IOException, java.security.KeyException;
+    method @Deprecated public void encode(java.io.OutputStream) throws java.io.IOException, java.security.KeyException;
+    method @Deprecated public String getFormat();
+    method @Deprecated public java.security.Principal getGuarantor();
+    method @Deprecated public java.security.Principal getPrincipal();
+    method @Deprecated public java.security.PublicKey getPublicKey();
+    method @Deprecated public String toString(boolean);
   }
 
   public final class CodeSigner implements java.io.Serializable {
@@ -63499,9 +63882,7 @@
     method public boolean implies(java.security.CodeSource);
   }
 
-  public final class CryptoPrimitive extends java.lang.Enum {
-    method public static java.security.CryptoPrimitive valueOf(java.lang.String);
-    method public static final java.security.CryptoPrimitive[] values();
+  public enum CryptoPrimitive {
     enum_constant public static final java.security.CryptoPrimitive BLOCK_CIPHER;
     enum_constant public static final java.security.CryptoPrimitive KEY_AGREEMENT;
     enum_constant public static final java.security.CryptoPrimitive KEY_ENCAPSULATION;
@@ -63516,9 +63897,9 @@
 
   public class DigestException extends java.security.GeneralSecurityException {
     ctor public DigestException();
-    ctor public DigestException(java.lang.String);
-    ctor public DigestException(java.lang.String, java.lang.Throwable);
-    ctor public DigestException(java.lang.Throwable);
+    ctor public DigestException(String);
+    ctor public DigestException(String, Throwable);
+    ctor public DigestException(Throwable);
   }
 
   public class DigestInputStream extends java.io.FilterInputStream {
@@ -63537,108 +63918,108 @@
     field protected java.security.MessageDigest digest;
   }
 
-  public abstract interface DomainCombiner {
-    method public abstract java.security.ProtectionDomain[] combine(java.security.ProtectionDomain[], java.security.ProtectionDomain[]);
+  public interface DomainCombiner {
+    method public java.security.ProtectionDomain[] combine(java.security.ProtectionDomain[], java.security.ProtectionDomain[]);
   }
 
   public final class DomainLoadStoreParameter implements java.security.KeyStore.LoadStoreParameter {
-    ctor public DomainLoadStoreParameter(java.net.URI, java.util.Map<java.lang.String, java.security.KeyStore.ProtectionParameter>);
+    ctor public DomainLoadStoreParameter(java.net.URI, java.util.Map<java.lang.String,java.security.KeyStore.ProtectionParameter>);
     method public java.net.URI getConfiguration();
     method public java.security.KeyStore.ProtectionParameter getProtectionParameter();
-    method public java.util.Map<java.lang.String, java.security.KeyStore.ProtectionParameter> getProtectionParams();
+    method public java.util.Map<java.lang.String,java.security.KeyStore.ProtectionParameter> getProtectionParams();
   }
 
   public class GeneralSecurityException extends java.lang.Exception {
     ctor public GeneralSecurityException();
-    ctor public GeneralSecurityException(java.lang.String);
-    ctor public GeneralSecurityException(java.lang.String, java.lang.Throwable);
-    ctor public GeneralSecurityException(java.lang.Throwable);
+    ctor public GeneralSecurityException(String);
+    ctor public GeneralSecurityException(String, Throwable);
+    ctor public GeneralSecurityException(Throwable);
   }
 
-  public abstract interface Guard {
-    method public abstract void checkGuard(java.lang.Object) throws java.lang.SecurityException;
+  public interface Guard {
+    method public void checkGuard(Object) throws java.lang.SecurityException;
   }
 
   public class GuardedObject implements java.io.Serializable {
-    ctor public GuardedObject(java.lang.Object, java.security.Guard);
-    method public java.lang.Object getObject() throws java.lang.SecurityException;
+    ctor public GuardedObject(Object, java.security.Guard);
+    method public Object getObject() throws java.lang.SecurityException;
   }
 
-  public abstract deprecated class Identity implements java.security.Principal java.io.Serializable {
-    ctor protected Identity();
-    ctor public Identity(java.lang.String, java.security.IdentityScope) throws java.security.KeyManagementException;
-    ctor public Identity(java.lang.String);
-    method public void addCertificate(java.security.Certificate) throws java.security.KeyManagementException;
-    method public java.security.Certificate[] certificates();
-    method public final boolean equals(java.lang.Object);
-    method public java.lang.String getInfo();
-    method public final java.lang.String getName();
-    method public java.security.PublicKey getPublicKey();
-    method public final java.security.IdentityScope getScope();
-    method protected boolean identityEquals(java.security.Identity);
-    method public void removeCertificate(java.security.Certificate) throws java.security.KeyManagementException;
-    method public void setInfo(java.lang.String);
-    method public void setPublicKey(java.security.PublicKey) throws java.security.KeyManagementException;
-    method public java.lang.String toString(boolean);
+  @Deprecated public abstract class Identity implements java.security.Principal java.io.Serializable {
+    ctor @Deprecated protected Identity();
+    ctor @Deprecated public Identity(String, java.security.IdentityScope) throws java.security.KeyManagementException;
+    ctor @Deprecated public Identity(String);
+    method @Deprecated public void addCertificate(java.security.Certificate) throws java.security.KeyManagementException;
+    method @Deprecated public java.security.Certificate[] certificates();
+    method @Deprecated public final boolean equals(Object);
+    method @Deprecated public String getInfo();
+    method @Deprecated public final String getName();
+    method @Deprecated public java.security.PublicKey getPublicKey();
+    method @Deprecated public final java.security.IdentityScope getScope();
+    method @Deprecated protected boolean identityEquals(java.security.Identity);
+    method @Deprecated public void removeCertificate(java.security.Certificate) throws java.security.KeyManagementException;
+    method @Deprecated public void setInfo(String);
+    method @Deprecated public void setPublicKey(java.security.PublicKey) throws java.security.KeyManagementException;
+    method @Deprecated public String toString(boolean);
   }
 
-  public abstract deprecated class IdentityScope extends java.security.Identity {
-    ctor protected IdentityScope();
-    ctor public IdentityScope(java.lang.String);
-    ctor public IdentityScope(java.lang.String, java.security.IdentityScope) throws java.security.KeyManagementException;
-    method public abstract void addIdentity(java.security.Identity) throws java.security.KeyManagementException;
-    method public abstract java.security.Identity getIdentity(java.lang.String);
-    method public java.security.Identity getIdentity(java.security.Principal);
-    method public abstract java.security.Identity getIdentity(java.security.PublicKey);
-    method public static java.security.IdentityScope getSystemScope();
-    method public abstract java.util.Enumeration<java.security.Identity> identities();
-    method public abstract void removeIdentity(java.security.Identity) throws java.security.KeyManagementException;
-    method protected static void setSystemScope(java.security.IdentityScope);
-    method public abstract int size();
+  @Deprecated public abstract class IdentityScope extends java.security.Identity {
+    ctor @Deprecated protected IdentityScope();
+    ctor @Deprecated public IdentityScope(String);
+    ctor @Deprecated public IdentityScope(String, java.security.IdentityScope) throws java.security.KeyManagementException;
+    method @Deprecated public abstract void addIdentity(java.security.Identity) throws java.security.KeyManagementException;
+    method @Deprecated public abstract java.security.Identity getIdentity(String);
+    method @Deprecated public java.security.Identity getIdentity(java.security.Principal);
+    method @Deprecated public abstract java.security.Identity getIdentity(java.security.PublicKey);
+    method @Deprecated public static java.security.IdentityScope getSystemScope();
+    method @Deprecated public abstract java.util.Enumeration<java.security.Identity> identities();
+    method @Deprecated public abstract void removeIdentity(java.security.Identity) throws java.security.KeyManagementException;
+    method @Deprecated protected static void setSystemScope(java.security.IdentityScope);
+    method @Deprecated public abstract int size();
   }
 
   public class InvalidAlgorithmParameterException extends java.security.GeneralSecurityException {
     ctor public InvalidAlgorithmParameterException();
-    ctor public InvalidAlgorithmParameterException(java.lang.String);
-    ctor public InvalidAlgorithmParameterException(java.lang.String, java.lang.Throwable);
-    ctor public InvalidAlgorithmParameterException(java.lang.Throwable);
+    ctor public InvalidAlgorithmParameterException(String);
+    ctor public InvalidAlgorithmParameterException(String, Throwable);
+    ctor public InvalidAlgorithmParameterException(Throwable);
   }
 
   public class InvalidKeyException extends java.security.KeyException {
     ctor public InvalidKeyException();
-    ctor public InvalidKeyException(java.lang.String);
-    ctor public InvalidKeyException(java.lang.String, java.lang.Throwable);
-    ctor public InvalidKeyException(java.lang.Throwable);
+    ctor public InvalidKeyException(String);
+    ctor public InvalidKeyException(String, Throwable);
+    ctor public InvalidKeyException(Throwable);
   }
 
   public class InvalidParameterException extends java.lang.IllegalArgumentException {
     ctor public InvalidParameterException();
-    ctor public InvalidParameterException(java.lang.String);
+    ctor public InvalidParameterException(String);
   }
 
-  public abstract interface Key implements java.io.Serializable {
-    method public abstract java.lang.String getAlgorithm();
-    method public abstract byte[] getEncoded();
-    method public abstract java.lang.String getFormat();
+  public interface Key extends java.io.Serializable {
+    method public String getAlgorithm();
+    method public byte[] getEncoded();
+    method public String getFormat();
     field public static final long serialVersionUID = 6603384152749567654L; // 0x5ba3eee69414eea6L
   }
 
   public class KeyException extends java.security.GeneralSecurityException {
     ctor public KeyException();
-    ctor public KeyException(java.lang.String);
-    ctor public KeyException(java.lang.String, java.lang.Throwable);
-    ctor public KeyException(java.lang.Throwable);
+    ctor public KeyException(String);
+    ctor public KeyException(String, Throwable);
+    ctor public KeyException(Throwable);
   }
 
   public class KeyFactory {
-    ctor protected KeyFactory(java.security.KeyFactorySpi, java.security.Provider, java.lang.String);
+    ctor protected KeyFactory(java.security.KeyFactorySpi, java.security.Provider, String);
     method public final java.security.PrivateKey generatePrivate(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
     method public final java.security.PublicKey generatePublic(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
-    method public final java.lang.String getAlgorithm();
-    method public static java.security.KeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static java.security.KeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static java.security.KeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final <T extends java.security.spec.KeySpec> T getKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
+    method public final String getAlgorithm();
+    method public static java.security.KeyFactory getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static java.security.KeyFactory getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static java.security.KeyFactory getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public final <T extends java.security.spec.KeySpec> T getKeySpec(java.security.Key, Class<T>) throws java.security.spec.InvalidKeySpecException;
     method public final java.security.Provider getProvider();
     method public final java.security.Key translateKey(java.security.Key) throws java.security.InvalidKeyException;
   }
@@ -63647,15 +64028,15 @@
     ctor public KeyFactorySpi();
     method protected abstract java.security.PrivateKey engineGeneratePrivate(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
     method protected abstract java.security.PublicKey engineGeneratePublic(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
-    method protected abstract <T extends java.security.spec.KeySpec> T engineGetKeySpec(java.security.Key, java.lang.Class<T>) throws java.security.spec.InvalidKeySpecException;
+    method protected abstract <T extends java.security.spec.KeySpec> T engineGetKeySpec(java.security.Key, Class<T>) throws java.security.spec.InvalidKeySpecException;
     method protected abstract java.security.Key engineTranslateKey(java.security.Key) throws java.security.InvalidKeyException;
   }
 
   public class KeyManagementException extends java.security.KeyException {
     ctor public KeyManagementException();
-    ctor public KeyManagementException(java.lang.String);
-    ctor public KeyManagementException(java.lang.String, java.lang.Throwable);
-    ctor public KeyManagementException(java.lang.Throwable);
+    ctor public KeyManagementException(String);
+    ctor public KeyManagementException(String, Throwable);
+    ctor public KeyManagementException(Throwable);
   }
 
   public final class KeyPair implements java.io.Serializable {
@@ -63665,13 +64046,13 @@
   }
 
   public abstract class KeyPairGenerator extends java.security.KeyPairGeneratorSpi {
-    ctor protected KeyPairGenerator(java.lang.String);
+    ctor protected KeyPairGenerator(String);
     method public final java.security.KeyPair genKeyPair();
     method public java.security.KeyPair generateKeyPair();
-    method public java.lang.String getAlgorithm();
-    method public static java.security.KeyPairGenerator getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static java.security.KeyPairGenerator getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static java.security.KeyPairGenerator getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public String getAlgorithm();
+    method public static java.security.KeyPairGenerator getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static java.security.KeyPairGenerator getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static java.security.KeyPairGenerator getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
     method public void initialize(int);
     method public void initialize(int, java.security.SecureRandom);
@@ -63686,56 +64067,54 @@
   }
 
   public class KeyRep implements java.io.Serializable {
-    ctor public KeyRep(java.security.KeyRep.Type, java.lang.String, java.lang.String, byte[]);
-    method protected java.lang.Object readResolve() throws java.io.ObjectStreamException;
+    ctor public KeyRep(java.security.KeyRep.Type, String, String, byte[]);
+    method protected Object readResolve() throws java.io.ObjectStreamException;
   }
 
-  public static final class KeyRep.Type extends java.lang.Enum {
-    method public static java.security.KeyRep.Type valueOf(java.lang.String);
-    method public static final java.security.KeyRep.Type[] values();
+  public enum KeyRep.Type {
     enum_constant public static final java.security.KeyRep.Type PRIVATE;
     enum_constant public static final java.security.KeyRep.Type PUBLIC;
     enum_constant public static final java.security.KeyRep.Type SECRET;
   }
 
   public class KeyStore {
-    ctor protected KeyStore(java.security.KeyStoreSpi, java.security.Provider, java.lang.String);
+    ctor protected KeyStore(java.security.KeyStoreSpi, java.security.Provider, String);
     method public final java.util.Enumeration<java.lang.String> aliases() throws java.security.KeyStoreException;
-    method public final boolean containsAlias(java.lang.String) throws java.security.KeyStoreException;
-    method public final void deleteEntry(java.lang.String) throws java.security.KeyStoreException;
-    method public final boolean entryInstanceOf(java.lang.String, java.lang.Class<? extends java.security.KeyStore.Entry>) throws java.security.KeyStoreException;
-    method public final java.security.cert.Certificate getCertificate(java.lang.String) throws java.security.KeyStoreException;
-    method public final java.lang.String getCertificateAlias(java.security.cert.Certificate) throws java.security.KeyStoreException;
-    method public final java.security.cert.Certificate[] getCertificateChain(java.lang.String) throws java.security.KeyStoreException;
-    method public final java.util.Date getCreationDate(java.lang.String) throws java.security.KeyStoreException;
-    method public static final java.lang.String getDefaultType();
-    method public final java.security.KeyStore.Entry getEntry(java.lang.String, java.security.KeyStore.ProtectionParameter) throws java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableEntryException;
-    method public static java.security.KeyStore getInstance(java.lang.String) throws java.security.KeyStoreException;
-    method public static java.security.KeyStore getInstance(java.lang.String, java.lang.String) throws java.security.KeyStoreException, java.security.NoSuchProviderException;
-    method public static java.security.KeyStore getInstance(java.lang.String, java.security.Provider) throws java.security.KeyStoreException;
-    method public final java.security.Key getKey(java.lang.String, char[]) throws java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException;
+    method public final boolean containsAlias(String) throws java.security.KeyStoreException;
+    method public final void deleteEntry(String) throws java.security.KeyStoreException;
+    method public final boolean entryInstanceOf(String, Class<? extends java.security.KeyStore.Entry>) throws java.security.KeyStoreException;
+    method public final java.security.cert.Certificate getCertificate(String) throws java.security.KeyStoreException;
+    method public final String getCertificateAlias(java.security.cert.Certificate) throws java.security.KeyStoreException;
+    method public final java.security.cert.Certificate[] getCertificateChain(String) throws java.security.KeyStoreException;
+    method public final java.util.Date getCreationDate(String) throws java.security.KeyStoreException;
+    method public static final String getDefaultType();
+    method public final java.security.KeyStore.Entry getEntry(String, java.security.KeyStore.ProtectionParameter) throws java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableEntryException;
+    method public static java.security.KeyStore getInstance(String) throws java.security.KeyStoreException;
+    method public static java.security.KeyStore getInstance(String, String) throws java.security.KeyStoreException, java.security.NoSuchProviderException;
+    method public static java.security.KeyStore getInstance(String, java.security.Provider) throws java.security.KeyStoreException;
+    method public final java.security.Key getKey(String, char[]) throws java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException;
     method public final java.security.Provider getProvider();
-    method public final java.lang.String getType();
-    method public final boolean isCertificateEntry(java.lang.String) throws java.security.KeyStoreException;
-    method public final boolean isKeyEntry(java.lang.String) throws java.security.KeyStoreException;
+    method public final String getType();
+    method public final boolean isCertificateEntry(String) throws java.security.KeyStoreException;
+    method public final boolean isKeyEntry(String) throws java.security.KeyStoreException;
     method public final void load(java.io.InputStream, char[]) throws java.security.cert.CertificateException, java.io.IOException, java.security.NoSuchAlgorithmException;
     method public final void load(java.security.KeyStore.LoadStoreParameter) throws java.security.cert.CertificateException, java.io.IOException, java.security.NoSuchAlgorithmException;
-    method public final void setCertificateEntry(java.lang.String, java.security.cert.Certificate) throws java.security.KeyStoreException;
-    method public final void setEntry(java.lang.String, java.security.KeyStore.Entry, java.security.KeyStore.ProtectionParameter) throws java.security.KeyStoreException;
-    method public final void setKeyEntry(java.lang.String, java.security.Key, char[], java.security.cert.Certificate[]) throws java.security.KeyStoreException;
-    method public final void setKeyEntry(java.lang.String, byte[], java.security.cert.Certificate[]) throws java.security.KeyStoreException;
+    method public final void setCertificateEntry(String, java.security.cert.Certificate) throws java.security.KeyStoreException;
+    method public final void setEntry(String, java.security.KeyStore.Entry, java.security.KeyStore.ProtectionParameter) throws java.security.KeyStoreException;
+    method public final void setKeyEntry(String, java.security.Key, char[], java.security.cert.Certificate[]) throws java.security.KeyStoreException;
+    method public final void setKeyEntry(String, byte[], java.security.cert.Certificate[]) throws java.security.KeyStoreException;
     method public final int size() throws java.security.KeyStoreException;
     method public final void store(java.io.OutputStream, char[]) throws java.security.cert.CertificateException, java.io.IOException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException;
     method public final void store(java.security.KeyStore.LoadStoreParameter) throws java.security.cert.CertificateException, java.io.IOException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException;
   }
 
-  public static abstract class KeyStore.Builder {
+  public abstract static class KeyStore.Builder {
     ctor protected KeyStore.Builder();
     method public abstract java.security.KeyStore getKeyStore() throws java.security.KeyStoreException;
-    method public abstract java.security.KeyStore.ProtectionParameter getProtectionParameter(java.lang.String) throws java.security.KeyStoreException;
+    method public abstract java.security.KeyStore.ProtectionParameter getProtectionParameter(String) throws java.security.KeyStoreException;
     method public static java.security.KeyStore.Builder newInstance(java.security.KeyStore, java.security.KeyStore.ProtectionParameter);
-    method public static java.security.KeyStore.Builder newInstance(java.lang.String, java.security.Provider, java.io.File, java.security.KeyStore.ProtectionParameter);
-    method public static java.security.KeyStore.Builder newInstance(java.lang.String, java.security.Provider, java.security.KeyStore.ProtectionParameter);
+    method public static java.security.KeyStore.Builder newInstance(String, java.security.Provider, java.io.File, java.security.KeyStore.ProtectionParameter);
+    method public static java.security.KeyStore.Builder newInstance(String, java.security.Provider, java.security.KeyStore.ProtectionParameter);
   }
 
   public static class KeyStore.CallbackHandlerProtection implements java.security.KeyStore.ProtectionParameter {
@@ -63743,27 +64122,25 @@
     method public javax.security.auth.callback.CallbackHandler getCallbackHandler();
   }
 
-  public static abstract interface KeyStore.Entry {
+  public static interface KeyStore.Entry {
     method public default java.util.Set<java.security.KeyStore.Entry.Attribute> getAttributes();
   }
 
-  public static abstract interface KeyStore.Entry.Attribute {
-    method public abstract java.lang.String getName();
-    method public abstract java.lang.String getValue();
+  public static interface KeyStore.Entry.Attribute {
+    method public String getName();
+    method public String getValue();
   }
 
-  public static abstract interface KeyStore.LoadStoreParameter {
-    method public abstract java.security.KeyStore.ProtectionParameter getProtectionParameter();
+  public static interface KeyStore.LoadStoreParameter {
+    method public java.security.KeyStore.ProtectionParameter getProtectionParameter();
   }
 
   public static class KeyStore.PasswordProtection implements javax.security.auth.Destroyable java.security.KeyStore.ProtectionParameter {
     ctor public KeyStore.PasswordProtection(char[]);
-    ctor public KeyStore.PasswordProtection(char[], java.lang.String, java.security.spec.AlgorithmParameterSpec);
-    method public synchronized void destroy() throws javax.security.auth.DestroyFailedException;
-    method public synchronized char[] getPassword();
-    method public java.lang.String getProtectionAlgorithm();
+    ctor public KeyStore.PasswordProtection(char[], String, java.security.spec.AlgorithmParameterSpec);
+    method public char[] getPassword();
+    method public String getProtectionAlgorithm();
     method public java.security.spec.AlgorithmParameterSpec getProtectionParameters();
-    method public synchronized boolean isDestroyed();
   }
 
   public static final class KeyStore.PrivateKeyEntry implements java.security.KeyStore.Entry {
@@ -63774,7 +64151,7 @@
     method public java.security.PrivateKey getPrivateKey();
   }
 
-  public static abstract interface KeyStore.ProtectionParameter {
+  public static interface KeyStore.ProtectionParameter {
   }
 
   public static final class KeyStore.SecretKeyEntry implements java.security.KeyStore.Entry {
@@ -63791,58 +64168,58 @@
 
   public class KeyStoreException extends java.security.GeneralSecurityException {
     ctor public KeyStoreException();
-    ctor public KeyStoreException(java.lang.String);
-    ctor public KeyStoreException(java.lang.String, java.lang.Throwable);
-    ctor public KeyStoreException(java.lang.Throwable);
+    ctor public KeyStoreException(String);
+    ctor public KeyStoreException(String, Throwable);
+    ctor public KeyStoreException(Throwable);
   }
 
   public abstract class KeyStoreSpi {
     ctor public KeyStoreSpi();
     method public abstract java.util.Enumeration<java.lang.String> engineAliases();
-    method public abstract boolean engineContainsAlias(java.lang.String);
-    method public abstract void engineDeleteEntry(java.lang.String) throws java.security.KeyStoreException;
-    method public boolean engineEntryInstanceOf(java.lang.String, java.lang.Class<? extends java.security.KeyStore.Entry>);
-    method public abstract java.security.cert.Certificate engineGetCertificate(java.lang.String);
-    method public abstract java.lang.String engineGetCertificateAlias(java.security.cert.Certificate);
-    method public abstract java.security.cert.Certificate[] engineGetCertificateChain(java.lang.String);
-    method public abstract java.util.Date engineGetCreationDate(java.lang.String);
-    method public java.security.KeyStore.Entry engineGetEntry(java.lang.String, java.security.KeyStore.ProtectionParameter) throws java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableEntryException;
-    method public abstract java.security.Key engineGetKey(java.lang.String, char[]) throws java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException;
-    method public abstract boolean engineIsCertificateEntry(java.lang.String);
-    method public abstract boolean engineIsKeyEntry(java.lang.String);
+    method public abstract boolean engineContainsAlias(String);
+    method public abstract void engineDeleteEntry(String) throws java.security.KeyStoreException;
+    method public boolean engineEntryInstanceOf(String, Class<? extends java.security.KeyStore.Entry>);
+    method public abstract java.security.cert.Certificate engineGetCertificate(String);
+    method public abstract String engineGetCertificateAlias(java.security.cert.Certificate);
+    method public abstract java.security.cert.Certificate[] engineGetCertificateChain(String);
+    method public abstract java.util.Date engineGetCreationDate(String);
+    method public java.security.KeyStore.Entry engineGetEntry(String, java.security.KeyStore.ProtectionParameter) throws java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableEntryException;
+    method public abstract java.security.Key engineGetKey(String, char[]) throws java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException;
+    method public abstract boolean engineIsCertificateEntry(String);
+    method public abstract boolean engineIsKeyEntry(String);
     method public abstract void engineLoad(java.io.InputStream, char[]) throws java.security.cert.CertificateException, java.io.IOException, java.security.NoSuchAlgorithmException;
     method public void engineLoad(java.security.KeyStore.LoadStoreParameter) throws java.security.cert.CertificateException, java.io.IOException, java.security.NoSuchAlgorithmException;
-    method public abstract void engineSetCertificateEntry(java.lang.String, java.security.cert.Certificate) throws java.security.KeyStoreException;
-    method public void engineSetEntry(java.lang.String, java.security.KeyStore.Entry, java.security.KeyStore.ProtectionParameter) throws java.security.KeyStoreException;
-    method public abstract void engineSetKeyEntry(java.lang.String, java.security.Key, char[], java.security.cert.Certificate[]) throws java.security.KeyStoreException;
-    method public abstract void engineSetKeyEntry(java.lang.String, byte[], java.security.cert.Certificate[]) throws java.security.KeyStoreException;
+    method public abstract void engineSetCertificateEntry(String, java.security.cert.Certificate) throws java.security.KeyStoreException;
+    method public void engineSetEntry(String, java.security.KeyStore.Entry, java.security.KeyStore.ProtectionParameter) throws java.security.KeyStoreException;
+    method public abstract void engineSetKeyEntry(String, java.security.Key, char[], java.security.cert.Certificate[]) throws java.security.KeyStoreException;
+    method public abstract void engineSetKeyEntry(String, byte[], java.security.cert.Certificate[]) throws java.security.KeyStoreException;
     method public abstract int engineSize();
     method public abstract void engineStore(java.io.OutputStream, char[]) throws java.security.cert.CertificateException, java.io.IOException, java.security.NoSuchAlgorithmException;
     method public void engineStore(java.security.KeyStore.LoadStoreParameter) throws java.security.cert.CertificateException, java.io.IOException, java.security.NoSuchAlgorithmException;
   }
 
   public abstract class MessageDigest extends java.security.MessageDigestSpi {
-    ctor protected MessageDigest(java.lang.String);
+    ctor protected MessageDigest(@NonNull String);
     method public byte[] digest();
     method public int digest(byte[], int, int) throws java.security.DigestException;
     method public byte[] digest(byte[]);
-    method public final java.lang.String getAlgorithm();
+    method @NonNull public final String getAlgorithm();
     method public final int getDigestLength();
-    method public static java.security.MessageDigest getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static java.security.MessageDigest getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static java.security.MessageDigest getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final java.security.Provider getProvider();
+    method @NonNull public static java.security.MessageDigest getInstance(@NonNull String) throws java.security.NoSuchAlgorithmException;
+    method @NonNull public static java.security.MessageDigest getInstance(@NonNull String, @NonNull String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method @NonNull public static java.security.MessageDigest getInstance(@NonNull String, @NonNull java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method @NonNull public final java.security.Provider getProvider();
     method public static boolean isEqual(byte[], byte[]);
     method public void reset();
     method public void update(byte);
     method public void update(byte[], int, int);
     method public void update(byte[]);
-    method public final void update(java.nio.ByteBuffer);
+    method public final void update(@NonNull java.nio.ByteBuffer);
   }
 
   public abstract class MessageDigestSpi {
     ctor public MessageDigestSpi();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
+    method public Object clone() throws java.lang.CloneNotSupportedException;
     method protected abstract byte[] engineDigest();
     method protected int engineDigest(byte[], int, int) throws java.security.DigestException;
     method protected int engineGetDigestLength();
@@ -63854,29 +64231,29 @@
 
   public class NoSuchAlgorithmException extends java.security.GeneralSecurityException {
     ctor public NoSuchAlgorithmException();
-    ctor public NoSuchAlgorithmException(java.lang.String);
-    ctor public NoSuchAlgorithmException(java.lang.String, java.lang.Throwable);
-    ctor public NoSuchAlgorithmException(java.lang.Throwable);
+    ctor public NoSuchAlgorithmException(String);
+    ctor public NoSuchAlgorithmException(String, Throwable);
+    ctor public NoSuchAlgorithmException(Throwable);
   }
 
   public class NoSuchProviderException extends java.security.GeneralSecurityException {
     ctor public NoSuchProviderException();
-    ctor public NoSuchProviderException(java.lang.String);
+    ctor public NoSuchProviderException(String);
   }
 
   public final class PKCS12Attribute implements java.security.KeyStore.Entry.Attribute {
-    ctor public PKCS12Attribute(java.lang.String, java.lang.String);
+    ctor public PKCS12Attribute(String, String);
     ctor public PKCS12Attribute(byte[]);
     method public byte[] getEncoded();
-    method public java.lang.String getName();
-    method public java.lang.String getValue();
+    method public String getName();
+    method public String getValue();
   }
 
   public abstract class Permission implements java.security.Guard java.io.Serializable {
-    ctor public Permission(java.lang.String);
-    method public void checkGuard(java.lang.Object) throws java.lang.SecurityException;
-    method public abstract java.lang.String getActions();
-    method public final java.lang.String getName();
+    ctor public Permission(String);
+    method public void checkGuard(Object) throws java.lang.SecurityException;
+    method public abstract String getActions();
+    method public final String getName();
     method public abstract boolean implies(java.security.Permission);
     method public java.security.PermissionCollection newPermissionCollection();
   }
@@ -63899,22 +64276,22 @@
 
   public abstract class Policy {
     ctor public Policy();
-    method public static java.security.Policy getInstance(java.lang.String, java.security.Policy.Parameters) throws java.security.NoSuchAlgorithmException;
-    method public static java.security.Policy getInstance(java.lang.String, java.security.Policy.Parameters, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static java.security.Policy getInstance(java.lang.String, java.security.Policy.Parameters, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public static java.security.Policy getInstance(String, java.security.Policy.Parameters) throws java.security.NoSuchAlgorithmException;
+    method public static java.security.Policy getInstance(String, java.security.Policy.Parameters, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static java.security.Policy getInstance(String, java.security.Policy.Parameters, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public java.security.Policy.Parameters getParameters();
     method public java.security.PermissionCollection getPermissions(java.security.CodeSource);
     method public java.security.PermissionCollection getPermissions(java.security.ProtectionDomain);
     method public static java.security.Policy getPolicy();
     method public java.security.Provider getProvider();
-    method public java.lang.String getType();
+    method public String getType();
     method public boolean implies(java.security.ProtectionDomain, java.security.Permission);
     method public void refresh();
     method public static void setPolicy(java.security.Policy);
     field public static final java.security.PermissionCollection UNSUPPORTED_EMPTY_COLLECTION;
   }
 
-  public static abstract interface Policy.Parameters {
+  public static interface Policy.Parameters {
   }
 
   public abstract class PolicySpi {
@@ -63925,36 +64302,35 @@
     method protected void engineRefresh();
   }
 
-  public abstract interface Principal {
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract java.lang.String getName();
-    method public abstract int hashCode();
+  public interface Principal {
+    method public boolean equals(Object);
+    method public String getName();
+    method public int hashCode();
     method public default boolean implies(javax.security.auth.Subject);
-    method public abstract java.lang.String toString();
+    method public String toString();
   }
 
-  public abstract interface PrivateKey implements javax.security.auth.Destroyable java.security.Key {
+  public interface PrivateKey extends java.security.Key javax.security.auth.Destroyable {
     field public static final long serialVersionUID = 6034044314589513430L; // 0x53bd3b559a12c6d6L
   }
 
-  public abstract interface PrivilegedAction<T> {
-    method public abstract T run();
+  public interface PrivilegedAction<T> {
+    method public T run();
   }
 
   public class PrivilegedActionException extends java.lang.Exception {
-    ctor public PrivilegedActionException(java.lang.Exception);
-    method public java.lang.Throwable getCause();
-    method public java.lang.Exception getException();
+    ctor public PrivilegedActionException(Exception);
+    method public Exception getException();
   }
 
-  public abstract interface PrivilegedExceptionAction<T> {
-    method public abstract T run() throws java.lang.Exception;
+  public interface PrivilegedExceptionAction<T> {
+    method public T run() throws java.lang.Exception;
   }
 
   public class ProtectionDomain {
     ctor public ProtectionDomain(java.security.CodeSource, java.security.PermissionCollection);
-    ctor public ProtectionDomain(java.security.CodeSource, java.security.PermissionCollection, java.lang.ClassLoader, java.security.Principal[]);
-    method public final java.lang.ClassLoader getClassLoader();
+    ctor public ProtectionDomain(java.security.CodeSource, java.security.PermissionCollection, ClassLoader, java.security.Principal[]);
+    method public final ClassLoader getClassLoader();
     method public final java.security.CodeSource getCodeSource();
     method public final java.security.PermissionCollection getPermissions();
     method public final java.security.Principal[] getPrincipals();
@@ -63962,62 +64338,62 @@
   }
 
   public abstract class Provider extends java.util.Properties {
-    ctor protected Provider(java.lang.String, double, java.lang.String);
-    method public synchronized java.lang.Object compute(java.lang.Object, java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
-    method public synchronized java.lang.Object computeIfAbsent(java.lang.Object, java.util.function.Function<? super java.lang.Object, ? extends java.lang.Object>);
-    method public synchronized java.lang.Object computeIfPresent(java.lang.Object, java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
+    ctor protected Provider(String, double, String);
+    method public Object compute(Object, java.util.function.BiFunction<? super java.lang.Object,? super java.lang.Object,?>);
+    method public Object computeIfAbsent(Object, java.util.function.Function<? super java.lang.Object,?>);
+    method public Object computeIfPresent(Object, java.util.function.BiFunction<? super java.lang.Object,? super java.lang.Object,?>);
     method public java.util.Enumeration<java.lang.Object> elements();
-    method public synchronized java.util.Set<java.util.Map.Entry<java.lang.Object, java.lang.Object>> entrySet();
-    method public synchronized void forEach(java.util.function.BiConsumer<? super java.lang.Object, ? super java.lang.Object>);
-    method public java.lang.Object get(java.lang.Object);
-    method public java.lang.String getInfo();
-    method public java.lang.String getName();
-    method public synchronized java.lang.Object getOrDefault(java.lang.Object, java.lang.Object);
-    method public synchronized java.security.Provider.Service getService(java.lang.String, java.lang.String);
-    method public synchronized java.util.Set<java.security.Provider.Service> getServices();
+    method public java.util.Set<java.util.Map.Entry<java.lang.Object,java.lang.Object>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super java.lang.Object,? super java.lang.Object>);
+    method public Object get(Object);
+    method public String getInfo();
+    method public String getName();
+    method public Object getOrDefault(Object, Object);
+    method public java.security.Provider.Service getService(String, String);
+    method public java.util.Set<java.security.Provider.Service> getServices();
     method public double getVersion();
     method public java.util.Set<java.lang.Object> keySet();
     method public java.util.Enumeration<java.lang.Object> keys();
-    method public synchronized java.lang.Object merge(java.lang.Object, java.lang.Object, java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
-    method public synchronized java.lang.Object put(java.lang.Object, java.lang.Object);
-    method public synchronized void putAll(java.util.Map<?, ?>);
-    method public synchronized java.lang.Object putIfAbsent(java.lang.Object, java.lang.Object);
-    method protected synchronized void putService(java.security.Provider.Service);
-    method public synchronized java.lang.Object remove(java.lang.Object);
-    method protected synchronized void removeService(java.security.Provider.Service);
-    method public synchronized boolean replace(java.lang.Object, java.lang.Object, java.lang.Object);
-    method public synchronized java.lang.Object replace(java.lang.Object, java.lang.Object);
-    method public synchronized void replaceAll(java.util.function.BiFunction<? super java.lang.Object, ? super java.lang.Object, ? extends java.lang.Object>);
+    method public Object merge(Object, Object, java.util.function.BiFunction<? super java.lang.Object,? super java.lang.Object,?>);
+    method public Object put(Object, Object);
+    method public void putAll(java.util.Map<?,?>);
+    method public Object putIfAbsent(Object, Object);
+    method protected void putService(java.security.Provider.Service);
+    method public Object remove(Object);
+    method protected void removeService(java.security.Provider.Service);
+    method public boolean replace(Object, Object, Object);
+    method public Object replace(Object, Object);
+    method public void replaceAll(java.util.function.BiFunction<? super java.lang.Object,? super java.lang.Object,?>);
     method public java.util.Collection<java.lang.Object> values();
   }
 
   public static class Provider.Service {
-    ctor public Provider.Service(java.security.Provider, java.lang.String, java.lang.String, java.lang.String, java.util.List<java.lang.String>, java.util.Map<java.lang.String, java.lang.String>);
-    method public final java.lang.String getAlgorithm();
-    method public final java.lang.String getAttribute(java.lang.String);
-    method public final java.lang.String getClassName();
+    ctor public Provider.Service(java.security.Provider, String, String, String, java.util.List<java.lang.String>, java.util.Map<java.lang.String,java.lang.String>);
+    method public final String getAlgorithm();
+    method public final String getAttribute(String);
+    method public final String getClassName();
     method public final java.security.Provider getProvider();
-    method public final java.lang.String getType();
-    method public java.lang.Object newInstance(java.lang.Object) throws java.security.NoSuchAlgorithmException;
-    method public boolean supportsParameter(java.lang.Object);
+    method public final String getType();
+    method public Object newInstance(Object) throws java.security.NoSuchAlgorithmException;
+    method public boolean supportsParameter(Object);
   }
 
   public class ProviderException extends java.lang.RuntimeException {
     ctor public ProviderException();
-    ctor public ProviderException(java.lang.String);
-    ctor public ProviderException(java.lang.String, java.lang.Throwable);
-    ctor public ProviderException(java.lang.Throwable);
+    ctor public ProviderException(String);
+    ctor public ProviderException(String, Throwable);
+    ctor public ProviderException(Throwable);
   }
 
-  public abstract interface PublicKey implements java.security.Key {
+  public interface PublicKey extends java.security.Key {
     field public static final long serialVersionUID = 7187392471159151072L; // 0x63bebf5f40c219e0L
   }
 
   public class SecureClassLoader extends java.lang.ClassLoader {
-    ctor protected SecureClassLoader(java.lang.ClassLoader);
+    ctor protected SecureClassLoader(ClassLoader);
     ctor protected SecureClassLoader();
-    method protected final java.lang.Class<?> defineClass(java.lang.String, byte[], int, int, java.security.CodeSource);
-    method protected final java.lang.Class<?> defineClass(java.lang.String, java.nio.ByteBuffer, java.security.CodeSource);
+    method protected final Class<?> defineClass(String, byte[], int, int, java.security.CodeSource);
+    method protected final Class<?> defineClass(String, java.nio.ByteBuffer, java.security.CodeSource);
     method protected java.security.PermissionCollection getPermissions(java.security.CodeSource);
   }
 
@@ -64026,17 +64402,15 @@
     ctor public SecureRandom(byte[]);
     ctor protected SecureRandom(java.security.SecureRandomSpi, java.security.Provider);
     method public byte[] generateSeed(int);
-    method public java.lang.String getAlgorithm();
-    method public static java.security.SecureRandom getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static java.security.SecureRandom getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static java.security.SecureRandom getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public String getAlgorithm();
+    method public static java.security.SecureRandom getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static java.security.SecureRandom getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static java.security.SecureRandom getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public static java.security.SecureRandom getInstanceStrong() throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
     method public static byte[] getSeed(int);
     method protected final int next(int);
-    method public synchronized void nextBytes(byte[]);
-    method public synchronized void setSeed(byte[]);
-    method public void setSeed(long);
+    method public void setSeed(byte[]);
   }
 
   public abstract class SecureRandomSpi implements java.io.Serializable {
@@ -64048,37 +64422,37 @@
 
   public final class Security {
     method public static int addProvider(java.security.Provider);
-    method public static deprecated java.lang.String getAlgorithmProperty(java.lang.String, java.lang.String);
-    method public static java.util.Set<java.lang.String> getAlgorithms(java.lang.String);
-    method public static java.lang.String getProperty(java.lang.String);
-    method public static java.security.Provider getProvider(java.lang.String);
+    method @Deprecated public static String getAlgorithmProperty(String, String);
+    method public static java.util.Set<java.lang.String> getAlgorithms(String);
+    method public static String getProperty(String);
+    method public static java.security.Provider getProvider(String);
     method public static java.security.Provider[] getProviders();
-    method public static java.security.Provider[] getProviders(java.lang.String);
-    method public static java.security.Provider[] getProviders(java.util.Map<java.lang.String, java.lang.String>);
-    method public static synchronized int insertProviderAt(java.security.Provider, int);
-    method public static synchronized void removeProvider(java.lang.String);
-    method public static void setProperty(java.lang.String, java.lang.String);
+    method public static java.security.Provider[] getProviders(String);
+    method public static java.security.Provider[] getProviders(java.util.Map<java.lang.String,java.lang.String>);
+    method public static int insertProviderAt(java.security.Provider, int);
+    method public static void removeProvider(String);
+    method public static void setProperty(String, String);
   }
 
   public final class SecurityPermission extends java.security.BasicPermission {
-    ctor public SecurityPermission(java.lang.String);
-    ctor public SecurityPermission(java.lang.String, java.lang.String);
+    ctor public SecurityPermission(String);
+    ctor public SecurityPermission(String, String);
   }
 
   public abstract class Signature extends java.security.SignatureSpi {
-    ctor protected Signature(java.lang.String);
-    method public final java.lang.String getAlgorithm();
-    method public static java.security.Signature getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static java.security.Signature getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static java.security.Signature getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final deprecated java.lang.Object getParameter(java.lang.String) throws java.security.InvalidParameterException;
+    ctor protected Signature(String);
+    method public final String getAlgorithm();
+    method public static java.security.Signature getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static java.security.Signature getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static java.security.Signature getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method @Deprecated public final Object getParameter(String) throws java.security.InvalidParameterException;
     method public final java.security.AlgorithmParameters getParameters();
     method public final java.security.Provider getProvider();
     method public final void initSign(java.security.PrivateKey) throws java.security.InvalidKeyException;
     method public final void initSign(java.security.PrivateKey, java.security.SecureRandom) throws java.security.InvalidKeyException;
     method public final void initVerify(java.security.PublicKey) throws java.security.InvalidKeyException;
     method public final void initVerify(java.security.cert.Certificate) throws java.security.InvalidKeyException;
-    method public final deprecated void setParameter(java.lang.String, java.lang.Object) throws java.security.InvalidParameterException;
+    method @Deprecated public final void setParameter(String, Object) throws java.security.InvalidParameterException;
     method public final void setParameter(java.security.spec.AlgorithmParameterSpec) throws java.security.InvalidAlgorithmParameterException;
     method public final byte[] sign() throws java.security.SignatureException;
     method public final int sign(byte[], int, int) throws java.security.SignatureException;
@@ -64096,20 +64470,20 @@
 
   public class SignatureException extends java.security.GeneralSecurityException {
     ctor public SignatureException();
-    ctor public SignatureException(java.lang.String);
-    ctor public SignatureException(java.lang.String, java.lang.Throwable);
-    ctor public SignatureException(java.lang.Throwable);
+    ctor public SignatureException(String);
+    ctor public SignatureException(String, Throwable);
+    ctor public SignatureException(Throwable);
   }
 
   public abstract class SignatureSpi {
     ctor public SignatureSpi();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
-    method protected abstract deprecated java.lang.Object engineGetParameter(java.lang.String) throws java.security.InvalidParameterException;
+    method public Object clone() throws java.lang.CloneNotSupportedException;
+    method @Deprecated protected abstract Object engineGetParameter(String) throws java.security.InvalidParameterException;
     method protected java.security.AlgorithmParameters engineGetParameters();
     method protected abstract void engineInitSign(java.security.PrivateKey) throws java.security.InvalidKeyException;
     method protected void engineInitSign(java.security.PrivateKey, java.security.SecureRandom) throws java.security.InvalidKeyException;
     method protected abstract void engineInitVerify(java.security.PublicKey) throws java.security.InvalidKeyException;
-    method protected abstract deprecated void engineSetParameter(java.lang.String, java.lang.Object) throws java.security.InvalidParameterException;
+    method @Deprecated protected abstract void engineSetParameter(String, Object) throws java.security.InvalidParameterException;
     method protected void engineSetParameter(java.security.spec.AlgorithmParameterSpec) throws java.security.InvalidAlgorithmParameterException;
     method protected abstract byte[] engineSign() throws java.security.SignatureException;
     method protected int engineSign(byte[], int, int) throws java.security.SignatureException;
@@ -64123,18 +64497,18 @@
 
   public final class SignedObject implements java.io.Serializable {
     ctor public SignedObject(java.io.Serializable, java.security.PrivateKey, java.security.Signature) throws java.io.IOException, java.security.InvalidKeyException, java.security.SignatureException;
-    method public java.lang.String getAlgorithm();
-    method public java.lang.Object getObject() throws java.lang.ClassNotFoundException, java.io.IOException;
+    method public String getAlgorithm();
+    method public Object getObject() throws java.lang.ClassNotFoundException, java.io.IOException;
     method public byte[] getSignature();
     method public boolean verify(java.security.PublicKey, java.security.Signature) throws java.security.InvalidKeyException, java.security.SignatureException;
   }
 
-  public abstract deprecated class Signer extends java.security.Identity {
-    ctor protected Signer();
-    ctor public Signer(java.lang.String);
-    ctor public Signer(java.lang.String, java.security.IdentityScope) throws java.security.KeyManagementException;
-    method public java.security.PrivateKey getPrivateKey();
-    method public final void setKeyPair(java.security.KeyPair) throws java.security.InvalidParameterException, java.security.KeyException;
+  @Deprecated public abstract class Signer extends java.security.Identity {
+    ctor @Deprecated protected Signer();
+    ctor @Deprecated public Signer(String);
+    ctor @Deprecated public Signer(String, java.security.IdentityScope) throws java.security.KeyManagementException;
+    method @Deprecated public java.security.PrivateKey getPrivateKey();
+    method @Deprecated public final void setKeyPair(java.security.KeyPair) throws java.security.InvalidParameterException, java.security.KeyException;
   }
 
   public final class Timestamp implements java.io.Serializable {
@@ -64145,21 +64519,21 @@
 
   public class UnrecoverableEntryException extends java.security.GeneralSecurityException {
     ctor public UnrecoverableEntryException();
-    ctor public UnrecoverableEntryException(java.lang.String);
+    ctor public UnrecoverableEntryException(String);
   }
 
   public class UnrecoverableKeyException extends java.security.UnrecoverableEntryException {
     ctor public UnrecoverableKeyException();
-    ctor public UnrecoverableKeyException(java.lang.String);
+    ctor public UnrecoverableKeyException(String);
   }
 
   public final class UnresolvedPermission extends java.security.Permission implements java.io.Serializable {
-    ctor public UnresolvedPermission(java.lang.String, java.lang.String, java.lang.String, java.security.cert.Certificate[]);
-    method public java.lang.String getActions();
-    method public java.lang.String getUnresolvedActions();
+    ctor public UnresolvedPermission(String, String, String, java.security.cert.Certificate[]);
+    method public String getActions();
+    method public String getUnresolvedActions();
     method public java.security.cert.Certificate[] getUnresolvedCerts();
-    method public java.lang.String getUnresolvedName();
-    method public java.lang.String getUnresolvedType();
+    method public String getUnresolvedName();
+    method public String getUnresolvedType();
     method public boolean implies(java.security.Permission);
   }
 
@@ -64167,39 +64541,39 @@
 
 package java.security.acl {
 
-  public abstract interface Acl implements java.security.acl.Owner {
-    method public abstract boolean addEntry(java.security.Principal, java.security.acl.AclEntry) throws java.security.acl.NotOwnerException;
-    method public abstract boolean checkPermission(java.security.Principal, java.security.acl.Permission);
-    method public abstract java.util.Enumeration<java.security.acl.AclEntry> entries();
-    method public abstract java.lang.String getName();
-    method public abstract java.util.Enumeration<java.security.acl.Permission> getPermissions(java.security.Principal);
-    method public abstract boolean removeEntry(java.security.Principal, java.security.acl.AclEntry) throws java.security.acl.NotOwnerException;
-    method public abstract void setName(java.security.Principal, java.lang.String) throws java.security.acl.NotOwnerException;
-    method public abstract java.lang.String toString();
+  public interface Acl extends java.security.acl.Owner {
+    method public boolean addEntry(java.security.Principal, java.security.acl.AclEntry) throws java.security.acl.NotOwnerException;
+    method public boolean checkPermission(java.security.Principal, java.security.acl.Permission);
+    method public java.util.Enumeration<java.security.acl.AclEntry> entries();
+    method public String getName();
+    method public java.util.Enumeration<java.security.acl.Permission> getPermissions(java.security.Principal);
+    method public boolean removeEntry(java.security.Principal, java.security.acl.AclEntry) throws java.security.acl.NotOwnerException;
+    method public void setName(java.security.Principal, String) throws java.security.acl.NotOwnerException;
+    method public String toString();
   }
 
-  public abstract interface AclEntry implements java.lang.Cloneable {
-    method public abstract boolean addPermission(java.security.acl.Permission);
-    method public abstract boolean checkPermission(java.security.acl.Permission);
-    method public abstract java.lang.Object clone();
-    method public abstract java.security.Principal getPrincipal();
-    method public abstract boolean isNegative();
-    method public abstract java.util.Enumeration<java.security.acl.Permission> permissions();
-    method public abstract boolean removePermission(java.security.acl.Permission);
-    method public abstract void setNegativePermissions();
-    method public abstract boolean setPrincipal(java.security.Principal);
-    method public abstract java.lang.String toString();
+  public interface AclEntry extends java.lang.Cloneable {
+    method public boolean addPermission(java.security.acl.Permission);
+    method public boolean checkPermission(java.security.acl.Permission);
+    method public Object clone();
+    method public java.security.Principal getPrincipal();
+    method public boolean isNegative();
+    method public java.util.Enumeration<java.security.acl.Permission> permissions();
+    method public boolean removePermission(java.security.acl.Permission);
+    method public void setNegativePermissions();
+    method public boolean setPrincipal(java.security.Principal);
+    method public String toString();
   }
 
   public class AclNotFoundException extends java.lang.Exception {
     ctor public AclNotFoundException();
   }
 
-  public abstract interface Group implements java.security.Principal {
-    method public abstract boolean addMember(java.security.Principal);
-    method public abstract boolean isMember(java.security.Principal);
-    method public abstract java.util.Enumeration<? extends java.security.Principal> members();
-    method public abstract boolean removeMember(java.security.Principal);
+  public interface Group extends java.security.Principal {
+    method public boolean addMember(java.security.Principal);
+    method public boolean isMember(java.security.Principal);
+    method public java.util.Enumeration<? extends java.security.Principal> members();
+    method public boolean removeMember(java.security.Principal);
   }
 
   public class LastOwnerException extends java.lang.Exception {
@@ -64210,13 +64584,13 @@
     ctor public NotOwnerException();
   }
 
-  public abstract interface Owner {
-    method public abstract boolean addOwner(java.security.Principal, java.security.Principal) throws java.security.acl.NotOwnerException;
-    method public abstract boolean deleteOwner(java.security.Principal, java.security.Principal) throws java.security.acl.LastOwnerException, java.security.acl.NotOwnerException;
-    method public abstract boolean isOwner(java.security.Principal);
+  public interface Owner {
+    method public boolean addOwner(java.security.Principal, java.security.Principal) throws java.security.acl.NotOwnerException;
+    method public boolean deleteOwner(java.security.Principal, java.security.Principal) throws java.security.acl.LastOwnerException, java.security.acl.NotOwnerException;
+    method public boolean isOwner(java.security.Principal);
   }
 
-  public abstract interface Permission {
+  public interface Permission {
   }
 
 }
@@ -64224,22 +64598,20 @@
 package java.security.cert {
 
   public abstract class CRL {
-    ctor protected CRL(java.lang.String);
-    method public final java.lang.String getType();
+    ctor protected CRL(String);
+    method public final String getType();
     method public abstract boolean isRevoked(java.security.cert.Certificate);
-    method public abstract java.lang.String toString();
+    method public abstract String toString();
   }
 
   public class CRLException extends java.security.GeneralSecurityException {
     ctor public CRLException();
-    ctor public CRLException(java.lang.String);
-    ctor public CRLException(java.lang.String, java.lang.Throwable);
-    ctor public CRLException(java.lang.Throwable);
+    ctor public CRLException(String);
+    ctor public CRLException(String, Throwable);
+    ctor public CRLException(Throwable);
   }
 
-  public final class CRLReason extends java.lang.Enum {
-    method public static java.security.cert.CRLReason valueOf(java.lang.String);
-    method public static final java.security.cert.CRLReason[] values();
+  public enum CRLReason {
     enum_constant public static final java.security.cert.CRLReason AA_COMPROMISE;
     enum_constant public static final java.security.cert.CRLReason AFFILIATION_CHANGED;
     enum_constant public static final java.security.cert.CRLReason CA_COMPROMISE;
@@ -64253,48 +64625,48 @@
     enum_constant public static final java.security.cert.CRLReason UNUSED;
   }
 
-  public abstract interface CRLSelector implements java.lang.Cloneable {
-    method public abstract java.lang.Object clone();
-    method public abstract boolean match(java.security.cert.CRL);
+  public interface CRLSelector extends java.lang.Cloneable {
+    method public Object clone();
+    method public boolean match(java.security.cert.CRL);
   }
 
   public abstract class CertPath implements java.io.Serializable {
-    ctor protected CertPath(java.lang.String);
+    ctor protected CertPath(String);
     method public abstract java.util.List<? extends java.security.cert.Certificate> getCertificates();
     method public abstract byte[] getEncoded() throws java.security.cert.CertificateEncodingException;
-    method public abstract byte[] getEncoded(java.lang.String) throws java.security.cert.CertificateEncodingException;
+    method public abstract byte[] getEncoded(String) throws java.security.cert.CertificateEncodingException;
     method public abstract java.util.Iterator<java.lang.String> getEncodings();
-    method public java.lang.String getType();
-    method protected java.lang.Object writeReplace() throws java.io.ObjectStreamException;
+    method public String getType();
+    method protected Object writeReplace() throws java.io.ObjectStreamException;
   }
 
   protected static class CertPath.CertPathRep implements java.io.Serializable {
-    ctor protected CertPath.CertPathRep(java.lang.String, byte[]);
-    method protected java.lang.Object readResolve() throws java.io.ObjectStreamException;
+    ctor protected CertPath.CertPathRep(String, byte[]);
+    method protected Object readResolve() throws java.io.ObjectStreamException;
   }
 
   public class CertPathBuilder {
-    ctor protected CertPathBuilder(java.security.cert.CertPathBuilderSpi, java.security.Provider, java.lang.String);
+    ctor protected CertPathBuilder(java.security.cert.CertPathBuilderSpi, java.security.Provider, String);
     method public final java.security.cert.CertPathBuilderResult build(java.security.cert.CertPathParameters) throws java.security.cert.CertPathBuilderException, java.security.InvalidAlgorithmParameterException;
-    method public final java.lang.String getAlgorithm();
-    method public static final java.lang.String getDefaultType();
-    method public static java.security.cert.CertPathBuilder getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public final String getAlgorithm();
+    method public static final String getDefaultType();
+    method public static java.security.cert.CertPathBuilder getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static java.security.cert.CertPathBuilder getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static java.security.cert.CertPathBuilder getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
     method public final java.security.cert.CertPathChecker getRevocationChecker();
   }
 
   public class CertPathBuilderException extends java.security.GeneralSecurityException {
     ctor public CertPathBuilderException();
-    ctor public CertPathBuilderException(java.lang.String);
-    ctor public CertPathBuilderException(java.lang.Throwable);
-    ctor public CertPathBuilderException(java.lang.String, java.lang.Throwable);
+    ctor public CertPathBuilderException(String);
+    ctor public CertPathBuilderException(Throwable);
+    ctor public CertPathBuilderException(String, Throwable);
   }
 
-  public abstract interface CertPathBuilderResult implements java.lang.Cloneable {
-    method public abstract java.lang.Object clone();
-    method public abstract java.security.cert.CertPath getCertPath();
+  public interface CertPathBuilderResult extends java.lang.Cloneable {
+    method public Object clone();
+    method public java.security.cert.CertPath getCertPath();
   }
 
   public abstract class CertPathBuilderSpi {
@@ -64303,23 +64675,23 @@
     method public java.security.cert.CertPathChecker engineGetRevocationChecker();
   }
 
-  public abstract interface CertPathChecker {
-    method public abstract void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
-    method public abstract void init(boolean) throws java.security.cert.CertPathValidatorException;
-    method public abstract boolean isForwardCheckingSupported();
+  public interface CertPathChecker {
+    method public void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
+    method public void init(boolean) throws java.security.cert.CertPathValidatorException;
+    method public boolean isForwardCheckingSupported();
   }
 
-  public abstract interface CertPathParameters implements java.lang.Cloneable {
-    method public abstract java.lang.Object clone();
+  public interface CertPathParameters extends java.lang.Cloneable {
+    method public Object clone();
   }
 
   public class CertPathValidator {
-    ctor protected CertPathValidator(java.security.cert.CertPathValidatorSpi, java.security.Provider, java.lang.String);
-    method public final java.lang.String getAlgorithm();
-    method public static final java.lang.String getDefaultType();
-    method public static java.security.cert.CertPathValidator getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    ctor protected CertPathValidator(java.security.cert.CertPathValidatorSpi, java.security.Provider, String);
+    method public final String getAlgorithm();
+    method public static final String getDefaultType();
+    method public static java.security.cert.CertPathValidator getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static java.security.cert.CertPathValidator getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static java.security.cert.CertPathValidator getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
     method public final java.security.cert.CertPathChecker getRevocationChecker();
     method public final java.security.cert.CertPathValidatorResult validate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
@@ -64327,19 +64699,17 @@
 
   public class CertPathValidatorException extends java.security.GeneralSecurityException {
     ctor public CertPathValidatorException();
-    ctor public CertPathValidatorException(java.lang.String);
-    ctor public CertPathValidatorException(java.lang.Throwable);
-    ctor public CertPathValidatorException(java.lang.String, java.lang.Throwable);
-    ctor public CertPathValidatorException(java.lang.String, java.lang.Throwable, java.security.cert.CertPath, int);
-    ctor public CertPathValidatorException(java.lang.String, java.lang.Throwable, java.security.cert.CertPath, int, java.security.cert.CertPathValidatorException.Reason);
+    ctor public CertPathValidatorException(String);
+    ctor public CertPathValidatorException(Throwable);
+    ctor public CertPathValidatorException(String, Throwable);
+    ctor public CertPathValidatorException(String, Throwable, java.security.cert.CertPath, int);
+    ctor public CertPathValidatorException(String, Throwable, java.security.cert.CertPath, int, java.security.cert.CertPathValidatorException.Reason);
     method public java.security.cert.CertPath getCertPath();
     method public int getIndex();
     method public java.security.cert.CertPathValidatorException.Reason getReason();
   }
 
-  public static final class CertPathValidatorException.BasicReason extends java.lang.Enum implements java.security.cert.CertPathValidatorException.Reason {
-    method public static java.security.cert.CertPathValidatorException.BasicReason valueOf(java.lang.String);
-    method public static final java.security.cert.CertPathValidatorException.BasicReason[] values();
+  public enum CertPathValidatorException.BasicReason implements java.security.cert.CertPathValidatorException.Reason {
     enum_constant public static final java.security.cert.CertPathValidatorException.BasicReason ALGORITHM_CONSTRAINED;
     enum_constant public static final java.security.cert.CertPathValidatorException.BasicReason EXPIRED;
     enum_constant public static final java.security.cert.CertPathValidatorException.BasicReason INVALID_SIGNATURE;
@@ -64349,11 +64719,11 @@
     enum_constant public static final java.security.cert.CertPathValidatorException.BasicReason UNSPECIFIED;
   }
 
-  public static abstract interface CertPathValidatorException.Reason implements java.io.Serializable {
+  public static interface CertPathValidatorException.Reason extends java.io.Serializable {
   }
 
-  public abstract interface CertPathValidatorResult implements java.lang.Cloneable {
-    method public abstract java.lang.Object clone();
+  public interface CertPathValidatorResult extends java.lang.Cloneable {
+    method public Object clone();
   }
 
   public abstract class CertPathValidatorSpi {
@@ -64362,33 +64732,33 @@
     method public abstract java.security.cert.CertPathValidatorResult engineValidate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
   }
 
-  public abstract interface CertSelector implements java.lang.Cloneable {
-    method public abstract java.lang.Object clone();
-    method public abstract boolean match(java.security.cert.Certificate);
+  public interface CertSelector extends java.lang.Cloneable {
+    method public Object clone();
+    method public boolean match(java.security.cert.Certificate);
   }
 
   public class CertStore {
-    ctor protected CertStore(java.security.cert.CertStoreSpi, java.security.Provider, java.lang.String, java.security.cert.CertStoreParameters);
+    ctor protected CertStore(java.security.cert.CertStoreSpi, java.security.Provider, String, java.security.cert.CertStoreParameters);
     method public final java.util.Collection<? extends java.security.cert.CRL> getCRLs(java.security.cert.CRLSelector) throws java.security.cert.CertStoreException;
     method public final java.security.cert.CertStoreParameters getCertStoreParameters();
     method public final java.util.Collection<? extends java.security.cert.Certificate> getCertificates(java.security.cert.CertSelector) throws java.security.cert.CertStoreException;
-    method public static final java.lang.String getDefaultType();
-    method public static java.security.cert.CertStore getInstance(java.lang.String, java.security.cert.CertStoreParameters) throws java.security.InvalidAlgorithmParameterException, java.security.NoSuchAlgorithmException;
-    method public static java.security.cert.CertStore getInstance(java.lang.String, java.security.cert.CertStoreParameters, java.lang.String) throws java.security.InvalidAlgorithmParameterException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static java.security.cert.CertStore getInstance(java.lang.String, java.security.cert.CertStoreParameters, java.security.Provider) throws java.security.InvalidAlgorithmParameterException, java.security.NoSuchAlgorithmException;
+    method public static final String getDefaultType();
+    method public static java.security.cert.CertStore getInstance(String, java.security.cert.CertStoreParameters) throws java.security.InvalidAlgorithmParameterException, java.security.NoSuchAlgorithmException;
+    method public static java.security.cert.CertStore getInstance(String, java.security.cert.CertStoreParameters, String) throws java.security.InvalidAlgorithmParameterException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static java.security.cert.CertStore getInstance(String, java.security.cert.CertStoreParameters, java.security.Provider) throws java.security.InvalidAlgorithmParameterException, java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
-    method public final java.lang.String getType();
+    method public final String getType();
   }
 
   public class CertStoreException extends java.security.GeneralSecurityException {
     ctor public CertStoreException();
-    ctor public CertStoreException(java.lang.String);
-    ctor public CertStoreException(java.lang.Throwable);
-    ctor public CertStoreException(java.lang.String, java.lang.Throwable);
+    ctor public CertStoreException(String);
+    ctor public CertStoreException(Throwable);
+    ctor public CertStoreException(String, Throwable);
   }
 
-  public abstract interface CertStoreParameters implements java.lang.Cloneable {
-    method public abstract java.lang.Object clone();
+  public interface CertStoreParameters extends java.lang.Cloneable {
+    method public Object clone();
   }
 
   public abstract class CertStoreSpi {
@@ -64398,56 +64768,56 @@
   }
 
   public abstract class Certificate implements java.io.Serializable {
-    ctor protected Certificate(java.lang.String);
+    ctor protected Certificate(String);
     method public abstract byte[] getEncoded() throws java.security.cert.CertificateEncodingException;
     method public abstract java.security.PublicKey getPublicKey();
-    method public final java.lang.String getType();
-    method public abstract java.lang.String toString();
+    method public final String getType();
+    method public abstract String toString();
     method public abstract void verify(java.security.PublicKey) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
-    method public abstract void verify(java.security.PublicKey, java.lang.String) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
+    method public abstract void verify(java.security.PublicKey, String) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
     method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
-    method protected java.lang.Object writeReplace() throws java.io.ObjectStreamException;
+    method protected Object writeReplace() throws java.io.ObjectStreamException;
   }
 
   protected static class Certificate.CertificateRep implements java.io.Serializable {
-    ctor protected Certificate.CertificateRep(java.lang.String, byte[]);
-    method protected java.lang.Object readResolve() throws java.io.ObjectStreamException;
+    ctor protected Certificate.CertificateRep(String, byte[]);
+    method protected Object readResolve() throws java.io.ObjectStreamException;
   }
 
   public class CertificateEncodingException extends java.security.cert.CertificateException {
     ctor public CertificateEncodingException();
-    ctor public CertificateEncodingException(java.lang.String);
-    ctor public CertificateEncodingException(java.lang.String, java.lang.Throwable);
-    ctor public CertificateEncodingException(java.lang.Throwable);
+    ctor public CertificateEncodingException(String);
+    ctor public CertificateEncodingException(String, Throwable);
+    ctor public CertificateEncodingException(Throwable);
   }
 
   public class CertificateException extends java.security.GeneralSecurityException {
     ctor public CertificateException();
-    ctor public CertificateException(java.lang.String);
-    ctor public CertificateException(java.lang.String, java.lang.Throwable);
-    ctor public CertificateException(java.lang.Throwable);
+    ctor public CertificateException(String);
+    ctor public CertificateException(String, Throwable);
+    ctor public CertificateException(Throwable);
   }
 
   public class CertificateExpiredException extends java.security.cert.CertificateException {
     ctor public CertificateExpiredException();
-    ctor public CertificateExpiredException(java.lang.String);
+    ctor public CertificateExpiredException(String);
   }
 
   public class CertificateFactory {
-    ctor protected CertificateFactory(java.security.cert.CertificateFactorySpi, java.security.Provider, java.lang.String);
+    ctor protected CertificateFactory(java.security.cert.CertificateFactorySpi, java.security.Provider, String);
     method public final java.security.cert.CRL generateCRL(java.io.InputStream) throws java.security.cert.CRLException;
     method public final java.util.Collection<? extends java.security.cert.CRL> generateCRLs(java.io.InputStream) throws java.security.cert.CRLException;
     method public final java.security.cert.CertPath generateCertPath(java.io.InputStream) throws java.security.cert.CertificateException;
-    method public final java.security.cert.CertPath generateCertPath(java.io.InputStream, java.lang.String) throws java.security.cert.CertificateException;
+    method public final java.security.cert.CertPath generateCertPath(java.io.InputStream, String) throws java.security.cert.CertificateException;
     method public final java.security.cert.CertPath generateCertPath(java.util.List<? extends java.security.cert.Certificate>) throws java.security.cert.CertificateException;
     method public final java.security.cert.Certificate generateCertificate(java.io.InputStream) throws java.security.cert.CertificateException;
     method public final java.util.Collection<? extends java.security.cert.Certificate> generateCertificates(java.io.InputStream) throws java.security.cert.CertificateException;
     method public final java.util.Iterator<java.lang.String> getCertPathEncodings();
-    method public static final java.security.cert.CertificateFactory getInstance(java.lang.String) throws java.security.cert.CertificateException;
-    method public static final java.security.cert.CertificateFactory getInstance(java.lang.String, java.lang.String) throws java.security.cert.CertificateException, java.security.NoSuchProviderException;
-    method public static final java.security.cert.CertificateFactory getInstance(java.lang.String, java.security.Provider) throws java.security.cert.CertificateException;
+    method public static final java.security.cert.CertificateFactory getInstance(String) throws java.security.cert.CertificateException;
+    method public static final java.security.cert.CertificateFactory getInstance(String, String) throws java.security.cert.CertificateException, java.security.NoSuchProviderException;
+    method public static final java.security.cert.CertificateFactory getInstance(String, java.security.Provider) throws java.security.cert.CertificateException;
     method public final java.security.Provider getProvider();
-    method public final java.lang.String getType();
+    method public final String getType();
   }
 
   public abstract class CertificateFactorySpi {
@@ -64455,7 +64825,7 @@
     method public abstract java.security.cert.CRL engineGenerateCRL(java.io.InputStream) throws java.security.cert.CRLException;
     method public abstract java.util.Collection<? extends java.security.cert.CRL> engineGenerateCRLs(java.io.InputStream) throws java.security.cert.CRLException;
     method public java.security.cert.CertPath engineGenerateCertPath(java.io.InputStream) throws java.security.cert.CertificateException;
-    method public java.security.cert.CertPath engineGenerateCertPath(java.io.InputStream, java.lang.String) throws java.security.cert.CertificateException;
+    method public java.security.cert.CertPath engineGenerateCertPath(java.io.InputStream, String) throws java.security.cert.CertificateException;
     method public java.security.cert.CertPath engineGenerateCertPath(java.util.List<? extends java.security.cert.Certificate>) throws java.security.cert.CertificateException;
     method public abstract java.security.cert.Certificate engineGenerateCertificate(java.io.InputStream) throws java.security.cert.CertificateException;
     method public abstract java.util.Collection<? extends java.security.cert.Certificate> engineGenerateCertificates(java.io.InputStream) throws java.security.cert.CertificateException;
@@ -64464,20 +64834,20 @@
 
   public class CertificateNotYetValidException extends java.security.cert.CertificateException {
     ctor public CertificateNotYetValidException();
-    ctor public CertificateNotYetValidException(java.lang.String);
+    ctor public CertificateNotYetValidException(String);
   }
 
   public class CertificateParsingException extends java.security.cert.CertificateException {
     ctor public CertificateParsingException();
-    ctor public CertificateParsingException(java.lang.String);
-    ctor public CertificateParsingException(java.lang.String, java.lang.Throwable);
-    ctor public CertificateParsingException(java.lang.Throwable);
+    ctor public CertificateParsingException(String);
+    ctor public CertificateParsingException(String, Throwable);
+    ctor public CertificateParsingException(Throwable);
   }
 
   public class CertificateRevokedException extends java.security.cert.CertificateException {
-    ctor public CertificateRevokedException(java.util.Date, java.security.cert.CRLReason, javax.security.auth.x500.X500Principal, java.util.Map<java.lang.String, java.security.cert.Extension>);
+    ctor public CertificateRevokedException(java.util.Date, java.security.cert.CRLReason, javax.security.auth.x500.X500Principal, java.util.Map<java.lang.String,java.security.cert.Extension>);
     method public javax.security.auth.x500.X500Principal getAuthorityName();
-    method public java.util.Map<java.lang.String, java.security.cert.Extension> getExtensions();
+    method public java.util.Map<java.lang.String,java.security.cert.Extension> getExtensions();
     method public java.util.Date getInvalidityDate();
     method public java.util.Date getRevocationDate();
     method public java.security.cert.CRLReason getRevocationReason();
@@ -64486,24 +64856,24 @@
   public class CollectionCertStoreParameters implements java.security.cert.CertStoreParameters {
     ctor public CollectionCertStoreParameters(java.util.Collection<?>);
     ctor public CollectionCertStoreParameters();
-    method public java.lang.Object clone();
+    method public Object clone();
     method public java.util.Collection<?> getCollection();
   }
 
-  public abstract interface Extension {
-    method public abstract void encode(java.io.OutputStream) throws java.io.IOException;
-    method public abstract java.lang.String getId();
-    method public abstract byte[] getValue();
-    method public abstract boolean isCritical();
+  public interface Extension {
+    method public void encode(java.io.OutputStream) throws java.io.IOException;
+    method public String getId();
+    method public byte[] getValue();
+    method public boolean isCritical();
   }
 
   public class LDAPCertStoreParameters implements java.security.cert.CertStoreParameters {
-    ctor public LDAPCertStoreParameters(java.lang.String, int);
-    ctor public LDAPCertStoreParameters(java.lang.String);
+    ctor public LDAPCertStoreParameters(String, int);
+    ctor public LDAPCertStoreParameters(String);
     ctor public LDAPCertStoreParameters();
-    method public java.lang.Object clone();
+    method public Object clone();
     method public int getPort();
-    method public java.lang.String getServerName();
+    method public String getServerName();
   }
 
   public class PKIXBuilderParameters extends java.security.cert.PKIXParameters {
@@ -64522,13 +64892,13 @@
     ctor protected PKIXCertPathChecker();
     method public abstract void check(java.security.cert.Certificate, java.util.Collection<java.lang.String>) throws java.security.cert.CertPathValidatorException;
     method public void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
-    method public java.lang.Object clone();
+    method public Object clone();
     method public abstract java.util.Set<java.lang.String> getSupportedExtensions();
   }
 
   public class PKIXCertPathValidatorResult implements java.security.cert.CertPathValidatorResult {
     ctor public PKIXCertPathValidatorResult(java.security.cert.TrustAnchor, java.security.cert.PolicyNode, java.security.PublicKey);
-    method public java.lang.Object clone();
+    method public Object clone();
     method public java.security.cert.PolicyNode getPolicyTree();
     method public java.security.PublicKey getPublicKey();
     method public java.security.cert.TrustAnchor getTrustAnchor();
@@ -64539,13 +64909,13 @@
     ctor public PKIXParameters(java.security.KeyStore) throws java.security.InvalidAlgorithmParameterException, java.security.KeyStoreException;
     method public void addCertPathChecker(java.security.cert.PKIXCertPathChecker);
     method public void addCertStore(java.security.cert.CertStore);
-    method public java.lang.Object clone();
+    method public Object clone();
     method public java.util.List<java.security.cert.PKIXCertPathChecker> getCertPathCheckers();
     method public java.util.List<java.security.cert.CertStore> getCertStores();
     method public java.util.Date getDate();
     method public java.util.Set<java.lang.String> getInitialPolicies();
     method public boolean getPolicyQualifiersRejected();
-    method public java.lang.String getSigProvider();
+    method public String getSigProvider();
     method public java.security.cert.CertSelector getTargetCertConstraints();
     method public java.util.Set<java.security.cert.TrustAnchor> getTrustAnchors();
     method public boolean isAnyPolicyInhibited();
@@ -64561,14 +64931,12 @@
     method public void setPolicyMappingInhibited(boolean);
     method public void setPolicyQualifiersRejected(boolean);
     method public void setRevocationEnabled(boolean);
-    method public void setSigProvider(java.lang.String);
+    method public void setSigProvider(String);
     method public void setTargetCertConstraints(java.security.cert.CertSelector);
     method public void setTrustAnchors(java.util.Set<java.security.cert.TrustAnchor>) throws java.security.InvalidAlgorithmParameterException;
   }
 
-  public final class PKIXReason extends java.lang.Enum implements java.security.cert.CertPathValidatorException.Reason {
-    method public static java.security.cert.PKIXReason valueOf(java.lang.String);
-    method public static final java.security.cert.PKIXReason[] values();
+  public enum PKIXReason implements java.security.cert.CertPathValidatorException.Reason {
     enum_constant public static final java.security.cert.PKIXReason INVALID_KEY_USAGE;
     enum_constant public static final java.security.cert.PKIXReason INVALID_NAME;
     enum_constant public static final java.security.cert.PKIXReason INVALID_POLICY;
@@ -64585,48 +64953,46 @@
     method public java.util.List<java.security.cert.Extension> getOcspExtensions();
     method public java.net.URI getOcspResponder();
     method public java.security.cert.X509Certificate getOcspResponderCert();
-    method public java.util.Map<java.security.cert.X509Certificate, byte[]> getOcspResponses();
+    method public java.util.Map<java.security.cert.X509Certificate,byte[]> getOcspResponses();
     method public java.util.Set<java.security.cert.PKIXRevocationChecker.Option> getOptions();
     method public abstract java.util.List<java.security.cert.CertPathValidatorException> getSoftFailExceptions();
     method public void setOcspExtensions(java.util.List<java.security.cert.Extension>);
     method public void setOcspResponder(java.net.URI);
     method public void setOcspResponderCert(java.security.cert.X509Certificate);
-    method public void setOcspResponses(java.util.Map<java.security.cert.X509Certificate, byte[]>);
+    method public void setOcspResponses(java.util.Map<java.security.cert.X509Certificate,byte[]>);
     method public void setOptions(java.util.Set<java.security.cert.PKIXRevocationChecker.Option>);
   }
 
-  public static final class PKIXRevocationChecker.Option extends java.lang.Enum {
-    method public static java.security.cert.PKIXRevocationChecker.Option valueOf(java.lang.String);
-    method public static final java.security.cert.PKIXRevocationChecker.Option[] values();
+  public enum PKIXRevocationChecker.Option {
     enum_constant public static final java.security.cert.PKIXRevocationChecker.Option NO_FALLBACK;
     enum_constant public static final java.security.cert.PKIXRevocationChecker.Option ONLY_END_ENTITY;
     enum_constant public static final java.security.cert.PKIXRevocationChecker.Option PREFER_CRLS;
     enum_constant public static final java.security.cert.PKIXRevocationChecker.Option SOFT_FAIL;
   }
 
-  public abstract interface PolicyNode {
-    method public abstract java.util.Iterator<? extends java.security.cert.PolicyNode> getChildren();
-    method public abstract int getDepth();
-    method public abstract java.util.Set<java.lang.String> getExpectedPolicies();
-    method public abstract java.security.cert.PolicyNode getParent();
-    method public abstract java.util.Set<? extends java.security.cert.PolicyQualifierInfo> getPolicyQualifiers();
-    method public abstract java.lang.String getValidPolicy();
-    method public abstract boolean isCritical();
+  public interface PolicyNode {
+    method public java.util.Iterator<? extends java.security.cert.PolicyNode> getChildren();
+    method public int getDepth();
+    method public java.util.Set<java.lang.String> getExpectedPolicies();
+    method public java.security.cert.PolicyNode getParent();
+    method public java.util.Set<? extends java.security.cert.PolicyQualifierInfo> getPolicyQualifiers();
+    method public String getValidPolicy();
+    method public boolean isCritical();
   }
 
   public class PolicyQualifierInfo {
     ctor public PolicyQualifierInfo(byte[]) throws java.io.IOException;
     method public final byte[] getEncoded();
     method public final byte[] getPolicyQualifier();
-    method public final java.lang.String getPolicyQualifierId();
+    method public final String getPolicyQualifierId();
   }
 
   public class TrustAnchor {
     ctor public TrustAnchor(java.security.cert.X509Certificate, byte[]);
     ctor public TrustAnchor(javax.security.auth.x500.X500Principal, java.security.PublicKey, byte[]);
-    ctor public TrustAnchor(java.lang.String, java.security.PublicKey, byte[]);
+    ctor public TrustAnchor(String, java.security.PublicKey, byte[]);
     method public final javax.security.auth.x500.X500Principal getCA();
-    method public final java.lang.String getCAName();
+    method public final String getCAName();
     method public final java.security.PublicKey getCAPublicKey();
     method public final byte[] getNameConstraints();
     method public final java.security.cert.X509Certificate getTrustedCert();
@@ -64641,15 +65007,15 @@
     method public abstract java.security.cert.X509CRLEntry getRevokedCertificate(java.math.BigInteger);
     method public java.security.cert.X509CRLEntry getRevokedCertificate(java.security.cert.X509Certificate);
     method public abstract java.util.Set<? extends java.security.cert.X509CRLEntry> getRevokedCertificates();
-    method public abstract java.lang.String getSigAlgName();
-    method public abstract java.lang.String getSigAlgOID();
+    method public abstract String getSigAlgName();
+    method public abstract String getSigAlgOID();
     method public abstract byte[] getSigAlgParams();
     method public abstract byte[] getSignature();
     method public abstract byte[] getTBSCertList() throws java.security.cert.CRLException;
     method public abstract java.util.Date getThisUpdate();
     method public abstract int getVersion();
     method public abstract void verify(java.security.PublicKey) throws java.security.cert.CRLException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
-    method public abstract void verify(java.security.PublicKey, java.lang.String) throws java.security.cert.CRLException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
+    method public abstract void verify(java.security.PublicKey, String) throws java.security.cert.CRLException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
     method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CRLException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
   }
 
@@ -64661,15 +65027,15 @@
     method public java.security.cert.CRLReason getRevocationReason();
     method public abstract java.math.BigInteger getSerialNumber();
     method public abstract boolean hasExtensions();
-    method public abstract java.lang.String toString();
+    method public abstract String toString();
   }
 
   public class X509CRLSelector implements java.security.cert.CRLSelector {
     ctor public X509CRLSelector();
     method public void addIssuer(javax.security.auth.x500.X500Principal);
-    method public void addIssuerName(java.lang.String) throws java.io.IOException;
+    method public void addIssuerName(String) throws java.io.IOException;
     method public void addIssuerName(byte[]) throws java.io.IOException;
-    method public java.lang.Object clone();
+    method public Object clone();
     method public java.security.cert.X509Certificate getCertificateChecking();
     method public java.util.Date getDateAndTime();
     method public java.util.Collection<java.lang.Object> getIssuerNames();
@@ -64687,11 +65053,11 @@
 
   public class X509CertSelector implements java.security.cert.CertSelector {
     ctor public X509CertSelector();
-    method public void addPathToName(int, java.lang.String) throws java.io.IOException;
+    method public void addPathToName(int, String) throws java.io.IOException;
     method public void addPathToName(int, byte[]) throws java.io.IOException;
-    method public void addSubjectAlternativeName(int, java.lang.String) throws java.io.IOException;
+    method public void addSubjectAlternativeName(int, String) throws java.io.IOException;
     method public void addSubjectAlternativeName(int, byte[]) throws java.io.IOException;
-    method public java.lang.Object clone();
+    method public Object clone();
     method public byte[] getAuthorityKeyIdentifier();
     method public int getBasicConstraints();
     method public java.security.cert.X509Certificate getCertificate();
@@ -64699,7 +65065,7 @@
     method public java.util.Set<java.lang.String> getExtendedKeyUsage();
     method public javax.security.auth.x500.X500Principal getIssuer();
     method public byte[] getIssuerAsBytes() throws java.io.IOException;
-    method public java.lang.String getIssuerAsString();
+    method public String getIssuerAsString();
     method public boolean[] getKeyUsage();
     method public boolean getMatchAllSubjectAltNames();
     method public byte[] getNameConstraints();
@@ -64710,10 +65076,10 @@
     method public javax.security.auth.x500.X500Principal getSubject();
     method public java.util.Collection<java.util.List<?>> getSubjectAlternativeNames();
     method public byte[] getSubjectAsBytes() throws java.io.IOException;
-    method public java.lang.String getSubjectAsString();
+    method public String getSubjectAsString();
     method public byte[] getSubjectKeyIdentifier();
     method public java.security.PublicKey getSubjectPublicKey();
-    method public java.lang.String getSubjectPublicKeyAlgID();
+    method public String getSubjectPublicKeyAlgID();
     method public boolean match(java.security.cert.Certificate);
     method public void setAuthorityKeyIdentifier(byte[]);
     method public void setBasicConstraints(int);
@@ -64721,7 +65087,7 @@
     method public void setCertificateValid(java.util.Date);
     method public void setExtendedKeyUsage(java.util.Set<java.lang.String>) throws java.io.IOException;
     method public void setIssuer(javax.security.auth.x500.X500Principal);
-    method public void setIssuer(java.lang.String) throws java.io.IOException;
+    method public void setIssuer(String) throws java.io.IOException;
     method public void setIssuer(byte[]) throws java.io.IOException;
     method public void setKeyUsage(boolean[]);
     method public void setMatchAllSubjectAltNames(boolean);
@@ -64731,13 +65097,13 @@
     method public void setPrivateKeyValid(java.util.Date);
     method public void setSerialNumber(java.math.BigInteger);
     method public void setSubject(javax.security.auth.x500.X500Principal);
-    method public void setSubject(java.lang.String) throws java.io.IOException;
+    method public void setSubject(String) throws java.io.IOException;
     method public void setSubject(byte[]) throws java.io.IOException;
     method public void setSubjectAlternativeNames(java.util.Collection<java.util.List<?>>) throws java.io.IOException;
     method public void setSubjectKeyIdentifier(byte[]);
     method public void setSubjectPublicKey(java.security.PublicKey);
     method public void setSubjectPublicKey(byte[]) throws java.io.IOException;
-    method public void setSubjectPublicKeyAlgID(java.lang.String) throws java.io.IOException;
+    method public void setSubjectPublicKeyAlgID(String) throws java.io.IOException;
   }
 
   public abstract class X509Certificate extends java.security.cert.Certificate implements java.security.cert.X509Extension {
@@ -64754,8 +65120,8 @@
     method public abstract java.util.Date getNotAfter();
     method public abstract java.util.Date getNotBefore();
     method public abstract java.math.BigInteger getSerialNumber();
-    method public abstract java.lang.String getSigAlgName();
-    method public abstract java.lang.String getSigAlgOID();
+    method public abstract String getSigAlgName();
+    method public abstract String getSigAlgOID();
     method public abstract byte[] getSigAlgParams();
     method public abstract byte[] getSignature();
     method public java.util.Collection<java.util.List<?>> getSubjectAlternativeNames() throws java.security.cert.CertificateParsingException;
@@ -64766,88 +65132,88 @@
     method public abstract int getVersion();
   }
 
-  public abstract interface X509Extension {
-    method public abstract java.util.Set<java.lang.String> getCriticalExtensionOIDs();
-    method public abstract byte[] getExtensionValue(java.lang.String);
-    method public abstract java.util.Set<java.lang.String> getNonCriticalExtensionOIDs();
-    method public abstract boolean hasUnsupportedCriticalExtension();
+  public interface X509Extension {
+    method public java.util.Set<java.lang.String> getCriticalExtensionOIDs();
+    method public byte[] getExtensionValue(String);
+    method public java.util.Set<java.lang.String> getNonCriticalExtensionOIDs();
+    method public boolean hasUnsupportedCriticalExtension();
   }
 
 }
 
 package java.security.interfaces {
 
-  public abstract interface DSAKey {
-    method public abstract java.security.interfaces.DSAParams getParams();
+  public interface DSAKey {
+    method public java.security.interfaces.DSAParams getParams();
   }
 
-  public abstract interface DSAKeyPairGenerator {
-    method public abstract void initialize(java.security.interfaces.DSAParams, java.security.SecureRandom) throws java.security.InvalidParameterException;
-    method public abstract void initialize(int, boolean, java.security.SecureRandom) throws java.security.InvalidParameterException;
+  public interface DSAKeyPairGenerator {
+    method public void initialize(java.security.interfaces.DSAParams, java.security.SecureRandom) throws java.security.InvalidParameterException;
+    method public void initialize(int, boolean, java.security.SecureRandom) throws java.security.InvalidParameterException;
   }
 
-  public abstract interface DSAParams {
-    method public abstract java.math.BigInteger getG();
-    method public abstract java.math.BigInteger getP();
-    method public abstract java.math.BigInteger getQ();
+  public interface DSAParams {
+    method public java.math.BigInteger getG();
+    method public java.math.BigInteger getP();
+    method public java.math.BigInteger getQ();
   }
 
-  public abstract interface DSAPrivateKey implements java.security.interfaces.DSAKey java.security.PrivateKey {
-    method public abstract java.math.BigInteger getX();
+  public interface DSAPrivateKey extends java.security.interfaces.DSAKey java.security.PrivateKey {
+    method public java.math.BigInteger getX();
     field public static final long serialVersionUID = 7776497482533790279L; // 0x6bebab423b256247L
   }
 
-  public abstract interface DSAPublicKey implements java.security.interfaces.DSAKey java.security.PublicKey {
-    method public abstract java.math.BigInteger getY();
+  public interface DSAPublicKey extends java.security.interfaces.DSAKey java.security.PublicKey {
+    method public java.math.BigInteger getY();
     field public static final long serialVersionUID = 1234526332779022332L; // 0x1121eb28ab28c7fcL
   }
 
-  public abstract interface ECKey {
-    method public abstract java.security.spec.ECParameterSpec getParams();
+  public interface ECKey {
+    method public java.security.spec.ECParameterSpec getParams();
   }
 
-  public abstract interface ECPrivateKey implements java.security.interfaces.ECKey java.security.PrivateKey {
-    method public abstract java.math.BigInteger getS();
+  public interface ECPrivateKey extends java.security.PrivateKey java.security.interfaces.ECKey {
+    method public java.math.BigInteger getS();
     field public static final long serialVersionUID = -7896394956925609184L; // 0x926a5e9fa2435b20L
   }
 
-  public abstract interface ECPublicKey implements java.security.interfaces.ECKey java.security.PublicKey {
-    method public abstract java.security.spec.ECPoint getW();
+  public interface ECPublicKey extends java.security.PublicKey java.security.interfaces.ECKey {
+    method public java.security.spec.ECPoint getW();
     field public static final long serialVersionUID = -3314988629879632826L; // 0xd1fecb679990cc46L
   }
 
-  public abstract interface RSAKey {
-    method public abstract java.math.BigInteger getModulus();
+  public interface RSAKey {
+    method public java.math.BigInteger getModulus();
   }
 
-  public abstract interface RSAMultiPrimePrivateCrtKey implements java.security.interfaces.RSAPrivateKey {
-    method public abstract java.math.BigInteger getCrtCoefficient();
-    method public abstract java.security.spec.RSAOtherPrimeInfo[] getOtherPrimeInfo();
-    method public abstract java.math.BigInteger getPrimeExponentP();
-    method public abstract java.math.BigInteger getPrimeExponentQ();
-    method public abstract java.math.BigInteger getPrimeP();
-    method public abstract java.math.BigInteger getPrimeQ();
-    method public abstract java.math.BigInteger getPublicExponent();
+  public interface RSAMultiPrimePrivateCrtKey extends java.security.interfaces.RSAPrivateKey {
+    method public java.math.BigInteger getCrtCoefficient();
+    method public java.security.spec.RSAOtherPrimeInfo[] getOtherPrimeInfo();
+    method public java.math.BigInteger getPrimeExponentP();
+    method public java.math.BigInteger getPrimeExponentQ();
+    method public java.math.BigInteger getPrimeP();
+    method public java.math.BigInteger getPrimeQ();
+    method public java.math.BigInteger getPublicExponent();
     field public static final long serialVersionUID = 618058533534628008L; // 0x893c8f62dbaf8a8L
   }
 
-  public abstract interface RSAPrivateCrtKey implements java.security.interfaces.RSAPrivateKey {
-    method public abstract java.math.BigInteger getCrtCoefficient();
-    method public abstract java.math.BigInteger getPrimeExponentP();
-    method public abstract java.math.BigInteger getPrimeExponentQ();
-    method public abstract java.math.BigInteger getPrimeP();
-    method public abstract java.math.BigInteger getPrimeQ();
-    method public abstract java.math.BigInteger getPublicExponent();
+  public interface RSAPrivateCrtKey extends java.security.interfaces.RSAPrivateKey {
+    method public java.math.BigInteger getCrtCoefficient();
+    method public java.math.BigInteger getPrimeExponentP();
+    method public java.math.BigInteger getPrimeExponentQ();
+    method public java.math.BigInteger getPrimeP();
+    method public java.math.BigInteger getPrimeQ();
+    method public java.math.BigInteger getPublicExponent();
     field public static final long serialVersionUID = -5682214253527700368L; // 0xb124b83df8d1ec70L
   }
 
-  public abstract interface RSAPrivateKey implements java.security.PrivateKey java.security.interfaces.RSAKey {
-    method public abstract java.math.BigInteger getPrivateExponent();
+  public interface RSAPrivateKey extends java.security.PrivateKey java.security.interfaces.RSAKey {
+    method public java.math.BigInteger getPrivateExponent();
     field public static final long serialVersionUID = 5187144804936595022L; // 0x47fc70b7a8c2364eL
   }
 
-  public abstract interface RSAPublicKey implements java.security.PublicKey java.security.interfaces.RSAKey {
-    method public abstract java.math.BigInteger getPublicExponent();
+  public interface RSAPublicKey extends java.security.PublicKey java.security.interfaces.RSAKey {
+    method public java.math.BigInteger getPublicExponent();
     field public static final long serialVersionUID = -8727434096241101194L; // 0x86e1ecedeceab676L
   }
 
@@ -64855,7 +65221,7 @@
 
 package java.security.spec {
 
-  public abstract interface AlgorithmParameterSpec {
+  public interface AlgorithmParameterSpec {
   }
 
   public class DSAParameterSpec implements java.security.spec.AlgorithmParameterSpec java.security.interfaces.DSAParams {
@@ -64881,8 +65247,8 @@
     method public java.math.BigInteger getY();
   }
 
-  public abstract interface ECField {
-    method public abstract int getFieldSize();
+  public interface ECField {
+    method public int getFieldSize();
   }
 
   public class ECFieldF2m implements java.security.spec.ECField {
@@ -64902,8 +65268,8 @@
   }
 
   public class ECGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
-    ctor public ECGenParameterSpec(java.lang.String);
-    method public java.lang.String getName();
+    ctor public ECGenParameterSpec(String);
+    method public String getName();
   }
 
   public class ECParameterSpec implements java.security.spec.AlgorithmParameterSpec {
@@ -64945,27 +65311,27 @@
   public abstract class EncodedKeySpec implements java.security.spec.KeySpec {
     ctor public EncodedKeySpec(byte[]);
     method public byte[] getEncoded();
-    method public abstract java.lang.String getFormat();
+    method public abstract String getFormat();
   }
 
   public class InvalidKeySpecException extends java.security.GeneralSecurityException {
     ctor public InvalidKeySpecException();
-    ctor public InvalidKeySpecException(java.lang.String);
-    ctor public InvalidKeySpecException(java.lang.String, java.lang.Throwable);
-    ctor public InvalidKeySpecException(java.lang.Throwable);
+    ctor public InvalidKeySpecException(String);
+    ctor public InvalidKeySpecException(String, Throwable);
+    ctor public InvalidKeySpecException(Throwable);
   }
 
   public class InvalidParameterSpecException extends java.security.GeneralSecurityException {
     ctor public InvalidParameterSpecException();
-    ctor public InvalidParameterSpecException(java.lang.String);
+    ctor public InvalidParameterSpecException(String);
   }
 
-  public abstract interface KeySpec {
+  public interface KeySpec {
   }
 
   public class MGF1ParameterSpec implements java.security.spec.AlgorithmParameterSpec {
-    ctor public MGF1ParameterSpec(java.lang.String);
-    method public java.lang.String getDigestAlgorithm();
+    ctor public MGF1ParameterSpec(String);
+    method public String getDigestAlgorithm();
     field public static final java.security.spec.MGF1ParameterSpec SHA1;
     field public static final java.security.spec.MGF1ParameterSpec SHA224;
     field public static final java.security.spec.MGF1ParameterSpec SHA256;
@@ -64975,14 +65341,14 @@
 
   public class PKCS8EncodedKeySpec extends java.security.spec.EncodedKeySpec {
     ctor public PKCS8EncodedKeySpec(byte[]);
-    method public final java.lang.String getFormat();
+    method public final String getFormat();
   }
 
   public class PSSParameterSpec implements java.security.spec.AlgorithmParameterSpec {
-    ctor public PSSParameterSpec(java.lang.String, java.lang.String, java.security.spec.AlgorithmParameterSpec, int, int);
+    ctor public PSSParameterSpec(String, String, java.security.spec.AlgorithmParameterSpec, int, int);
     ctor public PSSParameterSpec(int);
-    method public java.lang.String getDigestAlgorithm();
-    method public java.lang.String getMGFAlgorithm();
+    method public String getDigestAlgorithm();
+    method public String getMGFAlgorithm();
     method public java.security.spec.AlgorithmParameterSpec getMGFParameters();
     method public int getSaltLength();
     method public int getTrailerField();
@@ -65039,242 +65405,240 @@
 
   public class X509EncodedKeySpec extends java.security.spec.EncodedKeySpec {
     ctor public X509EncodedKeySpec(byte[]);
-    method public final java.lang.String getFormat();
+    method public final String getFormat();
   }
 
 }
 
 package java.sql {
 
-  public abstract interface Array {
-    method public abstract void free() throws java.sql.SQLException;
-    method public abstract java.lang.Object getArray() throws java.sql.SQLException;
-    method public abstract java.lang.Object getArray(java.util.Map<java.lang.String, java.lang.Class<?>>) throws java.sql.SQLException;
-    method public abstract java.lang.Object getArray(long, int) throws java.sql.SQLException;
-    method public abstract java.lang.Object getArray(long, int, java.util.Map<java.lang.String, java.lang.Class<?>>) throws java.sql.SQLException;
-    method public abstract int getBaseType() throws java.sql.SQLException;
-    method public abstract java.lang.String getBaseTypeName() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getResultSet() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getResultSet(java.util.Map<java.lang.String, java.lang.Class<?>>) throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getResultSet(long, int) throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getResultSet(long, int, java.util.Map<java.lang.String, java.lang.Class<?>>) throws java.sql.SQLException;
+  public interface Array {
+    method public void free() throws java.sql.SQLException;
+    method public Object getArray() throws java.sql.SQLException;
+    method public Object getArray(java.util.Map<java.lang.String,java.lang.Class<?>>) throws java.sql.SQLException;
+    method public Object getArray(long, int) throws java.sql.SQLException;
+    method public Object getArray(long, int, java.util.Map<java.lang.String,java.lang.Class<?>>) throws java.sql.SQLException;
+    method public int getBaseType() throws java.sql.SQLException;
+    method public String getBaseTypeName() throws java.sql.SQLException;
+    method public java.sql.ResultSet getResultSet() throws java.sql.SQLException;
+    method public java.sql.ResultSet getResultSet(java.util.Map<java.lang.String,java.lang.Class<?>>) throws java.sql.SQLException;
+    method public java.sql.ResultSet getResultSet(long, int) throws java.sql.SQLException;
+    method public java.sql.ResultSet getResultSet(long, int, java.util.Map<java.lang.String,java.lang.Class<?>>) throws java.sql.SQLException;
   }
 
   public class BatchUpdateException extends java.sql.SQLException {
-    ctor public BatchUpdateException(java.lang.String, java.lang.String, int, int[]);
-    ctor public BatchUpdateException(java.lang.String, java.lang.String, int[]);
-    ctor public BatchUpdateException(java.lang.String, int[]);
+    ctor public BatchUpdateException(String, String, int, int[]);
+    ctor public BatchUpdateException(String, String, int[]);
+    ctor public BatchUpdateException(String, int[]);
     ctor public BatchUpdateException(int[]);
     ctor public BatchUpdateException();
-    ctor public BatchUpdateException(java.lang.Throwable);
-    ctor public BatchUpdateException(int[], java.lang.Throwable);
-    ctor public BatchUpdateException(java.lang.String, int[], java.lang.Throwable);
-    ctor public BatchUpdateException(java.lang.String, java.lang.String, int[], java.lang.Throwable);
-    ctor public BatchUpdateException(java.lang.String, java.lang.String, int, int[], java.lang.Throwable);
+    ctor public BatchUpdateException(Throwable);
+    ctor public BatchUpdateException(int[], Throwable);
+    ctor public BatchUpdateException(String, int[], Throwable);
+    ctor public BatchUpdateException(String, String, int[], Throwable);
+    ctor public BatchUpdateException(String, String, int, int[], Throwable);
     method public int[] getUpdateCounts();
   }
 
-  public abstract interface Blob {
-    method public abstract void free() throws java.sql.SQLException;
-    method public abstract java.io.InputStream getBinaryStream() throws java.sql.SQLException;
-    method public abstract java.io.InputStream getBinaryStream(long, long) throws java.sql.SQLException;
-    method public abstract byte[] getBytes(long, int) throws java.sql.SQLException;
-    method public abstract long length() throws java.sql.SQLException;
-    method public abstract long position(byte[], long) throws java.sql.SQLException;
-    method public abstract long position(java.sql.Blob, long) throws java.sql.SQLException;
-    method public abstract java.io.OutputStream setBinaryStream(long) throws java.sql.SQLException;
-    method public abstract int setBytes(long, byte[]) throws java.sql.SQLException;
-    method public abstract int setBytes(long, byte[], int, int) throws java.sql.SQLException;
-    method public abstract void truncate(long) throws java.sql.SQLException;
+  public interface Blob {
+    method public void free() throws java.sql.SQLException;
+    method public java.io.InputStream getBinaryStream() throws java.sql.SQLException;
+    method public java.io.InputStream getBinaryStream(long, long) throws java.sql.SQLException;
+    method public byte[] getBytes(long, int) throws java.sql.SQLException;
+    method public long length() throws java.sql.SQLException;
+    method public long position(byte[], long) throws java.sql.SQLException;
+    method public long position(java.sql.Blob, long) throws java.sql.SQLException;
+    method public java.io.OutputStream setBinaryStream(long) throws java.sql.SQLException;
+    method public int setBytes(long, byte[]) throws java.sql.SQLException;
+    method public int setBytes(long, byte[], int, int) throws java.sql.SQLException;
+    method public void truncate(long) throws java.sql.SQLException;
   }
 
-  public abstract interface CallableStatement implements java.sql.PreparedStatement {
-    method public abstract java.sql.Array getArray(int) throws java.sql.SQLException;
-    method public abstract java.sql.Array getArray(java.lang.String) throws java.sql.SQLException;
-    method public abstract deprecated java.math.BigDecimal getBigDecimal(int, int) throws java.sql.SQLException;
-    method public abstract java.math.BigDecimal getBigDecimal(int) throws java.sql.SQLException;
-    method public abstract java.math.BigDecimal getBigDecimal(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Blob getBlob(int) throws java.sql.SQLException;
-    method public abstract java.sql.Blob getBlob(java.lang.String) throws java.sql.SQLException;
-    method public abstract boolean getBoolean(int) throws java.sql.SQLException;
-    method public abstract boolean getBoolean(java.lang.String) throws java.sql.SQLException;
-    method public abstract byte getByte(int) throws java.sql.SQLException;
-    method public abstract byte getByte(java.lang.String) throws java.sql.SQLException;
-    method public abstract byte[] getBytes(int) throws java.sql.SQLException;
-    method public abstract byte[] getBytes(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.io.Reader getCharacterStream(int) throws java.sql.SQLException;
-    method public abstract java.io.Reader getCharacterStream(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Clob getClob(int) throws java.sql.SQLException;
-    method public abstract java.sql.Clob getClob(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Date getDate(int) throws java.sql.SQLException;
-    method public abstract java.sql.Date getDate(int, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract java.sql.Date getDate(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Date getDate(java.lang.String, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract double getDouble(int) throws java.sql.SQLException;
-    method public abstract double getDouble(java.lang.String) throws java.sql.SQLException;
-    method public abstract float getFloat(int) throws java.sql.SQLException;
-    method public abstract float getFloat(java.lang.String) throws java.sql.SQLException;
-    method public abstract int getInt(int) throws java.sql.SQLException;
-    method public abstract int getInt(java.lang.String) throws java.sql.SQLException;
-    method public abstract long getLong(int) throws java.sql.SQLException;
-    method public abstract long getLong(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.io.Reader getNCharacterStream(int) throws java.sql.SQLException;
-    method public abstract java.io.Reader getNCharacterStream(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.NClob getNClob(int) throws java.sql.SQLException;
-    method public abstract java.sql.NClob getNClob(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.lang.String getNString(int) throws java.sql.SQLException;
-    method public abstract java.lang.String getNString(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.lang.Object getObject(int) throws java.sql.SQLException;
-    method public abstract java.lang.Object getObject(int, java.util.Map<java.lang.String, java.lang.Class<?>>) throws java.sql.SQLException;
-    method public abstract java.lang.Object getObject(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.lang.Object getObject(java.lang.String, java.util.Map<java.lang.String, java.lang.Class<?>>) throws java.sql.SQLException;
-    method public abstract java.sql.Ref getRef(int) throws java.sql.SQLException;
-    method public abstract java.sql.Ref getRef(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.RowId getRowId(int) throws java.sql.SQLException;
-    method public abstract java.sql.RowId getRowId(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.SQLXML getSQLXML(int) throws java.sql.SQLException;
-    method public abstract java.sql.SQLXML getSQLXML(java.lang.String) throws java.sql.SQLException;
-    method public abstract short getShort(int) throws java.sql.SQLException;
-    method public abstract short getShort(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.lang.String getString(int) throws java.sql.SQLException;
-    method public abstract java.lang.String getString(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Time getTime(int) throws java.sql.SQLException;
-    method public abstract java.sql.Time getTime(int, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract java.sql.Time getTime(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Time getTime(java.lang.String, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract java.sql.Timestamp getTimestamp(int) throws java.sql.SQLException;
-    method public abstract java.sql.Timestamp getTimestamp(int, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract java.sql.Timestamp getTimestamp(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Timestamp getTimestamp(java.lang.String, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract java.net.URL getURL(int) throws java.sql.SQLException;
-    method public abstract java.net.URL getURL(java.lang.String) throws java.sql.SQLException;
-    method public abstract void registerOutParameter(int, int) throws java.sql.SQLException;
-    method public abstract void registerOutParameter(int, int, int) throws java.sql.SQLException;
-    method public abstract void registerOutParameter(int, int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void registerOutParameter(java.lang.String, int) throws java.sql.SQLException;
-    method public abstract void registerOutParameter(java.lang.String, int, int) throws java.sql.SQLException;
-    method public abstract void registerOutParameter(java.lang.String, int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setAsciiStream(java.lang.String, java.io.InputStream, int) throws java.sql.SQLException;
-    method public abstract void setAsciiStream(java.lang.String, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void setAsciiStream(java.lang.String, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void setBigDecimal(java.lang.String, java.math.BigDecimal) throws java.sql.SQLException;
-    method public abstract void setBinaryStream(java.lang.String, java.io.InputStream, int) throws java.sql.SQLException;
-    method public abstract void setBinaryStream(java.lang.String, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void setBinaryStream(java.lang.String, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void setBlob(java.lang.String, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void setBlob(java.lang.String, java.sql.Blob) throws java.sql.SQLException;
-    method public abstract void setBlob(java.lang.String, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void setBoolean(java.lang.String, boolean) throws java.sql.SQLException;
-    method public abstract void setByte(java.lang.String, byte) throws java.sql.SQLException;
-    method public abstract void setBytes(java.lang.String, byte[]) throws java.sql.SQLException;
-    method public abstract void setCharacterStream(java.lang.String, java.io.Reader, int) throws java.sql.SQLException;
-    method public abstract void setCharacterStream(java.lang.String, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setCharacterStream(java.lang.String, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setClob(java.lang.String, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setClob(java.lang.String, java.sql.Clob) throws java.sql.SQLException;
-    method public abstract void setClob(java.lang.String, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setDate(java.lang.String, java.sql.Date) throws java.sql.SQLException;
-    method public abstract void setDate(java.lang.String, java.sql.Date, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract void setDouble(java.lang.String, double) throws java.sql.SQLException;
-    method public abstract void setFloat(java.lang.String, float) throws java.sql.SQLException;
-    method public abstract void setInt(java.lang.String, int) throws java.sql.SQLException;
-    method public abstract void setLong(java.lang.String, long) throws java.sql.SQLException;
-    method public abstract void setNCharacterStream(java.lang.String, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setNCharacterStream(java.lang.String, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setNClob(java.lang.String, java.sql.NClob) throws java.sql.SQLException;
-    method public abstract void setNClob(java.lang.String, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setNClob(java.lang.String, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setNString(java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setNull(java.lang.String, int) throws java.sql.SQLException;
-    method public abstract void setNull(java.lang.String, int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setObject(java.lang.String, java.lang.Object, int, int) throws java.sql.SQLException;
-    method public abstract void setObject(java.lang.String, java.lang.Object, int) throws java.sql.SQLException;
-    method public abstract void setObject(java.lang.String, java.lang.Object) throws java.sql.SQLException;
-    method public abstract void setRowId(java.lang.String, java.sql.RowId) throws java.sql.SQLException;
-    method public abstract void setSQLXML(java.lang.String, java.sql.SQLXML) throws java.sql.SQLException;
-    method public abstract void setShort(java.lang.String, short) throws java.sql.SQLException;
-    method public abstract void setString(java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setTime(java.lang.String, java.sql.Time) throws java.sql.SQLException;
-    method public abstract void setTime(java.lang.String, java.sql.Time, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract void setTimestamp(java.lang.String, java.sql.Timestamp) throws java.sql.SQLException;
-    method public abstract void setTimestamp(java.lang.String, java.sql.Timestamp, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract void setURL(java.lang.String, java.net.URL) throws java.sql.SQLException;
-    method public abstract boolean wasNull() throws java.sql.SQLException;
+  public interface CallableStatement extends java.sql.PreparedStatement {
+    method public java.sql.Array getArray(int) throws java.sql.SQLException;
+    method public java.sql.Array getArray(String) throws java.sql.SQLException;
+    method @Deprecated public java.math.BigDecimal getBigDecimal(int, int) throws java.sql.SQLException;
+    method public java.math.BigDecimal getBigDecimal(int) throws java.sql.SQLException;
+    method public java.math.BigDecimal getBigDecimal(String) throws java.sql.SQLException;
+    method public java.sql.Blob getBlob(int) throws java.sql.SQLException;
+    method public java.sql.Blob getBlob(String) throws java.sql.SQLException;
+    method public boolean getBoolean(int) throws java.sql.SQLException;
+    method public boolean getBoolean(String) throws java.sql.SQLException;
+    method public byte getByte(int) throws java.sql.SQLException;
+    method public byte getByte(String) throws java.sql.SQLException;
+    method public byte[] getBytes(int) throws java.sql.SQLException;
+    method public byte[] getBytes(String) throws java.sql.SQLException;
+    method public java.io.Reader getCharacterStream(int) throws java.sql.SQLException;
+    method public java.io.Reader getCharacterStream(String) throws java.sql.SQLException;
+    method public java.sql.Clob getClob(int) throws java.sql.SQLException;
+    method public java.sql.Clob getClob(String) throws java.sql.SQLException;
+    method public java.sql.Date getDate(int) throws java.sql.SQLException;
+    method public java.sql.Date getDate(int, java.util.Calendar) throws java.sql.SQLException;
+    method public java.sql.Date getDate(String) throws java.sql.SQLException;
+    method public java.sql.Date getDate(String, java.util.Calendar) throws java.sql.SQLException;
+    method public double getDouble(int) throws java.sql.SQLException;
+    method public double getDouble(String) throws java.sql.SQLException;
+    method public float getFloat(int) throws java.sql.SQLException;
+    method public float getFloat(String) throws java.sql.SQLException;
+    method public int getInt(int) throws java.sql.SQLException;
+    method public int getInt(String) throws java.sql.SQLException;
+    method public long getLong(int) throws java.sql.SQLException;
+    method public long getLong(String) throws java.sql.SQLException;
+    method public java.io.Reader getNCharacterStream(int) throws java.sql.SQLException;
+    method public java.io.Reader getNCharacterStream(String) throws java.sql.SQLException;
+    method public java.sql.NClob getNClob(int) throws java.sql.SQLException;
+    method public java.sql.NClob getNClob(String) throws java.sql.SQLException;
+    method public String getNString(int) throws java.sql.SQLException;
+    method public String getNString(String) throws java.sql.SQLException;
+    method public Object getObject(int) throws java.sql.SQLException;
+    method public Object getObject(int, java.util.Map<java.lang.String,java.lang.Class<?>>) throws java.sql.SQLException;
+    method public Object getObject(String) throws java.sql.SQLException;
+    method public Object getObject(String, java.util.Map<java.lang.String,java.lang.Class<?>>) throws java.sql.SQLException;
+    method public java.sql.Ref getRef(int) throws java.sql.SQLException;
+    method public java.sql.Ref getRef(String) throws java.sql.SQLException;
+    method public java.sql.RowId getRowId(int) throws java.sql.SQLException;
+    method public java.sql.RowId getRowId(String) throws java.sql.SQLException;
+    method public java.sql.SQLXML getSQLXML(int) throws java.sql.SQLException;
+    method public java.sql.SQLXML getSQLXML(String) throws java.sql.SQLException;
+    method public short getShort(int) throws java.sql.SQLException;
+    method public short getShort(String) throws java.sql.SQLException;
+    method public String getString(int) throws java.sql.SQLException;
+    method public String getString(String) throws java.sql.SQLException;
+    method public java.sql.Time getTime(int) throws java.sql.SQLException;
+    method public java.sql.Time getTime(int, java.util.Calendar) throws java.sql.SQLException;
+    method public java.sql.Time getTime(String) throws java.sql.SQLException;
+    method public java.sql.Time getTime(String, java.util.Calendar) throws java.sql.SQLException;
+    method public java.sql.Timestamp getTimestamp(int) throws java.sql.SQLException;
+    method public java.sql.Timestamp getTimestamp(int, java.util.Calendar) throws java.sql.SQLException;
+    method public java.sql.Timestamp getTimestamp(String) throws java.sql.SQLException;
+    method public java.sql.Timestamp getTimestamp(String, java.util.Calendar) throws java.sql.SQLException;
+    method public java.net.URL getURL(int) throws java.sql.SQLException;
+    method public java.net.URL getURL(String) throws java.sql.SQLException;
+    method public void registerOutParameter(int, int) throws java.sql.SQLException;
+    method public void registerOutParameter(int, int, int) throws java.sql.SQLException;
+    method public void registerOutParameter(int, int, String) throws java.sql.SQLException;
+    method public void registerOutParameter(String, int) throws java.sql.SQLException;
+    method public void registerOutParameter(String, int, int) throws java.sql.SQLException;
+    method public void registerOutParameter(String, int, String) throws java.sql.SQLException;
+    method public void setAsciiStream(String, java.io.InputStream, int) throws java.sql.SQLException;
+    method public void setAsciiStream(String, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void setAsciiStream(String, java.io.InputStream) throws java.sql.SQLException;
+    method public void setBigDecimal(String, java.math.BigDecimal) throws java.sql.SQLException;
+    method public void setBinaryStream(String, java.io.InputStream, int) throws java.sql.SQLException;
+    method public void setBinaryStream(String, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void setBinaryStream(String, java.io.InputStream) throws java.sql.SQLException;
+    method public void setBlob(String, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void setBlob(String, java.sql.Blob) throws java.sql.SQLException;
+    method public void setBlob(String, java.io.InputStream) throws java.sql.SQLException;
+    method public void setBoolean(String, boolean) throws java.sql.SQLException;
+    method public void setByte(String, byte) throws java.sql.SQLException;
+    method public void setBytes(String, byte[]) throws java.sql.SQLException;
+    method public void setCharacterStream(String, java.io.Reader, int) throws java.sql.SQLException;
+    method public void setCharacterStream(String, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setCharacterStream(String, java.io.Reader) throws java.sql.SQLException;
+    method public void setClob(String, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setClob(String, java.sql.Clob) throws java.sql.SQLException;
+    method public void setClob(String, java.io.Reader) throws java.sql.SQLException;
+    method public void setDate(String, java.sql.Date) throws java.sql.SQLException;
+    method public void setDate(String, java.sql.Date, java.util.Calendar) throws java.sql.SQLException;
+    method public void setDouble(String, double) throws java.sql.SQLException;
+    method public void setFloat(String, float) throws java.sql.SQLException;
+    method public void setInt(String, int) throws java.sql.SQLException;
+    method public void setLong(String, long) throws java.sql.SQLException;
+    method public void setNCharacterStream(String, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setNCharacterStream(String, java.io.Reader) throws java.sql.SQLException;
+    method public void setNClob(String, java.sql.NClob) throws java.sql.SQLException;
+    method public void setNClob(String, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setNClob(String, java.io.Reader) throws java.sql.SQLException;
+    method public void setNString(String, String) throws java.sql.SQLException;
+    method public void setNull(String, int) throws java.sql.SQLException;
+    method public void setNull(String, int, String) throws java.sql.SQLException;
+    method public void setObject(String, Object, int, int) throws java.sql.SQLException;
+    method public void setObject(String, Object, int) throws java.sql.SQLException;
+    method public void setObject(String, Object) throws java.sql.SQLException;
+    method public void setRowId(String, java.sql.RowId) throws java.sql.SQLException;
+    method public void setSQLXML(String, java.sql.SQLXML) throws java.sql.SQLException;
+    method public void setShort(String, short) throws java.sql.SQLException;
+    method public void setString(String, String) throws java.sql.SQLException;
+    method public void setTime(String, java.sql.Time) throws java.sql.SQLException;
+    method public void setTime(String, java.sql.Time, java.util.Calendar) throws java.sql.SQLException;
+    method public void setTimestamp(String, java.sql.Timestamp) throws java.sql.SQLException;
+    method public void setTimestamp(String, java.sql.Timestamp, java.util.Calendar) throws java.sql.SQLException;
+    method public void setURL(String, java.net.URL) throws java.sql.SQLException;
+    method public boolean wasNull() throws java.sql.SQLException;
   }
 
-  public final class ClientInfoStatus extends java.lang.Enum {
-    method public static java.sql.ClientInfoStatus valueOf(java.lang.String);
-    method public static final java.sql.ClientInfoStatus[] values();
+  public enum ClientInfoStatus {
     enum_constant public static final java.sql.ClientInfoStatus REASON_UNKNOWN;
     enum_constant public static final java.sql.ClientInfoStatus REASON_UNKNOWN_PROPERTY;
     enum_constant public static final java.sql.ClientInfoStatus REASON_VALUE_INVALID;
     enum_constant public static final java.sql.ClientInfoStatus REASON_VALUE_TRUNCATED;
   }
 
-  public abstract interface Clob {
-    method public abstract void free() throws java.sql.SQLException;
-    method public abstract java.io.InputStream getAsciiStream() throws java.sql.SQLException;
-    method public abstract java.io.Reader getCharacterStream() throws java.sql.SQLException;
-    method public abstract java.io.Reader getCharacterStream(long, long) throws java.sql.SQLException;
-    method public abstract java.lang.String getSubString(long, int) throws java.sql.SQLException;
-    method public abstract long length() throws java.sql.SQLException;
-    method public abstract long position(java.lang.String, long) throws java.sql.SQLException;
-    method public abstract long position(java.sql.Clob, long) throws java.sql.SQLException;
-    method public abstract java.io.OutputStream setAsciiStream(long) throws java.sql.SQLException;
-    method public abstract java.io.Writer setCharacterStream(long) throws java.sql.SQLException;
-    method public abstract int setString(long, java.lang.String) throws java.sql.SQLException;
-    method public abstract int setString(long, java.lang.String, int, int) throws java.sql.SQLException;
-    method public abstract void truncate(long) throws java.sql.SQLException;
+  public interface Clob {
+    method public void free() throws java.sql.SQLException;
+    method public java.io.InputStream getAsciiStream() throws java.sql.SQLException;
+    method public java.io.Reader getCharacterStream() throws java.sql.SQLException;
+    method public java.io.Reader getCharacterStream(long, long) throws java.sql.SQLException;
+    method public String getSubString(long, int) throws java.sql.SQLException;
+    method public long length() throws java.sql.SQLException;
+    method public long position(String, long) throws java.sql.SQLException;
+    method public long position(java.sql.Clob, long) throws java.sql.SQLException;
+    method public java.io.OutputStream setAsciiStream(long) throws java.sql.SQLException;
+    method public java.io.Writer setCharacterStream(long) throws java.sql.SQLException;
+    method public int setString(long, String) throws java.sql.SQLException;
+    method public int setString(long, String, int, int) throws java.sql.SQLException;
+    method public void truncate(long) throws java.sql.SQLException;
   }
 
-  public abstract interface Connection implements java.lang.AutoCloseable java.sql.Wrapper {
-    method public abstract void clearWarnings() throws java.sql.SQLException;
-    method public abstract void close() throws java.sql.SQLException;
-    method public abstract void commit() throws java.sql.SQLException;
-    method public abstract java.sql.Array createArrayOf(java.lang.String, java.lang.Object[]) throws java.sql.SQLException;
-    method public abstract java.sql.Blob createBlob() throws java.sql.SQLException;
-    method public abstract java.sql.Clob createClob() throws java.sql.SQLException;
-    method public abstract java.sql.NClob createNClob() throws java.sql.SQLException;
-    method public abstract java.sql.SQLXML createSQLXML() throws java.sql.SQLException;
-    method public abstract java.sql.Statement createStatement() throws java.sql.SQLException;
-    method public abstract java.sql.Statement createStatement(int, int) throws java.sql.SQLException;
-    method public abstract java.sql.Statement createStatement(int, int, int) throws java.sql.SQLException;
-    method public abstract java.sql.Struct createStruct(java.lang.String, java.lang.Object[]) throws java.sql.SQLException;
-    method public abstract boolean getAutoCommit() throws java.sql.SQLException;
-    method public abstract java.lang.String getCatalog() throws java.sql.SQLException;
-    method public abstract java.lang.String getClientInfo(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.util.Properties getClientInfo() throws java.sql.SQLException;
-    method public abstract int getHoldability() throws java.sql.SQLException;
-    method public abstract java.sql.DatabaseMetaData getMetaData() throws java.sql.SQLException;
-    method public abstract int getTransactionIsolation() throws java.sql.SQLException;
-    method public abstract java.util.Map<java.lang.String, java.lang.Class<?>> getTypeMap() throws java.sql.SQLException;
-    method public abstract java.sql.SQLWarning getWarnings() throws java.sql.SQLException;
-    method public abstract boolean isClosed() throws java.sql.SQLException;
-    method public abstract boolean isReadOnly() throws java.sql.SQLException;
-    method public abstract boolean isValid(int) throws java.sql.SQLException;
-    method public abstract java.lang.String nativeSQL(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.CallableStatement prepareCall(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.CallableStatement prepareCall(java.lang.String, int, int) throws java.sql.SQLException;
-    method public abstract java.sql.CallableStatement prepareCall(java.lang.String, int, int, int) throws java.sql.SQLException;
-    method public abstract java.sql.PreparedStatement prepareStatement(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.PreparedStatement prepareStatement(java.lang.String, int, int) throws java.sql.SQLException;
-    method public abstract java.sql.PreparedStatement prepareStatement(java.lang.String, int, int, int) throws java.sql.SQLException;
-    method public abstract java.sql.PreparedStatement prepareStatement(java.lang.String, int) throws java.sql.SQLException;
-    method public abstract java.sql.PreparedStatement prepareStatement(java.lang.String, int[]) throws java.sql.SQLException;
-    method public abstract java.sql.PreparedStatement prepareStatement(java.lang.String, java.lang.String[]) throws java.sql.SQLException;
-    method public abstract void releaseSavepoint(java.sql.Savepoint) throws java.sql.SQLException;
-    method public abstract void rollback() throws java.sql.SQLException;
-    method public abstract void rollback(java.sql.Savepoint) throws java.sql.SQLException;
-    method public abstract void setAutoCommit(boolean) throws java.sql.SQLException;
-    method public abstract void setCatalog(java.lang.String) throws java.sql.SQLException;
-    method public abstract void setClientInfo(java.lang.String, java.lang.String) throws java.sql.SQLClientInfoException;
-    method public abstract void setClientInfo(java.util.Properties) throws java.sql.SQLClientInfoException;
-    method public abstract void setHoldability(int) throws java.sql.SQLException;
-    method public abstract void setReadOnly(boolean) throws java.sql.SQLException;
-    method public abstract java.sql.Savepoint setSavepoint() throws java.sql.SQLException;
-    method public abstract java.sql.Savepoint setSavepoint(java.lang.String) throws java.sql.SQLException;
-    method public abstract void setTransactionIsolation(int) throws java.sql.SQLException;
-    method public abstract void setTypeMap(java.util.Map<java.lang.String, java.lang.Class<?>>) throws java.sql.SQLException;
+  public interface Connection extends java.sql.Wrapper java.lang.AutoCloseable {
+    method public void clearWarnings() throws java.sql.SQLException;
+    method public void close() throws java.sql.SQLException;
+    method public void commit() throws java.sql.SQLException;
+    method public java.sql.Array createArrayOf(String, Object[]) throws java.sql.SQLException;
+    method public java.sql.Blob createBlob() throws java.sql.SQLException;
+    method public java.sql.Clob createClob() throws java.sql.SQLException;
+    method public java.sql.NClob createNClob() throws java.sql.SQLException;
+    method public java.sql.SQLXML createSQLXML() throws java.sql.SQLException;
+    method public java.sql.Statement createStatement() throws java.sql.SQLException;
+    method public java.sql.Statement createStatement(int, int) throws java.sql.SQLException;
+    method public java.sql.Statement createStatement(int, int, int) throws java.sql.SQLException;
+    method public java.sql.Struct createStruct(String, Object[]) throws java.sql.SQLException;
+    method public boolean getAutoCommit() throws java.sql.SQLException;
+    method public String getCatalog() throws java.sql.SQLException;
+    method public String getClientInfo(String) throws java.sql.SQLException;
+    method public java.util.Properties getClientInfo() throws java.sql.SQLException;
+    method public int getHoldability() throws java.sql.SQLException;
+    method public java.sql.DatabaseMetaData getMetaData() throws java.sql.SQLException;
+    method public int getTransactionIsolation() throws java.sql.SQLException;
+    method public java.util.Map<java.lang.String,java.lang.Class<?>> getTypeMap() throws java.sql.SQLException;
+    method public java.sql.SQLWarning getWarnings() throws java.sql.SQLException;
+    method public boolean isClosed() throws java.sql.SQLException;
+    method public boolean isReadOnly() throws java.sql.SQLException;
+    method public boolean isValid(int) throws java.sql.SQLException;
+    method public String nativeSQL(String) throws java.sql.SQLException;
+    method public java.sql.CallableStatement prepareCall(String) throws java.sql.SQLException;
+    method public java.sql.CallableStatement prepareCall(String, int, int) throws java.sql.SQLException;
+    method public java.sql.CallableStatement prepareCall(String, int, int, int) throws java.sql.SQLException;
+    method public java.sql.PreparedStatement prepareStatement(String) throws java.sql.SQLException;
+    method public java.sql.PreparedStatement prepareStatement(String, int, int) throws java.sql.SQLException;
+    method public java.sql.PreparedStatement prepareStatement(String, int, int, int) throws java.sql.SQLException;
+    method public java.sql.PreparedStatement prepareStatement(String, int) throws java.sql.SQLException;
+    method public java.sql.PreparedStatement prepareStatement(String, int[]) throws java.sql.SQLException;
+    method public java.sql.PreparedStatement prepareStatement(String, String[]) throws java.sql.SQLException;
+    method public void releaseSavepoint(java.sql.Savepoint) throws java.sql.SQLException;
+    method public void rollback() throws java.sql.SQLException;
+    method public void rollback(java.sql.Savepoint) throws java.sql.SQLException;
+    method public void setAutoCommit(boolean) throws java.sql.SQLException;
+    method public void setCatalog(String) throws java.sql.SQLException;
+    method public void setClientInfo(String, String) throws java.sql.SQLClientInfoException;
+    method public void setClientInfo(java.util.Properties) throws java.sql.SQLClientInfoException;
+    method public void setHoldability(int) throws java.sql.SQLException;
+    method public void setReadOnly(boolean) throws java.sql.SQLException;
+    method public java.sql.Savepoint setSavepoint() throws java.sql.SQLException;
+    method public java.sql.Savepoint setSavepoint(String) throws java.sql.SQLException;
+    method public void setTransactionIsolation(int) throws java.sql.SQLException;
+    method public void setTypeMap(java.util.Map<java.lang.String,java.lang.Class<?>>) throws java.sql.SQLException;
     field public static final int TRANSACTION_NONE = 0; // 0x0
     field public static final int TRANSACTION_READ_COMMITTED = 2; // 0x2
     field public static final int TRANSACTION_READ_UNCOMMITTED = 1; // 0x1
@@ -65284,7 +65648,7 @@
 
   public class DataTruncation extends java.sql.SQLWarning {
     ctor public DataTruncation(int, boolean, boolean, int, int);
-    ctor public DataTruncation(int, boolean, boolean, int, int, java.lang.Throwable);
+    ctor public DataTruncation(int, boolean, boolean, int, int, Throwable);
     method public int getDataSize();
     method public int getIndex();
     method public boolean getParameter();
@@ -65292,179 +65656,179 @@
     method public int getTransferSize();
   }
 
-  public abstract interface DatabaseMetaData implements java.sql.Wrapper {
-    method public abstract boolean allProceduresAreCallable() throws java.sql.SQLException;
-    method public abstract boolean allTablesAreSelectable() throws java.sql.SQLException;
-    method public abstract boolean autoCommitFailureClosesAllResultSets() throws java.sql.SQLException;
-    method public abstract boolean dataDefinitionCausesTransactionCommit() throws java.sql.SQLException;
-    method public abstract boolean dataDefinitionIgnoredInTransactions() throws java.sql.SQLException;
-    method public abstract boolean deletesAreDetected(int) throws java.sql.SQLException;
-    method public abstract boolean doesMaxRowSizeIncludeBlobs() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getAttributes(java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getBestRowIdentifier(java.lang.String, java.lang.String, java.lang.String, int, boolean) throws java.sql.SQLException;
-    method public abstract java.lang.String getCatalogSeparator() throws java.sql.SQLException;
-    method public abstract java.lang.String getCatalogTerm() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getCatalogs() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getClientInfoProperties() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getColumnPrivileges(java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Connection getConnection() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getCrossReference(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract int getDatabaseMajorVersion() throws java.sql.SQLException;
-    method public abstract int getDatabaseMinorVersion() throws java.sql.SQLException;
-    method public abstract java.lang.String getDatabaseProductName() throws java.sql.SQLException;
-    method public abstract java.lang.String getDatabaseProductVersion() throws java.sql.SQLException;
-    method public abstract int getDefaultTransactionIsolation() throws java.sql.SQLException;
-    method public abstract int getDriverMajorVersion();
-    method public abstract int getDriverMinorVersion();
-    method public abstract java.lang.String getDriverName() throws java.sql.SQLException;
-    method public abstract java.lang.String getDriverVersion() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getExportedKeys(java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract java.lang.String getExtraNameCharacters() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getFunctionColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getFunctions(java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract java.lang.String getIdentifierQuoteString() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getImportedKeys(java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getIndexInfo(java.lang.String, java.lang.String, java.lang.String, boolean, boolean) throws java.sql.SQLException;
-    method public abstract int getJDBCMajorVersion() throws java.sql.SQLException;
-    method public abstract int getJDBCMinorVersion() throws java.sql.SQLException;
-    method public abstract int getMaxBinaryLiteralLength() throws java.sql.SQLException;
-    method public abstract int getMaxCatalogNameLength() throws java.sql.SQLException;
-    method public abstract int getMaxCharLiteralLength() throws java.sql.SQLException;
-    method public abstract int getMaxColumnNameLength() throws java.sql.SQLException;
-    method public abstract int getMaxColumnsInGroupBy() throws java.sql.SQLException;
-    method public abstract int getMaxColumnsInIndex() throws java.sql.SQLException;
-    method public abstract int getMaxColumnsInOrderBy() throws java.sql.SQLException;
-    method public abstract int getMaxColumnsInSelect() throws java.sql.SQLException;
-    method public abstract int getMaxColumnsInTable() throws java.sql.SQLException;
-    method public abstract int getMaxConnections() throws java.sql.SQLException;
-    method public abstract int getMaxCursorNameLength() throws java.sql.SQLException;
-    method public abstract int getMaxIndexLength() throws java.sql.SQLException;
-    method public abstract int getMaxProcedureNameLength() throws java.sql.SQLException;
-    method public abstract int getMaxRowSize() throws java.sql.SQLException;
-    method public abstract int getMaxSchemaNameLength() throws java.sql.SQLException;
-    method public abstract int getMaxStatementLength() throws java.sql.SQLException;
-    method public abstract int getMaxStatements() throws java.sql.SQLException;
-    method public abstract int getMaxTableNameLength() throws java.sql.SQLException;
-    method public abstract int getMaxTablesInSelect() throws java.sql.SQLException;
-    method public abstract int getMaxUserNameLength() throws java.sql.SQLException;
-    method public abstract java.lang.String getNumericFunctions() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getPrimaryKeys(java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getProcedureColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract java.lang.String getProcedureTerm() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getProcedures(java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract int getResultSetHoldability() throws java.sql.SQLException;
-    method public abstract java.sql.RowIdLifetime getRowIdLifetime() throws java.sql.SQLException;
-    method public abstract java.lang.String getSQLKeywords() throws java.sql.SQLException;
-    method public abstract int getSQLStateType() throws java.sql.SQLException;
-    method public abstract java.lang.String getSchemaTerm() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getSchemas() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getSchemas(java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract java.lang.String getSearchStringEscape() throws java.sql.SQLException;
-    method public abstract java.lang.String getStringFunctions() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getSuperTables(java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getSuperTypes(java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract java.lang.String getSystemFunctions() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getTablePrivileges(java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getTableTypes() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getTables(java.lang.String, java.lang.String, java.lang.String, java.lang.String[]) throws java.sql.SQLException;
-    method public abstract java.lang.String getTimeDateFunctions() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getTypeInfo() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getUDTs(java.lang.String, java.lang.String, java.lang.String, int[]) throws java.sql.SQLException;
-    method public abstract java.lang.String getURL() throws java.sql.SQLException;
-    method public abstract java.lang.String getUserName() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getVersionColumns(java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract boolean insertsAreDetected(int) throws java.sql.SQLException;
-    method public abstract boolean isCatalogAtStart() throws java.sql.SQLException;
-    method public abstract boolean isReadOnly() throws java.sql.SQLException;
-    method public abstract boolean locatorsUpdateCopy() throws java.sql.SQLException;
-    method public abstract boolean nullPlusNonNullIsNull() throws java.sql.SQLException;
-    method public abstract boolean nullsAreSortedAtEnd() throws java.sql.SQLException;
-    method public abstract boolean nullsAreSortedAtStart() throws java.sql.SQLException;
-    method public abstract boolean nullsAreSortedHigh() throws java.sql.SQLException;
-    method public abstract boolean nullsAreSortedLow() throws java.sql.SQLException;
-    method public abstract boolean othersDeletesAreVisible(int) throws java.sql.SQLException;
-    method public abstract boolean othersInsertsAreVisible(int) throws java.sql.SQLException;
-    method public abstract boolean othersUpdatesAreVisible(int) throws java.sql.SQLException;
-    method public abstract boolean ownDeletesAreVisible(int) throws java.sql.SQLException;
-    method public abstract boolean ownInsertsAreVisible(int) throws java.sql.SQLException;
-    method public abstract boolean ownUpdatesAreVisible(int) throws java.sql.SQLException;
-    method public abstract boolean storesLowerCaseIdentifiers() throws java.sql.SQLException;
-    method public abstract boolean storesLowerCaseQuotedIdentifiers() throws java.sql.SQLException;
-    method public abstract boolean storesMixedCaseIdentifiers() throws java.sql.SQLException;
-    method public abstract boolean storesMixedCaseQuotedIdentifiers() throws java.sql.SQLException;
-    method public abstract boolean storesUpperCaseIdentifiers() throws java.sql.SQLException;
-    method public abstract boolean storesUpperCaseQuotedIdentifiers() throws java.sql.SQLException;
-    method public abstract boolean supportsANSI92EntryLevelSQL() throws java.sql.SQLException;
-    method public abstract boolean supportsANSI92FullSQL() throws java.sql.SQLException;
-    method public abstract boolean supportsANSI92IntermediateSQL() throws java.sql.SQLException;
-    method public abstract boolean supportsAlterTableWithAddColumn() throws java.sql.SQLException;
-    method public abstract boolean supportsAlterTableWithDropColumn() throws java.sql.SQLException;
-    method public abstract boolean supportsBatchUpdates() throws java.sql.SQLException;
-    method public abstract boolean supportsCatalogsInDataManipulation() throws java.sql.SQLException;
-    method public abstract boolean supportsCatalogsInIndexDefinitions() throws java.sql.SQLException;
-    method public abstract boolean supportsCatalogsInPrivilegeDefinitions() throws java.sql.SQLException;
-    method public abstract boolean supportsCatalogsInProcedureCalls() throws java.sql.SQLException;
-    method public abstract boolean supportsCatalogsInTableDefinitions() throws java.sql.SQLException;
-    method public abstract boolean supportsColumnAliasing() throws java.sql.SQLException;
-    method public abstract boolean supportsConvert() throws java.sql.SQLException;
-    method public abstract boolean supportsConvert(int, int) throws java.sql.SQLException;
-    method public abstract boolean supportsCoreSQLGrammar() throws java.sql.SQLException;
-    method public abstract boolean supportsCorrelatedSubqueries() throws java.sql.SQLException;
-    method public abstract boolean supportsDataDefinitionAndDataManipulationTransactions() throws java.sql.SQLException;
-    method public abstract boolean supportsDataManipulationTransactionsOnly() throws java.sql.SQLException;
-    method public abstract boolean supportsDifferentTableCorrelationNames() throws java.sql.SQLException;
-    method public abstract boolean supportsExpressionsInOrderBy() throws java.sql.SQLException;
-    method public abstract boolean supportsExtendedSQLGrammar() throws java.sql.SQLException;
-    method public abstract boolean supportsFullOuterJoins() throws java.sql.SQLException;
-    method public abstract boolean supportsGetGeneratedKeys() throws java.sql.SQLException;
-    method public abstract boolean supportsGroupBy() throws java.sql.SQLException;
-    method public abstract boolean supportsGroupByBeyondSelect() throws java.sql.SQLException;
-    method public abstract boolean supportsGroupByUnrelated() throws java.sql.SQLException;
-    method public abstract boolean supportsIntegrityEnhancementFacility() throws java.sql.SQLException;
-    method public abstract boolean supportsLikeEscapeClause() throws java.sql.SQLException;
-    method public abstract boolean supportsLimitedOuterJoins() throws java.sql.SQLException;
-    method public abstract boolean supportsMinimumSQLGrammar() throws java.sql.SQLException;
-    method public abstract boolean supportsMixedCaseIdentifiers() throws java.sql.SQLException;
-    method public abstract boolean supportsMixedCaseQuotedIdentifiers() throws java.sql.SQLException;
-    method public abstract boolean supportsMultipleOpenResults() throws java.sql.SQLException;
-    method public abstract boolean supportsMultipleResultSets() throws java.sql.SQLException;
-    method public abstract boolean supportsMultipleTransactions() throws java.sql.SQLException;
-    method public abstract boolean supportsNamedParameters() throws java.sql.SQLException;
-    method public abstract boolean supportsNonNullableColumns() throws java.sql.SQLException;
-    method public abstract boolean supportsOpenCursorsAcrossCommit() throws java.sql.SQLException;
-    method public abstract boolean supportsOpenCursorsAcrossRollback() throws java.sql.SQLException;
-    method public abstract boolean supportsOpenStatementsAcrossCommit() throws java.sql.SQLException;
-    method public abstract boolean supportsOpenStatementsAcrossRollback() throws java.sql.SQLException;
-    method public abstract boolean supportsOrderByUnrelated() throws java.sql.SQLException;
-    method public abstract boolean supportsOuterJoins() throws java.sql.SQLException;
-    method public abstract boolean supportsPositionedDelete() throws java.sql.SQLException;
-    method public abstract boolean supportsPositionedUpdate() throws java.sql.SQLException;
-    method public abstract boolean supportsResultSetConcurrency(int, int) throws java.sql.SQLException;
-    method public abstract boolean supportsResultSetHoldability(int) throws java.sql.SQLException;
-    method public abstract boolean supportsResultSetType(int) throws java.sql.SQLException;
-    method public abstract boolean supportsSavepoints() throws java.sql.SQLException;
-    method public abstract boolean supportsSchemasInDataManipulation() throws java.sql.SQLException;
-    method public abstract boolean supportsSchemasInIndexDefinitions() throws java.sql.SQLException;
-    method public abstract boolean supportsSchemasInPrivilegeDefinitions() throws java.sql.SQLException;
-    method public abstract boolean supportsSchemasInProcedureCalls() throws java.sql.SQLException;
-    method public abstract boolean supportsSchemasInTableDefinitions() throws java.sql.SQLException;
-    method public abstract boolean supportsSelectForUpdate() throws java.sql.SQLException;
-    method public abstract boolean supportsStatementPooling() throws java.sql.SQLException;
-    method public abstract boolean supportsStoredFunctionsUsingCallSyntax() throws java.sql.SQLException;
-    method public abstract boolean supportsStoredProcedures() throws java.sql.SQLException;
-    method public abstract boolean supportsSubqueriesInComparisons() throws java.sql.SQLException;
-    method public abstract boolean supportsSubqueriesInExists() throws java.sql.SQLException;
-    method public abstract boolean supportsSubqueriesInIns() throws java.sql.SQLException;
-    method public abstract boolean supportsSubqueriesInQuantifieds() throws java.sql.SQLException;
-    method public abstract boolean supportsTableCorrelationNames() throws java.sql.SQLException;
-    method public abstract boolean supportsTransactionIsolationLevel(int) throws java.sql.SQLException;
-    method public abstract boolean supportsTransactions() throws java.sql.SQLException;
-    method public abstract boolean supportsUnion() throws java.sql.SQLException;
-    method public abstract boolean supportsUnionAll() throws java.sql.SQLException;
-    method public abstract boolean updatesAreDetected(int) throws java.sql.SQLException;
-    method public abstract boolean usesLocalFilePerTable() throws java.sql.SQLException;
-    method public abstract boolean usesLocalFiles() throws java.sql.SQLException;
+  public interface DatabaseMetaData extends java.sql.Wrapper {
+    method public boolean allProceduresAreCallable() throws java.sql.SQLException;
+    method public boolean allTablesAreSelectable() throws java.sql.SQLException;
+    method public boolean autoCommitFailureClosesAllResultSets() throws java.sql.SQLException;
+    method public boolean dataDefinitionCausesTransactionCommit() throws java.sql.SQLException;
+    method public boolean dataDefinitionIgnoredInTransactions() throws java.sql.SQLException;
+    method public boolean deletesAreDetected(int) throws java.sql.SQLException;
+    method public boolean doesMaxRowSizeIncludeBlobs() throws java.sql.SQLException;
+    method public java.sql.ResultSet getAttributes(String, String, String, String) throws java.sql.SQLException;
+    method public java.sql.ResultSet getBestRowIdentifier(String, String, String, int, boolean) throws java.sql.SQLException;
+    method public String getCatalogSeparator() throws java.sql.SQLException;
+    method public String getCatalogTerm() throws java.sql.SQLException;
+    method public java.sql.ResultSet getCatalogs() throws java.sql.SQLException;
+    method public java.sql.ResultSet getClientInfoProperties() throws java.sql.SQLException;
+    method public java.sql.ResultSet getColumnPrivileges(String, String, String, String) throws java.sql.SQLException;
+    method public java.sql.ResultSet getColumns(String, String, String, String) throws java.sql.SQLException;
+    method public java.sql.Connection getConnection() throws java.sql.SQLException;
+    method public java.sql.ResultSet getCrossReference(String, String, String, String, String, String) throws java.sql.SQLException;
+    method public int getDatabaseMajorVersion() throws java.sql.SQLException;
+    method public int getDatabaseMinorVersion() throws java.sql.SQLException;
+    method public String getDatabaseProductName() throws java.sql.SQLException;
+    method public String getDatabaseProductVersion() throws java.sql.SQLException;
+    method public int getDefaultTransactionIsolation() throws java.sql.SQLException;
+    method public int getDriverMajorVersion();
+    method public int getDriverMinorVersion();
+    method public String getDriverName() throws java.sql.SQLException;
+    method public String getDriverVersion() throws java.sql.SQLException;
+    method public java.sql.ResultSet getExportedKeys(String, String, String) throws java.sql.SQLException;
+    method public String getExtraNameCharacters() throws java.sql.SQLException;
+    method public java.sql.ResultSet getFunctionColumns(String, String, String, String) throws java.sql.SQLException;
+    method public java.sql.ResultSet getFunctions(String, String, String) throws java.sql.SQLException;
+    method public String getIdentifierQuoteString() throws java.sql.SQLException;
+    method public java.sql.ResultSet getImportedKeys(String, String, String) throws java.sql.SQLException;
+    method public java.sql.ResultSet getIndexInfo(String, String, String, boolean, boolean) throws java.sql.SQLException;
+    method public int getJDBCMajorVersion() throws java.sql.SQLException;
+    method public int getJDBCMinorVersion() throws java.sql.SQLException;
+    method public int getMaxBinaryLiteralLength() throws java.sql.SQLException;
+    method public int getMaxCatalogNameLength() throws java.sql.SQLException;
+    method public int getMaxCharLiteralLength() throws java.sql.SQLException;
+    method public int getMaxColumnNameLength() throws java.sql.SQLException;
+    method public int getMaxColumnsInGroupBy() throws java.sql.SQLException;
+    method public int getMaxColumnsInIndex() throws java.sql.SQLException;
+    method public int getMaxColumnsInOrderBy() throws java.sql.SQLException;
+    method public int getMaxColumnsInSelect() throws java.sql.SQLException;
+    method public int getMaxColumnsInTable() throws java.sql.SQLException;
+    method public int getMaxConnections() throws java.sql.SQLException;
+    method public int getMaxCursorNameLength() throws java.sql.SQLException;
+    method public int getMaxIndexLength() throws java.sql.SQLException;
+    method public int getMaxProcedureNameLength() throws java.sql.SQLException;
+    method public int getMaxRowSize() throws java.sql.SQLException;
+    method public int getMaxSchemaNameLength() throws java.sql.SQLException;
+    method public int getMaxStatementLength() throws java.sql.SQLException;
+    method public int getMaxStatements() throws java.sql.SQLException;
+    method public int getMaxTableNameLength() throws java.sql.SQLException;
+    method public int getMaxTablesInSelect() throws java.sql.SQLException;
+    method public int getMaxUserNameLength() throws java.sql.SQLException;
+    method public String getNumericFunctions() throws java.sql.SQLException;
+    method public java.sql.ResultSet getPrimaryKeys(String, String, String) throws java.sql.SQLException;
+    method public java.sql.ResultSet getProcedureColumns(String, String, String, String) throws java.sql.SQLException;
+    method public String getProcedureTerm() throws java.sql.SQLException;
+    method public java.sql.ResultSet getProcedures(String, String, String) throws java.sql.SQLException;
+    method public int getResultSetHoldability() throws java.sql.SQLException;
+    method public java.sql.RowIdLifetime getRowIdLifetime() throws java.sql.SQLException;
+    method public String getSQLKeywords() throws java.sql.SQLException;
+    method public int getSQLStateType() throws java.sql.SQLException;
+    method public String getSchemaTerm() throws java.sql.SQLException;
+    method public java.sql.ResultSet getSchemas() throws java.sql.SQLException;
+    method public java.sql.ResultSet getSchemas(String, String) throws java.sql.SQLException;
+    method public String getSearchStringEscape() throws java.sql.SQLException;
+    method public String getStringFunctions() throws java.sql.SQLException;
+    method public java.sql.ResultSet getSuperTables(String, String, String) throws java.sql.SQLException;
+    method public java.sql.ResultSet getSuperTypes(String, String, String) throws java.sql.SQLException;
+    method public String getSystemFunctions() throws java.sql.SQLException;
+    method public java.sql.ResultSet getTablePrivileges(String, String, String) throws java.sql.SQLException;
+    method public java.sql.ResultSet getTableTypes() throws java.sql.SQLException;
+    method public java.sql.ResultSet getTables(String, String, String, String[]) throws java.sql.SQLException;
+    method public String getTimeDateFunctions() throws java.sql.SQLException;
+    method public java.sql.ResultSet getTypeInfo() throws java.sql.SQLException;
+    method public java.sql.ResultSet getUDTs(String, String, String, int[]) throws java.sql.SQLException;
+    method public String getURL() throws java.sql.SQLException;
+    method public String getUserName() throws java.sql.SQLException;
+    method public java.sql.ResultSet getVersionColumns(String, String, String) throws java.sql.SQLException;
+    method public boolean insertsAreDetected(int) throws java.sql.SQLException;
+    method public boolean isCatalogAtStart() throws java.sql.SQLException;
+    method public boolean isReadOnly() throws java.sql.SQLException;
+    method public boolean locatorsUpdateCopy() throws java.sql.SQLException;
+    method public boolean nullPlusNonNullIsNull() throws java.sql.SQLException;
+    method public boolean nullsAreSortedAtEnd() throws java.sql.SQLException;
+    method public boolean nullsAreSortedAtStart() throws java.sql.SQLException;
+    method public boolean nullsAreSortedHigh() throws java.sql.SQLException;
+    method public boolean nullsAreSortedLow() throws java.sql.SQLException;
+    method public boolean othersDeletesAreVisible(int) throws java.sql.SQLException;
+    method public boolean othersInsertsAreVisible(int) throws java.sql.SQLException;
+    method public boolean othersUpdatesAreVisible(int) throws java.sql.SQLException;
+    method public boolean ownDeletesAreVisible(int) throws java.sql.SQLException;
+    method public boolean ownInsertsAreVisible(int) throws java.sql.SQLException;
+    method public boolean ownUpdatesAreVisible(int) throws java.sql.SQLException;
+    method public boolean storesLowerCaseIdentifiers() throws java.sql.SQLException;
+    method public boolean storesLowerCaseQuotedIdentifiers() throws java.sql.SQLException;
+    method public boolean storesMixedCaseIdentifiers() throws java.sql.SQLException;
+    method public boolean storesMixedCaseQuotedIdentifiers() throws java.sql.SQLException;
+    method public boolean storesUpperCaseIdentifiers() throws java.sql.SQLException;
+    method public boolean storesUpperCaseQuotedIdentifiers() throws java.sql.SQLException;
+    method public boolean supportsANSI92EntryLevelSQL() throws java.sql.SQLException;
+    method public boolean supportsANSI92FullSQL() throws java.sql.SQLException;
+    method public boolean supportsANSI92IntermediateSQL() throws java.sql.SQLException;
+    method public boolean supportsAlterTableWithAddColumn() throws java.sql.SQLException;
+    method public boolean supportsAlterTableWithDropColumn() throws java.sql.SQLException;
+    method public boolean supportsBatchUpdates() throws java.sql.SQLException;
+    method public boolean supportsCatalogsInDataManipulation() throws java.sql.SQLException;
+    method public boolean supportsCatalogsInIndexDefinitions() throws java.sql.SQLException;
+    method public boolean supportsCatalogsInPrivilegeDefinitions() throws java.sql.SQLException;
+    method public boolean supportsCatalogsInProcedureCalls() throws java.sql.SQLException;
+    method public boolean supportsCatalogsInTableDefinitions() throws java.sql.SQLException;
+    method public boolean supportsColumnAliasing() throws java.sql.SQLException;
+    method public boolean supportsConvert() throws java.sql.SQLException;
+    method public boolean supportsConvert(int, int) throws java.sql.SQLException;
+    method public boolean supportsCoreSQLGrammar() throws java.sql.SQLException;
+    method public boolean supportsCorrelatedSubqueries() throws java.sql.SQLException;
+    method public boolean supportsDataDefinitionAndDataManipulationTransactions() throws java.sql.SQLException;
+    method public boolean supportsDataManipulationTransactionsOnly() throws java.sql.SQLException;
+    method public boolean supportsDifferentTableCorrelationNames() throws java.sql.SQLException;
+    method public boolean supportsExpressionsInOrderBy() throws java.sql.SQLException;
+    method public boolean supportsExtendedSQLGrammar() throws java.sql.SQLException;
+    method public boolean supportsFullOuterJoins() throws java.sql.SQLException;
+    method public boolean supportsGetGeneratedKeys() throws java.sql.SQLException;
+    method public boolean supportsGroupBy() throws java.sql.SQLException;
+    method public boolean supportsGroupByBeyondSelect() throws java.sql.SQLException;
+    method public boolean supportsGroupByUnrelated() throws java.sql.SQLException;
+    method public boolean supportsIntegrityEnhancementFacility() throws java.sql.SQLException;
+    method public boolean supportsLikeEscapeClause() throws java.sql.SQLException;
+    method public boolean supportsLimitedOuterJoins() throws java.sql.SQLException;
+    method public boolean supportsMinimumSQLGrammar() throws java.sql.SQLException;
+    method public boolean supportsMixedCaseIdentifiers() throws java.sql.SQLException;
+    method public boolean supportsMixedCaseQuotedIdentifiers() throws java.sql.SQLException;
+    method public boolean supportsMultipleOpenResults() throws java.sql.SQLException;
+    method public boolean supportsMultipleResultSets() throws java.sql.SQLException;
+    method public boolean supportsMultipleTransactions() throws java.sql.SQLException;
+    method public boolean supportsNamedParameters() throws java.sql.SQLException;
+    method public boolean supportsNonNullableColumns() throws java.sql.SQLException;
+    method public boolean supportsOpenCursorsAcrossCommit() throws java.sql.SQLException;
+    method public boolean supportsOpenCursorsAcrossRollback() throws java.sql.SQLException;
+    method public boolean supportsOpenStatementsAcrossCommit() throws java.sql.SQLException;
+    method public boolean supportsOpenStatementsAcrossRollback() throws java.sql.SQLException;
+    method public boolean supportsOrderByUnrelated() throws java.sql.SQLException;
+    method public boolean supportsOuterJoins() throws java.sql.SQLException;
+    method public boolean supportsPositionedDelete() throws java.sql.SQLException;
+    method public boolean supportsPositionedUpdate() throws java.sql.SQLException;
+    method public boolean supportsResultSetConcurrency(int, int) throws java.sql.SQLException;
+    method public boolean supportsResultSetHoldability(int) throws java.sql.SQLException;
+    method public boolean supportsResultSetType(int) throws java.sql.SQLException;
+    method public boolean supportsSavepoints() throws java.sql.SQLException;
+    method public boolean supportsSchemasInDataManipulation() throws java.sql.SQLException;
+    method public boolean supportsSchemasInIndexDefinitions() throws java.sql.SQLException;
+    method public boolean supportsSchemasInPrivilegeDefinitions() throws java.sql.SQLException;
+    method public boolean supportsSchemasInProcedureCalls() throws java.sql.SQLException;
+    method public boolean supportsSchemasInTableDefinitions() throws java.sql.SQLException;
+    method public boolean supportsSelectForUpdate() throws java.sql.SQLException;
+    method public boolean supportsStatementPooling() throws java.sql.SQLException;
+    method public boolean supportsStoredFunctionsUsingCallSyntax() throws java.sql.SQLException;
+    method public boolean supportsStoredProcedures() throws java.sql.SQLException;
+    method public boolean supportsSubqueriesInComparisons() throws java.sql.SQLException;
+    method public boolean supportsSubqueriesInExists() throws java.sql.SQLException;
+    method public boolean supportsSubqueriesInIns() throws java.sql.SQLException;
+    method public boolean supportsSubqueriesInQuantifieds() throws java.sql.SQLException;
+    method public boolean supportsTableCorrelationNames() throws java.sql.SQLException;
+    method public boolean supportsTransactionIsolationLevel(int) throws java.sql.SQLException;
+    method public boolean supportsTransactions() throws java.sql.SQLException;
+    method public boolean supportsUnion() throws java.sql.SQLException;
+    method public boolean supportsUnionAll() throws java.sql.SQLException;
+    method public boolean updatesAreDetected(int) throws java.sql.SQLException;
+    method public boolean usesLocalFilePerTable() throws java.sql.SQLException;
+    method public boolean usesLocalFiles() throws java.sql.SQLException;
     field public static final short attributeNoNulls = 0; // 0x0
     field public static final short attributeNullable = 1; // 0x1
     field public static final short attributeNullableUnknown = 2; // 0x2
@@ -65529,59 +65893,59 @@
   }
 
   public class Date extends java.util.Date {
-    ctor public deprecated Date(int, int, int);
+    ctor @Deprecated public Date(int, int, int);
     ctor public Date(long);
-    method public static java.sql.Date valueOf(java.lang.String);
+    method public static java.sql.Date valueOf(String);
   }
 
-  public abstract interface Driver {
-    method public abstract boolean acceptsURL(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Connection connect(java.lang.String, java.util.Properties) throws java.sql.SQLException;
-    method public abstract int getMajorVersion();
-    method public abstract int getMinorVersion();
-    method public abstract java.sql.DriverPropertyInfo[] getPropertyInfo(java.lang.String, java.util.Properties) throws java.sql.SQLException;
-    method public abstract boolean jdbcCompliant();
+  public interface Driver {
+    method public boolean acceptsURL(String) throws java.sql.SQLException;
+    method public java.sql.Connection connect(String, java.util.Properties) throws java.sql.SQLException;
+    method public int getMajorVersion();
+    method public int getMinorVersion();
+    method public java.sql.DriverPropertyInfo[] getPropertyInfo(String, java.util.Properties) throws java.sql.SQLException;
+    method public boolean jdbcCompliant();
   }
 
   public class DriverManager {
-    method public static synchronized void deregisterDriver(java.sql.Driver) throws java.sql.SQLException;
-    method public static java.sql.Connection getConnection(java.lang.String, java.util.Properties) throws java.sql.SQLException;
-    method public static java.sql.Connection getConnection(java.lang.String, java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public static java.sql.Connection getConnection(java.lang.String) throws java.sql.SQLException;
-    method public static java.sql.Driver getDriver(java.lang.String) throws java.sql.SQLException;
+    method public static void deregisterDriver(java.sql.Driver) throws java.sql.SQLException;
+    method public static java.sql.Connection getConnection(String, java.util.Properties) throws java.sql.SQLException;
+    method public static java.sql.Connection getConnection(String, String, String) throws java.sql.SQLException;
+    method public static java.sql.Connection getConnection(String) throws java.sql.SQLException;
+    method public static java.sql.Driver getDriver(String) throws java.sql.SQLException;
     method public static java.util.Enumeration<java.sql.Driver> getDrivers();
-    method public static deprecated java.io.PrintStream getLogStream();
+    method @Deprecated public static java.io.PrintStream getLogStream();
     method public static java.io.PrintWriter getLogWriter();
     method public static int getLoginTimeout();
-    method public static void println(java.lang.String);
-    method public static synchronized void registerDriver(java.sql.Driver) throws java.sql.SQLException;
-    method public static deprecated void setLogStream(java.io.PrintStream);
+    method public static void println(String);
+    method public static void registerDriver(java.sql.Driver) throws java.sql.SQLException;
+    method @Deprecated public static void setLogStream(java.io.PrintStream);
     method public static void setLogWriter(java.io.PrintWriter);
     method public static void setLoginTimeout(int);
   }
 
   public class DriverPropertyInfo {
-    ctor public DriverPropertyInfo(java.lang.String, java.lang.String);
-    field public java.lang.String[] choices;
-    field public java.lang.String description;
-    field public java.lang.String name;
+    ctor public DriverPropertyInfo(String, String);
+    field public String[] choices;
+    field public String description;
+    field public String name;
     field public boolean required;
-    field public java.lang.String value;
+    field public String value;
   }
 
-  public abstract interface NClob implements java.sql.Clob {
+  public interface NClob extends java.sql.Clob {
   }
 
-  public abstract interface ParameterMetaData implements java.sql.Wrapper {
-    method public abstract java.lang.String getParameterClassName(int) throws java.sql.SQLException;
-    method public abstract int getParameterCount() throws java.sql.SQLException;
-    method public abstract int getParameterMode(int) throws java.sql.SQLException;
-    method public abstract int getParameterType(int) throws java.sql.SQLException;
-    method public abstract java.lang.String getParameterTypeName(int) throws java.sql.SQLException;
-    method public abstract int getPrecision(int) throws java.sql.SQLException;
-    method public abstract int getScale(int) throws java.sql.SQLException;
-    method public abstract int isNullable(int) throws java.sql.SQLException;
-    method public abstract boolean isSigned(int) throws java.sql.SQLException;
+  public interface ParameterMetaData extends java.sql.Wrapper {
+    method public String getParameterClassName(int) throws java.sql.SQLException;
+    method public int getParameterCount() throws java.sql.SQLException;
+    method public int getParameterMode(int) throws java.sql.SQLException;
+    method public int getParameterType(int) throws java.sql.SQLException;
+    method public String getParameterTypeName(int) throws java.sql.SQLException;
+    method public int getPrecision(int) throws java.sql.SQLException;
+    method public int getScale(int) throws java.sql.SQLException;
+    method public int isNullable(int) throws java.sql.SQLException;
+    method public boolean isSigned(int) throws java.sql.SQLException;
     field public static final int parameterModeIn = 1; // 0x1
     field public static final int parameterModeInOut = 2; // 0x2
     field public static final int parameterModeOut = 4; // 0x4
@@ -65591,259 +65955,259 @@
     field public static final int parameterNullableUnknown = 2; // 0x2
   }
 
-  public abstract interface PreparedStatement implements java.sql.Statement {
-    method public abstract void addBatch() throws java.sql.SQLException;
-    method public abstract void clearParameters() throws java.sql.SQLException;
-    method public abstract boolean execute() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet executeQuery() throws java.sql.SQLException;
-    method public abstract int executeUpdate() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSetMetaData getMetaData() throws java.sql.SQLException;
-    method public abstract java.sql.ParameterMetaData getParameterMetaData() throws java.sql.SQLException;
-    method public abstract void setArray(int, java.sql.Array) throws java.sql.SQLException;
-    method public abstract void setAsciiStream(int, java.io.InputStream, int) throws java.sql.SQLException;
-    method public abstract void setAsciiStream(int, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void setAsciiStream(int, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void setBigDecimal(int, java.math.BigDecimal) throws java.sql.SQLException;
-    method public abstract void setBinaryStream(int, java.io.InputStream, int) throws java.sql.SQLException;
-    method public abstract void setBinaryStream(int, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void setBinaryStream(int, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void setBlob(int, java.sql.Blob) throws java.sql.SQLException;
-    method public abstract void setBlob(int, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void setBlob(int, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void setBoolean(int, boolean) throws java.sql.SQLException;
-    method public abstract void setByte(int, byte) throws java.sql.SQLException;
-    method public abstract void setBytes(int, byte[]) throws java.sql.SQLException;
-    method public abstract void setCharacterStream(int, java.io.Reader, int) throws java.sql.SQLException;
-    method public abstract void setCharacterStream(int, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setCharacterStream(int, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setClob(int, java.sql.Clob) throws java.sql.SQLException;
-    method public abstract void setClob(int, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setClob(int, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setDate(int, java.sql.Date) throws java.sql.SQLException;
-    method public abstract void setDate(int, java.sql.Date, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract void setDouble(int, double) throws java.sql.SQLException;
-    method public abstract void setFloat(int, float) throws java.sql.SQLException;
-    method public abstract void setInt(int, int) throws java.sql.SQLException;
-    method public abstract void setLong(int, long) throws java.sql.SQLException;
-    method public abstract void setNCharacterStream(int, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setNCharacterStream(int, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setNClob(int, java.sql.NClob) throws java.sql.SQLException;
-    method public abstract void setNClob(int, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setNClob(int, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setNString(int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setNull(int, int) throws java.sql.SQLException;
-    method public abstract void setNull(int, int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setObject(int, java.lang.Object, int) throws java.sql.SQLException;
-    method public abstract void setObject(int, java.lang.Object) throws java.sql.SQLException;
-    method public abstract void setObject(int, java.lang.Object, int, int) throws java.sql.SQLException;
-    method public abstract void setRef(int, java.sql.Ref) throws java.sql.SQLException;
-    method public abstract void setRowId(int, java.sql.RowId) throws java.sql.SQLException;
-    method public abstract void setSQLXML(int, java.sql.SQLXML) throws java.sql.SQLException;
-    method public abstract void setShort(int, short) throws java.sql.SQLException;
-    method public abstract void setString(int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setTime(int, java.sql.Time) throws java.sql.SQLException;
-    method public abstract void setTime(int, java.sql.Time, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract void setTimestamp(int, java.sql.Timestamp) throws java.sql.SQLException;
-    method public abstract void setTimestamp(int, java.sql.Timestamp, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract void setURL(int, java.net.URL) throws java.sql.SQLException;
-    method public abstract deprecated void setUnicodeStream(int, java.io.InputStream, int) throws java.sql.SQLException;
+  public interface PreparedStatement extends java.sql.Statement {
+    method public void addBatch() throws java.sql.SQLException;
+    method public void clearParameters() throws java.sql.SQLException;
+    method public boolean execute() throws java.sql.SQLException;
+    method public java.sql.ResultSet executeQuery() throws java.sql.SQLException;
+    method public int executeUpdate() throws java.sql.SQLException;
+    method public java.sql.ResultSetMetaData getMetaData() throws java.sql.SQLException;
+    method public java.sql.ParameterMetaData getParameterMetaData() throws java.sql.SQLException;
+    method public void setArray(int, java.sql.Array) throws java.sql.SQLException;
+    method public void setAsciiStream(int, java.io.InputStream, int) throws java.sql.SQLException;
+    method public void setAsciiStream(int, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void setAsciiStream(int, java.io.InputStream) throws java.sql.SQLException;
+    method public void setBigDecimal(int, java.math.BigDecimal) throws java.sql.SQLException;
+    method public void setBinaryStream(int, java.io.InputStream, int) throws java.sql.SQLException;
+    method public void setBinaryStream(int, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void setBinaryStream(int, java.io.InputStream) throws java.sql.SQLException;
+    method public void setBlob(int, java.sql.Blob) throws java.sql.SQLException;
+    method public void setBlob(int, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void setBlob(int, java.io.InputStream) throws java.sql.SQLException;
+    method public void setBoolean(int, boolean) throws java.sql.SQLException;
+    method public void setByte(int, byte) throws java.sql.SQLException;
+    method public void setBytes(int, byte[]) throws java.sql.SQLException;
+    method public void setCharacterStream(int, java.io.Reader, int) throws java.sql.SQLException;
+    method public void setCharacterStream(int, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setCharacterStream(int, java.io.Reader) throws java.sql.SQLException;
+    method public void setClob(int, java.sql.Clob) throws java.sql.SQLException;
+    method public void setClob(int, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setClob(int, java.io.Reader) throws java.sql.SQLException;
+    method public void setDate(int, java.sql.Date) throws java.sql.SQLException;
+    method public void setDate(int, java.sql.Date, java.util.Calendar) throws java.sql.SQLException;
+    method public void setDouble(int, double) throws java.sql.SQLException;
+    method public void setFloat(int, float) throws java.sql.SQLException;
+    method public void setInt(int, int) throws java.sql.SQLException;
+    method public void setLong(int, long) throws java.sql.SQLException;
+    method public void setNCharacterStream(int, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setNCharacterStream(int, java.io.Reader) throws java.sql.SQLException;
+    method public void setNClob(int, java.sql.NClob) throws java.sql.SQLException;
+    method public void setNClob(int, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setNClob(int, java.io.Reader) throws java.sql.SQLException;
+    method public void setNString(int, String) throws java.sql.SQLException;
+    method public void setNull(int, int) throws java.sql.SQLException;
+    method public void setNull(int, int, String) throws java.sql.SQLException;
+    method public void setObject(int, Object, int) throws java.sql.SQLException;
+    method public void setObject(int, Object) throws java.sql.SQLException;
+    method public void setObject(int, Object, int, int) throws java.sql.SQLException;
+    method public void setRef(int, java.sql.Ref) throws java.sql.SQLException;
+    method public void setRowId(int, java.sql.RowId) throws java.sql.SQLException;
+    method public void setSQLXML(int, java.sql.SQLXML) throws java.sql.SQLException;
+    method public void setShort(int, short) throws java.sql.SQLException;
+    method public void setString(int, String) throws java.sql.SQLException;
+    method public void setTime(int, java.sql.Time) throws java.sql.SQLException;
+    method public void setTime(int, java.sql.Time, java.util.Calendar) throws java.sql.SQLException;
+    method public void setTimestamp(int, java.sql.Timestamp) throws java.sql.SQLException;
+    method public void setTimestamp(int, java.sql.Timestamp, java.util.Calendar) throws java.sql.SQLException;
+    method public void setURL(int, java.net.URL) throws java.sql.SQLException;
+    method @Deprecated public void setUnicodeStream(int, java.io.InputStream, int) throws java.sql.SQLException;
   }
 
-  public abstract interface Ref {
-    method public abstract java.lang.String getBaseTypeName() throws java.sql.SQLException;
-    method public abstract java.lang.Object getObject(java.util.Map<java.lang.String, java.lang.Class<?>>) throws java.sql.SQLException;
-    method public abstract java.lang.Object getObject() throws java.sql.SQLException;
-    method public abstract void setObject(java.lang.Object) throws java.sql.SQLException;
+  public interface Ref {
+    method public String getBaseTypeName() throws java.sql.SQLException;
+    method public Object getObject(java.util.Map<java.lang.String,java.lang.Class<?>>) throws java.sql.SQLException;
+    method public Object getObject() throws java.sql.SQLException;
+    method public void setObject(Object) throws java.sql.SQLException;
   }
 
-  public abstract interface ResultSet implements java.lang.AutoCloseable java.sql.Wrapper {
-    method public abstract boolean absolute(int) throws java.sql.SQLException;
-    method public abstract void afterLast() throws java.sql.SQLException;
-    method public abstract void beforeFirst() throws java.sql.SQLException;
-    method public abstract void cancelRowUpdates() throws java.sql.SQLException;
-    method public abstract void clearWarnings() throws java.sql.SQLException;
-    method public abstract void close() throws java.sql.SQLException;
-    method public abstract void deleteRow() throws java.sql.SQLException;
-    method public abstract int findColumn(java.lang.String) throws java.sql.SQLException;
-    method public abstract boolean first() throws java.sql.SQLException;
-    method public abstract java.sql.Array getArray(int) throws java.sql.SQLException;
-    method public abstract java.sql.Array getArray(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.io.InputStream getAsciiStream(int) throws java.sql.SQLException;
-    method public abstract java.io.InputStream getAsciiStream(java.lang.String) throws java.sql.SQLException;
-    method public abstract deprecated java.math.BigDecimal getBigDecimal(int, int) throws java.sql.SQLException;
-    method public abstract deprecated java.math.BigDecimal getBigDecimal(java.lang.String, int) throws java.sql.SQLException;
-    method public abstract java.math.BigDecimal getBigDecimal(int) throws java.sql.SQLException;
-    method public abstract java.math.BigDecimal getBigDecimal(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.io.InputStream getBinaryStream(int) throws java.sql.SQLException;
-    method public abstract java.io.InputStream getBinaryStream(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Blob getBlob(int) throws java.sql.SQLException;
-    method public abstract java.sql.Blob getBlob(java.lang.String) throws java.sql.SQLException;
-    method public abstract boolean getBoolean(int) throws java.sql.SQLException;
-    method public abstract boolean getBoolean(java.lang.String) throws java.sql.SQLException;
-    method public abstract byte getByte(int) throws java.sql.SQLException;
-    method public abstract byte getByte(java.lang.String) throws java.sql.SQLException;
-    method public abstract byte[] getBytes(int) throws java.sql.SQLException;
-    method public abstract byte[] getBytes(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.io.Reader getCharacterStream(int) throws java.sql.SQLException;
-    method public abstract java.io.Reader getCharacterStream(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Clob getClob(int) throws java.sql.SQLException;
-    method public abstract java.sql.Clob getClob(java.lang.String) throws java.sql.SQLException;
-    method public abstract int getConcurrency() throws java.sql.SQLException;
-    method public abstract java.lang.String getCursorName() throws java.sql.SQLException;
-    method public abstract java.sql.Date getDate(int) throws java.sql.SQLException;
-    method public abstract java.sql.Date getDate(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Date getDate(int, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract java.sql.Date getDate(java.lang.String, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract double getDouble(int) throws java.sql.SQLException;
-    method public abstract double getDouble(java.lang.String) throws java.sql.SQLException;
-    method public abstract int getFetchDirection() throws java.sql.SQLException;
-    method public abstract int getFetchSize() throws java.sql.SQLException;
-    method public abstract float getFloat(int) throws java.sql.SQLException;
-    method public abstract float getFloat(java.lang.String) throws java.sql.SQLException;
-    method public abstract int getHoldability() throws java.sql.SQLException;
-    method public abstract int getInt(int) throws java.sql.SQLException;
-    method public abstract int getInt(java.lang.String) throws java.sql.SQLException;
-    method public abstract long getLong(int) throws java.sql.SQLException;
-    method public abstract long getLong(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.ResultSetMetaData getMetaData() throws java.sql.SQLException;
-    method public abstract java.io.Reader getNCharacterStream(int) throws java.sql.SQLException;
-    method public abstract java.io.Reader getNCharacterStream(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.NClob getNClob(int) throws java.sql.SQLException;
-    method public abstract java.sql.NClob getNClob(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.lang.String getNString(int) throws java.sql.SQLException;
-    method public abstract java.lang.String getNString(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.lang.Object getObject(int) throws java.sql.SQLException;
-    method public abstract java.lang.Object getObject(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.lang.Object getObject(int, java.util.Map<java.lang.String, java.lang.Class<?>>) throws java.sql.SQLException;
-    method public abstract java.lang.Object getObject(java.lang.String, java.util.Map<java.lang.String, java.lang.Class<?>>) throws java.sql.SQLException;
-    method public abstract java.sql.Ref getRef(int) throws java.sql.SQLException;
-    method public abstract java.sql.Ref getRef(java.lang.String) throws java.sql.SQLException;
-    method public abstract int getRow() throws java.sql.SQLException;
-    method public abstract java.sql.RowId getRowId(int) throws java.sql.SQLException;
-    method public abstract java.sql.RowId getRowId(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.SQLXML getSQLXML(int) throws java.sql.SQLException;
-    method public abstract java.sql.SQLXML getSQLXML(java.lang.String) throws java.sql.SQLException;
-    method public abstract short getShort(int) throws java.sql.SQLException;
-    method public abstract short getShort(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Statement getStatement() throws java.sql.SQLException;
-    method public abstract java.lang.String getString(int) throws java.sql.SQLException;
-    method public abstract java.lang.String getString(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Time getTime(int) throws java.sql.SQLException;
-    method public abstract java.sql.Time getTime(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Time getTime(int, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract java.sql.Time getTime(java.lang.String, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract java.sql.Timestamp getTimestamp(int) throws java.sql.SQLException;
-    method public abstract java.sql.Timestamp getTimestamp(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.Timestamp getTimestamp(int, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract java.sql.Timestamp getTimestamp(java.lang.String, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract int getType() throws java.sql.SQLException;
-    method public abstract java.net.URL getURL(int) throws java.sql.SQLException;
-    method public abstract java.net.URL getURL(java.lang.String) throws java.sql.SQLException;
-    method public abstract deprecated java.io.InputStream getUnicodeStream(int) throws java.sql.SQLException;
-    method public abstract deprecated java.io.InputStream getUnicodeStream(java.lang.String) throws java.sql.SQLException;
-    method public abstract java.sql.SQLWarning getWarnings() throws java.sql.SQLException;
-    method public abstract void insertRow() throws java.sql.SQLException;
-    method public abstract boolean isAfterLast() throws java.sql.SQLException;
-    method public abstract boolean isBeforeFirst() throws java.sql.SQLException;
-    method public abstract boolean isClosed() throws java.sql.SQLException;
-    method public abstract boolean isFirst() throws java.sql.SQLException;
-    method public abstract boolean isLast() throws java.sql.SQLException;
-    method public abstract boolean last() throws java.sql.SQLException;
-    method public abstract void moveToCurrentRow() throws java.sql.SQLException;
-    method public abstract void moveToInsertRow() throws java.sql.SQLException;
-    method public abstract boolean next() throws java.sql.SQLException;
-    method public abstract boolean previous() throws java.sql.SQLException;
-    method public abstract void refreshRow() throws java.sql.SQLException;
-    method public abstract boolean relative(int) throws java.sql.SQLException;
-    method public abstract boolean rowDeleted() throws java.sql.SQLException;
-    method public abstract boolean rowInserted() throws java.sql.SQLException;
-    method public abstract boolean rowUpdated() throws java.sql.SQLException;
-    method public abstract void setFetchDirection(int) throws java.sql.SQLException;
-    method public abstract void setFetchSize(int) throws java.sql.SQLException;
-    method public abstract void updateArray(int, java.sql.Array) throws java.sql.SQLException;
-    method public abstract void updateArray(java.lang.String, java.sql.Array) throws java.sql.SQLException;
-    method public abstract void updateAsciiStream(int, java.io.InputStream, int) throws java.sql.SQLException;
-    method public abstract void updateAsciiStream(java.lang.String, java.io.InputStream, int) throws java.sql.SQLException;
-    method public abstract void updateAsciiStream(int, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void updateAsciiStream(java.lang.String, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void updateAsciiStream(int, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void updateAsciiStream(java.lang.String, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void updateBigDecimal(int, java.math.BigDecimal) throws java.sql.SQLException;
-    method public abstract void updateBigDecimal(java.lang.String, java.math.BigDecimal) throws java.sql.SQLException;
-    method public abstract void updateBinaryStream(int, java.io.InputStream, int) throws java.sql.SQLException;
-    method public abstract void updateBinaryStream(java.lang.String, java.io.InputStream, int) throws java.sql.SQLException;
-    method public abstract void updateBinaryStream(int, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void updateBinaryStream(java.lang.String, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void updateBinaryStream(int, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void updateBinaryStream(java.lang.String, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void updateBlob(int, java.sql.Blob) throws java.sql.SQLException;
-    method public abstract void updateBlob(java.lang.String, java.sql.Blob) throws java.sql.SQLException;
-    method public abstract void updateBlob(int, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void updateBlob(java.lang.String, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void updateBlob(int, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void updateBlob(java.lang.String, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void updateBoolean(int, boolean) throws java.sql.SQLException;
-    method public abstract void updateBoolean(java.lang.String, boolean) throws java.sql.SQLException;
-    method public abstract void updateByte(int, byte) throws java.sql.SQLException;
-    method public abstract void updateByte(java.lang.String, byte) throws java.sql.SQLException;
-    method public abstract void updateBytes(int, byte[]) throws java.sql.SQLException;
-    method public abstract void updateBytes(java.lang.String, byte[]) throws java.sql.SQLException;
-    method public abstract void updateCharacterStream(int, java.io.Reader, int) throws java.sql.SQLException;
-    method public abstract void updateCharacterStream(java.lang.String, java.io.Reader, int) throws java.sql.SQLException;
-    method public abstract void updateCharacterStream(int, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void updateCharacterStream(java.lang.String, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void updateCharacterStream(int, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void updateCharacterStream(java.lang.String, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void updateClob(int, java.sql.Clob) throws java.sql.SQLException;
-    method public abstract void updateClob(java.lang.String, java.sql.Clob) throws java.sql.SQLException;
-    method public abstract void updateClob(int, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void updateClob(java.lang.String, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void updateClob(int, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void updateClob(java.lang.String, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void updateDate(int, java.sql.Date) throws java.sql.SQLException;
-    method public abstract void updateDate(java.lang.String, java.sql.Date) throws java.sql.SQLException;
-    method public abstract void updateDouble(int, double) throws java.sql.SQLException;
-    method public abstract void updateDouble(java.lang.String, double) throws java.sql.SQLException;
-    method public abstract void updateFloat(int, float) throws java.sql.SQLException;
-    method public abstract void updateFloat(java.lang.String, float) throws java.sql.SQLException;
-    method public abstract void updateInt(int, int) throws java.sql.SQLException;
-    method public abstract void updateInt(java.lang.String, int) throws java.sql.SQLException;
-    method public abstract void updateLong(int, long) throws java.sql.SQLException;
-    method public abstract void updateLong(java.lang.String, long) throws java.sql.SQLException;
-    method public abstract void updateNCharacterStream(int, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void updateNCharacterStream(java.lang.String, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void updateNCharacterStream(int, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void updateNCharacterStream(java.lang.String, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void updateNClob(int, java.sql.NClob) throws java.sql.SQLException;
-    method public abstract void updateNClob(java.lang.String, java.sql.NClob) throws java.sql.SQLException;
-    method public abstract void updateNClob(int, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void updateNClob(java.lang.String, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void updateNClob(int, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void updateNClob(java.lang.String, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void updateNString(int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void updateNString(java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract void updateNull(int) throws java.sql.SQLException;
-    method public abstract void updateNull(java.lang.String) throws java.sql.SQLException;
-    method public abstract void updateObject(int, java.lang.Object, int) throws java.sql.SQLException;
-    method public abstract void updateObject(int, java.lang.Object) throws java.sql.SQLException;
-    method public abstract void updateObject(java.lang.String, java.lang.Object, int) throws java.sql.SQLException;
-    method public abstract void updateObject(java.lang.String, java.lang.Object) throws java.sql.SQLException;
-    method public abstract void updateRef(int, java.sql.Ref) throws java.sql.SQLException;
-    method public abstract void updateRef(java.lang.String, java.sql.Ref) throws java.sql.SQLException;
-    method public abstract void updateRow() throws java.sql.SQLException;
-    method public abstract void updateRowId(int, java.sql.RowId) throws java.sql.SQLException;
-    method public abstract void updateRowId(java.lang.String, java.sql.RowId) throws java.sql.SQLException;
-    method public abstract void updateSQLXML(int, java.sql.SQLXML) throws java.sql.SQLException;
-    method public abstract void updateSQLXML(java.lang.String, java.sql.SQLXML) throws java.sql.SQLException;
-    method public abstract void updateShort(int, short) throws java.sql.SQLException;
-    method public abstract void updateShort(java.lang.String, short) throws java.sql.SQLException;
-    method public abstract void updateString(int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void updateString(java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract void updateTime(int, java.sql.Time) throws java.sql.SQLException;
-    method public abstract void updateTime(java.lang.String, java.sql.Time) throws java.sql.SQLException;
-    method public abstract void updateTimestamp(int, java.sql.Timestamp) throws java.sql.SQLException;
-    method public abstract void updateTimestamp(java.lang.String, java.sql.Timestamp) throws java.sql.SQLException;
-    method public abstract boolean wasNull() throws java.sql.SQLException;
+  public interface ResultSet extends java.sql.Wrapper java.lang.AutoCloseable {
+    method public boolean absolute(int) throws java.sql.SQLException;
+    method public void afterLast() throws java.sql.SQLException;
+    method public void beforeFirst() throws java.sql.SQLException;
+    method public void cancelRowUpdates() throws java.sql.SQLException;
+    method public void clearWarnings() throws java.sql.SQLException;
+    method public void close() throws java.sql.SQLException;
+    method public void deleteRow() throws java.sql.SQLException;
+    method public int findColumn(String) throws java.sql.SQLException;
+    method public boolean first() throws java.sql.SQLException;
+    method public java.sql.Array getArray(int) throws java.sql.SQLException;
+    method public java.sql.Array getArray(String) throws java.sql.SQLException;
+    method public java.io.InputStream getAsciiStream(int) throws java.sql.SQLException;
+    method public java.io.InputStream getAsciiStream(String) throws java.sql.SQLException;
+    method @Deprecated public java.math.BigDecimal getBigDecimal(int, int) throws java.sql.SQLException;
+    method @Deprecated public java.math.BigDecimal getBigDecimal(String, int) throws java.sql.SQLException;
+    method public java.math.BigDecimal getBigDecimal(int) throws java.sql.SQLException;
+    method public java.math.BigDecimal getBigDecimal(String) throws java.sql.SQLException;
+    method public java.io.InputStream getBinaryStream(int) throws java.sql.SQLException;
+    method public java.io.InputStream getBinaryStream(String) throws java.sql.SQLException;
+    method public java.sql.Blob getBlob(int) throws java.sql.SQLException;
+    method public java.sql.Blob getBlob(String) throws java.sql.SQLException;
+    method public boolean getBoolean(int) throws java.sql.SQLException;
+    method public boolean getBoolean(String) throws java.sql.SQLException;
+    method public byte getByte(int) throws java.sql.SQLException;
+    method public byte getByte(String) throws java.sql.SQLException;
+    method public byte[] getBytes(int) throws java.sql.SQLException;
+    method public byte[] getBytes(String) throws java.sql.SQLException;
+    method public java.io.Reader getCharacterStream(int) throws java.sql.SQLException;
+    method public java.io.Reader getCharacterStream(String) throws java.sql.SQLException;
+    method public java.sql.Clob getClob(int) throws java.sql.SQLException;
+    method public java.sql.Clob getClob(String) throws java.sql.SQLException;
+    method public int getConcurrency() throws java.sql.SQLException;
+    method public String getCursorName() throws java.sql.SQLException;
+    method public java.sql.Date getDate(int) throws java.sql.SQLException;
+    method public java.sql.Date getDate(String) throws java.sql.SQLException;
+    method public java.sql.Date getDate(int, java.util.Calendar) throws java.sql.SQLException;
+    method public java.sql.Date getDate(String, java.util.Calendar) throws java.sql.SQLException;
+    method public double getDouble(int) throws java.sql.SQLException;
+    method public double getDouble(String) throws java.sql.SQLException;
+    method public int getFetchDirection() throws java.sql.SQLException;
+    method public int getFetchSize() throws java.sql.SQLException;
+    method public float getFloat(int) throws java.sql.SQLException;
+    method public float getFloat(String) throws java.sql.SQLException;
+    method public int getHoldability() throws java.sql.SQLException;
+    method public int getInt(int) throws java.sql.SQLException;
+    method public int getInt(String) throws java.sql.SQLException;
+    method public long getLong(int) throws java.sql.SQLException;
+    method public long getLong(String) throws java.sql.SQLException;
+    method public java.sql.ResultSetMetaData getMetaData() throws java.sql.SQLException;
+    method public java.io.Reader getNCharacterStream(int) throws java.sql.SQLException;
+    method public java.io.Reader getNCharacterStream(String) throws java.sql.SQLException;
+    method public java.sql.NClob getNClob(int) throws java.sql.SQLException;
+    method public java.sql.NClob getNClob(String) throws java.sql.SQLException;
+    method public String getNString(int) throws java.sql.SQLException;
+    method public String getNString(String) throws java.sql.SQLException;
+    method public Object getObject(int) throws java.sql.SQLException;
+    method public Object getObject(String) throws java.sql.SQLException;
+    method public Object getObject(int, java.util.Map<java.lang.String,java.lang.Class<?>>) throws java.sql.SQLException;
+    method public Object getObject(String, java.util.Map<java.lang.String,java.lang.Class<?>>) throws java.sql.SQLException;
+    method public java.sql.Ref getRef(int) throws java.sql.SQLException;
+    method public java.sql.Ref getRef(String) throws java.sql.SQLException;
+    method public int getRow() throws java.sql.SQLException;
+    method public java.sql.RowId getRowId(int) throws java.sql.SQLException;
+    method public java.sql.RowId getRowId(String) throws java.sql.SQLException;
+    method public java.sql.SQLXML getSQLXML(int) throws java.sql.SQLException;
+    method public java.sql.SQLXML getSQLXML(String) throws java.sql.SQLException;
+    method public short getShort(int) throws java.sql.SQLException;
+    method public short getShort(String) throws java.sql.SQLException;
+    method public java.sql.Statement getStatement() throws java.sql.SQLException;
+    method public String getString(int) throws java.sql.SQLException;
+    method public String getString(String) throws java.sql.SQLException;
+    method public java.sql.Time getTime(int) throws java.sql.SQLException;
+    method public java.sql.Time getTime(String) throws java.sql.SQLException;
+    method public java.sql.Time getTime(int, java.util.Calendar) throws java.sql.SQLException;
+    method public java.sql.Time getTime(String, java.util.Calendar) throws java.sql.SQLException;
+    method public java.sql.Timestamp getTimestamp(int) throws java.sql.SQLException;
+    method public java.sql.Timestamp getTimestamp(String) throws java.sql.SQLException;
+    method public java.sql.Timestamp getTimestamp(int, java.util.Calendar) throws java.sql.SQLException;
+    method public java.sql.Timestamp getTimestamp(String, java.util.Calendar) throws java.sql.SQLException;
+    method public int getType() throws java.sql.SQLException;
+    method public java.net.URL getURL(int) throws java.sql.SQLException;
+    method public java.net.URL getURL(String) throws java.sql.SQLException;
+    method @Deprecated public java.io.InputStream getUnicodeStream(int) throws java.sql.SQLException;
+    method @Deprecated public java.io.InputStream getUnicodeStream(String) throws java.sql.SQLException;
+    method public java.sql.SQLWarning getWarnings() throws java.sql.SQLException;
+    method public void insertRow() throws java.sql.SQLException;
+    method public boolean isAfterLast() throws java.sql.SQLException;
+    method public boolean isBeforeFirst() throws java.sql.SQLException;
+    method public boolean isClosed() throws java.sql.SQLException;
+    method public boolean isFirst() throws java.sql.SQLException;
+    method public boolean isLast() throws java.sql.SQLException;
+    method public boolean last() throws java.sql.SQLException;
+    method public void moveToCurrentRow() throws java.sql.SQLException;
+    method public void moveToInsertRow() throws java.sql.SQLException;
+    method public boolean next() throws java.sql.SQLException;
+    method public boolean previous() throws java.sql.SQLException;
+    method public void refreshRow() throws java.sql.SQLException;
+    method public boolean relative(int) throws java.sql.SQLException;
+    method public boolean rowDeleted() throws java.sql.SQLException;
+    method public boolean rowInserted() throws java.sql.SQLException;
+    method public boolean rowUpdated() throws java.sql.SQLException;
+    method public void setFetchDirection(int) throws java.sql.SQLException;
+    method public void setFetchSize(int) throws java.sql.SQLException;
+    method public void updateArray(int, java.sql.Array) throws java.sql.SQLException;
+    method public void updateArray(String, java.sql.Array) throws java.sql.SQLException;
+    method public void updateAsciiStream(int, java.io.InputStream, int) throws java.sql.SQLException;
+    method public void updateAsciiStream(String, java.io.InputStream, int) throws java.sql.SQLException;
+    method public void updateAsciiStream(int, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void updateAsciiStream(String, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void updateAsciiStream(int, java.io.InputStream) throws java.sql.SQLException;
+    method public void updateAsciiStream(String, java.io.InputStream) throws java.sql.SQLException;
+    method public void updateBigDecimal(int, java.math.BigDecimal) throws java.sql.SQLException;
+    method public void updateBigDecimal(String, java.math.BigDecimal) throws java.sql.SQLException;
+    method public void updateBinaryStream(int, java.io.InputStream, int) throws java.sql.SQLException;
+    method public void updateBinaryStream(String, java.io.InputStream, int) throws java.sql.SQLException;
+    method public void updateBinaryStream(int, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void updateBinaryStream(String, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void updateBinaryStream(int, java.io.InputStream) throws java.sql.SQLException;
+    method public void updateBinaryStream(String, java.io.InputStream) throws java.sql.SQLException;
+    method public void updateBlob(int, java.sql.Blob) throws java.sql.SQLException;
+    method public void updateBlob(String, java.sql.Blob) throws java.sql.SQLException;
+    method public void updateBlob(int, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void updateBlob(String, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void updateBlob(int, java.io.InputStream) throws java.sql.SQLException;
+    method public void updateBlob(String, java.io.InputStream) throws java.sql.SQLException;
+    method public void updateBoolean(int, boolean) throws java.sql.SQLException;
+    method public void updateBoolean(String, boolean) throws java.sql.SQLException;
+    method public void updateByte(int, byte) throws java.sql.SQLException;
+    method public void updateByte(String, byte) throws java.sql.SQLException;
+    method public void updateBytes(int, byte[]) throws java.sql.SQLException;
+    method public void updateBytes(String, byte[]) throws java.sql.SQLException;
+    method public void updateCharacterStream(int, java.io.Reader, int) throws java.sql.SQLException;
+    method public void updateCharacterStream(String, java.io.Reader, int) throws java.sql.SQLException;
+    method public void updateCharacterStream(int, java.io.Reader, long) throws java.sql.SQLException;
+    method public void updateCharacterStream(String, java.io.Reader, long) throws java.sql.SQLException;
+    method public void updateCharacterStream(int, java.io.Reader) throws java.sql.SQLException;
+    method public void updateCharacterStream(String, java.io.Reader) throws java.sql.SQLException;
+    method public void updateClob(int, java.sql.Clob) throws java.sql.SQLException;
+    method public void updateClob(String, java.sql.Clob) throws java.sql.SQLException;
+    method public void updateClob(int, java.io.Reader, long) throws java.sql.SQLException;
+    method public void updateClob(String, java.io.Reader, long) throws java.sql.SQLException;
+    method public void updateClob(int, java.io.Reader) throws java.sql.SQLException;
+    method public void updateClob(String, java.io.Reader) throws java.sql.SQLException;
+    method public void updateDate(int, java.sql.Date) throws java.sql.SQLException;
+    method public void updateDate(String, java.sql.Date) throws java.sql.SQLException;
+    method public void updateDouble(int, double) throws java.sql.SQLException;
+    method public void updateDouble(String, double) throws java.sql.SQLException;
+    method public void updateFloat(int, float) throws java.sql.SQLException;
+    method public void updateFloat(String, float) throws java.sql.SQLException;
+    method public void updateInt(int, int) throws java.sql.SQLException;
+    method public void updateInt(String, int) throws java.sql.SQLException;
+    method public void updateLong(int, long) throws java.sql.SQLException;
+    method public void updateLong(String, long) throws java.sql.SQLException;
+    method public void updateNCharacterStream(int, java.io.Reader, long) throws java.sql.SQLException;
+    method public void updateNCharacterStream(String, java.io.Reader, long) throws java.sql.SQLException;
+    method public void updateNCharacterStream(int, java.io.Reader) throws java.sql.SQLException;
+    method public void updateNCharacterStream(String, java.io.Reader) throws java.sql.SQLException;
+    method public void updateNClob(int, java.sql.NClob) throws java.sql.SQLException;
+    method public void updateNClob(String, java.sql.NClob) throws java.sql.SQLException;
+    method public void updateNClob(int, java.io.Reader, long) throws java.sql.SQLException;
+    method public void updateNClob(String, java.io.Reader, long) throws java.sql.SQLException;
+    method public void updateNClob(int, java.io.Reader) throws java.sql.SQLException;
+    method public void updateNClob(String, java.io.Reader) throws java.sql.SQLException;
+    method public void updateNString(int, String) throws java.sql.SQLException;
+    method public void updateNString(String, String) throws java.sql.SQLException;
+    method public void updateNull(int) throws java.sql.SQLException;
+    method public void updateNull(String) throws java.sql.SQLException;
+    method public void updateObject(int, Object, int) throws java.sql.SQLException;
+    method public void updateObject(int, Object) throws java.sql.SQLException;
+    method public void updateObject(String, Object, int) throws java.sql.SQLException;
+    method public void updateObject(String, Object) throws java.sql.SQLException;
+    method public void updateRef(int, java.sql.Ref) throws java.sql.SQLException;
+    method public void updateRef(String, java.sql.Ref) throws java.sql.SQLException;
+    method public void updateRow() throws java.sql.SQLException;
+    method public void updateRowId(int, java.sql.RowId) throws java.sql.SQLException;
+    method public void updateRowId(String, java.sql.RowId) throws java.sql.SQLException;
+    method public void updateSQLXML(int, java.sql.SQLXML) throws java.sql.SQLException;
+    method public void updateSQLXML(String, java.sql.SQLXML) throws java.sql.SQLException;
+    method public void updateShort(int, short) throws java.sql.SQLException;
+    method public void updateShort(String, short) throws java.sql.SQLException;
+    method public void updateString(int, String) throws java.sql.SQLException;
+    method public void updateString(String, String) throws java.sql.SQLException;
+    method public void updateTime(int, java.sql.Time) throws java.sql.SQLException;
+    method public void updateTime(String, java.sql.Time) throws java.sql.SQLException;
+    method public void updateTimestamp(int, java.sql.Timestamp) throws java.sql.SQLException;
+    method public void updateTimestamp(String, java.sql.Timestamp) throws java.sql.SQLException;
+    method public boolean wasNull() throws java.sql.SQLException;
     field public static final int CLOSE_CURSORS_AT_COMMIT = 2; // 0x2
     field public static final int CONCUR_READ_ONLY = 1007; // 0x3ef
     field public static final int CONCUR_UPDATABLE = 1008; // 0x3f0
@@ -65856,43 +66220,41 @@
     field public static final int TYPE_SCROLL_SENSITIVE = 1005; // 0x3ed
   }
 
-  public abstract interface ResultSetMetaData implements java.sql.Wrapper {
-    method public abstract java.lang.String getCatalogName(int) throws java.sql.SQLException;
-    method public abstract java.lang.String getColumnClassName(int) throws java.sql.SQLException;
-    method public abstract int getColumnCount() throws java.sql.SQLException;
-    method public abstract int getColumnDisplaySize(int) throws java.sql.SQLException;
-    method public abstract java.lang.String getColumnLabel(int) throws java.sql.SQLException;
-    method public abstract java.lang.String getColumnName(int) throws java.sql.SQLException;
-    method public abstract int getColumnType(int) throws java.sql.SQLException;
-    method public abstract java.lang.String getColumnTypeName(int) throws java.sql.SQLException;
-    method public abstract int getPrecision(int) throws java.sql.SQLException;
-    method public abstract int getScale(int) throws java.sql.SQLException;
-    method public abstract java.lang.String getSchemaName(int) throws java.sql.SQLException;
-    method public abstract java.lang.String getTableName(int) throws java.sql.SQLException;
-    method public abstract boolean isAutoIncrement(int) throws java.sql.SQLException;
-    method public abstract boolean isCaseSensitive(int) throws java.sql.SQLException;
-    method public abstract boolean isCurrency(int) throws java.sql.SQLException;
-    method public abstract boolean isDefinitelyWritable(int) throws java.sql.SQLException;
-    method public abstract int isNullable(int) throws java.sql.SQLException;
-    method public abstract boolean isReadOnly(int) throws java.sql.SQLException;
-    method public abstract boolean isSearchable(int) throws java.sql.SQLException;
-    method public abstract boolean isSigned(int) throws java.sql.SQLException;
-    method public abstract boolean isWritable(int) throws java.sql.SQLException;
+  public interface ResultSetMetaData extends java.sql.Wrapper {
+    method public String getCatalogName(int) throws java.sql.SQLException;
+    method public String getColumnClassName(int) throws java.sql.SQLException;
+    method public int getColumnCount() throws java.sql.SQLException;
+    method public int getColumnDisplaySize(int) throws java.sql.SQLException;
+    method public String getColumnLabel(int) throws java.sql.SQLException;
+    method public String getColumnName(int) throws java.sql.SQLException;
+    method public int getColumnType(int) throws java.sql.SQLException;
+    method public String getColumnTypeName(int) throws java.sql.SQLException;
+    method public int getPrecision(int) throws java.sql.SQLException;
+    method public int getScale(int) throws java.sql.SQLException;
+    method public String getSchemaName(int) throws java.sql.SQLException;
+    method public String getTableName(int) throws java.sql.SQLException;
+    method public boolean isAutoIncrement(int) throws java.sql.SQLException;
+    method public boolean isCaseSensitive(int) throws java.sql.SQLException;
+    method public boolean isCurrency(int) throws java.sql.SQLException;
+    method public boolean isDefinitelyWritable(int) throws java.sql.SQLException;
+    method public int isNullable(int) throws java.sql.SQLException;
+    method public boolean isReadOnly(int) throws java.sql.SQLException;
+    method public boolean isSearchable(int) throws java.sql.SQLException;
+    method public boolean isSigned(int) throws java.sql.SQLException;
+    method public boolean isWritable(int) throws java.sql.SQLException;
     field public static final int columnNoNulls = 0; // 0x0
     field public static final int columnNullable = 1; // 0x1
     field public static final int columnNullableUnknown = 2; // 0x2
   }
 
-  public abstract interface RowId {
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract byte[] getBytes();
-    method public abstract int hashCode();
-    method public abstract java.lang.String toString();
+  public interface RowId {
+    method public boolean equals(Object);
+    method public byte[] getBytes();
+    method public int hashCode();
+    method public String toString();
   }
 
-  public final class RowIdLifetime extends java.lang.Enum {
-    method public static java.sql.RowIdLifetime valueOf(java.lang.String);
-    method public static final java.sql.RowIdLifetime[] values();
+  public enum RowIdLifetime {
     enum_constant public static final java.sql.RowIdLifetime ROWID_UNSUPPORTED;
     enum_constant public static final java.sql.RowIdLifetime ROWID_VALID_FOREVER;
     enum_constant public static final java.sql.RowIdLifetime ROWID_VALID_OTHER;
@@ -65902,307 +66264,307 @@
 
   public class SQLClientInfoException extends java.sql.SQLException {
     ctor public SQLClientInfoException();
-    ctor public SQLClientInfoException(java.util.Map<java.lang.String, java.sql.ClientInfoStatus>);
-    ctor public SQLClientInfoException(java.util.Map<java.lang.String, java.sql.ClientInfoStatus>, java.lang.Throwable);
-    ctor public SQLClientInfoException(java.lang.String, java.util.Map<java.lang.String, java.sql.ClientInfoStatus>);
-    ctor public SQLClientInfoException(java.lang.String, java.util.Map<java.lang.String, java.sql.ClientInfoStatus>, java.lang.Throwable);
-    ctor public SQLClientInfoException(java.lang.String, java.lang.String, java.util.Map<java.lang.String, java.sql.ClientInfoStatus>);
-    ctor public SQLClientInfoException(java.lang.String, java.lang.String, java.util.Map<java.lang.String, java.sql.ClientInfoStatus>, java.lang.Throwable);
-    ctor public SQLClientInfoException(java.lang.String, java.lang.String, int, java.util.Map<java.lang.String, java.sql.ClientInfoStatus>);
-    ctor public SQLClientInfoException(java.lang.String, java.lang.String, int, java.util.Map<java.lang.String, java.sql.ClientInfoStatus>, java.lang.Throwable);
-    method public java.util.Map<java.lang.String, java.sql.ClientInfoStatus> getFailedProperties();
+    ctor public SQLClientInfoException(java.util.Map<java.lang.String,java.sql.ClientInfoStatus>);
+    ctor public SQLClientInfoException(java.util.Map<java.lang.String,java.sql.ClientInfoStatus>, Throwable);
+    ctor public SQLClientInfoException(String, java.util.Map<java.lang.String,java.sql.ClientInfoStatus>);
+    ctor public SQLClientInfoException(String, java.util.Map<java.lang.String,java.sql.ClientInfoStatus>, Throwable);
+    ctor public SQLClientInfoException(String, String, java.util.Map<java.lang.String,java.sql.ClientInfoStatus>);
+    ctor public SQLClientInfoException(String, String, java.util.Map<java.lang.String,java.sql.ClientInfoStatus>, Throwable);
+    ctor public SQLClientInfoException(String, String, int, java.util.Map<java.lang.String,java.sql.ClientInfoStatus>);
+    ctor public SQLClientInfoException(String, String, int, java.util.Map<java.lang.String,java.sql.ClientInfoStatus>, Throwable);
+    method public java.util.Map<java.lang.String,java.sql.ClientInfoStatus> getFailedProperties();
   }
 
-  public abstract interface SQLData {
-    method public abstract java.lang.String getSQLTypeName() throws java.sql.SQLException;
-    method public abstract void readSQL(java.sql.SQLInput, java.lang.String) throws java.sql.SQLException;
-    method public abstract void writeSQL(java.sql.SQLOutput) throws java.sql.SQLException;
+  public interface SQLData {
+    method public String getSQLTypeName() throws java.sql.SQLException;
+    method public void readSQL(java.sql.SQLInput, String) throws java.sql.SQLException;
+    method public void writeSQL(java.sql.SQLOutput) throws java.sql.SQLException;
   }
 
   public class SQLDataException extends java.sql.SQLNonTransientException {
     ctor public SQLDataException();
-    ctor public SQLDataException(java.lang.String);
-    ctor public SQLDataException(java.lang.String, java.lang.String);
-    ctor public SQLDataException(java.lang.String, java.lang.String, int);
-    ctor public SQLDataException(java.lang.Throwable);
-    ctor public SQLDataException(java.lang.String, java.lang.Throwable);
-    ctor public SQLDataException(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLDataException(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLDataException(String);
+    ctor public SQLDataException(String, String);
+    ctor public SQLDataException(String, String, int);
+    ctor public SQLDataException(Throwable);
+    ctor public SQLDataException(String, Throwable);
+    ctor public SQLDataException(String, String, Throwable);
+    ctor public SQLDataException(String, String, int, Throwable);
   }
 
-  public class SQLException extends java.lang.Exception implements java.lang.Iterable {
-    ctor public SQLException(java.lang.String, java.lang.String, int);
-    ctor public SQLException(java.lang.String, java.lang.String);
-    ctor public SQLException(java.lang.String);
+  public class SQLException extends java.lang.Exception implements java.lang.Iterable<java.lang.Throwable> {
+    ctor public SQLException(String, String, int);
+    ctor public SQLException(String, String);
+    ctor public SQLException(String);
     ctor public SQLException();
-    ctor public SQLException(java.lang.Throwable);
-    ctor public SQLException(java.lang.String, java.lang.Throwable);
-    ctor public SQLException(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLException(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLException(Throwable);
+    ctor public SQLException(String, Throwable);
+    ctor public SQLException(String, String, Throwable);
+    ctor public SQLException(String, String, int, Throwable);
     method public int getErrorCode();
     method public java.sql.SQLException getNextException();
-    method public java.lang.String getSQLState();
+    method public String getSQLState();
     method public java.util.Iterator<java.lang.Throwable> iterator();
     method public void setNextException(java.sql.SQLException);
   }
 
   public class SQLFeatureNotSupportedException extends java.sql.SQLNonTransientException {
     ctor public SQLFeatureNotSupportedException();
-    ctor public SQLFeatureNotSupportedException(java.lang.String);
-    ctor public SQLFeatureNotSupportedException(java.lang.String, java.lang.String);
-    ctor public SQLFeatureNotSupportedException(java.lang.String, java.lang.String, int);
-    ctor public SQLFeatureNotSupportedException(java.lang.Throwable);
-    ctor public SQLFeatureNotSupportedException(java.lang.String, java.lang.Throwable);
-    ctor public SQLFeatureNotSupportedException(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLFeatureNotSupportedException(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLFeatureNotSupportedException(String);
+    ctor public SQLFeatureNotSupportedException(String, String);
+    ctor public SQLFeatureNotSupportedException(String, String, int);
+    ctor public SQLFeatureNotSupportedException(Throwable);
+    ctor public SQLFeatureNotSupportedException(String, Throwable);
+    ctor public SQLFeatureNotSupportedException(String, String, Throwable);
+    ctor public SQLFeatureNotSupportedException(String, String, int, Throwable);
   }
 
-  public abstract interface SQLInput {
-    method public abstract java.sql.Array readArray() throws java.sql.SQLException;
-    method public abstract java.io.InputStream readAsciiStream() throws java.sql.SQLException;
-    method public abstract java.math.BigDecimal readBigDecimal() throws java.sql.SQLException;
-    method public abstract java.io.InputStream readBinaryStream() throws java.sql.SQLException;
-    method public abstract java.sql.Blob readBlob() throws java.sql.SQLException;
-    method public abstract boolean readBoolean() throws java.sql.SQLException;
-    method public abstract byte readByte() throws java.sql.SQLException;
-    method public abstract byte[] readBytes() throws java.sql.SQLException;
-    method public abstract java.io.Reader readCharacterStream() throws java.sql.SQLException;
-    method public abstract java.sql.Clob readClob() throws java.sql.SQLException;
-    method public abstract java.sql.Date readDate() throws java.sql.SQLException;
-    method public abstract double readDouble() throws java.sql.SQLException;
-    method public abstract float readFloat() throws java.sql.SQLException;
-    method public abstract int readInt() throws java.sql.SQLException;
-    method public abstract long readLong() throws java.sql.SQLException;
-    method public abstract java.sql.NClob readNClob() throws java.sql.SQLException;
-    method public abstract java.lang.String readNString() throws java.sql.SQLException;
-    method public abstract java.lang.Object readObject() throws java.sql.SQLException;
-    method public abstract java.sql.Ref readRef() throws java.sql.SQLException;
-    method public abstract java.sql.RowId readRowId() throws java.sql.SQLException;
-    method public abstract java.sql.SQLXML readSQLXML() throws java.sql.SQLException;
-    method public abstract short readShort() throws java.sql.SQLException;
-    method public abstract java.lang.String readString() throws java.sql.SQLException;
-    method public abstract java.sql.Time readTime() throws java.sql.SQLException;
-    method public abstract java.sql.Timestamp readTimestamp() throws java.sql.SQLException;
-    method public abstract java.net.URL readURL() throws java.sql.SQLException;
-    method public abstract boolean wasNull() throws java.sql.SQLException;
+  public interface SQLInput {
+    method public java.sql.Array readArray() throws java.sql.SQLException;
+    method public java.io.InputStream readAsciiStream() throws java.sql.SQLException;
+    method public java.math.BigDecimal readBigDecimal() throws java.sql.SQLException;
+    method public java.io.InputStream readBinaryStream() throws java.sql.SQLException;
+    method public java.sql.Blob readBlob() throws java.sql.SQLException;
+    method public boolean readBoolean() throws java.sql.SQLException;
+    method public byte readByte() throws java.sql.SQLException;
+    method public byte[] readBytes() throws java.sql.SQLException;
+    method public java.io.Reader readCharacterStream() throws java.sql.SQLException;
+    method public java.sql.Clob readClob() throws java.sql.SQLException;
+    method public java.sql.Date readDate() throws java.sql.SQLException;
+    method public double readDouble() throws java.sql.SQLException;
+    method public float readFloat() throws java.sql.SQLException;
+    method public int readInt() throws java.sql.SQLException;
+    method public long readLong() throws java.sql.SQLException;
+    method public java.sql.NClob readNClob() throws java.sql.SQLException;
+    method public String readNString() throws java.sql.SQLException;
+    method public Object readObject() throws java.sql.SQLException;
+    method public java.sql.Ref readRef() throws java.sql.SQLException;
+    method public java.sql.RowId readRowId() throws java.sql.SQLException;
+    method public java.sql.SQLXML readSQLXML() throws java.sql.SQLException;
+    method public short readShort() throws java.sql.SQLException;
+    method public String readString() throws java.sql.SQLException;
+    method public java.sql.Time readTime() throws java.sql.SQLException;
+    method public java.sql.Timestamp readTimestamp() throws java.sql.SQLException;
+    method public java.net.URL readURL() throws java.sql.SQLException;
+    method public boolean wasNull() throws java.sql.SQLException;
   }
 
   public class SQLIntegrityConstraintViolationException extends java.sql.SQLNonTransientException {
     ctor public SQLIntegrityConstraintViolationException();
-    ctor public SQLIntegrityConstraintViolationException(java.lang.String);
-    ctor public SQLIntegrityConstraintViolationException(java.lang.String, java.lang.String);
-    ctor public SQLIntegrityConstraintViolationException(java.lang.String, java.lang.String, int);
-    ctor public SQLIntegrityConstraintViolationException(java.lang.Throwable);
-    ctor public SQLIntegrityConstraintViolationException(java.lang.String, java.lang.Throwable);
-    ctor public SQLIntegrityConstraintViolationException(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLIntegrityConstraintViolationException(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLIntegrityConstraintViolationException(String);
+    ctor public SQLIntegrityConstraintViolationException(String, String);
+    ctor public SQLIntegrityConstraintViolationException(String, String, int);
+    ctor public SQLIntegrityConstraintViolationException(Throwable);
+    ctor public SQLIntegrityConstraintViolationException(String, Throwable);
+    ctor public SQLIntegrityConstraintViolationException(String, String, Throwable);
+    ctor public SQLIntegrityConstraintViolationException(String, String, int, Throwable);
   }
 
   public class SQLInvalidAuthorizationSpecException extends java.sql.SQLNonTransientException {
     ctor public SQLInvalidAuthorizationSpecException();
-    ctor public SQLInvalidAuthorizationSpecException(java.lang.String);
-    ctor public SQLInvalidAuthorizationSpecException(java.lang.String, java.lang.String);
-    ctor public SQLInvalidAuthorizationSpecException(java.lang.String, java.lang.String, int);
-    ctor public SQLInvalidAuthorizationSpecException(java.lang.Throwable);
-    ctor public SQLInvalidAuthorizationSpecException(java.lang.String, java.lang.Throwable);
-    ctor public SQLInvalidAuthorizationSpecException(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLInvalidAuthorizationSpecException(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLInvalidAuthorizationSpecException(String);
+    ctor public SQLInvalidAuthorizationSpecException(String, String);
+    ctor public SQLInvalidAuthorizationSpecException(String, String, int);
+    ctor public SQLInvalidAuthorizationSpecException(Throwable);
+    ctor public SQLInvalidAuthorizationSpecException(String, Throwable);
+    ctor public SQLInvalidAuthorizationSpecException(String, String, Throwable);
+    ctor public SQLInvalidAuthorizationSpecException(String, String, int, Throwable);
   }
 
   public class SQLNonTransientConnectionException extends java.sql.SQLNonTransientException {
     ctor public SQLNonTransientConnectionException();
-    ctor public SQLNonTransientConnectionException(java.lang.String);
-    ctor public SQLNonTransientConnectionException(java.lang.String, java.lang.String);
-    ctor public SQLNonTransientConnectionException(java.lang.String, java.lang.String, int);
-    ctor public SQLNonTransientConnectionException(java.lang.Throwable);
-    ctor public SQLNonTransientConnectionException(java.lang.String, java.lang.Throwable);
-    ctor public SQLNonTransientConnectionException(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLNonTransientConnectionException(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLNonTransientConnectionException(String);
+    ctor public SQLNonTransientConnectionException(String, String);
+    ctor public SQLNonTransientConnectionException(String, String, int);
+    ctor public SQLNonTransientConnectionException(Throwable);
+    ctor public SQLNonTransientConnectionException(String, Throwable);
+    ctor public SQLNonTransientConnectionException(String, String, Throwable);
+    ctor public SQLNonTransientConnectionException(String, String, int, Throwable);
   }
 
   public class SQLNonTransientException extends java.sql.SQLException {
     ctor public SQLNonTransientException();
-    ctor public SQLNonTransientException(java.lang.String);
-    ctor public SQLNonTransientException(java.lang.String, java.lang.String);
-    ctor public SQLNonTransientException(java.lang.String, java.lang.String, int);
-    ctor public SQLNonTransientException(java.lang.Throwable);
-    ctor public SQLNonTransientException(java.lang.String, java.lang.Throwable);
-    ctor public SQLNonTransientException(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLNonTransientException(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLNonTransientException(String);
+    ctor public SQLNonTransientException(String, String);
+    ctor public SQLNonTransientException(String, String, int);
+    ctor public SQLNonTransientException(Throwable);
+    ctor public SQLNonTransientException(String, Throwable);
+    ctor public SQLNonTransientException(String, String, Throwable);
+    ctor public SQLNonTransientException(String, String, int, Throwable);
   }
 
-  public abstract interface SQLOutput {
-    method public abstract void writeArray(java.sql.Array) throws java.sql.SQLException;
-    method public abstract void writeAsciiStream(java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void writeBigDecimal(java.math.BigDecimal) throws java.sql.SQLException;
-    method public abstract void writeBinaryStream(java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void writeBlob(java.sql.Blob) throws java.sql.SQLException;
-    method public abstract void writeBoolean(boolean) throws java.sql.SQLException;
-    method public abstract void writeByte(byte) throws java.sql.SQLException;
-    method public abstract void writeBytes(byte[]) throws java.sql.SQLException;
-    method public abstract void writeCharacterStream(java.io.Reader) throws java.sql.SQLException;
-    method public abstract void writeClob(java.sql.Clob) throws java.sql.SQLException;
-    method public abstract void writeDate(java.sql.Date) throws java.sql.SQLException;
-    method public abstract void writeDouble(double) throws java.sql.SQLException;
-    method public abstract void writeFloat(float) throws java.sql.SQLException;
-    method public abstract void writeInt(int) throws java.sql.SQLException;
-    method public abstract void writeLong(long) throws java.sql.SQLException;
-    method public abstract void writeNClob(java.sql.NClob) throws java.sql.SQLException;
-    method public abstract void writeNString(java.lang.String) throws java.sql.SQLException;
-    method public abstract void writeObject(java.sql.SQLData) throws java.sql.SQLException;
-    method public abstract void writeRef(java.sql.Ref) throws java.sql.SQLException;
-    method public abstract void writeRowId(java.sql.RowId) throws java.sql.SQLException;
-    method public abstract void writeSQLXML(java.sql.SQLXML) throws java.sql.SQLException;
-    method public abstract void writeShort(short) throws java.sql.SQLException;
-    method public abstract void writeString(java.lang.String) throws java.sql.SQLException;
-    method public abstract void writeStruct(java.sql.Struct) throws java.sql.SQLException;
-    method public abstract void writeTime(java.sql.Time) throws java.sql.SQLException;
-    method public abstract void writeTimestamp(java.sql.Timestamp) throws java.sql.SQLException;
-    method public abstract void writeURL(java.net.URL) throws java.sql.SQLException;
+  public interface SQLOutput {
+    method public void writeArray(java.sql.Array) throws java.sql.SQLException;
+    method public void writeAsciiStream(java.io.InputStream) throws java.sql.SQLException;
+    method public void writeBigDecimal(java.math.BigDecimal) throws java.sql.SQLException;
+    method public void writeBinaryStream(java.io.InputStream) throws java.sql.SQLException;
+    method public void writeBlob(java.sql.Blob) throws java.sql.SQLException;
+    method public void writeBoolean(boolean) throws java.sql.SQLException;
+    method public void writeByte(byte) throws java.sql.SQLException;
+    method public void writeBytes(byte[]) throws java.sql.SQLException;
+    method public void writeCharacterStream(java.io.Reader) throws java.sql.SQLException;
+    method public void writeClob(java.sql.Clob) throws java.sql.SQLException;
+    method public void writeDate(java.sql.Date) throws java.sql.SQLException;
+    method public void writeDouble(double) throws java.sql.SQLException;
+    method public void writeFloat(float) throws java.sql.SQLException;
+    method public void writeInt(int) throws java.sql.SQLException;
+    method public void writeLong(long) throws java.sql.SQLException;
+    method public void writeNClob(java.sql.NClob) throws java.sql.SQLException;
+    method public void writeNString(String) throws java.sql.SQLException;
+    method public void writeObject(java.sql.SQLData) throws java.sql.SQLException;
+    method public void writeRef(java.sql.Ref) throws java.sql.SQLException;
+    method public void writeRowId(java.sql.RowId) throws java.sql.SQLException;
+    method public void writeSQLXML(java.sql.SQLXML) throws java.sql.SQLException;
+    method public void writeShort(short) throws java.sql.SQLException;
+    method public void writeString(String) throws java.sql.SQLException;
+    method public void writeStruct(java.sql.Struct) throws java.sql.SQLException;
+    method public void writeTime(java.sql.Time) throws java.sql.SQLException;
+    method public void writeTimestamp(java.sql.Timestamp) throws java.sql.SQLException;
+    method public void writeURL(java.net.URL) throws java.sql.SQLException;
   }
 
   public final class SQLPermission extends java.security.BasicPermission {
-    ctor public SQLPermission(java.lang.String);
-    ctor public SQLPermission(java.lang.String, java.lang.String);
+    ctor public SQLPermission(String);
+    ctor public SQLPermission(String, String);
   }
 
   public class SQLRecoverableException extends java.sql.SQLException {
     ctor public SQLRecoverableException();
-    ctor public SQLRecoverableException(java.lang.String);
-    ctor public SQLRecoverableException(java.lang.String, java.lang.String);
-    ctor public SQLRecoverableException(java.lang.String, java.lang.String, int);
-    ctor public SQLRecoverableException(java.lang.Throwable);
-    ctor public SQLRecoverableException(java.lang.String, java.lang.Throwable);
-    ctor public SQLRecoverableException(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLRecoverableException(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLRecoverableException(String);
+    ctor public SQLRecoverableException(String, String);
+    ctor public SQLRecoverableException(String, String, int);
+    ctor public SQLRecoverableException(Throwable);
+    ctor public SQLRecoverableException(String, Throwable);
+    ctor public SQLRecoverableException(String, String, Throwable);
+    ctor public SQLRecoverableException(String, String, int, Throwable);
   }
 
   public class SQLSyntaxErrorException extends java.sql.SQLNonTransientException {
     ctor public SQLSyntaxErrorException();
-    ctor public SQLSyntaxErrorException(java.lang.String);
-    ctor public SQLSyntaxErrorException(java.lang.String, java.lang.String);
-    ctor public SQLSyntaxErrorException(java.lang.String, java.lang.String, int);
-    ctor public SQLSyntaxErrorException(java.lang.Throwable);
-    ctor public SQLSyntaxErrorException(java.lang.String, java.lang.Throwable);
-    ctor public SQLSyntaxErrorException(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLSyntaxErrorException(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLSyntaxErrorException(String);
+    ctor public SQLSyntaxErrorException(String, String);
+    ctor public SQLSyntaxErrorException(String, String, int);
+    ctor public SQLSyntaxErrorException(Throwable);
+    ctor public SQLSyntaxErrorException(String, Throwable);
+    ctor public SQLSyntaxErrorException(String, String, Throwable);
+    ctor public SQLSyntaxErrorException(String, String, int, Throwable);
   }
 
   public class SQLTimeoutException extends java.sql.SQLTransientException {
     ctor public SQLTimeoutException();
-    ctor public SQLTimeoutException(java.lang.String);
-    ctor public SQLTimeoutException(java.lang.String, java.lang.String);
-    ctor public SQLTimeoutException(java.lang.String, java.lang.String, int);
-    ctor public SQLTimeoutException(java.lang.Throwable);
-    ctor public SQLTimeoutException(java.lang.String, java.lang.Throwable);
-    ctor public SQLTimeoutException(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLTimeoutException(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLTimeoutException(String);
+    ctor public SQLTimeoutException(String, String);
+    ctor public SQLTimeoutException(String, String, int);
+    ctor public SQLTimeoutException(Throwable);
+    ctor public SQLTimeoutException(String, Throwable);
+    ctor public SQLTimeoutException(String, String, Throwable);
+    ctor public SQLTimeoutException(String, String, int, Throwable);
   }
 
   public class SQLTransactionRollbackException extends java.sql.SQLTransientException {
     ctor public SQLTransactionRollbackException();
-    ctor public SQLTransactionRollbackException(java.lang.String);
-    ctor public SQLTransactionRollbackException(java.lang.String, java.lang.String);
-    ctor public SQLTransactionRollbackException(java.lang.String, java.lang.String, int);
-    ctor public SQLTransactionRollbackException(java.lang.Throwable);
-    ctor public SQLTransactionRollbackException(java.lang.String, java.lang.Throwable);
-    ctor public SQLTransactionRollbackException(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLTransactionRollbackException(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLTransactionRollbackException(String);
+    ctor public SQLTransactionRollbackException(String, String);
+    ctor public SQLTransactionRollbackException(String, String, int);
+    ctor public SQLTransactionRollbackException(Throwable);
+    ctor public SQLTransactionRollbackException(String, Throwable);
+    ctor public SQLTransactionRollbackException(String, String, Throwable);
+    ctor public SQLTransactionRollbackException(String, String, int, Throwable);
   }
 
   public class SQLTransientConnectionException extends java.sql.SQLTransientException {
     ctor public SQLTransientConnectionException();
-    ctor public SQLTransientConnectionException(java.lang.String);
-    ctor public SQLTransientConnectionException(java.lang.String, java.lang.String);
-    ctor public SQLTransientConnectionException(java.lang.String, java.lang.String, int);
-    ctor public SQLTransientConnectionException(java.lang.Throwable);
-    ctor public SQLTransientConnectionException(java.lang.String, java.lang.Throwable);
-    ctor public SQLTransientConnectionException(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLTransientConnectionException(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLTransientConnectionException(String);
+    ctor public SQLTransientConnectionException(String, String);
+    ctor public SQLTransientConnectionException(String, String, int);
+    ctor public SQLTransientConnectionException(Throwable);
+    ctor public SQLTransientConnectionException(String, Throwable);
+    ctor public SQLTransientConnectionException(String, String, Throwable);
+    ctor public SQLTransientConnectionException(String, String, int, Throwable);
   }
 
   public class SQLTransientException extends java.sql.SQLException {
     ctor public SQLTransientException();
-    ctor public SQLTransientException(java.lang.String);
-    ctor public SQLTransientException(java.lang.String, java.lang.String);
-    ctor public SQLTransientException(java.lang.String, java.lang.String, int);
-    ctor public SQLTransientException(java.lang.Throwable);
-    ctor public SQLTransientException(java.lang.String, java.lang.Throwable);
-    ctor public SQLTransientException(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLTransientException(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLTransientException(String);
+    ctor public SQLTransientException(String, String);
+    ctor public SQLTransientException(String, String, int);
+    ctor public SQLTransientException(Throwable);
+    ctor public SQLTransientException(String, Throwable);
+    ctor public SQLTransientException(String, String, Throwable);
+    ctor public SQLTransientException(String, String, int, Throwable);
   }
 
   public class SQLWarning extends java.sql.SQLException {
-    ctor public SQLWarning(java.lang.String, java.lang.String, int);
-    ctor public SQLWarning(java.lang.String, java.lang.String);
-    ctor public SQLWarning(java.lang.String);
+    ctor public SQLWarning(String, String, int);
+    ctor public SQLWarning(String, String);
+    ctor public SQLWarning(String);
     ctor public SQLWarning();
-    ctor public SQLWarning(java.lang.Throwable);
-    ctor public SQLWarning(java.lang.String, java.lang.Throwable);
-    ctor public SQLWarning(java.lang.String, java.lang.String, java.lang.Throwable);
-    ctor public SQLWarning(java.lang.String, java.lang.String, int, java.lang.Throwable);
+    ctor public SQLWarning(Throwable);
+    ctor public SQLWarning(String, Throwable);
+    ctor public SQLWarning(String, String, Throwable);
+    ctor public SQLWarning(String, String, int, Throwable);
     method public java.sql.SQLWarning getNextWarning();
     method public void setNextWarning(java.sql.SQLWarning);
   }
 
-  public abstract interface SQLXML {
-    method public abstract void free() throws java.sql.SQLException;
-    method public abstract java.io.InputStream getBinaryStream() throws java.sql.SQLException;
-    method public abstract java.io.Reader getCharacterStream() throws java.sql.SQLException;
-    method public abstract <T extends javax.xml.transform.Source> T getSource(java.lang.Class<T>) throws java.sql.SQLException;
-    method public abstract java.lang.String getString() throws java.sql.SQLException;
-    method public abstract java.io.OutputStream setBinaryStream() throws java.sql.SQLException;
-    method public abstract java.io.Writer setCharacterStream() throws java.sql.SQLException;
-    method public abstract <T extends javax.xml.transform.Result> T setResult(java.lang.Class<T>) throws java.sql.SQLException;
-    method public abstract void setString(java.lang.String) throws java.sql.SQLException;
+  public interface SQLXML {
+    method public void free() throws java.sql.SQLException;
+    method public java.io.InputStream getBinaryStream() throws java.sql.SQLException;
+    method public java.io.Reader getCharacterStream() throws java.sql.SQLException;
+    method public <T extends javax.xml.transform.Source> T getSource(Class<T>) throws java.sql.SQLException;
+    method public String getString() throws java.sql.SQLException;
+    method public java.io.OutputStream setBinaryStream() throws java.sql.SQLException;
+    method public java.io.Writer setCharacterStream() throws java.sql.SQLException;
+    method public <T extends javax.xml.transform.Result> T setResult(Class<T>) throws java.sql.SQLException;
+    method public void setString(String) throws java.sql.SQLException;
   }
 
-  public abstract interface Savepoint {
-    method public abstract int getSavepointId() throws java.sql.SQLException;
-    method public abstract java.lang.String getSavepointName() throws java.sql.SQLException;
+  public interface Savepoint {
+    method public int getSavepointId() throws java.sql.SQLException;
+    method public String getSavepointName() throws java.sql.SQLException;
   }
 
-  public abstract interface Statement implements java.lang.AutoCloseable java.sql.Wrapper {
-    method public abstract void addBatch(java.lang.String) throws java.sql.SQLException;
-    method public abstract void cancel() throws java.sql.SQLException;
-    method public abstract void clearBatch() throws java.sql.SQLException;
-    method public abstract void clearWarnings() throws java.sql.SQLException;
-    method public abstract void close() throws java.sql.SQLException;
-    method public abstract boolean execute(java.lang.String) throws java.sql.SQLException;
-    method public abstract boolean execute(java.lang.String, int) throws java.sql.SQLException;
-    method public abstract boolean execute(java.lang.String, int[]) throws java.sql.SQLException;
-    method public abstract boolean execute(java.lang.String, java.lang.String[]) throws java.sql.SQLException;
-    method public abstract int[] executeBatch() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet executeQuery(java.lang.String) throws java.sql.SQLException;
-    method public abstract int executeUpdate(java.lang.String) throws java.sql.SQLException;
-    method public abstract int executeUpdate(java.lang.String, int) throws java.sql.SQLException;
-    method public abstract int executeUpdate(java.lang.String, int[]) throws java.sql.SQLException;
-    method public abstract int executeUpdate(java.lang.String, java.lang.String[]) throws java.sql.SQLException;
-    method public abstract java.sql.Connection getConnection() throws java.sql.SQLException;
-    method public abstract int getFetchDirection() throws java.sql.SQLException;
-    method public abstract int getFetchSize() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getGeneratedKeys() throws java.sql.SQLException;
-    method public abstract int getMaxFieldSize() throws java.sql.SQLException;
-    method public abstract int getMaxRows() throws java.sql.SQLException;
-    method public abstract boolean getMoreResults() throws java.sql.SQLException;
-    method public abstract boolean getMoreResults(int) throws java.sql.SQLException;
-    method public abstract int getQueryTimeout() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getResultSet() throws java.sql.SQLException;
-    method public abstract int getResultSetConcurrency() throws java.sql.SQLException;
-    method public abstract int getResultSetHoldability() throws java.sql.SQLException;
-    method public abstract int getResultSetType() throws java.sql.SQLException;
-    method public abstract int getUpdateCount() throws java.sql.SQLException;
-    method public abstract java.sql.SQLWarning getWarnings() throws java.sql.SQLException;
-    method public abstract boolean isClosed() throws java.sql.SQLException;
-    method public abstract boolean isPoolable() throws java.sql.SQLException;
-    method public abstract void setCursorName(java.lang.String) throws java.sql.SQLException;
-    method public abstract void setEscapeProcessing(boolean) throws java.sql.SQLException;
-    method public abstract void setFetchDirection(int) throws java.sql.SQLException;
-    method public abstract void setFetchSize(int) throws java.sql.SQLException;
-    method public abstract void setMaxFieldSize(int) throws java.sql.SQLException;
-    method public abstract void setMaxRows(int) throws java.sql.SQLException;
-    method public abstract void setPoolable(boolean) throws java.sql.SQLException;
-    method public abstract void setQueryTimeout(int) throws java.sql.SQLException;
+  public interface Statement extends java.sql.Wrapper java.lang.AutoCloseable {
+    method public void addBatch(String) throws java.sql.SQLException;
+    method public void cancel() throws java.sql.SQLException;
+    method public void clearBatch() throws java.sql.SQLException;
+    method public void clearWarnings() throws java.sql.SQLException;
+    method public void close() throws java.sql.SQLException;
+    method public boolean execute(String) throws java.sql.SQLException;
+    method public boolean execute(String, int) throws java.sql.SQLException;
+    method public boolean execute(String, int[]) throws java.sql.SQLException;
+    method public boolean execute(String, String[]) throws java.sql.SQLException;
+    method public int[] executeBatch() throws java.sql.SQLException;
+    method public java.sql.ResultSet executeQuery(String) throws java.sql.SQLException;
+    method public int executeUpdate(String) throws java.sql.SQLException;
+    method public int executeUpdate(String, int) throws java.sql.SQLException;
+    method public int executeUpdate(String, int[]) throws java.sql.SQLException;
+    method public int executeUpdate(String, String[]) throws java.sql.SQLException;
+    method public java.sql.Connection getConnection() throws java.sql.SQLException;
+    method public int getFetchDirection() throws java.sql.SQLException;
+    method public int getFetchSize() throws java.sql.SQLException;
+    method public java.sql.ResultSet getGeneratedKeys() throws java.sql.SQLException;
+    method public int getMaxFieldSize() throws java.sql.SQLException;
+    method public int getMaxRows() throws java.sql.SQLException;
+    method public boolean getMoreResults() throws java.sql.SQLException;
+    method public boolean getMoreResults(int) throws java.sql.SQLException;
+    method public int getQueryTimeout() throws java.sql.SQLException;
+    method public java.sql.ResultSet getResultSet() throws java.sql.SQLException;
+    method public int getResultSetConcurrency() throws java.sql.SQLException;
+    method public int getResultSetHoldability() throws java.sql.SQLException;
+    method public int getResultSetType() throws java.sql.SQLException;
+    method public int getUpdateCount() throws java.sql.SQLException;
+    method public java.sql.SQLWarning getWarnings() throws java.sql.SQLException;
+    method public boolean isClosed() throws java.sql.SQLException;
+    method public boolean isPoolable() throws java.sql.SQLException;
+    method public void setCursorName(String) throws java.sql.SQLException;
+    method public void setEscapeProcessing(boolean) throws java.sql.SQLException;
+    method public void setFetchDirection(int) throws java.sql.SQLException;
+    method public void setFetchSize(int) throws java.sql.SQLException;
+    method public void setMaxFieldSize(int) throws java.sql.SQLException;
+    method public void setMaxRows(int) throws java.sql.SQLException;
+    method public void setPoolable(boolean) throws java.sql.SQLException;
+    method public void setQueryTimeout(int) throws java.sql.SQLException;
     field public static final int CLOSE_ALL_RESULTS = 3; // 0x3
     field public static final int CLOSE_CURRENT_RESULT = 1; // 0x1
     field public static final int EXECUTE_FAILED = -3; // 0xfffffffd
@@ -66212,20 +66574,20 @@
     field public static final int SUCCESS_NO_INFO = -2; // 0xfffffffe
   }
 
-  public abstract interface Struct {
-    method public abstract java.lang.Object[] getAttributes() throws java.sql.SQLException;
-    method public abstract java.lang.Object[] getAttributes(java.util.Map<java.lang.String, java.lang.Class<?>>) throws java.sql.SQLException;
-    method public abstract java.lang.String getSQLTypeName() throws java.sql.SQLException;
+  public interface Struct {
+    method public Object[] getAttributes() throws java.sql.SQLException;
+    method public Object[] getAttributes(java.util.Map<java.lang.String,java.lang.Class<?>>) throws java.sql.SQLException;
+    method public String getSQLTypeName() throws java.sql.SQLException;
   }
 
   public class Time extends java.util.Date {
-    ctor public deprecated Time(int, int, int);
+    ctor @Deprecated public Time(int, int, int);
     ctor public Time(long);
-    method public static java.sql.Time valueOf(java.lang.String);
+    method public static java.sql.Time valueOf(String);
   }
 
   public class Timestamp extends java.util.Date {
-    ctor public deprecated Timestamp(int, int, int, int, int, int, int);
+    ctor @Deprecated public Timestamp(int, int, int, int, int, int, int);
     ctor public Timestamp(long);
     method public boolean after(java.sql.Timestamp);
     method public boolean before(java.sql.Timestamp);
@@ -66233,7 +66595,7 @@
     method public boolean equals(java.sql.Timestamp);
     method public int getNanos();
     method public void setNanos(int);
-    method public static java.sql.Timestamp valueOf(java.lang.String);
+    method public static java.sql.Timestamp valueOf(String);
   }
 
   public class Types {
@@ -66275,9 +66637,9 @@
     field public static final int VARCHAR = 12; // 0xc
   }
 
-  public abstract interface Wrapper {
-    method public abstract boolean isWrapperFor(java.lang.Class<?>) throws java.sql.SQLException;
-    method public abstract <T> T unwrap(java.lang.Class<T>) throws java.sql.SQLException;
+  public interface Wrapper {
+    method public boolean isWrapperFor(Class<?>) throws java.sql.SQLException;
+    method public <T> T unwrap(Class<T>) throws java.sql.SQLException;
   }
 
 }
@@ -66285,49 +66647,49 @@
 package java.text {
 
   public class Annotation {
-    ctor public Annotation(java.lang.Object);
-    method public java.lang.Object getValue();
+    ctor public Annotation(Object);
+    method public Object getValue();
   }
 
-  public abstract interface AttributedCharacterIterator implements java.text.CharacterIterator {
-    method public abstract java.util.Set<java.text.AttributedCharacterIterator.Attribute> getAllAttributeKeys();
-    method public abstract java.lang.Object getAttribute(java.text.AttributedCharacterIterator.Attribute);
-    method public abstract java.util.Map<java.text.AttributedCharacterIterator.Attribute, java.lang.Object> getAttributes();
-    method public abstract int getRunLimit();
-    method public abstract int getRunLimit(java.text.AttributedCharacterIterator.Attribute);
-    method public abstract int getRunLimit(java.util.Set<? extends java.text.AttributedCharacterIterator.Attribute>);
-    method public abstract int getRunStart();
-    method public abstract int getRunStart(java.text.AttributedCharacterIterator.Attribute);
-    method public abstract int getRunStart(java.util.Set<? extends java.text.AttributedCharacterIterator.Attribute>);
+  public interface AttributedCharacterIterator extends java.text.CharacterIterator {
+    method public java.util.Set<java.text.AttributedCharacterIterator.Attribute> getAllAttributeKeys();
+    method public Object getAttribute(java.text.AttributedCharacterIterator.Attribute);
+    method public java.util.Map<java.text.AttributedCharacterIterator.Attribute,java.lang.Object> getAttributes();
+    method public int getRunLimit();
+    method public int getRunLimit(java.text.AttributedCharacterIterator.Attribute);
+    method public int getRunLimit(java.util.Set<? extends java.text.AttributedCharacterIterator.Attribute>);
+    method public int getRunStart();
+    method public int getRunStart(java.text.AttributedCharacterIterator.Attribute);
+    method public int getRunStart(java.util.Set<? extends java.text.AttributedCharacterIterator.Attribute>);
   }
 
   public static class AttributedCharacterIterator.Attribute implements java.io.Serializable {
-    ctor protected AttributedCharacterIterator.Attribute(java.lang.String);
-    method public final boolean equals(java.lang.Object);
-    method protected java.lang.String getName();
+    ctor protected AttributedCharacterIterator.Attribute(String);
+    method public final boolean equals(Object);
+    method protected String getName();
     method public final int hashCode();
-    method protected java.lang.Object readResolve() throws java.io.InvalidObjectException;
+    method protected Object readResolve() throws java.io.InvalidObjectException;
     field public static final java.text.AttributedCharacterIterator.Attribute INPUT_METHOD_SEGMENT;
     field public static final java.text.AttributedCharacterIterator.Attribute LANGUAGE;
     field public static final java.text.AttributedCharacterIterator.Attribute READING;
   }
 
   public class AttributedString {
-    ctor public AttributedString(java.lang.String);
-    ctor public AttributedString(java.lang.String, java.util.Map<? extends java.text.AttributedCharacterIterator.Attribute, ?>);
+    ctor public AttributedString(String);
+    ctor public AttributedString(String, java.util.Map<? extends java.text.AttributedCharacterIterator.Attribute,?>);
     ctor public AttributedString(java.text.AttributedCharacterIterator);
     ctor public AttributedString(java.text.AttributedCharacterIterator, int, int);
     ctor public AttributedString(java.text.AttributedCharacterIterator, int, int, java.text.AttributedCharacterIterator.Attribute[]);
-    method public void addAttribute(java.text.AttributedCharacterIterator.Attribute, java.lang.Object);
-    method public void addAttribute(java.text.AttributedCharacterIterator.Attribute, java.lang.Object, int, int);
-    method public void addAttributes(java.util.Map<? extends java.text.AttributedCharacterIterator.Attribute, ?>, int, int);
+    method public void addAttribute(java.text.AttributedCharacterIterator.Attribute, Object);
+    method public void addAttribute(java.text.AttributedCharacterIterator.Attribute, Object, int, int);
+    method public void addAttributes(java.util.Map<? extends java.text.AttributedCharacterIterator.Attribute,?>, int, int);
     method public java.text.AttributedCharacterIterator getIterator();
     method public java.text.AttributedCharacterIterator getIterator(java.text.AttributedCharacterIterator.Attribute[]);
     method public java.text.AttributedCharacterIterator getIterator(java.text.AttributedCharacterIterator.Attribute[], int, int);
   }
 
   public final class Bidi {
-    ctor public Bidi(java.lang.String, int);
+    ctor public Bidi(String, int);
     ctor public Bidi(java.text.AttributedCharacterIterator);
     ctor public Bidi(char[], int, byte[], int, int, int);
     method public boolean baseIsLeftToRight();
@@ -66342,7 +66704,7 @@
     method public boolean isLeftToRight();
     method public boolean isMixed();
     method public boolean isRightToLeft();
-    method public static void reorderVisually(byte[], int, java.lang.Object[], int, int);
+    method public static void reorderVisually(byte[], int, Object[], int, int);
     method public static boolean requiresBidi(char[], int, int);
     field public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT = -2; // 0xfffffffe
     field public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = -1; // 0xffffffff
@@ -66352,11 +66714,11 @@
 
   public abstract class BreakIterator implements java.lang.Cloneable {
     ctor protected BreakIterator();
-    method public java.lang.Object clone();
+    method public Object clone();
     method public abstract int current();
     method public abstract int first();
     method public abstract int following(int);
-    method public static synchronized java.util.Locale[] getAvailableLocales();
+    method public static java.util.Locale[] getAvailableLocales();
     method public static java.text.BreakIterator getCharacterInstance();
     method public static java.text.BreakIterator getCharacterInstance(java.util.Locale);
     method public static java.text.BreakIterator getLineInstance();
@@ -66372,39 +66734,39 @@
     method public abstract int next();
     method public int preceding(int);
     method public abstract int previous();
-    method public void setText(java.lang.String);
+    method public void setText(String);
     method public abstract void setText(java.text.CharacterIterator);
     field public static final int DONE = -1; // 0xffffffff
   }
 
-  public abstract interface CharacterIterator implements java.lang.Cloneable {
-    method public abstract java.lang.Object clone();
-    method public abstract char current();
-    method public abstract char first();
-    method public abstract int getBeginIndex();
-    method public abstract int getEndIndex();
-    method public abstract int getIndex();
-    method public abstract char last();
-    method public abstract char next();
-    method public abstract char previous();
-    method public abstract char setIndex(int);
+  public interface CharacterIterator extends java.lang.Cloneable {
+    method public Object clone();
+    method public char current();
+    method public char first();
+    method public int getBeginIndex();
+    method public int getEndIndex();
+    method public int getIndex();
+    method public char last();
+    method public char next();
+    method public char previous();
+    method public char setIndex(int);
     field public static final char DONE = 65535; // 0xffff '\uffff'
   }
 
   public class ChoiceFormat extends java.text.NumberFormat {
-    ctor public ChoiceFormat(java.lang.String);
-    ctor public ChoiceFormat(double[], java.lang.String[]);
-    method public void applyPattern(java.lang.String);
-    method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.lang.Object[] getFormats();
+    ctor public ChoiceFormat(String);
+    ctor public ChoiceFormat(double[], String[]);
+    method public void applyPattern(String);
+    method public StringBuffer format(long, StringBuffer, java.text.FieldPosition);
+    method public StringBuffer format(double, StringBuffer, java.text.FieldPosition);
+    method public Object[] getFormats();
     method public double[] getLimits();
     method public static final double nextDouble(double);
     method public static double nextDouble(double, boolean);
-    method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
+    method public Number parse(String, java.text.ParsePosition);
     method public static final double previousDouble(double);
-    method public void setChoices(double[], java.lang.String[]);
-    method public java.lang.String toPattern();
+    method public void setChoices(double[], String[]);
+    method public String toPattern();
   }
 
   public final class CollationElementIterator {
@@ -66416,34 +66778,34 @@
     method public void reset();
     method public static short secondaryOrder(int);
     method public void setOffset(int);
-    method public void setText(java.lang.String);
+    method public void setText(String);
     method public void setText(java.text.CharacterIterator);
     method public static short tertiaryOrder(int);
     field public static final int NULLORDER = -1; // 0xffffffff
   }
 
-  public abstract class CollationKey implements java.lang.Comparable {
-    ctor protected CollationKey(java.lang.String);
+  public abstract class CollationKey implements java.lang.Comparable<java.text.CollationKey> {
+    ctor protected CollationKey(String);
     method public abstract int compareTo(java.text.CollationKey);
-    method public java.lang.String getSourceString();
+    method public String getSourceString();
     method public abstract byte[] toByteArray();
   }
 
-  public abstract class Collator implements java.lang.Cloneable java.util.Comparator {
+  public abstract class Collator implements java.lang.Cloneable java.util.Comparator<java.lang.Object> {
     ctor protected Collator();
-    method public java.lang.Object clone();
-    method public abstract int compare(java.lang.String, java.lang.String);
-    method public int compare(java.lang.Object, java.lang.Object);
-    method public boolean equals(java.lang.String, java.lang.String);
-    method public static synchronized java.util.Locale[] getAvailableLocales();
-    method public abstract java.text.CollationKey getCollationKey(java.lang.String);
-    method public synchronized int getDecomposition();
-    method public static synchronized java.text.Collator getInstance();
-    method public static synchronized java.text.Collator getInstance(java.util.Locale);
-    method public synchronized int getStrength();
+    method public Object clone();
+    method public abstract int compare(String, String);
+    method public int compare(Object, Object);
+    method public boolean equals(String, String);
+    method public static java.util.Locale[] getAvailableLocales();
+    method public abstract java.text.CollationKey getCollationKey(String);
+    method public int getDecomposition();
+    method public static java.text.Collator getInstance();
+    method public static java.text.Collator getInstance(java.util.Locale);
+    method public int getStrength();
     method public abstract int hashCode();
-    method public synchronized void setDecomposition(int);
-    method public synchronized void setStrength(int);
+    method public void setDecomposition(int);
+    method public void setStrength(int);
     field public static final int CANONICAL_DECOMPOSITION = 1; // 0x1
     field public static final int FULL_DECOMPOSITION = 2; // 0x2
     field public static final int IDENTICAL = 3; // 0x3
@@ -66455,31 +66817,31 @@
 
   public abstract class DateFormat extends java.text.Format {
     ctor protected DateFormat();
-    method public final java.lang.StringBuffer format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition);
-    method public abstract java.lang.StringBuffer format(java.util.Date, java.lang.StringBuffer, java.text.FieldPosition);
-    method public final java.lang.String format(java.util.Date);
+    method @NonNull public final StringBuffer format(@NonNull Object, @NonNull StringBuffer, @NonNull java.text.FieldPosition);
+    method @NonNull public abstract StringBuffer format(@NonNull java.util.Date, @NonNull StringBuffer, @NonNull java.text.FieldPosition);
+    method @NonNull public final String format(@NonNull java.util.Date);
     method public static java.util.Locale[] getAvailableLocales();
-    method public java.util.Calendar getCalendar();
-    method public static final java.text.DateFormat getDateInstance();
-    method public static final java.text.DateFormat getDateInstance(int);
-    method public static final java.text.DateFormat getDateInstance(int, java.util.Locale);
-    method public static final java.text.DateFormat getDateTimeInstance();
-    method public static final java.text.DateFormat getDateTimeInstance(int, int);
-    method public static final java.text.DateFormat getDateTimeInstance(int, int, java.util.Locale);
-    method public static final java.text.DateFormat getInstance();
-    method public java.text.NumberFormat getNumberFormat();
-    method public static final java.text.DateFormat getTimeInstance();
-    method public static final java.text.DateFormat getTimeInstance(int);
-    method public static final java.text.DateFormat getTimeInstance(int, java.util.Locale);
-    method public java.util.TimeZone getTimeZone();
+    method @NonNull public java.util.Calendar getCalendar();
+    method @NonNull public static final java.text.DateFormat getDateInstance();
+    method @NonNull public static final java.text.DateFormat getDateInstance(int);
+    method @NonNull public static final java.text.DateFormat getDateInstance(int, @NonNull java.util.Locale);
+    method @NonNull public static final java.text.DateFormat getDateTimeInstance();
+    method @NonNull public static final java.text.DateFormat getDateTimeInstance(int, int);
+    method @NonNull public static final java.text.DateFormat getDateTimeInstance(int, int, @NonNull java.util.Locale);
+    method @NonNull public static final java.text.DateFormat getInstance();
+    method @NonNull public java.text.NumberFormat getNumberFormat();
+    method @NonNull public static final java.text.DateFormat getTimeInstance();
+    method @NonNull public static final java.text.DateFormat getTimeInstance(int);
+    method @NonNull public static final java.text.DateFormat getTimeInstance(int, @NonNull java.util.Locale);
+    method @NonNull public java.util.TimeZone getTimeZone();
     method public boolean isLenient();
-    method public java.util.Date parse(java.lang.String) throws java.text.ParseException;
-    method public abstract java.util.Date parse(java.lang.String, java.text.ParsePosition);
-    method public java.lang.Object parseObject(java.lang.String, java.text.ParsePosition);
-    method public void setCalendar(java.util.Calendar);
+    method @Nullable public java.util.Date parse(@NonNull String) throws java.text.ParseException;
+    method @Nullable public abstract java.util.Date parse(@NonNull String, @NonNull java.text.ParsePosition);
+    method @Nullable public Object parseObject(@NonNull String, @NonNull java.text.ParsePosition);
+    method public void setCalendar(@NonNull java.util.Calendar);
     method public void setLenient(boolean);
-    method public void setNumberFormat(java.text.NumberFormat);
-    method public void setTimeZone(java.util.TimeZone);
+    method public void setNumberFormat(@NonNull java.text.NumberFormat);
+    method public void setTimeZone(@NonNull java.util.TimeZone);
     field public static final int AM_PM_FIELD = 14; // 0xe
     field public static final int DATE_FIELD = 3; // 0x3
     field public static final int DAY_OF_WEEK_FIELD = 9; // 0x9
@@ -66503,124 +66865,124 @@
     field public static final int WEEK_OF_MONTH_FIELD = 13; // 0xd
     field public static final int WEEK_OF_YEAR_FIELD = 12; // 0xc
     field public static final int YEAR_FIELD = 1; // 0x1
-    field protected java.util.Calendar calendar;
-    field protected java.text.NumberFormat numberFormat;
+    field @NonNull protected java.util.Calendar calendar;
+    field @NonNull protected java.text.NumberFormat numberFormat;
   }
 
   public static class DateFormat.Field extends java.text.Format.Field {
-    ctor protected DateFormat.Field(java.lang.String, int);
+    ctor protected DateFormat.Field(@NonNull String, int);
     method public int getCalendarField();
-    method public static java.text.DateFormat.Field ofCalendarField(int);
-    field public static final java.text.DateFormat.Field AM_PM;
-    field public static final java.text.DateFormat.Field DAY_OF_MONTH;
-    field public static final java.text.DateFormat.Field DAY_OF_WEEK;
-    field public static final java.text.DateFormat.Field DAY_OF_WEEK_IN_MONTH;
-    field public static final java.text.DateFormat.Field DAY_OF_YEAR;
-    field public static final java.text.DateFormat.Field ERA;
-    field public static final java.text.DateFormat.Field HOUR0;
-    field public static final java.text.DateFormat.Field HOUR1;
-    field public static final java.text.DateFormat.Field HOUR_OF_DAY0;
-    field public static final java.text.DateFormat.Field HOUR_OF_DAY1;
-    field public static final java.text.DateFormat.Field MILLISECOND;
-    field public static final java.text.DateFormat.Field MINUTE;
-    field public static final java.text.DateFormat.Field MONTH;
-    field public static final java.text.DateFormat.Field SECOND;
-    field public static final java.text.DateFormat.Field TIME_ZONE;
-    field public static final java.text.DateFormat.Field WEEK_OF_MONTH;
-    field public static final java.text.DateFormat.Field WEEK_OF_YEAR;
-    field public static final java.text.DateFormat.Field YEAR;
+    method @NonNull public static java.text.DateFormat.Field ofCalendarField(int);
+    field @NonNull public static final java.text.DateFormat.Field AM_PM;
+    field @NonNull public static final java.text.DateFormat.Field DAY_OF_MONTH;
+    field @NonNull public static final java.text.DateFormat.Field DAY_OF_WEEK;
+    field @NonNull public static final java.text.DateFormat.Field DAY_OF_WEEK_IN_MONTH;
+    field @NonNull public static final java.text.DateFormat.Field DAY_OF_YEAR;
+    field @NonNull public static final java.text.DateFormat.Field ERA;
+    field @NonNull public static final java.text.DateFormat.Field HOUR0;
+    field @NonNull public static final java.text.DateFormat.Field HOUR1;
+    field @NonNull public static final java.text.DateFormat.Field HOUR_OF_DAY0;
+    field @NonNull public static final java.text.DateFormat.Field HOUR_OF_DAY1;
+    field @NonNull public static final java.text.DateFormat.Field MILLISECOND;
+    field @NonNull public static final java.text.DateFormat.Field MINUTE;
+    field @NonNull public static final java.text.DateFormat.Field MONTH;
+    field @NonNull public static final java.text.DateFormat.Field SECOND;
+    field @NonNull public static final java.text.DateFormat.Field TIME_ZONE;
+    field @NonNull public static final java.text.DateFormat.Field WEEK_OF_MONTH;
+    field @NonNull public static final java.text.DateFormat.Field WEEK_OF_YEAR;
+    field @NonNull public static final java.text.DateFormat.Field YEAR;
   }
 
   public class DateFormatSymbols implements java.lang.Cloneable java.io.Serializable {
     ctor public DateFormatSymbols();
     ctor public DateFormatSymbols(java.util.Locale);
-    method public java.lang.Object clone();
-    method public java.lang.String[] getAmPmStrings();
+    method public Object clone();
+    method public String[] getAmPmStrings();
     method public static java.util.Locale[] getAvailableLocales();
-    method public java.lang.String[] getEras();
+    method public String[] getEras();
     method public static final java.text.DateFormatSymbols getInstance();
     method public static final java.text.DateFormatSymbols getInstance(java.util.Locale);
-    method public java.lang.String getLocalPatternChars();
-    method public java.lang.String[] getMonths();
-    method public java.lang.String[] getShortMonths();
-    method public java.lang.String[] getShortWeekdays();
-    method public java.lang.String[] getWeekdays();
-    method public java.lang.String[][] getZoneStrings();
-    method public void setAmPmStrings(java.lang.String[]);
-    method public void setEras(java.lang.String[]);
-    method public void setLocalPatternChars(java.lang.String);
-    method public void setMonths(java.lang.String[]);
-    method public void setShortMonths(java.lang.String[]);
-    method public void setShortWeekdays(java.lang.String[]);
-    method public void setWeekdays(java.lang.String[]);
-    method public void setZoneStrings(java.lang.String[][]);
+    method public String getLocalPatternChars();
+    method public String[] getMonths();
+    method public String[] getShortMonths();
+    method public String[] getShortWeekdays();
+    method public String[] getWeekdays();
+    method public String[][] getZoneStrings();
+    method public void setAmPmStrings(String[]);
+    method public void setEras(String[]);
+    method public void setLocalPatternChars(String);
+    method public void setMonths(String[]);
+    method public void setShortMonths(String[]);
+    method public void setShortWeekdays(String[]);
+    method public void setWeekdays(String[]);
+    method public void setZoneStrings(String[][]);
   }
 
   public class DecimalFormat extends java.text.NumberFormat {
     ctor public DecimalFormat();
-    ctor public DecimalFormat(java.lang.String);
-    ctor public DecimalFormat(java.lang.String, java.text.DecimalFormatSymbols);
-    method public void applyLocalizedPattern(java.lang.String);
-    method public void applyPattern(java.lang.String);
-    method public final java.lang.StringBuffer format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
+    ctor public DecimalFormat(String);
+    ctor public DecimalFormat(String, java.text.DecimalFormatSymbols);
+    method public void applyLocalizedPattern(String);
+    method public void applyPattern(String);
+    method public final StringBuffer format(Object, StringBuffer, java.text.FieldPosition);
+    method public StringBuffer format(double, StringBuffer, java.text.FieldPosition);
+    method public StringBuffer format(long, StringBuffer, java.text.FieldPosition);
     method public java.text.DecimalFormatSymbols getDecimalFormatSymbols();
     method public int getGroupingSize();
     method public int getMultiplier();
-    method public java.lang.String getNegativePrefix();
-    method public java.lang.String getNegativeSuffix();
-    method public java.lang.String getPositivePrefix();
-    method public java.lang.String getPositiveSuffix();
+    method public String getNegativePrefix();
+    method public String getNegativeSuffix();
+    method public String getPositivePrefix();
+    method public String getPositiveSuffix();
     method public boolean isDecimalSeparatorAlwaysShown();
     method public boolean isParseBigDecimal();
-    method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
+    method public Number parse(String, java.text.ParsePosition);
     method public void setDecimalFormatSymbols(java.text.DecimalFormatSymbols);
     method public void setDecimalSeparatorAlwaysShown(boolean);
     method public void setGroupingSize(int);
     method public void setMultiplier(int);
-    method public void setNegativePrefix(java.lang.String);
-    method public void setNegativeSuffix(java.lang.String);
+    method public void setNegativePrefix(String);
+    method public void setNegativeSuffix(String);
     method public void setParseBigDecimal(boolean);
-    method public void setPositivePrefix(java.lang.String);
-    method public void setPositiveSuffix(java.lang.String);
-    method public java.lang.String toLocalizedPattern();
-    method public java.lang.String toPattern();
+    method public void setPositivePrefix(String);
+    method public void setPositiveSuffix(String);
+    method public String toLocalizedPattern();
+    method public String toPattern();
   }
 
   public class DecimalFormatSymbols implements java.lang.Cloneable java.io.Serializable {
     ctor public DecimalFormatSymbols();
     ctor public DecimalFormatSymbols(java.util.Locale);
-    method public java.lang.Object clone();
+    method public Object clone();
     method public static java.util.Locale[] getAvailableLocales();
     method public java.util.Currency getCurrency();
-    method public java.lang.String getCurrencySymbol();
+    method public String getCurrencySymbol();
     method public char getDecimalSeparator();
     method public char getDigit();
-    method public java.lang.String getExponentSeparator();
+    method public String getExponentSeparator();
     method public char getGroupingSeparator();
-    method public java.lang.String getInfinity();
+    method public String getInfinity();
     method public static final java.text.DecimalFormatSymbols getInstance();
     method public static final java.text.DecimalFormatSymbols getInstance(java.util.Locale);
-    method public java.lang.String getInternationalCurrencySymbol();
+    method public String getInternationalCurrencySymbol();
     method public char getMinusSign();
     method public char getMonetaryDecimalSeparator();
-    method public java.lang.String getNaN();
+    method public String getNaN();
     method public char getPatternSeparator();
     method public char getPerMill();
     method public char getPercent();
     method public char getZeroDigit();
     method public void setCurrency(java.util.Currency);
-    method public void setCurrencySymbol(java.lang.String);
+    method public void setCurrencySymbol(String);
     method public void setDecimalSeparator(char);
     method public void setDigit(char);
-    method public void setExponentSeparator(java.lang.String);
+    method public void setExponentSeparator(String);
     method public void setGroupingSeparator(char);
-    method public void setInfinity(java.lang.String);
-    method public void setInternationalCurrencySymbol(java.lang.String);
+    method public void setInfinity(String);
+    method public void setInternationalCurrencySymbol(String);
     method public void setMinusSign(char);
     method public void setMonetaryDecimalSeparator(char);
-    method public void setNaN(java.lang.String);
+    method public void setNaN(String);
     method public void setPatternSeparator(char);
     method public void setPerMill(char);
     method public void setPercent(char);
@@ -66641,52 +67003,50 @@
 
   public abstract class Format implements java.lang.Cloneable java.io.Serializable {
     ctor protected Format();
-    method public java.lang.Object clone();
-    method public final java.lang.String format(java.lang.Object);
-    method public abstract java.lang.StringBuffer format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition);
-    method public java.text.AttributedCharacterIterator formatToCharacterIterator(java.lang.Object);
-    method public abstract java.lang.Object parseObject(java.lang.String, java.text.ParsePosition);
-    method public java.lang.Object parseObject(java.lang.String) throws java.text.ParseException;
+    method public Object clone();
+    method public final String format(Object);
+    method public abstract StringBuffer format(Object, StringBuffer, java.text.FieldPosition);
+    method public java.text.AttributedCharacterIterator formatToCharacterIterator(Object);
+    method public abstract Object parseObject(String, java.text.ParsePosition);
+    method public Object parseObject(String) throws java.text.ParseException;
   }
 
   public static class Format.Field extends java.text.AttributedCharacterIterator.Attribute {
-    ctor protected Format.Field(java.lang.String);
+    ctor protected Format.Field(String);
   }
 
   public class MessageFormat extends java.text.Format {
-    ctor public MessageFormat(java.lang.String);
-    ctor public MessageFormat(java.lang.String, java.util.Locale);
-    method public void applyPattern(java.lang.String);
-    method public final java.lang.StringBuffer format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition);
-    method public static java.lang.String format(java.lang.String, java.lang.Object...);
-    method public final java.lang.StringBuffer format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition);
+    ctor public MessageFormat(String);
+    ctor public MessageFormat(String, java.util.Locale);
+    method public void applyPattern(String);
+    method public final StringBuffer format(Object[], StringBuffer, java.text.FieldPosition);
+    method public static String format(String, java.lang.Object...);
+    method public final StringBuffer format(Object, StringBuffer, java.text.FieldPosition);
     method public java.text.Format[] getFormats();
     method public java.text.Format[] getFormatsByArgumentIndex();
     method public java.util.Locale getLocale();
-    method public java.lang.Object[] parse(java.lang.String, java.text.ParsePosition);
-    method public java.lang.Object[] parse(java.lang.String) throws java.text.ParseException;
-    method public java.lang.Object parseObject(java.lang.String, java.text.ParsePosition);
+    method public Object[] parse(String, java.text.ParsePosition);
+    method public Object[] parse(String) throws java.text.ParseException;
+    method public Object parseObject(String, java.text.ParsePosition);
     method public void setFormat(int, java.text.Format);
     method public void setFormatByArgumentIndex(int, java.text.Format);
     method public void setFormats(java.text.Format[]);
     method public void setFormatsByArgumentIndex(java.text.Format[]);
     method public void setLocale(java.util.Locale);
-    method public java.lang.String toPattern();
+    method public String toPattern();
   }
 
   public static class MessageFormat.Field extends java.text.Format.Field {
-    ctor protected MessageFormat.Field(java.lang.String);
+    ctor protected MessageFormat.Field(String);
     field public static final java.text.MessageFormat.Field ARGUMENT;
   }
 
   public final class Normalizer {
-    method public static boolean isNormalized(java.lang.CharSequence, java.text.Normalizer.Form);
-    method public static java.lang.String normalize(java.lang.CharSequence, java.text.Normalizer.Form);
+    method public static boolean isNormalized(CharSequence, java.text.Normalizer.Form);
+    method public static String normalize(CharSequence, java.text.Normalizer.Form);
   }
 
-  public static final class Normalizer.Form extends java.lang.Enum {
-    method public static java.text.Normalizer.Form valueOf(java.lang.String);
-    method public static final java.text.Normalizer.Form[] values();
+  public enum Normalizer.Form {
     enum_constant public static final java.text.Normalizer.Form NFC;
     enum_constant public static final java.text.Normalizer.Form NFD;
     enum_constant public static final java.text.Normalizer.Form NFKC;
@@ -66695,62 +67055,62 @@
 
   public abstract class NumberFormat extends java.text.Format {
     ctor protected NumberFormat();
-    method public java.lang.StringBuffer format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition);
-    method public final java.lang.String format(double);
-    method public final java.lang.String format(long);
-    method public abstract java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
-    method public abstract java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
+    method @NonNull public StringBuffer format(@NonNull Object, @NonNull StringBuffer, @NonNull java.text.FieldPosition);
+    method @NonNull public final String format(double);
+    method @NonNull public final String format(long);
+    method @NonNull public abstract StringBuffer format(double, @NonNull StringBuffer, @NonNull java.text.FieldPosition);
+    method @NonNull public abstract StringBuffer format(long, @NonNull StringBuffer, @NonNull java.text.FieldPosition);
     method public static java.util.Locale[] getAvailableLocales();
-    method public java.util.Currency getCurrency();
-    method public static final java.text.NumberFormat getCurrencyInstance();
-    method public static java.text.NumberFormat getCurrencyInstance(java.util.Locale);
-    method public static final java.text.NumberFormat getInstance();
-    method public static java.text.NumberFormat getInstance(java.util.Locale);
-    method public static final java.text.NumberFormat getIntegerInstance();
-    method public static java.text.NumberFormat getIntegerInstance(java.util.Locale);
+    method @Nullable public java.util.Currency getCurrency();
+    method @NonNull public static final java.text.NumberFormat getCurrencyInstance();
+    method @NonNull public static java.text.NumberFormat getCurrencyInstance(@NonNull java.util.Locale);
+    method @NonNull public static final java.text.NumberFormat getInstance();
+    method @NonNull public static java.text.NumberFormat getInstance(@NonNull java.util.Locale);
+    method @NonNull public static final java.text.NumberFormat getIntegerInstance();
+    method @NonNull public static java.text.NumberFormat getIntegerInstance(@NonNull java.util.Locale);
     method public int getMaximumFractionDigits();
     method public int getMaximumIntegerDigits();
     method public int getMinimumFractionDigits();
     method public int getMinimumIntegerDigits();
-    method public static final java.text.NumberFormat getNumberInstance();
-    method public static java.text.NumberFormat getNumberInstance(java.util.Locale);
-    method public static final java.text.NumberFormat getPercentInstance();
-    method public static java.text.NumberFormat getPercentInstance(java.util.Locale);
-    method public java.math.RoundingMode getRoundingMode();
+    method @NonNull public static final java.text.NumberFormat getNumberInstance();
+    method @NonNull public static java.text.NumberFormat getNumberInstance(@NonNull java.util.Locale);
+    method @NonNull public static final java.text.NumberFormat getPercentInstance();
+    method @NonNull public static java.text.NumberFormat getPercentInstance(@NonNull java.util.Locale);
+    method @NonNull public java.math.RoundingMode getRoundingMode();
     method public boolean isGroupingUsed();
     method public boolean isParseIntegerOnly();
-    method public abstract java.lang.Number parse(java.lang.String, java.text.ParsePosition);
-    method public java.lang.Number parse(java.lang.String) throws java.text.ParseException;
-    method public final java.lang.Object parseObject(java.lang.String, java.text.ParsePosition);
-    method public void setCurrency(java.util.Currency);
+    method @Nullable public abstract Number parse(@NonNull String, @NonNull java.text.ParsePosition);
+    method @Nullable public Number parse(@NonNull String) throws java.text.ParseException;
+    method @Nullable public final Object parseObject(@NonNull String, @NonNull java.text.ParsePosition);
+    method public void setCurrency(@NonNull java.util.Currency);
     method public void setGroupingUsed(boolean);
     method public void setMaximumFractionDigits(int);
     method public void setMaximumIntegerDigits(int);
     method public void setMinimumFractionDigits(int);
     method public void setMinimumIntegerDigits(int);
     method public void setParseIntegerOnly(boolean);
-    method public void setRoundingMode(java.math.RoundingMode);
+    method public void setRoundingMode(@Nullable java.math.RoundingMode);
     field public static final int FRACTION_FIELD = 1; // 0x1
     field public static final int INTEGER_FIELD = 0; // 0x0
   }
 
   public static class NumberFormat.Field extends java.text.Format.Field {
-    ctor protected NumberFormat.Field(java.lang.String);
-    field public static final java.text.NumberFormat.Field CURRENCY;
-    field public static final java.text.NumberFormat.Field DECIMAL_SEPARATOR;
-    field public static final java.text.NumberFormat.Field EXPONENT;
-    field public static final java.text.NumberFormat.Field EXPONENT_SIGN;
-    field public static final java.text.NumberFormat.Field EXPONENT_SYMBOL;
-    field public static final java.text.NumberFormat.Field FRACTION;
-    field public static final java.text.NumberFormat.Field GROUPING_SEPARATOR;
-    field public static final java.text.NumberFormat.Field INTEGER;
-    field public static final java.text.NumberFormat.Field PERCENT;
-    field public static final java.text.NumberFormat.Field PERMILLE;
-    field public static final java.text.NumberFormat.Field SIGN;
+    ctor protected NumberFormat.Field(@NonNull String);
+    field @NonNull public static final java.text.NumberFormat.Field CURRENCY;
+    field @NonNull public static final java.text.NumberFormat.Field DECIMAL_SEPARATOR;
+    field @NonNull public static final java.text.NumberFormat.Field EXPONENT;
+    field @NonNull public static final java.text.NumberFormat.Field EXPONENT_SIGN;
+    field @NonNull public static final java.text.NumberFormat.Field EXPONENT_SYMBOL;
+    field @NonNull public static final java.text.NumberFormat.Field FRACTION;
+    field @NonNull public static final java.text.NumberFormat.Field GROUPING_SEPARATOR;
+    field @NonNull public static final java.text.NumberFormat.Field INTEGER;
+    field @NonNull public static final java.text.NumberFormat.Field PERCENT;
+    field @NonNull public static final java.text.NumberFormat.Field PERMILLE;
+    field @NonNull public static final java.text.NumberFormat.Field SIGN;
   }
 
   public class ParseException extends java.lang.Exception {
-    ctor public ParseException(java.lang.String, int);
+    ctor public ParseException(String, int);
     method public int getErrorOffset();
   }
 
@@ -66763,36 +67123,36 @@
   }
 
   public class RuleBasedCollator extends java.text.Collator {
-    ctor public RuleBasedCollator(java.lang.String) throws java.text.ParseException;
-    method public synchronized int compare(java.lang.String, java.lang.String);
-    method public java.text.CollationElementIterator getCollationElementIterator(java.lang.String);
+    ctor public RuleBasedCollator(String) throws java.text.ParseException;
+    method public int compare(String, String);
+    method public java.text.CollationElementIterator getCollationElementIterator(String);
     method public java.text.CollationElementIterator getCollationElementIterator(java.text.CharacterIterator);
-    method public synchronized java.text.CollationKey getCollationKey(java.lang.String);
-    method public java.lang.String getRules();
+    method public java.text.CollationKey getCollationKey(String);
+    method public String getRules();
   }
 
   public class SimpleDateFormat extends java.text.DateFormat {
     ctor public SimpleDateFormat();
-    ctor public SimpleDateFormat(java.lang.String);
-    ctor public SimpleDateFormat(java.lang.String, java.util.Locale);
-    ctor public SimpleDateFormat(java.lang.String, java.text.DateFormatSymbols);
-    method public void applyLocalizedPattern(java.lang.String);
-    method public void applyPattern(java.lang.String);
-    method public java.lang.StringBuffer format(java.util.Date, java.lang.StringBuffer, java.text.FieldPosition);
+    ctor public SimpleDateFormat(String);
+    ctor public SimpleDateFormat(String, java.util.Locale);
+    ctor public SimpleDateFormat(String, java.text.DateFormatSymbols);
+    method public void applyLocalizedPattern(String);
+    method public void applyPattern(String);
+    method public StringBuffer format(java.util.Date, StringBuffer, java.text.FieldPosition);
     method public java.util.Date get2DigitYearStart();
     method public java.text.DateFormatSymbols getDateFormatSymbols();
-    method public java.util.Date parse(java.lang.String, java.text.ParsePosition);
+    method public java.util.Date parse(String, java.text.ParsePosition);
     method public void set2DigitYearStart(java.util.Date);
     method public void setDateFormatSymbols(java.text.DateFormatSymbols);
-    method public java.lang.String toLocalizedPattern();
-    method public java.lang.String toPattern();
+    method public String toLocalizedPattern();
+    method public String toPattern();
   }
 
   public final class StringCharacterIterator implements java.text.CharacterIterator {
-    ctor public StringCharacterIterator(java.lang.String);
-    ctor public StringCharacterIterator(java.lang.String, int);
-    ctor public StringCharacterIterator(java.lang.String, int, int, int);
-    method public java.lang.Object clone();
+    ctor public StringCharacterIterator(String);
+    ctor public StringCharacterIterator(String, int);
+    ctor public StringCharacterIterator(String, int, int, int);
+    method public Object clone();
     method public char current();
     method public char first();
     method public int getBeginIndex();
@@ -66802,7 +67162,7 @@
     method public char next();
     method public char previous();
     method public char setIndex(int);
-    method public void setText(java.lang.String);
+    method public void setText(String);
   }
 
 }
@@ -66826,22 +67186,20 @@
   }
 
   public class DateTimeException extends java.lang.RuntimeException {
-    ctor public DateTimeException(java.lang.String);
-    ctor public DateTimeException(java.lang.String, java.lang.Throwable);
+    ctor public DateTimeException(String);
+    ctor public DateTimeException(String, Throwable);
   }
 
-  public final class DayOfWeek extends java.lang.Enum implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+  public enum DayOfWeek implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
     method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
     method public static java.time.DayOfWeek from(java.time.temporal.TemporalAccessor);
-    method public java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public String getDisplayName(java.time.format.TextStyle, java.util.Locale);
     method public long getLong(java.time.temporal.TemporalField);
     method public int getValue();
     method public boolean isSupported(java.time.temporal.TemporalField);
     method public java.time.DayOfWeek minus(long);
     method public static java.time.DayOfWeek of(int);
     method public java.time.DayOfWeek plus(long);
-    method public static java.time.DayOfWeek valueOf(java.lang.String);
-    method public static final java.time.DayOfWeek[] values();
     enum_constant public static final java.time.DayOfWeek FRIDAY;
     enum_constant public static final java.time.DayOfWeek MONDAY;
     enum_constant public static final java.time.DayOfWeek SATURDAY;
@@ -66851,7 +67209,7 @@
     enum_constant public static final java.time.DayOfWeek WEDNESDAY;
   }
 
-  public final class Duration implements java.lang.Comparable java.io.Serializable java.time.temporal.TemporalAmount {
+  public final class Duration implements java.lang.Comparable<java.time.Duration> java.io.Serializable java.time.temporal.TemporalAmount {
     method public java.time.Duration abs();
     method public java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
     method public static java.time.Duration between(java.time.temporal.Temporal, java.time.temporal.Temporal);
@@ -66882,7 +67240,7 @@
     method public static java.time.Duration ofNanos(long);
     method public static java.time.Duration ofSeconds(long);
     method public static java.time.Duration ofSeconds(long, long);
-    method public static java.time.Duration parse(java.lang.CharSequence);
+    method public static java.time.Duration parse(CharSequence);
     method public java.time.Duration plus(java.time.Duration);
     method public java.time.Duration plus(long, java.time.temporal.TemporalUnit);
     method public java.time.Duration plusDays(long);
@@ -66902,7 +67260,7 @@
     field public static final java.time.Duration ZERO;
   }
 
-  public final class Instant implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+  public final class Instant implements java.lang.Comparable<java.time.Instant> java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
     method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
     method public java.time.OffsetDateTime atOffset(java.time.ZoneOffset);
     method public java.time.ZonedDateTime atZone(java.time.ZoneId);
@@ -66925,7 +67283,7 @@
     method public static java.time.Instant ofEpochMilli(long);
     method public static java.time.Instant ofEpochSecond(long);
     method public static java.time.Instant ofEpochSecond(long, long);
-    method public static java.time.Instant parse(java.lang.CharSequence);
+    method public static java.time.Instant parse(CharSequence);
     method public java.time.Instant plus(java.time.temporal.TemporalAmount);
     method public java.time.Instant plus(long, java.time.temporal.TemporalUnit);
     method public java.time.Instant plusMillis(long);
@@ -66972,8 +67330,8 @@
     method public static java.time.LocalDate of(int, int, int);
     method public static java.time.LocalDate ofEpochDay(long);
     method public static java.time.LocalDate ofYearDay(int, int);
-    method public static java.time.LocalDate parse(java.lang.CharSequence);
-    method public static java.time.LocalDate parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public static java.time.LocalDate parse(CharSequence);
+    method public static java.time.LocalDate parse(CharSequence, java.time.format.DateTimeFormatter);
     method public java.time.LocalDate plus(java.time.temporal.TemporalAmount);
     method public java.time.LocalDate plus(long, java.time.temporal.TemporalUnit);
     method public java.time.LocalDate plusDays(long);
@@ -66992,7 +67350,7 @@
     field public static final java.time.LocalDate MIN;
   }
 
-  public final class LocalDateTime implements java.time.chrono.ChronoLocalDateTime java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+  public final class LocalDateTime implements java.time.chrono.ChronoLocalDateTime<java.time.LocalDate> java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
     method public java.time.OffsetDateTime atOffset(java.time.ZoneOffset);
     method public java.time.ZonedDateTime atZone(java.time.ZoneId);
     method public static java.time.LocalDateTime from(java.time.temporal.TemporalAccessor);
@@ -67030,8 +67388,8 @@
     method public static java.time.LocalDateTime of(java.time.LocalDate, java.time.LocalTime);
     method public static java.time.LocalDateTime ofEpochSecond(long, int, java.time.ZoneOffset);
     method public static java.time.LocalDateTime ofInstant(java.time.Instant, java.time.ZoneId);
-    method public static java.time.LocalDateTime parse(java.lang.CharSequence);
-    method public static java.time.LocalDateTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public static java.time.LocalDateTime parse(CharSequence);
+    method public static java.time.LocalDateTime parse(CharSequence, java.time.format.DateTimeFormatter);
     method public java.time.LocalDateTime plus(java.time.temporal.TemporalAmount);
     method public java.time.LocalDateTime plus(long, java.time.temporal.TemporalUnit);
     method public java.time.LocalDateTime plusDays(long);
@@ -67060,12 +67418,12 @@
     field public static final java.time.LocalDateTime MIN;
   }
 
-  public final class LocalTime implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+  public final class LocalTime implements java.lang.Comparable<java.time.LocalTime> java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
     method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
     method public java.time.LocalDateTime atDate(java.time.LocalDate);
     method public java.time.OffsetTime atOffset(java.time.ZoneOffset);
     method public int compareTo(java.time.LocalTime);
-    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public String format(java.time.format.DateTimeFormatter);
     method public static java.time.LocalTime from(java.time.temporal.TemporalAccessor);
     method public int getHour();
     method public long getLong(java.time.temporal.TemporalField);
@@ -67090,8 +67448,8 @@
     method public static java.time.LocalTime of(int, int, int, int);
     method public static java.time.LocalTime ofNanoOfDay(long);
     method public static java.time.LocalTime ofSecondOfDay(long);
-    method public static java.time.LocalTime parse(java.lang.CharSequence);
-    method public static java.time.LocalTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public static java.time.LocalTime parse(CharSequence);
+    method public static java.time.LocalTime parse(CharSequence, java.time.format.DateTimeFormatter);
     method public java.time.LocalTime plus(java.time.temporal.TemporalAmount);
     method public java.time.LocalTime plus(long, java.time.temporal.TemporalUnit);
     method public java.time.LocalTime plusHours(long);
@@ -67114,12 +67472,12 @@
     field public static final java.time.LocalTime NOON;
   }
 
-  public final class Month extends java.lang.Enum implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+  public enum Month implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
     method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
     method public int firstDayOfYear(boolean);
     method public java.time.Month firstMonthOfQuarter();
     method public static java.time.Month from(java.time.temporal.TemporalAccessor);
-    method public java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public String getDisplayName(java.time.format.TextStyle, java.util.Locale);
     method public long getLong(java.time.temporal.TemporalField);
     method public int getValue();
     method public boolean isSupported(java.time.temporal.TemporalField);
@@ -67129,8 +67487,6 @@
     method public java.time.Month minus(long);
     method public static java.time.Month of(int);
     method public java.time.Month plus(long);
-    method public static java.time.Month valueOf(java.lang.String);
-    method public static final java.time.Month[] values();
     enum_constant public static final java.time.Month APRIL;
     enum_constant public static final java.time.Month AUGUST;
     enum_constant public static final java.time.Month DECEMBER;
@@ -67145,11 +67501,11 @@
     enum_constant public static final java.time.Month SEPTEMBER;
   }
 
-  public final class MonthDay implements java.lang.Comparable java.io.Serializable java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+  public final class MonthDay implements java.lang.Comparable<java.time.MonthDay> java.io.Serializable java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
     method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
     method public java.time.LocalDate atYear(int);
     method public int compareTo(java.time.MonthDay);
-    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public String format(java.time.format.DateTimeFormatter);
     method public static java.time.MonthDay from(java.time.temporal.TemporalAccessor);
     method public int getDayOfMonth();
     method public long getLong(java.time.temporal.TemporalField);
@@ -67164,19 +67520,19 @@
     method public static java.time.MonthDay now(java.time.Clock);
     method public static java.time.MonthDay of(java.time.Month, int);
     method public static java.time.MonthDay of(int, int);
-    method public static java.time.MonthDay parse(java.lang.CharSequence);
-    method public static java.time.MonthDay parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public static java.time.MonthDay parse(CharSequence);
+    method public static java.time.MonthDay parse(CharSequence, java.time.format.DateTimeFormatter);
     method public java.time.MonthDay with(java.time.Month);
     method public java.time.MonthDay withDayOfMonth(int);
     method public java.time.MonthDay withMonth(int);
   }
 
-  public final class OffsetDateTime implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+  public final class OffsetDateTime implements java.lang.Comparable<java.time.OffsetDateTime> java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
     method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
     method public java.time.ZonedDateTime atZoneSameInstant(java.time.ZoneId);
     method public java.time.ZonedDateTime atZoneSimilarLocal(java.time.ZoneId);
     method public int compareTo(java.time.OffsetDateTime);
-    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public String format(java.time.format.DateTimeFormatter);
     method public static java.time.OffsetDateTime from(java.time.temporal.TemporalAccessor);
     method public int getDayOfMonth();
     method public java.time.DayOfWeek getDayOfWeek();
@@ -67212,8 +67568,8 @@
     method public static java.time.OffsetDateTime of(java.time.LocalDateTime, java.time.ZoneOffset);
     method public static java.time.OffsetDateTime of(int, int, int, int, int, int, int, java.time.ZoneOffset);
     method public static java.time.OffsetDateTime ofInstant(java.time.Instant, java.time.ZoneId);
-    method public static java.time.OffsetDateTime parse(java.lang.CharSequence);
-    method public static java.time.OffsetDateTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public static java.time.OffsetDateTime parse(CharSequence);
+    method public static java.time.OffsetDateTime parse(CharSequence, java.time.format.DateTimeFormatter);
     method public java.time.OffsetDateTime plus(java.time.temporal.TemporalAmount);
     method public java.time.OffsetDateTime plus(long, java.time.temporal.TemporalUnit);
     method public java.time.OffsetDateTime plusDays(long);
@@ -67250,11 +67606,11 @@
     field public static final java.time.OffsetDateTime MIN;
   }
 
-  public final class OffsetTime implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+  public final class OffsetTime implements java.lang.Comparable<java.time.OffsetTime> java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
     method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
     method public java.time.OffsetDateTime atDate(java.time.LocalDate);
     method public int compareTo(java.time.OffsetTime);
-    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public String format(java.time.format.DateTimeFormatter);
     method public static java.time.OffsetTime from(java.time.temporal.TemporalAccessor);
     method public int getHour();
     method public long getLong(java.time.temporal.TemporalField);
@@ -67279,8 +67635,8 @@
     method public static java.time.OffsetTime of(java.time.LocalTime, java.time.ZoneOffset);
     method public static java.time.OffsetTime of(int, int, int, int, java.time.ZoneOffset);
     method public static java.time.OffsetTime ofInstant(java.time.Instant, java.time.ZoneId);
-    method public static java.time.OffsetTime parse(java.lang.CharSequence);
-    method public static java.time.OffsetTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public static java.time.OffsetTime parse(CharSequence);
+    method public static java.time.OffsetTime parse(CharSequence, java.time.format.DateTimeFormatter);
     method public java.time.OffsetTime plus(java.time.temporal.TemporalAmount);
     method public java.time.OffsetTime plus(long, java.time.temporal.TemporalUnit);
     method public java.time.OffsetTime plusHours(long);
@@ -67324,7 +67680,7 @@
     method public static java.time.Period ofMonths(int);
     method public static java.time.Period ofWeeks(int);
     method public static java.time.Period ofYears(int);
-    method public static java.time.Period parse(java.lang.CharSequence);
+    method public static java.time.Period parse(CharSequence);
     method public java.time.Period plus(java.time.temporal.TemporalAmount);
     method public java.time.Period plusDays(long);
     method public java.time.Period plusMonths(long);
@@ -67337,14 +67693,14 @@
     field public static final java.time.Period ZERO;
   }
 
-  public final class Year implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+  public final class Year implements java.lang.Comparable<java.time.Year> java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
     method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
     method public java.time.LocalDate atDay(int);
     method public java.time.YearMonth atMonth(java.time.Month);
     method public java.time.YearMonth atMonth(int);
     method public java.time.LocalDate atMonthDay(java.time.MonthDay);
     method public int compareTo(java.time.Year);
-    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public String format(java.time.format.DateTimeFormatter);
     method public static java.time.Year from(java.time.temporal.TemporalAccessor);
     method public long getLong(java.time.temporal.TemporalField);
     method public int getValue();
@@ -67363,8 +67719,8 @@
     method public static java.time.Year now(java.time.ZoneId);
     method public static java.time.Year now(java.time.Clock);
     method public static java.time.Year of(int);
-    method public static java.time.Year parse(java.lang.CharSequence);
-    method public static java.time.Year parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public static java.time.Year parse(CharSequence);
+    method public static java.time.Year parse(CharSequence, java.time.format.DateTimeFormatter);
     method public java.time.Year plus(java.time.temporal.TemporalAmount);
     method public java.time.Year plus(long, java.time.temporal.TemporalUnit);
     method public java.time.Year plusYears(long);
@@ -67375,12 +67731,12 @@
     field public static final int MIN_VALUE = -999999999; // 0xc4653601
   }
 
-  public final class YearMonth implements java.lang.Comparable java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+  public final class YearMonth implements java.lang.Comparable<java.time.YearMonth> java.io.Serializable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
     method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
     method public java.time.LocalDate atDay(int);
     method public java.time.LocalDate atEndOfMonth();
     method public int compareTo(java.time.YearMonth);
-    method public java.lang.String format(java.time.format.DateTimeFormatter);
+    method public String format(java.time.format.DateTimeFormatter);
     method public static java.time.YearMonth from(java.time.temporal.TemporalAccessor);
     method public long getLong(java.time.temporal.TemporalField);
     method public java.time.Month getMonth();
@@ -67403,8 +67759,8 @@
     method public static java.time.YearMonth now(java.time.Clock);
     method public static java.time.YearMonth of(int, java.time.Month);
     method public static java.time.YearMonth of(int, int);
-    method public static java.time.YearMonth parse(java.lang.CharSequence);
-    method public static java.time.YearMonth parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public static java.time.YearMonth parse(CharSequence);
+    method public static java.time.YearMonth parse(CharSequence, java.time.format.DateTimeFormatter);
     method public java.time.YearMonth plus(java.time.temporal.TemporalAmount);
     method public java.time.YearMonth plus(long, java.time.temporal.TemporalUnit);
     method public java.time.YearMonth plusMonths(long);
@@ -67419,27 +67775,27 @@
   public abstract class ZoneId implements java.io.Serializable {
     method public static java.time.ZoneId from(java.time.temporal.TemporalAccessor);
     method public static java.util.Set<java.lang.String> getAvailableZoneIds();
-    method public java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
-    method public abstract java.lang.String getId();
+    method public String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public abstract String getId();
     method public abstract java.time.zone.ZoneRules getRules();
     method public java.time.ZoneId normalized();
-    method public static java.time.ZoneId of(java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
-    method public static java.time.ZoneId of(java.lang.String);
-    method public static java.time.ZoneId ofOffset(java.lang.String, java.time.ZoneOffset);
+    method public static java.time.ZoneId of(String, java.util.Map<java.lang.String,java.lang.String>);
+    method public static java.time.ZoneId of(String);
+    method public static java.time.ZoneId ofOffset(String, java.time.ZoneOffset);
     method public static java.time.ZoneId systemDefault();
-    field public static final java.util.Map<java.lang.String, java.lang.String> SHORT_IDS;
+    field public static final java.util.Map<java.lang.String,java.lang.String> SHORT_IDS;
   }
 
-  public final class ZoneOffset extends java.time.ZoneId implements java.lang.Comparable java.io.Serializable java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+  public final class ZoneOffset extends java.time.ZoneId implements java.lang.Comparable<java.time.ZoneOffset> java.io.Serializable java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
     method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
     method public int compareTo(java.time.ZoneOffset);
     method public static java.time.ZoneOffset from(java.time.temporal.TemporalAccessor);
-    method public java.lang.String getId();
+    method public String getId();
     method public long getLong(java.time.temporal.TemporalField);
     method public java.time.zone.ZoneRules getRules();
     method public int getTotalSeconds();
     method public boolean isSupported(java.time.temporal.TemporalField);
-    method public static java.time.ZoneOffset of(java.lang.String);
+    method public static java.time.ZoneOffset of(String);
     method public static java.time.ZoneOffset ofHours(int);
     method public static java.time.ZoneOffset ofHoursMinutes(int, int);
     method public static java.time.ZoneOffset ofHoursMinutesSeconds(int, int, int);
@@ -67449,7 +67805,7 @@
     field public static final java.time.ZoneOffset UTC;
   }
 
-  public final class ZonedDateTime implements java.time.chrono.ChronoZonedDateTime java.io.Serializable java.time.temporal.Temporal {
+  public final class ZonedDateTime implements java.time.chrono.ChronoZonedDateTime<java.time.LocalDate> java.io.Serializable java.time.temporal.Temporal {
     method public static java.time.ZonedDateTime from(java.time.temporal.TemporalAccessor);
     method public int getDayOfMonth();
     method public java.time.DayOfWeek getDayOfWeek();
@@ -67484,8 +67840,8 @@
     method public static java.time.ZonedDateTime ofInstant(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneId);
     method public static java.time.ZonedDateTime ofLocal(java.time.LocalDateTime, java.time.ZoneId, java.time.ZoneOffset);
     method public static java.time.ZonedDateTime ofStrict(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneId);
-    method public static java.time.ZonedDateTime parse(java.lang.CharSequence);
-    method public static java.time.ZonedDateTime parse(java.lang.CharSequence, java.time.format.DateTimeFormatter);
+    method public static java.time.ZonedDateTime parse(CharSequence);
+    method public static java.time.ZonedDateTime parse(CharSequence, java.time.format.DateTimeFormatter);
     method public java.time.ZonedDateTime plus(java.time.temporal.TemporalAmount);
     method public java.time.ZonedDateTime plus(long, java.time.temporal.TemporalUnit);
     method public java.time.ZonedDateTime plusDays(long);
@@ -67525,26 +67881,26 @@
   public abstract class AbstractChronology implements java.time.chrono.Chronology {
     ctor protected AbstractChronology();
     method public int compareTo(java.time.chrono.Chronology);
-    method public java.time.chrono.ChronoLocalDate resolveDate(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.format.ResolverStyle);
+    method public java.time.chrono.ChronoLocalDate resolveDate(java.util.Map<java.time.temporal.TemporalField,java.lang.Long>, java.time.format.ResolverStyle);
   }
 
-  public abstract interface ChronoLocalDate implements java.lang.Comparable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+  public interface ChronoLocalDate extends java.time.temporal.Temporal java.lang.Comparable<java.time.chrono.ChronoLocalDate> java.time.temporal.TemporalAdjuster {
     method public default java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
     method public default java.time.chrono.ChronoLocalDateTime<?> atTime(java.time.LocalTime);
     method public default int compareTo(java.time.chrono.ChronoLocalDate);
-    method public abstract boolean equals(java.lang.Object);
-    method public default java.lang.String format(java.time.format.DateTimeFormatter);
+    method public boolean equals(Object);
+    method public default String format(java.time.format.DateTimeFormatter);
     method public static java.time.chrono.ChronoLocalDate from(java.time.temporal.TemporalAccessor);
-    method public abstract java.time.chrono.Chronology getChronology();
+    method public java.time.chrono.Chronology getChronology();
     method public default java.time.chrono.Era getEra();
-    method public abstract int hashCode();
+    method public int hashCode();
     method public default boolean isAfter(java.time.chrono.ChronoLocalDate);
     method public default boolean isBefore(java.time.chrono.ChronoLocalDate);
     method public default boolean isEqual(java.time.chrono.ChronoLocalDate);
     method public default boolean isLeapYear();
     method public default boolean isSupported(java.time.temporal.TemporalField);
     method public default boolean isSupported(java.time.temporal.TemporalUnit);
-    method public abstract int lengthOfMonth();
+    method public int lengthOfMonth();
     method public default int lengthOfYear();
     method public default java.time.chrono.ChronoLocalDate minus(java.time.temporal.TemporalAmount);
     method public default java.time.chrono.ChronoLocalDate minus(long, java.time.temporal.TemporalUnit);
@@ -67552,21 +67908,21 @@
     method public default java.time.chrono.ChronoLocalDate plus(long, java.time.temporal.TemporalUnit);
     method public static java.util.Comparator<java.time.chrono.ChronoLocalDate> timeLineOrder();
     method public default long toEpochDay();
-    method public abstract java.lang.String toString();
-    method public abstract java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+    method public String toString();
+    method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
     method public default java.time.chrono.ChronoLocalDate with(java.time.temporal.TemporalAdjuster);
     method public default java.time.chrono.ChronoLocalDate with(java.time.temporal.TemporalField, long);
   }
 
-  public abstract interface ChronoLocalDateTime<D extends java.time.chrono.ChronoLocalDate> implements java.lang.Comparable java.time.temporal.Temporal java.time.temporal.TemporalAdjuster {
+  public interface ChronoLocalDateTime<D extends java.time.chrono.ChronoLocalDate> extends java.time.temporal.Temporal java.lang.Comparable<java.time.chrono.ChronoLocalDateTime<?>> java.time.temporal.TemporalAdjuster {
     method public default java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
-    method public abstract java.time.chrono.ChronoZonedDateTime<D> atZone(java.time.ZoneId);
+    method public java.time.chrono.ChronoZonedDateTime<D> atZone(java.time.ZoneId);
     method public default int compareTo(java.time.chrono.ChronoLocalDateTime<?>);
-    method public abstract boolean equals(java.lang.Object);
-    method public default java.lang.String format(java.time.format.DateTimeFormatter);
+    method public boolean equals(Object);
+    method public default String format(java.time.format.DateTimeFormatter);
     method public static java.time.chrono.ChronoLocalDateTime<?> from(java.time.temporal.TemporalAccessor);
     method public default java.time.chrono.Chronology getChronology();
-    method public abstract int hashCode();
+    method public int hashCode();
     method public default boolean isAfter(java.time.chrono.ChronoLocalDateTime<?>);
     method public default boolean isBefore(java.time.chrono.ChronoLocalDateTime<?>);
     method public default boolean isEqual(java.time.chrono.ChronoLocalDateTime<?>);
@@ -67574,42 +67930,42 @@
     method public default java.time.chrono.ChronoLocalDateTime<D> minus(java.time.temporal.TemporalAmount);
     method public default java.time.chrono.ChronoLocalDateTime<D> minus(long, java.time.temporal.TemporalUnit);
     method public default java.time.chrono.ChronoLocalDateTime<D> plus(java.time.temporal.TemporalAmount);
-    method public abstract java.time.chrono.ChronoLocalDateTime<D> plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.chrono.ChronoLocalDateTime<D> plus(long, java.time.temporal.TemporalUnit);
     method public static java.util.Comparator<java.time.chrono.ChronoLocalDateTime<?>> timeLineOrder();
     method public default long toEpochSecond(java.time.ZoneOffset);
     method public default java.time.Instant toInstant(java.time.ZoneOffset);
-    method public abstract D toLocalDate();
-    method public abstract java.time.LocalTime toLocalTime();
-    method public abstract java.lang.String toString();
+    method public D toLocalDate();
+    method public java.time.LocalTime toLocalTime();
+    method public String toString();
     method public default java.time.chrono.ChronoLocalDateTime<D> with(java.time.temporal.TemporalAdjuster);
-    method public abstract java.time.chrono.ChronoLocalDateTime<D> with(java.time.temporal.TemporalField, long);
+    method public java.time.chrono.ChronoLocalDateTime<D> with(java.time.temporal.TemporalField, long);
   }
 
-  public abstract interface ChronoPeriod implements java.time.temporal.TemporalAmount {
+  public interface ChronoPeriod extends java.time.temporal.TemporalAmount {
     method public static java.time.chrono.ChronoPeriod between(java.time.chrono.ChronoLocalDate, java.time.chrono.ChronoLocalDate);
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract java.time.chrono.Chronology getChronology();
-    method public abstract int hashCode();
+    method public boolean equals(Object);
+    method public java.time.chrono.Chronology getChronology();
+    method public int hashCode();
     method public default boolean isNegative();
     method public default boolean isZero();
-    method public abstract java.time.chrono.ChronoPeriod minus(java.time.temporal.TemporalAmount);
-    method public abstract java.time.chrono.ChronoPeriod multipliedBy(int);
+    method public java.time.chrono.ChronoPeriod minus(java.time.temporal.TemporalAmount);
+    method public java.time.chrono.ChronoPeriod multipliedBy(int);
     method public default java.time.chrono.ChronoPeriod negated();
-    method public abstract java.time.chrono.ChronoPeriod normalized();
-    method public abstract java.time.chrono.ChronoPeriod plus(java.time.temporal.TemporalAmount);
-    method public abstract java.lang.String toString();
+    method public java.time.chrono.ChronoPeriod normalized();
+    method public java.time.chrono.ChronoPeriod plus(java.time.temporal.TemporalAmount);
+    method public String toString();
   }
 
-  public abstract interface ChronoZonedDateTime<D extends java.time.chrono.ChronoLocalDate> implements java.lang.Comparable java.time.temporal.Temporal {
+  public interface ChronoZonedDateTime<D extends java.time.chrono.ChronoLocalDate> extends java.time.temporal.Temporal java.lang.Comparable<java.time.chrono.ChronoZonedDateTime<?>> {
     method public default int compareTo(java.time.chrono.ChronoZonedDateTime<?>);
-    method public abstract boolean equals(java.lang.Object);
-    method public default java.lang.String format(java.time.format.DateTimeFormatter);
+    method public boolean equals(Object);
+    method public default String format(java.time.format.DateTimeFormatter);
     method public static java.time.chrono.ChronoZonedDateTime<?> from(java.time.temporal.TemporalAccessor);
     method public default java.time.chrono.Chronology getChronology();
     method public default long getLong(java.time.temporal.TemporalField);
-    method public abstract java.time.ZoneOffset getOffset();
-    method public abstract java.time.ZoneId getZone();
-    method public abstract int hashCode();
+    method public java.time.ZoneOffset getOffset();
+    method public java.time.ZoneId getZone();
+    method public int hashCode();
     method public default boolean isAfter(java.time.chrono.ChronoZonedDateTime<?>);
     method public default boolean isBefore(java.time.chrono.ChronoZonedDateTime<?>);
     method public default boolean isEqual(java.time.chrono.ChronoZonedDateTime<?>);
@@ -67617,60 +67973,60 @@
     method public default java.time.chrono.ChronoZonedDateTime<D> minus(java.time.temporal.TemporalAmount);
     method public default java.time.chrono.ChronoZonedDateTime<D> minus(long, java.time.temporal.TemporalUnit);
     method public default java.time.chrono.ChronoZonedDateTime<D> plus(java.time.temporal.TemporalAmount);
-    method public abstract java.time.chrono.ChronoZonedDateTime<D> plus(long, java.time.temporal.TemporalUnit);
+    method public java.time.chrono.ChronoZonedDateTime<D> plus(long, java.time.temporal.TemporalUnit);
     method public static java.util.Comparator<java.time.chrono.ChronoZonedDateTime<?>> timeLineOrder();
     method public default long toEpochSecond();
     method public default java.time.Instant toInstant();
     method public default D toLocalDate();
-    method public abstract java.time.chrono.ChronoLocalDateTime<D> toLocalDateTime();
+    method public java.time.chrono.ChronoLocalDateTime<D> toLocalDateTime();
     method public default java.time.LocalTime toLocalTime();
-    method public abstract java.lang.String toString();
+    method public String toString();
     method public default java.time.chrono.ChronoZonedDateTime<D> with(java.time.temporal.TemporalAdjuster);
-    method public abstract java.time.chrono.ChronoZonedDateTime<D> with(java.time.temporal.TemporalField, long);
-    method public abstract java.time.chrono.ChronoZonedDateTime<D> withEarlierOffsetAtOverlap();
-    method public abstract java.time.chrono.ChronoZonedDateTime<D> withLaterOffsetAtOverlap();
-    method public abstract java.time.chrono.ChronoZonedDateTime<D> withZoneSameInstant(java.time.ZoneId);
-    method public abstract java.time.chrono.ChronoZonedDateTime<D> withZoneSameLocal(java.time.ZoneId);
+    method public java.time.chrono.ChronoZonedDateTime<D> with(java.time.temporal.TemporalField, long);
+    method public java.time.chrono.ChronoZonedDateTime<D> withEarlierOffsetAtOverlap();
+    method public java.time.chrono.ChronoZonedDateTime<D> withLaterOffsetAtOverlap();
+    method public java.time.chrono.ChronoZonedDateTime<D> withZoneSameInstant(java.time.ZoneId);
+    method public java.time.chrono.ChronoZonedDateTime<D> withZoneSameLocal(java.time.ZoneId);
   }
 
-  public abstract interface Chronology implements java.lang.Comparable {
-    method public abstract int compareTo(java.time.chrono.Chronology);
+  public interface Chronology extends java.lang.Comparable<java.time.chrono.Chronology> {
+    method public int compareTo(java.time.chrono.Chronology);
     method public default java.time.chrono.ChronoLocalDate date(java.time.chrono.Era, int, int, int);
-    method public abstract java.time.chrono.ChronoLocalDate date(int, int, int);
-    method public abstract java.time.chrono.ChronoLocalDate date(java.time.temporal.TemporalAccessor);
-    method public abstract java.time.chrono.ChronoLocalDate dateEpochDay(long);
+    method public java.time.chrono.ChronoLocalDate date(int, int, int);
+    method public java.time.chrono.ChronoLocalDate date(java.time.temporal.TemporalAccessor);
+    method public java.time.chrono.ChronoLocalDate dateEpochDay(long);
     method public default java.time.chrono.ChronoLocalDate dateNow();
     method public default java.time.chrono.ChronoLocalDate dateNow(java.time.ZoneId);
     method public default java.time.chrono.ChronoLocalDate dateNow(java.time.Clock);
     method public default java.time.chrono.ChronoLocalDate dateYearDay(java.time.chrono.Era, int, int);
-    method public abstract java.time.chrono.ChronoLocalDate dateYearDay(int, int);
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract java.time.chrono.Era eraOf(int);
-    method public abstract java.util.List<java.time.chrono.Era> eras();
+    method public java.time.chrono.ChronoLocalDate dateYearDay(int, int);
+    method public boolean equals(Object);
+    method public java.time.chrono.Era eraOf(int);
+    method public java.util.List<java.time.chrono.Era> eras();
     method public static java.time.chrono.Chronology from(java.time.temporal.TemporalAccessor);
     method public static java.util.Set<java.time.chrono.Chronology> getAvailableChronologies();
-    method public abstract java.lang.String getCalendarType();
-    method public default java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
-    method public abstract java.lang.String getId();
-    method public abstract int hashCode();
-    method public abstract boolean isLeapYear(long);
+    method public String getCalendarType();
+    method public default String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public String getId();
+    method public int hashCode();
+    method public boolean isLeapYear(long);
     method public default java.time.chrono.ChronoLocalDateTime<? extends java.time.chrono.ChronoLocalDate> localDateTime(java.time.temporal.TemporalAccessor);
-    method public static java.time.chrono.Chronology of(java.lang.String);
+    method public static java.time.chrono.Chronology of(String);
     method public static java.time.chrono.Chronology ofLocale(java.util.Locale);
     method public default java.time.chrono.ChronoPeriod period(int, int, int);
-    method public abstract int prolepticYear(java.time.chrono.Era, int);
-    method public abstract java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
-    method public abstract java.time.chrono.ChronoLocalDate resolveDate(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.format.ResolverStyle);
-    method public abstract java.lang.String toString();
+    method public int prolepticYear(java.time.chrono.Era, int);
+    method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
+    method public java.time.chrono.ChronoLocalDate resolveDate(java.util.Map<java.time.temporal.TemporalField,java.lang.Long>, java.time.format.ResolverStyle);
+    method public String toString();
     method public default java.time.chrono.ChronoZonedDateTime<? extends java.time.chrono.ChronoLocalDate> zonedDateTime(java.time.temporal.TemporalAccessor);
     method public default java.time.chrono.ChronoZonedDateTime<? extends java.time.chrono.ChronoLocalDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
   }
 
-  public abstract interface Era implements java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
+  public interface Era extends java.time.temporal.TemporalAccessor java.time.temporal.TemporalAdjuster {
     method public default java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
-    method public default java.lang.String getDisplayName(java.time.format.TextStyle, java.util.Locale);
+    method public default String getDisplayName(java.time.format.TextStyle, java.util.Locale);
     method public default long getLong(java.time.temporal.TemporalField);
-    method public abstract int getValue();
+    method public int getValue();
     method public default boolean isSupported(java.time.temporal.TemporalField);
   }
 
@@ -67686,13 +68042,13 @@
     method public java.time.chrono.HijrahDate dateYearDay(int, int);
     method public java.time.chrono.HijrahEra eraOf(int);
     method public java.util.List<java.time.chrono.Era> eras();
-    method public java.lang.String getCalendarType();
-    method public java.lang.String getId();
+    method public String getCalendarType();
+    method public String getId();
     method public boolean isLeapYear(long);
     method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.HijrahDate> localDateTime(java.time.temporal.TemporalAccessor);
     method public int prolepticYear(java.time.chrono.Era, int);
     method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
-    method public java.time.chrono.HijrahDate resolveDate(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.format.ResolverStyle);
+    method public java.time.chrono.HijrahDate resolveDate(java.util.Map<java.time.temporal.TemporalField,java.lang.Long>, java.time.format.ResolverStyle);
     method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.HijrahDate> zonedDateTime(java.time.temporal.TemporalAccessor);
     method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.HijrahDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
     field public static final java.time.chrono.HijrahChronology INSTANCE;
@@ -67714,16 +68070,15 @@
     method public java.time.chrono.HijrahDate plus(java.time.temporal.TemporalAmount);
     method public java.time.chrono.HijrahDate plus(long, java.time.temporal.TemporalUnit);
     method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
     method public java.time.chrono.HijrahDate with(java.time.temporal.TemporalField, long);
     method public java.time.chrono.HijrahDate with(java.time.temporal.TemporalAdjuster);
     method public java.time.chrono.HijrahDate withVariant(java.time.chrono.HijrahChronology);
   }
 
-  public final class HijrahEra extends java.lang.Enum implements java.time.chrono.Era {
+  public enum HijrahEra implements java.time.chrono.Era {
     method public int getValue();
     method public static java.time.chrono.HijrahEra of(int);
-    method public static java.time.chrono.HijrahEra valueOf(java.lang.String);
-    method public static final java.time.chrono.HijrahEra[] values();
     enum_constant public static final java.time.chrono.HijrahEra AH;
   }
 
@@ -67739,24 +68094,22 @@
     method public java.time.LocalDate dateYearDay(int, int);
     method public java.time.chrono.IsoEra eraOf(int);
     method public java.util.List<java.time.chrono.Era> eras();
-    method public java.lang.String getCalendarType();
-    method public java.lang.String getId();
+    method public String getCalendarType();
+    method public String getId();
     method public boolean isLeapYear(long);
     method public java.time.LocalDateTime localDateTime(java.time.temporal.TemporalAccessor);
     method public java.time.Period period(int, int, int);
     method public int prolepticYear(java.time.chrono.Era, int);
     method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
-    method public java.time.LocalDate resolveDate(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.format.ResolverStyle);
+    method public java.time.LocalDate resolveDate(java.util.Map<java.time.temporal.TemporalField,java.lang.Long>, java.time.format.ResolverStyle);
     method public java.time.ZonedDateTime zonedDateTime(java.time.temporal.TemporalAccessor);
     method public java.time.ZonedDateTime zonedDateTime(java.time.Instant, java.time.ZoneId);
     field public static final java.time.chrono.IsoChronology INSTANCE;
   }
 
-  public final class IsoEra extends java.lang.Enum implements java.time.chrono.Era {
+  public enum IsoEra implements java.time.chrono.Era {
     method public int getValue();
     method public static java.time.chrono.IsoEra of(int);
-    method public static java.time.chrono.IsoEra valueOf(java.lang.String);
-    method public static final java.time.chrono.IsoEra[] values();
     enum_constant public static final java.time.chrono.IsoEra BCE;
     enum_constant public static final java.time.chrono.IsoEra CE;
   }
@@ -67773,13 +68126,13 @@
     method public java.time.chrono.JapaneseDate dateYearDay(int, int);
     method public java.time.chrono.JapaneseEra eraOf(int);
     method public java.util.List<java.time.chrono.Era> eras();
-    method public java.lang.String getCalendarType();
-    method public java.lang.String getId();
+    method public String getCalendarType();
+    method public String getId();
     method public boolean isLeapYear(long);
     method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.JapaneseDate> localDateTime(java.time.temporal.TemporalAccessor);
     method public int prolepticYear(java.time.chrono.Era, int);
     method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
-    method public java.time.chrono.JapaneseDate resolveDate(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.format.ResolverStyle);
+    method public java.time.chrono.JapaneseDate resolveDate(java.util.Map<java.time.temporal.TemporalField,java.lang.Long>, java.time.format.ResolverStyle);
     method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.JapaneseDate> zonedDateTime(java.time.temporal.TemporalAccessor);
     method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.JapaneseDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
     field public static final java.time.chrono.JapaneseChronology INSTANCE;
@@ -67802,6 +68155,7 @@
     method public java.time.chrono.JapaneseDate plus(java.time.temporal.TemporalAmount);
     method public java.time.chrono.JapaneseDate plus(long, java.time.temporal.TemporalUnit);
     method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
     method public java.time.chrono.JapaneseDate with(java.time.temporal.TemporalField, long);
     method public java.time.chrono.JapaneseDate with(java.time.temporal.TemporalAdjuster);
   }
@@ -67809,7 +68163,7 @@
   public final class JapaneseEra implements java.time.chrono.Era java.io.Serializable {
     method public int getValue();
     method public static java.time.chrono.JapaneseEra of(int);
-    method public static java.time.chrono.JapaneseEra valueOf(java.lang.String);
+    method public static java.time.chrono.JapaneseEra valueOf(String);
     method public static java.time.chrono.JapaneseEra[] values();
     field public static final java.time.chrono.JapaneseEra HEISEI;
     field public static final java.time.chrono.JapaneseEra MEIJI;
@@ -67829,13 +68183,13 @@
     method public java.time.chrono.MinguoDate dateYearDay(int, int);
     method public java.time.chrono.MinguoEra eraOf(int);
     method public java.util.List<java.time.chrono.Era> eras();
-    method public java.lang.String getCalendarType();
-    method public java.lang.String getId();
+    method public String getCalendarType();
+    method public String getId();
     method public boolean isLeapYear(long);
     method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.MinguoDate> localDateTime(java.time.temporal.TemporalAccessor);
     method public int prolepticYear(java.time.chrono.Era, int);
     method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
-    method public java.time.chrono.MinguoDate resolveDate(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.format.ResolverStyle);
+    method public java.time.chrono.MinguoDate resolveDate(java.util.Map<java.time.temporal.TemporalField,java.lang.Long>, java.time.format.ResolverStyle);
     method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.MinguoDate> zonedDateTime(java.time.temporal.TemporalAccessor);
     method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.MinguoDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
     field public static final java.time.chrono.MinguoChronology INSTANCE;
@@ -67857,15 +68211,14 @@
     method public java.time.chrono.MinguoDate plus(java.time.temporal.TemporalAmount);
     method public java.time.chrono.MinguoDate plus(long, java.time.temporal.TemporalUnit);
     method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
     method public java.time.chrono.MinguoDate with(java.time.temporal.TemporalField, long);
     method public java.time.chrono.MinguoDate with(java.time.temporal.TemporalAdjuster);
   }
 
-  public final class MinguoEra extends java.lang.Enum implements java.time.chrono.Era {
+  public enum MinguoEra implements java.time.chrono.Era {
     method public int getValue();
     method public static java.time.chrono.MinguoEra of(int);
-    method public static java.time.chrono.MinguoEra valueOf(java.lang.String);
-    method public static final java.time.chrono.MinguoEra[] values();
     enum_constant public static final java.time.chrono.MinguoEra BEFORE_ROC;
     enum_constant public static final java.time.chrono.MinguoEra ROC;
   }
@@ -67882,13 +68235,13 @@
     method public java.time.chrono.ThaiBuddhistDate dateYearDay(int, int);
     method public java.time.chrono.ThaiBuddhistEra eraOf(int);
     method public java.util.List<java.time.chrono.Era> eras();
-    method public java.lang.String getCalendarType();
-    method public java.lang.String getId();
+    method public String getCalendarType();
+    method public String getId();
     method public boolean isLeapYear(long);
     method public java.time.chrono.ChronoLocalDateTime<java.time.chrono.ThaiBuddhistDate> localDateTime(java.time.temporal.TemporalAccessor);
     method public int prolepticYear(java.time.chrono.Era, int);
     method public java.time.temporal.ValueRange range(java.time.temporal.ChronoField);
-    method public java.time.chrono.ThaiBuddhistDate resolveDate(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.format.ResolverStyle);
+    method public java.time.chrono.ThaiBuddhistDate resolveDate(java.util.Map<java.time.temporal.TemporalField,java.lang.Long>, java.time.format.ResolverStyle);
     method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.ThaiBuddhistDate> zonedDateTime(java.time.temporal.TemporalAccessor);
     method public java.time.chrono.ChronoZonedDateTime<java.time.chrono.ThaiBuddhistDate> zonedDateTime(java.time.Instant, java.time.ZoneId);
     field public static final java.time.chrono.ThaiBuddhistChronology INSTANCE;
@@ -67910,15 +68263,14 @@
     method public java.time.chrono.ThaiBuddhistDate plus(java.time.temporal.TemporalAmount);
     method public java.time.chrono.ThaiBuddhistDate plus(long, java.time.temporal.TemporalUnit);
     method public java.time.chrono.ChronoPeriod until(java.time.chrono.ChronoLocalDate);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
     method public java.time.chrono.ThaiBuddhistDate with(java.time.temporal.TemporalField, long);
     method public java.time.chrono.ThaiBuddhistDate with(java.time.temporal.TemporalAdjuster);
   }
 
-  public final class ThaiBuddhistEra extends java.lang.Enum implements java.time.chrono.Era {
+  public enum ThaiBuddhistEra implements java.time.chrono.Era {
     method public int getValue();
     method public static java.time.chrono.ThaiBuddhistEra of(int);
-    method public static java.time.chrono.ThaiBuddhistEra valueOf(java.lang.String);
-    method public static final java.time.chrono.ThaiBuddhistEra[] values();
     enum_constant public static final java.time.chrono.ThaiBuddhistEra BE;
     enum_constant public static final java.time.chrono.ThaiBuddhistEra BEFORE_BE;
   }
@@ -67928,8 +68280,8 @@
 package java.time.format {
 
   public final class DateTimeFormatter {
-    method public java.lang.String format(java.time.temporal.TemporalAccessor);
-    method public void formatTo(java.time.temporal.TemporalAccessor, java.lang.Appendable);
+    method public String format(java.time.temporal.TemporalAccessor);
+    method public void formatTo(java.time.temporal.TemporalAccessor, Appendable);
     method public java.time.chrono.Chronology getChronology();
     method public java.time.format.DecimalStyle getDecimalStyle();
     method public java.util.Locale getLocale();
@@ -67940,13 +68292,13 @@
     method public static java.time.format.DateTimeFormatter ofLocalizedDateTime(java.time.format.FormatStyle);
     method public static java.time.format.DateTimeFormatter ofLocalizedDateTime(java.time.format.FormatStyle, java.time.format.FormatStyle);
     method public static java.time.format.DateTimeFormatter ofLocalizedTime(java.time.format.FormatStyle);
-    method public static java.time.format.DateTimeFormatter ofPattern(java.lang.String);
-    method public static java.time.format.DateTimeFormatter ofPattern(java.lang.String, java.util.Locale);
-    method public java.time.temporal.TemporalAccessor parse(java.lang.CharSequence);
-    method public java.time.temporal.TemporalAccessor parse(java.lang.CharSequence, java.text.ParsePosition);
-    method public <T> T parse(java.lang.CharSequence, java.time.temporal.TemporalQuery<T>);
-    method public java.time.temporal.TemporalAccessor parseBest(java.lang.CharSequence, java.time.temporal.TemporalQuery<?>...);
-    method public java.time.temporal.TemporalAccessor parseUnresolved(java.lang.CharSequence, java.text.ParsePosition);
+    method public static java.time.format.DateTimeFormatter ofPattern(String);
+    method public static java.time.format.DateTimeFormatter ofPattern(String, java.util.Locale);
+    method public java.time.temporal.TemporalAccessor parse(CharSequence);
+    method public java.time.temporal.TemporalAccessor parse(CharSequence, java.text.ParsePosition);
+    method public <T> T parse(CharSequence, java.time.temporal.TemporalQuery<T>);
+    method public java.time.temporal.TemporalAccessor parseBest(CharSequence, java.time.temporal.TemporalQuery<?>...);
+    method public java.time.temporal.TemporalAccessor parseUnresolved(CharSequence, java.text.ParsePosition);
     method public static java.time.temporal.TemporalQuery<java.time.Period> parsedExcessDays();
     method public static java.time.temporal.TemporalQuery<java.lang.Boolean> parsedLeapSecond();
     method public java.text.Format toFormat();
@@ -67984,16 +68336,16 @@
     method public java.time.format.DateTimeFormatterBuilder appendInstant();
     method public java.time.format.DateTimeFormatterBuilder appendInstant(int);
     method public java.time.format.DateTimeFormatterBuilder appendLiteral(char);
-    method public java.time.format.DateTimeFormatterBuilder appendLiteral(java.lang.String);
+    method public java.time.format.DateTimeFormatterBuilder appendLiteral(String);
     method public java.time.format.DateTimeFormatterBuilder appendLocalized(java.time.format.FormatStyle, java.time.format.FormatStyle);
     method public java.time.format.DateTimeFormatterBuilder appendLocalizedOffset(java.time.format.TextStyle);
-    method public java.time.format.DateTimeFormatterBuilder appendOffset(java.lang.String, java.lang.String);
+    method public java.time.format.DateTimeFormatterBuilder appendOffset(String, String);
     method public java.time.format.DateTimeFormatterBuilder appendOffsetId();
     method public java.time.format.DateTimeFormatterBuilder appendOptional(java.time.format.DateTimeFormatter);
-    method public java.time.format.DateTimeFormatterBuilder appendPattern(java.lang.String);
+    method public java.time.format.DateTimeFormatterBuilder appendPattern(String);
     method public java.time.format.DateTimeFormatterBuilder appendText(java.time.temporal.TemporalField);
     method public java.time.format.DateTimeFormatterBuilder appendText(java.time.temporal.TemporalField, java.time.format.TextStyle);
-    method public java.time.format.DateTimeFormatterBuilder appendText(java.time.temporal.TemporalField, java.util.Map<java.lang.Long, java.lang.String>);
+    method public java.time.format.DateTimeFormatterBuilder appendText(java.time.temporal.TemporalField, java.util.Map<java.lang.Long,java.lang.String>);
     method public java.time.format.DateTimeFormatterBuilder appendValue(java.time.temporal.TemporalField);
     method public java.time.format.DateTimeFormatterBuilder appendValue(java.time.temporal.TemporalField, int);
     method public java.time.format.DateTimeFormatterBuilder appendValue(java.time.temporal.TemporalField, int, int, java.time.format.SignStyle);
@@ -68004,7 +68356,7 @@
     method public java.time.format.DateTimeFormatterBuilder appendZoneRegionId();
     method public java.time.format.DateTimeFormatterBuilder appendZoneText(java.time.format.TextStyle);
     method public java.time.format.DateTimeFormatterBuilder appendZoneText(java.time.format.TextStyle, java.util.Set<java.time.ZoneId>);
-    method public static java.lang.String getLocalizedDateTimePattern(java.time.format.FormatStyle, java.time.format.FormatStyle, java.time.chrono.Chronology, java.util.Locale);
+    method public static String getLocalizedDateTimePattern(java.time.format.FormatStyle, java.time.format.FormatStyle, java.time.chrono.Chronology, java.util.Locale);
     method public java.time.format.DateTimeFormatterBuilder optionalEnd();
     method public java.time.format.DateTimeFormatterBuilder optionalStart();
     method public java.time.format.DateTimeFormatterBuilder padNext(int);
@@ -68019,10 +68371,10 @@
   }
 
   public class DateTimeParseException extends java.time.DateTimeException {
-    ctor public DateTimeParseException(java.lang.String, java.lang.CharSequence, int);
-    ctor public DateTimeParseException(java.lang.String, java.lang.CharSequence, int, java.lang.Throwable);
+    ctor public DateTimeParseException(String, CharSequence, int);
+    ctor public DateTimeParseException(String, CharSequence, int, Throwable);
     method public int getErrorIndex();
-    method public java.lang.String getParsedString();
+    method public String getParsedString();
   }
 
   public final class DecimalStyle {
@@ -68040,26 +68392,20 @@
     field public static final java.time.format.DecimalStyle STANDARD;
   }
 
-  public final class FormatStyle extends java.lang.Enum {
-    method public static java.time.format.FormatStyle valueOf(java.lang.String);
-    method public static final java.time.format.FormatStyle[] values();
+  public enum FormatStyle {
     enum_constant public static final java.time.format.FormatStyle FULL;
     enum_constant public static final java.time.format.FormatStyle LONG;
     enum_constant public static final java.time.format.FormatStyle MEDIUM;
     enum_constant public static final java.time.format.FormatStyle SHORT;
   }
 
-  public final class ResolverStyle extends java.lang.Enum {
-    method public static java.time.format.ResolverStyle valueOf(java.lang.String);
-    method public static final java.time.format.ResolverStyle[] values();
+  public enum ResolverStyle {
     enum_constant public static final java.time.format.ResolverStyle LENIENT;
     enum_constant public static final java.time.format.ResolverStyle SMART;
     enum_constant public static final java.time.format.ResolverStyle STRICT;
   }
 
-  public final class SignStyle extends java.lang.Enum {
-    method public static java.time.format.SignStyle valueOf(java.lang.String);
-    method public static final java.time.format.SignStyle[] values();
+  public enum SignStyle {
     enum_constant public static final java.time.format.SignStyle ALWAYS;
     enum_constant public static final java.time.format.SignStyle EXCEEDS_PAD;
     enum_constant public static final java.time.format.SignStyle NEVER;
@@ -68067,12 +68413,10 @@
     enum_constant public static final java.time.format.SignStyle NOT_NEGATIVE;
   }
 
-  public final class TextStyle extends java.lang.Enum {
+  public enum TextStyle {
     method public java.time.format.TextStyle asNormal();
     method public java.time.format.TextStyle asStandalone();
     method public boolean isStandalone();
-    method public static java.time.format.TextStyle valueOf(java.lang.String);
-    method public static final java.time.format.TextStyle[] values();
     enum_constant public static final java.time.format.TextStyle FULL;
     enum_constant public static final java.time.format.TextStyle FULL_STANDALONE;
     enum_constant public static final java.time.format.TextStyle NARROW;
@@ -68085,7 +68429,7 @@
 
 package java.time.temporal {
 
-  public final class ChronoField extends java.lang.Enum implements java.time.temporal.TemporalField {
+  public enum ChronoField implements java.time.temporal.TemporalField {
     method public <R extends java.time.temporal.Temporal> R adjustInto(R, long);
     method public int checkValidIntValue(long);
     method public long checkValidValue(long);
@@ -68097,8 +68441,6 @@
     method public boolean isTimeBased();
     method public java.time.temporal.ValueRange range();
     method public java.time.temporal.ValueRange rangeRefinedBy(java.time.temporal.TemporalAccessor);
-    method public static java.time.temporal.ChronoField valueOf(java.lang.String);
-    method public static final java.time.temporal.ChronoField[] values();
     enum_constant public static final java.time.temporal.ChronoField ALIGNED_DAY_OF_WEEK_IN_MONTH;
     enum_constant public static final java.time.temporal.ChronoField ALIGNED_DAY_OF_WEEK_IN_YEAR;
     enum_constant public static final java.time.temporal.ChronoField ALIGNED_WEEK_OF_MONTH;
@@ -68131,15 +68473,13 @@
     enum_constant public static final java.time.temporal.ChronoField YEAR_OF_ERA;
   }
 
-  public final class ChronoUnit extends java.lang.Enum implements java.time.temporal.TemporalUnit {
+  public enum ChronoUnit implements java.time.temporal.TemporalUnit {
     method public <R extends java.time.temporal.Temporal> R addTo(R, long);
     method public long between(java.time.temporal.Temporal, java.time.temporal.Temporal);
     method public java.time.Duration getDuration();
     method public boolean isDateBased();
     method public boolean isDurationEstimated();
     method public boolean isTimeBased();
-    method public static java.time.temporal.ChronoUnit valueOf(java.lang.String);
-    method public static final java.time.temporal.ChronoUnit[] values();
     enum_constant public static final java.time.temporal.ChronoUnit CENTURIES;
     enum_constant public static final java.time.temporal.ChronoUnit DAYS;
     enum_constant public static final java.time.temporal.ChronoUnit DECADES;
@@ -68173,27 +68513,27 @@
     field public static final java.time.temporal.TemporalField RATA_DIE;
   }
 
-  public abstract interface Temporal implements java.time.temporal.TemporalAccessor {
-    method public abstract boolean isSupported(java.time.temporal.TemporalUnit);
+  public interface Temporal extends java.time.temporal.TemporalAccessor {
+    method public boolean isSupported(java.time.temporal.TemporalUnit);
     method public default java.time.temporal.Temporal minus(java.time.temporal.TemporalAmount);
     method public default java.time.temporal.Temporal minus(long, java.time.temporal.TemporalUnit);
     method public default java.time.temporal.Temporal plus(java.time.temporal.TemporalAmount);
-    method public abstract java.time.temporal.Temporal plus(long, java.time.temporal.TemporalUnit);
-    method public abstract long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
+    method public java.time.temporal.Temporal plus(long, java.time.temporal.TemporalUnit);
+    method public long until(java.time.temporal.Temporal, java.time.temporal.TemporalUnit);
     method public default java.time.temporal.Temporal with(java.time.temporal.TemporalAdjuster);
-    method public abstract java.time.temporal.Temporal with(java.time.temporal.TemporalField, long);
+    method public java.time.temporal.Temporal with(java.time.temporal.TemporalField, long);
   }
 
-  public abstract interface TemporalAccessor {
+  public interface TemporalAccessor {
     method public default int get(java.time.temporal.TemporalField);
-    method public abstract long getLong(java.time.temporal.TemporalField);
-    method public abstract boolean isSupported(java.time.temporal.TemporalField);
+    method public long getLong(java.time.temporal.TemporalField);
+    method public boolean isSupported(java.time.temporal.TemporalField);
     method public default <R> R query(java.time.temporal.TemporalQuery<R>);
     method public default java.time.temporal.ValueRange range(java.time.temporal.TemporalField);
   }
 
-  public abstract interface TemporalAdjuster {
-    method public abstract java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
+  @java.lang.FunctionalInterface public interface TemporalAdjuster {
+    method public java.time.temporal.Temporal adjustInto(java.time.temporal.Temporal);
   }
 
   public final class TemporalAdjusters {
@@ -68213,26 +68553,26 @@
     method public static java.time.temporal.TemporalAdjuster previousOrSame(java.time.DayOfWeek);
   }
 
-  public abstract interface TemporalAmount {
-    method public abstract java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
-    method public abstract long get(java.time.temporal.TemporalUnit);
-    method public abstract java.util.List<java.time.temporal.TemporalUnit> getUnits();
-    method public abstract java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
+  public interface TemporalAmount {
+    method public java.time.temporal.Temporal addTo(java.time.temporal.Temporal);
+    method public long get(java.time.temporal.TemporalUnit);
+    method public java.util.List<java.time.temporal.TemporalUnit> getUnits();
+    method public java.time.temporal.Temporal subtractFrom(java.time.temporal.Temporal);
   }
 
-  public abstract interface TemporalField {
-    method public abstract <R extends java.time.temporal.Temporal> R adjustInto(R, long);
-    method public abstract java.time.temporal.TemporalUnit getBaseUnit();
-    method public default java.lang.String getDisplayName(java.util.Locale);
-    method public abstract long getFrom(java.time.temporal.TemporalAccessor);
-    method public abstract java.time.temporal.TemporalUnit getRangeUnit();
-    method public abstract boolean isDateBased();
-    method public abstract boolean isSupportedBy(java.time.temporal.TemporalAccessor);
-    method public abstract boolean isTimeBased();
-    method public abstract java.time.temporal.ValueRange range();
-    method public abstract java.time.temporal.ValueRange rangeRefinedBy(java.time.temporal.TemporalAccessor);
-    method public default java.time.temporal.TemporalAccessor resolve(java.util.Map<java.time.temporal.TemporalField, java.lang.Long>, java.time.temporal.TemporalAccessor, java.time.format.ResolverStyle);
-    method public abstract java.lang.String toString();
+  public interface TemporalField {
+    method public <R extends java.time.temporal.Temporal> R adjustInto(R, long);
+    method public java.time.temporal.TemporalUnit getBaseUnit();
+    method public default String getDisplayName(java.util.Locale);
+    method public long getFrom(java.time.temporal.TemporalAccessor);
+    method public java.time.temporal.TemporalUnit getRangeUnit();
+    method public boolean isDateBased();
+    method public boolean isSupportedBy(java.time.temporal.TemporalAccessor);
+    method public boolean isTimeBased();
+    method public java.time.temporal.ValueRange range();
+    method public java.time.temporal.ValueRange rangeRefinedBy(java.time.temporal.TemporalAccessor);
+    method public default java.time.temporal.TemporalAccessor resolve(java.util.Map<java.time.temporal.TemporalField,java.lang.Long>, java.time.temporal.TemporalAccessor, java.time.format.ResolverStyle);
+    method public String toString();
   }
 
   public final class TemporalQueries {
@@ -68245,24 +68585,24 @@
     method public static java.time.temporal.TemporalQuery<java.time.ZoneId> zoneId();
   }
 
-  public abstract interface TemporalQuery<R> {
-    method public abstract R queryFrom(java.time.temporal.TemporalAccessor);
+  @java.lang.FunctionalInterface public interface TemporalQuery<R> {
+    method public R queryFrom(java.time.temporal.TemporalAccessor);
   }
 
-  public abstract interface TemporalUnit {
-    method public abstract <R extends java.time.temporal.Temporal> R addTo(R, long);
-    method public abstract long between(java.time.temporal.Temporal, java.time.temporal.Temporal);
-    method public abstract java.time.Duration getDuration();
-    method public abstract boolean isDateBased();
-    method public abstract boolean isDurationEstimated();
+  public interface TemporalUnit {
+    method public <R extends java.time.temporal.Temporal> R addTo(R, long);
+    method public long between(java.time.temporal.Temporal, java.time.temporal.Temporal);
+    method public java.time.Duration getDuration();
+    method public boolean isDateBased();
+    method public boolean isDurationEstimated();
     method public default boolean isSupportedBy(java.time.temporal.Temporal);
-    method public abstract boolean isTimeBased();
-    method public abstract java.lang.String toString();
+    method public boolean isTimeBased();
+    method public String toString();
   }
 
   public class UnsupportedTemporalTypeException extends java.time.DateTimeException {
-    ctor public UnsupportedTemporalTypeException(java.lang.String);
-    ctor public UnsupportedTemporalTypeException(java.lang.String, java.lang.Throwable);
+    ctor public UnsupportedTemporalTypeException(String);
+    ctor public UnsupportedTemporalTypeException(String, Throwable);
   }
 
   public final class ValueRange implements java.io.Serializable {
@@ -68300,7 +68640,7 @@
 
 package java.time.zone {
 
-  public final class ZoneOffsetTransition implements java.lang.Comparable java.io.Serializable {
+  public final class ZoneOffsetTransition implements java.lang.Comparable<java.time.zone.ZoneOffsetTransition> java.io.Serializable {
     method public int compareTo(java.time.zone.ZoneOffsetTransition);
     method public java.time.LocalDateTime getDateTimeAfter();
     method public java.time.LocalDateTime getDateTimeBefore();
@@ -68329,10 +68669,8 @@
     method public static java.time.zone.ZoneOffsetTransitionRule of(java.time.Month, int, java.time.DayOfWeek, java.time.LocalTime, boolean, java.time.zone.ZoneOffsetTransitionRule.TimeDefinition, java.time.ZoneOffset, java.time.ZoneOffset, java.time.ZoneOffset);
   }
 
-  public static final class ZoneOffsetTransitionRule.TimeDefinition extends java.lang.Enum {
+  public enum ZoneOffsetTransitionRule.TimeDefinition {
     method public java.time.LocalDateTime createDateTime(java.time.LocalDateTime, java.time.ZoneOffset, java.time.ZoneOffset);
-    method public static java.time.zone.ZoneOffsetTransitionRule.TimeDefinition valueOf(java.lang.String);
-    method public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition[] values();
     enum_constant public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition STANDARD;
     enum_constant public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition UTC;
     enum_constant public static final java.time.zone.ZoneOffsetTransitionRule.TimeDefinition WALL;
@@ -68357,136 +68695,136 @@
   }
 
   public class ZoneRulesException extends java.time.DateTimeException {
-    ctor public ZoneRulesException(java.lang.String);
-    ctor public ZoneRulesException(java.lang.String, java.lang.Throwable);
+    ctor public ZoneRulesException(String);
+    ctor public ZoneRulesException(String, Throwable);
   }
 
 }
 
 package java.util {
 
-  public abstract class AbstractCollection<E> implements java.util.Collection {
+  public abstract class AbstractCollection<E> implements java.util.Collection<E> {
     ctor protected AbstractCollection();
     method public boolean add(E);
-    method public boolean addAll(java.util.Collection<? extends E>);
+    method public boolean addAll(@NonNull java.util.Collection<? extends E>);
     method public void clear();
-    method public boolean contains(java.lang.Object);
-    method public boolean containsAll(java.util.Collection<?>);
+    method public boolean contains(@Nullable Object);
+    method public boolean containsAll(@NonNull java.util.Collection<?>);
     method public boolean isEmpty();
-    method public boolean remove(java.lang.Object);
-    method public boolean removeAll(java.util.Collection<?>);
-    method public boolean retainAll(java.util.Collection<?>);
-    method public java.lang.Object[] toArray();
+    method public boolean remove(@Nullable Object);
+    method public boolean removeAll(@NonNull java.util.Collection<?>);
+    method public boolean retainAll(@NonNull java.util.Collection<?>);
+    method public Object[] toArray();
     method public <T> T[] toArray(T[]);
   }
 
-  public abstract class AbstractList<E> extends java.util.AbstractCollection implements java.util.List {
+  public abstract class AbstractList<E> extends java.util.AbstractCollection<E> implements java.util.List<E> {
     ctor protected AbstractList();
     method public void add(int, E);
-    method public boolean addAll(int, java.util.Collection<? extends E>);
-    method public int indexOf(java.lang.Object);
-    method public java.util.Iterator<E> iterator();
-    method public int lastIndexOf(java.lang.Object);
-    method public java.util.ListIterator<E> listIterator();
-    method public java.util.ListIterator<E> listIterator(int);
+    method public boolean addAll(int, @NonNull java.util.Collection<? extends E>);
+    method public int indexOf(@Nullable Object);
+    method @NonNull public java.util.Iterator<E> iterator();
+    method public int lastIndexOf(@Nullable Object);
+    method @NonNull public java.util.ListIterator<E> listIterator();
+    method @NonNull public java.util.ListIterator<E> listIterator(int);
     method public E remove(int);
     method protected void removeRange(int, int);
     method public E set(int, E);
-    method public java.util.List<E> subList(int, int);
+    method @NonNull public java.util.List<E> subList(int, int);
     field protected transient int modCount;
   }
 
-  public abstract class AbstractMap<K, V> implements java.util.Map {
+  public abstract class AbstractMap<K, V> implements java.util.Map<K,V> {
     ctor protected AbstractMap();
     method public void clear();
-    method public boolean containsKey(java.lang.Object);
-    method public boolean containsValue(java.lang.Object);
-    method public V get(java.lang.Object);
+    method public boolean containsKey(@Nullable Object);
+    method public boolean containsValue(@Nullable Object);
+    method @Nullable public V get(@Nullable Object);
     method public boolean isEmpty();
-    method public java.util.Set<K> keySet();
-    method public V put(K, V);
-    method public void putAll(java.util.Map<? extends K, ? extends V>);
-    method public V remove(java.lang.Object);
+    method @NonNull public java.util.Set<K> keySet();
+    method @Nullable public V put(K, V);
+    method public void putAll(@NonNull java.util.Map<? extends K,? extends V>);
+    method @Nullable public V remove(@Nullable Object);
     method public int size();
-    method public java.util.Collection<V> values();
+    method @NonNull public java.util.Collection<V> values();
   }
 
-  public static class AbstractMap.SimpleEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
+  public static class AbstractMap.SimpleEntry<K, V> implements java.util.Map.Entry<K,V> java.io.Serializable {
     ctor public AbstractMap.SimpleEntry(K, V);
-    ctor public AbstractMap.SimpleEntry(java.util.Map.Entry<? extends K, ? extends V>);
+    ctor public AbstractMap.SimpleEntry(@NonNull java.util.Map.Entry<? extends K,? extends V>);
     method public K getKey();
     method public V getValue();
     method public V setValue(V);
   }
 
-  public static class AbstractMap.SimpleImmutableEntry<K, V> implements java.util.Map.Entry java.io.Serializable {
+  public static class AbstractMap.SimpleImmutableEntry<K, V> implements java.util.Map.Entry<K,V> java.io.Serializable {
     ctor public AbstractMap.SimpleImmutableEntry(K, V);
-    ctor public AbstractMap.SimpleImmutableEntry(java.util.Map.Entry<? extends K, ? extends V>);
+    ctor public AbstractMap.SimpleImmutableEntry(@NonNull java.util.Map.Entry<? extends K,? extends V>);
     method public K getKey();
     method public V getValue();
     method public V setValue(V);
   }
 
-  public abstract class AbstractQueue<E> extends java.util.AbstractCollection implements java.util.Queue {
+  public abstract class AbstractQueue<E> extends java.util.AbstractCollection<E> implements java.util.Queue<E> {
     ctor protected AbstractQueue();
     method public E element();
     method public E remove();
   }
 
-  public abstract class AbstractSequentialList<E> extends java.util.AbstractList {
+  public abstract class AbstractSequentialList<E> extends java.util.AbstractList<E> {
     ctor protected AbstractSequentialList();
     method public E get(int);
   }
 
-  public abstract class AbstractSet<E> extends java.util.AbstractCollection implements java.util.Set {
+  public abstract class AbstractSet<E> extends java.util.AbstractCollection<E> implements java.util.Set<E> {
     ctor protected AbstractSet();
   }
 
-  public class ArrayDeque<E> extends java.util.AbstractCollection implements java.lang.Cloneable java.util.Deque java.io.Serializable {
+  public class ArrayDeque<E> extends java.util.AbstractCollection<E> implements java.lang.Cloneable java.util.Deque<E> java.io.Serializable {
     ctor public ArrayDeque();
     ctor public ArrayDeque(int);
-    ctor public ArrayDeque(java.util.Collection<? extends E>);
+    ctor public ArrayDeque(@NonNull java.util.Collection<? extends E>);
     method public void addFirst(E);
     method public void addLast(E);
-    method public java.util.ArrayDeque<E> clone();
-    method public java.util.Iterator<E> descendingIterator();
+    method @NonNull public java.util.ArrayDeque<E> clone();
+    method @NonNull public java.util.Iterator<E> descendingIterator();
     method public E element();
     method public E getFirst();
     method public E getLast();
-    method public java.util.Iterator<E> iterator();
+    method @NonNull public java.util.Iterator<E> iterator();
     method public boolean offer(E);
     method public boolean offerFirst(E);
     method public boolean offerLast(E);
-    method public E peek();
-    method public E peekFirst();
-    method public E peekLast();
-    method public E poll();
-    method public E pollFirst();
-    method public E pollLast();
+    method @Nullable public E peek();
+    method @Nullable public E peekFirst();
+    method @Nullable public E peekLast();
+    method @Nullable public E poll();
+    method @Nullable public E pollFirst();
+    method @Nullable public E pollLast();
     method public E pop();
     method public void push(E);
     method public E remove();
     method public E removeFirst();
-    method public boolean removeFirstOccurrence(java.lang.Object);
+    method public boolean removeFirstOccurrence(@Nullable Object);
     method public E removeLast();
-    method public boolean removeLastOccurrence(java.lang.Object);
+    method public boolean removeLastOccurrence(@Nullable Object);
     method public int size();
   }
 
-  public class ArrayList<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
+  public class ArrayList<E> extends java.util.AbstractList<E> implements java.lang.Cloneable java.util.List<E> java.util.RandomAccess java.io.Serializable {
     ctor public ArrayList(int);
     ctor public ArrayList();
-    ctor public ArrayList(java.util.Collection<? extends E>);
-    method public java.lang.Object clone();
+    ctor public ArrayList(@NonNull java.util.Collection<? extends E>);
+    method @NonNull public Object clone();
     method public void ensureCapacity(int);
-    method public void forEach(java.util.function.Consumer<? super E>);
+    method public void forEach(@NonNull java.util.function.Consumer<? super E>);
     method public E get(int);
     method public int size();
     method public void trimToSize();
   }
 
   public class Arrays {
-    method public static <T> java.util.List<T> asList(T...);
+    method @NonNull @java.lang.SafeVarargs public static <T> java.util.List<T> asList(T...);
     method public static int binarySearch(long[], long);
     method public static int binarySearch(long[], int, int, long);
     method public static int binarySearch(int[], int);
@@ -68501,12 +68839,12 @@
     method public static int binarySearch(double[], int, int, double);
     method public static int binarySearch(float[], float);
     method public static int binarySearch(float[], int, int, float);
-    method public static int binarySearch(java.lang.Object[], java.lang.Object);
-    method public static int binarySearch(java.lang.Object[], int, int, java.lang.Object);
-    method public static <T> int binarySearch(T[], T, java.util.Comparator<? super T>);
-    method public static <T> int binarySearch(T[], int, int, T, java.util.Comparator<? super T>);
+    method public static int binarySearch(Object[], @NonNull Object);
+    method public static int binarySearch(Object[], int, int, @NonNull Object);
+    method public static <T> int binarySearch(T[], T, @Nullable java.util.Comparator<? super T>);
+    method public static <T> int binarySearch(T[], int, int, T, @Nullable java.util.Comparator<? super T>);
     method public static <T> T[] copyOf(T[], int);
-    method public static <T, U> T[] copyOf(U[], int, java.lang.Class<? extends T[]>);
+    method public static <T, U> T[] copyOf(U[], int, @NonNull Class<? extends T[]>);
     method public static byte[] copyOf(byte[], int);
     method public static short[] copyOf(short[], int);
     method public static int[] copyOf(int[], int);
@@ -68516,7 +68854,7 @@
     method public static double[] copyOf(double[], int);
     method public static boolean[] copyOf(boolean[], int);
     method public static <T> T[] copyOfRange(T[], int, int);
-    method public static <T, U> T[] copyOfRange(U[], int, int, java.lang.Class<? extends T[]>);
+    method public static <T, U> T[] copyOfRange(U[], int, int, @NonNull Class<? extends T[]>);
     method public static byte[] copyOfRange(byte[], int, int);
     method public static short[] copyOfRange(short[], int, int);
     method public static int[] copyOfRange(int[], int, int);
@@ -68525,9 +68863,9 @@
     method public static float[] copyOfRange(float[], int, int);
     method public static double[] copyOfRange(double[], int, int);
     method public static boolean[] copyOfRange(boolean[], int, int);
-    method public static boolean deepEquals(java.lang.Object[], java.lang.Object[]);
-    method public static int deepHashCode(java.lang.Object[]);
-    method public static java.lang.String deepToString(java.lang.Object[]);
+    method public static boolean deepEquals(Object[], Object[]);
+    method public static int deepHashCode(Object[]);
+    method @NonNull public static String deepToString(Object[]);
     method public static boolean equals(long[], long[]);
     method public static boolean equals(int[], int[]);
     method public static boolean equals(short[], short[]);
@@ -68536,7 +68874,7 @@
     method public static boolean equals(boolean[], boolean[]);
     method public static boolean equals(double[], double[]);
     method public static boolean equals(float[], float[]);
-    method public static boolean equals(java.lang.Object[], java.lang.Object[]);
+    method public static boolean equals(Object[], Object[]);
     method public static void fill(long[], long);
     method public static void fill(long[], int, int, long);
     method public static void fill(int[], int);
@@ -68553,8 +68891,8 @@
     method public static void fill(double[], int, int, double);
     method public static void fill(float[], float);
     method public static void fill(float[], int, int, float);
-    method public static void fill(java.lang.Object[], java.lang.Object);
-    method public static void fill(java.lang.Object[], int, int, java.lang.Object);
+    method public static void fill(Object[], @Nullable Object);
+    method public static void fill(Object[], int, int, @Nullable Object);
     method public static int hashCode(long[]);
     method public static int hashCode(int[]);
     method public static int hashCode(short[]);
@@ -68563,19 +68901,19 @@
     method public static int hashCode(boolean[]);
     method public static int hashCode(float[]);
     method public static int hashCode(double[]);
-    method public static int hashCode(java.lang.Object[]);
-    method public static <T> void parallelPrefix(T[], java.util.function.BinaryOperator<T>);
-    method public static <T> void parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>);
-    method public static void parallelPrefix(long[], java.util.function.LongBinaryOperator);
-    method public static void parallelPrefix(long[], int, int, java.util.function.LongBinaryOperator);
-    method public static void parallelPrefix(double[], java.util.function.DoubleBinaryOperator);
-    method public static void parallelPrefix(double[], int, int, java.util.function.DoubleBinaryOperator);
-    method public static void parallelPrefix(int[], java.util.function.IntBinaryOperator);
-    method public static void parallelPrefix(int[], int, int, java.util.function.IntBinaryOperator);
-    method public static <T> void parallelSetAll(T[], java.util.function.IntFunction<? extends T>);
-    method public static void parallelSetAll(int[], java.util.function.IntUnaryOperator);
-    method public static void parallelSetAll(long[], java.util.function.IntToLongFunction);
-    method public static void parallelSetAll(double[], java.util.function.IntToDoubleFunction);
+    method public static int hashCode(Object[]);
+    method public static <T> void parallelPrefix(T[], @NonNull java.util.function.BinaryOperator<T>);
+    method public static <T> void parallelPrefix(T[], int, int, @NonNull java.util.function.BinaryOperator<T>);
+    method public static void parallelPrefix(long[], @NonNull java.util.function.LongBinaryOperator);
+    method public static void parallelPrefix(long[], int, int, @NonNull java.util.function.LongBinaryOperator);
+    method public static void parallelPrefix(double[], @NonNull java.util.function.DoubleBinaryOperator);
+    method public static void parallelPrefix(double[], int, int, @NonNull java.util.function.DoubleBinaryOperator);
+    method public static void parallelPrefix(int[], @NonNull java.util.function.IntBinaryOperator);
+    method public static void parallelPrefix(int[], int, int, @NonNull java.util.function.IntBinaryOperator);
+    method public static <T> void parallelSetAll(T[], @NonNull java.util.function.IntFunction<? extends T>);
+    method public static void parallelSetAll(int[], @NonNull java.util.function.IntUnaryOperator);
+    method public static void parallelSetAll(long[], @NonNull java.util.function.IntToLongFunction);
+    method public static void parallelSetAll(double[], @NonNull java.util.function.IntToDoubleFunction);
     method public static void parallelSort(byte[]);
     method public static void parallelSort(byte[], int, int);
     method public static void parallelSort(char[]);
@@ -68592,12 +68930,12 @@
     method public static void parallelSort(double[], int, int);
     method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[]);
     method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[], int, int);
-    method public static <T> void parallelSort(T[], java.util.Comparator<? super T>);
-    method public static <T> void parallelSort(T[], int, int, java.util.Comparator<? super T>);
-    method public static <T> void setAll(T[], java.util.function.IntFunction<? extends T>);
-    method public static void setAll(int[], java.util.function.IntUnaryOperator);
-    method public static void setAll(long[], java.util.function.IntToLongFunction);
-    method public static void setAll(double[], java.util.function.IntToDoubleFunction);
+    method public static <T> void parallelSort(T[], @Nullable java.util.Comparator<? super T>);
+    method public static <T> void parallelSort(T[], int, int, @Nullable java.util.Comparator<? super T>);
+    method public static <T> void setAll(T[], @NonNull java.util.function.IntFunction<? extends T>);
+    method public static void setAll(int[], @NonNull java.util.function.IntUnaryOperator);
+    method public static void setAll(long[], @NonNull java.util.function.IntToLongFunction);
+    method public static void setAll(double[], @NonNull java.util.function.IntToDoubleFunction);
     method public static void sort(int[]);
     method public static void sort(int[], int, int);
     method public static void sort(long[]);
@@ -68612,35 +68950,35 @@
     method public static void sort(float[], int, int);
     method public static void sort(double[]);
     method public static void sort(double[], int, int);
-    method public static void sort(java.lang.Object[]);
-    method public static void sort(java.lang.Object[], int, int);
-    method public static <T> void sort(T[], java.util.Comparator<? super T>);
-    method public static <T> void sort(T[], int, int, java.util.Comparator<? super T>);
-    method public static <T> java.util.Spliterator<T> spliterator(T[]);
-    method public static <T> java.util.Spliterator<T> spliterator(T[], int, int);
-    method public static java.util.Spliterator.OfInt spliterator(int[]);
-    method public static java.util.Spliterator.OfInt spliterator(int[], int, int);
-    method public static java.util.Spliterator.OfLong spliterator(long[]);
-    method public static java.util.Spliterator.OfLong spliterator(long[], int, int);
-    method public static java.util.Spliterator.OfDouble spliterator(double[]);
-    method public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
-    method public static <T> java.util.stream.Stream<T> stream(T[]);
-    method public static <T> java.util.stream.Stream<T> stream(T[], int, int);
-    method public static java.util.stream.IntStream stream(int[]);
-    method public static java.util.stream.IntStream stream(int[], int, int);
-    method public static java.util.stream.LongStream stream(long[]);
-    method public static java.util.stream.LongStream stream(long[], int, int);
-    method public static java.util.stream.DoubleStream stream(double[]);
-    method public static java.util.stream.DoubleStream stream(double[], int, int);
-    method public static java.lang.String toString(long[]);
-    method public static java.lang.String toString(int[]);
-    method public static java.lang.String toString(short[]);
-    method public static java.lang.String toString(char[]);
-    method public static java.lang.String toString(byte[]);
-    method public static java.lang.String toString(boolean[]);
-    method public static java.lang.String toString(float[]);
-    method public static java.lang.String toString(double[]);
-    method public static java.lang.String toString(java.lang.Object[]);
+    method public static void sort(Object[]);
+    method public static void sort(Object[], int, int);
+    method public static <T> void sort(T[], @Nullable java.util.Comparator<? super T>);
+    method public static <T> void sort(T[], int, int, @Nullable java.util.Comparator<? super T>);
+    method @NonNull public static <T> java.util.Spliterator<T> spliterator(T[]);
+    method @NonNull public static <T> java.util.Spliterator<T> spliterator(T[], int, int);
+    method @NonNull public static java.util.Spliterator.OfInt spliterator(int[]);
+    method @NonNull public static java.util.Spliterator.OfInt spliterator(int[], int, int);
+    method @NonNull public static java.util.Spliterator.OfLong spliterator(long[]);
+    method @NonNull public static java.util.Spliterator.OfLong spliterator(long[], int, int);
+    method @NonNull public static java.util.Spliterator.OfDouble spliterator(double[]);
+    method @NonNull public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
+    method @NonNull public static <T> java.util.stream.Stream<T> stream(T[]);
+    method @NonNull public static <T> java.util.stream.Stream<T> stream(T[], int, int);
+    method @NonNull public static java.util.stream.IntStream stream(int[]);
+    method @NonNull public static java.util.stream.IntStream stream(int[], int, int);
+    method @NonNull public static java.util.stream.LongStream stream(long[]);
+    method @NonNull public static java.util.stream.LongStream stream(long[], int, int);
+    method @NonNull public static java.util.stream.DoubleStream stream(double[]);
+    method @NonNull public static java.util.stream.DoubleStream stream(double[], int, int);
+    method @NonNull public static String toString(long[]);
+    method @NonNull public static String toString(int[]);
+    method @NonNull public static String toString(short[]);
+    method @NonNull public static String toString(char[]);
+    method @NonNull public static String toString(byte[]);
+    method @NonNull public static String toString(boolean[]);
+    method @NonNull public static String toString(float[]);
+    method @NonNull public static String toString(double[]);
+    method @NonNull public static String toString(Object[]);
   }
 
   public class Base64 {
@@ -68655,7 +68993,7 @@
 
   public static class Base64.Decoder {
     method public byte[] decode(byte[]);
-    method public byte[] decode(java.lang.String);
+    method public byte[] decode(String);
     method public int decode(byte[], byte[]);
     method public java.nio.ByteBuffer decode(java.nio.ByteBuffer);
     method public java.io.InputStream wrap(java.io.InputStream);
@@ -68665,7 +69003,7 @@
     method public byte[] encode(byte[]);
     method public int encode(byte[], byte[]);
     method public java.nio.ByteBuffer encode(java.nio.ByteBuffer);
-    method public java.lang.String encodeToString(byte[]);
+    method public String encodeToString(byte[]);
     method public java.util.Base64.Encoder withoutPadding();
     method public java.io.OutputStream wrap(java.io.OutputStream);
   }
@@ -68679,7 +69017,7 @@
     method public void clear(int);
     method public void clear(int, int);
     method public void clear();
-    method public java.lang.Object clone();
+    method public Object clone();
     method public void flip(int);
     method public void flip(int, int);
     method public boolean get(int);
@@ -68707,40 +69045,40 @@
     method public void xor(java.util.BitSet);
   }
 
-  public abstract class Calendar implements java.lang.Cloneable java.lang.Comparable java.io.Serializable {
+  public abstract class Calendar implements java.lang.Cloneable java.lang.Comparable<java.util.Calendar> java.io.Serializable {
     ctor protected Calendar();
-    ctor protected Calendar(java.util.TimeZone, java.util.Locale);
+    ctor protected Calendar(@NonNull java.util.TimeZone, @NonNull java.util.Locale);
     method public abstract void add(int, int);
-    method public boolean after(java.lang.Object);
-    method public boolean before(java.lang.Object);
+    method public boolean after(@Nullable Object);
+    method public boolean before(@Nullable Object);
     method public final void clear();
     method public final void clear(int);
-    method public java.lang.Object clone();
-    method public int compareTo(java.util.Calendar);
+    method @NonNull public Object clone();
+    method public int compareTo(@NonNull java.util.Calendar);
     method protected void complete();
     method protected abstract void computeFields();
     method protected abstract void computeTime();
     method public int get(int);
     method public int getActualMaximum(int);
     method public int getActualMinimum(int);
-    method public static java.util.Set<java.lang.String> getAvailableCalendarTypes();
-    method public static synchronized java.util.Locale[] getAvailableLocales();
-    method public java.lang.String getCalendarType();
-    method public java.lang.String getDisplayName(int, int, java.util.Locale);
-    method public java.util.Map<java.lang.String, java.lang.Integer> getDisplayNames(int, int, java.util.Locale);
+    method @NonNull public static java.util.Set<java.lang.String> getAvailableCalendarTypes();
+    method public static java.util.Locale[] getAvailableLocales();
+    method @NonNull public String getCalendarType();
+    method @Nullable public String getDisplayName(int, int, @NonNull java.util.Locale);
+    method @Nullable public java.util.Map<java.lang.String,java.lang.Integer> getDisplayNames(int, int, @NonNull java.util.Locale);
     method public int getFirstDayOfWeek();
     method public abstract int getGreatestMinimum(int);
-    method public static java.util.Calendar getInstance();
-    method public static java.util.Calendar getInstance(java.util.TimeZone);
-    method public static java.util.Calendar getInstance(java.util.Locale);
-    method public static java.util.Calendar getInstance(java.util.TimeZone, java.util.Locale);
+    method @NonNull public static java.util.Calendar getInstance();
+    method @NonNull public static java.util.Calendar getInstance(@NonNull java.util.TimeZone);
+    method @NonNull public static java.util.Calendar getInstance(@NonNull java.util.Locale);
+    method @NonNull public static java.util.Calendar getInstance(@NonNull java.util.TimeZone, @NonNull java.util.Locale);
     method public abstract int getLeastMaximum(int);
     method public abstract int getMaximum(int);
     method public int getMinimalDaysInFirstWeek();
     method public abstract int getMinimum(int);
-    method public final java.util.Date getTime();
+    method @NonNull public final java.util.Date getTime();
     method public long getTimeInMillis();
-    method public java.util.TimeZone getTimeZone();
+    method @NonNull public java.util.TimeZone getTimeZone();
     method public int getWeekYear();
     method public int getWeeksInWeekYear();
     method protected final int internalGet(int);
@@ -68756,11 +69094,11 @@
     method public void setFirstDayOfWeek(int);
     method public void setLenient(boolean);
     method public void setMinimalDaysInFirstWeek(int);
-    method public final void setTime(java.util.Date);
+    method public final void setTime(@NonNull java.util.Date);
     method public void setTimeInMillis(long);
-    method public void setTimeZone(java.util.TimeZone);
+    method public void setTimeZone(@NonNull java.util.TimeZone);
     method public void setWeekDate(int, int, int);
-    method public final java.time.Instant toInstant();
+    method @NonNull public final java.time.Instant toInstant();
     field public static final int ALL_STYLES = 0; // 0x0
     field public static final int AM = 0; // 0x0
     field public static final int AM_PM = 9; // 0x9
@@ -68820,132 +69158,132 @@
 
   public static class Calendar.Builder {
     ctor public Calendar.Builder();
-    method public java.util.Calendar build();
-    method public java.util.Calendar.Builder set(int, int);
-    method public java.util.Calendar.Builder setCalendarType(java.lang.String);
-    method public java.util.Calendar.Builder setDate(int, int, int);
-    method public java.util.Calendar.Builder setFields(int...);
-    method public java.util.Calendar.Builder setInstant(long);
-    method public java.util.Calendar.Builder setInstant(java.util.Date);
-    method public java.util.Calendar.Builder setLenient(boolean);
-    method public java.util.Calendar.Builder setLocale(java.util.Locale);
-    method public java.util.Calendar.Builder setTimeOfDay(int, int, int);
-    method public java.util.Calendar.Builder setTimeOfDay(int, int, int, int);
-    method public java.util.Calendar.Builder setTimeZone(java.util.TimeZone);
-    method public java.util.Calendar.Builder setWeekDate(int, int, int);
-    method public java.util.Calendar.Builder setWeekDefinition(int, int);
+    method @NonNull public java.util.Calendar build();
+    method @NonNull public java.util.Calendar.Builder set(int, int);
+    method @NonNull public java.util.Calendar.Builder setCalendarType(@NonNull String);
+    method @NonNull public java.util.Calendar.Builder setDate(int, int, int);
+    method @NonNull public java.util.Calendar.Builder setFields(int...);
+    method @NonNull public java.util.Calendar.Builder setInstant(long);
+    method @NonNull public java.util.Calendar.Builder setInstant(@NonNull java.util.Date);
+    method @NonNull public java.util.Calendar.Builder setLenient(boolean);
+    method @NonNull public java.util.Calendar.Builder setLocale(@NonNull java.util.Locale);
+    method @NonNull public java.util.Calendar.Builder setTimeOfDay(int, int, int);
+    method @NonNull public java.util.Calendar.Builder setTimeOfDay(int, int, int, int);
+    method @NonNull public java.util.Calendar.Builder setTimeZone(@NonNull java.util.TimeZone);
+    method @NonNull public java.util.Calendar.Builder setWeekDate(int, int, int);
+    method @NonNull public java.util.Calendar.Builder setWeekDefinition(int, int);
   }
 
-  public abstract interface Collection<E> implements java.lang.Iterable {
-    method public abstract boolean add(E);
-    method public abstract boolean addAll(java.util.Collection<? extends E>);
-    method public abstract void clear();
-    method public abstract boolean contains(java.lang.Object);
-    method public abstract boolean containsAll(java.util.Collection<?>);
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract int hashCode();
-    method public abstract boolean isEmpty();
-    method public abstract java.util.Iterator<E> iterator();
-    method public default java.util.stream.Stream<E> parallelStream();
-    method public abstract boolean remove(java.lang.Object);
-    method public abstract boolean removeAll(java.util.Collection<?>);
-    method public default boolean removeIf(java.util.function.Predicate<? super E>);
-    method public abstract boolean retainAll(java.util.Collection<?>);
-    method public abstract int size();
-    method public default java.util.Spliterator<E> spliterator();
-    method public default java.util.stream.Stream<E> stream();
-    method public abstract java.lang.Object[] toArray();
-    method public abstract <T> T[] toArray(T[]);
+  public interface Collection<E> extends java.lang.Iterable<E> {
+    method public boolean add(E);
+    method public boolean addAll(@NonNull java.util.Collection<? extends E>);
+    method public void clear();
+    method public boolean contains(@Nullable Object);
+    method public boolean containsAll(@NonNull java.util.Collection<?>);
+    method public boolean equals(@Nullable Object);
+    method public int hashCode();
+    method public boolean isEmpty();
+    method @NonNull public java.util.Iterator<E> iterator();
+    method @NonNull public default java.util.stream.Stream<E> parallelStream();
+    method public boolean remove(@Nullable Object);
+    method public boolean removeAll(@NonNull java.util.Collection<?>);
+    method public default boolean removeIf(@NonNull java.util.function.Predicate<? super E>);
+    method public boolean retainAll(@NonNull java.util.Collection<?>);
+    method public int size();
+    method @NonNull public default java.util.Spliterator<E> spliterator();
+    method @NonNull public default java.util.stream.Stream<E> stream();
+    method public Object[] toArray();
+    method public <T> T[] toArray(T[]);
   }
 
   public class Collections {
-    method public static <T> boolean addAll(java.util.Collection<? super T>, T...);
-    method public static <T> java.util.Queue<T> asLifoQueue(java.util.Deque<T>);
-    method public static <T> int binarySearch(java.util.List<? extends java.lang.Comparable<? super T>>, T);
-    method public static <T> int binarySearch(java.util.List<? extends T>, T, java.util.Comparator<? super T>);
-    method public static <E> java.util.Collection<E> checkedCollection(java.util.Collection<E>, java.lang.Class<E>);
-    method public static <E> java.util.List<E> checkedList(java.util.List<E>, java.lang.Class<E>);
-    method public static <K, V> java.util.Map<K, V> checkedMap(java.util.Map<K, V>, java.lang.Class<K>, java.lang.Class<V>);
-    method public static <K, V> java.util.NavigableMap<K, V> checkedNavigableMap(java.util.NavigableMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
-    method public static <E> java.util.NavigableSet<E> checkedNavigableSet(java.util.NavigableSet<E>, java.lang.Class<E>);
-    method public static <E> java.util.Queue<E> checkedQueue(java.util.Queue<E>, java.lang.Class<E>);
-    method public static <E> java.util.Set<E> checkedSet(java.util.Set<E>, java.lang.Class<E>);
-    method public static <K, V> java.util.SortedMap<K, V> checkedSortedMap(java.util.SortedMap<K, V>, java.lang.Class<K>, java.lang.Class<V>);
-    method public static <E> java.util.SortedSet<E> checkedSortedSet(java.util.SortedSet<E>, java.lang.Class<E>);
-    method public static <T> void copy(java.util.List<? super T>, java.util.List<? extends T>);
-    method public static boolean disjoint(java.util.Collection<?>, java.util.Collection<?>);
-    method public static <T> java.util.Enumeration<T> emptyEnumeration();
-    method public static <T> java.util.Iterator<T> emptyIterator();
-    method public static final <T> java.util.List<T> emptyList();
-    method public static <T> java.util.ListIterator<T> emptyListIterator();
-    method public static final <K, V> java.util.Map<K, V> emptyMap();
-    method public static final <K, V> java.util.NavigableMap<K, V> emptyNavigableMap();
-    method public static <E> java.util.NavigableSet<E> emptyNavigableSet();
-    method public static final <T> java.util.Set<T> emptySet();
-    method public static final <K, V> java.util.SortedMap<K, V> emptySortedMap();
-    method public static <E> java.util.SortedSet<E> emptySortedSet();
-    method public static <T> java.util.Enumeration<T> enumeration(java.util.Collection<T>);
-    method public static <T> void fill(java.util.List<? super T>, T);
-    method public static int frequency(java.util.Collection<?>, java.lang.Object);
-    method public static int indexOfSubList(java.util.List<?>, java.util.List<?>);
-    method public static int lastIndexOfSubList(java.util.List<?>, java.util.List<?>);
-    method public static <T> java.util.ArrayList<T> list(java.util.Enumeration<T>);
-    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>);
-    method public static <T> T max(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
-    method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T min(java.util.Collection<? extends T>);
-    method public static <T> T min(java.util.Collection<? extends T>, java.util.Comparator<? super T>);
-    method public static <T> java.util.List<T> nCopies(int, T);
-    method public static <E> java.util.Set<E> newSetFromMap(java.util.Map<E, java.lang.Boolean>);
-    method public static <T> boolean replaceAll(java.util.List<T>, T, T);
-    method public static void reverse(java.util.List<?>);
-    method public static <T> java.util.Comparator<T> reverseOrder();
-    method public static <T> java.util.Comparator<T> reverseOrder(java.util.Comparator<T>);
-    method public static void rotate(java.util.List<?>, int);
-    method public static void shuffle(java.util.List<?>);
-    method public static void shuffle(java.util.List<?>, java.util.Random);
-    method public static <T> java.util.Set<T> singleton(T);
-    method public static <T> java.util.List<T> singletonList(T);
-    method public static <K, V> java.util.Map<K, V> singletonMap(K, V);
-    method public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T>);
-    method public static <T> void sort(java.util.List<T>, java.util.Comparator<? super T>);
-    method public static void swap(java.util.List<?>, int, int);
-    method public static <T> java.util.Collection<T> synchronizedCollection(java.util.Collection<T>);
-    method public static <T> java.util.List<T> synchronizedList(java.util.List<T>);
-    method public static <K, V> java.util.Map<K, V> synchronizedMap(java.util.Map<K, V>);
-    method public static <K, V> java.util.NavigableMap<K, V> synchronizedNavigableMap(java.util.NavigableMap<K, V>);
-    method public static <T> java.util.NavigableSet<T> synchronizedNavigableSet(java.util.NavigableSet<T>);
-    method public static <T> java.util.Set<T> synchronizedSet(java.util.Set<T>);
-    method public static <K, V> java.util.SortedMap<K, V> synchronizedSortedMap(java.util.SortedMap<K, V>);
-    method public static <T> java.util.SortedSet<T> synchronizedSortedSet(java.util.SortedSet<T>);
-    method public static <T> java.util.Collection<T> unmodifiableCollection(java.util.Collection<? extends T>);
-    method public static <T> java.util.List<T> unmodifiableList(java.util.List<? extends T>);
-    method public static <K, V> java.util.Map<K, V> unmodifiableMap(java.util.Map<? extends K, ? extends V>);
-    method public static <K, V> java.util.NavigableMap<K, V> unmodifiableNavigableMap(java.util.NavigableMap<K, ? extends V>);
-    method public static <T> java.util.NavigableSet<T> unmodifiableNavigableSet(java.util.NavigableSet<T>);
-    method public static <T> java.util.Set<T> unmodifiableSet(java.util.Set<? extends T>);
-    method public static <K, V> java.util.SortedMap<K, V> unmodifiableSortedMap(java.util.SortedMap<K, ? extends V>);
-    method public static <T> java.util.SortedSet<T> unmodifiableSortedSet(java.util.SortedSet<T>);
-    field public static final java.util.List EMPTY_LIST;
-    field public static final java.util.Map EMPTY_MAP;
-    field public static final java.util.Set EMPTY_SET;
+    method @java.lang.SafeVarargs public static <T> boolean addAll(@NonNull java.util.Collection<? super T>, T...);
+    method @NonNull public static <T> java.util.Queue<T> asLifoQueue(@NonNull java.util.Deque<T>);
+    method public static <T> int binarySearch(@NonNull java.util.List<? extends java.lang.Comparable<? super T>>, @NonNull T);
+    method public static <T> int binarySearch(@NonNull java.util.List<? extends T>, T, @Nullable java.util.Comparator<? super T>);
+    method @NonNull public static <E> java.util.Collection<E> checkedCollection(@NonNull java.util.Collection<E>, @NonNull Class<E>);
+    method @NonNull public static <E> java.util.List<E> checkedList(@NonNull java.util.List<E>, @NonNull Class<E>);
+    method @NonNull public static <K, V> java.util.Map<K,V> checkedMap(@NonNull java.util.Map<K,V>, @NonNull Class<K>, @NonNull Class<V>);
+    method @NonNull public static <K, V> java.util.NavigableMap<K,V> checkedNavigableMap(@NonNull java.util.NavigableMap<K,V>, @NonNull Class<K>, @NonNull Class<V>);
+    method @NonNull public static <E> java.util.NavigableSet<E> checkedNavigableSet(@NonNull java.util.NavigableSet<E>, @NonNull Class<E>);
+    method @NonNull public static <E> java.util.Queue<E> checkedQueue(@NonNull java.util.Queue<E>, @NonNull Class<E>);
+    method @NonNull public static <E> java.util.Set<E> checkedSet(@NonNull java.util.Set<E>, @NonNull Class<E>);
+    method @NonNull public static <K, V> java.util.SortedMap<K,V> checkedSortedMap(@NonNull java.util.SortedMap<K,V>, @NonNull Class<K>, @NonNull Class<V>);
+    method @NonNull public static <E> java.util.SortedSet<E> checkedSortedSet(@NonNull java.util.SortedSet<E>, @NonNull Class<E>);
+    method public static <T> void copy(@NonNull java.util.List<? super T>, @NonNull java.util.List<? extends T>);
+    method public static boolean disjoint(@NonNull java.util.Collection<?>, @NonNull java.util.Collection<?>);
+    method @NonNull public static <T> java.util.Enumeration<T> emptyEnumeration();
+    method @NonNull public static <T> java.util.Iterator<T> emptyIterator();
+    method @NonNull public static final <T> java.util.List<T> emptyList();
+    method @NonNull public static <T> java.util.ListIterator<T> emptyListIterator();
+    method @NonNull public static final <K, V> java.util.Map<K,V> emptyMap();
+    method @NonNull public static final <K, V> java.util.NavigableMap<K,V> emptyNavigableMap();
+    method @NonNull public static <E> java.util.NavigableSet<E> emptyNavigableSet();
+    method @NonNull public static final <T> java.util.Set<T> emptySet();
+    method @NonNull public static final <K, V> java.util.SortedMap<K,V> emptySortedMap();
+    method @NonNull public static <E> java.util.SortedSet<E> emptySortedSet();
+    method @NonNull public static <T> java.util.Enumeration<T> enumeration(@NonNull java.util.Collection<T>);
+    method public static <T> void fill(@NonNull java.util.List<? super T>, T);
+    method public static int frequency(@NonNull java.util.Collection<?>, @Nullable Object);
+    method public static int indexOfSubList(@NonNull java.util.List<?>, @NonNull java.util.List<?>);
+    method public static int lastIndexOfSubList(@NonNull java.util.List<?>, @NonNull java.util.List<?>);
+    method @NonNull public static <T> java.util.ArrayList<T> list(@NonNull java.util.Enumeration<T>);
+    method @NonNull public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(@NonNull java.util.Collection<? extends T>);
+    method public static <T> T max(@NonNull java.util.Collection<? extends T>, @Nullable java.util.Comparator<? super T>);
+    method @NonNull public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T min(@NonNull java.util.Collection<? extends T>);
+    method public static <T> T min(@NonNull java.util.Collection<? extends T>, @Nullable java.util.Comparator<? super T>);
+    method @NonNull public static <T> java.util.List<T> nCopies(int, T);
+    method @NonNull public static <E> java.util.Set<E> newSetFromMap(@NonNull java.util.Map<E,java.lang.Boolean>);
+    method public static <T> boolean replaceAll(@NonNull java.util.List<T>, T, T);
+    method public static void reverse(@NonNull java.util.List<?>);
+    method @NonNull public static <T> java.util.Comparator<T> reverseOrder();
+    method @NonNull public static <T> java.util.Comparator<T> reverseOrder(@Nullable java.util.Comparator<T>);
+    method public static void rotate(@NonNull java.util.List<?>, int);
+    method public static void shuffle(@NonNull java.util.List<?>);
+    method public static void shuffle(@NonNull java.util.List<?>, @NonNull java.util.Random);
+    method @NonNull public static <T> java.util.Set<T> singleton(T);
+    method @NonNull public static <T> java.util.List<T> singletonList(T);
+    method @NonNull public static <K, V> java.util.Map<K,V> singletonMap(K, V);
+    method public static <T extends java.lang.Comparable<? super T>> void sort(@NonNull java.util.List<T>);
+    method public static <T> void sort(@NonNull java.util.List<T>, @Nullable java.util.Comparator<? super T>);
+    method public static void swap(@NonNull java.util.List<?>, int, int);
+    method @NonNull public static <T> java.util.Collection<T> synchronizedCollection(@NonNull java.util.Collection<T>);
+    method @NonNull public static <T> java.util.List<T> synchronizedList(@NonNull java.util.List<T>);
+    method @NonNull public static <K, V> java.util.Map<K,V> synchronizedMap(@NonNull java.util.Map<K,V>);
+    method @NonNull public static <K, V> java.util.NavigableMap<K,V> synchronizedNavigableMap(@NonNull java.util.NavigableMap<K,V>);
+    method @NonNull public static <T> java.util.NavigableSet<T> synchronizedNavigableSet(@NonNull java.util.NavigableSet<T>);
+    method @NonNull public static <T> java.util.Set<T> synchronizedSet(@NonNull java.util.Set<T>);
+    method @NonNull public static <K, V> java.util.SortedMap<K,V> synchronizedSortedMap(@NonNull java.util.SortedMap<K,V>);
+    method @NonNull public static <T> java.util.SortedSet<T> synchronizedSortedSet(@NonNull java.util.SortedSet<T>);
+    method @NonNull public static <T> java.util.Collection<T> unmodifiableCollection(@NonNull java.util.Collection<? extends T>);
+    method @NonNull public static <T> java.util.List<T> unmodifiableList(@NonNull java.util.List<? extends T>);
+    method @NonNull public static <K, V> java.util.Map<K,V> unmodifiableMap(@NonNull java.util.Map<? extends K,? extends V>);
+    method @NonNull public static <K, V> java.util.NavigableMap<K,V> unmodifiableNavigableMap(@NonNull java.util.NavigableMap<K,? extends V>);
+    method @NonNull public static <T> java.util.NavigableSet<T> unmodifiableNavigableSet(@NonNull java.util.NavigableSet<T>);
+    method @NonNull public static <T> java.util.Set<T> unmodifiableSet(@NonNull java.util.Set<? extends T>);
+    method @NonNull public static <K, V> java.util.SortedMap<K,V> unmodifiableSortedMap(@NonNull java.util.SortedMap<K,? extends V>);
+    method @NonNull public static <T> java.util.SortedSet<T> unmodifiableSortedSet(@NonNull java.util.SortedSet<T>);
+    field @NonNull public static final java.util.List EMPTY_LIST;
+    field @NonNull public static final java.util.Map EMPTY_MAP;
+    field @NonNull public static final java.util.Set EMPTY_SET;
   }
 
-  public abstract interface Comparator<T> {
-    method public abstract int compare(T, T);
-    method public static <T, U> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
-    method public static <T, U extends java.lang.Comparable<? super U>> java.util.Comparator<T> comparing(java.util.function.Function<? super T, ? extends U>);
+  @java.lang.FunctionalInterface public interface Comparator<T> {
+    method public int compare(T, T);
+    method public static <T, U> java.util.Comparator<T> comparing(java.util.function.Function<? super T,? extends U>, java.util.Comparator<? super U>);
+    method public static <T, U extends java.lang.Comparable<? super U>> java.util.Comparator<T> comparing(java.util.function.Function<? super T,? extends U>);
     method public static <T> java.util.Comparator<T> comparingDouble(java.util.function.ToDoubleFunction<? super T>);
     method public static <T> java.util.Comparator<T> comparingInt(java.util.function.ToIntFunction<? super T>);
     method public static <T> java.util.Comparator<T> comparingLong(java.util.function.ToLongFunction<? super T>);
-    method public abstract boolean equals(java.lang.Object);
+    method public boolean equals(Object);
     method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> naturalOrder();
     method public static <T> java.util.Comparator<T> nullsFirst(java.util.Comparator<? super T>);
     method public static <T> java.util.Comparator<T> nullsLast(java.util.Comparator<? super T>);
     method public static <T extends java.lang.Comparable<? super T>> java.util.Comparator<T> reverseOrder();
     method public default java.util.Comparator<T> reversed();
     method public default java.util.Comparator<T> thenComparing(java.util.Comparator<? super T>);
-    method public default <U> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>, java.util.Comparator<? super U>);
-    method public default <U extends java.lang.Comparable<? super U>> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T, ? extends U>);
+    method public default <U> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T,? extends U>, java.util.Comparator<? super U>);
+    method public default <U extends java.lang.Comparable<? super U>> java.util.Comparator<T> thenComparing(java.util.function.Function<? super T,? extends U>);
     method public default java.util.Comparator<T> thenComparingDouble(java.util.function.ToDoubleFunction<? super T>);
     method public default java.util.Comparator<T> thenComparingInt(java.util.function.ToIntFunction<? super T>);
     method public default java.util.Comparator<T> thenComparingLong(java.util.function.ToLongFunction<? super T>);
@@ -68953,87 +69291,87 @@
 
   public class ConcurrentModificationException extends java.lang.RuntimeException {
     ctor public ConcurrentModificationException();
-    ctor public ConcurrentModificationException(java.lang.String);
-    ctor public ConcurrentModificationException(java.lang.Throwable);
-    ctor public ConcurrentModificationException(java.lang.String, java.lang.Throwable);
+    ctor public ConcurrentModificationException(String);
+    ctor public ConcurrentModificationException(Throwable);
+    ctor public ConcurrentModificationException(String, Throwable);
   }
 
   public final class Currency implements java.io.Serializable {
     method public static java.util.Set<java.util.Currency> getAvailableCurrencies();
-    method public java.lang.String getCurrencyCode();
+    method public String getCurrencyCode();
     method public int getDefaultFractionDigits();
-    method public java.lang.String getDisplayName();
-    method public java.lang.String getDisplayName(java.util.Locale);
-    method public static java.util.Currency getInstance(java.lang.String);
+    method public String getDisplayName();
+    method public String getDisplayName(java.util.Locale);
+    method public static java.util.Currency getInstance(String);
     method public static java.util.Currency getInstance(java.util.Locale);
     method public int getNumericCode();
-    method public java.lang.String getSymbol();
-    method public java.lang.String getSymbol(java.util.Locale);
+    method public String getSymbol();
+    method public String getSymbol(java.util.Locale);
   }
 
-  public class Date implements java.lang.Cloneable java.lang.Comparable java.io.Serializable {
+  public class Date implements java.lang.Cloneable java.lang.Comparable<java.util.Date> java.io.Serializable {
     ctor public Date();
     ctor public Date(long);
-    ctor public deprecated Date(int, int, int);
-    ctor public deprecated Date(int, int, int, int, int);
-    ctor public deprecated Date(int, int, int, int, int, int);
-    ctor public deprecated Date(java.lang.String);
-    method public static deprecated long UTC(int, int, int, int, int, int);
+    ctor @Deprecated public Date(int, int, int);
+    ctor @Deprecated public Date(int, int, int, int, int);
+    ctor @Deprecated public Date(int, int, int, int, int, int);
+    ctor @Deprecated public Date(String);
+    method @Deprecated public static long UTC(int, int, int, int, int, int);
     method public boolean after(java.util.Date);
     method public boolean before(java.util.Date);
-    method public java.lang.Object clone();
+    method public Object clone();
     method public int compareTo(java.util.Date);
     method public static java.util.Date from(java.time.Instant);
-    method public deprecated int getDate();
-    method public deprecated int getDay();
-    method public deprecated int getHours();
-    method public deprecated int getMinutes();
-    method public deprecated int getMonth();
-    method public deprecated int getSeconds();
+    method @Deprecated public int getDate();
+    method @Deprecated public int getDay();
+    method @Deprecated public int getHours();
+    method @Deprecated public int getMinutes();
+    method @Deprecated public int getMonth();
+    method @Deprecated public int getSeconds();
     method public long getTime();
-    method public deprecated int getTimezoneOffset();
-    method public deprecated int getYear();
-    method public static deprecated long parse(java.lang.String);
-    method public deprecated void setDate(int);
-    method public deprecated void setHours(int);
-    method public deprecated void setMinutes(int);
-    method public deprecated void setMonth(int);
-    method public deprecated void setSeconds(int);
+    method @Deprecated public int getTimezoneOffset();
+    method @Deprecated public int getYear();
+    method @Deprecated public static long parse(String);
+    method @Deprecated public void setDate(int);
+    method @Deprecated public void setHours(int);
+    method @Deprecated public void setMinutes(int);
+    method @Deprecated public void setMonth(int);
+    method @Deprecated public void setSeconds(int);
     method public void setTime(long);
-    method public deprecated void setYear(int);
-    method public deprecated java.lang.String toGMTString();
+    method @Deprecated public void setYear(int);
+    method @Deprecated public String toGMTString();
     method public java.time.Instant toInstant();
-    method public deprecated java.lang.String toLocaleString();
+    method @Deprecated public String toLocaleString();
   }
 
-  public abstract interface Deque<E> implements java.util.Queue {
-    method public abstract void addFirst(E);
-    method public abstract void addLast(E);
-    method public abstract java.util.Iterator<E> descendingIterator();
-    method public abstract E getFirst();
-    method public abstract E getLast();
-    method public abstract boolean offerFirst(E);
-    method public abstract boolean offerLast(E);
-    method public abstract E peekFirst();
-    method public abstract E peekLast();
-    method public abstract E pollFirst();
-    method public abstract E pollLast();
-    method public abstract E pop();
-    method public abstract void push(E);
-    method public abstract E removeFirst();
-    method public abstract boolean removeFirstOccurrence(java.lang.Object);
-    method public abstract E removeLast();
-    method public abstract boolean removeLastOccurrence(java.lang.Object);
+  public interface Deque<E> extends java.util.Queue<E> {
+    method public void addFirst(E);
+    method public void addLast(E);
+    method @NonNull public java.util.Iterator<E> descendingIterator();
+    method public E getFirst();
+    method public E getLast();
+    method public boolean offerFirst(E);
+    method public boolean offerLast(E);
+    method @Nullable public E peekFirst();
+    method @Nullable public E peekLast();
+    method @Nullable public E pollFirst();
+    method @Nullable public E pollLast();
+    method public E pop();
+    method public void push(E);
+    method public E removeFirst();
+    method public boolean removeFirstOccurrence(@Nullable Object);
+    method public E removeLast();
+    method public boolean removeLastOccurrence(@Nullable Object);
   }
 
   public abstract class Dictionary<K, V> {
     ctor public Dictionary();
     method public abstract java.util.Enumeration<V> elements();
-    method public abstract V get(java.lang.Object);
+    method public abstract V get(Object);
     method public abstract boolean isEmpty();
     method public abstract java.util.Enumeration<K> keys();
     method public abstract V put(K, V);
-    method public abstract V remove(java.lang.Object);
+    method public abstract V remove(Object);
     method public abstract int size();
   }
 
@@ -69049,44 +69387,44 @@
   }
 
   public class DuplicateFormatFlagsException extends java.util.IllegalFormatException {
-    ctor public DuplicateFormatFlagsException(java.lang.String);
-    method public java.lang.String getFlags();
+    ctor public DuplicateFormatFlagsException(String);
+    method public String getFlags();
   }
 
   public class EmptyStackException extends java.lang.RuntimeException {
     ctor public EmptyStackException();
   }
 
-  public class EnumMap<K extends java.lang.Enum<K>, V> extends java.util.AbstractMap implements java.lang.Cloneable java.io.Serializable {
-    ctor public EnumMap(java.lang.Class<K>);
-    ctor public EnumMap(java.util.EnumMap<K, ? extends V>);
-    ctor public EnumMap(java.util.Map<K, ? extends V>);
-    method public java.util.EnumMap<K, V> clone();
-    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+  public class EnumMap<K extends java.lang.Enum<K>, V> extends java.util.AbstractMap<K,V> implements java.lang.Cloneable java.io.Serializable {
+    ctor public EnumMap(Class<K>);
+    ctor public EnumMap(java.util.EnumMap<K,? extends V>);
+    ctor public EnumMap(java.util.Map<K,? extends V>);
+    method public java.util.EnumMap<K,V> clone();
+    method public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
   }
 
-  public abstract class EnumSet<E extends java.lang.Enum<E>> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable {
-    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> allOf(java.lang.Class<E>);
+  public abstract class EnumSet<E extends java.lang.Enum<E>> extends java.util.AbstractSet<E> implements java.lang.Cloneable java.io.Serializable {
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> allOf(Class<E>);
     method public java.util.EnumSet<E> clone();
     method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> complementOf(java.util.EnumSet<E>);
     method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.EnumSet<E>);
     method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> copyOf(java.util.Collection<E>);
-    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> noneOf(java.lang.Class<E>);
+    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> noneOf(Class<E>);
     method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E);
     method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E);
     method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E);
     method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E);
     method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E, E, E, E);
-    method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E...);
+    method @java.lang.SafeVarargs public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> of(E, E...);
     method public static <E extends java.lang.Enum<E>> java.util.EnumSet<E> range(E, E);
   }
 
-  public abstract interface Enumeration<E> {
-    method public abstract boolean hasMoreElements();
-    method public abstract E nextElement();
+  public interface Enumeration<E> {
+    method public boolean hasMoreElements();
+    method public E nextElement();
   }
 
-  public abstract interface EventListener {
+  public interface EventListener {
   }
 
   public abstract class EventListenerProxy<T extends java.util.EventListener> implements java.util.EventListener {
@@ -69095,19 +69433,19 @@
   }
 
   public class EventObject implements java.io.Serializable {
-    ctor public EventObject(java.lang.Object);
-    method public java.lang.Object getSource();
-    field protected transient java.lang.Object source;
+    ctor public EventObject(Object);
+    method public Object getSource();
+    field protected transient Object source;
   }
 
   public class FormatFlagsConversionMismatchException extends java.util.IllegalFormatException {
-    ctor public FormatFlagsConversionMismatchException(java.lang.String, char);
+    ctor public FormatFlagsConversionMismatchException(String, char);
     method public char getConversion();
-    method public java.lang.String getFlags();
+    method public String getFlags();
   }
 
-  public abstract interface Formattable {
-    method public abstract void formatTo(java.util.Formatter, int, int, int);
+  public interface Formattable {
+    method public void formatTo(java.util.Formatter, int, int, int);
   }
 
   public class FormattableFlags {
@@ -69118,31 +69456,29 @@
 
   public final class Formatter implements java.io.Closeable java.io.Flushable {
     ctor public Formatter();
-    ctor public Formatter(java.lang.Appendable);
+    ctor public Formatter(Appendable);
     ctor public Formatter(java.util.Locale);
-    ctor public Formatter(java.lang.Appendable, java.util.Locale);
-    ctor public Formatter(java.lang.String) throws java.io.FileNotFoundException;
-    ctor public Formatter(java.lang.String, java.lang.String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
-    ctor public Formatter(java.lang.String, java.lang.String, java.util.Locale) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+    ctor public Formatter(Appendable, java.util.Locale);
+    ctor public Formatter(String) throws java.io.FileNotFoundException;
+    ctor public Formatter(String, String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+    ctor public Formatter(String, String, java.util.Locale) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
     ctor public Formatter(java.io.File) throws java.io.FileNotFoundException;
-    ctor public Formatter(java.io.File, java.lang.String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
-    ctor public Formatter(java.io.File, java.lang.String, java.util.Locale) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+    ctor public Formatter(java.io.File, String) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
+    ctor public Formatter(java.io.File, String, java.util.Locale) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException;
     ctor public Formatter(java.io.PrintStream);
     ctor public Formatter(java.io.OutputStream);
-    ctor public Formatter(java.io.OutputStream, java.lang.String) throws java.io.UnsupportedEncodingException;
-    ctor public Formatter(java.io.OutputStream, java.lang.String, java.util.Locale) throws java.io.UnsupportedEncodingException;
+    ctor public Formatter(java.io.OutputStream, String) throws java.io.UnsupportedEncodingException;
+    ctor public Formatter(java.io.OutputStream, String, java.util.Locale) throws java.io.UnsupportedEncodingException;
     method public void close();
     method public void flush();
-    method public java.util.Formatter format(java.lang.String, java.lang.Object...);
-    method public java.util.Formatter format(java.util.Locale, java.lang.String, java.lang.Object...);
+    method public java.util.Formatter format(String, java.lang.Object...);
+    method public java.util.Formatter format(java.util.Locale, String, java.lang.Object...);
     method public java.io.IOException ioException();
     method public java.util.Locale locale();
-    method public java.lang.Appendable out();
+    method public Appendable out();
   }
 
-  public static final class Formatter.BigDecimalLayoutForm extends java.lang.Enum {
-    method public static java.util.Formatter.BigDecimalLayoutForm valueOf(java.lang.String);
-    method public static final java.util.Formatter.BigDecimalLayoutForm[] values();
+  public enum Formatter.BigDecimalLayoutForm {
     enum_constant public static final java.util.Formatter.BigDecimalLayoutForm DECIMAL_FLOAT;
     enum_constant public static final java.util.Formatter.BigDecimalLayoutForm SCIENTIFIC;
   }
@@ -69177,69 +69513,55 @@
     field public static final int BC = 0; // 0x0
   }
 
-  public class HashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
+  public class HashMap<K, V> extends java.util.AbstractMap<K,V> implements java.lang.Cloneable java.util.Map<K,V> java.io.Serializable {
     ctor public HashMap(int, float);
     ctor public HashMap(int);
     ctor public HashMap();
-    ctor public HashMap(java.util.Map<? extends K, ? extends V>);
-    method public java.lang.Object clone();
-    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    ctor public HashMap(@NonNull java.util.Map<? extends K,? extends V>);
+    method @NonNull public Object clone();
+    method @NonNull public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
   }
 
-  public class HashSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
+  public class HashSet<E> extends java.util.AbstractSet<E> implements java.lang.Cloneable java.io.Serializable java.util.Set<E> {
     ctor public HashSet();
-    ctor public HashSet(java.util.Collection<? extends E>);
+    ctor public HashSet(@NonNull java.util.Collection<? extends E>);
     ctor public HashSet(int, float);
     ctor public HashSet(int);
-    method public java.lang.Object clone();
-    method public java.util.Iterator<E> iterator();
+    method @NonNull public Object clone();
+    method @NonNull public java.util.Iterator<E> iterator();
     method public int size();
   }
 
-  public class Hashtable<K, V> extends java.util.Dictionary implements java.lang.Cloneable java.util.Map java.io.Serializable {
+  public class Hashtable<K, V> extends java.util.Dictionary<K,V> implements java.lang.Cloneable java.util.Map<K,V> java.io.Serializable {
     ctor public Hashtable(int, float);
     ctor public Hashtable(int);
     ctor public Hashtable();
-    ctor public Hashtable(java.util.Map<? extends K, ? extends V>);
-    method public synchronized void clear();
-    method public synchronized java.lang.Object clone();
-    method public synchronized V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
-    method public synchronized V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
-    method public synchronized V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
-    method public synchronized boolean contains(java.lang.Object);
-    method public synchronized boolean containsKey(java.lang.Object);
-    method public boolean containsValue(java.lang.Object);
-    method public synchronized java.util.Enumeration<V> elements();
-    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
-    method public synchronized boolean equals(java.lang.Object);
-    method public synchronized void forEach(java.util.function.BiConsumer<? super K, ? super V>);
-    method public synchronized V get(java.lang.Object);
-    method public synchronized V getOrDefault(java.lang.Object, V);
-    method public synchronized int hashCode();
-    method public synchronized boolean isEmpty();
+    ctor public Hashtable(java.util.Map<? extends K,? extends V>);
+    method public void clear();
+    method public Object clone();
+    method public boolean contains(Object);
+    method public boolean containsKey(Object);
+    method public boolean containsValue(Object);
+    method public java.util.Enumeration<V> elements();
+    method public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
+    method public V get(Object);
+    method public boolean isEmpty();
     method public java.util.Set<K> keySet();
-    method public synchronized java.util.Enumeration<K> keys();
-    method public synchronized V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
-    method public synchronized V put(K, V);
-    method public synchronized void putAll(java.util.Map<? extends K, ? extends V>);
-    method public synchronized V putIfAbsent(K, V);
+    method public java.util.Enumeration<K> keys();
+    method public V put(K, V);
+    method public void putAll(java.util.Map<? extends K,? extends V>);
     method protected void rehash();
-    method public synchronized V remove(java.lang.Object);
-    method public synchronized boolean remove(java.lang.Object, java.lang.Object);
-    method public synchronized boolean replace(K, V, V);
-    method public synchronized V replace(K, V);
-    method public synchronized void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
-    method public synchronized int size();
-    method public synchronized java.lang.String toString();
+    method public V remove(Object);
+    method public int size();
     method public java.util.Collection<V> values();
   }
 
-  public class IdentityHashMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.Map java.io.Serializable {
+  public class IdentityHashMap<K, V> extends java.util.AbstractMap<K,V> implements java.lang.Cloneable java.util.Map<K,V> java.io.Serializable {
     ctor public IdentityHashMap();
     ctor public IdentityHashMap(int);
-    ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
-    method public java.lang.Object clone();
-    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    ctor public IdentityHashMap(java.util.Map<? extends K,? extends V>);
+    method public Object clone();
+    method public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
   }
 
   public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -69248,8 +69570,8 @@
   }
 
   public class IllegalFormatConversionException extends java.util.IllegalFormatException {
-    ctor public IllegalFormatConversionException(char, java.lang.Class<?>);
-    method public java.lang.Class<?> getArgumentClass();
+    ctor public IllegalFormatConversionException(char, Class<?>);
+    method public Class<?> getArgumentClass();
     method public char getConversion();
   }
 
@@ -69257,8 +69579,8 @@
   }
 
   public class IllegalFormatFlagsException extends java.util.IllegalFormatException {
-    ctor public IllegalFormatFlagsException(java.lang.String);
-    method public java.lang.String getFlags();
+    ctor public IllegalFormatFlagsException(String);
+    method public String getFlags();
   }
 
   public class IllegalFormatPrecisionException extends java.util.IllegalFormatException {
@@ -69273,14 +69595,14 @@
 
   public class IllformedLocaleException extends java.lang.RuntimeException {
     ctor public IllformedLocaleException();
-    ctor public IllformedLocaleException(java.lang.String);
-    ctor public IllformedLocaleException(java.lang.String, int);
+    ctor public IllformedLocaleException(String);
+    ctor public IllformedLocaleException(String, int);
     method public int getErrorIndex();
   }
 
   public class InputMismatchException extends java.util.NoSuchElementException {
     ctor public InputMismatchException();
-    ctor public InputMismatchException(java.lang.String);
+    ctor public InputMismatchException(String);
   }
 
   public class IntSummaryStatistics implements java.util.function.IntConsumer {
@@ -69295,190 +69617,186 @@
   }
 
   public class InvalidPropertiesFormatException extends java.io.IOException {
-    ctor public InvalidPropertiesFormatException(java.lang.Throwable);
-    ctor public InvalidPropertiesFormatException(java.lang.String);
+    ctor public InvalidPropertiesFormatException(Throwable);
+    ctor public InvalidPropertiesFormatException(String);
   }
 
-  public abstract interface Iterator<E> {
-    method public default void forEachRemaining(java.util.function.Consumer<? super E>);
-    method public abstract boolean hasNext();
-    method public abstract E next();
+  public interface Iterator<E> {
+    method public default void forEachRemaining(@NonNull java.util.function.Consumer<? super E>);
+    method public boolean hasNext();
+    method public E next();
     method public default void remove();
   }
 
-  public class LinkedHashMap<K, V> extends java.util.HashMap implements java.util.Map {
+  public class LinkedHashMap<K, V> extends java.util.HashMap<K,V> implements java.util.Map<K,V> {
     ctor public LinkedHashMap(int, float);
     ctor public LinkedHashMap(int);
     ctor public LinkedHashMap();
-    ctor public LinkedHashMap(java.util.Map<? extends K, ? extends V>);
+    ctor public LinkedHashMap(java.util.Map<? extends K,? extends V>);
     ctor public LinkedHashMap(int, float, boolean);
-    method protected boolean removeEldestEntry(java.util.Map.Entry<K, V>);
+    method protected boolean removeEldestEntry(java.util.Map.Entry<K,V>);
   }
 
-  public class LinkedHashSet<E> extends java.util.HashSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
+  public class LinkedHashSet<E> extends java.util.HashSet<E> implements java.lang.Cloneable java.io.Serializable java.util.Set<E> {
     ctor public LinkedHashSet(int, float);
     ctor public LinkedHashSet(int);
     ctor public LinkedHashSet();
     ctor public LinkedHashSet(java.util.Collection<? extends E>);
   }
 
-  public class LinkedList<E> extends java.util.AbstractSequentialList implements java.lang.Cloneable java.util.Deque java.util.List java.io.Serializable {
+  public class LinkedList<E> extends java.util.AbstractSequentialList<E> implements java.lang.Cloneable java.util.Deque<E> java.util.List<E> java.io.Serializable {
     ctor public LinkedList();
-    ctor public LinkedList(java.util.Collection<? extends E>);
+    ctor public LinkedList(@NonNull java.util.Collection<? extends E>);
     method public void addFirst(E);
     method public void addLast(E);
-    method public java.lang.Object clone();
-    method public java.util.Iterator<E> descendingIterator();
+    method @NonNull public Object clone();
+    method @NonNull public java.util.Iterator<E> descendingIterator();
     method public E element();
     method public E getFirst();
     method public E getLast();
     method public boolean offer(E);
     method public boolean offerFirst(E);
     method public boolean offerLast(E);
-    method public E peek();
-    method public E peekFirst();
-    method public E peekLast();
-    method public E poll();
-    method public E pollFirst();
-    method public E pollLast();
+    method @Nullable public E peek();
+    method @Nullable public E peekFirst();
+    method @Nullable public E peekLast();
+    method @Nullable public E poll();
+    method @Nullable public E pollFirst();
+    method @Nullable public E pollLast();
     method public E pop();
     method public void push(E);
     method public E remove();
     method public E removeFirst();
-    method public boolean removeFirstOccurrence(java.lang.Object);
+    method public boolean removeFirstOccurrence(@Nullable Object);
     method public E removeLast();
-    method public boolean removeLastOccurrence(java.lang.Object);
+    method public boolean removeLastOccurrence(@Nullable Object);
     method public int size();
   }
 
-  public abstract interface List<E> implements java.util.Collection {
-    method public abstract void add(int, E);
-    method public abstract boolean addAll(int, java.util.Collection<? extends E>);
-    method public abstract E get(int);
-    method public abstract int indexOf(java.lang.Object);
-    method public abstract int lastIndexOf(java.lang.Object);
-    method public abstract java.util.ListIterator<E> listIterator();
-    method public abstract java.util.ListIterator<E> listIterator(int);
-    method public abstract E remove(int);
-    method public default void replaceAll(java.util.function.UnaryOperator<E>);
-    method public abstract E set(int, E);
-    method public default void sort(java.util.Comparator<? super E>);
-    method public abstract java.util.List<E> subList(int, int);
+  public interface List<E> extends java.util.Collection<E> {
+    method public void add(int, E);
+    method public boolean addAll(int, @NonNull java.util.Collection<? extends E>);
+    method public E get(int);
+    method public int indexOf(@Nullable Object);
+    method public int lastIndexOf(@Nullable Object);
+    method @NonNull public java.util.ListIterator<E> listIterator();
+    method @NonNull public java.util.ListIterator<E> listIterator(int);
+    method public E remove(int);
+    method public default void replaceAll(@NonNull java.util.function.UnaryOperator<E>);
+    method public E set(int, E);
+    method public default void sort(@Nullable java.util.Comparator<? super E>);
+    method @NonNull public java.util.List<E> subList(int, int);
   }
 
-  public abstract interface ListIterator<E> implements java.util.Iterator {
-    method public abstract void add(E);
-    method public abstract boolean hasPrevious();
-    method public abstract int nextIndex();
-    method public abstract E previous();
-    method public abstract int previousIndex();
-    method public abstract void remove();
-    method public abstract void set(E);
+  public interface ListIterator<E> extends java.util.Iterator<E> {
+    method public void add(E);
+    method public boolean hasPrevious();
+    method public int nextIndex();
+    method public E previous();
+    method public int previousIndex();
+    method public void remove();
+    method public void set(E);
   }
 
   public abstract class ListResourceBundle extends java.util.ResourceBundle {
     ctor public ListResourceBundle();
-    method protected abstract java.lang.Object[][] getContents();
+    method protected abstract Object[][] getContents();
     method public java.util.Enumeration<java.lang.String> getKeys();
-    method public final java.lang.Object handleGetObject(java.lang.String);
+    method public final Object handleGetObject(String);
   }
 
   public final class Locale implements java.lang.Cloneable java.io.Serializable {
-    ctor public Locale(java.lang.String, java.lang.String, java.lang.String);
-    ctor public Locale(java.lang.String, java.lang.String);
-    ctor public Locale(java.lang.String);
-    method public java.lang.Object clone();
-    method public static java.util.List<java.util.Locale> filter(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.util.Locale>, java.util.Locale.FilteringMode);
-    method public static java.util.List<java.util.Locale> filter(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.util.Locale>);
-    method public static java.util.List<java.lang.String> filterTags(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.lang.String>, java.util.Locale.FilteringMode);
-    method public static java.util.List<java.lang.String> filterTags(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.lang.String>);
-    method public static java.util.Locale forLanguageTag(java.lang.String);
+    ctor public Locale(@NonNull String, @NonNull String, @NonNull String);
+    ctor public Locale(@NonNull String, @NonNull String);
+    ctor public Locale(@NonNull String);
+    method @NonNull public Object clone();
+    method @NonNull public static java.util.List<java.util.Locale> filter(@NonNull java.util.List<java.util.Locale.LanguageRange>, @NonNull java.util.Collection<java.util.Locale>, @NonNull java.util.Locale.FilteringMode);
+    method @NonNull public static java.util.List<java.util.Locale> filter(@NonNull java.util.List<java.util.Locale.LanguageRange>, @NonNull java.util.Collection<java.util.Locale>);
+    method @NonNull public static java.util.List<java.lang.String> filterTags(@NonNull java.util.List<java.util.Locale.LanguageRange>, @NonNull java.util.Collection<java.lang.String>, @NonNull java.util.Locale.FilteringMode);
+    method @NonNull public static java.util.List<java.lang.String> filterTags(@NonNull java.util.List<java.util.Locale.LanguageRange>, @NonNull java.util.Collection<java.lang.String>);
+    method @NonNull public static java.util.Locale forLanguageTag(@NonNull String);
     method public static java.util.Locale[] getAvailableLocales();
-    method public java.lang.String getCountry();
-    method public static java.util.Locale getDefault();
-    method public static java.util.Locale getDefault(java.util.Locale.Category);
-    method public java.lang.String getDisplayCountry();
-    method public java.lang.String getDisplayCountry(java.util.Locale);
-    method public java.lang.String getDisplayLanguage();
-    method public java.lang.String getDisplayLanguage(java.util.Locale);
-    method public java.lang.String getDisplayName();
-    method public java.lang.String getDisplayName(java.util.Locale);
-    method public java.lang.String getDisplayScript();
-    method public java.lang.String getDisplayScript(java.util.Locale);
-    method public java.lang.String getDisplayVariant();
-    method public java.lang.String getDisplayVariant(java.util.Locale);
-    method public java.lang.String getExtension(char);
-    method public java.util.Set<java.lang.Character> getExtensionKeys();
-    method public java.lang.String getISO3Country() throws java.util.MissingResourceException;
-    method public java.lang.String getISO3Language() throws java.util.MissingResourceException;
-    method public static java.lang.String[] getISOCountries();
-    method public static java.lang.String[] getISOLanguages();
-    method public java.lang.String getLanguage();
-    method public java.lang.String getScript();
-    method public java.util.Set<java.lang.String> getUnicodeLocaleAttributes();
-    method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
-    method public java.lang.String getUnicodeLocaleType(java.lang.String);
-    method public java.lang.String getVariant();
+    method @NonNull public String getCountry();
+    method @NonNull public static java.util.Locale getDefault();
+    method @NonNull public static java.util.Locale getDefault(@NonNull java.util.Locale.Category);
+    method @NonNull public String getDisplayCountry();
+    method @NonNull public String getDisplayCountry(@NonNull java.util.Locale);
+    method @NonNull public String getDisplayLanguage();
+    method @NonNull public String getDisplayLanguage(@NonNull java.util.Locale);
+    method @NonNull public String getDisplayName();
+    method @NonNull public String getDisplayName(@NonNull java.util.Locale);
+    method @NonNull public String getDisplayScript();
+    method @NonNull public String getDisplayScript(@NonNull java.util.Locale);
+    method @NonNull public String getDisplayVariant();
+    method @NonNull public String getDisplayVariant(@NonNull java.util.Locale);
+    method @Nullable public String getExtension(char);
+    method @NonNull public java.util.Set<java.lang.Character> getExtensionKeys();
+    method @NonNull public String getISO3Country() throws java.util.MissingResourceException;
+    method @NonNull public String getISO3Language() throws java.util.MissingResourceException;
+    method public static String[] getISOCountries();
+    method public static String[] getISOLanguages();
+    method @NonNull public String getLanguage();
+    method @NonNull public String getScript();
+    method @NonNull public java.util.Set<java.lang.String> getUnicodeLocaleAttributes();
+    method @NonNull public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
+    method @Nullable public String getUnicodeLocaleType(@NonNull String);
+    method @NonNull public String getVariant();
     method public boolean hasExtensions();
-    method public static java.util.Locale lookup(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.util.Locale>);
-    method public static java.lang.String lookupTag(java.util.List<java.util.Locale.LanguageRange>, java.util.Collection<java.lang.String>);
-    method public static synchronized void setDefault(java.util.Locale);
-    method public static synchronized void setDefault(java.util.Locale.Category, java.util.Locale);
-    method public java.util.Locale stripExtensions();
-    method public java.lang.String toLanguageTag();
-    field public static final java.util.Locale CANADA;
-    field public static final java.util.Locale CANADA_FRENCH;
-    field public static final java.util.Locale CHINA;
-    field public static final java.util.Locale CHINESE;
-    field public static final java.util.Locale ENGLISH;
-    field public static final java.util.Locale FRANCE;
-    field public static final java.util.Locale FRENCH;
-    field public static final java.util.Locale GERMAN;
-    field public static final java.util.Locale GERMANY;
-    field public static final java.util.Locale ITALIAN;
-    field public static final java.util.Locale ITALY;
-    field public static final java.util.Locale JAPAN;
-    field public static final java.util.Locale JAPANESE;
-    field public static final java.util.Locale KOREA;
-    field public static final java.util.Locale KOREAN;
-    field public static final java.util.Locale PRC;
+    method @Nullable public static java.util.Locale lookup(@NonNull java.util.List<java.util.Locale.LanguageRange>, @NonNull java.util.Collection<java.util.Locale>);
+    method @Nullable public static String lookupTag(@NonNull java.util.List<java.util.Locale.LanguageRange>, @NonNull java.util.Collection<java.lang.String>);
+    method public static void setDefault(@NonNull java.util.Locale);
+    method public static void setDefault(@NonNull java.util.Locale.Category, @NonNull java.util.Locale);
+    method @NonNull public java.util.Locale stripExtensions();
+    method @NonNull public String toLanguageTag();
+    field @NonNull public static final java.util.Locale CANADA;
+    field @NonNull public static final java.util.Locale CANADA_FRENCH;
+    field @NonNull public static final java.util.Locale CHINA;
+    field @NonNull public static final java.util.Locale CHINESE;
+    field @NonNull public static final java.util.Locale ENGLISH;
+    field @NonNull public static final java.util.Locale FRANCE;
+    field @NonNull public static final java.util.Locale FRENCH;
+    field @NonNull public static final java.util.Locale GERMAN;
+    field @NonNull public static final java.util.Locale GERMANY;
+    field @NonNull public static final java.util.Locale ITALIAN;
+    field @NonNull public static final java.util.Locale ITALY;
+    field @NonNull public static final java.util.Locale JAPAN;
+    field @NonNull public static final java.util.Locale JAPANESE;
+    field @NonNull public static final java.util.Locale KOREA;
+    field @NonNull public static final java.util.Locale KOREAN;
+    field @NonNull public static final java.util.Locale PRC;
     field public static final char PRIVATE_USE_EXTENSION = 120; // 0x0078 'x'
-    field public static final java.util.Locale ROOT;
-    field public static final java.util.Locale SIMPLIFIED_CHINESE;
-    field public static final java.util.Locale TAIWAN;
-    field public static final java.util.Locale TRADITIONAL_CHINESE;
-    field public static final java.util.Locale UK;
+    field @NonNull public static final java.util.Locale ROOT;
+    field @NonNull public static final java.util.Locale SIMPLIFIED_CHINESE;
+    field @NonNull public static final java.util.Locale TAIWAN;
+    field @NonNull public static final java.util.Locale TRADITIONAL_CHINESE;
+    field @NonNull public static final java.util.Locale UK;
     field public static final char UNICODE_LOCALE_EXTENSION = 117; // 0x0075 'u'
-    field public static final java.util.Locale US;
+    field @NonNull public static final java.util.Locale US;
   }
 
   public static final class Locale.Builder {
     ctor public Locale.Builder();
-    method public java.util.Locale.Builder addUnicodeLocaleAttribute(java.lang.String);
-    method public java.util.Locale build();
-    method public java.util.Locale.Builder clear();
-    method public java.util.Locale.Builder clearExtensions();
-    method public java.util.Locale.Builder removeUnicodeLocaleAttribute(java.lang.String);
-    method public java.util.Locale.Builder setExtension(char, java.lang.String);
-    method public java.util.Locale.Builder setLanguage(java.lang.String);
-    method public java.util.Locale.Builder setLanguageTag(java.lang.String);
-    method public java.util.Locale.Builder setLocale(java.util.Locale);
-    method public java.util.Locale.Builder setRegion(java.lang.String);
-    method public java.util.Locale.Builder setScript(java.lang.String);
-    method public java.util.Locale.Builder setUnicodeLocaleKeyword(java.lang.String, java.lang.String);
-    method public java.util.Locale.Builder setVariant(java.lang.String);
+    method @NonNull public java.util.Locale.Builder addUnicodeLocaleAttribute(@NonNull String);
+    method @NonNull public java.util.Locale build();
+    method @NonNull public java.util.Locale.Builder clear();
+    method @NonNull public java.util.Locale.Builder clearExtensions();
+    method @NonNull public java.util.Locale.Builder removeUnicodeLocaleAttribute(@NonNull String);
+    method @NonNull public java.util.Locale.Builder setExtension(char, @Nullable String);
+    method @NonNull public java.util.Locale.Builder setLanguage(@Nullable String);
+    method @NonNull public java.util.Locale.Builder setLanguageTag(@NonNull String);
+    method @NonNull public java.util.Locale.Builder setLocale(@NonNull java.util.Locale);
+    method @NonNull public java.util.Locale.Builder setRegion(@Nullable String);
+    method @NonNull public java.util.Locale.Builder setScript(@Nullable String);
+    method @NonNull public java.util.Locale.Builder setUnicodeLocaleKeyword(@NonNull String, @Nullable String);
+    method @NonNull public java.util.Locale.Builder setVariant(@Nullable String);
   }
 
-  public static final class Locale.Category extends java.lang.Enum {
-    method public static java.util.Locale.Category valueOf(java.lang.String);
-    method public static final java.util.Locale.Category[] values();
+  public enum Locale.Category {
     enum_constant public static final java.util.Locale.Category DISPLAY;
     enum_constant public static final java.util.Locale.Category FORMAT;
   }
 
-  public static final class Locale.FilteringMode extends java.lang.Enum {
-    method public static java.util.Locale.FilteringMode valueOf(java.lang.String);
-    method public static final java.util.Locale.FilteringMode[] values();
+  public enum Locale.FilteringMode {
     enum_constant public static final java.util.Locale.FilteringMode AUTOSELECT_FILTERING;
     enum_constant public static final java.util.Locale.FilteringMode EXTENDED_FILTERING;
     enum_constant public static final java.util.Locale.FilteringMode IGNORE_EXTENDED_RANGES;
@@ -69487,13 +69805,13 @@
   }
 
   public static final class Locale.LanguageRange {
-    ctor public Locale.LanguageRange(java.lang.String);
-    ctor public Locale.LanguageRange(java.lang.String, double);
-    method public java.lang.String getRange();
+    ctor public Locale.LanguageRange(@NonNull String);
+    ctor public Locale.LanguageRange(@NonNull String, double);
+    method @NonNull public String getRange();
     method public double getWeight();
-    method public static java.util.List<java.util.Locale.LanguageRange> mapEquivalents(java.util.List<java.util.Locale.LanguageRange>, java.util.Map<java.lang.String, java.util.List<java.lang.String>>);
-    method public static java.util.List<java.util.Locale.LanguageRange> parse(java.lang.String);
-    method public static java.util.List<java.util.Locale.LanguageRange> parse(java.lang.String, java.util.Map<java.lang.String, java.util.List<java.lang.String>>);
+    method @NonNull public static java.util.List<java.util.Locale.LanguageRange> mapEquivalents(@NonNull java.util.List<java.util.Locale.LanguageRange>, @NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>);
+    method @NonNull public static java.util.List<java.util.Locale.LanguageRange> parse(@NonNull String);
+    method @NonNull public static java.util.List<java.util.Locale.LanguageRange> parse(@NonNull String, @NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>);
     field public static final double MAX_WEIGHT = 1.0;
     field public static final double MIN_WEIGHT = 0.0;
   }
@@ -69510,147 +69828,147 @@
     method public final long getSum();
   }
 
-  public abstract interface Map<K, V> {
-    method public abstract void clear();
-    method public default V compute(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
-    method public default V computeIfAbsent(K, java.util.function.Function<? super K, ? extends V>);
-    method public default V computeIfPresent(K, java.util.function.BiFunction<? super K, ? super V, ? extends V>);
-    method public abstract boolean containsKey(java.lang.Object);
-    method public abstract boolean containsValue(java.lang.Object);
-    method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
-    method public abstract boolean equals(java.lang.Object);
-    method public default void forEach(java.util.function.BiConsumer<? super K, ? super V>);
-    method public abstract V get(java.lang.Object);
-    method public default V getOrDefault(java.lang.Object, V);
-    method public abstract int hashCode();
-    method public abstract boolean isEmpty();
-    method public abstract java.util.Set<K> keySet();
-    method public default V merge(K, V, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
-    method public abstract V put(K, V);
-    method public abstract void putAll(java.util.Map<? extends K, ? extends V>);
-    method public default V putIfAbsent(K, V);
-    method public abstract V remove(java.lang.Object);
-    method public default boolean remove(java.lang.Object, java.lang.Object);
-    method public default boolean replace(K, V, V);
-    method public default V replace(K, V);
-    method public default void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
-    method public abstract int size();
-    method public abstract java.util.Collection<V> values();
+  public interface Map<K, V> {
+    method public void clear();
+    method @Nullable public default V compute(K, @NonNull java.util.function.BiFunction<? super K,? super V,? extends V>);
+    method @Nullable public default V computeIfAbsent(K, @NonNull java.util.function.Function<? super K,? extends V>);
+    method @Nullable public default V computeIfPresent(K, @NonNull java.util.function.BiFunction<? super K,? super V,? extends V>);
+    method public boolean containsKey(@Nullable Object);
+    method public boolean containsValue(@Nullable Object);
+    method @NonNull public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
+    method public boolean equals(@Nullable Object);
+    method public default void forEach(@NonNull java.util.function.BiConsumer<? super K,? super V>);
+    method @Nullable public V get(@Nullable Object);
+    method @Nullable public default V getOrDefault(@Nullable Object, @Nullable V);
+    method public int hashCode();
+    method public boolean isEmpty();
+    method @NonNull public java.util.Set<K> keySet();
+    method @Nullable public default V merge(K, @NonNull V, @NonNull java.util.function.BiFunction<? super V,? super V,? extends V>);
+    method @Nullable public V put(K, V);
+    method public void putAll(@NonNull java.util.Map<? extends K,? extends V>);
+    method @Nullable public default V putIfAbsent(K, V);
+    method @Nullable public V remove(@Nullable Object);
+    method public default boolean remove(@Nullable Object, @Nullable Object);
+    method public default boolean replace(K, @Nullable V, V);
+    method @Nullable public default V replace(K, V);
+    method public default void replaceAll(@NonNull java.util.function.BiFunction<? super K,? super V,? extends V>);
+    method public int size();
+    method @NonNull public java.util.Collection<V> values();
   }
 
-  public static abstract interface Map.Entry<K, V> {
-    method public static <K extends java.lang.Comparable<? super K>, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey();
-    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByKey(java.util.Comparator<? super K>);
-    method public static <K, V extends java.lang.Comparable<? super V>> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue();
-    method public static <K, V> java.util.Comparator<java.util.Map.Entry<K, V>> comparingByValue(java.util.Comparator<? super V>);
-    method public abstract boolean equals(java.lang.Object);
-    method public abstract K getKey();
-    method public abstract V getValue();
-    method public abstract int hashCode();
-    method public abstract V setValue(V);
+  public static interface Map.Entry<K, V> {
+    method @NonNull public static <K extends java.lang.Comparable<? super K>, V> java.util.Comparator<java.util.Map.Entry<K,V>> comparingByKey();
+    method @NonNull public static <K, V> java.util.Comparator<java.util.Map.Entry<K,V>> comparingByKey(@NonNull java.util.Comparator<? super K>);
+    method @NonNull public static <K, V extends java.lang.Comparable<? super V>> java.util.Comparator<java.util.Map.Entry<K,V>> comparingByValue();
+    method @NonNull public static <K, V> java.util.Comparator<java.util.Map.Entry<K,V>> comparingByValue(@NonNull java.util.Comparator<? super V>);
+    method public boolean equals(@Nullable Object);
+    method public K getKey();
+    method public V getValue();
+    method public int hashCode();
+    method public V setValue(V);
   }
 
   public class MissingFormatArgumentException extends java.util.IllegalFormatException {
-    ctor public MissingFormatArgumentException(java.lang.String);
-    method public java.lang.String getFormatSpecifier();
+    ctor public MissingFormatArgumentException(String);
+    method public String getFormatSpecifier();
   }
 
   public class MissingFormatWidthException extends java.util.IllegalFormatException {
-    ctor public MissingFormatWidthException(java.lang.String);
-    method public java.lang.String getFormatSpecifier();
+    ctor public MissingFormatWidthException(String);
+    method public String getFormatSpecifier();
   }
 
   public class MissingResourceException extends java.lang.RuntimeException {
-    ctor public MissingResourceException(java.lang.String, java.lang.String, java.lang.String);
-    method public java.lang.String getClassName();
-    method public java.lang.String getKey();
+    ctor public MissingResourceException(String, String, String);
+    method public String getClassName();
+    method public String getKey();
   }
 
-  public abstract interface NavigableMap<K, V> implements java.util.SortedMap {
-    method public abstract java.util.Map.Entry<K, V> ceilingEntry(K);
-    method public abstract K ceilingKey(K);
-    method public abstract java.util.NavigableSet<K> descendingKeySet();
-    method public abstract java.util.NavigableMap<K, V> descendingMap();
-    method public abstract java.util.Map.Entry<K, V> firstEntry();
-    method public abstract java.util.Map.Entry<K, V> floorEntry(K);
-    method public abstract K floorKey(K);
-    method public abstract java.util.NavigableMap<K, V> headMap(K, boolean);
-    method public abstract java.util.Map.Entry<K, V> higherEntry(K);
-    method public abstract K higherKey(K);
-    method public abstract java.util.Map.Entry<K, V> lastEntry();
-    method public abstract java.util.Map.Entry<K, V> lowerEntry(K);
-    method public abstract K lowerKey(K);
-    method public abstract java.util.NavigableSet<K> navigableKeySet();
-    method public abstract java.util.Map.Entry<K, V> pollFirstEntry();
-    method public abstract java.util.Map.Entry<K, V> pollLastEntry();
-    method public abstract java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean);
-    method public abstract java.util.NavigableMap<K, V> tailMap(K, boolean);
+  public interface NavigableMap<K, V> extends java.util.SortedMap<K,V> {
+    method @Nullable public java.util.Map.Entry<K,V> ceilingEntry(K);
+    method @Nullable public K ceilingKey(K);
+    method @NonNull public java.util.NavigableSet<K> descendingKeySet();
+    method @NonNull public java.util.NavigableMap<K,V> descendingMap();
+    method @Nullable public java.util.Map.Entry<K,V> firstEntry();
+    method @Nullable public java.util.Map.Entry<K,V> floorEntry(K);
+    method @Nullable public K floorKey(K);
+    method @NonNull public java.util.NavigableMap<K,V> headMap(K, boolean);
+    method @Nullable public java.util.Map.Entry<K,V> higherEntry(K);
+    method @Nullable public K higherKey(K);
+    method @Nullable public java.util.Map.Entry<K,V> lastEntry();
+    method @Nullable public java.util.Map.Entry<K,V> lowerEntry(K);
+    method @Nullable public K lowerKey(K);
+    method @NonNull public java.util.NavigableSet<K> navigableKeySet();
+    method @Nullable public java.util.Map.Entry<K,V> pollFirstEntry();
+    method @Nullable public java.util.Map.Entry<K,V> pollLastEntry();
+    method @NonNull public java.util.NavigableMap<K,V> subMap(K, boolean, K, boolean);
+    method @NonNull public java.util.NavigableMap<K,V> tailMap(K, boolean);
   }
 
-  public abstract interface NavigableSet<E> implements java.util.SortedSet {
-    method public abstract E ceiling(E);
-    method public abstract java.util.Iterator<E> descendingIterator();
-    method public abstract java.util.NavigableSet<E> descendingSet();
-    method public abstract E floor(E);
-    method public abstract java.util.NavigableSet<E> headSet(E, boolean);
-    method public abstract E higher(E);
-    method public abstract E lower(E);
-    method public abstract E pollFirst();
-    method public abstract E pollLast();
-    method public abstract java.util.NavigableSet<E> subSet(E, boolean, E, boolean);
-    method public abstract java.util.NavigableSet<E> tailSet(E, boolean);
+  public interface NavigableSet<E> extends java.util.SortedSet<E> {
+    method public E ceiling(E);
+    method public java.util.Iterator<E> descendingIterator();
+    method public java.util.NavigableSet<E> descendingSet();
+    method public E floor(E);
+    method public java.util.NavigableSet<E> headSet(E, boolean);
+    method public E higher(E);
+    method public E lower(E);
+    method public E pollFirst();
+    method public E pollLast();
+    method public java.util.NavigableSet<E> subSet(E, boolean, E, boolean);
+    method public java.util.NavigableSet<E> tailSet(E, boolean);
   }
 
   public class NoSuchElementException extends java.lang.RuntimeException {
     ctor public NoSuchElementException();
-    ctor public NoSuchElementException(java.lang.String);
+    ctor public NoSuchElementException(String);
   }
 
   public final class Objects {
-    method public static <T> int compare(T, T, java.util.Comparator<? super T>);
-    method public static boolean deepEquals(java.lang.Object, java.lang.Object);
-    method public static boolean equals(java.lang.Object, java.lang.Object);
+    method public static <T> int compare(T, T, @NonNull java.util.Comparator<? super T>);
+    method public static boolean deepEquals(@Nullable Object, @Nullable Object);
+    method public static boolean equals(@Nullable Object, @Nullable Object);
     method public static int hash(java.lang.Object...);
-    method public static int hashCode(java.lang.Object);
-    method public static boolean isNull(java.lang.Object);
-    method public static boolean nonNull(java.lang.Object);
-    method public static <T> T requireNonNull(T);
-    method public static <T> T requireNonNull(T, java.lang.String);
-    method public static <T> T requireNonNull(T, java.util.function.Supplier<java.lang.String>);
-    method public static java.lang.String toString(java.lang.Object);
-    method public static java.lang.String toString(java.lang.Object, java.lang.String);
+    method public static int hashCode(@Nullable Object);
+    method public static boolean isNull(@Nullable Object);
+    method public static boolean nonNull(@Nullable Object);
+    method @NonNull public static <T> T requireNonNull(@Nullable T);
+    method @NonNull public static <T> T requireNonNull(@Nullable T, @NonNull String);
+    method @NonNull public static <T> T requireNonNull(@Nullable T, @NonNull java.util.function.Supplier<java.lang.String>);
+    method @NonNull public static String toString(@Nullable Object);
+    method @NonNull public static String toString(@Nullable Object, @NonNull String);
   }
 
   public class Observable {
     ctor public Observable();
-    method public synchronized void addObserver(java.util.Observer);
-    method protected synchronized void clearChanged();
-    method public synchronized int countObservers();
-    method public synchronized void deleteObserver(java.util.Observer);
-    method public synchronized void deleteObservers();
-    method public synchronized boolean hasChanged();
+    method public void addObserver(java.util.Observer);
+    method protected void clearChanged();
+    method public int countObservers();
+    method public void deleteObserver(java.util.Observer);
+    method public void deleteObservers();
+    method public boolean hasChanged();
     method public void notifyObservers();
-    method public void notifyObservers(java.lang.Object);
-    method protected synchronized void setChanged();
+    method public void notifyObservers(Object);
+    method protected void setChanged();
   }
 
-  public abstract interface Observer {
-    method public abstract void update(java.util.Observable, java.lang.Object);
+  public interface Observer {
+    method public void update(java.util.Observable, Object);
   }
 
   public final class Optional<T> {
     method public static <T> java.util.Optional<T> empty();
     method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
-    method public <U> java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
+    method public <U> java.util.Optional<U> flatMap(java.util.function.Function<? super T,java.util.Optional<U>>);
     method public T get();
     method public void ifPresent(java.util.function.Consumer<? super T>);
     method public boolean isPresent();
-    method public <U> java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
+    method public <U> java.util.Optional<U> map(java.util.function.Function<? super T,? extends U>);
     method public static <T> java.util.Optional<T> of(T);
     method public static <T> java.util.Optional<T> ofNullable(T);
     method public T orElse(T);
     method public T orElseGet(java.util.function.Supplier<? extends T>);
-    method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws X;
   }
 
   public final class OptionalDouble {
@@ -69661,7 +69979,7 @@
     method public static java.util.OptionalDouble of(double);
     method public double orElse(double);
     method public double orElseGet(java.util.function.DoubleSupplier);
-    method public <X extends java.lang.Throwable> double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> double orElseThrow(java.util.function.Supplier<X>) throws X;
   }
 
   public final class OptionalInt {
@@ -69672,7 +69990,7 @@
     method public static java.util.OptionalInt of(int);
     method public int orElse(int);
     method public int orElseGet(java.util.function.IntSupplier);
-    method public <X extends java.lang.Throwable> int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> int orElseThrow(java.util.function.Supplier<X>) throws X;
   }
 
   public final class OptionalLong {
@@ -69683,35 +70001,35 @@
     method public static java.util.OptionalLong of(long);
     method public long orElse(long);
     method public long orElseGet(java.util.function.LongSupplier);
-    method public <X extends java.lang.Throwable> long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+    method public <X extends java.lang.Throwable> long orElseThrow(java.util.function.Supplier<X>) throws X;
   }
 
-  public abstract interface PrimitiveIterator<T, T_CONS> implements java.util.Iterator {
-    method public abstract void forEachRemaining(T_CONS);
+  public interface PrimitiveIterator<T, T_CONS> extends java.util.Iterator<T> {
+    method public void forEachRemaining(T_CONS);
   }
 
-  public static abstract interface PrimitiveIterator.OfDouble implements java.util.PrimitiveIterator {
+  public static interface PrimitiveIterator.OfDouble extends java.util.PrimitiveIterator<java.lang.Double,java.util.function.DoubleConsumer> {
     method public default void forEachRemaining(java.util.function.DoubleConsumer);
     method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
-    method public default java.lang.Double next();
-    method public abstract double nextDouble();
+    method public default Double next();
+    method public double nextDouble();
   }
 
-  public static abstract interface PrimitiveIterator.OfInt implements java.util.PrimitiveIterator {
+  public static interface PrimitiveIterator.OfInt extends java.util.PrimitiveIterator<java.lang.Integer,java.util.function.IntConsumer> {
     method public default void forEachRemaining(java.util.function.IntConsumer);
     method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
-    method public default java.lang.Integer next();
-    method public abstract int nextInt();
+    method public default Integer next();
+    method public int nextInt();
   }
 
-  public static abstract interface PrimitiveIterator.OfLong implements java.util.PrimitiveIterator {
+  public static interface PrimitiveIterator.OfLong extends java.util.PrimitiveIterator<java.lang.Long,java.util.function.LongConsumer> {
     method public default void forEachRemaining(java.util.function.LongConsumer);
     method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
-    method public default java.lang.Long next();
-    method public abstract long nextLong();
+    method public default Long next();
+    method public long nextLong();
   }
 
-  public class PriorityQueue<E> extends java.util.AbstractQueue implements java.io.Serializable {
+  public class PriorityQueue<E> extends java.util.AbstractQueue<E> implements java.io.Serializable {
     ctor public PriorityQueue();
     ctor public PriorityQueue(int);
     ctor public PriorityQueue(java.util.Comparator<? super E>);
@@ -69728,44 +70046,44 @@
     method public final java.util.Spliterator<E> spliterator();
   }
 
-  public class Properties extends java.util.Hashtable {
+  public class Properties extends java.util.Hashtable<java.lang.Object,java.lang.Object> {
     ctor public Properties();
     ctor public Properties(java.util.Properties);
-    method public java.lang.String getProperty(java.lang.String);
-    method public java.lang.String getProperty(java.lang.String, java.lang.String);
+    method public String getProperty(String);
+    method public String getProperty(String, String);
     method public void list(java.io.PrintStream);
     method public void list(java.io.PrintWriter);
-    method public synchronized void load(java.io.Reader) throws java.io.IOException;
-    method public synchronized void load(java.io.InputStream) throws java.io.IOException;
-    method public synchronized void loadFromXML(java.io.InputStream) throws java.io.IOException, java.util.InvalidPropertiesFormatException;
+    method public void load(java.io.Reader) throws java.io.IOException;
+    method public void load(java.io.InputStream) throws java.io.IOException;
+    method public void loadFromXML(java.io.InputStream) throws java.io.IOException, java.util.InvalidPropertiesFormatException;
     method public java.util.Enumeration<?> propertyNames();
-    method public deprecated void save(java.io.OutputStream, java.lang.String);
-    method public synchronized java.lang.Object setProperty(java.lang.String, java.lang.String);
-    method public void store(java.io.Writer, java.lang.String) throws java.io.IOException;
-    method public void store(java.io.OutputStream, java.lang.String) throws java.io.IOException;
-    method public void storeToXML(java.io.OutputStream, java.lang.String) throws java.io.IOException;
-    method public void storeToXML(java.io.OutputStream, java.lang.String, java.lang.String) throws java.io.IOException;
+    method @Deprecated public void save(java.io.OutputStream, String);
+    method public Object setProperty(String, String);
+    method public void store(java.io.Writer, String) throws java.io.IOException;
+    method public void store(java.io.OutputStream, String) throws java.io.IOException;
+    method public void storeToXML(java.io.OutputStream, String) throws java.io.IOException;
+    method public void storeToXML(java.io.OutputStream, String, String) throws java.io.IOException;
     method public java.util.Set<java.lang.String> stringPropertyNames();
     field protected java.util.Properties defaults;
   }
 
   public final class PropertyPermission extends java.security.BasicPermission {
-    ctor public PropertyPermission(java.lang.String, java.lang.String);
+    ctor public PropertyPermission(String, String);
   }
 
   public class PropertyResourceBundle extends java.util.ResourceBundle {
     ctor public PropertyResourceBundle(java.io.InputStream) throws java.io.IOException;
     ctor public PropertyResourceBundle(java.io.Reader) throws java.io.IOException;
     method public java.util.Enumeration<java.lang.String> getKeys();
-    method public java.lang.Object handleGetObject(java.lang.String);
+    method public Object handleGetObject(String);
   }
 
-  public abstract interface Queue<E> implements java.util.Collection {
-    method public abstract E element();
-    method public abstract boolean offer(E);
-    method public abstract E peek();
-    method public abstract E poll();
-    method public abstract E remove();
+  public interface Queue<E> extends java.util.Collection<E> {
+    method public E element();
+    method public boolean offer(E);
+    method @Nullable public E peek();
+    method @Nullable public E poll();
+    method public E remove();
   }
 
   public class Random implements java.io.Serializable {
@@ -69788,34 +70106,34 @@
     method public void nextBytes(byte[]);
     method public double nextDouble();
     method public float nextFloat();
-    method public synchronized double nextGaussian();
+    method public double nextGaussian();
     method public int nextInt();
     method public int nextInt(int);
     method public long nextLong();
-    method public synchronized void setSeed(long);
+    method public void setSeed(long);
   }
 
-  public abstract interface RandomAccess {
+  public interface RandomAccess {
   }
 
   public abstract class ResourceBundle {
     ctor public ResourceBundle();
     method public static final void clearCache();
-    method public static final void clearCache(java.lang.ClassLoader);
-    method public boolean containsKey(java.lang.String);
-    method public java.lang.String getBaseBundleName();
-    method public static final java.util.ResourceBundle getBundle(java.lang.String);
-    method public static final java.util.ResourceBundle getBundle(java.lang.String, java.util.ResourceBundle.Control);
-    method public static final java.util.ResourceBundle getBundle(java.lang.String, java.util.Locale);
-    method public static final java.util.ResourceBundle getBundle(java.lang.String, java.util.Locale, java.util.ResourceBundle.Control);
-    method public static java.util.ResourceBundle getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader);
-    method public static java.util.ResourceBundle getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader, java.util.ResourceBundle.Control);
+    method public static final void clearCache(ClassLoader);
+    method public boolean containsKey(String);
+    method public String getBaseBundleName();
+    method public static final java.util.ResourceBundle getBundle(String);
+    method public static final java.util.ResourceBundle getBundle(String, java.util.ResourceBundle.Control);
+    method public static final java.util.ResourceBundle getBundle(String, java.util.Locale);
+    method public static final java.util.ResourceBundle getBundle(String, java.util.Locale, java.util.ResourceBundle.Control);
+    method public static java.util.ResourceBundle getBundle(String, java.util.Locale, ClassLoader);
+    method public static java.util.ResourceBundle getBundle(String, java.util.Locale, ClassLoader, java.util.ResourceBundle.Control);
     method public abstract java.util.Enumeration<java.lang.String> getKeys();
     method public java.util.Locale getLocale();
-    method public final java.lang.Object getObject(java.lang.String);
-    method public final java.lang.String getString(java.lang.String);
-    method public final java.lang.String[] getStringArray(java.lang.String);
-    method protected abstract java.lang.Object handleGetObject(java.lang.String);
+    method public final Object getObject(String);
+    method public final String getString(String);
+    method public final String[] getStringArray(String);
+    method protected abstract Object handleGetObject(String);
     method protected java.util.Set<java.lang.String> handleKeySet();
     method public java.util.Set<java.lang.String> keySet();
     method protected void setParent(java.util.ResourceBundle);
@@ -69824,16 +70142,16 @@
 
   public static class ResourceBundle.Control {
     ctor protected ResourceBundle.Control();
-    method public java.util.List<java.util.Locale> getCandidateLocales(java.lang.String, java.util.Locale);
+    method public java.util.List<java.util.Locale> getCandidateLocales(String, java.util.Locale);
     method public static final java.util.ResourceBundle.Control getControl(java.util.List<java.lang.String>);
-    method public java.util.Locale getFallbackLocale(java.lang.String, java.util.Locale);
-    method public java.util.List<java.lang.String> getFormats(java.lang.String);
+    method public java.util.Locale getFallbackLocale(String, java.util.Locale);
+    method public java.util.List<java.lang.String> getFormats(String);
     method public static final java.util.ResourceBundle.Control getNoFallbackControl(java.util.List<java.lang.String>);
-    method public long getTimeToLive(java.lang.String, java.util.Locale);
-    method public boolean needsReload(java.lang.String, java.util.Locale, java.lang.String, java.lang.ClassLoader, java.util.ResourceBundle, long);
-    method public java.util.ResourceBundle newBundle(java.lang.String, java.util.Locale, java.lang.String, java.lang.ClassLoader, boolean) throws java.io.IOException, java.lang.IllegalAccessException, java.lang.InstantiationException;
-    method public java.lang.String toBundleName(java.lang.String, java.util.Locale);
-    method public final java.lang.String toResourceName(java.lang.String, java.lang.String);
+    method public long getTimeToLive(String, java.util.Locale);
+    method public boolean needsReload(String, java.util.Locale, String, ClassLoader, java.util.ResourceBundle, long);
+    method public java.util.ResourceBundle newBundle(String, java.util.Locale, String, ClassLoader, boolean) throws java.io.IOException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public String toBundleName(String, java.util.Locale);
+    method public final String toResourceName(String, String);
     field public static final java.util.List<java.lang.String> FORMAT_CLASS;
     field public static final java.util.List<java.lang.String> FORMAT_DEFAULT;
     field public static final java.util.List<java.lang.String> FORMAT_PROPERTIES;
@@ -69841,25 +70159,25 @@
     field public static final long TTL_NO_EXPIRATION_CONTROL = -2L; // 0xfffffffffffffffeL
   }
 
-  public final class Scanner implements java.io.Closeable java.util.Iterator {
-    ctor public Scanner(java.lang.Readable);
+  public final class Scanner implements java.io.Closeable java.util.Iterator<java.lang.String> {
+    ctor public Scanner(Readable);
     ctor public Scanner(java.io.InputStream);
-    ctor public Scanner(java.io.InputStream, java.lang.String);
+    ctor public Scanner(java.io.InputStream, String);
     ctor public Scanner(java.io.File) throws java.io.FileNotFoundException;
-    ctor public Scanner(java.io.File, java.lang.String) throws java.io.FileNotFoundException;
+    ctor public Scanner(java.io.File, String) throws java.io.FileNotFoundException;
     ctor public Scanner(java.nio.file.Path) throws java.io.IOException;
-    ctor public Scanner(java.nio.file.Path, java.lang.String) throws java.io.IOException;
-    ctor public Scanner(java.lang.String);
+    ctor public Scanner(java.nio.file.Path, String) throws java.io.IOException;
+    ctor public Scanner(String);
     ctor public Scanner(java.nio.channels.ReadableByteChannel);
-    ctor public Scanner(java.nio.channels.ReadableByteChannel, java.lang.String);
+    ctor public Scanner(java.nio.channels.ReadableByteChannel, String);
     method public void close();
     method public java.util.regex.Pattern delimiter();
-    method public java.lang.String findInLine(java.lang.String);
-    method public java.lang.String findInLine(java.util.regex.Pattern);
-    method public java.lang.String findWithinHorizon(java.lang.String, int);
-    method public java.lang.String findWithinHorizon(java.util.regex.Pattern, int);
+    method public String findInLine(String);
+    method public String findInLine(java.util.regex.Pattern);
+    method public String findWithinHorizon(String, int);
+    method public String findWithinHorizon(java.util.regex.Pattern, int);
     method public boolean hasNext();
-    method public boolean hasNext(java.lang.String);
+    method public boolean hasNext(String);
     method public boolean hasNext(java.util.regex.Pattern);
     method public boolean hasNextBigDecimal();
     method public boolean hasNextBigInteger();
@@ -69879,9 +70197,9 @@
     method public java.io.IOException ioException();
     method public java.util.Locale locale();
     method public java.util.regex.MatchResult match();
-    method public java.lang.String next();
-    method public java.lang.String next(java.lang.String);
-    method public java.lang.String next(java.util.regex.Pattern);
+    method public String next();
+    method public String next(String);
+    method public String next(java.util.regex.Pattern);
     method public java.math.BigDecimal nextBigDecimal();
     method public java.math.BigInteger nextBigInteger();
     method public java.math.BigInteger nextBigInteger(int);
@@ -69892,7 +70210,7 @@
     method public float nextFloat();
     method public int nextInt();
     method public int nextInt(int);
-    method public java.lang.String nextLine();
+    method public String nextLine();
     method public long nextLong();
     method public long nextLong(int);
     method public short nextShort();
@@ -69900,37 +70218,36 @@
     method public int radix();
     method public java.util.Scanner reset();
     method public java.util.Scanner skip(java.util.regex.Pattern);
-    method public java.util.Scanner skip(java.lang.String);
+    method public java.util.Scanner skip(String);
     method public java.util.Scanner useDelimiter(java.util.regex.Pattern);
-    method public java.util.Scanner useDelimiter(java.lang.String);
+    method public java.util.Scanner useDelimiter(String);
     method public java.util.Scanner useLocale(java.util.Locale);
     method public java.util.Scanner useRadix(int);
   }
 
   public class ServiceConfigurationError extends java.lang.Error {
-    ctor public ServiceConfigurationError(java.lang.String);
-    ctor public ServiceConfigurationError(java.lang.String, java.lang.Throwable);
+    ctor public ServiceConfigurationError(String);
+    ctor public ServiceConfigurationError(String, Throwable);
   }
 
-  public final class ServiceLoader<S> implements java.lang.Iterable {
+  public final class ServiceLoader<S> implements java.lang.Iterable<S> {
     method public java.util.Iterator<S> iterator();
-    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>, java.lang.ClassLoader);
-    method public static <S> java.util.ServiceLoader<S> load(java.lang.Class<S>);
-    method public static <S> java.util.ServiceLoader<S> loadInstalled(java.lang.Class<S>);
+    method public static <S> java.util.ServiceLoader<S> load(Class<S>, ClassLoader);
+    method public static <S> java.util.ServiceLoader<S> load(Class<S>);
+    method public static <S> java.util.ServiceLoader<S> loadInstalled(Class<S>);
     method public void reload();
   }
 
-  public abstract interface Set<E> implements java.util.Collection {
+  public interface Set<E> extends java.util.Collection<E> {
   }
 
   public class SimpleTimeZone extends java.util.TimeZone {
-    ctor public SimpleTimeZone(int, java.lang.String);
-    ctor public SimpleTimeZone(int, java.lang.String, int, int, int, int, int, int, int, int);
-    ctor public SimpleTimeZone(int, java.lang.String, int, int, int, int, int, int, int, int, int);
-    ctor public SimpleTimeZone(int, java.lang.String, int, int, int, int, int, int, int, int, int, int, int);
+    ctor public SimpleTimeZone(int, String);
+    ctor public SimpleTimeZone(int, String, int, int, int, int, int, int, int, int);
+    ctor public SimpleTimeZone(int, String, int, int, int, int, int, int, int, int, int);
+    ctor public SimpleTimeZone(int, String, int, int, int, int, int, int, int, int, int, int, int);
     method public int getOffset(int, int, int, int, int, int);
     method public int getRawOffset();
-    method public synchronized int hashCode();
     method public boolean inDaylightTime(java.util.Date);
     method public void setDSTSavings(int);
     method public void setEndRule(int, int, int, int);
@@ -69947,33 +70264,33 @@
     field public static final int WALL_TIME = 0; // 0x0
   }
 
-  public abstract interface SortedMap<K, V> implements java.util.Map {
-    method public abstract java.util.Comparator<? super K> comparator();
-    method public abstract K firstKey();
-    method public abstract java.util.SortedMap<K, V> headMap(K);
-    method public abstract K lastKey();
-    method public abstract java.util.SortedMap<K, V> subMap(K, K);
-    method public abstract java.util.SortedMap<K, V> tailMap(K);
+  public interface SortedMap<K, V> extends java.util.Map<K,V> {
+    method @Nullable public java.util.Comparator<? super K> comparator();
+    method public K firstKey();
+    method @NonNull public java.util.SortedMap<K,V> headMap(K);
+    method public K lastKey();
+    method @NonNull public java.util.SortedMap<K,V> subMap(K, K);
+    method @NonNull public java.util.SortedMap<K,V> tailMap(K);
   }
 
-  public abstract interface SortedSet<E> implements java.util.Set {
-    method public abstract java.util.Comparator<? super E> comparator();
-    method public abstract E first();
-    method public abstract java.util.SortedSet<E> headSet(E);
-    method public abstract E last();
-    method public abstract java.util.SortedSet<E> subSet(E, E);
-    method public abstract java.util.SortedSet<E> tailSet(E);
+  public interface SortedSet<E> extends java.util.Set<E> {
+    method public java.util.Comparator<? super E> comparator();
+    method public E first();
+    method public java.util.SortedSet<E> headSet(E);
+    method public E last();
+    method public java.util.SortedSet<E> subSet(E, E);
+    method public java.util.SortedSet<E> tailSet(E);
   }
 
-  public abstract interface Spliterator<T> {
-    method public abstract int characteristics();
-    method public abstract long estimateSize();
+  public interface Spliterator<T> {
+    method public int characteristics();
+    method public long estimateSize();
     method public default void forEachRemaining(java.util.function.Consumer<? super T>);
     method public default java.util.Comparator<? super T> getComparator();
     method public default long getExactSizeIfKnown();
     method public default boolean hasCharacteristics(int);
-    method public abstract boolean tryAdvance(java.util.function.Consumer<? super T>);
-    method public abstract java.util.Spliterator<T> trySplit();
+    method public boolean tryAdvance(java.util.function.Consumer<? super T>);
+    method public java.util.Spliterator<T> trySplit();
     field public static final int CONCURRENT = 4096; // 0x1000
     field public static final int DISTINCT = 1; // 0x1
     field public static final int IMMUTABLE = 1024; // 0x400
@@ -69984,34 +70301,34 @@
     field public static final int SUBSIZED = 16384; // 0x4000
   }
 
-  public static abstract interface Spliterator.OfDouble implements java.util.Spliterator.OfPrimitive {
+  public static interface Spliterator.OfDouble extends java.util.Spliterator.OfPrimitive<java.lang.Double,java.util.function.DoubleConsumer,java.util.Spliterator.OfDouble> {
     method public default void forEachRemaining(java.util.function.DoubleConsumer);
     method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
-    method public abstract boolean tryAdvance(java.util.function.DoubleConsumer);
+    method public boolean tryAdvance(java.util.function.DoubleConsumer);
     method public default boolean tryAdvance(java.util.function.Consumer<? super java.lang.Double>);
-    method public abstract java.util.Spliterator.OfDouble trySplit();
+    method public java.util.Spliterator.OfDouble trySplit();
   }
 
-  public static abstract interface Spliterator.OfInt implements java.util.Spliterator.OfPrimitive {
+  public static interface Spliterator.OfInt extends java.util.Spliterator.OfPrimitive<java.lang.Integer,java.util.function.IntConsumer,java.util.Spliterator.OfInt> {
     method public default void forEachRemaining(java.util.function.IntConsumer);
     method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
-    method public abstract boolean tryAdvance(java.util.function.IntConsumer);
+    method public boolean tryAdvance(java.util.function.IntConsumer);
     method public default boolean tryAdvance(java.util.function.Consumer<? super java.lang.Integer>);
-    method public abstract java.util.Spliterator.OfInt trySplit();
+    method public java.util.Spliterator.OfInt trySplit();
   }
 
-  public static abstract interface Spliterator.OfLong implements java.util.Spliterator.OfPrimitive {
+  public static interface Spliterator.OfLong extends java.util.Spliterator.OfPrimitive<java.lang.Long,java.util.function.LongConsumer,java.util.Spliterator.OfLong> {
     method public default void forEachRemaining(java.util.function.LongConsumer);
     method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
-    method public abstract boolean tryAdvance(java.util.function.LongConsumer);
+    method public boolean tryAdvance(java.util.function.LongConsumer);
     method public default boolean tryAdvance(java.util.function.Consumer<? super java.lang.Long>);
-    method public abstract java.util.Spliterator.OfLong trySplit();
+    method public java.util.Spliterator.OfLong trySplit();
   }
 
-  public static abstract interface Spliterator.OfPrimitive<T, T_CONS, T_SPLITR extends java.util.Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> implements java.util.Spliterator {
+  public static interface Spliterator.OfPrimitive<T, T_CONS, T_SPLITR extends java.util.Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> extends java.util.Spliterator<T> {
     method public default void forEachRemaining(T_CONS);
-    method public abstract boolean tryAdvance(T_CONS);
-    method public abstract T_SPLITR trySplit();
+    method public boolean tryAdvance(T_CONS);
+    method public T_SPLITR trySplit();
   }
 
   public final class Spliterators {
@@ -70023,8 +70340,8 @@
     method public static java.util.PrimitiveIterator.OfInt iterator(java.util.Spliterator.OfInt);
     method public static java.util.PrimitiveIterator.OfLong iterator(java.util.Spliterator.OfLong);
     method public static java.util.PrimitiveIterator.OfDouble iterator(java.util.Spliterator.OfDouble);
-    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int);
-    method public static <T> java.util.Spliterator<T> spliterator(java.lang.Object[], int, int, int);
+    method public static <T> java.util.Spliterator<T> spliterator(Object[], int);
+    method public static <T> java.util.Spliterator<T> spliterator(Object[], int, int, int);
     method public static java.util.Spliterator.OfInt spliterator(int[], int);
     method public static java.util.Spliterator.OfInt spliterator(int[], int, int, int);
     method public static java.util.Spliterator.OfLong spliterator(long[], int);
@@ -70042,28 +70359,28 @@
     method public static java.util.Spliterator.OfDouble spliteratorUnknownSize(java.util.PrimitiveIterator.OfDouble, int);
   }
 
-  public static abstract class Spliterators.AbstractDoubleSpliterator implements java.util.Spliterator.OfDouble {
+  public abstract static class Spliterators.AbstractDoubleSpliterator implements java.util.Spliterator.OfDouble {
     ctor protected Spliterators.AbstractDoubleSpliterator(long, int);
     method public int characteristics();
     method public long estimateSize();
     method public java.util.Spliterator.OfDouble trySplit();
   }
 
-  public static abstract class Spliterators.AbstractIntSpliterator implements java.util.Spliterator.OfInt {
+  public abstract static class Spliterators.AbstractIntSpliterator implements java.util.Spliterator.OfInt {
     ctor protected Spliterators.AbstractIntSpliterator(long, int);
     method public int characteristics();
     method public long estimateSize();
     method public java.util.Spliterator.OfInt trySplit();
   }
 
-  public static abstract class Spliterators.AbstractLongSpliterator implements java.util.Spliterator.OfLong {
+  public abstract static class Spliterators.AbstractLongSpliterator implements java.util.Spliterator.OfLong {
     ctor protected Spliterators.AbstractLongSpliterator(long, int);
     method public int characteristics();
     method public long estimateSize();
     method public java.util.Spliterator.OfLong trySplit();
   }
 
-  public static abstract class Spliterators.AbstractSpliterator<T> implements java.util.Spliterator {
+  public abstract static class Spliterators.AbstractSpliterator<T> implements java.util.Spliterator<T> {
     ctor protected Spliterators.AbstractSpliterator(long, int);
     method public int characteristics();
     method public long estimateSize();
@@ -70098,58 +70415,58 @@
     method public java.util.SplittableRandom split();
   }
 
-  public class Stack<E> extends java.util.Vector {
+  public class Stack<E> extends java.util.Vector<E> {
     ctor public Stack();
     method public boolean empty();
-    method public synchronized E peek();
-    method public synchronized E pop();
+    method public E peek();
+    method public E pop();
     method public E push(E);
-    method public synchronized int search(java.lang.Object);
+    method public int search(Object);
   }
 
   public final class StringJoiner {
-    ctor public StringJoiner(java.lang.CharSequence);
-    ctor public StringJoiner(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
-    method public java.util.StringJoiner add(java.lang.CharSequence);
+    ctor public StringJoiner(CharSequence);
+    ctor public StringJoiner(CharSequence, CharSequence, CharSequence);
+    method public java.util.StringJoiner add(CharSequence);
     method public int length();
     method public java.util.StringJoiner merge(java.util.StringJoiner);
-    method public java.util.StringJoiner setEmptyValue(java.lang.CharSequence);
+    method public java.util.StringJoiner setEmptyValue(CharSequence);
   }
 
-  public class StringTokenizer implements java.util.Enumeration {
-    ctor public StringTokenizer(java.lang.String, java.lang.String, boolean);
-    ctor public StringTokenizer(java.lang.String, java.lang.String);
-    ctor public StringTokenizer(java.lang.String);
+  public class StringTokenizer implements java.util.Enumeration<java.lang.Object> {
+    ctor public StringTokenizer(String, String, boolean);
+    ctor public StringTokenizer(String, String);
+    ctor public StringTokenizer(String);
     method public int countTokens();
     method public boolean hasMoreElements();
     method public boolean hasMoreTokens();
-    method public java.lang.Object nextElement();
-    method public java.lang.String nextToken();
-    method public java.lang.String nextToken(java.lang.String);
+    method public Object nextElement();
+    method public String nextToken();
+    method public String nextToken(String);
   }
 
   public abstract class TimeZone implements java.lang.Cloneable java.io.Serializable {
     ctor public TimeZone();
-    method public java.lang.Object clone();
-    method public static synchronized java.lang.String[] getAvailableIDs(int);
-    method public static synchronized java.lang.String[] getAvailableIDs();
+    method public Object clone();
+    method public static String[] getAvailableIDs(int);
+    method public static String[] getAvailableIDs();
     method public int getDSTSavings();
     method public static java.util.TimeZone getDefault();
-    method public final java.lang.String getDisplayName();
-    method public final java.lang.String getDisplayName(java.util.Locale);
-    method public final java.lang.String getDisplayName(boolean, int);
-    method public java.lang.String getDisplayName(boolean, int, java.util.Locale);
-    method public java.lang.String getID();
+    method public final String getDisplayName();
+    method public final String getDisplayName(java.util.Locale);
+    method public final String getDisplayName(boolean, int);
+    method public String getDisplayName(boolean, int, java.util.Locale);
+    method public String getID();
     method public abstract int getOffset(int, int, int, int, int, int);
     method public int getOffset(long);
     method public abstract int getRawOffset();
-    method public static synchronized java.util.TimeZone getTimeZone(java.lang.String);
+    method public static java.util.TimeZone getTimeZone(String);
     method public static java.util.TimeZone getTimeZone(java.time.ZoneId);
     method public boolean hasSameRules(java.util.TimeZone);
     method public abstract boolean inDaylightTime(java.util.Date);
     method public boolean observesDaylightTime();
-    method public static synchronized void setDefault(java.util.TimeZone);
-    method public void setID(java.lang.String);
+    method public static void setDefault(java.util.TimeZone);
+    method public void setID(String);
     method public abstract void setRawOffset(int);
     method public java.time.ZoneId toZoneId();
     method public abstract boolean useDaylightTime();
@@ -70160,8 +70477,8 @@
   public class Timer {
     ctor public Timer();
     ctor public Timer(boolean);
-    ctor public Timer(java.lang.String);
-    ctor public Timer(java.lang.String, boolean);
+    ctor public Timer(String);
+    ctor public Timer(String, boolean);
     method public void cancel();
     method public int purge();
     method public void schedule(java.util.TimerTask, long);
@@ -70180,49 +70497,49 @@
 
   public class TooManyListenersException extends java.lang.Exception {
     ctor public TooManyListenersException();
-    ctor public TooManyListenersException(java.lang.String);
+    ctor public TooManyListenersException(String);
   }
 
-  public class TreeMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.NavigableMap java.io.Serializable {
+  public class TreeMap<K, V> extends java.util.AbstractMap<K,V> implements java.lang.Cloneable java.util.NavigableMap<K,V> java.io.Serializable {
     ctor public TreeMap();
-    ctor public TreeMap(java.util.Comparator<? super K>);
-    ctor public TreeMap(java.util.Map<? extends K, ? extends V>);
-    ctor public TreeMap(java.util.SortedMap<K, ? extends V>);
-    method public java.util.Map.Entry<K, V> ceilingEntry(K);
-    method public K ceilingKey(K);
-    method public java.lang.Object clone();
-    method public java.util.Comparator<? super K> comparator();
-    method public java.util.NavigableSet<K> descendingKeySet();
-    method public java.util.NavigableMap<K, V> descendingMap();
-    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
-    method public java.util.Map.Entry<K, V> firstEntry();
+    ctor public TreeMap(@Nullable java.util.Comparator<? super K>);
+    ctor public TreeMap(@NonNull java.util.Map<? extends K,? extends V>);
+    ctor public TreeMap(@NonNull java.util.SortedMap<K,? extends V>);
+    method @Nullable public java.util.Map.Entry<K,V> ceilingEntry(K);
+    method @Nullable public K ceilingKey(K);
+    method @NonNull public Object clone();
+    method @Nullable public java.util.Comparator<? super K> comparator();
+    method @NonNull public java.util.NavigableSet<K> descendingKeySet();
+    method @NonNull public java.util.NavigableMap<K,V> descendingMap();
+    method @NonNull public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
+    method @Nullable public java.util.Map.Entry<K,V> firstEntry();
     method public K firstKey();
-    method public java.util.Map.Entry<K, V> floorEntry(K);
-    method public K floorKey(K);
-    method public java.util.NavigableMap<K, V> headMap(K, boolean);
-    method public java.util.SortedMap<K, V> headMap(K);
-    method public java.util.Map.Entry<K, V> higherEntry(K);
-    method public K higherKey(K);
-    method public java.util.Map.Entry<K, V> lastEntry();
+    method @Nullable public java.util.Map.Entry<K,V> floorEntry(K);
+    method @Nullable public K floorKey(K);
+    method @NonNull public java.util.NavigableMap<K,V> headMap(K, boolean);
+    method @NonNull public java.util.SortedMap<K,V> headMap(K);
+    method @Nullable public java.util.Map.Entry<K,V> higherEntry(K);
+    method @Nullable public K higherKey(K);
+    method @Nullable public java.util.Map.Entry<K,V> lastEntry();
     method public K lastKey();
-    method public java.util.Map.Entry<K, V> lowerEntry(K);
-    method public K lowerKey(K);
-    method public java.util.NavigableSet<K> navigableKeySet();
-    method public java.util.Map.Entry<K, V> pollFirstEntry();
-    method public java.util.Map.Entry<K, V> pollLastEntry();
-    method public java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean);
-    method public java.util.SortedMap<K, V> subMap(K, K);
-    method public java.util.NavigableMap<K, V> tailMap(K, boolean);
-    method public java.util.SortedMap<K, V> tailMap(K);
+    method @Nullable public java.util.Map.Entry<K,V> lowerEntry(K);
+    method @Nullable public K lowerKey(K);
+    method @NonNull public java.util.NavigableSet<K> navigableKeySet();
+    method @Nullable public java.util.Map.Entry<K,V> pollFirstEntry();
+    method @Nullable public java.util.Map.Entry<K,V> pollLastEntry();
+    method @NonNull public java.util.NavigableMap<K,V> subMap(K, boolean, K, boolean);
+    method @NonNull public java.util.SortedMap<K,V> subMap(K, K);
+    method @NonNull public java.util.NavigableMap<K,V> tailMap(K, boolean);
+    method @NonNull public java.util.SortedMap<K,V> tailMap(K);
   }
 
-  public class TreeSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
+  public class TreeSet<E> extends java.util.AbstractSet<E> implements java.lang.Cloneable java.util.NavigableSet<E> java.io.Serializable {
     ctor public TreeSet();
     ctor public TreeSet(java.util.Comparator<? super E>);
     ctor public TreeSet(java.util.Collection<? extends E>);
     ctor public TreeSet(java.util.SortedSet<E>);
     method public E ceiling(E);
-    method public java.lang.Object clone();
+    method public Object clone();
     method public java.util.Comparator<? super E> comparator();
     method public java.util.Iterator<E> descendingIterator();
     method public java.util.NavigableSet<E> descendingSet();
@@ -70243,11 +70560,11 @@
     method public java.util.SortedSet<E> tailSet(E);
   }
 
-  public final class UUID implements java.lang.Comparable java.io.Serializable {
+  public final class UUID implements java.lang.Comparable<java.util.UUID> java.io.Serializable {
     ctor public UUID(long, long);
     method public int clockSequence();
     method public int compareTo(java.util.UUID);
-    method public static java.util.UUID fromString(java.lang.String);
+    method public static java.util.UUID fromString(String);
     method public long getLeastSignificantBits();
     method public long getMostSignificantBits();
     method public static java.util.UUID nameUUIDFromBytes(byte[]);
@@ -70259,75 +70576,52 @@
   }
 
   public class UnknownFormatConversionException extends java.util.IllegalFormatException {
-    ctor public UnknownFormatConversionException(java.lang.String);
-    method public java.lang.String getConversion();
+    ctor public UnknownFormatConversionException(String);
+    method public String getConversion();
   }
 
   public class UnknownFormatFlagsException extends java.util.IllegalFormatException {
-    ctor public UnknownFormatFlagsException(java.lang.String);
-    method public java.lang.String getFlags();
+    ctor public UnknownFormatFlagsException(String);
+    method public String getFlags();
   }
 
-  public class Vector<E> extends java.util.AbstractList implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
+  public class Vector<E> extends java.util.AbstractList<E> implements java.lang.Cloneable java.util.List<E> java.util.RandomAccess java.io.Serializable {
     ctor public Vector(int, int);
     ctor public Vector(int);
     ctor public Vector();
-    ctor public Vector(java.util.Collection<? extends E>);
-    method public synchronized boolean add(E);
-    method public synchronized boolean addAll(java.util.Collection<? extends E>);
-    method public synchronized boolean addAll(int, java.util.Collection<? extends E>);
-    method public synchronized void addElement(E);
-    method public synchronized int capacity();
-    method public synchronized java.lang.Object clone();
-    method public synchronized boolean containsAll(java.util.Collection<?>);
-    method public synchronized void copyInto(java.lang.Object[]);
-    method public synchronized E elementAt(int);
-    method public java.util.Enumeration<E> elements();
-    method public synchronized void ensureCapacity(int);
-    method public synchronized boolean equals(java.lang.Object);
-    method public synchronized E firstElement();
-    method public synchronized void forEach(java.util.function.Consumer<? super E>);
-    method public synchronized E get(int);
-    method public synchronized int hashCode();
-    method public synchronized int indexOf(java.lang.Object, int);
-    method public synchronized void insertElementAt(E, int);
-    method public synchronized boolean isEmpty();
-    method public synchronized java.util.Iterator<E> iterator();
-    method public synchronized E lastElement();
-    method public synchronized int lastIndexOf(java.lang.Object);
-    method public synchronized int lastIndexOf(java.lang.Object, int);
-    method public synchronized java.util.ListIterator<E> listIterator(int);
-    method public synchronized java.util.ListIterator<E> listIterator();
-    method public synchronized E remove(int);
-    method public synchronized boolean removeAll(java.util.Collection<?>);
-    method public synchronized void removeAllElements();
-    method public synchronized boolean removeElement(java.lang.Object);
-    method public synchronized void removeElementAt(int);
-    method public synchronized boolean removeIf(java.util.function.Predicate<? super E>);
-    method protected synchronized void removeRange(int, int);
-    method public synchronized void replaceAll(java.util.function.UnaryOperator<E>);
-    method public synchronized boolean retainAll(java.util.Collection<?>);
-    method public synchronized E set(int, E);
-    method public synchronized void setElementAt(E, int);
-    method public synchronized void setSize(int);
-    method public synchronized int size();
-    method public synchronized void sort(java.util.Comparator<? super E>);
-    method public synchronized java.util.List<E> subList(int, int);
-    method public synchronized java.lang.Object[] toArray();
-    method public synchronized <T> T[] toArray(T[]);
-    method public synchronized java.lang.String toString();
-    method public synchronized void trimToSize();
+    ctor public Vector(@NonNull java.util.Collection<? extends E>);
+    method public void addElement(E);
+    method public int capacity();
+    method @NonNull public Object clone();
+    method public void copyInto(Object[]);
+    method public E elementAt(int);
+    method @NonNull public java.util.Enumeration<E> elements();
+    method public void ensureCapacity(int);
+    method public E firstElement();
+    method public void forEach(@NonNull java.util.function.Consumer<? super E>);
+    method public E get(int);
+    method public int indexOf(@Nullable Object, int);
+    method public void insertElementAt(E, int);
+    method public E lastElement();
+    method public int lastIndexOf(@Nullable Object, int);
+    method public void removeAllElements();
+    method public boolean removeElement(@Nullable Object);
+    method public void removeElementAt(int);
+    method public void setElementAt(E, int);
+    method public void setSize(int);
+    method public int size();
+    method public void trimToSize();
     field protected int capacityIncrement;
     field protected int elementCount;
-    field protected java.lang.Object[] elementData;
+    field protected Object[] elementData;
   }
 
-  public class WeakHashMap<K, V> extends java.util.AbstractMap implements java.util.Map {
+  public class WeakHashMap<K, V> extends java.util.AbstractMap<K,V> implements java.util.Map<K,V> {
     ctor public WeakHashMap(int, float);
     ctor public WeakHashMap(int);
     ctor public WeakHashMap();
-    ctor public WeakHashMap(java.util.Map<? extends K, ? extends V>);
-    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    ctor public WeakHashMap(@NonNull java.util.Map<? extends K,? extends V>);
+    method @NonNull public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
   }
 
 }
@@ -70340,14 +70634,14 @@
     method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
     method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
     method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
-    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.lang.Runnable, T);
+    method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(Runnable, T);
     method protected <T> java.util.concurrent.RunnableFuture<T> newTaskFor(java.util.concurrent.Callable<T>);
-    method public java.util.concurrent.Future<?> submit(java.lang.Runnable);
-    method public <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
+    method public java.util.concurrent.Future<?> submit(Runnable);
+    method public <T> java.util.concurrent.Future<T> submit(Runnable, T);
     method public <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
   }
 
-  public class ArrayBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class ArrayBlockingQueue<E> extends java.util.AbstractQueue<E> implements java.util.concurrent.BlockingQueue<E> java.io.Serializable {
     ctor public ArrayBlockingQueue(int);
     ctor public ArrayBlockingQueue(int, boolean);
     ctor public ArrayBlockingQueue(int, boolean, java.util.Collection<? extends E>);
@@ -70365,221 +70659,231 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
-  public abstract interface BlockingDeque<E> implements java.util.concurrent.BlockingQueue java.util.Deque {
-    method public abstract boolean offerFirst(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract boolean offerLast(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract E pollFirst(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract E pollLast(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract void putFirst(E) throws java.lang.InterruptedException;
-    method public abstract void putLast(E) throws java.lang.InterruptedException;
-    method public abstract E takeFirst() throws java.lang.InterruptedException;
-    method public abstract E takeLast() throws java.lang.InterruptedException;
+  public interface BlockingDeque<E> extends java.util.concurrent.BlockingQueue<E> java.util.Deque<E> {
+    method public boolean offerFirst(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public boolean offerLast(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public E pollFirst(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public E pollLast(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public void putFirst(E) throws java.lang.InterruptedException;
+    method public void putLast(E) throws java.lang.InterruptedException;
+    method public E takeFirst() throws java.lang.InterruptedException;
+    method public E takeLast() throws java.lang.InterruptedException;
   }
 
-  public abstract interface BlockingQueue<E> implements java.util.Queue {
-    method public abstract int drainTo(java.util.Collection<? super E>);
-    method public abstract int drainTo(java.util.Collection<? super E>, int);
-    method public abstract boolean offer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract E poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract void put(E) throws java.lang.InterruptedException;
-    method public abstract int remainingCapacity();
-    method public abstract E take() throws java.lang.InterruptedException;
+  public interface BlockingQueue<E> extends java.util.Queue<E> {
+    method public int drainTo(java.util.Collection<? super E>);
+    method public int drainTo(java.util.Collection<? super E>, int);
+    method public boolean offer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public E poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public void put(E) throws java.lang.InterruptedException;
+    method public int remainingCapacity();
+    method public E take() throws java.lang.InterruptedException;
   }
 
   public class BrokenBarrierException extends java.lang.Exception {
     ctor public BrokenBarrierException();
-    ctor public BrokenBarrierException(java.lang.String);
+    ctor public BrokenBarrierException(String);
   }
 
-  public abstract interface Callable<V> {
-    method public abstract V call() throws java.lang.Exception;
+  @java.lang.FunctionalInterface public interface Callable<V> {
+    method public V call() throws java.lang.Exception;
   }
 
   public class CancellationException extends java.lang.IllegalStateException {
     ctor public CancellationException();
-    ctor public CancellationException(java.lang.String);
+    ctor public CancellationException(String);
   }
 
-  public class CompletableFuture<T> implements java.util.concurrent.CompletionStage java.util.concurrent.Future {
+  public class CompletableFuture<T> implements java.util.concurrent.CompletionStage<T> java.util.concurrent.Future<T> {
     ctor public CompletableFuture();
     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
     method public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>...);
     method public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>...);
-    method public <U> java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T,U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T,U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T,U>, java.util.concurrent.Executor);
     method public boolean cancel(boolean);
     method public boolean complete(T);
-    method public boolean completeExceptionally(java.lang.Throwable);
+    method public boolean completeExceptionally(Throwable);
     method public static <U> java.util.concurrent.CompletableFuture<U> completedFuture(U);
-    method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
+    method public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable,? extends T>);
     method public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
     method public T get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
     method public T getNow(T);
     method public int getNumberOfDependents();
-    method public <U> java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends U>, java.util.concurrent.Executor);
     method public boolean isCancelled();
     method public boolean isCompletedExceptionally();
     method public boolean isDone();
     method public T join();
-    method public void obtrudeException(java.lang.Throwable);
+    method public void obtrudeException(Throwable);
     method public void obtrudeValue(T);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEither(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
-    method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable);
-    method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, Runnable, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEither(java.util.concurrent.CompletionStage<?>, Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, Runnable, java.util.concurrent.Executor);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(Runnable);
+    method public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(Runnable, java.util.concurrent.Executor);
     method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>);
     method public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U>, java.util.concurrent.Executor);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
     method public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
-    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
-    method public <U> java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T, ? extends U>);
-    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
-    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
-    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
-    method public <U> java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable);
-    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T,? super U>);
+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T,? super U>);
+    method public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T,? super U>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T,? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T,? extends U>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T,? extends U>, java.util.concurrent.Executor);
+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T,? super U,? extends V>);
+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T,? super U,? extends V>);
+    method public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T,? super U,? extends V>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T,? extends java.util.concurrent.CompletionStage<U>>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T,? extends java.util.concurrent.CompletionStage<U>>);
+    method public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T,? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(Runnable);
+    method public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(Runnable, java.util.concurrent.Executor);
     method public java.util.concurrent.CompletableFuture<T> toCompletableFuture();
-    method public java.util.concurrent.CompletableFuture<T> whenComplete(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
-    method public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
-    method public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<T> whenComplete(java.util.function.BiConsumer<? super T,? super java.lang.Throwable>);
+    method public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T,? super java.lang.Throwable>);
+    method public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T,? super java.lang.Throwable>, java.util.concurrent.Executor);
   }
 
-  public static abstract interface CompletableFuture.AsynchronousCompletionTask {
+  public static interface CompletableFuture.AsynchronousCompletionTask {
   }
 
   public class CompletionException extends java.lang.RuntimeException {
     ctor protected CompletionException();
-    ctor protected CompletionException(java.lang.String);
-    ctor public CompletionException(java.lang.String, java.lang.Throwable);
-    ctor public CompletionException(java.lang.Throwable);
+    ctor protected CompletionException(String);
+    ctor public CompletionException(String, Throwable);
+    ctor public CompletionException(Throwable);
   }
 
-  public abstract interface CompletionService<V> {
-    method public abstract java.util.concurrent.Future<V> poll();
-    method public abstract java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract java.util.concurrent.Future<V> submit(java.util.concurrent.Callable<V>);
-    method public abstract java.util.concurrent.Future<V> submit(java.lang.Runnable, V);
-    method public abstract java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
+  public interface CompletionService<V> {
+    method public java.util.concurrent.Future<V> poll();
+    method public java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public java.util.concurrent.Future<V> submit(java.util.concurrent.Callable<V>);
+    method public java.util.concurrent.Future<V> submit(Runnable, V);
+    method public java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
   }
 
-  public abstract interface CompletionStage<T> {
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
-    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>);
-    method public abstract <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T, U>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable, ? extends T>);
-    method public abstract <U> java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>);
-    method public abstract <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T, java.lang.Throwable, ? extends U>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterEither(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, java.lang.Runnable, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
-    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>);
-    method public abstract <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T, ? super U>, java.util.concurrent.Executor);
-    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T, ? extends U>);
-    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>);
-    method public abstract <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T, ? extends U>, java.util.concurrent.Executor);
-    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>);
-    method public abstract <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T, ? super U, ? extends V>, java.util.concurrent.Executor);
-    method public abstract <U> java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>);
-    method public abstract <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T, ? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRun(java.lang.Runnable);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable);
-    method public abstract java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(java.lang.Runnable, java.util.concurrent.Executor);
-    method public abstract java.util.concurrent.CompletableFuture<T> toCompletableFuture();
-    method public abstract java.util.concurrent.CompletionStage<T> whenComplete(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
-    method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>);
-    method public abstract java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T, ? super java.lang.Throwable>, java.util.concurrent.Executor);
+  public interface CompletionStage<T> {
+    method public java.util.concurrent.CompletionStage<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletionStage<U> applyToEither(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T,U>);
+    method public <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T,U>);
+    method public <U> java.util.concurrent.CompletionStage<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T>, java.util.function.Function<? super T,U>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletionStage<T> exceptionally(java.util.function.Function<java.lang.Throwable,? extends T>);
+    method public <U> java.util.concurrent.CompletionStage<U> handle(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends U>);
+    method public <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends U>);
+    method public <U> java.util.concurrent.CompletionStage<U> handleAsync(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends U>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?>, Runnable);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, Runnable);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?>, Runnable, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> runAfterEither(java.util.concurrent.CompletionStage<?>, Runnable);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, Runnable);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?>, Runnable, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> thenAccept(java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T,? super U>);
+    method public <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T,? super U>);
+    method public <U> java.util.concurrent.CompletionStage<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiConsumer<? super T,? super U>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletionStage<U> thenApply(java.util.function.Function<? super T,? extends U>);
+    method public <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T,? extends U>);
+    method public <U> java.util.concurrent.CompletionStage<U> thenApplyAsync(java.util.function.Function<? super T,? extends U>, java.util.concurrent.Executor);
+    method public <U, V> java.util.concurrent.CompletionStage<V> thenCombine(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T,? super U,? extends V>);
+    method public <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T,? super U,? extends V>);
+    method public <U, V> java.util.concurrent.CompletionStage<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U>, java.util.function.BiFunction<? super T,? super U,? extends V>, java.util.concurrent.Executor);
+    method public <U> java.util.concurrent.CompletionStage<U> thenCompose(java.util.function.Function<? super T,? extends java.util.concurrent.CompletionStage<U>>);
+    method public <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T,? extends java.util.concurrent.CompletionStage<U>>);
+    method public <U> java.util.concurrent.CompletionStage<U> thenComposeAsync(java.util.function.Function<? super T,? extends java.util.concurrent.CompletionStage<U>>, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> thenRun(Runnable);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(Runnable);
+    method public java.util.concurrent.CompletionStage<java.lang.Void> thenRunAsync(Runnable, java.util.concurrent.Executor);
+    method public java.util.concurrent.CompletableFuture<T> toCompletableFuture();
+    method public java.util.concurrent.CompletionStage<T> whenComplete(java.util.function.BiConsumer<? super T,? super java.lang.Throwable>);
+    method public java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T,? super java.lang.Throwable>);
+    method public java.util.concurrent.CompletionStage<T> whenCompleteAsync(java.util.function.BiConsumer<? super T,? super java.lang.Throwable>, java.util.concurrent.Executor);
   }
 
-  public class ConcurrentHashMap<K, V> extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
+  public class ConcurrentHashMap<K, V> extends java.util.AbstractMap<K,V> implements java.util.concurrent.ConcurrentMap<K,V> java.io.Serializable {
     ctor public ConcurrentHashMap();
     ctor public ConcurrentHashMap(int);
-    ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
+    ctor public ConcurrentHashMap(@NonNull java.util.Map<? extends K,? extends V>);
     ctor public ConcurrentHashMap(int, float);
     ctor public ConcurrentHashMap(int, float, int);
-    method public boolean contains(java.lang.Object);
-    method public java.util.Enumeration<V> elements();
-    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
-    method public void forEach(long, java.util.function.BiConsumer<? super K, ? super V>);
-    method public <U> void forEach(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.Consumer<? super U>);
-    method public void forEachEntry(long, java.util.function.Consumer<? super java.util.Map.Entry<K, V>>);
-    method public <U> void forEachEntry(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.Consumer<? super U>);
-    method public void forEachKey(long, java.util.function.Consumer<? super K>);
-    method public <U> void forEachKey(long, java.util.function.Function<? super K, ? extends U>, java.util.function.Consumer<? super U>);
-    method public void forEachValue(long, java.util.function.Consumer<? super V>);
-    method public <U> void forEachValue(long, java.util.function.Function<? super V, ? extends U>, java.util.function.Consumer<? super U>);
-    method public java.util.concurrent.ConcurrentHashMap.KeySetView<K, V> keySet(V);
-    method public java.util.Enumeration<K> keys();
+    method public boolean contains(@NonNull Object);
+    method @NonNull public java.util.Enumeration<V> elements();
+    method @NonNull public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
+    method public void forEach(long, @NonNull java.util.function.BiConsumer<? super K,? super V>);
+    method public <U> void forEach(long, @NonNull java.util.function.BiFunction<? super K,? super V,? extends U>, @NonNull java.util.function.Consumer<? super U>);
+    method public void forEachEntry(long, @NonNull java.util.function.Consumer<? super java.util.Map.Entry<K,V>>);
+    method public <U> void forEachEntry(long, @NonNull java.util.function.Function<java.util.Map.Entry<K,V>,? extends U>, @NonNull java.util.function.Consumer<? super U>);
+    method public void forEachKey(long, @NonNull java.util.function.Consumer<? super K>);
+    method public <U> void forEachKey(long, @NonNull java.util.function.Function<? super K,? extends U>, @NonNull java.util.function.Consumer<? super U>);
+    method public void forEachValue(long, @NonNull java.util.function.Consumer<? super V>);
+    method public <U> void forEachValue(long, @NonNull java.util.function.Function<? super V,? extends U>, @NonNull java.util.function.Consumer<? super U>);
+    method @NonNull public java.util.concurrent.ConcurrentHashMap.KeySetView<K,V> keySet(@NonNull V);
+    method @NonNull public java.util.Enumeration<K> keys();
     method public long mappingCount();
-    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet();
-    method public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K, java.lang.Boolean> newKeySet(int);
-    method public <U> U reduce(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
-    method public java.util.Map.Entry<K, V> reduceEntries(long, java.util.function.BiFunction<java.util.Map.Entry<K, V>, java.util.Map.Entry<K, V>, ? extends java.util.Map.Entry<K, V>>);
-    method public <U> U reduceEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
-    method public double reduceEntriesToDouble(long, java.util.function.ToDoubleFunction<java.util.Map.Entry<K, V>>, double, java.util.function.DoubleBinaryOperator);
-    method public int reduceEntriesToInt(long, java.util.function.ToIntFunction<java.util.Map.Entry<K, V>>, int, java.util.function.IntBinaryOperator);
-    method public long reduceEntriesToLong(long, java.util.function.ToLongFunction<java.util.Map.Entry<K, V>>, long, java.util.function.LongBinaryOperator);
-    method public K reduceKeys(long, java.util.function.BiFunction<? super K, ? super K, ? extends K>);
-    method public <U> U reduceKeys(long, java.util.function.Function<? super K, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
-    method public double reduceKeysToDouble(long, java.util.function.ToDoubleFunction<? super K>, double, java.util.function.DoubleBinaryOperator);
-    method public int reduceKeysToInt(long, java.util.function.ToIntFunction<? super K>, int, java.util.function.IntBinaryOperator);
-    method public long reduceKeysToLong(long, java.util.function.ToLongFunction<? super K>, long, java.util.function.LongBinaryOperator);
-    method public double reduceToDouble(long, java.util.function.ToDoubleBiFunction<? super K, ? super V>, double, java.util.function.DoubleBinaryOperator);
-    method public int reduceToInt(long, java.util.function.ToIntBiFunction<? super K, ? super V>, int, java.util.function.IntBinaryOperator);
-    method public long reduceToLong(long, java.util.function.ToLongBiFunction<? super K, ? super V>, long, java.util.function.LongBinaryOperator);
-    method public V reduceValues(long, java.util.function.BiFunction<? super V, ? super V, ? extends V>);
-    method public <U> U reduceValues(long, java.util.function.Function<? super V, ? extends U>, java.util.function.BiFunction<? super U, ? super U, ? extends U>);
-    method public double reduceValuesToDouble(long, java.util.function.ToDoubleFunction<? super V>, double, java.util.function.DoubleBinaryOperator);
-    method public int reduceValuesToInt(long, java.util.function.ToIntFunction<? super V>, int, java.util.function.IntBinaryOperator);
-    method public long reduceValuesToLong(long, java.util.function.ToLongFunction<? super V>, long, java.util.function.LongBinaryOperator);
-    method public <U> U search(long, java.util.function.BiFunction<? super K, ? super V, ? extends U>);
-    method public <U> U searchEntries(long, java.util.function.Function<java.util.Map.Entry<K, V>, ? extends U>);
-    method public <U> U searchKeys(long, java.util.function.Function<? super K, ? extends U>);
-    method public <U> U searchValues(long, java.util.function.Function<? super V, ? extends U>);
+    method @NonNull public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K,java.lang.Boolean> newKeySet();
+    method @NonNull public static <K> java.util.concurrent.ConcurrentHashMap.KeySetView<K,java.lang.Boolean> newKeySet(int);
+    method @Nullable public <U> U reduce(long, @NonNull java.util.function.BiFunction<? super K,? super V,? extends U>, @NonNull java.util.function.BiFunction<? super U,? super U,? extends U>);
+    method @Nullable public java.util.Map.Entry<K,V> reduceEntries(long, @NonNull java.util.function.BiFunction<java.util.Map.Entry<K,V>,java.util.Map.Entry<K,V>,? extends java.util.Map.Entry<K,V>>);
+    method @Nullable public <U> U reduceEntries(long, @NonNull java.util.function.Function<java.util.Map.Entry<K,V>,? extends U>, @NonNull java.util.function.BiFunction<? super U,? super U,? extends U>);
+    method public double reduceEntriesToDouble(long, @NonNull java.util.function.ToDoubleFunction<java.util.Map.Entry<K,V>>, double, @NonNull java.util.function.DoubleBinaryOperator);
+    method public int reduceEntriesToInt(long, @NonNull java.util.function.ToIntFunction<java.util.Map.Entry<K,V>>, int, @NonNull java.util.function.IntBinaryOperator);
+    method public long reduceEntriesToLong(long, @NonNull java.util.function.ToLongFunction<java.util.Map.Entry<K,V>>, long, @NonNull java.util.function.LongBinaryOperator);
+    method @Nullable public K reduceKeys(long, @NonNull java.util.function.BiFunction<? super K,? super K,? extends K>);
+    method @Nullable public <U> U reduceKeys(long, @NonNull java.util.function.Function<? super K,? extends U>, @NonNull java.util.function.BiFunction<? super U,? super U,? extends U>);
+    method public double reduceKeysToDouble(long, @NonNull java.util.function.ToDoubleFunction<? super K>, double, @NonNull java.util.function.DoubleBinaryOperator);
+    method public int reduceKeysToInt(long, @NonNull java.util.function.ToIntFunction<? super K>, int, @NonNull java.util.function.IntBinaryOperator);
+    method public long reduceKeysToLong(long, @NonNull java.util.function.ToLongFunction<? super K>, long, @NonNull java.util.function.LongBinaryOperator);
+    method public double reduceToDouble(long, @NonNull java.util.function.ToDoubleBiFunction<? super K,? super V>, double, @NonNull java.util.function.DoubleBinaryOperator);
+    method public int reduceToInt(long, @NonNull java.util.function.ToIntBiFunction<? super K,? super V>, int, @NonNull java.util.function.IntBinaryOperator);
+    method public long reduceToLong(long, @NonNull java.util.function.ToLongBiFunction<? super K,? super V>, long, @NonNull java.util.function.LongBinaryOperator);
+    method @Nullable public V reduceValues(long, @NonNull java.util.function.BiFunction<? super V,? super V,? extends V>);
+    method @Nullable public <U> U reduceValues(long, @NonNull java.util.function.Function<? super V,? extends U>, @NonNull java.util.function.BiFunction<? super U,? super U,? extends U>);
+    method public double reduceValuesToDouble(long, @NonNull java.util.function.ToDoubleFunction<? super V>, double, @NonNull java.util.function.DoubleBinaryOperator);
+    method public int reduceValuesToInt(long, @NonNull java.util.function.ToIntFunction<? super V>, int, @NonNull java.util.function.IntBinaryOperator);
+    method public long reduceValuesToLong(long, @NonNull java.util.function.ToLongFunction<? super V>, long, @NonNull java.util.function.LongBinaryOperator);
+    method @Nullable public <U> U search(long, @NonNull java.util.function.BiFunction<? super K,? super V,? extends U>);
+    method @Nullable public <U> U searchEntries(long, @NonNull java.util.function.Function<java.util.Map.Entry<K,V>,? extends U>);
+    method @Nullable public <U> U searchKeys(long, @NonNull java.util.function.Function<? super K,? extends U>);
+    method @Nullable public <U> U searchValues(long, @NonNull java.util.function.Function<? super V,? extends U>);
   }
 
-  public static class ConcurrentHashMap.KeySetView<K, V> implements java.util.Collection java.io.Serializable java.util.Set {
-    method public boolean add(K);
-    method public boolean addAll(java.util.Collection<? extends K>);
-    method public boolean contains(java.lang.Object);
-    method public void forEach(java.util.function.Consumer<? super K>);
-    method public V getMappedValue();
-    method public java.util.Iterator<K> iterator();
-    method public boolean remove(java.lang.Object);
-    method public java.util.Spliterator<K> spliterator();
+  public static class ConcurrentHashMap.KeySetView<K, V> implements java.util.Collection<K> java.io.Serializable java.util.Set<K> {
+    method public boolean add(@NonNull K);
+    method public boolean addAll(@NonNull java.util.Collection<? extends K>);
+    method public final void clear();
+    method public boolean contains(@NonNull Object);
+    method public final boolean containsAll(java.util.Collection<?>);
+    method public void forEach(@NonNull java.util.function.Consumer<? super K>);
+    method public java.util.concurrent.ConcurrentHashMap<K,V> getMap();
+    method @Nullable public V getMappedValue();
+    method public final boolean isEmpty();
+    method @NonNull public java.util.Iterator<K> iterator();
+    method public boolean remove(@NonNull Object);
+    method public final boolean removeAll(java.util.Collection<?>);
+    method public final boolean retainAll(java.util.Collection<?>);
+    method public final int size();
+    method @NonNull public java.util.Spliterator<K> spliterator();
+    method public final Object[] toArray();
+    method public final <T> T[] toArray(T[]);
+    method public final String toString();
   }
 
-  public class ConcurrentLinkedDeque<E> extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
+  public class ConcurrentLinkedDeque<E> extends java.util.AbstractCollection<E> implements java.util.Deque<E> java.io.Serializable {
     ctor public ConcurrentLinkedDeque();
     ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>);
     method public void addFirst(E);
@@ -70602,13 +70906,13 @@
     method public void push(E);
     method public E remove();
     method public E removeFirst();
-    method public boolean removeFirstOccurrence(java.lang.Object);
+    method public boolean removeFirstOccurrence(Object);
     method public E removeLast();
-    method public boolean removeLastOccurrence(java.lang.Object);
+    method public boolean removeLastOccurrence(Object);
     method public int size();
   }
 
-  public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
+  public class ConcurrentLinkedQueue<E> extends java.util.AbstractQueue<E> implements java.util.Queue<E> java.io.Serializable {
     ctor public ConcurrentLinkedQueue();
     ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
     method public java.util.Iterator<E> iterator();
@@ -70618,59 +70922,59 @@
     method public int size();
   }
 
-  public abstract interface ConcurrentMap<K, V> implements java.util.Map {
-    method public abstract V putIfAbsent(K, V);
-    method public abstract boolean remove(java.lang.Object, java.lang.Object);
-    method public abstract boolean replace(K, V, V);
-    method public abstract V replace(K, V);
+  public interface ConcurrentMap<K, V> extends java.util.Map<K,V> {
+    method public V putIfAbsent(K, V);
+    method public boolean remove(Object, Object);
+    method public boolean replace(K, V, V);
+    method public V replace(K, V);
   }
 
-  public abstract interface ConcurrentNavigableMap<K, V> implements java.util.concurrent.ConcurrentMap java.util.NavigableMap {
-    method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
-    method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
-    method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K);
-    method public abstract java.util.NavigableSet<K> keySet();
-    method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> subMap(K, boolean, K, boolean);
-    method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> subMap(K, K);
-    method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K, boolean);
-    method public abstract java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
+  public interface ConcurrentNavigableMap<K, V> extends java.util.concurrent.ConcurrentMap<K,V> java.util.NavigableMap<K,V> {
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> descendingMap();
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> headMap(K, boolean);
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> headMap(K);
+    method public java.util.NavigableSet<K> keySet();
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> subMap(K, boolean, K, boolean);
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> subMap(K, K);
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> tailMap(K, boolean);
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> tailMap(K);
   }
 
-  public class ConcurrentSkipListMap<K, V> extends java.util.AbstractMap implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap java.io.Serializable {
+  public class ConcurrentSkipListMap<K, V> extends java.util.AbstractMap<K,V> implements java.lang.Cloneable java.util.concurrent.ConcurrentNavigableMap<K,V> java.io.Serializable {
     ctor public ConcurrentSkipListMap();
     ctor public ConcurrentSkipListMap(java.util.Comparator<? super K>);
-    ctor public ConcurrentSkipListMap(java.util.Map<? extends K, ? extends V>);
-    ctor public ConcurrentSkipListMap(java.util.SortedMap<K, ? extends V>);
-    method public java.util.Map.Entry<K, V> ceilingEntry(K);
+    ctor public ConcurrentSkipListMap(java.util.Map<? extends K,? extends V>);
+    ctor public ConcurrentSkipListMap(java.util.SortedMap<K,? extends V>);
+    method public java.util.Map.Entry<K,V> ceilingEntry(K);
     method public K ceilingKey(K);
-    method public java.util.concurrent.ConcurrentSkipListMap<K, V> clone();
+    method public java.util.concurrent.ConcurrentSkipListMap<K,V> clone();
     method public java.util.Comparator<? super K> comparator();
     method public java.util.NavigableSet<K> descendingKeySet();
-    method public java.util.concurrent.ConcurrentNavigableMap<K, V> descendingMap();
-    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
-    method public java.util.Map.Entry<K, V> firstEntry();
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> descendingMap();
+    method public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
+    method public java.util.Map.Entry<K,V> firstEntry();
     method public K firstKey();
-    method public java.util.Map.Entry<K, V> floorEntry(K);
+    method public java.util.Map.Entry<K,V> floorEntry(K);
     method public K floorKey(K);
-    method public java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K, boolean);
-    method public java.util.concurrent.ConcurrentNavigableMap<K, V> headMap(K);
-    method public java.util.Map.Entry<K, V> higherEntry(K);
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> headMap(K, boolean);
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> headMap(K);
+    method public java.util.Map.Entry<K,V> higherEntry(K);
     method public K higherKey(K);
     method public java.util.NavigableSet<K> keySet();
-    method public java.util.Map.Entry<K, V> lastEntry();
+    method public java.util.Map.Entry<K,V> lastEntry();
     method public K lastKey();
-    method public java.util.Map.Entry<K, V> lowerEntry(K);
+    method public java.util.Map.Entry<K,V> lowerEntry(K);
     method public K lowerKey(K);
     method public java.util.NavigableSet<K> navigableKeySet();
-    method public java.util.Map.Entry<K, V> pollFirstEntry();
-    method public java.util.Map.Entry<K, V> pollLastEntry();
-    method public java.util.concurrent.ConcurrentNavigableMap<K, V> subMap(K, boolean, K, boolean);
-    method public java.util.concurrent.ConcurrentNavigableMap<K, V> subMap(K, K);
-    method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K, boolean);
-    method public java.util.concurrent.ConcurrentNavigableMap<K, V> tailMap(K);
+    method public java.util.Map.Entry<K,V> pollFirstEntry();
+    method public java.util.Map.Entry<K,V> pollLastEntry();
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> subMap(K, boolean, K, boolean);
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> subMap(K, K);
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> tailMap(K, boolean);
+    method public java.util.concurrent.ConcurrentNavigableMap<K,V> tailMap(K);
   }
 
-  public class ConcurrentSkipListSet<E> extends java.util.AbstractSet implements java.lang.Cloneable java.util.NavigableSet java.io.Serializable {
+  public class ConcurrentSkipListSet<E> extends java.util.AbstractSet<E> implements java.lang.Cloneable java.util.NavigableSet<E> java.io.Serializable {
     ctor public ConcurrentSkipListSet();
     ctor public ConcurrentSkipListSet(java.util.Comparator<? super E>);
     ctor public ConcurrentSkipListSet(java.util.Collection<? extends E>);
@@ -70697,42 +71001,42 @@
     method public java.util.NavigableSet<E> tailSet(E);
   }
 
-  public class CopyOnWriteArrayList<E> implements java.lang.Cloneable java.util.List java.util.RandomAccess java.io.Serializable {
+  public class CopyOnWriteArrayList<E> implements java.lang.Cloneable java.util.List<E> java.util.RandomAccess java.io.Serializable {
     ctor public CopyOnWriteArrayList();
-    ctor public CopyOnWriteArrayList(java.util.Collection<? extends E>);
+    ctor public CopyOnWriteArrayList(@NonNull java.util.Collection<? extends E>);
     ctor public CopyOnWriteArrayList(E[]);
     method public boolean add(E);
     method public void add(int, E);
-    method public boolean addAll(java.util.Collection<? extends E>);
-    method public boolean addAll(int, java.util.Collection<? extends E>);
-    method public int addAllAbsent(java.util.Collection<? extends E>);
+    method public boolean addAll(@NonNull java.util.Collection<? extends E>);
+    method public boolean addAll(int, @NonNull java.util.Collection<? extends E>);
+    method public int addAllAbsent(@NonNull java.util.Collection<? extends E>);
     method public boolean addIfAbsent(E);
     method public void clear();
-    method public java.lang.Object clone();
-    method public boolean contains(java.lang.Object);
-    method public boolean containsAll(java.util.Collection<?>);
-    method public void forEach(java.util.function.Consumer<? super E>);
+    method @NonNull public Object clone();
+    method public boolean contains(@Nullable Object);
+    method public boolean containsAll(@NonNull java.util.Collection<?>);
+    method public void forEach(@NonNull java.util.function.Consumer<? super E>);
     method public E get(int);
-    method public int indexOf(java.lang.Object);
-    method public int indexOf(E, int);
+    method public int indexOf(@Nullable Object);
+    method public int indexOf(@Nullable E, int);
     method public boolean isEmpty();
-    method public java.util.Iterator<E> iterator();
-    method public int lastIndexOf(java.lang.Object);
-    method public int lastIndexOf(E, int);
-    method public java.util.ListIterator<E> listIterator();
-    method public java.util.ListIterator<E> listIterator(int);
+    method @NonNull public java.util.Iterator<E> iterator();
+    method public int lastIndexOf(@Nullable Object);
+    method public int lastIndexOf(@Nullable E, int);
+    method @NonNull public java.util.ListIterator<E> listIterator();
+    method @NonNull public java.util.ListIterator<E> listIterator(int);
     method public E remove(int);
-    method public boolean remove(java.lang.Object);
-    method public boolean removeAll(java.util.Collection<?>);
-    method public boolean retainAll(java.util.Collection<?>);
+    method public boolean remove(@Nullable Object);
+    method public boolean removeAll(@NonNull java.util.Collection<?>);
+    method public boolean retainAll(@NonNull java.util.Collection<?>);
     method public E set(int, E);
     method public int size();
-    method public java.util.List<E> subList(int, int);
-    method public java.lang.Object[] toArray();
+    method @NonNull public java.util.List<E> subList(int, int);
+    method public Object[] toArray();
     method public <T> T[] toArray(T[]);
   }
 
-  public class CopyOnWriteArraySet<E> extends java.util.AbstractSet implements java.io.Serializable {
+  public class CopyOnWriteArraySet<E> extends java.util.AbstractSet<E> implements java.io.Serializable {
     ctor public CopyOnWriteArraySet();
     ctor public CopyOnWriteArraySet(java.util.Collection<? extends E>);
     method public void forEach(java.util.function.Consumer<? super E>);
@@ -70748,7 +71052,7 @@
     method public long getCount();
   }
 
-  public abstract class CountedCompleter<T> extends java.util.concurrent.ForkJoinTask {
+  public abstract class CountedCompleter<T> extends java.util.concurrent.ForkJoinTask<T> {
     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>, int);
     ctor protected CountedCompleter(java.util.concurrent.CountedCompleter<?>);
     ctor protected CountedCompleter();
@@ -70766,7 +71070,7 @@
     method public final void helpComplete(int);
     method public final java.util.concurrent.CountedCompleter<?> nextComplete();
     method public void onCompletion(java.util.concurrent.CountedCompleter<?>);
-    method public boolean onExceptionalCompletion(java.lang.Throwable, java.util.concurrent.CountedCompleter<?>);
+    method public boolean onExceptionalCompletion(Throwable, java.util.concurrent.CountedCompleter<?>);
     method public final void propagateCompletion();
     method public final void quietlyCompleteRoot();
     method public final void setPendingCount(int);
@@ -70775,7 +71079,7 @@
   }
 
   public class CyclicBarrier {
-    ctor public CyclicBarrier(int, java.lang.Runnable);
+    ctor public CyclicBarrier(int, Runnable);
     ctor public CyclicBarrier(int);
     method public int await() throws java.util.concurrent.BrokenBarrierException, java.lang.InterruptedException;
     method public int await(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.BrokenBarrierException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
@@ -70785,7 +71089,7 @@
     method public void reset();
   }
 
-  public class DelayQueue<E extends java.util.concurrent.Delayed> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue {
+  public class DelayQueue<E extends java.util.concurrent.Delayed> extends java.util.AbstractQueue<E> implements java.util.concurrent.BlockingQueue<E> {
     ctor public DelayQueue();
     ctor public DelayQueue(java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
@@ -70802,8 +71106,8 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
-  public abstract interface Delayed implements java.lang.Comparable {
-    method public abstract long getDelay(java.util.concurrent.TimeUnit);
+  public interface Delayed extends java.lang.Comparable<java.util.concurrent.Delayed> {
+    method public long getDelay(java.util.concurrent.TimeUnit);
   }
 
   public class Exchanger<V> {
@@ -70814,43 +71118,43 @@
 
   public class ExecutionException extends java.lang.Exception {
     ctor protected ExecutionException();
-    ctor protected ExecutionException(java.lang.String);
-    ctor public ExecutionException(java.lang.String, java.lang.Throwable);
-    ctor public ExecutionException(java.lang.Throwable);
+    ctor protected ExecutionException(String);
+    ctor public ExecutionException(String, Throwable);
+    ctor public ExecutionException(Throwable);
   }
 
-  public abstract interface Executor {
-    method public abstract void execute(java.lang.Runnable);
+  public interface Executor {
+    method public void execute(Runnable);
   }
 
-  public class ExecutorCompletionService<V> implements java.util.concurrent.CompletionService {
+  public class ExecutorCompletionService<V> implements java.util.concurrent.CompletionService<V> {
     ctor public ExecutorCompletionService(java.util.concurrent.Executor);
     ctor public ExecutorCompletionService(java.util.concurrent.Executor, java.util.concurrent.BlockingQueue<java.util.concurrent.Future<V>>);
     method public java.util.concurrent.Future<V> poll();
     method public java.util.concurrent.Future<V> poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
     method public java.util.concurrent.Future<V> submit(java.util.concurrent.Callable<V>);
-    method public java.util.concurrent.Future<V> submit(java.lang.Runnable, V);
+    method public java.util.concurrent.Future<V> submit(Runnable, V);
     method public java.util.concurrent.Future<V> take() throws java.lang.InterruptedException;
   }
 
-  public abstract interface ExecutorService implements java.util.concurrent.Executor {
-    method public abstract boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
-    method public abstract <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
-    method public abstract <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
-    method public abstract boolean isShutdown();
-    method public abstract boolean isTerminated();
-    method public abstract void shutdown();
-    method public abstract java.util.List<java.lang.Runnable> shutdownNow();
-    method public abstract <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
-    method public abstract <T> java.util.concurrent.Future<T> submit(java.lang.Runnable, T);
-    method public abstract java.util.concurrent.Future<?> submit(java.lang.Runnable);
+  public interface ExecutorService extends java.util.concurrent.Executor {
+    method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.lang.InterruptedException;
+    method public <T> java.util.List<java.util.concurrent.Future<T>> invokeAll(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
+    method public <T> T invokeAny(java.util.Collection<? extends java.util.concurrent.Callable<T>>, long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method public boolean isShutdown();
+    method public boolean isTerminated();
+    method public void shutdown();
+    method public java.util.List<java.lang.Runnable> shutdownNow();
+    method public <T> java.util.concurrent.Future<T> submit(java.util.concurrent.Callable<T>);
+    method public <T> java.util.concurrent.Future<T> submit(Runnable, T);
+    method public java.util.concurrent.Future<?> submit(Runnable);
   }
 
   public class Executors {
-    method public static <T> java.util.concurrent.Callable<T> callable(java.lang.Runnable, T);
-    method public static java.util.concurrent.Callable<java.lang.Object> callable(java.lang.Runnable);
+    method public static <T> java.util.concurrent.Callable<T> callable(Runnable, T);
+    method public static java.util.concurrent.Callable<java.lang.Object> callable(Runnable);
     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedAction<?>);
     method public static java.util.concurrent.Callable<java.lang.Object> callable(java.security.PrivilegedExceptionAction<?>);
     method public static java.util.concurrent.ThreadFactory defaultThreadFactory();
@@ -70882,7 +71186,7 @@
     method public static java.util.concurrent.ForkJoinPool commonPool();
     method protected int drainTasksTo(java.util.Collection<? super java.util.concurrent.ForkJoinTask<?>>);
     method public void execute(java.util.concurrent.ForkJoinTask<?>);
-    method public void execute(java.lang.Runnable);
+    method public void execute(Runnable);
     method public int getActiveThreadCount();
     method public boolean getAsyncMode();
     method public static int getCommonPoolParallelism();
@@ -70907,34 +71211,34 @@
     method public java.util.List<java.lang.Runnable> shutdownNow();
     method public <T> java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
     method public <T> java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.Callable<T>);
-    method public <T> java.util.concurrent.ForkJoinTask<T> submit(java.lang.Runnable, T);
-    method public java.util.concurrent.ForkJoinTask<?> submit(java.lang.Runnable);
+    method public <T> java.util.concurrent.ForkJoinTask<T> submit(Runnable, T);
+    method public java.util.concurrent.ForkJoinTask<?> submit(Runnable);
     field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;
   }
 
-  public static abstract interface ForkJoinPool.ForkJoinWorkerThreadFactory {
-    method public abstract java.util.concurrent.ForkJoinWorkerThread newThread(java.util.concurrent.ForkJoinPool);
+  public static interface ForkJoinPool.ForkJoinWorkerThreadFactory {
+    method public java.util.concurrent.ForkJoinWorkerThread newThread(java.util.concurrent.ForkJoinPool);
   }
 
-  public static abstract interface ForkJoinPool.ManagedBlocker {
-    method public abstract boolean block() throws java.lang.InterruptedException;
-    method public abstract boolean isReleasable();
+  public static interface ForkJoinPool.ManagedBlocker {
+    method public boolean block() throws java.lang.InterruptedException;
+    method public boolean isReleasable();
   }
 
-  public abstract class ForkJoinTask<V> implements java.util.concurrent.Future java.io.Serializable {
+  public abstract class ForkJoinTask<V> implements java.util.concurrent.Future<V> java.io.Serializable {
     ctor public ForkJoinTask();
-    method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable);
-    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
+    method public static java.util.concurrent.ForkJoinTask<?> adapt(Runnable);
+    method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(Runnable, T);
     method public static <T> java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
     method public boolean cancel(boolean);
     method public final boolean compareAndSetForkJoinTaskTag(short, short);
     method public void complete(V);
-    method public void completeExceptionally(java.lang.Throwable);
+    method public void completeExceptionally(Throwable);
     method protected abstract boolean exec();
     method public final java.util.concurrent.ForkJoinTask<V> fork();
     method public final V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
     method public final V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
-    method public final java.lang.Throwable getException();
+    method public final Throwable getException();
     method public final short getForkJoinTaskTag();
     method public static java.util.concurrent.ForkJoinPool getPool();
     method public static int getQueuedTaskCount();
@@ -70968,20 +71272,20 @@
     method public java.util.concurrent.ForkJoinPool getPool();
     method public int getPoolIndex();
     method protected void onStart();
-    method protected void onTermination(java.lang.Throwable);
+    method protected void onTermination(Throwable);
   }
 
-  public abstract interface Future<V> {
-    method public abstract boolean cancel(boolean);
-    method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
-    method public abstract V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
-    method public abstract boolean isCancelled();
-    method public abstract boolean isDone();
+  public interface Future<V> {
+    method public boolean cancel(boolean);
+    method public V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
+    method public V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method public boolean isCancelled();
+    method public boolean isDone();
   }
 
-  public class FutureTask<V> implements java.util.concurrent.RunnableFuture {
+  public class FutureTask<V> implements java.util.concurrent.RunnableFuture<V> {
     ctor public FutureTask(java.util.concurrent.Callable<V>);
-    ctor public FutureTask(java.lang.Runnable, V);
+    ctor public FutureTask(Runnable, V);
     method public boolean cancel(boolean);
     method protected void done();
     method public V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
@@ -70991,10 +71295,10 @@
     method public void run();
     method protected boolean runAndReset();
     method protected void set(V);
-    method protected void setException(java.lang.Throwable);
+    method protected void setException(Throwable);
   }
 
-  public class LinkedBlockingDeque<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingDeque java.io.Serializable {
+  public class LinkedBlockingDeque<E> extends java.util.AbstractQueue<E> implements java.util.concurrent.BlockingDeque<E> java.io.Serializable {
     ctor public LinkedBlockingDeque();
     ctor public LinkedBlockingDeque(int);
     ctor public LinkedBlockingDeque(java.util.Collection<? extends E>);
@@ -71028,16 +71332,16 @@
     method public void putLast(E) throws java.lang.InterruptedException;
     method public int remainingCapacity();
     method public E removeFirst();
-    method public boolean removeFirstOccurrence(java.lang.Object);
+    method public boolean removeFirstOccurrence(Object);
     method public E removeLast();
-    method public boolean removeLastOccurrence(java.lang.Object);
+    method public boolean removeLastOccurrence(Object);
     method public int size();
     method public E take() throws java.lang.InterruptedException;
     method public E takeFirst() throws java.lang.InterruptedException;
     method public E takeLast() throws java.lang.InterruptedException;
   }
 
-  public class LinkedBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class LinkedBlockingQueue<E> extends java.util.AbstractQueue<E> implements java.util.concurrent.BlockingQueue<E> java.io.Serializable {
     ctor public LinkedBlockingQueue();
     ctor public LinkedBlockingQueue(int);
     ctor public LinkedBlockingQueue(java.util.Collection<? extends E>);
@@ -71055,7 +71359,7 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
-  public class LinkedTransferQueue<E> extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
+  public class LinkedTransferQueue<E> extends java.util.AbstractQueue<E> implements java.io.Serializable java.util.concurrent.TransferQueue<E> {
     ctor public LinkedTransferQueue();
     ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
     method public int drainTo(java.util.Collection<? super E>);
@@ -71101,7 +71405,7 @@
     method public int register();
   }
 
-  public class PriorityBlockingQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class PriorityBlockingQueue<E> extends java.util.AbstractQueue<E> implements java.util.concurrent.BlockingQueue<E> java.io.Serializable {
     ctor public PriorityBlockingQueue();
     ctor public PriorityBlockingQueue(int);
     ctor public PriorityBlockingQueue(int, java.util.Comparator<? super E>);
@@ -71121,15 +71425,15 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
-  public abstract class RecursiveAction extends java.util.concurrent.ForkJoinTask {
+  public abstract class RecursiveAction extends java.util.concurrent.ForkJoinTask<java.lang.Void> {
     ctor public RecursiveAction();
     method protected abstract void compute();
     method protected final boolean exec();
-    method public final java.lang.Void getRawResult();
-    method protected final void setRawResult(java.lang.Void);
+    method public final Void getRawResult();
+    method protected final void setRawResult(Void);
   }
 
-  public abstract class RecursiveTask<V> extends java.util.concurrent.ForkJoinTask {
+  public abstract class RecursiveTask<V> extends java.util.concurrent.ForkJoinTask<V> {
     ctor public RecursiveTask();
     method protected abstract V compute();
     method protected final boolean exec();
@@ -71139,30 +71443,30 @@
 
   public class RejectedExecutionException extends java.lang.RuntimeException {
     ctor public RejectedExecutionException();
-    ctor public RejectedExecutionException(java.lang.String);
-    ctor public RejectedExecutionException(java.lang.String, java.lang.Throwable);
-    ctor public RejectedExecutionException(java.lang.Throwable);
+    ctor public RejectedExecutionException(String);
+    ctor public RejectedExecutionException(String, Throwable);
+    ctor public RejectedExecutionException(Throwable);
   }
 
-  public abstract interface RejectedExecutionHandler {
-    method public abstract void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
+  public interface RejectedExecutionHandler {
+    method public void rejectedExecution(Runnable, java.util.concurrent.ThreadPoolExecutor);
   }
 
-  public abstract interface RunnableFuture<V> implements java.util.concurrent.Future java.lang.Runnable {
+  public interface RunnableFuture<V> extends java.lang.Runnable java.util.concurrent.Future<V> {
   }
 
-  public abstract interface RunnableScheduledFuture<V> implements java.util.concurrent.RunnableFuture java.util.concurrent.ScheduledFuture {
-    method public abstract boolean isPeriodic();
+  public interface RunnableScheduledFuture<V> extends java.util.concurrent.RunnableFuture<V> java.util.concurrent.ScheduledFuture<V> {
+    method public boolean isPeriodic();
   }
 
-  public abstract interface ScheduledExecutorService implements java.util.concurrent.ExecutorService {
-    method public abstract java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
-    method public abstract <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
-    method public abstract java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
-    method public abstract java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
+  public interface ScheduledExecutorService extends java.util.concurrent.ExecutorService {
+    method public java.util.concurrent.ScheduledFuture<?> schedule(Runnable, long, java.util.concurrent.TimeUnit);
+    method public <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
+    method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(Runnable, long, long, java.util.concurrent.TimeUnit);
+    method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(Runnable, long, long, java.util.concurrent.TimeUnit);
   }
 
-  public abstract interface ScheduledFuture<V> implements java.util.concurrent.Delayed java.util.concurrent.Future {
+  public interface ScheduledFuture<V> extends java.util.concurrent.Delayed java.util.concurrent.Future<V> {
   }
 
   public class ScheduledThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor implements java.util.concurrent.ScheduledExecutorService {
@@ -71170,15 +71474,15 @@
     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory);
     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.RejectedExecutionHandler);
     ctor public ScheduledThreadPoolExecutor(int, java.util.concurrent.ThreadFactory, java.util.concurrent.RejectedExecutionHandler);
-    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.lang.Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
+    method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(Runnable, java.util.concurrent.RunnableScheduledFuture<V>);
     method protected <V> java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
     method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy();
     method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy();
     method public boolean getRemoveOnCancelPolicy();
-    method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
+    method public java.util.concurrent.ScheduledFuture<?> schedule(Runnable, long, java.util.concurrent.TimeUnit);
     method public <V> java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
-    method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
-    method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
+    method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(Runnable, long, long, java.util.concurrent.TimeUnit);
+    method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(Runnable, long, long, java.util.concurrent.TimeUnit);
     method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean);
     method public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean);
     method public void setRemoveOnCancelPolicy(boolean);
@@ -71206,7 +71510,7 @@
     method public boolean tryAcquire(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
   }
 
-  public class SynchronousQueue<E> extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
+  public class SynchronousQueue<E> extends java.util.AbstractQueue<E> implements java.util.concurrent.BlockingQueue<E> java.io.Serializable {
     ctor public SynchronousQueue();
     ctor public SynchronousQueue(boolean);
     method public int drainTo(java.util.Collection<? super E>);
@@ -71223,19 +71527,17 @@
     method public E take() throws java.lang.InterruptedException;
   }
 
-  public abstract interface ThreadFactory {
-    method public abstract java.lang.Thread newThread(java.lang.Runnable);
+  public interface ThreadFactory {
+    method public Thread newThread(Runnable);
   }
 
   public class ThreadLocalRandom extends java.util.Random {
     method public static java.util.concurrent.ThreadLocalRandom current();
     method public double nextDouble(double);
     method public double nextDouble(double, double);
-    method public double nextGaussian();
     method public int nextInt(int, int);
     method public long nextLong(long);
     method public long nextLong(long, long);
-    method public void setSeed(long);
   }
 
   public class ThreadPoolExecutor extends java.util.concurrent.AbstractExecutorService {
@@ -71243,12 +71545,12 @@
     ctor public ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue<java.lang.Runnable>, java.util.concurrent.ThreadFactory);
     ctor public ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue<java.lang.Runnable>, java.util.concurrent.RejectedExecutionHandler);
     ctor public ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue<java.lang.Runnable>, java.util.concurrent.ThreadFactory, java.util.concurrent.RejectedExecutionHandler);
-    method protected void afterExecute(java.lang.Runnable, java.lang.Throwable);
+    method protected void afterExecute(Runnable, Throwable);
     method public void allowCoreThreadTimeOut(boolean);
     method public boolean allowsCoreThreadTimeOut();
     method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method protected void beforeExecute(java.lang.Thread, java.lang.Runnable);
-    method public void execute(java.lang.Runnable);
+    method protected void beforeExecute(Thread, Runnable);
+    method public void execute(Runnable);
     method protected void finalize();
     method public int getActiveCount();
     method public long getCompletedTaskCount();
@@ -71267,7 +71569,7 @@
     method public int prestartAllCoreThreads();
     method public boolean prestartCoreThread();
     method public void purge();
-    method public boolean remove(java.lang.Runnable);
+    method public boolean remove(Runnable);
     method public void setCorePoolSize(int);
     method public void setKeepAliveTime(long, java.util.concurrent.TimeUnit);
     method public void setMaximumPoolSize(int);
@@ -71280,29 +71582,29 @@
 
   public static class ThreadPoolExecutor.AbortPolicy implements java.util.concurrent.RejectedExecutionHandler {
     ctor public ThreadPoolExecutor.AbortPolicy();
-    method public void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
+    method public void rejectedExecution(Runnable, java.util.concurrent.ThreadPoolExecutor);
   }
 
   public static class ThreadPoolExecutor.CallerRunsPolicy implements java.util.concurrent.RejectedExecutionHandler {
     ctor public ThreadPoolExecutor.CallerRunsPolicy();
-    method public void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
+    method public void rejectedExecution(Runnable, java.util.concurrent.ThreadPoolExecutor);
   }
 
   public static class ThreadPoolExecutor.DiscardOldestPolicy implements java.util.concurrent.RejectedExecutionHandler {
     ctor public ThreadPoolExecutor.DiscardOldestPolicy();
-    method public void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
+    method public void rejectedExecution(Runnable, java.util.concurrent.ThreadPoolExecutor);
   }
 
   public static class ThreadPoolExecutor.DiscardPolicy implements java.util.concurrent.RejectedExecutionHandler {
     ctor public ThreadPoolExecutor.DiscardPolicy();
-    method public void rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor);
+    method public void rejectedExecution(Runnable, java.util.concurrent.ThreadPoolExecutor);
   }
 
-  public class TimeUnit extends java.lang.Enum {
+  public enum TimeUnit {
     method public long convert(long, java.util.concurrent.TimeUnit);
     method public void sleep(long) throws java.lang.InterruptedException;
-    method public void timedJoin(java.lang.Thread, long) throws java.lang.InterruptedException;
-    method public void timedWait(java.lang.Object, long) throws java.lang.InterruptedException;
+    method public void timedJoin(Thread, long) throws java.lang.InterruptedException;
+    method public void timedWait(Object, long) throws java.lang.InterruptedException;
     method public long toDays(long);
     method public long toHours(long);
     method public long toMicros(long);
@@ -71310,8 +71612,6 @@
     method public long toMinutes(long);
     method public long toNanos(long);
     method public long toSeconds(long);
-    method public static java.util.concurrent.TimeUnit valueOf(java.lang.String);
-    method public static final java.util.concurrent.TimeUnit[] values();
     enum_constant public static final java.util.concurrent.TimeUnit DAYS;
     enum_constant public static final java.util.concurrent.TimeUnit HOURS;
     enum_constant public static final java.util.concurrent.TimeUnit MICROSECONDS;
@@ -71323,15 +71623,15 @@
 
   public class TimeoutException extends java.lang.Exception {
     ctor public TimeoutException();
-    ctor public TimeoutException(java.lang.String);
+    ctor public TimeoutException(String);
   }
 
-  public abstract interface TransferQueue<E> implements java.util.concurrent.BlockingQueue {
-    method public abstract int getWaitingConsumerCount();
-    method public abstract boolean hasWaitingConsumer();
-    method public abstract void transfer(E) throws java.lang.InterruptedException;
-    method public abstract boolean tryTransfer(E);
-    method public abstract boolean tryTransfer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+  public interface TransferQueue<E> extends java.util.concurrent.BlockingQueue<E> {
+    method public int getWaitingConsumerCount();
+    method public boolean hasWaitingConsumer();
+    method public void transfer(E) throws java.lang.InterruptedException;
+    method public boolean tryTransfer(E);
+    method public boolean tryTransfer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
   }
 
 }
@@ -71411,7 +71711,7 @@
     method public final int getAndUpdate(T, java.util.function.IntUnaryOperator);
     method public int incrementAndGet(T);
     method public abstract void lazySet(T, int);
-    method public static <U> java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
+    method public static <U> java.util.concurrent.atomic.AtomicIntegerFieldUpdater<U> newUpdater(Class<U>, String);
     method public abstract void set(T, int);
     method public final int updateAndGet(T, java.util.function.IntUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, int, int);
@@ -71479,7 +71779,7 @@
     method public final long getAndUpdate(T, java.util.function.LongUnaryOperator);
     method public long incrementAndGet(T);
     method public abstract void lazySet(T, long);
-    method public static <U> java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(java.lang.Class<U>, java.lang.String);
+    method public static <U> java.util.concurrent.atomic.AtomicLongFieldUpdater<U> newUpdater(Class<U>, String);
     method public abstract void set(T, long);
     method public final long updateAndGet(T, java.util.function.LongUnaryOperator);
     method public abstract boolean weakCompareAndSet(T, long, long);
@@ -71536,7 +71836,7 @@
     method public V getAndSet(T, V);
     method public final V getAndUpdate(T, java.util.function.UnaryOperator<V>);
     method public abstract void lazySet(T, V);
-    method public static <U, W> java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U, W> newUpdater(java.lang.Class<U>, java.lang.Class<W>, java.lang.String);
+    method public static <U, W> java.util.concurrent.atomic.AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U>, Class<W>, String);
     method public abstract void set(T, V);
     method public final V updateAndGet(T, java.util.function.UnaryOperator<V>);
     method public abstract boolean weakCompareAndSet(T, V, V);
@@ -71609,8 +71909,8 @@
 
   public abstract class AbstractOwnableSynchronizer implements java.io.Serializable {
     ctor protected AbstractOwnableSynchronizer();
-    method protected final java.lang.Thread getExclusiveOwnerThread();
-    method protected final void setExclusiveOwnerThread(java.lang.Thread);
+    method protected final Thread getExclusiveOwnerThread();
+    method protected final void setExclusiveOwnerThread(Thread);
   }
 
   public abstract class AbstractQueuedLongSynchronizer extends java.util.concurrent.locks.AbstractOwnableSynchronizer implements java.io.Serializable {
@@ -71621,7 +71921,7 @@
     method public final void acquireSharedInterruptibly(long) throws java.lang.InterruptedException;
     method protected final boolean compareAndSetState(long, long);
     method public final java.util.Collection<java.lang.Thread> getExclusiveQueuedThreads();
-    method public final java.lang.Thread getFirstQueuedThread();
+    method public final Thread getFirstQueuedThread();
     method public final int getQueueLength();
     method public final java.util.Collection<java.lang.Thread> getQueuedThreads();
     method public final java.util.Collection<java.lang.Thread> getSharedQueuedThreads();
@@ -71633,7 +71933,7 @@
     method public final boolean hasQueuedThreads();
     method public final boolean hasWaiters(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject);
     method protected boolean isHeldExclusively();
-    method public final boolean isQueued(java.lang.Thread);
+    method public final boolean isQueued(Thread);
     method public final boolean owns(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject);
     method public final boolean release(long);
     method public final boolean releaseShared(long);
@@ -71668,7 +71968,7 @@
     method public final void acquireSharedInterruptibly(int) throws java.lang.InterruptedException;
     method protected final boolean compareAndSetState(int, int);
     method public final java.util.Collection<java.lang.Thread> getExclusiveQueuedThreads();
-    method public final java.lang.Thread getFirstQueuedThread();
+    method public final Thread getFirstQueuedThread();
     method public final int getQueueLength();
     method public final java.util.Collection<java.lang.Thread> getQueuedThreads();
     method public final java.util.Collection<java.lang.Thread> getSharedQueuedThreads();
@@ -71680,7 +71980,7 @@
     method public final boolean hasQueuedThreads();
     method public final boolean hasWaiters(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject);
     method protected boolean isHeldExclusively();
-    method public final boolean isQueued(java.lang.Thread);
+    method public final boolean isQueued(Thread);
     method public final boolean owns(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject);
     method public final boolean release(int);
     method public final boolean releaseShared(int);
@@ -71707,51 +72007,51 @@
     method public final void signalAll();
   }
 
-  public abstract interface Condition {
-    method public abstract void await() throws java.lang.InterruptedException;
-    method public abstract boolean await(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract long awaitNanos(long) throws java.lang.InterruptedException;
-    method public abstract void awaitUninterruptibly();
-    method public abstract boolean awaitUntil(java.util.Date) throws java.lang.InterruptedException;
-    method public abstract void signal();
-    method public abstract void signalAll();
+  public interface Condition {
+    method public void await() throws java.lang.InterruptedException;
+    method public boolean await(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public long awaitNanos(long) throws java.lang.InterruptedException;
+    method public void awaitUninterruptibly();
+    method public boolean awaitUntil(java.util.Date) throws java.lang.InterruptedException;
+    method public void signal();
+    method public void signalAll();
   }
 
-  public abstract interface Lock {
-    method public abstract void lock();
-    method public abstract void lockInterruptibly() throws java.lang.InterruptedException;
-    method public abstract java.util.concurrent.locks.Condition newCondition();
-    method public abstract boolean tryLock();
-    method public abstract boolean tryLock(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
-    method public abstract void unlock();
+  public interface Lock {
+    method public void lock();
+    method public void lockInterruptibly() throws java.lang.InterruptedException;
+    method public java.util.concurrent.locks.Condition newCondition();
+    method public boolean tryLock();
+    method public boolean tryLock(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
+    method public void unlock();
   }
 
   public class LockSupport {
-    method public static java.lang.Object getBlocker(java.lang.Thread);
-    method public static void park(java.lang.Object);
+    method public static Object getBlocker(Thread);
+    method public static void park(Object);
     method public static void park();
-    method public static void parkNanos(java.lang.Object, long);
+    method public static void parkNanos(Object, long);
     method public static void parkNanos(long);
-    method public static void parkUntil(java.lang.Object, long);
+    method public static void parkUntil(Object, long);
     method public static void parkUntil(long);
-    method public static void unpark(java.lang.Thread);
+    method public static void unpark(Thread);
   }
 
-  public abstract interface ReadWriteLock {
-    method public abstract java.util.concurrent.locks.Lock readLock();
-    method public abstract java.util.concurrent.locks.Lock writeLock();
+  public interface ReadWriteLock {
+    method public java.util.concurrent.locks.Lock readLock();
+    method public java.util.concurrent.locks.Lock writeLock();
   }
 
   public class ReentrantLock implements java.util.concurrent.locks.Lock java.io.Serializable {
     ctor public ReentrantLock();
     ctor public ReentrantLock(boolean);
     method public int getHoldCount();
-    method protected java.lang.Thread getOwner();
+    method protected Thread getOwner();
     method public final int getQueueLength();
     method protected java.util.Collection<java.lang.Thread> getQueuedThreads();
     method public int getWaitQueueLength(java.util.concurrent.locks.Condition);
     method protected java.util.Collection<java.lang.Thread> getWaitingThreads(java.util.concurrent.locks.Condition);
-    method public final boolean hasQueuedThread(java.lang.Thread);
+    method public final boolean hasQueuedThread(Thread);
     method public final boolean hasQueuedThreads();
     method public boolean hasWaiters(java.util.concurrent.locks.Condition);
     method public final boolean isFair();
@@ -71768,7 +72068,7 @@
   public class ReentrantReadWriteLock implements java.util.concurrent.locks.ReadWriteLock java.io.Serializable {
     ctor public ReentrantReadWriteLock();
     ctor public ReentrantReadWriteLock(boolean);
-    method protected java.lang.Thread getOwner();
+    method protected Thread getOwner();
     method public final int getQueueLength();
     method protected java.util.Collection<java.lang.Thread> getQueuedReaderThreads();
     method protected java.util.Collection<java.lang.Thread> getQueuedThreads();
@@ -71778,7 +72078,7 @@
     method public int getWaitQueueLength(java.util.concurrent.locks.Condition);
     method protected java.util.Collection<java.lang.Thread> getWaitingThreads(java.util.concurrent.locks.Condition);
     method public int getWriteHoldCount();
-    method public final boolean hasQueuedThread(java.lang.Thread);
+    method public final boolean hasQueuedThread(Thread);
     method public final boolean hasQueuedThreads();
     method public boolean hasWaiters(java.util.concurrent.locks.Condition);
     method public final boolean isFair();
@@ -71842,210 +72142,210 @@
 
 package java.util.function {
 
-  public abstract interface BiConsumer<T, U> {
-    method public abstract void accept(T, U);
-    method public default java.util.function.BiConsumer<T, U> andThen(java.util.function.BiConsumer<? super T, ? super U>);
+  @java.lang.FunctionalInterface public interface BiConsumer<T, U> {
+    method public void accept(T, U);
+    method public default java.util.function.BiConsumer<T,U> andThen(java.util.function.BiConsumer<? super T,? super U>);
   }
 
-  public abstract interface BiFunction<T, U, R> {
-    method public default <V> java.util.function.BiFunction<T, U, V> andThen(java.util.function.Function<? super R, ? extends V>);
-    method public abstract R apply(T, U);
+  @java.lang.FunctionalInterface public interface BiFunction<T, U, R> {
+    method public default <V> java.util.function.BiFunction<T,U,V> andThen(java.util.function.Function<? super R,? extends V>);
+    method public R apply(T, U);
   }
 
-  public abstract interface BiPredicate<T, U> {
-    method public default java.util.function.BiPredicate<T, U> and(java.util.function.BiPredicate<? super T, ? super U>);
-    method public default java.util.function.BiPredicate<T, U> negate();
-    method public default java.util.function.BiPredicate<T, U> or(java.util.function.BiPredicate<? super T, ? super U>);
-    method public abstract boolean test(T, U);
+  @java.lang.FunctionalInterface public interface BiPredicate<T, U> {
+    method public default java.util.function.BiPredicate<T,U> and(java.util.function.BiPredicate<? super T,? super U>);
+    method public default java.util.function.BiPredicate<T,U> negate();
+    method public default java.util.function.BiPredicate<T,U> or(java.util.function.BiPredicate<? super T,? super U>);
+    method public boolean test(T, U);
   }
 
-  public abstract interface BinaryOperator<T> implements java.util.function.BiFunction {
+  @java.lang.FunctionalInterface public interface BinaryOperator<T> extends java.util.function.BiFunction<T,T,T> {
     method public static <T> java.util.function.BinaryOperator<T> maxBy(java.util.Comparator<? super T>);
     method public static <T> java.util.function.BinaryOperator<T> minBy(java.util.Comparator<? super T>);
   }
 
-  public abstract interface BooleanSupplier {
-    method public abstract boolean getAsBoolean();
+  @java.lang.FunctionalInterface public interface BooleanSupplier {
+    method public boolean getAsBoolean();
   }
 
-  public abstract interface Consumer<T> {
-    method public abstract void accept(T);
+  @java.lang.FunctionalInterface public interface Consumer<T> {
+    method public void accept(T);
     method public default java.util.function.Consumer<T> andThen(java.util.function.Consumer<? super T>);
   }
 
-  public abstract interface DoubleBinaryOperator {
-    method public abstract double applyAsDouble(double, double);
+  @java.lang.FunctionalInterface public interface DoubleBinaryOperator {
+    method public double applyAsDouble(double, double);
   }
 
-  public abstract interface DoubleConsumer {
-    method public abstract void accept(double);
+  @java.lang.FunctionalInterface public interface DoubleConsumer {
+    method public void accept(double);
     method public default java.util.function.DoubleConsumer andThen(java.util.function.DoubleConsumer);
   }
 
-  public abstract interface DoubleFunction<R> {
-    method public abstract R apply(double);
+  @java.lang.FunctionalInterface public interface DoubleFunction<R> {
+    method public R apply(double);
   }
 
-  public abstract interface DoublePredicate {
+  @java.lang.FunctionalInterface public interface DoublePredicate {
     method public default java.util.function.DoublePredicate and(java.util.function.DoublePredicate);
     method public default java.util.function.DoublePredicate negate();
     method public default java.util.function.DoublePredicate or(java.util.function.DoublePredicate);
-    method public abstract boolean test(double);
+    method public boolean test(double);
   }
 
-  public abstract interface DoubleSupplier {
-    method public abstract double getAsDouble();
+  @java.lang.FunctionalInterface public interface DoubleSupplier {
+    method public double getAsDouble();
   }
 
-  public abstract interface DoubleToIntFunction {
-    method public abstract int applyAsInt(double);
+  @java.lang.FunctionalInterface public interface DoubleToIntFunction {
+    method public int applyAsInt(double);
   }
 
-  public abstract interface DoubleToLongFunction {
-    method public abstract long applyAsLong(double);
+  @java.lang.FunctionalInterface public interface DoubleToLongFunction {
+    method public long applyAsLong(double);
   }
 
-  public abstract interface DoubleUnaryOperator {
+  @java.lang.FunctionalInterface public interface DoubleUnaryOperator {
     method public default java.util.function.DoubleUnaryOperator andThen(java.util.function.DoubleUnaryOperator);
-    method public abstract double applyAsDouble(double);
+    method public double applyAsDouble(double);
     method public default java.util.function.DoubleUnaryOperator compose(java.util.function.DoubleUnaryOperator);
     method public static java.util.function.DoubleUnaryOperator identity();
   }
 
-  public abstract interface Function<T, R> {
-    method public default <V> java.util.function.Function<T, V> andThen(java.util.function.Function<? super R, ? extends V>);
-    method public abstract R apply(T);
-    method public default <V> java.util.function.Function<V, R> compose(java.util.function.Function<? super V, ? extends T>);
-    method public static <T> java.util.function.Function<T, T> identity();
+  @java.lang.FunctionalInterface public interface Function<T, R> {
+    method public default <V> java.util.function.Function<T,V> andThen(java.util.function.Function<? super R,? extends V>);
+    method public R apply(T);
+    method public default <V> java.util.function.Function<V,R> compose(java.util.function.Function<? super V,? extends T>);
+    method public static <T> java.util.function.Function<T,T> identity();
   }
 
-  public abstract interface IntBinaryOperator {
-    method public abstract int applyAsInt(int, int);
+  @java.lang.FunctionalInterface public interface IntBinaryOperator {
+    method public int applyAsInt(int, int);
   }
 
-  public abstract interface IntConsumer {
-    method public abstract void accept(int);
+  @java.lang.FunctionalInterface public interface IntConsumer {
+    method public void accept(int);
     method public default java.util.function.IntConsumer andThen(java.util.function.IntConsumer);
   }
 
-  public abstract interface IntFunction<R> {
-    method public abstract R apply(int);
+  @java.lang.FunctionalInterface public interface IntFunction<R> {
+    method public R apply(int);
   }
 
-  public abstract interface IntPredicate {
+  @java.lang.FunctionalInterface public interface IntPredicate {
     method public default java.util.function.IntPredicate and(java.util.function.IntPredicate);
     method public default java.util.function.IntPredicate negate();
     method public default java.util.function.IntPredicate or(java.util.function.IntPredicate);
-    method public abstract boolean test(int);
+    method public boolean test(int);
   }
 
-  public abstract interface IntSupplier {
-    method public abstract int getAsInt();
+  @java.lang.FunctionalInterface public interface IntSupplier {
+    method public int getAsInt();
   }
 
-  public abstract interface IntToDoubleFunction {
-    method public abstract double applyAsDouble(int);
+  @java.lang.FunctionalInterface public interface IntToDoubleFunction {
+    method public double applyAsDouble(int);
   }
 
-  public abstract interface IntToLongFunction {
-    method public abstract long applyAsLong(int);
+  @java.lang.FunctionalInterface public interface IntToLongFunction {
+    method public long applyAsLong(int);
   }
 
-  public abstract interface IntUnaryOperator {
+  @java.lang.FunctionalInterface public interface IntUnaryOperator {
     method public default java.util.function.IntUnaryOperator andThen(java.util.function.IntUnaryOperator);
-    method public abstract int applyAsInt(int);
+    method public int applyAsInt(int);
     method public default java.util.function.IntUnaryOperator compose(java.util.function.IntUnaryOperator);
     method public static java.util.function.IntUnaryOperator identity();
   }
 
-  public abstract interface LongBinaryOperator {
-    method public abstract long applyAsLong(long, long);
+  @java.lang.FunctionalInterface public interface LongBinaryOperator {
+    method public long applyAsLong(long, long);
   }
 
-  public abstract interface LongConsumer {
-    method public abstract void accept(long);
+  @java.lang.FunctionalInterface public interface LongConsumer {
+    method public void accept(long);
     method public default java.util.function.LongConsumer andThen(java.util.function.LongConsumer);
   }
 
-  public abstract interface LongFunction<R> {
-    method public abstract R apply(long);
+  @java.lang.FunctionalInterface public interface LongFunction<R> {
+    method public R apply(long);
   }
 
-  public abstract interface LongPredicate {
+  @java.lang.FunctionalInterface public interface LongPredicate {
     method public default java.util.function.LongPredicate and(java.util.function.LongPredicate);
     method public default java.util.function.LongPredicate negate();
     method public default java.util.function.LongPredicate or(java.util.function.LongPredicate);
-    method public abstract boolean test(long);
+    method public boolean test(long);
   }
 
-  public abstract interface LongSupplier {
-    method public abstract long getAsLong();
+  @java.lang.FunctionalInterface public interface LongSupplier {
+    method public long getAsLong();
   }
 
-  public abstract interface LongToDoubleFunction {
-    method public abstract double applyAsDouble(long);
+  @java.lang.FunctionalInterface public interface LongToDoubleFunction {
+    method public double applyAsDouble(long);
   }
 
-  public abstract interface LongToIntFunction {
-    method public abstract int applyAsInt(long);
+  @java.lang.FunctionalInterface public interface LongToIntFunction {
+    method public int applyAsInt(long);
   }
 
-  public abstract interface LongUnaryOperator {
+  @java.lang.FunctionalInterface public interface LongUnaryOperator {
     method public default java.util.function.LongUnaryOperator andThen(java.util.function.LongUnaryOperator);
-    method public abstract long applyAsLong(long);
+    method public long applyAsLong(long);
     method public default java.util.function.LongUnaryOperator compose(java.util.function.LongUnaryOperator);
     method public static java.util.function.LongUnaryOperator identity();
   }
 
-  public abstract interface ObjDoubleConsumer<T> {
-    method public abstract void accept(T, double);
+  @java.lang.FunctionalInterface public interface ObjDoubleConsumer<T> {
+    method public void accept(T, double);
   }
 
-  public abstract interface ObjIntConsumer<T> {
-    method public abstract void accept(T, int);
+  @java.lang.FunctionalInterface public interface ObjIntConsumer<T> {
+    method public void accept(T, int);
   }
 
-  public abstract interface ObjLongConsumer<T> {
-    method public abstract void accept(T, long);
+  @java.lang.FunctionalInterface public interface ObjLongConsumer<T> {
+    method public void accept(T, long);
   }
 
-  public abstract interface Predicate<T> {
+  @java.lang.FunctionalInterface public interface Predicate<T> {
     method public default java.util.function.Predicate<T> and(java.util.function.Predicate<? super T>);
-    method public static <T> java.util.function.Predicate<T> isEqual(java.lang.Object);
+    method public static <T> java.util.function.Predicate<T> isEqual(Object);
     method public default java.util.function.Predicate<T> negate();
     method public default java.util.function.Predicate<T> or(java.util.function.Predicate<? super T>);
-    method public abstract boolean test(T);
+    method public boolean test(T);
   }
 
-  public abstract interface Supplier<T> {
-    method public abstract T get();
+  @java.lang.FunctionalInterface public interface Supplier<T> {
+    method public T get();
   }
 
-  public abstract interface ToDoubleBiFunction<T, U> {
-    method public abstract double applyAsDouble(T, U);
+  @java.lang.FunctionalInterface public interface ToDoubleBiFunction<T, U> {
+    method public double applyAsDouble(T, U);
   }
 
-  public abstract interface ToDoubleFunction<T> {
-    method public abstract double applyAsDouble(T);
+  @java.lang.FunctionalInterface public interface ToDoubleFunction<T> {
+    method public double applyAsDouble(T);
   }
 
-  public abstract interface ToIntBiFunction<T, U> {
-    method public abstract int applyAsInt(T, U);
+  @java.lang.FunctionalInterface public interface ToIntBiFunction<T, U> {
+    method public int applyAsInt(T, U);
   }
 
-  public abstract interface ToIntFunction<T> {
-    method public abstract int applyAsInt(T);
+  @java.lang.FunctionalInterface public interface ToIntFunction<T> {
+    method public int applyAsInt(T);
   }
 
-  public abstract interface ToLongBiFunction<T, U> {
-    method public abstract long applyAsLong(T, U);
+  @java.lang.FunctionalInterface public interface ToLongBiFunction<T, U> {
+    method public long applyAsLong(T, U);
   }
 
-  public abstract interface ToLongFunction<T> {
-    method public abstract long applyAsLong(T);
+  @java.lang.FunctionalInterface public interface ToLongFunction<T> {
+    method public long applyAsLong(T);
   }
 
-  public abstract interface UnaryOperator<T> implements java.util.function.Function {
+  @java.lang.FunctionalInterface public interface UnaryOperator<T> extends java.util.function.Function<T,T> {
     method public static <T> java.util.function.UnaryOperator<T> identity();
   }
 
@@ -72053,40 +72353,40 @@
 
 package java.util.jar {
 
-  public class Attributes implements java.lang.Cloneable java.util.Map {
+  public class Attributes implements java.lang.Cloneable java.util.Map<java.lang.Object,java.lang.Object> {
     ctor public Attributes();
     ctor public Attributes(int);
     ctor public Attributes(java.util.jar.Attributes);
     method public void clear();
-    method public java.lang.Object clone();
-    method public boolean containsKey(java.lang.Object);
-    method public boolean containsValue(java.lang.Object);
-    method public java.util.Set<java.util.Map.Entry<java.lang.Object, java.lang.Object>> entrySet();
-    method public java.lang.Object get(java.lang.Object);
-    method public java.lang.String getValue(java.lang.String);
-    method public java.lang.String getValue(java.util.jar.Attributes.Name);
+    method public Object clone();
+    method public boolean containsKey(Object);
+    method public boolean containsValue(Object);
+    method public java.util.Set<java.util.Map.Entry<java.lang.Object,java.lang.Object>> entrySet();
+    method public Object get(Object);
+    method public String getValue(String);
+    method public String getValue(java.util.jar.Attributes.Name);
     method public boolean isEmpty();
     method public java.util.Set<java.lang.Object> keySet();
-    method public java.lang.Object put(java.lang.Object, java.lang.Object);
-    method public void putAll(java.util.Map<?, ?>);
-    method public java.lang.String putValue(java.lang.String, java.lang.String);
-    method public java.lang.Object remove(java.lang.Object);
+    method public Object put(Object, Object);
+    method public void putAll(java.util.Map<?,?>);
+    method public String putValue(String, String);
+    method public Object remove(Object);
     method public int size();
     method public java.util.Collection<java.lang.Object> values();
-    field protected java.util.Map<java.lang.Object, java.lang.Object> map;
+    field protected java.util.Map<java.lang.Object,java.lang.Object> map;
   }
 
   public static class Attributes.Name {
-    ctor public Attributes.Name(java.lang.String);
+    ctor public Attributes.Name(String);
     field public static final java.util.jar.Attributes.Name CLASS_PATH;
     field public static final java.util.jar.Attributes.Name CONTENT_TYPE;
-    field public static final deprecated java.util.jar.Attributes.Name EXTENSION_INSTALLATION;
+    field @Deprecated public static final java.util.jar.Attributes.Name EXTENSION_INSTALLATION;
     field public static final java.util.jar.Attributes.Name EXTENSION_LIST;
     field public static final java.util.jar.Attributes.Name EXTENSION_NAME;
     field public static final java.util.jar.Attributes.Name IMPLEMENTATION_TITLE;
-    field public static final deprecated java.util.jar.Attributes.Name IMPLEMENTATION_URL;
+    field @Deprecated public static final java.util.jar.Attributes.Name IMPLEMENTATION_URL;
     field public static final java.util.jar.Attributes.Name IMPLEMENTATION_VENDOR;
-    field public static final deprecated java.util.jar.Attributes.Name IMPLEMENTATION_VENDOR_ID;
+    field @Deprecated public static final java.util.jar.Attributes.Name IMPLEMENTATION_VENDOR_ID;
     field public static final java.util.jar.Attributes.Name IMPLEMENTATION_VERSION;
     field public static final java.util.jar.Attributes.Name MAIN_CLASS;
     field public static final java.util.jar.Attributes.Name MANIFEST_VERSION;
@@ -72098,7 +72398,7 @@
   }
 
   public class JarEntry extends java.util.zip.ZipEntry {
-    ctor public JarEntry(java.lang.String);
+    ctor public JarEntry(String);
     ctor public JarEntry(java.util.zip.ZipEntry);
     ctor public JarEntry(java.util.jar.JarEntry);
     method public java.util.jar.Attributes getAttributes() throws java.io.IOException;
@@ -72148,18 +72448,17 @@
 
   public class JarException extends java.util.zip.ZipException {
     ctor public JarException();
-    ctor public JarException(java.lang.String);
+    ctor public JarException(String);
   }
 
   public class JarFile extends java.util.zip.ZipFile {
-    ctor public JarFile(java.lang.String) throws java.io.IOException;
-    ctor public JarFile(java.lang.String, boolean) throws java.io.IOException;
+    ctor public JarFile(String) throws java.io.IOException;
+    ctor public JarFile(String, boolean) throws java.io.IOException;
     ctor public JarFile(java.io.File) throws java.io.IOException;
     ctor public JarFile(java.io.File, boolean) throws java.io.IOException;
     ctor public JarFile(java.io.File, boolean, int) throws java.io.IOException;
     method public java.util.Enumeration<java.util.jar.JarEntry> entries();
-    method public synchronized java.io.InputStream getInputStream(java.util.zip.ZipEntry) throws java.io.IOException;
-    method public java.util.jar.JarEntry getJarEntry(java.lang.String);
+    method public java.util.jar.JarEntry getJarEntry(String);
     method public java.util.jar.Manifest getManifest() throws java.io.IOException;
     method public java.util.stream.Stream<java.util.jar.JarEntry> stream();
     field public static final int CENATT = 36; // 0x24
@@ -72202,7 +72501,7 @@
     field public static final int LOCSIZ = 18; // 0x12
     field public static final int LOCTIM = 10; // 0xa
     field public static final int LOCVER = 4; // 0x4
-    field public static final java.lang.String MANIFEST_NAME = "META-INF/MANIFEST.MF";
+    field public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
   }
 
   public class JarInputStream extends java.util.zip.ZipInputStream {
@@ -72302,57 +72601,57 @@
     ctor public Manifest(java.io.InputStream) throws java.io.IOException;
     ctor public Manifest(java.util.jar.Manifest);
     method public void clear();
-    method public java.lang.Object clone();
-    method public java.util.jar.Attributes getAttributes(java.lang.String);
-    method public java.util.Map<java.lang.String, java.util.jar.Attributes> getEntries();
+    method public Object clone();
+    method public java.util.jar.Attributes getAttributes(String);
+    method public java.util.Map<java.lang.String,java.util.jar.Attributes> getEntries();
     method public java.util.jar.Attributes getMainAttributes();
     method public void read(java.io.InputStream) throws java.io.IOException;
     method public void write(java.io.OutputStream) throws java.io.IOException;
   }
 
   public abstract class Pack200 {
-    method public static synchronized java.util.jar.Pack200.Packer newPacker();
+    method public static java.util.jar.Pack200.Packer newPacker();
     method public static java.util.jar.Pack200.Unpacker newUnpacker();
   }
 
-  public static abstract interface Pack200.Packer {
-    method public default deprecated void addPropertyChangeListener(java.beans.PropertyChangeListener);
-    method public abstract void pack(java.util.jar.JarFile, java.io.OutputStream) throws java.io.IOException;
-    method public abstract void pack(java.util.jar.JarInputStream, java.io.OutputStream) throws java.io.IOException;
-    method public abstract java.util.SortedMap<java.lang.String, java.lang.String> properties();
-    method public default deprecated void removePropertyChangeListener(java.beans.PropertyChangeListener);
-    field public static final java.lang.String CLASS_ATTRIBUTE_PFX = "pack.class.attribute.";
-    field public static final java.lang.String CODE_ATTRIBUTE_PFX = "pack.code.attribute.";
-    field public static final java.lang.String DEFLATE_HINT = "pack.deflate.hint";
-    field public static final java.lang.String EFFORT = "pack.effort";
-    field public static final java.lang.String ERROR = "error";
-    field public static final java.lang.String FALSE = "false";
-    field public static final java.lang.String FIELD_ATTRIBUTE_PFX = "pack.field.attribute.";
-    field public static final java.lang.String KEEP = "keep";
-    field public static final java.lang.String KEEP_FILE_ORDER = "pack.keep.file.order";
-    field public static final java.lang.String LATEST = "latest";
-    field public static final java.lang.String METHOD_ATTRIBUTE_PFX = "pack.method.attribute.";
-    field public static final java.lang.String MODIFICATION_TIME = "pack.modification.time";
-    field public static final java.lang.String PASS = "pass";
-    field public static final java.lang.String PASS_FILE_PFX = "pack.pass.file.";
-    field public static final java.lang.String PROGRESS = "pack.progress";
-    field public static final java.lang.String SEGMENT_LIMIT = "pack.segment.limit";
-    field public static final java.lang.String STRIP = "strip";
-    field public static final java.lang.String TRUE = "true";
-    field public static final java.lang.String UNKNOWN_ATTRIBUTE = "pack.unknown.attribute";
+  public static interface Pack200.Packer {
+    method @Deprecated public default void addPropertyChangeListener(java.beans.PropertyChangeListener);
+    method public void pack(java.util.jar.JarFile, java.io.OutputStream) throws java.io.IOException;
+    method public void pack(java.util.jar.JarInputStream, java.io.OutputStream) throws java.io.IOException;
+    method public java.util.SortedMap<java.lang.String,java.lang.String> properties();
+    method @Deprecated public default void removePropertyChangeListener(java.beans.PropertyChangeListener);
+    field public static final String CLASS_ATTRIBUTE_PFX = "pack.class.attribute.";
+    field public static final String CODE_ATTRIBUTE_PFX = "pack.code.attribute.";
+    field public static final String DEFLATE_HINT = "pack.deflate.hint";
+    field public static final String EFFORT = "pack.effort";
+    field public static final String ERROR = "error";
+    field public static final String FALSE = "false";
+    field public static final String FIELD_ATTRIBUTE_PFX = "pack.field.attribute.";
+    field public static final String KEEP = "keep";
+    field public static final String KEEP_FILE_ORDER = "pack.keep.file.order";
+    field public static final String LATEST = "latest";
+    field public static final String METHOD_ATTRIBUTE_PFX = "pack.method.attribute.";
+    field public static final String MODIFICATION_TIME = "pack.modification.time";
+    field public static final String PASS = "pass";
+    field public static final String PASS_FILE_PFX = "pack.pass.file.";
+    field public static final String PROGRESS = "pack.progress";
+    field public static final String SEGMENT_LIMIT = "pack.segment.limit";
+    field public static final String STRIP = "strip";
+    field public static final String TRUE = "true";
+    field public static final String UNKNOWN_ATTRIBUTE = "pack.unknown.attribute";
   }
 
-  public static abstract interface Pack200.Unpacker {
-    method public default deprecated void addPropertyChangeListener(java.beans.PropertyChangeListener);
-    method public abstract java.util.SortedMap<java.lang.String, java.lang.String> properties();
-    method public default deprecated void removePropertyChangeListener(java.beans.PropertyChangeListener);
-    method public abstract void unpack(java.io.InputStream, java.util.jar.JarOutputStream) throws java.io.IOException;
-    method public abstract void unpack(java.io.File, java.util.jar.JarOutputStream) throws java.io.IOException;
-    field public static final java.lang.String DEFLATE_HINT = "unpack.deflate.hint";
-    field public static final java.lang.String FALSE = "false";
-    field public static final java.lang.String KEEP = "keep";
-    field public static final java.lang.String PROGRESS = "unpack.progress";
-    field public static final java.lang.String TRUE = "true";
+  public static interface Pack200.Unpacker {
+    method @Deprecated public default void addPropertyChangeListener(java.beans.PropertyChangeListener);
+    method public java.util.SortedMap<java.lang.String,java.lang.String> properties();
+    method @Deprecated public default void removePropertyChangeListener(java.beans.PropertyChangeListener);
+    method public void unpack(java.io.InputStream, java.util.jar.JarOutputStream) throws java.io.IOException;
+    method public void unpack(java.io.File, java.util.jar.JarOutputStream) throws java.io.IOException;
+    field public static final String DEFLATE_HINT = "unpack.deflate.hint";
+    field public static final String FALSE = "false";
+    field public static final String KEEP = "keep";
+    field public static final String PROGRESS = "unpack.progress";
+    field public static final String TRUE = "true";
   }
 
 }
@@ -72362,12 +72661,11 @@
   public class ConsoleHandler extends java.util.logging.StreamHandler {
     ctor public ConsoleHandler();
     method public void close();
-    method public void publish(java.util.logging.LogRecord);
   }
 
   public class ErrorManager {
     ctor public ErrorManager();
-    method public synchronized void error(java.lang.String, java.lang.Exception, int);
+    method public void error(String, Exception, int);
     field public static final int CLOSE_FAILURE = 3; // 0x3
     field public static final int FLUSH_FAILURE = 2; // 0x2
     field public static final int FORMAT_FAILURE = 5; // 0x5
@@ -72378,183 +72676,183 @@
 
   public class FileHandler extends java.util.logging.StreamHandler {
     ctor public FileHandler() throws java.io.IOException, java.lang.SecurityException;
-    ctor public FileHandler(java.lang.String) throws java.io.IOException, java.lang.SecurityException;
-    ctor public FileHandler(java.lang.String, boolean) throws java.io.IOException, java.lang.SecurityException;
-    ctor public FileHandler(java.lang.String, int, int) throws java.io.IOException, java.lang.SecurityException;
-    ctor public FileHandler(java.lang.String, int, int, boolean) throws java.io.IOException, java.lang.SecurityException;
+    ctor public FileHandler(String) throws java.io.IOException, java.lang.SecurityException;
+    ctor public FileHandler(String, boolean) throws java.io.IOException, java.lang.SecurityException;
+    ctor public FileHandler(String, int, int) throws java.io.IOException, java.lang.SecurityException;
+    ctor public FileHandler(String, int, int, boolean) throws java.io.IOException, java.lang.SecurityException;
   }
 
-  public abstract interface Filter {
-    method public abstract boolean isLoggable(java.util.logging.LogRecord);
+  @java.lang.FunctionalInterface public interface Filter {
+    method public boolean isLoggable(java.util.logging.LogRecord);
   }
 
   public abstract class Formatter {
     ctor protected Formatter();
-    method public abstract java.lang.String format(java.util.logging.LogRecord);
-    method public synchronized java.lang.String formatMessage(java.util.logging.LogRecord);
-    method public java.lang.String getHead(java.util.logging.Handler);
-    method public java.lang.String getTail(java.util.logging.Handler);
+    method public abstract String format(java.util.logging.LogRecord);
+    method public String formatMessage(java.util.logging.LogRecord);
+    method public String getHead(java.util.logging.Handler);
+    method public String getTail(java.util.logging.Handler);
   }
 
   public abstract class Handler {
     ctor protected Handler();
     method public abstract void close() throws java.lang.SecurityException;
     method public abstract void flush();
-    method public java.lang.String getEncoding();
+    method public String getEncoding();
     method public java.util.logging.ErrorManager getErrorManager();
     method public java.util.logging.Filter getFilter();
     method public java.util.logging.Formatter getFormatter();
     method public java.util.logging.Level getLevel();
     method public boolean isLoggable(java.util.logging.LogRecord);
     method public abstract void publish(java.util.logging.LogRecord);
-    method protected void reportError(java.lang.String, java.lang.Exception, int);
-    method public synchronized void setEncoding(java.lang.String) throws java.lang.SecurityException, java.io.UnsupportedEncodingException;
-    method public synchronized void setErrorManager(java.util.logging.ErrorManager);
-    method public synchronized void setFilter(java.util.logging.Filter) throws java.lang.SecurityException;
-    method public synchronized void setFormatter(java.util.logging.Formatter) throws java.lang.SecurityException;
-    method public synchronized void setLevel(java.util.logging.Level) throws java.lang.SecurityException;
+    method protected void reportError(String, Exception, int);
+    method public void setEncoding(String) throws java.lang.SecurityException, java.io.UnsupportedEncodingException;
+    method public void setErrorManager(java.util.logging.ErrorManager);
+    method public void setFilter(java.util.logging.Filter) throws java.lang.SecurityException;
+    method public void setFormatter(java.util.logging.Formatter) throws java.lang.SecurityException;
+    method public void setLevel(java.util.logging.Level) throws java.lang.SecurityException;
   }
 
   public class Level implements java.io.Serializable {
-    ctor protected Level(java.lang.String, int);
-    ctor protected Level(java.lang.String, int, java.lang.String);
-    method public java.lang.String getLocalizedName();
-    method public java.lang.String getName();
-    method public java.lang.String getResourceBundleName();
+    ctor protected Level(@NonNull String, int);
+    ctor protected Level(@NonNull String, int, @Nullable String);
+    method @NonNull public String getLocalizedName();
+    method @NonNull public String getName();
+    method @Nullable public String getResourceBundleName();
     method public final int intValue();
-    method public static synchronized java.util.logging.Level parse(java.lang.String) throws java.lang.IllegalArgumentException;
-    method public final java.lang.String toString();
-    field public static final java.util.logging.Level ALL;
-    field public static final java.util.logging.Level CONFIG;
-    field public static final java.util.logging.Level FINE;
-    field public static final java.util.logging.Level FINER;
-    field public static final java.util.logging.Level FINEST;
-    field public static final java.util.logging.Level INFO;
-    field public static final java.util.logging.Level OFF;
-    field public static final java.util.logging.Level SEVERE;
-    field public static final java.util.logging.Level WARNING;
+    method @NonNull public static java.util.logging.Level parse(@NonNull String) throws java.lang.IllegalArgumentException;
+    method @NonNull public final String toString();
+    field @NonNull public static final java.util.logging.Level ALL;
+    field @NonNull public static final java.util.logging.Level CONFIG;
+    field @NonNull public static final java.util.logging.Level FINE;
+    field @NonNull public static final java.util.logging.Level FINER;
+    field @NonNull public static final java.util.logging.Level FINEST;
+    field @NonNull public static final java.util.logging.Level INFO;
+    field @NonNull public static final java.util.logging.Level OFF;
+    field @NonNull public static final java.util.logging.Level SEVERE;
+    field @NonNull public static final java.util.logging.Level WARNING;
   }
 
   public class LogManager {
     ctor protected LogManager();
     method public boolean addLogger(java.util.logging.Logger);
-    method public deprecated void addPropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
+    method @Deprecated public void addPropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
     method public void checkAccess() throws java.lang.SecurityException;
     method public static java.util.logging.LogManager getLogManager();
-    method public java.util.logging.Logger getLogger(java.lang.String);
+    method public java.util.logging.Logger getLogger(String);
     method public java.util.Enumeration<java.lang.String> getLoggerNames();
-    method public static synchronized java.util.logging.LoggingMXBean getLoggingMXBean();
-    method public java.lang.String getProperty(java.lang.String);
+    method public static java.util.logging.LoggingMXBean getLoggingMXBean();
+    method public String getProperty(String);
     method public void readConfiguration() throws java.io.IOException, java.lang.SecurityException;
     method public void readConfiguration(java.io.InputStream) throws java.io.IOException, java.lang.SecurityException;
-    method public deprecated void removePropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
+    method @Deprecated public void removePropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
     method public void reset() throws java.lang.SecurityException;
-    field public static final java.lang.String LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging";
+    field public static final String LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging";
   }
 
   public class LogRecord implements java.io.Serializable {
-    ctor public LogRecord(java.util.logging.Level, java.lang.String);
+    ctor public LogRecord(java.util.logging.Level, String);
     method public java.util.logging.Level getLevel();
-    method public java.lang.String getLoggerName();
-    method public java.lang.String getMessage();
+    method public String getLoggerName();
+    method public String getMessage();
     method public long getMillis();
-    method public java.lang.Object[] getParameters();
+    method public Object[] getParameters();
     method public java.util.ResourceBundle getResourceBundle();
-    method public java.lang.String getResourceBundleName();
+    method public String getResourceBundleName();
     method public long getSequenceNumber();
-    method public java.lang.String getSourceClassName();
-    method public java.lang.String getSourceMethodName();
+    method public String getSourceClassName();
+    method public String getSourceMethodName();
     method public int getThreadID();
-    method public java.lang.Throwable getThrown();
+    method public Throwable getThrown();
     method public void setLevel(java.util.logging.Level);
-    method public void setLoggerName(java.lang.String);
-    method public void setMessage(java.lang.String);
+    method public void setLoggerName(String);
+    method public void setMessage(String);
     method public void setMillis(long);
-    method public void setParameters(java.lang.Object[]);
+    method public void setParameters(Object[]);
     method public void setResourceBundle(java.util.ResourceBundle);
-    method public void setResourceBundleName(java.lang.String);
+    method public void setResourceBundleName(String);
     method public void setSequenceNumber(long);
-    method public void setSourceClassName(java.lang.String);
-    method public void setSourceMethodName(java.lang.String);
+    method public void setSourceClassName(String);
+    method public void setSourceMethodName(String);
     method public void setThreadID(int);
-    method public void setThrown(java.lang.Throwable);
+    method public void setThrown(Throwable);
   }
 
   public class Logger {
-    ctor protected Logger(java.lang.String, java.lang.String);
-    method public void addHandler(java.util.logging.Handler) throws java.lang.SecurityException;
-    method public void config(java.lang.String);
-    method public void config(java.util.function.Supplier<java.lang.String>);
-    method public void entering(java.lang.String, java.lang.String);
-    method public void entering(java.lang.String, java.lang.String, java.lang.Object);
-    method public void entering(java.lang.String, java.lang.String, java.lang.Object[]);
-    method public void exiting(java.lang.String, java.lang.String);
-    method public void exiting(java.lang.String, java.lang.String, java.lang.Object);
-    method public void fine(java.lang.String);
-    method public void fine(java.util.function.Supplier<java.lang.String>);
-    method public void finer(java.lang.String);
-    method public void finer(java.util.function.Supplier<java.lang.String>);
-    method public void finest(java.lang.String);
-    method public void finest(java.util.function.Supplier<java.lang.String>);
-    method public static java.util.logging.Logger getAnonymousLogger();
-    method public static java.util.logging.Logger getAnonymousLogger(java.lang.String);
-    method public java.util.logging.Filter getFilter();
-    method public static final java.util.logging.Logger getGlobal();
+    ctor protected Logger(@Nullable String, @Nullable String);
+    method public void addHandler(@NonNull java.util.logging.Handler) throws java.lang.SecurityException;
+    method public void config(@Nullable String);
+    method public void config(@NonNull java.util.function.Supplier<java.lang.String>);
+    method public void entering(@Nullable String, @Nullable String);
+    method public void entering(@Nullable String, @Nullable String, @Nullable Object);
+    method public void entering(@Nullable String, @Nullable String, Object[]);
+    method public void exiting(@Nullable String, @Nullable String);
+    method public void exiting(@Nullable String, @Nullable String, @Nullable Object);
+    method public void fine(@Nullable String);
+    method public void fine(@NonNull java.util.function.Supplier<java.lang.String>);
+    method public void finer(@Nullable String);
+    method public void finer(@NonNull java.util.function.Supplier<java.lang.String>);
+    method public void finest(@Nullable String);
+    method public void finest(@NonNull java.util.function.Supplier<java.lang.String>);
+    method @NonNull public static java.util.logging.Logger getAnonymousLogger();
+    method @NonNull public static java.util.logging.Logger getAnonymousLogger(@Nullable String);
+    method @Nullable public java.util.logging.Filter getFilter();
+    method @NonNull public static final java.util.logging.Logger getGlobal();
     method public java.util.logging.Handler[] getHandlers();
-    method public java.util.logging.Level getLevel();
-    method public static java.util.logging.Logger getLogger(java.lang.String);
-    method public static java.util.logging.Logger getLogger(java.lang.String, java.lang.String);
-    method public java.lang.String getName();
-    method public java.util.logging.Logger getParent();
-    method public java.util.ResourceBundle getResourceBundle();
-    method public java.lang.String getResourceBundleName();
+    method @Nullable public java.util.logging.Level getLevel();
+    method @NonNull public static java.util.logging.Logger getLogger(@NonNull String);
+    method @NonNull public static java.util.logging.Logger getLogger(@NonNull String, @Nullable String);
+    method @Nullable public String getName();
+    method @Nullable public java.util.logging.Logger getParent();
+    method @Nullable public java.util.ResourceBundle getResourceBundle();
+    method @Nullable public String getResourceBundleName();
     method public boolean getUseParentHandlers();
-    method public void info(java.lang.String);
-    method public void info(java.util.function.Supplier<java.lang.String>);
-    method public boolean isLoggable(java.util.logging.Level);
-    method public void log(java.util.logging.LogRecord);
-    method public void log(java.util.logging.Level, java.lang.String);
-    method public void log(java.util.logging.Level, java.util.function.Supplier<java.lang.String>);
-    method public void log(java.util.logging.Level, java.lang.String, java.lang.Object);
-    method public void log(java.util.logging.Level, java.lang.String, java.lang.Object[]);
-    method public void log(java.util.logging.Level, java.lang.String, java.lang.Throwable);
-    method public void log(java.util.logging.Level, java.lang.Throwable, java.util.function.Supplier<java.lang.String>);
-    method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String);
-    method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.util.function.Supplier<java.lang.String>);
-    method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Object);
-    method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[]);
-    method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable);
-    method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.Throwable, java.util.function.Supplier<java.lang.String>);
-    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object);
-    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[]);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.util.ResourceBundle, java.lang.String, java.lang.Object...);
-    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.util.ResourceBundle, java.lang.String, java.lang.Throwable);
-    method public void removeHandler(java.util.logging.Handler) throws java.lang.SecurityException;
-    method public void setFilter(java.util.logging.Filter) throws java.lang.SecurityException;
-    method public void setLevel(java.util.logging.Level) throws java.lang.SecurityException;
-    method public void setParent(java.util.logging.Logger);
-    method public void setResourceBundle(java.util.ResourceBundle);
+    method public void info(@Nullable String);
+    method public void info(@NonNull java.util.function.Supplier<java.lang.String>);
+    method public boolean isLoggable(@NonNull java.util.logging.Level);
+    method public void log(@NonNull java.util.logging.LogRecord);
+    method public void log(@NonNull java.util.logging.Level, @Nullable String);
+    method public void log(@NonNull java.util.logging.Level, @NonNull java.util.function.Supplier<java.lang.String>);
+    method public void log(@NonNull java.util.logging.Level, @Nullable String, @Nullable Object);
+    method public void log(@NonNull java.util.logging.Level, @Nullable String, Object[]);
+    method public void log(@NonNull java.util.logging.Level, @Nullable String, @Nullable Throwable);
+    method public void log(@NonNull java.util.logging.Level, @Nullable Throwable, @NonNull java.util.function.Supplier<java.lang.String>);
+    method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String);
+    method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @NonNull java.util.function.Supplier<java.lang.String>);
+    method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable Object);
+    method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, Object[]);
+    method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable Throwable);
+    method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable Throwable, @NonNull java.util.function.Supplier<java.lang.String>);
+    method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String);
+    method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String, @Nullable Object);
+    method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String, Object[]);
+    method public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable java.util.ResourceBundle, @Nullable String, java.lang.Object...);
+    method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String, @Nullable Throwable);
+    method public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable java.util.ResourceBundle, @Nullable String, @Nullable Throwable);
+    method public void removeHandler(@Nullable java.util.logging.Handler) throws java.lang.SecurityException;
+    method public void setFilter(@Nullable java.util.logging.Filter) throws java.lang.SecurityException;
+    method public void setLevel(@Nullable java.util.logging.Level) throws java.lang.SecurityException;
+    method public void setParent(@NonNull java.util.logging.Logger);
+    method public void setResourceBundle(@NonNull java.util.ResourceBundle);
     method public void setUseParentHandlers(boolean);
-    method public void severe(java.lang.String);
-    method public void severe(java.util.function.Supplier<java.lang.String>);
-    method public void throwing(java.lang.String, java.lang.String, java.lang.Throwable);
-    method public void warning(java.lang.String);
-    method public void warning(java.util.function.Supplier<java.lang.String>);
-    field public static final java.lang.String GLOBAL_LOGGER_NAME = "global";
-    field public static final deprecated java.util.logging.Logger global;
+    method public void severe(@Nullable String);
+    method public void severe(@NonNull java.util.function.Supplier<java.lang.String>);
+    method public void throwing(@Nullable String, @Nullable String, @Nullable Throwable);
+    method public void warning(@Nullable String);
+    method public void warning(@NonNull java.util.function.Supplier<java.lang.String>);
+    field @NonNull public static final String GLOBAL_LOGGER_NAME = "global";
+    field @Deprecated @NonNull public static final java.util.logging.Logger global;
   }
 
-  public abstract interface LoggingMXBean {
-    method public abstract java.lang.String getLoggerLevel(java.lang.String);
-    method public abstract java.util.List<java.lang.String> getLoggerNames();
-    method public abstract java.lang.String getParentLoggerName(java.lang.String);
-    method public abstract void setLoggerLevel(java.lang.String, java.lang.String);
+  public interface LoggingMXBean {
+    method public String getLoggerLevel(String);
+    method public java.util.List<java.lang.String> getLoggerNames();
+    method public String getParentLoggerName(String);
+    method public void setLoggerLevel(String, String);
   }
 
   public final class LoggingPermission extends java.security.BasicPermission {
-    ctor public LoggingPermission(java.lang.String, java.lang.String) throws java.lang.IllegalArgumentException;
+    ctor public LoggingPermission(String, String) throws java.lang.IllegalArgumentException;
   }
 
   public class MemoryHandler extends java.util.logging.Handler {
@@ -72563,33 +72861,33 @@
     method public void close() throws java.lang.SecurityException;
     method public void flush();
     method public java.util.logging.Level getPushLevel();
-    method public synchronized void publish(java.util.logging.LogRecord);
-    method public synchronized void push();
-    method public synchronized void setPushLevel(java.util.logging.Level) throws java.lang.SecurityException;
+    method public void publish(java.util.logging.LogRecord);
+    method public void push();
+    method public void setPushLevel(java.util.logging.Level) throws java.lang.SecurityException;
   }
 
   public class SimpleFormatter extends java.util.logging.Formatter {
     ctor public SimpleFormatter();
-    method public synchronized java.lang.String format(java.util.logging.LogRecord);
+    method public String format(java.util.logging.LogRecord);
   }
 
   public class SocketHandler extends java.util.logging.StreamHandler {
     ctor public SocketHandler() throws java.io.IOException;
-    ctor public SocketHandler(java.lang.String, int) throws java.io.IOException;
+    ctor public SocketHandler(String, int) throws java.io.IOException;
   }
 
   public class StreamHandler extends java.util.logging.Handler {
     ctor public StreamHandler();
     ctor public StreamHandler(java.io.OutputStream, java.util.logging.Formatter);
-    method public synchronized void close() throws java.lang.SecurityException;
-    method public synchronized void flush();
-    method public synchronized void publish(java.util.logging.LogRecord);
-    method protected synchronized void setOutputStream(java.io.OutputStream) throws java.lang.SecurityException;
+    method public void close() throws java.lang.SecurityException;
+    method public void flush();
+    method public void publish(java.util.logging.LogRecord);
+    method protected void setOutputStream(java.io.OutputStream) throws java.lang.SecurityException;
   }
 
   public class XMLFormatter extends java.util.logging.Formatter {
     ctor public XMLFormatter();
-    method public java.lang.String format(java.util.logging.LogRecord);
+    method public String format(java.util.logging.LogRecord);
   }
 
 }
@@ -72597,65 +72895,65 @@
 package java.util.prefs {
 
   public abstract class AbstractPreferences extends java.util.prefs.Preferences {
-    ctor protected AbstractPreferences(java.util.prefs.AbstractPreferences, java.lang.String);
-    method public java.lang.String absolutePath();
+    ctor protected AbstractPreferences(java.util.prefs.AbstractPreferences, String);
+    method public String absolutePath();
     method public void addNodeChangeListener(java.util.prefs.NodeChangeListener);
     method public void addPreferenceChangeListener(java.util.prefs.PreferenceChangeListener);
     method protected final java.util.prefs.AbstractPreferences[] cachedChildren();
-    method protected abstract java.util.prefs.AbstractPreferences childSpi(java.lang.String);
-    method public java.lang.String[] childrenNames() throws java.util.prefs.BackingStoreException;
-    method protected abstract java.lang.String[] childrenNamesSpi() throws java.util.prefs.BackingStoreException;
+    method protected abstract java.util.prefs.AbstractPreferences childSpi(String);
+    method public String[] childrenNames() throws java.util.prefs.BackingStoreException;
+    method protected abstract String[] childrenNamesSpi() throws java.util.prefs.BackingStoreException;
     method public void clear() throws java.util.prefs.BackingStoreException;
     method public void exportNode(java.io.OutputStream) throws java.util.prefs.BackingStoreException, java.io.IOException;
     method public void exportSubtree(java.io.OutputStream) throws java.util.prefs.BackingStoreException, java.io.IOException;
     method public void flush() throws java.util.prefs.BackingStoreException;
     method protected abstract void flushSpi() throws java.util.prefs.BackingStoreException;
-    method public java.lang.String get(java.lang.String, java.lang.String);
-    method public boolean getBoolean(java.lang.String, boolean);
-    method public byte[] getByteArray(java.lang.String, byte[]);
-    method protected java.util.prefs.AbstractPreferences getChild(java.lang.String) throws java.util.prefs.BackingStoreException;
-    method public double getDouble(java.lang.String, double);
-    method public float getFloat(java.lang.String, float);
-    method public int getInt(java.lang.String, int);
-    method public long getLong(java.lang.String, long);
-    method protected abstract java.lang.String getSpi(java.lang.String);
+    method public String get(String, String);
+    method public boolean getBoolean(String, boolean);
+    method public byte[] getByteArray(String, byte[]);
+    method protected java.util.prefs.AbstractPreferences getChild(String) throws java.util.prefs.BackingStoreException;
+    method public double getDouble(String, double);
+    method public float getFloat(String, float);
+    method public int getInt(String, int);
+    method public long getLong(String, long);
+    method protected abstract String getSpi(String);
     method protected boolean isRemoved();
     method public boolean isUserNode();
-    method public java.lang.String[] keys() throws java.util.prefs.BackingStoreException;
-    method protected abstract java.lang.String[] keysSpi() throws java.util.prefs.BackingStoreException;
-    method public java.lang.String name();
-    method public java.util.prefs.Preferences node(java.lang.String);
-    method public boolean nodeExists(java.lang.String) throws java.util.prefs.BackingStoreException;
+    method public String[] keys() throws java.util.prefs.BackingStoreException;
+    method protected abstract String[] keysSpi() throws java.util.prefs.BackingStoreException;
+    method public String name();
+    method public java.util.prefs.Preferences node(String);
+    method public boolean nodeExists(String) throws java.util.prefs.BackingStoreException;
     method public java.util.prefs.Preferences parent();
-    method public void put(java.lang.String, java.lang.String);
-    method public void putBoolean(java.lang.String, boolean);
-    method public void putByteArray(java.lang.String, byte[]);
-    method public void putDouble(java.lang.String, double);
-    method public void putFloat(java.lang.String, float);
-    method public void putInt(java.lang.String, int);
-    method public void putLong(java.lang.String, long);
-    method protected abstract void putSpi(java.lang.String, java.lang.String);
-    method public void remove(java.lang.String);
+    method public void put(String, String);
+    method public void putBoolean(String, boolean);
+    method public void putByteArray(String, byte[]);
+    method public void putDouble(String, double);
+    method public void putFloat(String, float);
+    method public void putInt(String, int);
+    method public void putLong(String, long);
+    method protected abstract void putSpi(String, String);
+    method public void remove(String);
     method public void removeNode() throws java.util.prefs.BackingStoreException;
     method public void removeNodeChangeListener(java.util.prefs.NodeChangeListener);
     method protected abstract void removeNodeSpi() throws java.util.prefs.BackingStoreException;
     method public void removePreferenceChangeListener(java.util.prefs.PreferenceChangeListener);
-    method protected abstract void removeSpi(java.lang.String);
+    method protected abstract void removeSpi(String);
     method public void sync() throws java.util.prefs.BackingStoreException;
     method protected abstract void syncSpi() throws java.util.prefs.BackingStoreException;
-    field protected final java.lang.Object lock;
+    field protected final Object lock;
     field protected boolean newNode;
   }
 
   public class BackingStoreException extends java.lang.Exception {
-    ctor public BackingStoreException(java.lang.String);
-    ctor public BackingStoreException(java.lang.Throwable);
+    ctor public BackingStoreException(String);
+    ctor public BackingStoreException(Throwable);
   }
 
   public class InvalidPreferencesFormatException extends java.lang.Exception {
-    ctor public InvalidPreferencesFormatException(java.lang.Throwable);
-    ctor public InvalidPreferencesFormatException(java.lang.String);
-    ctor public InvalidPreferencesFormatException(java.lang.String, java.lang.Throwable);
+    ctor public InvalidPreferencesFormatException(Throwable);
+    ctor public InvalidPreferencesFormatException(String);
+    ctor public InvalidPreferencesFormatException(String, Throwable);
   }
 
   public class NodeChangeEvent extends java.util.EventObject {
@@ -72664,135 +72962,135 @@
     method public java.util.prefs.Preferences getParent();
   }
 
-  public abstract interface NodeChangeListener implements java.util.EventListener {
-    method public abstract void childAdded(java.util.prefs.NodeChangeEvent);
-    method public abstract void childRemoved(java.util.prefs.NodeChangeEvent);
+  public interface NodeChangeListener extends java.util.EventListener {
+    method public void childAdded(java.util.prefs.NodeChangeEvent);
+    method public void childRemoved(java.util.prefs.NodeChangeEvent);
   }
 
   public class PreferenceChangeEvent extends java.util.EventObject {
-    ctor public PreferenceChangeEvent(java.util.prefs.Preferences, java.lang.String, java.lang.String);
-    method public java.lang.String getKey();
-    method public java.lang.String getNewValue();
+    ctor public PreferenceChangeEvent(java.util.prefs.Preferences, String, String);
+    method public String getKey();
+    method public String getNewValue();
     method public java.util.prefs.Preferences getNode();
   }
 
-  public abstract interface PreferenceChangeListener implements java.util.EventListener {
-    method public abstract void preferenceChange(java.util.prefs.PreferenceChangeEvent);
+  @java.lang.FunctionalInterface public interface PreferenceChangeListener extends java.util.EventListener {
+    method public void preferenceChange(java.util.prefs.PreferenceChangeEvent);
   }
 
   public abstract class Preferences {
     ctor protected Preferences();
-    method public abstract java.lang.String absolutePath();
+    method public abstract String absolutePath();
     method public abstract void addNodeChangeListener(java.util.prefs.NodeChangeListener);
     method public abstract void addPreferenceChangeListener(java.util.prefs.PreferenceChangeListener);
-    method public abstract java.lang.String[] childrenNames() throws java.util.prefs.BackingStoreException;
+    method public abstract String[] childrenNames() throws java.util.prefs.BackingStoreException;
     method public abstract void clear() throws java.util.prefs.BackingStoreException;
     method public abstract void exportNode(java.io.OutputStream) throws java.util.prefs.BackingStoreException, java.io.IOException;
     method public abstract void exportSubtree(java.io.OutputStream) throws java.util.prefs.BackingStoreException, java.io.IOException;
     method public abstract void flush() throws java.util.prefs.BackingStoreException;
-    method public abstract java.lang.String get(java.lang.String, java.lang.String);
-    method public abstract boolean getBoolean(java.lang.String, boolean);
-    method public abstract byte[] getByteArray(java.lang.String, byte[]);
-    method public abstract double getDouble(java.lang.String, double);
-    method public abstract float getFloat(java.lang.String, float);
-    method public abstract int getInt(java.lang.String, int);
-    method public abstract long getLong(java.lang.String, long);
+    method public abstract String get(String, String);
+    method public abstract boolean getBoolean(String, boolean);
+    method public abstract byte[] getByteArray(String, byte[]);
+    method public abstract double getDouble(String, double);
+    method public abstract float getFloat(String, float);
+    method public abstract int getInt(String, int);
+    method public abstract long getLong(String, long);
     method public static void importPreferences(java.io.InputStream) throws java.io.IOException, java.util.prefs.InvalidPreferencesFormatException;
     method public abstract boolean isUserNode();
-    method public abstract java.lang.String[] keys() throws java.util.prefs.BackingStoreException;
-    method public abstract java.lang.String name();
-    method public abstract java.util.prefs.Preferences node(java.lang.String);
-    method public abstract boolean nodeExists(java.lang.String) throws java.util.prefs.BackingStoreException;
+    method public abstract String[] keys() throws java.util.prefs.BackingStoreException;
+    method public abstract String name();
+    method public abstract java.util.prefs.Preferences node(String);
+    method public abstract boolean nodeExists(String) throws java.util.prefs.BackingStoreException;
     method public abstract java.util.prefs.Preferences parent();
-    method public abstract void put(java.lang.String, java.lang.String);
-    method public abstract void putBoolean(java.lang.String, boolean);
-    method public abstract void putByteArray(java.lang.String, byte[]);
-    method public abstract void putDouble(java.lang.String, double);
-    method public abstract void putFloat(java.lang.String, float);
-    method public abstract void putInt(java.lang.String, int);
-    method public abstract void putLong(java.lang.String, long);
-    method public abstract void remove(java.lang.String);
+    method public abstract void put(String, String);
+    method public abstract void putBoolean(String, boolean);
+    method public abstract void putByteArray(String, byte[]);
+    method public abstract void putDouble(String, double);
+    method public abstract void putFloat(String, float);
+    method public abstract void putInt(String, int);
+    method public abstract void putLong(String, long);
+    method public abstract void remove(String);
     method public abstract void removeNode() throws java.util.prefs.BackingStoreException;
     method public abstract void removeNodeChangeListener(java.util.prefs.NodeChangeListener);
     method public abstract void removePreferenceChangeListener(java.util.prefs.PreferenceChangeListener);
     method public abstract void sync() throws java.util.prefs.BackingStoreException;
-    method public static java.util.prefs.Preferences systemNodeForPackage(java.lang.Class<?>);
+    method public static java.util.prefs.Preferences systemNodeForPackage(Class<?>);
     method public static java.util.prefs.Preferences systemRoot();
-    method public abstract java.lang.String toString();
-    method public static java.util.prefs.Preferences userNodeForPackage(java.lang.Class<?>);
+    method public abstract String toString();
+    method public static java.util.prefs.Preferences userNodeForPackage(Class<?>);
     method public static java.util.prefs.Preferences userRoot();
     field public static final int MAX_KEY_LENGTH = 80; // 0x50
     field public static final int MAX_NAME_LENGTH = 80; // 0x50
     field public static final int MAX_VALUE_LENGTH = 8192; // 0x2000
   }
 
-  public abstract interface PreferencesFactory {
-    method public abstract java.util.prefs.Preferences systemRoot();
-    method public abstract java.util.prefs.Preferences userRoot();
+  public interface PreferencesFactory {
+    method public java.util.prefs.Preferences systemRoot();
+    method public java.util.prefs.Preferences userRoot();
   }
 
 }
 
 package java.util.regex {
 
-  public abstract interface MatchResult {
-    method public abstract int end();
-    method public abstract int end(int);
-    method public abstract java.lang.String group();
-    method public abstract java.lang.String group(int);
-    method public abstract int groupCount();
-    method public abstract int start();
-    method public abstract int start(int);
+  public interface MatchResult {
+    method public int end();
+    method public int end(int);
+    method public String group();
+    method public String group(int);
+    method public int groupCount();
+    method public int start();
+    method public int start(int);
   }
 
   public final class Matcher implements java.util.regex.MatchResult {
-    method public java.util.regex.Matcher appendReplacement(java.lang.StringBuffer, java.lang.String);
-    method public java.lang.StringBuffer appendTail(java.lang.StringBuffer);
+    method @NonNull public java.util.regex.Matcher appendReplacement(@NonNull StringBuffer, @NonNull String);
+    method @NonNull public StringBuffer appendTail(@NonNull StringBuffer);
     method public int end();
     method public int end(int);
-    method public int end(java.lang.String);
+    method public int end(@NonNull String);
     method public boolean find();
     method public boolean find(int);
-    method public java.lang.String group();
-    method public java.lang.String group(int);
-    method public java.lang.String group(java.lang.String);
+    method @NonNull public String group();
+    method @Nullable public String group(int);
+    method @Nullable public String group(@NonNull String);
     method public int groupCount();
     method public boolean hasAnchoringBounds();
     method public boolean hasTransparentBounds();
     method public boolean hitEnd();
     method public boolean lookingAt();
     method public boolean matches();
-    method public java.util.regex.Pattern pattern();
-    method public static java.lang.String quoteReplacement(java.lang.String);
-    method public java.util.regex.Matcher region(int, int);
+    method @NonNull public java.util.regex.Pattern pattern();
+    method @NonNull public static String quoteReplacement(@NonNull String);
+    method @NonNull public java.util.regex.Matcher region(int, int);
     method public int regionEnd();
     method public int regionStart();
-    method public java.lang.String replaceAll(java.lang.String);
-    method public java.lang.String replaceFirst(java.lang.String);
+    method @NonNull public String replaceAll(@NonNull String);
+    method @NonNull public String replaceFirst(@NonNull String);
     method public boolean requireEnd();
-    method public java.util.regex.Matcher reset();
-    method public java.util.regex.Matcher reset(java.lang.CharSequence);
+    method @NonNull public java.util.regex.Matcher reset();
+    method @NonNull public java.util.regex.Matcher reset(@NonNull CharSequence);
     method public int start();
     method public int start(int);
-    method public int start(java.lang.String);
-    method public java.util.regex.MatchResult toMatchResult();
-    method public java.util.regex.Matcher useAnchoringBounds(boolean);
-    method public java.util.regex.Matcher usePattern(java.util.regex.Pattern);
-    method public java.util.regex.Matcher useTransparentBounds(boolean);
+    method public int start(@NonNull String);
+    method @NonNull public java.util.regex.MatchResult toMatchResult();
+    method @NonNull public java.util.regex.Matcher useAnchoringBounds(boolean);
+    method @NonNull public java.util.regex.Matcher usePattern(@NonNull java.util.regex.Pattern);
+    method @NonNull public java.util.regex.Matcher useTransparentBounds(boolean);
   }
 
   public final class Pattern implements java.io.Serializable {
-    method public java.util.function.Predicate<java.lang.String> asPredicate();
-    method public static java.util.regex.Pattern compile(java.lang.String);
-    method public static java.util.regex.Pattern compile(java.lang.String, int);
+    method @NonNull public java.util.function.Predicate<java.lang.String> asPredicate();
+    method @NonNull public static java.util.regex.Pattern compile(@NonNull String);
+    method @NonNull public static java.util.regex.Pattern compile(@NonNull String, int);
     method public int flags();
-    method public java.util.regex.Matcher matcher(java.lang.CharSequence);
-    method public static boolean matches(java.lang.String, java.lang.CharSequence);
-    method public java.lang.String pattern();
-    method public static java.lang.String quote(java.lang.String);
-    method public java.lang.String[] split(java.lang.CharSequence, int);
-    method public java.lang.String[] split(java.lang.CharSequence);
-    method public java.util.stream.Stream<java.lang.String> splitAsStream(java.lang.CharSequence);
+    method @NonNull public java.util.regex.Matcher matcher(@NonNull CharSequence);
+    method public static boolean matches(@NonNull String, @NonNull CharSequence);
+    method @NonNull public String pattern();
+    method @NonNull public static String quote(@NonNull String);
+    method public String[] split(@NonNull CharSequence, int);
+    method public String[] split(@NonNull CharSequence);
+    method @NonNull public java.util.stream.Stream<java.lang.String> splitAsStream(@NonNull CharSequence);
     field public static final int CANON_EQ = 128; // 0x80
     field public static final int CASE_INSENSITIVE = 2; // 0x2
     field public static final int COMMENTS = 4; // 0x4
@@ -72805,281 +73103,279 @@
   }
 
   public class PatternSyntaxException extends java.lang.IllegalArgumentException {
-    ctor public PatternSyntaxException(java.lang.String, java.lang.String, int);
-    method public java.lang.String getDescription();
+    ctor public PatternSyntaxException(String, String, int);
+    method public String getDescription();
     method public int getIndex();
-    method public java.lang.String getPattern();
+    method public String getPattern();
   }
 
 }
 
 package java.util.stream {
 
-  public abstract interface BaseStream<T, S extends java.util.stream.BaseStream<T, S>> implements java.lang.AutoCloseable {
-    method public abstract void close();
-    method public abstract boolean isParallel();
-    method public abstract java.util.Iterator<T> iterator();
-    method public abstract S onClose(java.lang.Runnable);
-    method public abstract S parallel();
-    method public abstract S sequential();
-    method public abstract java.util.Spliterator<T> spliterator();
-    method public abstract S unordered();
+  public interface BaseStream<T, S extends java.util.stream.BaseStream<T, S>> extends java.lang.AutoCloseable {
+    method public void close();
+    method public boolean isParallel();
+    method public java.util.Iterator<T> iterator();
+    method public S onClose(Runnable);
+    method public S parallel();
+    method public S sequential();
+    method public java.util.Spliterator<T> spliterator();
+    method public S unordered();
   }
 
-  public abstract interface Collector<T, A, R> {
-    method public abstract java.util.function.BiConsumer<A, T> accumulator();
-    method public abstract java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
-    method public abstract java.util.function.BinaryOperator<A> combiner();
-    method public abstract java.util.function.Function<A, R> finisher();
-    method public static <T, R> java.util.stream.Collector<T, R, R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
-    method public static <T, A, R> java.util.stream.Collector<T, A, R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A, T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A, R>, java.util.stream.Collector.Characteristics...);
-    method public abstract java.util.function.Supplier<A> supplier();
+  public interface Collector<T, A, R> {
+    method public java.util.function.BiConsumer<A,T> accumulator();
+    method public java.util.Set<java.util.stream.Collector.Characteristics> characteristics();
+    method public java.util.function.BinaryOperator<A> combiner();
+    method public java.util.function.Function<A,R> finisher();
+    method public static <T, R> java.util.stream.Collector<T,R,R> of(java.util.function.Supplier<R>, java.util.function.BiConsumer<R,T>, java.util.function.BinaryOperator<R>, java.util.stream.Collector.Characteristics...);
+    method public static <T, A, R> java.util.stream.Collector<T,A,R> of(java.util.function.Supplier<A>, java.util.function.BiConsumer<A,T>, java.util.function.BinaryOperator<A>, java.util.function.Function<A,R>, java.util.stream.Collector.Characteristics...);
+    method public java.util.function.Supplier<A> supplier();
   }
 
-  public static final class Collector.Characteristics extends java.lang.Enum {
-    method public static java.util.stream.Collector.Characteristics valueOf(java.lang.String);
-    method public static final java.util.stream.Collector.Characteristics[] values();
+  public enum Collector.Characteristics {
     enum_constant public static final java.util.stream.Collector.Characteristics CONCURRENT;
     enum_constant public static final java.util.stream.Collector.Characteristics IDENTITY_FINISH;
     enum_constant public static final java.util.stream.Collector.Characteristics UNORDERED;
   }
 
   public final class Collectors {
-    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
-    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
-    method public static <T, A, R, RR> java.util.stream.Collector<T, A, RR> collectingAndThen(java.util.stream.Collector<T, A, R>, java.util.function.Function<R, RR>);
-    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> counting();
-    method public static <T, K> java.util.stream.Collector<T, ?, java.util.Map<K, java.util.List<T>>> groupingBy(java.util.function.Function<? super T, ? extends K>);
-    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.Map<K, D>> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
-    method public static <T, K, D, A, M extends java.util.Map<K, D>> java.util.stream.Collector<T, ?, M> groupingBy(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
-    method public static <T, K> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>);
-    method public static <T, K, A, D> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, D>> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.stream.Collector<? super T, A, D>);
-    method public static <T, K, A, D, M extends java.util.concurrent.ConcurrentMap<K, D>> java.util.stream.Collector<T, ?, M> groupingByConcurrent(java.util.function.Function<? super T, ? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T, A, D>);
-    method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining();
-    method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence);
-    method public static java.util.stream.Collector<java.lang.CharSequence, ?, java.lang.String> joining(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
-    method public static <T, U, A, R> java.util.stream.Collector<T, ?, R> mapping(java.util.function.Function<? super T, ? extends U>, java.util.stream.Collector<? super U, A, R>);
-    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
-    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
-    method public static <T> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
-    method public static <T, D, A> java.util.stream.Collector<T, ?, java.util.Map<java.lang.Boolean, D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T, A, D>);
-    method public static <T> java.util.stream.Collector<T, ?, T> reducing(T, java.util.function.BinaryOperator<T>);
-    method public static <T> java.util.stream.Collector<T, ?, java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
-    method public static <T, U> java.util.stream.Collector<T, ?, U> reducing(U, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
-    method public static <T> java.util.stream.Collector<T, ?, java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static <T> java.util.stream.Collector<T, ?, java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
-    method public static <T> java.util.stream.Collector<T, ?, java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
-    method public static <T> java.util.stream.Collector<T, ?, java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public static <T> java.util.stream.Collector<T, ?, java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
-    method public static <T> java.util.stream.Collector<T, ?, java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
-    method public static <T, C extends java.util.Collection<T>> java.util.stream.Collector<T, ?, C> toCollection(java.util.function.Supplier<C>);
-    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
-    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.concurrent.ConcurrentMap<K, U>> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
-    method public static <T, K, U, M extends java.util.concurrent.ConcurrentMap<K, U>> java.util.stream.Collector<T, ?, M> toConcurrentMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
-    method public static <T> java.util.stream.Collector<T, ?, java.util.List<T>> toList();
-    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>);
-    method public static <T, K, U> java.util.stream.Collector<T, ?, java.util.Map<K, U>> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>);
-    method public static <T, K, U, M extends java.util.Map<K, U>> java.util.stream.Collector<T, ?, M> toMap(java.util.function.Function<? super T, ? extends K>, java.util.function.Function<? super T, ? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
-    method public static <T> java.util.stream.Collector<T, ?, java.util.Set<T>> toSet();
+    method public static <T> java.util.stream.Collector<T,?,java.lang.Double> averagingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T,?,java.lang.Double> averagingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T,?,java.lang.Double> averagingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T, A, R, RR> java.util.stream.Collector<T,A,RR> collectingAndThen(java.util.stream.Collector<T,A,R>, java.util.function.Function<R,RR>);
+    method public static <T> java.util.stream.Collector<T,?,java.lang.Long> counting();
+    method public static <T, K> java.util.stream.Collector<T,?,java.util.Map<K,java.util.List<T>>> groupingBy(java.util.function.Function<? super T,? extends K>);
+    method public static <T, K, A, D> java.util.stream.Collector<T,?,java.util.Map<K,D>> groupingBy(java.util.function.Function<? super T,? extends K>, java.util.stream.Collector<? super T,A,D>);
+    method public static <T, K, D, A, M extends java.util.Map<K, D>> java.util.stream.Collector<T,?,M> groupingBy(java.util.function.Function<? super T,? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T,A,D>);
+    method public static <T, K> java.util.stream.Collector<T,?,java.util.concurrent.ConcurrentMap<K,java.util.List<T>>> groupingByConcurrent(java.util.function.Function<? super T,? extends K>);
+    method public static <T, K, A, D> java.util.stream.Collector<T,?,java.util.concurrent.ConcurrentMap<K,D>> groupingByConcurrent(java.util.function.Function<? super T,? extends K>, java.util.stream.Collector<? super T,A,D>);
+    method public static <T, K, A, D, M extends java.util.concurrent.ConcurrentMap<K, D>> java.util.stream.Collector<T,?,M> groupingByConcurrent(java.util.function.Function<? super T,? extends K>, java.util.function.Supplier<M>, java.util.stream.Collector<? super T,A,D>);
+    method public static java.util.stream.Collector<java.lang.CharSequence,?,java.lang.String> joining();
+    method public static java.util.stream.Collector<java.lang.CharSequence,?,java.lang.String> joining(CharSequence);
+    method public static java.util.stream.Collector<java.lang.CharSequence,?,java.lang.String> joining(CharSequence, CharSequence, CharSequence);
+    method public static <T, U, A, R> java.util.stream.Collector<T,?,R> mapping(java.util.function.Function<? super T,? extends U>, java.util.stream.Collector<? super U,A,R>);
+    method public static <T> java.util.stream.Collector<T,?,java.util.Optional<T>> maxBy(java.util.Comparator<? super T>);
+    method public static <T> java.util.stream.Collector<T,?,java.util.Optional<T>> minBy(java.util.Comparator<? super T>);
+    method public static <T> java.util.stream.Collector<T,?,java.util.Map<java.lang.Boolean,java.util.List<T>>> partitioningBy(java.util.function.Predicate<? super T>);
+    method public static <T, D, A> java.util.stream.Collector<T,?,java.util.Map<java.lang.Boolean,D>> partitioningBy(java.util.function.Predicate<? super T>, java.util.stream.Collector<? super T,A,D>);
+    method public static <T> java.util.stream.Collector<T,?,T> reducing(T, java.util.function.BinaryOperator<T>);
+    method public static <T> java.util.stream.Collector<T,?,java.util.Optional<T>> reducing(java.util.function.BinaryOperator<T>);
+    method public static <T, U> java.util.stream.Collector<T,?,U> reducing(U, java.util.function.Function<? super T,? extends U>, java.util.function.BinaryOperator<U>);
+    method public static <T> java.util.stream.Collector<T,?,java.util.DoubleSummaryStatistics> summarizingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T,?,java.util.IntSummaryStatistics> summarizingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T,?,java.util.LongSummaryStatistics> summarizingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T,?,java.lang.Double> summingDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T,?,java.lang.Integer> summingInt(java.util.function.ToIntFunction<? super T>);
+    method public static <T> java.util.stream.Collector<T,?,java.lang.Long> summingLong(java.util.function.ToLongFunction<? super T>);
+    method public static <T, C extends java.util.Collection<T>> java.util.stream.Collector<T,?,C> toCollection(java.util.function.Supplier<C>);
+    method public static <T, K, U> java.util.stream.Collector<T,?,java.util.concurrent.ConcurrentMap<K,U>> toConcurrentMap(java.util.function.Function<? super T,? extends K>, java.util.function.Function<? super T,? extends U>);
+    method public static <T, K, U> java.util.stream.Collector<T,?,java.util.concurrent.ConcurrentMap<K,U>> toConcurrentMap(java.util.function.Function<? super T,? extends K>, java.util.function.Function<? super T,? extends U>, java.util.function.BinaryOperator<U>);
+    method public static <T, K, U, M extends java.util.concurrent.ConcurrentMap<K, U>> java.util.stream.Collector<T,?,M> toConcurrentMap(java.util.function.Function<? super T,? extends K>, java.util.function.Function<? super T,? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static <T> java.util.stream.Collector<T,?,java.util.List<T>> toList();
+    method public static <T, K, U> java.util.stream.Collector<T,?,java.util.Map<K,U>> toMap(java.util.function.Function<? super T,? extends K>, java.util.function.Function<? super T,? extends U>);
+    method public static <T, K, U> java.util.stream.Collector<T,?,java.util.Map<K,U>> toMap(java.util.function.Function<? super T,? extends K>, java.util.function.Function<? super T,? extends U>, java.util.function.BinaryOperator<U>);
+    method public static <T, K, U, M extends java.util.Map<K, U>> java.util.stream.Collector<T,?,M> toMap(java.util.function.Function<? super T,? extends K>, java.util.function.Function<? super T,? extends U>, java.util.function.BinaryOperator<U>, java.util.function.Supplier<M>);
+    method public static <T> java.util.stream.Collector<T,?,java.util.Set<T>> toSet();
   }
 
-  public abstract interface DoubleStream implements java.util.stream.BaseStream {
-    method public abstract boolean allMatch(java.util.function.DoublePredicate);
-    method public abstract boolean anyMatch(java.util.function.DoublePredicate);
-    method public abstract java.util.OptionalDouble average();
-    method public abstract java.util.stream.Stream<java.lang.Double> boxed();
+  public interface DoubleStream extends java.util.stream.BaseStream<java.lang.Double,java.util.stream.DoubleStream> {
+    method public boolean allMatch(java.util.function.DoublePredicate);
+    method public boolean anyMatch(java.util.function.DoublePredicate);
+    method public java.util.OptionalDouble average();
+    method public java.util.stream.Stream<java.lang.Double> boxed();
     method public static java.util.stream.DoubleStream.Builder builder();
-    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjDoubleConsumer<R>, java.util.function.BiConsumer<R,R>);
     method public static java.util.stream.DoubleStream concat(java.util.stream.DoubleStream, java.util.stream.DoubleStream);
-    method public abstract long count();
-    method public abstract java.util.stream.DoubleStream distinct();
+    method public long count();
+    method public java.util.stream.DoubleStream distinct();
     method public static java.util.stream.DoubleStream empty();
-    method public abstract java.util.stream.DoubleStream filter(java.util.function.DoublePredicate);
-    method public abstract java.util.OptionalDouble findAny();
-    method public abstract java.util.OptionalDouble findFirst();
-    method public abstract java.util.stream.DoubleStream flatMap(java.util.function.DoubleFunction<? extends java.util.stream.DoubleStream>);
-    method public abstract void forEach(java.util.function.DoubleConsumer);
-    method public abstract void forEachOrdered(java.util.function.DoubleConsumer);
+    method public java.util.stream.DoubleStream filter(java.util.function.DoublePredicate);
+    method public java.util.OptionalDouble findAny();
+    method public java.util.OptionalDouble findFirst();
+    method public java.util.stream.DoubleStream flatMap(java.util.function.DoubleFunction<? extends java.util.stream.DoubleStream>);
+    method public void forEach(java.util.function.DoubleConsumer);
+    method public void forEachOrdered(java.util.function.DoubleConsumer);
     method public static java.util.stream.DoubleStream generate(java.util.function.DoubleSupplier);
     method public static java.util.stream.DoubleStream iterate(double, java.util.function.DoubleUnaryOperator);
-    method public abstract java.util.PrimitiveIterator.OfDouble iterator();
-    method public abstract java.util.stream.DoubleStream limit(long);
-    method public abstract java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
-    method public abstract java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
-    method public abstract java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
-    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
-    method public abstract java.util.OptionalDouble max();
-    method public abstract java.util.OptionalDouble min();
-    method public abstract boolean noneMatch(java.util.function.DoublePredicate);
+    method public java.util.PrimitiveIterator.OfDouble iterator();
+    method public java.util.stream.DoubleStream limit(long);
+    method public java.util.stream.DoubleStream map(java.util.function.DoubleUnaryOperator);
+    method public java.util.stream.IntStream mapToInt(java.util.function.DoubleToIntFunction);
+    method public java.util.stream.LongStream mapToLong(java.util.function.DoubleToLongFunction);
+    method public <U> java.util.stream.Stream<U> mapToObj(java.util.function.DoubleFunction<? extends U>);
+    method public java.util.OptionalDouble max();
+    method public java.util.OptionalDouble min();
+    method public boolean noneMatch(java.util.function.DoublePredicate);
     method public static java.util.stream.DoubleStream of(double);
     method public static java.util.stream.DoubleStream of(double...);
-    method public abstract java.util.stream.DoubleStream parallel();
-    method public abstract java.util.stream.DoubleStream peek(java.util.function.DoubleConsumer);
-    method public abstract double reduce(double, java.util.function.DoubleBinaryOperator);
-    method public abstract java.util.OptionalDouble reduce(java.util.function.DoubleBinaryOperator);
-    method public abstract java.util.stream.DoubleStream sequential();
-    method public abstract java.util.stream.DoubleStream skip(long);
-    method public abstract java.util.stream.DoubleStream sorted();
-    method public abstract java.util.Spliterator.OfDouble spliterator();
-    method public abstract double sum();
-    method public abstract java.util.DoubleSummaryStatistics summaryStatistics();
-    method public abstract double[] toArray();
+    method public java.util.stream.DoubleStream parallel();
+    method public java.util.stream.DoubleStream peek(java.util.function.DoubleConsumer);
+    method public double reduce(double, java.util.function.DoubleBinaryOperator);
+    method public java.util.OptionalDouble reduce(java.util.function.DoubleBinaryOperator);
+    method public java.util.stream.DoubleStream sequential();
+    method public java.util.stream.DoubleStream skip(long);
+    method public java.util.stream.DoubleStream sorted();
+    method public java.util.Spliterator.OfDouble spliterator();
+    method public double sum();
+    method public java.util.DoubleSummaryStatistics summaryStatistics();
+    method public double[] toArray();
   }
 
-  public static abstract interface DoubleStream.Builder implements java.util.function.DoubleConsumer {
+  public static interface DoubleStream.Builder extends java.util.function.DoubleConsumer {
     method public default java.util.stream.DoubleStream.Builder add(double);
-    method public abstract java.util.stream.DoubleStream build();
+    method public java.util.stream.DoubleStream build();
   }
 
-  public abstract interface IntStream implements java.util.stream.BaseStream {
-    method public abstract boolean allMatch(java.util.function.IntPredicate);
-    method public abstract boolean anyMatch(java.util.function.IntPredicate);
-    method public abstract java.util.stream.DoubleStream asDoubleStream();
-    method public abstract java.util.stream.LongStream asLongStream();
-    method public abstract java.util.OptionalDouble average();
-    method public abstract java.util.stream.Stream<java.lang.Integer> boxed();
+  public interface IntStream extends java.util.stream.BaseStream<java.lang.Integer,java.util.stream.IntStream> {
+    method public boolean allMatch(java.util.function.IntPredicate);
+    method public boolean anyMatch(java.util.function.IntPredicate);
+    method public java.util.stream.DoubleStream asDoubleStream();
+    method public java.util.stream.LongStream asLongStream();
+    method public java.util.OptionalDouble average();
+    method public java.util.stream.Stream<java.lang.Integer> boxed();
     method public static java.util.stream.IntStream.Builder builder();
-    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjIntConsumer<R>, java.util.function.BiConsumer<R,R>);
     method public static java.util.stream.IntStream concat(java.util.stream.IntStream, java.util.stream.IntStream);
-    method public abstract long count();
-    method public abstract java.util.stream.IntStream distinct();
+    method public long count();
+    method public java.util.stream.IntStream distinct();
     method public static java.util.stream.IntStream empty();
-    method public abstract java.util.stream.IntStream filter(java.util.function.IntPredicate);
-    method public abstract java.util.OptionalInt findAny();
-    method public abstract java.util.OptionalInt findFirst();
-    method public abstract java.util.stream.IntStream flatMap(java.util.function.IntFunction<? extends java.util.stream.IntStream>);
-    method public abstract void forEach(java.util.function.IntConsumer);
-    method public abstract void forEachOrdered(java.util.function.IntConsumer);
+    method public java.util.stream.IntStream filter(java.util.function.IntPredicate);
+    method public java.util.OptionalInt findAny();
+    method public java.util.OptionalInt findFirst();
+    method public java.util.stream.IntStream flatMap(java.util.function.IntFunction<? extends java.util.stream.IntStream>);
+    method public void forEach(java.util.function.IntConsumer);
+    method public void forEachOrdered(java.util.function.IntConsumer);
     method public static java.util.stream.IntStream generate(java.util.function.IntSupplier);
     method public static java.util.stream.IntStream iterate(int, java.util.function.IntUnaryOperator);
-    method public abstract java.util.PrimitiveIterator.OfInt iterator();
-    method public abstract java.util.stream.IntStream limit(long);
-    method public abstract java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
-    method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
-    method public abstract java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
-    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
-    method public abstract java.util.OptionalInt max();
-    method public abstract java.util.OptionalInt min();
-    method public abstract boolean noneMatch(java.util.function.IntPredicate);
+    method public java.util.PrimitiveIterator.OfInt iterator();
+    method public java.util.stream.IntStream limit(long);
+    method public java.util.stream.IntStream map(java.util.function.IntUnaryOperator);
+    method public java.util.stream.DoubleStream mapToDouble(java.util.function.IntToDoubleFunction);
+    method public java.util.stream.LongStream mapToLong(java.util.function.IntToLongFunction);
+    method public <U> java.util.stream.Stream<U> mapToObj(java.util.function.IntFunction<? extends U>);
+    method public java.util.OptionalInt max();
+    method public java.util.OptionalInt min();
+    method public boolean noneMatch(java.util.function.IntPredicate);
     method public static java.util.stream.IntStream of(int);
     method public static java.util.stream.IntStream of(int...);
-    method public abstract java.util.stream.IntStream parallel();
-    method public abstract java.util.stream.IntStream peek(java.util.function.IntConsumer);
+    method public java.util.stream.IntStream parallel();
+    method public java.util.stream.IntStream peek(java.util.function.IntConsumer);
     method public static java.util.stream.IntStream range(int, int);
     method public static java.util.stream.IntStream rangeClosed(int, int);
-    method public abstract int reduce(int, java.util.function.IntBinaryOperator);
-    method public abstract java.util.OptionalInt reduce(java.util.function.IntBinaryOperator);
-    method public abstract java.util.stream.IntStream sequential();
-    method public abstract java.util.stream.IntStream skip(long);
-    method public abstract java.util.stream.IntStream sorted();
-    method public abstract java.util.Spliterator.OfInt spliterator();
-    method public abstract int sum();
-    method public abstract java.util.IntSummaryStatistics summaryStatistics();
-    method public abstract int[] toArray();
+    method public int reduce(int, java.util.function.IntBinaryOperator);
+    method public java.util.OptionalInt reduce(java.util.function.IntBinaryOperator);
+    method public java.util.stream.IntStream sequential();
+    method public java.util.stream.IntStream skip(long);
+    method public java.util.stream.IntStream sorted();
+    method public java.util.Spliterator.OfInt spliterator();
+    method public int sum();
+    method public java.util.IntSummaryStatistics summaryStatistics();
+    method public int[] toArray();
   }
 
-  public static abstract interface IntStream.Builder implements java.util.function.IntConsumer {
+  public static interface IntStream.Builder extends java.util.function.IntConsumer {
     method public default java.util.stream.IntStream.Builder add(int);
-    method public abstract java.util.stream.IntStream build();
+    method public java.util.stream.IntStream build();
   }
 
-  public abstract interface LongStream implements java.util.stream.BaseStream {
-    method public abstract boolean allMatch(java.util.function.LongPredicate);
-    method public abstract boolean anyMatch(java.util.function.LongPredicate);
-    method public abstract java.util.stream.DoubleStream asDoubleStream();
-    method public abstract java.util.OptionalDouble average();
-    method public abstract java.util.stream.Stream<java.lang.Long> boxed();
+  public interface LongStream extends java.util.stream.BaseStream<java.lang.Long,java.util.stream.LongStream> {
+    method public boolean allMatch(java.util.function.LongPredicate);
+    method public boolean anyMatch(java.util.function.LongPredicate);
+    method public java.util.stream.DoubleStream asDoubleStream();
+    method public java.util.OptionalDouble average();
+    method public java.util.stream.Stream<java.lang.Long> boxed();
     method public static java.util.stream.LongStream.Builder builder();
-    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R, R>);
+    method public <R> R collect(java.util.function.Supplier<R>, java.util.function.ObjLongConsumer<R>, java.util.function.BiConsumer<R,R>);
     method public static java.util.stream.LongStream concat(java.util.stream.LongStream, java.util.stream.LongStream);
-    method public abstract long count();
-    method public abstract java.util.stream.LongStream distinct();
+    method public long count();
+    method public java.util.stream.LongStream distinct();
     method public static java.util.stream.LongStream empty();
-    method public abstract java.util.stream.LongStream filter(java.util.function.LongPredicate);
-    method public abstract java.util.OptionalLong findAny();
-    method public abstract java.util.OptionalLong findFirst();
-    method public abstract java.util.stream.LongStream flatMap(java.util.function.LongFunction<? extends java.util.stream.LongStream>);
-    method public abstract void forEach(java.util.function.LongConsumer);
-    method public abstract void forEachOrdered(java.util.function.LongConsumer);
+    method public java.util.stream.LongStream filter(java.util.function.LongPredicate);
+    method public java.util.OptionalLong findAny();
+    method public java.util.OptionalLong findFirst();
+    method public java.util.stream.LongStream flatMap(java.util.function.LongFunction<? extends java.util.stream.LongStream>);
+    method public void forEach(java.util.function.LongConsumer);
+    method public void forEachOrdered(java.util.function.LongConsumer);
     method public static java.util.stream.LongStream generate(java.util.function.LongSupplier);
     method public static java.util.stream.LongStream iterate(long, java.util.function.LongUnaryOperator);
-    method public abstract java.util.PrimitiveIterator.OfLong iterator();
-    method public abstract java.util.stream.LongStream limit(long);
-    method public abstract java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
-    method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
-    method public abstract java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
-    method public abstract <U> java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
-    method public abstract java.util.OptionalLong max();
-    method public abstract java.util.OptionalLong min();
-    method public abstract boolean noneMatch(java.util.function.LongPredicate);
+    method public java.util.PrimitiveIterator.OfLong iterator();
+    method public java.util.stream.LongStream limit(long);
+    method public java.util.stream.LongStream map(java.util.function.LongUnaryOperator);
+    method public java.util.stream.DoubleStream mapToDouble(java.util.function.LongToDoubleFunction);
+    method public java.util.stream.IntStream mapToInt(java.util.function.LongToIntFunction);
+    method public <U> java.util.stream.Stream<U> mapToObj(java.util.function.LongFunction<? extends U>);
+    method public java.util.OptionalLong max();
+    method public java.util.OptionalLong min();
+    method public boolean noneMatch(java.util.function.LongPredicate);
     method public static java.util.stream.LongStream of(long);
     method public static java.util.stream.LongStream of(long...);
-    method public abstract java.util.stream.LongStream parallel();
-    method public abstract java.util.stream.LongStream peek(java.util.function.LongConsumer);
+    method public java.util.stream.LongStream parallel();
+    method public java.util.stream.LongStream peek(java.util.function.LongConsumer);
     method public static java.util.stream.LongStream range(long, long);
     method public static java.util.stream.LongStream rangeClosed(long, long);
-    method public abstract long reduce(long, java.util.function.LongBinaryOperator);
-    method public abstract java.util.OptionalLong reduce(java.util.function.LongBinaryOperator);
-    method public abstract java.util.stream.LongStream sequential();
-    method public abstract java.util.stream.LongStream skip(long);
-    method public abstract java.util.stream.LongStream sorted();
-    method public abstract java.util.Spliterator.OfLong spliterator();
-    method public abstract long sum();
-    method public abstract java.util.LongSummaryStatistics summaryStatistics();
-    method public abstract long[] toArray();
+    method public long reduce(long, java.util.function.LongBinaryOperator);
+    method public java.util.OptionalLong reduce(java.util.function.LongBinaryOperator);
+    method public java.util.stream.LongStream sequential();
+    method public java.util.stream.LongStream skip(long);
+    method public java.util.stream.LongStream sorted();
+    method public java.util.Spliterator.OfLong spliterator();
+    method public long sum();
+    method public java.util.LongSummaryStatistics summaryStatistics();
+    method public long[] toArray();
   }
 
-  public static abstract interface LongStream.Builder implements java.util.function.LongConsumer {
+  public static interface LongStream.Builder extends java.util.function.LongConsumer {
     method public default java.util.stream.LongStream.Builder add(long);
-    method public abstract java.util.stream.LongStream build();
+    method public java.util.stream.LongStream build();
   }
 
-  public abstract interface Stream<T> implements java.util.stream.BaseStream {
-    method public abstract boolean allMatch(java.util.function.Predicate<? super T>);
-    method public abstract boolean anyMatch(java.util.function.Predicate<? super T>);
+  public interface Stream<T> extends java.util.stream.BaseStream<T,java.util.stream.Stream<T>> {
+    method public boolean allMatch(java.util.function.Predicate<? super T>);
+    method public boolean anyMatch(java.util.function.Predicate<? super T>);
     method public static <T> java.util.stream.Stream.Builder<T> builder();
-    method public abstract <R> R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R, ? super T>, java.util.function.BiConsumer<R, R>);
-    method public abstract <R, A> R collect(java.util.stream.Collector<? super T, A, R>);
+    method public <R> R collect(java.util.function.Supplier<R>, java.util.function.BiConsumer<R,? super T>, java.util.function.BiConsumer<R,R>);
+    method public <R, A> R collect(java.util.stream.Collector<? super T,A,R>);
     method public static <T> java.util.stream.Stream<T> concat(java.util.stream.Stream<? extends T>, java.util.stream.Stream<? extends T>);
-    method public abstract long count();
-    method public abstract java.util.stream.Stream<T> distinct();
+    method public long count();
+    method public java.util.stream.Stream<T> distinct();
     method public static <T> java.util.stream.Stream<T> empty();
-    method public abstract java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
-    method public abstract java.util.Optional<T> findAny();
-    method public abstract java.util.Optional<T> findFirst();
-    method public abstract <R> java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T, ? extends java.util.stream.Stream<? extends R>>);
-    method public abstract java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T, ? extends java.util.stream.DoubleStream>);
-    method public abstract java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T, ? extends java.util.stream.IntStream>);
-    method public abstract java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T, ? extends java.util.stream.LongStream>);
-    method public abstract void forEach(java.util.function.Consumer<? super T>);
-    method public abstract void forEachOrdered(java.util.function.Consumer<? super T>);
+    method public java.util.stream.Stream<T> filter(java.util.function.Predicate<? super T>);
+    method public java.util.Optional<T> findAny();
+    method public java.util.Optional<T> findFirst();
+    method public <R> java.util.stream.Stream<R> flatMap(java.util.function.Function<? super T,? extends java.util.stream.Stream<? extends R>>);
+    method public java.util.stream.DoubleStream flatMapToDouble(java.util.function.Function<? super T,? extends java.util.stream.DoubleStream>);
+    method public java.util.stream.IntStream flatMapToInt(java.util.function.Function<? super T,? extends java.util.stream.IntStream>);
+    method public java.util.stream.LongStream flatMapToLong(java.util.function.Function<? super T,? extends java.util.stream.LongStream>);
+    method public void forEach(java.util.function.Consumer<? super T>);
+    method public void forEachOrdered(java.util.function.Consumer<? super T>);
     method public static <T> java.util.stream.Stream<T> generate(java.util.function.Supplier<T>);
     method public static <T> java.util.stream.Stream<T> iterate(T, java.util.function.UnaryOperator<T>);
-    method public abstract java.util.stream.Stream<T> limit(long);
-    method public abstract <R> java.util.stream.Stream<R> map(java.util.function.Function<? super T, ? extends R>);
-    method public abstract java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
-    method public abstract java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
-    method public abstract java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
-    method public abstract java.util.Optional<T> max(java.util.Comparator<? super T>);
-    method public abstract java.util.Optional<T> min(java.util.Comparator<? super T>);
-    method public abstract boolean noneMatch(java.util.function.Predicate<? super T>);
+    method public java.util.stream.Stream<T> limit(long);
+    method public <R> java.util.stream.Stream<R> map(java.util.function.Function<? super T,? extends R>);
+    method public java.util.stream.DoubleStream mapToDouble(java.util.function.ToDoubleFunction<? super T>);
+    method public java.util.stream.IntStream mapToInt(java.util.function.ToIntFunction<? super T>);
+    method public java.util.stream.LongStream mapToLong(java.util.function.ToLongFunction<? super T>);
+    method public java.util.Optional<T> max(java.util.Comparator<? super T>);
+    method public java.util.Optional<T> min(java.util.Comparator<? super T>);
+    method public boolean noneMatch(java.util.function.Predicate<? super T>);
     method public static <T> java.util.stream.Stream<T> of(T);
-    method public static <T> java.util.stream.Stream<T> of(T...);
-    method public abstract java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
-    method public abstract T reduce(T, java.util.function.BinaryOperator<T>);
-    method public abstract java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
-    method public abstract <U> U reduce(U, java.util.function.BiFunction<U, ? super T, U>, java.util.function.BinaryOperator<U>);
-    method public abstract java.util.stream.Stream<T> skip(long);
-    method public abstract java.util.stream.Stream<T> sorted();
-    method public abstract java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
-    method public abstract java.lang.Object[] toArray();
-    method public abstract <A> A[] toArray(java.util.function.IntFunction<A[]>);
+    method @java.lang.SafeVarargs public static <T> java.util.stream.Stream<T> of(T...);
+    method public java.util.stream.Stream<T> peek(java.util.function.Consumer<? super T>);
+    method public T reduce(T, java.util.function.BinaryOperator<T>);
+    method public java.util.Optional<T> reduce(java.util.function.BinaryOperator<T>);
+    method public <U> U reduce(U, java.util.function.BiFunction<U,? super T,U>, java.util.function.BinaryOperator<U>);
+    method public java.util.stream.Stream<T> skip(long);
+    method public java.util.stream.Stream<T> sorted();
+    method public java.util.stream.Stream<T> sorted(java.util.Comparator<? super T>);
+    method public Object[] toArray();
+    method public <A> A[] toArray(java.util.function.IntFunction<A[]>);
   }
 
-  public static abstract interface Stream.Builder<T> implements java.util.function.Consumer {
+  public static interface Stream.Builder<T> extends java.util.function.Consumer<T> {
     method public default java.util.stream.Stream.Builder<T> add(T);
-    method public abstract java.util.stream.Stream<T> build();
+    method public java.util.stream.Stream<T> build();
   }
 
   public final class StreamSupport {
@@ -73127,16 +73423,16 @@
     method public java.util.zip.Checksum getChecksum();
   }
 
-  public abstract interface Checksum {
-    method public abstract long getValue();
-    method public abstract void reset();
-    method public abstract void update(int);
-    method public abstract void update(byte[], int, int);
+  public interface Checksum {
+    method public long getValue();
+    method public void reset();
+    method public void update(int);
+    method public void update(byte[], int, int);
   }
 
   public class DataFormatException extends java.lang.Exception {
     ctor public DataFormatException();
-    ctor public DataFormatException(java.lang.String);
+    ctor public DataFormatException(String);
   }
 
   public class Deflater {
@@ -73180,8 +73476,6 @@
     ctor public DeflaterInputStream(java.io.InputStream);
     ctor public DeflaterInputStream(java.io.InputStream, java.util.zip.Deflater);
     ctor public DeflaterInputStream(java.io.InputStream, java.util.zip.Deflater, int);
-    method public void mark(int);
-    method public void reset() throws java.io.IOException;
     field protected final byte[] buf;
     field protected final java.util.zip.Deflater def;
   }
@@ -73212,7 +73506,6 @@
     ctor public GZIPOutputStream(java.io.OutputStream, int, boolean) throws java.io.IOException;
     ctor public GZIPOutputStream(java.io.OutputStream) throws java.io.IOException;
     ctor public GZIPOutputStream(java.io.OutputStream, boolean) throws java.io.IOException;
-    method public synchronized void write(byte[], int, int) throws java.io.IOException;
     field protected java.util.zip.CRC32 crc;
   }
 
@@ -73245,7 +73538,7 @@
     ctor public InflaterInputStream(java.io.InputStream);
     method protected void fill() throws java.io.IOException;
     field protected byte[] buf;
-    field protected deprecated boolean closed;
+    field @Deprecated protected boolean closed;
     field protected java.util.zip.Inflater inf;
     field protected int len;
   }
@@ -73260,10 +73553,10 @@
   }
 
   public class ZipEntry implements java.lang.Cloneable {
-    ctor public ZipEntry(java.lang.String);
+    ctor public ZipEntry(String);
     ctor public ZipEntry(java.util.zip.ZipEntry);
-    method public java.lang.Object clone();
-    method public java.lang.String getComment();
+    method public Object clone();
+    method public String getComment();
     method public long getCompressedSize();
     method public long getCrc();
     method public java.nio.file.attribute.FileTime getCreationTime();
@@ -73271,11 +73564,11 @@
     method public java.nio.file.attribute.FileTime getLastAccessTime();
     method public java.nio.file.attribute.FileTime getLastModifiedTime();
     method public int getMethod();
-    method public java.lang.String getName();
+    method public String getName();
     method public long getSize();
     method public long getTime();
     method public boolean isDirectory();
-    method public void setComment(java.lang.String);
+    method public void setComment(String);
     method public void setCompressedSize(long);
     method public void setCrc(long);
     method public java.util.zip.ZipEntry setCreationTime(java.nio.file.attribute.FileTime);
@@ -73330,28 +73623,28 @@
   }
 
   public class ZipError extends java.lang.InternalError {
-    ctor public ZipError(java.lang.String);
+    ctor public ZipError(String);
   }
 
   public class ZipException extends java.io.IOException {
     ctor public ZipException();
-    ctor public ZipException(java.lang.String);
+    ctor public ZipException(String);
   }
 
   public class ZipFile implements java.io.Closeable {
-    ctor public ZipFile(java.lang.String) throws java.io.IOException;
+    ctor public ZipFile(String) throws java.io.IOException;
     ctor public ZipFile(java.io.File, int) throws java.io.IOException;
     ctor public ZipFile(java.io.File) throws java.io.IOException, java.util.zip.ZipException;
     ctor public ZipFile(java.io.File, int, java.nio.charset.Charset) throws java.io.IOException;
-    ctor public ZipFile(java.lang.String, java.nio.charset.Charset) throws java.io.IOException;
+    ctor public ZipFile(String, java.nio.charset.Charset) throws java.io.IOException;
     ctor public ZipFile(java.io.File, java.nio.charset.Charset) throws java.io.IOException;
     method public void close() throws java.io.IOException;
     method public java.util.Enumeration<? extends java.util.zip.ZipEntry> entries();
     method protected void finalize() throws java.io.IOException;
-    method public java.lang.String getComment();
-    method public java.util.zip.ZipEntry getEntry(java.lang.String);
+    method public String getComment();
+    method public java.util.zip.ZipEntry getEntry(String);
     method public java.io.InputStream getInputStream(java.util.zip.ZipEntry) throws java.io.IOException;
-    method public java.lang.String getName();
+    method public String getName();
     method public int size();
     method public java.util.stream.Stream<? extends java.util.zip.ZipEntry> stream();
     field public static final int CENATT = 36; // 0x24
@@ -73402,7 +73695,7 @@
     ctor public ZipInputStream(java.io.InputStream);
     ctor public ZipInputStream(java.io.InputStream, java.nio.charset.Charset);
     method public void closeEntry() throws java.io.IOException;
-    method protected java.util.zip.ZipEntry createZipEntry(java.lang.String);
+    method protected java.util.zip.ZipEntry createZipEntry(String);
     method public java.util.zip.ZipEntry getNextEntry() throws java.io.IOException;
     field public static final int CENATT = 36; // 0x24
     field public static final int CENATX = 38; // 0x26
@@ -73451,10 +73744,9 @@
     ctor public ZipOutputStream(java.io.OutputStream, java.nio.charset.Charset);
     method public void closeEntry() throws java.io.IOException;
     method public void putNextEntry(java.util.zip.ZipEntry) throws java.io.IOException;
-    method public void setComment(java.lang.String);
+    method public void setComment(String);
     method public void setLevel(int);
     method public void setMethod(int);
-    method public synchronized void write(byte[], int, int) throws java.io.IOException;
     field public static final int CENATT = 36; // 0x24
     field public static final int CENATX = 38; // 0x26
     field public static final int CENCOM = 32; // 0x20
@@ -73505,16 +73797,16 @@
 
   public class AEADBadTagException extends javax.crypto.BadPaddingException {
     ctor public AEADBadTagException();
-    ctor public AEADBadTagException(java.lang.String);
+    ctor public AEADBadTagException(String);
   }
 
   public class BadPaddingException extends java.security.GeneralSecurityException {
     ctor public BadPaddingException();
-    ctor public BadPaddingException(java.lang.String);
+    ctor public BadPaddingException(String);
   }
 
   public class Cipher {
-    ctor protected Cipher(javax.crypto.CipherSpi, java.security.Provider, java.lang.String);
+    ctor protected Cipher(javax.crypto.CipherSpi, java.security.Provider, String);
     method public final byte[] doFinal() throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException;
     method public final int doFinal(byte[], int) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException, javax.crypto.ShortBufferException;
     method public final byte[] doFinal(byte[]) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException;
@@ -73522,15 +73814,15 @@
     method public final int doFinal(byte[], int, int, byte[]) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException, javax.crypto.ShortBufferException;
     method public final int doFinal(byte[], int, int, byte[], int) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException, javax.crypto.ShortBufferException;
     method public final int doFinal(java.nio.ByteBuffer, java.nio.ByteBuffer) throws javax.crypto.BadPaddingException, javax.crypto.IllegalBlockSizeException, javax.crypto.ShortBufferException;
-    method public final java.lang.String getAlgorithm();
+    method public final String getAlgorithm();
     method public final int getBlockSize();
     method public final javax.crypto.ExemptionMechanism getExemptionMechanism();
     method public final byte[] getIV();
-    method public static final javax.crypto.Cipher getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException;
-    method public static final javax.crypto.Cipher getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException, java.security.NoSuchProviderException;
-    method public static final javax.crypto.Cipher getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException;
-    method public static final int getMaxAllowedKeyLength(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static final java.security.spec.AlgorithmParameterSpec getMaxAllowedParameterSpec(java.lang.String) throws java.security.NoSuchAlgorithmException;
+    method public static final javax.crypto.Cipher getInstance(String) throws java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException;
+    method public static final javax.crypto.Cipher getInstance(String, String) throws java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException, java.security.NoSuchProviderException;
+    method public static final javax.crypto.Cipher getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException;
+    method public static final int getMaxAllowedKeyLength(String) throws java.security.NoSuchAlgorithmException;
+    method public static final java.security.spec.AlgorithmParameterSpec getMaxAllowedParameterSpec(String) throws java.security.NoSuchAlgorithmException;
     method public final int getOutputSize(int);
     method public final java.security.AlgorithmParameters getParameters();
     method public final java.security.Provider getProvider();
@@ -73542,7 +73834,7 @@
     method public final void init(int, java.security.Key, java.security.AlgorithmParameters, java.security.SecureRandom) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException;
     method public final void init(int, java.security.cert.Certificate) throws java.security.InvalidKeyException;
     method public final void init(int, java.security.cert.Certificate, java.security.SecureRandom) throws java.security.InvalidKeyException;
-    method public final java.security.Key unwrap(byte[], java.lang.String, int) throws java.security.InvalidKeyException, java.security.NoSuchAlgorithmException;
+    method public final java.security.Key unwrap(byte[], String, int) throws java.security.InvalidKeyException, java.security.NoSuchAlgorithmException;
     method public final byte[] update(byte[]);
     method public final byte[] update(byte[], int, int);
     method public final int update(byte[], int, int, byte[]) throws javax.crypto.ShortBufferException;
@@ -73584,9 +73876,9 @@
     method protected abstract void engineInit(int, java.security.Key, java.security.SecureRandom) throws java.security.InvalidKeyException;
     method protected abstract void engineInit(int, java.security.Key, java.security.spec.AlgorithmParameterSpec, java.security.SecureRandom) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException;
     method protected abstract void engineInit(int, java.security.Key, java.security.AlgorithmParameters, java.security.SecureRandom) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException;
-    method protected abstract void engineSetMode(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method protected abstract void engineSetPadding(java.lang.String) throws javax.crypto.NoSuchPaddingException;
-    method protected java.security.Key engineUnwrap(byte[], java.lang.String, int) throws java.security.InvalidKeyException, java.security.NoSuchAlgorithmException;
+    method protected abstract void engineSetMode(String) throws java.security.NoSuchAlgorithmException;
+    method protected abstract void engineSetPadding(String) throws javax.crypto.NoSuchPaddingException;
+    method protected java.security.Key engineUnwrap(byte[], String, int) throws java.security.InvalidKeyException, java.security.NoSuchAlgorithmException;
     method protected abstract byte[] engineUpdate(byte[], int, int);
     method protected abstract int engineUpdate(byte[], int, int, byte[], int) throws javax.crypto.ShortBufferException;
     method protected int engineUpdate(java.nio.ByteBuffer, java.nio.ByteBuffer) throws javax.crypto.ShortBufferException;
@@ -73597,27 +73889,27 @@
 
   public class EncryptedPrivateKeyInfo {
     ctor public EncryptedPrivateKeyInfo(byte[]) throws java.io.IOException;
-    ctor public EncryptedPrivateKeyInfo(java.lang.String, byte[]) throws java.security.NoSuchAlgorithmException;
+    ctor public EncryptedPrivateKeyInfo(String, byte[]) throws java.security.NoSuchAlgorithmException;
     ctor public EncryptedPrivateKeyInfo(java.security.AlgorithmParameters, byte[]) throws java.security.NoSuchAlgorithmException;
-    method public java.lang.String getAlgName();
+    method public String getAlgName();
     method public java.security.AlgorithmParameters getAlgParameters();
     method public byte[] getEncoded() throws java.io.IOException;
     method public byte[] getEncryptedData();
     method public java.security.spec.PKCS8EncodedKeySpec getKeySpec(javax.crypto.Cipher) throws java.security.spec.InvalidKeySpecException;
     method public java.security.spec.PKCS8EncodedKeySpec getKeySpec(java.security.Key) throws java.security.InvalidKeyException, java.security.NoSuchAlgorithmException;
-    method public java.security.spec.PKCS8EncodedKeySpec getKeySpec(java.security.Key, java.lang.String) throws java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public java.security.spec.PKCS8EncodedKeySpec getKeySpec(java.security.Key, String) throws java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     method public java.security.spec.PKCS8EncodedKeySpec getKeySpec(java.security.Key, java.security.Provider) throws java.security.InvalidKeyException, java.security.NoSuchAlgorithmException;
   }
 
   public class ExemptionMechanism {
-    ctor protected ExemptionMechanism(javax.crypto.ExemptionMechanismSpi, java.security.Provider, java.lang.String);
+    ctor protected ExemptionMechanism(javax.crypto.ExemptionMechanismSpi, java.security.Provider, String);
     method public final byte[] genExemptionBlob() throws javax.crypto.ExemptionMechanismException, java.lang.IllegalStateException;
     method public final int genExemptionBlob(byte[]) throws javax.crypto.ExemptionMechanismException, java.lang.IllegalStateException, javax.crypto.ShortBufferException;
     method public final int genExemptionBlob(byte[], int) throws javax.crypto.ExemptionMechanismException, java.lang.IllegalStateException, javax.crypto.ShortBufferException;
-    method public static final javax.crypto.ExemptionMechanism getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static final javax.crypto.ExemptionMechanism getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static final javax.crypto.ExemptionMechanism getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final java.lang.String getName();
+    method public static final javax.crypto.ExemptionMechanism getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static final javax.crypto.ExemptionMechanism getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static final javax.crypto.ExemptionMechanism getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public final String getName();
     method public final int getOutputSize(int) throws java.lang.IllegalStateException;
     method public final java.security.Provider getProvider();
     method public final void init(java.security.Key) throws javax.crypto.ExemptionMechanismException, java.security.InvalidKeyException;
@@ -73628,7 +73920,7 @@
 
   public class ExemptionMechanismException extends java.security.GeneralSecurityException {
     ctor public ExemptionMechanismException();
-    ctor public ExemptionMechanismException(java.lang.String);
+    ctor public ExemptionMechanismException(String);
   }
 
   public abstract class ExemptionMechanismSpi {
@@ -73643,19 +73935,19 @@
 
   public class IllegalBlockSizeException extends java.security.GeneralSecurityException {
     ctor public IllegalBlockSizeException();
-    ctor public IllegalBlockSizeException(java.lang.String);
+    ctor public IllegalBlockSizeException(String);
   }
 
   public class KeyAgreement {
-    ctor protected KeyAgreement(javax.crypto.KeyAgreementSpi, java.security.Provider, java.lang.String);
+    ctor protected KeyAgreement(javax.crypto.KeyAgreementSpi, java.security.Provider, String);
     method public final java.security.Key doPhase(java.security.Key, boolean) throws java.lang.IllegalStateException, java.security.InvalidKeyException;
     method public final byte[] generateSecret() throws java.lang.IllegalStateException;
     method public final int generateSecret(byte[], int) throws java.lang.IllegalStateException, javax.crypto.ShortBufferException;
-    method public final javax.crypto.SecretKey generateSecret(java.lang.String) throws java.lang.IllegalStateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException;
-    method public final java.lang.String getAlgorithm();
-    method public static final javax.crypto.KeyAgreement getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static final javax.crypto.KeyAgreement getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static final javax.crypto.KeyAgreement getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public final javax.crypto.SecretKey generateSecret(String) throws java.lang.IllegalStateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException;
+    method public final String getAlgorithm();
+    method public static final javax.crypto.KeyAgreement getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static final javax.crypto.KeyAgreement getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static final javax.crypto.KeyAgreement getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
     method public final void init(java.security.Key) throws java.security.InvalidKeyException;
     method public final void init(java.security.Key, java.security.SecureRandom) throws java.security.InvalidKeyException;
@@ -73668,18 +73960,18 @@
     method protected abstract java.security.Key engineDoPhase(java.security.Key, boolean) throws java.lang.IllegalStateException, java.security.InvalidKeyException;
     method protected abstract byte[] engineGenerateSecret() throws java.lang.IllegalStateException;
     method protected abstract int engineGenerateSecret(byte[], int) throws java.lang.IllegalStateException, javax.crypto.ShortBufferException;
-    method protected abstract javax.crypto.SecretKey engineGenerateSecret(java.lang.String) throws java.lang.IllegalStateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException;
+    method protected abstract javax.crypto.SecretKey engineGenerateSecret(String) throws java.lang.IllegalStateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException;
     method protected abstract void engineInit(java.security.Key, java.security.SecureRandom) throws java.security.InvalidKeyException;
     method protected abstract void engineInit(java.security.Key, java.security.spec.AlgorithmParameterSpec, java.security.SecureRandom) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException;
   }
 
   public class KeyGenerator {
-    ctor protected KeyGenerator(javax.crypto.KeyGeneratorSpi, java.security.Provider, java.lang.String);
+    ctor protected KeyGenerator(javax.crypto.KeyGeneratorSpi, java.security.Provider, String);
     method public final javax.crypto.SecretKey generateKey();
-    method public final java.lang.String getAlgorithm();
-    method public static final javax.crypto.KeyGenerator getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static final javax.crypto.KeyGenerator getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static final javax.crypto.KeyGenerator getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public final String getAlgorithm();
+    method public static final javax.crypto.KeyGenerator getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static final javax.crypto.KeyGenerator getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static final javax.crypto.KeyGenerator getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
     method public final void init(java.security.SecureRandom);
     method public final void init(java.security.spec.AlgorithmParameterSpec) throws java.security.InvalidAlgorithmParameterException;
@@ -73697,15 +73989,15 @@
   }
 
   public class Mac implements java.lang.Cloneable {
-    ctor protected Mac(javax.crypto.MacSpi, java.security.Provider, java.lang.String);
-    method public final java.lang.Object clone() throws java.lang.CloneNotSupportedException;
+    ctor protected Mac(javax.crypto.MacSpi, java.security.Provider, String);
+    method public final Object clone() throws java.lang.CloneNotSupportedException;
     method public final byte[] doFinal() throws java.lang.IllegalStateException;
     method public final void doFinal(byte[], int) throws java.lang.IllegalStateException, javax.crypto.ShortBufferException;
     method public final byte[] doFinal(byte[]) throws java.lang.IllegalStateException;
-    method public final java.lang.String getAlgorithm();
-    method public static final javax.crypto.Mac getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static final javax.crypto.Mac getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static final javax.crypto.Mac getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public final String getAlgorithm();
+    method public static final javax.crypto.Mac getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static final javax.crypto.Mac getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static final javax.crypto.Mac getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final int getMacLength();
     method public final java.security.Provider getProvider();
     method public final void init(java.security.Key) throws java.security.InvalidKeyException;
@@ -73719,7 +74011,7 @@
 
   public abstract class MacSpi {
     ctor public MacSpi();
-    method public java.lang.Object clone() throws java.lang.CloneNotSupportedException;
+    method public Object clone() throws java.lang.CloneNotSupportedException;
     method protected abstract byte[] engineDoFinal();
     method protected abstract int engineGetMacLength();
     method protected abstract void engineInit(java.security.Key, java.security.spec.AlgorithmParameterSpec) throws java.security.InvalidAlgorithmParameterException, java.security.InvalidKeyException;
@@ -73731,7 +74023,7 @@
 
   public class NoSuchPaddingException extends java.security.GeneralSecurityException {
     ctor public NoSuchPaddingException();
-    ctor public NoSuchPaddingException(java.lang.String);
+    ctor public NoSuchPaddingException(String);
   }
 
   public class NullCipher extends javax.crypto.Cipher {
@@ -73741,25 +74033,25 @@
   public class SealedObject implements java.io.Serializable {
     ctor public SealedObject(java.io.Serializable, javax.crypto.Cipher) throws java.io.IOException, javax.crypto.IllegalBlockSizeException;
     ctor protected SealedObject(javax.crypto.SealedObject);
-    method public final java.lang.String getAlgorithm();
-    method public final java.lang.Object getObject(java.security.Key) throws java.lang.ClassNotFoundException, java.io.IOException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException;
-    method public final java.lang.Object getObject(javax.crypto.Cipher) throws javax.crypto.BadPaddingException, java.lang.ClassNotFoundException, java.io.IOException, javax.crypto.IllegalBlockSizeException;
-    method public final java.lang.Object getObject(java.security.Key, java.lang.String) throws java.lang.ClassNotFoundException, java.io.IOException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public final String getAlgorithm();
+    method public final Object getObject(java.security.Key) throws java.lang.ClassNotFoundException, java.io.IOException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException;
+    method public final Object getObject(javax.crypto.Cipher) throws javax.crypto.BadPaddingException, java.lang.ClassNotFoundException, java.io.IOException, javax.crypto.IllegalBlockSizeException;
+    method public final Object getObject(java.security.Key, String) throws java.lang.ClassNotFoundException, java.io.IOException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
     field protected byte[] encodedParams;
   }
 
-  public abstract interface SecretKey implements javax.security.auth.Destroyable java.security.Key {
+  public interface SecretKey extends java.security.Key javax.security.auth.Destroyable {
     field public static final long serialVersionUID = -4795878709595146952L; // 0xbd719db928b8f538L
   }
 
   public class SecretKeyFactory {
-    ctor protected SecretKeyFactory(javax.crypto.SecretKeyFactorySpi, java.security.Provider, java.lang.String);
+    ctor protected SecretKeyFactory(javax.crypto.SecretKeyFactorySpi, java.security.Provider, String);
     method public final javax.crypto.SecretKey generateSecret(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
-    method public final java.lang.String getAlgorithm();
-    method public static final javax.crypto.SecretKeyFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static final javax.crypto.SecretKeyFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static final javax.crypto.SecretKeyFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final java.security.spec.KeySpec getKeySpec(javax.crypto.SecretKey, java.lang.Class<?>) throws java.security.spec.InvalidKeySpecException;
+    method public final String getAlgorithm();
+    method public static final javax.crypto.SecretKeyFactory getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static final javax.crypto.SecretKeyFactory getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static final javax.crypto.SecretKeyFactory getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public final java.security.spec.KeySpec getKeySpec(javax.crypto.SecretKey, Class<?>) throws java.security.spec.InvalidKeySpecException;
     method public final java.security.Provider getProvider();
     method public final javax.crypto.SecretKey translateKey(javax.crypto.SecretKey) throws java.security.InvalidKeyException;
   }
@@ -73767,37 +74059,37 @@
   public abstract class SecretKeyFactorySpi {
     ctor public SecretKeyFactorySpi();
     method protected abstract javax.crypto.SecretKey engineGenerateSecret(java.security.spec.KeySpec) throws java.security.spec.InvalidKeySpecException;
-    method protected abstract java.security.spec.KeySpec engineGetKeySpec(javax.crypto.SecretKey, java.lang.Class<?>) throws java.security.spec.InvalidKeySpecException;
+    method protected abstract java.security.spec.KeySpec engineGetKeySpec(javax.crypto.SecretKey, Class<?>) throws java.security.spec.InvalidKeySpecException;
     method protected abstract javax.crypto.SecretKey engineTranslateKey(javax.crypto.SecretKey) throws java.security.InvalidKeyException;
   }
 
   public class ShortBufferException extends java.security.GeneralSecurityException {
     ctor public ShortBufferException();
-    ctor public ShortBufferException(java.lang.String);
+    ctor public ShortBufferException(String);
   }
 
 }
 
 package javax.crypto.interfaces {
 
-  public abstract interface DHKey {
-    method public abstract javax.crypto.spec.DHParameterSpec getParams();
+  public interface DHKey {
+    method public javax.crypto.spec.DHParameterSpec getParams();
   }
 
-  public abstract interface DHPrivateKey implements javax.crypto.interfaces.DHKey java.security.PrivateKey {
-    method public abstract java.math.BigInteger getX();
+  public interface DHPrivateKey extends javax.crypto.interfaces.DHKey java.security.PrivateKey {
+    method public java.math.BigInteger getX();
     field public static final long serialVersionUID = 2211791113380396553L; // 0x1eb1dc4c8e677e09L
   }
 
-  public abstract interface DHPublicKey implements javax.crypto.interfaces.DHKey java.security.PublicKey {
-    method public abstract java.math.BigInteger getY();
+  public interface DHPublicKey extends javax.crypto.interfaces.DHKey java.security.PublicKey {
+    method public java.math.BigInteger getY();
     field public static final long serialVersionUID = -6628103563352519193L; // 0xa4043eed23df4de7L
   }
 
-  public abstract interface PBEKey implements javax.crypto.SecretKey {
-    method public abstract int getIterationCount();
-    method public abstract char[] getPassword();
-    method public abstract byte[] getSalt();
+  public interface PBEKey extends javax.crypto.SecretKey {
+    method public int getIterationCount();
+    method public char[] getPassword();
+    method public byte[] getSalt();
     field public static final long serialVersionUID = -1430015993304333921L; // 0xec279007d7f7c19fL
   }
 
@@ -73864,9 +74156,9 @@
   }
 
   public class OAEPParameterSpec implements java.security.spec.AlgorithmParameterSpec {
-    ctor public OAEPParameterSpec(java.lang.String, java.lang.String, java.security.spec.AlgorithmParameterSpec, javax.crypto.spec.PSource);
-    method public java.lang.String getDigestAlgorithm();
-    method public java.lang.String getMGFAlgorithm();
+    ctor public OAEPParameterSpec(String, String, java.security.spec.AlgorithmParameterSpec, javax.crypto.spec.PSource);
+    method public String getDigestAlgorithm();
+    method public String getMGFAlgorithm();
     method public java.security.spec.AlgorithmParameterSpec getMGFParameters();
     method public javax.crypto.spec.PSource getPSource();
     field public static final javax.crypto.spec.OAEPParameterSpec DEFAULT;
@@ -73892,8 +74184,8 @@
   }
 
   public class PSource {
-    ctor protected PSource(java.lang.String);
-    method public java.lang.String getAlgorithm();
+    ctor protected PSource(String);
+    method public String getAlgorithm();
   }
 
   public static final class PSource.PSpecified extends javax.crypto.spec.PSource {
@@ -73921,45 +74213,45 @@
   }
 
   public class SecretKeySpec implements java.security.spec.KeySpec javax.crypto.SecretKey {
-    ctor public SecretKeySpec(byte[], java.lang.String);
-    ctor public SecretKeySpec(byte[], int, int, java.lang.String);
-    method public java.lang.String getAlgorithm();
+    ctor public SecretKeySpec(byte[], String);
+    ctor public SecretKeySpec(byte[], int, int, String);
+    method public String getAlgorithm();
     method public byte[] getEncoded();
-    method public java.lang.String getFormat();
+    method public String getFormat();
   }
 
 }
 
 package javax.microedition.khronos.egl {
 
-  public abstract interface EGL {
+  public interface EGL {
   }
 
-  public abstract interface EGL10 implements javax.microedition.khronos.egl.EGL {
-    method public abstract boolean eglChooseConfig(javax.microedition.khronos.egl.EGLDisplay, int[], javax.microedition.khronos.egl.EGLConfig[], int, int[]);
-    method public abstract boolean eglCopyBuffers(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface, java.lang.Object);
-    method public abstract javax.microedition.khronos.egl.EGLContext eglCreateContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, javax.microedition.khronos.egl.EGLContext, int[]);
-    method public abstract javax.microedition.khronos.egl.EGLSurface eglCreatePbufferSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, int[]);
-    method public abstract deprecated javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
-    method public abstract javax.microedition.khronos.egl.EGLSurface eglCreateWindowSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
-    method public abstract boolean eglDestroyContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLContext);
-    method public abstract boolean eglDestroySurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface);
-    method public abstract boolean eglGetConfigAttrib(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, int, int[]);
-    method public abstract boolean eglGetConfigs(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig[], int, int[]);
-    method public abstract javax.microedition.khronos.egl.EGLContext eglGetCurrentContext();
-    method public abstract javax.microedition.khronos.egl.EGLDisplay eglGetCurrentDisplay();
-    method public abstract javax.microedition.khronos.egl.EGLSurface eglGetCurrentSurface(int);
-    method public abstract javax.microedition.khronos.egl.EGLDisplay eglGetDisplay(java.lang.Object);
-    method public abstract int eglGetError();
-    method public abstract boolean eglInitialize(javax.microedition.khronos.egl.EGLDisplay, int[]);
-    method public abstract boolean eglMakeCurrent(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface, javax.microedition.khronos.egl.EGLSurface, javax.microedition.khronos.egl.EGLContext);
-    method public abstract boolean eglQueryContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLContext, int, int[]);
-    method public abstract java.lang.String eglQueryString(javax.microedition.khronos.egl.EGLDisplay, int);
-    method public abstract boolean eglQuerySurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface, int, int[]);
-    method public abstract boolean eglSwapBuffers(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface);
-    method public abstract boolean eglTerminate(javax.microedition.khronos.egl.EGLDisplay);
-    method public abstract boolean eglWaitGL();
-    method public abstract boolean eglWaitNative(int, java.lang.Object);
+  public interface EGL10 extends javax.microedition.khronos.egl.EGL {
+    method public boolean eglChooseConfig(javax.microedition.khronos.egl.EGLDisplay, int[], javax.microedition.khronos.egl.EGLConfig[], int, int[]);
+    method public boolean eglCopyBuffers(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface, Object);
+    method public javax.microedition.khronos.egl.EGLContext eglCreateContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, javax.microedition.khronos.egl.EGLContext, int[]);
+    method public javax.microedition.khronos.egl.EGLSurface eglCreatePbufferSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, int[]);
+    method @Deprecated public javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, Object, int[]);
+    method public javax.microedition.khronos.egl.EGLSurface eglCreateWindowSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, Object, int[]);
+    method public boolean eglDestroyContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLContext);
+    method public boolean eglDestroySurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface);
+    method public boolean eglGetConfigAttrib(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, int, int[]);
+    method public boolean eglGetConfigs(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig[], int, int[]);
+    method public javax.microedition.khronos.egl.EGLContext eglGetCurrentContext();
+    method public javax.microedition.khronos.egl.EGLDisplay eglGetCurrentDisplay();
+    method public javax.microedition.khronos.egl.EGLSurface eglGetCurrentSurface(int);
+    method public javax.microedition.khronos.egl.EGLDisplay eglGetDisplay(Object);
+    method public int eglGetError();
+    method public boolean eglInitialize(javax.microedition.khronos.egl.EGLDisplay, int[]);
+    method public boolean eglMakeCurrent(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface, javax.microedition.khronos.egl.EGLSurface, javax.microedition.khronos.egl.EGLContext);
+    method public boolean eglQueryContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLContext, int, int[]);
+    method public String eglQueryString(javax.microedition.khronos.egl.EGLDisplay, int);
+    method public boolean eglQuerySurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface, int, int[]);
+    method public boolean eglSwapBuffers(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface);
+    method public boolean eglTerminate(javax.microedition.khronos.egl.EGLDisplay);
+    method public boolean eglWaitGL();
+    method public boolean eglWaitNative(int, Object);
     field public static final int EGL_ALPHA_FORMAT = 12424; // 0x3088
     field public static final int EGL_ALPHA_MASK_SIZE = 12350; // 0x303e
     field public static final int EGL_ALPHA_SIZE = 12321; // 0x3021
@@ -73982,7 +74274,7 @@
     field public static final int EGL_CONFIG_CAVEAT = 12327; // 0x3027
     field public static final int EGL_CONFIG_ID = 12328; // 0x3028
     field public static final int EGL_CORE_NATIVE_ENGINE = 12379; // 0x305b
-    field public static final java.lang.Object EGL_DEFAULT_DISPLAY;
+    field public static final Object EGL_DEFAULT_DISPLAY;
     field public static final int EGL_DEPTH_SIZE = 12325; // 0x3025
     field public static final int EGL_DONT_CARE = -1; // 0xffffffff
     field public static final int EGL_DRAW = 12377; // 0x3059
@@ -74033,7 +74325,7 @@
     field public static final int EGL_WINDOW_BIT = 4; // 0x4
   }
 
-  public abstract interface EGL11 implements javax.microedition.khronos.egl.EGL10 {
+  public interface EGL11 extends javax.microedition.khronos.egl.EGL10 {
     field public static final int EGL_CONTEXT_LOST = 12302; // 0x300e
   }
 
@@ -74059,133 +74351,133 @@
 
 package javax.microedition.khronos.opengles {
 
-  public abstract interface GL {
+  public interface GL {
   }
 
-  public abstract interface GL10 implements javax.microedition.khronos.opengles.GL {
-    method public abstract void glActiveTexture(int);
-    method public abstract void glAlphaFunc(int, float);
-    method public abstract void glAlphaFuncx(int, int);
-    method public abstract void glBindTexture(int, int);
-    method public abstract void glBlendFunc(int, int);
-    method public abstract void glClear(int);
-    method public abstract void glClearColor(float, float, float, float);
-    method public abstract void glClearColorx(int, int, int, int);
-    method public abstract void glClearDepthf(float);
-    method public abstract void glClearDepthx(int);
-    method public abstract void glClearStencil(int);
-    method public abstract void glClientActiveTexture(int);
-    method public abstract void glColor4f(float, float, float, float);
-    method public abstract void glColor4x(int, int, int, int);
-    method public abstract void glColorMask(boolean, boolean, boolean, boolean);
-    method public abstract void glColorPointer(int, int, int, java.nio.Buffer);
-    method public abstract void glCompressedTexImage2D(int, int, int, int, int, int, int, java.nio.Buffer);
-    method public abstract void glCompressedTexSubImage2D(int, int, int, int, int, int, int, int, java.nio.Buffer);
-    method public abstract void glCopyTexImage2D(int, int, int, int, int, int, int, int);
-    method public abstract void glCopyTexSubImage2D(int, int, int, int, int, int, int, int);
-    method public abstract void glCullFace(int);
-    method public abstract void glDeleteTextures(int, int[], int);
-    method public abstract void glDeleteTextures(int, java.nio.IntBuffer);
-    method public abstract void glDepthFunc(int);
-    method public abstract void glDepthMask(boolean);
-    method public abstract void glDepthRangef(float, float);
-    method public abstract void glDepthRangex(int, int);
-    method public abstract void glDisable(int);
-    method public abstract void glDisableClientState(int);
-    method public abstract void glDrawArrays(int, int, int);
-    method public abstract void glDrawElements(int, int, int, java.nio.Buffer);
-    method public abstract void glEnable(int);
-    method public abstract void glEnableClientState(int);
-    method public abstract void glFinish();
-    method public abstract void glFlush();
-    method public abstract void glFogf(int, float);
-    method public abstract void glFogfv(int, float[], int);
-    method public abstract void glFogfv(int, java.nio.FloatBuffer);
-    method public abstract void glFogx(int, int);
-    method public abstract void glFogxv(int, int[], int);
-    method public abstract void glFogxv(int, java.nio.IntBuffer);
-    method public abstract void glFrontFace(int);
-    method public abstract void glFrustumf(float, float, float, float, float, float);
-    method public abstract void glFrustumx(int, int, int, int, int, int);
-    method public abstract void glGenTextures(int, int[], int);
-    method public abstract void glGenTextures(int, java.nio.IntBuffer);
-    method public abstract int glGetError();
-    method public abstract void glGetIntegerv(int, int[], int);
-    method public abstract void glGetIntegerv(int, java.nio.IntBuffer);
-    method public abstract java.lang.String glGetString(int);
-    method public abstract void glHint(int, int);
-    method public abstract void glLightModelf(int, float);
-    method public abstract void glLightModelfv(int, float[], int);
-    method public abstract void glLightModelfv(int, java.nio.FloatBuffer);
-    method public abstract void glLightModelx(int, int);
-    method public abstract void glLightModelxv(int, int[], int);
-    method public abstract void glLightModelxv(int, java.nio.IntBuffer);
-    method public abstract void glLightf(int, int, float);
-    method public abstract void glLightfv(int, int, float[], int);
-    method public abstract void glLightfv(int, int, java.nio.FloatBuffer);
-    method public abstract void glLightx(int, int, int);
-    method public abstract void glLightxv(int, int, int[], int);
-    method public abstract void glLightxv(int, int, java.nio.IntBuffer);
-    method public abstract void glLineWidth(float);
-    method public abstract void glLineWidthx(int);
-    method public abstract void glLoadIdentity();
-    method public abstract void glLoadMatrixf(float[], int);
-    method public abstract void glLoadMatrixf(java.nio.FloatBuffer);
-    method public abstract void glLoadMatrixx(int[], int);
-    method public abstract void glLoadMatrixx(java.nio.IntBuffer);
-    method public abstract void glLogicOp(int);
-    method public abstract void glMaterialf(int, int, float);
-    method public abstract void glMaterialfv(int, int, float[], int);
-    method public abstract void glMaterialfv(int, int, java.nio.FloatBuffer);
-    method public abstract void glMaterialx(int, int, int);
-    method public abstract void glMaterialxv(int, int, int[], int);
-    method public abstract void glMaterialxv(int, int, java.nio.IntBuffer);
-    method public abstract void glMatrixMode(int);
-    method public abstract void glMultMatrixf(float[], int);
-    method public abstract void glMultMatrixf(java.nio.FloatBuffer);
-    method public abstract void glMultMatrixx(int[], int);
-    method public abstract void glMultMatrixx(java.nio.IntBuffer);
-    method public abstract void glMultiTexCoord4f(int, float, float, float, float);
-    method public abstract void glMultiTexCoord4x(int, int, int, int, int);
-    method public abstract void glNormal3f(float, float, float);
-    method public abstract void glNormal3x(int, int, int);
-    method public abstract void glNormalPointer(int, int, java.nio.Buffer);
-    method public abstract void glOrthof(float, float, float, float, float, float);
-    method public abstract void glOrthox(int, int, int, int, int, int);
-    method public abstract void glPixelStorei(int, int);
-    method public abstract void glPointSize(float);
-    method public abstract void glPointSizex(int);
-    method public abstract void glPolygonOffset(float, float);
-    method public abstract void glPolygonOffsetx(int, int);
-    method public abstract void glPopMatrix();
-    method public abstract void glPushMatrix();
-    method public abstract void glReadPixels(int, int, int, int, int, int, java.nio.Buffer);
-    method public abstract void glRotatef(float, float, float, float);
-    method public abstract void glRotatex(int, int, int, int);
-    method public abstract void glSampleCoverage(float, boolean);
-    method public abstract void glSampleCoveragex(int, boolean);
-    method public abstract void glScalef(float, float, float);
-    method public abstract void glScalex(int, int, int);
-    method public abstract void glScissor(int, int, int, int);
-    method public abstract void glShadeModel(int);
-    method public abstract void glStencilFunc(int, int, int);
-    method public abstract void glStencilMask(int);
-    method public abstract void glStencilOp(int, int, int);
-    method public abstract void glTexCoordPointer(int, int, int, java.nio.Buffer);
-    method public abstract void glTexEnvf(int, int, float);
-    method public abstract void glTexEnvfv(int, int, float[], int);
-    method public abstract void glTexEnvfv(int, int, java.nio.FloatBuffer);
-    method public abstract void glTexEnvx(int, int, int);
-    method public abstract void glTexEnvxv(int, int, int[], int);
-    method public abstract void glTexEnvxv(int, int, java.nio.IntBuffer);
-    method public abstract void glTexImage2D(int, int, int, int, int, int, int, int, java.nio.Buffer);
-    method public abstract void glTexParameterf(int, int, float);
-    method public abstract void glTexParameterx(int, int, int);
-    method public abstract void glTexSubImage2D(int, int, int, int, int, int, int, int, java.nio.Buffer);
-    method public abstract void glTranslatef(float, float, float);
-    method public abstract void glTranslatex(int, int, int);
-    method public abstract void glVertexPointer(int, int, int, java.nio.Buffer);
-    method public abstract void glViewport(int, int, int, int);
+  public interface GL10 extends javax.microedition.khronos.opengles.GL {
+    method public void glActiveTexture(int);
+    method public void glAlphaFunc(int, float);
+    method public void glAlphaFuncx(int, int);
+    method public void glBindTexture(int, int);
+    method public void glBlendFunc(int, int);
+    method public void glClear(int);
+    method public void glClearColor(float, float, float, float);
+    method public void glClearColorx(int, int, int, int);
+    method public void glClearDepthf(float);
+    method public void glClearDepthx(int);
+    method public void glClearStencil(int);
+    method public void glClientActiveTexture(int);
+    method public void glColor4f(float, float, float, float);
+    method public void glColor4x(int, int, int, int);
+    method public void glColorMask(boolean, boolean, boolean, boolean);
+    method public void glColorPointer(int, int, int, java.nio.Buffer);
+    method public void glCompressedTexImage2D(int, int, int, int, int, int, int, java.nio.Buffer);
+    method public void glCompressedTexSubImage2D(int, int, int, int, int, int, int, int, java.nio.Buffer);
+    method public void glCopyTexImage2D(int, int, int, int, int, int, int, int);
+    method public void glCopyTexSubImage2D(int, int, int, int, int, int, int, int);
+    method public void glCullFace(int);
+    method public void glDeleteTextures(int, int[], int);
+    method public void glDeleteTextures(int, java.nio.IntBuffer);
+    method public void glDepthFunc(int);
+    method public void glDepthMask(boolean);
+    method public void glDepthRangef(float, float);
+    method public void glDepthRangex(int, int);
+    method public void glDisable(int);
+    method public void glDisableClientState(int);
+    method public void glDrawArrays(int, int, int);
+    method public void glDrawElements(int, int, int, java.nio.Buffer);
+    method public void glEnable(int);
+    method public void glEnableClientState(int);
+    method public void glFinish();
+    method public void glFlush();
+    method public void glFogf(int, float);
+    method public void glFogfv(int, float[], int);
+    method public void glFogfv(int, java.nio.FloatBuffer);
+    method public void glFogx(int, int);
+    method public void glFogxv(int, int[], int);
+    method public void glFogxv(int, java.nio.IntBuffer);
+    method public void glFrontFace(int);
+    method public void glFrustumf(float, float, float, float, float, float);
+    method public void glFrustumx(int, int, int, int, int, int);
+    method public void glGenTextures(int, int[], int);
+    method public void glGenTextures(int, java.nio.IntBuffer);
+    method public int glGetError();
+    method public void glGetIntegerv(int, int[], int);
+    method public void glGetIntegerv(int, java.nio.IntBuffer);
+    method public String glGetString(int);
+    method public void glHint(int, int);
+    method public void glLightModelf(int, float);
+    method public void glLightModelfv(int, float[], int);
+    method public void glLightModelfv(int, java.nio.FloatBuffer);
+    method public void glLightModelx(int, int);
+    method public void glLightModelxv(int, int[], int);
+    method public void glLightModelxv(int, java.nio.IntBuffer);
+    method public void glLightf(int, int, float);
+    method public void glLightfv(int, int, float[], int);
+    method public void glLightfv(int, int, java.nio.FloatBuffer);
+    method public void glLightx(int, int, int);
+    method public void glLightxv(int, int, int[], int);
+    method public void glLightxv(int, int, java.nio.IntBuffer);
+    method public void glLineWidth(float);
+    method public void glLineWidthx(int);
+    method public void glLoadIdentity();
+    method public void glLoadMatrixf(float[], int);
+    method public void glLoadMatrixf(java.nio.FloatBuffer);
+    method public void glLoadMatrixx(int[], int);
+    method public void glLoadMatrixx(java.nio.IntBuffer);
+    method public void glLogicOp(int);
+    method public void glMaterialf(int, int, float);
+    method public void glMaterialfv(int, int, float[], int);
+    method public void glMaterialfv(int, int, java.nio.FloatBuffer);
+    method public void glMaterialx(int, int, int);
+    method public void glMaterialxv(int, int, int[], int);
+    method public void glMaterialxv(int, int, java.nio.IntBuffer);
+    method public void glMatrixMode(int);
+    method public void glMultMatrixf(float[], int);
+    method public void glMultMatrixf(java.nio.FloatBuffer);
+    method public void glMultMatrixx(int[], int);
+    method public void glMultMatrixx(java.nio.IntBuffer);
+    method public void glMultiTexCoord4f(int, float, float, float, float);
+    method public void glMultiTexCoord4x(int, int, int, int, int);
+    method public void glNormal3f(float, float, float);
+    method public void glNormal3x(int, int, int);
+    method public void glNormalPointer(int, int, java.nio.Buffer);
+    method public void glOrthof(float, float, float, float, float, float);
+    method public void glOrthox(int, int, int, int, int, int);
+    method public void glPixelStorei(int, int);
+    method public void glPointSize(float);
+    method public void glPointSizex(int);
+    method public void glPolygonOffset(float, float);
+    method public void glPolygonOffsetx(int, int);
+    method public void glPopMatrix();
+    method public void glPushMatrix();
+    method public void glReadPixels(int, int, int, int, int, int, java.nio.Buffer);
+    method public void glRotatef(float, float, float, float);
+    method public void glRotatex(int, int, int, int);
+    method public void glSampleCoverage(float, boolean);
+    method public void glSampleCoveragex(int, boolean);
+    method public void glScalef(float, float, float);
+    method public void glScalex(int, int, int);
+    method public void glScissor(int, int, int, int);
+    method public void glShadeModel(int);
+    method public void glStencilFunc(int, int, int);
+    method public void glStencilMask(int);
+    method public void glStencilOp(int, int, int);
+    method public void glTexCoordPointer(int, int, int, java.nio.Buffer);
+    method public void glTexEnvf(int, int, float);
+    method public void glTexEnvfv(int, int, float[], int);
+    method public void glTexEnvfv(int, int, java.nio.FloatBuffer);
+    method public void glTexEnvx(int, int, int);
+    method public void glTexEnvxv(int, int, int[], int);
+    method public void glTexEnvxv(int, int, java.nio.IntBuffer);
+    method public void glTexImage2D(int, int, int, int, int, int, int, int, java.nio.Buffer);
+    method public void glTexParameterf(int, int, float);
+    method public void glTexParameterx(int, int, int);
+    method public void glTexSubImage2D(int, int, int, int, int, int, int, int, java.nio.Buffer);
+    method public void glTranslatef(float, float, float);
+    method public void glTranslatex(int, int, int);
+    method public void glVertexPointer(int, int, int, java.nio.Buffer);
+    method public void glViewport(int, int, int, int);
     field public static final int GL_ADD = 260; // 0x104
     field public static final int GL_ALIASED_LINE_WIDTH_RANGE = 33902; // 0x846e
     field public static final int GL_ALIASED_POINT_SIZE_RANGE = 33901; // 0x846d
@@ -74425,80 +74717,80 @@
     field public static final int GL_ZERO = 0; // 0x0
   }
 
-  public abstract interface GL10Ext implements javax.microedition.khronos.opengles.GL {
-    method public abstract int glQueryMatrixxOES(int[], int, int[], int);
-    method public abstract int glQueryMatrixxOES(java.nio.IntBuffer, java.nio.IntBuffer);
+  public interface GL10Ext extends javax.microedition.khronos.opengles.GL {
+    method public int glQueryMatrixxOES(int[], int, int[], int);
+    method public int glQueryMatrixxOES(java.nio.IntBuffer, java.nio.IntBuffer);
   }
 
-  public abstract interface GL11 implements javax.microedition.khronos.opengles.GL10 {
-    method public abstract void glBindBuffer(int, int);
-    method public abstract void glBufferData(int, int, java.nio.Buffer, int);
-    method public abstract void glBufferSubData(int, int, int, java.nio.Buffer);
-    method public abstract void glClipPlanef(int, float[], int);
-    method public abstract void glClipPlanef(int, java.nio.FloatBuffer);
-    method public abstract void glClipPlanex(int, int[], int);
-    method public abstract void glClipPlanex(int, java.nio.IntBuffer);
-    method public abstract void glColor4ub(byte, byte, byte, byte);
-    method public abstract void glColorPointer(int, int, int, int);
-    method public abstract void glDeleteBuffers(int, int[], int);
-    method public abstract void glDeleteBuffers(int, java.nio.IntBuffer);
-    method public abstract void glDrawElements(int, int, int, int);
-    method public abstract void glGenBuffers(int, int[], int);
-    method public abstract void glGenBuffers(int, java.nio.IntBuffer);
-    method public abstract void glGetBooleanv(int, boolean[], int);
-    method public abstract void glGetBooleanv(int, java.nio.IntBuffer);
-    method public abstract void glGetBufferParameteriv(int, int, int[], int);
-    method public abstract void glGetBufferParameteriv(int, int, java.nio.IntBuffer);
-    method public abstract void glGetClipPlanef(int, float[], int);
-    method public abstract void glGetClipPlanef(int, java.nio.FloatBuffer);
-    method public abstract void glGetClipPlanex(int, int[], int);
-    method public abstract void glGetClipPlanex(int, java.nio.IntBuffer);
-    method public abstract void glGetFixedv(int, int[], int);
-    method public abstract void glGetFixedv(int, java.nio.IntBuffer);
-    method public abstract void glGetFloatv(int, float[], int);
-    method public abstract void glGetFloatv(int, java.nio.FloatBuffer);
-    method public abstract void glGetLightfv(int, int, float[], int);
-    method public abstract void glGetLightfv(int, int, java.nio.FloatBuffer);
-    method public abstract void glGetLightxv(int, int, int[], int);
-    method public abstract void glGetLightxv(int, int, java.nio.IntBuffer);
-    method public abstract void glGetMaterialfv(int, int, float[], int);
-    method public abstract void glGetMaterialfv(int, int, java.nio.FloatBuffer);
-    method public abstract void glGetMaterialxv(int, int, int[], int);
-    method public abstract void glGetMaterialxv(int, int, java.nio.IntBuffer);
-    method public abstract void glGetPointerv(int, java.nio.Buffer[]);
-    method public abstract void glGetTexEnviv(int, int, int[], int);
-    method public abstract void glGetTexEnviv(int, int, java.nio.IntBuffer);
-    method public abstract void glGetTexEnvxv(int, int, int[], int);
-    method public abstract void glGetTexEnvxv(int, int, java.nio.IntBuffer);
-    method public abstract void glGetTexParameterfv(int, int, float[], int);
-    method public abstract void glGetTexParameterfv(int, int, java.nio.FloatBuffer);
-    method public abstract void glGetTexParameteriv(int, int, int[], int);
-    method public abstract void glGetTexParameteriv(int, int, java.nio.IntBuffer);
-    method public abstract void glGetTexParameterxv(int, int, int[], int);
-    method public abstract void glGetTexParameterxv(int, int, java.nio.IntBuffer);
-    method public abstract boolean glIsBuffer(int);
-    method public abstract boolean glIsEnabled(int);
-    method public abstract boolean glIsTexture(int);
-    method public abstract void glNormalPointer(int, int, int);
-    method public abstract void glPointParameterf(int, float);
-    method public abstract void glPointParameterfv(int, float[], int);
-    method public abstract void glPointParameterfv(int, java.nio.FloatBuffer);
-    method public abstract void glPointParameterx(int, int);
-    method public abstract void glPointParameterxv(int, int[], int);
-    method public abstract void glPointParameterxv(int, java.nio.IntBuffer);
-    method public abstract void glPointSizePointerOES(int, int, java.nio.Buffer);
-    method public abstract void glTexCoordPointer(int, int, int, int);
-    method public abstract void glTexEnvi(int, int, int);
-    method public abstract void glTexEnviv(int, int, int[], int);
-    method public abstract void glTexEnviv(int, int, java.nio.IntBuffer);
-    method public abstract void glTexParameterfv(int, int, float[], int);
-    method public abstract void glTexParameterfv(int, int, java.nio.FloatBuffer);
-    method public abstract void glTexParameteri(int, int, int);
-    method public abstract void glTexParameteriv(int, int, int[], int);
-    method public abstract void glTexParameteriv(int, int, java.nio.IntBuffer);
-    method public abstract void glTexParameterxv(int, int, int[], int);
-    method public abstract void glTexParameterxv(int, int, java.nio.IntBuffer);
-    method public abstract void glVertexPointer(int, int, int, int);
+  public interface GL11 extends javax.microedition.khronos.opengles.GL10 {
+    method public void glBindBuffer(int, int);
+    method public void glBufferData(int, int, java.nio.Buffer, int);
+    method public void glBufferSubData(int, int, int, java.nio.Buffer);
+    method public void glClipPlanef(int, float[], int);
+    method public void glClipPlanef(int, java.nio.FloatBuffer);
+    method public void glClipPlanex(int, int[], int);
+    method public void glClipPlanex(int, java.nio.IntBuffer);
+    method public void glColor4ub(byte, byte, byte, byte);
+    method public void glColorPointer(int, int, int, int);
+    method public void glDeleteBuffers(int, int[], int);
+    method public void glDeleteBuffers(int, java.nio.IntBuffer);
+    method public void glDrawElements(int, int, int, int);
+    method public void glGenBuffers(int, int[], int);
+    method public void glGenBuffers(int, java.nio.IntBuffer);
+    method public void glGetBooleanv(int, boolean[], int);
+    method public void glGetBooleanv(int, java.nio.IntBuffer);
+    method public void glGetBufferParameteriv(int, int, int[], int);
+    method public void glGetBufferParameteriv(int, int, java.nio.IntBuffer);
+    method public void glGetClipPlanef(int, float[], int);
+    method public void glGetClipPlanef(int, java.nio.FloatBuffer);
+    method public void glGetClipPlanex(int, int[], int);
+    method public void glGetClipPlanex(int, java.nio.IntBuffer);
+    method public void glGetFixedv(int, int[], int);
+    method public void glGetFixedv(int, java.nio.IntBuffer);
+    method public void glGetFloatv(int, float[], int);
+    method public void glGetFloatv(int, java.nio.FloatBuffer);
+    method public void glGetLightfv(int, int, float[], int);
+    method public void glGetLightfv(int, int, java.nio.FloatBuffer);
+    method public void glGetLightxv(int, int, int[], int);
+    method public void glGetLightxv(int, int, java.nio.IntBuffer);
+    method public void glGetMaterialfv(int, int, float[], int);
+    method public void glGetMaterialfv(int, int, java.nio.FloatBuffer);
+    method public void glGetMaterialxv(int, int, int[], int);
+    method public void glGetMaterialxv(int, int, java.nio.IntBuffer);
+    method public void glGetPointerv(int, java.nio.Buffer[]);
+    method public void glGetTexEnviv(int, int, int[], int);
+    method public void glGetTexEnviv(int, int, java.nio.IntBuffer);
+    method public void glGetTexEnvxv(int, int, int[], int);
+    method public void glGetTexEnvxv(int, int, java.nio.IntBuffer);
+    method public void glGetTexParameterfv(int, int, float[], int);
+    method public void glGetTexParameterfv(int, int, java.nio.FloatBuffer);
+    method public void glGetTexParameteriv(int, int, int[], int);
+    method public void glGetTexParameteriv(int, int, java.nio.IntBuffer);
+    method public void glGetTexParameterxv(int, int, int[], int);
+    method public void glGetTexParameterxv(int, int, java.nio.IntBuffer);
+    method public boolean glIsBuffer(int);
+    method public boolean glIsEnabled(int);
+    method public boolean glIsTexture(int);
+    method public void glNormalPointer(int, int, int);
+    method public void glPointParameterf(int, float);
+    method public void glPointParameterfv(int, float[], int);
+    method public void glPointParameterfv(int, java.nio.FloatBuffer);
+    method public void glPointParameterx(int, int);
+    method public void glPointParameterxv(int, int[], int);
+    method public void glPointParameterxv(int, java.nio.IntBuffer);
+    method public void glPointSizePointerOES(int, int, java.nio.Buffer);
+    method public void glTexCoordPointer(int, int, int, int);
+    method public void glTexEnvi(int, int, int);
+    method public void glTexEnviv(int, int, int[], int);
+    method public void glTexEnviv(int, int, java.nio.IntBuffer);
+    method public void glTexParameterfv(int, int, float[], int);
+    method public void glTexParameterfv(int, int, java.nio.FloatBuffer);
+    method public void glTexParameteri(int, int, int);
+    method public void glTexParameteriv(int, int, int[], int);
+    method public void glTexParameteriv(int, int, java.nio.IntBuffer);
+    method public void glTexParameterxv(int, int, int[], int);
+    method public void glTexParameterxv(int, int, java.nio.IntBuffer);
+    method public void glVertexPointer(int, int, int, int);
     field public static final int GL_ACTIVE_TEXTURE = 34016; // 0x84e0
     field public static final int GL_ADD_SIGNED = 34164; // 0x8574
     field public static final int GL_ALPHA_SCALE = 3356; // 0xd1c
@@ -74623,28 +74915,28 @@
     field public static final int GL_WRITE_ONLY = 35001; // 0x88b9
   }
 
-  public abstract interface GL11Ext implements javax.microedition.khronos.opengles.GL {
-    method public abstract void glCurrentPaletteMatrixOES(int);
-    method public abstract void glDrawTexfOES(float, float, float, float, float);
-    method public abstract void glDrawTexfvOES(float[], int);
-    method public abstract void glDrawTexfvOES(java.nio.FloatBuffer);
-    method public abstract void glDrawTexiOES(int, int, int, int, int);
-    method public abstract void glDrawTexivOES(int[], int);
-    method public abstract void glDrawTexivOES(java.nio.IntBuffer);
-    method public abstract void glDrawTexsOES(short, short, short, short, short);
-    method public abstract void glDrawTexsvOES(short[], int);
-    method public abstract void glDrawTexsvOES(java.nio.ShortBuffer);
-    method public abstract void glDrawTexxOES(int, int, int, int, int);
-    method public abstract void glDrawTexxvOES(int[], int);
-    method public abstract void glDrawTexxvOES(java.nio.IntBuffer);
-    method public abstract void glEnable(int);
-    method public abstract void glEnableClientState(int);
-    method public abstract void glLoadPaletteFromModelViewMatrixOES();
-    method public abstract void glMatrixIndexPointerOES(int, int, int, java.nio.Buffer);
-    method public abstract void glMatrixIndexPointerOES(int, int, int, int);
-    method public abstract void glTexParameterfv(int, int, float[], int);
-    method public abstract void glWeightPointerOES(int, int, int, java.nio.Buffer);
-    method public abstract void glWeightPointerOES(int, int, int, int);
+  public interface GL11Ext extends javax.microedition.khronos.opengles.GL {
+    method public void glCurrentPaletteMatrixOES(int);
+    method public void glDrawTexfOES(float, float, float, float, float);
+    method public void glDrawTexfvOES(float[], int);
+    method public void glDrawTexfvOES(java.nio.FloatBuffer);
+    method public void glDrawTexiOES(int, int, int, int, int);
+    method public void glDrawTexivOES(int[], int);
+    method public void glDrawTexivOES(java.nio.IntBuffer);
+    method public void glDrawTexsOES(short, short, short, short, short);
+    method public void glDrawTexsvOES(short[], int);
+    method public void glDrawTexsvOES(java.nio.ShortBuffer);
+    method public void glDrawTexxOES(int, int, int, int, int);
+    method public void glDrawTexxvOES(int[], int);
+    method public void glDrawTexxvOES(java.nio.IntBuffer);
+    method public void glEnable(int);
+    method public void glEnableClientState(int);
+    method public void glLoadPaletteFromModelViewMatrixOES();
+    method public void glMatrixIndexPointerOES(int, int, int, java.nio.Buffer);
+    method public void glMatrixIndexPointerOES(int, int, int, int);
+    method public void glTexParameterfv(int, int, float[], int);
+    method public void glWeightPointerOES(int, int, int, java.nio.Buffer);
+    method public void glWeightPointerOES(int, int, int, int);
     field public static final int GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES = 35742; // 0x8b9e
     field public static final int GL_MATRIX_INDEX_ARRAY_OES = 34884; // 0x8844
     field public static final int GL_MATRIX_INDEX_ARRAY_POINTER_OES = 34889; // 0x8849
@@ -74663,60 +74955,60 @@
     field public static final int GL_WEIGHT_ARRAY_TYPE_OES = 34473; // 0x86a9
   }
 
-  public abstract interface GL11ExtensionPack implements javax.microedition.khronos.opengles.GL {
-    method public abstract void glBindFramebufferOES(int, int);
-    method public abstract void glBindRenderbufferOES(int, int);
-    method public abstract void glBindTexture(int, int);
-    method public abstract void glBlendEquation(int);
-    method public abstract void glBlendEquationSeparate(int, int);
-    method public abstract void glBlendFuncSeparate(int, int, int, int);
-    method public abstract int glCheckFramebufferStatusOES(int);
-    method public abstract void glCompressedTexImage2D(int, int, int, int, int, int, int, java.nio.Buffer);
-    method public abstract void glCopyTexImage2D(int, int, int, int, int, int, int, int);
-    method public abstract void glDeleteFramebuffersOES(int, int[], int);
-    method public abstract void glDeleteFramebuffersOES(int, java.nio.IntBuffer);
-    method public abstract void glDeleteRenderbuffersOES(int, int[], int);
-    method public abstract void glDeleteRenderbuffersOES(int, java.nio.IntBuffer);
-    method public abstract void glEnable(int);
-    method public abstract void glFramebufferRenderbufferOES(int, int, int, int);
-    method public abstract void glFramebufferTexture2DOES(int, int, int, int, int);
-    method public abstract void glGenFramebuffersOES(int, int[], int);
-    method public abstract void glGenFramebuffersOES(int, java.nio.IntBuffer);
-    method public abstract void glGenRenderbuffersOES(int, int[], int);
-    method public abstract void glGenRenderbuffersOES(int, java.nio.IntBuffer);
-    method public abstract void glGenerateMipmapOES(int);
-    method public abstract void glGetFramebufferAttachmentParameterivOES(int, int, int, int[], int);
-    method public abstract void glGetFramebufferAttachmentParameterivOES(int, int, int, java.nio.IntBuffer);
-    method public abstract void glGetIntegerv(int, int[], int);
-    method public abstract void glGetIntegerv(int, java.nio.IntBuffer);
-    method public abstract void glGetRenderbufferParameterivOES(int, int, int[], int);
-    method public abstract void glGetRenderbufferParameterivOES(int, int, java.nio.IntBuffer);
-    method public abstract void glGetTexGenfv(int, int, float[], int);
-    method public abstract void glGetTexGenfv(int, int, java.nio.FloatBuffer);
-    method public abstract void glGetTexGeniv(int, int, int[], int);
-    method public abstract void glGetTexGeniv(int, int, java.nio.IntBuffer);
-    method public abstract void glGetTexGenxv(int, int, int[], int);
-    method public abstract void glGetTexGenxv(int, int, java.nio.IntBuffer);
-    method public abstract boolean glIsFramebufferOES(int);
-    method public abstract boolean glIsRenderbufferOES(int);
-    method public abstract void glRenderbufferStorageOES(int, int, int, int);
-    method public abstract void glStencilOp(int, int, int);
-    method public abstract void glTexEnvf(int, int, float);
-    method public abstract void glTexEnvfv(int, int, float[], int);
-    method public abstract void glTexEnvfv(int, int, java.nio.FloatBuffer);
-    method public abstract void glTexEnvx(int, int, int);
-    method public abstract void glTexEnvxv(int, int, int[], int);
-    method public abstract void glTexEnvxv(int, int, java.nio.IntBuffer);
-    method public abstract void glTexGenf(int, int, float);
-    method public abstract void glTexGenfv(int, int, float[], int);
-    method public abstract void glTexGenfv(int, int, java.nio.FloatBuffer);
-    method public abstract void glTexGeni(int, int, int);
-    method public abstract void glTexGeniv(int, int, int[], int);
-    method public abstract void glTexGeniv(int, int, java.nio.IntBuffer);
-    method public abstract void glTexGenx(int, int, int);
-    method public abstract void glTexGenxv(int, int, int[], int);
-    method public abstract void glTexGenxv(int, int, java.nio.IntBuffer);
-    method public abstract void glTexParameterf(int, int, float);
+  public interface GL11ExtensionPack extends javax.microedition.khronos.opengles.GL {
+    method public void glBindFramebufferOES(int, int);
+    method public void glBindRenderbufferOES(int, int);
+    method public void glBindTexture(int, int);
+    method public void glBlendEquation(int);
+    method public void glBlendEquationSeparate(int, int);
+    method public void glBlendFuncSeparate(int, int, int, int);
+    method public int glCheckFramebufferStatusOES(int);
+    method public void glCompressedTexImage2D(int, int, int, int, int, int, int, java.nio.Buffer);
+    method public void glCopyTexImage2D(int, int, int, int, int, int, int, int);
+    method public void glDeleteFramebuffersOES(int, int[], int);
+    method public void glDeleteFramebuffersOES(int, java.nio.IntBuffer);
+    method public void glDeleteRenderbuffersOES(int, int[], int);
+    method public void glDeleteRenderbuffersOES(int, java.nio.IntBuffer);
+    method public void glEnable(int);
+    method public void glFramebufferRenderbufferOES(int, int, int, int);
+    method public void glFramebufferTexture2DOES(int, int, int, int, int);
+    method public void glGenFramebuffersOES(int, int[], int);
+    method public void glGenFramebuffersOES(int, java.nio.IntBuffer);
+    method public void glGenRenderbuffersOES(int, int[], int);
+    method public void glGenRenderbuffersOES(int, java.nio.IntBuffer);
+    method public void glGenerateMipmapOES(int);
+    method public void glGetFramebufferAttachmentParameterivOES(int, int, int, int[], int);
+    method public void glGetFramebufferAttachmentParameterivOES(int, int, int, java.nio.IntBuffer);
+    method public void glGetIntegerv(int, int[], int);
+    method public void glGetIntegerv(int, java.nio.IntBuffer);
+    method public void glGetRenderbufferParameterivOES(int, int, int[], int);
+    method public void glGetRenderbufferParameterivOES(int, int, java.nio.IntBuffer);
+    method public void glGetTexGenfv(int, int, float[], int);
+    method public void glGetTexGenfv(int, int, java.nio.FloatBuffer);
+    method public void glGetTexGeniv(int, int, int[], int);
+    method public void glGetTexGeniv(int, int, java.nio.IntBuffer);
+    method public void glGetTexGenxv(int, int, int[], int);
+    method public void glGetTexGenxv(int, int, java.nio.IntBuffer);
+    method public boolean glIsFramebufferOES(int);
+    method public boolean glIsRenderbufferOES(int);
+    method public void glRenderbufferStorageOES(int, int, int, int);
+    method public void glStencilOp(int, int, int);
+    method public void glTexEnvf(int, int, float);
+    method public void glTexEnvfv(int, int, float[], int);
+    method public void glTexEnvfv(int, int, java.nio.FloatBuffer);
+    method public void glTexEnvx(int, int, int);
+    method public void glTexEnvxv(int, int, int[], int);
+    method public void glTexEnvxv(int, int, java.nio.IntBuffer);
+    method public void glTexGenf(int, int, float);
+    method public void glTexGenfv(int, int, float[], int);
+    method public void glTexGenfv(int, int, java.nio.FloatBuffer);
+    method public void glTexGeni(int, int, int);
+    method public void glTexGeniv(int, int, int[], int);
+    method public void glTexGeniv(int, int, java.nio.IntBuffer);
+    method public void glTexGenx(int, int, int);
+    method public void glTexGenxv(int, int, int[], int);
+    method public void glTexGenxv(int, int, java.nio.IntBuffer);
+    method public void glTexParameterf(int, int, float);
     field public static final int GL_BLEND_DST_ALPHA = 32970; // 0x80ca
     field public static final int GL_BLEND_DST_RGB = 32968; // 0x80c8
     field public static final int GL_BLEND_EQUATION = 32777; // 0x8009
@@ -74821,8 +75113,8 @@
   public abstract class SocketFactory {
     ctor protected SocketFactory();
     method public java.net.Socket createSocket() throws java.io.IOException;
-    method public abstract java.net.Socket createSocket(java.lang.String, int) throws java.io.IOException, java.net.UnknownHostException;
-    method public abstract java.net.Socket createSocket(java.lang.String, int, java.net.InetAddress, int) throws java.io.IOException, java.net.UnknownHostException;
+    method public abstract java.net.Socket createSocket(String, int) throws java.io.IOException, java.net.UnknownHostException;
+    method public abstract java.net.Socket createSocket(String, int, java.net.InetAddress, int) throws java.io.IOException, java.net.UnknownHostException;
     method public abstract java.net.Socket createSocket(java.net.InetAddress, int) throws java.io.IOException;
     method public abstract java.net.Socket createSocket(java.net.InetAddress, int, java.net.InetAddress, int) throws java.io.IOException;
     method public static javax.net.SocketFactory getDefault();
@@ -74839,14 +75131,14 @@
 
   public abstract class ExtendedSSLSession implements javax.net.ssl.SSLSession {
     ctor public ExtendedSSLSession();
-    method public abstract java.lang.String[] getLocalSupportedSignatureAlgorithms();
-    method public abstract java.lang.String[] getPeerSupportedSignatureAlgorithms();
+    method public abstract String[] getLocalSupportedSignatureAlgorithms();
+    method public abstract String[] getPeerSupportedSignatureAlgorithms();
     method public java.util.List<javax.net.ssl.SNIServerName> getRequestedServerNames();
   }
 
   public class HandshakeCompletedEvent extends java.util.EventObject {
     ctor public HandshakeCompletedEvent(javax.net.ssl.SSLSocket, javax.net.ssl.SSLSession);
-    method public java.lang.String getCipherSuite();
+    method public String getCipherSuite();
     method public java.security.cert.Certificate[] getLocalCertificates();
     method public java.security.Principal getLocalPrincipal();
     method public javax.security.cert.X509Certificate[] getPeerCertificateChain() throws javax.net.ssl.SSLPeerUnverifiedException;
@@ -74856,17 +75148,17 @@
     method public javax.net.ssl.SSLSocket getSocket();
   }
 
-  public abstract interface HandshakeCompletedListener implements java.util.EventListener {
-    method public abstract void handshakeCompleted(javax.net.ssl.HandshakeCompletedEvent);
+  public interface HandshakeCompletedListener extends java.util.EventListener {
+    method public void handshakeCompleted(javax.net.ssl.HandshakeCompletedEvent);
   }
 
-  public abstract interface HostnameVerifier {
-    method public abstract boolean verify(java.lang.String, javax.net.ssl.SSLSession);
+  public interface HostnameVerifier {
+    method public boolean verify(String, javax.net.ssl.SSLSession);
   }
 
   public abstract class HttpsURLConnection extends java.net.HttpURLConnection {
     ctor protected HttpsURLConnection(java.net.URL);
-    method public abstract java.lang.String getCipherSuite();
+    method public abstract String getCipherSuite();
     method public static javax.net.ssl.HostnameVerifier getDefaultHostnameVerifier();
     method public static javax.net.ssl.SSLSocketFactory getDefaultSSLSocketFactory();
     method public javax.net.ssl.HostnameVerifier getHostnameVerifier();
@@ -74882,16 +75174,16 @@
     field protected javax.net.ssl.HostnameVerifier hostnameVerifier;
   }
 
-  public abstract interface KeyManager {
+  public interface KeyManager {
   }
 
   public class KeyManagerFactory {
-    ctor protected KeyManagerFactory(javax.net.ssl.KeyManagerFactorySpi, java.security.Provider, java.lang.String);
-    method public final java.lang.String getAlgorithm();
-    method public static final java.lang.String getDefaultAlgorithm();
-    method public static final javax.net.ssl.KeyManagerFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static final javax.net.ssl.KeyManagerFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static final javax.net.ssl.KeyManagerFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    ctor protected KeyManagerFactory(javax.net.ssl.KeyManagerFactorySpi, java.security.Provider, String);
+    method public final String getAlgorithm();
+    method public static final String getDefaultAlgorithm();
+    method public static final javax.net.ssl.KeyManagerFactory getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static final javax.net.ssl.KeyManagerFactory getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static final javax.net.ssl.KeyManagerFactory getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final javax.net.ssl.KeyManager[] getKeyManagers();
     method public final java.security.Provider getProvider();
     method public final void init(java.security.KeyStore, char[]) throws java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException;
@@ -74911,14 +75203,14 @@
     method public java.util.List<java.security.KeyStore.Builder> getParameters();
   }
 
-  public abstract interface ManagerFactoryParameters {
+  public interface ManagerFactoryParameters {
   }
 
   public final class SNIHostName extends javax.net.ssl.SNIServerName {
-    ctor public SNIHostName(java.lang.String);
+    ctor public SNIHostName(String);
     ctor public SNIHostName(byte[]);
-    method public static javax.net.ssl.SNIMatcher createSNIMatcher(java.lang.String);
-    method public java.lang.String getAsciiName();
+    method public static javax.net.ssl.SNIMatcher createSNIMatcher(String);
+    method public String getAsciiName();
   }
 
   public abstract class SNIMatcher {
@@ -74934,29 +75226,29 @@
   }
 
   public class SSLContext {
-    ctor protected SSLContext(javax.net.ssl.SSLContextSpi, java.security.Provider, java.lang.String);
+    ctor protected SSLContext(javax.net.ssl.SSLContextSpi, java.security.Provider, String);
     method public final javax.net.ssl.SSLEngine createSSLEngine();
-    method public final javax.net.ssl.SSLEngine createSSLEngine(java.lang.String, int);
+    method public final javax.net.ssl.SSLEngine createSSLEngine(String, int);
     method public final javax.net.ssl.SSLSessionContext getClientSessionContext();
-    method public static synchronized javax.net.ssl.SSLContext getDefault() throws java.security.NoSuchAlgorithmException;
+    method public static javax.net.ssl.SSLContext getDefault() throws java.security.NoSuchAlgorithmException;
     method public final javax.net.ssl.SSLParameters getDefaultSSLParameters();
-    method public static javax.net.ssl.SSLContext getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static javax.net.ssl.SSLContext getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static javax.net.ssl.SSLContext getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
-    method public final java.lang.String getProtocol();
+    method public static javax.net.ssl.SSLContext getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static javax.net.ssl.SSLContext getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static javax.net.ssl.SSLContext getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    method public final String getProtocol();
     method public final java.security.Provider getProvider();
     method public final javax.net.ssl.SSLSessionContext getServerSessionContext();
     method public final javax.net.ssl.SSLServerSocketFactory getServerSocketFactory();
     method public final javax.net.ssl.SSLSocketFactory getSocketFactory();
     method public final javax.net.ssl.SSLParameters getSupportedSSLParameters();
     method public final void init(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], java.security.SecureRandom) throws java.security.KeyManagementException;
-    method public static synchronized void setDefault(javax.net.ssl.SSLContext);
+    method public static void setDefault(javax.net.ssl.SSLContext);
   }
 
   public abstract class SSLContextSpi {
     ctor public SSLContextSpi();
     method protected abstract javax.net.ssl.SSLEngine engineCreateSSLEngine();
-    method protected abstract javax.net.ssl.SSLEngine engineCreateSSLEngine(java.lang.String, int);
+    method protected abstract javax.net.ssl.SSLEngine engineCreateSSLEngine(String, int);
     method protected abstract javax.net.ssl.SSLSessionContext engineGetClientSessionContext();
     method protected javax.net.ssl.SSLParameters engineGetDefaultSSLParameters();
     method protected abstract javax.net.ssl.SSLSessionContext engineGetServerSessionContext();
@@ -74968,34 +75260,34 @@
 
   public abstract class SSLEngine {
     ctor protected SSLEngine();
-    ctor protected SSLEngine(java.lang.String, int);
+    ctor protected SSLEngine(String, int);
     method public abstract void beginHandshake() throws javax.net.ssl.SSLException;
     method public abstract void closeInbound() throws javax.net.ssl.SSLException;
     method public abstract void closeOutbound();
-    method public java.lang.String getApplicationProtocol();
-    method public abstract java.lang.Runnable getDelegatedTask();
+    method public String getApplicationProtocol();
+    method public abstract Runnable getDelegatedTask();
     method public abstract boolean getEnableSessionCreation();
-    method public abstract java.lang.String[] getEnabledCipherSuites();
-    method public abstract java.lang.String[] getEnabledProtocols();
-    method public java.lang.String getHandshakeApplicationProtocol();
-    method public java.util.function.BiFunction<javax.net.ssl.SSLEngine, java.util.List<java.lang.String>, java.lang.String> getHandshakeApplicationProtocolSelector();
+    method public abstract String[] getEnabledCipherSuites();
+    method public abstract String[] getEnabledProtocols();
+    method public String getHandshakeApplicationProtocol();
+    method public java.util.function.BiFunction<javax.net.ssl.SSLEngine,java.util.List<java.lang.String>,java.lang.String> getHandshakeApplicationProtocolSelector();
     method public javax.net.ssl.SSLSession getHandshakeSession();
     method public abstract javax.net.ssl.SSLEngineResult.HandshakeStatus getHandshakeStatus();
     method public abstract boolean getNeedClientAuth();
-    method public java.lang.String getPeerHost();
+    method public String getPeerHost();
     method public int getPeerPort();
     method public javax.net.ssl.SSLParameters getSSLParameters();
     method public abstract javax.net.ssl.SSLSession getSession();
-    method public abstract java.lang.String[] getSupportedCipherSuites();
-    method public abstract java.lang.String[] getSupportedProtocols();
+    method public abstract String[] getSupportedCipherSuites();
+    method public abstract String[] getSupportedProtocols();
     method public abstract boolean getUseClientMode();
     method public abstract boolean getWantClientAuth();
     method public abstract boolean isInboundDone();
     method public abstract boolean isOutboundDone();
     method public abstract void setEnableSessionCreation(boolean);
-    method public abstract void setEnabledCipherSuites(java.lang.String[]);
-    method public abstract void setEnabledProtocols(java.lang.String[]);
-    method public void setHandshakeApplicationProtocolSelector(java.util.function.BiFunction<javax.net.ssl.SSLEngine, java.util.List<java.lang.String>, java.lang.String>);
+    method public abstract void setEnabledCipherSuites(String[]);
+    method public abstract void setEnabledProtocols(String[]);
+    method public void setHandshakeApplicationProtocolSelector(java.util.function.BiFunction<javax.net.ssl.SSLEngine,java.util.List<java.lang.String>,java.lang.String>);
     method public abstract void setNeedClientAuth(boolean);
     method public void setSSLParameters(javax.net.ssl.SSLParameters);
     method public abstract void setUseClientMode(boolean);
@@ -75016,9 +75308,7 @@
     method public final javax.net.ssl.SSLEngineResult.Status getStatus();
   }
 
-  public static final class SSLEngineResult.HandshakeStatus extends java.lang.Enum {
-    method public static javax.net.ssl.SSLEngineResult.HandshakeStatus valueOf(java.lang.String);
-    method public static final javax.net.ssl.SSLEngineResult.HandshakeStatus[] values();
+  public enum SSLEngineResult.HandshakeStatus {
     enum_constant public static final javax.net.ssl.SSLEngineResult.HandshakeStatus FINISHED;
     enum_constant public static final javax.net.ssl.SSLEngineResult.HandshakeStatus NEED_TASK;
     enum_constant public static final javax.net.ssl.SSLEngineResult.HandshakeStatus NEED_UNWRAP;
@@ -75026,9 +75316,7 @@
     enum_constant public static final javax.net.ssl.SSLEngineResult.HandshakeStatus NOT_HANDSHAKING;
   }
 
-  public static final class SSLEngineResult.Status extends java.lang.Enum {
-    method public static javax.net.ssl.SSLEngineResult.Status valueOf(java.lang.String);
-    method public static final javax.net.ssl.SSLEngineResult.Status[] values();
+  public enum SSLEngineResult.Status {
     enum_constant public static final javax.net.ssl.SSLEngineResult.Status BUFFER_OVERFLOW;
     enum_constant public static final javax.net.ssl.SSLEngineResult.Status BUFFER_UNDERFLOW;
     enum_constant public static final javax.net.ssl.SSLEngineResult.Status CLOSED;
@@ -75036,39 +75324,39 @@
   }
 
   public class SSLException extends java.io.IOException {
-    ctor public SSLException(java.lang.String);
-    ctor public SSLException(java.lang.String, java.lang.Throwable);
-    ctor public SSLException(java.lang.Throwable);
+    ctor public SSLException(String);
+    ctor public SSLException(String, Throwable);
+    ctor public SSLException(Throwable);
   }
 
   public class SSLHandshakeException extends javax.net.ssl.SSLException {
-    ctor public SSLHandshakeException(java.lang.String);
+    ctor public SSLHandshakeException(String);
   }
 
   public class SSLKeyException extends javax.net.ssl.SSLException {
-    ctor public SSLKeyException(java.lang.String);
+    ctor public SSLKeyException(String);
   }
 
   public class SSLParameters {
     ctor public SSLParameters();
-    ctor public SSLParameters(java.lang.String[]);
-    ctor public SSLParameters(java.lang.String[], java.lang.String[]);
+    ctor public SSLParameters(String[]);
+    ctor public SSLParameters(String[], String[]);
     method public java.security.AlgorithmConstraints getAlgorithmConstraints();
-    method public java.lang.String[] getApplicationProtocols();
-    method public java.lang.String[] getCipherSuites();
-    method public java.lang.String getEndpointIdentificationAlgorithm();
+    method public String[] getApplicationProtocols();
+    method public String[] getCipherSuites();
+    method public String getEndpointIdentificationAlgorithm();
     method public boolean getNeedClientAuth();
-    method public java.lang.String[] getProtocols();
+    method public String[] getProtocols();
     method public final java.util.Collection<javax.net.ssl.SNIMatcher> getSNIMatchers();
     method public final java.util.List<javax.net.ssl.SNIServerName> getServerNames();
     method public final boolean getUseCipherSuitesOrder();
     method public boolean getWantClientAuth();
     method public void setAlgorithmConstraints(java.security.AlgorithmConstraints);
-    method public void setApplicationProtocols(java.lang.String[]);
-    method public void setCipherSuites(java.lang.String[]);
-    method public void setEndpointIdentificationAlgorithm(java.lang.String);
+    method public void setApplicationProtocols(String[]);
+    method public void setCipherSuites(String[]);
+    method public void setEndpointIdentificationAlgorithm(String);
     method public void setNeedClientAuth(boolean);
-    method public void setProtocols(java.lang.String[]);
+    method public void setProtocols(String[]);
     method public final void setSNIMatchers(java.util.Collection<javax.net.ssl.SNIMatcher>);
     method public final void setServerNames(java.util.List<javax.net.ssl.SNIServerName>);
     method public final void setUseCipherSuitesOrder(boolean);
@@ -75076,16 +75364,16 @@
   }
 
   public class SSLPeerUnverifiedException extends javax.net.ssl.SSLException {
-    ctor public SSLPeerUnverifiedException(java.lang.String);
+    ctor public SSLPeerUnverifiedException(String);
   }
 
   public final class SSLPermission extends java.security.BasicPermission {
-    ctor public SSLPermission(java.lang.String);
-    ctor public SSLPermission(java.lang.String, java.lang.String);
+    ctor public SSLPermission(String);
+    ctor public SSLPermission(String, String);
   }
 
   public class SSLProtocolException extends javax.net.ssl.SSLException {
-    ctor public SSLProtocolException(java.lang.String);
+    ctor public SSLProtocolException(String);
   }
 
   public abstract class SSLServerSocket extends java.net.ServerSocket {
@@ -75094,17 +75382,17 @@
     ctor protected SSLServerSocket(int, int) throws java.io.IOException;
     ctor protected SSLServerSocket(int, int, java.net.InetAddress) throws java.io.IOException;
     method public abstract boolean getEnableSessionCreation();
-    method public abstract java.lang.String[] getEnabledCipherSuites();
-    method public abstract java.lang.String[] getEnabledProtocols();
+    method public abstract String[] getEnabledCipherSuites();
+    method public abstract String[] getEnabledProtocols();
     method public abstract boolean getNeedClientAuth();
     method public javax.net.ssl.SSLParameters getSSLParameters();
-    method public abstract java.lang.String[] getSupportedCipherSuites();
-    method public abstract java.lang.String[] getSupportedProtocols();
+    method public abstract String[] getSupportedCipherSuites();
+    method public abstract String[] getSupportedProtocols();
     method public abstract boolean getUseClientMode();
     method public abstract boolean getWantClientAuth();
     method public abstract void setEnableSessionCreation(boolean);
-    method public abstract void setEnabledCipherSuites(java.lang.String[]);
-    method public abstract void setEnabledProtocols(java.lang.String[]);
+    method public abstract void setEnabledCipherSuites(String[]);
+    method public abstract void setEnabledProtocols(String[]);
     method public abstract void setNeedClientAuth(boolean);
     method public void setSSLParameters(javax.net.ssl.SSLParameters);
     method public abstract void setUseClientMode(boolean);
@@ -75113,81 +75401,81 @@
 
   public abstract class SSLServerSocketFactory extends javax.net.ServerSocketFactory {
     ctor protected SSLServerSocketFactory();
-    method public static synchronized javax.net.ServerSocketFactory getDefault();
-    method public abstract java.lang.String[] getDefaultCipherSuites();
-    method public abstract java.lang.String[] getSupportedCipherSuites();
+    method public static javax.net.ServerSocketFactory getDefault();
+    method public abstract String[] getDefaultCipherSuites();
+    method public abstract String[] getSupportedCipherSuites();
   }
 
-  public abstract interface SSLSession {
-    method public abstract int getApplicationBufferSize();
-    method public abstract java.lang.String getCipherSuite();
-    method public abstract long getCreationTime();
-    method public abstract byte[] getId();
-    method public abstract long getLastAccessedTime();
-    method public abstract java.security.cert.Certificate[] getLocalCertificates();
-    method public abstract java.security.Principal getLocalPrincipal();
-    method public abstract int getPacketBufferSize();
-    method public abstract javax.security.cert.X509Certificate[] getPeerCertificateChain() throws javax.net.ssl.SSLPeerUnverifiedException;
-    method public abstract java.security.cert.Certificate[] getPeerCertificates() throws javax.net.ssl.SSLPeerUnverifiedException;
-    method public abstract java.lang.String getPeerHost();
-    method public abstract int getPeerPort();
-    method public abstract java.security.Principal getPeerPrincipal() throws javax.net.ssl.SSLPeerUnverifiedException;
-    method public abstract java.lang.String getProtocol();
-    method public abstract javax.net.ssl.SSLSessionContext getSessionContext();
-    method public abstract java.lang.Object getValue(java.lang.String);
-    method public abstract java.lang.String[] getValueNames();
-    method public abstract void invalidate();
-    method public abstract boolean isValid();
-    method public abstract void putValue(java.lang.String, java.lang.Object);
-    method public abstract void removeValue(java.lang.String);
+  public interface SSLSession {
+    method public int getApplicationBufferSize();
+    method public String getCipherSuite();
+    method public long getCreationTime();
+    method public byte[] getId();
+    method public long getLastAccessedTime();
+    method public java.security.cert.Certificate[] getLocalCertificates();
+    method public java.security.Principal getLocalPrincipal();
+    method public int getPacketBufferSize();
+    method public javax.security.cert.X509Certificate[] getPeerCertificateChain() throws javax.net.ssl.SSLPeerUnverifiedException;
+    method public java.security.cert.Certificate[] getPeerCertificates() throws javax.net.ssl.SSLPeerUnverifiedException;
+    method public String getPeerHost();
+    method public int getPeerPort();
+    method public java.security.Principal getPeerPrincipal() throws javax.net.ssl.SSLPeerUnverifiedException;
+    method public String getProtocol();
+    method public javax.net.ssl.SSLSessionContext getSessionContext();
+    method public Object getValue(String);
+    method public String[] getValueNames();
+    method public void invalidate();
+    method public boolean isValid();
+    method public void putValue(String, Object);
+    method public void removeValue(String);
   }
 
   public class SSLSessionBindingEvent extends java.util.EventObject {
-    ctor public SSLSessionBindingEvent(javax.net.ssl.SSLSession, java.lang.String);
-    method public java.lang.String getName();
+    ctor public SSLSessionBindingEvent(javax.net.ssl.SSLSession, String);
+    method public String getName();
     method public javax.net.ssl.SSLSession getSession();
   }
 
-  public abstract interface SSLSessionBindingListener implements java.util.EventListener {
-    method public abstract void valueBound(javax.net.ssl.SSLSessionBindingEvent);
-    method public abstract void valueUnbound(javax.net.ssl.SSLSessionBindingEvent);
+  public interface SSLSessionBindingListener extends java.util.EventListener {
+    method public void valueBound(javax.net.ssl.SSLSessionBindingEvent);
+    method public void valueUnbound(javax.net.ssl.SSLSessionBindingEvent);
   }
 
-  public abstract interface SSLSessionContext {
-    method public abstract java.util.Enumeration<byte[]> getIds();
-    method public abstract javax.net.ssl.SSLSession getSession(byte[]);
-    method public abstract int getSessionCacheSize();
-    method public abstract int getSessionTimeout();
-    method public abstract void setSessionCacheSize(int) throws java.lang.IllegalArgumentException;
-    method public abstract void setSessionTimeout(int) throws java.lang.IllegalArgumentException;
+  public interface SSLSessionContext {
+    method public java.util.Enumeration<byte[]> getIds();
+    method public javax.net.ssl.SSLSession getSession(byte[]);
+    method public int getSessionCacheSize();
+    method public int getSessionTimeout();
+    method public void setSessionCacheSize(int) throws java.lang.IllegalArgumentException;
+    method public void setSessionTimeout(int) throws java.lang.IllegalArgumentException;
   }
 
   public abstract class SSLSocket extends java.net.Socket {
     ctor protected SSLSocket();
-    ctor protected SSLSocket(java.lang.String, int) throws java.io.IOException, java.net.UnknownHostException;
+    ctor protected SSLSocket(String, int) throws java.io.IOException, java.net.UnknownHostException;
     ctor protected SSLSocket(java.net.InetAddress, int) throws java.io.IOException;
-    ctor protected SSLSocket(java.lang.String, int, java.net.InetAddress, int) throws java.io.IOException, java.net.UnknownHostException;
+    ctor protected SSLSocket(String, int, java.net.InetAddress, int) throws java.io.IOException, java.net.UnknownHostException;
     ctor protected SSLSocket(java.net.InetAddress, int, java.net.InetAddress, int) throws java.io.IOException;
     method public abstract void addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener);
-    method public java.lang.String getApplicationProtocol();
+    method public String getApplicationProtocol();
     method public abstract boolean getEnableSessionCreation();
-    method public abstract java.lang.String[] getEnabledCipherSuites();
-    method public abstract java.lang.String[] getEnabledProtocols();
-    method public java.lang.String getHandshakeApplicationProtocol();
-    method public java.util.function.BiFunction<javax.net.ssl.SSLSocket, java.util.List<java.lang.String>, java.lang.String> getHandshakeApplicationProtocolSelector();
+    method public abstract String[] getEnabledCipherSuites();
+    method public abstract String[] getEnabledProtocols();
+    method public String getHandshakeApplicationProtocol();
+    method public java.util.function.BiFunction<javax.net.ssl.SSLSocket,java.util.List<java.lang.String>,java.lang.String> getHandshakeApplicationProtocolSelector();
     method public javax.net.ssl.SSLSession getHandshakeSession();
     method public abstract boolean getNeedClientAuth();
     method public javax.net.ssl.SSLParameters getSSLParameters();
     method public abstract javax.net.ssl.SSLSession getSession();
-    method public abstract java.lang.String[] getSupportedCipherSuites();
-    method public abstract java.lang.String[] getSupportedProtocols();
+    method public abstract String[] getSupportedCipherSuites();
+    method public abstract String[] getSupportedProtocols();
     method public abstract boolean getUseClientMode();
     method public abstract boolean getWantClientAuth();
     method public abstract void removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener);
     method public abstract void setEnableSessionCreation(boolean);
-    method public abstract void setEnabledCipherSuites(java.lang.String[]);
-    method public abstract void setEnabledProtocols(java.lang.String[]);
-    method public void setHandshakeApplicationProtocolSelector(java.util.function.BiFunction<javax.net.ssl.SSLSocket, java.util.List<java.lang.String>, java.lang.String>);
+    method public abstract void setEnabledCipherSuites(String[]);
+    method public abstract void setEnabledProtocols(String[]);
+    method public void setHandshakeApplicationProtocolSelector(java.util.function.BiFunction<javax.net.ssl.SSLSocket,java.util.List<java.lang.String>,java.lang.String>);
     method public abstract void setNeedClientAuth(boolean);
     method public void setSSLParameters(javax.net.ssl.SSLParameters);
     method public abstract void setUseClientMode(boolean);
@@ -75197,26 +75485,26 @@
 
   public abstract class SSLSocketFactory extends javax.net.SocketFactory {
     ctor public SSLSocketFactory();
-    method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException;
-    method public static synchronized javax.net.SocketFactory getDefault();
-    method public abstract java.lang.String[] getDefaultCipherSuites();
-    method public abstract java.lang.String[] getSupportedCipherSuites();
+    method public abstract java.net.Socket createSocket(java.net.Socket, String, int, boolean) throws java.io.IOException;
+    method public static javax.net.SocketFactory getDefault();
+    method public abstract String[] getDefaultCipherSuites();
+    method public abstract String[] getSupportedCipherSuites();
   }
 
   public final class StandardConstants {
     field public static final int SNI_HOST_NAME = 0; // 0x0
   }
 
-  public abstract interface TrustManager {
+  public interface TrustManager {
   }
 
   public class TrustManagerFactory {
-    ctor protected TrustManagerFactory(javax.net.ssl.TrustManagerFactorySpi, java.security.Provider, java.lang.String);
-    method public final java.lang.String getAlgorithm();
-    method public static final java.lang.String getDefaultAlgorithm();
-    method public static final javax.net.ssl.TrustManagerFactory getInstance(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public static final javax.net.ssl.TrustManagerFactory getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
-    method public static final javax.net.ssl.TrustManagerFactory getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
+    ctor protected TrustManagerFactory(javax.net.ssl.TrustManagerFactorySpi, java.security.Provider, String);
+    method public final String getAlgorithm();
+    method public static final String getDefaultAlgorithm();
+    method public static final javax.net.ssl.TrustManagerFactory getInstance(String) throws java.security.NoSuchAlgorithmException;
+    method public static final javax.net.ssl.TrustManagerFactory getInstance(String, String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
+    method public static final javax.net.ssl.TrustManagerFactory getInstance(String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
     method public final java.security.Provider getProvider();
     method public final javax.net.ssl.TrustManager[] getTrustManagers();
     method public final void init(java.security.KeyStore) throws java.security.KeyStoreException;
@@ -75232,31 +75520,31 @@
 
   public abstract class X509ExtendedKeyManager implements javax.net.ssl.X509KeyManager {
     ctor protected X509ExtendedKeyManager();
-    method public java.lang.String chooseEngineClientAlias(java.lang.String[], java.security.Principal[], javax.net.ssl.SSLEngine);
-    method public java.lang.String chooseEngineServerAlias(java.lang.String, java.security.Principal[], javax.net.ssl.SSLEngine);
+    method public String chooseEngineClientAlias(String[], java.security.Principal[], javax.net.ssl.SSLEngine);
+    method public String chooseEngineServerAlias(String, java.security.Principal[], javax.net.ssl.SSLEngine);
   }
 
   public abstract class X509ExtendedTrustManager implements javax.net.ssl.X509TrustManager {
     ctor public X509ExtendedTrustManager();
-    method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException;
-    method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
-    method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException;
-    method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
+    method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], String, java.net.Socket) throws java.security.cert.CertificateException;
+    method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
+    method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], String, java.net.Socket) throws java.security.cert.CertificateException;
+    method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
   }
 
-  public abstract interface X509KeyManager implements javax.net.ssl.KeyManager {
-    method public abstract java.lang.String chooseClientAlias(java.lang.String[], java.security.Principal[], java.net.Socket);
-    method public abstract java.lang.String chooseServerAlias(java.lang.String, java.security.Principal[], java.net.Socket);
-    method public abstract java.security.cert.X509Certificate[] getCertificateChain(java.lang.String);
-    method public abstract java.lang.String[] getClientAliases(java.lang.String, java.security.Principal[]);
-    method public abstract java.security.PrivateKey getPrivateKey(java.lang.String);
-    method public abstract java.lang.String[] getServerAliases(java.lang.String, java.security.Principal[]);
+  public interface X509KeyManager extends javax.net.ssl.KeyManager {
+    method public String chooseClientAlias(String[], java.security.Principal[], java.net.Socket);
+    method public String chooseServerAlias(String, java.security.Principal[], java.net.Socket);
+    method public java.security.cert.X509Certificate[] getCertificateChain(String);
+    method public String[] getClientAliases(String, java.security.Principal[]);
+    method public java.security.PrivateKey getPrivateKey(String);
+    method public String[] getServerAliases(String, java.security.Principal[]);
   }
 
-  public abstract interface X509TrustManager implements javax.net.ssl.TrustManager {
-    method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String) throws java.security.cert.CertificateException;
-    method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String) throws java.security.cert.CertificateException;
-    method public abstract java.security.cert.X509Certificate[] getAcceptedIssuers();
+  public interface X509TrustManager extends javax.net.ssl.TrustManager {
+    method public void checkClientTrusted(java.security.cert.X509Certificate[], String) throws java.security.cert.CertificateException;
+    method public void checkServerTrusted(java.security.cert.X509Certificate[], String) throws java.security.cert.CertificateException;
+    method public java.security.cert.X509Certificate[] getAcceptedIssuers();
   }
 
 }
@@ -75264,25 +75552,25 @@
 package javax.security.auth {
 
   public final class AuthPermission extends java.security.BasicPermission {
-    ctor public AuthPermission(java.lang.String);
-    ctor public AuthPermission(java.lang.String, java.lang.String);
+    ctor public AuthPermission(String);
+    ctor public AuthPermission(String, String);
   }
 
   public class DestroyFailedException extends java.lang.Exception {
     ctor public DestroyFailedException();
-    ctor public DestroyFailedException(java.lang.String);
+    ctor public DestroyFailedException(String);
   }
 
-  public abstract interface Destroyable {
+  public interface Destroyable {
     method public default void destroy() throws javax.security.auth.DestroyFailedException;
     method public default boolean isDestroyed();
   }
 
   public final class PrivateCredentialPermission extends java.security.Permission {
-    ctor public PrivateCredentialPermission(java.lang.String, java.lang.String);
-    method public java.lang.String getActions();
-    method public java.lang.String getCredentialClass();
-    method public java.lang.String[][] getPrincipals();
+    ctor public PrivateCredentialPermission(String, String);
+    method public String getActions();
+    method public String getCredentialClass();
+    method public String[][] getPrincipals();
     method public boolean implies(java.security.Permission);
   }
 
@@ -75294,11 +75582,11 @@
     method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedAction<T>, java.security.AccessControlContext);
     method public static <T> T doAsPrivileged(javax.security.auth.Subject, java.security.PrivilegedExceptionAction<T>, java.security.AccessControlContext) throws java.security.PrivilegedActionException;
     method public java.util.Set<java.security.Principal> getPrincipals();
-    method public <T extends java.security.Principal> java.util.Set<T> getPrincipals(java.lang.Class<T>);
+    method public <T extends java.security.Principal> java.util.Set<T> getPrincipals(Class<T>);
     method public java.util.Set<java.lang.Object> getPrivateCredentials();
-    method public <T> java.util.Set<T> getPrivateCredentials(java.lang.Class<T>);
+    method public <T> java.util.Set<T> getPrivateCredentials(Class<T>);
     method public java.util.Set<java.lang.Object> getPublicCredentials();
-    method public <T> java.util.Set<T> getPublicCredentials(java.lang.Class<T>);
+    method public <T> java.util.Set<T> getPublicCredentials(Class<T>);
     method public static javax.security.auth.Subject getSubject(java.security.AccessControlContext);
     method public boolean isReadOnly();
     method public void setReadOnly();
@@ -75314,25 +75602,25 @@
 
 package javax.security.auth.callback {
 
-  public abstract interface Callback {
+  public interface Callback {
   }
 
-  public abstract interface CallbackHandler {
-    method public abstract void handle(javax.security.auth.callback.Callback[]) throws java.io.IOException, javax.security.auth.callback.UnsupportedCallbackException;
+  public interface CallbackHandler {
+    method public void handle(javax.security.auth.callback.Callback[]) throws java.io.IOException, javax.security.auth.callback.UnsupportedCallbackException;
   }
 
   public class PasswordCallback implements javax.security.auth.callback.Callback java.io.Serializable {
-    ctor public PasswordCallback(java.lang.String, boolean);
+    ctor public PasswordCallback(String, boolean);
     method public void clearPassword();
     method public char[] getPassword();
-    method public java.lang.String getPrompt();
+    method public String getPrompt();
     method public boolean isEchoOn();
     method public void setPassword(char[]);
   }
 
   public class UnsupportedCallbackException extends java.lang.Exception {
     ctor public UnsupportedCallbackException(javax.security.auth.callback.Callback);
-    ctor public UnsupportedCallbackException(javax.security.auth.callback.Callback, java.lang.String);
+    ctor public UnsupportedCallbackException(javax.security.auth.callback.Callback, String);
     method public javax.security.auth.callback.Callback getCallback();
   }
 
@@ -75342,7 +75630,7 @@
 
   public class LoginException extends java.security.GeneralSecurityException {
     ctor public LoginException();
-    ctor public LoginException(java.lang.String);
+    ctor public LoginException(String);
   }
 
 }
@@ -75350,17 +75638,17 @@
 package javax.security.auth.x500 {
 
   public final class X500Principal implements java.security.Principal java.io.Serializable {
-    ctor public X500Principal(java.lang.String);
-    ctor public X500Principal(java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
+    ctor public X500Principal(String);
+    ctor public X500Principal(String, java.util.Map<java.lang.String,java.lang.String>);
     ctor public X500Principal(byte[]);
     ctor public X500Principal(java.io.InputStream);
     method public byte[] getEncoded();
-    method public java.lang.String getName();
-    method public java.lang.String getName(java.lang.String);
-    method public java.lang.String getName(java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
-    field public static final java.lang.String CANONICAL = "CANONICAL";
-    field public static final java.lang.String RFC1779 = "RFC1779";
-    field public static final java.lang.String RFC2253 = "RFC2253";
+    method public String getName();
+    method public String getName(String);
+    method public String getName(String, java.util.Map<java.lang.String,java.lang.String>);
+    field public static final String CANONICAL = "CANONICAL";
+    field public static final String RFC1779 = "RFC1779";
+    field public static final String RFC2253 = "RFC2253";
   }
 
 }
@@ -75371,34 +75659,34 @@
     ctor public Certificate();
     method public abstract byte[] getEncoded() throws javax.security.cert.CertificateEncodingException;
     method public abstract java.security.PublicKey getPublicKey();
-    method public abstract java.lang.String toString();
+    method public abstract String toString();
     method public abstract void verify(java.security.PublicKey) throws javax.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
-    method public abstract void verify(java.security.PublicKey, java.lang.String) throws javax.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
+    method public abstract void verify(java.security.PublicKey, String) throws javax.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException, java.security.SignatureException;
   }
 
   public class CertificateEncodingException extends javax.security.cert.CertificateException {
     ctor public CertificateEncodingException();
-    ctor public CertificateEncodingException(java.lang.String);
+    ctor public CertificateEncodingException(String);
   }
 
   public class CertificateException extends java.lang.Exception {
     ctor public CertificateException();
-    ctor public CertificateException(java.lang.String);
+    ctor public CertificateException(String);
   }
 
   public class CertificateExpiredException extends javax.security.cert.CertificateException {
     ctor public CertificateExpiredException();
-    ctor public CertificateExpiredException(java.lang.String);
+    ctor public CertificateExpiredException(String);
   }
 
   public class CertificateNotYetValidException extends javax.security.cert.CertificateException {
     ctor public CertificateNotYetValidException();
-    ctor public CertificateNotYetValidException(java.lang.String);
+    ctor public CertificateNotYetValidException(String);
   }
 
   public class CertificateParsingException extends javax.security.cert.CertificateException {
     ctor public CertificateParsingException();
-    ctor public CertificateParsingException(java.lang.String);
+    ctor public CertificateParsingException(String);
   }
 
   public abstract class X509Certificate extends javax.security.cert.Certificate {
@@ -75411,8 +75699,8 @@
     method public abstract java.util.Date getNotAfter();
     method public abstract java.util.Date getNotBefore();
     method public abstract java.math.BigInteger getSerialNumber();
-    method public abstract java.lang.String getSigAlgName();
-    method public abstract java.lang.String getSigAlgOID();
+    method public abstract String getSigAlgName();
+    method public abstract String getSigAlgOID();
     method public abstract byte[] getSigAlgParams();
     method public abstract java.security.Principal getSubjectDN();
     method public abstract int getVersion();
@@ -75422,12 +75710,12 @@
 
 package javax.sql {
 
-  public abstract interface CommonDataSource {
-    method public abstract java.io.PrintWriter getLogWriter() throws java.sql.SQLException;
-    method public abstract int getLoginTimeout() throws java.sql.SQLException;
-    method public abstract java.util.logging.Logger getParentLogger() throws java.sql.SQLFeatureNotSupportedException;
-    method public abstract void setLogWriter(java.io.PrintWriter) throws java.sql.SQLException;
-    method public abstract void setLoginTimeout(int) throws java.sql.SQLException;
+  public interface CommonDataSource {
+    method public java.io.PrintWriter getLogWriter() throws java.sql.SQLException;
+    method public int getLoginTimeout() throws java.sql.SQLException;
+    method public java.util.logging.Logger getParentLogger() throws java.sql.SQLFeatureNotSupportedException;
+    method public void setLogWriter(java.io.PrintWriter) throws java.sql.SQLException;
+    method public void setLoginTimeout(int) throws java.sql.SQLException;
   }
 
   public class ConnectionEvent extends java.util.EventObject {
@@ -75436,192 +75724,192 @@
     method public java.sql.SQLException getSQLException();
   }
 
-  public abstract interface ConnectionEventListener implements java.util.EventListener {
-    method public abstract void connectionClosed(javax.sql.ConnectionEvent);
-    method public abstract void connectionErrorOccurred(javax.sql.ConnectionEvent);
+  public interface ConnectionEventListener extends java.util.EventListener {
+    method public void connectionClosed(javax.sql.ConnectionEvent);
+    method public void connectionErrorOccurred(javax.sql.ConnectionEvent);
   }
 
-  public abstract interface ConnectionPoolDataSource implements javax.sql.CommonDataSource {
-    method public abstract javax.sql.PooledConnection getPooledConnection() throws java.sql.SQLException;
-    method public abstract javax.sql.PooledConnection getPooledConnection(java.lang.String, java.lang.String) throws java.sql.SQLException;
+  public interface ConnectionPoolDataSource extends javax.sql.CommonDataSource {
+    method public javax.sql.PooledConnection getPooledConnection() throws java.sql.SQLException;
+    method public javax.sql.PooledConnection getPooledConnection(String, String) throws java.sql.SQLException;
   }
 
-  public abstract interface DataSource implements javax.sql.CommonDataSource java.sql.Wrapper {
-    method public abstract java.sql.Connection getConnection() throws java.sql.SQLException;
-    method public abstract java.sql.Connection getConnection(java.lang.String, java.lang.String) throws java.sql.SQLException;
+  public interface DataSource extends javax.sql.CommonDataSource java.sql.Wrapper {
+    method public java.sql.Connection getConnection() throws java.sql.SQLException;
+    method public java.sql.Connection getConnection(String, String) throws java.sql.SQLException;
   }
 
-  public abstract interface PooledConnection {
-    method public abstract void addConnectionEventListener(javax.sql.ConnectionEventListener);
-    method public abstract void addStatementEventListener(javax.sql.StatementEventListener);
-    method public abstract void close() throws java.sql.SQLException;
-    method public abstract java.sql.Connection getConnection() throws java.sql.SQLException;
-    method public abstract void removeConnectionEventListener(javax.sql.ConnectionEventListener);
-    method public abstract void removeStatementEventListener(javax.sql.StatementEventListener);
+  public interface PooledConnection {
+    method public void addConnectionEventListener(javax.sql.ConnectionEventListener);
+    method public void addStatementEventListener(javax.sql.StatementEventListener);
+    method public void close() throws java.sql.SQLException;
+    method public java.sql.Connection getConnection() throws java.sql.SQLException;
+    method public void removeConnectionEventListener(javax.sql.ConnectionEventListener);
+    method public void removeStatementEventListener(javax.sql.StatementEventListener);
   }
 
-  public abstract interface RowSet implements java.sql.ResultSet {
-    method public abstract void addRowSetListener(javax.sql.RowSetListener);
-    method public abstract void clearParameters() throws java.sql.SQLException;
-    method public abstract void execute() throws java.sql.SQLException;
-    method public abstract java.lang.String getCommand();
-    method public abstract java.lang.String getDataSourceName();
-    method public abstract boolean getEscapeProcessing() throws java.sql.SQLException;
-    method public abstract int getMaxFieldSize() throws java.sql.SQLException;
-    method public abstract int getMaxRows() throws java.sql.SQLException;
-    method public abstract java.lang.String getPassword();
-    method public abstract int getQueryTimeout() throws java.sql.SQLException;
-    method public abstract int getTransactionIsolation();
-    method public abstract java.util.Map<java.lang.String, java.lang.Class<?>> getTypeMap() throws java.sql.SQLException;
-    method public abstract java.lang.String getUrl() throws java.sql.SQLException;
-    method public abstract java.lang.String getUsername();
-    method public abstract boolean isReadOnly();
-    method public abstract void removeRowSetListener(javax.sql.RowSetListener);
-    method public abstract void setArray(int, java.sql.Array) throws java.sql.SQLException;
-    method public abstract void setAsciiStream(int, java.io.InputStream, int) throws java.sql.SQLException;
-    method public abstract void setAsciiStream(java.lang.String, java.io.InputStream, int) throws java.sql.SQLException;
-    method public abstract void setAsciiStream(int, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void setAsciiStream(java.lang.String, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void setBigDecimal(int, java.math.BigDecimal) throws java.sql.SQLException;
-    method public abstract void setBigDecimal(java.lang.String, java.math.BigDecimal) throws java.sql.SQLException;
-    method public abstract void setBinaryStream(int, java.io.InputStream, int) throws java.sql.SQLException;
-    method public abstract void setBinaryStream(java.lang.String, java.io.InputStream, int) throws java.sql.SQLException;
-    method public abstract void setBinaryStream(int, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void setBinaryStream(java.lang.String, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void setBlob(int, java.sql.Blob) throws java.sql.SQLException;
-    method public abstract void setBlob(int, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void setBlob(int, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void setBlob(java.lang.String, java.io.InputStream, long) throws java.sql.SQLException;
-    method public abstract void setBlob(java.lang.String, java.sql.Blob) throws java.sql.SQLException;
-    method public abstract void setBlob(java.lang.String, java.io.InputStream) throws java.sql.SQLException;
-    method public abstract void setBoolean(int, boolean) throws java.sql.SQLException;
-    method public abstract void setBoolean(java.lang.String, boolean) throws java.sql.SQLException;
-    method public abstract void setByte(int, byte) throws java.sql.SQLException;
-    method public abstract void setByte(java.lang.String, byte) throws java.sql.SQLException;
-    method public abstract void setBytes(int, byte[]) throws java.sql.SQLException;
-    method public abstract void setBytes(java.lang.String, byte[]) throws java.sql.SQLException;
-    method public abstract void setCharacterStream(int, java.io.Reader, int) throws java.sql.SQLException;
-    method public abstract void setCharacterStream(java.lang.String, java.io.Reader, int) throws java.sql.SQLException;
-    method public abstract void setCharacterStream(int, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setCharacterStream(java.lang.String, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setClob(int, java.sql.Clob) throws java.sql.SQLException;
-    method public abstract void setClob(int, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setClob(int, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setClob(java.lang.String, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setClob(java.lang.String, java.sql.Clob) throws java.sql.SQLException;
-    method public abstract void setClob(java.lang.String, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setCommand(java.lang.String) throws java.sql.SQLException;
-    method public abstract void setConcurrency(int) throws java.sql.SQLException;
-    method public abstract void setDataSourceName(java.lang.String) throws java.sql.SQLException;
-    method public abstract void setDate(int, java.sql.Date) throws java.sql.SQLException;
-    method public abstract void setDate(int, java.sql.Date, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract void setDate(java.lang.String, java.sql.Date) throws java.sql.SQLException;
-    method public abstract void setDate(java.lang.String, java.sql.Date, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract void setDouble(int, double) throws java.sql.SQLException;
-    method public abstract void setDouble(java.lang.String, double) throws java.sql.SQLException;
-    method public abstract void setEscapeProcessing(boolean) throws java.sql.SQLException;
-    method public abstract void setFloat(int, float) throws java.sql.SQLException;
-    method public abstract void setFloat(java.lang.String, float) throws java.sql.SQLException;
-    method public abstract void setInt(int, int) throws java.sql.SQLException;
-    method public abstract void setInt(java.lang.String, int) throws java.sql.SQLException;
-    method public abstract void setLong(int, long) throws java.sql.SQLException;
-    method public abstract void setLong(java.lang.String, long) throws java.sql.SQLException;
-    method public abstract void setMaxFieldSize(int) throws java.sql.SQLException;
-    method public abstract void setMaxRows(int) throws java.sql.SQLException;
-    method public abstract void setNCharacterStream(int, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setNCharacterStream(int, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setNCharacterStream(java.lang.String, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setNCharacterStream(java.lang.String, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setNClob(java.lang.String, java.sql.NClob) throws java.sql.SQLException;
-    method public abstract void setNClob(java.lang.String, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setNClob(java.lang.String, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setNClob(int, java.io.Reader, long) throws java.sql.SQLException;
-    method public abstract void setNClob(int, java.sql.NClob) throws java.sql.SQLException;
-    method public abstract void setNClob(int, java.io.Reader) throws java.sql.SQLException;
-    method public abstract void setNString(int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setNString(java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setNull(int, int) throws java.sql.SQLException;
-    method public abstract void setNull(java.lang.String, int) throws java.sql.SQLException;
-    method public abstract void setNull(int, int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setNull(java.lang.String, int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setObject(int, java.lang.Object, int, int) throws java.sql.SQLException;
-    method public abstract void setObject(java.lang.String, java.lang.Object, int, int) throws java.sql.SQLException;
-    method public abstract void setObject(int, java.lang.Object, int) throws java.sql.SQLException;
-    method public abstract void setObject(java.lang.String, java.lang.Object, int) throws java.sql.SQLException;
-    method public abstract void setObject(java.lang.String, java.lang.Object) throws java.sql.SQLException;
-    method public abstract void setObject(int, java.lang.Object) throws java.sql.SQLException;
-    method public abstract void setPassword(java.lang.String) throws java.sql.SQLException;
-    method public abstract void setQueryTimeout(int) throws java.sql.SQLException;
-    method public abstract void setReadOnly(boolean) throws java.sql.SQLException;
-    method public abstract void setRef(int, java.sql.Ref) throws java.sql.SQLException;
-    method public abstract void setRowId(int, java.sql.RowId) throws java.sql.SQLException;
-    method public abstract void setRowId(java.lang.String, java.sql.RowId) throws java.sql.SQLException;
-    method public abstract void setSQLXML(int, java.sql.SQLXML) throws java.sql.SQLException;
-    method public abstract void setSQLXML(java.lang.String, java.sql.SQLXML) throws java.sql.SQLException;
-    method public abstract void setShort(int, short) throws java.sql.SQLException;
-    method public abstract void setShort(java.lang.String, short) throws java.sql.SQLException;
-    method public abstract void setString(int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setString(java.lang.String, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setTime(int, java.sql.Time) throws java.sql.SQLException;
-    method public abstract void setTime(int, java.sql.Time, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract void setTime(java.lang.String, java.sql.Time) throws java.sql.SQLException;
-    method public abstract void setTime(java.lang.String, java.sql.Time, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract void setTimestamp(int, java.sql.Timestamp) throws java.sql.SQLException;
-    method public abstract void setTimestamp(java.lang.String, java.sql.Timestamp) throws java.sql.SQLException;
-    method public abstract void setTimestamp(int, java.sql.Timestamp, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract void setTimestamp(java.lang.String, java.sql.Timestamp, java.util.Calendar) throws java.sql.SQLException;
-    method public abstract void setTransactionIsolation(int) throws java.sql.SQLException;
-    method public abstract void setType(int) throws java.sql.SQLException;
-    method public abstract void setTypeMap(java.util.Map<java.lang.String, java.lang.Class<?>>) throws java.sql.SQLException;
-    method public abstract void setURL(int, java.net.URL) throws java.sql.SQLException;
-    method public abstract void setUrl(java.lang.String) throws java.sql.SQLException;
-    method public abstract void setUsername(java.lang.String) throws java.sql.SQLException;
+  public interface RowSet extends java.sql.ResultSet {
+    method public void addRowSetListener(javax.sql.RowSetListener);
+    method public void clearParameters() throws java.sql.SQLException;
+    method public void execute() throws java.sql.SQLException;
+    method public String getCommand();
+    method public String getDataSourceName();
+    method public boolean getEscapeProcessing() throws java.sql.SQLException;
+    method public int getMaxFieldSize() throws java.sql.SQLException;
+    method public int getMaxRows() throws java.sql.SQLException;
+    method public String getPassword();
+    method public int getQueryTimeout() throws java.sql.SQLException;
+    method public int getTransactionIsolation();
+    method public java.util.Map<java.lang.String,java.lang.Class<?>> getTypeMap() throws java.sql.SQLException;
+    method public String getUrl() throws java.sql.SQLException;
+    method public String getUsername();
+    method public boolean isReadOnly();
+    method public void removeRowSetListener(javax.sql.RowSetListener);
+    method public void setArray(int, java.sql.Array) throws java.sql.SQLException;
+    method public void setAsciiStream(int, java.io.InputStream, int) throws java.sql.SQLException;
+    method public void setAsciiStream(String, java.io.InputStream, int) throws java.sql.SQLException;
+    method public void setAsciiStream(int, java.io.InputStream) throws java.sql.SQLException;
+    method public void setAsciiStream(String, java.io.InputStream) throws java.sql.SQLException;
+    method public void setBigDecimal(int, java.math.BigDecimal) throws java.sql.SQLException;
+    method public void setBigDecimal(String, java.math.BigDecimal) throws java.sql.SQLException;
+    method public void setBinaryStream(int, java.io.InputStream, int) throws java.sql.SQLException;
+    method public void setBinaryStream(String, java.io.InputStream, int) throws java.sql.SQLException;
+    method public void setBinaryStream(int, java.io.InputStream) throws java.sql.SQLException;
+    method public void setBinaryStream(String, java.io.InputStream) throws java.sql.SQLException;
+    method public void setBlob(int, java.sql.Blob) throws java.sql.SQLException;
+    method public void setBlob(int, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void setBlob(int, java.io.InputStream) throws java.sql.SQLException;
+    method public void setBlob(String, java.io.InputStream, long) throws java.sql.SQLException;
+    method public void setBlob(String, java.sql.Blob) throws java.sql.SQLException;
+    method public void setBlob(String, java.io.InputStream) throws java.sql.SQLException;
+    method public void setBoolean(int, boolean) throws java.sql.SQLException;
+    method public void setBoolean(String, boolean) throws java.sql.SQLException;
+    method public void setByte(int, byte) throws java.sql.SQLException;
+    method public void setByte(String, byte) throws java.sql.SQLException;
+    method public void setBytes(int, byte[]) throws java.sql.SQLException;
+    method public void setBytes(String, byte[]) throws java.sql.SQLException;
+    method public void setCharacterStream(int, java.io.Reader, int) throws java.sql.SQLException;
+    method public void setCharacterStream(String, java.io.Reader, int) throws java.sql.SQLException;
+    method public void setCharacterStream(int, java.io.Reader) throws java.sql.SQLException;
+    method public void setCharacterStream(String, java.io.Reader) throws java.sql.SQLException;
+    method public void setClob(int, java.sql.Clob) throws java.sql.SQLException;
+    method public void setClob(int, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setClob(int, java.io.Reader) throws java.sql.SQLException;
+    method public void setClob(String, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setClob(String, java.sql.Clob) throws java.sql.SQLException;
+    method public void setClob(String, java.io.Reader) throws java.sql.SQLException;
+    method public void setCommand(String) throws java.sql.SQLException;
+    method public void setConcurrency(int) throws java.sql.SQLException;
+    method public void setDataSourceName(String) throws java.sql.SQLException;
+    method public void setDate(int, java.sql.Date) throws java.sql.SQLException;
+    method public void setDate(int, java.sql.Date, java.util.Calendar) throws java.sql.SQLException;
+    method public void setDate(String, java.sql.Date) throws java.sql.SQLException;
+    method public void setDate(String, java.sql.Date, java.util.Calendar) throws java.sql.SQLException;
+    method public void setDouble(int, double) throws java.sql.SQLException;
+    method public void setDouble(String, double) throws java.sql.SQLException;
+    method public void setEscapeProcessing(boolean) throws java.sql.SQLException;
+    method public void setFloat(int, float) throws java.sql.SQLException;
+    method public void setFloat(String, float) throws java.sql.SQLException;
+    method public void setInt(int, int) throws java.sql.SQLException;
+    method public void setInt(String, int) throws java.sql.SQLException;
+    method public void setLong(int, long) throws java.sql.SQLException;
+    method public void setLong(String, long) throws java.sql.SQLException;
+    method public void setMaxFieldSize(int) throws java.sql.SQLException;
+    method public void setMaxRows(int) throws java.sql.SQLException;
+    method public void setNCharacterStream(int, java.io.Reader) throws java.sql.SQLException;
+    method public void setNCharacterStream(int, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setNCharacterStream(String, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setNCharacterStream(String, java.io.Reader) throws java.sql.SQLException;
+    method public void setNClob(String, java.sql.NClob) throws java.sql.SQLException;
+    method public void setNClob(String, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setNClob(String, java.io.Reader) throws java.sql.SQLException;
+    method public void setNClob(int, java.io.Reader, long) throws java.sql.SQLException;
+    method public void setNClob(int, java.sql.NClob) throws java.sql.SQLException;
+    method public void setNClob(int, java.io.Reader) throws java.sql.SQLException;
+    method public void setNString(int, String) throws java.sql.SQLException;
+    method public void setNString(String, String) throws java.sql.SQLException;
+    method public void setNull(int, int) throws java.sql.SQLException;
+    method public void setNull(String, int) throws java.sql.SQLException;
+    method public void setNull(int, int, String) throws java.sql.SQLException;
+    method public void setNull(String, int, String) throws java.sql.SQLException;
+    method public void setObject(int, Object, int, int) throws java.sql.SQLException;
+    method public void setObject(String, Object, int, int) throws java.sql.SQLException;
+    method public void setObject(int, Object, int) throws java.sql.SQLException;
+    method public void setObject(String, Object, int) throws java.sql.SQLException;
+    method public void setObject(String, Object) throws java.sql.SQLException;
+    method public void setObject(int, Object) throws java.sql.SQLException;
+    method public void setPassword(String) throws java.sql.SQLException;
+    method public void setQueryTimeout(int) throws java.sql.SQLException;
+    method public void setReadOnly(boolean) throws java.sql.SQLException;
+    method public void setRef(int, java.sql.Ref) throws java.sql.SQLException;
+    method public void setRowId(int, java.sql.RowId) throws java.sql.SQLException;
+    method public void setRowId(String, java.sql.RowId) throws java.sql.SQLException;
+    method public void setSQLXML(int, java.sql.SQLXML) throws java.sql.SQLException;
+    method public void setSQLXML(String, java.sql.SQLXML) throws java.sql.SQLException;
+    method public void setShort(int, short) throws java.sql.SQLException;
+    method public void setShort(String, short) throws java.sql.SQLException;
+    method public void setString(int, String) throws java.sql.SQLException;
+    method public void setString(String, String) throws java.sql.SQLException;
+    method public void setTime(int, java.sql.Time) throws java.sql.SQLException;
+    method public void setTime(int, java.sql.Time, java.util.Calendar) throws java.sql.SQLException;
+    method public void setTime(String, java.sql.Time) throws java.sql.SQLException;
+    method public void setTime(String, java.sql.Time, java.util.Calendar) throws java.sql.SQLException;
+    method public void setTimestamp(int, java.sql.Timestamp) throws java.sql.SQLException;
+    method public void setTimestamp(String, java.sql.Timestamp) throws java.sql.SQLException;
+    method public void setTimestamp(int, java.sql.Timestamp, java.util.Calendar) throws java.sql.SQLException;
+    method public void setTimestamp(String, java.sql.Timestamp, java.util.Calendar) throws java.sql.SQLException;
+    method public void setTransactionIsolation(int) throws java.sql.SQLException;
+    method public void setType(int) throws java.sql.SQLException;
+    method public void setTypeMap(java.util.Map<java.lang.String,java.lang.Class<?>>) throws java.sql.SQLException;
+    method public void setURL(int, java.net.URL) throws java.sql.SQLException;
+    method public void setUrl(String) throws java.sql.SQLException;
+    method public void setUsername(String) throws java.sql.SQLException;
   }
 
   public class RowSetEvent extends java.util.EventObject {
     ctor public RowSetEvent(javax.sql.RowSet);
   }
 
-  public abstract interface RowSetInternal {
-    method public abstract java.sql.Connection getConnection() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getOriginal() throws java.sql.SQLException;
-    method public abstract java.sql.ResultSet getOriginalRow() throws java.sql.SQLException;
-    method public abstract java.lang.Object[] getParams() throws java.sql.SQLException;
-    method public abstract void setMetaData(javax.sql.RowSetMetaData) throws java.sql.SQLException;
+  public interface RowSetInternal {
+    method public java.sql.Connection getConnection() throws java.sql.SQLException;
+    method public java.sql.ResultSet getOriginal() throws java.sql.SQLException;
+    method public java.sql.ResultSet getOriginalRow() throws java.sql.SQLException;
+    method public Object[] getParams() throws java.sql.SQLException;
+    method public void setMetaData(javax.sql.RowSetMetaData) throws java.sql.SQLException;
   }
 
-  public abstract interface RowSetListener implements java.util.EventListener {
-    method public abstract void cursorMoved(javax.sql.RowSetEvent);
-    method public abstract void rowChanged(javax.sql.RowSetEvent);
-    method public abstract void rowSetChanged(javax.sql.RowSetEvent);
+  public interface RowSetListener extends java.util.EventListener {
+    method public void cursorMoved(javax.sql.RowSetEvent);
+    method public void rowChanged(javax.sql.RowSetEvent);
+    method public void rowSetChanged(javax.sql.RowSetEvent);
   }
 
-  public abstract interface RowSetMetaData implements java.sql.ResultSetMetaData {
-    method public abstract void setAutoIncrement(int, boolean) throws java.sql.SQLException;
-    method public abstract void setCaseSensitive(int, boolean) throws java.sql.SQLException;
-    method public abstract void setCatalogName(int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setColumnCount(int) throws java.sql.SQLException;
-    method public abstract void setColumnDisplaySize(int, int) throws java.sql.SQLException;
-    method public abstract void setColumnLabel(int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setColumnName(int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setColumnType(int, int) throws java.sql.SQLException;
-    method public abstract void setColumnTypeName(int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setCurrency(int, boolean) throws java.sql.SQLException;
-    method public abstract void setNullable(int, int) throws java.sql.SQLException;
-    method public abstract void setPrecision(int, int) throws java.sql.SQLException;
-    method public abstract void setScale(int, int) throws java.sql.SQLException;
-    method public abstract void setSchemaName(int, java.lang.String) throws java.sql.SQLException;
-    method public abstract void setSearchable(int, boolean) throws java.sql.SQLException;
-    method public abstract void setSigned(int, boolean) throws java.sql.SQLException;
-    method public abstract void setTableName(int, java.lang.String) throws java.sql.SQLException;
+  public interface RowSetMetaData extends java.sql.ResultSetMetaData {
+    method public void setAutoIncrement(int, boolean) throws java.sql.SQLException;
+    method public void setCaseSensitive(int, boolean) throws java.sql.SQLException;
+    method public void setCatalogName(int, String) throws java.sql.SQLException;
+    method public void setColumnCount(int) throws java.sql.SQLException;
+    method public void setColumnDisplaySize(int, int) throws java.sql.SQLException;
+    method public void setColumnLabel(int, String) throws java.sql.SQLException;
+    method public void setColumnName(int, String) throws java.sql.SQLException;
+    method public void setColumnType(int, int) throws java.sql.SQLException;
+    method public void setColumnTypeName(int, String) throws java.sql.SQLException;
+    method public void setCurrency(int, boolean) throws java.sql.SQLException;
+    method public void setNullable(int, int) throws java.sql.SQLException;
+    method public void setPrecision(int, int) throws java.sql.SQLException;
+    method public void setScale(int, int) throws java.sql.SQLException;
+    method public void setSchemaName(int, String) throws java.sql.SQLException;
+    method public void setSearchable(int, boolean) throws java.sql.SQLException;
+    method public void setSigned(int, boolean) throws java.sql.SQLException;
+    method public void setTableName(int, String) throws java.sql.SQLException;
   }
 
-  public abstract interface RowSetReader {
-    method public abstract void readData(javax.sql.RowSetInternal) throws java.sql.SQLException;
+  public interface RowSetReader {
+    method public void readData(javax.sql.RowSetInternal) throws java.sql.SQLException;
   }
 
-  public abstract interface RowSetWriter {
-    method public abstract boolean writeData(javax.sql.RowSetInternal) throws java.sql.SQLException;
+  public interface RowSetWriter {
+    method public boolean writeData(javax.sql.RowSetInternal) throws java.sql.SQLException;
   }
 
   public class StatementEvent extends java.util.EventObject {
@@ -75631,9 +75919,9 @@
     method public java.sql.PreparedStatement getStatement();
   }
 
-  public abstract interface StatementEventListener implements java.util.EventListener {
-    method public abstract void statementClosed(javax.sql.StatementEvent);
-    method public abstract void statementErrorOccurred(javax.sql.StatementEvent);
+  public interface StatementEventListener extends java.util.EventListener {
+    method public void statementClosed(javax.sql.StatementEvent);
+    method public void statementErrorOccurred(javax.sql.StatementEvent);
   }
 
 }
@@ -75641,18 +75929,18 @@
 package javax.xml {
 
   public final class XMLConstants {
-    field public static final java.lang.String DEFAULT_NS_PREFIX = "";
-    field public static final java.lang.String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing";
-    field public static final java.lang.String NULL_NS_URI = "";
-    field public static final java.lang.String RELAXNG_NS_URI = "http://relaxng.org/ns/structure/1.0";
-    field public static final java.lang.String W3C_XML_SCHEMA_INSTANCE_NS_URI = "http://www.w3.org/2001/XMLSchema-instance";
-    field public static final java.lang.String W3C_XML_SCHEMA_NS_URI = "http://www.w3.org/2001/XMLSchema";
-    field public static final java.lang.String W3C_XPATH_DATATYPE_NS_URI = "http://www.w3.org/2003/11/xpath-datatypes";
-    field public static final java.lang.String XMLNS_ATTRIBUTE = "xmlns";
-    field public static final java.lang.String XMLNS_ATTRIBUTE_NS_URI = "http://www.w3.org/2000/xmlns/";
-    field public static final java.lang.String XML_DTD_NS_URI = "http://www.w3.org/TR/REC-xml";
-    field public static final java.lang.String XML_NS_PREFIX = "xml";
-    field public static final java.lang.String XML_NS_URI = "http://www.w3.org/XML/1998/namespace";
+    field public static final String DEFAULT_NS_PREFIX = "";
+    field public static final String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing";
+    field public static final String NULL_NS_URI = "";
+    field public static final String RELAXNG_NS_URI = "http://relaxng.org/ns/structure/1.0";
+    field public static final String W3C_XML_SCHEMA_INSTANCE_NS_URI = "http://www.w3.org/2001/XMLSchema-instance";
+    field public static final String W3C_XML_SCHEMA_NS_URI = "http://www.w3.org/2001/XMLSchema";
+    field public static final String W3C_XPATH_DATATYPE_NS_URI = "http://www.w3.org/2003/11/xpath-datatypes";
+    field public static final String XMLNS_ATTRIBUTE = "xmlns";
+    field public static final String XMLNS_ATTRIBUTE_NS_URI = "http://www.w3.org/2000/xmlns/";
+    field public static final String XML_DTD_NS_URI = "http://www.w3.org/TR/REC-xml";
+    field public static final String XML_NS_PREFIX = "xml";
+    field public static final String XML_NS_URI = "http://www.w3.org/XML/1998/namespace";
   }
 
 }
@@ -75661,9 +75949,9 @@
 
   public class DatatypeConfigurationException extends java.lang.Exception {
     ctor public DatatypeConfigurationException();
-    ctor public DatatypeConfigurationException(java.lang.String);
-    ctor public DatatypeConfigurationException(java.lang.String, java.lang.Throwable);
-    ctor public DatatypeConfigurationException(java.lang.Throwable);
+    ctor public DatatypeConfigurationException(String);
+    ctor public DatatypeConfigurationException(String, Throwable);
+    ctor public DatatypeConfigurationException(Throwable);
   }
 
   public final class DatatypeConstants {
@@ -75711,22 +75999,22 @@
 
   public abstract class DatatypeFactory {
     ctor protected DatatypeFactory();
-    method public abstract javax.xml.datatype.Duration newDuration(java.lang.String);
+    method public abstract javax.xml.datatype.Duration newDuration(String);
     method public abstract javax.xml.datatype.Duration newDuration(long);
     method public abstract javax.xml.datatype.Duration newDuration(boolean, java.math.BigInteger, java.math.BigInteger, java.math.BigInteger, java.math.BigInteger, java.math.BigInteger, java.math.BigDecimal);
     method public javax.xml.datatype.Duration newDuration(boolean, int, int, int, int, int, int);
-    method public javax.xml.datatype.Duration newDurationDayTime(java.lang.String);
+    method public javax.xml.datatype.Duration newDurationDayTime(String);
     method public javax.xml.datatype.Duration newDurationDayTime(long);
     method public javax.xml.datatype.Duration newDurationDayTime(boolean, java.math.BigInteger, java.math.BigInteger, java.math.BigInteger, java.math.BigInteger);
     method public javax.xml.datatype.Duration newDurationDayTime(boolean, int, int, int, int);
-    method public javax.xml.datatype.Duration newDurationYearMonth(java.lang.String);
+    method public javax.xml.datatype.Duration newDurationYearMonth(String);
     method public javax.xml.datatype.Duration newDurationYearMonth(long);
     method public javax.xml.datatype.Duration newDurationYearMonth(boolean, java.math.BigInteger, java.math.BigInteger);
     method public javax.xml.datatype.Duration newDurationYearMonth(boolean, int, int);
     method public static javax.xml.datatype.DatatypeFactory newInstance() throws javax.xml.datatype.DatatypeConfigurationException;
-    method public static javax.xml.datatype.DatatypeFactory newInstance(java.lang.String, java.lang.ClassLoader) throws javax.xml.datatype.DatatypeConfigurationException;
+    method public static javax.xml.datatype.DatatypeFactory newInstance(String, ClassLoader) throws javax.xml.datatype.DatatypeConfigurationException;
     method public abstract javax.xml.datatype.XMLGregorianCalendar newXMLGregorianCalendar();
-    method public abstract javax.xml.datatype.XMLGregorianCalendar newXMLGregorianCalendar(java.lang.String);
+    method public abstract javax.xml.datatype.XMLGregorianCalendar newXMLGregorianCalendar(String);
     method public abstract javax.xml.datatype.XMLGregorianCalendar newXMLGregorianCalendar(java.util.GregorianCalendar);
     method public abstract javax.xml.datatype.XMLGregorianCalendar newXMLGregorianCalendar(java.math.BigInteger, int, int, int, int, int, java.math.BigDecimal, int);
     method public javax.xml.datatype.XMLGregorianCalendar newXMLGregorianCalendar(int, int, int, int, int, int, int, int);
@@ -75734,8 +76022,8 @@
     method public javax.xml.datatype.XMLGregorianCalendar newXMLGregorianCalendarTime(int, int, int, int);
     method public javax.xml.datatype.XMLGregorianCalendar newXMLGregorianCalendarTime(int, int, int, java.math.BigDecimal, int);
     method public javax.xml.datatype.XMLGregorianCalendar newXMLGregorianCalendarTime(int, int, int, int, int);
-    field public static final java.lang.String DATATYPEFACTORY_IMPLEMENTATION_CLASS;
-    field public static final java.lang.String DATATYPEFACTORY_PROPERTY = "javax.xml.datatype.DatatypeFactory";
+    field public static final String DATATYPEFACTORY_IMPLEMENTATION_CLASS;
+    field public static final String DATATYPEFACTORY_PROPERTY = "javax.xml.datatype.DatatypeFactory";
   }
 
   public abstract class Duration {
@@ -75745,7 +76033,7 @@
     method public void addTo(java.util.Date);
     method public abstract int compare(javax.xml.datatype.Duration);
     method public int getDays();
-    method public abstract java.lang.Number getField(javax.xml.datatype.DatatypeConstants.Field);
+    method public abstract Number getField(javax.xml.datatype.DatatypeConstants.Field);
     method public int getHours();
     method public int getMinutes();
     method public int getMonths();
@@ -75770,7 +76058,7 @@
     ctor public XMLGregorianCalendar();
     method public abstract void add(javax.xml.datatype.Duration);
     method public abstract void clear();
-    method public abstract java.lang.Object clone();
+    method public abstract Object clone();
     method public abstract int compare(javax.xml.datatype.XMLGregorianCalendar);
     method public abstract int getDay();
     method public abstract java.math.BigInteger getEon();
@@ -75803,29 +76091,29 @@
     method public abstract void setYear(int);
     method public abstract java.util.GregorianCalendar toGregorianCalendar();
     method public abstract java.util.GregorianCalendar toGregorianCalendar(java.util.TimeZone, java.util.Locale, javax.xml.datatype.XMLGregorianCalendar);
-    method public abstract java.lang.String toXMLFormat();
+    method public abstract String toXMLFormat();
   }
 
 }
 
 package javax.xml.namespace {
 
-  public abstract interface NamespaceContext {
-    method public abstract java.lang.String getNamespaceURI(java.lang.String);
-    method public abstract java.lang.String getPrefix(java.lang.String);
-    method public abstract java.util.Iterator getPrefixes(java.lang.String);
+  public interface NamespaceContext {
+    method public String getNamespaceURI(String);
+    method public String getPrefix(String);
+    method public java.util.Iterator getPrefixes(String);
   }
 
   public class QName implements java.io.Serializable {
-    ctor public QName(java.lang.String, java.lang.String);
-    ctor public QName(java.lang.String, java.lang.String, java.lang.String);
-    ctor public QName(java.lang.String);
-    method public final boolean equals(java.lang.Object);
-    method public java.lang.String getLocalPart();
-    method public java.lang.String getNamespaceURI();
-    method public java.lang.String getPrefix();
+    ctor public QName(String, String);
+    ctor public QName(String, String, String);
+    ctor public QName(String);
+    method public final boolean equals(Object);
+    method public String getLocalPart();
+    method public String getNamespaceURI();
+    method public String getPrefix();
     method public final int hashCode();
-    method public static javax.xml.namespace.QName valueOf(java.lang.String);
+    method public static javax.xml.namespace.QName valueOf(String);
   }
 
 }
@@ -75841,8 +76129,8 @@
     method public boolean isXIncludeAware();
     method public abstract org.w3c.dom.Document newDocument();
     method public org.w3c.dom.Document parse(java.io.InputStream) throws java.io.IOException, org.xml.sax.SAXException;
-    method public org.w3c.dom.Document parse(java.io.InputStream, java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
-    method public org.w3c.dom.Document parse(java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public org.w3c.dom.Document parse(java.io.InputStream, String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public org.w3c.dom.Document parse(String) throws java.io.IOException, org.xml.sax.SAXException;
     method public org.w3c.dom.Document parse(java.io.File) throws java.io.IOException, org.xml.sax.SAXException;
     method public abstract org.w3c.dom.Document parse(org.xml.sax.InputSource) throws java.io.IOException, org.xml.sax.SAXException;
     method public void reset();
@@ -75852,8 +76140,8 @@
 
   public abstract class DocumentBuilderFactory {
     ctor protected DocumentBuilderFactory();
-    method public abstract java.lang.Object getAttribute(java.lang.String) throws java.lang.IllegalArgumentException;
-    method public abstract boolean getFeature(java.lang.String) throws javax.xml.parsers.ParserConfigurationException;
+    method public abstract Object getAttribute(String) throws java.lang.IllegalArgumentException;
+    method public abstract boolean getFeature(String) throws javax.xml.parsers.ParserConfigurationException;
     method public javax.xml.validation.Schema getSchema();
     method public boolean isCoalescing();
     method public boolean isExpandEntityReferences();
@@ -75864,11 +76152,11 @@
     method public boolean isXIncludeAware();
     method public abstract javax.xml.parsers.DocumentBuilder newDocumentBuilder() throws javax.xml.parsers.ParserConfigurationException;
     method public static javax.xml.parsers.DocumentBuilderFactory newInstance();
-    method public static javax.xml.parsers.DocumentBuilderFactory newInstance(java.lang.String, java.lang.ClassLoader);
-    method public abstract void setAttribute(java.lang.String, java.lang.Object) throws java.lang.IllegalArgumentException;
+    method public static javax.xml.parsers.DocumentBuilderFactory newInstance(String, ClassLoader);
+    method public abstract void setAttribute(String, Object) throws java.lang.IllegalArgumentException;
     method public void setCoalescing(boolean);
     method public void setExpandEntityReferences(boolean);
-    method public abstract void setFeature(java.lang.String, boolean) throws javax.xml.parsers.ParserConfigurationException;
+    method public abstract void setFeature(String, boolean) throws javax.xml.parsers.ParserConfigurationException;
     method public void setIgnoringComments(boolean);
     method public void setIgnoringElementContentWhitespace(boolean);
     method public void setNamespaceAware(boolean);
@@ -75879,51 +76167,51 @@
 
   public class FactoryConfigurationError extends java.lang.Error {
     ctor public FactoryConfigurationError();
-    ctor public FactoryConfigurationError(java.lang.String);
-    ctor public FactoryConfigurationError(java.lang.Exception);
-    ctor public FactoryConfigurationError(java.lang.Exception, java.lang.String);
-    method public java.lang.Exception getException();
+    ctor public FactoryConfigurationError(String);
+    ctor public FactoryConfigurationError(Exception);
+    ctor public FactoryConfigurationError(Exception, String);
+    method public Exception getException();
   }
 
   public class ParserConfigurationException extends java.lang.Exception {
     ctor public ParserConfigurationException();
-    ctor public ParserConfigurationException(java.lang.String);
+    ctor public ParserConfigurationException(String);
   }
 
   public abstract class SAXParser {
     ctor protected SAXParser();
     method public abstract org.xml.sax.Parser getParser() throws org.xml.sax.SAXException;
-    method public abstract java.lang.Object getProperty(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public abstract Object getProperty(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public javax.xml.validation.Schema getSchema();
     method public abstract org.xml.sax.XMLReader getXMLReader() throws org.xml.sax.SAXException;
     method public abstract boolean isNamespaceAware();
     method public abstract boolean isValidating();
     method public boolean isXIncludeAware();
     method public void parse(java.io.InputStream, org.xml.sax.HandlerBase) throws java.io.IOException, org.xml.sax.SAXException;
-    method public void parse(java.io.InputStream, org.xml.sax.HandlerBase, java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void parse(java.io.InputStream, org.xml.sax.HandlerBase, String) throws java.io.IOException, org.xml.sax.SAXException;
     method public void parse(java.io.InputStream, org.xml.sax.helpers.DefaultHandler) throws java.io.IOException, org.xml.sax.SAXException;
-    method public void parse(java.io.InputStream, org.xml.sax.helpers.DefaultHandler, java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
-    method public void parse(java.lang.String, org.xml.sax.HandlerBase) throws java.io.IOException, org.xml.sax.SAXException;
-    method public void parse(java.lang.String, org.xml.sax.helpers.DefaultHandler) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void parse(java.io.InputStream, org.xml.sax.helpers.DefaultHandler, String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void parse(String, org.xml.sax.HandlerBase) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void parse(String, org.xml.sax.helpers.DefaultHandler) throws java.io.IOException, org.xml.sax.SAXException;
     method public void parse(java.io.File, org.xml.sax.HandlerBase) throws java.io.IOException, org.xml.sax.SAXException;
     method public void parse(java.io.File, org.xml.sax.helpers.DefaultHandler) throws java.io.IOException, org.xml.sax.SAXException;
     method public void parse(org.xml.sax.InputSource, org.xml.sax.HandlerBase) throws java.io.IOException, org.xml.sax.SAXException;
     method public void parse(org.xml.sax.InputSource, org.xml.sax.helpers.DefaultHandler) throws java.io.IOException, org.xml.sax.SAXException;
     method public void reset();
-    method public abstract void setProperty(java.lang.String, java.lang.Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public abstract void setProperty(String, Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
   }
 
   public abstract class SAXParserFactory {
     ctor protected SAXParserFactory();
-    method public abstract boolean getFeature(java.lang.String) throws javax.xml.parsers.ParserConfigurationException, org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public abstract boolean getFeature(String) throws javax.xml.parsers.ParserConfigurationException, org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public javax.xml.validation.Schema getSchema();
     method public boolean isNamespaceAware();
     method public boolean isValidating();
     method public boolean isXIncludeAware();
     method public static javax.xml.parsers.SAXParserFactory newInstance();
-    method public static javax.xml.parsers.SAXParserFactory newInstance(java.lang.String, java.lang.ClassLoader);
+    method public static javax.xml.parsers.SAXParserFactory newInstance(String, ClassLoader);
     method public abstract javax.xml.parsers.SAXParser newSAXParser() throws javax.xml.parsers.ParserConfigurationException, org.xml.sax.SAXException;
-    method public abstract void setFeature(java.lang.String, boolean) throws javax.xml.parsers.ParserConfigurationException, org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public abstract void setFeature(String, boolean) throws javax.xml.parsers.ParserConfigurationException, org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public void setNamespaceAware(boolean);
     method public void setSchema(javax.xml.validation.Schema);
     method public void setValidating(boolean);
@@ -75934,47 +76222,47 @@
 
 package javax.xml.transform {
 
-  public abstract interface ErrorListener {
-    method public abstract void error(javax.xml.transform.TransformerException) throws javax.xml.transform.TransformerException;
-    method public abstract void fatalError(javax.xml.transform.TransformerException) throws javax.xml.transform.TransformerException;
-    method public abstract void warning(javax.xml.transform.TransformerException) throws javax.xml.transform.TransformerException;
+  public interface ErrorListener {
+    method public void error(javax.xml.transform.TransformerException) throws javax.xml.transform.TransformerException;
+    method public void fatalError(javax.xml.transform.TransformerException) throws javax.xml.transform.TransformerException;
+    method public void warning(javax.xml.transform.TransformerException) throws javax.xml.transform.TransformerException;
   }
 
   public class OutputKeys {
-    field public static final java.lang.String CDATA_SECTION_ELEMENTS = "cdata-section-elements";
-    field public static final java.lang.String DOCTYPE_PUBLIC = "doctype-public";
-    field public static final java.lang.String DOCTYPE_SYSTEM = "doctype-system";
-    field public static final java.lang.String ENCODING = "encoding";
-    field public static final java.lang.String INDENT = "indent";
-    field public static final java.lang.String MEDIA_TYPE = "media-type";
-    field public static final java.lang.String METHOD = "method";
-    field public static final java.lang.String OMIT_XML_DECLARATION = "omit-xml-declaration";
-    field public static final java.lang.String STANDALONE = "standalone";
-    field public static final java.lang.String VERSION = "version";
+    field public static final String CDATA_SECTION_ELEMENTS = "cdata-section-elements";
+    field public static final String DOCTYPE_PUBLIC = "doctype-public";
+    field public static final String DOCTYPE_SYSTEM = "doctype-system";
+    field public static final String ENCODING = "encoding";
+    field public static final String INDENT = "indent";
+    field public static final String MEDIA_TYPE = "media-type";
+    field public static final String METHOD = "method";
+    field public static final String OMIT_XML_DECLARATION = "omit-xml-declaration";
+    field public static final String STANDALONE = "standalone";
+    field public static final String VERSION = "version";
   }
 
-  public abstract interface Result {
-    method public abstract java.lang.String getSystemId();
-    method public abstract void setSystemId(java.lang.String);
-    field public static final java.lang.String PI_DISABLE_OUTPUT_ESCAPING = "javax.xml.transform.disable-output-escaping";
-    field public static final java.lang.String PI_ENABLE_OUTPUT_ESCAPING = "javax.xml.transform.enable-output-escaping";
+  public interface Result {
+    method public String getSystemId();
+    method public void setSystemId(String);
+    field public static final String PI_DISABLE_OUTPUT_ESCAPING = "javax.xml.transform.disable-output-escaping";
+    field public static final String PI_ENABLE_OUTPUT_ESCAPING = "javax.xml.transform.enable-output-escaping";
   }
 
-  public abstract interface Source {
-    method public abstract java.lang.String getSystemId();
-    method public abstract void setSystemId(java.lang.String);
+  public interface Source {
+    method public String getSystemId();
+    method public void setSystemId(String);
   }
 
-  public abstract interface SourceLocator {
-    method public abstract int getColumnNumber();
-    method public abstract int getLineNumber();
-    method public abstract java.lang.String getPublicId();
-    method public abstract java.lang.String getSystemId();
+  public interface SourceLocator {
+    method public int getColumnNumber();
+    method public int getLineNumber();
+    method public String getPublicId();
+    method public String getSystemId();
   }
 
-  public abstract interface Templates {
-    method public abstract java.util.Properties getOutputProperties();
-    method public abstract javax.xml.transform.Transformer newTransformer() throws javax.xml.transform.TransformerConfigurationException;
+  public interface Templates {
+    method public java.util.Properties getOutputProperties();
+    method public javax.xml.transform.Transformer newTransformer() throws javax.xml.transform.TransformerConfigurationException;
   }
 
   public abstract class Transformer {
@@ -75982,103 +76270,102 @@
     method public abstract void clearParameters();
     method public abstract javax.xml.transform.ErrorListener getErrorListener();
     method public abstract java.util.Properties getOutputProperties();
-    method public abstract java.lang.String getOutputProperty(java.lang.String) throws java.lang.IllegalArgumentException;
-    method public abstract java.lang.Object getParameter(java.lang.String);
+    method public abstract String getOutputProperty(String) throws java.lang.IllegalArgumentException;
+    method public abstract Object getParameter(String);
     method public abstract javax.xml.transform.URIResolver getURIResolver();
     method public void reset();
     method public abstract void setErrorListener(javax.xml.transform.ErrorListener) throws java.lang.IllegalArgumentException;
     method public abstract void setOutputProperties(java.util.Properties);
-    method public abstract void setOutputProperty(java.lang.String, java.lang.String) throws java.lang.IllegalArgumentException;
-    method public abstract void setParameter(java.lang.String, java.lang.Object);
+    method public abstract void setOutputProperty(String, String) throws java.lang.IllegalArgumentException;
+    method public abstract void setParameter(String, Object);
     method public abstract void setURIResolver(javax.xml.transform.URIResolver);
     method public abstract void transform(javax.xml.transform.Source, javax.xml.transform.Result) throws javax.xml.transform.TransformerException;
   }
 
   public class TransformerConfigurationException extends javax.xml.transform.TransformerException {
     ctor public TransformerConfigurationException();
-    ctor public TransformerConfigurationException(java.lang.String);
-    ctor public TransformerConfigurationException(java.lang.Throwable);
-    ctor public TransformerConfigurationException(java.lang.String, java.lang.Throwable);
-    ctor public TransformerConfigurationException(java.lang.String, javax.xml.transform.SourceLocator);
-    ctor public TransformerConfigurationException(java.lang.String, javax.xml.transform.SourceLocator, java.lang.Throwable);
+    ctor public TransformerConfigurationException(String);
+    ctor public TransformerConfigurationException(Throwable);
+    ctor public TransformerConfigurationException(String, Throwable);
+    ctor public TransformerConfigurationException(String, javax.xml.transform.SourceLocator);
+    ctor public TransformerConfigurationException(String, javax.xml.transform.SourceLocator, Throwable);
   }
 
   public class TransformerException extends java.lang.Exception {
-    ctor public TransformerException(java.lang.String);
-    ctor public TransformerException(java.lang.Throwable);
-    ctor public TransformerException(java.lang.String, java.lang.Throwable);
-    ctor public TransformerException(java.lang.String, javax.xml.transform.SourceLocator);
-    ctor public TransformerException(java.lang.String, javax.xml.transform.SourceLocator, java.lang.Throwable);
-    method public java.lang.Throwable getCause();
-    method public java.lang.Throwable getException();
-    method public java.lang.String getLocationAsString();
+    ctor public TransformerException(String);
+    ctor public TransformerException(Throwable);
+    ctor public TransformerException(String, Throwable);
+    ctor public TransformerException(String, javax.xml.transform.SourceLocator);
+    ctor public TransformerException(String, javax.xml.transform.SourceLocator, Throwable);
+    method public Throwable getException();
+    method public String getLocationAsString();
     method public javax.xml.transform.SourceLocator getLocator();
-    method public java.lang.String getMessageAndLocation();
+    method public String getMessageAndLocation();
     method public void setLocator(javax.xml.transform.SourceLocator);
   }
 
   public abstract class TransformerFactory {
     ctor protected TransformerFactory();
-    method public abstract javax.xml.transform.Source getAssociatedStylesheet(javax.xml.transform.Source, java.lang.String, java.lang.String, java.lang.String) throws javax.xml.transform.TransformerConfigurationException;
-    method public abstract java.lang.Object getAttribute(java.lang.String);
+    method public abstract javax.xml.transform.Source getAssociatedStylesheet(javax.xml.transform.Source, String, String, String) throws javax.xml.transform.TransformerConfigurationException;
+    method public abstract Object getAttribute(String);
     method public abstract javax.xml.transform.ErrorListener getErrorListener();
-    method public abstract boolean getFeature(java.lang.String);
+    method public abstract boolean getFeature(String);
     method public abstract javax.xml.transform.URIResolver getURIResolver();
     method public static javax.xml.transform.TransformerFactory newInstance() throws javax.xml.transform.TransformerFactoryConfigurationError;
-    method public static javax.xml.transform.TransformerFactory newInstance(java.lang.String, java.lang.ClassLoader) throws javax.xml.transform.TransformerFactoryConfigurationError;
+    method public static javax.xml.transform.TransformerFactory newInstance(String, ClassLoader) throws javax.xml.transform.TransformerFactoryConfigurationError;
     method public abstract javax.xml.transform.Templates newTemplates(javax.xml.transform.Source) throws javax.xml.transform.TransformerConfigurationException;
     method public abstract javax.xml.transform.Transformer newTransformer(javax.xml.transform.Source) throws javax.xml.transform.TransformerConfigurationException;
     method public abstract javax.xml.transform.Transformer newTransformer() throws javax.xml.transform.TransformerConfigurationException;
-    method public abstract void setAttribute(java.lang.String, java.lang.Object);
+    method public abstract void setAttribute(String, Object);
     method public abstract void setErrorListener(javax.xml.transform.ErrorListener);
-    method public abstract void setFeature(java.lang.String, boolean) throws javax.xml.transform.TransformerConfigurationException;
+    method public abstract void setFeature(String, boolean) throws javax.xml.transform.TransformerConfigurationException;
     method public abstract void setURIResolver(javax.xml.transform.URIResolver);
   }
 
   public class TransformerFactoryConfigurationError extends java.lang.Error {
     ctor public TransformerFactoryConfigurationError();
-    ctor public TransformerFactoryConfigurationError(java.lang.String);
-    ctor public TransformerFactoryConfigurationError(java.lang.Exception);
-    ctor public TransformerFactoryConfigurationError(java.lang.Exception, java.lang.String);
-    method public java.lang.Exception getException();
+    ctor public TransformerFactoryConfigurationError(String);
+    ctor public TransformerFactoryConfigurationError(Exception);
+    ctor public TransformerFactoryConfigurationError(Exception, String);
+    method public Exception getException();
   }
 
-  public abstract interface URIResolver {
-    method public abstract javax.xml.transform.Source resolve(java.lang.String, java.lang.String) throws javax.xml.transform.TransformerException;
+  public interface URIResolver {
+    method public javax.xml.transform.Source resolve(String, String) throws javax.xml.transform.TransformerException;
   }
 
 }
 
 package javax.xml.transform.dom {
 
-  public abstract interface DOMLocator implements javax.xml.transform.SourceLocator {
-    method public abstract org.w3c.dom.Node getOriginatingNode();
+  public interface DOMLocator extends javax.xml.transform.SourceLocator {
+    method public org.w3c.dom.Node getOriginatingNode();
   }
 
   public class DOMResult implements javax.xml.transform.Result {
     ctor public DOMResult();
     ctor public DOMResult(org.w3c.dom.Node);
-    ctor public DOMResult(org.w3c.dom.Node, java.lang.String);
+    ctor public DOMResult(org.w3c.dom.Node, String);
     ctor public DOMResult(org.w3c.dom.Node, org.w3c.dom.Node);
-    ctor public DOMResult(org.w3c.dom.Node, org.w3c.dom.Node, java.lang.String);
+    ctor public DOMResult(org.w3c.dom.Node, org.w3c.dom.Node, String);
     method public org.w3c.dom.Node getNextSibling();
     method public org.w3c.dom.Node getNode();
-    method public java.lang.String getSystemId();
+    method public String getSystemId();
     method public void setNextSibling(org.w3c.dom.Node);
     method public void setNode(org.w3c.dom.Node);
-    method public void setSystemId(java.lang.String);
-    field public static final java.lang.String FEATURE = "http://javax.xml.transform.dom.DOMResult/feature";
+    method public void setSystemId(String);
+    field public static final String FEATURE = "http://javax.xml.transform.dom.DOMResult/feature";
   }
 
   public class DOMSource implements javax.xml.transform.Source {
     ctor public DOMSource();
     ctor public DOMSource(org.w3c.dom.Node);
-    ctor public DOMSource(org.w3c.dom.Node, java.lang.String);
+    ctor public DOMSource(org.w3c.dom.Node, String);
     method public org.w3c.dom.Node getNode();
-    method public java.lang.String getSystemId();
+    method public String getSystemId();
     method public void setNode(org.w3c.dom.Node);
-    method public void setSystemId(java.lang.String);
-    field public static final java.lang.String FEATURE = "http://javax.xml.transform.dom.DOMSource/feature";
+    method public void setSystemId(String);
+    field public static final String FEATURE = "http://javax.xml.transform.dom.DOMSource/feature";
   }
 
 }
@@ -76090,11 +76377,11 @@
     ctor public SAXResult(org.xml.sax.ContentHandler);
     method public org.xml.sax.ContentHandler getHandler();
     method public org.xml.sax.ext.LexicalHandler getLexicalHandler();
-    method public java.lang.String getSystemId();
+    method public String getSystemId();
     method public void setHandler(org.xml.sax.ContentHandler);
     method public void setLexicalHandler(org.xml.sax.ext.LexicalHandler);
-    method public void setSystemId(java.lang.String);
-    field public static final java.lang.String FEATURE = "http://javax.xml.transform.sax.SAXResult/feature";
+    method public void setSystemId(String);
+    field public static final String FEATURE = "http://javax.xml.transform.sax.SAXResult/feature";
   }
 
   public class SAXSource implements javax.xml.transform.Source {
@@ -76102,13 +76389,13 @@
     ctor public SAXSource(org.xml.sax.XMLReader, org.xml.sax.InputSource);
     ctor public SAXSource(org.xml.sax.InputSource);
     method public org.xml.sax.InputSource getInputSource();
-    method public java.lang.String getSystemId();
+    method public String getSystemId();
     method public org.xml.sax.XMLReader getXMLReader();
     method public void setInputSource(org.xml.sax.InputSource);
-    method public void setSystemId(java.lang.String);
+    method public void setSystemId(String);
     method public void setXMLReader(org.xml.sax.XMLReader);
     method public static org.xml.sax.InputSource sourceToInputSource(javax.xml.transform.Source);
-    field public static final java.lang.String FEATURE = "http://javax.xml.transform.sax.SAXSource/feature";
+    field public static final String FEATURE = "http://javax.xml.transform.sax.SAXSource/feature";
   }
 
   public abstract class SAXTransformerFactory extends javax.xml.transform.TransformerFactory {
@@ -76119,21 +76406,21 @@
     method public abstract javax.xml.transform.sax.TransformerHandler newTransformerHandler() throws javax.xml.transform.TransformerConfigurationException;
     method public abstract org.xml.sax.XMLFilter newXMLFilter(javax.xml.transform.Source) throws javax.xml.transform.TransformerConfigurationException;
     method public abstract org.xml.sax.XMLFilter newXMLFilter(javax.xml.transform.Templates) throws javax.xml.transform.TransformerConfigurationException;
-    field public static final java.lang.String FEATURE = "http://javax.xml.transform.sax.SAXTransformerFactory/feature";
-    field public static final java.lang.String FEATURE_XMLFILTER = "http://javax.xml.transform.sax.SAXTransformerFactory/feature/xmlfilter";
+    field public static final String FEATURE = "http://javax.xml.transform.sax.SAXTransformerFactory/feature";
+    field public static final String FEATURE_XMLFILTER = "http://javax.xml.transform.sax.SAXTransformerFactory/feature/xmlfilter";
   }
 
-  public abstract interface TemplatesHandler implements org.xml.sax.ContentHandler {
-    method public abstract java.lang.String getSystemId();
-    method public abstract javax.xml.transform.Templates getTemplates();
-    method public abstract void setSystemId(java.lang.String);
+  public interface TemplatesHandler extends org.xml.sax.ContentHandler {
+    method public String getSystemId();
+    method public javax.xml.transform.Templates getTemplates();
+    method public void setSystemId(String);
   }
 
-  public abstract interface TransformerHandler implements org.xml.sax.ContentHandler org.xml.sax.DTDHandler org.xml.sax.ext.LexicalHandler {
-    method public abstract java.lang.String getSystemId();
-    method public abstract javax.xml.transform.Transformer getTransformer();
-    method public abstract void setResult(javax.xml.transform.Result) throws java.lang.IllegalArgumentException;
-    method public abstract void setSystemId(java.lang.String);
+  public interface TransformerHandler extends org.xml.sax.ContentHandler org.xml.sax.DTDHandler org.xml.sax.ext.LexicalHandler {
+    method public String getSystemId();
+    method public javax.xml.transform.Transformer getTransformer();
+    method public void setResult(javax.xml.transform.Result) throws java.lang.IllegalArgumentException;
+    method public void setSystemId(String);
   }
 
 }
@@ -76144,36 +76431,36 @@
     ctor public StreamResult();
     ctor public StreamResult(java.io.OutputStream);
     ctor public StreamResult(java.io.Writer);
-    ctor public StreamResult(java.lang.String);
+    ctor public StreamResult(String);
     ctor public StreamResult(java.io.File);
     method public java.io.OutputStream getOutputStream();
-    method public java.lang.String getSystemId();
+    method public String getSystemId();
     method public java.io.Writer getWriter();
     method public void setOutputStream(java.io.OutputStream);
-    method public void setSystemId(java.lang.String);
+    method public void setSystemId(String);
     method public void setSystemId(java.io.File);
     method public void setWriter(java.io.Writer);
-    field public static final java.lang.String FEATURE = "http://javax.xml.transform.stream.StreamResult/feature";
+    field public static final String FEATURE = "http://javax.xml.transform.stream.StreamResult/feature";
   }
 
   public class StreamSource implements javax.xml.transform.Source {
     ctor public StreamSource();
     ctor public StreamSource(java.io.InputStream);
-    ctor public StreamSource(java.io.InputStream, java.lang.String);
+    ctor public StreamSource(java.io.InputStream, String);
     ctor public StreamSource(java.io.Reader);
-    ctor public StreamSource(java.io.Reader, java.lang.String);
-    ctor public StreamSource(java.lang.String);
+    ctor public StreamSource(java.io.Reader, String);
+    ctor public StreamSource(String);
     ctor public StreamSource(java.io.File);
     method public java.io.InputStream getInputStream();
-    method public java.lang.String getPublicId();
+    method public String getPublicId();
     method public java.io.Reader getReader();
-    method public java.lang.String getSystemId();
+    method public String getSystemId();
     method public void setInputStream(java.io.InputStream);
-    method public void setPublicId(java.lang.String);
+    method public void setPublicId(String);
     method public void setReader(java.io.Reader);
-    method public void setSystemId(java.lang.String);
+    method public void setSystemId(String);
     method public void setSystemId(java.io.File);
-    field public static final java.lang.String FEATURE = "http://javax.xml.transform.stream.StreamSource/feature";
+    field public static final String FEATURE = "http://javax.xml.transform.stream.StreamSource/feature";
   }
 
 }
@@ -76189,26 +76476,26 @@
   public abstract class SchemaFactory {
     ctor protected SchemaFactory();
     method public abstract org.xml.sax.ErrorHandler getErrorHandler();
-    method public boolean getFeature(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public java.lang.Object getProperty(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public boolean getFeature(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public Object getProperty(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public abstract org.w3c.dom.ls.LSResourceResolver getResourceResolver();
-    method public abstract boolean isSchemaLanguageSupported(java.lang.String);
-    method public static javax.xml.validation.SchemaFactory newInstance(java.lang.String);
-    method public static javax.xml.validation.SchemaFactory newInstance(java.lang.String, java.lang.String, java.lang.ClassLoader);
+    method public abstract boolean isSchemaLanguageSupported(String);
+    method public static javax.xml.validation.SchemaFactory newInstance(String);
+    method public static javax.xml.validation.SchemaFactory newInstance(String, String, ClassLoader);
     method public javax.xml.validation.Schema newSchema(javax.xml.transform.Source) throws org.xml.sax.SAXException;
     method public javax.xml.validation.Schema newSchema(java.io.File) throws org.xml.sax.SAXException;
     method public javax.xml.validation.Schema newSchema(java.net.URL) throws org.xml.sax.SAXException;
     method public abstract javax.xml.validation.Schema newSchema(javax.xml.transform.Source[]) throws org.xml.sax.SAXException;
     method public abstract javax.xml.validation.Schema newSchema() throws org.xml.sax.SAXException;
     method public abstract void setErrorHandler(org.xml.sax.ErrorHandler);
-    method public void setFeature(java.lang.String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public void setProperty(java.lang.String, java.lang.Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public void setFeature(String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public void setProperty(String, Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public abstract void setResourceResolver(org.w3c.dom.ls.LSResourceResolver);
   }
 
   public abstract class SchemaFactoryLoader {
     ctor protected SchemaFactoryLoader();
-    method public abstract javax.xml.validation.SchemaFactory newFactory(java.lang.String);
+    method public abstract javax.xml.validation.SchemaFactory newFactory(String);
   }
 
   public abstract class TypeInfoProvider {
@@ -76222,13 +76509,13 @@
   public abstract class Validator {
     ctor protected Validator();
     method public abstract org.xml.sax.ErrorHandler getErrorHandler();
-    method public boolean getFeature(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public java.lang.Object getProperty(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public boolean getFeature(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public Object getProperty(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public abstract org.w3c.dom.ls.LSResourceResolver getResourceResolver();
     method public abstract void reset();
     method public abstract void setErrorHandler(org.xml.sax.ErrorHandler);
-    method public void setFeature(java.lang.String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public void setProperty(java.lang.String, java.lang.Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public void setFeature(String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public void setProperty(String, Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public abstract void setResourceResolver(org.w3c.dom.ls.LSResourceResolver);
     method public void validate(javax.xml.transform.Source) throws java.io.IOException, org.xml.sax.SAXException;
     method public abstract void validate(javax.xml.transform.Source, javax.xml.transform.Result) throws java.io.IOException, org.xml.sax.SAXException;
@@ -76238,14 +76525,14 @@
     ctor protected ValidatorHandler();
     method public abstract org.xml.sax.ContentHandler getContentHandler();
     method public abstract org.xml.sax.ErrorHandler getErrorHandler();
-    method public boolean getFeature(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public java.lang.Object getProperty(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public boolean getFeature(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public Object getProperty(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public abstract org.w3c.dom.ls.LSResourceResolver getResourceResolver();
     method public abstract javax.xml.validation.TypeInfoProvider getTypeInfoProvider();
     method public abstract void setContentHandler(org.xml.sax.ContentHandler);
     method public abstract void setErrorHandler(org.xml.sax.ErrorHandler);
-    method public void setFeature(java.lang.String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public void setProperty(java.lang.String, java.lang.Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public void setFeature(String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public void setProperty(String, Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public abstract void setResourceResolver(org.w3c.dom.ls.LSResourceResolver);
   }
 
@@ -76253,24 +76540,24 @@
 
 package javax.xml.xpath {
 
-  public abstract interface XPath {
-    method public abstract javax.xml.xpath.XPathExpression compile(java.lang.String) throws javax.xml.xpath.XPathExpressionException;
-    method public abstract java.lang.Object evaluate(java.lang.String, java.lang.Object, javax.xml.namespace.QName) throws javax.xml.xpath.XPathExpressionException;
-    method public abstract java.lang.String evaluate(java.lang.String, java.lang.Object) throws javax.xml.xpath.XPathExpressionException;
-    method public abstract java.lang.Object evaluate(java.lang.String, org.xml.sax.InputSource, javax.xml.namespace.QName) throws javax.xml.xpath.XPathExpressionException;
-    method public abstract java.lang.String evaluate(java.lang.String, org.xml.sax.InputSource) throws javax.xml.xpath.XPathExpressionException;
-    method public abstract javax.xml.namespace.NamespaceContext getNamespaceContext();
-    method public abstract javax.xml.xpath.XPathFunctionResolver getXPathFunctionResolver();
-    method public abstract javax.xml.xpath.XPathVariableResolver getXPathVariableResolver();
-    method public abstract void reset();
-    method public abstract void setNamespaceContext(javax.xml.namespace.NamespaceContext);
-    method public abstract void setXPathFunctionResolver(javax.xml.xpath.XPathFunctionResolver);
-    method public abstract void setXPathVariableResolver(javax.xml.xpath.XPathVariableResolver);
+  public interface XPath {
+    method public javax.xml.xpath.XPathExpression compile(String) throws javax.xml.xpath.XPathExpressionException;
+    method public Object evaluate(String, Object, javax.xml.namespace.QName) throws javax.xml.xpath.XPathExpressionException;
+    method public String evaluate(String, Object) throws javax.xml.xpath.XPathExpressionException;
+    method public Object evaluate(String, org.xml.sax.InputSource, javax.xml.namespace.QName) throws javax.xml.xpath.XPathExpressionException;
+    method public String evaluate(String, org.xml.sax.InputSource) throws javax.xml.xpath.XPathExpressionException;
+    method public javax.xml.namespace.NamespaceContext getNamespaceContext();
+    method public javax.xml.xpath.XPathFunctionResolver getXPathFunctionResolver();
+    method public javax.xml.xpath.XPathVariableResolver getXPathVariableResolver();
+    method public void reset();
+    method public void setNamespaceContext(javax.xml.namespace.NamespaceContext);
+    method public void setXPathFunctionResolver(javax.xml.xpath.XPathFunctionResolver);
+    method public void setXPathVariableResolver(javax.xml.xpath.XPathVariableResolver);
   }
 
   public class XPathConstants {
     field public static final javax.xml.namespace.QName BOOLEAN;
-    field public static final java.lang.String DOM_OBJECT_MODEL = "http://java.sun.com/jaxp/xpath/dom";
+    field public static final String DOM_OBJECT_MODEL = "http://java.sun.com/jaxp/xpath/dom";
     field public static final javax.xml.namespace.QName NODE;
     field public static final javax.xml.namespace.QName NODESET;
     field public static final javax.xml.namespace.QName NUMBER;
@@ -76278,192 +76565,191 @@
   }
 
   public class XPathException extends java.lang.Exception {
-    ctor public XPathException(java.lang.String);
-    ctor public XPathException(java.lang.Throwable);
-    method public java.lang.Throwable getCause();
+    ctor public XPathException(String);
+    ctor public XPathException(Throwable);
   }
 
-  public abstract interface XPathExpression {
-    method public abstract java.lang.Object evaluate(java.lang.Object, javax.xml.namespace.QName) throws javax.xml.xpath.XPathExpressionException;
-    method public abstract java.lang.String evaluate(java.lang.Object) throws javax.xml.xpath.XPathExpressionException;
-    method public abstract java.lang.Object evaluate(org.xml.sax.InputSource, javax.xml.namespace.QName) throws javax.xml.xpath.XPathExpressionException;
-    method public abstract java.lang.String evaluate(org.xml.sax.InputSource) throws javax.xml.xpath.XPathExpressionException;
+  public interface XPathExpression {
+    method public Object evaluate(Object, javax.xml.namespace.QName) throws javax.xml.xpath.XPathExpressionException;
+    method public String evaluate(Object) throws javax.xml.xpath.XPathExpressionException;
+    method public Object evaluate(org.xml.sax.InputSource, javax.xml.namespace.QName) throws javax.xml.xpath.XPathExpressionException;
+    method public String evaluate(org.xml.sax.InputSource) throws javax.xml.xpath.XPathExpressionException;
   }
 
   public class XPathExpressionException extends javax.xml.xpath.XPathException {
-    ctor public XPathExpressionException(java.lang.String);
-    ctor public XPathExpressionException(java.lang.Throwable);
+    ctor public XPathExpressionException(String);
+    ctor public XPathExpressionException(Throwable);
   }
 
   public abstract class XPathFactory {
     ctor protected XPathFactory();
-    method public abstract boolean getFeature(java.lang.String) throws javax.xml.xpath.XPathFactoryConfigurationException;
-    method public abstract boolean isObjectModelSupported(java.lang.String);
+    method public abstract boolean getFeature(String) throws javax.xml.xpath.XPathFactoryConfigurationException;
+    method public abstract boolean isObjectModelSupported(String);
     method public static final javax.xml.xpath.XPathFactory newInstance();
-    method public static final javax.xml.xpath.XPathFactory newInstance(java.lang.String) throws javax.xml.xpath.XPathFactoryConfigurationException;
-    method public static javax.xml.xpath.XPathFactory newInstance(java.lang.String, java.lang.String, java.lang.ClassLoader) throws javax.xml.xpath.XPathFactoryConfigurationException;
+    method public static final javax.xml.xpath.XPathFactory newInstance(String) throws javax.xml.xpath.XPathFactoryConfigurationException;
+    method public static javax.xml.xpath.XPathFactory newInstance(String, String, ClassLoader) throws javax.xml.xpath.XPathFactoryConfigurationException;
     method public abstract javax.xml.xpath.XPath newXPath();
-    method public abstract void setFeature(java.lang.String, boolean) throws javax.xml.xpath.XPathFactoryConfigurationException;
+    method public abstract void setFeature(String, boolean) throws javax.xml.xpath.XPathFactoryConfigurationException;
     method public abstract void setXPathFunctionResolver(javax.xml.xpath.XPathFunctionResolver);
     method public abstract void setXPathVariableResolver(javax.xml.xpath.XPathVariableResolver);
-    field public static final java.lang.String DEFAULT_OBJECT_MODEL_URI = "http://java.sun.com/jaxp/xpath/dom";
-    field public static final java.lang.String DEFAULT_PROPERTY_NAME = "javax.xml.xpath.XPathFactory";
+    field public static final String DEFAULT_OBJECT_MODEL_URI = "http://java.sun.com/jaxp/xpath/dom";
+    field public static final String DEFAULT_PROPERTY_NAME = "javax.xml.xpath.XPathFactory";
   }
 
   public class XPathFactoryConfigurationException extends javax.xml.xpath.XPathException {
-    ctor public XPathFactoryConfigurationException(java.lang.String);
-    ctor public XPathFactoryConfigurationException(java.lang.Throwable);
+    ctor public XPathFactoryConfigurationException(String);
+    ctor public XPathFactoryConfigurationException(Throwable);
   }
 
-  public abstract interface XPathFunction {
-    method public abstract java.lang.Object evaluate(java.util.List) throws javax.xml.xpath.XPathFunctionException;
+  public interface XPathFunction {
+    method public Object evaluate(java.util.List) throws javax.xml.xpath.XPathFunctionException;
   }
 
   public class XPathFunctionException extends javax.xml.xpath.XPathExpressionException {
-    ctor public XPathFunctionException(java.lang.String);
-    ctor public XPathFunctionException(java.lang.Throwable);
+    ctor public XPathFunctionException(String);
+    ctor public XPathFunctionException(Throwable);
   }
 
-  public abstract interface XPathFunctionResolver {
-    method public abstract javax.xml.xpath.XPathFunction resolveFunction(javax.xml.namespace.QName, int);
+  public interface XPathFunctionResolver {
+    method public javax.xml.xpath.XPathFunction resolveFunction(javax.xml.namespace.QName, int);
   }
 
-  public abstract interface XPathVariableResolver {
-    method public abstract java.lang.Object resolveVariable(javax.xml.namespace.QName);
+  public interface XPathVariableResolver {
+    method public Object resolveVariable(javax.xml.namespace.QName);
   }
 
 }
 
 package org.apache.http.conn {
 
-  public deprecated class ConnectTimeoutException extends java.io.InterruptedIOException {
-    ctor public ConnectTimeoutException();
-    ctor public ConnectTimeoutException(java.lang.String);
+  @Deprecated public class ConnectTimeoutException extends java.io.InterruptedIOException {
+    ctor @Deprecated public ConnectTimeoutException();
+    ctor @Deprecated public ConnectTimeoutException(String);
   }
 
 }
 
 package org.apache.http.conn.scheme {
 
-  public abstract deprecated interface HostNameResolver {
-    method public abstract java.net.InetAddress resolve(java.lang.String) throws java.io.IOException;
+  @Deprecated public interface HostNameResolver {
+    method @Deprecated public java.net.InetAddress resolve(String) throws java.io.IOException;
   }
 
-  public abstract deprecated interface LayeredSocketFactory implements org.apache.http.conn.scheme.SocketFactory {
-    method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException, java.net.UnknownHostException;
+  @Deprecated public interface LayeredSocketFactory extends org.apache.http.conn.scheme.SocketFactory {
+    method @Deprecated public java.net.Socket createSocket(java.net.Socket, String, int, boolean) throws java.io.IOException, java.net.UnknownHostException;
   }
 
-  public abstract deprecated interface SocketFactory {
-    method public abstract java.net.Socket connectSocket(java.net.Socket, java.lang.String, int, java.net.InetAddress, int, org.apache.http.params.HttpParams) throws org.apache.http.conn.ConnectTimeoutException, java.io.IOException, java.net.UnknownHostException;
-    method public abstract java.net.Socket createSocket() throws java.io.IOException;
-    method public abstract boolean isSecure(java.net.Socket) throws java.lang.IllegalArgumentException;
+  @Deprecated public interface SocketFactory {
+    method @Deprecated public java.net.Socket connectSocket(java.net.Socket, String, int, java.net.InetAddress, int, org.apache.http.params.HttpParams) throws org.apache.http.conn.ConnectTimeoutException, java.io.IOException, java.net.UnknownHostException;
+    method @Deprecated public java.net.Socket createSocket() throws java.io.IOException;
+    method @Deprecated public boolean isSecure(java.net.Socket) throws java.lang.IllegalArgumentException;
   }
 
 }
 
 package org.apache.http.conn.ssl {
 
-  public abstract deprecated class AbstractVerifier implements org.apache.http.conn.ssl.X509HostnameVerifier {
-    ctor public AbstractVerifier();
-    method public static boolean acceptableCountryWildcard(java.lang.String);
-    method public static int countDots(java.lang.String);
-    method public static java.lang.String[] getCNs(java.security.cert.X509Certificate);
-    method public static java.lang.String[] getDNSSubjectAlts(java.security.cert.X509Certificate);
-    method public final void verify(java.lang.String, javax.net.ssl.SSLSocket) throws java.io.IOException;
-    method public final boolean verify(java.lang.String, javax.net.ssl.SSLSession);
-    method public final void verify(java.lang.String, java.security.cert.X509Certificate) throws javax.net.ssl.SSLException;
-    method public final void verify(java.lang.String, java.lang.String[], java.lang.String[], boolean) throws javax.net.ssl.SSLException;
+  @Deprecated public abstract class AbstractVerifier implements org.apache.http.conn.ssl.X509HostnameVerifier {
+    ctor @Deprecated public AbstractVerifier();
+    method @Deprecated public static boolean acceptableCountryWildcard(String);
+    method @Deprecated public static int countDots(String);
+    method @Deprecated public static String[] getCNs(java.security.cert.X509Certificate);
+    method @Deprecated public static String[] getDNSSubjectAlts(java.security.cert.X509Certificate);
+    method @Deprecated public final void verify(String, javax.net.ssl.SSLSocket) throws java.io.IOException;
+    method @Deprecated public final boolean verify(String, javax.net.ssl.SSLSession);
+    method @Deprecated public final void verify(String, java.security.cert.X509Certificate) throws javax.net.ssl.SSLException;
+    method @Deprecated public final void verify(String, String[], String[], boolean) throws javax.net.ssl.SSLException;
   }
 
-  public deprecated class AllowAllHostnameVerifier extends org.apache.http.conn.ssl.AbstractVerifier {
-    ctor public AllowAllHostnameVerifier();
-    method public final java.lang.String toString();
-    method public final void verify(java.lang.String, java.lang.String[], java.lang.String[]);
+  @Deprecated public class AllowAllHostnameVerifier extends org.apache.http.conn.ssl.AbstractVerifier {
+    ctor @Deprecated public AllowAllHostnameVerifier();
+    method @Deprecated public final String toString();
+    method @Deprecated public final void verify(String, String[], String[]);
   }
 
-  public deprecated class BrowserCompatHostnameVerifier extends org.apache.http.conn.ssl.AbstractVerifier {
-    ctor public BrowserCompatHostnameVerifier();
-    method public final java.lang.String toString();
-    method public final void verify(java.lang.String, java.lang.String[], java.lang.String[]) throws javax.net.ssl.SSLException;
+  @Deprecated public class BrowserCompatHostnameVerifier extends org.apache.http.conn.ssl.AbstractVerifier {
+    ctor @Deprecated public BrowserCompatHostnameVerifier();
+    method @Deprecated public final String toString();
+    method @Deprecated public final void verify(String, String[], String[]) throws javax.net.ssl.SSLException;
   }
 
-  public deprecated class SSLSocketFactory implements org.apache.http.conn.scheme.LayeredSocketFactory {
-    ctor public SSLSocketFactory(java.lang.String, java.security.KeyStore, java.lang.String, java.security.KeyStore, java.security.SecureRandom, org.apache.http.conn.scheme.HostNameResolver) throws java.security.KeyManagementException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException;
-    ctor public SSLSocketFactory(java.security.KeyStore, java.lang.String, java.security.KeyStore) throws java.security.KeyManagementException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException;
-    ctor public SSLSocketFactory(java.security.KeyStore, java.lang.String) throws java.security.KeyManagementException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException;
-    ctor public SSLSocketFactory(java.security.KeyStore) throws java.security.KeyManagementException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException;
-    method public java.net.Socket connectSocket(java.net.Socket, java.lang.String, int, java.net.InetAddress, int, org.apache.http.params.HttpParams) throws java.io.IOException;
-    method public java.net.Socket createSocket() throws java.io.IOException;
-    method public java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException, java.net.UnknownHostException;
-    method public org.apache.http.conn.ssl.X509HostnameVerifier getHostnameVerifier();
-    method public static org.apache.http.conn.ssl.SSLSocketFactory getSocketFactory();
-    method public boolean isSecure(java.net.Socket) throws java.lang.IllegalArgumentException;
-    method public void setHostnameVerifier(org.apache.http.conn.ssl.X509HostnameVerifier);
-    field public static final org.apache.http.conn.ssl.X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER;
-    field public static final org.apache.http.conn.ssl.X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
-    field public static final java.lang.String SSL = "SSL";
-    field public static final java.lang.String SSLV2 = "SSLv2";
-    field public static final org.apache.http.conn.ssl.X509HostnameVerifier STRICT_HOSTNAME_VERIFIER;
-    field public static final java.lang.String TLS = "TLS";
+  @Deprecated public class SSLSocketFactory implements org.apache.http.conn.scheme.LayeredSocketFactory {
+    ctor @Deprecated public SSLSocketFactory(String, java.security.KeyStore, String, java.security.KeyStore, java.security.SecureRandom, org.apache.http.conn.scheme.HostNameResolver) throws java.security.KeyManagementException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException;
+    ctor @Deprecated public SSLSocketFactory(java.security.KeyStore, String, java.security.KeyStore) throws java.security.KeyManagementException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException;
+    ctor @Deprecated public SSLSocketFactory(java.security.KeyStore, String) throws java.security.KeyManagementException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException;
+    ctor @Deprecated public SSLSocketFactory(java.security.KeyStore) throws java.security.KeyManagementException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException;
+    method @Deprecated public java.net.Socket connectSocket(java.net.Socket, String, int, java.net.InetAddress, int, org.apache.http.params.HttpParams) throws java.io.IOException;
+    method @Deprecated public java.net.Socket createSocket() throws java.io.IOException;
+    method @Deprecated public java.net.Socket createSocket(java.net.Socket, String, int, boolean) throws java.io.IOException, java.net.UnknownHostException;
+    method @Deprecated public org.apache.http.conn.ssl.X509HostnameVerifier getHostnameVerifier();
+    method @Deprecated public static org.apache.http.conn.ssl.SSLSocketFactory getSocketFactory();
+    method @Deprecated public boolean isSecure(java.net.Socket) throws java.lang.IllegalArgumentException;
+    method @Deprecated public void setHostnameVerifier(org.apache.http.conn.ssl.X509HostnameVerifier);
+    field @Deprecated public static final org.apache.http.conn.ssl.X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER;
+    field @Deprecated public static final org.apache.http.conn.ssl.X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
+    field @Deprecated public static final String SSL = "SSL";
+    field @Deprecated public static final String SSLV2 = "SSLv2";
+    field @Deprecated public static final org.apache.http.conn.ssl.X509HostnameVerifier STRICT_HOSTNAME_VERIFIER;
+    field @Deprecated public static final String TLS = "TLS";
   }
 
-  public deprecated class StrictHostnameVerifier extends org.apache.http.conn.ssl.AbstractVerifier {
-    ctor public StrictHostnameVerifier();
-    method public final java.lang.String toString();
-    method public final void verify(java.lang.String, java.lang.String[], java.lang.String[]) throws javax.net.ssl.SSLException;
+  @Deprecated public class StrictHostnameVerifier extends org.apache.http.conn.ssl.AbstractVerifier {
+    ctor @Deprecated public StrictHostnameVerifier();
+    method @Deprecated public final String toString();
+    method @Deprecated public final void verify(String, String[], String[]) throws javax.net.ssl.SSLException;
   }
 
-  public abstract deprecated interface X509HostnameVerifier implements javax.net.ssl.HostnameVerifier {
-    method public abstract void verify(java.lang.String, javax.net.ssl.SSLSocket) throws java.io.IOException;
-    method public abstract void verify(java.lang.String, java.security.cert.X509Certificate) throws javax.net.ssl.SSLException;
-    method public abstract void verify(java.lang.String, java.lang.String[], java.lang.String[]) throws javax.net.ssl.SSLException;
+  @Deprecated public interface X509HostnameVerifier extends javax.net.ssl.HostnameVerifier {
+    method @Deprecated public void verify(String, javax.net.ssl.SSLSocket) throws java.io.IOException;
+    method @Deprecated public void verify(String, java.security.cert.X509Certificate) throws javax.net.ssl.SSLException;
+    method @Deprecated public void verify(String, String[], String[]) throws javax.net.ssl.SSLException;
   }
 
 }
 
 package org.apache.http.params {
 
-  public abstract deprecated interface CoreConnectionPNames {
-    field public static final java.lang.String CONNECTION_TIMEOUT = "http.connection.timeout";
-    field public static final java.lang.String MAX_HEADER_COUNT = "http.connection.max-header-count";
-    field public static final java.lang.String MAX_LINE_LENGTH = "http.connection.max-line-length";
-    field public static final java.lang.String SOCKET_BUFFER_SIZE = "http.socket.buffer-size";
-    field public static final java.lang.String SO_LINGER = "http.socket.linger";
-    field public static final java.lang.String SO_TIMEOUT = "http.socket.timeout";
-    field public static final java.lang.String STALE_CONNECTION_CHECK = "http.connection.stalecheck";
-    field public static final java.lang.String TCP_NODELAY = "http.tcp.nodelay";
+  @Deprecated public interface CoreConnectionPNames {
+    field @Deprecated public static final String CONNECTION_TIMEOUT = "http.connection.timeout";
+    field @Deprecated public static final String MAX_HEADER_COUNT = "http.connection.max-header-count";
+    field @Deprecated public static final String MAX_LINE_LENGTH = "http.connection.max-line-length";
+    field @Deprecated public static final String SOCKET_BUFFER_SIZE = "http.socket.buffer-size";
+    field @Deprecated public static final String SO_LINGER = "http.socket.linger";
+    field @Deprecated public static final String SO_TIMEOUT = "http.socket.timeout";
+    field @Deprecated public static final String STALE_CONNECTION_CHECK = "http.connection.stalecheck";
+    field @Deprecated public static final String TCP_NODELAY = "http.tcp.nodelay";
   }
 
-  public final deprecated class HttpConnectionParams implements org.apache.http.params.CoreConnectionPNames {
-    method public static int getConnectionTimeout(org.apache.http.params.HttpParams);
-    method public static int getLinger(org.apache.http.params.HttpParams);
-    method public static int getSoTimeout(org.apache.http.params.HttpParams);
-    method public static int getSocketBufferSize(org.apache.http.params.HttpParams);
-    method public static boolean getTcpNoDelay(org.apache.http.params.HttpParams);
-    method public static boolean isStaleCheckingEnabled(org.apache.http.params.HttpParams);
-    method public static void setConnectionTimeout(org.apache.http.params.HttpParams, int);
-    method public static void setLinger(org.apache.http.params.HttpParams, int);
-    method public static void setSoTimeout(org.apache.http.params.HttpParams, int);
-    method public static void setSocketBufferSize(org.apache.http.params.HttpParams, int);
-    method public static void setStaleCheckingEnabled(org.apache.http.params.HttpParams, boolean);
-    method public static void setTcpNoDelay(org.apache.http.params.HttpParams, boolean);
+  @Deprecated public final class HttpConnectionParams implements org.apache.http.params.CoreConnectionPNames {
+    method @Deprecated public static int getConnectionTimeout(org.apache.http.params.HttpParams);
+    method @Deprecated public static int getLinger(org.apache.http.params.HttpParams);
+    method @Deprecated public static int getSoTimeout(org.apache.http.params.HttpParams);
+    method @Deprecated public static int getSocketBufferSize(org.apache.http.params.HttpParams);
+    method @Deprecated public static boolean getTcpNoDelay(org.apache.http.params.HttpParams);
+    method @Deprecated public static boolean isStaleCheckingEnabled(org.apache.http.params.HttpParams);
+    method @Deprecated public static void setConnectionTimeout(org.apache.http.params.HttpParams, int);
+    method @Deprecated public static void setLinger(org.apache.http.params.HttpParams, int);
+    method @Deprecated public static void setSoTimeout(org.apache.http.params.HttpParams, int);
+    method @Deprecated public static void setSocketBufferSize(org.apache.http.params.HttpParams, int);
+    method @Deprecated public static void setStaleCheckingEnabled(org.apache.http.params.HttpParams, boolean);
+    method @Deprecated public static void setTcpNoDelay(org.apache.http.params.HttpParams, boolean);
   }
 
-  public abstract deprecated interface HttpParams {
-    method public abstract org.apache.http.params.HttpParams copy();
-    method public abstract boolean getBooleanParameter(java.lang.String, boolean);
-    method public abstract double getDoubleParameter(java.lang.String, double);
-    method public abstract int getIntParameter(java.lang.String, int);
-    method public abstract long getLongParameter(java.lang.String, long);
-    method public abstract java.lang.Object getParameter(java.lang.String);
-    method public abstract boolean isParameterFalse(java.lang.String);
-    method public abstract boolean isParameterTrue(java.lang.String);
-    method public abstract boolean removeParameter(java.lang.String);
-    method public abstract org.apache.http.params.HttpParams setBooleanParameter(java.lang.String, boolean);
-    method public abstract org.apache.http.params.HttpParams setDoubleParameter(java.lang.String, double);
-    method public abstract org.apache.http.params.HttpParams setIntParameter(java.lang.String, int);
-    method public abstract org.apache.http.params.HttpParams setLongParameter(java.lang.String, long);
-    method public abstract org.apache.http.params.HttpParams setParameter(java.lang.String, java.lang.Object);
+  @Deprecated public interface HttpParams {
+    method @Deprecated public org.apache.http.params.HttpParams copy();
+    method @Deprecated public boolean getBooleanParameter(String, boolean);
+    method @Deprecated public double getDoubleParameter(String, double);
+    method @Deprecated public int getIntParameter(String, int);
+    method @Deprecated public long getLongParameter(String, long);
+    method @Deprecated public Object getParameter(String);
+    method @Deprecated public boolean isParameterFalse(String);
+    method @Deprecated public boolean isParameterTrue(String);
+    method @Deprecated public boolean removeParameter(String);
+    method @Deprecated public org.apache.http.params.HttpParams setBooleanParameter(String, boolean);
+    method @Deprecated public org.apache.http.params.HttpParams setDoubleParameter(String, double);
+    method @Deprecated public org.apache.http.params.HttpParams setIntParameter(String, int);
+    method @Deprecated public org.apache.http.params.HttpParams setLongParameter(String, long);
+    method @Deprecated public org.apache.http.params.HttpParams setParameter(String, Object);
   }
 
 }
@@ -76474,20 +76760,20 @@
     ctor public JSONArray();
     ctor public JSONArray(java.util.Collection);
     ctor public JSONArray(org.json.JSONTokener) throws org.json.JSONException;
-    ctor public JSONArray(java.lang.String) throws org.json.JSONException;
-    ctor public JSONArray(java.lang.Object) throws org.json.JSONException;
-    method public java.lang.Object get(int) throws org.json.JSONException;
+    ctor public JSONArray(String) throws org.json.JSONException;
+    ctor public JSONArray(Object) throws org.json.JSONException;
+    method public Object get(int) throws org.json.JSONException;
     method public boolean getBoolean(int) throws org.json.JSONException;
     method public double getDouble(int) throws org.json.JSONException;
     method public int getInt(int) throws org.json.JSONException;
     method public org.json.JSONArray getJSONArray(int) throws org.json.JSONException;
     method public org.json.JSONObject getJSONObject(int) throws org.json.JSONException;
     method public long getLong(int) throws org.json.JSONException;
-    method public java.lang.String getString(int) throws org.json.JSONException;
+    method public String getString(int) throws org.json.JSONException;
     method public boolean isNull(int);
-    method public java.lang.String join(java.lang.String) throws org.json.JSONException;
+    method public String join(String) throws org.json.JSONException;
     method public int length();
-    method public java.lang.Object opt(int);
+    method public Object opt(int);
     method public boolean optBoolean(int);
     method public boolean optBoolean(int, boolean);
     method public double optDouble(int);
@@ -76498,75 +76784,75 @@
     method public org.json.JSONObject optJSONObject(int);
     method public long optLong(int);
     method public long optLong(int, long);
-    method public java.lang.String optString(int);
-    method public java.lang.String optString(int, java.lang.String);
+    method public String optString(int);
+    method public String optString(int, String);
     method public org.json.JSONArray put(boolean);
     method public org.json.JSONArray put(double) throws org.json.JSONException;
     method public org.json.JSONArray put(int);
     method public org.json.JSONArray put(long);
-    method public org.json.JSONArray put(java.lang.Object);
+    method public org.json.JSONArray put(Object);
     method public org.json.JSONArray put(int, boolean) throws org.json.JSONException;
     method public org.json.JSONArray put(int, double) throws org.json.JSONException;
     method public org.json.JSONArray put(int, int) throws org.json.JSONException;
     method public org.json.JSONArray put(int, long) throws org.json.JSONException;
-    method public org.json.JSONArray put(int, java.lang.Object) throws org.json.JSONException;
-    method public java.lang.Object remove(int);
+    method public org.json.JSONArray put(int, Object) throws org.json.JSONException;
+    method public Object remove(int);
     method public org.json.JSONObject toJSONObject(org.json.JSONArray) throws org.json.JSONException;
-    method public java.lang.String toString(int) throws org.json.JSONException;
+    method public String toString(int) throws org.json.JSONException;
   }
 
   public class JSONException extends java.lang.Exception {
-    ctor public JSONException(java.lang.String);
-    ctor public JSONException(java.lang.String, java.lang.Throwable);
-    ctor public JSONException(java.lang.Throwable);
+    ctor public JSONException(String);
+    ctor public JSONException(String, Throwable);
+    ctor public JSONException(Throwable);
   }
 
   public class JSONObject {
     ctor public JSONObject();
-    ctor public JSONObject(java.util.Map);
-    ctor public JSONObject(org.json.JSONTokener) throws org.json.JSONException;
-    ctor public JSONObject(java.lang.String) throws org.json.JSONException;
-    ctor public JSONObject(org.json.JSONObject, java.lang.String[]) throws org.json.JSONException;
-    method public org.json.JSONObject accumulate(java.lang.String, java.lang.Object) throws org.json.JSONException;
-    method public java.lang.Object get(java.lang.String) throws org.json.JSONException;
-    method public boolean getBoolean(java.lang.String) throws org.json.JSONException;
-    method public double getDouble(java.lang.String) throws org.json.JSONException;
-    method public int getInt(java.lang.String) throws org.json.JSONException;
-    method public org.json.JSONArray getJSONArray(java.lang.String) throws org.json.JSONException;
-    method public org.json.JSONObject getJSONObject(java.lang.String) throws org.json.JSONException;
-    method public long getLong(java.lang.String) throws org.json.JSONException;
-    method public java.lang.String getString(java.lang.String) throws org.json.JSONException;
-    method public boolean has(java.lang.String);
-    method public boolean isNull(java.lang.String);
-    method public java.util.Iterator<java.lang.String> keys();
+    ctor public JSONObject(@NonNull java.util.Map);
+    ctor public JSONObject(@NonNull org.json.JSONTokener) throws org.json.JSONException;
+    ctor public JSONObject(@NonNull String) throws org.json.JSONException;
+    ctor public JSONObject(@NonNull org.json.JSONObject, @NonNull String[]) throws org.json.JSONException;
+    method @NonNull public org.json.JSONObject accumulate(@NonNull String, @Nullable Object) throws org.json.JSONException;
+    method @NonNull public Object get(@NonNull String) throws org.json.JSONException;
+    method public boolean getBoolean(@NonNull String) throws org.json.JSONException;
+    method public double getDouble(@NonNull String) throws org.json.JSONException;
+    method public int getInt(@NonNull String) throws org.json.JSONException;
+    method @NonNull public org.json.JSONArray getJSONArray(@NonNull String) throws org.json.JSONException;
+    method @NonNull public org.json.JSONObject getJSONObject(@NonNull String) throws org.json.JSONException;
+    method public long getLong(@NonNull String) throws org.json.JSONException;
+    method @NonNull public String getString(@NonNull String) throws org.json.JSONException;
+    method public boolean has(@Nullable String);
+    method public boolean isNull(@Nullable String);
+    method @NonNull public java.util.Iterator<java.lang.String> keys();
     method public int length();
-    method public org.json.JSONArray names();
-    method public static java.lang.String numberToString(java.lang.Number) throws org.json.JSONException;
-    method public java.lang.Object opt(java.lang.String);
-    method public boolean optBoolean(java.lang.String);
-    method public boolean optBoolean(java.lang.String, boolean);
-    method public double optDouble(java.lang.String);
-    method public double optDouble(java.lang.String, double);
-    method public int optInt(java.lang.String);
-    method public int optInt(java.lang.String, int);
-    method public org.json.JSONArray optJSONArray(java.lang.String);
-    method public org.json.JSONObject optJSONObject(java.lang.String);
-    method public long optLong(java.lang.String);
-    method public long optLong(java.lang.String, long);
-    method public java.lang.String optString(java.lang.String);
-    method public java.lang.String optString(java.lang.String, java.lang.String);
-    method public org.json.JSONObject put(java.lang.String, boolean) throws org.json.JSONException;
-    method public org.json.JSONObject put(java.lang.String, double) throws org.json.JSONException;
-    method public org.json.JSONObject put(java.lang.String, int) throws org.json.JSONException;
-    method public org.json.JSONObject put(java.lang.String, long) throws org.json.JSONException;
-    method public org.json.JSONObject put(java.lang.String, java.lang.Object) throws org.json.JSONException;
-    method public org.json.JSONObject putOpt(java.lang.String, java.lang.Object) throws org.json.JSONException;
-    method public static java.lang.String quote(java.lang.String);
-    method public java.lang.Object remove(java.lang.String);
-    method public org.json.JSONArray toJSONArray(org.json.JSONArray) throws org.json.JSONException;
-    method public java.lang.String toString(int) throws org.json.JSONException;
-    method public static java.lang.Object wrap(java.lang.Object);
-    field public static final java.lang.Object NULL;
+    method @Nullable public org.json.JSONArray names();
+    method @NonNull public static String numberToString(@NonNull Number) throws org.json.JSONException;
+    method @Nullable public Object opt(@Nullable String);
+    method public boolean optBoolean(@Nullable String);
+    method public boolean optBoolean(@Nullable String, boolean);
+    method public double optDouble(@Nullable String);
+    method public double optDouble(@Nullable String, double);
+    method public int optInt(@Nullable String);
+    method public int optInt(@Nullable String, int);
+    method @Nullable public org.json.JSONArray optJSONArray(@Nullable String);
+    method @Nullable public org.json.JSONObject optJSONObject(@Nullable String);
+    method public long optLong(@Nullable String);
+    method public long optLong(@Nullable String, long);
+    method @NonNull public String optString(@Nullable String);
+    method @NonNull public String optString(@Nullable String, @NonNull String);
+    method @NonNull public org.json.JSONObject put(@NonNull String, boolean) throws org.json.JSONException;
+    method @NonNull public org.json.JSONObject put(@NonNull String, double) throws org.json.JSONException;
+    method @NonNull public org.json.JSONObject put(@NonNull String, int) throws org.json.JSONException;
+    method @NonNull public org.json.JSONObject put(@NonNull String, long) throws org.json.JSONException;
+    method @NonNull public org.json.JSONObject put(@NonNull String, @Nullable Object) throws org.json.JSONException;
+    method @NonNull public org.json.JSONObject putOpt(@Nullable String, @Nullable Object) throws org.json.JSONException;
+    method @NonNull public static String quote(@Nullable String);
+    method @Nullable public Object remove(@Nullable String);
+    method @Nullable public org.json.JSONArray toJSONArray(@Nullable org.json.JSONArray) throws org.json.JSONException;
+    method @NonNull public String toString(int) throws org.json.JSONException;
+    method @Nullable public static Object wrap(@Nullable Object);
+    field @NonNull public static final Object NULL;
   }
 
   public class JSONStringer {
@@ -76574,88 +76860,88 @@
     method public org.json.JSONStringer array() throws org.json.JSONException;
     method public org.json.JSONStringer endArray() throws org.json.JSONException;
     method public org.json.JSONStringer endObject() throws org.json.JSONException;
-    method public org.json.JSONStringer key(java.lang.String) throws org.json.JSONException;
+    method public org.json.JSONStringer key(String) throws org.json.JSONException;
     method public org.json.JSONStringer object() throws org.json.JSONException;
-    method public org.json.JSONStringer value(java.lang.Object) throws org.json.JSONException;
+    method public org.json.JSONStringer value(Object) throws org.json.JSONException;
     method public org.json.JSONStringer value(boolean) throws org.json.JSONException;
     method public org.json.JSONStringer value(double) throws org.json.JSONException;
     method public org.json.JSONStringer value(long) throws org.json.JSONException;
   }
 
   public class JSONTokener {
-    ctor public JSONTokener(java.lang.String);
+    ctor public JSONTokener(String);
     method public void back();
     method public static int dehexchar(char);
     method public boolean more();
     method public char next();
     method public char next(char) throws org.json.JSONException;
-    method public java.lang.String next(int) throws org.json.JSONException;
+    method public String next(int) throws org.json.JSONException;
     method public char nextClean() throws org.json.JSONException;
-    method public java.lang.String nextString(char) throws org.json.JSONException;
-    method public java.lang.String nextTo(java.lang.String);
-    method public java.lang.String nextTo(char);
-    method public java.lang.Object nextValue() throws org.json.JSONException;
-    method public void skipPast(java.lang.String);
+    method public String nextString(char) throws org.json.JSONException;
+    method public String nextTo(String);
+    method public String nextTo(char);
+    method public Object nextValue() throws org.json.JSONException;
+    method public void skipPast(String);
     method public char skipTo(char);
-    method public org.json.JSONException syntaxError(java.lang.String);
+    method public org.json.JSONException syntaxError(String);
   }
 
 }
 
 package org.w3c.dom {
 
-  public abstract interface Attr implements org.w3c.dom.Node {
-    method public abstract java.lang.String getName();
-    method public abstract org.w3c.dom.Element getOwnerElement();
-    method public abstract org.w3c.dom.TypeInfo getSchemaTypeInfo();
-    method public abstract boolean getSpecified();
-    method public abstract java.lang.String getValue();
-    method public abstract boolean isId();
-    method public abstract void setValue(java.lang.String) throws org.w3c.dom.DOMException;
+  public interface Attr extends org.w3c.dom.Node {
+    method public String getName();
+    method public org.w3c.dom.Element getOwnerElement();
+    method public org.w3c.dom.TypeInfo getSchemaTypeInfo();
+    method public boolean getSpecified();
+    method public String getValue();
+    method public boolean isId();
+    method public void setValue(String) throws org.w3c.dom.DOMException;
   }
 
-  public abstract interface CDATASection implements org.w3c.dom.Text {
+  public interface CDATASection extends org.w3c.dom.Text {
   }
 
-  public abstract interface CharacterData implements org.w3c.dom.Node {
-    method public abstract void appendData(java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract void deleteData(int, int) throws org.w3c.dom.DOMException;
-    method public abstract java.lang.String getData() throws org.w3c.dom.DOMException;
-    method public abstract int getLength();
-    method public abstract void insertData(int, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract void replaceData(int, int, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract void setData(java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract java.lang.String substringData(int, int) throws org.w3c.dom.DOMException;
+  public interface CharacterData extends org.w3c.dom.Node {
+    method public void appendData(String) throws org.w3c.dom.DOMException;
+    method public void deleteData(int, int) throws org.w3c.dom.DOMException;
+    method public String getData() throws org.w3c.dom.DOMException;
+    method public int getLength();
+    method public void insertData(int, String) throws org.w3c.dom.DOMException;
+    method public void replaceData(int, int, String) throws org.w3c.dom.DOMException;
+    method public void setData(String) throws org.w3c.dom.DOMException;
+    method public String substringData(int, int) throws org.w3c.dom.DOMException;
   }
 
-  public abstract interface Comment implements org.w3c.dom.CharacterData {
+  public interface Comment extends org.w3c.dom.CharacterData {
   }
 
-  public abstract interface DOMConfiguration {
-    method public abstract boolean canSetParameter(java.lang.String, java.lang.Object);
-    method public abstract java.lang.Object getParameter(java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.DOMStringList getParameterNames();
-    method public abstract void setParameter(java.lang.String, java.lang.Object) throws org.w3c.dom.DOMException;
+  public interface DOMConfiguration {
+    method public boolean canSetParameter(String, Object);
+    method public Object getParameter(String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.DOMStringList getParameterNames();
+    method public void setParameter(String, Object) throws org.w3c.dom.DOMException;
   }
 
-  public abstract interface DOMError {
-    method public abstract org.w3c.dom.DOMLocator getLocation();
-    method public abstract java.lang.String getMessage();
-    method public abstract java.lang.Object getRelatedData();
-    method public abstract java.lang.Object getRelatedException();
-    method public abstract short getSeverity();
-    method public abstract java.lang.String getType();
+  public interface DOMError {
+    method public org.w3c.dom.DOMLocator getLocation();
+    method public String getMessage();
+    method public Object getRelatedData();
+    method public Object getRelatedException();
+    method public short getSeverity();
+    method public String getType();
     field public static final short SEVERITY_ERROR = 2; // 0x2
     field public static final short SEVERITY_FATAL_ERROR = 3; // 0x3
     field public static final short SEVERITY_WARNING = 1; // 0x1
   }
 
-  public abstract interface DOMErrorHandler {
-    method public abstract boolean handleError(org.w3c.dom.DOMError);
+  public interface DOMErrorHandler {
+    method public boolean handleError(org.w3c.dom.DOMError);
   }
 
   public class DOMException extends java.lang.RuntimeException {
-    ctor public DOMException(short, java.lang.String);
+    ctor public DOMException(short, String);
     field public static final short DOMSTRING_SIZE_ERR = 2; // 0x2
     field public static final short HIERARCHY_REQUEST_ERR = 3; // 0x3
     field public static final short INDEX_SIZE_ERR = 1; // 0x1
@@ -76676,176 +76962,176 @@
     field public short code;
   }
 
-  public abstract interface DOMImplementation {
-    method public abstract org.w3c.dom.Document createDocument(java.lang.String, java.lang.String, org.w3c.dom.DocumentType) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.DocumentType createDocumentType(java.lang.String, java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract java.lang.Object getFeature(java.lang.String, java.lang.String);
-    method public abstract boolean hasFeature(java.lang.String, java.lang.String);
+  public interface DOMImplementation {
+    method public org.w3c.dom.Document createDocument(String, String, org.w3c.dom.DocumentType) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.DocumentType createDocumentType(String, String, String) throws org.w3c.dom.DOMException;
+    method public Object getFeature(String, String);
+    method public boolean hasFeature(String, String);
   }
 
-  public abstract interface DOMImplementationList {
-    method public abstract int getLength();
-    method public abstract org.w3c.dom.DOMImplementation item(int);
+  public interface DOMImplementationList {
+    method public int getLength();
+    method public org.w3c.dom.DOMImplementation item(int);
   }
 
-  public abstract interface DOMImplementationSource {
-    method public abstract org.w3c.dom.DOMImplementation getDOMImplementation(java.lang.String);
-    method public abstract org.w3c.dom.DOMImplementationList getDOMImplementationList(java.lang.String);
+  public interface DOMImplementationSource {
+    method public org.w3c.dom.DOMImplementation getDOMImplementation(String);
+    method public org.w3c.dom.DOMImplementationList getDOMImplementationList(String);
   }
 
-  public abstract interface DOMLocator {
-    method public abstract int getByteOffset();
-    method public abstract int getColumnNumber();
-    method public abstract int getLineNumber();
-    method public abstract org.w3c.dom.Node getRelatedNode();
-    method public abstract java.lang.String getUri();
-    method public abstract int getUtf16Offset();
+  public interface DOMLocator {
+    method public int getByteOffset();
+    method public int getColumnNumber();
+    method public int getLineNumber();
+    method public org.w3c.dom.Node getRelatedNode();
+    method public String getUri();
+    method public int getUtf16Offset();
   }
 
-  public abstract interface DOMStringList {
-    method public abstract boolean contains(java.lang.String);
-    method public abstract int getLength();
-    method public abstract java.lang.String item(int);
+  public interface DOMStringList {
+    method public boolean contains(String);
+    method public int getLength();
+    method public String item(int);
   }
 
-  public abstract interface Document implements org.w3c.dom.Node {
-    method public abstract org.w3c.dom.Node adoptNode(org.w3c.dom.Node) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Attr createAttribute(java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Attr createAttributeNS(java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.CDATASection createCDATASection(java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Comment createComment(java.lang.String);
-    method public abstract org.w3c.dom.DocumentFragment createDocumentFragment();
-    method public abstract org.w3c.dom.Element createElement(java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Element createElementNS(java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.EntityReference createEntityReference(java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.ProcessingInstruction createProcessingInstruction(java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Text createTextNode(java.lang.String);
-    method public abstract org.w3c.dom.DocumentType getDoctype();
-    method public abstract org.w3c.dom.Element getDocumentElement();
-    method public abstract java.lang.String getDocumentURI();
-    method public abstract org.w3c.dom.DOMConfiguration getDomConfig();
-    method public abstract org.w3c.dom.Element getElementById(java.lang.String);
-    method public abstract org.w3c.dom.NodeList getElementsByTagName(java.lang.String);
-    method public abstract org.w3c.dom.NodeList getElementsByTagNameNS(java.lang.String, java.lang.String);
-    method public abstract org.w3c.dom.DOMImplementation getImplementation();
-    method public abstract java.lang.String getInputEncoding();
-    method public abstract boolean getStrictErrorChecking();
-    method public abstract java.lang.String getXmlEncoding();
-    method public abstract boolean getXmlStandalone();
-    method public abstract java.lang.String getXmlVersion();
-    method public abstract org.w3c.dom.Node importNode(org.w3c.dom.Node, boolean) throws org.w3c.dom.DOMException;
-    method public abstract void normalizeDocument();
-    method public abstract org.w3c.dom.Node renameNode(org.w3c.dom.Node, java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract void setDocumentURI(java.lang.String);
-    method public abstract void setStrictErrorChecking(boolean);
-    method public abstract void setXmlStandalone(boolean) throws org.w3c.dom.DOMException;
-    method public abstract void setXmlVersion(java.lang.String) throws org.w3c.dom.DOMException;
+  public interface Document extends org.w3c.dom.Node {
+    method public org.w3c.dom.Node adoptNode(org.w3c.dom.Node) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Attr createAttribute(String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Attr createAttributeNS(String, String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.CDATASection createCDATASection(String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Comment createComment(String);
+    method public org.w3c.dom.DocumentFragment createDocumentFragment();
+    method public org.w3c.dom.Element createElement(String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Element createElementNS(String, String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.EntityReference createEntityReference(String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.ProcessingInstruction createProcessingInstruction(String, String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Text createTextNode(String);
+    method public org.w3c.dom.DocumentType getDoctype();
+    method public org.w3c.dom.Element getDocumentElement();
+    method public String getDocumentURI();
+    method public org.w3c.dom.DOMConfiguration getDomConfig();
+    method public org.w3c.dom.Element getElementById(String);
+    method public org.w3c.dom.NodeList getElementsByTagName(String);
+    method public org.w3c.dom.NodeList getElementsByTagNameNS(String, String);
+    method public org.w3c.dom.DOMImplementation getImplementation();
+    method public String getInputEncoding();
+    method public boolean getStrictErrorChecking();
+    method public String getXmlEncoding();
+    method public boolean getXmlStandalone();
+    method public String getXmlVersion();
+    method public org.w3c.dom.Node importNode(org.w3c.dom.Node, boolean) throws org.w3c.dom.DOMException;
+    method public void normalizeDocument();
+    method public org.w3c.dom.Node renameNode(org.w3c.dom.Node, String, String) throws org.w3c.dom.DOMException;
+    method public void setDocumentURI(String);
+    method public void setStrictErrorChecking(boolean);
+    method public void setXmlStandalone(boolean) throws org.w3c.dom.DOMException;
+    method public void setXmlVersion(String) throws org.w3c.dom.DOMException;
   }
 
-  public abstract interface DocumentFragment implements org.w3c.dom.Node {
+  public interface DocumentFragment extends org.w3c.dom.Node {
   }
 
-  public abstract interface DocumentType implements org.w3c.dom.Node {
-    method public abstract org.w3c.dom.NamedNodeMap getEntities();
-    method public abstract java.lang.String getInternalSubset();
-    method public abstract java.lang.String getName();
-    method public abstract org.w3c.dom.NamedNodeMap getNotations();
-    method public abstract java.lang.String getPublicId();
-    method public abstract java.lang.String getSystemId();
+  public interface DocumentType extends org.w3c.dom.Node {
+    method public org.w3c.dom.NamedNodeMap getEntities();
+    method public String getInternalSubset();
+    method public String getName();
+    method public org.w3c.dom.NamedNodeMap getNotations();
+    method public String getPublicId();
+    method public String getSystemId();
   }
 
-  public abstract interface Element implements org.w3c.dom.Node {
-    method public abstract java.lang.String getAttribute(java.lang.String);
-    method public abstract java.lang.String getAttributeNS(java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Attr getAttributeNode(java.lang.String);
-    method public abstract org.w3c.dom.Attr getAttributeNodeNS(java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.NodeList getElementsByTagName(java.lang.String);
-    method public abstract org.w3c.dom.NodeList getElementsByTagNameNS(java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.TypeInfo getSchemaTypeInfo();
-    method public abstract java.lang.String getTagName();
-    method public abstract boolean hasAttribute(java.lang.String);
-    method public abstract boolean hasAttributeNS(java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract void removeAttribute(java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract void removeAttributeNS(java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Attr removeAttributeNode(org.w3c.dom.Attr) throws org.w3c.dom.DOMException;
-    method public abstract void setAttribute(java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract void setAttributeNS(java.lang.String, java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Attr setAttributeNode(org.w3c.dom.Attr) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Attr setAttributeNodeNS(org.w3c.dom.Attr) throws org.w3c.dom.DOMException;
-    method public abstract void setIdAttribute(java.lang.String, boolean) throws org.w3c.dom.DOMException;
-    method public abstract void setIdAttributeNS(java.lang.String, java.lang.String, boolean) throws org.w3c.dom.DOMException;
-    method public abstract void setIdAttributeNode(org.w3c.dom.Attr, boolean) throws org.w3c.dom.DOMException;
+  public interface Element extends org.w3c.dom.Node {
+    method public String getAttribute(String);
+    method public String getAttributeNS(String, String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Attr getAttributeNode(String);
+    method public org.w3c.dom.Attr getAttributeNodeNS(String, String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.NodeList getElementsByTagName(String);
+    method public org.w3c.dom.NodeList getElementsByTagNameNS(String, String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.TypeInfo getSchemaTypeInfo();
+    method public String getTagName();
+    method public boolean hasAttribute(String);
+    method public boolean hasAttributeNS(String, String) throws org.w3c.dom.DOMException;
+    method public void removeAttribute(String) throws org.w3c.dom.DOMException;
+    method public void removeAttributeNS(String, String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Attr removeAttributeNode(org.w3c.dom.Attr) throws org.w3c.dom.DOMException;
+    method public void setAttribute(String, String) throws org.w3c.dom.DOMException;
+    method public void setAttributeNS(String, String, String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Attr setAttributeNode(org.w3c.dom.Attr) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Attr setAttributeNodeNS(org.w3c.dom.Attr) throws org.w3c.dom.DOMException;
+    method public void setIdAttribute(String, boolean) throws org.w3c.dom.DOMException;
+    method public void setIdAttributeNS(String, String, boolean) throws org.w3c.dom.DOMException;
+    method public void setIdAttributeNode(org.w3c.dom.Attr, boolean) throws org.w3c.dom.DOMException;
   }
 
-  public abstract interface Entity implements org.w3c.dom.Node {
-    method public abstract java.lang.String getInputEncoding();
-    method public abstract java.lang.String getNotationName();
-    method public abstract java.lang.String getPublicId();
-    method public abstract java.lang.String getSystemId();
-    method public abstract java.lang.String getXmlEncoding();
-    method public abstract java.lang.String getXmlVersion();
+  public interface Entity extends org.w3c.dom.Node {
+    method public String getInputEncoding();
+    method public String getNotationName();
+    method public String getPublicId();
+    method public String getSystemId();
+    method public String getXmlEncoding();
+    method public String getXmlVersion();
   }
 
-  public abstract interface EntityReference implements org.w3c.dom.Node {
+  public interface EntityReference extends org.w3c.dom.Node {
   }
 
-  public abstract interface NameList {
-    method public abstract boolean contains(java.lang.String);
-    method public abstract boolean containsNS(java.lang.String, java.lang.String);
-    method public abstract int getLength();
-    method public abstract java.lang.String getName(int);
-    method public abstract java.lang.String getNamespaceURI(int);
+  public interface NameList {
+    method public boolean contains(String);
+    method public boolean containsNS(String, String);
+    method public int getLength();
+    method public String getName(int);
+    method public String getNamespaceURI(int);
   }
 
-  public abstract interface NamedNodeMap {
-    method public abstract int getLength();
-    method public abstract org.w3c.dom.Node getNamedItem(java.lang.String);
-    method public abstract org.w3c.dom.Node getNamedItemNS(java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Node item(int);
-    method public abstract org.w3c.dom.Node removeNamedItem(java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Node removeNamedItemNS(java.lang.String, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Node setNamedItem(org.w3c.dom.Node) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Node setNamedItemNS(org.w3c.dom.Node) throws org.w3c.dom.DOMException;
+  public interface NamedNodeMap {
+    method public int getLength();
+    method public org.w3c.dom.Node getNamedItem(String);
+    method public org.w3c.dom.Node getNamedItemNS(String, String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Node item(int);
+    method public org.w3c.dom.Node removeNamedItem(String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Node removeNamedItemNS(String, String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Node setNamedItem(org.w3c.dom.Node) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Node setNamedItemNS(org.w3c.dom.Node) throws org.w3c.dom.DOMException;
   }
 
-  public abstract interface Node {
-    method public abstract org.w3c.dom.Node appendChild(org.w3c.dom.Node) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Node cloneNode(boolean);
-    method public abstract short compareDocumentPosition(org.w3c.dom.Node) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.NamedNodeMap getAttributes();
-    method public abstract java.lang.String getBaseURI();
-    method public abstract org.w3c.dom.NodeList getChildNodes();
-    method public abstract java.lang.Object getFeature(java.lang.String, java.lang.String);
-    method public abstract org.w3c.dom.Node getFirstChild();
-    method public abstract org.w3c.dom.Node getLastChild();
-    method public abstract java.lang.String getLocalName();
-    method public abstract java.lang.String getNamespaceURI();
-    method public abstract org.w3c.dom.Node getNextSibling();
-    method public abstract java.lang.String getNodeName();
-    method public abstract short getNodeType();
-    method public abstract java.lang.String getNodeValue() throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Document getOwnerDocument();
-    method public abstract org.w3c.dom.Node getParentNode();
-    method public abstract java.lang.String getPrefix();
-    method public abstract org.w3c.dom.Node getPreviousSibling();
-    method public abstract java.lang.String getTextContent() throws org.w3c.dom.DOMException;
-    method public abstract java.lang.Object getUserData(java.lang.String);
-    method public abstract boolean hasAttributes();
-    method public abstract boolean hasChildNodes();
-    method public abstract org.w3c.dom.Node insertBefore(org.w3c.dom.Node, org.w3c.dom.Node) throws org.w3c.dom.DOMException;
-    method public abstract boolean isDefaultNamespace(java.lang.String);
-    method public abstract boolean isEqualNode(org.w3c.dom.Node);
-    method public abstract boolean isSameNode(org.w3c.dom.Node);
-    method public abstract boolean isSupported(java.lang.String, java.lang.String);
-    method public abstract java.lang.String lookupNamespaceURI(java.lang.String);
-    method public abstract java.lang.String lookupPrefix(java.lang.String);
-    method public abstract void normalize();
-    method public abstract org.w3c.dom.Node removeChild(org.w3c.dom.Node) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Node replaceChild(org.w3c.dom.Node, org.w3c.dom.Node) throws org.w3c.dom.DOMException;
-    method public abstract void setNodeValue(java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract void setPrefix(java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract void setTextContent(java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract java.lang.Object setUserData(java.lang.String, java.lang.Object, org.w3c.dom.UserDataHandler);
+  public interface Node {
+    method public org.w3c.dom.Node appendChild(org.w3c.dom.Node) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Node cloneNode(boolean);
+    method public short compareDocumentPosition(org.w3c.dom.Node) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.NamedNodeMap getAttributes();
+    method public String getBaseURI();
+    method public org.w3c.dom.NodeList getChildNodes();
+    method public Object getFeature(String, String);
+    method public org.w3c.dom.Node getFirstChild();
+    method public org.w3c.dom.Node getLastChild();
+    method public String getLocalName();
+    method public String getNamespaceURI();
+    method public org.w3c.dom.Node getNextSibling();
+    method public String getNodeName();
+    method public short getNodeType();
+    method public String getNodeValue() throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Document getOwnerDocument();
+    method public org.w3c.dom.Node getParentNode();
+    method public String getPrefix();
+    method public org.w3c.dom.Node getPreviousSibling();
+    method public String getTextContent() throws org.w3c.dom.DOMException;
+    method public Object getUserData(String);
+    method public boolean hasAttributes();
+    method public boolean hasChildNodes();
+    method public org.w3c.dom.Node insertBefore(org.w3c.dom.Node, org.w3c.dom.Node) throws org.w3c.dom.DOMException;
+    method public boolean isDefaultNamespace(String);
+    method public boolean isEqualNode(org.w3c.dom.Node);
+    method public boolean isSameNode(org.w3c.dom.Node);
+    method public boolean isSupported(String, String);
+    method public String lookupNamespaceURI(String);
+    method public String lookupPrefix(String);
+    method public void normalize();
+    method public org.w3c.dom.Node removeChild(org.w3c.dom.Node) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Node replaceChild(org.w3c.dom.Node, org.w3c.dom.Node) throws org.w3c.dom.DOMException;
+    method public void setNodeValue(String) throws org.w3c.dom.DOMException;
+    method public void setPrefix(String) throws org.w3c.dom.DOMException;
+    method public void setTextContent(String) throws org.w3c.dom.DOMException;
+    method public Object setUserData(String, Object, org.w3c.dom.UserDataHandler);
     field public static final short ATTRIBUTE_NODE = 2; // 0x2
     field public static final short CDATA_SECTION_NODE = 4; // 0x4
     field public static final short COMMENT_NODE = 8; // 0x8
@@ -76866,41 +77152,41 @@
     field public static final short TEXT_NODE = 3; // 0x3
   }
 
-  public abstract interface NodeList {
-    method public abstract int getLength();
-    method public abstract org.w3c.dom.Node item(int);
+  public interface NodeList {
+    method public int getLength();
+    method public org.w3c.dom.Node item(int);
   }
 
-  public abstract interface Notation implements org.w3c.dom.Node {
-    method public abstract java.lang.String getPublicId();
-    method public abstract java.lang.String getSystemId();
+  public interface Notation extends org.w3c.dom.Node {
+    method public String getPublicId();
+    method public String getSystemId();
   }
 
-  public abstract interface ProcessingInstruction implements org.w3c.dom.Node {
-    method public abstract java.lang.String getData();
-    method public abstract java.lang.String getTarget();
-    method public abstract void setData(java.lang.String) throws org.w3c.dom.DOMException;
+  public interface ProcessingInstruction extends org.w3c.dom.Node {
+    method public String getData();
+    method public String getTarget();
+    method public void setData(String) throws org.w3c.dom.DOMException;
   }
 
-  public abstract interface Text implements org.w3c.dom.CharacterData {
-    method public abstract java.lang.String getWholeText();
-    method public abstract boolean isElementContentWhitespace();
-    method public abstract org.w3c.dom.Text replaceWholeText(java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.Text splitText(int) throws org.w3c.dom.DOMException;
+  public interface Text extends org.w3c.dom.CharacterData {
+    method public String getWholeText();
+    method public boolean isElementContentWhitespace();
+    method public org.w3c.dom.Text replaceWholeText(String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.Text splitText(int) throws org.w3c.dom.DOMException;
   }
 
-  public abstract interface TypeInfo {
-    method public abstract java.lang.String getTypeName();
-    method public abstract java.lang.String getTypeNamespace();
-    method public abstract boolean isDerivedFrom(java.lang.String, java.lang.String, int);
+  public interface TypeInfo {
+    method public String getTypeName();
+    method public String getTypeNamespace();
+    method public boolean isDerivedFrom(String, String, int);
     field public static final int DERIVATION_EXTENSION = 2; // 0x2
     field public static final int DERIVATION_LIST = 8; // 0x8
     field public static final int DERIVATION_RESTRICTION = 1; // 0x1
     field public static final int DERIVATION_UNION = 4; // 0x4
   }
 
-  public abstract interface UserDataHandler {
-    method public abstract void handle(short, java.lang.String, java.lang.Object, org.w3c.dom.Node, org.w3c.dom.Node);
+  public interface UserDataHandler {
+    method public void handle(short, String, Object, org.w3c.dom.Node, org.w3c.dom.Node);
     field public static final short NODE_ADOPTED = 5; // 0x5
     field public static final short NODE_CLONED = 1; // 0x1
     field public static final short NODE_DELETED = 3; // 0x3
@@ -76912,62 +77198,62 @@
 
 package org.w3c.dom.ls {
 
-  public abstract interface DOMImplementationLS {
-    method public abstract org.w3c.dom.ls.LSInput createLSInput();
-    method public abstract org.w3c.dom.ls.LSOutput createLSOutput();
-    method public abstract org.w3c.dom.ls.LSParser createLSParser(short, java.lang.String) throws org.w3c.dom.DOMException;
-    method public abstract org.w3c.dom.ls.LSSerializer createLSSerializer();
+  public interface DOMImplementationLS {
+    method public org.w3c.dom.ls.LSInput createLSInput();
+    method public org.w3c.dom.ls.LSOutput createLSOutput();
+    method public org.w3c.dom.ls.LSParser createLSParser(short, String) throws org.w3c.dom.DOMException;
+    method public org.w3c.dom.ls.LSSerializer createLSSerializer();
     field public static final short MODE_ASYNCHRONOUS = 2; // 0x2
     field public static final short MODE_SYNCHRONOUS = 1; // 0x1
   }
 
   public class LSException extends java.lang.RuntimeException {
-    ctor public LSException(short, java.lang.String);
+    ctor public LSException(short, String);
     field public static final short PARSE_ERR = 81; // 0x51
     field public static final short SERIALIZE_ERR = 82; // 0x52
     field public short code;
   }
 
-  public abstract interface LSInput {
-    method public abstract java.lang.String getBaseURI();
-    method public abstract java.io.InputStream getByteStream();
-    method public abstract boolean getCertifiedText();
-    method public abstract java.io.Reader getCharacterStream();
-    method public abstract java.lang.String getEncoding();
-    method public abstract java.lang.String getPublicId();
-    method public abstract java.lang.String getStringData();
-    method public abstract java.lang.String getSystemId();
-    method public abstract void setBaseURI(java.lang.String);
-    method public abstract void setByteStream(java.io.InputStream);
-    method public abstract void setCertifiedText(boolean);
-    method public abstract void setCharacterStream(java.io.Reader);
-    method public abstract void setEncoding(java.lang.String);
-    method public abstract void setPublicId(java.lang.String);
-    method public abstract void setStringData(java.lang.String);
-    method public abstract void setSystemId(java.lang.String);
+  public interface LSInput {
+    method public String getBaseURI();
+    method public java.io.InputStream getByteStream();
+    method public boolean getCertifiedText();
+    method public java.io.Reader getCharacterStream();
+    method public String getEncoding();
+    method public String getPublicId();
+    method public String getStringData();
+    method public String getSystemId();
+    method public void setBaseURI(String);
+    method public void setByteStream(java.io.InputStream);
+    method public void setCertifiedText(boolean);
+    method public void setCharacterStream(java.io.Reader);
+    method public void setEncoding(String);
+    method public void setPublicId(String);
+    method public void setStringData(String);
+    method public void setSystemId(String);
   }
 
-  public abstract interface LSOutput {
-    method public abstract java.io.OutputStream getByteStream();
-    method public abstract java.io.Writer getCharacterStream();
-    method public abstract java.lang.String getEncoding();
-    method public abstract java.lang.String getSystemId();
-    method public abstract void setByteStream(java.io.OutputStream);
-    method public abstract void setCharacterStream(java.io.Writer);
-    method public abstract void setEncoding(java.lang.String);
-    method public abstract void setSystemId(java.lang.String);
+  public interface LSOutput {
+    method public java.io.OutputStream getByteStream();
+    method public java.io.Writer getCharacterStream();
+    method public String getEncoding();
+    method public String getSystemId();
+    method public void setByteStream(java.io.OutputStream);
+    method public void setCharacterStream(java.io.Writer);
+    method public void setEncoding(String);
+    method public void setSystemId(String);
   }
 
-  public abstract interface LSParser {
-    method public abstract void abort();
-    method public abstract boolean getAsync();
-    method public abstract boolean getBusy();
-    method public abstract org.w3c.dom.DOMConfiguration getDomConfig();
-    method public abstract org.w3c.dom.ls.LSParserFilter getFilter();
-    method public abstract org.w3c.dom.Document parse(org.w3c.dom.ls.LSInput) throws org.w3c.dom.DOMException, org.w3c.dom.ls.LSException;
-    method public abstract org.w3c.dom.Document parseURI(java.lang.String) throws org.w3c.dom.DOMException, org.w3c.dom.ls.LSException;
-    method public abstract org.w3c.dom.Node parseWithContext(org.w3c.dom.ls.LSInput, org.w3c.dom.Node, short) throws org.w3c.dom.DOMException, org.w3c.dom.ls.LSException;
-    method public abstract void setFilter(org.w3c.dom.ls.LSParserFilter);
+  public interface LSParser {
+    method public void abort();
+    method public boolean getAsync();
+    method public boolean getBusy();
+    method public org.w3c.dom.DOMConfiguration getDomConfig();
+    method public org.w3c.dom.ls.LSParserFilter getFilter();
+    method public org.w3c.dom.Document parse(org.w3c.dom.ls.LSInput) throws org.w3c.dom.DOMException, org.w3c.dom.ls.LSException;
+    method public org.w3c.dom.Document parseURI(String) throws org.w3c.dom.DOMException, org.w3c.dom.ls.LSException;
+    method public org.w3c.dom.Node parseWithContext(org.w3c.dom.ls.LSInput, org.w3c.dom.Node, short) throws org.w3c.dom.DOMException, org.w3c.dom.ls.LSException;
+    method public void setFilter(org.w3c.dom.ls.LSParserFilter);
     field public static final short ACTION_APPEND_AS_CHILDREN = 1; // 0x1
     field public static final short ACTION_INSERT_AFTER = 4; // 0x4
     field public static final short ACTION_INSERT_BEFORE = 3; // 0x3
@@ -76975,343 +77261,343 @@
     field public static final short ACTION_REPLACE_CHILDREN = 2; // 0x2
   }
 
-  public abstract interface LSParserFilter {
-    method public abstract short acceptNode(org.w3c.dom.Node);
-    method public abstract int getWhatToShow();
-    method public abstract short startElement(org.w3c.dom.Element);
+  public interface LSParserFilter {
+    method public short acceptNode(org.w3c.dom.Node);
+    method public int getWhatToShow();
+    method public short startElement(org.w3c.dom.Element);
     field public static final short FILTER_ACCEPT = 1; // 0x1
     field public static final short FILTER_INTERRUPT = 4; // 0x4
     field public static final short FILTER_REJECT = 2; // 0x2
     field public static final short FILTER_SKIP = 3; // 0x3
   }
 
-  public abstract interface LSResourceResolver {
-    method public abstract org.w3c.dom.ls.LSInput resolveResource(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+  public interface LSResourceResolver {
+    method public org.w3c.dom.ls.LSInput resolveResource(String, String, String, String, String);
   }
 
-  public abstract interface LSSerializer {
-    method public abstract org.w3c.dom.DOMConfiguration getDomConfig();
-    method public abstract java.lang.String getNewLine();
-    method public abstract void setNewLine(java.lang.String);
-    method public abstract boolean write(org.w3c.dom.Node, org.w3c.dom.ls.LSOutput) throws org.w3c.dom.ls.LSException;
-    method public abstract java.lang.String writeToString(org.w3c.dom.Node) throws org.w3c.dom.DOMException, org.w3c.dom.ls.LSException;
-    method public abstract boolean writeToURI(org.w3c.dom.Node, java.lang.String) throws org.w3c.dom.ls.LSException;
+  public interface LSSerializer {
+    method public org.w3c.dom.DOMConfiguration getDomConfig();
+    method public String getNewLine();
+    method public void setNewLine(String);
+    method public boolean write(org.w3c.dom.Node, org.w3c.dom.ls.LSOutput) throws org.w3c.dom.ls.LSException;
+    method public String writeToString(org.w3c.dom.Node) throws org.w3c.dom.DOMException, org.w3c.dom.ls.LSException;
+    method public boolean writeToURI(org.w3c.dom.Node, String) throws org.w3c.dom.ls.LSException;
   }
 
 }
 
 package org.xml.sax {
 
-  public abstract deprecated interface AttributeList {
-    method public abstract int getLength();
-    method public abstract java.lang.String getName(int);
-    method public abstract java.lang.String getType(int);
-    method public abstract java.lang.String getType(java.lang.String);
-    method public abstract java.lang.String getValue(int);
-    method public abstract java.lang.String getValue(java.lang.String);
+  @Deprecated public interface AttributeList {
+    method @Deprecated public int getLength();
+    method @Deprecated public String getName(int);
+    method @Deprecated public String getType(int);
+    method @Deprecated public String getType(String);
+    method @Deprecated public String getValue(int);
+    method @Deprecated public String getValue(String);
   }
 
-  public abstract interface Attributes {
-    method public abstract int getIndex(java.lang.String, java.lang.String);
-    method public abstract int getIndex(java.lang.String);
-    method public abstract int getLength();
-    method public abstract java.lang.String getLocalName(int);
-    method public abstract java.lang.String getQName(int);
-    method public abstract java.lang.String getType(int);
-    method public abstract java.lang.String getType(java.lang.String, java.lang.String);
-    method public abstract java.lang.String getType(java.lang.String);
-    method public abstract java.lang.String getURI(int);
-    method public abstract java.lang.String getValue(int);
-    method public abstract java.lang.String getValue(java.lang.String, java.lang.String);
-    method public abstract java.lang.String getValue(java.lang.String);
+  public interface Attributes {
+    method public int getIndex(String, String);
+    method public int getIndex(String);
+    method public int getLength();
+    method public String getLocalName(int);
+    method public String getQName(int);
+    method public String getType(int);
+    method public String getType(String, String);
+    method public String getType(String);
+    method public String getURI(int);
+    method public String getValue(int);
+    method public String getValue(String, String);
+    method public String getValue(String);
   }
 
-  public abstract interface ContentHandler {
-    method public abstract void characters(char[], int, int) throws org.xml.sax.SAXException;
-    method public abstract void endDocument() throws org.xml.sax.SAXException;
-    method public abstract void endElement(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public abstract void endPrefixMapping(java.lang.String) throws org.xml.sax.SAXException;
-    method public abstract void ignorableWhitespace(char[], int, int) throws org.xml.sax.SAXException;
-    method public abstract void processingInstruction(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public abstract void setDocumentLocator(org.xml.sax.Locator);
-    method public abstract void skippedEntity(java.lang.String) throws org.xml.sax.SAXException;
-    method public abstract void startDocument() throws org.xml.sax.SAXException;
-    method public abstract void startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) throws org.xml.sax.SAXException;
-    method public abstract void startPrefixMapping(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-  }
-
-  public abstract interface DTDHandler {
-    method public abstract void notationDecl(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public abstract void unparsedEntityDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-  }
-
-  public abstract deprecated interface DocumentHandler {
-    method public abstract void characters(char[], int, int) throws org.xml.sax.SAXException;
-    method public abstract void endDocument() throws org.xml.sax.SAXException;
-    method public abstract void endElement(java.lang.String) throws org.xml.sax.SAXException;
-    method public abstract void ignorableWhitespace(char[], int, int) throws org.xml.sax.SAXException;
-    method public abstract void processingInstruction(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public abstract void setDocumentLocator(org.xml.sax.Locator);
-    method public abstract void startDocument() throws org.xml.sax.SAXException;
-    method public abstract void startElement(java.lang.String, org.xml.sax.AttributeList) throws org.xml.sax.SAXException;
-  }
-
-  public abstract interface EntityResolver {
-    method public abstract org.xml.sax.InputSource resolveEntity(java.lang.String, java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
-  }
-
-  public abstract interface ErrorHandler {
-    method public abstract void error(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
-    method public abstract void fatalError(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
-    method public abstract void warning(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
-  }
-
-  public deprecated class HandlerBase implements org.xml.sax.DTDHandler org.xml.sax.DocumentHandler org.xml.sax.EntityResolver org.xml.sax.ErrorHandler {
-    ctor public HandlerBase();
+  public interface ContentHandler {
     method public void characters(char[], int, int) throws org.xml.sax.SAXException;
     method public void endDocument() throws org.xml.sax.SAXException;
-    method public void endElement(java.lang.String) throws org.xml.sax.SAXException;
+    method public void endElement(String, String, String) throws org.xml.sax.SAXException;
+    method public void endPrefixMapping(String) throws org.xml.sax.SAXException;
+    method public void ignorableWhitespace(char[], int, int) throws org.xml.sax.SAXException;
+    method public void processingInstruction(String, String) throws org.xml.sax.SAXException;
+    method public void setDocumentLocator(org.xml.sax.Locator);
+    method public void skippedEntity(String) throws org.xml.sax.SAXException;
+    method public void startDocument() throws org.xml.sax.SAXException;
+    method public void startElement(String, String, String, org.xml.sax.Attributes) throws org.xml.sax.SAXException;
+    method public void startPrefixMapping(String, String) throws org.xml.sax.SAXException;
+  }
+
+  public interface DTDHandler {
+    method public void notationDecl(String, String, String) throws org.xml.sax.SAXException;
+    method public void unparsedEntityDecl(String, String, String, String) throws org.xml.sax.SAXException;
+  }
+
+  @Deprecated public interface DocumentHandler {
+    method @Deprecated public void characters(char[], int, int) throws org.xml.sax.SAXException;
+    method @Deprecated public void endDocument() throws org.xml.sax.SAXException;
+    method @Deprecated public void endElement(String) throws org.xml.sax.SAXException;
+    method @Deprecated public void ignorableWhitespace(char[], int, int) throws org.xml.sax.SAXException;
+    method @Deprecated public void processingInstruction(String, String) throws org.xml.sax.SAXException;
+    method @Deprecated public void setDocumentLocator(org.xml.sax.Locator);
+    method @Deprecated public void startDocument() throws org.xml.sax.SAXException;
+    method @Deprecated public void startElement(String, org.xml.sax.AttributeList) throws org.xml.sax.SAXException;
+  }
+
+  public interface EntityResolver {
+    method public org.xml.sax.InputSource resolveEntity(String, String) throws java.io.IOException, org.xml.sax.SAXException;
+  }
+
+  public interface ErrorHandler {
     method public void error(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
     method public void fatalError(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
-    method public void ignorableWhitespace(char[], int, int) throws org.xml.sax.SAXException;
-    method public void notationDecl(java.lang.String, java.lang.String, java.lang.String);
-    method public void processingInstruction(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public org.xml.sax.InputSource resolveEntity(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public void setDocumentLocator(org.xml.sax.Locator);
-    method public void startDocument() throws org.xml.sax.SAXException;
-    method public void startElement(java.lang.String, org.xml.sax.AttributeList) throws org.xml.sax.SAXException;
-    method public void unparsedEntityDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
     method public void warning(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
   }
 
+  @Deprecated public class HandlerBase implements org.xml.sax.DTDHandler org.xml.sax.DocumentHandler org.xml.sax.EntityResolver org.xml.sax.ErrorHandler {
+    ctor @Deprecated public HandlerBase();
+    method @Deprecated public void characters(char[], int, int) throws org.xml.sax.SAXException;
+    method @Deprecated public void endDocument() throws org.xml.sax.SAXException;
+    method @Deprecated public void endElement(String) throws org.xml.sax.SAXException;
+    method @Deprecated public void error(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
+    method @Deprecated public void fatalError(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
+    method @Deprecated public void ignorableWhitespace(char[], int, int) throws org.xml.sax.SAXException;
+    method @Deprecated public void notationDecl(String, String, String);
+    method @Deprecated public void processingInstruction(String, String) throws org.xml.sax.SAXException;
+    method @Deprecated public org.xml.sax.InputSource resolveEntity(String, String) throws org.xml.sax.SAXException;
+    method @Deprecated public void setDocumentLocator(org.xml.sax.Locator);
+    method @Deprecated public void startDocument() throws org.xml.sax.SAXException;
+    method @Deprecated public void startElement(String, org.xml.sax.AttributeList) throws org.xml.sax.SAXException;
+    method @Deprecated public void unparsedEntityDecl(String, String, String, String);
+    method @Deprecated public void warning(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
+  }
+
   public class InputSource {
     ctor public InputSource();
-    ctor public InputSource(java.lang.String);
+    ctor public InputSource(String);
     ctor public InputSource(java.io.InputStream);
     ctor public InputSource(java.io.Reader);
     method public java.io.InputStream getByteStream();
     method public java.io.Reader getCharacterStream();
-    method public java.lang.String getEncoding();
-    method public java.lang.String getPublicId();
-    method public java.lang.String getSystemId();
+    method public String getEncoding();
+    method public String getPublicId();
+    method public String getSystemId();
     method public void setByteStream(java.io.InputStream);
     method public void setCharacterStream(java.io.Reader);
-    method public void setEncoding(java.lang.String);
-    method public void setPublicId(java.lang.String);
-    method public void setSystemId(java.lang.String);
+    method public void setEncoding(String);
+    method public void setPublicId(String);
+    method public void setSystemId(String);
   }
 
-  public abstract interface Locator {
-    method public abstract int getColumnNumber();
-    method public abstract int getLineNumber();
-    method public abstract java.lang.String getPublicId();
-    method public abstract java.lang.String getSystemId();
+  public interface Locator {
+    method public int getColumnNumber();
+    method public int getLineNumber();
+    method public String getPublicId();
+    method public String getSystemId();
   }
 
-  public abstract deprecated interface Parser {
-    method public abstract void parse(org.xml.sax.InputSource) throws java.io.IOException, org.xml.sax.SAXException;
-    method public abstract void parse(java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
-    method public abstract void setDTDHandler(org.xml.sax.DTDHandler);
-    method public abstract void setDocumentHandler(org.xml.sax.DocumentHandler);
-    method public abstract void setEntityResolver(org.xml.sax.EntityResolver);
-    method public abstract void setErrorHandler(org.xml.sax.ErrorHandler);
-    method public abstract void setLocale(java.util.Locale) throws org.xml.sax.SAXException;
+  @Deprecated public interface Parser {
+    method @Deprecated public void parse(org.xml.sax.InputSource) throws java.io.IOException, org.xml.sax.SAXException;
+    method @Deprecated public void parse(String) throws java.io.IOException, org.xml.sax.SAXException;
+    method @Deprecated public void setDTDHandler(org.xml.sax.DTDHandler);
+    method @Deprecated public void setDocumentHandler(org.xml.sax.DocumentHandler);
+    method @Deprecated public void setEntityResolver(org.xml.sax.EntityResolver);
+    method @Deprecated public void setErrorHandler(org.xml.sax.ErrorHandler);
+    method @Deprecated public void setLocale(java.util.Locale) throws org.xml.sax.SAXException;
   }
 
   public class SAXException extends java.lang.Exception {
     ctor public SAXException();
-    ctor public SAXException(java.lang.String);
-    ctor public SAXException(java.lang.Exception);
-    ctor public SAXException(java.lang.String, java.lang.Exception);
-    method public java.lang.Exception getException();
+    ctor public SAXException(String);
+    ctor public SAXException(Exception);
+    ctor public SAXException(String, Exception);
+    method public Exception getException();
   }
 
   public class SAXNotRecognizedException extends org.xml.sax.SAXException {
     ctor public SAXNotRecognizedException();
-    ctor public SAXNotRecognizedException(java.lang.String);
+    ctor public SAXNotRecognizedException(String);
   }
 
   public class SAXNotSupportedException extends org.xml.sax.SAXException {
     ctor public SAXNotSupportedException();
-    ctor public SAXNotSupportedException(java.lang.String);
+    ctor public SAXNotSupportedException(String);
   }
 
   public class SAXParseException extends org.xml.sax.SAXException {
-    ctor public SAXParseException(java.lang.String, org.xml.sax.Locator);
-    ctor public SAXParseException(java.lang.String, org.xml.sax.Locator, java.lang.Exception);
-    ctor public SAXParseException(java.lang.String, java.lang.String, java.lang.String, int, int);
-    ctor public SAXParseException(java.lang.String, java.lang.String, java.lang.String, int, int, java.lang.Exception);
+    ctor public SAXParseException(String, org.xml.sax.Locator);
+    ctor public SAXParseException(String, org.xml.sax.Locator, Exception);
+    ctor public SAXParseException(String, String, String, int, int);
+    ctor public SAXParseException(String, String, String, int, int, Exception);
     method public int getColumnNumber();
     method public int getLineNumber();
-    method public java.lang.String getPublicId();
-    method public java.lang.String getSystemId();
+    method public String getPublicId();
+    method public String getSystemId();
   }
 
-  public abstract interface XMLFilter implements org.xml.sax.XMLReader {
-    method public abstract org.xml.sax.XMLReader getParent();
-    method public abstract void setParent(org.xml.sax.XMLReader);
+  public interface XMLFilter extends org.xml.sax.XMLReader {
+    method public org.xml.sax.XMLReader getParent();
+    method public void setParent(org.xml.sax.XMLReader);
   }
 
-  public abstract interface XMLReader {
-    method public abstract org.xml.sax.ContentHandler getContentHandler();
-    method public abstract org.xml.sax.DTDHandler getDTDHandler();
-    method public abstract org.xml.sax.EntityResolver getEntityResolver();
-    method public abstract org.xml.sax.ErrorHandler getErrorHandler();
-    method public abstract boolean getFeature(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public abstract java.lang.Object getProperty(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public abstract void parse(org.xml.sax.InputSource) throws java.io.IOException, org.xml.sax.SAXException;
-    method public abstract void parse(java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
-    method public abstract void setContentHandler(org.xml.sax.ContentHandler);
-    method public abstract void setDTDHandler(org.xml.sax.DTDHandler);
-    method public abstract void setEntityResolver(org.xml.sax.EntityResolver);
-    method public abstract void setErrorHandler(org.xml.sax.ErrorHandler);
-    method public abstract void setFeature(java.lang.String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public abstract void setProperty(java.lang.String, java.lang.Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+  public interface XMLReader {
+    method public org.xml.sax.ContentHandler getContentHandler();
+    method public org.xml.sax.DTDHandler getDTDHandler();
+    method public org.xml.sax.EntityResolver getEntityResolver();
+    method public org.xml.sax.ErrorHandler getErrorHandler();
+    method public boolean getFeature(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public Object getProperty(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public void parse(org.xml.sax.InputSource) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void parse(String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void setContentHandler(org.xml.sax.ContentHandler);
+    method public void setDTDHandler(org.xml.sax.DTDHandler);
+    method public void setEntityResolver(org.xml.sax.EntityResolver);
+    method public void setErrorHandler(org.xml.sax.ErrorHandler);
+    method public void setFeature(String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public void setProperty(String, Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
   }
 
 }
 
 package org.xml.sax.ext {
 
-  public abstract interface Attributes2 implements org.xml.sax.Attributes {
-    method public abstract boolean isDeclared(int);
-    method public abstract boolean isDeclared(java.lang.String);
-    method public abstract boolean isDeclared(java.lang.String, java.lang.String);
-    method public abstract boolean isSpecified(int);
-    method public abstract boolean isSpecified(java.lang.String, java.lang.String);
-    method public abstract boolean isSpecified(java.lang.String);
+  public interface Attributes2 extends org.xml.sax.Attributes {
+    method public boolean isDeclared(int);
+    method public boolean isDeclared(String);
+    method public boolean isDeclared(String, String);
+    method public boolean isSpecified(int);
+    method public boolean isSpecified(String, String);
+    method public boolean isSpecified(String);
   }
 
   public class Attributes2Impl extends org.xml.sax.helpers.AttributesImpl implements org.xml.sax.ext.Attributes2 {
     ctor public Attributes2Impl();
     ctor public Attributes2Impl(org.xml.sax.Attributes);
     method public boolean isDeclared(int);
-    method public boolean isDeclared(java.lang.String, java.lang.String);
-    method public boolean isDeclared(java.lang.String);
+    method public boolean isDeclared(String, String);
+    method public boolean isDeclared(String);
     method public boolean isSpecified(int);
-    method public boolean isSpecified(java.lang.String, java.lang.String);
-    method public boolean isSpecified(java.lang.String);
+    method public boolean isSpecified(String, String);
+    method public boolean isSpecified(String);
     method public void setDeclared(int, boolean);
     method public void setSpecified(int, boolean);
   }
 
-  public abstract interface DeclHandler {
-    method public abstract void attributeDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public abstract void elementDecl(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public abstract void externalEntityDecl(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public abstract void internalEntityDecl(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
+  public interface DeclHandler {
+    method public void attributeDecl(String, String, String, String, String) throws org.xml.sax.SAXException;
+    method public void elementDecl(String, String) throws org.xml.sax.SAXException;
+    method public void externalEntityDecl(String, String, String) throws org.xml.sax.SAXException;
+    method public void internalEntityDecl(String, String) throws org.xml.sax.SAXException;
   }
 
   public class DefaultHandler2 extends org.xml.sax.helpers.DefaultHandler implements org.xml.sax.ext.DeclHandler org.xml.sax.ext.EntityResolver2 org.xml.sax.ext.LexicalHandler {
     ctor public DefaultHandler2();
-    method public void attributeDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
+    method public void attributeDecl(String, String, String, String, String) throws org.xml.sax.SAXException;
     method public void comment(char[], int, int) throws org.xml.sax.SAXException;
-    method public void elementDecl(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
+    method public void elementDecl(String, String) throws org.xml.sax.SAXException;
     method public void endCDATA() throws org.xml.sax.SAXException;
     method public void endDTD() throws org.xml.sax.SAXException;
-    method public void endEntity(java.lang.String) throws org.xml.sax.SAXException;
-    method public void externalEntityDecl(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public org.xml.sax.InputSource getExternalSubset(java.lang.String, java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
-    method public void internalEntityDecl(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public org.xml.sax.InputSource resolveEntity(java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void endEntity(String) throws org.xml.sax.SAXException;
+    method public void externalEntityDecl(String, String, String) throws org.xml.sax.SAXException;
+    method public org.xml.sax.InputSource getExternalSubset(String, String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void internalEntityDecl(String, String) throws org.xml.sax.SAXException;
+    method public org.xml.sax.InputSource resolveEntity(String, String, String, String) throws java.io.IOException, org.xml.sax.SAXException;
     method public void startCDATA() throws org.xml.sax.SAXException;
-    method public void startDTD(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public void startEntity(java.lang.String) throws org.xml.sax.SAXException;
+    method public void startDTD(String, String, String) throws org.xml.sax.SAXException;
+    method public void startEntity(String) throws org.xml.sax.SAXException;
   }
 
-  public abstract interface EntityResolver2 implements org.xml.sax.EntityResolver {
-    method public abstract org.xml.sax.InputSource getExternalSubset(java.lang.String, java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
-    method public abstract org.xml.sax.InputSource resolveEntity(java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
+  public interface EntityResolver2 extends org.xml.sax.EntityResolver {
+    method public org.xml.sax.InputSource getExternalSubset(String, String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public org.xml.sax.InputSource resolveEntity(String, String, String, String) throws java.io.IOException, org.xml.sax.SAXException;
   }
 
-  public abstract interface LexicalHandler {
-    method public abstract void comment(char[], int, int) throws org.xml.sax.SAXException;
-    method public abstract void endCDATA() throws org.xml.sax.SAXException;
-    method public abstract void endDTD() throws org.xml.sax.SAXException;
-    method public abstract void endEntity(java.lang.String) throws org.xml.sax.SAXException;
-    method public abstract void startCDATA() throws org.xml.sax.SAXException;
-    method public abstract void startDTD(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public abstract void startEntity(java.lang.String) throws org.xml.sax.SAXException;
+  public interface LexicalHandler {
+    method public void comment(char[], int, int) throws org.xml.sax.SAXException;
+    method public void endCDATA() throws org.xml.sax.SAXException;
+    method public void endDTD() throws org.xml.sax.SAXException;
+    method public void endEntity(String) throws org.xml.sax.SAXException;
+    method public void startCDATA() throws org.xml.sax.SAXException;
+    method public void startDTD(String, String, String) throws org.xml.sax.SAXException;
+    method public void startEntity(String) throws org.xml.sax.SAXException;
   }
 
-  public abstract interface Locator2 implements org.xml.sax.Locator {
-    method public abstract java.lang.String getEncoding();
-    method public abstract java.lang.String getXMLVersion();
+  public interface Locator2 extends org.xml.sax.Locator {
+    method public String getEncoding();
+    method public String getXMLVersion();
   }
 
   public class Locator2Impl extends org.xml.sax.helpers.LocatorImpl implements org.xml.sax.ext.Locator2 {
     ctor public Locator2Impl();
     ctor public Locator2Impl(org.xml.sax.Locator);
-    method public java.lang.String getEncoding();
-    method public java.lang.String getXMLVersion();
-    method public void setEncoding(java.lang.String);
-    method public void setXMLVersion(java.lang.String);
+    method public String getEncoding();
+    method public String getXMLVersion();
+    method public void setEncoding(String);
+    method public void setXMLVersion(String);
   }
 
 }
 
 package org.xml.sax.helpers {
 
-  public deprecated class AttributeListImpl implements org.xml.sax.AttributeList {
-    ctor public AttributeListImpl();
-    ctor public AttributeListImpl(org.xml.sax.AttributeList);
-    method public void addAttribute(java.lang.String, java.lang.String, java.lang.String);
-    method public void clear();
-    method public int getLength();
-    method public java.lang.String getName(int);
-    method public java.lang.String getType(int);
-    method public java.lang.String getType(java.lang.String);
-    method public java.lang.String getValue(int);
-    method public java.lang.String getValue(java.lang.String);
-    method public void removeAttribute(java.lang.String);
-    method public void setAttributeList(org.xml.sax.AttributeList);
+  @Deprecated public class AttributeListImpl implements org.xml.sax.AttributeList {
+    ctor @Deprecated public AttributeListImpl();
+    ctor @Deprecated public AttributeListImpl(org.xml.sax.AttributeList);
+    method @Deprecated public void addAttribute(String, String, String);
+    method @Deprecated public void clear();
+    method @Deprecated public int getLength();
+    method @Deprecated public String getName(int);
+    method @Deprecated public String getType(int);
+    method @Deprecated public String getType(String);
+    method @Deprecated public String getValue(int);
+    method @Deprecated public String getValue(String);
+    method @Deprecated public void removeAttribute(String);
+    method @Deprecated public void setAttributeList(org.xml.sax.AttributeList);
   }
 
   public class AttributesImpl implements org.xml.sax.Attributes {
     ctor public AttributesImpl();
     ctor public AttributesImpl(org.xml.sax.Attributes);
-    method public void addAttribute(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method public void addAttribute(String, String, String, String, String);
     method public void clear();
-    method public int getIndex(java.lang.String, java.lang.String);
-    method public int getIndex(java.lang.String);
+    method public int getIndex(String, String);
+    method public int getIndex(String);
     method public int getLength();
-    method public java.lang.String getLocalName(int);
-    method public java.lang.String getQName(int);
-    method public java.lang.String getType(int);
-    method public java.lang.String getType(java.lang.String, java.lang.String);
-    method public java.lang.String getType(java.lang.String);
-    method public java.lang.String getURI(int);
-    method public java.lang.String getValue(int);
-    method public java.lang.String getValue(java.lang.String, java.lang.String);
-    method public java.lang.String getValue(java.lang.String);
+    method public String getLocalName(int);
+    method public String getQName(int);
+    method public String getType(int);
+    method public String getType(String, String);
+    method public String getType(String);
+    method public String getURI(int);
+    method public String getValue(int);
+    method public String getValue(String, String);
+    method public String getValue(String);
     method public void removeAttribute(int);
-    method public void setAttribute(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method public void setAttribute(int, String, String, String, String, String);
     method public void setAttributes(org.xml.sax.Attributes);
-    method public void setLocalName(int, java.lang.String);
-    method public void setQName(int, java.lang.String);
-    method public void setType(int, java.lang.String);
-    method public void setURI(int, java.lang.String);
-    method public void setValue(int, java.lang.String);
+    method public void setLocalName(int, String);
+    method public void setQName(int, String);
+    method public void setType(int, String);
+    method public void setURI(int, String);
+    method public void setValue(int, String);
   }
 
   public class DefaultHandler implements org.xml.sax.ContentHandler org.xml.sax.DTDHandler org.xml.sax.EntityResolver org.xml.sax.ErrorHandler {
     ctor public DefaultHandler();
     method public void characters(char[], int, int) throws org.xml.sax.SAXException;
     method public void endDocument() throws org.xml.sax.SAXException;
-    method public void endElement(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public void endPrefixMapping(java.lang.String) throws org.xml.sax.SAXException;
+    method public void endElement(String, String, String) throws org.xml.sax.SAXException;
+    method public void endPrefixMapping(String) throws org.xml.sax.SAXException;
     method public void error(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
     method public void fatalError(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
     method public void ignorableWhitespace(char[], int, int) throws org.xml.sax.SAXException;
-    method public void notationDecl(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public void processingInstruction(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public org.xml.sax.InputSource resolveEntity(java.lang.String, java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void notationDecl(String, String, String) throws org.xml.sax.SAXException;
+    method public void processingInstruction(String, String) throws org.xml.sax.SAXException;
+    method public org.xml.sax.InputSource resolveEntity(String, String) throws java.io.IOException, org.xml.sax.SAXException;
     method public void setDocumentLocator(org.xml.sax.Locator);
-    method public void skippedEntity(java.lang.String) throws org.xml.sax.SAXException;
+    method public void skippedEntity(String) throws org.xml.sax.SAXException;
     method public void startDocument() throws org.xml.sax.SAXException;
-    method public void startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) throws org.xml.sax.SAXException;
-    method public void startPrefixMapping(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public void unparsedEntityDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
+    method public void startElement(String, String, String, org.xml.sax.Attributes) throws org.xml.sax.SAXException;
+    method public void startPrefixMapping(String, String) throws org.xml.sax.SAXException;
+    method public void unparsedEntityDecl(String, String, String, String) throws org.xml.sax.SAXException;
     method public void warning(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
   }
 
@@ -77320,30 +77606,30 @@
     ctor public LocatorImpl(org.xml.sax.Locator);
     method public int getColumnNumber();
     method public int getLineNumber();
-    method public java.lang.String getPublicId();
-    method public java.lang.String getSystemId();
+    method public String getPublicId();
+    method public String getSystemId();
     method public void setColumnNumber(int);
     method public void setLineNumber(int);
-    method public void setPublicId(java.lang.String);
-    method public void setSystemId(java.lang.String);
+    method public void setPublicId(String);
+    method public void setSystemId(String);
   }
 
   public class NamespaceSupport {
     ctor public NamespaceSupport();
-    method public boolean declarePrefix(java.lang.String, java.lang.String);
+    method public boolean declarePrefix(String, String);
     method public java.util.Enumeration getDeclaredPrefixes();
-    method public java.lang.String getPrefix(java.lang.String);
+    method public String getPrefix(String);
     method public java.util.Enumeration getPrefixes();
-    method public java.util.Enumeration getPrefixes(java.lang.String);
-    method public java.lang.String getURI(java.lang.String);
+    method public java.util.Enumeration getPrefixes(String);
+    method public String getURI(String);
     method public boolean isNamespaceDeclUris();
     method public void popContext();
-    method public java.lang.String[] processName(java.lang.String, java.lang.String[], boolean);
+    method public String[] processName(String, String[], boolean);
     method public void pushContext();
     method public void reset();
     method public void setNamespaceDeclUris(boolean);
-    field public static final java.lang.String NSDECL = "http://www.w3.org/xmlns/2000/";
-    field public static final java.lang.String XMLNS = "http://www.w3.org/XML/1998/namespace";
+    field public static final String NSDECL = "http://www.w3.org/xmlns/2000/";
+    field public static final String XMLNS = "http://www.w3.org/XML/1998/namespace";
   }
 
   public class ParserAdapter implements org.xml.sax.DocumentHandler org.xml.sax.XMLReader {
@@ -77351,31 +77637,31 @@
     ctor public ParserAdapter(org.xml.sax.Parser);
     method public void characters(char[], int, int) throws org.xml.sax.SAXException;
     method public void endDocument() throws org.xml.sax.SAXException;
-    method public void endElement(java.lang.String) throws org.xml.sax.SAXException;
+    method public void endElement(String) throws org.xml.sax.SAXException;
     method public org.xml.sax.ContentHandler getContentHandler();
     method public org.xml.sax.DTDHandler getDTDHandler();
     method public org.xml.sax.EntityResolver getEntityResolver();
     method public org.xml.sax.ErrorHandler getErrorHandler();
-    method public boolean getFeature(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public java.lang.Object getProperty(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public boolean getFeature(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public Object getProperty(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public void ignorableWhitespace(char[], int, int) throws org.xml.sax.SAXException;
-    method public void parse(java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void parse(String) throws java.io.IOException, org.xml.sax.SAXException;
     method public void parse(org.xml.sax.InputSource) throws java.io.IOException, org.xml.sax.SAXException;
-    method public void processingInstruction(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
+    method public void processingInstruction(String, String) throws org.xml.sax.SAXException;
     method public void setContentHandler(org.xml.sax.ContentHandler);
     method public void setDTDHandler(org.xml.sax.DTDHandler);
     method public void setDocumentLocator(org.xml.sax.Locator);
     method public void setEntityResolver(org.xml.sax.EntityResolver);
     method public void setErrorHandler(org.xml.sax.ErrorHandler);
-    method public void setFeature(java.lang.String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public void setProperty(java.lang.String, java.lang.Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public void setFeature(String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public void setProperty(String, Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public void startDocument() throws org.xml.sax.SAXException;
-    method public void startElement(java.lang.String, org.xml.sax.AttributeList) throws org.xml.sax.SAXException;
+    method public void startElement(String, org.xml.sax.AttributeList) throws org.xml.sax.SAXException;
   }
 
-  public deprecated class ParserFactory {
-    method public static org.xml.sax.Parser makeParser() throws java.lang.ClassCastException, java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.NullPointerException;
-    method public static org.xml.sax.Parser makeParser(java.lang.String) throws java.lang.ClassCastException, java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+  @Deprecated public class ParserFactory {
+    method @Deprecated public static org.xml.sax.Parser makeParser() throws java.lang.ClassCastException, java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.NullPointerException;
+    method @Deprecated public static org.xml.sax.Parser makeParser(String) throws java.lang.ClassCastException, java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
   public class XMLFilterImpl implements org.xml.sax.ContentHandler org.xml.sax.DTDHandler org.xml.sax.EntityResolver org.xml.sax.ErrorHandler org.xml.sax.XMLFilter {
@@ -77383,36 +77669,36 @@
     ctor public XMLFilterImpl(org.xml.sax.XMLReader);
     method public void characters(char[], int, int) throws org.xml.sax.SAXException;
     method public void endDocument() throws org.xml.sax.SAXException;
-    method public void endElement(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public void endPrefixMapping(java.lang.String) throws org.xml.sax.SAXException;
+    method public void endElement(String, String, String) throws org.xml.sax.SAXException;
+    method public void endPrefixMapping(String) throws org.xml.sax.SAXException;
     method public void error(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
     method public void fatalError(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
     method public org.xml.sax.ContentHandler getContentHandler();
     method public org.xml.sax.DTDHandler getDTDHandler();
     method public org.xml.sax.EntityResolver getEntityResolver();
     method public org.xml.sax.ErrorHandler getErrorHandler();
-    method public boolean getFeature(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public boolean getFeature(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public org.xml.sax.XMLReader getParent();
-    method public java.lang.Object getProperty(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public Object getProperty(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public void ignorableWhitespace(char[], int, int) throws org.xml.sax.SAXException;
-    method public void notationDecl(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
+    method public void notationDecl(String, String, String) throws org.xml.sax.SAXException;
     method public void parse(org.xml.sax.InputSource) throws java.io.IOException, org.xml.sax.SAXException;
-    method public void parse(java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
-    method public void processingInstruction(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public org.xml.sax.InputSource resolveEntity(java.lang.String, java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void parse(String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void processingInstruction(String, String) throws org.xml.sax.SAXException;
+    method public org.xml.sax.InputSource resolveEntity(String, String) throws java.io.IOException, org.xml.sax.SAXException;
     method public void setContentHandler(org.xml.sax.ContentHandler);
     method public void setDTDHandler(org.xml.sax.DTDHandler);
     method public void setDocumentLocator(org.xml.sax.Locator);
     method public void setEntityResolver(org.xml.sax.EntityResolver);
     method public void setErrorHandler(org.xml.sax.ErrorHandler);
-    method public void setFeature(java.lang.String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public void setFeature(String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
     method public void setParent(org.xml.sax.XMLReader);
-    method public void setProperty(java.lang.String, java.lang.Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public void skippedEntity(java.lang.String) throws org.xml.sax.SAXException;
+    method public void setProperty(String, Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public void skippedEntity(String) throws org.xml.sax.SAXException;
     method public void startDocument() throws org.xml.sax.SAXException;
-    method public void startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) throws org.xml.sax.SAXException;
-    method public void startPrefixMapping(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public void unparsedEntityDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
+    method public void startElement(String, String, String, org.xml.sax.Attributes) throws org.xml.sax.SAXException;
+    method public void startPrefixMapping(String, String) throws org.xml.sax.SAXException;
+    method public void unparsedEntityDecl(String, String, String, String) throws org.xml.sax.SAXException;
     method public void warning(org.xml.sax.SAXParseException) throws org.xml.sax.SAXException;
   }
 
@@ -77421,146 +77707,146 @@
     ctor public XMLReaderAdapter(org.xml.sax.XMLReader);
     method public void characters(char[], int, int) throws org.xml.sax.SAXException;
     method public void endDocument() throws org.xml.sax.SAXException;
-    method public void endElement(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    method public void endPrefixMapping(java.lang.String);
+    method public void endElement(String, String, String) throws org.xml.sax.SAXException;
+    method public void endPrefixMapping(String);
     method public void ignorableWhitespace(char[], int, int) throws org.xml.sax.SAXException;
-    method public void parse(java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void parse(String) throws java.io.IOException, org.xml.sax.SAXException;
     method public void parse(org.xml.sax.InputSource) throws java.io.IOException, org.xml.sax.SAXException;
-    method public void processingInstruction(java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
+    method public void processingInstruction(String, String) throws org.xml.sax.SAXException;
     method public void setDTDHandler(org.xml.sax.DTDHandler);
     method public void setDocumentHandler(org.xml.sax.DocumentHandler);
     method public void setDocumentLocator(org.xml.sax.Locator);
     method public void setEntityResolver(org.xml.sax.EntityResolver);
     method public void setErrorHandler(org.xml.sax.ErrorHandler);
     method public void setLocale(java.util.Locale) throws org.xml.sax.SAXException;
-    method public void skippedEntity(java.lang.String) throws org.xml.sax.SAXException;
+    method public void skippedEntity(String) throws org.xml.sax.SAXException;
     method public void startDocument() throws org.xml.sax.SAXException;
-    method public void startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) throws org.xml.sax.SAXException;
-    method public void startPrefixMapping(java.lang.String, java.lang.String);
+    method public void startElement(String, String, String, org.xml.sax.Attributes) throws org.xml.sax.SAXException;
+    method public void startPrefixMapping(String, String);
   }
 
   public final class XMLReaderFactory {
     method public static org.xml.sax.XMLReader createXMLReader() throws org.xml.sax.SAXException;
-    method public static org.xml.sax.XMLReader createXMLReader(java.lang.String) throws org.xml.sax.SAXException;
+    method public static org.xml.sax.XMLReader createXMLReader(String) throws org.xml.sax.SAXException;
   }
 
 }
 
 package org.xmlpull.v1 {
 
-  public abstract interface XmlPullParser {
-    method public abstract void defineEntityReplacementText(java.lang.String, java.lang.String) throws org.xmlpull.v1.XmlPullParserException;
-    method public abstract int getAttributeCount();
-    method public abstract java.lang.String getAttributeName(int);
-    method public abstract java.lang.String getAttributeNamespace(int);
-    method public abstract java.lang.String getAttributePrefix(int);
-    method public abstract java.lang.String getAttributeType(int);
-    method public abstract java.lang.String getAttributeValue(int);
-    method public abstract java.lang.String getAttributeValue(java.lang.String, java.lang.String);
-    method public abstract int getColumnNumber();
-    method public abstract int getDepth();
-    method public abstract int getEventType() throws org.xmlpull.v1.XmlPullParserException;
-    method public abstract boolean getFeature(java.lang.String);
-    method public abstract java.lang.String getInputEncoding();
-    method public abstract int getLineNumber();
-    method public abstract java.lang.String getName();
-    method public abstract java.lang.String getNamespace(java.lang.String);
-    method public abstract java.lang.String getNamespace();
-    method public abstract int getNamespaceCount(int) throws org.xmlpull.v1.XmlPullParserException;
-    method public abstract java.lang.String getNamespacePrefix(int) throws org.xmlpull.v1.XmlPullParserException;
-    method public abstract java.lang.String getNamespaceUri(int) throws org.xmlpull.v1.XmlPullParserException;
-    method public abstract java.lang.String getPositionDescription();
-    method public abstract java.lang.String getPrefix();
-    method public abstract java.lang.Object getProperty(java.lang.String);
-    method public abstract java.lang.String getText();
-    method public abstract char[] getTextCharacters(int[]);
-    method public abstract boolean isAttributeDefault(int);
-    method public abstract boolean isEmptyElementTag() throws org.xmlpull.v1.XmlPullParserException;
-    method public abstract boolean isWhitespace() throws org.xmlpull.v1.XmlPullParserException;
-    method public abstract int next() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public abstract int nextTag() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public abstract java.lang.String nextText() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public abstract int nextToken() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public abstract void require(int, java.lang.String, java.lang.String) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public abstract void setFeature(java.lang.String, boolean) throws org.xmlpull.v1.XmlPullParserException;
-    method public abstract void setInput(java.io.Reader) throws org.xmlpull.v1.XmlPullParserException;
-    method public abstract void setInput(java.io.InputStream, java.lang.String) throws org.xmlpull.v1.XmlPullParserException;
-    method public abstract void setProperty(java.lang.String, java.lang.Object) throws org.xmlpull.v1.XmlPullParserException;
+  public interface XmlPullParser {
+    method public void defineEntityReplacementText(String, String) throws org.xmlpull.v1.XmlPullParserException;
+    method public int getAttributeCount();
+    method public String getAttributeName(int);
+    method public String getAttributeNamespace(int);
+    method public String getAttributePrefix(int);
+    method public String getAttributeType(int);
+    method public String getAttributeValue(int);
+    method public String getAttributeValue(String, String);
+    method public int getColumnNumber();
+    method public int getDepth();
+    method public int getEventType() throws org.xmlpull.v1.XmlPullParserException;
+    method public boolean getFeature(String);
+    method public String getInputEncoding();
+    method public int getLineNumber();
+    method public String getName();
+    method public String getNamespace(String);
+    method public String getNamespace();
+    method public int getNamespaceCount(int) throws org.xmlpull.v1.XmlPullParserException;
+    method public String getNamespacePrefix(int) throws org.xmlpull.v1.XmlPullParserException;
+    method public String getNamespaceUri(int) throws org.xmlpull.v1.XmlPullParserException;
+    method public String getPositionDescription();
+    method public String getPrefix();
+    method public Object getProperty(String);
+    method public String getText();
+    method public char[] getTextCharacters(int[]);
+    method public boolean isAttributeDefault(int);
+    method public boolean isEmptyElementTag() throws org.xmlpull.v1.XmlPullParserException;
+    method public boolean isWhitespace() throws org.xmlpull.v1.XmlPullParserException;
+    method public int next() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public int nextTag() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public String nextText() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public int nextToken() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void require(int, String, String) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void setFeature(String, boolean) throws org.xmlpull.v1.XmlPullParserException;
+    method public void setInput(java.io.Reader) throws org.xmlpull.v1.XmlPullParserException;
+    method public void setInput(java.io.InputStream, String) throws org.xmlpull.v1.XmlPullParserException;
+    method public void setProperty(String, Object) throws org.xmlpull.v1.XmlPullParserException;
     field public static final int CDSECT = 5; // 0x5
     field public static final int COMMENT = 9; // 0x9
     field public static final int DOCDECL = 10; // 0xa
     field public static final int END_DOCUMENT = 1; // 0x1
     field public static final int END_TAG = 3; // 0x3
     field public static final int ENTITY_REF = 6; // 0x6
-    field public static final java.lang.String FEATURE_PROCESS_DOCDECL = "http://xmlpull.org/v1/doc/features.html#process-docdecl";
-    field public static final java.lang.String FEATURE_PROCESS_NAMESPACES = "http://xmlpull.org/v1/doc/features.html#process-namespaces";
-    field public static final java.lang.String FEATURE_REPORT_NAMESPACE_ATTRIBUTES = "http://xmlpull.org/v1/doc/features.html#report-namespace-prefixes";
-    field public static final java.lang.String FEATURE_VALIDATION = "http://xmlpull.org/v1/doc/features.html#validation";
+    field public static final String FEATURE_PROCESS_DOCDECL = "http://xmlpull.org/v1/doc/features.html#process-docdecl";
+    field public static final String FEATURE_PROCESS_NAMESPACES = "http://xmlpull.org/v1/doc/features.html#process-namespaces";
+    field public static final String FEATURE_REPORT_NAMESPACE_ATTRIBUTES = "http://xmlpull.org/v1/doc/features.html#report-namespace-prefixes";
+    field public static final String FEATURE_VALIDATION = "http://xmlpull.org/v1/doc/features.html#validation";
     field public static final int IGNORABLE_WHITESPACE = 7; // 0x7
-    field public static final java.lang.String NO_NAMESPACE = "";
+    field public static final String NO_NAMESPACE = "";
     field public static final int PROCESSING_INSTRUCTION = 8; // 0x8
     field public static final int START_DOCUMENT = 0; // 0x0
     field public static final int START_TAG = 2; // 0x2
     field public static final int TEXT = 4; // 0x4
-    field public static final java.lang.String[] TYPES;
+    field public static final String[] TYPES;
   }
 
   public class XmlPullParserException extends java.lang.Exception {
-    ctor public XmlPullParserException(java.lang.String);
-    ctor public XmlPullParserException(java.lang.String, org.xmlpull.v1.XmlPullParser, java.lang.Throwable);
+    ctor public XmlPullParserException(String);
+    ctor public XmlPullParserException(String, org.xmlpull.v1.XmlPullParser, Throwable);
     method public int getColumnNumber();
-    method public java.lang.Throwable getDetail();
+    method public Throwable getDetail();
     method public int getLineNumber();
     field protected int column;
-    field protected java.lang.Throwable detail;
+    field protected Throwable detail;
     field protected int row;
   }
 
   public class XmlPullParserFactory {
     ctor protected XmlPullParserFactory();
-    method public boolean getFeature(java.lang.String);
+    method public boolean getFeature(String);
     method public boolean isNamespaceAware();
     method public boolean isValidating();
     method public static org.xmlpull.v1.XmlPullParserFactory newInstance() throws org.xmlpull.v1.XmlPullParserException;
-    method public static org.xmlpull.v1.XmlPullParserFactory newInstance(java.lang.String, java.lang.Class) throws org.xmlpull.v1.XmlPullParserException;
+    method public static org.xmlpull.v1.XmlPullParserFactory newInstance(String, Class) throws org.xmlpull.v1.XmlPullParserException;
     method public org.xmlpull.v1.XmlPullParser newPullParser() throws org.xmlpull.v1.XmlPullParserException;
     method public org.xmlpull.v1.XmlSerializer newSerializer() throws org.xmlpull.v1.XmlPullParserException;
-    method public void setFeature(java.lang.String, boolean) throws org.xmlpull.v1.XmlPullParserException;
+    method public void setFeature(String, boolean) throws org.xmlpull.v1.XmlPullParserException;
     method public void setNamespaceAware(boolean);
     method public void setValidating(boolean);
-    field public static final java.lang.String PROPERTY_NAME = "org.xmlpull.v1.XmlPullParserFactory";
-    field protected java.lang.String classNamesLocation;
-    field protected java.util.HashMap<java.lang.String, java.lang.Boolean> features;
+    field public static final String PROPERTY_NAME = "org.xmlpull.v1.XmlPullParserFactory";
+    field protected String classNamesLocation;
+    field protected java.util.HashMap<java.lang.String,java.lang.Boolean> features;
     field protected java.util.ArrayList parserClasses;
     field protected java.util.ArrayList serializerClasses;
   }
 
-  public abstract interface XmlSerializer {
-    method public abstract org.xmlpull.v1.XmlSerializer attribute(java.lang.String, java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract void cdsect(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract void comment(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract void docdecl(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract void endDocument() throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract org.xmlpull.v1.XmlSerializer endTag(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract void entityRef(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract void flush() throws java.io.IOException;
-    method public abstract int getDepth();
-    method public abstract boolean getFeature(java.lang.String);
-    method public abstract java.lang.String getName();
-    method public abstract java.lang.String getNamespace();
-    method public abstract java.lang.String getPrefix(java.lang.String, boolean) throws java.lang.IllegalArgumentException;
-    method public abstract java.lang.Object getProperty(java.lang.String);
-    method public abstract void ignorableWhitespace(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract void processingInstruction(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract void setFeature(java.lang.String, boolean) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract void setOutput(java.io.OutputStream, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract void setOutput(java.io.Writer) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract void setPrefix(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract void setProperty(java.lang.String, java.lang.Object) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract void startDocument(java.lang.String, java.lang.Boolean) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract org.xmlpull.v1.XmlSerializer startTag(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract org.xmlpull.v1.XmlSerializer text(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public abstract org.xmlpull.v1.XmlSerializer text(char[], int, int) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+  public interface XmlSerializer {
+    method public org.xmlpull.v1.XmlSerializer attribute(String, String, String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void cdsect(String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void comment(String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void docdecl(String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void endDocument() throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public org.xmlpull.v1.XmlSerializer endTag(String, String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void entityRef(String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void flush() throws java.io.IOException;
+    method public int getDepth();
+    method public boolean getFeature(String);
+    method public String getName();
+    method public String getNamespace();
+    method public String getPrefix(String, boolean) throws java.lang.IllegalArgumentException;
+    method public Object getProperty(String);
+    method public void ignorableWhitespace(String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void processingInstruction(String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void setFeature(String, boolean) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void setOutput(java.io.OutputStream, String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void setOutput(java.io.Writer) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void setPrefix(String, String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void setProperty(String, Object) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void startDocument(String, Boolean) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public org.xmlpull.v1.XmlSerializer startTag(String, String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public org.xmlpull.v1.XmlSerializer text(String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public org.xmlpull.v1.XmlSerializer text(char[], int, int) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
   }
 
 }
@@ -77575,44 +77861,44 @@
     method public org.xml.sax.DTDHandler getDTDHandler();
     method public org.xml.sax.EntityResolver getEntityResolver();
     method public org.xml.sax.ErrorHandler getErrorHandler();
-    method public boolean getFeature(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public int getIndex(java.lang.String, java.lang.String);
-    method public int getIndex(java.lang.String);
+    method public boolean getFeature(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public int getIndex(String, String);
+    method public int getIndex(String);
     method public int getLength();
     method public int getLineNumber();
-    method public java.lang.String getLocalName(int);
-    method public java.lang.Object getProperty(java.lang.String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public java.lang.String getPublicId();
-    method public java.lang.String getQName(int);
-    method public java.lang.String getSystemId();
-    method public java.lang.String getType(int);
-    method public java.lang.String getType(java.lang.String, java.lang.String);
-    method public java.lang.String getType(java.lang.String);
-    method public java.lang.String getURI(int);
-    method public java.lang.String getValue(int);
-    method public java.lang.String getValue(java.lang.String, java.lang.String);
-    method public java.lang.String getValue(java.lang.String);
+    method public String getLocalName(int);
+    method public Object getProperty(String) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public String getPublicId();
+    method public String getQName(int);
+    method public String getSystemId();
+    method public String getType(int);
+    method public String getType(String, String);
+    method public String getType(String);
+    method public String getURI(int);
+    method public String getValue(int);
+    method public String getValue(String, String);
+    method public String getValue(String);
     method public void parse(org.xml.sax.InputSource) throws java.io.IOException, org.xml.sax.SAXException;
-    method public void parse(java.lang.String) throws java.io.IOException, org.xml.sax.SAXException;
+    method public void parse(String) throws java.io.IOException, org.xml.sax.SAXException;
     method public void parseSubTree(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xml.sax.SAXException;
     method public void setContentHandler(org.xml.sax.ContentHandler);
     method public void setDTDHandler(org.xml.sax.DTDHandler);
     method public void setEntityResolver(org.xml.sax.EntityResolver);
     method public void setErrorHandler(org.xml.sax.ErrorHandler);
-    method public void setFeature(java.lang.String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method public void setProperty(java.lang.String, java.lang.Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
-    method protected void startElement(java.lang.String, java.lang.String, java.lang.String) throws org.xml.sax.SAXException;
-    field protected static final java.lang.String APACHE_DYNAMIC_VALIDATION_FEATURE = "http://apache.org/xml/features/validation/dynamic";
-    field protected static final java.lang.String APACHE_SCHEMA_VALIDATION_FEATURE = "http://apache.org/xml/features/validation/schema";
-    field protected static final java.lang.String DECLARATION_HANDLER_PROPERTY = "http://xml.org/sax/properties/declaration-handler";
-    field protected static final java.lang.String LEXICAL_HANDLER_PROPERTY = "http://xml.org/sax/properties/lexical-handler";
-    field protected static final java.lang.String NAMESPACES_FEATURE = "http://xml.org/sax/features/namespaces";
-    field protected static final java.lang.String NAMESPACE_PREFIXES_FEATURE = "http://xml.org/sax/features/namespace-prefixes";
-    field protected static final java.lang.String VALIDATION_FEATURE = "http://xml.org/sax/features/validation";
+    method public void setFeature(String, boolean) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method public void setProperty(String, Object) throws org.xml.sax.SAXNotRecognizedException, org.xml.sax.SAXNotSupportedException;
+    method protected void startElement(String, String, String) throws org.xml.sax.SAXException;
+    field protected static final String APACHE_DYNAMIC_VALIDATION_FEATURE = "http://apache.org/xml/features/validation/dynamic";
+    field protected static final String APACHE_SCHEMA_VALIDATION_FEATURE = "http://apache.org/xml/features/validation/schema";
+    field protected static final String DECLARATION_HANDLER_PROPERTY = "http://xml.org/sax/properties/declaration-handler";
+    field protected static final String LEXICAL_HANDLER_PROPERTY = "http://xml.org/sax/properties/lexical-handler";
+    field protected static final String NAMESPACES_FEATURE = "http://xml.org/sax/features/namespaces";
+    field protected static final String NAMESPACE_PREFIXES_FEATURE = "http://xml.org/sax/features/namespace-prefixes";
+    field protected static final String VALIDATION_FEATURE = "http://xml.org/sax/features/validation";
     field protected org.xml.sax.ContentHandler contentHandler;
     field protected org.xml.sax.ErrorHandler errorHandler;
     field protected org.xmlpull.v1.XmlPullParser pp;
-    field protected java.lang.String systemId;
+    field protected String systemId;
   }
 
 }
diff --git a/api/removed.txt b/api/removed.txt
index f7106d2..9f4b041 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -1,31 +1,32 @@
+// Signature format: 2.0
 package android.app {
 
   public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback {
-    method public deprecated boolean enterPictureInPictureMode(android.app.PictureInPictureArgs);
-    method public deprecated void setPictureInPictureArgs(android.app.PictureInPictureArgs);
+    method @Deprecated public boolean enterPictureInPictureMode(@NonNull android.app.PictureInPictureArgs);
+    method @Deprecated public void setPictureInPictureArgs(@NonNull android.app.PictureInPictureArgs);
   }
 
   public class ActivityManager {
-    method public static deprecated int getMaxNumPictureInPictureActions();
+    method @Deprecated public static int getMaxNumPictureInPictureActions();
   }
 
   public class KeyguardManager {
-    method public deprecated void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
+    method @Deprecated public void dismissKeyguard(@NonNull android.app.Activity, @Nullable android.app.KeyguardManager.KeyguardDismissCallback, @Nullable android.os.Handler);
   }
 
   public class Notification implements android.os.Parcelable {
-    method public deprecated java.lang.String getChannel();
-    method public static java.lang.Class<? extends android.app.Notification.Style> getNotificationStyleClass(java.lang.String);
-    method public deprecated long getTimeout();
-    method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
+    method @Deprecated public String getChannel();
+    method public static Class<? extends android.app.Notification.Style> getNotificationStyleClass(String);
+    method @Deprecated public long getTimeout();
+    method @Deprecated public void setLatestEventInfo(android.content.Context, CharSequence, CharSequence, android.app.PendingIntent);
   }
 
   public static class Notification.Builder {
-    method public deprecated android.app.Notification.Builder setChannel(java.lang.String);
-    method public deprecated android.app.Notification.Builder setTimeout(long);
+    method @Deprecated public android.app.Notification.Builder setChannel(String);
+    method @Deprecated public android.app.Notification.Builder setTimeout(long);
   }
 
-  public final deprecated class PictureInPictureArgs implements android.os.Parcelable {
+  @Deprecated public final class PictureInPictureArgs implements android.os.Parcelable {
     method public static android.app.PictureInPictureArgs convert(android.app.PictureInPictureParams);
     method public static android.app.PictureInPictureParams convert(android.app.PictureInPictureArgs);
     method public int describeContents();
@@ -48,8 +49,8 @@
 package android.app.admin {
 
   public class DevicePolicyManager {
-    method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
-    method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
+    method @Deprecated @Nullable public android.os.UserHandle createAndInitializeUser(@NonNull android.content.ComponentName, String, String, @NonNull android.content.ComponentName, android.os.Bundle);
+    method @Deprecated @Nullable public android.os.UserHandle createUser(@NonNull android.content.ComponentName, String);
   }
 
 }
@@ -57,17 +58,17 @@
 package android.app.job {
 
   public class JobInfo implements android.os.Parcelable {
-    method public deprecated long getEstimatedNetworkBytes();
+    method @Deprecated public long getEstimatedNetworkBytes();
   }
 
   public static final class JobInfo.Builder {
-    method public deprecated android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long);
-    method public deprecated android.app.job.JobInfo.Builder setIsPrefetch(boolean);
+    method @Deprecated public android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long);
+    method @Deprecated public android.app.job.JobInfo.Builder setIsPrefetch(boolean);
   }
 
   public final class JobWorkItem implements android.os.Parcelable {
-    ctor public deprecated JobWorkItem(android.content.Intent, long);
-    method public deprecated long getEstimatedNetworkBytes();
+    ctor @Deprecated public JobWorkItem(android.content.Intent, long);
+    method @Deprecated public long getEstimatedNetworkBytes();
   }
 
 }
@@ -75,29 +76,29 @@
 package android.app.slice {
 
   public final class Slice implements android.os.Parcelable {
-    field public static final deprecated java.lang.String EXTRA_SLIDER_VALUE = "android.app.slice.extra.SLIDER_VALUE";
-    field public static final deprecated java.lang.String SUBTYPE_SLIDER = "slider";
+    field @Deprecated public static final String EXTRA_SLIDER_VALUE = "android.app.slice.extra.SLIDER_VALUE";
+    field @Deprecated public static final String SUBTYPE_SLIDER = "slider";
   }
 
   public static class Slice.Builder {
-    ctor public deprecated Slice.Builder(android.net.Uri);
-    method public deprecated android.app.slice.Slice.Builder addTimestamp(long, java.lang.String, java.util.List<java.lang.String>);
-    method public deprecated android.app.slice.Slice.Builder setSpec(android.app.slice.SliceSpec);
+    ctor @Deprecated public Slice.Builder(@NonNull android.net.Uri);
+    method @Deprecated public android.app.slice.Slice.Builder addTimestamp(long, @Nullable String, java.util.List<java.lang.String>);
+    method @Deprecated public android.app.slice.Slice.Builder setSpec(android.app.slice.SliceSpec);
   }
 
   public final class SliceItem implements android.os.Parcelable {
-    method public deprecated long getTimestamp();
-    field public static final deprecated java.lang.String FORMAT_TIMESTAMP = "long";
+    method @Deprecated public long getTimestamp();
+    field @Deprecated public static final String FORMAT_TIMESTAMP = "long";
   }
 
   public class SliceManager {
-    method public deprecated android.app.slice.Slice bindSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
-    method public deprecated android.app.slice.Slice bindSlice(android.content.Intent, java.util.List<android.app.slice.SliceSpec>);
-    method public deprecated void pinSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
+    method @Deprecated @Nullable public android.app.slice.Slice bindSlice(@NonNull android.net.Uri, @NonNull java.util.List<android.app.slice.SliceSpec>);
+    method @Deprecated @Nullable public android.app.slice.Slice bindSlice(@NonNull android.content.Intent, @NonNull java.util.List<android.app.slice.SliceSpec>);
+    method @Deprecated public void pinSlice(@NonNull android.net.Uri, @NonNull java.util.List<android.app.slice.SliceSpec>);
   }
 
   public abstract class SliceProvider extends android.content.ContentProvider {
-    method public deprecated android.app.slice.Slice onBindSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
+    method @Deprecated public android.app.slice.Slice onBindSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
   }
 
 }
@@ -105,17 +106,17 @@
 package android.app.usage {
 
   public final class StorageStats implements android.os.Parcelable {
-    method public deprecated long getCodeBytes();
+    method @Deprecated public long getCodeBytes();
   }
 
   public class StorageStatsManager {
-    method public deprecated long getFreeBytes(java.lang.String) throws java.io.IOException;
-    method public deprecated long getTotalBytes(java.lang.String) throws java.io.IOException;
-    method public deprecated boolean isQuotaSupported(java.lang.String);
-    method public deprecated android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException;
-    method public deprecated android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
-    method public deprecated android.app.usage.StorageStats queryStatsForUid(java.lang.String, int) throws java.io.IOException;
-    method public deprecated android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle) throws java.io.IOException;
+    method @Deprecated public long getFreeBytes(String) throws java.io.IOException;
+    method @Deprecated public long getTotalBytes(String) throws java.io.IOException;
+    method @Deprecated public boolean isQuotaSupported(String);
+    method @Deprecated public android.app.usage.ExternalStorageStats queryExternalStatsForUser(String, android.os.UserHandle) throws java.io.IOException;
+    method @Deprecated public android.app.usage.StorageStats queryStatsForPackage(String, String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.app.usage.StorageStats queryStatsForUid(String, int) throws java.io.IOException;
+    method @Deprecated public android.app.usage.StorageStats queryStatsForUser(String, android.os.UserHandle) throws java.io.IOException;
   }
 
 }
@@ -123,21 +124,21 @@
 package android.content {
 
   public class ClipData implements android.os.Parcelable {
-    method public deprecated void addItem(android.content.ClipData.Item, android.content.ContentResolver);
+    method @Deprecated public void addItem(android.content.ClipData.Item, android.content.ContentResolver);
   }
 
   public abstract class Context {
     method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
+    method public abstract java.io.File getSharedPreferencesPath(String);
   }
 
   public class ContextWrapper extends android.content.Context {
     method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
+    method public java.io.File getSharedPreferencesPath(String);
   }
 
   public class Intent implements java.lang.Cloneable android.os.Parcelable {
-    field public static final deprecated java.lang.String EXTRA_QUICK_VIEW_ADVANCED = "android.intent.extra.QUICK_VIEW_ADVANCED";
+    field @Deprecated public static final String EXTRA_QUICK_VIEW_ADVANCED = "android.intent.extra.QUICK_VIEW_ADVANCED";
   }
 
 }
@@ -145,11 +146,11 @@
 package android.content.pm {
 
   public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
-    field public deprecated java.lang.String volumeUuid;
+    field @Deprecated public String volumeUuid;
   }
 
   public class ComponentInfo extends android.content.pm.PackageItemInfo {
-    field public deprecated boolean encryptionAware;
+    field @Deprecated public boolean encryptionAware;
   }
 
   public class PackageInfo implements android.os.Parcelable {
@@ -157,11 +158,11 @@
   }
 
   public abstract class PackageManager {
-    method public abstract boolean setInstantAppCookie(byte[]);
+    method public abstract boolean setInstantAppCookie(@Nullable byte[]);
   }
 
   public class ResolveInfo implements android.os.Parcelable {
-    field public deprecated boolean instantAppAvailable;
+    field @Deprecated public boolean instantAppAvailable;
   }
 
   public final class SharedLibraryInfo implements android.os.Parcelable {
@@ -175,76 +176,74 @@
 package android.database {
 
   public abstract class AbstractCursor implements android.database.CrossProcessCursor {
-    field protected java.lang.Long mCurrentRowID;
+    field protected Long mCurrentRowID;
     field protected int mRowIdColumnIndex;
-    field protected java.util.HashMap<java.lang.Long, java.util.Map<java.lang.String, java.lang.Object>> mUpdatedRows;
+    field protected java.util.HashMap<java.lang.Long,java.util.Map<java.lang.String,java.lang.Object>> mUpdatedRows;
   }
 
 }
 
 package android.graphics {
 
-  public deprecated class AvoidXfermode extends android.graphics.Xfermode {
+  @Deprecated public class AvoidXfermode extends android.graphics.Xfermode {
     ctor public AvoidXfermode(int, int, android.graphics.AvoidXfermode.Mode);
   }
 
-  public static final class AvoidXfermode.Mode extends java.lang.Enum {
-    method public static android.graphics.AvoidXfermode.Mode valueOf(java.lang.String);
-    method public static final android.graphics.AvoidXfermode.Mode[] values();
+  public enum AvoidXfermode.Mode {
     enum_constant public static final android.graphics.AvoidXfermode.Mode AVOID;
     enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
   }
 
   public class Canvas {
-    method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
-    method public deprecated boolean clipRegion(android.graphics.Region);
-    method public deprecated int save(int);
-    field public static final deprecated int CLIP_SAVE_FLAG = 2; // 0x2
-    field public static final deprecated int CLIP_TO_LAYER_SAVE_FLAG = 16; // 0x10
-    field public static final deprecated int FULL_COLOR_LAYER_SAVE_FLAG = 8; // 0x8
-    field public static final deprecated int HAS_ALPHA_LAYER_SAVE_FLAG = 4; // 0x4
-    field public static final deprecated int MATRIX_SAVE_FLAG = 1; // 0x1
+    method @Deprecated public boolean clipRegion(@NonNull android.graphics.Region, @NonNull android.graphics.Region.Op);
+    method @Deprecated public boolean clipRegion(@NonNull android.graphics.Region);
+    method @Deprecated public int save(int);
+    field @Deprecated public static final int CLIP_SAVE_FLAG = 2; // 0x2
+    field @Deprecated public static final int CLIP_TO_LAYER_SAVE_FLAG = 16; // 0x10
+    field @Deprecated public static final int FULL_COLOR_LAYER_SAVE_FLAG = 8; // 0x8
+    field @Deprecated public static final int HAS_ALPHA_LAYER_SAVE_FLAG = 4; // 0x4
+    field @Deprecated public static final int MATRIX_SAVE_FLAG = 1; // 0x1
   }
 
   public final class ImageDecoder implements java.lang.AutoCloseable {
-    method public deprecated boolean getAsAlphaMask();
-    method public deprecated boolean getConserveMemory();
-    method public deprecated boolean getDecodeAsAlphaMask();
-    method public deprecated boolean getMutable();
-    method public deprecated boolean getRequireUnpremultiplied();
-    method public deprecated android.graphics.ImageDecoder setAsAlphaMask(boolean);
-    method public deprecated void setConserveMemory(boolean);
-    method public deprecated android.graphics.ImageDecoder setDecodeAsAlphaMask(boolean);
-    method public deprecated android.graphics.ImageDecoder setMutable(boolean);
-    method public deprecated android.graphics.ImageDecoder setRequireUnpremultiplied(boolean);
-    method public deprecated android.graphics.ImageDecoder setResize(int, int);
-    method public deprecated android.graphics.ImageDecoder setResize(int);
-    field public static final deprecated int ERROR_SOURCE_ERROR = 3; // 0x3
-    field public static final deprecated int ERROR_SOURCE_EXCEPTION = 1; // 0x1
-    field public static final deprecated int ERROR_SOURCE_INCOMPLETE = 2; // 0x2
+    method @Deprecated public boolean getAsAlphaMask();
+    method @Deprecated public boolean getConserveMemory();
+    method @Deprecated public boolean getDecodeAsAlphaMask();
+    method @Deprecated public boolean getMutable();
+    method @Deprecated public boolean getRequireUnpremultiplied();
+    method @Deprecated public android.graphics.ImageDecoder setAsAlphaMask(boolean);
+    method @Deprecated public void setConserveMemory(boolean);
+    method @Deprecated public android.graphics.ImageDecoder setDecodeAsAlphaMask(boolean);
+    method @Deprecated public android.graphics.ImageDecoder setMutable(boolean);
+    method @Deprecated public android.graphics.ImageDecoder setRequireUnpremultiplied(boolean);
+    method @Deprecated public android.graphics.ImageDecoder setResize(int, int);
+    method @Deprecated public android.graphics.ImageDecoder setResize(int);
+    field @Deprecated public static final int ERROR_SOURCE_ERROR = 3; // 0x3
+    field @Deprecated public static final int ERROR_SOURCE_EXCEPTION = 1; // 0x1
+    field @Deprecated public static final int ERROR_SOURCE_INCOMPLETE = 2; // 0x2
   }
 
-  public static deprecated class ImageDecoder.IncompleteException extends java.io.IOException {
+  @Deprecated public static class ImageDecoder.IncompleteException extends java.io.IOException {
     ctor public ImageDecoder.IncompleteException();
   }
 
-  public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
+  @Deprecated public class LayerRasterizer extends android.graphics.Rasterizer {
     ctor public LayerRasterizer();
     method public void addLayer(android.graphics.Paint, float, float);
     method public void addLayer(android.graphics.Paint);
   }
 
   public class Paint {
-    method public deprecated android.graphics.Rasterizer getRasterizer();
-    method public deprecated android.graphics.Rasterizer setRasterizer(android.graphics.Rasterizer);
+    method @Deprecated public android.graphics.Rasterizer getRasterizer();
+    method @Deprecated public android.graphics.Rasterizer setRasterizer(android.graphics.Rasterizer);
   }
 
   public class Picture {
-    method public static deprecated android.graphics.Picture createFromStream(java.io.InputStream);
-    method public deprecated void writeToStream(java.io.OutputStream);
+    method @Deprecated public static android.graphics.Picture createFromStream(@NonNull java.io.InputStream);
+    method @Deprecated public void writeToStream(@NonNull java.io.OutputStream);
   }
 
-  public deprecated class PixelXorXfermode extends android.graphics.Xfermode {
+  @Deprecated public class PixelXorXfermode extends android.graphics.Xfermode {
     ctor public PixelXorXfermode(int);
   }
 
@@ -257,9 +256,9 @@
 package android.graphics.drawable {
 
   public class AnimatedImageDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
-    method public deprecated int getLoopCount(int);
-    method public deprecated void setLoopCount(int);
-    field public static final deprecated int LOOP_INFINITE = -1; // 0xffffffff
+    method @Deprecated public int getLoopCount(int);
+    method @Deprecated public void setLoopCount(int);
+    field @Deprecated public static final int LOOP_INFINITE = -1; // 0xffffffff
   }
 
 }
@@ -267,16 +266,16 @@
 package android.hardware {
 
   public final class HardwareBuffer implements java.lang.AutoCloseable android.os.Parcelable {
-    method public deprecated void destroy();
-    method public deprecated boolean isDestroyed();
+    method @Deprecated public void destroy();
+    method @Deprecated public boolean isDestroyed();
   }
 
   public final class SensorDirectChannel implements java.nio.channels.Channel {
-    method public deprecated boolean isValid();
+    method @Deprecated public boolean isValid();
   }
 
   public abstract class SensorManager {
-    method public deprecated int configureDirectChannel(android.hardware.SensorDirectChannel, android.hardware.Sensor, int);
+    method @Deprecated public int configureDirectChannel(android.hardware.SensorDirectChannel, android.hardware.Sensor, int);
   }
 
 }
@@ -284,9 +283,9 @@
 package android.location {
 
   public class Location implements android.os.Parcelable {
-    method public deprecated void removeBearingAccuracy();
-    method public deprecated void removeSpeedAccuracy();
-    method public deprecated void removeVerticalAccuracy();
+    method @Deprecated public void removeBearingAccuracy();
+    method @Deprecated public void removeSpeedAccuracy();
+    method @Deprecated public void removeVerticalAccuracy();
   }
 
 }
@@ -310,28 +309,28 @@
 package android.net {
 
   public class ConnectivityManager {
-    method public deprecated boolean requestRouteToHost(int, int);
-    method public deprecated int startUsingNetworkFeature(int, java.lang.String);
-    method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
+    method @Deprecated public boolean requestRouteToHost(int, int);
+    method @Deprecated public int startUsingNetworkFeature(int, String);
+    method @Deprecated public int stopUsingNetworkFeature(int, String);
   }
 
-  public deprecated class NetworkBadging {
-    method public static android.graphics.drawable.Drawable getWifiIcon(int, int, android.content.res.Resources.Theme);
+  @Deprecated public class NetworkBadging {
+    method @NonNull public static android.graphics.drawable.Drawable getWifiIcon(@IntRange(from=0, to=4) int, int, @Nullable android.content.res.Resources.Theme);
     field public static final int BADGING_4K = 30; // 0x1e
     field public static final int BADGING_HD = 20; // 0x14
     field public static final int BADGING_NONE = 0; // 0x0
     field public static final int BADGING_SD = 10; // 0xa
   }
 
-  public static abstract class NetworkBadging.Badging implements java.lang.annotation.Annotation {
+  @IntDef({0x0, 0xa, 0x14, 0x1e}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NetworkBadging.Badging {
   }
 
-  public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
-    method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
+  @Deprecated public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
+    method @Deprecated public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
   }
 
   public class TrafficStats {
-    method public static deprecated void setThreadStatsUidSelf();
+    method @Deprecated public static void setThreadStatsUidSelf();
   }
 
 }
@@ -344,7 +343,7 @@
 
   public final class PowerManager {
     method public void goToSleep(long);
-    method public deprecated void userActivity(long, boolean);
+    method @Deprecated public void userActivity(long, boolean);
     method public void wakeUp(long);
   }
 
@@ -353,27 +352,27 @@
   }
 
   public static final class StrictMode.ThreadPolicy.Builder {
-    method public android.os.StrictMode.ThreadPolicy.Builder penaltyListener(android.os.StrictMode.OnThreadViolationListener, java.util.concurrent.Executor);
+    method public android.os.StrictMode.ThreadPolicy.Builder penaltyListener(@NonNull android.os.StrictMode.OnThreadViolationListener, @NonNull java.util.concurrent.Executor);
   }
 
   public static final class StrictMode.VmPolicy.Builder {
-    method public android.os.StrictMode.VmPolicy.Builder penaltyListener(android.os.StrictMode.OnVmViolationListener, java.util.concurrent.Executor);
+    method public android.os.StrictMode.VmPolicy.Builder penaltyListener(@NonNull android.os.StrictMode.OnVmViolationListener, @NonNull java.util.concurrent.Executor);
   }
 
   public final class SystemClock {
-    method public static java.time.Clock elapsedRealtimeClock();
-    method public static java.time.Clock uptimeClock();
-    method public static deprecated java.time.Clock uptimeMillisClock();
+    method @NonNull public static java.time.Clock elapsedRealtimeClock();
+    method @NonNull public static java.time.Clock uptimeClock();
+    method @Deprecated @NonNull public static java.time.Clock uptimeMillisClock();
   }
 
   public class TestLooperManager {
-    method public deprecated android.os.MessageQueue getQueue();
+    method @Deprecated public android.os.MessageQueue getQueue();
   }
 
   public class UserManager {
     method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
     method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
-    method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
+    method public CharSequence getBadgedLabelForUser(CharSequence, android.os.UserHandle);
   }
 
 }
@@ -381,8 +380,8 @@
 package android.os.storage {
 
   public class StorageManager {
-    method public android.os.storage.StorageVolume getPrimaryVolume();
-    method public android.os.storage.StorageVolume[] getVolumeList();
+    method @NonNull public android.os.storage.StorageVolume getPrimaryVolume();
+    method @NonNull public android.os.storage.StorageVolume[] getVolumeList();
   }
 
 }
@@ -390,20 +389,20 @@
 package android.provider {
 
   public class Browser {
-    method public static final void addSearchUrl(android.content.ContentResolver, java.lang.String);
-    method public static final boolean canClearHistory(android.content.ContentResolver);
-    method public static final void clearHistory(android.content.ContentResolver);
-    method public static final void clearSearches(android.content.ContentResolver);
-    method public static final void deleteFromHistory(android.content.ContentResolver, java.lang.String);
-    method public static final void deleteHistoryTimeFrame(android.content.ContentResolver, long, long);
-    method public static final android.database.Cursor getAllBookmarks(android.content.ContentResolver) throws java.lang.IllegalStateException;
-    method public static final android.database.Cursor getAllVisitedUrls(android.content.ContentResolver) throws java.lang.IllegalStateException;
-    method public static final void requestAllIcons(android.content.ContentResolver, java.lang.String, android.webkit.WebIconDatabase.IconListener);
-    method public static final void saveBookmark(android.content.Context, java.lang.String, java.lang.String);
-    method public static final void truncateHistory(android.content.ContentResolver);
-    method public static final void updateVisitedHistory(android.content.ContentResolver, java.lang.String, boolean);
-    field public static final android.net.Uri BOOKMARKS_URI;
-    field public static final java.lang.String[] HISTORY_PROJECTION;
+    method @RequiresPermission(allOf={"com.android.browser.permission.READ_HISTORY_BOOKMARKS", "com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"}, apis="..22") public static final void addSearchUrl(android.content.ContentResolver, String);
+    method @RequiresPermission(value="com.android.browser.permission.READ_HISTORY_BOOKMARKS", apis="..22") public static final boolean canClearHistory(android.content.ContentResolver);
+    method @RequiresPermission(value="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS", apis="..22") public static final void clearHistory(android.content.ContentResolver);
+    method @RequiresPermission(value="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS", apis="..22") public static final void clearSearches(android.content.ContentResolver);
+    method @RequiresPermission(value="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS", apis="..22") public static final void deleteFromHistory(android.content.ContentResolver, String);
+    method @RequiresPermission(value="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS", apis="..22") public static final void deleteHistoryTimeFrame(android.content.ContentResolver, long, long);
+    method @RequiresPermission(value="com.android.browser.permission.READ_HISTORY_BOOKMARKS", apis="..22") public static final android.database.Cursor getAllBookmarks(android.content.ContentResolver) throws java.lang.IllegalStateException;
+    method @RequiresPermission(value="com.android.browser.permission.READ_HISTORY_BOOKMARKS", apis="..22") public static final android.database.Cursor getAllVisitedUrls(android.content.ContentResolver) throws java.lang.IllegalStateException;
+    method @RequiresPermission(value="com.android.browser.permission.READ_HISTORY_BOOKMARKS", apis="..22") public static final void requestAllIcons(android.content.ContentResolver, String, android.webkit.WebIconDatabase.IconListener);
+    method public static final void saveBookmark(android.content.Context, String, String);
+    method @RequiresPermission(allOf={"com.android.browser.permission.READ_HISTORY_BOOKMARKS", "com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"}, apis="..22") public static final void truncateHistory(android.content.ContentResolver);
+    method @RequiresPermission(allOf={"com.android.browser.permission.READ_HISTORY_BOOKMARKS", "com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"}, apis="..22") public static final void updateVisitedHistory(android.content.ContentResolver, String, boolean);
+    field @RequiresPermission.Read(value="com.android.browser.permission.READ_HISTORY_BOOKMARKS", apis="..22") @RequiresPermission.Write(value="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS", apis="..22") public static final android.net.Uri BOOKMARKS_URI;
+    field public static final String[] HISTORY_PROJECTION;
     field public static final int HISTORY_PROJECTION_BOOKMARK_INDEX = 4; // 0x4
     field public static final int HISTORY_PROJECTION_DATE_INDEX = 3; // 0x3
     field public static final int HISTORY_PROJECTION_FAVICON_INDEX = 6; // 0x6
@@ -411,121 +410,121 @@
     field public static final int HISTORY_PROJECTION_TITLE_INDEX = 5; // 0x5
     field public static final int HISTORY_PROJECTION_URL_INDEX = 1; // 0x1
     field public static final int HISTORY_PROJECTION_VISITS_INDEX = 2; // 0x2
-    field public static final java.lang.String[] SEARCHES_PROJECTION;
+    field public static final String[] SEARCHES_PROJECTION;
     field public static final int SEARCHES_PROJECTION_DATE_INDEX = 2; // 0x2
     field public static final int SEARCHES_PROJECTION_SEARCH_INDEX = 1; // 0x1
-    field public static final android.net.Uri SEARCHES_URI;
-    field public static final java.lang.String[] TRUNCATE_HISTORY_PROJECTION;
+    field @RequiresPermission.Read(value="com.android.browser.permission.READ_HISTORY_BOOKMARKS", apis="..22") @RequiresPermission.Write(value="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS", apis="..22") public static final android.net.Uri SEARCHES_URI;
+    field public static final String[] TRUNCATE_HISTORY_PROJECTION;
     field public static final int TRUNCATE_HISTORY_PROJECTION_ID_INDEX = 0; // 0x0
     field public static final int TRUNCATE_N_OLDEST = 5; // 0x5
   }
 
   public static class Browser.BookmarkColumns implements android.provider.BaseColumns {
     ctor public Browser.BookmarkColumns();
-    field public static final java.lang.String BOOKMARK = "bookmark";
-    field public static final java.lang.String CREATED = "created";
-    field public static final java.lang.String DATE = "date";
-    field public static final java.lang.String FAVICON = "favicon";
-    field public static final java.lang.String TITLE = "title";
-    field public static final java.lang.String URL = "url";
-    field public static final java.lang.String VISITS = "visits";
-    field public static final java.lang.String _COUNT = "_count";
-    field public static final java.lang.String _ID = "_id";
+    field public static final String BOOKMARK = "bookmark";
+    field public static final String CREATED = "created";
+    field public static final String DATE = "date";
+    field public static final String FAVICON = "favicon";
+    field public static final String TITLE = "title";
+    field public static final String URL = "url";
+    field public static final String VISITS = "visits";
+    field public static final String _COUNT = "_count";
+    field public static final String _ID = "_id";
   }
 
   public static class Browser.SearchColumns implements android.provider.BaseColumns {
     ctor public Browser.SearchColumns();
-    field public static final java.lang.String DATE = "date";
-    field public static final java.lang.String SEARCH = "search";
-    field public static final deprecated java.lang.String URL = "url";
-    field public static final java.lang.String _COUNT = "_count";
-    field public static final java.lang.String _ID = "_id";
+    field public static final String DATE = "date";
+    field public static final String SEARCH = "search";
+    field @Deprecated public static final String URL = "url";
+    field public static final String _COUNT = "_count";
+    field public static final String _ID = "_id";
   }
 
-  public static final deprecated class ContactsContract.Contacts.StreamItems implements android.provider.ContactsContract.StreamItemsColumns {
-    field public static final deprecated java.lang.String CONTENT_DIRECTORY = "stream_items";
+  @Deprecated public static final class ContactsContract.Contacts.StreamItems implements android.provider.ContactsContract.StreamItemsColumns {
+    field @Deprecated public static final String CONTENT_DIRECTORY = "stream_items";
   }
 
-  public static final deprecated class ContactsContract.RawContacts.StreamItems implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemsColumns {
-    field public static final deprecated java.lang.String CONTENT_DIRECTORY = "stream_items";
-    field public static final java.lang.String _COUNT = "_count";
-    field public static final java.lang.String _ID = "_id";
+  @Deprecated public static final class ContactsContract.RawContacts.StreamItems implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemsColumns {
+    field @Deprecated public static final String CONTENT_DIRECTORY = "stream_items";
+    field public static final String _COUNT = "_count";
+    field public static final String _ID = "_id";
   }
 
-  public static final deprecated class ContactsContract.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns {
-    field public static final deprecated java.lang.String PHOTO = "photo";
-    field public static final java.lang.String _COUNT = "_count";
-    field public static final java.lang.String _ID = "_id";
+  @Deprecated public static final class ContactsContract.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns {
+    field @Deprecated public static final String PHOTO = "photo";
+    field public static final String _COUNT = "_count";
+    field public static final String _ID = "_id";
   }
 
-  protected static abstract deprecated interface ContactsContract.StreamItemPhotosColumns {
-    field public static final deprecated java.lang.String PHOTO_FILE_ID = "photo_file_id";
-    field public static final deprecated java.lang.String PHOTO_URI = "photo_uri";
-    field public static final deprecated java.lang.String SORT_INDEX = "sort_index";
-    field public static final deprecated java.lang.String STREAM_ITEM_ID = "stream_item_id";
-    field public static final deprecated java.lang.String SYNC1 = "stream_item_photo_sync1";
-    field public static final deprecated java.lang.String SYNC2 = "stream_item_photo_sync2";
-    field public static final deprecated java.lang.String SYNC3 = "stream_item_photo_sync3";
-    field public static final deprecated java.lang.String SYNC4 = "stream_item_photo_sync4";
+  @Deprecated protected static interface ContactsContract.StreamItemPhotosColumns {
+    field @Deprecated public static final String PHOTO_FILE_ID = "photo_file_id";
+    field @Deprecated public static final String PHOTO_URI = "photo_uri";
+    field @Deprecated public static final String SORT_INDEX = "sort_index";
+    field @Deprecated public static final String STREAM_ITEM_ID = "stream_item_id";
+    field @Deprecated public static final String SYNC1 = "stream_item_photo_sync1";
+    field @Deprecated public static final String SYNC2 = "stream_item_photo_sync2";
+    field @Deprecated public static final String SYNC3 = "stream_item_photo_sync3";
+    field @Deprecated public static final String SYNC4 = "stream_item_photo_sync4";
   }
 
-  public static final deprecated class ContactsContract.StreamItems implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemsColumns {
-    field public static final deprecated java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item";
-    field public static final deprecated android.net.Uri CONTENT_LIMIT_URI;
-    field public static final deprecated android.net.Uri CONTENT_PHOTO_URI;
-    field public static final deprecated java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item";
-    field public static final deprecated android.net.Uri CONTENT_URI;
-    field public static final deprecated java.lang.String MAX_ITEMS = "max_items";
-    field public static final java.lang.String _COUNT = "_count";
-    field public static final java.lang.String _ID = "_id";
+  @Deprecated public static final class ContactsContract.StreamItems implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemsColumns {
+    field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item";
+    field @Deprecated public static final android.net.Uri CONTENT_LIMIT_URI;
+    field @Deprecated public static final android.net.Uri CONTENT_PHOTO_URI;
+    field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item";
+    field @Deprecated public static final android.net.Uri CONTENT_URI;
+    field @Deprecated public static final String MAX_ITEMS = "max_items";
+    field public static final String _COUNT = "_count";
+    field public static final String _ID = "_id";
   }
 
-  public static final deprecated class ContactsContract.StreamItems.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns {
-    field public static final deprecated java.lang.String CONTENT_DIRECTORY = "photo";
-    field public static final deprecated java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item_photo";
-    field public static final deprecated java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item_photo";
-    field public static final java.lang.String _COUNT = "_count";
-    field public static final java.lang.String _ID = "_id";
+  @Deprecated public static final class ContactsContract.StreamItems.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns {
+    field @Deprecated public static final String CONTENT_DIRECTORY = "photo";
+    field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item_photo";
+    field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item_photo";
+    field public static final String _COUNT = "_count";
+    field public static final String _ID = "_id";
   }
 
-  protected static abstract deprecated interface ContactsContract.StreamItemsColumns {
-    field public static final deprecated java.lang.String ACCOUNT_NAME = "account_name";
-    field public static final deprecated java.lang.String ACCOUNT_TYPE = "account_type";
-    field public static final deprecated java.lang.String COMMENTS = "comments";
-    field public static final deprecated java.lang.String CONTACT_ID = "contact_id";
-    field public static final deprecated java.lang.String CONTACT_LOOKUP_KEY = "contact_lookup";
-    field public static final deprecated java.lang.String DATA_SET = "data_set";
-    field public static final deprecated java.lang.String RAW_CONTACT_ID = "raw_contact_id";
-    field public static final deprecated java.lang.String RAW_CONTACT_SOURCE_ID = "raw_contact_source_id";
-    field public static final deprecated java.lang.String RES_ICON = "icon";
-    field public static final deprecated java.lang.String RES_LABEL = "label";
-    field public static final deprecated java.lang.String RES_PACKAGE = "res_package";
-    field public static final deprecated java.lang.String SYNC1 = "stream_item_sync1";
-    field public static final deprecated java.lang.String SYNC2 = "stream_item_sync2";
-    field public static final deprecated java.lang.String SYNC3 = "stream_item_sync3";
-    field public static final deprecated java.lang.String SYNC4 = "stream_item_sync4";
-    field public static final deprecated java.lang.String TEXT = "text";
-    field public static final deprecated java.lang.String TIMESTAMP = "timestamp";
+  @Deprecated protected static interface ContactsContract.StreamItemsColumns {
+    field @Deprecated public static final String ACCOUNT_NAME = "account_name";
+    field @Deprecated public static final String ACCOUNT_TYPE = "account_type";
+    field @Deprecated public static final String COMMENTS = "comments";
+    field @Deprecated public static final String CONTACT_ID = "contact_id";
+    field @Deprecated public static final String CONTACT_LOOKUP_KEY = "contact_lookup";
+    field @Deprecated public static final String DATA_SET = "data_set";
+    field @Deprecated public static final String RAW_CONTACT_ID = "raw_contact_id";
+    field @Deprecated public static final String RAW_CONTACT_SOURCE_ID = "raw_contact_source_id";
+    field @Deprecated public static final String RES_ICON = "icon";
+    field @Deprecated public static final String RES_LABEL = "label";
+    field @Deprecated public static final String RES_PACKAGE = "res_package";
+    field @Deprecated public static final String SYNC1 = "stream_item_sync1";
+    field @Deprecated public static final String SYNC2 = "stream_item_sync2";
+    field @Deprecated public static final String SYNC3 = "stream_item_sync3";
+    field @Deprecated public static final String SYNC4 = "stream_item_sync4";
+    field @Deprecated public static final String TEXT = "text";
+    field @Deprecated public static final String TIMESTAMP = "timestamp";
   }
 
   public static final class Settings.Global extends android.provider.Settings.NameValueTable {
-    field public static final deprecated java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync";
+    field @Deprecated public static final String CONTACT_METADATA_SYNC = "contact_metadata_sync";
   }
 
   public static final class Settings.System extends android.provider.Settings.NameValueTable {
-    field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
-    field public static final java.lang.String VOLUME_ALARM = "volume_alarm";
-    field public static final java.lang.String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
-    field public static final java.lang.String VOLUME_MUSIC = "volume_music";
-    field public static final java.lang.String VOLUME_NOTIFICATION = "volume_notification";
-    field public static final java.lang.String VOLUME_RING = "volume_ring";
-    field public static final java.lang.String[] VOLUME_SETTINGS;
-    field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
-    field public static final java.lang.String VOLUME_VOICE = "volume_voice";
+    field public static final String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
+    field public static final String VOLUME_ALARM = "volume_alarm";
+    field public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
+    field public static final String VOLUME_MUSIC = "volume_music";
+    field public static final String VOLUME_NOTIFICATION = "volume_notification";
+    field public static final String VOLUME_RING = "volume_ring";
+    field public static final String[] VOLUME_SETTINGS;
+    field public static final String VOLUME_SYSTEM = "volume_system";
+    field public static final String VOLUME_VOICE = "volume_voice";
   }
 
   public static final class Telephony.Sms.Intents {
-    field public static final java.lang.String SMS_EMERGENCY_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
+    field public static final String SMS_EMERGENCY_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
   }
 
 }
@@ -533,7 +532,7 @@
 package android.speech.tts {
 
   public abstract class UtteranceProgressListener {
-    method public deprecated void onUtteranceRangeStart(java.lang.String, int, int);
+    method @Deprecated public void onUtteranceRangeStart(String, int, int);
   }
 
 }
@@ -541,12 +540,12 @@
 package android.telephony {
 
   public class NetworkScan {
-    method public deprecated void stop() throws android.os.RemoteException;
+    method @Deprecated public void stop() throws android.os.RemoteException;
   }
 
   public class TelephonyManager {
-    method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
-    method public deprecated android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, android.telephony.TelephonyScanManager.NetworkScanCallback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, android.telephony.TelephonyScanManager.NetworkScanCallback);
   }
 
 }
@@ -554,19 +553,19 @@
 package android.text.format {
 
   public class DateFormat {
-    field public static final deprecated char AM_PM = 97; // 0x0061 'a'
-    field public static final deprecated char CAPITAL_AM_PM = 65; // 0x0041 'A'
-    field public static final deprecated char DATE = 100; // 0x0064 'd'
-    field public static final deprecated char DAY = 69; // 0x0045 'E'
-    field public static final deprecated char HOUR = 104; // 0x0068 'h'
-    field public static final deprecated char HOUR_OF_DAY = 107; // 0x006b 'k'
-    field public static final deprecated char MINUTE = 109; // 0x006d 'm'
-    field public static final deprecated char MONTH = 77; // 0x004d 'M'
-    field public static final deprecated char QUOTE = 39; // 0x0027 '\''
-    field public static final deprecated char SECONDS = 115; // 0x0073 's'
-    field public static final deprecated char STANDALONE_MONTH = 76; // 0x004c 'L'
-    field public static final deprecated char TIME_ZONE = 122; // 0x007a 'z'
-    field public static final deprecated char YEAR = 121; // 0x0079 'y'
+    field @Deprecated public static final char AM_PM = 97; // 0x0061 'a'
+    field @Deprecated public static final char CAPITAL_AM_PM = 65; // 0x0041 'A'
+    field @Deprecated public static final char DATE = 100; // 0x0064 'd'
+    field @Deprecated public static final char DAY = 69; // 0x0045 'E'
+    field @Deprecated public static final char HOUR = 104; // 0x0068 'h'
+    field @Deprecated public static final char HOUR_OF_DAY = 107; // 0x006b 'k'
+    field @Deprecated public static final char MINUTE = 109; // 0x006d 'm'
+    field @Deprecated public static final char MONTH = 77; // 0x004d 'M'
+    field @Deprecated public static final char QUOTE = 39; // 0x0027 '\''
+    field @Deprecated public static final char SECONDS = 115; // 0x0073 's'
+    field @Deprecated public static final char STANDALONE_MONTH = 76; // 0x004c 'L'
+    field @Deprecated public static final char TIME_ZONE = 122; // 0x007a 'z'
+    field @Deprecated public static final char YEAR = 121; // 0x0079 'y'
   }
 
 }
@@ -583,7 +582,7 @@
 
 package android.util {
 
-  public deprecated class FloatMath {
+  @Deprecated public class FloatMath {
     method public static float ceil(float);
     method public static float cos(float);
     method public static float exp(float);
@@ -598,7 +597,7 @@
 
 package android.view {
 
-  public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
+  @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
     method protected void initializeFadingEdge(android.content.res.TypedArray);
     method protected void initializeScrollbars(android.content.res.TypedArray);
   }
@@ -623,12 +622,12 @@
 
 package android.widget {
 
-  public class ListView extends android.widget.AbsListView {
-    method protected <T extends android.view.View> T findViewTraversal(int);
-    method protected <T extends android.view.View> T findViewWithTagTraversal(java.lang.Object);
+  @android.widget.RemoteViews.RemoteView public class ListView extends android.widget.AbsListView {
+    method protected <T extends android.view.View> T findViewTraversal(@IdRes int);
+    method protected <T extends android.view.View> T findViewWithTagTraversal(Object);
   }
 
-  public class TextView extends android.view.View implements android.view.ViewTreeObserver.OnPreDrawListener {
+  @android.widget.RemoteViews.RemoteView public class TextView extends android.view.View implements android.view.ViewTreeObserver.OnPreDrawListener {
     method public static int getTextColor(android.content.Context, android.content.res.TypedArray, int);
     method public static android.content.res.ColorStateList getTextColors(android.content.Context, android.content.res.TypedArray);
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index e27c29f..3466e2e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1,200 +1,210 @@
+// Signature format: 2.0
 package android {
 
   public static final class Manifest.permission {
-    field public static final java.lang.String ACCESS_AMBIENT_LIGHT_STATS = "android.permission.ACCESS_AMBIENT_LIGHT_STATS";
-    field public static final java.lang.String ACCESS_BROADCAST_RADIO = "android.permission.ACCESS_BROADCAST_RADIO";
-    field public static final java.lang.String ACCESS_CACHE_FILESYSTEM = "android.permission.ACCESS_CACHE_FILESYSTEM";
-    field public static final java.lang.String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES";
-    field public static final deprecated java.lang.String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO";
-    field public static final java.lang.String ACCESS_INSTANT_APPS = "android.permission.ACCESS_INSTANT_APPS";
-    field public static final java.lang.String ACCESS_MOCK_LOCATION = "android.permission.ACCESS_MOCK_LOCATION";
-    field public static final java.lang.String ACCESS_MTP = "android.permission.ACCESS_MTP";
-    field public static final java.lang.String ACCESS_NETWORK_CONDITIONS = "android.permission.ACCESS_NETWORK_CONDITIONS";
-    field public static final java.lang.String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
-    field public static final java.lang.String ACCESS_SHORTCUTS = "android.permission.ACCESS_SHORTCUTS";
-    field public static final java.lang.String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
-    field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
-    field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
-    field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
-    field public static final java.lang.String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
-    field public static final java.lang.String BACKUP = "android.permission.BACKUP";
-    field public static final java.lang.String BIND_AUGMENTED_AUTOFILL_SERVICE = "android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE";
-    field public static final deprecated java.lang.String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
-    field public static final java.lang.String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE";
-    field public static final java.lang.String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH";
-    field public static final java.lang.String BIND_EUICC_SERVICE = "android.permission.BIND_EUICC_SERVICE";
-    field public static final java.lang.String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE";
-    field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
-    field public static final java.lang.String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE";
-    field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
-    field public static final java.lang.String BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE = "android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE";
-    field public static final java.lang.String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
-    field public static final java.lang.String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
-    field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
-    field public static final java.lang.String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE";
-    field public static final java.lang.String BIND_SOUND_TRIGGER_DETECTION_SERVICE = "android.permission.BIND_SOUND_TRIGGER_DETECTION_SERVICE";
-    field public static final java.lang.String BIND_TELEPHONY_DATA_SERVICE = "android.permission.BIND_TELEPHONY_DATA_SERVICE";
-    field public static final java.lang.String BIND_TELEPHONY_NETWORK_SERVICE = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE";
-    field public static final java.lang.String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE";
-    field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
-    field public static final java.lang.String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
-    field public static final java.lang.String BRICK = "android.permission.BRICK";
-    field public static final java.lang.String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
-    field public static final deprecated java.lang.String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED";
-    field public static final java.lang.String CAMERA_DISABLE_TRANSMIT_LED = "android.permission.CAMERA_DISABLE_TRANSMIT_LED";
-    field public static final java.lang.String CAPTURE_AUDIO_HOTWORD = "android.permission.CAPTURE_AUDIO_HOTWORD";
-    field public static final java.lang.String CAPTURE_TV_INPUT = "android.permission.CAPTURE_TV_INPUT";
-    field public static final java.lang.String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
-    field public static final java.lang.String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST";
-    field public static final java.lang.String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
-    field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
-    field public static final java.lang.String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL";
-    field public static final java.lang.String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS";
-    field public static final java.lang.String CONTROL_DISPLAY_COLOR_TRANSFORMS = "android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS";
-    field public static final java.lang.String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
-    field public static final java.lang.String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE";
-    field public static final java.lang.String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS";
-    field public static final java.lang.String CONTROL_VPN = "android.permission.CONTROL_VPN";
-    field public static final java.lang.String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER";
-    field public static final java.lang.String DEVICE_POWER = "android.permission.DEVICE_POWER";
-    field public static final java.lang.String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE";
-    field public static final java.lang.String FORCE_BACK = "android.permission.FORCE_BACK";
-    field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
-    field public static final java.lang.String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
-    field public static final java.lang.String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE";
-    field public static final java.lang.String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
-    field public static final java.lang.String GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS = "android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS";
-    field public static final java.lang.String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS";
-    field public static final java.lang.String HARDWARE_TEST = "android.permission.HARDWARE_TEST";
-    field public static final java.lang.String HDMI_CEC = "android.permission.HDMI_CEC";
-    field public static final java.lang.String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS";
-    field public static final java.lang.String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
-    field public static final java.lang.String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
-    field public static final java.lang.String INSTALL_PACKAGE_UPDATES = "android.permission.INSTALL_PACKAGE_UPDATES";
-    field public static final java.lang.String INSTALL_SELF_UPDATES = "android.permission.INSTALL_SELF_UPDATES";
-    field public static final java.lang.String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
-    field public static final java.lang.String INTERACT_ACROSS_PROFILES = "android.permission.INTERACT_ACROSS_PROFILES";
-    field public static final java.lang.String INTERACT_ACROSS_USERS = "android.permission.INTERACT_ACROSS_USERS";
-    field public static final java.lang.String INTERACT_ACROSS_USERS_FULL = "android.permission.INTERACT_ACROSS_USERS_FULL";
-    field public static final java.lang.String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
-    field public static final java.lang.String INVOKE_CARRIER_SETUP = "android.permission.INVOKE_CARRIER_SETUP";
-    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 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_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY";
-    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";
-    field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
-    field public static final java.lang.String MANAGE_AUTO_FILL = "android.permission.MANAGE_AUTO_FILL";
-    field public static final java.lang.String MANAGE_CARRIER_OEM_UNLOCK_STATE = "android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE";
-    field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
-    field public static final java.lang.String MANAGE_CONTENT_CAPTURE = "android.permission.MANAGE_CONTENT_CAPTURE";
-    field public static final java.lang.String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
-    field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
-    field public static final java.lang.String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
-    field public static final java.lang.String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
-    field public static final java.lang.String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
-    field public static final java.lang.String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
-    field public static final java.lang.String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
-    field public static final java.lang.String MANAGE_USB = "android.permission.MANAGE_USB";
-    field public static final java.lang.String MANAGE_USERS = "android.permission.MANAGE_USERS";
-    field public static final java.lang.String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
-    field public static final java.lang.String MODIFY_APPWIDGET_BIND_PERMISSIONS = "android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS";
-    field public static final java.lang.String MODIFY_AUDIO_ROUTING = "android.permission.MODIFY_AUDIO_ROUTING";
-    field public static final java.lang.String MODIFY_CELL_BROADCASTS = "android.permission.MODIFY_CELL_BROADCASTS";
-    field public static final java.lang.String MODIFY_DAY_NIGHT_MODE = "android.permission.MODIFY_DAY_NIGHT_MODE";
-    field public static final deprecated java.lang.String MODIFY_NETWORK_ACCOUNTING = "android.permission.MODIFY_NETWORK_ACCOUNTING";
-    field public static final java.lang.String MODIFY_PARENTAL_CONTROLS = "android.permission.MODIFY_PARENTAL_CONTROLS";
-    field public static final java.lang.String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE";
-    field public static final java.lang.String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
-    field public static final java.lang.String NETWORK_MANAGED_PROVISIONING = "android.permission.NETWORK_MANAGED_PROVISIONING";
-    field public static final java.lang.String NETWORK_SETUP_WIZARD = "android.permission.NETWORK_SETUP_WIZARD";
-    field public static final java.lang.String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
-    field public static final java.lang.String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
-    field public static final java.lang.String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
-    field public static final java.lang.String OBSERVE_ROLE_HOLDERS = "android.permission.OBSERVE_ROLE_HOLDERS";
-    field public static final java.lang.String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
-    field public static final java.lang.String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
-    field public static final java.lang.String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS";
-    field public static final java.lang.String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING";
-    field public static final java.lang.String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION";
-    field public static final java.lang.String POWER_SAVER = "android.permission.POWER_SAVER";
-    field public static final java.lang.String PROVIDE_RESOLVER_RANKER_SERVICE = "android.permission.PROVIDE_RESOLVER_RANKER_SERVICE";
-    field public static final java.lang.String PROVIDE_TRUST_AGENT = "android.permission.PROVIDE_TRUST_AGENT";
-    field public static final java.lang.String QUERY_TIME_ZONE_RULES = "android.permission.QUERY_TIME_ZONE_RULES";
-    field public static final java.lang.String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
-    field public static final java.lang.String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
-    field public static final java.lang.String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
-    field public static final java.lang.String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS";
-    field public static final java.lang.String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
-    field public static final java.lang.String READ_OEM_UNLOCK_STATE = "android.permission.READ_OEM_UNLOCK_STATE";
-    field public static final java.lang.String READ_PRINT_SERVICES = "android.permission.READ_PRINT_SERVICES";
-    field public static final java.lang.String READ_PRINT_SERVICE_RECOMMENDATIONS = "android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS";
-    field public static final java.lang.String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
-    field public static final java.lang.String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES";
-    field public static final java.lang.String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
-    field public static final java.lang.String READ_SYSTEM_UPDATE_INFO = "android.permission.READ_SYSTEM_UPDATE_INFO";
-    field public static final java.lang.String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL";
-    field public static final java.lang.String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL";
-    field public static final java.lang.String REAL_GET_TASKS = "android.permission.REAL_GET_TASKS";
-    field public static final java.lang.String RECEIVE_DATA_ACTIVITY_CHANGE = "android.permission.RECEIVE_DATA_ACTIVITY_CHANGE";
-    field public static final java.lang.String RECEIVE_DEVICE_CUSTOMIZATION_READY = "android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY";
-    field public static final java.lang.String RECEIVE_EMERGENCY_BROADCAST = "android.permission.RECEIVE_EMERGENCY_BROADCAST";
-    field public static final java.lang.String RECEIVE_WIFI_CREDENTIAL_CHANGE = "android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE";
-    field public static final java.lang.String RECOVERY = "android.permission.RECOVERY";
-    field public static final java.lang.String RECOVER_KEYSTORE = "android.permission.RECOVER_KEYSTORE";
-    field public static final java.lang.String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER";
-    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 REMOVE_TASKS = "android.permission.REMOVE_TASKS";
-    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";
-    field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
-    field public static final java.lang.String SEND_DEVICE_CUSTOMIZATION_READY = "android.permission.SEND_DEVICE_CUSTOMIZATION_READY";
-    field public static final java.lang.String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS";
-    field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
-    field public static final java.lang.String SERIAL_PORT = "android.permission.SERIAL_PORT";
-    field public static final java.lang.String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
-    field public static final java.lang.String SET_HARMFUL_APP_WARNINGS = "android.permission.SET_HARMFUL_APP_WARNINGS";
-    field public static final java.lang.String SET_MEDIA_KEY_LISTENER = "android.permission.SET_MEDIA_KEY_LISTENER";
-    field public static final java.lang.String SET_ORIENTATION = "android.permission.SET_ORIENTATION";
-    field public static final java.lang.String SET_POINTER_SPEED = "android.permission.SET_POINTER_SPEED";
-    field public static final java.lang.String SET_SCREEN_COMPATIBILITY = "android.permission.SET_SCREEN_COMPATIBILITY";
-    field public static final java.lang.String SET_VOLUME_KEY_LONG_PRESS_LISTENER = "android.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER";
-    field public static final java.lang.String SET_WALLPAPER_COMPONENT = "android.permission.SET_WALLPAPER_COMPONENT";
-    field public static final java.lang.String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE";
-    field public static final java.lang.String SHUTDOWN = "android.permission.SHUTDOWN";
-    field public static final java.lang.String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
-    field public static final java.lang.String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
-    field public static final java.lang.String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
-    field public static final java.lang.String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
-    field public static final java.lang.String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
-    field public static final java.lang.String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER";
-    field public static final java.lang.String UNLIMITED_SHORTCUTS_API_CALLS = "android.permission.UNLIMITED_SHORTCUTS_API_CALLS";
-    field public static final java.lang.String UPDATE_APP_OPS_STATS = "android.permission.UPDATE_APP_OPS_STATS";
-    field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
-    field public static final java.lang.String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
-    field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
-    field public static final java.lang.String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
-    field public static final java.lang.String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
-    field public static final java.lang.String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
-    field public static final java.lang.String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
-    field public static final java.lang.String WRITE_OBB = "android.permission.WRITE_OBB";
+    field public static final String ACCESS_AMBIENT_LIGHT_STATS = "android.permission.ACCESS_AMBIENT_LIGHT_STATS";
+    field public static final String ACCESS_BROADCAST_RADIO = "android.permission.ACCESS_BROADCAST_RADIO";
+    field public static final String ACCESS_CACHE_FILESYSTEM = "android.permission.ACCESS_CACHE_FILESYSTEM";
+    field public static final String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES";
+    field @Deprecated public static final String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO";
+    field public static final String ACCESS_INSTANT_APPS = "android.permission.ACCESS_INSTANT_APPS";
+    field public static final String ACCESS_MOCK_LOCATION = "android.permission.ACCESS_MOCK_LOCATION";
+    field public static final String ACCESS_MTP = "android.permission.ACCESS_MTP";
+    field public static final String ACCESS_NETWORK_CONDITIONS = "android.permission.ACCESS_NETWORK_CONDITIONS";
+    field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
+    field public static final String ACCESS_SHORTCUTS = "android.permission.ACCESS_SHORTCUTS";
+    field public static final String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
+    field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
+    field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
+    field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
+    field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
+    field public static final String BACKUP = "android.permission.BACKUP";
+    field public static final String BIND_ATTENTION_SERVICE = "android.permission.BIND_ATTENTION_SERVICE";
+    field public static final String BIND_AUGMENTED_AUTOFILL_SERVICE = "android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE";
+    field @Deprecated public static final String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
+    field public static final String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE";
+    field public static final String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH";
+    field public static final String BIND_EUICC_SERVICE = "android.permission.BIND_EUICC_SERVICE";
+    field public static final String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE";
+    field public static final String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
+    field public static final String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE";
+    field public static final String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
+    field public static final String BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE = "android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE";
+    field public static final String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
+    field public static final String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
+    field public static final String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
+    field public static final String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE";
+    field public static final String BIND_SOUND_TRIGGER_DETECTION_SERVICE = "android.permission.BIND_SOUND_TRIGGER_DETECTION_SERVICE";
+    field public static final String BIND_TELEPHONY_DATA_SERVICE = "android.permission.BIND_TELEPHONY_DATA_SERVICE";
+    field public static final String BIND_TELEPHONY_NETWORK_SERVICE = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE";
+    field public static final String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE";
+    field public static final String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
+    field public static final String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
+    field public static final String BRICK = "android.permission.BRICK";
+    field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
+    field @Deprecated public static final String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED";
+    field public static final String CAMERA_DISABLE_TRANSMIT_LED = "android.permission.CAMERA_DISABLE_TRANSMIT_LED";
+    field public static final String CAPTURE_AUDIO_HOTWORD = "android.permission.CAPTURE_AUDIO_HOTWORD";
+    field public static final String CAPTURE_TV_INPUT = "android.permission.CAPTURE_TV_INPUT";
+    field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
+    field public static final String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST";
+    field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
+    field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
+    field public static final String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL";
+    field public static final String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS";
+    field public static final String CONTROL_DISPLAY_COLOR_TRANSFORMS = "android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS";
+    field public static final String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
+    field public static final String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE";
+    field public static final String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS";
+    field public static final String CONTROL_VPN = "android.permission.CONTROL_VPN";
+    field public static final String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER";
+    field public static final String DEVICE_POWER = "android.permission.DEVICE_POWER";
+    field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE";
+    field public static final String FORCE_BACK = "android.permission.FORCE_BACK";
+    field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
+    field public static final String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
+    field public static final String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE";
+    field public static final String GET_RUNTIME_PERMISSIONS = "android.permission.GET_RUNTIME_PERMISSIONS";
+    field public static final String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
+    field public static final String GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS = "android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS";
+    field public static final String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS";
+    field public static final String HARDWARE_TEST = "android.permission.HARDWARE_TEST";
+    field public static final String HDMI_CEC = "android.permission.HDMI_CEC";
+    field public static final String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS";
+    field public static final String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
+    field public static final String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
+    field public static final String INSTALL_PACKAGE_UPDATES = "android.permission.INSTALL_PACKAGE_UPDATES";
+    field public static final String INSTALL_SELF_UPDATES = "android.permission.INSTALL_SELF_UPDATES";
+    field public static final String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
+    field public static final String INTERACT_ACROSS_PROFILES = "android.permission.INTERACT_ACROSS_PROFILES";
+    field public static final String INTERACT_ACROSS_USERS = "android.permission.INTERACT_ACROSS_USERS";
+    field public static final String INTERACT_ACROSS_USERS_FULL = "android.permission.INTERACT_ACROSS_USERS_FULL";
+    field public static final String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
+    field public static final String INVOKE_CARRIER_SETUP = "android.permission.INVOKE_CARRIER_SETUP";
+    field public static final String KILL_UID = "android.permission.KILL_UID";
+    field public static final String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS";
+    field public static final String LOCK_DEVICE = "android.permission.LOCK_DEVICE";
+    field public static final String LOOP_RADIO = "android.permission.LOOP_RADIO";
+    field public static final String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY";
+    field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
+    field public static final String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
+    field public static final String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS";
+    field public static final String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
+    field public static final String MANAGE_AUTO_FILL = "android.permission.MANAGE_AUTO_FILL";
+    field public static final String MANAGE_CARRIER_OEM_UNLOCK_STATE = "android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE";
+    field public static final String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
+    field public static final String MANAGE_CONTENT_CAPTURE = "android.permission.MANAGE_CONTENT_CAPTURE";
+    field public static final String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
+    field public static final String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
+    field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
+    field public static final String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
+    field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
+    field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
+    field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
+    field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
+    field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
+    field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
+    field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
+    field public static final String MODIFY_APPWIDGET_BIND_PERMISSIONS = "android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS";
+    field public static final String MODIFY_AUDIO_ROUTING = "android.permission.MODIFY_AUDIO_ROUTING";
+    field public static final String MODIFY_CELL_BROADCASTS = "android.permission.MODIFY_CELL_BROADCASTS";
+    field public static final String MODIFY_DAY_NIGHT_MODE = "android.permission.MODIFY_DAY_NIGHT_MODE";
+    field @Deprecated public static final String MODIFY_NETWORK_ACCOUNTING = "android.permission.MODIFY_NETWORK_ACCOUNTING";
+    field public static final String MODIFY_PARENTAL_CONTROLS = "android.permission.MODIFY_PARENTAL_CONTROLS";
+    field public static final String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE";
+    field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
+    field public static final String NETWORK_MANAGED_PROVISIONING = "android.permission.NETWORK_MANAGED_PROVISIONING";
+    field public static final String NETWORK_SETUP_WIZARD = "android.permission.NETWORK_SETUP_WIZARD";
+    field public static final String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
+    field public static final String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
+    field public static final String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
+    field public static final String OBSERVE_ROLE_HOLDERS = "android.permission.OBSERVE_ROLE_HOLDERS";
+    field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
+    field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
+    field public static final String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS";
+    field public static final String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING";
+    field public static final String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION";
+    field public static final String POWER_SAVER = "android.permission.POWER_SAVER";
+    field public static final String PROVIDE_RESOLVER_RANKER_SERVICE = "android.permission.PROVIDE_RESOLVER_RANKER_SERVICE";
+    field public static final String PROVIDE_TRUST_AGENT = "android.permission.PROVIDE_TRUST_AGENT";
+    field public static final String QUERY_TIME_ZONE_RULES = "android.permission.QUERY_TIME_ZONE_RULES";
+    field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
+    field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
+    field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
+    field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
+    field public static final String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS";
+    field public static final String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
+    field public static final String READ_OEM_UNLOCK_STATE = "android.permission.READ_OEM_UNLOCK_STATE";
+    field public static final String READ_PRINT_SERVICES = "android.permission.READ_PRINT_SERVICES";
+    field public static final String READ_PRINT_SERVICE_RECOMMENDATIONS = "android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS";
+    field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
+    field public static final String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES";
+    field public static final String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
+    field public static final String READ_SYSTEM_UPDATE_INFO = "android.permission.READ_SYSTEM_UPDATE_INFO";
+    field public static final String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL";
+    field public static final String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL";
+    field public static final String REAL_GET_TASKS = "android.permission.REAL_GET_TASKS";
+    field public static final String RECEIVE_DATA_ACTIVITY_CHANGE = "android.permission.RECEIVE_DATA_ACTIVITY_CHANGE";
+    field public static final String RECEIVE_DEVICE_CUSTOMIZATION_READY = "android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY";
+    field public static final String RECEIVE_EMERGENCY_BROADCAST = "android.permission.RECEIVE_EMERGENCY_BROADCAST";
+    field public static final String RECEIVE_WIFI_CREDENTIAL_CHANGE = "android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE";
+    field public static final String RECOVERY = "android.permission.RECOVERY";
+    field public static final String RECOVER_KEYSTORE = "android.permission.RECOVER_KEYSTORE";
+    field public static final String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER";
+    field public static final String REGISTER_CONNECTION_MANAGER = "android.permission.REGISTER_CONNECTION_MANAGER";
+    field public static final String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
+    field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
+    field public static final String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
+    field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+    field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
+    field public static final String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
+    field public static final String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
+    field public static final String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
+    field public static final String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
+    field public static final String SEND_DEVICE_CUSTOMIZATION_READY = "android.permission.SEND_DEVICE_CUSTOMIZATION_READY";
+    field public static final String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS";
+    field public static final String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
+    field public static final String SERIAL_PORT = "android.permission.SERIAL_PORT";
+    field public static final String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
+    field public static final String SET_HARMFUL_APP_WARNINGS = "android.permission.SET_HARMFUL_APP_WARNINGS";
+    field public static final String SET_MEDIA_KEY_LISTENER = "android.permission.SET_MEDIA_KEY_LISTENER";
+    field public static final String SET_ORIENTATION = "android.permission.SET_ORIENTATION";
+    field public static final String SET_POINTER_SPEED = "android.permission.SET_POINTER_SPEED";
+    field public static final String SET_SCREEN_COMPATIBILITY = "android.permission.SET_SCREEN_COMPATIBILITY";
+    field public static final String SET_VOLUME_KEY_LONG_PRESS_LISTENER = "android.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER";
+    field public static final String SET_WALLPAPER_COMPONENT = "android.permission.SET_WALLPAPER_COMPONENT";
+    field public static final String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE";
+    field public static final String SHUTDOWN = "android.permission.SHUTDOWN";
+    field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
+    field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
+    field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
+    field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
+    field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
+    field public static final String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER";
+    field public static final String UNLIMITED_SHORTCUTS_API_CALLS = "android.permission.UNLIMITED_SHORTCUTS_API_CALLS";
+    field public static final String UPDATE_APP_OPS_STATS = "android.permission.UPDATE_APP_OPS_STATS";
+    field public static final String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
+    field public static final String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
+    field public static final String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
+    field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
+    field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
+    field public static final String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
+    field public static final String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
+    field public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
+    field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
   }
 
   public static final class Manifest.permission_group {
-    field public static final java.lang.String UNDEFINED = "android.permission-group.UNDEFINED";
+    field public static final String UNDEFINED = "android.permission-group.UNDEFINED";
   }
 
   public static final class R.array {
+    field public static final int config_defaultRoleHolders = 17235974; // 0x1070006
     field public static final int config_keySystemUuidMapping = 17235973; // 0x1070005
   }
 
   public static final class R.attr {
+    field public static final int inheritShowWhenLocked = 16844194; // 0x10105a2
     field public static final int isVrOnly = 16844152; // 0x1010578
     field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
     field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
@@ -234,6 +244,7 @@
   }
 
   public static final class R.style {
+    field public static final int Theme_DeviceDefault_DocumentsUI = 16974562; // 0x10302e2
     field public static final int Theme_Leanback_FormWizard = 16974544; // 0x10302d0
   }
 
@@ -242,7 +253,7 @@
 package android.accounts {
 
   public class AccountManager {
-    method public android.accounts.AccountManagerFuture<android.os.Bundle> finishSessionAsUser(android.os.Bundle, android.app.Activity, android.os.UserHandle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.accounts.AccountManagerFuture<android.os.Bundle> finishSessionAsUser(android.os.Bundle, android.app.Activity, android.os.UserHandle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
   }
 
 }
@@ -252,87 +263,89 @@
   public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback {
     method public void convertFromTranslucent();
     method public boolean convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions);
-    method public deprecated boolean isBackgroundVisibleBehind();
-    method public deprecated void onBackgroundVisibleBehindChanged(boolean);
+    method @Deprecated public boolean isBackgroundVisibleBehind();
+    method @Deprecated public void onBackgroundVisibleBehindChanged(boolean);
+    method public void setInheritShowWhenLocked(boolean);
   }
 
-  public static abstract interface Activity.TranslucentConversionListener {
-    method public abstract void onTranslucentConversionComplete(boolean);
+  public static interface Activity.TranslucentConversionListener {
+    method public void onTranslucentConversionComplete(boolean);
   }
 
   public class ActivityManager {
-    method public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
-    method public void forceStopPackage(java.lang.String);
-    method public static int getCurrentUser();
-    method public int getPackageImportance(java.lang.String);
-    method public int getUidImportance(int);
-    method public void killUid(int, java.lang.String);
-    method public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
-    method public static void setPersistentVrThread(int);
-    method public boolean switchUser(android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
+    method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
+    method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public static int getCurrentUser();
+    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
+    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
+    method @RequiresPermission(android.Manifest.permission.KILL_UID) public void killUid(int, String);
+    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
+    method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public static void setPersistentVrThread(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean switchUser(@NonNull android.os.UserHandle);
   }
 
-  public static abstract interface ActivityManager.OnUidImportanceListener {
-    method public abstract void onUidImportance(int, int);
+  public static interface ActivityManager.OnUidImportanceListener {
+    method public void onUidImportance(int, int);
   }
 
   public class AlarmManager {
-    method public void set(int, long, long, long, android.app.PendingIntent, android.os.WorkSource);
-    method public void set(int, long, long, long, android.app.AlarmManager.OnAlarmListener, android.os.Handler, android.os.WorkSource);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, android.app.PendingIntent, android.os.WorkSource);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, android.app.AlarmManager.OnAlarmListener, android.os.Handler, android.os.WorkSource);
   }
 
   public class AppOpsManager {
-    method public java.util.List<android.app.AppOpsManager.HistoricalPackageOps> getAllHistoricPackagesOps(java.lang.String[], long, long);
-    method public android.app.AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int, java.lang.String, java.lang.String[], long, long);
-    method public static java.lang.String[] getOpStrs();
-    method public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, int[]);
-    method public static int opToDefaultMode(java.lang.String);
-    method public static java.lang.String opToPermission(java.lang.String);
-    method public void setMode(java.lang.String, int, java.lang.String, int);
-    method public void setUidMode(java.lang.String, int, int);
-    field public static final java.lang.String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
-    field public static final java.lang.String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
-    field public static final java.lang.String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
-    field public static final java.lang.String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
-    field public static final java.lang.String OPSTR_ASSIST_STRUCTURE = "android:assist_structure";
-    field public static final java.lang.String OPSTR_AUDIO_ACCESSIBILITY_VOLUME = "android:audio_accessibility_volume";
-    field public static final java.lang.String OPSTR_AUDIO_ALARM_VOLUME = "android:audio_alarm_volume";
-    field public static final java.lang.String OPSTR_AUDIO_BLUETOOTH_VOLUME = "android:audio_bluetooth_volume";
-    field public static final java.lang.String OPSTR_AUDIO_MASTER_VOLUME = "android:audio_master_volume";
-    field public static final java.lang.String OPSTR_AUDIO_MEDIA_VOLUME = "android:audio_media_volume";
-    field public static final java.lang.String OPSTR_AUDIO_NOTIFICATION_VOLUME = "android:audio_notification_volume";
-    field public static final java.lang.String OPSTR_AUDIO_RING_VOLUME = "android:audio_ring_volume";
-    field public static final java.lang.String OPSTR_AUDIO_VOICE_VOLUME = "android:audio_voice_volume";
-    field public static final java.lang.String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service";
-    field public static final java.lang.String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state";
-    field public static final java.lang.String OPSTR_GET_ACCOUNTS = "android:get_accounts";
-    field public static final java.lang.String OPSTR_GPS = "android:gps";
-    field public static final java.lang.String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
-    field public static final java.lang.String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
-    field public static final java.lang.String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
-    field public static final java.lang.String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
-    field public static final java.lang.String OPSTR_PLAY_AUDIO = "android:play_audio";
-    field public static final java.lang.String OPSTR_POST_NOTIFICATION = "android:post_notification";
-    field public static final java.lang.String OPSTR_PROJECT_MEDIA = "android:project_media";
-    field public static final java.lang.String OPSTR_READ_CLIPBOARD = "android:read_clipboard";
-    field public static final java.lang.String OPSTR_READ_ICC_SMS = "android:read_icc_sms";
-    field public static final java.lang.String OPSTR_RECEIVE_EMERGENCY_BROADCAST = "android:receive_emergency_broadcast";
-    field public static final java.lang.String OPSTR_REQUEST_DELETE_PACKAGES = "android:request_delete_packages";
-    field public static final java.lang.String OPSTR_REQUEST_INSTALL_PACKAGES = "android:request_install_packages";
-    field public static final java.lang.String OPSTR_RUN_ANY_IN_BACKGROUND = "android:run_any_in_background";
-    field public static final java.lang.String OPSTR_RUN_IN_BACKGROUND = "android:run_in_background";
-    field public static final java.lang.String OPSTR_START_FOREGROUND = "android:start_foreground";
-    field public static final java.lang.String OPSTR_TAKE_AUDIO_FOCUS = "android:take_audio_focus";
-    field public static final java.lang.String OPSTR_TAKE_MEDIA_BUTTONS = "android:take_media_buttons";
-    field public static final java.lang.String OPSTR_TOAST_WINDOW = "android:toast_window";
-    field public static final java.lang.String OPSTR_TURN_SCREEN_ON = "android:turn_screen_on";
-    field public static final java.lang.String OPSTR_VIBRATE = "android:vibrate";
-    field public static final java.lang.String OPSTR_WAKE_LOCK = "android:wake_lock";
-    field public static final java.lang.String OPSTR_WIFI_SCAN = "android:wifi_scan";
-    field public static final java.lang.String OPSTR_WRITE_CLIPBOARD = "android:write_clipboard";
-    field public static final java.lang.String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms";
-    field public static final java.lang.String OPSTR_WRITE_SMS = "android:write_sms";
-    field public static final java.lang.String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper";
+    method @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public void getHistoricalOps(int, @Nullable String, @Nullable String[], long, long, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
+    method public static String[] getOpStrs();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, String, int[]);
+    method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable java.lang.String...);
+    method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[]);
+    method public static int opToDefaultMode(@NonNull String);
+    method @Nullable public static String opToPermission(@NonNull String);
+    method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(String, int, String, int);
+    method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(String, int, int);
+    field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
+    field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
+    field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
+    field public static final String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
+    field public static final String OPSTR_ASSIST_STRUCTURE = "android:assist_structure";
+    field public static final String OPSTR_AUDIO_ACCESSIBILITY_VOLUME = "android:audio_accessibility_volume";
+    field public static final String OPSTR_AUDIO_ALARM_VOLUME = "android:audio_alarm_volume";
+    field public static final String OPSTR_AUDIO_BLUETOOTH_VOLUME = "android:audio_bluetooth_volume";
+    field public static final String OPSTR_AUDIO_MASTER_VOLUME = "android:audio_master_volume";
+    field public static final String OPSTR_AUDIO_MEDIA_VOLUME = "android:audio_media_volume";
+    field public static final String OPSTR_AUDIO_NOTIFICATION_VOLUME = "android:audio_notification_volume";
+    field public static final String OPSTR_AUDIO_RING_VOLUME = "android:audio_ring_volume";
+    field public static final String OPSTR_AUDIO_VOICE_VOLUME = "android:audio_voice_volume";
+    field public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service";
+    field public static final String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state";
+    field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts";
+    field public static final String OPSTR_GPS = "android:gps";
+    field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
+    field public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
+    field public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
+    field public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
+    field public static final String OPSTR_PLAY_AUDIO = "android:play_audio";
+    field public static final String OPSTR_POST_NOTIFICATION = "android:post_notification";
+    field public static final String OPSTR_PROJECT_MEDIA = "android:project_media";
+    field public static final String OPSTR_READ_CLIPBOARD = "android:read_clipboard";
+    field public static final String OPSTR_READ_ICC_SMS = "android:read_icc_sms";
+    field public static final String OPSTR_RECEIVE_EMERGENCY_BROADCAST = "android:receive_emergency_broadcast";
+    field public static final String OPSTR_REQUEST_DELETE_PACKAGES = "android:request_delete_packages";
+    field public static final String OPSTR_REQUEST_INSTALL_PACKAGES = "android:request_install_packages";
+    field public static final String OPSTR_RUN_ANY_IN_BACKGROUND = "android:run_any_in_background";
+    field public static final String OPSTR_RUN_IN_BACKGROUND = "android:run_in_background";
+    field public static final String OPSTR_START_FOREGROUND = "android:start_foreground";
+    field public static final String OPSTR_TAKE_AUDIO_FOCUS = "android:take_audio_focus";
+    field public static final String OPSTR_TAKE_MEDIA_BUTTONS = "android:take_media_buttons";
+    field public static final String OPSTR_TOAST_WINDOW = "android:toast_window";
+    field public static final String OPSTR_TURN_SCREEN_ON = "android:turn_screen_on";
+    field public static final String OPSTR_VIBRATE = "android:vibrate";
+    field public static final String OPSTR_WAKE_LOCK = "android:wake_lock";
+    field public static final String OPSTR_WIFI_SCAN = "android:wifi_scan";
+    field public static final String OPSTR_WRITE_CLIPBOARD = "android:write_clipboard";
+    field public static final String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms";
+    field public static final String OPSTR_WRITE_SMS = "android:write_sms";
+    field public static final String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper";
     field public static final int UID_STATE_BACKGROUND = 4; // 0x4
     field public static final int UID_STATE_CACHED = 5; // 0x5
     field public static final int UID_STATE_FOREGROUND = 3; // 0x3
@@ -341,7 +354,7 @@
     field public static final int UID_STATE_TOP = 1; // 0x1
   }
 
-  public static final class AppOpsManager.HistoricalOpEntry implements android.os.Parcelable {
+  public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
     method public int describeContents();
     method public long getAccessCount(int);
     method public long getAccessDuration(int);
@@ -351,21 +364,41 @@
     method public long getForegroundAccessCount();
     method public long getForegroundAccessDuration();
     method public long getForegroundRejectCount();
-    method public java.lang.String getOp();
+    method @NonNull public String getOpName();
     method public long getRejectCount(int);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOpEntry> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOp> CREATOR;
+  }
+
+  public static final class AppOpsManager.HistoricalOps implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getBeginTimeMillis();
+    method public long getEndTimeMillis();
+    method public int getUidCount();
+    method @Nullable public android.app.AppOpsManager.HistoricalUidOps getUidOps(int);
+    method @NonNull public android.app.AppOpsManager.HistoricalUidOps getUidOpsAt(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
   }
 
   public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
     method public int describeContents();
-    method public android.app.AppOpsManager.HistoricalOpEntry getEntry(java.lang.String);
-    method public android.app.AppOpsManager.HistoricalOpEntry getEntryAt(int);
-    method public int getEntryCount();
-    method public java.lang.String getPackageName();
+    method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
+    method @NonNull public android.app.AppOpsManager.HistoricalOp getOpAt(int);
+    method public int getOpCount();
+    method @NonNull public String getPackageName();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalPackageOps> CREATOR;
+  }
+
+  public static final class AppOpsManager.HistoricalUidOps implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getPackageCount();
+    method @Nullable public android.app.AppOpsManager.HistoricalPackageOps getPackageOps(@NonNull String);
+    method @NonNull public android.app.AppOpsManager.HistoricalPackageOps getPackageOpsAt(int);
     method public int getUid();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalPackageOps> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalUidOps> CREATOR;
   }
 
   public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
@@ -378,8 +411,8 @@
     method public long getLastRejectForegroundTime();
     method public long getLastRejectTime();
     method public int getMode();
-    method public java.lang.String getOpStr();
-    method public java.lang.String getProxyPackageName();
+    method public String getOpStr();
+    method public String getProxyPackageName();
     method public int getProxyUid();
     method public boolean isRunning();
     method public void writeToParcel(android.os.Parcel, int);
@@ -389,7 +422,7 @@
   public static final class AppOpsManager.PackageOps implements android.os.Parcelable {
     method public int describeContents();
     method public java.util.List<android.app.AppOpsManager.OpEntry> getOps();
-    method public java.lang.String getPackageName();
+    method public String getPackageName();
     method public int getUid();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.PackageOps> CREATOR;
@@ -398,24 +431,24 @@
   public class BroadcastOptions {
     method public static android.app.BroadcastOptions makeBasic();
     method public void setDontSendToRestrictedApps(boolean);
-    method public void setTemporaryAppWhitelistDuration(long);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void setTemporaryAppWhitelistDuration(long);
     method public android.os.Bundle toBundle();
   }
 
   public class DownloadManager {
-    field public static final java.lang.String ACTION_DOWNLOAD_COMPLETED = "android.intent.action.DOWNLOAD_COMPLETED";
+    field public static final String ACTION_DOWNLOAD_COMPLETED = "android.intent.action.DOWNLOAD_COMPLETED";
   }
 
   public abstract class InstantAppResolverService extends android.app.Service {
     ctor public InstantAppResolverService();
     method public final void attachBaseContext(android.content.Context);
     method public final android.os.IBinder onBind(android.content.Intent);
-    method public deprecated void onGetInstantAppIntentFilter(int[], java.lang.String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
-    method public deprecated void onGetInstantAppIntentFilter(android.content.Intent, int[], java.lang.String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
-    method public void onGetInstantAppIntentFilter(android.content.Intent, int[], android.os.UserHandle, java.lang.String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
-    method public deprecated void onGetInstantAppResolveInfo(int[], java.lang.String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
-    method public deprecated void onGetInstantAppResolveInfo(android.content.Intent, int[], java.lang.String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
-    method public void onGetInstantAppResolveInfo(android.content.Intent, int[], android.os.UserHandle, java.lang.String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
+    method @Deprecated public void onGetInstantAppIntentFilter(int[], String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
+    method @Deprecated public void onGetInstantAppIntentFilter(android.content.Intent, int[], String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
+    method public void onGetInstantAppIntentFilter(android.content.Intent, int[], android.os.UserHandle, String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
+    method @Deprecated public void onGetInstantAppResolveInfo(int[], String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
+    method @Deprecated public void onGetInstantAppResolveInfo(android.content.Intent, int[], String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
+    method public void onGetInstantAppResolveInfo(android.content.Intent, int[], android.os.UserHandle, String, android.app.InstantAppResolverService.InstantAppResolutionCallback);
   }
 
   public static final class InstantAppResolverService.InstantAppResolutionCallback {
@@ -423,18 +456,18 @@
   }
 
   public class KeyguardManager {
-    method public android.content.Intent createConfirmFactoryResetCredentialIntent(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
-    method public boolean getPrivateNotificationsAllowed();
-    method public void requestDismissKeyguard(android.app.Activity, java.lang.CharSequence, android.app.KeyguardManager.KeyguardDismissCallback);
-    method public void setPrivateNotificationsAllowed(boolean);
+    method public android.content.Intent createConfirmFactoryResetCredentialIntent(CharSequence, CharSequence, CharSequence);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public boolean getPrivateNotificationsAllowed();
+    method @RequiresPermission(android.Manifest.permission.SHOW_KEYGUARD_MESSAGE) public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable CharSequence, @Nullable android.app.KeyguardManager.KeyguardDismissCallback);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public void setPrivateNotificationsAllowed(boolean);
   }
 
   public class Notification implements android.os.Parcelable {
-    field public static final java.lang.String CATEGORY_CAR_EMERGENCY = "car_emergency";
-    field public static final java.lang.String CATEGORY_CAR_INFORMATION = "car_information";
-    field public static final java.lang.String CATEGORY_CAR_WARNING = "car_warning";
-    field public static final java.lang.String EXTRA_ALLOW_DURING_SETUP = "android.allowDuringSetup";
-    field public static final java.lang.String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
+    field public static final String CATEGORY_CAR_EMERGENCY = "car_emergency";
+    field public static final String CATEGORY_CAR_INFORMATION = "car_information";
+    field public static final String CATEGORY_CAR_WARNING = "car_warning";
+    field @RequiresPermission(android.Manifest.permission.NOTIFICATION_DURING_SETUP) public static final String EXTRA_ALLOW_DURING_SETUP = "android.allowDuringSetup";
+    field @RequiresPermission(android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME) public static final String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
     field public static final int FLAG_AUTOGROUP_SUMMARY = 1024; // 0x400
   }
 
@@ -442,13 +475,13 @@
     ctor public Notification.TvExtender();
     ctor public Notification.TvExtender(android.app.Notification);
     method public android.app.Notification.Builder extend(android.app.Notification.Builder);
-    method public java.lang.String getChannelId();
+    method public String getChannelId();
     method public android.app.PendingIntent getContentIntent();
     method public android.app.PendingIntent getDeleteIntent();
     method public boolean getSuppressShowOverApps();
     method public boolean isAvailableOnTv();
-    method public android.app.Notification.TvExtender setChannel(java.lang.String);
-    method public android.app.Notification.TvExtender setChannelId(java.lang.String);
+    method public android.app.Notification.TvExtender setChannel(String);
+    method public android.app.Notification.TvExtender setChannelId(String);
     method public android.app.Notification.TvExtender setContentIntent(android.app.PendingIntent);
     method public android.app.Notification.TvExtender setDeleteIntent(android.app.PendingIntent);
     method public android.app.Notification.TvExtender setSuppressShowOverApps(boolean);
@@ -467,36 +500,36 @@
   }
 
   public final class StatsManager {
-    method public void addConfig(long, byte[]) throws android.app.StatsManager.StatsUnavailableException;
-    method public deprecated boolean addConfiguration(long, byte[]);
-    method public deprecated byte[] getData(long);
-    method public deprecated byte[] getMetadata();
-    method public byte[] getReports(long) throws android.app.StatsManager.StatsUnavailableException;
-    method public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
-    method public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
-    method public deprecated boolean removeConfiguration(long);
-    method public void setBroadcastSubscriber(android.app.PendingIntent, long, long) throws android.app.StatsManager.StatsUnavailableException;
-    method public deprecated boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
-    method public deprecated boolean setDataFetchOperation(long, android.app.PendingIntent);
-    method public void setFetchReportsOperation(android.app.PendingIntent, long) throws android.app.StatsManager.StatsUnavailableException;
-    field public static final java.lang.String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
-    field public static final java.lang.String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
-    field public static final java.lang.String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
-    field public static final java.lang.String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
-    field public static final java.lang.String EXTRA_STATS_DIMENSIONS_VALUE = "android.app.extra.STATS_DIMENSIONS_VALUE";
-    field public static final java.lang.String EXTRA_STATS_SUBSCRIPTION_ID = "android.app.extra.STATS_SUBSCRIPTION_ID";
-    field public static final java.lang.String EXTRA_STATS_SUBSCRIPTION_RULE_ID = "android.app.extra.STATS_SUBSCRIPTION_RULE_ID";
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void addConfig(long, byte[]) throws android.app.StatsManager.StatsUnavailableException;
+    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean addConfiguration(long, byte[]);
+    method @Deprecated @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getData(long);
+    method @Deprecated @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getMetadata();
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getReports(long) throws android.app.StatsManager.StatsUnavailableException;
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
+    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean removeConfiguration(long);
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setBroadcastSubscriber(android.app.PendingIntent, long, long) throws android.app.StatsManager.StatsUnavailableException;
+    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
+    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setDataFetchOperation(long, android.app.PendingIntent);
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setFetchReportsOperation(android.app.PendingIntent, long) throws android.app.StatsManager.StatsUnavailableException;
+    field public static final String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
+    field public static final String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
+    field public static final String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
+    field public static final String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
+    field public static final String EXTRA_STATS_DIMENSIONS_VALUE = "android.app.extra.STATS_DIMENSIONS_VALUE";
+    field public static final String EXTRA_STATS_SUBSCRIPTION_ID = "android.app.extra.STATS_SUBSCRIPTION_ID";
+    field public static final String EXTRA_STATS_SUBSCRIPTION_RULE_ID = "android.app.extra.STATS_SUBSCRIPTION_RULE_ID";
   }
 
   public static class StatsManager.StatsUnavailableException extends android.util.AndroidException {
-    ctor public StatsManager.StatsUnavailableException(java.lang.String);
-    ctor public StatsManager.StatsUnavailableException(java.lang.String, java.lang.Throwable);
+    ctor public StatsManager.StatsUnavailableException(String);
+    ctor public StatsManager.StatsUnavailableException(String, Throwable);
   }
 
   public final class Vr2dDisplayProperties implements android.os.Parcelable {
     ctor public Vr2dDisplayProperties(int, int, int);
     method public int describeContents();
-    method public void dump(java.io.PrintWriter, java.lang.String);
+    method public void dump(java.io.PrintWriter, String);
     method public int getAddedFlags();
     method public int getDpi();
     method public int getHeight();
@@ -517,16 +550,16 @@
   }
 
   public class VrManager {
-    method public int getVr2dDisplayId();
-    method public boolean isPersistentVrModeEnabled();
-    method public boolean isVrModeEnabled();
-    method public void registerVrStateCallback(java.util.concurrent.Executor, android.app.VrStateCallback);
-    method public void setAndBindVrCompositor(android.content.ComponentName);
-    method public void setPersistentVrModeEnabled(boolean);
-    method public void setStandbyEnabled(boolean);
-    method public void setVr2dDisplayProperties(android.app.Vr2dDisplayProperties);
-    method public void setVrInputMethod(android.content.ComponentName);
-    method public void unregisterVrStateCallback(android.app.VrStateCallback);
+    method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public int getVr2dDisplayId();
+    method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public boolean isPersistentVrModeEnabled();
+    method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public boolean isVrModeEnabled();
+    method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public void registerVrStateCallback(@NonNull java.util.concurrent.Executor, android.app.VrStateCallback);
+    method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setAndBindVrCompositor(android.content.ComponentName);
+    method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setPersistentVrModeEnabled(boolean);
+    method @RequiresPermission("android.permission.ACCESS_VR_MANAGER") public void setStandbyEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVr2dDisplayProperties(android.app.Vr2dDisplayProperties);
+    method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVrInputMethod(android.content.ComponentName);
+    method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public void unregisterVrStateCallback(android.app.VrStateCallback);
   }
 
   public abstract class VrStateCallback {
@@ -535,14 +568,21 @@
     method public void onVrStateChanged(boolean);
   }
 
+  public final class WallpaperColors implements android.os.Parcelable {
+    ctor public WallpaperColors(@NonNull android.graphics.Color, @Nullable android.graphics.Color, @Nullable android.graphics.Color, int);
+    method public int getColorHints();
+    field public static final int HINT_SUPPORTS_DARK_TEXT = 1; // 0x1
+    field public static final int HINT_SUPPORTS_DARK_THEME = 2; // 0x2
+  }
+
   public final class WallpaperInfo implements android.os.Parcelable {
     method public boolean supportsAmbientMode();
   }
 
   public class WallpaperManager {
-    method public void clearWallpaper(int, int);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void clearWallpaper(int, int);
     method public void setDisplayOffset(android.os.IBinder, int, int);
-    method public boolean setWallpaperComponent(android.content.ComponentName);
+    method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT) public boolean setWallpaperComponent(android.content.ComponentName);
   }
 
 }
@@ -550,41 +590,41 @@
 package android.app.admin {
 
   public class DevicePolicyManager {
-    method public java.lang.String getDeviceOwner();
-    method public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
-    method public java.lang.String getDeviceOwnerNameOnAnyUser();
-    method public java.lang.CharSequence getDeviceOwnerOrganizationName();
-    method public android.os.UserHandle getDeviceOwnerUser();
-    method public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
-    method public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
-    method public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
-    method public android.content.ComponentName getProfileOwnerAsUser(android.os.UserHandle);
-    method public java.lang.String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
-    method public int getUserProvisioningState();
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwnerNameOnAnyUser();
+    method @Nullable public CharSequence getDeviceOwnerOrganizationName();
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getDeviceOwnerUser();
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
+    method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
+    method @Nullable @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS, conditional=true) public android.content.ComponentName getProfileOwnerAsUser(@NonNull android.os.UserHandle);
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserProvisioningState();
     method public boolean isDeviceManaged();
-    method public boolean isDeviceProvisioned();
-    method public boolean isDeviceProvisioningConfigApplied();
-    method public boolean isManagedKiosk();
-    method public boolean isUnattendedManagedKiosk();
-    method public void notifyPendingSystemUpdate(long);
-    method public void notifyPendingSystemUpdate(long, boolean);
-    method public boolean packageHasActiveAdmins(java.lang.String);
-    method public deprecated boolean setActiveProfileOwner(android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException;
-    method public void setDeviceProvisioningConfigApplied();
-    method public void setProfileOwnerCanAccessDeviceIdsForUser(android.content.ComponentName, android.os.UserHandle);
-    field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
-    field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
-    field public static final java.lang.String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION";
-    field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE = "android.app.action.PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE";
-    field public static final java.lang.String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
-    field public static final java.lang.String ACTION_STATE_USER_SETUP_COMPLETE = "android.app.action.STATE_USER_SETUP_COMPLETE";
-    field public static final java.lang.String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
-    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
-    field public static final java.lang.String EXTRA_PROVISIONING_ORGANIZATION_NAME = "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
-    field public static final java.lang.String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
-    field public static final java.lang.String EXTRA_PROVISIONING_TRIGGER = "android.app.extra.PROVISIONING_TRIGGER";
-    field public static final java.lang.String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedKiosk();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUnattendedManagedKiosk();
+    method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
+    method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
+    method @Deprecated @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
+    method public void setProfileOwnerCanAccessDeviceIdsForUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
+    field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
+    field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
+    field public static final String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION";
+    field public static final String ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE = "android.app.action.PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE";
+    field public static final String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
+    field public static final String ACTION_STATE_USER_SETUP_COMPLETE = "android.app.action.STATE_USER_SETUP_COMPLETE";
+    field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
+    field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
+    field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
+    field public static final String EXTRA_PROVISIONING_ORGANIZATION_NAME = "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
+    field public static final String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
+    field public static final String EXTRA_PROVISIONING_TRIGGER = "android.app.extra.PROVISIONING_TRIGGER";
+    field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
     field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1
     field public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3
     field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2
@@ -628,28 +668,28 @@
   }
 
   public class BackupManager {
-    method public void backupNow();
-    method public android.app.backup.RestoreSession beginRestoreSession();
-    method public void cancelBackups();
-    method public long getAvailableRestoreToken(java.lang.String);
-    method public android.content.Intent getConfigurationIntent(java.lang.String);
-    method public java.lang.String getCurrentTransport();
-    method public android.content.ComponentName getCurrentTransportComponent();
-    method public android.content.Intent getDataManagementIntent(java.lang.String);
-    method public java.lang.String getDataManagementLabel(java.lang.String);
-    method public java.lang.String getDestinationString(java.lang.String);
-    method public boolean isAppEligibleForBackup(java.lang.String);
-    method public boolean isBackupEnabled();
-    method public boolean isBackupServiceActive(android.os.UserHandle);
-    method public java.lang.String[] listAllTransports();
-    method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver);
-    method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver, android.app.backup.BackupManagerMonitor, int);
-    method public deprecated int requestRestore(android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
-    method public deprecated java.lang.String selectBackupTransport(java.lang.String);
-    method public void selectBackupTransport(android.content.ComponentName, android.app.backup.SelectBackupTransportCallback);
-    method public void setAutoRestore(boolean);
-    method public void setBackupEnabled(boolean);
-    method public void updateTransportAttributes(android.content.ComponentName, java.lang.String, android.content.Intent, java.lang.String, android.content.Intent, java.lang.String);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public void backupNow();
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public android.app.backup.RestoreSession beginRestoreSession();
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public void cancelBackups();
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public long getAvailableRestoreToken(String);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getConfigurationIntent(String);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public String getCurrentTransport();
+    method @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.ComponentName getCurrentTransportComponent();
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getDataManagementIntent(String);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public String getDataManagementLabel(String);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public String getDestinationString(String);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public boolean isAppEligibleForBackup(String);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public boolean isBackupEnabled();
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public boolean isBackupServiceActive(android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public String[] listAllTransports();
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public int requestBackup(String[], android.app.backup.BackupObserver);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public int requestBackup(String[], android.app.backup.BackupObserver, android.app.backup.BackupManagerMonitor, int);
+    method @Deprecated public int requestRestore(android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.BACKUP) public String selectBackupTransport(String);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public void selectBackupTransport(android.content.ComponentName, android.app.backup.SelectBackupTransportCallback);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public void setAutoRestore(boolean);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public void setBackupEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public void updateTransportAttributes(android.content.ComponentName, String, @Nullable android.content.Intent, String, @Nullable android.content.Intent, @Nullable String);
     field public static final int ERROR_AGENT_FAILURE = -1003; // 0xfffffc15
     field public static final int ERROR_BACKUP_CANCELLED = -2003; // 0xfffff82d
     field public static final int ERROR_BACKUP_NOT_ALLOWED = -2001; // 0xfffff82f
@@ -660,28 +700,28 @@
     field public static final int ERROR_TRANSPORT_QUOTA_EXCEEDED = -1005; // 0xfffffc13
     field public static final int ERROR_TRANSPORT_UNAVAILABLE = -1; // 0xffffffff
     field public static final int FLAG_NON_INCREMENTAL_BACKUP = 1; // 0x1
-    field public static final java.lang.String PACKAGE_MANAGER_SENTINEL = "@pm@";
+    field public static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
     field public static final int SUCCESS = 0; // 0x0
   }
 
   public class BackupManagerMonitor {
     ctor public BackupManagerMonitor();
     method public void onEvent(android.os.Bundle);
-    field public static final java.lang.String EXTRA_LOG_CANCEL_ALL = "android.app.backup.extra.LOG_CANCEL_ALL";
-    field public static final java.lang.String EXTRA_LOG_EVENT_CATEGORY = "android.app.backup.extra.LOG_EVENT_CATEGORY";
-    field public static final java.lang.String EXTRA_LOG_EVENT_ID = "android.app.backup.extra.LOG_EVENT_ID";
-    field public static final java.lang.String EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_FULL_VERSION";
-    field public static final java.lang.String EXTRA_LOG_EVENT_PACKAGE_NAME = "android.app.backup.extra.LOG_EVENT_PACKAGE_NAME";
-    field public static final deprecated java.lang.String EXTRA_LOG_EVENT_PACKAGE_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_VERSION";
-    field public static final java.lang.String EXTRA_LOG_EXCEPTION_FULL_BACKUP = "android.app.backup.extra.LOG_EXCEPTION_FULL_BACKUP";
-    field public static final java.lang.String EXTRA_LOG_ILLEGAL_KEY = "android.app.backup.extra.LOG_ILLEGAL_KEY";
-    field public static final java.lang.String EXTRA_LOG_MANIFEST_PACKAGE_NAME = "android.app.backup.extra.LOG_MANIFEST_PACKAGE_NAME";
-    field public static final java.lang.String EXTRA_LOG_OLD_VERSION = "android.app.backup.extra.LOG_OLD_VERSION";
-    field public static final java.lang.String EXTRA_LOG_POLICY_ALLOW_APKS = "android.app.backup.extra.LOG_POLICY_ALLOW_APKS";
-    field public static final java.lang.String EXTRA_LOG_PREFLIGHT_ERROR = "android.app.backup.extra.LOG_PREFLIGHT_ERROR";
-    field public static final java.lang.String EXTRA_LOG_RESTORE_ANYWAY = "android.app.backup.extra.LOG_RESTORE_ANYWAY";
-    field public static final java.lang.String EXTRA_LOG_RESTORE_VERSION = "android.app.backup.extra.LOG_RESTORE_VERSION";
-    field public static final java.lang.String EXTRA_LOG_WIDGET_PACKAGE_NAME = "android.app.backup.extra.LOG_WIDGET_PACKAGE_NAME";
+    field public static final String EXTRA_LOG_CANCEL_ALL = "android.app.backup.extra.LOG_CANCEL_ALL";
+    field public static final String EXTRA_LOG_EVENT_CATEGORY = "android.app.backup.extra.LOG_EVENT_CATEGORY";
+    field public static final String EXTRA_LOG_EVENT_ID = "android.app.backup.extra.LOG_EVENT_ID";
+    field public static final String EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_FULL_VERSION";
+    field public static final String EXTRA_LOG_EVENT_PACKAGE_NAME = "android.app.backup.extra.LOG_EVENT_PACKAGE_NAME";
+    field @Deprecated public static final String EXTRA_LOG_EVENT_PACKAGE_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_VERSION";
+    field public static final String EXTRA_LOG_EXCEPTION_FULL_BACKUP = "android.app.backup.extra.LOG_EXCEPTION_FULL_BACKUP";
+    field public static final String EXTRA_LOG_ILLEGAL_KEY = "android.app.backup.extra.LOG_ILLEGAL_KEY";
+    field public static final String EXTRA_LOG_MANIFEST_PACKAGE_NAME = "android.app.backup.extra.LOG_MANIFEST_PACKAGE_NAME";
+    field public static final String EXTRA_LOG_OLD_VERSION = "android.app.backup.extra.LOG_OLD_VERSION";
+    field public static final String EXTRA_LOG_POLICY_ALLOW_APKS = "android.app.backup.extra.LOG_POLICY_ALLOW_APKS";
+    field public static final String EXTRA_LOG_PREFLIGHT_ERROR = "android.app.backup.extra.LOG_PREFLIGHT_ERROR";
+    field public static final String EXTRA_LOG_RESTORE_ANYWAY = "android.app.backup.extra.LOG_RESTORE_ANYWAY";
+    field public static final String EXTRA_LOG_RESTORE_VERSION = "android.app.backup.extra.LOG_RESTORE_VERSION";
+    field public static final String EXTRA_LOG_WIDGET_PACKAGE_NAME = "android.app.backup.extra.LOG_WIDGET_PACKAGE_NAME";
     field public static final int LOG_EVENT_CATEGORY_AGENT = 2; // 0x2
     field public static final int LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY = 3; // 0x3
     field public static final int LOG_EVENT_CATEGORY_TRANSPORT = 1; // 0x1
@@ -732,8 +772,8 @@
   public abstract class BackupObserver {
     ctor public BackupObserver();
     method public void backupFinished(int);
-    method public void onResult(java.lang.String, int);
-    method public void onUpdate(java.lang.String, android.app.backup.BackupProgress);
+    method public void onResult(String, int);
+    method public void onUpdate(String, android.app.backup.BackupProgress);
   }
 
   public class BackupProgress implements android.os.Parcelable {
@@ -752,13 +792,13 @@
     method public int checkFullBackupSize(long);
     method public int clearBackupData(android.content.pm.PackageInfo);
     method public android.content.Intent configurationIntent();
-    method public java.lang.String currentDestinationString();
+    method public String currentDestinationString();
     method public android.content.Intent dataManagementIntent();
-    method public java.lang.String dataManagementLabel();
+    method public String dataManagementLabel();
     method public int finishBackup();
     method public void finishRestore();
     method public android.app.backup.RestoreSet[] getAvailableRestoreSets();
-    method public long getBackupQuota(java.lang.String, boolean);
+    method public long getBackupQuota(String, boolean);
     method public android.os.IBinder getBinder();
     method public long getCurrentRestoreSet();
     method public int getNextFullRestoreDataChunk(android.os.ParcelFileDescriptor);
@@ -766,7 +806,7 @@
     method public int getTransportFlags();
     method public int initializeDevice();
     method public boolean isAppEligibleForBackup(android.content.pm.PackageInfo, boolean);
-    method public java.lang.String name();
+    method public String name();
     method public android.app.backup.RestoreDescription nextRestorePackage();
     method public int performBackup(android.content.pm.PackageInfo, android.os.ParcelFileDescriptor, int);
     method public int performBackup(android.content.pm.PackageInfo, android.os.ParcelFileDescriptor);
@@ -776,10 +816,10 @@
     method public long requestFullBackupTime();
     method public int sendBackupData(int);
     method public int startRestore(long, android.content.pm.PackageInfo[]);
-    method public java.lang.String transportDirName();
+    method public String transportDirName();
     field public static final int AGENT_ERROR = -1003; // 0xfffffc15
     field public static final int AGENT_UNKNOWN = -1004; // 0xfffffc14
-    field public static final java.lang.String EXTRA_TRANSPORT_REGISTRATION = "android.app.backup.extra.TRANSPORT_REGISTRATION";
+    field public static final String EXTRA_TRANSPORT_REGISTRATION = "android.app.backup.extra.TRANSPORT_REGISTRATION";
     field public static final int FLAG_INCREMENTAL = 2; // 0x2
     field public static final int FLAG_NON_INCREMENTAL = 4; // 0x4
     field public static final int FLAG_USER_INITIATED = 1; // 0x1
@@ -793,10 +833,10 @@
   }
 
   public class RestoreDescription implements android.os.Parcelable {
-    ctor public RestoreDescription(java.lang.String, int);
+    ctor public RestoreDescription(String, int);
     method public int describeContents();
     method public int getDataType();
-    method public java.lang.String getPackageName();
+    method public String getPackageName();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.backup.RestoreDescription> CREATOR;
     field public static final android.app.backup.RestoreDescription NO_MORE_PACKAGES;
@@ -814,27 +854,94 @@
     method public int getAvailableRestoreSets(android.app.backup.RestoreObserver);
     method public int restoreAll(long, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
     method public int restoreAll(long, android.app.backup.RestoreObserver);
-    method public int restorePackage(java.lang.String, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
-    method public int restorePackage(java.lang.String, android.app.backup.RestoreObserver);
-    method public int restoreSome(long, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor, java.lang.String[]);
-    method public int restoreSome(long, android.app.backup.RestoreObserver, java.lang.String[]);
+    method public int restorePackage(String, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
+    method public int restorePackage(String, android.app.backup.RestoreObserver);
+    method public int restoreSome(long, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor, String[]);
+    method public int restoreSome(long, android.app.backup.RestoreObserver, String[]);
   }
 
   public class RestoreSet implements android.os.Parcelable {
     ctor public RestoreSet();
-    ctor public RestoreSet(java.lang.String, java.lang.String, long);
+    ctor public RestoreSet(String, String, long);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.backup.RestoreSet> CREATOR;
-    field public java.lang.String device;
-    field public java.lang.String name;
+    field public String device;
+    field public String name;
     field public long token;
   }
 
   public abstract class SelectBackupTransportCallback {
     ctor public SelectBackupTransportCallback();
     method public void onFailure(int);
-    method public void onSuccess(java.lang.String);
+    method public void onSuccess(String);
+  }
+
+}
+
+package android.app.contentsuggestions {
+
+  public final class ClassificationsRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public java.util.List<android.app.contentsuggestions.ContentSelection> getSelections();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ClassificationsRequest> CREATOR;
+  }
+
+  public static final class ClassificationsRequest.Builder {
+    ctor public ClassificationsRequest.Builder(@NonNull java.util.List<android.app.contentsuggestions.ContentSelection>);
+    method public android.app.contentsuggestions.ClassificationsRequest build();
+    method public android.app.contentsuggestions.ClassificationsRequest.Builder setExtras(@NonNull android.os.Bundle);
+  }
+
+  public final class ContentClassification implements android.os.Parcelable {
+    ctor public ContentClassification(@NonNull String, @NonNull android.os.Bundle);
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public String getId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ContentClassification> CREATOR;
+  }
+
+  public final class ContentSelection implements android.os.Parcelable {
+    ctor public ContentSelection(@NonNull String, @NonNull android.os.Bundle);
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public String getId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ContentSelection> CREATOR;
+  }
+
+  public final class ContentSuggestionsManager {
+    method public void classifyContentSelections(@NonNull android.app.contentsuggestions.ClassificationsRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.contentsuggestions.ContentSuggestionsManager.ClassificationsCallback);
+    method public void notifyInteraction(@NonNull String, @NonNull android.os.Bundle);
+    method public void provideContextImage(int, @NonNull android.os.Bundle);
+    method public void suggestContentSelections(@NonNull android.app.contentsuggestions.SelectionsRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.contentsuggestions.ContentSuggestionsManager.SelectionsCallback);
+  }
+
+  public static interface ContentSuggestionsManager.ClassificationsCallback {
+    method public void onContentClassificationsAvailable(int, @NonNull java.util.List<android.app.contentsuggestions.ContentClassification>);
+  }
+
+  public static interface ContentSuggestionsManager.SelectionsCallback {
+    method public void onContentSelectionsAvailable(int, @NonNull java.util.List<android.app.contentsuggestions.ContentSelection>);
+  }
+
+  public final class SelectionsRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.Bundle getExtras();
+    method public android.graphics.Point getInterestPoint();
+    method public int getTaskId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.contentsuggestions.SelectionsRequest> CREATOR;
+  }
+
+  public static final class SelectionsRequest.Builder {
+    ctor public SelectionsRequest.Builder(int);
+    method public android.app.contentsuggestions.SelectionsRequest build();
+    method public android.app.contentsuggestions.SelectionsRequest.Builder setExtras(@NonNull android.os.Bundle);
+    method public android.app.contentsuggestions.SelectionsRequest.Builder setInterestPoint(@NonNull android.graphics.Point);
   }
 
 }
@@ -842,35 +949,115 @@
 package android.app.job {
 
   public abstract class JobScheduler {
-    method public abstract int scheduleAsPackage(android.app.job.JobInfo, java.lang.String, int, java.lang.String);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public abstract int scheduleAsPackage(@NonNull android.app.job.JobInfo, @NonNull String, int, String);
+  }
+
+}
+
+package android.app.prediction {
+
+  public final class AppPredictionContext implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.os.Bundle getExtras();
+    method @NonNull public String getPackageName();
+    method public int getPredictedTargetCount();
+    method public String getUiSurface();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.prediction.AppPredictionContext> CREATOR;
+  }
+
+  public static final class AppPredictionContext.Builder {
+    method public android.app.prediction.AppPredictionContext build();
+    method public android.app.prediction.AppPredictionContext.Builder setExtras(@Nullable android.os.Bundle);
+    method public android.app.prediction.AppPredictionContext.Builder setPredictedTargetCount(int);
+    method public android.app.prediction.AppPredictionContext.Builder setUiSurface(@Nullable String);
+  }
+
+  public final class AppPredictionManager {
+    method public android.app.prediction.AppPredictor createAppPredictionSession(@NonNull android.app.prediction.AppPredictionContext);
+  }
+
+  public final class AppPredictionSessionId implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.prediction.AppPredictionSessionId> CREATOR;
+  }
+
+  public final class AppPredictor {
+    method public void destroy();
+    method public void notifyAppTargetEvent(@NonNull android.app.prediction.AppTargetEvent);
+    method public void notifyLocationShown(@NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
+    method public void registerPredictionUpdates(@NonNull java.util.concurrent.Executor, @NonNull android.app.prediction.AppPredictor.Callback);
+    method public void requestPredictionUpdate();
+    method @Nullable public void sortTargets(@NonNull java.util.List<android.app.prediction.AppTarget>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
+    method public void unregisterPredictionUpdates(@NonNull android.app.prediction.AppPredictor.Callback);
+  }
+
+  public static interface AppPredictor.Callback {
+    method public void onTargetsAvailable(@NonNull java.util.List<android.app.prediction.AppTarget>);
+  }
+
+  public final class AppTarget implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public String getClassName();
+    method @NonNull public android.app.prediction.AppTargetId getId();
+    method @NonNull public String getPackageName();
+    method public int getRank();
+    method @Nullable public android.content.pm.ShortcutInfo getShortcutInfo();
+    method @NonNull public android.os.UserHandle getUser();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.prediction.AppTarget> CREATOR;
+  }
+
+  public final class AppTargetEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public int getAction();
+    method @NonNull public String getLaunchLocation();
+    method @Nullable public android.app.prediction.AppTarget getTarget();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ACTION_DISMISS = 2; // 0x2
+    field public static final int ACTION_LAUNCH = 1; // 0x1
+    field public static final int ACTION_PIN = 3; // 0x3
+    field public static final android.os.Parcelable.Creator<android.app.prediction.AppTargetEvent> CREATOR;
+  }
+
+  public static final class AppTargetEvent.Builder {
+    ctor public AppTargetEvent.Builder(@Nullable android.app.prediction.AppTarget, int);
+    method public android.app.prediction.AppTargetEvent build();
+    method public android.app.prediction.AppTargetEvent.Builder setLaunchLocation(String);
+  }
+
+  public final class AppTargetId implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.prediction.AppTargetId> CREATOR;
   }
 
 }
 
 package android.app.role {
 
-  public abstract interface OnRoleHoldersChangedListener {
-    method public abstract void onRoleHoldersChanged(java.lang.String, android.os.UserHandle);
+  public interface OnRoleHoldersChangedListener {
+    method public void onRoleHoldersChanged(@NonNull String, @NonNull android.os.UserHandle);
   }
 
   public final class RoleManager {
-    method public void addOnRoleHoldersChangedListenerAsUser(java.util.concurrent.Executor, android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle);
-    method public void addRoleHolderAsUser(java.lang.String, java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
-    method public boolean addRoleHolderFromController(java.lang.String, java.lang.String);
-    method public void clearRoleHoldersAsUser(java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
-    method public java.util.List<java.lang.String> getHeldRolesFromController(java.lang.String);
-    method public java.util.List<java.lang.String> getRoleHolders(java.lang.String);
-    method public java.util.List<java.lang.String> getRoleHoldersAsUser(java.lang.String, android.os.UserHandle);
-    method public void removeOnRoleHoldersChangedListenerAsUser(android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle);
-    method public void removeRoleHolderAsUser(java.lang.String, java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
-    method public boolean removeRoleHolderFromController(java.lang.String, java.lang.String);
-    method public void setRoleNamesFromController(java.util.List<java.lang.String>);
-    field public static final java.lang.String EXTRA_REQUEST_ROLE_NAME = "android.app.role.extra.REQUEST_ROLE_NAME";
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void addOnRoleHoldersChangedListenerAsUser(@NonNull java.util.concurrent.Executor, @NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
+    method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>);
   }
 
-  public abstract interface RoleManagerCallback {
-    method public abstract void onFailure();
-    method public abstract void onSuccess();
+  public interface RoleManagerCallback {
+    method public void onFailure();
+    method public void onSuccess();
   }
 
 }
@@ -883,7 +1070,7 @@
     method public long getQuota();
     method public int getUid();
     method public android.app.usage.UsageStats getUsageStats();
-    method public java.lang.String getVolumeUuid();
+    method public String getVolumeUuid();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.usage.CacheQuotaHint> CREATOR;
     field public static final long QUOTA_NOT_SET = -1L; // 0xffffffffffffffffL
@@ -892,23 +1079,25 @@
   public static final class CacheQuotaHint.Builder {
     ctor public CacheQuotaHint.Builder();
     ctor public CacheQuotaHint.Builder(android.app.usage.CacheQuotaHint);
-    method public android.app.usage.CacheQuotaHint build();
-    method public android.app.usage.CacheQuotaHint.Builder setQuota(long);
-    method public android.app.usage.CacheQuotaHint.Builder setUid(int);
-    method public android.app.usage.CacheQuotaHint.Builder setUsageStats(android.app.usage.UsageStats);
-    method public android.app.usage.CacheQuotaHint.Builder setVolumeUuid(java.lang.String);
+    method @NonNull public android.app.usage.CacheQuotaHint build();
+    method @NonNull public android.app.usage.CacheQuotaHint.Builder setQuota(long);
+    method @NonNull public android.app.usage.CacheQuotaHint.Builder setUid(int);
+    method @NonNull public android.app.usage.CacheQuotaHint.Builder setUsageStats(@Nullable android.app.usage.UsageStats);
+    method @NonNull public android.app.usage.CacheQuotaHint.Builder setVolumeUuid(@Nullable String);
   }
 
   public abstract class CacheQuotaService extends android.app.Service {
     ctor public CacheQuotaService();
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract java.util.List<android.app.usage.CacheQuotaHint> onComputeCacheQuotaHints(java.util.List<android.app.usage.CacheQuotaHint>);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.app.usage.CacheQuotaService";
+    field public static final String SERVICE_INTERFACE = "android.app.usage.CacheQuotaService";
   }
 
   public static final class UsageEvents.Event {
     method public int getInstanceId();
-    method public java.lang.String getNotificationChannelId();
+    method public String getNotificationChannelId();
+    method @Nullable public String getTaskRootClassName();
+    method @Nullable public String getTaskRootPackageName();
     field public static final int NOTIFICATION_INTERRUPTION = 12; // 0xc
     field public static final int NOTIFICATION_SEEN = 10; // 0xa
     field public static final int SLICE_PINNED = 14; // 0xe
@@ -921,20 +1110,26 @@
   }
 
   public final class UsageStatsManager {
-    method public int getAppStandbyBucket(java.lang.String);
-    method public java.util.Map<java.lang.String, java.lang.Integer> getAppStandbyBuckets();
-    method public void registerAppUsageObserver(int, java.lang.String[], long, java.util.concurrent.TimeUnit, android.app.PendingIntent);
-    method public void registerUsageSessionObserver(int, java.lang.String[], long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit, android.app.PendingIntent, android.app.PendingIntent);
-    method public void setAppStandbyBucket(java.lang.String, int);
-    method public void setAppStandbyBuckets(java.util.Map<java.lang.String, java.lang.Integer>);
-    method public void unregisterAppUsageObserver(int);
-    method public void unregisterUsageSessionObserver(int);
-    method public void whitelistAppTemporarily(java.lang.String, long, android.os.UserHandle);
-    field public static final java.lang.String EXTRA_OBSERVER_ID = "android.app.usage.extra.OBSERVER_ID";
-    field public static final java.lang.String EXTRA_TIME_LIMIT = "android.app.usage.extra.TIME_LIMIT";
-    field public static final java.lang.String EXTRA_TIME_USED = "android.app.usage.extra.TIME_USED";
+    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getAppStandbyBucket(String);
+    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.Map<java.lang.String,java.lang.Integer> getAppStandbyBuckets();
+    method public int getUsageSource();
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
+    method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String);
+    method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String, long);
+    method public void reportUsageStop(@NonNull android.app.Activity, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE) public void setAppStandbyBucket(String, int);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE) public void setAppStandbyBuckets(java.util.Map<java.lang.String,java.lang.Integer>);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void unregisterAppUsageObserver(int);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void unregisterUsageSessionObserver(int);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(String, long, android.os.UserHandle);
+    field public static final String EXTRA_OBSERVER_ID = "android.app.usage.extra.OBSERVER_ID";
+    field public static final String EXTRA_TIME_LIMIT = "android.app.usage.extra.TIME_LIMIT";
+    field public static final String EXTRA_TIME_USED = "android.app.usage.extra.TIME_USED";
     field public static final int STANDBY_BUCKET_EXEMPTED = 5; // 0x5
     field public static final int STANDBY_BUCKET_NEVER = 50; // 0x32
+    field public static final int USAGE_SOURCE_CURRENT_ACTIVITY = 2; // 0x2
+    field public static final int USAGE_SOURCE_TASK_ROOT_ACTIVITY = 1; // 0x1
   }
 
 }
@@ -944,31 +1139,58 @@
   public final class BluetoothAdapter {
     method public boolean disableBLE();
     method public boolean enableBLE();
-    method public boolean enableNoAutoConnect();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect();
     method public boolean isBleScanAlwaysAvailable();
     method public boolean isLeEnabled();
-    field public static final java.lang.String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
-    field public static final java.lang.String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean registerMetadataListener(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothAdapter.MetadataListener, android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean unregisterMetadataListener(android.bluetooth.BluetoothDevice);
+    field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
+    field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
+  }
+
+  public abstract static class BluetoothAdapter.MetadataListener {
+    ctor public BluetoothAdapter.MetadataListener();
+    method public void onMetadataChanged(android.bluetooth.BluetoothDevice, int, String);
   }
 
   public final class BluetoothDevice implements android.os.Parcelable {
-    method public boolean cancelBondProcess();
-    method public boolean isConnected();
-    method public boolean isEncrypted();
-    method public boolean removeBond();
-    method public boolean setPhonebookAccessPermission(int);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public String getMetadata(int);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, String);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
     field public static final int ACCESS_ALLOWED = 1; // 0x1
     field public static final int ACCESS_REJECTED = 2; // 0x2
     field public static final int ACCESS_UNKNOWN = 0; // 0x0
+    field public static final int METADATA_COMPANION_APP = 4; // 0x4
+    field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10
+    field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3
+    field public static final int METADATA_IS_UNTHETHERED_HEADSET = 6; // 0x6
+    field public static final int METADATA_MAIN_ICON = 5; // 0x5
+    field public static final int METADATA_MANUFACTURER_NAME = 0; // 0x0
+    field public static final int METADATA_MAX_LENGTH = 2048; // 0x800
+    field public static final int METADATA_MODEL_NAME = 1; // 0x1
+    field public static final int METADATA_SOFTWARE_VERSION = 2; // 0x2
+    field public static final int METADATA_UNTHETHERED_CASE_BATTERY = 12; // 0xc
+    field public static final int METADATA_UNTHETHERED_CASE_CHARGING = 15; // 0xf
+    field public static final int METADATA_UNTHETHERED_CASE_ICON = 9; // 0x9
+    field public static final int METADATA_UNTHETHERED_LEFT_BATTERY = 10; // 0xa
+    field public static final int METADATA_UNTHETHERED_LEFT_CHARGING = 13; // 0xd
+    field public static final int METADATA_UNTHETHERED_LEFT_ICON = 7; // 0x7
+    field public static final int METADATA_UNTHETHERED_RIGHT_BATTERY = 11; // 0xb
+    field public static final int METADATA_UNTHETHERED_RIGHT_CHARGING = 14; // 0xe
+    field public static final int METADATA_UNTHETHERED_RIGHT_ICON = 8; // 0x8
   }
 
   public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
-    method public boolean connect(android.bluetooth.BluetoothDevice);
-    method public boolean disconnect(android.bluetooth.BluetoothDevice);
-    method public boolean setPriority(android.bluetooth.BluetoothDevice, int);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean connect(android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disconnect(android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
   }
 
-  public abstract interface BluetoothProfile {
+  public interface BluetoothProfile {
     field public static final int PRIORITY_OFF = 0; // 0x0
     field public static final int PRIORITY_ON = 100; // 0x64
   }
@@ -978,8 +1200,8 @@
 package android.bluetooth.le {
 
   public final class BluetoothLeScanner {
-    method public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback);
-    method public void startScanFromSource(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.os.WorkSource, android.bluetooth.le.ScanCallback);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADMIN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback);
+    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADMIN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.os.WorkSource, android.bluetooth.le.ScanCallback);
     method public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
   }
 
@@ -1013,94 +1235,102 @@
 package android.content {
 
   public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
-    method public void setDetectNotResponding(long);
+    method @RequiresPermission(android.Manifest.permission.REMOVE_TASKS) public void setDetectNotResponding(long);
   }
 
   public abstract class ContentResolver implements android.content.ContentInterface {
-    method public android.graphics.drawable.Drawable getTypeDrawable(java.lang.String);
+    method public android.graphics.drawable.Drawable getTypeDrawable(String);
   }
 
   public abstract class Context {
-    method public boolean bindServiceAsUser(android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean bindServiceAsUser(@RequiresPermission android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
     method public abstract android.content.Context createCredentialProtectedStorageContext();
-    method public android.content.Context createPackageContextAsUser(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract java.io.File getPreloadsFileCache();
+    method public android.content.Context createPackageContextAsUser(String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Nullable public abstract java.io.File getPreloadsFileCache();
     method public abstract boolean isCredentialProtectedStorage();
-    method public abstract void sendBroadcast(android.content.Intent, java.lang.String, android.os.Bundle);
-    method public abstract void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.os.Bundle);
-    method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void startActivityAsUser(android.content.Intent, android.os.UserHandle);
-    field public static final java.lang.String BACKUP_SERVICE = "backup";
-    field public static final java.lang.String CONTEXTHUB_SERVICE = "contexthub";
-    field public static final java.lang.String EUICC_CARD_SERVICE = "euicc_card";
-    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";
-    field public static final java.lang.String SYSTEM_UPDATE_SERVICE = "system_update";
-    field public static final java.lang.String VR_SERVICE = "vrmanager";
-    field public static final deprecated java.lang.String WIFI_RTT_SERVICE = "rttmanager";
-    field public static final java.lang.String WIFI_SCANNING_SERVICE = "wifiscanner";
+    method public abstract void sendBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
+    method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void startActivityAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
+    field public static final String APP_PREDICTION_SERVICE = "app_prediction";
+    field public static final String BACKUP_SERVICE = "backup";
+    field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
+    field public static final String CONTEXTHUB_SERVICE = "contexthub";
+    field public static final String EUICC_CARD_SERVICE = "euicc_card";
+    field public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
+    field public static final String NETWORK_SCORE_SERVICE = "network_score";
+    field public static final String OEM_LOCK_SERVICE = "oem_lock";
+    field public static final String PERMISSION_SERVICE = "permission";
+    field public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
+    field public static final String ROLLBACK_SERVICE = "rollback";
+    field public static final String SECURE_ELEMENT_SERVICE = "secure_element";
+    field public static final String STATS_MANAGER = "stats";
+    field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
+    field public static final String VR_SERVICE = "vrmanager";
+    field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
+    field public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
   }
 
   public class ContextWrapper extends android.content.Context {
     method public android.content.Context createCredentialProtectedStorageContext();
     method public java.io.File getPreloadsFileCache();
     method public boolean isCredentialProtectedStorage();
-    method public void sendBroadcast(android.content.Intent, java.lang.String, android.os.Bundle);
-    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.os.Bundle);
-    method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public void sendBroadcast(android.content.Intent, String, android.os.Bundle);
+    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, String, android.os.Bundle);
+    method public void sendOrderedBroadcast(android.content.Intent, String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
   }
 
   public class Intent implements java.lang.Cloneable android.os.Parcelable {
-    field public static final java.lang.String ACTION_BATTERY_LEVEL_CHANGED = "android.intent.action.BATTERY_LEVEL_CHANGED";
-    field public static final java.lang.String ACTION_CALL_EMERGENCY = "android.intent.action.CALL_EMERGENCY";
-    field public static final java.lang.String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";
-    field public static final java.lang.String ACTION_DEVICE_CUSTOMIZATION_READY = "android.intent.action.DEVICE_CUSTOMIZATION_READY";
-    field public static final java.lang.String ACTION_FACTORY_RESET = "android.intent.action.FACTORY_RESET";
-    field public static final java.lang.String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON";
-    field public static final java.lang.String ACTION_INSTALL_INSTANT_APP_PACKAGE = "android.intent.action.INSTALL_INSTANT_APP_PACKAGE";
-    field public static final java.lang.String ACTION_INSTANT_APP_RESOLVER_SETTINGS = "android.intent.action.INSTANT_APP_RESOLVER_SETTINGS";
-    field public static final java.lang.String ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION";
-    field public static final java.lang.String ACTION_MANAGE_APP_PERMISSIONS = "android.intent.action.MANAGE_APP_PERMISSIONS";
-    field public static final java.lang.String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS";
-    field public static final java.lang.String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
-    field public static final java.lang.String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
-    field public static final java.lang.String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
-    field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
-    field public static final java.lang.String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
-    field public static final java.lang.String ACTION_REVIEW_APP_PERMISSION_USAGE = "android.intent.action.REVIEW_APP_PERMISSION_USAGE";
-    field public static final java.lang.String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
-    field public static final java.lang.String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
-    field public static final java.lang.String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
-    field public static final deprecated java.lang.String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
-    field public static final java.lang.String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
-    field public static final java.lang.String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
-    field public static final java.lang.String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
-    field public static final java.lang.String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
-    field public static final java.lang.String CATEGORY_LEANBACK_SETTINGS = "android.intent.category.LEANBACK_SETTINGS";
-    field public static final java.lang.String EXTRA_CALLING_PACKAGE = "android.intent.extra.CALLING_PACKAGE";
-    field public static final java.lang.String EXTRA_FORCE_FACTORY_RESET = "android.intent.extra.FORCE_FACTORY_RESET";
-    field public static final java.lang.String EXTRA_INSTANT_APP_ACTION = "android.intent.extra.INSTANT_APP_ACTION";
-    field public static final java.lang.String EXTRA_INSTANT_APP_BUNDLES = "android.intent.extra.INSTANT_APP_BUNDLES";
-    field public static final java.lang.String EXTRA_INSTANT_APP_EXTRAS = "android.intent.extra.INSTANT_APP_EXTRAS";
-    field public static final java.lang.String EXTRA_INSTANT_APP_FAILURE = "android.intent.extra.INSTANT_APP_FAILURE";
-    field public static final java.lang.String EXTRA_INSTANT_APP_HOSTNAME = "android.intent.extra.INSTANT_APP_HOSTNAME";
-    field public static final java.lang.String EXTRA_INSTANT_APP_SUCCESS = "android.intent.extra.INSTANT_APP_SUCCESS";
-    field public static final java.lang.String EXTRA_INSTANT_APP_TOKEN = "android.intent.extra.INSTANT_APP_TOKEN";
-    field public static final java.lang.String EXTRA_LONG_VERSION_CODE = "android.intent.extra.LONG_VERSION_CODE";
-    field public static final java.lang.String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID";
-    field public static final java.lang.String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
-    field public static final java.lang.String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
-    field public static final java.lang.String EXTRA_REASON = "android.intent.extra.REASON";
-    field public static final java.lang.String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
-    field public static final java.lang.String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
-    field public static final java.lang.String EXTRA_UNKNOWN_INSTANT_APP = "android.intent.extra.UNKNOWN_INSTANT_APP";
-    field public static final java.lang.String EXTRA_VERIFICATION_BUNDLE = "android.intent.extra.VERIFICATION_BUNDLE";
-    field public static final java.lang.String METADATA_SETUP_VERSION = "android.SETUP_VERSION";
+    field public static final String ACTION_BATTERY_LEVEL_CHANGED = "android.intent.action.BATTERY_LEVEL_CHANGED";
+    field public static final String ACTION_CALL_EMERGENCY = "android.intent.action.CALL_EMERGENCY";
+    field public static final String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";
+    field public static final String ACTION_DEVICE_CUSTOMIZATION_READY = "android.intent.action.DEVICE_CUSTOMIZATION_READY";
+    field public static final String ACTION_FACTORY_RESET = "android.intent.action.FACTORY_RESET";
+    field public static final String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON";
+    field public static final String ACTION_INSTALL_INSTANT_APP_PACKAGE = "android.intent.action.INSTALL_INSTANT_APP_PACKAGE";
+    field public static final String ACTION_INSTANT_APP_RESOLVER_SETTINGS = "android.intent.action.INSTANT_APP_RESOLVER_SETTINGS";
+    field public static final String ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION";
+    field public static final String ACTION_MANAGE_APP_PERMISSIONS = "android.intent.action.MANAGE_APP_PERMISSIONS";
+    field @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public static final String ACTION_MANAGE_DEFAULT_APP = "android.intent.action.MANAGE_DEFAULT_APP";
+    field public static final String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS";
+    field public static final String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
+    field @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public static final String ACTION_MANAGE_SPECIAL_APP_ACCESSES = "android.intent.action.MANAGE_SPECIAL_APP_ACCESSES";
+    field public static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
+    field public static final String ACTION_PACKAGE_ROLLBACK_EXECUTED = "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
+    field public static final String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
+    field public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
+    field public static final String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
+    field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_APP_PERMISSION_USAGE = "android.intent.action.REVIEW_APP_PERMISSION_USAGE";
+    field public static final String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
+    field public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
+    field public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
+    field @Deprecated public static final String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
+    field public static final String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
+    field public static final String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
+    field public static final String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
+    field public static final String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
+    field public static final String CATEGORY_LEANBACK_SETTINGS = "android.intent.category.LEANBACK_SETTINGS";
+    field public static final String EXTRA_CALLING_PACKAGE = "android.intent.extra.CALLING_PACKAGE";
+    field public static final String EXTRA_FORCE_FACTORY_RESET = "android.intent.extra.FORCE_FACTORY_RESET";
+    field public static final String EXTRA_INSTANT_APP_ACTION = "android.intent.extra.INSTANT_APP_ACTION";
+    field public static final String EXTRA_INSTANT_APP_BUNDLES = "android.intent.extra.INSTANT_APP_BUNDLES";
+    field public static final String EXTRA_INSTANT_APP_EXTRAS = "android.intent.extra.INSTANT_APP_EXTRAS";
+    field public static final String EXTRA_INSTANT_APP_FAILURE = "android.intent.extra.INSTANT_APP_FAILURE";
+    field public static final String EXTRA_INSTANT_APP_HOSTNAME = "android.intent.extra.INSTANT_APP_HOSTNAME";
+    field public static final String EXTRA_INSTANT_APP_SUCCESS = "android.intent.extra.INSTANT_APP_SUCCESS";
+    field public static final String EXTRA_INSTANT_APP_TOKEN = "android.intent.extra.INSTANT_APP_TOKEN";
+    field public static final String EXTRA_LONG_VERSION_CODE = "android.intent.extra.LONG_VERSION_CODE";
+    field public static final String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID";
+    field public static final String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
+    field public static final String EXTRA_PERMISSION_GROUP_NAME = "android.intent.extra.PERMISSION_GROUP_NAME";
+    field public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
+    field public static final String EXTRA_REASON = "android.intent.extra.REASON";
+    field public static final String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
+    field public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
+    field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
+    field public static final String EXTRA_UNKNOWN_INSTANT_APP = "android.intent.extra.UNKNOWN_INSTANT_APP";
+    field public static final String EXTRA_VERIFICATION_BUNDLE = "android.intent.extra.VERIFICATION_BUNDLE";
+    field public static final String METADATA_SETUP_VERSION = "android.SETUP_VERSION";
   }
 
   public class IntentFilter implements android.os.Parcelable {
@@ -1110,61 +1340,83 @@
 
 }
 
+package android.content.om {
+
+  public final class OverlayInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean isEnabled();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.om.OverlayInfo> CREATOR;
+    field public final String category;
+    field public final String packageName;
+    field public final String targetPackageName;
+    field public final int userId;
+  }
+
+  public class OverlayManager {
+    method public java.util.List<android.content.om.OverlayInfo> getOverlayInfosForTarget(@Nullable String, int);
+    method public boolean setEnabled(@Nullable String, boolean, int);
+    method public boolean setEnabledExclusiveInCategory(@Nullable String, int);
+  }
+
+}
+
 package android.content.pm {
 
   public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+    method public boolean isEncryptionAware();
     method public boolean isInstantApp();
-    field public java.lang.String credentialProtectedDataDir;
+    field public String credentialProtectedDataDir;
     field public int targetSandboxVersion;
   }
 
   public class CrossProfileApps {
-    method public void startAnyActivity(android.content.ComponentName, android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_PROFILES) public void startActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
   }
 
   public final class InstantAppInfo implements android.os.Parcelable {
-    ctor public InstantAppInfo(android.content.pm.ApplicationInfo, java.lang.String[], java.lang.String[]);
-    ctor public InstantAppInfo(java.lang.String, java.lang.CharSequence, java.lang.String[], java.lang.String[]);
+    ctor public InstantAppInfo(android.content.pm.ApplicationInfo, String[], String[]);
+    ctor public InstantAppInfo(String, CharSequence, String[], String[]);
     method public int describeContents();
-    method public android.content.pm.ApplicationInfo getApplicationInfo();
-    method public java.lang.String[] getGrantedPermissions();
-    method public java.lang.String getPackageName();
-    method public java.lang.String[] getRequestedPermissions();
-    method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
-    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
+    method @Nullable public android.content.pm.ApplicationInfo getApplicationInfo();
+    method @Nullable public String[] getGrantedPermissions();
+    method @NonNull public String getPackageName();
+    method @Nullable public String[] getRequestedPermissions();
+    method @NonNull public android.graphics.drawable.Drawable loadIcon(@NonNull android.content.pm.PackageManager);
+    method @NonNull public CharSequence loadLabel(@NonNull android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.InstantAppInfo> CREATOR;
   }
 
   public final class InstantAppIntentFilter implements android.os.Parcelable {
-    ctor public InstantAppIntentFilter(java.lang.String, java.util.List<android.content.IntentFilter>);
+    ctor public InstantAppIntentFilter(@Nullable String, @NonNull java.util.List<android.content.IntentFilter>);
     method public int describeContents();
     method public java.util.List<android.content.IntentFilter> getFilters();
-    method public java.lang.String getSplitName();
+    method public String getSplitName();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.InstantAppIntentFilter> CREATOR;
   }
 
   public final class InstantAppResolveInfo implements android.os.Parcelable {
-    ctor public InstantAppResolveInfo(android.content.pm.InstantAppResolveInfo.InstantAppDigest, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>, int);
-    ctor public InstantAppResolveInfo(android.content.pm.InstantAppResolveInfo.InstantAppDigest, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>, long, android.os.Bundle);
-    ctor public InstantAppResolveInfo(java.lang.String, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>);
-    ctor public InstantAppResolveInfo(android.os.Bundle);
+    ctor public InstantAppResolveInfo(@NonNull android.content.pm.InstantAppResolveInfo.InstantAppDigest, @Nullable String, @Nullable java.util.List<android.content.pm.InstantAppIntentFilter>, int);
+    ctor public InstantAppResolveInfo(@NonNull android.content.pm.InstantAppResolveInfo.InstantAppDigest, @Nullable String, @Nullable java.util.List<android.content.pm.InstantAppIntentFilter>, long, @Nullable android.os.Bundle);
+    ctor public InstantAppResolveInfo(@NonNull String, @Nullable String, @Nullable java.util.List<android.content.pm.InstantAppIntentFilter>);
+    ctor public InstantAppResolveInfo(@Nullable android.os.Bundle);
     method public int describeContents();
     method public byte[] getDigestBytes();
     method public int getDigestPrefix();
-    method public android.os.Bundle getExtras();
+    method @Nullable public android.os.Bundle getExtras();
     method public java.util.List<android.content.pm.InstantAppIntentFilter> getIntentFilters();
     method public long getLongVersionCode();
-    method public java.lang.String getPackageName();
-    method public deprecated int getVersionCode();
+    method public String getPackageName();
+    method @Deprecated public int getVersionCode();
     method public boolean shouldLetInstallerDecide();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.InstantAppResolveInfo> CREATOR;
   }
 
   public static final class InstantAppResolveInfo.InstantAppDigest implements android.os.Parcelable {
-    ctor public InstantAppResolveInfo.InstantAppDigest(java.lang.String);
+    ctor public InstantAppResolveInfo.InstantAppDigest(@NonNull String);
     method public int describeContents();
     method public byte[][] getDigestBytes();
     method public int[] getDigestPrefix();
@@ -1176,90 +1428,92 @@
   public final class IntentFilterVerificationInfo implements android.os.Parcelable {
     method public int describeContents();
     method public java.util.Set<java.lang.String> getDomains();
-    method public java.lang.String getPackageName();
+    method public String getPackageName();
     method public int getStatus();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.IntentFilterVerificationInfo> CREATOR;
   }
 
   public class PackageInstaller {
-    method public void setPermissionsResult(int, boolean);
+    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setPermissionsResult(int, boolean);
   }
 
   public static class PackageInstaller.Session implements java.io.Closeable {
-    method public void commitTransferred(android.content.IntentSender);
+    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void commitTransferred(@NonNull android.content.IntentSender);
   }
 
   public static class PackageInstaller.SessionInfo implements android.os.Parcelable {
     method public boolean getAllocateAggressive();
     method public boolean getAllowDowngrade();
     method public boolean getDontKillApp();
-    method public java.lang.String[] getGrantedRuntimePermissions();
+    method @Nullable public String[] getGrantedRuntimePermissions();
     method public boolean getInstallAsFullApp(boolean);
     method public boolean getInstallAsInstantApp(boolean);
     method public boolean getInstallAsVirtualPreload();
   }
 
   public static class PackageInstaller.SessionParams implements android.os.Parcelable {
-    method public void setAllocateAggressive(boolean);
+    method @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public void setAllocateAggressive(boolean);
     method public void setAllowDowngrade(boolean);
     method public void setDontKillApp(boolean);
-    method public void setGrantedRuntimePermissions(java.lang.String[]);
+    method public void setEnableRollback();
+    method @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[]);
     method public void setInstallAsInstantApp(boolean);
     method public void setInstallAsVirtualPreload();
   }
 
   public class PackageItemInfo {
     method public static void forceSafeLabels();
-    method public deprecated java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager);
-    method public java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager, float, int);
-    field public static final deprecated int SAFE_LABEL_FLAG_FIRST_LINE = 4; // 0x4
-    field public static final deprecated int SAFE_LABEL_FLAG_SINGLE_LINE = 2; // 0x2
-    field public static final deprecated int SAFE_LABEL_FLAG_TRIM = 1; // 0x1
+    method @Deprecated @NonNull public CharSequence loadSafeLabel(@NonNull android.content.pm.PackageManager);
+    method @NonNull public CharSequence loadSafeLabel(@NonNull android.content.pm.PackageManager, @FloatRange(from=0) float, int);
+    field @Deprecated public static final int SAFE_LABEL_FLAG_FIRST_LINE = 4; // 0x4
+    field @Deprecated public static final int SAFE_LABEL_FLAG_SINGLE_LINE = 2; // 0x2
+    field @Deprecated public static final int SAFE_LABEL_FLAG_TRIM = 1; // 0x1
   }
 
   public abstract class PackageManager {
-    method public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
+    method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public abstract boolean arePermissionsIndividuallyControlled();
-    method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String);
-    method public android.content.pm.ApplicationInfo getApplicationInfoAsUser(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.content.pm.dex.ArtManager getArtManager();
-    method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int);
-    method public java.lang.CharSequence getHarmfulAppWarning(java.lang.String);
-    method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
-    method public abstract android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String);
+    method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.pm.ApplicationInfo getApplicationInfoAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public android.content.pm.dex.ArtManager getArtManager();
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract String getDefaultBrowserPackageNameAsUser(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.SET_HARMFUL_APP_WARNINGS) public CharSequence getHarmfulAppWarning(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_INSTANT_APPS) public abstract android.graphics.drawable.Drawable getInstantAppIcon(String);
     method public abstract android.content.ComponentName getInstantAppInstallerComponent();
     method public abstract android.content.ComponentName getInstantAppResolverSettingsComponent();
-    method public abstract java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
-    method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
-    method public abstract int getIntentVerificationStatusAsUser(java.lang.String, int);
-    method public abstract int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
-    method public java.lang.String[] getUnsuspendablePackages(java.lang.String[]);
-    method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
-    method public abstract int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, android.os.UserHandle);
-    method public java.util.List<android.content.pm.ResolveInfo> queryIntentActivitiesAsUser(android.content.Intent, int, android.os.UserHandle);
-    method public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProvidersAsUser(android.content.Intent, int, android.os.UserHandle);
-    method public java.util.List<android.content.pm.ResolveInfo> queryIntentServicesAsUser(android.content.Intent, int, android.os.UserHandle);
-    method public abstract void registerDexModule(java.lang.String, android.content.pm.PackageManager.DexModuleRegisterCallback);
-    method public abstract void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
-    method public deprecated void replacePreferredActivity(android.content.IntentFilter, int, java.util.List<android.content.ComponentName>, android.content.ComponentName);
-    method public abstract void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
+    method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_INSTANT_APPS) public abstract java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
+    method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(String);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract int getIntentVerificationStatusAsUser(String, int);
+    method @android.content.pm.PackageManager.PermissionFlags @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract int getPermissionFlags(String, String, @NonNull android.os.UserHandle);
+    method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] getUnsuspendablePackages(@NonNull String[]);
+    method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
+    method public abstract int installExistingPackage(String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract int installExistingPackage(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, android.os.UserHandle);
+    method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentActivitiesAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
+    method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProvidersAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
+    method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentServicesAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
+    method public abstract void registerDexModule(String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback);
+    method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
+    method @Deprecated public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName);
+    method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method public void sendDeviceCustomizationReadyBroadcast();
-    method public abstract boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
-    method public void setHarmfulAppWarning(java.lang.String, java.lang.CharSequence);
-    method public deprecated java.lang.String[] setPackagesSuspended(java.lang.String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, java.lang.String);
-    method public java.lang.String[] setPackagesSuspended(java.lang.String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, android.content.pm.SuspendDialogInfo);
-    method public abstract void setUpdateAvailable(java.lang.String, boolean);
-    method public abstract boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
-    method public abstract void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
-    method public abstract void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
-    field public static final java.lang.String ACTION_REQUEST_PERMISSIONS = "android.content.pm.action.REQUEST_PERMISSIONS";
-    field public static final java.lang.String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
-    field public static final java.lang.String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
-    field public static final java.lang.String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
-    field public static final java.lang.String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
+    method @RequiresPermission(allOf={android.Manifest.permission.SET_PREFERRED_APPLICATIONS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract boolean setDefaultBrowserPackageNameAsUser(String, int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setDistractingPackageRestrictions(@NonNull String[], @android.content.pm.PackageManager.DistractionRestriction int);
+    method @RequiresPermission(android.Manifest.permission.SET_HARMFUL_APP_WARNINGS) public void setHarmfulAppWarning(@NonNull String, @Nullable CharSequence);
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable String);
+    method @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable android.content.pm.SuspendDialogInfo);
+    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public abstract void setUpdateAvailable(String, boolean);
+    method @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS) public abstract boolean updateIntentVerificationStatusAsUser(String, int, int);
+    method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract void updatePermissionFlags(String, String, @android.content.pm.PackageManager.PermissionFlags int, @android.content.pm.PackageManager.PermissionFlags int, @NonNull android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT) public abstract void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
+    field public static final String ACTION_REQUEST_PERMISSIONS = "android.content.pm.action.REQUEST_PERMISSIONS";
+    field public static final String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
+    field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
+    field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
+    field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
     field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20
     field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
     field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
@@ -1315,37 +1569,60 @@
     field public static final int MATCH_ANY_USER = 4194304; // 0x400000
     field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
     field public static final int MATCH_INSTANT = 8388608; // 0x800000
+    field public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 1; // 0x1
+    field public static final int RESTRICTION_HIDE_NOTIFICATIONS = 2; // 0x2
+    field public static final int RESTRICTION_NONE = 0; // 0x0
   }
 
-  public static abstract class PackageManager.DexModuleRegisterCallback {
+  public abstract static class PackageManager.DexModuleRegisterCallback {
     ctor public PackageManager.DexModuleRegisterCallback();
-    method public abstract void onDexModuleRegistered(java.lang.String, boolean, java.lang.String);
+    method public abstract void onDexModuleRegistered(String, boolean, String);
   }
 
-  public static abstract interface PackageManager.OnPermissionsChangedListener {
-    method public abstract void onPermissionsChanged(int);
+  @IntDef(flag=true, prefix={"RESTRICTION_"}, value={android.content.pm.PackageManager.RESTRICTION_NONE, android.content.pm.PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, android.content.pm.PackageManager.RESTRICTION_HIDE_NOTIFICATIONS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.DistractionRestriction {
   }
 
-  public static abstract class PackageManager.PermissionFlags implements java.lang.annotation.Annotation {
+  public static interface PackageManager.OnPermissionsChangedListener {
+    method public void onPermissionsChanged(int);
+  }
+
+  @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
   }
 
   public class PermissionGroupInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
-    field public int backgroundRequestDetailResourceId;
-    field public int backgroundRequestResourceId;
-    field public int requestDetailResourceId;
-    field public int requestRes;
+    field @StringRes public int backgroundRequestDetailResourceId;
+    field @StringRes public int backgroundRequestResourceId;
+    field @StringRes public int requestDetailResourceId;
+    field @StringRes public int requestRes;
   }
 
   public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
     field public static final int FLAG_REMOVED = 2; // 0x2
+    field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
     field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
     field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
     field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
     field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
-    field public java.lang.String backgroundPermission;
+    field public String backgroundPermission;
     field public int requestRes;
   }
 
+  public class ResolveInfo implements android.os.Parcelable {
+    field public boolean handleAllWebDataURI;
+  }
+
+  public class ShortcutManager {
+    method @NonNull public java.util.List<android.content.pm.ShortcutManager.ShareShortcutInfo> getShareTargets(@NonNull android.content.IntentFilter);
+  }
+
+  public static final class ShortcutManager.ShareShortcutInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.pm.ShortcutInfo getShortcutInfo();
+    method public android.content.ComponentName getTargetComponent();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutManager.ShareShortcutInfo> CREATOR;
+  }
+
   public final class SuspendDialogInfo implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -1354,12 +1631,12 @@
 
   public static final class SuspendDialogInfo.Builder {
     ctor public SuspendDialogInfo.Builder();
-    method public android.content.pm.SuspendDialogInfo build();
-    method public android.content.pm.SuspendDialogInfo.Builder setIcon(int);
-    method public android.content.pm.SuspendDialogInfo.Builder setMessage(java.lang.String);
-    method public android.content.pm.SuspendDialogInfo.Builder setMessage(int);
-    method public android.content.pm.SuspendDialogInfo.Builder setNeutralButtonText(int);
-    method public android.content.pm.SuspendDialogInfo.Builder setTitle(int);
+    method @NonNull public android.content.pm.SuspendDialogInfo build();
+    method @NonNull public android.content.pm.SuspendDialogInfo.Builder setIcon(@DrawableRes int);
+    method @NonNull public android.content.pm.SuspendDialogInfo.Builder setMessage(@NonNull String);
+    method @NonNull public android.content.pm.SuspendDialogInfo.Builder setMessage(@StringRes int);
+    method @NonNull public android.content.pm.SuspendDialogInfo.Builder setNeutralButtonText(@StringRes int);
+    method @NonNull public android.content.pm.SuspendDialogInfo.Builder setTitle(@StringRes int);
   }
 
 }
@@ -1367,8 +1644,8 @@
 package android.content.pm.dex {
 
   public class ArtManager {
-    method public boolean isRuntimeProfilingEnabled(int);
-    method public void snapshotRuntimeProfile(int, java.lang.String, java.lang.String, java.util.concurrent.Executor, android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback);
+    method @RequiresPermission(allOf={android.Manifest.permission.READ_RUNTIME_PROFILES, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean isRuntimeProfilingEnabled(int);
+    method @RequiresPermission(allOf={android.Manifest.permission.READ_RUNTIME_PROFILES, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void snapshotRuntimeProfile(int, @Nullable String, @Nullable String, @NonNull java.util.concurrent.Executor, @NonNull android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback);
     field public static final int PROFILE_APPS = 0; // 0x0
     field public static final int PROFILE_BOOT_IMAGE = 1; // 0x1
     field public static final int SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND = 1; // 0x1
@@ -1376,7 +1653,7 @@
     field public static final int SNAPSHOT_FAILED_PACKAGE_NOT_FOUND = 0; // 0x0
   }
 
-  public static abstract class ArtManager.SnapshotRuntimeProfileCallback {
+  public abstract static class ArtManager.SnapshotRuntimeProfileCallback {
     ctor public ArtManager.SnapshotRuntimeProfileCallback();
     method public abstract void onError(int);
     method public abstract void onSuccess(android.os.ParcelFileDescriptor);
@@ -1386,14 +1663,44 @@
 
 package android.content.pm.permission {
 
-  public final deprecated class RuntimePermissionPresentationInfo implements android.os.Parcelable {
-    ctor public RuntimePermissionPresentationInfo(java.lang.CharSequence, boolean, boolean);
+  @Deprecated public final class RuntimePermissionPresentationInfo implements android.os.Parcelable {
+    ctor @Deprecated public RuntimePermissionPresentationInfo(CharSequence, boolean, boolean);
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public CharSequence getLabel();
+    method @Deprecated public boolean isGranted();
+    method @Deprecated public boolean isStandard();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.content.pm.permission.RuntimePermissionPresentationInfo> CREATOR;
+  }
+
+}
+
+package android.content.rollback {
+
+  public final class PackageRollbackInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.CharSequence getLabel();
-    method public boolean isGranted();
-    method public boolean isStandard();
+    method public String getPackageName();
+    method public android.content.pm.VersionedPackage getVersionRolledBackFrom();
+    method public android.content.pm.VersionedPackage getVersionRolledBackTo();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.content.pm.permission.RuntimePermissionPresentationInfo> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.content.rollback.PackageRollbackInfo> CREATOR;
+  }
+
+  public final class RollbackInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getRollbackId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR;
+    field public final android.content.rollback.PackageRollbackInfo targetPackage;
+  }
+
+  public final class RollbackManager {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void executeRollback(@NonNull android.content.rollback.RollbackInfo, @NonNull android.content.IntentSender);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @Nullable public android.content.rollback.RollbackInfo getAvailableRollback(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<java.lang.String> getPackagesWithAvailableRollbacks();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyExecutedRollbacks();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData();
   }
 
 }
@@ -1403,8 +1710,8 @@
   public final class Sensor {
     method public java.util.UUID getUuid();
     method public boolean isDataInjectionSupported();
-    field public static final java.lang.String STRING_TYPE_DYNAMIC_SENSOR_META = "android.sensor.dynamic_sensor_meta";
-    field public static final java.lang.String STRING_TYPE_WRIST_TILT_GESTURE = "android.sensor.wrist_tilt_gesture";
+    field public static final String STRING_TYPE_DYNAMIC_SENSOR_META = "android.sensor.dynamic_sensor_meta";
+    field public static final String STRING_TYPE_WRIST_TILT_GESTURE = "android.sensor.wrist_tilt_gesture";
     field public static final int TYPE_DYNAMIC_SENSOR_META = 32; // 0x20
     field public static final int TYPE_WRIST_TILT_GESTURE = 26; // 0x1a
   }
@@ -1419,7 +1726,7 @@
 package android.hardware.camera2 {
 
   public abstract class CameraDevice implements java.lang.AutoCloseable {
-    method public abstract void createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     field public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED = 1; // 0x1
     field public static final int SESSION_OPERATION_MODE_NORMAL = 0; // 0x0
     field public static final int SESSION_OPERATION_MODE_VENDOR_START = 32768; // 0x8000
@@ -1430,8 +1737,8 @@
 package android.hardware.camera2.params {
 
   public final class OutputConfiguration implements android.os.Parcelable {
-    ctor public OutputConfiguration(android.view.Surface, int);
-    ctor public OutputConfiguration(int, android.view.Surface, int);
+    ctor public OutputConfiguration(@NonNull android.view.Surface, int);
+    ctor public OutputConfiguration(int, @NonNull android.view.Surface, int);
     method public int getRotation();
     field public static final int ROTATION_0 = 0; // 0x0
     field public static final int ROTATION_180 = 2; // 0x2
@@ -1465,16 +1772,16 @@
     field public final long[] luxTimestamps;
     field public final float[] luxValues;
     field public final boolean nightMode;
-    field public final java.lang.String packageName;
+    field public final String packageName;
     field public final float powerBrightnessFactor;
     field public final long timeStamp;
   }
 
   public final class BrightnessConfiguration implements android.os.Parcelable {
     method public int describeContents();
-    method public android.hardware.display.BrightnessCorrection getCorrectionByCategory(int);
-    method public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(java.lang.String);
-    method public android.util.Pair<float[], float[]> getCurve();
+    method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByCategory(int);
+    method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(String);
+    method public android.util.Pair<float[],float[]> getCurve();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR;
   }
@@ -1482,30 +1789,40 @@
   public static class BrightnessConfiguration.Builder {
     ctor public BrightnessConfiguration.Builder(float[], float[]);
     method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByCategory(int, android.hardware.display.BrightnessCorrection);
-    method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByPackageName(java.lang.String, android.hardware.display.BrightnessCorrection);
+    method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByPackageName(String, android.hardware.display.BrightnessCorrection);
     method public android.hardware.display.BrightnessConfiguration build();
     method public int getMaxCorrectionsByCategory();
     method public int getMaxCorrectionsByPackageName();
-    method public android.hardware.display.BrightnessConfiguration.Builder setDescription(java.lang.String);
+    method public android.hardware.display.BrightnessConfiguration.Builder setDescription(@Nullable String);
   }
 
   public final class BrightnessCorrection implements android.os.Parcelable {
     method public float apply(float);
-    method public static android.hardware.display.BrightnessCorrection createScaleAndTranslateLog(float, float);
+    method @NonNull public static android.hardware.display.BrightnessCorrection createScaleAndTranslateLog(float, float);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessCorrection> CREATOR;
   }
 
+  public final class ColorDisplayManager {
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public int getTransformCapabilities();
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setAppSaturationLevel(@NonNull String, @IntRange(from=0, to=100) int);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setSaturationLevel(@IntRange(from=0, to=100) int);
+    field public static final int CAPABILITY_HARDWARE_ACCELERATION_GLOBAL = 2; // 0x2
+    field public static final int CAPABILITY_HARDWARE_ACCELERATION_PER_APP = 4; // 0x4
+    field public static final int CAPABILITY_NONE = 0; // 0x0
+    field public static final int CAPABILITY_PROTECTED_CONTENT = 1; // 0x1
+  }
+
   public final class DisplayManager {
-    method public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
-    method public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration();
-    method public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents();
-    method public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration();
-    method public android.util.Pair<float[], float[]> getMinimumBrightnessCurve();
+    method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_LIGHT_STATS) public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
+    method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration();
+    method @RequiresPermission(android.Manifest.permission.BRIGHTNESS_SLIDER_USAGE) public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents();
+    method @Nullable @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration();
+    method public android.util.Pair<float[],float[]> getMinimumBrightnessCurve();
     method public android.graphics.Point getStableDisplaySize();
-    method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
-    method public void setSaturationLevel(float);
+    method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_SATURATION) public void setSaturationLevel(float);
   }
 
 }
@@ -1516,17 +1833,17 @@
     method public android.hardware.hdmi.HdmiDeviceInfo getActiveSource();
     method public void sendKeyEvent(int, boolean);
     method public void sendVendorCommand(int, byte[], boolean);
-    method public void setVendorCommandListener(android.hardware.hdmi.HdmiControlManager.VendorCommandListener);
+    method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener);
   }
 
   public final class HdmiControlManager {
-    method public void addHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
-    method public android.hardware.hdmi.HdmiClient getClient(int);
-    method public android.hardware.hdmi.HdmiPlaybackClient getPlaybackClient();
-    method public android.hardware.hdmi.HdmiTvClient getTvClient();
-    method public void removeHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
-    method public void setStandbyMode(boolean);
-    field public static final java.lang.String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE";
+    method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
+    method @Nullable public android.hardware.hdmi.HdmiClient getClient(int);
+    method @Nullable public android.hardware.hdmi.HdmiPlaybackClient getPlaybackClient();
+    method @Nullable public android.hardware.hdmi.HdmiTvClient getTvClient();
+    method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
+    method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setStandbyMode(boolean);
+    field public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE";
     field public static final int AVR_VOLUME_MUTED = 101; // 0x65
     field public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 162; // 0xa2
     field public static final int CLEAR_TIMER_STATUS_CHECK_RECORDER_CONNECTION = 160; // 0xa0
@@ -1542,8 +1859,8 @@
     field public static final int DEVICE_EVENT_ADD_DEVICE = 1; // 0x1
     field public static final int DEVICE_EVENT_REMOVE_DEVICE = 2; // 0x2
     field public static final int DEVICE_EVENT_UPDATE_DEVICE = 3; // 0x3
-    field public static final java.lang.String EXTRA_MESSAGE_EXTRA_PARAM1 = "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1";
-    field public static final java.lang.String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID";
+    field public static final String EXTRA_MESSAGE_EXTRA_PARAM1 = "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1";
+    field public static final String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID";
     field public static final int ONE_TOUCH_RECORD_ALREADY_RECORDING = 18; // 0x12
     field public static final int ONE_TOUCH_RECORD_CEC_DISABLED = 51; // 0x33
     field public static final int ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION = 49; // 0x31
@@ -1579,7 +1896,7 @@
     field public static final int POWER_STATUS_TRANSIENT_TO_ON = 2; // 0x2
     field public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3; // 0x3
     field public static final int POWER_STATUS_UNKNOWN = -1; // 0xffffffff
-    field public static final deprecated int RESULT_ALREADY_IN_PROGRESS = 4; // 0x4
+    field @Deprecated public static final int RESULT_ALREADY_IN_PROGRESS = 4; // 0x4
     field public static final int RESULT_COMMUNICATION_FAILED = 7; // 0x7
     field public static final int RESULT_EXCEPTION = 5; // 0x5
     field public static final int RESULT_INCORRECT_MODE = 6; // 0x6
@@ -1614,13 +1931,13 @@
     field public static final int TIMER_STATUS_PROGRAMMED_INFO_NO_MEDIA_INFO = 10; // 0xa
   }
 
-  public static abstract interface HdmiControlManager.HotplugEventListener {
-    method public abstract void onReceived(android.hardware.hdmi.HdmiHotplugEvent);
+  public static interface HdmiControlManager.HotplugEventListener {
+    method public void onReceived(android.hardware.hdmi.HdmiHotplugEvent);
   }
 
-  public static abstract interface HdmiControlManager.VendorCommandListener {
-    method public abstract void onControlStateChanged(boolean, int);
-    method public abstract void onReceived(int, int, byte[], boolean);
+  public static interface HdmiControlManager.VendorCommandListener {
+    method public void onControlStateChanged(boolean, int);
+    method public void onReceived(int, int, byte[], boolean);
   }
 
   public class HdmiDeviceInfo implements android.os.Parcelable {
@@ -1630,7 +1947,7 @@
     method public int getDeviceId();
     method public int getDevicePowerStatus();
     method public int getDeviceType();
-    method public java.lang.String getDisplayName();
+    method public String getDisplayName();
     method public int getId();
     method public int getLogicalAddress();
     method public int getPhysicalAddress();
@@ -1675,12 +1992,12 @@
     method public void sendStandby();
   }
 
-  public static abstract interface HdmiPlaybackClient.DisplayStatusCallback {
-    method public abstract void onComplete(int);
+  public static interface HdmiPlaybackClient.DisplayStatusCallback {
+    method public void onComplete(int);
   }
 
-  public static abstract interface HdmiPlaybackClient.OneTouchPlayCallback {
-    method public abstract void onComplete(int);
+  public static interface HdmiPlaybackClient.OneTouchPlayCallback {
+    method public void onComplete(int);
   }
 
   public final class HdmiPortInfo implements android.os.Parcelable {
@@ -1737,7 +2054,7 @@
   public static final class HdmiRecordSources.OwnSource extends android.hardware.hdmi.HdmiRecordSources.RecordSource {
   }
 
-  public static abstract class HdmiRecordSources.RecordSource {
+  public abstract static class HdmiRecordSources.RecordSource {
   }
 
   public class HdmiTimerRecordSources {
@@ -1773,34 +2090,34 @@
 
   public final class HdmiTvClient extends android.hardware.hdmi.HdmiClient {
     method public void clearTimerRecording(int, int, android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource);
-    method public void deviceSelect(int, android.hardware.hdmi.HdmiTvClient.SelectCallback);
+    method public void deviceSelect(int, @NonNull android.hardware.hdmi.HdmiTvClient.SelectCallback);
     method public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getDeviceList();
     method public int getDeviceType();
-    method public void portSelect(int, android.hardware.hdmi.HdmiTvClient.SelectCallback);
+    method public void portSelect(int, @NonNull android.hardware.hdmi.HdmiTvClient.SelectCallback);
     method public void sendMhlVendorCommand(int, int, int, byte[]);
     method public void sendStandby(int);
     method public void setHdmiMhlVendorCommandListener(android.hardware.hdmi.HdmiTvClient.HdmiMhlVendorCommandListener);
     method public void setInputChangeListener(android.hardware.hdmi.HdmiTvClient.InputChangeListener);
-    method public void setRecordListener(android.hardware.hdmi.HdmiRecordListener);
+    method public void setRecordListener(@NonNull android.hardware.hdmi.HdmiRecordListener);
     method public void setSystemAudioMode(boolean, android.hardware.hdmi.HdmiTvClient.SelectCallback);
     method public void setSystemAudioMute(boolean);
     method public void setSystemAudioVolume(int, int, int);
-    method public void startOneTouchRecord(int, android.hardware.hdmi.HdmiRecordSources.RecordSource);
+    method public void startOneTouchRecord(int, @NonNull android.hardware.hdmi.HdmiRecordSources.RecordSource);
     method public void startTimerRecording(int, int, android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource);
     method public void stopOneTouchRecord(int);
     field public static final int VENDOR_DATA_SIZE = 16; // 0x10
   }
 
-  public static abstract interface HdmiTvClient.HdmiMhlVendorCommandListener {
-    method public abstract void onReceived(int, int, int, byte[]);
+  public static interface HdmiTvClient.HdmiMhlVendorCommandListener {
+    method public void onReceived(int, int, int, byte[]);
   }
 
-  public static abstract interface HdmiTvClient.InputChangeListener {
-    method public abstract void onChanged(android.hardware.hdmi.HdmiDeviceInfo);
+  public static interface HdmiTvClient.InputChangeListener {
+    method public void onChanged(android.hardware.hdmi.HdmiDeviceInfo);
   }
 
-  public static abstract interface HdmiTvClient.SelectCallback {
-    method public abstract void onComplete(int);
+  public static interface HdmiTvClient.SelectCallback {
+    method public void onComplete(int);
   }
 
 }
@@ -1809,8 +2126,8 @@
 
   public class ContextHubClient implements java.io.Closeable {
     method public void close();
-    method public android.hardware.location.ContextHubInfo getAttachedHub();
-    method public int sendMessageToNanoApp(android.hardware.location.NanoAppMessage);
+    method @NonNull public android.hardware.location.ContextHubInfo getAttachedHub();
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int sendMessageToNanoApp(@NonNull android.hardware.location.NanoAppMessage);
   }
 
   public class ContextHubClientCallback {
@@ -1834,7 +2151,7 @@
     method public int getId();
     method public int getMaxPacketLengthBytes();
     method public android.hardware.location.MemoryRegion[] getMemoryRegions();
-    method public java.lang.String getName();
+    method public String getName();
     method public float getPeakMips();
     method public float getPeakPowerDrawMw();
     method public int getPlatformVersion();
@@ -1842,42 +2159,42 @@
     method public int getStaticSwVersion();
     method public float getStoppedPowerDrawMw();
     method public int[] getSupportedSensors();
-    method public java.lang.String getToolchain();
+    method public String getToolchain();
     method public int getToolchainVersion();
-    method public java.lang.String getVendor();
+    method public String getVendor();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubInfo> CREATOR;
   }
 
   public class ContextHubIntentEvent {
-    method public static android.hardware.location.ContextHubIntentEvent fromIntent(android.content.Intent);
-    method public android.hardware.location.ContextHubInfo getContextHubInfo();
+    method @NonNull public static android.hardware.location.ContextHubIntentEvent fromIntent(@NonNull android.content.Intent);
+    method @NonNull public android.hardware.location.ContextHubInfo getContextHubInfo();
     method public int getEventType();
     method public int getNanoAppAbortCode();
     method public long getNanoAppId();
-    method public android.hardware.location.NanoAppMessage getNanoAppMessage();
+    method @NonNull public android.hardware.location.NanoAppMessage getNanoAppMessage();
   }
 
   public final class ContextHubManager {
-    method public android.hardware.location.ContextHubClient createClient(android.hardware.location.ContextHubInfo, android.hardware.location.ContextHubClientCallback, java.util.concurrent.Executor);
-    method public android.hardware.location.ContextHubClient createClient(android.hardware.location.ContextHubInfo, android.hardware.location.ContextHubClientCallback);
-    method public android.hardware.location.ContextHubClient createClient(android.hardware.location.ContextHubInfo, android.app.PendingIntent, long);
-    method public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(android.hardware.location.ContextHubInfo, long);
-    method public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(android.hardware.location.ContextHubInfo, long);
-    method public deprecated int[] findNanoAppOnHub(int, android.hardware.location.NanoAppFilter);
-    method public deprecated int[] getContextHubHandles();
-    method public deprecated android.hardware.location.ContextHubInfo getContextHubInfo(int);
-    method public java.util.List<android.hardware.location.ContextHubInfo> getContextHubs();
-    method public deprecated android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
-    method public deprecated int loadNanoApp(int, android.hardware.location.NanoApp);
-    method public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(android.hardware.location.ContextHubInfo, android.hardware.location.NanoAppBinary);
-    method public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(android.hardware.location.ContextHubInfo);
-    method public deprecated int registerCallback(android.hardware.location.ContextHubManager.Callback);
-    method public deprecated int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler);
-    method public deprecated int sendMessage(int, int, android.hardware.location.ContextHubMessage);
-    method public deprecated int unloadNanoApp(int);
-    method public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(android.hardware.location.ContextHubInfo, long);
-    method public deprecated int unregisterCallback(android.hardware.location.ContextHubManager.Callback);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback, @NonNull java.util.concurrent.Executor);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.app.PendingIntent, long);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int[] findNanoAppOnHub(int, @NonNull android.hardware.location.NanoAppFilter);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int[] getContextHubHandles();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubInfo getContextHubInfo(int);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public java.util.List<android.hardware.location.ContextHubInfo> getContextHubs();
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int loadNanoApp(int, @NonNull android.hardware.location.NanoApp);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo);
+    method @Deprecated public int registerCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
+    method @Deprecated public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int unloadNanoApp(int);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+    method @Deprecated public int unregisterCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
     field public static final int EVENT_HUB_RESET = 6; // 0x6
     field public static final int EVENT_NANOAPP_ABORTED = 4; // 0x4
     field public static final int EVENT_NANOAPP_DISABLED = 3; // 0x3
@@ -1885,36 +2202,36 @@
     field public static final int EVENT_NANOAPP_LOADED = 0; // 0x0
     field public static final int EVENT_NANOAPP_MESSAGE = 5; // 0x5
     field public static final int EVENT_NANOAPP_UNLOADED = 1; // 0x1
-    field public static final java.lang.String EXTRA_CONTEXT_HUB_INFO = "android.hardware.location.extra.CONTEXT_HUB_INFO";
-    field public static final java.lang.String EXTRA_EVENT_TYPE = "android.hardware.location.extra.EVENT_TYPE";
-    field public static final java.lang.String EXTRA_MESSAGE = "android.hardware.location.extra.MESSAGE";
-    field public static final java.lang.String EXTRA_NANOAPP_ABORT_CODE = "android.hardware.location.extra.NANOAPP_ABORT_CODE";
-    field public static final java.lang.String EXTRA_NANOAPP_ID = "android.hardware.location.extra.NANOAPP_ID";
+    field public static final String EXTRA_CONTEXT_HUB_INFO = "android.hardware.location.extra.CONTEXT_HUB_INFO";
+    field public static final String EXTRA_EVENT_TYPE = "android.hardware.location.extra.EVENT_TYPE";
+    field public static final String EXTRA_MESSAGE = "android.hardware.location.extra.MESSAGE";
+    field public static final String EXTRA_NANOAPP_ABORT_CODE = "android.hardware.location.extra.NANOAPP_ABORT_CODE";
+    field public static final String EXTRA_NANOAPP_ID = "android.hardware.location.extra.NANOAPP_ID";
   }
 
-  public static abstract deprecated class ContextHubManager.Callback {
-    ctor protected ContextHubManager.Callback();
-    method public abstract void onMessageReceipt(int, int, android.hardware.location.ContextHubMessage);
+  @Deprecated public abstract static class ContextHubManager.Callback {
+    ctor @Deprecated protected ContextHubManager.Callback();
+    method @Deprecated public abstract void onMessageReceipt(int, int, @NonNull android.hardware.location.ContextHubMessage);
   }
 
-  public deprecated class ContextHubMessage implements android.os.Parcelable {
-    ctor public ContextHubMessage(int, int, byte[]);
-    method public int describeContents();
-    method public byte[] getData();
-    method public int getMsgType();
-    method public int getVersion();
-    method public void setMsgData(byte[]);
-    method public void setMsgType(int);
-    method public void setVersion(int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubMessage> CREATOR;
+  @Deprecated public class ContextHubMessage implements android.os.Parcelable {
+    ctor @Deprecated public ContextHubMessage(int, int, byte[]);
+    method @Deprecated public int describeContents();
+    method @Deprecated public byte[] getData();
+    method @Deprecated public int getMsgType();
+    method @Deprecated public int getVersion();
+    method @Deprecated public void setMsgData(byte[]);
+    method @Deprecated public void setMsgType(int);
+    method @Deprecated public void setVersion(int);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubMessage> CREATOR;
   }
 
   public class ContextHubTransaction<T> {
     method public int getType();
-    method public void setOnCompleteListener(android.hardware.location.ContextHubTransaction.OnCompleteListener<T>, java.util.concurrent.Executor);
-    method public void setOnCompleteListener(android.hardware.location.ContextHubTransaction.OnCompleteListener<T>);
-    method public static java.lang.String typeToString(int, boolean);
+    method public void setOnCompleteListener(@NonNull android.hardware.location.ContextHubTransaction.OnCompleteListener<T>, @NonNull java.util.concurrent.Executor);
+    method public void setOnCompleteListener(@NonNull android.hardware.location.ContextHubTransaction.OnCompleteListener<T>);
+    method public static String typeToString(int, boolean);
     method public android.hardware.location.ContextHubTransaction.Response<T> waitForResponse(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
     field public static final int RESULT_FAILED_AT_HUB = 5; // 0x5
     field public static final int RESULT_FAILED_BAD_PARAMS = 2; // 0x2
@@ -1932,8 +2249,8 @@
     field public static final int TYPE_UNLOAD_NANOAPP = 1; // 0x1
   }
 
-  public static abstract interface ContextHubTransaction.OnCompleteListener<L> {
-    method public abstract void onComplete(android.hardware.location.ContextHubTransaction<L>, android.hardware.location.ContextHubTransaction.Response<L>);
+  @java.lang.FunctionalInterface public static interface ContextHubTransaction.OnCompleteListener<L> {
+    method public void onComplete(android.hardware.location.ContextHubTransaction<L>, android.hardware.location.ContextHubTransaction.Response<L>);
   }
 
   public static class ContextHubTransaction.Response<R> {
@@ -1983,7 +2300,7 @@
 
   public abstract class GeofenceHardwareMonitorCallback {
     ctor public GeofenceHardwareMonitorCallback();
-    method public deprecated void onMonitoringSystemChange(int, boolean, android.location.Location);
+    method @Deprecated public void onMonitoringSystemChange(int, boolean, android.location.Location);
     method public void onMonitoringSystemChange(android.hardware.location.GeofenceHardwareMonitorEvent);
   }
 
@@ -2028,33 +2345,33 @@
     field public static final android.os.Parcelable.Creator<android.hardware.location.MemoryRegion> CREATOR;
   }
 
-  public deprecated class NanoApp implements android.os.Parcelable {
-    ctor public NanoApp();
-    ctor public deprecated NanoApp(int, byte[]);
-    ctor public NanoApp(long, byte[]);
-    method public int describeContents();
-    method public byte[] getAppBinary();
-    method public long getAppId();
-    method public int getAppVersion();
-    method public java.lang.String getName();
-    method public int getNeededExecMemBytes();
-    method public int getNeededReadMemBytes();
-    method public int[] getNeededSensors();
-    method public int getNeededWriteMemBytes();
-    method public int[] getOutputEvents();
-    method public java.lang.String getPublisher();
-    method public void setAppBinary(byte[]);
-    method public void setAppId(long);
-    method public void setAppVersion(int);
-    method public void setName(java.lang.String);
-    method public void setNeededExecMemBytes(int);
-    method public void setNeededReadMemBytes(int);
-    method public void setNeededSensors(int[]);
-    method public void setNeededWriteMemBytes(int);
-    method public void setOutputEvents(int[]);
-    method public void setPublisher(java.lang.String);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.hardware.location.NanoApp> CREATOR;
+  @Deprecated public class NanoApp implements android.os.Parcelable {
+    ctor @Deprecated public NanoApp();
+    ctor @Deprecated public NanoApp(int, byte[]);
+    ctor @Deprecated public NanoApp(long, byte[]);
+    method @Deprecated public int describeContents();
+    method @Deprecated public byte[] getAppBinary();
+    method @Deprecated public long getAppId();
+    method @Deprecated public int getAppVersion();
+    method @Deprecated public String getName();
+    method @Deprecated public int getNeededExecMemBytes();
+    method @Deprecated public int getNeededReadMemBytes();
+    method @Deprecated public int[] getNeededSensors();
+    method @Deprecated public int getNeededWriteMemBytes();
+    method @Deprecated public int[] getOutputEvents();
+    method @Deprecated public String getPublisher();
+    method @Deprecated public void setAppBinary(byte[]);
+    method @Deprecated public void setAppId(long);
+    method @Deprecated public void setAppVersion(int);
+    method @Deprecated public void setName(String);
+    method @Deprecated public void setNeededExecMemBytes(int);
+    method @Deprecated public void setNeededReadMemBytes(int);
+    method @Deprecated public void setNeededSensors(int[]);
+    method @Deprecated public void setNeededWriteMemBytes(int);
+    method @Deprecated public void setOutputEvents(int[]);
+    method @Deprecated public void setPublisher(String);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.hardware.location.NanoApp> CREATOR;
   }
 
   public final class NanoAppBinary implements android.os.Parcelable {
@@ -2076,37 +2393,37 @@
     field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppBinary> CREATOR;
   }
 
-  public deprecated class NanoAppFilter implements android.os.Parcelable {
-    ctor public NanoAppFilter(long, int, int, long);
-    method public int describeContents();
-    method public boolean testMatch(android.hardware.location.NanoAppInstanceInfo);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final int APP_ANY = -1; // 0xffffffff
-    field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppFilter> CREATOR;
-    field public static final int FLAGS_VERSION_ANY = -1; // 0xffffffff
-    field public static final int FLAGS_VERSION_GREAT_THAN = 2; // 0x2
-    field public static final int FLAGS_VERSION_LESS_THAN = 4; // 0x4
-    field public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8; // 0x8
-    field public static final int HUB_ANY = -1; // 0xffffffff
-    field public static final int VENDOR_ANY = -1; // 0xffffffff
+  @Deprecated public class NanoAppFilter implements android.os.Parcelable {
+    ctor @Deprecated public NanoAppFilter(long, int, int, long);
+    method @Deprecated public int describeContents();
+    method @Deprecated public boolean testMatch(android.hardware.location.NanoAppInstanceInfo);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final int APP_ANY = -1; // 0xffffffff
+    field @Deprecated public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppFilter> CREATOR;
+    field @Deprecated public static final int FLAGS_VERSION_ANY = -1; // 0xffffffff
+    field @Deprecated public static final int FLAGS_VERSION_GREAT_THAN = 2; // 0x2
+    field @Deprecated public static final int FLAGS_VERSION_LESS_THAN = 4; // 0x4
+    field @Deprecated public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8; // 0x8
+    field @Deprecated public static final int HUB_ANY = -1; // 0xffffffff
+    field @Deprecated public static final int VENDOR_ANY = -1; // 0xffffffff
   }
 
-  public deprecated class NanoAppInstanceInfo implements android.os.Parcelable {
-    ctor public NanoAppInstanceInfo();
-    method public int describeContents();
-    method public long getAppId();
-    method public int getAppVersion();
-    method public int getContexthubId();
-    method public int getHandle();
-    method public java.lang.String getName();
-    method public int getNeededExecMemBytes();
-    method public int getNeededReadMemBytes();
-    method public int[] getNeededSensors();
-    method public int getNeededWriteMemBytes();
-    method public int[] getOutputEvents();
-    method public java.lang.String getPublisher();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppInstanceInfo> CREATOR;
+  @Deprecated public class NanoAppInstanceInfo implements android.os.Parcelable {
+    ctor @Deprecated public NanoAppInstanceInfo();
+    method @Deprecated public int describeContents();
+    method @Deprecated public long getAppId();
+    method @Deprecated public int getAppVersion();
+    method @Deprecated public int getContexthubId();
+    method @Deprecated public int getHandle();
+    method @Deprecated public String getName();
+    method @Deprecated public int getNeededExecMemBytes();
+    method @Deprecated public int getNeededReadMemBytes();
+    method @Deprecated @NonNull public int[] getNeededSensors();
+    method @Deprecated public int getNeededWriteMemBytes();
+    method @Deprecated @NonNull public int[] getOutputEvents();
+    method @Deprecated public String getPublisher();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppInstanceInfo> CREATOR;
   }
 
   public final class NanoAppMessage implements android.os.Parcelable {
@@ -2137,9 +2454,9 @@
 
   public final class Announcement implements android.os.Parcelable {
     method public int describeContents();
-    method public android.hardware.radio.ProgramSelector getSelector();
+    method @NonNull public android.hardware.radio.ProgramSelector getSelector();
     method public int getType();
-    method public java.util.Map<java.lang.String, java.lang.String> getVendorInfo();
+    method @NonNull public java.util.Map<java.lang.String,java.lang.String> getVendorInfo();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.radio.Announcement> CREATOR;
     field public static final int TYPE_EMERGENCY = 1; // 0x1
@@ -2152,55 +2469,55 @@
     field public static final int TYPE_WEATHER = 4; // 0x4
   }
 
-  public static abstract interface Announcement.OnListUpdatedListener {
-    method public abstract void onListUpdated(java.util.Collection<android.hardware.radio.Announcement>);
+  public static interface Announcement.OnListUpdatedListener {
+    method public void onListUpdated(java.util.Collection<android.hardware.radio.Announcement>);
   }
 
   public final class ProgramList implements java.lang.AutoCloseable {
-    method public void addOnCompleteListener(java.util.concurrent.Executor, android.hardware.radio.ProgramList.OnCompleteListener);
-    method public void addOnCompleteListener(android.hardware.radio.ProgramList.OnCompleteListener);
+    method public void addOnCompleteListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.radio.ProgramList.OnCompleteListener);
+    method public void addOnCompleteListener(@NonNull android.hardware.radio.ProgramList.OnCompleteListener);
     method public void close();
-    method public android.hardware.radio.RadioManager.ProgramInfo get(android.hardware.radio.ProgramSelector.Identifier);
-    method public void registerListCallback(java.util.concurrent.Executor, android.hardware.radio.ProgramList.ListCallback);
-    method public void registerListCallback(android.hardware.radio.ProgramList.ListCallback);
-    method public void removeOnCompleteListener(android.hardware.radio.ProgramList.OnCompleteListener);
-    method public java.util.List<android.hardware.radio.RadioManager.ProgramInfo> toList();
-    method public void unregisterListCallback(android.hardware.radio.ProgramList.ListCallback);
+    method @Nullable public android.hardware.radio.RadioManager.ProgramInfo get(@NonNull android.hardware.radio.ProgramSelector.Identifier);
+    method public void registerListCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.radio.ProgramList.ListCallback);
+    method public void registerListCallback(@NonNull android.hardware.radio.ProgramList.ListCallback);
+    method public void removeOnCompleteListener(@NonNull android.hardware.radio.ProgramList.OnCompleteListener);
+    method @NonNull public java.util.List<android.hardware.radio.RadioManager.ProgramInfo> toList();
+    method public void unregisterListCallback(@NonNull android.hardware.radio.ProgramList.ListCallback);
   }
 
   public static final class ProgramList.Filter implements android.os.Parcelable {
-    ctor public ProgramList.Filter(java.util.Set<java.lang.Integer>, java.util.Set<android.hardware.radio.ProgramSelector.Identifier>, boolean, boolean);
+    ctor public ProgramList.Filter(@NonNull java.util.Set<java.lang.Integer>, @NonNull java.util.Set<android.hardware.radio.ProgramSelector.Identifier>, boolean, boolean);
     method public boolean areCategoriesIncluded();
     method public boolean areModificationsExcluded();
     method public int describeContents();
-    method public java.util.Set<java.lang.Integer> getIdentifierTypes();
-    method public java.util.Set<android.hardware.radio.ProgramSelector.Identifier> getIdentifiers();
+    method @NonNull public java.util.Set<java.lang.Integer> getIdentifierTypes();
+    method @NonNull public java.util.Set<android.hardware.radio.ProgramSelector.Identifier> getIdentifiers();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.radio.ProgramList.Filter> CREATOR;
   }
 
-  public static abstract class ProgramList.ListCallback {
+  public abstract static class ProgramList.ListCallback {
     ctor public ProgramList.ListCallback();
-    method public void onItemChanged(android.hardware.radio.ProgramSelector.Identifier);
-    method public void onItemRemoved(android.hardware.radio.ProgramSelector.Identifier);
+    method public void onItemChanged(@NonNull android.hardware.radio.ProgramSelector.Identifier);
+    method public void onItemRemoved(@NonNull android.hardware.radio.ProgramSelector.Identifier);
   }
 
-  public static abstract interface ProgramList.OnCompleteListener {
-    method public abstract void onComplete();
+  public static interface ProgramList.OnCompleteListener {
+    method public void onComplete();
   }
 
   public final class ProgramSelector implements android.os.Parcelable {
-    ctor public ProgramSelector(int, android.hardware.radio.ProgramSelector.Identifier, android.hardware.radio.ProgramSelector.Identifier[], long[]);
-    method public static android.hardware.radio.ProgramSelector createAmFmSelector(int, int);
-    method public static android.hardware.radio.ProgramSelector createAmFmSelector(int, int, int);
+    ctor public ProgramSelector(@android.hardware.radio.ProgramSelector.ProgramType int, @NonNull android.hardware.radio.ProgramSelector.Identifier, @Nullable android.hardware.radio.ProgramSelector.Identifier[], @Nullable long[]);
+    method @NonNull public static android.hardware.radio.ProgramSelector createAmFmSelector(@android.hardware.radio.RadioManager.Band int, int);
+    method @NonNull public static android.hardware.radio.ProgramSelector createAmFmSelector(@android.hardware.radio.RadioManager.Band int, int, int);
     method public int describeContents();
-    method public android.hardware.radio.ProgramSelector.Identifier[] getAllIds(int);
-    method public long getFirstId(int);
-    method public android.hardware.radio.ProgramSelector.Identifier getPrimaryId();
-    method public deprecated int getProgramType();
-    method public android.hardware.radio.ProgramSelector.Identifier[] getSecondaryIds();
-    method public deprecated long[] getVendorIds();
-    method public android.hardware.radio.ProgramSelector withSecondaryPreferred(android.hardware.radio.ProgramSelector.Identifier);
+    method @NonNull public android.hardware.radio.ProgramSelector.Identifier[] getAllIds(@android.hardware.radio.ProgramSelector.IdentifierType int);
+    method public long getFirstId(@android.hardware.radio.ProgramSelector.IdentifierType int);
+    method @NonNull public android.hardware.radio.ProgramSelector.Identifier getPrimaryId();
+    method @Deprecated @android.hardware.radio.ProgramSelector.ProgramType public int getProgramType();
+    method @NonNull public android.hardware.radio.ProgramSelector.Identifier[] getSecondaryIds();
+    method @Deprecated @NonNull public long[] getVendorIds();
+    method @NonNull public android.hardware.radio.ProgramSelector withSecondaryPreferred(@NonNull android.hardware.radio.ProgramSelector.Identifier);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.radio.ProgramSelector> CREATOR;
     field public static final int IDENTIFIER_TYPE_AMFM_FREQUENCY = 1; // 0x1
@@ -2210,52 +2527,52 @@
     field public static final int IDENTIFIER_TYPE_DAB_SIDECC = 5; // 0x5
     field public static final int IDENTIFIER_TYPE_DAB_SID_EXT = 5; // 0x5
     field public static final int IDENTIFIER_TYPE_DRMO_FREQUENCY = 10; // 0xa
-    field public static final deprecated int IDENTIFIER_TYPE_DRMO_MODULATION = 11; // 0xb
+    field @Deprecated public static final int IDENTIFIER_TYPE_DRMO_MODULATION = 11; // 0xb
     field public static final int IDENTIFIER_TYPE_DRMO_SERVICE_ID = 9; // 0x9
     field public static final int IDENTIFIER_TYPE_HD_STATION_ID_EXT = 3; // 0x3
     field public static final int IDENTIFIER_TYPE_HD_STATION_NAME = 10004; // 0x2714
-    field public static final deprecated int IDENTIFIER_TYPE_HD_SUBCHANNEL = 4; // 0x4
+    field @Deprecated public static final int IDENTIFIER_TYPE_HD_SUBCHANNEL = 4; // 0x4
     field public static final int IDENTIFIER_TYPE_INVALID = 0; // 0x0
     field public static final int IDENTIFIER_TYPE_RDS_PI = 2; // 0x2
     field public static final int IDENTIFIER_TYPE_SXM_CHANNEL = 13; // 0xd
     field public static final int IDENTIFIER_TYPE_SXM_SERVICE_ID = 12; // 0xc
     field public static final int IDENTIFIER_TYPE_VENDOR_END = 1999; // 0x7cf
-    field public static final deprecated int IDENTIFIER_TYPE_VENDOR_PRIMARY_END = 1999; // 0x7cf
-    field public static final deprecated int IDENTIFIER_TYPE_VENDOR_PRIMARY_START = 1000; // 0x3e8
+    field @Deprecated public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_END = 1999; // 0x7cf
+    field @Deprecated public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_START = 1000; // 0x3e8
     field public static final int IDENTIFIER_TYPE_VENDOR_START = 1000; // 0x3e8
-    field public static final deprecated int PROGRAM_TYPE_AM = 1; // 0x1
-    field public static final deprecated int PROGRAM_TYPE_AM_HD = 3; // 0x3
-    field public static final deprecated int PROGRAM_TYPE_DAB = 5; // 0x5
-    field public static final deprecated int PROGRAM_TYPE_DRMO = 6; // 0x6
-    field public static final deprecated int PROGRAM_TYPE_FM = 2; // 0x2
-    field public static final deprecated int PROGRAM_TYPE_FM_HD = 4; // 0x4
-    field public static final deprecated int PROGRAM_TYPE_INVALID = 0; // 0x0
-    field public static final deprecated int PROGRAM_TYPE_SXM = 7; // 0x7
-    field public static final deprecated int PROGRAM_TYPE_VENDOR_END = 1999; // 0x7cf
-    field public static final deprecated int PROGRAM_TYPE_VENDOR_START = 1000; // 0x3e8
+    field @Deprecated public static final int PROGRAM_TYPE_AM = 1; // 0x1
+    field @Deprecated public static final int PROGRAM_TYPE_AM_HD = 3; // 0x3
+    field @Deprecated public static final int PROGRAM_TYPE_DAB = 5; // 0x5
+    field @Deprecated public static final int PROGRAM_TYPE_DRMO = 6; // 0x6
+    field @Deprecated public static final int PROGRAM_TYPE_FM = 2; // 0x2
+    field @Deprecated public static final int PROGRAM_TYPE_FM_HD = 4; // 0x4
+    field @Deprecated public static final int PROGRAM_TYPE_INVALID = 0; // 0x0
+    field @Deprecated public static final int PROGRAM_TYPE_SXM = 7; // 0x7
+    field @Deprecated public static final int PROGRAM_TYPE_VENDOR_END = 1999; // 0x7cf
+    field @Deprecated public static final int PROGRAM_TYPE_VENDOR_START = 1000; // 0x3e8
   }
 
   public static final class ProgramSelector.Identifier implements android.os.Parcelable {
-    ctor public ProgramSelector.Identifier(int, long);
+    ctor public ProgramSelector.Identifier(@android.hardware.radio.ProgramSelector.IdentifierType int, long);
     method public int describeContents();
-    method public int getType();
+    method @android.hardware.radio.ProgramSelector.IdentifierType public int getType();
     method public long getValue();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.radio.ProgramSelector.Identifier> CREATOR;
   }
 
-  public static abstract class ProgramSelector.IdentifierType implements java.lang.annotation.Annotation {
+  @IntDef(prefix={"IDENTIFIER_TYPE_"}, value={android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_INVALID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_RDS_PI, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_HD_STATION_ID_EXT, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_HD_SUBCHANNEL, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_HD_STATION_NAME, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_SIDECC, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_SCID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DRMO_SERVICE_ID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DRMO_FREQUENCY, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DRMO_MODULATION, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_SXM_SERVICE_ID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL}) @IntRange(from=android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_VENDOR_START, to=android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_VENDOR_END) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ProgramSelector.IdentifierType {
   }
 
-  public static abstract deprecated class ProgramSelector.ProgramType implements java.lang.annotation.Annotation {
+  @Deprecated @IntDef(prefix={"PROGRAM_TYPE_"}, value={android.hardware.radio.ProgramSelector.PROGRAM_TYPE_INVALID, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_AM, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_FM, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_AM_HD, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_FM_HD, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_DAB, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_DRMO, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_SXM}) @IntRange(from=android.hardware.radio.ProgramSelector.PROGRAM_TYPE_VENDOR_START, to=android.hardware.radio.ProgramSelector.PROGRAM_TYPE_VENDOR_END) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ProgramSelector.ProgramType {
   }
 
   public class RadioManager {
-    method public void addAnnouncementListener(java.util.Set<java.lang.Integer>, android.hardware.radio.Announcement.OnListUpdatedListener);
-    method public void addAnnouncementListener(java.util.concurrent.Executor, java.util.Set<java.lang.Integer>, android.hardware.radio.Announcement.OnListUpdatedListener);
-    method public int listModules(java.util.List<android.hardware.radio.RadioManager.ModuleProperties>);
-    method public android.hardware.radio.RadioTuner openTuner(int, android.hardware.radio.RadioManager.BandConfig, boolean, android.hardware.radio.RadioTuner.Callback, android.os.Handler);
-    method public void removeAnnouncementListener(android.hardware.radio.Announcement.OnListUpdatedListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public void addAnnouncementListener(@NonNull java.util.Set<java.lang.Integer>, @NonNull android.hardware.radio.Announcement.OnListUpdatedListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public void addAnnouncementListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.Set<java.lang.Integer>, @NonNull android.hardware.radio.Announcement.OnListUpdatedListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public int listModules(java.util.List<android.hardware.radio.RadioManager.ModuleProperties>);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public android.hardware.radio.RadioTuner openTuner(int, android.hardware.radio.RadioManager.BandConfig, boolean, android.hardware.radio.RadioTuner.Callback, android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public void removeAnnouncementListener(@NonNull android.hardware.radio.Announcement.OnListUpdatedListener);
     field public static final int BAND_AM = 0; // 0x0
     field public static final int BAND_AM_HD = 3; // 0x3
     field public static final int BAND_FM = 1; // 0x1
@@ -2305,7 +2622,7 @@
     field public static final android.os.Parcelable.Creator<android.hardware.radio.RadioManager.AmBandDescriptor> CREATOR;
   }
 
-  public static abstract class RadioManager.Band implements java.lang.annotation.Annotation {
+  @IntDef(prefix={"BAND_"}, value={android.hardware.radio.RadioManager.BAND_INVALID, android.hardware.radio.RadioManager.BAND_AM, android.hardware.radio.RadioManager.BAND_FM, android.hardware.radio.RadioManager.BAND_AM_HD, android.hardware.radio.RadioManager.BAND_FM_HD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RadioManager.Band {
   }
 
   public static class RadioManager.BandConfig implements android.os.Parcelable {
@@ -2365,37 +2682,37 @@
     method public int describeContents();
     method public android.hardware.radio.RadioManager.BandDescriptor[] getBands();
     method public int getClassId();
-    method public java.util.Map<java.lang.String, java.lang.Integer> getDabFrequencyTable();
+    method @Nullable public java.util.Map<java.lang.String,java.lang.Integer> getDabFrequencyTable();
     method public int getId();
-    method public java.lang.String getImplementor();
+    method public String getImplementor();
     method public int getNumAudioSources();
     method public int getNumTuners();
-    method public java.lang.String getProduct();
-    method public java.lang.String getSerial();
-    method public java.lang.String getServiceName();
-    method public java.util.Map<java.lang.String, java.lang.String> getVendorInfo();
-    method public java.lang.String getVersion();
+    method public String getProduct();
+    method public String getSerial();
+    method @NonNull public String getServiceName();
+    method @NonNull public java.util.Map<java.lang.String,java.lang.String> getVendorInfo();
+    method public String getVersion();
     method public boolean isBackgroundScanningSupported();
     method public boolean isCaptureSupported();
     method public boolean isInitializationRequired();
-    method public boolean isProgramIdentifierSupported(int);
-    method public boolean isProgramTypeSupported(int);
+    method public boolean isProgramIdentifierSupported(@android.hardware.radio.ProgramSelector.IdentifierType int);
+    method public boolean isProgramTypeSupported(@android.hardware.radio.ProgramSelector.ProgramType int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.radio.RadioManager.ModuleProperties> CREATOR;
   }
 
   public static class RadioManager.ProgramInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public deprecated int getChannel();
-    method public android.hardware.radio.ProgramSelector.Identifier getLogicallyTunedTo();
+    method @Deprecated public int getChannel();
+    method @Nullable public android.hardware.radio.ProgramSelector.Identifier getLogicallyTunedTo();
     method public android.hardware.radio.RadioMetadata getMetadata();
-    method public android.hardware.radio.ProgramSelector.Identifier getPhysicallyTunedTo();
-    method public java.util.Collection<android.hardware.radio.ProgramSelector.Identifier> getRelatedContent();
-    method public android.hardware.radio.ProgramSelector getSelector();
+    method @Nullable public android.hardware.radio.ProgramSelector.Identifier getPhysicallyTunedTo();
+    method @Nullable public java.util.Collection<android.hardware.radio.ProgramSelector.Identifier> getRelatedContent();
+    method @NonNull public android.hardware.radio.ProgramSelector getSelector();
     method public int getSignalStrength();
-    method public deprecated int getSubChannel();
-    method public java.util.Map<java.lang.String, java.lang.String> getVendorInfo();
-    method public deprecated boolean isDigital();
+    method @Deprecated public int getSubChannel();
+    method @NonNull public java.util.Map<java.lang.String,java.lang.String> getVendorInfo();
+    method @Deprecated public boolean isDigital();
     method public boolean isLive();
     method public boolean isMuted();
     method public boolean isStereo();
@@ -2407,45 +2724,45 @@
   }
 
   public final class RadioMetadata implements android.os.Parcelable {
-    method public boolean containsKey(java.lang.String);
+    method public boolean containsKey(String);
     method public int describeContents();
-    method public deprecated android.graphics.Bitmap getBitmap(java.lang.String);
-    method public android.hardware.radio.RadioMetadata.Clock getClock(java.lang.String);
-    method public int getInt(java.lang.String);
-    method public java.lang.String getString(java.lang.String);
+    method @Deprecated public android.graphics.Bitmap getBitmap(String);
+    method public android.hardware.radio.RadioMetadata.Clock getClock(String);
+    method public int getInt(String);
+    method public String getString(String);
     method public java.util.Set<java.lang.String> keySet();
     method public int size();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.radio.RadioMetadata> CREATOR;
-    field public static final java.lang.String METADATA_KEY_ALBUM = "android.hardware.radio.metadata.ALBUM";
-    field public static final java.lang.String METADATA_KEY_ART = "android.hardware.radio.metadata.ART";
-    field public static final java.lang.String METADATA_KEY_ARTIST = "android.hardware.radio.metadata.ARTIST";
-    field public static final java.lang.String METADATA_KEY_CLOCK = "android.hardware.radio.metadata.CLOCK";
-    field public static final java.lang.String METADATA_KEY_DAB_COMPONENT_NAME = "android.hardware.radio.metadata.DAB_COMPONENT_NAME";
-    field public static final java.lang.String METADATA_KEY_DAB_COMPONENT_NAME_SHORT = "android.hardware.radio.metadata.DAB_COMPONENT_NAME_SHORT";
-    field public static final java.lang.String METADATA_KEY_DAB_ENSEMBLE_NAME = "android.hardware.radio.metadata.DAB_ENSEMBLE_NAME";
-    field public static final java.lang.String METADATA_KEY_DAB_ENSEMBLE_NAME_SHORT = "android.hardware.radio.metadata.DAB_ENSEMBLE_NAME_SHORT";
-    field public static final java.lang.String METADATA_KEY_DAB_SERVICE_NAME = "android.hardware.radio.metadata.DAB_SERVICE_NAME";
-    field public static final java.lang.String METADATA_KEY_DAB_SERVICE_NAME_SHORT = "android.hardware.radio.metadata.DAB_SERVICE_NAME_SHORT";
-    field public static final java.lang.String METADATA_KEY_GENRE = "android.hardware.radio.metadata.GENRE";
-    field public static final java.lang.String METADATA_KEY_ICON = "android.hardware.radio.metadata.ICON";
-    field public static final java.lang.String METADATA_KEY_PROGRAM_NAME = "android.hardware.radio.metadata.PROGRAM_NAME";
-    field public static final java.lang.String METADATA_KEY_RBDS_PTY = "android.hardware.radio.metadata.RBDS_PTY";
-    field public static final java.lang.String METADATA_KEY_RDS_PI = "android.hardware.radio.metadata.RDS_PI";
-    field public static final java.lang.String METADATA_KEY_RDS_PS = "android.hardware.radio.metadata.RDS_PS";
-    field public static final java.lang.String METADATA_KEY_RDS_PTY = "android.hardware.radio.metadata.RDS_PTY";
-    field public static final java.lang.String METADATA_KEY_RDS_RT = "android.hardware.radio.metadata.RDS_RT";
-    field public static final java.lang.String METADATA_KEY_TITLE = "android.hardware.radio.metadata.TITLE";
+    field public static final String METADATA_KEY_ALBUM = "android.hardware.radio.metadata.ALBUM";
+    field public static final String METADATA_KEY_ART = "android.hardware.radio.metadata.ART";
+    field public static final String METADATA_KEY_ARTIST = "android.hardware.radio.metadata.ARTIST";
+    field public static final String METADATA_KEY_CLOCK = "android.hardware.radio.metadata.CLOCK";
+    field public static final String METADATA_KEY_DAB_COMPONENT_NAME = "android.hardware.radio.metadata.DAB_COMPONENT_NAME";
+    field public static final String METADATA_KEY_DAB_COMPONENT_NAME_SHORT = "android.hardware.radio.metadata.DAB_COMPONENT_NAME_SHORT";
+    field public static final String METADATA_KEY_DAB_ENSEMBLE_NAME = "android.hardware.radio.metadata.DAB_ENSEMBLE_NAME";
+    field public static final String METADATA_KEY_DAB_ENSEMBLE_NAME_SHORT = "android.hardware.radio.metadata.DAB_ENSEMBLE_NAME_SHORT";
+    field public static final String METADATA_KEY_DAB_SERVICE_NAME = "android.hardware.radio.metadata.DAB_SERVICE_NAME";
+    field public static final String METADATA_KEY_DAB_SERVICE_NAME_SHORT = "android.hardware.radio.metadata.DAB_SERVICE_NAME_SHORT";
+    field public static final String METADATA_KEY_GENRE = "android.hardware.radio.metadata.GENRE";
+    field public static final String METADATA_KEY_ICON = "android.hardware.radio.metadata.ICON";
+    field public static final String METADATA_KEY_PROGRAM_NAME = "android.hardware.radio.metadata.PROGRAM_NAME";
+    field public static final String METADATA_KEY_RBDS_PTY = "android.hardware.radio.metadata.RBDS_PTY";
+    field public static final String METADATA_KEY_RDS_PI = "android.hardware.radio.metadata.RDS_PI";
+    field public static final String METADATA_KEY_RDS_PS = "android.hardware.radio.metadata.RDS_PS";
+    field public static final String METADATA_KEY_RDS_PTY = "android.hardware.radio.metadata.RDS_PTY";
+    field public static final String METADATA_KEY_RDS_RT = "android.hardware.radio.metadata.RDS_RT";
+    field public static final String METADATA_KEY_TITLE = "android.hardware.radio.metadata.TITLE";
   }
 
   public static final class RadioMetadata.Builder {
     ctor public RadioMetadata.Builder();
     ctor public RadioMetadata.Builder(android.hardware.radio.RadioMetadata);
     method public android.hardware.radio.RadioMetadata build();
-    method public android.hardware.radio.RadioMetadata.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
-    method public android.hardware.radio.RadioMetadata.Builder putClock(java.lang.String, long, int);
-    method public android.hardware.radio.RadioMetadata.Builder putInt(java.lang.String, int);
-    method public android.hardware.radio.RadioMetadata.Builder putString(java.lang.String, java.lang.String);
+    method public android.hardware.radio.RadioMetadata.Builder putBitmap(String, android.graphics.Bitmap);
+    method public android.hardware.radio.RadioMetadata.Builder putClock(String, long, int);
+    method public android.hardware.radio.RadioMetadata.Builder putInt(String, int);
+    method public android.hardware.radio.RadioMetadata.Builder putString(String, String);
   }
 
   public static final class RadioMetadata.Clock implements android.os.Parcelable {
@@ -2462,53 +2779,53 @@
     method public abstract int cancel();
     method public abstract void cancelAnnouncement();
     method public abstract void close();
-    method public abstract deprecated int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]);
-    method public android.hardware.radio.ProgramList getDynamicProgramList(android.hardware.radio.ProgramList.Filter);
+    method @Deprecated public abstract int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]);
+    method @Nullable public android.hardware.radio.ProgramList getDynamicProgramList(@Nullable android.hardware.radio.ProgramList.Filter);
     method public abstract boolean getMute();
-    method public java.util.Map<java.lang.String, java.lang.String> getParameters(java.util.List<java.lang.String>);
-    method public abstract deprecated int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]);
-    method public abstract deprecated java.util.List<android.hardware.radio.RadioManager.ProgramInfo> getProgramList(java.util.Map<java.lang.String, java.lang.String>);
+    method @NonNull public java.util.Map<java.lang.String,java.lang.String> getParameters(@NonNull java.util.List<java.lang.String>);
+    method @Deprecated public abstract int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]);
+    method @Deprecated @NonNull public abstract java.util.List<android.hardware.radio.RadioManager.ProgramInfo> getProgramList(@Nullable java.util.Map<java.lang.String,java.lang.String>);
     method public abstract boolean hasControl();
-    method public abstract deprecated boolean isAnalogForced();
-    method public abstract deprecated boolean isAntennaConnected();
+    method @Deprecated public abstract boolean isAnalogForced();
+    method @Deprecated public abstract boolean isAntennaConnected();
     method public boolean isConfigFlagSet(int);
     method public boolean isConfigFlagSupported(int);
     method public abstract int scan(int, boolean);
-    method public abstract deprecated void setAnalogForced(boolean);
+    method @Deprecated public abstract void setAnalogForced(boolean);
     method public void setConfigFlag(int, boolean);
-    method public abstract deprecated int setConfiguration(android.hardware.radio.RadioManager.BandConfig);
+    method @Deprecated public abstract int setConfiguration(android.hardware.radio.RadioManager.BandConfig);
     method public abstract int setMute(boolean);
-    method public java.util.Map<java.lang.String, java.lang.String> setParameters(java.util.Map<java.lang.String, java.lang.String>);
+    method @NonNull public java.util.Map<java.lang.String,java.lang.String> setParameters(@NonNull java.util.Map<java.lang.String,java.lang.String>);
     method public abstract boolean startBackgroundScan();
     method public abstract int step(int, boolean);
-    method public abstract deprecated int tune(int, int);
-    method public abstract void tune(android.hardware.radio.ProgramSelector);
+    method @Deprecated public abstract int tune(int, int);
+    method public abstract void tune(@NonNull android.hardware.radio.ProgramSelector);
     field public static final int DIRECTION_DOWN = 1; // 0x1
     field public static final int DIRECTION_UP = 0; // 0x0
-    field public static final deprecated int ERROR_BACKGROUND_SCAN_FAILED = 6; // 0x6
-    field public static final deprecated int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5; // 0x5
-    field public static final deprecated int ERROR_CANCELLED = 2; // 0x2
-    field public static final deprecated int ERROR_CONFIG = 4; // 0x4
-    field public static final deprecated int ERROR_HARDWARE_FAILURE = 0; // 0x0
-    field public static final deprecated int ERROR_SCAN_TIMEOUT = 3; // 0x3
-    field public static final deprecated int ERROR_SERVER_DIED = 1; // 0x1
+    field @Deprecated public static final int ERROR_BACKGROUND_SCAN_FAILED = 6; // 0x6
+    field @Deprecated public static final int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5; // 0x5
+    field @Deprecated public static final int ERROR_CANCELLED = 2; // 0x2
+    field @Deprecated public static final int ERROR_CONFIG = 4; // 0x4
+    field @Deprecated public static final int ERROR_HARDWARE_FAILURE = 0; // 0x0
+    field @Deprecated public static final int ERROR_SCAN_TIMEOUT = 3; // 0x3
+    field @Deprecated public static final int ERROR_SERVER_DIED = 1; // 0x1
   }
 
-  public static abstract class RadioTuner.Callback {
+  public abstract static class RadioTuner.Callback {
     ctor public RadioTuner.Callback();
     method public void onAntennaState(boolean);
     method public void onBackgroundScanAvailabilityChange(boolean);
     method public void onBackgroundScanComplete();
-    method public deprecated void onConfigurationChanged(android.hardware.radio.RadioManager.BandConfig);
+    method @Deprecated public void onConfigurationChanged(android.hardware.radio.RadioManager.BandConfig);
     method public void onControlChanged(boolean);
     method public void onEmergencyAnnouncement(boolean);
-    method public deprecated void onError(int);
-    method public deprecated void onMetadataChanged(android.hardware.radio.RadioMetadata);
-    method public void onParametersUpdated(java.util.Map<java.lang.String, java.lang.String>);
+    method @Deprecated public void onError(int);
+    method @Deprecated public void onMetadataChanged(android.hardware.radio.RadioMetadata);
+    method public void onParametersUpdated(@NonNull java.util.Map<java.lang.String,java.lang.String>);
     method public void onProgramInfoChanged(android.hardware.radio.RadioManager.ProgramInfo);
     method public void onProgramListChanged();
     method public void onTrafficAnnouncement(boolean);
-    method public void onTuneFailed(int, android.hardware.radio.ProgramSelector);
+    method public void onTuneFailed(int, @Nullable android.hardware.radio.ProgramSelector);
   }
 
 }
@@ -2520,7 +2837,7 @@
   }
 
   public static class SoundTrigger.RecognitionEvent {
-    method public android.media.AudioFormat getCaptureFormat();
+    method @Nullable public android.media.AudioFormat getCaptureFormat();
     method public int getCaptureSession();
     method public byte[] getData();
     method public boolean isCaptureAvailable();
@@ -2535,14 +2852,14 @@
   }
 
   public class UsbManager {
-    method public java.util.List<android.hardware.usb.UsbPort> getPorts();
-    method public void grantPermission(android.hardware.usb.UsbDevice, java.lang.String);
-    field public static final java.lang.String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED";
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USB) public java.util.List<android.hardware.usb.UsbPort> getPorts();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void grantPermission(android.hardware.usb.UsbDevice, String);
+    field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED";
   }
 
   public final class UsbPort {
-    method public android.hardware.usb.UsbPortStatus getStatus();
-    method public void setRoles(int, int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USB) @Nullable public android.hardware.usb.UsbPortStatus getStatus();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int);
   }
 
   public final class UsbPortStatus implements android.os.Parcelable {
@@ -2582,7 +2899,7 @@
     method public double getAltitudeMeters();
     method public double getLatitudeDegrees();
     method public double getLongitudeDegrees();
-    method public java.util.List<android.location.GnssSingleSatCorrection> getSingleSatCorrectionList();
+    method @Nullable public java.util.List<android.location.GnssSingleSatCorrection> getSingleSatCorrectionList();
     method public long getToaGpsNanosecondsOfWeek();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementCorrections> CREATOR;
@@ -2594,7 +2911,7 @@
     method public android.location.GnssMeasurementCorrections.Builder setAltitudeMeters(double);
     method public android.location.GnssMeasurementCorrections.Builder setLatitudeDegrees(double);
     method public android.location.GnssMeasurementCorrections.Builder setLongitudeDegrees(double);
-    method public android.location.GnssMeasurementCorrections.Builder setSingleSatCorrectionList(java.util.List<android.location.GnssSingleSatCorrection>);
+    method public android.location.GnssMeasurementCorrections.Builder setSingleSatCorrectionList(@Nullable java.util.List<android.location.GnssSingleSatCorrection>);
     method public android.location.GnssMeasurementCorrections.Builder setToaGpsNanosecondsOfWeek(long);
   }
 
@@ -2623,20 +2940,20 @@
     method public int getConstellationType();
     method public float getExcessPathLengthMeters();
     method public float getExcessPathLengthUncertaintyMeters();
-    method public android.location.GnssReflectingPlane getReflectingPlane();
+    method @FloatRange(from=0.0f, to=1.0f) public float getProbSatIsLos();
+    method @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
     method public int getSatId();
     method public int getSingleSatCorrectionFlags();
     method public boolean hasExcessPathLength();
     method public boolean hasExcessPathLengthUncertainty();
     method public boolean hasReflectingPlane();
     method public boolean hasSatelliteLineOfSight();
-    method public boolean isSatelliteLineOfSight();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
     field public static final int HAS_EXCESS_PATH_LENGTH_MASK = 2; // 0x2
     field public static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK = 4; // 0x4
+    field public static final int HAS_PROB_SAT_IS_LOS_MASK = 1; // 0x1
     field public static final int HAS_REFLECTING_PLANE_MASK = 8; // 0x8
-    field public static final int HAS_SAT_IS_LOS_MASK = 1; // 0x1
   }
 
   public static class GnssSingleSatCorrection.Builder {
@@ -2646,9 +2963,9 @@
     method public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
     method public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(float);
     method public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(float);
+    method public android.location.GnssSingleSatCorrection.Builder setProbSatIsLos(@FloatRange(from=0.0f, to=1.0f) float);
     method public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(android.location.GnssReflectingPlane);
     method public android.location.GnssSingleSatCorrection.Builder setSatId(int);
-    method public android.location.GnssSingleSatCorrection.Builder setSatIsLos(boolean);
     method public android.location.GnssSingleSatCorrection.Builder setSingleSatCorrectionFlags(int);
   }
 
@@ -2819,8 +3136,8 @@
   public class GpsMeasurementsEvent implements android.os.Parcelable {
     ctor public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
     method public int describeContents();
-    method public android.location.GpsClock getClock();
-    method public java.util.Collection<android.location.GpsMeasurement> getMeasurements();
+    method @NonNull public android.location.GpsClock getClock();
+    method @NonNull public java.util.Collection<android.location.GpsMeasurement> getMeasurements();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GpsMeasurementsEvent> CREATOR;
     field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
@@ -2828,14 +3145,14 @@
     field public static final int STATUS_READY = 1; // 0x1
   }
 
-  public static abstract interface GpsMeasurementsEvent.Listener {
-    method public abstract void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
-    method public abstract void onStatusChanged(int);
+  public static interface GpsMeasurementsEvent.Listener {
+    method public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
+    method public void onStatusChanged(int);
   }
 
   public class GpsNavigationMessage implements android.os.Parcelable {
     method public int describeContents();
-    method public byte[] getData();
+    method @NonNull public byte[] getData();
     method public short getMessageId();
     method public byte getPrn();
     method public short getStatus();
@@ -2864,7 +3181,7 @@
   public class GpsNavigationMessageEvent implements android.os.Parcelable {
     ctor public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
     method public int describeContents();
-    method public android.location.GpsNavigationMessage getNavigationMessage();
+    method @NonNull public android.location.GpsNavigationMessage getNavigationMessage();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
     field public static int STATUS_GPS_LOCATION_DISABLED;
@@ -2872,9 +3189,9 @@
     field public static int STATUS_READY;
   }
 
-  public static abstract interface GpsNavigationMessageEvent.Listener {
-    method public abstract void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
-    method public abstract void onStatusChanged(int);
+  public static interface GpsNavigationMessageEvent.Listener {
+    method public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
+    method public void onStatusChanged(int);
   }
 
   public class Location implements android.os.Parcelable {
@@ -2884,52 +3201,54 @@
   }
 
   public class LocationManager {
-    method public deprecated boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
-    method public deprecated boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
-    method public void flushGnssBatch();
-    method public int getGnssBatchSize();
+    method @Deprecated public boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
+    method @Deprecated public boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
     method public int getGnssCapabilities();
-    method public java.lang.String getLocationControllerExtraPackage();
-    method public java.lang.String getNetworkProviderPackage();
-    method public void injectGnssMeasurementCorrections(android.location.GnssMeasurementCorrections);
+    method @Nullable public String getLocationControllerExtraPackage();
+    method @Nullable public String getNetworkProviderPackage();
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
     method public boolean isLocationControllerExtraPackageEnabled();
     method public boolean isLocationEnabledForUser(android.os.UserHandle);
-    method public boolean isProviderEnabledForUser(java.lang.String, android.os.UserHandle);
-    method public boolean registerGnssBatchedLocationCallback(long, boolean, android.location.BatchedLocationCallback, android.os.Handler);
-    method public deprecated void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
-    method public deprecated void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
-    method public void requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper);
-    method public void requestLocationUpdates(android.location.LocationRequest, android.app.PendingIntent);
-    method public void setLocationControllerExtraPackage(java.lang.String);
-    method public void setLocationControllerExtraPackageEnabled(boolean);
-    method public void setLocationEnabledForUser(boolean, android.os.UserHandle);
-    method public boolean setProviderEnabledForUser(java.lang.String, boolean, android.os.UserHandle);
-    method public boolean unregisterGnssBatchedLocationCallback(android.location.BatchedLocationCallback);
+    method public boolean isProviderEnabledForUser(String, android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, android.location.BatchedLocationCallback, android.os.Handler);
+    method @Deprecated public void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
+    method @Deprecated public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(android.location.LocationRequest, android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackage(String);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackageEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, android.os.UserHandle);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(String, boolean, android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(android.location.BatchedLocationCallback);
   }
 
   public final class LocationRequest implements android.os.Parcelable {
     method public static android.location.LocationRequest create();
     method public static android.location.LocationRequest createFromDeprecatedCriteria(android.location.Criteria, long, float, boolean);
-    method public static android.location.LocationRequest createFromDeprecatedProvider(java.lang.String, long, float, boolean);
+    method public static android.location.LocationRequest createFromDeprecatedProvider(String, long, float, boolean);
     method public int describeContents();
     method public long getExpireAt();
     method public long getFastestInterval();
     method public boolean getHideFromAppOps();
     method public long getInterval();
     method public int getNumUpdates();
-    method public java.lang.String getProvider();
+    method public String getProvider();
     method public int getQuality();
     method public float getSmallestDisplacement();
     method public android.os.WorkSource getWorkSource();
+    method public boolean isLocationSettingsIgnored();
     method public boolean isLowPowerMode();
     method public android.location.LocationRequest setExpireAt(long);
     method public android.location.LocationRequest setExpireIn(long);
     method public android.location.LocationRequest setFastestInterval(long);
     method public void setHideFromAppOps(boolean);
     method public android.location.LocationRequest setInterval(long);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
     method public android.location.LocationRequest setLowPowerMode(boolean);
     method public android.location.LocationRequest setNumUpdates(int);
-    method public android.location.LocationRequest setProvider(java.lang.String);
+    method public android.location.LocationRequest setProvider(String);
     method public android.location.LocationRequest setQuality(int);
     method public android.location.LocationRequest setSmallestDisplacement(float);
     method public void setWorkSource(android.os.WorkSource);
@@ -2958,7 +3277,7 @@
   }
 
   public static class AudioAttributes.Builder {
-    method public android.media.AudioAttributes.Builder addBundle(android.os.Bundle);
+    method public android.media.AudioAttributes.Builder addBundle(@NonNull android.os.Bundle);
     method public android.media.AudioAttributes.Builder setCapturePreset(int);
     method public android.media.AudioAttributes.Builder setInternalCapturePreset(int);
   }
@@ -2966,12 +3285,12 @@
   public final class AudioFocusInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.media.AudioAttributes getAttributes();
-    method public java.lang.String getClientId();
+    method public String getClientId();
     method public int getClientUid();
     method public int getFlags();
     method public int getGainRequest();
     method public int getLossReceived();
-    method public java.lang.String getPackageName();
+    method public String getPackageName();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.media.AudioFocusInfo> CREATOR;
   }
@@ -2981,22 +3300,22 @@
   }
 
   public static final class AudioFocusRequest.Builder {
-    method public android.media.AudioFocusRequest.Builder setLocksFocus(boolean);
+    method @NonNull public android.media.AudioFocusRequest.Builder setLocksFocus(boolean);
   }
 
   public class AudioManager {
-    method public deprecated int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
+    method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
     method public void clearAudioServerStateCallback();
-    method public int dispatchAudioFocusChange(android.media.AudioFocusInfo, int, android.media.audiopolicy.AudioPolicy);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
     method public boolean isAudioServerRunning();
     method public boolean isHdmiSystemAudioSupported();
-    method public int registerAudioPolicy(android.media.audiopolicy.AudioPolicy);
-    method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
-    method public deprecated int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;
-    method public int requestAudioFocus(android.media.AudioFocusRequest, android.media.audiopolicy.AudioPolicy);
-    method public void setAudioServerStateCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioServerStateCallback);
-    method public void setFocusRequestResult(android.media.AudioFocusInfo, int, android.media.audiopolicy.AudioPolicy);
-    method public void unregisterAudioPolicyAsync(android.media.audiopolicy.AudioPolicy);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy);
+    method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy);
     field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
     field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
     field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
@@ -3004,7 +3323,7 @@
     field public static final int SUCCESS = 0; // 0x0
   }
 
-  public static abstract class AudioManager.AudioServerStateCallback {
+  public abstract static class AudioManager.AudioServerStateCallback {
     ctor public AudioManager.AudioServerStateCallback();
     method public void onAudioServerDown();
     method public void onAudioServerUp();
@@ -3036,20 +3355,21 @@
   }
 
   public static class AudioRecord.Builder {
-    method public android.media.AudioRecord.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioRecord.Builder setAudioAttributes(@NonNull android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
     method public android.media.AudioRecord.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
   }
 
   public final class MediaRecorder.AudioSource {
-    field public static final int HOTWORD = 1999; // 0x7cf
+    field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public static final int ECHO_REFERENCE = 1997; // 0x7cd
+    field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD) public static final int HOTWORD = 1999; // 0x7cf
     field public static final int RADIO_TUNER = 1998; // 0x7ce
   }
 
   public static class MediaTimestamp.Builder {
     ctor public MediaTimestamp.Builder();
-    ctor public MediaTimestamp.Builder(android.media.MediaTimestamp);
-    method public android.media.MediaTimestamp build();
-    method public android.media.MediaTimestamp.Builder setMediaTimestamp(long, long, float);
+    ctor public MediaTimestamp.Builder(@NonNull android.media.MediaTimestamp);
+    method @NonNull public android.media.MediaTimestamp build();
+    method @NonNull public android.media.MediaTimestamp.Builder setMediaTimestamp(long, long, float);
   }
 
   public class PlayerProxy {
@@ -3063,16 +3383,25 @@
 
   public static class SubtitleData.Builder {
     ctor public SubtitleData.Builder();
-    ctor public SubtitleData.Builder(android.media.SubtitleData);
-    method public android.media.SubtitleData build();
-    method public android.media.SubtitleData.Builder setSubtitleData(int, long, long, byte[]);
+    ctor public SubtitleData.Builder(@NonNull android.media.SubtitleData);
+    method @NonNull public android.media.SubtitleData build();
+    method @NonNull public android.media.SubtitleData.Builder setSubtitleData(int, long, long, @NonNull byte[]);
   }
 
   public static class TimedMetaData.Builder {
     ctor public TimedMetaData.Builder();
-    ctor public TimedMetaData.Builder(android.media.TimedMetaData);
-    method public android.media.TimedMetaData build();
-    method public android.media.TimedMetaData.Builder setTimedMetaData(long, byte[]);
+    ctor public TimedMetaData.Builder(@NonNull android.media.TimedMetaData);
+    method @NonNull public android.media.TimedMetaData build();
+    method @NonNull public android.media.TimedMetaData.Builder setTimedMetaData(long, @NonNull byte[]);
+  }
+
+  public abstract class VolumeProvider {
+    method public void setCallback(android.media.VolumeProvider.Callback);
+  }
+
+  public abstract static class VolumeProvider.Callback {
+    ctor public VolumeProvider.Callback();
+    method public abstract void onVolumeChanged(android.media.VolumeProvider);
   }
 
 }
@@ -3091,7 +3420,7 @@
   public static class AudioMix.Builder {
     ctor public AudioMix.Builder(android.media.audiopolicy.AudioMixingRule) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMix build() throws java.lang.IllegalArgumentException;
-    method public android.media.audiopolicy.AudioMix.Builder setDevice(android.media.AudioDeviceInfo) throws java.lang.IllegalArgumentException;
+    method public android.media.audiopolicy.AudioMix.Builder setDevice(@NonNull android.media.AudioDeviceInfo) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMix.Builder setFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMix.Builder setRouteFlags(int) throws java.lang.IllegalArgumentException;
   }
@@ -3104,25 +3433,25 @@
 
   public static class AudioMixingRule.Builder {
     ctor public AudioMixingRule.Builder();
-    method public android.media.audiopolicy.AudioMixingRule.Builder addMixRule(int, java.lang.Object) throws java.lang.IllegalArgumentException;
+    method public android.media.audiopolicy.AudioMixingRule.Builder addMixRule(int, Object) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMixingRule.Builder addRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMixingRule build();
-    method public android.media.audiopolicy.AudioMixingRule.Builder excludeMixRule(int, java.lang.Object) throws java.lang.IllegalArgumentException;
+    method public android.media.audiopolicy.AudioMixingRule.Builder excludeMixRule(int, Object) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMixingRule.Builder excludeRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
   }
 
   public class AudioPolicy {
-    method public int attachMixes(java.util.List<android.media.audiopolicy.AudioMix>);
+    method public int attachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>);
     method public android.media.AudioRecord createAudioRecordSink(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
     method public android.media.AudioTrack createAudioTrackSource(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
-    method public int detachMixes(java.util.List<android.media.audiopolicy.AudioMix>);
+    method public int detachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>);
     method public int getFocusDuckingBehavior();
     method public int getStatus();
     method public int removeUidDeviceAffinity(int);
     method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
-    method public void setRegistration(java.lang.String);
-    method public int setUidDeviceAffinity(int, java.util.List<android.media.AudioDeviceInfo>);
-    method public java.lang.String toLogFriendlyString();
+    method public void setRegistration(String);
+    method public int setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
+    method public String toLogFriendlyString();
     field public static final int FOCUS_POLICY_DUCKING_DEFAULT = 0; // 0x0
     field public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; // 0x0
     field public static final int FOCUS_POLICY_DUCKING_IN_POLICY = 1; // 0x1
@@ -3130,7 +3459,7 @@
     field public static final int POLICY_STATUS_UNREGISTERED = 1; // 0x1
   }
 
-  public static abstract class AudioPolicy.AudioPolicyFocusListener {
+  public abstract static class AudioPolicy.AudioPolicyFocusListener {
     ctor public AudioPolicy.AudioPolicyFocusListener();
     method public void onAudioFocusAbandon(android.media.AudioFocusInfo);
     method public void onAudioFocusGrant(android.media.AudioFocusInfo, int);
@@ -3138,25 +3467,25 @@
     method public void onAudioFocusRequest(android.media.AudioFocusInfo, int);
   }
 
-  public static abstract class AudioPolicy.AudioPolicyStatusListener {
+  public abstract static class AudioPolicy.AudioPolicyStatusListener {
     ctor public AudioPolicy.AudioPolicyStatusListener();
     method public void onMixStateUpdate(android.media.audiopolicy.AudioMix);
     method public void onStatusChange();
   }
 
-  public static abstract class AudioPolicy.AudioPolicyVolumeCallback {
+  public abstract static class AudioPolicy.AudioPolicyVolumeCallback {
     method public void onVolumeAdjustment(int);
   }
 
   public static class AudioPolicy.Builder {
     ctor public AudioPolicy.Builder(android.content.Context);
-    method public android.media.audiopolicy.AudioPolicy.Builder addMix(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
+    method public android.media.audiopolicy.AudioPolicy.Builder addMix(@NonNull android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioPolicy build();
     method public void setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener);
     method public void setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener);
-    method public android.media.audiopolicy.AudioPolicy.Builder setAudioPolicyVolumeCallback(android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback);
+    method public android.media.audiopolicy.AudioPolicy.Builder setAudioPolicyVolumeCallback(@NonNull android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback);
     method public android.media.audiopolicy.AudioPolicy.Builder setIsAudioFocusPolicy(boolean);
-    method public android.media.audiopolicy.AudioPolicy.Builder setLooper(android.os.Looper) throws java.lang.IllegalArgumentException;
+    method public android.media.audiopolicy.AudioPolicy.Builder setLooper(@NonNull android.os.Looper) throws java.lang.IllegalArgumentException;
   }
 
 }
@@ -3164,102 +3493,233 @@
 package android.media.session {
 
   public final class ControllerCallbackLink implements android.os.Parcelable {
-    ctor public ControllerCallbackLink(android.media.session.ControllerCallbackLink.CallbackStub);
+    ctor public ControllerCallbackLink(@NonNull android.content.Context, @NonNull android.media.session.ControllerCallbackLink.CallbackStub);
+    ctor public ControllerCallbackLink(android.os.IBinder);
     method public int describeContents();
-    method public android.os.IBinder getBinder();
-    method public void notifyEvent(java.lang.String, android.os.Bundle);
-    method public void notifyExtrasChanged(android.os.Bundle);
-    method public void notifyMetadataChanged(android.media.MediaMetadata);
-    method public void notifyPlaybackStateChanged(android.media.session.PlaybackState);
-    method public void notifyQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>);
-    method public void notifyQueueTitleChanged(java.lang.CharSequence);
-    method public void notifySessionDestroyed();
-    method public void notifyVolumeInfoChanged(int, android.media.AudioAttributes, int, int, int);
+    method @NonNull public android.os.IBinder getBinder();
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyEvent(@NonNull String, @Nullable android.os.Bundle);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyExtrasChanged(@Nullable android.os.Bundle);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyMetadataChanged(@Nullable android.media.MediaMetadata);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlaybackStateChanged(@Nullable android.media.session.PlaybackState);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyQueueChanged(@Nullable java.util.List<android.media.session.MediaSession.QueueItem>);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyQueueTitleChanged(@Nullable CharSequence);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySessionDestroyed();
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyVolumeInfoChanged(@NonNull android.media.session.MediaController.PlaybackInfo);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.media.session.ControllerCallbackLink> CREATOR;
   }
 
-  public static abstract class ControllerCallbackLink.CallbackStub {
+  public abstract static class ControllerCallbackLink.CallbackStub {
     ctor public ControllerCallbackLink.CallbackStub();
-    method public void onEvent(java.lang.String, android.os.Bundle);
-    method public void onExtrasChanged(android.os.Bundle);
-    method public void onMetadataChanged(android.media.MediaMetadata);
-    method public void onPlaybackStateChanged(android.media.session.PlaybackState);
-    method public void onQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>);
-    method public void onQueueTitleChanged(java.lang.CharSequence);
+    method public void onEvent(@NonNull String, @Nullable android.os.Bundle);
+    method public void onExtrasChanged(@Nullable android.os.Bundle);
+    method public void onMetadataChanged(@Nullable android.media.MediaMetadata);
+    method public void onPlaybackStateChanged(@Nullable android.media.session.PlaybackState);
+    method public void onQueueChanged(@Nullable java.util.List<android.media.session.MediaSession.QueueItem>);
+    method public void onQueueTitleChanged(@Nullable CharSequence);
     method public void onSessionDestroyed();
-    method public void onVolumeInfoChanged(int, android.media.AudioAttributes, int, int, int);
+    method public void onVolumeInfoChanged(@NonNull android.media.session.MediaController.PlaybackInfo);
+  }
+
+  public final class ControllerLink implements android.os.Parcelable {
+    ctor public ControllerLink(@NonNull android.media.session.ControllerLink.ControllerStub);
+    ctor public ControllerLink(android.os.IBinder);
+    method public int describeContents();
+    method @NonNull public android.os.IBinder getBinder();
+    method @Nullable public android.os.Bundle getExtras();
+    method @Nullable public android.media.MediaMetadata getMetadata();
+    method @Nullable public android.media.session.PlaybackState getPlaybackState();
+    method @Nullable public java.util.List<android.media.session.MediaSession.QueueItem> getQueue();
+    method @Nullable public CharSequence getQueueTitle();
+    method public int getRatingType();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.session.ControllerLink> CREATOR;
+  }
+
+  public abstract static class ControllerLink.ControllerStub {
+    ctor public ControllerLink.ControllerStub();
+    method public void adjustVolume(@NonNull String, @NonNull String, @NonNull android.media.session.ControllerCallbackLink, boolean, int, int);
+    method public void fastForward(@NonNull String, @NonNull android.media.session.ControllerCallbackLink);
+    method @Nullable public android.os.Bundle getExtras();
+    method public long getFlags();
+    method @Nullable public android.app.PendingIntent getLaunchPendingIntent();
+    method @Nullable public android.media.MediaMetadata getMetadata();
+    method @NonNull public String getPackageName();
+    method @Nullable public android.media.session.PlaybackState getPlaybackState();
+    method @Nullable public java.util.List<android.media.session.MediaSession.QueueItem> getQueue();
+    method @Nullable public CharSequence getQueueTitle();
+    method public int getRatingType();
+    method @NonNull public String getTag();
+    method @NonNull public android.media.session.MediaController.PlaybackInfo getVolumeAttributes();
+    method public void next(@NonNull String, @NonNull android.media.session.ControllerCallbackLink);
+    method public void pause(@NonNull String, @NonNull android.media.session.ControllerCallbackLink);
+    method public void play(@NonNull String, @NonNull android.media.session.ControllerCallbackLink);
+    method public void playFromMediaId(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle);
+    method public void playFromSearch(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle);
+    method public void playFromUri(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle);
+    method public void prepare(@NonNull String, @NonNull android.media.session.ControllerCallbackLink);
+    method public void prepareFromMediaId(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle);
+    method public void prepareFromSearch(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle);
+    method public void prepareFromUri(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle);
+    method public void previous(@NonNull String, @NonNull android.media.session.ControllerCallbackLink);
+    method public void rate(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.media.Rating);
+    method public void registerCallback(@NonNull String, @NonNull android.media.session.ControllerCallbackLink);
+    method public void rewind(@NonNull String, @NonNull android.media.session.ControllerCallbackLink);
+    method public void seekTo(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, long);
+    method public void sendCommand(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.ResultReceiver);
+    method public void sendCustomAction(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle);
+    method public boolean sendMediaButton(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, boolean, @NonNull android.view.KeyEvent);
+    method public void setVolumeTo(@NonNull String, @NonNull String, @NonNull android.media.session.ControllerCallbackLink, int, int);
+    method public void skipToQueueItem(@NonNull String, @NonNull android.media.session.ControllerCallbackLink, long);
+    method public void stop(@NonNull String, @NonNull android.media.session.ControllerCallbackLink);
+    method public void unregisterCallback(@NonNull android.media.session.ControllerCallbackLink);
+  }
+
+  public abstract static class MediaSession.Callback {
+    method public void onSetMediaButtonEventDelegate(@NonNull android.media.session.MediaSessionEngine.MediaButtonEventDelegate);
+  }
+
+  public static final class MediaSession.Token implements android.os.Parcelable {
+    method public android.media.session.ControllerLink getControllerLink();
+  }
+
+  public final class MediaSessionEngine implements java.lang.AutoCloseable {
+    ctor public MediaSessionEngine(@NonNull android.content.Context, @NonNull android.media.session.SessionLink, @NonNull android.media.session.SessionCallbackLink, @NonNull android.media.session.MediaSessionEngine.CallbackStub, int);
+    method public void close();
+    method public String getCallingPackage();
+    method @NonNull public android.media.session.MediaController getController();
+    method @NonNull public android.media.session.MediaSessionManager.RemoteUserInfo getCurrentControllerInfo();
+    method @NonNull public android.media.session.MediaSession.Token getSessionToken();
+    method public boolean isActive();
+    method public static boolean isActiveState(int);
+    method public void sendSessionEvent(@NonNull String, @Nullable android.os.Bundle);
+    method public void setActive(boolean);
+    method public void setCallback(@Nullable android.media.session.MediaSession.Callback);
+    method public void setCallback(@Nullable android.media.session.MediaSession.Callback, @NonNull android.os.Handler);
+    method public void setExtras(@Nullable android.os.Bundle);
+    method public void setFlags(int);
+    method public void setMediaButtonReceiver(@Nullable android.app.PendingIntent);
+    method public void setMetadata(@Nullable android.media.MediaMetadata);
+    method public void setPlaybackState(@Nullable android.media.session.PlaybackState);
+    method public void setPlaybackToLocal(android.media.AudioAttributes);
+    method public void setPlaybackToRemote(@NonNull android.media.VolumeProvider);
+    method public void setQueue(@Nullable java.util.List<android.media.session.MediaSession.QueueItem>);
+    method public void setQueueTitle(@Nullable CharSequence);
+    method public void setRatingType(int);
+    method public void setSessionActivity(@Nullable android.app.PendingIntent);
+  }
+
+  public static final class MediaSessionEngine.CallbackStub {
+    ctor public MediaSessionEngine.CallbackStub();
+    method public void onAdjustVolume(String, int, int, android.media.session.ControllerCallbackLink, int);
+    method public void onCommand(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle, android.os.ResultReceiver);
+    method public void onCustomAction(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle);
+    method public void onFastForward(String, int, int, android.media.session.ControllerCallbackLink);
+    method public void onMediaButton(String, int, int, android.content.Intent, int, android.os.ResultReceiver);
+    method public void onMediaButtonFromController(String, int, int, android.media.session.ControllerCallbackLink, android.content.Intent);
+    method public void onNext(String, int, int, android.media.session.ControllerCallbackLink);
+    method public void onPause(String, int, int, android.media.session.ControllerCallbackLink);
+    method public void onPlay(String, int, int, android.media.session.ControllerCallbackLink);
+    method public void onPlayFromMediaId(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle);
+    method public void onPlayFromSearch(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle);
+    method public void onPlayFromUri(String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle);
+    method public void onPrepare(String, int, int, android.media.session.ControllerCallbackLink);
+    method public void onPrepareFromMediaId(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle);
+    method public void onPrepareFromSearch(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle);
+    method public void onPrepareFromUri(String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle);
+    method public void onPrevious(String, int, int, android.media.session.ControllerCallbackLink);
+    method public void onRate(String, int, int, android.media.session.ControllerCallbackLink, android.media.Rating);
+    method public void onRewind(String, int, int, android.media.session.ControllerCallbackLink);
+    method public void onSeekTo(String, int, int, android.media.session.ControllerCallbackLink, long);
+    method public void onSetVolumeTo(String, int, int, android.media.session.ControllerCallbackLink, int);
+    method public void onSkipToTrack(String, int, int, android.media.session.ControllerCallbackLink, long);
+    method public void onStop(String, int, int, android.media.session.ControllerCallbackLink);
+  }
+
+  public static interface MediaSessionEngine.MediaButtonEventDelegate {
+    method public boolean onMediaButtonIntent(android.content.Intent);
+  }
+
+  public static final class MediaSessionEngine.QueueItem {
+    ctor public MediaSessionEngine.QueueItem(android.media.MediaDescription, long);
+    ctor public MediaSessionEngine.QueueItem(android.os.Parcel);
+    method public android.media.MediaDescription getDescription();
+    method public long getQueueId();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int UNKNOWN_ID = -1; // 0xffffffff
   }
 
   public final class MediaSessionManager {
-    method public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, android.os.Handler);
-    method public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler);
   }
 
-  public static abstract interface MediaSessionManager.OnMediaKeyListener {
-    method public abstract boolean onMediaKey(android.view.KeyEvent);
+  public static interface MediaSessionManager.OnMediaKeyListener {
+    method public boolean onMediaKey(android.view.KeyEvent);
   }
 
-  public static abstract interface MediaSessionManager.OnVolumeKeyLongPressListener {
-    method public abstract void onVolumeKeyLongPress(android.view.KeyEvent);
+  public static interface MediaSessionManager.OnVolumeKeyLongPressListener {
+    method public void onVolumeKeyLongPress(android.view.KeyEvent);
   }
 
   public final class SessionCallbackLink implements android.os.Parcelable {
-    ctor public SessionCallbackLink(android.media.session.SessionCallbackLink.CallbackStub);
+    ctor public SessionCallbackLink(android.os.IBinder);
     method public int describeContents();
-    method public android.os.IBinder getBinder();
-    method public void notifyAdjustVolume(java.lang.String, int, int, android.media.session.ControllerCallbackLink, int);
-    method public void notifyCommand(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
-    method public void notifyCustomAction(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
-    method public void notifyFastForward(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void notifyMediaButton(java.lang.String, int, int, android.content.Intent, int, android.os.ResultReceiver);
-    method public void notifyMediaButtonFromController(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.content.Intent);
-    method public void notifyNext(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void notifyPause(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void notifyPlay(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void notifyPlayFromMediaId(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
-    method public void notifyPlayFromSearch(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
-    method public void notifyPlayFromUri(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle);
-    method public void notifyPrepare(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void notifyPrepareFromMediaId(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
-    method public void notifyPrepareFromSearch(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
-    method public void notifyPrepareFromUri(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle);
-    method public void notifyPrevious(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void notifyRate(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.media.Rating);
-    method public void notifyRewind(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void notifySeekTo(java.lang.String, int, int, android.media.session.ControllerCallbackLink, long);
-    method public void notifySetVolumeTo(java.lang.String, int, int, android.media.session.ControllerCallbackLink, int);
-    method public void notifySkipToTrack(java.lang.String, int, int, android.media.session.ControllerCallbackLink, long);
-    method public void notifyStop(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+    method @NonNull public android.os.IBinder getBinder();
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyAdjustVolume(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, int);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyCommand(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.ResultReceiver);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyCustomAction(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyFastForward(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyMediaButton(@NonNull String, int, int, @NonNull android.content.Intent, int, @Nullable android.os.ResultReceiver);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyMediaButtonFromController(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.content.Intent);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyNext(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPause(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlay(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlayFromMediaId(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlayFromSearch(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPlayFromUri(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepare(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepareFromMediaId(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepareFromSearch(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull String, @Nullable android.os.Bundle);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrepareFromUri(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.net.Uri, @Nullable android.os.Bundle);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyPrevious(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyRate(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, @NonNull android.media.Rating);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyRewind(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySeekTo(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, long);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySetVolumeTo(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, int);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifySkipToTrack(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink, long);
+    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void notifyStop(@NonNull String, int, int, @NonNull android.media.session.ControllerCallbackLink);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.media.session.SessionCallbackLink> CREATOR;
   }
 
-  public static abstract class SessionCallbackLink.CallbackStub {
-    ctor public SessionCallbackLink.CallbackStub();
-    method public void onAdjustVolume(java.lang.String, int, int, android.media.session.ControllerCallbackLink, int);
-    method public void onCommand(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
-    method public void onCustomAction(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
-    method public void onFastForward(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onMediaButton(java.lang.String, int, int, android.content.Intent, int, android.os.ResultReceiver);
-    method public void onMediaButtonFromController(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.content.Intent);
-    method public void onNext(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onPause(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onPlay(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onPlayFromMediaId(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
-    method public void onPlayFromSearch(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
-    method public void onPlayFromUri(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle);
-    method public void onPrepare(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onPrepareFromMediaId(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
-    method public void onPrepareFromSearch(java.lang.String, int, int, android.media.session.ControllerCallbackLink, java.lang.String, android.os.Bundle);
-    method public void onPrepareFromUri(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle);
-    method public void onPrevious(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onRate(java.lang.String, int, int, android.media.session.ControllerCallbackLink, android.media.Rating);
-    method public void onRewind(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
-    method public void onSeekTo(java.lang.String, int, int, android.media.session.ControllerCallbackLink, long);
-    method public void onSetVolumeTo(java.lang.String, int, int, android.media.session.ControllerCallbackLink, int);
-    method public void onSkipToTrack(java.lang.String, int, int, android.media.session.ControllerCallbackLink, long);
-    method public void onStop(java.lang.String, int, int, android.media.session.ControllerCallbackLink);
+  public final class SessionLink implements android.os.Parcelable {
+    ctor public SessionLink(@NonNull android.media.session.SessionLink.SessionStub);
+    ctor public SessionLink(android.os.IBinder);
+    method public int describeContents();
+    method @NonNull public android.os.IBinder getBinder();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.media.session.SessionLink> CREATOR;
+  }
+
+  public abstract static class SessionLink.SessionStub {
+    ctor public SessionLink.SessionStub();
+    method public void destroySession();
+    method @NonNull public android.media.session.ControllerLink getController();
+    method public void sendEvent(@NonNull String, @Nullable android.os.Bundle);
+    method public void setActive(boolean);
+    method public void setCurrentVolume(int);
+    method public void setExtras(@Nullable android.os.Bundle);
+    method public void setFlags(int);
+    method public void setLaunchPendingIntent(@Nullable android.app.PendingIntent);
+    method public void setMediaButtonReceiver(@Nullable android.app.PendingIntent);
+    method public void setMetadata(@Nullable android.media.MediaMetadata, long, @Nullable String);
+    method public void setPlaybackState(@Nullable android.media.session.PlaybackState);
+    method public void setPlaybackToLocal(@NonNull android.media.AudioAttributes);
+    method public void setPlaybackToRemote(int, int);
+    method public void setQueue(@Nullable java.util.List<android.media.session.MediaSession.QueueItem>);
+    method public void setQueueTitle(@Nullable CharSequence);
+    method public void setRatingType(int);
   }
 
 }
@@ -3268,41 +3728,41 @@
 
   public abstract class SoundTriggerDetectionService extends android.app.Service {
     ctor public SoundTriggerDetectionService();
-    method public void onConnected(java.util.UUID, android.os.Bundle);
-    method public void onDisconnected(java.util.UUID, android.os.Bundle);
-    method public void onError(java.util.UUID, android.os.Bundle, int, int);
-    method public void onGenericRecognitionEvent(java.util.UUID, android.os.Bundle, int, android.hardware.soundtrigger.SoundTrigger.RecognitionEvent);
-    method public abstract void onStopOperation(java.util.UUID, android.os.Bundle, int);
-    method public final void operationFinished(java.util.UUID, int);
+    method @MainThread public void onConnected(@NonNull java.util.UUID, @Nullable android.os.Bundle);
+    method @MainThread public void onDisconnected(@NonNull java.util.UUID, @Nullable android.os.Bundle);
+    method @MainThread public void onError(@NonNull java.util.UUID, @Nullable android.os.Bundle, int, int);
+    method @MainThread public void onGenericRecognitionEvent(@NonNull java.util.UUID, @Nullable android.os.Bundle, int, @NonNull android.hardware.soundtrigger.SoundTrigger.RecognitionEvent);
+    method @MainThread public abstract void onStopOperation(@NonNull java.util.UUID, @Nullable android.os.Bundle, int);
+    method public final void operationFinished(@Nullable java.util.UUID, int);
   }
 
   public final class SoundTriggerDetector {
-    method public boolean startRecognition(int);
-    method public boolean stopRecognition();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public boolean startRecognition(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public boolean stopRecognition();
     field public static final int RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS = 2; // 0x2
     field public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 1; // 0x1
   }
 
-  public static abstract class SoundTriggerDetector.Callback {
+  public abstract static class SoundTriggerDetector.Callback {
     ctor public SoundTriggerDetector.Callback();
     method public abstract void onAvailabilityChanged(int);
-    method public abstract void onDetected(android.media.soundtrigger.SoundTriggerDetector.EventPayload);
+    method public abstract void onDetected(@NonNull android.media.soundtrigger.SoundTriggerDetector.EventPayload);
     method public abstract void onError();
     method public abstract void onRecognitionPaused();
     method public abstract void onRecognitionResumed();
   }
 
   public static class SoundTriggerDetector.EventPayload {
-    method public android.media.AudioFormat getCaptureAudioFormat();
-    method public byte[] getTriggerAudio();
+    method @Nullable public android.media.AudioFormat getCaptureAudioFormat();
+    method @Nullable public byte[] getTriggerAudio();
   }
 
   public final class SoundTriggerManager {
-    method public android.media.soundtrigger.SoundTriggerDetector createSoundTriggerDetector(java.util.UUID, android.media.soundtrigger.SoundTriggerDetector.Callback, android.os.Handler);
-    method public void deleteModel(java.util.UUID);
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerDetector createSoundTriggerDetector(java.util.UUID, @NonNull android.media.soundtrigger.SoundTriggerDetector.Callback, @Nullable android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void deleteModel(java.util.UUID);
     method public int getDetectionServiceOperationsTimeout();
-    method public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
-    method public void updateModel(android.media.soundtrigger.SoundTriggerManager.Model);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void updateModel(android.media.soundtrigger.SoundTriggerManager.Model);
   }
 
   public static class SoundTriggerManager.Model {
@@ -3325,44 +3785,44 @@
   }
 
   public final class TvContract {
-    method public static android.net.Uri buildChannelsUriForInput(java.lang.String, boolean);
-    method public static android.net.Uri buildChannelsUriForInput(java.lang.String, java.lang.String, boolean);
-    field public static final java.lang.String ACTION_CHANNEL_BROWSABLE_REQUESTED = "android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED";
-    field public static final java.lang.String EXTRA_BLOCKED_PACKAGES = "android.media.tv.extra.BLOCKED_PACKAGES";
-    field public static final java.lang.String EXTRA_COLUMN_NAME = "android.media.tv.extra.COLUMN_NAME";
-    field public static final java.lang.String EXTRA_DATA_TYPE = "android.media.tv.extra.DATA_TYPE";
-    field public static final java.lang.String EXTRA_DEFAULT_VALUE = "android.media.tv.extra.DEFAULT_VALUE";
-    field public static final java.lang.String EXTRA_EXISTING_COLUMN_NAMES = "android.media.tv.extra.EXISTING_COLUMN_NAMES";
-    field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
-    field public static final java.lang.String EXTRA_RESULT_CODE = "android.media.tv.extra.RESULT_CODE";
-    field public static final java.lang.String METHOD_ADD_COLUMN = "add_column";
-    field public static final java.lang.String METHOD_BLOCK_PACKAGE = "block_package";
-    field public static final java.lang.String METHOD_GET_BLOCKED_PACKAGES = "get_blocked_packages";
-    field public static final java.lang.String METHOD_GET_COLUMNS = "get_columns";
-    field public static final java.lang.String METHOD_UNBLOCK_PACKAGE = "unblock_package";
+    method public static android.net.Uri buildChannelsUriForInput(@Nullable String, boolean);
+    method public static android.net.Uri buildChannelsUriForInput(@Nullable String, @Nullable String, boolean);
+    field public static final String ACTION_CHANNEL_BROWSABLE_REQUESTED = "android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED";
+    field public static final String EXTRA_BLOCKED_PACKAGES = "android.media.tv.extra.BLOCKED_PACKAGES";
+    field public static final String EXTRA_COLUMN_NAME = "android.media.tv.extra.COLUMN_NAME";
+    field public static final String EXTRA_DATA_TYPE = "android.media.tv.extra.DATA_TYPE";
+    field public static final String EXTRA_DEFAULT_VALUE = "android.media.tv.extra.DEFAULT_VALUE";
+    field public static final String EXTRA_EXISTING_COLUMN_NAMES = "android.media.tv.extra.EXISTING_COLUMN_NAMES";
+    field public static final String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+    field public static final String EXTRA_RESULT_CODE = "android.media.tv.extra.RESULT_CODE";
+    field public static final String METHOD_ADD_COLUMN = "add_column";
+    field public static final String METHOD_BLOCK_PACKAGE = "block_package";
+    field public static final String METHOD_GET_BLOCKED_PACKAGES = "get_blocked_packages";
+    field public static final String METHOD_GET_COLUMNS = "get_columns";
+    field public static final String METHOD_UNBLOCK_PACKAGE = "unblock_package";
     field public static final int RESULT_ERROR_INVALID_ARGUMENT = 2; // 0x2
     field public static final int RESULT_ERROR_IO = 1; // 0x1
     field public static final int RESULT_OK = 0; // 0x0
   }
 
   public static final class TvContract.WatchedPrograms implements android.media.tv.TvContract.BaseTvColumns {
-    field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
-    field public static final java.lang.String COLUMN_DESCRIPTION = "description";
-    field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final java.lang.String COLUMN_INTERNAL_SESSION_TOKEN = "session_token";
-    field public static final java.lang.String COLUMN_INTERNAL_TUNE_PARAMS = "tune_params";
-    field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis";
-    field public static final java.lang.String COLUMN_WATCH_START_TIME_UTC_MILLIS = "watch_start_time_utc_millis";
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watched_program";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watched_program";
+    field public static final String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final String COLUMN_DESCRIPTION = "description";
+    field public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+    field public static final String COLUMN_INTERNAL_SESSION_TOKEN = "session_token";
+    field public static final String COLUMN_INTERNAL_TUNE_PARAMS = "tune_params";
+    field public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+    field public static final String COLUMN_TITLE = "title";
+    field public static final String COLUMN_WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis";
+    field public static final String COLUMN_WATCH_START_TIME_UTC_MILLIS = "watch_start_time_utc_millis";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watched_program";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watched_program";
     field public static final android.net.Uri CONTENT_URI;
   }
 
   public final class TvInputHardwareInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getAudioAddress();
+    method public String getAudioAddress();
     method public int getAudioType();
     method public int getCableConnectionStatus();
     method public int getDeviceId();
@@ -3388,7 +3848,7 @@
 
   public static final class TvInputHardwareInfo.Builder {
     ctor public TvInputHardwareInfo.Builder();
-    method public android.media.tv.TvInputHardwareInfo.Builder audioAddress(java.lang.String);
+    method public android.media.tv.TvInputHardwareInfo.Builder audioAddress(String);
     method public android.media.tv.TvInputHardwareInfo.Builder audioType(int);
     method public android.media.tv.TvInputHardwareInfo build();
     method public android.media.tv.TvInputHardwareInfo.Builder cableConnectionStatus(int);
@@ -3398,79 +3858,79 @@
   }
 
   public final class TvInputInfo implements android.os.Parcelable {
-    method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, java.lang.String, java.lang.String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, java.lang.String, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, java.lang.String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public static deprecated android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @Deprecated public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, String, String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @Deprecated public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, String, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @Deprecated public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @Deprecated public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public android.hardware.hdmi.HdmiDeviceInfo getHdmiDeviceInfo();
     method public boolean isConnectedToHdmiSwitch();
     method public boolean isHardwareInput();
-    method public android.graphics.drawable.Drawable loadIcon(android.content.Context, int);
+    method public android.graphics.drawable.Drawable loadIcon(@NonNull android.content.Context, int);
   }
 
   public static final class TvInputInfo.Builder {
     method public android.media.tv.TvInputInfo.Builder setHdmiDeviceInfo(android.hardware.hdmi.HdmiDeviceInfo);
     method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon);
     method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon, int);
-    method public android.media.tv.TvInputInfo.Builder setLabel(java.lang.CharSequence);
-    method public android.media.tv.TvInputInfo.Builder setLabel(int);
-    method public android.media.tv.TvInputInfo.Builder setParentId(java.lang.String);
+    method public android.media.tv.TvInputInfo.Builder setLabel(CharSequence);
+    method public android.media.tv.TvInputInfo.Builder setLabel(@StringRes int);
+    method public android.media.tv.TvInputInfo.Builder setParentId(String);
     method public android.media.tv.TvInputInfo.Builder setTvInputHardwareInfo(android.media.tv.TvInputHardwareInfo);
   }
 
   public static final class TvInputInfo.TvInputSettings {
-    method public static java.util.Map<java.lang.String, java.lang.String> getCustomLabels(android.content.Context, int);
+    method public static java.util.Map<java.lang.String,java.lang.String> getCustomLabels(android.content.Context, int);
     method public static java.util.Set<java.lang.String> getHiddenTvInputIds(android.content.Context, int);
-    method public static void putCustomLabels(android.content.Context, java.util.Map<java.lang.String, java.lang.String>, int);
+    method public static void putCustomLabels(android.content.Context, java.util.Map<java.lang.String,java.lang.String>, int);
     method public static void putHiddenTvInputs(android.content.Context, java.util.Set<java.lang.String>, int);
   }
 
   public final class TvInputManager {
-    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputInfo, android.media.tv.TvInputManager.HardwareCallback);
-    method public void addBlockedRating(android.media.tv.TvContentRating);
-    method public boolean captureFrame(java.lang.String, android.view.Surface, android.media.tv.TvStreamConfig);
-    method public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(java.lang.String);
-    method public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList();
-    method public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList();
-    method public boolean isSingleSessionActive();
-    method public void notifyPreviewProgramAddedToWatchNext(java.lang.String, long, long);
-    method public void notifyPreviewProgramBrowsableDisabled(java.lang.String, long);
-    method public void notifyWatchNextProgramBrowsableDisabled(java.lang.String, long);
-    method public void releaseTvInputHardware(int, android.media.tv.TvInputManager.Hardware);
-    method public void removeBlockedRating(android.media.tv.TvContentRating);
-    method public void setParentalControlsEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputInfo, android.media.tv.TvInputManager.HardwareCallback);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void addBlockedRating(@NonNull android.media.tv.TvContentRating);
+    method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean captureFrame(String, android.view.Surface, android.media.tv.TvStreamConfig);
+    method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
+    method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList();
+    method @RequiresPermission(android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS) public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList();
+    method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean isSingleSessionActive();
+    method @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS) public void notifyPreviewProgramAddedToWatchNext(String, long, long);
+    method @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS) public void notifyPreviewProgramBrowsableDisabled(String, long);
+    method @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS) public void notifyWatchNextProgramBrowsableDisabled(String, long);
+    method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public void releaseTvInputHardware(int, android.media.tv.TvInputManager.Hardware);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void removeBlockedRating(@NonNull android.media.tv.TvContentRating);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void setParentalControlsEnabled(boolean);
   }
 
   public static final class TvInputManager.Hardware {
-    method public void overrideAudioSink(int, java.lang.String, int, int, int);
+    method public void overrideAudioSink(int, String, int, int, int);
     method public void setStreamVolume(float);
     method public boolean setSurface(android.view.Surface, android.media.tv.TvStreamConfig);
   }
 
-  public static abstract class TvInputManager.HardwareCallback {
+  public abstract static class TvInputManager.HardwareCallback {
     ctor public TvInputManager.HardwareCallback();
     method public abstract void onReleased();
     method public abstract void onStreamConfigChanged(android.media.tv.TvStreamConfig[]);
   }
 
   public abstract class TvInputService extends android.app.Service {
-    method public android.media.tv.TvInputInfo onHardwareAdded(android.media.tv.TvInputHardwareInfo);
-    method public java.lang.String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
-    method public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo);
-    method public java.lang.String onHdmiDeviceRemoved(android.hardware.hdmi.HdmiDeviceInfo);
+    method @Nullable public android.media.tv.TvInputInfo onHardwareAdded(android.media.tv.TvInputHardwareInfo);
+    method @Nullable public String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
+    method @Nullable public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo);
+    method @Nullable public String onHdmiDeviceRemoved(android.hardware.hdmi.HdmiDeviceInfo);
   }
 
-  public static abstract class TvInputService.RecordingSession {
-    method public void notifySessionEvent(java.lang.String, android.os.Bundle);
+  public abstract static class TvInputService.RecordingSession {
+    method public void notifySessionEvent(@NonNull String, android.os.Bundle);
   }
 
-  public static abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
-    method public void notifySessionEvent(java.lang.String, android.os.Bundle);
+  public abstract static class TvInputService.Session implements android.view.KeyEvent.Callback {
+    method public void notifySessionEvent(@NonNull String, android.os.Bundle);
     method public void onSetMain(boolean);
   }
 
-  public static abstract class TvRecordingClient.RecordingCallback {
-    method public void onEvent(java.lang.String, java.lang.String, android.os.Bundle);
+  public abstract static class TvRecordingClient.RecordingCallback {
+    method public void onEvent(String, String, android.os.Bundle);
   }
 
   public class TvStreamConfig implements android.os.Parcelable {
@@ -3497,12 +3957,12 @@
   }
 
   public class TvView extends android.view.ViewGroup {
-    method public void setMain();
-    method public void unblockContent(android.media.tv.TvContentRating);
+    method @RequiresPermission("android.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE") public void setMain();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void unblockContent(android.media.tv.TvContentRating);
   }
 
-  public static abstract class TvView.TvInputCallback {
-    method public void onEvent(java.lang.String, java.lang.String, android.os.Bundle);
+  public abstract static class TvView.TvInputCallback {
+    method public void onEvent(String, String, android.os.Bundle);
   }
 
 }
@@ -3511,31 +3971,31 @@
 
   public class LogMaker {
     ctor public LogMaker(int);
-    ctor public LogMaker(java.lang.Object[]);
-    method public android.metrics.LogMaker addTaggedData(int, java.lang.Object);
+    ctor public LogMaker(Object[]);
+    method public android.metrics.LogMaker addTaggedData(int, Object);
     method public android.metrics.LogMaker clearCategory();
     method public android.metrics.LogMaker clearPackageName();
     method public android.metrics.LogMaker clearSubtype();
     method public android.metrics.LogMaker clearTaggedData(int);
     method public android.metrics.LogMaker clearType();
-    method public void deserialize(java.lang.Object[]);
+    method public void deserialize(Object[]);
     method public int getCategory();
     method public long getCounterBucket();
-    method public java.lang.String getCounterName();
+    method public String getCounterName();
     method public int getCounterValue();
-    method public java.lang.String getPackageName();
+    method public String getPackageName();
     method public int getProcessId();
     method public int getSubtype();
-    method public java.lang.Object getTaggedData(int);
+    method public Object getTaggedData(int);
     method public long getTimestamp();
     method public int getType();
     method public int getUid();
     method public boolean isLongCounterBucket();
     method public boolean isSubsetOf(android.metrics.LogMaker);
-    method public boolean isValidValue(java.lang.Object);
-    method public java.lang.Object[] serialize();
+    method public boolean isValidValue(Object);
+    method public Object[] serialize();
     method public android.metrics.LogMaker setCategory(int);
-    method public android.metrics.LogMaker setPackageName(java.lang.String);
+    method public android.metrics.LogMaker setPackageName(String);
     method public android.metrics.LogMaker setSubtype(int);
     method public android.metrics.LogMaker setType(int);
   }
@@ -3553,43 +4013,59 @@
 
 package android.net {
 
+  public class CaptivePortal implements android.os.Parcelable {
+    ctor public CaptivePortal(android.os.IBinder);
+    method public void useNetwork();
+    field public static final int APP_RETURN_DISMISSED = 0; // 0x0
+    field public static final int APP_RETURN_UNWANTED = 1; // 0x1
+    field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2
+  }
+
   public class ConnectivityManager {
-    method public java.lang.String getCaptivePortalServerUrl();
-    method public boolean isTetheringSupported();
-    method public void setAirplaneMode(boolean);
-    method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
-    method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
-    method public void stopTethering(int);
+    method @RequiresPermission("android.permission.PACKET_KEEPALIVE_OFFLOAD") public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull java.io.FileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
+    method public boolean getAvoidBadWifi();
+    method @RequiresPermission(android.Manifest.permission.LOCAL_MAC_ADDRESS) public String getCaptivePortalServerUrl();
+    method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean);
+    method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
+    method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
+    field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
+    field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
     field public static final int TETHERING_BLUETOOTH = 2; // 0x2
     field public static final int TETHERING_USB = 1; // 0x1
     field public static final int TETHERING_WIFI = 0; // 0x0
   }
 
-  public static abstract class ConnectivityManager.OnStartTetheringCallback {
+  public abstract static class ConnectivityManager.OnStartTetheringCallback {
     ctor public ConnectivityManager.OnStartTetheringCallback();
     method public void onTetheringFailed();
     method public void onTetheringStarted();
   }
 
+  public final class IpPrefix implements android.os.Parcelable {
+    ctor public IpPrefix(java.net.InetAddress, int);
+  }
+
   public final class IpSecManager {
-    method public void applyTunnelModeTransform(android.net.IpSecManager.IpSecTunnelInterface, int, android.net.IpSecTransform) throws java.io.IOException;
-    method public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(java.net.InetAddress, java.net.InetAddress, android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
   }
 
   public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
-    method public void addAddress(java.net.InetAddress, int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
     method public void close();
-    method public java.lang.String getInterfaceName();
-    method public void removeAddress(java.net.InetAddress, int) throws java.io.IOException;
+    method @NonNull public String getInterfaceName();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
   }
 
   public final class IpSecTransform implements java.lang.AutoCloseable {
-    method public void startNattKeepalive(android.net.IpSecTransform.NattKeepaliveCallback, int, android.os.Handler) throws java.io.IOException;
-    method public void stopNattKeepalive();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "android.permission.PACKET_KEEPALIVE_OFFLOAD"}) public void startNattKeepalive(@NonNull android.net.IpSecTransform.NattKeepaliveCallback, int, @NonNull android.os.Handler) throws java.io.IOException;
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "android.permission.PACKET_KEEPALIVE_OFFLOAD"}) public void stopNattKeepalive();
   }
 
   public static class IpSecTransform.Builder {
-    method public android.net.IpSecTransform buildTunnelModeTransform(java.net.InetAddress, android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecTransform buildTunnelModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
   }
 
   public static class IpSecTransform.NattKeepaliveCallback {
@@ -3603,24 +4079,56 @@
   }
 
   public class LinkAddress implements android.os.Parcelable {
+    ctor public LinkAddress(java.net.InetAddress, int, int, int);
     ctor public LinkAddress(java.net.InetAddress, int);
-    ctor public LinkAddress(java.lang.String);
+    ctor public LinkAddress(String);
+    method public boolean isGlobalPreferred();
+    method public boolean isIPv4();
+    method public boolean isIPv6();
+    method public boolean isSameAddressAs(android.net.LinkAddress);
   }
 
   public final class LinkProperties implements android.os.Parcelable {
     ctor public LinkProperties();
+    ctor public LinkProperties(android.net.LinkProperties);
+    method public boolean addDnsServer(java.net.InetAddress);
     method public boolean addRoute(android.net.RouteInfo);
     method public void clear();
+    method @Nullable public android.net.IpPrefix getNat64Prefix();
+    method public java.util.List<java.net.InetAddress> getPcscfServers();
+    method public String getTcpBufferSizes();
+    method public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
+    method public boolean hasGlobalIPv6Address();
+    method public boolean hasIPv4Address();
+    method public boolean hasIPv6DefaultRoute();
+    method public boolean isIPv4Provisioned();
+    method public boolean isIPv6Provisioned();
+    method public boolean isProvisioned();
+    method public boolean isReachable(java.net.InetAddress);
+    method public boolean removeDnsServer(java.net.InetAddress);
+    method public boolean removeRoute(android.net.RouteInfo);
     method public void setDnsServers(java.util.Collection<java.net.InetAddress>);
-    method public void setDomains(java.lang.String);
+    method public void setDomains(String);
     method public void setHttpProxy(android.net.ProxyInfo);
-    method public void setInterfaceName(java.lang.String);
+    method public void setInterfaceName(String);
     method public void setLinkAddresses(java.util.Collection<android.net.LinkAddress>);
     method public void setMtu(int);
+    method public void setNat64Prefix(android.net.IpPrefix);
+    method public void setPcscfServers(java.util.Collection<java.net.InetAddress>);
+    method public void setPrivateDnsServerName(@Nullable String);
+    method public void setTcpBufferSizes(String);
+    method public void setUsePrivateDns(boolean);
+    method public void setValidatedPrivateDnsServers(java.util.Collection<java.net.InetAddress>);
+  }
+
+  public class Network implements android.os.Parcelable {
+    method public android.net.Network getPrivateDnsBypassingCopy();
   }
 
   public final class NetworkCapabilities implements android.os.Parcelable {
     method public int getSignalStrength();
+    method public int[] getTransportTypes();
+    method public boolean satisfiedByNetworkCapabilities(android.net.NetworkCapabilities);
     field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
   }
 
@@ -3645,19 +4153,27 @@
   }
 
   public class NetworkScoreManager {
-    method public boolean clearScores() throws java.lang.SecurityException;
-    method public void disableScoring() throws java.lang.SecurityException;
-    method public java.lang.String getActiveScorerPackage();
-    method public boolean setActiveScorer(java.lang.String) throws java.lang.SecurityException;
-    method public boolean updateScores(android.net.ScoredNetwork[]) throws java.lang.SecurityException;
-    field public static final java.lang.String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
-    field public static final java.lang.String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";
-    field public static final java.lang.String ACTION_RECOMMEND_NETWORKS = "android.net.action.RECOMMEND_NETWORKS";
-    field public static final java.lang.String ACTION_SCORER_CHANGED = "android.net.scoring.SCORER_CHANGED";
-    field public static final java.lang.String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
-    field public static final java.lang.String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
-    field public static final java.lang.String EXTRA_NEW_SCORER = "newScorer";
-    field public static final java.lang.String EXTRA_PACKAGE_NAME = "packageName";
+    method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public boolean clearScores() throws java.lang.SecurityException;
+    method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public void disableScoring() throws java.lang.SecurityException;
+    method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public String getActiveScorerPackage();
+    method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public boolean setActiveScorer(String) throws java.lang.SecurityException;
+    method @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) public boolean updateScores(android.net.ScoredNetwork[]) throws java.lang.SecurityException;
+    field public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
+    field public static final String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";
+    field public static final String ACTION_RECOMMEND_NETWORKS = "android.net.action.RECOMMEND_NETWORKS";
+    field public static final String ACTION_SCORER_CHANGED = "android.net.scoring.SCORER_CHANGED";
+    field public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
+    field public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
+    field public static final String EXTRA_NEW_SCORER = "newScorer";
+    field public static final String EXTRA_PACKAGE_NAME = "packageName";
+  }
+
+  public final class RouteInfo implements android.os.Parcelable {
+    ctor public RouteInfo(android.net.IpPrefix, java.net.InetAddress, String, int);
+    method public int getType();
+    field public static final int RTN_THROW = 9; // 0x9
+    field public static final int RTN_UNICAST = 1; // 0x1
+    field public static final int RTN_UNREACHABLE = 7; // 0x7
   }
 
   public class RssiCurve implements android.os.Parcelable {
@@ -3677,15 +4193,15 @@
   public class ScoredNetwork implements android.os.Parcelable {
     ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve);
     ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean);
-    ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean, android.os.Bundle);
+    ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean, @Nullable android.os.Bundle);
     method public int calculateBadge(int);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final java.lang.String ATTRIBUTES_KEY_BADGING_CURVE = "android.net.attributes.key.BADGING_CURVE";
-    field public static final java.lang.String ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL = "android.net.attributes.key.HAS_CAPTIVE_PORTAL";
-    field public static final java.lang.String ATTRIBUTES_KEY_RANKING_SCORE_OFFSET = "android.net.attributes.key.RANKING_SCORE_OFFSET";
+    field public static final String ATTRIBUTES_KEY_BADGING_CURVE = "android.net.attributes.key.BADGING_CURVE";
+    field public static final String ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL = "android.net.attributes.key.HAS_CAPTIVE_PORTAL";
+    field public static final String ATTRIBUTES_KEY_RANKING_SCORE_OFFSET = "android.net.attributes.key.RANKING_SCORE_OFFSET";
     field public static final android.os.Parcelable.Creator<android.net.ScoredNetwork> CREATOR;
-    field public final android.os.Bundle attributes;
+    field @Nullable public final android.os.Bundle attributes;
     field public final boolean meteredHint;
     field public final android.net.NetworkKey networkKey;
     field public final android.net.RssiCurve rssiCurve;
@@ -3698,324 +4214,505 @@
   }
 
   public class VpnService extends android.app.Service {
-    method public static void prepareAndAuthorize(android.content.Context);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_VPN) public static void prepareAndAuthorize(android.content.Context);
   }
 
   public class WebAddress {
-    ctor public WebAddress(java.lang.String) throws android.net.ParseException;
+    ctor public WebAddress(String) throws android.net.ParseException;
   }
 
   public class WifiKey implements android.os.Parcelable {
-    ctor public WifiKey(java.lang.String, java.lang.String);
+    ctor public WifiKey(String, String);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.WifiKey> CREATOR;
-    field public final java.lang.String bssid;
-    field public final java.lang.String ssid;
+    field public final String bssid;
+    field public final String ssid;
+  }
+
+}
+
+package android.net.metrics {
+
+  public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
+  }
+
+  public static class ApfProgramEvent.Builder {
+    ctor public ApfProgramEvent.Builder();
+    method public android.net.metrics.ApfProgramEvent build();
+    method public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
+    method public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
+    method public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
+    method public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
+    method public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
+    method public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
+  }
+
+  public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event {
+  }
+
+  public static class ApfStats.Builder {
+    ctor public ApfStats.Builder();
+    method public android.net.metrics.ApfStats build();
+    method public android.net.metrics.ApfStats.Builder setDroppedRas(int);
+    method public android.net.metrics.ApfStats.Builder setDurationMs(long);
+    method public android.net.metrics.ApfStats.Builder setMatchingRas(int);
+    method public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
+    method public android.net.metrics.ApfStats.Builder setParseErrors(int);
+    method public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
+    method public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
+    method public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
+    method public android.net.metrics.ApfStats.Builder setReceivedRas(int);
+    method public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
+  }
+
+  public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event {
+  }
+
+  public static class DhcpClientEvent.Builder {
+    ctor public DhcpClientEvent.Builder();
+    method public android.net.metrics.DhcpClientEvent build();
+    method public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
+    method public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
+  }
+
+  public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event {
+    ctor public DhcpErrorEvent(int);
+    method public static int errorCodeWithOption(int, int);
+    field public static final int BOOTP_TOO_SHORT;
+    field public static final int BUFFER_UNDERFLOW;
+    field public static final int DHCP_BAD_MAGIC_COOKIE;
+    field public static final int DHCP_ERROR = 4; // 0x4
+    field public static final int DHCP_INVALID_OPTION_LENGTH;
+    field public static final int DHCP_NO_COOKIE;
+    field public static final int DHCP_NO_MSG_TYPE;
+    field public static final int DHCP_UNKNOWN_MSG_TYPE;
+    field public static final int L2_ERROR = 1; // 0x1
+    field public static final int L2_TOO_SHORT;
+    field public static final int L2_WRONG_ETH_TYPE;
+    field public static final int L3_ERROR = 2; // 0x2
+    field public static final int L3_INVALID_IP;
+    field public static final int L3_NOT_IPV4;
+    field public static final int L3_TOO_SHORT;
+    field public static final int L4_ERROR = 3; // 0x3
+    field public static final int L4_NOT_UDP;
+    field public static final int L4_WRONG_PORT;
+    field public static final int MISC_ERROR = 5; // 0x5
+    field public static final int PARSING_ERROR;
+    field public static final int RECEIVE_ERROR;
+  }
+
+  public class IpConnectivityLog {
+    ctor public IpConnectivityLog();
+    method public boolean log(long, android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(String, android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(android.net.Network, int[], android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(int, int[], android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(android.net.metrics.IpConnectivityLog.Event);
+  }
+
+  public static interface IpConnectivityLog.Event extends android.os.Parcelable {
+  }
+
+  public final class IpManagerEvent implements android.net.metrics.IpConnectivityLog.Event {
+    ctor public IpManagerEvent(int, long);
+    field public static final int COMPLETE_LIFECYCLE = 3; // 0x3
+    field public static final int ERROR_INTERFACE_NOT_FOUND = 8; // 0x8
+    field public static final int ERROR_INVALID_PROVISIONING = 7; // 0x7
+    field public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6; // 0x6
+    field public static final int ERROR_STARTING_IPV4 = 4; // 0x4
+    field public static final int ERROR_STARTING_IPV6 = 5; // 0x5
+    field public static final int PROVISIONING_FAIL = 2; // 0x2
+    field public static final int PROVISIONING_OK = 1; // 0x1
+  }
+
+  public final class IpReachabilityEvent implements android.net.metrics.IpConnectivityLog.Event {
+    ctor public IpReachabilityEvent(int);
+    field public static final int NUD_FAILED = 512; // 0x200
+    field public static final int NUD_FAILED_ORGANIC = 1024; // 0x400
+    field public static final int PROBE = 256; // 0x100
+    field public static final int PROVISIONING_LOST = 768; // 0x300
+    field public static final int PROVISIONING_LOST_ORGANIC = 1280; // 0x500
+  }
+
+  public final class NetworkEvent implements android.net.metrics.IpConnectivityLog.Event {
+    ctor public NetworkEvent(int, long);
+    ctor public NetworkEvent(int);
+    field public static final int NETWORK_CAPTIVE_PORTAL_FOUND = 4; // 0x4
+    field public static final int NETWORK_CONNECTED = 1; // 0x1
+    field public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12; // 0xc
+    field public static final int NETWORK_DISCONNECTED = 7; // 0x7
+    field public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; // 0xa
+    field public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; // 0x8
+    field public static final int NETWORK_LINGER = 5; // 0x5
+    field public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; // 0xb
+    field public static final int NETWORK_REVALIDATION_SUCCESS = 9; // 0x9
+    field public static final int NETWORK_UNLINGER = 6; // 0x6
+    field public static final int NETWORK_VALIDATED = 2; // 0x2
+    field public static final int NETWORK_VALIDATION_FAILED = 3; // 0x3
+  }
+
+  public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event {
+  }
+
+  public static class RaEvent.Builder {
+    ctor public RaEvent.Builder();
+    method public android.net.metrics.RaEvent build();
+    method public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long);
+    method public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long);
+    method public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long);
+    method public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long);
+    method public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long);
+    method public android.net.metrics.RaEvent.Builder updateRouterLifetime(long);
+  }
+
+  public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event {
+    method public static String getProbeName(int);
+    field public static final int DNS_FAILURE = 0; // 0x0
+    field public static final int DNS_SUCCESS = 1; // 0x1
+    field public static final int PROBE_DNS = 0; // 0x0
+    field public static final int PROBE_FALLBACK = 4; // 0x4
+    field public static final int PROBE_HTTP = 1; // 0x1
+    field public static final int PROBE_HTTPS = 2; // 0x2
+    field public static final int PROBE_PAC = 3; // 0x3
+    field public static final int PROBE_PRIVDNS = 5; // 0x5
+  }
+
+  public static class ValidationProbeEvent.Builder {
+    ctor public ValidationProbeEvent.Builder();
+    method public android.net.metrics.ValidationProbeEvent build();
+    method public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
+    method public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
+    method public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
+  }
+
+}
+
+package android.net.util {
+
+  public class SocketUtils {
+    method public static void bindSocketToInterface(java.io.FileDescriptor, String) throws android.system.ErrnoException;
+    method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
+    method public static java.net.SocketAddress makePacketSocketAddress(short, int);
+    method public static java.net.SocketAddress makePacketSocketAddress(int, byte[]);
   }
 
 }
 
 package android.net.wifi {
 
-  public abstract class DppStatusCallback {
-    ctor public DppStatusCallback();
+  public abstract class EasyConnectStatusCallback {
+    ctor public EasyConnectStatusCallback();
     method public abstract void onConfiguratorSuccess(int);
     method public abstract void onEnrolleeSuccess(int);
     method public abstract void onFailure(int);
     method public abstract void onProgress(int);
-    field public static final int DPP_EVENT_FAILURE = -7; // 0xfffffff9
-    field public static final int DPP_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
-    field public static final int DPP_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
-    field public static final int DPP_EVENT_FAILURE_CONFIGURATION = -4; // 0xfffffffc
-    field public static final int DPP_EVENT_FAILURE_INVALID_NETWORK = -9; // 0xfffffff7
-    field public static final int DPP_EVENT_FAILURE_INVALID_URI = -1; // 0xffffffff
-    field public static final int DPP_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
-    field public static final int DPP_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
-    field public static final int DPP_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
-    field public static final int DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0; // 0x0
-    field public static final int DPP_EVENT_PROGRESS_RESPONSE_PENDING = 1; // 0x1
-    field public static final int DPP_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0
+    field public static final int EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION = -2; // 0xfffffffe
+    field public static final int EASY_CONNECT_EVENT_FAILURE_BUSY = -5; // 0xfffffffb
+    field public static final int EASY_CONNECT_EVENT_FAILURE_CONFIGURATION = -4; // 0xfffffffc
+    field public static final int EASY_CONNECT_EVENT_FAILURE_GENERIC = -7; // 0xfffffff9
+    field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = -9; // 0xfffffff7
+    field public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_URI = -1; // 0xffffffff
+    field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
+    field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
+    field public static final int EASY_CONNECT_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
+    field public static final int EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0; // 0x0
+    field public static final int EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING = 1; // 0x1
+    field public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0
   }
 
-  public deprecated class RttManager {
-    method public void disableResponder(android.net.wifi.RttManager.ResponderCallback);
-    method public void enableResponder(android.net.wifi.RttManager.ResponderCallback);
-    method public deprecated android.net.wifi.RttManager.Capabilities getCapabilities();
-    method public android.net.wifi.RttManager.RttCapabilities getRttCapabilities();
-    method public void startRanging(android.net.wifi.RttManager.RttParams[], android.net.wifi.RttManager.RttListener);
-    method public void stopRanging(android.net.wifi.RttManager.RttListener);
-    field public static final int BASE = 160256; // 0x27200
-    field public static final int CMD_OP_ABORTED = 160260; // 0x27204
-    field public static final int CMD_OP_DISABLE_RESPONDER = 160262; // 0x27206
-    field public static final int CMD_OP_ENABLE_RESPONDER = 160261; // 0x27205
-    field public static final int CMD_OP_ENALBE_RESPONDER_FAILED = 160264; // 0x27208
-    field public static final int CMD_OP_ENALBE_RESPONDER_SUCCEEDED = 160263; // 0x27207
-    field public static final int CMD_OP_FAILED = 160258; // 0x27202
-    field public static final int CMD_OP_START_RANGING = 160256; // 0x27200
-    field public static final int CMD_OP_STOP_RANGING = 160257; // 0x27201
-    field public static final int CMD_OP_SUCCEEDED = 160259; // 0x27203
-    field public static final java.lang.String DESCRIPTION_KEY = "android.net.wifi.RttManager.Description";
-    field public static final int PREAMBLE_HT = 2; // 0x2
-    field public static final int PREAMBLE_LEGACY = 1; // 0x1
-    field public static final int PREAMBLE_VHT = 4; // 0x4
-    field public static final int REASON_INITIATOR_NOT_ALLOWED_WHEN_RESPONDER_ON = -6; // 0xfffffffa
-    field public static final int REASON_INVALID_LISTENER = -3; // 0xfffffffd
-    field public static final int REASON_INVALID_REQUEST = -4; // 0xfffffffc
-    field public static final int REASON_NOT_AVAILABLE = -2; // 0xfffffffe
-    field public static final int REASON_PERMISSION_DENIED = -5; // 0xfffffffb
-    field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
-    field public static final int RTT_BW_10_SUPPORT = 2; // 0x2
-    field public static final int RTT_BW_160_SUPPORT = 32; // 0x20
-    field public static final int RTT_BW_20_SUPPORT = 4; // 0x4
-    field public static final int RTT_BW_40_SUPPORT = 8; // 0x8
-    field public static final int RTT_BW_5_SUPPORT = 1; // 0x1
-    field public static final int RTT_BW_80_SUPPORT = 16; // 0x10
-    field public static final deprecated int RTT_CHANNEL_WIDTH_10 = 6; // 0x6
-    field public static final deprecated int RTT_CHANNEL_WIDTH_160 = 3; // 0x3
-    field public static final deprecated int RTT_CHANNEL_WIDTH_20 = 0; // 0x0
-    field public static final deprecated int RTT_CHANNEL_WIDTH_40 = 1; // 0x1
-    field public static final deprecated int RTT_CHANNEL_WIDTH_5 = 5; // 0x5
-    field public static final deprecated int RTT_CHANNEL_WIDTH_80 = 2; // 0x2
-    field public static final deprecated int RTT_CHANNEL_WIDTH_80P80 = 4; // 0x4
-    field public static final deprecated int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1; // 0xffffffff
-    field public static final int RTT_PEER_NAN = 5; // 0x5
-    field public static final int RTT_PEER_P2P_CLIENT = 4; // 0x4
-    field public static final int RTT_PEER_P2P_GO = 3; // 0x3
-    field public static final int RTT_PEER_TYPE_AP = 1; // 0x1
-    field public static final int RTT_PEER_TYPE_STA = 2; // 0x2
-    field public static final deprecated int RTT_PEER_TYPE_UNSPECIFIED = 0; // 0x0
-    field public static final int RTT_STATUS_ABORTED = 8; // 0x8
-    field public static final int RTT_STATUS_FAILURE = 1; // 0x1
-    field public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6; // 0x6
-    field public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER = 12; // 0xc
-    field public static final int RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE = 15; // 0xf
-    field public static final int RTT_STATUS_FAIL_INVALID_TS = 9; // 0x9
-    field public static final int RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4; // 0x4
-    field public static final int RTT_STATUS_FAIL_NO_CAPABILITY = 7; // 0x7
-    field public static final int RTT_STATUS_FAIL_NO_RSP = 2; // 0x2
-    field public static final int RTT_STATUS_FAIL_PROTOCOL = 10; // 0xa
-    field public static final int RTT_STATUS_FAIL_REJECTED = 3; // 0x3
-    field public static final int RTT_STATUS_FAIL_SCHEDULE = 11; // 0xb
-    field public static final int RTT_STATUS_FAIL_TM_TIMEOUT = 5; // 0x5
-    field public static final int RTT_STATUS_INVALID_REQ = 13; // 0xd
-    field public static final int RTT_STATUS_NO_WIFI = 14; // 0xe
-    field public static final int RTT_STATUS_SUCCESS = 0; // 0x0
-    field public static final deprecated int RTT_TYPE_11_MC = 4; // 0x4
-    field public static final deprecated int RTT_TYPE_11_V = 2; // 0x2
-    field public static final int RTT_TYPE_ONE_SIDED = 1; // 0x1
-    field public static final int RTT_TYPE_TWO_SIDED = 2; // 0x2
-    field public static final deprecated int RTT_TYPE_UNSPECIFIED = 0; // 0x0
+  @Deprecated public class RttManager {
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void disableResponder(android.net.wifi.RttManager.ResponderCallback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void enableResponder(android.net.wifi.RttManager.ResponderCallback);
+    method @Deprecated public android.net.wifi.RttManager.Capabilities getCapabilities();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.net.wifi.RttManager.RttCapabilities getRttCapabilities();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startRanging(android.net.wifi.RttManager.RttParams[], android.net.wifi.RttManager.RttListener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void stopRanging(android.net.wifi.RttManager.RttListener);
+    field @Deprecated public static final int BASE = 160256; // 0x27200
+    field @Deprecated public static final int CMD_OP_ABORTED = 160260; // 0x27204
+    field @Deprecated public static final int CMD_OP_DISABLE_RESPONDER = 160262; // 0x27206
+    field @Deprecated public static final int CMD_OP_ENABLE_RESPONDER = 160261; // 0x27205
+    field @Deprecated public static final int CMD_OP_ENALBE_RESPONDER_FAILED = 160264; // 0x27208
+    field @Deprecated public static final int CMD_OP_ENALBE_RESPONDER_SUCCEEDED = 160263; // 0x27207
+    field @Deprecated public static final int CMD_OP_FAILED = 160258; // 0x27202
+    field @Deprecated public static final int CMD_OP_START_RANGING = 160256; // 0x27200
+    field @Deprecated public static final int CMD_OP_STOP_RANGING = 160257; // 0x27201
+    field @Deprecated public static final int CMD_OP_SUCCEEDED = 160259; // 0x27203
+    field @Deprecated public static final String DESCRIPTION_KEY = "android.net.wifi.RttManager.Description";
+    field @Deprecated public static final int PREAMBLE_HT = 2; // 0x2
+    field @Deprecated public static final int PREAMBLE_LEGACY = 1; // 0x1
+    field @Deprecated public static final int PREAMBLE_VHT = 4; // 0x4
+    field @Deprecated public static final int REASON_INITIATOR_NOT_ALLOWED_WHEN_RESPONDER_ON = -6; // 0xfffffffa
+    field @Deprecated public static final int REASON_INVALID_LISTENER = -3; // 0xfffffffd
+    field @Deprecated public static final int REASON_INVALID_REQUEST = -4; // 0xfffffffc
+    field @Deprecated public static final int REASON_NOT_AVAILABLE = -2; // 0xfffffffe
+    field @Deprecated public static final int REASON_PERMISSION_DENIED = -5; // 0xfffffffb
+    field @Deprecated public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
+    field @Deprecated public static final int RTT_BW_10_SUPPORT = 2; // 0x2
+    field @Deprecated public static final int RTT_BW_160_SUPPORT = 32; // 0x20
+    field @Deprecated public static final int RTT_BW_20_SUPPORT = 4; // 0x4
+    field @Deprecated public static final int RTT_BW_40_SUPPORT = 8; // 0x8
+    field @Deprecated public static final int RTT_BW_5_SUPPORT = 1; // 0x1
+    field @Deprecated public static final int RTT_BW_80_SUPPORT = 16; // 0x10
+    field @Deprecated public static final int RTT_CHANNEL_WIDTH_10 = 6; // 0x6
+    field @Deprecated public static final int RTT_CHANNEL_WIDTH_160 = 3; // 0x3
+    field @Deprecated public static final int RTT_CHANNEL_WIDTH_20 = 0; // 0x0
+    field @Deprecated public static final int RTT_CHANNEL_WIDTH_40 = 1; // 0x1
+    field @Deprecated public static final int RTT_CHANNEL_WIDTH_5 = 5; // 0x5
+    field @Deprecated public static final int RTT_CHANNEL_WIDTH_80 = 2; // 0x2
+    field @Deprecated public static final int RTT_CHANNEL_WIDTH_80P80 = 4; // 0x4
+    field @Deprecated public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1; // 0xffffffff
+    field @Deprecated public static final int RTT_PEER_NAN = 5; // 0x5
+    field @Deprecated public static final int RTT_PEER_P2P_CLIENT = 4; // 0x4
+    field @Deprecated public static final int RTT_PEER_P2P_GO = 3; // 0x3
+    field @Deprecated public static final int RTT_PEER_TYPE_AP = 1; // 0x1
+    field @Deprecated public static final int RTT_PEER_TYPE_STA = 2; // 0x2
+    field @Deprecated public static final int RTT_PEER_TYPE_UNSPECIFIED = 0; // 0x0
+    field @Deprecated public static final int RTT_STATUS_ABORTED = 8; // 0x8
+    field @Deprecated public static final int RTT_STATUS_FAILURE = 1; // 0x1
+    field @Deprecated public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6; // 0x6
+    field @Deprecated public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER = 12; // 0xc
+    field @Deprecated public static final int RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE = 15; // 0xf
+    field @Deprecated public static final int RTT_STATUS_FAIL_INVALID_TS = 9; // 0x9
+    field @Deprecated public static final int RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4; // 0x4
+    field @Deprecated public static final int RTT_STATUS_FAIL_NO_CAPABILITY = 7; // 0x7
+    field @Deprecated public static final int RTT_STATUS_FAIL_NO_RSP = 2; // 0x2
+    field @Deprecated public static final int RTT_STATUS_FAIL_PROTOCOL = 10; // 0xa
+    field @Deprecated public static final int RTT_STATUS_FAIL_REJECTED = 3; // 0x3
+    field @Deprecated public static final int RTT_STATUS_FAIL_SCHEDULE = 11; // 0xb
+    field @Deprecated public static final int RTT_STATUS_FAIL_TM_TIMEOUT = 5; // 0x5
+    field @Deprecated public static final int RTT_STATUS_INVALID_REQ = 13; // 0xd
+    field @Deprecated public static final int RTT_STATUS_NO_WIFI = 14; // 0xe
+    field @Deprecated public static final int RTT_STATUS_SUCCESS = 0; // 0x0
+    field @Deprecated public static final int RTT_TYPE_11_MC = 4; // 0x4
+    field @Deprecated public static final int RTT_TYPE_11_V = 2; // 0x2
+    field @Deprecated public static final int RTT_TYPE_ONE_SIDED = 1; // 0x1
+    field @Deprecated public static final int RTT_TYPE_TWO_SIDED = 2; // 0x2
+    field @Deprecated public static final int RTT_TYPE_UNSPECIFIED = 0; // 0x0
   }
 
-  public deprecated class RttManager.Capabilities {
-    ctor public RttManager.Capabilities();
-    field public int supportedPeerType;
-    field public int supportedType;
+  @Deprecated public class RttManager.Capabilities {
+    ctor @Deprecated public RttManager.Capabilities();
+    field @Deprecated public int supportedPeerType;
+    field @Deprecated public int supportedType;
   }
 
-  public static deprecated class RttManager.ParcelableRttParams implements android.os.Parcelable {
-    field public android.net.wifi.RttManager.RttParams[] mParams;
+  @Deprecated public static class RttManager.ParcelableRttParams implements android.os.Parcelable {
+    field @Deprecated @NonNull public android.net.wifi.RttManager.RttParams[] mParams;
   }
 
-  public static deprecated class RttManager.ParcelableRttResults implements android.os.Parcelable {
-    ctor public RttManager.ParcelableRttResults(android.net.wifi.RttManager.RttResult[]);
-    field public android.net.wifi.RttManager.RttResult[] mResults;
+  @Deprecated public static class RttManager.ParcelableRttResults implements android.os.Parcelable {
+    ctor @Deprecated public RttManager.ParcelableRttResults(android.net.wifi.RttManager.RttResult[]);
+    field @Deprecated public android.net.wifi.RttManager.RttResult[] mResults;
   }
 
-  public static abstract deprecated class RttManager.ResponderCallback {
-    ctor public RttManager.ResponderCallback();
-    method public abstract void onResponderEnableFailure(int);
-    method public abstract void onResponderEnabled(android.net.wifi.RttManager.ResponderConfig);
+  @Deprecated public abstract static class RttManager.ResponderCallback {
+    ctor @Deprecated public RttManager.ResponderCallback();
+    method @Deprecated public abstract void onResponderEnableFailure(int);
+    method @Deprecated public abstract void onResponderEnabled(android.net.wifi.RttManager.ResponderConfig);
   }
 
-  public static deprecated class RttManager.ResponderConfig implements android.os.Parcelable {
-    ctor public RttManager.ResponderConfig();
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.wifi.RttManager.ResponderConfig> CREATOR;
-    field public int centerFreq0;
-    field public int centerFreq1;
-    field public int channelWidth;
-    field public int frequency;
-    field public java.lang.String macAddress;
-    field public int preamble;
+  @Deprecated public static class RttManager.ResponderConfig implements android.os.Parcelable {
+    ctor @Deprecated public RttManager.ResponderConfig();
+    method @Deprecated public int describeContents();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.net.wifi.RttManager.ResponderConfig> CREATOR;
+    field @Deprecated public int centerFreq0;
+    field @Deprecated public int centerFreq1;
+    field @Deprecated public int channelWidth;
+    field @Deprecated public int frequency;
+    field @Deprecated public String macAddress;
+    field @Deprecated public int preamble;
   }
 
-  public static deprecated class RttManager.RttCapabilities implements android.os.Parcelable {
-    ctor public RttManager.RttCapabilities();
-    field public int bwSupported;
-    field public boolean lciSupported;
-    field public boolean lcrSupported;
-    field public int mcVersion;
-    field public boolean oneSidedRttSupported;
-    field public int preambleSupported;
-    field public boolean responderSupported;
-    field public boolean secureRttSupported;
-    field public deprecated boolean supportedPeerType;
-    field public deprecated boolean supportedType;
-    field public boolean twoSided11McRttSupported;
+  @Deprecated public static class RttManager.RttCapabilities implements android.os.Parcelable {
+    ctor @Deprecated public RttManager.RttCapabilities();
+    field @Deprecated public int bwSupported;
+    field @Deprecated public boolean lciSupported;
+    field @Deprecated public boolean lcrSupported;
+    field @Deprecated public int mcVersion;
+    field @Deprecated public boolean oneSidedRttSupported;
+    field @Deprecated public int preambleSupported;
+    field @Deprecated public boolean responderSupported;
+    field @Deprecated public boolean secureRttSupported;
+    field @Deprecated public boolean supportedPeerType;
+    field @Deprecated public boolean supportedType;
+    field @Deprecated public boolean twoSided11McRttSupported;
   }
 
-  public static abstract deprecated interface RttManager.RttListener {
-    method public abstract void onAborted();
-    method public abstract void onFailure(int, java.lang.String);
-    method public abstract void onSuccess(android.net.wifi.RttManager.RttResult[]);
+  @Deprecated public static interface RttManager.RttListener {
+    method @Deprecated public void onAborted();
+    method @Deprecated public void onFailure(int, String);
+    method @Deprecated public void onSuccess(android.net.wifi.RttManager.RttResult[]);
   }
 
-  public static deprecated class RttManager.RttParams {
-    ctor public RttManager.RttParams();
-    field public boolean LCIRequest;
-    field public boolean LCRRequest;
-    field public int bandwidth;
-    field public java.lang.String bssid;
-    field public int burstTimeout;
-    field public int centerFreq0;
-    field public int centerFreq1;
-    field public int channelWidth;
-    field public int deviceType;
-    field public int frequency;
-    field public int interval;
-    field public int numRetriesPerFTMR;
-    field public int numRetriesPerMeasurementFrame;
-    field public int numSamplesPerBurst;
-    field public deprecated int num_retries;
-    field public deprecated int num_samples;
-    field public int numberBurst;
-    field public int preamble;
-    field public int requestType;
-    field public boolean secure;
+  @Deprecated public static class RttManager.RttParams {
+    ctor @Deprecated public RttManager.RttParams();
+    field @Deprecated public boolean LCIRequest;
+    field @Deprecated public boolean LCRRequest;
+    field @Deprecated public int bandwidth;
+    field @Deprecated public String bssid;
+    field @Deprecated public int burstTimeout;
+    field @Deprecated public int centerFreq0;
+    field @Deprecated public int centerFreq1;
+    field @Deprecated public int channelWidth;
+    field @Deprecated public int deviceType;
+    field @Deprecated public int frequency;
+    field @Deprecated public int interval;
+    field @Deprecated public int numRetriesPerFTMR;
+    field @Deprecated public int numRetriesPerMeasurementFrame;
+    field @Deprecated public int numSamplesPerBurst;
+    field @Deprecated public int num_retries;
+    field @Deprecated public int num_samples;
+    field @Deprecated public int numberBurst;
+    field @Deprecated public int preamble;
+    field @Deprecated public int requestType;
+    field @Deprecated public boolean secure;
   }
 
-  public static deprecated class RttManager.RttResult {
-    ctor public RttManager.RttResult();
-    field public android.net.wifi.RttManager.WifiInformationElement LCI;
-    field public android.net.wifi.RttManager.WifiInformationElement LCR;
-    field public java.lang.String bssid;
-    field public int burstDuration;
-    field public int burstNumber;
-    field public int distance;
-    field public int distanceSpread;
-    field public int distanceStandardDeviation;
-    field public deprecated int distance_cm;
-    field public deprecated int distance_sd_cm;
-    field public deprecated int distance_spread_cm;
-    field public int frameNumberPerBurstPeer;
-    field public int measurementFrameNumber;
-    field public int measurementType;
-    field public int negotiatedBurstNum;
-    field public deprecated int requestType;
-    field public int retryAfterDuration;
-    field public int rssi;
-    field public int rssiSpread;
-    field public deprecated int rssi_spread;
-    field public long rtt;
-    field public long rttSpread;
-    field public long rttStandardDeviation;
-    field public deprecated long rtt_ns;
-    field public deprecated long rtt_sd_ns;
-    field public deprecated long rtt_spread_ns;
-    field public int rxRate;
-    field public boolean secure;
-    field public int status;
-    field public int successMeasurementFrameNumber;
-    field public long ts;
-    field public int txRate;
-    field public deprecated int tx_rate;
+  @Deprecated public static class RttManager.RttResult {
+    ctor @Deprecated public RttManager.RttResult();
+    field @Deprecated public android.net.wifi.RttManager.WifiInformationElement LCI;
+    field @Deprecated public android.net.wifi.RttManager.WifiInformationElement LCR;
+    field @Deprecated public String bssid;
+    field @Deprecated public int burstDuration;
+    field @Deprecated public int burstNumber;
+    field @Deprecated public int distance;
+    field @Deprecated public int distanceSpread;
+    field @Deprecated public int distanceStandardDeviation;
+    field @Deprecated public int distance_cm;
+    field @Deprecated public int distance_sd_cm;
+    field @Deprecated public int distance_spread_cm;
+    field @Deprecated public int frameNumberPerBurstPeer;
+    field @Deprecated public int measurementFrameNumber;
+    field @Deprecated public int measurementType;
+    field @Deprecated public int negotiatedBurstNum;
+    field @Deprecated public int requestType;
+    field @Deprecated public int retryAfterDuration;
+    field @Deprecated public int rssi;
+    field @Deprecated public int rssiSpread;
+    field @Deprecated public int rssi_spread;
+    field @Deprecated public long rtt;
+    field @Deprecated public long rttSpread;
+    field @Deprecated public long rttStandardDeviation;
+    field @Deprecated public long rtt_ns;
+    field @Deprecated public long rtt_sd_ns;
+    field @Deprecated public long rtt_spread_ns;
+    field @Deprecated public int rxRate;
+    field @Deprecated public boolean secure;
+    field @Deprecated public int status;
+    field @Deprecated public int successMeasurementFrameNumber;
+    field @Deprecated public long ts;
+    field @Deprecated public int txRate;
+    field @Deprecated public int tx_rate;
   }
 
-  public static deprecated class RttManager.WifiInformationElement {
-    ctor public RttManager.WifiInformationElement();
-    field public byte[] data;
-    field public byte id;
+  @Deprecated public static class RttManager.WifiInformationElement {
+    ctor @Deprecated public RttManager.WifiInformationElement();
+    field @Deprecated public byte[] data;
+    field @Deprecated public byte id;
   }
 
-  public deprecated class WifiConfiguration implements android.os.Parcelable {
-    method public boolean hasNoInternetAccess();
-    method public boolean isEphemeral();
-    method public boolean isNoInternetAccessExpected();
-    field public java.lang.String creatorName;
-    field public int creatorUid;
-    field public java.lang.String lastUpdateName;
-    field public int lastUpdateUid;
-    field public boolean meteredHint;
-    field public int numAssociation;
-    field public int numScorerOverride;
-    field public int numScorerOverrideAndSwitchedNetwork;
-    field public boolean useExternalScores;
+  @Deprecated public class WifiConfiguration implements android.os.Parcelable {
+    method @Deprecated public boolean hasNoInternetAccess();
+    method @Deprecated public boolean isEphemeral();
+    method @Deprecated public boolean isNoInternetAccessExpected();
+    field @Deprecated public String creatorName;
+    field @Deprecated public int creatorUid;
+    field @Deprecated public String lastUpdateName;
+    field @Deprecated public int lastUpdateUid;
+    field @Deprecated public boolean meteredHint;
+    field @Deprecated public int numAssociation;
+    field @Deprecated public int numScorerOverride;
+    field @Deprecated public int numScorerOverrideAndSwitchedNetwork;
+    field @Deprecated public boolean useExternalScores;
   }
 
-  public static class WifiConfiguration.KeyMgmt {
-    field public static final int WPA2_PSK = 4; // 0x4
+  @Deprecated public static class WifiConfiguration.KeyMgmt {
+    field @Deprecated public static final int WPA2_PSK = 4; // 0x4
+  }
+
+  public class WifiInfo implements android.os.Parcelable {
+    method public boolean isOsuAp();
   }
 
   public class WifiManager {
-    method public void connect(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
-    method public void connect(int, android.net.wifi.WifiManager.ActionListener);
-    method public void disable(int, android.net.wifi.WifiManager.ActionListener);
-    method public void disableEphemeralNetwork(java.lang.String);
-    method public void forget(int, android.net.wifi.WifiManager.ActionListener);
-    method public java.util.List<android.net.wifi.WifiConfiguration> getAllMatchingWifiConfigs(java.util.List<android.net.wifi.ScanResult>);
-    method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
-    method public android.net.wifi.WifiConfiguration getWifiApConfiguration();
-    method public int getWifiApState();
+    method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void addWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiUsabilityStatsListener);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void connect(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void connect(int, android.net.wifi.WifiManager.ActionListener);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void disable(int, android.net.wifi.WifiManager.ActionListener);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void forget(int, android.net.wifi.WifiManager.ActionListener);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(java.util.List<android.net.wifi.ScanResult>);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
+    method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
+    method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
+    method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
     method public boolean isDeviceToDeviceRttSupported();
     method public boolean isPortableHotspotSupported();
-    method public boolean isWifiApEnabled();
+    method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
     method public boolean isWifiScannerSupported();
-    method public void registerNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback, android.os.Handler);
-    method public void save(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
-    method public void setDeviceMobilityState(int);
-    method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
-    method public void startDppAsConfiguratorInitiator(java.lang.String, int, int, android.os.Handler, android.net.wifi.DppStatusCallback);
-    method public void startDppAsEnrolleeInitiator(java.lang.String, android.os.Handler, android.net.wifi.DppStatusCallback);
-    method public boolean startScan(android.os.WorkSource);
-    method public void stopDppSession();
-    method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback);
+    method @RequiresPermission("android.permission.NETWORK_SETTINGS") public void registerNetworkRequestMatchCallback(@NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback, @Nullable android.os.Handler);
+    method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.WifiUsabilityStatsListener);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void save(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
+    method @RequiresPermission("android.permission.WIFI_SET_DEVICE_MOBILITY_STATE") public void setDeviceMobilityState(int);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(android.os.WorkSource);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(android.net.wifi.hotspot2.OsuProvider, android.net.wifi.hotspot2.ProvisioningCallback, @Nullable android.os.Handler);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession();
+    method @RequiresPermission("android.permission.NETWORK_SETTINGS") public void unregisterNetworkRequestMatchCallback(@NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
     field public static final int CHANGE_REASON_ADDED = 0; // 0x0
     field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
     field public static final int CHANGE_REASON_REMOVED = 1; // 0x1
-    field public static final java.lang.String CONFIGURED_NETWORKS_CHANGED_ACTION = "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
+    field public static final String CONFIGURED_NETWORKS_CHANGED_ACTION = "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
     field public static final int DEVICE_MOBILITY_STATE_HIGH_MVMT = 1; // 0x1
     field public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2; // 0x2
     field public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3; // 0x3
     field public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0; // 0x0
-    field public static final int DPP_NETWORK_ROLE_AP = 1; // 0x1
-    field public static final int DPP_NETWORK_ROLE_STA = 0; // 0x0
-    field public static final java.lang.String EXTRA_CHANGE_REASON = "changeReason";
-    field public static final java.lang.String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
-    field public static final java.lang.String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
-    field public static final java.lang.String EXTRA_WIFI_AP_STATE = "wifi_state";
-    field public static final java.lang.String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
-    field public static final java.lang.String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
-    field public static final java.lang.String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
-    field public static final java.lang.String WIFI_AP_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_AP_STATE_CHANGED";
+    field public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1; // 0x1
+    field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
+    field public static final String EXTRA_CHANGE_REASON = "changeReason";
+    field public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
+    field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
+    field public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
+    field public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
+    field public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
+    field public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
+    field public static final int PASSPOINT_HOME_NETWORK = 0; // 0x0
+    field public static final int PASSPOINT_ROAMING_NETWORK = 1; // 0x1
+    field public static final String WIFI_AP_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_AP_STATE_CHANGED";
     field public static final int WIFI_AP_STATE_DISABLED = 11; // 0xb
     field public static final int WIFI_AP_STATE_DISABLING = 10; // 0xa
     field public static final int WIFI_AP_STATE_ENABLED = 13; // 0xd
     field public static final int WIFI_AP_STATE_ENABLING = 12; // 0xc
     field public static final int WIFI_AP_STATE_FAILED = 14; // 0xe
-    field public static final java.lang.String WIFI_CREDENTIAL_CHANGED_ACTION = "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
+    field public static final String WIFI_CREDENTIAL_CHANGED_ACTION = "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
     field public static final int WIFI_CREDENTIAL_FORGOT = 1; // 0x1
     field public static final int WIFI_CREDENTIAL_SAVED = 0; // 0x0
   }
 
-  public static abstract interface WifiManager.ActionListener {
-    method public abstract void onFailure(int);
-    method public abstract void onSuccess();
+  public static interface WifiManager.ActionListener {
+    method public void onFailure(int);
+    method public void onSuccess();
   }
 
-  public static abstract interface WifiManager.NetworkRequestMatchCallback {
-    method public abstract void onAbort();
-    method public abstract void onMatch(java.util.List<android.net.wifi.ScanResult>);
-    method public abstract void onUserSelectionCallbackRegistration(android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback);
-    method public abstract void onUserSelectionConnectFailure(android.net.wifi.WifiConfiguration);
-    method public abstract void onUserSelectionConnectSuccess(android.net.wifi.WifiConfiguration);
+  public static interface WifiManager.NetworkRequestMatchCallback {
+    method public void onAbort();
+    method public void onMatch(@NonNull java.util.List<android.net.wifi.ScanResult>);
+    method public void onUserSelectionCallbackRegistration(@NonNull android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback);
+    method public void onUserSelectionConnectFailure(@NonNull android.net.wifi.WifiConfiguration);
+    method public void onUserSelectionConnectSuccess(@NonNull android.net.wifi.WifiConfiguration);
   }
 
-  public static abstract interface WifiManager.NetworkRequestUserSelectionCallback {
-    method public abstract void reject();
-    method public abstract void select(android.net.wifi.WifiConfiguration);
+  public static interface WifiManager.NetworkRequestUserSelectionCallback {
+    method public void reject();
+    method public void select(@NonNull android.net.wifi.WifiConfiguration);
+  }
+
+  public static interface WifiManager.WifiUsabilityStatsListener {
+    method public void onStatsUpdated(int, boolean, android.net.wifi.WifiUsabilityStatsEntry);
   }
 
   public class WifiNetworkConnectionStatistics implements android.os.Parcelable {
@@ -4030,19 +4727,19 @@
   }
 
   public class WifiScanner {
-    method public deprecated void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.BssidInfo[]);
-    method public deprecated void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
-    method public boolean getScanResults();
-    method public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
-    method public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
-    method public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
-    method public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
-    method public deprecated void startTrackingBssids(android.net.wifi.WifiScanner.BssidInfo[], int, android.net.wifi.WifiScanner.BssidListener);
-    method public deprecated void startTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
-    method public void stopBackgroundScan(android.net.wifi.WifiScanner.ScanListener);
-    method public void stopScan(android.net.wifi.WifiScanner.ScanListener);
-    method public deprecated void stopTrackingBssids(android.net.wifi.WifiScanner.BssidListener);
-    method public deprecated void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
+    method @Deprecated public void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.BssidInfo[]);
+    method @Deprecated public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean getScanResults();
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
+    method @Deprecated public void startTrackingBssids(android.net.wifi.WifiScanner.BssidInfo[], int, android.net.wifi.WifiScanner.BssidListener);
+    method @Deprecated public void startTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void stopBackgroundScan(android.net.wifi.WifiScanner.ScanListener);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void stopScan(android.net.wifi.WifiScanner.ScanListener);
+    method @Deprecated public void stopTrackingBssids(android.net.wifi.WifiScanner.BssidListener);
+    method @Deprecated public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
     field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
     field public static final int MIN_SCAN_PERIOD_MS = 1000; // 0x3e8
     field public static final int REASON_DUPLICATE_REQEUST = -5; // 0xfffffffb
@@ -4051,7 +4748,7 @@
     field public static final int REASON_NOT_AUTHORIZED = -4; // 0xfffffffc
     field public static final int REASON_SUCCEEDED = 0; // 0x0
     field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
-    field public static final deprecated int REPORT_EVENT_AFTER_BUFFER_FULL = 0; // 0x0
+    field @Deprecated public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0; // 0x0
     field public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1; // 0x1
     field public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2; // 0x2
     field public static final int REPORT_EVENT_NO_BATCH = 4; // 0x4
@@ -4064,22 +4761,22 @@
     field public static final int WIFI_BAND_UNSPECIFIED = 0; // 0x0
   }
 
-  public static abstract interface WifiScanner.ActionListener {
-    method public abstract void onFailure(int, java.lang.String);
-    method public abstract void onSuccess();
+  public static interface WifiScanner.ActionListener {
+    method public void onFailure(int, String);
+    method public void onSuccess();
   }
 
-  public static deprecated class WifiScanner.BssidInfo {
-    ctor public WifiScanner.BssidInfo();
-    field public java.lang.String bssid;
-    field public int frequencyHint;
-    field public int high;
-    field public int low;
+  @Deprecated public static class WifiScanner.BssidInfo {
+    ctor @Deprecated public WifiScanner.BssidInfo();
+    field @Deprecated public String bssid;
+    field @Deprecated public int frequencyHint;
+    field @Deprecated public int high;
+    field @Deprecated public int low;
   }
 
-  public static abstract deprecated interface WifiScanner.BssidListener implements android.net.wifi.WifiScanner.ActionListener {
-    method public abstract void onFound(android.net.wifi.ScanResult[]);
-    method public abstract void onLost(android.net.wifi.ScanResult[]);
+  @Deprecated public static interface WifiScanner.BssidListener extends android.net.wifi.WifiScanner.ActionListener {
+    method @Deprecated public void onFound(android.net.wifi.ScanResult[]);
+    method @Deprecated public void onLost(android.net.wifi.ScanResult[]);
   }
 
   public static class WifiScanner.ChannelSpec {
@@ -4087,10 +4784,10 @@
     field public int frequency;
   }
 
-  public static deprecated class WifiScanner.HotlistSettings implements android.os.Parcelable {
-    ctor public WifiScanner.HotlistSettings();
-    field public int apLostThreshold;
-    field public android.net.wifi.WifiScanner.BssidInfo[] bssidInfos;
+  @Deprecated public static class WifiScanner.HotlistSettings implements android.os.Parcelable {
+    ctor @Deprecated public WifiScanner.HotlistSettings();
+    field @Deprecated public int apLostThreshold;
+    field @Deprecated public android.net.wifi.WifiScanner.BssidInfo[] bssidInfos;
   }
 
   public static class WifiScanner.ParcelableScanData implements android.os.Parcelable {
@@ -4113,17 +4810,17 @@
     method public android.net.wifi.ScanResult[] getResults();
   }
 
-  public static abstract interface WifiScanner.ScanListener implements android.net.wifi.WifiScanner.ActionListener {
-    method public abstract void onFullResult(android.net.wifi.ScanResult);
-    method public abstract void onPeriodChanged(int);
-    method public abstract void onResults(android.net.wifi.WifiScanner.ScanData[]);
+  public static interface WifiScanner.ScanListener extends android.net.wifi.WifiScanner.ActionListener {
+    method public void onFullResult(android.net.wifi.ScanResult);
+    method public void onPeriodChanged(int);
+    method public void onResults(android.net.wifi.WifiScanner.ScanData[]);
   }
 
   public static class WifiScanner.ScanSettings implements android.os.Parcelable {
     ctor public WifiScanner.ScanSettings();
     field public int band;
     field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
-    field public boolean ignoreLocationSettings;
+    field @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean ignoreLocationSettings;
     field public int maxPeriodInMs;
     field public int maxScansToCache;
     field public int numBssidsPerScan;
@@ -4132,19 +4829,44 @@
     field public int stepCount;
   }
 
-  public static abstract deprecated interface WifiScanner.WifiChangeListener implements android.net.wifi.WifiScanner.ActionListener {
-    method public abstract void onChanging(android.net.wifi.ScanResult[]);
-    method public abstract void onQuiescence(android.net.wifi.ScanResult[]);
+  @Deprecated public static interface WifiScanner.WifiChangeListener extends android.net.wifi.WifiScanner.ActionListener {
+    method @Deprecated public void onChanging(android.net.wifi.ScanResult[]);
+    method @Deprecated public void onQuiescence(android.net.wifi.ScanResult[]);
   }
 
-  public static deprecated class WifiScanner.WifiChangeSettings implements android.os.Parcelable {
-    ctor public WifiScanner.WifiChangeSettings();
-    field public android.net.wifi.WifiScanner.BssidInfo[] bssidInfos;
-    field public int lostApSampleSize;
-    field public int minApsBreachingThreshold;
-    field public int periodInMs;
-    field public int rssiSampleSize;
-    field public int unchangedSampleSize;
+  @Deprecated public static class WifiScanner.WifiChangeSettings implements android.os.Parcelable {
+    ctor @Deprecated public WifiScanner.WifiChangeSettings();
+    field @Deprecated public android.net.wifi.WifiScanner.BssidInfo[] bssidInfos;
+    field @Deprecated public int lostApSampleSize;
+    field @Deprecated public int minApsBreachingThreshold;
+    field @Deprecated public int periodInMs;
+    field @Deprecated public int rssiSampleSize;
+    field @Deprecated public int unchangedSampleSize;
+  }
+
+  public final class WifiUsabilityStatsEntry implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.WifiUsabilityStatsEntry> CREATOR;
+    field public final int linkSpeedMbps;
+    field public final int rssi;
+    field public final long timeStampMs;
+    field public final long totalBackgroundScanTimeMs;
+    field public final long totalBeaconRx;
+    field public final long totalCcaBusyFreqTimeMs;
+    field public final long totalHotspot2ScanTimeMs;
+    field public final long totalNanScanTimeMs;
+    field public final long totalPnoScanTimeMs;
+    field public final long totalRadioOnFreqTimeMs;
+    field public final long totalRadioOnTimeMs;
+    field public final long totalRadioRxTimeMs;
+    field public final long totalRadioTxTimeMs;
+    field public final long totalRoamScanTimeMs;
+    field public final long totalRxSuccess;
+    field public final long totalScanTimeMs;
+    field public final long totalTxBad;
+    field public final long totalTxRetries;
+    field public final long totalTxSuccess;
   }
 
 }
@@ -4152,15 +4874,68 @@
 package android.net.wifi.aware {
 
   public class DiscoverySession implements java.lang.AutoCloseable {
-    method public deprecated android.net.NetworkSpecifier createNetworkSpecifierPmk(android.net.wifi.aware.PeerHandle, byte[]);
+    method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierPmk(@NonNull android.net.wifi.aware.PeerHandle, @NonNull byte[]);
   }
 
   public static class WifiAwareManager.NetworkSpecifierBuilder {
-    method public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPmk(byte[]);
+    method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPmk(@NonNull byte[]);
   }
 
   public class WifiAwareSession implements java.lang.AutoCloseable {
-    method public android.net.NetworkSpecifier createNetworkSpecifierPmk(int, byte[], byte[]);
+    method public android.net.NetworkSpecifier createNetworkSpecifierPmk(int, @NonNull byte[], @NonNull byte[]);
+  }
+
+}
+
+package android.net.wifi.hotspot2 {
+
+  public final class OsuProvider implements android.os.Parcelable {
+    method public int describeContents();
+    method public String getFriendlyName();
+    method public android.net.Uri getServerUri();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.OsuProvider> CREATOR;
+  }
+
+  public abstract class ProvisioningCallback {
+    ctor public ProvisioningCallback();
+    method public abstract void onProvisioningComplete();
+    method public abstract void onProvisioningFailure(int);
+    method public abstract void onProvisioningStatus(int);
+    field public static final int OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION = 22; // 0x16
+    field public static final int OSU_FAILURE_AP_CONNECTION = 1; // 0x1
+    field public static final int OSU_FAILURE_INVALID_URL_FORMAT_FOR_OSU = 8; // 0x8
+    field public static final int OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE = 17; // 0x11
+    field public static final int OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE = 21; // 0x15
+    field public static final int OSU_FAILURE_NO_OSU_ACTIVITY_FOUND = 14; // 0xe
+    field public static final int OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE = 19; // 0x13
+    field public static final int OSU_FAILURE_NO_PPS_MO = 16; // 0x10
+    field public static final int OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE = 18; // 0x12
+    field public static final int OSU_FAILURE_OSU_PROVIDER_NOT_FOUND = 23; // 0x17
+    field public static final int OSU_FAILURE_PROVISIONING_ABORTED = 6; // 0x6
+    field public static final int OSU_FAILURE_PROVISIONING_NOT_AVAILABLE = 7; // 0x7
+    field public static final int OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES = 20; // 0x14
+    field public static final int OSU_FAILURE_SERVER_CONNECTION = 3; // 0x3
+    field public static final int OSU_FAILURE_SERVER_URL_INVALID = 2; // 0x2
+    field public static final int OSU_FAILURE_SERVER_VALIDATION = 4; // 0x4
+    field public static final int OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION = 5; // 0x5
+    field public static final int OSU_FAILURE_SOAP_MESSAGE_EXCHANGE = 11; // 0xb
+    field public static final int OSU_FAILURE_START_REDIRECT_LISTENER = 12; // 0xc
+    field public static final int OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER = 13; // 0xd
+    field public static final int OSU_FAILURE_UNEXPECTED_COMMAND_TYPE = 9; // 0x9
+    field public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS = 15; // 0xf
+    field public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE = 10; // 0xa
+    field public static final int OSU_STATUS_AP_CONNECTED = 2; // 0x2
+    field public static final int OSU_STATUS_AP_CONNECTING = 1; // 0x1
+    field public static final int OSU_STATUS_INIT_SOAP_EXCHANGE = 6; // 0x6
+    field public static final int OSU_STATUS_REDIRECT_RESPONSE_RECEIVED = 8; // 0x8
+    field public static final int OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS = 11; // 0xb
+    field public static final int OSU_STATUS_SECOND_SOAP_EXCHANGE = 9; // 0x9
+    field public static final int OSU_STATUS_SERVER_CONNECTED = 5; // 0x5
+    field public static final int OSU_STATUS_SERVER_CONNECTING = 3; // 0x3
+    field public static final int OSU_STATUS_SERVER_VALIDATED = 4; // 0x4
+    field public static final int OSU_STATUS_THIRD_SOAP_EXCHANGE = 10; // 0xa
+    field public static final int OSU_STATUS_WAITING_FOR_REDIRECT_RESPONSE = 7; // 0x7
   }
 
 }
@@ -4168,17 +4943,17 @@
 package android.net.wifi.rtt {
 
   public static final class RangingRequest.Builder {
-    method public android.net.wifi.rtt.RangingRequest.Builder addResponder(android.net.wifi.rtt.ResponderConfig);
+    method public android.net.wifi.rtt.RangingRequest.Builder addResponder(@NonNull android.net.wifi.rtt.ResponderConfig);
   }
 
   public final class RangingResult implements android.os.Parcelable {
-    method public byte[] getLci();
-    method public byte[] getLcr();
+    method @NonNull public byte[] getLci();
+    method @NonNull public byte[] getLcr();
   }
 
   public final class ResponderConfig implements android.os.Parcelable {
-    ctor public ResponderConfig(android.net.MacAddress, int, boolean, int, int, int, int, int);
-    ctor public ResponderConfig(android.net.wifi.aware.PeerHandle, int, boolean, int, int, int, int, int);
+    ctor public ResponderConfig(@NonNull android.net.MacAddress, int, boolean, int, int, int, int, int);
+    ctor public ResponderConfig(@NonNull android.net.wifi.aware.PeerHandle, int, boolean, int, int, int, int, int);
     method public int describeContents();
     method public static android.net.wifi.rtt.ResponderConfig fromScanResult(android.net.wifi.ScanResult);
     method public static android.net.wifi.rtt.ResponderConfig fromWifiAwarePeerHandleWithDefaults(android.net.wifi.aware.PeerHandle);
@@ -4210,8 +4985,8 @@
   }
 
   public class WifiRttManager {
-    method public void cancelRanging(android.os.WorkSource);
-    method public void startRanging(android.os.WorkSource, android.net.wifi.rtt.RangingRequest, java.util.concurrent.Executor, android.net.wifi.rtt.RangingResultCallback);
+    method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE}) public void cancelRanging(@Nullable android.os.WorkSource);
+    method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.ACCESS_WIFI_STATE}) public void startRanging(@Nullable android.os.WorkSource, @NonNull android.net.wifi.rtt.RangingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.rtt.RangingResultCallback);
   }
 
 }
@@ -4219,19 +4994,19 @@
 package android.nfc {
 
   public final class NfcAdapter {
-    method public boolean addNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler, java.lang.String[]);
-    method public boolean disable();
-    method public boolean disable(boolean);
-    method public boolean disableNdefPush();
-    method public boolean enable();
-    method public boolean enableNdefPush();
-    method public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean addNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler, String[]);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable();
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disableNdefPush();
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
     method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
     field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
   }
 
-  public static abstract interface NfcAdapter.NfcUnlockHandler {
-    method public abstract boolean onUnlockAttempted(android.nfc.Tag);
+  public static interface NfcAdapter.NfcUnlockHandler {
+    method public boolean onUnlockAttempted(android.nfc.Tag);
   }
 
 }
@@ -4239,8 +5014,8 @@
 package android.os {
 
   public class BatteryManager {
-    field public static final java.lang.String EXTRA_EVENTS = "android.os.extra.EVENTS";
-    field public static final java.lang.String EXTRA_EVENT_TIMESTAMP = "android.os.extra.EVENT_TIMESTAMP";
+    field public static final String EXTRA_EVENTS = "android.os.extra.EVENTS";
+    field public static final String EXTRA_EVENT_TIMESTAMP = "android.os.extra.EVENT_TIMESTAMP";
   }
 
   public class Binder implements android.os.IBinder {
@@ -4248,25 +5023,29 @@
     method public static final int getCallingWorkSourceUid();
     method public static final void restoreCallingWorkSource(long);
     method public static final long setCallingWorkSourceUid(int);
-    method public static void setProxyTransactListener(android.os.Binder.ProxyTransactListener);
+    method public static void setProxyTransactListener(@Nullable android.os.Binder.ProxyTransactListener);
   }
 
-  public static abstract interface Binder.ProxyTransactListener {
-    method public abstract void onTransactEnded(java.lang.Object);
-    method public abstract java.lang.Object onTransactStarted(android.os.IBinder, int);
+  public static interface Binder.ProxyTransactListener {
+    method public void onTransactEnded(@Nullable Object);
+    method public Object onTransactStarted(android.os.IBinder, int);
+  }
+
+  public static class Build.VERSION {
+    field public static final String PREVIEW_SDK_FINGERPRINT;
   }
 
   public final class ConfigUpdate {
-    field public static final java.lang.String ACTION_UPDATE_CARRIER_ID_DB = "android.os.action.UPDATE_CARRIER_ID_DB";
-    field public static final java.lang.String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
-    field public static final java.lang.String ACTION_UPDATE_CONVERSATION_ACTIONS = "android.intent.action.UPDATE_CONVERSATION_ACTIONS";
-    field public static final java.lang.String ACTION_UPDATE_CT_LOGS = "android.intent.action.UPDATE_CT_LOGS";
-    field public static final java.lang.String ACTION_UPDATE_INTENT_FIREWALL = "android.intent.action.UPDATE_INTENT_FIREWALL";
-    field public static final java.lang.String ACTION_UPDATE_LANG_ID = "android.intent.action.UPDATE_LANG_ID";
-    field public static final java.lang.String ACTION_UPDATE_NETWORK_WATCHLIST = "android.intent.action.UPDATE_NETWORK_WATCHLIST";
-    field public static final java.lang.String ACTION_UPDATE_PINS = "android.intent.action.UPDATE_PINS";
-    field public static final java.lang.String ACTION_UPDATE_SMART_SELECTION = "android.intent.action.UPDATE_SMART_SELECTION";
-    field public static final java.lang.String ACTION_UPDATE_SMS_SHORT_CODES = "android.intent.action.UPDATE_SMS_SHORT_CODES";
+    field public static final String ACTION_UPDATE_CARRIER_ID_DB = "android.os.action.UPDATE_CARRIER_ID_DB";
+    field public static final String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
+    field public static final String ACTION_UPDATE_CONVERSATION_ACTIONS = "android.intent.action.UPDATE_CONVERSATION_ACTIONS";
+    field public static final String ACTION_UPDATE_CT_LOGS = "android.intent.action.UPDATE_CT_LOGS";
+    field public static final String ACTION_UPDATE_INTENT_FIREWALL = "android.intent.action.UPDATE_INTENT_FIREWALL";
+    field public static final String ACTION_UPDATE_LANG_ID = "android.intent.action.UPDATE_LANG_ID";
+    field public static final String ACTION_UPDATE_NETWORK_WATCHLIST = "android.intent.action.UPDATE_NETWORK_WATCHLIST";
+    field public static final String ACTION_UPDATE_PINS = "android.intent.action.UPDATE_PINS";
+    field public static final String ACTION_UPDATE_SMART_SELECTION = "android.intent.action.UPDATE_SMART_SELECTION";
+    field public static final String ACTION_UPDATE_SMS_SHORT_CODES = "android.intent.action.UPDATE_SMS_SHORT_CODES";
   }
 
   public class Environment {
@@ -4278,21 +5057,21 @@
   }
 
   public class HidlSupport {
-    method public static boolean deepEquals(java.lang.Object, java.lang.Object);
-    method public static int deepHashCode(java.lang.Object);
+    method public static boolean deepEquals(Object, Object);
+    method public static int deepHashCode(Object);
     method public static int getPidIfSharable();
-    method public static boolean interfacesEqual(android.os.IHwInterface, java.lang.Object);
+    method public static boolean interfacesEqual(android.os.IHwInterface, Object);
   }
 
   public abstract class HwBinder implements android.os.IHwBinder {
     ctor public HwBinder();
     method public static final void configureRpcThreadpool(long, boolean);
     method public static void enableInstrumentation();
-    method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String) throws java.util.NoSuchElementException, android.os.RemoteException;
-    method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String, boolean) throws java.util.NoSuchElementException, android.os.RemoteException;
+    method public static final android.os.IHwBinder getService(String, String) throws java.util.NoSuchElementException, android.os.RemoteException;
+    method public static final android.os.IHwBinder getService(String, String, boolean) throws java.util.NoSuchElementException, android.os.RemoteException;
     method public static final void joinRpcThreadpool();
     method public abstract void onTransact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
-    method public final void registerService(java.lang.String) throws android.os.RemoteException;
+    method public final void registerService(String) throws android.os.RemoteException;
     method public final void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
   }
 
@@ -4312,7 +5091,7 @@
     method public final int getInt32(long);
     method public final long getInt64(long);
     method public final byte getInt8(long);
-    method public final java.lang.String getString(long);
+    method public final String getString(long);
     method public final long handle();
     method public final void putBlob(long, android.os.HwBlob);
     method public final void putBool(long, boolean);
@@ -4330,19 +5109,19 @@
     method public final void putInt8(long, byte);
     method public final void putInt8Array(long, byte[]);
     method public final void putNativeHandle(long, android.os.NativeHandle);
-    method public final void putString(long, java.lang.String);
-    method public static java.lang.Boolean[] wrapArray(boolean[]);
-    method public static java.lang.Long[] wrapArray(long[]);
-    method public static java.lang.Byte[] wrapArray(byte[]);
-    method public static java.lang.Short[] wrapArray(short[]);
-    method public static java.lang.Integer[] wrapArray(int[]);
-    method public static java.lang.Float[] wrapArray(float[]);
-    method public static java.lang.Double[] wrapArray(double[]);
+    method public final void putString(long, String);
+    method public static Boolean[] wrapArray(@NonNull boolean[]);
+    method public static Long[] wrapArray(@NonNull long[]);
+    method public static Byte[] wrapArray(@NonNull byte[]);
+    method public static Short[] wrapArray(@NonNull short[]);
+    method public static Integer[] wrapArray(@NonNull int[]);
+    method public static Float[] wrapArray(@NonNull float[]);
+    method public static Double[] wrapArray(@NonNull double[]);
   }
 
   public class HwParcel {
     ctor public HwParcel();
-    method public final void enforceInterface(java.lang.String);
+    method public final void enforceInterface(String);
     method public final boolean readBool();
     method public final java.util.ArrayList<java.lang.Boolean> readBoolVector();
     method public final android.os.HwBlob readBuffer(long);
@@ -4362,7 +5141,7 @@
     method public final java.util.ArrayList<java.lang.Byte> readInt8Vector();
     method public final android.os.NativeHandle readNativeHandle();
     method public final java.util.ArrayList<android.os.NativeHandle> readNativeHandleVector();
-    method public final java.lang.String readString();
+    method public final String readString();
     method public final java.util.ArrayList<java.lang.String> readStringVector();
     method public final android.os.IHwBinder readStrongBinder();
     method public final void release();
@@ -4384,36 +5163,36 @@
     method public final void writeInt64Vector(java.util.ArrayList<java.lang.Long>);
     method public final void writeInt8(byte);
     method public final void writeInt8Vector(java.util.ArrayList<java.lang.Byte>);
-    method public final void writeInterfaceToken(java.lang.String);
+    method public final void writeInterfaceToken(String);
     method public final void writeNativeHandle(android.os.NativeHandle);
     method public final void writeNativeHandleVector(java.util.ArrayList<android.os.NativeHandle>);
     method public final void writeStatus(int);
-    method public final void writeString(java.lang.String);
+    method public final void writeString(String);
     method public final void writeStringVector(java.util.ArrayList<java.lang.String>);
     method public final void writeStrongBinder(android.os.IHwBinder);
     field public static final int STATUS_SUCCESS = 0; // 0x0
   }
 
-  public static abstract class HwParcel.Status implements java.lang.annotation.Annotation {
+  @IntDef(prefix={"STATUS_"}, value={android.os.HwParcel.STATUS_SUCCESS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface HwParcel.Status {
   }
 
-  public abstract interface IHwBinder {
-    method public abstract boolean linkToDeath(android.os.IHwBinder.DeathRecipient, long);
-    method public abstract android.os.IHwInterface queryLocalInterface(java.lang.String);
-    method public abstract void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
-    method public abstract boolean unlinkToDeath(android.os.IHwBinder.DeathRecipient);
+  public interface IHwBinder {
+    method public boolean linkToDeath(android.os.IHwBinder.DeathRecipient, long);
+    method public android.os.IHwInterface queryLocalInterface(String);
+    method public void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
+    method public boolean unlinkToDeath(android.os.IHwBinder.DeathRecipient);
   }
 
-  public static abstract interface IHwBinder.DeathRecipient {
-    method public abstract void serviceDied(long);
+  public static interface IHwBinder.DeathRecipient {
+    method public void serviceDied(long);
   }
 
-  public abstract interface IHwInterface {
-    method public abstract android.os.IHwBinder asBinder();
+  public interface IHwInterface {
+    method public android.os.IHwBinder asBinder();
   }
 
   public class IncidentManager {
-    method public void reportIncident(android.os.IncidentReportArgs);
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void reportIncident(android.os.IncidentReportArgs);
   }
 
   public final class IncidentReportArgs implements android.os.Parcelable {
@@ -4434,8 +5213,8 @@
 
   public final class NativeHandle implements java.io.Closeable {
     ctor public NativeHandle();
-    ctor public NativeHandle(java.io.FileDescriptor, boolean);
-    ctor public NativeHandle(java.io.FileDescriptor[], int[], boolean);
+    ctor public NativeHandle(@NonNull java.io.FileDescriptor, boolean);
+    ctor public NativeHandle(@NonNull java.io.FileDescriptor[], @NonNull int[], boolean);
     method public void close() throws java.io.IOException;
     method public android.os.NativeHandle dup() throws java.io.IOException;
     method public java.io.FileDescriptor getFileDescriptor();
@@ -4445,11 +5224,11 @@
   }
 
   public final class PowerManager {
-    method public void dream(long);
-    method public int getPowerSaveMode();
-    method public boolean setDynamicPowerSavings(boolean, int);
-    method public boolean setPowerSaveMode(boolean);
-    method public void userActivity(long, int, int);
+    method @RequiresPermission(allOf={android.Manifest.permission.READ_DREAM_STATE, android.Manifest.permission.WRITE_DREAM_STATE}) public void dream(long);
+    method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public int getPowerSaveMode();
+    method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setDynamicPowerSavings(boolean, int);
+    method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveMode(boolean);
+    method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.USER_ACTIVITY}) public void userActivity(long, int, int);
     field public static final int POWER_SAVER_MODE_DYNAMIC = 1; // 0x1
     field public static final int POWER_SAVER_MODE_PERCENTAGE = 0; // 0x0
     field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
@@ -4461,26 +5240,32 @@
   }
 
   public class RecoverySystem {
-    method public static void cancelScheduledUpdate(android.content.Context) throws java.io.IOException;
-    method public static void installPackage(android.content.Context, java.io.File, boolean) throws java.io.IOException;
-    method public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener, android.os.Handler) throws java.io.IOException;
-    method public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener) throws java.io.IOException;
-    method public static void rebootWipeAb(android.content.Context, java.io.File, java.lang.String) throws java.io.IOException;
-    method public static void scheduleUpdateOnBoot(android.content.Context, java.io.File) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void cancelScheduledUpdate(android.content.Context) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void installPackage(android.content.Context, java.io.File, boolean) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener, android.os.Handler) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener) throws java.io.IOException;
+    method @RequiresPermission(allOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static void rebootWipeAb(android.content.Context, java.io.File, String) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void scheduleUpdateOnBoot(android.content.Context, java.io.File) throws java.io.IOException;
     method public static boolean verifyPackageCompatibility(java.io.File) throws java.io.IOException;
   }
 
   public final class RemoteCallback implements android.os.Parcelable {
     ctor public RemoteCallback(android.os.RemoteCallback.OnResultListener);
-    ctor public RemoteCallback(android.os.RemoteCallback.OnResultListener, android.os.Handler);
+    ctor public RemoteCallback(@NonNull android.os.RemoteCallback.OnResultListener, @Nullable android.os.Handler);
     method public int describeContents();
-    method public void sendResult(android.os.Bundle);
+    method public void sendResult(@Nullable android.os.Bundle);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.RemoteCallback> CREATOR;
   }
 
-  public static abstract interface RemoteCallback.OnResultListener {
-    method public abstract void onResult(android.os.Bundle);
+  public static interface RemoteCallback.OnResultListener {
+    method public void onResult(android.os.Bundle);
+  }
+
+  public class ServiceSpecificException extends java.lang.RuntimeException {
+    ctor public ServiceSpecificException(int, String);
+    ctor public ServiceSpecificException(int);
+    field public final int errorCode;
   }
 
   public final class StatsDimensionsValue implements android.os.Parcelable {
@@ -4490,7 +5275,7 @@
     method public float getFloatValue();
     method public int getIntValue();
     method public long getLongValue();
-    method public java.lang.String getStringValue();
+    method public String getStringValue();
     method public java.util.List<android.os.StatsDimensionsValue> getTupleValueList();
     method public int getValueType();
     method public boolean isValueType(int);
@@ -4505,21 +5290,21 @@
   }
 
   public class SystemProperties {
-    method public static java.lang.String get(java.lang.String);
-    method public static java.lang.String get(java.lang.String, java.lang.String);
-    method public static boolean getBoolean(java.lang.String, boolean);
-    method public static int getInt(java.lang.String, int);
-    method public static long getLong(java.lang.String, long);
+    method @NonNull public static String get(@NonNull String);
+    method @NonNull public static String get(@NonNull String, @Nullable String);
+    method public static boolean getBoolean(@NonNull String, boolean);
+    method public static int getInt(@NonNull String, int);
+    method public static long getLong(@NonNull String, long);
   }
 
   public class SystemUpdateManager {
-    method public android.os.Bundle retrieveSystemUpdateInfo();
-    method public void updateSystemUpdateInfo(android.os.PersistableBundle);
-    field public static final java.lang.String KEY_IS_SECURITY_UPDATE = "is_security_update";
-    field public static final java.lang.String KEY_STATUS = "status";
-    field public static final java.lang.String KEY_TARGET_BUILD_FINGERPRINT = "target_build_fingerprint";
-    field public static final java.lang.String KEY_TARGET_SECURITY_PATCH_LEVEL = "target_security_patch_level";
-    field public static final java.lang.String KEY_TITLE = "title";
+    method @RequiresPermission(anyOf={android.Manifest.permission.READ_SYSTEM_UPDATE_INFO, android.Manifest.permission.RECOVERY}) public android.os.Bundle retrieveSystemUpdateInfo();
+    method @RequiresPermission(android.Manifest.permission.RECOVERY) public void updateSystemUpdateInfo(android.os.PersistableBundle);
+    field public static final String KEY_IS_SECURITY_UPDATE = "is_security_update";
+    field public static final String KEY_STATUS = "status";
+    field public static final String KEY_TARGET_BUILD_FINGERPRINT = "target_build_fingerprint";
+    field public static final String KEY_TARGET_SECURITY_PATCH_LEVEL = "target_security_patch_level";
+    field public static final String KEY_TITLE = "title";
     field public static final int STATUS_IDLE = 1; // 0x1
     field public static final int STATUS_IN_PROGRESS = 3; // 0x3
     field public static final int STATUS_UNKNOWN = 0; // 0x0
@@ -4530,7 +5315,7 @@
 
   public class UpdateEngine {
     ctor public UpdateEngine();
-    method public void applyPayload(java.lang.String, long, long, java.lang.String[]);
+    method public void applyPayload(String, long, long, String[]);
     method public boolean bind(android.os.UpdateEngineCallback, android.os.Handler);
     method public boolean bind(android.os.UpdateEngineCallback);
     method public void cancel();
@@ -4538,7 +5323,7 @@
     method public void resume();
     method public void suspend();
     method public boolean unbind();
-    method public boolean verifyPayloadMetadata(java.lang.String);
+    method public boolean verifyPayloadMetadata(String);
   }
 
   public static final class UpdateEngine.ErrorCodeConstants {
@@ -4552,6 +5337,7 @@
     field public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10; // 0xa
     field public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6; // 0x6
     field public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; // 0xb
+    field public static final int PAYLOAD_TIMESTAMP_ERROR = 51; // 0x33
     field public static final int POST_INSTALL_RUNNER_ERROR = 5; // 0x5
     field public static final int SUCCESS = 0; // 0x0
     field public static final int UPDATED_BUT_NOT_ACTIVE = 52; // 0x34
@@ -4579,7 +5365,7 @@
 
   public final class UserHandle implements android.os.Parcelable {
     method public int getIdentifier();
-    method public deprecated boolean isOwner();
+    method @Deprecated public boolean isOwner();
     method public boolean isSystem();
     method public static int myUserId();
     method public static android.os.UserHandle of(int);
@@ -4589,26 +5375,26 @@
   }
 
   public class UserManager {
-    method public boolean canSwitchUsers();
-    method public void clearSeedAccountData();
-    method public android.os.UserHandle getProfileParent(android.os.UserHandle);
-    method public java.lang.String getSeedAccountName();
-    method public android.os.PersistableBundle getSeedAccountOptions();
-    method public java.lang.String getSeedAccountType();
-    method public long[] getSerialNumbersOfUsers(boolean);
-    method public deprecated int getUserRestrictionSource(java.lang.String, android.os.UserHandle);
-    method public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(java.lang.String, android.os.UserHandle);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean canSwitchUsers();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void clearSeedAccountData();
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountType();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public long[] getSerialNumbersOfUsers(boolean);
+    method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserRestrictionSource(String, android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
     method public boolean hasRestrictedProfiles();
-    method public boolean isAdminUser();
-    method public boolean isGuestUser();
-    method public boolean isManagedProfile();
-    method public boolean isManagedProfile(int);
-    method public boolean isPrimaryUser();
-    method public boolean isRestrictedProfile();
-    method public boolean removeUser(android.os.UserHandle);
-    field public static final java.lang.String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
-    field public static final deprecated java.lang.String DISALLOW_OEM_UNLOCK = "no_oem_unlock";
-    field public static final java.lang.String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background";
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isAdminUser();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isGuestUser();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedProfile();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedProfile(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isPrimaryUser();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean removeUser(android.os.UserHandle);
+    field public static final String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
+    field @Deprecated public static final String DISALLOW_OEM_UNLOCK = "no_oem_unlock";
+    field public static final String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background";
     field public static final int RESTRICTION_NOT_SET = 0; // 0x0
     field public static final int RESTRICTION_SOURCE_DEVICE_OWNER = 2; // 0x2
     field public static final int RESTRICTION_SOURCE_PROFILE_OWNER = 4; // 0x4
@@ -4618,12 +5404,12 @@
   public static final class UserManager.EnforcingUser implements android.os.Parcelable {
     method public int describeContents();
     method public android.os.UserHandle getUserHandle();
-    method public int getUserRestrictionSource();
+    method @android.os.UserManager.UserRestrictionSource public int getUserRestrictionSource();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.UserManager.EnforcingUser> CREATOR;
   }
 
-  public static abstract class UserManager.UserRestrictionSource implements java.lang.annotation.Annotation {
+  @IntDef(flag=true, prefix={"RESTRICTION_"}, value={android.os.UserManager.RESTRICTION_NOT_SET, android.os.UserManager.RESTRICTION_SOURCE_SYSTEM, android.os.UserManager.RESTRICTION_SOURCE_DEVICE_OWNER, android.os.UserManager.RESTRICTION_SOURCE_PROFILE_OWNER}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface UserManager.UserRestrictionSource {
   }
 
   public class WorkSource implements android.os.Parcelable {
@@ -4632,9 +5418,9 @@
 
   public static final class WorkSource.WorkChain implements android.os.Parcelable {
     ctor public WorkSource.WorkChain();
-    method public android.os.WorkSource.WorkChain addNode(int, java.lang.String);
+    method public android.os.WorkSource.WorkChain addNode(int, @Nullable String);
     method public int describeContents();
-    method public java.lang.String getAttributionTag();
+    method public String getAttributionTag();
     method public int getAttributionUid();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.WorkSource.WorkChain> CREATOR;
@@ -4645,66 +5431,90 @@
 package android.os.storage {
 
   public class StorageManager {
-    method public void allocateBytes(java.util.UUID, long, int) throws java.io.IOException;
-    method public void allocateBytes(java.io.FileDescriptor, long, int) throws java.io.IOException;
-    method public long getAllocatableBytes(java.util.UUID, int) throws java.io.IOException;
-    field public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1
+    method @WorkerThread public void allocateBytes(@NonNull java.util.UUID, long, @RequiresPermission int) throws java.io.IOException;
+    method @WorkerThread public void allocateBytes(java.io.FileDescriptor, long, @RequiresPermission int) throws java.io.IOException;
+    method @WorkerThread public long getAllocatableBytes(@NonNull java.util.UUID, @RequiresPermission int) throws java.io.IOException;
+    method public static boolean hasIsolatedStorage();
+    field @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1
   }
 
 }
 
 package android.permission {
 
+  public final class PermissionControllerManager {
+    method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
+    field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2
+    field public static final int REASON_MALWARE = 1; // 0x1
+  }
+
+  public abstract static class PermissionControllerManager.OnRevokeRuntimePermissionsCallback {
+    ctor public PermissionControllerManager.OnRevokeRuntimePermissionsCallback();
+    method public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>);
+  }
+
+  public abstract class PermissionControllerService extends android.app.Service {
+    ctor public PermissionControllerService();
+    method public final void attachBaseContext(android.content.Context);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract int onCountPermissionApps(@NonNull java.util.List<java.lang.String>, boolean, boolean);
+    method @NonNull public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(@NonNull String);
+    method public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream);
+    method @NonNull public abstract java.util.List<android.permission.RuntimePermissionUsageInfo> onPermissionUsageResult(boolean, long);
+    method public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String);
+    method @NonNull public abstract java.util.Map<java.lang.String,java.util.List<java.lang.String>> onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String);
+    field public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
+  }
+
   public final class PermissionManager {
-    method public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
+    method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
   }
 
   public static final class PermissionManager.SplitPermissionInfo {
-    method public java.util.List<java.lang.String> getNewPermissions();
-    method public java.lang.String getSplitPermission();
+    method @NonNull public java.util.List<java.lang.String> getNewPermissions();
+    method @NonNull public String getSplitPermission();
     method public int getTargetSdk();
   }
 
   public final class RuntimePermissionPresentationInfo implements android.os.Parcelable {
-    ctor public RuntimePermissionPresentationInfo(java.lang.CharSequence, boolean, boolean);
+    ctor public RuntimePermissionPresentationInfo(CharSequence, boolean, boolean);
     method public int describeContents();
-    method public java.lang.CharSequence getLabel();
+    method @NonNull public CharSequence getLabel();
     method public boolean isGranted();
     method public boolean isStandard();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.permission.RuntimePermissionPresentationInfo> CREATOR;
   }
 
-  public abstract class RuntimePermissionPresenterService extends android.app.Service {
-    ctor public RuntimePermissionPresenterService();
-    method public final void attachBaseContext(android.content.Context);
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract int onCountPermissionApps(java.util.List<java.lang.String>, boolean, boolean);
-    method public abstract java.util.List<android.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.permission.RuntimePermissionPresenterService";
+  public final class RuntimePermissionUsageInfo implements android.os.Parcelable {
+    ctor public RuntimePermissionUsageInfo(@NonNull CharSequence, int);
+    method public int describeContents();
+    method public int getAppAccessCount();
+    method @NonNull public CharSequence getName();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.permission.RuntimePermissionUsageInfo> CREATOR;
   }
 
 }
 
 package android.permissionpresenterservice {
 
-  public abstract deprecated class RuntimePermissionPresenterService extends android.app.Service {
-    ctor public RuntimePermissionPresenterService();
-    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";
+  @Deprecated public abstract class RuntimePermissionPresenterService extends android.app.Service {
+    ctor @Deprecated public RuntimePermissionPresenterService();
+    method @Deprecated public final void attachBaseContext(android.content.Context);
+    method @Deprecated public final android.os.IBinder onBind(android.content.Intent);
+    method @Deprecated public abstract java.util.List<android.content.pm.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(@NonNull String);
+    method @Deprecated public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String);
+    field @Deprecated public static final String SERVICE_INTERFACE = "android.permissionpresenterservice.RuntimePermissionPresenterService";
   }
 
 }
 
 package android.preference {
 
-  public deprecated class PreferenceManager {
-    method public boolean isStorageCredentialProtected();
-    method public void setStorageCredentialProtected();
+  @Deprecated public class PreferenceManager {
+    method @Deprecated public boolean isStorageCredentialProtected();
+    method @Deprecated public void setStorageCredentialProtected();
   }
 
 }
@@ -4712,21 +5522,21 @@
 package android.print {
 
   public final class PrintManager {
-    method public void addPrintServiceRecommendationsChangeListener(android.print.PrintManager.PrintServiceRecommendationsChangeListener, android.os.Handler);
-    method public void addPrintServicesChangeListener(android.print.PrintManager.PrintServicesChangeListener, android.os.Handler);
-    method public java.util.List<android.printservice.recommendation.RecommendationInfo> getPrintServiceRecommendations();
-    method public java.util.List<android.printservice.PrintServiceInfo> getPrintServices(int);
-    method public void removePrintServiceRecommendationsChangeListener(android.print.PrintManager.PrintServiceRecommendationsChangeListener);
-    method public void removePrintServicesChangeListener(android.print.PrintManager.PrintServicesChangeListener);
+    method @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS) public void addPrintServiceRecommendationsChangeListener(@NonNull android.print.PrintManager.PrintServiceRecommendationsChangeListener, @Nullable android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICES) public void addPrintServicesChangeListener(@NonNull android.print.PrintManager.PrintServicesChangeListener, @Nullable android.os.Handler);
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS) public java.util.List<android.printservice.recommendation.RecommendationInfo> getPrintServiceRecommendations();
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICES) public java.util.List<android.printservice.PrintServiceInfo> getPrintServices(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS) public void removePrintServiceRecommendationsChangeListener(@NonNull android.print.PrintManager.PrintServiceRecommendationsChangeListener);
+    method @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICES) public void removePrintServicesChangeListener(@NonNull android.print.PrintManager.PrintServicesChangeListener);
     field public static final int ENABLED_SERVICES = 1; // 0x1
   }
 
-  public static abstract interface PrintManager.PrintServiceRecommendationsChangeListener {
-    method public abstract void onPrintServiceRecommendationsChanged();
+  public static interface PrintManager.PrintServiceRecommendationsChangeListener {
+    method public void onPrintServiceRecommendationsChanged();
   }
 
-  public static abstract interface PrintManager.PrintServicesChangeListener {
-    method public abstract void onPrintServicesChanged();
+  public static interface PrintManager.PrintServicesChangeListener {
+    method public void onPrintServicesChanged();
   }
 
 }
@@ -4735,7 +5545,7 @@
 
   public final class PrintServiceInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public android.content.ComponentName getComponentName();
+    method @NonNull public android.content.ComponentName getComponentName();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.printservice.PrintServiceInfo> CREATOR;
   }
@@ -4745,13 +5555,13 @@
 package android.printservice.recommendation {
 
   public final class RecommendationInfo implements android.os.Parcelable {
-    ctor public RecommendationInfo(java.lang.CharSequence, java.lang.CharSequence, java.util.List<java.net.InetAddress>, boolean);
-    ctor public deprecated RecommendationInfo(java.lang.CharSequence, java.lang.CharSequence, int, boolean);
+    ctor public RecommendationInfo(@NonNull CharSequence, @NonNull CharSequence, @NonNull java.util.List<java.net.InetAddress>, boolean);
+    ctor @Deprecated public RecommendationInfo(@NonNull CharSequence, @NonNull CharSequence, @IntRange(from=0) int, boolean);
     method public int describeContents();
-    method public java.util.List<java.net.InetAddress> getDiscoveredPrinters();
-    method public java.lang.CharSequence getName();
+    method @NonNull public java.util.List<java.net.InetAddress> getDiscoveredPrinters();
+    method public CharSequence getName();
     method public int getNumDiscoveredPrinters();
-    method public java.lang.CharSequence getPackageName();
+    method public CharSequence getPackageName();
     method public boolean recommendsMultiVendorService();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.printservice.recommendation.RecommendationInfo> CREATOR;
@@ -4762,8 +5572,8 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract void onConnected();
     method public abstract void onDisconnected();
-    method public final void updateRecommendations(java.util.List<android.printservice.recommendation.RecommendationInfo>);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.printservice.recommendation.RecommendationService";
+    method public final void updateRecommendations(@Nullable java.util.List<android.printservice.recommendation.RecommendationInfo>);
+    field public static final String SERVICE_INTERFACE = "android.printservice.recommendation.RecommendationService";
   }
 
 }
@@ -4771,53 +5581,77 @@
 package android.provider {
 
   public static final class ContactsContract.MetadataSync implements android.provider.BaseColumns android.provider.ContactsContract.MetadataSyncColumns {
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String METADATA_AUTHORITY = "com.android.contacts.metadata";
+    field public static final String METADATA_AUTHORITY = "com.android.contacts.metadata";
     field public static final android.net.Uri METADATA_AUTHORITY_URI;
   }
 
-  protected static abstract interface ContactsContract.MetadataSyncColumns {
-    field public static final java.lang.String ACCOUNT_NAME = "account_name";
-    field public static final java.lang.String ACCOUNT_TYPE = "account_type";
-    field public static final java.lang.String DATA = "data";
-    field public static final java.lang.String DATA_SET = "data_set";
-    field public static final java.lang.String DELETED = "deleted";
-    field public static final java.lang.String RAW_CONTACT_BACKUP_ID = "raw_contact_backup_id";
+  protected static interface ContactsContract.MetadataSyncColumns {
+    field public static final String ACCOUNT_NAME = "account_name";
+    field public static final String ACCOUNT_TYPE = "account_type";
+    field public static final String DATA = "data";
+    field public static final String DATA_SET = "data_set";
+    field public static final String DELETED = "deleted";
+    field public static final String RAW_CONTACT_BACKUP_ID = "raw_contact_backup_id";
   }
 
   public static final class ContactsContract.MetadataSyncState implements android.provider.BaseColumns android.provider.ContactsContract.MetadataSyncStateColumns {
-    field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata_sync_state";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata_sync_state";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata_sync_state";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata_sync_state";
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  protected static abstract interface ContactsContract.MetadataSyncStateColumns {
-    field public static final java.lang.String ACCOUNT_NAME = "account_name";
-    field public static final java.lang.String ACCOUNT_TYPE = "account_type";
-    field public static final java.lang.String DATA_SET = "data_set";
-    field public static final java.lang.String STATE = "state";
+  protected static interface ContactsContract.MetadataSyncStateColumns {
+    field public static final String ACCOUNT_NAME = "account_name";
+    field public static final String ACCOUNT_TYPE = "account_type";
+    field public static final String DATA_SET = "data_set";
+    field public static final String STATE = "state";
   }
 
   public final class DeviceConfig {
-    method public static void addOnPropertyChangedListener(java.lang.String, java.util.concurrent.Executor, android.provider.DeviceConfig.OnPropertyChangedListener);
-    method public static java.lang.String getProperty(java.lang.String, java.lang.String);
+    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
+    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getProperty(String, String);
     method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener);
-    method public static void resetToDefaults(int, java.lang.String);
-    method public static boolean setProperty(java.lang.String, java.lang.String, java.lang.String, boolean);
+    method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
+    method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(String, String, String, boolean);
+    field public static final String NAMESPACE_AUTOFILL = "autofill";
+    field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
+    field public static final String NAMESPACE_GAME_DRIVER = "game_driver";
+    field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
+    field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
+    field public static final String NAMESPACE_NOTIFICATION_ASSISTANT = "notification_assistant";
   }
 
-  public static abstract interface DeviceConfig.OnPropertyChangedListener {
-    method public abstract void onPropertyChanged(java.lang.String, java.lang.String, java.lang.String);
+  public static interface DeviceConfig.FsiBoot {
+    field public static final String NAMESPACE = "fsi_boot";
+    field public static final String OOB_ENABLED = "oob_enabled";
+    field public static final String OOB_WHITELIST = "oob_whitelist";
+  }
+
+  public static interface DeviceConfig.IntelligenceAttention {
+    field public static final String NAMESPACE = "intelligence_attention";
+    field public static final String PROPERTY_ATTENTION_CHECK_ENABLED = "attention_check_enabled";
+    field public static final String PROPERTY_ATTENTION_CHECK_SETTINGS = "attention_check_settings";
+  }
+
+  public static interface DeviceConfig.OnPropertyChangedListener {
+    method public void onPropertyChanged(String, String, String);
+  }
+
+  public static interface DeviceConfig.Telephony {
+    field public static final String NAMESPACE = "telephony";
+    field public static final String PROPERTY_ENABLE_RAMPING_RINGER = "enable_ramping_ringer";
+    field public static final String PROPERTY_RAMPING_RINGER_DURATION = "ramping_duration";
   }
 
   public final class DocumentsContract {
     method public static boolean isManageMode(android.net.Uri);
     method public static android.net.Uri setManageMode(android.net.Uri);
-    field public static final java.lang.String ACTION_DOCUMENT_ROOT_SETTINGS = "android.provider.action.DOCUMENT_ROOT_SETTINGS";
-    field public static final java.lang.String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT";
-    field public static final java.lang.String EXTRA_SHOW_ADVANCED = "android.provider.extra.SHOW_ADVANCED";
+    field public static final String ACTION_DOCUMENT_ROOT_SETTINGS = "android.provider.action.DOCUMENT_ROOT_SETTINGS";
+    field public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT";
+    field public static final String EXTRA_SHOW_ADVANCED = "android.provider.extra.SHOW_ADVANCED";
   }
 
   public static final class DocumentsContract.Root {
@@ -4830,22 +5664,22 @@
   public abstract class SearchIndexableData {
     ctor public SearchIndexableData();
     ctor public SearchIndexableData(android.content.Context);
-    field public java.lang.String className;
+    field public String className;
     field public android.content.Context context;
     field public boolean enabled;
     field public int iconResId;
-    field public java.lang.String intentAction;
-    field public java.lang.String intentTargetClass;
-    field public java.lang.String intentTargetPackage;
-    field public java.lang.String key;
+    field public String intentAction;
+    field public String intentTargetClass;
+    field public String intentTargetPackage;
+    field public String key;
     field public java.util.Locale locale;
-    field public java.lang.String packageName;
+    field public String packageName;
     field public int rank;
     field public int userId;
   }
 
   public class SearchIndexableResource extends android.provider.SearchIndexableData {
-    ctor public SearchIndexableResource(int, int, java.lang.String, int);
+    ctor public SearchIndexableResource(int, int, String, int);
     ctor public SearchIndexableResource(android.content.Context);
     field public int xmlResId;
   }
@@ -4874,150 +5708,166 @@
     field public static final int COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE = 5; // 0x5
     field public static final int COLUMN_INDEX_XML_RES_RANK = 0; // 0x0
     field public static final int COLUMN_INDEX_XML_RES_RESID = 1; // 0x1
-    field public static final java.lang.String INDEXABLES_RAW = "indexables_raw";
-    field public static final java.lang.String[] INDEXABLES_RAW_COLUMNS;
-    field public static final java.lang.String INDEXABLES_RAW_PATH = "settings/indexables_raw";
-    field public static final java.lang.String INDEXABLES_XML_RES = "indexables_xml_res";
-    field public static final java.lang.String[] INDEXABLES_XML_RES_COLUMNS;
-    field public static final java.lang.String INDEXABLES_XML_RES_PATH = "settings/indexables_xml_res";
-    field public static final java.lang.String NON_INDEXABLES_KEYS = "non_indexables_key";
-    field public static final java.lang.String[] NON_INDEXABLES_KEYS_COLUMNS;
-    field public static final java.lang.String NON_INDEXABLES_KEYS_PATH = "settings/non_indexables_key";
-    field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.SEARCH_INDEXABLES_PROVIDER";
+    field public static final String INDEXABLES_RAW = "indexables_raw";
+    field public static final String[] INDEXABLES_RAW_COLUMNS;
+    field public static final String INDEXABLES_RAW_PATH = "settings/indexables_raw";
+    field public static final String INDEXABLES_XML_RES = "indexables_xml_res";
+    field public static final String[] INDEXABLES_XML_RES_COLUMNS;
+    field public static final String INDEXABLES_XML_RES_PATH = "settings/indexables_xml_res";
+    field public static final String NON_INDEXABLES_KEYS = "non_indexables_key";
+    field public static final String[] NON_INDEXABLES_KEYS_COLUMNS;
+    field public static final String NON_INDEXABLES_KEYS_PATH = "settings/non_indexables_key";
+    field public static final String PROVIDER_INTERFACE = "android.content.action.SEARCH_INDEXABLES_PROVIDER";
   }
 
   public static class SearchIndexablesContract.BaseColumns {
-    field public static final java.lang.String COLUMN_CLASS_NAME = "className";
-    field public static final java.lang.String COLUMN_ICON_RESID = "iconResId";
-    field public static final java.lang.String COLUMN_INTENT_ACTION = "intentAction";
-    field public static final java.lang.String COLUMN_INTENT_TARGET_CLASS = "intentTargetClass";
-    field public static final java.lang.String COLUMN_INTENT_TARGET_PACKAGE = "intentTargetPackage";
-    field public static final java.lang.String COLUMN_RANK = "rank";
+    field public static final String COLUMN_CLASS_NAME = "className";
+    field public static final String COLUMN_ICON_RESID = "iconResId";
+    field public static final String COLUMN_INTENT_ACTION = "intentAction";
+    field public static final String COLUMN_INTENT_TARGET_CLASS = "intentTargetClass";
+    field public static final String COLUMN_INTENT_TARGET_PACKAGE = "intentTargetPackage";
+    field public static final String COLUMN_RANK = "rank";
   }
 
   public static final class SearchIndexablesContract.NonIndexableKey extends android.provider.SearchIndexablesContract.BaseColumns {
-    field public static final java.lang.String COLUMN_KEY_VALUE = "key";
-    field public static final java.lang.String MIME_TYPE = "vnd.android.cursor.dir/non_indexables_key";
+    field public static final String COLUMN_KEY_VALUE = "key";
+    field public static final String MIME_TYPE = "vnd.android.cursor.dir/non_indexables_key";
   }
 
   public static final class SearchIndexablesContract.RawData extends android.provider.SearchIndexablesContract.BaseColumns {
-    field public static final java.lang.String COLUMN_ENTRIES = "entries";
-    field public static final java.lang.String COLUMN_KEY = "key";
-    field public static final java.lang.String COLUMN_KEYWORDS = "keywords";
-    field public static final java.lang.String COLUMN_SCREEN_TITLE = "screenTitle";
-    field public static final java.lang.String COLUMN_SUMMARY_OFF = "summaryOff";
-    field public static final java.lang.String COLUMN_SUMMARY_ON = "summaryOn";
-    field public static final java.lang.String COLUMN_TITLE = "title";
-    field public static final java.lang.String COLUMN_USER_ID = "user_id";
-    field public static final java.lang.String MIME_TYPE = "vnd.android.cursor.dir/indexables_raw";
+    field public static final String COLUMN_ENTRIES = "entries";
+    field public static final String COLUMN_KEY = "key";
+    field public static final String COLUMN_KEYWORDS = "keywords";
+    field public static final String COLUMN_SCREEN_TITLE = "screenTitle";
+    field public static final String COLUMN_SUMMARY_OFF = "summaryOff";
+    field public static final String COLUMN_SUMMARY_ON = "summaryOn";
+    field public static final String COLUMN_TITLE = "title";
+    field public static final String COLUMN_USER_ID = "user_id";
+    field public static final String MIME_TYPE = "vnd.android.cursor.dir/indexables_raw";
   }
 
   public static final class SearchIndexablesContract.XmlResource extends android.provider.SearchIndexablesContract.BaseColumns {
-    field public static final java.lang.String COLUMN_XML_RESID = "xmlResId";
-    field public static final java.lang.String MIME_TYPE = "vnd.android.cursor.dir/indexables_xml_res";
+    field public static final String COLUMN_XML_RESID = "xmlResId";
+    field public static final String MIME_TYPE = "vnd.android.cursor.dir/indexables_xml_res";
   }
 
   public abstract class SearchIndexablesProvider extends android.content.ContentProvider {
     ctor public SearchIndexablesProvider();
-    method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
-    method public java.lang.String getType(android.net.Uri);
+    method public final int delete(android.net.Uri, String, String[]);
+    method public String getType(android.net.Uri);
     method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
-    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public abstract android.database.Cursor queryNonIndexableKeys(java.lang.String[]);
-    method public abstract android.database.Cursor queryRawData(java.lang.String[]);
-    method public abstract android.database.Cursor queryXmlResources(java.lang.String[]);
-    method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+    method public android.database.Cursor query(android.net.Uri, String[], String, String[], String);
+    method public abstract android.database.Cursor queryNonIndexableKeys(String[]);
+    method public abstract android.database.Cursor queryRawData(String[]);
+    method public abstract android.database.Cursor queryXmlResources(String[]);
+    method public final int update(android.net.Uri, android.content.ContentValues, String, String[]);
   }
 
   public final class Settings {
-    field public static final java.lang.String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
-    field public static final java.lang.String ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS = "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS";
-    field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
+    field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
+    field public static final String ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS = "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS";
+    field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
   }
 
   public static final class Settings.Global extends android.provider.Settings.NameValueTable {
-    method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String, boolean);
-    method public static void resetToDefaults(android.content.ContentResolver, java.lang.String);
-    field public static final java.lang.String APP_STANDBY_ENABLED = "app_standby_enabled";
-    field public static final java.lang.String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
-    field public static final java.lang.String CARRIER_APP_NAMES = "carrier_app_names";
-    field public static final java.lang.String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
-    field public static final java.lang.String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
-    field public static final java.lang.String DEVICE_DEMO_MODE = "device_demo_mode";
-    field public static final java.lang.String DEVICE_PROVISIONING_MOBILE_DATA_ENABLED = "device_provisioning_mobile_data";
-    field public static final java.lang.String EUICC_PROVISIONED = "euicc_provisioned";
-    field public static final java.lang.String INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT = "install_carrier_app_notification_persistent";
-    field public static final java.lang.String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis";
-    field public static final java.lang.String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
-    field public static final java.lang.String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt";
-    field public static final java.lang.String SMS_ACCESS_RESTRICTION_ENABLED = "sms_access_restriction_enabled";
-    field public static final java.lang.String THEATER_MODE_ON = "theater_mode_on";
-    field public static final java.lang.String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
-    field public static final java.lang.String WIFI_BADGING_THRESHOLDS = "wifi_badging_thresholds";
-    field public static final java.lang.String WIFI_WAKEUP_ENABLED = "wifi_wakeup_enabled";
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, @Nullable String, boolean);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String);
+    field public static final String APP_STANDBY_ENABLED = "app_standby_enabled";
+    field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
+    field public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS = "captive_portal_fallback_probe_specs";
+    field public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
+    field public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url";
+    field public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
+    field public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
+    field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
+    field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0
+    field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1
+    field public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS = "captive_portal_other_fallback_urls";
+    field public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
+    field public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
+    field public static final String CARRIER_APP_NAMES = "carrier_app_names";
+    field public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
+    field public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = "data_stall_consecutive_dns_timeout_threshold";
+    field public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
+    field public static final String DATA_STALL_MIN_EVALUATE_INTERVAL = "data_stall_min_evaluate_interval";
+    field public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD = "data_stall_valid_dns_time_threshold";
+    field public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
+    field public static final String DEVICE_DEMO_MODE = "device_demo_mode";
+    field public static final String DEVICE_PROVISIONING_MOBILE_DATA_ENABLED = "device_provisioning_mobile_data";
+    field public static final String EUICC_PROVISIONED = "euicc_provisioned";
+    field public static final String INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT = "install_carrier_app_notification_persistent";
+    field public static final String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis";
+    field public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
+    field public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt";
+    field public static final String SMS_ACCESS_RESTRICTION_ENABLED = "sms_access_restriction_enabled";
+    field public static final String THEATER_MODE_ON = "theater_mode_on";
+    field public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
+    field public static final String WIFI_BADGING_THRESHOLDS = "wifi_badging_thresholds";
+    field public static final String WIFI_WAKEUP_ENABLED = "wifi_wakeup_enabled";
   }
 
   public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
-    method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String, boolean);
-    method public static void resetToDefaults(android.content.ContentResolver, java.lang.String);
-    field public static final java.lang.String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED = "accessibility_display_magnification_navbar_enabled";
-    field public static final java.lang.String ASSIST_GESTURE_SETUP_COMPLETE = "assist_gesture_setup_complete";
-    field public static final java.lang.String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification";
-    field public static final java.lang.String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count";
-    field public static final java.lang.String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size";
-    field public static final java.lang.String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
-    field public static final java.lang.String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
-    field public static final java.lang.String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
-    field public static final java.lang.String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
-    field public static final java.lang.String DOZE_ALWAYS_ON = "doze_always_on";
-    field public static final java.lang.String HUSH_GESTURE_USED = "hush_gesture_used";
-    field public static final java.lang.String INSTANT_APPS_ENABLED = "instant_apps_enabled";
-    field public static final java.lang.String LAST_SETUP_SHOWN = "last_setup_shown";
-    field public static final java.lang.String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis";
-    field public static final java.lang.String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS = "location_access_check_interval_millis";
-    field public static final java.lang.String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications";
-    field public static final java.lang.String LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications";
-    field public static final java.lang.String MANUAL_RINGER_TOGGLE_COUNT = "manual_ringer_toggle_count";
-    field public static final java.lang.String USER_SETUP_COMPLETE = "user_setup_complete";
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, @Nullable String, boolean);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String);
+    field public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED = "accessibility_display_magnification_navbar_enabled";
+    field public static final String ASSIST_GESTURE_SETUP_COMPLETE = "assist_gesture_setup_complete";
+    field public static final String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification";
+    field public static final String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count";
+    field public static final String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size";
+    field public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
+    field public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
+    field public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
+    field public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
+    field public static final String DOZE_ALWAYS_ON = "doze_always_on";
+    field public static final String HUSH_GESTURE_USED = "hush_gesture_used";
+    field public static final String INSTANT_APPS_ENABLED = "instant_apps_enabled";
+    field public static final String LAST_SETUP_SHOWN = "last_setup_shown";
+    field public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis";
+    field public static final String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS = "location_access_check_interval_millis";
+    field public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications";
+    field public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications";
+    field public static final String MANUAL_RINGER_TOGGLE_COUNT = "manual_ringer_toggle_count";
+    field public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES = "theme_customization_overlay_packages";
+    field public static final String USER_SETUP_COMPLETE = "user_setup_complete";
     field public static final int USER_SETUP_PERSONALIZATION_COMPLETE = 10; // 0xa
     field public static final int USER_SETUP_PERSONALIZATION_NOT_STARTED = 0; // 0x0
     field public static final int USER_SETUP_PERSONALIZATION_PAUSED = 2; // 0x2
     field public static final int USER_SETUP_PERSONALIZATION_STARTED = 1; // 0x1
-    field public static final java.lang.String USER_SETUP_PERSONALIZATION_STATE = "user_setup_personalization_state";
-    field public static final java.lang.String VOLUME_HUSH_GESTURE = "volume_hush_gesture";
+    field public static final String USER_SETUP_PERSONALIZATION_STATE = "user_setup_personalization_state";
+    field public static final String VOLUME_HUSH_GESTURE = "volume_hush_gesture";
   }
 
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
-    field public static final java.lang.String APN_SET_ID = "apn_set_id";
+    field public static final String APN_SET_ID = "apn_set_id";
     field public static final int CARRIER_EDITED = 4; // 0x4
-    field public static final java.lang.String EDITED_STATUS = "edited";
-    field public static final java.lang.String MAX_CONNECTIONS = "max_conns";
-    field public static final java.lang.String MODEM_PERSIST = "modem_cognitive";
-    field public static final java.lang.String MTU = "mtu";
+    field public static final String EDITED_STATUS = "edited";
+    field public static final String MAX_CONNECTIONS = "max_conns";
+    field public static final String MODEM_PERSIST = "modem_cognitive";
+    field public static final String MTU = "mtu";
     field public static final int NO_APN_SET_ID = 0; // 0x0
-    field public static final java.lang.String TIME_LIMIT_FOR_MAX_CONNECTIONS = "max_conns_time";
+    field public static final String TIME_LIMIT_FOR_MAX_CONNECTIONS = "max_conns_time";
     field public static final int UNEDITED = 0; // 0x0
     field public static final int USER_DELETED = 2; // 0x2
-    field public static final java.lang.String USER_EDITABLE = "user_editable";
+    field public static final String USER_EDITABLE = "user_editable";
     field public static final int USER_EDITED = 1; // 0x1
-    field public static final java.lang.String USER_VISIBLE = "user_visible";
-    field public static final java.lang.String WAIT_TIME_RETRY = "wait_time";
+    field public static final String USER_VISIBLE = "user_visible";
+    field public static final String WAIT_TIME_RETRY = "wait_time";
   }
 
   public final class TimeZoneRulesDataContract {
-    field public static final java.lang.String AUTHORITY = "com.android.timezone";
+    field public static final String AUTHORITY = "com.android.timezone";
   }
 
   public static final class TimeZoneRulesDataContract.Operation {
-    field public static final java.lang.String COLUMN_DISTRO_MAJOR_VERSION = "distro_major_version";
-    field public static final java.lang.String COLUMN_DISTRO_MINOR_VERSION = "distro_minor_version";
-    field public static final java.lang.String COLUMN_REVISION = "revision";
-    field public static final java.lang.String COLUMN_RULES_VERSION = "rules_version";
-    field public static final java.lang.String COLUMN_TYPE = "type";
+    field public static final String COLUMN_DISTRO_MAJOR_VERSION = "distro_major_version";
+    field public static final String COLUMN_DISTRO_MINOR_VERSION = "distro_minor_version";
+    field public static final String COLUMN_REVISION = "revision";
+    field public static final String COLUMN_RULES_VERSION = "rules_version";
+    field public static final String COLUMN_TYPE = "type";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String TYPE_INSTALL = "INSTALL";
-    field public static final java.lang.String TYPE_NO_OP = "NOOP";
-    field public static final java.lang.String TYPE_UNINSTALL = "UNINSTALL";
+    field public static final String TYPE_INSTALL = "INSTALL";
+    field public static final String TYPE_NO_OP = "NOOP";
+    field public static final String TYPE_UNINSTALL = "UNINSTALL";
   }
 
 }
@@ -5026,12 +5876,12 @@
 
   public abstract class RoleControllerService extends android.app.Service {
     ctor public RoleControllerService();
-    method public abstract void onAddRoleHolder(java.lang.String, java.lang.String, android.app.role.RoleManagerCallback);
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract void onClearRoleHolders(java.lang.String, android.app.role.RoleManagerCallback);
-    method public abstract void onGrantDefaultRoles(android.app.role.RoleManagerCallback);
-    method public abstract void onRemoveRoleHolder(java.lang.String, java.lang.String, android.app.role.RoleManagerCallback);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.rolecontrollerservice.RoleControllerService";
+    method public abstract void onAddRoleHolder(@NonNull String, @NonNull String, @NonNull android.app.role.RoleManagerCallback);
+    method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
+    method public abstract void onClearRoleHolders(@NonNull String, @NonNull android.app.role.RoleManagerCallback);
+    method public abstract void onGrantDefaultRoles(@NonNull android.app.role.RoleManagerCallback);
+    method public abstract void onRemoveRoleHolder(@NonNull String, @NonNull String, @NonNull android.app.role.RoleManagerCallback);
+    field public static final String SERVICE_INTERFACE = "android.rolecontrollerservice.RoleControllerService";
   }
 
 }
@@ -5039,15 +5889,15 @@
 package android.security.keystore {
 
   public abstract class AttestationUtils {
-    method public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, int[], byte[]) throws android.security.keystore.DeviceIdAttestationException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @NonNull public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException;
     field public static final int ID_TYPE_IMEI = 2; // 0x2
     field public static final int ID_TYPE_MEID = 3; // 0x3
     field public static final int ID_TYPE_SERIAL = 1; // 0x1
   }
 
   public class DeviceIdAttestationException extends java.lang.Exception {
-    ctor public DeviceIdAttestationException(java.lang.String);
-    ctor public DeviceIdAttestationException(java.lang.String, java.lang.Throwable);
+    ctor public DeviceIdAttestationException(String);
+    ctor public DeviceIdAttestationException(String, Throwable);
   }
 
 }
@@ -5055,20 +5905,20 @@
 package android.security.keystore.recovery {
 
   public class DecryptionFailedException extends java.security.GeneralSecurityException {
-    ctor public DecryptionFailedException(java.lang.String);
+    ctor public DecryptionFailedException(String);
   }
 
   public class InternalRecoveryServiceException extends java.security.GeneralSecurityException {
-    ctor public InternalRecoveryServiceException(java.lang.String);
-    ctor public InternalRecoveryServiceException(java.lang.String, java.lang.Throwable);
+    ctor public InternalRecoveryServiceException(String);
+    ctor public InternalRecoveryServiceException(String, Throwable);
   }
 
   public final class KeyChainProtectionParams implements android.os.Parcelable {
     method public void clearSecret();
     method public int describeContents();
-    method public android.security.keystore.recovery.KeyDerivationParams getKeyDerivationParams();
+    method @NonNull public android.security.keystore.recovery.KeyDerivationParams getKeyDerivationParams();
     method public int getLockScreenUiFormat();
-    method public byte[] getSecret();
+    method @NonNull public byte[] getSecret();
     method public int getUserSecretType();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.security.keystore.recovery.KeyChainProtectionParams> CREATOR;
@@ -5080,34 +5930,34 @@
 
   public static class KeyChainProtectionParams.Builder {
     ctor public KeyChainProtectionParams.Builder();
-    method public android.security.keystore.recovery.KeyChainProtectionParams build();
-    method public android.security.keystore.recovery.KeyChainProtectionParams.Builder setKeyDerivationParams(android.security.keystore.recovery.KeyDerivationParams);
+    method @NonNull public android.security.keystore.recovery.KeyChainProtectionParams build();
+    method public android.security.keystore.recovery.KeyChainProtectionParams.Builder setKeyDerivationParams(@NonNull android.security.keystore.recovery.KeyDerivationParams);
     method public android.security.keystore.recovery.KeyChainProtectionParams.Builder setLockScreenUiFormat(int);
-    method public android.security.keystore.recovery.KeyChainProtectionParams.Builder setSecret(byte[]);
+    method public android.security.keystore.recovery.KeyChainProtectionParams.Builder setSecret(@NonNull byte[]);
     method public android.security.keystore.recovery.KeyChainProtectionParams.Builder setUserSecretType(int);
   }
 
   public final class KeyChainSnapshot implements android.os.Parcelable {
     method public int describeContents();
     method public long getCounterId();
-    method public byte[] getEncryptedRecoveryKeyBlob();
-    method public java.util.List<android.security.keystore.recovery.KeyChainProtectionParams> getKeyChainProtectionParams();
+    method @NonNull public byte[] getEncryptedRecoveryKeyBlob();
+    method @NonNull public java.util.List<android.security.keystore.recovery.KeyChainProtectionParams> getKeyChainProtectionParams();
     method public int getMaxAttempts();
-    method public byte[] getServerParams();
+    method @NonNull public byte[] getServerParams();
     method public int getSnapshotVersion();
-    method public java.security.cert.CertPath getTrustedHardwareCertPath();
-    method public java.util.List<android.security.keystore.recovery.WrappedApplicationKey> getWrappedApplicationKeys();
+    method @NonNull public java.security.cert.CertPath getTrustedHardwareCertPath();
+    method @NonNull public java.util.List<android.security.keystore.recovery.WrappedApplicationKey> getWrappedApplicationKeys();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.security.keystore.recovery.KeyChainSnapshot> CREATOR;
   }
 
   public final class KeyDerivationParams implements android.os.Parcelable {
-    method public static android.security.keystore.recovery.KeyDerivationParams createScryptParams(byte[], int);
-    method public static android.security.keystore.recovery.KeyDerivationParams createSha256Params(byte[]);
+    method @NonNull public static android.security.keystore.recovery.KeyDerivationParams createScryptParams(@NonNull byte[], int);
+    method @NonNull public static android.security.keystore.recovery.KeyDerivationParams createSha256Params(@NonNull byte[]);
     method public int describeContents();
     method public int getAlgorithm();
     method public int getMemoryDifficulty();
-    method public byte[] getSalt();
+    method @NonNull public byte[] getSalt();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ALGORITHM_SCRYPT = 2; // 0x2
     field public static final int ALGORITHM_SHA256 = 1; // 0x1
@@ -5115,55 +5965,99 @@
   }
 
   public class LockScreenRequiredException extends java.security.GeneralSecurityException {
-    ctor public LockScreenRequiredException(java.lang.String);
+    ctor public LockScreenRequiredException(String);
   }
 
   public class RecoveryController {
-    method public android.security.keystore.recovery.RecoverySession createRecoverySession();
-    method public java.security.Key generateKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
-    method public java.util.List<java.lang.String> getAliases() throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public static android.security.keystore.recovery.RecoveryController getInstance(android.content.Context);
-    method public java.security.Key getKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException, java.security.UnrecoverableKeyException;
-    method public android.security.keystore.recovery.KeyChainSnapshot getKeyChainSnapshot() throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public int getRecoveryStatus(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public java.util.Map<java.lang.String, java.security.cert.X509Certificate> getRootCertificates();
-    method public java.security.Key importKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
-    method public void initRecoveryService(java.lang.String, byte[], byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public static boolean isRecoverableKeyStoreEnabled(android.content.Context);
-    method public void removeKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public void setRecoverySecretTypes(int[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public void setRecoveryStatus(java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public void setServerParams(byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public void setSnapshotCreatedPendingIntent(android.app.PendingIntent) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public android.security.keystore.recovery.RecoverySession createRecoverySession();
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key generateKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.security.Key generateKey(@NonNull String, @Nullable byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.util.List<java.lang.String> getAliases() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public static android.security.keystore.recovery.RecoveryController getInstance(@NonNull android.content.Context);
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @Nullable public java.security.Key getKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException, java.security.UnrecoverableKeyException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @Nullable public android.security.keystore.recovery.KeyChainSnapshot getKeyChainSnapshot() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public int getRecoveryStatus(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.util.Map<java.lang.String,java.security.cert.X509Certificate> getRootCertificates();
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key importKey(@NonNull String, @NonNull byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.security.Key importKey(@NonNull String, @NonNull byte[], @Nullable byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void initRecoveryService(@NonNull String, @NonNull byte[], @NonNull byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public static boolean isRecoverableKeyStoreEnabled(@NonNull android.content.Context);
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void removeKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void setRecoverySecretTypes(@NonNull int[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void setRecoveryStatus(@NonNull String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void setServerParams(@NonNull byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void setSnapshotCreatedPendingIntent(@Nullable android.app.PendingIntent) throws android.security.keystore.recovery.InternalRecoveryServiceException;
     field public static final int RECOVERY_STATUS_PERMANENT_FAILURE = 3; // 0x3
     field public static final int RECOVERY_STATUS_SYNCED = 0; // 0x0
     field public static final int RECOVERY_STATUS_SYNC_IN_PROGRESS = 1; // 0x1
   }
 
   public class RecoverySession implements java.lang.AutoCloseable {
-    method public void close();
-    method public java.util.Map<java.lang.String, java.security.Key> recoverKeyChainSnapshot(byte[], java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
-    method public byte[] start(java.lang.String, java.security.cert.CertPath, byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void close();
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.util.Map<java.lang.String,java.security.Key> recoverKeyChainSnapshot(@NonNull byte[], @NonNull java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
+    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public byte[] start(@NonNull String, @NonNull java.security.cert.CertPath, @NonNull byte[], @NonNull byte[], @NonNull java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
   }
 
   public class SessionExpiredException extends java.security.GeneralSecurityException {
-    ctor public SessionExpiredException(java.lang.String);
+    ctor public SessionExpiredException(String);
   }
 
   public final class WrappedApplicationKey implements android.os.Parcelable {
     method public int describeContents();
-    method public java.lang.String getAlias();
-    method public byte[] getEncryptedKeyMaterial();
+    method @NonNull public String getAlias();
+    method @NonNull public byte[] getEncryptedKeyMaterial();
+    method @Nullable public byte[] getMetadata();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.security.keystore.recovery.WrappedApplicationKey> CREATOR;
   }
 
   public static class WrappedApplicationKey.Builder {
     ctor public WrappedApplicationKey.Builder();
-    method public android.security.keystore.recovery.WrappedApplicationKey build();
-    method public android.security.keystore.recovery.WrappedApplicationKey.Builder setAlias(java.lang.String);
-    method public android.security.keystore.recovery.WrappedApplicationKey.Builder setEncryptedKeyMaterial(byte[]);
+    method @NonNull public android.security.keystore.recovery.WrappedApplicationKey build();
+    method public android.security.keystore.recovery.WrappedApplicationKey.Builder setAlias(@NonNull String);
+    method public android.security.keystore.recovery.WrappedApplicationKey.Builder setEncryptedKeyMaterial(@NonNull byte[]);
+    method public android.security.keystore.recovery.WrappedApplicationKey.Builder setMetadata(@Nullable byte[]);
+  }
+
+}
+
+package android.service.appprediction {
+
+  public abstract class AppPredictionService extends android.app.Service {
+    ctor public AppPredictionService();
+    method @MainThread public abstract void onAppTargetEvent(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull android.app.prediction.AppTargetEvent);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onCreatePredictionSession(@NonNull android.app.prediction.AppPredictionContext, @NonNull android.app.prediction.AppPredictionSessionId);
+    method @MainThread public void onDestroyPredictionSession(@NonNull android.app.prediction.AppPredictionSessionId);
+    method @MainThread public abstract void onLocationShown(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
+    method @MainThread public abstract void onRequestPredictionUpdate(@NonNull android.app.prediction.AppPredictionSessionId);
+    method @MainThread public abstract void onSortAppTargets(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull java.util.List<android.app.prediction.AppTarget>, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
+    method @MainThread public void onStartPredictionUpdates();
+    method @MainThread public void onStopPredictionUpdates();
+    method public final void updatePredictions(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull java.util.List<android.app.prediction.AppTarget>);
+  }
+
+}
+
+package android.service.attention {
+
+  public abstract class AttentionService extends android.app.Service {
+    ctor public AttentionService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onCancelAttentionCheck(int);
+    method public abstract void onCheckAttention(int, @NonNull android.service.attention.AttentionService.AttentionCallback);
+    field public static final int ATTENTION_FAILURE_PREEMPTED = 2; // 0x2
+    field public static final int ATTENTION_FAILURE_TIMED_OUT = 3; // 0x3
+    field public static final int ATTENTION_FAILURE_UNKNOWN = 4; // 0x4
+    field public static final int ATTENTION_SUCCESS_ABSENT = 0; // 0x0
+    field public static final int ATTENTION_SUCCESS_PRESENT = 1; // 0x1
+    field public static final String SERVICE_INTERFACE = "android.service.attention.AttentionService";
+  }
+
+  public static final class AttentionService.AttentionCallback {
+    method public void onFailure(int, int);
+    method public void onSuccess(int, int, long);
   }
 
 }
@@ -5172,13 +6066,13 @@
 
   public abstract class AutofillFieldClassificationService extends android.app.Service {
     method public android.os.IBinder onBind(android.content.Intent);
-    method public float[][] onCalculateScores(java.util.List<android.view.autofill.AutofillValue>, java.util.List<java.lang.String>, java.util.List<java.lang.String>, java.lang.String, android.os.Bundle, java.util.Map, java.util.Map);
-    method public deprecated float[][] onGetScores(java.lang.String, android.os.Bundle, java.util.List<android.view.autofill.AutofillValue>, java.util.List<java.lang.String>);
-    field public static final java.lang.String REQUIRED_ALGORITHM_EDIT_DISTANCE = "EDIT_DISTANCE";
-    field public static final java.lang.String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH";
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService";
-    field public static final java.lang.String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = "android.autofill.field_classification.available_algorithms";
-    field public static final java.lang.String SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM = "android.autofill.field_classification.default_algorithm";
+    method @Nullable public float[][] onCalculateScores(@NonNull java.util.List<android.view.autofill.AutofillValue>, @NonNull java.util.List<java.lang.String>, @NonNull java.util.List<java.lang.String>, @Nullable String, @Nullable android.os.Bundle, @Nullable java.util.Map, @Nullable java.util.Map);
+    method @Deprecated @Nullable public float[][] onGetScores(@Nullable String, @Nullable android.os.Bundle, @NonNull java.util.List<android.view.autofill.AutofillValue>, @NonNull java.util.List<java.lang.String>);
+    field public static final String REQUIRED_ALGORITHM_EDIT_DISTANCE = "EDIT_DISTANCE";
+    field public static final String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH";
+    field public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService";
+    field public static final String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = "android.autofill.field_classification.available_algorithms";
+    field public static final String SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM = "android.autofill.field_classification.default_algorithm";
   }
 
 }
@@ -5187,50 +6081,48 @@
 
   public abstract class AugmentedAutofillService extends android.app.Service {
     ctor public AugmentedAutofillService();
-    method public void onFillRequest(android.service.autofill.augmented.FillRequest, android.os.CancellationSignal, android.service.autofill.augmented.FillController, android.service.autofill.augmented.FillCallback);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.augmented.AugmentedAutofillService";
+    method protected final void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
+    method protected void dump(@NonNull java.io.PrintWriter, @NonNull String[]);
+    method public void onFillRequest(@NonNull android.service.autofill.augmented.FillRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.augmented.FillController, @NonNull android.service.autofill.augmented.FillCallback);
+    field public static final String SERVICE_INTERFACE = "android.service.autofill.augmented.AugmentedAutofillService";
   }
 
   public final class FillCallback {
-    method public void onSuccess(android.service.autofill.augmented.FillResponse);
+    method public void onSuccess(@Nullable android.service.autofill.augmented.FillResponse);
   }
 
   public final class FillController {
-    method public void autofill(java.util.List<android.util.Pair<android.view.autofill.AutofillId, android.view.autofill.AutofillValue>>);
+    method public void autofill(@NonNull java.util.List<android.util.Pair<android.view.autofill.AutofillId,android.view.autofill.AutofillValue>>);
   }
 
   public final class FillRequest {
-    method public android.content.ComponentName getActivityComponent();
-    method public android.view.autofill.AutofillId getFocusedId();
-    method public android.view.autofill.AutofillValue getFocusedValue();
-    method public android.service.autofill.augmented.PresentationParams getPresentationParams();
+    method @NonNull public android.content.ComponentName getActivityComponent();
+    method @NonNull public android.view.autofill.AutofillId getFocusedId();
+    method @NonNull public android.view.autofill.AutofillValue getFocusedValue();
+    method @Nullable public android.service.autofill.augmented.PresentationParams getPresentationParams();
     method public int getTaskId();
   }
 
-  public final class FillResponse implements android.os.Parcelable {
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.service.autofill.augmented.FillResponse> CREATOR;
+  public final class FillResponse {
   }
 
   public static final class FillResponse.Builder {
     ctor public FillResponse.Builder();
     method public android.service.autofill.augmented.FillResponse build();
-    method public android.service.autofill.augmented.FillResponse.Builder setFillWindow(android.service.autofill.augmented.FillWindow);
-    method public android.service.autofill.augmented.FillResponse.Builder setIgnoredIds(java.util.List<android.view.autofill.AutofillId>);
+    method public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@NonNull android.service.autofill.augmented.FillWindow);
+    method public android.service.autofill.augmented.FillResponse.Builder setIgnoredIds(@NonNull java.util.List<android.view.autofill.AutofillId>);
   }
 
   public final class FillWindow implements java.lang.AutoCloseable {
     ctor public FillWindow();
     method public void destroy();
-    method public boolean update(android.service.autofill.augmented.PresentationParams.Area, android.view.View, long);
-    field public static final long FLAG_METADATA_ADDRESS = 1L; // 0x1L
+    method public boolean update(@NonNull android.service.autofill.augmented.PresentationParams.Area, @NonNull android.view.View, long);
   }
 
   public abstract class PresentationParams {
     method public int getFlags();
-    method public android.service.autofill.augmented.PresentationParams.Area getFullArea();
-    method public android.service.autofill.augmented.PresentationParams.Area getSuggestionArea();
+    method @Nullable public android.service.autofill.augmented.PresentationParams.Area getFullArea();
+    method @Nullable public android.service.autofill.augmented.PresentationParams.Area getSuggestionArea();
     field public static final int FLAG_HINT_GRAVITY_BOTTOM = 2; // 0x2
     field public static final int FLAG_HINT_GRAVITY_LEFT = 4; // 0x4
     field public static final int FLAG_HINT_GRAVITY_RIGHT = 8; // 0x8
@@ -5239,9 +6131,9 @@
     field public static final int FLAG_HOST_SYSTEM = 32; // 0x20
   }
 
-  public static abstract class PresentationParams.Area {
-    method public android.graphics.Rect getBounds();
-    method public android.service.autofill.augmented.PresentationParams.Area getSubArea(android.graphics.Rect);
+  public abstract static class PresentationParams.Area {
+    method @NonNull public android.graphics.Rect getBounds();
+    method @Nullable public android.service.autofill.augmented.PresentationParams.Area getSubArea(@NonNull android.graphics.Rect);
   }
 
 }
@@ -5251,35 +6143,36 @@
   public abstract class ApnService extends android.app.Service {
     ctor public ApnService();
     method public android.os.IBinder onBind(android.content.Intent);
-    method public abstract java.util.List<android.content.ContentValues> onRestoreApns(int);
+    method @WorkerThread public abstract java.util.List<android.content.ContentValues> onRestoreApns(int);
   }
 
 }
 
 package android.service.contentcapture {
 
-  public final deprecated class ContentCaptureEventsRequest implements android.os.Parcelable {
-    method public int describeContents();
-    method public java.util.List<android.view.contentcapture.ContentCaptureEvent> getEvents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.service.contentcapture.ContentCaptureEventsRequest> CREATOR;
+  @Deprecated public final class ContentCaptureEventsRequest implements android.os.Parcelable {
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public java.util.List<android.view.contentcapture.ContentCaptureEvent> getEvents();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.service.contentcapture.ContentCaptureEventsRequest> CREATOR;
   }
 
   public abstract class ContentCaptureService extends android.app.Service {
     ctor public ContentCaptureService();
-    method public final java.util.Set<android.content.ComponentName> getContentCaptureDisabledActivities();
-    method public final java.util.Set<java.lang.String> getContentCaptureDisabledPackages();
-    method public void onActivitySnapshot(android.view.contentcapture.ContentCaptureSessionId, android.service.contentcapture.SnapshotData);
+    method @NonNull public final java.util.Set<android.content.ComponentName> getContentCaptureDisabledActivities();
+    method @NonNull public final java.util.Set<java.lang.String> getContentCaptureDisabledPackages();
+    method public void onActivitySnapshot(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.SnapshotData);
     method public void onConnected();
-    method public void onContentCaptureEvent(android.view.contentcapture.ContentCaptureSessionId, android.view.contentcapture.ContentCaptureEvent);
-    method public deprecated void onContentCaptureEventsRequest(android.view.contentcapture.ContentCaptureSessionId, android.service.contentcapture.ContentCaptureEventsRequest);
-    method public void onCreateContentCaptureSession(android.view.contentcapture.ContentCaptureContext, android.view.contentcapture.ContentCaptureSessionId);
-    method public void onDestroyContentCaptureSession(android.view.contentcapture.ContentCaptureSessionId);
+    method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent);
+    method @Deprecated public void onContentCaptureEventsRequest(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.ContentCaptureEventsRequest);
+    method public void onCreateContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureContext, @NonNull android.view.contentcapture.ContentCaptureSessionId);
+    method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId);
     method public void onDisconnected();
-    method public final void setActivityContentCaptureEnabled(android.content.ComponentName, boolean);
-    method public final void setContentCaptureWhitelist(java.util.List<java.lang.String>, java.util.List<android.content.ComponentName>);
-    method public final void setPackageContentCaptureEnabled(java.lang.String, boolean);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService";
+    method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest);
+    method public final void setActivityContentCaptureEnabled(@NonNull android.content.ComponentName, boolean);
+    method public final void setContentCaptureWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>);
+    method public final void setPackageContentCaptureEnabled(@NonNull String, boolean);
+    field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService";
   }
 
   public final class SnapshotData implements android.os.Parcelable {
@@ -5287,12 +6180,25 @@
     method public android.app.assist.AssistContent getAssistContent();
     method public android.os.Bundle getAssistData();
     method public android.app.assist.AssistStructure getAssistStructure();
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.contentcapture.SnapshotData> CREATOR;
   }
 
 }
 
+package android.service.contentsuggestions {
+
+  public abstract class ContentSuggestionsService extends android.app.Service {
+    ctor public ContentSuggestionsService();
+    method public abstract void classifyContentSelections(@NonNull android.app.contentsuggestions.ClassificationsRequest, @NonNull android.app.contentsuggestions.ContentSuggestionsManager.ClassificationsCallback);
+    method public abstract void notifyInteraction(@NonNull String, @NonNull android.os.Bundle);
+    method public abstract void processContextImage(int, @Nullable android.graphics.Bitmap, @NonNull android.os.Bundle);
+    method public abstract void suggestContentSelections(@NonNull android.app.contentsuggestions.SelectionsRequest, @NonNull android.app.contentsuggestions.ContentSuggestionsManager.SelectionsCallback);
+    field public static final String SERVICE_INTERFACE = "android.service.contentsuggestions.ContentSuggestionsService";
+  }
+
+}
+
 package android.service.euicc {
 
   public final class DownloadSubscriptionResult implements android.os.Parcelable {
@@ -5308,15 +6214,15 @@
   public final class EuiccProfileInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.service.carrier.CarrierIdentifier getCarrierIdentifier();
-    method public java.lang.String getIccid();
-    method public java.lang.String getNickname();
-    method public int getPolicyRules();
-    method public int getProfileClass();
-    method public java.lang.String getProfileName();
-    method public java.lang.String getServiceProviderName();
-    method public int getState();
-    method public java.util.List<android.telephony.UiccAccessRule> getUiccAccessRules();
-    method public boolean hasPolicyRule(int);
+    method public String getIccid();
+    method @Nullable public String getNickname();
+    method @android.service.euicc.EuiccProfileInfo.PolicyRule public int getPolicyRules();
+    method @android.service.euicc.EuiccProfileInfo.ProfileClass public int getProfileClass();
+    method public String getProfileName();
+    method public String getServiceProviderName();
+    method @android.service.euicc.EuiccProfileInfo.ProfileState public int getState();
+    method @Nullable public java.util.List<android.telephony.UiccAccessRule> getUiccAccessRules();
+    method public boolean hasPolicyRule(@android.service.euicc.EuiccProfileInfo.PolicyRule int);
     method public boolean hasPolicyRules();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.euicc.EuiccProfileInfo> CREATOR;
@@ -5331,98 +6237,102 @@
   }
 
   public static final class EuiccProfileInfo.Builder {
-    ctor public EuiccProfileInfo.Builder(java.lang.String);
+    ctor public EuiccProfileInfo.Builder(String);
     ctor public EuiccProfileInfo.Builder(android.service.euicc.EuiccProfileInfo);
     method public android.service.euicc.EuiccProfileInfo build();
     method public android.service.euicc.EuiccProfileInfo.Builder setCarrierIdentifier(android.service.carrier.CarrierIdentifier);
-    method public android.service.euicc.EuiccProfileInfo.Builder setIccid(java.lang.String);
-    method public android.service.euicc.EuiccProfileInfo.Builder setNickname(java.lang.String);
-    method public android.service.euicc.EuiccProfileInfo.Builder setPolicyRules(int);
-    method public android.service.euicc.EuiccProfileInfo.Builder setProfileClass(int);
-    method public android.service.euicc.EuiccProfileInfo.Builder setProfileName(java.lang.String);
-    method public android.service.euicc.EuiccProfileInfo.Builder setServiceProviderName(java.lang.String);
-    method public android.service.euicc.EuiccProfileInfo.Builder setState(int);
-    method public android.service.euicc.EuiccProfileInfo.Builder setUiccAccessRule(java.util.List<android.telephony.UiccAccessRule>);
+    method public android.service.euicc.EuiccProfileInfo.Builder setIccid(String);
+    method public android.service.euicc.EuiccProfileInfo.Builder setNickname(String);
+    method public android.service.euicc.EuiccProfileInfo.Builder setPolicyRules(@android.service.euicc.EuiccProfileInfo.PolicyRule int);
+    method public android.service.euicc.EuiccProfileInfo.Builder setProfileClass(@android.service.euicc.EuiccProfileInfo.ProfileClass int);
+    method public android.service.euicc.EuiccProfileInfo.Builder setProfileName(String);
+    method public android.service.euicc.EuiccProfileInfo.Builder setServiceProviderName(String);
+    method public android.service.euicc.EuiccProfileInfo.Builder setState(@android.service.euicc.EuiccProfileInfo.ProfileState int);
+    method public android.service.euicc.EuiccProfileInfo.Builder setUiccAccessRule(@Nullable java.util.List<android.telephony.UiccAccessRule>);
   }
 
-  public static abstract class EuiccProfileInfo.PolicyRule implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(flag=true, prefix={"POLICY_RULE_"}, value={android.service.euicc.EuiccProfileInfo.POLICY_RULE_DO_NOT_DISABLE, android.service.euicc.EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE, android.service.euicc.EuiccProfileInfo.POLICY_RULE_DELETE_AFTER_DISABLING}) public static @interface EuiccProfileInfo.PolicyRule {
   }
 
-  public static abstract class EuiccProfileInfo.ProfileClass implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"PROFILE_CLASS_"}, value={android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_TESTING, android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_PROVISIONING, android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL, 0xffffffff}) public static @interface EuiccProfileInfo.ProfileClass {
   }
 
-  public static abstract class EuiccProfileInfo.ProfileState implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"PROFILE_STATE_"}, value={android.service.euicc.EuiccProfileInfo.PROFILE_STATE_DISABLED, android.service.euicc.EuiccProfileInfo.PROFILE_STATE_ENABLED, 0xffffffff}) public static @interface EuiccProfileInfo.ProfileState {
   }
 
   public abstract class EuiccService extends android.app.Service {
     ctor public EuiccService();
-    method public android.os.IBinder onBind(android.content.Intent);
-    method public abstract int onDeleteSubscription(int, java.lang.String);
-    method public abstract android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, android.telephony.euicc.DownloadableSubscription, boolean, boolean, android.os.Bundle);
-    method public deprecated int onDownloadSubscription(int, android.telephony.euicc.DownloadableSubscription, boolean, boolean);
+    method @CallSuper public android.os.IBinder onBind(android.content.Intent);
+    method public abstract int onDeleteSubscription(int, String);
+    method public abstract android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @Nullable android.os.Bundle);
+    method @Deprecated public int onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean);
     method public abstract int onEraseSubscriptions(int);
     method public abstract android.service.euicc.GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int, boolean);
     method public abstract android.service.euicc.GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(int, android.telephony.euicc.DownloadableSubscription, boolean);
-    method public abstract java.lang.String onGetEid(int);
-    method public abstract android.telephony.euicc.EuiccInfo onGetEuiccInfo(int);
-    method public abstract android.service.euicc.GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int);
-    method public abstract int onGetOtaStatus(int);
+    method public abstract String onGetEid(int);
+    method @NonNull public abstract android.telephony.euicc.EuiccInfo onGetEuiccInfo(int);
+    method @NonNull public abstract android.service.euicc.GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int);
+    method @android.telephony.euicc.EuiccManager.OtaStatus public abstract int onGetOtaStatus(int);
     method public abstract int onRetainSubscriptionsForFactoryReset(int);
     method public abstract void onStartOtaIfNecessary(int, android.service.euicc.EuiccService.OtaStatusChangedCallback);
-    method public abstract int onSwitchToSubscription(int, java.lang.String, boolean);
-    method public abstract int onUpdateSubscriptionNickname(int, java.lang.String, java.lang.String);
-    field public static final java.lang.String ACTION_BIND_CARRIER_PROVISIONING_SERVICE = "android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE";
-    field public static final java.lang.String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
-    field public static final java.lang.String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
-    field public static final deprecated java.lang.String ACTION_RESOLVE_CONFIRMATION_CODE = "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE";
-    field public static final java.lang.String ACTION_RESOLVE_DEACTIVATE_SIM = "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM";
-    field public static final java.lang.String ACTION_RESOLVE_NO_PRIVILEGES = "android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
-    field public static final java.lang.String ACTION_RESOLVE_RESOLVABLE_ERRORS = "android.service.euicc.action.RESOLVE_RESOLVABLE_ERRORS";
-    field public static final java.lang.String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI";
-    field public static final java.lang.String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService";
-    field public static final java.lang.String EXTRA_RESOLUTION_ALLOW_POLICY_RULES = "android.service.euicc.extra.RESOLUTION_ALLOW_POLICY_RULES";
-    field public static final java.lang.String EXTRA_RESOLUTION_CALLING_PACKAGE = "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE";
-    field public static final java.lang.String EXTRA_RESOLUTION_CONFIRMATION_CODE = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE";
-    field public static final java.lang.String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
-    field public static final java.lang.String EXTRA_RESOLUTION_CONSENT = "android.service.euicc.extra.RESOLUTION_CONSENT";
-    field public static final java.lang.String EXTRA_RESOLVABLE_ERRORS = "android.service.euicc.extra.RESOLVABLE_ERRORS";
+    method public abstract int onSwitchToSubscription(int, @Nullable String, boolean);
+    method public abstract int onUpdateSubscriptionNickname(int, String, String);
+    field public static final String ACTION_BIND_CARRIER_PROVISIONING_SERVICE = "android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE";
+    field public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED = "android.service.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED";
+    field public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
+    field public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
+    field public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED = "android.service.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED";
+    field @Deprecated public static final String ACTION_RESOLVE_CONFIRMATION_CODE = "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE";
+    field public static final String ACTION_RESOLVE_DEACTIVATE_SIM = "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM";
+    field public static final String ACTION_RESOLVE_NO_PRIVILEGES = "android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
+    field public static final String ACTION_RESOLVE_RESOLVABLE_ERRORS = "android.service.euicc.action.RESOLVE_RESOLVABLE_ERRORS";
+    field public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED = "android.service.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED";
+    field public static final String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI";
+    field public static final String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService";
+    field public static final String EXTRA_RESOLUTION_ALLOW_POLICY_RULES = "android.service.euicc.extra.RESOLUTION_ALLOW_POLICY_RULES";
+    field public static final String EXTRA_RESOLUTION_CALLING_PACKAGE = "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE";
+    field public static final String EXTRA_RESOLUTION_CARD_ID = "android.service.euicc.extra.RESOLUTION_CARD_ID";
+    field public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE";
+    field public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
+    field public static final String EXTRA_RESOLUTION_CONSENT = "android.service.euicc.extra.RESOLUTION_CONSENT";
+    field public static final String EXTRA_RESOLVABLE_ERRORS = "android.service.euicc.extra.RESOLVABLE_ERRORS";
     field public static final int RESOLVABLE_ERROR_CONFIRMATION_CODE = 1; // 0x1
     field public static final int RESOLVABLE_ERROR_POLICY_RULES = 2; // 0x2
     field public static final int RESULT_FIRST_USER = 1; // 0x1
     field public static final int RESULT_MUST_DEACTIVATE_SIM = -1; // 0xffffffff
-    field public static final deprecated int RESULT_NEED_CONFIRMATION_CODE = -2; // 0xfffffffe
+    field @Deprecated public static final int RESULT_NEED_CONFIRMATION_CODE = -2; // 0xfffffffe
     field public static final int RESULT_OK = 0; // 0x0
     field public static final int RESULT_RESOLVABLE_ERRORS = -2; // 0xfffffffe
   }
 
-  public static abstract class EuiccService.OtaStatusChangedCallback {
+  public abstract static class EuiccService.OtaStatusChangedCallback {
     ctor public EuiccService.OtaStatusChangedCallback();
     method public abstract void onOtaStatusChanged(int);
   }
 
   public final class GetDefaultDownloadableSubscriptionListResult implements android.os.Parcelable {
-    ctor public GetDefaultDownloadableSubscriptionListResult(int, android.telephony.euicc.DownloadableSubscription[]);
+    ctor public GetDefaultDownloadableSubscriptionListResult(int, @Nullable android.telephony.euicc.DownloadableSubscription[]);
     method public int describeContents();
-    method public java.util.List<android.telephony.euicc.DownloadableSubscription> getDownloadableSubscriptions();
+    method @Nullable public java.util.List<android.telephony.euicc.DownloadableSubscription> getDownloadableSubscriptions();
     method public int getResult();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.euicc.GetDefaultDownloadableSubscriptionListResult> CREATOR;
   }
 
   public final class GetDownloadableSubscriptionMetadataResult implements android.os.Parcelable {
-    ctor public GetDownloadableSubscriptionMetadataResult(int, android.telephony.euicc.DownloadableSubscription);
+    ctor public GetDownloadableSubscriptionMetadataResult(int, @Nullable android.telephony.euicc.DownloadableSubscription);
     method public int describeContents();
-    method public android.telephony.euicc.DownloadableSubscription getDownloadableSubscription();
+    method @Nullable public android.telephony.euicc.DownloadableSubscription getDownloadableSubscription();
     method public int getResult();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.euicc.GetDownloadableSubscriptionMetadataResult> CREATOR;
   }
 
   public final class GetEuiccProfileInfoListResult implements android.os.Parcelable {
-    ctor public GetEuiccProfileInfoListResult(int, android.service.euicc.EuiccProfileInfo[], boolean);
+    ctor public GetEuiccProfileInfoListResult(int, @Nullable android.service.euicc.EuiccProfileInfo[], boolean);
     method public int describeContents();
     method public boolean getIsRemovable();
-    method public java.util.List<android.service.euicc.EuiccProfileInfo> getProfiles();
+    method @Nullable public java.util.List<android.service.euicc.EuiccProfileInfo> getProfiles();
     method public int getResult();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.euicc.GetEuiccProfileInfoListResult> CREATOR;
@@ -5433,40 +6343,40 @@
 package android.service.notification {
 
   public final class Adjustment implements android.os.Parcelable {
-    ctor public Adjustment(java.lang.String, java.lang.String, android.os.Bundle, java.lang.CharSequence, int);
+    ctor public Adjustment(String, String, android.os.Bundle, CharSequence, int);
     ctor protected Adjustment(android.os.Parcel);
     method public int describeContents();
-    method public java.lang.CharSequence getExplanation();
-    method public java.lang.String getKey();
-    method public java.lang.String getPackage();
+    method public CharSequence getExplanation();
+    method public String getKey();
+    method public String getPackage();
     method public android.os.Bundle getSignals();
     method public int getUser();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
-    field public static final java.lang.String KEY_IMPORTANCE = "key_importance";
-    field public static final java.lang.String KEY_PEOPLE = "key_people";
-    field public static final java.lang.String KEY_SMART_ACTIONS = "key_smart_actions";
-    field public static final java.lang.String KEY_SMART_REPLIES = "key_smart_replies";
-    field public static final java.lang.String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
-    field public static final java.lang.String KEY_USER_SENTIMENT = "key_user_sentiment";
+    field public static final String KEY_IMPORTANCE = "key_importance";
+    field public static final String KEY_PEOPLE = "key_people";
+    field public static final String KEY_SMART_ACTIONS = "key_smart_actions";
+    field public static final String KEY_SMART_REPLIES = "key_smart_replies";
+    field public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
+    field public static final String KEY_USER_SENTIMENT = "key_user_sentiment";
   }
 
   public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
     ctor public NotificationAssistantService();
     method public final void adjustNotification(android.service.notification.Adjustment);
     method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
-    method public void onActionClicked(java.lang.String, android.app.Notification.Action, int);
+    method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
     method public final android.os.IBinder onBind(android.content.Intent);
-    method public void onNotificationDirectReply(java.lang.String);
+    method public void onNotificationDirectReplied(@NonNull String);
     method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
     method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, android.app.NotificationChannel);
-    method public void onNotificationExpansionChanged(java.lang.String, boolean, boolean);
+    method public void onNotificationExpansionChanged(@NonNull String, boolean, boolean);
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, android.service.notification.NotificationStats, int);
-    method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
+    method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, String);
     method public void onNotificationsSeen(java.util.List<java.lang.String>);
-    method public void onSuggestedReplySent(java.lang.String, java.lang.CharSequence, int);
-    method public final void unsnoozeNotification(java.lang.String);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
+    method public void onSuggestedReplySent(@NonNull String, @NonNull CharSequence, int);
+    method public final void unsnoozeNotification(String);
+    field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
     field public static final int SOURCE_FROM_APP = 0; // 0x0
     field public static final int SOURCE_FROM_ASSISTANT = 1; // 0x1
   }
@@ -5504,12 +6414,12 @@
   }
 
   public final class SnoozeCriterion implements android.os.Parcelable {
-    ctor public SnoozeCriterion(java.lang.String, java.lang.CharSequence, java.lang.CharSequence);
+    ctor public SnoozeCriterion(String, CharSequence, CharSequence);
     ctor protected SnoozeCriterion(android.os.Parcel);
     method public int describeContents();
-    method public java.lang.CharSequence getConfirmation();
-    method public java.lang.CharSequence getExplanation();
-    method public java.lang.String getId();
+    method public CharSequence getConfirmation();
+    method public CharSequence getExplanation();
+    method public String getId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.notification.SnoozeCriterion> CREATOR;
   }
@@ -5519,11 +6429,11 @@
 package android.service.oemlock {
 
   public class OemLockManager {
-    method public java.lang.String getLockName();
-    method public boolean isOemUnlockAllowedByCarrier();
-    method public boolean isOemUnlockAllowedByUser();
-    method public void setOemUnlockAllowedByCarrier(boolean, byte[]);
-    method public void setOemUnlockAllowedByUser(boolean);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) @Nullable public String getLockName();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) public boolean isOemUnlockAllowedByCarrier();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USER_OEM_UNLOCK_STATE) public boolean isOemUnlockAllowedByUser();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) public void setOemUnlockAllowedByCarrier(boolean, @Nullable byte[]);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USER_OEM_UNLOCK_STATE) public void setOemUnlockAllowedByUser(boolean);
   }
 
 }
@@ -5531,20 +6441,20 @@
 package android.service.persistentdata {
 
   public class PersistentDataBlockManager {
-    method public int getDataBlockSize();
-    method public int getFlashLockState();
+    method @RequiresPermission("android.permission.ACCESS_PDB_STATE") public int getDataBlockSize();
+    method @RequiresPermission(anyOf={android.Manifest.permission.READ_OEM_UNLOCK_STATE, "android.permission.OEM_UNLOCK_STATE"}) @android.service.persistentdata.PersistentDataBlockManager.FlashLockState public int getFlashLockState();
     method public long getMaximumDataBlockSize();
-    method public deprecated boolean getOemUnlockEnabled();
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_OEM_UNLOCK_STATE, "android.permission.OEM_UNLOCK_STATE"}) public boolean getOemUnlockEnabled();
     method public byte[] read();
-    method public deprecated void setOemUnlockEnabled(boolean);
-    method public void wipe();
+    method @Deprecated @RequiresPermission("android.permission.OEM_UNLOCK_STATE") public void setOemUnlockEnabled(boolean);
+    method @RequiresPermission("android.permission.OEM_UNLOCK_STATE") public void wipe();
     method public int write(byte[]);
     field public static final int FLASH_LOCK_LOCKED = 1; // 0x1
     field public static final int FLASH_LOCK_UNKNOWN = -1; // 0xffffffff
     field public static final int FLASH_LOCK_UNLOCKED = 0; // 0x0
   }
 
-  public static abstract class PersistentDataBlockManager.FlashLockState implements java.lang.annotation.Annotation {
+  @IntDef(prefix={"FLASH_LOCK_"}, value={android.service.persistentdata.PersistentDataBlockManager.FLASH_LOCK_UNKNOWN, android.service.persistentdata.PersistentDataBlockManager.FLASH_LOCK_LOCKED, android.service.persistentdata.PersistentDataBlockManager.FLASH_LOCK_UNLOCKED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PersistentDataBlockManager.FlashLockState {
   }
 
 }
@@ -5552,7 +6462,7 @@
 package android.service.quicksettings {
 
   public class TileService extends android.app.Service {
-    method public final void setStatusIcon(android.graphics.drawable.Icon, java.lang.String);
+    method public final void setStatusIcon(android.graphics.drawable.Icon, String);
   }
 
 }
@@ -5564,9 +6474,9 @@
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onPredictSharingProbabilities(java.util.List<android.service.resolver.ResolverTarget>);
     method public void onTrainRankingModel(java.util.List<android.service.resolver.ResolverTarget>, int);
-    field public static final java.lang.String BIND_PERMISSION = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
-    field public static final java.lang.String HOLD_PERMISSION = "android.permission.PROVIDE_RESOLVER_RANKER_SERVICE";
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.resolver.ResolverRankerService";
+    field public static final String BIND_PERMISSION = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
+    field public static final String HOLD_PERMISSION = "android.permission.PROVIDE_RESOLVER_RANKER_SERVICE";
+    field public static final String SERVICE_INTERFACE = "android.service.resolver.ResolverRankerService";
   }
 
   public final class ResolverTarget implements android.os.Parcelable {
@@ -5594,23 +6504,23 @@
     method public int describeContents();
     method public int getFlags();
     method public android.graphics.drawable.Icon getIcon();
-    method public java.lang.String getId();
+    method public String getId();
     method public android.app.PendingIntent getPendingIntent();
-    method public java.lang.CharSequence getSummary();
-    method public java.lang.CharSequence getTitle();
+    method public CharSequence getSummary();
+    method public CharSequence getTitle();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.settings.suggestions.Suggestion> CREATOR;
     field public static final int FLAG_HAS_BUTTON = 1; // 0x1
   }
 
   public static class Suggestion.Builder {
-    ctor public Suggestion.Builder(java.lang.String);
+    ctor public Suggestion.Builder(String);
     method public android.service.settings.suggestions.Suggestion build();
     method public android.service.settings.suggestions.Suggestion.Builder setFlags(int);
     method public android.service.settings.suggestions.Suggestion.Builder setIcon(android.graphics.drawable.Icon);
     method public android.service.settings.suggestions.Suggestion.Builder setPendingIntent(android.app.PendingIntent);
-    method public android.service.settings.suggestions.Suggestion.Builder setSummary(java.lang.CharSequence);
-    method public android.service.settings.suggestions.Suggestion.Builder setTitle(java.lang.CharSequence);
+    method public android.service.settings.suggestions.Suggestion.Builder setSummary(CharSequence);
+    method public android.service.settings.suggestions.Suggestion.Builder setTitle(CharSequence);
   }
 
   public abstract class SuggestionService extends android.app.Service {
@@ -5627,8 +6537,8 @@
 
   public abstract class FinancialSmsService extends android.app.Service {
     method public android.os.IBinder onBind(android.content.Intent);
-    method public abstract android.database.CursorWindow onGetSmsMessages(android.os.Bundle);
-    field public static final java.lang.String ACTION_FINANCIAL_SERVICE_INTENT = "android.service.sms.action.FINANCIAL_SERVICE_INTENT";
+    method @Nullable public abstract android.database.CursorWindow onGetSmsMessages(@NonNull android.os.Bundle);
+    field public static final String ACTION_FINANCIAL_SERVICE_INTENT = "android.service.sms.action.FINANCIAL_SERVICE_INTENT";
   }
 
 }
@@ -5638,22 +6548,22 @@
   public abstract class TextClassifierService extends android.app.Service {
     ctor public TextClassifierService();
     method public final android.view.textclassifier.TextClassifier getLocalTextClassifier();
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract void onClassifyText(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.TextClassification.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextClassification>);
-    method public void onCreateTextClassificationSession(android.view.textclassifier.TextClassificationContext, android.view.textclassifier.TextClassificationSessionId);
-    method public void onDestroyTextClassificationSession(android.view.textclassifier.TextClassificationSessionId);
-    method public void onDetectLanguage(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.TextLanguage.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLanguage>);
-    method public abstract void onGenerateLinks(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.TextLinks.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLinks>);
-    method public deprecated void onSelectionEvent(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.SelectionEvent);
-    method public void onSuggestConversationActions(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.ConversationActions.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.ConversationActions>);
-    method public abstract void onSuggestSelection(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.TextSelection.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextSelection>);
-    method public void onTextClassifierEvent(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.TextClassifierEvent);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.textclassifier.TextClassifierService";
+    method @Nullable public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onClassifyText(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextClassification.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextClassification>);
+    method public void onCreateTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationContext, @NonNull android.view.textclassifier.TextClassificationSessionId);
+    method public void onDestroyTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationSessionId);
+    method public void onDetectLanguage(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextLanguage.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLanguage>);
+    method public abstract void onGenerateLinks(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextLinks.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLinks>);
+    method @Deprecated public void onSelectionEvent(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.SelectionEvent);
+    method public void onSuggestConversationActions(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.ConversationActions.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.ConversationActions>);
+    method public abstract void onSuggestSelection(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextSelection.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextSelection>);
+    method public void onTextClassifierEvent(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextClassifierEvent);
+    field public static final String SERVICE_INTERFACE = "android.service.textclassifier.TextClassifierService";
   }
 
-  public static abstract interface TextClassifierService.Callback<T> {
-    method public abstract void onFailure(java.lang.CharSequence);
-    method public abstract void onSuccess(T);
+  public static interface TextClassifierService.Callback<T> {
+    method public void onFailure(CharSequence);
+    method public void onSuccess(T);
   }
 
 }
@@ -5663,8 +6573,8 @@
   public class TrustAgentService extends android.app.Service {
     ctor public TrustAgentService();
     method public final void addEscrowToken(byte[], android.os.UserHandle);
-    method public final deprecated void grantTrust(java.lang.CharSequence, long, boolean);
-    method public final void grantTrust(java.lang.CharSequence, long, int);
+    method @Deprecated public final void grantTrust(CharSequence, long, boolean);
+    method public final void grantTrust(CharSequence, long, int);
     method public final void isEscrowTokenActive(long, android.os.UserHandle);
     method public final android.os.IBinder onBind(android.content.Intent);
     method public boolean onConfigure(java.util.List<android.os.PersistableBundle>);
@@ -5679,14 +6589,14 @@
     method public final void removeEscrowToken(long, android.os.UserHandle);
     method public final void revokeTrust();
     method public final void setManagingTrust(boolean);
-    method public final void showKeyguardErrorMessage(java.lang.CharSequence);
+    method public final void showKeyguardErrorMessage(@NonNull CharSequence);
     method public final void unlockUserWithToken(long, byte[], android.os.UserHandle);
     field public static final int FLAG_GRANT_TRUST_DISMISS_KEYGUARD = 2; // 0x2
     field public static final int FLAG_GRANT_TRUST_INITIATED_BY_USER = 1; // 0x1
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.trust.TrustAgentService";
+    field public static final String SERVICE_INTERFACE = "android.service.trust.TrustAgentService";
     field public static final int TOKEN_STATE_ACTIVE = 1; // 0x1
     field public static final int TOKEN_STATE_INACTIVE = 0; // 0x0
-    field public static final java.lang.String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
+    field public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
   }
 
 }
@@ -5702,55 +6612,55 @@
 
 package android.telecom {
 
-  public deprecated class AudioState implements android.os.Parcelable {
-    ctor public AudioState(boolean, int, int);
-    ctor public AudioState(android.telecom.AudioState);
-    ctor public AudioState(android.telecom.CallAudioState);
-    method public static java.lang.String audioRouteToString(int);
-    method public int describeContents();
-    method public int getRoute();
-    method public int getSupportedRouteMask();
-    method public boolean isMuted();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telecom.AudioState> CREATOR;
-    field public static final int ROUTE_BLUETOOTH = 2; // 0x2
-    field public static final int ROUTE_EARPIECE = 1; // 0x1
-    field public static final int ROUTE_SPEAKER = 8; // 0x8
-    field public static final int ROUTE_WIRED_HEADSET = 4; // 0x4
-    field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
+  @Deprecated public class AudioState implements android.os.Parcelable {
+    ctor @Deprecated public AudioState(boolean, int, int);
+    ctor @Deprecated public AudioState(android.telecom.AudioState);
+    ctor @Deprecated public AudioState(android.telecom.CallAudioState);
+    method @Deprecated public static String audioRouteToString(int);
+    method @Deprecated public int describeContents();
+    method @Deprecated public int getRoute();
+    method @Deprecated public int getSupportedRouteMask();
+    method @Deprecated public boolean isMuted();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final android.os.Parcelable.Creator<android.telecom.AudioState> CREATOR;
+    field @Deprecated public static final int ROUTE_BLUETOOTH = 2; // 0x2
+    field @Deprecated public static final int ROUTE_EARPIECE = 1; // 0x1
+    field @Deprecated public static final int ROUTE_SPEAKER = 8; // 0x8
+    field @Deprecated public static final int ROUTE_WIRED_HEADSET = 4; // 0x4
+    field @Deprecated public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
   }
 
   public final class Call {
-    method public deprecated void addListener(android.telecom.Call.Listener);
-    method public deprecated void removeListener(android.telecom.Call.Listener);
-    field public static final deprecated int STATE_PRE_DIAL_WAIT = 8; // 0x8
+    method @Deprecated public void addListener(android.telecom.Call.Listener);
+    method @Deprecated public void removeListener(android.telecom.Call.Listener);
+    field @Deprecated public static final int STATE_PRE_DIAL_WAIT = 8; // 0x8
   }
 
-  public static abstract deprecated class Call.Listener extends android.telecom.Call.Callback {
-    ctor public Call.Listener();
+  @Deprecated public abstract static class Call.Listener extends android.telecom.Call.Callback {
+    ctor @Deprecated public Call.Listener();
   }
 
   public abstract class Conference extends android.telecom.Conferenceable {
-    method public final deprecated android.telecom.AudioState getAudioState();
-    method public final deprecated long getConnectTimeMillis();
+    method @Deprecated public final android.telecom.AudioState getAudioState();
+    method @Deprecated public final long getConnectTimeMillis();
     method public android.telecom.Connection getPrimaryConnection();
-    method public deprecated void onAudioStateChanged(android.telecom.AudioState);
-    method public final deprecated void setConnectTimeMillis(long);
+    method @Deprecated public void onAudioStateChanged(android.telecom.AudioState);
+    method @Deprecated public final void setConnectTimeMillis(long);
   }
 
   public abstract class Connection extends android.telecom.Conferenceable {
-    method public final deprecated android.telecom.AudioState getAudioState();
-    method public deprecated void onAudioStateChanged(android.telecom.AudioState);
+    method @Deprecated public final android.telecom.AudioState getAudioState();
+    method @Deprecated public void onAudioStateChanged(android.telecom.AudioState);
   }
 
   public abstract class InCallService extends android.app.Service {
-    method public deprecated android.telecom.Phone getPhone();
-    method public deprecated void onPhoneCreated(android.telecom.Phone);
-    method public deprecated void onPhoneDestroyed(android.telecom.Phone);
+    method @Deprecated public android.telecom.Phone getPhone();
+    method @Deprecated public void onPhoneCreated(android.telecom.Phone);
+    method @Deprecated public void onPhoneDestroyed(android.telecom.Phone);
   }
 
   public class ParcelableCallAnalytics implements android.os.Parcelable {
-    ctor public ParcelableCallAnalytics(long, long, int, boolean, boolean, int, int, boolean, java.lang.String, boolean, java.util.List<android.telecom.ParcelableCallAnalytics.AnalyticsEvent>, java.util.List<android.telecom.ParcelableCallAnalytics.EventTiming>);
+    ctor public ParcelableCallAnalytics(long, long, int, boolean, boolean, int, int, boolean, String, boolean, java.util.List<android.telecom.ParcelableCallAnalytics.AnalyticsEvent>, java.util.List<android.telecom.ParcelableCallAnalytics.EventTiming>);
     ctor public ParcelableCallAnalytics(android.os.Parcel);
     method public java.util.List<android.telecom.ParcelableCallAnalytics.AnalyticsEvent> analyticsEvents();
     method public int describeContents();
@@ -5758,7 +6668,7 @@
     method public int getCallTechnologies();
     method public int getCallTerminationCode();
     method public int getCallType();
-    method public java.lang.String getConnectionService();
+    method public String getConnectionService();
     method public java.util.List<android.telecom.ParcelableCallAnalytics.EventTiming> getEventTimings();
     method public long getStartTimeMillis();
     method public boolean isAdditionalCall();
@@ -5847,27 +6757,27 @@
     field public static final int UNHOLD_TIMING = 4; // 0x4
   }
 
-  public final deprecated class Phone {
-    method public void addListener(android.telecom.Phone.Listener);
-    method public boolean canAddCall();
-    method public deprecated android.telecom.AudioState getAudioState();
-    method public android.telecom.CallAudioState getCallAudioState();
-    method public java.util.List<android.telecom.Call> getCalls();
-    method public void removeListener(android.telecom.Phone.Listener);
-    method public void requestBluetoothAudio(java.lang.String);
-    method public void setAudioRoute(int);
-    method public void setMuted(boolean);
+  @Deprecated public final class Phone {
+    method @Deprecated public void addListener(android.telecom.Phone.Listener);
+    method @Deprecated public boolean canAddCall();
+    method @Deprecated public android.telecom.AudioState getAudioState();
+    method @Deprecated public android.telecom.CallAudioState getCallAudioState();
+    method @Deprecated public java.util.List<android.telecom.Call> getCalls();
+    method @Deprecated public void removeListener(android.telecom.Phone.Listener);
+    method @Deprecated public void requestBluetoothAudio(String);
+    method @Deprecated public void setAudioRoute(int);
+    method @Deprecated public void setMuted(boolean);
   }
 
-  public static abstract class Phone.Listener {
-    ctor public Phone.Listener();
-    method public deprecated void onAudioStateChanged(android.telecom.Phone, android.telecom.AudioState);
-    method public void onBringToForeground(android.telecom.Phone, boolean);
-    method public void onCallAdded(android.telecom.Phone, android.telecom.Call);
-    method public void onCallAudioStateChanged(android.telecom.Phone, android.telecom.CallAudioState);
-    method public void onCallRemoved(android.telecom.Phone, android.telecom.Call);
-    method public void onCanAddCallChanged(android.telecom.Phone, boolean);
-    method public void onSilenceRinger(android.telecom.Phone);
+  @Deprecated public abstract static class Phone.Listener {
+    ctor @Deprecated public Phone.Listener();
+    method @Deprecated public void onAudioStateChanged(android.telecom.Phone, android.telecom.AudioState);
+    method @Deprecated public void onBringToForeground(android.telecom.Phone, boolean);
+    method @Deprecated public void onCallAdded(android.telecom.Phone, android.telecom.Call);
+    method @Deprecated public void onCallAudioStateChanged(android.telecom.Phone, android.telecom.CallAudioState);
+    method @Deprecated public void onCallRemoved(android.telecom.Phone, android.telecom.Call);
+    method @Deprecated public void onCanAddCallChanged(android.telecom.Phone, boolean);
+    method @Deprecated public void onSilenceRinger(android.telecom.Phone);
   }
 
   public final class PhoneAccount implements android.os.Parcelable {
@@ -5880,25 +6790,25 @@
 
   public class PhoneAccountSuggestionService extends android.app.Service {
     ctor public PhoneAccountSuggestionService();
-    method public void onAccountSuggestionRequest(java.lang.String);
+    method public void onAccountSuggestionRequest(@NonNull String);
     method public android.os.IBinder onBind(android.content.Intent);
-    method public final void suggestPhoneAccounts(java.lang.String, java.util.List<android.telecom.PhoneAccountSuggestion>);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService";
+    method public final void suggestPhoneAccounts(@NonNull String, @NonNull java.util.List<android.telecom.PhoneAccountSuggestion>);
+    field public static final String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService";
   }
 
   public final class RemoteConference {
-    method public deprecated void setAudioState(android.telecom.AudioState);
+    method @Deprecated public void setAudioState(android.telecom.AudioState);
   }
 
   public final class RemoteConnection {
-    method public deprecated void setAudioState(android.telecom.AudioState);
+    method @Deprecated public void setAudioState(android.telecom.AudioState);
   }
 
   public final class StatusHints implements android.os.Parcelable {
-    ctor public deprecated StatusHints(android.content.ComponentName, java.lang.CharSequence, int, android.os.Bundle);
-    method public deprecated android.graphics.drawable.Drawable getIcon(android.content.Context);
-    method public deprecated int getIconResId();
-    method public deprecated android.content.ComponentName getPackageName();
+    ctor @Deprecated public StatusHints(android.content.ComponentName, CharSequence, int, android.os.Bundle);
+    method @Deprecated public android.graphics.drawable.Drawable getIcon(android.content.Context);
+    method @Deprecated public int getIconResId();
+    method @Deprecated public android.content.ComponentName getPackageName();
   }
 
   public final class TelecomAnalytics implements android.os.Parcelable {
@@ -5913,7 +6823,7 @@
   public static final class TelecomAnalytics.SessionTiming implements android.os.Parcelable {
     ctor public TelecomAnalytics.SessionTiming(int, long);
     method public int describeContents();
-    method public java.lang.Integer getKey();
+    method public Integer getKey();
     method public long getTime();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telecom.TelecomAnalytics.SessionTiming> CREATOR;
@@ -5938,25 +6848,26 @@
 
   public class TelecomManager {
     method public void addNewUnknownCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
-    method public deprecated void clearAccounts();
+    method @Deprecated public void clearAccounts();
     method public void clearPhoneAccounts();
-    method public android.telecom.TelecomAnalytics dumpAnalytics();
-    method public void enablePhoneAccount(android.telecom.PhoneAccountHandle, boolean);
+    method @RequiresPermission(android.Manifest.permission.DUMP) public android.telecom.TelecomAnalytics dumpAnalytics();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enablePhoneAccount(android.telecom.PhoneAccountHandle, boolean);
     method public java.util.List<android.telecom.PhoneAccountHandle> getAllPhoneAccountHandles();
     method public java.util.List<android.telecom.PhoneAccount> getAllPhoneAccounts();
     method public int getAllPhoneAccountsCount();
     method public int getCallState();
     method public android.telecom.PhoneAccountHandle getConnectionManager();
-    method public int getCurrentTtyMode();
-    method public deprecated android.content.ComponentName getDefaultPhoneApp();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode();
+    method @Deprecated public 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 deprecated boolean setDefaultDialer(java.lang.String);
-    field public static final java.lang.String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
-    field public static final java.lang.String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
-    field public static final java.lang.String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE";
+    method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
+    method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
+    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.WRITE_SECURE_SETTINGS}) public boolean setDefaultDialer(String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(android.telecom.PhoneAccountHandle);
+    field public static final String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
+    field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
+    field public static final String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE";
     field public static final int TTY_MODE_FULL = 1; // 0x1
     field public static final int TTY_MODE_HCO = 2; // 0x2
     field public static final int TTY_MODE_OFF = 0; // 0x0
@@ -5972,11 +6883,412 @@
     field public static final int WWAN = 1; // 0x1
   }
 
+  public class CallAttributes implements android.os.Parcelable {
+    ctor public CallAttributes(android.telephony.PreciseCallState, int, android.telephony.CallQuality);
+    method public int describeContents();
+    method public android.telephony.CallQuality getCallQuality();
+    method public int getNetworkType();
+    method public android.telephony.PreciseCallState getPreciseCallState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR;
+  }
+
+  public final class CallQuality implements android.os.Parcelable {
+    ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int);
+    method public int describeContents();
+    method public int getAverageRelativeJitter();
+    method public int getAverageRoundTripTime();
+    method public int getCallDuration();
+    method public int getCodecType();
+    method public int getDownlinkCallQualityLevel();
+    method public int getMaxRelativeJitter();
+    method public int getNumRtpPacketsNotReceived();
+    method public int getNumRtpPacketsReceived();
+    method public int getNumRtpPacketsTransmitted();
+    method public int getNumRtpPacketsTransmittedLost();
+    method public int getUplinkCallQualityLevel();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CALL_QUALITY_BAD = 4; // 0x4
+    field public static final int CALL_QUALITY_EXCELLENT = 0; // 0x0
+    field public static final int CALL_QUALITY_FAIR = 2; // 0x2
+    field public static final int CALL_QUALITY_GOOD = 1; // 0x1
+    field public static final int CALL_QUALITY_NOT_AVAILABLE = 5; // 0x5
+    field public static final int CALL_QUALITY_POOR = 3; // 0x3
+    field public static final android.os.Parcelable.Creator<android.telephony.CallQuality> CREATOR;
+  }
+
   public class CarrierConfigManager {
-    method public static android.os.PersistableBundle getDefaultConfig();
-    method public void overrideConfig(int, android.os.PersistableBundle);
-    method public void updateConfigForPhoneId(int, java.lang.String);
-    field public static final java.lang.String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string";
+    method @NonNull public static android.os.PersistableBundle getDefaultConfig();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void overrideConfig(int, @Nullable android.os.PersistableBundle);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void updateConfigForPhoneId(int, String);
+    field public static final String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string";
+  }
+
+  public final class CarrierRestrictionRules implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers();
+    method public int getDefaultCarrierRestriction();
+    method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getExcludedCarriers();
+    method public int getMultiSimPolicy();
+    method public boolean isAllCarriersAllowed();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CARRIER_RESTRICTION_DEFAULT_ALLOWED = 1; // 0x1
+    field public static final int CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED = 0; // 0x0
+    field public static final android.os.Parcelable.Creator<android.telephony.CarrierRestrictionRules> CREATOR;
+    field public static final int MULTISIM_POLICY_NONE = 0; // 0x0
+    field public static final int MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT = 1; // 0x1
+  }
+
+  public static class CarrierRestrictionRules.Builder {
+    method public android.telephony.CarrierRestrictionRules build();
+    method public android.telephony.CarrierRestrictionRules.Builder setAllCarriersAllowed();
+    method public android.telephony.CarrierRestrictionRules.Builder setAllowedCarriers(java.util.List<android.service.carrier.CarrierIdentifier>);
+    method public android.telephony.CarrierRestrictionRules.Builder setDefaultCarrierRestriction(int);
+    method public android.telephony.CarrierRestrictionRules.Builder setExcludedCarriers(java.util.List<android.service.carrier.CarrierIdentifier>);
+    method public android.telephony.CarrierRestrictionRules.Builder setMultiSimPolicy(int);
+  }
+
+  public final class DataFailCause {
+    field public static final int ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 2219; // 0x8ab
+    field public static final int ACCESS_BLOCK = 2087; // 0x827
+    field public static final int ACCESS_BLOCK_ALL = 2088; // 0x828
+    field public static final int ACCESS_CLASS_DSAC_REJECTION = 2108; // 0x83c
+    field public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128; // 0x850
+    field public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 48; // 0x30
+    field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e
+    field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f
+    field public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 65; // 0x41
+    field public static final int APN_DISABLED = 2045; // 0x7fd
+    field public static final int APN_DISALLOWED_ON_ROAMING = 2059; // 0x80b
+    field public static final int APN_MISMATCH = 2054; // 0x806
+    field public static final int APN_PARAMETERS_CHANGED = 2060; // 0x80c
+    field public static final int APN_PENDING_HANDOVER = 2041; // 0x7f9
+    field public static final int APN_TYPE_CONFLICT = 112; // 0x70
+    field public static final int AUTH_FAILURE_ON_EMERGENCY_CALL = 122; // 0x7a
+    field public static final int BEARER_HANDLING_NOT_SUPPORTED = 60; // 0x3c
+    field public static final int CALL_DISALLOWED_IN_ROAMING = 2068; // 0x814
+    field public static final int CALL_PREEMPT_BY_EMERGENCY_APN = 127; // 0x7f
+    field public static final int CANNOT_ENCODE_OTA_MESSAGE = 2159; // 0x86f
+    field public static final int CDMA_ALERT_STOP = 2077; // 0x81d
+    field public static final int CDMA_INCOMING_CALL = 2076; // 0x81c
+    field public static final int CDMA_INTERCEPT = 2073; // 0x819
+    field public static final int CDMA_LOCK = 2072; // 0x818
+    field public static final int CDMA_RELEASE_DUE_TO_SO_REJECTION = 2075; // 0x81b
+    field public static final int CDMA_REORDER = 2074; // 0x81a
+    field public static final int CDMA_RETRY_ORDER = 2086; // 0x826
+    field public static final int CHANNEL_ACQUISITION_FAILURE = 2078; // 0x81e
+    field public static final int CLOSE_IN_PROGRESS = 2030; // 0x7ee
+    field public static final int COLLISION_WITH_NETWORK_INITIATED_REQUEST = 56; // 0x38
+    field public static final int COMPANION_IFACE_IN_USE = 118; // 0x76
+    field public static final int CONCURRENT_SERVICES_INCOMPATIBLE = 2083; // 0x823
+    field public static final int CONCURRENT_SERVICES_NOT_ALLOWED = 2091; // 0x82b
+    field public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 2080; // 0x820
+    field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64
+    field public static final int CONGESTION = 2106; // 0x83a
+    field public static final int CONNECTION_RELEASED = 2113; // 0x841
+    field public static final int CS_DOMAIN_NOT_AVAILABLE = 2181; // 0x885
+    field public static final int CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED = 2188; // 0x88c
+    field public static final int DATA_PLAN_EXPIRED = 2198; // 0x896
+    field public static final int DATA_ROAMING_SETTINGS_DISABLED = 2064; // 0x810
+    field public static final int DATA_SETTINGS_DISABLED = 2063; // 0x80f
+    field public static final int DBM_OR_SMS_IN_PROGRESS = 2211; // 0x8a3
+    field public static final int DDS_SWITCHED = 2065; // 0x811
+    field public static final int DDS_SWITCH_IN_PROGRESS = 2067; // 0x813
+    field public static final int DRB_RELEASED_BY_RRC = 2112; // 0x840
+    field public static final int DS_EXPLICIT_DEACTIVATION = 2125; // 0x84d
+    field public static final int DUAL_SWITCH = 2227; // 0x8b3
+    field public static final int DUN_CALL_DISALLOWED = 2056; // 0x808
+    field public static final int DUPLICATE_BEARER_ID = 2118; // 0x846
+    field public static final int EHRPD_TO_HRPD_FALLBACK = 2049; // 0x801
+    field public static final int EMBMS_NOT_ENABLED = 2193; // 0x891
+    field public static final int EMBMS_REGULAR_DEACTIVATION = 2195; // 0x893
+    field public static final int EMERGENCY_IFACE_ONLY = 116; // 0x74
+    field public static final int EMERGENCY_MODE = 2221; // 0x8ad
+    field public static final int EMM_ACCESS_BARRED = 115; // 0x73
+    field public static final int EMM_ACCESS_BARRED_INFINITE_RETRY = 121; // 0x79
+    field public static final int EMM_ATTACH_FAILED = 2115; // 0x843
+    field public static final int EMM_ATTACH_STARTED = 2116; // 0x844
+    field public static final int EMM_DETACHED = 2114; // 0x842
+    field public static final int EMM_T3417_EXPIRED = 2130; // 0x852
+    field public static final int EMM_T3417_EXT_EXPIRED = 2131; // 0x853
+    field public static final int EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED = 2178; // 0x882
+    field public static final int EPS_SERVICES_NOT_ALLOWED_IN_PLMN = 2179; // 0x883
+    field public static final int ERROR_UNSPECIFIED = 65535; // 0xffff
+    field public static final int ESM_BAD_OTA_MESSAGE = 2122; // 0x84a
+    field public static final int ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK = 2120; // 0x848
+    field public static final int ESM_COLLISION_SCENARIOS = 2119; // 0x847
+    field public static final int ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT = 2124; // 0x84c
+    field public static final int ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL = 2123; // 0x84b
+    field public static final int ESM_FAILURE = 2182; // 0x886
+    field public static final int ESM_INFO_NOT_RECEIVED = 53; // 0x35
+    field public static final int ESM_LOCAL_CAUSE_NONE = 2126; // 0x84e
+    field public static final int ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER = 2121; // 0x849
+    field public static final int ESM_PROCEDURE_TIME_OUT = 2155; // 0x86b
+    field public static final int ESM_UNKNOWN_EPS_BEARER_CONTEXT = 2111; // 0x83f
+    field public static final int EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE = 2201; // 0x899
+    field public static final int EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY = 2200; // 0x898
+    field public static final int EVDO_HDR_CHANGED = 2202; // 0x89a
+    field public static final int EVDO_HDR_CONNECTION_SETUP_TIMEOUT = 2206; // 0x89e
+    field public static final int EVDO_HDR_EXITED = 2203; // 0x89b
+    field public static final int EVDO_HDR_NO_SESSION = 2204; // 0x89c
+    field public static final int EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL = 2205; // 0x89d
+    field public static final int FADE = 2217; // 0x8a9
+    field public static final int FAILED_TO_ACQUIRE_COLOCATED_HDR = 2207; // 0x89f
+    field public static final int FEATURE_NOT_SUPP = 40; // 0x28
+    field public static final int FILTER_SEMANTIC_ERROR = 44; // 0x2c
+    field public static final int FILTER_SYTAX_ERROR = 45; // 0x2d
+    field public static final int FORBIDDEN_APN_NAME = 2066; // 0x812
+    field public static final int GPRS_REGISTRATION_FAIL = -2; // 0xfffffffe
+    field public static final int GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 2097; // 0x831
+    field public static final int GPRS_SERVICES_NOT_ALLOWED = 2098; // 0x832
+    field public static final int GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN = 2103; // 0x837
+    field public static final int HANDOFF_PREFERENCE_CHANGED = 2251; // 0x8cb
+    field public static final int HDR_ACCESS_FAILURE = 2213; // 0x8a5
+    field public static final int HDR_FADE = 2212; // 0x8a4
+    field public static final int HDR_NO_LOCK_GRANTED = 2210; // 0x8a2
+    field public static final int IFACE_AND_POL_FAMILY_MISMATCH = 120; // 0x78
+    field public static final int IFACE_MISMATCH = 117; // 0x75
+    field public static final int ILLEGAL_ME = 2096; // 0x830
+    field public static final int ILLEGAL_MS = 2095; // 0x82f
+    field public static final int IMEI_NOT_ACCEPTED = 2177; // 0x881
+    field public static final int IMPLICITLY_DETACHED = 2100; // 0x834
+    field public static final int IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER = 2176; // 0x880
+    field public static final int INCOMING_CALL_REJECTED = 2092; // 0x82c
+    field public static final int INSUFFICIENT_RESOURCES = 26; // 0x1a
+    field public static final int INTERFACE_IN_USE = 2058; // 0x80a
+    field public static final int INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 114; // 0x72
+    field public static final int INTERNAL_EPC_NONEPC_TRANSITION = 2057; // 0x809
+    field public static final int INVALID_CONNECTION_ID = 2156; // 0x86c
+    field public static final int INVALID_DNS_ADDR = 123; // 0x7b
+    field public static final int INVALID_EMM_STATE = 2190; // 0x88e
+    field public static final int INVALID_MANDATORY_INFO = 96; // 0x60
+    field public static final int INVALID_MODE = 2223; // 0x8af
+    field public static final int INVALID_PCSCF_ADDR = 113; // 0x71
+    field public static final int INVALID_PCSCF_OR_DNS_ADDRESS = 124; // 0x7c
+    field public static final int INVALID_PRIMARY_NSAPI = 2158; // 0x86e
+    field public static final int INVALID_SIM_STATE = 2224; // 0x8b0
+    field public static final int INVALID_TRANSACTION_ID = 81; // 0x51
+    field public static final int IPV6_ADDRESS_TRANSFER_FAILED = 2047; // 0x7ff
+    field public static final int IPV6_PREFIX_UNAVAILABLE = 2250; // 0x8ca
+    field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77
+    field public static final int IP_VERSION_MISMATCH = 2055; // 0x807
+    field public static final int IRAT_HANDOVER_FAILED = 2194; // 0x892
+    field public static final int IS707B_MAX_ACCESS_PROBES = 2089; // 0x829
+    field public static final int LIMITED_TO_IPV4 = 2234; // 0x8ba
+    field public static final int LIMITED_TO_IPV6 = 2235; // 0x8bb
+    field public static final int LLC_SNDCP = 25; // 0x19
+    field public static final int LOCAL_END = 2215; // 0x8a7
+    field public static final int LOCATION_AREA_NOT_ALLOWED = 2102; // 0x836
+    field public static final int LOST_CONNECTION = 65540; // 0x10004
+    field public static final int LOWER_LAYER_REGISTRATION_FAILURE = 2197; // 0x895
+    field public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 2044; // 0x7fc
+    field public static final int LTE_NAS_SERVICE_REQUEST_FAILED = 2117; // 0x845
+    field public static final int LTE_THROTTLING_NOT_REQUIRED = 2127; // 0x84f
+    field public static final int MAC_FAILURE = 2183; // 0x887
+    field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d
+    field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876
+    field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f
+    field public static final int MAX_IPV4_CONNECTIONS = 2052; // 0x804
+    field public static final int MAX_IPV6_CONNECTIONS = 2053; // 0x805
+    field public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
+    field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f
+    field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61
+    field public static final int MIP_CONFIG_FAILURE = 2050; // 0x802
+    field public static final int MIP_FA_ADMIN_PROHIBITED = 2001; // 0x7d1
+    field public static final int MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED = 2012; // 0x7dc
+    field public static final int MIP_FA_ENCAPSULATION_UNAVAILABLE = 2008; // 0x7d8
+    field public static final int MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE = 2004; // 0x7d4
+    field public static final int MIP_FA_INSUFFICIENT_RESOURCES = 2002; // 0x7d2
+    field public static final int MIP_FA_MALFORMED_REPLY = 2007; // 0x7d7
+    field public static final int MIP_FA_MALFORMED_REQUEST = 2006; // 0x7d6
+    field public static final int MIP_FA_MISSING_CHALLENGE = 2017; // 0x7e1
+    field public static final int MIP_FA_MISSING_HOME_ADDRESS = 2015; // 0x7df
+    field public static final int MIP_FA_MISSING_HOME_AGENT = 2014; // 0x7de
+    field public static final int MIP_FA_MISSING_NAI = 2013; // 0x7dd
+    field public static final int MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2003; // 0x7d3
+    field public static final int MIP_FA_REASON_UNSPECIFIED = 2000; // 0x7d0
+    field public static final int MIP_FA_REQUESTED_LIFETIME_TOO_LONG = 2005; // 0x7d5
+    field public static final int MIP_FA_REVERSE_TUNNEL_IS_MANDATORY = 2011; // 0x7db
+    field public static final int MIP_FA_REVERSE_TUNNEL_UNAVAILABLE = 2010; // 0x7da
+    field public static final int MIP_FA_STALE_CHALLENGE = 2018; // 0x7e2
+    field public static final int MIP_FA_UNKNOWN_CHALLENGE = 2016; // 0x7e0
+    field public static final int MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE = 2009; // 0x7d9
+    field public static final int MIP_HA_ADMIN_PROHIBITED = 2020; // 0x7e4
+    field public static final int MIP_HA_ENCAPSULATION_UNAVAILABLE = 2029; // 0x7ed
+    field public static final int MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE = 2023; // 0x7e7
+    field public static final int MIP_HA_INSUFFICIENT_RESOURCES = 2021; // 0x7e5
+    field public static final int MIP_HA_MALFORMED_REQUEST = 2025; // 0x7e9
+    field public static final int MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2022; // 0x7e6
+    field public static final int MIP_HA_REASON_UNSPECIFIED = 2019; // 0x7e3
+    field public static final int MIP_HA_REGISTRATION_ID_MISMATCH = 2024; // 0x7e8
+    field public static final int MIP_HA_REVERSE_TUNNEL_IS_MANDATORY = 2028; // 0x7ec
+    field public static final int MIP_HA_REVERSE_TUNNEL_UNAVAILABLE = 2027; // 0x7eb
+    field public static final int MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS = 2026; // 0x7ea
+    field public static final int MISSING_UNKNOWN_APN = 27; // 0x1b
+    field public static final int MODEM_APP_PREEMPTED = 2032; // 0x7f0
+    field public static final int MODEM_RESTART = 2037; // 0x7f5
+    field public static final int MSC_TEMPORARILY_NOT_REACHABLE = 2180; // 0x884
+    field public static final int MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101; // 0x65
+    field public static final int MSG_TYPE_NONCOMPATIBLE_STATE = 98; // 0x62
+    field public static final int MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK = 2099; // 0x833
+    field public static final int MULTIPLE_PDP_CALL_NOT_ALLOWED = 2192; // 0x890
+    field public static final int MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 55; // 0x37
+    field public static final int NAS_LAYER_FAILURE = 2191; // 0x88f
+    field public static final int NAS_REQUEST_REJECTED_BY_NETWORK = 2167; // 0x877
+    field public static final int NAS_SIGNALLING = 14; // 0xe
+    field public static final int NETWORK_FAILURE = 38; // 0x26
+    field public static final int NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH = 2154; // 0x86a
+    field public static final int NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH = 2153; // 0x869
+    field public static final int NETWORK_INITIATED_TERMINATION = 2031; // 0x7ef
+    field public static final int NONE = 0; // 0x0
+    field public static final int NON_IP_NOT_SUPPORTED = 2069; // 0x815
+    field public static final int NORMAL_RELEASE = 2218; // 0x8aa
+    field public static final int NO_CDMA_SERVICE = 2084; // 0x824
+    field public static final int NO_COLLOCATED_HDR = 2225; // 0x8b1
+    field public static final int NO_EPS_BEARER_CONTEXT_ACTIVATED = 2189; // 0x88d
+    field public static final int NO_GPRS_CONTEXT = 2094; // 0x82e
+    field public static final int NO_HYBRID_HDR_SERVICE = 2209; // 0x8a1
+    field public static final int NO_PDP_CONTEXT_ACTIVATED = 2107; // 0x83b
+    field public static final int NO_RESPONSE_FROM_BASE_STATION = 2081; // 0x821
+    field public static final int NO_SERVICE = 2216; // 0x8a8
+    field public static final int NO_SERVICE_ON_GATEWAY = 2093; // 0x82d
+    field public static final int NSAPI_IN_USE = 35; // 0x23
+    field public static final int NULL_APN_DISALLOWED = 2061; // 0x80d
+    field public static final int OEM_DCFAILCAUSE_1 = 4097; // 0x1001
+    field public static final int OEM_DCFAILCAUSE_10 = 4106; // 0x100a
+    field public static final int OEM_DCFAILCAUSE_11 = 4107; // 0x100b
+    field public static final int OEM_DCFAILCAUSE_12 = 4108; // 0x100c
+    field public static final int OEM_DCFAILCAUSE_13 = 4109; // 0x100d
+    field public static final int OEM_DCFAILCAUSE_14 = 4110; // 0x100e
+    field public static final int OEM_DCFAILCAUSE_15 = 4111; // 0x100f
+    field public static final int OEM_DCFAILCAUSE_2 = 4098; // 0x1002
+    field public static final int OEM_DCFAILCAUSE_3 = 4099; // 0x1003
+    field public static final int OEM_DCFAILCAUSE_4 = 4100; // 0x1004
+    field public static final int OEM_DCFAILCAUSE_5 = 4101; // 0x1005
+    field public static final int OEM_DCFAILCAUSE_6 = 4102; // 0x1006
+    field public static final int OEM_DCFAILCAUSE_7 = 4103; // 0x1007
+    field public static final int OEM_DCFAILCAUSE_8 = 4104; // 0x1008
+    field public static final int OEM_DCFAILCAUSE_9 = 4105; // 0x1009
+    field public static final int ONLY_IPV4V6_ALLOWED = 57; // 0x39
+    field public static final int ONLY_IPV4_ALLOWED = 50; // 0x32
+    field public static final int ONLY_IPV6_ALLOWED = 51; // 0x33
+    field public static final int ONLY_NON_IP_ALLOWED = 58; // 0x3a
+    field public static final int ONLY_SINGLE_BEARER_ALLOWED = 52; // 0x34
+    field public static final int OPERATOR_BARRED = 8; // 0x8
+    field public static final int OTASP_COMMIT_IN_PROGRESS = 2208; // 0x8a0
+    field public static final int PDN_CONN_DOES_NOT_EXIST = 54; // 0x36
+    field public static final int PDN_INACTIVITY_TIMER_EXPIRED = 2051; // 0x803
+    field public static final int PDN_IPV4_CALL_DISALLOWED = 2033; // 0x7f1
+    field public static final int PDN_IPV4_CALL_THROTTLED = 2034; // 0x7f2
+    field public static final int PDN_IPV6_CALL_DISALLOWED = 2035; // 0x7f3
+    field public static final int PDN_IPV6_CALL_THROTTLED = 2036; // 0x7f4
+    field public static final int PDN_NON_IP_CALL_DISALLOWED = 2071; // 0x817
+    field public static final int PDN_NON_IP_CALL_THROTTLED = 2070; // 0x816
+    field public static final int PDP_ACTIVATE_MAX_RETRY_FAILED = 2109; // 0x83d
+    field public static final int PDP_DUPLICATE = 2104; // 0x838
+    field public static final int PDP_ESTABLISH_TIMEOUT_EXPIRED = 2161; // 0x871
+    field public static final int PDP_INACTIVE_TIMEOUT_EXPIRED = 2163; // 0x873
+    field public static final int PDP_LOWERLAYER_ERROR = 2164; // 0x874
+    field public static final int PDP_MODIFY_COLLISION = 2165; // 0x875
+    field public static final int PDP_MODIFY_TIMEOUT_EXPIRED = 2162; // 0x872
+    field public static final int PDP_PPP_NOT_SUPPORTED = 2038; // 0x7f6
+    field public static final int PDP_WITHOUT_ACTIVE_TFT = 46; // 0x2e
+    field public static final int PHONE_IN_USE = 2222; // 0x8ae
+    field public static final int PHYSICAL_LINK_CLOSE_IN_PROGRESS = 2040; // 0x7f8
+    field public static final int PLMN_NOT_ALLOWED = 2101; // 0x835
+    field public static final int PPP_AUTH_FAILURE = 2229; // 0x8b5
+    field public static final int PPP_CHAP_FAILURE = 2232; // 0x8b8
+    field public static final int PPP_CLOSE_IN_PROGRESS = 2233; // 0x8b9
+    field public static final int PPP_OPTION_MISMATCH = 2230; // 0x8b6
+    field public static final int PPP_PAP_FAILURE = 2231; // 0x8b7
+    field public static final int PPP_TIMEOUT = 2228; // 0x8b4
+    field public static final int PREF_RADIO_TECH_CHANGED = -4; // 0xfffffffc
+    field public static final int PROFILE_BEARER_INCOMPATIBLE = 2042; // 0x7fa
+    field public static final int PROTOCOL_ERRORS = 111; // 0x6f
+    field public static final int QOS_NOT_ACCEPTED = 37; // 0x25
+    field public static final int RADIO_ACCESS_BEARER_FAILURE = 2110; // 0x83e
+    field public static final int RADIO_ACCESS_BEARER_SETUP_FAILURE = 2160; // 0x870
+    field public static final int RADIO_NOT_AVAILABLE = 65537; // 0x10001
+    field public static final int RADIO_POWER_OFF = -5; // 0xfffffffb
+    field public static final int REDIRECTION_OR_HANDOFF_IN_PROGRESS = 2220; // 0x8ac
+    field public static final int REGISTRATION_FAIL = -1; // 0xffffffff
+    field public static final int REGULAR_DEACTIVATION = 36; // 0x24
+    field public static final int REJECTED_BY_BASE_STATION = 2082; // 0x822
+    field public static final int RRC_CONNECTION_ABORTED_AFTER_HANDOVER = 2173; // 0x87d
+    field public static final int RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE = 2174; // 0x87e
+    field public static final int RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE = 2171; // 0x87b
+    field public static final int RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE = 2175; // 0x87f
+    field public static final int RRC_CONNECTION_ABORT_REQUEST = 2151; // 0x867
+    field public static final int RRC_CONNECTION_ACCESS_BARRED = 2139; // 0x85b
+    field public static final int RRC_CONNECTION_ACCESS_STRATUM_FAILURE = 2137; // 0x859
+    field public static final int RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS = 2138; // 0x85a
+    field public static final int RRC_CONNECTION_CELL_NOT_CAMPED = 2144; // 0x860
+    field public static final int RRC_CONNECTION_CELL_RESELECTION = 2140; // 0x85c
+    field public static final int RRC_CONNECTION_CONFIG_FAILURE = 2141; // 0x85d
+    field public static final int RRC_CONNECTION_INVALID_REQUEST = 2168; // 0x878
+    field public static final int RRC_CONNECTION_LINK_FAILURE = 2143; // 0x85f
+    field public static final int RRC_CONNECTION_NORMAL_RELEASE = 2147; // 0x863
+    field public static final int RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER = 2150; // 0x866
+    field public static final int RRC_CONNECTION_RADIO_LINK_FAILURE = 2148; // 0x864
+    field public static final int RRC_CONNECTION_REESTABLISHMENT_FAILURE = 2149; // 0x865
+    field public static final int RRC_CONNECTION_REJECT_BY_NETWORK = 2146; // 0x862
+    field public static final int RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE = 2172; // 0x87c
+    field public static final int RRC_CONNECTION_RF_UNAVAILABLE = 2170; // 0x87a
+    field public static final int RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR = 2152; // 0x868
+    field public static final int RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE = 2145; // 0x861
+    field public static final int RRC_CONNECTION_TIMER_EXPIRED = 2142; // 0x85e
+    field public static final int RRC_CONNECTION_TRACKING_AREA_ID_CHANGED = 2169; // 0x879
+    field public static final int RRC_UPLINK_CONNECTION_RELEASE = 2134; // 0x856
+    field public static final int RRC_UPLINK_DATA_TRANSMISSION_FAILURE = 2132; // 0x854
+    field public static final int RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER = 2133; // 0x855
+    field public static final int RRC_UPLINK_ERROR_REQUEST_FROM_NAS = 2136; // 0x858
+    field public static final int RRC_UPLINK_RADIO_LINK_FAILURE = 2135; // 0x857
+    field public static final int RUIM_NOT_PRESENT = 2085; // 0x825
+    field public static final int SECURITY_MODE_REJECTED = 2186; // 0x88a
+    field public static final int SERVICE_NOT_ALLOWED_ON_PLMN = 2129; // 0x851
+    field public static final int SERVICE_OPTION_NOT_SUBSCRIBED = 33; // 0x21
+    field public static final int SERVICE_OPTION_NOT_SUPPORTED = 32; // 0x20
+    field public static final int SERVICE_OPTION_OUT_OF_ORDER = 34; // 0x22
+    field public static final int SIGNAL_LOST = -3; // 0xfffffffd
+    field public static final int SIM_CARD_CHANGED = 2043; // 0x7fb
+    field public static final int SYNCHRONIZATION_FAILURE = 2184; // 0x888
+    field public static final int TEST_LOOPBACK_REGULAR_DEACTIVATION = 2196; // 0x894
+    field public static final int TETHERED_CALL_ACTIVE = -6; // 0xfffffffa
+    field public static final int TFT_SEMANTIC_ERROR = 41; // 0x29
+    field public static final int TFT_SYTAX_ERROR = 42; // 0x2a
+    field public static final int THERMAL_EMERGENCY = 2090; // 0x82a
+    field public static final int THERMAL_MITIGATION = 2062; // 0x80e
+    field public static final int TRAT_SWAP_FAILED = 2048; // 0x800
+    field public static final int UE_INITIATED_DETACH_OR_DISCONNECT = 128; // 0x80
+    field public static final int UE_IS_ENTERING_POWERSAVE_MODE = 2226; // 0x8b2
+    field public static final int UE_RAT_CHANGE = 2105; // 0x839
+    field public static final int UE_SECURITY_CAPABILITIES_MISMATCH = 2185; // 0x889
+    field public static final int UMTS_HANDOVER_TO_IWLAN = 2199; // 0x897
+    field public static final int UMTS_REACTIVATION_REQ = 39; // 0x27
+    field public static final int UNACCEPTABLE_NON_EPS_AUTHENTICATION = 2187; // 0x88b
+    field public static final int UNKNOWN = 65536; // 0x10000
+    field public static final int UNKNOWN_INFO_ELEMENT = 99; // 0x63
+    field public static final int UNKNOWN_PDP_ADDRESS_TYPE = 28; // 0x1c
+    field public static final int UNKNOWN_PDP_CONTEXT = 43; // 0x2b
+    field public static final int UNPREFERRED_RAT = 2039; // 0x7f7
+    field public static final int UNSUPPORTED_1X_PREV = 2214; // 0x8a6
+    field public static final int UNSUPPORTED_APN_IN_CURRENT_PLMN = 66; // 0x42
+    field public static final int UNSUPPORTED_QCI_VALUE = 59; // 0x3b
+    field public static final int USER_AUTHENTICATION = 29; // 0x1d
+    field public static final int VSNCP_ADMINISTRATIVELY_PROHIBITED = 2245; // 0x8c5
+    field public static final int VSNCP_APN_UNATHORIZED = 2238; // 0x8be
+    field public static final int VSNCP_GEN_ERROR = 2237; // 0x8bd
+    field public static final int VSNCP_INSUFFICIENT_PARAMETERS = 2243; // 0x8c3
+    field public static final int VSNCP_NO_PDN_GATEWAY_ADDRESS = 2240; // 0x8c0
+    field public static final int VSNCP_PDN_EXISTS_FOR_THIS_APN = 2248; // 0x8c8
+    field public static final int VSNCP_PDN_GATEWAY_REJECT = 2242; // 0x8c2
+    field public static final int VSNCP_PDN_GATEWAY_UNREACHABLE = 2241; // 0x8c1
+    field public static final int VSNCP_PDN_ID_IN_USE = 2246; // 0x8c6
+    field public static final int VSNCP_PDN_LIMIT_EXCEEDED = 2239; // 0x8bf
+    field public static final int VSNCP_RECONNECT_NOT_ALLOWED = 2249; // 0x8c9
+    field public static final int VSNCP_RESOURCE_UNAVAILABLE = 2244; // 0x8c4
+    field public static final int VSNCP_SUBSCRIBER_LIMITATION = 2247; // 0x8c7
+    field public static final int VSNCP_TIMEOUT = 2236; // 0x8bc
   }
 
   public class DisconnectCause {
@@ -6056,20 +7368,32 @@
     field public static final int WIFI_LOST = 59; // 0x3b
   }
 
+  public final class LteVopsSupportInfo implements android.os.Parcelable {
+    ctor public LteVopsSupportInfo(int, int);
+    method public int describeContents();
+    method public int getEmcBearerSupport();
+    method public int getVopsSupport();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.LteVopsSupportInfo> CREATOR;
+    field public static final int LTE_STATUS_NOT_AVAILABLE = 1; // 0x1
+    field public static final int LTE_STATUS_NOT_SUPPORTED = 3; // 0x3
+    field public static final int LTE_STATUS_SUPPORTED = 2; // 0x2
+  }
+
   public class MbmsDownloadSession implements java.lang.AutoCloseable {
-    field public static final java.lang.String MBMS_DOWNLOAD_SERVICE_ACTION = "android.telephony.action.EmbmsDownload";
+    field public static final 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";
+    field public static final 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";
+    field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
   }
 
   public class NetworkRegistrationState implements android.os.Parcelable {
-    ctor public NetworkRegistrationState(int, int, int, int, int, boolean, int[], android.telephony.CellIdentity);
+    ctor public NetworkRegistrationState(int, int, int, int, int, boolean, int[], @Nullable android.telephony.CellIdentity);
     ctor protected NetworkRegistrationState(android.os.Parcel);
     method public int describeContents();
     method public int getAccessNetworkTechnology();
@@ -6102,7 +7426,7 @@
   public abstract class NetworkService extends android.app.Service {
     ctor public NetworkService();
     method protected abstract android.telephony.NetworkService.NetworkServiceProvider createNetworkServiceProvider(int);
-    field public static final java.lang.String NETWORK_SERVICE_INTERFACE = "android.telephony.NetworkService";
+    field public static final String NETWORK_SERVICE_INTERFACE = "android.telephony.NetworkService";
   }
 
   public abstract class NetworkService.NetworkServiceProvider implements java.lang.AutoCloseable {
@@ -6123,8 +7447,8 @@
     field public static final int RESULT_SUCCESS = 0; // 0x0
   }
 
-  public abstract interface NumberVerificationCallback {
-    method public default void onCallReceived(java.lang.String);
+  public interface NumberVerificationCallback {
+    method public default void onCallReceived(@NonNull String);
     method public default void onVerificationFailed(int);
     field public static final int REASON_CONCURRENT_REQUESTS = 4; // 0x4
     field public static final int REASON_IN_ECBM = 5; // 0x5
@@ -6136,23 +7460,27 @@
   }
 
   public final class PhoneNumberRange implements android.os.Parcelable {
-    ctor public PhoneNumberRange(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    ctor public PhoneNumberRange(@NonNull String, @NonNull String, @NonNull String, @NonNull String);
     method public int describeContents();
-    method public boolean matches(java.lang.String);
+    method public boolean matches(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.PhoneNumberRange> CREATOR;
   }
 
   public class PhoneStateListener {
+    method public void onCallAttributesChanged(android.telephony.CallAttributes);
     method public void onCallDisconnectCauseChanged(int, int);
     method public void onPreciseCallStateChanged(android.telephony.PreciseCallState);
+    method public void onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState);
     method public void onRadioPowerStateChanged(int);
     method public void onSrvccStateChanged(int);
     method public void onVoiceActivationStateChanged(int);
+    field public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
     field public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
     field public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
+    field public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
     field public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
-    field public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000
+    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000
     field public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
   }
 
@@ -6175,6 +7503,16 @@
     field public static final int PRECISE_CALL_STATE_WAITING = 6; // 0x6
   }
 
+  public final class PreciseDataConnectionState implements android.os.Parcelable {
+    method public int describeContents();
+    method public String getDataConnectionApn();
+    method public int getDataConnectionApnTypeBitMask();
+    method public int getDataConnectionFailCause();
+    method public int getDataConnectionState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.PreciseDataConnectionState> CREATOR;
+  }
+
   public class PreciseDisconnectCause {
     field public static final int ACCESS_CLASS_BLOCKED = 260; // 0x104
     field public static final int ACCESS_INFORMATION_DISCARDED = 43; // 0x2b
@@ -6275,8 +7613,8 @@
   public class ServiceState implements android.os.Parcelable {
     method public android.telephony.NetworkRegistrationState getNetworkRegistrationState(int, int);
     method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates();
-    method public deprecated java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates(int);
-    method public deprecated android.telephony.NetworkRegistrationState getNetworkRegistrationStates(int, int);
+    method @Deprecated public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates(int);
+    method @Deprecated public android.telephony.NetworkRegistrationState getNetworkRegistrationStates(int, int);
     method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStatesForDomain(int);
     method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStatesForTransportType(int);
     field public static final int ROAMING_TYPE_DOMESTIC = 2; // 0x2
@@ -6286,7 +7624,7 @@
   }
 
   public final class SmsManager {
-    method public void sendMultipartTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>);
     field public static final int RESULT_CANCELLED = 23; // 0x17
     field public static final int RESULT_ENCODING_ERROR = 18; // 0x12
     field public static final int RESULT_ERROR_FDN_CHECK_FAILURE = 6; // 0x6
@@ -6308,17 +7646,26 @@
   }
 
   public class SubscriptionInfo implements android.os.Parcelable {
-    method public java.util.List<android.telephony.UiccAccessRule> getAccessRules();
+    method @Nullable public java.util.List<android.telephony.UiccAccessRule> getAccessRules();
     method public int getCardId();
+    method public int getProfileClass();
   }
 
   public class SubscriptionManager {
     method public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEnabledSubscriptionId(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSubscriptionEnabled(int);
     method public void requestEmbeddedSubscriptionInfoListRefresh();
     method public void requestEmbeddedSubscriptionInfoListRefresh(int);
-    method public void setDefaultDataSubId(int);
-    method public void setDefaultSmsSubId(int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultDataSubId(int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultSmsSubId(int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSubscriptionEnabled(int, boolean);
     field public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI;
+    field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff
+    field public static final int PROFILE_CLASS_OPERATIONAL = 2; // 0x2
+    field public static final int PROFILE_CLASS_PROVISIONING = 1; // 0x1
+    field public static final int PROFILE_CLASS_TESTING = 0; // 0x0
+    field public static final int PROFILE_CLASS_UNSET = -1; // 0xffffffff
     field public static final android.net.Uri VT_ENABLED_CONTENT_URI;
     field public static final android.net.Uri WFC_ENABLED_CONTENT_URI;
     field public static final android.net.Uri WFC_MODE_CONTENT_URI;
@@ -6327,9 +7674,9 @@
   }
 
   public static class SubscriptionPlan.Builder {
-    method public static deprecated android.telephony.SubscriptionPlan.Builder createRecurringDaily(java.time.ZonedDateTime);
-    method public static deprecated android.telephony.SubscriptionPlan.Builder createRecurringMonthly(java.time.ZonedDateTime);
-    method public static deprecated android.telephony.SubscriptionPlan.Builder createRecurringWeekly(java.time.ZonedDateTime);
+    method @Deprecated public static android.telephony.SubscriptionPlan.Builder createRecurringDaily(java.time.ZonedDateTime);
+    method @Deprecated public static android.telephony.SubscriptionPlan.Builder createRecurringMonthly(java.time.ZonedDateTime);
+    method @Deprecated public static android.telephony.SubscriptionPlan.Builder createRecurringWeekly(java.time.ZonedDateTime);
   }
 
   public final class TelephonyHistogram implements android.os.Parcelable {
@@ -6353,84 +7700,89 @@
   }
 
   public class TelephonyManager {
-    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);
-    method public void dial(java.lang.String);
-    method public boolean disableDataConnectivity();
-    method public boolean enableDataConnectivity();
-    method public void enableVideoCalling(boolean);
-    method public java.lang.String getAidForAppType(int);
-    method public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
-    method public int getCardIdForDefaultEuicc();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String);
+    method public int checkCarrierPrivilegesForPackage(String);
+    method public int checkCarrierPrivilegesForPackageAnyPhone(String);
+    method public void dial(String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean disableDataConnectivity();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableDataConnectivity();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableModemForSlot(int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getCardIdForDefaultEuicc();
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
-    method public java.lang.String getCdmaMdn();
-    method public java.lang.String getCdmaMdn(int);
-    method public java.lang.String getCdmaMin();
-    method public java.lang.String getCdmaMin(int);
-    method public java.lang.String getCdmaPrlVersion();
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(int);
+    method public String getCdmaPrlVersion();
     method public int getCurrentPhoneType();
     method public int getCurrentPhoneType(int);
-    method public int getDataActivationState();
-    method public deprecated boolean getDataEnabled();
-    method public deprecated boolean getDataEnabled(int);
-    method public boolean getEmergencyCallbackMode();
-    method public java.lang.String getIsimDomain();
-    method public int getPreferredNetworkTypeBitmap();
-    method public int getRadioPowerState();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getDataActivationState();
+    method @Deprecated public boolean getDataEnabled();
+    method @Deprecated public boolean getDataEnabled(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getPreferredNetworkTypeBitmap();
+    method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState();
     method public int getSimApplicationState();
     method public int getSimCardState();
-    method public int getSupportedRadioAccessFamily();
-    method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
-    method public android.telephony.UiccCardInfo[] getUiccCardsInfo();
-    method public android.telephony.UiccSlotInfo[] getUiccSlotsInfo();
-    method public android.os.Bundle getVisualVoicemailSettings();
-    method public int getVoiceActivationState();
-    method public boolean handlePinMmi(java.lang.String);
-    method public boolean handlePinMmiForSubscriber(int, java.lang.String);
-    method public boolean isCurrentPotentialEmergencyNumber(java.lang.String);
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getSimLocale();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSupportedRadioAccessFamily();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.UiccCardInfo[] getUiccCardsInfo();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.UiccSlotInfo[] getUiccSlotsInfo();
+    method @Nullable public android.os.Bundle getVisualVoicemailSettings();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCurrentPotentialEmergencyNumber(@NonNull 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 @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn();
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
+    method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
     method public boolean needsOtaServiceProvisioning();
-    method public boolean rebootRadio();
-    method public void requestCellInfoUpdate(android.os.WorkSource, java.util.concurrent.Executor, android.telephony.TelephonyManager.CellInfoCallback);
-    method public void requestNumberVerification(android.telephony.PhoneNumberRange, long, java.util.concurrent.Executor, android.telephony.NumberVerificationCallback);
-    method public boolean resetRadioConfig();
-    method public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
-    method public void setCarrierDataEnabled(boolean);
-    method public void setDataActivationState(int);
-    method public deprecated void setDataEnabled(int, boolean);
-    method public void setDataRoamingEnabled(boolean);
-    method public boolean setPreferredNetworkTypeBitmap(int);
-    method public boolean setRadio(boolean);
-    method public boolean setRadioPower(boolean);
-    method public void setSimPowerState(int);
-    method public void setSimPowerStateForSlot(int, int);
-    method public deprecated void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean);
-    method public void setVoiceActivationState(int);
-    method public boolean supplyPin(java.lang.String);
-    method public int[] supplyPinReportResult(java.lang.String);
-    method public boolean supplyPuk(java.lang.String, java.lang.String);
-    method public int[] supplyPukReportResult(java.lang.String, java.lang.String);
-    method public boolean switchSlots(int[]);
-    method public void toggleRadioOnOff();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
+    method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmap(int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadioPower(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerState(int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerStateForSlot(int, int);
+    method @Deprecated public void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoiceActivationState(int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPin(String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPinReportResult(String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPuk(String, String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPukReportResult(String, String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff();
     method public void updateServiceLocation();
-    field public static final java.lang.String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
-    field public static final java.lang.String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
-    field public static final java.lang.String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
+    field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
+    field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
+    field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
     field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
     field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
     field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
     field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
-    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 String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
+    field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
+    field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
     field public static final int INVALID_CARD_ID = -1; // 0xffffffff
     field public static final long MAX_NUMBER_VERIFICATION_TIMEOUT_MILLIS = 60000L; // 0xea60L
     field public static final int NETWORK_TYPE_BITMASK_1xRTT = 128; // 0x80
@@ -6455,6 +7807,9 @@
     field public static final int RADIO_POWER_OFF = 0; // 0x0
     field public static final int RADIO_POWER_ON = 1; // 0x1
     field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2
+    field public static final int SET_CARRIER_RESTRICTION_ERROR = 2; // 0x2
+    field public static final int SET_CARRIER_RESTRICTION_NOT_SUPPORTED = 1; // 0x1
+    field public static final int SET_CARRIER_RESTRICTION_SUCCESS = 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
@@ -6470,22 +7825,22 @@
   }
 
   public final class UiccAccessRule implements android.os.Parcelable {
-    ctor public UiccAccessRule(byte[], java.lang.String, long);
+    ctor public UiccAccessRule(byte[], @Nullable String, long);
     method public int describeContents();
     method public int getCarrierPrivilegeStatus(android.content.pm.PackageInfo);
-    method public int getCarrierPrivilegeStatus(android.content.pm.Signature, java.lang.String);
-    method public java.lang.String getCertificateHexString();
-    method public java.lang.String getPackageName();
+    method public int getCarrierPrivilegeStatus(android.content.pm.Signature, String);
+    method public String getCertificateHexString();
+    method @Nullable public String getPackageName();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.UiccAccessRule> CREATOR;
   }
 
   public class UiccCardInfo implements android.os.Parcelable {
-    ctor public UiccCardInfo(boolean, int, java.lang.String, java.lang.String, int);
+    ctor public UiccCardInfo(boolean, int, String, String, int);
     method public int describeContents();
     method public int getCardId();
-    method public java.lang.String getEid();
-    method public java.lang.String getIccId();
+    method public String getEid();
+    method public String getIccId();
     method public int getSlotIndex();
     method public boolean isEuicc();
     method public void writeToParcel(android.os.Parcel, int);
@@ -6493,9 +7848,9 @@
   }
 
   public class UiccSlotInfo implements android.os.Parcelable {
-    ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int, int, boolean);
+    ctor public UiccSlotInfo(boolean, boolean, String, int, int, boolean);
     method public int describeContents();
-    method public java.lang.String getCardId();
+    method public String getCardId();
     method public int getCardStateInfo();
     method public boolean getIsActive();
     method public boolean getIsEuicc();
@@ -6510,7 +7865,7 @@
   }
 
   public abstract class VisualVoicemailService extends android.app.Service {
-    method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, java.lang.String, short, java.lang.String, android.app.PendingIntent);
+    method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, String, short, String, android.app.PendingIntent);
     method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
   }
 
@@ -6519,38 +7874,38 @@
 package android.telephony.data {
 
   public final class DataCallResponse implements android.os.Parcelable {
-    ctor public DataCallResponse(int, int, int, int, java.lang.String, java.lang.String, java.util.List<android.net.LinkAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.net.InetAddress>, java.util.List<java.lang.String>, int);
+    ctor public DataCallResponse(int, int, int, int, @Nullable String, @Nullable String, @Nullable java.util.List<android.net.LinkAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.lang.String>, int);
     ctor public DataCallResponse(android.os.Parcel);
     method public int describeContents();
     method public int getActive();
-    method public java.util.List<android.net.LinkAddress> getAddresses();
+    method @NonNull public java.util.List<android.net.LinkAddress> getAddresses();
     method public int getCallId();
-    method public java.util.List<java.net.InetAddress> getDnses();
-    method public java.util.List<java.net.InetAddress> getGateways();
-    method public java.lang.String getIfname();
+    method @NonNull public java.util.List<java.net.InetAddress> getDnses();
+    method @NonNull public java.util.List<java.net.InetAddress> getGateways();
+    method @NonNull public String getIfname();
     method public int getMtu();
-    method public java.util.List<java.lang.String> getPcscfs();
+    method @NonNull public java.util.List<java.lang.String> getPcscfs();
     method public int getStatus();
     method public int getSuggestedRetryTime();
-    method public java.lang.String getType();
+    method @NonNull public String getType();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR;
   }
 
   public final class DataProfile implements android.os.Parcelable {
-    method public java.lang.String getApn();
+    method public String getApn();
     method public int getAuthType();
     method public int getBearerBitmap();
     method public int getMaxConns();
     method public int getMaxConnsTime();
     method public int getMtu();
-    method public java.lang.String getPassword();
+    method public String getPassword();
     method public int getProfileId();
-    method public java.lang.String getProtocol();
-    method public java.lang.String getRoamingProtocol();
+    method public String getProtocol();
+    method public String getRoamingProtocol();
     method public int getSupportedApnTypesBitmap();
     method public int getType();
-    method public java.lang.String getUserName();
+    method public String getUserName();
     method public int getWaitTime();
     method public boolean isEnabled();
     method public boolean isPersistent();
@@ -6563,7 +7918,7 @@
   public abstract class DataService extends android.app.Service {
     ctor public DataService();
     method public abstract android.telephony.data.DataService.DataServiceProvider createDataServiceProvider(int);
-    field public static final java.lang.String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService";
+    field public static final String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService";
     field public static final int REQUEST_REASON_HANDOVER = 3; // 0x3
     field public static final int REQUEST_REASON_NORMAL = 1; // 0x1
     field public static final int REQUEST_REASON_SHUTDOWN = 2; // 0x2
@@ -6572,13 +7927,13 @@
   public abstract class DataService.DataServiceProvider implements java.lang.AutoCloseable {
     ctor public DataService.DataServiceProvider(int);
     method public abstract void close();
-    method public void deactivateDataCall(int, int, android.telephony.data.DataServiceCallback);
-    method public void getDataCallList(android.telephony.data.DataServiceCallback);
+    method public void deactivateDataCall(int, int, @Nullable android.telephony.data.DataServiceCallback);
+    method public void getDataCallList(@NonNull android.telephony.data.DataServiceCallback);
     method public final int getSlotId();
     method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>);
-    method public void setDataProfile(java.util.List<android.telephony.data.DataProfile>, boolean, android.telephony.data.DataServiceCallback);
-    method public void setInitialAttachApn(android.telephony.data.DataProfile, boolean, android.telephony.data.DataServiceCallback);
-    method public void setupDataCall(int, android.telephony.data.DataProfile, boolean, boolean, int, android.net.LinkProperties, android.telephony.data.DataServiceCallback);
+    method public void setDataProfile(java.util.List<android.telephony.data.DataProfile>, boolean, @Nullable android.telephony.data.DataServiceCallback);
+    method public void setInitialAttachApn(android.telephony.data.DataProfile, boolean, @Nullable android.telephony.data.DataServiceCallback);
+    method public void setupDataCall(int, android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @Nullable android.telephony.data.DataServiceCallback);
   }
 
   public class DataServiceCallback {
@@ -6598,7 +7953,7 @@
   public abstract class QualifiedNetworksService extends android.app.Service {
     ctor public QualifiedNetworksService();
     method public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityUpdater createNetworkAvailabilityUpdater(int);
-    field public static final java.lang.String QUALIFIED_NETWORKS_SERVICE_INTERFACE = "android.telephony.data.QualifiedNetworksService";
+    field public static final String QUALIFIED_NETWORKS_SERVICE_INTERFACE = "android.telephony.data.QualifiedNetworksService";
   }
 
   public abstract class QualifiedNetworksService.NetworkAvailabilityUpdater implements java.lang.AutoCloseable {
@@ -6614,7 +7969,7 @@
 
   public final class DownloadableSubscription implements android.os.Parcelable {
     method public java.util.List<android.telephony.UiccAccessRule> getAccessRules();
-    method public java.lang.String getCarrierName();
+    method @Nullable public String getCarrierName();
   }
 
   public static final class DownloadableSubscription.Builder {
@@ -6622,34 +7977,34 @@
     ctor public DownloadableSubscription.Builder(android.telephony.euicc.DownloadableSubscription);
     method public android.telephony.euicc.DownloadableSubscription build();
     method public android.telephony.euicc.DownloadableSubscription.Builder setAccessRules(java.util.List<android.telephony.UiccAccessRule>);
-    method public android.telephony.euicc.DownloadableSubscription.Builder setCarrierName(java.lang.String);
-    method public android.telephony.euicc.DownloadableSubscription.Builder setConfirmationCode(java.lang.String);
-    method public android.telephony.euicc.DownloadableSubscription.Builder setEncodedActivationCode(java.lang.String);
+    method public android.telephony.euicc.DownloadableSubscription.Builder setCarrierName(String);
+    method public android.telephony.euicc.DownloadableSubscription.Builder setConfirmationCode(String);
+    method public android.telephony.euicc.DownloadableSubscription.Builder setEncodedActivationCode(String);
   }
 
   public class EuiccCardManager {
-    method public void authenticateServer(java.lang.String, java.lang.String, byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
-    method public void cancelSession(java.lang.String, byte[], int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
-    method public void deleteProfile(java.lang.String, java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
-    method public void disableProfile(java.lang.String, java.lang.String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
-    method public void listNotifications(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>);
-    method public void loadBoundProfilePackage(java.lang.String, byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
-    method public void prepareDownload(java.lang.String, byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
-    method public void removeNotificationFromList(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
-    method public void requestAllProfiles(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo[]>);
-    method public void requestDefaultSmdpAddress(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.String>);
-    method public void requestEuiccChallenge(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
-    method public void requestEuiccInfo1(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
-    method public void requestEuiccInfo2(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
-    method public void requestProfile(java.lang.String, java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>);
-    method public void requestRulesAuthTable(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccRulesAuthTable>);
-    method public void requestSmdsAddress(java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.String>);
-    method public void resetMemory(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
-    method public void retrieveNotification(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification>);
-    method public void retrieveNotificationList(java.lang.String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>);
-    method public void setDefaultSmdpAddress(java.lang.String, java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
-    method public void setNickname(java.lang.String, java.lang.String, java.lang.String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
-    method public void switchToProfile(java.lang.String, java.lang.String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>);
+    method public void authenticateServer(String, String, byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+    method public void cancelSession(String, byte[], @android.telephony.euicc.EuiccCardManager.CancelReason int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+    method public void deleteProfile(String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+    method public void disableProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+    method public void listNotifications(String, @android.telephony.euicc.EuiccNotification.Event int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>);
+    method public void loadBoundProfilePackage(String, byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+    method public void prepareDownload(String, @Nullable byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+    method public void removeNotificationFromList(String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+    method public void requestAllProfiles(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo[]>);
+    method public void requestDefaultSmdpAddress(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.String>);
+    method public void requestEuiccChallenge(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+    method public void requestEuiccInfo1(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+    method public void requestEuiccInfo2(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
+    method public void requestProfile(String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>);
+    method public void requestRulesAuthTable(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccRulesAuthTable>);
+    method public void requestSmdsAddress(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.String>);
+    method public void resetMemory(String, @android.telephony.euicc.EuiccCardManager.ResetOption int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+    method public void retrieveNotification(String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification>);
+    method public void retrieveNotificationList(String, @android.telephony.euicc.EuiccNotification.Event int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>);
+    method public void setDefaultSmdpAddress(String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+    method public void setNickname(String, String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+    method public void switchToProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>);
     field public static final int CANCEL_REASON_END_USER_REJECTED = 0; // 0x0
     field public static final int CANCEL_REASON_POSTPONED = 1; // 0x1
     field public static final int CANCEL_REASON_PPR_NOT_ALLOWED = 3; // 0x3
@@ -6663,25 +8018,28 @@
     field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff
   }
 
-  public static abstract class EuiccCardManager.CancelReason implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"CANCEL_REASON_"}, value={android.telephony.euicc.EuiccCardManager.CANCEL_REASON_END_USER_REJECTED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_POSTPONED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_TIMEOUT, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_PPR_NOT_ALLOWED}) public static @interface EuiccCardManager.CancelReason {
   }
 
-  public static abstract class EuiccCardManager.ResetOption implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(flag=true, prefix={"RESET_OPTION_"}, value={android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_OPERATIONAL_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS}) public static @interface EuiccCardManager.ResetOption {
   }
 
-  public static abstract interface EuiccCardManager.ResultCallback<T> {
-    method public abstract void onComplete(int, T);
+  public static interface EuiccCardManager.ResultCallback<T> {
+    method public void onComplete(int, T);
   }
 
   public class EuiccManager {
-    method public void continueOperation(android.content.Intent, android.os.Bundle);
-    method public void eraseSubscriptions(android.app.PendingIntent);
-    method public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent);
-    method public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent);
-    method public int getOtaStatus();
-    field public static final java.lang.String ACTION_OTA_STATUS_CHANGED = "android.telephony.euicc.action.OTA_STATUS_CHANGED";
-    field public static final java.lang.String ACTION_PROFILE_SELECTION = "android.telephony.euicc.action.PROFILE_SELECTION";
-    field public static final java.lang.String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
+    method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void continueOperation(android.content.Intent, android.os.Bundle);
+    method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public int getOtaStatus();
+    field public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED";
+    field @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public static final String ACTION_OTA_STATUS_CHANGED = "android.telephony.euicc.action.OTA_STATUS_CHANGED";
+    field public static final String ACTION_PROFILE_SELECTION = "android.telephony.euicc.action.PROFILE_SELECTION";
+    field public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
+    field public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED";
+    field public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED";
     field public static final int EUICC_ACTIVATION_TYPE_BACKUP = 2; // 0x2
     field public static final int EUICC_ACTIVATION_TYPE_DEFAULT = 1; // 0x1
     field public static final int EUICC_ACTIVATION_TYPE_TRANSFER = 3; // 0x3
@@ -6690,23 +8048,26 @@
     field public static final int EUICC_OTA_NOT_NEEDED = 4; // 0x4
     field public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5; // 0x5
     field public static final int EUICC_OTA_SUCCEEDED = 3; // 0x3
-    field public static final java.lang.String EXTRA_ACTIVATION_TYPE = "android.telephony.euicc.extra.ACTIVATION_TYPE";
-    field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS";
-    field public static final java.lang.String EXTRA_FORCE_PROVISION = "android.telephony.euicc.extra.FORCE_PROVISION";
+    field public static final String EXTRA_ACTIVATION_TYPE = "android.telephony.euicc.extra.ACTIVATION_TYPE";
+    field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS";
+    field public static final String EXTRA_ENABLE_SUBSCRIPTION = "android.telephony.euicc.extra.ENABLE_SUBSCRIPTION";
+    field public static final String EXTRA_FORCE_PROVISION = "android.telephony.euicc.extra.FORCE_PROVISION";
+    field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.euicc.extra.SUBSCRIPTION_ID";
+    field public static final String EXTRA_SUBSCRIPTION_NICKNAME = "android.telephony.euicc.extra.SUBSCRIPTION_NICKNAME";
   }
 
-  public static abstract class EuiccManager.OtaStatus implements java.lang.annotation.Annotation {
+  @IntDef(prefix={"EUICC_OTA_"}, value={android.telephony.euicc.EuiccManager.EUICC_OTA_IN_PROGRESS, android.telephony.euicc.EuiccManager.EUICC_OTA_FAILED, android.telephony.euicc.EuiccManager.EUICC_OTA_SUCCEEDED, android.telephony.euicc.EuiccManager.EUICC_OTA_NOT_NEEDED, android.telephony.euicc.EuiccManager.EUICC_OTA_STATUS_UNAVAILABLE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccManager.OtaStatus {
   }
 
   public final class EuiccNotification implements android.os.Parcelable {
-    ctor public EuiccNotification(int, java.lang.String, int, byte[]);
+    ctor public EuiccNotification(int, String, @android.telephony.euicc.EuiccNotification.Event int, @Nullable byte[]);
     method public int describeContents();
-    method public byte[] getData();
-    method public int getEvent();
+    method @Nullable public byte[] getData();
+    method @android.telephony.euicc.EuiccNotification.Event public int getEvent();
     method public int getSeq();
-    method public java.lang.String getTargetAddr();
+    method public String getTargetAddr();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final int ALL_EVENTS = 15; // 0xf
+    field @android.telephony.euicc.EuiccNotification.Event public static final int ALL_EVENTS = 15; // 0xf
     field public static final android.os.Parcelable.Creator<android.telephony.euicc.EuiccNotification> CREATOR;
     field public static final int EVENT_DELETE = 8; // 0x8
     field public static final int EVENT_DISABLE = 4; // 0x4
@@ -6714,13 +8075,13 @@
     field public static final int EVENT_INSTALL = 1; // 0x1
   }
 
-  public static abstract class EuiccNotification.Event implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(flag=true, prefix={"EVENT_"}, value={android.telephony.euicc.EuiccNotification.EVENT_INSTALL, android.telephony.euicc.EuiccNotification.EVENT_ENABLE, android.telephony.euicc.EuiccNotification.EVENT_DISABLE, android.telephony.euicc.EuiccNotification.EVENT_DELETE}) public static @interface EuiccNotification.Event {
   }
 
   public final class EuiccRulesAuthTable implements android.os.Parcelable {
     method public int describeContents();
-    method public int findIndex(int, android.service.carrier.CarrierIdentifier);
-    method public boolean hasPolicyRuleFlag(int, int);
+    method public int findIndex(@android.service.euicc.EuiccProfileInfo.PolicyRule int, android.service.carrier.CarrierIdentifier);
+    method public boolean hasPolicyRuleFlag(int, @android.telephony.euicc.EuiccRulesAuthTable.PolicyRuleFlag int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.euicc.EuiccRulesAuthTable> CREATOR;
     field public static final int POLICY_RULE_FLAG_CONSENT_REQUIRED = 1; // 0x1
@@ -6732,7 +8093,7 @@
     method public android.telephony.euicc.EuiccRulesAuthTable build();
   }
 
-  public static abstract class EuiccRulesAuthTable.PolicyRuleFlag implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(flag=true, prefix={"POLICY_RULE_FLAG_"}, value={android.telephony.euicc.EuiccRulesAuthTable.POLICY_RULE_FLAG_CONSENT_REQUIRED}) public static @interface EuiccRulesAuthTable.PolicyRuleFlag {
   }
 
 }
@@ -6740,10 +8101,10 @@
 package android.telephony.ims {
 
   public final class ImsCallForwardInfo implements android.os.Parcelable {
-    ctor public ImsCallForwardInfo(int, int, int, int, java.lang.String, int);
+    ctor public ImsCallForwardInfo(int, int, int, int, @NonNull String, int);
     method public int describeContents();
     method public int getCondition();
-    method public java.lang.String getNumber();
+    method public String getNumber();
     method public int getServiceClass();
     method public int getStatus();
     method public int getTimeSeconds();
@@ -6768,29 +8129,35 @@
     ctor public ImsCallProfile(int, int);
     ctor public ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile);
     method public int describeContents();
-    method public java.lang.String getCallExtra(java.lang.String);
-    method public java.lang.String getCallExtra(java.lang.String, java.lang.String);
-    method public boolean getCallExtraBoolean(java.lang.String);
-    method public boolean getCallExtraBoolean(java.lang.String, boolean);
-    method public int getCallExtraInt(java.lang.String);
-    method public int getCallExtraInt(java.lang.String, int);
+    method public String getCallExtra(String);
+    method public String getCallExtra(String, String);
+    method public boolean getCallExtraBoolean(String);
+    method public boolean getCallExtraBoolean(String, boolean);
+    method public int getCallExtraInt(String);
+    method public int getCallExtraInt(String, int);
     method public android.os.Bundle getCallExtras();
     method public int getCallType();
     method public static int getCallTypeFromVideoState(int);
+    method public int getEmergencyCallRouting();
     method public int getEmergencyServiceCategories();
+    method public java.util.List<java.lang.String> getEmergencyUrns();
     method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
     method public int getRestrictCause();
     method public int getServiceType();
     method public static int getVideoStateFromCallType(int);
     method public static int getVideoStateFromImsCallProfile(android.telephony.ims.ImsCallProfile);
+    method public boolean isEmergencyCallTesting();
     method public boolean isVideoCall();
     method public boolean isVideoPaused();
     method public static int presentationToOir(int);
-    method public void setCallExtra(java.lang.String, java.lang.String);
-    method public void setCallExtraBoolean(java.lang.String, boolean);
-    method public void setCallExtraInt(java.lang.String, int);
+    method public void setCallExtra(String, String);
+    method public void setCallExtraBoolean(String, boolean);
+    method public void setCallExtraInt(String, int);
     method public void setCallRestrictCause(int);
+    method public void setEmergencyCallRouting(int);
+    method public void setEmergencyCallTesting(boolean);
     method public void setEmergencyServiceCategories(int);
+    method public void setEmergencyUrns(java.util.List<java.lang.String>);
     method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
     method public void updateCallType(android.telephony.ims.ImsCallProfile);
     method public void updateMediaProfile(android.telephony.ims.ImsCallProfile);
@@ -6813,21 +8180,21 @@
     field public static final int DIALSTRING_NORMAL = 0; // 0x0
     field public static final int DIALSTRING_SS_CONF = 1; // 0x1
     field public static final int DIALSTRING_USSD = 2; // 0x2
-    field public static final java.lang.String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
-    field public static final java.lang.String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS = "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS";
-    field public static final java.lang.String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
-    field public static final java.lang.String EXTRA_CHILD_NUMBER = "ChildNum";
-    field public static final java.lang.String EXTRA_CNA = "cna";
-    field public static final java.lang.String EXTRA_CNAP = "cnap";
-    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_EMERGENCY_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";
-    field public static final java.lang.String EXTRA_REMOTE_URI = "remote_uri";
-    field public static final java.lang.String EXTRA_USSD = "ussd";
+    field public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
+    field public static final String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS = "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS";
+    field public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
+    field public static final String EXTRA_CHILD_NUMBER = "ChildNum";
+    field public static final String EXTRA_CNA = "cna";
+    field public static final String EXTRA_CNAP = "cnap";
+    field public static final String EXTRA_CODEC = "Codec";
+    field public static final String EXTRA_DIALSTRING = "dialstring";
+    field public static final String EXTRA_DISPLAY_TEXT = "DisplayText";
+    field public static final String EXTRA_EMERGENCY_CALL = "e_call";
+    field public static final String EXTRA_IS_CALL_PULL = "CallPull";
+    field public static final String EXTRA_OI = "oi";
+    field public static final String EXTRA_OIR = "oir";
+    field public static final String EXTRA_REMOTE_URI = "remote_uri";
+    field public static final String EXTRA_USSD = "ussd";
     field public static final int OIR_DEFAULT = 0; // 0x0
     field public static final int OIR_PRESENTATION_NOT_RESTRICTED = 2; // 0x2
     field public static final int OIR_PRESENTATION_PAYPHONE = 4; // 0x4
@@ -6839,6 +8206,7 @@
   }
 
   public class ImsCallSessionListener {
+    method public void callQualityChanged(android.telephony.CallQuality);
     method public void callSessionConferenceExtendFailed(android.telephony.ims.ImsReasonInfo);
     method public void callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
     method public void callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
@@ -6863,7 +8231,8 @@
     method public void callSessionResumeFailed(android.telephony.ims.ImsReasonInfo);
     method public void callSessionResumeReceived(android.telephony.ims.ImsCallProfile);
     method public void callSessionResumed(android.telephony.ims.ImsCallProfile);
-    method public void callSessionRttMessageReceived(java.lang.String);
+    method public void callSessionRttAudioIndicatorChanged(android.telephony.ims.ImsStreamMediaProfile);
+    method public void callSessionRttMessageReceived(String);
     method public void callSessionRttModifyRequestReceived(android.telephony.ims.ImsCallProfile);
     method public void callSessionRttModifyResponseReceived(int);
     method public void callSessionSuppServiceReceived(android.telephony.ims.ImsSuppServiceNotification);
@@ -6872,36 +8241,36 @@
     method public void callSessionUpdateFailed(android.telephony.ims.ImsReasonInfo);
     method public void callSessionUpdateReceived(android.telephony.ims.ImsCallProfile);
     method public void callSessionUpdated(android.telephony.ims.ImsCallProfile);
-    method public void callSessionUssdMessageReceived(int, java.lang.String);
+    method public void callSessionUssdMessageReceived(int, String);
   }
 
   public final class ImsConferenceState implements android.os.Parcelable {
     method public int describeContents();
-    method public static int getConnectionStateForStatus(java.lang.String);
+    method public static int getConnectionStateForStatus(String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.ims.ImsConferenceState> CREATOR;
-    field public static final java.lang.String DISPLAY_TEXT = "display-text";
-    field public static final java.lang.String ENDPOINT = "endpoint";
-    field public static final java.lang.String SIP_STATUS_CODE = "sipstatuscode";
-    field public static final java.lang.String STATUS = "status";
-    field public static final java.lang.String STATUS_ALERTING = "alerting";
-    field public static final java.lang.String STATUS_CONNECTED = "connected";
-    field public static final java.lang.String STATUS_CONNECT_FAIL = "connect-fail";
-    field public static final java.lang.String STATUS_DIALING_IN = "dialing-in";
-    field public static final java.lang.String STATUS_DIALING_OUT = "dialing-out";
-    field public static final java.lang.String STATUS_DISCONNECTED = "disconnected";
-    field public static final java.lang.String STATUS_DISCONNECTING = "disconnecting";
-    field public static final java.lang.String STATUS_MUTED_VIA_FOCUS = "muted-via-focus";
-    field public static final java.lang.String STATUS_ON_HOLD = "on-hold";
-    field public static final java.lang.String STATUS_PENDING = "pending";
-    field public static final java.lang.String STATUS_SEND_ONLY = "sendonly";
-    field public static final java.lang.String STATUS_SEND_RECV = "sendrecv";
-    field public static final java.lang.String USER = "user";
-    field public final java.util.HashMap<java.lang.String, android.os.Bundle> mParticipants;
+    field public static final String DISPLAY_TEXT = "display-text";
+    field public static final String ENDPOINT = "endpoint";
+    field public static final String SIP_STATUS_CODE = "sipstatuscode";
+    field public static final String STATUS = "status";
+    field public static final String STATUS_ALERTING = "alerting";
+    field public static final String STATUS_CONNECTED = "connected";
+    field public static final String STATUS_CONNECT_FAIL = "connect-fail";
+    field public static final String STATUS_DIALING_IN = "dialing-in";
+    field public static final String STATUS_DIALING_OUT = "dialing-out";
+    field public static final String STATUS_DISCONNECTED = "disconnected";
+    field public static final String STATUS_DISCONNECTING = "disconnecting";
+    field public static final String STATUS_MUTED_VIA_FOCUS = "muted-via-focus";
+    field public static final String STATUS_ON_HOLD = "on-hold";
+    field public static final String STATUS_PENDING = "pending";
+    field public static final String STATUS_SEND_ONLY = "sendonly";
+    field public static final String STATUS_SEND_RECV = "sendrecv";
+    field public static final String USER = "user";
+    field public final java.util.HashMap<java.lang.String,android.os.Bundle> mParticipants;
   }
 
   public final class ImsExternalCallState implements android.os.Parcelable {
-    ctor public ImsExternalCallState(java.lang.String, android.net.Uri, android.net.Uri, boolean, int, int, boolean);
+    ctor public ImsExternalCallState(String, android.net.Uri, android.net.Uri, boolean, int, int, boolean);
     method public int describeContents();
     method public android.net.Uri getAddress();
     method public int getCallId();
@@ -6918,25 +8287,26 @@
 
   public class ImsMmTelManager {
     method public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(android.content.Context, int);
-    method public int getVoWiFiModeSetting();
-    method public boolean isAdvancedCallingSettingEnabled();
-    method public boolean isAvailable(int, int);
-    method public boolean isCapable(int, int);
-    method public boolean isVoWiFiRoamingSettingEnabled();
-    method public boolean isVoWiFiSettingEnabled();
-    method public boolean isVtSettingEnabled();
-    method public void registerImsRegistrationCallback(java.util.concurrent.Executor, android.telephony.ims.ImsMmTelManager.RegistrationCallback);
-    method public void registerMmTelCapabilityCallback(java.util.concurrent.Executor, android.telephony.ims.ImsMmTelManager.CapabilityCallback);
-    method public void setAdvancedCallingSetting(boolean);
-    method public void setRttCapabilitySetting(boolean);
-    method public void setVoWiFiModeSetting(int);
-    method public void setVoWiFiNonPersistent(boolean, int);
-    method public void setVoWiFiRoamingModeSetting(int);
-    method public void setVoWiFiRoamingSetting(boolean);
-    method public void setVoWiFiSetting(boolean);
-    method public void setVtSetting(boolean);
-    method public void unregisterImsRegistrationCallback(android.telephony.ims.ImsMmTelManager.RegistrationCallback);
-    method public void unregisterMmTelCapabilityCallback(android.telephony.ims.ImsMmTelManager.CapabilityCallback);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiModeSetting();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAdvancedCallingSettingEnabled();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiRoamingSettingEnabled();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiSettingEnabled();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVtSettingEnabled();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSetting(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiNonPersistent(boolean, int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingModeSetting(int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingSetting(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSetting(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSetting(boolean);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback);
     field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1
     field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0
     field public static final int WIFI_MODE_WIFI_PREFERRED = 2; // 0x2
@@ -6956,11 +8326,11 @@
   }
 
   public final class ImsReasonInfo implements android.os.Parcelable {
-    ctor public ImsReasonInfo(int, int, java.lang.String);
+    ctor public ImsReasonInfo(int, int, String);
     method public int describeContents();
     method public int getCode();
     method public int getExtraCode();
-    method public java.lang.String getExtraMessage();
+    method public String getExtraMessage();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CODE_ACCESS_CLASS_BLOCKED = 1512; // 0x5e8
     field public static final int CODE_ANSWERED_ELSEWHERE = 1014; // 0x3f6
@@ -7136,7 +8506,7 @@
     field public static final int EXTRA_CODE_CALL_RETRY_BY_SETTINGS = 3; // 0x3
     field public static final int EXTRA_CODE_CALL_RETRY_NORMAL = 1; // 0x1
     field public static final int EXTRA_CODE_CALL_RETRY_SILENT_REDIAL = 2; // 0x2
-    field public static final java.lang.String EXTRA_MSG_SERVICE_NOT_AUTHORIZED = "Forbidden. Not Authorized for Service";
+    field public static final String EXTRA_MSG_SERVICE_NOT_AUTHORIZED = "Forbidden. Not Authorized for Service";
   }
 
   public class ImsService extends android.app.Service {
@@ -7160,7 +8530,7 @@
     method public int getResult();
     method public int getServiceClass();
     method public int getServiceType();
-    method public android.telephony.ims.ImsSsInfo[] getSuppServiceInfo();
+    method @NonNull public android.telephony.ims.ImsSsInfo[] getSuppServiceInfo();
     method public int getTeleserviceType();
     method public boolean isTypeBarring();
     method public boolean isTypeCf();
@@ -7222,18 +8592,18 @@
 
   public static class ImsSsData.Builder {
     ctor public ImsSsData.Builder(int, int, int, int, int);
-    method public android.telephony.ims.ImsSsData build();
-    method public android.telephony.ims.ImsSsData.Builder setCallForwardingInfo(android.telephony.ims.ImsCallForwardInfo[]);
-    method public android.telephony.ims.ImsSsData.Builder setSuppServiceInfo(android.telephony.ims.ImsSsInfo[]);
+    method @NonNull public android.telephony.ims.ImsSsData build();
+    method @NonNull public android.telephony.ims.ImsSsData.Builder setCallForwardingInfo(@NonNull android.telephony.ims.ImsCallForwardInfo[]);
+    method @NonNull public android.telephony.ims.ImsSsData.Builder setSuppServiceInfo(@NonNull android.telephony.ims.ImsSsInfo[]);
   }
 
   public final class ImsSsInfo implements android.os.Parcelable {
-    ctor public deprecated ImsSsInfo(int, java.lang.String);
+    ctor @Deprecated public ImsSsInfo(int, @Nullable String);
     method public int describeContents();
     method public int getClirInterrogationStatus();
     method public int getClirOutgoingState();
-    method public deprecated java.lang.String getIcbNum();
-    method public java.lang.String getIncomingCommunicationBarringNumber();
+    method @Deprecated public String getIcbNum();
+    method public String getIncomingCommunicationBarringNumber();
     method public int getProvisionStatus();
     method public int getStatus();
     method public void writeToParcel(android.os.Parcel, int);
@@ -7256,11 +8626,11 @@
 
   public static class ImsSsInfo.Builder {
     ctor public ImsSsInfo.Builder(int);
-    method public android.telephony.ims.ImsSsInfo build();
-    method public android.telephony.ims.ImsSsInfo.Builder setClirInterrogationStatus(int);
-    method public android.telephony.ims.ImsSsInfo.Builder setClirOutgoingState(int);
-    method public android.telephony.ims.ImsSsInfo.Builder setIncomingCommunicationBarringNumber(java.lang.String);
-    method public android.telephony.ims.ImsSsInfo.Builder setProvisionStatus(int);
+    method @NonNull public android.telephony.ims.ImsSsInfo build();
+    method @NonNull public android.telephony.ims.ImsSsInfo.Builder setClirInterrogationStatus(int);
+    method @NonNull public android.telephony.ims.ImsSsInfo.Builder setClirOutgoingState(int);
+    method @NonNull public android.telephony.ims.ImsSsInfo.Builder setIncomingCommunicationBarringNumber(@NonNull String);
+    method @NonNull public android.telephony.ims.ImsSsInfo.Builder setProvisionStatus(int);
   }
 
   public final class ImsStreamMediaProfile implements android.os.Parcelable {
@@ -7269,10 +8639,12 @@
     method public int describeContents();
     method public int getAudioDirection();
     method public int getAudioQuality();
+    method public boolean getRttAudioSpeech();
     method public int getRttMode();
     method public int getVideoDirection();
     method public int getVideoQuality();
     method public boolean isRttCall();
+    method public void setRttAudioSpeech(boolean);
     method public void setRttMode(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int AUDIO_QUALITY_AMR = 1; // 0x1
@@ -7313,15 +8685,15 @@
   }
 
   public final class ImsSuppServiceNotification implements android.os.Parcelable {
-    ctor public ImsSuppServiceNotification(int, int, int, int, java.lang.String, java.lang.String[]);
+    ctor public ImsSuppServiceNotification(int, int, int, int, String, String[]);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.ims.ImsSuppServiceNotification> CREATOR;
     field public final int code;
-    field public final java.lang.String[] history;
+    field public final String[] history;
     field public final int index;
     field public final int notificationType;
-    field public final java.lang.String number;
+    field public final String number;
     field public final int type;
   }
 
@@ -7347,8 +8719,8 @@
     method public abstract void onRequestCameraCapabilities();
     method public abstract void onSendSessionModifyRequest(android.telecom.VideoProfile, android.telecom.VideoProfile);
     method public abstract void onSendSessionModifyResponse(android.telecom.VideoProfile);
-    method public abstract void onSetCamera(java.lang.String);
-    method public void onSetCamera(java.lang.String, int);
+    method public abstract void onSetCamera(String);
+    method public void onSetCamera(String, int);
     method public abstract void onSetDeviceOrientation(int);
     method public abstract void onSetDisplaySurface(android.view.Surface);
     method public abstract void onSetPauseImage(android.net.Uri);
@@ -7360,18 +8732,18 @@
 
   public class ProvisioningManager {
     method public static android.telephony.ims.ProvisioningManager createForSubscriptionId(android.content.Context, int);
-    method public int getProvisioningIntValue(int);
-    method public java.lang.String getProvisioningStringValue(int);
-    method public void registerProvisioningChangedCallback(java.util.concurrent.Executor, android.telephony.ims.ProvisioningManager.Callback);
-    method public int setProvisioningIntValue(int, int);
-    method public int setProvisioningStringValue(int, java.lang.String);
-    method public void unregisterProvisioningChangedCallback(android.telephony.ims.ProvisioningManager.Callback);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getProvisioningIntValue(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getProvisioningStringValue(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setProvisioningIntValue(int, int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setProvisioningStringValue(int, String);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
   }
 
   public static class ProvisioningManager.Callback {
     ctor public ProvisioningManager.Callback();
     method public void onProvisioningIntChanged(int, int);
-    method public void onProvisioningStringChanged(int, java.lang.String);
+    method public void onProvisioningStringChanged(int, String);
   }
 
 }
@@ -7379,8 +8751,8 @@
 package android.telephony.ims.feature {
 
   public final class CapabilityChangeRequest implements android.os.Parcelable {
-    method public void addCapabilitiesToDisableForTech(int, int);
-    method public void addCapabilitiesToEnableForTech(int, int);
+    method public void addCapabilitiesToDisableForTech(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method public void addCapabilitiesToEnableForTech(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
     method public int describeContents();
     method public java.util.List<android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair> getCapabilitiesToDisable();
     method public java.util.List<android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair> getCapabilitiesToEnable();
@@ -7389,8 +8761,8 @@
   }
 
   public static class CapabilityChangeRequest.CapabilityPair {
-    ctor public CapabilityChangeRequest.CapabilityPair(int, int);
-    method public int getCapability();
+    ctor public CapabilityChangeRequest.CapabilityPair(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method @android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability public int getCapability();
     method public int getRadioTech();
   }
 
@@ -7420,44 +8792,44 @@
 
   public class MmTelFeature extends android.telephony.ims.feature.ImsFeature {
     ctor public MmTelFeature();
-    method public void changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
-    method public android.telephony.ims.ImsCallProfile createCallProfile(int, int);
-    method public android.telephony.ims.stub.ImsCallSessionImplBase createCallSession(android.telephony.ims.ImsCallProfile);
-    method public android.telephony.ims.stub.ImsEcbmImplBase getEcbm();
-    method public android.telephony.ims.stub.ImsMultiEndpointImplBase getMultiEndpoint();
-    method public android.telephony.ims.stub.ImsSmsImplBase getSmsImplementation();
-    method public android.telephony.ims.stub.ImsUtImplBase getUt();
-    method public final void notifyCapabilitiesStatusChanged(android.telephony.ims.feature.MmTelFeature.MmTelCapabilities);
-    method public final void notifyIncomingCall(android.telephony.ims.stub.ImsCallSessionImplBase, android.os.Bundle);
-    method public final void notifyRejectedCall(android.telephony.ims.ImsCallProfile, android.telephony.ims.ImsReasonInfo);
+    method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
+    method @Nullable public android.telephony.ims.ImsCallProfile createCallProfile(int, int);
+    method @Nullable public android.telephony.ims.stub.ImsCallSessionImplBase createCallSession(@NonNull android.telephony.ims.ImsCallProfile);
+    method @NonNull public android.telephony.ims.stub.ImsEcbmImplBase getEcbm();
+    method @NonNull public android.telephony.ims.stub.ImsMultiEndpointImplBase getMultiEndpoint();
+    method @NonNull public android.telephony.ims.stub.ImsSmsImplBase getSmsImplementation();
+    method @NonNull public android.telephony.ims.stub.ImsUtImplBase getUt();
+    method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities);
+    method public final void notifyIncomingCall(@NonNull android.telephony.ims.stub.ImsCallSessionImplBase, @NonNull android.os.Bundle);
+    method public final void notifyRejectedCall(@NonNull android.telephony.ims.ImsCallProfile, @NonNull android.telephony.ims.ImsReasonInfo);
     method public final void notifyVoiceMessageCountUpdate(int);
     method public void onFeatureReady();
     method public void onFeatureRemoved();
-    method public boolean queryCapabilityConfiguration(int, int);
+    method public boolean queryCapabilityConfiguration(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
     method public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus();
-    method public void setUiTtyMode(int, android.os.Message);
-    method public int shouldProcessCall(java.lang.String[]);
+    method public void setUiTtyMode(int, @Nullable android.os.Message);
+    method @android.telephony.ims.feature.MmTelFeature.ProcessCallResult public int shouldProcessCall(@NonNull String[]);
     field public static final int PROCESS_CALL_CSFB = 1; // 0x1
     field public static final int PROCESS_CALL_IMS = 0; // 0x0
   }
 
   public static class MmTelFeature.MmTelCapabilities extends android.telephony.ims.feature.ImsFeature.Capabilities {
     ctor public MmTelFeature.MmTelCapabilities();
-    ctor public deprecated MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities);
+    ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities);
     ctor public MmTelFeature.MmTelCapabilities(int);
-    method public final void addCapabilities(int);
-    method public final boolean isCapable(int);
-    method public final void removeCapabilities(int);
+    method public final void addCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
+    method public final boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
+    method public final void removeCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
     field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8
     field public static final int CAPABILITY_TYPE_UT = 4; // 0x4
     field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2
     field public static final int CAPABILITY_TYPE_VOICE = 1; // 0x1
   }
 
-  public static abstract class MmTelFeature.MmTelCapabilities.MmTelCapability implements java.lang.annotation.Annotation {
+  @IntDef(flag=true, value={android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MmTelFeature.MmTelCapabilities.MmTelCapability {
   }
 
-  public static abstract class MmTelFeature.ProcessCallResult implements java.lang.annotation.Annotation {
+  @IntDef(flag=true, value={android.telephony.ims.feature.MmTelFeature.PROCESS_CALL_IMS, android.telephony.ims.feature.MmTelFeature.PROCESS_CALL_CSFB}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MmTelFeature.ProcessCallResult {
   }
 
   public class RcsFeature extends android.telephony.ims.feature.ImsFeature {
@@ -7475,32 +8847,32 @@
     ctor public ImsCallSessionImplBase();
     method public void accept(int, android.telephony.ims.ImsStreamMediaProfile);
     method public void close();
-    method public void deflect(java.lang.String);
-    method public void extendToConference(java.lang.String[]);
-    method public java.lang.String getCallId();
+    method public void deflect(String);
+    method public void extendToConference(String[]);
+    method public String getCallId();
     method public android.telephony.ims.ImsCallProfile getCallProfile();
     method public android.telephony.ims.ImsVideoCallProvider getImsVideoCallProvider();
     method public android.telephony.ims.ImsCallProfile getLocalCallProfile();
-    method public java.lang.String getProperty(java.lang.String);
+    method public String getProperty(String);
     method public android.telephony.ims.ImsCallProfile getRemoteCallProfile();
     method public int getState();
     method public void hold(android.telephony.ims.ImsStreamMediaProfile);
-    method public void inviteParticipants(java.lang.String[]);
+    method public void inviteParticipants(String[]);
     method public boolean isInCall();
     method public boolean isMultiparty();
     method public void merge();
     method public void reject(int);
-    method public void removeParticipants(java.lang.String[]);
+    method public void removeParticipants(String[]);
     method public void resume(android.telephony.ims.ImsStreamMediaProfile);
     method public void sendDtmf(char, android.os.Message);
-    method public void sendRttMessage(java.lang.String);
+    method public void sendRttMessage(String);
     method public void sendRttModifyRequest(android.telephony.ims.ImsCallProfile);
     method public void sendRttModifyResponse(boolean);
-    method public void sendUssd(java.lang.String);
+    method public void sendUssd(String);
     method public void setListener(android.telephony.ims.ImsCallSessionListener);
     method public void setMute(boolean);
-    method public void start(java.lang.String, android.telephony.ims.ImsCallProfile);
-    method public void startConference(java.lang.String[], android.telephony.ims.ImsCallProfile);
+    method public void start(String, android.telephony.ims.ImsCallProfile);
+    method public void startConference(String[], android.telephony.ims.ImsCallProfile);
     method public void startDtmf(char);
     method public void stopDtmf();
     method public void terminate(int);
@@ -7510,7 +8882,7 @@
   }
 
   public static class ImsCallSessionImplBase.State {
-    method public static java.lang.String toString(int);
+    method public static String toString(int);
     field public static final int ESTABLISHED = 4; // 0x4
     field public static final int ESTABLISHING = 3; // 0x3
     field public static final int IDLE = 0; // 0x0
@@ -7526,11 +8898,11 @@
   public class ImsConfigImplBase {
     ctor public ImsConfigImplBase();
     method public int getConfigInt(int);
-    method public java.lang.String getConfigString(int);
+    method public String getConfigString(int);
     method public final void notifyProvisionedValueChanged(int, int);
-    method public final void notifyProvisionedValueChanged(int, java.lang.String);
+    method public final void notifyProvisionedValueChanged(int, String);
     method public int setConfig(int, int);
-    method public int setConfig(int, java.lang.String);
+    method public int setConfig(int, String);
     field public static final int CONFIG_RESULT_FAILED = 1; // 0x1
     field public static final int CONFIG_RESULT_SUCCESS = 0; // 0x0
     field public static final int CONFIG_RESULT_UNKNOWN = -1; // 0xffffffff
@@ -7584,12 +8956,12 @@
     ctor public ImsSmsImplBase();
     method public void acknowledgeSms(int, int, int);
     method public void acknowledgeSmsReport(int, int, int);
-    method public java.lang.String getSmsFormat();
+    method public String getSmsFormat();
     method public void onReady();
     method public final void onSendSmsResult(int, int, int, int) throws java.lang.RuntimeException;
-    method public final void onSmsReceived(int, java.lang.String, byte[]) throws java.lang.RuntimeException;
-    method public final void onSmsStatusReportReceived(int, int, java.lang.String, byte[]) throws java.lang.RuntimeException;
-    method public void sendSms(int, int, java.lang.String, java.lang.String, boolean, byte[]);
+    method public final void onSmsReceived(int, String, byte[]) throws java.lang.RuntimeException;
+    method public final void onSmsStatusReportReceived(int, int, String, byte[]) throws java.lang.RuntimeException;
+    method public void sendSms(int, int, String, String, boolean, byte[]);
     field public static final int DELIVER_STATUS_ERROR_GENERIC = 2; // 0x2
     field public static final int DELIVER_STATUS_ERROR_NO_MEMORY = 3; // 0x3
     field public static final int DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED = 4; // 0x4
@@ -7607,7 +8979,7 @@
     method public void close();
     method public int queryCallBarring(int);
     method public int queryCallBarringForServiceClass(int, int);
-    method public int queryCallForward(int, java.lang.String);
+    method public int queryCallForward(int, String);
     method public int queryCallWaiting();
     method public int queryClip();
     method public int queryClir();
@@ -7615,9 +8987,9 @@
     method public int queryColr();
     method public void setListener(android.telephony.ims.ImsUtListener);
     method public int transact(android.os.Bundle);
-    method public int updateCallBarring(int, int, java.lang.String[]);
-    method public int updateCallBarringForServiceClass(int, int, java.lang.String[], int);
-    method public int updateCallForward(int, int, java.lang.String, int, int);
+    method public int updateCallBarring(int, int, String[]);
+    method public int updateCallBarringForServiceClass(int, int, String[], int);
+    method public int updateCallForward(int, int, String, int, int);
     method public int updateCallWaiting(boolean, int);
     method public int updateClip(boolean);
     method public int updateClir(int);
@@ -7630,15 +9002,15 @@
 package android.telephony.mbms {
 
   public static class DownloadRequest.Builder {
-    method public android.telephony.mbms.DownloadRequest.Builder setServiceId(java.lang.String);
+    method public android.telephony.mbms.DownloadRequest.Builder setServiceId(String);
   }
 
   public final class FileInfo implements android.os.Parcelable {
-    ctor public FileInfo(android.net.Uri, java.lang.String);
+    ctor public FileInfo(android.net.Uri, String);
   }
 
   public final class FileServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
-    ctor public FileServiceInfo(java.util.Map<java.util.Locale, java.lang.String>, java.lang.String, java.util.List<java.util.Locale>, java.lang.String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>);
+    ctor public FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>);
   }
 
   public class MbmsDownloadReceiver extends android.content.BroadcastReceiver {
@@ -7652,7 +9024,7 @@
   }
 
   public final class StreamingServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
-    ctor public StreamingServiceInfo(java.util.Map<java.util.Locale, java.lang.String>, java.lang.String, java.util.List<java.util.Locale>, java.lang.String, java.util.Date, java.util.Date);
+    ctor public StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date);
   }
 
   public final class UriPathPair implements android.os.Parcelable {
@@ -7671,18 +9043,22 @@
     ctor public MbmsDownloadServiceBase();
     method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
     method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
+    method public android.os.IBinder asBinder();
     method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
     method public void dispose(int) throws android.os.RemoteException;
     method public int download(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
+    method public static String getDefaultTransactionName(int);
+    method public String getTransactionName(int);
     method public int initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) throws android.os.RemoteException;
-    method public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException;
+    method @NonNull public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException;
     method public void onAppCallbackDied(int, int);
+    method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
     method public int removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
     method public int removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
     method public int requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) throws android.os.RemoteException;
     method public int requestUpdateFileServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException;
     method public int resetDownloadKnowledge(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
-    method public int setTempFileRootDirectory(int, java.lang.String) throws android.os.RemoteException;
+    method public int setTempFileRootDirectory(int, String) throws android.os.RemoteException;
   }
 
   public class MbmsGroupCallServiceBase extends android.app.Service {
@@ -7698,36 +9074,56 @@
 
   public class MbmsStreamingServiceBase extends android.os.Binder {
     ctor public MbmsStreamingServiceBase();
+    method public android.os.IBinder asBinder();
     method public void dispose(int) throws android.os.RemoteException;
-    method public android.net.Uri getPlaybackUri(int, java.lang.String) throws android.os.RemoteException;
+    method public static String getDefaultTransactionName(int);
+    method @Nullable public android.net.Uri getPlaybackUri(int, String) throws android.os.RemoteException;
+    method public String getTransactionName(int);
     method public int initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) throws android.os.RemoteException;
     method public void onAppCallbackDied(int, int);
+    method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
     method public int requestUpdateStreamingServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException;
-    method public int startStreaming(int, java.lang.String, android.telephony.mbms.StreamingServiceCallback) throws android.os.RemoteException;
-    method public void stopStreaming(int, java.lang.String) throws android.os.RemoteException;
+    method public int startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback) throws android.os.RemoteException;
+    method public void stopStreaming(int, String) throws android.os.RemoteException;
   }
 
   public class VendorUtils {
     ctor public VendorUtils();
-    method public static android.content.ComponentName getAppReceiverFromPackageName(android.content.Context, java.lang.String);
-    field public static final java.lang.String ACTION_CLEANUP = "android.telephony.mbms.action.CLEANUP";
-    field public static final java.lang.String ACTION_DOWNLOAD_RESULT_INTERNAL = "android.telephony.mbms.action.DOWNLOAD_RESULT_INTERNAL";
-    field public static final java.lang.String ACTION_FILE_DESCRIPTOR_REQUEST = "android.telephony.mbms.action.FILE_DESCRIPTOR_REQUEST";
-    field public static final java.lang.String EXTRA_FD_COUNT = "android.telephony.mbms.extra.FD_COUNT";
-    field public static final java.lang.String EXTRA_FINAL_URI = "android.telephony.mbms.extra.FINAL_URI";
-    field public static final java.lang.String EXTRA_FREE_URI_LIST = "android.telephony.mbms.extra.FREE_URI_LIST";
-    field public static final java.lang.String EXTRA_PAUSED_LIST = "android.telephony.mbms.extra.PAUSED_LIST";
-    field public static final java.lang.String EXTRA_PAUSED_URI_LIST = "android.telephony.mbms.extra.PAUSED_URI_LIST";
-    field public static final java.lang.String EXTRA_SERVICE_ID = "android.telephony.mbms.extra.SERVICE_ID";
-    field public static final java.lang.String EXTRA_TEMP_FILES_IN_USE = "android.telephony.mbms.extra.TEMP_FILES_IN_USE";
-    field public static final java.lang.String EXTRA_TEMP_FILE_ROOT = "android.telephony.mbms.extra.TEMP_FILE_ROOT";
-    field public static final java.lang.String EXTRA_TEMP_LIST = "android.telephony.mbms.extra.TEMP_LIST";
+    method public static android.content.ComponentName getAppReceiverFromPackageName(android.content.Context, String);
+    field public static final String ACTION_CLEANUP = "android.telephony.mbms.action.CLEANUP";
+    field public static final String ACTION_DOWNLOAD_RESULT_INTERNAL = "android.telephony.mbms.action.DOWNLOAD_RESULT_INTERNAL";
+    field public static final String ACTION_FILE_DESCRIPTOR_REQUEST = "android.telephony.mbms.action.FILE_DESCRIPTOR_REQUEST";
+    field public static final String EXTRA_FD_COUNT = "android.telephony.mbms.extra.FD_COUNT";
+    field public static final String EXTRA_FINAL_URI = "android.telephony.mbms.extra.FINAL_URI";
+    field public static final String EXTRA_FREE_URI_LIST = "android.telephony.mbms.extra.FREE_URI_LIST";
+    field public static final String EXTRA_PAUSED_LIST = "android.telephony.mbms.extra.PAUSED_LIST";
+    field public static final String EXTRA_PAUSED_URI_LIST = "android.telephony.mbms.extra.PAUSED_URI_LIST";
+    field public static final String EXTRA_SERVICE_ID = "android.telephony.mbms.extra.SERVICE_ID";
+    field public static final String EXTRA_TEMP_FILES_IN_USE = "android.telephony.mbms.extra.TEMP_FILES_IN_USE";
+    field public static final String EXTRA_TEMP_FILE_ROOT = "android.telephony.mbms.extra.TEMP_FILE_ROOT";
+    field public static final String EXTRA_TEMP_LIST = "android.telephony.mbms.extra.TEMP_LIST";
   }
 
 }
 
 package android.util {
 
+  public class DocumentsStatsLog {
+    method public static void logActivityLaunch(int, boolean, int, int);
+    method public static void logFileOperation(int, int);
+    method public static void logFileOperationCanceled(int);
+    method public static void logFileOperationCopyMoveMode(int, int);
+    method public static void logFileOperationFailure(int, int);
+    method public static void logFilePick(int, long, int, boolean, int, int, int);
+    method public static void logInvalidScopedAccessRequest(int);
+    method public static void logPickerLaunchedFrom(String);
+    method public static void logRootVisited(int, int);
+    method public static void logSearchMode(int);
+    method public static void logSearchType(int);
+    method public static void logStartupMs(int);
+    method public static void logUserAction(int);
+  }
+
   public class EventLog {
     method public static void readEventsOnWrapping(int[], long, java.util.Collection<android.util.EventLog.Event>) throws java.io.IOException;
   }
@@ -7741,20 +9137,20 @@
 package android.view {
 
   public abstract class Window {
-    method public void addSystemFlags(int);
+    method public void addSystemFlags(@android.view.WindowManager.LayoutParams.SystemFlags int);
   }
 
-  public abstract interface WindowManager implements android.view.ViewManager {
-    method public abstract android.graphics.Region getCurrentImeTouchRegion();
+  public interface WindowManager extends android.view.ViewManager {
+    method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public android.graphics.Region getCurrentImeTouchRegion();
   }
 
   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 SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 524288; // 0x80000
+    field @RequiresPermission(android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS) public static final int SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 524288; // 0x80000
   }
 
-  public static abstract class WindowManager.LayoutParams.SystemFlags implements java.lang.annotation.Annotation {
+  @IntDef(flag=true, prefix={"SYSTEM_FLAG_"}, value={android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface WindowManager.LayoutParams.SystemFlags {
   }
 
 }
@@ -7763,7 +9159,19 @@
 
   public final class AccessibilityManager {
     method public int getAccessibilityWindowId(android.os.IBinder);
-    method public void performAccessibilityShortcut();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void performAccessibilityShortcut();
+  }
+
+}
+
+package android.view.autofill {
+
+  public final class AutofillManager {
+    method @NonNull public java.util.Set<android.content.ComponentName> getAugmentedAutofillDisabledActivities();
+    method @NonNull public java.util.Set<java.lang.String> getAugmentedAutofillDisabledPackages();
+    method public void setActivityAugmentedAutofillEnabled(@NonNull android.content.ComponentName, boolean);
+    method public void setAugmentedAutofillWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>);
+    method public void setPackageAugmentedAutofillEnabled(@NonNull String, boolean);
   }
 
 }
@@ -7771,13 +9179,14 @@
 package android.view.contentcapture {
 
   public final class ContentCaptureContext implements android.os.Parcelable {
-    method public android.content.ComponentName getActivityComponent();
+    method @Nullable public String getAction();
+    method @Nullable public android.content.ComponentName getActivityComponent();
     method public int getDisplayId();
-    method public android.os.Bundle getExtras();
+    method @Nullable public android.os.Bundle getExtras();
     method public int getFlags();
-    method public android.view.contentcapture.ContentCaptureSessionId getParentSessionId();
+    method @Nullable public android.view.contentcapture.ContentCaptureSessionId getParentSessionId();
     method public int getTaskId();
-    method public android.net.Uri getUri();
+    method @Nullable public android.net.Uri getUri();
     field public static final int FLAG_DISABLED_BY_APP = 1; // 0x1
     field public static final int FLAG_DISABLED_BY_FLAG_SECURE = 2; // 0x2
   }
@@ -7785,11 +9194,11 @@
   public final class ContentCaptureEvent implements android.os.Parcelable {
     method public int describeContents();
     method public long getEventTime();
-    method public int getFlags();
-    method public android.view.autofill.AutofillId getId();
-    method public java.lang.CharSequence getText();
+    method @Nullable public android.view.autofill.AutofillId getId();
+    method @Nullable public java.util.List<android.view.autofill.AutofillId> getIds();
+    method @Nullable public CharSequence getText();
     method public int getType();
-    method public android.view.contentcapture.ViewNode getViewNode();
+    method @Nullable public android.view.contentcapture.ViewNode getViewNode();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureEvent> CREATOR;
     field public static final int TYPE_VIEW_APPEARED = 1; // 0x1
@@ -7798,18 +9207,18 @@
   }
 
   public final class UserDataRemovalRequest implements android.os.Parcelable {
-    method public java.lang.String getPackageName();
-    method public java.util.List<android.view.contentcapture.UserDataRemovalRequest.UriRequest> getUriRequests();
+    method @NonNull public String getPackageName();
+    method @NonNull public java.util.List<android.view.contentcapture.UserDataRemovalRequest.UriRequest> getUriRequests();
     method public boolean isForEverything();
   }
 
   public final class UserDataRemovalRequest.UriRequest {
-    method public android.net.Uri getUri();
-    method public boolean isRecursive();
+    method @NonNull public android.net.Uri getUri();
+    method @NonNull public boolean isRecursive();
   }
 
   public final class ViewNode extends android.app.assist.AssistStructure.ViewNode {
-    method public android.view.autofill.AutofillId getParentAutofillId();
+    method @Nullable public android.view.autofill.AutofillId getParentAutofillId();
   }
 
 }
@@ -7818,8 +9227,8 @@
 
   public abstract class CookieManager {
     method protected abstract boolean allowFileSchemeCookiesImpl();
-    method public abstract java.lang.String getCookie(java.lang.String, boolean);
-    method public synchronized java.lang.String getCookie(android.net.WebAddress);
+    method public abstract String getCookie(String, boolean);
+    method public String getCookie(android.net.WebAddress);
     method public abstract boolean hasCookies(boolean);
     method protected abstract void setAcceptFileSchemeCookiesImpl(boolean);
   }
@@ -7827,7 +9236,7 @@
   public class FindActionModeCallback implements android.view.ActionMode.Callback android.text.TextWatcher android.view.View.OnClickListener android.webkit.WebView.FindListener {
     ctor public FindActionModeCallback(android.content.Context);
     method public void afterTextChanged(android.text.Editable);
-    method public void beforeTextChanged(java.lang.CharSequence, int, int, int);
+    method public void beforeTextChanged(CharSequence, int, int, int);
     method public void findAll();
     method public void finish();
     method public int getActionModeGlobalBottom();
@@ -7837,9 +9246,9 @@
     method public void onDestroyActionMode(android.view.ActionMode);
     method public void onFindResultReceived(int, int, boolean);
     method public boolean onPrepareActionMode(android.view.ActionMode, android.view.Menu);
-    method public void onTextChanged(java.lang.CharSequence, int, int, int);
-    method public void setText(java.lang.String);
-    method public void setWebView(android.webkit.WebView);
+    method public void onTextChanged(CharSequence, int, int, int);
+    method public void setText(String);
+    method public void setWebView(@NonNull android.webkit.WebView);
     method public void showSoftInput();
     method public void updateMatchCount(int, int, boolean);
   }
@@ -7861,7 +9270,7 @@
   }
 
   public class JsDialogHelper {
-    ctor public JsDialogHelper(android.webkit.JsPromptResult, int, java.lang.String, java.lang.String, java.lang.String);
+    ctor public JsDialogHelper(android.webkit.JsPromptResult, int, String, String, String);
     ctor public JsDialogHelper(android.webkit.JsPromptResult, android.os.Message);
     method public boolean invokeCallback(android.webkit.WebChromeClient, android.webkit.WebView);
     method public void showDialog(android.content.Context);
@@ -7873,7 +9282,7 @@
 
   public class JsPromptResult extends android.webkit.JsResult {
     ctor public JsPromptResult(android.webkit.JsResult.ResultReceiver);
-    method public java.lang.String getStringResult();
+    method public String getStringResult();
   }
 
   public class JsResult {
@@ -7881,28 +9290,28 @@
     method public final boolean getResult();
   }
 
-  public static abstract interface JsResult.ResultReceiver {
-    method public abstract void onJsResultComplete(android.webkit.JsResult);
+  public static interface JsResult.ResultReceiver {
+    method public void onJsResultComplete(android.webkit.JsResult);
   }
 
   public class SslErrorHandler extends android.os.Handler {
     ctor public SslErrorHandler();
   }
 
-  public abstract deprecated class TokenBindingService {
-    ctor public TokenBindingService();
+  @Deprecated public abstract class TokenBindingService {
+    ctor @Deprecated public TokenBindingService();
   }
 
   public class WebChromeClient {
-    method public deprecated void openFileChooser(android.webkit.ValueCallback<android.net.Uri>, java.lang.String, java.lang.String);
+    method @Deprecated public void openFileChooser(android.webkit.ValueCallback<android.net.Uri>, String, String);
   }
 
   public abstract class WebHistoryItem implements java.lang.Cloneable {
-    method public abstract deprecated int getId();
+    method @Deprecated public abstract int getId();
   }
 
-  public abstract deprecated class WebIconDatabase {
-    method public abstract void bulkRequestIconForPageUrl(android.content.ContentResolver, java.lang.String, android.webkit.WebIconDatabase.IconListener);
+  @Deprecated public abstract class WebIconDatabase {
+    method @Deprecated public abstract void bulkRequestIconForPageUrl(android.content.ContentResolver, String, android.webkit.WebIconDatabase.IconListener);
   }
 
   public abstract class WebMessagePort {
@@ -7914,21 +9323,21 @@
   }
 
   public class WebResourceResponse {
-    ctor public WebResourceResponse(boolean, java.lang.String, java.lang.String, int, java.lang.String, java.util.Map<java.lang.String, java.lang.String>, java.io.InputStream);
+    ctor public WebResourceResponse(boolean, String, String, int, String, java.util.Map<java.lang.String,java.lang.String>, java.io.InputStream);
   }
 
   public abstract class WebSettings {
     method public abstract boolean getAcceptThirdPartyCookies();
-    method public abstract deprecated boolean getNavDump();
-    method public abstract deprecated boolean getPluginsEnabled();
-    method public abstract deprecated boolean getUseWebViewBackgroundForOverscrollBackground();
-    method public abstract deprecated int getUserAgent();
+    method @Deprecated public abstract boolean getNavDump();
+    method @Deprecated public abstract boolean getPluginsEnabled();
+    method @Deprecated public abstract boolean getUseWebViewBackgroundForOverscrollBackground();
+    method @Deprecated public abstract int getUserAgent();
     method public abstract boolean getVideoOverlayForEmbeddedEncryptedVideoEnabled();
     method public abstract void setAcceptThirdPartyCookies(boolean);
-    method public abstract deprecated void setNavDump(boolean);
-    method public abstract deprecated void setPluginsEnabled(boolean);
-    method public abstract deprecated void setUseWebViewBackgroundForOverscrollBackground(boolean);
-    method public abstract deprecated void setUserAgent(int);
+    method @Deprecated public abstract void setNavDump(boolean);
+    method @Deprecated public abstract void setPluginsEnabled(boolean);
+    method @Deprecated public abstract void setUseWebViewBackgroundForOverscrollBackground(boolean);
+    method @Deprecated public abstract void setUserAgent(int);
     method public abstract void setVideoOverlayForEmbeddedEncryptedVideoEnabled(boolean);
   }
 
@@ -7937,7 +9346,7 @@
   }
 
   public static class WebStorage.Origin {
-    ctor protected WebStorage.Origin(java.lang.String, long, long);
+    ctor protected WebStorage.Origin(String, long, long);
   }
 
   public class WebView extends android.widget.AbsoluteLayout implements android.view.ViewGroup.OnHierarchyChangeListener android.view.ViewTreeObserver.OnGlobalFocusChangeListener {
@@ -7946,7 +9355,7 @@
 
   public static class WebView.HitTestResult {
     ctor public WebView.HitTestResult();
-    method public void setExtra(java.lang.String);
+    method public void setExtra(String);
     method public void setType(int);
   }
 
@@ -7980,27 +9389,28 @@
   public final class WebViewDelegate {
     method public void addWebViewAssetPath(android.content.Context);
     method public void callDrawGlFunction(android.graphics.Canvas, long);
-    method public void callDrawGlFunction(android.graphics.Canvas, long, java.lang.Runnable);
+    method public void callDrawGlFunction(@NonNull android.graphics.Canvas, long, @Nullable Runnable);
     method public boolean canInvokeDrawGlFunctor(android.view.View);
     method public void detachDrawGlFunctor(android.view.View, long);
+    method public void drawWebViewFunctor(@NonNull android.graphics.Canvas, int);
     method public android.app.Application getApplication();
-    method public java.lang.String getDataDirectorySuffix();
-    method public java.lang.String getErrorString(android.content.Context, int);
-    method public int getPackageId(android.content.res.Resources, java.lang.String);
+    method public String getDataDirectorySuffix();
+    method public String getErrorString(android.content.Context, int);
+    method public int getPackageId(android.content.res.Resources, String);
     method public void invokeDrawGlFunctor(android.view.View, long, boolean);
     method public boolean isMultiProcessEnabled();
     method public boolean isTraceTagEnabled();
     method public void setOnTraceEnabledChangeListener(android.webkit.WebViewDelegate.OnTraceEnabledChangeListener);
   }
 
-  public static abstract interface WebViewDelegate.OnTraceEnabledChangeListener {
-    method public abstract void onTraceEnabledChange(boolean);
+  public static interface WebViewDelegate.OnTraceEnabledChangeListener {
+    method public void onTraceEnabledChange(boolean);
   }
 
   public final class WebViewFactory {
     ctor public WebViewFactory();
     method public static android.content.pm.PackageInfo getLoadedPackageInfo();
-    method public static int loadWebViewNativeLibraryFromPackage(java.lang.String, java.lang.ClassLoader);
+    method public static int loadWebViewNativeLibraryFromPackage(String, ClassLoader);
     method public static void prepareWebViewInZygote();
     field public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2; // 0x2
     field public static final int LIBLOAD_FAILED_JNI_CALL = 7; // 0x7
@@ -8014,214 +9424,221 @@
     field public static final int LIBLOAD_WRONG_PACKAGE_NAME = 1; // 0x1
   }
 
-  public abstract interface WebViewFactoryProvider {
-    method public abstract android.webkit.WebViewProvider createWebView(android.webkit.WebView, android.webkit.WebView.PrivateAccess);
-    method public abstract android.webkit.CookieManager getCookieManager();
-    method public abstract android.webkit.GeolocationPermissions getGeolocationPermissions();
-    method public abstract android.webkit.ServiceWorkerController getServiceWorkerController();
-    method public abstract android.webkit.WebViewFactoryProvider.Statics getStatics();
-    method public abstract deprecated android.webkit.TokenBindingService getTokenBindingService();
-    method public abstract android.webkit.TracingController getTracingController();
-    method public abstract android.webkit.WebIconDatabase getWebIconDatabase();
-    method public abstract android.webkit.WebStorage getWebStorage();
-    method public abstract java.lang.ClassLoader getWebViewClassLoader();
-    method public abstract android.webkit.WebViewDatabase getWebViewDatabase(android.content.Context);
+  public interface WebViewFactoryProvider {
+    method public android.webkit.WebViewProvider createWebView(android.webkit.WebView, android.webkit.WebView.PrivateAccess);
+    method public android.webkit.CookieManager getCookieManager();
+    method public android.webkit.GeolocationPermissions getGeolocationPermissions();
+    method public android.webkit.ServiceWorkerController getServiceWorkerController();
+    method public android.webkit.WebViewFactoryProvider.Statics getStatics();
+    method @Deprecated public android.webkit.TokenBindingService getTokenBindingService();
+    method public android.webkit.TracingController getTracingController();
+    method public android.webkit.WebIconDatabase getWebIconDatabase();
+    method public android.webkit.WebStorage getWebStorage();
+    method public ClassLoader getWebViewClassLoader();
+    method public android.webkit.WebViewDatabase getWebViewDatabase(android.content.Context);
   }
 
-  public static abstract interface WebViewFactoryProvider.Statics {
-    method public abstract void clearClientCertPreferences(java.lang.Runnable);
-    method public abstract void enableSlowWholeDocumentDraw();
-    method public abstract java.lang.String findAddress(java.lang.String);
-    method public abstract void freeMemoryForTests();
-    method public abstract java.lang.String getDefaultUserAgent(android.content.Context);
-    method public abstract android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
-    method public abstract void initSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
-    method public abstract android.net.Uri[] parseFileChooserResult(int, android.content.Intent);
-    method public abstract void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
-    method public abstract void setWebContentsDebuggingEnabled(boolean);
+  public static interface WebViewFactoryProvider.Statics {
+    method public void clearClientCertPreferences(Runnable);
+    method public void enableSlowWholeDocumentDraw();
+    method public String findAddress(String);
+    method public void freeMemoryForTests();
+    method public String getDefaultUserAgent(android.content.Context);
+    method @NonNull public android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
+    method public void initSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
+    method public android.net.Uri[] parseFileChooserResult(int, android.content.Intent);
+    method public void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
+    method public void setWebContentsDebuggingEnabled(boolean);
   }
 
-  public abstract interface WebViewProvider {
-    method public abstract void addJavascriptInterface(java.lang.Object, java.lang.String);
-    method public abstract boolean canGoBack();
-    method public abstract boolean canGoBackOrForward(int);
-    method public abstract boolean canGoForward();
-    method public abstract boolean canZoomIn();
-    method public abstract boolean canZoomOut();
-    method public abstract android.graphics.Picture capturePicture();
-    method public abstract void clearCache(boolean);
-    method public abstract void clearFormData();
-    method public abstract void clearHistory();
-    method public abstract void clearMatches();
-    method public abstract void clearSslPreferences();
-    method public abstract void clearView();
-    method public abstract android.webkit.WebBackForwardList copyBackForwardList();
-    method public abstract android.print.PrintDocumentAdapter createPrintDocumentAdapter(java.lang.String);
-    method public abstract android.webkit.WebMessagePort[] createWebMessageChannel();
-    method public abstract void destroy();
-    method public abstract void documentHasImages(android.os.Message);
-    method public abstract void dumpViewHierarchyWithProperties(java.io.BufferedWriter, int);
-    method public abstract void evaluateJavaScript(java.lang.String, android.webkit.ValueCallback<java.lang.String>);
-    method public abstract int findAll(java.lang.String);
-    method public abstract void findAllAsync(java.lang.String);
-    method public abstract android.view.View findHierarchyView(java.lang.String, int);
-    method public abstract void findNext(boolean);
-    method public abstract void flingScroll(int, int);
-    method public abstract void freeMemory();
-    method public abstract android.net.http.SslCertificate getCertificate();
-    method public abstract int getContentHeight();
-    method public abstract int getContentWidth();
-    method public abstract android.graphics.Bitmap getFavicon();
-    method public abstract android.webkit.WebView.HitTestResult getHitTestResult();
-    method public abstract java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
-    method public abstract java.lang.String getOriginalUrl();
-    method public abstract int getProgress();
-    method public abstract boolean getRendererPriorityWaivedWhenNotVisible();
-    method public abstract int getRendererRequestedPriority();
-    method public abstract float getScale();
-    method public abstract android.webkit.WebViewProvider.ScrollDelegate getScrollDelegate();
-    method public abstract android.webkit.WebSettings getSettings();
-    method public default android.view.textclassifier.TextClassifier getTextClassifier();
-    method public abstract java.lang.String getTitle();
-    method public abstract java.lang.String getTouchIconUrl();
-    method public abstract java.lang.String getUrl();
-    method public abstract android.webkit.WebViewProvider.ViewDelegate getViewDelegate();
-    method public abstract int getVisibleTitleHeight();
-    method public abstract android.webkit.WebChromeClient getWebChromeClient();
-    method public abstract android.webkit.WebViewClient getWebViewClient();
-    method public abstract android.view.View getZoomControls();
-    method public abstract void goBack();
-    method public abstract void goBackOrForward(int);
-    method public abstract void goForward();
-    method public abstract void init(java.util.Map<java.lang.String, java.lang.Object>, boolean);
-    method public abstract void insertVisualStateCallback(long, android.webkit.WebView.VisualStateCallback);
-    method public abstract void invokeZoomPicker();
-    method public abstract boolean isPaused();
-    method public abstract boolean isPrivateBrowsingEnabled();
-    method public abstract void loadData(java.lang.String, java.lang.String, java.lang.String);
-    method public abstract void loadDataWithBaseURL(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public abstract void loadUrl(java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
-    method public abstract void loadUrl(java.lang.String);
-    method public abstract void notifyFindDialogDismissed();
-    method public abstract void onPause();
-    method public abstract void onResume();
-    method public abstract boolean overlayHorizontalScrollbar();
-    method public abstract boolean overlayVerticalScrollbar();
-    method public abstract boolean pageDown(boolean);
-    method public abstract boolean pageUp(boolean);
-    method public abstract void pauseTimers();
-    method public abstract void postMessageToMainFrame(android.webkit.WebMessage, android.net.Uri);
-    method public abstract void postUrl(java.lang.String, byte[]);
-    method public abstract void reload();
-    method public abstract void removeJavascriptInterface(java.lang.String);
-    method public abstract void requestFocusNodeHref(android.os.Message);
-    method public abstract void requestImageRef(android.os.Message);
-    method public abstract boolean restorePicture(android.os.Bundle, java.io.File);
-    method public abstract android.webkit.WebBackForwardList restoreState(android.os.Bundle);
-    method public abstract void resumeTimers();
-    method public abstract void savePassword(java.lang.String, java.lang.String, java.lang.String);
-    method public abstract boolean savePicture(android.os.Bundle, java.io.File);
-    method public abstract android.webkit.WebBackForwardList saveState(android.os.Bundle);
-    method public abstract void saveWebArchive(java.lang.String);
-    method public abstract void saveWebArchive(java.lang.String, boolean, android.webkit.ValueCallback<java.lang.String>);
-    method public abstract void setCertificate(android.net.http.SslCertificate);
-    method public abstract void setDownloadListener(android.webkit.DownloadListener);
-    method public abstract void setFindListener(android.webkit.WebView.FindListener);
-    method public abstract void setHorizontalScrollbarOverlay(boolean);
-    method public abstract void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public abstract void setInitialScale(int);
-    method public abstract void setMapTrackballToArrowKeys(boolean);
-    method public abstract void setNetworkAvailable(boolean);
-    method public abstract void setPictureListener(android.webkit.WebView.PictureListener);
-    method public abstract void setRendererPriorityPolicy(int, boolean);
-    method public default void setTextClassifier(android.view.textclassifier.TextClassifier);
-    method public abstract void setVerticalScrollbarOverlay(boolean);
-    method public abstract void setWebChromeClient(android.webkit.WebChromeClient);
-    method public abstract void setWebViewClient(android.webkit.WebViewClient);
-    method public abstract boolean showFindDialog(java.lang.String, boolean);
-    method public abstract void stopLoading();
-    method public abstract boolean zoomBy(float);
-    method public abstract boolean zoomIn();
-    method public abstract boolean zoomOut();
+  public interface WebViewProvider {
+    method public void addJavascriptInterface(Object, String);
+    method public boolean canGoBack();
+    method public boolean canGoBackOrForward(int);
+    method public boolean canGoForward();
+    method public boolean canZoomIn();
+    method public boolean canZoomOut();
+    method public android.graphics.Picture capturePicture();
+    method public void clearCache(boolean);
+    method public void clearFormData();
+    method public void clearHistory();
+    method public void clearMatches();
+    method public void clearSslPreferences();
+    method public void clearView();
+    method public android.webkit.WebBackForwardList copyBackForwardList();
+    method public android.print.PrintDocumentAdapter createPrintDocumentAdapter(String);
+    method public android.webkit.WebMessagePort[] createWebMessageChannel();
+    method public void destroy();
+    method public void documentHasImages(android.os.Message);
+    method public void dumpViewHierarchyWithProperties(java.io.BufferedWriter, int);
+    method public void evaluateJavaScript(String, android.webkit.ValueCallback<java.lang.String>);
+    method public int findAll(String);
+    method public void findAllAsync(String);
+    method public android.view.View findHierarchyView(String, int);
+    method public void findNext(boolean);
+    method public void flingScroll(int, int);
+    method public void freeMemory();
+    method public android.net.http.SslCertificate getCertificate();
+    method public int getContentHeight();
+    method public int getContentWidth();
+    method public android.graphics.Bitmap getFavicon();
+    method public android.webkit.WebView.HitTestResult getHitTestResult();
+    method public String[] getHttpAuthUsernamePassword(String, String);
+    method public String getOriginalUrl();
+    method public int getProgress();
+    method public boolean getRendererPriorityWaivedWhenNotVisible();
+    method public int getRendererRequestedPriority();
+    method public float getScale();
+    method public android.webkit.WebViewProvider.ScrollDelegate getScrollDelegate();
+    method public android.webkit.WebSettings getSettings();
+    method @NonNull public default android.view.textclassifier.TextClassifier getTextClassifier();
+    method public String getTitle();
+    method public String getTouchIconUrl();
+    method public String getUrl();
+    method public android.webkit.WebViewProvider.ViewDelegate getViewDelegate();
+    method public int getVisibleTitleHeight();
+    method public android.webkit.WebChromeClient getWebChromeClient();
+    method public android.webkit.WebViewClient getWebViewClient();
+    method public android.webkit.WebViewRenderer getWebViewRenderer();
+    method public android.webkit.WebViewRendererClient getWebViewRendererClient();
+    method public android.view.View getZoomControls();
+    method public void goBack();
+    method public void goBackOrForward(int);
+    method public void goForward();
+    method public void init(java.util.Map<java.lang.String,java.lang.Object>, boolean);
+    method public void insertVisualStateCallback(long, android.webkit.WebView.VisualStateCallback);
+    method public void invokeZoomPicker();
+    method public boolean isPaused();
+    method public boolean isPrivateBrowsingEnabled();
+    method public void loadData(String, String, String);
+    method public void loadDataWithBaseURL(String, String, String, String, String);
+    method public void loadUrl(String, java.util.Map<java.lang.String,java.lang.String>);
+    method public void loadUrl(String);
+    method public void notifyFindDialogDismissed();
+    method public void onPause();
+    method public void onResume();
+    method public boolean overlayHorizontalScrollbar();
+    method public boolean overlayVerticalScrollbar();
+    method public boolean pageDown(boolean);
+    method public boolean pageUp(boolean);
+    method public void pauseTimers();
+    method public void postMessageToMainFrame(android.webkit.WebMessage, android.net.Uri);
+    method public void postUrl(String, byte[]);
+    method public void reload();
+    method public void removeJavascriptInterface(String);
+    method public void requestFocusNodeHref(android.os.Message);
+    method public void requestImageRef(android.os.Message);
+    method public boolean restorePicture(android.os.Bundle, java.io.File);
+    method public android.webkit.WebBackForwardList restoreState(android.os.Bundle);
+    method public void resumeTimers();
+    method public void savePassword(String, String, String);
+    method public boolean savePicture(android.os.Bundle, java.io.File);
+    method public android.webkit.WebBackForwardList saveState(android.os.Bundle);
+    method public void saveWebArchive(String);
+    method public void saveWebArchive(String, boolean, android.webkit.ValueCallback<java.lang.String>);
+    method public void setCertificate(android.net.http.SslCertificate);
+    method public void setDownloadListener(android.webkit.DownloadListener);
+    method public void setFindListener(android.webkit.WebView.FindListener);
+    method public void setHorizontalScrollbarOverlay(boolean);
+    method public void setHttpAuthUsernamePassword(String, String, String, String);
+    method public void setInitialScale(int);
+    method public void setMapTrackballToArrowKeys(boolean);
+    method public void setNetworkAvailable(boolean);
+    method public void setPictureListener(android.webkit.WebView.PictureListener);
+    method public void setRendererPriorityPolicy(int, boolean);
+    method public default void setTextClassifier(@Nullable android.view.textclassifier.TextClassifier);
+    method public void setVerticalScrollbarOverlay(boolean);
+    method public void setWebChromeClient(android.webkit.WebChromeClient);
+    method public void setWebViewClient(android.webkit.WebViewClient);
+    method public void setWebViewRendererClient(@Nullable java.util.concurrent.Executor, @Nullable android.webkit.WebViewRendererClient);
+    method public boolean showFindDialog(String, boolean);
+    method public void stopLoading();
+    method public boolean zoomBy(float);
+    method public boolean zoomIn();
+    method public boolean zoomOut();
   }
 
-  public static abstract interface WebViewProvider.ScrollDelegate {
-    method public abstract int computeHorizontalScrollOffset();
-    method public abstract int computeHorizontalScrollRange();
-    method public abstract void computeScroll();
-    method public abstract int computeVerticalScrollExtent();
-    method public abstract int computeVerticalScrollOffset();
-    method public abstract int computeVerticalScrollRange();
+  public static interface WebViewProvider.ScrollDelegate {
+    method public int computeHorizontalScrollOffset();
+    method public int computeHorizontalScrollRange();
+    method public void computeScroll();
+    method public int computeVerticalScrollExtent();
+    method public int computeVerticalScrollOffset();
+    method public int computeVerticalScrollRange();
   }
 
-  public static abstract interface WebViewProvider.ViewDelegate {
+  public static interface WebViewProvider.ViewDelegate {
     method public default void autofill(android.util.SparseArray<android.view.autofill.AutofillValue>);
-    method public abstract boolean dispatchKeyEvent(android.view.KeyEvent);
-    method public abstract android.view.View findFocus(android.view.View);
-    method public abstract android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
-    method public abstract android.os.Handler getHandler(android.os.Handler);
+    method public boolean dispatchKeyEvent(android.view.KeyEvent);
+    method public android.view.View findFocus(android.view.View);
+    method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
+    method public android.os.Handler getHandler(android.os.Handler);
     method public default boolean isVisibleToUserForAutofill(int);
-    method public abstract void onActivityResult(int, int, android.content.Intent);
-    method public abstract void onAttachedToWindow();
+    method public void onActivityResult(int, int, android.content.Intent);
+    method public void onAttachedToWindow();
     method public default boolean onCheckIsTextEditor();
-    method public abstract void onConfigurationChanged(android.content.res.Configuration);
-    method public abstract android.view.inputmethod.InputConnection onCreateInputConnection(android.view.inputmethod.EditorInfo);
-    method public abstract void onDetachedFromWindow();
-    method public abstract boolean onDragEvent(android.view.DragEvent);
-    method public abstract void onDraw(android.graphics.Canvas);
-    method public abstract void onDrawVerticalScrollBar(android.graphics.Canvas, android.graphics.drawable.Drawable, int, int, int, int);
-    method public abstract void onFinishTemporaryDetach();
-    method public abstract void onFocusChanged(boolean, int, android.graphics.Rect);
-    method public abstract boolean onGenericMotionEvent(android.view.MotionEvent);
-    method public abstract boolean onHoverEvent(android.view.MotionEvent);
-    method public abstract void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public abstract void onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo);
-    method public abstract boolean onKeyDown(int, android.view.KeyEvent);
-    method public abstract boolean onKeyMultiple(int, int, android.view.KeyEvent);
-    method public abstract boolean onKeyUp(int, android.view.KeyEvent);
-    method public abstract void onMeasure(int, int);
+    method public void onConfigurationChanged(android.content.res.Configuration);
+    method public android.view.inputmethod.InputConnection onCreateInputConnection(android.view.inputmethod.EditorInfo);
+    method public void onDetachedFromWindow();
+    method public boolean onDragEvent(android.view.DragEvent);
+    method public void onDraw(android.graphics.Canvas);
+    method public void onDrawVerticalScrollBar(android.graphics.Canvas, android.graphics.drawable.Drawable, int, int, int, int);
+    method public void onFinishTemporaryDetach();
+    method public void onFocusChanged(boolean, int, android.graphics.Rect);
+    method public boolean onGenericMotionEvent(android.view.MotionEvent);
+    method public boolean onHoverEvent(android.view.MotionEvent);
+    method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo);
+    method public boolean onKeyDown(int, android.view.KeyEvent);
+    method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
+    method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public void onMeasure(int, int);
     method public default void onMovedToDisplay(int, android.content.res.Configuration);
-    method public abstract void onOverScrolled(int, int, boolean, boolean);
+    method public void onOverScrolled(int, int, boolean, boolean);
     method public default void onProvideAutofillVirtualStructure(android.view.ViewStructure, int);
     method public default void onProvideContentCaptureStructure(android.view.ViewStructure, int);
-    method public abstract void onProvideVirtualStructure(android.view.ViewStructure);
-    method public abstract void onScrollChanged(int, int, int, int);
-    method public abstract void onSizeChanged(int, int, int, int);
-    method public abstract void onStartTemporaryDetach();
-    method public abstract boolean onTouchEvent(android.view.MotionEvent);
-    method public abstract boolean onTrackballEvent(android.view.MotionEvent);
-    method public abstract void onVisibilityChanged(android.view.View, int);
-    method public abstract void onWindowFocusChanged(boolean);
-    method public abstract void onWindowVisibilityChanged(int);
-    method public abstract boolean performAccessibilityAction(int, android.os.Bundle);
-    method public abstract boolean performLongClick();
-    method public abstract void preDispatchDraw(android.graphics.Canvas);
-    method public abstract boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean);
-    method public abstract boolean requestFocus(int, android.graphics.Rect);
-    method public abstract void setBackgroundColor(int);
-    method public abstract boolean setFrame(int, int, int, int);
-    method public abstract void setLayerType(int, android.graphics.Paint);
-    method public abstract void setLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public abstract void setOverScrollMode(int);
-    method public abstract void setScrollBarStyle(int);
-    method public abstract boolean shouldDelayChildPressedState();
+    method public void onProvideVirtualStructure(android.view.ViewStructure);
+    method public void onScrollChanged(int, int, int, int);
+    method public void onSizeChanged(int, int, int, int);
+    method public void onStartTemporaryDetach();
+    method public boolean onTouchEvent(android.view.MotionEvent);
+    method public boolean onTrackballEvent(android.view.MotionEvent);
+    method public void onVisibilityChanged(android.view.View, int);
+    method public void onWindowFocusChanged(boolean);
+    method public void onWindowVisibilityChanged(int);
+    method public boolean performAccessibilityAction(int, android.os.Bundle);
+    method public boolean performLongClick();
+    method public void preDispatchDraw(android.graphics.Canvas);
+    method public boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean);
+    method public boolean requestFocus(int, android.graphics.Rect);
+    method public void setBackgroundColor(int);
+    method public boolean setFrame(int, int, int, int);
+    method public void setLayerType(int, android.graphics.Paint);
+    method public void setLayoutParams(android.view.ViewGroup.LayoutParams);
+    method public void setOverScrollMode(int);
+    method public void setScrollBarStyle(int);
+    method public boolean shouldDelayChildPressedState();
   }
 
   public final class WebViewProviderInfo implements android.os.Parcelable {
-    ctor public WebViewProviderInfo(java.lang.String, java.lang.String, boolean, boolean, java.lang.String[]);
+    ctor public WebViewProviderInfo(String, String, boolean, boolean, String[]);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.webkit.WebViewProviderInfo> CREATOR;
     field public final boolean availableByDefault;
-    field public final java.lang.String description;
+    field public final String description;
     field public final boolean isFallback;
-    field public final java.lang.String packageName;
+    field public final String packageName;
     field public final android.content.pm.Signature[] signatures;
   }
 
+  public abstract class WebViewRenderer {
+    ctor public WebViewRenderer();
+  }
+
   public final class WebViewUpdateService {
     method public static android.webkit.WebViewProviderInfo[] getAllWebViewPackages();
-    method public static java.lang.String getCurrentWebViewPackageName();
+    method public static String getCurrentWebViewPackageName();
     method public static android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
   }
 
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 4beb699..22a3fb3 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -1,11 +1,20 @@
+// Signature format: 2.0
+package android {
+
+  public static final class Manifest.permission {
+    field public static final String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
+  }
+
+}
+
 package android.app {
 
   public class Notification implements android.os.Parcelable {
-    method public static java.lang.Class<? extends android.app.Notification.Style> getNotificationStyleClass(java.lang.String);
+    method public static Class<? extends android.app.Notification.Style> getNotificationStyleClass(String);
   }
 
   public static final class Notification.TvExtender implements android.app.Notification.Extender {
-    method public deprecated java.lang.String getChannel();
+    method @Deprecated public String getChannel();
   }
 
 }
@@ -13,8 +22,8 @@
 package android.app.admin {
 
   public class DevicePolicyManager {
-    method public deprecated java.lang.String getDeviceInitializerApp();
-    method public deprecated android.content.ComponentName getDeviceInitializerComponent();
+    method @Deprecated @Nullable public String getDeviceInitializerApp();
+    method @Deprecated @Nullable public android.content.ComponentName getDeviceInitializerComponent();
   }
 
 }
@@ -22,31 +31,31 @@
 package android.content {
 
   public class Intent implements java.lang.Cloneable android.os.Parcelable {
-    field public static final deprecated java.lang.String ACTION_DEVICE_INITIALIZATION_WIZARD = "android.intent.action.DEVICE_INITIALIZATION_WIZARD";
-    field public static final deprecated java.lang.String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
-    field public static final deprecated java.lang.String ACTION_SERVICE_STATE = "android.intent.action.SERVICE_STATE";
-    field public static final deprecated java.lang.String EXTRA_CDMA_DEFAULT_ROAMING_INDICATOR = "cdmaDefaultRoamingIndicator";
-    field public static final deprecated java.lang.String EXTRA_CDMA_ROAMING_INDICATOR = "cdmaRoamingIndicator";
-    field public static final deprecated java.lang.String EXTRA_CSS_INDICATOR = "cssIndicator";
-    field public static final deprecated java.lang.String EXTRA_DATA_OPERATOR_ALPHA_LONG = "data-operator-alpha-long";
-    field public static final deprecated java.lang.String EXTRA_DATA_OPERATOR_ALPHA_SHORT = "data-operator-alpha-short";
-    field public static final deprecated java.lang.String EXTRA_DATA_OPERATOR_NUMERIC = "data-operator-numeric";
-    field public static final deprecated java.lang.String EXTRA_DATA_RADIO_TECH = "dataRadioTechnology";
-    field public static final deprecated java.lang.String EXTRA_DATA_REG_STATE = "dataRegState";
-    field public static final deprecated java.lang.String EXTRA_DATA_ROAMING_TYPE = "dataRoamingType";
-    field public static final deprecated java.lang.String EXTRA_EMERGENCY_ONLY = "emergencyOnly";
-    field public static final deprecated java.lang.String EXTRA_IS_DATA_ROAMING_FROM_REGISTRATION = "isDataRoamingFromRegistration";
-    field public static final deprecated java.lang.String EXTRA_IS_USING_CARRIER_AGGREGATION = "isUsingCarrierAggregation";
-    field public static final deprecated java.lang.String EXTRA_LTE_EARFCN_RSRP_BOOST = "LteEarfcnRsrpBoost";
-    field public static final deprecated java.lang.String EXTRA_MANUAL = "manual";
-    field public static final deprecated java.lang.String EXTRA_NETWORK_ID = "networkId";
-    field public static final deprecated java.lang.String EXTRA_OPERATOR_ALPHA_LONG = "operator-alpha-long";
-    field public static final deprecated java.lang.String EXTRA_OPERATOR_ALPHA_SHORT = "operator-alpha-short";
-    field public static final deprecated java.lang.String EXTRA_OPERATOR_NUMERIC = "operator-numeric";
-    field public static final deprecated java.lang.String EXTRA_SYSTEM_ID = "systemId";
-    field public static final deprecated java.lang.String EXTRA_VOICE_RADIO_TECH = "radioTechnology";
-    field public static final deprecated java.lang.String EXTRA_VOICE_REG_STATE = "voiceRegState";
-    field public static final deprecated java.lang.String EXTRA_VOICE_ROAMING_TYPE = "voiceRoamingType";
+    field @Deprecated public static final String ACTION_DEVICE_INITIALIZATION_WIZARD = "android.intent.action.DEVICE_INITIALIZATION_WIZARD";
+    field @Deprecated public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
+    field @Deprecated public static final String ACTION_SERVICE_STATE = "android.intent.action.SERVICE_STATE";
+    field @Deprecated public static final String EXTRA_CDMA_DEFAULT_ROAMING_INDICATOR = "cdmaDefaultRoamingIndicator";
+    field @Deprecated public static final String EXTRA_CDMA_ROAMING_INDICATOR = "cdmaRoamingIndicator";
+    field @Deprecated public static final String EXTRA_CSS_INDICATOR = "cssIndicator";
+    field @Deprecated public static final String EXTRA_DATA_OPERATOR_ALPHA_LONG = "data-operator-alpha-long";
+    field @Deprecated public static final String EXTRA_DATA_OPERATOR_ALPHA_SHORT = "data-operator-alpha-short";
+    field @Deprecated public static final String EXTRA_DATA_OPERATOR_NUMERIC = "data-operator-numeric";
+    field @Deprecated public static final String EXTRA_DATA_RADIO_TECH = "dataRadioTechnology";
+    field @Deprecated public static final String EXTRA_DATA_REG_STATE = "dataRegState";
+    field @Deprecated public static final String EXTRA_DATA_ROAMING_TYPE = "dataRoamingType";
+    field @Deprecated public static final String EXTRA_EMERGENCY_ONLY = "emergencyOnly";
+    field @Deprecated public static final String EXTRA_IS_DATA_ROAMING_FROM_REGISTRATION = "isDataRoamingFromRegistration";
+    field @Deprecated public static final String EXTRA_IS_USING_CARRIER_AGGREGATION = "isUsingCarrierAggregation";
+    field @Deprecated public static final String EXTRA_LTE_EARFCN_RSRP_BOOST = "LteEarfcnRsrpBoost";
+    field @Deprecated public static final String EXTRA_MANUAL = "manual";
+    field @Deprecated public static final String EXTRA_NETWORK_ID = "networkId";
+    field @Deprecated public static final String EXTRA_OPERATOR_ALPHA_LONG = "operator-alpha-long";
+    field @Deprecated public static final String EXTRA_OPERATOR_ALPHA_SHORT = "operator-alpha-short";
+    field @Deprecated public static final String EXTRA_OPERATOR_NUMERIC = "operator-numeric";
+    field @Deprecated public static final String EXTRA_SYSTEM_ID = "systemId";
+    field @Deprecated public static final String EXTRA_VOICE_RADIO_TECH = "radioTechnology";
+    field @Deprecated public static final String EXTRA_VOICE_REG_STATE = "voiceRegState";
+    field @Deprecated public static final String EXTRA_VOICE_ROAMING_TYPE = "voiceRoamingType";
   }
 
 }
@@ -54,7 +63,7 @@
 package android.media.tv {
 
   public final class TvInputManager {
-    method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
+    method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
   }
 
   public static final class TvInputManager.Hardware {
@@ -65,7 +74,7 @@
 
 package android.net.wifi {
 
-  public deprecated class BatchedScanResult implements android.os.Parcelable {
+  @Deprecated public class BatchedScanResult implements android.os.Parcelable {
     ctor public BatchedScanResult();
     ctor public BatchedScanResult(android.net.wifi.BatchedScanResult);
     field public final java.util.List<android.net.wifi.ScanResult> scanResults;
@@ -85,8 +94,8 @@
   }
 
   public final class PowerManager {
-    method public deprecated boolean isScreenBrightnessBoosted();
-    field public static final deprecated java.lang.String ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED = "android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED";
+    method @Deprecated public boolean isScreenBrightnessBoosted();
+    field @Deprecated public static final String ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED = "android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED";
   }
 
 }
@@ -95,10 +104,10 @@
 
   public abstract class NotificationListenerService extends android.app.Service {
     method public android.service.notification.StatusBarNotification[] getActiveNotifications(int);
-    method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[], int);
+    method public android.service.notification.StatusBarNotification[] getActiveNotifications(String[], int);
     method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException;
     method public final void setOnNotificationPostedTrim(int);
-    method public final void snoozeNotification(java.lang.String, java.lang.String);
+    method public final void snoozeNotification(String, String);
     method public void unregisterAsSystemService() throws android.os.RemoteException;
     field public static final int TRIM_FULL = 0; // 0x0
     field public static final int TRIM_LIGHT = 1; // 0x1
@@ -114,9 +123,9 @@
 package android.telephony {
 
   public class TelephonyManager {
-    method public deprecated void answerRingingCall();
-    method public deprecated boolean endCall();
-    method public deprecated void silenceRinger();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void answerRingingCall();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public boolean endCall();
+    method @Deprecated public void silenceRinger();
   }
 
 }
diff --git a/api/test-current.txt b/api/test-current.txt
index 9c51c9f..3dfd6e4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1,16 +1,17 @@
+// Signature format: 2.0
 package android {
 
   public static final class Manifest.permission {
-    field public static final java.lang.String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
-    field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
-    field public static final java.lang.String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
-    field public static final java.lang.String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
-    field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
-    field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
-    field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
-    field public static final java.lang.String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
-    field public static final java.lang.String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
-    field public static final java.lang.String WRITE_OBB = "android.permission.WRITE_OBB";
+    field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
+    field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
+    field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
+    field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
+    field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
+    field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
+    field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
+    field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
+    field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+    field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
   }
 
 }
@@ -28,21 +29,22 @@
 
   public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback {
     method public void onMovedToDisplay(int, android.content.res.Configuration);
+    method public void setInheritShowWhenLocked(boolean);
   }
 
   public class ActivityManager {
-    method public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
+    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
     method public void alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName);
-    method public void forceStopPackage(java.lang.String);
-    method public int getPackageImportance(java.lang.String);
+    method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
+    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
     method public long getTotalRam();
-    method public int getUidImportance(int);
-    method public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
-    method public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
+    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
+    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
   }
 
-  public static abstract interface ActivityManager.OnUidImportanceListener {
-    method public abstract void onUidImportance(int, int);
+  public static interface ActivityManager.OnUidImportanceListener {
+    method public void onUidImportance(int, int);
   }
 
   public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable {
@@ -50,7 +52,7 @@
   }
 
   public static class ActivityManager.TaskDescription implements android.os.Parcelable {
-    method public java.lang.String getIconFilename();
+    method public String getIconFilename();
     method public int getIconResource();
   }
 
@@ -62,21 +64,21 @@
   }
 
   public class ActivityTaskManager {
-    method public void clearLaunchParamsForPackages(java.util.List<java.lang.String>);
-    method public java.lang.String listAllStacks();
-    method public void moveTaskToStack(int, int, boolean);
-    method public boolean moveTopActivityToPinnedStack(int, android.graphics.Rect);
-    method public void removeStacksInWindowingModes(int[]) throws java.lang.SecurityException;
-    method public void removeStacksWithActivityTypes(int[]) throws java.lang.SecurityException;
-    method public void resizeDockedStack(android.graphics.Rect, android.graphics.Rect);
-    method public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException;
-    method public void resizeStack(int, android.graphics.Rect, boolean);
-    method public void resizeTask(int, android.graphics.Rect);
-    method public void setDisplayToSingleTaskInstance(int);
-    method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException;
-    method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) throws java.lang.SecurityException;
-    method public void startSystemLockTaskMode(int);
-    method public void stopSystemLockTaskMode();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void clearLaunchParamsForPackages(java.util.List<java.lang.String>);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public String listAllStacks();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void moveTaskToStack(int, int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public boolean moveTopActivityToPinnedStack(int, android.graphics.Rect);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void removeStacksInWindowingModes(int[]) throws java.lang.SecurityException;
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void removeStacksWithActivityTypes(int[]) throws java.lang.SecurityException;
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeDockedStack(android.graphics.Rect, android.graphics.Rect);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException;
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeStack(int, android.graphics.Rect, boolean);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeTask(int, android.graphics.Rect);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setDisplayToSingleTaskInstance(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException;
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) throws java.lang.SecurityException;
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void startSystemLockTaskMode(int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void stopSystemLockTaskMode();
     method public static boolean supportsMultiWindow(android.content.Context);
     method public static boolean supportsSplitScreenMultiWindow(android.content.Context);
     field public static final int INVALID_STACK_ID = -1; // 0xffffffff
@@ -89,66 +91,81 @@
   }
 
   public class AppOpsManager {
-    method public java.util.List<android.app.AppOpsManager.HistoricalPackageOps> getAllHistoricPackagesOps(java.lang.String[], long, long);
-    method public android.app.AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int, java.lang.String, java.lang.String[], long, long);
+    method @RequiresPermission("android.permission.MANAGE_APPOPS") public void addHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOps);
+    method @RequiresPermission("android.permission.MANAGE_APPOPS") public void clearHistory();
+    method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOps(int, @Nullable String, @Nullable String[], long, long, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
+    method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOpsFromDiskRaw(int, @Nullable String, @Nullable String[], long, long, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
     method public static int getNumOps();
-    method public static java.lang.String[] getOpStrs();
-    method public boolean isOperationActive(int, int, java.lang.String);
-    method public static java.lang.String opToPermission(int);
-    method public static int permissionToOpCode(java.lang.String);
-    method public void setMode(int, int, java.lang.String, int);
-    method public void setUidMode(java.lang.String, int, int);
-    method public void startWatchingActive(int[], android.app.AppOpsManager.OnOpActiveChangedListener);
-    method public void stopWatchingActive(android.app.AppOpsManager.OnOpActiveChangedListener);
-    method public static int strOpToOp(java.lang.String);
-    field public static final java.lang.String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
-    field public static final java.lang.String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
-    field public static final java.lang.String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
-    field public static final java.lang.String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
-    field public static final java.lang.String OPSTR_ASSIST_STRUCTURE = "android:assist_structure";
-    field public static final java.lang.String OPSTR_AUDIO_ACCESSIBILITY_VOLUME = "android:audio_accessibility_volume";
-    field public static final java.lang.String OPSTR_AUDIO_ALARM_VOLUME = "android:audio_alarm_volume";
-    field public static final java.lang.String OPSTR_AUDIO_BLUETOOTH_VOLUME = "android:audio_bluetooth_volume";
-    field public static final java.lang.String OPSTR_AUDIO_MASTER_VOLUME = "android:audio_master_volume";
-    field public static final java.lang.String OPSTR_AUDIO_MEDIA_VOLUME = "android:audio_media_volume";
-    field public static final java.lang.String OPSTR_AUDIO_NOTIFICATION_VOLUME = "android:audio_notification_volume";
-    field public static final java.lang.String OPSTR_AUDIO_RING_VOLUME = "android:audio_ring_volume";
-    field public static final java.lang.String OPSTR_AUDIO_VOICE_VOLUME = "android:audio_voice_volume";
-    field public static final java.lang.String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service";
-    field public static final java.lang.String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state";
-    field public static final java.lang.String OPSTR_GET_ACCOUNTS = "android:get_accounts";
-    field public static final java.lang.String OPSTR_GPS = "android:gps";
-    field public static final java.lang.String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
-    field public static final java.lang.String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
-    field public static final java.lang.String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
-    field public static final java.lang.String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
-    field public static final java.lang.String OPSTR_PLAY_AUDIO = "android:play_audio";
-    field public static final java.lang.String OPSTR_POST_NOTIFICATION = "android:post_notification";
-    field public static final java.lang.String OPSTR_PROJECT_MEDIA = "android:project_media";
-    field public static final java.lang.String OPSTR_READ_CLIPBOARD = "android:read_clipboard";
-    field public static final java.lang.String OPSTR_READ_ICC_SMS = "android:read_icc_sms";
-    field public static final java.lang.String OPSTR_RECEIVE_EMERGENCY_BROADCAST = "android:receive_emergency_broadcast";
-    field public static final java.lang.String OPSTR_REQUEST_DELETE_PACKAGES = "android:request_delete_packages";
-    field public static final java.lang.String OPSTR_REQUEST_INSTALL_PACKAGES = "android:request_install_packages";
-    field public static final java.lang.String OPSTR_RUN_ANY_IN_BACKGROUND = "android:run_any_in_background";
-    field public static final java.lang.String OPSTR_RUN_IN_BACKGROUND = "android:run_in_background";
-    field public static final java.lang.String OPSTR_START_FOREGROUND = "android:start_foreground";
-    field public static final java.lang.String OPSTR_TAKE_AUDIO_FOCUS = "android:take_audio_focus";
-    field public static final java.lang.String OPSTR_TAKE_MEDIA_BUTTONS = "android:take_media_buttons";
-    field public static final java.lang.String OPSTR_TOAST_WINDOW = "android:toast_window";
-    field public static final java.lang.String OPSTR_TURN_SCREEN_ON = "android:turn_screen_on";
-    field public static final java.lang.String OPSTR_VIBRATE = "android:vibrate";
-    field public static final java.lang.String OPSTR_WAKE_LOCK = "android:wake_lock";
-    field public static final java.lang.String OPSTR_WIFI_SCAN = "android:wifi_scan";
-    field public static final java.lang.String OPSTR_WRITE_CLIPBOARD = "android:write_clipboard";
-    field public static final java.lang.String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms";
-    field public static final java.lang.String OPSTR_WRITE_SMS = "android:write_sms";
-    field public static final java.lang.String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper";
+    method public static String[] getOpStrs();
+    method public boolean isOperationActive(int, int, String);
+    method @RequiresPermission("android.permission.MANAGE_APPOPS") public void offsetHistory(long);
+    method public static String opToPermission(int);
+    method public static int permissionToOpCode(String);
+    method @RequiresPermission("android.permission.MANAGE_APPOPS") public void resetHistoryParameters();
+    method @RequiresPermission("android.permission.MANAGE_APPOPS") public void setHistoryParameters(int, long, int);
+    method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(int, int, String, int);
+    method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(String, int, int);
+    method public void startWatchingActive(@NonNull int[], @NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
+    method public void stopWatchingActive(@NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
+    method public static int strOpToOp(String);
+    field public static final int HISTORICAL_MODE_DISABLED = 0; // 0x0
+    field public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1; // 0x1
+    field public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2; // 0x2
+    field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
+    field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
+    field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
+    field public static final String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
+    field public static final String OPSTR_ASSIST_STRUCTURE = "android:assist_structure";
+    field public static final String OPSTR_AUDIO_ACCESSIBILITY_VOLUME = "android:audio_accessibility_volume";
+    field public static final String OPSTR_AUDIO_ALARM_VOLUME = "android:audio_alarm_volume";
+    field public static final String OPSTR_AUDIO_BLUETOOTH_VOLUME = "android:audio_bluetooth_volume";
+    field public static final String OPSTR_AUDIO_MASTER_VOLUME = "android:audio_master_volume";
+    field public static final String OPSTR_AUDIO_MEDIA_VOLUME = "android:audio_media_volume";
+    field public static final String OPSTR_AUDIO_NOTIFICATION_VOLUME = "android:audio_notification_volume";
+    field public static final String OPSTR_AUDIO_RING_VOLUME = "android:audio_ring_volume";
+    field public static final String OPSTR_AUDIO_VOICE_VOLUME = "android:audio_voice_volume";
+    field public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service";
+    field public static final String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state";
+    field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts";
+    field public static final String OPSTR_GPS = "android:gps";
+    field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
+    field public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
+    field public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
+    field public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
+    field public static final String OPSTR_PLAY_AUDIO = "android:play_audio";
+    field public static final String OPSTR_POST_NOTIFICATION = "android:post_notification";
+    field public static final String OPSTR_PROJECT_MEDIA = "android:project_media";
+    field public static final String OPSTR_READ_CLIPBOARD = "android:read_clipboard";
+    field public static final String OPSTR_READ_ICC_SMS = "android:read_icc_sms";
+    field public static final String OPSTR_RECEIVE_EMERGENCY_BROADCAST = "android:receive_emergency_broadcast";
+    field public static final String OPSTR_REQUEST_DELETE_PACKAGES = "android:request_delete_packages";
+    field public static final String OPSTR_REQUEST_INSTALL_PACKAGES = "android:request_install_packages";
+    field public static final String OPSTR_RUN_ANY_IN_BACKGROUND = "android:run_any_in_background";
+    field public static final String OPSTR_RUN_IN_BACKGROUND = "android:run_in_background";
+    field public static final String OPSTR_START_FOREGROUND = "android:start_foreground";
+    field public static final String OPSTR_TAKE_AUDIO_FOCUS = "android:take_audio_focus";
+    field public static final String OPSTR_TAKE_MEDIA_BUTTONS = "android:take_media_buttons";
+    field public static final String OPSTR_TOAST_WINDOW = "android:toast_window";
+    field public static final String OPSTR_TURN_SCREEN_ON = "android:turn_screen_on";
+    field public static final String OPSTR_VIBRATE = "android:vibrate";
+    field public static final String OPSTR_WAKE_LOCK = "android:wake_lock";
+    field public static final String OPSTR_WIFI_SCAN = "android:wifi_scan";
+    field public static final String OPSTR_WRITE_CLIPBOARD = "android:write_clipboard";
+    field public static final String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms";
+    field public static final String OPSTR_WRITE_SMS = "android:write_sms";
+    field public static final String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper";
+    field public static final int OP_COARSE_LOCATION = 0; // 0x0
     field public static final int OP_RECORD_AUDIO = 27; // 0x1b
     field public static final int OP_SYSTEM_ALERT_WINDOW = 24; // 0x18
+    field public static final int UID_STATE_BACKGROUND = 4; // 0x4
+    field public static final int UID_STATE_CACHED = 5; // 0x5
+    field public static final int UID_STATE_FOREGROUND = 3; // 0x3
+    field public static final int UID_STATE_FOREGROUND_SERVICE = 2; // 0x2
+    field public static final int UID_STATE_PERSISTENT = 0; // 0x0
+    field public static final int UID_STATE_TOP = 1; // 0x1
   }
 
-  public static final class AppOpsManager.HistoricalOpEntry implements android.os.Parcelable {
+  public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
     method public int describeContents();
     method public long getAccessCount(int);
     method public long getAccessDuration(int);
@@ -158,25 +175,55 @@
     method public long getForegroundAccessCount();
     method public long getForegroundAccessDuration();
     method public long getForegroundRejectCount();
-    method public java.lang.String getOp();
+    method @NonNull public String getOpName();
     method public long getRejectCount(int);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOpEntry> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOp> CREATOR;
+  }
+
+  public static final class AppOpsManager.HistoricalOps implements android.os.Parcelable {
+    ctor public AppOpsManager.HistoricalOps(long, long);
+    method public int describeContents();
+    method public long getBeginTimeMillis();
+    method public long getEndTimeMillis();
+    method public int getUidCount();
+    method @Nullable public android.app.AppOpsManager.HistoricalUidOps getUidOps(int);
+    method @NonNull public android.app.AppOpsManager.HistoricalUidOps getUidOpsAt(int);
+    method public void increaseAccessCount(int, int, @NonNull String, int, long);
+    method public void increaseAccessDuration(int, int, @NonNull String, int, long);
+    method public void increaseRejectCount(int, int, @NonNull String, int, long);
+    method public void offsetBeginAndEndTime(long);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
   }
 
   public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
     method public int describeContents();
-    method public android.app.AppOpsManager.HistoricalOpEntry getEntry(java.lang.String);
-    method public android.app.AppOpsManager.HistoricalOpEntry getEntryAt(int);
-    method public int getEntryCount();
-    method public java.lang.String getPackageName();
-    method public int getUid();
-    method public void writeToParcel(android.os.Parcel, int);
+    method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
+    method @NonNull public android.app.AppOpsManager.HistoricalOp getOpAt(int);
+    method public int getOpCount();
+    method @NonNull public String getPackageName();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalPackageOps> CREATOR;
   }
 
-  public static abstract interface AppOpsManager.OnOpActiveChangedListener {
-    method public abstract void onOpActiveChanged(int, int, java.lang.String, boolean);
+  public static final class AppOpsManager.HistoricalUidOps implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getPackageCount();
+    method @Nullable public android.app.AppOpsManager.HistoricalPackageOps getPackageOps(@NonNull String);
+    method @NonNull public android.app.AppOpsManager.HistoricalPackageOps getPackageOpsAt(int);
+    method public int getUid();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalUidOps> CREATOR;
+  }
+
+  public static interface AppOpsManager.OnOpActiveChangedListener {
+    method public void onOpActiveChanged(int, int, String, boolean);
+  }
+
+  public final class NotificationChannel implements android.os.Parcelable {
+    method public boolean isImportanceLockedByOEM();
+    method public void setImportanceLockedByOEM(boolean);
   }
 
   public final class NotificationChannelGroup implements android.os.Parcelable {
@@ -201,9 +248,9 @@
 
   public final class UiAutomation {
     method public void destroy();
-    method public android.os.ParcelFileDescriptor[] executeShellCommandRw(java.lang.String);
-    method public deprecated boolean grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
-    method public deprecated boolean revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
+    method public android.os.ParcelFileDescriptor[] executeShellCommandRw(String);
+    method @Deprecated public boolean grantRuntimePermission(String, String, android.os.UserHandle);
+    method @Deprecated public boolean revokeRuntimePermission(String, String, android.os.UserHandle);
   }
 
   public class UiModeManager {
@@ -211,7 +258,7 @@
     method public boolean isUiModeLocked();
   }
 
-  public class WindowConfiguration implements java.lang.Comparable android.os.Parcelable {
+  public class WindowConfiguration implements java.lang.Comparable<android.app.WindowConfiguration> android.os.Parcelable {
     ctor public WindowConfiguration();
     method public int compareTo(android.app.WindowConfiguration);
     method public int describeContents();
@@ -247,17 +294,17 @@
 package android.app.admin {
 
   public class DevicePolicyManager {
-    method public java.lang.CharSequence getDeviceOwnerOrganizationName();
+    method @Nullable public CharSequence getDeviceOwnerOrganizationName();
     method public long getLastBugReportRequestTime();
     method public long getLastNetworkLogRetrievalTime();
     method public long getLastSecurityLogRetrievalTime();
-    method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(android.os.UserHandle);
+    method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(@NonNull android.os.UserHandle);
     method public boolean isCurrentInputMethodSetByOwner();
     method public boolean isDeviceManaged();
-    field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
-    field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
-    field public static final java.lang.String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
-    field public static final java.lang.String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
+    field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
+    field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
+    field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
+    field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
   }
 
   public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
@@ -269,10 +316,10 @@
 package android.app.backup {
 
   public class BackupManager {
-    method public android.content.Intent getConfigurationIntent(java.lang.String);
-    method public android.content.Intent getDataManagementIntent(java.lang.String);
-    method public java.lang.String getDataManagementLabel(java.lang.String);
-    method public java.lang.String getDestinationString(java.lang.String);
+    method @RequiresPermission("android.permission.BACKUP") public android.content.Intent getConfigurationIntent(String);
+    method @RequiresPermission("android.permission.BACKUP") public android.content.Intent getDataManagementIntent(String);
+    method @RequiresPermission("android.permission.BACKUP") public String getDataManagementLabel(String);
+    method @RequiresPermission("android.permission.BACKUP") public String getDestinationString(String);
   }
 
 }
@@ -280,16 +327,16 @@
 package android.app.role {
 
   public final class RoleManager {
-    method public void addRoleHolderAsUser(java.lang.String, java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
-    method public void clearRoleHoldersAsUser(java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
-    method public java.util.List<java.lang.String> getRoleHolders(java.lang.String);
-    method public java.util.List<java.lang.String> getRoleHoldersAsUser(java.lang.String, android.os.UserHandle);
-    method public void removeRoleHolderAsUser(java.lang.String, java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
+    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void addRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void clearRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
+    method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
+    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
   }
 
-  public abstract interface RoleManagerCallback {
-    method public abstract void onFailure();
-    method public abstract void onSuccess();
+  public interface RoleManagerCallback {
+    method public void onFailure();
+    method public void onSuccess();
   }
 
 }
@@ -301,8 +348,12 @@
   }
 
   public class StorageStatsManager {
-    method public boolean isQuotaSupported(java.util.UUID);
-    method public boolean isReservedSupported(java.util.UUID);
+    method public boolean isQuotaSupported(@NonNull java.util.UUID);
+    method public boolean isReservedSupported(@NonNull java.util.UUID);
+  }
+
+  public final class UsageStatsManager {
+    method public void forceUsageSourceSettingRead();
   }
 
 }
@@ -318,23 +369,18 @@
 package android.content {
 
   public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
-    method public void setDetectNotResponding(long);
+    method @RequiresPermission(android.Manifest.permission.REMOVE_TASKS) public void setDetectNotResponding(long);
   }
 
   public abstract class ContentResolver implements android.content.ContentInterface {
-    method public static java.lang.String[] getSyncAdapterPackagesForAuthorityAsUser(java.lang.String, int);
+    method public static String[] getSyncAdapterPackagesForAuthorityAsUser(String, int);
   }
 
   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 android.content.Context createPackageContextAsUser(String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.os.UserHandle getUser();
     method public int getUserId();
     method public void setAutofillCompatibilityEnabled(boolean);
-    field public static final java.lang.String ROLLBACK_SERVICE = "rollback";
-  }
-
-  public class Intent implements java.lang.Cloneable android.os.Parcelable {
-    field public static final java.lang.String ACTION_PACKAGE_ROLLBACK_EXECUTED = "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
   }
 
 }
@@ -357,37 +403,35 @@
     ctor public LauncherApps(android.content.Context);
   }
 
-  public static class PackageInstaller.SessionParams implements android.os.Parcelable {
-    method public void setEnableRollback();
-  }
-
   public abstract class PackageManager {
     method public abstract boolean arePermissionsIndividuallyControlled();
-    method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int);
-    method public abstract int getInstallReason(java.lang.String, android.os.UserHandle);
+    method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract String getDefaultBrowserPackageNameAsUser(int);
+    method public abstract int getInstallReason(String, @NonNull android.os.UserHandle);
     method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int);
-    method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
-    method public abstract java.lang.String[] getNamesForUids(int[]);
-    method public abstract java.lang.String getPermissionControllerPackageName();
-    method public abstract java.lang.String getServicesSystemSharedLibraryPackageName();
-    method public abstract java.lang.String getSharedSystemSharedLibraryPackageName();
-    method public java.lang.String getWellbeingPackageName();
-    method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
-    method public abstract void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
-    field public static final java.lang.String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
-    field public static final java.lang.String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
+    method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
+    method @Nullable public abstract String[] getNamesForUids(int[]);
+    method public abstract String getPermissionControllerPackageName();
+    method @NonNull public abstract String getServicesSystemSharedLibraryPackageName();
+    method @NonNull public abstract String getSharedSystemSharedLibraryPackageName();
+    method public String getWellbeingPackageName();
+    method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
+    method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
+    field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
+    field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
     field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
     field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000
-    field public static final java.lang.String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
-    field public static final java.lang.String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared";
+    field public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
+    field public static final String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared";
   }
 
   public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+    field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
     field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
+    field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
     field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
     field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
     field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
-    field public java.lang.String backgroundPermission;
+    field public String backgroundPermission;
   }
 
   public final class ShortcutInfo implements android.os.Parcelable {
@@ -402,48 +446,13 @@
 
 package android.content.res {
 
-  public final class Configuration implements java.lang.Comparable android.os.Parcelable {
+  public final class Configuration implements java.lang.Comparable<android.content.res.Configuration> android.os.Parcelable {
+    field public int assetsSeq;
     field public final android.app.WindowConfiguration windowConfiguration;
   }
 
 }
 
-package android.content.rollback {
-
-  public final class PackageRollbackInfo implements android.os.Parcelable {
-    ctor public PackageRollbackInfo(java.lang.String, android.content.rollback.PackageRollbackInfo.PackageVersion, android.content.rollback.PackageRollbackInfo.PackageVersion);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.content.rollback.PackageRollbackInfo> CREATOR;
-    field public final android.content.rollback.PackageRollbackInfo.PackageVersion higherVersion;
-    field public final android.content.rollback.PackageRollbackInfo.PackageVersion lowerVersion;
-    field public final java.lang.String packageName;
-  }
-
-  public static class PackageRollbackInfo.PackageVersion {
-    ctor public PackageRollbackInfo.PackageVersion(long);
-    field public final long versionCode;
-  }
-
-  public final class RollbackInfo implements android.os.Parcelable {
-    ctor public RollbackInfo(android.content.rollback.PackageRollbackInfo);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR;
-    field public final android.content.rollback.PackageRollbackInfo targetPackage;
-  }
-
-  public final class RollbackManager {
-    method public void executeRollback(android.content.rollback.RollbackInfo, android.content.IntentSender);
-    method public void expireRollbackForPackage(java.lang.String);
-    method public android.content.rollback.RollbackInfo getAvailableRollback(java.lang.String);
-    method public java.util.List<java.lang.String> getPackagesWithAvailableRollbacks();
-    method public java.util.List<android.content.rollback.RollbackInfo> getRecentlyExecutedRollbacks();
-    method public void reloadPersistedData();
-  }
-
-}
-
 package android.database.sqlite {
 
   public class SQLiteCompatibilityWalFlags {
@@ -451,14 +460,14 @@
   }
 
   public final class SQLiteDebug {
-    method public static void dump(android.util.Printer, java.lang.String[]);
+    method public static void dump(android.util.Printer, String[]);
     method public static android.database.sqlite.SQLiteDebug.PagerStats getDatabaseInfo();
   }
 
   public static class SQLiteDebug.DbStats {
-    ctor public SQLiteDebug.DbStats(java.lang.String, long, long, int, int, int, int);
-    field public java.lang.String cache;
-    field public java.lang.String dbName;
+    ctor public SQLiteDebug.DbStats(String, long, long, int, int, int, int);
+    field public String cache;
+    field public String dbName;
     field public long dbSize;
     field public int lookaside;
     field public long pageSize;
@@ -473,23 +482,23 @@
   }
 
   public final class SQLiteDirectCursorDriver implements android.database.sqlite.SQLiteCursorDriver {
-    ctor public SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, java.lang.String, java.lang.String, android.os.CancellationSignal);
+    ctor public SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal);
     method public void cursorClosed();
     method public void cursorDeactivated();
     method public void cursorRequeried(android.database.Cursor);
-    method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase.CursorFactory, java.lang.String[]);
-    method public void setBindArguments(java.lang.String[]);
+    method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]);
+    method public void setBindArguments(String[]);
   }
 
   public final class SQLiteGlobal {
-    method public static java.lang.String getDefaultJournalMode();
+    method public static String getDefaultJournalMode();
     method public static int getDefaultPageSize();
-    method public static java.lang.String getDefaultSyncMode();
+    method public static String getDefaultSyncMode();
     method public static int getIdleConnectionTimeout();
     method public static int getJournalSizeLimit();
     method public static int getWALAutoCheckpoint();
     method public static int getWALConnectionPoolSize();
-    method public static java.lang.String getWALSyncMode();
+    method public static String getWALSyncMode();
     method public static boolean isCompatibilityWalSupported();
     method public static int releaseMemory();
   }
@@ -498,8 +507,19 @@
 
 package android.graphics {
 
+  public final class Bitmap implements android.os.Parcelable {
+    method public void eraseColor(@ColorLong long);
+  }
+
   public final class ImageDecoder implements java.lang.AutoCloseable {
-    method public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int);
+    method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int);
+  }
+
+  public class Paint {
+    method @ColorLong public long getColorLong();
+    method @ColorLong public long getShadowLayerColorLong();
+    method public void setColor(@ColorLong long);
+    method public void setShadowLayer(float, float, float, @ColorLong long);
   }
 
 }
@@ -520,7 +540,7 @@
   }
 
   public class ShapeDrawable extends android.graphics.drawable.Drawable {
-    method public void setXfermode(android.graphics.Xfermode);
+    method public void setXfermode(@Nullable android.graphics.Xfermode);
   }
 
 }
@@ -528,7 +548,7 @@
 package android.hardware.camera2 {
 
   public abstract class CameraDevice implements java.lang.AutoCloseable {
-    method public abstract void createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     field public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED = 1; // 0x1
     field public static final int SESSION_OPERATION_MODE_NORMAL = 0; // 0x0
     field public static final int SESSION_OPERATION_MODE_VENDOR_START = 32768; // 0x8000
@@ -560,31 +580,45 @@
     field public final long[] luxTimestamps;
     field public final float[] luxValues;
     field public final boolean nightMode;
-    field public final java.lang.String packageName;
+    field public final String packageName;
     field public final float powerBrightnessFactor;
     field public final long timeStamp;
   }
 
   public final class BrightnessConfiguration implements android.os.Parcelable {
     method public int describeContents();
-    method public android.util.Pair<float[], float[]> getCurve();
+    method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByCategory(int);
+    method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(String);
+    method public android.util.Pair<float[],float[]> getCurve();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR;
   }
 
   public static class BrightnessConfiguration.Builder {
     ctor public BrightnessConfiguration.Builder(float[], float[]);
+    method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByCategory(int, android.hardware.display.BrightnessCorrection);
+    method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByPackageName(String, android.hardware.display.BrightnessCorrection);
     method public android.hardware.display.BrightnessConfiguration build();
-    method public android.hardware.display.BrightnessConfiguration.Builder setDescription(java.lang.String);
+    method public int getMaxCorrectionsByCategory();
+    method public int getMaxCorrectionsByPackageName();
+    method public android.hardware.display.BrightnessConfiguration.Builder setDescription(@Nullable String);
+  }
+
+  public final class BrightnessCorrection implements android.os.Parcelable {
+    method public float apply(float);
+    method @NonNull public static android.hardware.display.BrightnessCorrection createScaleAndTranslateLog(float, float);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessCorrection> CREATOR;
   }
 
   public final class DisplayManager {
-    method public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
-    method public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration();
-    method public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents();
-    method public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration();
+    method @RequiresPermission("android.permission.ACCESS_AMBIENT_LIGHT_STATS") public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
+    method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration();
+    method @RequiresPermission(android.Manifest.permission.BRIGHTNESS_SLIDER_USAGE) public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents();
+    method @Nullable @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration();
     method public android.graphics.Point getStableDisplaySize();
-    method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
+    method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
   }
 
 }
@@ -617,21 +651,23 @@
     ctor public GnssMeasurement();
     method public void reset();
     method public void resetAutomaticGainControlLevel();
-    method public deprecated void resetCarrierCycles();
+    method @Deprecated public void resetCarrierCycles();
     method public void resetCarrierFrequencyHz();
-    method public deprecated void resetCarrierPhase();
-    method public deprecated void resetCarrierPhaseUncertainty();
+    method @Deprecated public void resetCarrierPhase();
+    method @Deprecated public void resetCarrierPhaseUncertainty();
+    method public void resetCodeType();
     method public void resetSnrInDb();
     method public void set(android.location.GnssMeasurement);
     method public void setAccumulatedDeltaRangeMeters(double);
     method public void setAccumulatedDeltaRangeState(int);
     method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
     method public void setAutomaticGainControlLevelInDb(double);
-    method public deprecated void setCarrierCycles(long);
+    method @Deprecated public void setCarrierCycles(long);
     method public void setCarrierFrequencyHz(float);
-    method public deprecated void setCarrierPhase(double);
-    method public deprecated void setCarrierPhaseUncertainty(double);
+    method @Deprecated public void setCarrierPhase(double);
+    method @Deprecated public void setCarrierPhaseUncertainty(double);
     method public void setCn0DbHz(double);
+    method public void setCodeType(int);
     method public void setConstellationType(int);
     method public void setMultipathIndicator(int);
     method public void setPseudorangeRateMetersPerSecond(double);
@@ -666,7 +702,7 @@
   }
 
   public class LocationManager {
-    method public java.lang.String[] getBackgroundThrottlingWhitelist();
+    method public String[] getBackgroundThrottlingWhitelist();
   }
 
 }
@@ -674,7 +710,7 @@
 package android.media {
 
   public final class AudioFocusRequest {
-    method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener();
+    method @Nullable public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener();
   }
 
   public final class AudioFormat implements android.os.Parcelable {
@@ -685,8 +721,8 @@
   }
 
   public final class AudioRecordingConfiguration implements android.os.Parcelable {
-    ctor public AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, java.lang.String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]);
-    ctor public AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, java.lang.String);
+    ctor public AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]);
+    ctor public AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String);
   }
 
   public final class BufferingParams implements android.os.Parcelable {
@@ -711,7 +747,7 @@
   }
 
   public static final class VolumeShaper.Configuration.Builder {
-    method public android.media.VolumeShaper.Configuration.Builder setOptionFlags(int);
+    method @NonNull public android.media.VolumeShaper.Configuration.Builder setOptionFlags(int);
   }
 
 }
@@ -740,21 +776,88 @@
     field public static final java.util.UUID EFFECT_TYPE_NULL;
   }
 
-  public static abstract interface AudioEffect.OnParameterChangeListener {
-    method public abstract void onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]);
+  public static class AudioEffect.Descriptor {
+    ctor public AudioEffect.Descriptor(android.os.Parcel);
+    method public void writeToParcel(android.os.Parcel);
+  }
+
+  public static interface AudioEffect.OnParameterChangeListener {
+    method public void onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]);
   }
 
 }
 
 package android.net {
 
+  public class CaptivePortal implements android.os.Parcelable {
+    ctor public CaptivePortal(android.os.IBinder);
+    method public void useNetwork();
+    field public static final int APP_RETURN_DISMISSED = 0; // 0x0
+    field public static final int APP_RETURN_UNWANTED = 1; // 0x1
+    field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2
+  }
+
+  public class ConnectivityManager {
+    field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
+    field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
+  }
+
+  public final class IpPrefix implements android.os.Parcelable {
+    ctor public IpPrefix(java.net.InetAddress, int);
+  }
+
   public final class IpSecManager {
     field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
   }
 
+  public class LinkAddress implements android.os.Parcelable {
+    ctor public LinkAddress(java.net.InetAddress, int, int, int);
+    method public boolean isGlobalPreferred();
+    method public boolean isIPv4();
+    method public boolean isIPv6();
+    method public boolean isSameAddressAs(android.net.LinkAddress);
+  }
+
+  public final class LinkProperties implements android.os.Parcelable {
+    ctor public LinkProperties(android.net.LinkProperties);
+    method public boolean addDnsServer(java.net.InetAddress);
+    method @Nullable public android.net.IpPrefix getNat64Prefix();
+    method public java.util.List<java.net.InetAddress> getPcscfServers();
+    method public String getTcpBufferSizes();
+    method public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
+    method public boolean hasGlobalIPv6Address();
+    method public boolean hasIPv4Address();
+    method public boolean hasIPv6DefaultRoute();
+    method public boolean isIPv4Provisioned();
+    method public boolean isIPv6Provisioned();
+    method public boolean isProvisioned();
+    method public boolean isReachable(java.net.InetAddress);
+    method public boolean removeDnsServer(java.net.InetAddress);
+    method public boolean removeRoute(android.net.RouteInfo);
+    method public void setNat64Prefix(android.net.IpPrefix);
+    method public void setPcscfServers(java.util.Collection<java.net.InetAddress>);
+    method public void setPrivateDnsServerName(@Nullable String);
+    method public void setTcpBufferSizes(String);
+    method public void setUsePrivateDns(boolean);
+    method public void setValidatedPrivateDnsServers(java.util.Collection<java.net.InetAddress>);
+  }
+
+  public class Network implements android.os.Parcelable {
+    method public android.net.Network getPrivateDnsBypassingCopy();
+  }
+
   public final class NetworkCapabilities implements android.os.Parcelable {
     method public int[] getCapabilities();
     method public int[] getTransportTypes();
+    method public boolean satisfiedByNetworkCapabilities(android.net.NetworkCapabilities);
+  }
+
+  public final class RouteInfo implements android.os.Parcelable {
+    ctor public RouteInfo(android.net.IpPrefix, java.net.InetAddress, String, int);
+    method public int getType();
+    field public static final int RTN_THROW = 9; // 0x9
+    field public static final int RTN_UNICAST = 1; // 0x1
+    field public static final int RTN_UNREACHABLE = 7; // 0x7
   }
 
   public class TrafficStats {
@@ -766,10 +869,166 @@
 
 }
 
+package android.net.metrics {
+
+  public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
+  }
+
+  public static class ApfProgramEvent.Builder {
+    ctor public ApfProgramEvent.Builder();
+    method public android.net.metrics.ApfProgramEvent build();
+    method public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
+    method public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
+    method public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
+    method public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
+    method public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
+    method public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
+  }
+
+  public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event {
+  }
+
+  public static class ApfStats.Builder {
+    ctor public ApfStats.Builder();
+    method public android.net.metrics.ApfStats build();
+    method public android.net.metrics.ApfStats.Builder setDroppedRas(int);
+    method public android.net.metrics.ApfStats.Builder setDurationMs(long);
+    method public android.net.metrics.ApfStats.Builder setMatchingRas(int);
+    method public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
+    method public android.net.metrics.ApfStats.Builder setParseErrors(int);
+    method public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
+    method public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
+    method public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
+    method public android.net.metrics.ApfStats.Builder setReceivedRas(int);
+    method public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
+  }
+
+  public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event {
+  }
+
+  public static class DhcpClientEvent.Builder {
+    ctor public DhcpClientEvent.Builder();
+    method public android.net.metrics.DhcpClientEvent build();
+    method public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
+    method public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
+  }
+
+  public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event {
+    ctor public DhcpErrorEvent(int);
+    method public static int errorCodeWithOption(int, int);
+    field public static final int BOOTP_TOO_SHORT;
+    field public static final int BUFFER_UNDERFLOW;
+    field public static final int DHCP_BAD_MAGIC_COOKIE;
+    field public static final int DHCP_ERROR = 4; // 0x4
+    field public static final int DHCP_INVALID_OPTION_LENGTH;
+    field public static final int DHCP_NO_COOKIE;
+    field public static final int DHCP_NO_MSG_TYPE;
+    field public static final int DHCP_UNKNOWN_MSG_TYPE;
+    field public static final int L2_ERROR = 1; // 0x1
+    field public static final int L2_TOO_SHORT;
+    field public static final int L2_WRONG_ETH_TYPE;
+    field public static final int L3_ERROR = 2; // 0x2
+    field public static final int L3_INVALID_IP;
+    field public static final int L3_NOT_IPV4;
+    field public static final int L3_TOO_SHORT;
+    field public static final int L4_ERROR = 3; // 0x3
+    field public static final int L4_NOT_UDP;
+    field public static final int L4_WRONG_PORT;
+    field public static final int MISC_ERROR = 5; // 0x5
+    field public static final int PARSING_ERROR;
+    field public static final int RECEIVE_ERROR;
+  }
+
+  public class IpConnectivityLog {
+    ctor public IpConnectivityLog();
+    method public boolean log(long, android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(String, android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(android.net.Network, int[], android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(int, int[], android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(android.net.metrics.IpConnectivityLog.Event);
+  }
+
+  public static interface IpConnectivityLog.Event extends android.os.Parcelable {
+  }
+
+  public final class IpManagerEvent implements android.net.metrics.IpConnectivityLog.Event {
+    ctor public IpManagerEvent(int, long);
+    field public static final int COMPLETE_LIFECYCLE = 3; // 0x3
+    field public static final int ERROR_INTERFACE_NOT_FOUND = 8; // 0x8
+    field public static final int ERROR_INVALID_PROVISIONING = 7; // 0x7
+    field public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6; // 0x6
+    field public static final int ERROR_STARTING_IPV4 = 4; // 0x4
+    field public static final int ERROR_STARTING_IPV6 = 5; // 0x5
+    field public static final int PROVISIONING_FAIL = 2; // 0x2
+    field public static final int PROVISIONING_OK = 1; // 0x1
+  }
+
+  public final class IpReachabilityEvent implements android.net.metrics.IpConnectivityLog.Event {
+    ctor public IpReachabilityEvent(int);
+    field public static final int NUD_FAILED = 512; // 0x200
+    field public static final int NUD_FAILED_ORGANIC = 1024; // 0x400
+    field public static final int PROBE = 256; // 0x100
+    field public static final int PROVISIONING_LOST = 768; // 0x300
+    field public static final int PROVISIONING_LOST_ORGANIC = 1280; // 0x500
+  }
+
+  public final class NetworkEvent implements android.net.metrics.IpConnectivityLog.Event {
+    ctor public NetworkEvent(int, long);
+    ctor public NetworkEvent(int);
+    field public static final int NETWORK_CAPTIVE_PORTAL_FOUND = 4; // 0x4
+    field public static final int NETWORK_CONNECTED = 1; // 0x1
+    field public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12; // 0xc
+    field public static final int NETWORK_DISCONNECTED = 7; // 0x7
+    field public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; // 0xa
+    field public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; // 0x8
+    field public static final int NETWORK_LINGER = 5; // 0x5
+    field public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; // 0xb
+    field public static final int NETWORK_REVALIDATION_SUCCESS = 9; // 0x9
+    field public static final int NETWORK_UNLINGER = 6; // 0x6
+    field public static final int NETWORK_VALIDATED = 2; // 0x2
+    field public static final int NETWORK_VALIDATION_FAILED = 3; // 0x3
+  }
+
+  public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event {
+  }
+
+  public static class RaEvent.Builder {
+    ctor public RaEvent.Builder();
+    method public android.net.metrics.RaEvent build();
+    method public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long);
+    method public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long);
+    method public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long);
+    method public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long);
+    method public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long);
+    method public android.net.metrics.RaEvent.Builder updateRouterLifetime(long);
+  }
+
+  public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event {
+    method public static String getProbeName(int);
+    field public static final int DNS_FAILURE = 0; // 0x0
+    field public static final int DNS_SUCCESS = 1; // 0x1
+    field public static final int PROBE_DNS = 0; // 0x0
+    field public static final int PROBE_FALLBACK = 4; // 0x4
+    field public static final int PROBE_HTTP = 1; // 0x1
+    field public static final int PROBE_HTTPS = 2; // 0x2
+    field public static final int PROBE_PAC = 3; // 0x3
+    field public static final int PROBE_PRIVDNS = 5; // 0x5
+  }
+
+  public static class ValidationProbeEvent.Builder {
+    ctor public ValidationProbeEvent.Builder();
+    method public android.net.metrics.ValidationProbeEvent build();
+    method public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
+    method public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
+    method public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
+  }
+
+}
+
 package android.os {
 
   public class Build {
-    method public static boolean is64BitAbi(java.lang.String);
+    method public static boolean is64BitAbi(String);
   }
 
   public static class Build.VERSION {
@@ -778,8 +1037,8 @@
   }
 
   public class DeviceIdleManager {
-    method public java.lang.String[] getSystemPowerWhitelist();
-    method public java.lang.String[] getSystemPowerWhitelistExceptIdle();
+    method @NonNull public String[] getSystemPowerWhitelist();
+    method @NonNull public String[] getSystemPowerWhitelistExceptIdle();
   }
 
   public class Environment {
@@ -788,8 +1047,136 @@
     method public static java.io.File getStorageDirectory();
   }
 
+  public abstract class HwBinder implements android.os.IHwBinder {
+    ctor public HwBinder();
+    method public static final void configureRpcThreadpool(long, boolean);
+    method public static void enableInstrumentation();
+    method public static final android.os.IHwBinder getService(String, String) throws java.util.NoSuchElementException, android.os.RemoteException;
+    method public static final android.os.IHwBinder getService(String, String, boolean) throws java.util.NoSuchElementException, android.os.RemoteException;
+    method public static final void joinRpcThreadpool();
+    method public abstract void onTransact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
+    method public final void registerService(String) throws android.os.RemoteException;
+    method public final void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
+  }
+
+  public class HwBlob {
+    ctor public HwBlob(int);
+    method public final void copyToBoolArray(long, boolean[], int);
+    method public final void copyToDoubleArray(long, double[], int);
+    method public final void copyToFloatArray(long, float[], int);
+    method public final void copyToInt16Array(long, short[], int);
+    method public final void copyToInt32Array(long, int[], int);
+    method public final void copyToInt64Array(long, long[], int);
+    method public final void copyToInt8Array(long, byte[], int);
+    method public final boolean getBool(long);
+    method public final double getDouble(long);
+    method public final float getFloat(long);
+    method public final short getInt16(long);
+    method public final int getInt32(long);
+    method public final long getInt64(long);
+    method public final byte getInt8(long);
+    method public final String getString(long);
+    method public final long handle();
+    method public final void putBlob(long, android.os.HwBlob);
+    method public final void putBool(long, boolean);
+    method public final void putBoolArray(long, boolean[]);
+    method public final void putDouble(long, double);
+    method public final void putDoubleArray(long, double[]);
+    method public final void putFloat(long, float);
+    method public final void putFloatArray(long, float[]);
+    method public final void putInt16(long, short);
+    method public final void putInt16Array(long, short[]);
+    method public final void putInt32(long, int);
+    method public final void putInt32Array(long, int[]);
+    method public final void putInt64(long, long);
+    method public final void putInt64Array(long, long[]);
+    method public final void putInt8(long, byte);
+    method public final void putInt8Array(long, byte[]);
+    method public final void putNativeHandle(long, android.os.NativeHandle);
+    method public final void putString(long, String);
+    method public static Boolean[] wrapArray(@NonNull boolean[]);
+    method public static Long[] wrapArray(@NonNull long[]);
+    method public static Byte[] wrapArray(@NonNull byte[]);
+    method public static Short[] wrapArray(@NonNull short[]);
+    method public static Integer[] wrapArray(@NonNull int[]);
+    method public static Float[] wrapArray(@NonNull float[]);
+    method public static Double[] wrapArray(@NonNull double[]);
+  }
+
+  public class HwParcel {
+    ctor public HwParcel();
+    method public final void enforceInterface(String);
+    method public final boolean readBool();
+    method public final java.util.ArrayList<java.lang.Boolean> readBoolVector();
+    method public final android.os.HwBlob readBuffer(long);
+    method public final double readDouble();
+    method public final java.util.ArrayList<java.lang.Double> readDoubleVector();
+    method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean);
+    method public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
+    method public final float readFloat();
+    method public final java.util.ArrayList<java.lang.Float> readFloatVector();
+    method public final short readInt16();
+    method public final java.util.ArrayList<java.lang.Short> readInt16Vector();
+    method public final int readInt32();
+    method public final java.util.ArrayList<java.lang.Integer> readInt32Vector();
+    method public final long readInt64();
+    method public final java.util.ArrayList<java.lang.Long> readInt64Vector();
+    method public final byte readInt8();
+    method public final java.util.ArrayList<java.lang.Byte> readInt8Vector();
+    method public final android.os.NativeHandle readNativeHandle();
+    method public final java.util.ArrayList<android.os.NativeHandle> readNativeHandleVector();
+    method public final String readString();
+    method public final java.util.ArrayList<java.lang.String> readStringVector();
+    method public final android.os.IHwBinder readStrongBinder();
+    method public final void release();
+    method public final void releaseTemporaryStorage();
+    method public final void send();
+    method public final void verifySuccess();
+    method public final void writeBool(boolean);
+    method public final void writeBoolVector(java.util.ArrayList<java.lang.Boolean>);
+    method public final void writeBuffer(android.os.HwBlob);
+    method public final void writeDouble(double);
+    method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>);
+    method public final void writeFloat(float);
+    method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>);
+    method public final void writeInt16(short);
+    method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>);
+    method public final void writeInt32(int);
+    method public final void writeInt32Vector(java.util.ArrayList<java.lang.Integer>);
+    method public final void writeInt64(long);
+    method public final void writeInt64Vector(java.util.ArrayList<java.lang.Long>);
+    method public final void writeInt8(byte);
+    method public final void writeInt8Vector(java.util.ArrayList<java.lang.Byte>);
+    method public final void writeInterfaceToken(String);
+    method public final void writeNativeHandle(android.os.NativeHandle);
+    method public final void writeNativeHandleVector(java.util.ArrayList<android.os.NativeHandle>);
+    method public final void writeStatus(int);
+    method public final void writeString(String);
+    method public final void writeStringVector(java.util.ArrayList<java.lang.String>);
+    method public final void writeStrongBinder(android.os.IHwBinder);
+    field public static final int STATUS_SUCCESS = 0; // 0x0
+  }
+
+  @IntDef(prefix={"STATUS_"}, value={android.os.HwParcel.STATUS_SUCCESS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface HwParcel.Status {
+  }
+
+  public interface IHwBinder {
+    method public boolean linkToDeath(android.os.IHwBinder.DeathRecipient, long);
+    method public android.os.IHwInterface queryLocalInterface(String);
+    method public void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
+    method public boolean unlinkToDeath(android.os.IHwBinder.DeathRecipient);
+  }
+
+  public static interface IHwBinder.DeathRecipient {
+    method public void serviceDied(long);
+  }
+
+  public interface IHwInterface {
+    method public android.os.IHwBinder asBinder();
+  }
+
   public class IncidentManager {
-    method public void reportIncident(android.os.IncidentReportArgs);
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void reportIncident(android.os.IncidentReportArgs);
   }
 
   public final class IncidentReportArgs implements android.os.Parcelable {
@@ -813,29 +1200,46 @@
     method public void removeSyncBarrier(int);
   }
 
+  public final class NativeHandle implements java.io.Closeable {
+    ctor public NativeHandle();
+    ctor public NativeHandle(@NonNull java.io.FileDescriptor, boolean);
+    ctor public NativeHandle(@NonNull java.io.FileDescriptor[], @NonNull int[], boolean);
+    method public void close() throws java.io.IOException;
+    method public android.os.NativeHandle dup() throws java.io.IOException;
+    method public java.io.FileDescriptor getFileDescriptor();
+    method public java.io.FileDescriptor[] getFileDescriptors();
+    method public int[] getInts();
+    method public boolean hasSingleFileDescriptor();
+  }
+
   public final class PowerManager {
-    method public int getPowerSaveMode();
-    method public boolean setDynamicPowerSavings(boolean, int);
-    method public boolean setPowerSaveMode(boolean);
+    method @RequiresPermission("android.permission.POWER_SAVER") public int getPowerSaveMode();
+    method @RequiresPermission("android.permission.POWER_SAVER") public boolean setDynamicPowerSavings(boolean, int);
+    method @RequiresPermission(anyOf={"android.permission.DEVICE_POWER", "android.permission.POWER_SAVER"}) public boolean setPowerSaveMode(boolean);
     field public static final int POWER_SAVER_MODE_DYNAMIC = 1; // 0x1
     field public static final int POWER_SAVER_MODE_PERCENTAGE = 0; // 0x0
   }
 
   public class Process {
     method public static final int getThreadScheduler(int) throws java.lang.IllegalArgumentException;
+    field public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; // 0x15f90
+    field public static final int FIRST_ISOLATED_UID = 99000; // 0x182b8
+    field public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999; // 0x182b7
+    field public static final int LAST_ISOLATED_UID = 99999; // 0x1869f
+    field public static final int NUM_UIDS_PER_APP_ZYGOTE = 100; // 0x64
   }
 
   public final class RemoteCallback implements android.os.Parcelable {
     ctor public RemoteCallback(android.os.RemoteCallback.OnResultListener);
-    ctor public RemoteCallback(android.os.RemoteCallback.OnResultListener, android.os.Handler);
+    ctor public RemoteCallback(@NonNull android.os.RemoteCallback.OnResultListener, @Nullable android.os.Handler);
     method public int describeContents();
-    method public void sendResult(android.os.Bundle);
+    method public void sendResult(@Nullable android.os.Bundle);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.RemoteCallback> CREATOR;
   }
 
-  public static abstract interface RemoteCallback.OnResultListener {
-    method public abstract void onResult(android.os.Bundle);
+  public static interface RemoteCallback.OnResultListener {
+    method public void onResult(android.os.Bundle);
   }
 
   public final class StrictMode {
@@ -851,28 +1255,28 @@
     ctor public StrictMode.ViolationInfo(android.os.Parcel);
     ctor public StrictMode.ViolationInfo(android.os.Parcel, boolean);
     method public int describeContents();
-    method public void dump(android.util.Printer, java.lang.String);
-    method public java.lang.String getStackTrace();
-    method public java.lang.Class<? extends android.os.strictmode.Violation> getViolationClass();
-    method public java.lang.String getViolationDetails();
+    method public void dump(android.util.Printer, String);
+    method public String getStackTrace();
+    method public Class<? extends android.os.strictmode.Violation> getViolationClass();
+    method public String getViolationDetails();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.StrictMode.ViolationInfo> CREATOR;
-    field public java.lang.String broadcastIntentAction;
+    field public String broadcastIntentAction;
     field public int durationMillis;
     field public int numAnimationsRunning;
     field public long numInstances;
-    field public java.lang.String[] tags;
+    field public String[] tags;
     field public int violationNumThisLoop;
     field public long violationUptimeMillis;
   }
 
-  public static abstract interface StrictMode.ViolationLogger {
-    method public abstract void log(android.os.StrictMode.ViolationInfo);
+  public static interface StrictMode.ViolationLogger {
+    method public void log(android.os.StrictMode.ViolationInfo);
   }
 
   public class SystemProperties {
-    method public static java.lang.String get(java.lang.String);
-    method public static java.lang.String get(java.lang.String, java.lang.String);
+    method @NonNull public static String get(@NonNull String);
+    method @NonNull public static String get(@NonNull String, @Nullable String);
   }
 
   public final class UserHandle implements android.os.Parcelable {
@@ -886,13 +1290,13 @@
 
   public class UserManager {
     method public static boolean isSplitSystemUser();
-    field public static final java.lang.String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
+    field public static final String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
   }
 
   public abstract class VibrationEffect implements android.os.Parcelable {
     method public static android.os.VibrationEffect get(int);
     method public static android.os.VibrationEffect get(int, boolean);
-    method public static android.os.VibrationEffect get(android.net.Uri, android.content.Context);
+    method @Nullable public static android.os.VibrationEffect get(android.net.Uri, android.content.Context);
     method public abstract long getDuration();
     method protected static int scale(int, float, int);
     field public static final int EFFECT_CLICK = 0; // 0x0
@@ -944,14 +1348,32 @@
     field public static final android.os.Parcelable.Creator<android.os.VibrationEffect.Waveform> CREATOR;
   }
 
+  public class VintfObject {
+    method public static String[] getHalNamesAndVersions();
+    method public static String getSepolicyVersion();
+    method public static Long getTargetFrameworkCompatibilityMatrixVersion();
+    method public static java.util.Map<java.lang.String,java.lang.String[]> getVndkSnapshots();
+    method public static String[] report();
+  }
+
+  public class VintfRuntimeInfo {
+    method public static String getCpuInfo();
+    method public static String getHardwareId();
+    method public static String getKernelVersion();
+    method public static String getNodeName();
+    method public static String getOsName();
+    method public static String getOsRelease();
+    method public static String getOsVersion();
+  }
+
   public class WorkSource implements android.os.Parcelable {
     ctor public WorkSource(int);
     method public boolean add(int);
-    method public boolean add(int, java.lang.String);
-    method public deprecated android.os.WorkSource addReturningNewbs(android.os.WorkSource);
+    method public boolean add(int, String);
+    method @Deprecated public android.os.WorkSource addReturningNewbs(android.os.WorkSource);
     method public int get(int);
-    method public java.lang.String getName(int);
-    method public deprecated android.os.WorkSource[] setReturningDiffs(android.os.WorkSource);
+    method public String getName(int);
+    method @Deprecated public android.os.WorkSource[] setReturningDiffs(android.os.WorkSource);
     method public int size();
   }
 
@@ -975,12 +1397,13 @@
     field public static final int UNKNOWN_KEY = 0; // 0x0
   }
 
-  public static abstract class HealthKeys.Constant implements java.lang.annotation.Annotation {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD}) public static @interface HealthKeys.Constant {
+    method public abstract int type();
   }
 
   public static class HealthKeys.Constants {
-    ctor public HealthKeys.Constants(java.lang.Class);
-    method public java.lang.String getDataType();
+    ctor public HealthKeys.Constants(Class);
+    method public String getDataType();
     method public int getIndex(int, int);
     method public int[] getKeys(int);
     method public int getSize(int);
@@ -1002,10 +1425,10 @@
   public class HealthStatsWriter {
     ctor public HealthStatsWriter(android.os.health.HealthKeys.Constants);
     method public void addMeasurement(int, long);
-    method public void addMeasurements(int, java.lang.String, long);
-    method public void addStats(int, java.lang.String, android.os.health.HealthStatsWriter);
+    method public void addMeasurements(int, String, long);
+    method public void addStats(int, String, android.os.health.HealthStatsWriter);
     method public void addTimer(int, int, long);
-    method public void addTimers(int, java.lang.String, android.os.health.TimerStat);
+    method public void addTimers(int, String, android.os.health.TimerStat);
     method public void flattenToParcel(android.os.Parcel);
   }
 
@@ -1018,7 +1441,7 @@
   }
 
   public final class StorageVolume implements android.os.Parcelable {
-    method public java.lang.String getPath();
+    method public String getPath();
   }
 
 }
@@ -1030,15 +1453,30 @@
 
 }
 
+package android.permission {
+
+  public final class PermissionControllerManager {
+    method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
+    field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2
+    field public static final int REASON_MALWARE = 1; // 0x1
+  }
+
+  public abstract static class PermissionControllerManager.OnRevokeRuntimePermissionsCallback {
+    ctor public PermissionControllerManager.OnRevokeRuntimePermissionsCallback();
+    method public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>);
+  }
+
+}
+
 package android.print {
 
   public final class PrintJobInfo implements android.os.Parcelable {
     method public float getProgress();
-    method public java.lang.CharSequence getStatus(android.content.pm.PackageManager);
+    method @Nullable public CharSequence getStatus(@NonNull android.content.pm.PackageManager);
   }
 
   public final class PrinterInfo implements android.os.Parcelable {
-    method public android.graphics.drawable.Drawable loadIcon(android.content.Context);
+    method @Nullable public android.graphics.drawable.Drawable loadIcon(@NonNull android.content.Context);
   }
 
 }
@@ -1054,50 +1492,65 @@
   }
 
   public final class MediaStore {
-    method public static void deleteContributedMedia(android.content.Context, java.lang.String, android.os.UserHandle) throws java.io.IOException;
-    method public static long getContributedMediaSize(android.content.Context, java.lang.String, android.os.UserHandle) throws java.io.IOException;
+    method @RequiresPermission("android.permission.CLEAR_APP_USER_DATA") public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
+    method @RequiresPermission("android.permission.CLEAR_APP_USER_DATA") public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
   }
 
   public final class Settings {
-    field public static final java.lang.String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
+    field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
   }
 
   public static final class Settings.Global extends android.provider.Settings.NameValueTable {
-    field public static final java.lang.String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
-    field public static final java.lang.String AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS = "autofill_smart_suggestion_emulation_flags";
-    field public static final java.lang.String AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode";
-    field public static final java.lang.String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold";
-    field public static final java.lang.String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
-    field public static final java.lang.String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
-    field public static final java.lang.String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
-    field public static final java.lang.String LOW_POWER_MODE = "low_power";
-    field public static final java.lang.String LOW_POWER_MODE_STICKY = "low_power_sticky";
-    field public static final java.lang.String SMS_ACCESS_RESTRICTION_ENABLED = "sms_access_restriction_enabled";
-    field public static final java.lang.String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
+    field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
+    field public static final String AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS = "autofill_smart_suggestion_emulation_flags";
+    field public static final String AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode";
+    field public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS = "captive_portal_fallback_probe_specs";
+    field public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
+    field public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url";
+    field public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
+    field public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
+    field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
+    field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0
+    field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1
+    field public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS = "captive_portal_other_fallback_urls";
+    field public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
+    field public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
+    field public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = "data_stall_consecutive_dns_timeout_threshold";
+    field public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
+    field public static final String DATA_STALL_MIN_EVALUATE_INTERVAL = "data_stall_min_evaluate_interval";
+    field public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD = "data_stall_valid_dns_time_threshold";
+    field public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold";
+    field public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
+    field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
+    field public static final String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
+    field public static final String LOW_POWER_MODE = "low_power";
+    field public static final String LOW_POWER_MODE_STICKY = "low_power_sticky";
+    field public static final String SMS_ACCESS_RESTRICTION_ENABLED = "sms_access_restriction_enabled";
+    field public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
   }
 
   public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
-    method public static void resetToDefaults(android.content.ContentResolver, java.lang.String);
-    field public static final java.lang.String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = "accessibility_display_magnification_enabled";
-    field public static final java.lang.String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE = "accessibility_shortcut_target_service";
-    field public static final java.lang.String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification";
-    field public static final java.lang.String AUTOFILL_SERVICE = "autofill_service";
-    field public static final java.lang.String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count";
-    field public static final java.lang.String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size";
-    field public static final java.lang.String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
-    field public static final java.lang.String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
-    field public static final java.lang.String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
-    field public static final java.lang.String DISABLED_PRINT_SERVICES = "disabled_print_services";
-    field public static final deprecated java.lang.String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages";
-    field public static final java.lang.String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis";
-    field public static final java.lang.String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS = "location_access_check_interval_millis";
-    field public static final java.lang.String SYNC_PARENT_SOUNDS = "sync_parent_sounds";
-    field public static final java.lang.String USER_SETUP_COMPLETE = "user_setup_complete";
-    field public static final java.lang.String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String);
+    field public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = "accessibility_display_magnification_enabled";
+    field public static final String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE = "accessibility_shortcut_target_service";
+    field public static final String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification";
+    field public static final String AUTOFILL_SERVICE = "autofill_service";
+    field public static final String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count";
+    field public static final String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size";
+    field public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
+    field public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
+    field public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
+    field public static final String DISABLED_PRINT_SERVICES = "disabled_print_services";
+    field @Deprecated public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages";
+    field public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis";
+    field public static final String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS = "location_access_check_interval_millis";
+    field @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds";
+    field public static final String USER_SETUP_COMPLETE = "user_setup_complete";
+    field public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
   }
 
   public static final class Telephony.Sms.Intents {
-    field public static final java.lang.String SMS_CARRIER_PROVISION_ACTION = "android.provider.Telephony.SMS_CARRIER_PROVISION";
+    field public static final String SMS_CARRIER_PROVISION_ACTION = "android.provider.Telephony.SMS_CARRIER_PROVISION";
   }
 
 }
@@ -1105,7 +1558,7 @@
 package android.security {
 
   public class KeyStoreException extends java.lang.Exception {
-    ctor public KeyStoreException(int, java.lang.String);
+    ctor public KeyStoreException(int, String);
     method public int getErrorCode();
   }
 
@@ -1114,19 +1567,19 @@
 package android.security.keystore {
 
   public abstract class AttestationUtils {
-    method public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, int[], byte[]) throws android.security.keystore.DeviceIdAttestationException;
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @NonNull public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException;
     field public static final int ID_TYPE_IMEI = 2; // 0x2
     field public static final int ID_TYPE_MEID = 3; // 0x3
     field public static final int ID_TYPE_SERIAL = 1; // 0x1
   }
 
   public class DeviceIdAttestationException extends java.lang.Exception {
-    ctor public DeviceIdAttestationException(java.lang.String);
-    ctor public DeviceIdAttestationException(java.lang.String, java.lang.Throwable);
+    ctor public DeviceIdAttestationException(String);
+    ctor public DeviceIdAttestationException(String, Throwable);
   }
 
   public static final class KeyGenParameterSpec.Builder {
-    method public android.security.keystore.KeyGenParameterSpec.Builder setUniqueIdIncluded(boolean);
+    method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUniqueIdIncluded(boolean);
   }
 
   public final class KeyProtection implements java.security.KeyStore.ProtectionParameter {
@@ -1143,41 +1596,41 @@
 
   public abstract class AutofillFieldClassificationService extends android.app.Service {
     method public android.os.IBinder onBind(android.content.Intent);
-    field public static final java.lang.String REQUIRED_ALGORITHM_EDIT_DISTANCE = "EDIT_DISTANCE";
-    field public static final java.lang.String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH";
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService";
-    field public static final java.lang.String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = "android.autofill.field_classification.available_algorithms";
-    field public static final java.lang.String SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM = "android.autofill.field_classification.default_algorithm";
+    field public static final String REQUIRED_ALGORITHM_EDIT_DISTANCE = "EDIT_DISTANCE";
+    field public static final String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH";
+    field public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService";
+    field public static final String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = "android.autofill.field_classification.available_algorithms";
+    field public static final String SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM = "android.autofill.field_classification.default_algorithm";
   }
 
   public final class CharSequenceTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
-    method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
+    method public void apply(@NonNull android.service.autofill.ValueFinder, @NonNull android.widget.RemoteViews, int) throws java.lang.Exception;
   }
 
   public final class CompositeUserData implements android.os.Parcelable {
-    ctor public CompositeUserData(android.service.autofill.UserData, android.service.autofill.UserData);
+    ctor public CompositeUserData(@Nullable android.service.autofill.UserData, @NonNull android.service.autofill.UserData);
     method public int describeContents();
-    method public java.lang.String[] getCategoryIds();
+    method public String[] getCategoryIds();
     method public android.os.Bundle getDefaultFieldClassificationArgs();
-    method public java.lang.String getFieldClassificationAlgorithm();
-    method public java.lang.String getFieldClassificationAlgorithmForCategory(java.lang.String);
-    method public android.util.ArrayMap<java.lang.String, java.lang.String> getFieldClassificationAlgorithms();
-    method public android.util.ArrayMap<java.lang.String, android.os.Bundle> getFieldClassificationArgs();
-    method public java.lang.String[] getValues();
+    method @Nullable public String getFieldClassificationAlgorithm();
+    method @Nullable public String getFieldClassificationAlgorithmForCategory(@NonNull String);
+    method public android.util.ArrayMap<java.lang.String,java.lang.String> getFieldClassificationAlgorithms();
+    method public android.util.ArrayMap<java.lang.String,android.os.Bundle> getFieldClassificationArgs();
+    method public String[] getValues();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.autofill.CompositeUserData> CREATOR;
   }
 
   public final class CustomDescription implements android.os.Parcelable {
-    method public android.util.SparseArray<android.service.autofill.InternalOnClickAction> getActions();
+    method @Nullable public android.util.SparseArray<android.service.autofill.InternalOnClickAction> getActions();
   }
 
   public final class DateTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
-    method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
+    method public void apply(@NonNull android.service.autofill.ValueFinder, @NonNull android.widget.RemoteViews, int) throws java.lang.Exception;
   }
 
   public final class DateValueSanitizer extends android.service.autofill.InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
-    method public android.view.autofill.AutofillValue sanitize(android.view.autofill.AutofillValue);
+    method @Nullable public android.view.autofill.AutofillValue sanitize(@NonNull android.view.autofill.AutofillValue);
   }
 
   public final class FillResponse implements android.os.Parcelable {
@@ -1185,52 +1638,113 @@
   }
 
   public final class ImageTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
-    method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
+    method public void apply(@NonNull android.service.autofill.ValueFinder, @NonNull android.widget.RemoteViews, int) throws java.lang.Exception;
   }
 
   public abstract class InternalOnClickAction implements android.service.autofill.OnClickAction android.os.Parcelable {
     ctor public InternalOnClickAction();
-    method public abstract void onClick(android.view.ViewGroup);
+    method public abstract void onClick(@NonNull android.view.ViewGroup);
   }
 
   public abstract class InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
     ctor public InternalSanitizer();
-    method public abstract android.view.autofill.AutofillValue sanitize(android.view.autofill.AutofillValue);
+    method @Nullable public abstract android.view.autofill.AutofillValue sanitize(@NonNull android.view.autofill.AutofillValue);
   }
 
   public abstract class InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
     ctor public InternalTransformation();
-    method public static boolean batchApply(android.service.autofill.ValueFinder, android.widget.RemoteViews, java.util.ArrayList<android.util.Pair<java.lang.Integer, android.service.autofill.InternalTransformation>>);
+    method public static boolean batchApply(@NonNull android.service.autofill.ValueFinder, @NonNull android.widget.RemoteViews, @NonNull java.util.ArrayList<android.util.Pair<java.lang.Integer,android.service.autofill.InternalTransformation>>);
   }
 
   public abstract class InternalValidator implements android.os.Parcelable android.service.autofill.Validator {
     ctor public InternalValidator();
-    method public abstract boolean isValid(android.service.autofill.ValueFinder);
+    method public abstract boolean isValid(@NonNull android.service.autofill.ValueFinder);
   }
 
   public final class LuhnChecksumValidator extends android.service.autofill.InternalValidator implements android.os.Parcelable android.service.autofill.Validator {
-    method public boolean isValid(android.service.autofill.ValueFinder);
+    method public boolean isValid(@NonNull android.service.autofill.ValueFinder);
   }
 
   public final class RegexValidator extends android.service.autofill.InternalValidator implements android.os.Parcelable android.service.autofill.Validator {
-    method public boolean isValid(android.service.autofill.ValueFinder);
+    method public boolean isValid(@NonNull android.service.autofill.ValueFinder);
   }
 
   public final class TextValueSanitizer extends android.service.autofill.InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
-    method public android.view.autofill.AutofillValue sanitize(android.view.autofill.AutofillValue);
+    method @Nullable public android.view.autofill.AutofillValue sanitize(@NonNull android.view.autofill.AutofillValue);
   }
 
   public final class UserData implements android.os.Parcelable {
-    method public android.util.ArrayMap<java.lang.String, java.lang.String> getFieldClassificationAlgorithms();
+    method public android.util.ArrayMap<java.lang.String,java.lang.String> getFieldClassificationAlgorithms();
   }
 
-  public abstract interface ValueFinder {
-    method public default java.lang.String findByAutofillId(android.view.autofill.AutofillId);
-    method public abstract android.view.autofill.AutofillValue findRawValueByAutofillId(android.view.autofill.AutofillId);
+  public interface ValueFinder {
+    method @Nullable public default String findByAutofillId(@NonNull android.view.autofill.AutofillId);
+    method @Nullable public android.view.autofill.AutofillValue findRawValueByAutofillId(@NonNull android.view.autofill.AutofillId);
   }
 
   public final class VisibilitySetterAction extends android.service.autofill.InternalOnClickAction implements android.service.autofill.OnClickAction android.os.Parcelable {
-    method public void onClick(android.view.ViewGroup);
+    method public void onClick(@NonNull android.view.ViewGroup);
+  }
+
+}
+
+package android.service.autofill.augmented {
+
+  public abstract class AugmentedAutofillService extends android.app.Service {
+    ctor public AugmentedAutofillService();
+    method protected final void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
+    method protected void dump(@NonNull java.io.PrintWriter, @NonNull String[]);
+    method public void onFillRequest(@NonNull android.service.autofill.augmented.FillRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.augmented.FillController, @NonNull android.service.autofill.augmented.FillCallback);
+    field public static final String SERVICE_INTERFACE = "android.service.autofill.augmented.AugmentedAutofillService";
+  }
+
+  public final class FillCallback {
+    method public void onSuccess(@Nullable android.service.autofill.augmented.FillResponse);
+  }
+
+  public final class FillController {
+    method public void autofill(@NonNull java.util.List<android.util.Pair<android.view.autofill.AutofillId,android.view.autofill.AutofillValue>>);
+  }
+
+  public final class FillRequest {
+    method @NonNull public android.content.ComponentName getActivityComponent();
+    method @NonNull public android.view.autofill.AutofillId getFocusedId();
+    method @NonNull public android.view.autofill.AutofillValue getFocusedValue();
+    method @Nullable public android.service.autofill.augmented.PresentationParams getPresentationParams();
+    method public int getTaskId();
+  }
+
+  public final class FillResponse {
+  }
+
+  public static final class FillResponse.Builder {
+    ctor public FillResponse.Builder();
+    method public android.service.autofill.augmented.FillResponse build();
+    method public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@NonNull android.service.autofill.augmented.FillWindow);
+    method public android.service.autofill.augmented.FillResponse.Builder setIgnoredIds(@NonNull java.util.List<android.view.autofill.AutofillId>);
+  }
+
+  public final class FillWindow implements java.lang.AutoCloseable {
+    ctor public FillWindow();
+    method public void destroy();
+    method public boolean update(@NonNull android.service.autofill.augmented.PresentationParams.Area, @NonNull android.view.View, long);
+  }
+
+  public abstract class PresentationParams {
+    method public int getFlags();
+    method @Nullable public android.service.autofill.augmented.PresentationParams.Area getFullArea();
+    method @Nullable public android.service.autofill.augmented.PresentationParams.Area getSuggestionArea();
+    field public static final int FLAG_HINT_GRAVITY_BOTTOM = 2; // 0x2
+    field public static final int FLAG_HINT_GRAVITY_LEFT = 4; // 0x4
+    field public static final int FLAG_HINT_GRAVITY_RIGHT = 8; // 0x8
+    field public static final int FLAG_HINT_GRAVITY_TOP = 1; // 0x1
+    field public static final int FLAG_HOST_IME = 16; // 0x10
+    field public static final int FLAG_HOST_SYSTEM = 32; // 0x20
+  }
+
+  public abstract static class PresentationParams.Area {
+    method @NonNull public android.graphics.Rect getBounds();
+    method @Nullable public android.service.autofill.augmented.PresentationParams.Area getSubArea(@NonNull android.graphics.Rect);
   }
 
 }
@@ -1238,43 +1752,43 @@
 package android.service.notification {
 
   public final class Adjustment implements android.os.Parcelable {
-    ctor public Adjustment(java.lang.String, java.lang.String, android.os.Bundle, java.lang.CharSequence, int);
+    ctor public Adjustment(String, String, android.os.Bundle, CharSequence, int);
     ctor protected Adjustment(android.os.Parcel);
     method public int describeContents();
-    method public java.lang.CharSequence getExplanation();
-    method public java.lang.String getKey();
-    method public java.lang.String getPackage();
+    method public CharSequence getExplanation();
+    method public String getKey();
+    method public String getPackage();
     method public android.os.Bundle getSignals();
     method public int getUser();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
-    field public static final java.lang.String KEY_IMPORTANCE = "key_importance";
-    field public static final java.lang.String KEY_PEOPLE = "key_people";
-    field public static final java.lang.String KEY_SMART_ACTIONS = "key_smart_actions";
-    field public static final java.lang.String KEY_SMART_REPLIES = "key_smart_replies";
-    field public static final java.lang.String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
-    field public static final java.lang.String KEY_USER_SENTIMENT = "key_user_sentiment";
+    field public static final String KEY_IMPORTANCE = "key_importance";
+    field public static final String KEY_PEOPLE = "key_people";
+    field public static final String KEY_SMART_ACTIONS = "key_smart_actions";
+    field public static final String KEY_SMART_REPLIES = "key_smart_replies";
+    field public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
+    field public static final String KEY_USER_SENTIMENT = "key_user_sentiment";
   }
 
-  public abstract deprecated class ConditionProviderService extends android.app.Service {
-    method public boolean isBound();
+  @Deprecated public abstract class ConditionProviderService extends android.app.Service {
+    method @Deprecated public boolean isBound();
   }
 
   public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
     ctor public NotificationAssistantService();
     method public final void adjustNotification(android.service.notification.Adjustment);
     method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
-    method public void onActionClicked(java.lang.String, android.app.Notification.Action, int);
+    method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
     method public final android.os.IBinder onBind(android.content.Intent);
-    method public void onNotificationDirectReply(java.lang.String);
+    method public void onNotificationDirectReplied(@NonNull String);
     method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
     method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, android.app.NotificationChannel);
-    method public void onNotificationExpansionChanged(java.lang.String, boolean, boolean);
-    method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
+    method public void onNotificationExpansionChanged(@NonNull String, boolean, boolean);
+    method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, String);
     method public void onNotificationsSeen(java.util.List<java.lang.String>);
-    method public void onSuggestedReplySent(java.lang.String, java.lang.CharSequence, int);
-    method public final void unsnoozeNotification(java.lang.String);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
+    method public void onSuggestedReplySent(@NonNull String, @NonNull CharSequence, int);
+    method public final void unsnoozeNotification(String);
+    field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
     field public static final int SOURCE_FROM_APP = 0; // 0x0
     field public static final int SOURCE_FROM_ASSISTANT = 1; // 0x1
   }
@@ -1316,12 +1830,12 @@
   }
 
   public final class SnoozeCriterion implements android.os.Parcelable {
-    ctor public SnoozeCriterion(java.lang.String, java.lang.CharSequence, java.lang.CharSequence);
+    ctor public SnoozeCriterion(String, CharSequence, CharSequence);
     ctor protected SnoozeCriterion(android.os.Parcel);
     method public int describeContents();
-    method public java.lang.CharSequence getConfirmation();
-    method public java.lang.CharSequence getExplanation();
-    method public java.lang.String getId();
+    method public CharSequence getConfirmation();
+    method public CharSequence getExplanation();
+    method public String getId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.notification.SnoozeCriterion> CREATOR;
   }
@@ -1339,7 +1853,7 @@
 package android.telecom {
 
   public final class CallAudioState implements android.os.Parcelable {
-    ctor public CallAudioState(boolean, int, int, android.bluetooth.BluetoothDevice, java.util.Collection<android.bluetooth.BluetoothDevice>);
+    ctor public CallAudioState(boolean, int, int, @Nullable android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.bluetooth.BluetoothDevice>);
   }
 
   public final class PhoneAccountSuggestion implements android.os.Parcelable {
@@ -1348,10 +1862,10 @@
 
   public class PhoneAccountSuggestionService extends android.app.Service {
     ctor public PhoneAccountSuggestionService();
-    method public void onAccountSuggestionRequest(java.lang.String);
+    method public void onAccountSuggestionRequest(@NonNull String);
     method public android.os.IBinder onBind(android.content.Intent);
-    method public final void suggestPhoneAccounts(java.lang.String, java.util.List<android.telecom.PhoneAccountSuggestion>);
-    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService";
+    method public final void suggestPhoneAccounts(@NonNull String, @NonNull java.util.List<android.telecom.PhoneAccountSuggestion>);
+    field public static final String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService";
   }
 
 }
@@ -1359,19 +1873,19 @@
 package android.telephony {
 
   public class CarrierConfigManager {
-    method public void overrideConfig(int, android.os.PersistableBundle);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void overrideConfig(int, @Nullable android.os.PersistableBundle);
   }
 
   public class MbmsDownloadSession implements java.lang.AutoCloseable {
-    field public static final java.lang.String MBMS_DOWNLOAD_SERVICE_OVERRIDE_METADATA = "mbms-download-service-override";
+    field public static final 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";
+    field public static final 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";
+    field public static final String MBMS_STREAMING_SERVICE_OVERRIDE_METADATA = "mbms-streaming-service-override";
   }
 
   public class ServiceState implements android.os.Parcelable {
@@ -1385,8 +1899,8 @@
   public class TelephonyManager {
     method public int getCarrierIdListVersion();
     method public boolean isRttSupported();
-    method public void refreshUiccProfile();
-    method public void setCarrierTestOverride(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
+    method public void setCarrierTestOverride(String, String, String, String, String, String, String);
     field public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1; // 0xffffffff
   }
 
@@ -1395,19 +1909,19 @@
 package android.telephony.mbms {
 
   public static class DownloadRequest.Builder {
-    method public android.telephony.mbms.DownloadRequest.Builder setServiceId(java.lang.String);
+    method public android.telephony.mbms.DownloadRequest.Builder setServiceId(String);
   }
 
   public final class FileInfo implements android.os.Parcelable {
-    ctor public FileInfo(android.net.Uri, java.lang.String);
+    ctor public FileInfo(android.net.Uri, String);
   }
 
   public final class FileServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
-    ctor public FileServiceInfo(java.util.Map<java.util.Locale, java.lang.String>, java.lang.String, java.util.List<java.util.Locale>, java.lang.String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>);
+    ctor public FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>);
   }
 
   public final class StreamingServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
-    ctor public StreamingServiceInfo(java.util.Map<java.util.Locale, java.lang.String>, java.lang.String, java.util.List<java.util.Locale>, java.lang.String, java.util.Date, java.util.Date);
+    ctor public StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date);
   }
 
   public final class UriPathPair implements android.os.Parcelable {
@@ -1426,18 +1940,22 @@
     ctor public MbmsDownloadServiceBase();
     method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
     method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
+    method public android.os.IBinder asBinder();
     method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
     method public void dispose(int) throws android.os.RemoteException;
     method public int download(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
+    method public static String getDefaultTransactionName(int);
+    method public String getTransactionName(int);
     method public int initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) throws android.os.RemoteException;
-    method public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException;
+    method @NonNull public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException;
     method public void onAppCallbackDied(int, int);
+    method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
     method public int removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
     method public int removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
     method public int requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) throws android.os.RemoteException;
     method public int requestUpdateFileServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException;
     method public int resetDownloadKnowledge(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
-    method public int setTempFileRootDirectory(int, java.lang.String) throws android.os.RemoteException;
+    method public int setTempFileRootDirectory(int, String) throws android.os.RemoteException;
   }
 
   public class MbmsGroupCallServiceBase extends android.app.Service {
@@ -1453,30 +1971,34 @@
 
   public class MbmsStreamingServiceBase extends android.os.Binder {
     ctor public MbmsStreamingServiceBase();
+    method public android.os.IBinder asBinder();
     method public void dispose(int) throws android.os.RemoteException;
-    method public android.net.Uri getPlaybackUri(int, java.lang.String) throws android.os.RemoteException;
+    method public static String getDefaultTransactionName(int);
+    method @Nullable public android.net.Uri getPlaybackUri(int, String) throws android.os.RemoteException;
+    method public String getTransactionName(int);
     method public int initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) throws android.os.RemoteException;
     method public void onAppCallbackDied(int, int);
+    method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
     method public int requestUpdateStreamingServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException;
-    method public int startStreaming(int, java.lang.String, android.telephony.mbms.StreamingServiceCallback) throws android.os.RemoteException;
-    method public void stopStreaming(int, java.lang.String) throws android.os.RemoteException;
+    method public int startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback) throws android.os.RemoteException;
+    method public void stopStreaming(int, String) throws android.os.RemoteException;
   }
 
   public class VendorUtils {
     ctor public VendorUtils();
-    method public static android.content.ComponentName getAppReceiverFromPackageName(android.content.Context, java.lang.String);
-    field public static final java.lang.String ACTION_CLEANUP = "android.telephony.mbms.action.CLEANUP";
-    field public static final java.lang.String ACTION_DOWNLOAD_RESULT_INTERNAL = "android.telephony.mbms.action.DOWNLOAD_RESULT_INTERNAL";
-    field public static final java.lang.String ACTION_FILE_DESCRIPTOR_REQUEST = "android.telephony.mbms.action.FILE_DESCRIPTOR_REQUEST";
-    field public static final java.lang.String EXTRA_FD_COUNT = "android.telephony.mbms.extra.FD_COUNT";
-    field public static final java.lang.String EXTRA_FINAL_URI = "android.telephony.mbms.extra.FINAL_URI";
-    field public static final java.lang.String EXTRA_FREE_URI_LIST = "android.telephony.mbms.extra.FREE_URI_LIST";
-    field public static final java.lang.String EXTRA_PAUSED_LIST = "android.telephony.mbms.extra.PAUSED_LIST";
-    field public static final java.lang.String EXTRA_PAUSED_URI_LIST = "android.telephony.mbms.extra.PAUSED_URI_LIST";
-    field public static final java.lang.String EXTRA_SERVICE_ID = "android.telephony.mbms.extra.SERVICE_ID";
-    field public static final java.lang.String EXTRA_TEMP_FILES_IN_USE = "android.telephony.mbms.extra.TEMP_FILES_IN_USE";
-    field public static final java.lang.String EXTRA_TEMP_FILE_ROOT = "android.telephony.mbms.extra.TEMP_FILE_ROOT";
-    field public static final java.lang.String EXTRA_TEMP_LIST = "android.telephony.mbms.extra.TEMP_LIST";
+    method public static android.content.ComponentName getAppReceiverFromPackageName(android.content.Context, String);
+    field public static final String ACTION_CLEANUP = "android.telephony.mbms.action.CLEANUP";
+    field public static final String ACTION_DOWNLOAD_RESULT_INTERNAL = "android.telephony.mbms.action.DOWNLOAD_RESULT_INTERNAL";
+    field public static final String ACTION_FILE_DESCRIPTOR_REQUEST = "android.telephony.mbms.action.FILE_DESCRIPTOR_REQUEST";
+    field public static final String EXTRA_FD_COUNT = "android.telephony.mbms.extra.FD_COUNT";
+    field public static final String EXTRA_FINAL_URI = "android.telephony.mbms.extra.FINAL_URI";
+    field public static final String EXTRA_FREE_URI_LIST = "android.telephony.mbms.extra.FREE_URI_LIST";
+    field public static final String EXTRA_PAUSED_LIST = "android.telephony.mbms.extra.PAUSED_LIST";
+    field public static final String EXTRA_PAUSED_URI_LIST = "android.telephony.mbms.extra.PAUSED_URI_LIST";
+    field public static final String EXTRA_SERVICE_ID = "android.telephony.mbms.extra.SERVICE_ID";
+    field public static final String EXTRA_TEMP_FILES_IN_USE = "android.telephony.mbms.extra.TEMP_FILES_IN_USE";
+    field public static final String EXTRA_TEMP_FILE_ROOT = "android.telephony.mbms.extra.TEMP_FILE_ROOT";
+    field public static final String EXTRA_TEMP_LIST = "android.telephony.mbms.extra.TEMP_LIST";
   }
 
 }
@@ -1486,8 +2008,8 @@
   public static final class Selection.MemoryTextWatcher implements android.text.TextWatcher {
     ctor public Selection.MemoryTextWatcher();
     method public void afterTextChanged(android.text.Editable);
-    method public void beforeTextChanged(java.lang.CharSequence, int, int, int);
-    method public void onTextChanged(java.lang.CharSequence, int, int, int);
+    method public void beforeTextChanged(CharSequence, int, int, int);
+    method public void onTextChanged(CharSequence, int, int, int);
   }
 
 }
@@ -1502,7 +2024,7 @@
 
 package android.util {
 
-  public final class ArraySet<E> implements java.util.Collection java.util.Set {
+  public final class ArraySet<E> implements java.util.Collection<E> java.util.Set<E> {
     method public E valueAtUnchecked(int);
   }
 
@@ -1513,12 +2035,12 @@
   public final class EncodedBuffer {
     ctor public EncodedBuffer();
     ctor public EncodedBuffer(int);
-    method public void dumpBuffers(java.lang.String);
-    method public static void dumpByteString(java.lang.String, java.lang.String, byte[]);
+    method public void dumpBuffers(String);
+    method public static void dumpByteString(String, String, byte[]);
     method public void editRawFixed32(int, int);
     method public byte[] getBytes(int);
     method public int getChunkCount();
-    method public java.lang.String getDebugString();
+    method public String getDebugString();
     method public int getRawFixed32At(int);
     method public static int getRawVarint32Size(int);
     method public static int getRawVarint64Size(long);
@@ -1554,7 +2076,7 @@
     ctor public ProtoInputStream(byte[]);
     method public int decodeZigZag32(int);
     method public long decodeZigZag64(long);
-    method public java.lang.String dumpDebugData();
+    method public String dumpDebugData();
     method public void end(long);
     method public int getFieldNumber();
     method public int getOffset();
@@ -1567,7 +2089,7 @@
     method public float readFloat(long) throws java.io.IOException;
     method public int readInt(long) throws java.io.IOException;
     method public long readLong(long) throws java.io.IOException;
-    method public java.lang.String readString(long) throws java.io.IOException;
+    method public String readString(long) throws java.io.IOException;
     method public void skip() throws java.io.IOException;
     method public long start(long) throws java.io.IOException;
     field public static final int NO_MORE_FIELDS = -1; // 0xffffffff
@@ -1579,93 +2101,93 @@
     ctor public ProtoOutputStream(java.io.OutputStream);
     ctor public ProtoOutputStream(java.io.FileDescriptor);
     method public static int checkFieldId(long, long);
-    method public void dump(java.lang.String);
+    method public void dump(String);
     method public void end(long);
-    method public deprecated void endObject(long);
-    method public deprecated void endRepeatedObject(long);
+    method @Deprecated public void endObject(long);
+    method @Deprecated public void endRepeatedObject(long);
     method public void flush();
     method public byte[] getBytes();
     method public static long makeFieldId(int, long);
     method public long start(long);
-    method public deprecated long startObject(long);
-    method public deprecated long startRepeatedObject(long);
+    method @Deprecated public long startObject(long);
+    method @Deprecated public long startRepeatedObject(long);
     method public void write(long, double);
     method public void write(long, float);
     method public void write(long, int);
     method public void write(long, long);
     method public void write(long, boolean);
-    method public void write(long, java.lang.String);
+    method public void write(long, String);
     method public void write(long, byte[]);
-    method public deprecated void writeBool(long, boolean);
-    method public deprecated void writeBytes(long, byte[]);
-    method public deprecated void writeDouble(long, double);
-    method public deprecated void writeEnum(long, int);
-    method public deprecated void writeFixed32(long, int);
-    method public deprecated void writeFixed64(long, long);
-    method public deprecated void writeFloat(long, float);
-    method public deprecated void writeInt32(long, int);
-    method public deprecated void writeInt64(long, long);
-    method public deprecated void writeObject(long, byte[]);
-    method public deprecated void writePackedBool(long, boolean[]);
-    method public deprecated void writePackedDouble(long, double[]);
-    method public deprecated void writePackedEnum(long, int[]);
-    method public deprecated void writePackedFixed32(long, int[]);
-    method public deprecated void writePackedFixed64(long, long[]);
-    method public deprecated void writePackedFloat(long, float[]);
-    method public deprecated void writePackedInt32(long, int[]);
-    method public deprecated void writePackedInt64(long, long[]);
-    method public deprecated void writePackedSFixed32(long, int[]);
-    method public deprecated void writePackedSFixed64(long, long[]);
-    method public deprecated void writePackedSInt32(long, int[]);
-    method public deprecated void writePackedSInt64(long, long[]);
-    method public deprecated void writePackedUInt32(long, int[]);
-    method public deprecated void writePackedUInt64(long, long[]);
-    method public deprecated void writeRepeatedBool(long, boolean);
-    method public deprecated void writeRepeatedBytes(long, byte[]);
-    method public deprecated void writeRepeatedDouble(long, double);
-    method public deprecated void writeRepeatedEnum(long, int);
-    method public deprecated void writeRepeatedFixed32(long, int);
-    method public deprecated void writeRepeatedFixed64(long, long);
-    method public deprecated void writeRepeatedFloat(long, float);
-    method public deprecated void writeRepeatedInt32(long, int);
-    method public deprecated void writeRepeatedInt64(long, long);
-    method public deprecated void writeRepeatedObject(long, byte[]);
-    method public deprecated void writeRepeatedSFixed32(long, int);
-    method public deprecated void writeRepeatedSFixed64(long, long);
-    method public deprecated void writeRepeatedSInt32(long, int);
-    method public deprecated void writeRepeatedSInt64(long, long);
-    method public deprecated void writeRepeatedString(long, java.lang.String);
-    method public deprecated void writeRepeatedUInt32(long, int);
-    method public deprecated void writeRepeatedUInt64(long, long);
-    method public deprecated void writeSFixed32(long, int);
-    method public deprecated void writeSFixed64(long, long);
-    method public deprecated void writeSInt32(long, int);
-    method public deprecated void writeSInt64(long, long);
-    method public deprecated void writeString(long, java.lang.String);
+    method @Deprecated public void writeBool(long, boolean);
+    method @Deprecated public void writeBytes(long, byte[]);
+    method @Deprecated public void writeDouble(long, double);
+    method @Deprecated public void writeEnum(long, int);
+    method @Deprecated public void writeFixed32(long, int);
+    method @Deprecated public void writeFixed64(long, long);
+    method @Deprecated public void writeFloat(long, float);
+    method @Deprecated public void writeInt32(long, int);
+    method @Deprecated public void writeInt64(long, long);
+    method @Deprecated public void writeObject(long, byte[]);
+    method @Deprecated public void writePackedBool(long, boolean[]);
+    method @Deprecated public void writePackedDouble(long, double[]);
+    method @Deprecated public void writePackedEnum(long, int[]);
+    method @Deprecated public void writePackedFixed32(long, int[]);
+    method @Deprecated public void writePackedFixed64(long, long[]);
+    method @Deprecated public void writePackedFloat(long, float[]);
+    method @Deprecated public void writePackedInt32(long, int[]);
+    method @Deprecated public void writePackedInt64(long, long[]);
+    method @Deprecated public void writePackedSFixed32(long, int[]);
+    method @Deprecated public void writePackedSFixed64(long, long[]);
+    method @Deprecated public void writePackedSInt32(long, int[]);
+    method @Deprecated public void writePackedSInt64(long, long[]);
+    method @Deprecated public void writePackedUInt32(long, int[]);
+    method @Deprecated public void writePackedUInt64(long, long[]);
+    method @Deprecated public void writeRepeatedBool(long, boolean);
+    method @Deprecated public void writeRepeatedBytes(long, byte[]);
+    method @Deprecated public void writeRepeatedDouble(long, double);
+    method @Deprecated public void writeRepeatedEnum(long, int);
+    method @Deprecated public void writeRepeatedFixed32(long, int);
+    method @Deprecated public void writeRepeatedFixed64(long, long);
+    method @Deprecated public void writeRepeatedFloat(long, float);
+    method @Deprecated public void writeRepeatedInt32(long, int);
+    method @Deprecated public void writeRepeatedInt64(long, long);
+    method @Deprecated public void writeRepeatedObject(long, byte[]);
+    method @Deprecated public void writeRepeatedSFixed32(long, int);
+    method @Deprecated public void writeRepeatedSFixed64(long, long);
+    method @Deprecated public void writeRepeatedSInt32(long, int);
+    method @Deprecated public void writeRepeatedSInt64(long, long);
+    method @Deprecated public void writeRepeatedString(long, String);
+    method @Deprecated public void writeRepeatedUInt32(long, int);
+    method @Deprecated public void writeRepeatedUInt64(long, long);
+    method @Deprecated public void writeSFixed32(long, int);
+    method @Deprecated public void writeSFixed64(long, long);
+    method @Deprecated public void writeSInt32(long, int);
+    method @Deprecated public void writeSInt64(long, long);
+    method @Deprecated public void writeString(long, String);
     method public void writeTag(int, int);
-    method public deprecated void writeUInt32(long, int);
-    method public deprecated void writeUInt64(long, long);
+    method @Deprecated public void writeUInt32(long, int);
+    method @Deprecated public void writeUInt64(long, long);
   }
 
   public class ProtoParseException extends java.lang.RuntimeException {
-    ctor public ProtoParseException(java.lang.String);
+    ctor public ProtoParseException(String);
   }
 
   public abstract class ProtoStream {
     ctor public ProtoStream();
     method public static int convertObjectIdToOrdinal(int);
     method public static int getDepthFromToken(long);
-    method public static java.lang.String getFieldCountString(long);
-    method public static java.lang.String getFieldIdString(long);
-    method public static java.lang.String getFieldTypeString(long);
+    method public static String getFieldCountString(long);
+    method public static String getFieldIdString(long);
+    method public static String getFieldTypeString(long);
     method public static int getObjectIdFromToken(long);
     method public static int getOffsetFromToken(long);
     method public static boolean getRepeatedFromToken(long);
     method public static int getTagSizeFromToken(long);
-    method public static java.lang.String getWireTypeString(int);
+    method public static String getWireTypeString(int);
     method public static long makeFieldId(int, long);
     method public static long makeToken(int, boolean, int, int, int);
-    method public static java.lang.String token2String(long);
+    method public static String token2String(long);
     field public static final long FIELD_COUNT_MASK = 16492674416640L; // 0xf0000000000L
     field public static final long FIELD_COUNT_PACKED = 5497558138880L; // 0x50000000000L
     field public static final long FIELD_COUNT_REPEATED = 2199023255552L; // 0x20000000000L
@@ -1685,7 +2207,7 @@
     field public static final long FIELD_TYPE_INT64 = 12884901888L; // 0x300000000L
     field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L
     field public static final long FIELD_TYPE_MESSAGE = 47244640256L; // 0xb00000000L
-    field protected static final java.lang.String[] FIELD_TYPE_NAMES;
+    field protected static final String[] FIELD_TYPE_NAMES;
     field public static final long FIELD_TYPE_SFIXED32 = 64424509440L; // 0xf00000000L
     field public static final long FIELD_TYPE_SFIXED64 = 68719476736L; // 0x1000000000L
     field public static final int FIELD_TYPE_SHIFT = 32; // 0x20
@@ -1705,7 +2227,7 @@
   }
 
   public class WireTypeMismatchException extends android.util.proto.ProtoParseException {
-    ctor public WireTypeMismatchException(java.lang.String);
+    ctor public WireTypeMismatchException(String);
   }
 
 }
@@ -1718,9 +2240,9 @@
 
   public final class Choreographer {
     method public static long getFrameDelay();
-    method public void postCallback(int, java.lang.Runnable, java.lang.Object);
-    method public void postCallbackDelayed(int, java.lang.Runnable, java.lang.Object, long);
-    method public void removeCallbacks(int, java.lang.Runnable, java.lang.Object);
+    method public void postCallback(int, Runnable, Object);
+    method public void postCallbackDelayed(int, Runnable, Object, long);
+    method public void removeCallbacks(int, Runnable, Object);
     method public static void setFrameDelay(long);
     field public static final int CALLBACK_ANIMATION = 1; // 0x1
   }
@@ -1730,19 +2252,19 @@
   }
 
   public final class InputDevice implements android.os.Parcelable {
-    method public void disable();
-    method public void enable();
+    method @RequiresPermission("android.permission.DISABLE_INPUT_DEVICE") public void disable();
+    method @RequiresPermission("android.permission.DISABLE_INPUT_DEVICE") public void enable();
   }
 
   public class KeyEvent extends android.view.InputEvent implements android.os.Parcelable {
-    method public static java.lang.String actionToString(int);
+    method public static String actionToString(int);
     method public final void setDisplayId(int);
     field public static final int LAST_KEYCODE = 288; // 0x120
   }
 
   public final class KeyboardShortcutGroup implements android.os.Parcelable {
-    ctor public KeyboardShortcutGroup(java.lang.CharSequence, java.util.List<android.view.KeyboardShortcutInfo>, boolean);
-    ctor public KeyboardShortcutGroup(java.lang.CharSequence, boolean);
+    ctor public KeyboardShortcutGroup(@Nullable CharSequence, @NonNull java.util.List<android.view.KeyboardShortcutInfo>, boolean);
+    ctor public KeyboardShortcutGroup(@Nullable CharSequence, boolean);
     method public boolean isSystemGroup();
   }
 
@@ -1752,7 +2274,7 @@
     method public void setDisplayId(int);
   }
 
-  public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
+  @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
     method public android.view.View getTooltipView();
     method public static boolean isDefaultFocusHighlightEnabled();
     method public boolean isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
@@ -1777,7 +2299,11 @@
     method public static int getLongPressTooltipHideTimeout();
   }
 
-  public abstract interface WindowManager implements android.view.ViewManager {
+  public class ViewDebug {
+    method @Nullable public static AutoCloseable startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>);
+  }
+
+  public interface WindowManager extends android.view.ViewManager {
     method public default void setShouldShowIme(int, boolean);
     method public default void setShouldShowSystemDecors(int, boolean);
     method public default void setShouldShowWithInsecureKeyguard(int, boolean);
@@ -1786,8 +2312,8 @@
   public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
     field public static final int ACCESSIBILITY_TITLE_CHANGED = 33554432; // 0x2000000
     field public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 64; // 0x40
-    field public java.lang.CharSequence accessibilityTitle;
-    field public int privateFlags;
+    field public CharSequence accessibilityTitle;
+    field @android.view.ViewDebug.ExportedProperty(flagMapping={@android.view.ViewDebug.FlagToString(mask=0x1, equals=0x1, name="FAKE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x2, equals=0x2, name="FORCE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x4, equals=0x4, name="WANTS_OFFSET_NOTIFICATIONS"), @android.view.ViewDebug.FlagToString(mask=0x10, equals=0x10, name="SHOW_FOR_ALL_USERS"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, equals=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, name="NO_MOVE_ANIMATION"), @android.view.ViewDebug.FlagToString(mask=0x80, equals=0x80, name="COMPATIBLE_WINDOW"), @android.view.ViewDebug.FlagToString(mask=0x100, equals=0x100, name="SYSTEM_ERROR"), @android.view.ViewDebug.FlagToString(mask=0x200, equals=0x200, name="INHERIT_TRANSLUCENT_DECOR"), @android.view.ViewDebug.FlagToString(mask=0x400, equals=0x400, name="KEYGUARD"), @android.view.ViewDebug.FlagToString(mask=0x800, equals=0x800, name="DISABLE_WALLPAPER_TOUCH_EVENTS"), @android.view.ViewDebug.FlagToString(mask=0x1000, equals=0x1000, name="FORCE_STATUS_BAR_VISIBLE_TRANSPARENT"), @android.view.ViewDebug.FlagToString(mask=0x2000, equals=0x2000, name="PRESERVE_GEOMETRY"), @android.view.ViewDebug.FlagToString(mask=0x4000, equals=0x4000, name="FORCE_DECOR_VIEW_VISIBILITY"), @android.view.ViewDebug.FlagToString(mask=0x8000, equals=0x8000, name="WILL_NOT_REPLACE_ON_RELAUNCH"), @android.view.ViewDebug.FlagToString(mask=0x10000, equals=0x10000, name="LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME"), @android.view.ViewDebug.FlagToString(mask=0x20000, equals=0x20000, name="FORCE_DRAW_STATUS_BAR_BACKGROUND"), @android.view.ViewDebug.FlagToString(mask=0x40000, equals=0x40000, name="SUSTAINED_PERFORMANCE_MODE"), @android.view.ViewDebug.FlagToString(mask=0x80000, equals=0x80000, name="HIDE_NON_SYSTEM_OVERLAY_WINDOWS"), @android.view.ViewDebug.FlagToString(mask=0x100000, equals=0x100000, name="IS_ROUNDED_CORNERS_OVERLAY"), @android.view.ViewDebug.FlagToString(mask=0x400000, equals=0x400000, name="IS_SCREEN_DECOR"), @android.view.ViewDebug.FlagToString(mask=0x800000, equals=0x800000, name="STATUS_FORCE_SHOW_NAVIGATION")}) public int privateFlags;
   }
 
 }
@@ -1795,14 +2321,14 @@
 package android.view.accessibility {
 
   public final class AccessibilityManager {
-    method public void addAccessibilityServicesStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener, android.os.Handler);
-    method public java.lang.String getAccessibilityShortcutService();
-    method public void performAccessibilityShortcut();
-    method public void removeAccessibilityServicesStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
+    method public void addAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener, @Nullable android.os.Handler);
+    method @Nullable @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public String getAccessibilityShortcutService();
+    method @RequiresPermission("android.permission.MANAGE_ACCESSIBILITY") public void performAccessibilityShortcut();
+    method public void removeAccessibilityServicesStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
   }
 
-  public static abstract interface AccessibilityManager.AccessibilityServicesStateChangeListener {
-    method public abstract void onAccessibilityServicesStateChanged(android.view.accessibility.AccessibilityManager);
+  public static interface AccessibilityManager.AccessibilityServicesStateChangeListener {
+    method public void onAccessibilityServicesStateChanged(android.view.accessibility.AccessibilityManager);
   }
 
   public class AccessibilityNodeInfo implements android.os.Parcelable {
@@ -1811,7 +2337,7 @@
   }
 
   public static final class AccessibilityNodeInfo.TouchDelegateInfo implements android.os.Parcelable {
-    method public long getAccessibilityIdForRegion(android.graphics.Region);
+    method public long getAccessibilityIdForRegion(@NonNull android.graphics.Region);
   }
 
   public final class AccessibilityWindowInfo implements android.os.Parcelable {
@@ -1833,7 +2359,17 @@
 
   public final class AutofillId implements android.os.Parcelable {
     ctor public AutofillId(int);
-    ctor public AutofillId(android.view.autofill.AutofillId, int);
+    ctor public AutofillId(@NonNull android.view.autofill.AutofillId, int);
+  }
+
+  public final class AutofillManager {
+    method @NonNull public java.util.Set<android.content.ComponentName> getAugmentedAutofillDisabledActivities();
+    method @NonNull public java.util.Set<java.lang.String> getAugmentedAutofillDisabledPackages();
+    method public void setActivityAugmentedAutofillEnabled(@NonNull android.content.ComponentName, boolean);
+    method public void setAugmentedAutofillWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>);
+    method public void setPackageAugmentedAutofillEnabled(@NonNull String, boolean);
+    field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1
+    field public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 120000; // 0x1d4c0
   }
 
 }
@@ -1846,9 +2382,46 @@
 
 }
 
+package android.view.inspector {
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public @interface InspectableNodeName {
+    method public abstract String value();
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface InspectableProperty {
+    method public abstract int attributeId() default android.content.res.Resources.ID_NULL;
+    method public abstract android.view.inspector.InspectableProperty.EnumMap[] enumMapping() default {};
+    method public abstract android.view.inspector.InspectableProperty.FlagMap[] flagMapping() default {};
+    method public abstract boolean hasAttributeId() default true;
+    method public abstract String name() default "";
+    method public abstract android.view.inspector.InspectableProperty.ValueType valueType() default android.view.inspector.InspectableProperty.ValueType.INFERRED;
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.EnumMap {
+    method public abstract String name();
+    method public abstract int value();
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.FlagMap {
+    method public abstract int mask() default 0;
+    method public abstract String name();
+    method public abstract int target();
+  }
+
+  public enum InspectableProperty.ValueType {
+    enum_constant public static final android.view.inspector.InspectableProperty.ValueType COLOR;
+    enum_constant public static final android.view.inspector.InspectableProperty.ValueType GRAVITY;
+    enum_constant public static final android.view.inspector.InspectableProperty.ValueType INFERRED;
+    enum_constant public static final android.view.inspector.InspectableProperty.ValueType INT_ENUM;
+    enum_constant public static final android.view.inspector.InspectableProperty.ValueType INT_FLAG;
+    enum_constant public static final android.view.inspector.InspectableProperty.ValueType NONE;
+  }
+
+}
+
 package android.widget {
 
-  public abstract class AbsListView extends android.widget.AdapterView implements android.widget.Filter.FilterListener android.text.TextWatcher android.view.ViewTreeObserver.OnGlobalLayoutListener android.view.ViewTreeObserver.OnTouchModeChangeListener {
+  public abstract class AbsListView extends android.widget.AdapterView<android.widget.ListAdapter> implements android.widget.Filter.FilterListener android.text.TextWatcher android.view.ViewTreeObserver.OnGlobalLayoutListener android.view.ViewTreeObserver.OnTouchModeChangeListener {
     method public final boolean shouldDrawSelector();
   }
 
@@ -1862,19 +2435,19 @@
     field public static final int MODE_SPINNER = 1; // 0x1
   }
 
-  public final class Magnifier {
-    method public android.graphics.Bitmap getContent();
+  @UiThread public final class Magnifier {
+    method @Nullable public android.graphics.Bitmap getContent();
     method public static android.graphics.PointF getMagnifierDefaultSize();
-    method public android.graphics.Bitmap getOriginalContent();
+    method @Nullable public android.graphics.Bitmap getOriginalContent();
     method public void setOnOperationCompleteCallback(android.widget.Magnifier.Callback);
   }
 
-  public static abstract interface Magnifier.Callback {
-    method public abstract void onOperationComplete();
+  public static interface Magnifier.Callback {
+    method public void onOperationComplete();
   }
 
   public class NumberPicker extends android.widget.LinearLayout {
-    method public java.lang.CharSequence getDisplayedValueForCurrentSelection();
+    method public CharSequence getDisplayedValueForCurrentSelection();
   }
 
   public class PopupMenu {
@@ -1885,7 +2458,7 @@
     method public boolean isPopupShowing();
   }
 
-  public class TextClock extends android.widget.TextView {
+  @android.widget.RemoteViews.RemoteView public class TextClock extends android.widget.TextView {
     method public void disableClockTick();
   }
 
@@ -1900,7 +2473,7 @@
   }
 
   public class Toolbar extends android.view.ViewGroup {
-    method public android.view.View getNavigationView();
+    method @Nullable public android.view.View getNavigationView();
   }
 
 }
diff --git a/api/test-removed.txt b/api/test-removed.txt
index e69de29..d802177 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
index 469c964..1b3c32b 100644
--- a/cmds/bootanimation/bootanim.rc
+++ b/cmds/bootanimation/bootanim.rc
@@ -2,6 +2,7 @@
     class core animation
     user graphics
     group graphics audio
+    updatable
     disabled
     oneshot
     writepid /dev/stune/top-app/tasks
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index abe18ba..803f83c 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -20,6 +20,7 @@
         "misc-*",
         "modernize-*",
         "readability-*",
+        "-modernize-avoid-c-arrays",
     ],
     tidy_flags: [
         "-system-headers",
@@ -38,6 +39,7 @@
         "libidmap2/CommandLineOptions.cpp",
         "libidmap2/FileUtils.cpp",
         "libidmap2/Idmap.cpp",
+        "libidmap2/Policies.cpp",
         "libidmap2/PrettyPrintVisitor.cpp",
         "libidmap2/RawPrintVisitor.cpp",
         "libidmap2/ResourceUtils.cpp",
@@ -87,6 +89,7 @@
         "tests/Idmap2BinaryTests.cpp",
         "tests/IdmapTests.cpp",
         "tests/Main.cpp",
+        "tests/PoliciesTests.cpp",
         "tests/PrettyPrintVisitorTests.cpp",
         "tests/RawPrintVisitorTests.cpp",
         "tests/ResourceUtilsTests.cpp",
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index b075673..c455ac0 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -27,17 +27,25 @@
 #include "idmap2/CommandLineOptions.h"
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/Result.h"
 
 using android::ApkAssets;
 using android::idmap2::BinaryStreamVisitor;
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Idmap;
+using android::idmap2::PoliciesToBitmask;
+using android::idmap2::PolicyBitmask;
+using android::idmap2::PolicyFlags;
+using android::idmap2::Result;
 using android::idmap2::utils::kIdmapFilePermissionMask;
 
 bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
   std::string target_apk_path;
   std::string overlay_apk_path;
   std::string idmap_path;
+  std::vector<std::string> policies;
+  bool ignore_overlayable;
 
   const CommandLineOptions opts =
       CommandLineOptions("idmap2 create")
@@ -47,12 +55,28 @@
           .MandatoryOption("--overlay-apk-path",
                            "input: path to apk which contains the new resource values",
                            &overlay_apk_path)
-          .MandatoryOption("--idmap-path", "output: path to where to write idmap file",
-                           &idmap_path);
+          .MandatoryOption("--idmap-path", "output: path to where to write idmap file", &idmap_path)
+          .OptionalOption("--policy",
+                          "input: an overlayable policy this overlay fulfills "
+                          "(if none or supplied, the overlay policy will default to \"public\")",
+                          &policies)
+          .OptionalFlag("--ignore-overlayable", "disables overlayable and policy checks",
+                        &ignore_overlayable);
   if (!opts.Parse(args, out_error)) {
     return false;
   }
 
+  PolicyBitmask fulfilled_policies = 0;
+  if (auto result = PoliciesToBitmask(policies, out_error)) {
+    fulfilled_policies |= *result;
+  } else {
+    return false;
+  }
+
+  if (fulfilled_policies == 0) {
+    fulfilled_policies |= PolicyFlags::POLICY_PUBLIC;
+  }
+
   const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
   if (!target_apk) {
     out_error << "error: failed to load apk " << target_apk_path << std::endl;
@@ -66,7 +90,8 @@
   }
 
   const std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, out_error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           fulfilled_policies, !ignore_overlayable, out_error);
   if (!idmap) {
     return false;
   }
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index 4918747..b1ed42a 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -21,11 +21,15 @@
 #include <set>
 #include <sstream>
 #include <string>
+#include <utility>
 #include <vector>
 
+#include "android-base/properties.h"
+
 #include "idmap2/CommandLineOptions.h"
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
+#include "idmap2/ResourceUtils.h"
 #include "idmap2/Xml.h"
 #include "idmap2/ZipFile.h"
 
@@ -33,12 +37,34 @@
 
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Idmap;
-using android::idmap2::MemoryChunk;
-using android::idmap2::Xml;
-using android::idmap2::ZipFile;
+using android::idmap2::PoliciesToBitmask;
+using android::idmap2::PolicyBitmask;
+using android::idmap2::PolicyFlags;
+using android::idmap2::Result;
+using android::idmap2::utils::ExtractOverlayManifestInfo;
 using android::idmap2::utils::FindFiles;
+using android::idmap2::utils::OverlayManifestInfo;
 
 namespace {
+
+struct InputOverlay {
+  bool operator<(InputOverlay const& rhs) const {
+    return priority < rhs.priority || (priority == rhs.priority && apk_path < rhs.apk_path);
+  }
+
+  std::string apk_path;               // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string idmap_path;             // NOLINT(misc-non-private-member-variables-in-classes)
+  int priority;                       // NOLINT(misc-non-private-member-variables-in-classes)
+  std::vector<std::string> policies;  // NOLINT(misc-non-private-member-variables-in-classes)
+  bool ignore_overlayable;            // NOLINT(misc-non-private-member-variables-in-classes)
+};
+
+bool VendorIsQOrLater() {
+  // STOPSHIP(b/119390857): Check api version once Q sdk version is finalized
+  std::string version = android::base::GetProperty("ro.vndk.version", "Q");
+  return version == "Q" || version == "q";
+}
+
 std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs,
                                                        bool recursive, std::ostream& out_error) {
   const auto predicate = [](unsigned char type, const std::string& path) -> bool {
@@ -58,6 +84,23 @@
   }
   return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend());
 }
+
+PolicyBitmask PolicyForPath(const std::string& apk_path) {
+  static const std::vector<std::pair<std::string, PolicyBitmask>> values = {
+      {"/product/", PolicyFlags::POLICY_PRODUCT_PARTITION},
+      {"/system/", PolicyFlags::POLICY_SYSTEM_PARTITION},
+      {"/vendor/", PolicyFlags::POLICY_VENDOR_PARTITION},
+  };
+
+  for (auto const& pair : values) {
+    if (apk_path.compare(0, pair.first.size(), pair.first) == 0) {
+      return pair.second | PolicyFlags::POLICY_PUBLIC;
+    }
+  }
+
+  return PolicyFlags::POLICY_PUBLIC;
+}
+
 }  // namespace
 
 bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
@@ -65,6 +108,7 @@
   std::string target_package_name;
   std::string target_apk_path;
   std::string output_directory;
+  std::vector<std::string> override_policies;
   bool recursive = false;
 
   const CommandLineOptions opts =
@@ -77,7 +121,12 @@
           .MandatoryOption("--target-apk-path", "path to target apk", &target_apk_path)
           .MandatoryOption("--output-directory",
                            "directory in which to write artifacts (idmap files and overlays.list)",
-                           &output_directory);
+                           &output_directory)
+          .OptionalOption(
+              "--override-policy",
+              "input: an overlayable policy this overlay fulfills "
+              "(if none or supplied, the overlays will not have their policies overriden",
+              &override_policies);
   if (!opts.Parse(args, out_error)) {
     return false;
   }
@@ -87,72 +136,86 @@
     return false;
   }
 
-  std::vector<std::string> interesting_apks;
+  std::vector<InputOverlay> interesting_apks;
   for (const std::string& path : *apk_paths) {
-    std::unique_ptr<const ZipFile> zip = ZipFile::Open(path);
-    if (!zip) {
-      out_error << "error: failed to open " << path << " as a zip file" << std::endl;
+    Result<OverlayManifestInfo> overlay_info =
+        ExtractOverlayManifestInfo(path, out_error,
+                                   /* assert_overlay */ false);
+    if (!overlay_info) {
       return false;
     }
 
-    std::unique_ptr<const MemoryChunk> entry = zip->Uncompress("AndroidManifest.xml");
-    if (!entry) {
-      out_error << "error: failed to uncompress AndroidManifest.xml from " << path << std::endl;
-      return false;
-    }
-
-    std::unique_ptr<const Xml> xml = Xml::Create(entry->buf, entry->size);
-    if (!xml) {
-      out_error << "error: failed to parse AndroidManifest.xml from " << path << std::endl;
+    if (!overlay_info->is_static) {
       continue;
     }
 
-    const auto tag = xml->FindTag("overlay");
-    if (!tag) {
+    if (overlay_info->target_package.empty() ||
+        overlay_info->target_package != target_package_name) {
       continue;
     }
 
-    auto iter = tag->find("isStatic");
-    if (iter == tag->end() || std::stoul(iter->second) == 0U) {
+    if (overlay_info->priority < 0) {
       continue;
     }
 
-    iter = tag->find("targetPackage");
-    if (iter == tag->end() || iter->second != target_package_name) {
-      continue;
+    PolicyBitmask fulfilled_policies;
+    if (!override_policies.empty()) {
+      if (Result<PolicyBitmask> result = PoliciesToBitmask(override_policies, out_error)) {
+        fulfilled_policies = *result;
+      } else {
+        return false;
+      }
+    } else {
+      fulfilled_policies = PolicyForPath(path);
     }
 
-    iter = tag->find("priority");
-    if (iter == tag->end()) {
-      continue;
+    bool ignore_overlayable = false;
+    if ((fulfilled_policies & PolicyFlags::POLICY_VENDOR_PARTITION) != 0 && !VendorIsQOrLater()) {
+      // If the overlay is on a pre-Q vendor partition, do not enforce overlayable
+      // restrictions on this overlay because the pre-Q platform has no understanding of
+      // overlayable.
+      ignore_overlayable = true;
     }
 
-    const int priority = std::stoi(iter->second);
-    if (priority < 0) {
-      continue;
-    }
+    std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path);
 
+    // Sort the static overlays in ascending priority order
+    InputOverlay input{path, idmap_path, overlay_info->priority, override_policies,
+                       ignore_overlayable};
     interesting_apks.insert(
-        std::lower_bound(interesting_apks.begin(), interesting_apks.end(), path), path);
+        std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input);
   }
 
   std::stringstream stream;
-  for (const auto& apk : interesting_apks) {
-    const std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, apk);
+  for (const auto& overlay : interesting_apks) {
+    // Create the idmap for the overlay if it currently does not exist or if it is not up to date.
     std::stringstream dev_null;
-    if (!Verify(std::vector<std::string>({"--idmap-path", idmap_path}), dev_null) &&
-        !Create(std::vector<std::string>({
-                    "--target-apk-path",
-                    target_apk_path,
-                    "--overlay-apk-path",
-                    apk,
-                    "--idmap-path",
-                    idmap_path,
-                }),
-                out_error)) {
-      return false;
+
+    std::vector<std::string> verify_args = {"--idmap-path", overlay.idmap_path};
+    for (const std::string& policy : overlay.policies) {
+      verify_args.emplace_back("--policy");
+      verify_args.emplace_back(policy);
     }
-    stream << idmap_path << std::endl;
+
+    if (!Verify(std::vector<std::string>(verify_args), dev_null)) {
+      std::vector<std::string> create_args = {"--target-apk-path",  target_apk_path,
+                                              "--overlay-apk-path", overlay.apk_path,
+                                              "--idmap-path",       overlay.idmap_path};
+      if (overlay.ignore_overlayable) {
+        create_args.emplace_back("--ignore-overlayable");
+      }
+
+      for (const std::string& policy : overlay.policies) {
+        verify_args.emplace_back("--policy");
+        verify_args.emplace_back(policy);
+      }
+
+      if (!Create(create_args, out_error)) {
+        return false;
+      }
+    }
+
+    stream << overlay.idmap_path << std::endl;
   }
 
   std::cout << stream.str();
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index d2e46e1..a3c7527 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -26,12 +26,15 @@
 #include <string>
 
 #include "android-base/macros.h"
+#include "android-base/stringprintf.h"
 #include "utils/String8.h"
 #include "utils/Trace.h"
 
 #include "idmap2/BinaryStreamVisitor.h"
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/Result.h"
 
 #include "idmap2d/Idmap2Service.h"
 
@@ -39,6 +42,8 @@
 using android::idmap2::BinaryStreamVisitor;
 using android::idmap2::Idmap;
 using android::idmap2::IdmapHeader;
+using android::idmap2::PolicyBitmask;
+using android::idmap2::Result;
 using android::idmap2::utils::kIdmapFilePermissionMask;
 
 namespace {
@@ -54,6 +59,10 @@
   return Status::fromExceptionCode(Status::EX_NONE, msg.c_str());
 }
 
+PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) {
+  return static_cast<PolicyBitmask>(arg);
+}
+
 }  // namespace
 
 namespace android::os {
@@ -78,6 +87,8 @@
 }
 
 Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path,
+                                  int32_t fulfilled_policies ATTRIBUTE_UNUSED,
+                                  bool enforce_overlayable ATTRIBUTE_UNUSED,
                                   int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
   assert(_aidl_return);
   const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
@@ -86,11 +97,15 @@
   fin.close();
   std::stringstream dev_null;
   *_aidl_return = header && header->IsUpToDate(dev_null);
+
+  // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed
+
   return ok();
 }
 
 Status Idmap2Service::createIdmap(const std::string& target_apk_path,
-                                  const std::string& overlay_apk_path, int32_t user_id,
+                                  const std::string& overlay_apk_path, int32_t fulfilled_policies,
+                                  bool enforce_overlayable, int32_t user_id,
                                   std::unique_ptr<std::string>* _aidl_return) {
   assert(_aidl_return);
   std::stringstream trace;
@@ -101,6 +116,8 @@
 
   _aidl_return->reset(nullptr);
 
+  const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);
+
   const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
   if (!target_apk) {
     return error("failed to load apk " + target_apk_path);
@@ -113,7 +130,8 @@
 
   std::stringstream err;
   const std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, err);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           policy_bitmask, enforce_overlayable, err);
   if (!idmap) {
     return error(err.str());
   }
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index e0bc22e..1aab059 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -39,11 +39,12 @@
   binder::Status removeIdmap(const std::string& overlay_apk_path, int32_t user_id,
                              bool* _aidl_return);
 
-  binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t user_id,
-                             bool* _aidl_return);
+  binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t fulfilled_policies,
+                             bool enforce_overlayable, int32_t user_id, bool* _aidl_return);
 
   binder::Status createIdmap(const std::string& target_apk_path,
-                             const std::string& overlay_apk_path, int32_t user_id,
+                             const std::string& overlay_apk_path, int32_t fulfilled_policies,
+                             bool enforce_overlayable, int32_t user_id,
                              std::unique_ptr<std::string>* _aidl_return);
 };
 
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
index d475417..ea7274f 100644
--- a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
+++ b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
@@ -20,9 +20,18 @@
  * @hide
  */
 interface IIdmap2 {
+  const int POLICY_PUBLIC = 0x00000001;
+  const int POLICY_SYSTEM_PARTITION = 0x00000002;
+  const int POLICY_VENDOR_PARTITION = 0x00000004;
+  const int POLICY_PRODUCT_PARTITION = 0x00000008;
+
   @utf8InCpp String getIdmapPath(@utf8InCpp String overlayApkPath, int userId);
   boolean removeIdmap(@utf8InCpp String overlayApkPath, int userId);
-  boolean verifyIdmap(@utf8InCpp String overlayApkPath, int userId);
+  boolean verifyIdmap(@utf8InCpp String overlayApkPath, int fulfilledPolicies,
+                      boolean enforceOverlayable, int userId);
   @nullable @utf8InCpp String createIdmap(@utf8InCpp String targetApkPath,
-                                          @utf8InCpp String overlayApkPath, int userId);
+                                          @utf8InCpp String overlayApkPath,
+                                          int fulfilledPolicies,
+                                          boolean enforceOverlayable,
+                                          int userId);
 }
diff --git a/cmds/idmap2/include/idmap2/CommandLineOptions.h b/cmds/idmap2/include/idmap2/CommandLineOptions.h
index b93e716..6db6bf9 100644
--- a/cmds/idmap2/include/idmap2/CommandLineOptions.h
+++ b/cmds/idmap2/include/idmap2/CommandLineOptions.h
@@ -44,6 +44,8 @@
                                       std::vector<std::string>* value);
   CommandLineOptions& OptionalOption(const std::string& name, const std::string& description,
                                      std::string* value);
+  CommandLineOptions& OptionalOption(const std::string& name, const std::string& description,
+                                     std::vector<std::string>* value);
   bool Parse(const std::vector<std::string>& argv, std::ostream& outError) const;
   void Usage(std::ostream& out) const;
 
@@ -56,6 +58,7 @@
       COUNT_OPTIONAL,
       COUNT_EXACTLY_ONCE,
       COUNT_ONCE_OR_MORE,
+      COUNT_OPTIONAL_ONCE_OR_MORE,
     } count;
     bool argument;
   };
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index b989e4c..1666dc8 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -57,6 +57,8 @@
 #include "androidfw/ResourceTypes.h"
 #include "androidfw/StringPiece.h"
 
+#include "idmap2/Policies.h"
+
 namespace android::idmap2 {
 
 class Idmap;
@@ -233,11 +235,10 @@
   // file is used; change this in the next version of idmap to use a named
   // package instead; also update FromApkAssets to take additional parameters:
   // the target and overlay package names
-  static std::unique_ptr<const Idmap> FromApkAssets(const std::string& target_apk_path,
-                                                    const ApkAssets& target_apk_assets,
-                                                    const std::string& overlay_apk_path,
-                                                    const ApkAssets& overlay_apk_assets,
-                                                    std::ostream& out_error);
+  static std::unique_ptr<const Idmap> FromApkAssets(
+      const std::string& target_apk_path, const ApkAssets& target_apk_assets,
+      const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
+      const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error);
 
   inline const std::unique_ptr<const IdmapHeader>& GetHeader() const {
     return header_;
diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/include/idmap2/Policies.h
new file mode 100644
index 0000000..eecee25
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/Policies.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
+
+#include "Result.h"
+
+#ifndef IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
+#define IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
+
+namespace android::idmap2 {
+
+using PolicyFlags = ResTable_overlayable_policy_header::PolicyFlags;
+using PolicyBitmask = uint32_t;
+
+// Parses a the string representation of a set of policies into a bitmask. The format of the string
+// is the same as for the <policy> element.
+Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies,
+                                        std::ostream& err);
+
+}  // namespace android::idmap2
+
+#endif  // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index 323796b..22827ac 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -17,6 +17,8 @@
 #ifndef IDMAP2_INCLUDE_IDMAP2_RESOURCEUTILS_H_
 #define IDMAP2_INCLUDE_IDMAP2_RESOURCEUTILS_H_
 
+#include <optional>
+#include <ostream>
 #include <string>
 
 #include "android-base/macros.h"
@@ -24,9 +26,21 @@
 
 #include "idmap2/Idmap.h"
 #include "idmap2/Result.h"
+#include "idmap2/ZipFile.h"
 
 namespace android::idmap2::utils {
 
+struct OverlayManifestInfo {
+  std::string target_package;  // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string target_name;     // NOLINT(misc-non-private-member-variables-in-classes)
+  bool is_static;              // NOLINT(misc-non-private-member-variables-in-classes)
+  int priority = -1;           // NOLINT(misc-non-private-member-variables-in-classes)
+};
+
+Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path,
+                                                       std::ostream& out_error,
+                                                       bool assert_overlay = true);
+
 Result<std::string> WARN_UNUSED ResToTypeEntryName(const AssetManager2& am, ResourceId resid);
 
 }  // namespace android::idmap2::utils
diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
index cabc8f3..a49a607 100644
--- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp
+++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
@@ -68,9 +68,18 @@
   return *this;
 }
 
+CommandLineOptions& CommandLineOptions::OptionalOption(const std::string& name,
+                                                       const std::string& description,
+                                                       std::vector<std::string>* value) {
+  assert(value != nullptr);
+  auto func = [value](const std::string& arg) -> void { value->push_back(arg); };
+  options_.push_back(Option{name, description, func, Option::COUNT_OPTIONAL_ONCE_OR_MORE, true});
+  return *this;
+}
+
 bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostream& outError) const {
   const auto pivot = std::partition(options_.begin(), options_.end(), [](const Option& opt) {
-    return opt.count != Option::COUNT_OPTIONAL;
+    return opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE;
   });
   std::set<std::string> mandatory_opts;
   std::transform(options_.begin(), pivot, std::inserter(mandatory_opts, mandatory_opts.end()),
@@ -122,7 +131,8 @@
   size_t maxLength = 0;
   out << "usage: " << name_;
   for (const Option& opt : options_) {
-    const bool mandatory = opt.count != Option::COUNT_OPTIONAL;
+    const bool mandatory =
+        opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE;
     out << " ";
     if (!mandatory) {
       out << "[";
@@ -134,9 +144,15 @@
       out << opt.name;
       maxLength = std::max(maxLength, opt.name.size());
     }
+
+    if (opt.count == Option::COUNT_OPTIONAL_ONCE_OR_MORE) {
+      out << " [..]";
+    }
+
     if (!mandatory) {
       out << "]";
     }
+
     if (opt.count == Option::COUNT_ONCE_OR_MORE) {
       out << " [" << opt.name << " arg [..]]";
     }
@@ -150,7 +166,8 @@
       out << opt.name;
     }
     out << "    " << opt.description;
-    if (opt.count == Option::COUNT_ONCE_OR_MORE) {
+    if (opt.count == Option::COUNT_ONCE_OR_MORE ||
+        opt.count == Option::COUNT_OPTIONAL_ONCE_OR_MORE) {
       out << " (can be provided multiple times)";
     }
     out << std::endl;
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 37d6af8..5d449e9 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -274,11 +274,30 @@
   return std::move(idmap);
 }
 
-std::unique_ptr<const Idmap> Idmap::FromApkAssets(const std::string& target_apk_path,
-                                                  const ApkAssets& target_apk_assets,
-                                                  const std::string& overlay_apk_path,
-                                                  const ApkAssets& overlay_apk_assets,
-                                                  std::ostream& out_error) {
+bool CheckOverlayable(const LoadedPackage& target_package,
+                      const utils::OverlayManifestInfo& overlay_info,
+                      const PolicyBitmask& fulfilled_polices, const ResourceId& resid) {
+  const OverlayableInfo* overlayable_info = target_package.GetOverlayableInfo(resid);
+  if (overlayable_info == nullptr) {
+    // If the resource does not have an overlayable definition, allow the resource to be overlaid.
+    // Once overlayable enforcement is turned on, this check will return false.
+    return true;
+  }
+
+  if (!overlay_info.target_name.empty() && overlay_info.target_name != overlayable_info->name) {
+    // If the overlay supplies a target overlayable name, the resource must belong to the
+    // overlayable defined with the specified name to be overlaid.
+    return false;
+  }
+
+  // Enforce policy restrictions if the resource is declared as overlayable.
+  return (overlayable_info->policy_flags & fulfilled_polices) != 0;
+}
+
+std::unique_ptr<const Idmap> Idmap::FromApkAssets(
+    const std::string& target_apk_path, const ApkAssets& target_apk_assets,
+    const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
+    const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error) {
   AssetManager2 target_asset_manager;
   if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true, false)) {
     out_error << "error: failed to create target asset manager" << std::endl;
@@ -327,6 +346,12 @@
     return nullptr;
   }
 
+  Result<utils::OverlayManifestInfo> overlay_info =
+      utils::ExtractOverlayManifestInfo(overlay_apk_path, out_error);
+  if (!overlay_info) {
+    return nullptr;
+  }
+
   std::unique_ptr<IdmapHeader> header(new IdmapHeader());
   header->magic_ = kIdmapMagic;
   header->version_ = kIdmapCurrentVersion;
@@ -380,6 +405,14 @@
     if (target_resid == 0) {
       continue;
     }
+
+    if (enforce_overlayable &&
+        !CheckOverlayable(*target_pkg, *overlay_info, fulfilled_policies, target_resid)) {
+      LOG(WARNING) << "overlay \"" << overlay_apk_path << "\" is not allowed to overlay resource \""
+                   << full_name << "\"" << std::endl;
+      continue;
+    }
+
     matching_resources.Add(target_resid, overlay_resid);
   }
 
diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp
new file mode 100644
index 0000000..0f87ef0
--- /dev/null
+++ b/cmds/idmap2/libidmap2/Policies.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "androidfw/ResourceTypes.h"
+
+#include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/Result.h"
+
+namespace android::idmap2 {
+
+namespace {
+
+const std::map<android::StringPiece, PolicyFlags> kStringToFlag = {
+    {"public", PolicyFlags::POLICY_PUBLIC},
+    {"product", PolicyFlags::POLICY_PRODUCT_PARTITION},
+    {"system", PolicyFlags::POLICY_SYSTEM_PARTITION},
+    {"vendor", PolicyFlags::POLICY_VENDOR_PARTITION},
+};
+}  // namespace
+
+Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies,
+                                        std::ostream& err) {
+  PolicyBitmask bitmask = 0;
+  for (const std::string& policy : policies) {
+    const auto iter = kStringToFlag.find(policy);
+    if (iter != kStringToFlag.end()) {
+      bitmask |= iter->second;
+    } else {
+      err << "error: unknown policy \"" << policy << "\"";
+      return kResultError;
+    }
+  }
+
+  return Result<PolicyBitmask>(bitmask);
+}
+
+}  // namespace android::idmap2
diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
index ec2decf..b78e942 100644
--- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
@@ -89,6 +89,7 @@
   }
 }
 
+// NOLINTNEXTLINE(cert-dcl50-cpp)
 void RawPrintVisitor::print(uint16_t value, const char* fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
@@ -101,6 +102,7 @@
   offset_ += sizeof(uint16_t);
 }
 
+// NOLINTNEXTLINE(cert-dcl50-cpp)
 void RawPrintVisitor::print(uint32_t value, const char* fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
@@ -113,6 +115,7 @@
   offset_ += sizeof(uint32_t);
 }
 
+// NOLINTNEXTLINE(cert-dcl50-cpp)
 void RawPrintVisitor::print(const std::string& value, const char* fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp
index 04e0ec7..7a984f3 100644
--- a/cmds/idmap2/libidmap2/ResourceUtils.cpp
+++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <memory>
 #include <string>
 
 #include "androidfw/StringPiece.h"
@@ -21,8 +22,13 @@
 
 #include "idmap2/ResourceUtils.h"
 #include "idmap2/Result.h"
+#include "idmap2/Xml.h"
+#include "idmap2/ZipFile.h"
 
 using android::StringPiece16;
+using android::idmap2::Result;
+using android::idmap2::Xml;
+using android::idmap2::ZipFile;
 using android::util::Utf16ToUtf8;
 
 namespace android::idmap2::utils {
@@ -47,4 +53,63 @@
   return {out};
 }
 
+Result<OverlayManifestInfo> ExtractOverlayManifestInfo(const std::string& path,
+                                                       std::ostream& out_error,
+                                                       bool assert_overlay) {
+  std::unique_ptr<const ZipFile> zip = ZipFile::Open(path);
+  if (!zip) {
+    out_error << "error: failed to open " << path << " as a zip file" << std::endl;
+    return kResultError;
+  }
+
+  std::unique_ptr<const MemoryChunk> entry = zip->Uncompress("AndroidManifest.xml");
+  if (!entry) {
+    out_error << "error: failed to uncompress AndroidManifest.xml from " << path << std::endl;
+    return kResultError;
+  }
+
+  std::unique_ptr<const Xml> xml = Xml::Create(entry->buf, entry->size);
+  if (!xml) {
+    out_error << "error: failed to parse AndroidManifest.xml from " << path << std::endl;
+    return kResultError;
+  }
+
+  OverlayManifestInfo info{};
+  const auto tag = xml->FindTag("overlay");
+  if (!tag) {
+    if (assert_overlay) {
+      out_error << "error: <overlay> missing from AndroidManifest.xml of " << path << std::endl;
+      return kResultError;
+    }
+    return info;
+  }
+
+  auto iter = tag->find("targetPackage");
+  if (iter == tag->end()) {
+    if (assert_overlay) {
+      out_error << "error: android:targetPackage missing from <overlay> of " << path << std::endl;
+      return kResultError;
+    }
+  } else {
+    info.target_package = iter->second;
+  }
+
+  iter = tag->find("targetName");
+  if (iter != tag->end()) {
+    info.target_name = iter->second;
+  }
+
+  iter = tag->find("isStatic");
+  if (iter != tag->end()) {
+    info.is_static = std::stoul(iter->second) != 0U;
+  }
+
+  iter = tag->find("priority");
+  if (iter != tag->end()) {
+    info.priority = std::stoi(iter->second);
+  }
+
+  return info;
+}
+
 }  // namespace android::idmap2::utils
diff --git a/cmds/idmap2/static-checks.sh b/cmds/idmap2/static-checks.sh
index 560ccb6..ad9830b 100755
--- a/cmds/idmap2/static-checks.sh
+++ b/cmds/idmap2/static-checks.sh
@@ -70,7 +70,15 @@
 function _cpplint()
 {
     local cpplint="${ANDROID_BUILD_TOP}/tools/repohooks/tools/cpplint.py"
-    $cpplint --quiet $cpp_files
+    local output="$($cpplint --quiet $cpp_files 2>&1 >/dev/null | grep -v \
+        -e 'Found C system header after C++ system header.' \
+        -e 'Unknown NOLINT error category: misc-non-private-member-variables-in-classes' \
+    )"
+    if [[ "$output" ]]; then
+        echo "$output"
+        return 1
+    fi
+    return 0
 }
 
 function _parse_args()
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index 2698ac0..0e0e25f 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -78,7 +78,8 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   std::stringstream stream;
@@ -101,25 +102,55 @@
   header = loaded_idmap->GetEntryMapForType(0x02);
   ASSERT_THAT(header, NotNull());
 
-  success = LoadedIdmap::Lookup(header, 0x0002, &entry);
+  success = LoadedIdmap::Lookup(header, 0x0000, &entry);  // string/a
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0003, &entry);
+  success = LoadedIdmap::Lookup(header, 0x0001, &entry);  // string/b
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0002, &entry);  // string/c
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0003, &entry);  // string/other
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0004, &entry);  // string/not_overlayable
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0005, &entry);  // string/policy_product
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0006, &entry);  // string/policy_public
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0007, &entry);  // string/policy_system
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0008, &entry);  // string/policy_system_vendor
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x0009, &entry);  // string/str1
   ASSERT_TRUE(success);
   ASSERT_EQ(entry, 0x0000);
 
-  success = LoadedIdmap::Lookup(header, 0x0004, &entry);
+  success = LoadedIdmap::Lookup(header, 0x000a, &entry);  // string/str2
   ASSERT_FALSE(success);
 
-  success = LoadedIdmap::Lookup(header, 0x0005, &entry);
+  success = LoadedIdmap::Lookup(header, 0x000b, &entry);  // string/str3
   ASSERT_TRUE(success);
   ASSERT_EQ(entry, 0x0001);
 
-  success = LoadedIdmap::Lookup(header, 0x0006, &entry);
+  success = LoadedIdmap::Lookup(header, 0x000c, &entry);  // string/str4
   ASSERT_TRUE(success);
   ASSERT_EQ(entry, 0x0002);
 
-  success = LoadedIdmap::Lookup(header, 0x0007, &entry);
+  success = LoadedIdmap::Lookup(header, 0x000d, &entry);  // string/x
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x000e, &entry);  // string/y
+  ASSERT_FALSE(success);
+
+  success = LoadedIdmap::Lookup(header, 0x000f, &entry);  // string/z
   ASSERT_FALSE(success);
 }
 
diff --git a/cmds/idmap2/tests/CommandLineOptionsTests.cpp b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
index c27d27a..39f18d3 100644
--- a/cmds/idmap2/tests/CommandLineOptionsTests.cpp
+++ b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
@@ -121,6 +121,56 @@
   ASSERT_FALSE(success);
 }
 
+TEST(CommandLineOptionsTests, OptionalOptionList) {
+  std::vector<std::string> foo;
+  std::vector<std::string> bar;
+  CommandLineOptions opts = CommandLineOptions("test")
+                                .OptionalOption("--foo", "", &foo)
+                                .OptionalOption("--bar", "", &bar);
+  std::ostream fakeStdErr(nullptr);
+  bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
+  ASSERT_TRUE(success);
+  ASSERT_EQ(foo.size(), 1U);
+  ASSERT_EQ(foo[0], "FOO");
+  ASSERT_EQ(bar.size(), 1U);
+  ASSERT_EQ(bar[0], "BAR");
+
+  foo.clear();
+  bar.clear();
+  success = opts.Parse({"--foo", "BAZ"}, fakeStdErr);
+  ASSERT_TRUE(success);
+  ASSERT_EQ(foo.size(), 1U);
+  ASSERT_EQ(foo[0], "BAZ");
+  ASSERT_EQ(bar.size(), 0U);
+
+  foo.clear();
+  bar.clear();
+  success =
+      opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"}, fakeStdErr);
+  ASSERT_TRUE(success);
+  ASSERT_EQ(foo.size(), 2U);
+  ASSERT_EQ(foo[0], "BAZ");
+  ASSERT_EQ(foo[1], "BIZ");
+  ASSERT_EQ(bar.size(), 2U);
+  ASSERT_EQ(bar[0], "FIZ");
+  ASSERT_EQ(bar[1], "FUZZ");
+
+  foo.clear();
+  bar.clear();
+  success = opts.Parse({"--foo"}, fakeStdErr);
+  ASSERT_FALSE(success);
+
+  foo.clear();
+  bar.clear();
+  success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr);
+  ASSERT_FALSE(success);
+
+  foo.clear();
+  bar.clear();
+  success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr);
+  ASSERT_FALSE(success);
+}
+
 TEST(CommandLineOptionsTests, CornerCases) {
   std::string foo;
   std::string bar;
@@ -172,6 +222,7 @@
   bool arg5 = false;
   bool arg6 = false;
   std::vector<std::string> arg7;
+  std::vector<std::string> arg8;
   CommandLineOptions opts = CommandLineOptions("test")
                                 .MandatoryOption("--aa", "description-aa", &arg1)
                                 .OptionalFlag("--bb", "description-bb", &arg5)
@@ -179,12 +230,13 @@
                                 .OptionalOption("--dd", "description-dd", &arg3)
                                 .MandatoryOption("--ee", "description-ee", &arg4)
                                 .OptionalFlag("--ff", "description-ff", &arg6)
-                                .MandatoryOption("--gg", "description-gg", &arg7);
+                                .MandatoryOption("--gg", "description-gg", &arg7)
+                                .OptionalOption("--hh", "description-hh", &arg8);
   std::stringstream stream;
   opts.Usage(stream);
   const std::string s = stream.str();
   ASSERT_NE(s.find("usage: test --aa arg [--bb] [--cc arg] [--dd arg] --ee arg [--ff] --gg arg "
-                   "[--gg arg [..]]"),
+                   "[--gg arg [..]] [--hh arg [..]]"),
             std::string::npos);
   ASSERT_NE(s.find("--aa arg    description-aa"), std::string::npos);
   ASSERT_NE(s.find("--ff        description-ff"), std::string::npos);
diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp
index 4bf832a..d9d9a7f 100644
--- a/cmds/idmap2/tests/FileUtilsTests.cpp
+++ b/cmds/idmap2/tests/FileUtilsTests.cpp
@@ -37,10 +37,10 @@
                             [](unsigned char type ATTRIBUTE_UNUSED,
                                const std::string& path ATTRIBUTE_UNUSED) -> bool { return true; });
   ASSERT_THAT(v, NotNull());
-  ASSERT_EQ(v->size(), 4U);
-  ASSERT_EQ(
-      std::set<std::string>(v->begin(), v->end()),
-      std::set<std::string>({root + "/.", root + "/..", root + "/overlay", root + "/target"}));
+  ASSERT_EQ(v->size(), 6U);
+  ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
+            std::set<std::string>({root + "/.", root + "/..", root + "/overlay", root + "/target",
+                                   root + "/system-overlay", root + "/system-overlay-invalid"}));
 }
 
 TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) {
@@ -49,11 +49,13 @@
     return type == DT_REG && path.size() > 4 && path.compare(path.size() - 4, 4, ".apk") == 0;
   });
   ASSERT_THAT(v, NotNull());
-  ASSERT_EQ(v->size(), 4U);
+  ASSERT_EQ(v->size(), 6U);
   ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
             std::set<std::string>({root + "/target/target.apk", root + "/overlay/overlay.apk",
                                    root + "/overlay/overlay-static-1.apk",
-                                   root + "/overlay/overlay-static-2.apk"}));
+                                   root + "/overlay/overlay-static-2.apk",
+                                   root + "/system-overlay/system-overlay.apk",
+                                   root + "/system-overlay-invalid/system-overlay-invalid.apk"}));
 }
 
 TEST(FileUtilsTests, ReadFile) {
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index 22f48e9..4334fa6 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -38,6 +38,7 @@
 #include "gtest/gtest.h"
 
 #include "androidfw/PosixUtils.h"
+
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
 
@@ -114,8 +115,9 @@
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
   ASSERT_NE(result->stdout.find("0x7f010000 -> 0x7f010000 integer/int1"), std::string::npos);
-  ASSERT_NE(result->stdout.find("0x7f020003 -> 0x7f020000 string/str1"), std::string::npos);
-  ASSERT_NE(result->stdout.find("0x7f020005 -> 0x7f020001 string/str3"), std::string::npos);
+  ASSERT_NE(result->stdout.find("0x7f020009 -> 0x7f020000 string/str1"), std::string::npos);
+  ASSERT_NE(result->stdout.find("0x7f02000b -> 0x7f020001 string/str3"), std::string::npos);
+  ASSERT_NE(result->stdout.find("0x7f02000c -> 0x7f020002 string/str4"), std::string::npos);
   ASSERT_EQ(result->stdout.find("00000210:     007f  target package id"), std::string::npos);
 
   // clang-format off
@@ -157,7 +159,8 @@
                                "--recursive",
                                "--target-package-name", "test.target",
                                "--target-apk-path", GetTargetApkPath(),
-                               "--output-directory", GetTempDirPath()});
+                               "--output-directory", GetTempDirPath(),
+                               "--override-policy", "public"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -190,7 +193,8 @@
                           "--input-directory", GetTestDataPath() + "/overlay",
                           "--target-package-name", "test.target",
                           "--target-apk-path", GetTargetApkPath(),
-                          "--output-directory", GetTempDirPath()});
+                          "--output-directory", GetTempDirPath(),
+                          "--override-policy", "public"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -207,7 +211,8 @@
                           "--recursive",
                           "--target-package-name", "test.target",
                           "--target-apk-path", GetTargetApkPath(),
-                          "--output-directory", GetTempDirPath()});
+                          "--output-directory", GetTempDirPath(),
+                          "--override-policy", "public"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -222,7 +227,8 @@
                           "--input-directory", GetTempDirPath(),
                           "--target-package-name", "test.target",
                           "--target-apk-path", GetTargetApkPath(),
-                          "--output-directory", GetTempDirPath()});
+                          "--output-directory", GetTempDirPath(),
+                          "--override-policy", "public"});
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -245,7 +251,7 @@
                           "lookup",
                           "--idmap-path", GetIdmapPath(),
                           "--config", "",
-                          "--resid", "0x7f020003"});  // string/str1
+                          "--resid", "0x7f020009"});  // string/str1
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -310,6 +316,18 @@
   // clang-format on
   ASSERT_THAT(result, NotNull());
   ASSERT_NE(result->status, EXIT_SUCCESS);
+
+  // unknown policy
+  // clang-format off
+  result = ExecuteBinary({"idmap2",
+                          "create",
+                          "--target-apk-path", GetTargetApkPath(),
+                          "--overlay-apk-path", GetOverlayApkPath(),
+                          "--idmap-path", GetIdmapPath(),
+                          "--policy", "this-does-not-exist"});
+  // clang-format on
+  ASSERT_THAT(result, NotNull());
+  ASSERT_NE(result->status, EXIT_SUCCESS);
 }
 
 }  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 963f22e..df28918 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -184,13 +184,14 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
   ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x01U);
-  ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xf5ad1d1d);
+  ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xab7cf70d);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xd470336b);
   ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
@@ -216,13 +217,129 @@
   ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U);
   ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U);
   ASSERT_EQ(types[1]->GetEntryCount(), 4U);
-  ASSERT_EQ(types[1]->GetEntryOffset(), 3U);
+  ASSERT_EQ(types[1]->GetEntryOffset(), 9U);
   ASSERT_EQ(types[1]->GetEntry(0), 0x0000U);
   ASSERT_EQ(types[1]->GetEntry(1), kNoEntry);
   ASSERT_EQ(types[1]->GetEntry(2), 0x0001U);
   ASSERT_EQ(types[1]->GetEntry(3), 0x0002U);
 }
 
+TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
+  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
+  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+  ASSERT_THAT(target_apk, NotNull());
+
+  const std::string overlay_apk_path(GetTestDataPath() + "/system-overlay/system-overlay.apk");
+  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+  ASSERT_THAT(overlay_apk, NotNull());
+
+  std::stringstream error;
+  std::unique_ptr<const Idmap> idmap =
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+                           /* enforce_overlayable */ true, error);
+  ASSERT_THAT(idmap, NotNull());
+
+  const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+  ASSERT_EQ(dataBlocks.size(), 1U);
+
+  const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+
+  ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+  ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+  ASSERT_EQ(types.size(), 1U);
+
+  ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+  ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+  ASSERT_EQ(types[0]->GetEntryCount(), 3U);
+  ASSERT_EQ(types[0]->GetEntryOffset(), 6U);
+  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/policy_public
+  ASSERT_EQ(types[0]->GetEntry(1), 0x0001U);  // string/policy_system
+  ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_system_vendor
+}
+
+TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
+  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
+  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+  ASSERT_THAT(target_apk, NotNull());
+
+  const std::string overlay_apk_path(GetTestDataPath() +
+                                     "/system-overlay-invalid/system-overlay-invalid.apk");
+  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+  ASSERT_THAT(overlay_apk, NotNull());
+
+  std::stringstream error;
+  std::unique_ptr<const Idmap> idmap =
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+                           /* enforce_overlayable */ true, error);
+  ASSERT_THAT(idmap, NotNull());
+
+  const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+  ASSERT_EQ(dataBlocks.size(), 1U);
+
+  const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+
+  ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+  ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+  ASSERT_EQ(types.size(), 1U);
+
+  ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+  ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+  ASSERT_EQ(types[0]->GetEntryCount(), 6U);
+  ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
+  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);   // string/not_overlayable
+  ASSERT_EQ(types[0]->GetEntry(1), kNoEntry);  // string/other
+  ASSERT_EQ(types[0]->GetEntry(2), kNoEntry);  // string/policy_product
+  ASSERT_EQ(types[0]->GetEntry(3), 0x0003U);   // string/policy_public
+  ASSERT_EQ(types[0]->GetEntry(4), 0x0004U);   // string/policy_system
+  ASSERT_EQ(types[0]->GetEntry(5), 0x0005U);   // string/policy_system_vendor
+}
+
+TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
+  const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
+  std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+  ASSERT_THAT(target_apk, NotNull());
+
+  const std::string overlay_apk_path(GetTestDataPath() +
+                                     "/system-overlay-invalid/system-overlay-invalid.apk");
+  std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+  ASSERT_THAT(overlay_apk, NotNull());
+
+  std::stringstream error;
+  std::unique_ptr<const Idmap> idmap =
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+                           /* enforce_overlayable */ false, error);
+  ASSERT_THAT(idmap, NotNull());
+
+  const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+  ASSERT_EQ(dataBlocks.size(), 1U);
+
+  const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+
+  ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+  ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+  const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+  ASSERT_EQ(types.size(), 1U);
+
+  ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+  ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+  ASSERT_EQ(types[0]->GetEntryCount(), 6U);
+  ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
+  ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);  // string/not_overlayable
+  ASSERT_EQ(types[0]->GetEntry(1), 0x0001U);  // string/other
+  ASSERT_EQ(types[0]->GetEntry(2), 0x0002U);  // string/policy_product
+  ASSERT_EQ(types[0]->GetEntry(3), 0x0003U);  // string/policy_public
+  ASSERT_EQ(types[0]->GetEntry(4), 0x0004U);  // string/policy_system
+  ASSERT_EQ(types[0]->GetEntry(5), 0x0005U);  // string/policy_system_vendor
+}
+
 TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) {
   std::string target_apk_path(GetTestDataPath());
   for (int i = 0; i < 32; i++) {
@@ -239,7 +356,8 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, IsNull());
 }
 
@@ -255,8 +373,9 @@
   ASSERT_THAT(overlay_apk, NotNull());
 
   std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+  std::unique_ptr<const Idmap> idmap = Idmap::FromApkAssets(
+      target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+      /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   std::stringstream stream;
diff --git a/cmds/idmap2/tests/PoliciesTests.cpp b/cmds/idmap2/tests/PoliciesTests.cpp
new file mode 100644
index 0000000..ab567ad
--- /dev/null
+++ b/cmds/idmap2/tests/PoliciesTests.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include "gtest/gtest.h"
+
+#include "TestHelpers.h"
+#include "idmap2/Policies.h"
+
+using android::idmap2::PolicyBitmask;
+using android::idmap2::PolicyFlags;
+
+namespace android::idmap2 {
+
+TEST(PoliciesTests, PoliciesToBitmasks) {
+  const Result<PolicyBitmask> bitmask1 = PoliciesToBitmask({"system"}, std::cerr);
+  ASSERT_NE(bitmask1, kResultError);
+  ASSERT_EQ(bitmask1, PolicyFlags::POLICY_SYSTEM_PARTITION);
+
+  const Result<PolicyBitmask> bitmask2 = PoliciesToBitmask({"system", "vendor"}, std::cerr);
+  ASSERT_NE(bitmask2, kResultError);
+  ASSERT_EQ(bitmask2, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
+
+  const Result<PolicyBitmask> bitmask3 = PoliciesToBitmask({"vendor", "system"}, std::cerr);
+  ASSERT_NE(bitmask3, kResultError);
+  ASSERT_EQ(bitmask3, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
+
+  const Result<PolicyBitmask> bitmask4 =
+      PoliciesToBitmask({"public", "product", "system", "vendor"}, std::cerr);
+  ASSERT_NE(bitmask4, kResultError);
+  ASSERT_EQ(bitmask4, PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_PRODUCT_PARTITION |
+                          PolicyFlags::POLICY_SYSTEM_PARTITION |
+                          PolicyFlags::POLICY_VENDOR_PARTITION);
+
+  const Result<PolicyBitmask> bitmask5 =
+      PoliciesToBitmask({"system", "system", "system"}, std::cerr);
+  ASSERT_NE(bitmask5, kResultError);
+  ASSERT_EQ(bitmask5, PolicyFlags::POLICY_SYSTEM_PARTITION);
+
+  const Result<PolicyBitmask> bitmask6 = PoliciesToBitmask({""}, std::cerr);
+  ASSERT_EQ(bitmask6, kResultError);
+
+  const Result<PolicyBitmask> bitmask7 = PoliciesToBitmask({"foo"}, std::cerr);
+  ASSERT_EQ(bitmask7, kResultError);
+
+  const Result<PolicyBitmask> bitmask8 = PoliciesToBitmask({"system", "foo"}, std::cerr);
+  ASSERT_EQ(bitmask8, kResultError);
+
+  const Result<PolicyBitmask> bitmask9 = PoliciesToBitmask({"system", ""}, std::cerr);
+  ASSERT_EQ(bitmask9, kResultError);
+
+  const Result<PolicyBitmask> bitmask10 = PoliciesToBitmask({"system "}, std::cerr);
+  ASSERT_EQ(bitmask10, kResultError);
+}
+
+}  // namespace android::idmap2
diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
index 7736bc0..eaa47cd 100644
--- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
@@ -25,6 +25,7 @@
 #include "androidfw/Idmap.h"
 
 #include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
 #include "idmap2/PrettyPrintVisitor.h"
 
 #include "TestHelpers.h"
@@ -32,6 +33,7 @@
 using ::testing::NotNull;
 
 using android::ApkAssets;
+using android::idmap2::PolicyBitmask;
 
 namespace android::idmap2 {
 
@@ -46,7 +48,8 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   std::stringstream stream;
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 0318cd2..b1ca125 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -42,7 +42,8 @@
 
   std::stringstream error;
   std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
   ASSERT_THAT(idmap, NotNull());
 
   std::stringstream stream;
@@ -51,7 +52,7 @@
 
   ASSERT_NE(stream.str().find("00000000: 504d4449  magic\n"), std::string::npos);
   ASSERT_NE(stream.str().find("00000004: 00000001  version\n"), std::string::npos);
-  ASSERT_NE(stream.str().find("00000008: f5ad1d1d  target crc\n"), std::string::npos);
+  ASSERT_NE(stream.str().find("00000008: ab7cf70d  target crc\n"), std::string::npos);
   ASSERT_NE(stream.str().find("0000000c: d470336b  overlay crc\n"), std::string::npos);
   ASSERT_NE(stream.str().find("0000021c: 00000000  0x7f010000 -> 0x7f010000 integer/int1\n"),
             std::string::npos);
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
new file mode 100644
index 0000000..ae687d3
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="test.overlay.system.invalid">
+    <overlay
+        android:targetPackage="test.target"
+        android:targetName="TestResources"/>
+</manifest>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/build b/cmds/idmap2/tests/data/system-overlay-invalid/build
new file mode 100644
index 0000000..920e1f8
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/build
@@ -0,0 +1,26 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
+
+aapt2 compile --dir res -o compiled.flata
+
+aapt2 link \
+    --no-resource-removal \
+    -I "$FRAMEWORK_RES_APK" \
+    --manifest AndroidManifest.xml \
+    -o system-overlay-invalid.apk \
+    compiled.flata
+
+rm compiled.flata
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
new file mode 100644
index 0000000..af1bea1
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- This overlay will fulfill the policies "public|system". This allows it overlay the
+         following resources. -->
+    <string name="policy_system">policy_system</string>
+    <string name="policy_system_vendor">policy_system_vendor</string>
+    <string name="policy_public">policy_public</string>
+
+    <!-- Requests to overlay a resource that belongs to a policy the overlay does not fulfill. -->
+    <string name="policy_product">policy_product</string>
+
+    <!-- Requests to overlay a resource that is not declared as overlayable. -->
+    <string name="not_overlayable">not_overlayable</string>
+
+    <!-- Requests to overlay a resource that is defined in an overlayable with a name other than
+         the targetName in the manifest. -->
+    <string name="other">other</string>
+</resources>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
new file mode 100644
index 0000000..710ed90
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
new file mode 100644
index 0000000..8af9064
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        package="test.overlay.system">
+    <overlay
+            android:targetPackage="test.target" />
+</manifest>
diff --git a/cmds/idmap2/tests/data/system-overlay/build b/cmds/idmap2/tests/data/system-overlay/build
new file mode 100644
index 0000000..be0d239
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/build
@@ -0,0 +1,26 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
+
+aapt2 compile --dir res -o compiled.flata
+
+aapt2 link \
+    --no-resource-removal \
+    -I "$FRAMEWORK_RES_APK" \
+    --manifest AndroidManifest.xml \
+    -o system-overlay.apk \
+    compiled.flata
+
+rm compiled.flata
diff --git a/cmds/idmap2/tests/data/system-overlay/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay/res/values/values.xml
new file mode 100644
index 0000000..6aaa0b0
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/res/values/values.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- This overlay will fulfill the policies "public|system". This allows it overlay the
+     following resources. -->
+    <string name="policy_system">policy_system</string>
+    <string name="policy_system_vendor">policy_system_vendor</string>
+    <string name="policy_public">policy_public</string>
+</resources>
diff --git a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
new file mode 100644
index 0000000..90f30eb
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
new file mode 100644
index 0000000..02d2563
--- /dev/null
+++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+<overlayable name="TestResources">
+    <!-- Publicly overlayable resources -->
+    <item type="string" name="a" />
+    <item type="string" name="b" />
+    <item type="string" name="c" />
+    <item type="string" name="str1" />
+    <item type="string" name="str2" />
+    <item type="string" name="str3" />
+    <item type="string" name="str4" />
+    <item type="string" name="x" />
+    <item type="string" name="y" />
+    <item type="string" name="z" />
+    <item type="integer" name="int1" />
+
+    <!-- Resources with partition restrictins -->
+    <policy type="system">
+        <item type="string" name="policy_system" />
+    </policy>
+
+    <policy type="system|vendor">
+        <item type="string" name="policy_system_vendor" />
+    </policy>
+
+    <policy type="product">
+        <item type="string" name="policy_product" />
+    </policy>
+
+    <policy type="public">
+        <item type="string" name="policy_public" />
+    </policy>
+</overlayable>
+
+<overlayable name="OtherResources">
+    <item type="string" name="other" />
+</overlayable>
+</resources>
\ No newline at end of file
diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml
index 56bf0d6..0d337f3 100644
--- a/cmds/idmap2/tests/data/target/res/values/values.xml
+++ b/cmds/idmap2/tests/data/target/res/values/values.xml
@@ -25,4 +25,14 @@
     <string name="y">y</string>
     <string name="z">z</string>
     <integer name="int1">1</integer>
+
+    <!-- This resources is not marked as overlayable -->
+    <string name="not_overlayable">not_overlayable</string>
+
+    <string name="policy_system">policy_system</string>
+    <string name="policy_system_vendor">policy_system_vendor</string>
+    <string name="policy_product">policy_product</string>
+    <string name="policy_public">policy_public</string>
+
+    <item type="string" name="other" />
 </resources>
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index 18ecc27..ecbe875 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index 74edffb..0c861cf 100644
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -16,15 +16,20 @@
 
 package com.android.commands.input;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
 import android.hardware.input.InputManager;
 import android.os.SystemClock;
-import android.util.Log;
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 
+import com.android.internal.os.BaseCommand;
+
+import java.io.PrintStream;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -33,9 +38,14 @@
  * desired character output.
  */
 
-public class Input {
+public class Input extends BaseCommand {
     private static final String TAG = "Input";
     private static final String INVALID_ARGUMENTS = "Error: Invalid arguments for command: ";
+    private static final String INVALID_DISPLAY_ARGUMENTS =
+            "Error: Invalid arguments for display ID.";
+
+    private static final float DEFAULT_PRESSURE = 1.0f;
+    private static final float NO_PRESSURE = 0.0f;
 
     private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{
         put("keyboard", InputDevice.SOURCE_KEYBOARD);
@@ -50,6 +60,7 @@
         put("joystick", InputDevice.SOURCE_JOYSTICK);
     }};
 
+    private static final Map<String, InputCmd> COMMANDS = new HashMap<String, InputCmd>();
 
     /**
      * Command-line entry point.
@@ -60,217 +71,292 @@
         (new Input()).run(args);
     }
 
-    private void run(String[] args) {
-        if (args.length < 1) {
-            showUsage();
-            return;
-        }
+    Input() {
+        COMMANDS.put("text", new InputText());
+        COMMANDS.put("keyevent", new InputKeyEvent());
+        COMMANDS.put("tap", new InputTap());
+        COMMANDS.put("swipe", new InputSwipe());
+        COMMANDS.put("draganddrop", new InputDragAndDrop());
+        COMMANDS.put("press", new InputPress());
+        COMMANDS.put("roll", new InputRoll());
+        COMMANDS.put("motionevent", new InputMotionEvent());
+    }
 
-        int index = 0;
-        String command = args[index];
+    @Override
+    public void onRun() throws Exception {
+        String arg = nextArgRequired();
         int inputSource = InputDevice.SOURCE_UNKNOWN;
-        if (SOURCES.containsKey(command)) {
-            inputSource = SOURCES.get(command);
-            index++;
-            command = args[index];
-        }
-        final int length = args.length - index;
 
-        try {
-            if (command.equals("text")) {
-                if (length == 2) {
-                    inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
-                    sendText(inputSource, args[index+1]);
-                    return;
+        // Get source (optional).
+        if (SOURCES.containsKey(arg)) {
+            inputSource = SOURCES.get(arg);
+            arg = nextArgRequired();
+        }
+
+        // Get displayId (optional).
+        int displayId = INVALID_DISPLAY;
+        if ("-d".equals(arg)) {
+            displayId = getDisplayId();
+            arg = nextArgRequired();
+        }
+
+        // Get command and run.
+        InputCmd cmd = COMMANDS.get(arg);
+        if (cmd != null) {
+            try {
+                cmd.run(inputSource, displayId);
+                return;
+            } catch (NumberFormatException ex) {
+                throw new IllegalArgumentException(INVALID_ARGUMENTS + arg);
+            }
+        }
+
+        throw new IllegalArgumentException("Error: Unknown command: " + arg);
+    }
+
+    private int getDisplayId() {
+        String displayArg = nextArgRequired();
+        if ("INVALID_DISPLAY".equalsIgnoreCase(displayArg)) {
+            return INVALID_DISPLAY;
+        } else if ("DEFAULT_DISPLAY".equalsIgnoreCase(displayArg)) {
+            return DEFAULT_DISPLAY;
+        } else {
+            try {
+                final int displayId = Integer.parseInt(displayArg);
+                if (displayId == INVALID_DISPLAY) {
+                    return INVALID_DISPLAY;
                 }
-            } else if (command.equals("keyevent")) {
-                if (length >= 2) {
-                    final boolean longpress = "--longpress".equals(args[index + 1]);
-                    final int start = longpress ? index + 2 : index + 1;
-                    inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
-                    if (args.length > start) {
-                        for (int i = start; i < args.length; i++) {
-                            int keyCode = KeyEvent.keyCodeFromString(args[i]);
-                            sendKeyEvent(inputSource, keyCode, longpress);
-                        }
-                        return;
+                return Math.max(displayId, 0);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException(INVALID_DISPLAY_ARGUMENTS);
+            }
+        }
+    }
+
+    class InputText implements InputCmd {
+        @Override
+        public void run(int inputSource, int displayId) {
+            inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
+            sendText(inputSource, nextArgRequired(), displayId);
+        }
+
+        /**
+         * Convert the characters of string text into key event's and send to
+         * device.
+         *
+         * @param text is a string of characters you want to input to the device.
+         */
+        private void sendText(int source, final String text, int displayId) {
+            final StringBuffer buff = new StringBuffer(text);
+            boolean escapeFlag = false;
+            for (int i = 0; i < buff.length(); i++) {
+                if (escapeFlag) {
+                    escapeFlag = false;
+                    if (buff.charAt(i) == 's') {
+                        buff.setCharAt(i, ' ');
+                        buff.deleteCharAt(--i);
                     }
                 }
-            } else if (command.equals("tap")) {
-                if (length == 3) {
-                    inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
-                    sendTap(inputSource, Float.parseFloat(args[index+1]),
-                            Float.parseFloat(args[index+2]));
-                    return;
+                if (buff.charAt(i) == '%') {
+                    escapeFlag = true;
                 }
-            } else if (command.equals("swipe")) {
-                int duration = -1;
-                inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
-                switch (length) {
-                    case 6:
-                        duration = Integer.parseInt(args[index+5]);
-                    case 5:
-                        sendSwipe(inputSource,
-                                Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]),
-                                Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]),
-                                duration);
-                        return;
-                }
-            } else if (command.equals("draganddrop")) {
-                int duration = -1;
-                inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
-                switch (length) {
-                    case 6:
-                        duration = Integer.parseInt(args[index+5]);
-                    case 5:
-                        sendDragAndDrop(inputSource,
-                                Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]),
-                                Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]),
-                                duration);
-                        return;
-                }
-            } else if (command.equals("press")) {
-                inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
-                if (length == 1) {
-                    sendTap(inputSource, 0.0f, 0.0f);
-                    return;
-                }
-            } else if (command.equals("roll")) {
-                inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
-                if (length == 3) {
-                    sendMove(inputSource, Float.parseFloat(args[index+1]),
-                            Float.parseFloat(args[index+2]));
-                    return;
-                }
-            } else {
-                System.err.println("Error: Unknown command: " + command);
-                showUsage();
-                return;
             }
-        } catch (NumberFormatException ex) {
+
+            final char[] chars = buff.toString().toCharArray();
+            final KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+            final KeyEvent[] events = kcm.getEvents(chars);
+            for (int i = 0; i < events.length; i++) {
+                KeyEvent e = events[i];
+                if (source != e.getSource()) {
+                    e.setSource(source);
+                }
+                e.setDisplayId(displayId);
+                injectKeyEvent(e);
+            }
         }
-        System.err.println(INVALID_ARGUMENTS + command);
-        showUsage();
+    }
+
+    class InputKeyEvent implements InputCmd {
+        @Override
+        public void run(int inputSource, int displayId) {
+            String arg = nextArgRequired();
+            final boolean longpress = "--longpress".equals(arg);
+            if (longpress) {
+                arg = nextArgRequired();
+            }
+
+            do {
+                final int keycode = KeyEvent.keyCodeFromString(arg);
+                sendKeyEvent(inputSource, keycode, longpress, displayId);
+            } while ((arg = nextArg()) != null);
+        }
+
+        private void sendKeyEvent(int inputSource, int keyCode, boolean longpress, int displayId) {
+            final long now = SystemClock.uptimeMillis();
+            int repeatCount = 0;
+
+            KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, repeatCount,
+                    0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0/*flags*/,
+                    inputSource);
+            event.setDisplayId(displayId);
+
+            injectKeyEvent(event);
+            if (longpress) {
+                repeatCount++;
+                injectKeyEvent(KeyEvent.changeTimeRepeat(event, now, repeatCount,
+                        KeyEvent.FLAG_LONG_PRESS));
+            }
+            injectKeyEvent(KeyEvent.changeAction(event, KeyEvent.ACTION_UP));
+        }
+    }
+
+    class InputTap implements InputCmd {
+        @Override
+        public void run(int inputSource, int displayId) {
+            inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
+            sendTap(inputSource, Float.parseFloat(nextArgRequired()),
+                    Float.parseFloat(nextArgRequired()), displayId);
+        }
+
+        void sendTap(int inputSource, float x, float y, int displayId) {
+            final long now = SystemClock.uptimeMillis();
+            injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, now, x, y, 1.0f,
+                    displayId);
+            injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, now, x, y, 0.0f, displayId);
+        }
+    }
+
+    class InputPress extends InputTap {
+        @Override
+        public void run(int inputSource, int displayId) {
+            inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
+            sendTap(inputSource, 0.0f, 0.0f, displayId);
+        }
+    }
+
+    class InputSwipe implements InputCmd {
+        @Override
+        public void run(int inputSource, int displayId) {
+            inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
+            sendSwipe(inputSource, displayId, false);
+        }
+
+        void sendSwipe(int inputSource, int displayId, boolean isDragDrop) {
+            // Parse two points and duration.
+            final float x1 = Float.parseFloat(nextArgRequired());
+            final float y1 = Float.parseFloat(nextArgRequired());
+            final float x2 = Float.parseFloat(nextArgRequired());
+            final float y2 = Float.parseFloat(nextArgRequired());
+            String durationArg = nextArg();
+            int duration = durationArg != null ? Integer.parseInt(durationArg) : -1;
+            if (duration < 0) {
+                duration = 300;
+            }
+
+            final long down = SystemClock.uptimeMillis();
+            injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, down, down, x1, y1, 1.0f,
+                    displayId);
+            if (isDragDrop) {
+                // long press until drag start.
+                try {
+                    Thread.sleep(ViewConfiguration.getLongPressTimeout());
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+            long now = SystemClock.uptimeMillis();
+            final long endTime = down + duration;
+            while (now < endTime) {
+                final long elapsedTime = now - down;
+                final float alpha = (float) elapsedTime / duration;
+                injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, down, now,
+                        lerp(x1, x2, alpha), lerp(y1, y2, alpha), 1.0f, displayId);
+                now = SystemClock.uptimeMillis();
+            }
+            injectMotionEvent(inputSource, MotionEvent.ACTION_UP, down, now, x2, y2, 0.0f,
+                    displayId);
+        }
+    }
+
+    class InputDragAndDrop extends InputSwipe {
+        @Override
+        public void run(int inputSource, int displayId) {
+            inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
+            sendSwipe(inputSource, displayId, true);
+        }
+    }
+
+    class InputRoll implements InputCmd {
+        @Override
+        public void run(int inputSource, int displayId) {
+            inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
+            sendMove(inputSource, Float.parseFloat(nextArgRequired()),
+                    Float.parseFloat(nextArgRequired()), displayId);
+        }
+
+        /**
+         * Sends a simple zero-pressure move event.
+         *
+         * @param inputSource the InputDevice.SOURCE_* sending the input event
+         * @param dx change in x coordinate due to move
+         * @param dy change in y coordinate due to move
+         */
+        private void sendMove(int inputSource, float dx, float dy, int displayId) {
+            final long now = SystemClock.uptimeMillis();
+            injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, now, dx, dy, 0.0f,
+                    displayId);
+        }
+    }
+
+    class InputMotionEvent implements InputCmd {
+        @Override
+        public void run(int inputSource, int displayId) {
+            inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
+            sendMotionEvent(inputSource, nextArgRequired(), Float.parseFloat(nextArgRequired()),
+                    Float.parseFloat(nextArgRequired()), displayId);
+        }
+
+        private void sendMotionEvent(int inputSource, String motionEventType, float x, float y,
+                int displayId) {
+            final int action;
+            final float pressure;
+
+            switch (motionEventType.toUpperCase()) {
+                case "DOWN":
+                    action = MotionEvent.ACTION_DOWN;
+                    pressure = DEFAULT_PRESSURE;
+                    break;
+                case "UP":
+                    action = MotionEvent.ACTION_UP;
+                    pressure = NO_PRESSURE;
+                    break;
+                case "MOVE":
+                    action = MotionEvent.ACTION_MOVE;
+                    pressure = DEFAULT_PRESSURE;
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unknown motionevent " + motionEventType);
+            }
+
+            final long now = SystemClock.uptimeMillis();
+            injectMotionEvent(inputSource, action, now, now, x, y, pressure, displayId);
+        }
     }
 
     /**
-     * Convert the characters of string text into key event's and send to
-     * device.
-     *
-     * @param text is a string of characters you want to input to the device.
+     * Abstract class for command
+     * use nextArgRequired or nextArg to check next argument if necessary.
      */
-    private void sendText(int source, String text) {
-
-        StringBuffer buff = new StringBuffer(text);
-
-        boolean escapeFlag = false;
-        for (int i=0; i<buff.length(); i++) {
-            if (escapeFlag) {
-                escapeFlag = false;
-                if (buff.charAt(i) == 's') {
-                    buff.setCharAt(i, ' ');
-                    buff.deleteCharAt(--i);
-                }
-            }
-            if (buff.charAt(i) == '%') {
-                escapeFlag = true;
-            }
-        }
-
-        char[] chars = buff.toString().toCharArray();
-
-        KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
-        KeyEvent[] events = kcm.getEvents(chars);
-        for(int i = 0; i < events.length; i++) {
-            KeyEvent e = events[i];
-            if (source != e.getSource()) {
-                e.setSource(source);
-            }
-            injectKeyEvent(e);
-        }
+    private interface InputCmd {
+        void run(int inputSource, int displayId);
     }
 
-    private void sendKeyEvent(int inputSource, int keyCode, boolean longpress) {
-        long now = SystemClock.uptimeMillis();
-        injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
-                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
-        if (longpress) {
-            injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 1, 0,
-                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_LONG_PRESS,
-                    inputSource));
-        }
-        injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
-                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
-    }
-
-    private void sendTap(int inputSource, float x, float y) {
-        long now = SystemClock.uptimeMillis();
-        injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x, y, 1.0f);
-        injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x, y, 0.0f);
-    }
-
-    private void sendSwipe(int inputSource, float x1, float y1, float x2, float y2, int duration) {
-        if (duration < 0) {
-            duration = 300;
-        }
-        long now = SystemClock.uptimeMillis();
-        injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f);
-        long startTime = now;
-        long endTime = startTime + duration;
-        while (now < endTime) {
-            long elapsedTime = now - startTime;
-            float alpha = (float) elapsedTime / duration;
-            injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha),
-                    lerp(y1, y2, alpha), 1.0f);
-            now = SystemClock.uptimeMillis();
-        }
-        injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f);
-    }
-
-    private void sendDragAndDrop(int inputSource, float x1, float y1, float x2, float y2,
-            int dragDuration) {
-        if (dragDuration < 0) {
-            dragDuration = 300;
-        }
-        long now = SystemClock.uptimeMillis();
-        injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f);
-        try {
-            Thread.sleep(ViewConfiguration.getLongPressTimeout());
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        }
-        now = SystemClock.uptimeMillis();
-        long startTime = now;
-        long endTime = startTime + dragDuration;
-        while (now < endTime) {
-            long elapsedTime = now - startTime;
-            float alpha = (float) elapsedTime / dragDuration;
-            injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha),
-                    lerp(y1, y2, alpha), 1.0f);
-            now = SystemClock.uptimeMillis();
-        }
-        injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f);
-    }
-
-    /**
-     * Sends a simple zero-pressure move event.
-     *
-     * @param inputSource the InputDevice.SOURCE_* sending the input event
-     * @param dx change in x coordinate due to move
-     * @param dy change in y coordinate due to move
-     */
-    private void sendMove(int inputSource, float dx, float dy) {
-        long now = SystemClock.uptimeMillis();
-        injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, dx, dy, 0.0f);
-    }
-
-    private void injectKeyEvent(KeyEvent event) {
-        Log.i(TAG, "injectKeyEvent: " + event);
+    private static void injectKeyEvent(KeyEvent event) {
         InputManager.getInstance().injectInputEvent(event,
                 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
     }
 
-    private int getInputDeviceId(int inputSource) {
+    private static int getInputDeviceId(int inputSource) {
         final int DEFAULT_DEVICE_ID = 0;
         int[] devIds = InputDevice.getDeviceIds();
         for (int devId : devIds) {
@@ -287,22 +373,27 @@
      *
      * @param inputSource the InputDevice.SOURCE_* sending the input event
      * @param action the MotionEvent.ACTION_* for the event
+     * @param downTime the value of the ACTION_DOWN event happened
      * @param when the value of SystemClock.uptimeMillis() at which the event happened
      * @param x x coordinate of event
      * @param y y coordinate of event
      * @param pressure pressure of event
      */
-    private void injectMotionEvent(int inputSource, int action, long when, float x, float y, float pressure) {
+    private static void injectMotionEvent(int inputSource, int action, long downTime, long when,
+            float x, float y, float pressure, int displayId) {
         final float DEFAULT_SIZE = 1.0f;
         final int DEFAULT_META_STATE = 0;
         final float DEFAULT_PRECISION_X = 1.0f;
         final float DEFAULT_PRECISION_Y = 1.0f;
         final int DEFAULT_EDGE_FLAGS = 0;
-        MotionEvent event = MotionEvent.obtain(when, when, action, x, y, pressure, DEFAULT_SIZE,
+        MotionEvent event = MotionEvent.obtain(downTime, when, action, x, y, pressure, DEFAULT_SIZE,
                 DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y,
                 getInputDeviceId(inputSource), DEFAULT_EDGE_FLAGS);
         event.setSource(inputSource);
-        Log.i(TAG, "injectMotionEvent: " + event);
+        if (displayId == INVALID_DISPLAY && (inputSource & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+            displayId = DEFAULT_DISPLAY;
+        }
+        event.setDisplayId(displayId);
         InputManager.getInstance().injectInputEvent(event,
                 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
     }
@@ -315,24 +406,30 @@
         return inputSource == InputDevice.SOURCE_UNKNOWN ? defaultSource : inputSource;
     }
 
-    private void showUsage() {
-        System.err.println("Usage: input [<source>] <command> [<arg>...]");
-        System.err.println();
-        System.err.println("The sources are: ");
+    @Override
+    public void onShowUsage(PrintStream out) {
+        out.println("Usage: input [<source>] [-d DISPLAY_ID] <command> [<arg>...]");
+        out.println();
+        out.println("The sources are: ");
         for (String src : SOURCES.keySet()) {
-            System.err.println("      " + src);
+            out.println("      " + src);
         }
-        System.err.println();
-        System.err.println("The commands and default sources are:");
-        System.err.println("      text <string> (Default: touchscreen)");
-        System.err.println("      keyevent [--longpress] <key code number or name> ..."
+        out.println();
+        out.printf("-d: specify the display ID.\n"
+                + "      (Default: %d for key event, %d for motion event if not specified.)",
+                INVALID_DISPLAY, DEFAULT_DISPLAY);
+        out.println();
+        out.println("The commands and default sources are:");
+        out.println("      text <string> (Default: touchscreen)");
+        out.println("      keyevent [--longpress] <key code number or name> ..."
                 + " (Default: keyboard)");
-        System.err.println("      tap <x> <y> (Default: touchscreen)");
-        System.err.println("      swipe <x1> <y1> <x2> <y2> [duration(ms)]"
+        out.println("      tap <x> <y> (Default: touchscreen)");
+        out.println("      swipe <x1> <y1> <x2> <y2> [duration(ms)]"
                 + " (Default: touchscreen)");
-        System.err.println("      draganddrop <x1> <y1> <x2> <y2> [duration(ms)]"
+        out.println("      draganddrop <x1> <y1> <x2> <y2> [duration(ms)]"
                 + " (Default: touchscreen)");
-        System.err.println("      press (Default: trackball)");
-        System.err.println("      roll <dx> <dy> (Default: trackball)");
+        out.println("      press (Default: trackball)");
+        out.println("      roll <dx> <dy> (Default: trackball)");
+        out.println("      event <DOWN|UP|MOVE> <x> <y> (Default: touchscreen)");
     }
 }
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index ded20c4..1e915f8 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -17,18 +17,18 @@
 
 package com.android.commands.media;
 
-import android.app.ActivityManager;
+import android.app.ActivityThread;
 import android.content.Context;
-import android.media.AudioAttributes;
 import android.media.MediaMetadata;
-import android.media.session.ControllerCallbackLink;
-import android.media.session.ISessionController;
 import android.media.session.ISessionManager;
+import android.media.session.MediaController;
+import android.media.session.MediaController.PlaybackInfo;
 import android.media.session.MediaSession.QueueItem;
+import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
 import android.os.Bundle;
 import android.os.HandlerThread;
-import android.os.IBinder;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -48,6 +48,8 @@
 public class Media extends BaseCommand {
     // This doesn't belongs to any package. Setting the package name to empty string.
     private static final String PACKAGE_NAME = "";
+    private static ActivityThread sThread;
+    private static MediaSessionManager sMediaSessionManager;
     private ISessionManager mSessionService;
 
     /**
@@ -80,6 +82,13 @@
 
     @Override
     public void onRun() throws Exception {
+        if (sThread == null) {
+            Looper.prepareMainLooper();
+            sThread = ActivityThread.systemMain();
+            Context context = sThread.getSystemContext();
+            sMediaSessionManager =
+                    (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
+        }
         mSessionService = ISessionManager.Stub.asInterface(ServiceManager.checkService(
                 Context.MEDIA_SESSION_SERVICE));
         if (mSessionService == null) {
@@ -117,12 +126,11 @@
             showError("Error: must include a session id");
             return;
         }
+
         boolean success = false;
         try {
-            List<IBinder> sessions = mSessionService
-                    .getSessions(null, ActivityManager.getCurrentUser());
-            for (IBinder session : sessions) {
-                ISessionController controller = ISessionController.Stub.asInterface(session);
+            List<MediaController> controllers = sMediaSessionManager.getActiveSessions(null);
+            for (MediaController controller : controllers) {
                 try {
                     if (controller != null && id.equals(controller.getTag())) {
                         ControllerMonitor monitor = new ControllerMonitor(controller);
@@ -178,14 +186,14 @@
                 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
     }
 
-    class ControllerCallbackStub extends ControllerCallbackLink.CallbackStub {
+    class ControllerCallback extends MediaController.Callback {
         @Override
         public void onSessionDestroyed() {
             System.out.println("onSessionDestroyed. Enter q to quit.");
         }
 
         @Override
-        public void onEvent(String event, Bundle extras) {
+        public void onSessionEvent(String event, Bundle extras) {
             System.out.println("onSessionEvent event=" + event + ", extras=" + extras);
         }
 
@@ -218,28 +226,25 @@
         }
 
         @Override
-        public void onVolumeInfoChanged(int volumeType, AudioAttributes attrs, int controlType,
-                int maxVolume, int currentVolume) {
-            System.out.println("onVolumeInfoChanged " + "volumeType=" + volumeType + ", attrs="
-                    + attrs + ", controlType=" + controlType + ", maxVolume=" + maxVolume
-                    + ", currentVolume=" + currentVolume);
+        public void onAudioInfoChanged(PlaybackInfo info) {
+            System.out.println("onAudioInfoChanged " + info);
         }
     }
 
     private class ControllerMonitor {
-        private final ISessionController mController;
-        private final ControllerCallbackLink mControllerCallbackLink;
+        private final MediaController mController;
+        private final ControllerCallback mControllerCallback;
 
-        ControllerMonitor(ISessionController controller) {
+        ControllerMonitor(MediaController controller) {
             mController = controller;
-            mControllerCallbackLink = new ControllerCallbackLink(new ControllerCallbackStub());
+            mControllerCallback = new ControllerCallback();
         }
 
         void printUsageMessage() {
             try {
                 System.out.println("V2Monitoring session " + mController.getTag()
                         + "...  available commands: play, pause, next, previous");
-            } catch (RemoteException e) {
+            } catch (RuntimeException e) {
                 System.out.println("Error trying to monitor session!");
             }
             System.out.println("(q)uit: finish monitoring");
@@ -251,8 +256,8 @@
                 @Override
                 protected void onLooperPrepared() {
                     try {
-                        mController.registerCallbackListener(PACKAGE_NAME, mControllerCallbackLink);
-                    } catch (RemoteException e) {
+                        mController.registerCallback(mControllerCallback);
+                    } catch (RuntimeException e) {
                         System.out.println("Error registering monitor callback");
                     }
                 }
@@ -294,7 +299,7 @@
             } finally {
                 cbThread.getLooper().quit();
                 try {
-                    mController.unregisterCallbackListener(mControllerCallbackLink);
+                    mController.unregisterCallback(mControllerCallback);
                 } catch (Exception e) {
                     // ignoring
                 }
@@ -308,9 +313,9 @@
             KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
                     KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD);
             try {
-                mController.sendMediaButton(PACKAGE_NAME, null, false, down);
-                mController.sendMediaButton(PACKAGE_NAME, null, false, up);
-            } catch (RemoteException e) {
+                mController.dispatchMediaButtonEvent(down);
+                mController.dispatchMediaButtonEvent(up);
+            } catch (RuntimeException e) {
                 System.out.println("Failed to dispatch " + keyCode);
             }
         }
@@ -319,16 +324,13 @@
     private void runListSessions() {
         System.out.println("Sessions:");
         try {
-            List<IBinder> sessions = mSessionService
-                    .getSessions(null, ActivityManager.getCurrentUser());
-            for (IBinder session : sessions) {
-
-                ISessionController controller = ISessionController.Stub.asInterface(session);
+            List<MediaController> controllers = sMediaSessionManager.getActiveSessions(null);
+            for (MediaController controller : controllers) {
                 if (controller != null) {
                     try {
                         System.out.println("  tag=" + controller.getTag()
                                 + ", package=" + controller.getPackageName());
-                    } catch (RemoteException e) {
+                    } catch (RuntimeException e) {
                         // ignore
                     }
                 }
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 8fa2980..3d74f8b 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -81,8 +81,7 @@
         case ui::Dataspace::V0_SRGB:
             return SkColorSpace::MakeSRGB();
         case ui::Dataspace::DISPLAY_P3:
-            return SkColorSpace::MakeRGB(
-                    SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut);
+            return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
         default:
             return nullptr;
     }
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index f0b751d..ca10482 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -74,7 +74,6 @@
         "src/external/SubsystemSleepStatePuller.cpp",
         "src/external/PowerStatsPuller.cpp",
         "src/external/ResourceHealthManagerPuller.cpp",
-        "src/external/ResourceThermalManagerPuller.cpp",
         "src/external/StatsPullerManager.cpp",
         "src/external/puller_util.cpp",
         "src/logd/LogEvent.cpp",
@@ -136,7 +135,6 @@
         "android.hardware.power@1.0",
         "android.hardware.power@1.1",
         "android.hardware.power.stats@1.0",
-        "android.hardware.thermal@1.0",
         "libpackagelistparser",
         "libsysutils",
         "libcutils",
@@ -332,6 +330,8 @@
         "src/stats_log.proto",
         "src/statsd_config.proto",
         "src/atoms.proto",
+        "src/shell/shell_config.proto",
+        "src/shell/shell_data.proto",
     ],
 
     static_libs: [
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index f2a4663..9c320d3 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -360,7 +360,11 @@
             if (mShellSubscriber == nullptr) {
                 mShellSubscriber = new ShellSubscriber(mUidMap, mPullerManager);
             }
-            mShellSubscriber->startNewSubscription(in, out, resultReceiver);
+            int timeoutSec = -1;
+            if (argCount >= 2) {
+                timeoutSec = atoi(args[1].c_str());
+            }
+            mShellSubscriber->startNewSubscription(in, out, resultReceiver, timeoutSec);
             return NO_ERROR;
         }
     }
@@ -1085,6 +1089,38 @@
     return hardware::Void();
 }
 
+hardware::Return<void> StatsService::reportUsbPortOverheatEvent(
+        const UsbPortOverheatEvent& usbPortOverheatEvent) {
+    LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), usbPortOverheatEvent);
+    mProcessor->OnLogEvent(&event);
+
+    return hardware::Void();
+}
+
+hardware::Return<void> StatsService::reportSpeechDspStat(
+        const SpeechDspStat& speechDspStat) {
+    LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), speechDspStat);
+    mProcessor->OnLogEvent(&event);
+
+    return hardware::Void();
+}
+
+hardware::Return<void> StatsService::reportVendorAtom(const VendorAtom& vendorAtom) {
+    std::string reverseDomainName = (std::string) vendorAtom.reverseDomainName;
+    if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) {
+        ALOGE("Atom ID %ld is not a valid vendor atom ID", (long) vendorAtom.atomId);
+        return hardware::Void();
+    }
+    if (reverseDomainName.length() > 50) {
+        ALOGE("Vendor atom reverse domain name %s is too long.", reverseDomainName.c_str());
+        return hardware::Void();
+    }
+    LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), vendorAtom);
+    mProcessor->OnLogEvent(&event);
+
+    return hardware::Void();
+}
+
 void StatsService::binderDied(const wp <IBinder>& who) {
     ALOGW("statscompanion service died");
     StatsdStats::getInstance().noteSystemServerRestart(getWallClockSec());
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 135a3c9..fe0504f 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -199,6 +199,23 @@
     virtual Return<void> reportBatteryCausedShutdown(
             const BatteryCausedShutdown& batteryCausedShutdown) override;
 
+    /**
+     * Binder call to get UsbPortOverheatEvent atom.
+     */
+    virtual Return<void> reportUsbPortOverheatEvent(
+            const UsbPortOverheatEvent& usbPortOverheatEvent) override;
+
+    /**
+     * Binder call to get Speech DSP state atom.
+     */
+    virtual Return<void> reportSpeechDspStat(
+            const SpeechDspStat& speechDspStat) override;
+
+    /**
+     * Binder call to get vendor atom.
+     */
+    virtual Return<void> reportVendorAtom(const VendorAtom& vendorAtom) override;
+
     /** IBinder::DeathRecipient */
     virtual void binderDied(const wp<IBinder>& who) override;
 
diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp
index 9d37cdb..ad5eae3 100644
--- a/cmds/statsd/src/anomaly/subscriber_util.cpp
+++ b/cmds/statsd/src/anomaly/subscriber_util.cpp
@@ -57,7 +57,7 @@
                 break;
             case Subscription::SubscriberInformationCase::kPerfettoDetails:
                 if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details(),
-                                                            rule_id, configKey)) {
+                                                            subscription.id(), rule_id, configKey)) {
                     ALOGW("Failed to generate perfetto traces.");
                 }
                 break;
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index e541543..008a008 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -25,7 +25,12 @@
 import "frameworks/base/core/proto/android/app/settings_enums.proto";
 import "frameworks/base/core/proto/android/app/job/enums.proto";
 import "frameworks/base/core/proto/android/bluetooth/enums.proto";
+import "frameworks/base/core/proto/android/bluetooth/hci/enums.proto";
+import "frameworks/base/core/proto/android/bluetooth/hfp/enums.proto";
+import "frameworks/base/core/proto/android/debug/enums.proto";
+import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
 import "frameworks/base/core/proto/android/os/enums.proto";
+import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto";
 import "frameworks/base/core/proto/android/server/enums.proto";
 import "frameworks/base/core/proto/android/server/location/enums.proto";
 import "frameworks/base/core/proto/android/service/procstats_enum.proto";
@@ -87,7 +92,7 @@
         ChargingStateChanged charging_state_changed = 31;
         PluggedStateChanged plugged_state_changed = 32;
         InteractiveStateChanged interactive_state_changed = 33;
-        // 34 is available
+        TouchEventReported touch_event_reported = 34;
         WakeupAlarmOccurred wakeup_alarm_occurred = 35;
         KernelWakeupReported kernel_wakeup_reported = 36;
         WifiLockStateChanged wifi_lock_state_changed = 37;
@@ -172,7 +177,36 @@
         WifiEnabledStateChanged wifi_enabled_state_changed = 113;
         WifiRunningStateChanged wifi_running_state_changed = 114;
         AppCompacted app_compacted = 115;
-        NetworkDnsEventReported network_dns_event_Reported = 116;
+        NetworkDnsEventReported network_dns_event_reported = 116;
+        DocsUIPickerLaunchedFromReported docs_ui_picker_launched_from_reported = 117;
+        DocsUIPickResultReported docs_ui_pick_result_reported = 118;
+        DocsUISearchModeReported docs_ui_search_mode_reported = 119;
+        DocsUISearchTypeReported docs_ui_search_type_reported = 120;
+        DataStallEvent data_stall_event = 121;
+        RescuePartyResetReported rescue_party_reset_reported = 122;
+        SignedConfigReported signed_config_reported = 123;
+        GnssNiEventReported gnss_ni_event_reported = 124;
+        BluetoothLinkLayerConnectionEvent bluetooth_link_layer_connection_event = 125;
+        BluetoothAclConnectionStateChanged bluetooth_acl_connection_state_changed = 126;
+        BluetoothScoConnectionStateChanged bluetooth_sco_connection_state_changed = 127;
+        AppDowngraded app_downgraded = 128;
+        AppOptimizedAfterDowngraded app_optimized_after_downgraded = 129;
+        LowStorageStateChanged low_storage_state_changed = 130;
+        GnssNfwNotificationReported gnss_nfw_notification_reported = 131;
+        GnssConfigurationReported gnss_configuration_reported = 132;
+        UsbPortOverheatEvent usb_port_overheat_event_reported = 133;
+        NfcErrorOccurred nfc_error_occurred = 134;
+        NfcStateChanged nfc_state_changed = 135;
+        NfcBeamOccurred nfc_beam_occurred = 136;
+        NfcCardemulationOccurred nfc_cardemulation_occurred = 137;
+        NfcTagOccurred nfc_tag_occurred = 138;
+        NfcHceTransactionOccurred nfc_hce_transaction_occurred = 139;
+        SeStateChanged se_state_changed = 140;
+        SeOmapiReported se_omapi_reported = 141;
+        BroadcastDispatchLatencyReported broadcast_dispatch_latency_reported = 142;
+        AttentionManagerServiceResultReported attention_manager_service_result_reported = 143;
+        AdbConnectionChanged adb_connection_changed = 144;
+        SpeechDspStatReported speech_dsp_stat_reported = 145;
     }
 
     // Pulled events will start at field 10000.
@@ -212,7 +246,7 @@
         NumFingerprints num_fingerprints = 10031;
         DiskIo disk_io = 10032;
         PowerProfile power_profile = 10033;
-        ProcStats proc_stats_pkg_proc = 10034;
+        ProcStatsPkgProc proc_stats_pkg_proc = 10034;
         ProcessCpuTime process_cpu_time = 10035;
         NativeProcessMemoryState native_process_memory_state = 10036;
         CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037;
@@ -223,6 +257,7 @@
         ProcessMemoryHighWaterMark process_memory_high_water_mark = 10042;
         BatteryLevel battery_level = 10043;
         BuildInformation build_information = 10044;
+        BatteryCycleCount battery_cycle_count = 10045;
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP.
@@ -1288,10 +1323,12 @@
 }
 
 /**
- * Logs when a Bluetooth device connects and disconnects.
+ * Logs when profiles on a Bluetooth device connects and disconnects.
  *
  * Logged from:
- *    packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java
+ *    packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java
+ *
+ * Next Tag: 5
  */
 message BluetoothConnectionStateChanged {
     // The state of the connection.
@@ -1300,13 +1337,152 @@
     // An identifier that can be used to match connect and disconnect events.
     // Currently is last two bytes of a hash of a device level ID and
     // the mac address of the bluetooth device that is connected.
-    optional int32 obfuscated_id = 2;
+    // Deprecated: use obfuscated_id instead, this one is always 0 for Q+
+    optional int32 OBSOLETE_obfuscated_id = 2 [deprecated = true];
     // The profile that is connected. Eg. GATT, A2DP, HEADSET.
     // From android.bluetooth.BluetoothAdapter.java
+    // Default: 0 when not used
     optional int32 bt_profile = 3;
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 4 [(android.os.statsd.log_mode) = MODE_BYTES];
 }
 
 /**
+ * Logs when a Bluetooth device connects and disconnects over ACL
+ *
+ * Logged from:
+ *    packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java
+ *
+ * Next Tag: 3
+ */
+message BluetoothAclConnectionStateChanged {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // The state of the connection.
+    // Eg: CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED.
+    optional android.bluetooth.ConnectionStateEnum state = 2;
+}
+
+/**
+ * Logs when a Bluetooth device connects and disconnects over SCO
+ *
+ * Logged from:
+ *    packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+ *    packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetClientStateMachine.java
+ *
+ * Next Tag: 4
+ */
+message BluetoothScoConnectionStateChanged {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // The state of the connection.
+    // Eg: CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED.
+    optional android.bluetooth.ConnectionStateEnum state = 2;
+    // Codec used for this SCO connection
+    // Default: UNKNOWN
+    optional android.bluetooth.hfp.ScoCodec codec = 3;
+}
+
+// Logs when there is an event affecting Bluetooth device's link layer connection.
+// - This event is triggered when there is a related HCI command or event
+// - Users of this metrics can deduce Bluetooth device's connection state from these events
+// - HCI commands are logged before the command is sent, after receiving command status, and after
+//   receiving command complete
+// - HCI events are logged when they arrive
+//
+// Low level log from system/bt
+//
+// Bluetooth classic commands:
+// - CMD_CREATE_CONNECTION
+// - CMD_DISCONNECT
+// - CMD_CREATE_CONNECTION_CANCEL
+// - CMD_ACCEPT_CONNECTION_REQUEST
+// - CMD_REJECT_CONNECTION_REQUEST
+// - CMD_SETUP_ESCO_CONNECTION
+// - CMD_ACCEPT_ESCO_CONNECTION
+// - CMD_REJECT_ESCO_CONNECTION
+// - CMD_ENH_SETUP_ESCO_CONNECTION
+// - CMD_ENH_ACCEPT_ESCO_CONNECTION
+//
+// Bluetooth low energy commands:
+// - CMD_BLE_CREATE_LL_CONN [Only logged on error or when initiator filter policy is 0x00]
+// - CMD_BLE_CREATE_CONN_CANCEL [Only logged when there is an error]
+// - CMD_BLE_EXTENDED_CREATE_CONNECTION [Only logged on error or when initiator filter policy is 0x00]
+// - CMD_BLE_CLEAR_WHITE_LIST
+// - CMD_BLE_ADD_WHITE_LIST
+// - CMD_BLE_REMOVE_WHITE_LIST
+//
+// Bluetooth classic events:
+// - EVT_CONNECTION_COMP
+// - EVT_CONNECTION_REQUEST
+// - EVT_DISCONNECTION_COMP
+// - EVT_ESCO_CONNECTION_COMP
+// - EVT_ESCO_CONNECTION_CHANGED
+//
+// Bluetooth low energy meta events:
+// - BLE_EVT_CONN_COMPLETE_EVT
+// - BLE_EVT_ENHANCED_CONN_COMPLETE_EVT
+//
+// Next tag: 10
+message BluetoothLinkLayerConnectionEvent {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Connection handle of this connection if available
+    // Range: 0x0000 - 0x0EFF (12 bits)
+    // Default: 0xFFFF if the handle is unknown
+    optional int32 connection_handle = 2;
+    // Direction of the link
+    // Default: DIRECTION_UNKNOWN
+    optional android.bluetooth.DirectionEnum direction = 3;
+    // Type of this link
+    // Default: LINK_TYPE_UNKNOWN
+    optional android.bluetooth.LinkTypeEnum type = 4;
+
+    // Reason metadata for this link layer connection event, rules for interpretation:
+    // 1. If hci_cmd is set and valid, hci_event can be either EVT_COMMAND_STATUS or
+    //    EVT_COMMAND_COMPLETE, ignore hci_ble_event in this case
+    // 2. If hci_event is set to EVT_BLE_META, look at hci_ble_event; otherwise, if hci_event is
+    //    set and valid, ignore hci_ble_event
+
+    // HCI command associated with this event
+    // Default: CMD_UNKNOWN
+    optional android.bluetooth.hci.CommandEnum hci_cmd = 5;
+    // HCI event associated with this event
+    // Default: EVT_UNKNOWN
+    optional android.bluetooth.hci.EventEnum hci_event = 6;
+    // HCI BLE meta event associated with this event
+    // Default: BLE_EVT_UNKNOWN
+    optional android.bluetooth.hci.BleMetaEventEnum hci_ble_event = 7;
+    // HCI command status code if this is triggerred by hci_cmd
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum cmd_status = 8;
+    // HCI reason code associated with this event
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum reason_code = 9;
+}
+
+
+/**
  * Logs when something is plugged into or removed from the USB-C connector.
  *
  * Logged from:
@@ -1574,6 +1750,33 @@
 }
 
 /**
+ * Logs basic timing information about touch events.
+ * Reported at most every 5 minutes while device is being interacted with.
+ *
+ * Logged from:
+ *   frameworks/native/services/inputflinger
+ */
+message TouchEventReported {
+    /**
+     * The fields latency_{min|max|mean|stdev} represent minimum, maximum, mean,
+     * and the standard deviation of latency between the kernel and framework
+     * for touchscreen events. The units are microseconds.
+     *
+     * The number is measured as the difference between the time at which
+     * the input event was received in the evdev driver,
+     * and the time at which the input event was received in EventHub.
+     */
+    // Minimum value
+    optional float latency_min_micros = 1;
+    // Maximum value
+    optional float latency_max_micros = 2;
+    // Average value
+    optional float latency_mean_micros = 3;
+    // Standard deviation
+    optional float latency_stdev_micros = 4;
+}
+
+/**
  * Logs that a setting was updated.
  * Logged from:
  *   frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -1631,6 +1834,47 @@
 }
 
 /**
+ * Logs when a volume entered low Storage state.
+ * Logged from:
+ *      frameworks/base/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+ */
+message LowStorageStateChanged {
+    // Volume that ran out of storage.
+    optional string volume_description = 1;
+
+    enum State {
+        UNKNOWN = 0;
+        OFF = 1;
+        ON = 2;
+    }
+    optional State state = 2;
+}
+
+/**
+ * Logs when an app is downgraded.
+ * Logged from:
+ *      frameworks/base/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+ */
+message AppDowngraded {
+    optional string package_name = 1;
+    // Size of the package (all data) before being downgraded.
+    optional int64 size_in_bytes_before = 2;
+    // Size of the package (all data) after being downgraded.
+    optional int64 size_in_bytes_after = 3;
+
+    optional bool aggressive = 4;
+}
+
+/**
+ * Logs when an app is optimized after being downgraded.
+ * Logged from:
+ *      frameworks/base/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+ */
+message AppOptimizedAfterDowngraded {
+    optional string package_name = 1;
+}
+
+/**
  * Logs when an app crashes.
  * Logged from:
  *      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2266,6 +2510,37 @@
     optional State state = 3;
 }
 
+/** Represents USB port overheat event. */
+message UsbPortOverheatEvent {
+    /* Temperature of USB port at USB plug event, in 1/10ths of degree C. */
+    optional int32 plug_temperature_deci_c = 1;
+
+    /* Maximum temperature of USB port during overheat event, in 1/10ths of degree C. */
+    optional int32 max_temperature_deci_c = 2;
+
+    /* Time between USB plug event and overheat threshold trip, in seconds. */
+    optional int32 time_to_overheat_secs = 3;
+
+    /* Time between overheat threshold trip and hysteresis, in seconds. */
+    optional int32 time_to_hysteresis_secs = 4;
+
+    /* Time between hysteresis and active mitigation ending, in seconds. */
+    optional int32 time_to_inactive_secs = 5;
+};
+
+/**
+ * Logs total effective full charge and discharge cycles on a battery.
+ * Here are some examples of one effective cycle:
+ *   1) the battery charges from 0% to 100% and drains back to 0%,
+ *   2) charging from 50% to 100% and draining back to 50% twice.
+ * Pulled from:
+ *   frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
+ */
+message BatteryCycleCount {
+    /* Number of total charge and discharge cycles on the system battery. */
+    optional int32 cycle_count = 1;
+}
+
 /*
  * Logs when a connection becomes available and lost.
  * Logged in StatsCompanionService.java
@@ -2744,8 +3019,8 @@
 
 /**
  * Pulls battery coulomb counter, which is the remaining battery charge in uAh.
- * Pulled from:
- *   frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
+ *
+ * Pulled from StatsCompanionService.java
  */
 message RemainingBatteryCapacity {
     optional int32 charge_micro_ampere_hour = 1;
@@ -2789,13 +3064,14 @@
  *   frameworks/base/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
  */
 message Temperature {
-    // The type of temperature being reported. Eg. CPU, GPU, SKIN, BATTERY.
+    // The type of temperature being reported. Eg. CPU, GPU, SKIN, BATTERY, BCL_.
     optional android.os.TemperatureTypeEnum sensor_location = 1;
 
     // The name of the temperature source. Eg. CPU0
     optional string sensor_name = 2;
 
     // Temperature in tenths of a degree C.
+    // For BCL, it is decimillivolt, decimilliamps, and percentage * 10.
     optional int32 temperature_deci_celsius = 3;
 }
 
@@ -3174,7 +3450,8 @@
     optional int32 process_uid = 1;
     // Process name.
     optional string process_name = 2;
-
+    // Package name.
+    optional string package_name = 7;
     // Total count of the times this association appeared.
     optional int32 total_count = 3;
 
@@ -3253,6 +3530,9 @@
     }
     repeated Status status = 7;
 
+    // Number of pages available of various types and sizes, representation fragmentation.
+    repeated ProcessStatsAvailablePagesProto available_pages = 10;
+
     // Stats for each process.
     repeated ProcessStatsProto process_stats = 8;
 
@@ -3260,6 +3540,21 @@
     repeated ProcessStatsPackageProto package_stats = 9;
 }
 
+message ProcessStatsAvailablePagesProto {
+    // Node these pages are in (as per /proc/pagetypeinfo)
+    optional int32 node = 1;
+
+    // Zone these pages are in (as per /proc/pagetypeinfo)
+    optional string zone = 2;
+
+    // Label for the type of these pages (as per /proc/pagetypeinfo)
+    optional string label = 3;
+
+    // Distribution of number of pages available by order size.  First entry in array is
+    // order 0, second is order 1, etc.  Each order increase is a doubling of page size.
+    repeated int32 pages_per_order = 4;
+}
+
 /**
  * Pulled from ProcessStatsService.java
  */
@@ -3267,6 +3562,13 @@
     optional ProcessStatsSectionProto proc_stats_section = 1;
 }
 
+/**
+ * Pulled from ProcessStatsService.java
+ */
+message ProcStatsPkgProc {
+    optional ProcessStatsSectionProto proc_stats_section = 1;
+}
+
 message PowerProfileProto {
     optional double cpu_suspend = 1;
 
@@ -3655,6 +3957,52 @@
 }
 
 /**
+ * Logs the package name that launches docsui picker mode.
+ *
+ * Logged from:
+ *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
+ */
+message DocsUIPickerLaunchedFromReported {
+    optional string package_name = 1;
+}
+
+/**
+ * Logs the search type.
+ *
+ * Logged from:
+ *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
+ */
+message DocsUISearchTypeReported {
+    optional android.stats.docsui.SearchType search_type = 1;
+}
+
+/**
+ * Logs the search mode.
+ *
+ * Logged from:
+ *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
+ */
+message DocsUISearchModeReported {
+    optional android.stats.docsui.SearchMode search_mode = 1;
+}
+
+/**
+ * Logs the pick result information.
+ *
+ * Logged from:
+ *     package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
+ */
+message DocsUIPickResultReported {
+    optional int32 total_action_count = 1;
+    optional int64 duration_millis = 2;
+    optional int32 file_count= 3;
+    optional bool is_searching = 4;
+    optional android.stats.docsui.Root picked_from = 5;
+    optional android.stats.docsui.MimeType mime_type = 6;
+    optional int32 repeatedly_pick_times = 7;
+}
+
+/**
  * Logs when an app's memory is compacted.
  *
  * Logged from:
@@ -3740,7 +4088,7 @@
     //bionic/libc/include/netdb.h
     //system/netd/resolv/include/netd_resolv/resolv.h
     enum ReturnCode {
-        EAI_NOERR = 0;
+        EAI_NO_ERROR = 0;
         EAI_ADDRFAMILY = 1;
         EAI_AGAIN = 2;
         EAI_BADFLAGS = 3;
@@ -3763,3 +4111,429 @@
     // The latency period(in microseconds) it took for this DNS lookup to complete.
     optional int32 latency_micros = 3;
 }
+
+/**
+ * Logs when a data stall event occurs.
+ *
+ * Log from:
+ *     frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+ */
+message DataStallEvent {
+    // Data stall evaluation type.
+    // See frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+    // Refer to the definition of DATA_STALL_EVALUATION_TYPE_*.
+    optional int32 evaluation_type = 1;
+    // See definition in data_stall_event.proto.
+    optional com.android.server.connectivity.ProbeResult validation_result = 2;
+    // See definition in data_stall_event.proto.
+    optional android.net.NetworkCapabilitiesProto.Transport network_type = 3;
+    // See definition in data_stall_event.proto.
+    optional com.android.server.connectivity.WifiData wifi_info = 4 [(log_mode) = MODE_BYTES];
+    // See definition in data_stall_event.proto.
+    optional com.android.server.connectivity.CellularData cell_info = 5 [(log_mode) = MODE_BYTES];
+    // See definition in data_stall_event.proto.
+    optional com.android.server.connectivity.DnsEvent dns_event = 6 [(log_mode) = MODE_BYTES];
+}
+
+/*
+ * Logs when RescueParty resets some set of experiment flags.
+ *
+ * Logged from:
+ *     frameworks/base/services/core/java/com/android/server/RescueParty.java
+ */
+message RescuePartyResetReported {
+    // The rescue level of this reset. A value of 0 indicates missing or unknown level information.
+    optional int32 rescue_level = 1;
+}
+
+/**
+ * Logs when signed config is received from an APK, and if that config was applied successfully.
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/signedconfig/SignedConfigService.java
+ */
+message SignedConfigReported {
+    enum Type {
+        UNKNOWN_TYPE = 0;
+        GLOBAL_SETTINGS = 1;
+    }
+    optional Type type = 1;
+
+    // The final status of the signed config received.
+    enum Status {
+        UNKNOWN_STATUS = 0;
+        APPLIED = 1;
+        BASE64_FAILURE_CONFIG = 2;
+        BASE64_FAILURE_SIGNATURE = 3;
+        SECURITY_EXCEPTION = 4;
+        INVALID_CONFIG = 5;
+        OLD_CONFIG = 6;
+        SIGNATURE_CHECK_FAILED = 7;
+        NOT_APPLICABLE = 8;
+        SIGNATURE_CHECK_FAILED_PROD_KEY_ABSENT = 9;
+    }
+    optional Status status = 2;
+
+    // The version of the signed config processed.
+    optional int32 version = 3;
+
+    // The package name that the config was extracted from.
+    optional string from_package = 4;
+
+    enum Key {
+        NO_KEY = 0;
+        DEBUG = 1;
+        PRODUCTION = 2;
+    }
+    // Which key was used to verify the config.
+    optional Key verified_with = 5;
+}
+
+/*
+ * Logs GNSS Network-Initiated (NI) location events.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/location/GnssLocationProvider.java
+ */
+message GnssNiEventReported {
+    // The type of GnssNiEvent.
+    enum EventType {
+        UNKNOWN = 0;
+        NI_REQUEST = 1;
+        NI_RESPONSE = 2;
+    }
+    optional EventType event_type = 1;
+
+    // An ID generated by HAL to associate NI notifications and UI responses.
+    optional int32 notification_id = 2;
+
+    // A type which distinguishes different categories of NI request, such as VOICE, UMTS_SUPL etc.
+    optional android.server.location.GnssNiType ni_type = 3;
+
+    // NI requires notification.
+    optional bool need_notify = 4;
+
+    // NI requires verification.
+    optional bool need_verify = 5;
+
+    // NI requires privacy override, no notification/minimal trace.
+    optional bool privacy_override = 6;
+
+    // Timeout period to wait for user response. Set to 0 for no timeout limit. Specified in
+    // seconds.
+    optional int32 timeout = 7;
+
+    // Default response when timeout.
+    optional android.server.location.GnssUserResponseType default_response = 8;
+
+    // String representing the requester of the network inititated location request.
+    optional string requestor_id = 9;
+
+    // Notification message text string representing the service(for eg. SUPL-service) who sent the
+    // network initiated location request.
+    optional string text = 10;
+
+    // requestorId decoding scheme.
+    optional android.server.location.GnssNiEncodingType requestor_id_encoding = 11;
+
+    // Notification message text decoding scheme.
+    optional android.server.location.GnssNiEncodingType text_encoding = 12;
+
+    // True if SUPL ES is enabled.
+    optional bool is_supl_es_enabled = 13;
+
+    // True if GNSS location is enabled.
+    optional bool is_location_enabled = 14;
+
+    // GNSS NI responses which define the response in NI structures.
+    optional android.server.location.GnssUserResponseType user_response = 15;
+}
+
+/**
+ * Logs GNSS non-framework (NFW) location notification.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/location/GnssLocationProvider.java
+ */
+message GnssNfwNotificationReported {
+    // Package name of the Android proxy application representing the non-framework entity that
+    // requested location. Set to empty string if unknown.
+    optional string proxy_app_package_name = 1;
+
+    // Protocol stack that initiated the non-framework location request.
+    optional android.server.location.NfwProtocolStack protocol_stack = 2;
+
+    // Name of the protocol stack if protocol_stack field is set to OTHER_PROTOCOL_STACK. Otherwise,
+    // set to empty string. This field is opaque to the framework and used for logging purposes.
+    optional string other_protocol_stack_name = 3;
+
+    // Source initiating/receiving the location information.
+    optional android.server.location.NfwRequestor requestor = 4;
+
+    // Identity of the endpoint receiving the location information. For example, carrier name, OEM
+    // name, SUPL SLP/E-SLP FQDN, chipset vendor name, etc. This field is opaque to the framework
+    // and used for logging purposes.
+    optional string requestor_id = 5;
+
+    // Indicates whether location information was provided for this request.
+    optional android.server.location.NfwResponseType response_type = 6;
+
+    // True if the device is in user initiated emergency session.
+    optional bool in_emergency_mode = 7;
+
+    // True if cached location is provided.
+    optional bool is_cached_location = 8;
+
+    // True if proxy app permission mismatch between framework and GNSS HAL.
+    optional bool is_permission_mismatched = 9;
+}
+
+/**
+ * Logs GNSS configuration as defined in IGnssConfiguration.hal.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/location/GnssConfiguration.java
+ */
+message GnssConfigurationReported {
+    // SUPL host name.
+    optional string supl_host = 1;
+
+    // SUPL port number.
+    optional int32 supl_port = 2;
+
+    // C2K host name.
+    optional string c2k_host = 3;
+
+    // C2K port number.
+    optional int32 c2k_port = 4;
+
+    // The SUPL version requested by Carrier.
+    optional int32 supl_ver = 5;
+
+    // The SUPL mode.
+    optional android.server.location.SuplMode supl_mode = 6;
+
+    // True if NI emergency SUPL restrictions is enabled.
+    optional bool supl_es = 7;
+
+    // LTE Positioning Profile settings
+    optional android.server.location.LppProfile lpp_profile = 8;
+
+    // Positioning protocol on A-Glonass system.
+    optional android.server.location.GlonassPosProtocol a_glonass_pos_protocol_select = 9;
+
+    // True if emergency PDN is used. Otherwise, regular PDN is used.
+    optional bool use_emergency_pdn_for_emergency_supl= 10;
+
+    // Configurations of how GPS functionalities should be locked when user turns off GPS On setting.
+    optional android.server.location.GpsLock gps_lock = 11;
+
+    // Number of seconds to extend the emergency session duration post emergency call.
+    optional int32 es_extension_sec = 12;
+
+    // The full list of package names of proxy Android applications representing the non-framework
+    // location access entities (on/off the device) for which the framework user has granted
+    // non-framework location access permission. The package names are concatenated in one string
+    // with spaces as separators.
+    optional string enabled_proxy_app_package_name_list = 13;
+}
+
+/**
+ * Logs when a NFC device's error occurred.
+ * Logged from:
+ *     system/nfc/src/nfc/nfc/nfc_ncif.cc
+ *     packages/apps/Nfc/src/com/android/nfc/cardemulation/AidRoutingManager.java
+ */
+message NfcErrorOccurred {
+  enum Type {
+    UNKNOWN = 0;
+    CMD_TIMEOUT = 1;
+    ERROR_NOTIFICATION = 2;
+    AID_OVERFLOW = 3;
+  }
+  optional Type type = 1;
+  // If it's nci cmd timeout, log the timeout command.
+  optional uint32 nci_cmd = 2;
+
+  optional uint32 error_ntf_status_code = 3;
+}
+
+/**
+ * Logs when a NFC device's state changed event
+ * Logged from:
+ *     packages/apps/Nfc/src/com/android/nfc/NfcService.java
+ */
+message NfcStateChanged {
+  enum State {
+    UNKNOWN = 0;
+    OFF = 1;
+    ON = 2;
+    ON_LOCKED = 3; // Secure Nfc enabled.
+    CRASH_RESTART = 4; // NfcService watchdog timeout restart.
+  }
+  optional State state = 1;
+}
+
+/**
+ * Logs when a NFC Beam Transaction occurred.
+ * Logged from:
+ *     packages/apps/Nfc/src/com/android/nfc/P2pLinkManager.java
+ */
+message NfcBeamOccurred {
+  enum Operation {
+      UNKNOWN = 0;
+      SEND = 1;
+      RECEIVE = 2;
+  }
+  optional Operation operation = 1;
+}
+
+/**
+ * Logs when a NFC Card Emulation Transaction occurred.
+ * Logged from:
+ *     packages/apps/Nfc/src/com/android/nfc/cardemulation/HostEmulationManager.java
+ *     packages/apps/Nfc/src/com/android/nfc/cardemulation/HostNfcFEmulationManager.java
+ */
+message NfcCardemulationOccurred {
+  enum Category {
+      UNKNOWN = 0;
+      HCE_PAYMENT = 1;
+      HCE_OTHER = 2;
+      OFFHOST = 3;
+  }
+  // Transaction belongs to HCE payment or HCE other category, or offhost.
+  optional Category category = 1;
+  // SeName from transaction: SIMx, eSEx, HCE, HCEF.
+  optional string se_name = 2;
+}
+
+/**
+ * Logs when a NFC Tag event occurred.
+ * Logged from:
+ *     packages/apps/Nfc/src/com/android/nfc/NfcDispatcher.java
+ */
+message NfcTagOccurred {
+  enum Type {
+      UNKNOWN = 0;
+      URL = 1;
+      BT_PAIRING = 2;
+      PROVISION = 3;
+      WIFI_CONNECT = 4;
+      APP_LAUNCH = 5;
+      OTHERS = 6;
+  }
+  optional Type type = 1;
+}
+
+/**
+ * Logs when Hce transaction triggered
+ * Logged from:
+ *     system/nfc/src/nfc/nfc/nfc_ncif.cc
+ */
+message NfcHceTransactionOccurred {
+    // The latency period(in microseconds) it took for the first HCE data
+    // exchange.
+    optional uint32 latency_micros = 1;
+}
+
+/**
+ * Logs when SecureElement state event changed
+ * Logged from:
+ *     packages/apps/SecureElement/src/com/android/se/Terminal.java
+ */
+message SeStateChanged {
+  enum State {
+    UNKNOWN = 0;
+    INITIALIZED = 1;
+    DISCONNECTED = 2;
+    CONNECTED = 3;
+    HALCRASH = 4;
+  }
+  optional State state = 1;
+
+  optional string state_change_reason = 2;
+  // SIMx or eSEx.
+  optional string terminal = 3;
+}
+
+/**
+ * Logs when Omapi API used
+ * Logged from:
+ *     packages/apps/SecureElement/src/com/android/se/Terminal.java
+ */
+message SeOmapiReported {
+  enum Operation {
+    UNKNOWN = 0;
+    OPEN_CHANNEL = 1;
+  }
+  optional Operation operation = 1;
+  // SIMx or eSEx.
+  optional string terminal = 2;
+
+  optional string package_name = 3;
+}
+
+/**
+  * Logs the dispatch latency of a broadcast during processing of BOOT_COMPLETED.
+  * The dispatch latency is the dispatchClockTime - enqueueClockTime.
+  * Logged from:
+  *   frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
+  */
+message BroadcastDispatchLatencyReported {
+    optional int64 dispatch_latency_millis = 1;
+}
+
+/**
+   * Logs AttentionManagerService attention check result.
+   *
+   * Logged from:
+   *   frameworks/base/services/core/java/com/android/server/attention/AttentionManagerService.java
+   */
+message AttentionManagerServiceResultReported {
+    // See core/java/android/service/attention/AttentionService.java
+    enum AttentionCheckResult {
+        UNKNOWN = 20;
+        ATTENTION_SUCCESS_ABSENT = 0;
+        ATTENTION_SUCCESS_PRESENT = 1;
+        ATTENTION_FAILURE_PREEMPTED = 2;
+        ATTENTION_FAILURE_TIMED_OUT = 3;
+        ATTENTION_FAILURE_UNKNOWN = 4;
+    }
+    optional AttentionCheckResult attention_check_result = 1 [default = UNKNOWN];
+}
+
+/**
+ * Logs when an adb connection changes state.
+ *
+ * Logged from:
+ *     frameworks/base/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+ */
+message AdbConnectionChanged {
+    // The last time this system connected via adb, or 0 if the 'always allow' option was not
+    // previously selected for this system.
+    optional int64 last_connection_time_millis = 1;
+
+    // The time in ms within which a subsequent connection from an 'always allow' system is allowed
+    // to reconnect via adb without user interaction.
+    optional int64 auth_window_millis = 2;
+
+    // The state of the adb connection from frameworks/base/core/proto/android/debug/enums.proto.
+    optional android.debug.AdbConnectionStateEnum state = 3;
+
+    // True if the 'always allow' option was selected for this system.
+    optional bool always_allow = 4;
+}
+
+/*
+ * Logs the reported speech DSP status.
+ *
+ * Logged from:
+ *  Vendor audio implementation.
+ */
+message SpeechDspStatReported {
+    // The total Speech DSP uptime in milliseconds.
+    optional int32 total_uptime_millis = 1;
+    // The total Speech DSP downtime in milliseconds.
+    optional int32 total_downtime_millis = 2;
+    optional int32 total_crash_count = 3;
+    optional int32 total_recover_count = 4;
+}
diff --git a/cmds/statsd/src/external/Perfetto.cpp b/cmds/statsd/src/external/Perfetto.cpp
index 42cc543..0c4c330 100644
--- a/cmds/statsd/src/external/Perfetto.cpp
+++ b/cmds/statsd/src/external/Perfetto.cpp
@@ -39,6 +39,7 @@
 namespace statsd {
 
 bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config,
+                                            int64_t subscription_id,
                                             int64_t alert_id,
                                             const ConfigKey& configKey) {
     VLOG("Starting trace collection through perfetto");
@@ -48,9 +49,11 @@
         return false;
     }
 
-    char alertId[20];
-    char configId[20];
-    char configUid[20];
+    char subscriptionId[25];
+    char alertId[25];
+    char configId[25];
+    char configUid[25];
+    snprintf(subscriptionId, sizeof(subscriptionId), "%" PRId64, subscription_id);
     snprintf(alertId, sizeof(alertId), "%" PRId64, alert_id);
     snprintf(configId, sizeof(configId), "%" PRId64, configKey.GetId());
     snprintf(configUid, sizeof(configUid), "%d", configKey.GetUid());
@@ -94,7 +97,7 @@
 
         execl("/system/bin/perfetto", "perfetto", "--background", "--config", "-", "--dropbox",
               kDropboxTag, "--alert-id", alertId, "--config-id", configId, "--config-uid",
-              configUid, nullptr);
+              configUid, "--subscription-id", subscriptionId, nullptr);
 
         // execl() doesn't return in case of success, if we get here something
         // failed.
diff --git a/cmds/statsd/src/external/Perfetto.h b/cmds/statsd/src/external/Perfetto.h
index 1e7f728..ab2c195 100644
--- a/cmds/statsd/src/external/Perfetto.h
+++ b/cmds/statsd/src/external/Perfetto.h
@@ -32,6 +32,7 @@
 // This method returns immediately after passing the config and does NOT wait
 // for the full duration of the trace.
 bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config,
+                                            int64_t subscription_id,
                                             int64_t alert_id,
                                             const ConfigKey& configKey);
 
diff --git a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
index b878652..75b63f4 100644
--- a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
+++ b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp
@@ -24,16 +24,16 @@
 
 #include "ResourceHealthManagerPuller.h"
 #include "logd/LogEvent.h"
-#include "statslog.h"
 #include "stats_log_util.h"
+#include "statslog.h"
 
 using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
 using android::hardware::health::V2_0::get_health_service;
 using android::hardware::health::V2_0::HealthInfo;
 using android::hardware::health::V2_0::IHealth;
 using android::hardware::health::V2_0::Result;
-using android::hardware::Return;
-using android::hardware::Void;
 
 using std::make_shared;
 using std::shared_ptr;
@@ -75,35 +75,41 @@
         }
         if (mTagId == android::util::REMAINING_BATTERY_CAPACITY) {
             auto ptr = make_shared<LogEvent>(android::util::REMAINING_BATTERY_CAPACITY,
-                wallClockTimestampNs, elapsedTimestampNs);
+                                             wallClockTimestampNs, elapsedTimestampNs);
             ptr->write(v.legacy.batteryChargeCounter);
             ptr->init();
             data->push_back(ptr);
         } else if (mTagId == android::util::FULL_BATTERY_CAPACITY) {
             auto ptr = make_shared<LogEvent>(android::util::FULL_BATTERY_CAPACITY,
-                wallClockTimestampNs, elapsedTimestampNs);
+                                             wallClockTimestampNs, elapsedTimestampNs);
             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);
+            auto ptr = make_shared<LogEvent>(android::util::BATTERY_VOLTAGE, wallClockTimestampNs,
+                                             elapsedTimestampNs);
             ptr->write(v.legacy.batteryVoltage);
             ptr->init();
             data->push_back(ptr);
         } else if (mTagId == android::util::BATTERY_LEVEL) {
-                     auto ptr = make_shared<LogEvent>(android::util::BATTERY_LEVEL,
-                         wallClockTimestampNs, elapsedTimestampNs);
-                     ptr->write(v.legacy.batteryLevel);
-                     ptr->init();
-                     data->push_back(ptr);
+            auto ptr = make_shared<LogEvent>(android::util::BATTERY_LEVEL, wallClockTimestampNs,
+                                             elapsedTimestampNs);
+            ptr->write(v.legacy.batteryLevel);
+            ptr->init();
+            data->push_back(ptr);
+        } else if (mTagId == android::util::BATTERY_CYCLE_COUNT) {
+            auto ptr = make_shared<LogEvent>(android::util::BATTERY_CYCLE_COUNT,
+                                             wallClockTimestampNs, elapsedTimestampNs);
+            ptr->write(v.legacy.batteryCycleCount);
+            ptr->init();
+            data->push_back(ptr);
         } else {
             ALOGE("Unsupported tag in ResourceHealthManagerPuller: %d", mTagId);
         }
     });
     if (!result_success || !ret.isOk()) {
         ALOGE("getHealthHal() failed: health HAL service not available. Description: %s",
-                ret.description().c_str());
+              ret.description().c_str());
         if (!ret.isOk() && ret.isDeadObject()) {
             gHealthHal = nullptr;
         }
diff --git a/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp b/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
deleted file mode 100644
index 33a17de..0000000
--- a/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
+++ /dev/null
@@ -1,146 +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.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include <android/hardware/thermal/1.0/IThermal.h>
-#include "external/ResourceThermalManagerPuller.h"
-#include "external/StatsPuller.h"
-
-#include "ResourceThermalManagerPuller.h"
-#include "logd/LogEvent.h"
-#include "statslog.h"
-#include "stats_log_util.h"
-
-#include <chrono>
-
-using android::hardware::hidl_death_recipient;
-using android::hardware::hidl_vec;
-using android::hidl::base::V1_0::IBase;
-using android::hardware::thermal::V1_0::IThermal;
-using android::hardware::thermal::V1_0::Temperature;
-using android::hardware::thermal::V1_0::ThermalStatus;
-using android::hardware::thermal::V1_0::ThermalStatusCode;
-using android::hardware::Return;
-using android::hardware::Void;
-
-using std::chrono::duration_cast;
-using std::chrono::nanoseconds;
-using std::chrono::system_clock;
-using std::make_shared;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-bool getThermalHalLocked();
-sp<android::hardware::thermal::V1_0::IThermal> gThermalHal = nullptr;
-std::mutex gThermalHalMutex;
-
-struct ThermalHalDeathRecipient : virtual public hidl_death_recipient {
-      virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override {
-          std::lock_guard<std::mutex> lock(gThermalHalMutex);
-          ALOGE("ThermalHAL just died");
-          gThermalHal = nullptr;
-          getThermalHalLocked();
-      }
-};
-
-sp<ThermalHalDeathRecipient> gThermalHalDeathRecipient = nullptr;
-
-// The caller must be holding gThermalHalMutex.
-bool getThermalHalLocked() {
-    if (gThermalHal == nullptr) {
-            gThermalHal = IThermal::getService();
-            if (gThermalHal == nullptr) {
-                ALOGE("Unable to get Thermal service.");
-            } else {
-                if (gThermalHalDeathRecipient == nullptr) {
-                    gThermalHalDeathRecipient = new ThermalHalDeathRecipient();
-                }
-                hardware::Return<bool> linked = gThermalHal->linkToDeath(
-                    gThermalHalDeathRecipient, 0x451F /* cookie */);
-                if (!linked.isOk()) {
-                    ALOGE("Transaction error in linking to ThermalHAL death: %s",
-                            linked.description().c_str());
-                    gThermalHal = nullptr;
-                } else if (!linked) {
-                    ALOGW("Unable to link to ThermalHal death notifications");
-                    gThermalHal = nullptr;
-                } else {
-                    ALOGD("Link to death notification successful");
-                }
-            }
-    }
-    return gThermalHal != nullptr;
-}
-
-ResourceThermalManagerPuller::ResourceThermalManagerPuller() :
-        StatsPuller(android::util::TEMPERATURE) {
-}
-
-bool ResourceThermalManagerPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
-    std::lock_guard<std::mutex> lock(gThermalHalMutex);
-    if (!getThermalHalLocked()) {
-        ALOGE("Thermal Hal not loaded");
-        return false;
-    }
-
-    int64_t wallClockTimestampNs = getWallClockNs();
-    int64_t elapsedTimestampNs = getElapsedRealtimeNs();
-
-    data->clear();
-    bool resultSuccess = true;
-
-    Return<void> ret = gThermalHal->getTemperatures(
-            [&](ThermalStatus status, const hidl_vec<Temperature>& temps) {
-        if (status.code != ThermalStatusCode::SUCCESS) {
-            ALOGE("Failed to get temperatures from ThermalHAL. Status: %d", status.code);
-            resultSuccess = false;
-            return;
-        }
-        if (mTagId == android::util::TEMPERATURE) {
-            for (size_t i = 0; i < temps.size(); ++i) {
-                auto ptr = make_shared<LogEvent>(android::util::TEMPERATURE,
-                        wallClockTimestampNs, elapsedTimestampNs);
-                ptr->write((static_cast<int>(temps[i].type)));
-                ptr->write(temps[i].name);
-                // Convert the temperature to an int.
-                int32_t temp = static_cast<int>(temps[i].currentValue * 10);
-                ptr->write(temp);
-                ptr->init();
-                data->push_back(ptr);
-            }
-        } else {
-            ALOGE("Unsupported tag in ResourceThermalManagerPuller: %d", mTagId);
-        }
-    });
-    if (!ret.isOk()) {
-        ALOGE("getThermalHalLocked() failed: thermal HAL service not available. Description: %s",
-                ret.description().c_str());
-        if (ret.isDeadObject()) {
-            gThermalHal = nullptr;
-        }
-        return false;
-    }
-    return resultSuccess;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/ResourceThermalManagerPuller.h b/cmds/statsd/src/external/ResourceThermalManagerPuller.h
deleted file mode 100644
index 5313792..0000000
--- a/cmds/statsd/src/external/ResourceThermalManagerPuller.h
+++ /dev/null
@@ -1,39 +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.
- */
-
-#pragma once
-
-#include <utils/String16.h>
-#include "StatsPuller.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Reads IThermal.hal
- */
-class ResourceThermalManagerPuller : public StatsPuller {
-public:
-    ResourceThermalManagerPuller();
-
-private:
-    bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 4a716cf..7e56bee 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -28,7 +28,6 @@
 #include "../statscompanion_util.h"
 #include "PowerStatsPuller.h"
 #include "ResourceHealthManagerPuller.h"
-#include "ResourceThermalManagerPuller.h"
 #include "StatsCompanionServicePuller.h"
 #include "StatsPullerManager.h"
 #include "SubsystemSleepStatePuller.h"
@@ -131,9 +130,12 @@
         // battery_voltage
         {android::util::BATTERY_VOLTAGE,
          {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_VOLTAGE)}},
-        // battery_voltage
+        // battery_level
         {android::util::BATTERY_LEVEL,
          {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_LEVEL)}},
+        // battery_cycle_count
+        {android::util::BATTERY_CYCLE_COUNT,
+         {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_CYCLE_COUNT)}},
         // process_memory_state
         {android::util::PROCESS_MEMORY_STATE,
          {.additiveFields = {4, 5, 6, 7, 8, 9},
@@ -147,7 +149,8 @@
           .puller =
                   new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
         // temperature
-        {android::util::TEMPERATURE, {.puller = new ResourceThermalManagerPuller()}},
+        {android::util::TEMPERATURE,
+          {.puller = new StatsCompanionServicePuller(android::util::TEMPERATURE)}},
         // binder_calls
         {android::util::BINDER_CALLS,
          {.additiveFields = {4, 5, 6, 8, 12},
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 2ff8aa1..eaba9be 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -267,6 +267,22 @@
 }
 
 LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+                   const SpeechDspStat& speechDspStat) {
+    mLogdTimestampNs = wallClockTimestampNs;
+    mElapsedTimestampNs = elapsedTimestampNs;
+    mTagId = android::util::SPEECH_DSP_STAT_REPORTED;
+
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)),
+                                 Value(speechDspStat.totalUptimeMillis)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)),
+                                 Value(speechDspStat.totalDowntimeMillis)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)),
+                                 Value(speechDspStat.totalCrashCount)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)),
+                                 Value(speechDspStat.totalRecoverCount)));
+}
+
+LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
                    const BatteryCausedShutdown& batteryCausedShutdown) {
     mLogdTimestampNs = wallClockTimestampNs;
     mElapsedTimestampNs = elapsedTimestampNs;
@@ -276,6 +292,54 @@
                                  Value(batteryCausedShutdown.voltageMicroV)));
 }
 
+LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+                   const UsbPortOverheatEvent& usbPortOverheatEvent) {
+    mLogdTimestampNs = wallClockTimestampNs;
+    mElapsedTimestampNs = elapsedTimestampNs;
+    mTagId = android::util::USB_PORT_OVERHEAT_EVENT_REPORTED;
+
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)),
+                                 Value(usbPortOverheatEvent.plugTemperatureDeciC)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)),
+                                 Value(usbPortOverheatEvent.maxTemperatureDeciC)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)),
+                                 Value(usbPortOverheatEvent.timeToOverheat)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)),
+                                 Value(usbPortOverheatEvent.timeToHysteresis)));
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(5)),
+                                 Value(usbPortOverheatEvent.timeToInactive)));
+}
+
+LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+                   const VendorAtom& vendorAtom) {
+    mLogdTimestampNs = wallClockTimestampNs;
+    mElapsedTimestampNs = elapsedTimestampNs;
+    mTagId = vendorAtom.atomId;
+
+    mValues.push_back(
+            FieldValue(Field(mTagId, getSimpleField(1)), Value(vendorAtom.reverseDomainName)));
+    for (int i = 0; i < (int)vendorAtom.values.size(); i++) {
+        switch (vendorAtom.values[i].getDiscriminator()) {
+            case VendorAtom::Value::hidl_discriminator::intValue:
+                mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 2)),
+                                             Value(vendorAtom.values[i].intValue())));
+                break;
+            case VendorAtom::Value::hidl_discriminator::longValue:
+                mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 2)),
+                                             Value(vendorAtom.values[i].longValue())));
+                break;
+            case VendorAtom::Value::hidl_discriminator::floatValue:
+                mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 2)),
+                                             Value(vendorAtom.values[i].floatValue())));
+                break;
+            case VendorAtom::Value::hidl_discriminator::stringValue:
+                mValues.push_back(FieldValue(Field(mTagId, getSimpleField(i + 2)),
+                                             Value(vendorAtom.values[i].stringValue())));
+                break;
+        }
+    }
+}
+
 LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) : LogEvent(tagId, timestampNs, 0) {}
 
 LogEvent::LogEvent(int32_t tagId, int64_t timestampNs, int32_t uid) {
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 43e6e4f..784376a 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -118,6 +118,15 @@
     explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
                       const BatteryCausedShutdown& batteryCausedShutdown);
 
+    explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+                      const UsbPortOverheatEvent& usbPortOverheatEvent);
+
+    explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+                      const SpeechDspStat& speechDspStat);
+
+    explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
+                      const VendorAtom& vendorAtom);
+
     ~LogEvent();
 
     /**
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 67a1a47..c2878f0 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -93,7 +93,8 @@
                                           StatsdStats::kAtomDimensionKeySizeLimitMap.end()
                                   ? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).second
                                   : StatsdStats::kDimensionKeySizeHardLimit),
-      mGaugeAtomsPerDimensionLimit(metric.max_num_gauge_atoms_per_bucket()) {
+      mGaugeAtomsPerDimensionLimit(metric.max_num_gauge_atoms_per_bucket()),
+      mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()) {
     mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
     mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
     int64_t bucketSizeMills = 0;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index a1a5061..df08779 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -74,6 +74,9 @@
                           const int64_t version) override {
         std::lock_guard<std::mutex> lock(mMutex);
 
+        if (!mSplitBucketForAppUpgrade) {
+            return;
+        }
         if (eventTimeNs > getCurrentBucketEndTimeNs()) {
             // Flush full buckets on the normal path up to the latest bucket boundary.
             flushIfNeededLocked(eventTimeNs);
@@ -176,11 +179,14 @@
 
     const size_t mGaugeAtomsPerDimensionLimit;
 
+    const bool mSplitBucketForAppUpgrade;
+
     FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition);
     FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition);
     FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition);
     FRIEND_TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade);
     FRIEND_TEST(GaugeMetricProducerTest, TestPulledWithUpgrade);
+    FRIEND_TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled);
     FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection);
     FRIEND_TEST(GaugeMetricProducerTest, TestFirstBucket);
     FRIEND_TEST(GaugeMetricProducerTest, TestPullOnTrigger);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 9a8e3bd..4122d84 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -105,7 +105,8 @@
       mUseZeroDefaultBase(metric.use_zero_default_base()),
       mHasGlobalBase(false),
       mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC
-                                                      : StatsdStats::kPullMaxDelayNs) {
+                                                      : StatsdStats::kPullMaxDelayNs),
+      mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()) {
     int64_t bucketSizeMills = 0;
     if (metric.has_bucket()) {
         bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 4865aee..69eb0af 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -57,6 +57,9 @@
     void notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid,
                           const int64_t version) override {
         std::lock_guard<std::mutex> lock(mMutex);
+        if (!mSplitBucketForAppUpgrade) {
+            return;
+        }
         if (mIsPulled && mCondition) {
             pullAndMatchEventsLocked(eventTimeNs - 1);
         }
@@ -185,6 +188,8 @@
 
     const int64_t mMaxPullDelayNs;
 
+    const bool mSplitBucketForAppUpgrade;
+
     FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering);
     FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset);
@@ -193,6 +198,7 @@
     FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade);
     FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade);
     FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse);
+    FRIEND_TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled);
     FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestAnomalyDetection);
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index e9c43cd..5cf012638 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -548,6 +548,7 @@
                                                              {"AID_LMKD", 1069},
                                                              {"AID_LLKD", 1070},
                                                              {"AID_IORAPD", 1071},
+                                                             {"AID_NETWORK_STACK", 1073},
                                                              {"AID_SHELL", 2000},
                                                              {"AID_CACHE", 2001},
                                                              {"AID_DIAG", 2002}};
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
index 22883f3..52d5ffc 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.cpp
+++ b/cmds/statsd/src/shell/ShellSubscriber.cpp
@@ -30,7 +30,8 @@
 
 const static int FIELD_ID_ATOM = 1;
 
-void ShellSubscriber::startNewSubscription(int in, int out, sp<IResultReceiver> resultReceiver) {
+void ShellSubscriber::startNewSubscription(int in, int out, sp<IResultReceiver> resultReceiver,
+                                           int timeoutSec) {
     VLOG("start new shell subscription");
     {
         std::lock_guard<std::mutex> lock(mMutex);
@@ -50,11 +51,18 @@
     // Read config forever until EOF is reached. Clients may send multiple configs -- each new
     // config replace the previous one.
     readConfig(in);
+    VLOG("timeout : %d", timeoutSec);
 
     // Now we have read an EOF we now wait for the semaphore until the client exits.
     VLOG("Now wait for client to exit");
     std::unique_lock<std::mutex> lk(mMutex);
-    mShellDied.wait(lk, [this, resultReceiver] { return mResultReceiver != resultReceiver; });
+
+    if (timeoutSec > 0) {
+        mShellDied.wait_for(lk, timeoutSec * 1s,
+                            [this, resultReceiver] { return mResultReceiver != resultReceiver; });
+    } else {
+        mShellDied.wait(lk, [this, resultReceiver] { return mResultReceiver != resultReceiver; });
+    }
 }
 
 void ShellSubscriber::updateConfig(const ShellSubscription& config) {
diff --git a/cmds/statsd/src/shell/ShellSubscriber.h b/cmds/statsd/src/shell/ShellSubscriber.h
index 5401f31..8e54a8b 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.h
+++ b/cmds/statsd/src/shell/ShellSubscriber.h
@@ -65,7 +65,8 @@
     /**
      * Start a new subscription.
      */
-    void startNewSubscription(int inFd, int outFd, sp<IResultReceiver> resultReceiver);
+    void startNewSubscription(int inFd, int outFd, sp<IResultReceiver> resultReceiver,
+                              int timeoutSec);
 
     void binderDied(const wp<IBinder>& who);
 
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 381ac32..9d3a669 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -244,6 +244,8 @@
   optional int64 max_num_gauge_atoms_per_bucket = 11 [default = 10];
 
   optional int32 max_pull_delay_sec = 13 [default = 10];
+
+  optional bool split_bucket_for_app_upgrade = 14 [default = true];
 }
 
 message ValueMetric {
@@ -290,6 +292,8 @@
   optional bool skip_zero_diff_output = 14 [default = true];
 
   optional int32 max_pull_delay_sec = 16 [default = 10];
+
+  optional bool split_bucket_for_app_upgrade = 17 [default = true];
 }
 
 message Alert {
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 2799107..0ffbb54 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -276,8 +276,9 @@
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
     atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
 
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
     EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
@@ -295,9 +296,8 @@
             }));
 
     GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      logEventMatcherIndex, eventMatcherWizard,
-                                      tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-                                      pullerManager);
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
 
     vector<shared_ptr<LogEvent>> allData;
     shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
@@ -337,6 +337,58 @@
                          ->mValue.int_value);
 }
 
+TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    metric.set_split_bucket_for_app_upgrade(false);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(2);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard,
+                                      tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
+                                      pullerManager);
+
+    vector<shared_ptr<LogEvent>> allData;
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
+    event->write("some value");
+    event->write(1);
+    event->init();
+    allData.push_back(event);
+    gaugeProducer.onDataPulled(allData);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+
+    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(bucketStartTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+}
+
 TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
     GaugeMetric metric;
     metric.set_id(metricId);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 67570fc..9cfe343 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -641,7 +641,8 @@
     valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
     EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
+    EXPECT_EQ(20L,
+              valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -652,7 +653,48 @@
     valueProducer.onDataPulled(allData);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
     EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
+    EXPECT_EQ(20L,
+              valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
+}
+
+TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    metric.set_split_bucket_for_app_upgrade(false);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+    event->write(tagId);
+    event->write(100);
+    event->init();
+    allData.push_back(event);
+
+    valueProducer.onDataPulled(allData);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+
+    valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1);
+    EXPECT_EQ(0UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(bucketStartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
 }
 
 TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) {
diff --git a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
index a184f56..73d1fd7 100644
--- a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
+++ b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
@@ -83,7 +83,7 @@
 
     // mimic a binder thread that a shell subscriber runs on. it would block.
     std::thread reader([&resultReceiver, &fds_config, &fds_data, &shellClient] {
-        shellClient->startNewSubscription(fds_config[0], fds_data[1], resultReceiver);
+        shellClient->startNewSubscription(fds_config[0], fds_data[1], resultReceiver, -1);
     });
     reader.detach();
 
diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
index 0775afe..d9aba61 100644
--- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
+++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
@@ -54,7 +54,9 @@
         "AID_SYSTEM",
         "AID_ROOT",
         "AID_BLUETOOTH",
-        "AID_LMKD"
+        "AID_LMKD",
+        "com.android.managedprovisioning",
+        "AID_NETWORK_STACK"
     };
     private static final Logger LOGGER = Logger.getLogger(TestDrive.class.getName());
 
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 4174ad7..1b7fbfe 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -23,8 +23,10 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.telecom.Log;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.text.TextUtils;
 
 import com.android.internal.os.BaseCommand;
 import com.android.internal.telecom.ITelecomService;
@@ -45,6 +47,8 @@
     private static final String COMMAND_SET_PHONE_ACCOUNT_ENABLED = "set-phone-account-enabled";
     private static final String COMMAND_SET_PHONE_ACCOUNT_DISABLED = "set-phone-account-disabled";
     private static final String COMMAND_REGISTER_PHONE_ACCOUNT = "register-phone-account";
+    private static final String COMMAND_SET_USER_SELECTED_OUTGOING_PHONE_ACCOUNT =
+            "set-user-selected-outgoing-phone-account";
     private static final String COMMAND_REGISTER_SIM_PHONE_ACCOUNT = "register-sim-phone-account";
     private static final String COMMAND_SET_TEST_CALL_REDIRECTION_APP = "set-test-call-redirection-app";
     private static final String COMMAND_SET_TEST_CALL_SCREENING_APP = "set-test-call-screening-app";
@@ -70,6 +74,8 @@
                 + "usage: telecom set-phone-account-enabled <COMPONENT> <ID> <USER_SN>\n"
                 + "usage: telecom set-phone-account-disabled <COMPONENT> <ID> <USER_SN>\n"
                 + "usage: telecom register-phone-account <COMPONENT> <ID> <USER_SN> <LABEL>\n"
+                + "usage: telecom set-user-selected-outgoing-phone-account <COMPONENT> <ID> "
+                + "<USER_SN>\n"
                 + "usage: telecom set-test-call-redirection-app <PACKAGE>\n"
                 + "usage: telecom set-test-call-screening-app <PACKAGE>\n"
                 + "usage: telecom set-test-auto-mode-app <PACKAGE>\n"
@@ -104,16 +110,18 @@
         mTelecomService = ITelecomService.Stub.asInterface(
                 ServiceManager.getService(Context.TELECOM_SERVICE));
         if (mTelecomService == null) {
+            Log.w(this, "onRun: Can't access telecom manager.");
             showError("Error: Could not access the Telecom Manager. Is the system running?");
             return;
         }
         mUserManager = IUserManager.Stub
                 .asInterface(ServiceManager.getService(Context.USER_SERVICE));
         if (mUserManager == null) {
+            Log.w(this, "onRun: Can't access user manager.");
             showError("Error: Could not access the User Manager. Is the system running?");
             return;
         }
-
+        Log.i(this, "onRun: parsing command.");
         String command = nextArgRequired();
         switch (command) {
             case COMMAND_SET_PHONE_ACCOUNT_ENABLED:
@@ -143,6 +151,9 @@
             case COMMAND_REGISTER_SIM_PHONE_ACCOUNT:
                 runRegisterSimPhoneAccount();
                 break;
+            case COMMAND_SET_USER_SELECTED_OUTGOING_PHONE_ACCOUNT:
+                runSetUserSelectedOutgoingPhoneAccount();
+                break;
             case COMMAND_UNREGISTER_PHONE_ACCOUNT:
                 runUnregisterPhoneAccount();
                 break;
@@ -159,6 +170,7 @@
                 runWaitOnHandler();
                 break;
             default:
+                Log.w(this, "onRun: unknown command: %s", command);
                 throw new IllegalArgumentException ("unknown command '" + command + "'");
         }
     }
@@ -227,6 +239,13 @@
         mTelecomService.setTestPhoneAcctSuggestionComponent(componentName);
     }
 
+    private void runSetUserSelectedOutgoingPhoneAccount() throws RemoteException {
+        Log.i(this, "runSetUserSelectedOutgoingPhoneAccount");
+        final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
+        mTelecomService.setUserSelectedOutgoingPhoneAccount(handle);
+        System.out.println("Success - " + handle + " set as default outgoing account.");
+    }
+
     private void runUnregisterPhoneAccount() throws RemoteException {
         final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
         mTelecomService.unregisterPhoneAccount(handle);
@@ -256,7 +275,10 @@
 
     }
 
-    private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException{
+    private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException {
+        if (TextUtils.isEmpty(mArgs.peekNextArg())) {
+            return null;
+        }
         final ComponentName component = parseComponentName(nextArgRequired());
         final String accountId = nextArgRequired();
         final String userSnInStr = nextArgRequired();
@@ -265,6 +287,7 @@
             final int userSn = Integer.parseInt(userSnInStr);
             userHandle = UserHandle.of(mUserManager.getUserHandle(userSn));
         } catch (NumberFormatException ex) {
+            Log.w(this, "getPhoneAccountHandleFromArgs - invalid user %s", userSnInStr);
             throw new IllegalArgumentException ("Invalid user serial number " + userSnInStr);
         }
         return new PhoneAccountHandle(component, accountId, userHandle);
@@ -277,4 +300,4 @@
         }
         return cn;
     }
-}
\ No newline at end of file
+}
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 7a993fd..ee2fe8f 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -56,7 +56,6 @@
 Landroid/app/IActivityManager$Stub$Proxy;->getLaunchedFromUid(Landroid/os/IBinder;)I
 Landroid/app/IActivityManager$Stub$Proxy;->getProcessLimit()I
 Landroid/app/IActivityManager$Stub$Proxy;->getProcessPss([I)[J
-Landroid/app/IActivityManager$Stub$Proxy;->isAppForeground(I)Z
 Landroid/app/IActivityManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
 Landroid/app/IActivityManager$Stub$Proxy;->setActivityController(Landroid/app/IActivityController;Z)V
 Landroid/app/IActivityManager$Stub$Proxy;->updatePersistentConfiguration(Landroid/content/res/Configuration;)V
@@ -491,7 +490,6 @@
 Landroid/location/ILocationManager$Stub;->TRANSACTION_getAllProviders:I
 Landroid/location/ILocationManager;->getAllProviders()Ljava/util/List;
 Landroid/location/ILocationManager;->getNetworkProviderPackage()Ljava/lang/String;
-Landroid/location/ILocationManager;->reportLocation(Landroid/location/Location;Z)V
 Landroid/location/INetInitiatedListener$Stub;-><init>()V
 Landroid/location/INetInitiatedListener;->sendNiResponse(II)Z
 Landroid/location/LocationManager$ListenerTransport;-><init>(Landroid/location/LocationManager;Landroid/location/LocationListener;Landroid/os/Looper;)V
@@ -925,7 +923,6 @@
 Landroid/os/PowerManager;->mService:Landroid/os/IPowerManager;
 Landroid/os/PowerManager;->validateWakeLockParameters(ILjava/lang/String;)V
 Landroid/os/PowerManager;->wakeUp(JLjava/lang/String;)V
-Landroid/os/Process;->BLUETOOTH_UID:I
 Landroid/os/Process;->DRM_UID:I
 Landroid/os/Process;->getFreeMemory()J
 Landroid/os/Process;->getParentPid(I)I
@@ -952,10 +949,8 @@
 Landroid/os/Process;->PROC_ZERO_TERM:I
 Landroid/os/Process;->readProcFile(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z
 Landroid/os/Process;->readProcLines(Ljava/lang/String;[Ljava/lang/String;[J)V
-Landroid/os/Process;->ROOT_UID:I
 Landroid/os/Process;->setArgV0(Ljava/lang/String;)V
 Landroid/os/Process;->setProcessGroup(II)V
-Landroid/os/Process;->SHELL_UID:I
 Landroid/os/Process;->VPN_UID:I
 Landroid/os/Process;->WIFI_UID:I
 Landroid/os/RecoverySystem;->verifyPackageCompatibility(Ljava/io/InputStream;)Z
@@ -997,8 +992,6 @@
 Landroid/os/ServiceManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/os/IServiceManager;
 Landroid/os/ServiceManagerProxy;->getService(Ljava/lang/String;)Landroid/os/IBinder;
 Landroid/os/ServiceManagerProxy;->mRemote:Landroid/os/IBinder;
-Landroid/os/ServiceSpecificException;-><init>(ILjava/lang/String;)V
-Landroid/os/ServiceSpecificException;->errorCode:I
 Landroid/os/SharedMemory;->getFd()I
 Landroid/os/ShellCommand;->peekNextArg()Ljava/lang/String;
 Landroid/os/StatFs;->mStat:Landroid/system/StructStatVfs;
@@ -1110,18 +1103,6 @@
 Landroid/os/UserManager;->mService:Landroid/os/IUserManager;
 Landroid/os/UserManager;->removeUser(I)Z
 Landroid/os/Vibrator;-><init>()V
-Landroid/os/VintfObject;->getHalNamesAndVersions()[Ljava/lang/String;
-Landroid/os/VintfObject;->getSepolicyVersion()Ljava/lang/String;
-Landroid/os/VintfObject;->getTargetFrameworkCompatibilityMatrixVersion()Ljava/lang/Long;
-Landroid/os/VintfObject;->getVndkSnapshots()Ljava/util/Map;
-Landroid/os/VintfObject;->report()[Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getCpuInfo()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getHardwareId()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getKernelVersion()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getNodeName()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getOsName()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getOsRelease()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getOsVersion()Ljava/lang/String;
 Landroid/os/WorkSource;-><init>(Landroid/os/Parcel;)V
 Landroid/os/WorkSource;->mNames:[Ljava/lang/String;
 Landroid/os/WorkSource;->mNum:I
@@ -1435,11 +1416,6 @@
 Landroid/service/euicc/IRetainSubscriptionsForFactoryResetCallback;->onComplete(I)V
 Landroid/service/euicc/ISwitchToSubscriptionCallback;->onComplete(I)V
 Landroid/service/euicc/IUpdateSubscriptionNicknameCallback;->onComplete(I)V
-Landroid/service/media/IMediaBrowserServiceCallbacks$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/media/IMediaBrowserServiceCallbacks;
-Landroid/service/media/IMediaBrowserServiceCallbacks;->onConnect(Ljava/lang/String;Landroid/media/session/MediaSession$Token;Landroid/os/Bundle;)V
-Landroid/service/media/IMediaBrowserServiceCallbacks;->onConnectFailed()V
-Landroid/service/media/IMediaBrowserServiceCallbacks;->onLoadChildren(Ljava/lang/String;Landroid/content/pm/ParceledListSlice;)V
-Landroid/service/media/IMediaBrowserServiceCallbacks;->onLoadChildrenWithOptions(Ljava/lang/String;Landroid/content/pm/ParceledListSlice;Landroid/os/Bundle;)V
 Landroid/service/notification/INotificationListener$Stub;-><init>()V
 Landroid/service/persistentdata/IPersistentDataBlockService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/persistentdata/IPersistentDataBlockService;
 Landroid/service/vr/IVrManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/vr/IVrManager;
@@ -1494,7 +1470,6 @@
 Landroid/test/AndroidTestCase;->getTestContext()Landroid/content/Context;
 Landroid/test/AndroidTestCase;->setTestContext(Landroid/content/Context;)V
 Landroid/test/InstrumentationTestCase;->runMethod(Ljava/lang/reflect/Method;I)V
-Landroid/test/RepetitiveTest;->numIterations()I
 Landroid/util/Singleton;-><init>()V
 Landroid/util/XmlPullAttributes;-><init>(Lorg/xmlpull/v1/XmlPullParser;)V
 Landroid/util/XmlPullAttributes;->mParser:Lorg/xmlpull/v1/XmlPullParser;
@@ -1827,22 +1802,10 @@
 Lcom/android/internal/os/RuntimeInit;->initialized:Z
 Lcom/android/internal/os/RuntimeInit;->main([Ljava/lang/String;)V
 Lcom/android/internal/os/RuntimeInit;->mApplicationObject:Landroid/os/IBinder;
-Lcom/android/internal/os/ZygoteConnection$Arguments;-><init>([Ljava/lang/String;)V
-Lcom/android/internal/os/ZygoteConnection$Arguments;->effectiveCapabilities:J
-Lcom/android/internal/os/ZygoteConnection$Arguments;->gid:I
-Lcom/android/internal/os/ZygoteConnection$Arguments;->gids:[I
-Lcom/android/internal/os/ZygoteConnection$Arguments;->permittedCapabilities:J
-Lcom/android/internal/os/ZygoteConnection$Arguments;->remainingArgs:[Ljava/lang/String;
-Lcom/android/internal/os/ZygoteConnection$Arguments;->rlimits:Ljava/util/ArrayList;
-Lcom/android/internal/os/ZygoteConnection$Arguments;->uid:I
-Lcom/android/internal/os/ZygoteConnection;->applyUidSecurityPolicy(Lcom/android/internal/os/ZygoteConnection$Arguments;Landroid/net/Credentials;)V
 Lcom/android/internal/os/ZygoteConnection;->closeSocket()V
-Lcom/android/internal/os/ZygoteConnection;->getFileDesciptor()Ljava/io/FileDescriptor;
-Lcom/android/internal/os/ZygoteConnection;->intArray2d:[[I
 Lcom/android/internal/os/ZygoteConnection;->mSocket:Landroid/net/LocalSocket;
 Lcom/android/internal/os/ZygoteConnection;->mSocketOutStream:Ljava/io/DataOutputStream;
 Lcom/android/internal/os/ZygoteConnection;->peer:Landroid/net/Credentials;
-Lcom/android/internal/os/ZygoteConnection;->readArgumentList()[Ljava/lang/String;
 Lcom/android/internal/os/ZygoteInit;->main([Ljava/lang/String;)V
 Lcom/android/internal/os/ZygoteInit;->mResources:Landroid/content/res/Resources;
 Lcom/android/internal/os/ZygoteSecurityException;-><init>(Ljava/lang/String;)V
@@ -2768,94 +2731,6 @@
 Lcom/android/internal/telephony/Connection;->mIsIncoming:Z
 Lcom/android/internal/telephony/Connection;->mNumberPresentation:I
 Lcom/android/internal/telephony/Connection;->setVideoState(I)V
-Lcom/android/internal/telephony/dataconnection/ApnContext;->getApnType()Ljava/lang/String;
-Lcom/android/internal/telephony/dataconnection/ApnContext;->getReason()Ljava/lang/String;
-Lcom/android/internal/telephony/dataconnection/ApnContext;->getState()Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/dataconnection/ApnContext;->isConnectable()Z
-Lcom/android/internal/telephony/dataconnection/ApnContext;->isDisconnected()Z
-Lcom/android/internal/telephony/dataconnection/ApnContext;->isEnabled()Z
-Lcom/android/internal/telephony/dataconnection/ApnContext;->isReady()Z
-Lcom/android/internal/telephony/dataconnection/ApnContext;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/ApnContext;->mApnType:Ljava/lang/String;
-Lcom/android/internal/telephony/dataconnection/ApnContext;->mRefCount:I
-Lcom/android/internal/telephony/dataconnection/ApnContext;->mRefCountLock:Ljava/lang/Object;
-Lcom/android/internal/telephony/dataconnection/ApnContext;->setState(Lcom/android/internal/telephony/DctConstants$State;)V
-Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;->mApnContext:Lcom/android/internal/telephony/dataconnection/ApnContext;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->clearSettings()V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->dumpToLog()V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->initConnection(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)Z
-Lcom/android/internal/telephony/dataconnection/DataConnection;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mActivatingState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcActivatingState;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mActiveState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcActiveState;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mConnectionParams:Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mDataRegState:I
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingErrorCreatingConnection:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectionErrorCreatingConnection;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectingState;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectParams:Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mId:I
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mInactiveState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcInactiveState;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mLinkProperties:Landroid/net/LinkProperties;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mNetworkInfo:Landroid/net/NetworkInfo;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mPhone:Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mRilRat:I
-Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfConnected(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams;Z)V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->onConnect(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->tearDownData(Ljava/lang/Object;)V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->updateTcpBufferSizes(I)V
-Lcom/android/internal/telephony/dataconnection/DcController;->lr(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DcController;->mDcListActiveByCid:Ljava/util/HashMap;
-Lcom/android/internal/telephony/dataconnection/DcController;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker;
-Lcom/android/internal/telephony/dataconnection/DcController;->mDcTesterDeactivateAll:Lcom/android/internal/telephony/dataconnection/DcTesterDeactivateAll;
-Lcom/android/internal/telephony/dataconnection/DcTracker$RecoveryAction;->isAggressiveRecovery(I)Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->cancelReconnectAlarm(Lcom/android/internal/telephony/dataconnection/ApnContext;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpAllConnections(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->createAllApnList()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->getActiveApnTypes()[Ljava/lang/String;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->getOverallState()Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->getUiccRecords(I)Lcom/android/internal/telephony/uicc/IccRecords;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->isConnected()Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->isDisconnected()Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->isOnlySingleDcAllowed(I)Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mAllApnSettings:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mApnContexts:Ljava/util/concurrent/ConcurrentHashMap;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mAttached:Ljava/util/concurrent/atomic/AtomicBoolean;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mAutoAttachOnCreation:Ljava/util/concurrent/atomic/AtomicBoolean;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mDataConnectionTracker:Landroid/os/Handler;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mDisconnectPendingCount:I
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mIccRecords:Ljava/util/concurrent/atomic/AtomicReference;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mIsPsRestricted:Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mIsScreenOn:Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mNetStatPollEnabled:Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mNetStatPollPeriod:I
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mPhone:Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mPrioritySortedApnContexts:Ljava/util/PriorityQueue;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mProvisioningSpinner:Landroid/app/ProgressDialog;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mResolver:Landroid/content/ContentResolver;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mState:Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->mSubscriptionManager:Landroid/telephony/SubscriptionManager;
-Lcom/android/internal/telephony/dataconnection/DcTracker;->notifyDataConnection(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->notifyOffApnsOfAvailability(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentDataStallAlarm(Landroid/content/Intent;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentProvisioningApnAlarm(Landroid/content/Intent;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->onRecordsLoadedOrSubIdChanged()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->onTrySetupData(Lcom/android/internal/telephony/dataconnection/ApnContext;)Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->onTrySetupData(Ljava/lang/String;)Z
-Lcom/android/internal/telephony/dataconnection/DcTracker;->registerSettingsObserver()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->resetPollStats()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->restartDataStallAlarm()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->setInitialAttachApn()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->setPreferredApn(I)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->setRadio(Z)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->setupDataOnConnectableApns(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->startDataStallAlarm(Z)V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->startNetStatPoll()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->stopDataStallAlarm()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->stopNetStatPoll()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->unregisterForAllDataDisconnected(Landroid/os/Handler;)V
 Lcom/android/internal/telephony/DctConstants$Activity;->DATAIN:Lcom/android/internal/telephony/DctConstants$Activity;
 Lcom/android/internal/telephony/DctConstants$Activity;->DATAINANDOUT:Lcom/android/internal/telephony/DctConstants$Activity;
 Lcom/android/internal/telephony/DctConstants$Activity;->DATAOUT:Lcom/android/internal/telephony/DctConstants$Activity;
@@ -3290,7 +3165,7 @@
 Lcom/android/internal/telephony/ITelephonyRegistry;->listen(Ljava/lang/String;Lcom/android/internal/telephony/IPhoneStateListener;IZ)V
 Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCallState(ILjava/lang/String;)V
 Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCellInfo(Ljava/util/List;)V
-Lcom/android/internal/telephony/ITelephonyRegistry;->notifyDataConnectionFailed(Ljava/lang/String;Ljava/lang/String;)V
+Lcom/android/internal/telephony/ITelephonyRegistry;->notifyDataConnectionFailed(Ljava/lang/String;)V
 Lcom/android/internal/telephony/IWapPushManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IWapPushManager;
 Lcom/android/internal/telephony/IWapPushManager;->addPackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZZ)Z
 Lcom/android/internal/telephony/IWapPushManager;->deletePackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
@@ -3643,7 +3518,7 @@
 Lcom/android/internal/telephony/SubscriptionController;->mLock:Ljava/lang/Object;
 Lcom/android/internal/telephony/SubscriptionController;->notifySubscriptionInfoChanged()V
 Lcom/android/internal/telephony/SubscriptionController;->setDefaultDataSubId(I)V
-Lcom/android/internal/telephony/SubscriptionController;->setDefaultFallbackSubId(I)V
+Lcom/android/internal/telephony/SubscriptionController;->setDefaultFallbackSubId(II)V
 Lcom/android/internal/telephony/SubscriptionController;->setDefaultSmsSubId(I)V
 Lcom/android/internal/telephony/SubscriptionController;->setDefaultVoiceSubId(I)V
 Lcom/android/internal/telephony/SubscriptionController;->setPlmnSpn(IZLjava/lang/String;ZLjava/lang/String;)Z
@@ -3655,11 +3530,9 @@
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mContext:Landroid/content/Context;
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mCurrentlyActiveUserId:I
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mIccId:[Ljava/lang/String;
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mInsertSimState:[I
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPackageManager:Landroid/content/pm/IPackageManager;
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPhone:[Lcom/android/internal/telephony/Phone;
 Lcom/android/internal/telephony/SubscriptionInfoUpdater;->PROJECT_SIM_NUM:I
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->updateSubscriptionInfoByIccId()V
 Lcom/android/internal/telephony/TelephonyCapabilities;->supportsAdn(I)Z
 Lcom/android/internal/telephony/TelephonyProperties;->PROPERTY_ICC_OPERATOR_NUMERIC:Ljava/lang/String;
 Lcom/android/internal/telephony/test/InterpreterEx;-><init>(Ljava/lang/String;)V
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index f2ad268..cebe6e12 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -37,6 +37,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.Display;
 import android.view.KeyEvent;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
@@ -382,7 +383,8 @@
         void init(int connectionId, IBinder windowToken);
         boolean onGesture(int gestureId);
         boolean onKeyEvent(KeyEvent event);
-        void onMagnificationChanged(@NonNull Region region,
+        /** Magnification changed callbacks for different displays */
+        void onMagnificationChanged(int displayId, @NonNull Region region,
                 float scale, float centerX, float centerY);
         void onSoftKeyboardShowModeChanged(int showMode);
         void onPerformGestureResult(int sequence, boolean completedSuccessfully);
@@ -452,7 +454,9 @@
 
     private WindowManager mWindowManager;
 
-    private MagnificationController mMagnificationController;
+    /** List of magnification controllers, mapping from displayId -> MagnificationController. */
+    private final SparseArray<MagnificationController> mMagnificationControllers =
+            new SparseArray<>(0);
     private SoftKeyboardController mSoftKeyboardController;
     private AccessibilityButtonController mAccessibilityButtonController;
 
@@ -483,8 +487,10 @@
      * client code.
      */
     private void dispatchServiceConnected() {
-        if (mMagnificationController != null) {
-            mMagnificationController.onServiceConnected();
+        synchronized (mLock) {
+            for (int i = 0; i < mMagnificationControllers.size(); i++) {
+                mMagnificationControllers.valueAt(i).onServiceConnectedLocked();
+            }
         }
         if (mSoftKeyboardController != null) {
             mSoftKeyboardController.onServiceConnected();
@@ -652,11 +658,34 @@
      */
     @NonNull
     public final MagnificationController getMagnificationController() {
+        return getMagnificationController(Display.DEFAULT_DISPLAY);
+    }
+
+    /**
+     * Returns the magnification controller of specified logical display, which may be used to
+     * query and modify the state of display magnification.
+     * <p>
+     * <strong>Note:</strong> In order to control magnification, your service
+     * must declare the capability by setting the
+     * {@link android.R.styleable#AccessibilityService_canControlMagnification}
+     * property in its meta-data. For more information, see
+     * {@link #SERVICE_META_DATA}.
+     *
+     * @param displayId The logic display id, use {@link Display#DEFAULT_DISPLAY} for
+     *                  default display.
+     * @return the magnification controller
+     *
+     * @hide
+     */
+    @NonNull
+    public final MagnificationController getMagnificationController(int displayId) {
         synchronized (mLock) {
-            if (mMagnificationController == null) {
-                mMagnificationController = new MagnificationController(this, mLock);
+            MagnificationController controller = mMagnificationControllers.get(displayId);
+            if (controller == null) {
+                controller = new MagnificationController(this, mLock, displayId);
+                mMagnificationControllers.put(displayId, controller);
             }
-            return mMagnificationController;
+            return controller;
         }
     }
 
@@ -765,11 +794,14 @@
         }
     }
 
-    private void onMagnificationChanged(@NonNull Region region, float scale,
+    private void onMagnificationChanged(int displayId, @NonNull Region region, float scale,
             float centerX, float centerY) {
-        if (mMagnificationController != null) {
-            mMagnificationController.dispatchMagnificationChanged(
-                    region, scale, centerX, centerY);
+        MagnificationController controller;
+        synchronized (mLock) {
+            controller = mMagnificationControllers.get(displayId);
+        }
+        if (controller != null) {
+            controller.dispatchMagnificationChanged(region, scale, centerX, centerY);
         }
     }
 
@@ -794,6 +826,7 @@
      */
     public static final class MagnificationController {
         private final AccessibilityService mService;
+        private final int mDisplayId;
 
         /**
          * Map of listeners to their handlers. Lazily created when adding the
@@ -802,19 +835,19 @@
         private ArrayMap<OnMagnificationChangedListener, Handler> mListeners;
         private final Object mLock;
 
-        MagnificationController(@NonNull AccessibilityService service, @NonNull Object lock) {
+        MagnificationController(@NonNull AccessibilityService service, @NonNull Object lock,
+                int displayId) {
             mService = service;
             mLock = lock;
+            mDisplayId = displayId;
         }
 
         /**
          * Called when the service is connected.
          */
-        void onServiceConnected() {
-            synchronized (mLock) {
-                if (mListeners != null && !mListeners.isEmpty()) {
-                    setMagnificationCallbackEnabled(true);
-                }
+        void onServiceConnectedLocked() {
+            if (mListeners != null && !mListeners.isEmpty()) {
+                setMagnificationCallbackEnabled(true);
             }
         }
 
@@ -891,7 +924,7 @@
                             mService.mConnectionId);
             if (connection != null) {
                 try {
-                    connection.setMagnificationCallbackEnabled(enabled);
+                    connection.setMagnificationCallbackEnabled(mDisplayId, enabled);
                 } catch (RemoteException re) {
                     throw new RuntimeException(re);
                 }
@@ -952,7 +985,7 @@
                             mService.mConnectionId);
             if (connection != null) {
                 try {
-                    return connection.getMagnificationScale();
+                    return connection.getMagnificationScale(mDisplayId);
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to obtain scale", re);
                     re.rethrowFromSystemServer();
@@ -981,7 +1014,7 @@
                             mService.mConnectionId);
             if (connection != null) {
                 try {
-                    return connection.getMagnificationCenterX();
+                    return connection.getMagnificationCenterX(mDisplayId);
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to obtain center X", re);
                     re.rethrowFromSystemServer();
@@ -1010,7 +1043,7 @@
                             mService.mConnectionId);
             if (connection != null) {
                 try {
-                    return connection.getMagnificationCenterY();
+                    return connection.getMagnificationCenterY(mDisplayId);
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to obtain center Y", re);
                     re.rethrowFromSystemServer();
@@ -1044,7 +1077,7 @@
                             mService.mConnectionId);
             if (connection != null) {
                 try {
-                    return connection.getMagnificationRegion();
+                    return connection.getMagnificationRegion(mDisplayId);
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to obtain magnified region", re);
                     re.rethrowFromSystemServer();
@@ -1073,7 +1106,7 @@
                             mService.mConnectionId);
             if (connection != null) {
                 try {
-                    return connection.resetMagnification(animate);
+                    return connection.resetMagnification(mDisplayId, animate);
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to reset", re);
                     re.rethrowFromSystemServer();
@@ -1090,7 +1123,7 @@
          * called) or the service has been disconnected, this method will have
          * no effect and return {@code false}.
          *
-         * @param scale the magnification scale to set, must be >= 1 and <= 5
+         * @param scale the magnification scale to set, must be >= 1 and <= 8
          * @param animate {@code true} to animate from the current scale or
          *                {@code false} to set the scale immediately
          * @return {@code true} on success, {@code false} on failure
@@ -1101,7 +1134,7 @@
                             mService.mConnectionId);
             if (connection != null) {
                 try {
-                    return connection.setMagnificationScaleAndCenter(
+                    return connection.setMagnificationScaleAndCenter(mDisplayId,
                             scale, Float.NaN, Float.NaN, animate);
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to set scale", re);
@@ -1133,7 +1166,7 @@
                             mService.mConnectionId);
             if (connection != null) {
                 try {
-                    return connection.setMagnificationScaleAndCenter(
+                    return connection.setMagnificationScaleAndCenter(mDisplayId,
                             Float.NaN, centerX, centerY, animate);
                 } catch (RemoteException re) {
                     Log.w(LOG_TAG, "Failed to set center", re);
@@ -1624,9 +1657,10 @@
             }
 
             @Override
-            public void onMagnificationChanged(@NonNull Region region,
+            public void onMagnificationChanged(int displayId, @NonNull Region region,
                     float scale, float centerX, float centerY) {
-                AccessibilityService.this.onMagnificationChanged(region, scale, centerX, centerY);
+                AccessibilityService.this.onMagnificationChanged(displayId, region, scale,
+                        centerX, centerY);
             }
 
             @Override
@@ -1729,13 +1763,15 @@
             mCaller.sendMessage(message);
         }
 
-        public void onMagnificationChanged(@NonNull Region region,
+        /** Magnification changed callbacks for different displays */
+        public void onMagnificationChanged(int displayId, @NonNull Region region,
                 float scale, float centerX, float centerY) {
             final SomeArgs args = SomeArgs.obtain();
             args.arg1 = region;
             args.arg2 = scale;
             args.arg3 = centerX;
             args.arg4 = centerY;
+            args.argi1 = displayId;
 
             final Message message = mCaller.obtainMessageO(DO_ON_MAGNIFICATION_CHANGED, args);
             mCaller.sendMessage(message);
@@ -1865,7 +1901,10 @@
                         final float scale = (float) args.arg2;
                         final float centerX = (float) args.arg3;
                         final float centerY = (float) args.arg4;
-                        mCallback.onMagnificationChanged(region, scale, centerX, centerY);
+                        final int displayId = args.argi1;
+                        args.recycle();
+                        mCallback.onMagnificationChanged(displayId, region, scale,
+                                centerX, centerY);
                     }
                 } return;
 
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 997ed25..e86fa89 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
 
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
@@ -794,7 +795,7 @@
      *
      * @see android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
      */
-    public void setNonInteractiveUiTimeoutMillis(int timeout) {
+    public void setNonInteractiveUiTimeoutMillis(@IntRange(from = 0) int timeout) {
         mNonInteractiveUiTimeout = timeout;
     }
 
@@ -821,7 +822,7 @@
      *
      * @see android.R.styleable#AccessibilityService_interactiveUiTimeout
      */
-    public void setInteractiveUiTimeoutMillis(int timeout) {
+    public void setInteractiveUiTimeoutMillis(@IntRange(from = 0) int timeout) {
         mInteractiveUiTimeout = timeout;
     }
 
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 4e96b8f..1dae4fc 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -41,7 +41,7 @@
 
     void onKeyEvent(in KeyEvent event, int sequence);
 
-    void onMagnificationChanged(in Region region, float scale, float centerX, float centerY);
+    void onMagnificationChanged(int displayId, in Region region, float scale, float centerX, float centerY);
 
     void onSoftKeyboardShowModeChanged(int showMode);
 
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 276131f..8c38fe4 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -70,20 +70,20 @@
 
     oneway void setOnKeyEventResult(boolean handled, int sequence);
 
-    float getMagnificationScale();
+    float getMagnificationScale(int displayId);
 
-    float getMagnificationCenterX();
+    float getMagnificationCenterX(int displayId);
 
-    float getMagnificationCenterY();
+    float getMagnificationCenterY(int displayId);
 
-    Region getMagnificationRegion();
+    Region getMagnificationRegion(int displayId);
 
-    boolean resetMagnification(boolean animate);
+    boolean resetMagnification(int displayId, boolean animate);
 
-    boolean setMagnificationScaleAndCenter(float scale, float centerX, float centerY,
+    boolean setMagnificationScaleAndCenter(int displayId, float scale, float centerX, float centerY,
         boolean animate);
 
-    void setMagnificationCallbackEnabled(boolean enabled);
+    void setMagnificationCallbackEnabled(int displayId, boolean enabled);
 
     boolean setSoftKeyboardShowMode(int showMode);
 
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5b8261e..92f47e7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.os.Process.myUid;
 
 import static java.lang.Character.MIN_VALUE;
 
@@ -73,6 +74,7 @@
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.StrictMode;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
@@ -121,7 +123,9 @@
 import android.view.autofill.AutofillManager.AutofillClient;
 import android.view.autofill.AutofillPopupWindow;
 import android.view.autofill.IAutofillWindowPresenter;
+import android.view.contentcapture.ContentCaptureContext;
 import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.ContentCaptureSession;
 import android.widget.AdapterView;
 import android.widget.Toast;
 import android.widget.Toolbar;
@@ -1022,7 +1026,9 @@
      *
      * @return The content capture manager
      */
-    @NonNull private ContentCaptureManager getContentCaptureManager() {
+    @Nullable private ContentCaptureManager getContentCaptureManager() {
+        // ContextCapture disabled for system apps
+        if (!UserHandle.isApp(myUid())) return null;
         if (mContentCaptureManager == null) {
             mContentCaptureManager = getSystemService(ContentCaptureManager.class);
         }
@@ -1030,38 +1036,70 @@
     }
 
     /** @hide */ private static final int CONTENT_CAPTURE_START = 1;
-    /** @hide */ private static final int CONTENT_CAPTURE_FLUSH = 2;
-    /** @hide */ private static final int CONTENT_CAPTURE_STOP = 3;
+    /** @hide */ private static final int CONTENT_CAPTURE_PAUSE = 2;
+    /** @hide */ private static final int CONTENT_CAPTURE_RESUME = 3;
+    /** @hide */ private static final int CONTENT_CAPTURE_STOP = 4;
 
     /** @hide */
     @IntDef(prefix = { "CONTENT_CAPTURE_" }, value = {
             CONTENT_CAPTURE_START,
-            CONTENT_CAPTURE_FLUSH,
+            CONTENT_CAPTURE_PAUSE,
+            CONTENT_CAPTURE_RESUME,
             CONTENT_CAPTURE_STOP
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface ContentCaptureNotificationType{}
 
-
-    private void notifyContentCaptureManagerIfNeeded(@ContentCaptureNotificationType int type) {
-        final ContentCaptureManager cm = getContentCaptureManager();
-        if (cm == null || !cm.isContentCaptureEnabled()) {
-            return;
-        }
+    private String getContentCaptureTypeAsString(@ContentCaptureNotificationType int type) {
         switch (type) {
             case CONTENT_CAPTURE_START:
-                //TODO(b/111276913): decide whether the InteractionSessionId should be
-                // saved / restored in the activity bundle - probably not
-                cm.onActivityStarted(mToken, getComponentName());
-                break;
-            case CONTENT_CAPTURE_FLUSH:
-                cm.flush();
-                break;
+                return "START";
+            case CONTENT_CAPTURE_PAUSE:
+                return "PAUSE";
+            case CONTENT_CAPTURE_RESUME:
+                return "RESUME";
             case CONTENT_CAPTURE_STOP:
-                cm.onActivityStopped();
-                break;
+                return "STOP";
             default:
-                Log.wtf(TAG, "Invalid @ContentCaptureNotificationType: " + type);
+                return "UNKNOW-" + type;
+        }
+    }
+
+    private void notifyContentCaptureManagerIfNeeded(@ContentCaptureNotificationType int type) {
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                    "notifyContentCapture(" + getContentCaptureTypeAsString(type) + ") for "
+                            + mComponent.toShortString());
+        }
+        try {
+            final ContentCaptureManager cm = getContentCaptureManager();
+            if (cm == null) return;
+
+            switch (type) {
+                case CONTENT_CAPTURE_START:
+                    //TODO(b/111276913): decide whether the InteractionSessionId should be
+                    // saved / restored in the activity bundle - probably not
+                    int flags = 0;
+                    if ((getWindow().getAttributes().flags
+                            & WindowManager.LayoutParams.FLAG_SECURE) != 0) {
+                        flags |= ContentCaptureContext.FLAG_DISABLED_BY_FLAG_SECURE;
+                    }
+                    cm.onActivityStarted(mToken, getComponentName(), flags);
+                    break;
+                case CONTENT_CAPTURE_PAUSE:
+                    cm.flush(ContentCaptureSession.FLUSH_REASON_ACTIVITY_PAUSED);
+                    break;
+                case CONTENT_CAPTURE_RESUME:
+                    cm.flush(ContentCaptureSession.FLUSH_REASON_ACTIVITY_RESUMED);
+                    break;
+                case CONTENT_CAPTURE_STOP:
+                    cm.onActivityStopped();
+                    break;
+                default:
+                    Log.wtf(TAG, "Invalid @ContentCaptureNotificationType: " + type);
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
         }
     }
 
@@ -1747,7 +1785,7 @@
             }
         }
         mCalled = true;
-        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_FLUSH);
+        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_RESUME);
     }
 
     /**
@@ -2141,7 +2179,7 @@
             }
         }
         mCalled = true;
-        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_FLUSH);
+        notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_PAUSE);
     }
 
     /**
@@ -2158,6 +2196,7 @@
      * for helping activities determine the proper time to cancel a notification.
      *
      * @see #onUserInteraction()
+     * @see android.content.Intent#FLAG_ACTIVITY_NO_USER_ACTION
      */
     protected void onUserLeaveHint() {
     }
@@ -8179,10 +8218,10 @@
             final AutofillId autofillId = autofillIds[i];
             final View view = autofillClientFindViewByAutofillIdTraversal(autofillId);
             if (view != null) {
-                if (!autofillId.isVirtual()) {
+                if (!autofillId.isVirtualInt()) {
                     visible[i] = view.isVisibleToUser();
                 } else {
-                    visible[i] = view.isVisibleToUserForAutofill(autofillId.getVirtualChildId());
+                    visible[i] = view.isVisibleToUserForAutofill(autofillId.getVirtualChildIntId());
                 }
             }
         }
@@ -8282,6 +8321,33 @@
     }
 
     /**
+     * Specifies whether this {@link Activity} should be shown on top of the lock screen whenever
+     * the lockscreen is up and this activity has another activity behind it with the showWhenLock
+     * attribute set. That is, this activity is only visible on the lock screen if there is another
+     * activity with the showWhenLock attribute visible at the same time on the lock screen. A use
+     * case for this is permission dialogs, that should only be visible on the lock screen if their
+     * requesting activity is also visible. This value can be set as a manifest attribute using
+     * android.R.attr#inheritShowWhenLocked.
+     *
+     * @param inheritShowWhenLocked {@code true} to show the {@link Activity} on top of the lock
+     *                              screen when this activity has another activity behind it with
+     *                              the showWhenLock attribute set; {@code false} otherwise.
+     * @see #setShowWhenLocked(boolean)
+     * See android.R.attr#inheritShowWhenLocked
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public void setInheritShowWhenLocked(boolean inheritShowWhenLocked) {
+        try {
+            ActivityTaskManager.getService().setInheritShowWhenLocked(
+                    mToken, inheritShowWhenLocked);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to call setInheritShowWhenLocked", e);
+        }
+    }
+
+    /**
      * Specifies whether the screen should be turned on when the {@link Activity} is resumed.
      * Normally an activity will be transitioned to the stopped state if it is started while the
      * screen if off, but with this flag set the activity will cause the screen to turn on if the
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d423260..1045b7a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3529,12 +3529,32 @@
 
     /**
      * Returns "true" if device is running in a test harness.
+     *
+     * @deprecated this method is false for all user builds. Users looking to check if their device
+     * is running in a device farm should see {@link #isRunningInUserTestHarness()}.
      */
+    @Deprecated
     public static boolean isRunningInTestHarness() {
         return SystemProperties.getBoolean("ro.test_harness", false);
     }
 
     /**
+     * Returns "true" if the device is running in Test Harness Mode.
+     *
+     * <p>Test Harness Mode is a feature that allows devices to run without human interaction in a
+     * device farm/testing harness (such as Firebase Test Lab). You should check this method if you
+     * want your app to behave differently when running in a test harness to skip setup screens that
+     * would impede UI testing. e.g. a keyboard application that has a full screen setup page for
+     * the first time it is launched.
+     *
+     * <p>Note that you should <em>not</em> use this to determine whether or not your app is running
+     * an instrumentation test, as it is not set for a standard device running a test.
+     */
+    public static boolean isRunningInUserTestHarness() {
+        return SystemProperties.getBoolean("persist.sys.test_harness", false);
+    }
+
+    /**
      * Unsupported compiled sdk warning should always be shown for the intput activity
      * even in cases where the system would normally not show the warning. E.g. when running in a
      * test harness.
@@ -3705,11 +3725,16 @@
      * Returns whether switching to provided user was successful.
      *
      * @param user the user to switch to.
+     *
+     * @throws IllegalArgumentException if the user is null.
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
-    public boolean switchUser(UserHandle user) {
+    public boolean switchUser(@NonNull UserHandle user) {
+        if (user == null) {
+            throw new IllegalArgumentException("UserHandle cannot be null.");
+        }
         return switchUser(user.getIdentifier());
     }
 
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index b42d53a..86e658d 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -73,6 +73,12 @@
             IBinder whitelistToken, long duration);
 
     /**
+     * Allows for a {@link PendingIntent} to be whitelisted to start activities from background.
+     */
+    public abstract void setPendingIntentAllowBgActivityStarts(
+            IIntentSender target, IBinder whitelistToken, int flags);
+
+    /**
      * Allow DeviceIdleController to tell us about what apps are whitelisted.
      */
     public abstract void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids);
@@ -213,9 +219,11 @@
      * @param userId
      * @param event
      * @param appToken ActivityRecord's appToken.
+     * @param taskRoot TaskRecord's root
      */
     public abstract void updateActivityUsageStats(
-            ComponentName activity, int userId, int event, IBinder appToken);
+            ComponentName activity, int userId, int event, IBinder appToken,
+            ComponentName taskRoot);
     public abstract void updateForegroundTimeIfOnBattery(
             String packageName, int uid, long cpuTimeDiff);
     public abstract void sendForegroundProfileChanged(int userId);
@@ -250,10 +258,10 @@
     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);
+            boolean sticky, int userId, boolean allowBackgroundActivityStarts);
     public abstract ComponentName startServiceInPackage(int uid, Intent service,
-            String resolvedType, boolean fgRequired, String callingPackage, int userId)
-            throws TransactionTooLargeException;
+            String resolvedType, boolean fgRequired, String callingPackage, int userId,
+            boolean allowBackgroundActivityStarts) throws TransactionTooLargeException;
 
     public abstract void disconnectActivityFromServices(Object connectionHolder);
     public abstract void cleanUpServices(int userId, ComponentName component, Intent baseIntent);
@@ -308,4 +316,16 @@
 
     /** Returns mount mode for process running with given pid */
     public abstract int getStorageMountMode(int pid, int uid);
+
+    /** Returns true if the given uid is the app in the foreground. */
+    public abstract boolean isAppForeground(int uid);
+
+    /** Remove pending backup for the given userId. */
+    public abstract void clearPendingBackup(int userId);
+
+    /**
+     * When power button is very long pressed, call this interface to do some pre-shutdown work
+     * like persisting database etc.
+     */
+    public abstract void prepareForPossibleShutdown();
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8faf08a..a3243a5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -271,6 +271,13 @@
     @UnsupportedAppUsage
     final H mH = new H();
     final Executor mExecutor = new HandlerExecutor(mH);
+    /**
+     * Maps from activity token to local record of running activities in this process.
+     *
+     * This variable is readable if the code is running in activity thread or holding {@link
+     * #mResourcesManager}. It's only writable if the code is running in activity thread and holding
+     * {@link #mResourcesManager}.
+     */
     @UnsupportedAppUsage
     final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
     /** The activities to be truly destroyed (not include relaunch). */
@@ -434,6 +441,10 @@
         Configuration newConfig;
         Configuration createdConfig;
         Configuration overrideConfig;
+        // Used to save the last reported configuration from server side so that activity
+        // configuration transactions can always use the latest configuration.
+        @GuardedBy("this")
+        private Configuration mPendingOverrideConfig;
         // Used for consolidating configs before sending on to Activity.
         private Configuration tmpConfig = new Configuration();
         // Callback used for updating activity override config.
@@ -3064,7 +3075,12 @@
             }
             r.setState(ON_CREATE);
 
-            mActivities.put(r.token, r);
+            // updatePendingActivityConfiguration() reads from mActivities to update
+            // ActivityClientRecord which runs in a different thread. Protect modifications to
+            // mActivities to avoid race.
+            synchronized (mResourcesManager) {
+                mActivities.put(r.token, r);
+            }
 
         } catch (SuperNotCalledException e) {
             throw e;
@@ -4639,7 +4655,12 @@
             r.setState(ON_DESTROY);
         }
         schedulePurgeIdler();
-        mActivities.remove(token);
+        // updatePendingActivityConfiguration() reads from mActivities to update
+        // ActivityClientRecord which runs in a different thread. Protect modifications to
+        // mActivities to avoid race.
+        synchronized (mResourcesManager) {
+            mActivities.remove(token);
+        }
         StrictMode.decrementExpectedActivityCount(activityClass);
         return r;
     }
@@ -5382,6 +5403,26 @@
         }
     }
 
+    @Override
+    public void updatePendingActivityConfiguration(IBinder activityToken,
+            Configuration overrideConfig) {
+        final ActivityClientRecord r;
+        synchronized (mResourcesManager) {
+            r = mActivities.get(activityToken);
+        }
+
+        if (r == null) {
+            if (DEBUG_CONFIGURATION) {
+                Slog.w(TAG, "Not found target activity to update its pending config.");
+            }
+            return;
+        }
+
+        synchronized (r) {
+            r.mPendingOverrideConfig = overrideConfig;
+        }
+    }
+
     /**
      * Handle new activity configuration and/or move to a different display.
      * @param activityToken Target activity token.
@@ -5401,6 +5442,24 @@
         final boolean movedToDifferentDisplay = displayId != INVALID_DISPLAY
                 && displayId != r.activity.getDisplayId();
 
+        synchronized (r) {
+            if (r.mPendingOverrideConfig != null
+                    && !r.mPendingOverrideConfig.isOtherSeqNewer(overrideConfig)) {
+                overrideConfig = r.mPendingOverrideConfig;
+            }
+            r.mPendingOverrideConfig = null;
+        }
+
+        if (r.overrideConfig != null && !r.overrideConfig.isOtherSeqNewer(overrideConfig)
+                && !movedToDifferentDisplay) {
+            if (DEBUG_CONFIGURATION) {
+                Slog.v(TAG, "Activity already handled newer configuration so drop this"
+                        + " transaction. overrideConfig=" + overrideConfig + " r.overrideConfig="
+                        + r.overrideConfig);
+            }
+            return;
+        }
+
         // Perform updates.
         r.overrideConfig = overrideConfig;
         final ViewRootImpl viewRoot = r.activity.mDecor != null
@@ -5880,6 +5939,11 @@
             Binder.enableTracing();
         }
 
+        // Initialize heap profiling.
+        if (isAppProfileable || Build.IS_DEBUGGABLE) {
+            nInitZygoteChildHeapProfiling();
+        }
+
         // Allow renderer debugging features if we're debuggable.
         boolean isAppDebuggable = (data.appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
         HardwareRenderer.setDebuggingEnabled(isAppDebuggable || Build.IS_DEBUGGABLE);
@@ -6906,4 +6970,5 @@
     // ------------------ Regular JNI ------------------------
     private native void nPurgePendingResources();
     private native void nDumpGraphicsInfo(FileDescriptor fd);
+    private native void nInitZygoteChildHeapProfiling();
 }
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 0b5776e..4d3711a 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -16,6 +16,10 @@
 
 package android.app;
 
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+
 import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager.StackInfo;
@@ -32,11 +36,11 @@
 import android.view.IWindowManager;
 import android.view.InputDevice;
 import android.view.MotionEvent;
-import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceHolder;
 import android.view.SurfaceSession;
 import android.view.SurfaceView;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
@@ -81,7 +85,6 @@
     private boolean mOpened; // Protected by mGuard.
 
     private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
-    private Surface mTmpSurface = new Surface();
 
     /** The ActivityView is only allowed to contain one task. */
     private final boolean mSingleTaskInstance;
@@ -318,20 +321,20 @@
     private class SurfaceCallback implements SurfaceHolder.Callback {
         @Override
         public void surfaceCreated(SurfaceHolder surfaceHolder) {
-            mTmpSurface = new Surface();
             if (mVirtualDisplay == null) {
-                initVirtualDisplay(new SurfaceSession(surfaceHolder.getSurface()));
+                initVirtualDisplay(new SurfaceSession());
                 if (mVirtualDisplay != null && mActivityViewCallback != null) {
                     mActivityViewCallback.onActivityViewReady(ActivityView.this);
                 }
             } else {
-                // TODO (b/119209373): DisplayManager determines if a VirtualDisplay is on by
-                // whether it has a surface. Setting a fake surface here so DisplayManager will
-                // consider this display on.
-                mVirtualDisplay.setSurface(mTmpSurface);
                 mTmpTransaction.reparent(mRootSurfaceControl,
-                        mSurfaceView.getSurfaceControl().getHandle()).apply();
+                        mSurfaceView.getSurfaceControl()).apply();
             }
+
+            if (mVirtualDisplay != null) {
+                mVirtualDisplay.setDisplayState(true);
+            }
+
             updateLocation();
         }
 
@@ -345,15 +348,19 @@
 
         @Override
         public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
-            mTmpSurface.release();
-            mTmpSurface = null;
             if (mVirtualDisplay != null) {
-                mVirtualDisplay.setSurface(null);
+                mVirtualDisplay.setDisplayState(false);
             }
             cleanTapExcludeRegion();
         }
     }
 
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+        mSurfaceView.setVisibility(visibility);
+    }
+
     private void initVirtualDisplay(SurfaceSession surfaceSession) {
         if (mVirtualDisplay != null) {
             throw new IllegalStateException("Trying to initialize for the second time.");
@@ -363,15 +370,11 @@
         final int height = mSurfaceView.getHeight();
         final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
 
-        // TODO (b/119209373): DisplayManager determines if a VirtualDisplay is on by
-        // whether it has a surface. Setting a fake surface here so DisplayManager will consider
-        // this display on.
         mVirtualDisplay = displayManager.createVirtualDisplay(
-                DISPLAY_NAME + "@" + System.identityHashCode(this),
-                width, height, getBaseDisplayDensity(), mTmpSurface,
-                DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
-                        | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
-                        | DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL);
+                DISPLAY_NAME + "@" + System.identityHashCode(this), width, height,
+                getBaseDisplayDensity(), null,
+                VIRTUAL_DISPLAY_FLAG_PUBLIC | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+                        | VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL);
         if (mVirtualDisplay == null) {
             Log.e(TAG, "Failed to initialize ActivityView");
             return;
@@ -382,11 +385,12 @@
 
         mRootSurfaceControl = new SurfaceControl.Builder(surfaceSession)
                 .setContainerLayer(true)
+                .setParent(mSurfaceView.getSurfaceControl())
                 .setName(DISPLAY_NAME)
                 .build();
 
         try {
-            wm.reparentDisplayContent(displayId, mRootSurfaceControl.getHandle());
+            wm.reparentDisplayContent(displayId, mRootSurfaceControl);
             wm.dontOverrideDisplayInfo(displayId);
             if (mSingleTaskInstance) {
                 mActivityTaskManager.setDisplayToSingleTaskInstance(displayId);
@@ -435,11 +439,6 @@
             displayReleased = false;
         }
 
-        if (mTmpSurface != null) {
-            mTmpSurface.release();
-            mTmpSurface = null;
-        }
-
         if (displayReleased && mActivityViewCallback != null) {
             mActivityViewCallback.onActivityViewDestroyed(this);
         }
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index cf40e06..bfc216a 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.ResourceId;
+import android.content.res.Resources;
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -465,7 +466,7 @@
          * @param context the parent context
          */
         public Builder(Context context) {
-            this(context, resolveDialogTheme(context, ResourceId.ID_NULL));
+            this(context, resolveDialogTheme(context, Resources.ID_NULL));
         }
 
         /**
diff --git a/core/java/android/app/AppOpsManager.aidl b/core/java/android/app/AppOpsManager.aidl
index 9329fbc..2240302 100644
--- a/core/java/android/app/AppOpsManager.aidl
+++ b/core/java/android/app/AppOpsManager.aidl
@@ -19,5 +19,7 @@
 parcelable AppOpsManager.PackageOps;
 parcelable AppOpsManager.OpEntry;
 
+parcelable AppOpsManager.HistoricalOp;
+parcelable AppOpsManager.HistoricalOps;
 parcelable AppOpsManager.HistoricalPackageOps;
-parcelable AppOpsManager.HistoricalOpEntry;
+parcelable AppOpsManager.HistoricalUidOps;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 78fe002..ab2430c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -27,6 +27,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.database.ContentObserver;
 import android.media.AudioAttributes.AttributeUsage;
@@ -36,26 +37,33 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.util.ArrayMap;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsActiveCallback;
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsNotedCallback;
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
 
 /**
  * API for interacting with "application operation" tracking.
@@ -106,6 +114,51 @@
 
     static IBinder sToken;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "HISTORICAL_MODE_" }, value = {
+            HISTORICAL_MODE_DISABLED,
+            HISTORICAL_MODE_ENABLED_ACTIVE,
+            HISTORICAL_MODE_ENABLED_PASSIVE
+    })
+    public @interface HistoricalMode {}
+
+    /**
+     * Mode in which app op history is completely disabled.
+     * @hide
+     */
+    @TestApi
+    public static final int HISTORICAL_MODE_DISABLED = 0;
+
+    /**
+     * Mode in which app op history is enabled and app ops performed by apps would
+     * be tracked. This is the mode in which the feature is completely enabled.
+     * @hide
+     */
+    @TestApi
+    public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1;
+
+    /**
+     * Mode in which app op history is enabled but app ops performed by apps would
+     * not be tracked and the only way to add ops to the history is via explicit calls
+     * to dedicated APIs. This mode is useful for testing to allow full control of
+     * the historical content.
+     * @hide
+     */
+    @TestApi
+    public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = { "MODE_" }, value = {
+            MODE_ALLOWED,
+            MODE_IGNORED,
+            MODE_ERRORED,
+            MODE_DEFAULT,
+            MODE_FOREGROUND
+    })
+    public @interface Mode {}
+
     /**
      * Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
      * allowed to perform the given operation.
@@ -159,7 +212,6 @@
             "foreground",   // MODE_FOREGROUND
     };
 
-
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag = true, prefix = { "UID_STATE_" }, value = {
@@ -173,9 +225,16 @@
     public @interface UidState {}
 
     /**
+     * Invalid UID state.
+     * @hide
+     */
+    public static final int UID_STATE_INVALID = -1;
+
+    /**
      * Metrics about an op when its uid is persistent.
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int UID_STATE_PERSISTENT = 0;
 
@@ -183,6 +242,7 @@
      * Metrics about an op when its uid is at the top.
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int UID_STATE_TOP = 1;
 
@@ -190,6 +250,7 @@
      * Metrics about an op when its uid is running a foreground service.
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int UID_STATE_FOREGROUND_SERVICE = 2;
 
@@ -203,6 +264,7 @@
      * Metrics about an op when its uid is in the foreground for any other reasons.
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int UID_STATE_FOREGROUND = 3;
 
@@ -210,6 +272,7 @@
      * Metrics about an op when its uid is in the background for any reason.
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int UID_STATE_BACKGROUND = 4;
 
@@ -217,6 +280,7 @@
      * Metrics about an op when its uid is cached.
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int UID_STATE_CACHED = 5;
 
@@ -237,7 +301,7 @@
     @UnsupportedAppUsage
     public static final int OP_NONE = -1;
     /** @hide Access to coarse location information. */
-    @UnsupportedAppUsage
+    @TestApi
     public static final int OP_COARSE_LOCATION = 0;
     /** @hide Access to fine location information. */
     @UnsupportedAppUsage
@@ -1426,7 +1490,7 @@
             AppOpsManager.MODE_ALLOWED, // READ_ICC_SMS
             AppOpsManager.MODE_ALLOWED, // WRITE_ICC_SMS
             AppOpsManager.MODE_DEFAULT, // WRITE_SETTINGS
-            AppOpsManager.MODE_DEFAULT, // SYSTEM_ALERT_WINDOW
+            getSystemAlertWindowDefault(), // SYSTEM_ALERT_WINDOW
             AppOpsManager.MODE_ALLOWED, // ACCESS_NOTIFICATIONS
             AppOpsManager.MODE_ALLOWED, // CAMERA
             AppOpsManager.MODE_ALLOWED, // RECORD_AUDIO
@@ -1645,6 +1709,9 @@
         }
     }
 
+    /** @hide */
+    public static final String KEY_HISTORICAL_OPS = "historical_ops";
+
     /**
      * Retrieve the op switch that controls the given operation.
      * @hide
@@ -1665,6 +1732,15 @@
     }
 
     /**
+     * Retrieve a non-localized public name for the operation.
+     *
+     * @hide
+     */
+    public static @NonNull String opToPublicName(int op) {
+        return sOpToString[op];
+    }
+
+    /**
      * @hide
      */
     public static int strDebugOpToOp(String op) {
@@ -1731,7 +1807,7 @@
      * Retrieve the default mode for the operation.
      * @hide
      */
-    public static int opToDefaultMode(int op) {
+    public static @Mode int opToDefaultMode(int op) {
         // STOPSHIP b/118520006: Hardcode the default values once the feature is stable.
         switch (op) {
             // SMS permissions
@@ -1795,7 +1871,7 @@
      * Retrieve the human readable mode.
      * @hide
      */
-    public static String modeToName(int mode) {
+    public static String modeToName(@Mode int mode) {
         if (mode >= 0 && mode < MODE_NAMES.length) {
             return MODE_NAMES[mode];
         }
@@ -1885,7 +1961,7 @@
     @SystemApi
     public static final class OpEntry implements Parcelable {
         private final int mOp;
-        private final int mMode;
+        private final @Mode int mMode;
         private final long[] mTimes;
         private final long[] mRejectTimes;
         private final int mDuration;
@@ -1896,7 +1972,7 @@
         /**
          * @hide
          */
-        public OpEntry(int op, int mode, long time, long rejectTime, int duration,
+        public OpEntry(int op, @Mode int mode, long time, long rejectTime, int duration,
                 int proxyUid, String proxyPackage) {
             mOp = op;
             mMode = mode;
@@ -1913,7 +1989,7 @@
         /**
          * @hide
          */
-        public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration,
+        public OpEntry(int op, @Mode int mode, long[] times, long[] rejectTimes, int duration,
                 boolean running, int proxyUid, String proxyPackage) {
             mOp = op;
             mMode = mode;
@@ -1930,7 +2006,7 @@
         /**
          * @hide
          */
-        public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration,
+        public OpEntry(int op, @Mode int mode, long[] times, long[] rejectTimes, int duration,
                 int proxyUid, String proxyPackage) {
             this(op, mode, times, rejectTimes, duration, duration == -1, proxyUid, proxyPackage);
         }
@@ -1953,7 +2029,7 @@
         /**
          * Return this entry's current mode, such as {@link #MODE_ALLOWED}.
          */
-        public int getMode() {
+        public @Mode int getMode() {
             return mMode;
         }
 
@@ -2086,41 +2162,774 @@
         };
     }
 
+    /** @hide */
+    public interface HistoricalOpsVisitor {
+        void visitHistoricalOps(@NonNull HistoricalOps ops);
+        void visitHistoricalUidOps(@NonNull HistoricalUidOps ops);
+        void visitHistoricalPackageOps(@NonNull HistoricalPackageOps ops);
+        void visitHistoricalOp(@NonNull HistoricalOp ops);
+    }
+
     /**
-     * This class represents historical app op information about a package. The history
-     * is aggregated information about ops for a certain amount of time such
-     * as the times the op was accessed, the times the op was rejected, the total
-     * duration the app op has been accessed.
+     * This class represents historical app op state of all UIDs for a given time interval.
+     *
+     * @hide
+     */
+    @TestApi
+    @SystemApi
+    public static final class HistoricalOps implements Parcelable {
+        private long mBeginTimeMillis;
+        private long mEndTimeMillis;
+        private @Nullable SparseArray<HistoricalUidOps> mHistoricalUidOps;
+
+        /** @hide */
+        @TestApi
+        public HistoricalOps(long beginTimeMillis, long endTimeMillis) {
+            Preconditions.checkState(beginTimeMillis <= endTimeMillis);
+            mBeginTimeMillis = beginTimeMillis;
+            mEndTimeMillis = endTimeMillis;
+        }
+
+        /** @hide */
+        public HistoricalOps(@NonNull HistoricalOps other) {
+            mBeginTimeMillis = other.mBeginTimeMillis;
+            mEndTimeMillis = other.mEndTimeMillis;
+            Preconditions.checkState(mBeginTimeMillis <= mEndTimeMillis);
+            if (other.mHistoricalUidOps != null) {
+                final int opCount = other.getUidCount();
+                for (int i = 0; i < opCount; i++) {
+                    final HistoricalUidOps origOps = other.getUidOpsAt(i);
+                    final HistoricalUidOps clonedOps = new HistoricalUidOps(origOps);
+                    if (mHistoricalUidOps == null) {
+                        mHistoricalUidOps = new SparseArray<>(opCount);
+                    }
+                    mHistoricalUidOps.put(clonedOps.getUid(), clonedOps);
+                }
+            }
+        }
+
+        private HistoricalOps(Parcel parcel) {
+            mBeginTimeMillis = parcel.readLong();
+            mEndTimeMillis = parcel.readLong();
+            final int[] uids = parcel.createIntArray();
+            if (!ArrayUtils.isEmpty(uids)) {
+                final ParceledListSlice<HistoricalUidOps> listSlice = parcel.readParcelable(
+                        HistoricalOps.class.getClassLoader());
+                final List<HistoricalUidOps> uidOps = (listSlice != null)
+                        ? listSlice.getList() : null;
+                if (uidOps == null) {
+                    return;
+                }
+                for (int i = 0; i < uids.length; i++) {
+                    if (mHistoricalUidOps == null) {
+                        mHistoricalUidOps = new SparseArray<>();
+                    }
+                    mHistoricalUidOps.put(uids[i], uidOps.get(i));
+                }
+            }
+        }
+
+        /**
+         * Splice a piece from the beginning of these ops.
+         *
+         * @param splicePoint The fraction of the data to be spliced off.
+         *
+         * @hide
+         */
+        public @NonNull HistoricalOps spliceFromBeginning(double splicePoint) {
+            return splice(splicePoint, true);
+        }
+
+        /**
+         * Splice a piece from the end of these ops.
+         *
+         * @param fractionToRemove The fraction of the data to be spliced off.
+         *
+         * @hide
+         */
+        public @NonNull HistoricalOps spliceFromEnd(double fractionToRemove) {
+            return splice(fractionToRemove, false);
+        }
+
+        /**
+         * Splice a piece from the beginning or end of these ops.
+         *
+         * @param fractionToRemove The fraction of the data to be spliced off.
+         * @param beginning Whether to splice off the beginning or the end.
+         *
+         * @return The spliced off part.
+         *
+         * @hide
+         */
+        private @Nullable HistoricalOps splice(double fractionToRemove, boolean beginning) {
+            final long spliceBeginTimeMills;
+            final long spliceEndTimeMills;
+            if (beginning) {
+                spliceBeginTimeMills = mBeginTimeMillis;
+                spliceEndTimeMills = (long) (mBeginTimeMillis
+                        + getDurationMillis() * fractionToRemove);
+                mBeginTimeMillis = spliceEndTimeMills;
+            } else {
+                spliceBeginTimeMills = (long) (mEndTimeMillis
+                        - getDurationMillis() * fractionToRemove);
+                spliceEndTimeMills = mEndTimeMillis;
+                mEndTimeMillis = spliceBeginTimeMills;
+            }
+
+            HistoricalOps splice = null;
+            final int uidCount = getUidCount();
+            for (int i = 0; i < uidCount; i++) {
+                final HistoricalUidOps origOps = getUidOpsAt(i);
+                final HistoricalUidOps spliceOps = origOps.splice(fractionToRemove);
+                if (spliceOps != null) {
+                    if (splice == null) {
+                        splice = new HistoricalOps(spliceBeginTimeMills, spliceEndTimeMills);
+                    }
+                    if (splice.mHistoricalUidOps == null) {
+                        splice.mHistoricalUidOps = new SparseArray<>();
+                    }
+                    splice.mHistoricalUidOps.put(spliceOps.getUid(), spliceOps);
+                }
+            }
+            return splice;
+        }
+
+        /**
+         * Merge the passed ops into the current ones. The time interval is a
+         * union of the current and passed in one and the passed in data is
+         * folded into the data of this instance.
+         *
+         * @hide
+         */
+        public void merge(@NonNull HistoricalOps other) {
+            mBeginTimeMillis = Math.min(mBeginTimeMillis, other.mBeginTimeMillis);
+            mEndTimeMillis = Math.max(mEndTimeMillis, other.mEndTimeMillis);
+            final int uidCount = other.getUidCount();
+            for (int i = 0; i < uidCount; i++) {
+                final HistoricalUidOps otherUidOps = other.getUidOpsAt(i);
+                final HistoricalUidOps thisUidOps = getUidOps(otherUidOps.getUid());
+                if (thisUidOps != null) {
+                    thisUidOps.merge(otherUidOps);
+                } else {
+                    if (mHistoricalUidOps == null) {
+                        mHistoricalUidOps = new SparseArray<>();
+                    }
+                    mHistoricalUidOps.put(otherUidOps.getUid(), otherUidOps);
+                }
+            }
+        }
+
+        /**
+         * AppPermissionUsage the ops to leave only the data we filter for.
+         *
+         * @param uid Uid to filter for or {@link android.os.Process#INCIDENTD_UID} for all.
+         * @param packageName Package to filter for or null for all.
+         * @param opNames Ops to filter for or null for all.
+         * @param beginTimeMillis The begin time to filter for or {@link Long#MIN_VALUE} for all.
+         * @param endTimeMillis The end time to filter for or {@link Long#MAX_VALUE} for all.
+         *
+         * @hide
+         */
+        public void filter(int uid, @Nullable String packageName, @Nullable String[] opNames,
+                long beginTimeMillis, long endTimeMillis) {
+            final long durationMillis = getDurationMillis();
+            mBeginTimeMillis = Math.max(mBeginTimeMillis, beginTimeMillis);
+            mEndTimeMillis = Math.min(mEndTimeMillis, endTimeMillis);
+            final double scaleFactor = Math.min((double) (endTimeMillis - beginTimeMillis)
+                    / (double) durationMillis, 1);
+            final int uidCount = getUidCount();
+            for (int i = uidCount - 1; i >= 0; i--) {
+                final HistoricalUidOps uidOp = mHistoricalUidOps.valueAt(i);
+                if (uid != Process.INVALID_UID && uid != uidOp.getUid()) {
+                    mHistoricalUidOps.removeAt(i);
+                } else {
+                    uidOp.filter(packageName, opNames, scaleFactor);
+                }
+            }
+        }
+
+        /** @hide */
+        public boolean isEmpty() {
+            if (getBeginTimeMillis() >= getEndTimeMillis()) {
+                return true;
+            }
+            final int uidCount = getUidCount();
+            for (int i = uidCount - 1; i >= 0; i--) {
+                final HistoricalUidOps uidOp = mHistoricalUidOps.valueAt(i);
+                if (!uidOp.isEmpty()) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /** @hide */
+        public long getDurationMillis() {
+            return mEndTimeMillis - mBeginTimeMillis;
+        }
+
+        /** @hide */
+        @TestApi
+        public void increaseAccessCount(int opCode, int uid, @NonNull String packageName,
+                @UidState int uidState, long increment) {
+            getOrCreateHistoricalUidOps(uid).increaseAccessCount(opCode,
+                    packageName, uidState, increment);
+        }
+
+        /** @hide */
+        @TestApi
+        public void increaseRejectCount(int opCode, int uid, @NonNull String packageName,
+                @UidState int uidState, long increment) {
+            getOrCreateHistoricalUidOps(uid).increaseRejectCount(opCode,
+                    packageName, uidState, increment);
+        }
+
+        /** @hide */
+        @TestApi
+        public void increaseAccessDuration(int opCode, int uid, @NonNull String packageName,
+                @UidState int uidState, long increment) {
+            getOrCreateHistoricalUidOps(uid).increaseAccessDuration(opCode,
+                    packageName, uidState, increment);
+        }
+
+        /** @hide */
+        @TestApi
+        public void offsetBeginAndEndTime(long offsetMillis) {
+            mBeginTimeMillis += offsetMillis;
+            mEndTimeMillis += offsetMillis;
+        }
+
+        /** @hide */
+        public void setBeginAndEndTime(long beginTimeMillis, long endTimeMillis) {
+            mBeginTimeMillis = beginTimeMillis;
+            mEndTimeMillis = endTimeMillis;
+        }
+
+        /** @hide */
+        public void setBeginTime(long beginTimeMillis) {
+            mBeginTimeMillis = beginTimeMillis;
+        }
+
+        /** @hide */
+        public void setEndTime(long endTimeMillis) {
+            mEndTimeMillis = endTimeMillis;
+        }
+
+        /**
+         * @return The beginning of the interval in milliseconds since
+         *    epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+         */
+        public long getBeginTimeMillis() {
+            return mBeginTimeMillis;
+        }
+
+        /**
+         * @return The end of the interval in milliseconds since
+         *    epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+         */
+        public long getEndTimeMillis() {
+            return mEndTimeMillis;
+        }
+
+        /**
+         * Gets number of UIDs with historical ops.
+         *
+         * @return The number of UIDs with historical ops.
+         *
+         * @see #getUidOpsAt(int)
+         */
+        public int getUidCount() {
+            if (mHistoricalUidOps == null) {
+                return 0;
+            }
+            return mHistoricalUidOps.size();
+        }
+
+        /**
+         * Gets the historical UID ops at a given index.
+         *
+         * @param index The index.
+         *
+         * @return The historical UID ops at the given index.
+         *
+         * @see #getUidCount()
+         */
+        public @NonNull HistoricalUidOps getUidOpsAt(int index) {
+            if (mHistoricalUidOps == null) {
+                throw new IndexOutOfBoundsException();
+            }
+            return mHistoricalUidOps.valueAt(index);
+        }
+
+        /**
+         * Gets the historical UID ops for a given UID.
+         *
+         * @param uid The UID.
+         *
+         * @return The historical ops for the UID.
+         */
+        public @Nullable HistoricalUidOps getUidOps(int uid) {
+            if (mHistoricalUidOps == null) {
+                return null;
+            }
+            return mHistoricalUidOps.get(uid);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel parcel, int flags) {
+            parcel.writeLong(mBeginTimeMillis);
+            parcel.writeLong(mEndTimeMillis);
+            if (mHistoricalUidOps != null) {
+                final int uidCount = mHistoricalUidOps.size();
+                parcel.writeInt(uidCount);
+                for (int i = 0; i < uidCount; i++) {
+                    parcel.writeInt(mHistoricalUidOps.keyAt(i));
+                }
+                final List<HistoricalUidOps> opsList = new ArrayList<>(uidCount);
+                for (int i = 0; i < uidCount; i++) {
+                    opsList.add(mHistoricalUidOps.valueAt(i));
+                }
+                parcel.writeParcelable(new ParceledListSlice<>(opsList), flags);
+            } else {
+                parcel.writeInt(-1);
+            }
+        }
+
+        /**
+         * Accepts a visitor to traverse the ops tree.
+         *
+         * @param visitor The visitor.
+         *
+         * @hide
+         */
+        public void accept(@NonNull HistoricalOpsVisitor visitor) {
+            visitor.visitHistoricalOps(this);
+            final int uidCount = getUidCount();
+            for (int i = 0; i < uidCount; i++) {
+                getUidOpsAt(i).accept(visitor);
+            }
+        }
+
+        private @NonNull HistoricalUidOps getOrCreateHistoricalUidOps(int uid) {
+            if (mHistoricalUidOps == null) {
+                mHistoricalUidOps = new SparseArray<>();
+            }
+            HistoricalUidOps historicalUidOp = mHistoricalUidOps.get(uid);
+            if (historicalUidOp == null) {
+                historicalUidOp = new HistoricalUidOps(uid);
+                mHistoricalUidOps.put(uid, historicalUidOp);
+            }
+            return historicalUidOp;
+        }
+
+        /**
+         * @return Rounded value up at the 0.5 boundary.
+         *
+         * @hide
+         */
+        public static double round(double value) {
+            final BigDecimal decimalScale = new BigDecimal(value);
+            return decimalScale.setScale(0, RoundingMode.HALF_UP).doubleValue();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null || getClass() != obj.getClass()) {
+                return false;
+            }
+            final HistoricalOps other = (HistoricalOps) obj;
+            if (mBeginTimeMillis != other.mBeginTimeMillis) {
+                return false;
+            }
+            if (mEndTimeMillis != other.mEndTimeMillis) {
+                return false;
+            }
+            if (mHistoricalUidOps == null) {
+                if (other.mHistoricalUidOps != null) {
+                    return false;
+                }
+            } else if (!mHistoricalUidOps.equals(other.mHistoricalUidOps)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = (int) (mBeginTimeMillis ^ (mBeginTimeMillis >>> 32));
+            result = 31 * result + mHistoricalUidOps.hashCode();
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getSimpleName() + "[from:"
+                    + mBeginTimeMillis + " to:" + mEndTimeMillis + "]";
+        }
+
+        public static final Creator<HistoricalOps> CREATOR = new Creator<HistoricalOps>() {
+            @Override
+            public @NonNull HistoricalOps createFromParcel(@NonNull Parcel parcel) {
+                return new HistoricalOps(parcel);
+            }
+
+            @Override
+            public @NonNull HistoricalOps[] newArray(int size) {
+                return new HistoricalOps[size];
+            }
+        };
+    }
+
+    /**
+     * This class represents historical app op state for a UID.
+     *
+     * @hide
+     */
+    @TestApi
+    @SystemApi
+    public static final class HistoricalUidOps implements Parcelable {
+        private final int mUid;
+        private @Nullable ArrayMap<String, HistoricalPackageOps> mHistoricalPackageOps;
+
+        /** @hide */
+        public HistoricalUidOps(int uid) {
+            mUid = uid;
+        }
+
+        private HistoricalUidOps(@NonNull HistoricalUidOps other) {
+            mUid = other.mUid;
+            final int opCount = other.getPackageCount();
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalPackageOps origOps = other.getPackageOpsAt(i);
+                final HistoricalPackageOps cloneOps = new HistoricalPackageOps(origOps);
+                if (mHistoricalPackageOps == null) {
+                    mHistoricalPackageOps = new ArrayMap<>(opCount);
+                }
+                mHistoricalPackageOps.put(cloneOps.getPackageName(), cloneOps);
+            }
+        }
+
+        private HistoricalUidOps(@NonNull Parcel parcel) {
+            // No arg check since we always read from a trusted source.
+            mUid = parcel.readInt();
+            mHistoricalPackageOps = parcel.createTypedArrayMap(HistoricalPackageOps.CREATOR);
+        }
+
+        private @Nullable HistoricalUidOps splice(double fractionToRemove) {
+            HistoricalUidOps splice = null;
+            final int packageCount = getPackageCount();
+            for (int i = 0; i < packageCount; i++) {
+                final HistoricalPackageOps origOps = getPackageOpsAt(i);
+                final HistoricalPackageOps spliceOps = origOps.splice(fractionToRemove);
+                if (spliceOps != null) {
+                    if (splice == null) {
+                        splice = new HistoricalUidOps(mUid);
+                    }
+                    if (splice.mHistoricalPackageOps == null) {
+                        splice.mHistoricalPackageOps = new ArrayMap<>();
+                    }
+                    splice.mHistoricalPackageOps.put(spliceOps.getPackageName(), spliceOps);
+                }
+            }
+            return splice;
+        }
+
+        private void merge(@NonNull HistoricalUidOps other) {
+            final int packageCount = other.getPackageCount();
+            for (int i = 0; i < packageCount; i++) {
+                final HistoricalPackageOps otherPackageOps = other.getPackageOpsAt(i);
+                final HistoricalPackageOps thisPackageOps = getPackageOps(
+                        otherPackageOps.getPackageName());
+                if (thisPackageOps != null) {
+                    thisPackageOps.merge(otherPackageOps);
+                } else {
+                    if (mHistoricalPackageOps == null) {
+                        mHistoricalPackageOps = new ArrayMap<>();
+                    }
+                    mHistoricalPackageOps.put(otherPackageOps.getPackageName(), otherPackageOps);
+                }
+            }
+        }
+
+        private void filter(@Nullable String packageName, @Nullable String[] opNames,
+                double fractionToRemove) {
+            final int packageCount = getPackageCount();
+            for (int i = packageCount - 1; i >= 0; i--) {
+                final HistoricalPackageOps packageOps = getPackageOpsAt(i);
+                if (packageName != null && !packageName.equals(packageOps.getPackageName())) {
+                    mHistoricalPackageOps.removeAt(i);
+                } else {
+                    packageOps.filter(opNames, fractionToRemove);
+                }
+            }
+        }
+
+        private boolean isEmpty() {
+            final int packageCount = getPackageCount();
+            for (int i = packageCount - 1; i >= 0; i--) {
+                final HistoricalPackageOps packageOps = mHistoricalPackageOps.valueAt(i);
+                if (!packageOps.isEmpty()) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private void increaseAccessCount(int opCode, @NonNull String packageName,
+                @UidState int uidState, long increment) {
+            getOrCreateHistoricalPackageOps(packageName).increaseAccessCount(
+                    opCode, uidState, increment);
+        }
+
+        private void increaseRejectCount(int opCode, @NonNull String packageName,
+                @UidState int uidState, long increment) {
+            getOrCreateHistoricalPackageOps(packageName).increaseRejectCount(
+                    opCode, uidState, increment);
+        }
+
+        private void increaseAccessDuration(int opCode, @NonNull String packageName,
+                @UidState int uidState, long increment) {
+            getOrCreateHistoricalPackageOps(packageName).increaseAccessDuration(
+                    opCode, uidState, increment);
+        }
+
+        /**
+         * @return The UID for which the data is related.
+         */
+        public int getUid() {
+            return mUid;
+        }
+
+        /**
+         * Gets number of packages with historical ops.
+         *
+         * @return The number of packages with historical ops.
+         *
+         * @see #getPackageOpsAt(int)
+         */
+        public int getPackageCount() {
+            if (mHistoricalPackageOps == null) {
+                return 0;
+            }
+            return mHistoricalPackageOps.size();
+        }
+
+        /**
+         * Gets the historical package ops at a given index.
+         *
+         * @param index The index.
+         *
+         * @return The historical package ops at the given index.
+         *
+         * @see #getPackageCount()
+         */
+        public @NonNull HistoricalPackageOps getPackageOpsAt(int index) {
+            if (mHistoricalPackageOps == null) {
+                throw new IndexOutOfBoundsException();
+            }
+            return mHistoricalPackageOps.valueAt(index);
+        }
+
+        /**
+         * Gets the historical package ops for a given package.
+         *
+         * @param packageName The package.
+         *
+         * @return The historical ops for the package.
+         */
+        public @Nullable HistoricalPackageOps getPackageOps(@NonNull String packageName) {
+            if (mHistoricalPackageOps == null) {
+                return null;
+            }
+            return mHistoricalPackageOps.get(packageName);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel parcel, int flags) {
+            parcel.writeInt(mUid);
+            parcel.writeTypedArrayMap(mHistoricalPackageOps, flags);
+        }
+
+        private void accept(@NonNull HistoricalOpsVisitor visitor) {
+            visitor.visitHistoricalUidOps(this);
+            final int packageCount = getPackageCount();
+            for (int i = 0; i < packageCount; i++) {
+                getPackageOpsAt(i).accept(visitor);
+            }
+        }
+
+        private @NonNull HistoricalPackageOps getOrCreateHistoricalPackageOps(
+                @NonNull String packageName) {
+            if (mHistoricalPackageOps == null) {
+                mHistoricalPackageOps = new ArrayMap<>();
+            }
+            HistoricalPackageOps historicalPackageOp = mHistoricalPackageOps.get(packageName);
+            if (historicalPackageOp == null) {
+                historicalPackageOp = new HistoricalPackageOps(packageName);
+                mHistoricalPackageOps.put(packageName, historicalPackageOp);
+            }
+            return historicalPackageOp;
+        }
+
+
+        public static final Creator<HistoricalUidOps> CREATOR = new Creator<HistoricalUidOps>() {
+            @Override
+            public @NonNull HistoricalUidOps createFromParcel(@NonNull Parcel parcel) {
+                return new HistoricalUidOps(parcel);
+            }
+
+            @Override
+            public @NonNull HistoricalUidOps[] newArray(int size) {
+                return new HistoricalUidOps[size];
+            }
+        };
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null || getClass() != obj.getClass()) {
+                return false;
+            }
+            final HistoricalUidOps other = (HistoricalUidOps) obj;
+            if (mUid != other.mUid) {
+                return false;
+            }
+            if (mHistoricalPackageOps == null) {
+                if (other.mHistoricalPackageOps != null) {
+                    return false;
+                }
+            } else if (!mHistoricalPackageOps.equals(other.mHistoricalPackageOps)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = mUid;
+            result = 31 * result + (mHistoricalPackageOps != null
+                    ? mHistoricalPackageOps.hashCode() : 0);
+            return result;
+        }
+    }
+
+    /**
+     * This class represents historical app op information about a package.
      *
      * @hide
      */
     @TestApi
     @SystemApi
     public static final class HistoricalPackageOps implements Parcelable {
-        private final int mUid;
         private final @NonNull String mPackageName;
-        private final @NonNull List<HistoricalOpEntry> mEntries;
+        private @Nullable ArrayMap<String, HistoricalOp> mHistoricalOps;
 
-        /**
-         * @hide
-         */
-        public HistoricalPackageOps(int uid, @NonNull String packageName) {
-            mUid = uid;
+        /** @hide */
+        public HistoricalPackageOps(@NonNull String packageName) {
             mPackageName = packageName;
-            mEntries = new ArrayList<>();
         }
 
-        HistoricalPackageOps(@NonNull Parcel parcel) {
-            mUid = parcel.readInt();
+        private HistoricalPackageOps(@NonNull HistoricalPackageOps other) {
+            mPackageName = other.mPackageName;
+            final int opCount = other.getOpCount();
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalOp origOp = other.getOpAt(i);
+                final HistoricalOp cloneOp = new HistoricalOp(origOp);
+                if (mHistoricalOps == null) {
+                    mHistoricalOps = new ArrayMap<>(opCount);
+                }
+                mHistoricalOps.put(cloneOp.getOpName(), cloneOp);
+            }
+        }
+
+        private HistoricalPackageOps(@NonNull Parcel parcel) {
             mPackageName = parcel.readString();
-            mEntries = parcel.createTypedArrayList(HistoricalOpEntry.CREATOR);
+            mHistoricalOps = parcel.createTypedArrayMap(HistoricalOp.CREATOR);
         }
 
-        /**
-         * @hide
-         */
-        public void addEntry(@NonNull HistoricalOpEntry entry) {
-            mEntries.add(entry);
+        private @Nullable HistoricalPackageOps splice(double fractionToRemove) {
+            HistoricalPackageOps splice = null;
+            final int opCount = getOpCount();
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalOp origOps = getOpAt(i);
+                final HistoricalOp spliceOps = origOps.splice(fractionToRemove);
+                if (spliceOps != null) {
+                    if (splice == null) {
+                        splice = new HistoricalPackageOps(mPackageName);
+                    }
+                    if (splice.mHistoricalOps == null) {
+                        splice.mHistoricalOps = new ArrayMap<>();
+                    }
+                    splice.mHistoricalOps.put(spliceOps.getOpName(), spliceOps);
+                }
+            }
+            return splice;
+        }
+
+        private void merge(@NonNull HistoricalPackageOps other) {
+            final int opCount = other.getOpCount();
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalOp otherOp = other.getOpAt(i);
+                final HistoricalOp thisOp = getOp(otherOp.getOpName());
+                if (thisOp != null) {
+                    thisOp.merge(otherOp);
+                } else {
+                    if (mHistoricalOps == null) {
+                        mHistoricalOps = new ArrayMap<>();
+                    }
+                    mHistoricalOps.put(otherOp.getOpName(), otherOp);
+                }
+            }
+        }
+
+        private void filter(@Nullable String[] opNames, double scaleFactor) {
+            final int opCount = getOpCount();
+            for (int i = opCount - 1; i >= 0; i--) {
+                final HistoricalOp op = mHistoricalOps.valueAt(i);
+                if (opNames != null && !ArrayUtils.contains(opNames, op.getOpName())) {
+                    mHistoricalOps.removeAt(i);
+                } else {
+                    op.filter(scaleFactor);
+                }
+            }
+        }
+
+        private boolean isEmpty() {
+            final int opCount = getOpCount();
+            for (int i = opCount - 1; i >= 0; i--) {
+                final HistoricalOp op = mHistoricalOps.valueAt(i);
+                if (!op.isEmpty()) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private void increaseAccessCount(int opCode, @UidState int uidState, long increment) {
+            getOrCreateHistoricalOp(opCode).increaseAccessCount(uidState, increment);
+        }
+
+        private void increaseRejectCount(int opCode, @UidState int uidState, long increment) {
+            getOrCreateHistoricalOp(opCode).increaseRejectCount(uidState, increment);
+        }
+
+        private void increaseAccessDuration(int opCode, @UidState int uidState, long increment) {
+            getOrCreateHistoricalOp(opCode).increaseAccessDuration(uidState, increment);
         }
 
         /**
@@ -2133,36 +2942,33 @@
         }
 
         /**
-         *  Gets the UID which the data represents.
+         * Gets number historical app ops.
          *
-         * @return The UID which the data represents.
+         * @return The number historical app ops.
+         *
+         * @see #getOpAt(int)
          */
-        public int getUid() {
-            return mUid;
+        public int getOpCount() {
+            if (mHistoricalOps == null) {
+                return 0;
+            }
+            return mHistoricalOps.size();
         }
 
         /**
-         * Gets number historical app op entries.
-         *
-         * @return The number historical app op entries.
-         *
-         * @see #getEntryAt(int)
-         */
-        public int getEntryCount() {
-            return mEntries.size();
-        }
-
-        /**
-         * Gets the historical at a given index.
+         * Gets the historical op at a given index.
          *
          * @param index The index to lookup.
          *
-         * @return The entry at the given index.
+         * @return The op at the given index.
          *
-         * @see #getEntryCount()
+         * @see #getOpCount()
          */
-        public @NonNull HistoricalOpEntry getEntryAt(int index) {
-            return mEntries.get(index);
+        public @NonNull HistoricalOp getOpAt(int index) {
+            if (mHistoricalOps == null) {
+                throw new IndexOutOfBoundsException();
+            }
+            return mHistoricalOps.valueAt(index);
         }
 
         /**
@@ -2172,15 +2978,11 @@
          *
          * @return The historical entry for that op name.
          */
-        public @Nullable HistoricalOpEntry getEntry(@NonNull String opName) {
-            final int entryCount = mEntries.size();
-            for (int i = 0; i < entryCount; i++) {
-                final HistoricalOpEntry entry = mEntries.get(i);
-                if (entry.getOp().equals(opName)) {
-                    return entry;
-                }
+        public @Nullable HistoricalOp getOp(@NonNull String opName) {
+            if (mHistoricalOps == null) {
+                return null;
             }
-            return null;
+            return mHistoricalOps.get(opName);
         }
 
         @Override
@@ -2190,9 +2992,29 @@
 
         @Override
         public void writeToParcel(@NonNull Parcel parcel, int flags) {
-            parcel.writeInt(mUid);
             parcel.writeString(mPackageName);
-            parcel.writeTypedList(mEntries, flags);
+            parcel.writeTypedArrayMap(mHistoricalOps, flags);
+        }
+
+        private void accept(@NonNull HistoricalOpsVisitor visitor) {
+            visitor.visitHistoricalPackageOps(this);
+            final int opCount = getOpCount();
+            for (int i = 0; i < opCount; i++) {
+                getOpAt(i).accept(visitor);
+            }
+        }
+
+        private @NonNull HistoricalOp getOrCreateHistoricalOp(int opCode) {
+            if (mHistoricalOps == null) {
+                mHistoricalOps = new ArrayMap<>();
+            }
+            final String opStr = sOpToString[opCode];
+            HistoricalOp op = mHistoricalOps.get(opStr);
+            if (op == null) {
+                op = new HistoricalOp(opCode);
+                mHistoricalOps.put(opStr, op);
+            }
+            return op;
         }
 
         public static final Creator<HistoricalPackageOps> CREATOR =
@@ -2207,49 +3029,177 @@
                 return new HistoricalPackageOps[size];
             }
         };
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null || getClass() != obj.getClass()) {
+                return false;
+            }
+            final HistoricalPackageOps other = (HistoricalPackageOps) obj;
+            if (!mPackageName.equals(other.mPackageName)) {
+                return false;
+            }
+            if (mHistoricalOps == null) {
+                if (other.mHistoricalOps != null) {
+                    return false;
+                }
+            } else if (!mHistoricalOps.equals(other.mHistoricalOps)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = mPackageName != null ? mPackageName.hashCode() : 0;
+            result = 31 * result + (mHistoricalOps != null ? mHistoricalOps.hashCode() : 0);
+            return result;
+        }
     }
 
     /**
-     * This class represents historical information about an app op. The history
-     * is aggregated information about the op for a certain amount of time such
-     * as the times the op was accessed, the times the op was rejected, the total
-     * duration the app op has been accessed.
+     * This class represents historical information about an app op.
      *
      * @hide
      */
     @TestApi
     @SystemApi
-    public static final class HistoricalOpEntry implements Parcelable {
+    public static final class HistoricalOp implements Parcelable {
         private final int mOp;
-        private final long[] mAccessCount;
-        private final long[] mRejectCount;
-        private final long[] mAccessDuration;
+        private @Nullable long[] mAccessCount;
+        private @Nullable long[] mRejectCount;
+        private @Nullable long[] mAccessDuration;
 
-        /**
-         * @hide
-         */
-        public HistoricalOpEntry(int op) {
+        /** @hide */
+        public HistoricalOp(int op) {
             mOp = op;
             mAccessCount = new long[_NUM_UID_STATE];
             mRejectCount = new long[_NUM_UID_STATE];
             mAccessDuration = new long[_NUM_UID_STATE];
         }
 
-        HistoricalOpEntry(@NonNull Parcel parcel) {
+        private HistoricalOp(@NonNull HistoricalOp other) {
+            mOp = other.mOp;
+            if (other.mAccessCount != null) {
+                System.arraycopy(other.mAccessCount, 0, getOrCreateAccessCount(),
+                        0, other.mAccessCount.length);
+            }
+            if (other.mRejectCount != null) {
+                System.arraycopy(other.mRejectCount, 0, getOrCreateRejectCount(),
+                        0, other.mRejectCount.length);
+            }
+            if (other.mAccessDuration != null) {
+                System.arraycopy(other.mAccessDuration, 0, getOrCreateAccessDuration(),
+                        0, other.mAccessDuration.length);
+            }
+        }
+
+        private HistoricalOp(@NonNull Parcel parcel) {
             mOp = parcel.readInt();
             mAccessCount = parcel.createLongArray();
             mRejectCount = parcel.createLongArray();
             mAccessDuration = parcel.createLongArray();
         }
 
-        /**
-         * @hide
-         */
-        public void addEntry(@UidState int uidState, long accessCount,
-                long rejectCount, long accessDuration) {
-            mAccessCount[uidState] = accessCount;
-            mRejectCount[uidState] = rejectCount;
-            mAccessDuration[uidState] = accessDuration;
+        private void filter(double scaleFactor) {
+            scale(mAccessCount, scaleFactor);
+            scale(mRejectCount, scaleFactor);
+            scale(mAccessDuration, scaleFactor);
+        }
+
+        private boolean isEmpty() {
+            return !hasData(mAccessCount)
+                    && !hasData(mRejectCount)
+                    && !hasData(mAccessDuration);
+        }
+
+        private boolean hasData(@NonNull long[] array) {
+            for (long value : array) {
+                if (value != 0) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private @Nullable HistoricalOp splice(double fractionToRemove) {
+            HistoricalOp splice = null;
+            if (mAccessCount != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    final long spliceAccessCount = Math.round(
+                            mAccessCount[i] * fractionToRemove);
+                    if (spliceAccessCount > 0) {
+                        if (splice == null) {
+                            splice = new HistoricalOp(mOp);
+                        }
+                        splice.getOrCreateAccessCount()[i] = spliceAccessCount;
+                        mAccessCount[i] -= spliceAccessCount;
+                    }
+                }
+            }
+
+            if (mRejectCount != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    final long spliceRejectCount = Math.round(
+                            mRejectCount[i] * fractionToRemove);
+
+                    if (spliceRejectCount > 0) {
+                        if (splice == null) {
+                            splice = new HistoricalOp(mOp);
+                        }
+                        splice.getOrCreateRejectCount()[i] = spliceRejectCount;
+                        mRejectCount[i] -= spliceRejectCount;
+                    }
+                }
+            }
+
+            if (mAccessDuration != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    final long spliceAccessDuration =  Math.round(
+                            mAccessDuration[i] * fractionToRemove);
+                    if (spliceAccessDuration > 0) {
+                        if (splice == null) {
+                            splice = new HistoricalOp(mOp);
+                        }
+                        splice.getOrCreateAccessDuration()[i] = spliceAccessDuration;
+                        mAccessDuration[i] -= spliceAccessDuration;
+                    }
+                }
+            }
+            return splice;
+        }
+
+        private void merge(@NonNull HistoricalOp other) {
+            if (other.mAccessCount != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    getOrCreateAccessCount()[i] += other.mAccessCount[i];
+                }
+            }
+            if (other.mRejectCount != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    getOrCreateRejectCount()[i] += other.mRejectCount[i];
+                }
+            }
+            if (other.mAccessDuration != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    getOrCreateAccessDuration()[i] += other.mAccessDuration[i];
+                }
+            }
+        }
+
+        private void increaseAccessCount(@UidState int uidState, long increment) {
+            getOrCreateAccessCount()[uidState] += increment;
+        }
+
+        private void increaseRejectCount(@UidState int uidState, long increment) {
+            getOrCreateRejectCount()[uidState] += increment;
+        }
+
+        private void increaseAccessDuration(@UidState int uidState, long increment) {
+            getOrCreateAccessDuration()[uidState] += increment;
         }
 
         /**
@@ -2257,10 +3207,15 @@
          *
          * @return The op name.
          */
-        public @NonNull String getOp() {
+        public @NonNull String getOpName() {
             return sOpToString[mOp];
         }
 
+        /** @hide */
+        public int getOpCode() {
+            return mOp;
+        }
+
         /**
          * Gets the number times the op was accessed (performed) in the foreground.
          *
@@ -2270,6 +3225,9 @@
          * @see #getAccessCount(int)
          */
         public long getForegroundAccessCount() {
+            if (mAccessCount == null) {
+                return 0;
+            }
             return sum(mAccessCount, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
         }
 
@@ -2282,6 +3240,9 @@
          * @see #getAccessCount(int)
          */
         public long getBackgroundAccessCount() {
+            if (mAccessCount == null) {
+                return 0;
+            }
             return sum(mAccessCount, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
         }
 
@@ -2299,6 +3260,9 @@
          * @see #getBackgroundAccessCount()
          */
         public long getAccessCount(@UidState int uidState) {
+            if (mAccessCount == null) {
+                return 0;
+            }
             return mAccessCount[uidState];
         }
 
@@ -2311,6 +3275,9 @@
          * @see #getRejectCount(int)
          */
         public long getForegroundRejectCount() {
+            if (mRejectCount == null) {
+                return 0;
+            }
             return sum(mRejectCount, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
         }
 
@@ -2323,6 +3290,9 @@
          * @see #getRejectCount(int)
          */
         public long getBackgroundRejectCount() {
+            if (mRejectCount == null) {
+                return 0;
+            }
             return sum(mRejectCount, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
         }
 
@@ -2340,6 +3310,9 @@
          * @see #getBackgroundRejectCount()
          */
         public long getRejectCount(@UidState int uidState) {
+            if (mRejectCount == null) {
+                return 0;
+            }
             return mRejectCount[uidState];
         }
 
@@ -2352,6 +3325,9 @@
          * @see #getAccessDuration(int)
          */
         public long getForegroundAccessDuration() {
+            if (mAccessDuration == null) {
+                return 0;
+            }
             return sum(mAccessDuration, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
         }
 
@@ -2364,6 +3340,9 @@
          * @see #getAccessDuration(int)
          */
         public long getBackgroundAccessDuration() {
+            if (mAccessDuration == null) {
+                return 0;
+            }
             return sum(mAccessDuration, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
         }
 
@@ -2381,6 +3360,9 @@
          * @see #getBackgroundAccessDuration()
          */
         public long getAccessDuration(@UidState int uidState) {
+            if (mAccessDuration == null) {
+                return 0;
+            }
             return mAccessDuration[uidState];
         }
 
@@ -2397,34 +3379,29 @@
             parcel.writeLongArray(mAccessDuration);
         }
 
-        @Override
-        public boolean equals(Object other) {
-            if (this == other) {
-                return true;
-            }
-            if (other == null || getClass() != other.getClass()) {
-                return false;
-            }
-            final HistoricalOpEntry otherInstance = (HistoricalOpEntry) other;
-            if (mOp != otherInstance.mOp) {
-                return false;
-            }
-            if (!Arrays.equals(mAccessCount, otherInstance.mAccessCount)) {
-                return false;
-            }
-            if (!Arrays.equals(mRejectCount, otherInstance.mRejectCount)) {
-                return false;
-            }
-            return Arrays.equals(mAccessDuration, otherInstance.mAccessDuration);
+        private void accept(@NonNull HistoricalOpsVisitor visitor) {
+            visitor.visitHistoricalOp(this);
         }
 
-        @Override
-        public int hashCode() {
-            int result = mOp;
-            result = 31 * result + Arrays.hashCode(mAccessCount);
-            result = 31 * result + Arrays.hashCode(mRejectCount);
-            result = 31 * result + Arrays.hashCode(mAccessDuration);
-            return result;
+        private @NonNull long[] getOrCreateAccessCount() {
+            if (mAccessCount == null) {
+                mAccessCount = new long[_NUM_UID_STATE];
+            }
+            return mAccessCount;
+        }
+
+        private @NonNull long[] getOrCreateRejectCount() {
+            if (mRejectCount == null) {
+                mRejectCount = new long[_NUM_UID_STATE];
+            }
+            return mRejectCount;
+        }
+
+        private @NonNull long[] getOrCreateAccessDuration() {
+            if (mAccessDuration == null) {
+                mAccessDuration = new long[_NUM_UID_STATE];
+            }
+            return mAccessDuration;
         }
 
         /**
@@ -2444,17 +3421,62 @@
             return totalCount;
         }
 
-        public static final Creator<HistoricalOpEntry> CREATOR = new Creator<HistoricalOpEntry>() {
+        /**
+         * Multiplies the entries in the array with the passed in scale factor and
+         * rounds the result at up 0.5 boundary.
+         *
+         * @param data The data to scale.
+         * @param scaleFactor The scale factor.
+         */
+        private static void scale(@NonNull long[] data, double scaleFactor) {
+            if (data != null) {
+                for (int i = 0; i < _NUM_UID_STATE; i++) {
+                    data[i] = (long) HistoricalOps.round((double) data[i] * scaleFactor);
+                }
+            }
+        }
+
+        public static final Creator<HistoricalOp> CREATOR = new Creator<HistoricalOp>() {
             @Override
-            public @NonNull HistoricalOpEntry createFromParcel(@NonNull Parcel source) {
-                return new HistoricalOpEntry(source);
+            public @NonNull HistoricalOp createFromParcel(@NonNull Parcel source) {
+                return new HistoricalOp(source);
             }
 
             @Override
-            public @NonNull HistoricalOpEntry[] newArray(int size) {
-                return new HistoricalOpEntry[size];
+            public @NonNull HistoricalOp[] newArray(int size) {
+                return new HistoricalOp[size];
             }
         };
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null || getClass() != obj.getClass()) {
+                return false;
+            }
+            final HistoricalOp other = (HistoricalOp) obj;
+            if (mOp != other.mOp) {
+                return false;
+            }
+            if (!Arrays.equals(mAccessCount, other.mAccessCount)) {
+                return false;
+            }
+            if (!Arrays.equals(mRejectCount, other.mRejectCount)) {
+                return false;
+            }
+            return Arrays.equals(mAccessDuration, other.mAccessDuration);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = mOp;
+            result = 31 * result + Arrays.hashCode(mAccessCount);
+            result = 31 * result + Arrays.hashCode(mRejectCount);
+            result = 31 * result + Arrays.hashCode(mAccessDuration);
+            return result;
+        }
     }
 
     /**
@@ -2520,6 +3542,24 @@
      * @param ops The set of operations you are interested in, or null if you want all of them.
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
+    public @NonNull List<AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[] ops) {
+        final int opCount = ops.length;
+        final int[] opCodes = new int[opCount];
+        for (int i = 0; i < opCount; i++) {
+            opCodes[i] = sOpStrToOp.get(ops[i]);
+        }
+        final List<AppOpsManager.PackageOps> result = getPackagesForOps(opCodes);
+        return (result != null) ? result : Collections.emptyList();
+    }
+
+    /**
+     * Retrieve current operation state for all applications.
+     *
+     * @param ops The set of operations you are interested in, or null if you want all of them.
+     * @hide
+     */
     @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
     @UnsupportedAppUsage
     public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
@@ -2536,11 +3576,17 @@
      * @param uid The uid of the application of interest.
      * @param packageName The name of the application of interest.
      * @param ops The set of operations you are interested in, or null if you want all of them.
+     *
+     * @deprecated The int op codes are not stable and you should use the string based op
+     * names which are stable and namespaced. Use
+     * {@link #getOpsForPackage(int, String, String...)})}.
+     *
      * @hide
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
-    public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
+    public List<PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
         try {
             return mService.getOpsForPackage(uid, packageName, ops);
         } catch (RemoteException e) {
@@ -2549,7 +3595,49 @@
     }
 
     /**
-     * Retrieve historical app op stats for a package.
+     * Retrieve current operation state for one application. The UID and the
+     * package must match.
+     *
+     * @param uid The uid of the application of interest.
+     * @param packageName The name of the application of interest.
+     * @param ops The set of operations you are interested in, or null if you want all of them.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
+    public @NonNull List<AppOpsManager.PackageOps> getOpsForPackage(int uid,
+            @NonNull String packageName, @Nullable String... ops) {
+        int[] opCodes = null;
+        if (ops != null) {
+            opCodes = new int[ops.length];
+            for (int i = 0; i < ops.length; i++) {
+                opCodes[i] = strOpToOp(ops[i]);
+            }
+        }
+        try {
+            final List<PackageOps> result = mService.getOpsForPackage(uid, packageName, opCodes);
+            if (result == null) {
+                return Collections.emptyList();
+            }
+            return result;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Retrieve historical app op stats for a period.
+     *
+     * <p>Historical data can be obtained
+     * for a specific package by specifying the <code>packageName</code> argument,
+     * for a specific UID if specifying the <code>uid</code> argument, for a
+     * specific package in a UID by specifying the <code>packageName</code>
+     * and the <code>uid</code> arguments, for all packages by passing
+     * {@link android.os.Process#INVALID_UID} and <code>null</code> for the
+     *  <code>uid</code> and <code>packageName</code> arguments, respectively.
+     *  Similarly, you can specify the <code>opNames</code> argument to get
+     *  data only for these ops or <code>null</code> for all ops.
      *
      * @param uid The UID to query for.
      * @param packageName The package to query for.
@@ -2558,10 +3646,12 @@
      *     negative.
      * @param endTimeMillis The end of the interval in milliseconds since
      *     epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be after
-     *     {@code beginTimeMillis}.
+     *     {@code beginTimeMillis}. Pass {@link Long#MAX_VALUE} to get the most recent
+     *     history including ops that happen while this call is in flight.
      * @param opNames The ops to query for. Pass {@code null} for all ops.
-     *
-     * @return The historical ops or {@code null} if there are no ops for this package.
+     * @param executor Executor on which to run the callback. If <code>null</code>
+     *     the callback is executed on the default executor running on the main thread.
+     * @param callback Callback on which to deliver the result.
      *
      * @throws IllegalArgumentException If any of the argument contracts is violated.
      *
@@ -2570,47 +3660,78 @@
     @TestApi
     @SystemApi
     @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
-    public @Nullable HistoricalPackageOps getHistoricalPackagesOps(
-            int uid, @NonNull String packageName, @Nullable String[] opNames,
-            long beginTimeMillis, long endTimeMillis) {
+    public void getHistoricalOps(int uid, @Nullable String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @NonNull Executor executor, @NonNull Consumer<HistoricalOps> callback) {
+        Preconditions.checkNotNull(executor, "executor cannot be null");
+        Preconditions.checkNotNull(callback, "callback cannot be null");
         try {
-            return mService.getHistoricalPackagesOps(uid, packageName, opNames,
-                    beginTimeMillis, endTimeMillis);
+            mService.getHistoricalOps(uid, packageName, opNames, beginTimeMillis, endTimeMillis,
+                    new RemoteCallback((result) -> {
+                final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() -> callback.accept(ops));
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Retrieve historical app op stats for all packages.
+     * Retrieve historical app op stats for a period.
      *
+     * <p>Historical data can be obtained
+     * for a specific package by specifying the <code>packageName</code> argument,
+     * for a specific UID if specifying the <code>uid</code> argument, for a
+     * specific package in a UID by specifying the <code>packageName</code>
+     * and the <code>uid</code> arguments, for all packages by passing
+     * {@link android.os.Process#INVALID_UID} and <code>null</code> for the
+     *  <code>uid</code> and <code>packageName</code> arguments, respectively.
+     *  Similarly, you can specify the <code>opNames</code> argument to get
+     *  data only for these ops or <code>null</code> for all ops.
+     *  <p>
+     *  This method queries only the on disk state and the returned ops are raw,
+     *  which is their times are relative to the history start as opposed to the
+     *  epoch start.
+     *
+     * @param uid The UID to query for.
+     * @param packageName The package to query for.
      * @param beginTimeMillis The beginning of the interval in milliseconds since
-     *     epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be non
-     *     negative.
+     *      history start. History time grows as one goes into the past.
      * @param endTimeMillis The end of the interval in milliseconds since
-     *     epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be after
+     *      history start. History time grows as one goes into the past. Must be after
      *     {@code beginTimeMillis}.
      * @param opNames The ops to query for. Pass {@code null} for all ops.
-     *
-     * @return The historical ops or an empty list if there are no ops for any package.
+     * @param executor Executor on which to run the callback. If <code>null</code>
+     *     the callback is executed on the default executor running on the main thread.
+     * @param callback Callback on which to deliver the result.
      *
      * @throws IllegalArgumentException If any of the argument contracts is violated.
      *
      * @hide
      */
     @TestApi
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
-    public @NonNull List<HistoricalPackageOps> getAllHistoricPackagesOps(
-            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis) {
+    public void getHistoricalOpsFromDiskRaw(int uid, @Nullable String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @Nullable Executor executor, @NonNull Consumer<HistoricalOps> callback) {
+        Preconditions.checkNotNull(executor, "executor cannot be null");
+        Preconditions.checkNotNull(callback, "callback cannot be null");
         try {
-            @SuppressWarnings("unchecked")
-            final ParceledListSlice<HistoricalPackageOps> payload =
-                    mService.getAllHistoricalPackagesOps(opNames, beginTimeMillis, endTimeMillis);
-            if (payload != null) {
-                return payload.getList();
-            }
-            return Collections.emptyList();
+            mService.getHistoricalOpsFromDiskRaw(uid, packageName, opNames, beginTimeMillis,
+                    endTimeMillis, new RemoteCallback((result) -> {
+               final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() -> callback.accept(ops));
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2627,7 +3748,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
-    public void setUidMode(int code, int uid, int mode) {
+    public void setUidMode(int code, int uid, @Mode int mode) {
         try {
             mService.setUidMode(code, uid, mode);
         } catch (RemoteException e) {
@@ -2648,7 +3769,7 @@
     @SystemApi
     @TestApi
     @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
-    public void setUidMode(String appOp, int uid, int mode) {
+    public void setUidMode(String appOp, int uid, @Mode int mode) {
         try {
             mService.setUidMode(AppOpsManager.strOpToOp(appOp), uid, mode);
         } catch (RemoteException e) {
@@ -2680,7 +3801,7 @@
     /** @hide */
     @TestApi
     @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
-    public void setMode(int code, int uid, String packageName, int mode) {
+    public void setMode(int code, int uid, String packageName, @Mode int mode) {
         try {
             mService.setMode(code, uid, packageName, mode);
         } catch (RemoteException e) {
@@ -2701,7 +3822,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
-    public void setMode(String op, int uid, String packageName, int mode) {
+    public void setMode(String op, int uid, String packageName, @Mode int mode) {
         try {
             mService.setMode(strOpToOp(op), uid, packageName, mode);
         } catch (RemoteException e) {
@@ -2722,7 +3843,7 @@
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
     @UnsupportedAppUsage
-    public void setRestriction(int code, @AttributeUsage int usage, int mode,
+    public void setRestriction(int code, @AttributeUsage int usage, @Mode int mode,
             String[] exceptionPackages) {
         try {
             final int uid = Binder.getCallingUid();
@@ -3507,6 +4628,104 @@
     }
 
     /**
+     * Configures the app ops persistence for testing.
+     *
+     * @param mode The mode in which the historical registry operates.
+     * @param baseSnapshotInterval The base interval on which we would be persisting a snapshot of
+     *   the historical data. The history is recursive where every subsequent step encompasses
+     *   {@code compressionStep} longer interval with {@code compressionStep} distance between
+     *    snapshots.
+     * @param compressionStep The compression step in every iteration.
+     *
+     * @see #HISTORICAL_MODE_DISABLED
+     * @see #HISTORICAL_MODE_ENABLED_ACTIVE
+     * @see #HISTORICAL_MODE_ENABLED_PASSIVE
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+    public void setHistoryParameters(@HistoricalMode int mode, long baseSnapshotInterval,
+            int compressionStep) {
+        try {
+            mService.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Offsets the history by the given duration.
+     *
+     * @param offsetMillis The offset duration.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+    public void offsetHistory(long offsetMillis) {
+        try {
+            mService.offsetHistory(offsetMillis);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Adds ops to the history directly. This could be useful for testing especially
+     * when the historical registry operates in {@link #HISTORICAL_MODE_ENABLED_PASSIVE}
+     * mode.
+     *
+     * @param ops The ops to add to the history.
+     *
+     * @see #setHistoryParameters(int, long, int)
+     * @see #HISTORICAL_MODE_ENABLED_PASSIVE
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+    public void addHistoricalOps(@NonNull HistoricalOps ops) {
+        try {
+            mService.addHistoricalOps(ops);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Resets the app ops persistence for testing.
+     *
+     * @see #setHistoryParameters(int, long, int)
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+    public void resetHistoryParameters() {
+        try {
+            mService.resetHistoryParameters();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Clears all app ops history.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+    public void clearHistory() {
+        try {
+            mService.clearHistory();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns all supported operation names.
      * @hide
      */
@@ -3538,4 +4757,81 @@
         }
         return time;
     }
+
+    /** @hide */
+    public static String uidStateToString(@UidState int uidState) {
+        switch (uidState) {
+            case UID_STATE_PERSISTENT: {
+                return "UID_STATE_PERSISTENT";
+            }
+            case UID_STATE_TOP: {
+                return "UID_STATE_TOP";
+            }
+            case UID_STATE_FOREGROUND_SERVICE: {
+                return "UID_STATE_FOREGROUND_SERVICE";
+            }
+            case UID_STATE_FOREGROUND: {
+                return "UID_STATE_FOREGROUND";
+            }
+            case UID_STATE_BACKGROUND: {
+                return "UID_STATE_BACKGROUND";
+            }
+            case UID_STATE_CACHED: {
+                return "UID_STATE_CACHED";
+            }
+            default: {
+                return "UNKNOWN";
+            }
+        }
+    }
+
+    /** @hide */
+    public static int parseHistoricalMode(@NonNull String mode) {
+        switch (mode) {
+            case "HISTORICAL_MODE_ENABLED_ACTIVE": {
+                return HISTORICAL_MODE_ENABLED_ACTIVE;
+            }
+            case "HISTORICAL_MODE_ENABLED_PASSIVE": {
+                return HISTORICAL_MODE_ENABLED_PASSIVE;
+            }
+            default: {
+                return HISTORICAL_MODE_DISABLED;
+            }
+        }
+    }
+
+    /** @hide */
+    public static String historicalModeToString(@HistoricalMode int mode) {
+        switch (mode) {
+            case HISTORICAL_MODE_DISABLED: {
+                return "HISTORICAL_MODE_DISABLED";
+            }
+            case HISTORICAL_MODE_ENABLED_ACTIVE: {
+                return "HISTORICAL_MODE_ENABLED_ACTIVE";
+            }
+            case HISTORICAL_MODE_ENABLED_PASSIVE: {
+                return "HISTORICAL_MODE_ENABLED_PASSIVE";
+            }
+            default: {
+                return "UNKNOWN";
+            }
+        }
+    }
+
+    private static int getSystemAlertWindowDefault() {
+        final Context context = ActivityThread.currentApplication();
+        if (context == null) {
+            return AppOpsManager.MODE_DEFAULT;
+        }
+
+        // system alert window is disable on low ram phones starting from Q
+        final PackageManager pm = context.getPackageManager();
+        // TVs are constantly plugged in and has less concern for memory/power
+        if (ActivityManager.isLowRamDeviceStatic()
+                && !pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK, 0)) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+
+        return AppOpsManager.MODE_DEFAULT;
+    }
 }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 94983e1..9bcb36f 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2276,6 +2276,16 @@
     }
 
     @Override
+    public String[] setDistractingPackageRestrictions(String[] packages, int distractionFlags) {
+        try {
+            return mPM.setDistractingPackageRestrictionsAsUser(packages, distractionFlags,
+                    mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
     public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
             PersistableBundle appExtras, PersistableBundle launcherExtras,
             String dialogMessage) {
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index b5295d1..07dbb6b 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -124,6 +124,10 @@
     /** Restart the activity after it was stopped. */
     public abstract void performRestartActivity(IBinder token, boolean start);
 
+    /** Set pending activity configuration in case it will be updated by other transaction item. */
+    public abstract void updatePendingActivityConfiguration(IBinder activityToken,
+            Configuration overrideConfig);
+
     /** Deliver activity (override) configuration change. */
     public abstract void handleActivityConfigurationChanged(IBinder activityToken,
             Configuration overrideConfig, int displayId);
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 4bd935c..088c245 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -31,7 +31,7 @@
 import android.content.DialogInterface;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
-import android.content.res.ResourceId;
+import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Build;
@@ -183,7 +183,7 @@
 
     Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
         if (createContextThemeWrapper) {
-            if (themeResId == ResourceId.ID_NULL) {
+            if (themeResId == Resources.ID_NULL) {
                 final TypedValue outValue = new TypedValue();
                 context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
                 themeResId = outValue.resourceId;
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 1622c06..853b45e 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1324,7 +1324,8 @@
      * @param description the description that would appear for this file in Downloads App.
      * @param isMediaScannerScannable true if the file is to be scanned by MediaScanner. Files
      * scanned by MediaScanner appear in the applications used to view media (for example,
-     * Gallery app).
+     * Gallery app). Starting from {@link android.os.Build.VERSION_CODES#Q}, this argument is
+     * ignored and the file is always scanned by MediaScanner.
      * @param mimeType mimetype of the file.
      * @param path absolute pathname to the file. The file should be world-readable, so that it can
      * be managed by the Downloads App and any other app that is used to read it (for example,
@@ -1353,7 +1354,8 @@
      * @param description the description that would appear for this file in Downloads App.
      * @param isMediaScannerScannable true if the file is to be scanned by MediaScanner. Files
      * scanned by MediaScanner appear in the applications used to view media (for example,
-     * Gallery app).
+     * Gallery app). Starting from {@link android.os.Build.VERSION_CODES#Q}, this argument is
+     * ignored and the file is always scanned by MediaScanner.
      * @param mimeType mimetype of the file.
      * @param path absolute pathname to the file. The file should be world-readable, so that it can
      * be managed by the Downloads App and any other app that is used to read it (for example,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index fb519b6..fb65da1 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -317,7 +317,6 @@
      */
     void requestWifiBugReport(in String shareTitle, in String shareDescription);
 
-    void clearPendingBackup();
     Intent getIntentForIntentSender(in IIntentSender sender);
     // This is not public because you need to be very careful in how you
     // manage your activity to make sure it is always the uid you expect.
@@ -421,7 +420,6 @@
     void resizeDockedStack(in Rect dockedBounds, in Rect tempDockedTaskBounds,
             in Rect tempDockedTaskInsetBounds,
             in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds);
-    boolean isAppForeground(int uid);
     void removeStack(int stackId);
     void makePackageIdle(String packageName, int userId);
     int getMemoryTrimLevel();
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index dd87dc3..cc6c999 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -419,6 +419,7 @@
     void updateLockTaskFeatures(int userId, int flags);
 
     void setShowWhenLocked(in IBinder token, boolean showWhenLocked);
+    void setInheritShowWhenLocked(in IBinder token, boolean setInheritShownWhenLocked);
     void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
 
     /**
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 163be8e..199c133 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -65,9 +65,9 @@
     boolean areNotificationsEnabled(String pkg);
     int getPackageImportance(String pkg);
 
-    void setAppOverlaysAllowed(String pkg, int uid, boolean allowed);
-    boolean areAppOverlaysAllowed(String pkg);
-    boolean areAppOverlaysAllowedForPackage(String pkg, int uid);
+    void setBubblesAllowed(String pkg, int uid, boolean allowed);
+    boolean areBubblesAllowed(String pkg);
+    boolean areBubblesAllowedForPackage(String pkg, int uid);
 
     void createNotificationChannelGroups(String pkg, in ParceledListSlice channelGroupList);
     void createNotificationChannels(String pkg, in ParceledListSlice channelsList);
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 3a2038d..666f721 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -142,19 +142,20 @@
      *
      * @param which either {@link WallpaperManager#FLAG_LOCK}
      * or {@link WallpaperManager#FLAG_SYSTEM}
+     * @param displayId Which display is interested
      * @return colors of chosen wallpaper
      */
-    WallpaperColors getWallpaperColors(int which, int userId);
+    WallpaperColors getWallpaperColors(int which, int userId, int displayId);
 
     /**
-     * Register a callback to receive color updates
+     * Register a callback to receive color updates from a display
      */
-    void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId);
+    void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, int displayId);
 
     /**
-     * Unregister a callback that was receiving color updates
+     * Unregister a callback that was receiving color updates from a display
      */
-    void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId);
+    void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, int displayId);
 
     /**
      * Called from SystemUI when it shows the AoD UI.
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 1ae0f52..75c9054 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -124,6 +125,7 @@
      *
      * @return the intent for launching the activity or null if no password is required.
      **/
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
         if (!isDeviceSecure()) return null;
         Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
@@ -176,6 +178,7 @@
      * @throws IllegalStateException if the device has already been provisioned
      * @hide
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     @SystemApi
     public Intent createConfirmFactoryResetCredentialIntent(
             CharSequence title, CharSequence description, CharSequence alternateButtonLabel) {
@@ -231,6 +234,7 @@
      * secure notifications cannot be shown if {@code false}
      * @hide
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)
     @SystemApi
     public void setPrivateNotificationsAllowed(boolean allow) {
@@ -249,6 +253,7 @@
      * By default, private notifications are allowed.
      * @hide
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)
     @SystemApi
     public boolean getPrivateNotificationsAllowed() {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e066f06..b8d748d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -384,9 +384,7 @@
         STANDARD_LAYOUTS.add(R.layout.notification_template_material_messaging);
         STANDARD_LAYOUTS.add(R.layout.notification_template_material_media);
         STANDARD_LAYOUTS.add(R.layout.notification_template_material_big_media);
-        STANDARD_LAYOUTS.add(R.layout.notification_template_ambient_header);
         STANDARD_LAYOUTS.add(R.layout.notification_template_header);
-        STANDARD_LAYOUTS.add(R.layout.notification_template_material_ambient);
     }
 
     /**
@@ -1276,7 +1274,7 @@
     private String mShortcutId;
     private CharSequence mSettingsText;
 
-    private PendingIntent mAppOverlayIntent;
+    private BubbleMetadata mBubbleMetadata;
 
     /** @hide */
     @IntDef(prefix = { "GROUP_ALERT_" }, value = {
@@ -1427,18 +1425,13 @@
          */
         public static final int SEMANTIC_ACTION_CALL = 10;
 
-        /**
-         * {@code SemanticAction}: Contextual action - dependent on the current notification. E.g.
-         * open a Map application with an address shown in the notification.
-         */
-        public static final int SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION = 11;
-
         private final Bundle mExtras;
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         private Icon mIcon;
         private final RemoteInput[] mRemoteInputs;
         private boolean mAllowGeneratedReplies = true;
         private final @SemanticAction int mSemanticAction;
+        private final boolean mIsContextual;
 
         /**
          * Small icon representing the action.
@@ -1474,6 +1467,7 @@
             mRemoteInputs = in.createTypedArray(RemoteInput.CREATOR);
             mAllowGeneratedReplies = in.readInt() == 1;
             mSemanticAction = in.readInt();
+            mIsContextual = in.readInt() == 1;
         }
 
         /**
@@ -1482,13 +1476,13 @@
         @Deprecated
         public Action(int icon, CharSequence title, PendingIntent intent) {
             this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, true,
-                    SEMANTIC_ACTION_NONE);
+                    SEMANTIC_ACTION_NONE, false /* isContextual */);
         }
 
         /** Keep in sync with {@link Notification.Action.Builder#Builder(Action)}! */
         private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
                 RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
-                       @SemanticAction int semanticAction) {
+                       @SemanticAction int semanticAction, boolean isContextual) {
             this.mIcon = icon;
             if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
                 this.icon = icon.getResId();
@@ -1499,6 +1493,7 @@
             this.mRemoteInputs = remoteInputs;
             this.mAllowGeneratedReplies = allowGeneratedReplies;
             this.mSemanticAction = semanticAction;
+            this.mIsContextual = isContextual;
         }
 
         /**
@@ -1546,6 +1541,15 @@
         }
 
         /**
+         * Returns whether this is a contextual Action, i.e. whether the action is dependent on the
+         * notification message body. An example of a contextual action could be an action opening a
+         * map application with an address shown in the notification.
+         */
+        public boolean isContextual() {
+            return mIsContextual;
+        }
+
+        /**
          * Get the list of inputs to be collected from the user that ONLY accept data when this
          * action is sent. These remote inputs are guaranteed to return true on a call to
          * {@link RemoteInput#isDataOnly}.
@@ -1570,6 +1574,7 @@
             private final Bundle mExtras;
             private ArrayList<RemoteInput> mRemoteInputs;
             private @SemanticAction int mSemanticAction;
+            private boolean mIsContextual;
 
             /**
              * Construct a new builder for {@link Action} object.
@@ -1684,6 +1689,16 @@
             }
 
             /**
+             * Sets whether this {@link Action} is a contextual action, i.e. whether the action is
+             * dependent on the notification message body. An example of a contextual action could
+             * be an action opening a map application with an address shown in the notification.
+             */
+            public Builder setContextual(boolean isContextual) {
+                mIsContextual = isContextual;
+                return this;
+            }
+
+            /**
              * Apply an extender to this action builder. Extenders may be used to add
              * metadata or change options on this builder.
              */
@@ -1697,7 +1712,7 @@
              * necessary to display the action.
              */
             private void checkContextualActionNullFields() {
-                if (mSemanticAction != SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION) return;
+                if (!mIsContextual) return;
 
                 if (mIcon == null) {
                     throw new NullPointerException("Contextual Actions must contain a valid icon");
@@ -1743,7 +1758,7 @@
                 RemoteInput[] textInputsArr = textInputs.isEmpty()
                         ? null : textInputs.toArray(new RemoteInput[textInputs.size()]);
                 return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr,
-                        mAllowGeneratedReplies, mSemanticAction);
+                        mAllowGeneratedReplies, mSemanticAction, mIsContextual);
             }
         }
 
@@ -1756,7 +1771,8 @@
                     mExtras == null ? new Bundle() : new Bundle(mExtras),
                     getRemoteInputs(),
                     getAllowGeneratedReplies(),
-                    getSemanticAction());
+                    getSemanticAction(),
+                    isContextual());
         }
 
         @Override
@@ -1784,6 +1800,7 @@
             out.writeTypedArray(mRemoteInputs, flags);
             out.writeInt(mAllowGeneratedReplies ? 1 : 0);
             out.writeInt(mSemanticAction);
+            out.writeInt(mIsContextual ? 1 : 0);
         }
 
         public static final Parcelable.Creator<Action> CREATOR =
@@ -2073,8 +2090,7 @@
                 SEMANTIC_ACTION_UNMUTE,
                 SEMANTIC_ACTION_THUMBS_UP,
                 SEMANTIC_ACTION_THUMBS_DOWN,
-                SEMANTIC_ACTION_CALL,
-                SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION
+                SEMANTIC_ACTION_CALL
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface SemanticAction {}
@@ -2260,7 +2276,7 @@
 
         mGroupAlertBehavior = parcel.readInt();
         if (parcel.readInt() != 0) {
-            mAppOverlayIntent = PendingIntent.CREATOR.createFromParcel(parcel);
+            mBubbleMetadata = BubbleMetadata.CREATOR.createFromParcel(parcel);
         }
 
         mAllowSystemGeneratedContextualActions = parcel.readBoolean();
@@ -2378,7 +2394,7 @@
         that.mBadgeIcon = this.mBadgeIcon;
         that.mSettingsText = this.mSettingsText;
         that.mGroupAlertBehavior = this.mGroupAlertBehavior;
-        that.mAppOverlayIntent = this.mAppOverlayIntent;
+        that.mBubbleMetadata = this.mBubbleMetadata;
         that.mAllowSystemGeneratedContextualActions = this.mAllowSystemGeneratedContextualActions;
 
         if (!heavy) {
@@ -2701,9 +2717,9 @@
 
         parcel.writeInt(mGroupAlertBehavior);
 
-        if (mAppOverlayIntent != null) {
+        if (mBubbleMetadata != null) {
             parcel.writeInt(1);
-            mAppOverlayIntent.writeToParcel(parcel, 0);
+            mBubbleMetadata.writeToParcel(parcel, 0);
         } else {
             parcel.writeInt(0);
         }
@@ -3123,11 +3139,11 @@
     }
 
     /**
-     * Returns the intent that will be used to display app content in a floating window over the
-     * existing foreground activity.
+     * Returns the bubble metadata that will be used to display app content in a floating window
+     * over the existing foreground activity.
      */
-    public PendingIntent getAppOverlayIntent() {
-        return mAppOverlayIntent;
+    public BubbleMetadata getBubbleMetadata() {
+        return mBubbleMetadata;
     }
 
     /**
@@ -3230,8 +3246,7 @@
     }
 
     /**
-     * Returns the actions that are contextual (marked as SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION) out
-     * of the actions in this notification.
+     * Returns the actions that are contextual out of the actions in this notification.
      *
      * @hide
      */
@@ -3240,8 +3255,7 @@
 
         List<Notification.Action> contextualActions = new ArrayList<>();
         for (Notification.Action action : actions) {
-            if (action.getSemanticAction()
-                    == Notification.Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION) {
+            if (action.isContextual()) {
                 contextualActions.add(action);
             }
         }
@@ -3492,19 +3506,18 @@
         }
 
         /**
-         * Sets the intent that will be used to display app content in a floating window
-         * over the existing foreground activity.
+         * Sets the {@link BubbleMetadata} that will be used to display app content in a floating
+         * window over the existing foreground activity.
          *
-         * <p>This intent will be ignored unless this notification is posted to a channel that
-         * allows {@link NotificationChannel#canOverlayApps() app overlays}.</p>
+         * <p>This data will be ignored unless the notification is posted to a channel that
+         * allows {@link NotificationChannel#canBubble() bubbles}.</p>
          *
-         * <p>Notifications with a valid and allowed app overlay intent will be displayed as
-         * floating windows outside of the notification shade on unlocked devices. When a user
-         * interacts with one of these windows, this app overlay intent will be invoked and
-         * displayed.</p>
+         * <b>Notifications with a valid and allowed bubble metadata will display in collapsed state
+         * outside of the notification shade on unlocked devices. When a user interacts with the
+         * collapsed state, the bubble intent will be invoked and displayed.</b>
          */
-        public Builder setAppOverlayIntent(PendingIntent intent) {
-            mN.mAppOverlayIntent = intent;
+        public Builder setBubbleMetadata(BubbleMetadata data) {
+            mN.mBubbleMetadata = data;
             return this;
         }
 
@@ -4555,9 +4568,7 @@
             if (p.title != null) {
                 contentView.setViewVisibility(R.id.title, View.VISIBLE);
                 contentView.setTextViewText(R.id.title, processTextSpans(p.title));
-                if (!p.ambient) {
-                    setTextViewColorPrimary(contentView, R.id.title, p);
-                }
+                setTextViewColorPrimary(contentView, R.id.title, p);
                 contentView.setViewLayoutWidth(R.id.title, showProgress
                         ? ViewGroup.LayoutParams.WRAP_CONTENT
                         : ViewGroup.LayoutParams.MATCH_PARENT);
@@ -4566,9 +4577,7 @@
                 int textId = showProgress ? com.android.internal.R.id.text_line_1
                         : com.android.internal.R.id.text;
                 contentView.setTextViewText(textId, processTextSpans(p.text));
-                if (!p.ambient) {
-                    setTextViewColorSecondary(contentView, textId, p);
-                }
+                setTextViewColorSecondary(contentView, textId, p);
                 contentView.setViewVisibility(textId, View.VISIBLE);
             }
 
@@ -4827,7 +4836,7 @@
             if (mN.mLargeIcon == null && mN.largeIcon != null) {
                 mN.mLargeIcon = Icon.createWithBitmap(mN.largeIcon);
             }
-            boolean showLargeIcon = mN.mLargeIcon != null && !p.hideLargeIcon && !p.ambient;
+            boolean showLargeIcon = mN.mLargeIcon != null && !p.hideLargeIcon;
             if (showLargeIcon) {
                 contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
                 contentView.setImageViewIcon(R.id.right_icon, mN.mLargeIcon);
@@ -4841,7 +4850,7 @@
          * @return if the reply icon is visible
          */
         private boolean bindReplyIcon(RemoteViews contentView, StandardTemplateParams p) {
-            boolean actionVisible = !p.hideReplyIcon && !p.ambient;
+            boolean actionVisible = !p.hideReplyIcon;
             Action action = null;
             if (actionVisible) {
                 action = findReplyAction();
@@ -4881,21 +4890,18 @@
         private void bindNotificationHeader(RemoteViews contentView, StandardTemplateParams p) {
             bindSmallIcon(contentView, p);
             bindHeaderAppName(contentView, p);
-            if (!p.ambient) {
-                // Ambient view does not have these
-                bindHeaderText(contentView, p);
-                bindHeaderTextSecondary(contentView, p);
-                bindHeaderChronometerAndTime(contentView, p);
-                bindProfileBadge(contentView, p);
-                bindAlertedIcon(contentView, p);
-            }
+            bindHeaderText(contentView, p);
+            bindHeaderTextSecondary(contentView, p);
+            bindHeaderChronometerAndTime(contentView, p);
+            bindProfileBadge(contentView, p);
+            bindAlertedIcon(contentView, p);
             bindActivePermissions(contentView, p);
             bindExpandButton(contentView, p);
             mN.mUsesStandardHeader = true;
         }
 
         private void bindActivePermissions(RemoteViews contentView, StandardTemplateParams p) {
-            int color = p.ambient ? resolveAmbientColor(p) : getNeutralColor(p);
+            int color = getNeutralColor(p);
             contentView.setDrawableTint(R.id.camera, false, color, PorterDuff.Mode.SRC_ATOP);
             contentView.setDrawableTint(R.id.mic, false, color, PorterDuff.Mode.SRC_ATOP);
             contentView.setDrawableTint(R.id.overlay, false, color, PorterDuff.Mode.SRC_ATOP);
@@ -5006,13 +5012,12 @@
             if (isColorized(p)) {
                 setTextViewColorPrimary(contentView, R.id.app_name_text, p);
             } else {
-                contentView.setTextColor(R.id.app_name_text,
-                        p.ambient ? resolveAmbientColor(p) : getSecondaryTextColor(p));
+                contentView.setTextColor(R.id.app_name_text, getSecondaryTextColor(p));
             }
         }
 
         private boolean isColorized(StandardTemplateParams p) {
-            return p.allowColorization && !p.ambient && mN.isColorized();
+            return p.allowColorization && mN.isColorized();
         }
 
         private void bindSmallIcon(RemoteViews contentView, StandardTemplateParams p) {
@@ -5062,8 +5067,7 @@
                 List<Notification.Action> actions) {
             List<Notification.Action> nonContextualActions = new ArrayList<>();
             for (Notification.Action action : actions) {
-                if (action.getSemanticAction()
-                        != Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION) {
+                if (!action.isContextual()) {
                     nonContextualActions.add(action);
                 }
             }
@@ -5083,7 +5087,7 @@
             List<Notification.Action> nonContextualActions = filterOutContextualActions(mActions);
 
             int N = nonContextualActions.size();
-            boolean emphazisedMode = mN.fullScreenIntent != null && !p.ambient;
+            boolean emphazisedMode = mN.fullScreenIntent != null;
             big.setBoolean(R.id.actions, "setEmphasizedMode", emphazisedMode);
             if (N > 0) {
                 big.setViewVisibility(R.id.actions_container, View.VISIBLE);
@@ -5108,7 +5112,7 @@
             }
 
             CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
-            if (!p.ambient && validRemoteInput && replyText != null
+            if (validRemoteInput && replyText != null
                     && replyText.length > 0 && !TextUtils.isEmpty(replyText[0])
                     && p.maxRemoteInputHistory > 0) {
                 boolean showSpinner = mN.extras.getBoolean(EXTRA_SHOW_REMOTE_INPUT_SPINNER);
@@ -5225,11 +5229,10 @@
          * Construct a RemoteViews for the final notification header only. This will not be
          * colorized.
          *
-         * @param ambient if true, generate the header for the ambient display layout.
          * @hide
          */
-        public RemoteViews makeNotificationHeader(boolean ambient) {
-            return makeNotificationHeader(mParams.reset().ambient(ambient).fillTextsFrom(this));
+        public RemoteViews makeNotificationHeader() {
+            return makeNotificationHeader(mParams.reset().fillTextsFrom(this));
         }
 
         /**
@@ -5242,8 +5245,7 @@
             // Headers on their own are never colorized
             p.disallowColorization();
             RemoteViews header = new BuilderRemoteViews(mContext.getApplicationInfo(),
-                    p.ambient ? R.layout.notification_template_ambient_header
-                            : R.layout.notification_template_header);
+                    R.layout.notification_template_header);
             resetNotificationHeader(header);
             bindNotificationHeader(header, p);
             return header;
@@ -5255,11 +5257,7 @@
          * @hide
          */
         public RemoteViews makeAmbientNotification() {
-            RemoteViews ambient = applyStandardTemplateWithActions(
-                    R.layout.notification_template_material_ambient,
-                    mParams.reset().ambient(true).fillTextsFrom(this).hasProgress(false),
-                    null /* result */);
-            return ambient;
+            return createHeadsUpContentView(false /* increasedHeight */);
         }
 
         private void hideLine1Text(RemoteViews result) {
@@ -5363,14 +5361,8 @@
             }
             mN.extras = publicExtras;
             RemoteViews view;
-            if (ambient) {
-                publicExtras.putCharSequence(EXTRA_TITLE,
-                        mContext.getString(com.android.internal.R.string.notification_hidden_text));
-                view = makeAmbientNotification();
-            } else{
-                view = makeNotificationHeader(false /* ambient */);
-                view.setBoolean(R.id.notification_header, "setExpandOnlyOnButton", true);
-            }
+            view = makeNotificationHeader();
+            view.setBoolean(R.id.notification_header, "setExpandOnlyOnButton", true);
             mN.extras = savedBundle;
             mN.mLargeIcon = largeIcon;
             mN.largeIcon = largeIconLegacy;
@@ -5390,7 +5382,6 @@
         public RemoteViews makeLowPriorityContentView(boolean useRegularSubtext) {
             StandardTemplateParams p = mParams.reset()
                     .forceDefaultColor()
-                    .ambient(false)
                     .fillTextsFrom(this);
             if (!useRegularSubtext || TextUtils.isEmpty(mParams.summaryText)) {
                 p.summaryText(createSummaryText());
@@ -5481,8 +5472,7 @@
                 if (isColorized(p)) {
                     setTextViewColorPrimary(button, R.id.action0, p);
                 } else if (getRawColor(p) != COLOR_DEFAULT && mTintActionButtons) {
-                    button.setTextColor(R.id.action0,
-                            p.ambient ? resolveAmbientColor(p) : resolveContrastColor(p));
+                    button.setTextColor(R.id.action0, resolveContrastColor(p));
                 }
             }
             button.setIntTag(R.id.action0, R.id.notification_action_index_tag,
@@ -5575,13 +5565,8 @@
         }
 
         private CharSequence processLegacyText(CharSequence charSequence) {
-            return processLegacyText(charSequence, false /* ambient */);
-        }
-
-        private CharSequence processLegacyText(CharSequence charSequence, boolean ambient) {
             boolean isAlreadyLightText = isLegacy() || textColorsNeedInversion();
-            boolean wantLightText = ambient;
-            if (isAlreadyLightText != wantLightText) {
+            if (isAlreadyLightText) {
                 return getColorUtil().invertCharSequenceColors(charSequence);
             } else {
                 return charSequence;
@@ -5595,9 +5580,7 @@
                 StandardTemplateParams p) {
             boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon);
             int color;
-            if (p.ambient) {
-                color = resolveAmbientColor(p);
-            } else if (isColorized(p)) {
+            if (isColorized(p)) {
                 color = getPrimaryTextColor(p);
             } else {
                 color = resolveContrastColor(p);
@@ -5684,17 +5667,6 @@
             return mNeutralColor;
         }
 
-        int resolveAmbientColor(StandardTemplateParams p) {
-            int rawColor = getRawColor(p);
-            if (mCachedAmbientColorIsFor == rawColor && mCachedAmbientColorIsFor != COLOR_INVALID) {
-                return mCachedAmbientColor;
-            }
-            final int contrasted = ContrastColorUtil.resolveAmbientColor(mContext, rawColor);
-
-            mCachedAmbientColorIsFor = rawColor;
-            return mCachedAmbientColor = contrasted;
-        }
-
         /**
          * Apply the unstyled operations and return a new {@link Notification} object.
          * @hide
@@ -8407,6 +8379,186 @@
         }
     }
 
+    /**
+     * Encapsulates the information needed to display a notification as a bubble.
+     *
+     * <p>A bubble is used to display app content in a floating window over the existing
+     * foreground activity. A bubble has a collapsed state represented by an icon,
+     * {@link BubbleMetadata.Builder#setIcon(Icon)} and an expanded state which is populated
+     * via {@link BubbleMetadata.Builder#setIntent(PendingIntent)}.</p>
+     *
+     * <b>Notifications with a valid and allowed bubble will display in collapsed state
+     * outside of the notification shade on unlocked devices. When a user interacts with the
+     * collapsed bubble, the bubble intent will be invoked and displayed.</b>
+     *
+     * @see Notification.Builder#setBubbleMetadata(BubbleMetadata)
+     */
+    public static final class BubbleMetadata implements Parcelable {
+
+        private PendingIntent mPendingIntent;
+        private CharSequence mTitle;
+        private Icon mIcon;
+        private int mDesiredHeight;
+
+        private BubbleMetadata(PendingIntent intent, CharSequence title, Icon icon, int height) {
+            mPendingIntent = intent;
+            mTitle = title;
+            mIcon = icon;
+            mDesiredHeight = height;
+        }
+
+        private BubbleMetadata(Parcel in) {
+            mPendingIntent = PendingIntent.CREATOR.createFromParcel(in);
+            mTitle = in.readCharSequence();
+            mIcon = Icon.CREATOR.createFromParcel(in);
+            mDesiredHeight = in.readInt();
+        }
+
+        /**
+         * @return the pending intent used to populate the floating window for this bubble.
+         */
+        public PendingIntent getIntent() {
+            return mPendingIntent;
+        }
+
+        /**
+         * @return the title that will appear along with the app content defined by
+         * {@link #getIntent()} for this bubble.
+         */
+        public CharSequence getTitle() {
+            return mTitle;
+        }
+
+        /**
+         * @return the icon that will be displayed for this bubble when it is collapsed.
+         */
+        public Icon getIcon() {
+            return mIcon;
+        }
+
+        /**
+         * @return the ideal height for the floating window that app content defined by
+         * {@link #getIntent()} for this bubble.
+         */
+        public int getDesiredHeight() {
+            return mDesiredHeight;
+        }
+
+        public static final Parcelable.Creator<BubbleMetadata> CREATOR =
+                new Parcelable.Creator<BubbleMetadata>() {
+
+                    @Override
+                    public BubbleMetadata createFromParcel(Parcel source) {
+                        return new BubbleMetadata(source);
+                    }
+
+                    @Override
+                    public BubbleMetadata[] newArray(int size) {
+                        return new BubbleMetadata[size];
+                    }
+                };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            mPendingIntent.writeToParcel(out, 0);
+            out.writeCharSequence(mTitle);
+            mIcon.writeToParcel(out, 0);
+            out.writeInt(mDesiredHeight);
+        }
+
+        /**
+         * Builder to construct a {@link BubbleMetadata} object.
+         */
+        public static class Builder {
+
+            private PendingIntent mPendingIntent;
+            private CharSequence mTitle;
+            private Icon mIcon;
+            private int mDesiredHeight;
+
+            /**
+             * Constructs a new builder object.
+             */
+            public Builder() {
+            }
+
+            /**
+             * Sets the intent that will be used when the bubble is expanded. This will display the
+             * app content in a floating window over the existing foreground activity.
+             */
+            public BubbleMetadata.Builder setIntent(PendingIntent intent) {
+                if (intent == null) {
+                    throw new IllegalArgumentException("Bubble requires non-null pending intent");
+                }
+                mPendingIntent = intent;
+                return this;
+            }
+
+            /**
+             * Sets the title that will appear along with the app content for this bubble.
+             *
+             * <p>A title is required and should expect to fit on a single line and make sense when
+             * shown with the content defined by {@link #setIntent(PendingIntent)}.</p>
+             */
+            public BubbleMetadata.Builder setTitle(CharSequence title) {
+                if (TextUtils.isEmpty(title)) {
+                    throw new IllegalArgumentException("Bubbles require non-null or empty title");
+                }
+                mTitle = title;
+                return this;
+            }
+
+            /**
+             * Sets the icon that will represent the bubble when it is collapsed.
+             *
+             * <p>An icon is required and should be representative of the content within the bubble.
+             * If your app produces multiple bubbles, the image should be unique for each of them.
+             * </p>
+             */
+            public BubbleMetadata.Builder setIcon(Icon icon) {
+                if (icon == null) {
+                    throw new IllegalArgumentException("Bubbles require non-null icon");
+                }
+                mIcon = icon;
+                return this;
+            }
+
+            /**
+             * Sets the desired height for the app content defined by
+             * {@link #setIntent(PendingIntent)}, this height may not be respected if there is not
+             * enough space on the screen or if the provided height is too small to be useful.
+             */
+            public BubbleMetadata.Builder setDesiredHeight(int height) {
+                mDesiredHeight = Math.max(height, 0);
+                return this;
+            }
+
+            /**
+             * Creates the {@link BubbleMetadata} defined by this builder.
+             * <p>Will throw {@link IllegalStateException} if required fields have not been set
+             * on this builder.</p>
+             */
+            public BubbleMetadata build() {
+                if (mPendingIntent == null) {
+                    throw new IllegalStateException("Must supply pending intent to bubble");
+                }
+                if (TextUtils.isEmpty(mTitle)) {
+                    throw new IllegalStateException("Must supply a title for the bubble");
+                }
+                if (mIcon == null) {
+                    throw new IllegalStateException("Must supply an icon for the bubble");
+                }
+                return new BubbleMetadata(mPendingIntent, mTitle, mIcon, mDesiredHeight);
+            }
+        }
+    }
+
+
     // When adding a new Style subclass here, don't forget to update
     // Builder.getNotificationStyleClass.
 
@@ -9950,7 +10102,6 @@
 
     private static class StandardTemplateParams {
         boolean hasProgress = true;
-        boolean ambient = false;
         CharSequence title;
         CharSequence text;
         CharSequence headerTextSecondary;
@@ -9963,7 +10114,6 @@
 
         final StandardTemplateParams reset() {
             hasProgress = true;
-            ambient = false;
             title = null;
             text = null;
             summaryText = null;
@@ -10019,22 +10169,15 @@
             return this;
         }
 
-        final StandardTemplateParams ambient(boolean ambient) {
-            Preconditions.checkState(title == null && text == null, "must set ambient before text");
-            this.ambient = ambient;
-            return this;
-        }
-
         final StandardTemplateParams fillTextsFrom(Builder b) {
             Bundle extras = b.mN.extras;
-            this.title = b.processLegacyText(extras.getCharSequence(EXTRA_TITLE), ambient);
+            this.title = b.processLegacyText(extras.getCharSequence(EXTRA_TITLE));
 
-            // Big text notifications should contain their content when viewed in ambient mode.
             CharSequence text = extras.getCharSequence(EXTRA_BIG_TEXT);
-            if (!ambient || TextUtils.isEmpty(text)) {
+            if (TextUtils.isEmpty(text)) {
                 text = extras.getCharSequence(EXTRA_TEXT);
             }
-            this.text = b.processLegacyText(text, ambient);
+            this.text = b.processLegacyText(text);
             this.summaryText = extras.getCharSequence(EXTRA_SUB_TEXT);
             return this;
         }
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 41ceaaf..e95d62f 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -19,6 +19,7 @@
 
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.NotificationManager.Importance;
 import android.content.ContentResolver;
@@ -84,7 +85,7 @@
     private static final String ATT_FG_SERVICE_SHOWN = "fgservice";
     private static final String ATT_GROUP = "group";
     private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system";
-    private static final String ATT_ALLOW_APP_OVERLAY = "app_overlay";
+    private static final String ATT_ALLOW_BUBBLE = "allow_bubble";
     private static final String DELIMITER = ",";
 
     /**
@@ -120,7 +121,7 @@
     /**
      * @hide
      */
-    public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 0x00000100;
+    public static final int USER_LOCKED_ALLOW_BUBBLE = 0x00000100;
 
     /**
      * @hide
@@ -133,7 +134,7 @@
             USER_LOCKED_VIBRATION,
             USER_LOCKED_SOUND,
             USER_LOCKED_SHOW_BADGE,
-            USER_LOCKED_ALLOW_APP_OVERLAY
+            USER_LOCKED_ALLOW_BUBBLE
     };
 
     private static final int DEFAULT_LIGHT_COLOR = 0;
@@ -143,7 +144,7 @@
             NotificationManager.IMPORTANCE_UNSPECIFIED;
     private static final boolean DEFAULT_DELETED = false;
     private static final boolean DEFAULT_SHOW_BADGE = true;
-    private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true;
+    private static final boolean DEFAULT_ALLOW_BUBBLE = true;
 
     @UnsupportedAppUsage
     private final String mId;
@@ -167,7 +168,8 @@
     private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
     // If this is a blockable system notification channel.
     private boolean mBlockableSystem = false;
-    private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY;
+    private boolean mAllowBubbles = DEFAULT_ALLOW_BUBBLE;
+    private boolean mImportanceLockedByOEM;
 
     /**
      * Creates a notification channel.
@@ -229,7 +231,8 @@
         mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null;
         mLightColor = in.readInt();
         mBlockableSystem = in.readBoolean();
-        mAllowAppOverlay = in.readBoolean();
+        mAllowBubbles = in.readBoolean();
+        mImportanceLockedByOEM = in.readBoolean();
     }
 
     @Override
@@ -282,7 +285,8 @@
         }
         dest.writeInt(mLightColor);
         dest.writeBoolean(mBlockableSystem);
-        dest.writeBoolean(mAllowAppOverlay);
+        dest.writeBoolean(mAllowBubbles);
+        dest.writeBoolean(mImportanceLockedByOEM);
     }
 
     /**
@@ -476,7 +480,7 @@
 
     /**
      * Sets whether notifications posted to this channel can appear outside of the notification
-     * shade, floating over other apps' content.
+     * shade, floating over other apps' content as a bubble.
      *
      * <p>This value will be ignored for channels that aren't allowed to pop on screen (that is,
      * channels whose {@link #getImportance() importance} is <
@@ -484,10 +488,10 @@
      *
      * <p>Only modifiable before the channel is submitted to
      *      * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.</p>
-     * @see Notification#getAppOverlayIntent()
+     * @see Notification#getBubbleMetadata()
      */
-    public void setAllowAppOverlay(boolean allowAppOverlay) {
-        mAllowAppOverlay = allowAppOverlay;
+    public void setAllowBubbles(boolean allowBubbles) {
+        mAllowBubbles = allowBubbles;
     }
 
     /**
@@ -606,16 +610,16 @@
      * Returns whether notifications posted to this channel can display outside of the notification
      * shade, in a floating window on top of other apps.
      */
-    public boolean canOverlayApps() {
-        return isAppOverlayAllowed() && getImportance() >= IMPORTANCE_HIGH;
+    public boolean canBubble() {
+        return isBubbleAllowed() && getImportance() >= IMPORTANCE_HIGH;
     }
 
     /**
-     * Like {@link #canOverlayApps()}, but only checks the permission, not the importance.
+     * Like {@link #canBubble()}, but only checks the permission, not the importance.
      * @hide
      */
-    public boolean isAppOverlayAllowed() {
-        return mAllowAppOverlay;
+    public boolean isBubbleAllowed() {
+        return mAllowBubbles;
     }
 
     /**
@@ -649,6 +653,22 @@
     }
 
     /**
+     * @hide
+     */
+    @TestApi
+    public void setImportanceLockedByOEM(boolean locked) {
+        mImportanceLockedByOEM = locked;
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
+    public boolean isImportanceLockedByOEM() {
+        return mImportanceLockedByOEM;
+    }
+
+    /**
      * Returns whether the user has chosen the importance of this channel, either to affirm the
      * initial selection from the app, or changed it to be higher or lower.
      * @see #getImportance()
@@ -699,7 +719,7 @@
         lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
         setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false));
         setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false));
-        setAllowAppOverlay(safeBool(parser, ATT_ALLOW_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY));
+        setAllowBubbles(safeBool(parser, ATT_ALLOW_BUBBLE, DEFAULT_ALLOW_BUBBLE));
     }
 
     @Nullable
@@ -818,8 +838,8 @@
         if (isBlockableSystem()) {
             out.attribute(null, ATT_BLOCKABLE_SYSTEM, Boolean.toString(isBlockableSystem()));
         }
-        if (canOverlayApps() != DEFAULT_ALLOW_APP_OVERLAY) {
-            out.attribute(null, ATT_ALLOW_APP_OVERLAY, Boolean.toString(canOverlayApps()));
+        if (canBubble() != DEFAULT_ALLOW_BUBBLE) {
+            out.attribute(null, ATT_ALLOW_BUBBLE, Boolean.toString(canBubble()));
         }
 
         out.endTag(null, TAG_CHANNEL);
@@ -863,7 +883,7 @@
         record.put(ATT_DELETED, Boolean.toString(isDeleted()));
         record.put(ATT_GROUP, getGroup());
         record.put(ATT_BLOCKABLE_SYSTEM, isBlockableSystem());
-        record.put(ATT_ALLOW_APP_OVERLAY, canOverlayApps());
+        record.put(ATT_ALLOW_BUBBLE, canBubble());
         return record;
     }
 
@@ -952,25 +972,26 @@
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         NotificationChannel that = (NotificationChannel) o;
-        return getImportance() == that.getImportance() &&
-                mBypassDnd == that.mBypassDnd &&
-                getLockscreenVisibility() == that.getLockscreenVisibility() &&
-                mLights == that.mLights &&
-                getLightColor() == that.getLightColor() &&
-                getUserLockedFields() == that.getUserLockedFields() &&
-                isFgServiceShown() == that.isFgServiceShown() &&
-                mVibrationEnabled == that.mVibrationEnabled &&
-                mShowBadge == that.mShowBadge &&
-                isDeleted() == that.isDeleted() &&
-                isBlockableSystem() == that.isBlockableSystem() &&
-                mAllowAppOverlay == that.mAllowAppOverlay &&
-                Objects.equals(getId(), that.getId()) &&
-                Objects.equals(getName(), that.getName()) &&
-                Objects.equals(mDesc, that.mDesc) &&
-                Objects.equals(getSound(), that.getSound()) &&
-                Arrays.equals(mVibration, that.mVibration) &&
-                Objects.equals(getGroup(), that.getGroup()) &&
-                Objects.equals(getAudioAttributes(), that.getAudioAttributes());
+        return getImportance() == that.getImportance()
+                && mBypassDnd == that.mBypassDnd
+                && getLockscreenVisibility() == that.getLockscreenVisibility()
+                && mLights == that.mLights
+                && getLightColor() == that.getLightColor()
+                && getUserLockedFields() == that.getUserLockedFields()
+                && isFgServiceShown() == that.isFgServiceShown()
+                && mVibrationEnabled == that.mVibrationEnabled
+                && mShowBadge == that.mShowBadge
+                && isDeleted() == that.isDeleted()
+                && isBlockableSystem() == that.isBlockableSystem()
+                && mAllowBubbles == that.mAllowBubbles
+                && Objects.equals(getId(), that.getId())
+                && Objects.equals(getName(), that.getName())
+                && Objects.equals(mDesc, that.mDesc)
+                && Objects.equals(getSound(), that.getSound())
+                && Arrays.equals(mVibration, that.mVibration)
+                && Objects.equals(getGroup(), that.getGroup())
+                && Objects.equals(getAudioAttributes(), that.getAudioAttributes())
+                && mImportanceLockedByOEM == that.mImportanceLockedByOEM;
     }
 
     @Override
@@ -979,7 +1000,8 @@
                 getLockscreenVisibility(), getSound(), mLights, getLightColor(),
                 getUserLockedFields(),
                 isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
-                getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay);
+                getAudioAttributes(), isBlockableSystem(), mAllowBubbles,
+                mImportanceLockedByOEM);
         result = 31 * result + Arrays.hashCode(mVibration);
         return result;
     }
@@ -1006,7 +1028,8 @@
                 + ", mGroup='" + mGroup + '\''
                 + ", mAudioAttributes=" + mAudioAttributes
                 + ", mBlockableSystem=" + mBlockableSystem
-                + ", mAllowAppOverlay=" + mAllowAppOverlay
+                + ", mAllowBubbles=" + mAllowBubbles
+                + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
                 + '}';
         pw.println(prefix + output);
     }
@@ -1032,7 +1055,8 @@
                 + ", mGroup='" + mGroup + '\''
                 + ", mAudioAttributes=" + mAudioAttributes
                 + ", mBlockableSystem=" + mBlockableSystem
-                + ", mAllowAppOverlay=" + mAllowAppOverlay
+                + ", mAllowBubbles=" + mAllowBubbles
+                + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
                 + '}';
     }
 
@@ -1066,7 +1090,7 @@
             mAudioAttributes.writeToProto(proto, NotificationChannelProto.AUDIO_ATTRIBUTES);
         }
         proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem);
-        proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowAppOverlay);
+        proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowBubbles);
 
         proto.end(token);
     }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index aad3253..43614fe 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1080,14 +1080,14 @@
      * notification shade, floating over other apps' content.
      *
      * <p>This value will be ignored for notifications that are posted to channels that do not
-     * allow app overlays ({@link NotificationChannel#canOverlayApps()}.
+     * allow bubbles ({@link NotificationChannel#canBubble()}.
      *
-     * @see Notification#getAppOverlayIntent()
+     * @see Notification#getBubbleMetadata()
      */
-    public boolean areAppOverlaysAllowed() {
+    public boolean areBubblesAllowed() {
         INotificationManager service = getService();
         try {
-            return service.areAppOverlaysAllowed(mContext.getPackageName());
+            return service.areBubblesAllowed(mContext.getPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index bf3d885..bbe5b8b 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -69,6 +69,22 @@
             | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK
             | DISABLE_SEARCH;
 
+    @IntDef(flag = true, prefix = {"DISABLE_"}, value = {
+            DISABLE_NONE,
+            DISABLE_EXPAND,
+            DISABLE_NOTIFICATION_ICONS,
+            DISABLE_NOTIFICATION_ALERTS,
+            DISABLE_NOTIFICATION_TICKER,
+            DISABLE_SYSTEM_INFO,
+            DISABLE_HOME,
+            DISABLE_RECENT,
+            DISABLE_BACK,
+            DISABLE_CLOCK,
+            DISABLE_SEARCH
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DisableFlags {}
+
     /**
      * Flag to disable quick settings.
      *
@@ -104,10 +120,25 @@
     public static final int WINDOW_STATUS_BAR = 1;
     public static final int WINDOW_NAVIGATION_BAR = 2;
 
+    @IntDef(flag = true, prefix = { "WINDOW_" }, value = {
+        WINDOW_STATUS_BAR,
+        WINDOW_NAVIGATION_BAR
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WindowType {}
+
     public static final int WINDOW_STATE_SHOWING = 0;
     public static final int WINDOW_STATE_HIDING = 1;
     public static final int WINDOW_STATE_HIDDEN = 2;
 
+    @IntDef(flag = true, prefix = { "WINDOW_STATE_" }, value = {
+            WINDOW_STATE_SHOWING,
+            WINDOW_STATE_HIDING,
+            WINDOW_STATE_HIDDEN
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WindowVisibleState {}
+
     public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0;
     public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1;
     public static final int CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER = 2;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 3f6ebc8..2dc225a 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -21,8 +21,11 @@
 import android.app.ContextImpl.ServiceInitializationState;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.IDevicePolicyManager;
+import android.app.contentsuggestions.ContentSuggestionsManager;
+import android.app.contentsuggestions.IContentSuggestionsManager;
 import android.app.job.IJobScheduler;
 import android.app.job.JobScheduler;
+import android.app.prediction.AppPredictionManager;
 import android.app.role.RoleManager;
 import android.app.slice.SliceManager;
 import android.app.timedetector.TimeDetector;
@@ -42,6 +45,8 @@
 import android.content.Context;
 import android.content.IRestrictionsManager;
 import android.content.RestrictionsManager;
+import android.content.om.IOverlayManager;
+import android.content.om.OverlayManager;
 import android.content.pm.CrossProfileApps;
 import android.content.pm.ICrossProfileApps;
 import android.content.pm.IShortcutService;
@@ -95,8 +100,10 @@
 import android.net.EthernetManager;
 import android.net.IConnectivityManager;
 import android.net.IEthernetManager;
+import android.net.IIpMemoryStore;
 import android.net.IIpSecService;
 import android.net.INetworkPolicyManager;
+import android.net.IpMemoryStore;
 import android.net.IpSecManager;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkScoreManager;
@@ -120,6 +127,7 @@
 import android.nfc.NfcManager;
 import android.os.BatteryManager;
 import android.os.BatteryStats;
+import android.os.BugreportManager;
 import android.os.Build;
 import android.os.DeviceIdleManager;
 import android.os.DropBoxManager;
@@ -127,6 +135,7 @@
 import android.os.IBatteryPropertiesRegistrar;
 import android.os.IBinder;
 import android.os.IDeviceIdleController;
+import android.os.IDumpstate;
 import android.os.IHardwarePropertiesManager;
 import android.os.IPowerManager;
 import android.os.IRecoverySystem;
@@ -144,6 +153,7 @@
 import android.os.Vibrator;
 import android.os.health.SystemHealthManager;
 import android.os.storage.StorageManager;
+import android.permission.PermissionControllerManager;
 import android.permission.PermissionManager;
 import android.print.IPrintManager;
 import android.print.PrintManager;
@@ -320,10 +330,21 @@
 
         registerService(Context.NETWORK_STACK_SERVICE, NetworkStack.class,
                 new StaticServiceFetcher<NetworkStack>() {
-                @Override
-                public NetworkStack createService() {
-                    return new NetworkStack();
-                }});
+                    @Override
+                    public NetworkStack createService() {
+                        return new NetworkStack();
+                    }});
+
+        registerService(Context.IP_MEMORY_STORE_SERVICE, IpMemoryStore.class,
+                new CachedServiceFetcher<IpMemoryStore>() {
+                    @Override
+                    public IpMemoryStore createService(final ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getServiceOrThrow(
+                                Context.IP_MEMORY_STORE_SERVICE);
+                        IIpMemoryStore service = IIpMemoryStore.Stub.asInterface(b);
+                        return new IpMemoryStore(ctx, service);
+                    }});
 
         registerService(Context.IPSEC_SERVICE, IpSecManager.class,
                 new CachedServiceFetcher<IpSecManager>() {
@@ -418,10 +439,11 @@
             }});
 
         registerService(Context.TEXT_SERVICES_MANAGER_SERVICE, TextServicesManager.class,
-                new StaticServiceFetcher<TextServicesManager>() {
+                new CachedServiceFetcher<TextServicesManager>() {
             @Override
-            public TextServicesManager createService() {
-                return TextServicesManager.getInstance();
+            public TextServicesManager createService(ContextImpl ctx)
+                    throws ServiceNotFoundException {
+                return TextServicesManager.createInstance(ctx);
             }});
 
         registerService(Context.KEYGUARD_SERVICE, KeyguardManager.class,
@@ -1034,6 +1056,14 @@
                 return new ShortcutManager(ctx, IShortcutService.Stub.asInterface(b));
             }});
 
+        registerService(Context.OVERLAY_SERVICE, OverlayManager.class,
+                new CachedServiceFetcher<OverlayManager>() {
+            @Override
+            public OverlayManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+                IBinder b = ServiceManager.getServiceOrThrow(Context.OVERLAY_SERVICE);
+                return new OverlayManager(ctx, IOverlayManager.Stub.asInterface(b));
+            }});
+
         registerService(Context.NETWORK_WATCHLIST_SERVICE, NetworkWatchlistManager.class,
                 new CachedServiceFetcher<NetworkWatchlistManager>() {
                     @Override
@@ -1068,6 +1098,16 @@
                 return new IncidentManager(ctx);
             }});
 
+        registerService(Context.BUGREPORT_SERVICE, BugreportManager.class,
+                new CachedServiceFetcher<BugreportManager>() {
+                    @Override
+                    public BugreportManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getServiceOrThrow(Context.BUGREPORT_SERVICE);
+                        return new BugreportManager(ctx.getOuterContext(),
+                                IDumpstate.Stub.asInterface(b));
+                    }});
+
         registerService(Context.AUTOFILL_MANAGER_SERVICE, AutofillManager.class,
                 new CachedServiceFetcher<AutofillManager>() {
             @Override
@@ -1094,6 +1134,29 @@
                 return null;
             }});
 
+        registerService(Context.APP_PREDICTION_SERVICE, AppPredictionManager.class,
+                new CachedServiceFetcher<AppPredictionManager>() {
+            @Override
+            public AppPredictionManager createService(ContextImpl ctx)
+                    throws ServiceNotFoundException {
+                return new AppPredictionManager(ctx);
+            }
+        });
+
+        registerService(Context.CONTENT_SUGGESTIONS_SERVICE,
+                ContentSuggestionsManager.class,
+                new CachedServiceFetcher<ContentSuggestionsManager>() {
+                    @Override
+                    public ContentSuggestionsManager createService(ContextImpl ctx) {
+                        // No throw as this is an optional service
+                        IBinder b = ServiceManager.getService(
+                                Context.CONTENT_SUGGESTIONS_SERVICE);
+                        IContentSuggestionsManager service =
+                                IContentSuggestionsManager.Stub.asInterface(b);
+                        return new ContentSuggestionsManager(service);
+                    }
+                });
+
         registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher<VrManager>() {
             @Override
             public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException {
@@ -1164,6 +1227,13 @@
                         return new PermissionManager(ctx.getOuterContext());
                     }});
 
+        registerService(Context.PERMISSION_CONTROLLER_SERVICE, PermissionControllerManager.class,
+                new CachedServiceFetcher<PermissionControllerManager>() {
+                    @Override
+                    public PermissionControllerManager createService(ContextImpl ctx) {
+                        return new PermissionControllerManager(ctx.getOuterContext());
+                    }});
+
         registerService(Context.ROLE_SERVICE, RoleManager.class,
                 new CachedServiceFetcher<RoleManager>() {
                     @Override
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 3f9627e..a021e3c 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -1240,7 +1240,7 @@
                 }
 
                 @Override
-                public void onMagnificationChanged(@NonNull Region region,
+                public void onMagnificationChanged(int displayId, @NonNull Region region,
                         float scale, float centerX, float centerY) {
                     /* do nothing */
                 }
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index 5b87de4..5f1a94c 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -215,19 +215,12 @@
     }
 
     /**
-     * Start VR Input method for the packageName in {@link ComponentName}.
-     * This method notifies InputMethodManagerService to use VR IME instead of
-     * regular phone IME.
-     * @param componentName ComponentName of a VR InputMethod that should be set as selected
-     * input by InputMethodManagerService.
+     * This method is not implemented.
+     *
+     * @param componentName not used
      */
     @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
     public void setVrInputMethod(ComponentName componentName) {
-        try {
-            mService.setVrInputMethod(componentName);
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
     }
 
     /**
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index ace814a..38a98d3c8 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.SystemApi;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -56,6 +56,7 @@
      * eg. A launcher may set its text color to black if this flag is specified.
      * @hide
      */
+    @SystemApi
     public static final int HINT_SUPPORTS_DARK_TEXT = 1 << 0;
 
     /**
@@ -64,6 +65,7 @@
      * eg. A launcher may set its drawer color to black if this flag is specified.
      * @hide
      */
+    @SystemApi
     public static final int HINT_SUPPORTS_DARK_THEME = 1 << 1;
 
     /**
@@ -234,7 +236,7 @@
      * @see WallpaperColors#fromDrawable(Drawable)
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public WallpaperColors(@NonNull Color primaryColor, @Nullable Color secondaryColor,
             @Nullable Color tertiaryColor, int colorHints) {
 
@@ -349,7 +351,7 @@
      * @return True if dark text is supported.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public int getColorHints() {
         return mColorHints;
     }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 27ae0b0..a929fe0 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -307,13 +307,14 @@
          * @param callback Listener
          * @param handler Thread to call it from. Main thread if null.
          * @param userId Owner of the wallpaper or UserHandle.USER_ALL
+         * @param displayId Caller comes from which display
          */
         public void addOnColorsChangedListener(@NonNull OnColorsChangedListener callback,
-                @Nullable Handler handler, int userId) {
+                @Nullable Handler handler, int userId, int displayId) {
             synchronized (this) {
                 if (!mColorCallbackRegistered) {
                     try {
-                        mService.registerWallpaperColorsCallback(this, userId);
+                        mService.registerWallpaperColorsCallback(this, userId, displayId);
                         mColorCallbackRegistered = true;
                     } catch (RemoteException e) {
                         // Failed, service is gone
@@ -329,16 +330,17 @@
          *
          * @param callback listener
          * @param userId Owner of the wallpaper or UserHandle.USER_ALL
+         * @param displayId Which display is interested
          */
         public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback,
-                int userId) {
+                int userId, int displayId) {
             synchronized (this) {
                 mColorListeners.removeIf(pair -> pair.first == callback);
 
                 if (mColorListeners.size() == 0 && mColorCallbackRegistered) {
                     mColorCallbackRegistered = false;
                     try {
-                        mService.unregisterWallpaperColorsCallback(this, userId);
+                        mService.unregisterWallpaperColorsCallback(this, userId, displayId);
                     } catch (RemoteException e) {
                         // Failed, service is gone
                         Log.w(TAG, "Can't unregister color updates", e);
@@ -370,14 +372,14 @@
             }
         }
 
-        WallpaperColors getWallpaperColors(int which, int userId) {
+        WallpaperColors getWallpaperColors(int which, int userId, int displayId) {
             if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
                 throw new IllegalArgumentException(
                         "Must request colors for exactly one kind of wallpaper");
             }
 
             try {
-                return mService.getWallpaperColors(which, userId);
+                return mService.getWallpaperColors(which, userId, displayId);
             } catch (RemoteException e) {
                 // Can't get colors, connection lost.
             }
@@ -894,7 +896,7 @@
     @UnsupportedAppUsage
     public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener,
             @NonNull Handler handler, int userId) {
-        sGlobals.addOnColorsChangedListener(listener, handler, userId);
+        sGlobals.addOnColorsChangedListener(listener, handler, userId, mContext.getDisplayId());
     }
 
     /**
@@ -913,7 +915,7 @@
      */
     public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener callback,
             int userId) {
-        sGlobals.removeOnColorsChangedListener(callback, userId);
+        sGlobals.removeOnColorsChangedListener(callback, userId, mContext.getDisplayId());
     }
 
     /**
@@ -947,7 +949,7 @@
      */
     @UnsupportedAppUsage
     public @Nullable WallpaperColors getWallpaperColors(int which, int userId) {
-        return sGlobals.getWallpaperColors(which, userId);
+        return sGlobals.getWallpaperColors(which, userId, mContext.getDisplayId());
     }
 
     /**
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 2990b57..e0a15a5 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityThread.isSystem;
 import static android.app.WindowConfigurationProto.ACTIVITY_TYPE;
 import static android.app.WindowConfigurationProto.APP_BOUNDS;
+import static android.app.WindowConfigurationProto.BOUNDS;
 import static android.app.WindowConfigurationProto.WINDOWING_MODE;
 import static android.view.Surface.rotationToString;
 
@@ -585,6 +586,9 @@
         }
         protoOutputStream.write(WINDOWING_MODE, mWindowingMode);
         protoOutputStream.write(ACTIVITY_TYPE, mActivityType);
+        if (mBounds != null) {
+            mBounds.writeToProto(protoOutputStream, BOUNDS);
+        }
         protoOutputStream.end(token);
     }
 
@@ -606,6 +610,10 @@
                         mAppBounds = new Rect();
                         mAppBounds.readFromProto(proto, APP_BOUNDS);
                         break;
+                    case (int) BOUNDS:
+                        mBounds = new Rect();
+                        mBounds.readFromProto(proto, BOUNDS);
+                        break;
                     case (int) WINDOWING_MODE:
                         mWindowingMode = proto.readInt(WINDOWING_MODE);
                         break;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f843262..55a3acb 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -907,9 +907,8 @@
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
 
     /**
-     * A String extra holding the URL-safe base64 encoded SHA-256 or SHA-1 hash (see notes below) of
-     * the file at download location specified in
-     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
+     * A String extra holding the URL-safe base64 encoded SHA-256 hash of the file at download
+     * location specified in {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
      *
      * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM} must be
      * present. The provided checksum must match the checksum of the file at the download
@@ -922,7 +921,8 @@
      * <p><strong>Note:</strong> for devices running {@link android.os.Build.VERSION_CODES#LOLLIPOP}
      * and {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} only SHA-1 hash is supported.
      * Starting from {@link android.os.Build.VERSION_CODES#M}, this parameter accepts SHA-256 in
-     * addition to SHA-1. Support for SHA-1 is likely to be removed in future OS releases.
+     * addition to SHA-1. From {@link android.os.Build.VERSION_CODES#Q}, only SHA-256 hash is
+     * supported.
      */
     public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
@@ -1362,16 +1362,23 @@
     public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
 
     /**
-     * Activity action: have the user enter a new password. This activity should
-     * be launched after using {@link #setPasswordQuality(ComponentName, int)},
-     * or {@link #setPasswordMinimumLength(ComponentName, int)} to have the user
-     * enter a new password that meets the current requirements. You can use
-     * {@link #isActivePasswordSufficient()} to determine whether you need to
-     * have the user select a new password in order to meet the current
-     * constraints. Upon being resumed from this activity, you can check the new
+     * Activity action: have the user enter a new password.
+     *
+     * <p>For admin apps, this activity should be launched after using {@link
+     * #setPasswordQuality(ComponentName, int)}, or {@link
+     * #setPasswordMinimumLength(ComponentName, int)} to have the user enter a new password that
+     * meets the current requirements. You can use {@link #isActivePasswordSufficient()} to
+     * determine whether you need to have the user select a new password in order to meet the
+     * current constraints. Upon being resumed from this activity, you can check the new
      * password characteristics to see if they are sufficient.
      *
-     * If the intent is launched from within a managed profile with a profile
+     * <p>Non-admin apps can use {@link #getPasswordComplexity()} to check the current screen lock
+     * complexity, and use this activity with extra {@link #EXTRA_PASSWORD_COMPLEXITY} to suggest
+     * to users how complex the app wants the new screen lock to be. Note that both {@link
+     * #getPasswordComplexity()} and the extra {@link #EXTRA_PASSWORD_COMPLEXITY} require the
+     * calling app to have the permission {@link permission#GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY}.
+     *
+     * <p>If the intent is launched from within a managed profile with a profile
      * owner built against {@link android.os.Build.VERSION_CODES#M} or before,
      * this will trigger entering a new password for the parent of the profile.
      * For all other cases it will trigger entering a new password for the user
@@ -1384,6 +1391,24 @@
             = "android.app.action.SET_NEW_PASSWORD";
 
     /**
+     * An integer indicating the complexity level of the new password an app would like the user to
+     * set when launching the action {@link #ACTION_SET_NEW_PASSWORD}.
+     *
+     * <p>Must be one of
+     * <ul>
+     *     <li>{@link #PASSWORD_COMPLEXITY_HIGH}
+     *     <li>{@link #PASSWORD_COMPLEXITY_MEDIUM}
+     *     <li>{@link #PASSWORD_COMPLEXITY_LOW}
+     *     <li>{@link #PASSWORD_COMPLEXITY_NONE}
+     * </ul>
+     *
+     * <p>If an invalid value is used, it will be treated as {@link #PASSWORD_COMPLEXITY_NONE}.
+     */
+    @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY)
+    public static final String EXTRA_PASSWORD_COMPLEXITY =
+            "android.app.extra.PASSWORD_COMPLEXITY";
+
+    /**
      * Constant for {@link #getPasswordComplexity()}: no password.
      *
      * <p>Note that these complexity constants are ordered so that higher values are more complex.
@@ -2168,6 +2193,74 @@
     public @interface SetPrivateDnsModeResultConstants {}
 
     /**
+     * Activity action: Starts the administrator to get the mode for the provisioning.
+     * This intent may contain the following extras:
+     * <ul>
+     *     <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}</li>
+     *     <li>{@link #EXTRA_PROVISIONING_IMEI}</li>
+     *     <li>{@link #EXTRA_PROVISIONING_SERIAL_NUMBER}</li>
+     * </ul>
+     *
+     * <p>The target activity should return one of the following values in
+     * {@link #EXTRA_PROVISIONING_MODE} as result:
+     * <ul>
+     *     <li>{@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}</li>
+     *     <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE}</li>
+     *     <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE}</li>
+     * </ul>
+     *
+     * <p>The target activity may also return the account that needs to be migrated from primary
+     * user to managed profile in case of a profile owner provisioning in
+     * {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE} as result.
+     */
+    public static final String ACTION_GET_PROVISIONING_MODE =
+            "android.app.action.GET_PROVISIONING_MODE";
+
+    /**
+     * A string extra holding the IMEI (International Mobile Equipment Identity) of the device.
+     */
+    public static final String EXTRA_PROVISIONING_IMEI = "android.app.extra.PROVISIONING_IMEI";
+
+    /**
+     * A string extra holding the serial number of the device.
+     */
+    public static final String EXTRA_PROVISIONING_SERIAL_NUMBER =
+            "android.app.extra.PROVISIONING_SERIAL_NUMBER";
+
+    /**
+     * An intent extra holding the provisioning mode returned by the administrator.
+     * The value for this extra should be one of the following:
+     * <ul>
+     *     <li>{@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}</li>
+     *     <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE}</li>
+     *     <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE}</li>
+     * </ul>
+     */
+    public static final String EXTRA_PROVISIONING_MODE =
+            "android.app.extra.PROVISIONING_MODE";
+
+    /**
+     * The provisioning mode for fully managed device.
+     */
+    public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1;
+
+    /**
+     * The provisioning mode for managed profile.
+     */
+    public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2;
+
+    /**
+     * The provisioning mode for managed profile on a fully managed device.
+     */
+    public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE = 3;
+
+    /**
+     * Activity action: Starts the administrator to show policy compliance for the provisioning.
+     */
+    public static final String ACTION_ADMIN_POLICY_COMPLIANCE =
+            "android.app.action.ADMIN_POLICY_COMPLIANCE";
+
+    /**
      * Return true if the given administrator component is currently active (enabled) in the system.
      *
      * @param admin The administrator component to check for.
@@ -2445,6 +2538,9 @@
      * requested quality constant (between the policy set here, the user's preference, and any other
      * considerations) is the one that is in effect.
      * <p>
+     * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     * <p>
      * The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
      * not, a security exception will be thrown.
@@ -2480,6 +2576,9 @@
      * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
      * restrictions on the parent profile.
      *
+     * <p>Note: on devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature,
+     * the password is always treated as empty.
+     *
      * @param admin The name of the admin component to check, or {@code null} to aggregate
      * all admins.
      */
@@ -2512,6 +2611,9 @@
      * {@link #PASSWORD_QUALITY_ALPHANUMERIC}, or {@link #PASSWORD_QUALITY_COMPLEX} with
      * {@link #setPasswordQuality}.
      * <p>
+     * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     * <p>
      * The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
      * not, a security exception will be thrown.
@@ -2541,11 +2643,13 @@
      * restrictions on this user and its participating profiles. Restrictions on profiles that have
      * a separate challenge are not taken into account.
      *
+     * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     *
      * <p>This method can be called on the {@link DevicePolicyManager} instance
      * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
      * restrictions on the parent profile.
      *
-     * user and its profiles or a particular one.
      * @param admin The name of the admin component to check, or {@code null} to aggregate
      * all admins.
      */
@@ -2576,6 +2680,9 @@
      * setting this value. This constraint is only imposed if the administrator has also requested
      * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The default value is 0.
      * <p>
+     * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     * <p>
      * The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
      * not, a security exception will be thrown.
@@ -2610,6 +2717,9 @@
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
+     * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     *
      * <p>This method can be called on the {@link DevicePolicyManager} instance
      * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
      * restrictions on the parent profile.
@@ -2646,6 +2756,9 @@
      * setting this value. This constraint is only imposed if the administrator has also requested
      * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The default value is 0.
      * <p>
+     * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     * <p>
      * The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
      * not, a security exception will be thrown.
@@ -2680,6 +2793,9 @@
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
+     * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     *
      * <p>This method can be called on the {@link DevicePolicyManager} instance
      * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
      * restrictions on the parent profile.
@@ -2716,6 +2832,9 @@
      * only imposed if the administrator has also requested {@link #PASSWORD_QUALITY_COMPLEX} with
      * {@link #setPasswordQuality}. The default value is 1.
      * <p>
+     * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     * <p>
      * The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
      * not, a security exception will be thrown.
@@ -2750,6 +2869,9 @@
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
+     * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     *
      * <p>This method can be called on the {@link DevicePolicyManager} instance
      * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
      * restrictions on the parent profile.
@@ -2785,6 +2907,9 @@
      * setting this value. This constraint is only imposed if the administrator has also requested
      * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The default value is 1.
      * <p>
+     * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     * <p>
      * The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
      * not, a security exception will be thrown.
@@ -2819,6 +2944,9 @@
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
+     * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     *
      * <p>This method can be called on the {@link DevicePolicyManager} instance
      * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
      * restrictions on the parent profile.
@@ -2854,6 +2982,9 @@
      * only imposed if the administrator has also requested {@link #PASSWORD_QUALITY_COMPLEX} with
      * {@link #setPasswordQuality}. The default value is 1.
      * <p>
+     * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     * <p>
      * The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
      * not, a security exception will be thrown.
@@ -2887,6 +3018,9 @@
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
+     * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     *
      * <p>This method can be called on the {@link DevicePolicyManager} instance
      * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
      * restrictions on the parent profile.
@@ -2922,6 +3056,9 @@
      * setting this value. This constraint is only imposed if the administrator has also requested
      * {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The default value is 0.
      * <p>
+     * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     * <p>
      * The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
      * not, a security exception will be thrown.
@@ -2956,6 +3093,9 @@
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
+     * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     *
      * <p>This method can be called on the {@link DevicePolicyManager} instance
      * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
      * restrictions on the parent profile.
@@ -2992,6 +3132,9 @@
      * , {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX} {@link #PASSWORD_QUALITY_ALPHABETIC}, or
      * {@link #PASSWORD_QUALITY_ALPHANUMERIC} with {@link #setPasswordQuality}.
      * <p>
+     * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     * <p>
      * The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
      * not, a security exception will be thrown.
@@ -3044,6 +3187,7 @@
      * @throws SecurityException if {@code admin} is not an active administrator or {@code admin}
      *             does not use {@link DeviceAdminInfo#USES_POLICY_EXPIRE_PASSWORD}
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public void setPasswordExpirationTimeout(@NonNull ComponentName admin, long timeout) {
         if (mService != null) {
             try {
@@ -3068,6 +3212,7 @@
      * @param admin The name of the admin component to check, or {@code null} to aggregate all admins.
      * @return The timeout for the given admin or the minimum of all timeouts
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public long getPasswordExpirationTimeout(@Nullable ComponentName admin) {
         if (mService != null) {
             try {
@@ -3092,6 +3237,7 @@
      * @param admin The name of the admin component to check, or {@code null} to aggregate all admins.
      * @return The password expiration time, in milliseconds since epoch.
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public long getPasswordExpiration(@Nullable ComponentName admin) {
         if (mService != null) {
             try {
@@ -3116,12 +3262,14 @@
      * all admins.
      * @return The length of the password history
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public int getPasswordHistoryLength(@Nullable ComponentName admin) {
         return getPasswordHistoryLength(admin, myUserId());
     }
 
     /** @hide per-user version */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public int getPasswordHistoryLength(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
@@ -3136,10 +3284,16 @@
     /**
      * Return the maximum password length that the device supports for a
      * particular password quality.
+     * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always empty.
      * @param quality The quality being interrogated.
      * @return Returns the maximum length that the user can enter.
      */
     public int getPasswordMaximumLength(int quality) {
+        PackageManager pm = mContext.getPackageManager();
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ID_ATTESTATION)) {
+            return 0;
+        }
         // Kind-of arbitrary.
         return 16;
     }
@@ -3150,6 +3304,10 @@
      * user and its participating profiles. Restrictions on profiles that have a separate challenge
      * are not taken into account. The user must be unlocked in order to perform the check.
      * <p>
+     * On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty - i.e. this method will always return false on such
+     * devices, provided any password requirements were set.
+     * <p>
      * The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
      * not, a security exception will be thrown.
@@ -3182,6 +3340,9 @@
      * explicitly querying the parent profile screen lock complexity via {@link
      * #getParentProfileInstance}.
      *
+     * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
+     * password is always treated as empty.
+     *
      * @throws IllegalStateException if the user is not unlocked.
      * @throws SecurityException if the calling application does not have the permission
      *                           {@link permission#GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY}
@@ -3261,6 +3422,7 @@
      * @throws SecurityException if the calling application does not own an active administrator
      *             that uses {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN}
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public int getCurrentFailedPasswordAttempts() {
         return getCurrentFailedPasswordAttempts(myUserId());
     }
@@ -3328,6 +3490,7 @@
      *             both {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} and
      *             {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}.
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public void setMaximumFailedPasswordsForWipe(@NonNull ComponentName admin, int num) {
         if (mService != null) {
             try {
@@ -3351,12 +3514,14 @@
      * @param admin The name of the admin component to check, or {@code null} to aggregate
      * all admins.
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin) {
         return getMaximumFailedPasswordsForWipe(admin, myUserId());
     }
 
     /** @hide per-user version */
     @UnsupportedAppUsage
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
@@ -3376,6 +3541,7 @@
      * user passed in.
      * @hide Used only by Keyguard
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public int getProfileWithMinimumFailedPasswordsForWipe(int userHandle) {
         if (mService != null) {
             try {
@@ -3446,6 +3612,7 @@
      *             that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD}
      * @throws IllegalStateException if the calling user is locked or has a managed profile.
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public boolean resetPassword(String password, int flags) {
         throwIfParentInstance("resetPassword");
         if (mService != null) {
@@ -3489,6 +3656,7 @@
      * @throws SecurityException if admin is not a device or profile owner.
      * @throws IllegalArgumentException if the supplied token is invalid.
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public boolean setResetPasswordToken(ComponentName admin, byte[] token) {
         throwIfParentInstance("setResetPasswordToken");
         if (mService != null) {
@@ -3508,6 +3676,7 @@
      * @return true if the operation is successful, false otherwise.
      * @throws SecurityException if admin is not a device or profile owner.
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public boolean clearResetPasswordToken(ComponentName admin) {
         throwIfParentInstance("clearResetPasswordToken");
         if (mService != null) {
@@ -3528,6 +3697,7 @@
      * @throws SecurityException if admin is not a device or profile owner.
      * @throws IllegalStateException if no token has been set.
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public boolean isResetPasswordTokenActive(ComponentName admin) {
         throwIfParentInstance("isResetPasswordTokenActive");
         if (mService != null) {
@@ -3569,6 +3739,7 @@
      * @throws SecurityException if admin is not a device or profile owner.
      * @throws IllegalStateException if the provided token is not valid.
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public boolean resetPasswordWithToken(@NonNull ComponentName admin, String password,
             byte[] token, int flags) {
         throwIfParentInstance("resetPassword");
@@ -3674,6 +3845,7 @@
      *
      * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public void setRequiredStrongAuthTimeout(@NonNull ComponentName admin,
             long timeoutMs) {
         if (mService != null) {
@@ -3698,12 +3870,14 @@
      *         across all participating admins.
      * @return The timeout in milliseconds or 0 if not configured for the provided admin.
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin) {
         return getRequiredStrongAuthTimeout(admin, myUserId());
     }
 
     /** @hide per-user version */
     @UnsupportedAppUsage
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin, @UserIdInt int userId) {
         if (mService != null) {
             try {
@@ -5282,6 +5456,7 @@
      * @hide
      */
     @UnsupportedAppUsage
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public void setActivePasswordState(PasswordMetrics metrics, int userHandle) {
         if (mService != null) {
             try {
@@ -5295,6 +5470,7 @@
     /**
      * @hide
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public void reportPasswordChanged(@UserIdInt int userId) {
         if (mService != null) {
             try {
@@ -5309,6 +5485,7 @@
      * @hide
      */
     @UnsupportedAppUsage
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public void reportFailedPasswordAttempt(int userHandle) {
         if (mService != null) {
             try {
@@ -5323,6 +5500,7 @@
      * @hide
      */
     @UnsupportedAppUsage
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public void reportSuccessfulPasswordAttempt(int userHandle) {
         if (mService != null) {
             try {
@@ -5336,6 +5514,7 @@
     /**
      * @hide
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public void reportFailedBiometricAttempt(int userHandle) {
         if (mService != null) {
             try {
@@ -5349,6 +5528,7 @@
     /**
      * @hide
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public void reportSuccessfulBiometricAttempt(int userHandle) {
         if (mService != null) {
             try {
@@ -6315,6 +6495,7 @@
      * @throws SecurityException if {@code admin} is not an active administrator or does not use
      *             {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES}
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public void setTrustAgentConfiguration(@NonNull ComponentName admin,
             @NonNull ComponentName target, PersistableBundle configuration) {
         if (mService != null) {
@@ -6344,6 +6525,7 @@
      * @param agent Which component to get enabled features for.
      * @return configuration for the given trust agent.
      */
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public @Nullable List<PersistableBundle> getTrustAgentConfiguration(
             @Nullable ComponentName admin, @NonNull ComponentName agent) {
         return getTrustAgentConfiguration(admin, agent, myUserId());
@@ -6351,6 +6533,7 @@
 
     /** @hide per-user version */
     @UnsupportedAppUsage
+    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public @Nullable List<PersistableBundle> getTrustAgentConfiguration(
             @Nullable ComponentName admin, @NonNull ComponentName agent, int userHandle) {
         if (mService != null) {
@@ -6815,8 +6998,12 @@
     }
 
     /**
-     * Returns the list of input methods permitted by the device or profiles
-     * owners of the current user.  (*Not* calling user, due to a limitation in InputMethodManager.)
+     * Returns the list of input methods permitted by the device or profiles owners.
+     *
+     * <p>On {@link android.os.Build.VERSION_CODES#Q} and later devices, this method returns the
+     * result for the calling user.</p>
+     *
+     * <p>On Android P and prior devices, this method returns the result for the current user.</p>
      *
      * <p>Null means all input methods are allowed, if a non-null list is returned
      * it will contain the intersection of the permitted lists for any device or profile
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index 8b41755..e5df2c7 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -20,6 +20,11 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -27,6 +32,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -85,6 +92,101 @@
         nonLetter = in.readInt();
     }
 
+    /** Returns the min quality allowed by {@code complexityLevel}. */
+    public static int complexityLevelToMinQuality(@PasswordComplexity int complexityLevel) {
+        // this would be the quality of the first metrics since mMetrics is sorted in ascending
+        // order of quality
+        return PasswordComplexityBucket
+                .complexityLevelToBucket(complexityLevel).mMetrics[0].quality;
+    }
+
+    /**
+     * Returns a merged minimum {@link PasswordMetrics} requirements that a new password must meet
+     * to fulfil {@code requestedQuality}, {@code requiresNumeric} and {@code
+     * requiresLettersOrSymbols}, which are derived from {@link DevicePolicyManager} requirements,
+     * and {@code complexityLevel}.
+     *
+     * <p>Note that we are taking {@code userEnteredPasswordQuality} into account because there are
+     * more than one set of metrics to meet the minimum complexity requirement and inspecting what
+     * the user has entered can help determine whether the alphabetic or alphanumeric set of metrics
+     * should be used. For example, suppose minimum complexity requires either ALPHABETIC(8+), or
+     * ALPHANUMERIC(6+). If the user has entered "a", the length requirement displayed on the UI
+     * would be 8. Then the user appends "1" to make it "a1". We now know the user is entering
+     * an alphanumeric password so we would update the min complexity required min length to 6.
+     */
+    public static PasswordMetrics getMinimumMetrics(@PasswordComplexity int complexityLevel,
+            int userEnteredPasswordQuality, int requestedQuality, boolean requiresNumeric,
+            boolean requiresLettersOrSymbols) {
+        int targetQuality = Math.max(
+                userEnteredPasswordQuality,
+                getActualRequiredQuality(
+                        requestedQuality, requiresNumeric, requiresLettersOrSymbols));
+        return getTargetQualityMetrics(complexityLevel, targetQuality);
+    }
+
+    /**
+     * Returns the {@link PasswordMetrics} at {@code complexityLevel} which the metrics quality
+     * is the same as {@code targetQuality}.
+     *
+     * <p>If {@code complexityLevel} does not allow {@code targetQuality}, returns the metrics
+     * with the min quality at {@code complexityLevel}.
+     */
+    // TODO(bernardchau): update tests to test getMinimumMetrics and change this to be private
+    @VisibleForTesting
+    public static PasswordMetrics getTargetQualityMetrics(
+            @PasswordComplexity int complexityLevel, int targetQuality) {
+        PasswordComplexityBucket targetBucket =
+                PasswordComplexityBucket.complexityLevelToBucket(complexityLevel);
+        for (PasswordMetrics metrics : targetBucket.mMetrics) {
+            if (targetQuality == metrics.quality) {
+                return metrics;
+            }
+        }
+        // none of the metrics at complexityLevel has targetQuality, return metrics with min quality
+        // see test case testGetMinimumMetrics_actualRequiredQualityStricter for an example, where
+        // min complexity allows at least NUMERIC_COMPLEX, user has not entered anything yet, and
+        // requested quality is NUMERIC
+        return targetBucket.mMetrics[0];
+    }
+
+    /**
+     * Finds out the actual quality requirement based on whether quality is {@link
+     * DevicePolicyManager#PASSWORD_QUALITY_COMPLEX} and whether digits, letters or symbols are
+     * required.
+     */
+    @VisibleForTesting
+    // TODO(bernardchau): update tests to test getMinimumMetrics and change this to be private
+    public static int getActualRequiredQuality(
+            int requestedQuality, boolean requiresNumeric, boolean requiresLettersOrSymbols) {
+        if (requestedQuality != PASSWORD_QUALITY_COMPLEX) {
+            return requestedQuality;
+        }
+
+        // find out actual password quality from complex requirements
+        if (requiresNumeric && requiresLettersOrSymbols) {
+            return PASSWORD_QUALITY_ALPHANUMERIC;
+        }
+        if (requiresLettersOrSymbols) {
+            return PASSWORD_QUALITY_ALPHABETIC;
+        }
+        if (requiresNumeric) {
+            // cannot specify numeric complex using complex quality so this must be numeric
+            return PASSWORD_QUALITY_NUMERIC;
+        }
+
+        // reaching here means dpm sets quality to complex without specifying any requirements
+        return PASSWORD_QUALITY_UNSPECIFIED;
+    }
+
+    /**
+     * Returns {@code complexityLevel} or {@link DevicePolicyManager#PASSWORD_COMPLEXITY_NONE}
+     * if {@code complexityLevel} is not valid.
+     */
+    @PasswordComplexity
+    public static int sanitizeComplexityLevel(@PasswordComplexity int complexityLevel) {
+        return PasswordComplexityBucket.complexityLevelToBucket(complexityLevel).mComplexityLevel;
+    }
+
     public boolean isDefault() {
         return quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
                 && length == 0 && letters == 0 && upperCase == 0 && lowerCase == 0
@@ -280,7 +382,7 @@
     @PasswordComplexity
     public int determineComplexity() {
         for (PasswordComplexityBucket bucket : PasswordComplexityBucket.BUCKETS) {
-            if (satisfiesBucket(bucket.getMetrics())) {
+            if (satisfiesBucket(bucket.mMetrics)) {
                 return bucket.mComplexityLevel;
             }
         }
@@ -290,7 +392,7 @@
     /**
      * Requirements in terms of {@link PasswordMetrics} for each {@link PasswordComplexity}.
      */
-    public static class PasswordComplexityBucket {
+    private static class PasswordComplexityBucket {
         /**
          * Definition of {@link DevicePolicyManager#PASSWORD_COMPLEXITY_HIGH} in terms of
          * {@link PasswordMetrics}.
@@ -299,12 +401,13 @@
                 new PasswordComplexityBucket(
                         PASSWORD_COMPLEXITY_HIGH,
                         new PasswordMetrics(
-                                DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, /* length= */ 6),
+                                DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX, /* length= */
+                                8),
                         new PasswordMetrics(
                                 DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, /* length= */ 6),
                         new PasswordMetrics(
-                                DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX, /* length= */
-                                8));
+                                DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, /* length= */
+                                6));
 
         /**
          * Definition of {@link DevicePolicyManager#PASSWORD_COMPLEXITY_MEDIUM} in terms of
@@ -314,11 +417,12 @@
                 new PasswordComplexityBucket(
                         PASSWORD_COMPLEXITY_MEDIUM,
                         new PasswordMetrics(
-                                DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, /* length= */ 4),
+                                DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX, /* length= */
+                                4),
                         new PasswordMetrics(
                                 DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, /* length= */ 4),
                         new PasswordMetrics(
-                                DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX, /* length= */
+                                DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, /* length= */
                                 4));
 
         /**
@@ -328,11 +432,11 @@
         private static final PasswordComplexityBucket LOW =
                 new PasswordComplexityBucket(
                         PASSWORD_COMPLEXITY_LOW,
-                        new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC),
-                        new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC),
-                        new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX),
+                        new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING),
                         new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC),
-                        new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING));
+                        new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX),
+                        new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC),
+                        new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC));
 
         /**
          * A special bucket to represent {@link DevicePolicyManager#PASSWORD_COMPLEXITY_NONE}.
@@ -348,19 +452,27 @@
         private final int mComplexityLevel;
         private final PasswordMetrics[] mMetrics;
 
+        /**
+         * @param metricsArray must be sorted in ascending order of {@link #quality}.
+         */
         private PasswordComplexityBucket(@PasswordComplexity int complexityLevel,
-                PasswordMetrics... metrics) {
-            this.mComplexityLevel = complexityLevel;
-            this.mMetrics = metrics;
-        }
+                PasswordMetrics... metricsArray) {
+            int previousQuality = PASSWORD_QUALITY_UNSPECIFIED;
+            for (PasswordMetrics metrics : metricsArray) {
+                if (metrics.quality < previousQuality) {
+                    throw new IllegalArgumentException("metricsArray must be sorted in ascending"
+                            + " order of quality");
+                }
+                previousQuality = metrics.quality;
+            }
 
-        /** Returns the {@link PasswordMetrics} that meet the min requirements of this bucket. */
-        public PasswordMetrics[] getMetrics() {
-            return mMetrics;
+            this.mMetrics = metricsArray;
+            this.mComplexityLevel = complexityLevel;
+
         }
 
         /** Returns the bucket that {@code complexityLevel} represents. */
-        public static PasswordComplexityBucket complexityLevelToBucket(
+        private static PasswordComplexityBucket complexityLevelToBucket(
                 @PasswordComplexity int complexityLevel) {
             for (PasswordComplexityBucket bucket : BUCKETS) {
                 if (bucket.mComplexityLevel == complexityLevel) {
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index cc4d4b1a..6006ad2 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -894,7 +894,7 @@
             }
             if (mAutofillId != null) {
                 autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID;
-                if (mAutofillId.isVirtual()) {
+                if (mAutofillId.isVirtualInt()) {
                     autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID;
                 }
             }
@@ -961,8 +961,9 @@
                 if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID) != 0) {
                     out.writeInt(mAutofillId.getViewId());
                     if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID) != 0) {
-                        out.writeInt(mAutofillId.getVirtualChildId());
+                        out.writeInt(mAutofillId.getVirtualChildIntId());
                     }
+                    // TODO(b/113593220): write session id as well
                 }
                 if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_TYPE) != 0) {
                     out.writeInt(mAutofillType);
@@ -1699,7 +1700,8 @@
 
         @Override
         public void setVisibility(int visibility) {
-            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_VISIBILITY_MASK) | visibility;
+            mNode.mFlags = (mNode.mFlags & ~ViewNode.FLAGS_VISIBILITY_MASK)
+                    | (visibility & ViewNode.FLAGS_VISIBILITY_MASK);
         }
 
         @Override
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index c983d4f..24580b4 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -16,6 +16,7 @@
 
 package android.app.backup;
 
+import android.annotation.Nullable;
 import android.app.IBackupAgent;
 import android.app.QueuedWork;
 import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
@@ -181,6 +182,8 @@
 
     Handler mHandler = null;
 
+    @Nullable private UserHandle mUser;
+
     Handler getHandler() {
         if (mHandler == null) {
             mHandler = new Handler(Looper.getMainLooper());
@@ -232,6 +235,8 @@
      */
     public void onCreate(UserHandle user) {
         onCreate();
+
+        mUser = user;
     }
 
     /**
@@ -528,6 +533,10 @@
     public void onQuotaExceeded(long backupDataBytes, long quotaBytes) {
     }
 
+    private int getBackupUserId() {
+        return mUser == null ? super.getUserId() : mUser.getIdentifier();
+    }
+
     /**
      * Check whether the xml yielded any <include/> tag for the provided <code>domainToken</code>.
      * If so, perform a {@link #fullBackupFileTree} which backs up the file or recurses if the path
@@ -1033,7 +1042,7 @@
 
                 Binder.restoreCallingIdentity(ident);
                 try {
-                    callbackBinder.opComplete(token, 0);
+                    callbackBinder.opCompleteForUser(getBackupUserId(), token, 0);
                 } catch (RemoteException e) {
                     // we'll time out anyway, so we're safe
                 }
@@ -1082,7 +1091,7 @@
 
                 Binder.restoreCallingIdentity(ident);
                 try {
-                    callbackBinder.opComplete(token, 0);
+                    callbackBinder.opCompleteForUser(getBackupUserId(), token, 0);
                 } catch (RemoteException e) {
                     // we'll time out anyway, so we're safe
                 }
@@ -1112,7 +1121,8 @@
             } finally {
                 Binder.restoreCallingIdentity(ident);
                 try {
-                    callbackBinder.opComplete(token, measureOutput.getSize());
+                    callbackBinder.opCompleteForUser(getBackupUserId(), token,
+                            measureOutput.getSize());
                 } catch (RemoteException e) {
                     // timeout, so we're safe
                 }
@@ -1137,7 +1147,7 @@
 
                 Binder.restoreCallingIdentity(ident);
                 try {
-                    callbackBinder.opComplete(token, 0);
+                    callbackBinder.opCompleteForUser(getBackupUserId(), token, 0);
                 } catch (RemoteException e) {
                     // we'll time out anyway, so we're safe
                 }
@@ -1162,7 +1172,7 @@
 
                 Binder.restoreCallingIdentity(ident);
                 try {
-                    callbackBinder.opComplete(token, 0);
+                    callbackBinder.opCompleteForUser(getBackupUserId(), token, 0);
                 } catch (RemoteException e) {
                     // we'll time out anyway, so we're safe
                 }
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index f8c5a81..eda8981 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -549,6 +549,19 @@
 
     /**
      * Notify the backup manager that a BackupAgent has completed the operation
+     * corresponding to the given token and user id.
+     *
+     * @param userId User id for which the operation has been completed.
+     * @param token The transaction token passed to the BackupAgent method being
+     *        invoked.
+     * @param result In the case of a full backup measure operation, the estimated
+     *        total file size that would result from the operation. Unused in all other
+     *        cases.
+     */
+    void opCompleteForUser(int userId, int token, long result);
+
+    /**
+     * Notify the backup manager that a BackupAgent has completed the operation
      * corresponding to the given token.
      *
      * @param token The transaction token passed to the BackupAgent method being
diff --git a/core/java/android/app/contentsuggestions/ClassificationsRequest.aidl b/core/java/android/app/contentsuggestions/ClassificationsRequest.aidl
new file mode 100644
index 0000000..a66413b
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ClassificationsRequest.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.contentsuggestions;
+
+parcelable ClassificationsRequest;
diff --git a/core/java/android/app/contentsuggestions/ClassificationsRequest.java b/core/java/android/app/contentsuggestions/ClassificationsRequest.java
new file mode 100644
index 0000000..3f71518
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ClassificationsRequest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class ClassificationsRequest implements Parcelable {
+    @NonNull
+    private final List<ContentSelection> mSelections;
+    @Nullable
+    private final Bundle mExtras;
+
+    private ClassificationsRequest(@NonNull List<ContentSelection> selections,
+            @Nullable Bundle extras) {
+        mSelections = selections;
+        mExtras = extras;
+    }
+
+    /**
+     * Return request selections.
+     */
+    public List<ContentSelection> getSelections() {
+        return mSelections;
+    }
+
+    /**
+     * Return the request extras.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeTypedList(mSelections);
+        dest.writeBundle(mExtras);
+    }
+
+    public static final Creator<ClassificationsRequest> CREATOR =
+            new Creator<ClassificationsRequest>() {
+        @Override
+        public ClassificationsRequest createFromParcel(Parcel source) {
+            return new ClassificationsRequest(
+                    source.createTypedArrayList(ContentSelection.CREATOR),
+                    source.readBundle());
+        }
+
+        @Override
+        public ClassificationsRequest[] newArray(int size) {
+            return new ClassificationsRequest[size];
+        }
+    };
+
+    /**
+     * A builder for classifications request events.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+
+        private final List<ContentSelection> mSelections;
+        private Bundle mExtras;
+
+        public Builder(@NonNull List<ContentSelection> selections) {
+            mSelections = selections;
+        }
+
+        /**
+         * Sets the request extras.
+         */
+        public Builder setExtras(@NonNull Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Builds a new request instance.
+         */
+        public ClassificationsRequest build() {
+            return new ClassificationsRequest(mSelections, mExtras);
+        }
+    }
+}
diff --git a/core/java/android/app/contentsuggestions/ContentClassification.aidl b/core/java/android/app/contentsuggestions/ContentClassification.aidl
new file mode 100644
index 0000000..f67b2c8
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentClassification.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.contentsuggestions;
+
+parcelable ContentClassification;
diff --git a/core/java/android/app/contentsuggestions/ContentClassification.java b/core/java/android/app/contentsuggestions/ContentClassification.java
new file mode 100644
index 0000000..f18520f
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentClassification.java
@@ -0,0 +1,79 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class ContentClassification implements Parcelable {
+    @NonNull
+    private final String mClassificationId;
+    @NonNull
+    private final Bundle mExtras;
+
+    public ContentClassification(@NonNull String classificationId, @NonNull Bundle extras) {
+        mClassificationId = classificationId;
+        mExtras = extras;
+    }
+
+    /**
+     * Return the classification id.
+     */
+    public String getId() {
+        return mClassificationId;
+    }
+
+    /**
+     * Return the classification extras.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mClassificationId);
+        dest.writeBundle(mExtras);
+    }
+
+    public static final Creator<ContentClassification> CREATOR =
+            new Creator<ContentClassification>() {
+        @Override
+        public ContentClassification createFromParcel(Parcel source) {
+            return new ContentClassification(
+                    source.readString(),
+                    source.readBundle());
+        }
+
+        @Override
+        public ContentClassification[] newArray(int size) {
+            return new ContentClassification[size];
+        }
+    };
+}
diff --git a/core/java/android/app/contentsuggestions/ContentSelection.aidl b/core/java/android/app/contentsuggestions/ContentSelection.aidl
new file mode 100644
index 0000000..e626d69
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentSelection.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.contentsuggestions;
+
+parcelable ContentSelection;
diff --git a/core/java/android/app/contentsuggestions/ContentSelection.java b/core/java/android/app/contentsuggestions/ContentSelection.java
new file mode 100644
index 0000000..a8917f7
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentSelection.java
@@ -0,0 +1,79 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class ContentSelection implements Parcelable {
+    @NonNull
+    private final String mSelectionId;
+    @NonNull
+    private final Bundle mExtras;
+
+    public ContentSelection(@NonNull String selectionId, @NonNull Bundle extras) {
+        mSelectionId = selectionId;
+        mExtras = extras;
+    }
+
+    /**
+     * Return the selection id.
+     */
+    public String getId() {
+        return mSelectionId;
+    }
+
+    /**
+     * Return the selection extras.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mSelectionId);
+        dest.writeBundle(mExtras);
+    }
+
+    public static final Creator<ContentSelection> CREATOR =
+            new Creator<ContentSelection>() {
+        @Override
+        public ContentSelection createFromParcel(Parcel source) {
+            return new ContentSelection(
+                    source.readString(),
+                    source.readBundle());
+        }
+
+        @Override
+        public ContentSelection[] newArray(int size) {
+            return new ContentSelection[size];
+        }
+    };
+}
diff --git a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
new file mode 100644
index 0000000..b4d8977
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
@@ -0,0 +1,230 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * When provided with content from an app, can suggest selections and classifications of that
+ * content.
+ *
+ * <p>The content is mainly a snapshot of a running task, the selections will be text and image
+ * selections with that image content. These mSelections can then be classified to find actions and
+ * entities on those selections.
+ *
+ * <p>Only accessible to blessed components such as Overview.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ContentSuggestionsManager {
+    private static final String TAG = ContentSuggestionsManager.class.getSimpleName();
+
+    @Nullable
+    private final IContentSuggestionsManager mService;
+
+    /** @hide */
+    public ContentSuggestionsManager(@Nullable IContentSuggestionsManager service) {
+        mService = service;
+    }
+
+    /**
+     * Hints to the system that a new context image for the provided task should be sent to the
+     * system content suggestions service.
+     *
+     * @param taskId of the task to snapshot.
+     * @param imageContextRequestExtras sent with with request to provide implementation specific
+     *                                  extra information.
+     */
+    public void provideContextImage(int taskId, @NonNull Bundle imageContextRequestExtras) {
+        if (mService == null) {
+            Log.e(TAG, "provideContextImage called, but no ContentSuggestionsManager configured");
+            return;
+        }
+
+        try {
+            mService.provideContextImage(taskId, imageContextRequestExtras);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Suggest content selections, based on the provided task id and optional
+     * location on screen provided in the request. Called after provideContextImage().
+     * The result can be passed to
+     * {@link #classifyContentSelections(ClassificationsRequest, Executor, ClassificationsCallback)}
+     *  to classify actions and entities on these selections.
+     *
+     * @param request containing the task and point location.
+     * @param callbackExecutor to execute the provided callback on.
+     * @param callback to receive the selections.
+     */
+    public void suggestContentSelections(
+            @NonNull SelectionsRequest request,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull SelectionsCallback callback) {
+        if (mService == null) {
+            Log.e(TAG,
+                    "suggestContentSelections called, but no ContentSuggestionsManager configured");
+            return;
+        }
+
+        try {
+            mService.suggestContentSelections(
+                    request, new SelectionsCallbackWrapper(callback, callbackExecutor));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Classify actions and entities in content selections, as returned from
+     * suggestContentSelections. Note these selections may be modified by the
+     * caller before being passed here.
+     *
+     * @param request containing the selections to classify.
+     * @param callbackExecutor to execute the provided callback on.
+     * @param callback to receive the classifications.
+     */
+    public void classifyContentSelections(
+            @NonNull ClassificationsRequest request,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull ClassificationsCallback callback) {
+        if (mService == null) {
+            Log.e(TAG, "classifyContentSelections called, "
+                    + "but no ContentSuggestionsManager configured");
+            return;
+        }
+
+        try {
+            mService.classifyContentSelections(
+                    request, new ClassificationsCallbackWrapper(callback, callbackExecutor));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Report telemetry for interaction with suggestions / classifications.
+     *
+     * @param requestId the id for the associated interaction
+     * @param interaction to report back to the system content suggestions service.
+     */
+    public void notifyInteraction(@NonNull String requestId, @NonNull Bundle interaction) {
+        if (mService == null) {
+            Log.e(TAG, "notifyInteraction called, but no ContentSuggestionsManager configured");
+            return;
+        }
+
+        try {
+            mService.notifyInteraction(requestId, interaction);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Callback to receive content selections from
+     *  {@link #suggestContentSelections(SelectionsRequest, Executor, SelectionsCallback)}.
+     */
+    public interface SelectionsCallback {
+        /**
+         * Async callback called when the content suggestions service has selections available.
+         * These can be modified and sent back to the manager for classification. The contents of
+         * the selection is implementation dependent.
+         *
+         * @param statusCode as defined by the implementation of content suggestions service.
+         * @param selections not {@code null}, but can be size {@code 0}.
+         */
+        void onContentSelectionsAvailable(
+                int statusCode, @NonNull List<ContentSelection> selections);
+    }
+
+    /**
+     * Callback to receive classifications from
+     * {@link #classifyContentSelections(ClassificationsRequest, Executor, ClassificationsCallback)}
+     */
+    public interface ClassificationsCallback {
+        /**
+         * Async callback called when the content suggestions service has classified selections. The
+         * contents of the classification is implementation dependent.
+         *
+         * @param statusCode as defined by the implementation of content suggestions service.
+         * @param classifications not {@code null}, but can be size {@code 0}.
+         */
+        void onContentClassificationsAvailable(int statusCode,
+                @NonNull List<ContentClassification> classifications);
+    }
+
+    private static class SelectionsCallbackWrapper extends ISelectionsCallback.Stub {
+        private final SelectionsCallback mCallback;
+        private final Executor mExecutor;
+
+        SelectionsCallbackWrapper(
+                @NonNull SelectionsCallback callback, @NonNull Executor executor) {
+            mCallback = callback;
+            mExecutor = executor;
+        }
+
+        @Override
+        public void onContentSelectionsAvailable(
+                int statusCode, List<ContentSelection> selections) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() ->
+                        mCallback.onContentSelectionsAvailable(statusCode, selections));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    private static final class ClassificationsCallbackWrapper extends
+            IClassificationsCallback.Stub {
+        private final ClassificationsCallback mCallback;
+        private final Executor mExecutor;
+
+        ClassificationsCallbackWrapper(@NonNull ClassificationsCallback callback,
+                @NonNull Executor executor) {
+            mCallback = callback;
+            mExecutor = executor;
+        }
+
+        @Override
+        public void onContentClassificationsAvailable(
+                int statusCode, List<ContentClassification> classifications) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() ->
+                        mCallback.onContentClassificationsAvailable(statusCode, classifications));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+}
diff --git a/core/java/android/app/contentsuggestions/IClassificationsCallback.aidl b/core/java/android/app/contentsuggestions/IClassificationsCallback.aidl
new file mode 100644
index 0000000..69f5d55
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/IClassificationsCallback.aidl
@@ -0,0 +1,25 @@
+/**
+ * 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.contentsuggestions;
+
+import android.app.contentsuggestions.ContentClassification;
+
+/** @hide */
+oneway interface IClassificationsCallback {
+    void onContentClassificationsAvailable(
+            int statusCode, in List<ContentClassification> classifications);
+}
diff --git a/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
new file mode 100644
index 0000000..24f5ad8
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
@@ -0,0 +1,37 @@
+/*
+ * 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.contentsuggestions;
+
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.os.Bundle;
+
+/** @hide */
+oneway interface IContentSuggestionsManager {
+    void provideContextImage(
+            int taskId,
+            in Bundle imageContextRequestExtras);
+    void suggestContentSelections(
+            in SelectionsRequest request,
+            in ISelectionsCallback callback);
+    void classifyContentSelections(
+            in ClassificationsRequest request,
+            in IClassificationsCallback callback);
+    void notifyInteraction(in String requestId, in Bundle interaction);
+}
diff --git a/core/java/android/app/contentsuggestions/ISelectionsCallback.aidl b/core/java/android/app/contentsuggestions/ISelectionsCallback.aidl
new file mode 100644
index 0000000..1952583
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/ISelectionsCallback.aidl
@@ -0,0 +1,25 @@
+/**
+ * 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.contentsuggestions;
+
+import android.app.contentsuggestions.ContentSelection;
+import android.os.Bundle;
+
+/** @hide */
+oneway interface ISelectionsCallback {
+    void onContentSelectionsAvailable(int statusCode, in List<ContentSelection> selections);
+}
diff --git a/core/java/android/app/contentsuggestions/SelectionsRequest.aidl b/core/java/android/app/contentsuggestions/SelectionsRequest.aidl
new file mode 100644
index 0000000..f5ce7c3
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/SelectionsRequest.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.contentsuggestions;
+
+parcelable SelectionsRequest;
diff --git a/core/java/android/app/contentsuggestions/SelectionsRequest.java b/core/java/android/app/contentsuggestions/SelectionsRequest.java
new file mode 100644
index 0000000..16f3e6b
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/SelectionsRequest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class SelectionsRequest implements Parcelable {
+    private final int mTaskId;
+    @Nullable
+    private final Point mInterestPoint;
+    @Nullable
+    private final Bundle mExtras;
+
+    private SelectionsRequest(int taskId, @Nullable Point interestPoint, @Nullable Bundle extras) {
+        mTaskId = taskId;
+        mInterestPoint = interestPoint;
+        mExtras = extras;
+    }
+
+    /**
+     * Return the request task id.
+     */
+    public int getTaskId() {
+        return mTaskId;
+    }
+
+    /**
+     * Return the request point of interest.
+     */
+    public Point getInterestPoint() {
+        return mInterestPoint;
+    }
+
+    /**
+     * Return the request extras.
+     */
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mTaskId);
+        dest.writeTypedObject(mInterestPoint, flags);
+        dest.writeBundle(mExtras);
+    }
+
+    public static final Creator<SelectionsRequest> CREATOR =
+            new Creator<SelectionsRequest>() {
+        @Override
+        public SelectionsRequest createFromParcel(Parcel source) {
+            return new SelectionsRequest(
+                    source.readInt(), source.readTypedObject(Point.CREATOR), source.readBundle());
+        }
+
+        @Override
+        public SelectionsRequest[] newArray(int size) {
+            return new SelectionsRequest[size];
+        }
+    };
+
+    /**
+     * A builder for selections requests events.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+
+        private final int mTaskId;
+        private Point mInterestPoint;
+        private Bundle mExtras;
+
+        public Builder(int taskId) {
+            mTaskId = taskId;
+        }
+
+        /**
+         * Sets the request extras.
+         */
+        public Builder setExtras(@NonNull Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Sets the request interest point.
+         */
+        public Builder setInterestPoint(@NonNull Point interestPoint) {
+            mInterestPoint = interestPoint;
+            return this;
+        }
+
+        /**
+         * Builds a new request instance.
+         */
+        public SelectionsRequest build() {
+            return new SelectionsRequest(mTaskId, mInterestPoint, mExtras);
+        }
+    }
+}
diff --git a/core/java/android/app/prediction/AppPredictionContext.aidl b/core/java/android/app/prediction/AppPredictionContext.aidl
new file mode 100644
index 0000000..5767bf4
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionContext.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.prediction;
+
+parcelable AppPredictionContext;
diff --git a/core/java/android/app/prediction/AppPredictionContext.java b/core/java/android/app/prediction/AppPredictionContext.java
new file mode 100644
index 0000000..87ccb66
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionContext.java
@@ -0,0 +1,158 @@
+/*
+ * 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.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * TODO(b/111701043): Add java docs
+ *
+ * @hide
+ */
+@SystemApi
+public final class AppPredictionContext implements Parcelable {
+
+    private final int mPredictedTargetCount;
+    @NonNull
+    private final String mUiSurface;
+    @NonNull
+    private final String mPackageName;
+    @Nullable
+    private final Bundle mExtras;
+
+    private AppPredictionContext(@NonNull String uiSurface, int numPredictedTargets,
+            @NonNull String packageName, @Nullable Bundle extras) {
+        mUiSurface = uiSurface;
+        mPredictedTargetCount = numPredictedTargets;
+        mPackageName = packageName;
+        mExtras = extras;
+    }
+
+    private AppPredictionContext(Parcel parcel) {
+        mUiSurface = parcel.readString();
+        mPredictedTargetCount = parcel.readInt();
+        mPackageName = parcel.readString();
+        mExtras = parcel.readBundle();
+    }
+
+    public String getUiSurface() {
+        return mUiSurface;
+    }
+
+    public int getPredictedTargetCount() {
+        return mPredictedTargetCount;
+    }
+
+    @NonNull
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    @Nullable
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mUiSurface);
+        dest.writeInt(mPredictedTargetCount);
+        dest.writeString(mPackageName);
+        dest.writeBundle(mExtras);
+    }
+
+    /**
+     * @see Parcelable.Creator
+     */
+    public static final Parcelable.Creator<AppPredictionContext> CREATOR =
+            new Parcelable.Creator<AppPredictionContext>() {
+                public AppPredictionContext createFromParcel(Parcel parcel) {
+                    return new AppPredictionContext(parcel);
+                }
+
+                public AppPredictionContext[] newArray(int size) {
+                    return new AppPredictionContext[size];
+                }
+            };
+
+    /**
+     * A builder for app prediction contexts.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+
+        @NonNull
+        private final String mPackageName;
+
+        private int mPredictedTargetCount;
+        @Nullable
+        private String mUiSurface;
+        @Nullable
+        private Bundle mExtras;
+
+        /**
+         * @hide
+         */
+        public Builder(@NonNull Context context) {
+            mPackageName = context.getPackageName();
+        }
+
+
+        /**
+         * Sets the number of prediction targets as a hint.
+         */
+        public Builder setPredictedTargetCount(int predictedTargetCount) {
+            mPredictedTargetCount = predictedTargetCount;
+            return this;
+        }
+
+        /**
+         * Sets the UI surface.
+         */
+        public Builder setUiSurface(@Nullable String uiSurface) {
+            mUiSurface = uiSurface;
+            return this;
+        }
+
+        /**
+         * Sets the extras.
+         */
+        public Builder setExtras(@Nullable Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Builds a new context instance.
+         */
+        public AppPredictionContext build() {
+            return new AppPredictionContext(mUiSurface, mPredictedTargetCount, mPackageName,
+                    mExtras);
+        }
+    }
+}
diff --git a/core/java/android/app/prediction/AppPredictionManager.java b/core/java/android/app/prediction/AppPredictionManager.java
new file mode 100644
index 0000000..f8578d4
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionManager.java
@@ -0,0 +1,47 @@
+/*
+ * 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.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.content.Context;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * TODO (b/111701043) : Add java doc
+ * @hide
+ */
+@SystemApi
+public final class AppPredictionManager {
+
+    private final Context mContext;
+
+    /**
+     * @hide
+     */
+    public AppPredictionManager(Context context) {
+        mContext = Preconditions.checkNotNull(context);
+    }
+
+    /**
+     * Creates a new app prediction session.
+     */
+    public AppPredictor createAppPredictionSession(
+            @NonNull AppPredictionContext predictionContext) {
+        return new AppPredictor(mContext, predictionContext);
+    }
+}
diff --git a/core/java/android/app/prediction/AppPredictionSessionId.aidl b/core/java/android/app/prediction/AppPredictionSessionId.aidl
new file mode 100644
index 0000000..e829526
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionSessionId.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.prediction;
+
+parcelable AppPredictionSessionId;
diff --git a/core/java/android/app/prediction/AppPredictionSessionId.java b/core/java/android/app/prediction/AppPredictionSessionId.java
new file mode 100644
index 0000000..1d7308e
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictionSessionId.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.app.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * TODO (b/111701043) : Add java doc
+ *
+ * @hide
+ */
+@SystemApi
+public final class AppPredictionSessionId implements Parcelable {
+
+    private final String mId;
+
+    /**
+     * @hide
+     */
+    public AppPredictionSessionId(@NonNull String id) {
+        mId = id;
+    }
+
+    private AppPredictionSessionId(Parcel p) {
+        mId = p.readString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!getClass().equals(o != null ? o.getClass() : null)) return false;
+
+        AppPredictionSessionId other = (AppPredictionSessionId) o;
+        return mId.equals(other.mId);
+    }
+
+    @Override
+    public @NonNull String toString() {
+        return mId;
+    }
+
+    @Override
+    public int hashCode() {
+        // Ensure that the id has a consistent hash
+        return mId.hashCode();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mId);
+    }
+
+    /**
+     * @see Parcelable.Creator
+     */
+    public static final Parcelable.Creator<AppPredictionSessionId> CREATOR =
+            new Parcelable.Creator<AppPredictionSessionId>() {
+                public AppPredictionSessionId createFromParcel(Parcel parcel) {
+                    return new AppPredictionSessionId(parcel);
+                }
+
+                public AppPredictionSessionId[] newArray(int size) {
+                    return new AppPredictionSessionId[size];
+                }
+            };
+}
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
new file mode 100644
index 0000000..2ddbd08
--- /dev/null
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -0,0 +1,257 @@
+/*
+ * 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.prediction;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.prediction.IPredictionCallback.Stub;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import dalvik.system.CloseGuard;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+
+/**
+ * TODO (b/111701043) : Add java doc
+ *
+ * <p>
+ * Usage: <pre> {@code
+ *
+ * class MyActivity {
+ *    private AppPredictor mClient
+ *
+ *    void onCreate() {
+ *         mClient = new AppPredictor(...)
+ *    }
+ *
+ *    void onStart() {
+ *        mClient.requestPredictionUpdate();
+ *    }
+ *
+ *    void onDestroy() {
+ *        mClient.close();
+ *    }
+ *
+ * }</pre>
+ *
+ * @hide
+ */
+@SystemApi
+public final class AppPredictor {
+
+    private static final String TAG = AppPredictor.class.getSimpleName();
+
+
+    private final IPredictionManager mPredictionManager;
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+    private final AtomicBoolean mIsClosed = new AtomicBoolean(false);
+
+    private final AppPredictionSessionId mSessionId;
+    private final ArrayMap<Callback, CallbackWrapper> mRegisteredCallbacks = new ArrayMap<>();
+
+    /**
+     * Creates a new Prediction client.
+     * <p>
+     * The caller should call {@link AppPredictor#destroy()} to dispose the client once it
+     * no longer used.
+     *
+     * @param predictionContext The prediction context
+     */
+    AppPredictor(@NonNull Context context, @NonNull AppPredictionContext predictionContext) {
+        IBinder b = ServiceManager.getService(Context.APP_PREDICTION_SERVICE);
+        mPredictionManager = IPredictionManager.Stub.asInterface(b);
+        mSessionId = new AppPredictionSessionId(
+                context.getPackageName() + ":" + UUID.randomUUID().toString());
+        try {
+            mPredictionManager.createPredictionSession(predictionContext, mSessionId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to create predictor", e);
+            return;
+        }
+
+        mCloseGuard.open("close");
+    }
+
+    /**
+     * Notifies the prediction service of an app target event.
+     */
+    public void notifyAppTargetEvent(@NonNull AppTargetEvent event) {
+        try {
+            mPredictionManager.notifyAppTargetEvent(mSessionId, event);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to notify app target event", e);
+        }
+    }
+
+    /**
+     * Notifies the prediction service when the targets in a launch location are shown to the user.
+     */
+    public void notifyLocationShown(@NonNull String launchLocation,
+            @NonNull List<AppTargetId> targetIds) {
+        try {
+            mPredictionManager.notifyLocationShown(mSessionId, launchLocation,
+                    new ParceledListSlice<>(targetIds));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to notify location shown event", e);
+        }
+    }
+
+    /**
+     * Requests the prediction service provide continuous updates of App predictions via the
+     * provided callback, until the given callback is unregistered.
+     *
+     * @see Callback#onTargetsAvailable(List)
+     */
+    public void registerPredictionUpdates(@NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull AppPredictor.Callback callback) {
+        if (mRegisteredCallbacks.containsKey(callback)) {
+            // Skip if this callback is already registered
+            return;
+        }
+        try {
+            final CallbackWrapper callbackWrapper = new CallbackWrapper(callbackExecutor,
+                    callback::onTargetsAvailable);
+            mPredictionManager.registerPredictionUpdates(mSessionId, callbackWrapper);
+            mRegisteredCallbacks.put(callback, callbackWrapper);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to register for prediction updates", e);
+        }
+    }
+
+    /**
+     * Requests the prediction service to stop providing continuous updates to the provided
+     * callback until the callback is re-registered.
+     */
+    public void unregisterPredictionUpdates(@NonNull AppPredictor.Callback callback) {
+        if (!mRegisteredCallbacks.containsKey(callback)) {
+            // Skip if this callback was never registered
+            return;
+        }
+        try {
+            final CallbackWrapper callbackWrapper = mRegisteredCallbacks.remove(callback);
+            mPredictionManager.unregisterPredictionUpdates(mSessionId, callbackWrapper);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to unregister for prediction updates", e);
+        }
+    }
+
+    /**
+     * Requests the prediction service to dispatch a new set of App predictions via the provided
+     * callback.
+     *
+     * @see Callback#onTargetsAvailable(List)
+     */
+    public void requestPredictionUpdate() {
+        try {
+            mPredictionManager.requestPredictionUpdate(mSessionId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to request prediction update", e);
+        }
+    }
+
+    /**
+     * Returns a new list of AppTargets sorted based on prediction rank or {@code null} if the
+     * ranker is not available.
+     */
+    @Nullable
+    public void sortTargets(@NonNull List<AppTarget> targets,
+            @NonNull Executor callbackExecutor, @NonNull Consumer<List<AppTarget>> callback) {
+        try {
+            mPredictionManager.sortAppTargets(mSessionId, new ParceledListSlice(targets),
+                    new CallbackWrapper(callbackExecutor, callback));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to sort targets", e);
+        }
+    }
+
+    /**
+     * Destroys the client and unregisters the callback. Any method on this class after this call
+     * with throw {@link IllegalStateException}.
+     *
+     * TODO(b/111701043): Add state check in other methods.
+     */
+    public void destroy() {
+        if (!mIsClosed.getAndSet(true)) {
+            mCloseGuard.close();
+
+            // Do destroy;
+            try {
+                mPredictionManager.onDestroyPredictionSession(mSessionId);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to notify app target event", e);
+            }
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+            destroy();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Callback for receiving prediction updates.
+     */
+    public interface Callback {
+
+        /**
+         * Called when a new set of predicted app targets are available.
+         * @param targets Sorted list of predicted targets
+         */
+        void onTargetsAvailable(@NonNull List<AppTarget> targets);
+    }
+
+    static class CallbackWrapper extends Stub {
+
+        private final Consumer<List<AppTarget>> mCallback;
+        private final Executor mExecutor;
+
+        CallbackWrapper(@NonNull Executor callbackExecutor,
+                @NonNull Consumer<List<AppTarget>> callback) {
+            mCallback = callback;
+            mExecutor = callbackExecutor;
+        }
+
+        @Override
+        public void onResult(ParceledListSlice result) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.accept(result.getList()));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+}
diff --git a/core/java/android/app/prediction/AppTarget.aidl b/core/java/android/app/prediction/AppTarget.aidl
new file mode 100644
index 0000000..e4e2bc2
--- /dev/null
+++ b/core/java/android/app/prediction/AppTarget.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.prediction;
+
+parcelable AppTarget;
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
new file mode 100644
index 0000000..99c1c44
--- /dev/null
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -0,0 +1,166 @@
+/*
+ * 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.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.pm.ShortcutInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A representation of a launchable target.
+ * @hide
+ */
+@SystemApi
+public final class AppTarget implements Parcelable {
+
+    private final AppTargetId mId;
+    private final String mPackageName;
+    private final String mClassName;
+    private final UserHandle mUser;
+
+    private final ShortcutInfo mShortcutInfo;
+
+    private int mRank;
+
+    /**
+     * @hide
+     */
+    public AppTarget(@NonNull AppTargetId id, @NonNull String packageName,
+            @Nullable String className, @NonNull UserHandle user) {
+        mId = id;
+        mShortcutInfo = null;
+
+        mPackageName = Preconditions.checkNotNull(packageName);
+        mClassName = className;
+        mUser = Preconditions.checkNotNull(user);
+    }
+
+    /**
+     * @hide
+     */
+    public AppTarget(@NonNull AppTargetId id, @NonNull ShortcutInfo shortcutInfo) {
+        mId = id;
+        mShortcutInfo = Preconditions.checkNotNull(shortcutInfo);
+
+        mPackageName = mShortcutInfo.getPackage();
+        mUser = mShortcutInfo.getUserHandle();
+        mClassName = null;
+    }
+
+    private AppTarget(Parcel parcel) {
+        mId = parcel.readTypedObject(AppTargetId.CREATOR);
+        mShortcutInfo = parcel.readTypedObject(ShortcutInfo.CREATOR);
+        if (mShortcutInfo == null) {
+            mPackageName = parcel.readString();
+            mClassName = parcel.readString();
+            mUser = UserHandle.of(parcel.readInt());
+        } else {
+            mPackageName = mShortcutInfo.getPackage();
+            mUser = mShortcutInfo.getUserHandle();
+            mClassName = null;
+        }
+        mRank = parcel.readInt();
+    }
+
+    /**
+     * Returns the target id.
+     */
+    @NonNull
+    public AppTargetId getId() {
+        return mId;
+    }
+
+    /**
+     * Returns the class name for the app target.
+     */
+    @Nullable
+    public String getClassName() {
+        return mClassName;
+    }
+
+    /**
+     * Returns the package name for the app target.
+     */
+    @NonNull
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * Returns the user for the app target.
+     */
+    @NonNull
+    public UserHandle getUser() {
+        return mUser;
+    }
+
+    /**
+     * Returns the shortcut info for the target.
+     */
+    @Nullable
+    public ShortcutInfo getShortcutInfo() {
+        return mShortcutInfo;
+    }
+
+    /**
+     * Sets the rank of the for the target.
+     * @hide
+     */
+    public void setRank(int rank) {
+        mRank = rank;
+    }
+
+    public int getRank() {
+        return mRank;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeTypedObject(mId, flags);
+        dest.writeTypedObject(mShortcutInfo, flags);
+        if (mShortcutInfo == null) {
+            dest.writeString(mPackageName);
+            dest.writeString(mClassName);
+            dest.writeInt(mUser.getIdentifier());
+        }
+        dest.writeInt(mRank);
+    }
+
+    /**
+     * @see Parcelable.Creator
+     */
+    public static final Parcelable.Creator<AppTarget> CREATOR =
+            new Parcelable.Creator<AppTarget>() {
+                public AppTarget createFromParcel(Parcel parcel) {
+                    return new AppTarget(parcel);
+                }
+
+                public AppTarget[] newArray(int size) {
+                    return new AppTarget[size];
+                }
+            };
+}
diff --git a/core/java/android/app/prediction/AppTargetEvent.aidl b/core/java/android/app/prediction/AppTargetEvent.aidl
new file mode 100644
index 0000000..ebed2da
--- /dev/null
+++ b/core/java/android/app/prediction/AppTargetEvent.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.prediction;
+
+parcelable AppTargetEvent;
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
new file mode 100644
index 0000000..18317e1
--- /dev/null
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -0,0 +1,154 @@
+/*
+ * 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.prediction;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A representation of an app target event.
+ * @hide
+ */
+@SystemApi
+public final class AppTargetEvent implements Parcelable {
+
+    /**
+     * @hide
+     */
+    @IntDef({ACTION_LAUNCH, ACTION_DISMISS, ACTION_PIN})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ActionType {}
+
+    /**
+     * Event type constant indicating an app target has been launched.
+     */
+    public static final int ACTION_LAUNCH = 1;
+
+    /**
+     * Event type constant indicating an app target has been dismissed.
+     */
+    public static final int ACTION_DISMISS = 2;
+
+    /**
+     * Event type constant indicating an app target has been pinned.
+     */
+    public static final int ACTION_PIN = 3;
+
+    private final AppTarget mTarget;
+    private final String mLocation;
+    private final int mAction;
+
+    private AppTargetEvent(@Nullable AppTarget target, @Nullable String location,
+            @ActionType int actionType) {
+        mTarget = target;
+        mLocation = location;
+        mAction = actionType;
+    }
+
+    private AppTargetEvent(Parcel parcel) {
+        mTarget = parcel.readParcelable(null);
+        mLocation = parcel.readString();
+        mAction = parcel.readInt();
+    }
+
+    /**
+     * Returns the app target.
+     */
+    @Nullable
+    public AppTarget getTarget() {
+        return mTarget;
+    }
+
+    /**
+     * Returns the launch location.
+     */
+    @NonNull
+    public String getLaunchLocation() {
+        return mLocation;
+    }
+
+    /**
+     * Returns the action type.
+     */
+    @NonNull
+    public int getAction() {
+        return mAction;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mTarget, 0);
+        dest.writeString(mLocation);
+        dest.writeInt(mAction);
+    }
+
+    /**
+     * @see Creator
+     */
+    public static final Creator<AppTargetEvent> CREATOR =
+            new Creator<AppTargetEvent>() {
+                public AppTargetEvent createFromParcel(Parcel parcel) {
+                    return new AppTargetEvent(parcel);
+                }
+
+                public AppTargetEvent[] newArray(int size) {
+                    return new AppTargetEvent[size];
+                }
+            };
+
+    /**
+     * A builder for app target events.
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+        private AppTarget mTarget;
+        private String mLocation;
+        private @ActionType int mAction;
+
+        public Builder(@Nullable AppTarget target, @ActionType int actionType) {
+            mTarget = target;
+            mAction = actionType;
+        }
+
+        /**
+         * Sets the launch location.
+         */
+        public Builder setLaunchLocation(String location) {
+            mLocation = location;
+            return this;
+        }
+
+        /**
+         * Builds a new event instance.
+         */
+        public AppTargetEvent build() {
+            return new AppTargetEvent(mTarget, mLocation, mAction);
+        }
+    }
+}
diff --git a/core/java/android/app/prediction/AppTargetId.aidl b/core/java/android/app/prediction/AppTargetId.aidl
new file mode 100644
index 0000000..bf69eea
--- /dev/null
+++ b/core/java/android/app/prediction/AppTargetId.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.prediction;
+
+parcelable AppTargetId;
diff --git a/core/java/android/app/prediction/AppTargetId.java b/core/java/android/app/prediction/AppTargetId.java
new file mode 100644
index 0000000..0b8fb47
--- /dev/null
+++ b/core/java/android/app/prediction/AppTargetId.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 android.app.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * The id for a prediction target.
+ * @hide
+ */
+@SystemApi
+public final class AppTargetId implements Parcelable {
+
+    @NonNull
+    private final String mId;
+
+    /**
+     * @hide
+     */
+    public AppTargetId(@NonNull String id) {
+        mId = id;
+    }
+
+    private AppTargetId(Parcel parcel) {
+        mId = parcel.readString();
+    }
+
+    /**
+     * Returns the id.
+     * @hide
+     */
+    @NonNull
+    public String getId() {
+        return mId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!getClass().equals(o != null ? o.getClass() : null)) return false;
+
+        AppTargetId other = (AppTargetId) o;
+        return mId.equals(other.mId);
+    }
+
+    @Override
+    public int hashCode() {
+        // Ensure that the id has a consistent hash
+        return mId.hashCode();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mId);
+    }
+
+    /**
+     * @see Creator
+     */
+    public static final Creator<AppTargetId> CREATOR =
+            new Creator<AppTargetId>() {
+                public AppTargetId createFromParcel(Parcel parcel) {
+                    return new AppTargetId(parcel);
+                }
+
+                public AppTargetId[] newArray(int size) {
+                    return new AppTargetId[size];
+                }
+            };
+}
diff --git a/core/java/android/app/prediction/IPredictionCallback.aidl b/core/java/android/app/prediction/IPredictionCallback.aidl
new file mode 100644
index 0000000..f6f241e
--- /dev/null
+++ b/core/java/android/app/prediction/IPredictionCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.prediction;
+
+import android.content.pm.ParceledListSlice;
+
+/**
+ * @hide
+ */
+oneway interface IPredictionCallback {
+
+    void onResult(in ParceledListSlice result);
+}
diff --git a/core/java/android/app/prediction/IPredictionManager.aidl b/core/java/android/app/prediction/IPredictionManager.aidl
new file mode 100644
index 0000000..114a1ff
--- /dev/null
+++ b/core/java/android/app/prediction/IPredictionManager.aidl
@@ -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 android.app.prediction;
+
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.IPredictionCallback;
+import android.content.pm.ParceledListSlice;
+
+/**
+ * @hide
+ */
+interface IPredictionManager {
+
+    void createPredictionSession(in AppPredictionContext context,
+            in AppPredictionSessionId sessionId);
+
+    void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event);
+
+    void notifyLocationShown(in AppPredictionSessionId sessionId, in String launchLocation,
+            in ParceledListSlice targetIds);
+
+    void sortAppTargets(in AppPredictionSessionId sessionId, in ParceledListSlice targets,
+            in IPredictionCallback callback);
+
+    void registerPredictionUpdates(in AppPredictionSessionId sessionId,
+            in IPredictionCallback callback);
+
+    void unregisterPredictionUpdates(in AppPredictionSessionId sessionId,
+            in IPredictionCallback callback);
+
+    void requestPredictionUpdate(in AppPredictionSessionId sessionId);
+
+    void onDestroyPredictionSession(in AppPredictionSessionId sessionId);
+}
diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl
index 0c9b41bf..2964fbc 100644
--- a/core/java/android/app/role/IRoleManager.aidl
+++ b/core/java/android/app/role/IRoleManager.aidl
@@ -50,4 +50,6 @@
     boolean removeRoleHolderFromController(in String roleName, in String packageName);
 
     List<String> getHeldRolesFromController(in String packageName);
+
+    String getDefaultSmsPackage(int userId);
 }
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index 2d630a6..a6abe0b 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -68,6 +69,8 @@
 
     /**
      * The name of the dialer role.
+     *
+     * @see Intent#ACTION_DIAL
      */
     public static final String ROLE_DIALER = "android.app.role.DIALER";
 
@@ -100,6 +103,75 @@
     public static final String ROLE_MUSIC = "android.app.role.MUSIC";
 
     /**
+     * The name of the home role.
+     *
+     * @see Intent#CATEGORY_HOME
+     */
+    public static final String ROLE_HOME = "android.app.role.HOME";
+
+    /**
+     * The name of the emergency role
+     *
+     * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
+     */
+    public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
+
+    /**
+     * The name of the car mode dialer app role.
+     * <p>
+     * Similar to the {@link #ROLE_DIALER dialer} role, this role determines which app is
+     * responsible for showing the user interface for ongoing calls on the device. It is only used
+     * when the device is in car mode.
+     *
+     * @see #ROLE_DIALER
+     * @see android.app.UiModeManager#ACTION_ENTER_CAR_MODE
+     * @see android.telecom.InCallService
+     *
+     * TODO: STOPSHIP: Make name of required roles public API
+     * @hide
+     */
+    public static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER_APP";
+
+    /**
+     * The name of the proxy calling role.
+     * <p>
+     * A proxy calling app provides a means to re-write the phone number for an outgoing call to
+     * place the call through a proxy calling service.
+     *
+     * @see android.telecom.CallRedirectionService
+     *
+     * TODO: STOPSHIP: Make name of required roles public API
+     * @hide
+     */
+    public static final String ROLE_PROXY_CALLING_APP = "android.app.role.PROXY_CALLING_APP";
+
+    /**
+     * The name of the call screening and caller id role.
+     *
+     * @see android.telecom.CallScreeningService
+     *
+     * TODO: STOPSHIP: Make name of required roles public API
+     * @hide
+     */
+    public static final String ROLE_CALL_SCREENING_APP = "android.app.role.CALL_SCREENING_APP";
+
+    /**
+     * The name of the call companion app role.
+     * <p>
+     * A call companion app provides no user interface for calls, but will be bound to by Telecom
+     * when there are active calls on the device. Companion apps for wearable devices are an
+     * acceptable use-case.
+     * <p>
+     * Multiple apps may hold this role at the same time.
+     *
+     * @see android.telecom.InCallService
+     *
+     * TODO: STOPSHIP: Make name of required roles public API
+     * @hide
+     */
+    public static final String ROLE_CALL_COMPANION_APP = "android.app.role.CALL_COMPANION_APP";
+
+    /**
      * The action used to request user approval of a role for an application.
      *
      * @hide
@@ -107,16 +179,6 @@
     public static final String ACTION_REQUEST_ROLE = "android.app.role.action.REQUEST_ROLE";
 
     /**
-     * The name of the requested role.
-     * <p>
-     * <strong>Type:</strong> String
-     *
-     * @hide
-     */
-    @SystemApi
-    public static final String EXTRA_REQUEST_ROLE_NAME = "android.app.role.extra.REQUEST_ROLE_NAME";
-
-    /**
      * The permission required to manage records of role holders in {@link RoleManager} directly.
      *
      * @hide
@@ -164,7 +226,7 @@
         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
         Intent intent = new Intent(ACTION_REQUEST_ROLE);
         intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
-        intent.putExtra(EXTRA_REQUEST_ROLE_NAME, roleName);
+        intent.putExtra(Intent.EXTRA_ROLE_NAME, roleName);
         return intent;
     }
 
@@ -542,7 +604,6 @@
         }
     }
 
-
     /**
      * Returns the list of all roles that the given package is currently holding
      *
@@ -563,6 +624,22 @@
         }
     }
 
+    /**
+     * Allows getting the role holder for {@link #ROLE_SMS} without
+     * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as required by
+     * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}
+     *
+     * @hide
+     */
+    @Nullable
+    public String getDefaultSmsPackage(@UserIdInt int userId) {
+        try {
+            return mService.getDefaultSmsPackage(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private static class RoleManagerCallbackDelegate extends IRoleManagerCallback.Stub {
 
         @NonNull
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
index a2b7d58..8ee9e53 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -36,6 +36,11 @@
     private Configuration mConfiguration;
 
     @Override
+    public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
+        client.updatePendingActivityConfiguration(token, mConfiguration);
+    }
+
+    @Override
     public void execute(ClientTransactionHandler client, IBinder token,
             PendingTransactionActions pendingActions) {
         // TODO(lifecycler): detect if PIP or multi-window mode changed and report it here.
diff --git a/core/java/android/app/usage/EventList.java b/core/java/android/app/usage/EventList.java
index a79ad2f..aaae57e5 100644
--- a/core/java/android/app/usage/EventList.java
+++ b/core/java/android/app/usage/EventList.java
@@ -103,21 +103,4 @@
         }
         return result;
     }
-
-    /**
-     * Remove events of certain type on or after a timestamp.
-     * @param type The type of event to remove.
-     * @param timeStamp the timeStamp on or after which to remove the event.
-     */
-    public void removeOnOrAfter(int type, long timeStamp) {
-        for (int i = mEvents.size() - 1; i >= 0; i--) {
-            UsageEvents.Event event = mEvents.get(i);
-            if (event.mTimeStamp < timeStamp) {
-                break;
-            }
-            if (event.mEventType == type) {
-                mEvents.remove(i);
-            }
-        }
-    }
 }
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 4d52263..d2934b9 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -55,4 +55,10 @@
             long sessionThresholdTimeMs, in PendingIntent limitReachedCallbackIntent,
             in PendingIntent sessionEndCallbackIntent, String callingPackage);
     void unregisterUsageSessionObserver(int sessionObserverId, String callingPackage);
+    void reportUsageStart(in IBinder activity, String token, String callingPackage);
+    void reportPastUsageStart(in IBinder activity, String token, long timeAgoMs,
+            String callingPackage);
+    void reportUsageStop(in IBinder activity, String token, String callingPackage);
+    int getUsageSource();
+    void forceUsageSourceSettingRead();
 }
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index d7a5328..451f44b 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -16,6 +16,7 @@
 package android.app.usage;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.res.Configuration;
@@ -245,10 +246,18 @@
         public static final int FLUSH_TO_DISK = 25;
 
         /**
+         * An event type denoting that the device underwent a shutdown process.
+         * A DEVICE_SHUTDOWN event should be treated as if all started activities and foreground
+         * services are now stopped and no explicit {@link #ACTIVITY_STOPPED} and
+         * {@link #FOREGROUND_SERVICE_STOP} events will be generated for them.
+         */
+        public static final int DEVICE_SHUTDOWN = 26;
+
+        /**
          * Keep in sync with the greatest event type value.
          * @hide
          */
-        public static final int MAX_EVENT_TYPE = 25;
+        public static final int MAX_EVENT_TYPE = 26;
 
         /** @hide */
         public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
@@ -278,7 +287,6 @@
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public String mClass;
 
-
         /**
          * {@hide}
          */
@@ -287,6 +295,16 @@
         /**
          * {@hide}
          */
+        public String mTaskRootPackage;
+
+        /**
+         * {@hide}
+         */
+        public String mTaskRootClass;
+
+        /**
+         * {@hide}
+         */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public long mTimeStamp;
 
@@ -365,6 +383,8 @@
             mPackage = orig.mPackage;
             mClass = orig.mClass;
             mInstanceId = orig.mInstanceId;
+            mTaskRootPackage = orig.mTaskRootPackage;
+            mTaskRootClass = orig.mTaskRootClass;
             mTimeStamp = orig.mTimeStamp;
             mEventType = orig.mEventType;
             mConfiguration = orig.mConfiguration;
@@ -403,6 +423,28 @@
         }
 
         /**
+         * The package name of the task root when this event was reported.
+         * Or {@code null} for queries from apps without {@link
+         * android.Manifest.permission#PACKAGE_USAGE_STATS}
+         * @hide
+         */
+        @SystemApi
+        public @Nullable String getTaskRootPackageName() {
+            return mTaskRootPackage;
+        }
+
+        /**
+         * The class name of the task root when this event was reported.
+         * Or {@code null} for queries from apps without {@link
+         * android.Manifest.permission#PACKAGE_USAGE_STATS}
+         * @hide
+         */
+        @SystemApi
+        public @Nullable String getTaskRootClassName() {
+            return mTaskRootClass;
+        }
+
+        /**
          * The time at which this event occurred, measured in milliseconds since the epoch.
          * <p/>
          * See {@link System#currentTimeMillis()}.
@@ -514,6 +556,9 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mIndex = 0;
 
+    // Only used when parceling events. If false, task roots will be omitted from the parcel
+    private final boolean mIncludeTaskRoots;
+
     /*
      * In order to save space, since ComponentNames will be duplicated everywhere,
      * we use a map and index into it.
@@ -544,6 +589,7 @@
             mParcel.setDataSize(mParcel.dataPosition());
             mParcel.setDataPosition(positionInParcel);
         }
+        mIncludeTaskRoots = true;
     }
 
     /**
@@ -552,16 +598,27 @@
      */
     UsageEvents() {
         mEventCount = 0;
+        mIncludeTaskRoots = true;
+    }
+
+    /**
+     * Construct the iterator in preparation for writing it to a parcel.
+     * Defaults to excluding task roots from the parcel.
+     * {@hide}
+     */
+    public UsageEvents(List<Event> events, String[] stringPool) {
+        this(events, stringPool, false);
     }
 
     /**
      * Construct the iterator in preparation for writing it to a parcel.
      * {@hide}
      */
-    public UsageEvents(List<Event> events, String[] stringPool) {
+    public UsageEvents(List<Event> events, String[] stringPool, boolean includeTaskRoots) {
         mStringPool = stringPool;
         mEventCount = events.size();
         mEventsToWrite = events;
+        mIncludeTaskRoots = includeTaskRoots;
     }
 
     /**
@@ -637,9 +694,25 @@
         } else {
             classIndex = -1;
         }
+
+        final int taskRootPackageIndex;
+        if (mIncludeTaskRoots && event.mTaskRootPackage != null) {
+            taskRootPackageIndex = findStringIndex(event.mTaskRootPackage);
+        } else {
+            taskRootPackageIndex = -1;
+        }
+
+        final int taskRootClassIndex;
+        if (mIncludeTaskRoots && event.mTaskRootClass != null) {
+            taskRootClassIndex = findStringIndex(event.mTaskRootClass);
+        } else {
+            taskRootClassIndex = -1;
+        }
         p.writeInt(packageIndex);
         p.writeInt(classIndex);
         p.writeInt(event.mInstanceId);
+        p.writeInt(taskRootPackageIndex);
+        p.writeInt(taskRootClassIndex);
         p.writeInt(event.mEventType);
         p.writeLong(event.mTimeStamp);
 
@@ -683,6 +756,21 @@
             eventOut.mClass = null;
         }
         eventOut.mInstanceId = p.readInt();
+
+        final int taskRootPackageIndex = p.readInt();
+        if (taskRootPackageIndex >= 0) {
+            eventOut.mTaskRootPackage = mStringPool[taskRootPackageIndex];
+        } else {
+            eventOut.mTaskRootPackage = null;
+        }
+
+        final int taskRootClassIndex = p.readInt();
+        if (taskRootClassIndex >= 0) {
+            eventOut.mTaskRootClass = mStringPool[taskRootClassIndex];
+        } else {
+            eventOut.mTaskRootClass = null;
+        }
+
         eventOut.mEventType = p.readInt();
         eventOut.mTimeStamp = p.readLong();
 
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 308180b..94a2a3e 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -21,6 +21,7 @@
 import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
 import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED;
 import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE;
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
 import static android.app.usage.UsageEvents.Event.END_OF_DAY;
 import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK;
 import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START;
@@ -119,12 +120,9 @@
     public int mLastEvent;
 
     /**
-     * If an activity is visible(onStart(), onPause() states) or in foreground (onResume() state),
-     * it has one entry in this map. When an activity becomes invisible (onStop() or onDestroy()),
-     * it is removed from this map.
      * Key is instanceId of the activity (ActivityRecode appToken hashCode)..
-     * Value is this activity's last event, one of ACTIVITY_RESUMED or
-     * ACTIVITY_PAUSED.
+     * Value is this activity's last event, one of ACTIVITY_RESUMED, ACTIVITY_PAUSED or
+     * ACTIVITY_STOPPED.
      * {@hide}
      */
     public SparseIntArray mActivities = new SparseIntArray();
@@ -560,6 +558,7 @@
                 mLastTimeForegroundServiceUsed = timeStamp;
                 mForegroundServices.put(className, eventType);
                 break;
+            case DEVICE_SHUTDOWN:
             case FLUSH_TO_DISK:
                 // update usage of all active activities/services.
                 if (hasForegroundActivity()) {
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 26beb45..d2de887 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -22,7 +22,9 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
+import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
@@ -233,6 +235,29 @@
     @SystemApi
     public static final String EXTRA_TIME_USED = "android.app.usage.extra.TIME_USED";
 
+
+    /**
+     * App usage observers will consider the task root package the source of usage.
+     * @hide
+     */
+    @SystemApi
+    public static final int USAGE_SOURCE_TASK_ROOT_ACTIVITY = 1;
+
+    /**
+     * App usage observers will consider the visible activity's package the source of usage.
+     * @hide
+     */
+    @SystemApi
+    public static final int USAGE_SOURCE_CURRENT_ACTIVITY = 2;
+
+    /** @hide */
+    @IntDef(prefix = { "USAGE_SOURCE_" }, value = {
+            USAGE_SOURCE_TASK_ROOT_ACTIVITY,
+            USAGE_SOURCE_CURRENT_ACTIVITY,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UsageSource {}
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private static final UsageEvents sEmptyResults = new UsageEvents();
 
@@ -579,15 +604,18 @@
     /**
      * @hide
      * Register an app usage limit observer that receives a callback on the provided intent when
-     * the sum of usages of apps in the packages array exceeds the {@code timeLimit} specified. The
-     * observer will automatically be unregistered when the time limit is reached and the intent
-     * is delivered. Registering an {@code observerId} that was already registered will override
-     * the previous one. No more than 1000 unique {@code observerId} may be registered by a single
-     * uid at any one time.
+     * the sum of usages of apps and tokens in the {@code observed} array exceeds the
+     * {@code timeLimit} specified. The structure of a token is a String with the reporting
+     * package's name and a token the reporting app will use, separated by the forward slash
+     * character. Example: com.reporting.package/5OM3*0P4QU3-7OK3N
+     * The observer will automatically be unregistered when the time limit is reached and the
+     * intent is delivered. Registering an {@code observerId} that was already registered will
+     * override the previous one. No more than 1000 unique {@code observerId} may be registered by
+     * a single uid at any one time.
      * @param observerId A unique id associated with the group of apps to be monitored. There can
      *                  be multiple groups with common packages and different time limits.
-     * @param packages The list of packages to observe for foreground activity time. Cannot be null
-     *                 and must include at least one package.
+     * @param observedEntities The list of packages and token to observe for usage time. Cannot be
+     *                         null and must include at least one package or token.
      * @param timeLimit The total time the set of apps can be in the foreground before the
      *                  callbackIntent is delivered. Must be at least one minute.
      * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
@@ -600,11 +628,11 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
-    public void registerAppUsageObserver(int observerId, @NonNull String[] packages, long timeLimit,
-            @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) {
+    public void registerAppUsageObserver(int observerId, @NonNull String[] observedEntities,
+            long timeLimit, @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) {
         try {
-            mService.registerAppUsageObserver(observerId, packages, timeUnit.toMillis(timeLimit),
-                    callbackIntent, mContext.getOpPackageName());
+            mService.registerAppUsageObserver(observerId, observedEntities,
+                    timeUnit.toMillis(timeLimit), callbackIntent, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -631,18 +659,21 @@
 
     /**
      * Register a usage session observer that receives a callback on the provided {@code
-     * limitReachedCallbackIntent} when the sum of usages of apps in the packages array exceeds
-     * the {@code timeLimit} specified within a usage session. After the {@code timeLimit} has
-     * been reached, the usage session observer will receive a callback on the provided {@code
-     * sessionEndCallbackIntent} when the usage session ends. Registering another session
-     * observer against a {@code sessionObserverId} that has already been registered will
-     * override the previous session observer.
+     * limitReachedCallbackIntent} when the sum of usages of apps and tokens in the {@code
+     * observed} array exceeds the {@code timeLimit} specified within a usage session. The
+     * structure of a token is a String with the reporting packages' name and a token the
+     * reporting app will use, separated by the forward slash character.
+     * Example: com.reporting.package/5OM3*0P4QU3-7OK3N
+     * After the {@code timeLimit} has been reached, the usage session observer will receive a
+     * callback on the provided {@code sessionEndCallbackIntent} when the usage session ends.
+     * Registering another session observer against a {@code sessionObserverId} that has already
+     * been registered will override the previous session observer.
      *
      * @param sessionObserverId A unique id associated with the group of apps to be
      *                          monitored. There can be multiple groups with common
      *                          packages and different time limits.
-     * @param packages The list of packages to observe for foreground activity time. Cannot be null
-     *                 and must include at least one package.
+     * @param observedEntities The list of packages and token to observe for usage time. Cannot be
+     *                         null and must include at least one package or token.
      * @param timeLimit The total time the set of apps can be used continuously before the {@code
      *                  limitReachedCallbackIntent} is delivered. Must be at least one minute.
      * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
@@ -668,13 +699,13 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
-    public void registerUsageSessionObserver(int sessionObserverId, @NonNull String[] packages,
-            long timeLimit, @NonNull TimeUnit timeUnit, long sessionThresholdTime,
-            @NonNull TimeUnit sessionThresholdTimeUnit,
+    public void registerUsageSessionObserver(int sessionObserverId,
+            @NonNull String[] observedEntities, long timeLimit, @NonNull TimeUnit timeUnit,
+            long sessionThresholdTime,  @NonNull TimeUnit sessionThresholdTimeUnit,
             @NonNull PendingIntent limitReachedCallbackIntent,
             @Nullable PendingIntent sessionEndCallbackIntent) {
         try {
-            mService.registerUsageSessionObserver(sessionObserverId, packages,
+            mService.registerUsageSessionObserver(sessionObserverId, observedEntities,
                     timeUnit.toMillis(timeLimit),
                     sessionThresholdTimeUnit.toMillis(sessionThresholdTime),
                     limitReachedCallbackIntent, sessionEndCallbackIntent,
@@ -704,6 +735,103 @@
         }
     }
 
+    /**
+     * Report usage associated with a particular {@code token} has started. Tokens are app defined
+     * strings used to represent usage of in-app features. Apps with the {@link
+     * android.Manifest.permission#OBSERVE_APP_USAGE} permission can register time limit observers
+     * to monitor the usage of a token. In app usage can only associated with an {@code activity}
+     * and usage will be considered stopped if the activity stops or crashes.
+     * @see #registerAppUsageObserver
+     * @see #registerUsageSessionObserver
+     *
+     * @param activity The activity {@code token} is associated with.
+     * @param token The token to report usage against.
+     * @hide
+     */
+    @SystemApi
+    public void reportUsageStart(@NonNull Activity activity, @NonNull String token) {
+        try {
+            mService.reportUsageStart(activity.getActivityToken(), token,
+                    mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Report usage associated with a particular {@code token} had started some amount of time in
+     * the past. Tokens are app defined strings used to represent usage of in-app features. Apps
+     * with the {@link android.Manifest.permission#OBSERVE_APP_USAGE} permission can register time
+     * limit observers to monitor the usage of a token. In app usage can only associated with an
+     * {@code activity} and usage will be considered stopped if the activity stops or crashes.
+     * @see #registerAppUsageObserver
+     * @see #registerUsageSessionObserver
+     *
+     * @param activity The activity {@code token} is associated with.
+     * @param token The token to report usage against.
+     * @param timeAgoMs How long ago the start of usage took place
+     * @hide
+     */
+    @SystemApi
+    public void reportUsageStart(@NonNull Activity activity, @NonNull String token,
+                                 long timeAgoMs) {
+        try {
+            mService.reportPastUsageStart(activity.getActivityToken(), token, timeAgoMs,
+                    mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Report the usage associated with a particular {@code token} has stopped.
+     *
+     * @param activity The activity {@code token} is associated with.
+     * @param token The token to report usage against.
+     * @hide
+     */
+    @SystemApi
+    public void reportUsageStop(@NonNull Activity activity, @NonNull String token) {
+        try {
+            mService.reportUsageStop(activity.getActivityToken(), token,
+                    mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get what App Usage Observers will consider the source of usage for an activity. Usage Source
+     * is decided at boot and will not change until next boot.
+     * @see #USAGE_SOURCE_TASK_ROOT_ACTIVITY
+     * @see #USAGE_SOURCE_CURRENT_ACTIVITY
+     *
+     * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission and
+     *                           is not the profile owner of this user.
+     * @hide
+     */
+    @SystemApi
+    public @UsageSource int getUsageSource() {
+        try {
+            return mService.getUsageSource();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Force the Usage Source be reread from global settings.
+     * @hide
+     */
+    @TestApi
+    public void forceUsageSourceSettingRead() {
+        try {
+            mService.forceUsageSourceSettingRead();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** @hide */
     public static String reasonToString(int standbyReason) {
         StringBuilder sb = new StringBuilder();
@@ -773,6 +901,22 @@
         return sb.toString();
     }
 
+    /** @hide */
+    public static String usageSourceToString(int usageSource) {
+        switch (usageSource) {
+            case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
+                return "TASK_ROOT_ACTIVITY";
+            case USAGE_SOURCE_CURRENT_ACTIVITY:
+                return "CURRENT_ACTIVITY";
+            default:
+                StringBuilder sb = new StringBuilder();
+                sb.append("UNKNOWN(");
+                sb.append(usageSource);
+                sb.append(")");
+                return sb.toString();
+        }
+    }
+
     /**
      * {@hide}
      * Temporarily whitelist the specified app for a short duration. This is to allow an app
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 2edad35..d2d0cf9 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -40,9 +40,11 @@
      *                  {@link UsageEvents}
      * @param instanceId For activity, hashCode of ActivityRecord's appToken.
      *                   For non-activity, it is not used.
+     * @param taskRoot For activity, the name of the package at the root of the task
+     *                 For non-activity, it is not used.
      */
     public abstract void reportEvent(ComponentName component, @UserIdInt int userId, int eventType,
-            int instanceId);
+            int instanceId, ComponentName taskRoot);
 
     /**
      * Reports an event to the UsageStatsManager.
@@ -98,6 +100,12 @@
     public abstract void prepareShutdown();
 
     /**
+     * When the device power button is long pressed for 3.5 seconds, prepareForPossibleShutdown()
+     * is called.
+     */
+    public abstract void prepareForPossibleShutdown();
+
+    /**
      * Returns true if the app has not been used for a certain amount of time. How much time?
      * Could be hours, could be days, who knows?
      *
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index c740c42..3e9dd28 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -375,12 +375,12 @@
     }
 
     /**
-     * Sets whether the widget should is being displayed on a light/white background and use an
+     * Sets whether the widget is being displayed on a light/white background and use an
      * alternate UI if available.
      * @see RemoteViews#setLightBackgroundLayoutId(int)
      */
-    public void setOnLightBackground(boolean useDarkTextLayout) {
-        mOnLightBackground = useDarkTextLayout;
+    public void setOnLightBackground(boolean onLightBackground) {
+        mOnLightBackground = onLightBackground;
     }
 
     /**
diff --git a/core/java/android/attention/AttentionManagerInternal.java b/core/java/android/attention/AttentionManagerInternal.java
new file mode 100644
index 0000000..6b7f10e
--- /dev/null
+++ b/core/java/android/attention/AttentionManagerInternal.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.attention;
+
+/**
+ * Attention manager local system server interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class AttentionManagerInternal {
+    /**
+     * Returns {@code true} if attention service is supported on this device.
+     */
+    public abstract boolean isAttentionServiceSupported();
+
+    /**
+     * Checks whether user attention is at the screen and calls in the provided callback.
+     *
+     * @param requestCode   a code associated with the attention check request; this code would be
+     *                      used to call back in {@link AttentionCallbackInternal#onSuccess} and
+     *                      {@link AttentionCallbackInternal#onFailure}
+     * @param timeoutMillis a budget for the attention check; if it takes longer - {@link
+     *                      AttentionCallbackInternal#onFailure} would be called with the {@link
+     *                      android.service.attention.AttentionService#ATTENTION_FAILURE_TIMED_OUT}
+     *                      code
+     * @param callback      a callback for when the attention check has completed
+     * @return {@code true} if the attention check should succeed; {@false} otherwise.
+     */
+    public abstract boolean checkAttention(int requestCode,
+            long timeoutMillis, AttentionCallbackInternal callback);
+
+    /**
+     * Cancels the specified attention check in case it's no longer needed.
+     *
+     * @param requestCode a code provided during {@link #checkAttention}
+     */
+    public abstract void cancelAttentionCheck(int requestCode);
+
+    /** Internal interface for attention callback. */
+    public abstract static class AttentionCallbackInternal {
+        /**
+         * Provides the result of the attention check, if the check was successful.
+         *
+         * @param requestCode a code provided in {@link #checkAttention}
+         * @param result      an int with the result of the check
+         * @param timestamp   a {@code SystemClock.uptimeMillis()} timestamp associated with the
+         *                    attention check
+         */
+        public abstract void onSuccess(int requestCode, int result, long timestamp);
+
+        /**
+         * Provides the explanation for why the attention check had failed.
+         *
+         * @param requestCode a code provided in {@link #checkAttention}
+         * @param error       an int with the reason for failure
+         */
+        public abstract void onFailure(int requestCode, int error);
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 87b64797..ab8c196 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -36,6 +36,7 @@
 import android.content.Context;
 import android.os.BatteryStats;
 import android.os.Binder;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
@@ -648,6 +649,32 @@
 
     private final Object mLock = new Object();
     private final Map<LeScanCallback, ScanCallback> mLeScanClients;
+    private static final Map<BluetoothDevice, List<Pair<MetadataListener, Handler>>>
+                sMetadataListeners = new HashMap<>();
+
+    /**
+     * Bluetooth metadata listener. Overrides the default BluetoothMetadataListener
+     * implementation.
+     */
+    private static final IBluetoothMetadataListener sBluetoothMetadataListener =
+            new IBluetoothMetadataListener.Stub() {
+        @Override
+        public void onMetadataChanged(BluetoothDevice device, int key, String value) {
+            synchronized (sMetadataListeners) {
+                if (sMetadataListeners.containsKey(device)) {
+                    List<Pair<MetadataListener, Handler>> list = sMetadataListeners.get(device);
+                    for (Pair<MetadataListener, Handler> pair : list) {
+                        MetadataListener listener = pair.first;
+                        Handler handler = pair.second;
+                        handler.post(() -> {
+                            listener.onMetadataChanged(device, key, value);
+                        });
+                    }
+                }
+            }
+            return;
+        }
+    };
 
     /**
      * Get a handle to the default local Bluetooth adapter.
@@ -1873,6 +1900,20 @@
     }
 
     /**
+     * Return true if Hearing Aid Profile is supported.
+     *
+     * @return true if phone supports Hearing Aid Profile
+     */
+    private boolean isHearingAidProfileSupported() {
+        try {
+            return mManagerService.isHearingAidProfileSupported();
+        } catch (RemoteException e) {
+            Log.e(TAG, "remote expection when calling isHearingAidProfileSupported", e);
+            return false;
+        }
+    }
+
+    /**
      * Get the maximum number of connected audio devices.
      *
      * @return the maximum number of connected audio devices
@@ -2024,6 +2065,11 @@
                             supportedProfiles.add(i);
                         }
                     }
+                } else {
+                    // Bluetooth is disabled. Just fill in known supported Profiles
+                    if (isHearingAidProfileSupported()) {
+                        supportedProfiles.add(BluetoothProfile.HEARING_AID);
+                    }
                 }
             }
         } catch (RemoteException e) {
@@ -2066,8 +2112,7 @@
      * Get the current connection state of a profile.
      * This function can be used to check whether the local Bluetooth adapter
      * is connected to any remote device for a specific profile.
-     * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
-     * {@link BluetoothProfile#A2DP}.
+     * Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}.
      *
      * <p> Return value can be one of
      * {@link BluetoothProfile#STATE_DISCONNECTED},
@@ -2441,17 +2486,17 @@
     /**
      * Get the profile proxy object associated with the profile.
      *
-     * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
-     * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or
-     * {@link BluetoothProfile#GATT_SERVER}. Clients must implement
-     * {@link BluetoothProfile.ServiceListener} to get notified of
-     * the connection status and to get the proxy object.
+     * <p>Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP},
+     * {@link BluetoothProfile#GATT}, {@link BluetoothProfile#HEARING_AID}, or {@link
+     * BluetoothProfile#GATT_SERVER}. Clients must implement {@link
+     * BluetoothProfile.ServiceListener} to get notified of the connection status and to get the
+     * proxy object.
      *
      * @param context Context of the application
      * @param listener The service Listener for connection callbacks.
-     * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH}, {@link
-     * BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}. {@link BluetoothProfile#GATT} or
-     * {@link BluetoothProfile#GATT_SERVER}.
+     * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEADSET},
+     * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, {@link
+     * BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#GATT_SERVER}.
      * @return true on success, false on error
      */
     public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
@@ -2479,8 +2524,8 @@
             BluetoothPan pan = new BluetoothPan(context, listener);
             return true;
         } else if (profile == BluetoothProfile.HEALTH) {
-            BluetoothHealth health = new BluetoothHealth(context, listener);
-            return true;
+            Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated");
+            return false;
         } else if (profile == BluetoothProfile.MAP) {
             BluetoothMap map = new BluetoothMap(context, listener);
             return true;
@@ -2500,8 +2545,11 @@
             BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener);
             return true;
         } else if (profile == BluetoothProfile.HEARING_AID) {
-            BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener);
-            return true;
+            if (isHearingAidProfileSupported()) {
+                BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener);
+                return true;
+            }
+            return false;
         } else {
             return false;
         }
@@ -2512,8 +2560,7 @@
      *
      * <p> Clients should call this when they are no longer using
      * the proxy obtained from {@link #getProfileProxy}.
-     * Profile can be one of  {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or
-     * {@link BluetoothProfile#A2DP}
+     * Profile can be one of  {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP}
      *
      * @param profile
      * @param proxy Profile proxy object
@@ -2548,10 +2595,6 @@
                 BluetoothPan pan = (BluetoothPan) proxy;
                 pan.close();
                 break;
-            case BluetoothProfile.HEALTH:
-                BluetoothHealth health = (BluetoothHealth) proxy;
-                health.close();
-                break;
             case BluetoothProfile.GATT:
                 BluetoothGatt gatt = (BluetoothGatt) proxy;
                 gatt.close();
@@ -2614,6 +2657,16 @@
                             }
                         }
                     }
+                    synchronized (sMetadataListeners) {
+                        sMetadataListeners.forEach((device, pair) -> {
+                            try {
+                                mService.registerMetadataListener(sBluetoothMetadataListener,
+                                        device);
+                            } catch (RemoteException e) {
+                                Log.e(TAG, "Failed to register metadata listener", e);
+                            }
+                        });
+                    }
                 }
 
                 public void onBluetoothServiceDown() {
@@ -3097,4 +3150,142 @@
                     + "listenUsingInsecureL2capChannel");
         return listenUsingInsecureL2capChannel();
     }
+
+    /**
+     * Register a {@link #MetadataListener} to receive update about metadata
+     * changes for this {@link BluetoothDevice}.
+     * Registration must be done when Bluetooth is ON and will last until
+     * {@link #unregisterMetadataListener(BluetoothDevice)} is called, even when Bluetooth
+     * restarted in the middle.
+     * All input parameters should not be null or {@link NullPointerException} will be triggered.
+     * The same {@link BluetoothDevice} and {@link #MetadataListener} pair can only be registered
+     * once, double registration would cause {@link IllegalArgumentException}.
+     *
+     * @param device {@link BluetoothDevice} that will be registered
+     * @param listener {@link #MetadataListener} that will receive asynchronous callbacks
+     * @param handler the handler for listener callback
+     * @return true on success, false on error
+     * @throws NullPointerException If one of {@code listener}, {@code device} or {@code handler}
+     * is null.
+     * @throws IllegalArgumentException The same {@link #MetadataListener} and
+     * {@link BluetoothDevice} are registered twice.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public boolean registerMetadataListener(BluetoothDevice device, MetadataListener listener,
+            Handler handler) {
+        if (DBG) Log.d(TAG, "registerMetdataListener()");
+
+        final IBluetooth service = mService;
+        if (service == null) {
+            Log.e(TAG, "Bluetooth is not enabled. Cannot register metadata listener");
+            return false;
+        }
+        if (listener == null) {
+            throw new NullPointerException("listener is null");
+        }
+        if (device == null) {
+            throw new NullPointerException("device is null");
+        }
+        if (handler == null) {
+            throw new NullPointerException("handler is null");
+        }
+
+        synchronized (sMetadataListeners) {
+            List<Pair<MetadataListener, Handler>> listenerList = sMetadataListeners.get(device);
+            if (listenerList == null) {
+                // Create new listener/handler list for registeration
+                listenerList = new ArrayList<>();
+                sMetadataListeners.put(device, listenerList);
+            } else {
+                // Check whether this device was already registed by the lisenter
+                if (listenerList.stream().anyMatch((pair) -> (pair.first.equals(listener)))) {
+                    throw new IllegalArgumentException("listener was already regestered"
+                            + " for the device");
+                }
+            }
+
+            Pair<MetadataListener, Handler> listenerPair = new Pair(listener, handler);
+            listenerList.add(listenerPair);
+
+            boolean ret = false;
+            try {
+                ret = service.registerMetadataListener(sBluetoothMetadataListener, device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "registerMetadataListener fail", e);
+            } finally {
+                if (!ret) {
+                    // Remove listener registered earlier when fail.
+                    listenerList.remove(listenerPair);
+                    if (listenerList.isEmpty()) {
+                        // Remove the device if its listener list is empty
+                        sMetadataListeners.remove(device);
+                    }
+                }
+            }
+            return ret;
+        }
+    }
+
+    /**
+     * Unregister all {@link MetadataListener} from this {@link BluetoothDevice}.
+     * Unregistration can be done when Bluetooth is either ON or OFF.
+     * {@link #registerMetadataListener(MetadataListener, BluetoothDevice, Handler)} must
+     * be called before unregisteration.
+     * Unregistering a device that is not regestered would cause {@link IllegalArgumentException}.
+     *
+     * @param device {@link BluetoothDevice} that will be unregistered. it
+     * should not be null or {@link NullPointerException} will be triggered.
+     * @return true on success, false on error
+     * @throws NullPointerException If {@code device} is null.
+     * @throws IllegalArgumentException If {@code device} has not been registered before.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public boolean unregisterMetadataListener(BluetoothDevice device) {
+        if (DBG) Log.d(TAG, "unregisterMetdataListener()");
+        if (device == null) {
+            throw new NullPointerException("device is null");
+        }
+
+        synchronized (sMetadataListeners) {
+            if (sMetadataListeners.containsKey(device)) {
+                sMetadataListeners.remove(device);
+            } else {
+                throw new IllegalArgumentException("device was not registered");
+            }
+
+            final IBluetooth service = mService;
+            if (service == null) {
+                // Bluetooth is OFF, do nothing to Bluetooth service.
+                return true;
+            }
+            try {
+                return service.unregisterMetadataListener(device);
+            } catch (RemoteException e) {
+                Log.e(TAG, "unregisterMetadataListener fail", e);
+                return false;
+            }
+        }
+    }
+
+    /**
+     * This abstract class is used to implement {@link BluetoothAdapter} metadata listener.
+     * @hide
+     */
+    @SystemApi
+    public abstract static class MetadataListener {
+        /**
+         * Callback triggered if the metadata of {@link BluetoothDevice} registered in
+         * {@link #registerMetadataListener}.
+         *
+         * @param device changed {@link BluetoothDevice}.
+         * @param key changed metadata key, one of BluetoothDevice.METADATA_*.
+         * @param value the new value of metadata.
+         */
+        public void onMetadataChanged(BluetoothDevice device, int key, String value) {
+        }
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index 79c0a3a..c9d0ef2 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -114,6 +114,19 @@
         mCodecSpecific4 = codecSpecific4;
     }
 
+    @UnsupportedAppUsage
+    public BluetoothCodecConfig(int codecType) {
+        mCodecType = codecType;
+        mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
+        mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE;
+        mBitsPerSample = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE;
+        mChannelMode = BluetoothCodecConfig.CHANNEL_MODE_NONE;
+        mCodecSpecific1 = 0;
+        mCodecSpecific2 = 0;
+        mCodecSpecific3 = 0;
+        mCodecSpecific4 = 0;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (o instanceof BluetoothCodecConfig) {
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 235dc5c..17cf702 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -341,6 +341,137 @@
             "android.bluetooth.device.action.SDP_RECORD";
 
     /**
+     * Maximum length of a metadata entry, this is to avoid exploding Bluetooth
+     * disk usage
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_MAX_LENGTH = 2048;
+
+    /**
+     * Manufacturer name of this Bluetooth device
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_MANUFACTURER_NAME = 0;
+
+    /**
+     * Model name of this Bluetooth device
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_MODEL_NAME = 1;
+
+    /**
+     * Software version of this Bluetooth device
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_SOFTWARE_VERSION = 2;
+
+    /**
+     * Hardware version of this Bluetooth device
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_HARDWARE_VERSION = 3;
+
+    /**
+     * Package name of the companion app, if any
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_COMPANION_APP = 4;
+
+    /**
+     * URI to the main icon shown on the settings UI
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_MAIN_ICON = 5;
+
+    /**
+     * Whether this device is an untethered headset with left, right and case
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_IS_UNTHETHERED_HEADSET = 6;
+
+    /**
+     * URI to icon of the left headset
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTHETHERED_LEFT_ICON = 7;
+
+    /**
+     * URI to icon of the right headset
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTHETHERED_RIGHT_ICON = 8;
+
+    /**
+     * URI to icon of the headset charging case
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTHETHERED_CASE_ICON = 9;
+
+    /**
+     * Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
+     * is invalid, of the left headset
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTHETHERED_LEFT_BATTERY = 10;
+
+    /**
+     * Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
+     * is invalid, of the right headset
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTHETHERED_RIGHT_BATTERY = 11;
+
+    /**
+     * Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
+     * is invalid, of the headset charging case
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTHETHERED_CASE_BATTERY = 12;
+
+    /**
+     * Whether the left headset is charging
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTHETHERED_LEFT_CHARGING = 13;
+
+    /**
+     * Whether the right headset is charging
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTHETHERED_RIGHT_CHARGING = 14;
+
+    /**
+     * Whether the headset charging case is charging
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_UNTHETHERED_CASE_CHARGING = 15;
+
+    /**
+     * URI to the enhanced settings UI slice, null or empty String means
+     * the UI does not exist
+     * @hide
+     */
+    @SystemApi
+    public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16;
+
+    /**
      * Broadcast Action: This intent is used to broadcast the {@link UUID}
      * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
      * has been fetched. This intent is sent only when the UUIDs of the remote
@@ -2026,4 +2157,61 @@
         Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createInsecureL2capChannel");
         return createInsecureL2capChannel(psm);
     }
+
+    /**
+     * Set a keyed metadata of this {@link BluetoothDevice} to a
+     * {@link String} value.
+     * Only bonded devices's metadata will be persisted across Bluetooth
+     * restart.
+     * Metadata will be removed when the device's bond state is moved to
+     * {@link #BOND_NONE}.
+     *
+     * @param key must be within the list of BluetoothDevice.METADATA_*
+     * @param value the string data to set for key. Must be less than
+     * {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length
+     * @return true on success, false on error
+     * @hide
+    */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public boolean setMetadata(int key, String value) {
+        final IBluetooth service = sService;
+        if (service == null) {
+            Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata");
+            return false;
+        }
+        if (value.length() > METADATA_MAX_LENGTH) {
+            throw new IllegalArgumentException("value length is " + value.length()
+                    + ", should not over " + METADATA_MAX_LENGTH);
+        }
+        try {
+            return service.setMetadata(this, key, value);
+        } catch (RemoteException e) {
+            Log.e(TAG, "setMetadata fail", e);
+            return false;
+        }
+    }
+
+    /**
+     * Get a keyed metadata for this {@link BluetoothDevice} as {@link String}
+     *
+     * @param key must be within the list of BluetoothDevice.METADATA_*
+     * @return Metadata of the key as string, null on error or not found
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public String getMetadata(int key) {
+        final IBluetooth service = sService;
+        if (service == null) {
+            Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata");
+            return null;
+        }
+        try {
+            return service.getMetadata(this, key);
+        } catch (RemoteException e) {
+            Log.e(TAG, "getMetadata fail", e);
+            return null;
+        }
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 22d41d9..e2e56fd 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -16,15 +16,7 @@
 
 package android.bluetooth;
 
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Binder;
-import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.os.UserHandle;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -54,79 +46,59 @@
  * <li> When done, close the health channel by calling {@link #disconnectChannel}
  * and unregister the application configuration calling
  * {@link #unregisterAppConfiguration}
+ *
+ * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New apps
+ * should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+ * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+ * {@link BluetoothDevice#createL2capChannel(int)}
  */
+@Deprecated
 public final class BluetoothHealth implements BluetoothProfile {
     private static final String TAG = "BluetoothHealth";
-    private static final boolean DBG = true;
-    private static final boolean VDBG = false;
-
     /**
      * Health Profile Source Role - the health device.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public static final int SOURCE_ROLE = 1 << 0;
 
     /**
      * Health Profile Sink Role the device talking to the health device.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public static final int SINK_ROLE = 1 << 1;
 
     /**
      * Health Profile - Channel Type used - Reliable
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public static final int CHANNEL_TYPE_RELIABLE = 10;
 
     /**
      * Health Profile - Channel Type used - Streaming
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public static final int CHANNEL_TYPE_STREAMING = 11;
 
-    /**
-     * @hide
-     */
-    public static final int CHANNEL_TYPE_ANY = 12;
-
-    /** @hide */
-    public static final int HEALTH_OPERATION_SUCCESS = 6000;
-    /** @hide */
-    public static final int HEALTH_OPERATION_ERROR = 6001;
-    /** @hide */
-    public static final int HEALTH_OPERATION_INVALID_ARGS = 6002;
-    /** @hide */
-    public static final int HEALTH_OPERATION_GENERIC_FAILURE = 6003;
-    /** @hide */
-    public static final int HEALTH_OPERATION_NOT_FOUND = 6004;
-    /** @hide */
-    public static final int HEALTH_OPERATION_NOT_ALLOWED = 6005;
-
-    private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
-            new IBluetoothStateChangeCallback.Stub() {
-                public void onBluetoothStateChange(boolean up) {
-                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
-                    if (!up) {
-                        if (VDBG) Log.d(TAG, "Unbinding service...");
-                        synchronized (mConnection) {
-                            try {
-                                mService = null;
-                                mContext.unbindService(mConnection);
-                            } catch (Exception re) {
-                                Log.e(TAG, "", re);
-                            }
-                        }
-                    } else {
-                        synchronized (mConnection) {
-                            try {
-                                if (mService == null) {
-                                    if (VDBG) Log.d(TAG, "Binding service...");
-                                    doBind();
-                                }
-                            } catch (Exception re) {
-                                Log.e(TAG, "", re);
-                            }
-                        }
-                    }
-                }
-            };
-
 
     /**
      * Register an application configuration that acts as a Health SINK.
@@ -142,53 +114,17 @@
      * @param callback A callback to indicate success or failure of the registration and all
      * operations done on this application configuration.
      * @return If true, callback will be called.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public boolean registerSinkAppConfiguration(String name, int dataType,
             BluetoothHealthCallback callback) {
-        if (!isEnabled() || name == null) return false;
-
-        if (VDBG) log("registerSinkApplication(" + name + ":" + dataType + ")");
-        return registerAppConfiguration(name, dataType, SINK_ROLE,
-                CHANNEL_TYPE_ANY, callback);
-    }
-
-    /**
-     * Register an application configuration that acts as a Health SINK or in a Health
-     * SOURCE role.This is an asynchronous call and so
-     * the callback is used to notify success or failure if the function returns true.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param name The friendly name associated with the application or configuration.
-     * @param dataType The dataType of the Source role of Health Profile.
-     * @param channelType The channel type. Will be one of {@link #CHANNEL_TYPE_RELIABLE}  or {@link
-     * #CHANNEL_TYPE_STREAMING}
-     * @param callback - A callback to indicate success or failure.
-     * @return If true, callback will be called.
-     * @hide
-     */
-    public boolean registerAppConfiguration(String name, int dataType, int role,
-            int channelType, BluetoothHealthCallback callback) {
-        boolean result = false;
-        if (!isEnabled() || !checkAppParam(name, role, channelType, callback)) return result;
-
-        if (VDBG) log("registerApplication(" + name + ":" + dataType + ")");
-        BluetoothHealthCallbackWrapper wrapper = new BluetoothHealthCallbackWrapper(callback);
-        BluetoothHealthAppConfiguration config =
-                new BluetoothHealthAppConfiguration(name, dataType, role, channelType);
-
-        final IBluetoothHealth service = mService;
-        if (service != null) {
-            try {
-                result = service.registerAppConfiguration(config, wrapper);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
-        return result;
+        Log.e(TAG, "registerSinkAppConfiguration(): BluetoothHealth is deprecated");
+        return false;
     }
 
     /**
@@ -199,22 +135,16 @@
      *
      * @param config The health app configuration
      * @return Success or failure.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
-        boolean result = false;
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled() && config != null) {
-            try {
-                result = service.unregisterAppConfiguration(config);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
-
-        return result;
+        Log.e(TAG, "unregisterAppConfiguration(): BluetoothHealth is deprecated");
+        return false;
     }
 
     /**
@@ -228,49 +158,16 @@
      * @param config The application configuration which has been registered using {@link
      * #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
      * @return If true, the callback associated with the application config will be called.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public boolean connectChannelToSource(BluetoothDevice device,
             BluetoothHealthAppConfiguration config) {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled() && isValidDevice(device) && config != null) {
-            try {
-                return service.connectChannelToSource(device, config);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
-        return false;
-    }
-
-    /**
-     * Connect to a health device which has the {@link #SINK_ROLE}.
-     * This is an asynchronous call. If this function returns true, the callback
-     * associated with the application configuration will be called.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param device The remote Bluetooth device.
-     * @param config The application configuration which has been registered using {@link
-     * #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
-     * @return If true, the callback associated with the application config will be called.
-     * @hide
-     */
-    public boolean connectChannelToSink(BluetoothDevice device,
-            BluetoothHealthAppConfiguration config, int channelType) {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled() && isValidDevice(device) && config != null) {
-            try {
-                return service.connectChannelToSink(device, config, channelType);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
+        Log.e(TAG, "connectChannelToSource(): BluetoothHealth is deprecated");
         return false;
     }
 
@@ -286,20 +183,16 @@
      * #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
      * @param channelId The channel id associated with the channel
      * @return If true, the callback associated with the application config will be called.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public boolean disconnectChannel(BluetoothDevice device,
             BluetoothHealthAppConfiguration config, int channelId) {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled() && isValidDevice(device) && config != null) {
-            try {
-                return service.disconnectChannel(device, config, channelId);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
+        Log.e(TAG, "disconnectChannel(): BluetoothHealth is deprecated");
         return false;
     }
 
@@ -315,20 +208,16 @@
      * @param device The remote Bluetooth health device
      * @param config The application configuration
      * @return null on failure, ParcelFileDescriptor on success.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
             BluetoothHealthAppConfiguration config) {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled() && isValidDevice(device) && config != null) {
-            try {
-                return service.getMainChannelFd(device, config);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
+        Log.e(TAG, "getMainChannelFd(): BluetoothHealth is deprecated");
         return null;
     }
 
@@ -348,17 +237,7 @@
      */
     @Override
     public int getConnectionState(BluetoothDevice device) {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled() && isValidDevice(device)) {
-            try {
-                return service.getHealthDeviceConnectionState(device);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
+        Log.e(TAG, "getConnectionState(): BluetoothHealth is deprecated");
         return STATE_DISCONNECTED;
     }
 
@@ -378,17 +257,8 @@
      */
     @Override
     public List<BluetoothDevice> getConnectedDevices() {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled()) {
-            try {
-                return service.getConnectedHealthDevices();
-            } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return new ArrayList<BluetoothDevice>();
-            }
-        }
-        if (service == null) Log.w(TAG, "Proxy not attached to service");
-        return new ArrayList<BluetoothDevice>();
+        Log.e(TAG, "getConnectedDevices(): BluetoothHealth is deprecated");
+        return new ArrayList<>();
     }
 
     /**
@@ -410,163 +280,81 @@
      */
     @Override
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled()) {
-            try {
-                return service.getHealthDevicesMatchingConnectionStates(states);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return new ArrayList<BluetoothDevice>();
-            }
-        }
-        if (service == null) Log.w(TAG, "Proxy not attached to service");
-        return new ArrayList<BluetoothDevice>();
+        Log.e(TAG, "getDevicesMatchingConnectionStates(): BluetoothHealth is deprecated");
+        return new ArrayList<>();
     }
 
-    private static class BluetoothHealthCallbackWrapper extends IBluetoothHealthCallback.Stub {
-        private BluetoothHealthCallback mCallback;
-
-        public BluetoothHealthCallbackWrapper(BluetoothHealthCallback callback) {
-            mCallback = callback;
-        }
-
-        @Override
-        public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
-                int status) {
-            mCallback.onHealthAppConfigurationStatusChange(config, status);
-        }
-
-        @Override
-        public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
-                BluetoothDevice device, int prevState, int newState,
-                ParcelFileDescriptor fd, int channelId) {
-            mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd,
-                    channelId);
-        }
-    }
-
-    /** Health Channel Connection State - Disconnected */
+    /** Health Channel Connection State - Disconnected
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
     public static final int STATE_CHANNEL_DISCONNECTED = 0;
-    /** Health Channel Connection State - Connecting */
+    /** Health Channel Connection State - Connecting
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
     public static final int STATE_CHANNEL_CONNECTING = 1;
-    /** Health Channel Connection State - Connected */
+    /** Health Channel Connection State - Connected
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
     public static final int STATE_CHANNEL_CONNECTED = 2;
-    /** Health Channel Connection State - Disconnecting */
+    /** Health Channel Connection State - Disconnecting
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
     public static final int STATE_CHANNEL_DISCONNECTING = 3;
 
-    /** Health App Configuration registration success */
-    public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0;
-    /** Health App Configuration registration failure */
-    public static final int APP_CONFIG_REGISTRATION_FAILURE = 1;
-    /** Health App Configuration un-registration success */
-    public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2;
-    /** Health App Configuration un-registration failure */
-    public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3;
-
-    private Context mContext;
-    private ServiceListener mServiceListener;
-    private volatile IBluetoothHealth mService;
-    BluetoothAdapter mAdapter;
-
-    /**
-     * Create a BluetoothHealth proxy object.
+    /** Health App Configuration registration success
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
-    /*package*/ BluetoothHealth(Context context, ServiceListener l) {
-        mContext = context;
-        mServiceListener = l;
-        mAdapter = BluetoothAdapter.getDefaultAdapter();
-        IBluetoothManager mgr = mAdapter.getBluetoothManager();
-        if (mgr != null) {
-            try {
-                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
-            } catch (RemoteException e) {
-                Log.e(TAG, "", e);
-            }
-        }
-
-        doBind();
-    }
-
-    boolean doBind() {
-        Intent intent = new Intent(IBluetoothHealth.class.getName());
-        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
-        intent.setComponent(comp);
-        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
-                UserHandle.CURRENT_OR_SELF)) {
-            Log.e(TAG, "Could not bind to Bluetooth Health Service with " + intent);
-            return false;
-        }
-        return true;
-    }
-
-    /*package*/ void close() {
-        if (VDBG) log("close()");
-        IBluetoothManager mgr = mAdapter.getBluetoothManager();
-        if (mgr != null) {
-            try {
-                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
-            } catch (Exception e) {
-                Log.e(TAG, "", e);
-            }
-        }
-
-        synchronized (mConnection) {
-            if (mService != null) {
-                try {
-                    mService = null;
-                    mContext.unbindService(mConnection);
-                } catch (Exception re) {
-                    Log.e(TAG, "", re);
-                }
-            }
-        }
-        mServiceListener = null;
-    }
-
-    private final ServiceConnection mConnection = new ServiceConnection() {
-        public void onServiceConnected(ComponentName className, IBinder service) {
-            if (DBG) Log.d(TAG, "Proxy object connected");
-            mService = IBluetoothHealth.Stub.asInterface(Binder.allowBlocking(service));
-
-            if (mServiceListener != null) {
-                mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, BluetoothHealth.this);
-            }
-        }
-
-        public void onServiceDisconnected(ComponentName className) {
-            if (DBG) Log.d(TAG, "Proxy object disconnected");
-            mService = null;
-            if (mServiceListener != null) {
-                mServiceListener.onServiceDisconnected(BluetoothProfile.HEALTH);
-            }
-        }
-    };
-
-    private boolean isEnabled() {
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
-        if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
-        log("Bluetooth is Not enabled");
-        return false;
-    }
-
-    private static boolean isValidDevice(BluetoothDevice device) {
-        return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
-    }
-
-    private boolean checkAppParam(String name, int role, int channelType,
-            BluetoothHealthCallback callback) {
-        if (name == null || (role != SOURCE_ROLE && role != SINK_ROLE)
-                || (channelType != CHANNEL_TYPE_RELIABLE && channelType != CHANNEL_TYPE_STREAMING
-                    && channelType != CHANNEL_TYPE_ANY)
-                || callback == null) {
-            return false;
-        }
-        if (role == SOURCE_ROLE && channelType == CHANNEL_TYPE_ANY) return false;
-        return true;
-    }
-
-    private static void log(String msg) {
-        Log.d(TAG, msg);
-    }
+    @Deprecated
+    public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0;
+    /** Health App Configuration registration failure
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
+    public static final int APP_CONFIG_REGISTRATION_FAILURE = 1;
+    /** Health App Configuration un-registration success
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
+    public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2;
+    /** Health App Configuration un-registration failure
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
+    public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3;
 }
diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
index 7c9db6f..9788bbf 100644
--- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
+++ b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
@@ -25,72 +25,14 @@
  * the {@link BluetoothHealth} class. This class represents an application configuration
  * that the Bluetooth Health third party application will register to communicate with the
  * remote Bluetooth health device.
+ *
+ * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+ * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+ * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+ * {@link BluetoothDevice#createL2capChannel(int)}
  */
+@Deprecated
 public final class BluetoothHealthAppConfiguration implements Parcelable {
-    private final String mName;
-    private final int mDataType;
-    private final int mRole;
-    private final int mChannelType;
-
-    /**
-     * Constructor to register the SINK role
-     *
-     * @param name Friendly name associated with the application configuration
-     * @param dataType Data Type of the remote Bluetooth Health device
-     * @hide
-     */
-    BluetoothHealthAppConfiguration(String name, int dataType) {
-        mName = name;
-        mDataType = dataType;
-        mRole = BluetoothHealth.SINK_ROLE;
-        mChannelType = BluetoothHealth.CHANNEL_TYPE_ANY;
-    }
-
-    /**
-     * Constructor to register the application configuration.
-     *
-     * @param name Friendly name associated with the application configuration
-     * @param dataType Data Type of the remote Bluetooth Health device
-     * @param role {@link BluetoothHealth#SOURCE_ROLE} or {@link BluetoothHealth#SINK_ROLE}
-     * @hide
-     */
-    BluetoothHealthAppConfiguration(String name, int dataType, int role, int
-            channelType) {
-        mName = name;
-        mDataType = dataType;
-        mRole = role;
-        mChannelType = channelType;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o instanceof BluetoothHealthAppConfiguration) {
-            BluetoothHealthAppConfiguration config = (BluetoothHealthAppConfiguration) o;
-
-            if (mName == null) return false;
-
-            return mName.equals(config.getName()) && mDataType == config.getDataType()
-                    && mRole == config.getRole() && mChannelType == config.getChannelType();
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = 17;
-        result = 31 * result + (mName != null ? mName.hashCode() : 0);
-        result = 31 * result + mDataType;
-        result = 31 * result + mRole;
-        result = 31 * result + mChannelType;
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "BluetoothHealthAppConfiguration [mName = " + mName + ",mDataType = " + mDataType
-                + ", mRole = " + mRole + ",mChannelType = " + mChannelType + "]";
-    }
-
     @Override
     public int describeContents() {
         return 0;
@@ -100,50 +42,59 @@
      * Return the data type associated with this application configuration.
      *
      * @return dataType
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public int getDataType() {
-        return mDataType;
+        return 0;
     }
 
     /**
      * Return the name of the application configuration.
      *
      * @return String name
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public String getName() {
-        return mName;
+        return null;
     }
 
     /**
      * Return the role associated with this application configuration.
      *
      * @return One of {@link BluetoothHealth#SOURCE_ROLE} or {@link BluetoothHealth#SINK_ROLE}
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public int getRole() {
-        return mRole;
+        return 0;
     }
 
     /**
-     * Return the channel type associated with this application configuration.
-     *
-     * @return One of {@link BluetoothHealth#CHANNEL_TYPE_RELIABLE} or {@link
-     * BluetoothHealth#CHANNEL_TYPE_STREAMING} or {@link BluetoothHealth#CHANNEL_TYPE_ANY}.
-     * @hide
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
-    public int getChannelType() {
-        return mChannelType;
-    }
-
+    @Deprecated
     public static final Parcelable.Creator<BluetoothHealthAppConfiguration> CREATOR =
             new Parcelable.Creator<BluetoothHealthAppConfiguration>() {
                 @Override
                 public BluetoothHealthAppConfiguration createFromParcel(Parcel in) {
-                    String name = in.readString();
-                    int type = in.readInt();
-                    int role = in.readInt();
-                    int channelType = in.readInt();
-                    return new BluetoothHealthAppConfiguration(name, type, role,
-                            channelType);
+                    return new BluetoothHealthAppConfiguration();
                 }
 
                 @Override
@@ -153,10 +104,5 @@
             };
 
     @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(mName);
-        out.writeInt(mDataType);
-        out.writeInt(mRole);
-        out.writeInt(mChannelType);
-    }
+    public void writeToParcel(Parcel out, int flags) {}
 }
diff --git a/core/java/android/bluetooth/BluetoothHealthCallback.java b/core/java/android/bluetooth/BluetoothHealthCallback.java
index 4023485..4769212 100644
--- a/core/java/android/bluetooth/BluetoothHealthCallback.java
+++ b/core/java/android/bluetooth/BluetoothHealthCallback.java
@@ -23,7 +23,13 @@
 
 /**
  * This abstract class is used to implement {@link BluetoothHealth} callbacks.
+ *
+ * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+ * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+ * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+ * {@link BluetoothDevice#createL2capChannel(int)}
  */
+@Deprecated
 public abstract class BluetoothHealthCallback {
     private static final String TAG = "BluetoothHealthCallback";
 
@@ -38,8 +44,14 @@
      * BluetoothHealth#APP_CONFIG_REGISTRATION_FAILURE} or
      * {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_SUCCESS}
      * or {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_FAILURE}
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
     @BinderThread
+    @Deprecated
     public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
             int status) {
         Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + "Status: " + status);
@@ -58,8 +70,14 @@
      * @param fd The Parcel File Descriptor when the channel state is connected.
      * @param channelId The id associated with the channel. This id will be used in future calls
      * like when disconnecting the channel.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
     @BinderThread
+    @Deprecated
     public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
             BluetoothDevice device, int prevState, int newState, ParcelFileDescriptor fd,
             int channelId) {
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index 6ed7942..82cc1bc 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -39,15 +39,14 @@
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
- * This class provides the public APIs to control the Bluetooth Hearing Aid
- * profile.
+ * This class provides the public APIs to control the Hearing Aid profile.
  *
  * <p>BluetoothHearingAid is a proxy object for controlling the Bluetooth Hearing Aid
  * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
  * the BluetoothHearingAid proxy object.
  *
- * <p> Each method is protected with its appropriate permission.
- * @hide
+ * <p> Android only supports one set of connected Bluetooth Hearing Aid device at a time. Each
+ * method is protected with its appropriate permission.
  */
 public final class BluetoothHearingAid implements BluetoothProfile {
     private static final String TAG = "BluetoothHearingAid";
@@ -56,7 +55,8 @@
 
     /**
      * Intent used to broadcast the change in connection state of the Hearing Aid
-     * profile.
+     * profile. Please note that in the binaural case, there will be two different LE devices for
+     * the left and right side and each device will have their own connection state changes.S
      *
      * <p>This intent will have 3 extras:
      * <ul>
@@ -77,27 +77,6 @@
             "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED";
 
     /**
-     * Intent used to broadcast the change in the Playing state of the Hearing Aid
-     * profile.
-     *
-     * <p>This intent will have 3 extras:
-     * <ul>
-     * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
-     * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
-     * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
-     * </ul>
-     *
-     * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
-     * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
-     * receive.
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_PLAYING_STATE_CHANGED =
-            "android.bluetooth.hearingaid.profile.action.PLAYING_STATE_CHANGED";
-
-    /**
      * Intent used to broadcast the selection of a connected device as active.
      *
      * <p>This intent will have one extra:
@@ -108,6 +87,8 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
      * receive.
+     *
+     * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     @UnsupportedAppUsage
@@ -115,32 +96,38 @@
             "android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED";
 
     /**
-     * Hearing Aid device is streaming music. This state can be one of
-     * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
-     * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
+     * This device represents Left Hearing Aid.
+     *
+     * @hide
      */
-    public static final int STATE_PLAYING = 10;
-
-    /**
-     * Hearing Aid device is NOT streaming music. This state can be one of
-     * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
-     * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
-     */
-    public static final int STATE_NOT_PLAYING = 11;
-
-    /** This device represents Left Hearing Aid. */
     public static final int SIDE_LEFT = IBluetoothHearingAid.SIDE_LEFT;
 
-    /** This device represents Right Hearing Aid. */
+    /**
+     * This device represents Right Hearing Aid.
+     *
+     * @hide
+     */
     public static final int SIDE_RIGHT = IBluetoothHearingAid.SIDE_RIGHT;
 
-    /** This device is Monaural. */
+    /**
+     * This device is Monaural.
+     *
+     * @hide
+     */
     public static final int MODE_MONAURAL = IBluetoothHearingAid.MODE_MONAURAL;
 
-    /** This device is Binaural (should receive only left or right audio). */
+    /**
+     * This device is Binaural (should receive only left or right audio).
+     *
+     * @hide
+     */
     public static final int MODE_BINAURAL = IBluetoothHearingAid.MODE_BINAURAL;
 
-    /** Can't read ClientID for this device */
+    /**
+     * Indicates the HiSyncID could not be read and is unavailable.
+     *
+     * @hide
+     */
     public static final long HI_SYNC_ID_INVALID = IBluetoothHearingAid.HI_SYNC_ID_INVALID;
 
     private Context mContext;
@@ -236,12 +223,6 @@
         }
     }
 
-    @Override
-    public void finalize() {
-        // The empty finalize needs to be kept or the
-        // cts signature tests would fail.
-    }
-
     /**
      * Initiate connection to a profile of the remote bluetooth device.
      *
@@ -538,10 +519,6 @@
                 return "connected";
             case STATE_DISCONNECTING:
                 return "disconnecting";
-            case STATE_PLAYING:
-                return "playing";
-            case STATE_NOT_PLAYING:
-                return "not playing";
             default:
                 return "<unknown state " + state + ">";
         }
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 3c3a01b..b8670db 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -72,7 +72,13 @@
 
     /**
      * Health Profile
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     int HEALTH = 3;
 
     /**
@@ -179,7 +185,6 @@
     /**
      * Hearing Aid Device
      *
-     * @hide
      */
     int HEARING_AID = 21;
 
@@ -269,9 +274,8 @@
          * Called to notify the client when the proxy object has been
          * connected to the service.
          *
-         * @param profile - One of {@link #HEALTH}, {@link #HEADSET} or {@link #A2DP}
-         * @param proxy - One of {@link BluetoothHealth}, {@link BluetoothHeadset} or {@link
-         * BluetoothA2dp}
+         * @param profile - One of {@link #HEADSET} or {@link #A2DP}
+         * @param proxy - One of {@link BluetoothHeadset} or {@link BluetoothA2dp}
          */
         public void onServiceConnected(int profile, BluetoothProfile proxy);
 
@@ -279,7 +283,7 @@
          * Called to notify the client that this proxy object has been
          * disconnected from the service.
          *
-         * @param profile - One of {@link #HEALTH}, {@link #HEADSET} or {@link #A2DP}
+         * @param profile - One of {@link #HEADSET} or {@link #A2DP}
          */
         public void onServiceDisconnected(int profile);
     }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 125c4c6..280f1ac 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -337,6 +337,15 @@
     public static final int BIND_ADJUST_BELOW_PERCEPTIBLE = 0x0100;
 
     /**
+     * @hide Flag for {@link #bindService}: the service being bound to represents a
+     * protected system component, so must have association restrictions applied to it.
+     * That is, a system config must have one or more allow-association tags limiting
+     * which packages it can interact with.  If it does not have any such association
+     * restrictions, a default empty set will be created.
+     */
+    public static final int BIND_RESTRICT_ASSOCIATIONS = 0x00200000;
+
+    /**
      * @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.
@@ -762,7 +771,9 @@
      * <p>
      * This is not generally intended for third party application developers.
      */
-    public abstract String getOpPackageName();
+    public String getOpPackageName() {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
 
     /** Return the full application info for this context's package. */
     public abstract ApplicationInfo getApplicationInfo();
@@ -2971,9 +2982,11 @@
      *
      * @see #bindService
      */
-    public abstract boolean bindIsolatedService(@RequiresPermission Intent service,
+    public boolean bindIsolatedService(@RequiresPermission Intent service,
             @NonNull ServiceConnection conn, @BindServiceFlags int flags,
-            @NonNull String instanceName);
+            @NonNull String instanceName) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
 
     /**
      * Same as {@link #bindService(Intent, ServiceConnection, int)}, but with an explicit userHandle
@@ -3028,8 +3041,10 @@
      *                   a related groups -- higher importance values will be killed before
      *                   lower ones.
      */
-    public abstract void updateServiceGroup(@NonNull ServiceConnection conn, int group,
-            int importance);
+    public void updateServiceGroup(@NonNull ServiceConnection conn, int group,
+            int importance) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
 
     /**
      * Disconnect from an application service.  You will no longer receive
@@ -3093,6 +3108,7 @@
             VIBRATOR_SERVICE,
             //@hide: STATUS_BAR_SERVICE,
             CONNECTIVITY_SERVICE,
+            //@hide: IP_MEMORY_STORE_SERVICE,
             IPSEC_SERVICE,
             //@hide: UPDATE_LOCK_SERVICE,
             //@hide: NETWORKMANAGEMENT_SERVICE,
@@ -3630,6 +3646,14 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.net.IpMemoryStore} to store and read information about
+     * known networks.
+     * @hide
+     */
+    public static final String IP_MEMORY_STORE_SERVICE = "ipmemorystore";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.net.IpSecManager} for encrypting Sockets or Networks with
      * IPSec.
      *
@@ -3975,6 +3999,24 @@
     public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
 
     /**
+     * Used for getting content selections and classifications for task snapshots.
+     *
+     * @hide
+     * @see #getSystemService(String)
+     */
+    @SystemApi
+    public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
+
+    /**
+     * Official published name of the app prediction service.
+     *
+     * @hide
+     * @see #getSystemService(String)
+     */
+    @SystemApi
+    public static final String APP_PREDICTION_SERVICE = "app_prediction";
+
+    /**
      * Use with {@link #getSystemService(String)} to access the
      * {@link com.android.server.voiceinteraction.SoundTriggerService}.
      *
@@ -3993,6 +4035,14 @@
     public static final String PERMISSION_SERVICE = "permission";
 
     /**
+     * Official published name of the (internal) permission controller service.
+     *
+     * @see #getSystemService(String)
+     * @hide
+     */
+    public static final String PERMISSION_CONTROLLER_SERVICE = "permission_controller";
+
+    /**
      * Use with {@link #getSystemService(String)} to retrieve an
      * {@link android.app.backup.IBackupManager IBackupManager} for communicating
      * with the backup mechanism.
@@ -4009,9 +4059,9 @@
      * with the rollback manager
      *
      * @see #getSystemService(String)
-     * @hide TODO(ruhler): hidden, @TestApi until we decide on public vs. @SystemApi.
+     * @hide
      */
-    @TestApi
+    @SystemApi
     public static final String ROLLBACK_SERVICE = "rollback";
 
     /**
@@ -4419,6 +4469,16 @@
     public static final String STATS_MANAGER = "stats";
 
     /**
+     * Service to capture a bugreport.
+     * @see #getSystemService(String)
+     * @see android.os.BugreportManager
+     * @hide
+     */
+    // TODO: Expose API when the implementation is more complete.
+    // @SystemApi
+    public static final String BUGREPORT_SERVICE = "bugreport";
+
+    /**
      * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.content.om.OverlayManager} for managing overlay packages.
      *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3492200..b46203c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -27,13 +27,13 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
@@ -817,6 +817,28 @@
             = "android.intent.action.SHOW_APP_INFO";
 
     /**
+     * Activity Action: Start an activity to show the app's detailed usage information for
+     * permission protected data.
+     *
+     * The Intent contains an extra {@link #EXTRA_PERMISSION_USAGE_PERMISSIONS} that is of
+     * type {@code String[]} and contains the specific permissions to show information for.
+     *
+     * Apps should handle this intent if they want to provide more information about permission
+     * usage to users beyond the information provided in the manifest.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_PERMISSION_USAGE_DETAILS =
+            "android.intent.action.PERMISSION_USAGE_DETAILS";
+
+    /**
+     * The name of the extra used to contain the permissions in
+     * {@link #ACTION_PERMISSION_USAGE_DETAILS}.
+     * @see #ACTION_PERMISSION_USAGE_DETAILS
+     */
+    public static final String EXTRA_PERMISSION_USAGE_PERMISSIONS =
+            "android.intent.extra.PERMISSION_USAGE_PERMISSIONS";
+
+    /**
      * Represents a shortcut/live folder icon resource.
      *
      * @see Intent#ACTION_CREATE_SHORTCUT
@@ -1812,6 +1834,54 @@
             "android.intent.action.REVIEW_PERMISSIONS";
 
     /**
+     * Activity action: Launch UI to manage a default app.
+     * <p>
+     * Input: {@link #EXTRA_ROLE_NAME} specifies the role of the default app which will be managed
+     * by the launched UI.
+     * </p>
+     * <p>
+     * Output: Nothing.
+     * </p>
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS)
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    @SystemApi
+    public static final String ACTION_MANAGE_DEFAULT_APP =
+            "android.intent.action.MANAGE_DEFAULT_APP";
+
+    /**
+     * Intent extra: A role name.
+     * <p>
+     * Type: String
+     * </p>
+     *
+     * @see android.app.role.RoleManager
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
+
+    /**
+     * Activity action: Launch UI to manage special app accesses.
+     * <p>
+     * Input: Nothing.
+     * </p>
+     * <p>
+     * Output: Nothing.
+     * </p>
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS)
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    @SystemApi
+    public static final String ACTION_MANAGE_SPECIAL_APP_ACCESSES =
+            "android.intent.action.MANAGE_SPECIAL_APP_ACCESSES";
+
+    /**
      * Intent extra: A callback for reporting remote result as a bundle.
      * <p>
      * Type: IRemoteCallback
@@ -1885,6 +1955,17 @@
     public static final String EXTRA_LAUNCHER_EXTRAS = "android.intent.extra.LAUNCHER_EXTRAS";
 
     /**
+     * Intent extra: ID of the shortcut used to send the share intent.
+     *
+     * @see ShortcutInfo#getId()
+     *
+     * <p>
+     * Type: String
+     * </p>
+     */
+    public static final String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID";
+
+    /**
      * Activity action: Launch UI to manage which apps have a given permission.
      * <p>
      * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission group
@@ -1915,16 +1996,49 @@
     public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
 
     /**
+     * Intent extra: The name of a permission group.
+     * <p>
+     * Type: String
+     * </p>
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PERMISSION_GROUP_NAME =
+            "android.intent.extra.PERMISSION_GROUP_NAME";
+
+    /**
+     * Intent extra: The number of milliseconds.
+     * <p>
+     * Type: long
+     * </p>
+     */
+    public static final String EXTRA_DURATION_MILLIS =
+            "android.intent.extra.DURATION_MILLIS";
+
+    /**
      * Activity action: Launch UI to review app uses of permissions.
      * <p>
      * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission name
-     * that will be displayed by the launched UI.
+     * that will be displayed by the launched UI.  Do not pass both this and
+     * {@link #EXTRA_PERMISSION_GROUP_NAME} .
+     * </p>
+     * <p>
+     * Input: {@link #EXTRA_PERMISSION_GROUP_NAME} specifies the permission group name
+     * that will be displayed by the launched UI.  Do not pass both this and
+     * {@link #EXTRA_PERMISSION_NAME}.
+     * </p>
+     * <p>
+     * Input: {@link #EXTRA_DURATION_MILLIS} specifies the minimum number of milliseconds of recent
+     * activity to show (optional).  Must be non-negative.
      * </p>
      * <p>
      * Output: Nothing.
      * </p>
      *
      * @see #EXTRA_PERMISSION_NAME
+     * @see #EXTRA_PERMISSION_GROUP_NAME
+     * @see #EXTRA_DURATION_MILLIS
      *
      * @hide
      */
@@ -2263,14 +2377,13 @@
     /**
      * Broadcast Action: An existing version of an application package has been
      * rolled back to a previous version.
-     * The data contains the name of the package.
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      *
-     * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi.
+     * @hide
      */
-    @TestApi
+    @SystemApi
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_PACKAGE_ROLLBACK_EXECUTED =
             "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
@@ -2354,6 +2467,25 @@
     public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
 
     /**
+     * Broadcast Action: Distracting packages have been changed.
+     * <p>Includes the following extras:
+     * <ul>
+     * <li> {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages which have been changed.
+     * <li> {@link #EXTRA_CHANGED_UID_LIST} is the set of uids which have been changed.
+     * <li> {@link #EXTRA_DISTRACTION_RESTRICTIONS} the new restrictions set on these packages.
+     * </ul>
+     *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system. It is only sent to registered receivers.
+     *
+     * @see PackageManager#setDistractingPackageRestrictions(String[], int)
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DISTRACTING_PACKAGES_CHANGED =
+            "android.intent.action.DISTRACTING_PACKAGES_CHANGED";
+
+    /**
      * Broadcast Action: Sent to a package that has been suspended by the system. This is sent
      * whenever a package is put into a suspended state or any of its app extras change while in the
      * suspended state.
@@ -3073,7 +3205,18 @@
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
+     *
+     * <p class="note">If the user has chosen a {@link android.telecom.CallRedirectionService} to
+     * handle redirection of outgoing calls, this intent will NOT be sent as an ordered broadcast.
+     * This means that attempts to re-write the outgoing call by other apps using this intent will
+     * be ignored.
+     * </p>
+     *
+     * @deprecated Apps that redirect outgoing calls should use the
+     * {@link android.telecom.CallRedirectionService} API.  Apps that perform call screening
+     * should use the {@link android.telecom.CallScreeningService} API.
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_NEW_OUTGOING_CALL =
             "android.intent.action.NEW_OUTGOING_CALL";
@@ -5063,6 +5206,17 @@
             "android.intent.extra.changed_uid_list";
 
     /**
+     * An integer denoting a bitwise combination of restrictions set on distracting packages via
+     * {@link PackageManager#setDistractingPackageRestrictions(String[], int)}
+     *
+     * @hide
+     * @see PackageManager.DistractionRestriction
+     * @see PackageManager#setDistractingPackageRestrictions(String[], int)
+     */
+    public static final String EXTRA_DISTRACTION_RESTRICTIONS =
+            "android.intent.extra.distraction_restrictions";
+
+    /**
      * @hide
      * Magic extra system code can use when binding, to give a label for
      * who it is that has bound to a service.  This is an integer giving
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index dd55003..1989f06 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -18,8 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
-import android.os.Build;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -32,8 +31,10 @@
  *
  * @hide
  */
+@SystemApi
 public final class OverlayInfo implements Parcelable {
 
+    /** @hide */
     @IntDef(prefix = "STATE_", value = {
             STATE_UNKNOWN,
             STATE_MISSING_TARGET,
@@ -44,6 +45,7 @@
             STATE_TARGET_UPGRADING,
             STATE_OVERLAY_UPGRADING,
     })
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     public @interface State {}
 
@@ -52,17 +54,23 @@
      * objects exposed outside the {@link
      * com.android.server.om.OverlayManagerService} should never have this
      * state.
+     *
+     * @hide
      */
     public static final int STATE_UNKNOWN = -1;
 
     /**
      * The target package of the overlay is not installed. The overlay cannot be enabled.
+     *
+     * @hide
      */
     public static final int STATE_MISSING_TARGET = 0;
 
     /**
      * Creation of idmap file failed (e.g. no matching resources). The overlay
      * cannot be enabled.
+     *
+     * @hide
      */
     public static final int STATE_NO_IDMAP = 1;
 
@@ -70,6 +78,7 @@
      * The overlay is currently disabled. It can be enabled.
      *
      * @see IOverlayManager#setEnabled
+     * @hide
      */
     public static final int STATE_DISABLED = 2;
 
@@ -77,18 +86,21 @@
      * The overlay is currently enabled. It can be disabled.
      *
      * @see IOverlayManager#setEnabled
+     * @hide
      */
     public static final int STATE_ENABLED = 3;
 
     /**
      * The target package is currently being upgraded; the state will change
      * once the package installation has finished.
+     * @hide
      */
     public static final int STATE_TARGET_UPGRADING = 4;
 
     /**
      * The overlay package is currently being upgraded; the state will change
      * once the package installation has finished.
+     * @hide
      */
     public static final int STATE_OVERLAY_UPGRADING = 5;
 
@@ -96,6 +108,7 @@
      * The overlay package is currently enabled because it is marked as
      * 'static'. It cannot be disabled but will change state if for instance
      * its target is uninstalled.
+     * @hide
      */
     public static final int STATE_ENABLED_STATIC = 6;
 
@@ -103,40 +116,52 @@
      * Overlay category: theme.
      * <p>
      * Change how Android (including the status bar, dialogs, ...) looks.
+     *
+     * @hide
      */
     public static final String CATEGORY_THEME = "android.theme";
 
     /**
      * Package name of the overlay package
+     *
+     * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public final String packageName;
 
     /**
      * Package name of the target package
+     *
+     * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+    @SystemApi
     public final String targetPackageName;
 
     /**
      * Category of the overlay package
+     *
+     * @hide
      */
+    @SystemApi
     public final String category;
 
     /**
      * Full path to the base APK for this overlay package
+     * @hide
      */
     public final String baseCodePath;
 
     /**
      * The state of this OverlayInfo as defined by the STATE_* constants in this class.
+     * @hide
      */
-    @UnsupportedAppUsage
     public final @State int state;
 
     /**
      * User handle for which this overlay applies
+     * @hide
      */
+    @SystemApi
     public final int userId;
 
     /**
@@ -161,12 +186,15 @@
      *
      * @param source the source OverlayInfo to base the new instance on
      * @param state the new state for the source OverlayInfo
+     *
+     * @hide
      */
     public OverlayInfo(@NonNull OverlayInfo source, @State int state) {
         this(source.packageName, source.targetPackageName, source.category, source.baseCodePath,
                 state, source.userId, source.priority, source.isStatic);
     }
 
+    /** @hide */
     public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName,
             @NonNull String category, @NonNull String baseCodePath, int state, int userId,
             int priority, boolean isStatic) {
@@ -181,6 +209,7 @@
         ensureValidState();
     }
 
+    /** @hide */
     public OverlayInfo(Parcel source) {
         packageName = source.readString();
         targetPackageName = source.readString();
@@ -255,8 +284,9 @@
      * Disabled overlay packages are installed but are currently not in use.
      *
      * @return true if the overlay is enabled, else false.
+     * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public boolean isEnabled() {
         switch (state) {
             case STATE_ENABLED:
@@ -272,6 +302,7 @@
      * debugging purposes.
      *
      * @return a human readable String representing the state.
+     * @hide
      */
     public static String stateToString(@State int state) {
         switch (state) {
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
new file mode 100644
index 0000000..8e72fa5
--- /dev/null
+++ b/core/java/android/content/om/OverlayManager.java
@@ -0,0 +1,119 @@
+/*
+ * 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.om;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import java.util.List;
+
+/**
+ * Updates OverlayManager state; gets information about installed overlay packages.
+ * @hide
+ */
+@SystemApi
+@SystemService(Context.OVERLAY_SERVICE)
+public class OverlayManager {
+
+    private final IOverlayManager mService;
+    private final Context mContext;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param context The current context in which to operate.
+     * @param service The backing system service.
+     *
+     * @hide
+     */
+    public OverlayManager(Context context, IOverlayManager service) {
+        mContext = context;
+        mService = service;
+    }
+
+    /** @hide */
+    public OverlayManager(Context context) {
+        this(context, IOverlayManager.Stub.asInterface(
+            ServiceManager.getService(Context.OVERLAY_SERVICE)));
+    }
+
+    /**
+     * Request that an overlay package is enabled and any other overlay packages with the same
+     * target package and category are disabled.
+     *
+     * @param packageName the name of the overlay package to enable.
+     * @param userId The user for which to change the overlay.
+     * @return true if the system successfully registered the request, false otherwise.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean setEnabledExclusiveInCategory(@Nullable final String packageName,
+            int userId) {
+        try {
+            return mService.setEnabledExclusiveInCategory(packageName, userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request that an overlay package is enabled.
+     *
+     * @param packageName the name of the overlay package to enable.
+     * @param enable {@code false} if the overlay should be turned off.
+     * @param userId The user for which to change the overlay.
+     * @return true if the system successfully registered the request, false otherwise.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean setEnabled(@Nullable final String packageName, final boolean enable,
+            int userId) {
+        try {
+            return mService.setEnabled(packageName, enable, userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns information about all overlays for the given target package for
+     * the specified user. The returned list is ordered according to the
+     * overlay priority with the highest priority at the end of the list.
+     *
+     * @param targetPackageName The name of the target package.
+     * @param userId The user to get the OverlayInfos for.
+     * @return A list of OverlayInfo objects; if no overlays exist for the
+     *         requested package, an empty list is returned.
+     *
+     * @hide
+     */
+    @SystemApi
+    public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName,
+            int userId) {
+        try {
+            return mService.getOverlayInfosForTarget(targetPackageName, userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 0edb36c..47034a6 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -505,6 +505,22 @@
      */
     public int flags;
 
+    /**
+     * Bit in {@link #privateFlags} indicating if the activity should be shown when locked in case
+     * an activity behind this can also be shown when locked.
+     * See {@link android.R.attr#inheritShowWhenLocked}.
+     * @hide
+     */
+    public static final int FLAG_INHERIT_SHOW_WHEN_LOCKED = 0x1;
+
+    /**
+     * Options that have been set in the activity declaration in the manifest.
+     * These include:
+     * {@link #FLAG_INHERIT_SHOW_WHEN_LOCKED}.
+     * @hide
+     */
+    public int privateFlags;
+
     /** @hide */
     @IntDef(prefix = { "SCREEN_ORIENTATION_" }, value = {
             SCREEN_ORIENTATION_UNSET,
@@ -975,6 +991,7 @@
         taskAffinity = orig.taskAffinity;
         targetActivity = orig.targetActivity;
         flags = orig.flags;
+        privateFlags = orig.privateFlags;
         screenOrientation = orig.screenOrientation;
         configChanges = orig.configChanges;
         softInputMode = orig.softInputMode;
@@ -1122,9 +1139,10 @@
                     + " targetActivity=" + targetActivity
                     + " persistableMode=" + persistableModeToString());
         }
-        if (launchMode != 0 || flags != 0 || theme != 0) {
+        if (launchMode != 0 || flags != 0 || privateFlags != 0 || theme != 0) {
             pw.println(prefix + "launchMode=" + launchMode
                     + " flags=0x" + Integer.toHexString(flags)
+                    + " privateFlags=0x" + Integer.toHexString(privateFlags)
                     + " theme=0x" + Integer.toHexString(theme));
         }
         if (screenOrientation != SCREEN_ORIENTATION_UNSPECIFIED
@@ -1178,6 +1196,7 @@
         dest.writeString(targetActivity);
         dest.writeString(launchToken);
         dest.writeInt(flags);
+        dest.writeInt(privateFlags);
         dest.writeInt(screenOrientation);
         dest.writeInt(configChanges);
         dest.writeInt(softInputMode);
@@ -1307,6 +1326,7 @@
         targetActivity = source.readString();
         launchToken = source.readString();
         flags = source.readInt();
+        privateFlags = source.readInt();
         screenOrientation = source.readInt();
         configChanges = source.readInt();
         softInputMode = source.readInt();
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 9f469962..5d6d144 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1866,7 +1866,15 @@
         return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) != 0;
     }
 
-    /** @hide */
+    /**
+     * Check whether the application is encryption aware.
+     *
+     * @see #isDirectBootAware()
+     * @see #isPartiallyDirectBootAware()
+     *
+     * @hide
+     */
+    @SystemApi
     public boolean isEncryptionAware() {
         return isDirectBootAware() || isPartiallyDirectBootAware();
     }
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 740fd7f..b7366f1 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -18,6 +18,7 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -76,9 +77,23 @@
     }
 
     /**
-     * Starts the specified activity of the caller package in the specified profile if the caller
-     * has {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} permission and
-     * both the caller and target user profiles are in the same user group.
+     * @deprecated use {@link #startActivity(ComponentName, UserHandle)} instead.
+     *
+     * @removed
+     * @hide
+     */
+    @Deprecated
+    @UnsupportedAppUsage
+    public void startAnyActivity(@NonNull ComponentName component, @NonNull UserHandle targetUser) {
+        startActivity(component, targetUser);
+    }
+
+    /**
+     * Starts the specified activity of the caller package in the specified profile. Unlike
+     * {@link #startMainActivity}, this can start any activity of the caller package, not just
+     * the main activity.
+     * The caller must have the {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}
+     * permission and both the caller and target user profiles must be in the same profile group.
      *
      * @param component The ComponentName of the activity to launch. It must be exported.
      * @param targetUser The UserHandle of the profile, must be one of the users returned by
@@ -88,7 +103,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_PROFILES)
-    public void startAnyActivity(@NonNull ComponentName component, @NonNull UserHandle targetUser) {
+    public void startActivity(@NonNull ComponentName component, @NonNull UserHandle targetUser) {
         try {
             mService.startActivityAsUser(mContext.getIApplicationThread(),
                     mContext.getPackageName(), component, targetUser.getIdentifier(), false);
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index ba7710b..db2b6fd 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -69,6 +69,7 @@
             int userId);
 
     boolean hasShortcutHostPermission(String callingPackage);
+    boolean shouldHideFromSuggestions(String packageName, in UserHandle user);
 
     ParceledListSlice getShortcutConfigActivities(
             String callingPackage, String packageName, in UserHandle user);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 64a4479b..4b130b2 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -273,6 +273,9 @@
 
     void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
 
+    String[] setDistractingPackageRestrictionsAsUser(in String[] packageNames, int restrictionFlags,
+            int userId);
+
     String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
             in PersistableBundle appExtras, in PersistableBundle launcherExtras,
             in SuspendDialogInfo dialogInfo, String callingPackage, int userId);
@@ -537,6 +540,11 @@
             String targetCompilerFilter, boolean force);
 
     /**
+    * Ask the package manager to compile layouts in the given package.
+    */
+    boolean compileLayouts(String packageName);
+
+    /**
      * Ask the package manager to dump profiles associated with a package.
      */
     void dumpProfiles(String packageName);
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 03124be..c702b16 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -16,6 +16,7 @@
 package android.content.pm;
 
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ShortcutInfo;
@@ -72,4 +73,7 @@
     void applyRestore(in byte[] payload, int user);
 
     boolean isRequestPinItemSupported(int user, int requestType);
+
+    // System API used by framework's ShareSheet (ChooserActivity)
+    ParceledListSlice getShareTargets(String packageName, in IntentFilter filter, int userId);
 }
\ No newline at end of file
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 44e652f..766c566 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -136,6 +136,17 @@
     public static final String EXTRA_PIN_ITEM_REQUEST =
             "android.content.pm.extra.PIN_ITEM_REQUEST";
 
+    /**
+     * Metadata key that specifies vouched certs, so any apps signed by a cert in vouched certs
+     * will not show hidden icon in launcher even it does not have a launcher visible activity.
+     *
+     * If an app has this metadata in manifest, it won't be eligible to hide its icon even if its
+     * cert is in vouched certs list.
+     *
+     * @hide
+     */
+    public static final String VOUCHED_CERTS_KEY = "vouched_certs";
+
     private final Context mContext;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final ILauncherApps mService;
@@ -697,6 +708,26 @@
     }
 
     /**
+     * Returns whether a package should be hidden from suggestions to the user. Currently, this
+     * could be done because the package was marked as distracting to the user via
+     * {@code PackageManager.setDistractingPackageRestrictions(String[], int)}.
+     *
+     * @param packageName The package for which to check.
+     * @param user the {@link UserHandle} of the profile.
+     * @return
+     */
+    public boolean shouldHideFromSuggestions(@NonNull String packageName,
+            @NonNull UserHandle user) {
+        Preconditions.checkNotNull(packageName, "packageName");
+        Preconditions.checkNotNull(user, "user");
+        try {
+            return mService.shouldHideFromSuggestions(packageName, user);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns {@link ApplicationInfo} about an application installed for a specific user profile.
      *
      * @param packageName The package name of the application
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index b8d7889..6d22277 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -18,14 +18,10 @@
 
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
-import android.apex.ApexInfo;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Overall information about the contents of a package.  This corresponds
  * to all of the information collected from AndroidManifest.xml.
@@ -374,6 +370,14 @@
     public String overlayTarget;
 
     /**
+     * What overlayable set of elements package, if any, this package will overlay.
+     *
+     * Overlayable name defined within the target package, or null.
+     * @hide
+     */
+    public String overlayTargetName;
+
+    /**
      * The overlay category, if any, of this package
      *
      * @hide
@@ -573,15 +577,6 @@
         }
     }
 
-    /**
-     * @hide
-     */
-    public PackageInfo(ApexInfo apexInfo) {
-        packageName = apexInfo.packageName;
-        setLongVersionCode(apexInfo.versionCode);
-        isApex = true;
-    }
-
     private void propagateApplicationInfo(ApplicationInfo appInfo, ComponentInfo[] components) {
         if (components != null) {
             for (ComponentInfo ci : components) {
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index a2fd83f..94b7c45 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -24,7 +24,6 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
@@ -1428,9 +1427,9 @@
 
         /**
          * Request that rollbacks be enabled for the given upgrade.
-         * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi.
+         * @hide
          */
-        @TestApi
+        @SystemApi
         public void setEnableRollback() {
             installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
         }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6110557..783ee64 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1368,6 +1368,14 @@
      */
     public static final int INSTALL_FAILED_BAD_DEX_METADATA = -117;
 
+    /**
+     * Installation parse return code: this is passed in the
+     * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if there is any signature problem.
+     *
+     * @hide
+     */
+    public static final int INSTALL_FAILED_BAD_SIGNATURE = -118;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "DELETE_" }, value = {
             DELETE_KEEP_DATA,
@@ -1931,6 +1939,30 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports uicc-
+     * based NFC card emulation.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC =
+                                                                       "android.hardware.nfc.uicc";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports eSE-
+     * based NFC card emulation.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE = "android.hardware.nfc.ese";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The Beam API is enabled on the device.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_NFC_BEAM = "android.sofware.nfc.beam";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports any
      * one of the {@link #FEATURE_NFC}, {@link #FEATURE_NFC_HOST_CARD_EMULATION},
      * or {@link #FEATURE_NFC_HOST_CARD_EMULATION_NFCF} features.
@@ -2028,6 +2060,14 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device has a secure implementation of keyguard, meaning the
+     * device supports PIN, pattern and password as defined in Android CDD
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_SECURE_LOCK_SCREEN = "android.software.secure_lock_screen";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device includes an accelerometer.
      */
     @SdkConstant(SdkConstantType.FEATURE)
@@ -2183,6 +2223,13 @@
     public static final String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+     * supports attaching to IMS implementations using the ImsService API in telephony.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims";
+
+    /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports connecting to USB devices
      * as the USB host.
@@ -5523,26 +5570,24 @@
     }
 
     /**
-     * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superseded
-     * by (and conflicts with) the modern activity-based preferences.
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     public abstract void addPackageToPreferred(String packageName);
 
     /**
-     * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superseded
-     * by (and conflicts with) the modern activity-based preferences.
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     public abstract void removePackageFromPreferred(String packageName);
 
     /**
-     * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superseded
-     * by (and conflicts with) the modern activity-based preferences.
-     *
      * Retrieve the list of all currently configured preferred packages. The
      * first package on the list is the most preferred, the last is the least
      * preferred.
@@ -5550,15 +5595,16 @@
      * @param flags Additional option flags to modify the data returned.
      * @return A List of PackageInfo objects, one for each preferred
      *         application, in order of preference.
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     public abstract List<PackageInfo> getPreferredPackages(@PackageInfoFlags int flags);
 
     /**
-     * @deprecated This is a protected API that should not have been available
-     * to third party applications.  It is the platform's responsibility for
-     * assigning preferred activities and this cannot be directly modified.
-     *
      * Add a new preferred activity mapping to the system.  This will be used
      * to automatically select the given activity component when
      * {@link Context#startActivity(Intent) Context.startActivity()} finds
@@ -5572,20 +5618,26 @@
      * this preference was made.
      * @param activity The component name of the activity that is to be
      * preferred.
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     public abstract void addPreferredActivity(IntentFilter filter, int match,
             ComponentName[] set, ComponentName activity);
 
     /**
-     * @deprecated This is a protected API that should not have been available
-     * to third party applications.  It is the platform's responsibility for
-     * assigning preferred activities and this cannot be directly modified.
-     *
      * Same as {@link #addPreferredActivity(IntentFilter, int,
             ComponentName[], ComponentName)}, but with a specific userId to apply the preference
             to.
      * @hide
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     @UnsupportedAppUsage
@@ -5595,10 +5647,6 @@
     }
 
     /**
-     * @deprecated This is a protected API that should not have been available
-     * to third party applications.  It is the platform's responsibility for
-     * assigning preferred activities and this cannot be directly modified.
-     *
      * Replaces an existing preferred activity mapping to the system, and if that were not present
      * adds a new preferred activity.  This will be used
      * to automatically select the given activity component when
@@ -5613,7 +5661,13 @@
      * this preference was made.
      * @param activity The component name of the activity that is to be
      * preferred.
+     *
      * @hide
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     @UnsupportedAppUsage
@@ -5621,10 +5675,6 @@
             ComponentName[] set, ComponentName activity);
 
     /**
-     * @deprecated This is a protected API that should not have been available
-     * to third party applications.  It is the platform's responsibility for
-     * assigning preferred activities and this cannot be directly modified.
-     *
      * Replaces an existing preferred activity mapping to the system, and if that were not present
      * adds a new preferred activity.  This will be used to automatically select the given activity
      * component when {@link Context#startActivity(Intent) Context.startActivity()} finds multiple
@@ -5639,6 +5689,11 @@
      * @param activity The component name of the activity that is to be preferred.
      *
      * @hide
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     @SystemApi
@@ -5649,6 +5704,11 @@
 
     /**
      * @hide
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     @UnsupportedAppUsage
@@ -5658,10 +5718,6 @@
     }
 
     /**
-     * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superseded
-     * by (and conflicts with) the modern activity-based preferences.
-     *
      * Remove all preferred activity mappings, previously added with
      * {@link #addPreferredActivity}, from the
      * system whose activities are implemented in the given package name.
@@ -5669,15 +5725,16 @@
      *
      * @param packageName The name of the package whose preferred activity
      * mappings are to be removed.
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     public abstract void clearPackagePreferredActivities(String packageName);
 
     /**
-     * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superseded
-     * by (and conflicts with) the modern activity-based preferences.
-     *
      * Retrieve all preferred activities, previously added with
      * {@link #addPreferredActivity}, that are
      * currently registered with the system.
@@ -5693,6 +5750,11 @@
      * @return Returns the total number of registered preferred activities
      * (the number of distinct IntentFilter records, not the number of unique
      * activity components) that were found.
+     *
+     * @deprecated This function no longer does anything. It is the platform's
+     * responsibility to assign preferred activities and this cannot be modified
+     * directly. To determine the activities resolved by the platform, use
+     * {@link #resolveActivity} or {@link #queryIntentActivities}.
      */
     @Deprecated
     public abstract int getPreferredActivities(@NonNull List<IntentFilter> outFilters,
@@ -5717,7 +5779,7 @@
      */
     @RequiresPermission(value = android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE,
             conditional = true)
-    public abstract void setComponentEnabledSetting(ComponentName componentName,
+    public abstract void setComponentEnabledSetting(@NonNull ComponentName componentName,
             @EnabledState int newState, @EnabledFlags int flags);
 
     /**
@@ -5731,7 +5793,7 @@
      * @return Returns the current enabled state for the component.
      */
     public abstract @EnabledState int getComponentEnabledSetting(
-            ComponentName componentName);
+            @NonNull ComponentName componentName);
 
     /**
      * Set the enabled setting for an application
@@ -5746,7 +5808,7 @@
      */
     @RequiresPermission(value = android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE,
             conditional = true)
-    public abstract void setApplicationEnabledSetting(String packageName,
+    public abstract void setApplicationEnabledSetting(@NonNull String packageName,
             @EnabledState int newState, @EnabledFlags int flags);
 
     /**
@@ -5760,7 +5822,7 @@
      * @return Returns the current enabled state for the application.
      * @throws IllegalArgumentException if the named package does not exist.
      */
-    public abstract @EnabledState int getApplicationEnabledSetting(String packageName);
+    public abstract @EnabledState int getApplicationEnabledSetting(@NonNull String packageName);
 
     /**
      * Flush the package restrictions for a given user to disk. This forces the package restrictions
@@ -5857,6 +5919,74 @@
     public abstract boolean isSignedByExactly(String packageName, KeySet ks);
 
     /**
+     * Flag to denote no restrictions. This should be used to clear any restrictions that may have
+     * been previously set for the package.
+     * @see PackageManager.DistractionRestriction
+     * @hide
+     */
+    @SystemApi
+    public static final int RESTRICTION_NONE = 0x0;
+
+    /**
+     * Flag to denote that a package should be hidden from any suggestions to the user.
+     * @see PackageManager.DistractionRestriction
+     * @hide
+     */
+    @SystemApi
+    public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 0x00000001;
+
+    /**
+     * Flag to denote that a package's notifications should be hidden.
+     * @see PackageManager.DistractionRestriction
+     * @hide
+     */
+    @SystemApi
+    public static final int RESTRICTION_HIDE_NOTIFICATIONS = 0x00000002;
+
+    /**
+     * Restriction flags to set on a package that is considered as distracting to the user.
+     * These should help the user to restrict their usage of these apps.
+     *
+     * @see #setDistractingPackageRestrictions(String[], int)
+     * @hide
+     */
+    @SystemApi
+    @IntDef(flag = true, prefix = {"RESTRICTION_"}, value = {
+            RESTRICTION_NONE,
+            RESTRICTION_HIDE_FROM_SUGGESTIONS,
+            RESTRICTION_HIDE_NOTIFICATIONS
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DistractionRestriction {}
+
+    /**
+     * Mark or unmark the given packages as distracting to the user.
+     * These packages can have certain restrictions set that should discourage the user to launch
+     * them often. For example, notifications from such an app can be hidden, or the app can be
+     * removed from launcher suggestions, so the user is able to restrict their use of these apps.
+     *
+     * <p>The caller must hold {@link android.Manifest.permission#SUSPEND_APPS} to use this API.
+     *
+     * @param packages Packages to mark as distracting.
+     * @param restrictionFlags Any combination of {@link DistractionRestriction restrictions} to
+     *                         impose on the given packages. {@link #RESTRICTION_NONE} can be used
+     *                         to clear any existing restrictions.
+     * @return A list of packages that could not have the {@code restrictionFlags} set. The system
+     * may prevent restricting critical packages to preserve normal device function.
+     *
+     * @see DistractionRestriction
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.SUSPEND_APPS)
+    @NonNull
+    public String[] setDistractingPackageRestrictions(@NonNull String[] packages,
+            @DistractionRestriction int restrictionFlags) {
+        throw new UnsupportedOperationException(
+                "setDistractingPackageRestrictions not implemented");
+    }
+
+    /**
      * Puts the package in a suspended state, where attempts at starting activities are denied.
      *
      * <p>It doesn't remove the data or the actual package file. The application's notifications
@@ -5879,8 +6009,7 @@
      * {@link PersistableBundle} objects to be shared with the apps being suspended and the
      * launcher to support customization that they might need to handle the suspended state.
      *
-     * <p>The caller must hold {@link Manifest.permission#SUSPEND_APPS} or
-     * {@link Manifest.permission#MANAGE_USERS} to use this api.</p>
+     * <p>The caller must hold {@link Manifest.permission#SUSPEND_APPS} to use this API.
      *
      * @param packageNames The names of the packages to set the suspended status.
      * @param suspended If set to {@code true}, the packages will be suspended, if set to
@@ -5923,7 +6052,7 @@
      * <p>When the user tries to launch a suspended app, a system dialog alerting them that the app
      * is suspended will be shown instead.
      * The caller can optionally customize the dialog by passing a {@link SuspendDialogInfo} object
-     * to this api. This dialog will have a button that starts the
+     * to this API. This dialog will have a button that starts the
      * {@link Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS} intent if the suspending app declares an
      * activity which handles this action.
      *
@@ -5934,7 +6063,7 @@
      * {@link PersistableBundle} objects to be shared with the apps being suspended and the
      * launcher to support customization that they might need to handle the suspended state.
      *
-     * <p>The caller must hold {@link Manifest.permission#SUSPEND_APPS} to use this api.
+     * <p>The caller must hold {@link Manifest.permission#SUSPEND_APPS} to use this API.
      *
      * @param packageNames The names of the packages to set the suspended status.
      * @param suspended If set to {@code true}, the packages will be suspended, if set to
@@ -5973,7 +6102,7 @@
      * #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
      * SuspendDialogInfo) setPackagesSuspended}. The platform prevents suspending certain critical
      * packages to keep the device in a functioning state, e.g. the default dialer.
-     * Apps need to hold {@link Manifest.permission#SUSPEND_APPS SUSPEND_APPS} to call this api.
+     * Apps need to hold {@link Manifest.permission#SUSPEND_APPS SUSPEND_APPS} to call this API.
      *
      * <p>
      * Note that this set of critical packages can change with time, so even though a package name
@@ -6243,6 +6372,7 @@
             case INSTALL_FAILED_ABORTED: return "INSTALL_FAILED_ABORTED";
             case INSTALL_FAILED_BAD_DEX_METADATA: return "INSTALL_FAILED_BAD_DEX_METADATA";
             case INSTALL_FAILED_MISSING_SPLIT: return "INSTALL_FAILED_MISSING_SPLIT";
+            case INSTALL_FAILED_BAD_SIGNATURE: return "INSTALL_FAILED_BAD_SIGNATURE";
             default: return Integer.toString(status);
         }
     }
@@ -6288,6 +6418,7 @@
             case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return PackageInstaller.STATUS_FAILURE_INVALID;
             case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return PackageInstaller.STATUS_FAILURE_INVALID;
             case INSTALL_FAILED_BAD_DEX_METADATA: return PackageInstaller.STATUS_FAILURE_INVALID;
+            case INSTALL_FAILED_BAD_SIGNATURE: return PackageInstaller.STATUS_FAILURE_INVALID;
             case INSTALL_FAILED_INTERNAL_ERROR: return PackageInstaller.STATUS_FAILURE;
             case INSTALL_FAILED_USER_RESTRICTED: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
             case INSTALL_FAILED_DUPLICATE_PERMISSION: return PackageInstaller.STATUS_FAILURE_CONFLICT;
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 83979e9..c9a4c82 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -55,6 +55,7 @@
     public static final int PACKAGE_PERMISSION_CONTROLLER = 6;
     public static final int PACKAGE_WELLBEING = 7;
     public static final int PACKAGE_DOCUMENTER = 8;
+    public static final int PACKAGE_CONFIGURATOR = 9;
     @IntDef(value = {
         PACKAGE_SYSTEM,
         PACKAGE_SETUP_WIZARD,
@@ -65,6 +66,7 @@
         PACKAGE_PERMISSION_CONTROLLER,
         PACKAGE_WELLBEING,
         PACKAGE_DOCUMENTER,
+        PACKAGE_CONFIGURATOR,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface KnownPackage {}
@@ -137,6 +139,12 @@
     public abstract void setLocationPackagesProvider(PackagesProvider provider);
 
     /**
+     * Set the location extra packages provider.
+     * @param provider The packages provider.
+     */
+    public abstract  void setLocationExtraPackagesProvider(PackagesProvider provider);
+
+    /**
      * Sets the voice interaction packages provider.
      * @param provider The packages provider.
      */
@@ -284,6 +292,17 @@
     public abstract SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage, int userId);
 
     /**
+     * Gets any distraction flags set via
+     * {@link PackageManager#setDistractingPackageRestrictions(String[], int)}
+     *
+     * @param packageName
+     * @param userId
+     * @return A bitwise OR of any of the {@link PackageManager.DistractionRestriction}
+     */
+    public abstract @PackageManager.DistractionRestriction int getDistractingPackageRestrictions(
+            String packageName, int userId);
+
+    /**
      * Do a straight uid lookup for the given package/application in the given user.
      * @see PackageManager#getPackageUidAsUser(String, int, int)
      * @return The app's uid, or < 0 if the package was not found in that user
@@ -775,6 +794,12 @@
             "android.content.pm.extra.ENABLE_ROLLBACK_INSTALL_FLAGS";
 
     /**
+     * Extra field name for the set of installed users for a given rollback package.
+     */
+    public static final String EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS =
+            "android.content.pm.extra.ENABLE_ROLLBACK_INSTALLED_USERS";
+
+    /**
      * Used as the {@code enableRollbackCode} argument for
      * {@link PackageManagerInternal#setEnableRollbackCode} to indicate that
      * enabling rollback succeeded.
@@ -803,4 +828,15 @@
      *            PACKAGE_ROLLBACK_AGENT permission.
      */
     public abstract void setEnableRollbackCode(int token, int enableRollbackCode);
+
+    /**
+     * Ask the package manager to compile layouts in the given package.
+     */
+    public abstract boolean compileLayouts(String packageName);
+
+    /*
+     * Inform the package manager that the pending package install identified by
+     * {@code token} can be completed.
+     */
+    public abstract void finishPackageInstall(int token, boolean didLaunch);
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2b266b7..d5636d5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -689,6 +689,7 @@
         pi.restrictedAccountType = p.mRestrictedAccountType;
         pi.requiredAccountType = p.mRequiredAccountType;
         pi.overlayTarget = p.mOverlayTarget;
+        pi.overlayTargetName = p.mOverlayTargetName;
         pi.overlayCategory = p.mOverlayCategory;
         pi.overlayPriority = p.mOverlayPriority;
         pi.mOverlayIsStatic = p.mOverlayIsStatic;
@@ -1621,7 +1622,7 @@
             }
 
             final AttributeSet attrs = parser;
-            return parseApkLite(apkPath, parser, attrs, signingDetails);
+            return parseApkLite(apkPath, parser, attrs, signingDetails, flags);
 
         } catch (XmlPullParserException | IOException | RuntimeException e) {
             Slog.w(TAG, "Failed to parse " + apkPath, e);
@@ -1708,7 +1709,7 @@
     }
 
     private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs,
-            SigningDetails signingDetails)
+            SigningDetails signingDetails, int flags)
             throws IOException, XmlPullParserException, PackageParserException {
         final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
 
@@ -1716,11 +1717,12 @@
         int versionCode = 0;
         int versionCodeMajor = 0;
         int revisionCode = 0;
+        int targetSdkVersion = 0;
         boolean coreApp = false;
         boolean debuggable = false;
         boolean multiArch = false;
         boolean use32bitAbi = false;
-        boolean extractNativeLibs = true;
+        Boolean extractNativeLibsProvided = null;
         boolean isolatedSplits = false;
         boolean isFeatureSplit = false;
         boolean isSplitRequired = false;
@@ -1785,7 +1787,8 @@
                         use32bitAbi = attrs.getAttributeBooleanValue(i, false);
                     }
                     if ("extractNativeLibs".equals(attr)) {
-                        extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
+                        extractNativeLibsProvided = Boolean.valueOf(
+                                attrs.getAttributeBooleanValue(i, true));
                     }
                     if ("preferCodeIntegrity".equals(attr)) {
                         preferCodeIntegrity = attrs.getAttributeBooleanValue(i, false);
@@ -1803,9 +1806,51 @@
                             PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                             "<uses-split> tag requires 'android:name' attribute");
                 }
+            } else if (TAG_USES_SDK.equals(parser.getName())) {
+                final String[] errorMsg = new String[1];
+                Pair<Integer, Integer> versions = deriveSdkVersions(new AbstractVersionsAccessor() {
+                    @Override public String getMinSdkVersionCode() {
+                        return getAttributeAsString("minSdkVersion");
+                    }
+
+                    @Override public int getMinSdkVersion() {
+                        return getAttributeAsInt("minSdkVersion");
+                    }
+
+                    @Override public String getTargetSdkVersionCode() {
+                        return getAttributeAsString("targetSdkVersion");
+                    }
+
+                    @Override public int getTargetSdkVersion() {
+                        return getAttributeAsInt("targetSdkVersion");
+                    }
+
+                    private String getAttributeAsString(String name) {
+                        return attrs.getAttributeValue(ANDROID_RESOURCES, name);
+                    }
+
+                    private int getAttributeAsInt(String name) {
+                        try {
+                            return attrs.getAttributeIntValue(ANDROID_RESOURCES, name, -1);
+                        } catch (NumberFormatException e) {
+                            return -1;
+                        }
+                    }
+                }, flags, errorMsg);
+
+                if (versions == null) {
+                    throw new PackageParserException(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, errorMsg[0]);
+                }
+
+                targetSdkVersion = versions.second;
             }
         }
 
+        final boolean extractNativeLibsDefault = targetSdkVersion < Build.VERSION_CODES.Q;
+        final boolean extractNativeLibs = (extractNativeLibsProvided != null)
+                ? extractNativeLibsProvided : extractNativeLibsDefault;
+
         if (preferCodeIntegrity && extractNativeLibs) {
             throw new PackageParserException(
                     PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
@@ -2078,6 +2123,8 @@
                         com.android.internal.R.styleable.AndroidManifestResourceOverlay);
                 pkg.mOverlayTarget = sa.getString(
                         com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
+                pkg.mOverlayTargetName = sa.getString(
+                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetName);
                 pkg.mOverlayCategory = sa.getString(
                         com.android.internal.R.styleable.AndroidManifestResourceOverlay_category);
                 pkg.mOverlayPriority = sa.getInt(
@@ -2215,65 +2262,60 @@
 
             } else if (tagName.equals(TAG_USES_SDK)) {
                 if (SDK_VERSION > 0) {
-                    sa = res.obtainAttributes(parser,
-                            com.android.internal.R.styleable.AndroidManifestUsesSdk);
+                    sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk);
+                    final TypedArray saFinal = sa;
+                    Pair<Integer, Integer> versions = deriveSdkVersions(
+                            new AbstractVersionsAccessor() {
+                                @Override public String getMinSdkVersionCode() {
+                                    return getAttributeAsString(
+                                            R.styleable.AndroidManifestUsesSdk_minSdkVersion);
+                                }
 
-                    int minVers = 1;
-                    String minCode = null;
-                    int targetVers = 0;
-                    String targetCode = null;
+                                @Override public int getMinSdkVersion() {
+                                    return getAttributeAsInt(
+                                            R.styleable.AndroidManifestUsesSdk_minSdkVersion);
+                                }
 
-                    TypedValue val = sa.peekValue(
-                            com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
-                    if (val != null) {
-                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
-                            minCode = val.string.toString();
-                        } else {
-                            // If it's not a string, it's an integer.
-                            minVers = val.data;
-                        }
+                                @Override public String getTargetSdkVersionCode() {
+                                    return getAttributeAsString(
+                                            R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
+                                }
+
+                                @Override public int getTargetSdkVersion() {
+                                    return getAttributeAsInt(
+                                            R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
+                                }
+
+                                private String getAttributeAsString(int index) {
+                                    TypedValue val = saFinal.peekValue(index);
+                                    if (val != null && val.type == TypedValue.TYPE_STRING
+                                            && val.string != null) {
+                                        return val.string.toString();
+                                    }
+                                    return null;
+                                }
+
+                                private int getAttributeAsInt(int index) {
+                                    TypedValue val = saFinal.peekValue(index);
+                                    if (val != null && val.type != TypedValue.TYPE_STRING) {
+                                        // If it's not a string, it's an integer.
+                                        return val.data;
+                                    }
+                                    return -1;
+                                }
+                            }, flags, outError);
+
+                    if (versions == null) {
+                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+                        return null;
                     }
 
-                    val = sa.peekValue(
-                            com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
-                    if (val != null) {
-                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
-                            targetCode = val.string.toString();
-                            if (minCode == null) {
-                                minCode = targetCode;
-                            }
-                        } else {
-                            // If it's not a string, it's an integer.
-                            targetVers = val.data;
-                        }
-                    } else {
-                        targetVers = minVers;
-                        targetCode = minCode;
-                    }
+                    pkg.applicationInfo.minSdkVersion = versions.first;
+                    pkg.applicationInfo.targetSdkVersion = versions.second;
 
                     sa.recycle();
-
-                    final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode,
-                            SDK_VERSION, SDK_CODENAMES, outError);
-                    if (minSdkVersion < 0) {
-                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
-                        return null;
-                    }
-
-                    boolean defaultToCurrentDevBranch = (flags & PARSE_FORCE_SDK) != 0;
-                    final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers,
-                            targetCode, SDK_CODENAMES, outError, defaultToCurrentDevBranch);
-                    if (targetSdkVersion < 0) {
-                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
-                        return null;
-                    }
-
-                    pkg.applicationInfo.minSdkVersion = minSdkVersion;
-                    pkg.applicationInfo.targetSdkVersion = targetSdkVersion;
                 }
-
                 XmlUtils.skipCurrentTag(parser);
-
             } else if (tagName.equals(TAG_SUPPORT_SCREENS)) {
                 sa = res.obtainAttributes(parser,
                         com.android.internal.R.styleable.AndroidManifestSupportsScreens);
@@ -2617,6 +2659,23 @@
     }
 
     /**
+     * Matches a given {@code targetCode} against a set of release codeNames. Target codes can
+     * either be of the form {@code [codename]}" (e.g {@code "Q"}) or of the form
+     * {@code [codename].[fingerprint]} (e.g {@code "Q.cafebc561"}).
+     */
+    private static boolean matchTargetCode(@NonNull String[] codeNames,
+            @NonNull String targetCode) {
+        final String targetCodeName;
+        final int targetCodeIdx = targetCode.indexOf('.');
+        if (targetCodeIdx == -1) {
+            targetCodeName = targetCode;
+        } else {
+            targetCodeName = targetCode.substring(0, targetCodeIdx);
+        }
+        return ArrayUtils.contains(codeNames, targetCodeName);
+    }
+
+    /**
      * Computes the targetSdkVersion to use at runtime. If the package is not
      * compatible with this platform, populates {@code outError[0]} with an
      * error message.
@@ -2659,7 +2718,7 @@
 
         // If it's a pre-release SDK and the codename matches this platform, it
         // definitely targets this SDK.
-        if (ArrayUtils.contains(platformSdkCodenames, targetCode) || forceCurrentDev) {
+        if (matchTargetCode(platformSdkCodenames, targetCode) || forceCurrentDev) {
             return Build.VERSION_CODES.CUR_DEVELOPMENT;
         }
 
@@ -2675,6 +2734,67 @@
         return -1;
     }
 
+    private interface AbstractVersionsAccessor {
+        /** Returns minimum SDK version code string, or null if absent. */
+        String getMinSdkVersionCode();
+
+        /** Returns minimum SDK version code, or -1 if absent. */
+        int getMinSdkVersion();
+
+        /** Returns target SDK version code string, or null if absent. */
+        String getTargetSdkVersionCode();
+
+        /** Returns target SDK version code, or -1 if absent. */
+        int getTargetSdkVersion();
+    }
+
+    private static @Nullable Pair<Integer, Integer> deriveSdkVersions(
+            @NonNull AbstractVersionsAccessor accessor, int flags, String[] outError) {
+        int minVers = 1;
+        String minCode = null;
+        int targetVers = 0;
+        String targetCode = null;
+
+        String code = accessor.getMinSdkVersionCode();
+        int version = accessor.getMinSdkVersion();
+        // Check integer first since code is almost never a null string (e.g. "28").
+        if (version >= 0) {
+            minVers = version;
+        } else if (code != null) {
+            minCode = code;
+        }
+
+        code = accessor.getTargetSdkVersionCode();
+        version = accessor.getTargetSdkVersion();
+        // Check integer first since code is almost never a null string (e.g. "28").
+        if (version >= 0) {
+            targetVers = version;
+        } else if (code != null) {
+            targetCode = code;
+            if (minCode == null) {
+                minCode = targetCode;
+            }
+        } else {
+            targetVers = minVers;
+            targetCode = minCode;
+        }
+
+        final int minSdkVersion = computeMinSdkVersion(minVers, minCode,
+                SDK_VERSION, SDK_CODENAMES, outError);
+        if (minSdkVersion < 0) {
+            return null;
+        }
+
+        boolean defaultToCurrentDevBranch = (flags & PARSE_FORCE_SDK) != 0;
+        final int targetSdkVersion = computeTargetSdkVersion(targetVers,
+                targetCode, SDK_CODENAMES, outError, defaultToCurrentDevBranch);
+        if (targetSdkVersion < 0) {
+            return null;
+        }
+
+        return Pair.create(minSdkVersion, targetSdkVersion);
+    }
+
     /**
      * Computes the minSdkVersion to use at runtime. If the package is not
      * compatible with this platform, populates {@code outError[0]} with an
@@ -2731,7 +2851,7 @@
 
         // If it's a pre-release SDK and the codename matches this platform, we
         // definitely meet the minimum SDK requirement.
-        if (ArrayUtils.contains(platformSdkCodenames, minCode)) {
+        if (matchTargetCode(platformSdkCodenames, minCode)) {
             return Build.VERSION_CODES.CUR_DEVELOPMENT;
         }
 
@@ -3660,9 +3780,11 @@
             ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
         }
 
+        final boolean extractNativeLibsDefault =
+                owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q;
         if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
-                true)) {
+                extractNativeLibsDefault)) {
             ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
         }
 
@@ -4546,6 +4668,9 @@
                 a.info.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON;
             }
 
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_inheritShowWhenLocked, false)) {
+                a.info.privateFlags |= ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED;
+            }
         } else {
             a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             a.info.configChanges = 0;
@@ -4925,6 +5050,7 @@
         info.targetActivity = targetActivity;
         info.configChanges = target.info.configChanges;
         info.flags = target.info.flags;
+        info.privateFlags = target.info.privateFlags;
         info.icon = target.info.icon;
         info.logo = target.info.logo;
         info.banner = target.info.banner;
@@ -6607,6 +6733,7 @@
         public String mRequiredAccountType;
 
         public String mOverlayTarget;
+        public String mOverlayTargetName;
         public String mOverlayCategory;
         public int mOverlayPriority;
         public boolean mOverlayIsStatic;
@@ -7130,6 +7257,7 @@
             mRestrictedAccountType = dest.readString();
             mRequiredAccountType = dest.readString();
             mOverlayTarget = dest.readString();
+            mOverlayTargetName = dest.readString();
             mOverlayCategory = dest.readString();
             mOverlayPriority = dest.readInt();
             mOverlayIsStatic = (dest.readInt() == 1);
@@ -7257,6 +7385,7 @@
             dest.writeString(mRestrictedAccountType);
             dest.writeString(mRequiredAccountType);
             dest.writeString(mOverlayTarget);
+            dest.writeString(mOverlayTargetName);
             dest.writeString(mOverlayCategory);
             dest.writeInt(mOverlayPriority);
             dest.writeInt(mOverlayIsStatic ? 1 : 0);
@@ -8361,4 +8490,55 @@
             this.error = error;
         }
     }
+
+    public static PackageInfo generatePackageInfoFromApex(File apexFile, boolean collectCerts)
+            throws PackageParserException {
+        PackageInfo pi = new PackageInfo();
+
+        // TODO(b/123086053) properly fill in the ApplicationInfo with data from AndroidManifest
+        // Add ApplicationInfo to the PackageInfo.
+        ApplicationInfo ai = new ApplicationInfo();
+        ai.sourceDir = apexFile.getPath();
+        ai.flags = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
+        ai.enabled = true;
+        ai.targetSdkVersion = 28;
+        ai.targetSandboxVersion = 0;
+        pi.applicationInfo = ai;
+
+
+        // TODO(b/123052859): We should avoid these repeated calls to parseApkLite each time
+        // we want to generate information for APEX modules.
+        PackageParser.ApkLite apk = PackageParser.parseApkLite(apexFile,
+            collectCerts ? PackageParser.PARSE_COLLECT_CERTIFICATES : 0);
+
+        pi.packageName = apk.packageName;
+        pi.setLongVersionCode(apk.getLongVersionCode());
+        ai.setVersionCode(apk.getLongVersionCode());
+
+        if (collectCerts) {
+            if (apk.signingDetails.hasPastSigningCertificates()) {
+                // Package has included signing certificate rotation information.  Return
+                // the oldest cert so that programmatic checks keep working even if unaware
+                // of key rotation.
+                pi.signatures = new Signature[1];
+                pi.signatures[0] = apk.signingDetails.pastSigningCertificates[0];
+            } else if (apk.signingDetails.hasSignatures()) {
+                // otherwise keep old behavior
+                int numberOfSigs = apk.signingDetails.signatures.length;
+                pi.signatures = new Signature[numberOfSigs];
+                System.arraycopy(apk.signingDetails.signatures, 0, pi.signatures, 0,
+                    numberOfSigs);
+            }
+
+            if (apk.signingDetails != SigningDetails.UNKNOWN) {
+                // only return a valid SigningInfo if there is signing information to report
+                pi.signingInfo = new SigningInfo(apk.signingDetails);
+            } else {
+                pi.signingInfo = null;
+            }
+        }
+
+        pi.isApex = true;
+        return pi;
+    }
 }
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index be6ed51..249b691 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -29,8 +29,11 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.os.BaseBundle;
+import android.os.Debug;
 import android.os.PersistableBundle;
 import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
@@ -43,11 +46,15 @@
  * @hide
  */
 public class PackageUserState {
+    private static final boolean DEBUG = false;
+    private static final String LOG_TAG = "PackageUserState";
+
     public long ceDataInode;
     public boolean installed;
     public boolean stopped;
     public boolean notLaunched;
     public boolean hidden; // Is the app restricted by owner / admin
+    public int distractionFlags;
     public boolean suspended;
     public String suspendingPackage;
     public SuspendDialogInfo dialogInfo;
@@ -86,6 +93,7 @@
         stopped = o.stopped;
         notLaunched = o.notLaunched;
         hidden = o.hidden;
+        distractionFlags = o.distractionFlags;
         suspended = o.suspended;
         suspendingPackage = o.suspendingPackage;
         dialogInfo = o.dialogInfo;
@@ -132,12 +140,12 @@
         final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp();
         final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
         if (!isAvailable(flags)
-                && !(isSystemApp && matchUninstalled)) return false;
-        if (!isEnabled(componentInfo, flags)) return false;
+                && !(isSystemApp && matchUninstalled)) return reportIfDebug(false, flags);
+        if (!isEnabled(componentInfo, flags)) return reportIfDebug(false, flags);
 
         if ((flags & MATCH_SYSTEM_ONLY) != 0) {
             if (!isSystemApp) {
-                return false;
+                return reportIfDebug(false, flags);
             }
         }
 
@@ -145,7 +153,16 @@
                 && !componentInfo.directBootAware;
         final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
                 && componentInfo.directBootAware;
-        return matchesUnaware || matchesAware;
+        return reportIfDebug(matchesUnaware || matchesAware, flags);
+    }
+
+    private boolean reportIfDebug(boolean result, int flags) {
+        if (DEBUG && !result) {
+            Slog.i(LOG_TAG, "No match!; flags: "
+                    + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
+                    + Debug.getCaller());
+        }
+        return result;
     }
 
     /**
@@ -207,6 +224,9 @@
         if (hidden != oldState.hidden) {
             return false;
         }
+        if (distractionFlags != oldState.distractionFlags) {
+            return false;
+        }
         if (suspended != oldState.suspended) {
             return false;
         }
diff --git a/core/java/android/content/pm/PermissionGroupInfo.java b/core/java/android/content/pm/PermissionGroupInfo.java
index 8cf66d8..f21612a 100644
--- a/core/java/android/content/pm/PermissionGroupInfo.java
+++ b/core/java/android/content/pm/PermissionGroupInfo.java
@@ -49,7 +49,7 @@
      * only access while in the foreground.
      *
      * From the "requestDetail" attribute or, if not set, {@link
-     * android.content.res.ResourceId#ID_NULL}.
+     * android.content.res.Resources#ID_NULL}.
      *
      * @hide
      */
@@ -61,7 +61,7 @@
      * access. Also used when requesting both foreground and background access.
      *
      * From the "backgroundRequest" attribute or, if not set, {@link
-     * android.content.res.ResourceId#ID_NULL}.
+     * android.content.res.Resources#ID_NULL}.
      *
      * @hide
      */
@@ -73,7 +73,7 @@
      * background access.
      *
      * From the "backgroundRequestDetail" attribute or, if not set, {@link
-     * android.content.res.ResourceId#ID_NULL}.
+     * android.content.res.Resources#ID_NULL}.
      *
      * @hide
      */
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index bb8c92d..5d2cf0a 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -158,6 +158,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int PROTECTION_FLAG_OEM = 0x4000;
 
     /**
@@ -202,6 +203,16 @@
     @TestApi
     public static final int PROTECTION_FLAG_DOCUMENTER = 0x40000;
 
+    /**
+     * Additional flag for {@link #protectionLevel}, corresponding to the
+     * {@code configurator} value of {@link android.R.attr#protectionLevel}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int PROTECTION_FLAG_CONFIGURATOR = 0x80000;
+
 
     /** @hide */
     @IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = {
@@ -221,6 +232,7 @@
             PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER,
             PROTECTION_FLAG_WELLBEING,
             PROTECTION_FLAG_DOCUMENTER,
+            PROTECTION_FLAG_CONFIGURATOR,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProtectionFlags {}
@@ -416,6 +428,9 @@
         if ((level & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0) {
             protLevel += "|documenter";
         }
+        if ((level & PROTECTION_FLAG_CONFIGURATOR) != 0) {
+            protLevel += "|configurator";
+        }
         return protLevel;
     }
 
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 701c5db..894de94 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.IntentFilter;
@@ -175,9 +176,12 @@
     public boolean system;
 
     /**
-     * @hide Does the associated IntentFilter comes from a Browser ?
+     * Will be set to {@code true} if the {@link IntentFilter} responsible for intent
+     * resolution is classified as a "browser".
+     *
+     * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public boolean handleAllWebDataURI;
 
     /** {@hide} */
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index ec2e2fd..fe68b8a 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -21,6 +21,7 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
+import android.app.Person;
 import android.app.TaskStackBuilder;
 import android.content.ComponentName;
 import android.content.Context;
@@ -111,6 +112,9 @@
     public static final int FLAG_SHADOW = 1 << 12;
 
     /** @hide */
+    public static final int FLAG_LONG_LIVED = 1 << 13;
+
+    /** @hide */
     @IntDef(flag = true, prefix = { "FLAG_" }, value = {
             FLAG_DYNAMIC,
             FLAG_PINNED,
@@ -124,6 +128,8 @@
             FLAG_ADAPTIVE_BITMAP,
             FLAG_RETURNED_BY_SERVICE,
             FLAG_ICON_FILE_PENDING_SAVE,
+            FLAG_SHADOW,
+            FLAG_LONG_LIVED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ShortcutFlags {}
@@ -344,6 +350,9 @@
     @Nullable
     private PersistableBundle[] mIntentPersistableExtrases;
 
+    @Nullable
+    private Person[] mPersons;
+
     private int mRank;
 
     /**
@@ -399,6 +408,10 @@
         mCategories = cloneCategories(b.mCategories);
         mIntents = cloneIntents(b.mIntents);
         fixUpIntentExtras();
+        mPersons = clonePersons(b.mPersons);
+        if (b.mIsLongLived) {
+            setLongLived();
+        }
         mRank = b.mRank;
         mExtras = b.mExtras;
         updateTimestamp();
@@ -465,6 +478,20 @@
         return ret;
     }
 
+    private static Person[] clonePersons(Person[] persons) {
+        if (persons == null) {
+            return null;
+        }
+        final Person[] ret = new Person[persons.length];
+        for (int i = 0; i < ret.length; i++) {
+            if (persons[i] != null) {
+                // Don't need to keep the icon, remove it to save space
+                ret[i] = persons[i].toBuilder().setIcon(null).build();
+            }
+        }
+        return ret;
+    }
+
     /**
      * Throws if any of the mandatory fields is not set.
      *
@@ -511,6 +538,7 @@
             mDisabledMessage = source.mDisabledMessage;
             mDisabledMessageResId = source.mDisabledMessageResId;
             mCategories = cloneCategories(source.mCategories);
+            mPersons = clonePersons(source.mPersons);
             if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
                 mIntents = cloneIntents(source.mIntents);
                 mIntentPersistableExtrases =
@@ -833,6 +861,9 @@
         if (source.mCategories != null) {
             mCategories = cloneCategories(source.mCategories);
         }
+        if (source.mPersons != null) {
+            mPersons = clonePersons(source.mPersons);
+        }
         if (source.mIntents != null) {
             mIntents = cloneIntents(source.mIntents);
             mIntentPersistableExtrases =
@@ -901,6 +932,10 @@
 
         private Intent[] mIntents;
 
+        private Person[] mPersons;
+
+        private boolean mIsLongLived;
+
         private int mRank = RANK_NOT_SET;
 
         private PersistableBundle mExtras;
@@ -1165,6 +1200,53 @@
         }
 
         /**
+         * Add a person that is relevant to this shortcut. Alternatively,
+         * {@link #setPersons(Person[])} can be used to add multiple persons to a shortcut.
+         *
+         * <p> This is an optional field, but the addition of person may cause this shortcut to
+         * appear more prominently in the user interface (e.g. ShareSheet).
+         *
+         * <p> A person should usually contain a uri in order to benefit from the ranking boost.
+         * However, even if no uri is provided, it's beneficial to provide people in the shortcut,
+         * such that listeners and voice only devices can announce and handle them properly.
+         *
+         * @see Person
+         * @see #setPersons(Person[])
+         */
+        @NonNull
+        public Builder setPerson(@NonNull Person person) {
+            return setPersons(new Person[]{person});
+        }
+
+        /**
+         * Sets multiple persons instead of a single person.
+         *
+         * @see Person
+         * @see #setPerson(Person)
+         */
+        @NonNull
+        public Builder setPersons(@NonNull Person[] persons) {
+            Preconditions.checkNotNull(persons, "persons cannot be null");
+            Preconditions.checkNotNull(persons.length, "persons cannot be empty");
+            for (Person person : persons) {
+                Preconditions.checkNotNull(person, "persons cannot contain null");
+            }
+            mPersons = clonePersons(persons);
+            return this;
+        }
+
+        /**
+         * Sets if a shortcut would be valid even if it has been unpublished/invisible by the app
+         * (as a dynamic or pinned shortcut). If it is long lived, it can be cached by various
+         * system services even after it has been unpublished as a dynamic shortcut.
+         */
+        @NonNull
+        public Builder setLongLived() {
+            mIsLongLived = true;
+            return this;
+        }
+
+        /**
          * "Rank" of a shortcut, which is a non-negative value that's used by the launcher app
          * to sort shortcuts.
          *
@@ -1395,6 +1477,16 @@
     }
 
     /**
+     * Return the Persons set with {@link Builder#setPersons(Person[])}.
+     *
+     * @hide
+     */
+    @Nullable
+    public Person[] getPersons() {
+        return clonePersons(mPersons);
+    }
+
+    /**
      * The extras in the intents.  We convert extras into {@link PersistableBundle} so we can
      * persist them.
      * @hide
@@ -1525,6 +1617,16 @@
         addFlags(FLAG_RETURNED_BY_SERVICE);
     }
 
+    /** @hide */
+    public boolean isLongLived() {
+        return hasFlags(FLAG_LONG_LIVED);
+    }
+
+    /** @hide */
+    public void setLongLived() {
+        addFlags(FLAG_LONG_LIVED);
+    }
+
     /** Return whether a shortcut is dynamic. */
     public boolean isDynamic() {
         return hasFlags(FLAG_DYNAMIC);
@@ -1893,6 +1995,8 @@
                 mCategories.add(source.readString().intern());
             }
         }
+
+        mPersons = source.readParcelableArray(cl, Person.class);
     }
 
     @Override
@@ -1940,6 +2044,8 @@
         } else {
             dest.writeInt(0);
         }
+
+        dest.writeParcelableArray(mPersons, flags);
     }
 
     public static final Creator<ShortcutInfo> CREATOR =
@@ -2040,6 +2146,9 @@
         if (isReturnedByServer()) {
             sb.append("Rets");
         }
+        if (isLongLived()) {
+            sb.append("Liv");
+        }
         sb.append("]");
 
         addIndentOrComma(sb, indent);
@@ -2094,6 +2203,11 @@
 
         addIndentOrComma(sb, indent);
 
+        sb.append("persons=");
+        sb.append(mPersons);
+
+        addIndentOrComma(sb, indent);
+
         sb.append("icon=");
         sb.append(mIcon);
 
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 2d59003..4f7acd9 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -17,17 +17,22 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.annotation.UserIdInt;
 import android.app.usage.UsageStatsManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 
@@ -549,4 +554,85 @@
     protected int injectMyUserId() {
         return mContext.getUserId();
     }
+
+    /**
+     * Used by framework's ShareSheet (ChooserActivity.java) to retrieve all of the direct share
+     * targets that match the given IntentFilter.
+     *
+     * @param filter IntentFilter that will be used to retrieve the matching {@link ShortcutInfo}s.
+     * @return List of {@link ShareShortcutInfo}s that match the given IntentFilter.
+     * @hide
+     */
+    @NonNull
+    @SystemApi
+    public List<ShareShortcutInfo> getShareTargets(@NonNull IntentFilter filter) {
+        try {
+            return mService.getShareTargets(mContext.getPackageName(), filter,
+                    injectMyUserId()).getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Represents the result of a query return by {@link #getShareTargets(IntentFilter)}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class ShareShortcutInfo implements Parcelable {
+        private final ShortcutInfo mShortcutInfo;
+        private final ComponentName mTargetComponent;
+
+        /**
+         * @hide
+         */
+        public ShareShortcutInfo(@NonNull ShortcutInfo shortcutInfo,
+                @NonNull ComponentName targetComponent) {
+            if (shortcutInfo == null) {
+                throw new NullPointerException("shortcut info is null");
+            }
+            if (targetComponent == null) {
+                throw new NullPointerException("target component is null");
+            }
+
+            mShortcutInfo = shortcutInfo;
+            mTargetComponent = targetComponent;
+        }
+
+        private ShareShortcutInfo(Parcel in) {
+            mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader());
+            mTargetComponent = in.readParcelable(ComponentName.class.getClassLoader());
+        }
+
+        public ShortcutInfo getShortcutInfo() {
+            return mShortcutInfo;
+        }
+
+        public ComponentName getTargetComponent() {
+            return mTargetComponent;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeParcelable(mShortcutInfo, flags);
+            dest.writeParcelable(mTargetComponent, flags);
+        }
+
+        public static final Parcelable.Creator<ShareShortcutInfo> CREATOR =
+                new Parcelable.Creator<ShareShortcutInfo>() {
+                    public ShareShortcutInfo createFromParcel(Parcel in) {
+                        return new ShareShortcutInfo(in);
+                    }
+
+                    public ShareShortcutInfo[] newArray(int size) {
+                        return new ShareShortcutInfo[size];
+                    }
+                };
+    }
 }
diff --git a/core/java/android/content/pm/SuspendDialogInfo.java b/core/java/android/content/pm/SuspendDialogInfo.java
index c798c99..53b52f5 100644
--- a/core/java/android/content/pm/SuspendDialogInfo.java
+++ b/core/java/android/content/pm/SuspendDialogInfo.java
@@ -16,7 +16,7 @@
 
 package android.content.pm;
 
-import static android.content.res.ResourceId.ID_NULL;
+import static android.content.res.Resources.ID_NULL;
 
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index f1a4db2..9e0a9ba 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -732,6 +732,38 @@
         }
     }
 
+    /**
+     * Enable resource resolution logging to track the steps taken to resolve the last resource
+     * entry retrieved. Stores the configuration and package names for each step.
+     *
+     * Default disabled.
+     *
+     * @param enabled Boolean indicating whether to enable or disable logging.
+     *
+     * @hide
+     */
+    public void setResourceResolutionLoggingEnabled(boolean enabled) {
+        synchronized (this) {
+            ensureValidLocked();
+            nativeSetResourceResolutionLoggingEnabled(mObject, enabled);
+        }
+    }
+
+    /**
+     * Retrieve the last resource resolution path logged.
+     *
+     * @return Formatted string containing last resource ID/name and steps taken to resolve final
+     * entry, including configuration and package names.
+     *
+     * @hide
+     */
+    public @Nullable String getLastResourceResolution() {
+        synchronized (this) {
+            ensureValidLocked();
+            return nativeGetLastResourceResolution(mObject);
+        }
+    }
+
     CharSequence getPooledStringForCookie(int cookie, int id) {
         // Cookies map to ApkAssets starting at 1.
         return getApkAssets()[cookie - 1].getStringFromPool(id);
@@ -1383,6 +1415,8 @@
     private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid);
     private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem);
     private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr);
+    private static native void nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled);
+    private static native @Nullable String nativeGetLastResourceResolution(long ptr);
 
     // Style attribute retrieval native methods.
     private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr,
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 799f8e5..536a1b7 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -794,6 +794,7 @@
      * {@link ActivityInfo#CONFIG_ASSETS_PATHS}.
      * @hide
      */
+    @TestApi
     public int assetsSeq;
 
     /**
diff --git a/core/java/android/content/res/ResourceId.java b/core/java/android/content/res/ResourceId.java
index adb9cf1..3c7b5fc 100644
--- a/core/java/android/content/res/ResourceId.java
+++ b/core/java/android/content/res/ResourceId.java
@@ -22,12 +22,6 @@
  * @hide
  */
 public final class ResourceId {
-
-    /**
-     * The {@code null} resource ID.
-     */
-    public static final @AnyRes int ID_NULL = 0;
-
     /**
      * Checks whether the integer {@code id} is a valid resource ID, as generated by AAPT.
      * <p>Note that a negative integer is not necessarily an invalid resource ID, and custom
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 365ceac..baf64ad 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -98,6 +98,12 @@
  * href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.</p>
  */
 public class Resources {
+    /**
+     * The {@code null} resource ID. This denotes an invalid resource ID that is returned by the
+     * system when a resource is not found or the value is set to {@code @null} in XML.
+     */
+    public static final @AnyRes int ID_NULL = 0;
+
     static final String TAG = "Resources";
 
     private static final Object sSync = new Object();
@@ -168,7 +174,7 @@
     /** @hide */
     public static int selectSystemTheme(int curTheme, int targetSdkVersion, int orig, int holo,
             int dark, int deviceDefault) {
-        if (curTheme != ResourceId.ID_NULL) {
+        if (curTheme != ID_NULL) {
             return curTheme;
         }
         if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) {
@@ -2010,22 +2016,36 @@
     public String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
         return mResourcesImpl.getResourceTypeName(resid);
     }
-    
+
     /**
      * Return the entry name for a given resource identifier.
-     * 
+     *
      * @param resid The resource identifier whose entry name is to be
      * retrieved.
-     * 
+     *
      * @return A string holding the entry name of the resource.
-     * 
+     *
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
-     * 
+     *
      * @see #getResourceName
      */
     public String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
         return mResourcesImpl.getResourceEntryName(resid);
     }
+
+    /**
+     * Return formatted log of the last retrieved resource's resolution path.
+     *
+     * @return A string holding a formatted log of the steps taken to resolve the last resource.
+     *
+     * @throws NotFoundException Throws NotFoundException if there hasn't been a resource
+     * resolved yet.
+     *
+     * @hide
+     */
+    public String getLastResourceResolution() throws NotFoundException {
+        return mResourcesImpl.getLastResourceResolution();
+    }
     
     /**
      * Parse a series of {@link android.R.styleable#Extra &lt;extra&gt;} tags from
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 2ad4f62..d8564d5 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -299,6 +299,13 @@
     }
 
     @NonNull
+    String getLastResourceResolution() throws NotFoundException {
+        String str = mAssets.getLastResourceResolution();
+        if (str != null) return str;
+        throw new NotFoundException("Associated AssetManager hasn't resolved a resource");
+    }
+
+    @NonNull
     CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException {
         PluralRules rule = getPluralRule();
         CharSequence res = mAssets.getResourceBagText(id,
@@ -848,13 +855,9 @@
             try {
                 if (file.endsWith(".xml")) {
                     if (file.startsWith("res/color/")) {
-                        ColorStateList csl = loadColorStateList(wrapper, value, id, null);
-                        dr = (csl != null ? new ColorStateListDrawable(csl) : null);
+                        dr = loadColorOrXmlDrawable(wrapper, value, id, density, file);
                     } else {
-                        final XmlResourceParser rp = loadXmlResourceParser(
-                                file, id, value.assetCookie, "drawable");
-                        dr = Drawable.createFromXmlForDensity(wrapper, rp, density, null);
-                        rp.close();
+                        dr = loadXmlDrawable(wrapper, value, id, density, file);
                     }
                 } else {
                     final InputStream is = mAssets.openNonAsset(
@@ -908,6 +911,33 @@
         return dr;
     }
 
+    private Drawable loadColorOrXmlDrawable(@NonNull Resources wrapper, @NonNull TypedValue value,
+            int id, int density, String file) {
+        try {
+            ColorStateList csl = loadColorStateList(wrapper, value, id, null);
+            return new ColorStateListDrawable(csl);
+        } catch (NotFoundException originalException) {
+            // If we fail to load as color, try as normal XML drawable
+            try {
+                return loadXmlDrawable(wrapper, value, id, density, file);
+            } catch (Exception ignored) {
+                // If fallback also fails, throw the original exception
+                throw originalException;
+            }
+        }
+    }
+
+    private Drawable loadXmlDrawable(@NonNull Resources wrapper, @NonNull TypedValue value,
+            int id, int density, String file)
+            throws IOException, XmlPullParserException {
+        try (
+                XmlResourceParser rp =
+                        loadXmlResourceParser(file, id, value.assetCookie, "drawable")
+        ) {
+            return Drawable.createFromXmlForDensity(wrapper, rp, density, null);
+        }
+    }
+
     /**
      * Loads a font from XML or resources stream.
      */
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 508626b..d53834c 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -19,6 +19,7 @@
 import android.annotation.AnyRes;
 import android.annotation.ColorInt;
 import android.annotation.Nullable;
+import android.annotation.StyleRes;
 import android.annotation.StyleableRes;
 import android.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo;
@@ -63,13 +64,15 @@
     }
 
     // STYLE_ prefixed constants are offsets within the typed data array.
-    static final int STYLE_NUM_ENTRIES = 6;
+    // Keep this in sync with libs/androidfw/include/androidfw/AttributeResolution.h
+    static final int STYLE_NUM_ENTRIES = 7;
     static final int STYLE_TYPE = 0;
     static final int STYLE_DATA = 1;
     static final int STYLE_ASSET_COOKIE = 2;
     static final int STYLE_RESOURCE_ID = 3;
     static final int STYLE_CHANGING_CONFIGURATIONS = 4;
     static final int STYLE_DENSITY = 5;
+    static final int SYTLE_SOURCE_STYLE_RESOURCE_ID = 6;
 
     @UnsupportedAppUsage
     private final Resources mResources;
@@ -1098,6 +1101,31 @@
     }
 
     /**
+     * Returns the resource ID of the style against which the specified attribute was resolved,
+     * otherwise returns defValue.
+     *
+     * @param index Index of attribute whose source style to retrieve.
+     * @param defValue Value to return if the attribute is not defined or
+     *                 not a resource.
+     *
+     * @return Attribute source style resource ID or defValue if it was not resolved in any style.
+     * @throws RuntimeException if the TypedArray has already been recycled.
+     */
+    @StyleRes
+    public int getSourceStyleResourceId(@StyleableRes int index, @StyleRes int defValue) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
+        index *= STYLE_NUM_ENTRIES;
+        final int resid = mData[index + SYTLE_SOURCE_STYLE_RESOURCE_ID];
+        if (resid != 0) {
+            return resid;
+        }
+        return defValue;
+    }
+
+    /**
      * Determines whether there is an attribute at <var>index</var>.
      * <p>
      * <strong>Note:</strong> If the attribute was set to {@code @empty} or
@@ -1309,6 +1337,7 @@
                 data[index + STYLE_CHANGING_CONFIGURATIONS]);
         outValue.density = data[index + STYLE_DENSITY];
         outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
+        outValue.sourceStyleResourceId = data[index + SYTLE_SOURCE_STYLE_RESOURCE_ID];
         return true;
     }
 
diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl
index 7f557cd..420bcb6 100644
--- a/core/java/android/content/rollback/IRollbackManager.aidl
+++ b/core/java/android/content/rollback/IRollbackManager.aidl
@@ -33,6 +33,12 @@
     void executeRollback(in RollbackInfo rollback, String callerPackageName,
             in IntentSender statusReceiver);
 
+    // Exposed for use from the system server only. Callback from the package
+    // manager during the install flow when user data can be restored for a given
+    // package.
+    void restoreUserData(String packageName, int userId, int appId, long ceDataInode,
+            String seInfo, int token);
+
     // Exposed for test purposes only.
     void reloadPersistedData();
 
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 0c05765..4644a83 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -16,72 +16,53 @@
 
 package android.content.rollback;
 
-import android.annotation.TestApi;
+import android.annotation.SystemApi;
+import android.content.pm.VersionedPackage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Objects;
-
 /**
  * Information about a rollback available for a particular package.
  *
- * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi.
+ * @hide
  */
-@TestApi
+@SystemApi
 public final class PackageRollbackInfo implements Parcelable {
-    /**
-     * The name of a package being rolled back.
-     */
-    public final String packageName;
+
+    private final VersionedPackage mVersionRolledBackFrom;
+    private final VersionedPackage mVersionRolledBackTo;
 
     /**
-     * The version the package was rolled back from.
+     * Returns the name of the package to roll back from.
      */
-    public final PackageVersion higherVersion;
-
-    /**
-     * The version the package was rolled back to.
-     */
-    public final PackageVersion lowerVersion;
-
-    /**
-     * Represents a version of a package.
-     */
-    public static class PackageVersion {
-        public final long versionCode;
-
-        // TODO(b/120200473): Include apk sha or some other way to distinguish
-        // between two different apks with the same version code.
-        public PackageVersion(long versionCode) {
-            this.versionCode = versionCode;
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            if (other instanceof PackageVersion)  {
-                PackageVersion otherVersion = (PackageVersion) other;
-                return versionCode == otherVersion.versionCode;
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(versionCode);
-        }
+    public String getPackageName() {
+        return mVersionRolledBackFrom.getPackageName();
     }
 
-    public PackageRollbackInfo(String packageName,
-            PackageVersion higherVersion, PackageVersion lowerVersion) {
-        this.packageName = packageName;
-        this.higherVersion = higherVersion;
-        this.lowerVersion = lowerVersion;
+    /**
+     * Returns the version of the package rolled back from.
+     */
+    public VersionedPackage getVersionRolledBackFrom() {
+        return mVersionRolledBackFrom;
+    }
+
+    /**
+     * Returns the version of the package rolled back to.
+     */
+    public VersionedPackage getVersionRolledBackTo() {
+        return mVersionRolledBackTo;
+    }
+
+    /** @hide */
+    public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
+            VersionedPackage packageRolledBackTo) {
+        this.mVersionRolledBackFrom = packageRolledBackFrom;
+        this.mVersionRolledBackTo = packageRolledBackTo;
     }
 
     private PackageRollbackInfo(Parcel in) {
-        this.packageName = in.readString();
-        this.higherVersion = new PackageVersion(in.readLong());
-        this.lowerVersion = new PackageVersion(in.readLong());
+        this.mVersionRolledBackFrom = VersionedPackage.CREATOR.createFromParcel(in);
+        this.mVersionRolledBackTo = VersionedPackage.CREATOR.createFromParcel(in);
     }
 
     @Override
@@ -91,9 +72,8 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
-        out.writeString(packageName);
-        out.writeLong(higherVersion.versionCode);
-        out.writeLong(lowerVersion.versionCode);
+        mVersionRolledBackFrom.writeToParcel(out, flags);
+        mVersionRolledBackTo.writeToParcel(out, flags);
     }
 
     public static final Parcelable.Creator<PackageRollbackInfo> CREATOR =
diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java
index 5fa4e57..0803a7c 100644
--- a/core/java/android/content/rollback/RollbackInfo.java
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -16,7 +16,7 @@
 
 package android.content.rollback;
 
-import android.annotation.TestApi;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -24,12 +24,17 @@
  * Information about a set of packages that can be, or already have been
  * rolled back together.
  *
- * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi.
+ * @hide
  */
-@TestApi
+@SystemApi
 public final class RollbackInfo implements Parcelable {
 
     /**
+     * A unique identifier for the rollback.
+     */
+    private final int mRollbackId;
+
+    /**
      * The package that needs to be rolled back.
      */
     public final PackageRollbackInfo targetPackage;
@@ -39,12 +44,22 @@
     // TODO: Add a flag to indicate if reboot is required, when rollback of
     // staged installs is supported.
 
-    public RollbackInfo(PackageRollbackInfo targetPackage) {
+    /** @hide */
+    public RollbackInfo(int rollbackId, PackageRollbackInfo targetPackage) {
+        this.mRollbackId = rollbackId;
         this.targetPackage = targetPackage;
     }
 
     private RollbackInfo(Parcel in) {
-        this.targetPackage = PackageRollbackInfo.CREATOR.createFromParcel(in);
+        mRollbackId = in.readInt();
+        targetPackage = PackageRollbackInfo.CREATOR.createFromParcel(in);
+    }
+
+    /**
+     * Returns a unique identifier for this rollback.
+     */
+    public int getRollbackId() {
+        return mRollbackId;
     }
 
     @Override
@@ -54,6 +69,7 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mRollbackId);
         targetPackage.writeToParcel(out, flags);
     }
 
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 294151a..c1c0bc1 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -18,8 +18,9 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.TestApi;
 import android.content.Context;
 import android.content.IntentSender;
 import android.os.RemoteException;
@@ -33,12 +34,10 @@
  * used to initiate rollback of those packages for a limited time period after
  * upgrade.
  *
- * TODO: Require an appropriate permission for apps to use these APIs.
- *
  * @see PackageInstaller.SessionParams#setEnableRollback()
- * @hide TODO: hidden, @TestApi until we decide on public vs. @SystemApi.
+ * @hide
  */
-@TestApi
+@SystemApi
 @SystemService(Context.ROLLBACK_SERVICE)
 public final class RollbackManager {
     private final String mCallerPackageName;
@@ -63,7 +62,10 @@
      * @param packageName name of the package to get the availble RollbackInfo for.
      * @return the rollback available for the package, or null if no rollback
      *         is available for the package.
+     * @throws SecurityException if the caller does not have the
+     *            MANAGE_ROLLBACKS permission.
      */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
     public @Nullable RollbackInfo getAvailableRollback(@NonNull String packageName) {
         try {
             return mBinder.getAvailableRollback(packageName);
@@ -78,7 +80,10 @@
      * about the rollback available for a particular package.
      *
      * @return the names of packages that are available for rollback.
+     * @throws SecurityException if the caller does not have the
+     *            MANAGE_ROLLBACKS permission.
      */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
     public @NonNull List<String> getPackagesWithAvailableRollbacks() {
         try {
             return mBinder.getPackagesWithAvailableRollbacks().getList();
@@ -103,7 +108,10 @@
      * rolled back from.
      *
      * @return the recently executed rollbacks
+     * @throws SecurityException if the caller does not have the
+     *            MANAGE_ROLLBACKS permission.
      */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
     public @NonNull List<RollbackInfo> getRecentlyExecutedRollbacks() {
         try {
             return mBinder.getRecentlyExecutedRollbacks().getList();
@@ -127,7 +135,10 @@
      *
      * @param rollback to execute
      * @param statusReceiver where to deliver the results
+     * @throws SecurityException if the caller does not have the
+     *            MANAGE_ROLLBACKS permission.
      */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
     public void executeRollback(@NonNull RollbackInfo rollback,
             @NonNull IntentSender statusReceiver) {
         try {
@@ -143,9 +154,10 @@
      * across device reboot, by simulating what happens on reboot without
      * actually rebooting the device.
      *
-     * @hide
+     * @throws SecurityException if the caller does not have the
+     *            MANAGE_ROLLBACKS permission.
      */
-    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
     public void reloadPersistedData() {
         try {
             mBinder.reloadPersistedData();
@@ -160,10 +172,10 @@
      * expiring rollback data.
      *
      * @param packageName the name of the package to expire data for.
-     *
-     * @hide
+     * @throws SecurityException if the caller does not have the
+     *            MANAGE_ROLLBACKS permission.
      */
-    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
     public void expireRollbackForPackage(@NonNull String packageName) {
         try {
             mBinder.expireRollbackForPackage(packageName);
diff --git a/core/java/android/database/TranslatingCursor.java b/core/java/android/database/TranslatingCursor.java
index 58e65b2..d9165b4 100644
--- a/core/java/android/database/TranslatingCursor.java
+++ b/core/java/android/database/TranslatingCursor.java
@@ -39,28 +39,29 @@
 public class TranslatingCursor extends CrossProcessCursorWrapper {
     public static class Config {
         public final Uri baseUri;
-        public final String idColumn;
-        public final String[] filePathColumns;
+        public final String auxiliaryColumn;
+        public final String[] translateColumns;
 
-        public Config(Uri baseUri, String idColumn, String... filePathColumns) {
+        public Config(Uri baseUri, String auxiliaryColumn, String... translateColumns) {
             this.baseUri = baseUri;
-            this.idColumn = idColumn;
-            this.filePathColumns = filePathColumns;
+            this.auxiliaryColumn = auxiliaryColumn;
+            this.translateColumns = translateColumns;
         }
     }
 
     public interface Translator {
-        String translate(String data, long id);
+        String translate(String data, int auxiliaryColumnIndex,
+                String matchingColumn, Cursor cursor);
     }
 
     private final @NonNull Config mConfig;
     private final @NonNull Translator mTranslator;
     private final boolean mDropLast;
 
-    private final int mIdIndex;
-    private final int[] mFilePathColIndices;
+    private final int mAuxiliaryColumnIndex;
+    private final int[] mTranslateColumnIndices;
 
-    private TranslatingCursor(@NonNull Cursor cursor, @NonNull Config config,
+    public TranslatingCursor(@NonNull Cursor cursor, @NonNull Config config,
             @NonNull Translator translator, boolean dropLast) {
         super(cursor);
 
@@ -68,10 +69,10 @@
         mTranslator = Objects.requireNonNull(translator);
         mDropLast = dropLast;
 
-        mIdIndex = cursor.getColumnIndexOrThrow(config.idColumn);
-        mFilePathColIndices = new int[config.filePathColumns.length];
-        for (int i = mFilePathColIndices.length - 1; i >= 0; --i) {
-            mFilePathColIndices[i] = cursor.getColumnIndex(config.filePathColumns[i]);
+        mAuxiliaryColumnIndex = cursor.getColumnIndexOrThrow(config.auxiliaryColumn);
+        mTranslateColumnIndices = new int[config.translateColumns.length];
+        for (int i = 0; i < mTranslateColumnIndices.length; ++i) {
+            mTranslateColumnIndices[i] = cursor.getColumnIndex(config.translateColumns[i]);
         }
     }
 
@@ -97,26 +98,27 @@
             SQLiteQueryBuilder qb, SQLiteDatabase db, String[] projectionIn, String selection,
             String[] selectionArgs, String groupBy, String having, String sortOrder, String limit,
             CancellationSignal signal) {
-        final boolean requestedId = ArrayUtils.isEmpty(projectionIn)
-                || ArrayUtils.contains(projectionIn, config.idColumn);
-        final boolean requestedData = ArrayUtils.isEmpty(projectionIn)
-                || ArrayUtils.containsAny(projectionIn, config.filePathColumns);
+        final boolean requestedAuxiliaryColumn = ArrayUtils.isEmpty(projectionIn)
+                || ArrayUtils.contains(projectionIn, config.auxiliaryColumn);
+        final boolean requestedTranslateColumns = ArrayUtils.isEmpty(projectionIn)
+                || ArrayUtils.containsAny(projectionIn, config.translateColumns);
 
-        // If caller didn't request data, we have nothing to redirect
-        if (!requestedData || !ContentResolver.DEPRECATE_DATA_COLUMNS) {
+        // If caller didn't request any columns that need to be translated,
+        // we have nothing to redirect
+        if (!requestedTranslateColumns) {
             return qb.query(db, projectionIn, selection, selectionArgs,
                     groupBy, having, sortOrder, limit, signal);
         }
 
-        // If caller didn't request id, we need to splice it in
-        if (!requestedId) {
+        // If caller didn't request auxiliary column, we need to splice it in
+        if (!requestedAuxiliaryColumn) {
             projectionIn = ArrayUtils.appendElement(String.class, projectionIn,
-                    config.idColumn);
+                    config.auxiliaryColumn);
         }
 
         final Cursor c = qb.query(db, projectionIn, selection, selectionArgs,
                 groupBy, having, sortOrder);
-        return new TranslatingCursor(c, config, translator, !requestedId);
+        return new TranslatingCursor(c, config, translator, !requestedAuxiliaryColumn);
     }
 
     @Override
@@ -139,7 +141,7 @@
 
     @Override
     public double getDouble(int columnIndex) {
-        if (ArrayUtils.contains(mFilePathColIndices, columnIndex)) {
+        if (ArrayUtils.contains(mTranslateColumnIndices, columnIndex)) {
             throw new IllegalArgumentException();
         } else {
             return super.getDouble(columnIndex);
@@ -148,7 +150,7 @@
 
     @Override
     public float getFloat(int columnIndex) {
-        if (ArrayUtils.contains(mFilePathColIndices, columnIndex)) {
+        if (ArrayUtils.contains(mTranslateColumnIndices, columnIndex)) {
             throw new IllegalArgumentException();
         } else {
             return super.getFloat(columnIndex);
@@ -157,7 +159,7 @@
 
     @Override
     public int getInt(int columnIndex) {
-        if (ArrayUtils.contains(mFilePathColIndices, columnIndex)) {
+        if (ArrayUtils.contains(mTranslateColumnIndices, columnIndex)) {
             throw new IllegalArgumentException();
         } else {
             return super.getInt(columnIndex);
@@ -166,7 +168,7 @@
 
     @Override
     public long getLong(int columnIndex) {
-        if (ArrayUtils.contains(mFilePathColIndices, columnIndex)) {
+        if (ArrayUtils.contains(mTranslateColumnIndices, columnIndex)) {
             throw new IllegalArgumentException();
         } else {
             return super.getLong(columnIndex);
@@ -175,7 +177,7 @@
 
     @Override
     public short getShort(int columnIndex) {
-        if (ArrayUtils.contains(mFilePathColIndices, columnIndex)) {
+        if (ArrayUtils.contains(mTranslateColumnIndices, columnIndex)) {
             throw new IllegalArgumentException();
         } else {
             return super.getShort(columnIndex);
@@ -184,8 +186,9 @@
 
     @Override
     public String getString(int columnIndex) {
-        if (ArrayUtils.contains(mFilePathColIndices, columnIndex)) {
-            return mTranslator.translate(super.getString(columnIndex), super.getLong(mIdIndex));
+        if (ArrayUtils.contains(mTranslateColumnIndices, columnIndex)) {
+            return mTranslator.translate(super.getString(columnIndex),
+                    mAuxiliaryColumnIndex, getColumnName(columnIndex), this);
         } else {
             return super.getString(columnIndex);
         }
@@ -193,7 +196,7 @@
 
     @Override
     public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
-        if (ArrayUtils.contains(mFilePathColIndices, columnIndex)) {
+        if (ArrayUtils.contains(mTranslateColumnIndices, columnIndex)) {
             throw new IllegalArgumentException();
         } else {
             super.copyStringToBuffer(columnIndex, buffer);
@@ -202,7 +205,7 @@
 
     @Override
     public byte[] getBlob(int columnIndex) {
-        if (ArrayUtils.contains(mFilePathColIndices, columnIndex)) {
+        if (ArrayUtils.contains(mTranslateColumnIndices, columnIndex)) {
             throw new IllegalArgumentException();
         } else {
             return super.getBlob(columnIndex);
@@ -211,7 +214,7 @@
 
     @Override
     public int getType(int columnIndex) {
-        if (ArrayUtils.contains(mFilePathColIndices, columnIndex)) {
+        if (ArrayUtils.contains(mTranslateColumnIndices, columnIndex)) {
             return Cursor.FIELD_TYPE_STRING;
         } else {
             return super.getType(columnIndex);
@@ -220,7 +223,7 @@
 
     @Override
     public boolean isNull(int columnIndex) {
-        if (ArrayUtils.contains(mFilePathColIndices, columnIndex)) {
+        if (ArrayUtils.contains(mTranslateColumnIndices, columnIndex)) {
             return getString(columnIndex) == null;
         } else {
             return super.isNull(columnIndex);
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index eb3414d..8aac1bf 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -42,13 +42,13 @@
     /**
      * The hardware is unavailable. Try again later.
      */
-    public static final int BIOMETRIC_ERROR_UNAVAILABLE =
+    public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE =
             BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;
 
     /**
      * The user does not have any biometrics enrolled.
      */
-    public static final int BIOMETRIC_ERROR_NO_BIOMETRICS =
+    public static final int BIOMETRIC_ERROR_NONE_ENROLLED =
             BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS;
 
     /**
@@ -58,8 +58,8 @@
             BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT;
 
     @IntDef({BIOMETRIC_SUCCESS,
-            BIOMETRIC_ERROR_UNAVAILABLE,
-            BIOMETRIC_ERROR_NO_BIOMETRICS,
+            BIOMETRIC_ERROR_HW_UNAVAILABLE,
+            BIOMETRIC_ERROR_NONE_ENROLLED,
             BIOMETRIC_ERROR_NO_HARDWARE})
     @interface BiometricError {}
 
@@ -95,8 +95,8 @@
      * Determine if biometrics can be used. In other words, determine if {@link BiometricPrompt}
      * can be expected to be shown (hardware available, templates enrolled, user-enabled).
      *
-     * @return Returns {@link #BIOMETRIC_ERROR_NO_BIOMETRICS} if the user does not have any
-     *     enrolled, or {@link #BIOMETRIC_ERROR_UNAVAILABLE} if none are currently
+     * @return Returns {@link #BIOMETRIC_ERROR_NONE_ENROLLED} if the user does not have any
+     *     enrolled, or {@link #BIOMETRIC_ERROR_HW_UNAVAILABLE} if none are currently
      *     supported/enabled. Returns {@link #BIOMETRIC_SUCCESS} if a biometric can currently be
      *     used (enrolled and available).
      */
@@ -113,7 +113,7 @@
                 return BIOMETRIC_ERROR_NO_HARDWARE;
             } else {
                 Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
-                return BIOMETRIC_ERROR_UNAVAILABLE;
+                return BIOMETRIC_ERROR_HW_UNAVAILABLE;
             }
         }
     }
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index b238d77..c69b68e4 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -73,6 +73,10 @@
      * @hide
      */
     public static final String KEY_NEGATIVE_TEXT = "negative_text";
+    /**
+     * @hide
+     */
+    public static final String KEY_REQUIRE_CONFIRMATION = "require_confirmation";
 
     /**
      * Error/help message will show for this amount of time.
@@ -215,6 +219,29 @@
         }
 
         /**
+         * Optional: A hint to the system to require user confirmation after a biometric has been
+         * authenticated. For example, implicit modalities like Face and Iris authentication are
+         * passive, meaning they don't require an explicit user action to complete. When set to
+         * 'false', the user action (e.g. pressing a button) will not be required. BiometricPrompt
+         * will require confirmation by default.
+         *
+         * A typical use case for not requiring confirmation would be for low-risk transactions,
+         * such as re-authenticating a recently authenticated application. A typical use case for
+         * requiring confirmation would be for authorizing a purchase.
+         *
+         * Note that this is a hint to the system. The system may choose to ignore the flag. For
+         * example, if the user disables implicit authentication in Settings, or if it does not
+         * apply to a modality (e.g. Fingerprint). When ignored, the system will default to
+         * requiring confirmation.
+         *
+         * @param requireConfirmation
+         */
+        public Builder setRequireConfirmation(boolean requireConfirmation) {
+            mBundle.putBoolean(KEY_REQUIRE_CONFIRMATION, requireConfirmation);
+            return this;
+        }
+
+        /**
          * Creates a {@link BiometricPrompt}.
          * @return a {@link BiometricPrompt}
          * @throws IllegalArgumentException if any of the required fields are not set.
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 105ae68..9758308 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3722,12 +3722,12 @@
 
     /**
      * <p>String containing the ids of the underlying physical cameras.</p>
-     * <p>For a logical camera, this is concatenation of all underlying physical camera ids.
-     * The null terminator for physical camera id must be preserved so that the whole string
-     * can be tokenized using '\0' to generate list of physical camera ids.</p>
-     * <p>For example, if the physical camera ids of the logical camera are "2" and "3", the
+     * <p>For a logical camera, this is concatenation of all underlying physical camera IDs.
+     * The null terminator for physical camera ID must be preserved so that the whole string
+     * can be tokenized using '\0' to generate list of physical camera IDs.</p>
+     * <p>For example, if the physical camera IDs of the logical camera are "2" and "3", the
      * value of this tag will be ['2', '\0', '3', '\0'].</p>
-     * <p>The number of physical camera ids must be no less than 2.</p>
+     * <p>The number of physical camera IDs must be no less than 2.</p>
      * <p><b>Units</b>: UTF-8 null-terminated string</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 402472a..6302aa5 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -428,6 +428,10 @@
      * <p>If this is supported, {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} will
      * additionally return a min frame duration that is greater than
      * zero for each supported size-format combination.</p>
+     * <p>For camera devices with LOGICAL_MULTI_CAMERA capability, when the underlying active
+     * physical camera switches, exposureTime, sensitivity, and lens properties may change
+     * even if AE/AF is locked. However, the overall auto exposure and auto focus experience
+     * for users will be consistent. Refer to LOGICAL_MULTI_CAMERA capability for details.</p>
      *
      * @see CaptureRequest#BLACK_LEVEL_LOCK
      * @see CaptureRequest#CONTROL_AE_LOCK
@@ -485,6 +489,10 @@
      * will accurately report the values applied by AWB in the result.</p>
      * <p>A given camera device may also support additional post-processing
      * controls, but this capability only covers the above list of controls.</p>
+     * <p>For camera devices with LOGICAL_MULTI_CAMERA capability, when underlying active
+     * physical camera switches, tonemap, white balance, and shading map may change even if
+     * awb is locked. However, the overall post-processing experience for users will be
+     * consistent. Refer to LOGICAL_MULTI_CAMERA capability for details.</p>
      *
      * @see CaptureRequest#COLOR_CORRECTION_ABERRATION_MODE
      * @see CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES
@@ -847,7 +855,7 @@
      * </li>
      * <li>The SENSOR_INFO_TIMESTAMP_SOURCE of the logical device and physical devices must be
      *   the same.</li>
-     * <li>The logical camera device must be LIMITED or higher device.</li>
+     * <li>The logical camera must be LIMITED or higher device.</li>
      * </ul>
      * <p>Both the logical camera device and its underlying physical devices support the
      * mandatory stream combinations required for their device levels.</p>
@@ -867,13 +875,84 @@
      * <p>Using physical streams in place of a logical stream of the same size and format will
      * not slow down the frame rate of the capture, as long as the minimum frame duration
      * of the physical and logical streams are the same.</p>
+     * <p>A logical camera device's dynamic metadata may contain
+     * {@link CaptureResult#LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID android.logicalMultiCamera.activePhysicalId} to notify the application of the current
+     * active physical camera Id. An active physical camera is the physical camera from which
+     * the logical camera's main image data outputs (YUV or RAW) and metadata come from.
+     * In addition, this serves as an indication which physical camera is used to output to
+     * a RAW stream, or in case only physical cameras support RAW, which physical RAW stream
+     * the application should request.</p>
+     * <p>Logical camera's static metadata tags below describe the default active physical
+     * camera. An active physical camera is default if it's used when application directly
+     * uses requests built from a template. All templates will default to the same active
+     * physical camera.</p>
+     * <ul>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT android.sensor.info.colorFilterArrangement}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE android.sensor.info.exposureTimeRange}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE android.sensor.info.physicalSize}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL android.sensor.info.whiteLevel}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1 android.sensor.referenceIlluminant1}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2 android.sensor.referenceIlluminant2}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM1 android.sensor.calibrationTransform1}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM2 android.sensor.calibrationTransform2}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_COLOR_TRANSFORM1 android.sensor.colorTransform1}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_COLOR_TRANSFORM2 android.sensor.colorTransform2}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_FORWARD_MATRIX1 android.sensor.forwardMatrix1}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_FORWARD_MATRIX2 android.sensor.forwardMatrix2}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN android.sensor.blackLevelPattern}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_MAX_ANALOG_SENSITIVITY android.sensor.maxAnalogSensitivity}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_OPTICAL_BLACK_REGIONS android.sensor.opticalBlackRegions}</li>
+     * <li>{@link CameraCharacteristics#SENSOR_AVAILABLE_TEST_PATTERN_MODES android.sensor.availableTestPatternModes}</li>
+     * <li>{@link CameraCharacteristics#LENS_INFO_HYPERFOCAL_DISTANCE android.lens.info.hyperfocalDistance}</li>
+     * <li>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance}</li>
+     * <li>{@link CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION android.lens.info.focusDistanceCalibration}</li>
+     * <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
+     * <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
+     * <li>{@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}</li>
+     * <li>{@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference}</li>
+     * <li>{@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}</li>
+     * </ul>
+     * <p>To maintain backward compatibility, the capture request and result metadata tags
+     * required for basic camera functionalities will be solely based on the
+     * logical camera capabiltity. Other request and result metadata tags, on the other
+     * hand, will be based on current active physical camera. For example, the physical
+     * cameras' sensor sensitivity and lens capability could be different from each other.
+     * So when the application manually controls sensor exposure time/gain, or does manual
+     * focus control, it must checks the current active physical camera's exposure, gain,
+     * and focus distance range.</p>
      *
      * @see CameraCharacteristics#LENS_DISTORTION
+     * @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
+     * @see CameraCharacteristics#LENS_INFO_HYPERFOCAL_DISTANCE
+     * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
      * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      * @see CameraCharacteristics#LENS_POSE_REFERENCE
      * @see CameraCharacteristics#LENS_POSE_ROTATION
      * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see CaptureResult#LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID
      * @see CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
+     * @see CameraCharacteristics#SENSOR_AVAILABLE_TEST_PATTERN_MODES
+     * @see CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN
+     * @see CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM1
+     * @see CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM2
+     * @see CameraCharacteristics#SENSOR_COLOR_TRANSFORM1
+     * @see CameraCharacteristics#SENSOR_COLOR_TRANSFORM2
+     * @see CameraCharacteristics#SENSOR_FORWARD_MATRIX1
+     * @see CameraCharacteristics#SENSOR_FORWARD_MATRIX2
+     * @see CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
+     * @see CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE
+     * @see CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED
+     * @see CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION
+     * @see CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE
+     * @see CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE
+     * @see CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL
+     * @see CameraCharacteristics#SENSOR_MAX_ANALOG_SENSITIVITY
+     * @see CameraCharacteristics#SENSOR_OPTICAL_BLACK_REGIONS
+     * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
+     * @see CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA = 11;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 8ebaf2f..5f05cfb 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2146,7 +2146,6 @@
     /**
      * <p>32 characters describing GPS algorithm to
      * include in EXIF.</p>
-     * <p><b>Units</b>: UTF-8 null-terminated string</p>
      * <p>This key is available on all devices.</p>
      * @hide
      */
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 3d70c51..585c597 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2470,7 +2470,6 @@
     /**
      * <p>32 characters describing GPS algorithm to
      * include in EXIF.</p>
-     * <p><b>Units</b>: UTF-8 null-terminated string</p>
      * <p>This key is available on all devices.</p>
      * @hide
      */
@@ -4638,6 +4637,23 @@
             new Key<Float>("android.reprocess.effectiveExposureFactor", float.class);
 
     /**
+     * <p>String containing the ID of the underlying active physical camera.</p>
+     * <p>The ID of the active physical camera that's backing the logical camera. All camera
+     * streams and metadata that are not physical camera specific will be originating from this
+     * physical camera. This must be one of valid physical IDs advertised in the physicalIds
+     * static tag.</p>
+     * <p>For a logical camera made up of physical cameras where each camera's lenses have
+     * different characteristics, the camera device may choose to switch between the physical
+     * cameras when application changes FOCAL_LENGTH or SCALER_CROP_REGION.
+     * At the time of lens switch, this result metadata reflects the new active physical camera
+     * ID.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     */
+    @PublicKey
+    public static final Key<String> LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID =
+            new Key<String>("android.logicalMultiCamera.activePhysicalId", String.class);
+
+    /**
      * <p>Mode of operation for the lens distortion correction block.</p>
      * <p>The lens distortion correction block attempts to improve image quality by fixing
      * radial, tangential, or other geometric aberrations in the camera device's optics.  If
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index be054297..8c74ddc 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -91,9 +91,7 @@
      *
      * @return The matching brightness correction, or null.
      *
-     * @hide
      */
-    @SystemApi
     @Nullable
     public BrightnessCorrection getCorrectionByPackageName(String packageName) {
         return mCorrectionsByPackageName.get(packageName);
@@ -106,10 +104,7 @@
      *      The app category.
      *
      * @return The matching brightness correction, or null.
-     *
-     * @hide
      */
-    @SystemApi
     @Nullable
     public BrightnessCorrection getCorrectionByCategory(int category) {
         return mCorrectionsByCategory.get(category);
@@ -416,9 +411,7 @@
          *
          * @return The maximum number of corrections by package name allowed.
          *
-         * @hide
          */
-        @SystemApi
         public int getMaxCorrectionsByPackageName() {
             return MAX_CORRECTIONS_BY_PACKAGE_NAME;
         }
@@ -428,9 +421,7 @@
          *
          * @return The maximum number of corrections by category allowed.
          *
-         * @hide
          */
-        @SystemApi
         public int getMaxCorrectionsByCategory() {
             return MAX_CORRECTIONS_BY_CATEGORY;
         }
@@ -451,9 +442,7 @@
          *      Maximum number of corrections by package name exceeded (see
          *      {@link #getMaxCorrectionsByPackageName}).
          *
-         * @hide
          */
-        @SystemApi
         public Builder addCorrectionByPackageName(String packageName,
                 BrightnessCorrection correction) {
             if (mCorrectionsByPackageName.size() >= getMaxCorrectionsByPackageName()) {
@@ -479,9 +468,7 @@
          *      Maximum number of corrections by category exceeded (see
          *      {@link #getMaxCorrectionsByCategory}).
          *
-         * @hide
          */
-        @SystemApi
         public Builder addCorrectionByCategory(@ApplicationInfo.Category int category,
                 BrightnessCorrection correction) {
             if (mCorrectionsByCategory.size() >= getMaxCorrectionsByCategory()) {
@@ -504,8 +491,6 @@
 
         /**
          * Builds the {@link BrightnessConfiguration}.
-         *
-         * A brightness curve <b>must</b> be set before calling this.
          */
         public BrightnessConfiguration build() {
             if (mCurveLux == null || mCurveNits == null) {
diff --git a/core/java/android/hardware/display/BrightnessCorrection.java b/core/java/android/hardware/display/BrightnessCorrection.java
index c4e0e3b..6a073ff 100644
--- a/core/java/android/hardware/display/BrightnessCorrection.java
+++ b/core/java/android/hardware/display/BrightnessCorrection.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.MathUtils;
@@ -41,6 +42,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public final class BrightnessCorrection implements Parcelable {
 
     private static final int SCALE_AND_TRANSLATE_LOG = 1;
@@ -98,6 +100,24 @@
         return mImplementation.toString();
     }
 
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (!(o instanceof BrightnessCorrection)) {
+            return false;
+        }
+        BrightnessCorrection other = (BrightnessCorrection) o;
+        return other.mImplementation.equals(mImplementation);
+    }
+
+    @Override
+    public int hashCode() {
+        return mImplementation.hashCode();
+    }
+
     public static final Creator<BrightnessCorrection> CREATOR =
             new Creator<BrightnessCorrection>() {
                 public BrightnessCorrection createFromParcel(Parcel in) {
@@ -215,6 +235,26 @@
         }
 
         @Override
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+            if (!(o instanceof ScaleAndTranslateLog)) {
+                return false;
+            }
+            ScaleAndTranslateLog other = (ScaleAndTranslateLog) o;
+            return other.mScale == mScale && other.mTranslate == mTranslate;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 1;
+            result = result * 31 + Float.hashCode(mScale);
+            result = result * 31 + Float.hashCode(mTranslate);
+            return result;
+        }
+
+        @Override
         public void writeToParcel(Parcel dest) {
             dest.writeInt(SCALE_AND_TRANSLATE_LOG);
             dest.writeFloat(mScale);
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index dd782ec..fa335c8 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -16,7 +16,12 @@
 
 package android.hardware.display;
 
+import android.Manifest;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.os.IBinder;
@@ -26,14 +31,56 @@
 
 import com.android.internal.R;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Manages the display's color transforms and modes.
  *
  * @hide
  */
+@SystemApi
 @SystemService(Context.COLOR_DISPLAY_SERVICE)
 public final class ColorDisplayManager {
 
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({CAPABILITY_NONE, CAPABILITY_PROTECTED_CONTENT, CAPABILITY_HARDWARE_ACCELERATION_GLOBAL,
+            CAPABILITY_HARDWARE_ACCELERATION_PER_APP})
+    public @interface CapabilityType {}
+
+    /**
+     * The device does not support color transforms.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int CAPABILITY_NONE = 0x0;
+    /**
+     * The device can properly apply transforms over protected content.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int CAPABILITY_PROTECTED_CONTENT = 0x1;
+    /**
+     * The device's hardware can efficiently apply transforms to the entire display.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int CAPABILITY_HARDWARE_ACCELERATION_GLOBAL = 0x2;
+    /**
+     * The device's hardware can efficiently apply transforms to a specific Surface (window) so
+     * that apps can be transformed independently of one another.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int CAPABILITY_HARDWARE_ACCELERATION_PER_APP = 0x4;
+
     private final ColorDisplayManagerInternal mManager;
 
     /**
@@ -48,13 +95,43 @@
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
     public boolean isDeviceColorManaged() {
         return mManager.isDeviceColorManaged();
     }
 
     /**
+     * Set the level of color saturation to apply to the display.
+     *
+     * @param saturationLevel 0-100 (inclusive), where 100 is full saturation
+     * @return whether the saturation level change was applied successfully
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+    public boolean setSaturationLevel(@IntRange(from = 0, to = 100) int saturationLevel) {
+        return mManager.setSaturationLevel(saturationLevel);
+    }
+
+    /**
+     * Set the level of color saturation to apply to a specific app.
+     *
+     * @param packageName the package name of the app whose windows should be desaturated
+     * @param saturationLevel 0-100 (inclusive), where 100 is full saturation
+     * @return whether the saturation level change was applied successfully
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+    public boolean setAppSaturationLevel(@NonNull String packageName,
+            @IntRange(from = 0, to = 100) int saturationLevel) {
+        return mManager.setAppSaturationLevel(packageName, saturationLevel);
+    }
+
+    /**
      * Returns {@code true} if Night Display is supported by the device.
+     *
+     * @hide
      */
     public static boolean isNightDisplayAvailable(Context context) {
         return context.getResources().getBoolean(R.bool.config_nightDisplayAvailable);
@@ -62,11 +139,34 @@
 
     /**
      * Returns {@code true} if display white balance is supported by the device.
+     *
+     * @hide
      */
     public static boolean isDisplayWhiteBalanceAvailable(Context context) {
         return context.getResources().getBoolean(R.bool.config_displayWhiteBalanceAvailable);
     }
 
+    /**
+     * Check if the color transforms are color accelerated. Some transforms are experimental only
+     * on non-accelerated platforms due to the performance implications.
+     *
+     * @hide
+     */
+    public static boolean isColorTransformAccelerated(Context context) {
+        return context.getResources().getBoolean(R.bool.config_setColorTransformAccelerated);
+    }
+
+    /**
+     * Returns the available software and hardware color transform capabilities of this device.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+    public @CapabilityType int getTransformCapabilities() {
+        return mManager.getTransformCapabilities();
+    }
+
     private static class ColorDisplayManagerInternal {
 
         private static ColorDisplayManagerInternal sInstance;
@@ -99,5 +199,29 @@
                 throw e.rethrowFromSystemServer();
             }
         }
+
+        boolean setSaturationLevel(int saturationLevel) {
+            try {
+                return mCdm.setSaturationLevel(saturationLevel);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        boolean setAppSaturationLevel(String packageName, int saturationLevel) {
+            try {
+                return mCdm.setAppSaturationLevel(packageName, saturationLevel);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        int getTransformCapabilities() {
+            try {
+                return mCdm.getTransformCapabilities();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
     }
 }
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 82e765d..44b653c 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -563,11 +563,16 @@
      * 0 produces a grayscale image, 1 is normal.
      *
      * @hide
+     * @deprecated use {@link ColorDisplayManager#setSaturationLevel(int)}.
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
     public void setSaturationLevel(float level) {
-        mGlobal.setSaturationLevel(level);
+        if (level < 0f || level > 1f) {
+            throw new IllegalArgumentException("Saturation level must be between 0 and 1");
+        }
+        final ColorDisplayManager cdm = mContext.getSystemService(ColorDisplayManager.class);
+        cdm.setSaturationLevel(Math.round(level * 100f));
     }
 
     /**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 7304ab4..7e45441 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -394,17 +394,6 @@
         }
     }
 
-    /**
-     * Set the level of color saturation to apply to the display.
-     */
-    public void setSaturationLevel(float level) {
-        try {
-            mDm.setSaturationLevel(level);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
-    }
-
     public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
             String name, int width, int height, int densityDpi, Surface surface, int flags,
             VirtualDisplay.Callback callback, Handler handler, String uniqueId) {
@@ -447,6 +436,7 @@
     public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {
         try {
             mDm.setVirtualDisplaySurface(token, surface);
+            setVirtualDisplayState(token, surface != null);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
@@ -469,6 +459,14 @@
         }
     }
 
+    void setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn) {
+        try {
+            mDm.setVirtualDisplayState(token, isOn);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
     /**
      * Gets the stable device display size, in pixels.
      */
diff --git a/core/java/android/hardware/display/IColorDisplayManager.aidl b/core/java/android/hardware/display/IColorDisplayManager.aidl
index f786589..53cb8db 100644
--- a/core/java/android/hardware/display/IColorDisplayManager.aidl
+++ b/core/java/android/hardware/display/IColorDisplayManager.aidl
@@ -19,4 +19,9 @@
 /** @hide */
 interface IColorDisplayManager {
     boolean isDeviceColorManaged();
+
+    boolean setSaturationLevel(int saturationLevel);
+    boolean setAppSaturationLevel(String packageName, int saturationLevel);
+
+    int getTransformCapabilities();
 }
\ No newline at end of file
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index b575997..aae8afb 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -66,9 +66,6 @@
     // Requires CONFIGURE_DISPLAY_COLOR_MODE
     void requestColorMode(int displayId, int colorMode);
 
-    // Requires CONTROL_DISPLAY_SATURATION
-    void setSaturationLevel(float level);
-
     // Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate
     // MediaProjection token for certain combinations of flags.
     int createVirtualDisplay(in IVirtualDisplayCallback callback,
@@ -85,6 +82,9 @@
     // No permissions required but must be same Uid as the creator.
     void releaseVirtualDisplay(in IVirtualDisplayCallback token);
 
+    // No permissions required but must be same Uid as the creator.
+    void setVirtualDisplayState(in IVirtualDisplayCallback token, boolean isOn);
+
     // Get a stable metric for the device's display size. No permissions required.
     Point getStableDisplaySize();
 
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index d354666..bf62c95 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -104,6 +104,18 @@
         }
     }
 
+    /**
+     * Sets the on/off state for a virtual display.
+     *
+     * @param isOn Whether the display should be on or off.
+     * @hide
+     */
+    public void setDisplayState(boolean isOn) {
+        if (mToken != null) {
+            mGlobal.setVirtualDisplayState(mToken, isOn);
+        }
+    }
+
     @Override
     public String toString() {
         return "VirtualDisplay{display=" + mDisplay + ", token=" + mToken
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 1630b06..c9a7830 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -163,8 +163,8 @@
                 mAuthenticationCallback = callback;
                 mCryptoObject = crypto;
                 long sessionId = crypto != null ? crypto.getOpId() : 0;
-                mService.authenticate(mToken, sessionId, mServiceReceiver, flags,
-                        mContext.getOpPackageName());
+                mService.authenticate(mToken, sessionId, mContext.getUserId(), mServiceReceiver,
+                        flags, mContext.getOpPackageName());
             } catch (RemoteException e) {
                 Log.w(TAG, "Remote exception while authenticating: ", e);
                 if (callback != null) {
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index a1c88f8..f67760a 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -27,7 +27,7 @@
  */
 interface IFaceService {
     // Authenticate the given sessionId with a face
-    void authenticate(IBinder token, long sessionId,
+    void authenticate(IBinder token, long sessionId, int userid,
             IFaceServiceReceiver receiver, int flags, String opPackageName);
 
     // This method prepares the service to start authenticating, but doesn't start authentication.
diff --git a/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java b/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
index 9bebbd2..bdd5ab6 100644
--- a/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
+++ b/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
@@ -15,9 +15,12 @@
  */
 package android.hardware.hdmi;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.RemoteException;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -52,7 +55,22 @@
     @VisibleForTesting(visibility = Visibility.PACKAGE)
     public HdmiAudioSystemClient(IHdmiControlService service, @Nullable Handler handler) {
         super(service);
-        mHandler = handler == null ? new Handler() : handler;
+        mHandler = handler == null ? new Handler(Looper.getMainLooper()) : handler;
+    }
+
+    /**
+     * Callback interface used to get the set System Audio Mode result.
+     *
+     * @hide
+     */
+    // TODO(b/110094868): unhide and add @SystemApi for Q
+    public interface SetSystemAudioModeCallback {
+        /**
+         * Called when the input was changed.
+         *
+         * @param result the result of the set System Audio Mode
+         */
+        void onComplete(int result);
     }
 
     /** @hide */
@@ -116,4 +134,34 @@
             mPendingReportAudioStatus = true;
         }
     }
+
+    /**
+     * Set System Audio Mode on/off with audio system device.
+     *
+     * @param state true to set System Audio Mode on. False to set off.
+     * @param callback callback offer the setting result.
+     *
+     * @hide
+     */
+    // TODO(b/110094868): unhide and add @SystemApi for Q
+    public void setSystemAudioMode(boolean state, @NonNull SetSystemAudioModeCallback callback) {
+        // TODO(amyjojo): implement this when needed.
+    }
+
+    /**
+     * When device is switching to an audio only source, this method is called to broadcast
+     * a setSystemAudioMode on message to the HDMI CEC system without querying Active Source or
+     * TV supporting System Audio Control or not. This is to get volume control passthrough
+     * from STB even if TV does not support it.
+     *
+     * @hide
+     */
+    // TODO(b/110094868): unhide and add @SystemApi for Q
+    public void setSystemAudioModeOnForAudioOnlySource() {
+        try {
+            mService.setSystemAudioModeOnForAudioOnlySource();
+        } catch (RemoteException e) {
+            Log.d(TAG, "Failed to set System Audio Mode on for Audio Only source");
+        }
+    }
 }
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 72a6ffe..a98b31a 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -16,6 +16,8 @@
 
 package android.hardware.hdmi;
 
+import static com.android.internal.os.RoSystemProperties.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH;
+
 import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
@@ -27,9 +29,12 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.util.ArrayMap;
 import android.util.Log;
 
+import java.util.List;
+
 /**
  * The {@link HdmiControlManager} class is used to send HDMI control messages
  * to attached CEC devices.
@@ -50,6 +55,10 @@
 
     @Nullable private final IHdmiControlService mService;
 
+    private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
+
+    private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+
     /**
      * Broadcast Action: Display OSD message.
      * <p>Send when the service has a message to display on screen for events
@@ -264,6 +273,10 @@
     private final boolean mHasTvDevice;
     // True if we have a logical device of type audio system hosted in the system.
     private final boolean mHasAudioSystemDevice;
+    // True if we have a logical device of type audio system hosted in the system.
+    private final boolean mHasSwitchDevice;
+    // True if it's a switch device.
+    private final boolean mIsSwitchDevice;
 
     /**
      * {@hide} - hide this constructor because it has a parameter of type IHdmiControlService,
@@ -283,6 +296,9 @@
         mHasTvDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_TV);
         mHasPlaybackDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PLAYBACK);
         mHasAudioSystemDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
+        mHasSwitchDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
+        mIsSwitchDevice = SystemProperties.getBoolean(
+            PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH, false);
     }
 
     private static boolean hasDeviceType(int[] types, int type) {
@@ -319,6 +335,9 @@
                 return mHasPlaybackDevice ? new HdmiPlaybackClient(mService) : null;
             case HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM:
                 return mHasAudioSystemDevice ? new HdmiAudioSystemClient(mService) : null;
+            case HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH:
+                return (mHasSwitchDevice || mIsSwitchDevice)
+                    ? new HdmiSwitchClient(mService) : null;
             default:
                 return null;
         }
@@ -373,6 +392,90 @@
     }
 
     /**
+     * Gets an object that represents an HDMI-CEC logical device of type switch on the system.
+     *
+     * <p>Used to send HDMI control messages to other devices like TV through HDMI bus. It is also
+     * possible to communicate with other logical devices hosted in the same system if the system is
+     * configured to host more than one type of HDMI-CEC logical devices.
+     *
+     * @return {@link HdmiSwitchClient} instance. {@code null} on failure.
+     *
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    @Nullable
+    @SuppressLint("Doclava125")
+    public HdmiSwitchClient getSwitchClient() {
+        return (HdmiSwitchClient) getClient(HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
+    }
+
+    /**
+     * Get a snapshot of the real-time status of the remote devices.
+     *
+     * @return a list of {@link HdmiDeviceInfo} of the devices connected to the current device.
+     *
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public List<HdmiDeviceInfo> getConnectedDevicesList() {
+        try {
+            return mService.getDeviceList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Power off the target device.
+     *
+     * @param deviceInfo HdmiDeviceInfo of the device to be powered off
+     *
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public void powerOffRemoteDevice(HdmiDeviceInfo deviceInfo) {
+        try {
+            mService.powerOffRemoteDevice(
+                    deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Power on the target device.
+     *
+     * @param deviceInfo HdmiDeviceInfo of the device to be powered on
+     *
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public void powerOnRemoteDevice(HdmiDeviceInfo deviceInfo) {
+        try {
+            mService.powerOnRemoteDevice(
+                    deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Ask the target device to be the new Active Source.
+     *
+     * @param deviceInfo HdmiDeviceInfo of the target device
+     *
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public void askRemoteDeviceToBecomeActiveSource(HdmiDeviceInfo deviceInfo) {
+        try {
+            mService.askRemoteDeviceToBecomeActiveSource(deviceInfo.getPhysicalAddress());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Controls standby mode of the system. It will also try to turn on/off the connected devices if
      * necessary.
      *
@@ -388,6 +491,59 @@
     }
 
     /**
+     * Gets whether the system is in system audio mode.
+     *
+     * @hide
+     */
+    public boolean getSystemAudioMode() {
+        try {
+            return mService.getSystemAudioMode();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get the physical address of the device.
+     *
+     * @hide
+     */
+    public int getPhysicalAddress() {
+        if (mPhysicalAddress != INVALID_PHYSICAL_ADDRESS) {
+            return mPhysicalAddress;
+        }
+        try {
+            mPhysicalAddress = mService.getPhysicalAddress();
+            return mPhysicalAddress;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Check if the target device is connected to the current device. The
+     * API also returns true if the current device is the target.
+     *
+     * @param targetDevice {@link HdmiDeviceInfo} of the target device.
+     * @return true if {@code device} is directly or indirectly connected to the
+     *
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public boolean isTargetDeviceConnected(HdmiDeviceInfo targetDevice) {
+        mPhysicalAddress = getPhysicalAddress();
+        if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+            return false;
+        }
+        int targetPhysicalAddress = targetDevice.getPhysicalAddress();
+        if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+            return false;
+        }
+        return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, mPhysicalAddress)
+            != HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE;
+    }
+
+    /**
      * Listener used to get hotplug event from HDMI port.
      */
     public interface HotplugEventListener {
diff --git a/core/java/android/hardware/hdmi/HdmiSwitchClient.java b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
new file mode 100644
index 0000000..1ac2973
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
@@ -0,0 +1,137 @@
+/*
+ * 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.hdmi;
+
+import android.annotation.NonNull;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * HdmiSwitchClient represents HDMI-CEC logical device of type Switch in the Android system which
+ * acts as switch.
+ *
+ * <p>HdmiSwitchClient has a CEC device type of HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH,
+ * but it is used by all Android TV devices that have multiple HDMI inputs,
+ * even if it is not a "pure" swicth and has another device type like TV or Player.
+ *
+ * @hide
+ * TODO(b/110094868): unhide and add @SystemApi for Q
+ */
+public class HdmiSwitchClient extends HdmiClient {
+
+    private static final String TAG = "HdmiSwitchClient";
+
+    /* package */ HdmiSwitchClient(IHdmiControlService service) {
+        super(service);
+    }
+
+    private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
+        return new IHdmiControlCallback.Stub() {
+            @Override
+            public void onComplete(int result) {
+                callback.onComplete(result);
+            }
+        };
+    }
+
+    /** @hide */
+    // TODO(b/110094868): unhide for Q
+    @Override
+    public int getDeviceType() {
+        return HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH;
+    }
+
+    /**
+     * Selects a CEC logical device to be a new active source.
+     *
+     * @param logicalAddress logical address of the device to select
+     * @param callback callback to get the result with
+     * @throws {@link IllegalArgumentException} if the {@code callback} is null
+     *
+     * @hide
+     * TODO(b/110094868): unhide and add @SystemApi for Q
+     */
+    public void deviceSelect(int logicalAddress, @NonNull SelectCallback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback must not be null.");
+        }
+        try {
+            mService.deviceSelect(logicalAddress, getCallbackWrapper(callback));
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to select device: ", e);
+        }
+    }
+
+    /**
+     * Selects a HDMI port to be a new route path.
+     *
+     * @param portId HDMI port to select
+     * @param callback callback to get the result with
+     * @throws {@link IllegalArgumentException} if the {@code callback} is null
+     *
+     * @hide
+     * TODO(b/110094868): unhide and add @SystemApi for Q
+     */
+    public void portSelect(int portId, @NonNull SelectCallback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("Callback must not be null");
+        }
+        try {
+            mService.portSelect(portId, getCallbackWrapper(callback));
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to select port: ", e);
+        }
+    }
+
+    /**
+     * Returns all the CEC devices connected to the device.
+     *
+     * <p>This only applies to device with multiple HDMI inputs
+     *
+     * @return list of {@link HdmiDeviceInfo} for connected CEC devices. Empty list is returned if
+     * there is none.
+     *
+     * @hide
+     * TODO(b/110094868): unhide and add @SystemApi for Q
+     */
+    public List<HdmiDeviceInfo> getDeviceList() {
+        try {
+            return mService.getDeviceList();
+        } catch (RemoteException e) {
+            Log.e("TAG", "Failed to call getDeviceList():", e);
+            return Collections.<HdmiDeviceInfo>emptyList();
+        }
+    }
+
+    /**
+     * Callback interface used to get the result of {@link #deviceSelect} or {@link #portSelect}.
+     *
+     * @hide
+     * TODO(b/110094868): unhide and add @SystemApi for Q
+     */
+    public interface SelectCallback {
+
+        /**
+         * Called when the operation is finished.
+         *
+         * @param result the result value of {@link #deviceSelect} or {@link #portSelect}.
+         */
+        void onComplete(int result);
+    }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiUtils.java b/core/java/android/hardware/hdmi/HdmiUtils.java
new file mode 100644
index 0000000..8c94b78
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiUtils.java
@@ -0,0 +1,245 @@
+/*
+ * 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.hdmi;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Various utilities related to HDMI CEC.
+ *
+ * TODO(b/110094868): unhide for Q
+ * @hide
+ */
+public final class HdmiUtils {
+    /**
+     * Return value of {@link #getLocalPortFromPhysicalAddress(int, int)}
+     */
+    static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
+    static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
+
+    private HdmiUtils() { /* cannot be instantiated */ }
+
+    /**
+     * Method to parse target physical address to the port number on the current device.
+     *
+     * <p>This check assumes target address is valid.
+     *
+     * @param targetPhysicalAddress is the physical address of the target device
+     * @param myPhysicalAddress is the physical address of the current device
+     * @return
+     * If the target device is under the current device, return the port number of current device
+     * that the target device is connected to. This also applies to the devices that are indirectly
+     * connected to the current device.
+     *
+     * <p>If the target device has the same physical address as the current device, return
+     * {@link #TARGET_SAME_PHYSICAL_ADDRESS}.
+     *
+     * <p>If the target device is not under the current device, return
+     * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}.
+     */
+    public static int getLocalPortFromPhysicalAddress(
+            int targetPhysicalAddress, int myPhysicalAddress) {
+        if (myPhysicalAddress == targetPhysicalAddress) {
+            return TARGET_SAME_PHYSICAL_ADDRESS;
+        }
+
+        int mask = 0xF000;
+        int finalMask = 0xF000;
+        int maskedAddress = myPhysicalAddress;
+
+        while (maskedAddress != 0) {
+            maskedAddress = myPhysicalAddress & mask;
+            finalMask |= mask;
+            mask >>= 4;
+        }
+
+        int portAddress = targetPhysicalAddress & finalMask;
+        if ((portAddress & (finalMask << 4)) != myPhysicalAddress) {
+            return TARGET_NOT_UNDER_LOCAL_DEVICE;
+        }
+
+        mask <<= 4;
+        int port = portAddress & mask;
+        while ((port >> 4) != 0) {
+            port >>= 4;
+        }
+        return port;
+    }
+
+    /**
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({HDMI_RELATIVE_POSITION_UNKNOWN, HDMI_RELATIVE_POSITION_DIRECTLY_BELOW,
+            HDMI_RELATIVE_POSITION_BELOW, HDMI_RELATIVE_POSITION_SAME,
+            HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE, HDMI_RELATIVE_POSITION_ABOVE,
+            HDMI_RELATIVE_POSITION_SIBLING, HDMI_RELATIVE_POSITION_DIFFERENT_BRANCH})
+    public @interface HdmiAddressRelativePosition {}
+    /**
+     * HDMI relative position is not determined.
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public static final int HDMI_RELATIVE_POSITION_UNKNOWN = 0;
+    /**
+     * HDMI relative position: directly blow the device.
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public static final int HDMI_RELATIVE_POSITION_DIRECTLY_BELOW = 1;
+    /**
+     * HDMI relative position: indirectly below the device.
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public static final int HDMI_RELATIVE_POSITION_BELOW = 2;
+    /**
+     * HDMI relative position: the same device.
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public static final int HDMI_RELATIVE_POSITION_SAME = 3;
+    /**
+     * HDMI relative position: directly above the device.
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public static final int HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE = 4;
+    /**
+     * HDMI relative position: indirectly above the device.
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public static final int HDMI_RELATIVE_POSITION_ABOVE = 5;
+    /**
+     * HDMI relative position: directly below a same device.
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public static final int HDMI_RELATIVE_POSITION_SIBLING = 6;
+    /**
+     * HDMI relative position: different branch.
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    public static final int HDMI_RELATIVE_POSITION_DIFFERENT_BRANCH = 7;
+
+    private static final int NPOS = -1;
+
+    /**
+     * Check if the given physical address is valid.
+     *
+     * @param address physical address
+     * @return {@code true} if the given address is valid
+     */
+    public static boolean isValidPhysicalAddress(int address) {
+        if (address < 0 || address >= 0xFFFF) {
+            return false;
+        }
+        int mask = 0xF000;
+        boolean hasZero = false;
+        for (int i = 0; i < 4; i++) {
+            if ((address & mask) == 0) {
+                hasZero = true;
+            } else if (hasZero) {
+                // only 0s are valid after a 0.
+                // e.g. 0x1012 is not valid.
+                return false;
+            }
+            mask >>= 4;
+        }
+        return true;
+    }
+
+
+    /**
+     * Returns the relative position of two physical addresses.
+     */
+    @HdmiAddressRelativePosition
+    public static int getHdmiAddressRelativePosition(int src, int dest) {
+        if (src == 0xFFFF || dest == 0xFFFF) {
+            // address not assigned
+            return HDMI_RELATIVE_POSITION_UNKNOWN;
+        }
+        try {
+            int firstDiffPos = physicalAddressFirstDifferentDigitPos(src, dest);
+            if (firstDiffPos == NPOS) {
+                return HDMI_RELATIVE_POSITION_SAME;
+            }
+            int mask = (0xF000 >> (firstDiffPos * 4));
+            int nextPos = firstDiffPos + 1;
+            if ((src & mask) == 0) {
+                // src is above dest
+                if (nextPos == 4) {
+                    // last digits are different
+                    return HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE;
+                }
+                if (((0xF000 >> (nextPos * 4)) & dest) == 0) {
+                    // next digit is 0
+                    return HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE;
+                }
+                return HDMI_RELATIVE_POSITION_ABOVE;
+            }
+
+            if ((dest & mask) == 0) {
+                // src is below dest
+                if (nextPos == 4) {
+                    // last digits are different
+                    return HDMI_RELATIVE_POSITION_DIRECTLY_BELOW;
+                }
+                if (((0xF000 >> (nextPos * 4)) & src) == 0) {
+                    // next digit is 0
+                    return HDMI_RELATIVE_POSITION_DIRECTLY_BELOW;
+                }
+                return HDMI_RELATIVE_POSITION_BELOW;
+            }
+            if (nextPos == 4) {
+                // last digits are different
+                return HDMI_RELATIVE_POSITION_SIBLING;
+            }
+            if (((0xF000 >> (nextPos * 4)) & src) == 0 && ((0xF000 >> (nextPos * 4)) & dest) == 0) {
+                return HDMI_RELATIVE_POSITION_SIBLING;
+            }
+            return HDMI_RELATIVE_POSITION_DIFFERENT_BRANCH;
+        } catch (IllegalArgumentException e) {
+            // invalid address
+            return HDMI_RELATIVE_POSITION_UNKNOWN;
+        }
+    }
+
+    private static int physicalAddressFirstDifferentDigitPos(int address1, int address2)
+            throws IllegalArgumentException {
+        if (!isValidPhysicalAddress(address1)) {
+            throw new IllegalArgumentException(address1 + " is not a valid address.");
+        }
+        if (!isValidPhysicalAddress(address2)) {
+            throw new IllegalArgumentException(address2 + " is not a valid address.");
+        }
+        int mask = 0xF000;
+        for (int i = 0; i < 4; i++) {
+            if ((address1 & mask) != (address2 & mask)) {
+                return i;
+            }
+            mask = mask >> 4;
+        }
+        return NPOS;
+    }
+}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 2b8d00b..1cd9920 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -50,6 +50,7 @@
     List<HdmiPortInfo> getPortInfo();
     boolean canChangeSystemAudioMode();
     boolean getSystemAudioMode();
+    int getPhysicalAddress();
     void setSystemAudioMode(boolean enabled, IHdmiControlCallback callback);
     void addSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
     void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
@@ -60,6 +61,9 @@
     void setInputChangeListener(IHdmiInputChangeListener listener);
     List<HdmiDeviceInfo> getInputDevices();
     List<HdmiDeviceInfo> getDeviceList();
+    void powerOffRemoteDevice(int logicalAddress, int powerStatus);
+    void powerOnRemoteDevice(int logicalAddress, int powerStatus);
+    void askRemoteDeviceToBecomeActiveSource(int physicalAddress);
     void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
             boolean hasVendorId);
     void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
@@ -73,4 +77,5 @@
     void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener);
     void setStandbyMode(boolean isStandbyModeOn);
     void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute);
+    void setSystemAudioModeOnForAudioOnlySource();
 }
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index edc3f94..299a00a 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -120,6 +120,9 @@
     /* Sets the port's current role. */
     void setPortRoles(in String portId, int powerRole, int dataRole);
 
+    /* Enable/disable contaminant detection */
+    void enableContaminantDetection(in String portId, boolean enable);
+
    /* Sets USB device connection handler. */
    void setUsbDeviceConnectionHandler(in ComponentName usbDeviceConnectionHandler);
 }
diff --git a/core/java/android/hardware/usb/ParcelableUsbPort.java b/core/java/android/hardware/usb/ParcelableUsbPort.java
index 7f7ba96..30388af 100644
--- a/core/java/android/hardware/usb/ParcelableUsbPort.java
+++ b/core/java/android/hardware/usb/ParcelableUsbPort.java
@@ -31,10 +31,21 @@
 public final class ParcelableUsbPort implements Parcelable {
     private final @NonNull String mId;
     private final int mSupportedModes;
+    private final int mSupportedContaminantProtectionModes;
+    private final boolean mSupportsEnableContaminantPresenceProtection;
+    private final boolean mSupportsEnableContaminantPresenceDetection;
 
-    private ParcelableUsbPort(@NonNull String id, int supportedModes) {
+    private ParcelableUsbPort(@NonNull String id, int supportedModes,
+            int supportedContaminantProtectionModes,
+            boolean supportsEnableContaminantPresenceProtection,
+            boolean supportsEnableContaminantPresenceDetection) {
         mId = id;
         mSupportedModes = supportedModes;
+        mSupportedContaminantProtectionModes = supportedContaminantProtectionModes;
+        mSupportsEnableContaminantPresenceProtection =
+                supportsEnableContaminantPresenceProtection;
+        mSupportsEnableContaminantPresenceDetection =
+                supportsEnableContaminantPresenceDetection;
     }
 
     /**
@@ -45,7 +56,10 @@
      * @return The parcelable version of the port
      */
     public static @NonNull ParcelableUsbPort of(@NonNull UsbPort port) {
-        return new ParcelableUsbPort(port.getId(), port.getSupportedModes());
+        return new ParcelableUsbPort(port.getId(), port.getSupportedModes(),
+                port.getSupportedContaminantProtectionModes(),
+                port.supportsEnableContaminantPresenceProtection(),
+                port.supportsEnableContaminantPresenceDetection());
     }
 
     /**
@@ -56,7 +70,9 @@
      * @return The UsbPort for this object
      */
     public @NonNull UsbPort getUsbPort(@NonNull UsbManager usbManager) {
-        return new UsbPort(usbManager, mId, mSupportedModes);
+        return new UsbPort(usbManager, mId, mSupportedModes, mSupportedContaminantProtectionModes,
+                mSupportsEnableContaminantPresenceProtection,
+                mSupportsEnableContaminantPresenceDetection);
     }
 
     @Override
@@ -68,6 +84,9 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mId);
         dest.writeInt(mSupportedModes);
+        dest.writeInt(mSupportedContaminantProtectionModes);
+        dest.writeBoolean(mSupportsEnableContaminantPresenceProtection);
+        dest.writeBoolean(mSupportsEnableContaminantPresenceDetection);
     }
 
     public static final Creator<ParcelableUsbPort> CREATOR =
@@ -76,7 +95,14 @@
                 public ParcelableUsbPort createFromParcel(Parcel in) {
                     String id = in.readString();
                     int supportedModes = in.readInt();
-                    return new ParcelableUsbPort(id, supportedModes);
+                    int supportedContaminantProtectionModes = in.readInt();
+                    boolean supportsEnableContaminantPresenceProtection = in.readBoolean();
+                    boolean supportsEnableContaminantPresenceDetection = in.readBoolean();
+
+                    return new ParcelableUsbPort(id, supportedModes,
+                            supportedContaminantProtectionModes,
+                            supportsEnableContaminantPresenceProtection,
+                            supportsEnableContaminantPresenceDetection);
                 }
 
                 @Override
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 6014478..eb148b9 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -854,6 +854,20 @@
     }
 
     /**
+     * Enables USB port contaminant detection algorithm.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MANAGE_USB)
+    void enableContaminantDetection(@NonNull UsbPort port, boolean enable) {
+        try {
+            mService.enableContaminantDetection(port.getId(), enable);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Sets the component that will handle USB device connection.
      * <p>
      * Setting component allows to specify external USB host manager to handle use cases, where
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index 37154e4..c674480 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -16,6 +16,10 @@
 
 package android.hardware.usb;
 
+import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DETECTED;
+import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_DISABLED;
+import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED;
+import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE;
@@ -48,16 +52,21 @@
     private final String mId;
     private final int mSupportedModes;
     private final UsbManager mUsbManager;
+    private final int mSupportedContaminantProtectionModes;
+    private final boolean mSupportsEnableContaminantPresenceProtection;
+    private final boolean mSupportsEnableContaminantPresenceDetection;
 
     private static final int NUM_DATA_ROLES = Constants.PortDataRole.NUM_DATA_ROLES;
-
     /**
      * Points to the first power role in the IUsb HAL.
      */
     private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE;
 
     /** @hide */
-    public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes) {
+    public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes,
+            int supportedContaminantProtectionModes,
+            boolean supportsEnableContaminantPresenceProtection,
+            boolean supportsEnableContaminantPresenceDetection) {
         Preconditions.checkNotNull(id);
         Preconditions.checkFlagsArgument(supportedModes,
                 MODE_DFP | MODE_UFP | MODE_AUDIO_ACCESSORY | MODE_DEBUG_ACCESSORY);
@@ -65,6 +74,11 @@
         mUsbManager = usbManager;
         mId = id;
         mSupportedModes = supportedModes;
+        mSupportedContaminantProtectionModes = supportedContaminantProtectionModes;
+        mSupportsEnableContaminantPresenceProtection =
+                supportsEnableContaminantPresenceProtection;
+        mSupportsEnableContaminantPresenceDetection =
+                supportsEnableContaminantPresenceDetection;
     }
 
     /**
@@ -93,6 +107,36 @@
         return mSupportedModes;
     }
 
+   /**
+     * Gets the supported port proctection modes when the port is contaminated.
+     * <p>
+     * The actual mode of the port is decided by the hardware
+     * </p>
+     *
+     * @hide
+     */
+    public int getSupportedContaminantProtectionModes() {
+        return mSupportedContaminantProtectionModes;
+    }
+
+   /**
+     * Tells if UsbService can enable/disable contaminant presence protection.
+     *
+     * @hide
+     */
+    public boolean supportsEnableContaminantPresenceProtection() {
+        return mSupportsEnableContaminantPresenceProtection;
+    }
+
+   /**
+     * Tells if UsbService can enable/disable contaminant presence detection.
+     *
+     * @hide
+     */
+    public boolean supportsEnableContaminantPresenceDetection() {
+        return mSupportsEnableContaminantPresenceDetection;
+    }
+
     /**
      * Gets the status of this USB port.
      *
@@ -131,6 +175,12 @@
     }
 
     /**
+     * @hide
+     **/
+    public void enableContaminantDetection(boolean enable) {
+        mUsbManager.enableContaminantDetection(this, enable);
+    }
+    /**
      * Combines one power and one data role together into a unique value with
      * exactly one bit set.  This can be used to efficiently determine whether
      * a combination of roles is supported by testing whether that bit is present
@@ -206,6 +256,22 @@
     }
 
     /** @hide */
+    public static String contaminantPresenceStatusToString(int contaminantPresenceStatus) {
+        switch (contaminantPresenceStatus) {
+            case CONTAMINANT_DETECTION_NOT_SUPPORTED:
+                return "not-supported";
+            case CONTAMINANT_DETECTION_DISABLED:
+                return "disabled";
+            case CONTAMINANT_DETECTION_DETECTED:
+                return "detected";
+            case CONTAMINANT_DETECTION_NOT_DETECTED:
+                return "not detected";
+            default:
+                return Integer.toString(contaminantPresenceStatus);
+        }
+    }
+
+    /** @hide */
     public static String roleCombinationsToString(int combo) {
         StringBuilder result = new StringBuilder();
         result.append("[");
@@ -264,6 +330,11 @@
 
     @Override
     public String toString() {
-        return "UsbPort{id=" + mId + ", supportedModes=" + modeToString(mSupportedModes) + "}";
+        return "UsbPort{id=" + mId + ", supportedModes=" + modeToString(mSupportedModes)
+                + "supportedContaminantProtectionModes=" + mSupportedContaminantProtectionModes
+                + "supportsEnableContaminantPresenceProtection="
+                + mSupportsEnableContaminantPresenceProtection
+                + "supportsEnableContaminantPresenceDetection="
+                + mSupportsEnableContaminantPresenceDetection;
     }
 }
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index d30201a..426dba8 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -39,6 +39,8 @@
     private final @UsbPowerRole int mCurrentPowerRole;
     private final @UsbDataRole int mCurrentDataRole;
     private final int mSupportedRoleCombinations;
+    private final @ContaminantProtectionStatus int mContaminantProtectionStatus;
+    private final @ContaminantDetectionStatus int mContaminantDetectionStatus;
 
     /**
      * Power role: This USB port does not have a power role.
@@ -131,6 +133,93 @@
     public static final int MODE_DEBUG_ACCESSORY =
             android.hardware.usb.V1_1.Constants.PortMode_1_1.DEBUG_ACCESSORY;
 
+   /**
+     * Contaminant presence detection not supported by the device.
+     * @hide
+     */
+    public static final int CONTAMINANT_DETECTION_NOT_SUPPORTED =
+            android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.NOT_SUPPORTED;
+
+    /**
+     * Contaminant presence detection supported but disabled.
+     * @hide
+     */
+    public static final int CONTAMINANT_DETECTION_DISABLED =
+            android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.DISABLED;
+
+    /**
+     * Contaminant presence enabled but not detected.
+     * @hide
+     */
+    public static final int CONTAMINANT_DETECTION_NOT_DETECTED =
+            android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.NOT_DETECTED;
+
+    /**
+     * Contaminant presence enabled and detected.
+     * @hide
+     */
+    public static final int CONTAMINANT_DETECTION_DETECTED =
+            android.hardware.usb.V1_2.Constants.ContaminantDetectionStatus.DETECTED;
+
+    /**
+     * Contaminant protection - No action performed upon detection of
+     * contaminant presence.
+     * @hide
+     */
+    public static final int CONTAMINANT_PROTECTION_NONE =
+            android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.NONE;
+
+    /**
+     * Contaminant protection - Port is forced to sink upon detection of
+     * contaminant presence.
+     * @hide
+     */
+    public static final int CONTAMINANT_PROTECTION_SINK =
+            android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_SINK;
+
+    /**
+     * Contaminant protection - Port is forced to source upon detection of
+     * contaminant presence.
+     * @hide
+     */
+    public static final int CONTAMINANT_PROTECTION_SOURCE =
+            android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_SOURCE;
+
+    /**
+     * Contaminant protection - Port is disabled upon detection of
+     * contaminant presence.
+     * @hide
+     */
+    public static final int CONTAMINANT_PROTECTION_FORCE_DISABLE =
+            android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.FORCE_DISABLE;
+
+    /**
+     * Contaminant protection - Port is disabled upon detection of
+     * contaminant presence.
+     * @hide
+     */
+    public static final int CONTAMINANT_PROTECTION_DISABLED =
+            android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.DISABLED;
+
+    @IntDef(prefix = { "CONTAMINANT_DETECION_" }, flag = true, value = {
+            CONTAMINANT_DETECTION_NOT_SUPPORTED,
+            CONTAMINANT_DETECTION_DISABLED,
+            CONTAMINANT_DETECTION_NOT_DETECTED,
+            CONTAMINANT_DETECTION_DETECTED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ContaminantDetectionStatus{}
+
+    @IntDef(prefix = { "CONTAMINANT_PROTECTION_" }, flag = true, value = {
+            CONTAMINANT_PROTECTION_NONE,
+            CONTAMINANT_PROTECTION_SINK,
+            CONTAMINANT_PROTECTION_SOURCE,
+            CONTAMINANT_PROTECTION_FORCE_DISABLE,
+            CONTAMINANT_PROTECTION_DISABLED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ContaminantProtectionStatus{}
+
     @IntDef(prefix = { "MODE_" }, flag = true, value = {
             MODE_NONE,
             MODE_DFP,
@@ -142,12 +231,15 @@
     @interface UsbPortMode{}
 
     /** @hide */
-    public UsbPortStatus(int currentMode, @UsbPowerRole int currentPowerRole,
-            @UsbDataRole int currentDataRole, int supportedRoleCombinations) {
+    public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
+            int supportedRoleCombinations, int contaminantProtectionStatus,
+            int contaminantDetectionStatus) {
         mCurrentMode = currentMode;
         mCurrentPowerRole = currentPowerRole;
         mCurrentDataRole = currentDataRole;
         mSupportedRoleCombinations = supportedRoleCombinations;
+        mContaminantProtectionStatus = contaminantProtectionStatus;
+        mContaminantDetectionStatus = contaminantDetectionStatus;
     }
 
     /**
@@ -212,6 +304,24 @@
         return mSupportedRoleCombinations;
     }
 
+    /**
+     * Returns contaminant detection status.
+     *
+     * @hide
+     */
+    public @ContaminantDetectionStatus int getContaminantDetectionStatus() {
+        return mContaminantDetectionStatus;
+    }
+
+    /**
+     * Returns contamiant protection status.
+     *
+     * @hide
+     */
+    public @ContaminantProtectionStatus int getContaminantProtectionStatus() {
+        return mContaminantProtectionStatus;
+    }
+
     @Override
     public String toString() {
         return "UsbPortStatus{connected=" + isConnected()
@@ -220,6 +330,10 @@
                 + ", currentDataRole=" + UsbPort.dataRoleToString(mCurrentDataRole)
                 + ", supportedRoleCombinations="
                         + UsbPort.roleCombinationsToString(mSupportedRoleCombinations)
+                + ", contaminantDetectionStatus="
+                        + getContaminantDetectionStatus()
+                + ", contaminantProtectionStatus="
+                        + getContaminantProtectionStatus()
                 + "}";
     }
 
@@ -234,6 +348,8 @@
         dest.writeInt(mCurrentPowerRole);
         dest.writeInt(mCurrentDataRole);
         dest.writeInt(mSupportedRoleCombinations);
+        dest.writeInt(mContaminantProtectionStatus);
+        dest.writeInt(mContaminantDetectionStatus);
     }
 
     public static final Parcelable.Creator<UsbPortStatus> CREATOR =
@@ -244,8 +360,11 @@
             int currentPowerRole = in.readInt();
             int currentDataRole = in.readInt();
             int supportedRoleCombinations = in.readInt();
+            int contaminantProtectionStatus = in.readInt();
+            int contaminantDetectionStatus = in.readInt();
             return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
-                    supportedRoleCombinations);
+                    supportedRoleCombinations, contaminantProtectionStatus,
+                    contaminantDetectionStatus);
         }
 
         @Override
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7d40227..38ddc16 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -2087,7 +2087,14 @@
      * protocol, so applications with custom text editing written before this method appeared will
      * not call to inform the IME of this interaction.
      * @param focusChanged true if the user changed the focused view by this click.
+     * @see InputMethodManager#viewClicked(View)
+     * @deprecated The method may not be called for composite {@link View} that works as a giant
+     *             "Canvas", which can host its own UI hierarchy and sub focus state.
+     *             {@link android.webkit.WebView} is a good example. Application / IME developers
+     *             should not rely on this method. If your goal is just being notified when an
+     *             on-going input is interrupted, simply monitor {@link #onFinishInput()}.
      */
+    @Deprecated
     public void onViewClicked(boolean focusChanged) {
         // Intentionally empty
     }
@@ -2856,7 +2863,7 @@
             if (mNotifyUserActionSent) {
                 return;
             }
-            mPrivOps.notifyUserActionAsync();
+            mPrivOps.notifyUserAction();
             mNotifyUserActionSent = true;
         }
     }
diff --git a/core/java/android/net/ApfCapabilitiesParcelable.aidl b/core/java/android/net/ApfCapabilitiesParcelable.aidl
new file mode 100644
index 0000000..f0645d2
--- /dev/null
+++ b/core/java/android/net/ApfCapabilitiesParcelable.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable ApfCapabilitiesParcelable {
+    int apfVersionSupported;
+    int maximumApfProgramSize;
+    int apfPacketFormat;
+}
\ No newline at end of file
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index ee05f28..3b01266 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -15,6 +15,8 @@
  */
 package android.net;
 
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -28,15 +30,23 @@
  */
 public class CaptivePortal implements Parcelable {
     /** @hide */
+    @SystemApi
+    @TestApi
     public static final int APP_RETURN_DISMISSED    = 0;
     /** @hide */
+    @SystemApi
+    @TestApi
     public static final int APP_RETURN_UNWANTED     = 1;
     /** @hide */
+    @SystemApi
+    @TestApi
     public static final int APP_RETURN_WANTED_AS_IS = 2;
 
     private final IBinder mBinder;
 
     /** @hide */
+    @SystemApi
+    @TestApi
     public CaptivePortal(IBinder binder) {
         mBinder = binder;
     }
@@ -99,6 +109,8 @@
      * connectivity for apps because the captive portal is still in place.
      * @hide
      */
+    @SystemApi
+    @TestApi
     public void useNetwork() {
         try {
             ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_WANTED_AS_IS);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 61d5a91..5bb24ba 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -15,17 +15,24 @@
  */
 package android.net;
 
+import static android.net.IpSecManager.INVALID_RESOURCE_ID;
+
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.net.IpSecManager.UdpEncapsulationSocket;
+import android.net.SocketKeepalive.Callback;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
@@ -56,6 +63,7 @@
 
 import libcore.net.event.NetworkEventDispatcher;
 
+import java.io.FileDescriptor;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.net.InetAddress;
@@ -64,6 +72,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Executor;
 
 /**
  * Class that answers queries about the state of network connectivity. It also
@@ -254,6 +263,8 @@
      * portal login activity.
      * {@hide}
      */
+    @SystemApi
+    @TestApi
     public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC =
             "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
 
@@ -261,6 +272,8 @@
      * Key for passing a user agent string to the captive portal login activity.
      * {@hide}
      */
+    @SystemApi
+    @TestApi
     public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT =
             "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
 
@@ -909,6 +922,7 @@
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+    @Nullable
     public NetworkInfo getActiveNetworkInfo() {
         try {
             return mService.getActiveNetworkInfo();
@@ -928,6 +942,7 @@
      *        {@code null} if no default network is currently active
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+    @Nullable
     public Network getActiveNetwork() {
         try {
             return mService.getActiveNetwork();
@@ -949,6 +964,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+    @Nullable
     public Network getActiveNetworkForUid(int uid) {
         return getActiveNetworkForUid(uid, false);
     }
@@ -1074,6 +1090,7 @@
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+    @Nullable
     public NetworkInfo getNetworkInfo(int networkType) {
         try {
             return mService.getNetworkInfo(networkType);
@@ -1095,7 +1112,8 @@
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    public NetworkInfo getNetworkInfo(Network network) {
+    @Nullable
+    public NetworkInfo getNetworkInfo(@Nullable Network network) {
         return getNetworkInfoForUid(network, Process.myUid(), false);
     }
 
@@ -1121,6 +1139,7 @@
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+    @NonNull
     public NetworkInfo[] getAllNetworkInfo() {
         try {
             return mService.getAllNetworkInfo();
@@ -1156,6 +1175,7 @@
      * @return an array of {@link Network} objects.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+    @NonNull
     public Network[] getAllNetworks() {
         try {
             return mService.getAllNetworks();
@@ -1230,7 +1250,8 @@
      * @return The {@link LinkProperties} for the network, or {@code null}.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    public LinkProperties getLinkProperties(Network network) {
+    @Nullable
+    public LinkProperties getLinkProperties(@Nullable Network network) {
         try {
             return mService.getLinkProperties(network);
         } catch (RemoteException e) {
@@ -1246,7 +1267,8 @@
      * @return The {@link android.net.NetworkCapabilities} for the network, or {@code null}.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    public NetworkCapabilities getNetworkCapabilities(Network network) {
+    @Nullable
+    public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
         try {
             return mService.getNetworkCapabilities(network);
         } catch (RemoteException e) {
@@ -1684,6 +1706,8 @@
      * {@link PacketKeepaliveCallback#onStopped} if the operation was successful or
      * {@link PacketKeepaliveCallback#onError} if an error occurred.
      *
+     * @deprecated Use {@link SocketKeepalive} instead.
+     *
      * @hide
      */
     public class PacketKeepalive {
@@ -1787,6 +1811,8 @@
     /**
      * Starts an IPsec NAT-T keepalive packet with the specified parameters.
      *
+     * @deprecated Use {@link #createSocketKeepalive} instead.
+     *
      * @hide
      */
     @UnsupportedAppUsage
@@ -1806,6 +1832,62 @@
     }
 
     /**
+     * Request that keepalives be started on a IPsec NAT-T socket.
+     *
+     * @param network The {@link Network} the socket is on.
+     * @param socket The socket that needs to be kept alive.
+     * @param source The source address of the {@link UdpEncapsulationSocket}.
+     * @param destination The destination address of the {@link UdpEncapsulationSocket}.
+     * @param executor The executor on which callback will be invoked. The provided {@link Executor}
+     *                 must run callback sequentially, otherwise the order of callbacks cannot be
+     *                 guaranteed.
+     * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive
+     *        changes. Must be extended by applications that use this API.
+     *
+     * @return A {@link SocketKeepalive} object, which can be used to control this keepalive object.
+     **/
+    public SocketKeepalive createSocketKeepalive(@NonNull Network network,
+            @NonNull UdpEncapsulationSocket socket,
+            @NonNull InetAddress source,
+            @NonNull InetAddress destination,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Callback callback) {
+        return new NattSocketKeepalive(mService, network, socket.getFileDescriptor(),
+            socket.getResourceId(), source, destination, executor, callback);
+    }
+
+    /**
+     * Request that keepalives be started on a IPsec NAT-T socket file descriptor. Directly called
+     * by system apps which don't use IpSecService to create {@link UdpEncapsulationSocket}.
+     *
+     * @param network The {@link Network} the socket is on.
+     * @param fd The {@link FileDescriptor} that needs to be kept alive. The provided
+     *        {@link FileDescriptor} must be bound to a port and the keepalives will be sent from
+     *        that port.
+     * @param source The source address of the {@link UdpEncapsulationSocket}.
+     * @param destination The destination address of the {@link UdpEncapsulationSocket}. The
+     *        keepalive packets will always be sent to port 4500 of the given {@code destination}.
+     * @param executor The executor on which callback will be invoked. The provided {@link Executor}
+     *                 must run callback sequentially, otherwise the order of callbacks cannot be
+     *                 guaranteed.
+     * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive
+     *        changes. Must be extended by applications that use this API.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD)
+    public SocketKeepalive createNattKeepalive(@NonNull Network network,
+            @NonNull FileDescriptor fd,
+            @NonNull InetAddress source,
+            @NonNull InetAddress destination,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Callback callback) {
+        return new NattSocketKeepalive(mService, network, fd, INVALID_RESOURCE_ID /* Unused */,
+                source, destination, executor, callback);
+    }
+
+    /**
      * Ensure that a network route exists to deliver traffic to the specified
      * host via the specified network interface. An attempt to add a route that
      * already exists is ignored, but treated as successful.
@@ -2000,7 +2082,7 @@
      *
      * @param l Previously registered listener.
      */
-    public void removeDefaultNetworkActiveListener(OnNetworkActiveListener l) {
+    public void removeDefaultNetworkActiveListener(@NonNull OnNetworkActiveListener l) {
         INetworkActivityListener rl = mNetworkActivityListeners.get(l);
         Preconditions.checkArgument(rl != null, "Listener was not registered.");
         try {
@@ -2041,6 +2123,16 @@
         return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
     }
 
+    /** @hide */
+    public NetworkRequest getDefaultRequest() {
+        try {
+            // This is not racy as the default request is final in ConnectivityService.
+            return mService.getDefaultRequest();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /* TODO: These permissions checks don't belong in client-side code. Move them to
      * services.jar, possibly in com.android.server.net. */
 
@@ -2475,6 +2567,8 @@
     public static final int TETHER_ERROR_IFACE_CFG_ERROR      = 10;
     /** {@hide} */
     public static final int TETHER_ERROR_PROVISION_FAILED     = 11;
+    /** {@hide} */
+    public static final int TETHER_ERROR_DHCPSERVER_ERROR     = 12;
 
     /**
      * Get a more detailed error code after a Tethering or Untethering
@@ -2528,7 +2622,7 @@
      *             working and non-working connectivity.
      */
     @Deprecated
-    public void reportBadNetwork(Network network) {
+    public void reportBadNetwork(@Nullable Network network) {
         printStackTrace();
         try {
             // One of these will be ignored because it matches system's current state.
@@ -2551,7 +2645,7 @@
      * @param hasConnectivity {@code true} if the application was able to successfully access the
      *                        Internet using {@code network} or {@code false} if not.
      */
-    public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
+    public void reportNetworkConnectivity(@Nullable Network network, boolean hasConnectivity) {
         printStackTrace();
         try {
             mService.reportNetworkConnectivity(network, hasConnectivity);
@@ -2625,6 +2719,7 @@
      * @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no
      *        HTTP proxy is active.
      */
+    @Nullable
     public ProxyInfo getDefaultProxy() {
         return getProxyForNetwork(getBoundNetworkForProcess());
     }
@@ -3156,8 +3251,9 @@
      *
      * @hide
      */
-    public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
-            int timeoutMs, int legacyType, Handler handler) {
+    public void requestNetwork(@NonNull NetworkRequest request,
+            @NonNull NetworkCallback networkCallback, int timeoutMs, int legacyType,
+            @NonNull Handler handler) {
         CallbackHandler cbHandler = new CallbackHandler(handler);
         NetworkCapabilities nc = request.networkCapabilities;
         sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, legacyType, cbHandler);
@@ -3194,7 +3290,8 @@
      * @throws IllegalArgumentException if {@code request} specifies any mutable
      *         {@code NetworkCapabilities}.
      */
-    public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback) {
+    public void requestNetwork(@NonNull NetworkRequest request,
+            @NonNull NetworkCallback networkCallback) {
         requestNetwork(request, networkCallback, getDefaultHandler());
     }
 
@@ -3229,8 +3326,8 @@
      * @throws IllegalArgumentException if {@code request} specifies any mutable
      *         {@code NetworkCapabilities}.
      */
-    public void requestNetwork(
-            NetworkRequest request, NetworkCallback networkCallback, Handler handler) {
+    public void requestNetwork(@NonNull NetworkRequest request,
+            @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
         int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
         CallbackHandler cbHandler = new CallbackHandler(handler);
         requestNetwork(request, networkCallback, 0, legacyType, cbHandler);
@@ -3264,8 +3361,8 @@
      *                  before {@link NetworkCallback#onUnavailable()} is called. The timeout must
      *                  be a positive value (i.e. >0).
      */
-    public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
-            int timeoutMs) {
+    public void requestNetwork(@NonNull NetworkRequest request,
+            @NonNull NetworkCallback networkCallback, int timeoutMs) {
         checkTimeout(timeoutMs);
         int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
         requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
@@ -3298,8 +3395,8 @@
      * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
      *                  before {@link NetworkCallback#onUnavailable} is called.
      */
-    public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
-            Handler handler, int timeoutMs) {
+    public void requestNetwork(@NonNull NetworkRequest request,
+            @NonNull NetworkCallback networkCallback, @NonNull Handler handler, int timeoutMs) {
         checkTimeout(timeoutMs);
         int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
         CallbackHandler cbHandler = new CallbackHandler(handler);
@@ -3371,7 +3468,8 @@
      *         {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
      *         {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
      */
-    public void requestNetwork(NetworkRequest request, PendingIntent operation) {
+    public void requestNetwork(@NonNull NetworkRequest request,
+            @NonNull PendingIntent operation) {
         printStackTrace();
         checkPendingIntentNotNull(operation);
         try {
@@ -3395,7 +3493,7 @@
      *                  {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} with the
      *                  corresponding NetworkRequest you'd like to remove. Cannot be null.
      */
-    public void releaseNetworkRequest(PendingIntent operation) {
+    public void releaseNetworkRequest(@NonNull PendingIntent operation) {
         printStackTrace();
         checkPendingIntentNotNull(operation);
         try {
@@ -3428,7 +3526,8 @@
      *                        The callback is invoked on the default internal Handler.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    public void registerNetworkCallback(NetworkRequest request, NetworkCallback networkCallback) {
+    public void registerNetworkCallback(@NonNull NetworkRequest request,
+            @NonNull NetworkCallback networkCallback) {
         registerNetworkCallback(request, networkCallback, getDefaultHandler());
     }
 
@@ -3443,8 +3542,8 @@
      * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    public void registerNetworkCallback(
-            NetworkRequest request, NetworkCallback networkCallback, Handler handler) {
+    public void registerNetworkCallback(@NonNull NetworkRequest request,
+            @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
         CallbackHandler cbHandler = new CallbackHandler(handler);
         NetworkCapabilities nc = request.networkCapabilities;
         sendRequestForNetwork(nc, networkCallback, 0, LISTEN, TYPE_NONE, cbHandler);
@@ -3480,7 +3579,8 @@
      *                  comes from {@link PendingIntent#getBroadcast}. Cannot be null.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    public void registerNetworkCallback(NetworkRequest request, PendingIntent operation) {
+    public void registerNetworkCallback(@NonNull NetworkRequest request,
+            @NonNull PendingIntent operation) {
         printStackTrace();
         checkPendingIntentNotNull(operation);
         try {
@@ -3502,7 +3602,7 @@
      *                        The callback is invoked on the default internal Handler.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    public void registerDefaultNetworkCallback(NetworkCallback networkCallback) {
+    public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback) {
         registerDefaultNetworkCallback(networkCallback, getDefaultHandler());
     }
 
@@ -3516,7 +3616,8 @@
      * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    public void registerDefaultNetworkCallback(NetworkCallback networkCallback, Handler handler) {
+    public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
+            @NonNull Handler handler) {
         // This works because if the NetworkCapabilities are null,
         // ConnectivityService takes them from the default request.
         //
@@ -3541,7 +3642,7 @@
      * @param network {@link Network} specifying which network you're interested.
      * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
      */
-    public boolean requestBandwidthUpdate(Network network) {
+    public boolean requestBandwidthUpdate(@NonNull Network network) {
         try {
             return mService.requestBandwidthUpdate(network);
         } catch (RemoteException e) {
@@ -3562,7 +3663,7 @@
      *
      * @param networkCallback The {@link NetworkCallback} used when making the request.
      */
-    public void unregisterNetworkCallback(NetworkCallback networkCallback) {
+    public void unregisterNetworkCallback(@NonNull NetworkCallback networkCallback) {
         printStackTrace();
         checkCallbackNotNull(networkCallback);
         final List<NetworkRequest> reqs = new ArrayList<>();
@@ -3601,7 +3702,7 @@
      *                  {@link #registerNetworkCallback(NetworkRequest, android.app.PendingIntent)}.
      *                  Cannot be null.
      */
-    public void unregisterNetworkCallback(PendingIntent operation) {
+    public void unregisterNetworkCallback(@NonNull PendingIntent operation) {
         checkPendingIntentNotNull(operation);
         releaseNetworkRequest(operation);
     }
@@ -3665,6 +3766,19 @@
     }
 
     /**
+     * Determine whether the device is configured to avoid bad wifi.
+     * @hide
+     */
+    @SystemApi
+    public boolean getAvoidBadWifi() {
+        try {
+            return mService.getAvoidBadWifi();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * It is acceptable to briefly use multipath data to provide seamless connectivity for
      * time-sensitive user-facing operations when the system default network is temporarily
      * unresponsive. The amount of data should be limited (less than one megabyte for every call to
@@ -3723,7 +3837,7 @@
      * @return a bitwise OR of zero or more of the  {@code MULTIPATH_PREFERENCE_*} constants.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    public @MultipathPreference int getMultipathPreference(Network network) {
+    public @MultipathPreference int getMultipathPreference(@Nullable Network network) {
         try {
             return mService.getMultipathPreference(network);
         } catch (RemoteException e) {
@@ -3761,7 +3875,7 @@
      *                the current binding.
      * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
      */
-    public boolean bindProcessToNetwork(Network network) {
+    public boolean bindProcessToNetwork(@Nullable Network network) {
         // Forcing callers to call through non-static function ensures ConnectivityManager
         // instantiated.
         return setProcessDefaultNetwork(network);
@@ -3789,7 +3903,7 @@
      *             is a direct replacement.
      */
     @Deprecated
-    public static boolean setProcessDefaultNetwork(Network network) {
+    public static boolean setProcessDefaultNetwork(@Nullable Network network) {
         int netId = (network == null) ? NETID_UNSET : network.netId;
         if (netId == NetworkUtils.getBoundNetworkForProcess()) {
             return true;
@@ -3820,6 +3934,7 @@
      *
      * @return {@code Network} to which this process is bound, or {@code null}.
      */
+    @Nullable
     public Network getBoundNetworkForProcess() {
         // Forcing callers to call thru non-static function ensures ConnectivityManager
         // instantiated.
@@ -3836,6 +3951,7 @@
      *             {@code getBoundNetworkForProcess} is a direct replacement.
      */
     @Deprecated
+    @Nullable
     public static Network getProcessDefaultNetwork() {
         int netId = NetworkUtils.getBoundNetworkForProcess();
         if (netId == NETID_UNSET) return null;
@@ -3962,6 +4078,7 @@
      *
      * @return Hash of network watchlist config file. Null if config does not exist.
      */
+    @Nullable
     public byte[] getNetworkWatchlistConfigHash() {
         try {
             return mService.getNetworkWatchlistConfigHash();
@@ -3983,8 +4100,8 @@
      * (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) {
+    public int getConnectionOwnerUid(int protocol, @NonNull InetSocketAddress local,
+            @NonNull InetSocketAddress remote) {
         ConnectionInfo connectionInfo = new ConnectionInfo(protocol, local, remote);
         try {
             return mService.getConnectionOwnerUid(connectionInfo);
diff --git a/core/java/android/net/DhcpResultsParcelable.aidl b/core/java/android/net/DhcpResultsParcelable.aidl
new file mode 100644
index 0000000..cf5629b
--- /dev/null
+++ b/core/java/android/net/DhcpResultsParcelable.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.StaticIpConfigurationParcelable;
+
+parcelable DhcpResultsParcelable {
+    StaticIpConfigurationParcelable baseConfiguration;
+    int leaseDuration;
+    int mtu;
+    String serverAddress;
+    String vendorInfo;
+}
\ No newline at end of file
diff --git a/core/java/android/net/DnsPacket.java b/core/java/android/net/DnsPacket.java
new file mode 100644
index 0000000..458fb34
--- /dev/null
+++ b/core/java/android/net/DnsPacket.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.text.TextUtils;
+
+import com.android.internal.util.BitUtils;
+
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.text.DecimalFormat;
+import java.text.FieldPosition;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringJoiner;
+
+/**
+ * Defines basic data for DNS protocol based on RFC 1035.
+ * Subclasses create the specific format used in DNS packet.
+ *
+ * @hide
+ */
+public abstract class DnsPacket {
+    public class DnsHeader {
+        private static final String TAG = "DnsHeader";
+        public final int id;
+        public final int flags;
+        public final int rcode;
+        private final int[] mSectionCount;
+
+        /**
+         * Create a new DnsHeader from a positioned ByteBuffer.
+         *
+         * The ByteBuffer must be in network byte order (which is the default).
+         * Reads the passed ByteBuffer from its current position and decodes a DNS header.
+         * When this constructor returns, the reading position of the ByteBuffer has been
+         * advanced to the end of the DNS header record.
+         * This is meant to chain with other methods reading a DNS response in sequence.
+         *
+         */
+        DnsHeader(@NonNull ByteBuffer buf) throws BufferUnderflowException {
+            id = BitUtils.uint16(buf.getShort());
+            flags = BitUtils.uint16(buf.getShort());
+            rcode = flags & 0xF;
+            mSectionCount = new int[NUM_SECTIONS];
+            for (int i = 0; i < NUM_SECTIONS; ++i) {
+                mSectionCount[i] = BitUtils.uint16(buf.getShort());
+            }
+        }
+
+        /**
+         * Get section count by section type.
+         */
+        public int getSectionCount(int sectionType) {
+            return mSectionCount[sectionType];
+        }
+    }
+
+    public class DnsSection {
+        private static final int MAXNAMESIZE = 255;
+        private static final int MAXLABELSIZE = 63;
+        private static final int MAXLABELCOUNT = 128;
+        private static final int NAME_NORMAL = 0;
+        private static final int NAME_COMPRESSION = 0xC0;
+        private final DecimalFormat byteFormat = new DecimalFormat();
+        private final FieldPosition pos = new FieldPosition(0);
+
+        private static final String TAG = "DnsSection";
+
+        public final String dName;
+        public final int nsType;
+        public final int nsClass;
+        public final long ttl;
+        private final byte[] mRR;
+
+        /**
+         * Create a new DnsSection from a positioned ByteBuffer.
+         *
+         * The ByteBuffer must be in network byte order (which is the default).
+         * Reads the passed ByteBuffer from its current position and decodes a DNS section.
+         * When this constructor returns, the reading position of the ByteBuffer has been
+         * advanced to the end of the DNS header record.
+         * This is meant to chain with other methods reading a DNS response in sequence.
+         *
+         */
+        DnsSection(int sectionType, @NonNull ByteBuffer buf)
+                throws BufferUnderflowException, ParseException {
+            dName = parseName(buf, 0 /* Parse depth */);
+            if (dName.length() > MAXNAMESIZE) {
+                throw new ParseException("Parse name fail, name size is too long");
+            }
+            nsType = BitUtils.uint16(buf.getShort());
+            nsClass = BitUtils.uint16(buf.getShort());
+
+            if (sectionType != QDSECTION) {
+                ttl = BitUtils.uint32(buf.getInt());
+                final int length = BitUtils.uint16(buf.getShort());
+                mRR = new byte[length];
+                buf.get(mRR);
+            } else {
+                ttl = 0;
+                mRR = null;
+            }
+        }
+
+        /**
+         * Get a copy of rr.
+         */
+        @Nullable public byte[] getRR() {
+            return (mRR == null) ? null : mRR.clone();
+        }
+
+        /**
+         * Convert label from {@code byte[]} to {@code String}
+         *
+         * It follows the same converting rule as native layer.
+         * (See ns_name.c in libc)
+         *
+         */
+        private String labelToString(@NonNull byte[] label) {
+            final StringBuffer sb = new StringBuffer();
+            for (int i = 0; i < label.length; ++i) {
+                int b = BitUtils.uint8(label[i]);
+                // Control characters and non-ASCII characters.
+                if (b <= 0x20 || b >= 0x7f) {
+                    sb.append('\\');
+                    byteFormat.format(b, sb, pos);
+                } else if (b == '"' || b == '.' || b == ';' || b == '\\'
+                        || b == '(' || b == ')' || b == '@' || b == '$') {
+                    sb.append('\\');
+                    sb.append((char) b);
+                } else {
+                    sb.append((char) b);
+                }
+            }
+            return sb.toString();
+        }
+
+        private String parseName(@NonNull ByteBuffer buf, int depth) throws
+                BufferUnderflowException, ParseException {
+            if (depth > MAXLABELCOUNT) throw new ParseException("Parse name fails, too many labels");
+            final int len = BitUtils.uint8(buf.get());
+            final int mask = len & NAME_COMPRESSION;
+            if (0 == len) {
+                return "";
+            } else if (mask != NAME_NORMAL && mask != NAME_COMPRESSION) {
+                throw new ParseException("Parse name fail, bad label type");
+            } else if (mask == NAME_COMPRESSION) {
+                // Name compression based on RFC 1035 - 4.1.4 Message compression
+                final int offset = ((len & ~NAME_COMPRESSION) << 8) + BitUtils.uint8(buf.get());
+                final int oldPos = buf.position();
+                if (offset >= oldPos - 2) {
+                    throw new ParseException("Parse compression name fail, invalid compression");
+                }
+                buf.position(offset);
+                final String pointed = parseName(buf, depth + 1);
+                buf.position(oldPos);
+                return pointed;
+            } else {
+                final byte[] label = new byte[len];
+                buf.get(label);
+                final String head = labelToString(label);
+                if (head.length() > MAXLABELSIZE) {
+                    throw new ParseException("Parse name fail, invalid label length");
+                }
+                final String tail = parseName(buf, depth + 1);
+                return TextUtils.isEmpty(tail) ? head : head + "." + tail;
+            }
+        }
+    }
+
+    public static final int QDSECTION = 0;
+    public static final int ANSECTION = 1;
+    public static final int NSSECTION = 2;
+    public static final int ARSECTION = 3;
+    private static final int NUM_SECTIONS = ARSECTION + 1;
+
+    private static final String TAG = DnsPacket.class.getSimpleName();
+
+    protected final DnsHeader mHeader;
+    protected final List<DnsSection>[] mSections;
+
+    public static class ParseException extends Exception {
+        public ParseException(String msg) {
+            super(msg);
+        }
+
+        public ParseException(String msg, Throwable cause) {
+            super(msg, cause);
+        }
+    }
+
+    protected DnsPacket(@NonNull byte[] data) throws ParseException {
+        if (null == data) throw new ParseException("Parse header failed, null input data");
+        final ByteBuffer buffer;
+        try {
+            buffer = ByteBuffer.wrap(data);
+            mHeader = new DnsHeader(buffer);
+        } catch (BufferUnderflowException e) {
+            throw new ParseException("Parse Header fail, bad input data", e);
+        }
+
+        mSections = new ArrayList[NUM_SECTIONS];
+
+        for (int i = 0; i < NUM_SECTIONS; ++i) {
+            final int count = mHeader.getSectionCount(i);
+            if (count > 0) {
+                mSections[i] = new ArrayList(count);
+            }
+            for (int j = 0; j < count; ++j) {
+                try {
+                    mSections[i].add(new DnsSection(i, buffer));
+                } catch (BufferUnderflowException e) {
+                    throw new ParseException("Parse section fail", e);
+                }
+            }
+        }
+    }
+}
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
new file mode 100644
index 0000000..6d54264
--- /dev/null
+++ b/core/java/android/net/DnsResolver.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.net.NetworkUtils.resNetworkQuery;
+import static android.net.NetworkUtils.resNetworkResult;
+import static android.net.NetworkUtils.resNetworkSend;
+import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
+import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.MessageQueue;
+import android.system.ErrnoException;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+
+/**
+ * Dns resolver class for asynchronous dns querying
+ *
+ */
+public final class DnsResolver {
+    private static final String TAG = "DnsResolver";
+    private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
+    private static final int MAXPACKET = 8 * 1024;
+
+    @IntDef(prefix = { "CLASS_" }, value = {
+            CLASS_IN
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface QueryClass {}
+    public static final int CLASS_IN = 1;
+
+    @IntDef(prefix = { "TYPE_" },  value = {
+            TYPE_A,
+            TYPE_AAAA
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface QueryType {}
+    public static final int TYPE_A = 1;
+    public static final int TYPE_AAAA = 28;
+
+    @IntDef(prefix = { "FLAG_" }, value = {
+            FLAG_EMPTY,
+            FLAG_NO_RETRY,
+            FLAG_NO_CACHE_STORE,
+            FLAG_NO_CACHE_LOOKUP
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface QueryFlag {}
+    public static final int FLAG_EMPTY = 0;
+    public static final int FLAG_NO_RETRY = 1 << 0;
+    public static final int FLAG_NO_CACHE_STORE = 1 << 1;
+    public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2;
+
+    private static final int DNS_RAW_RESPONSE = 1;
+
+    private static final int NETID_UNSET = 0;
+
+    private static final DnsResolver sInstance = new DnsResolver();
+
+    /**
+     * listener for receiving raw answers
+     */
+    public interface RawAnswerListener {
+        /**
+         * {@code byte[]} is {@code null} if query timed out
+         */
+        void onAnswer(@Nullable byte[] answer);
+    }
+
+    /**
+     * listener for receiving parsed answers
+     */
+    public interface InetAddressAnswerListener {
+        /**
+         * Will be called exactly once with all the answers to the query.
+         * size of addresses will be zero if no available answer could be parsed.
+         */
+        void onAnswer(@NonNull List<InetAddress> addresses);
+    }
+
+    /**
+     * Get instance for DnsResolver
+     */
+    public static DnsResolver getInstance() {
+        return sInstance;
+    }
+
+    private DnsResolver() {}
+
+    /**
+     * Pass in a blob and corresponding setting,
+     * get a blob back asynchronously with the entire raw answer.
+     *
+     * @param network {@link Network} specifying which network for querying.
+     *         {@code null} for query on default network.
+     * @param query blob message
+     * @param flags flags as a combination of the FLAGS_* constants
+     * @param handler {@link Handler} to specify the thread
+     *         upon which the {@link RawAnswerListener} will be invoked.
+     * @param listener a {@link RawAnswerListener} which will be called to notify the caller
+     *         of the result of dns query.
+     */
+    public void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
+            @NonNull Handler handler, @NonNull RawAnswerListener listener) throws ErrnoException {
+        final FileDescriptor queryfd = resNetworkSend((network != null
+                ? network.netId : NETID_UNSET), query, query.length, flags);
+        registerFDListener(handler.getLooper().getQueue(), queryfd,
+                answerbuf -> listener.onAnswer(answerbuf));
+    }
+
+    /**
+     * Pass in a domain name and corresponding setting,
+     * get a blob back asynchronously with the entire raw answer.
+     *
+     * @param network {@link Network} specifying which network for querying.
+     *         {@code null} for query on default network.
+     * @param domain domain name for querying
+     * @param nsClass dns class as one of the CLASS_* constants
+     * @param nsType dns resource record (RR) type as one of the TYPE_* constants
+     * @param flags flags as a combination of the FLAGS_* constants
+     * @param handler {@link Handler} to specify the thread
+     *         upon which the {@link RawAnswerListener} will be invoked.
+     * @param listener a {@link RawAnswerListener} which will be called to notify the caller
+     *         of the result of dns query.
+     */
+    public void query(@Nullable Network network, @NonNull String domain, @QueryClass int nsClass,
+            @QueryType int nsType, @QueryFlag int flags,
+            @NonNull Handler handler, @NonNull RawAnswerListener listener) throws ErrnoException {
+        final FileDescriptor queryfd = resNetworkQuery((network != null
+                ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
+        registerFDListener(handler.getLooper().getQueue(), queryfd,
+                answerbuf -> listener.onAnswer(answerbuf));
+    }
+
+    /**
+     * Pass in a domain name and corresponding setting,
+     * get back a set of InetAddresses asynchronously.
+     *
+     * @param network {@link Network} specifying which network for querying.
+     *         {@code null} for query on default network.
+     * @param domain domain name for querying
+     * @param flags flags as a combination of the FLAGS_* constants
+     * @param handler {@link Handler} to specify the thread
+     *         upon which the {@link InetAddressAnswerListener} will be invoked.
+     * @param listener an {@link InetAddressAnswerListener} which will be called to
+     *         notify the caller of the result of dns query.
+     *
+     */
+    public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags,
+            @NonNull Handler handler, @NonNull InetAddressAnswerListener listener)
+            throws ErrnoException {
+        final FileDescriptor v4fd = resNetworkQuery((network != null
+                ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags);
+        final FileDescriptor v6fd = resNetworkQuery((network != null
+                ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags);
+
+        final InetAddressAnswerAccumulator accmulator =
+                new InetAddressAnswerAccumulator(2, listener);
+        final Consumer<byte[]> consumer = answerbuf ->
+                accmulator.accumulate(parseAnswers(answerbuf));
+
+        registerFDListener(handler.getLooper().getQueue(), v4fd, consumer);
+        registerFDListener(handler.getLooper().getQueue(), v6fd, consumer);
+    }
+
+    private void registerFDListener(@NonNull MessageQueue queue,
+            @NonNull FileDescriptor queryfd, @NonNull Consumer<byte[]> answerConsumer) {
+        queue.addOnFileDescriptorEventListener(
+                queryfd,
+                FD_EVENTS,
+                (fd, events) -> {
+                    byte[] answerbuf = null;
+                    try {
+                    // TODO: Implement result function in Java side instead of using JNI
+                    //       Because JNI method close fd prior than unregistering fd on
+                    //       event listener.
+                        answerbuf = resNetworkResult(fd);
+                    } catch (ErrnoException e) {
+                        Log.e(TAG, "resNetworkResult:" + e.toString());
+                    }
+                    answerConsumer.accept(answerbuf);
+
+                    // Unregister this fd listener
+                    return 0;
+                });
+    }
+
+    private class DnsAddressAnswer extends DnsPacket {
+        private static final String TAG = "DnsResolver.DnsAddressAnswer";
+        private static final boolean DBG = false;
+
+        private final int mQueryType;
+
+        DnsAddressAnswer(@NonNull byte[] data) throws ParseException {
+            super(data);
+            if ((mHeader.flags & (1 << 15)) == 0) {
+                throw new ParseException("Not an answer packet");
+            }
+            if (mHeader.rcode != 0) {
+                throw new ParseException("Response error, rcode:" + mHeader.rcode);
+            }
+            if (mHeader.getSectionCount(ANSECTION) == 0) {
+                throw new ParseException("No available answer");
+            }
+            if (mHeader.getSectionCount(QDSECTION) == 0) {
+                throw new ParseException("No question found");
+            }
+            // Assume only one question per answer packet. (RFC1035)
+            mQueryType = mSections[QDSECTION].get(0).nsType;
+        }
+
+        public @NonNull List<InetAddress> getAddresses() {
+            final List<InetAddress> results = new ArrayList<InetAddress>();
+            for (final DnsSection ansSec : mSections[ANSECTION]) {
+                // Only support A and AAAA, also ignore answers if query type != answer type.
+                int nsType = ansSec.nsType;
+                if (nsType != mQueryType || (nsType != TYPE_A && nsType != TYPE_AAAA)) {
+                    continue;
+                }
+                try {
+                    results.add(InetAddress.getByAddress(ansSec.getRR()));
+                } catch (UnknownHostException e) {
+                    if (DBG) {
+                        Log.w(TAG, "rr to address fail");
+                    }
+                }
+            }
+            return results;
+        }
+    }
+
+    private @Nullable List<InetAddress> parseAnswers(@Nullable byte[] data) {
+        try {
+            return (data == null) ? null : new DnsAddressAnswer(data).getAddresses();
+        } catch (DnsPacket.ParseException e) {
+            Log.e(TAG, "Parse answer fail " + e.getMessage());
+            return null;
+        }
+    }
+
+    private class InetAddressAnswerAccumulator {
+        private final List<InetAddress> mAllAnswers;
+        private final InetAddressAnswerListener mAnswerListener;
+        private final int mTargetAnswerCount;
+        private int mReceivedAnswerCount = 0;
+
+        InetAddressAnswerAccumulator(int size, @NonNull InetAddressAnswerListener listener) {
+            mTargetAnswerCount = size;
+            mAllAnswers = new ArrayList<>();
+            mAnswerListener = listener;
+        }
+
+        public void accumulate(@Nullable List<InetAddress> answer) {
+            if (null != answer) {
+                mAllAnswers.addAll(answer);
+            }
+            if (++mReceivedAnswerCount == mTargetAnswerCount) {
+                mAnswerListener.onAnswer(mAllAnswers);
+            }
+        }
+    }
+}
diff --git a/core/java/android/net/ICaptivePortal.aidl b/core/java/android/net/ICaptivePortal.aidl
index a013e79..56ae57d 100644
--- a/core/java/android/net/ICaptivePortal.aidl
+++ b/core/java/android/net/ICaptivePortal.aidl
@@ -20,7 +20,6 @@
  * Interface to inform NetworkMonitor of decisions of app handling captive portal.
  * @hide
  */
-interface ICaptivePortal
-{
-    oneway void appResponse(int response);
+oneway interface ICaptivePortal {
+    void appResponse(int response);
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index e7d441d..e97060a 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -165,8 +165,11 @@
     void setAvoidUnvalidated(in Network network);
     void startCaptivePortalApp(in Network network);
 
+    boolean getAvoidBadWifi();
     int getMultipathPreference(in Network Network);
 
+    NetworkRequest getDefaultRequest();
+
     int getRestoreDefaultNetworkDelay(int networkType);
 
     boolean addVpnAddress(String address, int prefixLength);
@@ -178,6 +181,10 @@
     void startNattKeepalive(in Network network, int intervalSeconds, in Messenger messenger,
             in IBinder binder, String srcAddr, int srcPort, String dstAddr);
 
+    void startNattKeepaliveWithFd(in Network network, in FileDescriptor fd, int resourceId,
+            int intervalSeconds, in Messenger messenger, in IBinder binder, String srcAddr,
+            String dstAddr);
+
     void stopKeepalive(in Network network, int slot);
 
     String getCaptivePortalServerUrl();
@@ -185,4 +192,6 @@
     byte[] getNetworkWatchlistConfigHash();
 
     int getConnectionOwnerUid(in ConnectionInfo connectionInfo);
+    boolean isCallerCurrentAlwaysOnVpnApp();
+    boolean isCallerCurrentAlwaysOnVpnLockdownApp();
 }
diff --git a/core/java/android/net/IIpMemoryStore.aidl b/core/java/android/net/IIpMemoryStore.aidl
new file mode 100644
index 0000000..6f88dec
--- /dev/null
+++ b/core/java/android/net/IIpMemoryStore.aidl
@@ -0,0 +1,113 @@
+/*
+ * 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.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.NetworkAttributesParcelable;
+import android.net.ipmemorystore.IOnBlobRetrievedListener;
+import android.net.ipmemorystore.IOnL2KeyResponseListener;
+import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
+import android.net.ipmemorystore.IOnSameNetworkResponseListener;
+import android.net.ipmemorystore.IOnStatusListener;
+
+/** {@hide} */
+oneway interface IIpMemoryStore {
+    /**
+     * Store network attributes for a given L2 key.
+     * If L2Key is null, choose automatically from the attributes ; passing null is equivalent to
+     * calling findL2Key with the attributes and storing in the returned value.
+     *
+     * @param l2Key The L2 key for the L2 network. Clients that don't know or care about the L2
+     *              key and only care about grouping can pass a unique ID here like the ones
+     *              generated by {@code java.util.UUID.randomUUID()}, but keep in mind the low
+     *              relevance of such a network will lead to it being evicted soon if it's not
+     *              refreshed. Use findL2Key to try and find a similar L2Key to these attributes.
+     * @param attributes The attributes for this network.
+     * @param listener A listener that will be invoked to inform of the completion of this call,
+     *                 or null if the client is not interested in learning about success/failure.
+     * @return (through the listener) The L2 key. This is useful if the L2 key was not specified.
+     *         If the call failed, the L2 key will be null.
+     */
+    void storeNetworkAttributes(String l2Key, in NetworkAttributesParcelable attributes,
+            IOnStatusListener listener);
+
+    /**
+     * Store a binary blob associated with an L2 key and a name.
+     *
+     * @param l2Key The L2 key for this network.
+     * @param clientId The ID of the client.
+     * @param name The name of this data.
+     * @param data The data to store.
+     * @param listener A listener to inform of the completion of this call, or null if the client
+     *        is not interested in learning about success/failure.
+     * @return (through the listener) A status to indicate success or failure.
+     */
+    void storeBlob(String l2Key, String clientId, String name, in Blob data,
+            IOnStatusListener listener);
+
+    /**
+     * Returns the best L2 key associated with the attributes.
+     *
+     * This will find a record that would be in the same group as the passed attributes. This is
+     * useful to choose the key for storing a sample or private data when the L2 key is not known.
+     * If multiple records are group-close to these attributes, the closest match is returned.
+     * If multiple records have the same closeness, the one with the smaller (unicode codepoint
+     * order) L2 key is returned.
+     * If no record matches these attributes, null is returned.
+     *
+     * @param attributes The attributes of the network to find.
+     * @param listener The listener that will be invoked to return the answer.
+     * @return (through the listener) The L2 key if one matched, or null.
+     */
+    void findL2Key(in NetworkAttributesParcelable attributes, IOnL2KeyResponseListener listener);
+
+    /**
+     * Returns whether, to the best of the store's ability to tell, the two specified L2 keys point
+     * to the same L3 network. Group-closeness is used to determine this.
+     *
+     * @param l2Key1 The key for the first network.
+     * @param l2Key2 The key for the second network.
+     * @param listener The listener that will be invoked to return the answer.
+     * @return (through the listener) A SameL3NetworkResponse containing the answer and confidence.
+     */
+    void isSameNetwork(String l2Key1, String l2Key2, IOnSameNetworkResponseListener listener);
+
+    /**
+     * Retrieve the network attributes for a key.
+     * If no record is present for this key, this will return null attributes.
+     *
+     * @param l2Key The key of the network to query.
+     * @param listener The listener that will be invoked to return the answer.
+     * @return (through the listener) The network attributes and the L2 key associated with
+     *         the query.
+     */
+    void retrieveNetworkAttributes(String l2Key, IOnNetworkAttributesRetrieved listener);
+
+    /**
+     * Retrieve previously stored private data.
+     * If no data was stored for this L2 key and name this will return null.
+     *
+     * @param l2Key The L2 key.
+     * @param clientId The id of the client that stored this data.
+     * @param name The name of the data.
+     * @param listener The listener that will be invoked to return the answer.
+     * @return (through the listener) The private data (or null), with the L2 key
+     *         and the name of the data associated with the query.
+     */
+    void retrieveBlob(String l2Key, String clientId, String name,
+            IOnBlobRetrievedListener listener);
+}
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl
index b7af374..f0fe92e 100644
--- a/core/java/android/net/INetworkManagementEventObserver.aidl
+++ b/core/java/android/net/INetworkManagementEventObserver.aidl
@@ -24,7 +24,7 @@
  *
  * @hide
  */
-interface INetworkManagementEventObserver {
+oneway interface INetworkManagementEventObserver {
     /**
      * Interface configuration status has changed.
      *
diff --git a/core/java/android/net/INetworkMonitor.aidl b/core/java/android/net/INetworkMonitor.aidl
new file mode 100644
index 0000000..41f969a
--- /dev/null
+++ b/core/java/android/net/INetworkMonitor.aidl
@@ -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 perNmissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import android.net.PrivateDnsConfigParcel;
+
+/** @hide */
+oneway interface INetworkMonitor {
+    // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.
+    // The network should be used as a default internet connection.  It was found to be:
+    // 1. a functioning network providing internet access, or
+    // 2. a captive portal and the user decided to use it as is.
+    const int NETWORK_TEST_RESULT_VALID = 0;
+
+    // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.
+    // The network should not be used as a default internet connection.  It was found to be:
+    // 1. a captive portal and the user is prompted to sign-in, or
+    // 2. a captive portal and the user did not want to use it, or
+    // 3. a broken network (e.g. DNS failed, connect failed, HTTP request failed).
+    const int NETWORK_TEST_RESULT_INVALID = 1;
+
+    void start();
+    void launchCaptivePortalApp();
+    void forceReevaluation(int uid);
+    void notifyPrivateDnsChanged(in PrivateDnsConfigParcel config);
+    void notifyDnsResponse(int returnCode);
+    void notifySystemReady();
+    void notifyNetworkConnected();
+    void notifyNetworkDisconnected();
+    void notifyLinkPropertiesChanged();
+    void notifyNetworkCapabilitiesChanged();
+}
\ No newline at end of file
diff --git a/core/java/android/net/INetworkMonitorCallbacks.aidl b/core/java/android/net/INetworkMonitorCallbacks.aidl
new file mode 100644
index 0000000..0bc2575
--- /dev/null
+++ b/core/java/android/net/INetworkMonitorCallbacks.aidl
@@ -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.net;
+
+import android.net.INetworkMonitor;
+import android.net.PrivateDnsConfigParcel;
+
+/** @hide */
+oneway interface INetworkMonitorCallbacks {
+    void onNetworkMonitorCreated(in INetworkMonitor networkMonitor);
+    void notifyNetworkTested(int testResult, @nullable String redirectUrl);
+    void notifyPrivateDnsConfigResolved(in PrivateDnsConfigParcel config);
+    void showProvisioningNotification(String action);
+    void hideProvisioningNotification();
+}
\ No newline at end of file
diff --git a/core/java/android/net/INetworkStackConnector.aidl b/core/java/android/net/INetworkStackConnector.aidl
index 29f8828..8b64f1c 100644
--- a/core/java/android/net/INetworkStackConnector.aidl
+++ b/core/java/android/net/INetworkStackConnector.aidl
@@ -15,7 +15,15 @@
  */
 package android.net;
 
+import android.net.INetworkMonitorCallbacks;
+import android.net.dhcp.DhcpServingParamsParcel;
+import android.net.dhcp.IDhcpServerCallbacks;
+import android.net.ip.IIpClientCallbacks;
+
 /** @hide */
 oneway interface INetworkStackConnector {
-    // TODO: requestDhcpServer(), etc. will go here
+    void makeDhcpServer(in String ifName, in DhcpServingParamsParcel params,
+        in IDhcpServerCallbacks cb);
+    void makeNetworkMonitor(int netId, String name, in INetworkMonitorCallbacks cb);
+    void makeIpClient(in String ifName, in IIpClientCallbacks callbacks);
 }
\ No newline at end of file
diff --git a/core/java/android/net/INetworkStackStatusCallback.aidl b/core/java/android/net/INetworkStackStatusCallback.aidl
new file mode 100644
index 0000000..51032d8
--- /dev/null
+++ b/core/java/android/net/INetworkStackStatusCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+/** @hide */
+oneway interface INetworkStackStatusCallback {
+    void onStatusAvailable(int statusCode);
+}
\ No newline at end of file
diff --git a/core/java/android/net/InitialConfigurationParcelable.aidl b/core/java/android/net/InitialConfigurationParcelable.aidl
new file mode 100644
index 0000000..bdda355
--- /dev/null
+++ b/core/java/android/net/InitialConfigurationParcelable.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddressParcelable;
+
+parcelable InitialConfigurationParcelable {
+    LinkAddressParcelable[] ipAddresses;
+    IpPrefixParcelable[] directlyConnectedRoutes;
+    String[] dnsServers;
+    String gateway;
+}
\ No newline at end of file
diff --git a/core/java/android/net/IpMemoryStore.java b/core/java/android/net/IpMemoryStore.java
new file mode 100644
index 0000000..b35f097
--- /dev/null
+++ b/core/java/android/net/IpMemoryStore.java
@@ -0,0 +1,174 @@
+/*
+ * 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.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.IOnBlobRetrievedListener;
+import android.net.ipmemorystore.IOnL2KeyResponseListener;
+import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
+import android.net.ipmemorystore.IOnSameNetworkResponseListener;
+import android.net.ipmemorystore.IOnStatusListener;
+import android.net.ipmemorystore.NetworkAttributes;
+import android.os.RemoteException;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * The interface for system components to access the IP memory store.
+ * @see com.android.server.net.ipmemorystore.IpMemoryStoreService
+ * @hide
+ */
+@SystemService(Context.IP_MEMORY_STORE_SERVICE)
+public class IpMemoryStore {
+    @NonNull final Context mContext;
+    @NonNull final IIpMemoryStore mService;
+
+    public IpMemoryStore(@NonNull final Context context, @NonNull final IIpMemoryStore service) {
+        mContext = Preconditions.checkNotNull(context, "missing context");
+        mService = Preconditions.checkNotNull(service, "missing IIpMemoryStore");
+    }
+
+    /**
+     * Store network attributes for a given L2 key.
+     * If L2Key is null, choose automatically from the attributes ; passing null is equivalent to
+     * calling findL2Key with the attributes and storing in the returned value.
+     *
+     * @param l2Key The L2 key for the L2 network. Clients that don't know or care about the L2
+     *              key and only care about grouping can pass a unique ID here like the ones
+     *              generated by {@code java.util.UUID.randomUUID()}, but keep in mind the low
+     *              relevance of such a network will lead to it being evicted soon if it's not
+     *              refreshed. Use findL2Key to try and find a similar L2Key to these attributes.
+     * @param attributes The attributes for this network.
+     * @param listener A listener that will be invoked to inform of the completion of this call,
+     *                 or null if the client is not interested in learning about success/failure.
+     * Through the listener, returns the L2 key. This is useful if the L2 key was not specified.
+     * If the call failed, the L2 key will be null.
+     */
+    public void storeNetworkAttributes(@NonNull final String l2Key,
+            @NonNull final NetworkAttributes attributes,
+            @Nullable final IOnStatusListener listener) {
+        try {
+            mService.storeNetworkAttributes(l2Key, attributes.toParcelable(), listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Store a binary blob associated with an L2 key and a name.
+     *
+     * @param l2Key The L2 key for this network.
+     * @param clientId The ID of the client.
+     * @param name The name of this data.
+     * @param data The data to store.
+     * @param listener A listener to inform of the completion of this call, or null if the client
+     *        is not interested in learning about success/failure.
+     * Through the listener, returns a status to indicate success or failure.
+     */
+    public void storeBlob(@NonNull final String l2Key, @NonNull final String clientId,
+            @NonNull final String name, @NonNull final Blob data,
+            @Nullable final IOnStatusListener listener) {
+        try {
+            mService.storeBlob(l2Key, clientId, name, data, listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the best L2 key associated with the attributes.
+     *
+     * This will find a record that would be in the same group as the passed attributes. This is
+     * useful to choose the key for storing a sample or private data when the L2 key is not known.
+     * If multiple records are group-close to these attributes, the closest match is returned.
+     * If multiple records have the same closeness, the one with the smaller (unicode codepoint
+     * order) L2 key is returned.
+     * If no record matches these attributes, null is returned.
+     *
+     * @param attributes The attributes of the network to find.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, returns the L2 key if one matched, or null.
+     */
+    public void findL2Key(@NonNull final NetworkAttributes attributes,
+            @NonNull final IOnL2KeyResponseListener listener) {
+        try {
+            mService.findL2Key(attributes.toParcelable(), listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns whether, to the best of the store's ability to tell, the two specified L2 keys point
+     * to the same L3 network. Group-closeness is used to determine this.
+     *
+     * @param l2Key1 The key for the first network.
+     * @param l2Key2 The key for the second network.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, a SameL3NetworkResponse containing the answer and confidence.
+     */
+    public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
+            @NonNull final IOnSameNetworkResponseListener listener) {
+        try {
+            mService.isSameNetwork(l2Key1, l2Key2, listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Retrieve the network attributes for a key.
+     * If no record is present for this key, this will return null attributes.
+     *
+     * @param l2Key The key of the network to query.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, returns the network attributes and the L2 key associated with
+     *         the query.
+     */
+    public void retrieveNetworkAttributes(@NonNull final String l2Key,
+            @NonNull final IOnNetworkAttributesRetrieved listener) {
+        try {
+            mService.retrieveNetworkAttributes(l2Key, listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Retrieve previously stored private data.
+     * If no data was stored for this L2 key and name this will return null.
+     *
+     * @param l2Key The L2 key.
+     * @param clientId The id of the client that stored this data.
+     * @param name The name of the data.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, returns the private data (or null), with the L2 key
+     *         and the name of the data associated with the query.
+     */
+    public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId,
+            @NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) {
+        try {
+            mService.retrieveBlob(l2Key, clientId, name, listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index 4631c56..b996cda 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Pair;
@@ -83,6 +85,8 @@
      * @param prefixLength the prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
      * @hide
      */
+    @SystemApi
+    @TestApi
     public IpPrefix(InetAddress address, int prefixLength) {
         // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array,
         // which is unnecessary because getAddress() already returns a clone.
diff --git a/core/java/android/net/IpPrefixParcelable.aidl b/core/java/android/net/IpPrefixParcelable.aidl
new file mode 100644
index 0000000..93a8d41
--- /dev/null
+++ b/core/java/android/net/IpPrefixParcelable.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+parcelable IpPrefixParcelable {
+    String address;
+    int prefixLength;
+}
\ No newline at end of file
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index b40f15a..fbd602c 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -26,6 +26,7 @@
 import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
@@ -117,7 +118,8 @@
      * @return true if the address is IPv6.
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
+    @SystemApi
     public boolean isIPv6() {
         return address instanceof Inet6Address;
     }
@@ -126,6 +128,8 @@
      * @return true if the address is IPv4 or is a mapped IPv4 address.
      * @hide
      */
+    @TestApi
+    @SystemApi
     public boolean isIPv4() {
         return address instanceof Inet4Address;
     }
@@ -158,6 +162,8 @@
      *              {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
      * @hide
      */
+    @SystemApi
+    @TestApi
     public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) {
         init(address, prefixLength, flags, scope);
     }
@@ -263,7 +269,8 @@
      * otherwise.
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
+    @SystemApi
     public boolean isSameAddressAs(LinkAddress other) {
         return address.equals(other.address) && prefixLength == other.prefixLength;
     }
@@ -310,6 +317,8 @@
      * Returns true if this {@code LinkAddress} is global scope and preferred.
      * @hide
      */
+    @TestApi
+    @SystemApi
     public boolean isGlobalPreferred() {
         /**
          * Note that addresses flagged as IFA_F_OPTIMISTIC are
diff --git a/core/java/android/net/LinkAddressParcelable.aidl b/core/java/android/net/LinkAddressParcelable.aidl
new file mode 100644
index 0000000..af8e79b
--- /dev/null
+++ b/core/java/android/net/LinkAddressParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+parcelable LinkAddressParcelable {
+    String address;
+    int prefixLength;
+    int flags;
+    int scope;
+}
\ No newline at end of file
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 3a79206..6628701 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
@@ -55,6 +56,8 @@
     private String mIfaceName;
     private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
     private ArrayList<InetAddress> mDnses = new ArrayList<>();
+    // PCSCF addresses are addresses of SIP proxies that only exist for the IMS core service.
+    private ArrayList<InetAddress> mPcscfs = new ArrayList<InetAddress>();
     private ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>();
     private boolean mUsePrivateDns;
     private String mPrivateDnsServerName;
@@ -64,6 +67,7 @@
     private int mMtu;
     // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
     private String mTcpBufferSizes;
+    private IpPrefix mNat64Prefix;
 
     private static final int MIN_MTU    = 68;
     private static final int MIN_MTU_V6 = 1280;
@@ -170,7 +174,8 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
+    @TestApi
     public LinkProperties(LinkProperties source) {
         if (source != null) {
             mIfaceName = source.mIfaceName;
@@ -179,6 +184,7 @@
             mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses);
             mUsePrivateDns = source.mUsePrivateDns;
             mPrivateDnsServerName = source.mPrivateDnsServerName;
+            mPcscfs.addAll(source.mPcscfs);
             mDomains = source.mDomains;
             mRoutes.addAll(source.mRoutes);
             mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy);
@@ -187,6 +193,7 @@
             }
             setMtu(source.mMtu);
             mTcpBufferSizes = source.mTcpBufferSizes;
+            mNat64Prefix = source.mNat64Prefix;
         }
     }
 
@@ -363,7 +370,8 @@
      * @return true if the DNS server was added, false if it was already present.
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
+    @SystemApi
     public boolean addDnsServer(InetAddress dnsServer) {
         if (dnsServer != null && !mDnses.contains(dnsServer)) {
             mDnses.add(dnsServer);
@@ -379,7 +387,8 @@
      * @return true if the DNS server was removed, false if it did not exist.
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
+    @SystemApi
     public boolean removeDnsServer(InetAddress dnsServer) {
         if (dnsServer != null) {
             return mDnses.remove(dnsServer);
@@ -418,6 +427,8 @@
      * @param usePrivateDns The private DNS state.
      * @hide
      */
+    @TestApi
+    @SystemApi
     public void setUsePrivateDns(boolean usePrivateDns) {
         mUsePrivateDns = usePrivateDns;
     }
@@ -443,6 +454,8 @@
      * @param privateDnsServerName The private DNS server name.
      * @hide
      */
+    @TestApi
+    @SystemApi
     public void setPrivateDnsServerName(@Nullable String privateDnsServerName) {
         mPrivateDnsServerName = privateDnsServerName;
     }
@@ -505,6 +518,8 @@
      *        object.
      * @hide
      */
+    @TestApi
+    @SystemApi
     public void setValidatedPrivateDnsServers(Collection<InetAddress> dnsServers) {
         mValidatedPrivateDnses.clear();
         for (InetAddress dnsServer: dnsServers) {
@@ -520,11 +535,71 @@
      *         DNS servers on this link.
      * @hide
      */
+    @TestApi
+    @SystemApi
     public List<InetAddress> getValidatedPrivateDnsServers() {
         return Collections.unmodifiableList(mValidatedPrivateDnses);
     }
 
     /**
+     * Adds the given {@link InetAddress} to the list of PCSCF servers, if not present.
+     *
+     * @param pcscfServer The {@link InetAddress} to add to the list of PCSCF servers.
+     * @return true if the PCSCF server was added, false otherwise.
+     * @hide
+     */
+    public boolean addPcscfServer(InetAddress pcscfServer) {
+        if (pcscfServer != null && !mPcscfs.contains(pcscfServer)) {
+            mPcscfs.add(pcscfServer);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Removes the given {@link InetAddress} from the list of PCSCF servers.
+     *
+     * @param pcscf Server The {@link InetAddress} to remove from the list of PCSCF servers.
+     * @return true if the PCSCF server was removed, false otherwise.
+     * @hide
+     */
+    public boolean removePcscfServer(InetAddress pcscfServer) {
+        if (pcscfServer != null) {
+            return mPcscfs.remove(pcscfServer);
+        }
+        return false;
+    }
+
+    /**
+     * Replaces the PCSCF servers in this {@code LinkProperties} with
+     * the given {@link Collection} of {@link InetAddress} objects.
+     *
+     * @param addresses The {@link Collection} of PCSCF servers to set in this object.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public void setPcscfServers(Collection<InetAddress> pcscfServers) {
+        mPcscfs.clear();
+        for (InetAddress pcscfServer: pcscfServers) {
+            addPcscfServer(pcscfServer);
+        }
+    }
+
+    /**
+     * Returns all the {@link InetAddress} for PCSCF servers on this link.
+     *
+     * @return An unmodifiable {@link List} of {@link InetAddress} for PCSCF servers on
+     *         this link.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public List<InetAddress> getPcscfServers() {
+        return Collections.unmodifiableList(mPcscfs);
+    }
+
+    /**
      * Sets the DNS domain search path used on this link.
      *
      * @param domains A {@link String} listing in priority order the comma separated
@@ -577,7 +652,8 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
+    @SystemApi
     public void setTcpBufferSizes(String tcpBufferSizes) {
         mTcpBufferSizes = tcpBufferSizes;
     }
@@ -589,7 +665,8 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
+    @SystemApi
     public String getTcpBufferSizes() {
         return mTcpBufferSizes;
     }
@@ -640,7 +717,8 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
+    @SystemApi
     public boolean removeRoute(RouteInfo route) {
         return route != null &&
                 Objects.equals(mIfaceName, route.getInterface()) &&
@@ -703,6 +781,36 @@
     }
 
     /**
+     * Returns the NAT64 prefix in use on this link, if any.
+     *
+     * @return the NAT64 prefix.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public @Nullable IpPrefix getNat64Prefix() {
+        return mNat64Prefix;
+    }
+
+    /**
+     * Sets the NAT64 prefix in use on this link.
+     *
+     * Currently, only 96-bit prefixes (i.e., where the 32-bit IPv4 address is at the end of the
+     * 128-bit IPv6 address) are supported.
+     *
+     * @param prefix the NAT64 prefix.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public void setNat64Prefix(IpPrefix prefix) {
+        if (prefix != null && prefix.getPrefixLength() != 96) {
+            throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix);
+        }
+        mNat64Prefix = prefix;  // IpPrefix objects are immutable.
+    }
+
+    /**
      * Adds a stacked link.
      *
      * If there is already a stacked link with the same interface name as link,
@@ -767,12 +875,14 @@
         mDnses.clear();
         mUsePrivateDns = false;
         mPrivateDnsServerName = null;
+        mPcscfs.clear();
         mDomains = null;
         mRoutes.clear();
         mHttpProxy = null;
         mStackedLinks.clear();
         mMtu = 0;
         mTcpBufferSizes = null;
+        mNat64Prefix = null;
     }
 
     /**
@@ -813,6 +923,12 @@
             resultJoiner.add(mPrivateDnsServerName);
         }
 
+        if (!mPcscfs.isEmpty()) {
+            resultJoiner.add("PcscfAddresses: [");
+            resultJoiner.add(TextUtils.join(",", mPcscfs));
+            resultJoiner.add("]");
+        }
+
         if (!mValidatedPrivateDnses.isEmpty()) {
             final StringJoiner validatedPrivateDnsesJoiner =
                     new StringJoiner(",", "ValidatedPrivateDnsAddresses: [", "]");
@@ -844,6 +960,11 @@
             resultJoiner.add(mHttpProxy.toString());
         }
 
+        if (mNat64Prefix != null) {
+            resultJoiner.add("Nat64Prefix:");
+            resultJoiner.add(mNat64Prefix.toString());
+        }
+
         final Collection<LinkProperties> stackedLinksValues = mStackedLinks.values();
         if (!stackedLinksValues.isEmpty()) {
             final StringJoiner stackedLinksJoiner = new StringJoiner(",", "Stacked: [", "]");
@@ -862,7 +983,8 @@
      * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
+    @SystemApi
     public boolean hasIPv4Address() {
         for (LinkAddress address : mLinkAddresses) {
             if (address.getAddress() instanceof Inet4Address) {
@@ -890,7 +1012,8 @@
      * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
+    @SystemApi
     public boolean hasGlobalIPv6Address() {
         for (LinkAddress address : mLinkAddresses) {
           if (address.getAddress() instanceof Inet6Address && address.isGlobalPreferred()) {
@@ -922,7 +1045,8 @@
      * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
+    @SystemApi
     public boolean hasIPv6DefaultRoute() {
         for (RouteInfo r : mRoutes) {
             if (r.isIPv6Default()) {
@@ -965,12 +1089,44 @@
     }
 
     /**
+     * Returns true if this link has an IPv4 PCSCF server.
+     *
+     * @return {@code true} if there is an IPv4 PCSCF server, {@code false} otherwise.
+     * @hide
+     */
+    public boolean hasIPv4PcscfServer() {
+        for (InetAddress ia : mPcscfs) {
+          if (ia instanceof Inet4Address) {
+            return true;
+          }
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if this link has an IPv6 PCSCF server.
+     *
+     * @return {@code true} if there is an IPv6 PCSCF server, {@code false} otherwise.
+     * @hide
+     */
+    public boolean hasIPv6PcscfServer() {
+        for (InetAddress ia : mPcscfs) {
+          if (ia instanceof Inet6Address) {
+            return true;
+          }
+        }
+        return false;
+    }
+
+    /**
      * Returns true if this link is provisioned for global IPv4 connectivity.
      * This requires an IP address, default route, and DNS server.
      *
      * @return {@code true} if the link is provisioned, {@code false} otherwise.
      * @hide
      */
+    @TestApi
+    @SystemApi
     public boolean isIPv4Provisioned() {
         return (hasIPv4Address() &&
                 hasIPv4DefaultRoute() &&
@@ -984,7 +1140,8 @@
      * @return {@code true} if the link is provisioned, {@code false} otherwise.
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
+    @SystemApi
     public boolean isIPv6Provisioned() {
         return (hasGlobalIPv6Address() &&
                 hasIPv6DefaultRoute() &&
@@ -998,7 +1155,8 @@
      * @return {@code true} if the link is provisioned, {@code false} otherwise.
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
+    @SystemApi
     public boolean isProvisioned() {
         return (isIPv4Provisioned() || isIPv6Provisioned());
     }
@@ -1010,7 +1168,8 @@
      *         {@code false} otherwise.
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
+    @SystemApi
     public boolean isReachable(InetAddress ip) {
         final List<RouteInfo> allRoutes = getAllRoutes();
         // If we don't have a route to this IP address, it's not reachable.
@@ -1117,6 +1276,19 @@
     }
 
     /**
+     * Compares this {@code LinkProperties} PCSCF addresses against the target
+     *
+     * @param target LinkProperties to compare.
+     * @return {@code true} if both are identical, {@code false} otherwise.
+     * @hide
+     */
+    public boolean isIdenticalPcscfs(LinkProperties target) {
+        Collection<InetAddress> targetPcscfs = target.getPcscfServers();
+        return (mPcscfs.size() == targetPcscfs.size()) ?
+                    mPcscfs.containsAll(targetPcscfs) : false;
+    }
+
+    /**
      * Compares this {@code LinkProperties} Routes against the target
      *
      * @param target LinkProperties to compare.
@@ -1188,6 +1360,17 @@
     }
 
     /**
+     * Compares this {@code LinkProperties} NAT64 prefix against the target.
+     *
+     * @param target LinkProperties to compare.
+     * @return {@code true} if both are identical, {@code false} otherwise.
+     * @hide
+     */
+    public boolean isIdenticalNat64Prefix(LinkProperties target) {
+        return Objects.equals(mNat64Prefix, target.mNat64Prefix);
+    }
+
+    /**
      * Compares this {@code LinkProperties} instance against the target
      * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
      * all their fields are equal in values.
@@ -1218,11 +1401,13 @@
                 && isIdenticalDnses(target)
                 && isIdenticalPrivateDns(target)
                 && isIdenticalValidatedPrivateDnses(target)
+                && isIdenticalPcscfs(target)
                 && isIdenticalRoutes(target)
                 && isIdenticalHttpProxy(target)
                 && isIdenticalStackedLinks(target)
                 && isIdenticalMtu(target)
-                && isIdenticalTcpBufferSizes(target);
+                && isIdenticalTcpBufferSizes(target)
+                && isIdenticalNat64Prefix(target);
     }
 
     /**
@@ -1334,7 +1519,9 @@
                 + mMtu * 51
                 + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode())
                 + (mUsePrivateDns ? 57 : 0)
-                + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode());
+                + mPcscfs.size() * 67
+                + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode())
+                + Objects.hash(mNat64Prefix);
     }
 
     /**
@@ -1357,6 +1544,10 @@
         }
         dest.writeBoolean(mUsePrivateDns);
         dest.writeString(mPrivateDnsServerName);
+        dest.writeInt(mPcscfs.size());
+        for (InetAddress d : mPcscfs) {
+            dest.writeByteArray(d.getAddress());
+        }
         dest.writeString(mDomains);
         dest.writeInt(mMtu);
         dest.writeString(mTcpBufferSizes);
@@ -1371,6 +1562,8 @@
         } else {
             dest.writeByte((byte)0);
         }
+        dest.writeParcelable(mNat64Prefix, 0);
+
         ArrayList<LinkProperties> stackedLinks = new ArrayList<>(mStackedLinks.values());
         dest.writeList(stackedLinks);
     }
@@ -1406,6 +1599,12 @@
                 }
                 netProp.setUsePrivateDns(in.readBoolean());
                 netProp.setPrivateDnsServerName(in.readString());
+                addressCount = in.readInt();
+                for (int i = 0; i < addressCount; i++) {
+                    try {
+                        netProp.addPcscfServer(InetAddress.getByAddress(in.createByteArray()));
+                    } catch (UnknownHostException e) { }
+                }
                 netProp.setDomains(in.readString());
                 netProp.setMtu(in.readInt());
                 netProp.setTcpBufferSizes(in.readString());
@@ -1416,6 +1615,7 @@
                 if (in.readByte() == 1) {
                     netProp.setHttpProxy(in.readParcelable(null));
                 }
+                netProp.setNat64Prefix(in.readParcelable(null));
                 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
                 in.readList(stackedLinks, LinkProperties.class.getClassLoader());
                 for (LinkProperties stackedLink: stackedLinks) {
diff --git a/core/java/android/net/LinkPropertiesParcelable.aidl b/core/java/android/net/LinkPropertiesParcelable.aidl
new file mode 100644
index 0000000..6b52239
--- /dev/null
+++ b/core/java/android/net/LinkPropertiesParcelable.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddressParcelable;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfoParcelable;
+
+parcelable LinkPropertiesParcelable {
+    String ifaceName;
+    LinkAddressParcelable[] linkAddresses;
+    String[] dnses;
+    String[] pcscfs;
+    String[] validatedPrivateDnses;
+    boolean usePrivateDns;
+    String privateDnsServerName;
+    String domains;
+    RouteInfoParcelable[] routes;
+    ProxyInfoParcelable httpProxy;
+    int mtu;
+    String tcpBufferSizes;
+    IpPrefixParcelable nat64Prefix;
+}
\ No newline at end of file
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 4e551756..77d83f5 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -52,6 +52,8 @@
 
     /**
      * The MacAddress zero MAC address.
+     *
+     * <p>Not publicly exposed or treated specially since the OUI 00:00:00 is registered.
      * @hide
      */
     @UnsupportedAppUsage
diff --git a/core/java/android/net/NattSocketKeepalive.java b/core/java/android/net/NattSocketKeepalive.java
new file mode 100644
index 0000000..88631ae
--- /dev/null
+++ b/core/java/android/net/NattSocketKeepalive.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 android.net;
+
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.net.InetAddress;
+import java.util.concurrent.Executor;
+
+/** @hide */
+public final class NattSocketKeepalive extends SocketKeepalive {
+    /** The NAT-T destination port for IPsec */
+    public static final int NATT_PORT = 4500;
+
+    @NonNull private final InetAddress mSource;
+    @NonNull private final InetAddress mDestination;
+    @NonNull private final FileDescriptor mFd;
+    private final int mResourceId;
+
+    NattSocketKeepalive(@NonNull IConnectivityManager service,
+            @NonNull Network network,
+            @NonNull FileDescriptor fd,
+            int resourceId,
+            @NonNull InetAddress source,
+            @NonNull InetAddress destination,
+            @NonNull Executor executor,
+            @NonNull Callback callback) {
+        super(service, network, executor, callback);
+        mSource = source;
+        mDestination = destination;
+        mFd = fd;
+        mResourceId = resourceId;
+    }
+
+    @Override
+    void startImpl(int intervalSec) {
+        try {
+            mService.startNattKeepaliveWithFd(mNetwork, mFd, mResourceId, intervalSec, mMessenger,
+                    new Binder(), mSource.getHostAddress(), mDestination.getHostAddress());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error starting packet keepalive: ", e);
+            stopLooper();
+        }
+    }
+
+    @Override
+    void stopImpl() {
+        try {
+            if (mSlot != null) {
+                mService.stopKeepalive(mNetwork, mSlot);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error stopping packet keepalive: ", e);
+            stopLooper();
+        }
+    }
+}
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index bf2344d..2c831de 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -157,6 +159,8 @@
      *
      * @hide
      */
+    @TestApi
+    @SystemApi
     public Network getPrivateDnsBypassingCopy() {
         return new Network(netId, true);
     }
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 1b44c92..7e9bda1 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -712,6 +712,7 @@
      * @hide
      */
     @TestApi
+    @SystemApi
     public @Transport int[] getTransportTypes() {
         return BitUtils.unpackBits(mTransportTypes);
     }
@@ -1312,6 +1313,8 @@
      *
      * @hide
      */
+    @TestApi
+    @SystemApi
     public boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc) {
         return satisfiedByNetworkCapabilities(nc, false);
     }
diff --git a/core/java/android/net/NetworkParcelable.aidl b/core/java/android/net/NetworkParcelable.aidl
new file mode 100644
index 0000000..c26352e
--- /dev/null
+++ b/core/java/android/net/NetworkParcelable.aidl
@@ -0,0 +1,22 @@
+/*
+**
+** Copyright (C) 2019 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+parcelable NetworkParcelable {
+    long networkHandle;
+}
diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java
index be2f955..fcfb720 100644
--- a/core/java/android/net/NetworkSpecifier.java
+++ b/core/java/android/net/NetworkSpecifier.java
@@ -17,7 +17,7 @@
 package android.net;
 
 /**
- * Describes specific properties of a network for use in a {@link NetworkRequest}.
+ * Describes specific properties of a requested network for use in a {@link NetworkRequest}.
  *
  * Applications cannot instantiate this class by themselves, but can obtain instances of
  * subclasses of this class via other APIs.
@@ -49,4 +49,29 @@
     public void assertValidFromUid(int requestorUid) {
         // empty
     }
+
+    /**
+     * Optional method which can be overridden by concrete implementations of NetworkSpecifier to
+     * perform any redaction of information from the NetworkSpecifier, e.g. if it contains
+     * sensitive information. The default implementation simply returns the object itself - i.e.
+     * no information is redacted. A concrete implementation may return a modified (copy) of the
+     * NetworkSpecifier, or even return a null to fully remove all information.
+     * <p>
+     * This method is relevant to NetworkSpecifier objects used by agents - those are shared with
+     * apps by default. Some agents may store sensitive matching information in the specifier,
+     * e.g. a Wi-Fi SSID (which should not be shared since it may leak location). Those classes
+     * can redact to a null. Other agents use the Network Specifier to share public information
+     * with apps - those should not be redacted.
+     * <p>
+     * The default implementation redacts no information.
+     *
+     * @return A NetworkSpecifier object to be passed along to the requesting app.
+     *
+     * @hide
+     */
+    public NetworkSpecifier redact() {
+        // TODO (b/122160111): convert default to null once all platform NetworkSpecifiers
+        // implement this method.
+        return this;
+    }
 }
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
index 82a4e31..d277034 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -25,9 +25,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.net.dhcp.DhcpServingParamsParcel;
+import android.net.dhcp.IDhcpServerCallbacks;
+import android.net.ip.IIpClientCallbacks;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.util.Slog;
@@ -45,19 +49,71 @@
 public class NetworkStack {
     private static final String TAG = NetworkStack.class.getSimpleName();
 
+    public static final String NETWORKSTACK_PACKAGE_NAME = "com.android.mainline.networkstack";
+
+    private static final int NETWORKSTACK_TIMEOUT_MS = 10_000;
+
     @NonNull
     @GuardedBy("mPendingNetStackRequests")
-    private final ArrayList<NetworkStackRequest> mPendingNetStackRequests = new ArrayList<>();
+    private final ArrayList<NetworkStackCallback> mPendingNetStackRequests = new ArrayList<>();
     @Nullable
     @GuardedBy("mPendingNetStackRequests")
     private INetworkStackConnector mConnector;
 
-    private interface NetworkStackRequest {
+    private volatile boolean mNetworkStackStartRequested = false;
+
+    private interface NetworkStackCallback {
         void onNetworkStackConnected(INetworkStackConnector connector);
     }
 
     public NetworkStack() { }
 
+    /**
+     * Create a DHCP server according to the specified parameters.
+     *
+     * <p>The server will be returned asynchronously through the provided callbacks.
+     */
+    public void makeDhcpServer(final String ifName, final DhcpServingParamsParcel params,
+            final IDhcpServerCallbacks cb) {
+        requestConnector(connector -> {
+            try {
+                connector.makeDhcpServer(ifName, params, cb);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        });
+    }
+
+    /**
+     * Create an IpClient on the specified interface.
+     *
+     * <p>The IpClient will be returned asynchronously through the provided callbacks.
+     */
+    public void makeIpClient(String ifName, IIpClientCallbacks cb) {
+        requestConnector(connector -> {
+            try {
+                connector.makeIpClient(ifName, cb);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        });
+    }
+
+    /**
+     * Create a NetworkMonitor.
+     *
+     * <p>The INetworkMonitor will be returned asynchronously through the provided callbacks.
+     */
+    public void makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb) {
+        requestConnector(connector -> {
+            try {
+                connector.makeNetworkMonitor(network.netId, name, cb);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        });
+    }
+
     private class NetworkStackConnection implements ServiceConnection {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
@@ -77,14 +133,14 @@
         ServiceManager.addService(Context.NETWORK_STACK_SERVICE, service, false /* allowIsolated */,
                 DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
 
-        final ArrayList<NetworkStackRequest> requests;
+        final ArrayList<NetworkStackCallback> requests;
         synchronized (mPendingNetStackRequests) {
             requests = new ArrayList<>(mPendingNetStackRequests);
             mPendingNetStackRequests.clear();
             mConnector = connector;
         }
 
-        for (NetworkStackRequest r : requests) {
+        for (NetworkStackCallback r : requests) {
             r.onNetworkStackConnected(connector);
         }
     }
@@ -98,6 +154,7 @@
      * started.
      */
     public void start(Context context) {
+        mNetworkStackStartRequested = true;
         // Try to bind in-process if the library is available
         IBinder connector = null;
         try {
@@ -105,7 +162,8 @@
                     "com.android.server.NetworkStackService",
                     true /* initialize */,
                     context.getClassLoader());
-            connector = (IBinder) service.getMethod("makeConnector").invoke(null);
+            connector = (IBinder) service.getMethod("makeConnector", Context.class)
+                    .invoke(null, context);
         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
             Slog.wtf(TAG, "Could not create network stack connector from NetworkStackService");
             // TODO: crash/reboot system here ?
@@ -133,15 +191,54 @@
         }
     }
 
-    // TODO: use this method to obtain the connector when implementing network stack operations
-    private void requestConnector(@NonNull NetworkStackRequest request) {
+    /**
+     * For non-system server clients, get the connector registered by the system server.
+     */
+    private INetworkStackConnector getRemoteConnector() {
+        // Block until the NetworkStack connector is registered in ServiceManager.
+        // <p>This is only useful for non-system processes that do not have a way to be notified of
+        // registration completion. Adding a callback system would be too heavy weight considering
+        // that the connector is registered on boot, so it is unlikely that a client would request
+        // it before it is registered.
+        // TODO: consider blocking boot on registration and simplify much of the logic in this class
+        IBinder connector;
+        try {
+            final long before = System.currentTimeMillis();
+            while ((connector = ServiceManager.getService(Context.NETWORK_STACK_SERVICE)) == null) {
+                Thread.sleep(20);
+                if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
+                    Slog.e(TAG, "Timeout waiting for NetworkStack connector");
+                    return null;
+                }
+            }
+        } catch (InterruptedException e) {
+            Slog.e(TAG, "Error waiting for NetworkStack connector", e);
+            return null;
+        }
+
+        return INetworkStackConnector.Stub.asInterface(connector);
+    }
+
+    private void requestConnector(@NonNull NetworkStackCallback request) {
         // TODO: PID check.
-        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+        final int caller = Binder.getCallingUid();
+        if (caller != Process.SYSTEM_UID && caller != Process.BLUETOOTH_UID) {
             // Don't even attempt to obtain the connector and give a nice error message
             throw new SecurityException(
                     "Only the system server should try to bind to the network stack.");
         }
 
+        if (!mNetworkStackStartRequested) {
+            // The network stack is not being started in this process, e.g. this process is not
+            // the system server. Get a remote connector registered by the system server.
+            final INetworkStackConnector connector = getRemoteConnector();
+            synchronized (mPendingNetStackRequests) {
+                mConnector = connector;
+            }
+            request.onNetworkStackConnected(connector);
+            return;
+        }
+
         final INetworkStackConnector connector;
         synchronized (mPendingNetStackRequests) {
             connector = mConnector;
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index a00b9a3..9cf582b 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import static android.os.Process.CLAT_UID;
+
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -828,13 +830,15 @@
      *
      * <p>For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4
      * packet on the stacked interface, and once as translated to an IPv6 packet on the
-     * base interface. For correct stats accounting on the base interface, every 464xlat
-     * packet needs to be subtracted from the root UID on the base interface both for tx
-     * and rx traffic (http://b/12249687, http:/b/33681750).
+     * base interface. For correct stats accounting on the base interface, if using xt_qtaguid,
+     * every rx 464xlat packet needs to be subtracted from the root UID on the base interface
+     * (http://b/12249687, http:/b/33681750), and every tx 464xlat packet which was counted onto
+     * clat uid should be ignored.
      *
      * As for eBPF, the per uid stats is collected by different hook, the rx packets on base
-     * interface will not be counted. Thus, the adjustment on root uid is only needed in tx
-     * direction.
+     * interface will not be counted. Thus, the adjustment on root uid is not needed. However, the
+     * tx traffic counted in the same way xt_qtaguid does, so the traffic on clat uid still
+     * needs to be ignored.
      *
      * <p>This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only
      * {@code ConcurrentHashMap}
@@ -862,17 +866,14 @@
             if (baseIface == null) {
                 continue;
             }
-            // Subtract any 464lat traffic seen for the root UID on the current base interface.
-            // However, for eBPF, the per uid stats is collected by different hook, the rx packets
-            // on base interface will not be counted. Thus, the adjustment on root uid is only
-            // needed in tx direction.
+            // Subtract xt_qtaguid 464lat rx traffic seen for the root UID on the current base
+            // interface. As for eBPF, the per uid stats is collected by different hook, the rx
+            // packets on base interface will not be counted.
             adjust.iface = baseIface;
             if (!useBpfStats) {
                 adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA);
                 adjust.rxPackets = -entry.rxPackets;
             }
-            adjust.txBytes = -(entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA);
-            adjust.txPackets = -entry.txPackets;
             adjustments.combineValues(adjust);
 
             // For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet
@@ -884,6 +885,9 @@
             stackedTraffic.setValues(i, entry);
         }
 
+        // Traffic on clat uid is v6 tx traffic that is already counted with app uid on the stacked
+        // v4 interface, so it needs to be removed to avoid double-counting.
+        baseTraffic.removeUids(new int[] {CLAT_UID});
         baseTraffic.combineAllValues(adjustments);
     }
 
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 4eab49c..c996d01 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -39,6 +39,8 @@
 import java.util.Locale;
 import java.util.TreeSet;
 
+import android.system.ErrnoException;
+
 /**
  * Native methods for managing network interfaces.
  *
@@ -138,6 +140,32 @@
     public native static boolean queryUserAccess(int uid, int netId);
 
     /**
+     * DNS resolver series jni method.
+     * Issue the query {@code msg} on the network designated by {@code netId}.
+     * {@code flags} is an additional config to control actual querying behavior.
+     * @return a file descriptor to watch for read events
+     */
+    public static native FileDescriptor resNetworkSend(
+            int netId, byte[] msg, int msglen, int flags) throws ErrnoException;
+
+    /**
+     * DNS resolver series jni method.
+     * Look up the {@code nsClass} {@code nsType} Resource Record (RR) associated
+     * with Domain Name {@code dname} on the network designated by {@code netId}.
+     * {@code flags} is an additional config to control actual querying behavior.
+     * @return a file descriptor to watch for read events
+     */
+    public static native FileDescriptor resNetworkQuery(
+            int netId, String dname, int nsClass, int nsType, int flags) throws ErrnoException;
+
+    /**
+     * DNS resolver series jni method.
+     * Read a result for the query associated with the {@code fd}.
+     * @return a byte array containing blob answer
+     */
+    public static native byte[] resNetworkResult(FileDescriptor fd) throws ErrnoException;
+
+    /**
      * Add an entry into the ARP cache.
      */
     public static void addArpEntry(Inet4Address ipv4Addr, MacAddress ethAddr, String ifname,
diff --git a/core/java/android/net/PrivateDnsConfigParcel.aidl b/core/java/android/net/PrivateDnsConfigParcel.aidl
new file mode 100644
index 0000000..b52fce6
--- /dev/null
+++ b/core/java/android/net/PrivateDnsConfigParcel.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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 PrivateDnsConfigParcel {
+    String hostname;
+    String[] ips;
+}
diff --git a/core/java/android/net/ProvisioningConfigurationParcelable.aidl b/core/java/android/net/ProvisioningConfigurationParcelable.aidl
new file mode 100644
index 0000000..2a144f2
--- /dev/null
+++ b/core/java/android/net/ProvisioningConfigurationParcelable.aidl
@@ -0,0 +1,38 @@
+/*
+**
+** Copyright (C) 2019 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+import android.net.ApfCapabilitiesParcelable;
+import android.net.InitialConfigurationParcelable;
+import android.net.NetworkParcelable;
+import android.net.StaticIpConfigurationParcelable;
+
+parcelable ProvisioningConfigurationParcelable {
+    boolean enableIPv4;
+    boolean enableIPv6;
+    boolean usingMultinetworkPolicyTracker;
+    boolean usingIpReachabilityMonitor;
+    int requestedPreDhcpActionMs;
+    InitialConfigurationParcelable initialConfig;
+    StaticIpConfigurationParcelable staticIpConfig;
+    ApfCapabilitiesParcelable apfCapabilities;
+    int provisioningTimeoutMs;
+    int ipv6AddrGenMode;
+    NetworkParcelable network;
+    String displayName;
+}
diff --git a/core/java/android/net/ProxyInfoParcelable.aidl b/core/java/android/net/ProxyInfoParcelable.aidl
new file mode 100644
index 0000000..59fd846
--- /dev/null
+++ b/core/java/android/net/ProxyInfoParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+parcelable ProxyInfoParcelable {
+    String host;
+    int port;
+    String[] exclusionList;
+    String pacFileUrl;
+}
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 37ab9ff..5c0f758 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -16,16 +16,17 @@
 
 package android.net;
 
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.net.UnknownHostException;
-import java.net.InetAddress;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
-
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.Collection;
 import java.util.Objects;
 
@@ -67,12 +68,18 @@
 
 
     /** Unicast route. @hide */
+    @SystemApi
+    @TestApi
     public static final int RTN_UNICAST = 1;
 
     /** Unreachable route. @hide */
+    @SystemApi
+    @TestApi
     public static final int RTN_UNREACHABLE = 7;
 
     /** Throw route. @hide */
+    @SystemApi
+    @TestApi
     public static final int RTN_THROW = 9;
 
     /**
@@ -103,6 +110,8 @@
      *
      * @hide
      */
+    @SystemApi
+    @TestApi
     public RouteInfo(IpPrefix destination, InetAddress gateway, String iface, int type) {
         switch (type) {
             case RTN_UNICAST:
@@ -317,6 +326,8 @@
      *
      * @hide
      */
+    @TestApi
+    @SystemApi
     public int getType() {
         return mType;
     }
@@ -362,9 +373,7 @@
      * ({@code false}).
      *
      * @return {@code true} if a gateway is specified
-     * @hide
      */
-    @UnsupportedAppUsage
     public boolean hasGateway() {
         return mHasGateway;
     }
diff --git a/core/java/android/net/RouteInfoParcelable.aidl b/core/java/android/net/RouteInfoParcelable.aidl
new file mode 100644
index 0000000..15bcdcf
--- /dev/null
+++ b/core/java/android/net/RouteInfoParcelable.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+import android.net.IpPrefixParcelable;
+
+parcelable RouteInfoParcelable {
+    IpPrefixParcelable destination;
+    String gatewayAddr;
+    String ifaceName;
+    int type;
+}
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index abc1cac..90dccb5 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -86,7 +86,16 @@
  * <p>On development devices, "setprop socket.relaxsslcheck yes" bypasses all
  * SSL certificate and hostname checks for testing purposes.  This setting
  * requires root access.
+ *
+ * @deprecated This class has less error-prone replacements using standard APIs.  To create an
+ * {@code SSLSocket}, obtain an {@link SSLSocketFactory} from {@link SSLSocketFactory#getDefault()}
+ * or {@link javax.net.ssl.SSLContext#getSocketFactory()}.  To verify hostnames, pass
+ * {@code "HTTPS"} to
+ * {@link javax.net.ssl.SSLParameters#setEndpointIdentificationAlgorithm(String)}.  To enable ALPN,
+ * use {@link javax.net.ssl.SSLParameters#setApplicationProtocols(String[])}.  To enable SNI,
+ * use {@link javax.net.ssl.SSLParameters#setServerNames(java.util.List)}.
  */
+@Deprecated
 public class SSLCertificateSocketFactory extends SSLSocketFactory {
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private static final String TAG = "SSLCertificateSocketFactory";
diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java
new file mode 100644
index 0000000..97d50f4
--- /dev/null
+++ b/core/java/android/net/SocketKeepalive.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Process;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+
+/**
+ * Allows applications to request that the system periodically send specific packets on their
+ * behalf, using hardware offload to save battery power.
+ *
+ * To request that the system send keepalives, call one of the methods that return a
+ * {@link SocketKeepalive} object, such as {@link ConnectivityManager#createSocketKeepalive},
+ * passing in a non-null callback. If the {@link SocketKeepalive} is successfully
+ * started, the callback's {@code onStarted} method will be called. If an error occurs,
+ * {@code onError} will be called, specifying one of the {@code ERROR_*} constants in this
+ * class.
+ *
+ * To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call
+ * {@link SocketKeepalive.Callback#onStopped} if the operation was successful or
+ * {@link SocketKeepalive.Callback#onError} if an error occurred.
+ */
+public abstract class SocketKeepalive implements AutoCloseable {
+    static final String TAG = "SocketKeepalive";
+
+    /** @hide */
+    public static final int SUCCESS = 0;
+
+    /** @hide */
+    public static final int NO_KEEPALIVE = -1;
+
+    /** @hide */
+    public static final int DATA_RECEIVED = -2;
+
+    /** @hide */
+    public static final int BINDER_DIED = -10;
+
+    /** The specified {@code Network} is not connected. */
+    public static final int ERROR_INVALID_NETWORK = -20;
+    /** The specified IP addresses are invalid. For example, the specified source IP address is
+     * not configured on the specified {@code Network}. */
+    public static final int ERROR_INVALID_IP_ADDRESS = -21;
+    /** The requested port is invalid. */
+    public static final int ERROR_INVALID_PORT = -22;
+    /** The packet length is invalid (e.g., too long). */
+    public static final int ERROR_INVALID_LENGTH = -23;
+    /** The packet transmission interval is invalid (e.g., too short). */
+    public static final int ERROR_INVALID_INTERVAL = -24;
+    /** The target socket is invalid. */
+    public static final int ERROR_INVALID_SOCKET = -25;
+    /** The target socket is not idle. */
+    public static final int ERROR_SOCKET_NOT_IDLE = -26;
+
+    /** The hardware does not support this request. */
+    public static final int ERROR_HARDWARE_UNSUPPORTED = -30;
+    /** The hardware returned an error. */
+    public static final int ERROR_HARDWARE_ERROR = -31;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "ERROR_" }, value = {
+            ERROR_INVALID_NETWORK,
+            ERROR_INVALID_IP_ADDRESS,
+            ERROR_INVALID_PORT,
+            ERROR_INVALID_LENGTH,
+            ERROR_INVALID_INTERVAL,
+            ERROR_INVALID_SOCKET,
+            ERROR_SOCKET_NOT_IDLE
+    })
+    public @interface ErrorCode {}
+
+    /**
+     * The minimum interval in seconds between keepalive packet transmissions.
+     *
+     * @hide
+     **/
+    public static final int MIN_INTERVAL_SEC = 10;
+
+    /**
+     * The maximum interval in seconds between keepalive packet transmissions.
+     *
+     * @hide
+     **/
+    public static final int MAX_INTERVAL_SEC = 3600;
+
+    @NonNull final IConnectivityManager mService;
+    @NonNull final Network mNetwork;
+    @NonNull private final Executor mExecutor;
+    @NonNull private final SocketKeepalive.Callback mCallback;
+    @NonNull private final Looper mLooper;
+    @NonNull final Messenger mMessenger;
+    @NonNull Integer mSlot;
+
+    SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network,
+            @NonNull Executor executor, @NonNull Callback callback) {
+        mService = service;
+        mNetwork = network;
+        mExecutor = executor;
+        mCallback = callback;
+        // TODO: 1. Use other thread modeling instead of create one thread for every instance to
+        //          reduce the memory cost.
+        //       2. support restart.
+        //       3. Fix race condition which caused by rapidly start and stop.
+        HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND
+                + Process.THREAD_PRIORITY_LESS_FAVORABLE);
+        thread.start();
+        mLooper = thread.getLooper();
+        mMessenger = new Messenger(new Handler(mLooper) {
+            @Override
+            public void handleMessage(Message message) {
+                switch (message.what) {
+                    case NetworkAgent.EVENT_PACKET_KEEPALIVE:
+                        final int status = message.arg2;
+                        try {
+                            if (status == SUCCESS) {
+                                if (mSlot == null) {
+                                    mSlot = message.arg1;
+                                    mExecutor.execute(() -> mCallback.onStarted());
+                                } else {
+                                    mSlot = null;
+                                    stopLooper();
+                                    mExecutor.execute(() -> mCallback.onStopped());
+                                }
+                            } else if (status == DATA_RECEIVED) {
+                                stopLooper();
+                                mExecutor.execute(() -> mCallback.onDataReceived());
+                            } else {
+                                stopLooper();
+                                mExecutor.execute(() -> mCallback.onError(status));
+                            }
+                        } catch (Exception e) {
+                            Log.e(TAG, "Exception in keepalive callback(" + status + ")", e);
+                        }
+                        break;
+                    default:
+                        Log.e(TAG, "Unhandled message " + Integer.toHexString(message.what));
+                        break;
+                }
+            }
+        });
+    }
+
+    /**
+     * Request that keepalive be started with the given {@code intervalSec}. See
+     * {@link SocketKeepalive}.
+     *
+     * @param intervalSec The target interval in seconds between keepalive packet transmissions.
+     *                    The interval should be between 10 seconds and 3600 seconds, otherwise
+     *                    {@link #ERROR_INVALID_INTERVAL} will be returned.
+     */
+    public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
+            int intervalSec) {
+        startImpl(intervalSec);
+    }
+
+    abstract void startImpl(int intervalSec);
+
+    /** @hide */
+    protected void stopLooper() {
+        // TODO: remove this after changing thread modeling.
+        mLooper.quit();
+    }
+
+    /**
+     * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
+     * before using the object. See {@link SocketKeepalive}.
+     */
+    public final void stop() {
+        stopImpl();
+    }
+
+    abstract void stopImpl();
+
+    /**
+     * Deactivate this {@link SocketKeepalive} and free allocated resources. The instance won't be
+     * usable again if {@code close()} is called.
+     */
+    @Override
+    public final void close() {
+        stop();
+        stopLooper();
+    }
+
+    /**
+     * The callback which app can use to learn the status changes of {@link SocketKeepalive}. See
+     * {@link SocketKeepalive}.
+     */
+    public static class Callback {
+        /** The requested keepalive was successfully started. */
+        public void onStarted() {}
+        /** The keepalive was successfully stopped. */
+        public void onStopped() {}
+        /** An error occurred. */
+        public void onError(@ErrorCode int error) {}
+        /** The keepalive on a TCP socket was stopped because the socket received data. */
+        public void onDataReceived() {}
+    }
+}
diff --git a/core/java/android/net/StaticIpConfigurationParcelable.aidl b/core/java/android/net/StaticIpConfigurationParcelable.aidl
new file mode 100644
index 0000000..45dc021
--- /dev/null
+++ b/core/java/android/net/StaticIpConfigurationParcelable.aidl
@@ -0,0 +1,27 @@
+/*
+**
+** Copyright (C) 2019 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+import android.net.LinkAddressParcelable;
+
+parcelable StaticIpConfigurationParcelable {
+    LinkAddressParcelable ipAddress;
+    String gateway;
+    String[] dnsServers;
+    String domains;
+}
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index f0c0462..37bf3a7 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -368,6 +368,29 @@
     }
 
     /**
+     * Returns whether the service is running in always-on VPN mode.
+     */
+    public final boolean isAlwaysOn() {
+        try {
+            return getService().isCallerCurrentAlwaysOnVpnApp();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns whether the service is running in always-on VPN mode blocking connections without
+     * VPN.
+     */
+    public final boolean isLockdownEnabled() {
+        try {
+            return getService().isCallerCurrentAlwaysOnVpnLockdownApp();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Return the communication interface to the service. This method returns
      * {@code null} on {@link Intent}s other than {@link #SERVICE_INTERFACE}
      * action. Applications overriding this method must identify the intent
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
new file mode 100644
index 0000000..f28cdc9
--- /dev/null
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.apf;
+
+/**
+ * APF program support capabilities.
+ *
+ * @hide
+ */
+public class ApfCapabilities {
+    /**
+     * Version of APF instruction set supported for packet filtering. 0 indicates no support for
+     * packet filtering using APF programs.
+     */
+    public final int apfVersionSupported;
+
+    /**
+     * Maximum size of APF program allowed.
+     */
+    public final int maximumApfProgramSize;
+
+    /**
+     * Format of packets passed to APF filter. Should be one of ARPHRD_*
+     */
+    public final int apfPacketFormat;
+
+    public ApfCapabilities(
+            int apfVersionSupported, int maximumApfProgramSize, int apfPacketFormat) {
+        this.apfVersionSupported = apfVersionSupported;
+        this.maximumApfProgramSize = maximumApfProgramSize;
+        this.apfPacketFormat = apfPacketFormat;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
+                apfVersionSupported, maximumApfProgramSize, apfPacketFormat);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof  ApfCapabilities)) return false;
+        final ApfCapabilities other = (ApfCapabilities) obj;
+        return apfVersionSupported == other.apfVersionSupported
+                && maximumApfProgramSize == other.maximumApfProgramSize
+                && apfPacketFormat == other.apfPacketFormat;
+    }
+
+    /**
+     * Returns true if the APF interpreter advertises support for the data buffer access opcodes
+     * LDDW and STDW.
+     *
+     * Full LDDW and STDW support is present from APFv4 on.
+     */
+    public boolean hasDataAccess() {
+        return apfVersionSupported >= 4;
+    }
+}
diff --git a/core/java/android/net/dhcp/DhcpServerCallbacks.java b/core/java/android/net/dhcp/DhcpServerCallbacks.java
new file mode 100644
index 0000000..bb56876
--- /dev/null
+++ b/core/java/android/net/dhcp/DhcpServerCallbacks.java
@@ -0,0 +1,33 @@
+/*
+ * 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.dhcp;
+
+/**
+ * Convenience wrapper around IDhcpServerCallbacks.Stub that implements getInterfaceVersion().
+ * @hide
+ */
+public abstract class DhcpServerCallbacks extends IDhcpServerCallbacks.Stub {
+    // TODO: add @Override here once the API is versioned
+
+    /**
+     * Get the version of the aidl interface implemented by the callbacks.
+     */
+    public int getInterfaceVersion() {
+        // TODO: return IDhcpServerCallbacks.VERSION;
+        return 0;
+    }
+}
diff --git a/core/java/android/net/dhcp/DhcpServingParamsParcel.aidl b/core/java/android/net/dhcp/DhcpServingParamsParcel.aidl
new file mode 100644
index 0000000..7b8b9ee
--- /dev/null
+++ b/core/java/android/net/dhcp/DhcpServingParamsParcel.aidl
@@ -0,0 +1,30 @@
+/**
+ *
+ * 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.dhcp;
+
+parcelable DhcpServingParamsParcel {
+    int serverAddr;
+    int serverAddrPrefixLength;
+    int[] defaultRouters;
+    int[] dnsServers;
+    int[] excludedAddrs;
+    long dhcpLeaseTimeSecs;
+    int linkMtu;
+    boolean metered;
+}
+
diff --git a/core/java/android/net/dhcp/IDhcpServer.aidl b/core/java/android/net/dhcp/IDhcpServer.aidl
new file mode 100644
index 0000000..559433b
--- /dev/null
+++ b/core/java/android/net/dhcp/IDhcpServer.aidl
@@ -0,0 +1,32 @@
+/**
+ * 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 perNmissions and
+ * limitations under the License.
+ */
+
+package android.net.dhcp;
+
+import android.net.INetworkStackStatusCallback;
+import android.net.dhcp.DhcpServingParamsParcel;
+
+/** @hide */
+oneway interface IDhcpServer {
+    const int STATUS_UNKNOWN = 0;
+    const int STATUS_SUCCESS = 1;
+    const int STATUS_INVALID_ARGUMENT = 2;
+    const int STATUS_UNKNOWN_ERROR = 3;
+
+    void start(in INetworkStackStatusCallback cb);
+    void updateParams(in DhcpServingParamsParcel params, in INetworkStackStatusCallback cb);
+    void stop(in INetworkStackStatusCallback cb);
+}
diff --git a/core/java/android/net/dhcp/IDhcpServerCallbacks.aidl b/core/java/android/net/dhcp/IDhcpServerCallbacks.aidl
new file mode 100644
index 0000000..7ab4dcd
--- /dev/null
+++ b/core/java/android/net/dhcp/IDhcpServerCallbacks.aidl
@@ -0,0 +1,24 @@
+/**
+ * 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 perNmissions and
+ * limitations under the License.
+ */
+
+package android.net.dhcp;
+
+import android.net.dhcp.IDhcpServer;
+
+/** @hide */
+oneway interface IDhcpServerCallbacks {
+    void onDhcpServerCreated(int statusCode, in IDhcpServer server);
+}
diff --git a/core/java/android/net/ip/IIpClient.aidl b/core/java/android/net/ip/IIpClient.aidl
new file mode 100644
index 0000000..7769ec2
--- /dev/null
+++ b/core/java/android/net/ip/IIpClient.aidl
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+package android.net.ip;
+
+import android.net.ProxyInfoParcelable;
+import android.net.ProvisioningConfigurationParcelable;
+
+/** @hide */
+oneway interface IIpClient {
+    void completedPreDhcpAction();
+    void confirmConfiguration();
+    void readPacketFilterComplete(in byte[] data);
+    void shutdown();
+    void startProvisioning(in ProvisioningConfigurationParcelable req);
+    void stop();
+    void setTcpBufferSizes(in String tcpBufferSizes);
+    void setHttpProxy(in ProxyInfoParcelable proxyInfo);
+    void setMulticastFilter(boolean enabled);
+}
diff --git a/core/java/android/net/ip/IIpClientCallbacks.aidl b/core/java/android/net/ip/IIpClientCallbacks.aidl
new file mode 100644
index 0000000..f077e3b
--- /dev/null
+++ b/core/java/android/net/ip/IIpClientCallbacks.aidl
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+package android.net.ip;
+
+import android.net.LinkPropertiesParcelable;
+import android.net.ip.IIpClient;
+import android.net.DhcpResultsParcelable;
+
+/** @hide */
+oneway interface IIpClientCallbacks {
+    void onIpClientCreated(in IIpClient ipClient);
+
+    void onPreDhcpAction();
+    void onPostDhcpAction();
+
+    // This is purely advisory and not an indication of provisioning
+    // success or failure.  This is only here for callers that want to
+    // expose DHCPv4 results to other APIs (e.g., WifiInfo#setInetAddress).
+    // DHCPv4 or static IPv4 configuration failure or success can be
+    // determined by whether or not the passed-in DhcpResults object is
+    // null or not.
+    void onNewDhcpResults(in DhcpResultsParcelable dhcpResults);
+
+    void onProvisioningSuccess(in LinkPropertiesParcelable newLp);
+    void onProvisioningFailure(in LinkPropertiesParcelable newLp);
+
+    // Invoked on LinkProperties changes.
+    void onLinkPropertiesChange(in LinkPropertiesParcelable newLp);
+
+    // Called when the internal IpReachabilityMonitor (if enabled) has
+    // detected the loss of a critical number of required neighbors.
+    void onReachabilityLost(in String logMsg);
+
+    // Called when the IpClient state machine terminates.
+    void onQuit();
+
+    // Install an APF program to filter incoming packets.
+    void installPacketFilter(in byte[] filter);
+
+    // Asynchronously read back the APF program & data buffer from the wifi driver.
+    // Due to Wifi HAL limitations, the current implementation only supports dumping the entire
+    // buffer. In response to this request, the driver returns the data buffer asynchronously
+    // by sending an IpClient#EVENT_READ_PACKET_FILTER_COMPLETE message.
+    void startReadPacketFilter();
+
+    // If multicast filtering cannot be accomplished with APF, this function will be called to
+    // actuate multicast filtering using another means.
+    void setFallbackMulticastFilter(boolean enabled);
+
+    // Enabled/disable Neighbor Discover offload functionality. This is
+    // called, for example, whenever 464xlat is being started or stopped.
+    void setNeighborDiscoveryOffload(boolean enable);
+}
\ No newline at end of file
diff --git a/core/java/android/net/ip/IpClientCallbacks.java b/core/java/android/net/ip/IpClientCallbacks.java
new file mode 100644
index 0000000..db01ae4
--- /dev/null
+++ b/core/java/android/net/ip/IpClientCallbacks.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import android.net.DhcpResults;
+import android.net.LinkProperties;
+
+/**
+ * Callbacks for handling IpClient events.
+ *
+ * This is a convenience class to allow clients not to override all methods of IIpClientCallbacks,
+ * and avoid unparceling arguments.
+ * These methods are called asynchronously on a Binder thread, as IpClient lives in a different
+ * process.
+ * @hide
+ */
+public class IpClientCallbacks {
+
+    /**
+     * Callback called upon IpClient creation.
+     *
+     * @param ipClient The Binder token to communicate with IpClient.
+     */
+    public void onIpClientCreated(IIpClient ipClient) {}
+
+    /**
+     * Callback called prior to DHCP discovery/renewal.
+     *
+     * <p>In order to receive onPreDhcpAction(), call #withPreDhcpAction() when constructing a
+     * ProvisioningConfiguration.
+     *
+     * <p>Implementations of onPreDhcpAction() must call IpClient#completedPreDhcpAction() to
+     * indicate that DHCP is clear to proceed.
+      */
+    public void onPreDhcpAction() {}
+
+    /**
+     * Callback called after DHCP discovery/renewal.
+     */
+    public void onPostDhcpAction() {}
+
+    /**
+     * Callback called when new DHCP results are available.
+     *
+     * <p>This is purely advisory and not an indication of provisioning success or failure.  This is
+     * only here for callers that want to expose DHCPv4 results to other APIs
+     * (e.g., WifiInfo#setInetAddress).
+     *
+     * <p>DHCPv4 or static IPv4 configuration failure or success can be determined by whether or not
+     * the passed-in DhcpResults object is null.
+     */
+    public void onNewDhcpResults(DhcpResults dhcpResults) {}
+
+    /**
+     * Indicates that provisioning was successful.
+     */
+    public void onProvisioningSuccess(LinkProperties newLp) {}
+
+    /**
+     * Indicates that provisioning failed.
+     */
+    public void onProvisioningFailure(LinkProperties newLp) {}
+
+    /**
+     * Invoked on LinkProperties changes.
+     */
+    public void onLinkPropertiesChange(LinkProperties newLp) {}
+
+    /**Called when the internal IpReachabilityMonitor (if enabled) has
+     * detected the loss of a critical number of required neighbors.
+     */
+    public void onReachabilityLost(String logMsg) {}
+
+    /**
+     * Called when the IpClient state machine terminates.
+     */
+    public void onQuit() {}
+
+    /**
+     * Called to indicate that a new APF program must be installed to filter incoming packets.
+     */
+    public void installPacketFilter(byte[] filter) {}
+
+    /**
+     * Called to indicate that the APF Program & data buffer must be read asynchronously from the
+     * wifi driver.
+     *
+     * <p>Due to Wifi HAL limitations, the current implementation only supports dumping the entire
+     * buffer. In response to this request, the driver returns the data buffer asynchronously
+     * by sending an IpClient#EVENT_READ_PACKET_FILTER_COMPLETE message.
+     */
+    public void startReadPacketFilter() {}
+
+    /**
+     * If multicast filtering cannot be accomplished with APF, this function will be called to
+     * actuate multicast filtering using another means.
+     */
+    public void setFallbackMulticastFilter(boolean enabled) {}
+
+    /**
+     * Enabled/disable Neighbor Discover offload functionality. This is called, for example,
+     * whenever 464xlat is being started or stopped.
+     */
+    public void setNeighborDiscoveryOffload(boolean enable) {}
+}
diff --git a/core/java/android/net/ipmemorystore/Blob.aidl b/core/java/android/net/ipmemorystore/Blob.aidl
new file mode 100644
index 0000000..9dbef11
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/Blob.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.ipmemorystore;
+
+/**
+ * A blob of data opaque to the memory store. The client mutates this at its own risk,
+ * and it is strongly suggested to never do it at all and treat this as immutable.
+ * {@hide}
+ */
+parcelable Blob {
+    byte[] data;
+}
diff --git a/core/java/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl b/core/java/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl
new file mode 100644
index 0000000..4926feb
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnBlobRetrievedListener.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.ipmemorystore;
+
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnBlobRetrievedListener {
+    /**
+     * Private data was retrieved for the L2 key and name specified.
+     * Note this does not return the client ID, as clients are expected to only ever use one ID.
+     */
+     void onBlobRetrieved(in StatusParcelable status, in String l2Key, in String name,
+             in Blob data);
+}
diff --git a/core/java/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl b/core/java/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl
new file mode 100644
index 0000000..dea0cc4
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnL2KeyResponseListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.ipmemorystore;
+
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnL2KeyResponseListener {
+    /**
+     * The operation completed with the specified L2 key.
+     */
+     void onL2KeyResponse(in StatusParcelable status, in String l2Key);
+}
diff --git a/core/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl b/core/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl
new file mode 100644
index 0000000..fb4ca3b
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.ipmemorystore;
+
+import android.net.ipmemorystore.NetworkAttributesParcelable;
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnNetworkAttributesRetrieved {
+    /**
+     * Network attributes were fetched for the specified L2 key. While the L2 key will never
+     * be null, the attributes may be if no data is stored about this L2 key.
+     */
+     void onNetworkAttributesRetrieved(in StatusParcelable status, in String l2Key,
+             in NetworkAttributesParcelable attributes);
+}
diff --git a/core/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl b/core/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl
new file mode 100644
index 0000000..294bd3b
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl
@@ -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.net.ipmemorystore;
+
+import android.net.ipmemorystore.SameL3NetworkResponseParcelable;
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnSameNetworkResponseListener {
+    /**
+     * The memory store has come up with the answer to a query that was sent.
+     */
+     void onSameNetworkResponse(in StatusParcelable status,
+             in SameL3NetworkResponseParcelable response);
+}
diff --git a/core/java/android/net/ipmemorystore/IOnStatusListener.aidl b/core/java/android/net/ipmemorystore/IOnStatusListener.aidl
new file mode 100644
index 0000000..5d07504
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/IOnStatusListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.ipmemorystore;
+
+import android.net.ipmemorystore.StatusParcelable;
+
+/** {@hide} */
+oneway interface IOnStatusListener {
+    /**
+     * The operation has completed with the specified status.
+     */
+     void onComplete(in StatusParcelable status);
+}
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributes.java b/core/java/android/net/ipmemorystore/NetworkAttributes.java
new file mode 100644
index 0000000..6a9eae0
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/NetworkAttributes.java
@@ -0,0 +1,323 @@
+/*
+ * 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.ipmemorystore;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.StringJoiner;
+
+/**
+ * A POD object to represent attributes of a single L2 network entry.
+ * @hide
+ */
+public class NetworkAttributes {
+    private static final boolean DBG = true;
+
+    // Weight cutoff for grouping. To group, a similarity score is computed with the following
+    // algorithm : if both fields are non-null and equals() then add their assigned weight, else if
+    // both are null then add a portion of their assigned weight (see NULL_MATCH_WEIGHT),
+    // otherwise add nothing.
+    // As a guideline, this should be something like 60~75% of the total weights in this class. The
+    // design states "in essence a reader should imagine that if two important columns don't match,
+    // or one important and several unimportant columns don't match then the two records are
+    // considered a different group".
+    private static final float TOTAL_WEIGHT_CUTOFF = 520.0f;
+    // The portion of the weight that is earned when scoring group-sameness by having both columns
+    // being null. This is because some networks rightfully don't have some attributes (e.g. a
+    // V6-only network won't have an assigned V4 address) and both being null should count for
+    // something, but attributes may also be null just because data is unavailable.
+    private static final float NULL_MATCH_WEIGHT = 0.25f;
+
+    // The v4 address that was assigned to this device the last time it joined this network.
+    // This typically comes from DHCP but could be something else like static configuration.
+    // This does not apply to IPv6.
+    // TODO : add a list of v6 prefixes for the v6 case.
+    @Nullable
+    public final Inet4Address assignedV4Address;
+    private static final float WEIGHT_ASSIGNEDV4ADDR = 300.0f;
+
+    // Optionally supplied by the client if it has an opinion on L3 network. For example, this
+    // could be a hash of the SSID + security type on WiFi.
+    @Nullable
+    public final String groupHint;
+    private static final float WEIGHT_GROUPHINT = 300.0f;
+
+    // The list of DNS server addresses.
+    @Nullable
+    public final List<InetAddress> dnsAddresses;
+    private static final float WEIGHT_DNSADDRESSES = 200.0f;
+
+    // The mtu on this network.
+    @Nullable
+    public final Integer mtu;
+    private static final float WEIGHT_MTU = 50.0f;
+
+    // The sum of all weights in this class. Tests ensure that this stays equal to the total of
+    // all weights.
+    /** @hide */
+    @VisibleForTesting
+    public static final float TOTAL_WEIGHT = WEIGHT_ASSIGNEDV4ADDR
+            + WEIGHT_GROUPHINT
+            + WEIGHT_DNSADDRESSES
+            + WEIGHT_MTU;
+
+    /** @hide */
+    @VisibleForTesting
+    public NetworkAttributes(
+            @Nullable final Inet4Address assignedV4Address,
+            @Nullable final String groupHint,
+            @Nullable final List<InetAddress> dnsAddresses,
+            @Nullable final Integer mtu) {
+        if (mtu != null && mtu < 0) throw new IllegalArgumentException("MTU can't be negative");
+        this.assignedV4Address = assignedV4Address;
+        this.groupHint = groupHint;
+        this.dnsAddresses = null == dnsAddresses ? null :
+                Collections.unmodifiableList(new ArrayList<>(dnsAddresses));
+        this.mtu = mtu;
+    }
+
+    @VisibleForTesting
+    public NetworkAttributes(@NonNull final NetworkAttributesParcelable parcelable) {
+        // The call to the other constructor must be the first statement of this constructor,
+        // so everything has to be inline
+        this((Inet4Address) getByAddressOrNull(parcelable.assignedV4Address),
+                parcelable.groupHint,
+                blobArrayToInetAddressList(parcelable.dnsAddresses),
+                parcelable.mtu >= 0 ? parcelable.mtu : null);
+    }
+
+    @Nullable
+    private static InetAddress getByAddressOrNull(@Nullable final byte[] address) {
+        try {
+            return InetAddress.getByAddress(address);
+        } catch (UnknownHostException e) {
+            return null;
+        }
+    }
+
+    @Nullable
+    private static List<InetAddress> blobArrayToInetAddressList(@Nullable final Blob[] blobs) {
+        if (null == blobs) return null;
+        final ArrayList<InetAddress> list = new ArrayList<>(blobs.length);
+        for (final Blob b : blobs) {
+            final InetAddress addr = getByAddressOrNull(b.data);
+            if (null != addr) list.add(addr);
+        }
+        return list;
+    }
+
+    @Nullable
+    private static Blob[] inetAddressListToBlobArray(@Nullable final List<InetAddress> addresses) {
+        if (null == addresses) return null;
+        final ArrayList<Blob> blobs = new ArrayList<>();
+        for (int i = 0; i < addresses.size(); ++i) {
+            final InetAddress addr = addresses.get(i);
+            if (null == addr) continue;
+            final Blob b = new Blob();
+            b.data = addr.getAddress();
+            blobs.add(b);
+        }
+        return blobs.toArray(new Blob[0]);
+    }
+
+    /** Converts this NetworkAttributes to a parcelable object */
+    @NonNull
+    public NetworkAttributesParcelable toParcelable() {
+        final NetworkAttributesParcelable parcelable = new NetworkAttributesParcelable();
+        parcelable.assignedV4Address =
+                (null == assignedV4Address) ? null : assignedV4Address.getAddress();
+        parcelable.groupHint = groupHint;
+        parcelable.dnsAddresses = inetAddressListToBlobArray(dnsAddresses);
+        parcelable.mtu = (null == mtu) ? -1 : mtu;
+        return parcelable;
+    }
+
+    private float samenessContribution(final float weight,
+            @Nullable final Object o1, @Nullable final Object o2) {
+        if (null == o1) {
+            return (null == o2) ? weight * NULL_MATCH_WEIGHT : 0f;
+        }
+        return Objects.equals(o1, o2) ? weight : 0f;
+    }
+
+    /** @hide */
+    public float getNetworkGroupSamenessConfidence(@NonNull final NetworkAttributes o) {
+        final float samenessScore =
+                samenessContribution(WEIGHT_ASSIGNEDV4ADDR, assignedV4Address, o.assignedV4Address)
+                + samenessContribution(WEIGHT_GROUPHINT, groupHint, o.groupHint)
+                + samenessContribution(WEIGHT_DNSADDRESSES, dnsAddresses, o.dnsAddresses)
+                + samenessContribution(WEIGHT_MTU, mtu, o.mtu);
+        // The minimum is 0, the max is TOTAL_WEIGHT and should be represented by 1.0, and
+        // TOTAL_WEIGHT_CUTOFF should represent 0.5, but there is no requirement that
+        // TOTAL_WEIGHT_CUTOFF would be half of TOTAL_WEIGHT (indeed, it should not be).
+        // So scale scores under the cutoff between 0 and 0.5, and the scores over the cutoff
+        // between 0.5 and 1.0.
+        if (samenessScore < TOTAL_WEIGHT_CUTOFF) {
+            return samenessScore / (TOTAL_WEIGHT_CUTOFF * 2);
+        } else {
+            return (samenessScore - TOTAL_WEIGHT_CUTOFF) / (TOTAL_WEIGHT - TOTAL_WEIGHT_CUTOFF) / 2
+                    + 0.5f;
+        }
+    }
+
+    /** @hide */
+    public static class Builder {
+        @Nullable
+        private Inet4Address mAssignedAddress;
+        @Nullable
+        private String mGroupHint;
+        @Nullable
+        private List<InetAddress> mDnsAddresses;
+        @Nullable
+        private Integer mMtu;
+
+        /**
+         * Set the assigned address.
+         * @param assignedV4Address The assigned address.
+         * @return This builder.
+         */
+        public Builder setAssignedV4Address(@Nullable final Inet4Address assignedV4Address) {
+            mAssignedAddress = assignedV4Address;
+            return this;
+        }
+
+        /**
+         * Set the group hint.
+         * @param groupHint The group hint.
+         * @return This builder.
+         */
+        public Builder setGroupHint(@Nullable final String groupHint) {
+            mGroupHint = groupHint;
+            return this;
+        }
+
+        /**
+         * Set the DNS addresses.
+         * @param dnsAddresses The DNS addresses.
+         * @return This builder.
+         */
+        public Builder setDnsAddresses(@Nullable final List<InetAddress> dnsAddresses) {
+            if (DBG && null != dnsAddresses) {
+                // Parceling code crashes if one of the addresses is null, therefore validate
+                // them when running in debug.
+                for (final InetAddress address : dnsAddresses) {
+                    if (null == address) throw new IllegalArgumentException("Null DNS address");
+                }
+            }
+            this.mDnsAddresses = dnsAddresses;
+            return this;
+        }
+
+        /**
+         * Set the MTU.
+         * @param mtu The MTU.
+         * @return This builder.
+         */
+        public Builder setMtu(@Nullable final Integer mtu) {
+            if (null != mtu && mtu < 0) throw new IllegalArgumentException("MTU can't be negative");
+            mMtu = mtu;
+            return this;
+        }
+
+        /**
+         * Return the built NetworkAttributes object.
+         * @return The built NetworkAttributes object.
+         */
+        public NetworkAttributes build() {
+            return new NetworkAttributes(mAssignedAddress, mGroupHint, mDnsAddresses, mMtu);
+        }
+    }
+
+    /** @hide */
+    public boolean isEmpty() {
+        return (null == assignedV4Address) && (null == groupHint)
+                && (null == dnsAddresses) && (null == mtu);
+    }
+
+    @Override
+    public boolean equals(@Nullable final Object o) {
+        if (!(o instanceof NetworkAttributes)) return false;
+        final NetworkAttributes other = (NetworkAttributes) o;
+        return Objects.equals(assignedV4Address, other.assignedV4Address)
+                && Objects.equals(groupHint, other.groupHint)
+                && Objects.equals(dnsAddresses, other.dnsAddresses)
+                && Objects.equals(mtu, other.mtu);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(assignedV4Address, groupHint, dnsAddresses, mtu);
+    }
+
+    /** Pretty print */
+    @Override
+    public String toString() {
+        final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}");
+        final ArrayList<String> nullFields = new ArrayList<>();
+
+        if (null != assignedV4Address) {
+            resultJoiner.add("assignedV4Addr :");
+            resultJoiner.add(assignedV4Address.toString());
+        } else {
+            nullFields.add("assignedV4Addr");
+        }
+
+        if (null != groupHint) {
+            resultJoiner.add("groupHint :");
+            resultJoiner.add(groupHint);
+        } else {
+            nullFields.add("groupHint");
+        }
+
+        if (null != dnsAddresses) {
+            resultJoiner.add("dnsAddr : [");
+            for (final InetAddress addr : dnsAddresses) {
+                resultJoiner.add(addr.getHostAddress());
+            }
+            resultJoiner.add("]");
+        } else {
+            nullFields.add("dnsAddr");
+        }
+
+        if (null != mtu) {
+            resultJoiner.add("mtu :");
+            resultJoiner.add(mtu.toString());
+        } else {
+            nullFields.add("mtu");
+        }
+
+        if (!nullFields.isEmpty()) {
+            resultJoiner.add("; Null fields : [");
+            for (final String field : nullFields) {
+                resultJoiner.add(field);
+            }
+            resultJoiner.add("]");
+        }
+
+        return resultJoiner.toString();
+    }
+}
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl b/core/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
new file mode 100644
index 0000000..0894d72
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
@@ -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.
+ */
+
+package android.net.ipmemorystore;
+
+// Blob[] is used to represent an array of byte[], as structured AIDL does not support arrays
+// of arrays.
+import android.net.ipmemorystore.Blob;
+
+/**
+ * An object to represent attributes of a single L2 network entry.
+ * See NetworkAttributes.java for a description of each field. The types used in this class
+ * are structured parcelable types instead of the richer types of the NetworkAttributes object,
+ * but they have the same purpose. The NetworkAttributes.java file also contains the code
+ * to convert the richer types to the parcelable types and back.
+ * @hide
+ */
+parcelable NetworkAttributesParcelable {
+    byte[] assignedV4Address;
+    String groupHint;
+    Blob[] dnsAddresses;
+    int mtu;
+}
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java b/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
new file mode 100644
index 0000000..291aca8
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
@@ -0,0 +1,147 @@
+/*
+ * 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.ipmemorystore;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * An object representing the answer to a query whether two given L2 networks represent the
+ * same L3 network. Parcels as a SameL3NetworkResponseParceled object.
+ * @hide
+ */
+public class SameL3NetworkResponse {
+    @IntDef(prefix = "NETWORK_",
+            value = {NETWORK_SAME, NETWORK_DIFFERENT, NETWORK_NEVER_CONNECTED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NetworkSameness {}
+
+    /**
+     * Both L2 networks represent the same L3 network.
+     */
+    public static final int NETWORK_SAME = 1;
+
+    /**
+     * The two L2 networks represent a different L3 network.
+     */
+    public static final int NETWORK_DIFFERENT = 2;
+
+    /**
+     * The device has never connected to at least one of these two L2 networks, or data
+     * has been wiped. Therefore the device has never seen the L3 network behind at least
+     * one of these two L2 networks, and can't evaluate whether it's the same as the other.
+     */
+    public static final int NETWORK_NEVER_CONNECTED = 3;
+
+    /**
+     * The first L2 key specified in the query.
+     */
+    @NonNull
+    public final String l2Key1;
+
+    /**
+     * The second L2 key specified in the query.
+     */
+    @NonNull
+    public final String l2Key2;
+
+    /**
+     * A confidence value indicating whether the two L2 networks represent the same L3 network.
+     *
+     * If both L2 networks were known, this value will be between 0.0 and 1.0, with 0.0
+     * representing complete confidence that the given L2 networks represent a different
+     * L3 network, and 1.0 representing complete confidence that the given L2 networks
+     * represent the same L3 network.
+     * If at least one of the L2 networks was not known, this value will be outside of the
+     * 0.0~1.0 range.
+     *
+     * Most apps should not be interested in this, and are encouraged to use the collapsing
+     * {@link #getNetworkSameness()} function below.
+     */
+    public final float confidence;
+
+    /**
+     * @return whether the two L2 networks represent the same L3 network. Either
+     *     {@code NETWORK_SAME}, {@code NETWORK_DIFFERENT} or {@code NETWORK_NEVER_CONNECTED}.
+     */
+    @NetworkSameness
+    public final int getNetworkSameness() {
+        if (confidence > 1.0 || confidence < 0.0) return NETWORK_NEVER_CONNECTED;
+        return confidence > 0.5 ? NETWORK_SAME : NETWORK_DIFFERENT;
+    }
+
+    /** @hide */
+    public SameL3NetworkResponse(@NonNull final String l2Key1, @NonNull final String l2Key2,
+            final float confidence) {
+        this.l2Key1 = l2Key1;
+        this.l2Key2 = l2Key2;
+        this.confidence = confidence;
+    }
+
+    /** Builds a SameL3NetworkResponse from a parcelable object */
+    @VisibleForTesting
+    public SameL3NetworkResponse(@NonNull final SameL3NetworkResponseParcelable parceled) {
+        this(parceled.l2Key1, parceled.l2Key2, parceled.confidence);
+    }
+
+    /** Converts this SameL3NetworkResponse to a parcelable object */
+    @NonNull
+    public SameL3NetworkResponseParcelable toParcelable() {
+        final SameL3NetworkResponseParcelable parcelable = new SameL3NetworkResponseParcelable();
+        parcelable.l2Key1 = l2Key1;
+        parcelable.l2Key2 = l2Key2;
+        parcelable.confidence = confidence;
+        return parcelable;
+    }
+
+    // Note key1 and key2 have to match each other for this to return true. If
+    // key1 matches o.key2 and the other way around this returns false.
+    @Override
+    public boolean equals(@Nullable final Object o) {
+        if (!(o instanceof SameL3NetworkResponse)) return false;
+        final SameL3NetworkResponse other = (SameL3NetworkResponse) o;
+        return l2Key1.equals(other.l2Key1) && l2Key2.equals(other.l2Key2)
+                && confidence == other.confidence;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(l2Key1, l2Key2, confidence);
+    }
+
+    @Override
+    /** Pretty print */
+    public String toString() {
+        switch (getNetworkSameness()) {
+            case NETWORK_SAME:
+                return "\"" + l2Key1 + "\" same L3 network as \"" + l2Key2 + "\"";
+            case NETWORK_DIFFERENT:
+                return "\"" + l2Key1 + "\" different L3 network from \"" + l2Key2 + "\"";
+            case NETWORK_NEVER_CONNECTED:
+                return "\"" + l2Key1 + "\" can't be tested against \"" + l2Key2 + "\"";
+            default:
+                return "Buggy sameness value ? \"" + l2Key1 + "\", \"" + l2Key2 + "\"";
+        }
+    }
+}
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl b/core/java/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl
new file mode 100644
index 0000000..7196699
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/SameL3NetworkResponseParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.ipmemorystore;
+
+/** {@hide} */
+parcelable SameL3NetworkResponseParcelable {
+    String l2Key1;
+    String l2Key2;
+    float confidence;
+}
diff --git a/core/java/android/net/ipmemorystore/Status.java b/core/java/android/net/ipmemorystore/Status.java
new file mode 100644
index 0000000..cacd42d
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/Status.java
@@ -0,0 +1,73 @@
+/*
+ * 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.ipmemorystore;
+
+import android.annotation.NonNull;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A parcelable status representing the result of an operation.
+ * Parcels as StatusParceled.
+ * @hide
+ */
+public class Status {
+    public static final int SUCCESS = 0;
+
+    public static final int ERROR_GENERIC = -1;
+    public static final int ERROR_ILLEGAL_ARGUMENT = -2;
+    public static final int ERROR_DATABASE_CANNOT_BE_OPENED = -3;
+    public static final int ERROR_STORAGE = -4;
+
+    public final int resultCode;
+
+    public Status(final int resultCode) {
+        this.resultCode = resultCode;
+    }
+
+    @VisibleForTesting
+    public Status(@NonNull final StatusParcelable parcelable) {
+        this(parcelable.resultCode);
+    }
+
+    /** Converts this Status to a parcelable object */
+    @NonNull
+    public StatusParcelable toParcelable() {
+        final StatusParcelable parcelable = new StatusParcelable();
+        parcelable.resultCode = resultCode;
+        return parcelable;
+    }
+
+    public boolean isSuccess() {
+        return SUCCESS == resultCode;
+    }
+
+    /** Pretty print */
+    @Override
+    public String toString() {
+        switch (resultCode) {
+            case SUCCESS: return "SUCCESS";
+            case ERROR_GENERIC: return "GENERIC ERROR";
+            case ERROR_ILLEGAL_ARGUMENT: return "ILLEGAL ARGUMENT";
+            case ERROR_DATABASE_CANNOT_BE_OPENED: return "DATABASE CANNOT BE OPENED";
+            // "DB storage error" is not very helpful but SQLite does not provide specific error
+            // codes upon store failure. Thus this indicates SQLite returned some error upon store
+            case ERROR_STORAGE: return "DATABASE STORAGE ERROR";
+            default: return "Unknown value ?!";
+        }
+    }
+}
diff --git a/core/java/android/net/ipmemorystore/StatusParcelable.aidl b/core/java/android/net/ipmemorystore/StatusParcelable.aidl
new file mode 100644
index 0000000..fb36ef4
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/StatusParcelable.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.ipmemorystore;
+
+/** {@hide} */
+parcelable StatusParcelable {
+  int resultCode;
+}
diff --git a/core/java/android/net/ipmemorystore/Utils.java b/core/java/android/net/ipmemorystore/Utils.java
new file mode 100644
index 0000000..b361aca
--- /dev/null
+++ b/core/java/android/net/ipmemorystore/Utils.java
@@ -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 android.net.ipmemorystore;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/** {@hide} */
+public class Utils {
+    /** Pretty print */
+    public static String blobToString(@Nullable final Blob blob) {
+        return "Blob : " + byteArrayToString(null == blob ? null : blob.data);
+    }
+
+    /** Pretty print */
+    public static String byteArrayToString(@Nullable final byte[] data) {
+        if (null == data) return "null";
+        final StringBuilder sb = new StringBuilder("[");
+        if (data.length <= 24) {
+            appendByteArray(sb, data, 0, data.length);
+        } else {
+            appendByteArray(sb, data, 0, 16);
+            sb.append("...");
+            appendByteArray(sb, data, data.length - 8, data.length);
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    // Adds the hex representation of the array between the specified indices (inclusive, exclusive)
+    private static void appendByteArray(@NonNull final StringBuilder sb, @NonNull final byte[] ar,
+            final int from, final int to) {
+        for (int i = from; i < to; ++i) {
+            sb.append(String.format("%02X", ar[i]));
+        }
+    }
+}
diff --git a/core/java/android/net/metrics/ApfProgramEvent.java b/core/java/android/net/metrics/ApfProgramEvent.java
index 5dabf35..8601005 100644
--- a/core/java/android/net/metrics/ApfProgramEvent.java
+++ b/core/java/android/net/metrics/ApfProgramEvent.java
@@ -17,6 +17,8 @@
 package android.net.metrics;
 
 import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -36,11 +38,15 @@
  * the APF program in place with a new APF program.
  * {@hide}
  */
-public final class ApfProgramEvent implements Parcelable {
+@TestApi
+@SystemApi
+public final class ApfProgramEvent implements IpConnectivityLog.Event {
 
     // Bitflag constants describing what an Apf program filters.
     // Bits are indexeds from LSB to MSB, starting at index 0.
+    /** @hide */
     public static final int FLAG_MULTICAST_FILTER_ON = 0;
+    /** @hide */
     public static final int FLAG_HAS_IPV4_ADDRESS    = 1;
 
     /** {@hide} */
@@ -48,21 +54,33 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Flags {}
 
+    /** @hide */
     @UnsupportedAppUsage
-    public long lifetime;       // Maximum computed lifetime of the program in seconds
+    public final long lifetime;       // Maximum computed lifetime of the program in seconds
+    /** @hide */
     @UnsupportedAppUsage
-    public long actualLifetime; // Effective program lifetime in seconds
+    public final long actualLifetime; // Effective program lifetime in seconds
+    /** @hide */
     @UnsupportedAppUsage
-    public int filteredRas;     // Number of RAs filtered by the APF program
+    public final int filteredRas;     // Number of RAs filtered by the APF program
+    /** @hide */
     @UnsupportedAppUsage
-    public int currentRas;      // Total number of current RAs at generation time
+    public final int currentRas;      // Total number of current RAs at generation time
+    /** @hide */
     @UnsupportedAppUsage
-    public int programLength;   // Length of the APF program in bytes
+    public final int programLength;   // Length of the APF program in bytes
+    /** @hide */
     @UnsupportedAppUsage
-    public int flags;           // Bitfield compound of FLAG_* constants
+    public final int flags;           // Bitfield compound of FLAG_* constants
 
-    @UnsupportedAppUsage
-    public ApfProgramEvent() {
+    private ApfProgramEvent(long lifetime, long actualLifetime, int filteredRas, int currentRas,
+            int programLength, int flags) {
+        this.lifetime = lifetime;
+        this.actualLifetime = actualLifetime;
+        this.filteredRas = filteredRas;
+        this.currentRas = currentRas;
+        this.programLength = programLength;
+        this.flags = flags;
     }
 
     private ApfProgramEvent(Parcel in) {
@@ -74,6 +92,75 @@
         this.flags = in.readInt();
     }
 
+    /**
+     * Utility to create an instance of {@link ApfProgramEvent}.
+     */
+    public static class Builder {
+        private long mLifetime;
+        private long mActualLifetime;
+        private int mFilteredRas;
+        private int mCurrentRas;
+        private int mProgramLength;
+        private int mFlags;
+
+        /**
+         * Set the maximum computed lifetime of the program in seconds.
+         */
+        public Builder setLifetime(long lifetime) {
+            mLifetime = lifetime;
+            return this;
+        }
+
+        /**
+         * Set the effective program lifetime in seconds.
+         */
+        public Builder setActualLifetime(long lifetime) {
+            mActualLifetime = lifetime;
+            return this;
+        }
+
+        /**
+         * Set the number of RAs filtered by the APF program.
+         */
+        public Builder setFilteredRas(int filteredRas) {
+            mFilteredRas = filteredRas;
+            return this;
+        }
+
+        /**
+         * Set the total number of current RAs at generation time.
+         */
+        public Builder setCurrentRas(int currentRas) {
+            mCurrentRas = currentRas;
+            return this;
+        }
+
+        /**
+         * Set the length of the APF program in bytes.
+         */
+        public Builder setProgramLength(int programLength) {
+            mProgramLength = programLength;
+            return this;
+        }
+
+        /**
+         * Set the flags describing what an Apf program filters.
+         */
+        public Builder setFlags(boolean hasIPv4, boolean multicastFilterOn) {
+            mFlags = flagsFor(hasIPv4, multicastFilterOn);
+            return this;
+        }
+
+        /**
+         * Build a new {@link ApfProgramEvent}.
+         */
+        public ApfProgramEvent build() {
+            return new ApfProgramEvent(mLifetime, mActualLifetime, mFilteredRas, mCurrentRas,
+                    mProgramLength, mFlags);
+        }
+    }
+
+    /** @hide */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeLong(lifetime);
@@ -84,6 +171,7 @@
         out.writeInt(flags);
     }
 
+    /** @hide */
     @Override
     public int describeContents() {
         return 0;
@@ -96,6 +184,7 @@
                 programLength, actualLifetime, lifetimeString, namesOf(flags));
     }
 
+    /** @hide */
     public static final Parcelable.Creator<ApfProgramEvent> CREATOR
             = new Parcelable.Creator<ApfProgramEvent>() {
         public ApfProgramEvent createFromParcel(Parcel in) {
@@ -107,6 +196,7 @@
         }
     };
 
+    /** @hide */
     @UnsupportedAppUsage
     public static @Flags int flagsFor(boolean hasIPv4, boolean multicastFilterOn) {
         int bitfield = 0;
diff --git a/core/java/android/net/metrics/ApfStats.java b/core/java/android/net/metrics/ApfStats.java
index bb2a35c..844a134 100644
--- a/core/java/android/net/metrics/ApfStats.java
+++ b/core/java/android/net/metrics/ApfStats.java
@@ -16,6 +16,8 @@
 
 package android.net.metrics;
 
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -24,42 +26,70 @@
  * An event logged for an interface with APF capabilities when its IpClient state machine exits.
  * {@hide}
  */
-public final class ApfStats implements Parcelable {
+@SystemApi
+@TestApi
+public final class ApfStats implements IpConnectivityLog.Event {
 
-    /** time interval in milliseconds these stastistics covers. */
+    /**
+     * time interval in milliseconds these stastistics covers.
+     * @hide
+     */
     @UnsupportedAppUsage
-    public long durationMs;
-    /** number of received RAs. */
+    public final long durationMs;
+    /**
+     * number of received RAs.
+     * @hide
+     */
     @UnsupportedAppUsage
-    public int receivedRas;
-    /** number of received RAs matching a known RA. */
+    public final int receivedRas;
+    /**
+     * number of received RAs matching a known RA.
+     * @hide
+     */
     @UnsupportedAppUsage
-    public int matchingRas;
-    /** number of received RAs ignored due to the MAX_RAS limit. */
+    public final int matchingRas;
+    /**
+     * number of received RAs ignored due to the MAX_RAS limit.
+     * @hide
+     */
     @UnsupportedAppUsage
-    public int droppedRas;
-    /** number of received RAs with a minimum lifetime of 0. */
+    public final int droppedRas;
+    /**
+     * number of received RAs with a minimum lifetime of 0.
+     * @hide
+     */
     @UnsupportedAppUsage
-    public int zeroLifetimeRas;
-    /** number of received RAs that could not be parsed. */
+    public final int zeroLifetimeRas;
+    /**
+     * number of received RAs that could not be parsed.
+     * @hide
+     */
     @UnsupportedAppUsage
-    public int parseErrors;
-    /** number of APF program updates from receiving RAs.. */
+    public final int parseErrors;
+    /**
+     * number of APF program updates from receiving RAs.
+     * @hide
+     */
     @UnsupportedAppUsage
-    public int programUpdates;
-    /** total number of APF program updates. */
+    public final int programUpdates;
+    /**
+     * total number of APF program updates.
+     * @hide
+     */
     @UnsupportedAppUsage
-    public int programUpdatesAll;
-    /** number of APF program updates from allowing multicast traffic. */
+    public final int programUpdatesAll;
+    /**
+     * number of APF program updates from allowing multicast traffic.
+     * @hide
+     */
     @UnsupportedAppUsage
-    public int programUpdatesAllowingMulticast;
-    /** maximum APF program size advertised by hardware. */
+    public final int programUpdatesAllowingMulticast;
+    /**
+     * maximum APF program size advertised by hardware.
+     * @hide
+     */
     @UnsupportedAppUsage
-    public int maxProgramSize;
-
-    @UnsupportedAppUsage
-    public ApfStats() {
-    }
+    public final int maxProgramSize;
 
     private ApfStats(Parcel in) {
         this.durationMs = in.readLong();
@@ -74,6 +104,130 @@
         this.maxProgramSize = in.readInt();
     }
 
+    private ApfStats(long durationMs, int receivedRas, int matchingRas, int droppedRas,
+            int zeroLifetimeRas, int parseErrors, int programUpdates, int programUpdatesAll,
+            int programUpdatesAllowingMulticast, int maxProgramSize) {
+        this.durationMs = durationMs;
+        this.receivedRas = receivedRas;
+        this.matchingRas = matchingRas;
+        this.droppedRas = droppedRas;
+        this.zeroLifetimeRas = zeroLifetimeRas;
+        this.parseErrors = parseErrors;
+        this.programUpdates = programUpdates;
+        this.programUpdatesAll = programUpdatesAll;
+        this.programUpdatesAllowingMulticast = programUpdatesAllowingMulticast;
+        this.maxProgramSize = maxProgramSize;
+    }
+
+    /**
+     * Utility to create an instance of {@link ApfStats}.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static class Builder {
+        private long mDurationMs;
+        private int mReceivedRas;
+        private int mMatchingRas;
+        private int mDroppedRas;
+        private int mZeroLifetimeRas;
+        private int mParseErrors;
+        private int mProgramUpdates;
+        private int mProgramUpdatesAll;
+        private int mProgramUpdatesAllowingMulticast;
+        private int mMaxProgramSize;
+
+        /**
+         * Set the time interval in milliseconds these statistics covers.
+         */
+        public Builder setDurationMs(long durationMs) {
+            mDurationMs = durationMs;
+            return this;
+        }
+
+        /**
+         * Set the number of received RAs.
+         */
+        public Builder setReceivedRas(int receivedRas) {
+            mReceivedRas = receivedRas;
+            return this;
+        }
+
+        /**
+         * Set the number of received RAs matching a known RA.
+         */
+        public Builder setMatchingRas(int matchingRas) {
+            mMatchingRas = matchingRas;
+            return this;
+        }
+
+        /**
+         * Set the number of received RAs ignored due to the MAX_RAS limit.
+         */
+        public Builder setDroppedRas(int droppedRas) {
+            mDroppedRas = droppedRas;
+            return this;
+        }
+
+        /**
+         * Set the number of received RAs with a minimum lifetime of 0.
+         */
+        public Builder setZeroLifetimeRas(int zeroLifetimeRas) {
+            mZeroLifetimeRas = zeroLifetimeRas;
+            return this;
+        }
+
+        /**
+         * Set the number of received RAs that could not be parsed.
+         */
+        public Builder setParseErrors(int parseErrors) {
+            mParseErrors = parseErrors;
+            return this;
+        }
+
+        /**
+         * Set the number of APF program updates from receiving RAs.
+         */
+        public Builder setProgramUpdates(int programUpdates) {
+            mProgramUpdates = programUpdates;
+            return this;
+        }
+
+        /**
+         * Set the total number of APF program updates.
+         */
+        public Builder setProgramUpdatesAll(int programUpdatesAll) {
+            mProgramUpdatesAll = programUpdatesAll;
+            return this;
+        }
+
+        /**
+         * Set the number of APF program updates from allowing multicast traffic.
+         */
+        public Builder setProgramUpdatesAllowingMulticast(int programUpdatesAllowingMulticast) {
+            mProgramUpdatesAllowingMulticast = programUpdatesAllowingMulticast;
+            return this;
+        }
+
+        /**
+         * Set the maximum APF program size advertised by hardware.
+         */
+        public Builder setMaxProgramSize(int maxProgramSize) {
+            mMaxProgramSize = maxProgramSize;
+            return this;
+        }
+
+        /**
+         * Create a new {@link ApfStats}.
+         */
+        public ApfStats build() {
+            return new ApfStats(mDurationMs, mReceivedRas, mMatchingRas, mDroppedRas,
+                    mZeroLifetimeRas, mParseErrors, mProgramUpdates, mProgramUpdatesAll,
+                    mProgramUpdatesAllowingMulticast, mMaxProgramSize);
+        }
+    }
+
+    /** @hide */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeLong(durationMs);
@@ -88,6 +242,7 @@
         out.writeInt(maxProgramSize);
     }
 
+    /** @hide */
     @Override
     public int describeContents() {
         return 0;
@@ -108,6 +263,7 @@
                 .toString();
     }
 
+    /** @hide */
     public static final Parcelable.Creator<ApfStats> CREATOR = new Parcelable.Creator<ApfStats>() {
         public ApfStats createFromParcel(Parcel in) {
             return new ApfStats(in);
diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java
index 98a7d7e..2a942ee 100644
--- a/core/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -16,6 +16,8 @@
 
 package android.net.metrics;
 
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -24,7 +26,9 @@
  * An event recorded when a DhcpClient state machine transitions to a new state.
  * {@hide}
  */
-public final class DhcpClientEvent implements Parcelable {
+@SystemApi
+@TestApi
+public final class DhcpClientEvent implements IpConnectivityLog.Event {
 
     // Names for recording DhcpClient pseudo-state transitions.
     /** {@hide} Represents transitions from DhcpInitState to DhcpBoundState */
@@ -32,11 +36,13 @@
     /** {@hide} Represents transitions from and to DhcpBoundState via DhcpRenewingState */
     public static final String RENEWING_BOUND = "RenewingBoundState";
 
+    /** @hide */
     public final String msg;
+    /** @hide */
     public final int durationMs;
 
     @UnsupportedAppUsage
-    public DhcpClientEvent(String msg, int durationMs) {
+    private DhcpClientEvent(String msg, int durationMs) {
         this.msg = msg;
         this.durationMs = durationMs;
     }
@@ -46,12 +52,45 @@
         this.durationMs = in.readInt();
     }
 
+    /**
+     * Utility to create an instance of {@link ApfProgramEvent}.
+     */
+    public static class Builder {
+        private String mMsg;
+        private int mDurationMs;
+
+        /**
+         * Set the message of the event.
+         */
+        public Builder setMsg(String msg) {
+            mMsg = msg;
+            return this;
+        }
+
+        /**
+         * Set the duration of the event in milliseconds.
+         */
+        public Builder setDurationMs(int durationMs) {
+            mDurationMs = durationMs;
+            return this;
+        }
+
+        /**
+         * Create a new {@link DhcpClientEvent}.
+         */
+        public DhcpClientEvent build() {
+            return new DhcpClientEvent(mMsg, mDurationMs);
+        }
+    }
+
+    /** @hide */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(msg);
         out.writeInt(durationMs);
     }
 
+    /** @hide */
     @Override
     public int describeContents() {
         return 0;
@@ -62,6 +101,7 @@
         return String.format("DhcpClientEvent(%s, %dms)", msg, durationMs);
     }
 
+    /** @hide */
     public static final Parcelable.Creator<DhcpClientEvent> CREATOR
         = new Parcelable.Creator<DhcpClientEvent>() {
         public DhcpClientEvent createFromParcel(Parcel in) {
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
index c6c06f0..18fde80 100644
--- a/core/java/android/net/metrics/DhcpErrorEvent.java
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -16,7 +16,8 @@
 
 package android.net.metrics;
 
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.SparseArray;
@@ -27,48 +28,34 @@
  * Event class used to record error events when parsing DHCP response packets.
  * {@hide}
  */
-public final class DhcpErrorEvent implements Parcelable {
+@SystemApi
+@TestApi
+public final class DhcpErrorEvent implements IpConnectivityLog.Event {
     public static final int L2_ERROR   = 1;
     public static final int L3_ERROR   = 2;
     public static final int L4_ERROR   = 3;
     public static final int DHCP_ERROR = 4;
     public static final int MISC_ERROR = 5;
 
-    @UnsupportedAppUsage
     public static final int L2_TOO_SHORT               = makeErrorCode(L2_ERROR, 1);
-    @UnsupportedAppUsage
     public static final int L2_WRONG_ETH_TYPE          = makeErrorCode(L2_ERROR, 2);
 
-    @UnsupportedAppUsage
     public static final int L3_TOO_SHORT               = makeErrorCode(L3_ERROR, 1);
-    @UnsupportedAppUsage
     public static final int L3_NOT_IPV4                = makeErrorCode(L3_ERROR, 2);
-    @UnsupportedAppUsage
     public static final int L3_INVALID_IP              = makeErrorCode(L3_ERROR, 3);
 
-    @UnsupportedAppUsage
     public static final int L4_NOT_UDP                 = makeErrorCode(L4_ERROR, 1);
-    @UnsupportedAppUsage
     public static final int L4_WRONG_PORT              = makeErrorCode(L4_ERROR, 2);
 
-    @UnsupportedAppUsage
     public static final int BOOTP_TOO_SHORT            = makeErrorCode(DHCP_ERROR, 1);
-    @UnsupportedAppUsage
     public static final int DHCP_BAD_MAGIC_COOKIE      = makeErrorCode(DHCP_ERROR, 2);
-    @UnsupportedAppUsage
     public static final int DHCP_INVALID_OPTION_LENGTH = makeErrorCode(DHCP_ERROR, 3);
-    @UnsupportedAppUsage
     public static final int DHCP_NO_MSG_TYPE           = makeErrorCode(DHCP_ERROR, 4);
-    @UnsupportedAppUsage
     public static final int DHCP_UNKNOWN_MSG_TYPE      = makeErrorCode(DHCP_ERROR, 5);
-    @UnsupportedAppUsage
     public static final int DHCP_NO_COOKIE             = makeErrorCode(DHCP_ERROR, 6);
 
-    @UnsupportedAppUsage
     public static final int BUFFER_UNDERFLOW           = makeErrorCode(MISC_ERROR, 1);
-    @UnsupportedAppUsage
     public static final int RECEIVE_ERROR              = makeErrorCode(MISC_ERROR, 2);
-    @UnsupportedAppUsage
     public static final int PARSING_ERROR              = makeErrorCode(MISC_ERROR, 3);
 
     // error code byte format (MSB to LSB):
@@ -76,9 +63,9 @@
     // byte 1: error subtype
     // byte 2: unused
     // byte 3: optional code
+    /** @hide */
     public final int errorCode;
 
-    @UnsupportedAppUsage
     public DhcpErrorEvent(int errorCode) {
         this.errorCode = errorCode;
     }
@@ -87,16 +74,19 @@
         this.errorCode = in.readInt();
     }
 
+    /** @hide */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(errorCode);
     }
 
+    /** @hide */
     @Override
     public int describeContents() {
         return 0;
     }
 
+    /** @hide */
     public static final Parcelable.Creator<DhcpErrorEvent> CREATOR
         = new Parcelable.Creator<DhcpErrorEvent>() {
         public DhcpErrorEvent createFromParcel(Parcel in) {
@@ -108,7 +98,6 @@
         }
     };
 
-    @UnsupportedAppUsage
     public static int errorCodeWithOption(int errorCode, int option) {
         return (0xFFFF0000 & errorCode) | (0xFF & option);
     }
diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
index 998f4ba..5b5a235 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -16,13 +16,16 @@
 
 package android.net.metrics;
 
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.net.ConnectivityMetricsEvent;
 import android.net.IIpConnectivityMetrics;
+import android.net.Network;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.BitUtils;
 
@@ -30,18 +33,29 @@
  * Class for logging IpConnectvity events with IpConnectivityMetrics
  * {@hide}
  */
+@SystemApi
+@TestApi
 public class IpConnectivityLog {
     private static final String TAG = IpConnectivityLog.class.getSimpleName();
     private static final boolean DBG = false;
 
+    /** @hide */
     public static final String SERVICE_NAME = "connmetrics";
 
     private IIpConnectivityMetrics mService;
 
-    @UnsupportedAppUsage
+    /**
+     * An event to be logged.
+     */
+    public interface Event extends Parcelable {}
+
+    /** @hide */
+    @SystemApi
+    @TestApi
     public IpConnectivityLog() {
     }
 
+    /** @hide */
     @VisibleForTesting
     public IpConnectivityLog(IIpConnectivityMetrics service) {
         mService = service;
@@ -67,6 +81,7 @@
      * @param ev the event to log. If the event timestamp is 0,
      * the timestamp is set to the current time in milliseconds.
      * @return true if the event was successfully logged.
+     * @hide
      */
     public boolean log(ConnectivityMetricsEvent ev) {
         if (!checkLoggerService()) {
@@ -94,7 +109,7 @@
      * @param data is a Parcelable instance representing the event.
      * @return true if the event was successfully logged.
      */
-    public boolean log(long timestamp, Parcelable data) {
+    public boolean log(long timestamp, Event data) {
         ConnectivityMetricsEvent ev = makeEv(data);
         ev.timestamp = timestamp;
         return log(ev);
@@ -106,8 +121,7 @@
      * @param data is a Parcelable instance representing the event.
      * @return true if the event was successfully logged.
      */
-    @UnsupportedAppUsage
-    public boolean log(String ifname, Parcelable data) {
+    public boolean log(String ifname, Event data) {
         ConnectivityMetricsEvent ev = makeEv(data);
         ev.ifname = ifname;
         return log(ev);
@@ -115,13 +129,25 @@
 
     /**
      * Log an IpConnectivity event.
+     * @param network the network associated with the event.
+     * @param transports the current transports of the network associated with the event, as defined
+     * in NetworkCapabilities.
+     * @param data is a Parcelable instance representing the event.
+     * @return true if the event was successfully logged.
+     */
+    public boolean log(Network network, int[] transports, Event data) {
+        return log(network.netId, transports, data);
+    }
+
+    /**
+     * Log an IpConnectivity event.
      * @param netid the id of the network associated with the event.
      * @param transports the current transports of the network associated with the event, as defined
      * in NetworkCapabilities.
      * @param data is a Parcelable instance representing the event.
      * @return true if the event was successfully logged.
      */
-    public boolean log(int netid, int[] transports, Parcelable data) {
+    public boolean log(int netid, int[] transports, Event data) {
         ConnectivityMetricsEvent ev = makeEv(data);
         ev.netId = netid;
         ev.transports = BitUtils.packBits(transports);
@@ -133,12 +159,11 @@
      * @param data is a Parcelable instance representing the event.
      * @return true if the event was successfully logged.
      */
-    @UnsupportedAppUsage
-    public boolean log(Parcelable data) {
+    public boolean log(Event data) {
         return log(makeEv(data));
     }
 
-    private static ConnectivityMetricsEvent makeEv(Parcelable data) {
+    private static ConnectivityMetricsEvent makeEv(Event data) {
         ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
         ev.data = data;
         return ev;
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
index c47650f..013e353 100644
--- a/core/java/android/net/metrics/IpManagerEvent.java
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -17,7 +17,8 @@
 package android.net.metrics;
 
 import android.annotation.IntDef;
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.SparseArray;
@@ -28,11 +29,13 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * An event recorded by IpManager when IP provisioning completes for a network or
+ * An event recorded by IpClient when IP provisioning completes for a network or
  * when a network disconnects.
  * {@hide}
  */
-public final class IpManagerEvent implements Parcelable {
+@SystemApi
+@TestApi
+public final class IpManagerEvent implements IpConnectivityLog.Event {
 
     public static final int PROVISIONING_OK                       = 1;
     public static final int PROVISIONING_FAIL                     = 2;
@@ -43,6 +46,7 @@
     public static final int ERROR_INVALID_PROVISIONING            = 7;
     public static final int ERROR_INTERFACE_NOT_FOUND             = 8;
 
+    /** @hide */
     @IntDef(value = {
             PROVISIONING_OK, PROVISIONING_FAIL, COMPLETE_LIFECYCLE,
             ERROR_STARTING_IPV4, ERROR_STARTING_IPV6, ERROR_STARTING_IPREACHABILITYMONITOR,
@@ -51,10 +55,11 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventType {}
 
+    /** @hide */
     public final @EventType int eventType;
+    /** @hide */
     public final long durationMs;
 
-    @UnsupportedAppUsage
     public IpManagerEvent(@EventType int eventType, long duration) {
         this.eventType = eventType;
         this.durationMs = duration;
@@ -65,17 +70,20 @@
         this.durationMs = in.readLong();
     }
 
+    /** @hide */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(eventType);
         out.writeLong(durationMs);
     }
 
+    /** @hide */
     @Override
     public int describeContents() {
         return 0;
     }
 
+    /** @hide */
     public static final Parcelable.Creator<IpManagerEvent> CREATOR
         = new Parcelable.Creator<IpManagerEvent>() {
         public IpManagerEvent createFromParcel(Parcel in) {
diff --git a/core/java/android/net/metrics/IpReachabilityEvent.java b/core/java/android/net/metrics/IpReachabilityEvent.java
index 715c95e..c736297 100644
--- a/core/java/android/net/metrics/IpReachabilityEvent.java
+++ b/core/java/android/net/metrics/IpReachabilityEvent.java
@@ -16,7 +16,8 @@
 
 package android.net.metrics;
 
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.SparseArray;
@@ -28,7 +29,9 @@
  * a neighbor probe result.
  * {@hide}
  */
-public final class IpReachabilityEvent implements Parcelable {
+@SystemApi
+@TestApi
+public final class IpReachabilityEvent implements IpConnectivityLog.Event {
 
     // Event types.
     /** A probe forced by IpReachabilityMonitor. */
@@ -47,9 +50,9 @@
     // byte 1: unused
     // byte 2: type of event: PROBE, NUD_FAILED, PROVISIONING_LOST
     // byte 3: when byte 2 == PROBE, errno code from RTNetlink or IpReachabilityMonitor.
+    /** @hide */
     public final int eventType;
 
-    @UnsupportedAppUsage
     public IpReachabilityEvent(int eventType) {
         this.eventType = eventType;
     }
@@ -58,16 +61,19 @@
         this.eventType = in.readInt();
     }
 
+    /** @hide */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(eventType);
     }
 
+    /** @hide */
     @Override
     public int describeContents() {
         return 0;
     }
 
+    /** @hide */
     public static final Parcelable.Creator<IpReachabilityEvent> CREATOR
         = new Parcelable.Creator<IpReachabilityEvent>() {
         public IpReachabilityEvent createFromParcel(Parcel in) {
@@ -79,18 +85,6 @@
         }
     };
 
-    /**
-     * Returns the NUD failure event type code corresponding to the given conditions.
-     */
-    @UnsupportedAppUsage
-    public static int nudFailureEventType(boolean isFromProbe, boolean isProvisioningLost) {
-        if (isFromProbe) {
-            return isProvisioningLost ? PROVISIONING_LOST : NUD_FAILED;
-        } else {
-            return isProvisioningLost ? PROVISIONING_LOST_ORGANIC : NUD_FAILED_ORGANIC;
-        }
-    }
-
     @Override
     public String toString() {
         int hi = eventType & 0xff00;
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index cb82fbe..f5b2ff1 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -17,6 +17,8 @@
 package android.net.metrics;
 
 import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.SparseArray;
@@ -29,7 +31,9 @@
 /**
  * {@hide}
  */
-public final class NetworkEvent implements Parcelable {
+@SystemApi
+@TestApi
+public final class NetworkEvent implements IpConnectivityLog.Event {
 
     public static final int NETWORK_CONNECTED            = 1;
     public static final int NETWORK_VALIDATED            = 2;
@@ -46,6 +50,7 @@
 
     public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12;
 
+    /** @hide */
     @IntDef(value = {
             NETWORK_CONNECTED,
             NETWORK_VALIDATED,
@@ -63,7 +68,9 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventType {}
 
+    /** @hide */
     public final @EventType int eventType;
+    /** @hide */
     public final long durationMs;
 
     public NetworkEvent(@EventType int eventType, long durationMs) {
@@ -80,17 +87,20 @@
         durationMs = in.readLong();
     }
 
+    /** @hide */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(eventType);
         out.writeLong(durationMs);
     }
 
+    /** @hide */
     @Override
     public int describeContents() {
         return 0;
     }
 
+    /** @hide */
     public static final Parcelable.Creator<NetworkEvent> CREATOR
         = new Parcelable.Creator<NetworkEvent>() {
         public NetworkEvent createFromParcel(Parcel in) {
diff --git a/core/java/android/net/metrics/RaEvent.java b/core/java/android/net/metrics/RaEvent.java
index c41881c..04a2e6e 100644
--- a/core/java/android/net/metrics/RaEvent.java
+++ b/core/java/android/net/metrics/RaEvent.java
@@ -16,7 +16,8 @@
 
 package android.net.metrics;
 
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -24,19 +25,28 @@
  * An event logged when the APF packet socket receives an RA packet.
  * {@hide}
  */
-public final class RaEvent implements Parcelable {
+@SystemApi
+@TestApi
+public final class RaEvent implements IpConnectivityLog.Event {
 
-    public static final long NO_LIFETIME = -1L;
+    private static final long NO_LIFETIME = -1L;
 
     // Lifetime in seconds of options found in a single RA packet.
     // When an option is not set, the value of the associated field is -1;
+    /** @hide */
     public final long routerLifetime;
+    /** @hide */
     public final long prefixValidLifetime;
+    /** @hide */
     public final long prefixPreferredLifetime;
+    /** @hide */
     public final long routeInfoLifetime;
+    /** @hide */
     public final long rdnssLifetime;
+    /** @hide */
     public final long dnsslLifetime;
 
+    /** @hide */
     public RaEvent(long routerLifetime, long prefixValidLifetime, long prefixPreferredLifetime,
             long routeInfoLifetime, long rdnssLifetime, long dnsslLifetime) {
         this.routerLifetime = routerLifetime;
@@ -47,6 +57,7 @@
         this.dnsslLifetime = dnsslLifetime;
     }
 
+    /** @hide */
     private RaEvent(Parcel in) {
         routerLifetime          = in.readLong();
         prefixValidLifetime     = in.readLong();
@@ -56,6 +67,7 @@
         dnsslLifetime           = in.readLong();
     }
 
+    /** @hide */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeLong(routerLifetime);
@@ -66,6 +78,7 @@
         out.writeLong(dnsslLifetime);
     }
 
+    /** @hide */
     @Override
     public int describeContents() {
         return 0;
@@ -83,6 +96,7 @@
                 .toString();
     }
 
+    /** @hide */
     public static final Parcelable.Creator<RaEvent> CREATOR = new Parcelable.Creator<RaEvent>() {
         public RaEvent createFromParcel(Parcel in) {
             return new RaEvent(in);
@@ -102,47 +116,39 @@
         long rdnssLifetime           = NO_LIFETIME;
         long dnsslLifetime           = NO_LIFETIME;
 
-        @UnsupportedAppUsage
         public Builder() {
         }
 
-        @UnsupportedAppUsage
         public RaEvent build() {
             return new RaEvent(routerLifetime, prefixValidLifetime, prefixPreferredLifetime,
                     routeInfoLifetime, rdnssLifetime, dnsslLifetime);
         }
 
-        @UnsupportedAppUsage
         public Builder updateRouterLifetime(long lifetime) {
             routerLifetime = updateLifetime(routerLifetime, lifetime);
             return this;
         }
 
-        @UnsupportedAppUsage
         public Builder updatePrefixValidLifetime(long lifetime) {
             prefixValidLifetime = updateLifetime(prefixValidLifetime, lifetime);
             return this;
         }
 
-        @UnsupportedAppUsage
         public Builder updatePrefixPreferredLifetime(long lifetime) {
             prefixPreferredLifetime = updateLifetime(prefixPreferredLifetime, lifetime);
             return this;
         }
 
-        @UnsupportedAppUsage
         public Builder updateRouteInfoLifetime(long lifetime) {
             routeInfoLifetime = updateLifetime(routeInfoLifetime, lifetime);
             return this;
         }
 
-        @UnsupportedAppUsage
         public Builder updateRdnssLifetime(long lifetime) {
             rdnssLifetime = updateLifetime(rdnssLifetime, lifetime);
             return this;
         }
 
-        @UnsupportedAppUsage
         public Builder updateDnsslLifetime(long lifetime) {
             dnsslLifetime = updateLifetime(dnsslLifetime, lifetime);
             return this;
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 12c2305..42e8aa6 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -17,6 +17,8 @@
 package android.net.metrics;
 
 import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.SparseArray;
@@ -30,7 +32,9 @@
  * An event recorded by NetworkMonitor when sending a probe for finding captive portals.
  * {@hide}
  */
-public final class ValidationProbeEvent implements Parcelable {
+@SystemApi
+@TestApi
+public final class ValidationProbeEvent implements IpConnectivityLog.Event {
 
     public static final int PROBE_DNS       = 0;
     public static final int PROBE_HTTP      = 1;
@@ -45,20 +49,27 @@
     private static final int FIRST_VALIDATION  = 1 << 8;
     private static final int REVALIDATION      = 2 << 8;
 
+    /** @hide */
     @IntDef(value = {DNS_FAILURE, DNS_SUCCESS})
     @Retention(RetentionPolicy.SOURCE)
     public @interface ReturnCode {}
 
-    public long durationMs;
+    /** @hide */
+    public final long durationMs;
     // probeType byte format (MSB to LSB):
     // byte 0: unused
     // byte 1: unused
     // byte 2: 0 = UNKNOWN, 1 = FIRST_VALIDATION, 2 = REVALIDATION
     // byte 3: PROBE_* constant
-    public int probeType;
-    public @ReturnCode int returnCode;
+    /** @hide */
+    public final int probeType;
+    /** @hide */
+    public final @ReturnCode int returnCode;
 
-    public ValidationProbeEvent() {
+    private ValidationProbeEvent(long durationMs, int probeType, int returnCode) {
+        this.durationMs = durationMs;
+        this.probeType = probeType;
+        this.returnCode = returnCode;
     }
 
     private ValidationProbeEvent(Parcel in) {
@@ -67,6 +78,47 @@
         returnCode = in.readInt();
     }
 
+    /**
+     * Utility to create an instance of {@link ApfProgramEvent}.
+     */
+    public static class Builder {
+        private long mDurationMs;
+        private int mProbeType;
+        private int mReturnCode;
+
+        /**
+         * Set the duration of the probe in milliseconds.
+         */
+        public Builder setDurationMs(long durationMs) {
+            mDurationMs = durationMs;
+            return this;
+        }
+
+        /**
+         * Set the probe type based on whether it was the first validation.
+         */
+        public Builder setProbeType(int probeType, boolean firstValidation) {
+            mProbeType = makeProbeType(probeType, firstValidation);
+            return this;
+        }
+
+        /**
+         * Set the return code of the probe.
+         */
+        public Builder setReturnCode(int returnCode) {
+            mReturnCode = returnCode;
+            return this;
+        }
+
+        /**
+         * Create a new {@link ValidationProbeEvent}.
+         */
+        public ValidationProbeEvent build() {
+            return new ValidationProbeEvent(mDurationMs, mProbeType, mReturnCode);
+        }
+    }
+
+    /** @hide */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeLong(durationMs);
@@ -74,11 +126,13 @@
         out.writeInt(returnCode);
     }
 
+    /** @hide */
     @Override
     public int describeContents() {
         return 0;
     }
 
+    /** @hide */
     public static final Parcelable.Creator<ValidationProbeEvent> CREATOR
         = new Parcelable.Creator<ValidationProbeEvent>() {
         public ValidationProbeEvent createFromParcel(Parcel in) {
@@ -90,7 +144,7 @@
         }
     };
 
-    public static int makeProbeType(int probeType, boolean firstValidation) {
+    private static int makeProbeType(int probeType, boolean firstValidation) {
         return (probeType & 0xff) | (firstValidation ? FIRST_VALIDATION : REVALIDATION);
     }
 
@@ -98,7 +152,7 @@
         return Decoder.constants.get(probeType & 0xff, "PROBE_???");
     }
 
-    public static String getValidationStage(int probeType) {
+    private static String getValidationStage(int probeType) {
         return Decoder.constants.get(probeType & 0xff00, "UNKNOWN");
     }
 
diff --git a/services/net/java/android/net/util/MultinetworkPolicyTracker.java b/core/java/android/net/util/MultinetworkPolicyTracker.java
similarity index 100%
rename from services/net/java/android/net/util/MultinetworkPolicyTracker.java
rename to core/java/android/net/util/MultinetworkPolicyTracker.java
diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java
new file mode 100644
index 0000000..de67cf5
--- /dev/null
+++ b/core/java/android/net/util/SocketUtils.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_BINDTODEVICE;
+
+import android.annotation.SystemApi;
+import android.net.NetworkUtils;
+import android.system.ErrnoException;
+import android.system.NetlinkSocketAddress;
+import android.system.Os;
+import android.system.PacketSocketAddress;
+
+import java.io.FileDescriptor;
+import java.net.SocketAddress;
+
+/**
+ * Collection of utilities to interact with raw sockets.
+ * @hide
+ */
+@SystemApi
+public class SocketUtils {
+    /**
+     * Create a raw datagram socket that is bound to an interface.
+     *
+     * <p>Data sent through the socket will go directly to the underlying network, ignoring VPNs.
+     */
+    public static void bindSocketToInterface(FileDescriptor socket, String iface)
+            throws ErrnoException {
+        // SO_BINDTODEVICE actually takes a string. This works because the first member
+        // of struct ifreq is a NULL-terminated interface name.
+        // TODO: add a setsockoptString()
+        Os.setsockoptIfreq(socket, SOL_SOCKET, SO_BINDTODEVICE, iface);
+        NetworkUtils.protectFromVpn(socket);
+    }
+
+    /**
+     * Make a socket address to communicate with netlink.
+     */
+    public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) {
+        return new NetlinkSocketAddress(portId, groupsMask);
+    }
+
+    /**
+     * Make a socket address to bind to packet sockets.
+     */
+    public static SocketAddress makePacketSocketAddress(short protocol, int ifIndex) {
+        return new PacketSocketAddress(protocol, ifIndex);
+    }
+
+    /**
+     * Make a socket address to send raw packets.
+     */
+    public static SocketAddress makePacketSocketAddress(int ifIndex, byte[] hwAddr) {
+        return new PacketSocketAddress(ifIndex, hwAddr);
+    }
+
+    private SocketUtils() {}
+}
diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl
index d1b132c..dd2c0d4 100644
--- a/core/java/android/nfc/INfcCardEmulation.aidl
+++ b/core/java/android/nfc/INfcCardEmulation.aidl
@@ -31,6 +31,8 @@
     boolean setDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
     boolean setDefaultForNextTap(int userHandle, in ComponentName service);
     boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup);
+    boolean setOffHostForService(int userHandle, in ComponentName service, in String offHostSecureElement);
+    boolean unsetOffHostForService(int userHandle, in ComponentName service);
     AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category);
     boolean removeAidGroupForService(int userHandle, in ComponentName service, String category);
     List<ApduServiceInfo> getServices(int userHandle, in String category);
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 21fed48..e55e036 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -16,6 +16,7 @@
 
 package android.nfc;
 
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -42,7 +43,9 @@
 import android.util.Log;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 
 /**
  * Represents the local NFC adapter.
@@ -322,6 +325,7 @@
     // Guarded by NfcAdapter.class
     static boolean sIsInitialized = false;
     static boolean sHasNfcFeature;
+    static boolean sHasBeamFeature;
 
     // Final after first constructor, except for
     // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
@@ -369,7 +373,9 @@
      * A callback to be invoked when the system successfully delivers your {@link NdefMessage}
      * to another device.
      * @see #setOnNdefPushCompleteCallback
+     * @deprecated this feature is deprecated.
      */
+    @java.lang.Deprecated
     public interface OnNdefPushCompleteCallback {
         /**
          * Called on successful NDEF push.
@@ -392,7 +398,9 @@
      * content currently visible to the user. Alternatively, you can call {@link
      * #setNdefPushMessage setNdefPushMessage()} if the {@link NdefMessage} always contains the
      * same data.
+     * @deprecated this feature is deprecated.
      */
+    @java.lang.Deprecated
     public interface CreateNdefMessageCallback {
         /**
          * Called to provide a {@link NdefMessage} to push.
@@ -418,7 +426,10 @@
     }
 
 
-    // TODO javadoc
+     /**
+     * @deprecated this feature is deprecated.
+     */
+    @java.lang.Deprecated
     public interface CreateBeamUrisCallback {
         public Uri[] createBeamUris(NfcEvent event);
     }
@@ -446,6 +457,25 @@
         public boolean onUnlockAttempted(Tag tag);
     }
 
+    /**
+     * Helper to check if this device has FEATURE_NFC_BEAM, but without using
+     * a context.
+     * Equivalent to
+     * context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC_BEAM)
+     */
+    private static boolean hasBeamFeature() {
+        IPackageManager pm = ActivityThread.getPackageManager();
+        if (pm == null) {
+            Log.e(TAG, "Cannot get package manager, assuming no Android Beam feature");
+            return false;
+        }
+        try {
+            return pm.hasSystemFeature(PackageManager.FEATURE_NFC_BEAM, 0);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Package manager query failed, assuming no Android Beam feature", e);
+            return false;
+        }
+    }
 
     /**
      * Helper to check if this device has FEATURE_NFC, but without using
@@ -488,6 +518,35 @@
     }
 
     /**
+     * Return list of Secure Elements which support off host card emulation.
+     *
+     * @return List<String> containing secure elements on the device which supports
+     *                      off host card emulation. eSE for Embedded secure element,
+     *                      SIM for UICC and so on.
+     */
+    public @NonNull List<String> getSupportedOffHostSecureElements() {
+        List<String> offHostSE = new ArrayList<String>();
+        IPackageManager pm = ActivityThread.getPackageManager();
+        if (pm == null) {
+            Log.e(TAG, "Cannot get package manager, assuming no off-host CE feature");
+            return offHostSE;
+        }
+        try {
+            if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC, 0)) {
+                offHostSE.add("SIM");
+            }
+            if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE, 0)) {
+                offHostSE.add("eSE");
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Package manager query failed, assuming no off-host CE feature", e);
+            offHostSE.clear();
+            return offHostSE;
+        }
+        return offHostSE;
+    }
+
+    /**
      * Returns the NfcAdapter for application context,
      * or throws if NFC is not available.
      * @hide
@@ -496,6 +555,7 @@
     public static synchronized NfcAdapter getNfcAdapter(Context context) {
         if (!sIsInitialized) {
             sHasNfcFeature = hasNfcFeature();
+            sHasBeamFeature = hasBeamFeature();
             boolean hasHceFeature = hasNfcHceFeature();
             /* is this device meant to have NFC */
             if (!sHasNfcFeature && !hasHceFeature) {
@@ -921,12 +981,17 @@
      * @param uris an array of Uri(s) to push over Android Beam
      * @param activity activity for which the Uri(s) will be pushed
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @deprecated this feature is deprecated.
      */
+    @java.lang.Deprecated
     public void setBeamPushUris(Uri[] uris, Activity activity) {
         synchronized (NfcAdapter.class) {
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
+            if (!sHasBeamFeature) {
+                return;
+            }
         }
         if (activity == null) {
             throw new NullPointerException("activity cannot be null");
@@ -1003,12 +1068,17 @@
      * @param callback callback, or null to disable
      * @param activity activity for which the Uri(s) will be pushed
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @deprecated this feature is deprecated.
      */
+    @java.lang.Deprecated
     public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) {
         synchronized (NfcAdapter.class) {
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
+            if (!sHasBeamFeature) {
+                return;
+            }
         }
         if (activity == null) {
             throw new NullPointerException("activity cannot be null");
@@ -1087,13 +1157,18 @@
      *        to only register one at a time, and to do so in that activity's
      *        {@link Activity#onCreate}
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @deprecated this feature is deprecated.
      */
+    @java.lang.Deprecated
     public void setNdefPushMessage(NdefMessage message, Activity activity,
             Activity ... activities) {
         synchronized (NfcAdapter.class) {
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
+            if (!sHasBeamFeature) {
+                return;
+            }
         }
         int targetSdkVersion = getSdkVersion();
         try {
@@ -1200,13 +1275,18 @@
      *        to only register one at a time, and to do so in that activity's
      *        {@link Activity#onCreate}
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @deprecated this feature is deprecated.
      */
+    @java.lang.Deprecated
     public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
             Activity ... activities) {
         synchronized (NfcAdapter.class) {
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
+            if (!sHasBeamFeature) {
+                return;
+            }
         }
         int targetSdkVersion = getSdkVersion();
         try {
@@ -1281,13 +1361,18 @@
      *        to only register one at a time, and to do so in that activity's
      *        {@link Activity#onCreate}
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @deprecated this feature is deprecated.
      */
+    @java.lang.Deprecated
     public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback,
             Activity activity, Activity ... activities) {
         synchronized (NfcAdapter.class) {
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
+            if (!sHasBeamFeature) {
+                return;
+            }
         }
         int targetSdkVersion = getSdkVersion();
         try {
@@ -1492,12 +1577,17 @@
      * @param activity the current foreground Activity that has registered data to share
      * @return whether the Beam animation was successfully invoked
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @deprecated this feature is deprecated.
      */
+    @java.lang.Deprecated
     public boolean invokeBeam(Activity activity) {
         synchronized (NfcAdapter.class) {
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
+            if (!sHasBeamFeature) {
+                return false;
+            }
         }
         if (activity == null) {
             throw new NullPointerException("activity may not be null.");
@@ -1561,6 +1651,9 @@
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
+            if (!sHasBeamFeature) {
+                return;
+            }
         }
         if (activity == null || message == null) {
             throw new NullPointerException();
@@ -1595,6 +1688,9 @@
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
+            if (!sHasBeamFeature) {
+                return;
+            }
         }
         if (activity == null) {
             throw new NullPointerException();
@@ -1668,12 +1764,18 @@
      * @see android.provider.Settings#ACTION_NFCSHARING_SETTINGS
      * @return true if NDEF Push feature is enabled
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @deprecated this feature is deprecated.
      */
+    @java.lang.Deprecated
+
     public boolean isNdefPushEnabled() {
         synchronized (NfcAdapter.class) {
             if (!sHasNfcFeature) {
                 throw new UnsupportedOperationException();
             }
+            if (!sHasBeamFeature) {
+                return false;
+            }
         }
         try {
             return sService.isNdefPushEnabled();
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index e8d801c..911ec84 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -18,11 +18,10 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
 import android.content.res.TypedArray;
@@ -30,7 +29,6 @@
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.ResultReceiver;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
@@ -69,6 +67,18 @@
     final boolean mOnHost;
 
     /**
+     * Offhost reader name.
+     * eg: SIM, eSE etc
+     */
+    String mOffHostName;
+
+    /**
+     * Offhost reader name from manifest file.
+     * Used for unsetOffHostSecureElement()
+     */
+    final String mStaticOffHostName;
+
+    /**
      * Mapping from category to static AID group
      */
     @UnsupportedAppUsage
@@ -104,15 +114,17 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
+    public ApduServiceInfo(ResolveInfo info, String description,
             ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
             boolean requiresUnlock, int bannerResource, int uid,
-            String settingsActivityName) {
+            String settingsActivityName, String offHost, String staticOffHost) {
         this.mService = info;
         this.mDescription = description;
         this.mStaticAidGroups = new HashMap<String, AidGroup>();
         this.mDynamicAidGroups = new HashMap<String, AidGroup>();
-        this.mOnHost = onHost;
+        this.mOffHostName = offHost;
+        this.mStaticOffHostName = staticOffHost;
+        this.mOnHost = (offHost == null);
         this.mRequiresDeviceUnlock = requiresUnlock;
         for (AidGroup aidGroup : staticAidGroups) {
             this.mStaticAidGroups.put(aidGroup.category, aidGroup);
@@ -174,6 +186,8 @@
                         com.android.internal.R.styleable.HostApduService_apduServiceBanner, -1);
                 mSettingsActivityName = sa.getString(
                         com.android.internal.R.styleable.HostApduService_settingsActivity);
+                mOffHostName = null;
+                mStaticOffHostName = mOffHostName;
                 sa.recycle();
             } else {
                 TypedArray sa = res.obtainAttributes(attrs,
@@ -186,6 +200,16 @@
                         com.android.internal.R.styleable.OffHostApduService_apduServiceBanner, -1);
                 mSettingsActivityName = sa.getString(
                         com.android.internal.R.styleable.HostApduService_settingsActivity);
+                mOffHostName = sa.getString(
+                        com.android.internal.R.styleable.OffHostApduService_secureElementName);
+                if (mOffHostName != null) {
+                    if (mOffHostName.equals("eSE")) {
+                        mOffHostName = "eSE1";
+                    } else if (mOffHostName.equals("SIM")) {
+                        mOffHostName = "SIM1";
+                    }
+                }
+                mStaticOffHostName = mOffHostName;
                 sa.recycle();
             }
 
@@ -289,6 +313,10 @@
                 mService.serviceInfo.name);
     }
 
+    public String getOffHostSecureElement() {
+        return mOffHostName;
+    }
+
     /**
      * Returns a consolidated list of AIDs from the AID groups
      * registered by this service. Note that if a service has both
@@ -404,6 +432,20 @@
         mDynamicAidGroups.put(aidGroup.getCategory(), aidGroup);
     }
 
+    @UnsupportedAppUsage
+    public void setOffHostSecureElement(String offHost) {
+        mOffHostName = offHost;
+    }
+
+    /**
+     * Resets the off host Secure Element to statically defined
+     * by the service in the manifest file.
+     */
+    @UnsupportedAppUsage
+    public void unsetOffHostSecureElement() {
+        mOffHostName = mStaticOffHostName;
+    }
+
     public CharSequence loadLabel(PackageManager pm) {
         return mService.loadLabel(pm);
     }
@@ -481,6 +523,8 @@
         mService.writeToParcel(dest, flags);
         dest.writeString(mDescription);
         dest.writeInt(mOnHost ? 1 : 0);
+        dest.writeString(mOffHostName);
+        dest.writeString(mStaticOffHostName);
         dest.writeInt(mStaticAidGroups.size());
         if (mStaticAidGroups.size() > 0) {
             dest.writeTypedList(new ArrayList<AidGroup>(mStaticAidGroups.values()));
@@ -503,6 +547,8 @@
             ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
             String description = source.readString();
             boolean onHost = source.readInt() != 0;
+            String offHostName = source.readString();
+            String staticOffHostName = source.readString();
             ArrayList<AidGroup> staticAidGroups = new ArrayList<AidGroup>();
             int numStaticGroups = source.readInt();
             if (numStaticGroups > 0) {
@@ -517,9 +563,9 @@
             int bannerResource = source.readInt();
             int uid = source.readInt();
             String settingsActivityName = source.readString();
-            return new ApduServiceInfo(info, onHost, description, staticAidGroups,
+            return new ApduServiceInfo(info, description, staticAidGroups,
                     dynamicAidGroups, requiresUnlock, bannerResource, uid,
-                    settingsActivityName);
+                    settingsActivityName, offHostName, staticOffHostName);
         }
 
         @Override
@@ -531,6 +577,14 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("    " + getComponent() +
                 " (Description: " + getDescription() + ")");
+        if (mOnHost) {
+            pw.println("    On Host Service");
+        } else {
+            pw.println("    Off-host Service");
+            pw.println("        " + "Current off-host SE" + mOffHostName
+                    + " static off-host: " + mOffHostName);
+        }
+        pw.println("    Static off-host Secure Element:");
         pw.println("    Static AID groups:");
         for (AidGroup group : mStaticAidGroups.values()) {
             pw.println("        Category: " + group.category);
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 15d02f2..01932ab 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -27,7 +27,6 @@
 import android.nfc.INfcCardEmulation;
 import android.nfc.NfcAdapter;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Log;
@@ -345,6 +344,108 @@
     }
 
     /**
+     * Unsets the off-host Secure Element for the given service.
+     *
+     * <p>Note that this will only remove Secure Element that was dynamically
+     * set using the {@link #setOffHostForService(ComponentName, String)}
+     * and resets it to a value that was statically assigned using manifest.
+     *
+     * <p>Note that you can only unset off-host SE for a service that
+     * is running under the same UID as the caller of this API. Typically
+     * this means you need to call this from the same
+     * package as the service itself, though UIDs can also
+     * be shared between packages using shared UIDs.
+     *
+     * @param service The component name of the service
+     * @return whether the registration was successful.
+     */
+    public boolean unsetOffHostForService(ComponentName service) {
+        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+        if (adapter == null) {
+            return false;
+        }
+
+        try {
+            return sService.unsetOffHostForService(mContext.getUserId(), service);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.unsetOffHostForService(mContext.getUserId(), service);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Sets the off-host Secure Element for the given service.
+     *
+     * <p>If off-host SE was initially set (either statically
+     * through the manifest, or dynamically by using this API),
+     * it will be replaced with this one. All AIDs registered by
+     * this service will be re-routed to this Secure Element if
+     * successful.
+     *
+     * <p>Note that you can only set off-host SE for a service that
+     * is running under the same UID as the caller of this API. Typically
+     * this means you need to call this from the same
+     * package as the service itself, though UIDs can also
+     * be shared between packages using shared UIDs.
+     *
+     * <p>Registeration will be successful only if the Secure Element
+     * exists on the device.
+     *
+     * @param service The component name of the service
+     * @param offHostSecureElement Secure Element to register the AID to
+     * @return whether the registration was successful.
+     */
+    public boolean setOffHostForService(ComponentName service, String offHostSecureElement) {
+        boolean validSecureElement = false;
+
+        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+        if (adapter == null || offHostSecureElement == null) {
+            return false;
+        }
+
+        List<String> validSE = adapter.getSupportedOffHostSecureElements();
+        if ((offHostSecureElement.startsWith("eSE") && !validSE.contains("eSE"))
+                || (offHostSecureElement.startsWith("SIM") && !validSE.contains("SIM"))) {
+            return false;
+        }
+
+        if (offHostSecureElement.equals("eSE")) {
+            offHostSecureElement = "eSE1";
+        } else if (offHostSecureElement.equals("SIM")) {
+            offHostSecureElement = "SIM1";
+        }
+
+        try {
+            return sService.setOffHostForService(mContext.getUserId(), service,
+                offHostSecureElement);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.setOffHostForService(mContext.getUserId(), service,
+                        offHostSecureElement);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
      * Retrieves the currently registered AIDs for the specified
      * category for a service.
      *
diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java
new file mode 100644
index 0000000..6daa5b4
--- /dev/null
+++ b/core/java/android/os/AppZygote.java
@@ -0,0 +1,130 @@
+/*
+ * 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;
+
+import android.content.pm.ApplicationInfo;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * AppZygote is responsible for interfacing with an application-specific zygote.
+ *
+ * Application zygotes can pre-load app-specific code and data, and this interface can
+ * be used to spawn isolated services from such an application zygote.
+ *
+ * Note that we'll have only one instance of this per application / uid combination.
+ *
+ * @hide
+ */
+public class AppZygote {
+    private static final String LOG_TAG = "AppZygote";
+
+    // UID of the Zygote itself
+    private final int mZygoteUid;
+
+    // First UID/GID of the range the AppZygote can setuid()/setgid() to
+    private final int mZygoteUidGidMin;
+
+    // Last UID/GID of the range the AppZygote can setuid()/setgid() to
+    private final int mZygoteUidGidMax;
+
+    private final Object mLock = new Object();
+
+    /**
+     * Instance that maintains the socket connection to the zygote. This is {@code null} if the
+     * zygote is not running or is not connected.
+     */
+    @GuardedBy("mLock")
+    private ChildZygoteProcess mZygote;
+
+    private final ApplicationInfo mAppInfo;
+
+    public AppZygote(ApplicationInfo appInfo, int zygoteUid, int uidGidMin, int uidGidMax) {
+        mAppInfo = appInfo;
+        mZygoteUid = zygoteUid;
+        mZygoteUidGidMin = uidGidMin;
+        mZygoteUidGidMax = uidGidMax;
+    }
+
+    /**
+     * Returns the zygote process associated with this app zygote.
+     * Creates the process if it's not already running.
+     */
+    public ChildZygoteProcess getProcess() {
+        synchronized (mLock) {
+            if (mZygote != null) return mZygote;
+
+            connectToZygoteIfNeededLocked();
+            return mZygote;
+        }
+    }
+
+    /**
+     * Stops the Zygote and kills the zygote process.
+     */
+    public void stopZygote() {
+        synchronized (mLock) {
+            stopZygoteLocked();
+        }
+    }
+
+    public ApplicationInfo getAppInfo() {
+        return mAppInfo;
+    }
+
+    @GuardedBy("mLock")
+    private void stopZygoteLocked() {
+        if (mZygote != null) {
+            // Close the connection and kill the zygote process. This will not cause
+            // child processes to be killed by itself.
+            mZygote.close();
+            Process.killProcess(mZygote.getPid());
+            mZygote = null;
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void connectToZygoteIfNeededLocked() {
+        String abi = mAppInfo.primaryCpuAbi != null ? mAppInfo.primaryCpuAbi :
+                Build.SUPPORTED_ABIS[0];
+        try {
+            mZygote = Process.ZYGOTE_PROCESS.startChildZygote(
+                    "com.android.internal.os.AppZygoteInit",
+                    mAppInfo.processName + "_zygote",
+                    mZygoteUid,
+                    mZygoteUid,
+                    null,  // gids
+                    0,  // runtimeFlags
+                    "app_zygote",  // seInfo
+                    abi,  // abi
+                    abi, // acceptedAbiList
+                    null, // instructionSet
+                    mZygoteUidGidMin,
+                    mZygoteUidGidMax);
+
+            ZygoteProcess.waitForConnectionToZygote(mZygote.getPrimarySocketAddress());
+            // preload application code in the zygote
+            Log.i(LOG_TAG, "Starting application preload.");
+            mZygote.preloadApp(mAppInfo, abi);
+            Log.i(LOG_TAG, "Application preload done.");
+        } catch (Exception e) {
+            Log.e(LOG_TAG, "Error connecting to app zygote", e);
+            stopZygoteLocked();
+        }
+    }
+}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 9939a3c..1ebb551 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -273,6 +273,30 @@
     public static final native int getCallingUid();
 
     /**
+     * Returns {@code true} if the current thread is currently executing an
+     * incoming transaction.
+     *
+     * @hide
+     */
+    @CriticalNative
+    public static final native boolean isHandlingTransaction();
+
+    /**
+     * Return the Linux uid assigned to the process that sent the transaction
+     * currently being processed.
+     *
+     * @throws IllegalStateException if the current thread is not currently
+     *        executing an incoming transaction.
+     */
+    public static final int getCallingUidOrThrow() {
+        if (!isHandlingTransaction()) {
+            throw new IllegalStateException(
+                  "Thread is not in a binder transcation");
+        }
+        return getCallingUid();
+    }
+
+    /**
      * Return the UserHandle assigned to the process that sent you the
      * current transaction that is being processed.  This is the user
      * of the caller.  It is distinct from {@link #getCallingUid()} in that a
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
new file mode 100644
index 0000000..518528d
--- /dev/null
+++ b/core/java/android/os/BugreportManager.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.IBinder.DeathRecipient;
+
+import java.io.FileDescriptor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class that provides a privileged API to capture and consume bugreports.
+ *
+ * @hide
+ */
+// TODO: Expose API when the implementation is more complete.
+// @SystemApi
+@SystemService(Context.BUGREPORT_SERVICE)
+public class BugreportManager {
+    private final Context mContext;
+    private final IDumpstate mBinder;
+
+    /** @hide */
+    public BugreportManager(@NonNull Context context, IDumpstate binder) {
+        mContext = context;
+        mBinder = binder;
+    }
+
+    /**
+     * An interface describing the listener for bugreport progress and status.
+     */
+    public interface BugreportListener {
+        /**
+         * Called when there is a progress update.
+         * @param progress the progress in [0.0, 100.0]
+         */
+        void onProgress(float progress);
+
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = {
+                BUGREPORT_ERROR_INVALID_INPUT,
+                BUGREPORT_ERROR_RUNTIME
+        })
+
+        /** Possible error codes taking a bugreport can encounter */
+        @interface BugreportErrorCode {}
+
+        /** The input options were invalid */
+        int BUGREPORT_ERROR_INVALID_INPUT = IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT;
+
+        /** A runtime error occured */
+        int BUGREPORT_ERROR_RUNTIME = IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR;
+
+        /** User denied consent to share the bugreport */
+        int BUGREPORT_ERROR_USER_DENIED_CONSENT =
+                IDumpstateListener.BUGREPORT_ERROR_USER_DENIED_CONSENT;
+
+        /**
+         * Called when taking bugreport resulted in an error.
+         *
+         * @param errorCode the error that occurred. Possible values are
+         *     {@code BUGREPORT_ERROR_INVALID_INPUT},
+         *     {@code BUGREPORT_ERROR_RUNTIME},
+         *     {@code BUGREPORT_ERROR_USER_DENIED_CONSENT}.
+         */
+        void onError(@BugreportErrorCode int errorCode);
+
+        /**
+         * Called when taking bugreport finishes successfully.
+         */
+        void onFinished();
+    }
+
+    /**
+     * Starts a bugreport.
+     *
+     * <p>This starts a bugreport in the background. However the call itself can take several
+     * seconds to return in the worst case. {@code listener} will receive progress and status
+     * updates.
+     *
+     * <p>The bugreport artifacts will be copied over to the given file descriptors only if the
+     * user consents to sharing with the calling app.
+     *
+     * @param bugreportFd file to write the bugreport. This should be opened in write-only,
+     *     append mode.
+     * @param screenshotFd file to write the screenshot, if necessary. This should be opened
+     *     in write-only, append mode.
+     * @param params options that specify what kind of a bugreport should be taken
+     * @param listener callback for progress and status updates
+     */
+    @RequiresPermission(android.Manifest.permission.DUMP)
+    public void startBugreport(@NonNull FileDescriptor bugreportFd,
+            @Nullable FileDescriptor screenshotFd,
+            @NonNull BugreportParams params, @NonNull BugreportListener listener) {
+        // TODO(b/111441001): Enforce android.Manifest.permission.DUMP if necessary.
+        DumpstateListener dsListener = new DumpstateListener(listener);
+
+        try {
+            // Note: mBinder can get callingUid from the binder transaction.
+            mBinder.startBugreport(-1 /* callingUid */,
+                    mContext.getOpPackageName(), bugreportFd, screenshotFd,
+                    params.getMode(), dsListener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /*
+     * Cancels a currently running bugreport.
+     */
+    @RequiresPermission(android.Manifest.permission.DUMP)
+    public void cancelBugreport() {
+        try {
+            mBinder.cancelBugreport();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private final class DumpstateListener extends IDumpstateListener.Stub
+            implements DeathRecipient {
+        private final BugreportListener mListener;
+
+        DumpstateListener(@Nullable BugreportListener listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public void binderDied() {
+            // TODO(b/111441001): implement
+        }
+
+        @Override
+        public void onProgress(int progress) throws RemoteException {
+            mListener.onProgress(progress);
+        }
+
+        @Override
+        public void onError(int errorCode) throws RemoteException {
+            mListener.onError(errorCode);
+        }
+
+        @Override
+        public void onFinished() throws RemoteException {
+            try {
+                mListener.onFinished();
+            } finally {
+                // The bugreport has finished. Let's shutdown the service to minimize its footprint.
+                cancelBugreport();
+            }
+        }
+
+        // Old methods; should go away
+        @Override
+        public void onProgressUpdated(int progress) throws RemoteException {
+            // TODO(b/111441001): remove from interface
+        }
+
+        @Override
+        public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
+            // TODO(b/111441001): remove from interface
+        }
+
+        @Override
+        public void onSectionComplete(String title, int status, int size, int durationMs)
+                throws RemoteException {
+            // TODO(b/111441001): remove from interface
+        }
+    }
+}
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
new file mode 100644
index 0000000..4e696ae
--- /dev/null
+++ b/core/java/android/os/BugreportParams.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Parameters that specify what kind of bugreport should be taken.
+ *
+ * @hide
+ */
+// TODO: Expose API when the implementation is more complete.
+// @SystemApi
+public final class BugreportParams {
+    private final int mMode;
+
+    public BugreportParams(@BugreportMode int mode) {
+        mMode = mode;
+    }
+
+    public int getMode() {
+        return mMode;
+    }
+
+    /**
+     * Defines acceptable types of bugreports.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "BUGREPORT_MODE_" }, value = {
+            BUGREPORT_MODE_FULL,
+            BUGREPORT_MODE_INTERACTIVE,
+            BUGREPORT_MODE_REMOTE,
+            BUGREPORT_MODE_WEAR,
+            BUGREPORT_MODE_TELEPHONY,
+            BUGREPORT_MODE_WIFI
+    })
+    public @interface BugreportMode {}
+
+    /**
+     * Options for a bugreport without user interference (and hence causing less
+     * interference to the system), but includes all sections.
+     */
+    public static final int BUGREPORT_MODE_FULL = IDumpstate.BUGREPORT_MODE_FULL;
+
+    /**
+     * Options that allow user to monitor progress and enter additional data; might not
+     * include all sections.
+     */
+    public static final int BUGREPORT_MODE_INTERACTIVE = IDumpstate.BUGREPORT_MODE_INTERACTIVE;
+
+    /**
+     * Options for a bugreport requested remotely by administrator of the Device Owner app,
+     * not the device's user.
+     */
+    public static final int BUGREPORT_MODE_REMOTE = IDumpstate.BUGREPORT_MODE_REMOTE;
+
+    /**
+     * Options for a bugreport on a wearable device.
+     */
+    public static final int BUGREPORT_MODE_WEAR = IDumpstate.BUGREPORT_MODE_WEAR;
+
+    /**
+     * Options for a lightweight version of bugreport that only includes a few, urgent
+     * sections used to report telephony bugs.
+     */
+    public static final int BUGREPORT_MODE_TELEPHONY = IDumpstate.BUGREPORT_MODE_TELEPHONY;
+
+    /**
+     * Options for a lightweight bugreport that only includes a few sections related to
+     * Wifi.
+     */
+    public static final int BUGREPORT_MODE_WIFI = IDumpstate.BUGREPORT_MODE_WIFI;
+}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 9fea873..2d61a4e 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -289,6 +289,26 @@
                 "ro.build.version.preview_sdk", 0);
 
         /**
+         * The SDK fingerprint for a given prerelease SDK. This value will always be
+         * {@code REL} on production platform builds/devices.
+         *
+         * <p>When this value is not {@code REL}, it contains a string fingerprint of the API
+         * surface exposed by the preview SDK. Preview platforms with different API surfaces
+         * will have different {@code PREVIEW_SDK_FINGERPRINT}.
+         *
+         * <p>This attribute is intended for use by installers for finer grained targeting of
+         * packages. Applications targeting preview APIs should not use this field and should
+         * instead use {@code PREVIEW_SDK_INT} or use reflection or other runtime checks to
+         * detect the presence of an API or guard themselves against unexpected runtime
+         * behavior.
+         *
+         * @hide
+         */
+        @SystemApi
+        public static final String PREVIEW_SDK_FINGERPRINT = SystemProperties.get(
+                "ro.build.version.preview_sdk_fingerprint", "REL");
+
+        /**
          * The current development codename, or the string "REL" if this is
          * a release build.
          */
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 8904ee6..a236300 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -382,6 +382,11 @@
     }
 
     /** {@hide} */
+    public static File getDataStagingDirectory(String volumeUuid) {
+        return new File(getDataDirectory(volumeUuid), "staging");
+    }
+
+    /** {@hide} */
     public static File getDataUserCeDirectory(String volumeUuid) {
         return new File(getDataDirectory(volumeUuid), "user");
     }
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index e84a518..51c3c4c 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -72,6 +72,7 @@
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Comparator;
 import java.util.Objects;
 import java.util.concurrent.Executor;
@@ -831,6 +832,16 @@
         return false;
     }
 
+    /** {@hide} */
+    public static boolean contains(Collection<File> dirs, File file) {
+        for (File dir : dirs) {
+            if (contains(dir, file)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Test if a file lives under the given directory, either as a direct child
      * or a distant grandchild.
@@ -846,7 +857,16 @@
         return contains(dir.getAbsolutePath(), file.getAbsolutePath());
     }
 
-    /** {@hide} */
+    /**
+     * Test if a file lives under the given directory, either as a direct child
+     * or a distant grandchild.
+     * <p>
+     * Both files <em>must</em> have been resolved using
+     * {@link File#getCanonicalFile()} to avoid symlink or path traversal
+     * attacks.
+     *
+     * @hide
+     */
     public static boolean contains(String dirPath, String filePath) {
         if (dirPath.equals(filePath)) {
             return true;
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index fdadfbe..5bf9095 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -23,10 +23,15 @@
 import android.content.pm.ResolveInfo;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.AssetManager;
+import android.gamedriver.GameDriverProto.Blacklist;
+import android.gamedriver.GameDriverProto.Blacklists;
 import android.opengl.EGL14;
 import android.provider.Settings;
+import android.util.Base64;
 import android.util.Log;
 
+import com.android.framework.protobuf.InvalidProtocolBufferException;
+
 import dalvik.system.VMRuntime;
 
 import java.io.BufferedReader;
@@ -62,6 +67,8 @@
     private static final String ANGLE_RULES_FILE = "a4a_rules.json";
     private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
     private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
+    private static final String GAME_DRIVER_BLACKLIST_FLAG = "blacklist";
+    private static final int BASE64_FLAGS = Base64.NO_PADDING | Base64.NO_WRAP;
 
     private ClassLoader mClassLoader;
     private String mLayerPath;
@@ -306,9 +313,18 @@
                                                 String packageName,
                                                 String paths,
                                                 String devOptIn) {
-        // Check for temporary rules if debuggable or root
-        if (!isDebuggable(context) && !(getCanLoadSystemLibraries() == 1)) {
-            Log.v(TAG, "Skipping loading temporary rules file");
+        /**
+         * We only want to load a temp rules file for:
+         *  - apps that are marked 'debuggable' in their manifest
+         *  - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
+         *    debugging (PR_SET_DUMPABLE).
+         */
+        boolean appIsDebuggable = isDebuggable(context);
+        boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
+        if (!(appIsDebuggable || deviceIsDebuggable)) {
+            Log.v(TAG, "Skipping loading temporary rules file: "
+                    + "appIsDebuggable = " + appIsDebuggable + ", "
+                    + "adbRootEnabled = " + deviceIsDebuggable);
             return false;
         }
 
@@ -471,27 +487,6 @@
             return;
         }
 
-        // To minimize risk of driver updates crippling the device beyond user repair, never use an
-        // updated driver for privileged or non-updated system apps. Presumably pre-installed apps
-        // were tested thoroughly with the pre-installed driver.
-        ApplicationInfo ai = context.getApplicationInfo();
-        if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) {
-            if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app");
-            return;
-        }
-
-        String applicationPackageName = context.getPackageName();
-        String devOptInApplicationName = coreSettings.getString(
-                Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP);
-        boolean devOptIn = applicationPackageName.equals(devOptInApplicationName);
-        boolean whitelisted = onWhitelist(context, driverPackageName, ai.packageName);
-        if (!devOptIn && !whitelisted) {
-            if (DEBUG) {
-                Log.w(TAG, applicationPackageName + " is not on the whitelist.");
-            }
-            return;
-        }
-
         ApplicationInfo driverInfo;
         try {
             driverInfo = context.getPackageManager().getApplicationInfo(driverPackageName,
@@ -510,6 +505,77 @@
             return;
         }
 
+        // To minimize risk of driver updates crippling the device beyond user repair, never use an
+        // updated driver for privileged or non-updated system apps. Presumably pre-installed apps
+        // were tested thoroughly with the pre-installed driver.
+        ApplicationInfo ai = context.getApplicationInfo();
+        if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) {
+            if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app");
+            return;
+        }
+
+        // GUP_DEV_ALL_APPS
+        // 0: Default (Invalid values fallback to default as well)
+        // 1: All apps use Game Driver
+        // 2: All apps use system graphics driver
+        int gupDevAllApps = coreSettings.getInt(Settings.Global.GUP_DEV_ALL_APPS, 0);
+        if (gupDevAllApps == 2) {
+            if (DEBUG) {
+                Log.w(TAG, "GUP is turned off on this device");
+            }
+            return;
+        }
+
+        if (gupDevAllApps != 1) {
+            // GUP_DEV_OPT_OUT_APPS has higher priority than GUP_DEV_OPT_IN_APPS
+            if (getGlobalSettingsString(coreSettings, Settings.Global.GUP_DEV_OPT_OUT_APPS)
+                            .contains(ai.packageName)) {
+                if (DEBUG) {
+                    Log.w(TAG, ai.packageName + " opts out from GUP.");
+                }
+                return;
+            }
+            boolean isDevOptIn = getGlobalSettingsString(coreSettings,
+                                                         Settings.Global.GUP_DEV_OPT_IN_APPS)
+                              .contains(ai.packageName);
+
+            if (!isDevOptIn && !onWhitelist(context, driverPackageName, ai.packageName)) {
+                if (DEBUG) {
+                    Log.w(TAG, ai.packageName + " is not on the whitelist.");
+                }
+                return;
+            }
+
+            if (!isDevOptIn) {
+                // At this point, the application is on the whitelist only, check whether it's
+                // on the blacklist, terminate early when it's on the blacklist.
+                try {
+                    // TODO(b/121350991) Switch to DeviceConfig with property listener.
+                    String base64String = coreSettings.getString(Settings.Global.GUP_BLACKLIST);
+                    if (base64String != null && !base64String.isEmpty()) {
+                        Blacklists blacklistsProto = Blacklists.parseFrom(
+                                Base64.decode(base64String, BASE64_FLAGS));
+                        List<Blacklist> blacklists = blacklistsProto.getBlacklistsList();
+                        long driverVersionCode = driverInfo.longVersionCode;
+                        for (Blacklist blacklist : blacklists) {
+                            if (blacklist.getVersionCode() == driverVersionCode) {
+                                for (String packageName : blacklist.getPackageNamesList()) {
+                                    if (packageName == ai.packageName) {
+                                        return;
+                                    }
+                                }
+                                break;
+                            }
+                        }
+                    }
+                } catch (InvalidProtocolBufferException e) {
+                    if (DEBUG) {
+                        Log.w(TAG, "Can't parse blacklist, skip and continue...");
+                    }
+                }
+            }
+        }
+
         String abi = chooseAbi(driverInfo);
         if (abi == null) {
             if (DEBUG) {
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index a4d5c6f..92fcbb6 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -20,8 +20,10 @@
 import android.annotation.Nullable;
 
 /**
- * Handy class for starting a new thread that has a looper. The looper can then be 
- * used to create handler classes. Note that start() must still be called.
+ * A {@link Thread} that has a {@link Looper}.
+ * The {@link Looper} can then be used to create {@link Handler}s.
+ * <p>
+ * Note that just like with a regular {@link Thread}, {@link #start()} must still be called.
  */
 public class HandlerThread extends Thread {
     int mPriority;
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 3de3494..9e3e83e 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -24,6 +25,7 @@
 
 /** @hide */
 @SystemApi
+@TestApi
 public abstract class HwBinder implements IHwBinder {
     private static final String TAG = "HwBinder";
 
diff --git a/core/java/android/os/HwBlob.java b/core/java/android/os/HwBlob.java
index 6a5bb1c..0ec63b5 100644
--- a/core/java/android/os/HwBlob.java
+++ b/core/java/android/os/HwBlob.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -28,6 +29,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public class HwBlob {
     private static final String TAG = "HwBlob";
 
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index 7a51db2..7919a00 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -28,6 +29,7 @@
 
 /** @hide */
 @SystemApi
+@TestApi
 public class HwParcel {
     private static final String TAG = "HwParcel";
 
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index 8271701..fe17c6b 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -45,4 +45,6 @@
     void exitIdle(String reason);
     boolean registerMaintenanceActivityListener(IMaintenanceActivityListener listener);
     void unregisterMaintenanceActivityListener(IMaintenanceActivityListener listener);
+    int setPreIdleTimeoutMode(int Mode);
+    void resetPreIdleTimeoutMode();
 }
diff --git a/core/java/android/os/IHwBinder.java b/core/java/android/os/IHwBinder.java
index 249eb3a..46fa6ef 100644
--- a/core/java/android/os/IHwBinder.java
+++ b/core/java/android/os/IHwBinder.java
@@ -17,9 +17,11 @@
 package android.os;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 
 /** @hide */
 @SystemApi
+@TestApi
 public interface IHwBinder {
     /**
      * Process a hwbinder transaction.
diff --git a/core/java/android/os/IHwInterface.java b/core/java/android/os/IHwInterface.java
index f9edd5b..0a5a715 100644
--- a/core/java/android/os/IHwInterface.java
+++ b/core/java/android/os/IHwInterface.java
@@ -17,8 +17,11 @@
 package android.os;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
+
 /** @hide */
 @SystemApi
+@TestApi
 public interface IHwInterface {
     /**
      * @return the binder object that corresponds to this interface.
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index fdd7488..8ced722 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -356,16 +356,6 @@
     void removeVpnUidRanges(int netId, in UidRange[] ranges);
 
     /**
-     * Start the clatd (464xlat) service on the given interface.
-     */
-    void startClatd(String interfaceName);
-
-    /**
-     * Stop the clatd (464xlat) service on the given interface.
-     */
-    void stopClatd(String interfaceName);
-
-    /**
      * Start listening for mobile activity state changes.
      */
     void registerNetworkActivityListener(INetworkActivityListener listener);
diff --git a/core/java/android/os/NativeHandle.java b/core/java/android/os/NativeHandle.java
index f7ffc37..f13bf5f 100644
--- a/core/java/android/os/NativeHandle.java
+++ b/core/java/android/os/NativeHandle.java
@@ -20,6 +20,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.system.ErrnoException;
 import android.system.Os;
 
@@ -32,6 +33,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public final class NativeHandle implements Closeable {
     // whether this object owns mFds
     private boolean mOwn = false;
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index cc6bb12..b9cdcc0 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -899,6 +899,33 @@
     }
 
     /**
+     * Flatten an {@link ArrayMap} with string keys containing a particular object
+     * type into the parcel at the current dataPosition() and growing dataCapacity()
+     * if needed. The type of the objects in the array must be one that implements
+     * Parcelable. Only the raw data of the objects is written and not their type,
+     * so you must use the corresponding {@link #createTypedArrayMap(Parcelable.Creator)}
+     *
+     * @param val The map of objects to be written.
+     * @param parcelableFlags The parcelable flags to use.
+     *
+     * @see #createTypedArrayMap(Parcelable.Creator)
+     * @see Parcelable
+     */
+    public <T extends Parcelable> void writeTypedArrayMap(@Nullable ArrayMap<String, T> val,
+            int parcelableFlags) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        final int count = val.size();
+        writeInt(count);
+        for (int i = 0; i < count; i++) {
+            writeString(val.keyAt(i));
+            writeTypedObject(val.valueAt(i), parcelableFlags);
+        }
+    }
+
+    /**
      * Write an array set to the parcel.
      *
      * @param val The array set to write.
@@ -1001,7 +1028,7 @@
      * values are written using {@link #writeValue} and must follow the
      * specification there.
      */
-    public final void writeSparseArray(@Nullable SparseArray<Object> val) {
+    public final <T> void writeSparseArray(@Nullable SparseArray<T> val) {
         if (val == null) {
             writeInt(-1);
             return;
@@ -1400,6 +1427,34 @@
     }
 
     /**
+     * Flatten a {@link SparseArray} containing a particular object type into the parcel
+     * at the current dataPosition() and growing dataCapacity() if needed. The
+     * type of the objects in the array must be one that implements Parcelable.
+     * Unlike the generic {@link #writeSparseArray(SparseArray)} method, however, only
+     * the raw data of the objects is written and not their type, so you must use the
+     * corresponding {@link #createTypedSparseArray(Parcelable.Creator)}.
+     *
+     * @param val The list of objects to be written.
+     * @param parcelableFlags The parcelable flags to use.
+     *
+     * @see #createTypedSparseArray(Parcelable.Creator)
+     * @see Parcelable
+     */
+    public final <T extends Parcelable> void writeTypedSparseArray(@Nullable SparseArray<T> val,
+            int parcelableFlags) {
+        if (val == null) {
+            writeInt(-1);
+            return;
+        }
+        final int count = val.size();
+        writeInt(count);
+        for (int i = 0; i < count; i++) {
+            writeInt(val.keyAt(i));
+            writeTypedObject(val.valueAt(i), parcelableFlags);
+        }
+    }
+
+    /**
      * @hide
      */
     public <T extends Parcelable> void writeTypedList(@Nullable List<T> val, int parcelableFlags) {
@@ -2369,7 +2424,7 @@
      * Parcelables.
      */
     @Nullable
-    public final SparseArray readSparseArray(@Nullable ClassLoader loader) {
+    public final <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader) {
         int N = readInt();
         if (N < 0) {
             return null;
@@ -2466,6 +2521,62 @@
     }
 
     /**
+     * Read into a new {@link SparseArray} items containing a particular object type
+     * that were written with {@link #writeTypedSparseArray(SparseArray, int)} at the
+     * current dataPosition().  The list <em>must</em> have previously been written
+     * via {@link #writeTypedSparseArray(SparseArray, int)} with the same object type.
+     *
+     * @param creator The creator to use when for instantiation.
+     *
+     * @return A newly created {@link SparseArray} containing objects with the same data
+     *         as those that were previously written.
+     *
+     * @see #writeTypedSparseArray(SparseArray, int)
+     */
+    public final @Nullable <T extends Parcelable> SparseArray<T> createTypedSparseArray(
+            @NonNull Parcelable.Creator<T> creator) {
+        final int count = readInt();
+        if (count < 0) {
+            return null;
+        }
+        final SparseArray<T> array = new SparseArray<>(count);
+        for (int i = 0; i < count; i++) {
+            final int index = readInt();
+            final T value = readTypedObject(creator);
+            array.append(index, value);
+        }
+        return array;
+    }
+
+    /**
+     * Read into a new {@link ArrayMap} with string keys items containing a particular
+     * object type that were written with {@link #writeTypedArrayMap(ArrayMap, int)} at the
+     * current dataPosition().  The list <em>must</em> have previously been written
+     * via {@link #writeTypedArrayMap(ArrayMap, int)} with the same object type.
+     *
+     * @param creator The creator to use when for instantiation.
+     *
+     * @return A newly created {@link ArrayMap} containing objects with the same data
+     *         as those that were previously written.
+     *
+     * @see #writeTypedArrayMap(ArrayMap, int)
+     */
+    public final @Nullable <T extends Parcelable> ArrayMap<String, T> createTypedArrayMap(
+            @NonNull Parcelable.Creator<T> creator) {
+        final int count = readInt();
+        if (count < 0) {
+            return null;
+        }
+        final ArrayMap<String, T> map = new ArrayMap<>(count);
+        for (int i = 0; i < count; i++) {
+            final String key = readString();
+            final T value = readTypedObject(creator);
+            map.append(key, value);
+        }
+        return map;
+    }
+
+    /**
      * Read and return a new ArrayList containing String objects from
      * the parcel that was written with {@link #writeStringList} at the
      * current dataPosition().  Returns null if the
diff --git a/core/java/android/os/ParcelableException.aidl b/core/java/android/os/ParcelableException.aidl
new file mode 100644
index 0000000..d214922
--- /dev/null
+++ b/core/java/android/os/ParcelableException.aidl
@@ -0,0 +1,18 @@
+/* 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.os;
+
+parcelable ParcelableException;
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index c3e0489..4ce760f 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1326,7 +1326,7 @@
      * @return Battery saver state data.
      *
      * @hide
-     * @see com.android.server.power.BatterySaverPolicy
+     * @see com.android.server.power.batterysaver.BatterySaverPolicy
      * @see PowerSaveState
      */
     public PowerSaveState getPowerSaveState(@ServiceType int serviceType) {
@@ -1724,6 +1724,25 @@
             = "android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED";
 
     /**
+     * Constant for PreIdleTimeout normal mode (default mode, not short nor extend timeout) .
+     * @hide
+     */
+    public static final int PRE_IDLE_TIMEOUT_MODE_NORMAL = 0;
+
+    /**
+     * Constant for PreIdleTimeout long mode (extend timeout to keep in inactive mode
+     * longer).
+     * @hide
+     */
+    public static final int PRE_IDLE_TIMEOUT_MODE_LONG = 1;
+
+    /**
+     * Constant for PreIdleTimeout short mode (short timeout to go to doze mode quickly)
+     * @hide
+     */
+    public static final int PRE_IDLE_TIMEOUT_MODE_SHORT = 2;
+
+    /**
      * A wake lock is a mechanism to indicate that your application needs
      * to have the device stay on.
      * <p>
diff --git a/core/java/android/os/PowerSaveState.java b/core/java/android/os/PowerSaveState.java
index de1128df..4918ad1 100644
--- a/core/java/android/os/PowerSaveState.java
+++ b/core/java/android/os/PowerSaveState.java
@@ -27,7 +27,7 @@
     /**
      * Whether we should enable battery saver for this service.
      *
-     * @see com.android.server.power.BatterySaverPolicy
+     * @see com.android.server.power.batterysaver.BatterySaverPolicy
      */
     public final boolean batterySaverEnabled;
     /**
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 505aec2..d2ab053 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -32,23 +32,12 @@
     private static final String LOG_TAG = "Process";
 
     /**
-     * @hide for internal use only.
-     */
-    public static final String ZYGOTE_SOCKET = "zygote";
-
-    /**
-     * @hide for internal use only.
-     */
-    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
      */
     public static final int ROOT_UID = 0;
 
@@ -64,7 +53,6 @@
 
     /**
      * Defines the UID/GID for the user shell.
-     * @hide
      */
     public static final int SHELL_UID = 2000;
 
@@ -111,8 +99,13 @@
     public static final int NFC_UID = 1027;
 
     /**
-     * Defines the UID/GID for the Bluetooth service process.
+     * Defines the UID/GID for the clatd process.
      * @hide
+     * */
+    public static final int CLAT_UID = 1029;
+
+    /**
+     * Defines the UID/GID for the Bluetooth service process.
      */
     public static final int BLUETOOTH_UID = 1002;
 
@@ -199,15 +192,38 @@
     public static final int LAST_APPLICATION_UID = 19999;
 
     /**
+     * First uid used for fully isolated sandboxed processes spawned from an app zygote
+     * @hide
+     */
+    @TestApi
+    public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000;
+
+    /**
+     * Number of UIDs we allocate per application zygote
+     * @hide
+     */
+    @TestApi
+    public static final int NUM_UIDS_PER_APP_ZYGOTE = 100;
+
+    /**
+     * Last uid used for fully isolated sandboxed processes spawned from an app zygote
+     * @hide
+     */
+    @TestApi
+    public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999;
+
+    /**
      * First uid used for fully isolated sandboxed processes (with no permissions of their own)
      * @hide
      */
+    @TestApi
     public static final int FIRST_ISOLATED_UID = 99000;
 
     /**
      * Last uid used for fully isolated sandboxed processes (with no permissions of their own)
      * @hide
      */
+    @TestApi
     public static final int LAST_ISOLATED_UID = 99999;
 
     /**
@@ -453,8 +469,7 @@
      * State associated with the zygote process.
      * @hide
      */
-    public static final ZygoteProcess zygoteProcess =
-            new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);
+    public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess();
 
     /**
      * Start a new process.
@@ -512,10 +527,10 @@
                                   @Nullable String[] packagesForUid,
                                   @Nullable String[] visibleVols,
                                   @Nullable String[] zygoteArgs) {
-        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
+        return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, packageName,
-                    packagesForUid, visibleVols, zygoteArgs);
+                    packagesForUid, visibleVols, /*useBlastulaPool=*/ true, zygoteArgs);
     }
 
     /** @hide */
@@ -536,7 +551,7 @@
         return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, packageName,
-                    packagesForUid, visibleVols, zygoteArgs);
+                    packagesForUid, visibleVols, /*useBlastulaPool=*/ false, zygoteArgs);
     }
 
     /**
@@ -644,7 +659,8 @@
     /** {@hide} */
     public static final boolean isIsolated(int uid) {
         uid = UserHandle.getAppId(uid);
-        return uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID;
+        return (uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID)
+                || (uid >= FIRST_APP_ZYGOTE_ISOLATED_UID && uid <= LAST_APP_ZYGOTE_ISOLATED_UID);
     }
 
     /**
diff --git a/core/java/android/os/ServiceSpecificException.java b/core/java/android/os/ServiceSpecificException.java
index 3e0f6da..3b0f26ae 100644
--- a/core/java/android/os/ServiceSpecificException.java
+++ b/core/java/android/os/ServiceSpecificException.java
@@ -15,6 +15,8 @@
  */
 package android.os;
 
+import android.annotation.SystemApi;
+
 /**
  * An exception specific to a service.
  *
@@ -28,6 +30,7 @@
  *
  * @hide
  */
+@SystemApi
 public class ServiceSpecificException extends RuntimeException {
     public final int errorCode;
 
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 6ea155f..68d6d85 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import android.annotation.NonNull;
+
 import com.android.internal.os.Zygote;
 
 import dalvik.annotation.optimization.FastNative;
@@ -95,6 +97,8 @@
     public static final long TRACE_TAG_AIDL = 1L << 24;
     /** @hide */
     public static final long TRACE_TAG_NNAPI = 1L << 25;
+    /** @hide */
+    public static final long TRACE_TAG_RRO = 1L << 26;
 
     private static final long TRACE_TAG_NOT_READY = 1L << 63;
     private static final int MAX_SECTION_NAME_LEN = 127;
@@ -311,7 +315,7 @@
      * @param sectionName The name of the code section to appear in the trace.  This may be at
      * most 127 Unicode code units long.
      */
-    public static void beginSection(String sectionName) {
+    public static void beginSection(@NonNull String sectionName) {
         if (isTagEnabled(TRACE_TAG_APP)) {
             if (sectionName.length() > MAX_SECTION_NAME_LEN) {
                 throw new IllegalArgumentException("sectionName is too long");
@@ -343,7 +347,7 @@
      * @param methodName The method name to appear in the trace.
      * @param cookie Unique identifier for distinguishing simultaneous events
      */
-    public static void beginAsyncSection(String methodName, int cookie) {
+    public static void beginAsyncSection(@NonNull String methodName, int cookie) {
         asyncTraceBegin(TRACE_TAG_APP, methodName, cookie);
     }
 
@@ -355,7 +359,7 @@
      * @param methodName The method name to appear in the trace.
      * @param cookie Unique identifier for distinguishing simultaneous events
      */
-    public static void endAsyncSection(String methodName, int cookie) {
+    public static void endAsyncSection(@NonNull String methodName, int cookie) {
         asyncTraceEnd(TRACE_TAG_APP, methodName, cookie);
     }
 
@@ -365,7 +369,7 @@
      * @param counterName The counter name to appear in the trace.
      * @param counterValue The counter value.
      */
-    public static void setCounter(String counterName, long counterValue) {
+    public static void setCounter(@NonNull String counterName, long counterValue) {
         if (isTagEnabled(TRACE_TAG_APP)) {
             nativeTraceCounter(TRACE_TAG_APP, counterName, counterValue);
         }
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index 8f2826c..1df3dad 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -66,6 +66,7 @@
         public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10;
         public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11;
         public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12;
+        public static final int PAYLOAD_TIMESTAMP_ERROR = 51;
         public static final int UPDATED_BUT_NOT_ACTIVE = 52;
     }
 
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index f8feb7b..ad8a4d5 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -138,8 +138,7 @@
      */
     public static boolean isIsolated(int uid) {
         if (uid > 0) {
-            final int appId = getAppId(uid);
-            return appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID;
+            return Process.isIsolated(uid);
         } else {
             return false;
         }
@@ -294,9 +293,14 @@
             sb.append('u');
             sb.append(getUserId(uid));
             final int appId = getAppId(uid);
-            if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
-                sb.append('i');
-                sb.append(appId - Process.FIRST_ISOLATED_UID);
+            if (isIsolated(appId)) {
+                if (appId > Process.FIRST_ISOLATED_UID) {
+                    sb.append('i');
+                    sb.append(appId - Process.FIRST_ISOLATED_UID);
+                } else {
+                    sb.append("ai");
+                    sb.append(appId - Process.FIRST_APP_ZYGOTE_ISOLATED_UID);
+                }
             } else if (appId >= Process.FIRST_APPLICATION_UID) {
                 sb.append('a');
                 sb.append(appId - Process.FIRST_APPLICATION_UID);
@@ -330,9 +334,14 @@
             pw.print('u');
             pw.print(getUserId(uid));
             final int appId = getAppId(uid);
-            if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
-                pw.print('i');
-                pw.print(appId - Process.FIRST_ISOLATED_UID);
+            if (isIsolated(appId)) {
+                if (appId > Process.FIRST_ISOLATED_UID) {
+                    pw.print('i');
+                    pw.print(appId - Process.FIRST_ISOLATED_UID);
+                } else {
+                    pw.print("ai");
+                    pw.print(appId - Process.FIRST_APP_ZYGOTE_ISOLATED_UID);
+                }
             } else if (appId >= Process.FIRST_APPLICATION_UID) {
                 pw.print('a');
                 pw.print(appId - Process.FIRST_APPLICATION_UID);
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index b5aeba0..226d1d0 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -74,10 +74,13 @@
     private final String mPackageName;
     // The default vibration intensity level for haptic feedback.
     @VibrationIntensity
-    private final int mDefaultHapticFeedbackIntensity;
+    private int mDefaultHapticFeedbackIntensity;
     // The default vibration intensity level for notifications.
     @VibrationIntensity
-    private final int mDefaultNotificationVibrationIntensity;
+    private int mDefaultNotificationVibrationIntensity;
+    // The default vibration intensity level for ringtones.
+    @VibrationIntensity
+    private int mDefaultRingVibrationIntensity;
 
     /**
      * @hide to prevent subclassing from outside of the framework
@@ -85,10 +88,7 @@
     public Vibrator() {
         mPackageName = ActivityThread.currentPackageName();
         final Context ctx = ActivityThread.currentActivityThread().getSystemContext();
-        mDefaultHapticFeedbackIntensity = loadDefaultIntensity(ctx,
-                com.android.internal.R.integer.config_defaultHapticFeedbackIntensity);
-        mDefaultNotificationVibrationIntensity = loadDefaultIntensity(ctx,
-                com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
+        loadVibrationIntensities(ctx);
     }
 
     /**
@@ -96,10 +96,16 @@
      */
     protected Vibrator(Context context) {
         mPackageName = context.getOpPackageName();
+        loadVibrationIntensities(context);
+    }
+
+    private void loadVibrationIntensities(Context context) {
         mDefaultHapticFeedbackIntensity = loadDefaultIntensity(context,
                 com.android.internal.R.integer.config_defaultHapticFeedbackIntensity);
         mDefaultNotificationVibrationIntensity = loadDefaultIntensity(context,
                 com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
+        mDefaultRingVibrationIntensity = loadDefaultIntensity(context,
+                com.android.internal.R.integer.config_defaultRingVibrationIntensity);
     }
 
     private int loadDefaultIntensity(Context ctx, int resId) {
@@ -115,13 +121,20 @@
     }
 
     /**
-     * Get the default vibration intensity for notifications and ringtones.
+     * Get the default vibration intensity for notifications.
      * @hide
      */
     public int getDefaultNotificationVibrationIntensity() {
         return mDefaultNotificationVibrationIntensity;
     }
 
+    /** Get the default vibration intensity for ringtones.
+     * @hide
+     */
+    public int getDefaultRingVibrationIntensity() {
+        return mDefaultRingVibrationIntensity;
+    }
+
     /**
      * Check whether the hardware has a vibrator.
      *
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index fb22194..23c54f4 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -16,23 +16,27 @@
 
 package android.os;
 
-import java.util.Map;
+import android.annotation.TestApi;
 
+import java.util.Map;
 
 /**
  * Java API for libvintf.
+ *
  * @hide
  */
+@TestApi
 public class VintfObject {
 
-    /// ---------- OTA
-
     /**
      * Slurps all device information (both manifests and both matrices)
      * and report them.
      * If any error in getting one of the manifests, it is not included in
      * the list.
+     *
+     * @hide
      */
+    @TestApi
     public static native String[] report();
 
     /**
@@ -44,6 +48,8 @@
      * @return = 0 if success (compatible)
      *         > 0 if incompatible
      *         < 0 if any error (mount partition fails, illformed XML, etc.)
+     *
+     * @hide
      */
     public static native int verify(String[] packageInfo);
 
@@ -55,22 +61,28 @@
      * @return = 0 if success (compatible)
      *         > 0 if incompatible
      *         < 0 if any error (mount partition fails, illformed XML, etc.)
+     *
+     * @hide
      */
     public static native int verifyWithoutAvb();
 
-    /// ---------- CTS Device Info
-
     /**
      * @return a list of HAL names and versions that is supported by this
      * device as stated in device and framework manifests. For example,
      * ["android.hidl.manager@1.0", "android.hardware.camera.device@1.0",
      *  "android.hardware.camera.device@3.2"]. There are no duplicates.
+     *
+     * @hide
      */
+    @TestApi
     public static native String[] getHalNamesAndVersions();
 
     /**
      * @return the BOARD_SEPOLICY_VERS build flag available in device manifest.
+     *
+     * @hide
      */
+    @TestApi
     public static native String getSepolicyVersion();
 
     /**
@@ -78,13 +90,22 @@
      * specified in framework manifest. For example,
      * [("27", ["libjpeg.so", "libbase.so"]),
      *  ("28", ["libjpeg.so", "libbase.so"])]
+     *
+     * @hide
      */
+    @TestApi
     public static native Map<String, String[]> getVndkSnapshots();
 
     /**
-     * @return target FCM version, a number specified in the device manifest
-     * indicating the FCM version that the device manifest implements. Null if
-     * device manifest doesn't specify this number (for legacy devices).
+     * @return Target Framework Compatibility Matrix (FCM) version, a number
+     * specified in the device manifest indicating the FCM version that the
+     * device manifest implements. Null if device manifest doesn't specify this
+     * number (for legacy devices).
+     *
+     * @hide
      */
+    @TestApi
     public static native Long getTargetFrameworkCompatibilityMatrixVersion();
+
+    private VintfObject() {}
 }
diff --git a/core/java/android/os/VintfRuntimeInfo.java b/core/java/android/os/VintfRuntimeInfo.java
index 29698b9..f17039b 100644
--- a/core/java/android/os/VintfRuntimeInfo.java
+++ b/core/java/android/os/VintfRuntimeInfo.java
@@ -16,55 +16,84 @@
 
 package android.os;
 
+import android.annotation.TestApi;
+
 /**
  * Java API for ::android::vintf::RuntimeInfo. Methods return null / 0 on any error.
  *
  * @hide
  */
+@TestApi
 public class VintfRuntimeInfo {
 
     private VintfRuntimeInfo() {}
 
     /**
      * @return /sys/fs/selinux/policyvers, via security_policyvers() native call
+     *
+     * @hide
      */
     public static native long getKernelSepolicyVersion();
     /**
      * @return content of /proc/cpuinfo
+     *
+     * @hide
      */
+    @TestApi
     public static native String getCpuInfo();
     /**
      * @return os name extracted from uname() native call
+     *
+     * @hide
      */
+    @TestApi
     public static native String getOsName();
     /**
      * @return node name extracted from uname() native call
+     *
+     * @hide
      */
+    @TestApi
     public static native String getNodeName();
     /**
      * @return os release extracted from uname() native call
+     *
+     * @hide
      */
+    @TestApi
     public static native String getOsRelease();
     /**
      * @return os version extracted from uname() native call
+     *
+     * @hide
      */
+    @TestApi
     public static native String getOsVersion();
     /**
      * @return hardware id extracted from uname() native call
+     *
+     * @hide
      */
+    @TestApi
     public static native String getHardwareId();
     /**
      * @return kernel version extracted from uname() native call. Format is
      * {@code x.y.z}.
+     *
+     * @hide
      */
+    @TestApi
     public static native String getKernelVersion();
     /**
      * @return libavb version in OS. Format is {@code x.y}.
+     *
+     * @hide
      */
     public static native String getBootAvbVersion();
     /**
      * @return libavb version in bootloader. Format is {@code x.y}.
+     *
+     * @hide
      */
     public static native String getBootVbmetaAvbVersion();
-
 }
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index 2299ab2..76fe560 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -140,6 +140,21 @@
         return mUids[index];
     }
 
+    /**
+     * Return the UID to which this WorkSource should be attributed to, i.e, the UID that
+     * initiated the work and not the UID performing it. If the WorkSource has no UIDs, returns -1
+     * instead.
+     *
+     * @hide
+     */
+    public int getAttributionUid() {
+        if (isEmpty()) {
+            return -1;
+        }
+
+        return mNum > 0 ? mUids[0] : mChains.get(0).getAttributionUid();
+    }
+
     /** @hide */
     @TestApi
     public String getName(int index) {
@@ -912,17 +927,18 @@
 
         /**
          * Return the UID to which this WorkChain should be attributed to, i.e, the UID that
-         * initiated the work and not the UID performing it.
+         * initiated the work and not the UID performing it. Returns -1 if the chain is empty.
          */
         public int getAttributionUid() {
-            return mUids[0];
+            return mSize > 0 ? mUids[0] : -1;
         }
 
         /**
          * Return the tag associated with the attribution UID. See (@link #getAttributionUid}.
+         * Returns null if the chain is empty.
          */
         public String getAttributionTag() {
-            return mTags[0];
+            return mTags.length > 0 ? mTags[0] : null;
         }
 
         // TODO: The following three trivial getters are purely for testing and will be removed
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index f136cd6..9e47179 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.util.Log;
@@ -34,6 +35,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Base64;
 import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
@@ -60,87 +62,161 @@
  * {@hide}
  */
 public class ZygoteProcess {
+
+    /**
+     * @hide for internal use only.
+     */
+    public static final String ZYGOTE_SOCKET_NAME = "zygote";
+
+    /**
+     * @hide for internal use only.
+     */
+    public static final String ZYGOTE_SECONDARY_SOCKET_NAME = "zygote_secondary";
+
+    /**
+     * @hide for internal use only
+     */
+    public static final String BLASTULA_POOL_SOCKET_NAME = "blastula_pool";
+
+    /**
+     * @hide for internal use only
+     */
+    public static final String BLASTULA_POOL_SECONDARY_SOCKET_NAME = "blastula_pool_secondary";
+
+    /**
+     * @hide for internal use only
+     */
     private static final String LOG_TAG = "ZygoteProcess";
 
     /**
      * The name of the socket used to communicate with the primary zygote.
      */
-    private final LocalSocketAddress mSocket;
+    private final LocalSocketAddress mZygoteSocketAddress;
 
     /**
      * The name of the secondary (alternate ABI) zygote socket.
      */
-    private final LocalSocketAddress mSecondarySocket;
+    private final LocalSocketAddress mZygoteSecondarySocketAddress;
+    /**
+     * The name of the socket used to communicate with the primary blastula pool.
+     */
+    private final LocalSocketAddress mBlastulaPoolSocketAddress;
 
-    public ZygoteProcess(String primarySocket, String secondarySocket) {
-        this(new LocalSocketAddress(primarySocket, LocalSocketAddress.Namespace.RESERVED),
-                new LocalSocketAddress(secondarySocket, LocalSocketAddress.Namespace.RESERVED));
+    /**
+     * The name of the socket used to communicate with the secondary (alternate ABI) blastula pool.
+     */
+    private final LocalSocketAddress mBlastulaPoolSecondarySocketAddress;
+
+    public ZygoteProcess() {
+        mZygoteSocketAddress =
+                new LocalSocketAddress(ZYGOTE_SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED);
+        mZygoteSecondarySocketAddress =
+                new LocalSocketAddress(ZYGOTE_SECONDARY_SOCKET_NAME,
+                                       LocalSocketAddress.Namespace.RESERVED);
+
+        mBlastulaPoolSocketAddress =
+                new LocalSocketAddress(BLASTULA_POOL_SOCKET_NAME,
+                                       LocalSocketAddress.Namespace.RESERVED);
+        mBlastulaPoolSecondarySocketAddress =
+                new LocalSocketAddress(BLASTULA_POOL_SECONDARY_SOCKET_NAME,
+                                       LocalSocketAddress.Namespace.RESERVED);
     }
 
-    public ZygoteProcess(LocalSocketAddress primarySocket, LocalSocketAddress secondarySocket) {
-        mSocket = primarySocket;
-        mSecondarySocket = secondarySocket;
+    public ZygoteProcess(LocalSocketAddress primarySocketAddress,
+                         LocalSocketAddress secondarySocketAddress) {
+        mZygoteSocketAddress = primarySocketAddress;
+        mZygoteSecondarySocketAddress = secondarySocketAddress;
+
+        mBlastulaPoolSocketAddress = null;
+        mBlastulaPoolSecondarySocketAddress = null;
     }
 
     public LocalSocketAddress getPrimarySocketAddress() {
-        return mSocket;
+        return mZygoteSocketAddress;
     }
 
     /**
      * State for communicating with the zygote process.
      */
     public static class ZygoteState {
-        final LocalSocket socket;
-        final DataInputStream inputStream;
-        final BufferedWriter writer;
-        final List<String> abiList;
+        final LocalSocketAddress mZygoteSocketAddress;
+        final LocalSocketAddress mBlastulaSocketAddress;
 
-        boolean mClosed;
+        private final LocalSocket mZygoteSessionSocket;
 
-        private ZygoteState(LocalSocket socket, DataInputStream inputStream,
-                BufferedWriter writer, List<String> abiList) {
-            this.socket = socket;
-            this.inputStream = inputStream;
-            this.writer = writer;
-            this.abiList = abiList;
+        final DataInputStream mZygoteInputStream;
+        final BufferedWriter mZygoteOutputWriter;
+
+        private final List<String> mABIList;
+
+        private boolean mClosed;
+
+        private ZygoteState(LocalSocketAddress zygoteSocketAddress,
+                            LocalSocketAddress blastulaSocketAddress,
+                            LocalSocket zygoteSessionSocket,
+                            DataInputStream zygoteInputStream,
+                            BufferedWriter zygoteOutputWriter,
+                            List<String> abiList) {
+            this.mZygoteSocketAddress = zygoteSocketAddress;
+            this.mBlastulaSocketAddress = blastulaSocketAddress;
+            this.mZygoteSessionSocket = zygoteSessionSocket;
+            this.mZygoteInputStream = zygoteInputStream;
+            this.mZygoteOutputWriter = zygoteOutputWriter;
+            this.mABIList = abiList;
         }
 
-        public static ZygoteState connect(LocalSocketAddress address) throws IOException {
+        /**
+         * Create a new ZygoteState object by connecting to the given Zygote socket and saving the
+         * given blastula socket address.
+         *
+         * @param zygoteSocketAddress  Zygote socket to connect to
+         * @param blastulaSocketAddress  Blastula socket address to save for later
+         * @return  A new ZygoteState object containing a session socket for the given Zygote socket
+         * address
+         * @throws IOException
+         */
+        public static ZygoteState connect(LocalSocketAddress zygoteSocketAddress,
+                                          LocalSocketAddress blastulaSocketAddress)
+                throws IOException {
+
             DataInputStream zygoteInputStream = null;
-            BufferedWriter zygoteWriter = null;
-            final LocalSocket zygoteSocket = new LocalSocket();
+            BufferedWriter zygoteOutputWriter = null;
+            final LocalSocket zygoteSessionSocket = new LocalSocket();
 
             try {
-                zygoteSocket.connect(address);
-
-                zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
-
-                zygoteWriter = new BufferedWriter(new OutputStreamWriter(
-                        zygoteSocket.getOutputStream()), 256);
+                zygoteSessionSocket.connect(zygoteSocketAddress);
+                zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
+                zygoteOutputWriter =
+                        new BufferedWriter(
+                                new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),
+                                Zygote.SOCKET_BUFFER_SIZE);
             } catch (IOException ex) {
                 try {
-                    zygoteSocket.close();
-                } catch (IOException ignore) {
-                }
+                    zygoteSessionSocket.close();
+                } catch (IOException ignore) { }
 
                 throw ex;
             }
 
-            String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
-            Log.i("Zygote", "Process: zygote socket " + address.getNamespace() + "/"
-                    + address.getName() + " opened, supported ABIS: " + abiListString);
+            return new ZygoteState(zygoteSocketAddress, blastulaSocketAddress,
+                                   zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter,
+                                   getAbiList(zygoteOutputWriter, zygoteInputStream));
+        }
 
-            return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
-                    Arrays.asList(abiListString.split(",")));
+        LocalSocket getBlastulaSessionSocket() throws IOException {
+            final LocalSocket blastulaSessionSocket = new LocalSocket();
+            blastulaSessionSocket.connect(this.mBlastulaSocketAddress);
+
+            return blastulaSessionSocket;
         }
 
         boolean matches(String abi) {
-            return abiList.contains(abi);
+            return mABIList.contains(abi);
         }
 
         public void close() {
             try {
-                socket.close();
+                mZygoteSessionSocket.close();
             } catch (IOException ex) {
                 Log.e(LOG_TAG,"I/O exception on routine close", ex);
             }
@@ -235,12 +311,13 @@
                                                   @Nullable String packageName,
                                                   @Nullable String[] packagesForUid,
                                                   @Nullable String[] visibleVols,
+                                                  boolean useBlastulaPool,
                                                   @Nullable String[] zygoteArgs) {
         try {
             return startViaZygote(processClass, niceName, uid, gid, gids,
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
-                    abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
-                    packageName, packagesForUid, visibleVols, zygoteArgs);
+                    abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/false,
+                    packageName, packagesForUid, visibleVols, useBlastulaPool, zygoteArgs);
         } catch (ZygoteStartFailedEx ex) {
             Log.e(LOG_TAG,
                     "Starting VM process through Zygote failed");
@@ -258,7 +335,7 @@
      * @throws ZygoteStartFailedEx if the query failed.
      */
     @GuardedBy("mLock")
-    private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
+    private static List<String> getAbiList(BufferedWriter writer, DataInputStream inputStream)
             throws IOException {
         // Each query starts with the argument count (1 in this case)
         writer.write("1");
@@ -274,7 +351,9 @@
         byte[] bytes = new byte[numBytes];
         inputStream.readFully(bytes);
 
-        return new String(bytes, StandardCharsets.US_ASCII);
+        String rawList = new String(bytes, StandardCharsets.US_ASCII);
+
+        return Arrays.asList(rawList.split(","));
     }
 
     /**
@@ -286,59 +365,128 @@
      */
     @GuardedBy("mLock")
     private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
-            ZygoteState zygoteState, ArrayList<String> args)
+            ZygoteState zygoteState, boolean useBlastulaPool, ArrayList<String> args)
             throws ZygoteStartFailedEx {
-        try {
-            // Throw early if any of the arguments are malformed. This means we can
-            // avoid writing a partial response to the zygote.
-            int sz = args.size();
-            for (int i = 0; i < sz; i++) {
-                if (args.get(i).indexOf('\n') >= 0) {
-                    throw new ZygoteStartFailedEx("embedded newlines not allowed");
+        // Throw early if any of the arguments are malformed. This means we can
+        // avoid writing a partial response to the zygote.
+        for (String arg : args) {
+            if (arg.indexOf('\n') >= 0) {
+                throw new ZygoteStartFailedEx("embedded newlines not allowed");
+            }
+        }
+
+        /**
+         * See com.android.internal.os.SystemZygoteInit.readArgumentList()
+         * Presently the wire format to the zygote process is:
+         * a) a count of arguments (argc, in essence)
+         * b) a number of newline-separated argument strings equal to count
+         *
+         * After the zygote process reads these it will write the pid of
+         * the child or -1 on failure, followed by boolean to
+         * indicate whether a wrapper process was used.
+         */
+        String msgStr = Integer.toString(args.size()) + "\n"
+                        + String.join("\n", args) + "\n";
+
+        // Should there be a timeout on this?
+        Process.ProcessStartResult result = new Process.ProcessStartResult();
+
+        // TODO (chriswailes): Move branch body into separate function.
+        if (useBlastulaPool && Zygote.BLASTULA_POOL_ENABLED && isValidBlastulaCommand(args)) {
+            LocalSocket blastulaSessionSocket = null;
+
+            try {
+                blastulaSessionSocket = zygoteState.getBlastulaSessionSocket();
+
+                final BufferedWriter blastulaWriter =
+                        new BufferedWriter(
+                                new OutputStreamWriter(blastulaSessionSocket.getOutputStream()),
+                                Zygote.SOCKET_BUFFER_SIZE);
+                final DataInputStream blastulaReader =
+                        new DataInputStream(blastulaSessionSocket.getInputStream());
+
+                blastulaWriter.write(msgStr);
+                blastulaWriter.flush();
+
+                result.pid = blastulaReader.readInt();
+                // Blastulas can't be used to spawn processes that need wrappers.
+                result.usingWrapper = false;
+
+                if (result.pid < 0) {
+                    throw new ZygoteStartFailedEx("Blastula specialization failed");
+                }
+
+                return result;
+            } catch (IOException ex) {
+                // If there was an IOException using the blastula pool we will log the error and
+                // attempt to start the process through the Zygote.
+                Log.e(LOG_TAG, "IO Exception while communicating with blastula pool - "
+                               + ex.toString());
+            } finally {
+                try {
+                    blastulaSessionSocket.close();
+                } catch (IOException ex) {
+                    Log.e(LOG_TAG, "Failed to close blastula session socket: " + ex.getMessage());
                 }
             }
+        }
 
-            /**
-             * See com.android.internal.os.SystemZygoteInit.readArgumentList()
-             * Presently the wire format to the zygote process is:
-             * a) a count of arguments (argc, in essence)
-             * b) a number of newline-separated argument strings equal to count
-             *
-             * After the zygote process reads these it will write the pid of
-             * the child or -1 on failure, followed by boolean to
-             * indicate whether a wrapper process was used.
-             */
-            final BufferedWriter writer = zygoteState.writer;
-            final DataInputStream inputStream = zygoteState.inputStream;
+        try {
+            final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
+            final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
 
-            writer.write(Integer.toString(args.size()));
-            writer.newLine();
-
-            for (int i = 0; i < sz; i++) {
-                String arg = args.get(i);
-                writer.write(arg);
-                writer.newLine();
-            }
-
-            writer.flush();
-
-            // Should there be a timeout on this?
-            Process.ProcessStartResult result = new Process.ProcessStartResult();
+            zygoteWriter.write(msgStr);
+            zygoteWriter.flush();
 
             // Always read the entire result from the input stream to avoid leaving
             // bytes in the stream for future process starts to accidentally stumble
             // upon.
-            result.pid = inputStream.readInt();
-            result.usingWrapper = inputStream.readBoolean();
-
-            if (result.pid < 0) {
-                throw new ZygoteStartFailedEx("fork() failed");
-            }
-            return result;
+            result.pid = zygoteInputStream.readInt();
+            result.usingWrapper = zygoteInputStream.readBoolean();
         } catch (IOException ex) {
             zygoteState.close();
+            Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
+                    + ex.toString());
             throw new ZygoteStartFailedEx(ex);
         }
+
+        if (result.pid < 0) {
+            throw new ZygoteStartFailedEx("fork() failed");
+        }
+
+        return result;
+    }
+
+    /**
+     * Flags that may not be passed to a blastula.
+     */
+    private static final String[] INVALID_BLASTULA_FLAGS = {
+        "--query-abi-list",
+        "--get-pid",
+        "--preload-default",
+        "--preload-package",
+        "--preload-app",
+        "--start-child-zygote",
+        "--set-api-blacklist-exemptions",
+        "--hidden-api-log-sampling-rate",
+        "--invoke-with"
+    };
+
+    /**
+     * Tests a command list to see if it is valid to send to a blastula.
+     * @param args  Zygote/Blastula command arguments
+     * @return  True if the command can be passed to a blastula; false otherwise
+     */
+    private static boolean isValidBlastulaCommand(ArrayList<String> args) {
+        for (String flag : args) {
+            for (String badFlag : INVALID_BLASTULA_FLAGS) {
+                if (flag.startsWith(badFlag)) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
     }
 
     /**
@@ -380,6 +528,7 @@
                                                       @Nullable String packageName,
                                                       @Nullable String[] packagesForUid,
                                                       @Nullable String[] visibleVols,
+                                                      boolean useBlastulaPool,
                                                       @Nullable String[] extraArgs)
                                                       throws ZygoteStartFailedEx {
         ArrayList<String> argsForZygote = new ArrayList<String>();
@@ -400,6 +549,8 @@
             argsForZygote.add("--mount-external-full");
         } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
             argsForZygote.add("--mount-external-installer");
+        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
+            argsForZygote.add("--mount-external-legacy");
         }
 
         argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
@@ -484,7 +635,9 @@
         }
 
         synchronized(mLock) {
-            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
+            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
+                                              useBlastulaPool,
+                                              argsForZygote);
         }
     }
 
@@ -524,18 +677,18 @@
                 ZygoteState state = openZygoteSocketIfNeeded(abi);
 
                 // Each query starts with the argument count (1 in this case)
-                state.writer.write("1");
+                state.mZygoteOutputWriter.write("1");
                 // ... followed by a new-line.
-                state.writer.newLine();
+                state.mZygoteOutputWriter.newLine();
                 // ... followed by our only argument.
-                state.writer.write("--get-pid");
-                state.writer.newLine();
-                state.writer.flush();
+                state.mZygoteOutputWriter.write("--get-pid");
+                state.mZygoteOutputWriter.newLine();
+                state.mZygoteOutputWriter.flush();
 
                 // The response is a length prefixed stream of ASCII bytes.
-                int numBytes = state.inputStream.readInt();
+                int numBytes = state.mZygoteInputStream.readInt();
                 byte[] bytes = new byte[numBytes];
-                state.inputStream.readFully(bytes);
+                state.mZygoteInputStream.readFully(bytes);
 
                 return Integer.parseInt(new String(bytes, StandardCharsets.US_ASCII));
             }
@@ -589,16 +742,16 @@
             return true;
         }
         try {
-            state.writer.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
-            state.writer.newLine();
-            state.writer.write("--set-api-blacklist-exemptions");
-            state.writer.newLine();
+            state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
+            state.mZygoteOutputWriter.newLine();
+            state.mZygoteOutputWriter.write("--set-api-blacklist-exemptions");
+            state.mZygoteOutputWriter.newLine();
             for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
-                state.writer.write(mApiBlacklistExemptions.get(i));
-                state.writer.newLine();
+                state.mZygoteOutputWriter.write(mApiBlacklistExemptions.get(i));
+                state.mZygoteOutputWriter.newLine();
             }
-            state.writer.flush();
-            int status = state.inputStream.readInt();
+            state.mZygoteOutputWriter.flush();
+            int status = state.mZygoteInputStream.readInt();
             if (status != 0) {
                 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
             }
@@ -618,13 +771,13 @@
             return;
         }
         try {
-            state.writer.write(Integer.toString(1));
-            state.writer.newLine();
-            state.writer.write("--hidden-api-log-sampling-rate="
+            state.mZygoteOutputWriter.write(Integer.toString(1));
+            state.mZygoteOutputWriter.newLine();
+            state.mZygoteOutputWriter.write("--hidden-api-log-sampling-rate="
                     + Integer.toString(mHiddenApiAccessLogSampleRate));
-            state.writer.newLine();
-            state.writer.flush();
-            int status = state.inputStream.readInt();
+            state.mZygoteOutputWriter.newLine();
+            state.mZygoteOutputWriter.flush();
+            int status = state.mZygoteInputStream.readInt();
             if (status != 0) {
                 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate; status " + status);
             }
@@ -634,22 +787,29 @@
     }
 
     /**
-     * Tries to open socket to Zygote process if not already open. If
-     * already open, does nothing.  May block and retry.  Requires that mLock be held.
+     * Tries to open a session socket to a Zygote process with a compatible ABI if one is not
+     * already open. If a compatible session socket is already open that session socket is returned.
+     * This function may block and may have to try connecting to multiple Zygotes to find the
+     * appropriate one.  Requires that mLock be held.
      */
     @GuardedBy("mLock")
-    private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
+    private ZygoteState openZygoteSocketIfNeeded(String abi)
+            throws ZygoteStartFailedEx {
+
         Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
 
         if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
             try {
-                primaryZygoteState = ZygoteState.connect(mSocket);
+                primaryZygoteState =
+                    ZygoteState.connect(mZygoteSocketAddress, mBlastulaPoolSocketAddress);
             } catch (IOException ioe) {
                 throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
             }
+
             maybeSetApiBlacklistExemptions(primaryZygoteState, false);
             maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
         }
+
         if (primaryZygoteState.matches(abi)) {
             return primaryZygoteState;
         }
@@ -657,10 +817,13 @@
         // The primary zygote didn't match. Try the secondary.
         if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
             try {
-                secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
+                secondaryZygoteState =
+                    ZygoteState.connect(mZygoteSecondarySocketAddress,
+                                        mBlastulaPoolSecondarySocketAddress);
             } catch (IOException ioe) {
                 throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
             }
+
             maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
             maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
         }
@@ -673,6 +836,36 @@
     }
 
     /**
+     * Instructs the zygote to pre-load the application code for the given Application.
+     * Only the app zygote supports this function.
+     * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
+     */
+    public boolean preloadApp(ApplicationInfo appInfo, String abi) throws ZygoteStartFailedEx,
+                                                                          IOException {
+        synchronized (mLock) {
+            ZygoteState state = openZygoteSocketIfNeeded(abi);
+            state.mZygoteOutputWriter.write("2");
+            state.mZygoteOutputWriter.newLine();
+
+            state.mZygoteOutputWriter.write("--preload-app");
+            state.mZygoteOutputWriter.newLine();
+
+            // Zygote args needs to be strings, so in order to pass ApplicationInfo,
+            // write it to a Parcel, and base64 the raw Parcel bytes to the other side.
+            Parcel parcel = Parcel.obtain();
+            appInfo.writeToParcel(parcel, 0 /* flags */);
+            String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall());
+            parcel.recycle();
+            state.mZygoteOutputWriter.write(encodedParcelData);
+            state.mZygoteOutputWriter.newLine();
+
+            state.mZygoteOutputWriter.flush();
+
+            return (state.mZygoteInputStream.readInt() == 0);
+        }
+    }
+
+    /**
      * Instructs the zygote to pre-load the classes and native libraries at the given paths
      * for the specified abi. Not all zygotes support this function.
      */
@@ -681,27 +874,27 @@
                                                                             IOException {
         synchronized(mLock) {
             ZygoteState state = openZygoteSocketIfNeeded(abi);
-            state.writer.write("5");
-            state.writer.newLine();
+            state.mZygoteOutputWriter.write("5");
+            state.mZygoteOutputWriter.newLine();
 
-            state.writer.write("--preload-package");
-            state.writer.newLine();
+            state.mZygoteOutputWriter.write("--preload-package");
+            state.mZygoteOutputWriter.newLine();
 
-            state.writer.write(packagePath);
-            state.writer.newLine();
+            state.mZygoteOutputWriter.write(packagePath);
+            state.mZygoteOutputWriter.newLine();
 
-            state.writer.write(libsPath);
-            state.writer.newLine();
+            state.mZygoteOutputWriter.write(libsPath);
+            state.mZygoteOutputWriter.newLine();
 
-            state.writer.write(libFileName);
-            state.writer.newLine();
+            state.mZygoteOutputWriter.write(libFileName);
+            state.mZygoteOutputWriter.newLine();
 
-            state.writer.write(cacheKey);
-            state.writer.newLine();
+            state.mZygoteOutputWriter.write(cacheKey);
+            state.mZygoteOutputWriter.newLine();
 
-            state.writer.flush();
+            state.mZygoteOutputWriter.flush();
 
-            return (state.inputStream.readInt() == 0);
+            return (state.mZygoteInputStream.readInt() == 0);
         }
     }
 
@@ -715,13 +908,13 @@
         synchronized (mLock) {
             ZygoteState state = openZygoteSocketIfNeeded(abi);
             // Each query starts with the argument count (1 in this case)
-            state.writer.write("1");
-            state.writer.newLine();
-            state.writer.write("--preload-default");
-            state.writer.newLine();
-            state.writer.flush();
+            state.mZygoteOutputWriter.write("1");
+            state.mZygoteOutputWriter.newLine();
+            state.mZygoteOutputWriter.write("--preload-default");
+            state.mZygoteOutputWriter.newLine();
+            state.mZygoteOutputWriter.flush();
 
-            return (state.inputStream.readInt() == 0);
+            return (state.mZygoteInputStream.readInt() == 0);
         }
     }
 
@@ -729,20 +922,21 @@
      * Try connecting to the Zygote over and over again until we hit a time-out.
      * @param socketName The name of the socket to connect to.
      */
-    public static void waitForConnectionToZygote(String socketName) {
-        final LocalSocketAddress address =
-                new LocalSocketAddress(socketName, LocalSocketAddress.Namespace.RESERVED);
-        waitForConnectionToZygote(address);
+    public static void waitForConnectionToZygote(String zygoteSocketName) {
+        final LocalSocketAddress zygoteSocketAddress =
+                new LocalSocketAddress(zygoteSocketName, LocalSocketAddress.Namespace.RESERVED);
+        waitForConnectionToZygote(zygoteSocketAddress);
     }
 
     /**
      * Try connecting to the Zygote over and over again until we hit a time-out.
      * @param address The name of the socket to connect to.
      */
-    public static void waitForConnectionToZygote(LocalSocketAddress address) {
+    public static void waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress) {
         for (int n = 20; n >= 0; n--) {
             try {
-                final ZygoteState zs = ZygoteState.connect(address);
+                final ZygoteState zs =
+                        ZygoteState.connect(zygoteSocketAddress, null);
                 zs.close();
                 return;
             } catch (IOException ioe) {
@@ -755,7 +949,8 @@
             } catch (InterruptedException ie) {
             }
         }
-        Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + address.getName());
+        Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket "
+                + zygoteSocketAddress.getName());
     }
 
     /**
@@ -763,6 +958,22 @@
      * secondary zygotes that inherit data from the zygote that this object
      * communicates with. This returns a new ZygoteProcess representing a connection
      * to the newly created zygote. Throws an exception if the zygote cannot be started.
+     *
+     * @param processClass The class to use as the child zygote's main entry
+     *                     point.
+     * @param niceName A more readable name to use for the process.
+     * @param uid The user-id under which the child zygote will run.
+     * @param gid The group-id under which the child zygote will run.
+     * @param gids Additional group-ids associated with the child zygote process.
+     * @param runtimeFlags Additional flags.
+     * @param seInfo null-ok SELinux information for the child zygote process.
+     * @param abi non-null the ABI of the child zygote
+     * @param acceptedAbiList ABIs this child zygote will accept connections for; this
+     *                        may be different from <code>abi</code> in case the children
+     *                        spawned from this Zygote only communicate using ABI-safe methods.
+     * @param instructionSet null-ok the instruction set to use.
+     * @param uidRangeStart The first UID in the range the child zygote may setuid()/setgid() to
+     * @param uidRangeEnd The last UID in the range the child zygote may setuid()/setgid() to
      */
     public ChildZygoteProcess startChildZygote(final String processClass,
                                                final String niceName,
@@ -770,12 +981,18 @@
                                                int runtimeFlags,
                                                String seInfo,
                                                String abi,
-                                               String instructionSet) {
+                                               String acceptedAbiList,
+                                               String instructionSet,
+                                               int uidRangeStart,
+                                               int uidRangeEnd) {
         // Create an unguessable address in the global abstract namespace.
         final LocalSocketAddress serverAddress = new LocalSocketAddress(
                 processClass + "/" + UUID.randomUUID().toString());
 
-        final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName()};
+        final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName(),
+                                    Zygote.CHILD_ZYGOTE_ABI_LIST_ARG + acceptedAbiList,
+                                    Zygote.CHILD_ZYGOTE_UID_RANGE_START + uidRangeStart,
+                                    Zygote.CHILD_ZYGOTE_UID_RANGE_END + uidRangeEnd};
 
         Process.ProcessStartResult result;
         try {
@@ -783,7 +1000,8 @@
                     gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
                     abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
                     true /* startChildZygote */, null /* packageName */,
-                    null /* packagesForUid */, null /* visibleVolumes */, extraArgs);
+                    null /* packagesForUid */, null /* visibleVolumes */,
+                    false /* useBlastulaPool */, extraArgs);
         } catch (ZygoteStartFailedEx ex) {
             throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
         }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 9594a71..735f4f2 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1540,6 +1540,7 @@
     }
 
     /** {@hide} */
+    @SystemApi
     @TestApi
     public static boolean hasIsolatedStorage() {
         // Prefer to use snapshot for current boot when available
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index df1a713..714a061 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -35,6 +35,7 @@
 
 import java.io.CharArrayWriter;
 import java.io.File;
+import java.util.Locale;
 
 /**
  * Information about a shared/external storage volume for a specific user.
@@ -263,6 +264,11 @@
         return mFsUuid;
     }
 
+    /** {@hide} */
+    public @Nullable String getNormalizedUuid() {
+        return mFsUuid != null ? mFsUuid.toLowerCase(Locale.US) : null;
+    }
+
     /**
      * Parse and return volume UUID as FAT volume ID, or return -1 if unable to
      * parse or UUID is unknown.
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 8c3aa17..5d310e1 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -42,6 +42,7 @@
 import java.io.CharArrayWriter;
 import java.io.File;
 import java.util.Comparator;
+import java.util.Locale;
 import java.util.Objects;
 
 /**
@@ -254,6 +255,10 @@
         return fsUuid;
     }
 
+    public @Nullable String getNormalizedFsUuid() {
+        return fsUuid != null ? fsUuid.toLowerCase(Locale.US) : null;
+    }
+
     @UnsupportedAppUsage
     public int getMountUserId() {
         return mountUserId;
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
new file mode 100644
index 0000000..249b622
--- /dev/null
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission;
+
+import android.os.RemoteCallback;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+
+/**
+ * Interface for system apps to communication with the permission controller.
+ *
+ * @hide
+ */
+oneway interface IPermissionController {
+    void revokeRuntimePermissions(in Bundle request, boolean doDryRun, int reason,
+            String callerPackageName, in RemoteCallback callback);
+    void getRuntimePermissionBackup(in UserHandle user, in ParcelFileDescriptor pipe);
+    void getAppPermissions(String packageName, in RemoteCallback callback);
+    void revokeRuntimePermission(String packageName, String permissionName);
+    void countPermissionApps(in List<String> permissionNames, boolean countOnlyGranted,
+            boolean countSystem, in RemoteCallback callback);
+    void getPermissionUsages(boolean countSystem, long numMillis, in RemoteCallback callback);
+}
diff --git a/core/java/android/permission/IRuntimePermissionPresenter.aidl b/core/java/android/permission/IRuntimePermissionPresenter.aidl
deleted file mode 100644
index e95428a..0000000
--- a/core/java/android/permission/IRuntimePermissionPresenter.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.permission;
-
-import android.os.RemoteCallback;
-
-/**
- * Interface for communication with the permission presenter service.
- *
- * @hide
- */
-oneway interface IRuntimePermissionPresenter {
-    void getAppPermissions(String packageName, in RemoteCallback callback);
-    void revokeRuntimePermission(String packageName, String permissionName);
-    void countPermissionApps(in List<String> permissionNames, boolean countOnlyGranted,
-            boolean countSystem, in RemoteCallback callback);
-}
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
new file mode 100644
index 0000000..bfcca7c
--- /dev/null
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -0,0 +1,813 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission;
+
+import static android.permission.PermissionControllerService.SERVICE_INTERFACE;
+
+import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
+import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.annotation.TestApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.AsyncTask;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
+import com.android.internal.infra.AbstractRemoteService;
+import com.android.internal.util.Preconditions;
+
+import libcore.io.IoUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Interface for communicating with the permission controller.
+ *
+ * @hide
+ */
+@TestApi
+@SystemApi
+@SystemService(Context.PERMISSION_CONTROLLER_SERVICE)
+public final class PermissionControllerManager {
+    private static final String TAG = PermissionControllerManager.class.getSimpleName();
+
+    private static final Object sLock = new Object();
+
+    /** App global remote service used by all {@link PermissionControllerManager managers} */
+    @GuardedBy("sLock")
+    private static RemoteService sRemoteService;
+
+    /**
+     * The key for retrieving the result from the returned bundle.
+     *
+     * @hide
+     */
+    public static final String KEY_RESULT =
+            "android.permission.PermissionControllerManager.key.result";
+
+    /** @hide */
+    @IntDef(prefix = { "REASON_" }, value = {
+            REASON_MALWARE,
+            REASON_INSTALLER_POLICY_VIOLATION,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Reason {}
+
+    /** The permissions are revoked because the apps holding the permissions are malware */
+    public static final int REASON_MALWARE = 1;
+
+    /**
+     * The permissions are revoked because the apps holding the permissions violate a policy of the
+     * app that installed it.
+     *
+     * <p>If this reason is used only permissions of apps that are installed by the caller of the
+     * API can be revoked.
+     */
+    public static final int REASON_INSTALLER_POLICY_VIOLATION = 2;
+
+    /**
+     * Callback for delivering the result of {@link #revokeRuntimePermissions}.
+     */
+    public abstract static class OnRevokeRuntimePermissionsCallback {
+        /**
+         * The result for {@link #revokeRuntimePermissions}.
+         *
+         * @param revoked The actually revoked permissions as
+         *                {@code Map<packageName, List<permission>>}
+         */
+        public abstract void onRevokeRuntimePermissions(@NonNull Map<String, List<String>> revoked);
+    }
+
+    /**
+     * Callback for delivering the result of {@link #getRuntimePermissionBackup}.
+     *
+     * @hide
+     */
+    public interface OnGetRuntimePermissionBackupCallback {
+        /**
+         * The result for {@link #getRuntimePermissionBackup}.
+         *
+         * @param backup The backup file
+         */
+        void onGetRuntimePermissionsBackup(@NonNull byte[] backup);
+    }
+
+    /**
+     * Callback for delivering the result of {@link #getAppPermissions}.
+     *
+     * @hide
+     */
+    public interface OnGetAppPermissionResultCallback {
+        /**
+         * The result for {@link #getAppPermissions(String, OnGetAppPermissionResultCallback,
+         * Handler)}.
+         *
+         * @param permissions The permissions list.
+         */
+        void onGetAppPermissions(@NonNull List<RuntimePermissionPresentationInfo> permissions);
+    }
+
+    /**
+     * Callback for delivering the result of {@link #countPermissionApps}.
+     *
+     * @hide
+     */
+    public interface OnCountPermissionAppsResultCallback {
+        /**
+         * The result for {@link #countPermissionApps(List, boolean, boolean,
+         * OnCountPermissionAppsResultCallback, Handler)}.
+         *
+         * @param numApps The number of apps that have one of the permissions
+         */
+        void onCountPermissionApps(int numApps);
+    }
+
+    /**
+     * Callback for delivering the result of {@link #getPermissionUsages}.
+     *
+     * @hide
+     */
+    public interface OnPermissionUsageResultCallback {
+        /**
+         * The result for {@link #getPermissionUsages}.
+         *
+         * @param users The users list.
+         */
+        void onPermissionUsageResult(@NonNull List<RuntimePermissionUsageInfo> users);
+    }
+
+    private final @NonNull Context mContext;
+
+    /**
+     * Create a new {@link PermissionControllerManager}.
+     *
+     * @param context to create the manager for
+     *
+     * @hide
+     */
+    public PermissionControllerManager(@NonNull Context context) {
+        synchronized (sLock) {
+            if (sRemoteService == null) {
+                Intent intent = new Intent(SERVICE_INTERFACE);
+                intent.setPackage(context.getPackageManager().getPermissionControllerPackageName());
+                ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0);
+
+                sRemoteService = new RemoteService(context.getApplicationContext(),
+                        serviceInfo.getComponentInfo().getComponentName());
+            }
+        }
+
+        mContext = context;
+    }
+
+    /**
+     * Revoke a set of runtime permissions for various apps.
+     *
+     * @param request The permissions to revoke as {@code Map<packageName, List<permission>>}
+     * @param doDryRun Compute the permissions that would be revoked, but not actually revoke them
+     * @param reason Why the permission should be revoked
+     * @param executor Executor on which to invoke the callback
+     * @param callback Callback to receive the result
+     */
+    @RequiresPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
+    public void revokeRuntimePermissions(@NonNull Map<String, List<String>> request,
+            boolean doDryRun, @Reason int reason, @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnRevokeRuntimePermissionsCallback callback) {
+        // Check input to fail immediately instead of inside the async request
+        checkNotNull(executor);
+        checkNotNull(callback);
+        checkNotNull(request);
+        for (Map.Entry<String, List<String>> appRequest : request.entrySet()) {
+            checkNotNull(appRequest.getKey());
+            checkCollectionElementsNotNull(appRequest.getValue(), "permissions");
+        }
+
+        // Check required permission to fail immediately instead of inside the oneway binder call
+        if (mContext.checkSelfPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
+                    + " required");
+        }
+
+        sRemoteService.scheduleRequest(new PendingRevokeRuntimePermissionRequest(sRemoteService,
+                request, doDryRun, reason, mContext.getPackageName(), executor, callback));
+    }
+
+    /**
+     * Create a backup of the runtime permissions.
+     *
+     * @param user The user to be backed up
+     * @param executor Executor on which to invoke the callback
+     * @param callback Callback to receive the result
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
+    public void getRuntimePermissionBackup(@NonNull UserHandle user,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnGetRuntimePermissionBackupCallback callback) {
+        checkNotNull(executor);
+        checkNotNull(callback);
+
+        sRemoteService.scheduleRequest(new PendingGetRuntimePermissionBackup(sRemoteService,
+                user, executor, callback));
+    }
+
+    /**
+     * Gets the runtime permissions for an app.
+     *
+     * @param packageName The package for which to query.
+     * @param callback Callback to receive the result.
+     * @param handler Handler on which to invoke the callback.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
+    public void getAppPermissions(@NonNull String packageName,
+            @NonNull OnGetAppPermissionResultCallback callback, @Nullable Handler handler) {
+        checkNotNull(packageName);
+        checkNotNull(callback);
+
+        sRemoteService.scheduleRequest(new PendingGetAppPermissionRequest(sRemoteService,
+                packageName, callback, handler == null ? sRemoteService.getHandler() : handler));
+    }
+
+    /**
+     * Revoke the permission {@code permissionName} for app {@code packageName}
+     *
+     * @param packageName The package for which to revoke
+     * @param permissionName The permission to revoke
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
+    public void revokeRuntimePermission(@NonNull String packageName,
+            @NonNull String permissionName) {
+        checkNotNull(packageName);
+        checkNotNull(permissionName);
+
+        sRemoteService.scheduleAsyncRequest(new PendingRevokeAppPermissionRequest(packageName,
+                permissionName));
+    }
+
+    /**
+     * Count how many apps have one of a set of permissions.
+     *
+     * @param permissionNames The permissions the app might have
+     * @param countOnlyGranted Count an app only if the permission is granted to the app
+     * @param countSystem Also count system apps
+     * @param callback Callback to receive the result
+     * @param handler Handler on which to invoke the callback
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
+    public void countPermissionApps(@NonNull List<String> permissionNames,
+            boolean countOnlyGranted, boolean countSystem,
+            @NonNull OnCountPermissionAppsResultCallback callback, @Nullable Handler handler) {
+        checkCollectionElementsNotNull(permissionNames, "permissionNames");
+        checkNotNull(callback);
+
+        sRemoteService.scheduleRequest(new PendingCountPermissionAppsRequest(sRemoteService,
+                permissionNames, countOnlyGranted, countSystem, callback,
+                handler == null ? sRemoteService.getHandler() : handler));
+    }
+
+    /**
+     * Count how many apps have used permissions.
+     *
+     * @param countSystem Also count system apps
+     * @param numMillis The number of milliseconds in the past to check for uses
+     * @param executor Executor on which to invoke the callback
+     * @param callback Callback to receive the result
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
+    public void getPermissionUsages(boolean countSystem, long numMillis,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnPermissionUsageResultCallback callback) {
+        checkArgumentNonnegative(numMillis);
+        checkNotNull(executor);
+        checkNotNull(callback);
+
+        sRemoteService.scheduleRequest(new PendingGetPermissionUsagesRequest(sRemoteService,
+                countSystem, numMillis, executor, callback));
+    }
+
+    /**
+     * A connection to the remote service
+     */
+    static final class RemoteService extends
+            AbstractMultiplePendingRequestsRemoteService<RemoteService, IPermissionController> {
+        private static final long UNBIND_TIMEOUT_MILLIS = 10000;
+        private static final long MESSAGE_TIMEOUT_MILLIS = 30000;
+
+        /**
+         * Create a connection to the remote service
+         *
+         * @param context A context to use
+         * @param componentName The component of the service to connect to
+         */
+        RemoteService(@NonNull Context context, @NonNull ComponentName componentName) {
+            super(context, SERVICE_INTERFACE, componentName, UserHandle.myUserId(),
+                    service -> Log.e(TAG, "RuntimePermPresenterService " + service + " died"),
+                    false, false, 1);
+        }
+
+        /**
+         * @return The default handler used by this service.
+         */
+        Handler getHandler() {
+            return mHandler;
+        }
+
+        @Override
+        protected @NonNull IPermissionController getServiceInterface(@NonNull IBinder binder) {
+            return IPermissionController.Stub.asInterface(binder);
+        }
+
+        @Override
+        protected long getTimeoutIdleBindMillis() {
+            return UNBIND_TIMEOUT_MILLIS;
+        }
+
+        @Override
+        protected long getRemoteRequestMillis() {
+            return MESSAGE_TIMEOUT_MILLIS;
+        }
+
+        @Override
+        public void scheduleRequest(@NonNull PendingRequest<RemoteService,
+                IPermissionController> pendingRequest) {
+            super.scheduleRequest(pendingRequest);
+        }
+
+        @Override
+        public void scheduleAsyncRequest(@NonNull AsyncRequest<IPermissionController> request) {
+            super.scheduleAsyncRequest(request);
+        }
+    }
+
+    /**
+     * Task to read a large amount of data from a remote service.
+     */
+    private static class FileReaderTask<Callback extends Consumer<byte[]>>
+            extends AsyncTask<Void, Void, byte[]> {
+        private ParcelFileDescriptor mLocalPipe;
+        private ParcelFileDescriptor mRemotePipe;
+
+        private final @NonNull Callback mCallback;
+
+        FileReaderTask(@NonNull Callback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        protected void onPreExecute() {
+            ParcelFileDescriptor[] pipe;
+            try {
+                pipe = ParcelFileDescriptor.createPipe();
+            } catch (IOException e) {
+                Log.e(TAG, "Could not create pipe needed to get runtime permission backup", e);
+                return;
+            }
+
+            mLocalPipe = pipe[0];
+            mRemotePipe = pipe[1];
+        }
+
+        /**
+         * Get the file descriptor the remote service should write the data to.
+         *
+         * <p>Needs to be closed <u>locally</u> before the FileReader can finish.
+         *
+         * @return The file the data should be written to
+         */
+        ParcelFileDescriptor getRemotePipe() {
+            return mRemotePipe;
+        }
+
+        @Override
+        protected byte[] doInBackground(Void... ignored) {
+            ByteArrayOutputStream combinedBuffer = new ByteArrayOutputStream();
+
+            try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(mLocalPipe)) {
+                byte[] buffer = new byte[16 * 1024];
+
+                while (!isCancelled()) {
+                    int numRead = in.read(buffer);
+                    if (numRead == -1) {
+                        break;
+                    }
+
+                    combinedBuffer.write(buffer, 0, numRead);
+                }
+            } catch (IOException | NullPointerException e) {
+                Log.e(TAG, "Error reading runtime permission backup", e);
+                combinedBuffer.reset();
+            }
+
+            return combinedBuffer.toByteArray();
+        }
+
+        /**
+         * Interrupt the reading of the data.
+         *
+         * <p>Needs to be called when canceling this task as it might be hung.
+         */
+        void interruptRead() {
+            IoUtils.closeQuietly(mLocalPipe);
+        }
+
+        @Override
+        protected void onCancelled() {
+            onPostExecute(new byte[]{});
+        }
+
+        @Override
+        protected void onPostExecute(byte[] backup) {
+            IoUtils.closeQuietly(mLocalPipe);
+            mCallback.accept(backup);
+        }
+    }
+
+    /**
+     * Request for {@link #revokeRuntimePermissions}
+     */
+    private static final class PendingRevokeRuntimePermissionRequest extends
+            AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
+        private final @NonNull Map<String, List<String>> mRequest;
+        private final boolean mDoDryRun;
+        private final int mReason;
+        private final @NonNull String mCallingPackage;
+        private final @NonNull Executor mExecutor;
+        private final @NonNull OnRevokeRuntimePermissionsCallback mCallback;
+
+        private final @NonNull RemoteCallback mRemoteCallback;
+
+        private PendingRevokeRuntimePermissionRequest(@NonNull RemoteService service,
+                @NonNull Map<String, List<String>> request, boolean doDryRun,
+                @Reason int reason, @NonNull String callingPackage,
+                @NonNull @CallbackExecutor Executor executor,
+                @NonNull OnRevokeRuntimePermissionsCallback callback) {
+            super(service);
+
+            mRequest = request;
+            mDoDryRun = doDryRun;
+            mReason = reason;
+            mCallingPackage = callingPackage;
+            mExecutor = executor;
+            mCallback = callback;
+
+            mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    Map<String, List<String>> revoked = new ArrayMap<>();
+                    try {
+                        Bundle bundleizedRevoked = result.getBundle(KEY_RESULT);
+
+                        for (String packageName : bundleizedRevoked.keySet()) {
+                            Preconditions.checkNotNull(packageName);
+
+                            ArrayList<String> permissions =
+                                    bundleizedRevoked.getStringArrayList(packageName);
+                            Preconditions.checkCollectionElementsNotNull(permissions,
+                                    "permissions");
+
+                            revoked.put(packageName, permissions);
+                        }
+                    } catch (Exception e) {
+                        Log.e(TAG, "Could not read result when revoking runtime permissions", e);
+                    }
+
+                    callback.onRevokeRuntimePermissions(revoked);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+
+                    finish();
+                }
+            }), null);
+        }
+
+        @Override
+        protected void onTimeout(RemoteService remoteService) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(
+                        () -> mCallback.onRevokeRuntimePermissions(Collections.emptyMap()));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void run() {
+            Bundle bundledizedRequest = new Bundle();
+            for (Map.Entry<String, List<String>> appRequest : mRequest.entrySet()) {
+                bundledizedRequest.putStringArrayList(appRequest.getKey(),
+                        new ArrayList<>(appRequest.getValue()));
+            }
+
+            try {
+                getService().getServiceInterface().revokeRuntimePermissions(bundledizedRequest,
+                        mDoDryRun, mReason, mCallingPackage, mRemoteCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error revoking runtime permission", e);
+            }
+        }
+    }
+
+    /**
+     * Request for {@link #getRuntimePermissionBackup}
+     */
+    private static final class PendingGetRuntimePermissionBackup extends
+            AbstractRemoteService.PendingRequest<RemoteService, IPermissionController>
+            implements Consumer<byte[]> {
+        private final @NonNull FileReaderTask<PendingGetRuntimePermissionBackup> mBackupReader;
+        private final @NonNull Executor mExecutor;
+        private final @NonNull OnGetRuntimePermissionBackupCallback mCallback;
+        private final @NonNull UserHandle mUser;
+
+        private PendingGetRuntimePermissionBackup(@NonNull RemoteService service,
+                @NonNull UserHandle user, @NonNull @CallbackExecutor Executor executor,
+                @NonNull OnGetRuntimePermissionBackupCallback callback) {
+            super(service);
+
+            mUser = user;
+            mExecutor = executor;
+            mCallback = callback;
+
+            mBackupReader = new FileReaderTask<>(this);
+        }
+
+        @Override
+        protected void onTimeout(RemoteService remoteService) {
+            mBackupReader.cancel(true);
+            mBackupReader.interruptRead();
+        }
+
+        @Override
+        public void run() {
+            mBackupReader.execute();
+
+            ParcelFileDescriptor remotePipe = mBackupReader.getRemotePipe();
+            try {
+                getService().getServiceInterface().getRuntimePermissionBackup(mUser, remotePipe);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error getting runtime permission backup", e);
+            } finally {
+                // Remote pipe end is duped by binder call. Local copy is not needed anymore
+                IoUtils.closeQuietly(remotePipe);
+            }
+        }
+
+        /**
+         * Called when the {@link #mBackupReader} finished reading the file.
+         *
+         * @param backup The data read
+         */
+        @Override
+        public void accept(byte[] backup) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.onGetRuntimePermissionsBackup(backup));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+
+            finish();
+        }
+    }
+
+    /**
+     * Request for {@link #getAppPermissions}
+     */
+    private static final class PendingGetAppPermissionRequest extends
+            AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
+        private final @NonNull String mPackageName;
+        private final @NonNull OnGetAppPermissionResultCallback mCallback;
+
+        private final @NonNull RemoteCallback mRemoteCallback;
+
+        private PendingGetAppPermissionRequest(@NonNull RemoteService service,
+                @NonNull String packageName, @NonNull OnGetAppPermissionResultCallback callback,
+                @NonNull Handler handler) {
+            super(service);
+
+            mPackageName = packageName;
+            mCallback = callback;
+
+            mRemoteCallback = new RemoteCallback(result -> {
+                final List<RuntimePermissionPresentationInfo> reportedPermissions;
+                List<RuntimePermissionPresentationInfo> permissions = null;
+                if (result != null) {
+                    permissions = result.getParcelableArrayList(KEY_RESULT);
+                }
+                if (permissions == null) {
+                    permissions = Collections.emptyList();
+                }
+                reportedPermissions = permissions;
+
+                callback.onGetAppPermissions(reportedPermissions);
+
+                finish();
+            }, handler);
+        }
+
+        @Override
+        protected void onTimeout(RemoteService remoteService) {
+            mCallback.onGetAppPermissions(Collections.emptyList());
+        }
+
+        @Override
+        public void run() {
+            try {
+                getService().getServiceInterface().getAppPermissions(mPackageName, mRemoteCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error getting app permission", e);
+            }
+        }
+    }
+
+    /**
+     * Request for {@link #revokeRuntimePermission}
+     */
+    private static final class PendingRevokeAppPermissionRequest
+            implements AbstractRemoteService.AsyncRequest<IPermissionController> {
+        private final @NonNull String mPackageName;
+        private final @NonNull String mPermissionName;
+
+        private PendingRevokeAppPermissionRequest(@NonNull String packageName,
+                @NonNull String permissionName) {
+            mPackageName = packageName;
+            mPermissionName = permissionName;
+        }
+
+        @Override
+        public void run(IPermissionController remoteInterface) {
+            try {
+                remoteInterface.revokeRuntimePermission(mPackageName, mPermissionName);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error revoking app permission", e);
+            }
+        }
+    }
+
+    /**
+     * Request for {@link #countPermissionApps}
+     */
+    private static final class PendingCountPermissionAppsRequest extends
+            AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
+        private final @NonNull List<String> mPermissionNames;
+        private final @NonNull OnCountPermissionAppsResultCallback mCallback;
+        private final boolean mCountOnlyGranted;
+        private final boolean mCountSystem;
+
+        private final @NonNull RemoteCallback mRemoteCallback;
+
+        private PendingCountPermissionAppsRequest(@NonNull RemoteService service,
+                @NonNull List<String> permissionNames, boolean countOnlyGranted,
+                boolean countSystem, @NonNull OnCountPermissionAppsResultCallback callback,
+                @NonNull Handler handler) {
+            super(service);
+
+            mPermissionNames = permissionNames;
+            mCountOnlyGranted = countOnlyGranted;
+            mCountSystem = countSystem;
+            mCallback = callback;
+
+            mRemoteCallback = new RemoteCallback(result -> {
+                final int numApps;
+                if (result != null) {
+                    numApps = result.getInt(KEY_RESULT);
+                } else {
+                    numApps = 0;
+                }
+
+                callback.onCountPermissionApps(numApps);
+
+                finish();
+            }, handler);
+        }
+
+        @Override
+        protected void onTimeout(RemoteService remoteService) {
+            mCallback.onCountPermissionApps(0);
+        }
+
+        @Override
+        public void run() {
+            try {
+                getService().getServiceInterface().countPermissionApps(mPermissionNames,
+                        mCountOnlyGranted, mCountSystem, mRemoteCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error counting permission apps", e);
+            }
+        }
+    }
+
+    /**
+     * Request for {@link #getPermissionUsages}
+     */
+    private static final class PendingGetPermissionUsagesRequest extends
+            AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
+        private final @NonNull OnPermissionUsageResultCallback mCallback;
+        private final boolean mCountSystem;
+        private final long mNumMillis;
+
+        private final @NonNull RemoteCallback mRemoteCallback;
+
+        private PendingGetPermissionUsagesRequest(@NonNull RemoteService service,
+                boolean countSystem, long numMillis, @NonNull @CallbackExecutor Executor executor,
+                @NonNull OnPermissionUsageResultCallback callback) {
+            super(service);
+
+            mCountSystem = countSystem;
+            mNumMillis = numMillis;
+            mCallback = callback;
+
+            mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    final List<RuntimePermissionUsageInfo> reportedUsers;
+                    List<RuntimePermissionUsageInfo> users = null;
+                    if (result != null) {
+                        users = result.getParcelableArrayList(KEY_RESULT);
+                    } else {
+                        users = Collections.emptyList();
+                    }
+                    reportedUsers = users;
+
+                    callback.onPermissionUsageResult(reportedUsers);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+
+                    finish();
+                }
+            }), null);
+        }
+
+        @Override
+        protected void onTimeout(RemoteService remoteService) {
+            mCallback.onPermissionUsageResult(Collections.emptyList());
+        }
+
+        @Override
+        public void run() {
+            try {
+                getService().getServiceInterface().getPermissionUsages(mCountSystem, mNumMillis,
+                        mRemoteCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error counting permission users", e);
+            }
+        }
+    }
+}
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
new file mode 100644
index 0000000..10e8c8d
--- /dev/null
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
+import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteCallback;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This service is meant to be implemented by the app controlling permissions.
+ *
+ * @see PermissionController
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class PermissionControllerService extends Service {
+    private static final String LOG_TAG = PermissionControllerService.class.getSimpleName();
+
+    /**
+     * The {@link Intent} action that must be declared as handled by a service
+     * in its manifest for the system to recognize it as a runtime permission
+     * presenter service.
+     */
+    public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
+
+    // No need for locking - always set first and never modified
+    private Handler mHandler;
+
+    @Override
+    public final void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+        mHandler = new Handler(base.getMainLooper());
+    }
+
+    /**
+     * Revoke a set of runtime permissions for various apps.
+     *
+     * @param requests The permissions to revoke as {@code Map<packageName, List<permission>>}
+     * @param doDryRun Compute the permissions that would be revoked, but not actually revoke them
+     * @param reason Why the permission should be revoked
+     * @param callerPackageName The package name of the calling app
+     *
+     * @return the actually removed permissions as {@code Map<packageName, List<permission>>}
+     */
+    public abstract @NonNull Map<String, List<String>> onRevokeRuntimePermissions(
+            @NonNull Map<String, List<String>> requests, boolean doDryRun,
+            @PermissionControllerManager.Reason int reason, @NonNull String callerPackageName);
+
+    /**
+     * Create a backup of the runtime permissions.
+     *
+     * @param user The user to back up
+     * @param out The stream to write the backup to
+     */
+    public abstract void onGetRuntimePermissionsBackup(@NonNull UserHandle user,
+            @NonNull OutputStream out);
+
+    /**
+     * Gets the runtime permissions for an app.
+     *
+     * @param packageName The package for which to query.
+     *
+     * @return descriptions of the runtime permissions of the app
+     */
+    public abstract @NonNull List<RuntimePermissionPresentationInfo> onGetAppPermissions(
+            @NonNull String packageName);
+
+    /**
+     * Revokes the permission {@code permissionName} for app {@code packageName}
+     *
+     * @param packageName The package for which to revoke
+     * @param permissionName The permission to revoke
+     */
+    public abstract void onRevokeRuntimePermission(@NonNull String packageName,
+            @NonNull String permissionName);
+
+    /**
+     * Count how many apps have one of a set of permissions.
+     *
+     * @param permissionNames The permissions the app might have
+     * @param countOnlyGranted Count an app only if the permission is granted to the app
+     * @param countSystem Also count system apps
+     *
+     * @return the number of apps that have one of the permissions
+     */
+    public abstract int onCountPermissionApps(@NonNull List<String> permissionNames,
+            boolean countOnlyGranted, boolean countSystem);
+
+    /**
+     * Count how many apps have used permissions.
+     *
+     * @param countSystem Also count system apps
+     * @param numMillis The number of milliseconds in the past to check for uses
+     *
+     * @return descriptions of the users of permissions
+     */
+    public abstract @NonNull List<RuntimePermissionUsageInfo>
+            onPermissionUsageResult(boolean countSystem, long numMillis);
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return new IPermissionController.Stub() {
+            @Override
+            public void revokeRuntimePermissions(
+                    Bundle bundleizedRequest, boolean doDryRun, int reason,
+                    String callerPackageName, RemoteCallback callback) {
+                checkNotNull(bundleizedRequest, "bundleizedRequest");
+                checkNotNull(callerPackageName);
+                checkNotNull(callback);
+
+                Map<String, List<String>> request = new ArrayMap<>();
+                for (String packageName : bundleizedRequest.keySet()) {
+                    Preconditions.checkNotNull(packageName);
+
+                    ArrayList<String> permissions =
+                            bundleizedRequest.getStringArrayList(packageName);
+                    Preconditions.checkCollectionElementsNotNull(permissions, "permissions");
+
+                    request.put(packageName, permissions);
+                }
+
+                enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
+
+                // Verify callerPackageName
+                try {
+                    PackageInfo pkgInfo = getPackageManager().getPackageInfo(callerPackageName, 0);
+                    checkArgument(getCallingUid() == pkgInfo.applicationInfo.uid);
+                } catch (PackageManager.NameNotFoundException e) {
+                    throw new RuntimeException(e);
+                }
+
+                mHandler.sendMessage(obtainMessage(
+                        PermissionControllerService::revokeRuntimePermissions,
+                        PermissionControllerService.this, request, doDryRun, reason,
+                        callerPackageName, callback));
+            }
+
+            @Override
+            public void getRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) {
+                checkNotNull(user);
+                checkNotNull(pipe);
+
+                enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+
+                mHandler.sendMessage(obtainMessage(
+                        PermissionControllerService::getRuntimePermissionsBackup,
+                        PermissionControllerService.this, user, pipe));
+            }
+
+            @Override
+            public void getAppPermissions(String packageName, RemoteCallback callback) {
+                checkNotNull(packageName, "packageName");
+                checkNotNull(callback, "callback");
+
+                enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+
+                mHandler.sendMessage(
+                        obtainMessage(PermissionControllerService::getAppPermissions,
+                                PermissionControllerService.this, packageName, callback));
+            }
+
+            @Override
+            public void revokeRuntimePermission(String packageName, String permissionName) {
+                checkNotNull(packageName, "packageName");
+                checkNotNull(permissionName, "permissionName");
+
+                enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
+
+                mHandler.sendMessage(
+                        obtainMessage(PermissionControllerService::onRevokeRuntimePermission,
+                                PermissionControllerService.this, packageName, permissionName));
+            }
+
+            @Override
+            public void countPermissionApps(List<String> permissionNames, boolean countOnlyGranted,
+                    boolean countSystem, RemoteCallback callback) {
+                checkCollectionElementsNotNull(permissionNames, "permissionNames");
+                checkNotNull(callback, "callback");
+
+                enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+
+                mHandler.sendMessage(
+                        obtainMessage(PermissionControllerService::countPermissionApps,
+                                PermissionControllerService.this, permissionNames, countOnlyGranted,
+                                countSystem, callback));
+            }
+
+            @Override
+            public void getPermissionUsages(boolean countSystem, long numMillis,
+                    RemoteCallback callback) {
+                checkArgumentNonnegative(numMillis);
+                checkNotNull(callback, "callback");
+
+                enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+
+                mHandler.sendMessage(
+                        obtainMessage(PermissionControllerService::getPermissionUsages,
+                                PermissionControllerService.this, countSystem, numMillis,
+                                callback));
+            }
+        };
+    }
+
+    private void revokeRuntimePermissions(@NonNull Map<String, List<String>> requests,
+            boolean doDryRun, @PermissionControllerManager.Reason int reason,
+            @NonNull String callerPackageName, @NonNull RemoteCallback callback) {
+        Map<String, List<String>> revoked = onRevokeRuntimePermissions(requests,
+                doDryRun, reason, callerPackageName);
+
+        checkNotNull(revoked);
+        Bundle bundledizedRevoked = new Bundle();
+        for (Map.Entry<String, List<String>> appRevocation : revoked.entrySet()) {
+            checkNotNull(appRevocation.getKey());
+            checkCollectionElementsNotNull(appRevocation.getValue(), "permissions");
+
+            bundledizedRevoked.putStringArrayList(appRevocation.getKey(),
+                    new ArrayList<>(appRevocation.getValue()));
+        }
+
+        Bundle result = new Bundle();
+        result.putBundle(PermissionControllerManager.KEY_RESULT, bundledizedRevoked);
+        callback.sendResult(result);
+    }
+
+    private void getRuntimePermissionsBackup(@NonNull UserHandle user,
+            @NonNull ParcelFileDescriptor outFile) {
+        try (OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(outFile)) {
+            onGetRuntimePermissionsBackup(user, out);
+        } catch (IOException e) {
+            Log.e(LOG_TAG, "Could not open pipe to write backup tp", e);
+        }
+    }
+
+    private void getAppPermissions(@NonNull String packageName, @NonNull RemoteCallback callback) {
+        List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName);
+        if (permissions != null && !permissions.isEmpty()) {
+            Bundle result = new Bundle();
+            result.putParcelableList(PermissionControllerManager.KEY_RESULT, permissions);
+            callback.sendResult(result);
+        } else {
+            callback.sendResult(null);
+        }
+    }
+
+    private void countPermissionApps(@NonNull List<String> permissionNames,
+            boolean countOnlyGranted, boolean countSystem, @NonNull RemoteCallback callback) {
+        int numApps = onCountPermissionApps(permissionNames, countOnlyGranted, countSystem);
+
+        Bundle result = new Bundle();
+        result.putInt(PermissionControllerManager.KEY_RESULT, numApps);
+        callback.sendResult(result);
+    }
+
+    private void getPermissionUsages(boolean countSystem, long numMillis,
+            @NonNull RemoteCallback callback) {
+        List<RuntimePermissionUsageInfo> users =
+                onPermissionUsageResult(countSystem, numMillis);
+        if (users != null && !users.isEmpty()) {
+            Bundle result = new Bundle();
+            result.putParcelableList(PermissionControllerManager.KEY_RESULT, users);
+            callback.sendResult(result);
+        } else {
+            callback.sendResult(null);
+        }
+    }
+}
diff --git a/core/java/android/permission/RuntimePermissionPresenter.java b/core/java/android/permission/RuntimePermissionPresenter.java
deleted file mode 100644
index c607e3f..0000000
--- a/core/java/android/permission/RuntimePermissionPresenter.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.permission;
-
-import static android.permission.RuntimePermissionPresenterService.SERVICE_INTERFACE;
-
-import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteCallback;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
-import com.android.internal.infra.AbstractRemoteService;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * This class provides information about runtime permissions for a specific
- * app or all apps. This information is dedicated for presentation purposes
- * and does not necessarily reflect the individual permissions requested/
- * granted to an app as the platform may be grouping permissions to improve
- * presentation and help the user make an informed choice. For example, all
- * runtime permissions in the same permission group may be presented as a
- * single permission in the UI.
- *
- * @hide
- */
-public final class RuntimePermissionPresenter {
-    private static final String TAG = "RuntimePermPresenter";
-
-    /**
-     * The key for retrieving the result from the returned bundle.
-     *
-     * @hide
-     */
-    public static final String KEY_RESULT =
-            "android.permission.RuntimePermissionPresenter.key.result";
-
-    /**
-     * Listener for delivering the result of {@link #getAppPermissions}.
-     */
-    public interface OnGetAppPermissionResultCallback {
-        /**
-         * The result for {@link #getAppPermissions(String, OnGetAppPermissionResultCallback,
-         * Handler)}.
-         *
-         * @param permissions The permissions list.
-         */
-        void onGetAppPermissions(@NonNull List<RuntimePermissionPresentationInfo> permissions);
-    }
-
-    /**
-     * Listener for delivering the result of {@link #countPermissionApps}.
-     */
-    public interface OnCountPermissionAppsResultCallback {
-        /**
-         * The result for {@link #countPermissionApps(List, boolean, boolean,
-         * OnCountPermissionAppsResultCallback, Handler)}.
-         *
-         * @param numApps The number of apps that have one of the permissions
-         */
-        void onCountPermissionApps(int numApps);
-    }
-
-    private static final Object sLock = new Object();
-
-    @GuardedBy("sLock")
-    private static RuntimePermissionPresenter sInstance;
-
-    private final RemoteService mRemoteService;
-
-    /**
-     * Gets the singleton runtime permission presenter.
-     *
-     * @param context Context for accessing resources.
-     * @return The singleton instance.
-     */
-    public static RuntimePermissionPresenter getInstance(@NonNull Context context) {
-        synchronized (sLock) {
-            if (sInstance == null) {
-                sInstance = new RuntimePermissionPresenter(context.getApplicationContext());
-            }
-            return sInstance;
-        }
-    }
-
-    private RuntimePermissionPresenter(@NonNull Context context) {
-        Intent intent = new Intent(SERVICE_INTERFACE);
-        intent.setPackage(context.getPackageManager().getPermissionControllerPackageName());
-        ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0);
-
-        mRemoteService = new RemoteService(context,
-                serviceInfo.getComponentInfo().getComponentName());
-    }
-
-    /**
-     * Gets the runtime permissions for an app.
-     *
-     * @param packageName The package for which to query.
-     * @param callback Callback to receive the result.
-     * @param handler Handler on which to invoke the callback.
-     */
-    public void getAppPermissions(@NonNull String packageName,
-            @NonNull OnGetAppPermissionResultCallback callback, @Nullable Handler handler) {
-        checkNotNull(packageName);
-        checkNotNull(callback);
-
-        mRemoteService.scheduleRequest(new PendingGetAppPermissionRequest(mRemoteService,
-                packageName, callback, handler == null ? mRemoteService.getHandler() : handler));
-    }
-
-    /**
-     * Revoke the permission {@code permissionName} for app {@code packageName}
-     *
-     * @param packageName The package for which to revoke
-     * @param permissionName The permission to revoke
-     */
-    public void revokeRuntimePermission(@NonNull String packageName,
-            @NonNull String permissionName) {
-        checkNotNull(packageName);
-        checkNotNull(permissionName);
-
-        mRemoteService.scheduleAsyncRequest(new PendingRevokeAppPermissionRequest(packageName,
-                permissionName));
-    }
-
-    /**
-     * Count how many apps have one of a set of permissions.
-     *
-     * @param permissionNames The permissions the app might have
-     * @param countOnlyGranted Count an app only if the permission is granted to the app
-     * @param countSystem Also count system apps
-     * @param callback Callback to receive the result
-     * @param handler Handler on which to invoke the callback
-     */
-    public void countPermissionApps(@NonNull List<String> permissionNames,
-            boolean countOnlyGranted, boolean countSystem,
-            @NonNull OnCountPermissionAppsResultCallback callback, @Nullable Handler handler) {
-        checkCollectionElementsNotNull(permissionNames, "permissionNames");
-        checkNotNull(callback);
-
-        mRemoteService.scheduleRequest(new PendingCountPermissionAppsRequest(mRemoteService,
-                permissionNames, countOnlyGranted, countSystem, callback,
-                handler == null ? mRemoteService.getHandler() : handler));
-    }
-
-    /**
-     * A connection to the remote service
-     */
-    static final class RemoteService extends
-            AbstractMultiplePendingRequestsRemoteService<RemoteService,
-                    IRuntimePermissionPresenter>  {
-        private static final long UNBIND_TIMEOUT_MILLIS = 10000;
-        private static final long MESSAGE_TIMEOUT_MILLIS = 30000;
-
-        /**
-         * Create a connection to the remote service
-         *
-         * @param context A context to use
-         * @param componentName The component of the service to connect to
-         */
-        RemoteService(@NonNull Context context, @NonNull ComponentName componentName) {
-            super(context, SERVICE_INTERFACE, componentName, UserHandle.myUserId(),
-                    service -> Log.e(TAG, "RuntimePermPresenterService " + service + " died"),
-                    false, false, 1);
-        }
-
-        /**
-         * @return The default handler used by this service.
-         */
-        Handler getHandler() {
-            return mHandler;
-        }
-
-        @Override
-        protected @NonNull IRuntimePermissionPresenter getServiceInterface(
-                @NonNull IBinder binder) {
-            return IRuntimePermissionPresenter.Stub.asInterface(binder);
-        }
-
-        @Override
-        protected long getTimeoutIdleBindMillis() {
-            return UNBIND_TIMEOUT_MILLIS;
-        }
-
-        @Override
-        protected long getRemoteRequestMillis() {
-            return MESSAGE_TIMEOUT_MILLIS;
-        }
-
-        @Override
-        public void scheduleRequest(@NonNull PendingRequest<RemoteService,
-                IRuntimePermissionPresenter> pendingRequest) {
-            super.scheduleRequest(pendingRequest);
-        }
-
-        @Override
-        public void scheduleAsyncRequest(
-                @NonNull AsyncRequest<IRuntimePermissionPresenter> request) {
-            super.scheduleAsyncRequest(request);
-        }
-    }
-
-    /**
-     * Request for {@link #getAppPermissions}
-     */
-    private static final class PendingGetAppPermissionRequest extends
-            AbstractRemoteService.PendingRequest<RemoteService, IRuntimePermissionPresenter> {
-        private final @NonNull String mPackageName;
-        private final @NonNull OnGetAppPermissionResultCallback mCallback;
-
-        private final @NonNull RemoteCallback mRemoteCallback;
-
-        private PendingGetAppPermissionRequest(@NonNull RemoteService service,
-                @NonNull String packageName, @NonNull OnGetAppPermissionResultCallback callback,
-                @NonNull Handler handler) {
-            super(service);
-
-            mPackageName = packageName;
-            mCallback = callback;
-
-            mRemoteCallback = new RemoteCallback(result -> {
-                final List<RuntimePermissionPresentationInfo> reportedPermissions;
-                List<RuntimePermissionPresentationInfo> permissions = null;
-                if (result != null) {
-                    permissions = result.getParcelableArrayList(KEY_RESULT);
-                }
-                if (permissions == null) {
-                    permissions = Collections.emptyList();
-                }
-                reportedPermissions = permissions;
-
-                callback.onGetAppPermissions(reportedPermissions);
-
-                finish();
-            }, handler);
-        }
-
-        @Override
-        protected void onTimeout(RemoteService remoteService) {
-            mCallback.onGetAppPermissions(Collections.emptyList());
-        }
-
-        @Override
-        public void run() {
-            try {
-                getService().getServiceInterface().getAppPermissions(mPackageName, mRemoteCallback);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error getting app permission", e);
-            }
-        }
-    }
-
-    /**
-     * Request for {@link #revokeRuntimePermission}
-     */
-    private static final class PendingRevokeAppPermissionRequest
-            implements AbstractRemoteService.AsyncRequest<IRuntimePermissionPresenter> {
-        private final @NonNull String mPackageName;
-        private final @NonNull String mPermissionName;
-
-        private PendingRevokeAppPermissionRequest(@NonNull String packageName,
-                @NonNull String permissionName) {
-            mPackageName = packageName;
-            mPermissionName = permissionName;
-        }
-
-        @Override
-        public void run(IRuntimePermissionPresenter remoteInterface) {
-            try {
-                remoteInterface.revokeRuntimePermission(mPackageName, mPermissionName);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error revoking app permission", e);
-            }
-        }
-    }
-
-    /**
-     * Request for {@link #countPermissionApps}
-     */
-    private static final class PendingCountPermissionAppsRequest extends
-            AbstractRemoteService.PendingRequest<RemoteService, IRuntimePermissionPresenter> {
-        private final @NonNull List<String> mPermissionNames;
-        private final @NonNull OnCountPermissionAppsResultCallback mCallback;
-        private final boolean mCountOnlyGranted;
-        private final boolean mCountSystem;
-
-        private final @NonNull RemoteCallback mRemoteCallback;
-
-        private PendingCountPermissionAppsRequest(@NonNull RemoteService service,
-                @NonNull List<String> permissionNames, boolean countOnlyGranted,
-                boolean countSystem, @NonNull OnCountPermissionAppsResultCallback callback,
-                @NonNull Handler handler) {
-            super(service);
-
-            mPermissionNames = permissionNames;
-            mCountOnlyGranted = countOnlyGranted;
-            mCountSystem = countSystem;
-            mCallback = callback;
-
-            mRemoteCallback = new RemoteCallback(result -> {
-                final int numApps;
-                if (result != null) {
-                    numApps = result.getInt(KEY_RESULT);
-                } else {
-                    numApps = 0;
-                }
-
-                callback.onCountPermissionApps(numApps);
-
-                finish();
-            }, handler);
-        }
-
-        @Override
-        protected void onTimeout(RemoteService remoteService) {
-            mCallback.onCountPermissionApps(0);
-        }
-
-        @Override
-        public void run() {
-            try {
-                getService().getServiceInterface().countPermissionApps(mPermissionNames,
-                        mCountOnlyGranted, mCountSystem, mRemoteCallback);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error counting permission apps", e);
-            }
-        }
-    }
-}
diff --git a/core/java/android/permission/RuntimePermissionPresenterService.java b/core/java/android/permission/RuntimePermissionPresenterService.java
deleted file mode 100644
index 81ec7be..0000000
--- a/core/java/android/permission/RuntimePermissionPresenterService.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.permission;
-
-import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteCallback;
-
-import java.util.List;
-
-/**
- * This service presents information regarding runtime permissions that is
- * used for presenting them in the UI. Runtime permissions are presented as
- * a single permission in the UI but may be composed of several individual
- * permissions.
- *
- * @see RuntimePermissionPresenter
- * @see RuntimePermissionPresentationInfo
- *
- * @hide
- */
-@SystemApi
-public abstract class RuntimePermissionPresenterService extends Service {
-
-    /**
-     * The {@link Intent} action that must be declared as handled by a service
-     * in its manifest for the system to recognize it as a runtime permission
-     * presenter service.
-     */
-    public static final String SERVICE_INTERFACE =
-            "android.permission.RuntimePermissionPresenterService";
-
-    // No need for locking - always set first and never modified
-    private Handler mHandler;
-
-    @Override
-    public final void attachBaseContext(Context base) {
-        super.attachBaseContext(base);
-        mHandler = new Handler(base.getMainLooper());
-    }
-
-    /**
-     * Gets the runtime permissions for an app.
-     *
-     * @param packageName The package for which to query.
-     *
-     * @return descriptions of the runtime permissions of the app
-     */
-    public abstract @NonNull List<RuntimePermissionPresentationInfo> onGetAppPermissions(
-            @NonNull String packageName);
-
-    /**
-     * Revokes the permission {@code permissionName} for app {@code packageName}
-     *
-     * @param packageName The package for which to revoke
-     * @param permissionName The permission to revoke
-     */
-    public abstract void onRevokeRuntimePermission(@NonNull String packageName,
-            @NonNull String permissionName);
-
-    /**
-     * Count how many apps have one of a set of permissions.
-     *
-     * @param permissionNames The permissions the app might have
-     * @param countOnlyGranted Count an app only if the permission is granted to the app
-     * @param countSystem Also count system apps
-     *
-     * @return the number of apps that have one of the permissions
-     */
-    public abstract int onCountPermissionApps(@NonNull List<String> permissionNames,
-            boolean countOnlyGranted, boolean countSystem);
-
-    @Override
-    public final IBinder onBind(Intent intent) {
-        return new IRuntimePermissionPresenter.Stub() {
-            @Override
-            public void getAppPermissions(String packageName, RemoteCallback callback) {
-                checkNotNull(packageName, "packageName");
-                checkNotNull(callback, "callback");
-
-                mHandler.sendMessage(
-                        obtainMessage(
-                                RuntimePermissionPresenterService::getAppPermissions,
-                                RuntimePermissionPresenterService.this, packageName, callback));
-            }
-
-            @Override
-            public void revokeRuntimePermission(String packageName, String permissionName) {
-                checkNotNull(packageName, "packageName");
-                checkNotNull(permissionName, "permissionName");
-
-                mHandler.sendMessage(
-                        obtainMessage(
-                                RuntimePermissionPresenterService::onRevokeRuntimePermission,
-                                RuntimePermissionPresenterService.this, packageName,
-                                permissionName));
-            }
-
-            @Override
-            public void countPermissionApps(List<String> permissionNames, boolean countOnlyGranted,
-                    boolean countSystem, RemoteCallback callback) {
-                checkCollectionElementsNotNull(permissionNames, "permissionNames");
-                checkNotNull(callback, "callback");
-
-                mHandler.sendMessage(
-                        obtainMessage(
-                                RuntimePermissionPresenterService::countPermissionApps,
-                                RuntimePermissionPresenterService.this, permissionNames,
-                                countOnlyGranted, countSystem, callback));
-            }
-        };
-    }
-
-    private void getAppPermissions(@NonNull String packageName, @NonNull RemoteCallback callback) {
-        List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName);
-        if (permissions != null && !permissions.isEmpty()) {
-            Bundle result = new Bundle();
-            result.putParcelableList(RuntimePermissionPresenter.KEY_RESULT, permissions);
-            callback.sendResult(result);
-        } else {
-            callback.sendResult(null);
-        }
-    }
-
-    private void countPermissionApps(@NonNull List<String> permissionNames,
-            boolean countOnlyGranted, boolean countSystem, @NonNull RemoteCallback callback) {
-        int numApps = onCountPermissionApps(permissionNames, countOnlyGranted, countSystem);
-
-        Bundle result = new Bundle();
-        result.putInt(RuntimePermissionPresenter.KEY_RESULT, numApps);
-        callback.sendResult(result);
-    }
-}
diff --git a/core/java/android/permission/RuntimePermissionUsageInfo.aidl b/core/java/android/permission/RuntimePermissionUsageInfo.aidl
new file mode 100644
index 0000000..88820dd
--- /dev/null
+++ b/core/java/android/permission/RuntimePermissionUsageInfo.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission;
+
+parcelable RuntimePermissionUsageInfo;
\ No newline at end of file
diff --git a/core/java/android/permission/RuntimePermissionUsageInfo.java b/core/java/android/permission/RuntimePermissionUsageInfo.java
new file mode 100644
index 0000000..af1a1be
--- /dev/null
+++ b/core/java/android/permission/RuntimePermissionUsageInfo.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission;
+
+import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains information about how a runtime permission
+ * is used. A single runtime permission presented to the user may
+ * correspond to multiple platform defined permissions, e.g. the
+ * location permission may control both the coarse and fine platform
+ * permissions.
+ *
+ * @hide
+ */
+@SystemApi
+public final class RuntimePermissionUsageInfo implements Parcelable {
+    private final @NonNull CharSequence mName;
+    private final int mNumUsers;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param name The permission group name.
+     * @param numUsers The number of apps that have used this permission.
+     */
+    public RuntimePermissionUsageInfo(@NonNull CharSequence name, int numUsers) {
+        checkNotNull(name);
+        checkArgumentNonnegative(numUsers);
+
+        mName = name;
+        mNumUsers = numUsers;
+    }
+
+    private RuntimePermissionUsageInfo(Parcel parcel) {
+        this(parcel.readCharSequence(), parcel.readInt());
+    }
+
+    /**
+     * @return The number of apps that accessed this permission
+     */
+    public int getAppAccessCount() {
+        return mNumUsers;
+    }
+
+    /**
+     * Gets the permission group name.
+     *
+     * @return The name.
+     */
+    public @NonNull CharSequence getName() {
+        return mName;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeCharSequence(mName);
+        parcel.writeInt(mNumUsers);
+    }
+
+    public static final Creator<RuntimePermissionUsageInfo> CREATOR =
+            new Creator<RuntimePermissionUsageInfo>() {
+        public RuntimePermissionUsageInfo createFromParcel(Parcel source) {
+            return new RuntimePermissionUsageInfo(source);
+        }
+
+        public RuntimePermissionUsageInfo[] newArray(int size) {
+            return new RuntimePermissionUsageInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/permission/TEST_MAPPING b/core/java/android/permission/TEST_MAPPING
new file mode 100644
index 0000000..ba9f36a
--- /dev/null
+++ b/core/java/android/permission/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+    "presubmit": [
+        {
+            "name": "CtsPermissionTestCases",
+            "options": [
+                {
+                    "include-filter": "android.permission.cts.PermissionControllerTest"
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
index 2b3f0f5..8d568c8 100644
--- a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
+++ b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
@@ -30,6 +30,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteCallback;
+import android.permission.PermissionControllerService;
 
 import java.util.List;
 
@@ -43,7 +44,7 @@
  *
  * @hide
  *
- * @deprecated use {@link android.permission.RuntimePermissionPresenterService} instead
+ * @deprecated use {@link PermissionControllerService} instead
  */
 @Deprecated
 @SystemApi
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 4e207ed..6ccd296 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -16,9 +16,13 @@
 
 package android.provider;
 
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
+
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.app.ActivityThread;
 import android.content.ContentResolver;
@@ -48,6 +52,107 @@
      */
     public static final Uri CONTENT_URI = Uri.parse("content://" + Settings.AUTHORITY + "/config");
 
+    /**
+     * Namespace for all Game Driver features.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_GAME_DRIVER = "game_driver";
+
+    /**
+     * Namespace for autofill feature that provides suggestions across all apps when
+     * the user interacts with input fields.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_AUTOFILL = "autofill";
+
+    /**
+     * Namespace for content capture feature used by on-device machine intelligence
+     * to provide suggestions in a privacy-safe manner.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
+
+    /**
+     * Namespace for all input-related features that are used at the native level.
+     * These features are applied at reboot.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
+
+    /**
+     * Namespace for all netd related features.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_NETD_NATIVE = "netd_native";
+
+    /**
+     * Namespace for features related to the ExtServices Notification Assistant.
+     * These features are applied immediately.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_NOTIFICATION_ASSISTANT = "notification_assistant";
+
+    /**
+     * Namespace for attention-based features provided by on-device machine intelligence.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface IntelligenceAttention {
+        String NAMESPACE = "intelligence_attention";
+        /**
+         * If {@code true}, enables the attention check.
+         */
+        String PROPERTY_ATTENTION_CHECK_ENABLED = "attention_check_enabled";
+        /**
+         * Settings for performing the attention check.
+         */
+        String PROPERTY_ATTENTION_CHECK_SETTINGS = "attention_check_settings";
+    }
+
+    /**
+     * Telephony related properties definitions.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface Telephony {
+        String NAMESPACE = "telephony";
+        /**
+         * Whether to apply ramping ringer on incoming phone calls.
+         */
+        String PROPERTY_ENABLE_RAMPING_RINGER = "enable_ramping_ringer";
+        /**
+         * Ringer ramping time in milliseconds.
+         */
+        String PROPERTY_RAMPING_RINGER_DURATION = "ramping_duration";
+    }
+
+    /**
+     * Namespace for Full Stack Integrity to run privileged apps only in JIT mode. The flag applies
+     * at process start, so reboot is a way to bring the device to a clean state.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface FsiBoot {
+        String NAMESPACE = "fsi_boot";
+        String OOB_ENABLED = "oob_enabled";
+        String OOB_WHITELIST = "oob_whitelist";
+    }
+
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
     private static Map<OnPropertyChangedListener, Pair<String, Executor>> sListeners =
@@ -63,12 +168,12 @@
      * Look up the value of a property for a particular namespace.
      *
      * @param namespace The namespace containing the property to look up.
-     * @param name The name of the property to look up.
+     * @param name      The name of the property to look up.
      * @return the corresponding value, or null if not present.
-     *
      * @hide
      */
     @SystemApi
+    @RequiresPermission(READ_DEVICE_CONFIG)
     public static String getProperty(String namespace, String name) {
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
         String compositeName = createCompositeName(namespace, name);
@@ -86,16 +191,16 @@
      * All properties stored for a particular scope can be reverted to their default values
      * by passing the namespace to {@link #resetToDefaults(int, String)}.
      *
-     * @param namespace The namespace containing the property to create or update.
-     * @param name The name of the property to create or update.
-     * @param value The value to store for the property.
+     * @param namespace   The namespace containing the property to create or update.
+     * @param name        The name of the property to create or update.
+     * @param value       The value to store for the property.
      * @param makeDefault Whether to make the new value the default one.
      * @return True if the value was set, false if the storage implementation throws errors.
-     * @see #resetToDefaults(int, String).
-     *
      * @hide
+     * @see #resetToDefaults(int, String).
      */
     @SystemApi
+    @RequiresPermission(WRITE_DEVICE_CONFIG)
     public static boolean setProperty(
             String namespace, String name, String value, boolean makeDefault) {
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
@@ -111,11 +216,11 @@
      *
      * @param resetMode The reset mode to use.
      * @param namespace Optionally, the specific namespace which resets will be limited to.
-     * @see #setProperty(String, String, String, boolean)
-     *
      * @hide
+     * @see #setProperty(String, String, String, boolean)
      */
     @SystemApi
+    @RequiresPermission(WRITE_DEVICE_CONFIG)
     public static void resetToDefaults(@ResetMode int resetMode, @Nullable String namespace) {
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
         Settings.Config.resetToDefaults(contentResolver, resetMode, namespace);
@@ -129,18 +234,19 @@
      * will replace the old namespace and executor. Remove the listener entirely by calling
      * {@link #removeOnPropertyChangedListener(OnPropertyChangedListener)}.
      *
-     * @param namespace The namespace containing properties to monitor.
-     * @param executor The executor which will be used to run callbacks.
+     * @param namespace                 The namespace containing properties to monitor.
+     * @param executor                  The executor which will be used to run callbacks.
      * @param onPropertyChangedListener The listener to add.
-     * @see #removeOnPropertyChangedListener(OnPropertyChangedListener)
-     *
      * @hide
+     * @see #removeOnPropertyChangedListener(OnPropertyChangedListener)
      */
     @SystemApi
+    @RequiresPermission(READ_DEVICE_CONFIG)
     public static void addOnPropertyChangedListener(
             @NonNull String namespace,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OnPropertyChangedListener onPropertyChangedListener) {
+        // TODO enforce READ_DEVICE_CONFIG permission
         synchronized (sLock) {
             Pair<String, Executor> oldNamespace = sListeners.get(onPropertyChangedListener);
             if (oldNamespace == null) {
@@ -164,9 +270,8 @@
      * property changes.
      *
      * @param onPropertyChangedListener The listener to remove.
-     * @see #addOnPropertyChangedListener(String, Executor, OnPropertyChangedListener)
-     *
      * @hide
+     * @see #addOnPropertyChangedListener(String, Executor, OnPropertyChangedListener)
      */
     @SystemApi
     public static void removeOnPropertyChangedListener(
@@ -267,8 +372,8 @@
          * Called when a property has changed.
          *
          * @param namespace The namespace containing the property which has changed.
-         * @param name The name of the property which has changed.
-         * @param value The new value of the property which has changed.
+         * @param name      The name of the property which has changed.
+         * @param value     The new value of the property which has changed.
          */
         void onPropertyChanged(String namespace, String name, String value);
     }
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index a323ed1..5f1c560 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -16,7 +16,6 @@
 
 package android.provider;
 
-import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
 import static com.android.internal.util.Preconditions.checkCollectionNotEmpty;
 
@@ -50,6 +49,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
 import dalvik.system.VMRuntime;
 
 import java.io.File;
@@ -640,6 +641,28 @@
         public static final String COLUMN_MIME_TYPES = "mime_types";
 
         /**
+         * Query arguments supported by this root. This column is optional
+         * and related to {@link #COLUMN_FLAGS} and {@link #FLAG_SUPPORTS_SEARCH}.
+         * If the flags include {@link #FLAG_SUPPORTS_SEARCH}, and the column is
+         * {@code null}, the root is assumed to support {@link #QUERY_ARG_DISPLAY_NAME}
+         * search of {@link Document#COLUMN_DISPLAY_NAME}. Multiple query arguments
+         * can be separated by a newline. For example, a root supporting
+         * {@link #QUERY_ARG_MIME_TYPES} and {@link #QUERY_ARG_DISPLAY_NAME} might
+         * return "android:query-arg-mime-types\nandroid:query-arg-display-name".
+         * <p>
+         * Type: STRING
+         * @see #COLUMN_FLAGS
+         * @see #FLAG_SUPPORTS_SEARCH
+         * @see #QUERY_ARG_DISPLAY_NAME
+         * @see #QUERY_ARG_FILE_SIZE_OVER
+         * @see #QUERY_ARG_LAST_MODIFIED_AFTER
+         * @see #QUERY_ARG_MIME_TYPES
+         * @see DocumentsProvider#querySearchDocuments(String, String[],
+         *      Bundle)
+         */
+        public static final String COLUMN_QUERY_ARGS = "query_args";
+
+        /**
          * MIME type for a root.
          */
         public static final String MIME_TYPE_ITEM = "vnd.android.document/root";
@@ -680,6 +703,8 @@
          *      String)
          * @see DocumentsProvider#querySearchDocuments(String, String,
          *      String[])
+         * @see DocumentsProvider#querySearchDocuments(String, String[],
+         *      Bundle)
          */
         public static final int FLAG_SUPPORTS_SEARCH = 1 << 3;
 
@@ -1109,11 +1134,13 @@
     }
 
     /**
-     * Test if the given URI represents roots backed by {@link DocumentsProvider}.
+     * Test if the given URI represents all roots of the authority
+     * backed by {@link DocumentsProvider}.
      *
      * @see #buildRootsUri(String)
      */
-    public static boolean isRootsUri(Context context, @Nullable Uri uri) {
+    public static boolean isRootsUri(@NonNull Context context, @Nullable Uri uri) {
+        Preconditions.checkNotNull(context, "context can not be null");
         return isRootUri(context, uri, 1 /* pathSize */);
     }
 
@@ -1122,7 +1149,8 @@
      *
      * @see #buildRootUri(String, String)
      */
-    public static boolean isRootUri(Context context, @Nullable Uri uri) {
+    public static boolean isRootUri(@NonNull Context context, @Nullable Uri uri) {
+        Preconditions.checkNotNull(context, "context can not be null");
         return isRootUri(context, uri, 2 /* pathSize */);
     }
 
@@ -1215,6 +1243,7 @@
      * {@hide}
      */
     public static String getSearchDocumentsQuery(@NonNull Bundle bundle) {
+        Preconditions.checkNotNull(bundle, "bundle can not be null");
         return bundle.getString(QUERY_ARG_DISPLAY_NAME, "" /* defaultValue */);
     }
 
@@ -1315,8 +1344,12 @@
      * @return if given document is a descendant of the given parent.
      * @see Root#FLAG_SUPPORTS_IS_CHILD
      */
-    public static boolean isChildDocument(ContentInterface content, Uri parentDocumentUri,
-            Uri childDocumentUri) throws FileNotFoundException {
+    public static boolean isChildDocument(@NonNull ContentInterface content,
+            @NonNull Uri parentDocumentUri, @NonNull Uri childDocumentUri)
+            throws FileNotFoundException {
+        Preconditions.checkNotNull(content, "content can not be null");
+        Preconditions.checkNotNull(parentDocumentUri, "parentDocumentUri can not be null");
+        Preconditions.checkNotNull(childDocumentUri, "childDocumentUri can not be null");
         try {
             final Bundle in = new Bundle();
             in.putParcelable(DocumentsContract.EXTRA_URI, parentDocumentUri);
@@ -1325,7 +1358,7 @@
             final Bundle out = content.call(parentDocumentUri.getAuthority(),
                     METHOD_IS_CHILD_DOCUMENT, null, in);
             if (out == null) {
-                throw new RemoteException("Failed to get a reponse from isChildDocument query.");
+                throw new RemoteException("Failed to get a response from isChildDocument query.");
             }
             if (!out.containsKey(DocumentsContract.EXTRA_RESULT)) {
                 throw new RemoteException("Response did not include result field..");
@@ -1559,8 +1592,10 @@
      * @param documentUri a Document URI
      * @return a Bundle of Bundles.
      */
-    public static Bundle getDocumentMetadata(ContentInterface content, Uri documentUri)
-            throws FileNotFoundException {
+    public static @Nullable Bundle getDocumentMetadata(@NonNull ContentInterface content,
+            @NonNull Uri documentUri) throws FileNotFoundException {
+        Preconditions.checkNotNull(content, "content can not be null");
+        Preconditions.checkNotNull(documentUri, "documentUri can not be null");
         try {
             final Bundle in = new Bundle();
             in.putParcelable(EXTRA_URI, documentUri);
@@ -1595,8 +1630,6 @@
      */
     public static Path findDocumentPath(ContentInterface content, Uri treeUri)
             throws FileNotFoundException {
-        checkArgument(isTreeUri(treeUri), treeUri + " is not a tree uri.");
-
         try {
             final Bundle in = new Bundle();
             in.putParcelable(DocumentsContract.EXTRA_URI, treeUri);
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 70c84f8..9b9e2de 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -37,6 +37,7 @@
 
 import android.Manifest;
 import android.annotation.CallSuper;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AuthenticationRequiredException;
 import android.content.ClipDescription;
@@ -63,6 +64,8 @@
 import android.provider.DocumentsContract.Root;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
 import libcore.io.IoUtils;
 
 import java.io.FileNotFoundException;
@@ -687,14 +690,17 @@
      *         extras {@link Bundle} when any QUERY_ARG_* value was honored
      *         during the preparation of the results.
      *
+     * @see Root#COLUMN_QUERY_ARGS
      * @see ContentResolver#EXTRA_HONORED_ARGS
      * @see DocumentsContract#EXTRA_LOADING
      * @see DocumentsContract#EXTRA_INFO
      * @see DocumentsContract#EXTRA_ERROR
      */
     @SuppressWarnings("unused")
-    public Cursor querySearchDocuments(String rootId, String[] projection, Bundle queryArgs)
-            throws FileNotFoundException {
+    public Cursor querySearchDocuments(@NonNull String rootId, @Nullable String[] projection,
+            @NonNull Bundle queryArgs) throws FileNotFoundException {
+        Preconditions.checkNotNull(rootId, "rootId can not be null");
+        Preconditions.checkNotNull(queryArgs, "queryArgs can not be null");
         return querySearchDocuments(rootId, DocumentsContract.getSearchDocumentsQuery(queryArgs),
                 projection);
     }
@@ -732,7 +738,7 @@
      * @return a Bundle of Bundles.
      * @see DocumentsContract#getDocumentMetadata(ContentResolver, Uri)
      */
-    public @Nullable Bundle getDocumentMetadata(String documentId)
+    public @Nullable Bundle getDocumentMetadata(@NonNull String documentId)
             throws FileNotFoundException {
         throw new UnsupportedOperationException("Metadata not supported");
     }
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index e5fd29c..b348da4 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -409,6 +409,15 @@
         public static final String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
 
         /**
+         * Similar to {@link #COLUMN_MEDIAPROVIDER_URI}, except this cannot be updated/queried
+         * by apps and will be the source of truth when updating/deleting download entries in
+         * MediaProvider database.
+         *
+         * <P>Type: TEXT</P>
+         */
+        public static final String COLUMN_MEDIASTORE_URI = "mediastore_uri";
+
+        /**
          * The column that is used to remember whether the media scanner was invoked.
          * It can take the values: null or 0(not scanned), 1(scanned), 2 (not scannable).
          * <P>Type: TEXT</P>
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index 8e37559..e931826 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -34,6 +34,7 @@
 import android.graphics.fonts.FontStyle;
 import android.graphics.fonts.FontVariationAxis;
 import android.net.Uri;
+import android.os.Build.VERSION_CODES;
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -651,7 +652,16 @@
                 if (familyBuilder == null) {
                     familyBuilder = new FontFamily.Builder(font);
                 } else {
-                    familyBuilder.addFont(font);
+                    try {
+                        familyBuilder.addFont(font);
+                    } catch (IllegalArgumentException e) {
+                        if (context.getApplicationInfo().targetSdkVersion <= VERSION_CODES.P) {
+                            // Surpress the IllegalArgumentException for keeping the backward
+                            // compatibility.
+                            continue;
+                        }
+                        throw e;
+                    }
                 }
             } catch (IOException e) {
                 continue;
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 457453f..f5c442f 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -17,6 +17,7 @@
 package android.provider;
 
 import android.annotation.BytesLong;
+import android.annotation.DurationMillisLong;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -45,6 +46,7 @@
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.os.OperationCanceledException;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -55,6 +57,7 @@
 import android.os.storage.VolumeInfo;
 import android.service.media.CameraPrewarmService;
 import android.text.TextUtils;
+import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
@@ -67,6 +70,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -84,8 +89,20 @@
     /** A content:// style uri to the authority for the media provider */
     public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
 
-    private static final String VOLUME_INTERNAL = "internal";
-    private static final String VOLUME_EXTERNAL = "external";
+    /**
+     * Volume name used for content on "internal" storage of device. This
+     * volume contains media distributed with the device, such as built-in
+     * ringtones and wallpapers.
+     */
+    public static final String VOLUME_INTERNAL = "internal";
+
+    /**
+     * Volume name used for content on "external" storage of device. This only
+     * includes media on the primary shared storage device; the contents of any
+     * secondary storage devices can be obtained using
+     * {@link #getAllVolumeNames(Context)}.
+     */
+    public static final String VOLUME_EXTERNAL = "external";
 
     /**
      * The method name used by the media scanner and mtp to tell the media provider to
@@ -131,6 +148,8 @@
     /** {@hide} */
     public static final String PARAM_INCLUDE_PENDING = "includePending";
     /** {@hide} */
+    public static final String PARAM_INCLUDE_TRASHED = "includeTrashed";
+    /** {@hide} */
     public static final String PARAM_PROGRESS = "progress";
     /** {@hide} */
     public static final String PARAM_REQUIRE_ORIGINAL = "requireOriginal";
@@ -485,12 +504,29 @@
      * By default no pending items are returned.
      *
      * @see MediaColumns#IS_PENDING
+     * @see MediaStore#setIncludePending(Uri)
+     * @see MediaStore#createPending(Context, PendingParams)
      */
     public static @NonNull Uri setIncludePending(@NonNull Uri uri) {
         return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_PENDING, "1").build();
     }
 
     /**
+     * Update the given {@link Uri} to also include any trashed media items from
+     * calls such as
+     * {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}.
+     * By default no trashed items are returned.
+     *
+     * @see MediaColumns#IS_TRASHED
+     * @see MediaStore#setIncludeTrashed(Uri)
+     * @see MediaStore#trash(Context, Uri)
+     * @see MediaStore#untrash(Context, Uri)
+     */
+    public static @NonNull Uri setIncludeTrashed(@NonNull Uri uri) {
+        return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_TRASHED, "1").build();
+    }
+
+    /**
      * Update the given {@link Uri} to indicate that the caller requires the
      * original file contents when calling
      * {@link ContentResolver#openFileDescriptor(Uri, String)}.
@@ -516,6 +552,9 @@
      *
      * @return token which can be passed to {@link #openPending(Context, Uri)}
      *         to work with this pending item.
+     * @see MediaColumns#IS_PENDING
+     * @see MediaStore#setIncludePending(Uri)
+     * @see MediaStore#createPending(Context, PendingParams)
      */
     public static @NonNull Uri createPending(@NonNull Context context,
             @NonNull PendingParams params) {
@@ -572,6 +611,8 @@
             this.insertValues.put(MediaColumns.DATE_ADDED, now);
             this.insertValues.put(MediaColumns.DATE_MODIFIED, now);
             this.insertValues.put(MediaColumns.IS_PENDING, 1);
+            this.insertValues.put(MediaColumns.DATE_EXPIRES,
+                    (System.currentTimeMillis() + DateUtils.DAY_IN_MILLIS) / 1000);
         }
 
         /**
@@ -696,6 +737,7 @@
         public @NonNull Uri publish() {
             final ContentValues values = new ContentValues();
             values.put(MediaColumns.IS_PENDING, 0);
+            values.putNull(MediaColumns.DATE_EXPIRES);
             mContext.getContentResolver().update(mUri, values, null, null);
             return mUri;
         }
@@ -717,6 +759,67 @@
     }
 
     /**
+     * Mark the given item as being "trashed", meaning it should be deleted at
+     * some point in the future. This is a more gentle operation than simply
+     * calling {@link ContentResolver#delete(Uri, String, String[])}, which
+     * would take effect immediately.
+     * <p>
+     * This method preserves trashed items for at least 48 hours before erasing
+     * them, giving the user a chance to untrash the item.
+     *
+     * @see MediaColumns#IS_TRASHED
+     * @see MediaStore#setIncludeTrashed(Uri)
+     * @see MediaStore#trash(Context, Uri)
+     * @see MediaStore#untrash(Context, Uri)
+     */
+    public static void trash(@NonNull Context context, @NonNull Uri uri) {
+        trash(context, uri, 48 * DateUtils.HOUR_IN_MILLIS);
+    }
+
+    /**
+     * Mark the given item as being "trashed", meaning it should be deleted at
+     * some point in the future. This is a more gentle operation than simply
+     * calling {@link ContentResolver#delete(Uri, String, String[])}, which
+     * would take effect immediately.
+     * <p>
+     * This method preserves trashed items for at least the given timeout before
+     * erasing them, giving the user a chance to untrash the item.
+     *
+     * @see MediaColumns#IS_TRASHED
+     * @see MediaStore#setIncludeTrashed(Uri)
+     * @see MediaStore#trash(Context, Uri)
+     * @see MediaStore#untrash(Context, Uri)
+     */
+    public static void trash(@NonNull Context context, @NonNull Uri uri,
+            @DurationMillisLong long timeoutMillis) {
+        if (timeoutMillis < 0) {
+            throw new IllegalArgumentException();
+        }
+
+        final ContentValues values = new ContentValues();
+        values.put(MediaColumns.IS_TRASHED, 1);
+        values.put(MediaColumns.DATE_EXPIRES,
+                (System.currentTimeMillis() + timeoutMillis) / 1000);
+        context.getContentResolver().update(uri, values, null, null);
+    }
+
+    /**
+     * Mark the given item as being "untrashed", meaning it should no longer be
+     * deleted as previously requested through {@link #trash(Context, Uri)}.
+     *
+     * @see MediaColumns#IS_TRASHED
+     * @see MediaStore#setIncludeTrashed(Uri)
+     * @see MediaStore#trash(Context, Uri)
+     * @see MediaStore#untrash(Context, Uri)
+     */
+    public static void untrash(@NonNull Context context, @NonNull Uri uri) {
+        final ContentValues values = new ContentValues();
+        values.put(MediaColumns.IS_TRASHED, 0);
+        values.putNull(MediaColumns.DATE_EXPIRES);
+        context.getContentResolver().update(uri, values, null, null);
+    }
+
+    /**
      * Common fields for most MediaProvider tables
      */
     public interface MediaColumns extends BaseColumns {
@@ -821,12 +924,34 @@
          * <p>
          * Type: BOOLEAN
          *
+         * @see MediaColumns#IS_PENDING
+         * @see MediaStore#setIncludePending(Uri)
          * @see MediaStore#createPending(Context, PendingParams)
-         * @see MediaStore#PARAM_INCLUDE_PENDING
          */
         public static final String IS_PENDING = "is_pending";
 
         /**
+         * Flag indicating if a media item is trashed.
+         * <p>
+         * Type: BOOLEAN
+         *
+         * @see MediaColumns#IS_TRASHED
+         * @see MediaStore#setIncludeTrashed(Uri)
+         * @see MediaStore#trash(Context, Uri)
+         * @see MediaStore#untrash(Context, Uri)
+         */
+        public static final String IS_TRASHED = "is_trashed";
+
+        /**
+         * The time the file should be considered expired. Units are seconds
+         * since 1970. Typically only meaningful in the context of
+         * {@link #IS_PENDING} or {@link #IS_TRASHED}.
+         * <p>
+         * Type: INTEGER
+         */
+        public static final String DATE_EXPIRES = "date_expires";
+
+        /**
          * The width of the image/video in pixels.
          */
         public static final String WIDTH = "width";
@@ -915,6 +1040,11 @@
             return AUTHORITY_URI.buildUpon().appendPath(volumeName).appendPath("dir").build();
         }
 
+        /** @hide */
+        public static final Uri getContentUriForPath(String path) {
+            return getContentUri(getVolumeName(new File(path)));
+        }
+
         /**
          * Fields for master table for all media files.
          * Table also contains MediaColumns._ID, DATA, SIZE and DATE_MODIFIED.
@@ -1021,6 +1151,13 @@
          * Type: TEXT
          */
         String REFERER_URI = "referer_uri";
+
+        /**
+         * The description of the download.
+         * <p>
+         * Type: Text
+         */
+        String DESCRIPTION = "description";
     }
 
     /**
@@ -1075,7 +1212,7 @@
 
         /** @hide */
         public static Uri getContentUriForPath(@NonNull String path) {
-            return getContentUri(getVolumeNameForPath(path));
+            return getContentUri(getVolumeName(new File(path)));
         }
 
         /** @hide */
@@ -1089,16 +1226,20 @@
         }
     }
 
-    private static String getVolumeNameForPath(@NonNull String path) {
-        final StorageManager sm = AppGlobals.getInitialApplication()
-                .getSystemService(StorageManager.class);
-        final StorageVolume sv = sm.getStorageVolume(new File(path));
-        if (sv != null) {
-            if (sv.isPrimary()) {
-                return VOLUME_EXTERNAL;
-            } else {
-                return sv.getUuid();
+    /** {@hide} */
+    public static @NonNull String getVolumeName(@NonNull File path) {
+        if (FileUtils.contains(Environment.getStorageDirectory(), path)) {
+            final StorageManager sm = AppGlobals.getInitialApplication()
+                    .getSystemService(StorageManager.class);
+            final StorageVolume sv = sm.getStorageVolume(path);
+            if (sv != null) {
+                if (sv.isPrimary()) {
+                    return VOLUME_EXTERNAL;
+                } else {
+                    return checkArgumentVolumeName(sv.getNormalizedUuid());
+                }
             }
+            throw new IllegalStateException("Unknown volume at " + path);
         } else {
             return VOLUME_INTERNAL;
         }
@@ -1251,18 +1392,32 @@
             public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
 
             /**
-             * The bucket id of the image. This is a read-only property that
-             * is automatically computed from the DATA column.
-             * <P>Type: TEXT</P>
+             * The primary bucket ID of this media item. This can be useful to
+             * present the user a first-level clustering of related media items.
+             * This is a read-only column that is automatically computed.
+             * <p>
+             * Type: INTEGER
              */
             public static final String BUCKET_ID = "bucket_id";
 
             /**
-             * The bucket display name of the image. This is a read-only property that
-             * is automatically computed from the DATA column.
-             * <P>Type: TEXT</P>
+             * The primary bucket display name of this media item. This can be
+             * useful to present the user a first-level clustering of related
+             * media items. This is a read-only column that is automatically
+             * computed.
+             * <p>
+             * Type: TEXT
              */
             public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
+
+            /**
+             * The secondary bucket ID of this media item. This can be useful to
+             * present the user a second-level clustering of related media
+             * items. This is a read-only column that is automatically computed.
+             * <p>
+             * Type: INTEGER
+             */
+            public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id";
         }
 
         public static final class Media implements ImageColumns {
@@ -1338,7 +1493,7 @@
             public static final String insertImage(ContentResolver cr, Bitmap source,
                                                    String title, String description) {
                 ContentValues values = new ContentValues();
-                values.put(Images.Media.TITLE, title);
+                values.put(Images.Media.DISPLAY_NAME, title);
                 values.put(Images.Media.DESCRIPTION, description);
                 values.put(Images.Media.MIME_TYPE, "image/jpeg");
 
@@ -1421,7 +1576,13 @@
         /**
          * This class provides utility methods to obtain thumbnails for various
          * {@link Images} items.
+         *
+         * @deprecated Callers should migrate to using
+         *             {@link ContentResolver#loadThumbnail}, since it offers
+         *             richer control over requested thumbnail sizes and
+         *             cancellation behavior.
          */
+        @Deprecated
         public static class Thumbnails implements BaseColumns {
             public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
                 return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
@@ -1855,7 +2016,7 @@
              *             access this path.
              */
             public static @Nullable Uri getContentUriForPath(@NonNull String path) {
-                return getContentUri(getVolumeNameForPath(path));
+                return getContentUri(getVolumeName(new File(path)));
             }
 
             /**
@@ -2500,20 +2661,34 @@
             public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
 
             /**
-             * The bucket id of the video. This is a read-only property that
-             * is automatically computed from the DATA column.
-             * <P>Type: TEXT</P>
+             * The primary bucket ID of this media item. This can be useful to
+             * present the user a first-level clustering of related media items.
+             * This is a read-only column that is automatically computed.
+             * <p>
+             * Type: INTEGER
              */
             public static final String BUCKET_ID = "bucket_id";
 
             /**
-             * The bucket display name of the video. This is a read-only property that
-             * is automatically computed from the DATA column.
-             * <P>Type: TEXT</P>
+             * The primary bucket display name of this media item. This can be
+             * useful to present the user a first-level clustering of related
+             * media items. This is a read-only column that is automatically
+             * computed.
+             * <p>
+             * Type: TEXT
              */
             public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
 
             /**
+             * The secondary bucket ID of this media item. This can be useful to
+             * present the user a second-level clustering of related media
+             * items. This is a read-only column that is automatically computed.
+             * <p>
+             * Type: INTEGER
+             */
+            public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id";
+
+            /**
              * The bookmark for the video. Time in ms. Represents the location in the video that the
              * video should start playing at the next time it is opened. If the value is null or
              * out of the range 0..DURATION-1 then the video should start playing from the
@@ -2584,7 +2759,13 @@
         /**
          * This class provides utility methods to obtain thumbnails for various
          * {@link Video} items.
+         *
+         * @deprecated Callers should migrate to using
+         *             {@link ContentResolver#loadThumbnail}, since it offers
+         *             richer control over requested thumbnail sizes and
+         *             cancellation behavior.
          */
+        @Deprecated
         public static class Thumbnails implements BaseColumns {
             /**
              * Cancel any outstanding {@link #getThumbnail} requests, causing
@@ -2758,11 +2939,11 @@
         final Set<String> volumeNames = new ArraySet<>();
         volumeNames.add(VOLUME_INTERNAL);
         for (VolumeInfo vi : sm.getVolumes()) {
-            if (vi.isMountedReadable()) {
+            if (vi.isVisibleForUser(UserHandle.myUserId()) && vi.isMountedReadable()) {
                 if (vi.isPrimary()) {
                     volumeNames.add(VOLUME_EXTERNAL);
                 } else {
-                    volumeNames.add(vi.getFsUuid());
+                    volumeNames.add(vi.getNormalizedFsUuid());
                 }
             }
         }
@@ -2777,27 +2958,58 @@
         if (uri.getAuthority().equals(AUTHORITY) && segments != null && segments.size() > 0) {
             return segments.get(0);
         } else {
-            throw new IllegalArgumentException("Not a media Uri: " + uri);
+            throw new IllegalArgumentException("Missing volume name: " + uri);
         }
     }
 
     /** {@hide} */
-    public static @NonNull File getVolumePath(@NonNull String volumeName)
-            throws FileNotFoundException {
-        Objects.requireNonNull(volumeName);
+    public static @NonNull String checkArgumentVolumeName(@NonNull String volumeName) {
+        if (TextUtils.isEmpty(volumeName)) {
+            throw new IllegalArgumentException();
+        }
 
         if (VOLUME_INTERNAL.equals(volumeName)) {
-            return Environment.getDataDirectory();
+            return volumeName;
         } else if (VOLUME_EXTERNAL.equals(volumeName)) {
+            return volumeName;
+        }
+
+        // When not one of the well-known values above, it must be a hex UUID
+        for (int i = 0; i < volumeName.length(); i++) {
+            final char c = volumeName.charAt(i);
+            if (('a' <= c && c <= 'f') || ('0' <= c && c <= '9') || (c == '-')) {
+                continue;
+            } else {
+                throw new IllegalArgumentException("Invalid volume name: " + volumeName);
+            }
+        }
+        return volumeName;
+    }
+
+    /**
+     * Return path where the given volume is mounted. Not valid for
+     * {@link #VOLUME_INTERNAL}.
+     *
+     * @hide
+     */
+    public static @NonNull File getVolumePath(@NonNull String volumeName)
+            throws FileNotFoundException {
+        if (TextUtils.isEmpty(volumeName)) {
+            throw new IllegalArgumentException();
+        }
+
+        if (VOLUME_EXTERNAL.equals(volumeName)) {
             return Environment.getExternalStorageDirectory();
         }
 
         final StorageManager sm = AppGlobals.getInitialApplication()
                 .getSystemService(StorageManager.class);
         for (VolumeInfo vi : sm.getVolumes()) {
-            if (Objects.equals(vi.getFsUuid(), volumeName)) {
+            if (Objects.equals(vi.getNormalizedFsUuid(), volumeName)) {
                 final File path = vi.getPathForUser(UserHandle.myUserId());
-                if (path == null) {
+                if (path != null) {
+                    return path;
+                } else {
                     throw new FileNotFoundException("Failed to find path for " + vi);
                 }
             }
@@ -2806,6 +3018,33 @@
     }
 
     /**
+     * Return paths that should be scanned for the given volume.
+     *
+     * @hide
+     */
+    public static @NonNull Collection<File> getVolumeScanPaths(@NonNull String volumeName)
+            throws FileNotFoundException {
+        if (TextUtils.isEmpty(volumeName)) {
+            throw new IllegalArgumentException();
+        }
+
+        final ArrayList<File> res = new ArrayList<>();
+        if (VOLUME_INTERNAL.equals(volumeName)) {
+            res.add(new File(Environment.getRootDirectory(), "media"));
+            res.add(new File(Environment.getOemDirectory(), "media"));
+            res.add(new File(Environment.getProductDirectory(), "media"));
+        } else {
+            res.add(getVolumePath(volumeName));
+            final UserManager um = AppGlobals.getInitialApplication()
+                    .getSystemService(UserManager.class);
+            if (VOLUME_EXTERNAL.equals(volumeName) && um.isDemoUser()) {
+                res.add(Environment.getDataPreloadsMediaDirectory());
+            }
+        }
+        return res;
+    }
+
+    /**
      * Uri for querying the state of the media scanner.
      */
     public static Uri getMediaScannerUri() {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 65514b6..95cfb6e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -86,7 +86,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.MemoryIntArray;
-import android.view.textservice.TextServicesManager;
+import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.ColorDisplayController;
@@ -1190,7 +1190,8 @@
     /**
      * Activity Action: Show Do Not Disturb access settings.
      * <p>
-     * Users can grant and deny access to Do Not Disturb configuration from here.
+     * Users can grant and deny access to Do Not Disturb configuration from here. Managed
+     * profiles cannot grant Do Not Disturb access.
      * See {@link android.app.NotificationManager#isNotificationPolicyAccessGranted()} for more
      * details.
      * <p>
@@ -3299,6 +3300,14 @@
         public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1;
 
         /**
+         * Control whether to enable adaptive sleep mode.
+         * @hide
+         */
+        public static final String ADAPTIVE_SLEEP = "adaptive_sleep";
+
+        private static final Validator ADAPTIVE_SLEEP_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
          * Control whether the process CPU usage meter should be shown.
          *
          * @deprecated This functionality is no longer available as of
@@ -3377,6 +3386,22 @@
          */
         public static final String NOTIFICATION_VIBRATION_INTENSITY =
                 "notification_vibration_intensity";
+        /**
+         * The intensity of ringtone vibrations, if configurable.
+         *
+         * Not all devices are capable of changing their vibration intensity; on these devices
+         * there will likely be no difference between the various vibration intensities except for
+         * intensity 0 (off) and the rest.
+         *
+         * <b>Values:</b><br/>
+         * 0 - Vibration is disabled<br/>
+         * 1 - Weak vibrations<br/>
+         * 2 - Medium vibrations<br/>
+         * 3 - Strong vibrations
+         * @hide
+         */
+        public static final String RING_VIBRATION_INTENSITY =
+                "ring_vibration_intensity";
 
         /**
          * The intensity of haptic feedback vibrations, if configurable.
@@ -4215,6 +4240,7 @@
             SCREEN_BRIGHTNESS_MODE,
             SCREEN_AUTO_BRIGHTNESS_ADJ,
             SCREEN_BRIGHTNESS_FOR_VR,
+            ADAPTIVE_SLEEP,
             VIBRATE_INPUT_DEVICES,
             MODE_RINGER_STREAMS_AFFECTED,
             TEXT_AUTO_REPLACE,
@@ -4246,6 +4272,7 @@
             ACCELEROMETER_ROTATION,
             SHOW_BATTERY_PERCENT,
             NOTIFICATION_VIBRATION_INTENSITY,
+            RING_VIBRATION_INTENSITY,
             HAPTIC_FEEDBACK_INTENSITY,
             DISPLAY_COLOR_MODE,
             ALARM_ALERT,
@@ -4289,6 +4316,7 @@
             PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS);
             PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS_FOR_VR);
             PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS_MODE);
+            PUBLIC_SETTINGS.add(ADAPTIVE_SLEEP);
             PUBLIC_SETTINGS.add(MODE_RINGER_STREAMS_AFFECTED);
             PUBLIC_SETTINGS.add(MUTE_STREAMS_AFFECTED);
             PUBLIC_SETTINGS.add(VIBRATE_ON);
@@ -4393,10 +4421,12 @@
             VALIDATORS.put(SCREEN_OFF_TIMEOUT, SCREEN_OFF_TIMEOUT_VALIDATOR);
             VALIDATORS.put(SCREEN_BRIGHTNESS_FOR_VR, SCREEN_BRIGHTNESS_FOR_VR_VALIDATOR);
             VALIDATORS.put(SCREEN_BRIGHTNESS_MODE, SCREEN_BRIGHTNESS_MODE_VALIDATOR);
+            VALIDATORS.put(ADAPTIVE_SLEEP, ADAPTIVE_SLEEP_VALIDATOR);
             VALIDATORS.put(MODE_RINGER_STREAMS_AFFECTED, MODE_RINGER_STREAMS_AFFECTED_VALIDATOR);
             VALIDATORS.put(MUTE_STREAMS_AFFECTED, MUTE_STREAMS_AFFECTED_VALIDATOR);
             VALIDATORS.put(VIBRATE_ON, VIBRATE_ON_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
+            VALIDATORS.put(RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
             VALIDATORS.put(HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
             VALIDATORS.put(RINGTONE, RINGTONE_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_SOUND, NOTIFICATION_SOUND_VALIDATOR);
@@ -5030,10 +5060,6 @@
         public static boolean putStringForUser(@NonNull ContentResolver resolver,
                 @NonNull String name, @Nullable String value, @Nullable String tag,
                 boolean makeDefault, @UserIdInt int userHandle) {
-            if (LOCATION_MODE.equals(name)) {
-                // Map LOCATION_MODE to underlying location provider storage API
-                return setLocationModeForUser(resolver, Integer.parseInt(value), userHandle);
-            }
             if (MOVED_TO_GLOBAL.contains(name)) {
                 Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure"
                         + " to android.provider.Settings.Global");
@@ -5186,10 +5212,6 @@
         /** @hide */
         @UnsupportedAppUsage
         public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) {
-            if (LOCATION_MODE.equals(name)) {
-                // Map from to underlying location provider storage API to location mode
-                return getLocationModeForUser(cr, userHandle);
-            }
             String v = getStringForUser(cr, name, userHandle);
             try {
                 return v != null ? Integer.parseInt(v) : def;
@@ -5224,10 +5246,6 @@
         /** @hide */
         public static int getIntForUser(ContentResolver cr, String name, int userHandle)
                 throws SettingNotFoundException {
-            if (LOCATION_MODE.equals(name)) {
-                // Map from to underlying location provider storage API to location mode
-                return getLocationModeForUser(cr, userHandle);
-            }
             String v = getStringForUser(cr, name, userHandle);
             try {
                 return Integer.parseInt(v);
@@ -5810,9 +5828,8 @@
          * this value being present in settings.db or on ContentObserver notifications on the
          * corresponding Uri.
          *
-         * @deprecated use {@link #LOCATION_MODE} and
-         * {@link LocationManager#MODE_CHANGED_ACTION} (or
-         * {@link LocationManager#PROVIDERS_CHANGED_ACTION})
+         * @deprecated Providers should not be controlled individually. See {@link #LOCATION_MODE}
+          * documentation for information on reading/writing location information.
          */
         @Deprecated
         public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
@@ -5830,9 +5847,7 @@
          * notifications for the corresponding Uri. Use {@link LocationManager#MODE_CHANGED_ACTION}
          * to receive changes in this value.
          *
-         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
-         *             get the status of a location provider, use
-         *             {@link LocationManager#isProviderEnabled(String)}.
+         * @deprecated To check location mode, use {@link LocationManager#isLocationEnabled()}.
          */
         @Deprecated
         public static final String LOCATION_MODE = "location_mode";
@@ -5861,9 +5876,7 @@
         /**
          * Location access disabled.
          *
-         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
-         *             get the status of a location provider, use
-         *             {@link LocationManager#isProviderEnabled(String)}.
+         * @deprecated See {@link #LOCATION_MODE}.
          */
         @Deprecated
         public static final int LOCATION_MODE_OFF = 0;
@@ -5883,9 +5896,7 @@
          * with {@link android.location.Criteria#POWER_HIGH} may be downgraded to
          * {@link android.location.Criteria#POWER_MEDIUM}.
          *
-         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
-         *             get the status of a location provider, use
-         *             {@link LocationManager#isProviderEnabled(String)}.
+         * @deprecated See {@link #LOCATION_MODE}.
          */
         @Deprecated
         public static final int LOCATION_MODE_BATTERY_SAVING = 2;
@@ -5893,9 +5904,7 @@
         /**
          * Best-effort location computation allowed.
          *
-         * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
-         *             get the status of a location provider, use
-         *             {@link LocationManager#isProviderEnabled(String)}.
+         * @deprecated See {@link #LOCATION_MODE}.
          */
         @Deprecated
         public static final int LOCATION_MODE_HIGH_ACCURACY = 3;
@@ -6019,6 +6028,21 @@
                 "lock_screen_allow_remote_input";
 
         /**
+         * Indicates which clock face to show on lock screen and AOD.
+         * @hide
+         */
+        public static final String LOCK_SCREEN_CUSTOM_CLOCK_FACE = "lock_screen_custom_clock_face";
+
+        private static final Validator LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR =
+                ANY_STRING_VALIDATOR;
+
+        /**
+         * Indicates which clock face to show on lock screen and AOD while docked.
+         * @hide
+         */
+        private static final String DOCKED_CLOCK_FACE = "docked_clock_face";
+
+        /**
          * Set by the system to track if the user needs to see the call to action for
          * the lockscreen notification policy.
          * @hide
@@ -6207,7 +6231,7 @@
         public static final String CHARGING_SOUNDS_ENABLED = "charging_sounds_enabled";
 
         /**
-         * Whether to vibrate for wireless charging events.
+         * Whether to vibrate for charging events.
          * @hide
          */
         public static final String CHARGING_VIBRATION_ENABLED = "charging_vibration_enabled";
@@ -7384,6 +7408,14 @@
         private static final Validator DOZE_DOUBLE_TAP_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * Whether the device should respond to the SLPI tap gesture.
+         * @hide
+         */
+        public static final String DOZE_TAP_SCREEN_GESTURE = "doze_tap_gesture";
+
+        private static final Validator DOZE_TAP_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
          * Gesture that wakes up the lock screen.
          * @hide
          */
@@ -7400,6 +7432,22 @@
         private static final Validator DOZE_WAKE_SCREEN_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * Gesture that skips media.
+         * @hide
+         */
+        public static final String SKIP_GESTURE = "skip_gesture";
+
+        private static final Validator SKIP_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
+         * Gesture that silences sound (alarms, notification, calls).
+         * @hide
+         */
+        public static final String SILENCE_GESTURE = "silence_gesture";
+
+        private static final Validator SILENCE_GESTURE_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
          * The current night mode that has been selected by the user.  Owned
          * and controlled by UiModeManagerService.  Constants are as per
          * UiModeManager.
@@ -7701,6 +7749,23 @@
         public static final String TV_INPUT_CUSTOM_LABELS = "tv_input_custom_labels";
 
         /**
+         * Whether TV app uses non-system inputs.
+         *
+         * <p>
+         * The value is boolean (1 or 0), where 1 means non-system TV inputs are allowed,
+         * and 0 means non-system TV inputs are not allowed.
+         *
+         * <p>
+         * Devices such as sound bars may have changed the system property allow_third_party_inputs
+         * to false so the TV Application only uses HDMI and other built in inputs. This setting
+         * allows user to override the default and have the TV Application use third party TV inputs
+         * available on play store.
+         *
+         * @hide
+         */
+        public static final String TV_APP_USES_NON_SYSTEM_INPUTS = "tv_app_uses_non_system_inputs";
+
+        /**
          * Whether automatic routing of system audio to USB audio peripheral is disabled.
          * The value is boolean (1 or 0), where 1 means automatic routing is disabled,
          * and 0 means automatic routing is enabled.
@@ -7835,6 +7900,19 @@
                 BOOLEAN_VALIDATOR;
 
         /**
+         * Whether or not face unlock always requires user confirmation, meaning {@link
+         * android.hardware.biometrics.BiometricPrompt.Builder#setRequireConfirmation(boolean)}
+         * is always 'true'. This overrides the behavior that apps choose in the
+         * setRequireConfirmation API.
+         * @hide
+         */
+        public static final String FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION =
+                "face_unlock_always_require_confirmation";
+
+        private static final Validator FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION_VALIDATOR =
+                BOOLEAN_VALIDATOR;
+
+        /**
          * Whether the assist gesture should be enabled.
          *
          * @hide
@@ -8343,6 +8421,20 @@
         public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS =
                 "location_access_check_delay_millis";
 
+
+        /**
+         * Comma separated list of enabled overlay packages for all android.theme.customization.*
+         * categories. If there is no corresponding package included for a category, then all
+         * overlay packages in that category must be disabled.
+         * @hide
+         */
+        @SystemApi
+        public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES =
+                "theme_customization_overlay_packages";
+
+        private static final Validator THEME_CUSTOMIZATION_OVERLAY_PACKAGES_VALIDATOR =
+                new SettingsValidators.PackageNameListValidator(",");
+
         /**
          * This are the settings to be backed up.
          *
@@ -8425,12 +8517,14 @@
             DOZE_ALWAYS_ON,
             DOZE_PICK_UP_GESTURE,
             DOZE_DOUBLE_TAP_GESTURE,
+            DOZE_TAP_SCREEN_GESTURE,
             DOZE_WAKE_LOCK_SCREEN_GESTURE,
             DOZE_WAKE_SCREEN_GESTURE,
             NFC_PAYMENT_DEFAULT_COMPONENT,
             AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
             FACE_UNLOCK_KEYGUARD_ENABLED,
             FACE_UNLOCK_APP_ENABLED,
+            FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
             ASSIST_GESTURE_ENABLED,
             ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
             ASSIST_GESTURE_WAKE_ENABLED,
@@ -8448,6 +8542,7 @@
             HUSH_GESTURE_USED,
             IN_CALL_NOTIFICATION_ENABLED,
             LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+            LOCK_SCREEN_CUSTOM_CLOCK_FACE,
             LOCK_SCREEN_SHOW_NOTIFICATIONS,
             ZEN_DURATION,
             SHOW_ZEN_UPGRADE_NOTIFICATION,
@@ -8461,6 +8556,9 @@
             NOTIFICATION_NEW_INTERRUPTION_MODEL,
             TRUST_AGENTS_EXTEND_UNLOCK,
             LOCK_SCREEN_WHEN_TRUST_LOST,
+            SKIP_GESTURE,
+            SILENCE_GESTURE,
+            THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
         };
 
         /**
@@ -8577,6 +8675,7 @@
             VALIDATORS.put(DOZE_ALWAYS_ON, DOZE_ALWAYS_ON_VALIDATOR);
             VALIDATORS.put(DOZE_PICK_UP_GESTURE, DOZE_PICK_UP_GESTURE_VALIDATOR);
             VALIDATORS.put(DOZE_DOUBLE_TAP_GESTURE, DOZE_DOUBLE_TAP_GESTURE_VALIDATOR);
+            VALIDATORS.put(DOZE_TAP_SCREEN_GESTURE, DOZE_TAP_SCREEN_GESTURE_VALIDATOR);
             VALIDATORS.put(DOZE_WAKE_LOCK_SCREEN_GESTURE, DOZE_WAKE_LOCK_SCREEN_GESTURE_VALIDATOR);
             VALIDATORS.put(DOZE_WAKE_SCREEN_GESTURE, DOZE_WAKE_SCREEN_GESTURE_VALIDATOR);
             VALIDATORS.put(NFC_PAYMENT_DEFAULT_COMPONENT, NFC_PAYMENT_DEFAULT_COMPONENT_VALIDATOR);
@@ -8584,6 +8683,8 @@
                     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(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
+                    FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR);
             VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
                     ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR);
@@ -8624,7 +8725,12 @@
             VALIDATORS.put(ASSIST_GESTURE_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_NEW_INTERRUPTION_MODEL, BOOLEAN_VALIDATOR);
             VALIDATORS.put(TRUST_AGENTS_EXTEND_UNLOCK, TRUST_AGENTS_EXTEND_UNLOCK_VALIDATOR);
+            VALIDATORS.put(LOCK_SCREEN_CUSTOM_CLOCK_FACE, LOCK_SCREEN_CUSTOM_CLOCK_FACE_VALIDATOR);
             VALIDATORS.put(LOCK_SCREEN_WHEN_TRUST_LOST, LOCK_SCREEN_WHEN_TRUST_LOST_VALIDATOR);
+            VALIDATORS.put(SKIP_GESTURE, SKIP_GESTURE_VALIDATOR);
+            VALIDATORS.put(SILENCE_GESTURE, SILENCE_GESTURE_VALIDATOR);
+            VALIDATORS.put(THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
+                    THEME_CUSTOMIZATION_OVERLAY_PACKAGES_VALIDATOR);
         }
 
         /**
@@ -8652,14 +8758,14 @@
             CLONE_TO_MANAGED_PROFILE.add(ACCESSIBILITY_ENABLED);
             CLONE_TO_MANAGED_PROFILE.add(ALLOW_MOCK_LOCATION);
             CLONE_TO_MANAGED_PROFILE.add(ALLOWED_GEOLOCATION_ORIGINS);
-            CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
             CLONE_TO_MANAGED_PROFILE.add(ENABLED_ACCESSIBILITY_SERVICES);
-            CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_CHANGER);
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
             CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
-            CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
-            if (TextServicesManager.DISABLE_PER_PROFILE_SPELL_CHECKER) {
+            if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
+                CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
+                CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
+                CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
                 CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER);
                 CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER_SUBTYPE);
             }
@@ -8778,84 +8884,6 @@
                         userId);
             }
         }
-
-        /**
-         * Thread-safe method for setting the location mode to one of
-         * {@link #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY},
-         * {@link #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}.
-         * Necessary because the mode is a composite of the underlying location provider
-         * settings.
-         *
-         * @param cr the content resolver to use
-         * @param mode such as {@link #LOCATION_MODE_HIGH_ACCURACY}
-         * @param userId the userId for which to change mode
-         * @return true if the value was set, false on database errors
-         *
-         * @throws IllegalArgumentException if mode is not one of the supported values
-         *
-         * @deprecated To enable/disable location, use
-         *             {@link LocationManager#setLocationEnabledForUser(boolean, int)}.
-         *             To enable/disable a specific location provider, use
-         *             {@link LocationManager#setProviderEnabledForUser(String, boolean, int)}.
-         */
-        @Deprecated
-        private static boolean setLocationModeForUser(
-                ContentResolver cr, int mode, int userId) {
-            synchronized (mLocationSettingsLock) {
-                boolean gps = false;
-                boolean network = false;
-                switch (mode) {
-                    case LOCATION_MODE_OFF:
-                        break;
-                    case LOCATION_MODE_SENSORS_ONLY:
-                        gps = true;
-                        break;
-                    case LOCATION_MODE_BATTERY_SAVING:
-                        network = true;
-                        break;
-                    case LOCATION_MODE_HIGH_ACCURACY:
-                        gps = true;
-                        network = true;
-                        break;
-                    default:
-                        throw new IllegalArgumentException("Invalid location mode: " + mode);
-                }
-
-                boolean nlpSuccess = Settings.Secure.setLocationProviderEnabledForUser(
-                        cr, LocationManager.NETWORK_PROVIDER, network, userId);
-                boolean gpsSuccess = Settings.Secure.setLocationProviderEnabledForUser(
-                        cr, LocationManager.GPS_PROVIDER, gps, userId);
-                return gpsSuccess && nlpSuccess;
-            }
-        }
-
-        /**
-         * Thread-safe method for reading the location mode, returns one of
-         * {@link #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY},
-         * {@link #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}. Necessary
-         * because the mode is a composite of the underlying location provider settings.
-         *
-         * @param cr the content resolver to use
-         * @param userId the userId for which to read the mode
-         * @return the location mode
-         */
-        private static final int getLocationModeForUser(ContentResolver cr, int userId) {
-            synchronized (mLocationSettingsLock) {
-                boolean gpsEnabled = Settings.Secure.isLocationProviderEnabledForUser(
-                        cr, LocationManager.GPS_PROVIDER, userId);
-                boolean networkEnabled = Settings.Secure.isLocationProviderEnabledForUser(
-                        cr, LocationManager.NETWORK_PROVIDER, userId);
-                if (gpsEnabled && networkEnabled) {
-                    return LOCATION_MODE_HIGH_ACCURACY;
-                } else if (gpsEnabled) {
-                    return LOCATION_MODE_SENSORS_ONLY;
-                } else if (networkEnabled) {
-                    return LOCATION_MODE_BATTERY_SAVING;
-                } else {
-                    return LOCATION_MODE_OFF;
-                }
-            }
-        }
     }
 
     /**
@@ -8882,6 +8910,14 @@
         public static final String ADD_USERS_WHEN_LOCKED = "add_users_when_locked";
 
         /**
+         * Whether applying ramping ringer on incoming phone call ringtone.
+         * <p>1 = apply ramping ringer
+         * <p>0 = do not apply ramping ringer
+         * @hide
+         */
+        public static final String APPLY_RAMPING_RINGER = "apply_ramping_ringer";
+
+        /**
          * Setting whether the global gesture for enabling accessibility is enabled.
          * If this gesture is enabled the user will be able to perfrom it to enable
          * the accessibility state without visiting the settings app.
@@ -9406,6 +9442,15 @@
                 "hdmi_system_audio_control_enabled";
 
         /**
+         * Whether HDMI Routing Control feature is enabled. If enabled, the switch device will
+         * route to the correct input source on receiving Routing Control related messages. If
+         * disabled, you can only switch the input via controls on this device.
+         * @hide
+         */
+        public static final String HDMI_CEC_SWITCH_ENABLED =
+                "hdmi_cec_switch_enabled";
+
+        /**
          * Whether TV will automatically turn on upon reception of the CEC command
          * &lt;Text View On&gt; or &lt;Image View On&gt;. (0 = false, 1 = true)
          *
@@ -9424,23 +9469,6 @@
                 "hdmi_control_auto_device_off_enabled";
 
         /**
-         * If <b>true</b>, enables out-of-the-box execution for priv apps.
-         * Default: false
-         * Values: 0 = false, 1 = true
-         *
-         * @hide
-         */
-        public static final String PRIV_APP_OOB_ENABLED = "priv_app_oob_enabled";
-
-        /**
-         * Comma separated list of privileged package names, which will be running out-of-box APK.
-         * Default: "ALL"
-         *
-         * @hide
-         */
-        public static final String PRIV_APP_OOB_LIST = "priv_app_oob_list";
-
-        /**
          * The interval in milliseconds at which location requests will be throttled when they are
          * coming from the background.
          *
@@ -9465,6 +9493,14 @@
             "location_background_throttle_package_whitelist";
 
         /**
+         * Packages that are whitelisted for ignoring location settings (may retrieve location even
+         * when user location settings are off), for emergency purposes.
+         * @hide
+         */
+        public static final String LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST =
+                "location_ignore_settings_package_whitelist";
+
+        /**
          * Whether to disable location status callbacks in preparation for deprecation.
          * @hide
          */
@@ -10799,6 +10835,8 @@
          *
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
 
         /**
@@ -10807,6 +10845,8 @@
          *
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
 
         /**
@@ -10815,6 +10855,8 @@
          *
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
 
         /**
@@ -10824,6 +10866,8 @@
          * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
 
         /**
@@ -10852,6 +10896,8 @@
          *
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url";
 
         /**
@@ -10860,6 +10906,8 @@
          *
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
 
         /**
@@ -10868,6 +10916,8 @@
          *
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
 
         /**
@@ -10876,6 +10926,8 @@
          *
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS =
                 "captive_portal_other_fallback_urls";
 
@@ -10885,6 +10937,8 @@
          * by "@@,@@".
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS =
                 "captive_portal_fallback_probe_specs";
 
@@ -10895,6 +10949,8 @@
          *
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
 
         /**
@@ -10903,6 +10959,8 @@
          *
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
 
         /**
@@ -10912,6 +10970,8 @@
          *
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD =
                 "data_stall_consecutive_dns_timeout_threshold";
 
@@ -10920,6 +10980,8 @@
          *
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final String DATA_STALL_MIN_EVALUATE_INTERVAL =
                 "data_stall_min_evaluate_interval";
 
@@ -10929,6 +10991,8 @@
          *
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD =
                 "data_stall_valid_dns_time_threshold";
 
@@ -10938,9 +11002,26 @@
          *
          * @hide
          */
+        @SystemApi
+        @TestApi
         public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
 
         /**
+         * Whether to try cellular data recovery when a bad network is reported.
+         *
+         * @hide
+         */
+        public static final String DATA_STALL_RECOVERY_ON_BAD_NETWORK =
+                "data_stall_recovery_on_bad_network";
+
+        /**
+         * Minumim duration in millisecodns between cellular data recovery attempts
+         *
+         * @hide
+         */
+        public static final String MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS =
+                "min_duration_between_recovery_steps";
+        /**
          * Whether network service discovery is enabled.
          *
          * @hide
@@ -11071,6 +11152,10 @@
           */
         public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode";
 
+
+        /** {@hide} */
+        public static final String
+                BLUETOOTH_BTSNOOP_DEFAULT_MODE = "bluetooth_btsnoop_default_mode";
         /** {@hide} */
         public static final String
                 BLUETOOTH_HEADSET_PRIORITY_PREFIX = "bluetooth_headset_priority_";
@@ -11107,6 +11192,31 @@
         /** {@hide} */
         public static final String
                 BLUETOOTH_HEARING_AID_PRIORITY_PREFIX = "bluetooth_hearing_aid_priority_";
+        /**
+         * Enable/disable radio bug detection
+         *
+         * {@hide}
+         */
+        public static final String
+                ENABLE_RADIO_BUG_DETECTION = "enable_radio_bug_detection";
+
+        /**
+         * Count threshold of RIL wakelock timeout for radio bug detection
+         *
+         * {@hide}
+         */
+        public static final String
+                RADIO_BUG_WAKELOCK_TIMEOUT_COUNT_THRESHOLD =
+                "radio_bug_wakelock_timeout_count_threshold";
+
+        /**
+         * Count threshold of RIL system error for radio bug detection
+         *
+         * {@hide}
+         */
+        public static final String
+                RADIO_BUG_SYSTEM_ERROR_COUNT_THRESHOLD =
+                "radio_bug_system_error_count_threshold";
 
         /**
          * Activity manager specific settings.
@@ -11254,14 +11364,14 @@
          * quick_doze_enabled                (boolean)
          * </pre>
          * @hide
-         * @see com.android.server.power.BatterySaverPolicy
+         * @see com.android.server.power.batterysaver.BatterySaverPolicy
          */
         public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
 
         /**
          * Battery Saver device specific settings
          * This is encoded as a key=value list, separated by commas.
-         * See {@link com.android.server.power.BatterySaverPolicy} for the details.
+         * See {@link com.android.server.power.batterysaver.BatterySaverPolicy} for the details.
          *
          * @hide
          */
@@ -11404,6 +11514,20 @@
         public static final String DISPLAY_PANEL_LPM = "display_panel_lpm";
 
         /**
+         * App time limit usage source setting.
+         * This controls which app in a task will be considered the source of usage when
+         * calculating app usage time limits.
+         *
+         * 1 -> task root app
+         * 2 -> current app
+         * Any other value defaults to task root app.
+         *
+         * Need to reboot the device for this setting to take effect.
+         * @hide
+         */
+        public static final String APP_TIME_LIMIT_USAGE_SOURCE = "app_time_limit_usage_source";
+
+        /**
          * App standby (app idle) specific settings.
          * This is encoded as a key=value list, separated by commas. Ex:
          * <p>
@@ -11597,6 +11721,7 @@
          * battery_level_collection_delay_ms (long)
          * max_history_files (int)
          * max_history_buffer_kb (int)
+         * battery_charged_delay_ms (int)
          * </pre>
          *
          * <p>
@@ -11764,6 +11889,28 @@
         public static final String KEEP_PROFILE_IN_BACKGROUND = "keep_profile_in_background";
 
         /**
+         * The default time in ms within which a subsequent connection from an always allowed system
+         * is allowed to reconnect without user interaction.
+         *
+         * @hide
+         */
+        public static final long DEFAULT_ADB_ALLOWED_CONNECTION_TIME = 604800000;
+
+        /**
+         * When the user first connects their device to a system a prompt is displayed to allow
+         * the adb connection with an option to 'Always allow' connections from this system. If the
+         * user selects this always allow option then the connection time is stored for the system.
+         * This setting is the time in ms within which a subsequent connection from an always
+         * allowed system is allowed to reconnect without user interaction.
+         *
+         * Type: long
+         *
+         * @hide
+         */
+        public static final String ADB_ALLOWED_CONNECTION_TIME =
+                "adb_allowed_connection_time";
+
+        /**
          * Get the key that retrieves a bluetooth headset's priority.
          * @hide
          */
@@ -11982,11 +12129,41 @@
                 "angle_gl_driver_selection_values";
 
         /**
-         * App that is selected to use updated graphics driver.
+         * Game Update Package global preference for all Apps.
+         * 0 = Default
+         * 1 = All Apps use Game Update Package
+         * 2 = All Apps use system graphics driver
          * @hide
          */
-        public static final String UPDATED_GFX_DRIVER_DEV_OPT_IN_APP =
-                "updated_gfx_driver_dev_opt_in_app";
+        public static final String GUP_DEV_ALL_APPS = "gup_dev_all_apps";
+
+        /**
+         * List of Apps selected to use Game Update Package.
+         * i.e. <pkg1>,<pkg2>,...,<pkgN>
+         * @hide
+         */
+        public static final String GUP_DEV_OPT_IN_APPS = "gup_dev_opt_in_apps";
+
+        /**
+         * List of Apps selected not to use Game Update Package.
+         * i.e. <pkg1>,<pkg2>,...,<pkgN>
+         * @hide
+         */
+        public static final String GUP_DEV_OPT_OUT_APPS = "gup_dev_opt_out_apps";
+
+        /**
+         * Apps on the blacklist that are forbidden to use Game Update Package.
+         * @hide
+         */
+        public static final String GUP_BLACKLIST = "gup_blacklist";
+
+        /**
+         * Apps on the whitelist that are allowed to use Game Driver.
+         * The string is a list of application package names, seperated by comma.
+         * i.e. <apk1>,<apk2>,...,<apkN>
+         * @hide
+         */
+        public static final String GAME_DRIVER_WHITELIST = "game_driver_whitelist";
 
         /**
          * Ordered GPU debug layer list for Vulkan
@@ -12033,6 +12210,31 @@
         public static final String LOW_POWER_MODE_STICKY = "low_power_sticky";
 
         /**
+         * When a device is unplugged from a changer (or is rebooted), do not re-activate battery
+         * saver even if {@link #LOW_POWER_MODE_STICKY} is 1, if the battery level is equal to or
+         * above this threshold.
+         *
+         * @hide
+         */
+        public static final String LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL =
+                "low_power_sticky_auto_disable_level";
+
+        private static final Validator LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL_VALIDATOR =
+                new SettingsValidators.InclusiveIntegerRangeValidator(0, 100);
+
+        /**
+         * Whether sticky battery saver should be deactivated once the battery level has reached the
+         * threshold specified by {@link #LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL}.
+         *
+         * @hide
+         */
+        public static final String LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED =
+                "low_power_sticky_auto_disable_enabled";
+
+        private static final Validator LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED_VALIDATOR =
+                new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1"});
+
+        /**
          * Battery level [1-100] at which low power mode automatically turns on.
          * Pre-Q If 0, it will not automatically turn on. Q and newer it will only automatically
          * turn on if the {@link #AUTOMATIC_POWER_SAVER_MODE} setting is also set to
@@ -12044,7 +12246,6 @@
          */
         public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
 
-
         private static final Validator LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR =
                 new SettingsValidators.InclusiveIntegerRangeValidator(0, 100);
 
@@ -13035,6 +13236,8 @@
             ENCODED_SURROUND_OUTPUT,
             ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS,
             LOW_POWER_MODE_TRIGGER_LEVEL,
+            LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
+            LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL,
             BLUETOOTH_ON,
             PRIVATE_DNS_MODE,
             PRIVATE_DNS_SPECIFIER,
@@ -13073,6 +13276,10 @@
             VALIDATORS.put(ENCODED_SURROUND_OUTPUT, ENCODED_SURROUND_OUTPUT_VALIDATOR);
             VALIDATORS.put(ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS,
                     ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS_VALIDATOR);
+            VALIDATORS.put(LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL,
+                    LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL_VALIDATOR);
+            VALIDATORS.put(LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
+                    LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED_VALIDATOR);
             VALIDATORS.put(LOW_POWER_MODE_TRIGGER_LEVEL, LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR);
             VALIDATORS.put(LOW_POWER_MODE_TRIGGER_LEVEL_MAX,
                     LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR);
@@ -13587,6 +13794,19 @@
                 "user_preferred_sub2","user_preferred_sub3"};
 
         /**
+         * Which subscription is enabled for a physical slot.
+         * @hide
+         */
+        public static final String ENABLED_SUBSCRIPTION_FOR_SLOT = "enabled_subscription_for_slot";
+
+        /**
+         * Whether corresponding logical modem is enabled for a physical slot.
+         * The value 1 - enable, 0 - disable
+         * @hide
+         */
+        public static final String MODEM_STACK_ENABLED_FOR_SLOT = "modem_stack_enabled_for_slot";
+
+        /**
          * Whether to enable new contacts aggregator or not.
          * The value 1 - enable, 0 - disable
          * @hide
@@ -13803,9 +14023,12 @@
          * The following keys are supported:
          *
          * <pre>
-         * enabled                         (boolean)
-         * requires_targeting_p            (boolean)
-         * max_squeeze_remeasure_attempts  (int)
+         * enabled                           (boolean)
+         * requires_targeting_p              (boolean)
+         * max_squeeze_remeasure_attempts    (int)
+         * edit_choices_before_sending       (boolean)
+         * show_in_heads_up                  (boolean)
+         * min_num_system_generated_replies  (int)
          * </pre>
          * @see com.android.systemui.statusbar.policy.SmartReplyConstants
          * @hide
@@ -13990,6 +14213,53 @@
          */
         public static final String NATIVE_FLAGS_HEALTH_CHECK_ENABLED =
                 "native_flags_health_check_enabled";
+
+        /**
+         * Parameter for {@link #APPOP_HISTORY_PARAMETERS} that controls the mode
+         * in which the historical registry operates.
+         *
+         * @hide
+         */
+        public static final String APPOP_HISTORY_MODE = "mode";
+
+        /**
+         * Parameter for {@link #APPOP_HISTORY_PARAMETERS} that controls how long
+         * is the interval between snapshots in the base case i.e. the most recent
+         * part of the history.
+         *
+         * @hide
+         */
+        public static final String APPOP_HISTORY_BASE_INTERVAL_MILLIS = "baseIntervalMillis";
+
+        /**
+         * Parameter for {@link #APPOP_HISTORY_PARAMETERS} that controls the base
+         * for the logarithmic step when building app op history.
+         *
+         * @hide
+         */
+        public static final String APPOP_HISTORY_INTERVAL_MULTIPLIER = "intervalMultiplier";
+
+        /**
+         * Appop history parameters. These parameters are represented by
+         * a comma-delimited key-value list.
+         *
+         * The following strings are supported as keys:
+         * <pre>
+         *     mode                  (int)
+         *     baseIntervalMillis    (long)
+         *     intervalMultiplier    (int)
+         * </pre>
+         *
+         * Ex: "mode=HISTORICAL_MODE_ENABLED_ACTIVE,baseIntervalMillis=1000,intervalMultiplier=10"
+         *
+         * @see #APPOP_HISTORY_MODE
+         * @see #APPOP_HISTORY_BASE_INTERVAL_MILLIS
+         * @see #APPOP_HISTORY_INTERVAL_MULTIPLIER
+         *
+         * @hide
+         */
+        public static final String APPOP_HISTORY_PARAMETERS =
+                "appop_history_parameters";
     }
 
     /**
@@ -14018,7 +14288,7 @@
          *
          * @hide
          */
-        // TODO(b/117663715): require a new read permission
+        @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
         static String getString(ContentResolver resolver, String name) {
             return sNameValueCache.getStringForUser(resolver, name, resolver.getUserId());
         }
@@ -14041,8 +14311,7 @@
          *
          * @hide
          */
-        // TODO(b/117663715): require a new write permission restricted to a single source
-        @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+        @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
         static boolean putString(@NonNull ContentResolver resolver, @NonNull String name,
                 @Nullable String value, boolean makeDefault) {
             return sNameValueCache.putStringForUser(resolver, name, value, null, makeDefault,
@@ -14064,17 +14333,16 @@
          * @hide
          */
         // TODO(b/117663715): require a new write permission restricted to a single source
-        @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+        @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
         static void resetToDefaults(@NonNull ContentResolver resolver, @ResetMode int resetMode,
                 @Nullable String prefix) {
             try {
                 Bundle arg = new Bundle();
                 arg.putInt(CALL_METHOD_USER_KEY, resolver.getUserId());
-                arg.putInt(Settings.CALL_METHOD_RESET_MODE_KEY, resetMode);
+                arg.putInt(CALL_METHOD_RESET_MODE_KEY, resetMode);
                 if (prefix != null) {
                     arg.putString(Settings.CALL_METHOD_PREFIX_KEY, prefix);
                 }
-                arg.putInt(CALL_METHOD_RESET_MODE_KEY, resetMode);
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
                 cp.call(resolver.getPackageName(), sProviderHolder.mUri.getAuthority(),
                         CALL_METHOD_RESET_CONFIG, null, arg);
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 31a5962..c43a666 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -533,7 +533,10 @@
      *     service.
      * @throws LockScreenRequiredException if the user does not have a lock screen set. A lock
      *     screen is required to generate recoverable keys.
+     *
+     * @deprecated Use the method {@link #generateKey(String, byte[])} instead.
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
     public @NonNull Key generateKey(@NonNull String alias) throws InternalRecoveryServiceException,
             LockScreenRequiredException {
@@ -556,6 +559,47 @@
     }
 
     /**
+     * Generates a recoverable key with the given {@code alias} and {@code metadata}.
+     *
+     * <p>The metadata should contain any data that needs to be cryptographically bound to the
+     * generated key, but does not need to be encrypted by the key. For example, the metadata can
+     * be a byte string describing the algorithms and non-secret parameters to be used with the
+     * key. The supplied metadata can later be obtained via
+     * {@link WrappedApplicationKey#getMetadata()}.
+     *
+     * <p>During the key recovery process, the same metadata has to be supplied via
+     * {@link WrappedApplicationKey.Builder#setMetadata(byte[])}; otherwise, the recovery process
+     * will fail due to the checking of the cryptographic binding. This can help prevent
+     * potential attacks that try to swap key materials on the backup server and trick the
+     * application to use keys with different algorithms or parameters.
+     *
+     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+     *     service.
+     * @throws LockScreenRequiredException if the user does not have a lock screen set. A lock
+     *     screen is required to generate recoverable keys.
+     */
+    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
+    public @NonNull Key generateKey(@NonNull String alias, @Nullable byte[] metadata)
+            throws InternalRecoveryServiceException, LockScreenRequiredException {
+        try {
+            String grantAlias = mBinder.generateKeyWithMetadata(alias, metadata);
+            if (grantAlias == null) {
+                throw new InternalRecoveryServiceException("null grant alias");
+            }
+            return getKeyFromGrant(grantAlias);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (UnrecoverableKeyException e) {
+            throw new InternalRecoveryServiceException("Failed to get key from keystore", e);
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ERROR_INSECURE_USER) {
+                throw new LockScreenRequiredException(e.getMessage());
+            }
+            throw wrapUnexpectedServiceSpecificException(e);
+        }
+    }
+
+    /**
      * Imports a 256-bit recoverable AES key with the given {@code alias} and the raw bytes {@code
      * keyBytes}.
      *
@@ -564,7 +608,9 @@
      * @throws LockScreenRequiredException if the user does not have a lock screen set. A lock
      *     screen is required to generate recoverable keys.
      *
+     * @deprecated Use the method {@link #importKey(String, byte[], byte[])} instead.
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
     public @NonNull Key importKey(@NonNull String alias, @NonNull byte[] keyBytes)
             throws InternalRecoveryServiceException, LockScreenRequiredException {
@@ -587,6 +633,49 @@
     }
 
     /**
+     * Imports a recoverable 256-bit AES key with the given {@code alias}, the raw bytes {@code
+     * keyBytes}, and the {@code metadata}.
+     *
+     * <p>The metadata should contain any data that needs to be cryptographically bound to the
+     * imported key, but does not need to be encrypted by the key. For example, the metadata can
+     * be a byte string describing the algorithms and non-secret parameters to be used with the
+     * key. The supplied metadata can later be obtained via
+     * {@link WrappedApplicationKey#getMetadata()}.
+     *
+     * <p>During the key recovery process, the same metadata has to be supplied via
+     * {@link WrappedApplicationKey.Builder#setMetadata(byte[])}; otherwise, the recovery process
+     * will fail due to the checking of the cryptographic binding. This can help prevent
+     * potential attacks that try to swap key materials on the backup server and trick the
+     * application to use keys with different algorithms or parameters.
+     *
+     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+     *     service.
+     * @throws LockScreenRequiredException if the user does not have a lock screen set. A lock
+     *     screen is required to generate recoverable keys.
+     */
+    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
+    public @NonNull Key importKey(@NonNull String alias, @NonNull byte[] keyBytes,
+            @Nullable byte[] metadata)
+            throws InternalRecoveryServiceException, LockScreenRequiredException {
+        try {
+            String grantAlias = mBinder.importKeyWithMetadata(alias, keyBytes, metadata);
+            if (grantAlias == null) {
+                throw new InternalRecoveryServiceException("Null grant alias");
+            }
+            return getKeyFromGrant(grantAlias);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (UnrecoverableKeyException e) {
+            throw new InternalRecoveryServiceException("Failed to get key from keystore", e);
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ERROR_INSECURE_USER) {
+                throw new LockScreenRequiredException(e.getMessage());
+            }
+            throw wrapUnexpectedServiceSpecificException(e);
+        }
+    }
+
+    /**
      * Gets a key called {@code alias} from the recoverable key store.
      *
      * @param alias The key alias.
diff --git a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
index ae4448f..dbfd655 100644
--- a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
+++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
@@ -17,6 +17,7 @@
 package android.security.keystore.recovery;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -41,6 +42,8 @@
     private String mAlias;
     // The only supported format is AES-256 symmetric key.
     private byte[] mEncryptedKeyMaterial;
+    // The optional metadata that's authenticated (but unencrypted) with the key material.
+    private byte[] mMetadata;
 
     // IMPORTANT! PLEASE READ!
     // -----------------------
@@ -80,13 +83,23 @@
          * @param encryptedKeyMaterial The key material
          * @return This builder
          */
-
         public Builder setEncryptedKeyMaterial(@NonNull byte[] encryptedKeyMaterial) {
             mInstance.mEncryptedKeyMaterial = encryptedKeyMaterial;
             return this;
         }
 
         /**
+         * Sets the metadata that is authenticated (but unecrypted) with the key material.
+         *
+         * @param metadata The metadata
+         * @return This builder
+         */
+        public Builder setMetadata(@Nullable byte[] metadata) {
+            mInstance.mMetadata = metadata;
+            return this;
+        }
+
+        /**
          * Creates a new {@link WrappedApplicationKey} instance.
          *
          * @return new instance
@@ -102,9 +115,10 @@
     private WrappedApplicationKey() { }
 
     /**
-     * Deprecated - consider using Builder.
+     * @deprecated Use the builder instead.
      * @hide
      */
+    @Deprecated
     public WrappedApplicationKey(@NonNull String alias, @NonNull byte[] encryptedKeyMaterial) {
         mAlias = Preconditions.checkNotNull(alias);
         mEncryptedKeyMaterial = Preconditions.checkNotNull(encryptedKeyMaterial);
@@ -124,6 +138,11 @@
         return mEncryptedKeyMaterial;
     }
 
+    /** The metadata with the key. */
+    public @Nullable byte[] getMetadata() {
+        return mMetadata;
+    }
+
     public static final Parcelable.Creator<WrappedApplicationKey> CREATOR =
             new Parcelable.Creator<WrappedApplicationKey>() {
                 public WrappedApplicationKey createFromParcel(Parcel in) {
@@ -139,6 +158,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(mAlias);
         out.writeByteArray(mEncryptedKeyMaterial);
+        out.writeByteArray(mMetadata);
     }
 
     /**
@@ -147,6 +167,10 @@
     protected WrappedApplicationKey(Parcel in) {
         mAlias = in.readString();
         mEncryptedKeyMaterial = in.createByteArray();
+        // Check if there is still data to be read.
+        if (in.dataAvail() > 0) {
+            mMetadata = in.createByteArray();
+        }
     }
 
     @Override
diff --git a/core/java/android/service/appprediction/AppPredictionService.java b/core/java/android/service/appprediction/AppPredictionService.java
new file mode 100644
index 0000000..b77405a
--- /dev/null
+++ b/core/java/android/service/appprediction/AppPredictionService.java
@@ -0,0 +1,322 @@
+/*
+ * 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.appprediction;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppTargetId;
+import android.app.prediction.IPredictionCallback;
+import android.content.Intent;
+import android.content.pm.ParceledListSlice;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.service.appprediction.IPredictionService.Stub;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * TODO(b/111701043): Add java docs
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class AppPredictionService extends Service {
+
+    private static final String TAG = "AppPredictionService";
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     * TODO(b/111701043): Add any docs about permissions the service must hold
+     *
+     * @hide
+     */
+    public static final String SERVICE_INTERFACE =
+            "android.service.appprediction.AppPredictionService";
+
+    private final ArrayMap<AppPredictionSessionId, ArrayList<CallbackWrapper>> mSessionCallbacks =
+            new ArrayMap<>();
+    private Handler mHandler;
+
+    private final IPredictionService mInterface = new Stub() {
+
+        @Override
+        public void onCreatePredictionSession(AppPredictionContext context,
+                AppPredictionSessionId sessionId) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::doCreatePredictionSession,
+                            AppPredictionService.this, context, sessionId));
+        }
+
+        @Override
+        public void notifyAppTargetEvent(AppPredictionSessionId sessionId, AppTargetEvent event) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::onAppTargetEvent,
+                            AppPredictionService.this, sessionId, event));
+        }
+
+        @Override
+        public void notifyLocationShown(AppPredictionSessionId sessionId, String launchLocation,
+                ParceledListSlice targetIds) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::onLocationShown, AppPredictionService.this,
+                            sessionId, launchLocation, targetIds.getList()));
+        }
+
+        @Override
+        public void sortAppTargets(AppPredictionSessionId sessionId, ParceledListSlice targets,
+                IPredictionCallback callback) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::onSortAppTargets,
+                            AppPredictionService.this, sessionId, targets.getList(), null,
+                            new CallbackWrapper(callback)));
+        }
+
+        @Override
+        public void registerPredictionUpdates(AppPredictionSessionId sessionId,
+                IPredictionCallback callback) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::doRegisterPredictionUpdates,
+                            AppPredictionService.this, sessionId, callback));
+        }
+
+        @Override
+        public void unregisterPredictionUpdates(AppPredictionSessionId sessionId,
+                IPredictionCallback callback) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::doUnregisterPredictionUpdates,
+                            AppPredictionService.this, sessionId, callback));
+        }
+
+        @Override
+        public void requestPredictionUpdate(AppPredictionSessionId sessionId) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::doRequestPredictionUpdate,
+                            AppPredictionService.this, sessionId));
+        }
+
+        @Override
+        public void onDestroyPredictionSession(AppPredictionSessionId sessionId) {
+            mHandler.sendMessage(
+                    obtainMessage(AppPredictionService::doDestroyPredictionSession,
+                            AppPredictionService.this, sessionId));
+        }
+    };
+
+    @CallSuper
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mHandler = new Handler(Looper.getMainLooper(), null, true);
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return mInterface.asBinder();
+    }
+
+    /**
+     * Called by a client app to indicate a target launch
+     */
+    @MainThread
+    public abstract void onAppTargetEvent(@NonNull AppPredictionSessionId sessionId,
+            @NonNull AppTargetEvent event);
+
+    /**
+     * Called by a client app to indication a particular location has been shown to the user.
+     */
+    @MainThread
+    public abstract void onLocationShown(@NonNull AppPredictionSessionId sessionId,
+            @NonNull String launchLocation, @NonNull List<AppTargetId> targetIds);
+
+    private void doCreatePredictionSession(@NonNull AppPredictionContext context,
+            @NonNull AppPredictionSessionId sessionId) {
+        mSessionCallbacks.put(sessionId, new ArrayList<>());
+        onCreatePredictionSession(context, sessionId);
+    }
+
+    /**
+     * Creates a new interaction session.
+     *
+     * @param context interaction context
+     * @param sessionId the session's Id
+     */
+    public void onCreatePredictionSession(@NonNull AppPredictionContext context,
+            @NonNull AppPredictionSessionId sessionId) {}
+
+    /**
+     * Called by the client app to request sorting of targets based on prediction rank.
+     * TODO(b/111701043): Implement CancellationSignal so caller can cancel a long running request
+     */
+    @MainThread
+    public abstract void onSortAppTargets(@NonNull AppPredictionSessionId sessionId,
+            @NonNull List<AppTarget> targets, @NonNull CancellationSignal cancellationSignal,
+            @NonNull Consumer<List<AppTarget>> callback);
+
+    private void doRegisterPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+            @NonNull IPredictionCallback callback) {
+        final ArrayList<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
+        if (callbacks == null) {
+            Slog.e(TAG, "Failed to register for updates for unknown session: " + sessionId);
+            return;
+        }
+
+        final CallbackWrapper wrapper = findCallbackWrapper(callbacks, callback);
+        if (wrapper == null) {
+            callbacks.add(new CallbackWrapper(callback));
+            if (callbacks.size() == 1) {
+                onStartPredictionUpdates();
+            }
+        }
+    }
+
+    /**
+     * Called when any continuous prediction callback is registered.
+     */
+    @MainThread
+    public void onStartPredictionUpdates() {}
+
+    private void doUnregisterPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+            @NonNull IPredictionCallback callback) {
+        final ArrayList<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
+        if (callbacks == null) {
+            Slog.e(TAG, "Failed to unregister for updates for unknown session: " + sessionId);
+            return;
+        }
+
+        final CallbackWrapper wrapper = findCallbackWrapper(callbacks, callback);
+        if (wrapper != null) {
+            callbacks.remove(wrapper);
+            if (callbacks.isEmpty()) {
+                onStopPredictionUpdates();
+            }
+        }
+    }
+
+    /**
+     * Called when there are no longer any continuous prediction callbacks registered.
+     */
+    @MainThread
+    public void onStopPredictionUpdates() {}
+
+    private void doRequestPredictionUpdate(@NonNull AppPredictionSessionId sessionId) {
+        final ArrayList<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
+        if (callbacks != null && !callbacks.isEmpty()) {
+            onRequestPredictionUpdate(sessionId);
+        }
+    }
+
+    /**
+     * Called by the client app to request target predictions. This method is only called if there
+     * are one or more prediction callbacks registered.
+     * TODO(b/111701043): Add java docs
+     *
+     * @see #updatePredictions(AppPredictionSessionId, List)
+     */
+    @MainThread
+    public abstract void onRequestPredictionUpdate(@NonNull AppPredictionSessionId sessionId);
+
+    private void doDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {
+        mSessionCallbacks.remove(sessionId);
+        onDestroyPredictionSession(sessionId);
+    }
+
+    /**
+     * Destroys the interaction session.
+     *
+     * @param sessionId the id of the session to destroy
+     */
+    @MainThread
+    public void onDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {}
+
+    /**
+     * Used by the prediction factory to send back results the client app. The can be called
+     * in response to {@link #onRequestPredictionUpdate(AppPredictionSessionId)} or proactively as
+     * a result of changes in predictions.
+     */
+    public final void updatePredictions(@NonNull AppPredictionSessionId sessionId,
+            @NonNull List<AppTarget> targets) {
+        List<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
+        if (callbacks != null) {
+            for (CallbackWrapper callback : callbacks) {
+                callback.accept(targets);
+            }
+        }
+    }
+
+    /**
+     * Finds the callback wrapper for the given callback.
+     */
+    private CallbackWrapper findCallbackWrapper(ArrayList<CallbackWrapper> callbacks,
+            IPredictionCallback callback) {
+        for (int i = callbacks.size() - 1; i >= 0; i--) {
+            if (callbacks.get(i).isCallback(callback)) {
+                return callbacks.get(i);
+            }
+        }
+        return null;
+    }
+
+    private static final class CallbackWrapper implements Consumer<List<AppTarget>>,
+            IBinder.DeathRecipient {
+
+        private IPredictionCallback mCallback;
+
+        CallbackWrapper(IPredictionCallback callback) {
+            mCallback = callback;
+            try {
+                mCallback.asBinder().linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to link to death: " + e);
+            }
+        }
+
+        public boolean isCallback(@NonNull IPredictionCallback callback) {
+            return mCallback.equals(callback);
+        }
+
+        @Override
+        public void accept(List<AppTarget> ts) {
+            try {
+                if (mCallback != null) {
+                    mCallback.onResult(new ParceledListSlice(ts));
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Error sending result:" + e);
+            }
+        }
+
+        @Override
+        public void binderDied() {
+            mCallback = null;
+        }
+    }
+}
diff --git a/core/java/android/service/appprediction/IPredictionService.aidl b/core/java/android/service/appprediction/IPredictionService.aidl
new file mode 100644
index 0000000..3a6d166
--- /dev/null
+++ b/core/java/android/service/appprediction/IPredictionService.aidl
@@ -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.service.appprediction;
+
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.IPredictionCallback;
+import android.content.pm.ParceledListSlice;
+
+/**
+ * Interface from the system to a prediction service.
+ *
+ * @hide
+ */
+oneway interface IPredictionService {
+
+    void onCreatePredictionSession(in AppPredictionContext context,
+            in AppPredictionSessionId sessionId);
+
+    void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event);
+
+    void notifyLocationShown(in AppPredictionSessionId sessionId,  in String launchLocation,
+            in ParceledListSlice targetIds);
+
+    void sortAppTargets(in AppPredictionSessionId sessionId, in ParceledListSlice targets,
+            in IPredictionCallback callback);
+
+    void registerPredictionUpdates(in AppPredictionSessionId sessionId,
+            in IPredictionCallback callback);
+
+    void unregisterPredictionUpdates(in AppPredictionSessionId sessionId,
+            in IPredictionCallback callback);
+
+    void requestPredictionUpdate(in AppPredictionSessionId sessionId);
+
+    void onDestroyPredictionSession(in AppPredictionSessionId sessionId);
+}
diff --git a/core/java/android/service/attention/AttentionService.java b/core/java/android/service/attention/AttentionService.java
new file mode 100644
index 0000000..f6e448dc
--- /dev/null
+++ b/core/java/android/service/attention/AttentionService.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.attention;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+
+/**
+ * Abstract base class for Attention service.
+ *
+ * <p> An attention service provides attention estimation related features to the system.
+ * The system's default AttentionService implementation is configured in
+ * {@code config_AttentionComponent}. If this config has no value, a stub is returned.
+ *
+ * See: {@link AttentionManagerService}.
+ *
+ * <pre>
+ * {@literal
+ * <service android:name=".YourAttentionService"
+ *          android:permission="android.permission.BIND_ATTENTION_SERVICE">
+ * </service>}
+ * </pre>
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class AttentionService extends Service {
+    /**
+     * The {@link Intent} that must be declared as handled by the service. To be supported, the
+     * service must also require the {@link android.Manifest.permission#BIND_ATTENTION_SERVICE}
+     * permission so that other applications can not abuse it.
+     */
+    public static final String SERVICE_INTERFACE =
+            "android.service.attention.AttentionService";
+
+    /** Attention is absent. */
+    public static final int ATTENTION_SUCCESS_ABSENT = 0;
+
+    /** Attention is present. */
+    public static final int ATTENTION_SUCCESS_PRESENT = 1;
+
+    /** Preempted by other camera user. */
+    public static final int ATTENTION_FAILURE_PREEMPTED = 2;
+
+    /** Preempted by other camera user. */
+    public static final int ATTENTION_FAILURE_TIMED_OUT = 3;
+
+    /** Unknown reasons for failing to determine the attention. */
+    public static final int ATTENTION_FAILURE_UNKNOWN = 4;
+
+    /**
+     * Result codes for when attention check was successful.
+     *
+     * @hide
+     */
+    @IntDef(prefix = {"ATTENTION_SUCCESS_"}, value = {ATTENTION_SUCCESS_ABSENT,
+            ATTENTION_SUCCESS_PRESENT})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AttentionSuccessCodes {
+    }
+
+    /**
+     * Result codes explaining why attention check was not successful.
+     *
+     * @hide
+     */
+    @IntDef(prefix = {"ATTENTION_FAILURE_"}, value = {ATTENTION_FAILURE_PREEMPTED,
+            ATTENTION_FAILURE_TIMED_OUT, ATTENTION_FAILURE_UNKNOWN})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AttentionFailureCodes {
+    }
+
+    private final IAttentionService.Stub mBinder = new IAttentionService.Stub() {
+
+        /** {@inheritDoc} */
+        @Override
+        public void checkAttention(int requestCode, IAttentionCallback callback) {
+            Preconditions.checkNotNull(callback);
+            AttentionService.this.onCheckAttention(requestCode, new AttentionCallback(callback));
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void cancelAttentionCheck(int requestCode) {
+            AttentionService.this.onCancelAttentionCheck(requestCode);
+        }
+    };
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            return mBinder;
+        }
+        return null;
+    }
+
+    /**
+     * Checks the user attention and calls into the provided callback.
+     *
+     * @param requestCode an identifier that could be used to cancel the request
+     * @param callback    the callback to return the result to
+     */
+    public abstract void onCheckAttention(int requestCode, @NonNull AttentionCallback callback);
+
+    /** Cancels the attention check for a given request code. */
+    public abstract void onCancelAttentionCheck(int requestCode);
+
+
+    /** Callbacks for AttentionService results. */
+    public static final class AttentionCallback {
+        private final IAttentionCallback mCallback;
+
+        private AttentionCallback(IAttentionCallback callback) {
+            mCallback = callback;
+        }
+
+        /** Returns the result. */
+        public void onSuccess(int requestCode, @AttentionSuccessCodes int result, long timestamp) {
+            try {
+                mCallback.onSuccess(requestCode, result, timestamp);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+
+        /** Signals a failure. */
+        public void onFailure(int requestCode, @AttentionFailureCodes int error) {
+            try {
+                mCallback.onFailure(requestCode, error);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+    }
+}
diff --git a/core/java/android/service/attention/IAttentionCallback.aidl b/core/java/android/service/attention/IAttentionCallback.aidl
new file mode 100644
index 0000000..0e8a1e7
--- /dev/null
+++ b/core/java/android/service/attention/IAttentionCallback.aidl
@@ -0,0 +1,27 @@
+ /*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.attention;
+
+/**
+ * Callback for onCheckAttention request.
+ *
+ * @hide
+ */
+oneway interface IAttentionCallback {
+    void onSuccess(int requestCode, int result, long timestamp);
+    void onFailure(int requestCode, int error);
+}
diff --git a/core/java/android/service/attention/IAttentionService.aidl b/core/java/android/service/attention/IAttentionService.aidl
new file mode 100644
index 0000000..c3b6f48
--- /dev/null
+++ b/core/java/android/service/attention/IAttentionService.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.attention;
+
+import android.service.attention.IAttentionCallback;
+
+/**
+ * Interface for a concrete implementation to provide to the AttentionManagerService.
+ *
+ * @hide
+ */
+oneway interface IAttentionService {
+    void checkAttention(int requestCode, IAttentionCallback callback);
+    void cancelAttentionCheck(int requestCode);
+}
\ No newline at end of file
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 7683b8a..8e0f522 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.Service;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -41,6 +42,7 @@
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAugmentedAutofillManagerClient;
+import android.view.autofill.IAutofillWindowPresenter;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -58,11 +60,14 @@
  * @hide
  */
 @SystemApi
+@TestApi
+// TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
+// in the same package as the test, and that module is compiled with SDK=test_current
 public abstract class AugmentedAutofillService extends Service {
 
     private static final String TAG = AugmentedAutofillService.class.getSimpleName();
 
-    // TODO(b/111330312): STOPSHIP use dynamic value, or change to false
+    // TODO(b/123100811): STOPSHIP use dynamic value, or change to false
     static final boolean DEBUG = true;
     static final boolean VERBOSE = false;
 
@@ -91,10 +96,10 @@
         }
 
         @Override
-        public void onDestroyFillWindowRequest(int sessionId) {
+        public void onDestroyAllFillWindowsRequest() {
             mHandler.sendMessage(
-                    obtainMessage(AugmentedAutofillService::handleOnDestroyFillWindowRequest,
-                            AugmentedAutofillService.this, sessionId));
+                    obtainMessage(AugmentedAutofillService::handleOnDestroyAllFillWindowsRequest,
+                            AugmentedAutofillService.this));
         }
     };
 
@@ -122,8 +127,6 @@
         return false;
     }
 
-    // TODO(b/111330312): add methods to disable autofill per app / activity?
-
     /**
      * Asks the service to handle an "augmented" autofill request.
      *
@@ -170,29 +173,31 @@
                     focusedValue, requestTime, callback);
             mAutofillProxies.put(sessionId,  proxy);
         } else {
-            // TODO(b/111330312): figure out if it's ok to reuse the proxy; add logging
-            // TODO(b/111330312): also make sure to cover scenario on CTS test
+            // TODO(b/123099468): figure out if it's ok to reuse the proxy; add logging
             if (DEBUG) Log.d(TAG, "Reusing proxy for session " + sessionId);
             proxy.update(focusedId, focusedValue);
         }
-        // TODO(b/111330312): set cancellation signal
+        // TODO(b/123101711): set cancellation signal
         final CancellationSignal cancellationSignal = null;
         onFillRequest(new FillRequest(proxy), cancellationSignal, new FillController(proxy),
                 new FillCallback(proxy));
     }
 
-    private void handleOnDestroyFillWindowRequest(@NonNull int sessionId) {
-        AutofillProxy proxy = null;
+    private void handleOnDestroyAllFillWindowsRequest() {
         if (mAutofillProxies != null) {
-            proxy = mAutofillProxies.get(sessionId);
+            final int size = mAutofillProxies.size();
+            for (int i = 0; i < size; i++) {
+                final int sessionId = mAutofillProxies.keyAt(i);
+                final AutofillProxy proxy = mAutofillProxies.valueAt(i);
+                if (proxy == null) {
+                    // TODO(b/123100811): this might be fine, in which case we should logv it
+                    Log.w(TAG, "No proxy for session " + sessionId);
+                    return;
+                }
+                proxy.destroy();
+            }
+            mAutofillProxies.clear();
         }
-        if (proxy == null) {
-            // TODO(b/111330312): this might be fine, in which case we should logv it
-            Log.w(TAG, "No proxy for session " + sessionId);
-            return;
-        }
-        proxy.destroy();
-        mAutofillProxies.remove(sessionId);
     }
 
     private void handleOnUnbind() {
@@ -214,7 +219,7 @@
     }
 
     @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    protected final void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mAutofillProxies != null) {
             final int size = mAutofillProxies.size();
             pw.print("Number proxies: "); pw.println(size);
@@ -225,6 +230,15 @@
                 proxy.dump("  ", pw);
             }
         }
+        dump(pw, args);
+    }
+
+    /**
+     * Implementation specific {@code dump}.
+     */
+    protected void dump(@NonNull PrintWriter pw,
+            @SuppressWarnings("unused") @NonNull String[] args) {
+        pw.print(getClass().getName()); pw.println(": nothing to dump");
     }
 
     /** @hide */
@@ -259,7 +273,6 @@
          *
          * <p>Used to make sure the SmartSuggestionsParams is updated when a new fields is focused.
          */
-        // TODO(b/111330312): might not be needed when using IME
         @GuardedBy("mLock")
         private AutofillId mLastShownId;
 
@@ -287,7 +300,7 @@
             this.mFocusedId = focusedId;
             this.mFocusedValue = focusedValue;
             this.mRequestTime = requestTime;
-            // TODO(b/111330312): linkToDeath
+            // TODO(b/123099468): linkToDeath
         }
 
         @NonNull
@@ -338,9 +351,19 @@
             }
         }
 
+        public void requestShowFillUi(int width, int height, Rect anchorBounds,
+                IAutofillWindowPresenter presenter) throws RemoteException {
+            mClient.requestShowFillUi(mSessionId, mFocusedId, width, height, anchorBounds,
+                    presenter);
+        }
+
+        public void requestHideFillUi() throws RemoteException {
+            mClient.requestHideFillUi(mSessionId, mFocusedId);
+        }
+
         private void update(@NonNull AutofillId focusedId, @NonNull AutofillValue focusedValue) {
             synchronized (mLock) {
-                // TODO(b/111330312): should we close the popupwindow if the focused id changed?
+                // TODO(b/123099468): should we close the popupwindow if the focused id changed?
                 mFocusedId = focusedId;
                 mFocusedValue = focusedValue;
             }
@@ -399,7 +422,7 @@
                 default:
                     Slog.w(TAG, "invalid event reported: " + event);
             }
-            // TODO(b/111330312): log metrics as well
+            // TODO(b/122858578): log metrics as well
         }
 
         public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java
index 620ec59..f2a7a35 100644
--- a/core/java/android/service/autofill/augmented/FillCallback.java
+++ b/core/java/android/service/autofill/augmented/FillCallback.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
 import android.util.Log;
 
@@ -29,6 +30,9 @@
  * @hide
  */
 @SystemApi
+@TestApi
+//TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
+//in the same package as the test, and that module is compiled with SDK=test_current
 public final class FillCallback {
 
     private static final String TAG = FillCallback.class.getSimpleName();
@@ -55,7 +59,8 @@
         if (fillWindow != null) {
             fillWindow.show();
         }
-        // TODO(b/111330312): properly implement on server-side by updating the Session state
-        // accordingly (and adding CTS tests)
+        // TODO(b/123099468): must notify the server so it can update the session state to avoid
+        // showing conflicting UIs (for example, if a new request is made to the main autofill
+        // service and it now wants to show something).
     }
 }
diff --git a/core/java/android/service/autofill/augmented/FillController.java b/core/java/android/service/autofill/augmented/FillController.java
index e65cf47..d7bc893 100644
--- a/core/java/android/service/autofill/augmented/FillController.java
+++ b/core/java/android/service/autofill/augmented/FillController.java
@@ -19,6 +19,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.RemoteException;
 import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
 import android.util.Log;
@@ -36,6 +37,9 @@
  * @hide
  */
 @SystemApi
+@TestApi
+//TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
+//in the same package as the test, and that module is compiled with SDK=test_current
 public final class FillController {
     private static final String TAG = "FillController";
 
diff --git a/core/java/android/service/autofill/augmented/FillRequest.java b/core/java/android/service/autofill/augmented/FillRequest.java
index 57d2cc8..af9905f 100644
--- a/core/java/android/service/autofill/augmented/FillRequest.java
+++ b/core/java/android/service/autofill/augmented/FillRequest.java
@@ -18,6 +18,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.content.ComponentName;
 import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
 import android.view.autofill.AutofillId;
@@ -28,7 +29,10 @@
  * @hide
  */
 @SystemApi
-// TODO(b/111330312): pass a requestId and/or sessionId
+// TODO(b/123100811): pass a requestId and/or sessionId?
+@TestApi
+// TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
+// in the same package as the test, and that module is compiled with SDK=test_current
 public final class FillRequest {
 
     final AutofillProxy mProxy;
diff --git a/core/java/android/service/autofill/augmented/FillResponse.java b/core/java/android/service/autofill/augmented/FillResponse.java
index 1ecfab4..f1e904a 100644
--- a/core/java/android/service/autofill/augmented/FillResponse.java
+++ b/core/java/android/service/autofill/augmented/FillResponse.java
@@ -18,8 +18,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
+import android.annotation.TestApi;
 import android.view.autofill.AutofillId;
 
 import java.util.List;
@@ -30,7 +29,10 @@
  * @hide
  */
 @SystemApi
-public final class FillResponse implements Parcelable {
+@TestApi
+//TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
+//in the same package as the test, and that module is compiled with SDK=test_current
+public final class FillResponse {
 
     private final FillWindow mFillWindow;
 
@@ -50,6 +52,9 @@
      * @hide
      */
     @SystemApi
+    @TestApi
+    //TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
+    //in the same package as the test, and that module is compiled with SDK=test_current
     public static final class Builder {
 
         private FillWindow mFillWindow;
@@ -63,8 +68,8 @@
          * @return this builder
          */
         public Builder setFillWindow(@NonNull FillWindow fillWindow) {
-            // TODO(b/111330312): implement / check not null / unit test
-            // TODO(b/111330312): throw exception if FillWindow not updated yet
+            // TODO(b/123100712): check not null / unit test / throw exception if FillWindow not
+            // updated yet
             mFillWindow = fillWindow;
             return this;
         }
@@ -78,7 +83,7 @@
          * @return this builder
          */
         public Builder setIgnoredIds(@NonNull List<AutofillId> ids) {
-            // TODO(b/111330312): implement / check not null / unit test
+            // TODO(b/123100695): implement / check not null / unit test
             return this;
         }
 
@@ -95,37 +100,10 @@
          * @return A built response.
          */
         public FillResponse build() {
-            // TODO(b/111330312): check conditions / add unit test
+            // TODO(b/123100712): check conditions / add unit test
             return new FillResponse(this);
         }
-
-        // TODO(b/111330312): add methods to disable app / activity, either here or on manager
     }
 
-    // TODO(b/111330312): implement to String
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        // TODO(b/111330312): implement
-    }
-
-    public static final Parcelable.Creator<FillResponse> CREATOR =
-            new Parcelable.Creator<FillResponse>() {
-
-                @Override
-                public FillResponse createFromParcel(Parcel parcel) {
-                    // TODO(b/111330312): implement
-                    return null;
-                }
-
-                @Override
-                public FillResponse[] newArray(int size) {
-                    return new FillResponse[size];
-                }
-    };
+    // TODO(b/123100811): implement to String
 }
diff --git a/core/java/android/service/autofill/augmented/FillWindow.java b/core/java/android/service/autofill/augmented/FillWindow.java
index bad7ddd..40e3a12 100644
--- a/core/java/android/service/autofill/augmented/FillWindow.java
+++ b/core/java/android/service/autofill/augmented/FillWindow.java
@@ -16,21 +16,24 @@
 package android.service.autofill.augmented;
 
 import static android.service.autofill.augmented.AugmentedAutofillService.DEBUG;
+import static android.service.autofill.augmented.AugmentedAutofillService.VERBOSE;
 
-import android.annotation.LongDef;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.app.Dialog;
+import android.annotation.TestApi;
 import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
 import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
 import android.service.autofill.augmented.PresentationParams.Area;
 import android.util.Log;
-import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
 import android.view.WindowManager;
+import android.view.autofill.IAutofillWindowPresenter;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
@@ -38,8 +41,6 @@
 import dalvik.system.CloseGuard;
 
 import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 
 /**
  * Handle to a window used to display the augmented autofill UI.
@@ -61,26 +62,26 @@
  * @hide
  */
 @SystemApi
+@TestApi
+//TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
+//in the same package as the test, and that module is compiled with SDK=test_current
 public final class FillWindow implements AutoCloseable {
     private static final String TAG = "FillWindow";
 
-    /** Indicates the data being shown is a physical address */
-    public static final long FLAG_METADATA_ADDRESS = 0x1;
-
-    // TODO(b/111330312): add moar flags
-
-    /** @hide */
-    @LongDef(prefix = { "FLAG" }, value = {
-            FLAG_METADATA_ADDRESS,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    @interface Flags{}
-
     private final Object mLock = new Object();
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
+    private final @NonNull Handler mUiThreadHandler = new Handler(Looper.getMainLooper());
+    private final @NonNull FillWindowPresenter mFillWindowPresenter = new FillWindowPresenter();
+
     @GuardedBy("mLock")
-    private Dialog mDialog;
+    private WindowManager mWm;
+    @GuardedBy("mLock")
+    private View mFillView;
+    @GuardedBy("mLock")
+    private boolean mShowing;
+    @GuardedBy("mLock")
+    private Rect mBounds;
 
     @GuardedBy("mLock")
     private boolean mDestroyed;
@@ -92,29 +93,22 @@
      *
      * @param rootView new root view
      * @param area coordinates to render the view.
-     * @param flags optional flags such as metadata of what will be rendered in the window. The
-     * Smart Suggestion host might decide whether or not to render the UI based on them.
+     * @param flags currently not used.
      *
      * @return boolean whether the window was updated or not.
      *
      * @throws IllegalArgumentException if the area is not compatible with this window
      */
-    public boolean update(@NonNull Area area, @NonNull View rootView, @Flags long flags) {
+    public boolean update(@NonNull Area area, @NonNull View rootView, long flags) {
         if (DEBUG) {
             Log.d(TAG, "Updating " + area + " + with " + rootView);
         }
-        // TODO(b/111330312): add test case for null
+        // TODO(b/123100712): add test case for null
         Preconditions.checkNotNull(area);
         Preconditions.checkNotNull(rootView);
-        // TODO(b/111330312): must check the area is a valid object returned by
+        // TODO(b/123100712): must check the area is a valid object returned by
         // SmartSuggestionParams, throw IAE if not
 
-        // TODO(b/111330312): must some how pass metadata to the SmartSuggestiongs provider
-
-
-        // TODO(b/111330312): use a SurfaceControl approach; for now, we're manually creating
-        // the window underneath the existing view.
-
         final PresentationParams smartSuggestion = area.proxy.getSmartSuggestionParams();
         if (smartSuggestion == null) {
             Log.w(TAG, "No SmartSuggestionParams");
@@ -132,55 +126,32 @@
 
             mProxy = area.proxy;
 
-            // TODO(b/111330312): once we have the SurfaceControl approach, we should update the
+            // TODO(b/123227534): once we have the SurfaceControl approach, we should update the
             // window instead of destroying. In fact, it might be better to allocate a full window
             // initially, which is transparent (and let touches get through) everywhere but in the
             // rect boundaries.
-            destroy();
 
-            // TODO(b/111330312): make sure all touch events are handled, window is always closed,
+            // TODO(b/123099468): make sure all touch events are handled, window is always closed,
             // etc.
 
-            mDialog = new Dialog(rootView.getContext()) {
-                @Override
-                public boolean onTouchEvent(MotionEvent event) {
-                    if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
-                        FillWindow.this.destroy();
+            mWm = rootView.getContext().getSystemService(WindowManager.class);
+            mFillView = rootView;
+            // Listen to the touch outside to destroy the window when typing is detected.
+            mFillView.setOnTouchListener(
+                    (view, motionEvent) -> {
+                        if (motionEvent.getAction() == MotionEvent.ACTION_OUTSIDE) {
+                            if (VERBOSE) Log.v(TAG, "Outside touch detected, hiding the window");
+                            hide();
+                        }
+                        return false;
                     }
-                    return false;
-                }
-            };
-            mCloseGuard.open("destroy");
-            final Window window = mDialog.getWindow();
-            window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
-            // Makes sure touch outside the dialog is received by the window behind the dialog.
-            window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
-            // Makes sure the touch outside the dialog is received by the dialog to dismiss it.
-            window.addFlags(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
-            // Makes sure keyboard shows up.
-            window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-
-            final int height = rect.bottom - rect.top;
-            final int width = rect.right - rect.left;
-            final WindowManager.LayoutParams windowParams = window.getAttributes();
-            windowParams.gravity = Gravity.TOP | Gravity.LEFT;
-            windowParams.y = rect.top + height;
-            windowParams.height = height;
-            windowParams.x = rect.left;
-            windowParams.width = width;
-
-            window.setAttributes(windowParams);
-            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
-            window.setBackgroundDrawableResource(android.R.color.transparent);
-
-            mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
-            final ViewGroup.LayoutParams diagParams = new ViewGroup.LayoutParams(width, height);
-            mDialog.setContentView(rootView, diagParams);
-
+            );
+            mShowing = false;
+            mBounds = new Rect(area.getBounds());
             if (DEBUG) {
                 Log.d(TAG, "Created FillWindow: params= " + smartSuggestion + " view=" + rootView);
             }
-
+            mDestroyed = false;
             mProxy.setFillWindow(this);
             return true;
         }
@@ -188,38 +159,89 @@
 
     /** @hide */
     void show() {
-        // TODO(b/111330312): check if updated first / throw exception
+        // TODO(b/123100712): check if updated first / throw exception
         if (DEBUG) Log.d(TAG, "show()");
-
         synchronized (mLock) {
             checkNotDestroyedLocked();
-            if (mDialog == null) {
+            if (mWm == null || mFillView == null) {
                 throw new IllegalStateException("update() not called yet, or already destroyed()");
             }
-
-            mDialog.show();
             if (mProxy != null) {
+                try {
+                    mProxy.requestShowFillUi(mBounds.right - mBounds.left,
+                            mBounds.bottom - mBounds.top,
+                            /*anchorBounds=*/ null, mFillWindowPresenter);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Error requesting to show fill window", e);
+                }
                 mProxy.report(AutofillProxy.REPORT_EVENT_UI_SHOWN);
             }
         }
     }
 
     /**
+     * Hides the window.
+     *
+     * <p>The window is not destroyed and can be shown again
+     */
+    private void hide() {
+        if (DEBUG) Log.d(TAG, "hide()");
+        synchronized (mLock) {
+            checkNotDestroyedLocked();
+            if (mWm == null || mFillView == null) {
+                throw new IllegalStateException("update() not called yet, or already destroyed()");
+            }
+            if (mProxy != null && mShowing) {
+                try {
+                    mProxy.requestHideFillUi();
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Error requesting to hide fill window", e);
+                }
+            }
+        }
+    }
+
+    private void handleShow(WindowManager.LayoutParams p) {
+        if (DEBUG) Log.d(TAG, "handleShow()");
+        synchronized (mLock) {
+            if (mWm != null && mFillView != null) {
+                p.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+                if (!mShowing) {
+                    mWm.addView(mFillView, p);
+                    mShowing = true;
+                } else {
+                    mWm.updateViewLayout(mFillView, p);
+                }
+            }
+        }
+    }
+
+    private void handleHide() {
+        if (DEBUG) Log.d(TAG, "handleHide()");
+        synchronized (mLock) {
+            if (mWm != null && mFillView != null && mShowing) {
+                mWm.removeView(mFillView);
+                mShowing = false;
+            }
+        }
+    }
+
+    /**
      * Destroys the window.
      *
      * <p>Once destroyed, this window cannot be used anymore
      */
     public void destroy() {
-        if (DEBUG) Log.d(TAG, "destroy(): mDestroyed=" + mDestroyed + " mDialog=" + mDialog);
-
-        synchronized (this) {
-            if (mDestroyed || mDialog == null) return;
-
-            mDialog.dismiss();
-            mDialog = null;
-            if (mProxy != null) {
-                mProxy.report(AutofillProxy.REPORT_EVENT_UI_DESTROYED);
-            }
+        if (DEBUG) {
+            Log.d(TAG,
+                    "destroy(): mDestroyed=" + mDestroyed + " mShowing=" + mShowing + " mFillView="
+                            + mFillView);
+        }
+        synchronized (mLock) {
+            if (mDestroyed) return;
+            hide();
+            mProxy.report(AutofillProxy.REPORT_EVENT_UI_DESTROYED);
+            mDestroyed = true;
             mCloseGuard.close();
         }
     }
@@ -246,11 +268,15 @@
     public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
         synchronized (this) {
             pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed);
-            if (mDialog != null) {
-                pw.print(prefix); pw.print("dialog: ");
-                pw.println(mDialog.isShowing() ? "shown" : "hidden");
-                pw.print(prefix); pw.print("window: ");
-                pw.println(mDialog.getWindow().getAttributes());
+            if (mFillView != null) {
+                pw.print(prefix); pw.print("fill window: ");
+                pw.println(mShowing ? "shown" : "hidden");
+                pw.print(prefix); pw.print("fill view: ");
+                pw.println(mFillView);
+                pw.print(prefix); pw.print("mBounds: ");
+                pw.println(mBounds);
+                pw.print(prefix); pw.print("mWm: ");
+                pw.println(mWm);
             }
         }
     }
@@ -260,4 +286,19 @@
     public void close() throws Exception {
         destroy();
     }
+
+    private final class FillWindowPresenter extends IAutofillWindowPresenter.Stub {
+        @Override
+        public void show(WindowManager.LayoutParams p, Rect transitionEpicenter,
+                boolean fitsSystemWindows, int layoutDirection) {
+            if (DEBUG) Log.d(TAG, "FillWindowPresenter.show()");
+            mUiThreadHandler.sendMessage(obtainMessage(FillWindow::handleShow, FillWindow.this, p));
+        }
+
+        @Override
+        public void hide(Rect transitionEpicenter) {
+            if (DEBUG) Log.d(TAG, "FillWindowPresenter.hide()");
+            mUiThreadHandler.sendMessage(obtainMessage(FillWindow::handleHide, FillWindow.this));
+        }
+    }
 }
diff --git a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
index b3ac2da..fb6912a 100644
--- a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
+++ b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
@@ -36,5 +36,5 @@
                        in ComponentName activityComponent, in AutofillId focusedId,
                        in AutofillValue focusedValue, long requestTime, in IFillCallback callback);
 
-    void onDestroyFillWindowRequest(int sessionId);
+    void onDestroyAllFillWindowsRequest();
 }
diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl
index dac7590..2b072664 100644
--- a/core/java/android/service/autofill/augmented/IFillCallback.aidl
+++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl
@@ -24,8 +24,7 @@
  * @hide
  */
 interface IFillCallback {
-    // TODO(b/111330312): add cancellation (after we have CTS tests, so we can test it)
+    // TODO(b/123101711): add cancellation (after we have CTS tests, so we can test it)
 //    void onCancellable(in ICancellationSignal cancellation);
-    // TODO(b/111330312): might need to pass the response (once IME implements Smart Suggestions)
     void onSuccess();
 }
diff --git a/core/java/android/service/autofill/augmented/PresentationParams.java b/core/java/android/service/autofill/augmented/PresentationParams.java
index 0124ecc..1fb9032 100644
--- a/core/java/android/service/autofill/augmented/PresentationParams.java
+++ b/core/java/android/service/autofill/augmented/PresentationParams.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.graphics.Rect;
 import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
 import android.util.DebugUtils;
@@ -48,6 +49,9 @@
  * @hide
  */
 @SystemApi
+@TestApi
+//TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
+//in the same package as the test, and that module is compiled with SDK=test_current
 public abstract class PresentationParams {
 
     /**
@@ -147,8 +151,11 @@
      * Area associated with a {@link PresentationParams Smart Suggestions} provider.
      *
      * @hide
-     * */
+     */
     @SystemApi
+    @TestApi
+    //TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
+    //in the same package as the test, and that module is compiled with SDK=test_current
     public abstract static class Area {
 
         /** @hide */
@@ -183,7 +190,7 @@
          */
         @Nullable
         public Area getSubArea(@NonNull Rect bounds) {
-            // TODO(b/111330312): implement / check boundaries / throw IAE / add unit test
+            // TODO(b/123100712): implement / check boundaries / throw IAE / add unit test
             return null;
         }
 
diff --git a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
index 784e719..db242a2 100644
--- a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
+++ b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
@@ -34,7 +34,7 @@
 @SystemApi
 @Deprecated
 public final class ContentCaptureEventsRequest implements Parcelable {
-// TODO(b/121033016): remove .java and .aidl once service implementation doesn't use it anymore
+// TODO(b/121051220): remove .java and .aidl once service implementation doesn't use it anymore
 
     private final ContentCaptureEvent mEvent;
 
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index c9d46dd..020de7f 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -42,11 +42,13 @@
 import android.view.contentcapture.ContentCaptureSessionId;
 import android.view.contentcapture.IContentCaptureDirectManager;
 import android.view.contentcapture.MainContentCaptureSession;
+import android.view.contentcapture.UserDataRemovalRequest;
 
 import com.android.internal.os.IResultReceiver;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -76,6 +78,7 @@
             "android.service.contentcapture.ContentCaptureService";
 
     private Handler mHandler;
+    private IContentCaptureServiceCallback mCallback;
 
     /**
      * Binder that receives calls from the system server.
@@ -83,9 +86,15 @@
     private final IContentCaptureService mServerInterface = new IContentCaptureService.Stub() {
 
         @Override
-        public void onConnectedStateChanged(boolean state) {
-            mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnConnectedStateChanged,
-                    ContentCaptureService.this, state));
+        public void onConnected(IBinder callback) {
+            mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnConnected,
+                    ContentCaptureService.this, callback));
+        }
+
+        @Override
+        public void onDisconnected() {
+            mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnDisconnected,
+                    ContentCaptureService.this));
         }
 
         @Override
@@ -107,6 +116,13 @@
             mHandler.sendMessage(obtainMessage(ContentCaptureService::handleFinishSession,
                     ContentCaptureService.this, sessionId));
         }
+
+        @Override
+        public void onUserDataRemovalRequest(UserDataRemovalRequest request) {
+            mHandler.sendMessage(
+                    obtainMessage(ContentCaptureService::handleOnUserDataRemovalRequest,
+                            ContentCaptureService.this, request));
+        }
     };
 
     /**
@@ -123,12 +139,12 @@
     };
 
     /**
-     * List of sessions per UID.
+     * UIDs associated with each session.
      *
      * <p>This map is populated when an session is started, which is called by the system server
      * and can be trusted. Then subsequent calls made by the app are verified against this map.
      */
-    private final ArrayMap<String, Integer> mSessionsByUid = new ArrayMap<>();
+    private final ArrayMap<String, Integer> mSessionUids = new ArrayMap<>();
 
     @CallSuper
     @Override
@@ -165,7 +181,16 @@
      */
     public final void setContentCaptureWhitelist(@Nullable List<String> packages,
             @Nullable List<ComponentName> activities) {
-        //TODO(b/111276913): implement
+        final IContentCaptureServiceCallback callback = mCallback;
+        if (callback == null) {
+            Log.w(TAG, "setContentCaptureWhitelist(): no server callback");
+            return;
+        }
+        try {
+            callback.setContentCaptureWhitelist(packages, activities);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -176,7 +201,16 @@
      */
     public final void setActivityContentCaptureEnabled(@NonNull ComponentName activity,
             boolean enabled) {
-        //TODO(b/111276913): implement
+        final IContentCaptureServiceCallback callback = mCallback;
+        if (callback == null) {
+            Log.w(TAG, "setActivityContentCaptureEnabled(): no server callback");
+            return;
+        }
+        try {
+            callback.setActivityContentCaptureEnabled(activity, enabled);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -187,7 +221,16 @@
      */
     public final void setPackageContentCaptureEnabled(@NonNull String packageName,
             boolean enabled) {
-        //TODO(b/111276913): implement
+        final IContentCaptureServiceCallback callback = mCallback;
+        if (callback == null) {
+            Log.w(TAG, "setPackageContentCaptureEnabled(): no server callback");
+            return;
+        }
+        try {
+            callback.setPackageContentCaptureEnabled(packageName, enabled);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -196,7 +239,12 @@
      */
     @NonNull
     public final Set<ComponentName> getContentCaptureDisabledActivities() {
-        //TODO(b/111276913): implement
+        final IContentCaptureServiceCallback callback = mCallback;
+        if (callback == null) {
+            Log.w(TAG, "getContentCaptureDisabledActivities(): no server callback");
+            return Collections.emptySet();
+        }
+        //TODO(b/122595322): implement (using SyncResultReceiver)
         return null;
     }
 
@@ -206,7 +254,12 @@
      */
     @NonNull
     public final Set<String> getContentCaptureDisabledPackages() {
-        //TODO(b/111276913): implement
+        final IContentCaptureServiceCallback callback = mCallback;
+        if (callback == null) {
+            Log.w(TAG, "getContentCaptureDisabledPackages(): no server callback");
+            return Collections.emptySet();
+        }
+        //TODO(b/122595322): implement (using SyncResultReceiver)
         return null;
     }
 
@@ -255,6 +308,16 @@
         if (VERBOSE) Log.v(TAG, "onContentCaptureEventsRequest(id=" + sessionId + ")");
         onContentCaptureEventsRequest(sessionId, new ContentCaptureEventsRequest(event));
     }
+
+    /**
+     * Notifies the service that the app requested to remove data associated with the user.
+     *
+     * @param request the user data requested to be removed
+     */
+    public void onUserDataRemovalRequest(@NonNull UserDataRemovalRequest request) {
+        if (VERBOSE) Log.v(TAG, "onUserDataRemovalRequest()");
+    }
+
     /**
      * Notifies the service of {@link SnapshotData snapshot data} associated with a session.
      *
@@ -285,23 +348,25 @@
     @Override
     @CallSuper
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        final int size = mSessionsByUid.size();
+        final int size = mSessionUids.size();
         pw.print("Number sessions: "); pw.println(size);
         if (size > 0) {
             final String prefix = "  ";
             for (int i = 0; i < size; i++) {
-                pw.print(prefix); pw.print(mSessionsByUid.keyAt(i));
-                pw.print(": uid="); pw.println(mSessionsByUid.valueAt(i));
+                pw.print(prefix); pw.print(mSessionUids.keyAt(i));
+                pw.print(": uid="); pw.println(mSessionUids.valueAt(i));
             }
         }
     }
 
-    private void handleOnConnectedStateChanged(boolean state) {
-        if (state) {
-            onConnected();
-        } else {
-            onDisconnected();
-        }
+    private void handleOnConnected(@NonNull IBinder callback) {
+        mCallback = IContentCaptureServiceCallback.Stub.asInterface(callback);
+        onConnected();
+    }
+
+    private void handleOnDisconnected() {
+        onDisconnected();
+        mCallback = null;
     }
 
     //TODO(b/111276913): consider caching the InteractionSessionId for the lifetime of the session,
@@ -309,10 +374,24 @@
 
     private void handleOnCreateSession(@NonNull ContentCaptureContext context,
             @NonNull String sessionId, int uid, IResultReceiver clientReceiver) {
-        mSessionsByUid.put(sessionId, uid);
+        mSessionUids.put(sessionId, uid);
         onCreateContentCaptureSession(context, new ContentCaptureSessionId(sessionId));
-        setClientState(clientReceiver, ContentCaptureSession.STATE_ACTIVE,
-                mClientInterface.asBinder());
+
+        final int clientFlags = context.getFlags();
+        int stateFlags = 0;
+        if ((clientFlags & ContentCaptureContext.FLAG_DISABLED_BY_FLAG_SECURE) != 0) {
+            stateFlags |= ContentCaptureSession.STATE_FLAG_SECURE;
+        }
+        if ((clientFlags & ContentCaptureContext.FLAG_DISABLED_BY_APP) != 0) {
+            stateFlags |= ContentCaptureSession.STATE_BY_APP;
+        }
+        if (stateFlags == 0) {
+            stateFlags = ContentCaptureSession.STATE_ACTIVE;
+        } else {
+            stateFlags |= ContentCaptureSession.STATE_DISABLED;
+
+        }
+        setClientState(clientReceiver, stateFlags, mClientInterface.asBinder());
     }
 
     private void handleSendEvents(int uid,
@@ -336,11 +415,11 @@
                 case ContentCaptureEvent.TYPE_SESSION_STARTED:
                     final ContentCaptureContext clientContext = event.getClientContext();
                     clientContext.setParentSessionId(event.getParentSessionId());
-                    mSessionsByUid.put(sessionIdString, uid);
+                    mSessionUids.put(sessionIdString, uid);
                     onCreateContentCaptureSession(clientContext, sessionId);
                     break;
                 case ContentCaptureEvent.TYPE_SESSION_FINISHED:
-                    mSessionsByUid.remove(sessionIdString);
+                    mSessionUids.remove(sessionIdString);
                     onDestroyContentCaptureSession(sessionId);
                     break;
                 default:
@@ -355,10 +434,14 @@
     }
 
     private void handleFinishSession(@NonNull String sessionId) {
-        mSessionsByUid.remove(sessionId);
+        mSessionUids.remove(sessionId);
         onDestroyContentCaptureSession(new ContentCaptureSessionId(sessionId));
     }
 
+    private void handleOnUserDataRemovalRequest(@NonNull UserDataRemovalRequest request) {
+        onUserDataRemovalRequest(request);
+    }
+
     /**
      * Checks if the given {@code uid} owns the session associated with the event.
      */
@@ -372,10 +455,13 @@
             default:
                 sessionId = event.getSessionId();
         }
-        final Integer rightUid = mSessionsByUid.get(sessionId);
+        final Integer rightUid = mSessionUids.get(sessionId);
         if (rightUid == null) {
-            if (VERBOSE) Log.v(TAG, "No session for " + sessionId);
-            // Just ignore, as the session could have finished
+            if (DEBUG) {
+                Log.d(TAG, "handleIsRightCallerFor(" + event + "): no session for " + sessionId
+                        + ": " + mSessionUids);
+            }
+            // Just ignore, as the session could have been finished already
             return false;
         }
         if (rightUid != uid) {
@@ -389,15 +475,16 @@
     }
 
     /**
-     * Sends the state of the {@link ContentCaptureManager} in the cleint app.
+     * Sends the state of the {@link ContentCaptureManager} in the client app.
      *
      * @param clientReceiver receiver in the client app.
+     * @param sessionState state of the session
      * @param binder handle to the {@code IContentCaptureDirectManager} object that resides in the
      * service.
      * @hide
      */
     public static void setClientState(@NonNull IResultReceiver clientReceiver,
-            int sessionStatus, @Nullable IBinder binder) {
+            int sessionState, @Nullable IBinder binder) {
         try {
             final Bundle extras;
             if (binder != null) {
@@ -406,7 +493,7 @@
             } else {
                 extras = null;
             }
-            clientReceiver.send(sessionStatus, extras);
+            clientReceiver.send(sessionState, extras);
         } catch (RemoteException e) {
             Slog.w(TAG, "Error async reporting result to client: " + e);
         }
diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl
index 1b4cccf..d92fb3b 100644
--- a/core/java/android/service/contentcapture/IContentCaptureService.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl
@@ -16,8 +16,10 @@
 
 package android.service.contentcapture;
 
+import android.os.IBinder;
 import android.service.contentcapture.SnapshotData;
 import android.view.contentcapture.ContentCaptureContext;
+import android.view.contentcapture.UserDataRemovalRequest;
 
 import com.android.internal.os.IResultReceiver;
 
@@ -29,9 +31,11 @@
  * @hide
  */
 oneway interface IContentCaptureService {
-    void onConnectedStateChanged(boolean state);
+    void onConnected(IBinder callback);
+    void onDisconnected();
     void onSessionStarted(in ContentCaptureContext context, String sessionId, int uid,
                           in IResultReceiver clientReceiver);
     void onSessionFinished(String sessionId);
     void onActivitySnapshot(String sessionId, in SnapshotData snapshotData);
+    void onUserDataRemovalRequest(in UserDataRemovalRequest request);
 }
diff --git a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
new file mode 100644
index 0000000..e84bd6f
--- /dev/null
+++ b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.contentcapture;
+
+import android.content.ComponentName;
+import com.android.internal.os.IResultReceiver;
+
+import java.util.List;
+
+/**
+ * Interface from the Content Capture service to the system.
+ *
+ * @hide
+ */
+oneway interface IContentCaptureServiceCallback {
+    void setContentCaptureWhitelist(in List<String> packages, in List<ComponentName> activities);
+    void setActivityContentCaptureEnabled(in ComponentName activity, boolean enabled);
+    void setPackageContentCaptureEnabled(in String packageName, boolean enabled);
+    void getContentCaptureDisabledActivities(in IResultReceiver receiver);
+    void getContentCaptureDisabledPackages(in IResultReceiver receiver);
+}
diff --git a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
new file mode 100644
index 0000000..0da8039
--- /dev/null
+++ b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
@@ -0,0 +1,154 @@
+/*
+ * 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.contentsuggestions;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.ContentSuggestionsManager;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+
+/**
+ * @hide
+ */
+@SystemApi
+public abstract class ContentSuggestionsService extends Service {
+
+    private static final String TAG = ContentSuggestionsService.class.getSimpleName();
+
+    private Handler mHandler;
+
+    /**
+     * The action for the intent used to define the content suggestions service.
+     */
+    public static final String SERVICE_INTERFACE =
+            "android.service.contentsuggestions.ContentSuggestionsService";
+
+    private final IContentSuggestionsService mInterface = new IContentSuggestionsService.Stub() {
+        @Override
+        public void provideContextImage(int taskId, GraphicBuffer contextImage,
+                Bundle imageContextRequestExtras) {
+            mHandler.sendMessage(
+                    obtainMessage(ContentSuggestionsService::processContextImage,
+                            ContentSuggestionsService.this, taskId,
+                            Bitmap.createHardwareBitmap(contextImage),
+                            imageContextRequestExtras));
+        }
+
+        @Override
+        public void suggestContentSelections(SelectionsRequest request,
+                ISelectionsCallback callback) {
+            mHandler.sendMessage(obtainMessage(ContentSuggestionsService::suggestContentSelections,
+                    ContentSuggestionsService.this, request, wrapSelectionsCallback(callback)));
+
+        }
+
+        @Override
+        public void classifyContentSelections(ClassificationsRequest request,
+                IClassificationsCallback callback) {
+            mHandler.sendMessage(obtainMessage(ContentSuggestionsService::classifyContentSelections,
+                    ContentSuggestionsService.this, request, wrapClassificationCallback(callback)));
+        }
+
+        @Override
+        public void notifyInteraction(String requestId, Bundle interaction) {
+            mHandler.sendMessage(
+                    obtainMessage(ContentSuggestionsService::notifyInteraction,
+                            ContentSuggestionsService.this, requestId, interaction));
+        }
+    };
+
+    @CallSuper
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mHandler = new Handler(Looper.getMainLooper(), null, true);
+    }
+
+    /** @hide */
+    @Override
+    public final IBinder onBind(Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            return mInterface.asBinder();
+        }
+        Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
+        return null;
+    }
+
+    /**
+     * Called by the system to provide the snapshot for the task associated with the given
+     * {@param taskId}.
+     */
+    public abstract void processContextImage(
+            int taskId, @Nullable Bitmap contextImage, @NonNull Bundle extras);
+
+    /**
+     * Called by a client app to make a request for content selections.
+     */
+    public abstract void suggestContentSelections(@NonNull SelectionsRequest request,
+            @NonNull ContentSuggestionsManager.SelectionsCallback callback);
+
+    /**
+     * Called by a client app to classify the provided content selections.
+     */
+    public abstract void classifyContentSelections(@NonNull ClassificationsRequest request,
+            @NonNull ContentSuggestionsManager.ClassificationsCallback callback);
+
+    /**
+     * Called by a client app to report an interaction.
+     */
+    public abstract void notifyInteraction(@NonNull String requestId, @NonNull Bundle interaction);
+
+    private ContentSuggestionsManager.SelectionsCallback wrapSelectionsCallback(
+            ISelectionsCallback callback) {
+        return (statusCode, selections) -> {
+            try {
+                callback.onContentSelectionsAvailable(statusCode, selections);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Error sending result: " + e);
+            }
+        };
+    }
+
+    private ContentSuggestionsManager.ClassificationsCallback wrapClassificationCallback(
+            IClassificationsCallback callback) {
+        return ((statusCode, classifications) -> {
+            try {
+                callback.onContentClassificationsAvailable(statusCode, classifications);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Error sending result: " + e);
+            }
+        });
+    }
+}
diff --git a/core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl b/core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl
new file mode 100644
index 0000000..1926478
--- /dev/null
+++ b/core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl
@@ -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.service.contentsuggestions;
+
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+
+/**
+ * Interface from the system to an implementation of a content suggestions service.
+ *
+ * @hide
+ */
+oneway interface IContentSuggestionsService {
+    void provideContextImage(
+            int taskId,
+            in GraphicBuffer contextImage,
+            in Bundle imageContextRequestExtras);
+    void suggestContentSelections(
+            in SelectionsRequest request,
+            in ISelectionsCallback callback);
+    void classifyContentSelections(
+            in ClassificationsRequest request,
+            in IClassificationsCallback callback);
+    void notifyInteraction(in String requestId, in Bundle interaction);
+}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index be3f3b3..b84e6c9 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -33,4 +33,5 @@
     void finishSelf(in IBinder token, boolean immediate);
     void startDozing(in IBinder token, int screenState, int screenBrightness);
     void stopDozing(in IBinder token);
+    void forceAmbientDisplayEnabled(boolean enabled);
 }
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index 4be1f9c..ffb524d 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -103,10 +103,23 @@
      */
     public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS =
             "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
+
     /** @see android.telephony.euicc.EuiccManager#ACTION_PROVISION_EMBEDDED_SUBSCRIPTION */
     public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION =
             "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
 
+    /** @see android.telephony.euicc.EuiccManager#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED */
+    public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED =
+            "android.service.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED";
+
+    /** @see android.telephony.euicc.EuiccManager#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED */
+    public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED =
+            "android.service.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED";
+
+    /** @see android.telephony.euicc.EuiccManager#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED */
+    public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED =
+            "android.service.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED";
+
     // LUI resolution actions. These are called by the platform to resolve errors in situations that
     // require user interaction.
     // TODO(b/33075886): Define extras for any input parameters to these dialogs once they are
@@ -184,6 +197,12 @@
     public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED =
             "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
 
+    /**
+     * Intent extra set for resolution requests containing an int indicating the current card Id.
+     */
+    public static final String EXTRA_RESOLUTION_CARD_ID =
+            "android.service.euicc.extra.RESOLUTION_CARD_ID";
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = { "RESULT_" }, value = {
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index dd0242a..ad34ab3 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -173,7 +173,8 @@
     }
 
     /**
-     * Implement this to know when a notification is expanded / collapsed.
+     * Implement this to know when a notification change (expanded / collapsed) is visible to user.
+     *
      * @param key the notification key
      * @param isUserAction whether the expanded change is caused by user action.
      * @param isExpanded whether the notification is expanded.
@@ -185,7 +186,7 @@
      * Implement this to know when a direct reply is sent from a notification.
      * @param key the notification key
      */
-    public void onNotificationDirectReply(@NonNull String key) {}
+    public void onNotificationDirectReplied(@NonNull String key) {}
 
     /**
      * Implement this to know when a suggested reply is sent.
@@ -203,7 +204,7 @@
      * @param action the action that is just clicked
      * @param source the source that provided the action, e.g. SOURCE_FROM_APP
      */
-    public void onActionClicked(@NonNull String key, @NonNull Notification.Action action,
+    public void onActionInvoked(@NonNull String key, @NonNull Notification.Action action,
             @Source int source) {
     }
 
@@ -338,7 +339,7 @@
             args.arg1 = key;
             args.arg2 = action;
             args.argi2 = source;
-            mHandler.obtainMessage(MyHandler.MSG_ON_ACTION_CLICKED, args).sendToTarget();
+            mHandler.obtainMessage(MyHandler.MSG_ON_ACTION_INVOKED, args).sendToTarget();
         }
     }
 
@@ -349,7 +350,7 @@
         public static final int MSG_ON_NOTIFICATION_EXPANSION_CHANGED = 4;
         public static final int MSG_ON_NOTIFICATION_DIRECT_REPLY_SENT = 5;
         public static final int MSG_ON_SUGGESTED_REPLY_SENT = 6;
-        public static final int MSG_ON_ACTION_CLICKED = 7;
+        public static final int MSG_ON_ACTION_INVOKED = 7;
 
         public MyHandler(Looper looper) {
             super(looper, null, false);
@@ -407,7 +408,7 @@
                     SomeArgs args = (SomeArgs) msg.obj;
                     String key = (String) args.arg1;
                     args.recycle();
-                    onNotificationDirectReply(key);
+                    onNotificationDirectReplied(key);
                     break;
                 }
                 case MSG_ON_SUGGESTED_REPLY_SENT: {
@@ -419,13 +420,13 @@
                     onSuggestedReplySent(key, reply, source);
                     break;
                 }
-                case MSG_ON_ACTION_CLICKED: {
+                case MSG_ON_ACTION_INVOKED: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     String key = (String) args.arg1;
                     Notification.Action action = (Notification.Action) args.arg2;
                     int source = args.argi2;
                     args.recycle();
-                    onActionClicked(key, action, source);
+                    onActionInvoked(key, action, source);
                     break;
                 }
             }
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index ad10cc9..3a644d4 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -22,16 +22,21 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.metrics.LogMaker;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
 
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
 /**
  * Class encapsulating a Notification. Sent by the NotificationManagerService to clients including
  * the status bar and any {@link android.service.notification.NotificationListenerService}s.
  */
 public class StatusBarNotification implements Parcelable {
+    static final int MAX_LOG_TAG_LENGTH = 36;
+
     @UnsupportedAppUsage
     private final String pkg;
     @UnsupportedAppUsage
@@ -56,6 +61,9 @@
 
     private Context mContext; // used for inflation & icon expansion
 
+    // Contains the basic logging data of the notification.
+    private LogMaker mLogMaker;
+
     /** @hide */
     public StatusBarNotification(String pkg, String opPkg, int id,
             String tag, int uid, int initialPid, Notification notification, UserHandle user,
@@ -381,4 +389,51 @@
         }
         return mContext;
     }
+
+    /**
+     * Returns a LogMaker that contains all basic information of the notification.
+     * @hide
+     */
+    public LogMaker getLogMaker() {
+        if (mLogMaker == null) {
+            // Initialize fields that only change on update (so a new record).
+            mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
+                .setPackageName(getPackageName())
+                .addTaggedData(MetricsEvent.NOTIFICATION_ID, getId())
+                .addTaggedData(MetricsEvent.NOTIFICATION_TAG, getTag())
+                .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID, getChannelIdLogTag());
+        }
+        // Reset fields that can change between updates, or are used by multiple logs.
+        return mLogMaker
+            .clearCategory()
+            .clearType()
+            .clearSubtype()
+            .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag())
+            .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY,
+                getNotification().isGroupSummary() ? 1 : 0);
+    }
+
+    private String getGroupLogTag() {
+        return shortenTag(getGroup());
+    }
+
+    private String getChannelIdLogTag() {
+        if (notification.getChannelId() == null) {
+            return null;
+        }
+        return shortenTag(notification.getChannelId());
+    }
+
+    // Make logTag with max size MAX_LOG_TAG_LENGTH.
+    // For shorter or equal tags, returns the tag.
+    // For longer tags, truncate the tag and append a hash of the full tag to
+    // fill the maximum size.
+    private String shortenTag(String logTag) {
+        if (logTag == null || logTag.length() <= MAX_LOG_TAG_LENGTH) {
+            return logTag;
+        }
+        String hash = Integer.toHexString(logTag.hashCode());
+        return logTag.substring(0, MAX_LOG_TAG_LENGTH - hash.length() - 1) + "-"
+            + hash;
+    }
 }
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index e105fdf..2789651 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -16,6 +16,7 @@
 
 package android.service.voice;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -40,6 +41,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
@@ -77,6 +80,33 @@
      */
     public static final String SERVICE_META_DATA = "android.voice_interaction";
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"VOICE_STATE_"}, value = {
+            VOICE_STATE_NONE,
+            VOICE_STATE_CONDITIONAL_LISTENING,
+            VOICE_STATE_LISTENING,
+            VOICE_STATE_FULFILLING})
+    public @interface VoiceState {
+    }
+
+    /**
+     * Voice assistant inactive.
+     */
+    public static final int VOICE_STATE_NONE = 0;
+    /**
+     * Voice assistant listening, but will only trigger if it hears a request it can fulfill.
+     */
+    public static final int VOICE_STATE_CONDITIONAL_LISTENING = 1;
+    /**
+     * Voice assistant is listening to user speech.
+     */
+    public static final int VOICE_STATE_LISTENING = 2;
+    /**
+     * Voice assistant is fulfilling an action requested by the user.
+     */
+    public static final int VOICE_STATE_FULFILLING = 3;
+
     IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() {
         @Override
         public void ready() {
@@ -341,6 +371,43 @@
         }
     }
 
+    /**
+     * Requests that the voice state UI indicate the given state.
+     *
+     * @param state value indicating whether the assistant is listening, fulfilling, etc.
+     */
+    public final void setVoiceState(@VoiceState int state) {
+        try {
+            mSystemService.setVoiceState(state);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Displays the given voice transcription contents.
+     */
+    public final void setTranscription(@NonNull String transcription) {
+        try {
+            mSystemService.setTranscription(transcription);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Hides transcription.
+     *
+     * @param immediate if {@code true}, remove before transcription animation completes.
+     */
+    public final void clearTranscription(boolean immediate) {
+        try {
+            mSystemService.clearTranscription(immediate);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("VOICE INTERACTION");
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 163e3d5..6f27447 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -121,6 +121,12 @@
      */
     public static final int SHOW_SOURCE_NOTIFICATION = 1 << 6;
 
+    /**
+     * Flag for use with {@link #onShow}: indicates that the voice interaction service was invoked
+     * from an Android automotive system Ui.
+     */
+    public static final int SHOW_SOURCE_AUTOMOTIVE_SYSTEM_UI = 1 << 7;
+
     final Context mContext;
     final HandlerCaller mHandlerCaller;
 
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index f7acfc5..b0269e3 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -110,13 +110,5 @@
      * @param standy True if the device is entering standby, false if it's exiting standby.
      */
     void setStandbyEnabled(boolean standby);
-
-    /**
-     * Start VR Input method for the given packageName in {@param componentName}.
-     * This method notifies InputMethodManagerService to use VR IME instead of
-     * regular phone IME.
-     */
-    void setVrInputMethod(in ComponentName componentName);
-
 }
 
diff --git a/core/java/android/service/wallpaper/IWallpaperConnection.aidl b/core/java/android/service/wallpaper/IWallpaperConnection.aidl
index a976d0e..f334d9d 100644
--- a/core/java/android/service/wallpaper/IWallpaperConnection.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperConnection.aidl
@@ -27,5 +27,5 @@
     void attachEngine(IWallpaperEngine engine, int displayId);
     void engineShown(IWallpaperEngine engine);
     ParcelFileDescriptor setWallpaper(String name);
-    void onWallpaperColorsChanged(in WallpaperColors colors);
+    void onWallpaperColorsChanged(in WallpaperColors colors, int displayId);
 }
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index a011d67..b197c8a 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -56,6 +56,7 @@
 import android.view.InputEventReceiver;
 import android.view.InsetsState;
 import android.view.MotionEvent;
+import android.view.SurfaceControl;
 import android.view.SurfaceHolder;
 import android.view.View;
 import android.view.ViewGroup;
@@ -217,6 +218,8 @@
         private Context mDisplayContext;
         private int mDisplayState;
 
+        SurfaceControl mSurfaceControl = new SurfaceControl();
+
         final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
             {
                 mRequestedFormat = PixelFormat.RGBX_8888;
@@ -642,7 +645,7 @@
             try {
                 final WallpaperColors newColors = onComputeColors();
                 if (mConnection != null) {
-                    mConnection.onWallpaperColorsChanged(newColors);
+                    mConnection.onWallpaperColorsChanged(newColors, mDisplay.getDisplayId());
                 } else {
                     Log.w(TAG, "Can't notify system because wallpaper connection "
                             + "was not established.");
@@ -781,8 +784,11 @@
                         // only internal implementations like ImageWallpaper
                         DisplayInfo displayInfo = new DisplayInfo();
                         mDisplay.getDisplayInfo(displayInfo);
-                        mLayout.width = Math.max(displayInfo.logicalWidth, myWidth);
-                        mLayout.height = Math.max(displayInfo.logicalHeight, myHeight);
+                        final float layoutScale = Math.max(
+                                (float) displayInfo.logicalHeight / (float) myHeight,
+                                (float) displayInfo.logicalWidth / (float) myWidth);
+                        mLayout.height = (int) (myHeight * layoutScale);
+                        mLayout.width = (int) (myWidth * layoutScale);
                         mWindowFlags |= WindowManager.LayoutParams.FLAG_SCALED;
                     }
 
@@ -843,8 +849,12 @@
                         mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
                             View.VISIBLE, 0, -1, mWinFrame, mOverscanInsets, mContentInsets,
                             mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
-                            mDisplayCutout, mMergedConfiguration, mSurfaceHolder.mSurface,
+                            mDisplayCutout, mMergedConfiguration, mSurfaceControl,
                             mInsetsState);
+                    if (mSurfaceControl.isValid()) {
+                        mSurfaceHolder.mSurface.copyFrom(mSurfaceControl);
+                        mSurfaceControl.release();
+                    }
 
                     if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
                             + ", frame=" + mWinFrame);
@@ -963,7 +973,7 @@
                             mFinalSystemInsets.set(mDispatchedOverscanInsets);
                             mFinalStableInsets.set(mDispatchedStableInsets);
                             WindowInsets insets = new WindowInsets(mFinalSystemInsets,
-                                    null, mFinalStableInsets,
+                                    mFinalStableInsets,
                                     getResources().getConfiguration().isScreenRound(), false,
                                     mDispatchedDisplayCutout);
                             if (DEBUG) {
@@ -1466,7 +1476,7 @@
                         break;
                     }
                     try {
-                        mConnection.onWallpaperColorsChanged(mEngine.onComputeColors());
+                        mConnection.onWallpaperColorsChanged(mEngine.onComputeColors(), mDisplayId);
                     } catch (RemoteException e) {
                         // Connection went away, nothing to do in here.
                     }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 3d0c662..24d746e 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -376,9 +376,13 @@
          * Set paragraph justification mode. The default value is
          * {@link Layout#JUSTIFICATION_MODE_NONE}. If the last line is too short for justification,
          * the last line will be displayed with the alignment set by {@link #setAlignment}.
+         * When Justification mode is JUSTIFICATION_MODE_INTER_WORD, wordSpacing on the given
+         * {@link Paint} will be ignored. This behavior also affects Spans which change the
+         * wordSpacing.
          *
          * @param justificationMode justification mode for the paragraph.
          * @return this builder, useful for chaining.
+         * @see Paint#setWordSpacing(float)
          */
         @NonNull
         public Builder setJustificationMode(@JustificationMode int justificationMode) {
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 6eb433a..949328f 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -75,8 +75,9 @@
     private int mEllipsisEnd;
 
     // Additional width of whitespace for justification. This value is per whitespace, thus
-    // the line width will increase by mAddedWidth x (number of stretchable whitespaces).
-    private float mAddedWidth;
+    // the line width will increase by mAddedWidthForJustify x (number of stretchable whitespaces).
+    private float mAddedWidthForJustify;
+    private boolean mIsJustifying;
 
     private final TextPaint mWorkPaint = new TextPaint();
     private final TextPaint mActivePaint = new TextPaint();
@@ -229,7 +230,8 @@
             }
         }
         mTabs = tabStops;
-        mAddedWidth = 0;
+        mAddedWidthForJustify = 0;
+        mIsJustifying = false;
 
         mEllipsisStart = ellipsisStart != ellipsisEnd ? ellipsisStart : 0;
         mEllipsisEnd = ellipsisStart != ellipsisEnd ? ellipsisEnd : 0;
@@ -255,7 +257,8 @@
             return;
         }
         final float width = Math.abs(measure(end, false, null));
-        mAddedWidth = (justifyWidth - width) / spaces;
+        mAddedWidthForJustify = (justifyWidth - width) / spaces;
+        mIsJustifying = true;
     }
 
     /**
@@ -713,7 +716,9 @@
 
         TextPaint wp = mWorkPaint;
         wp.set(mPaint);
-        wp.setWordSpacing(mAddedWidth);
+        if (mIsJustifying) {
+            wp.setWordSpacing(mAddedWidthForJustify);
+        }
 
         int spanStart = runStart;
         int spanLimit;
@@ -849,7 +854,9 @@
             FontMetricsInt fmi, boolean needWidth, int offset,
             @Nullable ArrayList<DecorationInfo> decorations) {
 
-        wp.setWordSpacing(mAddedWidth);
+        if (mIsJustifying) {
+            wp.setWordSpacing(mAddedWidthForJustify);
+        }
         // Get metrics first (even for empty strings or "0" width runs)
         if (fmi != null) {
             expandMetricsFromPaint(fmi, wp);
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 85b6b88..44353b1 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -33,8 +33,7 @@
 import android.icu.util.ULocale;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.SystemProperties;
-import android.provider.Settings;
+import android.sysprop.DisplayProperties;
 import android.text.style.AbsoluteSizeSpan;
 import android.text.style.AccessibilityClickableSpan;
 import android.text.style.AccessibilityURLSpan;
@@ -2059,7 +2058,7 @@
         return ((locale != null && !locale.equals(Locale.ROOT)
                         && ULocale.forLocale(locale).isRightToLeft())
                 // If forcing into RTL layout mode, return RTL as default
-                || SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false))
+                || DisplayProperties.debug_force_rtl().orElse(false))
             ? View.LAYOUT_DIRECTION_RTL
             : View.LAYOUT_DIRECTION_LTR;
     }
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 433483f7..dd073e9 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -16,11 +16,11 @@
 
 package android.text.style;
 
+import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.content.Intent;
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.os.Parcel;
@@ -30,7 +30,6 @@
 import android.text.TextPaint;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.TextView;
 
 import java.util.Arrays;
@@ -71,9 +70,37 @@
      */
     public static final int FLAG_AUTO_CORRECTION = 0x0004;
 
+    /**
+     * This action is deprecated in {@link android.os.Build.VERSION_CODES#Q}.
+     *
+     * @deprecated For IMEs to receive this kind of user interaction signals, implement IMEs' own
+     *             suggestion picker UI instead of relying on {@link SuggestionSpan}. To retrieve
+     *             bounding boxes for each character of the composing text, use
+     *             {@link android.view.inputmethod.CursorAnchorInfo}.
+     */
+    @Deprecated
     public static final String ACTION_SUGGESTION_PICKED = "android.text.style.SUGGESTION_PICKED";
+
+    /**
+     * This is deprecated in {@link android.os.Build.VERSION_CODES#Q}.
+     *
+     * @deprecated See {@link #ACTION_SUGGESTION_PICKED}.
+     */
+    @Deprecated
     public static final String SUGGESTION_SPAN_PICKED_AFTER = "after";
+    /**
+     * This is deprecated in {@link android.os.Build.VERSION_CODES#Q}.
+     *
+     * @deprecated See {@link #ACTION_SUGGESTION_PICKED}.
+     */
+    @Deprecated
     public static final String SUGGESTION_SPAN_PICKED_BEFORE = "before";
+    /**
+     * This is deprecated in {@link android.os.Build.VERSION_CODES#Q}.
+     *
+     * @deprecated See {@link #ACTION_SUGGESTION_PICKED}.
+     */
+    @Deprecated
     public static final String SUGGESTION_SPAN_PICKED_HASHCODE = "hashcode";
 
     public static final int SUGGESTIONS_MAX_SIZE = 5;
@@ -96,8 +123,6 @@
     private final String mLocaleStringForCompatibility;
     @NonNull
     private final String mLanguageTag;
-    private final String mNotificationTargetClassName;
-    private final String mNotificationTargetPackageName;
     private final int mHashCode;
 
     @UnsupportedAppUsage
@@ -136,7 +161,9 @@
      * {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered. Null values not permitted.
      * @param flags Additional flags indicating how this span is handled in TextView
      * @param notificationTargetClass if not null, this class will get notified when the user
-     * selects one of the suggestions.
+     *                                selects one of the suggestions.  On Android
+     *                                {@link android.os.Build.VERSION_CODES#Q} and later this
+     *                                parameter is always ignored.
      */
     public SuggestionSpan(Context context, Locale locale, String[] suggestions, int flags,
             Class<?> notificationTargetClass) {
@@ -155,20 +182,7 @@
         }
         mLocaleStringForCompatibility = sourceLocale == null ? "" : sourceLocale.toString();
         mLanguageTag = sourceLocale == null ? "" : sourceLocale.toLanguageTag();
-
-        if (context != null) {
-            mNotificationTargetPackageName = context.getPackageName();
-        } else {
-            mNotificationTargetPackageName = null;
-        }
-
-        if (notificationTargetClass != null) {
-            mNotificationTargetClassName = notificationTargetClass.getCanonicalName();
-        } else {
-            mNotificationTargetClassName = "";
-        }
-        mHashCode = hashCodeInternal(mSuggestions, mLanguageTag, mLocaleStringForCompatibility,
-                mNotificationTargetClassName);
+        mHashCode = hashCodeInternal(mSuggestions, mLanguageTag, mLocaleStringForCompatibility);
 
         initStyle(context);
     }
@@ -214,8 +228,6 @@
         mFlags = src.readInt();
         mLocaleStringForCompatibility = src.readString();
         mLanguageTag = src.readString();
-        mNotificationTargetClassName = src.readString();
-        mNotificationTargetPackageName = src.readString();
         mHashCode = src.readInt();
         mEasyCorrectUnderlineColor = src.readInt();
         mEasyCorrectUnderlineThickness = src.readFloat();
@@ -259,17 +271,15 @@
     }
 
     /**
-     * @return The name of the class to notify. The class of the original IME package will receive
-     * a notification when the user selects one of the suggestions. The notification will include
-     * the original string, the suggested replacement string as well as the hashCode of this span.
-     * The class will get notified by an intent that has those information.
-     * This is an internal API because only the framework should know the class name.
+     * @return {@code null}.
      *
      * @hide
+     * @deprecated Do not use. Always returns {@code null}.
      */
+    @Deprecated
     @UnsupportedAppUsage
     public String getNotificationTargetClassName() {
-        return mNotificationTargetClassName;
+        return null;
     }
 
     public int getFlags() {
@@ -296,8 +306,6 @@
         dest.writeInt(mFlags);
         dest.writeString(mLocaleStringForCompatibility);
         dest.writeString(mLanguageTag);
-        dest.writeString(mNotificationTargetClassName);
-        dest.writeString(mNotificationTargetPackageName);
         dest.writeInt(mHashCode);
         dest.writeInt(mEasyCorrectUnderlineColor);
         dest.writeFloat(mEasyCorrectUnderlineThickness);
@@ -331,9 +339,9 @@
     }
 
     private static int hashCodeInternal(String[] suggestions, @NonNull String languageTag,
-            @NonNull String localeStringForCompatibility, String notificationTargetClassName) {
+            @NonNull String localeStringForCompatibility) {
         return Arrays.hashCode(new Object[] {Long.valueOf(SystemClock.uptimeMillis()), suggestions,
-                languageTag, localeStringForCompatibility, notificationTargetClassName});
+                languageTag, localeStringForCompatibility});
     }
 
     public static final Parcelable.Creator<SuggestionSpan> CREATOR =
@@ -370,6 +378,7 @@
     /**
      * @return The color of the underline for that span, or 0 if there is no underline
      */
+    @ColorInt
     public int getUnderlineColor() {
         // The order here should match what is used in updateDrawState
         final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
@@ -388,39 +397,14 @@
     }
 
     /**
-     * Notifies a suggestion selection.
+     * Does nothing.
      *
+     * @deprecated this is deprecated in {@link android.os.Build.VERSION_CODES#Q}.
      * @hide
      */
     @UnsupportedAppUsage
+    @Deprecated
     public void notifySelection(Context context, String original, int index) {
-        final Intent intent = new Intent();
-
-        if (context == null || mNotificationTargetClassName == null) {
-            return;
-        }
-        // Ensures that only a class in the original IME package will receive the
-        // notification.
-        if (mSuggestions == null || index < 0 || index >= mSuggestions.length) {
-            Log.w(TAG, "Unable to notify the suggestion as the index is out of range index=" + index
-                    + " length=" + mSuggestions.length);
-            return;
-        }
-
-        // The package name is not mandatory (legacy from JB), and if the package name
-        // is missing, we try to notify the suggestion through the input method manager.
-        if (mNotificationTargetPackageName != null) {
-            intent.setClassName(mNotificationTargetPackageName, mNotificationTargetClassName);
-            intent.setAction(SuggestionSpan.ACTION_SUGGESTION_PICKED);
-            intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_BEFORE, original);
-            intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_AFTER, mSuggestions[index]);
-            intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_HASHCODE, hashCode());
-            context.sendBroadcast(intent);
-        } else {
-            InputMethodManager imm = context.getSystemService(InputMethodManager.class);
-            if (imm != null) {
-                imm.notifySuggestionPicked(this, original, index);
-            }
-        }
+        Log.w(TAG, "notifySelection() is deprecated.  Does nothing.");
     }
 }
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index eef7ea2..50e7ec3 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -37,7 +37,6 @@
 import com.android.i18n.phonenumbers.PhoneNumberMatch;
 import com.android.i18n.phonenumbers.PhoneNumberUtil;
 import com.android.i18n.phonenumbers.PhoneNumberUtil.Leniency;
-import com.android.internal.annotations.GuardedBy;
 
 import libcore.util.EmptyArray;
 
@@ -49,6 +48,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Locale;
+import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -69,7 +69,6 @@
  *
  * @see MatchFilter
  * @see TransformFilter
- * @see UrlSpanFactory
  */
 
 public class Linkify {
@@ -228,44 +227,6 @@
     }
 
     /**
-     * Factory class to create {@link URLSpan}s. While adding spans to a {@link Spannable},
-     * {@link Linkify} will call {@link UrlSpanFactory#create(String)} function to create a
-     * {@link URLSpan}.
-     *
-     * @see #addLinks(Spannable, int, UrlSpanFactory)
-     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter,
-     * UrlSpanFactory)
-     */
-    public static class UrlSpanFactory {
-        private static final Object sInstanceLock = new Object();
-
-        @GuardedBy("sInstanceLock")
-        private static volatile UrlSpanFactory sInstance = null;
-
-        private static synchronized UrlSpanFactory getInstance() {
-            if (sInstance == null) {
-                synchronized (sInstanceLock) {
-                    if (sInstance == null) {
-                        sInstance = new UrlSpanFactory();
-                    }
-                }
-            }
-            return sInstance;
-        }
-
-        /**
-         * Factory function that will called by {@link Linkify} in order to create a
-         * {@link URLSpan}.
-         *
-         * @param url URL found
-         * @return a URLSpan instance
-         */
-        public URLSpan create(final String url) {
-            return new URLSpan(url);
-        }
-    }
-
-    /**
      *  Scans the text of the provided Spannable and turns all occurrences
      *  of the link types indicated in the mask into clickable links.
      *  If the mask is nonzero, it also removes any existing URLSpans
@@ -277,7 +238,7 @@
      *
      *  @return True if at least one link is found and applied.
      *
-     * @see #addLinks(Spannable, int, UrlSpanFactory)
+     * @see #addLinks(Spannable, int, Function)
      */
     public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask) {
         return addLinks(text, mask, null, null);
@@ -292,11 +253,11 @@
      *
      *  @param text Spannable whose text is to be marked-up with links
      *  @param mask mask to define which kinds of links will be searched
-     *  @param urlSpanFactory factory class used to create {@link URLSpan}s
+     *  @param urlSpanFactory function used to create {@link URLSpan}s
      *  @return True if at least one link is found and applied.
      */
     public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask,
-            @Nullable UrlSpanFactory urlSpanFactory) {
+            @Nullable Function<String, URLSpan> urlSpanFactory) {
         return addLinks(text, mask, null, urlSpanFactory);
     }
 
@@ -309,11 +270,11 @@
      * @param text Spannable whose text is to be marked-up with links
      * @param mask mask to define which kinds of links will be searched
      * @param context Context to be used while identifying phone numbers
-     * @param urlSpanFactory factory class used to create {@link URLSpan}s
+     * @param urlSpanFactory function used to create {@link URLSpan}s
      * @return true if at least one link is found and applied.
      */
     private static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask,
-            @Nullable Context context, @Nullable UrlSpanFactory urlSpanFactory) {
+            @Nullable Context context, @Nullable Function<String, URLSpan> urlSpanFactory) {
         if (text != null && containsUnsupportedCharacters(text.toString())) {
             android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
             return false;
@@ -398,7 +359,7 @@
      *
      *  @return True if at least one link is found and applied.
      *
-     *  @see #addLinks(Spannable, int, UrlSpanFactory)
+     *  @see #addLinks(Spannable, int, Function)
      */
     public static final boolean addLinks(@NonNull TextView text, @LinkifyMask int mask) {
         if (mask == 0) {
@@ -512,8 +473,7 @@
      *  @param pattern      Regex pattern to be used for finding links
      *  @param scheme       URL scheme string (eg <code>http://</code>) to be
      *                      prepended to the links that do not start with this scheme.
-     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter,
-     * UrlSpanFactory)
+     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, Function)
      */
     public static final boolean addLinks(@NonNull Spannable text, @NonNull Pattern pattern,
             @Nullable String scheme) {
@@ -534,8 +494,7 @@
      * @param transformFilter Filter to allow the client code to update the link found.
      *
      * @return True if at least one link is found and applied.
-     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter,
-     * UrlSpanFactory)
+     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, Function)
      */
     public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
             @Nullable String scheme, @Nullable MatchFilter matchFilter,
@@ -560,8 +519,7 @@
      *
      * @return True if at least one link is found and applied.
      *
-     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter,
-     * UrlSpanFactory)
+     * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, Function)
      */
     public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
             @Nullable String defaultScheme, @Nullable String[] schemes,
@@ -584,14 +542,14 @@
      * @param matchFilter     the filter that is used to allow the client code additional control
      *                        over which pattern matches are to be converted into links.
      * @param transformFilter filter to allow the client code to update the link found.
-     * @param urlSpanFactory  factory class used to create {@link URLSpan}s
+     * @param urlSpanFactory  function used to create {@link URLSpan}s
      *
      * @return True if at least one link is found and applied.
      */
     public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
             @Nullable String defaultScheme, @Nullable String[] schemes,
             @Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter,
-            @Nullable UrlSpanFactory urlSpanFactory) {
+            @Nullable Function<String, URLSpan> urlSpanFactory) {
         if (spannable != null && containsUnsupportedCharacters(spannable.toString())) {
             android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
             return false;
@@ -634,11 +592,11 @@
     }
 
     private static void applyLink(String url, int start, int end, Spannable text,
-            @Nullable UrlSpanFactory urlSpanFactory) {
+            @Nullable Function<String, URLSpan> urlSpanFactory) {
         if (urlSpanFactory == null) {
-            urlSpanFactory = UrlSpanFactory.getInstance();
+            urlSpanFactory = DEFAULT_SPAN_FACTORY;
         }
-        final URLSpan span = urlSpanFactory.create(url);
+        final URLSpan span = urlSpanFactory.apply(url);
         text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
     }
 
@@ -805,6 +763,13 @@
             i++;
         }
     }
+
+    /**
+     * Default factory function to create {@link URLSpan}s. While adding spans to a
+     * {@link Spannable}, {@link Linkify} will call this function to create a {@link URLSpan}.
+     */
+    private static final Function<String, URLSpan> DEFAULT_SPAN_FACTORY =
+            (String string) -> new URLSpan(string);
 }
 
 class LinkSpec {
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index af73a16..265b0d3 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -18,6 +18,7 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
+
 import java.io.PrintWriter;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
@@ -250,7 +251,7 @@
                     if (value == 0 && flagsWasZero) {
                         return constNameWithoutPrefix(prefix, field);
                     }
-                    if ((flags & value) != 0) {
+                    if ((flags & value) == value) {
                         flags &= ~value;
                         res.append(constNameWithoutPrefix(prefix, field)).append('|');
                     }
diff --git a/core/java/android/util/DocumentsStatsLog.java b/core/java/android/util/DocumentsStatsLog.java
new file mode 100644
index 0000000..f483944
--- /dev/null
+++ b/core/java/android/util/DocumentsStatsLog.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import android.annotation.SystemApi;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsProvider;
+
+/**
+ * DocumentsStatsLog provides APIs to send DocumentsUI related events to statsd.
+ * @hide
+ */
+@SystemApi
+public class DocumentsStatsLog {
+
+    private DocumentsStatsLog() {}
+
+    /**
+     * Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up.
+     *
+     * @param action action that launches DocumentsUI.
+     * @param hasInitialUri is DocumentsUI launched with
+     *                      {@link DocumentsContract#EXTRA_INITIAL_URI}.
+     * @param mimeType the requested mime type.
+     * @param rootUri the resolved rootUri, or {@code null} if the provider doesn't
+     *                support {@link DocumentsProvider#findDocumentPath(String, String)}
+     */
+    public static void logActivityLaunch(
+            int action, boolean hasInitialUri, int mimeType, int rootUri) {
+        StatsLog.write(StatsLog.DOCS_UI_LAUNCH_REPORTED, action, hasInitialUri, mimeType, rootUri);
+    }
+
+    /**
+     * Logs root visited event.
+     *
+     * @param scope whether it's in FILES or PICKER mode.
+     * @param root the root that user visited
+     */
+    public static void logRootVisited(int scope, int root) {
+        StatsLog.write(StatsLog.DOCS_UI_ROOT_VISITED, scope, root);
+    }
+
+    /**
+     * Logs file operation stats. Call this when a file operation has completed.
+     *
+     * @param provider whether it's system or external provider
+     * @param fileOp the file operation
+     */
+    public static void logFileOperation(int provider, int fileOp) {
+        StatsLog.write(StatsLog.DOCS_UI_PROVIDER_FILE_OP, provider, fileOp);
+    }
+
+    /**
+     * Logs file operation stats. Call this when a copy/move operation has completed with a specific
+     * mode.
+     *
+     * @param fileOp copy or move file operation
+     * @param mode the mode for copy and move operation
+     */
+    public static void logFileOperationCopyMoveMode(int fileOp, int mode) {
+        StatsLog.write(StatsLog.DOCS_UI_FILE_OP_COPY_MOVE_MODE_REPORTED, fileOp, mode);
+    }
+
+    /**
+     * Logs file sub operation stats. Call this when a file operation has failed.
+     *
+     * @param authority the authority of the source document
+     * @param subOp the sub-file operation
+     */
+    public static void logFileOperationFailure(int authority, int subOp) {
+        StatsLog.write(StatsLog.DOCS_UI_FILE_OP_FAILURE, authority, subOp);
+    }
+
+    /**
+     * Logs the cancellation of a file operation. Call this when a job is canceled
+     *
+     * @param fileOp the file operation.
+     */
+    public static void logFileOperationCanceled(int fileOp) {
+        StatsLog.write(StatsLog.DOCS_UI_FILE_OP_CANCELED, fileOp);
+    }
+
+    /**
+     * Logs startup time in milliseconds.
+     *
+     * @param startupMs
+     */
+    public static void logStartupMs(int startupMs) {
+        StatsLog.write(StatsLog.DOCS_UI_STARTUP_MS, startupMs);
+    }
+
+    /**
+     * Logs the action that was started by user.
+     *
+     * @param userAction
+     */
+    public static void logUserAction(int userAction) {
+        StatsLog.write(StatsLog.DOCS_UI_USER_ACTION_REPORTED, userAction);
+    }
+
+    /**
+     * Logs the invalid type when invalid scoped access is requested.
+     *
+     * @param type the type of invalid scoped access request.
+     */
+    public static void logInvalidScopedAccessRequest(int type) {
+        StatsLog.write(StatsLog.DOCS_UI_INVALID_SCOPED_ACCESS_REQUEST, type);
+    }
+
+    /**
+     * Logs the package name that launches docsui picker mode.
+     *
+     * @param packageName
+     */
+    public static void logPickerLaunchedFrom(String packageName) {
+        StatsLog.write(StatsLog.DOCS_UI_PICKER_LAUNCHED_FROM_REPORTED, packageName);
+    }
+
+    /**
+     * Logs the search type.
+     *
+     * @param searchType
+     */
+    public static void logSearchType(int searchType) {
+        StatsLog.write(StatsLog.DOCS_UI_SEARCH_TYPE_REPORTED, searchType);
+    }
+
+    /**
+     * Logs the search mode.
+     *
+     * @param searchMode
+     */
+    public static void logSearchMode(int searchMode) {
+        StatsLog.write(StatsLog.DOCS_UI_SEARCH_MODE_REPORTED, searchMode);
+    }
+
+    /**
+     * Logs the pick result information.
+     *
+     * @param actionCount total user action count during pick process.
+     * @param duration total time spent on pick process.
+     * @param fileCount number of picked files.
+     * @param isSearching are the picked files found by search.
+     * @param root the root where the picked files located.
+     * @param mimeType the mime type of the picked file. Only for single-select case.
+     * @param repeatedlyPickTimes number of times that the file has been picked before. Only for
+     *                            single-select case.
+     */
+    public static void logFilePick(int actionCount, long duration, int fileCount,
+            boolean isSearching, int root, int mimeType, int repeatedlyPickTimes) {
+        StatsLog.write(StatsLog.DOCS_UI_PICK_RESULT_REPORTED, actionCount, duration, fileCount,
+                isSearching, root, mimeType, repeatedlyPickTimes);
+    }
+}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 8b97e0e..0edcb3d 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -22,7 +22,9 @@
 import android.text.TextUtils;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Util class to get feature flag information.
@@ -37,8 +39,11 @@
     public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
     public static final String SAFETY_HUB = "settings_safety_hub";
     public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
+    public static final String AOD_IMAGEWALLPAPER_ENABLED = "settings_aod_imagewallpaper_enabled";
 
     private static final Map<String, String> DEFAULT_FLAGS;
+    private static final Set<String> OBSERVABLE_FLAGS;
+
     static {
         DEFAULT_FLAGS = new HashMap<>();
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
@@ -54,6 +59,10 @@
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
         DEFAULT_FLAGS.put(SAFETY_HUB, "false");
         DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
+        DEFAULT_FLAGS.put(AOD_IMAGEWALLPAPER_ENABLED, "false");
+
+        OBSERVABLE_FLAGS = new HashSet<>();
+        OBSERVABLE_FLAGS.add(AOD_IMAGEWALLPAPER_ENABLED);
     }
 
     /**
@@ -90,6 +99,16 @@
      */
     public static void setEnabled(Context context, String feature, boolean enabled) {
         SystemProperties.set(FFLAG_OVERRIDE_PREFIX + feature, enabled ? "true" : "false");
+
+        // Also update Settings.Global if needed so that we can observe it via observer.
+        if (OBSERVABLE_FLAGS.contains(feature)) {
+            setObservableFlag(context, feature, enabled);
+        }
+    }
+
+    private static void setObservableFlag(Context context, String feature, boolean enabled) {
+        Settings.Global.putString(
+                context.getContentResolver(), feature, enabled ? "true" : "false");
     }
 
     /**
diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java
index 5718d99..70d049a 100644
--- a/core/java/android/util/Half.java
+++ b/core/java/android/util/Half.java
@@ -162,6 +162,7 @@
     private static final int FP32_EXPONENT_MASK     = 0xff;
     private static final int FP32_SIGNIFICAND_MASK  = 0x7fffff;
     private static final int FP32_EXPONENT_BIAS     = 127;
+    private static final int FP32_QNAN_MASK         = 0x400000;
 
     private static final int FP32_DENORMAL_MAGIC = 126 << 23;
     private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC);
@@ -903,6 +904,9 @@
             outM = m << 13;
             if (e == 0x1f) { // Infinite or NaN
                 outE = 0xff;
+                if (outM != 0) { // SNaNs are quieted
+                    outM |= FP32_QNAN_MASK;
+                }
             } else {
                 outE = e - FP16_EXPONENT_BIAS + FP32_EXPONENT_BIAS;
             }
diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java
index 7eef63e..d051ed8 100644
--- a/core/java/android/util/KeyValueListParser.java
+++ b/core/java/android/util/KeyValueListParser.java
@@ -16,7 +16,9 @@
 package android.util;
 
 import android.text.TextUtils;
+import android.util.proto.ProtoOutputStream;
 
+import java.io.PrintWriter;
 import java.time.Duration;
 import java.time.format.DateTimeParseException;
 
@@ -212,4 +214,163 @@
         }
         return def;
     }
+
+    /** Represents an integer config value. */
+    public static class IntValue {
+        private final String mKey;
+        private final int mDefaultValue;
+        private int mValue;
+
+        /** Constructor, initialize with a config key and a default value. */
+        public IntValue(String key, int defaultValue) {
+            mKey = key;
+            mDefaultValue = defaultValue;
+            mValue = mDefaultValue;
+        }
+
+        /** Read a value from {@link KeyValueListParser} */
+        public void parse(KeyValueListParser parser) {
+            mValue = parser.getInt(mKey, mDefaultValue);
+        }
+
+        /** Return the config key. */
+        public String getKey() {
+            return mKey;
+        }
+
+        /** Return the default value. */
+        public int getDefaultValue() {
+            return mDefaultValue;
+        }
+
+        /** Return the actual config value. */
+        public int getValue() {
+            return mValue;
+        }
+
+        /** Overwrites with a value. */
+        public void setValue(int value) {
+            mValue = value;
+        }
+
+        /** Used for dumpsys */
+        public void dump(PrintWriter pw, String prefix) {
+            pw.print(prefix);
+            pw.print(mKey);
+            pw.print("=");
+            pw.print(mValue);
+            pw.println();
+        }
+
+        /** Used for proto dumpsys */
+        public void dumpProto(ProtoOutputStream proto, long tag) {
+            proto.write(tag, mValue);
+        }
+    }
+
+    /** Represents an long config value. */
+    public static class LongValue {
+        private final String mKey;
+        private final long mDefaultValue;
+        private long mValue;
+
+        /** Constructor, initialize with a config key and a default value. */
+        public LongValue(String key, long defaultValue) {
+            mKey = key;
+            mDefaultValue = defaultValue;
+            mValue = mDefaultValue;
+        }
+
+        /** Read a value from {@link KeyValueListParser} */
+        public void parse(KeyValueListParser parser) {
+            mValue = parser.getLong(mKey, mDefaultValue);
+        }
+
+        /** Return the config key. */
+        public String getKey() {
+            return mKey;
+        }
+
+        /** Return the default value. */
+        public long getDefaultValue() {
+            return mDefaultValue;
+        }
+
+        /** Return the actual config value. */
+        public long getValue() {
+            return mValue;
+        }
+
+        /** Overwrites with a value. */
+        public void setValue(long value) {
+            mValue = value;
+        }
+
+        /** Used for dumpsys */
+        public void dump(PrintWriter pw, String prefix) {
+            pw.print(prefix);
+            pw.print(mKey);
+            pw.print("=");
+            pw.print(mValue);
+            pw.println();
+        }
+
+        /** Used for proto dumpsys */
+        public void dumpProto(ProtoOutputStream proto, long tag) {
+            proto.write(tag, mValue);
+        }
+    }
+
+    /** Represents an string config value. */
+    public static class StringValue {
+        private final String mKey;
+        private final String mDefaultValue;
+        private String mValue;
+
+        /** Constructor, initialize with a config key and a default value. */
+        public StringValue(String key, String defaultValue) {
+            mKey = key;
+            mDefaultValue = defaultValue;
+            mValue = mDefaultValue;
+        }
+
+        /** Read a value from {@link KeyValueListParser} */
+        public void parse(KeyValueListParser parser) {
+            mValue = parser.getString(mKey, mDefaultValue);
+        }
+
+        /** Return the config key. */
+        public String getKey() {
+            return mKey;
+        }
+
+        /** Return the default value. */
+        public String getDefaultValue() {
+            return mDefaultValue;
+        }
+
+        /** Return the actual config value. */
+        public String getValue() {
+            return mValue;
+        }
+
+        /** Overwrites with a value. */
+        public void setValue(String value) {
+            mValue = value;
+        }
+
+        /** Used for dumpsys */
+        public void dump(PrintWriter pw, String prefix) {
+            pw.print(prefix);
+            pw.print(mKey);
+            pw.print("=");
+            pw.print(mValue);
+            pw.println();
+        }
+
+        /** Used for proto dumpsys */
+        public void dumpProto(ProtoOutputStream proto, long tag) {
+            proto.write(tag, mValue);
+        }
+    }
 }
diff --git a/core/java/android/util/LongArrayQueue.java b/core/java/android/util/LongArrayQueue.java
new file mode 100644
index 0000000..d5f0484
--- /dev/null
+++ b/core/java/android/util/LongArrayQueue.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import libcore.util.EmptyArray;
+
+import java.util.NoSuchElementException;
+
+/**
+ * A lightweight implementation for a queue with long values.
+ * Additionally supports getting an element with a specified position from the head of the queue.
+ * The queue grows in size if needed to accommodate new elements.
+ *
+ * @hide
+ */
+public class LongArrayQueue {
+
+    private long[] mValues;
+    private int mSize;
+    private int mHead;
+    private int mTail;
+
+    /**
+     * Initializes a queue with the given starting capacity.
+     *
+     * @param initialCapacity the capacity.
+     */
+    public LongArrayQueue(int initialCapacity) {
+        if (initialCapacity == 0) {
+            mValues = EmptyArray.LONG;
+        } else {
+            mValues = ArrayUtils.newUnpaddedLongArray(initialCapacity);
+        }
+        mSize = 0;
+        mHead = mTail = 0;
+    }
+
+    /**
+     * Initializes a queue with default starting capacity.
+     */
+    public LongArrayQueue() {
+        this(16);
+    }
+
+    private void grow() {
+        if (mSize < mValues.length) {
+            throw new IllegalStateException("Queue not full yet!");
+        }
+        final int newSize = GrowingArrayUtils.growSize(mSize);
+        final long[] newArray = ArrayUtils.newUnpaddedLongArray(newSize);
+        final int r = mValues.length - mHead; // Number of elements on and to the right of head.
+        System.arraycopy(mValues, mHead, newArray, 0, r);
+        System.arraycopy(mValues, 0, newArray, r, mHead);
+        mValues = newArray;
+        mHead = 0;
+        mTail = mSize;
+    }
+
+    /**
+     * Returns the number of elements in the queue.
+     */
+    public int size() {
+        return mSize;
+    }
+
+    /**
+     * Removes all elements from this queue.
+     */
+    public void clear() {
+        mSize = 0;
+        mHead = mTail = 0;
+    }
+
+    /**
+     * Adds a value to the tail of the queue.
+     *
+     * @param value the value to be added.
+     */
+    public void addLast(long value) {
+        if (mSize == mValues.length) {
+            grow();
+        }
+        mValues[mTail] = value;
+        mTail = (mTail + 1) % mValues.length;
+        mSize++;
+    }
+
+    /**
+     * Removes an element from the head of the queue.
+     *
+     * @return the element at the head of the queue.
+     * @throws NoSuchElementException if the queue is empty.
+     */
+    public long removeFirst() {
+        if (mSize == 0) {
+            throw new NoSuchElementException("Queue is empty!");
+        }
+        final long ret = mValues[mHead];
+        mHead = (mHead + 1) % mValues.length;
+        mSize--;
+        return ret;
+    }
+
+    /**
+     * Returns the element at the given position from the head of the queue, where 0 represents the
+     * head of the queue.
+     *
+     * @param position the position from the head of the queue.
+     * @return the element found at the given position.
+     * @throws IndexOutOfBoundsException if {@code position} < {@code 0} or
+     *                                   {@code position} >= {@link #size()}
+     */
+    public long get(int position) {
+        if (position < 0 || position >= mSize) {
+            throw new IndexOutOfBoundsException("Index " + position
+                    + " not valid for a queue of size " + mSize);
+        }
+        final int index = (mHead + position) % mValues.length;
+        return mValues[index];
+    }
+
+    /**
+     * Returns the element at the head of the queue, without removing it.
+     *
+     * @return the element at the head of the queue.
+     * @throws NoSuchElementException if the queue is empty
+     */
+    public long peekFirst() {
+        if (mSize == 0) {
+            throw new NoSuchElementException("Queue is empty!");
+        }
+        return mValues[mHead];
+    }
+
+    /**
+     * Returns the element at the tail of the queue.
+     *
+     * @return the element at the tail of the queue.
+     * @throws NoSuchElementException if the queue is empty.
+     */
+    public long peekLast() {
+        if (mSize == 0) {
+            throw new NoSuchElementException("Queue is empty!");
+        }
+        final int index = (mTail == 0) ? mValues.length - 1 : mTail - 1;
+        return mValues[index];
+    }
+}
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 91bc3eb..e4c8eeb 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -43,6 +43,9 @@
     /** {@hide} */
     private static SimpleDateFormat sLoggingFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
+    /** @hide */
+    public static final SimpleDateFormat sDumpDateFormat =
+            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
     /**
      * Tries to return a time zone that would have had the specified offset
      * and DST value at the specified moment in the specified country.
@@ -360,4 +363,28 @@
             return sLoggingFormat.format(new Date(millis));
         }
     }
-}
+
+    /**
+     * Dump a currentTimeMillis style timestamp for dumpsys.
+     *
+     * @hide
+     */
+    public static void dumpTime(PrintWriter pw, long time) {
+        pw.print(sDumpDateFormat.format(new Date(time)));
+    }
+
+    /**
+     * Dump a currentTimeMillis style timestamp for dumpsys, with the delta time from now.
+     *
+     * @hide
+     */
+    public static void dumpTimeWithDelta(PrintWriter pw, long time, long now) {
+        pw.print(sDumpDateFormat.format(new Date(time)));
+        if (time == now) {
+            pw.print(" (now)");
+        } else {
+            pw.print(" (");
+            TimeUtils.formatDuration(time, now, pw);
+            pw.print(")");
+        }
+    }}
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index ea4464d..99106be 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -216,6 +216,12 @@
      * */
     public int density;
 
+    /**
+     * If the Value came from a style resource, this holds the corresponding style resource id
+     * against which the attribute was resolved.
+     */
+    public int sourceStyleResourceId;
+
     /* ------------------------------------------------------------ */
 
     /** Return the data for this value as a float.  Only use for values
diff --git a/core/java/android/view/AccessibilityIterators.java b/core/java/android/view/AccessibilityIterators.java
index 9f7560c..54cfc00 100644
--- a/core/java/android/view/AccessibilityIterators.java
+++ b/core/java/android/view/AccessibilityIterators.java
@@ -147,6 +147,9 @@
         @Override
         public void onConfigurationChanged(Configuration globalConfig) {
             final Locale locale = globalConfig.getLocales().get(0);
+            if (locale == null) {
+                return;
+            }
             if (!mLocale.equals(locale)) {
                 mLocale = locale;
                 onLocaleChanged(locale);
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 96ef8ba..ccd0fc1 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.graphics.FrameInfo;
+import android.graphics.Insets;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.Build;
 import android.os.Handler;
@@ -199,7 +200,7 @@
      * @hide
      */
     private static final String[] CALLBACK_TRACE_TITLES = {
-            "input", "animation", "traversal", "commit"
+            "input", "animation", "insets_animation", "traversal", "commit"
     };
 
     /**
@@ -209,18 +210,33 @@
     public static final int CALLBACK_INPUT = 0;
 
     /**
-     * Callback type: Animation callback.  Runs before traversals.
+     * Callback type: Animation callback.  Runs before {@link #CALLBACK_INSETS_ANIMATION}.
      * @hide
      */
     @TestApi
     public static final int CALLBACK_ANIMATION = 1;
 
     /**
+     * Callback type: Animation callback to handle inset updates. This is separate from
+     * {@link #CALLBACK_ANIMATION} as we need to "gather" all inset animation updates via
+     * {@link WindowInsetsAnimationController#changeInsets} for multiple ongoing animations but then
+     * update the whole view system with a single callback to {@link View#dispatchWindowInsetsAnimationProgress}
+     * that contains all the combined updated insets.
+     * <p>
+     * Both input and animation may change insets, so we need to run this after these callbacks, but
+     * before traversals.
+     * <p>
+     * Runs before traversals.
+     * @hide
+     */
+    public static final int CALLBACK_INSETS_ANIMATION = 2;
+
+    /**
      * Callback type: Traversal callback.  Handles layout and draw.  Runs
      * after all other asynchronous messages have been handled.
      * @hide
      */
-    public static final int CALLBACK_TRAVERSAL = 2;
+    public static final int CALLBACK_TRAVERSAL = 3;
 
     /**
      * Callback type: Commit callback.  Handles post-draw operations for the frame.
@@ -232,7 +248,7 @@
      * to the view hierarchy state) actually took effect.
      * @hide
      */
-    public static final int CALLBACK_COMMIT = 3;
+    public static final int CALLBACK_COMMIT = 4;
 
     private static final int CALLBACK_LAST = CALLBACK_COMMIT;
 
@@ -704,6 +720,7 @@
 
             mFrameInfo.markAnimationsStart();
             doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
+            doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
 
             mFrameInfo.markPerformTraversalsStart();
             doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 4ead34e..f58efc9 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1391,11 +1391,17 @@
          */
         public static final int HDR_TYPE_HLG = 3;
 
+        /**
+         * HDR10+ display.
+         */
+        public static final int HDR_TYPE_HDR10_PLUS = 4;
+
         /** @hide */
         @IntDef(prefix = { "HDR_TYPE_" }, value = {
                 HDR_TYPE_DOLBY_VISION,
                 HDR_TYPE_HDR10,
                 HDR_TYPE_HLG,
+                HDR_TYPE_HDR10_PLUS,
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface HdrType {}
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 33b3ff4f..7d9ec70 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -237,6 +237,16 @@
     private static final int LONG_PRESS = 2;
     private static final int TAP = 3;
 
+    /**
+     * If a MotionEvent has CLASSIFICATION_AMBIGUOUS_GESTURE set, then certain actions, such as
+     * scrolling, will be inhibited. However, to account for the possibility of incorrect
+     * classification, the default scrolling will only be inhibited if the gesture moves beyond
+     * (default touch slop * AMBIGUOUS_GESTURE_MULTIPLIER). Likewise, the default long press
+     * timeout will be increased for some situations where the default behaviour
+     * is to cancel it.
+     */
+    private static final int AMBIGUOUS_GESTURE_MULTIPLIER = 2;
+
     private final Handler mHandler;
     @UnsupportedAppUsage
     private final OnGestureListener mListener;
@@ -292,27 +302,27 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-            case SHOW_PRESS:
-                mListener.onShowPress(mCurrentDownEvent);
-                break;
-                
-            case LONG_PRESS:
-                dispatchLongPress();
-                break;
-                
-            case TAP:
-                // If the user's finger is still down, do not count it as a tap
-                if (mDoubleTapListener != null) {
-                    if (!mStillDown) {
-                        mDoubleTapListener.onSingleTapConfirmed(mCurrentDownEvent);
-                    } else {
-                        mDeferConfirmSingleTap = true;
-                    }
-                }
-                break;
+                case SHOW_PRESS:
+                    mListener.onShowPress(mCurrentDownEvent);
+                    break;
 
-            default:
-                throw new RuntimeException("Unknown message " + msg); //never
+                case LONG_PRESS:
+                    dispatchLongPress();
+                    break;
+
+                case TAP:
+                    // If the user's finger is still down, do not count it as a tap
+                    if (mDoubleTapListener != null) {
+                        if (!mStillDown) {
+                            mDoubleTapListener.onSingleTapConfirmed(mCurrentDownEvent);
+                        } else {
+                            mDeferConfirmSingleTap = true;
+                        }
+                    }
+                    break;
+
+                default:
+                    throw new RuntimeException("Unknown message " + msg); //never
             }
         }
     }
@@ -427,7 +437,7 @@
         if (context == null) {
             //noinspection deprecation
             touchSlop = ViewConfiguration.getTouchSlop();
-            doubleTapTouchSlop = touchSlop; // Hack rather than adding a hiden method for this
+            doubleTapTouchSlop = touchSlop; // Hack rather than adding a hidden method for this
             doubleTapSlop = ViewConfiguration.getDoubleTapSlop();
             //noinspection deprecation
             mMinimumFlingVelocity = ViewConfiguration.getMinimumFlingVelocity();
@@ -605,6 +615,10 @@
                 if (mInLongPress || mInContextClick) {
                     break;
                 }
+
+                final int motionClassification = ev.getClassification();
+                final boolean hasPendingLongPress = mHandler.hasMessages(LONG_PRESS);
+
                 final float scrollX = mLastFocusX - focusX;
                 final float scrollY = mLastFocusY - focusY;
                 if (mIsDoubleTapping) {
@@ -615,6 +629,31 @@
                     final int deltaY = (int) (focusY - mDownFocusY);
                     int distance = (deltaX * deltaX) + (deltaY * deltaY);
                     int slopSquare = isGeneratedGesture ? 0 : mTouchSlopSquare;
+
+                    final boolean ambiguousGesture =
+                            motionClassification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE;
+                    final boolean shouldInhibitDefaultAction =
+                            hasPendingLongPress && ambiguousGesture;
+                    if (shouldInhibitDefaultAction) {
+                        // Inhibit default long press
+                        if (distance > slopSquare) {
+                            // The default action here is to remove long press. But if the touch
+                            // slop below gets increased, and we never exceed the modified touch
+                            // slop while still receiving AMBIGUOUS_GESTURE, we risk that *nothing*
+                            // will happen in response to user input. To prevent this,
+                            // reschedule long press with a modified timeout.
+                            mHandler.removeMessages(LONG_PRESS);
+                            final int longPressTimeout = ViewConfiguration.getLongPressTimeout();
+                            mHandler.sendEmptyMessageAtTime(LONG_PRESS, ev.getDownTime()
+                                    + longPressTimeout * AMBIGUOUS_GESTURE_MULTIPLIER);
+                        }
+                        // Inhibit default scroll. If a gesture is ambiguous, we prevent scroll
+                        // until the gesture is resolved.
+                        // However, for safety, simply increase the touch slop in case the
+                        // classification is erroneous. Since the value is squared, multiply twice.
+                        slopSquare *= AMBIGUOUS_GESTURE_MULTIPLIER * AMBIGUOUS_GESTURE_MULTIPLIER;
+                    }
+
                     if (distance > slopSquare) {
                         handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
                         mLastFocusX = focusX;
@@ -633,6 +672,12 @@
                     mLastFocusX = focusX;
                     mLastFocusY = focusY;
                 }
+                final boolean deepPress =
+                        motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS;
+                if (deepPress && hasPendingLongPress) {
+                    mHandler.removeMessages(LONG_PRESS);
+                    mHandler.sendEmptyMessage(LONG_PRESS);
+                }
                 break;
 
             case MotionEvent.ACTION_UP:
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 330d72f..42ac880 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -51,6 +51,7 @@
 import android.view.AppTransitionAnimationSpec;
 import android.view.WindowContentFrameStats;
 import android.view.WindowManager;
+import android.view.SurfaceControl;
 
 /**
  * System private interface to the window manager.
@@ -555,8 +556,8 @@
      * display content info to any SurfaceControl, as this would be a security issue.
      *
      * @param displayId The id of the display.
-     * @param surfaceControlHandle The SurfaceControl handle that the top level layers for the
+     * @param surfaceControlHandle The SurfaceControl that the top level layers for the
      *        display should be re-parented to.
      */
-    void reparentDisplayContent(int displayId, in IBinder surfaceControlHandle);
+    void reparentDisplayContent(int displayId, in SurfaceControl sc);
 }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index d1115c7..658f06a 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -99,7 +99,7 @@
             out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
             out Rect outOutsets, out Rect outBackdropFrame,
             out DisplayCutout.ParcelableWrapper displayCutout,
-            out MergedConfiguration outMergedConfiguration, out Surface outSurface,
+            out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
             out InsetsState insetsState);
 
     /*
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 7b9f78e..7291d0b 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -45,7 +45,9 @@
  * @hide
  */
 @VisibleForTesting
-public class InsetsAnimationControlImpl implements WindowInsetsAnimationController {
+public class InsetsAnimationControlImpl implements WindowInsetsAnimationController  {
+
+    private final Rect mTmpFrame = new Rect();
 
     private final WindowInsetsAnimationControlListener mListener;
     private final SparseArray<InsetsSourceConsumer> mConsumers;
@@ -61,19 +63,23 @@
     private final InsetsState mInitialInsetsState;
     private final @InsetType int mTypes;
     private final Supplier<SyncRtSurfaceTransactionApplier> mTransactionApplierSupplier;
-
+    private final InsetsController mController;
+    private final WindowInsetsAnimationListener.InsetsAnimation mAnimation;
     private Insets mCurrentInsets;
+    private Insets mPendingInsets;
 
     @VisibleForTesting
     public InsetsAnimationControlImpl(SparseArray<InsetsSourceConsumer> consumers, Rect frame,
             InsetsState state, WindowInsetsAnimationControlListener listener,
             @InsetType int types,
-            Supplier<SyncRtSurfaceTransactionApplier> transactionApplierSupplier) {
+            Supplier<SyncRtSurfaceTransactionApplier> transactionApplierSupplier,
+            InsetsController controller) {
         mConsumers = consumers;
         mListener = listener;
         mTypes = types;
         mTransactionApplierSupplier = transactionApplierSupplier;
-        mInitialInsetsState = new InsetsState(state);
+        mController = controller;
+        mInitialInsetsState = new InsetsState(state, true /* copySources */);
         mCurrentInsets = getInsetsFromState(mInitialInsetsState, frame, null /* typeSideMap */);
         mHiddenInsets = calculateInsets(mInitialInsetsState, frame, consumers, false /* shown */,
                 null /* typeSideMap */);
@@ -83,6 +89,10 @@
 
         // TODO: Check for controllability first and wait for IME if needed.
         listener.onReady(this, types);
+
+        mAnimation = new WindowInsetsAnimationListener.InsetsAnimation(mTypes, mHiddenInsets,
+                mShownInsets);
+        mController.dispatchAnimationStarted(mAnimation);
     }
 
     @Override
@@ -108,29 +118,36 @@
 
     @Override
     public void changeInsets(Insets insets) {
-        insets = sanitize(insets);
-        final Insets offset = Insets.subtract(mShownInsets, insets);
+        mPendingInsets = sanitize(insets);
+        mController.scheduleApplyChangeInsets();
+    }
+
+    @VisibleForTesting
+    public void applyChangeInsets(InsetsState state) {
+        final Insets offset = Insets.subtract(mShownInsets, mPendingInsets);
         ArrayList<SurfaceParams> params = new ArrayList<>();
         if (offset.left != 0) {
-            updateLeashesForSide(INSET_SIDE_LEFT, offset.left, params);
+            updateLeashesForSide(INSET_SIDE_LEFT, offset.left, params, state);
         }
         if (offset.top != 0) {
-            updateLeashesForSide(INSET_SIDE_TOP, offset.top, params);
+            updateLeashesForSide(INSET_SIDE_TOP, offset.top, params, state);
         }
         if (offset.right != 0) {
-            updateLeashesForSide(INSET_SIDE_RIGHT, offset.right, params);
+            updateLeashesForSide(INSET_SIDE_RIGHT, offset.right, params, state);
         }
         if (offset.bottom != 0) {
-            updateLeashesForSide(INSET_SIDE_BOTTOM, offset.bottom, params);
+            updateLeashesForSide(INSET_SIDE_BOTTOM, offset.bottom, params, state);
         }
         SyncRtSurfaceTransactionApplier applier = mTransactionApplierSupplier.get();
         applier.scheduleApply(params.toArray(new SurfaceParams[params.size()]));
-        mCurrentInsets = insets;
+        mCurrentInsets = mPendingInsets;
     }
 
     @Override
     public void finish(int shownTypes) {
         // TODO
+
+        mController.dispatchAnimationFinished(mAnimation);
     }
 
     private Insets calculateInsets(InsetsState state, Rect frame,
@@ -145,8 +162,9 @@
     private Insets getInsetsFromState(InsetsState state, Rect frame,
             @Nullable @InsetSide SparseIntArray typeSideMap) {
         return state.calculateInsets(frame, false /* isScreenRound */,
-                false /* alwaysConsumerNavBar */, null /* displayCutout */, typeSideMap)
-                .getSystemWindowInsets();
+                false /* alwaysConsumerNavBar */, null /* displayCutout */,
+                null /* legacyContentInsets */, null /* legacyStableInsets */, typeSideMap)
+               .getInsets(mTypes);
     }
 
     private Insets sanitize(Insets insets) {
@@ -154,7 +172,7 @@
     }
 
     private void updateLeashesForSide(@InsetSide int side, int inset,
-            ArrayList<SurfaceParams> surfaceParams) {
+            ArrayList<SurfaceParams> surfaceParams, InsetsState state) {
         ArraySet<InsetsSourceConsumer> items = mSideSourceMap.get(side);
         // TODO: Implement behavior when inset spans over multiple types
         for (int i = items.size() - 1; i >= 0; i--) {
@@ -162,24 +180,32 @@
             final InsetsSource source = mInitialInsetsState.getSource(consumer.getType());
             final SurfaceControl leash = consumer.getControl().getLeash();
             mTmpMatrix.setTranslate(source.getFrame().left, source.getFrame().top);
-            addTranslationToMatrix(side, inset, mTmpMatrix);
+
+            mTmpFrame.set(source.getFrame());
+            addTranslationToMatrix(side, inset, mTmpMatrix, mTmpFrame);
+
+            state.getSource(source.getType()).setFrame(mTmpFrame);
             surfaceParams.add(new SurfaceParams(leash, 1f, mTmpMatrix, null, 0, 0f));
         }
     }
 
-    private void addTranslationToMatrix(@InsetSide int side, int inset, Matrix m) {
+    private void addTranslationToMatrix(@InsetSide int side, int inset, Matrix m, Rect frame) {
         switch (side) {
             case INSET_SIDE_LEFT:
                 m.postTranslate(-inset, 0);
+                frame.offset(-inset, 0);
                 break;
             case INSET_SIDE_TOP:
                 m.postTranslate(0, -inset);
+                frame.offset(0, -inset);
                 break;
             case INSET_SIDE_RIGHT:
                 m.postTranslate(inset, 0);
+                frame.offset(inset, 0);
                 break;
             case INSET_SIDE_BOTTOM:
                 m.postTranslate(0, inset);
+                frame.offset(0, inset);
                 break;
         }
     }
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 01af37e..dd6231d 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.Insets;
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.util.ArraySet;
@@ -49,9 +50,33 @@
 
     private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();
     private final ArrayList<InsetsAnimationControlImpl> mAnimationControls = new ArrayList<>();
+    private WindowInsets mLastInsets;
+
+    private boolean mAnimCallbackScheduled;
+
+    private final Runnable mAnimCallback;
+
+    private final Rect mLastLegacyContentInsets = new Rect();
+    private final Rect mLastLegacyStableInsets = new Rect();
 
     public InsetsController(ViewRootImpl viewRoot) {
         mViewRoot = viewRoot;
+        mAnimCallback = () -> {
+            mAnimCallbackScheduled = false;
+            if (mAnimationControls.isEmpty()) {
+                return;
+            }
+
+            InsetsState state = new InsetsState(mState, true /* copySources */);
+            for (int i = mAnimationControls.size() - 1; i >= 0; i--) {
+                mAnimationControls.get(i).applyChangeInsets(state);
+            }
+            WindowInsets insets = state.calculateInsets(mFrame, mLastInsets.isRound(),
+                    mLastInsets.shouldAlwaysConsumeNavBar(), mLastInsets.getDisplayCutout(),
+                    mLastLegacyContentInsets, mLastLegacyStableInsets,
+                    null /* typeSideMap */);
+            mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets);
+        };
     }
 
     void onFrameChanged(Rect frame) {
@@ -81,9 +106,14 @@
      */
     @VisibleForTesting
     public WindowInsets calculateInsets(boolean isScreenRound,
-            boolean alwaysConsumeNavBar, DisplayCutout cutout) {
-        return mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout,
+            boolean alwaysConsumeNavBar, DisplayCutout cutout, Rect legacyContentInsets,
+            Rect legacyStableInsets) {
+        mLastLegacyContentInsets.set(legacyContentInsets);
+        mLastLegacyStableInsets.set(legacyStableInsets);
+        mLastInsets = mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout,
+                legacyContentInsets, legacyStableInsets,
                 null /* typeSideMap */);
+        return mLastInsets;
     }
 
     /**
@@ -148,7 +178,7 @@
         }
         final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(consumers,
                 mFrame, mState, listener, types,
-                () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView));
+                () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView), this);
         mAnimationControls.add(controller);
     }
 
@@ -200,4 +230,23 @@
         pw.println(prefix); pw.println("InsetsController:");
         mState.dump(prefix + "  ", pw);
     }
+
+    @VisibleForTesting
+    public void dispatchAnimationStarted(WindowInsetsAnimationListener.InsetsAnimation animation) {
+        mViewRoot.mView.dispatchWindowInsetsAnimationStarted(animation);
+    }
+
+    @VisibleForTesting
+    public void dispatchAnimationFinished(WindowInsetsAnimationListener.InsetsAnimation animation) {
+        mViewRoot.mView.dispatchWindowInsetsAnimationFinished(animation);
+    }
+
+    @VisibleForTesting
+    public void scheduleApplyChangeInsets() {
+        if (!mAnimCallbackScheduled) {
+            mViewRoot.mChoreographer.postCallback(Choreographer.CALLBACK_INSETS_ANIMATION,
+                    mAnimCallback, null /* token*/);
+            mAnimCallbackScheduled = true;
+        }
+    }
 }
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 3f8f882..529776e 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -16,6 +16,9 @@
 
 package android.view;
 
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
+import static android.view.WindowInsets.Type.indexOf;
+
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.graphics.Insets;
@@ -105,6 +108,10 @@
         set(copy);
     }
 
+    public InsetsState(InsetsState copy, boolean copySources) {
+        set(copy, copySources);
+    }
+
     /**
      * Calculates {@link WindowInsets} based on the current source configuration.
      *
@@ -113,42 +120,54 @@
      */
     public WindowInsets calculateInsets(Rect frame, boolean isScreenRound,
             boolean alwaysConsumeNavBar, DisplayCutout cutout,
+            @Nullable Rect legacyContentInsets, @Nullable Rect legacyStableInsets,
             @Nullable @InsetSide SparseIntArray typeSideMap) {
-        Insets systemInsets = Insets.NONE;
-        Insets maxInsets = Insets.NONE;
+        Insets[] typeInsetsMap = new Insets[Type.SIZE];
+        Insets[] typeMaxInsetsMap = new Insets[Type.SIZE];
         final Rect relativeFrame = new Rect(frame);
         final Rect relativeFrameMax = new Rect(frame);
+        if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_IME
+                && legacyContentInsets != null && legacyStableInsets != null) {
+            WindowInsets.assignCompatInsets(typeInsetsMap, legacyContentInsets);
+            WindowInsets.assignCompatInsets(typeMaxInsetsMap, legacyStableInsets);
+        }
         for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
             InsetsSource source = mSources.get(type);
             if (source == null) {
                 continue;
             }
-            systemInsets = processSource(source, systemInsets, relativeFrame,
-                    false /* ignoreVisibility */, typeSideMap);
+            processSource(source, relativeFrame, false /* ignoreVisibility */, typeInsetsMap,
+                    typeSideMap);
 
             // IME won't be reported in max insets as the size depends on the EditorInfo of the IME
             // target.
             if (source.getType() != TYPE_IME) {
-                maxInsets = processSource(source, maxInsets, relativeFrameMax,
-                        true /* ignoreVisibility */, null /* typeSideMap */);
+                processSource(source, relativeFrameMax, true /* ignoreVisibility */,
+                        typeMaxInsetsMap, null /* typeSideMap */);
             }
         }
-        return new WindowInsets(new Rect(systemInsets), null, new Rect(maxInsets), isScreenRound,
+        return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, isScreenRound,
                 alwaysConsumeNavBar, cutout);
     }
 
-    private Insets processSource(InsetsSource source, Insets insets, Rect relativeFrame,
-            boolean ignoreVisibility, @Nullable @InsetSide SparseIntArray typeSideMap) {
-        Insets currentInsets = source.calculateInsets(relativeFrame, ignoreVisibility);
-        insets = Insets.add(currentInsets, insets);
-        relativeFrame.inset(insets);
-        if (typeSideMap != null && !Insets.NONE.equals(currentInsets)) {
-            @InsetSide int insetSide = getInsetSide(currentInsets);
+    private void processSource(InsetsSource source, Rect relativeFrame, boolean ignoreVisibility,
+            Insets[] typeInsetsMap, @Nullable @InsetSide SparseIntArray typeSideMap) {
+        Insets insets = source.calculateInsets(relativeFrame, ignoreVisibility);
+
+        int index = indexOf(toPublicType(source.getType()));
+        Insets existing = typeInsetsMap[index];
+        if (existing == null) {
+            typeInsetsMap[index] = insets;
+        } else {
+            typeInsetsMap[index] = Insets.max(existing, insets);
+        }
+
+        if (typeSideMap != null && !Insets.NONE.equals(insets)) {
+            @InsetSide int insetSide = getInsetSide(insets);
             if (insetSide != INSET_SIDE_UNKNWON) {
-                typeSideMap.put(source.getType(), getInsetSide(currentInsets));
+                typeSideMap.put(source.getType(), getInsetSide(insets));
             }
         }
-        return insets;
     }
 
     /**
@@ -229,6 +248,21 @@
         return result;
     }
 
+    static @InsetType int toPublicType(@InternalInsetType int type) {
+        switch (type) {
+            case TYPE_TOP_BAR:
+                return Type.TOP_BAR;
+            case TYPE_SIDE_BAR_1:
+            case TYPE_SIDE_BAR_2:
+            case TYPE_SIDE_BAR_3:
+                return Type.SIDE_BARS;
+            case TYPE_IME:
+                return Type.IME;
+            default:
+                throw new IllegalArgumentException("Unknown type: " + type);
+        }
+    }
+
     public static boolean getDefaultVisibly(@InsetType int type) {
         switch (type) {
             case TYPE_TOP_BAR:
@@ -250,7 +284,7 @@
         }
     }
 
-    static String typeToString(int type) {
+    public static String typeToString(int type) {
         switch (type) {
             case TYPE_TOP_BAR:
                 return "TYPE_TOP_BAR";
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 9cced4e..f9a46b1 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -818,7 +818,10 @@
     public static final int KEYCODE_THUMBS_UP = 286;
     /** Key code constant: Thumbs down key. Apps can use this to let user downvote content. */
     public static final int KEYCODE_THUMBS_DOWN = 287;
-    /** Key code constant: Consumed by system to switch current viewer profile. */
+    /**
+     * Key code constant: Used to switch current {@link android.accounts.Account} that is
+     * consuming content. May be consumed by system to set account globally.
+     */
     public static final int KEYCODE_PROFILE_SWITCH = 288;
 
     /**
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index be81c06..dc7c343 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -22,6 +22,7 @@
 import android.annotation.SystemService;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
@@ -29,6 +30,7 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -38,6 +40,9 @@
 
 import com.android.internal.R;
 
+import dalvik.system.PathClassLoader;
+import java.io.File;
+import java.lang.reflect.Method;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -72,6 +77,10 @@
     private static final String TAG = LayoutInflater.class.getSimpleName();
     private static final boolean DEBUG = false;
 
+    private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY
+        = "view.precompiled_layout_enabled";
+    private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex";
+
     /** Empty stack trace used to avoid log spam in re-throw exceptions. */
     private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
 
@@ -93,6 +102,13 @@
     private Factory2 mPrivateFactory;
     private Filter mFilter;
 
+    // Indicates whether we should try to inflate layouts using a precompiled layout instead of
+    // inflating from the XML resource.
+    private boolean mUseCompiledView;
+    // This variable holds the classloader that will be used to look for precompiled layouts. The
+    // The classloader includes the generated compiled_view.dex file.
+    private ClassLoader mPrecompiledClassLoader;
+
     @UnsupportedAppUsage
     final Object[] mConstructorArgs = new Object[2];
 
@@ -223,6 +239,7 @@
      */
     protected LayoutInflater(Context context) {
         mContext = context;
+        initPrecompiledViews();
     }
 
     /**
@@ -239,6 +256,7 @@
         mFactory2 = original.mFactory2;
         mPrivateFactory = original.mPrivateFactory;
         setFilter(original.mFilter);
+        initPrecompiledViews();
     }
 
     /**
@@ -380,6 +398,41 @@
         }
     }
 
+    private void initPrecompiledViews() {
+        // Check if precompiled layouts are enabled by a system property.
+        mUseCompiledView =
+            SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false);
+        if (!mUseCompiledView) {
+            return;
+        }
+
+        // Make sure the application allows code generation
+        ApplicationInfo appInfo = mContext.getApplicationInfo();
+        if ((appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PREFER_CODE_INTEGRITY) != 0
+            || appInfo.isPrivilegedApp()) {
+            mUseCompiledView = false;
+            return;
+        }
+
+        // Try to load the precompiled layout file.
+        try {
+            mPrecompiledClassLoader = mContext.getClassLoader();
+            String dexFile = mContext.getCodeCacheDir() + COMPILED_VIEW_DEX_FILE_NAME;
+            if (new File(dexFile).exists()) {
+                mPrecompiledClassLoader = new PathClassLoader(dexFile, mPrecompiledClassLoader);
+            } else {
+                // If the precompiled layout file doesn't exist, then disable precompiled
+                // layouts.
+                mUseCompiledView = false;
+            }
+        } catch (Throwable e) {
+            if (DEBUG) {
+                Log.e(TAG, "Failed to initialized precompiled views layouts", e);
+            }
+            mUseCompiledView = false;
+        }
+    }
+
     /**
      * Inflate a new view hierarchy from the specified xml resource. Throws
      * {@link InflateException} if there is an error.
@@ -436,10 +489,14 @@
         final Resources res = getContext().getResources();
         if (DEBUG) {
             Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
-                    + Integer.toHexString(resource) + ")");
+                  + Integer.toHexString(resource) + ")");
         }
 
-        final XmlResourceParser parser = res.getLayout(resource);
+        View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
+        if (view != null) {
+            return view;
+        }
+        XmlResourceParser parser = res.getLayout(resource);
         try {
             return inflate(parser, root, attachToRoot);
         } finally {
@@ -447,6 +504,73 @@
         }
     }
 
+    private @Nullable
+    View tryInflatePrecompiled(@LayoutRes int resource, Resources res, @Nullable ViewGroup root,
+        boolean attachToRoot) {
+        if (!mUseCompiledView) {
+            return null;
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate (precompiled)");
+
+        // Try to inflate using a precompiled layout.
+        String pkg = res.getResourcePackageName(resource);
+        String layout = res.getResourceEntryName(resource);
+
+        try {
+            Class clazz = mPrecompiledClassLoader.loadClass("" + pkg + ".CompiledView");
+            Method inflater = clazz.getMethod(layout, Context.class, int.class);
+            View view = (View) inflater.invoke(null, mContext, resource);
+
+            if (view != null && root != null) {
+                // We were able to use the precompiled inflater, but now we need to do some work to
+                // attach the view to the root correctly.
+                XmlResourceParser parser = res.getLayout(resource);
+                try {
+                    AttributeSet attrs = Xml.asAttributeSet(parser);
+                    advanceToRootNode(parser);
+                    ViewGroup.LayoutParams params = root.generateLayoutParams(attrs);
+
+                    if (attachToRoot) {
+                        root.addView(view, params);
+                    } else {
+                        view.setLayoutParams(params);
+                    }
+                } finally {
+                    parser.close();
+                }
+            }
+
+            return view;
+        } catch (Throwable e) {
+            if (DEBUG) {
+                Log.e(TAG, "Failed to use precompiled view", e);
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+        return null;
+    }
+
+    /**
+     * Advances the given parser to the first START_TAG. Throws InflateException if no start tag is
+     * found.
+     */
+    private void advanceToRootNode(XmlPullParser parser)
+        throws InflateException, IOException, XmlPullParserException {
+        // Look for the root node.
+        int type;
+        while ((type = parser.next()) != XmlPullParser.START_TAG &&
+            type != XmlPullParser.END_DOCUMENT) {
+            // Empty
+        }
+
+        if (type != XmlPullParser.START_TAG) {
+            throw new InflateException(parser.getPositionDescription()
+                + ": No start tag found!");
+        }
+    }
+
     /**
      * Inflate a new view hierarchy from the specified XML node. Throws
      * {@link InflateException} if there is an error.
@@ -480,18 +604,7 @@
             View result = root;
 
             try {
-                // Look for the root node.
-                int type;
-                while ((type = parser.next()) != XmlPullParser.START_TAG &&
-                        type != XmlPullParser.END_DOCUMENT) {
-                    // Empty
-                }
-
-                if (type != XmlPullParser.START_TAG) {
-                    throw new InflateException(parser.getPositionDescription()
-                            + ": No start tag found!");
-                }
-
+                advanceToRootNode(parser);
                 final String name = parser.getName();
 
                 if (DEBUG) {
@@ -784,24 +897,8 @@
             ta.recycle();
         }
 
-        if (name.equals(TAG_1995)) {
-            // Let's party like it's 1995!
-            return new BlinkLayout(context, attrs);
-        }
-
         try {
-            View view;
-            if (mFactory2 != null) {
-                view = mFactory2.onCreateView(parent, name, context, attrs);
-            } else if (mFactory != null) {
-                view = mFactory.onCreateView(name, context, attrs);
-            } else {
-                view = null;
-            }
-
-            if (view == null && mPrivateFactory != null) {
-                view = mPrivateFactory.onCreateView(parent, name, context, attrs);
-            }
+            View view = tryCreateView(parent, name, context, attrs);
 
             if (view == null) {
                 final Object lastContext = mConstructorArgs[0];
@@ -836,6 +933,48 @@
     }
 
     /**
+     * Tries to create a view from a tag name using the supplied attribute set.
+     *
+     * This method gives the factory provided by {@link LayoutInflater#setFactory} and
+     * {@link LayoutInflater#setFactory2} a chance to create a view. However, it does not apply all
+     * of the general view creation logic, and thus may return {@code null} for some tags. This
+     * method is used by {@link LayoutInflater#inflate} in creating {@code View} objects.
+     *
+     * @hide for use by precompiled layouts.
+     *
+     * @param parent the parent view, used to inflate layout params
+     * @param name the name of the XML tag used to define the view
+     * @param context the inflation context for the view, typically the
+     *                {@code parent} or base layout inflater context
+     * @param attrs the attribute set for the XML tag used to define the view
+     */
+    @UnsupportedAppUsage(trackingBug = 122360734)
+    @Nullable
+    public final View tryCreateView(@Nullable View parent, @NonNull String name,
+        @NonNull Context context,
+        @NonNull AttributeSet attrs) {
+        if (name.equals(TAG_1995)) {
+            // Let's party like it's 1995!
+            return new BlinkLayout(context, attrs);
+        }
+
+        View view;
+        if (mFactory2 != null) {
+            view = mFactory2.onCreateView(parent, name, context, attrs);
+        } else if (mFactory != null) {
+            view = mFactory.onCreateView(name, context, attrs);
+        } else {
+            view = null;
+        }
+
+        if (view == null && mPrivateFactory != null) {
+            view = mPrivateFactory.onCreateView(parent, name, context, attrs);
+        }
+
+        return view;
+    }
+
+    /**
      * Recursive method used to inflate internal (non-root) children. This
      * method calls through to {@link #rInflate} using the parent context as
      * the inflation context.
@@ -968,82 +1107,85 @@
                 + "reference. The layout ID " + value + " is not valid.");
         }
 
-        final XmlResourceParser childParser = context.getResources().getLayout(layout);
+        final View precompiled = tryInflatePrecompiled(layout, context.getResources(),
+            (ViewGroup) parent, /*attachToRoot=*/true);
+        if (precompiled == null) {
+            final XmlResourceParser childParser = context.getResources().getLayout(layout);
 
-        try {
-            final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
+            try {
+                final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
 
-            while ((type = childParser.next()) != XmlPullParser.START_TAG &&
-                type != XmlPullParser.END_DOCUMENT) {
-                // Empty.
+                while ((type = childParser.next()) != XmlPullParser.START_TAG &&
+                    type != XmlPullParser.END_DOCUMENT) {
+                    // Empty.
+                }
+
+                if (type != XmlPullParser.START_TAG) {
+                    throw new InflateException(childParser.getPositionDescription() +
+                        ": No start tag found!");
+                }
+
+                final String childName = childParser.getName();
+
+                if (TAG_MERGE.equals(childName)) {
+                    // The <merge> tag doesn't support android:theme, so
+                    // nothing special to do here.
+                    rInflate(childParser, parent, context, childAttrs, false);
+                } else {
+                    final View view = createViewFromTag(parent, childName,
+                        context, childAttrs, hasThemeOverride);
+                    final ViewGroup group = (ViewGroup) parent;
+
+                    final TypedArray a = context.obtainStyledAttributes(
+                        attrs, R.styleable.Include);
+                    final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
+                    final int visibility = a.getInt(R.styleable.Include_visibility, -1);
+                    a.recycle();
+
+                    // We try to load the layout params set in the <include /> tag.
+                    // If the parent can't generate layout params (ex. missing width
+                    // or height for the framework ViewGroups, though this is not
+                    // necessarily true of all ViewGroups) then we expect it to throw
+                    // a runtime exception.
+                    // We catch this exception and set localParams accordingly: true
+                    // means we successfully loaded layout params from the <include>
+                    // tag, false means we need to rely on the included layout params.
+                    ViewGroup.LayoutParams params = null;
+                    try {
+                        params = group.generateLayoutParams(attrs);
+                    } catch (RuntimeException e) {
+                        // Ignore, just fail over to child attrs.
+                    }
+                    if (params == null) {
+                        params = group.generateLayoutParams(childAttrs);
+                    }
+                    view.setLayoutParams(params);
+
+                    // Inflate all children.
+                    rInflateChildren(childParser, view, childAttrs, true);
+
+                    if (id != View.NO_ID) {
+                        view.setId(id);
+                    }
+
+                    switch (visibility) {
+                        case 0:
+                            view.setVisibility(View.VISIBLE);
+                            break;
+                        case 1:
+                            view.setVisibility(View.INVISIBLE);
+                            break;
+                        case 2:
+                            view.setVisibility(View.GONE);
+                            break;
+                    }
+
+                    group.addView(view);
+                }
+            } finally {
+                childParser.close();
             }
-
-            if (type != XmlPullParser.START_TAG) {
-                throw new InflateException(childParser.getPositionDescription() +
-                    ": No start tag found!");
-            }
-
-            final String childName = childParser.getName();
-
-            if (TAG_MERGE.equals(childName)) {
-                // The <merge> tag doesn't support android:theme, so
-                // nothing special to do here.
-                rInflate(childParser, parent, context, childAttrs, false);
-            } else {
-                final View view = createViewFromTag(parent, childName,
-                    context, childAttrs, hasThemeOverride);
-                final ViewGroup group = (ViewGroup) parent;
-
-                final TypedArray a = context.obtainStyledAttributes(
-                    attrs, R.styleable.Include);
-                final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
-                final int visibility = a.getInt(R.styleable.Include_visibility, -1);
-                a.recycle();
-
-                // We try to load the layout params set in the <include /> tag.
-                // If the parent can't generate layout params (ex. missing width
-                // or height for the framework ViewGroups, though this is not
-                // necessarily true of all ViewGroups) then we expect it to throw
-                // a runtime exception.
-                // We catch this exception and set localParams accordingly: true
-                // means we successfully loaded layout params from the <include>
-                // tag, false means we need to rely on the included layout params.
-                ViewGroup.LayoutParams params = null;
-                try {
-                    params = group.generateLayoutParams(attrs);
-                } catch (RuntimeException e) {
-                    // Ignore, just fail over to child attrs.
-                }
-                if (params == null) {
-                    params = group.generateLayoutParams(childAttrs);
-                }
-                view.setLayoutParams(params);
-
-                // Inflate all children.
-                rInflateChildren(childParser, view, childAttrs, true);
-
-                if (id != View.NO_ID) {
-                    view.setId(id);
-                }
-
-                switch (visibility) {
-                    case 0:
-                        view.setVisibility(View.VISIBLE);
-                        break;
-                    case 1:
-                        view.setVisibility(View.INVISIBLE);
-                        break;
-                    case 2:
-                        view.setVisibility(View.GONE);
-                        break;
-                }
-
-                group.addView(view);
-            }
-        } finally {
-            childParser.close();
         }
-
         LayoutInflater.consumeChildElements(parser);
     }
 
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index a86abe5..9d3552f 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -18,6 +18,9 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Matrix;
@@ -30,6 +33,7 @@
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 
+import java.lang.annotation.Retention;
 import java.util.Objects;
 
 /**
@@ -462,7 +466,7 @@
 
     /**
      * This flag indicates that the event has been generated by a gesture generator. It
-     * provides a hint to the GestureDector to not apply any touch slop.
+     * provides a hint to the GestureDetector to not apply any touch slop.
      *
      * @hide
      */
@@ -1391,6 +1395,42 @@
     };
 
     /**
+     * Classification constant: None.
+     *
+     * No additional information is available about the current motion event stream.
+     *
+     * @see #getClassification
+     */
+    public static final int CLASSIFICATION_NONE = 0;
+
+    /**
+     * Classification constant: Ambiguous gesture.
+     *
+     * The user's intent with respect to the current event stream is not yet determined.
+     * Gestural actions, such as scrolling, should be inhibited until the classification resolves
+     * to another value or the event stream ends.
+     *
+     * @see #getClassification
+     */
+    public static final int CLASSIFICATION_AMBIGUOUS_GESTURE = 1;
+
+    /**
+     * Classification constant: Deep press.
+     *
+     * The current event stream represents the user intentionally pressing harder on the screen.
+     * This classification type should be used to accelerate the long press behaviour.
+     *
+     * @see #getClassification
+     */
+    public static final int CLASSIFICATION_DEEP_PRESS = 2;
+
+    /** @hide */
+    @Retention(SOURCE)
+    @IntDef(prefix = { "CLASSIFICATION" }, value = {
+            CLASSIFICATION_NONE, CLASSIFICATION_AMBIGUOUS_GESTURE, CLASSIFICATION_DEEP_PRESS})
+    public @interface Classification {};
+
+    /**
      * Tool type constant: Unknown tool type.
      * This constant is used when the tool type is not known or is not relevant,
      * such as for a trackball or other non-pointing device.
@@ -1478,7 +1518,7 @@
 
     private static native long nativeInitialize(long nativePtr,
             int deviceId, int source, int displayId, int action, int flags, int edgeFlags,
-            int metaState, int buttonState,
+            int metaState, int buttonState, @Classification int classification,
             float xOffset, float yOffset, float xPrecision, float yPrecision,
             long downTimeNanos, long eventTimeNanos,
             int pointerCount, PointerProperties[] pointerIds, PointerCoords[] pointerCoords);
@@ -1548,6 +1588,8 @@
     @CriticalNative
     private static native void nativeSetButtonState(long nativePtr, int buttonState);
     @CriticalNative
+    private static native int nativeGetClassification(long nativePtr);
+    @CriticalNative
     private static native int nativeGetActionButton(long nativePtr);
     @CriticalNative
     private static native void nativeSetActionButton(long nativePtr, int actionButton);
@@ -1648,7 +1690,7 @@
         MotionEvent ev = obtain();
         ev.mNativePtr = nativeInitialize(ev.mNativePtr,
                 deviceId, source, displayId, action, flags, edgeFlags, metaState, buttonState,
-                0, 0, xPrecision, yPrecision,
+                CLASSIFICATION_NONE, 0, 0, xPrecision, yPrecision,
                 downTime * NS_PER_MS, eventTime * NS_PER_MS,
                 pointerCount, pointerProperties, pointerCoords);
         if (ev.mNativePtr == 0) {
@@ -1833,7 +1875,7 @@
 
             ev.mNativePtr = nativeInitialize(ev.mNativePtr,
                     deviceId, source, displayId,
-                    action, 0, edgeFlags, metaState, 0,
+                    action, 0, edgeFlags, metaState, 0 /*buttonState*/, CLASSIFICATION_NONE,
                     0, 0, xPrecision, yPrecision,
                     downTime * NS_PER_MS, eventTime * NS_PER_MS,
                     1, pp, pc);
@@ -2539,6 +2581,18 @@
     }
 
     /**
+     * Returns the classification for the current gesture.
+     * The classification may change as more events become available for the same gesture.
+     *
+     * @see #CLASSIFICATION_NONE
+     * @see #CLASSIFICATION_AMBIGUOUS_GESTURE
+     * @see #CLASSIFICATION_DEEP_PRESS
+     */
+    public @Classification int getClassification() {
+        return nativeGetClassification(mNativePtr);
+    }
+
+    /**
      * Gets which button has been modified during a press or release action.
      *
      * For actions other than {@link #ACTION_BUTTON_PRESS} and {@link #ACTION_BUTTON_RELEASE}
@@ -3172,7 +3226,7 @@
     /**
      * Adds all of the movement samples of the specified event to this one if
      * it is compatible.  To be compatible, the event must have the same device id,
-     * source, display id, action, flags, pointer count, pointer properties.
+     * source, display id, action, flags, classification, pointer count, pointer properties.
      *
      * Only applies to {@link #ACTION_MOVE} or {@link #ACTION_HOVER_MOVE} events.
      *
@@ -3194,7 +3248,9 @@
         if (nativeGetDeviceId(mNativePtr) != nativeGetDeviceId(event.mNativePtr)
                 || nativeGetSource(mNativePtr) != nativeGetSource(event.mNativePtr)
                 || nativeGetDisplayId(mNativePtr) != nativeGetDisplayId(event.mNativePtr)
-                || nativeGetFlags(mNativePtr) != nativeGetFlags(event.mNativePtr)) {
+                || nativeGetFlags(mNativePtr) != nativeGetFlags(event.mNativePtr)
+                || nativeGetClassification(mNativePtr)
+                        != nativeGetClassification(event.mNativePtr)) {
             return false;
         }
 
@@ -3282,7 +3338,7 @@
                     nativeGetDisplayId(mNativePtr),
                     nativeGetAction(mNativePtr), nativeGetFlags(mNativePtr),
                     nativeGetEdgeFlags(mNativePtr), nativeGetMetaState(mNativePtr),
-                    nativeGetButtonState(mNativePtr),
+                    nativeGetButtonState(mNativePtr), nativeGetClassification(mNativePtr),
                     nativeGetXOffset(mNativePtr), nativeGetYOffset(mNativePtr),
                     nativeGetXPrecision(mNativePtr), nativeGetYPrecision(mNativePtr),
                     nativeGetDownTimeNanos(mNativePtr),
@@ -3376,7 +3432,7 @@
                             nativeGetDisplayId(mNativePtr),
                             newAction, nativeGetFlags(mNativePtr),
                             nativeGetEdgeFlags(mNativePtr), nativeGetMetaState(mNativePtr),
-                            nativeGetButtonState(mNativePtr),
+                            nativeGetButtonState(mNativePtr), nativeGetClassification(mNativePtr),
                             nativeGetXOffset(mNativePtr), nativeGetYOffset(mNativePtr),
                             nativeGetXPrecision(mNativePtr), nativeGetYPrecision(mNativePtr),
                             nativeGetDownTimeNanos(mNativePtr), eventTimeNanos,
@@ -3409,6 +3465,8 @@
         }
 
         appendUnless("0", msg, ", buttonState=", MotionEvent.buttonStateToString(getButtonState()));
+        appendUnless(classificationToString(CLASSIFICATION_NONE), msg, ", classification=",
+                classificationToString(getClassification()));
         appendUnless("0", msg, ", metaState=", KeyEvent.metaStateToString(getMetaState()));
         appendUnless("0", msg, ", flags=0x", Integer.toHexString(getFlags()));
         appendUnless("0", msg, ", edgeFlags=0x", Integer.toHexString(getEdgeFlags()));
@@ -3547,6 +3605,26 @@
     }
 
     /**
+     * Returns a string that represents the symbolic name of the specified classification.
+     *
+     * @param classification The classification type.
+     * @return The symbolic name of this classification.
+     * @hide
+     */
+    public static String classificationToString(@Classification int classification) {
+        switch (classification) {
+            case CLASSIFICATION_NONE:
+                return "NONE";
+            case CLASSIFICATION_AMBIGUOUS_GESTURE:
+                return "AMBIGUOUS_GESTURE";
+            case CLASSIFICATION_DEEP_PRESS:
+                return "DEEP_PRESS";
+
+        }
+        return "NONE";
+    }
+
+    /**
      * Returns a string that represents the symbolic name of the specified tool type
      * such as "TOOL_TYPE_FINGER" or an equivalent numeric constant such as "42" if unknown.
      *
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index cf11fd0..c3d13bd 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.hardware.display.DisplayManager;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -144,7 +145,8 @@
     public static final int TYPE_DEFAULT = TYPE_ARROW;
 
     private static final PointerIcon gNullIcon = new PointerIcon(TYPE_NULL);
-    private static final SparseArray<PointerIcon> gSystemIcons = new SparseArray<PointerIcon>();
+    private static final SparseArray<SparseArray<PointerIcon>> gSystemIconsByDisplay =
+            new SparseArray<SparseArray<PointerIcon>>();
     private static boolean sUseLargeIcons = false;
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -163,6 +165,12 @@
     @UnsupportedAppUsage
     private int mDurationPerFrame;
 
+    /**
+     * Listener for displays lifecycle.
+     * @hide
+     */
+    private static DisplayManager.DisplayListener sDisplayListener;
+
     private PointerIcon(int type) {
         mType = type;
     }
@@ -211,7 +219,19 @@
             return gNullIcon;
         }
 
-        PointerIcon icon = gSystemIcons.get(type);
+        if (sDisplayListener == null) {
+            registerDisplayListener(context);
+        }
+
+        final int displayId = context.getDisplayId();
+        SparseArray<PointerIcon> systemIcons = gSystemIconsByDisplay.get(displayId);
+        if (systemIcons == null) {
+            systemIcons = new SparseArray<>();
+            gSystemIconsByDisplay.put(displayId, systemIcons);
+        }
+
+        PointerIcon icon = systemIcons.get(type);
+        // Reload if not in the same display.
         if (icon != null) {
             return icon;
         }
@@ -240,7 +260,7 @@
         } else {
             icon.loadResource(context, context.getResources(), resourceId);
         }
-        gSystemIcons.append(type, icon);
+        systemIcons.append(type, icon);
         return icon;
     }
 
@@ -250,7 +270,7 @@
      */
     public static void setUseLargeIcons(boolean use) {
         sUseLargeIcons = use;
-        gSystemIcons.clear();
+        gSystemIconsByDisplay.clear();
     }
 
     /**
@@ -576,4 +596,30 @@
                 return 0;
         }
     }
+
+    /**
+     * Manage system icon cache handled by display lifecycle.
+     * @param context The context.
+     */
+    private static void registerDisplayListener(@NonNull Context context) {
+        sDisplayListener = new DisplayManager.DisplayListener() {
+            @Override
+            public void onDisplayAdded(int displayId) {
+            }
+
+            @Override
+            public void onDisplayRemoved(int displayId) {
+                gSystemIconsByDisplay.remove(displayId);
+            }
+
+            @Override
+            public void onDisplayChanged(int displayId) {
+                gSystemIconsByDisplay.remove(displayId);
+            }
+        };
+
+        DisplayManager displayManager = context.getSystemService(DisplayManager.class);
+        displayManager.registerDisplayListener(sDisplayListener, null /* handler */);
+    }
+
 }
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index 567b279..1d2cf4b 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -24,6 +24,8 @@
 import static android.view.RemoteAnimationTargetProto.POSITION;
 import static android.view.RemoteAnimationTargetProto.PREFIX_ORDER_INDEX;
 import static android.view.RemoteAnimationTargetProto.SOURCE_CONTAINER_BOUNDS;
+import static android.view.RemoteAnimationTargetProto.START_BOUNDS;
+import static android.view.RemoteAnimationTargetProto.START_LEASH;
 import static android.view.RemoteAnimationTargetProto.TASK_ID;
 import static android.view.RemoteAnimationTargetProto.WINDOW_CONFIGURATION;
 
@@ -57,9 +59,15 @@
      */
     public static final int MODE_CLOSING = 1;
 
+    /**
+     * The app is in the set of resizing apps (eg. mode change) of this transition.
+     */
+    public static final int MODE_CHANGING = 2;
+
     @IntDef(prefix = { "MODE_" }, value = {
             MODE_OPENING,
-            MODE_CLOSING
+            MODE_CLOSING,
+            MODE_CHANGING
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Mode {}
@@ -83,6 +91,13 @@
     public final SurfaceControl leash;
 
     /**
+     * The {@link SurfaceControl} for the starting state of a target if this transition is
+     * MODE_CHANGING, {@code null)} otherwise. This is relative to the app window.
+     */
+    @UnsupportedAppUsage
+    public final SurfaceControl startLeash;
+
+    /**
      * Whether the app is translucent and may reveal apps behind.
      */
     @UnsupportedAppUsage
@@ -128,6 +143,15 @@
     public final Rect sourceContainerBounds;
 
     /**
+     * The starting bounds of the source container in screen space coordinates. This is {@code null}
+     * if the animation target isn't MODE_CHANGING. Since this is the starting bounds, it's size
+     * should be equivalent to the size of the starting thumbnail. Note that sourceContainerBounds
+     * is the end bounds of a change transition.
+     */
+    @UnsupportedAppUsage
+    public final Rect startBounds;
+
+    /**
      * The window configuration for the target.
      */
     @UnsupportedAppUsage
@@ -141,7 +165,8 @@
 
     public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
             Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
-            Rect sourceContainerBounds, WindowConfiguration windowConfig, boolean isNotInRecents) {
+            Rect sourceContainerBounds, WindowConfiguration windowConfig, boolean isNotInRecents,
+            SurfaceControl startLeash, Rect startBounds) {
         this.mode = mode;
         this.taskId = taskId;
         this.leash = leash;
@@ -153,6 +178,8 @@
         this.sourceContainerBounds = new Rect(sourceContainerBounds);
         this.windowConfiguration = windowConfig;
         this.isNotInRecents = isNotInRecents;
+        this.startLeash = startLeash;
+        this.startBounds = startBounds == null ? null : new Rect(startBounds);
     }
 
     public RemoteAnimationTarget(Parcel in) {
@@ -167,6 +194,8 @@
         sourceContainerBounds = in.readParcelable(null);
         windowConfiguration = in.readParcelable(null);
         isNotInRecents = in.readBoolean();
+        startLeash = in.readParcelable(null);
+        startBounds = in.readParcelable(null);
     }
 
     @Override
@@ -187,6 +216,8 @@
         dest.writeParcelable(sourceContainerBounds, 0 /* flags */);
         dest.writeParcelable(windowConfiguration, 0 /* flags */);
         dest.writeBoolean(isNotInRecents);
+        dest.writeParcelable(startLeash, 0 /* flags */);
+        dest.writeParcelable(startBounds, 0 /* flags */);
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -215,6 +246,8 @@
         position.writeToProto(proto, POSITION);
         sourceContainerBounds.writeToProto(proto, SOURCE_CONTAINER_BOUNDS);
         windowConfiguration.writeToProto(proto, WINDOW_CONFIGURATION);
+        startLeash.writeToProto(proto, START_LEASH);
+        startBounds.writeToProto(proto, START_BOUNDS);
         proto.end(token);
     }
 
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index f3cb376..7fcb2af 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -185,6 +185,18 @@
     }
 
     /**
+     * Create a Surface assosciated with a given {@link SurfaceControl}. Buffers submitted to this
+     * surface will be displayed by the system compositor according to the parameters
+     * specified by the control. Multiple surfaces may be constructed from one SurfaceControl,
+     * but only one can be connected (e.g. have an active EGL context) at a time.
+     *
+     * @param from The SurfaceControl to assosciate this Surface with
+     */
+    public Surface(SurfaceControl from) {
+        copyFrom(from);
+    }
+
+    /**
      * Create Surface from a {@link SurfaceTexture}.
      *
      * Images drawn to the Surface will be made available to the {@link
@@ -494,7 +506,6 @@
      * in to it.
      *
      * @param other {@link SurfaceControl} to copy from.
-     *
      * @hide
      */
     @UnsupportedAppUsage
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index a006e5d..863b717 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -27,9 +27,14 @@
 import static android.view.SurfaceControlProto.HASH_CODE;
 import static android.view.SurfaceControlProto.NAME;
 
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.Size;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
 import android.graphics.GraphicBuffer;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
@@ -57,16 +62,23 @@
 import java.io.Closeable;
 
 /**
- * SurfaceControl
- *  @hide
+ * Handle to an on-screen Surface managed by the system compositor. The SurfaceControl is
+ * a combination of a buffer source, and metadata about how to display the buffers.
+ * By constructing a {@link Surface} from this SurfaceControl you can submit buffers to be
+ * composited. Using {@link SurfaceControl.Transaction} you can manipulate various
+ * properties of how the buffer will be displayed on-screen. SurfaceControl's are
+ * arranged into a scene-graph like hierarchy, and as such any SurfaceControl may have
+ * a parent. Geometric properties like transform, crop, and Z-ordering will be inherited
+ * from the parent, as if the child were content in the parents buffer stream.
  */
-public class SurfaceControl implements Parcelable {
+public final class SurfaceControl implements Parcelable {
     private static final String TAG = "SurfaceControl";
 
     private static native long nativeCreate(SurfaceSession session, String name,
             int w, int h, int format, int flags, long parentObject, int windowType, int ownerUid)
             throws OutOfResourcesException;
     private static native long nativeReadFromParcel(Parcel in);
+    private static native long nativeCopyFromSurfaceControl(long nativeObject);
     private static native void nativeWriteToParcel(long nativeObject, Parcel out);
     private static native void nativeRelease(long nativeObject);
     private static native void nativeDestroy(long nativeObject);
@@ -101,6 +113,8 @@
             float dtdy, float dsdy);
     private static native void nativeSetColorTransform(long transactionObj, long nativeObject,
             float[] matrix, float[] translation);
+    private static native void nativeSetGeometry(long transactionObj, long nativeObject,
+            Rect sourceCrop, Rect dest, long orientation);
     private static native void nativeSetColor(long transactionObj, long nativeObject, float[] color);
     private static native void nativeSetFlags(long transactionObj, long nativeObject,
             int flags, int mask);
@@ -140,6 +154,7 @@
     private static native int nativeGetActiveConfig(IBinder displayToken);
     private static native boolean nativeSetActiveConfig(IBinder displayToken, int id);
     private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
+    private static native int[] nativeGetCompositionDataspaces();
     private static native int nativeGetActiveColorMode(IBinder displayToken);
     private static native boolean nativeSetActiveColorMode(IBinder displayToken,
             int colorMode);
@@ -153,11 +168,10 @@
     private static native void nativeReparentChildren(long transactionObj, long nativeObject,
             IBinder handle);
     private static native void nativeReparent(long transactionObj, long nativeObject,
-            IBinder parentHandle);
+            long newParentNativeObject);
     private static native void nativeSeverChildren(long transactionObj, long nativeObject);
     private static native void nativeSetOverrideScalingMode(long transactionObj, long nativeObject,
             int scalingMode);
-    private static native void nativeDestroy(long transactionObj, long nativeObject);
     private static native IBinder nativeGetHandle(long nativeObject);
     private static native boolean nativeGetTransformToDisplayInverse(long nativeObject);
 
@@ -165,10 +179,12 @@
 
     private static native void nativeSetInputWindowInfo(long transactionObj, long nativeObject,
             InputWindowHandle handle);
-
+    private static native void nativeTransferTouchFocus(long transactionObj, IBinder fromToken,
+            IBinder toToken);
+    private static native boolean nativeGetProtectedContentSupport();
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
-    private final String mName;
+    private String mName;
     long mNativeObject; // package visibility only for Surface.java access
 
     // TODO: Move this to native.
@@ -185,6 +201,7 @@
 
     /**
      * Surface creation flag: Surface is created hidden
+     * @hide
      */
     @UnsupportedAppUsage
     public static final int HIDDEN = 0x00000004;
@@ -195,7 +212,7 @@
      * from another process. In particular, screenshots and VNC servers will
      * be disabled, but other measures can take place, for instance the
      * surface might not be hardware accelerated.
-     *
+     * @hide
      */
     public static final int SECURE = 0x00000080;
 
@@ -219,7 +236,7 @@
      * pixel.
      * <p>
      * In some rare situations, a non pre-multiplied surface is preferable.
-     *
+     * @hide
      */
     public static final int NON_PREMULTIPLIED = 0x00000100;
 
@@ -239,6 +256,7 @@
      * </ul>
      * If the underlying buffer lacks an alpha channel, the OPAQUE flag is effectively
      * set automatically.
+     * @hide
      */
     public static final int OPAQUE = 0x00000400;
 
@@ -247,6 +265,7 @@
      * external display sink. If a hardware-protected path is not available,
      * then this surface will not be displayed on the external sink.
      *
+     * @hide
      */
     public static final int PROTECTED_APP = 0x00000800;
 
@@ -254,6 +273,7 @@
 
     /**
      * Surface creation flag: Window represents a cursor glyph.
+     * @hide
      */
     public static final int CURSOR_WINDOW = 0x00002000;
 
@@ -261,6 +281,7 @@
      * Surface creation flag: Creates a normal surface.
      * This is the default.
      *
+     * @hide
      */
     public static final int FX_SURFACE_NORMAL   = 0x00000000;
 
@@ -270,6 +291,7 @@
      * in {@link #setAlpha}.  It is an error to lock a Dim surface, since it
      * doesn't have a backing store.
      *
+     * @hide
      */
     public static final int FX_SURFACE_DIM = 0x00020000;
 
@@ -277,12 +299,14 @@
      * Surface creation flag: Creates a container surface.
      * This surface will have no buffers and will only be used
      * as a container for other surfaces, or for its InputInfo.
+     * @hide
      */
     public static final int FX_SURFACE_CONTAINER = 0x00080000;
 
     /**
      * Mask used for FX values above.
      *
+     * @hide
      */
     public static final int FX_SURFACE_MASK = 0x000F0000;
 
@@ -308,44 +332,50 @@
     /**
      * Built-in physical display id: Main display.
      * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
+     * @hide
      */
     public static final int BUILT_IN_DISPLAY_ID_MAIN = 0;
 
     /**
      * Built-in physical display id: Attached HDMI display.
      * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
+     * @hide
      */
     public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
 
-    /* Display power modes * /
-
+    // Display power modes.
     /**
      * Display power mode off: used while blanking the screen.
      * Use only with {@link SurfaceControl#setDisplayPowerMode}.
+     * @hide
      */
     public static final int POWER_MODE_OFF = 0;
 
     /**
      * Display power mode doze: used while putting the screen into low power mode.
      * Use only with {@link SurfaceControl#setDisplayPowerMode}.
+     * @hide
      */
     public static final int POWER_MODE_DOZE = 1;
 
     /**
      * Display power mode normal: used while unblanking the screen.
      * Use only with {@link SurfaceControl#setDisplayPowerMode}.
+     * @hide
      */
     public static final int POWER_MODE_NORMAL = 2;
 
     /**
      * Display power mode doze: used while putting the screen into a suspended
      * low power mode.  Use only with {@link SurfaceControl#setDisplayPowerMode}.
+     * @hide
      */
     public static final int POWER_MODE_DOZE_SUSPEND = 3;
 
     /**
      * Display power mode on: used while putting the screen into a suspended
      * full power mode.  Use only with {@link SurfaceControl#setDisplayPowerMode}.
+     * @hide
      */
     public static final int POWER_MODE_ON_SUSPEND = 4;
 
@@ -359,6 +389,30 @@
     public static final int WINDOW_TYPE_DONT_SCREENSHOT = 441731;
 
     /**
+     * internal representation of how to interpret pixel value, used only to convert to ColorSpace.
+     */
+    private static final int INTERNAL_DATASPACE_SRGB = 142671872;
+    private static final int INTERNAL_DATASPACE_DISPLAY_P3 = 143261696;
+    private static final int INTERNAL_DATASPACE_SCRGB = 411107328;
+
+    private void assignNativeObject(long nativeObject) {
+        if (mNativeObject != 0) {
+            release();
+        }
+        mNativeObject = nativeObject;
+    }
+
+    /**
+     * @hide
+     */
+    public void copyFrom(SurfaceControl other) {
+        mName = other.mName;
+        mWidth = other.mWidth;
+        mHeight = other.mHeight;
+        assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject));
+    }
+
+    /**
      * Builder class for {@link SurfaceControl} objects.
      */
     public static class Builder {
@@ -376,13 +430,21 @@
          * Begin building a SurfaceControl with a given {@link SurfaceSession}.
          *
          * @param session The {@link SurfaceSession} with which to eventually construct the surface.
+         * @hide
          */
         public Builder(SurfaceSession session) {
             mSession = session;
         }
 
         /**
-         * Construct a new {@link SurfaceControl} with the set parameters.
+         * Begin building a SurfaceControl.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Construct a new {@link SurfaceControl} with the set parameters. The builder
+         * remains valid.
          */
         public SurfaceControl build() {
             if (mWidth < 0 || mHeight < 0) {
@@ -413,7 +475,8 @@
          * @param width The buffer width in pixels.
          * @param height The buffer height in pixels.
          */
-        public Builder setBufferSize(int width, int height) {
+        public Builder setBufferSize(@IntRange(from = 0) int width,
+                @IntRange(from = 0) int height) {
             if (width < 0 || height < 0) {
                 throw new IllegalArgumentException(
                         "width and height must be positive");
@@ -427,6 +490,7 @@
          * Set the pixel format of the controlled surface's buffers, using constants from
          * {@link android.graphics.PixelFormat}.
          */
+        @NonNull
         public Builder setFormat(@PixelFormat.Format int format) {
             mFormat = format;
             return this;
@@ -439,7 +503,9 @@
          * not be displayed.
          *
          * @param protectedContent Whether to require a protected sink.
+         * @hide
          */
+        @NonNull
         public Builder setProtected(boolean protectedContent) {
             if (protectedContent) {
                 mFlags |= PROTECTED_APP;
@@ -454,7 +520,9 @@
          * will prevent the surfaces content from being copied by another process. In
          * particular screenshots and VNC servers will be disabled. This is however
          * not a complete prevention of readback as {@link #setProtected}.
+         * @hide
          */
+        @NonNull
         public Builder setSecure(boolean secure) {
             if (secure) {
                 mFlags |= SECURE;
@@ -487,6 +555,7 @@
          * were set automatically.
          * @param opaque Whether the Surface is OPAQUE.
          */
+        @NonNull
         public Builder setOpaque(boolean opaque) {
             if (opaque) {
                 mFlags |= OPAQUE;
@@ -505,7 +574,8 @@
          *
          * @param parent The parent control.
          */
-        public Builder setParent(SurfaceControl parent) {
+        @NonNull
+        public Builder setParent(@Nullable SurfaceControl parent) {
             mParent = parent;
             return this;
         }
@@ -519,6 +589,7 @@
          *
          * @param windowType A window-type
          * @param ownerUid UID of the window owner.
+         * @hide
          */
         public Builder setMetadata(int windowType, int ownerUid) {
             if (UserHandle.getAppId(Process.myUid()) != Process.SYSTEM_UID) {
@@ -537,6 +608,7 @@
          * solid color (that is, solid before plane alpha). Currently that color is black.
          *
          * @param isColorLayer Whether to create a color layer.
+         * @hide
          */
         public Builder setColorLayer(boolean isColorLayer) {
             if (isColorLayer) {
@@ -558,6 +630,7 @@
          * as a parent of renderable layers.
          *
          * @param isContainerLayer Whether to create a container layer.
+         * @hide
          */
         public Builder setContainerLayer(boolean isContainerLayer) {
             if (isContainerLayer) {
@@ -577,6 +650,7 @@
          *
          * TODO: Finish conversion to individual builder methods?
          * @param flags The combined flags
+         * @hide
          */
         public Builder setFlags(int flags) {
             mFlags = flags;
@@ -616,9 +690,6 @@
     private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
             SurfaceControl parent, int windowType, int ownerUid)
                     throws OutOfResourcesException, IllegalArgumentException {
-        if (session == null) {
-            throw new IllegalArgumentException("session must not be null");
-        }
         if (name == null) {
             throw new IllegalArgumentException("name must not be null");
         }
@@ -645,9 +716,11 @@
         mCloseGuard.open("release");
     }
 
-    // This is a transfer constructor, useful for transferring a live SurfaceControl native
-    // object to another Java wrapper which could have some different behavior, e.g.
-    // event logging.
+    /** This is a transfer constructor, useful for transferring a live SurfaceControl native
+     * object to another Java wrapper which could have some different behavior, e.g.
+     * event logging.
+     * @hide
+     */
     public SurfaceControl(SurfaceControl other) {
         mName = other.mName;
         mWidth = other.mWidth;
@@ -659,14 +732,31 @@
     }
 
     private SurfaceControl(Parcel in) {
+        readFromParcel(in);
+        mCloseGuard.open("release");
+    }
+
+    /**
+     * @hide
+     */
+    public SurfaceControl() {
+        mCloseGuard.open("release");
+    }
+
+    public void readFromParcel(Parcel in) {
+        if (in == null) {
+            throw new IllegalArgumentException("source must not be null");
+        }
+
         mName = in.readString();
         mWidth = in.readInt();
         mHeight = in.readInt();
-        mNativeObject = nativeReadFromParcel(in);
-        if (mNativeObject == 0) {
-            throw new IllegalArgumentException("Couldn't read SurfaceControl from parcel=" + in);
+
+        long object = 0;
+        if (in.readInt() != 0) {
+            object = nativeReadFromParcel(in);
         }
-        mCloseGuard.open("release");
+        assignNativeObject(object);
     }
 
     @Override
@@ -679,7 +769,16 @@
         dest.writeString(mName);
         dest.writeInt(mWidth);
         dest.writeInt(mHeight);
+        if (mNativeObject == 0) {
+            dest.writeInt(0);
+        } else {
+            dest.writeInt(1);
+        }
         nativeWriteToParcel(mNativeObject, dest);
+
+        if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
+            release();
+        }
     }
 
     /**
@@ -708,6 +807,9 @@
         }
     };
 
+    /**
+     * @hide
+     */
     @Override
     protected void finalize() throws Throwable {
         try {
@@ -723,9 +825,12 @@
     }
 
     /**
-     * Release the local reference to the server-side surface.
-     * Always call release() when you're done with a Surface.
-     * This will make the surface invalid.
+     * Release the local reference to the server-side surface. The surface
+     * may continue to exist on-screen as long as its parent continues
+     * to exist. To explicitly remove a surface from the screen use
+     * {@link Transaction#reparent} with a null-parent.
+     *
+     * Always call release() when you're done with a SurfaceControl.
      */
     public void release() {
         if (mNativeObject != 0) {
@@ -739,6 +844,7 @@
      * Free all server-side state associated with this surface and
      * release this object's reference.  This method can only be
      * called from the process that created the service.
+     * @hide
      */
     public void destroy() {
         if (mNativeObject != 0) {
@@ -750,6 +856,7 @@
 
     /**
      * Disconnect any client still connected to the surface.
+     * @hide
      */
     public void disconnect() {
         if (mNativeObject != 0) {
@@ -762,12 +869,24 @@
                 "mNativeObject is null. Have you called release() already?");
     }
 
+    /**
+     * Check whether this instance points to a valid layer with the system-compositor. For
+     * example this may be false if construction failed, or the layer was released.
+     *
+     * @return Whether this SurfaceControl is valid.
+     */
+    public boolean isValid() {
+        return mNativeObject != 0;
+    }
+
     /*
      * set surface parameters.
      * needs to be inside open/closeTransaction block
      */
 
-    /** start a transaction */
+    /** start a transaction
+     * @hide
+     */
     @UnsupportedAppUsage
     public static void openTransaction() {
         synchronized (SurfaceControl.class) {
@@ -796,6 +915,7 @@
      * This clears the supplied transaction in an identical fashion to {@link Transaction#merge}.
      * <p>
      * This is a utility for interop with legacy-code and will go away with the Global Transaction.
+     * @hide
      */
     @Deprecated
     public static void mergeToGlobalTransaction(Transaction t) {
@@ -804,46 +924,69 @@
         }
     }
 
-    /** end a transaction */
+    /** end a transaction 
+     * @hide 
+     */
     @UnsupportedAppUsage
     public static void closeTransaction() {
         closeTransaction(false);
     }
 
+    /**
+     * @hide
+     */
     public static void closeTransactionSync() {
         closeTransaction(true);
     }
 
+    /**
+     * @hide
+     */
     public void deferTransactionUntil(IBinder handle, long frame) {
         synchronized(SurfaceControl.class) {
             sGlobalTransaction.deferTransactionUntil(this, handle, frame);
         }
     }
 
+    /**
+     * @hide
+     */
     public void deferTransactionUntil(Surface barrier, long frame) {
         synchronized(SurfaceControl.class) {
             sGlobalTransaction.deferTransactionUntilSurface(this, barrier, frame);
         }
     }
 
+    /**
+     * @hide
+     */
     public void reparentChildren(IBinder newParentHandle) {
         synchronized(SurfaceControl.class) {
             sGlobalTransaction.reparentChildren(this, newParentHandle);
         }
     }
 
-    public void reparent(IBinder newParentHandle) {
+    /**
+     * @hide
+     */
+    public void reparent(SurfaceControl newParent) {
         synchronized(SurfaceControl.class) {
-            sGlobalTransaction.reparent(this, newParentHandle);
+            sGlobalTransaction.reparent(this, newParent);
         }
     }
 
+    /**
+     * @hide
+     */
     public void detachChildren() {
         synchronized(SurfaceControl.class) {
             sGlobalTransaction.detachChildren(this);
         }
     }
 
+    /**
+     * @hide
+     */
     public void setOverrideScalingMode(int scalingMode) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -851,16 +994,25 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public IBinder getHandle() {
         return nativeGetHandle(mNativeObject);
     }
 
+    /**
+     * @hide
+     */
     public static void setAnimationTransaction() {
         synchronized (SurfaceControl.class) {
             sGlobalTransaction.setAnimationTransaction();
         }
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public void setLayer(int zorder) {
         checkNotReleased();
@@ -869,6 +1021,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setRelativeLayer(SurfaceControl relativeTo, int zorder) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -876,6 +1031,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public void setPosition(float x, float y) {
         checkNotReleased();
@@ -884,6 +1042,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setGeometryAppliesWithResize() {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -891,6 +1052,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setBufferSize(int w, int h) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -898,6 +1062,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public void hide() {
         checkNotReleased();
@@ -906,6 +1073,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public void show() {
         checkNotReleased();
@@ -914,6 +1084,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setTransparentRegionHint(Region region) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -921,24 +1094,39 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public boolean clearContentFrameStats() {
         checkNotReleased();
         return nativeClearContentFrameStats(mNativeObject);
     }
 
+    /**
+     * @hide
+     */
     public boolean getContentFrameStats(WindowContentFrameStats outStats) {
         checkNotReleased();
         return nativeGetContentFrameStats(mNativeObject, outStats);
     }
 
+    /**
+     * @hide
+     */
     public static boolean clearAnimationFrameStats() {
         return nativeClearAnimationFrameStats();
     }
 
+    /**
+     * @hide
+     */
     public static boolean getAnimationFrameStats(WindowAnimationFrameStats outStats) {
         return nativeGetAnimationFrameStats(outStats);
     }
 
+    /**
+     * @hide
+     */
     public void setAlpha(float alpha) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -946,6 +1134,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setColor(@Size(3) float[] color) {
         checkNotReleased();
         synchronized (SurfaceControl.class) {
@@ -953,6 +1144,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -965,6 +1159,7 @@
      *
      * @param matrix The matrix to apply.
      * @param float9 An array of 9 floats to be used to extract the values from the matrix.
+     * @hide
      */
     public void setMatrix(Matrix matrix, float[] float9) {
         checkNotReleased();
@@ -980,6 +1175,7 @@
      * Sets the color transform for the Surface.
      * @param matrix A float array with 9 values represents a 3x3 transform matrix
      * @param translation A float array with 3 values represents a translation vector
+     * @hide
      */
     public void setColorTransform(@Size(9) float[] matrix, @Size(3) float[] translation) {
         checkNotReleased();
@@ -995,6 +1191,7 @@
      * constrained by the size of its parent bounds.
      *
      * @param crop Bounds of the crop to apply.
+     * @hide
      */
     public void setWindowCrop(Rect crop) {
         checkNotReleased();
@@ -1008,6 +1205,7 @@
      *
      * @param width width of crop rect
      * @param height height of crop rect
+     * @hide
      */
     public void setWindowCrop(int width, int height) {
         checkNotReleased();
@@ -1020,6 +1218,7 @@
      * Sets the corner radius of a {@link SurfaceControl}.
      *
      * @param cornerRadius Corner radius in pixels.
+     * @hide
      */
     public void setCornerRadius(float cornerRadius) {
         checkNotReleased();
@@ -1028,6 +1227,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setLayerStack(int layerStack) {
         checkNotReleased();
         synchronized(SurfaceControl.class) {
@@ -1035,6 +1237,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setOpaque(boolean isOpaque) {
         checkNotReleased();
 
@@ -1043,6 +1248,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public void setSecure(boolean isSecure) {
         checkNotReleased();
 
@@ -1051,12 +1259,18 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public int getWidth() {
         synchronized (mSizeLock) {
             return mWidth;
         }
     }
 
+    /**
+     * @hide
+     */
     public int getHeight() {
         synchronized (mSizeLock) {
             return mHeight;
@@ -1076,40 +1290,88 @@
 
     /**
      * Describes the properties of a physical display known to surface flinger.
+     * @hide
      */
     public static final class PhysicalDisplayInfo {
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public int width;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public int height;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public float refreshRate;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public float density;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public float xDpi;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public float yDpi;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public boolean secure;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public long appVsyncOffsetNanos;
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public long presentationDeadlineNanos;
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public PhysicalDisplayInfo() {
         }
 
+        /**
+         * @hide
+         */
         public PhysicalDisplayInfo(PhysicalDisplayInfo other) {
             copyFrom(other);
         }
 
+        /**
+         * @hide
+         */
         @Override
         public boolean equals(Object o) {
             return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o);
         }
 
+        /**
+         * @hide
+         */
         public boolean equals(PhysicalDisplayInfo other) {
             return other != null
                     && width == other.width
@@ -1123,11 +1385,17 @@
                     && presentationDeadlineNanos == other.presentationDeadlineNanos;
         }
 
+        /**
+         * @hide
+         */
         @Override
         public int hashCode() {
             return 0; // don't care
         }
 
+        /**
+         * @hide
+         */
         public void copyFrom(PhysicalDisplayInfo other) {
             width = other.width;
             height = other.height;
@@ -1140,7 +1408,9 @@
             presentationDeadlineNanos = other.presentationDeadlineNanos;
         }
 
-        // For debugging purposes
+        /**
+         * @hide
+         */
         @Override
         public String toString() {
             return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, "
@@ -1150,6 +1420,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public static void setDisplayPowerMode(IBinder displayToken, int mode) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1157,6 +1430,9 @@
         nativeSetDisplayPowerMode(displayToken, mode);
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static SurfaceControl.PhysicalDisplayInfo[] getDisplayConfigs(IBinder displayToken) {
         if (displayToken == null) {
@@ -1165,6 +1441,9 @@
         return nativeGetDisplayConfigs(displayToken);
     }
 
+    /**
+     * @hide
+     */
     public static int getActiveConfig(IBinder displayToken) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1211,6 +1490,9 @@
     }
 
 
+    /**
+     * @hide
+     */
     public static boolean setActiveConfig(IBinder displayToken, int id) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1218,6 +1500,9 @@
         return nativeSetActiveConfig(displayToken, id);
     }
 
+    /**
+     * @hide
+     */
     public static int[] getDisplayColorModes(IBinder displayToken) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1225,6 +1510,9 @@
         return nativeGetDisplayColorModes(displayToken);
     }
 
+    /**
+     * @hide
+     */
     public static int getActiveColorMode(IBinder displayToken) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1232,6 +1520,9 @@
         return nativeGetActiveColorMode(displayToken);
     }
 
+    /**
+     * @hide
+     */
     public static boolean setActiveColorMode(IBinder displayToken, int colorMode) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1239,6 +1530,38 @@
         return nativeSetActiveColorMode(displayToken, colorMode);
     }
 
+    /**
+     * Returns an array of color spaces with 2 elements. The first color space is the
+     * default color space and second one is wide color gamut color space.
+     * @hide
+     */
+    public static ColorSpace[] getCompositionColorSpaces() {
+        int[] dataspaces = nativeGetCompositionDataspaces();
+        ColorSpace srgb = ColorSpace.get(ColorSpace.Named.SRGB);
+        ColorSpace[] colorSpaces = { srgb, srgb };
+        if (dataspaces.length == 2) {
+            for (int i = 0; i < 2; ++i) {
+                switch(dataspaces[i]) {
+                    case INTERNAL_DATASPACE_DISPLAY_P3:
+                        colorSpaces[i] = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
+                        break;
+                    case INTERNAL_DATASPACE_SCRGB:
+                        colorSpaces[i] = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
+                        break;
+                    case INTERNAL_DATASPACE_SRGB:
+                    // Other dataspace is not recognized, use SRGB color space instead,
+                    // the default value of the array is already SRGB, thus do nothing.
+                    default:
+                        break;
+                }
+            }
+        }
+        return colorSpaces;
+    }
+
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static void setDisplayProjection(IBinder displayToken,
             int orientation, Rect layerStackRect, Rect displayRect) {
@@ -1248,6 +1571,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static void setDisplayLayerStack(IBinder displayToken, int layerStack) {
         synchronized (SurfaceControl.class) {
@@ -1255,6 +1581,9 @@
         }
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static void setDisplaySurface(IBinder displayToken, Surface surface) {
         synchronized (SurfaceControl.class) {
@@ -1262,12 +1591,18 @@
         }
     }
 
+    /**
+     * @hide
+     */
     public static void setDisplaySize(IBinder displayToken, int width, int height) {
         synchronized (SurfaceControl.class) {
             sGlobalTransaction.setDisplaySize(displayToken, width, height);
         }
     }
 
+    /**
+     * @hide
+     */
     public static Display.HdrCapabilities getHdrCapabilities(IBinder displayToken) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
@@ -1275,6 +1610,9 @@
         return nativeGetHdrCapabilities(displayToken);
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static IBinder createDisplay(String name, boolean secure) {
         if (name == null) {
@@ -1283,6 +1621,9 @@
         return nativeCreateDisplay(name, secure);
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static void destroyDisplay(IBinder displayToken) {
         if (displayToken == null) {
@@ -1291,6 +1632,9 @@
         nativeDestroyDisplay(displayToken);
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage
     public static IBinder getBuiltInDisplay(int builtInDisplayId) {
         return nativeGetBuiltInDisplay(builtInDisplayId);
@@ -1298,6 +1642,7 @@
 
     /**
      * @see SurfaceControl#screenshot(IBinder, Surface, Rect, int, int, boolean, int)
+     * @hide
      */
     public static void screenshot(IBinder display, Surface consumer) {
         screenshot(display, consumer, new Rect(), 0, 0, false, 0);
@@ -1308,6 +1653,7 @@
      *
      * @param consumer The {@link Surface} to take the screenshot into.
      * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)
+     * @hide
      */
     public static void screenshot(IBinder display, Surface consumer, Rect sourceCrop, int width,
             int height, boolean useIdentityTransform, int rotation) {
@@ -1326,6 +1672,7 @@
 
     /**
      * @see SurfaceControl#screenshot(Rect, int, int, boolean, int)}
+     * @hide
      */
     @UnsupportedAppUsage
     public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) {
@@ -1343,6 +1690,7 @@
      * {@link SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}.
      *
      * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}
+     * @hide
      */
     @UnsupportedAppUsage
     public static Bitmap screenshot(Rect sourceCrop, int width, int height,
@@ -1386,6 +1734,7 @@
      *                             this is useful for returning screenshots that are independent of
      *                             device orientation.
      * @return Returns a GraphicBuffer that contains the captured content.
+     * @hide
      */
     public static GraphicBuffer screenshotToBuffer(IBinder display, Rect sourceCrop, int width,
             int height, boolean useIdentityTransform, int rotation) {
@@ -1417,13 +1766,28 @@
      *                         screen will be scaled up/down.
      *
      * @return Returns a GraphicBuffer that contains the layer capture.
+     * @hide
      */
     public static GraphicBuffer captureLayers(IBinder layerHandleToken, Rect sourceCrop,
             float frameScale) {
         return nativeCaptureLayers(layerHandleToken, sourceCrop, frameScale);
     }
 
+    /**
+     * Returns whether protected content is supported in GPU composition.
+     * @hide
+     */
+    public static boolean getProtectedContentSupport() {
+        return nativeGetProtectedContentSupport();
+    }
+
+    /**
+     * An atomic set of changes to a set of SurfaceControl.
+     */
     public static class Transaction implements Closeable {
+        /**
+         * @hide
+         */
         public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
                 Transaction.class.getClassLoader(),
                 nativeGetNativeTransactionFinalizer(), 512);
@@ -1432,7 +1796,13 @@
         private final ArrayMap<SurfaceControl, Point> mResizedSurfaces = new ArrayMap<>();
         Runnable mFreeNativeResources;
 
-        @UnsupportedAppUsage
+        /**
+         * Open a new transaction object. The transaction may be filed with commands to
+         * manipulate {@link SurfaceControl} instances, and then applied atomically with
+         * {@link #apply}. Eventually the user should invoke {@link #close}, when the object
+         * is no longer required. Note however that re-using a transaction after a call to apply
+         * is allowed as a convenience.
+         */
         public Transaction() {
             mNativeObject = nativeCreateTransaction();
             mFreeNativeResources
@@ -1443,7 +1813,6 @@
          * Apply the transaction, clearing it's state, and making it usable
          * as a new transaction.
          */
-        @UnsupportedAppUsage
         public void apply() {
             apply(false);
         }
@@ -1460,6 +1829,7 @@
 
         /**
          * Jankier version of apply. Avoid use (b/28068298).
+         * @hide
          */
         public void apply(boolean sync) {
             applyResizedSurfaces();
@@ -1478,6 +1848,30 @@
             mResizedSurfaces.clear();
         }
 
+        /**
+         * Toggle the visibility of a given Layer and it's sub-tree.
+         *
+         * @param sc The SurfaceControl for which to set the visibility
+         * @param visible The new visibility
+         * @return This transaction object.
+         */
+        @NonNull
+        public Transaction setVisibility(@NonNull SurfaceControl sc, boolean visible) {
+            sc.checkNotReleased();
+            if (visible) {
+                return show(sc);
+            } else {
+                return hide(sc);
+            }
+        }
+
+        /**
+         * Request that a given surface and it's sub-tree be shown.
+         *
+         * @param sc The surface to show.
+         * @return This transaction.
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction show(SurfaceControl sc) {
             sc.checkNotReleased();
@@ -1485,6 +1879,13 @@
             return this;
         }
 
+        /**
+         * Request that a given surface and it's sub-tree be hidden.
+         *
+         * @param sc The surface to hidden.
+         * @return This transaction.
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction hide(SurfaceControl sc) {
             sc.checkNotReleased();
@@ -1492,6 +1893,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction setPosition(SurfaceControl sc, float x, float y) {
             sc.checkNotReleased();
@@ -1499,21 +1903,44 @@
             return this;
         }
 
-        @UnsupportedAppUsage
-        public Transaction setBufferSize(SurfaceControl sc, int w, int h) {
+        /**
+         * Set the default buffer size for the SurfaceControl, if there is an
+         * {@link Surface} assosciated with the control, then
+         * this will be the default size for buffers dequeued from it.
+         * @param sc The surface to set the buffer size for.
+         * @param w The default width
+         * @param h The default height
+         * @return This Transaction
+         */
+        @NonNull
+        public Transaction setBufferSize(@NonNull SurfaceControl sc,
+                @IntRange(from = 0) int w, @IntRange(from = 0) int h) {
             sc.checkNotReleased();
             mResizedSurfaces.put(sc, new Point(w, h));
             nativeSetSize(mNativeObject, sc.mNativeObject, w, h);
             return this;
         }
 
-        @UnsupportedAppUsage
-        public Transaction setLayer(SurfaceControl sc, int z) {
+        /**
+         * Set the Z-order for a given SurfaceControl, relative to it's siblings.
+         * If two siblings share the same Z order the ordering is undefined. Surfaces
+         * with a negative Z will be placed below the parent surface.
+         *
+         * @param sc The SurfaceControl to set the Z order on
+         * @param z The Z-order
+         * @return This Transaction.
+         */
+        @NonNull
+        public Transaction setLayer(@NonNull SurfaceControl sc,
+                @IntRange(from = Integer.MIN_VALUE, to = Integer.MAX_VALUE) int z) {
             sc.checkNotReleased();
             nativeSetLayer(mNativeObject, sc.mNativeObject, z);
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo, int z) {
             sc.checkNotReleased();
             nativeSetRelativeLayer(mNativeObject, sc.mNativeObject,
@@ -1521,6 +1948,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setTransparentRegionHint(SurfaceControl sc, Region transparentRegion) {
             sc.checkNotReleased();
             nativeSetTransparentRegionHint(mNativeObject,
@@ -1528,19 +1958,68 @@
             return this;
         }
 
-        @UnsupportedAppUsage
-        public Transaction setAlpha(SurfaceControl sc, float alpha) {
+        /**
+         * Set the alpha for a given surface. If the alpha is non-zero the SurfaceControl
+         * will be blended with the Surfaces under it according to the specified ratio.
+         *
+         * @param sc The given SurfaceControl.
+         * @param alpha The alpha to set.
+         */
+        @NonNull
+        public Transaction setAlpha(@NonNull SurfaceControl sc,
+                @FloatRange(from = 0.0, to = 1.0) float alpha) {
             sc.checkNotReleased();
             nativeSetAlpha(mNativeObject, sc.mNativeObject, alpha);
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setInputWindowInfo(SurfaceControl sc, InputWindowHandle handle) {
             sc.checkNotReleased();
             nativeSetInputWindowInfo(mNativeObject, sc.mNativeObject, handle);
             return this;
         }
 
+        /**
+         * Transfers touch focus from one window to another. It is possible for multiple windows to
+         * have touch focus if they support split touch dispatch
+         * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
+         * method only transfers touch focus of the specified window without affecting
+         * other windows that may also have touch focus at the same time.
+         * @param fromToken The token of a window that currently has touch focus.
+         * @param toToken The token of the window that should receive touch focus in
+         * place of the first.
+         * @hide
+         */
+        public Transaction transferTouchFocus(IBinder fromToken, IBinder toToken) {
+            nativeTransferTouchFocus(mNativeObject, fromToken, toToken);
+            return this;
+        }
+
+        /**
+         * Specify how the buffer assosciated with this Surface is mapped in to the
+         * parent coordinate space. The source frame will be scaled to fit the destination
+         * frame, after being rotated according to the orientation parameter.
+         *
+         * @param sc The SurfaceControl to specify the geometry of
+         * @param sourceCrop The source rectangle in buffer space. Or null for the entire buffer.
+         * @param destFrame The destination rectangle in parent space. Or null for the source frame.
+         * @param orientation The buffer rotation
+         * @return This transaction object.
+         */
+        @NonNull
+        public Transaction setGeometry(@NonNull SurfaceControl sc, @Nullable Rect sourceCrop,
+                @Nullable Rect destFrame, @Surface.Rotation int orientation) {
+            sc.checkNotReleased();
+            nativeSetGeometry(mNativeObject, sc.mNativeObject, sourceCrop, destFrame, orientation);
+            return this;
+        }
+
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction setMatrix(SurfaceControl sc,
                 float dsdx, float dtdx, float dtdy, float dsdy) {
@@ -1550,6 +2029,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction setMatrix(SurfaceControl sc, Matrix matrix, float[] float9) {
             matrix.getValues(float9);
@@ -1563,6 +2045,7 @@
          * Sets the color transform for the Surface.
          * @param matrix A float array with 9 values represents a 3x3 transform matrix
          * @param translation A float array with 3 values represents a translation vector
+         * @hide
          */
         public Transaction setColorTransform(SurfaceControl sc, @Size(9) float[] matrix,
                 @Size(3) float[] translation) {
@@ -1571,6 +2054,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
             sc.checkNotReleased();
@@ -1584,6 +2070,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setWindowCrop(SurfaceControl sc, int width, int height) {
             sc.checkNotReleased();
             nativeSetWindowCrop(mNativeObject, sc.mNativeObject, 0, 0, width, height);
@@ -1595,6 +2084,7 @@
          * @param sc SurfaceControl
          * @param cornerRadius Corner radius in pixels.
          * @return Itself.
+         * @hide
          */
         @UnsupportedAppUsage
         public Transaction setCornerRadius(SurfaceControl sc, float cornerRadius) {
@@ -1604,6 +2094,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction setLayerStack(SurfaceControl sc, int layerStack) {
             sc.checkNotReleased();
@@ -1611,6 +2104,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle,
                 long frameNumber) {
@@ -1622,6 +2118,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         @UnsupportedAppUsage
         public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface,
                 long frameNumber) {
@@ -1634,26 +2133,49 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction reparentChildren(SurfaceControl sc, IBinder newParentHandle) {
             sc.checkNotReleased();
             nativeReparentChildren(mNativeObject, sc.mNativeObject, newParentHandle);
             return this;
         }
 
-        /** Re-parents a specific child layer to a new parent */
-        public Transaction reparent(SurfaceControl sc, IBinder newParentHandle) {
+        /**
+         * Re-parents a given layer to a new parent. Children inherit transform (position, scaling)
+         * crop, visibility, and Z-ordering from their parents, as if the children were pixels within the
+         * parent Surface.
+         *
+         * @param sc The SurfaceControl to reparent
+         * @param newParent The new parent for the given control.
+         * @return This Transaction
+         */
+        @NonNull
+        public Transaction reparent(@NonNull SurfaceControl sc,
+                @Nullable SurfaceControl newParent) {
             sc.checkNotReleased();
-            nativeReparent(mNativeObject, sc.mNativeObject,
-                    newParentHandle);
+            long otherObject = 0;
+            if (newParent != null) {
+                newParent.checkNotReleased();
+                otherObject = newParent.mNativeObject;
+            }
+            nativeReparent(mNativeObject, sc.mNativeObject, otherObject);
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction detachChildren(SurfaceControl sc) {
             sc.checkNotReleased();
             nativeSeverChildren(mNativeObject, sc.mNativeObject);
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setOverrideScalingMode(SurfaceControl sc, int overrideScalingMode) {
             sc.checkNotReleased();
             nativeSetOverrideScalingMode(mNativeObject, sc.mNativeObject,
@@ -1664,6 +2186,7 @@
         /**
          * Sets a color for the Surface.
          * @param color A float array with three values to represent r, g, b in range [0..1]
+         * @hide
          */
         @UnsupportedAppUsage
         public Transaction setColor(SurfaceControl sc, @Size(3) float[] color) {
@@ -1678,6 +2201,7 @@
          * arrives. As transform matrix and size are already frozen in this fashion,
          * this enables totally freezing the surface until the resize has completed
          * (at which point the geometry influencing aspects of this transaction will then occur)
+         * @hide
          */
         public Transaction setGeometryAppliesWithResize(SurfaceControl sc) {
             sc.checkNotReleased();
@@ -1688,6 +2212,7 @@
         /**
          * Sets the security of the surface.  Setting the flag is equivalent to creating the
          * Surface with the {@link #SECURE} flag.
+         * @hide
          */
         public Transaction setSecure(SurfaceControl sc, boolean isSecure) {
             sc.checkNotReleased();
@@ -1702,6 +2227,7 @@
         /**
          * Sets the opacity of the surface.  Setting the flag is equivalent to creating the
          * Surface with the {@link #OPAQUE} flag.
+         * @hide
          */
         public Transaction setOpaque(SurfaceControl sc, boolean isOpaque) {
             sc.checkNotReleased();
@@ -1714,29 +2240,8 @@
         }
 
         /**
-         * Same as {@link #destroy()} except this is invoked in a transaction instead of
-         * immediately.
+         * @hide
          */
-        public Transaction destroy(SurfaceControl sc) {
-            sc.checkNotReleased();
-
-            /**
-             * Perhaps it's safer to transfer the close guard to the Transaction
-             * but then we have a whole wonky scenario regarding merging, multiple
-             * close-guards per transaction etc...the whole scenario is kind of wonky
-             * and it seems really we'd like to just be able to call release here
-             * but the WindowManager has some code that looks like
-             * --- destroyInTransaction(a)
-             * --- reparentChildrenInTransaction(a)
-             * so we need to ensure the SC remains valid until the transaction
-             * is applied.
-             */
-            sc.mCloseGuard.close();
-
-            nativeDestroy(mNativeObject, sc.mNativeObject);
-            return this;
-        }
-
         public Transaction setDisplaySurface(IBinder displayToken, Surface surface) {
             if (displayToken == null) {
                 throw new IllegalArgumentException("displayToken must not be null");
@@ -1752,6 +2257,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setDisplayLayerStack(IBinder displayToken, int layerStack) {
             if (displayToken == null) {
                 throw new IllegalArgumentException("displayToken must not be null");
@@ -1760,6 +2268,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setDisplayProjection(IBinder displayToken,
                 int orientation, Rect layerStackRect, Rect displayRect) {
             if (displayToken == null) {
@@ -1777,6 +2288,9 @@
             return this;
         }
 
+        /**
+         * @hide
+         */
         public Transaction setDisplaySize(IBinder displayToken, int width, int height) {
             if (displayToken == null) {
                 throw new IllegalArgumentException("displayToken must not be null");
@@ -1789,7 +2303,9 @@
             return this;
         }
 
-        /** flag the transaction as an animation */
+        /** flag the transaction as an animation 
+         * @hide
+         */
         public Transaction setAnimationTransaction() {
             nativeSetAnimationTransaction(mNativeObject);
             return this;
@@ -1802,6 +2318,7 @@
          * order not to miss frame deadlines.
          * <p>
          * Corresponds to setting ISurfaceComposer::eEarlyWakeup
+         * @hide
          */
         public Transaction setEarlyWakeup() {
             nativeSetEarlyWakeup(mNativeObject);
@@ -1811,8 +2328,12 @@
         /**
          * Merge the other transaction into this transaction, clearing the
          * other transaction as if it had been applied.
+         *
+         * @param other The transaction to merge in to this one.
+         * @return This transaction.
          */
-        public Transaction merge(Transaction other) {
+        @NonNull
+        public Transaction merge(@NonNull Transaction other) {
             mResizedSurfaces.putAll(other.mResizedSurfaces);
             other.mResizedSurfaces.clear();
             nativeMergeTransaction(mNativeObject, other.mNativeObject);
diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java
index a4fa12a..361ac93 100644
--- a/core/java/android/view/SurfaceSession.java
+++ b/core/java/android/view/SurfaceSession.java
@@ -30,7 +30,6 @@
     private long mNativeClient; // SurfaceComposerClient*
 
     private static native long nativeCreate();
-    private static native long nativeCreateScoped(long surfacePtr);
     private static native void nativeDestroy(long ptr);
     private static native void nativeKill(long ptr);
 
@@ -40,15 +39,6 @@
         mNativeClient = nativeCreate();
     }
 
-    public SurfaceSession(Surface root) {
-        synchronized (root.mLock) {
-            if (root.mNativeObject == 0) {
-                throw new IllegalStateException("Surface is not initialized or has been released");
-            }
-            mNativeClient = nativeCreateScoped(root.mNativeObject);
-        }
-    }
-
     /* no user serviceable parts here ... */
     @Override
     protected void finalize() throws Throwable {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index a0af83d..45e6c50 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -120,10 +120,11 @@
     final Rect mScreenRect = new Rect();
     SurfaceSession mSurfaceSession;
 
-    SurfaceControlWithBackground mSurfaceControl;
+    SurfaceControl mSurfaceControl;
     // In the case of format changes we switch out the surface in-place
     // we need to preserve the old one until the new one has drawn.
     SurfaceControl mDeferredDestroySurfaceControl;
+    SurfaceControl mBackgroundControl;
     final Rect mTmpRect = new Rect();
     final Configuration mConfiguration = new Configuration();
 
@@ -487,6 +488,29 @@
         }
     }
 
+    private void updateBackgroundVisibilityInTransaction() {
+        if (mBackgroundControl == null) {
+            return;
+        }
+        if ((mSurfaceFlags & PixelFormat.OPAQUE) == 0) {
+            mBackgroundControl.show();
+            mBackgroundControl.setLayer(Integer.MIN_VALUE);
+        } else {
+            mBackgroundControl.hide();
+        }
+    }
+
+    private void releaseSurfaces() {
+        if (mSurfaceControl != null) {
+            mSurfaceControl.destroy();
+            mSurfaceControl = null;
+        }
+        if (mBackgroundControl != null) {
+            mBackgroundControl.destroy();
+            mBackgroundControl = null;
+        }
+    }
+
     /** @hide */
     protected void updateSurface() {
         if (!mHaveFrame) {
@@ -547,19 +571,27 @@
 
                 if (creating) {
                     viewRoot.createBoundsSurface(mSubLayer);
-                    mSurfaceSession = new SurfaceSession(viewRoot.mBoundsSurface);
+                    mSurfaceSession = new SurfaceSession();
                     mDeferredDestroySurfaceControl = mSurfaceControl;
 
                     updateOpaqueFlag();
                     final String name = "SurfaceView - " + viewRoot.getTitle().toString();
 
-                    mSurfaceControl = new SurfaceControlWithBackground(
-                            name,
-                            (mSurfaceFlags & SurfaceControl.OPAQUE) != 0,
-                            new SurfaceControl.Builder(mSurfaceSession)
-                                    .setBufferSize(mSurfaceWidth, mSurfaceHeight)
-                                    .setFormat(mFormat)
-                                    .setFlags(mSurfaceFlags));
+                    mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
+                        .setName(name)
+                        .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0)
+                        .setBufferSize(mSurfaceWidth, mSurfaceHeight)
+                        .setFormat(mFormat)
+                        .setParent(viewRoot.getSurfaceControl())
+                        .setFlags(mSurfaceFlags)
+                        .build();
+                    mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession)
+                        .setName("Background for -" + name)
+                        .setOpaque(true)
+                        .setColorLayer(true)
+                        .setParent(mSurfaceControl)
+                        .build();
+
                 } else if (mSurfaceControl == null) {
                     return;
                 }
@@ -576,11 +608,13 @@
                     SurfaceControl.openTransaction();
                     try {
                         mSurfaceControl.setLayer(mSubLayer);
+
                         if (mViewVisibility) {
                             mSurfaceControl.show();
                         } else {
                             mSurfaceControl.hide();
                         }
+                        updateBackgroundVisibilityInTransaction();
 
                         // While creating the surface, we will set it's initial
                         // geometry. Outside of that though, we should generally
@@ -723,8 +757,7 @@
                     if (mSurfaceControl != null && !mSurfaceCreated) {
                         mSurface.release();
 
-                        mSurfaceControl.destroy();
-                        mSurfaceControl = null;
+                        releaseSurfaces();
                     }
                 }
             } catch (Exception ex) {
@@ -822,7 +855,6 @@
         final ViewRootImpl viewRoot = getViewRootImpl();
 
         applySurfaceTransforms(mSurfaceControl, position, frameNumber);
-        applySurfaceTransforms(mSurfaceControl.mBackgroundControl, position, frameNumber);
 
         applyChildSurfaceTransaction_renderWorker(mRtTransaction, viewRoot.mSurface,
                 frameNumber);
@@ -949,7 +981,19 @@
      * @hide
      */
     public void setResizeBackgroundColor(int bgColor) {
-        mSurfaceControl.setBackgroundColor(bgColor);
+        if (mBackgroundControl == null) {
+            return;
+        }
+
+        final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
+                Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
+
+        SurfaceControl.openTransaction();
+        try {
+            mBackgroundControl.setColor(colorComponents);
+        } finally {
+            SurfaceControl.closeTransaction();
+        }
     }
 
     @UnsupportedAppUsage
@@ -1127,154 +1171,12 @@
     };
 
     /**
-     * @hide
+     * Return a SurfaceControl which can be used for parenting Surfaces to
+     * this SurfaceView.
+     *
+     * @return The SurfaceControl for this SurfaceView.
      */
     public SurfaceControl getSurfaceControl() {
         return mSurfaceControl;
     }
-
-    class SurfaceControlWithBackground extends SurfaceControl {
-        SurfaceControl mBackgroundControl;
-        private boolean mOpaque = true;
-        public boolean mVisible = false;
-
-        public SurfaceControlWithBackground(String name, boolean opaque, SurfaceControl.Builder b)
-                       throws Exception {
-            super(b.setName(name).build());
-
-            mBackgroundControl = b.setName("Background for -" + name)
-                    .setFormat(OPAQUE)
-                    // Unset the buffer size of the background color layer.
-                    .setBufferSize(0, 0)
-                    .setColorLayer(true)
-                    .build();
-            mOpaque = opaque;
-        }
-
-        @Override
-        public void setAlpha(float alpha) {
-            super.setAlpha(alpha);
-            mBackgroundControl.setAlpha(alpha);
-        }
-
-        @Override
-        public void setLayer(int zorder) {
-            super.setLayer(zorder);
-            // -3 is below all other child layers as SurfaceView never goes below -2
-            mBackgroundControl.setLayer(-3);
-        }
-
-        @Override
-        public void setPosition(float x, float y) {
-            super.setPosition(x, y);
-            mBackgroundControl.setPosition(x, y);
-        }
-
-        @Override
-        public void setBufferSize(int w, int h) {
-            super.setBufferSize(w, h);
-            // The background surface is a color layer so we do not set a size.
-        }
-
-        @Override
-        public void setWindowCrop(Rect crop) {
-            super.setWindowCrop(crop);
-            mBackgroundControl.setWindowCrop(crop);
-        }
-
-        @Override
-        public void setWindowCrop(int width, int height) {
-            super.setWindowCrop(width, height);
-            mBackgroundControl.setWindowCrop(width, height);
-        }
-
-        @Override
-        public void setLayerStack(int layerStack) {
-            super.setLayerStack(layerStack);
-            mBackgroundControl.setLayerStack(layerStack);
-        }
-
-        @Override
-        public void setOpaque(boolean isOpaque) {
-            super.setOpaque(isOpaque);
-            mOpaque = isOpaque;
-            updateBackgroundVisibility();
-        }
-
-        @Override
-        public void setSecure(boolean isSecure) {
-            super.setSecure(isSecure);
-        }
-
-        @Override
-        public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
-            super.setMatrix(dsdx, dtdx, dsdy, dtdy);
-            mBackgroundControl.setMatrix(dsdx, dtdx, dsdy, dtdy);
-        }
-
-        @Override
-        public void hide() {
-            super.hide();
-            mVisible = false;
-            updateBackgroundVisibility();
-        }
-
-        @Override
-        public void show() {
-            super.show();
-            mVisible = true;
-            updateBackgroundVisibility();
-        }
-
-        @Override
-        public void destroy() {
-            super.destroy();
-            mBackgroundControl.destroy();
-         }
-
-        @Override
-        public void release() {
-            super.release();
-            mBackgroundControl.release();
-        }
-
-        @Override
-        public void setTransparentRegionHint(Region region) {
-            super.setTransparentRegionHint(region);
-            mBackgroundControl.setTransparentRegionHint(region);
-        }
-
-        @Override
-        public void deferTransactionUntil(IBinder handle, long frame) {
-            super.deferTransactionUntil(handle, frame);
-            mBackgroundControl.deferTransactionUntil(handle, frame);
-        }
-
-        @Override
-        public void deferTransactionUntil(Surface barrier, long frame) {
-            super.deferTransactionUntil(barrier, frame);
-            mBackgroundControl.deferTransactionUntil(barrier, frame);
-        }
-
-        /** Set the color to fill the background with. */
-        private void setBackgroundColor(int bgColor) {
-            final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
-                    Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
-
-            SurfaceControl.openTransaction();
-            try {
-                mBackgroundControl.setColor(colorComponents);
-            } finally {
-                SurfaceControl.closeTransaction();
-            }
-        }
-
-        void updateBackgroundVisibility() {
-            if (mOpaque && mVisible) {
-                mBackgroundControl.show();
-            } else {
-                mBackgroundControl.hide();
-            }
-        }
-    }
 }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 34d076f..47b206ca 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.HardwareRenderer;
+import android.graphics.Picture;
 import android.graphics.Point;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
@@ -553,6 +554,10 @@
         dumpProfileInfo(fd, flags);
     }
 
+    Picture captureRenderingCommands() {
+        return null;
+    }
+
     @Override
     public boolean loadSystemProperties() {
         boolean changed = super.loadSystemProperties();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6b07efc..483280e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
 
 import static java.lang.Math.max;
@@ -76,8 +77,8 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.os.Trace;
+import android.sysprop.DisplayProperties;
 import android.text.InputType;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -96,6 +97,7 @@
 import android.view.AccessibilityIterators.TextSegmentIterator;
 import android.view.AccessibilityIterators.WordTextSegmentIterator;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.WindowInsetsAnimationListener.InsetsAnimation;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityEventSource;
 import android.view.accessibility.AccessibilityManager;
@@ -811,14 +813,6 @@
     private static final String CONTENT_CAPTURE_LOG_TAG = "View.ContentCapture";
 
     /**
-     * When set to true, apps will draw debugging information about their layouts.
-     *
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout";
-
-    /**
      * When set to true, this view will save its attribute data.
      *
      * @hide
@@ -939,6 +933,26 @@
      */
     private static boolean sAcceptZeroSizeDragShadow;
 
+    /**
+     * Prior to Q, {@link #dispatchApplyWindowInsets} had some issues:
+     * <ul>
+     *     <li>The modified insets changed by {@link #onApplyWindowInsets} were passed to the
+     *     entire view hierarchy in prefix order, including siblings as well as siblings of parents
+     *     further down the hierarchy. This violates the basic concepts of the view hierarchy, and
+     *     thus, the hierarchical dispatching mechanism was hard to use for apps.</li>
+     *
+     *     <li>Dispatch was stopped after the insets were fully consumed. This is somewhat confusing
+     *     for developers, but more importantly, by adding more granular information to
+     *     {@link WindowInsets} it becomes really cumbersome to define what consumed actually means
+     *     </li>
+     * </ul>
+     *
+     * In order to make window inset dispatching work properly, we dispatch window insets
+     * in the view hierarchy in a proper hierarchical manner and don't stop dispatching if the
+     * insets are consumed if this flag is set to {@code false}.
+     */
+    static boolean sBrokenInsetsDispatch;
+
     /** @hide */
     @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO})
     @Retention(RetentionPolicy.SOURCE)
@@ -4527,6 +4541,8 @@
         OnCapturedPointerListener mOnCapturedPointerListener;
 
         private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners;
+
+        private WindowInsetsAnimationListener mWindowInsetsAnimationListener;
     }
 
     @UnsupportedAppUsage
@@ -5108,6 +5124,9 @@
 
             sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P;
 
+            sBrokenInsetsDispatch = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL
+                    || targetSdkVersion < Build.VERSION_CODES.Q;
+
             sCompatibilityDone = true;
         }
     }
@@ -7660,10 +7679,13 @@
 
     /**
      * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT}
-     * {@link AccessibilityEvent} to make an announcement which is related to some
-     * sort of a context change for which none of the events representing UI transitions
-     * is a good fit. For example, announcing a new page in a book. If accessibility
-     * is not enabled this method does nothing.
+     * {@link AccessibilityEvent} to suggest that an accessibility service announce the
+     * specified text to its users.
+     * <p>
+     * Note: The event generated with this API carries no semantic meaning, and is appropriate only
+     * in exceptional situations. Apps can generally achieve correct behavior for accessibility by
+     * accurately supplying the semantics of their UI.
+     * They should not need to specify what exactly is announced to users.
      *
      * @param text The announcement text.
      */
@@ -8173,6 +8195,19 @@
      * <p>The populated structure is then passed to the service through
      * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}.
      *
+     * <p><b>Note: </b>views that manage a virtual structure under this view must populate just
+     * the node representing this view and return right away, then asynchronously report (not
+     * necessarily in the UI thread) when the children nodes appear, disappear or have their text
+     * changed by calling
+     * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)},
+     * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and
+     * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence, int)}
+     * respectively. The structure for the a child must be created using
+     * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the
+     * {@code autofillId} for a child can be obtained either through
+     * {@code childStructure.getAutofillId()} or
+     * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}.
+     *
      * <p><b>Note: </b>the following methods of the {@code structure} will be ignored:
      * <ul>
      *   <li>{@link ViewStructure#setChildCount(int)}
@@ -8185,10 +8220,22 @@
      *   <li>{@link ViewStructure#newHtmlInfoBuilder(String)}
      *   <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}
      *   <li>{@link ViewStructure#setDataIsSensitive(boolean)}
+     *   <li>{@link ViewStructure#setAlpha(float)}
+     *   <li>{@link ViewStructure#setElevation(float)}
+     *   <li>{@link ViewStructure#setTransformation(Matrix)}
+     *
      * </ul>
      */
     public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) {
-        onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags);
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+            Trace.traceBegin(Trace.TRACE_TAG_VIEW,
+                    "onProvideContentCaptureStructure() for " + getClass().getSimpleName());
+        }
+        try {
+            onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
     }
 
     /** @hide */
@@ -8209,10 +8256,6 @@
         } else {
             structure.setId(id, null, null, null);
         }
-        if (viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) {
-            //TODO(b/111276913): STOPSHIP - don't set it if not needed
-            structure.setDataIsSensitive(false);
-        }
 
         if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL
                 || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) {
@@ -8253,8 +8296,7 @@
 
         structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY,
                 mRight - mLeft, mBottom - mTop);
-        if (viewFor == VIEW_STRUCTURE_FOR_ASSIST
-                || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) {
+        if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) {
             if (!hasIdentityMatrix()) {
                 structure.setTransformation(getMatrix());
             }
@@ -8566,7 +8608,7 @@
         if (isAttachedToWindow()) {
             throw new IllegalStateException("Cannot set autofill id when view is attached");
         }
-        if (id != null && id.isVirtual()) {
+        if (id != null && !id.isNonVirtual()) {
             throw new IllegalStateException("Cannot set autofill id assigned to virtual views");
         }
         if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) {
@@ -8983,6 +9025,18 @@
      * </ol>
      */
     private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) {
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+            Trace.traceBegin(Trace.TRACE_TAG_VIEW,
+                    "notifyContentCapture(" + appeared + ") for " + getClass().getSimpleName());
+        }
+        try {
+            notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(appeared);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+    }
+
+    private void notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(boolean appeared) {
         // First check if context has client, so it saves a service lookup when it doesn't
         if (!mContext.isContentCaptureSupported()) return;
 
@@ -8998,11 +9052,12 @@
         if (session == null) return;
 
         if (appeared) {
-            if (!isLaidOut() || !isVisibleToUser()
+            if (!isLaidOut() || getVisibility() != VISIBLE
                     || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) {
                 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) {
                     Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid="
-                            + isLaidOut() + ", visible=" + isVisibleToUser()
+                            + isLaidOut() + ", visibleToUser=" + isVisibleToUser()
+                            + ", visible=" + (getVisibility() == VISIBLE)
                             + ": alreadyNotifiedAppeared="
                             + ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0));
                 }
@@ -10453,6 +10508,37 @@
     }
 
     /**
+     * Sets a {@link WindowInsetsAnimationListener} to be notified about animations of windows that
+     * cause insets.
+     *
+     * @param listener The listener to set.
+     * @hide pending unhide
+     */
+    public void setWindowInsetsAnimationListener(WindowInsetsAnimationListener listener) {
+        getListenerInfo().mWindowInsetsAnimationListener = listener;
+    }
+
+    void dispatchWindowInsetsAnimationStarted(InsetsAnimation animation) {
+        if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) {
+            mListenerInfo.mWindowInsetsAnimationListener.onStarted(animation);
+        }
+    }
+
+    WindowInsets dispatchWindowInsetsAnimationProgress(WindowInsets insets) {
+        if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) {
+            return mListenerInfo.mWindowInsetsAnimationListener.onProgress(insets);
+        } else {
+            return insets;
+        }
+    }
+
+    void dispatchWindowInsetsAnimationFinished(InsetsAnimation animation) {
+        if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) {
+            mListenerInfo.mWindowInsetsAnimationListener.onFinished(animation);
+        }
+    }
+
+    /**
      * Compute the view's coordinate within the surface.
      *
      * <p>Computes the coordinates of this view in its surface. The argument
@@ -13908,7 +13994,7 @@
                     if (clickable) {
                         setPressed(true, x, y);
                     }
-                    checkForLongClick(0, x, y);
+                    checkForLongClick(ViewConfiguration.getLongPressTimeout(), x, y);
                     return true;
                 }
             }
@@ -14649,7 +14735,7 @@
                     mHasPerformedLongPress = false;
 
                     if (!clickable) {
-                        checkForLongClick(0, x, y);
+                        checkForLongClick(ViewConfiguration.getLongPressTimeout(), x, y);
                         break;
                     }
 
@@ -14673,7 +14759,7 @@
                     } else {
                         // Not inside a scrolling container, so show the feedback right away
                         setPressed(true, x, y);
-                        checkForLongClick(0, x, y);
+                        checkForLongClick(ViewConfiguration.getLongPressTimeout(), x, y);
                     }
                     break;
 
@@ -25053,9 +25139,10 @@
         }
 
         final ViewRootImpl root = mAttachInfo.mViewRootImpl;
-        final SurfaceSession session = new SurfaceSession(root.mSurface);
+        final SurfaceSession session = new SurfaceSession();
         final SurfaceControl surfaceControl = new SurfaceControl.Builder(session)
                 .setName("drag surface")
+                .setParent(root.getSurfaceControl())
                 .setBufferSize(shadowSize.x, shadowSize.y)
                 .setFormat(PixelFormat.TRANSLUCENT)
                 .build();
@@ -25347,7 +25434,7 @@
         }
     }
 
-    private void checkForLongClick(int delayOffset, float x, float y) {
+    private void checkForLongClick(long delay, float x, float y) {
         if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) {
             mHasPerformedLongPress = false;
 
@@ -25357,8 +25444,7 @@
             mPendingCheckForLongPress.setAnchor(x, y);
             mPendingCheckForLongPress.rememberWindowAttachCount();
             mPendingCheckForLongPress.rememberPressedState();
-            postDelayed(mPendingCheckForLongPress,
-                    ViewConfiguration.getLongPressTimeout() - delayOffset);
+            postDelayed(mPendingCheckForLongPress, delay);
         }
     }
 
@@ -26948,7 +27034,9 @@
         public void run() {
             mPrivateFlags &= ~PFLAG_PREPRESSED;
             setPressed(true, x, y);
-            checkForLongClick(ViewConfiguration.getTapTimeout(), x, y);
+            final long delay =
+                    ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout();
+            checkForLongClick(delay, x, y);
         }
     }
 
@@ -27763,7 +27851,7 @@
         /**
          * Show where the margins, bounds and layout bounds are for each view.
          */
-        boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false);
+        boolean mDebugLayout = DisplayProperties.debug_layout().orElse(false);
 
         /**
          * Point used to compute visible regions.
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 292e933..5afc07f 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -17,17 +17,21 @@
 package android.view;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.HardwareRenderer;
 import android.graphics.Picture;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.RenderNode;
 import android.os.Debug;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -48,16 +52,20 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Function;
 
 /**
  * Various debugging/tracing tools related to {@link View} and the view hierarchy.
@@ -741,6 +749,123 @@
         root.getViewRootImpl().outputDisplayList(target);
     }
 
+    private static class PictureCallbackHandler implements AutoCloseable,
+            HardwareRenderer.PictureCapturedCallback, Runnable {
+        private final HardwareRenderer mRenderer;
+        private final Function<Picture, Boolean> mCallback;
+        private final Executor mExecutor;
+        private final ReentrantLock mLock = new ReentrantLock(false);
+        private final ArrayDeque<Picture> mQueue = new ArrayDeque<>(3);
+        private boolean mStopListening;
+        private Thread mRenderThread;
+
+        private PictureCallbackHandler(HardwareRenderer renderer,
+                Function<Picture, Boolean> callback, Executor executor) {
+            mRenderer = renderer;
+            mCallback = callback;
+            mExecutor = executor;
+            mRenderer.setPictureCaptureCallback(this);
+        }
+
+        @Override
+        public void close() {
+            mLock.lock();
+            mStopListening = true;
+            mLock.unlock();
+            mRenderer.setPictureCaptureCallback(null);
+        }
+
+        @Override
+        public void onPictureCaptured(Picture picture) {
+            mLock.lock();
+            if (mStopListening) {
+                mLock.unlock();
+                mRenderer.setPictureCaptureCallback(null);
+                return;
+            }
+            if (mRenderThread == null) {
+                mRenderThread = Thread.currentThread();
+            }
+            Picture toDestroy = null;
+            if (mQueue.size() == 3) {
+                toDestroy = mQueue.removeLast();
+            }
+            mQueue.add(picture);
+            mLock.unlock();
+            if (toDestroy == null) {
+                mExecutor.execute(this);
+            } else {
+                toDestroy.close();
+            }
+        }
+
+        @Override
+        public void run() {
+            mLock.lock();
+            final Picture picture = mQueue.poll();
+            final boolean isStopped = mStopListening;
+            mLock.unlock();
+            if (Thread.currentThread() == mRenderThread) {
+                close();
+                throw new IllegalStateException(
+                        "ViewDebug#startRenderingCommandsCapture must be given an executor that "
+                        + "invokes asynchronously");
+            }
+            if (isStopped) {
+                picture.close();
+                return;
+            }
+            final boolean keepReceiving = mCallback.apply(picture);
+            if (!keepReceiving) {
+                close();
+            }
+        }
+    }
+
+    /**
+     * Begins capturing the entire rendering commands for the view tree referenced by the given
+     * view. The view passed may be any View in the tree as long as it is attached. That is,
+     * {@link View#isAttachedToWindow()} must be true.
+     *
+     * Every time a frame is rendered a Picture will be passed to the given callback via the given
+     * executor. As long as the callback returns 'true' it will continue to receive new frames.
+     * The system will only invoke the callback at a rate that the callback is able to keep up with.
+     * That is, if it takes 48ms for the callback to complete and there is a 60fps animation running
+     * then the callback will only receive 33% of the frames produced.
+     *
+     * This method must be called on the same thread as the View tree.
+     *
+     * @param tree The View tree to capture the rendering commands.
+     * @param callback The callback to invoke on every frame produced. Should return true to
+     *                 continue receiving new frames, false to stop capturing.
+     * @param executor The executor to invoke the callback on. Recommend using a background thread
+     *                 to avoid stalling the UI thread. Must be an asynchronous invoke or an
+     *                 exception will be thrown.
+     * @return a closeable that can be used to stop capturing. May be invoked on any thread. Note
+     * that the callback may continue to receive another frame or two depending on thread timings.
+     * Returns null if the capture stream cannot be started, such as if there's no
+     * HardwareRenderer for the given view tree.
+     * @hide
+     */
+    @TestApi
+    @Nullable
+    public static AutoCloseable startRenderingCommandsCapture(View tree, Executor executor,
+            Function<Picture, Boolean> callback) {
+        final View.AttachInfo attachInfo = tree.mAttachInfo;
+        if (attachInfo == null) {
+            throw new IllegalArgumentException("Given view isn't attached");
+        }
+        if (attachInfo.mHandler.getLooper() != Looper.myLooper()) {
+            throw new IllegalStateException("Called on the wrong thread."
+                    + " Must be called on the thread that owns the given View");
+        }
+        final HardwareRenderer renderer = attachInfo.mThreadedRenderer;
+        if (renderer != null) {
+            return new PictureCallbackHandler(renderer, callback, executor);
+        }
+        return null;
+    }
+
     private static void capture(View root, final OutputStream clientStream, String parameter)
             throws IOException {
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 8372032..0986cfa 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -51,6 +51,7 @@
 import android.util.Pools.SynchronizedPool;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.view.WindowInsetsAnimationListener.InsetsAnimation;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -7111,6 +7112,14 @@
     @Override
     public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
         insets = super.dispatchApplyWindowInsets(insets);
+        if (View.sBrokenInsetsDispatch) {
+            return brokenDispatchApplyWindowInsets(insets);
+        } else {
+            return newDispatchApplyWindowInsets(insets);
+        }
+    }
+
+    private WindowInsets brokenDispatchApplyWindowInsets(WindowInsets insets) {
         if (!insets.isConsumed()) {
             final int count = getChildCount();
             for (int i = 0; i < count; i++) {
@@ -7123,6 +7132,42 @@
         return insets;
     }
 
+    private WindowInsets newDispatchApplyWindowInsets(WindowInsets insets) {
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            getChildAt(i).dispatchApplyWindowInsets(insets);
+        }
+        return insets;
+    }
+
+    @Override
+    void dispatchWindowInsetsAnimationStarted(InsetsAnimation animation) {
+        super.dispatchWindowInsetsAnimationStarted(animation);
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            getChildAt(i).dispatchWindowInsetsAnimationStarted(animation);
+        }
+    }
+
+    @Override
+    WindowInsets dispatchWindowInsetsAnimationProgress(WindowInsets insets) {
+        insets = super.dispatchWindowInsetsAnimationProgress(insets);
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            getChildAt(i).dispatchWindowInsetsAnimationProgress(insets);
+        }
+        return insets;
+    }
+
+    @Override
+    void dispatchWindowInsetsAnimationFinished(InsetsAnimation animation) {
+        super.dispatchWindowInsetsAnimationFinished(animation);
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            getChildAt(i).dispatchWindowInsetsAnimationFinished(animation);
+        }
+    }
+
     /**
      * Returns the animation listener to which layout animation events are
      * sent.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3f7a512..a031b70 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -75,6 +75,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
+import android.sysprop.DisplayProperties;
 import android.util.AndroidRuntimeException;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -162,13 +163,16 @@
     private static final boolean MT_RENDERER_AVAILABLE = true;
 
     /**
-     * If set to true, the view system will switch from using rectangles retrieved from window to
+     * If set to 2, the view system will switch from using rectangles retrieved from window to
      * dispatch to the view hierarchy to using {@link InsetsController}, that derives the insets
      * directly from the full configuration, enabling richer information about the insets state, as
      * well as new APIs to control it frame-by-frame, and synchronize animations with it.
      * <p>
-     * Only switch this to true once the new insets system is productionized and the old APIs are
+     * Only set this to 2 once the new insets system is productionized and the old APIs are
      * fully migrated over.
+     * <p>
+     * If set to 1, this will switch to a mode where we only use the new approach for IME, but not
+     * for the status/navigation bar.
      */
     private static final String USE_NEW_INSETS_PROPERTY = "persist.wm.new_insets";
 
@@ -176,8 +180,26 @@
      * @see #USE_NEW_INSETS_PROPERTY
      * @hide
      */
-    public static final boolean USE_NEW_INSETS =
-            SystemProperties.getBoolean(USE_NEW_INSETS_PROPERTY, false);
+    public static final int sNewInsetsMode =
+            SystemProperties.getInt(USE_NEW_INSETS_PROPERTY, 0);
+
+    /**
+     * @see #USE_NEW_INSETS_PROPERTY
+     * @hide
+     */
+    public static final int NEW_INSETS_MODE_NONE = 0;
+
+    /**
+     * @see #USE_NEW_INSETS_PROPERTY
+     * @hide
+     */
+    public static final int NEW_INSETS_MODE_IME = 1;
+
+    /**
+     * @see #USE_NEW_INSETS_PROPERTY
+     * @hide
+     */
+    public static final int NEW_INSETS_MODE_FULL = 2;
 
     /**
      * Set this system property to true to force the view hierarchy to render
@@ -432,6 +454,7 @@
     // Surface can never be reassigned or cleared (use Surface.clear()).
     @UnsupportedAppUsage
     public final Surface mSurface = new Surface();
+    private final SurfaceControl mSurfaceControl = new SurfaceControl();
 
     /**
      * Child surface of {@code mSurface} with the same bounds as its parent, and crop bounds
@@ -1365,7 +1388,7 @@
     }
 
     void notifyInsetsChanged() {
-        if (!USE_NEW_INSETS) {
+        if (sNewInsetsMode == NEW_INSETS_MODE_NONE) {
             return;
         }
         mApplyInsetsRequested = true;
@@ -1526,7 +1549,7 @@
      */
     public void createBoundsSurface(int zOrderLayer) {
         if (mSurfaceSession == null) {
-            mSurfaceSession = new SurfaceSession(mSurface);
+            mSurfaceSession = new SurfaceSession();
         }
         if (mBoundsSurfaceControl != null && mBoundsSurface.isValid()) {
             return; // surface control for bounds surface already exists.
@@ -1534,6 +1557,7 @@
 
         mBoundsSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
                 .setName("Bounds for - " + getTitle().toString())
+                .setParent(mSurfaceControl)
                 .build();
 
         setBoundsSurfaceCrop();
@@ -1567,6 +1591,8 @@
 
     private void destroySurface() {
         mSurface.release();
+        mSurfaceControl.release();
+
         mSurfaceSession = null;
 
         if (mBoundsSurfaceControl != null) {
@@ -1850,13 +1876,13 @@
             }
             contentInsets = ensureInsetsNonNegative(contentInsets, "content");
             stableInsets = ensureInsetsNonNegative(stableInsets, "stable");
-            if (USE_NEW_INSETS) {
+            if (sNewInsetsMode != NEW_INSETS_MODE_NONE) {
                 mLastWindowInsets = mInsetsController.calculateInsets(
                         mContext.getResources().getConfiguration().isScreenRound(),
-                        mAttachInfo.mAlwaysConsumeNavBar, displayCutout);
+                        mAttachInfo.mAlwaysConsumeNavBar, displayCutout,
+                        contentInsets, stableInsets);
             } else {
-                mLastWindowInsets = new WindowInsets(contentInsets,
-                        null /* windowDecorInsets */, stableInsets,
+                mLastWindowInsets = new WindowInsets(contentInsets, stableInsets,
                         mContext.getResources().getConfiguration().isScreenRound(),
                         mAttachInfo.mAlwaysConsumeNavBar, displayCutout);
             }
@@ -6801,7 +6827,12 @@
                 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
                 mTmpFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
                 mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
-                mPendingMergedConfiguration, mSurface, mTempInsets);
+                mPendingMergedConfiguration, mSurfaceControl, mTempInsets);
+        if (mSurfaceControl.isValid()) {
+            mSurface.copyFrom(mSurfaceControl);
+        } else {
+            destroySurface();
+        }
 
         mPendingAlwaysConsumeNavBar =
                 (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;
@@ -7063,7 +7094,7 @@
                 }
 
                 // Layout debugging
-                boolean layout = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
+                boolean layout = DisplayProperties.debug_layout().orElse(false);
                 if (layout != mAttachInfo.mDebugLayout) {
                     mAttachInfo.mDebugLayout = layout;
                     if (!mHandler.hasMessages(MSG_INVALIDATE_WORLD)) {
@@ -8483,6 +8514,10 @@
         mActivityRelaunched = true;
     }
 
+    public SurfaceControl getSurfaceControl() {
+        return mSurfaceControl;
+    }
+
     /**
      * Class for managing the accessibility interaction connection
      * based on the global accessibility state.
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 572d331..e808830 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -17,18 +17,33 @@
 
 package android.view;
 
-import android.annotation.NonNull;
+import static android.view.WindowInsets.Type.FIRST;
+import static android.view.WindowInsets.Type.IME;
+import static android.view.WindowInsets.Type.LAST;
+import static android.view.WindowInsets.Type.SIDE_BARS;
+import static android.view.WindowInsets.Type.SIZE;
+import static android.view.WindowInsets.Type.TOP_BAR;
+import static android.view.WindowInsets.Type.all;
+import static android.view.WindowInsets.Type.compatSystemInsets;
+import static android.view.WindowInsets.Type.indexOf;
+
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Insets;
 import android.graphics.Rect;
+import android.util.SparseArray;
+import android.view.InsetsState.InternalInsetType;
+import android.view.WindowInsets.Type.InsetType;
+import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethod;
 
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -49,9 +64,9 @@
  */
 public final class WindowInsets {
 
-    @NonNull private final Insets mSystemWindowInsets;
-    @NonNull private final Insets mWindowDecorInsets;
-    @NonNull private final Insets mStableInsets;
+    private final Insets[] mTypeInsetsMap;
+    private final Insets[] mTypeMaxInsetsMap;
+
     @Nullable private Rect mTempRect;
     private final boolean mIsRound;
     @Nullable private final DisplayCutout mDisplayCutout;
@@ -64,7 +79,6 @@
     private final boolean mAlwaysConsumeNavBar;
 
     private final boolean mSystemWindowInsetsConsumed;
-    private final boolean mWindowDecorInsetsConsumed;
     private final boolean mStableInsetsConsumed;
     private final boolean mDisplayCutoutConsumed;
 
@@ -78,7 +92,7 @@
     public static final WindowInsets CONSUMED;
 
     static {
-        CONSUMED = new WindowInsets((Insets) null, null, null, false, false, null);
+        CONSUMED = new WindowInsets((Rect) null, null, false, false, null);
     }
 
     /**
@@ -87,24 +101,38 @@
      * A {@code null} inset indicates that the respective inset is consumed.
      *
      * @hide
+     * @deprecated Use {@link WindowInsets(SparseArray, SparseArray, boolean, boolean, DisplayCutout)}
      */
-    public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets,
+    public WindowInsets(Rect systemWindowInsetsRect, Rect stableInsetsRect,
             boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
-        this(insetsOrNull(systemWindowInsets), insetsOrNull(windowDecorInsets),
-                insetsOrNull(stableInsets), isRound, alwaysConsumeNavBar, displayCutout);
+        this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
+                isRound, alwaysConsumeNavBar, displayCutout);
     }
 
-    private WindowInsets(Insets systemWindowInsets, Insets windowDecorInsets,
-            Insets stableInsets, boolean isRound, boolean alwaysConsumeNavBar,
-            DisplayCutout displayCutout) {
-        mSystemWindowInsetsConsumed = systemWindowInsets == null;
-        mSystemWindowInsets = mSystemWindowInsetsConsumed ? Insets.NONE : systemWindowInsets;
+    /**
+     * Construct a new WindowInsets from individual insets.
+     *
+     * {@code typeInsetsMap} and {@code typeMaxInsetsMap} are a map of indexOf(type) -> insets that
+     * contain the information what kind of system bars causes how much insets. The insets in this
+     * map are non-additive; i.e. they have the same origin. In other words: If two system bars
+     * overlap on one side, the insets of the larger bar will also include the insets of the smaller
+     * bar.
+     *
+     * {@code null} type inset map indicates that the respective inset is fully consumed.
+     * @hide
+     */
+    public WindowInsets(@Nullable Insets[] typeInsetsMap,
+            @Nullable Insets[] typeMaxInsetsMap, boolean isRound,
+            boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
+        mSystemWindowInsetsConsumed = typeInsetsMap == null;
+        mTypeInsetsMap = mSystemWindowInsetsConsumed
+                ? new Insets[SIZE]
+                : typeInsetsMap.clone();
 
-        mWindowDecorInsetsConsumed = windowDecorInsets == null;
-        mWindowDecorInsets = mWindowDecorInsetsConsumed ? Insets.NONE : windowDecorInsets;
-
-        mStableInsetsConsumed = stableInsets == null;
-        mStableInsets = mStableInsetsConsumed ? Insets.NONE : stableInsets;
+        mStableInsetsConsumed = typeMaxInsetsMap == null;
+        mTypeMaxInsetsMap = mStableInsetsConsumed
+                ? new Insets[SIZE]
+                : typeMaxInsetsMap.clone();
 
         mIsRound = isRound;
         mAlwaysConsumeNavBar = alwaysConsumeNavBar;
@@ -120,10 +148,7 @@
      * @param src Source to copy insets from
      */
     public WindowInsets(WindowInsets src) {
-        this(src.mSystemWindowInsetsConsumed ? null : src.mSystemWindowInsets,
-                src.mWindowDecorInsetsConsumed ? null : src.mWindowDecorInsets,
-                src.mStableInsetsConsumed ? null : src.mStableInsets,
-                src.mIsRound, src.mAlwaysConsumeNavBar,
+        this(src.mTypeInsetsMap, src.mTypeMaxInsetsMap, src.mIsRound, src.mAlwaysConsumeNavBar,
                 displayCutoutCopyConstructorArgument(src));
     }
 
@@ -137,10 +162,67 @@
         }
     }
 
+    /**
+     * @return The insets that include system bars indicated by {@code typeMask}, taken from
+     *         {@code typeInsetMap}.
+     */
+    private static Insets getInsets(Insets[] typeInsetsMap, @InsetType int typeMask) {
+        Insets result = null;
+        for (int i = FIRST; i <= LAST; i = i << 1) {
+            if ((typeMask & i) == 0) {
+                continue;
+            }
+            Insets insets = typeInsetsMap[indexOf(i)];
+            if (insets == null) {
+                continue;
+            }
+            if (result == null) {
+                result = insets;
+            } else {
+                result = Insets.max(result, insets);
+            }
+        }
+        return result == null ? Insets.NONE : result;
+    }
+
+    /**
+     * Sets all entries in {@code typeInsetsMap} that belong to {@code typeMask} to {@code insets},
+     */
+    private static void setInsets(Insets[] typeInsetsMap, @InsetType int typeMask, Insets insets) {
+        for (int i = FIRST; i <= LAST; i = i << 1) {
+            if ((typeMask & i) == 0) {
+                continue;
+            }
+            typeInsetsMap[indexOf(i)] = insets;
+        }
+    }
+
     /** @hide */
     @UnsupportedAppUsage
     public WindowInsets(Rect systemWindowInsets) {
-        this(systemWindowInsets, null, null, false, false, null);
+        this(createCompatTypeMap(systemWindowInsets), null, false, false, null);
+    }
+
+    /**
+     * Creates a indexOf(type) -> inset map for which the {@code insets} is just mapped to
+     * {@link InsetType#topBar()} and {@link InsetType#sideBars()}, depending on the location of the
+     * inset.
+     */
+    private static Insets[] createCompatTypeMap(@Nullable Rect insets) {
+        if (insets == null) {
+            return null;
+        }
+        Insets[] typeInsetMap = new Insets[SIZE];
+        assignCompatInsets(typeInsetMap, insets);
+        return typeInsetMap;
+    }
+
+    /**
+     * @hide
+     */
+    static void assignCompatInsets(Insets[] typeInsetMap, Rect insets) {
+        typeInsetMap[indexOf(TOP_BAR)] = Insets.of(0, insets.top, 0, 0);
+        typeInsetMap[indexOf(SIDE_BARS)] = Insets.of(insets.left, 0, insets.right, insets.bottom);
     }
 
     /**
@@ -156,8 +238,8 @@
         if (mTempRect == null) {
             mTempRect = new Rect();
         }
-        mTempRect.set(mSystemWindowInsets.left, mSystemWindowInsets.top,
-                mSystemWindowInsets.right, mSystemWindowInsets.bottom);
+        Insets insets = getSystemWindowInsets();
+        mTempRect.set(insets.left, insets.top, insets.right, insets.bottom);
         return mTempRect;
     }
 
@@ -172,7 +254,46 @@
      */
     @NonNull
     public Insets getSystemWindowInsets() {
-        return mSystemWindowInsets;
+        return getInsets(mTypeInsetsMap, compatSystemInsets());
+    }
+
+    /**
+     * Returns the insets of a specific set of windows causing insets, denoted by the
+     * {@code typeMask} bit mask of {@link InsetType}s.
+     *
+     * @param typeMask Bit mask of {@link InsetType}s to query the insets for.
+     * @return The insets.
+     *
+     * @hide pending unhide
+     */
+    public Insets getInsets(@InsetType int typeMask) {
+        return getInsets(mTypeInsetsMap, typeMask);
+    }
+
+    /**
+     * Returns the maximum amount of insets a specific set of windows can cause, denoted by the
+     * {@code typeMask} bit mask of {@link InsetType}s.
+     *
+     * <p>The maximum insets represents the area of a a window that that <b>may</b> be partially
+     * or fully obscured by the system window identified by {@code type}. This value does not
+     * change based on the visibility state of those elements. for example, if the status bar is
+     * normally shown, but temporarily hidden, the maximum inset will still provide the inset
+     * associated with the status bar being shown.</p>
+     *
+     * @param typeMask Bit mask of {@link InsetType}s to query the insets for.
+     * @return The insets.
+     *
+     * @throws IllegalArgumentException If the caller tries to query {@link Type#ime()}. Maximum
+     *                                  insets are not available for this type as the height of the
+     *                                  IME is dynamic depending on the {@link EditorInfo} of the
+     *                                  currently focused view, as well as the UI state of the IME.
+     * @hide pending unhide
+     */
+    public Insets getMaxInsets(@InsetType int typeMask) throws IllegalArgumentException {
+        if ((typeMask & IME) != 0) {
+            throw new IllegalArgumentException("Unable to query the maximum insets for IME");
+        }
+        return getInsets(mTypeMaxInsetsMap, typeMask);
     }
 
     /**
@@ -185,7 +306,7 @@
      * @return The left system window inset
      */
     public int getSystemWindowInsetLeft() {
-        return mSystemWindowInsets.left;
+        return getSystemWindowInsets().left;
     }
 
     /**
@@ -198,7 +319,7 @@
      * @return The top system window inset
      */
     public int getSystemWindowInsetTop() {
-        return mSystemWindowInsets.top;
+        return getSystemWindowInsets().top;
     }
 
     /**
@@ -211,7 +332,7 @@
      * @return The right system window inset
      */
     public int getSystemWindowInsetRight() {
-        return mSystemWindowInsets.right;
+        return getSystemWindowInsets().right;
     }
 
     /**
@@ -224,63 +345,7 @@
      * @return The bottom system window inset
      */
     public int getSystemWindowInsetBottom() {
-        return mSystemWindowInsets.bottom;
-    }
-
-    /**
-     * Returns the left window decor inset in pixels.
-     *
-     * <p>The window decor inset represents the area of the window content area that is
-     * partially or fully obscured by decorations within the window provided by the framework.
-     * This can include action bars, title bars, toolbars, etc.</p>
-     *
-     * @return The left window decor inset
-     * @hide pending API
-     */
-    public int getWindowDecorInsetLeft() {
-        return mWindowDecorInsets.left;
-    }
-
-    /**
-     * Returns the top window decor inset in pixels.
-     *
-     * <p>The window decor inset represents the area of the window content area that is
-     * partially or fully obscured by decorations within the window provided by the framework.
-     * This can include action bars, title bars, toolbars, etc.</p>
-     *
-     * @return The top window decor inset
-     * @hide pending API
-     */
-    public int getWindowDecorInsetTop() {
-        return mWindowDecorInsets.top;
-    }
-
-    /**
-     * Returns the right window decor inset in pixels.
-     *
-     * <p>The window decor inset represents the area of the window content area that is
-     * partially or fully obscured by decorations within the window provided by the framework.
-     * This can include action bars, title bars, toolbars, etc.</p>
-     *
-     * @return The right window decor inset
-     * @hide pending API
-     */
-    public int getWindowDecorInsetRight() {
-        return mWindowDecorInsets.right;
-    }
-
-    /**
-     * Returns the bottom window decor inset in pixels.
-     *
-     * <p>The window decor inset represents the area of the window content area that is
-     * partially or fully obscured by decorations within the window provided by the framework.
-     * This can include action bars, title bars, toolbars, etc.</p>
-     *
-     * @return The bottom window decor inset
-     * @hide pending API
-     */
-    public int getWindowDecorInsetBottom() {
-        return mWindowDecorInsets.bottom;
+        return getSystemWindowInsets().bottom;
     }
 
     /**
@@ -293,23 +358,7 @@
      * @return true if any of the system window inset values are nonzero
      */
     public boolean hasSystemWindowInsets() {
-        return mSystemWindowInsets.left != 0 || mSystemWindowInsets.top != 0 ||
-                mSystemWindowInsets.right != 0 || mSystemWindowInsets.bottom != 0;
-    }
-
-    /**
-     * Returns true if this WindowInsets has nonzero window decor insets.
-     *
-     * <p>The window decor inset represents the area of the window content area that is
-     * partially or fully obscured by decorations within the window provided by the framework.
-     * This can include action bars, title bars, toolbars, etc.</p>
-     *
-     * @return true if any of the window decor inset values are nonzero
-     * @hide pending API
-     */
-    public boolean hasWindowDecorInsets() {
-        return mWindowDecorInsets.left != 0 || mWindowDecorInsets.top != 0 ||
-                mWindowDecorInsets.right != 0 || mWindowDecorInsets.bottom != 0;
+        return !getSystemWindowInsets().equals(Insets.NONE);
     }
 
     /**
@@ -318,7 +367,8 @@
      * @return true if any inset values are nonzero
      */
     public boolean hasInsets() {
-        return hasSystemWindowInsets() || hasWindowDecorInsets() || hasStableInsets()
+        return !getInsets(mTypeInsetsMap, all()).equals(Insets.NONE)
+                || !getInsets(mTypeMaxInsetsMap, all()).equals(Insets.NONE)
                 || mDisplayCutout != null;
     }
 
@@ -340,9 +390,8 @@
      */
     @NonNull
     public WindowInsets consumeDisplayCutout() {
-        return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets,
-                mWindowDecorInsetsConsumed ? null : mWindowDecorInsets,
-                mStableInsetsConsumed ? null : mStableInsets,
+        return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap,
+                mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
                 mIsRound, mAlwaysConsumeNavBar,
                 null /* displayCutout */);
     }
@@ -362,7 +411,7 @@
      * @return true if the insets have been fully consumed.
      */
     public boolean isConsumed() {
-        return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed && mStableInsetsConsumed
+        return mSystemWindowInsetsConsumed && mStableInsetsConsumed
                 && mDisplayCutoutConsumed;
     }
 
@@ -387,9 +436,7 @@
      */
     @NonNull
     public WindowInsets consumeSystemWindowInsets() {
-        return new WindowInsets(null /* systemWindowInsets */,
-                mWindowDecorInsetsConsumed ? null : mWindowDecorInsets,
-                mStableInsetsConsumed ? null : mStableInsets,
+        return new WindowInsets(null, mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
                 mIsRound, mAlwaysConsumeNavBar,
                 displayCutoutCopyConstructorArgument(this));
     }
@@ -449,18 +496,6 @@
     }
 
     /**
-     * @hide
-     */
-    @NonNull
-    public WindowInsets consumeWindowDecorInsets() {
-        return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets,
-                null /* windowDecorInsets */,
-                mStableInsetsConsumed ? null : mStableInsets,
-                mIsRound, mAlwaysConsumeNavBar,
-                displayCutoutCopyConstructorArgument(this));
-    }
-
-    /**
      * Returns the stable insets in pixels.
      *
      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
@@ -473,7 +508,7 @@
      */
     @NonNull
     public Insets getStableInsets() {
-        return mStableInsets;
+        return getInsets(mTypeMaxInsetsMap, compatSystemInsets());
     }
 
     /**
@@ -488,7 +523,7 @@
      * @return The top stable inset
      */
     public int getStableInsetTop() {
-        return mStableInsets.top;
+        return getStableInsets().top;
     }
 
     /**
@@ -503,7 +538,7 @@
      * @return The left stable inset
      */
     public int getStableInsetLeft() {
-        return mStableInsets.left;
+        return getStableInsets().left;
     }
 
     /**
@@ -518,7 +553,7 @@
      * @return The right stable inset
      */
     public int getStableInsetRight() {
-        return mStableInsets.right;
+        return getStableInsets().right;
     }
 
     /**
@@ -533,7 +568,7 @@
      * @return The bottom stable inset
      */
     public int getStableInsetBottom() {
-        return mStableInsets.bottom;
+        return getStableInsets().bottom;
     }
 
     /**
@@ -548,8 +583,7 @@
      * @return true if any of the stable inset values are nonzero
      */
     public boolean hasStableInsets() {
-        return mStableInsets.top != 0 || mStableInsets.left != 0 || mStableInsets.right != 0
-                || mStableInsets.bottom != 0;
+        return !getStableInsets().equals(Insets.NONE);
     }
 
     /**
@@ -559,9 +593,7 @@
      */
     @NonNull
     public WindowInsets consumeStableInsets() {
-        return new WindowInsets(mSystemWindowInsetsConsumed ? null : mSystemWindowInsets,
-                mWindowDecorInsetsConsumed ? null : mWindowDecorInsets,
-                null /* stableInsets */,
+        return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap, null,
                 mIsRound, mAlwaysConsumeNavBar,
                 displayCutoutCopyConstructorArgument(this));
     }
@@ -575,9 +607,8 @@
 
     @Override
     public String toString() {
-        return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets
-                + " windowDecorInsets=" + mWindowDecorInsets
-                + " stableInsets=" + mStableInsets
+        return "WindowInsets{systemWindowInsets=" + getSystemWindowInsets()
+                + " stableInsets=" + getStableInsets()
                 + (mDisplayCutout != null ? " cutout=" + mDisplayCutout : "")
                 + (isRound() ? " round" : "")
                 + "}";
@@ -634,16 +665,16 @@
         Preconditions.checkArgumentNonnegative(bottom);
 
         return new WindowInsets(
-                mSystemWindowInsetsConsumed ? null :
-                        insetInsets(mSystemWindowInsets, left, top, right, bottom),
-                mWindowDecorInsetsConsumed ? null :
-                        insetInsets(mWindowDecorInsets, left, top, right, bottom),
-                mStableInsetsConsumed ? null :
-                        insetInsets(mStableInsets, left, top, right, bottom),
+                mSystemWindowInsetsConsumed
+                        ? null
+                        : insetInsets(mTypeInsetsMap, left, top, right, bottom),
+                mStableInsetsConsumed
+                        ? null
+                        : insetInsets(mTypeMaxInsetsMap, left, top, right, bottom),
                 mIsRound, mAlwaysConsumeNavBar,
                 mDisplayCutoutConsumed
-                        ? null :
-                        mDisplayCutout == null
+                        ? null
+                        : mDisplayCutout == null
                                 ? DisplayCutout.NO_CUTOUT
                                 : mDisplayCutout.inset(left, top, right, bottom));
     }
@@ -653,23 +684,49 @@
         if (this == o) return true;
         if (o == null || !(o instanceof WindowInsets)) return false;
         WindowInsets that = (WindowInsets) o;
+
         return mIsRound == that.mIsRound
                 && mAlwaysConsumeNavBar == that.mAlwaysConsumeNavBar
                 && mSystemWindowInsetsConsumed == that.mSystemWindowInsetsConsumed
-                && mWindowDecorInsetsConsumed == that.mWindowDecorInsetsConsumed
                 && mStableInsetsConsumed == that.mStableInsetsConsumed
                 && mDisplayCutoutConsumed == that.mDisplayCutoutConsumed
-                && Objects.equals(mSystemWindowInsets, that.mSystemWindowInsets)
-                && Objects.equals(mWindowDecorInsets, that.mWindowDecorInsets)
-                && Objects.equals(mStableInsets, that.mStableInsets)
+                && Arrays.equals(mTypeInsetsMap, that.mTypeInsetsMap)
+                && Arrays.equals(mTypeMaxInsetsMap, that.mTypeMaxInsetsMap)
                 && Objects.equals(mDisplayCutout, that.mDisplayCutout);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mSystemWindowInsets, mWindowDecorInsets, mStableInsets, mIsRound,
-                mDisplayCutout, mAlwaysConsumeNavBar, mSystemWindowInsetsConsumed,
-                mWindowDecorInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed);
+        return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
+                mIsRound, mDisplayCutout, mAlwaysConsumeNavBar, mSystemWindowInsetsConsumed,
+                mStableInsetsConsumed, mDisplayCutoutConsumed);
+    }
+
+
+    /**
+     * Insets every inset in {@code typeInsetsMap} by the specified left, top, right, bottom.
+     *
+     * @return {@code typeInsetsMap} if no inset was modified; a copy of the map with the modified
+     *          insets otherwise.
+     */
+    private static Insets[] insetInsets(
+            Insets[] typeInsetsMap, int left, int top, int right, int bottom) {
+        boolean cloned = false;
+        for (int i = 0; i < SIZE; i++) {
+            Insets insets = typeInsetsMap[i];
+            if (insets == null) {
+                continue;
+            }
+            Insets insetInsets = insetInsets(insets, left, top, right, bottom);
+            if (insetInsets != insets) {
+                if (!cloned) {
+                    typeInsetsMap = typeInsetsMap.clone();
+                    cloned = true;
+                }
+                typeInsetsMap[i] = insetInsets;
+            }
+        }
+        return typeInsetsMap;
     }
 
     private static Insets insetInsets(Insets insets, int left, int top, int right, int bottom) {
@@ -683,10 +740,6 @@
         return Insets.of(newLeft, newTop, newRight, newBottom);
     }
 
-    private static Insets insetsOrNull(Rect insets) {
-        return insets != null ? Insets.of(insets) : null;
-    }
-
     /**
      * @return whether system window insets have been consumed.
      */
@@ -699,11 +752,13 @@
      */
     public static class Builder {
 
-        private Insets mSystemWindowInsets;
-        private Insets mStableInsets;
+        private final Insets[] mTypeInsetsMap;
+        private final Insets[] mTypeMaxInsetsMap;
+        private boolean mSystemInsetsConsumed = true;
+        private boolean mStableInsetsConsumed = true;
+
         private DisplayCutout mDisplayCutout;
 
-        private Insets mWindowDecorInsets;
         private boolean mIsRound;
         private boolean mAlwaysConsumeNavBar;
 
@@ -711,6 +766,8 @@
          * Creates a builder where all insets are initially consumed.
          */
         public Builder() {
+            mTypeInsetsMap = new Insets[SIZE];
+            mTypeMaxInsetsMap = new Insets[SIZE];
         }
 
         /**
@@ -719,12 +776,11 @@
          * @param insets the instance to initialize from.
          */
         public Builder(WindowInsets insets) {
-            mSystemWindowInsets = insets.mSystemWindowInsetsConsumed ? null
-                    : insets.mSystemWindowInsets;
-            mStableInsets = insets.mStableInsetsConsumed ? null : insets.mStableInsets;
+            mTypeInsetsMap = insets.mTypeInsetsMap.clone();
+            mTypeMaxInsetsMap = insets.mTypeMaxInsetsMap.clone();
+            mSystemInsetsConsumed = insets.mSystemWindowInsetsConsumed;
+            mStableInsetsConsumed = insets.mStableInsetsConsumed;
             mDisplayCutout = displayCutoutCopyConstructorArgument(insets);
-            mWindowDecorInsets =  insets.mWindowDecorInsetsConsumed ? null
-                    : insets.mWindowDecorInsets;
             mIsRound = insets.mIsRound;
             mAlwaysConsumeNavBar = insets.mAlwaysConsumeNavBar;
         }
@@ -742,7 +798,66 @@
         @NonNull
         public Builder setSystemWindowInsets(@NonNull Insets systemWindowInsets) {
             Preconditions.checkNotNull(systemWindowInsets);
-            mSystemWindowInsets = systemWindowInsets;
+            assignCompatInsets(mTypeInsetsMap, systemWindowInsets.toRect());
+            mSystemInsetsConsumed = false;
+            return this;
+        }
+
+        /**
+         * Sets the insets of a specific window type in pixels.
+         *
+         * <p>The insets represents the area of a a window that is partially or fully obscured by
+         * the system windows identified by {@code typeMask}.
+         * </p>
+         *
+         * @see #getInsets(int)
+         *
+         * @param typeMask The bitmask of {@link InsetType} to set the insets for.
+         * @param insets The insets to set.
+         *
+         * @return itself
+         * @hide pending unhide
+         */
+        @NonNull
+        public Builder setInsets(@InsetType int typeMask, @NonNull Insets insets) {
+            Preconditions.checkNotNull(insets);
+            WindowInsets.setInsets(mTypeInsetsMap, typeMask, insets);
+            mSystemInsetsConsumed = false;
+            return this;
+        }
+
+        /**
+         * Sets the maximum amount of insets a specific window type in pixels.
+         *
+         * <p>The maximum insets represents the area of a a window that that <b>may</b> be partially
+         * or fully obscured by the system windows identified by {@code typeMask}. This value does
+         * not change based on the visibility state of those elements. for example, if the status
+         * bar is normally shown, but temporarily hidden, the maximum inset will still provide the
+         * inset associated with the status bar being shown.</p>
+         *
+         * @see #getMaxInsets(int)
+         *
+         * @param typeMask The bitmask of {@link InsetType} to set the insets for.
+         * @param insets The insets to set.
+         *
+         * @return itself
+         *
+         * @throws IllegalArgumentException If {@code typeMask} contains {@link Type#ime()}. Maximum
+         *                                  insets are not available for this type as the height of
+         *                                  the IME is dynamic depending on the {@link EditorInfo}
+         *                                  of the currently focused view, as well as the UI
+         *                                  state of the IME.
+         * @hide pending unhide
+         */
+        @NonNull
+        public Builder setMaxInsets(@InsetType int typeMask, @NonNull Insets insets)
+                throws IllegalArgumentException{
+            if (typeMask == IME) {
+                throw new IllegalArgumentException("Maximum inset not available for IME");
+            }
+            Preconditions.checkNotNull(insets);
+            WindowInsets.setInsets(mTypeMaxInsetsMap, typeMask, insets);
+            mStableInsetsConsumed = false;
             return this;
         }
 
@@ -761,7 +876,8 @@
         @NonNull
         public Builder setStableInsets(@NonNull Insets stableInsets) {
             Preconditions.checkNotNull(stableInsets);
-            mStableInsets = stableInsets;
+            assignCompatInsets(mTypeMaxInsetsMap, stableInsets.toRect());
+            mStableInsetsConsumed = false;
             return this;
         }
 
@@ -780,14 +896,6 @@
 
         /** @hide */
         @NonNull
-        public Builder setWindowDecorInsets(@NonNull Insets windowDecorInsets) {
-            Preconditions.checkNotNull(windowDecorInsets);
-            mWindowDecorInsets = windowDecorInsets;
-            return this;
-        }
-
-        /** @hide */
-        @NonNull
         public Builder setRound(boolean round) {
             mIsRound = round;
             return this;
@@ -807,8 +915,9 @@
          */
         @NonNull
         public WindowInsets build() {
-            return new WindowInsets(mSystemWindowInsets, mWindowDecorInsets, mStableInsets,
-                    mIsRound, mAlwaysConsumeNavBar, mDisplayCutout);
+            return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
+                    mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mIsRound,
+                    mAlwaysConsumeNavBar, mDisplayCutout);
         }
     }
 
@@ -818,10 +927,31 @@
      */
     public static final class Type {
 
-        static final int TOP_BAR = 0x1;
+        static final int FIRST = 0x1;
+        static final int TOP_BAR = FIRST;
+
         static final int IME = 0x2;
         static final int SIDE_BARS = 0x4;
-        static final int WINDOW_DECOR = 0x8;
+
+        static final int LAST = 0x8;
+        static final int SIZE = 4;
+        static final int WINDOW_DECOR = LAST;
+
+        static int indexOf(@InsetType int type) {
+            switch (type) {
+                case TOP_BAR:
+                    return 0;
+                case IME:
+                    return 1;
+                case SIDE_BARS:
+                    return 2;
+                case WINDOW_DECOR:
+                    return 3;
+                default:
+                    throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
+                            + " type=" + type);
+            }
+        }
 
         private Type() {
         }
@@ -870,6 +1000,15 @@
         }
 
         /**
+         * @return Inset types representing the list of bars that traditionally were denoted as
+         *         system insets.
+         * @hide
+         */
+        static @InsetType int compatSystemInsets() {
+            return TOP_BAR | SIDE_BARS | IME;
+        }
+
+        /**
          * @return All inset types combined.
          */
         public static @InsetType int all() {
diff --git a/core/java/android/view/WindowInsetsAnimationController.java b/core/java/android/view/WindowInsetsAnimationController.java
index 9de517d..cf4415d 100644
--- a/core/java/android/view/WindowInsetsAnimationController.java
+++ b/core/java/android/view/WindowInsetsAnimationController.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.graphics.Insets;
 import android.view.WindowInsets.Type.InsetType;
+import android.view.WindowInsetsAnimationListener.InsetsAnimation;
 
 /**
  * Interface to control a window inset animation frame-by-frame.
@@ -28,8 +29,13 @@
 
     /**
      * Retrieves the {@link Insets} when the windows this animation is controlling are fully hidden.
+     * <p>
+     * If there are any animation listeners registered, this value is the same as
+     * {@link InsetsAnimation#getLowerBound()} that will be passed into the callbacks.
      *
      * @return Insets when the windows this animation is controlling are fully hidden.
+     *
+     * @see InsetsAnimation#getLowerBound()
      */
     @NonNull Insets getHiddenStateInsets();
 
@@ -38,8 +44,13 @@
      * <p>
      * In case the size of a window causing insets is changing in the middle of the animation, we
      * execute that height change after this animation has finished.
+     * <p>
+     * If there are any animation listeners registered, this value is the same as
+     * {@link InsetsAnimation#getUpperBound()} that will be passed into the callbacks.
      *
      * @return Insets when the windows this animation is controlling are fully shown.
+     *
+     * @see InsetsAnimation#getUpperBound()
      */
     @NonNull Insets getShownStateInsets();
 
@@ -59,8 +70,11 @@
      * <p>
      * Note that this will <b>not</b> inform the view system of a full inset change via
      * {@link View#dispatchApplyWindowInsets} in order to avoid a full layout pass during the
-     * animation. If you'd like to animate views during a window inset animation, use
-     * TODO add link to animation listeners.
+     * animation. If you'd like to animate views during a window inset animation, register a
+     * {@link WindowInsetsAnimationListener} by calling
+     * {@link View#setWindowInsetsAnimationListener(WindowInsetsAnimationListener)} that will be
+     * notified about any insets change via {@link WindowInsetsAnimationListener#onProgress} during
+     * the animation.
      * <p>
      * {@link View#dispatchApplyWindowInsets} will instead be called once the animation has
      * finished, i.e. once {@link #finish} has been called.
@@ -70,6 +84,9 @@
      *               the resulting insets of that configuration will match the passed in parameter.
      *               Note that these insets are being clamped to the range from
      *               {@link #getHiddenStateInsets} to {@link #getShownStateInsets}
+     *
+     * @see WindowInsetsAnimationListener
+     * @see View#setWindowInsetsAnimationListener(WindowInsetsAnimationListener)
      */
     void changeInsets(@NonNull Insets insets);
 
diff --git a/core/java/android/view/WindowInsetsAnimationListener.java b/core/java/android/view/WindowInsetsAnimationListener.java
new file mode 100644
index 0000000..682ab5b
--- /dev/null
+++ b/core/java/android/view/WindowInsetsAnimationListener.java
@@ -0,0 +1,122 @@
+/*
+ * 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;
+
+import android.graphics.Insets;
+
+/**
+ * Interface that allows the application to listen to animation events for windows that cause
+ * insets.
+ * @hide pending unhide
+ */
+public interface WindowInsetsAnimationListener {
+
+    /**
+     * Called when an inset animation gets started.
+     *
+     * @param animation The animation that is about to start.
+     */
+    void onStarted(InsetsAnimation animation);
+
+    /**
+     * Called when the insets change as part of running an animation. Note that even if multiple
+     * animations for different types are running, there will only be one progress callback per
+     * frame. The {@code insets} passed as an argument represents the overall state and will include
+     * all types, regardless of whether they are animating or not.
+     * <p>
+     * Note that insets dispatch is hierarchical: It will start at the root of the view hierarchy,
+     * and then traverse it and invoke the callback of the specific {@link View} being traversed.
+     * The callback may return a modified instance by calling {@link WindowInsets#inset(int, int, int, int)}
+     * to indicate that a part of the insets have been used to offset or clip its children, and the
+     * children shouldn't worry about that part anymore.
+     *
+     * @param insets The current insets.
+     * @return The insets to dispatch to the subtree of the hierarchy.
+     */
+    WindowInsets onProgress(WindowInsets insets);
+
+    /**
+     * Called when an inset animation has finished.
+     *
+     * @param animation The animation that has finished running.
+     */
+    void onFinished(InsetsAnimation animation);
+
+    /**
+     * Class representing an animation of a set of windows that cause insets.
+     */
+    class InsetsAnimation {
+
+        private final @WindowInsets.Type.InsetType int mTypeMask;
+        private final Insets mLowerBound;
+        private final Insets mUpperBound;
+
+        /**
+         * @hide
+         */
+        InsetsAnimation(int typeMask, Insets lowerBound, Insets upperBound) {
+            mTypeMask = typeMask;
+            mLowerBound = lowerBound;
+            mUpperBound = upperBound;
+        }
+
+        /**
+         * @return The bitmask of {@link WindowInsets.Type.InsetType}s that are animating.
+         */
+        public @WindowInsets.Type.InsetType int getTypeMask() {
+            return mTypeMask;
+        }
+
+        /**
+         * Queries the lower inset bound of the animation. If the animation is about showing or
+         * hiding a window that cause insets, the lower bound is {@link Insets#NONE} and the upper
+         * bound is the same as {@link WindowInsets#getInsets(int)} for the fully shown state. This
+         * is the same as {@link WindowInsetsAnimationController#getHiddenStateInsets} and
+         * {@link WindowInsetsAnimationController#getShownStateInsets} in case the listener gets
+         * invoked because of an animation that originates from
+         * {@link WindowInsetsAnimationController}.
+         * <p>
+         * However, if the size of a window that causes insets is changing, these are the
+         * lower/upper bounds of that size animation.
+         * <p>
+         * There are no overlapping animations for a specific type, but there may be two animations
+         * running at the same time for different inset types.
+         *
+         * @see #getUpperBound()
+         * @see WindowInsetsAnimationController#getHiddenStateInsets
+         * TODO: It's a bit weird that these are global per window but onProgress is hierarchical.
+         * TODO: If multiple types are animating, querying the bound per type isn't possible. Should
+         * we:
+         * 1. Offer bounds by type here?
+         * 2. Restrict one animation to one single type only?
+         * Returning WindowInsets here isn't feasible in case of overlapping animations: We can't
+         * fill in the insets for the types from the other animation into the WindowInsets object
+         * as it's changing as well.
+         */
+        public Insets getLowerBound() {
+            return mLowerBound;
+        }
+
+        /**
+         * @see #getLowerBound()
+         * @see WindowInsetsAnimationController#getShownStateInsets
+         */
+        public Insets getUpperBound() {
+            return mUpperBound;
+        }
+    }
+}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 45c3651..6326c59 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -255,6 +255,12 @@
     int TRANSIT_CRASHING_ACTIVITY_CLOSE = 26;
 
     /**
+     * A task is changing windowing modes
+     * @hide
+     */
+    int TRANSIT_TASK_CHANGE_WINDOWING_MODE = 27;
+
+    /**
      * @hide
      */
     @IntDef(prefix = { "TRANSIT_" }, value = {
@@ -280,7 +286,8 @@
             TRANSIT_KEYGUARD_UNOCCLUDE,
             TRANSIT_TRANSLUCENT_ACTIVITY_OPEN,
             TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE,
-            TRANSIT_CRASHING_ACTIVITY_CLOSE
+            TRANSIT_CRASHING_ACTIVITY_CLOSE,
+            TRANSIT_TASK_CHANGE_WINDOWING_MODE
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface TransitionType {}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index c5c1bca..6aafa34 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -1166,9 +1166,10 @@
     /**
      * Notifies that the accessibility button in the system's navigation area has been clicked
      *
+     * @param displayId The logical display id.
      * @hide
      */
-    public void notifyAccessibilityButtonClicked() {
+    public void notifyAccessibilityButtonClicked(int displayId) {
         final IAccessibilityManager service;
         synchronized (mLock) {
             service = getServiceLocked();
@@ -1177,7 +1178,7 @@
             }
         }
         try {
-            service.notifyAccessibilityButtonClicked();
+            service.notifyAccessibilityButtonClicked(displayId);
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error while dispatching accessibility button click", re);
         }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index d7c8aed..793c315 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -43,6 +43,7 @@
 import android.text.style.URLSpan;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.LongArray;
 import android.util.Pools.SynchronizedPool;
 import android.view.TouchDelegate;
@@ -91,6 +92,8 @@
 
     private static final boolean DEBUG = false;
 
+    private static final String TAG = "AccessibilityNodeInfo";
+
     /** @hide */
     public static final int UNDEFINED_CONNECTION_ID = -1;
 
@@ -990,6 +993,7 @@
      * <strong>Note:</strong> Cannot be called from an
      * {@link android.accessibilityservice.AccessibilityService}.
      * This class is made immutable before being delivered to an AccessibilityService.
+     * Note that a view cannot be made its own child.
      * </p>
      *
      * @param child The child.
@@ -1037,6 +1041,7 @@
      * hierarchy for accessibility purposes. This enables custom views that draw complex
      * content to report them selves as a tree of virtual views, thus conveying their
      * logical structure.
+     * Note that a view cannot be made its own child.
      * </p>
      *
      * @param root The root of the virtual subtree.
@@ -1054,6 +1059,11 @@
         final int rootAccessibilityViewId =
             (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
         final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
+        if (childNodeId == mSourceNodeId) {
+            Log.e(TAG, "Rejecting attempt to make a View its own child");
+            return;
+        }
+
         // If we're checking uniqueness and the ID already exists, abort.
         if (checked && mChildNodeIds.indexOf(childNodeId) >= 0) {
             return;
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 38dac94..486b35d 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -63,7 +63,7 @@
 
     IBinder getWindowToken(int windowId, int userId);
 
-    void notifyAccessibilityButtonClicked();
+    void notifyAccessibilityButtonClicked(int displayId);
 
     void notifyAccessibilityButtonVisibilityChanged(boolean available);
 
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 95a346f..dfd9a2e 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -187,6 +187,7 @@
     /**
      * An animation listener to be notified when the animation starts, ends or repeats.
      */
+    @UnsupportedAppUsage
     private AnimationListener mListener;
 
     /**
@@ -794,7 +795,7 @@
      * @deprecated All window animations are running with detached wallpaper.
      */
     public boolean getDetachWallpaper() {
-        return false;
+        return true;
     }
 
     /**
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index cb1d89c..f1c7b69 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -15,6 +15,7 @@
  */
 package android.view.autofill;
 
+import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -25,31 +26,47 @@
  */
 public final class AutofillId implements Parcelable {
 
+    /** @hide */
+    public static final int NO_SESSION = 0;
+
+    private static final int FLAG_IS_VIRTUAL_INT = 0x1;
+    private static final int FLAG_IS_VIRTUAL_LONG = 0x2;
+    private static final int FLAG_HAS_SESSION = 0x4;
+
     private final int mViewId;
-    private final boolean mVirtual;
-    private final int mVirtualId;
+    private final int mFlags;
+    private final int mVirtualIntId;
+    private final long mVirtualLongId;
+    private final int mSessionId;
 
     /** @hide */
     @TestApi
     public AutofillId(int id) {
-        mVirtual = false;
-        mViewId = id;
-        mVirtualId = View.NO_ID;
+        this(/* flags= */ 0, id, View.NO_ID, NO_SESSION);
     }
 
     /** @hide */
     @TestApi
-    public AutofillId(AutofillId parent, int virtualChildId) {
-        mVirtual = true;
-        mViewId = parent.mViewId;
-        mVirtualId = virtualChildId;
+    public AutofillId(@NonNull AutofillId parent, int virtualChildId) {
+        this(FLAG_IS_VIRTUAL_INT, parent.mViewId, virtualChildId, NO_SESSION);
     }
 
     /** @hide */
     public AutofillId(int parentId, int virtualChildId) {
-        mVirtual = true;
+        this(FLAG_IS_VIRTUAL_INT, parentId, virtualChildId, NO_SESSION);
+    }
+
+    /** @hide */
+    public AutofillId(@NonNull AutofillId parent, long virtualChildId, int sessionId) {
+        this(FLAG_IS_VIRTUAL_LONG | FLAG_HAS_SESSION, parent.mViewId, virtualChildId, sessionId);
+    }
+
+    private AutofillId(int flags, int parentId, long virtualChildId, int sessionId) {
+        mFlags = flags;
         mViewId = parentId;
-        mVirtualId = virtualChildId;
+        mVirtualIntId = ((flags & FLAG_IS_VIRTUAL_INT) != 0) ? (int) virtualChildId : View.NO_ID;
+        mVirtualLongId = ((flags & FLAG_IS_VIRTUAL_LONG) != 0) ? virtualChildId : View.NO_ID;
+        mSessionId = sessionId;
     }
 
     /** @hide */
@@ -57,14 +74,72 @@
         return mViewId;
     }
 
-    /** @hide */
-    public int getVirtualChildId() {
-        return mVirtualId;
+    /**
+     * Gets the virtual child id.
+     *
+     * <p>Should only be used on subsystems where such id is represented by an {@code int}
+     * (Assist and Autofill).
+     *
+     * @hide
+     */
+    public int getVirtualChildIntId() {
+        return mVirtualIntId;
+    }
+
+    /**
+     * Gets the virtual child id.
+     *
+     * <p>Should only be used on subsystems where such id is represented by a {@code long}
+     * (ContentCapture).
+     *
+     * @hide
+     */
+    public long getVirtualChildLongId() {
+        return mVirtualLongId;
+    }
+
+    /**
+     * Checks whether this node represents a virtual child, whose id is represented by an
+     * {@code int}.
+     *
+     * <p>Should only be used on subsystems where such id is represented by an {@code int}
+     * (Assist and Autofill).
+     *
+     * @hide
+     */
+    public boolean isVirtualInt() {
+        return (mFlags & FLAG_IS_VIRTUAL_INT) != 0;
+    }
+
+    /**
+     * Checks whether this node represents a virtual child, whose id is represented by an
+     * {@code long}.
+     *
+     * <p>Should only be used on subsystems where such id is represented by a {@code long}
+     * (ContentCapture).
+     *
+     * @hide
+     */
+    public boolean isVirtualLong() {
+        return (mFlags & FLAG_IS_VIRTUAL_LONG) != 0;
+    }
+
+    /**
+     * Checks whether this node represents a non-virtual child.
+     *
+     * @hide
+     */
+    public boolean isNonVirtual() {
+        return !isVirtualInt() && !isVirtualLong();
+    }
+
+    private boolean hasSession() {
+        return (mFlags & FLAG_HAS_SESSION) != 0;
     }
 
     /** @hide */
-    public boolean isVirtual() {
-        return mVirtual;
+    public int getSessionId() {
+        return mSessionId;
     }
 
     /////////////////////////////////
@@ -76,7 +151,9 @@
         final int prime = 31;
         int result = 1;
         result = prime * result + mViewId;
-        result = prime * result + mVirtualId;
+        result = prime * result + mVirtualIntId;
+        result = prime * result + (int) (mVirtualLongId ^ (mVirtualLongId >>> 32));
+        result = prime * result + mSessionId;
         return result;
     }
 
@@ -87,15 +164,23 @@
         if (getClass() != obj.getClass()) return false;
         final AutofillId other = (AutofillId) obj;
         if (mViewId != other.mViewId) return false;
-        if (mVirtualId != other.mVirtualId) return false;
+        if (mVirtualIntId != other.mVirtualIntId) return false;
+        if (mVirtualLongId != other.mVirtualLongId) return false;
+        if (mSessionId != other.mSessionId) return false;
         return true;
     }
 
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder().append(mViewId);
-        if (mVirtual) {
-            builder.append(':').append(mVirtualId);
+        if (isVirtualInt()) {
+            builder.append(':').append(mVirtualIntId);
+        } else if (isVirtualLong()) {
+            builder.append(':').append(mVirtualLongId);
+        }
+
+        if (hasSession()) {
+            builder.append('@').append(mSessionId);
         }
         return builder.toString();
     }
@@ -108,21 +193,31 @@
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(mViewId);
-        parcel.writeInt(mVirtual ? 1 : 0);
-        parcel.writeInt(mVirtualId);
-    }
-
-    private AutofillId(Parcel parcel) {
-        mViewId = parcel.readInt();
-        mVirtual = parcel.readInt() == 1;
-        mVirtualId = parcel.readInt();
+        parcel.writeInt(mFlags);
+        if (hasSession()) {
+            parcel.writeInt(mSessionId);
+        }
+        if (isVirtualInt()) {
+            parcel.writeInt(mVirtualIntId);
+        } else if (isVirtualLong()) {
+            parcel.writeLong(mVirtualLongId);
+        }
     }
 
     public static final Parcelable.Creator<AutofillId> CREATOR =
             new Parcelable.Creator<AutofillId>() {
         @Override
         public AutofillId createFromParcel(Parcel source) {
-            return new AutofillId(source);
+            final int viewId = source.readInt();
+            final int flags = source.readInt();
+            final int sessionId = (flags & FLAG_HAS_SESSION) != 0 ? source.readInt() : NO_SESSION;
+            if ((flags & FLAG_IS_VIRTUAL_INT) != 0) {
+                return new AutofillId(flags, viewId, source.readInt(), sessionId);
+            }
+            if ((flags & FLAG_IS_VIRTUAL_LONG) != 0) {
+                return new AutofillId(flags, viewId, source.readLong(), sessionId);
+            }
+            return new AutofillId(flags, viewId, View.NO_ID, sessionId);
         }
 
         @Override
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 56f973e..64c34f61 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -17,6 +17,7 @@
 package android.view.autofill;
 
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
+import static android.util.DebugUtils.flagsToString;
 import static android.view.autofill.Helper.sDebug;
 import static android.view.autofill.Helper.sVerbose;
 
@@ -25,7 +26,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -62,6 +65,7 @@
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.SyncResultReceiver;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -75,8 +79,8 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
+import java.util.Set;
+
 //TODO: use java.lang.ref.Cleaner once Android supports Java 9
 import sun.misc.Cleaner;
 
@@ -324,6 +328,36 @@
     public static final int FC_SERVICE_TIMEOUT = 5000;
 
     /**
+     * Timeout for calls to system_server.
+     */
+    private static final int SYNC_CALLS_TIMEOUT_MS = 5000;
+
+    /**
+     * @hide
+     */
+    @TestApi
+    public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
+
+    /**
+     * Displays the Augment Autofill window using the same mechanism (such as a popup-window
+     * attached to the focused view) as the standard autofill.
+     *
+     * @hide
+     */
+    @TestApi
+    public static final int FLAG_SMART_SUGGESTION_SYSTEM = 0x1;
+
+    /** @hide */ // TODO(b/123233342): remove when not used anymore
+    public static final int FLAG_SMART_SUGGESTION_LEGACY = 0x2;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = { "FLAG_SMART_SUGGESTION_" }, value = {
+            FLAG_SMART_SUGGESTION_SYSTEM
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SmartSuggestionMode {}
+
+    /**
      * Makes an authentication id from a request id and a dataset id.
      *
      * @param requestId The request id.
@@ -612,7 +646,8 @@
 
                 final AutofillClient client = getClient();
                 if (client != null) {
-                    final SyncResultReceiver receiver = new SyncResultReceiver();
+                    final SyncResultReceiver receiver = new SyncResultReceiver(
+                            SYNC_CALLS_TIMEOUT_MS);
                     try {
                         mService.restoreSession(mSessionId, client.autofillClientGetActivityToken(),
                                 mServiceClient.asBinder(), receiver);
@@ -732,9 +767,9 @@
      */
     @Nullable public FillEventHistory getFillEventHistory() {
         try {
-            final SyncResultReceiver receiver = new SyncResultReceiver();
+            final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
             mService.getFillEventHistory(receiver);
-            return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE);
+            return receiver.getParcelableResult();
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
             return null;
@@ -1287,7 +1322,7 @@
     public boolean hasEnabledAutofillServices() {
         if (mService == null) return false;
 
-        final SyncResultReceiver receiver = new SyncResultReceiver();
+        final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
         try {
             mService.isServiceEnabled(mContext.getUserId(), mContext.getPackageName(), receiver);
             return receiver.getIntResult() == 1;
@@ -1304,10 +1339,10 @@
     public ComponentName getAutofillServiceComponentName() {
         if (mService == null) return null;
 
-        final SyncResultReceiver receiver = new SyncResultReceiver();
+        final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
         try {
             mService.getAutofillServiceComponentName(receiver);
-            return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE);
+            return receiver.getParcelableResult();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1330,9 +1365,9 @@
      */
     @Nullable public String getUserDataId() {
         try {
-            final SyncResultReceiver receiver = new SyncResultReceiver();
+            final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
             mService.getUserDataId(receiver);
-            return receiver.getObjectResult(SyncResultReceiver.TYPE_STRING);
+            return receiver.getStringResult();
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
             return null;
@@ -1352,9 +1387,9 @@
      */
     @Nullable public UserData getUserData() {
         try {
-            final SyncResultReceiver receiver = new SyncResultReceiver();
+            final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
             mService.getUserData(receiver);
-            return receiver.getObjectResult(SyncResultReceiver.TYPE_PARCELABLE);
+            return receiver.getParcelableResult();
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
             return null;
@@ -1390,7 +1425,7 @@
      * the user.
      */
     public boolean isFieldClassificationEnabled() {
-        final SyncResultReceiver receiver = new SyncResultReceiver();
+        final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
         try {
             mService.isFieldClassificationEnabled(receiver);
             return receiver.getIntResult() == 1;
@@ -1413,10 +1448,10 @@
      */
     @Nullable
     public String getDefaultFieldClassificationAlgorithm() {
-        final SyncResultReceiver receiver = new SyncResultReceiver();
+        final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
         try {
             mService.getDefaultFieldClassificationAlgorithm(receiver);
-            return receiver.getObjectResult(SyncResultReceiver.TYPE_STRING);
+            return receiver.getStringResult();
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
             return null;
@@ -1433,11 +1468,10 @@
      */
     @NonNull
     public List<String> getAvailableFieldClassificationAlgorithms() {
-        final SyncResultReceiver receiver = new SyncResultReceiver();
+        final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
         try {
             mService.getAvailableFieldClassificationAlgorithms(receiver);
-            final String[] algorithms = receiver
-                .getObjectResult(SyncResultReceiver.TYPE_STRING_ARRAY);
+            final String[] algorithms = receiver.getStringArrayResult();
             return algorithms != null ? Arrays.asList(algorithms) : Collections.emptyList();
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
@@ -1458,7 +1492,7 @@
     public boolean isAutofillSupported() {
         if (mService == null) return false;
 
-        final SyncResultReceiver receiver = new SyncResultReceiver();
+        final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
         try {
             mService.isServiceSupported(mContext.getUserId(), receiver);
             return receiver.getIntResult() == 1;
@@ -1582,7 +1616,7 @@
             final AutofillClient client = getClient();
             if (client == null) return; // NOTE: getClient() already logged it..
 
-            final SyncResultReceiver receiver = new SyncResultReceiver();
+            final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
             mService.startSession(client.autofillClientGetActivityToken(),
                     mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
                     mCallback != null, flags, client.autofillClientGetComponentName(),
@@ -1665,7 +1699,7 @@
             mServiceClient = new AutofillManagerClient(this);
             try {
                 final int userId = mContext.getUserId();
-                final SyncResultReceiver receiver = new SyncResultReceiver();
+                final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
                 mService.addClient(mServiceClient, userId, receiver);
                 final int flags = receiver.getIntResult();
                 mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0;
@@ -1674,7 +1708,7 @@
                 final IAutoFillManager service = mService;
                 final IAutoFillManagerClient serviceClient = mServiceClient;
                 mServiceClientCleaner = Cleaner.create(this, () -> {
-                    // TODO(b/111330312): call service to also remove reference to
+                    // TODO(b/123100811): call service to also remove reference to
                     // mAugmentedAutofillServiceClient
                     try {
                         service.removeClient(serviceClient, userId);
@@ -1734,6 +1768,108 @@
         }
     }
 
+    /**
+     * Defines whether augmented autofill should be triggered for activities with such
+     * {@link android.content.ComponentName}.
+     *
+     * <p>Useful to blacklist a particular activity.
+     *
+     * <p><b>Note:</b> This method should only be called by the app providing the augmented autofill
+     * service, and it's ignored if the caller isn't it.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    //TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
+    //in the same package as the test, and that module is compiled with SDK=test_current
+    public void setActivityAugmentedAutofillEnabled(@NonNull ComponentName activity,
+            boolean enabled) {
+        // TODO(b/123100824): implement
+    }
+
+    /**
+     * Defines whether augmented autofill should be triggered for activities of the app with such
+     * {@code packageName}.
+     *
+     * <p>Useful to blacklist any activity from a particular app.
+     *
+     * <p><b>Note:</b> This method should only be called by the app providing the augmented autofill
+     * service, and it's ignored if the caller isn't it.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    //TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
+    //in the same package as the test, and that module is compiled with SDK=test_current
+    public void setPackageAugmentedAutofillEnabled(@NonNull String packageName, boolean enabled) {
+        // TODO(b/123100824): implement
+    }
+
+    /**
+     * Explicitly limits augmented autofill to the given packages and activities.
+     *
+     * <p>When the whitelist is set, it overrides the values passed to
+     * {@link #setActivityAugmentedAutofillEnabled(ComponentName, boolean)}
+     * and {@link #setPackageAugmentedAutofillEnabled(String, boolean)}.
+     *
+     * <p>To reset the whitelist, call it passing {@code null} to both arguments.
+     *
+     * <p>Useful when the service wants to restrict augmented autofill to a category of apps, like
+     * apps that uses addresses. For example, if the service wants to support augmented autofill on
+     * all activities of app {@code AddressApp1} and just activities {@code act1} and {@code act2}
+     * of {@code AddressApp2}, it would call:
+     * {@code setAugmentedAutofillWhitelist(Arrays.asList("AddressApp1"),
+     * Arrays.asList(new ComponentName("AddressApp2", "act1"),
+     * new ComponentName("AddressApp2", "act2")));}
+     *
+     * <p><b>Note:</b> This method should only be called by the app providing the augmented autofill
+     * service, and it's ignored if the caller isn't it.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    //TODO(b/122654591): @TestApi is needed because CtsAutoFillServiceTestCases hosts the service
+    //in the same package as the test, and that module is compiled with SDK=test_current
+    public void setAugmentedAutofillWhitelist(@Nullable List<String> packages,
+            @Nullable List<ComponentName> activities) {
+        // TODO(b/123100824): implement
+    }
+
+    /**
+     * Gets the activities where augmented autofill was disabled by
+     * {@link #setActivityAugmentedAutofillEnabled(ComponentName, boolean)}.
+     *
+     * <p><b>Note:</b> This method should only be called by the app providing the augmented autofill
+     * service, and it's ignored if the caller isn't it.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    @NonNull
+    public Set<ComponentName> getAugmentedAutofillDisabledActivities() {
+        return null; // TODO(b/123100824): implement
+    }
+
+    /**
+     * Gets the apps where content capture was disabled by
+     * {@link #setPackageAugmentedAutofillEnabled(String, boolean)}.
+     *
+     * <p><b>Note:</b> This method should only be called by the app providing the augmented autofill
+     * service, and it's ignored if the caller isn't it.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    @NonNull
+    public Set<String> getAugmentedAutofillDisabledPackages() {
+        return null; // TODO(b/123100824): implement
+    }
+
     private void requestShowFillUi(int sessionId, AutofillId id, int width, int height,
             Rect anchorBounds, IAutofillWindowPresenter presenter) {
         final View anchor = findView(id);
@@ -1757,8 +1893,8 @@
         }
 
         if (callback != null) {
-            if (id.isVirtual()) {
-                callback.onAutofillEvent(anchor, id.getVirtualChildId(),
+            if (id.isVirtualInt()) {
+                callback.onAutofillEvent(anchor, id.getVirtualChildIntId(),
                         AutofillCallback.EVENT_INPUT_SHOWN);
             } else {
                 callback.onAutofillEvent(anchor, AutofillCallback.EVENT_INPUT_SHOWN);
@@ -1884,7 +2020,7 @@
                     failedIds.add(id);
                     continue;
                 }
-                if (id.isVirtual()) {
+                if (id.isVirtualInt()) {
                     if (virtualValues == null) {
                         // Most likely there will be just one view with virtual children.
                         virtualValues = new ArrayMap<>(1);
@@ -1895,7 +2031,7 @@
                         valuesByParent = new SparseArray<>(5);
                         virtualValues.put(view, valuesByParent);
                     }
-                    valuesByParent.put(id.getVirtualChildId(), value);
+                    valuesByParent.put(id.getVirtualChildIntId(), value);
                 } else {
                     // Mark the view as to be autofilled with 'value'
                     if (mLastAutofilledData == null) {
@@ -2130,8 +2266,8 @@
         }
 
         if (callback != null) {
-            if (id.isVirtual()) {
-                callback.onAutofillEvent(anchor, id.getVirtualChildId(),
+            if (id.isVirtualInt()) {
+                callback.onAutofillEvent(anchor, id.getVirtualChildIntId(),
                         AutofillCallback.EVENT_INPUT_HIDDEN);
             } else {
                 callback.onAutofillEvent(anchor, AutofillCallback.EVENT_INPUT_HIDDEN);
@@ -2157,8 +2293,8 @@
         }
 
         if (callback != null) {
-            if (id.isVirtual()) {
-                callback.onAutofillEvent(anchor, id.getVirtualChildId(),
+            if (id.isVirtualInt()) {
+                callback.onAutofillEvent(anchor, id.getVirtualChildIntId(),
                         AutofillCallback.EVENT_INPUT_UNAVAILABLE);
             } else {
                 callback.onAutofillEvent(anchor, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
@@ -2284,6 +2420,11 @@
         }
     }
 
+    /** @hide */
+    public static String getSmartSuggestionModeToString(@SmartSuggestionMode int flags) {
+        return flagsToString(AutofillManager.class, "FLAG_SMART_SUGGESTION_", flags);
+    }
+
     @GuardedBy("mLock")
     private boolean isActiveLocked() {
         return mState == STATE_ACTIVE;
@@ -2960,7 +3101,6 @@
 
         @Override
         public Rect getViewCoordinates(@NonNull AutofillId id) {
-            // TODO(b/111330312): use handler / callback?
             final AutofillManager afm = mAfm.get();
             if (afm == null) return null;
 
@@ -2985,105 +3125,23 @@
                 afm.post(() -> afm.autofill(sessionId, ids, values));
             }
         }
-    }
 
-    /**
-     * @hide
-     */
-    public static final class SyncResultReceiver extends IResultReceiver.Stub {
-
-        private static final String EXTRA = "EXTRA";
-
-        /**
-         * How long to block waiting for {@link IResultReceiver} callbacks when calling server.
-         */
-        private static final long BINDER_TIMEOUT_MS = 5000;
-
-        private static final int TYPE_STRING = 0;
-        private static final int TYPE_STRING_ARRAY = 1;
-        private static final int TYPE_PARCELABLE = 2;
-
-        private final CountDownLatch mLatch  = new CountDownLatch(1);
-        private int mResult;
-        private Bundle mBundle;
-
-        private void waitResult() {
-            try {
-                if (!mLatch.await(BINDER_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-                    throw new IllegalStateException("Not called in " + BINDER_TIMEOUT_MS + "ms");
-                }
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-            }
-        }
-
-        /**
-         * Gets the result from an operation that returns an {@code int}.
-         */
-        int getIntResult() {
-            waitResult();
-            return mResult;
-        }
-
-        /**
-         * Gets the result from an operation that returns an {@code Object}.
-         *
-         * @param type type of expected object.
-         */
-        @Nullable
-        @SuppressWarnings("unchecked")
-        <T> T getObjectResult(int type) {
-            waitResult();
-            if (mBundle == null) {
-                return null;
-            }
-            switch (type) {
-                case TYPE_STRING:
-                    return (T) mBundle.getString(EXTRA);
-                case TYPE_STRING_ARRAY:
-                    return (T) mBundle.getStringArray(EXTRA);
-                case TYPE_PARCELABLE:
-                    return (T) mBundle.getParcelable(EXTRA);
-                default:
-                    throw new IllegalArgumentException("unsupported type: " + type);
+        @Override
+        public void requestShowFillUi(int sessionId, AutofillId id, int width, int height,
+                Rect anchorBounds, IAutofillWindowPresenter presenter) {
+            final AutofillManager afm = mAfm.get();
+            if (afm != null) {
+                afm.post(() -> afm.requestShowFillUi(sessionId, id, width, height, anchorBounds,
+                        presenter));
             }
         }
 
         @Override
-        public void send(int resultCode, Bundle resultData) {
-            mResult = resultCode;
-            mBundle = resultData;
-            mLatch.countDown();
-        }
-
-        /**
-         * Creates a bundle for a {@code String} value.
-         */
-        @NonNull
-        public static Bundle bundleFor(@Nullable String value) {
-            final Bundle bundle = new Bundle();
-            bundle.putString(EXTRA, value);
-            return bundle;
-        }
-
-        /**
-         * Creates a bundle for a {@code String[]} value.
-         */
-        @NonNull
-        public static Bundle bundleFor(@Nullable String[] value) {
-            final Bundle bundle = new Bundle();
-            bundle.putStringArray(EXTRA, value);
-            return bundle;
-        }
-
-        /**
-         * Creates a bundle for a {@code Parcelable} value.
-         */
-        @NonNull
-        public static Bundle bundleFor(@Nullable Parcelable value) {
-            final Bundle bundle = new Bundle();
-            bundle.putParcelable(EXTRA, value);
-            return bundle;
+        public void requestHideFillUi(int sessionId, AutofillId id) {
+            final AutofillManager afm = mAfm.get();
+            if (afm != null) {
+                afm.post(() -> afm.requestHideFillUi(id, false));
+            }
         }
     }
 }
diff --git a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
index 67cd0bf..140507c 100644
--- a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
@@ -21,6 +21,7 @@
 import android.graphics.Rect;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
+import android.view.autofill.IAutofillWindowPresenter;
 
 /**
  * Object running in the application process and responsible to provide the functionalities
@@ -29,6 +30,24 @@
  * @hide
  */
 interface IAugmentedAutofillManagerClient {
-   Rect getViewCoordinates(in AutofillId id);
-   void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
+    /**
+      * Gets the coordinates of the input field view.
+      */
+    Rect getViewCoordinates(in AutofillId id);
+
+    /**
+     * Autofills the activity with the contents of the values.
+     */
+    void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
+
+    /**
+      * Requests showing the fill UI.
+      */
+    void requestShowFillUi(int sessionId, in AutofillId id, int width, int height,
+            in Rect anchorBounds, in IAutofillWindowPresenter presenter);
+
+    /**
+      * Requests hiding the fill UI.
+      */
+    void requestHideFillUi(int sessionId, in AutofillId id);
 }
diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
index 5166831..63c21f3 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -33,7 +33,7 @@
 final class ChildContentCaptureSession extends ContentCaptureSession {
 
     @NonNull
-    private final MainContentCaptureSession mParent;
+    private final ContentCaptureSession mParent;
 
     /**
      * {@link ContentCaptureContext} set by client, or {@code null} when it's the
@@ -46,46 +46,55 @@
     private final ContentCaptureContext mClientContext;
 
     /** @hide */
-    protected ChildContentCaptureSession(@NonNull MainContentCaptureSession parent,
+    protected ChildContentCaptureSession(@NonNull ContentCaptureSession parent,
             @NonNull ContentCaptureContext clientContext) {
         mParent = parent;
         mClientContext = Preconditions.checkNotNull(clientContext);
     }
 
     @Override
-    ContentCaptureSession newChild(@NonNull ContentCaptureContext context) {
-        // TODO(b/121033016): implement it
-        throw new UnsupportedOperationException("grand-children not implemented yet");
+    MainContentCaptureSession getMainCaptureSession() {
+        if (mParent instanceof MainContentCaptureSession) {
+            return (MainContentCaptureSession) mParent;
+        }
+        return mParent.getMainCaptureSession();
     }
 
     @Override
-    void flush() {
-        mParent.flush();
+    ContentCaptureSession newChild(@NonNull ContentCaptureContext clientContext) {
+        final ContentCaptureSession child = new ChildContentCaptureSession(this, clientContext);
+        getMainCaptureSession().notifyChildSessionStarted(mId, child.mId, clientContext);
+        return child;
+    }
+
+    @Override
+    void flush(@FlushReason int reason) {
+        mParent.flush(reason);
     }
 
     @Override
     void onDestroy() {
-        mParent.notifyChildSessionFinished(mParent.mId, mId);
+        getMainCaptureSession().notifyChildSessionFinished(mParent.mId, mId);
     }
 
     @Override
     void internalNotifyViewAppeared(@NonNull ViewStructureImpl node) {
-        mParent.notifyViewAppeared(mId, node);
+        getMainCaptureSession().notifyViewAppeared(mId, node);
     }
 
     @Override
     void internalNotifyViewDisappeared(@NonNull AutofillId id) {
-        mParent.notifyViewDisappeared(mId, id);
+        getMainCaptureSession().notifyViewDisappeared(mId, id);
     }
 
     @Override
-    void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
-            int flags) {
-        mParent.notifyViewTextChanged(mId, id, text, flags);
+    void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text) {
+        getMainCaptureSession().notifyViewTextChanged(mId, id, text);
     }
+
     @Override
     boolean isContentCaptureEnabled() {
-        return mParent.isContentCaptureEnabled();
+        return getMainCaptureSession().isContentCaptureEnabled();
     }
 
     @Override
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 2d2987a..1928613 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -22,6 +22,7 @@
 import android.app.TaskInfo;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -84,9 +85,9 @@
     // Fields below are set by app on Builder
     private final @Nullable Bundle mExtras;
     private final @Nullable Uri mUri;
+    private final @Nullable String mAction;
 
     // Fields below are set by server when the session starts
-    // TODO(b/111276913): create new object for taskId + componentName / reuse on other places
     private final @Nullable ComponentName mComponentName;
     private final int mTaskId;
     private final int mDisplayId;
@@ -102,10 +103,12 @@
             mHasClientContext = true;
             mExtras = clientContext.mExtras;
             mUri = clientContext.mUri;
+            mAction = clientContext.mAction;
         } else {
             mHasClientContext = false;
             mExtras = null;
             mUri = null;
+            mAction = null;
         }
         mComponentName = Preconditions.checkNotNull(componentName);
         mTaskId = taskId;
@@ -117,13 +120,14 @@
         mHasClientContext = true;
         mExtras = builder.mExtras;
         mUri = builder.mUri;
+        mAction = builder.mAction;
 
         mComponentName  = null;
         mTaskId = mFlags = mDisplayId = 0;
     }
 
     /**
-     * Gets the (optional) extras set by the app.
+     * Gets the (optional) extras set by the app (through {@link Builder#setExtras(Bundle)}).
      *
      * <p>It can be used to provide vendor-specific data that can be modified and examined.
      *
@@ -136,7 +140,7 @@
     }
 
     /**
-     * Gets the (optional) URI set by the app.
+     * Gets the (optional) URI set by the app (through {@link Builder#setUri(Uri)}).
      *
      * @hide
      */
@@ -147,6 +151,17 @@
     }
 
     /**
+     * Gets the (optional) action set by the app (through {@link Builder#setAction(String)}).
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public String getAction() {
+        return mAction;
+    }
+
+    /**
      * Gets the id of the {@link TaskInfo task} associated with this context.
      *
      * @hide
@@ -213,6 +228,8 @@
     public static final class Builder {
         private Bundle mExtras;
         private Uri mUri;
+        private boolean mDestroyed;
+        private String mAction;
 
         /**
          * Sets extra options associated with this context.
@@ -221,11 +238,13 @@
          *
          * @param extras extra options.
          * @return this builder.
+         *
+         * @throws IllegalStateException if {@link #build()} was already called.
          */
         @NonNull
         public Builder setExtras(@NonNull Bundle extras) {
-            // TODO(b/111276913): check build just once / throw exception / test / document
             mExtras = Preconditions.checkNotNull(extras);
+            throwIfDestroyed();
             return this;
         }
 
@@ -236,23 +255,51 @@
          *
          * @param uri URI associated with this context.
          * @return this builder.
+         *
+         * @throws IllegalStateException if {@link #build()} was already called.
          */
         @NonNull
         public Builder setUri(@NonNull Uri uri) {
-            // TODO(b/111276913): check build just once / throw exception / test / document
             mUri = Preconditions.checkNotNull(uri);
+            throwIfDestroyed();
+            return this;
+        }
+
+        /**
+         * Sets an {@link Intent#getAction() intent action} associated with this context.
+         *
+         * @param action intent action
+         *
+         * @return this builder
+         *
+         * @throws IllegalStateException if {@link #build()} was already called.
+         */
+        @NonNull
+        public Builder setAction(@NonNull String action) {
+            mAction = Preconditions.checkNotNull(action);
+            throwIfDestroyed();
             return this;
         }
 
         /**
          * Builds the {@link ContentCaptureContext}.
+         *
+         * @throws IllegalStateException if {@link #build()} was already called or no call to either
+         * {@link #setExtras(Bundle)}, {@link #setAction(String)}, or {@link #setUri(Uri)} was made.
+         *
+         * @return the built {@code ContentCaptureContext}
          */
         public ContentCaptureContext build() {
-            // TODO(b/111276913): check build just once / throw exception / test / document
-            // TODO(b/111276913): make sure it at least one property (uri / extras) / test /
-            // throw exception / documment
+            throwIfDestroyed();
+            Preconditions.checkState(mExtras != null || mUri != null || mAction != null,
+                    "Must call setUri() or setExtras() or setUri() before calling build()");
+            mDestroyed = true;
             return new ContentCaptureContext(this);
         }
+
+        private void throwIfDestroyed() {
+            Preconditions.checkState(!mDestroyed, "Already called #build()");
+        }
     }
 
     /**
@@ -277,6 +324,10 @@
             // NOTE: cannot dump because it could contain PII
             pw.print(", hasUri");
         }
+        if (mAction != null) {
+            // NOTE: cannot dump because it could contain PII
+            pw.print(", hasAction");
+        }
     }
 
     @Override
@@ -297,6 +348,10 @@
             // NOTE: cannot print because it could contain PII
             builder.append(", hasUri");
         }
+        if (mAction != null) {
+            // NOTE: cannot print because it could contain PII
+            builder.append(", hasAction");
+        }
         return builder.append(']').toString();
     }
 
@@ -310,6 +365,7 @@
         parcel.writeInt(mHasClientContext ? 1 : 0);
         if (mHasClientContext) {
             parcel.writeParcelable(mUri, flags);
+            parcel.writeString(mAction);
             parcel.writeBundle(mExtras);
         }
         parcel.writeParcelable(mComponentName, flags);
@@ -329,12 +385,14 @@
 
             final ContentCaptureContext clientContext;
             if (hasClientContext) {
+                // Must reconstruct the client context using the Builder API
                 final Builder builder = new Builder();
                 final Uri uri = parcel.readParcelable(null);
+                final String action = parcel.readString();
                 final Bundle extras = parcel.readBundle();
                 if (uri != null) builder.setUri(uri);
+                if (action != null) builder.setAction(action);
                 if (extras != null) builder.setExtras(extras);
-                // Must reconstruct the client context using the Builder API
                 clientContext = new ContentCaptureContext(builder);
             } else {
                 clientContext = null;
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index 9e3da92..a6d4472 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -15,12 +15,15 @@
  */
 package android.view.contentcapture;
 
+import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
 import android.view.autofill.AutofillId;
 
 import com.android.internal.util.Preconditions;
@@ -28,11 +31,15 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
 
 /** @hide */
 @SystemApi
 public final class ContentCaptureEvent implements Parcelable {
 
+    private static final String TAG = ContentCaptureEvent.class.getSimpleName();
+
     /** @hide */
     public static final int TYPE_SESSION_FINISHED = -2;
     /** @hide */
@@ -46,9 +53,11 @@
     public static final int TYPE_VIEW_APPEARED = 1;
 
     /**
-     * Called when a node has been removed from the screen and is not visible to the user anymore.
+     * Called when one or more nodes have been removed from the screen and is not visible to the
+     * user anymore.
      *
-     * <p>The id of the node is available through {@link #getId()}.
+     * <p>To get the id(s), first call {@link #getIds()} - if it returns {@code null}, then call
+     * {@link #getId()}.
      */
     public static final int TYPE_VIEW_DISAPPEARED = 2;
 
@@ -74,29 +83,23 @@
     private final @NonNull String mSessionId;
     private final int mType;
     private final long mEventTime;
-    private final int mFlags;
     private @Nullable AutofillId mId;
+    private @Nullable ArrayList<AutofillId> mIds;
     private @Nullable ViewNode mNode;
     private @Nullable CharSequence mText;
     private @Nullable String mParentSessionId;
     private @Nullable ContentCaptureContext mClientContext;
 
     /** @hide */
-    public ContentCaptureEvent(@NonNull String sessionId, int type, long eventTime, int flags) {
+    public ContentCaptureEvent(@NonNull String sessionId, int type, long eventTime) {
         mSessionId = sessionId;
         mType = type;
         mEventTime = eventTime;
-        mFlags = flags;
-    }
-
-    /** @hide */
-    public ContentCaptureEvent(@NonNull String sessionId, int type, int flags) {
-        this(sessionId, type, System.currentTimeMillis(), flags);
     }
 
     /** @hide */
     public ContentCaptureEvent(@NonNull String sessionId, int type) {
-        this(sessionId, type, /* flags= */ 0);
+        this(sessionId, type, System.currentTimeMillis());
     }
 
     /** @hide */
@@ -105,6 +108,27 @@
         return this;
     }
 
+    private void setAutofillIds(@NonNull ArrayList<AutofillId> ids) {
+        mIds = Preconditions.checkNotNull(ids);
+    }
+
+    /**
+     * Adds an autofill id to the this event, merging the single id into a list if necessary.
+     * @hide */
+    public ContentCaptureEvent addAutofillId(@NonNull AutofillId id) {
+        if (mIds == null) {
+            mIds = new ArrayList<>();
+            if (mId == null) {
+                Log.w(TAG, "addAutofillId(" + id + ") called without an initial id");
+            } else {
+                mIds.add(mId);
+                mId = null;
+            }
+        }
+        mIds.add(id);
+        return this;
+    }
+
     /**
      * Used by {@link #TYPE_SESSION_STARTED} and {@link #TYPE_SESSION_FINISHED}.
      *
@@ -183,16 +207,6 @@
     }
 
     /**
-     * Gets optional flags associated with the event.
-     *
-     * @return either {@code 0} or
-     * {@link android.view.contentcapture.ContentCaptureSession#FLAG_USER_INPUT}.
-     */
-    public int getFlags() {
-        return mFlags;
-    }
-
-    /**
      * Gets the whole metadata of the node associated with the event.
      *
      * <p>Only set on {@link #TYPE_VIEW_APPEARED} events.
@@ -205,7 +219,9 @@
     /**
      * Gets the {@link AutofillId} of the node associated with the event.
      *
-     * <p>Only set on {@link #TYPE_VIEW_DISAPPEARED} and {@link #TYPE_VIEW_TEXT_CHANGED} events.
+     * <p>Only set on {@link #TYPE_VIEW_DISAPPEARED} (when the event contains just one node - if
+     * it contains more than one, this method returns {@code null} and the actual ids should be
+     * retrived by {@link #getIds()}) and {@link #TYPE_VIEW_TEXT_CHANGED} events.
      */
     @Nullable
     public AutofillId getId() {
@@ -213,6 +229,17 @@
     }
 
     /**
+     * Gets the {@link AutofillId AutofillIds} of the nodes associated with the event.
+     *
+     * <p>Only set on {@link #TYPE_VIEW_DISAPPEARED}, when the event contains more than one node
+     * (if it contains just one node, it's returned by {@link #getId()} instead.
+     */
+    @Nullable
+    public List<AutofillId> getIds() {
+        return mIds;
+    }
+
+    /**
      * Gets the current text of the node associated with the event.
      *
      * <p>Only set on {@link #TYPE_VIEW_TEXT_CHANGED} events.
@@ -226,12 +253,12 @@
     public void dump(@NonNull PrintWriter pw) {
         pw.print("type="); pw.print(getTypeAsString(mType));
         pw.print(", time="); pw.print(mEventTime);
-        if (mFlags > 0) {
-            pw.print(", flags="); pw.print(mFlags);
-        }
         if (mId != null) {
             pw.print(", id="); pw.print(mId);
         }
+        if (mIds != null) {
+            pw.print(", ids="); pw.print(mIds);
+        }
         if (mNode != null) {
             pw.print(", mNode.id="); pw.print(mNode.getAutofillId());
         }
@@ -242,8 +269,7 @@
             pw.print(", parentSessionId="); pw.print(mParentSessionId);
         }
         if (mText != null) {
-            // Cannot print content because could have PII
-            pw.print(", text="); pw.print(mText.length()); pw.print("_chars");
+            pw.print(", text="); pw.println(getSanitizedString(mText));
         }
     }
 
@@ -251,12 +277,16 @@
     public String toString() {
         final StringBuilder string = new StringBuilder("ContentCaptureEvent[type=")
                 .append(getTypeAsString(mType));
-        if (mFlags > 0) {
-            string.append(", flags=").append(mFlags);
+        string.append(", session=").append(mSessionId);
+        if (mType == TYPE_SESSION_STARTED && mParentSessionId != null) {
+            string.append(", parent=").append(mParentSessionId);
         }
         if (mId != null) {
             string.append(", id=").append(mId);
         }
+        if (mIds != null) {
+            string.append(", ids=").append(mIds);
+        }
         if (mNode != null) {
             final String className = mNode.getClassName();
             if (mNode != null) {
@@ -264,6 +294,9 @@
             }
             string.append(", id=").append(mNode.getAutofillId());
         }
+        if (mText != null) {
+            string.append(", text=").append(getSanitizedString(mText));
+        }
         return string.append(']').toString();
     }
 
@@ -277,8 +310,8 @@
         parcel.writeString(mSessionId);
         parcel.writeInt(mType);
         parcel.writeLong(mEventTime);
-        parcel.writeInt(mFlags);
         parcel.writeParcelable(mId, flags);
+        parcel.writeTypedList(mIds);
         ViewNode.writeToParcel(parcel, mNode, flags);
         parcel.writeCharSequence(mText);
         if (mType == TYPE_SESSION_STARTED || mType == TYPE_SESSION_FINISHED) {
@@ -297,13 +330,15 @@
             final String sessionId = parcel.readString();
             final int type = parcel.readInt();
             final long eventTime  = parcel.readLong();
-            final int flags = parcel.readInt();
-            final ContentCaptureEvent event =
-                    new ContentCaptureEvent(sessionId, type, eventTime, flags);
+            final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, type, eventTime);
             final AutofillId id = parcel.readParcelable(null);
             if (id != null) {
                 event.setAutofillId(id);
             }
+            final ArrayList<AutofillId> ids = parcel.createTypedArrayList(AutofillId.CREATOR);
+            if (ids != null) {
+                event.setAutofillIds(ids);
+            }
             final ViewNode node = ViewNode.readFromParcel(parcel);
             if (node != null) {
                 event.setViewNode(node);
diff --git a/core/java/android/view/contentcapture/ContentCaptureHelper.java b/core/java/android/view/contentcapture/ContentCaptureHelper.java
new file mode 100644
index 0000000..508880f
--- /dev/null
+++ b/core/java/android/view/contentcapture/ContentCaptureHelper.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.contentcapture;
+
+import android.annotation.Nullable;
+
+/**
+ * Helpe class for this package.
+ */
+final class ContentCaptureHelper {
+
+    // TODO(b/121044306): define a way to dynamically set them(for example, using settings?)
+    static final boolean VERBOSE = false;
+    static final boolean DEBUG = true; // STOPSHIP if not set to false
+
+    /**
+     * Used to log text that could contain PII.
+     */
+    @Nullable
+    public static String getSanitizedString(@Nullable CharSequence text) {
+        return text == null ? null : text.length() + "_chars";
+    }
+
+    private ContentCaptureHelper() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 9830790..b9017b3 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -15,6 +15,10 @@
  */
 package android.view.contentcapture;
 
+import static android.view.contentcapture.ContentCaptureHelper.VERBOSE;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemService;
@@ -22,14 +26,18 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
 import android.util.Log;
+import android.view.contentcapture.ContentCaptureSession.FlushReason;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.SyncResultReceiver;
 
 import java.io.PrintWriter;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 /*
  * NOTE: all methods in this class should return right away, or do the real work in a handler
@@ -46,14 +54,15 @@
 
     private static final String TAG = ContentCaptureManager.class.getSimpleName();
 
-    private static final String BG_THREAD_NAME = "intel_svc_streamer_thread";
+    /**
+     * Timeout for calls to system_server.
+     */
+    private static final int SYNC_CALLS_TIMEOUT_MS = 5000;
 
-    // TODO(b/121044306): define a way to dynamically set them(for example, using settings?)
-    static final boolean VERBOSE = false;
-    static final boolean DEBUG = true; // STOPSHIP if not set to false
+    private final Object mLock = new Object();
 
-    @NonNull
-    private final AtomicBoolean mDisabled = new AtomicBoolean();
+    @GuardedBy("mLock")
+    private boolean mDisabled;
 
     @NonNull
     private final Context mContext;
@@ -61,35 +70,29 @@
     @Nullable
     private final IContentCaptureManager mService;
 
+    // Flags used for starting session.
+    @GuardedBy("mLock")
+    private int mFlags;
+
     // TODO(b/119220549): use UI Thread directly (as calls are one-way) or a shared thread / handler
     // held at the Application level
     @NonNull
     private final Handler mHandler;
 
+    @GuardedBy("mLock")
     private MainContentCaptureSession mMainSession;
 
     /** @hide */
     public ContentCaptureManager(@NonNull Context context,
             @Nullable IContentCaptureManager service) {
         mContext = Preconditions.checkNotNull(context, "context cannot be null");
-        if (VERBOSE) {
-            Log.v(TAG, "Constructor for " + context.getPackageName());
-        }
-        mService = service;
-        // TODO(b/119220549): use an existing bg thread instead...
-        final HandlerThread bgThread = new HandlerThread(BG_THREAD_NAME);
-        bgThread.start();
-        mHandler = Handler.createAsync(bgThread.getLooper());
-    }
+        if (VERBOSE) Log.v(TAG, "Constructor for " + context.getPackageName());
 
-    @NonNull
-    private static Handler newHandler() {
-        // TODO(b/119220549): use an existing bg thread instead...
-        // TODO(b/119220549): use UI Thread directly (as calls are one-way) or an existing bgThread
-        // or a shared thread / handler held at the Application level
-        final HandlerThread bgThread = new HandlerThread(BG_THREAD_NAME);
-        bgThread.start();
-        return Handler.createAsync(bgThread.getLooper());
+        mService = service;
+        // TODO(b/119220549): we might not even need a handler, as the IPCs are oneway. But if we
+        // do, then we should optimize it to run the tests after the Choreographer finishes the most
+        // important steps of the frame.
+        mHandler = Handler.createAsync(Looper.getMainLooper());
     }
 
     /**
@@ -104,26 +107,29 @@
     @NonNull
     @UiThread
     public MainContentCaptureSession getMainContentCaptureSession() {
-        if (mMainSession == null) {
-            mMainSession = new MainContentCaptureSession(mContext, mHandler, mService,
-                    mDisabled);
-            if (VERBOSE) {
-                Log.v(TAG, "getDefaultContentCaptureSession(): created " + mMainSession);
+        synchronized (mLock) {
+            if (mMainSession == null) {
+                mMainSession = new MainContentCaptureSession(mContext, mHandler, mService,
+                        mDisabled);
+                if (VERBOSE) {
+                    Log.v(TAG, "getDefaultContentCaptureSession(): created " + mMainSession);
+                }
             }
+            return mMainSession;
         }
-        return mMainSession;
     }
 
     /** @hide */
     public void onActivityStarted(@NonNull IBinder applicationToken,
-            @NonNull ComponentName activityComponent) {
-        // TODO(b/121033016): must start all sessions
-        getMainContentCaptureSession().start(applicationToken, activityComponent);
+            @NonNull ComponentName activityComponent, int flags) {
+        synchronized (mLock) {
+            mFlags |= flags;
+            getMainContentCaptureSession().start(applicationToken, activityComponent, mFlags);
+        }
     }
 
     /** @hide */
     public void onActivityStopped() {
-        // TODO(b/121033016): must finish all sessions
         getMainContentCaptureSession().destroy();
     }
 
@@ -134,9 +140,8 @@
      *
      * @hide
      */
-    public void flush() {
-        // TODO(b/121033016): must flush all sessions
-        getMainContentCaptureSession().flush();
+    public void flush(@FlushReason int reason) {
+        getMainContentCaptureSession().flush(reason);
     }
 
     /**
@@ -145,15 +150,30 @@
      */
     @Nullable
     public ComponentName getServiceComponentName() {
-        //TODO(b/121047489): implement
-        return null;
+        if (!isContentCaptureEnabled()) {
+            return null;
+        }
+        // Wait for system server to return the component name.
+        final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+        mHandler.sendMessage(obtainMessage(
+                ContentCaptureManager::handleReceiverServiceComponentName,
+                this, mContext.getUserId(), resultReceiver));
+
+        try {
+            return resultReceiver.getParcelableResult();
+        } catch (RemoteException e) {
+            // Unable to retrieve component name in a reasonable amount of time.
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
      * Checks whether content capture is enabled for this activity.
      */
     public boolean isContentCaptureEnabled() {
-        return mService != null && !mDisabled.get();
+        synchronized (mLock) {
+            return mService != null && !mDisabled;
+        }
     }
 
     /**
@@ -163,35 +183,55 @@
      * it on {@link android.app.Activity#onCreate(android.os.Bundle, android.os.PersistableBundle)}.
      */
     public void setContentCaptureEnabled(boolean enabled) {
-        //TODO(b/111276913): implement (need to finish / disable all sessions)
+        synchronized (mLock) {
+            mFlags |= enabled ? 0 : ContentCaptureContext.FLAG_DISABLED_BY_APP;
+        }
     }
 
     /**
-     * Called by the ap to request the Content Capture service to remove user-data associated with
+     * Called by the app to request the Content Capture service to remove user-data associated with
      * some context.
      *
      * @param request object specifying what user data should be removed.
      */
     public void removeUserData(@NonNull UserDataRemovalRequest request) {
-        //TODO(b/111276913): implement
+        Preconditions.checkNotNull(request);
+
+        try {
+            mService.removeUserData(mContext.getUserId(), request);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /** @hide */
     public void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.println("ContentCaptureManager");
-
-        pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled.get());
-        pw.print(prefix); pw.print("Context: "); pw.println(mContext);
-        pw.print(prefix); pw.print("User: "); pw.println(mContext.getUserId());
-        if (mService != null) {
-            pw.print(prefix); pw.print("Service: "); pw.println(mService);
+        synchronized (mLock) {
+            pw.print(prefix); pw.println("ContentCaptureManager");
+            pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
+            pw.print(prefix); pw.print("Context: "); pw.println(mContext);
+            pw.print(prefix); pw.print("User: "); pw.println(mContext.getUserId());
+            if (mService != null) {
+                pw.print(prefix); pw.print("Service: "); pw.println(mService);
+            }
+            pw.print(prefix); pw.print("Flags: "); pw.println(mFlags);
+            if (mMainSession != null) {
+                final String prefix2 = prefix + "  ";
+                pw.print(prefix); pw.println("Main session:");
+                mMainSession.dump(prefix2, pw);
+            } else {
+                pw.print(prefix); pw.println("No sessions");
+            }
         }
-        if (mMainSession != null) {
-            final String prefix2 = prefix + "  ";
-            pw.print(prefix); pw.println("Main session:");
-            mMainSession.dump(prefix2, pw);
-        } else {
-            pw.print(prefix); pw.println("No sessions");
+    }
+
+
+    /** Retrieves the component name of the target content capture service through system_server. */
+    private void handleReceiverServiceComponentName(int userId, IResultReceiver resultReceiver) {
+        try {
+            mService.getReceiverServiceComponentName(userId, resultReceiver);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Unable to retrieve service component name: " + e);
         }
     }
 }
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 9f666a4..6ed2d80 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -15,23 +15,30 @@
  */
 package android.view.contentcapture;
 
-import static android.view.contentcapture.ContentCaptureManager.DEBUG;
-import static android.view.contentcapture.ContentCaptureManager.VERBOSE;
+import static android.view.contentcapture.ContentCaptureHelper.DEBUG;
+import static android.view.contentcapture.ContentCaptureHelper.VERBOSE;
 
 import android.annotation.CallSuper;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.util.DebugUtils;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewStructure;
 import android.view.autofill.AutofillId;
 import android.view.contentcapture.ViewNode.ViewStructureImpl;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 
 import dalvik.system.CloseGuard;
 
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.UUID;
 
@@ -41,60 +48,123 @@
  */
 public abstract class ContentCaptureSession implements AutoCloseable {
 
-    /**
-     * Used on {@link #notifyViewTextChanged(AutofillId, CharSequence, int)} to indicate that the
-     *
-     * thext change was caused by user input (for example, through IME).
-     */
-    public static final int FLAG_USER_INPUT = 0x1;
+    private static final String TAG = ContentCaptureSession.class.getSimpleName();
 
     /**
      * Initial state, when there is no session.
      *
      * @hide
      */
-    public static final int STATE_UNKNOWN = 0;
+    // NOTE: not prefixed by STATE_ so it's not printed on getStateAsString()
+    public static final int UNKNWON_STATE = 0x0;
 
     /**
      * Service's startSession() was called, but server didn't confirm it was created yet.
      *
      * @hide
      */
-    public static final int STATE_WAITING_FOR_SERVER = 1;
+    public static final int STATE_WAITING_FOR_SERVER = 0x1;
 
     /**
      * Session is active.
      *
      * @hide
      */
-    public static final int STATE_ACTIVE = 2;
+    public static final int STATE_ACTIVE = 0x2;
 
     /**
-     * Session is disabled.
+     * Session is disabled because there is no service for this user.
      *
      * @hide
      */
-    public static final int STATE_DISABLED = 3;
+    public static final int STATE_DISABLED = 0x4;
 
     /**
      * Session is disabled because its id already existed on server.
      *
      * @hide
      */
-    public static final int STATE_DISABLED_DUPLICATED_ID = 4;
+    public static final int STATE_DUPLICATED_ID = 0x8;
+
+    /**
+     * Session is disabled because service is not set for user.
+     *
+     * @hide
+     */
+    public static final int STATE_NO_SERVICE = 0x10;
+
+    /**
+     * Session is disabled by FLAG_SECURE
+     *
+     * @hide
+     */
+    public static final int STATE_FLAG_SECURE = 0x20;
+
+    /**
+     * Session is disabled manually by the specific app.
+     *
+     * @hide
+     */
+    public static final int STATE_BY_APP = 0x40;
+
+    /**
+     * Session is disabled because session start was never replied.
+     *
+     * @hide
+     */
+    public static final int STATE_NO_RESPONSE = 0x80;
+
+    /**
+     * Session is disabled because an internal error.
+     *
+     * @hide
+     */
+    public static final int STATE_INTERNAL_ERROR = 0x100;
 
     private static final int INITIAL_CHILDREN_CAPACITY = 5;
 
     /** @hide */
-    protected final String mTag = getClass().getSimpleName();
+    public static final int FLUSH_REASON_FULL = 1;
+    /** @hide */
+    public static final int FLUSH_REASON_ACTIVITY_PAUSED = 2;
+    /** @hide */
+    public static final int FLUSH_REASON_ACTIVITY_RESUMED = 3;
+    /** @hide */
+    public static final int FLUSH_REASON_SESSION_STARTED = 4;
+    /** @hide */
+    public static final int FLUSH_REASON_SESSION_FINISHED = 5;
+    /** @hide */
+    public static final int FLUSH_REASON_IDLE_TIMEOUT = 6;
+
+    /** @hide */
+    @IntDef(prefix = { "FLUSH_REASON_" }, value = {
+            FLUSH_REASON_FULL,
+            FLUSH_REASON_ACTIVITY_PAUSED,
+            FLUSH_REASON_ACTIVITY_RESUMED,
+            FLUSH_REASON_SESSION_STARTED,
+            FLUSH_REASON_SESSION_FINISHED,
+            FLUSH_REASON_IDLE_TIMEOUT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface FlushReason{}
+
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
+    private final Object mLock = new Object();
+
+    /**
+     * Guard use to ignore events after it's destroyed.
+     */
+    @NonNull
+    @GuardedBy("mLock")
+    private boolean mDestroyed;
+
     /** @hide */
     @Nullable
-    protected final String mId = UUID.randomUUID().toString();
+    protected final String mId;
 
-    private int mState = STATE_UNKNOWN;
+    private int mState = UNKNWON_STATE;
 
     // Lazily created on demand.
     private ContentCaptureSessionId mContentCaptureSessionId;
@@ -102,18 +172,26 @@
     /**
      * List of children session.
      */
-    // TODO(b/121033016): need to synchonize access, either by changing on handler or UI thread
-    // (for now there's no handler on this class, so we need to wait for the next refactoring),
-    // most likely the former (as we have no guarantee that createContentCaptureSession()
-    // it will be called in the UiThread; for example, WebView most likely won't call on it)
     @Nullable
+    @GuardedBy("mLock")
     private ArrayList<ContentCaptureSession> mChildren;
 
     /** @hide */
     protected ContentCaptureSession() {
+        this(UUID.randomUUID().toString());
+    }
+
+    /** @hide */
+    @VisibleForTesting
+    public ContentCaptureSession(@NonNull String id) {
+        mId = Preconditions.checkNotNull(id);
         mCloseGuard.open("destroy");
     }
 
+    /** @hide */
+    @NonNull
+    abstract MainContentCaptureSession getMainCaptureSession();
+
     /**
      * Gets the id used to identify this session.
      */
@@ -124,6 +202,13 @@
         return mContentCaptureSessionId;
     }
 
+    /** @hide */
+    @VisibleForTesting
+    public int getIdAsInt() {
+        // TODO(b/121197119): use sessionId instead of hashcode once it's changed to int
+        return mId.hashCode();
+    }
+
     /**
      * Creates a new {@link ContentCaptureSession}.
      *
@@ -134,13 +219,15 @@
             @NonNull ContentCaptureContext context) {
         final ContentCaptureSession child = newChild(context);
         if (DEBUG) {
-            Log.d(mTag, "createContentCaptureSession(" + context + ": parent=" + mId + ", child= "
+            Log.d(TAG, "createContentCaptureSession(" + context + ": parent=" + mId + ", child="
                     + child.mId);
         }
-        if (mChildren == null) {
-            mChildren = new ArrayList<>(INITIAL_CHILDREN_CAPACITY);
+        synchronized (mLock) {
+            if (mChildren == null) {
+                mChildren = new ArrayList<>(INITIAL_CHILDREN_CAPACITY);
+            }
+            mChildren.add(child);
         }
-        mChildren.add(child);
         return child;
     }
 
@@ -149,7 +236,7 @@
     /**
      * Flushes the buffered events to the service.
      */
-    abstract void flush();
+    abstract void flush(@FlushReason int reason);
 
     /**
      * Destroys this session, flushing out all pending notifications to the service.
@@ -157,35 +244,37 @@
      * <p>Once destroyed, any new notification will be dropped.
      */
     public final void destroy() {
-        //TODO(b/111276913): mark it as destroyed so other methods are ignored (and test on CTS)
+        synchronized (mLock) {
+            if (mDestroyed) {
+                if (DEBUG) Log.d(TAG, "destroy(" + mId + "): already destroyed");
+                return;
+            }
+            mDestroyed = true;
 
-        //TODO(b/111276913): probably shouldn't check for it
-        if (!isContentCaptureEnabled()) return;
+            mCloseGuard.close();
 
-        mCloseGuard.close();
-
-        //TODO(b/111276913): check state (for example, how to handle if it's waiting for remote
-        // id) and send it to the cache of batched commands
-        if (VERBOSE) {
-            Log.v(mTag, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId);
-        }
-
-        // Finish children first
-        if (mChildren != null) {
-            final int numberChildren = mChildren.size();
-            if (VERBOSE) Log.v(mTag, "Destroying " + numberChildren + " children first");
-            for (int i = 0; i < numberChildren; i++) {
-                final ContentCaptureSession child = mChildren.get(i);
-                try {
-                    child.destroy();
-                } catch (Exception e) {
-                    Log.w(mTag, "exception destroying child session #" + i + ": " + e);
+            // TODO(b/111276913): check state (for example, how to handle if it's waiting for remote
+            // id) and send it to the cache of batched commands
+            if (VERBOSE) {
+                Log.v(TAG, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId);
+            }
+            // Finish children first
+            if (mChildren != null) {
+                final int numberChildren = mChildren.size();
+                if (VERBOSE) Log.v(TAG, "Destroying " + numberChildren + " children first");
+                for (int i = 0; i < numberChildren; i++) {
+                    final ContentCaptureSession child = mChildren.get(i);
+                    try {
+                        child.destroy();
+                    } catch (Exception e) {
+                        Log.w(TAG, "exception destroying child session #" + i + ": " + e);
+                    }
                 }
             }
         }
 
         try {
-            flush();
+            flush(FLUSH_REASON_SESSION_FINISHED);
         } finally {
             onDestroy();
         }
@@ -251,12 +340,36 @@
     abstract void internalNotifyViewDisappeared(@NonNull AutofillId id);
 
     /**
+     * Notifies the Content Capture Service that many nodes has been removed from a virtual view
+     * structure.
+     *
+     * <p>Should only be called by views that handle their own virtual view hierarchy.
+     *
+     * @param hostId id of the view hosting the virtual hierarchy.
+     * @param virtualIds ids of the virtual children.
+     *
+     * @throws IllegalArgumentException if the {@code hostId} is an autofill id for a virtual view.
+     * @throws IllegalArgumentException if {@code virtualIds} is empty
+     */
+    public final void notifyViewsDisappeared(@NonNull AutofillId hostId,
+            @NonNull long[] virtualIds) {
+        Preconditions.checkArgument(hostId.isNonVirtual(), "parent cannot be virtual");
+        Preconditions.checkArgument(!ArrayUtils.isEmpty(virtualIds), "virtual ids cannot be empty");
+        if (!isContentCaptureEnabled()) return;
+
+        // TODO(b/123036895): use a internalNotifyViewsDisappeared that optimizes how the event is
+        // parcelized
+        for (long id : virtualIds) {
+            internalNotifyViewDisappeared(new AutofillId(hostId, id, getIdAsInt()));
+        }
+    }
+
+    /**
      * Notifies the Intelligence Service that the value of a text node has been changed.
      *
      * @param id of the node.
      * @param text new text.
-     * @param flags either {@code 0} or {@link #FLAG_USER_INPUT} when the value was explicitly
-     * changed by the user (for example, through the keyboard).
+     * @param flags currently ignored.
      */
     public final void notifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
             int flags) {
@@ -264,11 +377,11 @@
 
         if (!isContentCaptureEnabled()) return;
 
-        internalNotifyViewTextChanged(id, text, flags);
+        internalNotifyViewTextChanged(id, text);
     }
 
-    abstract void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
-            int flags);
+    abstract void internalNotifyViewTextChanged(@NonNull AutofillId id,
+            @Nullable CharSequence text);
 
     /**
      * Creates a {@link ViewStructure} for a "standard" view.
@@ -281,6 +394,24 @@
     }
 
     /**
+     * Creates a new {@link AutofillId} for a virtual child, so it can be used to uniquely identify
+     * the children in the session.
+     *
+     * @param parentId id of the virtual view parent (it can be obtained by calling
+     * {@link ViewStructure#getAutofillId()} on the parent).
+     * @param virtualChildId id of the virtual child, relative to the parent.
+     *
+     * @return if for the virtual child
+     *
+     * @throws IllegalArgumentException if the {@code parentId} is a virtual child id.
+     */
+    public @NonNull AutofillId newAutofillId(@NonNull AutofillId parentId, long virtualChildId) {
+        Preconditions.checkNotNull(parentId);
+        Preconditions.checkArgument(parentId.isNonVirtual(), "virtual ids cannot have children");
+        return new AutofillId(parentId, virtualChildId, getIdAsInt());
+    }
+
+    /**
      * Creates a {@link ViewStructure} for a "virtual" view, so it can be passed to
      * {@link #notifyViewAppeared(ViewStructure)} by the view managing the virtual view hierarchy.
      *
@@ -289,29 +420,34 @@
      * @param virtualId id of the virtual child, relative to the parent.
      *
      * @return a new {@link ViewStructure} that can be used for Content Capture purposes.
-     *
-     * @hide
      */
     @NonNull
     public final ViewStructure newVirtualViewStructure(@NonNull AutofillId parentId,
-            int virtualId) {
-        return new ViewNode.ViewStructureImpl(parentId, virtualId);
+            long virtualId) {
+        return new ViewNode.ViewStructureImpl(parentId, virtualId, getIdAsInt());
     }
 
-    abstract boolean isContentCaptureEnabled();
+    boolean isContentCaptureEnabled() {
+        synchronized (mLock) {
+            return !mDestroyed;
+        }
+    }
 
     @CallSuper
     void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
-        if (mChildren != null && !mChildren.isEmpty()) {
-            final String prefix2 = prefix + "  ";
-            final int numberChildren = mChildren.size();
-            pw.print(prefix); pw.print("number children: "); pw.print(numberChildren);
-            for (int i = 0; i < numberChildren; i++) {
-                final ContentCaptureSession child = mChildren.get(i);
-                pw.print(prefix); pw.print(i); pw.println(": "); child.dump(prefix2, pw);
+        pw.print(prefix); pw.print("id: "); pw.println(mId);
+        synchronized (mLock) {
+            pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed);
+            if (mChildren != null && !mChildren.isEmpty()) {
+                final String prefix2 = prefix + "  ";
+                final int numberChildren = mChildren.size();
+                pw.print(prefix); pw.print("number children: "); pw.println(numberChildren);
+                for (int i = 0; i < numberChildren; i++) {
+                    final ContentCaptureSession child = mChildren.get(i);
+                    pw.print(prefix); pw.print(i); pw.println(": "); child.dump(prefix2, pw);
+                }
             }
         }
-
     }
 
     @Override
@@ -319,24 +455,31 @@
         return mId;
     }
 
-    /**
-     * @hide
-     */
+    /** @hide */
     @NonNull
     protected static String getStateAsString(int state) {
-        switch (state) {
-            case STATE_UNKNOWN:
-                return "UNKNOWN";
-            case STATE_WAITING_FOR_SERVER:
-                return "WAITING_FOR_SERVER";
-            case STATE_ACTIVE:
-                return "ACTIVE";
-            case STATE_DISABLED:
-                return "DISABLED";
-            case STATE_DISABLED_DUPLICATED_ID:
-                return "DISABLED_DUPLICATED_ID";
+        return state + " (" + (state == UNKNWON_STATE ? "UNKNOWN"
+                : DebugUtils.flagsToString(ContentCaptureSession.class, "STATE_", state)) + ")";
+    }
+
+    /** @hide */
+    @NonNull
+    static String getflushReasonAsString(@FlushReason int reason) {
+        switch (reason) {
+            case FLUSH_REASON_FULL:
+                return "FULL";
+            case FLUSH_REASON_ACTIVITY_PAUSED:
+                return "PAUSED";
+            case FLUSH_REASON_ACTIVITY_RESUMED:
+                return "RESUMED";
+            case FLUSH_REASON_SESSION_STARTED:
+                return "STARTED";
+            case FLUSH_REASON_SESSION_FINISHED:
+                return "FINISHED";
+            case FLUSH_REASON_IDLE_TIMEOUT:
+                return "IDLE";
             default:
-                return "INVALID:" + state;
+                return "UNKOWN-" + reason;
         }
     }
 }
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
index 01776f8..51aea16 100644
--- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -19,6 +19,7 @@
 import android.content.ComponentName;
 import android.view.contentcapture.ContentCaptureContext;
 import android.view.contentcapture.ContentCaptureEvent;
+import android.view.contentcapture.UserDataRemovalRequest;
 import android.os.IBinder;
 
 import com.android.internal.os.IResultReceiver;
@@ -32,7 +33,33 @@
   * @hide
   */
 oneway interface IContentCaptureManager {
+    /**
+     * Starts a new session for the provided {@code userId} running as part of the
+     * app's activity identified by {@code activityToken}/{@code componentName}.
+     *
+     * @param sessionId Unique session id as provided by the app.
+     * @param flags Meta flags that enable or disable content capture (see
+     *     {@link IContentCaptureContext#flags}).
+     */
     void startSession(int userId, IBinder activityToken, in ComponentName componentName,
                       String sessionId, int flags, in IResultReceiver result);
+
+    /**
+     * Marks the end of a session for the provided {@code userId} identified by
+     * the corresponding {@code startSession}'s {@code sessionId}.
+     */
     void finishSession(int userId, String sessionId);
+
+    /**
+     * Returns the content capture service's component name (if enabled and
+     * connected).
+     * @param Receiver of the content capture service's @{code ComponentName}
+     *     provided {@code Bundle} with key "{@code EXTRA}".
+     */
+    void getReceiverServiceComponentName(int userId, in IResultReceiver result);
+
+    /**
+     * Requests the removal of user data for the provided {@code userId}.
+     */
+    void removeUserData(int userId, in UserDataRemovalRequest request);
 }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 92e0187..9e99c88 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -20,8 +20,9 @@
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED;
-import static android.view.contentcapture.ContentCaptureManager.DEBUG;
-import static android.view.contentcapture.ContentCaptureManager.VERBOSE;
+import static android.view.contentcapture.ContentCaptureHelper.DEBUG;
+import static android.view.contentcapture.ContentCaptureHelper.VERBOSE;
+import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
@@ -35,7 +36,7 @@
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
 import android.os.RemoteException;
-import android.os.SystemClock;
+import android.util.LocalLog;
 import android.util.Log;
 import android.util.TimeUtils;
 import android.view.autofill.AutofillId;
@@ -63,6 +64,8 @@
  */
 public final class MainContentCaptureSession extends ContentCaptureSession {
 
+    private static final String TAG = MainContentCaptureSession.class.getSimpleName();
+
     /**
      * Handler message used to flush the buffer.
      */
@@ -86,6 +89,7 @@
      */
     public static final String EXTRA_BINDER = "binder";
 
+    // TODO(b/111276913): make sure disabled state is in sync with manager's disabled
     @NonNull
     private final AtomicBoolean mDisabled;
 
@@ -111,7 +115,7 @@
     @Nullable
     private DeathRecipient mDirectServiceVulture;
 
-    private int mState = STATE_UNKNOWN;
+    private int mState = UNKNWON_STATE;
 
     @Nullable
     private IBinder mApplicationToken;
@@ -128,17 +132,22 @@
     // Used just for debugging purposes (on dump)
     private long mNextFlush;
 
-    // Lazily created on demand.
-    private ContentCaptureSessionId mContentCaptureSessionId;
+    // TODO(b/121044064): use settings to set size
+    private final LocalLog mFlushHistory = new LocalLog(10);
 
     /** @hide */
     protected MainContentCaptureSession(@NonNull Context context, @NonNull Handler handler,
             @Nullable IContentCaptureManager systemServerInterface,
-            @NonNull AtomicBoolean disabled) {
+            @NonNull boolean disabled) {
         mContext = context;
         mHandler = handler;
         mSystemServerInterface = systemServerInterface;
-        mDisabled = disabled;
+        mDisabled = new AtomicBoolean(disabled);
+    }
+
+    @Override
+    MainContentCaptureSession getMainCaptureSession() {
+        return this;
     }
 
     @Override
@@ -153,34 +162,41 @@
      *
      * @hide
      */
-    void start(@NonNull IBinder applicationToken, @NonNull ComponentName activityComponent) {
+    void start(@NonNull IBinder applicationToken, @NonNull ComponentName activityComponent,
+            int flags) {
         if (!isContentCaptureEnabled()) return;
 
         if (VERBOSE) {
-            Log.v(mTag, "start(): token=" + applicationToken + ", comp="
+            Log.v(TAG, "start(): token=" + applicationToken + ", comp="
                     + ComponentName.flattenToShortString(activityComponent));
         }
 
         mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleStartSession, this,
-                applicationToken, activityComponent));
+                applicationToken, activityComponent, flags));
     }
 
     @Override
-    void flush() {
-        mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleForceFlush, this));
+    void flush(@FlushReason int reason) {
+        mHandler.sendMessage(
+                obtainMessage(MainContentCaptureSession::handleForceFlush, this, reason));
     }
 
     @Override
     void onDestroy() {
+        mHandler.removeMessages(MSG_FLUSH);
         mHandler.sendMessage(
                 obtainMessage(MainContentCaptureSession::handleDestroySession, this));
     }
 
-    private void handleStartSession(@NonNull IBinder token, @NonNull ComponentName componentName) {
-        if (mState != STATE_UNKNOWN) {
-            // TODO(b/111276913): revisit this scenario
-            Log.w(mTag, "ignoring handleStartSession(" + token + ") while on state "
-                    + getStateAsString(mState));
+    private void handleStartSession(@NonNull IBinder token, @NonNull ComponentName componentName,
+            int flags) {
+        if (handleHasStarted()) {
+            // TODO(b/122959591): make sure this is expected (and when), or use Log.w
+            if (DEBUG) {
+                Log.d(TAG, "ignoring handleStartSession(" + token + "/"
+                        + ComponentName.flattenToShortString(componentName) + " while on state "
+                        + getStateAsString(mState));
+            }
             return;
         }
         mState = STATE_WAITING_FOR_SERVER;
@@ -188,12 +204,13 @@
         mComponentName = componentName;
 
         if (VERBOSE) {
-            Log.v(mTag, "handleStartSession(): token=" + token + ", act="
-                    + getActivityDebugName() + ", id=" + mId);
+            Log.v(TAG, "handleStartSession(): token=" + token + ", act="
+                    + getDebugState() + ", id=" + mId);
         }
-        final int flags = 0; // TODO(b/111276913): get proper flags
 
         try {
+            if (mSystemServerInterface == null) return;
+
             mSystemServerInterface.startSession(mContext.getUserId(), mApplicationToken,
                     componentName, mId, flags, new IResultReceiver.Stub() {
                         @Override
@@ -202,8 +219,8 @@
                             if (resultData != null) {
                                 binder = resultData.getBinder(EXTRA_BINDER);
                                 if (binder == null) {
-                                    Log.wtf(mTag, "No " + EXTRA_BINDER + " extra result");
-                                    handleResetState();
+                                    Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result");
+                                    handleResetSession(STATE_DISABLED | STATE_INTERNAL_ERROR);
                                     return;
                                 }
                             }
@@ -211,7 +228,7 @@
                         }
                     });
         } catch (RemoteException e) {
-            Log.w(mTag, "Error starting session for " + componentName.flattenToShortString() + ": "
+            Log.w(TAG, "Error starting session for " + componentName.flattenToShortString() + ": "
                     + e);
         }
     }
@@ -219,61 +236,94 @@
     /**
      * Callback from {@code system_server} after call to
      * {@link IContentCaptureManager#startSession(int, IBinder, ComponentName, String,
-     * ContentCaptureContext, int, IResultReceiver)}.
+     * int, IResultReceiver)}.
      *
      * @param resultCode session state
      * @param binder handle to {@code IContentCaptureDirectManager}
      */
     private void handleSessionStarted(int resultCode, @Nullable IBinder binder) {
-        mState = resultCode;
         if (binder != null) {
             mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder);
             mDirectServiceVulture = () -> {
-                Log.w(mTag, "Destroying session " + mId + " because service died");
+                Log.w(TAG, "Destroying session " + mId + " because service died");
                 destroy();
             };
             try {
                 binder.linkToDeath(mDirectServiceVulture, 0);
             } catch (RemoteException e) {
-                Log.w(mTag, "Failed to link to death on " + binder + ": " + e);
+                Log.w(TAG, "Failed to link to death on " + binder + ": " + e);
             }
         }
-        if (resultCode == STATE_DISABLED || resultCode == STATE_DISABLED_DUPLICATED_ID) {
-            mDisabled.set(true);
-            handleResetSession(/* resetState= */ false);
+
+        if ((resultCode & STATE_DISABLED) != 0) {
+            handleResetSession(resultCode);
         } else {
+            mState = resultCode;
             mDisabled.set(false);
         }
         if (VERBOSE) {
-            Log.v(mTag, "handleSessionStarted() result: code=" + resultCode + ", id=" + mId
+            Log.v(TAG, "handleSessionStarted() result: id=" + mId + " resultCode=" + resultCode
                     + ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get()
-                    + ", binder=" + binder);
+                    + ", binder=" + binder + ", events=" + (mEvents == null ? 0 : mEvents.size()));
         }
     }
 
     private void handleSendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
+        final int eventType = event.getType();
+        if (VERBOSE) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event);
+        if (!handleHasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED) {
+            // TODO(b/120494182): comment when this could happen (dialogs?)
+            Log.v(TAG, "handleSendEvent(" + getDebugState() + ", "
+                    + ContentCaptureEvent.getTypeAsString(eventType)
+                    + "): session not started yet");
+            return;
+        }
+        if (mDisabled.get()) {
+            // This happens when the event was queued in the handler before the sesison was ready,
+            // then handleSessionStarted() returned and set it as disabled - we need to drop it,
+            // otherwise it will keep triggering handleScheduleFlush()
+            if (VERBOSE) Log.v(TAG, "handleSendEvent(): ignoring when disabled");
+            return;
+        }
         if (mEvents == null) {
             if (VERBOSE) {
-                Log.v(mTag, "Creating buffer for " + MAX_BUFFER_SIZE + " events");
+                Log.v(TAG, "handleSendEvent(): creating buffer for " + MAX_BUFFER_SIZE + " events");
             }
             mEvents = new ArrayList<>(MAX_BUFFER_SIZE);
         }
 
-        if (!mEvents.isEmpty() && event.getType() == TYPE_VIEW_TEXT_CHANGED) {
+        // Some type of events can be merged together
+        boolean addEvent = true;
+
+        if (!mEvents.isEmpty() && eventType == TYPE_VIEW_TEXT_CHANGED) {
             final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1);
 
             // TODO(b/121045053): check if flags match
             if (lastEvent.getType() == TYPE_VIEW_TEXT_CHANGED
                     && lastEvent.getId().equals(event.getId())) {
                 if (VERBOSE) {
-                    Log.v(mTag, "Buffering VIEW_TEXT_CHANGED event, updated text = "
-                            + event.getText());
+                    Log.v(TAG, "Buffering VIEW_TEXT_CHANGED event, updated text="
+                            + getSanitizedString(event.getText()));
                 }
                 lastEvent.setText(event.getText());
-            } else {
-                mEvents.add(event);
+                addEvent = false;
             }
-        } else {
+        }
+
+        if (!mEvents.isEmpty() && eventType == TYPE_VIEW_DISAPPEARED) {
+            final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1);
+            if (lastEvent.getType() == TYPE_VIEW_DISAPPEARED
+                    && event.getSessionId().equals(lastEvent.getSessionId())) {
+                if (VERBOSE) {
+                    Log.v(TAG, "Buffering TYPE_VIEW_DISAPPEARED events for session "
+                            + lastEvent.getSessionId());
+                }
+                lastEvent.addAutofillId(event.getId());
+                addEvent = false;
+            }
+        }
+
+        if (addEvent) {
             mEvents.add(event);
         }
 
@@ -282,74 +332,119 @@
         final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE;
 
         if (bufferEvent && !forceFlush) {
-            handleScheduleFlush(/* checkExisting= */ true);
+            handleScheduleFlush(FLUSH_REASON_IDLE_TIMEOUT, /* checkExisting= */ true);
             return;
         }
 
-        if (mState != STATE_ACTIVE) {
+        if (mState != STATE_ACTIVE && numberEvents >= MAX_BUFFER_SIZE) {
             // Callback from startSession hasn't been called yet - typically happens on system
             // apps that are started before the system service
-            // TODO(b/111276913): try to ignore session while system is not ready / boot
+            // TODO(b/122959591): try to ignore session while system is not ready / boot
             // not complete instead. Similarly, the manager service should return right away
             // when the user does not have a service set
-            if (VERBOSE) {
-                Log.v(mTag, "Closing session for " + getActivityDebugName()
-                        + " after " + numberEvents + " delayed events and state "
-                        + getStateAsString(mState));
+            if (DEBUG) {
+                Log.d(TAG, "Closing session for " + getDebugState()
+                        + " after " + numberEvents + " delayed events");
             }
-            handleResetState();
+            handleResetSession(STATE_DISABLED | STATE_NO_RESPONSE);
             // TODO(b/111276913): blacklist activity / use special flag to indicate that
             // when it's launched again
             return;
         }
+        final int flushReason;
+        switch (eventType) {
+            case ContentCaptureEvent.TYPE_SESSION_STARTED:
+                flushReason = FLUSH_REASON_SESSION_STARTED;
+                break;
+            case ContentCaptureEvent.TYPE_SESSION_FINISHED:
+                flushReason = FLUSH_REASON_SESSION_FINISHED;
+                break;
+            default:
+                flushReason = FLUSH_REASON_FULL;
+        }
 
-        handleForceFlush();
+        handleForceFlush(flushReason);
     }
 
-    private void handleScheduleFlush(boolean checkExisting) {
+    private boolean handleHasStarted() {
+        return mState != UNKNWON_STATE;
+    }
+
+    private void handleScheduleFlush(@FlushReason int reason, boolean checkExisting) {
+        if (VERBOSE) {
+            Log.v(TAG, "handleScheduleFlush(" + getDebugState(reason)
+                    + ", checkExisting=" + checkExisting);
+        }
+        if (!handleHasStarted()) {
+            if (VERBOSE) Log.v(TAG, "handleScheduleFlush(): session not started yet");
+            return;
+        }
+
+        if (mDisabled.get()) {
+            // Should not be called on this state, as handleSendEvent checks.
+            // But we rather add one if check and log than re-schedule and keep the session alive...
+            Log.e(TAG, "handleScheduleFlush(" + getDebugState(reason) + "): should not be called "
+                    + "when disabled. events=" + (mEvents == null ? null : mEvents.size()));
+            return;
+        }
         if (checkExisting && mHandler.hasMessages(MSG_FLUSH)) {
             // "Renew" the flush message by removing the previous one
             mHandler.removeMessages(MSG_FLUSH);
         }
-        mNextFlush = SystemClock.elapsedRealtime() + FLUSHING_FREQUENCY_MS;
+        mNextFlush = System.currentTimeMillis() + FLUSHING_FREQUENCY_MS;
         if (VERBOSE) {
-            Log.v(mTag, "Scheduled to flush in " + FLUSHING_FREQUENCY_MS + "ms: " + mNextFlush);
+            Log.v(TAG, "handleScheduleFlush(): scheduled to flush in "
+                    + FLUSHING_FREQUENCY_MS + "ms: " + TimeUtils.logTimeOfDay(mNextFlush));
         }
         mHandler.sendMessageDelayed(
-                obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this)
+                obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this, reason)
                 .setWhat(MSG_FLUSH), FLUSHING_FREQUENCY_MS);
     }
 
-    private void handleFlushIfNeeded() {
+    private void handleFlushIfNeeded(@FlushReason int reason) {
         if (mEvents.isEmpty()) {
-            if (VERBOSE) Log.v(mTag, "Nothing to flush");
+            if (VERBOSE) Log.v(TAG, "Nothing to flush");
             return;
         }
-        handleForceFlush();
+        handleForceFlush(reason);
     }
 
-    private void handleForceFlush() {
+    private void handleForceFlush(@FlushReason int reason) {
         if (mEvents == null) return;
 
+        if (mDisabled.get()) {
+            Log.e(TAG, "handleForceFlush(" + getDebugState(reason) + "): should not be when "
+                    + "disabled");
+            return;
+        }
+
         if (mDirectServiceInterface == null) {
-            if (DEBUG) Log.d(mTag, "handleForceFlush(): hold your horses, client not ready yet!");
+            if (VERBOSE) {
+                Log.v(TAG, "handleForceFlush(" + getDebugState(reason) + "): hold your horses, "
+                        + "client not ready: " + mEvents);
+            }
             if (!mHandler.hasMessages(MSG_FLUSH)) {
-                handleScheduleFlush(/* checkExisting= */ false);
+                handleScheduleFlush(reason, /* checkExisting= */ false);
             }
             return;
         }
 
         final int numberEvents = mEvents.size();
+        final String reasonString = getflushReasonAsString(reason);
+        if (DEBUG) {
+            Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState(reason));
+        }
+        // Logs reason, size, max size, idle timeout
+        final String logRecord = "r=" + reasonString + " s=" + numberEvents
+                + " m=" + MAX_BUFFER_SIZE + " i=" + FLUSHING_FREQUENCY_MS;
         try {
-            if (DEBUG) {
-                Log.d(mTag, "Flushing " + numberEvents + " event(s) for " + getActivityDebugName());
-            }
+            mFlushHistory.log(logRecord);
             mHandler.removeMessages(MSG_FLUSH);
 
             final ParceledListSlice<ContentCaptureEvent> events = handleClearEvents();
             mDirectServiceInterface.sendEvents(events);
         } catch (RemoteException e) {
-            Log.w(mTag, "Error sending " + numberEvents + " for " + getActivityDebugName()
+            Log.w(TAG, "Error sending " + numberEvents + " for " + getDebugState()
                     + ": " + e);
         }
     }
@@ -370,33 +465,31 @@
 
     private void handleDestroySession() {
         if (DEBUG) {
-            Log.d(mTag, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
+            Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
                     + (mEvents == null ? 0 : mEvents.size()) + " event(s) for "
-                    + getActivityDebugName());
+                    + getDebugState());
         }
 
         try {
+            if (mSystemServerInterface == null) return;
+
             mSystemServerInterface.finishSession(mContext.getUserId(), mId);
         } catch (RemoteException e) {
-            Log.e(mTag, "Error destroying system-service session " + mId + " for "
-                    + getActivityDebugName() + ": " + e);
+            Log.e(TAG, "Error destroying system-service session " + mId + " for "
+                    + getDebugState() + ": " + e);
         }
     }
 
-    private void handleResetState() {
-        handleResetSession(/* resetState= */ true);
-    }
-
-    // TODO(b/121033016): once we support multiple sessions, we might need to move some of these
+    // TODO(b/122454205): once we support multiple sessions, we might need to move some of these
     // clearings out.
-    private void handleResetSession(boolean resetState) {
-        if (resetState) {
-            mState = STATE_UNKNOWN;
+    private void handleResetSession(int newState) {
+        if (VERBOSE) {
+            Log.v(TAG, "handleResetSession(" + getActivityName() + "): from "
+                    + getStateAsString(mState) + " to " + getStateAsString(newState));
         }
-
-        // TODO(b/121033016): must reset children (which currently is owned by superclass)
-
-        mContentCaptureSessionId = null;
+        mState = newState;
+        mDisabled.set((newState & STATE_DISABLED) != 0);
+        // TODO(b/122454205): must reset children (which currently is owned by superclass)
         mApplicationToken = null;
         mComponentName = null;
         mEvents = null;
@@ -418,17 +511,17 @@
     }
 
     @Override
-    void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
-            int flags) {
-        notifyViewTextChanged(mId, id, text, flags);
+    void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text) {
+        notifyViewTextChanged(mId, id, text);
     }
 
     @Override
     boolean isContentCaptureEnabled() {
-        return mSystemServerInterface != null && !mDisabled.get();
+        return super.isContentCaptureEnabled() && mSystemServerInterface != null
+                && !mDisabled.get();
     }
 
-    // TODO(b/121033016): refactor "notifyXXXX" methods below to a common "Buffer" object that is
+    // TODO(b/122454205): refactor "notifyXXXX" methods below to a common "Buffer" object that is
     // shared between ActivityContentCaptureSession and ChildContentCaptureSession objects. Such
     // change should also get get rid of the "internalNotifyXXXX" methods above
     void notifyChildSessionStarted(@NonNull String parentSessionId,
@@ -437,14 +530,14 @@
                 new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
                         .setParentSessionId(parentSessionId)
                         .setClientContext(clientContext),
-                        /* forceFlush= */ false));
+                        /* forceFlush= */ true));
     }
 
     void notifyChildSessionFinished(@NonNull String parentSessionId,
             @NonNull String childSessionId) {
         mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this,
                 new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
-                        .setParentSessionId(parentSessionId), /* forceFlush= */ false));
+                        .setParentSessionId(parentSessionId), /* forceFlush= */ true));
     }
 
     void notifyViewAppeared(@NonNull String sessionId, @NonNull ViewStructureImpl node) {
@@ -460,15 +553,14 @@
     }
 
     void notifyViewTextChanged(@NonNull String sessionId, @NonNull AutofillId id,
-            @Nullable CharSequence text, int flags) {
+            @Nullable CharSequence text) {
         mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleSendEvent, this,
-                new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED, flags).setAutofillId(id)
+                new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED).setAutofillId(id)
                         .setText(text), /* forceFlush= */ false));
     }
 
     @Override
     void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
-        pw.print(prefix); pw.print("id: "); pw.println(mId);
         pw.print(prefix); pw.print("mContext: "); pw.println(mContext);
         pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId());
         if (mSystemServerInterface != null) {
@@ -481,11 +573,7 @@
         }
         pw.print(prefix); pw.print("mDisabled: "); pw.println(mDisabled.get());
         pw.print(prefix); pw.print("isEnabled(): "); pw.println(isContentCaptureEnabled());
-        if (mContentCaptureSessionId != null) {
-            pw.print(prefix); pw.print("public id: "); pw.println(mContentCaptureSessionId);
-        }
-        pw.print(prefix); pw.print("state: "); pw.print(mState); pw.print(" (");
-        pw.print(getStateAsString(mState)); pw.println(")");
+        pw.print(prefix); pw.print("state: "); pw.println(getStateAsString(mState));
         if (mApplicationToken != null) {
             pw.print(prefix); pw.print("app token: "); pw.println(mApplicationToken);
         }
@@ -507,16 +595,32 @@
             }
             pw.print(prefix); pw.print("flush frequency: "); pw.println(FLUSHING_FREQUENCY_MS);
             pw.print(prefix); pw.print("next flush: ");
-            TimeUtils.formatDuration(mNextFlush - SystemClock.elapsedRealtime(), pw); pw.println();
+            TimeUtils.formatDuration(mNextFlush - System.currentTimeMillis(), pw);
+            pw.print(" ("); pw.print(TimeUtils.logTimeOfDay(mNextFlush)); pw.println(")");
         }
+        pw.print(prefix); pw.println("flush history:");
+        mFlushHistory.reverseDump(/* fd= */ null, pw, /* args= */ null); pw.println();
+
         super.dump(prefix, pw);
     }
 
     /**
      * Gets a string that can be used to identify the activity on logging statements.
      */
-    private String getActivityDebugName() {
-        return mComponentName == null ? mContext.getPackageName()
-                : mComponentName.flattenToShortString();
+    private String getActivityName() {
+        return mComponentName == null
+                ? "pkg:" + mContext.getPackageName()
+                : "act:" + mComponentName.flattenToShortString();
+    }
+
+    @NonNull
+    private String getDebugState() {
+        return getActivityName() + " [state=" + getStateAsString(mState) + ", disabled="
+                + mDisabled.get() + "]";
+    }
+
+    @NonNull
+    private String getDebugState(@FlushReason int reason) {
+        return getDebugState() + ", reason=" + getflushReasonAsString(reason);
     }
 }
diff --git a/core/java/android/view/contentcapture/UserDataRemovalRequest.aidl b/core/java/android/view/contentcapture/UserDataRemovalRequest.aidl
new file mode 100644
index 0000000..fbe47e0
--- /dev/null
+++ b/core/java/android/view/contentcapture/UserDataRemovalRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.contentcapture;
+
+parcelable UserDataRemovalRequest;
diff --git a/core/java/android/view/contentcapture/UserDataRemovalRequest.java b/core/java/android/view/contentcapture/UserDataRemovalRequest.java
index 0261b70..8ee63ef 100644
--- a/core/java/android/view/contentcapture/UserDataRemovalRequest.java
+++ b/core/java/android/view/contentcapture/UserDataRemovalRequest.java
@@ -17,10 +17,15 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.app.ActivityThread;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.IntArray;
 
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -29,8 +34,35 @@
  */
 public final class UserDataRemovalRequest implements Parcelable {
 
-    private UserDataRemovalRequest(Builder builder) {
-        // TODO(b/111276913): implement
+    private final String mPackageName;
+
+    private final boolean mForEverything;
+    private ArrayList<UriRequest> mUriRequests;
+
+    private UserDataRemovalRequest(@NonNull Builder builder) {
+        mPackageName = ActivityThread.currentActivityThread().getApplication().getPackageName();
+        mForEverything = builder.mForEverything;
+        if (builder.mUris != null) {
+            final int size = builder.mUris.size();
+            mUriRequests = new ArrayList<>(size);
+            for (int i = 0; i < size; i++) {
+                mUriRequests.add(new UriRequest(builder.mUris.get(i),
+                        builder.mRecursive.get(i) == 1));
+            }
+        }
+    }
+
+    private UserDataRemovalRequest(@NonNull Parcel parcel) {
+        mPackageName = parcel.readString();
+        mForEverything = parcel.readBoolean();
+        if (!mForEverything) {
+            final int size = parcel.readInt();
+            mUriRequests = new ArrayList<>(size);
+            for (int i = 0; i < size; i++) {
+                mUriRequests.add(new UriRequest((Uri) parcel.readValue(null),
+                        parcel.readBoolean()));
+            }
+        }
     }
 
     /**
@@ -40,9 +72,7 @@
     @SystemApi
     @NonNull
     public String getPackageName() {
-        // TODO(b/111276913): implement
-        // TODO(b/111276913): make sure it's set on system_service so it cannot be faked by app
-        return null;
+        return mPackageName;
     }
 
     /**
@@ -52,8 +82,7 @@
      */
     @SystemApi
     public boolean isForEverything() {
-        // TODO(b/111276913): implement
-        return false;
+        return mForEverything;
     }
 
     /**
@@ -64,8 +93,7 @@
     @SystemApi
     @NonNull
     public List<UriRequest> getUriRequests() {
-        // TODO(b/111276913): implement
-        return null;
+        return mUriRequests;
     }
 
     /**
@@ -73,6 +101,12 @@
      */
     public static final class Builder {
 
+        private boolean mForEverything;
+        private ArrayList<Uri> mUris;
+        private IntArray mRecursive;
+
+        private boolean mDestroyed;
+
         /**
          * Requests servive to remove all user data associated with the app's package.
          *
@@ -80,7 +114,12 @@
          */
         @NonNull
         public Builder forEverything() {
-            // TODO(b/111276913): implement
+            throwIfDestroyed();
+            if (mUris != null) {
+                throw new IllegalStateException("Already added Uris");
+            }
+
+            mForEverything = true;
             return this;
         }
 
@@ -94,7 +133,19 @@
          * @return this builder
          */
         public Builder addUri(@NonNull Uri uri, boolean recursive) {
-            // TODO(b/111276913): implement
+            throwIfDestroyed();
+            if (mForEverything) {
+                throw new IllegalStateException("Already is for everything");
+            }
+            Preconditions.checkNotNull(uri);
+
+            if (mUris == null) {
+                mUris = new ArrayList<>();
+                mRecursive = new IntArray();
+            }
+
+            mUris.add(uri);
+            mRecursive.add(recursive ? 1 : 0);
             return this;
         }
 
@@ -103,8 +154,16 @@
          */
         @NonNull
         public UserDataRemovalRequest build() {
-            // TODO(b/111276913): implement / unit test / check built / document exceptions
-            return null;
+            throwIfDestroyed();
+
+            Preconditions.checkState(mForEverything || mUris != null);
+
+            mDestroyed = true;
+            return new UserDataRemovalRequest(this);
+        }
+
+        private void throwIfDestroyed() {
+            Preconditions.checkState(!mDestroyed, "Already destroyed!");
         }
     }
 
@@ -115,7 +174,17 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        // TODO(b/111276913): implement
+        parcel.writeString(mPackageName);
+        parcel.writeBoolean(mForEverything);
+        if (!mForEverything) {
+            final int size = mUriRequests.size();
+            parcel.writeInt(size);
+            for (int i = 0; i < size; i++) {
+                final UriRequest request = mUriRequests.get(i);
+                parcel.writeValue(request.getUri());
+                parcel.writeBoolean(request.isRecursive());
+            }
+        }
     }
 
     public static final Parcelable.Creator<UserDataRemovalRequest> CREATOR =
@@ -123,8 +192,7 @@
 
         @Override
         public UserDataRemovalRequest createFromParcel(Parcel parcel) {
-            // TODO(b/111276913): implement
-            return null;
+            return new UserDataRemovalRequest(parcel);
         }
 
         @Override
diff --git a/core/java/android/view/contentcapture/ViewNode.java b/core/java/android/view/contentcapture/ViewNode.java
index 86b89adb..0cabafa 100644
--- a/core/java/android/view/contentcapture/ViewNode.java
+++ b/core/java/android/view/contentcapture/ViewNode.java
@@ -24,6 +24,7 @@
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewParent;
@@ -32,30 +33,169 @@
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
-//TODO(b/111276913): add javadocs / implement Parcelable / implement
-//TODO(b/111276913): for now it's extending ViewNode directly as it needs most of its properties,
+//TODO(b/122484602): add javadocs / implement Parcelable / implement
+//TODO(b/122484602): for now it's extending ViewNode directly as it needs most of its properties,
 // but it might be better to create a common, abstract android.view.ViewNode class that both extend
 // instead
 /** @hide */
 @SystemApi
 public final class ViewNode extends AssistStructure.ViewNode {
 
-    private static final String TAG = "ViewNode";
+    private static final String TAG = ViewNode.class.getSimpleName();
+
+    private static final long FLAGS_HAS_TEXT = 1L << 0;
+    private static final long FLAGS_HAS_COMPLEX_TEXT = 1L << 1;
+    private static final long FLAGS_VISIBILITY_MASK = View.VISIBLE | View.INVISIBLE | View.GONE;
+    private static final long FLAGS_HAS_CLASSNAME = 1L << 4;
+    private static final long FLAGS_HAS_AUTOFILL_ID = 1L << 5;
+    private static final long FLAGS_HAS_AUTOFILL_PARENT_ID = 1L << 6;
+    private static final long FLAGS_HAS_ID = 1L << 7;
+    private static final long FLAGS_HAS_LARGE_COORDS = 1L << 8;
+    private static final long FLAGS_HAS_SCROLL = 1L << 9;
+    private static final long FLAGS_ASSIST_BLOCKED = 1L << 10;
+    private static final long FLAGS_DISABLED = 1L << 11;
+    private static final long FLAGS_CLICKABLE = 1L << 12;
+    private static final long FLAGS_LONG_CLICKABLE = 1L << 13;
+    private static final long FLAGS_CONTEXT_CLICKABLE = 1L << 14;
+    private static final long FLAGS_FOCUSABLE = 1L << 15;
+    private static final long FLAGS_FOCUSED = 1L << 16;
+    private static final long FLAGS_ACCESSIBILITY_FOCUSED = 1L << 17;
+    private static final long FLAGS_CHECKABLE = 1L << 18;
+    private static final long FLAGS_CHECKED = 1L << 19;
+    private static final long FLAGS_SELECTED = 1L << 20;
+    private static final long FLAGS_ACTIVATED = 1L << 21;
+    private static final long FLAGS_OPAQUE = 1L << 22;
+    private static final long FLAGS_HAS_CONTENT_DESCRIPTION = 1L << 23;
+    private static final long FLAGS_HAS_EXTRAS = 1L << 24;
+    private static final long FLAGS_HAS_LOCALE_LIST = 1L << 25;
+    private static final long FLAGS_HAS_INPUT_TYPE = 1L << 26;
+    private static final long FLAGS_HAS_MIN_TEXT_EMS = 1L << 27;
+    private static final long FLAGS_HAS_MAX_TEXT_EMS = 1L << 28;
+    private static final long FLAGS_HAS_MAX_TEXT_LENGTH = 1L << 29;
+    private static final long FLAGS_HAS_TEXT_ID_ENTRY = 1L << 30;
+    private static final long FLAGS_HAS_AUTOFILL_TYPE = 1L << 31;
+    private static final long FLAGS_HAS_AUTOFILL_VALUE = 1L << 32;
+    private static final long FLAGS_HAS_AUTOFILL_HINTS = 1L << 33;
+    private static final long FLAGS_HAS_AUTOFILL_OPTIONS = 1L << 34;
+
+    /** Flags used to optimize what's written to the parcel */
+    private long mFlags;
 
     private AutofillId mParentAutofillId;
 
-    // TODO(b/111276913): temporarily setting some fields here while they're not accessible from the
-    // superclass
     private AutofillId mAutofillId;
-    private CharSequence mText;
+    private ViewNodeText mText;
     private String mClassName;
+    private int mId = View.NO_ID;
+    private String mIdPackage;
+    private String mIdType;
+    private String mIdEntry;
+    private int mX;
+    private int mY;
+    private int mScrollX;
+    private int mScrollY;
+    private int mWidth;
+    private int mHeight;
+    private CharSequence mContentDescription;
+    private Bundle mExtras;
+    private LocaleList mLocaleList;
+    private int mInputType;
+    private int mMinEms = -1;
+    private int mMaxEms = -1;
+    private int mMaxLength = -1;
+    private String mTextIdEntry;
+    private @View.AutofillType int mAutofillType = View.AUTOFILL_TYPE_NONE;
+    private String[] mAutofillHints;
+    private AutofillValue mAutofillValue;
+    private CharSequence[] mAutofillOptions;
 
     /** @hide */
     public ViewNode() {
     }
 
+    private ViewNode(long nodeFlags, @NonNull Parcel parcel) {
+        mFlags = nodeFlags;
+
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_ID) != 0) {
+            mAutofillId = parcel.readParcelable(null);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_PARENT_ID) != 0) {
+            mParentAutofillId = parcel.readParcelable(null);
+        }
+        if ((nodeFlags & FLAGS_HAS_TEXT) != 0) {
+            mText = new ViewNodeText(parcel, (nodeFlags & FLAGS_HAS_COMPLEX_TEXT) == 0);
+        }
+        if ((nodeFlags & FLAGS_HAS_CLASSNAME) != 0) {
+            mClassName = parcel.readString();
+        }
+        if ((nodeFlags & FLAGS_HAS_ID) != 0) {
+            mId = parcel.readInt();
+            if (mId != View.NO_ID) {
+                mIdEntry = parcel.readString();
+                if (mIdEntry != null) {
+                    mIdType = parcel.readString();
+                    mIdPackage = parcel.readString();
+                }
+            }
+        }
+        if ((nodeFlags & FLAGS_HAS_LARGE_COORDS) != 0) {
+            mX = parcel.readInt();
+            mY = parcel.readInt();
+            mWidth = parcel.readInt();
+            mHeight = parcel.readInt();
+        } else {
+            int val = parcel.readInt();
+            mX = val & 0x7fff;
+            mY = (val >> 16) & 0x7fff;
+            val = parcel.readInt();
+            mWidth = val & 0x7fff;
+            mHeight = (val >> 16) & 0x7fff;
+        }
+        if ((nodeFlags & FLAGS_HAS_SCROLL) != 0) {
+            mScrollX = parcel.readInt();
+            mScrollY = parcel.readInt();
+        }
+        if ((nodeFlags & FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
+            mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+        }
+        if ((nodeFlags & FLAGS_HAS_EXTRAS) != 0) {
+            mExtras = parcel.readBundle();
+        }
+        if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) {
+            mLocaleList = parcel.readParcelable(null);
+        }
+        if ((nodeFlags & FLAGS_HAS_INPUT_TYPE) != 0) {
+            mInputType = parcel.readInt();
+        }
+        if ((nodeFlags & FLAGS_HAS_MIN_TEXT_EMS) != 0) {
+            mMinEms = parcel.readInt();
+        }
+        if ((nodeFlags & FLAGS_HAS_MAX_TEXT_EMS) != 0) {
+            mMaxEms = parcel.readInt();
+        }
+        if ((nodeFlags & FLAGS_HAS_MAX_TEXT_LENGTH) != 0) {
+            mMaxLength = parcel.readInt();
+        }
+        if ((nodeFlags & FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
+            mTextIdEntry = parcel.readString();
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_TYPE) != 0) {
+            mAutofillType = parcel.readInt();
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_HINTS) != 0) {
+            mAutofillHints = parcel.readStringArray();
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_VALUE) != 0) {
+            mAutofillValue = parcel.readParcelable(null);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
+            mAutofillOptions = parcel.readCharSequenceArray();
+        }
+    }
+
     /**
      * Returns the {@link AutofillId} of this view's parent, if the parent is also part of the
      * screen observation tree.
@@ -65,53 +205,410 @@
         return mParentAutofillId;
     }
 
-    // TODO(b/111276913): temporarily overwriting some methods
     @Override
     public AutofillId getAutofillId() {
         return mAutofillId;
     }
+
     @Override
     public CharSequence getText() {
-        return mText;
+        return mText != null ? mText.mText : null;
     }
+
     @Override
     public String getClassName() {
         return mClassName;
     }
 
+    @Override
+    public int getId() {
+        return mId;
+    }
+
+    @Override
+    public String getIdPackage() {
+        return mIdPackage;
+    }
+
+    @Override
+    public String getIdType() {
+        return mIdType;
+    }
+
+    @Override
+    public String getIdEntry() {
+        return mIdEntry;
+    }
+
+    @Override
+    public int getLeft() {
+        return mX;
+    }
+
+    @Override
+    public int getTop() {
+        return mY;
+    }
+
+    @Override
+    public int getScrollX() {
+        return mScrollX;
+    }
+
+    @Override
+    public int getScrollY() {
+        return mScrollY;
+    }
+
+    @Override
+    public int getWidth() {
+        return mWidth;
+    }
+
+    @Override
+    public int getHeight() {
+        return mHeight;
+    }
+
+    @Override
+    public boolean isAssistBlocked() {
+        return (mFlags & FLAGS_ASSIST_BLOCKED) != 0;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return (mFlags & FLAGS_DISABLED) == 0;
+    }
+
+    @Override
+    public boolean isClickable() {
+        return (mFlags & FLAGS_CLICKABLE) != 0;
+    }
+
+    @Override
+    public boolean isLongClickable() {
+        return (mFlags & FLAGS_LONG_CLICKABLE) != 0;
+    }
+
+    @Override
+    public boolean isContextClickable() {
+        return (mFlags & FLAGS_CONTEXT_CLICKABLE) != 0;
+    }
+
+    @Override
+    public boolean isFocusable() {
+        return (mFlags & FLAGS_FOCUSABLE) != 0;
+    }
+
+    @Override
+    public boolean isFocused() {
+        return (mFlags & FLAGS_FOCUSED) != 0;
+    }
+
+    @Override
+    public boolean isAccessibilityFocused() {
+        return (mFlags & FLAGS_ACCESSIBILITY_FOCUSED) != 0;
+    }
+
+    @Override
+    public boolean isCheckable() {
+        return (mFlags & FLAGS_CHECKABLE) != 0;
+    }
+
+    @Override
+    public boolean isChecked() {
+        return (mFlags & FLAGS_CHECKED) != 0;
+    }
+
+    @Override
+    public boolean isSelected() {
+        return (mFlags & FLAGS_SELECTED) != 0;
+    }
+
+    @Override
+    public boolean isActivated() {
+        return (mFlags & FLAGS_ACTIVATED) != 0;
+    }
+
+    @Override
+    public boolean isOpaque() {
+        return (mFlags & FLAGS_OPAQUE) != 0;
+    }
+
+    @Override
+    public CharSequence getContentDescription() {
+        return mContentDescription;
+    }
+
+    @Override
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public String getHint() {
+        return mText != null ? mText.mHint : null;
+    }
+
+    @Override
+    public int getTextSelectionStart() {
+        return mText != null ? mText.mTextSelectionStart : -1;
+    }
+
+    @Override
+    public int getTextSelectionEnd() {
+        return mText != null ? mText.mTextSelectionEnd : -1;
+    }
+
+    @Override
+    public int getTextColor() {
+        return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED;
+    }
+
+    @Override
+    public int getTextBackgroundColor() {
+        return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
+    }
+
+    @Override
+    public float getTextSize() {
+        return mText != null ? mText.mTextSize : 0;
+    }
+
+    @Override
+    public int getTextStyle() {
+        return mText != null ? mText.mTextStyle : 0;
+    }
+
+    @Override
+    public int[] getTextLineCharOffsets() {
+        return mText != null ? mText.mLineCharOffsets : null;
+    }
+
+    @Override
+    public int[] getTextLineBaselines() {
+        return mText != null ? mText.mLineBaselines : null;
+    }
+
+    @Override
+    public int getVisibility() {
+        return (int) (mFlags & FLAGS_VISIBILITY_MASK);
+    }
+
+    @Override
+    public int getInputType() {
+        return mInputType;
+    }
+
+    @Override
+    public int getMinTextEms() {
+        return mMinEms;
+    }
+
+    @Override
+    public int getMaxTextEms() {
+        return mMaxEms;
+    }
+
+    @Override
+    public int getMaxTextLength() {
+        return mMaxLength;
+    }
+
+    @Override
+    public String getTextIdEntry() {
+        return mTextIdEntry;
+    }
+
+    @Override
+    public @View.AutofillType int getAutofillType() {
+        return mAutofillType;
+    }
+
+    @Override
+    @Nullable public String[] getAutofillHints() {
+        return mAutofillHints;
+    }
+
+    @Override
+    @Nullable public AutofillValue getAutofillValue() {
+        return mAutofillValue;
+    }
+
+    @Override
+    @Nullable public CharSequence[] getAutofillOptions() {
+        return mAutofillOptions;
+    }
+
+    @Override
+    public LocaleList getLocaleList() {
+        return mLocaleList;
+    }
+
+    private void writeSelfToParcel(@NonNull Parcel parcel, int parcelFlags) {
+        long nodeFlags = mFlags;
+
+        if (mAutofillId != null) {
+            nodeFlags |= FLAGS_HAS_AUTOFILL_ID;
+        }
+
+        if (mParentAutofillId != null) {
+            nodeFlags |= FLAGS_HAS_AUTOFILL_PARENT_ID;
+        }
+
+        if (mText != null) {
+            nodeFlags |= FLAGS_HAS_TEXT;
+            if (!mText.isSimple()) {
+                nodeFlags |= FLAGS_HAS_COMPLEX_TEXT;
+            }
+        }
+        if (mClassName != null) {
+            nodeFlags |= FLAGS_HAS_CLASSNAME;
+        }
+        if (mId != View.NO_ID) {
+            nodeFlags |= FLAGS_HAS_ID;
+        }
+        if ((mX & ~0x7fff) != 0 || (mY & ~0x7fff) != 0
+                || (mWidth & ~0x7fff) != 0 | (mHeight & ~0x7fff) != 0) {
+            nodeFlags |= FLAGS_HAS_LARGE_COORDS;
+        }
+        if (mScrollX != 0 || mScrollY != 0) {
+            nodeFlags |= FLAGS_HAS_SCROLL;
+        }
+        if (mContentDescription != null) {
+            nodeFlags |= FLAGS_HAS_CONTENT_DESCRIPTION;
+        }
+        if (mExtras != null) {
+            nodeFlags |= FLAGS_HAS_EXTRAS;
+        }
+        if (mLocaleList != null) {
+            nodeFlags |= FLAGS_HAS_LOCALE_LIST;
+        }
+        if (mInputType != 0) {
+            nodeFlags |= FLAGS_HAS_INPUT_TYPE;
+        }
+        if (mMinEms > -1) {
+            nodeFlags |= FLAGS_HAS_MIN_TEXT_EMS;
+        }
+        if (mMaxEms > -1) {
+            nodeFlags |= FLAGS_HAS_MAX_TEXT_EMS;
+        }
+        if (mMaxLength > -1) {
+            nodeFlags |= FLAGS_HAS_MAX_TEXT_LENGTH;
+        }
+        if (mTextIdEntry != null) {
+            nodeFlags |= FLAGS_HAS_TEXT_ID_ENTRY;
+        }
+        if (mAutofillValue != null) {
+            nodeFlags |= FLAGS_HAS_AUTOFILL_VALUE;
+        }
+        if (mAutofillType != View.AUTOFILL_TYPE_NONE) {
+            nodeFlags |= FLAGS_HAS_AUTOFILL_TYPE;
+        }
+        if (mAutofillHints != null) {
+            nodeFlags |= FLAGS_HAS_AUTOFILL_HINTS;
+        }
+        if (mAutofillOptions != null) {
+            nodeFlags |= FLAGS_HAS_AUTOFILL_OPTIONS;
+        }
+        parcel.writeLong(nodeFlags);
+
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_ID) != 0) {
+            parcel.writeParcelable(mAutofillId, parcelFlags);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_PARENT_ID) != 0) {
+            parcel.writeParcelable(mParentAutofillId, parcelFlags);
+        }
+        if ((nodeFlags & FLAGS_HAS_TEXT) != 0) {
+            mText.writeToParcel(parcel, (nodeFlags & FLAGS_HAS_COMPLEX_TEXT) == 0);
+        }
+        if ((nodeFlags & FLAGS_HAS_CLASSNAME) != 0) {
+            parcel.writeString(mClassName);
+        }
+        if ((nodeFlags & FLAGS_HAS_ID) != 0) {
+            parcel.writeInt(mId);
+            if (mId != View.NO_ID) {
+                parcel.writeString(mIdEntry);
+                if (mIdEntry != null) {
+                    parcel.writeString(mIdType);
+                    parcel.writeString(mIdPackage);
+                }
+            }
+        }
+        if ((nodeFlags & FLAGS_HAS_LARGE_COORDS) != 0) {
+            parcel.writeInt(mX);
+            parcel.writeInt(mY);
+            parcel.writeInt(mWidth);
+            parcel.writeInt(mHeight);
+        } else {
+            parcel.writeInt((mY << 16) | mX);
+            parcel.writeInt((mHeight << 16) | mWidth);
+        }
+        if ((nodeFlags & FLAGS_HAS_SCROLL) != 0) {
+            parcel.writeInt(mScrollX);
+            parcel.writeInt(mScrollY);
+        }
+        if ((nodeFlags & FLAGS_HAS_CONTENT_DESCRIPTION) != 0) {
+            TextUtils.writeToParcel(mContentDescription, parcel, 0);
+        }
+        if ((nodeFlags & FLAGS_HAS_EXTRAS) != 0) {
+            parcel.writeBundle(mExtras);
+        }
+        if ((nodeFlags & FLAGS_HAS_LOCALE_LIST) != 0) {
+            parcel.writeParcelable(mLocaleList, 0);
+        }
+        if ((nodeFlags & FLAGS_HAS_INPUT_TYPE) != 0) {
+            parcel.writeInt(mInputType);
+        }
+        if ((nodeFlags & FLAGS_HAS_MIN_TEXT_EMS) != 0) {
+            parcel.writeInt(mMinEms);
+        }
+        if ((nodeFlags & FLAGS_HAS_MAX_TEXT_EMS) != 0) {
+            parcel.writeInt(mMaxEms);
+        }
+        if ((nodeFlags & FLAGS_HAS_MAX_TEXT_LENGTH) != 0) {
+            parcel.writeInt(mMaxLength);
+        }
+        if ((nodeFlags & FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
+            parcel.writeString(mTextIdEntry);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_TYPE) != 0) {
+            parcel.writeInt(mAutofillType);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_HINTS) != 0) {
+            parcel.writeStringArray(mAutofillHints);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_VALUE) != 0) {
+            parcel.writeParcelable(mAutofillValue, 0);
+        }
+        if ((nodeFlags & FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
+            parcel.writeCharSequenceArray(mAutofillOptions);
+        }
+    }
+
     /** @hide */
     public static void writeToParcel(@NonNull Parcel parcel, @Nullable ViewNode node, int flags) {
         if (node == null) {
-            parcel.writeParcelable(null, flags);
-            return;
+            parcel.writeLong(0);
+        } else {
+            node.writeSelfToParcel(parcel, flags);
         }
-        parcel.writeParcelable(node.mAutofillId, flags);
-        parcel.writeParcelable(node.mParentAutofillId, flags);
-        parcel.writeCharSequence(node.mText);
-        parcel.writeString(node.mClassName);
     }
 
     /** @hide */
     public static @Nullable ViewNode readFromParcel(@NonNull Parcel parcel) {
-        final AutofillId id = parcel.readParcelable(null);
-        if (id == null) return null;
-
-        final ViewNode node = new ViewNode();
-
-        node.mAutofillId = id;
-        node.mParentAutofillId = parcel.readParcelable(null);
-        node.mText = parcel.readCharSequence();
-        node.mClassName = parcel.readString();
-
-        return node;
+        final long nodeFlags = parcel.readLong();
+        return nodeFlags == 0 ? new ViewNode() : new ViewNode(nodeFlags, parcel);
     }
 
     /** @hide */
-    static final class ViewStructureImpl extends ViewStructure {
+    @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk.
+    public static final class ViewStructureImpl extends ViewStructure {
 
         final ViewNode mNode = new ViewNode();
 
-        ViewStructureImpl(@NonNull View view) {
+        @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk.
+        public ViewStructureImpl(@NonNull View view) {
             mNode.mAutofillId = Preconditions.checkNotNull(view).getAutofillId();
             final ViewParent parent = view.getParent();
             if (parent instanceof View) {
@@ -119,179 +616,208 @@
             }
         }
 
-        ViewStructureImpl(@NonNull AutofillId parentId, int virtualId) {
+        @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk.
+        public ViewStructureImpl(@NonNull AutofillId parentId, long virtualId, int sessionId) {
             mNode.mParentAutofillId = Preconditions.checkNotNull(parentId);
-            mNode.mAutofillId = new AutofillId(parentId, virtualId);
+            mNode.mAutofillId = new AutofillId(parentId, virtualId, sessionId);
+        }
+
+        @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk.
+        public ViewNode getNode() {
+            return mNode;
         }
 
         @Override
         public void setId(int id, String packageName, String typeName, String entryName) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mId = id;
+            mNode.mIdPackage = packageName;
+            mNode.mIdType = typeName;
+            mNode.mIdEntry = entryName;
         }
 
         @Override
         public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mX = left;
+            mNode.mY = top;
+            mNode.mScrollX = scrollX;
+            mNode.mScrollY = scrollY;
+            mNode.mWidth = width;
+            mNode.mHeight = height;
         }
 
         @Override
         public void setTransformation(Matrix matrix) {
-            // TODO(b/111276913): implement or move to superclass
+            Log.w(TAG, "setTransformation() is not supported");
         }
 
         @Override
         public void setElevation(float elevation) {
-            // TODO(b/111276913): implement or move to superclass
+            Log.w(TAG, "setElevation() is not supported");
         }
 
         @Override
         public void setAlpha(float alpha) {
-            // TODO(b/111276913): implement or move to superclass
+            Log.w(TAG, "setAlpha() is not supported");
         }
 
         @Override
         public void setVisibility(int visibility) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_VISIBILITY_MASK)
+                    | (visibility & FLAGS_VISIBILITY_MASK);
         }
 
         @Override
         public void setAssistBlocked(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_ASSIST_BLOCKED)
+                    | (state ? FLAGS_ASSIST_BLOCKED : 0);
         }
 
         @Override
         public void setEnabled(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_DISABLED) | (state ? 0 : FLAGS_DISABLED);
         }
 
         @Override
         public void setClickable(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_CLICKABLE) | (state ? FLAGS_CLICKABLE : 0);
         }
 
         @Override
         public void setLongClickable(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_LONG_CLICKABLE)
+                    | (state ? FLAGS_LONG_CLICKABLE : 0);
         }
 
         @Override
         public void setContextClickable(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_CONTEXT_CLICKABLE)
+                    | (state ? FLAGS_CONTEXT_CLICKABLE : 0);
         }
 
         @Override
         public void setFocusable(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_FOCUSABLE) | (state ? FLAGS_FOCUSABLE : 0);
         }
 
         @Override
         public void setFocused(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_FOCUSED) | (state ? FLAGS_FOCUSED : 0);
         }
 
         @Override
         public void setAccessibilityFocused(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_ACCESSIBILITY_FOCUSED)
+                    | (state ? FLAGS_ACCESSIBILITY_FOCUSED : 0);
         }
 
         @Override
         public void setCheckable(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_CHECKABLE) | (state ? FLAGS_CHECKABLE : 0);
         }
 
         @Override
         public void setChecked(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_CHECKED) | (state ? FLAGS_CHECKED : 0);
         }
 
         @Override
         public void setSelected(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_SELECTED) | (state ? FLAGS_SELECTED : 0);
         }
 
         @Override
         public void setActivated(boolean state) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_ACTIVATED) | (state ? FLAGS_ACTIVATED : 0);
         }
 
         @Override
         public void setOpaque(boolean opaque) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mFlags = (mNode.mFlags & ~FLAGS_OPAQUE) | (opaque ? FLAGS_OPAQUE : 0);
         }
 
         @Override
         public void setClassName(String className) {
-            // TODO(b/111276913): temporarily setting directly; should be done on superclass instead
             mNode.mClassName = className;
         }
 
         @Override
         public void setContentDescription(CharSequence contentDescription) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mContentDescription = contentDescription;
         }
 
         @Override
         public void setText(CharSequence text) {
-            // TODO(b/111276913): temporarily setting directly; should be done on superclass instead
-            mNode.mText = text;
+            final ViewNodeText t = getNodeText();
+            t.mText = TextUtils.trimNoCopySpans(text);
+            t.mTextSelectionStart = t.mTextSelectionEnd = -1;
         }
 
         @Override
         public void setText(CharSequence text, int selectionStart, int selectionEnd) {
-            // TODO(b/111276913): temporarily setting directly; should be done on superclass instead
-            mNode.mText = text;
-            // TODO(b/111276913): implement or move to superclass
+            final ViewNodeText t = getNodeText();
+            t.mText = TextUtils.trimNoCopySpans(text);
+            t.mTextSelectionStart = selectionStart;
+            t.mTextSelectionEnd = selectionEnd;
         }
 
         @Override
         public void setTextStyle(float size, int fgColor, int bgColor, int style) {
-            // TODO(b/111276913): implement or move to superclass
+            final ViewNodeText t = getNodeText();
+            t.mTextColor = fgColor;
+            t.mTextBackgroundColor = bgColor;
+            t.mTextSize = size;
+            t.mTextStyle = style;
         }
 
         @Override
         public void setTextLines(int[] charOffsets, int[] baselines) {
-            // TODO(b/111276913): implement or move to superclass
+            final ViewNodeText t = getNodeText();
+            t.mLineCharOffsets = charOffsets;
+            t.mLineBaselines = baselines;
+        }
+
+        @Override
+        public void setTextIdEntry(String entryName) {
+            mNode.mTextIdEntry = Preconditions.checkNotNull(entryName);
         }
 
         @Override
         public void setHint(CharSequence hint) {
-            // TODO(b/111276913): implement or move to superclass
+            getNodeText().mHint = hint != null ? hint.toString() : null;
         }
 
         @Override
         public CharSequence getText() {
-            // TODO(b/111276913): temporarily getting directly; should be done on superclass instead
-            return mNode.mText;
+            return mNode.getText();
         }
 
         @Override
         public int getTextSelectionStart() {
-            // TODO(b/111276913): implement or move to superclass
-            return 0;
+            return mNode.getTextSelectionStart();
         }
 
         @Override
         public int getTextSelectionEnd() {
-            // TODO(b/111276913): implement or move to superclass
-            return 0;
+            return mNode.getTextSelectionEnd();
         }
 
         @Override
         public CharSequence getHint() {
-            // TODO(b/111276913): implement or move to superclass
-            return null;
+            return mNode.getHint();
         }
 
         @Override
         public Bundle getExtras() {
-            // TODO(b/111276913): implement or move to superclass
-            return null;
+            if (mNode.mExtras != null) {
+                return mNode.mExtras;
+            }
+            mNode.mExtras = new Bundle();
+            return mNode.mExtras;
         }
 
         @Override
         public boolean hasExtras() {
-            // TODO(b/111276913): implement or move to superclass
-            return false;
+            return mNode.mExtras != null;
         }
 
         @Override
@@ -325,50 +851,64 @@
 
         @Override
         public AutofillId getAutofillId() {
-            // TODO(b/111276913): temporarily getting directly; should be done on superclass instead
             return mNode.mAutofillId;
         }
 
         @Override
         public void setAutofillId(AutofillId id) {
-            // TODO(b/111276913): temporarily setting directly; should be done on superclass instead
-            mNode.mAutofillId = id;
+            mNode.mAutofillId = Preconditions.checkNotNull(id);
         }
 
+
         @Override
         public void setAutofillId(AutofillId parentId, int virtualId) {
-            // TODO(b/111276913): temporarily setting directly; should be done on superclass instead
+            mNode.mParentAutofillId = Preconditions.checkNotNull(parentId);
             mNode.mAutofillId = new AutofillId(parentId, virtualId);
         }
 
         @Override
-        public void setAutofillType(int type) {
-            // TODO(b/111276913): implement or move to superclass
+        public void setAutofillType(@View.AutofillType int type) {
+            mNode.mAutofillType = type;
         }
 
         @Override
-        public void setAutofillHints(String[] hint) {
-            // TODO(b/111276913): implement or move to superclass
+        public void setAutofillHints(String[] hints) {
+            mNode.mAutofillHints = hints;
         }
 
         @Override
         public void setAutofillValue(AutofillValue value) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mAutofillValue = value;
         }
 
         @Override
         public void setAutofillOptions(CharSequence[] options) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mAutofillOptions = options;
         }
 
         @Override
         public void setInputType(int inputType) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mInputType = inputType;
+        }
+
+        @Override
+        public void setMinTextEms(int minEms) {
+            mNode.mMinEms = minEms;
+        }
+
+        @Override
+        public void setMaxTextEms(int maxEms) {
+            mNode.mMaxEms = maxEms;
+        }
+
+        @Override
+        public void setMaxTextLength(int maxLength) {
+            mNode.mMaxLength = maxLength;
         }
 
         @Override
         public void setDataIsSensitive(boolean sensitive) {
-            // TODO(b/111276913): implement or move to superclass
+            Log.w(TAG, "setDataIsSensitive() is not supported");
         }
 
         @Override
@@ -378,7 +918,7 @@
 
         @Override
         public Rect getTempRect() {
-            // TODO(b/111276913): implement or move to superclass
+            Log.w(TAG, "getTempRect() is not supported");
             return null;
         }
 
@@ -389,7 +929,7 @@
 
         @Override
         public void setLocaleList(LocaleList localeList) {
-            // TODO(b/111276913): implement or move to superclass
+            mNode.mLocaleList = localeList;
         }
 
         @Override
@@ -402,5 +942,66 @@
         public void setHtmlInfo(HtmlInfo htmlInfo) {
             Log.w(TAG, "setHtmlInfo() is not supported");
         }
+
+        private ViewNodeText getNodeText() {
+            if (mNode.mText != null) {
+                return mNode.mText;
+            }
+            mNode.mText = new ViewNodeText();
+            return mNode.mText;
+        }
+    }
+
+    //TODO(b/122484602): copied 'as-is' from AssistStructure, except for writeSensitive
+    static final class ViewNodeText {
+        CharSequence mText;
+        float mTextSize;
+        int mTextStyle;
+        int mTextColor = ViewNode.TEXT_COLOR_UNDEFINED;
+        int mTextBackgroundColor = ViewNode.TEXT_COLOR_UNDEFINED;
+        int mTextSelectionStart;
+        int mTextSelectionEnd;
+        int[] mLineCharOffsets;
+        int[] mLineBaselines;
+        String mHint;
+
+        ViewNodeText() {
+        }
+
+        boolean isSimple() {
+            return mTextBackgroundColor == ViewNode.TEXT_COLOR_UNDEFINED
+                    && mTextSelectionStart == 0 && mTextSelectionEnd == 0
+                    && mLineCharOffsets == null && mLineBaselines == null && mHint == null;
+        }
+
+        ViewNodeText(Parcel in, boolean simple) {
+            mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+            mTextSize = in.readFloat();
+            mTextStyle = in.readInt();
+            mTextColor = in.readInt();
+            if (!simple) {
+                mTextBackgroundColor = in.readInt();
+                mTextSelectionStart = in.readInt();
+                mTextSelectionEnd = in.readInt();
+                mLineCharOffsets = in.createIntArray();
+                mLineBaselines = in.createIntArray();
+                mHint = in.readString();
+            }
+        }
+
+        void writeToParcel(Parcel out, boolean simple) {
+            TextUtils.writeToParcel(mText, out, 0);
+            out.writeFloat(mTextSize);
+            out.writeInt(mTextStyle);
+            out.writeInt(mTextColor);
+            if (!simple) {
+                out.writeInt(mTextBackgroundColor);
+                out.writeInt(mTextSelectionStart);
+                out.writeInt(mTextSelectionEnd);
+                out.writeIntArray(mLineCharOffsets);
+                out.writeIntArray(mLineBaselines);
+                out.writeString(mHint);
+            }
+        }
     }
 }
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 28d9fcf..8e7b0db 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -16,11 +16,15 @@
 
 package android.view.inputmethod;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.text.InputType;
 import android.text.TextUtils;
 import android.util.Printer;
@@ -472,6 +476,22 @@
     public String[] contentMimeTypes = null;
 
     /**
+     * If not {@code null}, this editor needs to talk to IMEs that run for the specified user, no
+     * matter what user ID the calling process has.
+     *
+     * <p>Note: This field will be silently ignored when
+     * {@link android.view.inputmethod.InputMethodSystemProperty#MULTI_CLIENT_IME_ENABLED} is
+     * {@code true}.</p>
+     *
+     * <p>Note also that pseudo handles such as {@link UserHandle#ALL} are not supported.</p>
+     *
+     * @hide
+     */
+    @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
+    @Nullable
+    public UserHandle targetInputMethodUser = null;
+
+    /**
      * Ensure that the data in this EditorInfo is compatible with an application
      * that was developed against the given target API version.  This can
      * impact the following input types:
@@ -527,6 +547,9 @@
         pw.println(prefix + "extras=" + extras);
         pw.println(prefix + "hintLocales=" + hintLocales);
         pw.println(prefix + "contentMimeTypes=" + Arrays.toString(contentMimeTypes));
+        if (targetInputMethodUser != null) {
+            pw.println(prefix + "targetInputMethodUserId=" + targetInputMethodUser.getIdentifier());
+        }
     }
 
     /**
@@ -556,6 +579,7 @@
             LocaleList.getEmptyLocaleList().writeToParcel(dest, flags);
         }
         dest.writeStringArray(contentMimeTypes);
+        UserHandle.writeToParcel(targetInputMethodUser, dest);
     }
 
     /**
@@ -582,6 +606,7 @@
                     LocaleList hintLocales = LocaleList.CREATOR.createFromParcel(source);
                     res.hintLocales = hintLocales.isEmpty() ? null : hintLocales;
                     res.contentMimeTypes = source.readStringArray();
+                    res.targetInputMethodUser = UserHandle.readFromParcel(source);
                     return res;
                 }
 
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 1ba7d8e..0cb1800 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -27,6 +27,7 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -922,19 +923,6 @@
         }
     }
 
-    /**
-     * Returns a list of VR InputMethod currently installed.
-     * @hide
-     */
-    @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
-    public List<InputMethodInfo> getVrInputMethodList() {
-        try {
-            return mService.getVrInputMethodList();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
     public List<InputMethodInfo> getEnabledInputMethodList() {
         try {
             return mService.getEnabledInputMethodList();
@@ -980,24 +968,30 @@
         InputMethodPrivilegedOperationsRegistry.get(imeToken).updateStatusIcon(null, 0);
     }
 
-    /** @hide */
+    /**
+     * This hidden API is deprecated in {@link android.os.Build.VERSION_CODES#Q}. Does nothing.
+     *
+     * @param spans will be ignored.
+     *
+     * @deprecated Do not use.
+     * @hide
+     */
+    @Deprecated
     @UnsupportedAppUsage
     public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) {
-        try {
-            mService.registerSuggestionSpansForNotification(spans);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        Log.w(TAG, "registerSuggestionSpansForNotification() is deprecated.  Does nothing.");
     }
 
-    /** @hide */
+    /**
+     * This hidden API is deprecated in {@link android.os.Build.VERSION_CODES#Q}. Does nothing.
+     *
+     * @deprecated Do not use.
+     * @hide
+     */
+    @Deprecated
     @UnsupportedAppUsage
     public void notifySuggestionPicked(SuggestionSpan span, String originalString, int index) {
-        try {
-            mService.notifySuggestionPicked(span, originalString, index);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        Log.w(TAG, "notifySuggestionPicked() is deprecated.  Does nothing.");
     }
 
     /**
@@ -1888,7 +1882,15 @@
 
     /**
      * Notify the event when the user tapped or clicked the text view.
+     *
+     * @param view {@link View} which is being clicked.
+     * @see InputMethodService#onViewClicked(boolean)
+     * @deprecated The semantics of this method can never be defined well for composite {@link View}
+     *             that works as a giant "Canvas", which can host its own UI hierarchy and sub focus
+     *             state. {@link android.webkit.WebView} is a good example. Application / IME
+     *             developers should not rely on this method.
      */
+    @Deprecated
     public void viewClicked(View view) {
         // Re-dispatch if there is a context mismatch.
         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
@@ -2488,14 +2490,58 @@
      * @param subtype A new input method subtype to switch.
      * @return true if the current subtype was successfully switched. When the specified subtype is
      * null, this method returns false.
+     * @deprecated If the calling process is an IME, use
+     *             {@link InputMethodService#switchInputMethod(String, InputMethodSubtype)}, which
+     *             does not require any permission as long as the caller is the current IME.
+     *             If the calling process is some privileged app that already has
+     *             {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission, just
+     *             directly update {@link Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE}.
      */
+    @Deprecated
     @RequiresPermission(WRITE_SECURE_SETTINGS)
     public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
-        try {
-            return mService.setCurrentInputMethodSubtype(subtype);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+        if (Process.myUid() == Process.SYSTEM_UID) {
+            Log.w(TAG, "System process should not call setCurrentInputMethodSubtype() because "
+                    + "almost always it is a bug under multi-user / multi-profile environment. "
+                    + "Consider directly interacting with InputMethodManagerService "
+                    + "via LocalServices.");
+            return false;
         }
+        if (subtype == null) {
+            // See the JavaDoc. This is how this method has worked.
+            return false;
+        }
+        final Context fallbackContext = ActivityThread.currentApplication();
+        if (fallbackContext == null) {
+            return false;
+        }
+        if (fallbackContext.checkSelfPermission(WRITE_SECURE_SETTINGS)
+                != PackageManager.PERMISSION_GRANTED) {
+            return false;
+        }
+        final ContentResolver contentResolver = fallbackContext.getContentResolver();
+        final String imeId = Settings.Secure.getString(contentResolver,
+                Settings.Secure.DEFAULT_INPUT_METHOD);
+        if (ComponentName.unflattenFromString(imeId) == null) {
+            // Null or invalid IME ID format.
+            return false;
+        }
+        final List<InputMethodSubtype> enabledSubtypes;
+        try {
+            enabledSubtypes = mService.getEnabledInputMethodSubtypeList(imeId, true);
+        } catch (RemoteException e) {
+            return false;
+        }
+        final int numSubtypes = enabledSubtypes.size();
+        for (int i = 0; i < numSubtypes; ++i) {
+            final InputMethodSubtype enabledSubtype = enabledSubtypes.get(i);
+            if (enabledSubtype.equals(subtype)) {
+                Settings.Secure.putInt(contentResolver,
+                        Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, enabledSubtype.hashCode());
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -2636,7 +2682,13 @@
      *
      * @param imiId Id of InputMethodInfo which additional input method subtypes will be added to.
      * @param subtypes subtypes will be added as additional subtypes of the current input method.
+     * @deprecated For IMEs that have already implemented features like customizable/downloadable
+     *             keyboard layouts/languages, please start migration to other approaches. One idea
+     *             would be exposing only one unified {@link InputMethodSubtype} then implement
+     *             IME's own language switching mechanism within that unified subtype. The support
+     *             of "Additional Subtype" may be completely dropped in a future version of Android.
      */
+    @Deprecated
     public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
         try {
             mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
diff --git a/core/java/android/view/inputmethod/InputMethodSystemProperty.java b/core/java/android/view/inputmethod/InputMethodSystemProperty.java
index b233b75..57ed7f9 100644
--- a/core/java/android/view/inputmethod/InputMethodSystemProperty.java
+++ b/core/java/android/view/inputmethod/InputMethodSystemProperty.java
@@ -41,6 +41,17 @@
      */
     private static final String PROP_DEBUG_MULTI_CLIENT_IME = "persist.debug.multi_client_ime";
 
+    /**
+     * System property key for debugging purpose. The value must be empty, "1", or "0".
+     *
+     * <p>Values 'y', 'yes', '1', 'true' or 'on' are considered true.</p>
+     *
+     * <p>To set, run "adb root && adb shell setprop persist.debug.per_profile_ime 1".</p>
+     *
+     * <p>This value will be ignored when {@link Build#IS_DEBUGGABLE} returns {@code false}.</p>
+     */
+    private static final String PROP_DEBUG_PER_PROFILE_IME = "persist.debug.per_profile_ime";
+
     @Nullable
     private static ComponentName getMultiClientImeComponentName() {
         if (Build.IS_DEBUGGABLE) {
@@ -59,6 +70,9 @@
     /**
      * {@link ComponentName} of multi-client IME to be used.
      *
+     * <p>TODO: Move this back to MultiClientInputMethodManagerService once
+     * {@link #PER_PROFILE_IME_ENABLED} always becomes {@code true}.</p>
+     *
      * @hide
      */
     @Nullable
@@ -68,7 +82,19 @@
     /**
      * {@code true} when multi-client IME is enabled.
      *
+     * <p>TODO: Move this back to MultiClientInputMethodManagerService once
+     * {@link #PER_PROFILE_IME_ENABLED} always becomes {@code true}.</p>
+     *
      * @hide
      */
     public static final boolean MULTI_CLIENT_IME_ENABLED = (sMultiClientImeComponentName != null);
+
+    /**
+     * {@code true} when per-profile IME is enabled.
+     * @hide
+     */
+    public static final boolean PER_PROFILE_IME_ENABLED = MULTI_CLIENT_IME_ENABLED
+            || Build.IS_DEBUGGABLE && SystemProperties.getBoolean(
+                    PROP_DEBUG_PER_PROFILE_IME, false);
+
 }
diff --git a/core/java/android/view/inspector/InspectableNodeName.java b/core/java/android/view/inspector/InspectableNodeName.java
index ea94ad4..7b9a507 100644
--- a/core/java/android/view/inspector/InspectableNodeName.java
+++ b/core/java/android/view/inspector/InspectableNodeName.java
@@ -19,6 +19,8 @@
 import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
+import android.annotation.TestApi;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
@@ -39,6 +41,7 @@
  */
 @Target({TYPE})
 @Retention(SOURCE)
+@TestApi
 public @interface InspectableNodeName {
     /**
      * The display name for nodes of this type.
diff --git a/core/java/android/view/inspector/InspectableProperty.java b/core/java/android/view/inspector/InspectableProperty.java
index 5b957156..f859521 100644
--- a/core/java/android/view/inspector/InspectableProperty.java
+++ b/core/java/android/view/inspector/InspectableProperty.java
@@ -20,7 +20,8 @@
 import static java.lang.annotation.ElementType.TYPE;
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
-import android.content.res.ResourceId;
+import android.annotation.TestApi;
+import android.content.res.Resources;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
@@ -40,6 +41,7 @@
  */
 @Target({METHOD})
 @Retention(SOURCE)
+@TestApi
 public @interface InspectableProperty {
     /**
      * The name of the property.
@@ -57,16 +59,16 @@
      * If left as {ID_NULL}, and {@link #hasAttributeId()} is true, the attribute ID will be
      * inferred from {@link #name()}.
      *
-     * @return The attribute ID of the property or {@link ResourceId#ID_NULL}
+     * @return The attribute ID of the property or {@link Resources#ID_NULL}
      */
-    int attributeId() default ResourceId.ID_NULL;
+    int attributeId() default Resources.ID_NULL;
 
     /**
      * If this property has an attribute ID.
      *
      * Set to false if the annotated property does not have an attribute ID, that is, it is not
      * inflated from an XML attribute. This will prevent the automatic inference of the attribute
-     * ID if {@link #attributeId()} is set to {@link ResourceId#ID_NULL}.
+     * ID if {@link #attributeId()} is set to {@link Resources#ID_NULL}.
      *
      * @return Whether to infer an attribute ID if not supplied
      */
@@ -86,7 +88,6 @@
      *
      * @return An array of {@link EnumMap}, empty if not applicable
      * @see android.annotation.IntDef
-     * @see IntEnumMapping
      */
     EnumMap[] enumMapping() default {};
 
@@ -110,6 +111,7 @@
      */
     @Target({TYPE})
     @Retention(SOURCE)
+    @TestApi
     @interface EnumMap {
         /**
          * The string name of this enumeration value.
@@ -134,6 +136,7 @@
      */
     @Target({TYPE})
     @Retention(SOURCE)
+    @TestApi
     @interface FlagMap {
         /**
          * The string name of this flag.
@@ -168,15 +171,22 @@
      *
      * @hide
      */
+    @TestApi
     enum ValueType {
         /**
          * No special handling, property is considered to be a numeric value.
+         *
+         * @hide
          */
+        @TestApi
         NONE,
 
         /**
          * The default the annotation processor infers the value type from context.
+         *
+         * @hide
          */
+        @TestApi
         INFERRED,
 
         /**
@@ -185,7 +195,9 @@
          * This is inferred if {@link #enumMapping()} is specified.
          *
          * @see EnumMap
+         * @hide
          */
+        @TestApi
         INT_ENUM,
 
         /**
@@ -194,7 +206,9 @@
          * This is inferred if {@link #flagMapping()} is specified.
          *
          * @see FlagMap
+         * @hide
          */
+        @TestApi
         INT_FLAG,
 
         /**
@@ -204,7 +218,9 @@
          * {@link android.annotation.ColorLong} on the getter method.
          *
          * @see android.graphics.Color
+         * @hide
          */
+        @TestApi
         COLOR,
 
         /**
@@ -213,7 +229,9 @@
          * This type is not inferred, and is non-trivial to represent using {@link FlagMap}.
          *
          * @see android.view.Gravity
+         * @hide
          */
+        @TestApi
         GRAVITY
     }
 }
diff --git a/core/java/android/view/inspector/IntEnumMapping.java b/core/java/android/view/inspector/IntEnumMapping.java
index 69f6dce..147bb46 100644
--- a/core/java/android/view/inspector/IntEnumMapping.java
+++ b/core/java/android/view/inspector/IntEnumMapping.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,37 +18,33 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.util.SparseArray;
 
-import java.util.ArrayList;
+import java.util.Objects;
 
 /**
- * Maps the values of an {int} property to string names for properties that encode enumerations.
+ * Maps the values of an {@code int} property to strings for properties that encode an enumeration.
  *
  * An {@link InspectionCompanion} may provide an instance of this class to a {@link PropertyMapper}
- * for enumerations packed into primitive {int} properties.
+ * for flag values packed into primitive {@code int} properties.
  *
- * This class is immutable, and must be constructed by a {@link Builder}.
+ * This class is an immutable wrapper for {@link SparseArray}, and must be constructed by a
+ * {@link Builder}.
  *
  * @see PropertyMapper#mapIntEnum(String, int, IntEnumMapping)
  */
 public final class IntEnumMapping {
-    private final Value[] mValues;
+    private final SparseArray<String> mValues;
 
     /**
-     * Map from a property value to a string name.
+     * Get the name for the given property value
      *
-     * @param value The value of a property
-     * @return The name of the enumeration value, null if the value is not mapped
+     * @param value The value of the property
+     * @return The name of the value in the enumeration, or null if no value is defined
      */
     @Nullable
-    public String nameOf(int value) {
-        for (Value valueTuple : mValues) {
-            if (valueTuple.mValue == value) {
-                return valueTuple.mName;
-            }
-        }
-
-        return null;
+    public String get(int value) {
+        return mValues.get(value);
     }
 
     /**
@@ -59,60 +55,48 @@
      * @param builder A builder to create from
      */
     private IntEnumMapping(Builder builder) {
-        mValues = builder.mValues.toArray(new Value[builder.mValues.size()]);
+        mValues = builder.mValues.clone();
     }
 
     /**
-     * A builder for {@link IntEnumMapping}
+     * A builder for {@link IntEnumMapping}.
      */
     public static final class Builder {
-        private final ArrayList<Value> mValues;
+        @NonNull
+        private SparseArray<String> mValues;
+        private boolean mMustCloneValues = false;
 
         public Builder() {
-            mValues = new ArrayList<>();
+            mValues = new SparseArray<>();
         }
 
         /**
-         * Add a new entry to this mapping.
+         * Add a new enumerated value.
          *
-         * @param name Name of the enumeration value
-         * @param value Int value of the enumeration value
+         * @param name The string name of the enumeration value
+         * @param value The {@code int} value of the enumeration value
          * @return This builder
          */
         @NonNull
         public Builder addValue(@NonNull String name, int value) {
-            mValues.add(new Value(name, value));
+            // Save an allocation, only re-clone if the builder is used again after building
+            if (mMustCloneValues) {
+                mValues = mValues.clone();
+            }
+
+            mValues.put(value, Objects.requireNonNull(name));
             return this;
         }
 
         /**
-         * Clear the builder, allowing for recycling.
-         */
-        public void clear() {
-            mValues.clear();
-        }
-
-        /**
-         * Build a new {@link IntEnumMapping} from this builder
+         * Build a new {@link IntEnumMapping} from this builder.
          *
          * @return A new mapping
          */
         @NonNull
         public IntEnumMapping build() {
+            mMustCloneValues = true;
             return new IntEnumMapping(this);
         }
     }
-
-    /**
-     * Inner class that holds the name and value of an enumeration value.
-     */
-    private static final class Value {
-        @NonNull private final String mName;
-        private final int mValue;
-
-        private Value(@NonNull String name, int value) {
-            mName = name;
-            mValue = value;
-        }
-    }
 }
diff --git a/core/java/android/view/inspector/IntFlagMapping.java b/core/java/android/view/inspector/IntFlagMapping.java
index dcb87e1..2409081 100644
--- a/core/java/android/view/inspector/IntFlagMapping.java
+++ b/core/java/android/view/inspector/IntFlagMapping.java
@@ -19,14 +19,21 @@
 import android.annotation.NonNull;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
 
 /**
- * Maps the values of an {int} property to arrays of string for properties that encode flags.
+ * Maps the values of an {@code int} property to sets of string for properties that encode flags.
  *
  * An {@link InspectionCompanion} may provide an instance of this class to a {@link PropertyMapper}
- * for flag values packed into primitive {int} properties.
+ * for flag values packed into primitive {@code int} properties.
  *
- * Each flag has a
+ * Each flag has a mask and a target value, for non-exclusive flags, the target can also be used as
+ * the mask. A given integer value is compared against each flag to find what flags are active for
+ * it by bitwise anding it with the mask and comparing the result against the target, that is,
+ * {@code (value & mask) == target}.
  *
  * This class is immutable, and must be constructed by a {@link Builder}.
  *
@@ -39,11 +46,11 @@
      * Get an array of the names of enabled flags for a given property value.
      *
      * @param value The value of the property
-     * @return The names of the enabled flags
+     * @return The names of the enabled flags, empty if no flags enabled
      */
     @NonNull
-    public String[] namesOf(int value) {
-        ArrayList<String> enabledFlagNames = new ArrayList<>(mFlags.length);
+    public Set<String> get(int value) {
+        final Set<String> enabledFlagNames = new HashSet<>(mFlags.length);
 
         for (Flag flag : mFlags) {
             if (flag.isEnabledFor(value)) {
@@ -51,7 +58,7 @@
             }
         }
 
-        return enabledFlagNames.toArray(new String[enabledFlagNames.size()]);
+        return Collections.unmodifiableSet(enabledFlagNames);
     }
 
     /**
@@ -81,7 +88,7 @@
          * The target value will be used as a mask, to handle the common case where flag values
          * are not mutually exclusive. The flag will be considered enabled for a property value if
          * the result of bitwise anding the target and the value equals the target, that is:
-         * {(value & target) == target}.
+         * {@code (value & target) == target}.
          *
          * @param name The name of the flag
          * @param target The value to compare against
@@ -97,7 +104,7 @@
          * Add a new flag with a mask.
          *
          * The flag will be considered enabled for a property value if the result of bitwise anding
-         * the value and the mask equals the target, that is: {(value & mask) == target}.
+         * the value and the mask equals the target, that is: {@code (value & mask) == target}.
          *
          * @param name The name of the flag
          * @param target The value to compare against
@@ -111,13 +118,6 @@
         }
 
         /**
-         * Clear the builder, allowing for recycling.
-         */
-        public void clear() {
-            mFlags.clear();
-        }
-
-        /**
          * Build a new {@link IntFlagMapping} from this builder.
          *
          * @return A new mapping
@@ -137,13 +137,13 @@
         private final int mMask;
 
         private Flag(@NonNull String name, int target, int mask) {
-            mName = name;
+            mName = Objects.requireNonNull(name);
             mTarget = target;
             mMask = mask;
         }
 
         /**
-         * Compare the supplied property value against the mask and taget.
+         * Compare the supplied property value against the mask and target.
          *
          * @param value The value to check
          * @return True if this flag is enabled
diff --git a/core/java/android/view/inspector/PropertyMapper.java b/core/java/android/view/inspector/PropertyMapper.java
index 5fb291b..00b18d1 100644
--- a/core/java/android/view/inspector/PropertyMapper.java
+++ b/core/java/android/view/inspector/PropertyMapper.java
@@ -161,7 +161,7 @@
      *
      * @param name The name of the property
      * @param attributeId If the property is from an XML attribute, the resource ID of the property
-     * @param mapping A mapping from int to an array of strings
+     * @param mapping A mapping from int to a set of strings
      * @return An integer ID for the property
      * @throws PropertyConflictException If the property name is already mapped as another type.
      */
diff --git a/core/java/android/view/inspector/PropertyReader.java b/core/java/android/view/inspector/PropertyReader.java
index fd83e8d..a8b7ecc 100644
--- a/core/java/android/view/inspector/PropertyReader.java
+++ b/core/java/android/view/inspector/PropertyReader.java
@@ -25,7 +25,13 @@
 /**
  * An interface for reading the properties of an inspectable object.
  *
- * Used as the parameter for {@link InspectionCompanion#readProperties(Object, PropertyReader)}.
+ * {@code PropertyReader} is defined as an interface that will be called by
+ * {@link InspectionCompanion#readProperties(Object, PropertyReader)}. This approach allows a
+ * client inspector to read the values of primitive properties without the overhead of
+ * instantiating a class to hold the property values for each inspection pass. If an inspectable
+ * remains unchanged between reading passes, it should be possible for a {@code PropertyReader} to
+ * avoid new allocations for subsequent reading passes.
+ *
  * It has separate methods for all primitive types to avoid autoboxing overhead if a concrete
  * implementation is able to work with primitives. Implementations should be prepared to accept
  * {null} as the value of {@link PropertyReader#readObject(int, Object)}.
@@ -38,7 +44,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {boolean}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code boolean}
      */
     void readBoolean(int id, boolean value);
 
@@ -47,7 +53,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {byte}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code byte}
      */
     void readByte(int id, byte value);
 
@@ -56,7 +62,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {char}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code char}
      */
     void readChar(int id, char value);
 
@@ -65,7 +71,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {double}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code double}
      */
     void readDouble(int id, double value);
 
@@ -74,7 +80,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {float}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code float}
      */
     void readFloat(int id, float value);
 
@@ -83,7 +89,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as an {int}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as an {@code int}
      */
     void readInt(int id, int value);
 
@@ -92,7 +98,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {long}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code long}
      */
     void readLong(int id, long value);
 
@@ -101,7 +107,7 @@
      *
      * @param id Identifier of the property from a {@link PropertyMapper}
      * @param value Value of the property
-     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {short}
+     * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code short}
      */
     void readShort(int id, short value);
 
diff --git a/core/java/android/view/textclassifier/ConversationAction.java b/core/java/android/view/textclassifier/ConversationAction.java
new file mode 100644
index 0000000..1a6e5d8
--- /dev/null
+++ b/core/java/android/view/textclassifier/ConversationAction.java
@@ -0,0 +1,266 @@
+/*
+ * 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.textclassifier;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.app.RemoteAction;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+
+/** Represents the action suggested by a {@link TextClassifier} on a given conversation. */
+public final class ConversationAction implements Parcelable {
+
+    /** @hide */
+    @Retention(SOURCE)
+    @StringDef(
+            value = {
+                    TYPE_VIEW_CALENDAR,
+                    TYPE_VIEW_MAP,
+                    TYPE_TRACK_FLIGHT,
+                    TYPE_OPEN_URL,
+                    TYPE_SEND_SMS,
+                    TYPE_CALL_PHONE,
+                    TYPE_SEND_EMAIL,
+                    TYPE_TEXT_REPLY,
+                    TYPE_CREATE_REMINDER,
+                    TYPE_SHARE_LOCATION
+            },
+            prefix = "TYPE_")
+    public @interface ActionType {}
+
+    /**
+     * Indicates an action to view a calendar at a specified time.
+     */
+    public static final String TYPE_VIEW_CALENDAR = "view_calendar";
+    /**
+     * Indicates an action to view the map at a specified location.
+     */
+    public static final String TYPE_VIEW_MAP = "view_map";
+    /**
+     * Indicates an action to track a flight.
+     */
+    public static final String TYPE_TRACK_FLIGHT = "track_flight";
+    /**
+     * Indicates an action to open an URL.
+     */
+    public static final String TYPE_OPEN_URL = "open_url";
+    /**
+     * Indicates an action to send a SMS.
+     */
+    public static final String TYPE_SEND_SMS = "send_sms";
+    /**
+     * Indicates an action to call a phone number.
+     */
+    public static final String TYPE_CALL_PHONE = "call_phone";
+    /**
+     * Indicates an action to send an email.
+     */
+    public static final String TYPE_SEND_EMAIL = "send_email";
+    /**
+     * Indicates an action to reply with a text message.
+     */
+    public static final String TYPE_TEXT_REPLY = "text_reply";
+    /**
+     * Indicates an action to create a reminder.
+     */
+    public static final String TYPE_CREATE_REMINDER = "create_reminder";
+    /**
+     * Indicates an action to reply with a location.
+     */
+    public static final String TYPE_SHARE_LOCATION = "share_location";
+
+    public static final Creator<ConversationAction> CREATOR =
+            new Creator<ConversationAction>() {
+                @Override
+                public ConversationAction createFromParcel(Parcel in) {
+                    return new ConversationAction(in);
+                }
+
+                @Override
+                public ConversationAction[] newArray(int size) {
+                    return new ConversationAction[size];
+                }
+            };
+
+    @NonNull
+    @ActionType
+    private final String mType;
+    @NonNull
+    private final CharSequence mTextReply;
+    @Nullable
+    private final RemoteAction mAction;
+
+    @FloatRange(from = 0, to = 1)
+    private final float mScore;
+
+    @NonNull
+    private final Bundle mExtras;
+
+    private ConversationAction(
+            @NonNull String type,
+            @Nullable RemoteAction action,
+            @Nullable CharSequence textReply,
+            float score,
+            @NonNull Bundle extras) {
+        mType = Preconditions.checkNotNull(type);
+        mAction = action;
+        mTextReply = textReply;
+        mScore = score;
+        mExtras = Preconditions.checkNotNull(extras);
+    }
+
+    private ConversationAction(Parcel in) {
+        mType = in.readString();
+        mAction = in.readParcelable(null);
+        mTextReply = in.readCharSequence();
+        mScore = in.readFloat();
+        mExtras = in.readBundle();
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeString(mType);
+        parcel.writeParcelable(mAction, flags);
+        parcel.writeCharSequence(mTextReply);
+        parcel.writeFloat(mScore);
+        parcel.writeBundle(mExtras);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Returns the type of this action, for example, {@link #TYPE_VIEW_CALENDAR}. */
+    @NonNull
+    @ActionType
+    public String getType() {
+        return mType;
+    }
+
+    /**
+     * Returns a RemoteAction object, which contains the icon, label and a PendingIntent, for
+     * the specified action type.
+     */
+    @Nullable
+    public RemoteAction getAction() {
+        return mAction;
+    }
+
+    /**
+     * Returns the confidence score for the specified action. The value ranges from 0 (low
+     * confidence) to 1 (high confidence).
+     */
+    @FloatRange(from = 0, to = 1)
+    public float getConfidenceScore() {
+        return mScore;
+    }
+
+    /**
+     * Returns the text reply that could be sent as a reply to the given conversation.
+     * <p>
+     * This is only available when the type of the action is {@link #TYPE_TEXT_REPLY}.
+     */
+    @Nullable
+    public CharSequence getTextReply() {
+        return mTextReply;
+    }
+
+    /**
+     * Returns the extended data related to this conversation action.
+     *
+     * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
+     * prefer to hold a reference to the returned bundle rather than frequently calling this
+     * method.
+     */
+    @NonNull
+    public Bundle getExtras() {
+        return mExtras.deepCopy();
+    }
+
+    /** Builder class to construct {@link ConversationAction}. */
+    public static final class Builder {
+        @Nullable
+        @ActionType
+        private String mType;
+        @Nullable
+        private RemoteAction mAction;
+        @Nullable
+        private CharSequence mTextReply;
+        private float mScore;
+        @Nullable
+        private Bundle mExtras;
+
+        public Builder(@NonNull @ActionType String actionType) {
+            mType = Preconditions.checkNotNull(actionType);
+        }
+
+        /**
+         * Sets an action that may be performed on the given conversation.
+         */
+        @NonNull
+        public Builder setAction(@Nullable RemoteAction action) {
+            mAction = action;
+            return this;
+        }
+
+        /**
+         * Sets a text reply that may be performed on the given conversation.
+         */
+        @NonNull
+        public Builder setTextReply(@Nullable CharSequence textReply) {
+            mTextReply = textReply;
+            return this;
+        }
+
+        /** Sets the confident score. */
+        @NonNull
+        public Builder setConfidenceScore(@FloatRange(from = 0, to = 1) float score) {
+            mScore = score;
+            return this;
+        }
+
+        /**
+         * Sets the extended data for the conversation action object.
+         */
+        @NonNull
+        public Builder setExtras(@Nullable Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /** Builds the {@link ConversationAction} object. */
+        @NonNull
+        public ConversationAction build() {
+            return new ConversationAction(
+                    mType,
+                    mAction,
+                    mTextReply,
+                    mScore,
+                    mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
+        }
+    }
+}
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index 3f690f7..f7c1a26 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -17,18 +17,15 @@
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
-import android.annotation.FloatRange;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringDef;
 import android.app.Person;
-import android.app.RemoteAction;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.SpannedString;
-import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
@@ -37,10 +34,8 @@
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Set;
 
 /**
  * Represents a list of actions suggested by a {@link TextClassifier} on a given conversation.
@@ -62,83 +57,6 @@
                 }
             };
 
-    /** @hide */
-    @Retention(SOURCE)
-    @StringDef(
-            value = {
-                    TYPE_VIEW_CALENDAR,
-                    TYPE_VIEW_MAP,
-                    TYPE_TRACK_FLIGHT,
-                    TYPE_OPEN_URL,
-                    TYPE_SEND_SMS,
-                    TYPE_CALL_PHONE,
-                    TYPE_SEND_EMAIL,
-                    TYPE_TEXT_REPLY,
-                    TYPE_CREATE_REMINDER,
-                    TYPE_SHARE_LOCATION
-            },
-            prefix = "TYPE_")
-    public @interface ActionType {}
-
-    /**
-     * Indicates an action to view a calendar at a specified time.
-     */
-    public static final String TYPE_VIEW_CALENDAR = "view_calendar";
-    /**
-     * Indicates an action to view the map at a specified location.
-     */
-    public static final String TYPE_VIEW_MAP = "view_map";
-    /**
-     * Indicates an action to track a flight.
-     */
-    public static final String TYPE_TRACK_FLIGHT = "track_flight";
-    /**
-     * Indicates an action to open an URL.
-     */
-    public static final String TYPE_OPEN_URL = "open_url";
-    /**
-     * Indicates an action to send a SMS.
-     */
-    public static final String TYPE_SEND_SMS = "send_sms";
-    /**
-     * Indicates an action to call a phone number.
-     */
-    public static final String TYPE_CALL_PHONE = "call_phone";
-    /**
-     * Indicates an action to send an email.
-     */
-    public static final String TYPE_SEND_EMAIL = "send_email";
-    /**
-     * Indicates an action to reply with a text message.
-     */
-    public static final String TYPE_TEXT_REPLY = "text_reply";
-    /**
-     * Indicates an action to create a reminder.
-     */
-    public static final String TYPE_CREATE_REMINDER = "create_reminder";
-    /**
-     * Indicates an action to reply with a location.
-     */
-    public static final String TYPE_SHARE_LOCATION = "share_location";
-
-    /** @hide */
-    @Retention(SOURCE)
-    @StringDef(
-            value = {
-                    HINT_FOR_NOTIFICATION,
-                    HINT_FOR_IN_APP,
-            },
-            prefix = "HINT_")
-    public @interface Hint {}
-    /**
-     * To indicate the generated actions will be used within the app.
-     */
-    public static final String HINT_FOR_IN_APP = "in_app";
-    /**
-     * To indicate the generated actions will be used for notification.
-     */
-    public static final String HINT_FOR_NOTIFICATION = "notification";
-
     private final List<ConversationAction> mConversationActions;
     private final String mId;
 
@@ -184,182 +102,6 @@
         return mId;
     }
 
-    /** Represents the action suggested by a {@link TextClassifier} on a given conversation. */
-    public static final class ConversationAction implements Parcelable {
-
-        public static final Creator<ConversationAction> CREATOR =
-                new Creator<ConversationAction>() {
-                    @Override
-                    public ConversationAction createFromParcel(Parcel in) {
-                        return new ConversationAction(in);
-                    }
-
-                    @Override
-                    public ConversationAction[] newArray(int size) {
-                        return new ConversationAction[size];
-                    }
-                };
-
-        @NonNull
-        @ActionType
-        private final String mType;
-        @NonNull
-        private final CharSequence mTextReply;
-        @Nullable
-        private final RemoteAction mAction;
-
-        @FloatRange(from = 0, to = 1)
-        private final float mScore;
-
-        @NonNull
-        private final Bundle mExtras;
-
-        private ConversationAction(
-                @NonNull String type,
-                @Nullable RemoteAction action,
-                @Nullable CharSequence textReply,
-                float score,
-                @NonNull Bundle extras) {
-            mType = Preconditions.checkNotNull(type);
-            mAction = action;
-            mTextReply = textReply;
-            mScore = score;
-            mExtras = Preconditions.checkNotNull(extras);
-        }
-
-        private ConversationAction(Parcel in) {
-            mType = in.readString();
-            mAction = in.readParcelable(null);
-            mTextReply = in.readCharSequence();
-            mScore = in.readFloat();
-            mExtras = in.readBundle();
-        }
-
-        @Override
-        public void writeToParcel(Parcel parcel, int flags) {
-            parcel.writeString(mType);
-            parcel.writeParcelable(mAction, flags);
-            parcel.writeCharSequence(mTextReply);
-            parcel.writeFloat(mScore);
-            parcel.writeBundle(mExtras);
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @NonNull
-        @ActionType
-        /** Returns the type of this action, for example, {@link #TYPE_VIEW_CALENDAR}. */
-        public String getType() {
-            return mType;
-        }
-
-        @Nullable
-        /**
-         * Returns a RemoteAction object, which contains the icon, label and a PendingIntent, for
-         * the specified action type.
-         */
-        public RemoteAction getAction() {
-            return mAction;
-        }
-
-        /**
-         * Returns the confidence score for the specified action. The value ranges from 0 (low
-         * confidence) to 1 (high confidence).
-         */
-        @FloatRange(from = 0, to = 1)
-        public float getConfidenceScore() {
-            return mScore;
-        }
-
-        /**
-         * Returns the text reply that could be sent as a reply to the given conversation.
-         * <p>
-         * This is only available when the type of the action is {@link #TYPE_TEXT_REPLY}.
-         */
-        @Nullable
-        public CharSequence getTextReply() {
-            return mTextReply;
-        }
-
-        /**
-         * Returns the extended data related to this conversation action.
-         *
-         * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-         * prefer to hold a reference to the returned bundle rather than frequently calling this
-         * method.
-         */
-        @NonNull
-        public Bundle getExtras() {
-            return mExtras.deepCopy();
-        }
-
-        /** Builder class to construct {@link ConversationAction}. */
-        public static final class Builder {
-            @Nullable
-            @ActionType
-            private String mType;
-            @Nullable
-            private RemoteAction mAction;
-            @Nullable
-            private CharSequence mTextReply;
-            private float mScore;
-            @Nullable
-            private Bundle mExtras;
-
-            public Builder(@NonNull @ActionType String actionType) {
-                mType = Preconditions.checkNotNull(actionType);
-            }
-
-            /**
-             * Sets an action that may be performed on the given conversation.
-             */
-            @NonNull
-            public Builder setAction(@Nullable RemoteAction action) {
-                mAction = action;
-                return this;
-            }
-
-            /**
-             * Sets a text reply that may be performed on the given conversation.
-             */
-            @NonNull
-            public Builder setTextReply(@Nullable CharSequence textReply) {
-                mTextReply = textReply;
-                return this;
-            }
-
-            /** Sets the confident score. */
-            @NonNull
-            public Builder setConfidenceScore(@FloatRange(from = 0, to = 1) float score) {
-                mScore = score;
-                return this;
-            }
-
-            /**
-             * Sets the extended data for the conversation action object.
-             */
-            @NonNull
-            public Builder setExtras(@Nullable Bundle extras) {
-                mExtras = extras;
-                return this;
-            }
-
-            /** Builds the {@link ConversationAction} object. */
-            @NonNull
-            public ConversationAction build() {
-                return new ConversationAction(
-                        mType,
-                        mAction,
-                        mTextReply,
-                        mScore,
-                        mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
-            }
-        }
-    }
-
     /** Represents a message in the conversation. */
     public static final class Message implements Parcelable {
         /**
@@ -538,156 +280,36 @@
         }
     }
 
-    /** Configuration object for specifying what action types to identify. */
-    public static final class TypeConfig implements Parcelable {
-        @NonNull
-        @ActionType
-        private final Set<String> mExcludedTypes;
-        @NonNull
-        @ActionType
-        private final Set<String> mIncludedTypes;
-        private final boolean mIncludeTypesFromTextClassifier;
-
-        private TypeConfig(
-                @NonNull Set<String> includedTypes,
-                @NonNull Set<String> excludedTypes,
-                boolean includeTypesFromTextClassifier) {
-            mIncludedTypes = Preconditions.checkNotNull(includedTypes);
-            mExcludedTypes = Preconditions.checkNotNull(excludedTypes);
-            mIncludeTypesFromTextClassifier = includeTypesFromTextClassifier;
-        }
-
-        private TypeConfig(Parcel in) {
-            mIncludedTypes = new ArraySet<>(in.createStringArrayList());
-            mExcludedTypes = new ArraySet<>(in.createStringArrayList());
-            mIncludeTypesFromTextClassifier = in.readByte() != 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel parcel, int flags) {
-            parcel.writeStringList(new ArrayList<>(mIncludedTypes));
-            parcel.writeStringList(new ArrayList<>(mExcludedTypes));
-            parcel.writeByte((byte) (mIncludeTypesFromTextClassifier ? 1 : 0));
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        public static final Creator<TypeConfig> CREATOR =
-                new Creator<TypeConfig>() {
-                    @Override
-                    public TypeConfig createFromParcel(Parcel in) {
-                        return new TypeConfig(in);
-                    }
-
-                    @Override
-                    public TypeConfig[] newArray(int size) {
-                        return new TypeConfig[size];
-                    }
-                };
-
-        /**
-         * Returns a final list of types that the text classifier should look for.
-         *
-         * <p>NOTE: This method is intended for use by a text classifier.
-         *
-         * @param defaultTypes types the text classifier thinks should be included before factoring
-         *    in the included/excluded types given by the client.
-         */
-        @NonNull
-        public Collection<String> resolveTypes(@Nullable Collection<String> defaultTypes) {
-            Set<String> types = new ArraySet<>();
-            if (mIncludeTypesFromTextClassifier && defaultTypes != null) {
-                types.addAll(defaultTypes);
-            }
-            types.addAll(mIncludedTypes);
-            types.removeAll(mExcludedTypes);
-            return Collections.unmodifiableCollection(types);
-        }
-
-        /**
-         * Return whether the client allows the text classifier to include its own list of default
-         * types. If this function returns {@code true}, the text classifier can consider specifying
-         * a default list of entity types in {@link #resolveTypes(Collection)}.
-         *
-         * <p>NOTE: This method is intended for use by a text classifier.
-         *
-         * @see #resolveTypes(Collection)
-         */
-        public boolean shouldIncludeTypesFromTextClassifier() {
-            return mIncludeTypesFromTextClassifier;
-        }
-
-        /** Builder class to construct the {@link TypeConfig} object. */
-        public static final class Builder {
-            @Nullable
-            private Collection<String> mExcludedTypes;
-            @Nullable
-            private Collection<String> mIncludedTypes;
-            private boolean mIncludeTypesFromTextClassifier = true;
-
-            /**
-             * Sets a collection of types that are explicitly included, for example, {@link
-             * #TYPE_VIEW_CALENDAR}.
-             */
-            @NonNull
-            public Builder setIncludedTypes(
-                    @Nullable @ActionType Collection<String> includedTypes) {
-                mIncludedTypes = includedTypes;
-                return this;
-            }
-
-            /**
-             * Sets a collection of types that are explicitly excluded, for example, {@link
-             * #TYPE_VIEW_CALENDAR}.
-             */
-            @NonNull
-            public Builder setExcludedTypes(
-                    @Nullable @ActionType Collection<String> excludedTypes) {
-                mExcludedTypes = excludedTypes;
-                return this;
-            }
-
-            /**
-             * Specifies whether or not to include the types suggested by the text classifier. By
-             * default, it is included.
-             */
-            @NonNull
-            public Builder includeTypesFromTextClassifier(boolean includeTypesFromTextClassifier) {
-                mIncludeTypesFromTextClassifier = includeTypesFromTextClassifier;
-                return this;
-            }
-
-            /**
-             * Combines all of the options that have been set and returns a new {@link TypeConfig}
-             * object.
-             */
-            @NonNull
-            public TypeConfig build() {
-                return new TypeConfig(
-                        mIncludedTypes == null
-                                ? Collections.emptySet()
-                                : new ArraySet<>(mIncludedTypes),
-                        mExcludedTypes == null
-                                ? Collections.emptySet()
-                                : new ArraySet<>(mExcludedTypes),
-                        mIncludeTypesFromTextClassifier);
-            }
-        }
-    }
-
     /**
      * A request object for generating conversation action suggestions.
      *
      * @see TextClassifier#suggestConversationActions(Request)
      */
     public static final class Request implements Parcelable {
+
+        /** @hide */
+        @Retention(SOURCE)
+        @StringDef(
+                value = {
+                        HINT_FOR_NOTIFICATION,
+                        HINT_FOR_IN_APP,
+                },
+                prefix = "HINT_")
+        public @interface Hint {}
+
+        /**
+         * To indicate the generated actions will be used within the app.
+         */
+        public static final String HINT_FOR_IN_APP = "in_app";
+        /**
+         * To indicate the generated actions will be used for notification.
+         */
+        public static final String HINT_FOR_NOTIFICATION = "notification";
+
         @NonNull
         private final List<Message> mConversation;
         @NonNull
-        private final TypeConfig mTypeConfig;
+        private final TextClassifier.EntityConfig mTypeConfig;
         private final int mMaxSuggestions;
         @NonNull
         @Hint
@@ -699,7 +321,7 @@
 
         private Request(
                 @NonNull List<Message> conversation,
-                @NonNull TypeConfig typeConfig,
+                @NonNull TextClassifier.EntityConfig typeConfig,
                 int maxSuggestions,
                 String conversationId,
                 @Nullable @Hint List<String> hints) {
@@ -713,7 +335,7 @@
         private static Request readFromParcel(Parcel in) {
             List<Message> conversation = new ArrayList<>();
             in.readParcelableList(conversation, null);
-            TypeConfig typeConfig = in.readParcelable(null);
+            TextClassifier.EntityConfig typeConfig = in.readParcelable(null);
             int maxSuggestions = in.readInt();
             String conversationId = in.readString();
             List<String> hints = new ArrayList<>();
@@ -760,7 +382,7 @@
 
         /** Returns the type config. */
         @NonNull
-        public TypeConfig getTypeConfig() {
+        public TextClassifier.EntityConfig getTypeConfig() {
             return mTypeConfig;
         }
 
@@ -820,7 +442,7 @@
             @NonNull
             private List<Message> mConversation;
             @Nullable
-            private TypeConfig mTypeConfig;
+            private TextClassifier.EntityConfig mTypeConfig;
             private int mMaxSuggestions;
             @Nullable
             private String mConversationId;
@@ -849,7 +471,7 @@
 
             /** Sets the type config. */
             @NonNull
-            public Builder setTypeConfig(@Nullable TypeConfig typeConfig) {
+            public Builder setTypeConfig(@Nullable TextClassifier.EntityConfig typeConfig) {
                 mTypeConfig = typeConfig;
                 return this;
             }
@@ -879,7 +501,9 @@
             public Request build() {
                 return new Request(
                         Collections.unmodifiableList(mConversation),
-                        mTypeConfig == null ? new TypeConfig.Builder().build() : mTypeConfig,
+                        mTypeConfig == null
+                                ? new TextClassifier.EntityConfig.Builder().build()
+                                : mTypeConfig,
                         mMaxSuggestions,
                         mConversationId,
                         mHints == null
diff --git a/core/java/android/view/textclassifier/GenerateLinksLogger.java b/core/java/android/view/textclassifier/GenerateLinksLogger.java
index 067513f..3996b27 100644
--- a/core/java/android/view/textclassifier/GenerateLinksLogger.java
+++ b/core/java/android/view/textclassifier/GenerateLinksLogger.java
@@ -39,7 +39,6 @@
 public final class GenerateLinksLogger {
 
     private static final String LOG_TAG = "GenerateLinksLogger";
-    private static final boolean DEBUG_LOG_ENABLED = false;
     private static final String ZERO = "0";
 
     private final MetricsLogger mMetricsLogger;
@@ -128,8 +127,9 @@
     }
 
     private static void debugLog(LogMaker log) {
-        if (!DEBUG_LOG_ENABLED) return;
-
+        if (!Log.ENABLE_FULL_LOGGING) {
+            return;
+        }
         final String callId = Objects.toString(
                 log.getTaggedData(MetricsEvent.FIELD_LINKIFY_CALL_ID), "");
         final String entityType = Objects.toString(
@@ -143,7 +143,7 @@
         final int latencyMs = Integer.parseInt(
                 Objects.toString(log.getTaggedData(MetricsEvent.FIELD_LINKIFY_LATENCY), ZERO));
 
-        Log.d(LOG_TAG,
+        Log.v(LOG_TAG,
                 String.format(Locale.US, "%s:%s %d links (%d/%d chars) %dms %s", callId, entityType,
                         numLinks, linkLength, textLength, latencyMs, log.getPackageName()));
     }
diff --git a/core/java/android/view/textclassifier/Log.java b/core/java/android/view/textclassifier/Log.java
index ef19ee5..5c60c09 100644
--- a/core/java/android/view/textclassifier/Log.java
+++ b/core/java/android/view/textclassifier/Log.java
@@ -16,10 +16,12 @@
 
 package android.view.textclassifier;
 
-import android.util.Slog;
-
 /**
  * Logging for android.view.textclassifier package.
+ * <p>
+ * To enable full log:
+ * 1. adb shell setprop log.tag.androidtc VERBOSE
+ * 2. adb shell stop && adb shell start
  */
 final class Log {
 
@@ -27,24 +29,32 @@
      * true: Enables full logging.
      * false: Limits logging to debug level.
      */
-    private static final boolean ENABLE_FULL_LOGGING = false;
+    static final boolean ENABLE_FULL_LOGGING =
+            android.util.Log.isLoggable(TextClassifier.DEFAULT_LOG_TAG, android.util.Log.VERBOSE);
 
-    private Log() {}
+    private Log() {
+    }
+
+    public static void v(String tag, String msg) {
+        if (ENABLE_FULL_LOGGING) {
+            android.util.Log.v(tag, msg);
+        }
+    }
 
     public static void d(String tag, String msg) {
-        Slog.d(tag, msg);
+        android.util.Log.d(tag, msg);
     }
 
     public static void w(String tag, String msg) {
-        Slog.w(tag, msg);
+        android.util.Log.w(tag, msg);
     }
 
     public static void e(String tag, String msg, Throwable tr) {
         if (ENABLE_FULL_LOGGING) {
-            Slog.e(tag, msg, tr);
+            android.util.Log.e(tag, msg, tr);
         } else {
             final String trString = (tr != null) ? tr.getClass().getSimpleName() : "??";
-            Slog.d(tag, String.format("%s (%s)", msg, trString));
+            android.util.Log.d(tag, String.format("%s (%s)", msg, trString));
         }
     }
 }
diff --git a/core/java/android/view/textclassifier/SelectionSessionLogger.java b/core/java/android/view/textclassifier/SelectionSessionLogger.java
index cdacdd5..48a568a 100644
--- a/core/java/android/view/textclassifier/SelectionSessionLogger.java
+++ b/core/java/android/view/textclassifier/SelectionSessionLogger.java
@@ -39,7 +39,6 @@
 public final class SelectionSessionLogger {
 
     private static final String LOG_TAG = "SelectionSessionLogger";
-    private static final boolean DEBUG_LOG_ENABLED = false;
     static final String CLASSIFIER_ID = "androidtc";
 
     private static final int START_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_START;
@@ -195,8 +194,9 @@
     }
 
     private static void debugLog(LogMaker log) {
-        if (!DEBUG_LOG_ENABLED) return;
-
+        if (!Log.ENABLE_FULL_LOGGING) {
+            return;
+        }
         final String widgetType = Objects.toString(log.getTaggedData(WIDGET_TYPE), UNKNOWN);
         final String widgetVersion = Objects.toString(log.getTaggedData(WIDGET_VERSION), "");
         final String widget = widgetVersion.isEmpty()
@@ -221,7 +221,7 @@
         final int eventEnd = Integer.parseInt(
                 Objects.toString(log.getTaggedData(EVENT_END), ZERO));
 
-        Log.d(LOG_TAG,
+        Log.v(LOG_TAG,
                 String.format(Locale.US, "%2d: %s/%s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)",
                         index, type, subType, entity, eventStart, eventEnd, smartStart, smartEnd,
                         widget, model));
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index 50801a2..ce680ec 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -117,15 +117,15 @@
             .add(TextClassifier.TYPE_FLIGHT_NUMBER).toString();
     private static final String CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES =
             new StringJoiner(ENTITY_LIST_DELIMITER)
-                    .add(ConversationActions.TYPE_TEXT_REPLY)
-                    .add(ConversationActions.TYPE_CREATE_REMINDER)
-                    .add(ConversationActions.TYPE_CALL_PHONE)
-                    .add(ConversationActions.TYPE_OPEN_URL)
-                    .add(ConversationActions.TYPE_SEND_EMAIL)
-                    .add(ConversationActions.TYPE_SEND_SMS)
-                    .add(ConversationActions.TYPE_TRACK_FLIGHT)
-                    .add(ConversationActions.TYPE_VIEW_CALENDAR)
-                    .add(ConversationActions.TYPE_VIEW_MAP)
+                    .add(ConversationAction.TYPE_TEXT_REPLY)
+                    .add(ConversationAction.TYPE_CREATE_REMINDER)
+                    .add(ConversationAction.TYPE_CALL_PHONE)
+                    .add(ConversationAction.TYPE_OPEN_URL)
+                    .add(ConversationAction.TYPE_SEND_EMAIL)
+                    .add(ConversationAction.TYPE_SEND_SMS)
+                    .add(ConversationAction.TYPE_TRACK_FLIGHT)
+                    .add(ConversationAction.TYPE_VIEW_CALENDAR)
+                    .add(ConversationAction.TYPE_VIEW_MAP)
                     .toString();
 
     private final boolean mSystemTextClassifierEnabled;
diff --git a/core/java/android/view/textclassifier/TextClassificationSession.java b/core/java/android/view/textclassifier/TextClassificationSession.java
index 4c64198..45668c0 100644
--- a/core/java/android/view/textclassifier/TextClassificationSession.java
+++ b/core/java/android/view/textclassifier/TextClassificationSession.java
@@ -27,7 +27,6 @@
 @WorkerThread
 final class TextClassificationSession implements TextClassifier {
 
-    /* package */ static final boolean DEBUG_LOG_ENABLED = true;
     private static final String LOG_TAG = "TextClassificationSession";
 
     private final TextClassifier mDelegate;
@@ -133,9 +132,7 @@
 
             if (event.getEventType() != SelectionEvent.EVENT_SELECTION_STARTED
                     && mStartEvent == null) {
-                if (DEBUG_LOG_ENABLED) {
-                    Log.d(LOG_TAG, "Selection session not yet started. Ignoring event");
-                }
+                Log.d(LOG_TAG, "Selection session not yet started. Ignoring event");
                 return false;
             }
 
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 8709e09..5a56136 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -32,7 +32,6 @@
 import android.text.util.Linkify;
 import android.text.util.Linkify.LinkifyMask;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -43,6 +42,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -324,7 +324,7 @@
     }
 
     /**
-     * Detects the language of the specified text.
+     * Detects the language of the text in the given request.
      *
      * <p><strong>NOTE: </strong>Call on a worker thread.
      *
@@ -403,42 +403,59 @@
     default void dump(@NonNull IndentingPrintWriter printWriter) {}
 
     /**
-     * Configuration object for specifying what entities to identify.
+     * Configuration object for specifying what entity types to identify.
      *
      * Configs are initially based on a predefined preset, and can be modified from there.
      */
     final class EntityConfig implements Parcelable {
-        private final Collection<String> mHints;
-        private final Collection<String> mExcludedEntityTypes;
-        private final Collection<String> mIncludedEntityTypes;
-        private final boolean mUseHints;
+        private final List<String> mIncludedTypes;
+        private final List<String> mExcludedTypes;
+        private final List<String> mHints;
+        private final boolean mIncludeTypesFromTextClassifier;
 
-        private EntityConfig(boolean useHints, Collection<String> hints,
-                Collection<String> includedEntityTypes, Collection<String> excludedEntityTypes) {
-            mHints = hints == null
-                    ? Collections.EMPTY_LIST
-                    : Collections.unmodifiableCollection(new ArraySet<>(hints));
-            mExcludedEntityTypes = excludedEntityTypes == null
-                    ? Collections.EMPTY_LIST : new ArraySet<>(excludedEntityTypes);
-            mIncludedEntityTypes = includedEntityTypes == null
-                    ? Collections.EMPTY_LIST : new ArraySet<>(includedEntityTypes);
-            mUseHints = useHints;
+        private EntityConfig(
+                List<String> includedEntityTypes,
+                List<String> excludedEntityTypes,
+                List<String> hints,
+                boolean includeTypesFromTextClassifier) {
+            mIncludedTypes = Preconditions.checkNotNull(includedEntityTypes);
+            mExcludedTypes = Preconditions.checkNotNull(excludedEntityTypes);
+            mHints = Preconditions.checkNotNull(hints);
+            mIncludeTypesFromTextClassifier = includeTypesFromTextClassifier;
+        }
+
+        private EntityConfig(Parcel in) {
+            mIncludedTypes = new ArrayList<>();
+            in.readStringList(mIncludedTypes);
+            mExcludedTypes = new ArrayList<>();
+            in.readStringList(mExcludedTypes);
+            List<String> tmpHints = new ArrayList<>();
+            in.readStringList(tmpHints);
+            mHints = Collections.unmodifiableList(tmpHints);
+            mIncludeTypesFromTextClassifier = in.readByte() != 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel parcel, int flags) {
+            parcel.writeStringList(mIncludedTypes);
+            parcel.writeStringList(mExcludedTypes);
+            parcel.writeStringList(mHints);
+            parcel.writeByte((byte) (mIncludeTypesFromTextClassifier ? 1 : 0));
         }
 
         /**
          * Creates an EntityConfig.
          *
          * @param hints Hints for the TextClassifier to determine what types of entities to find.
+         *
+         * @deprecated Use {@link Builder} instead.
          */
+        @Deprecated
         public static EntityConfig createWithHints(@Nullable Collection<String> hints) {
-            return new EntityConfig(/* useHints */ true, hints,
-                    /* includedEntityTypes */null, /* excludedEntityTypes */ null);
-        }
-
-        // TODO: Remove once apps can build against the latest sdk.
-        /** @hide */
-        public static EntityConfig create(@Nullable Collection<String> hints) {
-            return createWithHints(hints);
+            return new EntityConfig.Builder()
+                    .includeTypesFromTextClassifier(true)
+                    .setHints(hints)
+                    .build();
         }
 
         /**
@@ -450,12 +467,19 @@
          *
          *
          * Note that if an entity has been excluded, the exclusion will take precedence.
+         *
+         * @deprecated Use {@link Builder} instead.
          */
+        @Deprecated
         public static EntityConfig create(@Nullable Collection<String> hints,
                 @Nullable Collection<String> includedEntityTypes,
                 @Nullable Collection<String> excludedEntityTypes) {
-            return new EntityConfig(/* useHints */ true, hints,
-                    includedEntityTypes, excludedEntityTypes);
+            return new EntityConfig.Builder()
+                    .setIncludedTypes(includedEntityTypes)
+                    .setExcludedTypes(excludedEntityTypes)
+                    .setHints(hints)
+                    .includeTypesFromTextClassifier(true)
+                    .build();
         }
 
         /**
@@ -463,34 +487,33 @@
          *
          * @param entityTypes Complete set of entities, e.g. {@link #TYPE_URL} to find.
          *
+         * @deprecated Use {@link Builder} instead.
          */
+        @Deprecated
         public static EntityConfig createWithExplicitEntityList(
                 @Nullable Collection<String> entityTypes) {
-            return new EntityConfig(/* useHints */ false, /* hints */ null,
-                    /* includedEntityTypes */ entityTypes, /* excludedEntityTypes */ null);
-        }
-
-        // TODO: Remove once apps can build against the latest sdk.
-        /** @hide */
-        public static EntityConfig createWithEntityList(@Nullable Collection<String> entityTypes) {
-            return createWithExplicitEntityList(entityTypes);
+            return new EntityConfig.Builder()
+                    .setIncludedTypes(entityTypes)
+                    .includeTypesFromTextClassifier(false)
+                    .build();
         }
 
         /**
-         * Returns a list of the final set of entities to find.
+         * Returns a final list of entity types to find.
          *
-         * @param entities Entities we think should be found before factoring in includes/excludes
+         * @param entityTypes Entity types we think should be found before factoring in
+         *                    includes/excludes
          *
          * This method is intended for use by TextClassifier implementations.
          */
         public Collection<String> resolveEntityListModifications(
-                @NonNull Collection<String> entities) {
-            final Set<String> finalSet = new HashSet();
-            if (mUseHints) {
-                finalSet.addAll(entities);
+                @NonNull Collection<String> entityTypes) {
+            final Set<String> finalSet = new HashSet<>();
+            if (mIncludeTypesFromTextClassifier) {
+                finalSet.addAll(entityTypes);
             }
-            finalSet.addAll(mIncludedEntityTypes);
-            finalSet.removeAll(mExcludedEntityTypes);
+            finalSet.addAll(mIncludedTypes);
+            finalSet.removeAll(mExcludedTypes);
             return finalSet;
         }
 
@@ -503,17 +526,22 @@
             return mHints;
         }
 
-        @Override
-        public int describeContents() {
-            return 0;
+        /**
+         * Return whether the client allows the text classifier to include its own list of
+         * default types. If this function returns {@code true}, a default list of types suggested
+         * from a text classifier will be taking into account.
+         *
+         * <p>NOTE: This method is intended for use by a text classifier.
+         *
+         * @see #resolveEntityListModifications(Collection)
+         */
+        public boolean shouldIncludeTypesFromTextClassifier() {
+            return mIncludeTypesFromTextClassifier;
         }
 
         @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeStringList(new ArrayList<>(mHints));
-            dest.writeStringList(new ArrayList<>(mExcludedEntityTypes));
-            dest.writeStringList(new ArrayList<>(mIncludedEntityTypes));
-            dest.writeInt(mUseHints ? 1 : 0);
+        public int describeContents() {
+            return 0;
         }
 
         public static final Parcelable.Creator<EntityConfig> CREATOR =
@@ -529,11 +557,75 @@
                     }
                 };
 
-        private EntityConfig(Parcel in) {
-            mHints = new ArraySet<>(in.createStringArrayList());
-            mExcludedEntityTypes = new ArraySet<>(in.createStringArrayList());
-            mIncludedEntityTypes = new ArraySet<>(in.createStringArrayList());
-            mUseHints = in.readInt() == 1;
+
+
+        /** Builder class to construct the {@link EntityConfig} object. */
+        public static final class Builder {
+            @Nullable
+            private Collection<String> mIncludedTypes;
+            @Nullable
+            private Collection<String> mExcludedTypes;
+            @Nullable
+            private Collection<String> mHints;
+            private boolean mIncludeTypesFromTextClassifier = true;
+
+            /**
+             * Sets a collection of types that are explicitly included.
+             */
+            @NonNull
+            public Builder setIncludedTypes(@Nullable Collection<String> includedTypes) {
+                mIncludedTypes = includedTypes;
+                return this;
+            }
+
+            /**
+             * Sets a collection of types that are explicitly excluded.
+             */
+            @NonNull
+            public Builder setExcludedTypes(@Nullable Collection<String> excludedTypes) {
+                mExcludedTypes = excludedTypes;
+                return this;
+            }
+
+            /**
+             * Specifies whether or not to include the types suggested by the text classifier. By
+             * default, it is included.
+             */
+            @NonNull
+            public Builder includeTypesFromTextClassifier(boolean includeTypesFromTextClassifier) {
+                mIncludeTypesFromTextClassifier = includeTypesFromTextClassifier;
+                return this;
+            }
+
+
+            /**
+             * Sets the hints for the TextClassifier to determine what types of entities to find.
+             * These hints will only be used if {@link #includeTypesFromTextClassifier} is
+             * set to be true.
+             */
+            public Builder setHints(Collection<String> hints) {
+                mHints = hints;
+                return this;
+            }
+
+            /**
+             * Combines all of the options that have been set and returns a new {@link EntityConfig}
+             * object.
+             */
+            @NonNull
+            public EntityConfig build() {
+                return new EntityConfig(
+                        mIncludedTypes == null
+                                ? Collections.emptyList()
+                                : new ArrayList<>(mIncludedTypes),
+                        mExcludedTypes == null
+                                ? Collections.emptyList()
+                                : new ArrayList<>(mExcludedTypes),
+                        mHints == null
+                                ? Collections.emptyList()
+                                : Collections.unmodifiableList(new ArrayList<>(mHints)),
+                        mIncludeTypesFromTextClassifier);
+            }
         }
     }
 
diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java
index f2fea02..b84f6f0 100644
--- a/core/java/android/view/textclassifier/TextClassifierEvent.java
+++ b/core/java/android/view/textclassifier/TextClassifierEvent.java
@@ -116,6 +116,8 @@
     public static final int TYPE_SELECTION_RESET = 18;
     /** User composed a reply. */
     public static final int TYPE_MANUAL_REPLY = 19;
+    /** TextClassifier generated some actions */
+    public static final int TYPE_ACTIONS_GENERATED = 20;
 
     @Category private final int mEventCategory;
     @Type private final int mEventType;
diff --git a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
new file mode 100644
index 0000000..439e594
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.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 distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_ENTITY_TYPE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_SESSION_ID;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_WIDGET_TYPE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_WIDGET_VERSION;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXTCLASSIFIER_MODEL;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_EVENT_TIME;
+
+import android.metrics.LogMaker;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.Preconditions;
+
+
+/**
+ * Log {@link TextClassifierEvent} by using Tron, only support language detection and
+ * conversation actions.
+ *
+ * @hide
+ */
+public final class TextClassifierEventTronLogger {
+
+    private static final String TAG = "TCEventTronLogger";
+
+    private final MetricsLogger mMetricsLogger;
+
+    public TextClassifierEventTronLogger() {
+        mMetricsLogger = new MetricsLogger();
+    }
+
+    @VisibleForTesting
+    public TextClassifierEventTronLogger(MetricsLogger metricsLogger) {
+        mMetricsLogger = Preconditions.checkNotNull(metricsLogger);
+    }
+
+    /** Emits a text classifier event to the logs. */
+    public void writeEvent(TextClassifierEvent event) {
+        Preconditions.checkNotNull(event);
+        int category = getCategory(event);
+        if (category == -1) {
+            Log.w(TAG, "Unknown category: " + event.getEventCategory());
+            return;
+        }
+        final LogMaker log = new LogMaker(category)
+                .setType(getLogType(event))
+                .addTaggedData(FIELD_SELECTION_SESSION_ID, event.getResultId())
+                .addTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME, event.getEventTime())
+                .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL,
+                        SelectionSessionLogger.SignatureParser.getModelName(event.getResultId()))
+                .addTaggedData(FIELD_SELECTION_ENTITY_TYPE, event.getEntityType());
+        TextClassificationContext eventContext = event.getEventContext();
+        if (eventContext != null) {
+            log.addTaggedData(FIELD_SELECTION_WIDGET_TYPE, eventContext.getWidgetType());
+            log.addTaggedData(FIELD_SELECTION_WIDGET_VERSION, eventContext.getWidgetVersion());
+            log.setPackageName(eventContext.getPackageName());
+        }
+        mMetricsLogger.write(log);
+        debugLog(log);
+    }
+
+    private static int getCategory(TextClassifierEvent event) {
+        switch (event.getEventCategory()) {
+            case TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS:
+                return MetricsEvent.CONVERSATION_ACTIONS;
+            case TextClassifierEvent.CATEGORY_LANGUAGE_DETECTION:
+                return MetricsEvent.LANGUAGE_DETECTION;
+        }
+        return -1;
+    }
+
+    private static int getLogType(TextClassifierEvent event) {
+        switch (event.getEventType()) {
+            case TextClassifierEvent.TYPE_SMART_ACTION:
+                return MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE;
+            case TextClassifierEvent.TYPE_ACTIONS_SHOWN:
+                return MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_SHOWN;
+            case TextClassifierEvent.TYPE_MANUAL_REPLY:
+                return MetricsEvent.ACTION_TEXT_CLASSIFIER_MANUAL_REPLY;
+            default:
+                return MetricsEvent.VIEW_UNKNOWN;
+        }
+    }
+
+    private String toCategoryName(int category) {
+        switch (category) {
+            case MetricsEvent.CONVERSATION_ACTIONS:
+                return "conversation_actions";
+            case MetricsEvent.LANGUAGE_DETECTION:
+                return "language_detection";
+        }
+        return "unknown";
+    }
+
+    private String toEventName(int logType) {
+        switch (logType) {
+            case MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE:
+                return "smart_share";
+            case MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_SHOWN:
+                return "actions_shown";
+            case MetricsEvent.ACTION_TEXT_CLASSIFIER_MANUAL_REPLY:
+                return "manual_reply";
+            case MetricsEvent.ACTION_TEXT_CLASSIFIER_ACTIONS_GENERATED:
+                return "actions_generated";
+        }
+        return "unknown";
+    }
+
+    private void debugLog(LogMaker log) {
+        if (!Log.ENABLE_FULL_LOGGING) {
+            return;
+        }
+        final String id = String.valueOf(log.getTaggedData(FIELD_SELECTION_SESSION_ID));
+        final String categoryName = toCategoryName(log.getCategory());
+        final String eventName = toEventName(log.getType());
+        final String widgetType = String.valueOf(log.getTaggedData(FIELD_SELECTION_WIDGET_TYPE));
+        final String widgetVersion =
+                String.valueOf(log.getTaggedData(FIELD_SELECTION_WIDGET_VERSION));
+        final String model = String.valueOf(log.getTaggedData(FIELD_TEXTCLASSIFIER_MODEL));
+        final String entityType = String.valueOf(log.getTaggedData(FIELD_SELECTION_ENTITY_TYPE));
+
+        StringBuilder builder = new StringBuilder();
+        builder.append("writeEvent: ");
+        builder.append("id=").append(id);
+        builder.append(", category=").append(categoryName);
+        builder.append(", eventName=").append(eventName);
+        builder.append(", widgetType=").append(widgetType);
+        builder.append(", widgetVersion=").append(widgetVersion);
+        builder.append(", model=").append(model);
+        builder.append(", entityType=").append(entityType);
+
+        Log.v(TAG, builder.toString());
+    }
+}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index fcd06c3..9ab963e 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -115,9 +115,9 @@
     @GuardedBy("mLock") // Do not access outside this lock.
     private ActionsSuggestionsModel mActionsImpl;
 
-    private final Object mLoggerLock = new Object();
-    @GuardedBy("mLoggerLock") // Do not access outside this lock.
-    private SelectionSessionLogger mSessionLogger;
+    private final SelectionSessionLogger mSessionLogger = new SelectionSessionLogger();
+    private final TextClassifierEventTronLogger mTextClassifierEventTronLogger =
+            new TextClassifierEventTronLogger();
 
     private final TextClassificationConstants mSettings;
 
@@ -337,12 +337,7 @@
     @Override
     public void onSelectionEvent(SelectionEvent event) {
         Preconditions.checkNotNull(event);
-        synchronized (mLoggerLock) {
-            if (mSessionLogger == null) {
-                mSessionLogger = new SelectionSessionLogger();
-            }
-            mSessionLogger.writeEvent(event);
-        }
+        mSessionLogger.writeEvent(event);
     }
 
     @Override
@@ -350,6 +345,7 @@
         if (DEBUG) {
             Log.d(DEFAULT_LOG_TAG, "onTextClassifierEvent() called with: event = [" + event + "]");
         }
+        mTextClassifierEventTronLogger.writeEvent(event);
     }
 
     /** @inheritDoc */
@@ -397,7 +393,7 @@
                     actionsImpl.suggestActions(nativeConversation, null);
 
             Collection<String> expectedTypes = resolveActionTypesFromRequest(request);
-            List<ConversationActions.ConversationAction> conversationActions = new ArrayList<>();
+            List<ConversationAction> conversationActions = new ArrayList<>();
             int maxSuggestions = nativeSuggestions.length;
             if (request.getMaxSuggestions() > 0) {
                 maxSuggestions = Math.min(request.getMaxSuggestions(), nativeSuggestions.length);
@@ -409,7 +405,7 @@
                     continue;
                 }
                 conversationActions.add(
-                        new ConversationActions.ConversationAction.Builder(actionType)
+                        new ConversationAction.Builder(actionType)
                                 .setTextReply(nativeSuggestion.getResponseText())
                                 .setConfidenceScore(nativeSuggestion.getScore())
                                 .build());
@@ -449,10 +445,10 @@
 
     private Collection<String> resolveActionTypesFromRequest(ConversationActions.Request request) {
         List<String> defaultActionTypes =
-                request.getHints().contains(ConversationActions.HINT_FOR_NOTIFICATION)
+                request.getHints().contains(ConversationActions.Request.HINT_FOR_NOTIFICATION)
                         ? mSettings.getNotificationConversationActionTypes()
                         : mSettings.getInAppConversationActionTypes();
-        return request.getTypeConfig().resolveTypes(defaultActionTypes);
+        return request.getTypeConfig().resolveEntityListModifications(defaultActionTypes);
     }
 
     private AnnotatorModel getAnnotatorImpl(LocaleList localeList)
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index 9733701..f553ca5 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -27,7 +27,6 @@
 
 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 dalvik.system.CloseGuard;
@@ -96,7 +95,7 @@
     private static final int MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE = 2;
 
     private final InternalListener mInternalListener;
-    private final ITextServicesManager mTextServicesManager;
+    private final TextServicesManager mTextServicesManager;
     private final SpellCheckerInfo mSpellCheckerInfo;
     @UnsupportedAppUsage
     private final SpellCheckerSessionListener mSpellCheckerSessionListener;
@@ -124,7 +123,7 @@
      * @hide
      */
     public SpellCheckerSession(
-            SpellCheckerInfo info, ITextServicesManager tsm, SpellCheckerSessionListener listener) {
+            SpellCheckerInfo info, TextServicesManager tsm, SpellCheckerSessionListener listener) {
         if (info == null || listener == null || tsm == null) {
             throw new NullPointerException();
         }
@@ -166,12 +165,8 @@
      */
     public void close() {
         mGuard.close();
-        try {
-            mSpellCheckerSessionListenerImpl.close();
-            mTextServicesManager.finishSpellCheckerService(mSpellCheckerSessionListenerImpl);
-        } catch (RemoteException e) {
-            // do nothing
-        }
+        mSpellCheckerSessionListenerImpl.close();
+        mTextServicesManager.finishSpellCheckerService(mSpellCheckerSessionListenerImpl);
     }
 
     /**
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index 4c6862c..9ff64d9 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -16,16 +16,20 @@
 
 package android.view.textservice;
 
+import android.annotation.NonNull;
 import android.annotation.SystemService;
 import android.annotation.UnsupportedAppUsage;
+import android.annotation.UserIdInt;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener;
 
+import com.android.internal.textservice.ISpellCheckerSessionListener;
 import com.android.internal.textservice.ITextServicesManager;
 
 import java.util.Locale;
@@ -68,22 +72,40 @@
     private static final boolean DBG = false;
 
     /**
-     * A compile time switch to control per-profile spell checker, which is not yet ready.
-     * @hide
+     * @deprecated Do not use. Just kept because of {@link UnsupportedAppUsage} in
+     * {@link #getInstance()}.
      */
-    public static final boolean DISABLE_PER_PROFILE_SPELL_CHECKER = true;
-
+    @Deprecated
     private static TextServicesManager sInstance;
 
     private final ITextServicesManager mService;
 
-    private TextServicesManager() throws ServiceNotFoundException {
+    @UserIdInt
+    private final int mUserId;
+
+    private TextServicesManager(@UserIdInt int userId) throws ServiceNotFoundException {
         mService = ITextServicesManager.Stub.asInterface(
                 ServiceManager.getServiceOrThrow(Context.TEXT_SERVICES_MANAGER_SERVICE));
+        mUserId = userId;
     }
 
     /**
-     * Retrieve the global TextServicesManager instance, creating it if it doesn't already exist.
+     * The factory method of {@link TextServicesManager}.
+     *
+     * @param context {@link Context} from which {@link TextServicesManager} should be instantiated.
+     * @return {@link TextServicesManager} that is associated with {@link Context#getUserId()}.
+     * @throws ServiceNotFoundException When {@link TextServicesManager} is not available.
+     * @hide
+     */
+    @NonNull
+    public static TextServicesManager createInstance(@NonNull Context context)
+            throws ServiceNotFoundException {
+        return new TextServicesManager(context.getUserId());
+    }
+
+    /**
+     * @deprecated Do not use. Just kept because of {@link UnsupportedAppUsage} in
+     * {@link #getInstance()}.
      * @hide
      */
     @UnsupportedAppUsage
@@ -91,7 +113,7 @@
         synchronized (TextServicesManager.class) {
             if (sInstance == null) {
                 try {
-                    sInstance = new TextServicesManager();
+                    sInstance = new TextServicesManager(UserHandle.myUserId());
                 } catch (ServiceNotFoundException e) {
                     throw new IllegalStateException(e);
                 }
@@ -142,7 +164,7 @@
 
         final SpellCheckerInfo sci;
         try {
-            sci = mService.getCurrentSpellChecker(null);
+            sci = mService.getCurrentSpellChecker(mUserId, null);
         } catch (RemoteException e) {
             return null;
         }
@@ -180,9 +202,9 @@
         if (subtypeInUse == null) {
             return null;
         }
-        final SpellCheckerSession session = new SpellCheckerSession(sci, mService, listener);
+        final SpellCheckerSession session = new SpellCheckerSession(sci, this, listener);
         try {
-            mService.getSpellCheckerService(sci.getId(), subtypeInUse.getLocale(),
+            mService.getSpellCheckerService(mUserId, sci.getId(), subtypeInUse.getLocale(),
                     session.getTextServicesSessionListener(),
                     session.getSpellCheckerSessionListener(), bundle);
         } catch (RemoteException e) {
@@ -197,7 +219,7 @@
     @UnsupportedAppUsage
     public SpellCheckerInfo[] getEnabledSpellCheckers() {
         try {
-            final SpellCheckerInfo[] retval = mService.getEnabledSpellCheckers();
+            final SpellCheckerInfo[] retval = mService.getEnabledSpellCheckers(mUserId);
             if (DBG) {
                 Log.d(TAG, "getEnabledSpellCheckers: " + (retval != null ? retval.length : "null"));
             }
@@ -214,7 +236,7 @@
     public SpellCheckerInfo getCurrentSpellChecker() {
         try {
             // Passing null as a locale for ICS
-            return mService.getCurrentSpellChecker(null);
+            return mService.getCurrentSpellChecker(mUserId, null);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -227,7 +249,7 @@
     public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
             boolean allowImplicitlySelectedSubtype) {
         try {
-            return mService.getCurrentSpellCheckerSubtype(allowImplicitlySelectedSubtype);
+            return mService.getCurrentSpellCheckerSubtype(mUserId, allowImplicitlySelectedSubtype);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -239,7 +261,15 @@
     @UnsupportedAppUsage
     public boolean isSpellCheckerEnabled() {
         try {
-            return mService.isSpellCheckerEnabled();
+            return mService.isSpellCheckerEnabled(mUserId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    void finishSpellCheckerService(ISpellCheckerSessionListener listener) {
+        try {
+            mService.finishSpellCheckerService(mUserId, listener);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index bad2dbf..6039350 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -69,6 +70,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Executor;
 
 /**
  * A View that displays web pages.
@@ -1688,6 +1690,84 @@
         return mProvider.getWebViewClient();
     }
 
+
+    /**
+     * Gets the WebView renderer associated with this WebView.
+     *
+     * <p>In {@link android.os.Build.VERSION_CODES#O} and above, WebView may
+     * run in "multiprocess" mode. In multiprocess mode, rendering of web
+     * content is performed by a sandboxed renderer process separate to the
+     * application process.  This renderer process may be shared with other
+     * WebViews in the application, but is not shared with other application
+     * processes.
+     *
+     * <p>If WebView is running in multiprocess mode, this method returns a
+     * handle to the renderer process associated with the WebView, which can
+     * be used to control the renderer process.
+     *
+     * @return the {@link WebViewRenderer} renderer handle associated
+     *         with this {@link WebView}, or {@code null} if
+     *         WebView is not runing in multiprocess mode.
+     */
+    @Nullable
+    public WebViewRenderer getWebViewRenderer() {
+        checkThread();
+        return mProvider.getWebViewRenderer();
+    }
+
+    /**
+     * Sets the renderer client object associated with this WebView.
+     *
+     * <p>The renderer client encapsulates callbacks relevant to WebView renderer
+     * state. See {@link WebViewRendererClient} for details.
+     *
+     * <p>Although many WebView instances may share a single underlying
+     * renderer, and renderers may live either in the application
+     * process, or in a sandboxed process that is isolated from the
+     * application process, instances of {@link WebViewRendererClient}
+     * are set per-WebView.  Callbacks represent renderer events from
+     * the perspective of this WebView, and may or may not be correlated
+     * with renderer events affecting other WebViews.
+     *
+     * @param executor the Executor on which {@link WebViewRendererClient} callbacks will execute.
+     * @param webViewRendererClient the {@link WebViewRendererClient} object.
+     */
+    public void setWebViewRendererClient(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull WebViewRendererClient webViewRendererClient) {
+        checkThread();
+        mProvider.setWebViewRendererClient(executor, webViewRendererClient);
+    }
+
+    /**
+     * Sets the renderer client object associated with this WebView.
+     *
+     * See {@link #setWebViewRendererClient(Executor,WebViewRendererClient)} for details.
+     *
+     * <p> {@link WebViewRendererClient} callbacks will run on the thread that this WebView was
+     * initialized on.
+     *
+     * @param webViewRendererClient the {@link WebViewRendererClient} object.
+     */
+    public void setWebViewRendererClient(
+            @Nullable WebViewRendererClient webViewRendererClient) {
+        checkThread();
+        mProvider.setWebViewRendererClient(null, webViewRendererClient);
+    }
+
+    /**
+     * Gets the renderer client object associated with this WebView.
+     *
+     * @return the {@link WebViewRendererClient} object associated with this WebView, if one has
+     * been set via {@link #setWebViewRendererClient(WebViewRendererClient)} or {@code null}
+     * otherwise.
+     */
+    @Nullable
+    public WebViewRendererClient getWebViewRendererClient() {
+        checkThread();
+        return mProvider.getWebViewRendererClient();
+    }
+
     /**
      * Registers the interface to be used when content can not be handled by
      * the rendering engine, and should be downloaded instead. This will replace
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 300bb6f..090640e 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -379,11 +379,16 @@
 
     /**
      * Notify the host application that an SSL error occurred while loading a
-     * resource. The host application must call either handler.cancel() or
-     * handler.proceed(). Note that the decision may be retained for use in
+     * resource. The host application must call either {@link SslErrorHandler#cancel} or
+     * {@link SslErrorHandler#proceed}. Note that the decision may be retained for use in
      * response to future SSL errors. The default behavior is to cancel the
      * load.
      * <p>
+     * This API is only called for recoverable SSL certificate errors. In the case of
+     * non-recoverable errors (such as when the server fails the client), WebView will call {@link
+     * #onReceivedError(WebView, WebResourceRequest, WebResourceError)} with {@link
+     * #ERROR_FAILED_SSL_HANDSHAKE}.
+     * <p>
      * Applications are advised not to prompt the user about SSL errors, as
      * the user is unlikely to be able to make an informed security decision
      * and WebView does not provide any UI for showing the details of the
@@ -391,10 +396,10 @@
      * <p>
      * Application overrides of this method may display custom error pages or
      * silently log issues, but it is strongly recommended to always call
-     * handler.cancel() and never allow proceeding past errors.
+     * {@link SslErrorHandler#cancel} and never allow proceeding past errors.
      *
      * @param view The WebView that is initiating the callback.
-     * @param handler An SslErrorHandler object that will handle the user's
+     * @param handler An {@link SslErrorHandler} that will handle the user's
      *            response.
      * @param error The SSL error object.
      */
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 6ab7f66..ef69b63 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -138,6 +138,20 @@
     }
 
     /**
+     * Call webview draw functor. See API in draw_fn.h.
+     * @param canvas a hardware accelerated canvas (see {@link Canvas#isHardwareAccelerated()}).
+     * @param functor created by AwDrawFn_CreateFunctor in draw_fn.h.
+     */
+    public void drawWebViewFunctor(@NonNull Canvas canvas, int functor) {
+        if (!(canvas instanceof RecordingCanvas)) {
+            // Canvas#isHardwareAccelerated() is only true for subclasses of RecordingCanvas.
+            throw new IllegalArgumentException(canvas.getClass().getName()
+                    + " is not a RecordingCanvas canvas");
+        }
+        ((RecordingCanvas) canvas).drawWebViewFunctor(functor);
+    }
+
+    /**
      * Detaches the draw GL functor.
      *
      * @param nativeDrawGLFunctor the pointer to the native functor that implements
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 95e7a986..baf5826 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -54,6 +54,7 @@
 import java.io.BufferedWriter;
 import java.io.File;
 import java.util.Map;
+import java.util.concurrent.Executor;
 
 /**
  * WebView backend provider interface: this interface is the abstract backend to a WebView
@@ -237,6 +238,14 @@
 
     public WebViewClient getWebViewClient();
 
+    public WebViewRenderer getWebViewRenderer();
+
+    public void setWebViewRendererClient(
+            @Nullable Executor executor,
+            @Nullable WebViewRendererClient client);
+
+    public WebViewRendererClient getWebViewRendererClient();
+
     public void setDownloadListener(DownloadListener listener);
 
     public void setWebChromeClient(WebChromeClient client);
diff --git a/core/java/android/webkit/WebViewRenderer.java b/core/java/android/webkit/WebViewRenderer.java
new file mode 100644
index 0000000..fc38cd9
--- /dev/null
+++ b/core/java/android/webkit/WebViewRenderer.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.annotation.SystemApi;
+
+/**
+ * WebViewRenderer provides an opaque handle to a {@link WebView} renderer.
+ */
+public abstract class WebViewRenderer {
+    /**
+     * Cause this renderer to terminate.
+     *
+     * <p>Calling this on a not yet started, or an already terminated renderer will have no effect.
+     *
+     * <p>Terminating a renderer process may have an effect on multiple {@link WebView} instances.
+     *
+     * <p>Renderer termination must be handled by properly overriding
+     * {@link WebViewClient#onRenderProcessGone} for every WebView that shares this
+     * renderer. If termination is not handled by all associated WebViews, then the application
+     * process will also be terminated.
+     *
+     * @return {@code true} if it was possible to terminate this renderer, {@code false} otherwise.
+     */
+    public abstract boolean terminate();
+
+    /**
+     * This class cannot be created by applications.
+     * @hide
+     */
+    @SystemApi
+    public WebViewRenderer() {
+    }
+}
diff --git a/core/java/android/webkit/WebViewRendererClient.java b/core/java/android/webkit/WebViewRendererClient.java
new file mode 100644
index 0000000..2fadf54
--- /dev/null
+++ b/core/java/android/webkit/WebViewRendererClient.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * Used to receive callbacks on {@link WebView} renderer events.
+ *
+ * WebViewRendererClient instances may be set or retrieved via {@link
+ * WebView#setWebViewRendererClient(WebViewRendererClient)} and {@link
+ * WebView#getWebViewRendererClient()}.
+ *
+ * Instances may be attached to multiple WebViews, and thus a single renderer event may cause
+ * a callback to be called multiple times with different WebView parameters.
+ */
+public abstract class WebViewRendererClient {
+    /**
+     * Called when the renderer currently associated with {@code view} becomes unresponsive as a
+     * result of a long running blocking task such as the execution of JavaScript.
+     *
+     * <p>If a WebView fails to process an input event, or successfully navigate to a new URL within
+     * a reasonable time frame, the renderer is considered to be unresponsive, and this callback
+     * will be called.
+     *
+     * <p>This callback will continue to be called at regular intervals as long as the renderer
+     * remains unresponsive. If the renderer becomes responsive again, {@link
+     * WebViewRendererClient#onRendererResponsive} will be called once, and this method will not
+     * subsequently be called unless another period of unresponsiveness is detected.
+     *
+     * <p>No action is taken by WebView as a result of this method call. Applications may
+     * choose to terminate the associated renderer via the object that is passed to this callback,
+     * if in multiprocess mode, however this must be accompanied by correctly handling
+     * {@link WebViewClient#onRenderProcessGone} for this WebView, and all other WebViews associated
+     * with the same renderer. Failure to do so will result in application termination.
+     *
+     * @param view The {@link WebView} for which unresponsiveness was detected.
+     * @param renderer The {@link WebViewRenderer} that has become unresponsive,
+     * or {@code null} if WebView is running in single process mode.
+     */
+    public abstract void onRendererUnresponsive(
+            @NonNull WebView view, @Nullable WebViewRenderer renderer);
+
+    /**
+     * Called once when an unresponsive renderer currently associated with {@code view} becomes
+     * responsive.
+     *
+     * <p>After a WebView renderer becomes unresponsive, which is notified to the application by
+     * {@link WebViewRendererClient#onRendererUnresponsive}, it is possible for the blocking
+     * renderer task to complete, returning the renderer to a responsive state. In that case,
+     * this method is called once to indicate responsiveness.
+     *
+     * <p>No action is taken by WebView as a result of this method call.
+     *
+     * @param view The {@link WebView} for which responsiveness was detected.
+     *
+     * @param renderer The {@link WebViewRenderer} that has become responsive, or {@code null} if
+     * WebView is running in single process mode.
+     */
+    public abstract void onRendererResponsive(
+            @NonNull WebView view, @Nullable WebViewRenderer renderer);
+}
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 49e11b8..3a1c457 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -150,7 +150,7 @@
         }
 
         try {
-            sZygote = Process.zygoteProcess.startChildZygote(
+            sZygote = Process.ZYGOTE_PROCESS.startChildZygote(
                     "com.android.internal.os.WebViewZygoteInit",
                     "webview_zygote",
                     Process.WEBVIEW_ZYGOTE_UID,
@@ -159,7 +159,10 @@
                     0,  // runtimeFlags
                     "webview_zygote",  // seInfo
                     sPackage.applicationInfo.primaryCpuAbi,  // abi
-                    null);  // instructionSet
+                    TextUtils.join(",", Build.SUPPORTED_ABIS),
+                    null, // instructionSet
+                    Process.FIRST_ISOLATED_UID,
+                    Process.LAST_ISOLATED_UID);
 
             // All the work below is usually done by LoadedApk, but the zygote can't talk to
             // PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 3c32bb2..4a60b6a 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2394,6 +2394,17 @@
         }
     }
 
+    /**
+     * Called when {@link TextView#mTextOperationUser} has changed.
+     *
+     * <p>Any user-specific resources need to be refreshed here.</p>
+     */
+    final void onTextOperationUserChanged() {
+        if (mSpellChecker != null) {
+            mSpellChecker.resetSession();
+        }
+    }
+
     protected void stopTextActionMode() {
         if (mTextActionMode != null) {
             // This will hide the mSelectionModifierCursorController
@@ -2890,10 +2901,6 @@
             }
         }
 
-        // Notify source IME of the suggestion pick. Do this before swapping texts.
-        targetSuggestionSpan.notifySelection(
-                mTextView.getContext(), originalText, suggestionInfo.mSuggestionIndex);
-
         // Swap text content between actual text and Suggestion span
         final int suggestionStart = suggestionInfo.mSuggestionStart;
         final int suggestionEnd = suggestionInfo.mSuggestionEnd;
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 7d02757..afe46701 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -104,8 +104,9 @@
     private final int mDefaultHorizontalSourceToMagnifierOffset;
     // The vertical offset between the source and window coords when #show(float, float) is used.
     private final int mDefaultVerticalSourceToMagnifierOffset;
-    // Whether the magnifier will be clamped inside the main surface and not overlap system insets.
-    private final boolean mForcePositionWithinWindowSystemInsetsBounds;
+    // Whether the area where the magnifier can be positioned will be clipped to the main window
+    // and within system insets.
+    private final boolean mClippingEnabled;
     // The behavior of the left bound of the rectangle where the content can be copied from.
     private @SourceBound int mLeftContentBound;
     // The behavior of the top bound of the rectangle where the content can be copied from.
@@ -165,7 +166,7 @@
         params.mOverlay = new ColorDrawable(a.getColor(
                 R.styleable.Magnifier_magnifierColorOverlay, Color.TRANSPARENT));
         a.recycle();
-        params.mForcePositionWithinWindowSystemInsetsBounds = true;
+        params.mClippingEnabled = true;
         params.mLeftContentBound = SOURCE_BOUND_MAX_VISIBLE;
         params.mTopContentBound = SOURCE_BOUND_MAX_IN_SURFACE;
         params.mRightContentBound = SOURCE_BOUND_MAX_VISIBLE;
@@ -203,8 +204,7 @@
                 params.mHorizontalDefaultSourceToMagnifierOffset;
         mDefaultVerticalSourceToMagnifierOffset =
                 params.mVerticalDefaultSourceToMagnifierOffset;
-        mForcePositionWithinWindowSystemInsetsBounds =
-                params.mForcePositionWithinWindowSystemInsetsBounds;
+        mClippingEnabled = params.mClippingEnabled;
         mLeftContentBound = params.mLeftContentBound;
         mTopContentBound = params.mTopContentBound;
         mRightContentBound = params.mRightContentBound;
@@ -271,7 +271,7 @@
             if (mWindow == null) {
                 synchronized (mLock) {
                     mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(),
-                            mParentSurface.mSurface, mWindowWidth, mWindowHeight,
+                            mParentSurface.mSurfaceControl, mWindowWidth, mWindowHeight,
                             mWindowElevation, mWindowCornerRadius,
                             mOverlay != null ? mOverlay : new ColorDrawable(Color.TRANSPARENT),
                             Handler.getMain() /* draw the magnifier on the UI thread */, mLock,
@@ -447,7 +447,7 @@
     }
 
     /**
-     * Returns the overlay to be drawn on the top of the magnifier content, or
+     * Returns the overlay to be drawn on the top of the magnifier, or
      * {@code null} if no overlay should be drawn.
      * @return the overlay
      * @see Magnifier.Builder#setOverlay(Drawable)
@@ -459,13 +459,15 @@
 
     /**
      * Returns whether the magnifier position will be adjusted such that the magnifier will be
-     * fully within the bounds of the main application window, by also avoiding any overlap with
-     * system insets (such as the one corresponding to the status bar).
+     * fully within the bounds of the main application window, by also avoiding any overlap
+     * with system insets (such as the one corresponding to the status bar) i.e. whether the
+     * area where the magnifier can be positioned will be clipped to the main application window
+     * and the system insets.
      * @return whether the magnifier position will be adjusted
-     * @see Magnifier.Builder#setForcePositionWithinWindowSystemInsetsBounds(boolean)
+     * @see Magnifier.Builder#setClippingEnabled(boolean)
      */
-    public boolean isForcePositionWithinWindowSystemInsetsBounds() {
-        return mForcePositionWithinWindowSystemInsetsBounds;
+    public boolean isClippingEnabled() {
+        return mClippingEnabled;
     }
 
     /**
@@ -528,17 +530,20 @@
                 final int surfaceHeight =
                         viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom;
                 validMainWindowSurface =
-                        new SurfaceInfo(mainWindowSurface, surfaceWidth, surfaceHeight, true);
+                        new SurfaceInfo(viewRootImpl.getSurfaceControl(), mainWindowSurface,
+                                surfaceWidth, surfaceHeight, true);
             }
         }
         // Get the surface backing the magnified view, if it is a SurfaceView.
         SurfaceInfo validSurfaceViewSurface = SurfaceInfo.NULL;
         if (mView instanceof SurfaceView) {
+            final SurfaceControl sc = ((SurfaceView) mView).getSurfaceControl();
             final SurfaceHolder surfaceHolder = ((SurfaceView) mView).getHolder();
             final Surface surfaceViewSurface = surfaceHolder.getSurface();
-            if (surfaceViewSurface != null && surfaceViewSurface.isValid()) {
+
+            if (sc != null && sc.isValid()) {
                 final Rect surfaceFrame = surfaceHolder.getSurfaceFrame();
-                validSurfaceViewSurface = new SurfaceInfo(surfaceViewSurface,
+                validSurfaceViewSurface = new SurfaceInfo(sc, surfaceViewSurface,
                         surfaceFrame.right, surfaceFrame.bottom, false);
             }
         }
@@ -708,7 +713,7 @@
      * @return the current window coordinates, after they are clamped inside the parent surface
      */
     private Point getCurrentClampedWindowCoordinates() {
-        if (!mForcePositionWithinWindowSystemInsetsBounds) {
+        if (!mClippingEnabled) {
             // No position adjustment should be done, so return the raw coordinates.
             return new Point(mWindowCoords);
         }
@@ -733,15 +738,18 @@
      * Contains a surface and metadata corresponding to it.
      */
     private static class SurfaceInfo {
-        public static final SurfaceInfo NULL = new SurfaceInfo(null, 0, 0, false);
+        public static final SurfaceInfo NULL = new SurfaceInfo(null, null, 0, 0, false);
 
         private Surface mSurface;
+        private SurfaceControl mSurfaceControl;
         private int mWidth;
         private int mHeight;
         private boolean mIsMainWindowSurface;
 
-        SurfaceInfo(final Surface surface, final int width, final int height,
+        SurfaceInfo(final SurfaceControl surfaceControl, final Surface surface,
+                final int width, final int height,
                 final boolean isMainWindowSurface) {
+            mSurfaceControl = surfaceControl;
             mSurface = surface;
             mWidth = width;
             mHeight = height;
@@ -819,7 +827,7 @@
         private Bitmap mCurrentContent;
 
         InternalPopupWindow(final Context context, final Display display,
-                final Surface parentSurface, final int width, final int height,
+                final SurfaceControl parentSurfaceControl, final int width, final int height,
                 final float elevation, final float cornerRadius, final Drawable overlay,
                 final Handler handler, final Object lock, final Callback callback) {
             mDisplay = display;
@@ -829,17 +837,18 @@
 
             mContentWidth = width;
             mContentHeight = height;
-            mOffsetX = (int) (0.1f * width);
-            mOffsetY = (int) (0.1f * height);
+            mOffsetX = (int) (1.05f * elevation);
+            mOffsetY = (int) (1.05f * elevation);
             // Setup the surface we will use for drawing the content and shadow.
             mSurfaceWidth = mContentWidth + 2 * mOffsetX;
             mSurfaceHeight = mContentHeight + 2 * mOffsetY;
-            mSurfaceSession = new SurfaceSession(parentSurface);
+            mSurfaceSession = new SurfaceSession();
             mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
                     .setFormat(PixelFormat.TRANSLUCENT)
                     .setBufferSize(mSurfaceWidth, mSurfaceHeight)
                     .setName("magnifier surface")
                     .setFlags(SurfaceControl.HIDDEN)
+                    .setParent(parentSurfaceControl)
                     .build();
             mSurface = new Surface();
             mSurface.copyFrom(mSurfaceControl);
@@ -1129,7 +1138,7 @@
         private @Nullable Drawable mOverlay;
         private int mHorizontalDefaultSourceToMagnifierOffset;
         private int mVerticalDefaultSourceToMagnifierOffset;
-        private boolean mForcePositionWithinWindowSystemInsetsBounds;
+        private boolean mClippingEnabled;
         private @SourceBound int mLeftContentBound;
         private @SourceBound int mTopContentBound;
         private @SourceBound int mRightContentBound;
@@ -1157,7 +1166,7 @@
                     resources.getDimensionPixelSize(R.dimen.default_magnifier_vertical_offset);
             mOverlay = new ColorDrawable(resources.getColor(
                     R.color.default_magnifier_color_overlay, null));
-            mForcePositionWithinWindowSystemInsetsBounds = true;
+            mClippingEnabled = true;
             mLeftContentBound = SOURCE_BOUND_MAX_VISIBLE;
             mTopContentBound = SOURCE_BOUND_MAX_VISIBLE;
             mRightContentBound = SOURCE_BOUND_MAX_VISIBLE;
@@ -1220,11 +1229,11 @@
         }
 
         /**
-         * Sets an overlay that will be drawn on the top of the magnifier content.
-         * In general, the overlay should not be opaque, in order to let the expected magnifier
-         * content be partially visible. The default overlay is {@code null} (no overlay).
-         * As an example, TextView applies a white {@link ColorDrawable} overlay with
-         * 5% alpha, aiming to make the magnifier distinguishable when shown in dark
+         * Sets an overlay that will be drawn on the top of the magnifier.
+         * In general, the overlay should not be opaque, in order to let the magnified
+         * content be partially visible in the magnifier. The default overlay is {@code null}
+         * (no overlay). As an example, TextView applies a white {@link ColorDrawable}
+         * overlay with 5% alpha, aiming to make the magnifier distinguishable when shown in dark
          * application regions. To disable the overlay, the parameter should be set
          * to {@code null}. If not null, the overlay will be automatically redrawn
          * when the drawable is invalidated. To achieve this, the magnifier will set a new
@@ -1258,22 +1267,24 @@
          * Defines the behavior of the magnifier when it is requested to position outside the
          * surface of the main application window. The default value is {@code true}, which means
          * that the position will be adjusted such that the magnifier will be fully within the
-         * bounds of the main application window, by also avoiding any overlap with system insets
-         * (such as the one corresponding to the status bar). If you require a custom behavior, this
-         * flag should be set to {@code false}, meaning that the magnifier will be able to cross the
-         * main application surface boundaries (and also overlap the system insets). This should be
-         * handled with care, when passing coordinates to {@link #show(float, float)}; note that:
+         * bounds of the main application window, while also avoiding any overlap with system insets
+         * (such as the one corresponding to the status bar). If this flag is set to {@code false},
+         * the area where the magnifier can be positioned will no longer be clipped, so the
+         * magnifier will be able to extend outside the main application window boundaries (and also
+         * overlap the system insets). This can be useful if you require a custom behavior, but it
+         * should be handled with care, when passing coordinates to {@link #show(float, float)};
+         * note that:
          * <ul>
          *   <li>in a multiwindow context, if the magnifier crosses the boundary between the two
          *   windows, it will not be able to show over the window of the other application</li>
          *   <li>if the magnifier overlaps the status bar, there is no guarantee about which one
          *   will be displayed on top. This should be handled with care.</li>
          * </ul>
-         * @param force whether the magnifier position will be adjusted
+         * @param clip whether the magnifier position will be adjusted
          */
         @NonNull
-        public Builder setForcePositionWithinWindowSystemInsetsBounds(boolean force) {
-            mForcePositionWithinWindowSystemInsetsBounds = force;
+        public Builder setClippingEnabled(boolean clip) {
+            mClippingEnabled = clip;
             return this;
         }
 
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index fc1172e..d4aad75 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -16,7 +16,7 @@
 
 package android.widget;
 
-import android.content.Context;
+import android.annotation.Nullable;
 import android.text.Editable;
 import android.text.Selection;
 import android.text.Spanned;
@@ -93,6 +93,7 @@
     // concurrently due to the asynchronous nature of onGetSuggestions.
     private WordIterator mWordIterator;
 
+    @Nullable
     private TextServicesManager mTextServicesManager;
 
     private Runnable mSpellRunnable;
@@ -114,12 +115,12 @@
         mCookie = hashCode();
     }
 
-    private void resetSession() {
+    void resetSession() {
         closeSession();
 
-        mTextServicesManager = (TextServicesManager) mTextView.getContext().
-                getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
+        mTextServicesManager = mTextView.getTextServicesManagerForUser();
         if (mCurrentLocale == null
+                || mTextServicesManager == null
                 || mTextView.length() == 0
                 || !mTextServicesManager.isSpellCheckerEnabled()
                 || mTextServicesManager.getCurrentSpellCheckerSubtype(true) == null) {
@@ -226,7 +227,8 @@
             start = 0;
             end = mTextView.getText().length();
         } else {
-            final boolean spellCheckerActivated = mTextServicesManager.isSpellCheckerEnabled();
+            final boolean spellCheckerActivated =
+                    mTextServicesManager != null && mTextServicesManager.isSpellCheckerEnabled();
             if (isSessionActive != spellCheckerActivated) {
                 // Spell checker has been turned of or off since last spellCheck
                 resetSession();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0ea8579..780fe8d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH;
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX;
 import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY;
@@ -31,6 +32,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Px;
+import android.annotation.RequiresPermission;
 import android.annotation.Size;
 import android.annotation.StringRes;
 import android.annotation.StyleRes;
@@ -45,10 +47,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.UndoManager;
+import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
-import android.content.res.ResourceId;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
@@ -74,7 +76,9 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.ParcelableParcel;
+import android.os.Process;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.BoringLayout;
 import android.text.DynamicLayout;
@@ -195,6 +199,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
@@ -786,6 +791,19 @@
 
     private InputFilter[] mFilters = NO_FILTERS;
 
+    /**
+     * {@link UserHandle} that represents the logical owner of the text. {@code null} when it is
+     * the same as {@link Process#myUserHandle()}.
+     *
+     * <p>Most of applications should not worry about this. Some privileged apps that host UI for
+     * other apps may need to set this so that the system can use right user's resources and
+     * services such as input methods and spell checkers.</p>
+     *
+     * @see #setTextOperationUser(UserHandle)
+     */
+    @Nullable
+    private UserHandle mTextOperationUser;
+
     private volatile Locale mCurrentSpellCheckerLocaleCache;
 
     // It is possible to have a selection even when mEditor is null (programmatically set, like when
@@ -889,7 +907,7 @@
     // sanitize autofill requests.
     private boolean mTextSetFromXmlOrResourceId = false;
     // Resource id used to set the text.
-    private @StringRes int mTextId = ResourceId.ID_NULL;
+    private @StringRes int mTextId = Resources.ID_NULL;
     //
     // End of autofill-related attributes
 
@@ -1180,7 +1198,7 @@
 
                 case com.android.internal.R.styleable.TextView_text:
                     textIsSetFromXml = true;
-                    mTextId = a.getResourceId(attr, ResourceId.ID_NULL);
+                    mTextId = a.getResourceId(attr, Resources.ID_NULL);
                     text = a.getText(attr);
                     break;
 
@@ -3520,7 +3538,7 @@
      */
     @android.view.RemotableViewMethod
     public void setTextSelectHandle(@DrawableRes int textSelectHandle) {
-        Preconditions.checkArgumentPositive(textSelectHandle,
+        Preconditions.checkArgument(textSelectHandle != 0,
                 "The text select handle should be a valid drawable resource id.");
         setTextSelectHandle(mContext.getDrawable(textSelectHandle));
     }
@@ -3577,7 +3595,7 @@
      */
     @android.view.RemotableViewMethod
     public void setTextSelectHandleLeft(@DrawableRes int textSelectHandleLeft) {
-        Preconditions.checkArgumentPositive(textSelectHandleLeft,
+        Preconditions.checkArgument(textSelectHandleLeft != 0,
                 "The text select left handle should be a valid drawable resource id.");
         setTextSelectHandleLeft(mContext.getDrawable(textSelectHandleLeft));
     }
@@ -3634,7 +3652,7 @@
      */
     @android.view.RemotableViewMethod
     public void setTextSelectHandleRight(@DrawableRes int textSelectHandleRight) {
-        Preconditions.checkArgumentPositive(textSelectHandleRight,
+        Preconditions.checkArgument(textSelectHandleRight != 0,
                 "The text select right handle should be a valid drawable resource id.");
         setTextSelectHandleRight(mContext.getDrawable(textSelectHandleRight));
     }
@@ -3667,9 +3685,7 @@
      * @see #setTextCursorDrawable(int)
      * @attr ref android.R.styleable#TextView_textCursorDrawable
      */
-    public void setTextCursorDrawable(@NonNull Drawable textCursorDrawable) {
-        Preconditions.checkNotNull(textCursorDrawable,
-                "The cursor drawable should not be null.");
+    public void setTextCursorDrawable(@Nullable Drawable textCursorDrawable) {
         mCursorDrawable = textCursorDrawable;
         mCursorDrawableRes = 0;
         if (mEditor != null) {
@@ -3687,9 +3703,8 @@
      * @attr ref android.R.styleable#TextView_textCursorDrawable
      */
     public void setTextCursorDrawable(@DrawableRes int textCursorDrawable) {
-        Preconditions.checkArgumentPositive(textCursorDrawable,
-                "The cursor drawable should be a valid drawable resource id.");
-        setTextCursorDrawable(mContext.getDrawable(textCursorDrawable));
+        setTextCursorDrawable(
+                textCursorDrawable != 0 ? mContext.getDrawable(textCursorDrawable) : null);
     }
 
     /**
@@ -5102,7 +5117,7 @@
      * @attr ref android.R.styleable#TextView_scrollHorizontally
      * @see #setHorizontallyScrolling(boolean)
      */
-    public final boolean isHorizontallyScrolling() {
+    public final boolean isHorizontallyScrollable() {
         return mHorizontallyScrolling;
     }
 
@@ -8061,6 +8076,26 @@
                     }
                 }
                 break;
+
+            case KeyEvent.KEYCODE_FORWARD_DEL:
+                if (event.hasModifiers(KeyEvent.META_SHIFT_ON) && canCut()) {
+                    if (onTextContextMenuItem(ID_CUT)) {
+                        return KEY_EVENT_HANDLED;
+                    }
+                }
+                break;
+
+            case KeyEvent.KEYCODE_INSERT:
+                if (event.hasModifiers(KeyEvent.META_CTRL_ON) && canCopy()) {
+                    if (onTextContextMenuItem(ID_COPY)) {
+                        return KEY_EVENT_HANDLED;
+                    }
+                } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON) && canPaste()) {
+                    if (onTextContextMenuItem(ID_PASTE)) {
+                        return KEY_EVENT_HANDLED;
+                    }
+                }
+                break;
         }
 
         if (mEditor != null && mEditor.mKeyListener != null) {
@@ -8308,6 +8343,7 @@
                 outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION;
             }
             outAttrs.hintText = mHint;
+            outAttrs.targetInputMethodUser = mTextOperationUser;
             if (mText instanceof Editable) {
                 InputConnection ic = new EditableInputConnection(this);
                 outAttrs.initialSelStart = getSelectionStart();
@@ -10831,25 +10867,6 @@
                         return onTextContextMenuItem(ID_PASTE);
                     }
                     break;
-                case KeyEvent.KEYCODE_INSERT:
-                    if (canCopy()) {
-                        return onTextContextMenuItem(ID_COPY);
-                    }
-                    break;
-            }
-        } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
-            // Handle Shift-only shortcuts.
-            switch (keyCode) {
-                case KeyEvent.KEYCODE_FORWARD_DEL:
-                    if (canCut()) {
-                        return onTextContextMenuItem(ID_CUT);
-                    }
-                    break;
-                case KeyEvent.KEYCODE_INSERT:
-                    if (canPaste()) {
-                        return onTextContextMenuItem(ID_PASTE);
-                    }
-                    break;
             }
         } else if (event.hasModifiers(KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)) {
             // Handle Ctrl-Shift shortcuts.
@@ -10904,6 +10921,55 @@
     }
 
     /**
+     * Associate {@link UserHandle} who is considered to be the logical owner of the text shown in
+     * this {@link TextView}.
+     *
+     * <p>Most of applications should not worry about this.  Some privileged apps that host UI for
+     * other apps may need to set this so that the system can user right user's resources and
+     * services such as input methods and spell checkers.</p>
+     *
+     * @param user {@link UserHandle} who is considered to be the owner of the text shown in this
+     *        {@link TextView}. {@code null} to reset {@link #mTextOperationUser}.
+     * @hide
+     */
+    @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
+    public final void setTextOperationUser(@Nullable UserHandle user) {
+        if (Objects.equals(mTextOperationUser, user)) {
+            return;
+        }
+        if (user != null && !Process.myUserHandle().equals(user)) {
+            // Just for preventing people from accidentally using this hidden API without
+            // the required permission.  The same permission is also checked in the system server.
+            if (getContext().checkSelfPermission(INTERACT_ACROSS_USERS_FULL)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("INTERACT_ACROSS_USERS_FULL is required."
+                        + " userId=" + user.getIdentifier()
+                        + " callingUserId" + UserHandle.myUserId());
+            }
+        }
+        mTextOperationUser = user;
+        // Invalidate some resources
+        mCurrentSpellCheckerLocaleCache = null;
+        if (mEditor != null) {
+            mEditor.onTextOperationUserChanged();
+        }
+    }
+
+    @Nullable
+    final TextServicesManager getTextServicesManagerForUser() {
+        if (mTextOperationUser == null) {
+            return getContext().getSystemService(TextServicesManager.class);
+        }
+        try {
+            return getContext().createPackageContextAsUser(
+                    "android", 0 /* flags */, mTextOperationUser)
+                    .getSystemService(TextServicesManager.class);
+        } catch (PackageManager.NameNotFoundException e) {
+            return null;
+        }
+    }
+
+    /**
      * This is a temporary method. Future versions may support multi-locale text.
      * Caveat: This method may not return the latest text services locale, but this should be
      * acceptable and it's more important to make this method asynchronous.
@@ -10975,8 +11041,10 @@
 
     @UnsupportedAppUsage
     private void updateTextServicesLocaleLocked() {
-        final TextServicesManager textServicesManager = (TextServicesManager)
-                mContext.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
+        final TextServicesManager textServicesManager = getTextServicesManagerForUser();
+        if (textServicesManager == null) {
+            return;
+        }
         final SpellCheckerSubtype subtype = textServicesManager.getCurrentSpellCheckerSubtype(true);
         final Locale locale;
         if (subtype != null) {
@@ -11033,7 +11101,7 @@
             if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) {
                 structure.setDataIsSensitive(!mTextSetFromXmlOrResourceId);
             }
-            if (mTextId != ResourceId.ID_NULL) {
+            if (mTextId != Resources.ID_NULL) {
                 try {
                     structure.setTextIdEntry(getResources().getResourceEntryName(mTextId));
                 } catch (Resources.NotFoundException e) {
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 6a3a8f0..dc9a585 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -454,6 +454,7 @@
                 (RelativeLayout.LayoutParams) mAmPmLayout.getLayoutParams();
         if (params.getRule(RelativeLayout.RIGHT_OF) != 0
                 || params.getRule(RelativeLayout.LEFT_OF) != 0) {
+            final int margin = (int) (mContext.getResources().getDisplayMetrics().density * 8);
             // Horizontal mode, with AM/PM appearing to left/right of hours and minutes.
             final boolean isAmPmAtLeft;
             if (TextUtils.getLayoutDirectionFromLocale(mLocale) == View.LAYOUT_DIRECTION_LTR) {
@@ -461,10 +462,6 @@
             } else {
                 isAmPmAtLeft = !isAmPmAtStart;
             }
-            if (mIsAmPmAtLeft == isAmPmAtLeft) {
-                // AM/PM is already at the correct location. No change needed.
-                return;
-            }
 
             if (isAmPmAtLeft) {
                 params.removeRule(RelativeLayout.RIGHT_OF);
@@ -473,6 +470,14 @@
                 params.removeRule(RelativeLayout.LEFT_OF);
                 params.addRule(RelativeLayout.RIGHT_OF, mMinuteView.getId());
             }
+
+            if (isAmPmAtStart) {
+                params.setMarginStart(0);
+                params.setMarginEnd(margin);
+            } else {
+                params.setMarginStart(margin);
+                params.setMarginEnd(0);
+            }
             mIsAmPmAtLeft = isAmPmAtLeft;
         } else if (params.getRule(RelativeLayout.BELOW) != 0
                 || params.getRule(RelativeLayout.ABOVE) != 0) {
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index e83e79b..925a589 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -357,15 +357,16 @@
     }
 
     private boolean performTtsPrompt(AlertDialog alertDialog) {
+        final String serviceName = getShortcutFeatureDescription(false /* no summary */);
         final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
-        if (serviceInfo == null) {
+        if (TextUtils.isEmpty(serviceName) || serviceInfo == null) {
             return false;
         }
         if ((serviceInfo.flags & AccessibilityServiceInfo
                 .FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK) == 0) {
             return false;
         }
-        final TtsPrompt tts = new TtsPrompt();
+        final TtsPrompt tts = new TtsPrompt(serviceName);
         alertDialog.setOnDismissListener(dialog -> tts.dismiss());
         return true;
     }
@@ -378,8 +379,9 @@
         private boolean mDismiss;
         private TextToSpeech mTts;
 
-        TtsPrompt() {
-            mText = mContext.getString(R.string.accessibility_shortcut_spoken_feedback);
+        TtsPrompt(String serviceName) {
+            mText = mContext.getString(R.string.accessibility_shortcut_spoken_feedback,
+                    serviceName);
             mTts = mFrameworkObjectProvider.getTextToSpeech(mContext, this);
         }
 
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 4523d3b..30137e38 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -21,19 +21,24 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.pm.LabeledIntent;
+import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
 import android.database.DataSetObserver;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -75,6 +80,7 @@
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -92,6 +98,17 @@
 
     private static final boolean DEBUG = false;
 
+    /**
+     * If set to true, use ShortcutManager to retrieve the matching direct share targets, instead of
+     * binding to every ChooserTargetService implementation.
+     */
+    // TODO(b/121287573): Replace with a system flag (setprop?)
+    private static final boolean USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS = true;
+    private static final boolean USE_CHOOSER_TARGET_SERVICE_FOR_DIRECT_TARGETS = true;
+
+    // TODO(b/121287224): Re-evaluate this limit
+    private static final int SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20;
+
     private static final int QUERY_TARGET_SERVICE_LIMIT = 5;
     private static final int WATCHDOG_TIMEOUT_MILLIS = 2000;
 
@@ -120,6 +137,8 @@
 
     private static final int CHOOSER_TARGET_SERVICE_RESULT = 1;
     private static final int CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT = 2;
+    private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT = 3;
+    private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED = 4;
 
     private final Handler mChooserHandler = new Handler() {
         @Override
@@ -158,6 +177,21 @@
                     mChooserListAdapter.setShowServiceTargets(true);
                     break;
 
+                case SHORTCUT_MANAGER_SHARE_TARGET_RESULT:
+                    if (DEBUG) Log.d(TAG, "SHORTCUT_MANAGER_SHARE_TARGET_RESULT");
+                    if (isDestroyed()) break;
+                    final ServiceResultInfo resultInfo = (ServiceResultInfo) msg.obj;
+                    if (resultInfo.resultTargets != null) {
+                        mChooserListAdapter.addServiceResults(resultInfo.originalTarget,
+                                resultInfo.resultTargets);
+                    }
+                    break;
+
+                case SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED:
+                    sendVoiceChoicesIfNeeded();
+                    mChooserListAdapter.setShowServiceTargets(true);
+                    break;
+
                 default:
                     super.handleMessage(msg);
             }
@@ -552,6 +586,102 @@
         }
     }
 
+    private IntentFilter getTargetIntentFilter() {
+        try {
+            final Intent intent = getTargetIntent();
+            String dataString = intent.getDataString();
+            if (TextUtils.isEmpty(dataString)) {
+                dataString = intent.getType();
+            }
+            return new IntentFilter(intent.getAction(), dataString);
+        } catch (Exception e) {
+            Log.e(TAG, "failed to get target intent filter " + e);
+            return null;
+        }
+    }
+
+    private void queryDirectShareTargets(ChooserListAdapter adapter) {
+        final IntentFilter filter = getTargetIntentFilter();
+        if (filter == null) {
+            return;
+        }
+
+        // Need to keep the original DisplayResolveInfos to be able to reconstruct ServiceResultInfo
+        // and use the old code path. This Ugliness should go away when Sharesheet is refactored.
+        final List<DisplayResolveInfo> driList = new ArrayList<>();
+        int targetsToQuery = 0;
+        for (int i = 0, n = adapter.getDisplayResolveInfoCount(); i < n; i++) {
+            final DisplayResolveInfo dri = adapter.getDisplayResolveInfo(i);
+            if (adapter.getScore(dri) == 0) {
+                // A score of 0 means the app hasn't been used in some time;
+                // don't query it as it's not likely to be relevant.
+                continue;
+            }
+            driList.add(dri);
+            targetsToQuery++;
+            // TODO(b/121287224): Do we need this here? (similar to queryTargetServices)
+            if (targetsToQuery >= SHARE_TARGET_QUERY_PACKAGE_LIMIT) {
+                if (DEBUG) {
+                    Log.d(TAG, "queryTargets hit query target limit "
+                            + SHARE_TARGET_QUERY_PACKAGE_LIMIT);
+                }
+                break;
+            }
+        }
+
+        AsyncTask.execute(() -> {
+            ShortcutManager sm = (ShortcutManager) getSystemService(Context.SHORTCUT_SERVICE);
+            List<ShortcutManager.ShareShortcutInfo> resultList = sm.getShareTargets(filter);
+
+            // Match ShareShortcutInfos with DisplayResolveInfos to be able to use the old code path
+            // for direct share targets. After ShareSheet is refactored we should use the
+            // ShareShortcutInfos directly.
+            boolean resultMessageSent = false;
+            for (int i = 0; i < driList.size(); i++) {
+                List<ChooserTarget> chooserTargets = new ArrayList<>();
+                for (int j = 0; j < resultList.size(); j++) {
+                    if (driList.get(i).getResolvedComponentName().equals(
+                            resultList.get(j).getTargetComponent())) {
+                        chooserTargets.add(convertToChooserTarget(resultList.get(j)));
+                    }
+                }
+                if (chooserTargets.isEmpty()) {
+                    continue;
+                }
+
+                final Message msg = Message.obtain();
+                msg.what = SHORTCUT_MANAGER_SHARE_TARGET_RESULT;
+                msg.obj = new ServiceResultInfo(driList.get(i), chooserTargets, null);
+                mChooserHandler.sendMessage(msg);
+                resultMessageSent = true;
+            }
+
+            if (resultMessageSent) {
+                final Message msg = Message.obtain();
+                msg.what = SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED;
+                mChooserHandler.sendMessage(msg);
+            }
+        });
+    }
+
+    private ChooserTarget convertToChooserTarget(ShortcutManager.ShareShortcutInfo shareShortcut) {
+        ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo();
+        Bundle extras = new Bundle();
+        extras.putString(Intent.EXTRA_SHORTCUT_ID, shortcutInfo.getId());
+        return new ChooserTarget(
+                // The name of this target.
+                shortcutInfo.getShortLabel(),
+                // Don't load the icon until it is selected to be shown
+                null,
+                // The ranking score for this target (0.0-1.0); the system will omit items with low
+                // scores when there are too many Direct Share items.
+                0.5f,
+                // The name of the component to be launched if this target is chosen.
+                shareShortcut.getTargetComponent().clone(),
+                // The extra values here will be merged into the Intent when this target is chosen.
+                extras);
+    }
+
     private String convertServiceName(String packageName, String serviceName) {
         if (TextUtils.isEmpty(serviceName)) {
             return null;
@@ -765,9 +895,8 @@
                     }
                 }
             }
-            final Icon icon = chooserTarget.getIcon();
-            // TODO do this in the background
-            mDisplayIcon = icon != null ? icon.loadDrawable(ChooserActivity.this) : null;
+            // TODO(b/121287224): do this in the background thread, and only for selected targets
+            mDisplayIcon = getChooserTargetIconDrawable(chooserTarget);
 
             if (sourceInfo != null) {
                 mBackupResolveInfo = null;
@@ -791,6 +920,39 @@
             mModifiedScore = other.mModifiedScore;
         }
 
+        /**
+         * Since ShortcutInfos are returned by ShortcutManager, we can cache the shortcuts and skip
+         * the call to LauncherApps#getShortcuts(ShortcutQuery).
+         */
+        // TODO(121287224): Refactor code to apply the suggestion above
+        private Drawable getChooserTargetIconDrawable(ChooserTarget target) {
+            final Icon icon = target.getIcon();
+            if (icon != null) {
+                return icon.loadDrawable(ChooserActivity.this);
+            }
+            if (!USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) {
+                return null;
+            }
+
+            Bundle extras = target.getIntentExtras();
+            if (extras == null || !extras.containsKey(Intent.EXTRA_SHORTCUT_ID)) {
+                return null;
+            }
+            CharSequence shortcutId = extras.getCharSequence(Intent.EXTRA_SHORTCUT_ID);
+            LauncherApps launcherApps = (LauncherApps) getSystemService(
+                    Context.LAUNCHER_APPS_SERVICE);
+            final LauncherApps.ShortcutQuery q = new LauncherApps.ShortcutQuery();
+            q.setPackage(target.getComponentName().getPackageName());
+            q.setShortcutIds(Arrays.asList(shortcutId.toString()));
+            q.setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC);
+            final List<ShortcutInfo> shortcuts = launcherApps.getShortcuts(q, getUser());
+            if (shortcuts != null && shortcuts.size() > 0) {
+                return launcherApps.getShortcutIconDrawable(shortcuts.get(0), 0);
+            }
+
+            return null;
+        }
+
         public float getModifiedScore() {
             return mModifiedScore;
         }
@@ -1030,8 +1192,19 @@
                     mTargetsNeedPruning = true;
                 }
             }
-            if (DEBUG) Log.d(TAG, "List built querying services");
-            queryTargetServices(this);
+
+            if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) {
+                if (DEBUG) {
+                    Log.d(TAG, "querying direct share targets from ShortcutManager");
+                }
+                queryDirectShareTargets(this);
+            }
+            if (USE_CHOOSER_TARGET_SERVICE_FOR_DIRECT_TARGETS) {
+                if (DEBUG) {
+                    Log.d(TAG, "List built querying services");
+                }
+                queryTargetServices(this);
+            }
         }
 
         @Override
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index e59bee4..c4ab91f 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -17,8 +17,10 @@
 package com.android.internal.app;
 
 import android.app.AppOpsManager;
+import android.app.AppOpsManager;
 import android.content.pm.ParceledListSlice;
 import android.os.Bundle;
+import android.os.RemoteCallback;
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsActiveCallback;
 import com.android.internal.app.IAppOpsNotedCallback;
@@ -42,10 +44,15 @@
     int checkPackage(int uid, String packageName);
     List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
     List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
-    ParceledListSlice getAllHistoricalPackagesOps(in String[] ops,
-            long beginTimeMillis, long endTimeMillis);
-    AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int uid, String packageName,
-            in String[] ops, long beginTimeMillis, long endTimeMillis);
+    void getHistoricalOps(int uid, String packageName, in String[] ops, long beginTimeMillis,
+            long endTimeMillis, in RemoteCallback callback);
+    void getHistoricalOpsFromDiskRaw(int uid, String packageName, in String[] ops,
+            long beginTimeMillis, long endTimeMillis, in RemoteCallback callback);
+    void offsetHistory(long duration);
+    void setHistoryParameters(int mode, long baseSnapshotInterval, int compressionStep);
+    void addHistoricalOps(in AppOpsManager.HistoricalOps ops);
+    void resetHistoryParameters();
+    void clearHistory();
     List<AppOpsManager.PackageOps> getUidOps(int uid, in int[] ops);
     void setUidMode(int code, int uid, int mode);
     void setMode(int code, int uid, String packageName, int mode);
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 5088cca..b85488f 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -151,4 +151,19 @@
      */
     void getActiveServiceSupportedActions(in List<String> voiceActions,
      in IVoiceActionCheckCallback callback);
+
+    /**
+     * Sets the transcribed voice to the given string.
+     */
+    void setTranscription(String transcription);
+
+    /**
+     * Indicates that the transcription session is finished.
+     */
+    void clearTranscription(boolean immediate);
+
+    /**
+     * Sets the voice state indication based upon the given value.
+     */
+    void setVoiceState(int state);
 }
diff --git a/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl b/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl
index 87749d2..674ad5b 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl
@@ -26,4 +26,20 @@
      * Called when a voice session is hidden.
      */
     void onVoiceSessionHidden();
+
+    /**
+     * Called when voice assistant transcription has been updated to the given string.
+     */
+    void onTranscriptionUpdate(in String transcription);
+
+    /**
+     * Called when voice transcription is completed.
+     */
+    void onTranscriptionComplete(in boolean immediate);
+
+    /**
+     * Called when the voice assistant's state has changed. Values are from
+     * VoiceInteractionService's VOICE_STATE* constants.
+     */
+    void onVoiceStateChange(in int state);
  }
\ No newline at end of file
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index 96d3baf..f61a03b 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -22,44 +22,36 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
+import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
-import android.content.SharedPreferences;
-import android.content.ServiceConnection;
 import android.metrics.LogMaker;
-import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.storage.StorageManager;
 import android.os.UserHandle;
-import android.service.resolver.IResolverRankerService;
 import android.service.resolver.IResolverRankerResult;
+import android.service.resolver.IResolverRankerService;
 import android.service.resolver.ResolverRankerService;
 import android.service.resolver.ResolverTarget;
-import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.Log;
+
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
-import java.io.File;
-import java.lang.InterruptedException;
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Comparator;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Ranks and compares packages based on usage stats.
@@ -90,6 +82,8 @@
 
     private final Collator mCollator;
     private final boolean mHttp;
+    // can be null if mHttp == false or current user has no default browser package
+    private final String mDefaultBrowserPackageName;
     private final PackageManager mPm;
     private final UsageStatsManager mUsm;
     private final Map<String, UsageStats> mStats;
@@ -184,6 +178,10 @@
         getContentAnnotations(intent);
         mAction = intent.getAction();
         mRankerServiceName = new ComponentName(mContext, this.getClass());
+
+        mDefaultBrowserPackageName = mHttp
+                ? mPm.getDefaultBrowserPackageNameAsUser(UserHandle.myUserId())
+                : null;
     }
 
     // get annotations of content from intent.
@@ -312,7 +310,14 @@
         if (mHttp) {
             // Special case: we want filters that match URI paths/schemes to be
             // ordered before others.  This is for the case when opening URIs,
-            // to make native apps go above browsers.
+            // to make native apps go above browsers - except for 1 even more special case
+            // which is the default browser, as we want that to go above them all.
+            if (isDefaultBrowser(lhs)) {
+                return -1;
+            }
+            if (isDefaultBrowser(rhs)) {
+                return 1;
+            }
             final boolean lhsSpecific = ResolverActivity.isSpecificUriMatch(lhs.match);
             final boolean rhsSpecific = ResolverActivity.isSpecificUriMatch(rhs.match);
             if (lhsSpecific != rhsSpecific) {
@@ -419,6 +424,20 @@
         }
     }
 
+    private boolean isDefaultBrowser(ResolveInfo ri) {
+        // It makes sense to prefer the default browser
+        // only if the targeted user is the current user
+        if (ri.targetUserId != UserHandle.USER_CURRENT) {
+            return false;
+        }
+
+        if (ri.activityInfo.packageName != null
+                && ri.activityInfo.packageName.equals(mDefaultBrowserPackageName)) {
+            return true;
+        }
+        return false;
+    }
+
     // records metrics for evaluation.
     private void logMetrics(int selectedPos) {
         if (mRankerServiceName != null) {
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index 498de53..70935d4 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.app;
 
-import static android.content.res.ResourceId.ID_NULL;
+import static android.content.res.Resources.ID_NULL;
 
 import android.Manifest;
 import android.app.AlertDialog;
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index 9b9b771..8e88c51 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -23,6 +23,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.service.procstats.ProcessStatsAvailablePagesProto;
 import android.service.procstats.ProcessStatsPackageProto;
 import android.service.procstats.ProcessStatsSectionProto;
 import android.text.format.DateFormat;
@@ -178,7 +179,7 @@
             {"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"};
 
     // Current version of the parcel format.
-    private static final int PARCEL_VERSION = 35;
+    private static final int PARCEL_VERSION = 36;
     // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
     private static final int MAGIC = 0x50535454;
 
@@ -237,10 +238,11 @@
     ArrayList<String> mIndexToCommonString;
 
     private static final Pattern sPageTypeRegex = Pattern.compile(
-            "^Node\\s+(\\d+),.*. type\\s+(\\w+)\\s+([\\s\\d]+?)\\s*$");
-    private final ArrayList<Integer> mPageTypeZones = new ArrayList<Integer>();
-    private final ArrayList<String> mPageTypeLabels = new ArrayList<String>();
-    private final ArrayList<int[]> mPageTypeSizes = new ArrayList<int[]>();
+            "^Node\\s+(\\d+),.* zone\\s+(\\w+),.* type\\s+(\\w+)\\s+([\\s\\d]+?)\\s*$");
+    private final ArrayList<Integer> mPageTypeNodes = new ArrayList<>();
+    private final ArrayList<String> mPageTypeZones = new ArrayList<>();
+    private final ArrayList<String> mPageTypeLabels = new ArrayList<>();
+    private final ArrayList<int[]> mPageTypeSizes = new ArrayList<>();
 
     public ProcessStats(boolean running) {
         mRunning = running;
@@ -621,6 +623,7 @@
         try {
             reader = new BufferedReader(new FileReader("/proc/pagetypeinfo"));
             final Matcher matcher = sPageTypeRegex.matcher("");
+            mPageTypeNodes.clear();
             mPageTypeZones.clear();
             mPageTypeLabels.clear();
             mPageTypeSizes.clear();
@@ -631,16 +634,18 @@
                 }
                 matcher.reset(line);
                 if (matcher.matches()) {
-                    final Integer zone = Integer.valueOf(matcher.group(1), 10);
-                    if (zone == null) {
+                    final Integer node = Integer.valueOf(matcher.group(1), 10);
+                    if (node == null) {
                         continue;
                     }
-                    mPageTypeZones.add(zone);
-                    mPageTypeLabels.add(matcher.group(2));
-                    mPageTypeSizes.add(splitAndParseNumbers(matcher.group(3)));
+                    mPageTypeNodes.add(node);
+                    mPageTypeZones.add(matcher.group(2));
+                    mPageTypeLabels.add(matcher.group(3));
+                    mPageTypeSizes.add(splitAndParseNumbers(matcher.group(4)));
                 }
             }
         } catch (IOException ex) {
+            mPageTypeNodes.clear();
             mPageTypeZones.clear();
             mPageTypeLabels.clear();
             mPageTypeSizes.clear();
@@ -935,7 +940,8 @@
         final int NPAGETYPES = mPageTypeLabels.size();
         out.writeInt(NPAGETYPES);
         for (int i=0; i<NPAGETYPES; i++) {
-            out.writeInt(mPageTypeZones.get(i));
+            out.writeInt(mPageTypeNodes.get(i));
+            out.writeString(mPageTypeZones.get(i));
             out.writeString(mPageTypeLabels.get(i));
             out.writeIntArray(mPageTypeSizes.get(i));
         }
@@ -1244,6 +1250,8 @@
 
         // Fragmentation info
         final int NPAGETYPES = in.readInt();
+        mPageTypeNodes.clear();
+        mPageTypeNodes.ensureCapacity(NPAGETYPES);
         mPageTypeZones.clear();
         mPageTypeZones.ensureCapacity(NPAGETYPES);
         mPageTypeLabels.clear();
@@ -1251,7 +1259,8 @@
         mPageTypeSizes.clear();
         mPageTypeSizes.ensureCapacity(NPAGETYPES);
         for (int i=0; i<NPAGETYPES; i++) {
-            mPageTypeZones.add(in.readInt());
+            mPageTypeNodes.add(in.readInt());
+            mPageTypeZones.add(in.readString());
             mPageTypeLabels.add(in.readString());
             mPageTypeSizes.add(in.createIntArray());
         }
@@ -1764,7 +1773,8 @@
         pw.println("Available pages by page size:");
         final int NPAGETYPES = mPageTypeLabels.size();
         for (int i=0; i<NPAGETYPES; i++) {
-            pw.format("Zone %3d  %14s ", mPageTypeZones.get(i), mPageTypeLabels.get(i));
+            pw.format("Node %3d Zone %7s  %14s ", mPageTypeNodes.get(i), mPageTypeZones.get(i),
+                    mPageTypeLabels.get(i));
             final int[] sizes = mPageTypeSizes.get(i);
             final int N = sizes == null ? 0 : sizes.length;
             for (int j=0; j<N; j++) {
@@ -2095,6 +2105,9 @@
             pw.print(",");
             pw.print(mPageTypeZones.get(i));
             pw.print(",");
+            // Wasn't included in original output.
+            //pw.print(mPageTypeNodes.get(i));
+            //pw.print(",");
             final int[] sizes = mPageTypeSizes.get(i);
             final int N = sizes == null ? 0 : sizes.length;
             for (int j=0; j<N; j++) {
@@ -2135,6 +2148,20 @@
             proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_PARTIAL);
         }
 
+        final int NPAGETYPES = mPageTypeLabels.size();
+        for (int i = 0; i < NPAGETYPES; i++) {
+            final long token = proto.start(ProcessStatsSectionProto.AVAILABLE_PAGES);
+            proto.write(ProcessStatsAvailablePagesProto.NODE, mPageTypeNodes.get(i));
+            proto.write(ProcessStatsAvailablePagesProto.ZONE, mPageTypeZones.get(i));
+            proto.write(ProcessStatsAvailablePagesProto.LABEL, mPageTypeLabels.get(i));
+            final int[] sizes = mPageTypeSizes.get(i);
+            final int N = sizes == null ? 0 : sizes.length;
+            for (int j = 0; j < N; j++) {
+                proto.write(ProcessStatsAvailablePagesProto.PAGES_PER_ORDER, sizes[j]);
+            }
+            proto.end(token);
+        }
+
         final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
         if ((section & REPORT_PROC_STATS) != 0) {
             for (int ip = 0; ip < procMap.size(); ip++) {
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index a27dbea..18c4b46 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -74,6 +74,16 @@
 
     private static final boolean LOG_INOTIFY = false;
 
+    protected static final String SUPPORTED_QUERY_ARGS = joinNewline(
+            DocumentsContract.QUERY_ARG_DISPLAY_NAME,
+            DocumentsContract.QUERY_ARG_FILE_SIZE_OVER,
+            DocumentsContract.QUERY_ARG_LAST_MODIFIED_AFTER,
+            DocumentsContract.QUERY_ARG_MIME_TYPES);
+
+    private static String joinNewline(String... args) {
+        return TextUtils.join("\n", args);
+    }
+
     private String[] mDefaultProjection;
 
     @GuardedBy("mObservers")
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index 78d366c..7a00a51 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -16,14 +16,14 @@
 
 package com.android.internal.hardware;
 
-import com.android.internal.R;
-
 import android.content.Context;
 import android.os.Build;
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.text.TextUtils;
 
+import com.android.internal.R;
+
 public class AmbientDisplayConfiguration {
 
     private final Context mContext;
@@ -37,7 +37,8 @@
     public boolean enabled(int user) {
         return pulseOnNotificationEnabled(user)
                 || pulseOnLongPressEnabled(user)
-                || alwaysOnEnabled(user);
+                || alwaysOnEnabled(user)
+                || wakeLockScreenGestureEnabled(user);
     }
 
     public boolean pulseOnNotificationEnabled(int user) {
@@ -57,6 +58,15 @@
         return mContext.getResources().getBoolean(R.bool.config_dozePulsePickup);
     }
 
+    public boolean tapGestureEnabled(int user) {
+        return boolSettingDefaultOn(Settings.Secure.DOZE_TAP_SCREEN_GESTURE, user)
+                && tapSensorAvailable();
+    }
+
+    public boolean tapSensorAvailable() {
+        return !TextUtils.isEmpty(tapSensorType());
+    }
+
     public boolean doubleTapGestureEnabled(int user) {
         return boolSettingDefaultOn(Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, user)
                 && doubleTapSensorAvailable();
@@ -85,6 +95,10 @@
         return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
     }
 
+    public String tapSensorType() {
+        return mContext.getResources().getString(R.string.config_dozeTapSensorType);
+    }
+
     public String longPressSensorType() {
         return mContext.getResources().getString(R.string.config_dozeLongPressSensorType);
     }
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index c94c64a..72c67d7 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -39,6 +39,7 @@
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 
 /**
  * Base class representing a remote service.
@@ -93,6 +94,9 @@
     // Used just for debugging purposes (on dump)
     private long mNextUnbind;
 
+    /** Requests that have been scheduled, but that are not finished yet */
+    private final ArrayList<PendingRequest<S, I>> mUnfinishedRequests = new ArrayList<>();
+
     /**
      * Callback called when the service dies.
      *
@@ -135,6 +139,14 @@
         return mDestroyed;
     }
 
+    /**
+     * Gets the name of the service.
+     */
+    @NonNull
+    public final ComponentName getComponentName() {
+        return mComponentName;
+    }
+
     private void handleOnConnectedStateChangedInternal(boolean connected) {
         if (connected) {
             handlePendingRequests();
@@ -209,6 +221,7 @@
         }
         mService = null;
         mServiceDied = true;
+        cancelScheduledUnbind();
         @SuppressWarnings("unchecked") // TODO(b/117779333): fix this warning
         final S castService = (S) this;
         mVultureCallback.onServiceDied(castService);
@@ -229,6 +242,8 @@
                 .append(mComponentName.flattenToString()).println();
         pw.append(prefix).append(tab).append("destroyed=")
                 .append(String.valueOf(mDestroyed)).println();
+        pw.append(prefix).append(tab).append("numUnfinishedRequests=")
+                .append(String.valueOf(mUnfinishedRequests.size()));
         final boolean bound = handleIsBound();
         pw.append(prefix).append(tab).append("bound=")
                 .append(String.valueOf(bound));
@@ -257,23 +272,37 @@
      * <p>This request must be responded by the service somehow (typically using a callback),
      * othewise it will trigger a {@link PendingRequest#onTimeout(AbstractRemoteService)} if the
      * service doesn't respond.
-     *
-     * <p><b>NOTE: </b>this request is responsible for calling {@link #scheduleUnbind()}.
      */
     protected void scheduleRequest(@NonNull PendingRequest<S, I> pendingRequest) {
-        cancelScheduledUnbind();
         mHandler.sendMessage(obtainMessage(
                 AbstractRemoteService::handlePendingRequest, this, pendingRequest));
     }
 
     /**
+     * Marks a pendingRequest as finished.
+     *
+     * @param finshedRequest The request that is finished
+     */
+    void finishRequest(@NonNull PendingRequest<S, I> finshedRequest) {
+        mHandler.sendMessage(
+                obtainMessage(AbstractRemoteService::handleFinishRequest, this, finshedRequest));
+    }
+
+    private void handleFinishRequest(@NonNull PendingRequest<S, I> finshedRequest) {
+        mUnfinishedRequests.remove(finshedRequest);
+
+        if (mUnfinishedRequests.isEmpty()) {
+            scheduleUnbind();
+        }
+    }
+
+    /**
      * Schedules an async request.
      *
      * <p>This request is not expecting a callback from the service, hence it's represented by
      * a simple {@link Runnable}.
      */
     protected void scheduleAsyncRequest(@NonNull AsyncRequest<I> request) {
-        scheduleUnbind();
         // TODO(b/117779333): fix generics below
         @SuppressWarnings({"unchecked", "rawtypes"})
         final MyAsyncPendingRequest<S, I> asyncRequest = new MyAsyncPendingRequest(this, request);
@@ -341,6 +370,10 @@
             handleEnsureBound();
         } else {
             if (mVerbose) Slog.v(mTag, "handlePendingRequest(): " + pendingRequest);
+
+            mUnfinishedRequests.add(pendingRequest);
+            cancelScheduledUnbind();
+
             pendingRequest.run();
             if (pendingRequest.isFinal()) {
                 mCompleted = true;
@@ -504,6 +537,12 @@
                 }
                 mCompleted = true;
             }
+
+            S service = mWeakService.get();
+            if (service != null) {
+                service.finishRequest(this);
+            }
+
             mServiceHandler.removeCallbacks(mTimeoutTrigger);
             return true;
         }
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index 2671781..d0272e0 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -38,6 +38,5 @@
     boolean switchToPreviousInputMethod();
     boolean switchToNextInputMethod(boolean onlyCurrentIme);
     boolean shouldOfferSwitchingToNextInputMethod();
-
-    oneway void notifyUserActionAsync();
+    void notifyUserAction();
 }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index cdb986a..7600dc9 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -332,16 +332,16 @@
     }
 
     /**
-     * Calls {@link IInputMethodPrivilegedOperations#notifyUserActionAsync()}
+     * Calls {@link IInputMethodPrivilegedOperations#notifyUserAction()}
      */
     @AnyThread
-    public void notifyUserActionAsync() {
+    public void notifyUserAction() {
         final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
         if (ops == null) {
             return;
         }
         try {
-            ops.notifyUserActionAsync();
+            ops.notifyUserAction();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index c4aa1d7..a691a24 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -25,7 +25,13 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 /**
- * Log all the things.
+ * Writes sysui_multi_event records to the system event log.
+ *
+ * Prefer the methods write(LogMaker), or count() or histogram(). Replace legacy methods with
+ * their current equivalents when the opportunity arises.
+ *
+ * This class is a lightweight dependency barrier - it is cheap and easy to construct.
+ * Logging is also cheap, so it is not normally necessary to move logging off of the UI thread.
  *
  * @hide
  */
@@ -52,6 +58,7 @@
     public static final int VIEW_UNKNOWN = MetricsEvent.VIEW_UNKNOWN;
     public static final int LOGTAG = EventLogTags.SYSUI_MULTI_ACTION;
 
+    /** Write an event log record, consisting of content.serialize(). */
     @UnsupportedAppUsage
     public void write(LogMaker content) {
         if (content.getType() == MetricsEvent.TYPE_UNKNOWN) {
@@ -60,128 +67,145 @@
         saveLog(content);
     }
 
+    /** Add an integer value to the monotonically increasing counter with the given name. */
+    public void count(String name, int value) {
+        saveLog(new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
+                .setCounterName(name)
+                .setCounterValue(value));
+    }
+
+    /** Increment the bucket with the integer label on the histogram with the given name. */
+    public void histogram(String name, int bucket) {
+        // see LogHistogram in system/core/libmetricslogger/metrics_logger.cpp
+        saveLog(new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
+                .setCounterName(name)
+                .setCounterBucket(bucket)
+                .setCounterValue(1));
+    }
+
+    /* Legacy logging methods follow.  These are all simple shorthands and can be replaced
+     * with an equivalent write(). */
+
+    /** Logs an OPEN event on the category.
+     *  Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_OPEN)) */
     public void visible(int category) throws IllegalArgumentException {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
             throw new IllegalArgumentException("Must define metric category");
         }
-        EventLogTags.writeSysuiViewVisibility(category, 100);
         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_OPEN));
     }
 
+    /** Logs a CLOSE event on the category.
+     *  Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_CLOSE)) */
     public void hidden(int category) throws IllegalArgumentException {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
             throw new IllegalArgumentException("Must define metric category");
         }
-        EventLogTags.writeSysuiViewVisibility(category, 0);
         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_CLOSE));
     }
 
-    public void visibility(int category, boolean visibile)
+    /** Logs an OPEN or CLOSE event on the category, depending on visible.
+     *  Equivalent to write(new LogMaker(category)
+     *                     .setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)) */
+    public void visibility(int category, boolean visible)
             throws IllegalArgumentException {
-        if (visibile) {
+        if (visible) {
             visible(category);
         } else {
             hidden(category);
         }
     }
 
+    /** Logs an OPEN or CLOSE event on the category, depending on vis.
+     *  Equivalent to write(new LogMaker(category)
+                           .setType(vis == View.VISIBLE ?
+                                    MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE)) */
     public void visibility(int category, int vis)
             throws IllegalArgumentException {
         visibility(category, vis == View.VISIBLE);
     }
 
+    /** Logs an ACTION event on the category.
+     * Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION)) */
     public void action(int category) {
-        EventLogTags.writeSysuiAction(category, "");
         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION));
     }
 
+    /** Logs an ACTION event on the category.
+     * Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION)
+                           .setSubtype(value) */
     public void action(int category, int value) {
-        EventLogTags.writeSysuiAction(category, Integer.toString(value));
         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION).setSubtype(value));
     }
 
+    /** Logs an ACTION event on the category.
+     * Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION)
+                           .setSubtype(value ? 1 : 0) */
     public void action(int category, boolean value) {
-        EventLogTags.writeSysuiAction(category, Boolean.toString(value));
         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION).setSubtype(value ? 1 : 0));
     }
 
+    /** Logs an ACTION event on the category.
+     * Equivalent to write(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION)
+                           .setPackageName(value ? 1 : 0) */
     public void action(int category, String pkg) {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
             throw new IllegalArgumentException("Must define metric category");
         }
-        EventLogTags.writeSysuiAction(category, pkg);
         saveLog(new LogMaker(category).setType(MetricsEvent.TYPE_ACTION).setPackageName(pkg));
     }
 
-    /** Add an integer value to the monotonically increasing counter with the given name. */
-    public void count(String name, int value) {
-        EventLogTags.writeSysuiCount(name, value);
-        saveLog(new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
-                    .setCounterName(name)
-                    .setCounterValue(value));
-    }
-
-    /** Increment the bucket with the integer label on the histogram with the given name. */
-    public void histogram(String name, int bucket) {
-        // see LogHistogram in system/core/libmetricslogger/metrics_logger.cpp
-        EventLogTags.writeSysuiHistogram(name, bucket);
-        saveLog(new LogMaker(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
-                    .setCounterName(name)
-                    .setCounterBucket(bucket)
-                    .setCounterValue(1));
-    }
-
-    /** @deprecated use {@link #visible(int)} */
+    /** @deprecated because untestable; use {@link #visible(int)} */
     @Deprecated
     public static void visible(Context context, int category) throws IllegalArgumentException {
         getLogger().visible(category);
     }
 
-    /** @deprecated use {@link #hidden(int)} */
+    /** @deprecated because untestable; use {@link #hidden(int)} */
     @Deprecated
     public static void hidden(Context context, int category) throws IllegalArgumentException {
         getLogger().hidden(category);
     }
 
-    /** @deprecated use {@link #visibility(int, boolean)} */
+    /** @deprecated because untestable; use {@link #visibility(int, boolean)} */
     @Deprecated
     public static void visibility(Context context, int category, boolean visibile)
             throws IllegalArgumentException {
         getLogger().visibility(category, visibile);
     }
 
-    /** @deprecated use {@link #visibility(int, int)} */
+    /** @deprecated because untestable; use {@link #visibility(int, int)} */
     @Deprecated
     public static void visibility(Context context, int category, int vis)
             throws IllegalArgumentException {
         visibility(context, category, vis == View.VISIBLE);
     }
 
-    /** @deprecated use {@link #action(int)} */
+    /** @deprecated because untestable; use {@link #action(int)} */
     @Deprecated
     public static void action(Context context, int category) {
         getLogger().action(category);
     }
 
-    /** @deprecated use {@link #action(int, int)} */
+    /** @deprecated because untestable; use {@link #action(int, int)} */
     @Deprecated
     public static void action(Context context, int category, int value) {
         getLogger().action(category, value);
     }
 
-    /** @deprecated use {@link #action(int, boolean)} */
+    /** @deprecated because untestable; use {@link #action(int, boolean)} */
     @Deprecated
     public static void action(Context context, int category, boolean value) {
         getLogger().action(category, value);
     }
 
-    /** @deprecated use {@link #write(LogMaker)} */
+    /** @deprecated because untestable; use {@link #write(LogMaker)} */
     @Deprecated
     public static void action(LogMaker content) {
         getLogger().write(content);
     }
 
-    /** @deprecated use {@link #action(int, String)} */
+    /** @deprecated because untestable; use {@link #action(int, String)} */
     @Deprecated
     public static void action(Context context, int category, String pkg) {
         getLogger().action(category, pkg);
@@ -189,7 +213,7 @@
 
     /**
      * Add an integer value to the monotonically increasing counter with the given name.
-     * @deprecated use {@link #count(String, int)}
+     * @deprecated because untestable; use {@link #count(String, int)}
      */
     @Deprecated
     public static void count(Context context, String name, int value) {
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 0a7cff6..9bacf9b 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -20,6 +20,7 @@
 import static android.net.NetworkStats.TAG_ALL;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
+
 import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
 
 import android.annotation.Nullable;
@@ -33,10 +34,8 @@
 
 import libcore.io.IoUtils;
 
-import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileReader;
 import java.io.IOException;
 import java.net.ProtocolException;
 import java.util.Arrays;
@@ -127,7 +126,7 @@
     }
 
     public NetworkStatsFactory() {
-        this(new File("/proc/"), new File("/sys/fs/bpf/traffic_uid_stats_map").exists());
+        this(new File("/proc/"), new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists());
     }
 
     @VisibleForTesting
diff --git a/core/java/com/android/internal/os/AppZygoteInit.java b/core/java/com/android/internal/os/AppZygoteInit.java
new file mode 100644
index 0000000..afe6dad
--- /dev/null
+++ b/core/java/com/android/internal/os/AppZygoteInit.java
@@ -0,0 +1,105 @@
+/*
+ * 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.os;
+
+import android.app.LoadedApk;
+import android.content.pm.ApplicationInfo;
+import android.net.LocalSocket;
+import android.util.Log;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Startup class for an Application zygote process.
+ *
+ * See {@link ZygoteInit} for generic zygote startup documentation.
+ *
+ * @hide
+ */
+class AppZygoteInit {
+    public static final String TAG = "AppZygoteInit";
+
+    private static ZygoteServer sServer;
+
+    private static class AppZygoteServer extends ZygoteServer {
+        @Override
+        protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
+                throws IOException {
+            return new AppZygoteConnection(socket, abiList);
+        }
+    }
+
+    private static class AppZygoteConnection extends ZygoteConnection {
+        AppZygoteConnection(LocalSocket socket, String abiList) throws IOException {
+            super(socket, abiList);
+        }
+
+        @Override
+        protected void preload() {
+            // Nothing to preload by default.
+        }
+
+        @Override
+        protected boolean isPreloadComplete() {
+            // App zygotes don't preload any classes or resources or defaults, all of their
+            // preloading is package specific.
+            return true;
+        }
+
+        @Override
+        protected boolean canPreloadApp() {
+            return true;
+        }
+
+        @Override
+        protected void handlePreloadApp(ApplicationInfo appInfo) {
+            Log.i(TAG, "Beginning application preload for " + appInfo.packageName);
+            LoadedApk loadedApk = new LoadedApk(null, appInfo, null, null, false, true, false);
+            ClassLoader loader = loadedApk.getClassLoader();
+            Class<?> cl;
+            Method m;
+            try {
+                cl = Class.forName(appInfo.packageName + ".ZygotePreload", true, loader);
+                m = cl.getMethod("doPreload");
+                m.setAccessible(true);
+                m.invoke(null);
+            } catch (ClassNotFoundException e) {
+                // Don't treat this as an error since an app may not want to do any preloads
+                Log.w(TAG, "No ZygotePreload class found for " + appInfo.packageName);
+            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+                Log.e(TAG, "AppZygote application preload failed for "
+                        + appInfo.packageName, e);
+            }
+            try {
+                DataOutputStream socketOut = getSocketOutputStream();
+                socketOut.writeInt(loader != null ? 1 : 0);
+            } catch (IOException e) {
+                throw new IllegalStateException("Error writing to command socket", e);
+            }
+
+            Log.i(TAG, "Application preload done");
+        }
+    }
+
+    public static void main(String[] argv) {
+        AppZygoteServer server = new AppZygoteServer();
+        ChildZygoteInit.runZygoteServer(server, argv);
+    }
+}
diff --git a/core/java/com/android/internal/os/AtomicDirectory.java b/core/java/com/android/internal/os/AtomicDirectory.java
new file mode 100644
index 0000000..f24d12e
--- /dev/null
+++ b/core/java/com/android/internal/os/AtomicDirectory.java
@@ -0,0 +1,294 @@
+/*
+ * 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.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.FileUtils;
+import android.util.ArrayMap;
+
+import com.android.internal.util.Preconditions;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * Helper class for performing atomic operations on a directory, by creating a
+ * backup directory until a write has successfully completed.
+ * <p>
+ * Atomic directory guarantees directory integrity by ensuring that a directory has
+ * been completely written and sync'd to disk before removing its backup.
+ * As long as the backup directory exists, the original directory is considered
+ * to be invalid (leftover from a previous attempt to write).
+ * <p>
+ * Atomic directory does not confer any file locking semantics. Do not use this
+ * class when the directory may be accessed or modified concurrently
+ * by multiple threads or processes. The caller is responsible for ensuring
+ * appropriate mutual exclusion invariants whenever it accesses the directory.
+ * <p>
+ * To ensure atomicity you must always use this class to interact with the
+ * backing directory when checking existence, making changes, and deleting.
+ */
+public final class AtomicDirectory {
+    private final @NonNull ArrayMap<File, FileOutputStream> mOpenFiles = new ArrayMap<>();
+    private final @NonNull File mBaseDirectory;
+    private final @NonNull File mBackupDirectory;
+
+    private int mBaseDirectoryFd = -1;
+    private int mBackupDirectoryFd = -1;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param baseDirectory The base directory to treat atomically.
+     */
+    public AtomicDirectory(@NonNull File baseDirectory) {
+        Preconditions.checkNotNull(baseDirectory, "baseDirectory cannot be null");
+        mBaseDirectory = baseDirectory;
+        mBackupDirectory = new File(baseDirectory.getPath() + "_bak");
+    }
+
+    /**
+     * Gets the backup directory if present. This could be useful if you are
+     * writing new state to the dir but need to access the last persisted state
+     * at the same time. This means that this call is useful in between
+     * {@link #startWrite()} and {@link #finishWrite()} or {@link #failWrite()}.
+     * You should not modify the content returned by this method.
+     *
+     * @see #startRead()
+     */
+    public @Nullable File getBackupDirectory() {
+        return mBackupDirectory;
+    }
+
+    /**
+     * Starts reading this directory. After calling this method you should
+     * not make any changes to its contents.
+     *
+     * @throws IOException If an error occurs.
+     *
+     * @see #finishRead()
+     * @see #startWrite()
+     */
+    public @NonNull File startRead() throws IOException {
+        restore();
+        return getOrCreateBaseDirectory();
+    }
+
+    /**
+     * Finishes reading this directory.
+     *
+     * @see #startRead()
+     * @see #startWrite()
+     */
+    public void finishRead() {
+        mBaseDirectoryFd = -1;
+        mBackupDirectoryFd = -1;
+    }
+
+    /**
+     * Starts editing this directory. After calling this method you should
+     * add content to the directory only via the APIs on this class. To open a
+     * file for writing in this directory you should use {@link #openWrite(File)}
+     * and to close the file {@link #closeWrite(FileOutputStream)}. Once all
+     * content has been written and all files closed you should commit via a
+     * call to {@link #finishWrite()} or discard via a call to {@link #failWrite()}.
+     *
+     * @throws IOException If an error occurs.
+     *
+     * @see #startRead()
+     * @see #openWrite(File)
+     * @see #finishWrite()
+     * @see #failWrite()
+     */
+    public @NonNull File startWrite() throws IOException {
+        backup();
+        return getOrCreateBaseDirectory();
+    }
+
+    /**
+     * Opens a file in this directory for writing.
+     *
+     * @param file The file to open. Must be a file in the base directory.
+     * @return An input stream for reading.
+     *
+     * @throws IOException If an I/O error occurs.
+     *
+     * @see #closeWrite(FileOutputStream)
+     */
+    public @NonNull FileOutputStream openWrite(@NonNull File file) throws IOException {
+        if (file.isDirectory() || !file.getParentFile().equals(getOrCreateBaseDirectory())) {
+            throw new IllegalArgumentException("Must be a file in " + getOrCreateBaseDirectory());
+        }
+        final FileOutputStream destination = new FileOutputStream(file);
+        if (mOpenFiles.put(file, destination) != null) {
+            throw new IllegalArgumentException("Already open file" + file.getCanonicalPath());
+        }
+        return destination;
+    }
+
+    /**
+     * Closes a previously opened file.
+     *
+     * @param destination The stream to the file returned by {@link #openWrite(File)}.
+     *
+     * @see #openWrite(File)
+     */
+    public void closeWrite(@NonNull FileOutputStream destination) {
+        final int indexOfValue = mOpenFiles.indexOfValue(destination);
+        if (mOpenFiles.removeAt(indexOfValue) == null) {
+            throw new IllegalArgumentException("Unknown file stream " + destination);
+        }
+        FileUtils.sync(destination);
+        try {
+            destination.close();
+        } catch (IOException ignored) {}
+    }
+
+    public void failWrite(@NonNull FileOutputStream destination) {
+        final int indexOfValue = mOpenFiles.indexOfValue(destination);
+        if (indexOfValue >= 0) {
+            mOpenFiles.removeAt(indexOfValue);
+        }
+    }
+
+    /**
+     * Finishes the edit and commits all changes.
+     *
+     * @see #startWrite()
+     *
+     * @throws IllegalStateException is some files are not closed.
+     */
+    public void finishWrite() {
+        throwIfSomeFilesOpen();
+        fsyncDirectoryFd(mBaseDirectoryFd);
+        deleteDirectory(mBackupDirectory);
+        fsyncDirectoryFd(mBackupDirectoryFd);
+        mBaseDirectoryFd = -1;
+        mBackupDirectoryFd = -1;
+    }
+
+    /**
+     * Finishes the edit and discards all changes.
+     *
+     * @see #startWrite()
+     */
+    public void failWrite() {
+        throwIfSomeFilesOpen();
+        try{
+            restore();
+        } catch (IOException ignored) {}
+        mBaseDirectoryFd = -1;
+        mBackupDirectoryFd = -1;
+    }
+
+    /**
+     * @return Whether this directory exists.
+     */
+    public boolean exists() {
+        return mBaseDirectory.exists() || mBackupDirectory.exists();
+    }
+
+    /**
+     * Deletes this directory.
+     */
+    public void delete() {
+        if (mBaseDirectory.exists()) {
+            deleteDirectory(mBaseDirectory);
+            fsyncDirectoryFd(mBaseDirectoryFd);
+        }
+        if (mBackupDirectory.exists()) {
+            deleteDirectory(mBackupDirectory);
+            fsyncDirectoryFd(mBackupDirectoryFd);
+        }
+    }
+
+    private @NonNull File getOrCreateBaseDirectory() throws IOException {
+        if (!mBaseDirectory.exists()) {
+            if (!mBaseDirectory.mkdirs()) {
+                throw new IOException("Couldn't create directory " + mBaseDirectory);
+            }
+            FileUtils.setPermissions(mBaseDirectory.getPath(),
+                    FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH,
+                    -1, -1);
+        }
+        if (mBaseDirectoryFd < 0) {
+            mBaseDirectoryFd = getDirectoryFd(mBaseDirectory.getCanonicalPath());
+        }
+        return mBaseDirectory;
+    }
+
+    private void throwIfSomeFilesOpen() {
+        if (!mOpenFiles.isEmpty()) {
+            throw new IllegalStateException("Unclosed files: "
+                    + Arrays.toString(mOpenFiles.keySet().toArray()));
+        }
+    }
+
+    private void backup() throws IOException {
+        if (!mBaseDirectory.exists()) {
+            return;
+        }
+        if (mBaseDirectoryFd < 0) {
+            mBaseDirectoryFd = getDirectoryFd(mBaseDirectory.getCanonicalPath());
+        }
+        if (mBackupDirectory.exists()) {
+            deleteDirectory(mBackupDirectory);
+        }
+        if (!mBaseDirectory.renameTo(mBackupDirectory)) {
+            throw new IOException("Couldn't backup " + mBaseDirectory
+                    + " to " + mBackupDirectory);
+        }
+        mBackupDirectoryFd = mBaseDirectoryFd;
+        mBaseDirectoryFd = -1;
+        fsyncDirectoryFd(mBackupDirectoryFd);
+    }
+
+    private void restore() throws IOException {
+        if (!mBackupDirectory.exists()) {
+            return;
+        }
+        if (mBackupDirectoryFd == -1) {
+            mBackupDirectoryFd = getDirectoryFd(mBackupDirectory.getCanonicalPath());
+        }
+        if (mBaseDirectory.exists()) {
+            deleteDirectory(mBaseDirectory);
+        }
+        if (!mBackupDirectory.renameTo(mBaseDirectory)) {
+            throw new IOException("Couldn't restore " + mBackupDirectory
+                    + " to " + mBaseDirectory);
+        }
+        mBaseDirectoryFd = mBackupDirectoryFd;
+        mBackupDirectoryFd = -1;
+        fsyncDirectoryFd(mBaseDirectoryFd);
+    }
+
+    private static void deleteDirectory(@NonNull File file) {
+        final File[] children = file.listFiles();
+        if (children != null) {
+            for (File child : children) {
+                deleteDirectory(child);
+            }
+        }
+        file.delete();
+    }
+
+    private static native int getDirectoryFd(String path);
+    private static native void fsyncDirectoryFd(int fd);
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index cc8da5c..534361e 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -30,6 +30,7 @@
 import android.database.ContentObserver;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
+import android.net.INetworkStatsService;
 import android.net.NetworkStats;
 import android.net.Uri;
 import android.net.wifi.WifiActivityEnergyInfo;
@@ -86,7 +87,10 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.location.gnssmetrics.GnssMetrics;
-import com.android.internal.net.NetworkStatsFactory;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
@@ -187,18 +191,19 @@
     private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
 
     @VisibleForTesting
-    protected KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader();
+    protected KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader =
+            new KernelCpuUidUserSysTimeReader(true);
     @VisibleForTesting
     protected KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
     @VisibleForTesting
-    protected KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader =
-            new KernelUidCpuFreqTimeReader();
+    protected KernelCpuUidFreqTimeReader mCpuUidFreqTimeReader =
+            new KernelCpuUidFreqTimeReader(true);
     @VisibleForTesting
-    protected KernelUidCpuActiveTimeReader mKernelUidCpuActiveTimeReader =
-            new KernelUidCpuActiveTimeReader();
+    protected KernelCpuUidActiveTimeReader mCpuUidActiveTimeReader =
+            new KernelCpuUidActiveTimeReader(true);
     @VisibleForTesting
-    protected KernelUidCpuClusterTimeReader mKernelUidCpuClusterTimeReader =
-            new KernelUidCpuClusterTimeReader();
+    protected KernelCpuUidClusterTimeReader mCpuUidClusterTimeReader =
+            new KernelCpuUidClusterTimeReader(true);
     @VisibleForTesting
     protected KernelSingleUidTimeReader mKernelSingleUidTimeReader;
 
@@ -248,9 +253,9 @@
     /** Last time that RPM stats were updated by updateRpmStatsLocked. */
     private long mLastRpmStatsUpdateTimeMs = -RPM_STATS_UPDATE_FREQ_MS;
     /**
-     * Use a queue to delay removing UIDs from {@link KernelUidCpuTimeReader},
-     * {@link KernelUidCpuActiveTimeReader}, {@link KernelUidCpuClusterTimeReader},
-     * {@link KernelUidCpuFreqTimeReader} and from the Kernel.
+     * Use a queue to delay removing UIDs from {@link KernelCpuUidUserSysTimeReader},
+     * {@link KernelCpuUidActiveTimeReader}, {@link KernelCpuUidClusterTimeReader},
+     * {@link KernelCpuUidFreqTimeReader} and from the Kernel.
      *
      * Isolated and invalid UID info must be removed to conserve memory. However, STATSD and
      * Batterystats both need to access UID cpu time. To resolve this race condition, only
@@ -281,22 +286,22 @@
 
         void remove() {
             if (startUid == endUid) {
-                mKernelUidCpuTimeReader.removeUid(startUid);
-                mKernelUidCpuFreqTimeReader.removeUid(startUid);
+                mCpuUidUserSysTimeReader.removeUid(startUid);
+                mCpuUidFreqTimeReader.removeUid(startUid);
                 if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
-                    mKernelUidCpuActiveTimeReader.removeUid(startUid);
-                    mKernelUidCpuClusterTimeReader.removeUid(startUid);
+                    mCpuUidActiveTimeReader.removeUid(startUid);
+                    mCpuUidClusterTimeReader.removeUid(startUid);
                 }
                 if (mKernelSingleUidTimeReader != null) {
                     mKernelSingleUidTimeReader.removeUid(startUid);
                 }
                 mNumUidsRemoved++;
             } else if (startUid < endUid) {
-                mKernelUidCpuFreqTimeReader.removeUidsInRange(startUid, endUid);
-                mKernelUidCpuTimeReader.removeUidsInRange(startUid, endUid);
+                mCpuUidFreqTimeReader.removeUidsInRange(startUid, endUid);
+                mCpuUidUserSysTimeReader.removeUidsInRange(startUid, endUid);
                 if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
-                    mKernelUidCpuActiveTimeReader.removeUidsInRange(startUid, endUid);
-                    mKernelUidCpuClusterTimeReader.removeUidsInRange(startUid, endUid);
+                    mCpuUidActiveTimeReader.removeUidsInRange(startUid, endUid);
+                    mCpuUidClusterTimeReader.removeUidsInRange(startUid, endUid);
                 }
                 if (mKernelSingleUidTimeReader != null) {
                     mKernelSingleUidTimeReader.removeUidsInRange(startUid, endUid);
@@ -337,6 +342,25 @@
 
     private final PlatformIdleStateCallback mPlatformIdleStateCallback;
 
+    private final Runnable mDeferSetCharging = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (BatteryStatsImpl.this) {
+                if (mOnBattery) {
+                    // if the device gets unplugged in the time between this runnable being
+                    // executed and the lock being taken, we don't want to set charging state
+                    return;
+                }
+                boolean changed = setChargingLocked(true);
+                if (changed) {
+                    final long uptime = mClocks.uptimeMillis();
+                    final long elapsedRealtime = mClocks.elapsedRealtime();
+                    addHistoryRecordLocked(elapsedRealtime, uptime);
+                }
+            }
+        }
+    };
+
     /**
      * This handler is running on {@link BackgroundThread}.
      */
@@ -477,7 +501,7 @@
             }
 
             final SparseArray<long[]> allUidCpuFreqTimesMs =
-                    mKernelUidCpuFreqTimeReader.getAllUidCpuFreqTimeMs();
+                    mCpuUidFreqTimeReader.getAllUidCpuFreqTimeMs();
             // If the KernelSingleUidTimeReader has stale cpu times, then we shouldn't try to
             // compute deltas since it might result in mis-attributing cpu times to wrong states.
             if (mIsPerProcessStateCpuDataStale) {
@@ -534,16 +558,16 @@
                 return false;
             }
             if (mCpuFreqs == null) {
-                mCpuFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile);
+                mCpuFreqs = mCpuUidFreqTimeReader.readFreqs(mPowerProfile);
             }
             if (mCpuFreqs != null) {
                 mKernelSingleUidTimeReader = new KernelSingleUidTimeReader(mCpuFreqs.length);
             } else {
-                mPerProcStateCpuTimesAvailable = mKernelUidCpuFreqTimeReader.allUidTimesAvailable();
+                mPerProcStateCpuTimesAvailable = mCpuUidFreqTimeReader.allUidTimesAvailable();
                 return false;
             }
         }
-        mPerProcStateCpuTimesAvailable = mKernelUidCpuFreqTimeReader.allUidTimesAvailable()
+        mPerProcStateCpuTimesAvailable = mCpuUidFreqTimeReader.allUidTimesAvailable()
                 && mKernelSingleUidTimeReader.singleUidCpuTimesAvailable();
         return true;
     }
@@ -11012,7 +11036,6 @@
         }
     }
 
-    private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
     private final Pools.Pool<NetworkStats> mNetworkStatsPool = new Pools.SynchronizedPool<>(6);
 
     private final Object mWifiNetworkLock = new Object();
@@ -11034,11 +11057,16 @@
     private NetworkStats readNetworkStatsLocked(String[] ifaces) {
         try {
             if (!ArrayUtils.isEmpty(ifaces)) {
-                return mNetworkStatsFactory.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
-                        NetworkStats.TAG_NONE, mNetworkStatsPool.acquire());
+                INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
+                        ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+                if (statsService != null) {
+                    return statsService.getDetailedUidStats(ifaces);
+                } else {
+                    Slog.e(TAG, "Failed to get networkStatsService ");
+                }
             }
-        } catch (IOException e) {
-            Slog.e(TAG, "failed to read network stats for ifaces: " + Arrays.toString(ifaces));
+        } catch (RemoteException e) {
+            Slog.e(TAG, "failed to read network stats for ifaces: " + Arrays.toString(ifaces) + e);
         }
         return null;
     }
@@ -11903,7 +11931,7 @@
         }
 
         if (mCpuFreqs == null) {
-            mCpuFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile);
+            mCpuFreqs = mCpuUidFreqTimeReader.readFreqs(mPowerProfile);
         }
 
         // Calculate the wakelocks we have to distribute amongst. The system is excluded as it is
@@ -11929,12 +11957,12 @@
         // When the battery is not on, we don't attribute the cpu times to any timers but we still
         // need to take the snapshots.
         if (!onBattery) {
-            mKernelUidCpuTimeReader.readDelta(null);
-            mKernelUidCpuFreqTimeReader.readDelta(null);
+            mCpuUidUserSysTimeReader.readDelta(null);
+            mCpuUidFreqTimeReader.readDelta(null);
             mNumAllUidCpuTimeReads += 2;
             if (mConstants.TRACK_CPU_ACTIVE_CLUSTER_TIME) {
-                mKernelUidCpuActiveTimeReader.readDelta(null);
-                mKernelUidCpuClusterTimeReader.readDelta(null);
+                mCpuUidActiveTimeReader.readDelta(null);
+                mCpuUidClusterTimeReader.readDelta(null);
                 mNumAllUidCpuTimeReads += 2;
             }
             for (int cluster = mKernelCpuSpeedReaders.length - 1; cluster >= 0; --cluster) {
@@ -11944,7 +11972,7 @@
         }
 
         mUserInfoProvider.refreshUserIds();
-        final SparseLongArray updatedUids = mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()
+        final SparseLongArray updatedUids = mCpuUidFreqTimeReader.perClusterTimesAvailable()
                 ? null : new SparseLongArray();
         readKernelUidCpuTimesLocked(partialTimersToConsider, updatedUids, onBattery);
         // updatedUids=null means /proc/uid_time_in_state provides snapshots of per-cluster cpu
@@ -12061,18 +12089,20 @@
         final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
         final long startTimeMs = mClocks.uptimeMillis();
 
-        mKernelUidCpuTimeReader.readDelta((uid, userTimeUs, systemTimeUs) -> {
+        mCpuUidUserSysTimeReader.readDelta((uid, timesUs) -> {
+            long userTimeUs = timesUs[0], systemTimeUs = timesUs[1];
+
             uid = mapUid(uid);
             if (Process.isIsolated(uid)) {
                 // This could happen if the isolated uid mapping was removed before that process
                 // was actually killed.
-                mKernelUidCpuTimeReader.removeUid(uid);
+                mCpuUidUserSysTimeReader.removeUid(uid);
                 Slog.d(TAG, "Got readings for an isolated uid with no mapping: " + uid);
                 return;
             }
             if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
                 Slog.d(TAG, "Got readings for an invalid user's uid " + uid);
-                mKernelUidCpuTimeReader.removeUid(uid);
+                mCpuUidUserSysTimeReader.removeUid(uid);
                 return;
             }
             final Uid u = getUidStatsLocked(uid);
@@ -12166,21 +12196,21 @@
     public void readKernelUidCpuFreqTimesLocked(@Nullable ArrayList<StopwatchTimer> partialTimers,
             boolean onBattery, boolean onBatteryScreenOff) {
         final boolean perClusterTimesAvailable =
-                mKernelUidCpuFreqTimeReader.perClusterTimesAvailable();
+                mCpuUidFreqTimeReader.perClusterTimesAvailable();
         final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
         final int numClusters = mPowerProfile.getNumCpuClusters();
         mWakeLockAllocationsUs = null;
         final long startTimeMs = mClocks.uptimeMillis();
-        mKernelUidCpuFreqTimeReader.readDelta((uid, cpuFreqTimeMs) -> {
+        mCpuUidFreqTimeReader.readDelta((uid, cpuFreqTimeMs) -> {
             uid = mapUid(uid);
             if (Process.isIsolated(uid)) {
-                mKernelUidCpuFreqTimeReader.removeUid(uid);
+                mCpuUidFreqTimeReader.removeUid(uid);
                 Slog.d(TAG, "Got freq readings for an isolated uid with no mapping: " + uid);
                 return;
             }
             if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
                 Slog.d(TAG, "Got freq readings for an invalid user's uid " + uid);
-                mKernelUidCpuFreqTimeReader.removeUid(uid);
+                mCpuUidFreqTimeReader.removeUid(uid);
                 return;
             }
             final Uid u = getUidStatsLocked(uid);
@@ -12284,16 +12314,16 @@
     @VisibleForTesting
     public void readKernelUidCpuActiveTimesLocked(boolean onBattery) {
         final long startTimeMs = mClocks.uptimeMillis();
-        mKernelUidCpuActiveTimeReader.readDelta((uid, cpuActiveTimesMs) -> {
+        mCpuUidActiveTimeReader.readDelta((uid, cpuActiveTimesMs) -> {
             uid = mapUid(uid);
             if (Process.isIsolated(uid)) {
-                mKernelUidCpuActiveTimeReader.removeUid(uid);
+                mCpuUidActiveTimeReader.removeUid(uid);
                 Slog.w(TAG, "Got active times for an isolated uid with no mapping: " + uid);
                 return;
             }
             if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
                 Slog.w(TAG, "Got active times for an invalid user's uid " + uid);
-                mKernelUidCpuActiveTimeReader.removeUid(uid);
+                mCpuUidActiveTimeReader.removeUid(uid);
                 return;
             }
             final Uid u = getUidStatsLocked(uid);
@@ -12313,16 +12343,16 @@
     @VisibleForTesting
     public void readKernelUidCpuClusterTimesLocked(boolean onBattery) {
         final long startTimeMs = mClocks.uptimeMillis();
-        mKernelUidCpuClusterTimeReader.readDelta((uid, cpuClusterTimesMs) -> {
+        mCpuUidClusterTimeReader.readDelta((uid, cpuClusterTimesMs) -> {
             uid = mapUid(uid);
             if (Process.isIsolated(uid)) {
-                mKernelUidCpuClusterTimeReader.removeUid(uid);
+                mCpuUidClusterTimeReader.removeUid(uid);
                 Slog.w(TAG, "Got cluster times for an isolated uid with no mapping: " + uid);
                 return;
             }
             if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) {
                 Slog.w(TAG, "Got cluster times for an invalid user's uid " + uid);
-                mKernelUidCpuClusterTimeReader.removeUid(uid);
+                mCpuUidClusterTimeReader.removeUid(uid);
                 return;
             }
             final Uid u = getUidStatsLocked(uid);
@@ -12336,6 +12366,14 @@
     }
 
     boolean setChargingLocked(boolean charging) {
+        // if the device is no longer charging, remove the callback
+        // if the device is now charging, it means that this is either called
+        // 1. directly when level >= 90
+        // 2. or from within the runnable that we deferred
+        // For 1. if we have an existing callback, remove it, since we will immediatelly send a
+        // ACTION_CHARGING
+        // For 2. we remove existing callback so we don't send multiple ACTION_CHARGING
+        mHandler.removeCallbacks(mDeferSetCharging);
         if (mCharging != charging) {
             mCharging = charging;
             if (charging) {
@@ -12674,12 +12712,23 @@
                     // charging even if it happens to go down a level.
                     changed |= setChargingLocked(true);
                     mLastChargeStepLevel = level;
-                } if (!mCharging) {
+                }
+                if (!mCharging) {
                     if (mLastChargeStepLevel < level) {
-                        // We have not reporting that we are charging, but the level has now
-                        // gone up, so consider the state to be charging.
-                        changed |= setChargingLocked(true);
+                        // We have not reported that we are charging, but the level has gone up,
+                        // but we would like to not have tons of activity from charging-constraint
+                        // jobs, so instead of reporting ACTION_CHARGING immediately, we defer it.
                         mLastChargeStepLevel = level;
+                        if (!mHandler.hasCallbacks(mDeferSetCharging)) {
+                            mHandler.postDelayed(
+                                    mDeferSetCharging,
+                                    mConstants.BATTERY_CHARGED_DELAY_MS);
+                        }
+                    } else if (mLastChargeStepLevel > level) {
+                        // if we had deferred a runnable due to charge level increasing, but then
+                        // later the charge level drops (could be due to thermal issues), we don't
+                        // want to trigger the deferred runnable, so remove it here
+                        mHandler.removeCallbacks(mDeferSetCharging);
                     }
                 } else {
                     if (mLastChargeStepLevel > level) {
@@ -13296,11 +13345,13 @@
                 = "battery_level_collection_delay_ms";
         public static final String KEY_MAX_HISTORY_FILES = "max_history_files";
         public static final String KEY_MAX_HISTORY_BUFFER_KB = "max_history_buffer_kb";
+        public static final String KEY_BATTERY_CHARGED_DELAY_MS =
+                "battery_charged_delay_ms";
 
         private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = false;
         private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true;
         private static final long DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS = 5_000;
-        private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 10_000;
+        private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 1_000;
         private static final long DEFAULT_UID_REMOVE_DELAY_MS = 5L * 60L * 1000L;
         private static final long DEFAULT_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS = 600_000;
         private static final long DEFAULT_BATTERY_LEVEL_COLLECTION_DELAY_MS = 300_000;
@@ -13308,11 +13359,14 @@
         private static final int DEFAULT_MAX_HISTORY_BUFFER_KB = 128; /*Kilo Bytes*/
         private static final int DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE = 64;
         private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/
+        private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */
 
         public boolean TRACK_CPU_TIMES_BY_PROC_STATE = DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE;
         public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
         public long PROC_STATE_CPU_TIMES_READ_DELAY_MS = DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS;
-        public long KERNEL_UID_READERS_THROTTLE_TIME = DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME;
+        /* Do not set default value for KERNEL_UID_READERS_THROTTLE_TIME. Need to trigger an
+         * update when startObserving. */
+        public long KERNEL_UID_READERS_THROTTLE_TIME;
         public long UID_REMOVE_DELAY_MS = DEFAULT_UID_REMOVE_DELAY_MS;
         public long EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS
                 = DEFAULT_EXTERNAL_STATS_COLLECTION_RATE_LIMIT_MS;
@@ -13320,6 +13374,7 @@
                 = DEFAULT_BATTERY_LEVEL_COLLECTION_DELAY_MS;
         public int MAX_HISTORY_FILES;
         public int MAX_HISTORY_BUFFER; /*Bytes*/
+        public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
 
         private ContentResolver mResolver;
         private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -13388,6 +13443,9 @@
                                 DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB
                                 : DEFAULT_MAX_HISTORY_BUFFER_KB)
                         * 1024;
+                BATTERY_CHARGED_DELAY_MS = mParser.getInt(
+                        KEY_BATTERY_CHARGED_DELAY_MS,
+                        DEFAULT_BATTERY_CHARGED_DELAY_MS);
             }
         }
 
@@ -13415,11 +13473,11 @@
         private void updateKernelUidReadersThrottleTime(long oldTimeMs, long newTimeMs) {
             KERNEL_UID_READERS_THROTTLE_TIME = newTimeMs;
             if (oldTimeMs != newTimeMs) {
-                mKernelUidCpuTimeReader.setThrottleInterval(KERNEL_UID_READERS_THROTTLE_TIME);
-                mKernelUidCpuFreqTimeReader.setThrottleInterval(KERNEL_UID_READERS_THROTTLE_TIME);
-                mKernelUidCpuActiveTimeReader.setThrottleInterval(KERNEL_UID_READERS_THROTTLE_TIME);
-                mKernelUidCpuClusterTimeReader
-                        .setThrottleInterval(KERNEL_UID_READERS_THROTTLE_TIME);
+                mCpuUidUserSysTimeReader.setThrottle(KERNEL_UID_READERS_THROTTLE_TIME);
+                mCpuUidFreqTimeReader.setThrottle(KERNEL_UID_READERS_THROTTLE_TIME);
+                mCpuUidActiveTimeReader.setThrottle(KERNEL_UID_READERS_THROTTLE_TIME);
+                mCpuUidClusterTimeReader
+                        .setThrottle(KERNEL_UID_READERS_THROTTLE_TIME);
             }
         }
 
@@ -13445,6 +13503,8 @@
             pw.println(MAX_HISTORY_FILES);
             pw.print(KEY_MAX_HISTORY_BUFFER_KB); pw.print("=");
             pw.println(MAX_HISTORY_BUFFER/1024);
+            pw.print(KEY_BATTERY_CHARGED_DELAY_MS); pw.print("=");
+            pw.println(BATTERY_CHARGED_DELAY_MS);
         }
     }
 
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 051a96c..6454352 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -53,6 +53,7 @@
     public static final boolean DETAILED_TRACKING_DEFAULT = true;
     public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 100;
     public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 5000;
+    private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_";
 
     private static class OverflowBinder extends Binder {}
 
@@ -347,7 +348,7 @@
         callStat.callingUid = uid;
         callStat.recordedCallCount = 1;
         callStat.callCount = 1;
-        callStat.methodName = "__DEBUG_" + variableName;
+        callStat.methodName = DEBUG_ENTRY_PREFIX + variableName;
         callStat.latencyMicros = value;
         return callStat;
     }
@@ -398,6 +399,10 @@
         final List<ExportedCallStat> exportedCallStats = getExportedCallStats();
         exportedCallStats.sort(BinderCallsStats::compareByCpuDesc);
         for (ExportedCallStat e : exportedCallStats) {
+            if (e.methodName.startsWith(DEBUG_ENTRY_PREFIX)) {
+                // Do not dump debug entries.
+                continue;
+            }
             sb.setLength(0);
             sb.append("    ")
                     .append(packageMap.mapUid(e.callingUid))
diff --git a/core/java/com/android/internal/os/ChildZygoteInit.java b/core/java/com/android/internal/os/ChildZygoteInit.java
new file mode 100644
index 0000000..a052a3b
--- /dev/null
+++ b/core/java/com/android/internal/os/ChildZygoteInit.java
@@ -0,0 +1,137 @@
+/*
+ * 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.os;
+
+import android.os.Process;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+
+/**
+ * ChildZygoteInit is shared by both the Application and WebView zygote to initialize
+ * and run a (child) Zygote server.
+ *
+ * @hide
+ */
+public class ChildZygoteInit {
+    private static final String TAG = "ChildZygoteInit";
+
+    static String parseSocketNameFromArgs(String[] argv) {
+        for (String arg : argv) {
+            if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
+                return arg.substring(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG.length());
+            }
+        }
+
+        return null;
+    }
+
+    static String parseAbiListFromArgs(String[] argv) {
+        for (String arg : argv) {
+            if (arg.startsWith(Zygote.CHILD_ZYGOTE_ABI_LIST_ARG)) {
+                return arg.substring(Zygote.CHILD_ZYGOTE_ABI_LIST_ARG.length());
+            }
+        }
+
+        return null;
+    }
+
+    static int parseIntFromArg(String[] argv, String desiredArg) {
+        int value = -1;
+        for (String arg : argv) {
+            if (arg.startsWith(desiredArg)) {
+                String valueStr = arg.substring(arg.indexOf('=') + 1);
+                try {
+                    value = Integer.parseInt(valueStr);
+                } catch (NumberFormatException e) {
+                    throw new IllegalArgumentException("Invalid int argument: "
+                            + valueStr, e);
+                }
+            }
+        }
+        return value;
+    }
+
+    /**
+     * Starts a ZygoteServer and listens for requests
+     *
+     * @param server An instance of a ZygoteServer to listen on
+     * @param args Passed in arguments for this ZygoteServer
+     */
+    static void runZygoteServer(ZygoteServer server, String[] args) {
+        String socketName = parseSocketNameFromArgs(args);
+        if (socketName == null) {
+            throw new NullPointerException("No socketName specified");
+        }
+
+        String abiList = parseAbiListFromArgs(args);
+        if (abiList == null) {
+            throw new NullPointerException("No abiList specified");
+        }
+
+        try {
+            Os.prctl(OsConstants.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+        } catch (ErrnoException ex) {
+            throw new RuntimeException("Failed to set PR_SET_NO_NEW_PRIVS", ex);
+        }
+
+        int uidGidMin = parseIntFromArg(args, Zygote.CHILD_ZYGOTE_UID_RANGE_START);
+        int uidGidMax = parseIntFromArg(args, Zygote.CHILD_ZYGOTE_UID_RANGE_END);
+        if (uidGidMin == -1 || uidGidMax == -1) {
+            throw new RuntimeException("Couldn't parse UID range start/end");
+        }
+        if (uidGidMin > uidGidMax) {
+            throw new RuntimeException("Passed in UID range is invalid, min > max.");
+        }
+
+        // Verify the UIDs are in the isolated UID range, as that's the only thing that we should
+        // be forking right now
+        if (!Process.isIsolated(uidGidMin) || !Process.isIsolated(uidGidMax)) {
+            throw new RuntimeException("Passed in UID range does not map to isolated processes.");
+        }
+
+        /**
+         * Install a seccomp filter that ensure this Zygote can only setuid()/setgid()
+         * to the passed in range.
+         */
+        Zygote.nativeInstallSeccompUidGidFilter(uidGidMin, uidGidMax);
+
+        final Runnable caller;
+        try {
+            server.registerServerSocketAtAbstractName(socketName);
+
+            // Add the abstract socket to the FD whitelist so that the native zygote code
+            // can properly detach it after forking.
+            Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName);
+
+            // The select loop returns early in the child process after a fork and
+            // loops forever in the zygote.
+            caller = server.runSelectLoop(abiList);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Fatal exception:", e);
+            throw e;
+        } finally {
+            server.closeServerSocket();
+        }
+
+        // We're in the child process and have exited the select loop. Proceed to execute the
+        // command.
+        if (caller != null) {
+            caller.run();
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/KernelCpuProcReader.java b/core/java/com/android/internal/os/KernelCpuProcReader.java
deleted file mode 100644
index c233ea8..0000000
--- a/core/java/com/android/internal/os/KernelCpuProcReader.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import android.os.StrictMode;
-import android.os.SystemClock;
-import android.util.Slog;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Arrays;
-
-/**
- * Reads cpu time proc files with throttling (adjustable interval).
- *
- * KernelCpuProcReader is implemented as singletons for built-in kernel proc files. Get___Instance()
- * method will return corresponding reader instance. In order to prevent frequent GC,
- * KernelCpuProcReader reuses a {@link ByteBuffer} to store data read from proc files.
- *
- * A KernelCpuProcReader instance keeps an error counter. When the number of read errors within that
- * instance accumulates to 5, this instance will reject all further read requests.
- *
- * Each KernelCpuProcReader instance also has a throttler. Throttle interval can be adjusted via
- * {@link #setThrottleInterval(long)} method. Default throttle interval is 3000ms. If current
- * timestamp based on {@link SystemClock#elapsedRealtime()} is less than throttle interval from
- * the last read timestamp, {@link #readBytes()} will return previous result.
- *
- * A KernelCpuProcReader instance is thread-unsafe. Caller needs to hold a lock on this object while
- * accessing its instance methods or digesting the return values.
- */
-public class KernelCpuProcReader {
-    private static final String TAG = "KernelCpuProcReader";
-    private static final int ERROR_THRESHOLD = 5;
-    // Throttle interval in milliseconds
-    private static final long DEFAULT_THROTTLE_INTERVAL = 3000L;
-    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";
-    private static final String PROC_UID_CLUSTER_TIME = "/proc/uid_cpupower/concurrent_policy_time";
-
-    private static final KernelCpuProcReader mFreqTimeReader = new KernelCpuProcReader(
-            PROC_UID_FREQ_TIME);
-    private static final KernelCpuProcReader mActiveTimeReader = new KernelCpuProcReader(
-            PROC_UID_ACTIVE_TIME);
-    private static final KernelCpuProcReader mClusterTimeReader = new KernelCpuProcReader(
-            PROC_UID_CLUSTER_TIME);
-
-    public static KernelCpuProcReader getFreqTimeReaderInstance() {
-        return mFreqTimeReader;
-    }
-
-    public static KernelCpuProcReader getActiveTimeReaderInstance() {
-        return mActiveTimeReader;
-    }
-
-    public static KernelCpuProcReader getClusterTimeReaderInstance() {
-        return mClusterTimeReader;
-    }
-
-    private int mErrors;
-    private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL;
-    private long mLastReadTime = Long.MIN_VALUE;
-    private final Path mProc;
-    private byte[] mBuffer = new byte[8 * 1024];
-    private int mContentSize;
-
-    @VisibleForTesting
-    public KernelCpuProcReader(String procFile) {
-        mProc = Paths.get(procFile);
-    }
-
-    /**
-     * Reads all bytes from the corresponding proc file.
-     *
-     * If elapsed time since last call to this method is less than the throttle interval, it will
-     * return previous result. When IOException accumulates to 5, it will always return null. This
-     * method is thread-unsafe, so is the return value. Caller needs to hold a lock on this
-     * object while calling this method and digesting its return value.
-     *
-     * @return a {@link ByteBuffer} containing all bytes from the proc file.
-     */
-    public ByteBuffer readBytes() {
-        if (mErrors >= ERROR_THRESHOLD) {
-            return null;
-        }
-        if (SystemClock.elapsedRealtime() < mLastReadTime + mThrottleInterval) {
-            if (mContentSize > 0) {
-                return ByteBuffer.wrap(mBuffer, 0, mContentSize).asReadOnlyBuffer()
-                        .order(ByteOrder.nativeOrder());
-            }
-            return null;
-        }
-        mLastReadTime = SystemClock.elapsedRealtime();
-        mContentSize = 0;
-        final int oldMask = StrictMode.allowThreadDiskReadsMask();
-        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));
-                }
-            }
-            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);
-        } catch (IOException e) {
-            mErrors++;
-            Slog.e(TAG, "Error reading: " + mProc, e);
-        } finally {
-            StrictMode.setThreadPolicyMask(oldMask);
-        }
-        return null;
-    }
-
-    /**
-     * Sets the throttle interval. Set to 0 will disable throttling. Thread-unsafe, holding a lock
-     * on this object is recommended.
-     *
-     * @param throttleInterval throttle interval in milliseconds
-     */
-    public void setThrottleInterval(long throttleInterval) {
-        if (throttleInterval >= 0) {
-            mThrottleInterval = throttleInterval;
-        }
-    }
-}
diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
index 7021b57..e6d044f 100644
--- a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
@@ -177,6 +177,9 @@
      * The file contains a monotonically increasing count of time for a single boot. This class
      * maintains the previous results of a call to {@link #readDelta} in order to provide a proper
      * delta.
+     *
+     * The second parameter of the callback is a long[] with 2 elements, [user time in us, system
+     * time in us].
      */
     public static class KernelCpuUidUserSysTimeReader extends KernelCpuUidTimeReader<long[]> {
         private static final String REMOVE_UID_PROC_FILE = "/proc/uid_cputime/remove_uid_range";
diff --git a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
index ad62852..3c43a11 100644
--- a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
@@ -16,7 +16,6 @@
 package com.android.internal.os;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
-import static com.android.internal.os.KernelUidCpuFreqTimeReader.UID_TIMES_PROC_FILE;
 
 import android.annotation.NonNull;
 import android.util.Slog;
@@ -34,11 +33,12 @@
 
 @VisibleForTesting(visibility = PACKAGE)
 public class KernelSingleUidTimeReader {
-    private final String TAG = KernelUidCpuFreqTimeReader.class.getName();
-    private final boolean DBG = false;
+    private static final String TAG = KernelSingleUidTimeReader.class.getName();
+    private static final boolean DBG = false;
 
-    private final String PROC_FILE_DIR = "/proc/uid/";
-    private final String PROC_FILE_NAME = "/time_in_state";
+    private static final String PROC_FILE_DIR = "/proc/uid/";
+    private static final String PROC_FILE_NAME = "/time_in_state";
+    private static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state";
 
     @VisibleForTesting
     public static final int TOTAL_READ_ERROR_COUNT = 5;
diff --git a/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java
deleted file mode 100644
index bd8a67a..0000000
--- a/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import android.annotation.Nullable;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
-import java.util.function.Consumer;
-
-/**
- * Reads binary proc file /proc/uid_cpupower/concurrent_active_time and reports CPU active time to
- * BatteryStats to compute {@link PowerProfile#POWER_CPU_ACTIVE}.
- *
- * concurrent_active_time is an array of u32's in the following format:
- * [n, uid0, time0a, time0b, ..., time0n,
- * uid1, time1a, time1b, ..., time1n,
- * uid2, time2a, time2b, ..., time2n, etc.]
- * where n is the total number of cpus (num_possible_cpus)
- * ...
- * timeXn means the CPU time that a UID X spent running concurrently with n other processes.
- * The file contains a monotonically increasing count of time for a single boot. This class
- * maintains the previous results of a call to {@link #readDelta} in order to provide a
- * proper delta.
- *
- * This class uses a throttler to reject any {@link #readDelta} call within
- * {@link #mThrottleInterval}. This is different from the throttler in {@link KernelCpuProcReader},
- * which has a shorter throttle interval and returns cached result from last read when the request
- * is throttled.
- *
- * This class is NOT thread-safe and NOT designed to be accessed by more than one caller since each
- * caller has its own view of delta.
- */
-public class KernelUidCpuActiveTimeReader extends
-        KernelUidCpuTimeReaderBase<KernelUidCpuActiveTimeReader.Callback> {
-    private static final String TAG = KernelUidCpuActiveTimeReader.class.getSimpleName();
-
-    private final KernelCpuProcReader mProcReader;
-    private SparseArray<Double> mLastUidCpuActiveTimeMs = new SparseArray<>();
-    private int mCores;
-
-    public interface Callback extends KernelUidCpuTimeReaderBase.Callback {
-        /**
-         * Notifies when new data is available.
-         *
-         * @param uid             uid int
-         * @param cpuActiveTimeMs cpu active time spent by this uid in milliseconds
-         */
-        void onUidCpuActiveTime(int uid, long cpuActiveTimeMs);
-    }
-
-    public KernelUidCpuActiveTimeReader() {
-        mProcReader = KernelCpuProcReader.getActiveTimeReaderInstance();
-    }
-
-    @VisibleForTesting
-    public KernelUidCpuActiveTimeReader(KernelCpuProcReader procReader) {
-        mProcReader = procReader;
-    }
-
-    @Override
-    protected void readDeltaImpl(@Nullable Callback callback) {
-        readImpl((buf) -> {
-            int uid = buf.get();
-            double activeTime = sumActiveTime(buf);
-            if (activeTime > 0) {
-                double delta = activeTime - mLastUidCpuActiveTimeMs.get(uid, 0.0);
-                if (delta > 0) {
-                    mLastUidCpuActiveTimeMs.put(uid, activeTime);
-                    if (callback != null) {
-                        callback.onUidCpuActiveTime(uid, (long) delta);
-                    }
-                } else if (delta < 0) {
-                    Slog.e(TAG, "Negative delta from active time proc: " + delta);
-                }
-            }
-        });
-    }
-
-    public void readAbsolute(Callback callback) {
-        readImpl((buf) -> {
-            int uid = buf.get();
-            double activeTime = sumActiveTime(buf);
-            if (activeTime > 0) {
-                callback.onUidCpuActiveTime(uid, (long) activeTime);
-            }
-        });
-    }
-
-    private double sumActiveTime(IntBuffer buffer) {
-        double sum = 0;
-        boolean corrupted = false;
-        for (int j = 1; j <= mCores; j++) {
-            int time = buffer.get();
-            if (time < 0) {
-                // Even if error happens, we still need to continue reading.
-                // Buffer cannot be skipped.
-                Slog.e(TAG, "Negative time from active time proc: " + time);
-                corrupted = true;
-            } else {
-                sum += (double) time * 10 / j; // Unit is 10ms.
-            }
-        }
-        return corrupted ? -1 : sum;
-    }
-
-    /**
-     * readImpl accepts a callback to process the uid entry. readDeltaImpl needs to store the last
-     * seen results while processing the buffer, while readAbsolute returns the absolute value read
-     * from the buffer without storing. So readImpl contains the common logic of the two, leaving
-     * the difference to a processUid function.
-     *
-     * @param processUid the callback function to process the uid entry in the buffer.
-     */
-    private void readImpl(Consumer<IntBuffer> processUid) {
-        synchronized (mProcReader) {
-            final ByteBuffer bytes = mProcReader.readBytes();
-            if (bytes == null || bytes.remaining() <= 4) {
-                // Error already logged in mProcReader.
-                return;
-            }
-            if ((bytes.remaining() & 3) != 0) {
-                Slog.wtf(TAG,
-                        "Cannot parse active time proc bytes to int: " + bytes.remaining());
-                return;
-            }
-            final IntBuffer buf = bytes.asIntBuffer();
-            final int cores = buf.get();
-            if (mCores != 0 && cores != mCores) {
-                Slog.wtf(TAG, "Cpu active time wrong # cores: " + cores);
-                return;
-            }
-            mCores = cores;
-            if (cores <= 0 || buf.remaining() % (cores + 1) != 0) {
-                Slog.wtf(TAG,
-                        "Cpu active time format error: " + buf.remaining() + " / " + (cores
-                                + 1));
-                return;
-            }
-            int numUids = buf.remaining() / (cores + 1);
-            for (int i = 0; i < numUids; i++) {
-                processUid.accept(buf);
-            }
-            if (DEBUG) {
-                Slog.d(TAG, "Read uids: " + numUids);
-            }
-        }
-    }
-
-    public void removeUid(int uid) {
-        mLastUidCpuActiveTimeMs.delete(uid);
-    }
-
-    public void removeUidsInRange(int startUid, int endUid) {
-        mLastUidCpuActiveTimeMs.put(startUid, null);
-        mLastUidCpuActiveTimeMs.put(endUid, null);
-        final int firstIndex = mLastUidCpuActiveTimeMs.indexOfKey(startUid);
-        final int lastIndex = mLastUidCpuActiveTimeMs.indexOfKey(endUid);
-        mLastUidCpuActiveTimeMs.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
-    }
-}
diff --git a/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java
deleted file mode 100644
index 3cbfaea..0000000
--- a/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import android.annotation.Nullable;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
-import java.util.function.Consumer;
-
-/**
- * Reads binary proc file /proc/uid_cpupower/concurrent_policy_time and reports CPU cluster times
- * to BatteryStats to compute cluster power. See
- * {@link PowerProfile#getAveragePowerForCpuCluster(int)}.
- *
- * concurrent_policy_time is an array of u32's in the following format:
- * [n, x0, ..., xn, uid0, time0a, time0b, ..., time0n,
- * uid1, time1a, time1b, ..., time1n,
- * uid2, time2a, time2b, ..., time2n, etc.]
- * where n is the number of policies
- * xi is the number cpus on a particular policy
- * Each uidX is followed by x0 time entries corresponding to the time UID X spent on cluster0
- * running concurrently with 0, 1, 2, ..., x0 - 1 other processes, then followed by x1, ..., xn
- * time entries.
- *
- * The file contains a monotonically increasing count of time for a single boot. This class
- * maintains the previous results of a call to {@link #readDelta} in order to provide a
- * proper delta.
- *
- * This class uses a throttler to reject any {@link #readDelta} call within
- * {@link #mThrottleInterval}. This is different from the throttler in {@link KernelCpuProcReader},
- * which has a shorter throttle interval and returns cached result from last read when the request
- * is throttled.
- *
- * This class is NOT thread-safe and NOT designed to be accessed by more than one caller since each
- * caller has its own view of delta.
- */
-public class KernelUidCpuClusterTimeReader extends
-        KernelUidCpuTimeReaderBase<KernelUidCpuClusterTimeReader.Callback> {
-    private static final String TAG = KernelUidCpuClusterTimeReader.class.getSimpleName();
-
-    private final KernelCpuProcReader mProcReader;
-    private SparseArray<double[]> mLastUidPolicyTimeMs = new SparseArray<>();
-
-    private int mNumClusters = -1;
-    private int mNumCores;
-    private int[] mNumCoresOnCluster;
-
-    private double[] mCurTime; // Reuse to avoid GC.
-    private long[] mDeltaTime; // Reuse to avoid GC.
-    private long[] mCurTimeRounded; // Reuse to avoid GC.
-
-    public interface Callback extends KernelUidCpuTimeReaderBase.Callback {
-        /**
-         * Notifies when new data is available.
-         *
-         * @param uid              uid int
-         * @param cpuClusterTimeMs an array of times spent by this uid on corresponding clusters.
-         *                         The array index is the cluster index.
-         */
-        void onUidCpuPolicyTime(int uid, long[] cpuClusterTimeMs);
-    }
-
-    public KernelUidCpuClusterTimeReader() {
-        mProcReader = KernelCpuProcReader.getClusterTimeReaderInstance();
-    }
-
-    @VisibleForTesting
-    public KernelUidCpuClusterTimeReader(KernelCpuProcReader procReader) {
-        mProcReader = procReader;
-    }
-
-    @Override
-    protected void readDeltaImpl(@Nullable Callback cb) {
-        readImpl((buf) -> {
-            int uid = buf.get();
-            double[] lastTimes = mLastUidPolicyTimeMs.get(uid);
-            if (lastTimes == null) {
-                lastTimes = new double[mNumClusters];
-                mLastUidPolicyTimeMs.put(uid, lastTimes);
-            }
-            if (!sumClusterTime(buf, mCurTime)) {
-                return;
-            }
-            boolean valid = true;
-            boolean notify = false;
-            for (int i = 0; i < mNumClusters; i++) {
-                mDeltaTime[i] = (long) (mCurTime[i] - lastTimes[i]);
-                if (mDeltaTime[i] < 0) {
-                    Slog.e(TAG, "Negative delta from cluster time proc: " + mDeltaTime[i]);
-                    valid = false;
-                }
-                notify |= mDeltaTime[i] > 0;
-            }
-            if (notify && valid) {
-                System.arraycopy(mCurTime, 0, lastTimes, 0, mNumClusters);
-                if (cb != null) {
-                    cb.onUidCpuPolicyTime(uid, mDeltaTime);
-                }
-            }
-        });
-    }
-
-    public void readAbsolute(Callback callback) {
-        readImpl((buf) -> {
-            int uid = buf.get();
-            if (sumClusterTime(buf, mCurTime)) {
-                for (int i = 0; i < mNumClusters; i++) {
-                    mCurTimeRounded[i] = (long) mCurTime[i];
-                }
-                callback.onUidCpuPolicyTime(uid, mCurTimeRounded);
-            }
-        });
-    }
-
-    private boolean sumClusterTime(IntBuffer buffer, double[] clusterTime) {
-        boolean valid = true;
-        for (int i = 0; i < mNumClusters; i++) {
-            clusterTime[i] = 0;
-            for (int j = 1; j <= mNumCoresOnCluster[i]; j++) {
-                int time = buffer.get();
-                if (time < 0) {
-                    Slog.e(TAG, "Negative time from cluster time proc: " + time);
-                    valid = false;
-                }
-                clusterTime[i] += (double) time * 10 / j; // Unit is 10ms.
-            }
-        }
-        return valid;
-    }
-
-    /**
-     * readImpl accepts a callback to process the uid entry. readDeltaImpl needs to store the last
-     * seen results while processing the buffer, while readAbsolute returns the absolute value read
-     * from the buffer without storing. So readImpl contains the common logic of the two, leaving
-     * the difference to a processUid function.
-     *
-     * @param processUid the callback function to process the uid entry in the buffer.
-     */
-    private void readImpl(Consumer<IntBuffer> processUid) {
-        synchronized (mProcReader) {
-            ByteBuffer bytes = mProcReader.readBytes();
-            if (bytes == null || bytes.remaining() <= 4) {
-                // Error already logged in mProcReader.
-                return;
-            }
-            if ((bytes.remaining() & 3) != 0) {
-                Slog.wtf(TAG,
-                        "Cannot parse cluster time proc bytes to int: " + bytes.remaining());
-                return;
-            }
-            IntBuffer buf = bytes.asIntBuffer();
-            final int numClusters = buf.get();
-            if (numClusters <= 0) {
-                Slog.wtf(TAG, "Cluster time format error: " + numClusters);
-                return;
-            }
-            if (mNumClusters == -1) {
-                mNumClusters = numClusters;
-            }
-            if (buf.remaining() < numClusters) {
-                Slog.wtf(TAG, "Too few data left in the buffer: " + buf.remaining());
-                return;
-            }
-            if (mNumCores <= 0) {
-                if (!readCoreInfo(buf, numClusters)) {
-                    return;
-                }
-            } else {
-                buf.position(buf.position() + numClusters);
-            }
-
-            if (buf.remaining() % (mNumCores + 1) != 0) {
-                Slog.wtf(TAG,
-                        "Cluster time format error: " + buf.remaining() + " / " + (mNumCores
-                                + 1));
-                return;
-            }
-            int numUids = buf.remaining() / (mNumCores + 1);
-
-            for (int i = 0; i < numUids; i++) {
-                processUid.accept(buf);
-            }
-            if (DEBUG) {
-                Slog.d(TAG, "Read uids: " + numUids);
-            }
-        }
-    }
-
-    // Returns if it has read valid info.
-    private boolean readCoreInfo(IntBuffer buf, int numClusters) {
-        int numCores = 0;
-        int[] numCoresOnCluster = new int[numClusters];
-        for (int i = 0; i < numClusters; i++) {
-            numCoresOnCluster[i] = buf.get();
-            numCores += numCoresOnCluster[i];
-        }
-        if (numCores <= 0) {
-            Slog.e(TAG, "Invalid # cores from cluster time proc file: " + numCores);
-            return false;
-        }
-        mNumCores = numCores;
-        mNumCoresOnCluster = numCoresOnCluster;
-        mCurTime = new double[numClusters];
-        mDeltaTime = new long[numClusters];
-        mCurTimeRounded = new long[numClusters];
-        return true;
-    }
-
-    public void removeUid(int uid) {
-        mLastUidPolicyTimeMs.delete(uid);
-    }
-
-    public void removeUidsInRange(int startUid, int endUid) {
-        mLastUidPolicyTimeMs.put(startUid, null);
-        mLastUidPolicyTimeMs.put(endUid, null);
-        final int firstIndex = mLastUidPolicyTimeMs.indexOfKey(startUid);
-        final int lastIndex = mLastUidPolicyTimeMs.indexOfKey(endUid);
-        mLastUidPolicyTimeMs.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
-    }
-}
diff --git a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
deleted file mode 100644
index 5b46d0f..0000000
--- a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import static com.android.internal.util.Preconditions.checkNotNull;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.StrictMode;
-import android.util.IntArray;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
-import java.util.function.Consumer;
-
-/**
- * Reads /proc/uid_time_in_state which has the format:
- *
- * uid: [freq1] [freq2] [freq3] ...
- * [uid1]: [time in freq1] [time in freq2] [time in freq3] ...
- * [uid2]: [time in freq1] [time in freq2] [time in freq3] ...
- * ...
- *
- * Binary variation reads /proc/uid_cpupower/time_in_state in the following format:
- * [n, uid0, time0a, time0b, ..., time0n,
- * uid1, time1a, time1b, ..., time1n,
- * uid2, time2a, time2b, ..., time2n, etc.]
- * where n is the total number of frequencies.
- *
- * This provides the times a UID's processes spent executing at each different cpu frequency.
- * The file contains a monotonically increasing count of time for a single boot. This class
- * maintains the previous results of a call to {@link #readDelta} in order to provide a proper
- * delta.
- *
- * This class uses a throttler to reject any {@link #readDelta} call within
- * {@link #mThrottleInterval}. This is different from the throttler in {@link KernelCpuProcReader},
- * which has a shorter throttle interval and returns cached result from last read when the request
- * is throttled.
- *
- * This class is NOT thread-safe and NOT designed to be accessed by more than one caller since each
- * caller has its own view of delta.
- */
-public class KernelUidCpuFreqTimeReader extends
-        KernelUidCpuTimeReaderBase<KernelUidCpuFreqTimeReader.Callback> {
-    private static final String TAG = KernelUidCpuFreqTimeReader.class.getSimpleName();
-    static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state";
-
-    public interface Callback extends KernelUidCpuTimeReaderBase.Callback {
-        void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs);
-    }
-
-    private long[] mCpuFreqs;
-    private long[] mCurTimes; // Reuse to prevent GC.
-    private long[] mDeltaTimes; // Reuse to prevent GC.
-    private int mCpuFreqsCount;
-    private final KernelCpuProcReader mProcReader;
-
-    private SparseArray<long[]> mLastUidCpuFreqTimeMs = new SparseArray<>();
-
-    // We check the existence of proc file a few times (just in case it is not ready yet when we
-    // start reading) and if it is not available, we simply ignore further read requests.
-    private static final int TOTAL_READ_ERROR_COUNT = 5;
-    private int mReadErrorCounter;
-    private boolean mPerClusterTimesAvailable;
-    private boolean mAllUidTimesAvailable = true;
-
-    public KernelUidCpuFreqTimeReader() {
-        mProcReader = KernelCpuProcReader.getFreqTimeReaderInstance();
-    }
-
-    @VisibleForTesting
-    public KernelUidCpuFreqTimeReader(KernelCpuProcReader procReader) {
-        mProcReader = procReader;
-    }
-
-    public boolean perClusterTimesAvailable() {
-        return mPerClusterTimesAvailable;
-    }
-
-    public boolean allUidTimesAvailable() {
-        return mAllUidTimesAvailable;
-    }
-
-    public SparseArray<long[]> getAllUidCpuFreqTimeMs() {
-        return mLastUidCpuFreqTimeMs;
-    }
-
-    public long[] readFreqs(@NonNull PowerProfile powerProfile) {
-        checkNotNull(powerProfile);
-        if (mCpuFreqs != null) {
-            // No need to read cpu freqs more than once.
-            return mCpuFreqs;
-        }
-        if (!mAllUidTimesAvailable) {
-            return null;
-        }
-        final int oldMask = StrictMode.allowThreadDiskReadsMask();
-        try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) {
-            return readFreqs(reader, powerProfile);
-        } catch (IOException e) {
-            if (++mReadErrorCounter >= TOTAL_READ_ERROR_COUNT) {
-                mAllUidTimesAvailable = false;
-            }
-            Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
-            return null;
-        } finally {
-            StrictMode.setThreadPolicyMask(oldMask);
-        }
-    }
-
-    @VisibleForTesting
-    public long[] readFreqs(BufferedReader reader, PowerProfile powerProfile)
-            throws IOException {
-        final String line = reader.readLine();
-        if (line == null) {
-            return null;
-        }
-        final String[] freqStr = line.split(" ");
-        // First item would be "uid: " which needs to be ignored.
-        mCpuFreqsCount = freqStr.length - 1;
-        mCpuFreqs = new long[mCpuFreqsCount];
-        mCurTimes = new long[mCpuFreqsCount];
-        mDeltaTimes = new long[mCpuFreqsCount];
-        for (int i = 0; i < mCpuFreqsCount; ++i) {
-            mCpuFreqs[i] = Long.parseLong(freqStr[i + 1], 10);
-        }
-
-        // Check if the freqs in the proc file correspond to per-cluster freqs.
-        final IntArray numClusterFreqs = extractClusterInfoFromProcFileFreqs();
-        final int numClusters = powerProfile.getNumCpuClusters();
-        if (numClusterFreqs.size() == numClusters) {
-            mPerClusterTimesAvailable = true;
-            for (int i = 0; i < numClusters; ++i) {
-                if (numClusterFreqs.get(i) != powerProfile.getNumSpeedStepsInCpuCluster(i)) {
-                    mPerClusterTimesAvailable = false;
-                    break;
-                }
-            }
-        } else {
-            mPerClusterTimesAvailable = false;
-        }
-        Slog.i(TAG, "mPerClusterTimesAvailable=" + mPerClusterTimesAvailable);
-        return mCpuFreqs;
-    }
-
-    @Override
-    @VisibleForTesting
-    public void readDeltaImpl(@Nullable Callback callback) {
-        if (mCpuFreqs == null) {
-            return;
-        }
-        readImpl((buf) -> {
-            int uid = buf.get();
-            long[] lastTimes = mLastUidCpuFreqTimeMs.get(uid);
-            if (lastTimes == null) {
-                lastTimes = new long[mCpuFreqsCount];
-                mLastUidCpuFreqTimeMs.put(uid, lastTimes);
-            }
-            if (!getFreqTimeForUid(buf, mCurTimes)) {
-                return;
-            }
-            boolean notify = false;
-            boolean valid = true;
-            for (int i = 0; i < mCpuFreqsCount; i++) {
-                mDeltaTimes[i] = mCurTimes[i] - lastTimes[i];
-                if (mDeltaTimes[i] < 0) {
-                    Slog.e(TAG, "Negative delta from freq time proc: " + mDeltaTimes[i]);
-                    valid = false;
-                }
-                notify |= mDeltaTimes[i] > 0;
-            }
-            if (notify && valid) {
-                System.arraycopy(mCurTimes, 0, lastTimes, 0, mCpuFreqsCount);
-                if (callback != null) {
-                    callback.onUidCpuFreqTime(uid, mDeltaTimes);
-                }
-            }
-        });
-    }
-
-    public void readAbsolute(Callback callback) {
-        readImpl((buf) -> {
-            int uid = buf.get();
-            if (getFreqTimeForUid(buf, mCurTimes)) {
-                callback.onUidCpuFreqTime(uid, mCurTimes);
-            }
-        });
-    }
-
-    private boolean getFreqTimeForUid(IntBuffer buffer, long[] freqTime) {
-        boolean valid = true;
-        for (int i = 0; i < mCpuFreqsCount; i++) {
-            freqTime[i] = (long) buffer.get() * 10; // Unit is 10ms.
-            if (freqTime[i] < 0) {
-                Slog.e(TAG, "Negative time from freq time proc: " + freqTime[i]);
-                valid = false;
-            }
-        }
-        return valid;
-    }
-
-    /**
-     * readImpl accepts a callback to process the uid entry. readDeltaImpl needs to store the last
-     * seen results while processing the buffer, while readAbsolute returns the absolute value read
-     * from the buffer without storing. So readImpl contains the common logic of the two, leaving
-     * the difference to a processUid function.
-     *
-     * @param processUid the callback function to process the uid entry in the buffer.
-     */
-    private void readImpl(Consumer<IntBuffer> processUid) {
-        synchronized (mProcReader) {
-            ByteBuffer bytes = mProcReader.readBytes();
-            if (bytes == null || bytes.remaining() <= 4) {
-                // Error already logged in mProcReader.
-                return;
-            }
-            if ((bytes.remaining() & 3) != 0) {
-                Slog.wtf(TAG, "Cannot parse freq time proc bytes to int: " + bytes.remaining());
-                return;
-            }
-            IntBuffer buf = bytes.asIntBuffer();
-            final int freqs = buf.get();
-            if (freqs != mCpuFreqsCount) {
-                Slog.wtf(TAG, "Cpu freqs expect " + mCpuFreqsCount + " , got " + freqs);
-                return;
-            }
-            if (buf.remaining() % (freqs + 1) != 0) {
-                Slog.wtf(TAG, "Freq time format error: " + buf.remaining() + " / " + (freqs + 1));
-                return;
-            }
-            int numUids = buf.remaining() / (freqs + 1);
-            for (int i = 0; i < numUids; i++) {
-                processUid.accept(buf);
-            }
-            if (DEBUG) {
-                Slog.d(TAG, "Read uids: #" + numUids);
-            }
-        }
-    }
-
-    public void removeUid(int uid) {
-        mLastUidCpuFreqTimeMs.delete(uid);
-    }
-
-    public void removeUidsInRange(int startUid, int endUid) {
-        mLastUidCpuFreqTimeMs.put(startUid, null);
-        mLastUidCpuFreqTimeMs.put(endUid, null);
-        final int firstIndex = mLastUidCpuFreqTimeMs.indexOfKey(startUid);
-        final int lastIndex = mLastUidCpuFreqTimeMs.indexOfKey(endUid);
-        mLastUidCpuFreqTimeMs.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
-    }
-
-    /**
-     * Extracts no. of cpu clusters and no. of freqs in each of these clusters from the freqs
-     * read from the proc file.
-     *
-     * We need to assume that freqs in each cluster are strictly increasing.
-     * For e.g. if the freqs read from proc file are: 12, 34, 15, 45, 12, 15, 52. Then it means
-     * there are 3 clusters: (12, 34), (15, 45), (12, 15, 52)
-     *
-     * @return an IntArray filled with no. of freqs in each cluster.
-     */
-    private IntArray extractClusterInfoFromProcFileFreqs() {
-        final IntArray numClusterFreqs = new IntArray();
-        int freqsFound = 0;
-        for (int i = 0; i < mCpuFreqsCount; ++i) {
-            freqsFound++;
-            if (i + 1 == mCpuFreqsCount || mCpuFreqs[i + 1] <= mCpuFreqs[i]) {
-                numClusterFreqs.add(freqsFound);
-                freqsFound = 0;
-            }
-        }
-        return numClusterFreqs;
-    }
-}
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
deleted file mode 100644
index 97b7211..0000000
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.internal.os;
-
-import android.annotation.Nullable;
-import android.os.StrictMode;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import android.util.Slog;
-import android.util.SparseLongArray;
-import android.util.TimeUtils;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-
-/**
- * Reads /proc/uid_cputime/show_uid_stat which has the line format:
- *
- * uid: user_time_micro_seconds system_time_micro_seconds power_in_milli-amp-micro_seconds
- *
- * This provides the time a UID's processes spent executing in user-space and kernel-space.
- * The file contains a monotonically increasing count of time for a single boot. This class
- * maintains the previous results of a call to {@link #readDelta} in order to provide a proper
- * delta.
- */
-public class KernelUidCpuTimeReader extends
-        KernelUidCpuTimeReaderBase<KernelUidCpuTimeReader.Callback> {
-    private static final String TAG = KernelUidCpuTimeReader.class.getSimpleName();
-    private static final String sProcFile = "/proc/uid_cputime/show_uid_stat";
-    private static final String sRemoveUidProcFile = "/proc/uid_cputime/remove_uid_range";
-
-    /**
-     * Callback interface for processing each line of the proc file.
-     */
-    public interface Callback extends KernelUidCpuTimeReaderBase.Callback {
-        /**
-         * @param uid          UID of the app
-         * @param userTimeUs   time spent executing in user space in microseconds
-         * @param systemTimeUs time spent executing in kernel space in microseconds
-         */
-        void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs);
-    }
-
-    private SparseLongArray mLastUserTimeUs = new SparseLongArray();
-    private SparseLongArray mLastSystemTimeUs = new SparseLongArray();
-    private long mLastTimeReadUs = 0;
-
-    /**
-     * Reads the proc file, calling into the callback with a delta of time for each UID.
-     *
-     * @param callback The callback to invoke for each line of the proc file. If null,
-     *                 the data is consumed and subsequent calls to readDelta will provide
-     *                 a fresh delta.
-     */
-    @Override
-    protected void readDeltaImpl(@Nullable Callback callback) {
-        final int oldMask = StrictMode.allowThreadDiskReadsMask();
-        long nowUs = SystemClock.elapsedRealtime() * 1000;
-        try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) {
-            TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
-            String line;
-            while ((line = reader.readLine()) != null) {
-                splitter.setString(line);
-                final String uidStr = splitter.next();
-                final int uid = Integer.parseInt(uidStr.substring(0, uidStr.length() - 1), 10);
-                final long userTimeUs = Long.parseLong(splitter.next(), 10);
-                final long systemTimeUs = Long.parseLong(splitter.next(), 10);
-
-                boolean notifyCallback = false;
-                long userTimeDeltaUs = userTimeUs;
-                long systemTimeDeltaUs = systemTimeUs;
-                // Only report if there is a callback and if this is not the first read.
-                if (callback != null && mLastTimeReadUs != 0) {
-                    int index = mLastUserTimeUs.indexOfKey(uid);
-                    if (index >= 0) {
-                        userTimeDeltaUs -= mLastUserTimeUs.valueAt(index);
-                        systemTimeDeltaUs -= mLastSystemTimeUs.valueAt(index);
-
-                        final long timeDiffUs = nowUs - mLastTimeReadUs;
-                        if (userTimeDeltaUs < 0 || systemTimeDeltaUs < 0) {
-                            StringBuilder sb = new StringBuilder("Malformed cpu data for UID=");
-                            sb.append(uid).append("!\n");
-                            sb.append("Time between reads: ");
-                            TimeUtils.formatDuration(timeDiffUs / 1000, sb);
-                            sb.append("\n");
-                            sb.append("Previous times: u=");
-                            TimeUtils.formatDuration(mLastUserTimeUs.valueAt(index) / 1000, sb);
-                            sb.append(" s=");
-                            TimeUtils.formatDuration(mLastSystemTimeUs.valueAt(index) / 1000, sb);
-
-                            sb.append("\nCurrent times: u=");
-                            TimeUtils.formatDuration(userTimeUs / 1000, sb);
-                            sb.append(" s=");
-                            TimeUtils.formatDuration(systemTimeUs / 1000, sb);
-                            sb.append("\nDelta: u=");
-                            TimeUtils.formatDuration(userTimeDeltaUs / 1000, sb);
-                            sb.append(" s=");
-                            TimeUtils.formatDuration(systemTimeDeltaUs / 1000, sb);
-                            Slog.e(TAG, sb.toString());
-
-                            userTimeDeltaUs = 0;
-                            systemTimeDeltaUs = 0;
-                        }
-                    }
-
-                    notifyCallback = (userTimeDeltaUs != 0 || systemTimeDeltaUs != 0);
-                }
-                mLastUserTimeUs.put(uid, userTimeUs);
-                mLastSystemTimeUs.put(uid, systemTimeUs);
-                if (notifyCallback) {
-                    callback.onUidCpuTime(uid, userTimeDeltaUs, systemTimeDeltaUs);
-                }
-            }
-        } catch (IOException e) {
-            Slog.e(TAG, "Failed to read uid_cputime: " + e.getMessage());
-        } finally {
-            StrictMode.setThreadPolicyMask(oldMask);
-        }
-        mLastTimeReadUs = nowUs;
-    }
-
-    /**
-     * Reads the proc file, calling into the callback with raw absolute value of time for each UID.
-     * @param callback The callback to invoke for each line of the proc file.
-     */
-    public void readAbsolute(Callback callback) {
-        final int oldMask = StrictMode.allowThreadDiskReadsMask();
-        try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) {
-            TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
-            String line;
-            while ((line = reader.readLine()) != null) {
-                splitter.setString(line);
-                final String uidStr = splitter.next();
-                final int uid = Integer.parseInt(uidStr.substring(0, uidStr.length() - 1), 10);
-                final long userTimeUs = Long.parseLong(splitter.next(), 10);
-                final long systemTimeUs = Long.parseLong(splitter.next(), 10);
-                callback.onUidCpuTime(uid, userTimeUs, systemTimeUs);
-            }
-        } catch (IOException e) {
-            Slog.e(TAG, "Failed to read uid_cputime: " + e.getMessage());
-        } finally {
-            StrictMode.setThreadPolicyMask(oldMask);
-        }
-    }
-
-    /**
-     * Removes the UID from the kernel module and from internal accounting data. Only
-     * {@link BatteryStatsImpl} and its child processes should call this, as the change on Kernel is
-     * visible system wide.
-     *
-     * @param uid The UID to remove.
-     */
-    public void removeUid(int uid) {
-        final int index = mLastSystemTimeUs.indexOfKey(uid);
-        if (index >= 0) {
-            mLastSystemTimeUs.removeAt(index);
-            mLastUserTimeUs.removeAt(index);
-        }
-        removeUidsFromKernelModule(uid, uid);
-    }
-
-    /**
-     * Removes UIDs in a given range from the kernel module and internal accounting data. Only
-     * {@link BatteryStatsImpl} and its child processes should call this, as the change on Kernel is
-     * visible system wide.
-     *
-     * @param startUid the first uid to remove
-     * @param endUid   the last uid to remove
-     */
-    public void removeUidsInRange(int startUid, int endUid) {
-        if (endUid < startUid) {
-            return;
-        }
-        mLastSystemTimeUs.put(startUid, 0);
-        mLastUserTimeUs.put(startUid, 0);
-        mLastSystemTimeUs.put(endUid, 0);
-        mLastUserTimeUs.put(endUid, 0);
-        final int startIndex = mLastSystemTimeUs.indexOfKey(startUid);
-        final int endIndex = mLastSystemTimeUs.indexOfKey(endUid);
-        mLastSystemTimeUs.removeAtRange(startIndex, endIndex - startIndex + 1);
-        mLastUserTimeUs.removeAtRange(startIndex, endIndex - startIndex + 1);
-        removeUidsFromKernelModule(startUid, endUid);
-    }
-
-    private void removeUidsFromKernelModule(int startUid, int endUid) {
-        Slog.d(TAG, "Removing uids " + startUid + "-" + endUid);
-        final int oldMask = StrictMode.allowThreadDiskWritesMask();
-        try (FileWriter writer = new FileWriter(sRemoveUidProcFile)) {
-            writer.write(startUid + "-" + endUid);
-            writer.flush();
-        } catch (IOException e) {
-            Slog.e(TAG, "failed to remove uids " + startUid + " - " + endUid
-                    + " from uid_cputime module", e);
-        } finally {
-            StrictMode.setThreadPolicyMask(oldMask);
-        }
-    }
-}
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReaderBase.java b/core/java/com/android/internal/os/KernelUidCpuTimeReaderBase.java
deleted file mode 100644
index 11e50e1..0000000
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReaderBase.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import android.annotation.Nullable;
-import android.os.SystemClock;
-import android.util.Slog;
-
-/**
- * The base class of all KernelUidCpuTimeReaders.
- *
- * This class is NOT designed to be thread-safe or accessed by more than one caller (due to
- * the nature of {@link #readDelta(Callback)}).
- */
-public abstract class KernelUidCpuTimeReaderBase<T extends KernelUidCpuTimeReaderBase.Callback> {
-    protected static final boolean DEBUG = false;
-    // Throttle interval in milliseconds
-    private static final long DEFAULT_THROTTLE_INTERVAL = 10_000L;
-
-    private final String TAG = this.getClass().getSimpleName();
-    private long mLastTimeReadMs = Long.MIN_VALUE;
-    private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL;
-
-    // A generic Callback interface (used by readDelta) to be extended by subclasses.
-    public interface Callback {
-    }
-
-    public void readDelta(@Nullable T cb) {
-        if (SystemClock.elapsedRealtime() < mLastTimeReadMs + mThrottleInterval) {
-            if (DEBUG) {
-                Slog.d(TAG, "Throttle");
-            }
-            return;
-        }
-        readDeltaImpl(cb);
-        mLastTimeReadMs = SystemClock.elapsedRealtime();
-    }
-
-    protected abstract void readDeltaImpl(@Nullable T cb);
-
-    public void setThrottleInterval(long throttleInterval) {
-        if (throttleInterval >= 0) {
-            mThrottleInterval = throttleInterval;
-        }
-    }
-}
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index 9a7fb9f..0f0eedd 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -37,6 +37,7 @@
  * @hide Only for use within the system server.
  */
 public class LooperStats implements Looper.Observer {
+    public static final String DEBUG_ENTRY_PREFIX = "__DEBUG_";
     private static final int SESSION_POOL_SIZE = 50;
 
     @GuardedBy("mLock")
@@ -165,7 +166,7 @@
     }
 
     private ExportedEntry createDebugEntry(String variableName, long value) {
-        final Entry entry = new Entry("__DEBUG_" + variableName);
+        final Entry entry = new Entry(DEBUG_ENTRY_PREFIX + variableName);
         entry.messageCount = 1;
         entry.recordedMessageCount = 1;
         entry.totalLatencyMicro = value;
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
index dc660a4..b529bbe 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -30,6 +30,23 @@
     public static final String CONTROL_PRIVAPP_PERMISSIONS =
             SystemProperties.get("ro.control_privapp_permissions");
 
+    // ------ ro.hdmi.* -------- //
+    /**
+     * Property to indicate if a CEC audio device should forward volume keys when system audio
+     * mode is off.
+     */
+    public static final boolean CEC_AUDIO_DEVICE_FORWARD_VOLUME_KEYS_SYSTEM_AUDIO_MODE_OFF =
+            SystemProperties.getBoolean(
+                    "ro.hdmi.cec_audio_device_forward_volume_keys_system_audio_mode_off", false);
+
+    /**
+     * Property to indicate if the current device is a cec switch device.
+     *
+     * <p> Default is false.
+     */
+    public static final String PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH =
+            "ro.hdmi.property_is_device_hdmi_cec_switch";
+
     // ------ ro.config.* -------- //
     public static final boolean CONFIG_AVOID_GFX_ACCEL =
             SystemProperties.getBoolean("ro.config.avoid_gfx_accel", false);
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index 9f2434e..0b329d7 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -18,11 +18,7 @@
 
 import android.app.ApplicationLoaders;
 import android.net.LocalSocket;
-import android.net.LocalServerSocket;
 import android.os.Build;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
 import android.text.TextUtils;
 import android.util.Log;
 import android.webkit.WebViewFactory;
@@ -44,8 +40,6 @@
 class WebViewZygoteInit {
     public static final String TAG = "WebViewZygoteInit";
 
-    private static ZygoteServer sServer;
-
     private static class WebViewZygoteServer extends ZygoteServer {
         @Override
         protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
@@ -127,48 +121,7 @@
 
     public static void main(String argv[]) {
         Log.i(TAG, "Starting WebViewZygoteInit");
-
-        String socketName = null;
-        for (String arg : argv) {
-            Log.i(TAG, arg);
-            if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
-                socketName = arg.substring(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG.length());
-            }
-        }
-        if (socketName == null) {
-            throw new RuntimeException("No " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + " specified");
-        }
-
-        try {
-            Os.prctl(OsConstants.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
-        } catch (ErrnoException ex) {
-            throw new RuntimeException("Failed to set PR_SET_NO_NEW_PRIVS", ex);
-        }
-
-        sServer = new WebViewZygoteServer();
-
-        final Runnable caller;
-        try {
-            sServer.registerServerSocketAtAbstractName(socketName);
-
-            // Add the abstract socket to the FD whitelist so that the native zygote code
-            // can properly detach it after forking.
-            Zygote.nativeAllowFileAcrossFork("ABSTRACT/" + socketName);
-
-            // The select loop returns early in the child process after a fork and
-            // loops forever in the zygote.
-            caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS));
-        } catch (RuntimeException e) {
-            Log.e(TAG, "Fatal exception:", e);
-            throw e;
-        } finally {
-            sServer.closeServerSocket();
-        }
-
-        // We're in the child process and have exited the select loop. Proceed to execute the
-        // command.
-        if (caller != null) {
-            caller.run();
-        }
+        WebViewZygoteServer server = new WebViewZygoteServer();
+        ChildZygoteInit.runZygoteServer(server, argv);
     }
 }
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 65b9fad..069413f 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -16,13 +16,33 @@
 
 package com.android.internal.os;
 
+import static android.system.OsConstants.O_CLOEXEC;
+
+import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC;
+
+import android.net.Credentials;
+import android.net.LocalServerSocket;
+import android.net.LocalSocket;
+import android.os.FactoryTest;
 import android.os.IVold;
+import android.os.Process;
+import android.os.SystemProperties;
 import android.os.Trace;
 import android.system.ErrnoException;
 import android.system.Os;
+import android.util.Log;
 
 import dalvik.system.ZygoteHooks;
 
+import libcore.io.IoUtils;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
 /** @hide */
 public final class Zygote {
     /*
@@ -82,6 +102,11 @@
     /** Read-write external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_WRITE = IVold.REMOUNT_MODE_WRITE;
     /**
+     * Mount mode for apps that are already installed on the device before the isolated_storage
+     * feature is enabled.
+     */
+    public static final int MOUNT_EXTERNAL_LEGACY = IVold.REMOUNT_MODE_LEGACY;
+    /**
      * Mount mode for package installers which should give them access to
      * all obb dirs in addition to their package sandboxes
      */
@@ -89,6 +114,24 @@
     /** Read-write external storage should be mounted instead of package sandbox */
     public static final int MOUNT_EXTERNAL_FULL = IVold.REMOUNT_MODE_FULL;
 
+    /** Number of bytes sent to the Zygote over blastula pipes or the pool event FD */
+    public static final int BLASTULA_MANAGEMENT_MESSAGE_BYTES = 8;
+
+    /**
+     * If the blastula pool should be created and used to start applications.
+     *
+     * Setting this value to false will disable the creation, maintenance, and use of the blastula
+     * pool.  When the blastula pool is disabled the application lifecycle will be identical to
+     * previous versions of Android.
+     */
+    public static final boolean BLASTULA_POOL_ENABLED = false;
+
+    /**
+     * File descriptor used for communication between the signal handler and the ZygoteServer poll
+     * loop.
+     * */
+    protected static FileDescriptor sBlastulaPoolEventFD;
+
     private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
 
     /**
@@ -98,10 +141,72 @@
      */
     public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket=";
 
+    /**
+     * An extraArg passed when a zygote process is forking a child-zygote, specifying the
+     * requested ABI for the child Zygote.
+     */
+    public static final String CHILD_ZYGOTE_ABI_LIST_ARG = "--abi-list=";
+
+    /**
+     * An extraArg passed when a zygote process is forking a child-zygote, specifying the
+     * start of the UID range the children of the Zygote may setuid()/setgid() to. This
+     * will be enforced with a seccomp filter.
+     */
+    public static final String CHILD_ZYGOTE_UID_RANGE_START = "--uid-range-start=";
+
+    /**
+     * An extraArg passed when a zygote process is forking a child-zygote, specifying the
+     * end of the UID range the children of the Zygote may setuid()/setgid() to. This
+     * will be enforced with a seccomp filter.
+     */
+    public static final String CHILD_ZYGOTE_UID_RANGE_END = "--uid-range-end=";
+
+    /** Prefix prepended to socket names created by init */
+    private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
+
+    /**
+     * The maximum value that the sBlastulaPoolMax variable may take.  This value
+     * is a mirror of BLASTULA_POOL_MAX_LIMIT found in com_android_internal_os_Zygote.cpp.
+     */
+    static final int BLASTULA_POOL_MAX_LIMIT = 10;
+
+    /**
+     * The minimum value that the sBlastulaPoolMin variable may take.
+     */
+    static final int BLASTULA_POOL_MIN_LIMIT = 1;
+
+    /**
+     * The runtime-adjustable maximum Blastula pool size.
+     */
+    static int sBlastulaPoolMax = BLASTULA_POOL_MAX_LIMIT;
+
+    /**
+     * The runtime-adjustable minimum Blastula pool size.
+     */
+    static int sBlastulaPoolMin = BLASTULA_POOL_MIN_LIMIT;
+
+    /**
+     * The runtime-adjustable value used to determine when to re-fill the
+     * blastula pool.  The pool will be re-filled when
+     * (sBlastulaPoolMax - gBlastulaPoolCount) >= sBlastulaPoolRefillThreshold.
+     */
+    // TODO (chriswailes): This must be updated at the same time as sBlastulaPoolMax.
+    static int sBlastulaPoolRefillThreshold = (sBlastulaPoolMax / 2);
+
+    /**
+     * @hide for internal use only
+     */
+    public static final int SOCKET_BUFFER_SIZE = 256;
+
+    private static LocalServerSocket sBlastulaPoolSocket = null;
+
+    /** a prototype instance for a future List.toArray() */
+    protected static final int[][] INT_ARRAY_2D = new int[0][0];
+
     private Zygote() {}
 
     /** Called for some security initialization before any fork. */
-    native static void nativeSecurityInit();
+    static native void nativeSecurityInit();
 
     /**
      * Forks a new VM instance.  The current VM must have been started
@@ -140,14 +245,14 @@
     public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
             int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
             int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
-            String packageName, String[] packagesForUid, String[] visibleVolIds) {
+            String packageName, String[] packagesForUID, String[] visibleVolIDs) {
         VM_HOOKS.preFork();
         // Resets nice priority for zygote process.
         resetNicePriority();
         int pid = nativeForkAndSpecialize(
-                  uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
-                  fdsToIgnore, startChildZygote, instructionSet, appDataDir, packageName,
-                  packagesForUid, visibleVolIds);
+                uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
+                fdsToIgnore, startChildZygote, instructionSet, appDataDir, packageName,
+                packagesForUID, visibleVolIDs);
         // Enable tracing as soon as possible for the child process.
         if (pid == 0) {
             Trace.setTracingEnabled(true, runtimeFlags);
@@ -159,15 +264,65 @@
         return pid;
     }
 
-    native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int runtimeFlags,
-            int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
-            int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
-            String packageName, String[] packagesForUid, String[] visibleVolIds);
+    private static native int nativeForkAndSpecialize(int uid, int gid, int[] gids,
+            int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
+            int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
+            String appDataDir, String packageName, String[] packagesForUID, String[] visibleVolIDs);
+
+    /**
+     * Specialize a Blastula instance.  The current VM must have been started
+     * with the -Xzygote flag.
+     *
+     * @param uid  The UNIX uid that the new process should setuid() to before spawning any threads
+     * @param gid  The UNIX gid that the new process should setgid() to before spawning any threads
+     * @param gids null-ok;  A list of UNIX gids that the new process should
+     * setgroups() to before spawning any threads
+     * @param runtimeFlags  Bit flags that enable ART features
+     * @param rlimits null-ok  An array of rlimit tuples, with the second
+     * dimension having a length of 3 and representing
+     * (resource, rlim_cur, rlim_max). These are set via the posix
+     * setrlimit(2) call.
+     * @param seInfo null-ok  A string specifying SELinux information for
+     * the new process.
+     * @param niceName null-ok  A string specifying the process name.
+     * @param startChildZygote  If true, the new child process will itself be a
+     * new zygote process.
+     * @param instructionSet null-ok  The instruction set to use.
+     * @param appDataDir null-ok  The data directory of the app.
+     */
+    public static void specializeBlastula(int uid, int gid, int[] gids, int runtimeFlags,
+            int[][] rlimits, int mountExternal, String seInfo, String niceName,
+            boolean startChildZygote, String instructionSet, String appDataDir, String packageName,
+            String[] packagesForUID, String[] visibleVolIDs) {
+
+        nativeSpecializeBlastula(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
+                                 niceName, startChildZygote, instructionSet, appDataDir,
+                                 packageName, packagesForUID, visibleVolIDs);
+
+        // Enable tracing as soon as possible for the child process.
+        Trace.setTracingEnabled(true, runtimeFlags);
+
+        // Note that this event ends at the end of handleChildProc.
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
+
+        /*
+         * This is called here (instead of after the fork but before the specialize) to maintain
+         * consistancy with the code paths for forkAndSpecialize.
+         *
+         * TODO (chriswailes): Look into moving this to immediately after the fork.
+         */
+        VM_HOOKS.postForkCommon();
+    }
+
+    private static native void nativeSpecializeBlastula(int uid, int gid, int[] gids,
+            int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
+            boolean startChildZygote, String instructionSet, String appDataDir, String packageName,
+            String[] packagesForUID, String[] visibleVolIDs);
 
     /**
      * Called to do any initialization before starting an application.
      */
-    native static void nativePreApplicationInit();
+    static native void nativePreApplicationInit();
 
     /**
      * Special method to start the system server process. In addition to the
@@ -198,7 +353,8 @@
         // Resets nice priority for zygote process.
         resetNicePriority();
         int pid = nativeForkSystemServer(
-                uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities, effectiveCapabilities);
+                uid, gid, gids, runtimeFlags, rlimits,
+                permittedCapabilities, effectiveCapabilities);
         // Enable tracing as soon as we enter the system_server.
         if (pid == 0) {
             Trace.setTracingEnabled(true, runtimeFlags);
@@ -207,19 +363,504 @@
         return pid;
     }
 
-    native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
+    private static native int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
             int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
 
     /**
      * Lets children of the zygote inherit open file descriptors to this path.
      */
-    native protected static void nativeAllowFileAcrossFork(String path);
+    protected static native void nativeAllowFileAcrossFork(String path);
+
+    /**
+     * Installs a seccomp filter that limits setresuid()/setresgid() to the passed-in range
+     * @param uidGidMin The smallest allowed uid/gid
+     * @param uidGidMax The largest allowed uid/gid
+     */
+    native protected static void nativeInstallSeccompUidGidFilter(int uidGidMin, int uidGidMax);
 
     /**
      * Zygote unmount storage space on initializing.
      * This method is called once.
      */
-    native protected static void nativeUnmountStorageOnInit();
+    protected static native void nativeUnmountStorageOnInit();
+
+    /**
+     * Get socket file descriptors (opened by init) from the environment and
+     * store them for access from native code later.
+     *
+     * @param isPrimary  True if this is the zygote process, false if it is zygote_secondary
+     */
+    public static void getSocketFDs(boolean isPrimary) {
+        nativeGetSocketFDs(isPrimary);
+    }
+
+    protected static native void nativeGetSocketFDs(boolean isPrimary);
+
+    /**
+     * Initialize the blastula pool and fill it with the desired number of
+     * processes.
+     */
+    protected static Runnable initBlastulaPool() {
+        if (BLASTULA_POOL_ENABLED) {
+            sBlastulaPoolEventFD = getBlastulaPoolEventFD();
+
+            return fillBlastulaPool(null);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Checks to see if the current policy says that pool should be refilled, and spawns new
+     * blastulas if necessary.
+     *
+     * NOTE: This function doesn't need to be guarded with BLASTULA_POOL_ENABLED because it is
+     *       only called from contexts that are only valid if the pool is enabled.
+     *
+     * @param sessionSocketRawFDs  Anonymous session sockets that are currently open
+     * @return In the Zygote process this function will always return null; in blastula processes
+     *         this function will return a Runnable object representing the new application that is
+     *         passed up from blastulaMain.
+     */
+    protected static Runnable fillBlastulaPool(int[] sessionSocketRawFDs) {
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillBlastulaPool");
+
+        int blastulaPoolCount = getBlastulaPoolCount();
+
+        int numBlastulasToSpawn = sBlastulaPoolMax - blastulaPoolCount;
+
+        if (blastulaPoolCount < sBlastulaPoolMin
+                || numBlastulasToSpawn >= sBlastulaPoolRefillThreshold) {
+
+            // Disable some VM functionality and reset some system values
+            // before forking.
+            VM_HOOKS.preFork();
+            resetNicePriority();
+
+            while (blastulaPoolCount++ < sBlastulaPoolMax) {
+                Runnable caller = forkBlastula(sessionSocketRawFDs);
+
+                if (caller != null) {
+                    return caller;
+                }
+            }
+
+            // Re-enable runtime services for the Zygote.  Blastula services
+            // are re-enabled in specializeBlastula.
+            VM_HOOKS.postForkCommon();
+
+            Log.i("zygote", "Filled the blastula pool. New blastulas: " + numBlastulasToSpawn);
+        }
+
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+
+        return null;
+    }
+
+    /**
+     * @return Number of blastulas currently in the pool
+     */
+    private static int getBlastulaPoolCount() {
+        return nativeGetBlastulaPoolCount();
+    }
+
+    private static native int nativeGetBlastulaPoolCount();
+
+    /**
+     * @return The event FD used for communication between the signal handler and the ZygoteServer
+     *         poll loop
+     */
+    private static FileDescriptor getBlastulaPoolEventFD() {
+        FileDescriptor fd = new FileDescriptor();
+        fd.setInt$(nativeGetBlastulaPoolEventFD());
+
+        return fd;
+    }
+
+    private static native int nativeGetBlastulaPoolEventFD();
+
+    /**
+     * Fork a new blastula process from the zygote
+     *
+     * @param sessionSocketRawFDs  Anonymous session sockets that are currently open
+     * @return In the Zygote process this function will always return null; in blastula processes
+     *         this function will return a Runnable object representing the new application that is
+     *         passed up from blastulaMain.
+     */
+    private static Runnable forkBlastula(int[] sessionSocketRawFDs) {
+        FileDescriptor[] pipeFDs = null;
+
+        try {
+            pipeFDs = Os.pipe2(O_CLOEXEC);
+        } catch (ErrnoException errnoEx) {
+            throw new IllegalStateException("Unable to create blastula pipe.", errnoEx);
+        }
+
+        int pid =
+                nativeForkBlastula(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), sessionSocketRawFDs);
+
+        if (pid == 0) {
+            IoUtils.closeQuietly(pipeFDs[0]);
+            return blastulaMain(pipeFDs[1]);
+        } else {
+            // The read-end of the pipe will be closed by the native code.
+            // See removeBlastulaTableEntry();
+            IoUtils.closeQuietly(pipeFDs[1]);
+            return null;
+        }
+    }
+
+    private static native int nativeForkBlastula(int readPipeFD,
+                                                 int writePipeFD,
+                                                 int[] sessionSocketRawFDs);
+
+    /**
+     * This function is used by blastulas to wait for specialization requests from the system
+     * server.
+     *
+     * @param writePipe  The write end of the reporting pipe used to communicate with the poll loop
+     *                   of the ZygoteServer.
+     * @return A runnable oject representing the new application.
+     */
+    static Runnable blastulaMain(FileDescriptor writePipe) {
+        final int pid = Process.myPid();
+
+        LocalSocket sessionSocket = null;
+        DataOutputStream blastulaOutputStream = null;
+        Credentials peerCredentials = null;
+        String[] argStrings = null;
+
+        while (true) {
+            try {
+                sessionSocket = sBlastulaPoolSocket.accept();
+
+                BufferedReader blastulaReader =
+                        new BufferedReader(new InputStreamReader(sessionSocket.getInputStream()));
+                blastulaOutputStream =
+                        new DataOutputStream(sessionSocket.getOutputStream());
+
+                peerCredentials = sessionSocket.getPeerCredentials();
+
+                argStrings = readArgumentList(blastulaReader);
+
+                if (argStrings != null) {
+                    break;
+                } else {
+                    Log.e("Blastula", "Truncated command received.");
+                    IoUtils.closeQuietly(sessionSocket);
+                }
+            } catch (IOException ioEx) {
+                Log.e("Blastula", "Failed to read command: " + ioEx.getMessage());
+                IoUtils.closeQuietly(sessionSocket);
+            }
+        }
+
+        ZygoteArguments args = new ZygoteArguments(argStrings);
+
+        // TODO (chriswailes): Should this only be run for debug builds?
+        validateBlastulaCommand(args);
+
+        applyUidSecurityPolicy(args, peerCredentials);
+        applyDebuggerSystemProperty(args);
+
+        int[][] rlimits = null;
+
+        if (args.mRLimits != null) {
+            rlimits = args.mRLimits.toArray(INT_ARRAY_2D);
+        }
+
+        // This must happen before the SELinux policy for this process is
+        // changed when specializing.
+        try {
+            // Used by ZygoteProcess.zygoteSendArgsAndGetResult to fill in a
+            // Process.ProcessStartResult object.
+            blastulaOutputStream.writeInt(pid);
+        } catch (IOException ioEx) {
+            Log.e("Blastula", "Failed to write response to session socket: " + ioEx.getMessage());
+            System.exit(-1);
+        } finally {
+            IoUtils.closeQuietly(sessionSocket);
+            IoUtils.closeQuietly(sBlastulaPoolSocket);
+        }
+
+        try {
+            ByteArrayOutputStream buffer =
+                    new ByteArrayOutputStream(Zygote.BLASTULA_MANAGEMENT_MESSAGE_BYTES);
+            DataOutputStream outputStream = new DataOutputStream(buffer);
+
+            // This is written as a long so that the blastula reporting pipe and blastula pool
+            // event FD handlers in ZygoteServer.runSelectLoop can be unified.  These two cases
+            // should both send/receive 8 bytes.
+            outputStream.writeLong(pid);
+            outputStream.flush();
+
+            Os.write(writePipe, buffer.toByteArray(), 0, buffer.size());
+        } catch (Exception ex) {
+            Log.e("Blastula",
+                    String.format("Failed to write PID (%d) to pipe (%d): %s",
+                            pid, writePipe.getInt$(), ex.getMessage()));
+            System.exit(-1);
+        } finally {
+            IoUtils.closeQuietly(writePipe);
+        }
+
+        specializeBlastula(args.mUid, args.mGid, args.mGids,
+                           args.mRuntimeFlags, rlimits, args.mMountExternal,
+                           args.mSeInfo, args.mNiceName, args.mStartChildZygote,
+                           args.mInstructionSet, args.mAppDataDir, args.mPackageName,
+                           args.mPackagesForUid, args.mVisibleVolIds);
+
+        if (args.mNiceName != null) {
+            Process.setArgV0(args.mNiceName);
+        }
+
+        // End of the postFork event.
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+
+        return ZygoteInit.zygoteInit(args.mTargetSdkVersion,
+                                     args.mRemainingArgs,
+                                     null /* classLoader */);
+    }
+
+    private static final String BLASTULA_ERROR_PREFIX = "Invalid command to blastula: ";
+
+    /**
+     * Checks a set of zygote arguments to see if they can be handled by a blastula.  Throws an
+     * exception if an invalid arugment is encountered.
+     * @param args  The arguments to test
+     */
+    static void validateBlastulaCommand(ZygoteArguments args) {
+        if (args.mAbiListQuery) {
+            throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--query-abi-list");
+        } else if (args.mPidQuery) {
+            throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--get-pid");
+        } else if (args.mPreloadDefault) {
+            throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--preload-default");
+        } else if (args.mPreloadPackage != null) {
+            throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--preload-package");
+        } else if (args.mPreloadApp != null) {
+            throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--preload-app");
+        } else if (args.mStartChildZygote) {
+            throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--start-child-zygote");
+        } else if (args.mApiBlacklistExemptions != null) {
+            throw new IllegalArgumentException(
+                BLASTULA_ERROR_PREFIX + "--set-api-blacklist-exemptions");
+        } else if (args.mHiddenApiAccessLogSampleRate != -1) {
+            throw new IllegalArgumentException(
+                BLASTULA_ERROR_PREFIX + "--hidden-api-log-sampling-rate=");
+        } else if (args.mInvokeWith != null) {
+            throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--invoke-with");
+        } else if (args.mPermittedCapabilities != 0 || args.mEffectiveCapabilities != 0) {
+            throw new ZygoteSecurityException("Client may not specify capabilities: "
+                + "permitted=0x" + Long.toHexString(args.mPermittedCapabilities)
+                + ", effective=0x" + Long.toHexString(args.mEffectiveCapabilities));
+        }
+    }
+
+    /**
+     * @return  Raw file descriptors for the read-end of blastula reporting pipes.
+     */
+    protected static int[] getBlastulaPipeFDs() {
+        return nativeGetBlastulaPipeFDs();
+    }
+
+    private static native int[] nativeGetBlastulaPipeFDs();
+
+    /**
+     * Remove the blastula table entry for the provided process ID.
+     *
+     * @param blastulaPID  Process ID of the entry to remove
+     * @return True if the entry was removed; false if it doesn't exist
+     */
+    protected static boolean removeBlastulaTableEntry(int blastulaPID) {
+        return nativeRemoveBlastulaTableEntry(blastulaPID);
+    }
+
+    private static native boolean nativeRemoveBlastulaTableEntry(int blastulaPID);
+
+    /**
+     * uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
+     * operation. It may also specify any gid and setgroups() list it chooses.
+     * In factory test mode, it may specify any UID.
+     *
+     * @param args non-null; zygote spawner arguments
+     * @param peer non-null; peer credentials
+     * @throws ZygoteSecurityException
+     */
+    protected static void applyUidSecurityPolicy(ZygoteArguments args, Credentials peer)
+            throws ZygoteSecurityException {
+
+        if (peer.getUid() == Process.SYSTEM_UID) {
+            /* In normal operation, SYSTEM_UID can only specify a restricted
+             * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
+             */
+            boolean uidRestricted = FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF;
+
+            if (uidRestricted && args.mUidSpecified && (args.mUid < Process.SYSTEM_UID)) {
+                throw new ZygoteSecurityException(
+                        "System UID may not launch process with UID < "
+                        + Process.SYSTEM_UID);
+            }
+        }
+
+        // If not otherwise specified, uid and gid are inherited from peer
+        if (!args.mUidSpecified) {
+            args.mUid = peer.getUid();
+            args.mUidSpecified = true;
+        }
+        if (!args.mGidSpecified) {
+            args.mGid = peer.getGid();
+            args.mGidSpecified = true;
+        }
+    }
+
+    /**
+     * Applies debugger system properties to the zygote arguments.
+     *
+     * If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
+     * the debugger state is specified via the "--enable-jdwp" flag
+     * in the spawn request.
+     *
+     * @param args non-null; zygote spawner args
+     */
+    protected static void applyDebuggerSystemProperty(ZygoteArguments args) {
+        if (RoSystemProperties.DEBUGGABLE) {
+            args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
+        }
+    }
+
+    /**
+     * Applies zygote security policy.
+     * Based on the credentials of the process issuing a zygote command:
+     * <ol>
+     * <li> uid 0 (root) may specify --invoke-with to launch Zygote with a
+     * wrapper command.
+     * <li> Any other uid may not specify any invoke-with argument.
+     * </ul>
+     *
+     * @param args non-null; zygote spawner arguments
+     * @param peer non-null; peer credentials
+     * @throws ZygoteSecurityException
+     */
+    protected static void applyInvokeWithSecurityPolicy(ZygoteArguments args, Credentials peer)
+            throws ZygoteSecurityException {
+        int peerUid = peer.getUid();
+
+        if (args.mInvokeWith != null && peerUid != 0
+                && (args.mRuntimeFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) {
+            throw new ZygoteSecurityException("Peer is permitted to specify an"
+                + "explicit invoke-with wrapper command only for debuggable"
+                + "applications.");
+        }
+    }
+
+    /**
+     * Applies invoke-with system properties to the zygote arguments.
+     *
+     * @param args non-null; zygote args
+     */
+    protected static void applyInvokeWithSystemProperty(ZygoteArguments args) {
+        if (args.mInvokeWith == null && args.mNiceName != null) {
+            String property = "wrap." + args.mNiceName;
+            args.mInvokeWith = SystemProperties.get(property);
+            if (args.mInvokeWith != null && args.mInvokeWith.length() == 0) {
+                args.mInvokeWith = null;
+            }
+        }
+    }
+
+    /**
+     * Reads an argument list from the provided socket
+     * @return Argument list or null if EOF is reached
+     * @throws IOException passed straight through
+     */
+    static String[] readArgumentList(BufferedReader socketReader) throws IOException {
+
+        /**
+         * See android.os.Process.zygoteSendArgsAndGetPid()
+         * Presently the wire format to the zygote process is:
+         * a) a count of arguments (argc, in essence)
+         * b) a number of newline-separated argument strings equal to count
+         *
+         * After the zygote process reads these it will write the pid of
+         * the child or -1 on failure.
+         */
+
+        int argc;
+
+        try {
+            String argc_string = socketReader.readLine();
+
+            if (argc_string == null) {
+                // EOF reached.
+                return null;
+            }
+            argc = Integer.parseInt(argc_string);
+
+        } catch (NumberFormatException ex) {
+            Log.e("Zygote", "Invalid Zygote wire format: non-int at argc");
+            throw new IOException("Invalid wire format");
+        }
+
+        // See bug 1092107: large argc can be used for a DOS attack
+        if (argc > MAX_ZYGOTE_ARGC) {
+            throw new IOException("Max arg count exceeded");
+        }
+
+        String[] args = new String[argc];
+        for (int arg_index = 0; arg_index < argc; arg_index++) {
+            args[arg_index] = socketReader.readLine();
+            if (args[arg_index] == null) {
+                // We got an unexpected EOF.
+                throw new IOException("Truncated request");
+            }
+        }
+
+        return args;
+    }
+
+    /**
+     * Creates a managed object representing the Blastula pool socket that has
+     * already been initialized and bound by init.
+     *
+     * TODO (chriswailes): Move the name selection logic into this function.
+     *
+     * @throws RuntimeException when open fails
+     */
+    static void createBlastulaSocket(String socketName) {
+        if (BLASTULA_POOL_ENABLED && sBlastulaPoolSocket == null) {
+            sBlastulaPoolSocket = createManagedSocketFromInitSocket(socketName);
+        }
+    }
+
+    /**
+     * Creates a managed LocalServerSocket object using a file descriptor
+     * created by an init.rc script.  The init scripts that specify the
+     * sockets name can be found in system/core/rootdir.  The socket is bound
+     * to the file system in the /dev/sockets/ directory, and the file
+     * descriptor is shared via the ANDROID_SOCKET_<socketName> environment
+     * variable.
+     */
+    static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
+        int fileDesc;
+        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
+
+        try {
+            String env = System.getenv(fullSocketName);
+            fileDesc = Integer.parseInt(env);
+        } catch (RuntimeException ex) {
+            throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
+        }
+
+        try {
+            FileDescriptor fd = new FileDescriptor();
+            fd.setInt$(fileDesc);
+            return new LocalServerSocket(fd);
+        } catch (IOException ex) {
+            throw new RuntimeException(
+                "Error building socket from file descriptor: " + fileDesc, ex);
+        }
+    }
 
     private static void callPostForkSystemServerHooks() {
         // SystemServer specific post fork hooks run before child post fork hooks.
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
new file mode 100644
index 0000000..df89b26
--- /dev/null
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -0,0 +1,428 @@
+/*
+ * 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.internal.os;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Handles argument parsing for args related to the zygote spawner.
+ *
+ * Current recognized args:
+ * <ul>
+ *   <li> --setuid=<i>uid of child process, defaults to 0</i>
+ *   <li> --setgid=<i>gid of child process, defaults to 0</i>
+ *   <li> --setgroups=<i>comma-separated list of supplimentary gid's</i>
+ *   <li> --capabilities=<i>a pair of comma-separated integer strings
+ * indicating Linux capabilities(2) set for child. The first string
+ * represents the <code>permitted</code> set, and the second the
+ * <code>effective</code> set. Precede each with 0 or
+ * 0x for octal or hexidecimal value. If unspecified, both default to 0.
+ * This parameter is only applied if the uid of the new process will
+ * be non-0. </i>
+ *   <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call.
+ *    <code>r</code> is the resource, <code>c</code> and <code>m</code>
+ *    are the settings for current and max value.</i>
+ *   <li> --instruction-set=<i>instruction-set-string</i> which instruction set to use/emulate.
+ *   <li> --nice-name=<i>nice name to appear in ps</i>
+ *   <li> --package-name=<i>package name this process belongs to</i>
+ *   <li> --runtime-args indicates that the remaining arg list should
+ * be handed off to com.android.internal.os.RuntimeInit, rather than
+ * processed directly.
+ * Android runtime startup (eg, Binder initialization) is also eschewed.
+ *   <li> [--] &lt;args for RuntimeInit &gt;
+ * </ul>
+ */
+class ZygoteArguments {
+
+    /**
+     * from --setuid
+     */
+    int mUid = 0;
+    boolean mUidSpecified;
+
+    /**
+     * from --setgid
+     */
+    int mGid = 0;
+    boolean mGidSpecified;
+
+    /**
+     * from --setgroups
+     */
+    int[] mGids;
+
+    /**
+     * From --runtime-flags.
+     */
+    int mRuntimeFlags;
+
+    /**
+     * From --mount-external
+     */
+    int mMountExternal = Zygote.MOUNT_EXTERNAL_NONE;
+
+    /**
+     * from --target-sdk-version.
+     */
+    int mTargetSdkVersion;
+    boolean mTargetSdkVersionSpecified;
+
+    /**
+     * from --nice-name
+     */
+    String mNiceName;
+
+    /**
+     * from --capabilities
+     */
+    boolean mCapabilitiesSpecified;
+    long mPermittedCapabilities;
+    long mEffectiveCapabilities;
+
+    /**
+     * from --seinfo
+     */
+    boolean mSeInfoSpecified;
+    String mSeInfo;
+
+    /**
+     * from all --rlimit=r,c,m
+     */
+    ArrayList<int[]> mRLimits;
+
+    /**
+     * from --invoke-with
+     */
+    String mInvokeWith;
+
+    /** from --package-name */
+    String mPackageName;
+
+    /** from --packages-for-uid */
+    String[] mPackagesForUid;
+
+    /** from --visible-vols */
+    String[] mVisibleVolIds;
+
+    /**
+     * Any args after and including the first non-option arg (or after a '--')
+     */
+    String[] mRemainingArgs;
+
+    /**
+     * Whether the current arguments constitute an ABI list query.
+     */
+    boolean mAbiListQuery;
+
+    /**
+     * The instruction set to use, or null when not important.
+     */
+    String mInstructionSet;
+
+    /**
+     * The app data directory. May be null, e.g., for the system server. Note that this might not be
+     * reliable in the case of process-sharing apps.
+     */
+    String mAppDataDir;
+
+    /**
+     * The APK path of the package to preload, when using --preload-package.
+     */
+    String mPreloadPackage;
+
+    /**
+     * A Base64 string representing a serialize ApplicationInfo Parcel,
+     when using --preload-app.
+     */
+    String mPreloadApp;
+
+    /**
+     * The native library path of the package to preload, when using --preload-package.
+     */
+    String mPreloadPackageLibs;
+
+    /**
+     * The filename of the native library to preload, when using --preload-package.
+     */
+    String mPreloadPackageLibFileName;
+
+    /**
+     * The cache key under which to enter the preloaded package into the classloader cache, when
+     * using --preload-package.
+     */
+    String mPreloadPackageCacheKey;
+
+    /**
+     * Whether this is a request to start preloading the default resources and classes. This
+     * argument only makes sense when the zygote is in lazy preload mode (i.e, when it's started
+     * with --enable-lazy-preload).
+     */
+    boolean mPreloadDefault;
+
+    /**
+     * Whether this is a request to start a zygote process as a child of this zygote. Set with
+     * --start-child-zygote. The remaining arguments must include the CHILD_ZYGOTE_SOCKET_NAME_ARG
+     * flag to indicate the abstract socket name that should be used for communication.
+     */
+    boolean mStartChildZygote;
+
+    /**
+     * Whether the current arguments constitute a request for the zygote's PID.
+     */
+    boolean mPidQuery;
+
+    /**
+     * Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time, or
+     * when they change, via --set-api-blacklist-exemptions.
+     */
+    String[] mApiBlacklistExemptions;
+
+    /**
+     * Sampling rate for logging hidden API accesses to the event log. This is sent to the
+     * pre-forked zygote at boot time, or when it changes, via --hidden-api-log-sampling-rate.
+     */
+    int mHiddenApiAccessLogSampleRate = -1;
+
+    /**
+     * Constructs instance and parses args
+     *
+     * @param args zygote command-line args
+     */
+    ZygoteArguments(String[] args) throws IllegalArgumentException {
+        parseArgs(args);
+    }
+
+    /**
+     * Parses the commandline arguments intended for the Zygote spawner (such as "--setuid=" and
+     * "--setgid=") and creates an array containing the remaining args.
+     *
+     * Per security review bug #1112214, duplicate args are disallowed in critical cases to make
+     * injection harder.
+     */
+    private void parseArgs(String[] args)
+            throws IllegalArgumentException {
+        int curArg = 0;
+
+        boolean seenRuntimeArgs = false;
+
+        boolean expectRuntimeArgs = true;
+        for ( /* curArg */ ; curArg < args.length; curArg++) {
+            String arg = args[curArg];
+
+            if (arg.equals("--")) {
+                curArg++;
+                break;
+            } else if (arg.startsWith("--setuid=")) {
+                if (mUidSpecified) {
+                    throw new IllegalArgumentException(
+                        "Duplicate arg specified");
+                }
+                mUidSpecified = true;
+                mUid = Integer.parseInt(
+                    arg.substring(arg.indexOf('=') + 1));
+            } else if (arg.startsWith("--setgid=")) {
+                if (mGidSpecified) {
+                    throw new IllegalArgumentException(
+                        "Duplicate arg specified");
+                }
+                mGidSpecified = true;
+                mGid = Integer.parseInt(
+                    arg.substring(arg.indexOf('=') + 1));
+            } else if (arg.startsWith("--target-sdk-version=")) {
+                if (mTargetSdkVersionSpecified) {
+                    throw new IllegalArgumentException(
+                        "Duplicate target-sdk-version specified");
+                }
+                mTargetSdkVersionSpecified = true;
+                mTargetSdkVersion = Integer.parseInt(
+                    arg.substring(arg.indexOf('=') + 1));
+            } else if (arg.equals("--runtime-args")) {
+                seenRuntimeArgs = true;
+            } else if (arg.startsWith("--runtime-flags=")) {
+                mRuntimeFlags = Integer.parseInt(
+                    arg.substring(arg.indexOf('=') + 1));
+            } else if (arg.startsWith("--seinfo=")) {
+                if (mSeInfoSpecified) {
+                    throw new IllegalArgumentException(
+                        "Duplicate arg specified");
+                }
+                mSeInfoSpecified = true;
+                mSeInfo = arg.substring(arg.indexOf('=') + 1);
+            } else if (arg.startsWith("--capabilities=")) {
+                if (mCapabilitiesSpecified) {
+                    throw new IllegalArgumentException(
+                        "Duplicate arg specified");
+                }
+                mCapabilitiesSpecified = true;
+                String capString = arg.substring(arg.indexOf('=') + 1);
+
+                String[] capStrings = capString.split(",", 2);
+
+                if (capStrings.length == 1) {
+                    mEffectiveCapabilities = Long.decode(capStrings[0]);
+                    mPermittedCapabilities = mEffectiveCapabilities;
+                } else {
+                    mPermittedCapabilities = Long.decode(capStrings[0]);
+                    mEffectiveCapabilities = Long.decode(capStrings[1]);
+                }
+            } else if (arg.startsWith("--rlimit=")) {
+                // Duplicate --rlimit arguments are specifically allowed.
+                String[] limitStrings = arg.substring(arg.indexOf('=') + 1).split(",");
+
+                if (limitStrings.length != 3) {
+                    throw new IllegalArgumentException(
+                        "--rlimit= should have 3 comma-delimited ints");
+                }
+                int[] rlimitTuple = new int[limitStrings.length];
+
+                for (int i = 0; i < limitStrings.length; i++) {
+                    rlimitTuple[i] = Integer.parseInt(limitStrings[i]);
+                }
+
+                if (mRLimits == null) {
+                    mRLimits = new ArrayList();
+                }
+
+                mRLimits.add(rlimitTuple);
+            } else if (arg.startsWith("--setgroups=")) {
+                if (mGids != null) {
+                    throw new IllegalArgumentException(
+                        "Duplicate arg specified");
+                }
+
+                String[] params = arg.substring(arg.indexOf('=') + 1).split(",");
+
+                mGids = new int[params.length];
+
+                for (int i = params.length - 1; i >= 0; i--) {
+                    mGids[i] = Integer.parseInt(params[i]);
+                }
+            } else if (arg.equals("--invoke-with")) {
+                if (mInvokeWith != null) {
+                    throw new IllegalArgumentException(
+                        "Duplicate arg specified");
+                }
+                try {
+                    mInvokeWith = args[++curArg];
+                } catch (IndexOutOfBoundsException ex) {
+                    throw new IllegalArgumentException(
+                        "--invoke-with requires argument");
+                }
+            } else if (arg.startsWith("--nice-name=")) {
+                if (mNiceName != null) {
+                    throw new IllegalArgumentException(
+                        "Duplicate arg specified");
+                }
+                mNiceName = arg.substring(arg.indexOf('=') + 1);
+            } else if (arg.equals("--mount-external-default")) {
+                mMountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
+            } else if (arg.equals("--mount-external-read")) {
+                mMountExternal = Zygote.MOUNT_EXTERNAL_READ;
+            } else if (arg.equals("--mount-external-write")) {
+                mMountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
+            } else if (arg.equals("--mount-external-full")) {
+                mMountExternal = Zygote.MOUNT_EXTERNAL_FULL;
+            }  else if (arg.equals("--mount-external-installer")) {
+                mMountExternal = Zygote.MOUNT_EXTERNAL_INSTALLER;
+            } else if (arg.equals("--query-abi-list")) {
+                mAbiListQuery = true;
+            } else if (arg.equals("--get-pid")) {
+                mPidQuery = true;
+            } else if (arg.startsWith("--instruction-set=")) {
+                mInstructionSet = arg.substring(arg.indexOf('=') + 1);
+            } else if (arg.startsWith("--app-data-dir=")) {
+                mAppDataDir = arg.substring(arg.indexOf('=') + 1);
+            } else if (arg.equals("--preload-app")) {
+                mPreloadApp = args[++curArg];
+            } else if (arg.equals("--preload-package")) {
+                mPreloadPackage = args[++curArg];
+                mPreloadPackageLibs = args[++curArg];
+                mPreloadPackageLibFileName = args[++curArg];
+                mPreloadPackageCacheKey = args[++curArg];
+            } else if (arg.equals("--preload-default")) {
+                mPreloadDefault = true;
+                expectRuntimeArgs = false;
+            } else if (arg.equals("--start-child-zygote")) {
+                mStartChildZygote = true;
+            } else if (arg.equals("--set-api-blacklist-exemptions")) {
+                // consume all remaining args; this is a stand-alone command, never included
+                // with the regular fork command.
+                mApiBlacklistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
+                curArg = args.length;
+                expectRuntimeArgs = false;
+            } else if (arg.startsWith("--hidden-api-log-sampling-rate=")) {
+                String rateStr = arg.substring(arg.indexOf('=') + 1);
+                try {
+                    mHiddenApiAccessLogSampleRate = Integer.parseInt(rateStr);
+                } catch (NumberFormatException nfe) {
+                    throw new IllegalArgumentException(
+                        "Invalid log sampling rate: " + rateStr, nfe);
+                }
+                expectRuntimeArgs = false;
+            } else if (arg.startsWith("--package-name=")) {
+                if (mPackageName != null) {
+                    throw new IllegalArgumentException("Duplicate arg specified");
+                }
+                mPackageName = arg.substring(arg.indexOf('=') + 1);
+            } else if (arg.startsWith("--packages-for-uid=")) {
+                mPackagesForUid = arg.substring(arg.indexOf('=') + 1).split(",");
+            } else if (arg.startsWith("--visible-vols=")) {
+                mVisibleVolIds = arg.substring(arg.indexOf('=') + 1).split(",");
+            } else {
+                break;
+            }
+        }
+
+        if (mAbiListQuery || mPidQuery) {
+            if (args.length - curArg > 0) {
+                throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
+            }
+        } else if (mPreloadPackage != null) {
+            if (args.length - curArg > 0) {
+                throw new IllegalArgumentException(
+                    "Unexpected arguments after --preload-package.");
+            }
+        } else if (mPreloadApp != null) {
+            if (args.length - curArg > 0) {
+                throw new IllegalArgumentException(
+                    "Unexpected arguments after --preload-app.");
+            }
+        } else if (expectRuntimeArgs) {
+            if (!seenRuntimeArgs) {
+                throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
+            }
+
+            mRemainingArgs = new String[args.length - curArg];
+            System.arraycopy(args, curArg, mRemainingArgs, 0, mRemainingArgs.length);
+        }
+
+        if (mStartChildZygote) {
+            boolean seenChildSocketArg = false;
+            for (String arg : mRemainingArgs) {
+                if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
+                    seenChildSocketArg = true;
+                    break;
+                }
+            }
+            if (!seenChildSocketArg) {
+                throw new IllegalArgumentException("--start-child-zygote specified "
+                        + "without " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG);
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index f182c4d..ffbe8eb 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -24,14 +24,13 @@
 import static android.system.OsConstants.STDOUT_FILENO;
 
 import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEOUT_MILLIS;
-import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC;
 import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
 
+import android.content.pm.ApplicationInfo;
 import android.net.Credentials;
 import android.net.LocalSocket;
-import android.os.FactoryTest;
+import android.os.Parcel;
 import android.os.Process;
-import android.os.SystemProperties;
 import android.os.Trace;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -50,8 +49,7 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Base64;
 
 /**
  * A connection that can make spawn requests.
@@ -59,9 +57,6 @@
 class ZygoteConnection {
     private static final String TAG = "Zygote";
 
-    /** a prototype instance for a future List.toArray() */
-    private static final int[][] intArray2d = new int[0][0];
-
     /**
      * The command socket.
      *
@@ -110,7 +105,7 @@
      *
      * @return null-ok; file descriptor
      */
-    FileDescriptor getFileDesciptor() {
+    FileDescriptor getFileDescriptor() {
         return mSocket.getFileDescriptor();
     }
 
@@ -124,11 +119,13 @@
      */
     Runnable processOneCommand(ZygoteServer zygoteServer) {
         String args[];
-        Arguments parsedArgs = null;
+        ZygoteArguments parsedArgs = null;
         FileDescriptor[] descriptors;
 
         try {
-            args = readArgumentList();
+            args = Zygote.readArgumentList(mSocketReader);
+
+            // TODO (chriswailes): Remove this and add an assert.
             descriptors = mSocket.getAncillaryFileDescriptors();
         } catch (IOException ex) {
             throw new IllegalStateException("IOException on command socket", ex);
@@ -145,60 +142,75 @@
         FileDescriptor childPipeFd = null;
         FileDescriptor serverPipeFd = null;
 
-        parsedArgs = new Arguments(args);
+        parsedArgs = new ZygoteArguments(args);
 
-        if (parsedArgs.abiListQuery) {
+        if (parsedArgs.mAbiListQuery) {
             handleAbiListQuery();
             return null;
         }
 
-        if (parsedArgs.pidQuery) {
+        if (parsedArgs.mPidQuery) {
             handlePidQuery();
             return null;
         }
 
-        if (parsedArgs.preloadDefault) {
+        if (parsedArgs.mPreloadDefault) {
             handlePreload();
             return null;
         }
 
-        if (parsedArgs.preloadPackage != null) {
-            handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs,
-                    parsedArgs.preloadPackageLibFileName, parsedArgs.preloadPackageCacheKey);
+        if (parsedArgs.mPreloadPackage != null) {
+            handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs,
+                    parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey);
             return null;
         }
 
-        if (parsedArgs.apiBlacklistExemptions != null) {
-            handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions);
+        if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
+            byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
+            Parcel appInfoParcel = Parcel.obtain();
+            appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
+            appInfoParcel.setDataPosition(0);
+            ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
+            appInfoParcel.recycle();
+            if (appInfo != null) {
+                handlePreloadApp(appInfo);
+            } else {
+                throw new IllegalArgumentException("Failed to deserialize --preload-app");
+            }
             return null;
         }
 
-        if (parsedArgs.hiddenApiAccessLogSampleRate != -1) {
-            handleHiddenApiAccessLogSampleRate(parsedArgs.hiddenApiAccessLogSampleRate);
+        if (parsedArgs.mApiBlacklistExemptions != null) {
+            handleApiBlacklistExemptions(parsedArgs.mApiBlacklistExemptions);
             return null;
         }
 
-        if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
-            throw new ZygoteSecurityException("Client may not specify capabilities: " +
-                    "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
-                    ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
+        if (parsedArgs.mHiddenApiAccessLogSampleRate != -1) {
+            handleHiddenApiAccessLogSampleRate(parsedArgs.mHiddenApiAccessLogSampleRate);
+            return null;
         }
 
-        applyUidSecurityPolicy(parsedArgs, peer);
-        applyInvokeWithSecurityPolicy(parsedArgs, peer);
+        if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) {
+            throw new ZygoteSecurityException("Client may not specify capabilities: "
+                    + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
+                    + ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities));
+        }
 
-        applyDebuggerSystemProperty(parsedArgs);
-        applyInvokeWithSystemProperty(parsedArgs);
+        Zygote.applyUidSecurityPolicy(parsedArgs, peer);
+        Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
+
+        Zygote.applyDebuggerSystemProperty(parsedArgs);
+        Zygote.applyInvokeWithSystemProperty(parsedArgs);
 
         int[][] rlimits = null;
 
-        if (parsedArgs.rlimits != null) {
-            rlimits = parsedArgs.rlimits.toArray(intArray2d);
+        if (parsedArgs.mRLimits != null) {
+            rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
         }
 
         int[] fdsToIgnore = null;
 
-        if (parsedArgs.invokeWith != null) {
+        if (parsedArgs.mInvokeWith != null) {
             try {
                 FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
                 childPipeFd = pipeFds[1];
@@ -230,7 +242,7 @@
             fdsToClose[0] = fd.getInt$();
         }
 
-        fd = zygoteServer.getServerSocketFileDescriptor();
+        fd = zygoteServer.getZygoteSocketFileDescriptor();
 
         if (fd != null) {
             fdsToClose[1] = fd.getInt$();
@@ -238,11 +250,11 @@
 
         fd = null;
 
-        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
-                parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
-                parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
-                parsedArgs.instructionSet, parsedArgs.appDataDir, parsedArgs.packageName,
-                parsedArgs.packagesForUid, parsedArgs.visibleVolIds);
+        pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
+                parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
+                parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
+                parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mPackageName,
+                parsedArgs.mPackagesForUid, parsedArgs.mVisibleVolIds);
 
         try {
             if (pid == 0) {
@@ -254,7 +266,7 @@
                 serverPipeFd = null;
 
                 return handleChildProc(parsedArgs, descriptors, childPipeFd,
-                        parsedArgs.startChildZygote);
+                        parsedArgs.mStartChildZygote);
             } else {
                 // In the parent. A pid < 0 indicates a failure and will be handled in
                 // handleParentProc.
@@ -341,7 +353,15 @@
 
     protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
             String cacheKey) {
-        throw new RuntimeException("Zyogte does not support package preloading");
+        throw new RuntimeException("Zygote does not support package preloading");
+    }
+
+    protected boolean canPreloadApp() {
+        return false;
+    }
+
+    protected void handlePreloadApp(ApplicationInfo aInfo) {
+        throw new RuntimeException("Zygote does not support app preloading");
     }
 
     /**
@@ -361,526 +381,6 @@
     }
 
     /**
-     * Handles argument parsing for args related to the zygote spawner.
-     *
-     * Current recognized args:
-     * <ul>
-     *   <li> --setuid=<i>uid of child process, defaults to 0</i>
-     *   <li> --setgid=<i>gid of child process, defaults to 0</i>
-     *   <li> --setgroups=<i>comma-separated list of supplimentary gid's</i>
-     *   <li> --capabilities=<i>a pair of comma-separated integer strings
-     * indicating Linux capabilities(2) set for child. The first string
-     * represents the <code>permitted</code> set, and the second the
-     * <code>effective</code> set. Precede each with 0 or
-     * 0x for octal or hexidecimal value. If unspecified, both default to 0.
-     * This parameter is only applied if the uid of the new process will
-     * be non-0. </i>
-     *   <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call.
-     *    <code>r</code> is the resource, <code>c</code> and <code>m</code>
-     *    are the settings for current and max value.</i>
-     *   <li> --instruction-set=<i>instruction-set-string</i> which instruction set to use/emulate.
-     *   <li> --nice-name=<i>nice name to appear in ps</i>
-     *   <li> --package-name=<i>package name this process belongs to</i>
-     *   <li> --runtime-args indicates that the remaining arg list should
-     * be handed off to com.android.internal.os.RuntimeInit, rather than
-     * processed directly.
-     * Android runtime startup (eg, Binder initialization) is also eschewed.
-     *   <li> [--] &lt;args for RuntimeInit &gt;
-     * </ul>
-     */
-    static class Arguments {
-        /** from --setuid */
-        int uid = 0;
-        boolean uidSpecified;
-
-        /** from --setgid */
-        int gid = 0;
-        boolean gidSpecified;
-
-        /** from --setgroups */
-        int[] gids;
-
-        /**
-         * From --runtime-flags.
-         */
-        int runtimeFlags;
-
-        /** From --mount-external */
-        int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
-
-        /** from --target-sdk-version. */
-        int targetSdkVersion;
-        boolean targetSdkVersionSpecified;
-
-        /** from --nice-name */
-        String niceName;
-
-        /** from --capabilities */
-        boolean capabilitiesSpecified;
-        long permittedCapabilities;
-        long effectiveCapabilities;
-
-        /** from --seinfo */
-        boolean seInfoSpecified;
-        String seInfo;
-
-        /** from all --rlimit=r,c,m */
-        ArrayList<int[]> rlimits;
-
-        /** from --invoke-with */
-        String invokeWith;
-
-        /** from --package-name */
-        String packageName;
-
-        /** from --packages-for-uid */
-        String[] packagesForUid;
-
-        /** from --visible-vols */
-        String[] visibleVolIds;
-
-        /**
-         * Any args after and including the first non-option arg
-         * (or after a '--')
-         */
-        String remainingArgs[];
-
-        /**
-         * Whether the current arguments constitute an ABI list query.
-         */
-        boolean abiListQuery;
-
-        /**
-         * The instruction set to use, or null when not important.
-         */
-        String instructionSet;
-
-        /**
-         * The app data directory. May be null, e.g., for the system server. Note that this might
-         * not be reliable in the case of process-sharing apps.
-         */
-        String appDataDir;
-
-        /**
-         * The APK path of the package to preload, when using --preload-package.
-         */
-        String preloadPackage;
-
-        /**
-         * The native library path of the package to preload, when using --preload-package.
-         */
-        String preloadPackageLibs;
-
-        /**
-         * The filename of the native library to preload, when using --preload-package.
-         */
-        String preloadPackageLibFileName;
-
-        /**
-         * The cache key under which to enter the preloaded package into the classloader cache,
-         * when using --preload-package.
-         */
-        String preloadPackageCacheKey;
-
-        /**
-         * Whether this is a request to start preloading the default resources and classes.
-         * This argument only makes sense when the zygote is in lazy preload mode (i.e, when
-         * it's started with --enable-lazy-preload).
-         */
-        boolean preloadDefault;
-
-        /**
-         * Whether this is a request to start a zygote process as a child of this zygote.
-         * Set with --start-child-zygote. The remaining arguments must include the
-         * CHILD_ZYGOTE_SOCKET_NAME_ARG flag to indicate the abstract socket name that
-         * should be used for communication.
-         */
-        boolean startChildZygote;
-
-        /**
-         * Whether the current arguments constitute a request for the zygote's PID.
-         */
-        boolean pidQuery;
-
-        /**
-         * Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time,
-         * or when they change, via --set-api-blacklist-exemptions.
-         */
-        String[] apiBlacklistExemptions;
-
-        /**
-         * Sampling rate for logging hidden API accesses to the event log. This is sent to the
-         * pre-forked zygote at boot time, or when it changes, via --hidden-api-log-sampling-rate.
-         */
-        int hiddenApiAccessLogSampleRate = -1;
-
-        /**
-         * Constructs instance and parses args
-         * @param args zygote command-line args
-         * @throws IllegalArgumentException
-         */
-        Arguments(String args[]) throws IllegalArgumentException {
-            parseArgs(args);
-        }
-
-        /**
-         * Parses the commandline arguments intended for the Zygote spawner
-         * (such as "--setuid=" and "--setgid=") and creates an array
-         * containing the remaining args.
-         *
-         * Per security review bug #1112214, duplicate args are disallowed in
-         * critical cases to make injection harder.
-         */
-        private void parseArgs(String args[])
-                throws IllegalArgumentException {
-            int curArg = 0;
-
-            boolean seenRuntimeArgs = false;
-
-            boolean expectRuntimeArgs = true;
-            for ( /* curArg */ ; curArg < args.length; curArg++) {
-                String arg = args[curArg];
-
-                if (arg.equals("--")) {
-                    curArg++;
-                    break;
-                } else if (arg.startsWith("--setuid=")) {
-                    if (uidSpecified) {
-                        throw new IllegalArgumentException(
-                                "Duplicate arg specified");
-                    }
-                    uidSpecified = true;
-                    uid = Integer.parseInt(
-                            arg.substring(arg.indexOf('=') + 1));
-                } else if (arg.startsWith("--setgid=")) {
-                    if (gidSpecified) {
-                        throw new IllegalArgumentException(
-                                "Duplicate arg specified");
-                    }
-                    gidSpecified = true;
-                    gid = Integer.parseInt(
-                            arg.substring(arg.indexOf('=') + 1));
-                } else if (arg.startsWith("--target-sdk-version=")) {
-                    if (targetSdkVersionSpecified) {
-                        throw new IllegalArgumentException(
-                                "Duplicate target-sdk-version specified");
-                    }
-                    targetSdkVersionSpecified = true;
-                    targetSdkVersion = Integer.parseInt(
-                            arg.substring(arg.indexOf('=') + 1));
-                } else if (arg.equals("--runtime-args")) {
-                    seenRuntimeArgs = true;
-                } else if (arg.startsWith("--runtime-flags=")) {
-                    runtimeFlags = Integer.parseInt(
-                            arg.substring(arg.indexOf('=') + 1));
-                } else if (arg.startsWith("--seinfo=")) {
-                    if (seInfoSpecified) {
-                        throw new IllegalArgumentException(
-                                "Duplicate arg specified");
-                    }
-                    seInfoSpecified = true;
-                    seInfo = arg.substring(arg.indexOf('=') + 1);
-                } else if (arg.startsWith("--capabilities=")) {
-                    if (capabilitiesSpecified) {
-                        throw new IllegalArgumentException(
-                                "Duplicate arg specified");
-                    }
-                    capabilitiesSpecified = true;
-                    String capString = arg.substring(arg.indexOf('=')+1);
-
-                    String[] capStrings = capString.split(",", 2);
-
-                    if (capStrings.length == 1) {
-                        effectiveCapabilities = Long.decode(capStrings[0]);
-                        permittedCapabilities = effectiveCapabilities;
-                    } else {
-                        permittedCapabilities = Long.decode(capStrings[0]);
-                        effectiveCapabilities = Long.decode(capStrings[1]);
-                    }
-                } else if (arg.startsWith("--rlimit=")) {
-                    // Duplicate --rlimit arguments are specifically allowed.
-                    String[] limitStrings
-                            = arg.substring(arg.indexOf('=')+1).split(",");
-
-                    if (limitStrings.length != 3) {
-                        throw new IllegalArgumentException(
-                                "--rlimit= should have 3 comma-delimited ints");
-                    }
-                    int[] rlimitTuple = new int[limitStrings.length];
-
-                    for(int i=0; i < limitStrings.length; i++) {
-                        rlimitTuple[i] = Integer.parseInt(limitStrings[i]);
-                    }
-
-                    if (rlimits == null) {
-                        rlimits = new ArrayList();
-                    }
-
-                    rlimits.add(rlimitTuple);
-                } else if (arg.startsWith("--setgroups=")) {
-                    if (gids != null) {
-                        throw new IllegalArgumentException(
-                                "Duplicate arg specified");
-                    }
-
-                    String[] params
-                            = arg.substring(arg.indexOf('=') + 1).split(",");
-
-                    gids = new int[params.length];
-
-                    for (int i = params.length - 1; i >= 0 ; i--) {
-                        gids[i] = Integer.parseInt(params[i]);
-                    }
-                } else if (arg.equals("--invoke-with")) {
-                    if (invokeWith != null) {
-                        throw new IllegalArgumentException(
-                                "Duplicate arg specified");
-                    }
-                    try {
-                        invokeWith = args[++curArg];
-                    } catch (IndexOutOfBoundsException ex) {
-                        throw new IllegalArgumentException(
-                                "--invoke-with requires argument");
-                    }
-                } else if (arg.startsWith("--nice-name=")) {
-                    if (niceName != null) {
-                        throw new IllegalArgumentException(
-                                "Duplicate arg specified");
-                    }
-                    niceName = arg.substring(arg.indexOf('=') + 1);
-                } else if (arg.equals("--mount-external-default")) {
-                    mountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
-                } else if (arg.equals("--mount-external-read")) {
-                    mountExternal = Zygote.MOUNT_EXTERNAL_READ;
-                } else if (arg.equals("--mount-external-write")) {
-                    mountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
-                } else if (arg.equals("--mount-external-full")) {
-                    mountExternal = Zygote.MOUNT_EXTERNAL_FULL;
-                }  else if (arg.equals("--mount-external-installer")) {
-                    mountExternal = Zygote.MOUNT_EXTERNAL_INSTALLER;
-                } else if (arg.equals("--query-abi-list")) {
-                    abiListQuery = true;
-                } else if (arg.equals("--get-pid")) {
-                    pidQuery = true;
-                } else if (arg.startsWith("--instruction-set=")) {
-                    instructionSet = arg.substring(arg.indexOf('=') + 1);
-                } else if (arg.startsWith("--app-data-dir=")) {
-                    appDataDir = arg.substring(arg.indexOf('=') + 1);
-                } else if (arg.equals("--preload-package")) {
-                    preloadPackage = args[++curArg];
-                    preloadPackageLibs = args[++curArg];
-                    preloadPackageLibFileName = args[++curArg];
-                    preloadPackageCacheKey = args[++curArg];
-                } else if (arg.equals("--preload-default")) {
-                    preloadDefault = true;
-                    expectRuntimeArgs = false;
-                } else if (arg.equals("--start-child-zygote")) {
-                    startChildZygote = true;
-                } else if (arg.equals("--set-api-blacklist-exemptions")) {
-                    // consume all remaining args; this is a stand-alone command, never included
-                    // with the regular fork command.
-                    apiBlacklistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
-                    curArg = args.length;
-                    expectRuntimeArgs = false;
-                } else if (arg.startsWith("--hidden-api-log-sampling-rate=")) {
-                    String rateStr = arg.substring(arg.indexOf('=') + 1);
-                    try {
-                        hiddenApiAccessLogSampleRate = Integer.parseInt(rateStr);
-                    } catch (NumberFormatException nfe) {
-                        throw new IllegalArgumentException(
-                                "Invalid log sampling rate: " + rateStr, nfe);
-                    }
-                    expectRuntimeArgs = false;
-                } else if (arg.startsWith("--package-name=")) {
-                    if (packageName != null) {
-                        throw new IllegalArgumentException("Duplicate arg specified");
-                    }
-                    packageName = arg.substring(arg.indexOf('=') + 1);
-                } else if (arg.startsWith("--packages-for-uid=")) {
-                    packagesForUid = arg.substring(arg.indexOf('=') + 1).split(",");
-                } else if (arg.startsWith("--visible-vols=")) {
-                    visibleVolIds = arg.substring(arg.indexOf('=') + 1).split(",");
-                } else {
-                    break;
-                }
-            }
-
-            if (abiListQuery || pidQuery) {
-                if (args.length - curArg > 0) {
-                    throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
-                }
-            } else if (preloadPackage != null) {
-                if (args.length - curArg > 0) {
-                    throw new IllegalArgumentException(
-                            "Unexpected arguments after --preload-package.");
-                }
-            } else if (expectRuntimeArgs) {
-                if (!seenRuntimeArgs) {
-                    throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
-                }
-
-                remainingArgs = new String[args.length - curArg];
-                System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length);
-            }
-
-            if (startChildZygote) {
-                boolean seenChildSocketArg = false;
-                for (String arg : remainingArgs) {
-                    if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
-                        seenChildSocketArg = true;
-                        break;
-                    }
-                }
-                if (!seenChildSocketArg) {
-                    throw new IllegalArgumentException("--start-child-zygote specified " +
-                            "without " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG);
-                }
-            }
-        }
-    }
-
-    /**
-     * Reads an argument list from the command socket/
-     * @return Argument list or null if EOF is reached
-     * @throws IOException passed straight through
-     */
-    private String[] readArgumentList()
-            throws IOException {
-
-        /**
-         * See android.os.Process.zygoteSendArgsAndGetPid()
-         * Presently the wire format to the zygote process is:
-         * a) a count of arguments (argc, in essence)
-         * b) a number of newline-separated argument strings equal to count
-         *
-         * After the zygote process reads these it will write the pid of
-         * the child or -1 on failure.
-         */
-
-        int argc;
-
-        try {
-            String s = mSocketReader.readLine();
-
-            if (s == null) {
-                // EOF reached.
-                return null;
-            }
-            argc = Integer.parseInt(s);
-        } catch (NumberFormatException ex) {
-            Log.e(TAG, "invalid Zygote wire format: non-int at argc");
-            throw new IOException("invalid wire format");
-        }
-
-        // See bug 1092107: large argc can be used for a DOS attack
-        if (argc > MAX_ZYGOTE_ARGC) {
-            throw new IOException("max arg count exceeded");
-        }
-
-        String[] result = new String[argc];
-        for (int i = 0; i < argc; i++) {
-            result[i] = mSocketReader.readLine();
-            if (result[i] == null) {
-                // We got an unexpected EOF.
-                throw new IOException("truncated request");
-            }
-        }
-
-        return result;
-    }
-
-    /**
-     * uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
-     * operation. It may also specify any gid and setgroups() list it chooses.
-     * In factory test mode, it may specify any UID.
-     *
-     * @param args non-null; zygote spawner arguments
-     * @param peer non-null; peer credentials
-     * @throws ZygoteSecurityException
-     */
-    private static void applyUidSecurityPolicy(Arguments args, Credentials peer)
-            throws ZygoteSecurityException {
-
-        if (peer.getUid() == Process.SYSTEM_UID) {
-            /* In normal operation, SYSTEM_UID can only specify a restricted
-             * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
-             */
-            boolean uidRestricted = FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF;
-
-            if (uidRestricted && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
-                throw new ZygoteSecurityException(
-                        "System UID may not launch process with UID < "
-                        + Process.SYSTEM_UID);
-            }
-        }
-
-        // If not otherwise specified, uid and gid are inherited from peer
-        if (!args.uidSpecified) {
-            args.uid = peer.getUid();
-            args.uidSpecified = true;
-        }
-        if (!args.gidSpecified) {
-            args.gid = peer.getGid();
-            args.gidSpecified = true;
-        }
-    }
-
-    /**
-     * Applies debugger system properties to the zygote arguments.
-     *
-     * If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
-     * the debugger state is specified via the "--enable-jdwp" flag
-     * in the spawn request.
-     *
-     * @param args non-null; zygote spawner args
-     */
-    public static void applyDebuggerSystemProperty(Arguments args) {
-        if (RoSystemProperties.DEBUGGABLE) {
-            args.runtimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
-        }
-    }
-
-    /**
-     * Applies zygote security policy.
-     * Based on the credentials of the process issuing a zygote command:
-     * <ol>
-     * <li> uid 0 (root) may specify --invoke-with to launch Zygote with a
-     * wrapper command.
-     * <li> Any other uid may not specify any invoke-with argument.
-     * </ul>
-     *
-     * @param args non-null; zygote spawner arguments
-     * @param peer non-null; peer credentials
-     * @throws ZygoteSecurityException
-     */
-    private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer)
-            throws ZygoteSecurityException {
-        int peerUid = peer.getUid();
-
-        if (args.invokeWith != null && peerUid != 0 &&
-            (args.runtimeFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) {
-            throw new ZygoteSecurityException("Peer is permitted to specify an"
-                    + "explicit invoke-with wrapper command only for debuggable"
-                    + "applications.");
-        }
-    }
-
-    /**
-     * Applies invoke-with system properties to the zygote arguments.
-     *
-     * @param args non-null; zygote args
-     */
-    public static void applyInvokeWithSystemProperty(Arguments args) {
-        if (args.invokeWith == null && args.niceName != null) {
-            String property = "wrap." + args.niceName;
-            args.invokeWith = SystemProperties.get(property);
-            if (args.invokeWith != null && args.invokeWith.length() == 0) {
-                args.invokeWith = null;
-            }
-        }
-    }
-
-    /**
      * Handles post-fork setup of child proc, closing sockets as appropriate,
      * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
      * if successful or returning if failed.
@@ -890,7 +390,7 @@
      * @param pipeFd null-ok; pipe for communication back to Zygote.
      * @param isZygote whether this new child process is itself a new Zygote.
      */
-    private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
+    private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
             FileDescriptor pipeFd, boolean isZygote) {
         /**
          * By the time we get here, the native code has closed the two actual Zygote
@@ -913,27 +413,27 @@
             }
         }
 
-        if (parsedArgs.niceName != null) {
-            Process.setArgV0(parsedArgs.niceName);
+        if (parsedArgs.mNiceName != null) {
+            Process.setArgV0(parsedArgs.mNiceName);
         }
 
         // End of the postFork event.
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-        if (parsedArgs.invokeWith != null) {
-            WrapperInit.execApplication(parsedArgs.invokeWith,
-                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
+        if (parsedArgs.mInvokeWith != null) {
+            WrapperInit.execApplication(parsedArgs.mInvokeWith,
+                    parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
                     VMRuntime.getCurrentInstructionSet(),
-                    pipeFd, parsedArgs.remainingArgs);
+                    pipeFd, parsedArgs.mRemainingArgs);
 
             // Should not get here.
             throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
         } else {
             if (!isZygote) {
-                return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
-                        null /* classLoader */);
+                return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
+                        parsedArgs.mRemainingArgs, null /* classLoader */);
             } else {
-                return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
-                        parsedArgs.remainingArgs, null /* classLoader */);
+                return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
+                        parsedArgs.mRemainingArgs, null /* classLoader */);
             }
         }
     }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index c2c6ae6..e3e55ed 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -21,7 +21,6 @@
 
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.opengl.EGL14;
 import android.os.Build;
 import android.os.Environment;
 import android.os.IInstalld;
@@ -71,16 +70,16 @@
 /**
  * Startup class for the zygote process.
  *
- * Pre-initializes some classes, and then waits for commands on a UNIX domain
- * socket. Based on these commands, forks off child processes that inherit
- * the initial state of the VM.
+ * Pre-initializes some classes, and then waits for commands on a UNIX domain socket. Based on these
+ * commands, forks off child processes that inherit the initial state of the VM.
  *
- * Please see {@link ZygoteConnection.Arguments} for documentation on the
- * client protocol.
+ * Please see {@link ZygoteArguments} for documentation on the client protocol.
  *
  * @hide
  */
 public class ZygoteInit {
+
+    // TODO (chriswailes): Change this so it is set with Zygote or ZygoteSecondary as appropriate
     private static final String TAG = "Zygote";
 
     private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
@@ -89,11 +88,15 @@
     private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
     private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
 
-    /** when preloading, GC after allocating this many bytes */
+    /**
+     * when preloading, GC after allocating this many bytes
+     */
     private static final int PRELOAD_GC_THRESHOLD = 50000;
 
     private static final String ABI_LIST_ARG = "--abi-list=";
 
+    // TODO (chriswailes): Re-name this --zygote-socket-name= and then add a
+    // --blastula-socket-name parameter.
     private static final String SOCKET_NAME_ARG = "--socket-name=";
 
     /**
@@ -106,7 +109,9 @@
      */
     private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";
 
-    /** Controls whether we should preload resources during zygote init. */
+    /**
+     * Controls whether we should preload resources during zygote init.
+     */
     public static final boolean PRELOAD_RESOURCES = true;
 
     private static final int UNPRIVILEGED_UID = 9999;
@@ -173,6 +178,7 @@
     }
 
     native private static void nativePreloadAppProcessHALs();
+
     native private static void nativePreloadOpenGL();
 
     private static void preloadOpenGL() {
@@ -191,8 +197,8 @@
     /**
      * Register AndroidKeyStoreProvider and warm up the providers that are already registered.
      *
-     * By doing it here we avoid that each app does it when requesting a service from the
-     * provider for the first time.
+     * By doing it here we avoid that each app does it when requesting a service from the provider
+     * for the first time.
      */
     private static void warmUpJcaProviders() {
         long startTime = SystemClock.uptimeMillis();
@@ -218,11 +224,10 @@
     }
 
     /**
-     * Performs Zygote process initialization. Loads and initializes
-     * commonly used classes.
+     * Performs Zygote process initialization. Loads and initializes commonly used classes.
      *
-     * Most classes only cause a few hundred bytes to be allocated, but
-     * a few will allocate a dozen Kbytes (in one case, 500+K).
+     * Most classes only cause a few hundred bytes to be allocated, but a few will allocate a dozen
+     * Kbytes (in one case, 500+K).
      */
     private static void preloadClasses() {
         final VMRuntime runtime = VMRuntime.getRuntime();
@@ -263,8 +268,8 @@
         runtime.setTargetHeapUtilization(0.8f);
 
         try {
-            BufferedReader br
-                = new BufferedReader(new InputStreamReader(is), 256);
+            BufferedReader br =
+                    new BufferedReader(new InputStreamReader(is), Zygote.SOCKET_BUFFER_SIZE);
 
             int count = 0;
             String line;
@@ -305,7 +310,7 @@
             }
 
             Log.i(TAG, "...preloaded " + count + " classes in "
-                    + (SystemClock.uptimeMillis()-startTime) + "ms.");
+                    + (SystemClock.uptimeMillis() - startTime) + "ms.");
         } catch (IOException e) {
             Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
         } finally {
@@ -331,11 +336,10 @@
     }
 
     /**
-     * Load in commonly used resources, so they can be shared across
-     * processes.
+     * Load in commonly used resources, so they can be shared across processes.
      *
-     * These tend to be a few Kbytes, but are frequently in the 20-40K
-     * range, and occasionally even larger.
+     * These tend to be a few Kbytes, but are frequently in the 20-40K range, and occasionally even
+     * larger.
      */
     private static void preloadResources() {
         final VMRuntime runtime = VMRuntime.getRuntime();
@@ -352,7 +356,7 @@
                 int N = preloadDrawables(ar);
                 ar.recycle();
                 Log.i(TAG, "...preloaded " + N + " resources in "
-                        + (SystemClock.uptimeMillis()-startTime) + "ms.");
+                        + (SystemClock.uptimeMillis() - startTime) + "ms.");
 
                 startTime = SystemClock.uptimeMillis();
                 ar = mResources.obtainTypedArray(
@@ -360,7 +364,7 @@
                 N = preloadColorStateLists(ar);
                 ar.recycle();
                 Log.i(TAG, "...preloaded " + N + " resources in "
-                        + (SystemClock.uptimeMillis()-startTime) + "ms.");
+                        + (SystemClock.uptimeMillis() - startTime) + "ms.");
 
                 if (mResources.getBoolean(
                         com.android.internal.R.bool.config_freeformWindowManagement)) {
@@ -381,7 +385,7 @@
 
     private static int preloadColorStateLists(TypedArray ar) {
         int N = ar.length();
-        for (int i=0; i<N; i++) {
+        for (int i = 0; i < N; i++) {
             int id = ar.getResourceId(i, 0);
             if (false) {
                 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
@@ -390,8 +394,8 @@
                 if (mResources.getColorStateList(id, null) == null) {
                     throw new IllegalArgumentException(
                             "Unable to find preloaded color resource #0x"
-                            + Integer.toHexString(id)
-                            + " (" + ar.getString(i) + ")");
+                                    + Integer.toHexString(id)
+                                    + " (" + ar.getString(i) + ")");
                 }
             }
         }
@@ -401,7 +405,7 @@
 
     private static int preloadDrawables(TypedArray ar) {
         int N = ar.length();
-        for (int i=0; i<N; i++) {
+        for (int i = 0; i < N; i++) {
             int id = ar.getResourceId(i, 0);
             if (false) {
                 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
@@ -410,8 +414,8 @@
                 if (mResources.getDrawable(id, null) == null) {
                     throw new IllegalArgumentException(
                             "Unable to find preloaded drawable resource #0x"
-                            + Integer.toHexString(id)
-                            + " (" + ar.getString(i) + ")");
+                                    + Integer.toHexString(id)
+                                    + " (" + ar.getString(i) + ")");
                 }
             }
         }
@@ -419,9 +423,8 @@
     }
 
     /**
-     * Runs several special GCs to try to clean up a few generations of
-     * softly- and final-reachable objects, along with any other garbage.
-     * This is only useful just before a fork().
+     * Runs several special GCs to try to clean up a few generations of softly- and final-reachable
+     * objects, along with any other garbage. This is only useful just before a fork().
      */
     private static void gcAndFinalize() {
         ZygoteHooks.gcAndFinalize();
@@ -430,12 +433,12 @@
     /**
      * Finish remaining work for the newly forked system server process.
      */
-    private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
+    private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
         // set umask to 0077 so new files and directories will default to owner-only permissions.
         Os.umask(S_IRWXG | S_IRWXO);
 
-        if (parsedArgs.niceName != null) {
-            Process.setArgV0(parsedArgs.niceName);
+        if (parsedArgs.mNiceName != null) {
+            Process.setArgV0(parsedArgs.mNiceName);
         }
 
         final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
@@ -454,8 +457,8 @@
             }
         }
 
-        if (parsedArgs.invokeWith != null) {
-            String[] args = parsedArgs.remainingArgs;
+        if (parsedArgs.mInvokeWith != null) {
+            String[] args = parsedArgs.mRemainingArgs;
             // If we have a non-null system server class path, we'll have to duplicate the
             // existing arguments and append the classpath to it. ART will handle the classpath
             // correctly when we exec a new process.
@@ -467,15 +470,15 @@
                 args = amendedArgs;
             }
 
-            WrapperInit.execApplication(parsedArgs.invokeWith,
-                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
+            WrapperInit.execApplication(parsedArgs.mInvokeWith,
+                    parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
                     VMRuntime.getCurrentInstructionSet(), null, args);
 
             throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
         } else {
             ClassLoader cl = null;
             if (systemServerClasspath != null) {
-                cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
+                cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion);
 
                 Thread.currentThread().setContextClassLoader(cl);
             }
@@ -483,16 +486,17 @@
             /*
              * Pass the remaining arguments to SystemServer.
              */
-            return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
+            return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
+                    parsedArgs.mRemainingArgs, cl);
         }
 
         /* should never reach here */
     }
 
     /**
-     * Note that preparing the profiles for system server does not require special
-     * selinux permissions. From the installer perspective the system server is a regular package
-     * which can capture profile information.
+     * Note that preparing the profiles for system server does not require special selinux
+     * permissions. From the installer perspective the system server is a regular package which can
+     * capture profile information.
      */
     private static void prepareSystemServerProfile(String systemServerClasspath)
             throws RemoteException {
@@ -544,8 +548,8 @@
     }
 
     /**
-     * Performs dex-opt on the elements of {@code classPath}, if needed. We
-     * choose the instruction set of the current runtime.
+     * Performs dex-opt on the elements of {@code classPath}, if needed. We choose the instruction
+     * set of the current runtime.
      */
     private static void performSystemServerDexOpt(String classPath) {
         final String[] classPathElements = classPath.split(":");
@@ -563,8 +567,9 @@
             int dexoptNeeded;
             try {
                 dexoptNeeded = DexFile.getDexOptNeeded(
-                    classPathElement, instructionSet, systemServerFilter,
-                    null /* classLoaderContext */, false /* newProfile */, false /* downgrade */);
+                        classPathElement, instructionSet, systemServerFilter,
+                        null /* classLoaderContext */, false /* newProfile */,
+                        false /* downgrade */);
             } catch (FileNotFoundException ignored) {
                 // Do not add to the classpath.
                 Log.w(TAG, "Missing classpath element for system server: " + classPathElement);
@@ -607,8 +612,8 @@
     }
 
     /**
-     * Encodes the system server class loader context in a format that is accepted by dexopt.
-     * This assumes the system server is always loaded with a {@link dalvik.system.PathClassLoader}.
+     * Encodes the system server class loader context in a format that is accepted by dexopt. This
+     * assumes the system server is always loaded with a {@link dalvik.system.PathClassLoader}.
      *
      * Note that ideally we would use the {@code DexoptUtils} to compute this. However we have no
      * dependency here on the server so we hard code the logic again.
@@ -619,10 +624,11 @@
 
     /**
      * Encodes the class path in a format accepted by dexopt.
-     * @param classPath the old class path (may be empty).
-     * @param newElement the new class path elements
-     * @return the class path encoding resulted from appending {@code newElement} to
-     * {@code classPath}.
+     *
+     * @param classPath  The old class path (may be empty).
+     * @param newElement  The new class path elements
+     * @return The class path encoding resulted from appending {@code newElement} to {@code
+     * classPath}.
      */
     private static String encodeSystemServerClassPath(String classPath, String newElement) {
         return (classPath == null || classPath.isEmpty())
@@ -633,25 +639,25 @@
     /**
      * Prepare the arguments and forks for the system server process.
      *
-     * Returns an {@code Runnable} that provides an entrypoint into system_server code in the
-     * child process, and {@code null} in the parent.
+     * @return A {@code Runnable} that provides an entrypoint into system_server code in the child
+     * process; {@code null} in the parent.
      */
     private static Runnable forkSystemServer(String abiList, String socketName,
             ZygoteServer zygoteServer) {
         long capabilities = posixCapabilitiesAsBits(
-            OsConstants.CAP_IPC_LOCK,
-            OsConstants.CAP_KILL,
-            OsConstants.CAP_NET_ADMIN,
-            OsConstants.CAP_NET_BIND_SERVICE,
-            OsConstants.CAP_NET_BROADCAST,
-            OsConstants.CAP_NET_RAW,
-            OsConstants.CAP_SYS_MODULE,
-            OsConstants.CAP_SYS_NICE,
-            OsConstants.CAP_SYS_PTRACE,
-            OsConstants.CAP_SYS_TIME,
-            OsConstants.CAP_SYS_TTY_CONFIG,
-            OsConstants.CAP_WAKE_ALARM,
-            OsConstants.CAP_BLOCK_SUSPEND
+                OsConstants.CAP_IPC_LOCK,
+                OsConstants.CAP_KILL,
+                OsConstants.CAP_NET_ADMIN,
+                OsConstants.CAP_NET_BIND_SERVICE,
+                OsConstants.CAP_NET_BROADCAST,
+                OsConstants.CAP_NET_RAW,
+                OsConstants.CAP_SYS_MODULE,
+                OsConstants.CAP_SYS_NICE,
+                OsConstants.CAP_SYS_PTRACE,
+                OsConstants.CAP_SYS_TIME,
+                OsConstants.CAP_SYS_TTY_CONFIG,
+                OsConstants.CAP_WAKE_ALARM,
+                OsConstants.CAP_BLOCK_SUSPEND
         );
         /* Containers run without some capabilities, so drop any caps that are not available. */
         StructCapUserHeader header = new StructCapUserHeader(
@@ -666,38 +672,39 @@
 
         /* Hardcoded command line to start the system server */
         String args[] = {
-            "--setuid=1000",
-            "--setgid=1000",
-            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
-            "--capabilities=" + capabilities + "," + capabilities,
-            "--nice-name=system_server",
-            "--runtime-args",
-            "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
-            "com.android.server.SystemServer",
+                "--setuid=1000",
+                "--setgid=1000",
+                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
+                        + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
+                "--capabilities=" + capabilities + "," + capabilities,
+                "--nice-name=system_server",
+                "--runtime-args",
+                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
+                "com.android.server.SystemServer",
         };
-        ZygoteConnection.Arguments parsedArgs = null;
+        ZygoteArguments parsedArgs = null;
 
         int pid;
 
         try {
-            parsedArgs = new ZygoteConnection.Arguments(args);
-            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
-            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
+            parsedArgs = new ZygoteArguments(args);
+            Zygote.applyDebuggerSystemProperty(parsedArgs);
+            Zygote.applyInvokeWithSystemProperty(parsedArgs);
 
             boolean profileSystemServer = SystemProperties.getBoolean(
                     "dalvik.vm.profilesystemserver", false);
             if (profileSystemServer) {
-                parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
+                parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
             }
 
             /* Request to fork the system server process */
             pid = Zygote.forkSystemServer(
-                    parsedArgs.uid, parsedArgs.gid,
-                    parsedArgs.gids,
-                    parsedArgs.runtimeFlags,
+                    parsedArgs.mUid, parsedArgs.mGid,
+                    parsedArgs.mGids,
+                    parsedArgs.mRuntimeFlags,
                     null,
-                    parsedArgs.permittedCapabilities,
-                    parsedArgs.effectiveCapabilities);
+                    parsedArgs.mPermittedCapabilities,
+                    parsedArgs.mEffectiveCapabilities);
         } catch (IllegalArgumentException ex) {
             throw new RuntimeException(ex);
         }
@@ -743,7 +750,7 @@
             throw new RuntimeException("Failed to setpgid(0,0)", ex);
         }
 
-        final Runnable caller;
+        Runnable caller;
         try {
             // Report Zygote start time to tron unless it is a runtime restart
             if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
@@ -779,16 +786,26 @@
                 throw new RuntimeException("No ABI list supplied.");
             }
 
-            zygoteServer.registerServerSocketFromEnv(socketName);
+            // TODO (chriswailes): Wrap these three calls in a helper function?
+            final String blastulaSocketName =
+                    socketName.equals(ZygoteProcess.ZYGOTE_SOCKET_NAME)
+                            ? ZygoteProcess.BLASTULA_POOL_SOCKET_NAME
+                            : ZygoteProcess.BLASTULA_POOL_SECONDARY_SOCKET_NAME;
+
+            zygoteServer.createZygoteSocket(socketName);
+            Zygote.createBlastulaSocket(blastulaSocketName);
+
+            Zygote.getSocketFDs(socketName.equals(ZygoteProcess.ZYGOTE_SOCKET_NAME));
+
             // In some configurations, we avoid preloading resources and classes eagerly.
             // In such cases, we will preload things prior to our first fork.
             if (!enableLazyPreload) {
                 bootTimingsTraceLog.traceBegin("ZygotePreload");
                 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
-                    SystemClock.uptimeMillis());
+                        SystemClock.uptimeMillis());
                 preload(bootTimingsTraceLog);
                 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
-                    SystemClock.uptimeMillis());
+                        SystemClock.uptimeMillis());
                 bootTimingsTraceLog.traceEnd(); // ZygotePreload
             } else {
                 Zygote.resetNicePriority();
@@ -822,11 +839,18 @@
                 }
             }
 
-            Log.i(TAG, "Accepting command socket connections");
+            // If the return value is null then this is the zygote process
+            // returning to the normal control flow.  If it returns a Runnable
+            // object then this is a blastula that has finished specializing.
+            caller = Zygote.initBlastulaPool();
 
-            // The select loop returns early in the child process after a fork and
-            // loops forever in the zygote.
-            caller = zygoteServer.runSelectLoop(abiList);
+            if (caller == null) {
+                Log.i(TAG, "Accepting command socket connections");
+
+                // The select loop returns early in the child process after a fork and
+                // loops forever in the zygote.
+                caller = zygoteServer.runSelectLoop(abiList);
+            }
         } catch (Throwable ex) {
             Log.e(TAG, "System zygote died with exception", ex);
             throw ex;
@@ -844,17 +868,16 @@
     /**
      * Return {@code true} if this device configuration has another zygote.
      *
-     * We determine this by comparing the device ABI list with this zygotes
-     * list. If this zygote supports all ABIs this device supports, there won't
-     * be another zygote.
+     * We determine this by comparing the device ABI list with this zygotes list. If this zygote
+     * supports all ABIs this device supports, there won't be another zygote.
      */
     private static boolean hasSecondZygote(String abiList) {
         return !SystemProperties.get("ro.product.cpu.abilist").equals(abiList);
     }
 
     private static void waitForSecondaryZygote(String socketName) {
-        String otherZygoteName = Process.ZYGOTE_SOCKET.equals(socketName) ?
-                Process.SECONDARY_ZYGOTE_SOCKET : Process.ZYGOTE_SOCKET;
+        String otherZygoteName = ZygoteProcess.ZYGOTE_SOCKET_NAME.equals(socketName)
+                ? ZygoteProcess.ZYGOTE_SECONDARY_SOCKET_NAME : ZygoteProcess.ZYGOTE_SOCKET_NAME;
         ZygoteProcess.waitForConnectionToZygote(otherZygoteName);
     }
 
@@ -869,9 +892,8 @@
     }
 
     /**
-     * The main function called when started through the zygote process. This
-     * could be unified with main(), if the native code in nativeFinishInit()
-     * were rationalized with Zygote startup.<p>
+     * The main function called when started through the zygote process. This could be unified with
+     * main(), if the native code in nativeFinishInit() were rationalized with Zygote startup.<p>
      *
      * Current recognized args:
      * <ul>
@@ -881,7 +903,8 @@
      * @param targetSdkVersion target SDK version
      * @param argv arg strings
      */
-    public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
+    public static final Runnable zygoteInit(int targetSdkVersion, String[] argv,
+            ClassLoader classLoader) {
         if (RuntimeInit.DEBUG) {
             Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
         }
@@ -895,9 +918,9 @@
     }
 
     /**
-     * The main function called when starting a child zygote process. This is used as an
-     * alternative to zygoteInit(), which skips calling into initialization routines that
-     * start the Binder threadpool.
+     * The main function called when starting a child zygote process. This is used as an alternative
+     * to zygoteInit(), which skips calling into initialization routines that start the Binder
+     * threadpool.
      */
     static final Runnable childZygoteInit(
             int targetSdkVersion, String[] argv, ClassLoader classLoader) {
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index fecf9b9..a78c095 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -20,14 +20,16 @@
 
 import android.net.LocalServerSocket;
 import android.net.LocalSocket;
-import android.system.Os;
 import android.system.ErrnoException;
+import android.system.Os;
 import android.system.StructPollfd;
 import android.util.Log;
-
 import android.util.Slog;
-import java.io.IOException;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.util.ArrayList;
 
 /**
@@ -40,18 +42,17 @@
  * client protocol.
  */
 class ZygoteServer {
+    // TODO (chriswailes): Change this so it is set with Zygote or ZygoteSecondary as appropriate
     public static final String TAG = "ZygoteServer";
 
-    private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
-
     /**
      * Listening socket that accepts new server connections.
      */
-    private LocalServerSocket mServerSocket;
+    private LocalServerSocket mZygoteSocket;
 
     /**
-     * Whether or not mServerSocket's underlying FD should be closed directly.
-     * If mServerSocket is created with an existing FD, closing the socket does
+     * Whether or not mZygoteSocket's underlying FD should be closed directly.
+     * If mZygoteSocket is created with an existing FD, closing the socket does
      * not close the FD and it must be closed explicitly. If the socket is created
      * with a name instead, then closing the socket will close the underlying FD
      * and it should not be double-closed.
@@ -63,39 +64,24 @@
      */
     private boolean mIsForkChild;
 
-    ZygoteServer() {
-    }
+    ZygoteServer() { }
 
     void setForkChild() {
         mIsForkChild = true;
     }
 
     /**
-     * Registers a server socket for zygote command connections. This locates the server socket
-     * file descriptor through an ANDROID_SOCKET_ environment variable.
+     * Creates a managed object representing the Zygote socket that has already
+     * been initialized and bound by init.
+     *
+     * TODO (chriswailes): Move the name selection logic into this function.
      *
      * @throws RuntimeException when open fails
      */
-    void registerServerSocketFromEnv(String socketName) {
-        if (mServerSocket == null) {
-            int fileDesc;
-            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
-            try {
-                String env = System.getenv(fullSocketName);
-                fileDesc = Integer.parseInt(env);
-            } catch (RuntimeException ex) {
-                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
-            }
-
-            try {
-                FileDescriptor fd = new FileDescriptor();
-                fd.setInt$(fileDesc);
-                mServerSocket = new LocalServerSocket(fd);
-                mCloseSocketFd = true;
-            } catch (IOException ex) {
-                throw new RuntimeException(
-                        "Error binding to local socket '" + fileDesc + "'", ex);
-            }
+    void createZygoteSocket(String socketName) {
+        if (mZygoteSocket == null) {
+            mZygoteSocket = Zygote.createManagedSocketFromInitSocket(socketName);
+            mCloseSocketFd = true;
         }
     }
 
@@ -104,9 +90,9 @@
      * at the specified name in the abstract socket namespace.
      */
     void registerServerSocketAtAbstractName(String socketName) {
-        if (mServerSocket == null) {
+        if (mZygoteSocket == null) {
             try {
-                mServerSocket = new LocalServerSocket(socketName);
+                mZygoteSocket = new LocalServerSocket(socketName);
                 mCloseSocketFd = false;
             } catch (IOException ex) {
                 throw new RuntimeException(
@@ -121,7 +107,7 @@
      */
     private ZygoteConnection acceptCommandPeer(String abiList) {
         try {
-            return createNewConnection(mServerSocket.accept(), abiList);
+            return createNewConnection(mZygoteSocket.accept(), abiList);
         } catch (IOException ex) {
             throw new RuntimeException(
                     "IOException during accept()", ex);
@@ -139,9 +125,9 @@
      */
     void closeServerSocket() {
         try {
-            if (mServerSocket != null) {
-                FileDescriptor fd = mServerSocket.getFileDescriptor();
-                mServerSocket.close();
+            if (mZygoteSocket != null) {
+                FileDescriptor fd = mZygoteSocket.getFileDescriptor();
+                mZygoteSocket.close();
                 if (fd != null && mCloseSocketFd) {
                     Os.close(fd);
                 }
@@ -152,7 +138,7 @@
             Log.e(TAG, "Zygote:  error closing descriptor", ex);
         }
 
-        mServerSocket = null;
+        mZygoteSocket = null;
     }
 
     /**
@@ -161,8 +147,8 @@
      * closure after a child process is forked off.
      */
 
-    FileDescriptor getServerSocketFileDescriptor() {
-        return mServerSocket.getFileDescriptor();
+    FileDescriptor getZygoteSocketFileDescriptor() {
+        return mZygoteSocket.getFileDescriptor();
     }
 
     /**
@@ -171,36 +157,67 @@
      * worth at a time.
      */
     Runnable runSelectLoop(String abiList) {
-        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
+        ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
         ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
 
-        fds.add(mServerSocket.getFileDescriptor());
+        socketFDs.add(mZygoteSocket.getFileDescriptor());
         peers.add(null);
 
         while (true) {
-            StructPollfd[] pollFds = new StructPollfd[fds.size()];
-            for (int i = 0; i < pollFds.length; ++i) {
-                pollFds[i] = new StructPollfd();
-                pollFds[i].fd = fds.get(i);
-                pollFds[i].events = (short) POLLIN;
+            int[] blastulaPipeFDs = Zygote.getBlastulaPipeFDs();
+
+            // Space for all of the socket FDs, the Blastula Pool Event FD, and
+            // all of the open blastula read pipe FDs.
+            StructPollfd[] pollFDs =
+                new StructPollfd[socketFDs.size() + 1 + blastulaPipeFDs.length];
+
+            int pollIndex = 0;
+            for (FileDescriptor socketFD : socketFDs) {
+                pollFDs[pollIndex] = new StructPollfd();
+                pollFDs[pollIndex].fd = socketFD;
+                pollFDs[pollIndex].events = (short) POLLIN;
+                ++pollIndex;
             }
+
+            final int blastulaPoolEventFDIndex = pollIndex;
+            pollFDs[pollIndex] = new StructPollfd();
+            pollFDs[pollIndex].fd = Zygote.sBlastulaPoolEventFD;
+            pollFDs[pollIndex].events = (short) POLLIN;
+            ++pollIndex;
+
+            for (int blastulaPipeFD : blastulaPipeFDs) {
+                FileDescriptor managedFd = new FileDescriptor();
+                managedFd.setInt$(blastulaPipeFD);
+
+                pollFDs[pollIndex] = new StructPollfd();
+                pollFDs[pollIndex].fd = managedFd;
+                pollFDs[pollIndex].events = (short) POLLIN;
+                ++pollIndex;
+            }
+
             try {
-                Os.poll(pollFds, -1);
+                Os.poll(pollFDs, -1);
             } catch (ErrnoException ex) {
                 throw new RuntimeException("poll failed", ex);
             }
-            for (int i = pollFds.length - 1; i >= 0; --i) {
-                if ((pollFds[i].revents & POLLIN) == 0) {
+
+            while (--pollIndex >= 0) {
+                if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
                     continue;
                 }
 
-                if (i == 0) {
+                if (pollIndex == 0) {
+                    // Zygote server socket
+
                     ZygoteConnection newPeer = acceptCommandPeer(abiList);
                     peers.add(newPeer);
-                    fds.add(newPeer.getFileDesciptor());
-                } else {
+                    socketFDs.add(newPeer.getFileDescriptor());
+
+                } else if (pollIndex < blastulaPoolEventFDIndex) {
+                    // Session socket accepted from the Zygote server socket
+
                     try {
-                        ZygoteConnection connection = peers.get(i);
+                        ZygoteConnection connection = peers.get(pollIndex);
                         final Runnable command = connection.processOneCommand(this);
 
                         if (mIsForkChild) {
@@ -218,12 +235,12 @@
                             }
 
                             // We don't know whether the remote side of the socket was closed or
-                            // not until we attempt to read from it from processOneCommand. This shows up as
-                            // a regular POLLIN event in our regular processing loop.
+                            // not until we attempt to read from it from processOneCommand. This
+                            // shows up as a regular POLLIN event in our regular processing loop.
                             if (connection.isClosedByPeer()) {
                                 connection.closeSocket();
-                                peers.remove(i);
-                                fds.remove(i);
+                                peers.remove(pollIndex);
+                                socketFDs.remove(pollIndex);
                             }
                         }
                     } catch (Exception e) {
@@ -235,13 +252,13 @@
 
                             Slog.e(TAG, "Exception executing zygote command: ", e);
 
-                            // Make sure the socket is closed so that the other end knows immediately
-                            // that something has gone wrong and doesn't time out waiting for a
-                            // response.
-                            ZygoteConnection conn = peers.remove(i);
+                            // Make sure the socket is closed so that the other end knows
+                            // immediately that something has gone wrong and doesn't time out
+                            // waiting for a response.
+                            ZygoteConnection conn = peers.remove(pollIndex);
                             conn.closeSocket();
 
-                            fds.remove(i);
+                            socketFDs.remove(pollIndex);
                         } else {
                             // We're in the child so any exception caught here has happened post
                             // fork and before we execute ActivityThread.main (or any other main()
@@ -255,6 +272,55 @@
                         // is returned.
                         mIsForkChild = false;
                     }
+                } else {
+                    // Either the blastula pool event FD or a blastula reporting pipe.
+
+                    // If this is the event FD the payload will be the number of blastulas removed.
+                    // If this is a reporting pipe FD the payload will be the PID of the blastula
+                    // that was just specialized.
+                    long messagePayload = -1;
+
+                    try {
+                        byte[] buffer = new byte[Zygote.BLASTULA_MANAGEMENT_MESSAGE_BYTES];
+                        int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
+
+                        if (readBytes == Zygote.BLASTULA_MANAGEMENT_MESSAGE_BYTES) {
+                            DataInputStream inputStream =
+                                    new DataInputStream(new ByteArrayInputStream(buffer));
+
+                            messagePayload = inputStream.readLong();
+                        } else {
+                            Log.e(TAG, "Incomplete read from blastula management FD of size "
+                                    + readBytes);
+                            continue;
+                        }
+                    } catch (Exception ex) {
+                        if (pollIndex == blastulaPoolEventFDIndex) {
+                            Log.e(TAG, "Failed to read from blastula pool event FD: "
+                                    + ex.getMessage());
+                        } else {
+                            Log.e(TAG, "Failed to read from blastula reporting pipe: "
+                                    + ex.getMessage());
+                        }
+
+                        continue;
+                    }
+
+                    if (pollIndex > blastulaPoolEventFDIndex) {
+                        Zygote.removeBlastulaTableEntry((int) messagePayload);
+                    }
+
+                    int[] sessionSocketRawFDs =
+                            socketFDs.subList(1, socketFDs.size())
+                                .stream()
+                                .mapToInt(fd -> fd.getInt$())
+                                .toArray();
+
+                    final Runnable command = Zygote.fillBlastulaPool(sessionSocketRawFDs);
+
+                    if (command != null) {
+                        return command;
+                    }
                 }
             }
         }
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index e2c23de..cdaf33f 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -232,7 +232,7 @@
     // This is the caption view for the window, containing the caption and window control
     // buttons. The visibility of this decor depends on the workspace and the window type.
     // If the window type does not require such a view, this member might be null.
-    DecorCaptionView mDecorCaptionView;
+    private DecorCaptionView mDecorCaptionView;
 
     private boolean mWindowResizeCallbacksAdded = false;
     private Drawable.Callback mLastBackgroundDrawableCb = null;
@@ -977,6 +977,7 @@
     @Override
     public void onWindowSystemUiVisibilityChanged(int visible) {
         updateColorViews(null /* insets */, true /* animate */);
+        updateDecorCaptionStatus(getResources().getConfiguration());
     }
 
     @Override
@@ -1855,8 +1856,27 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
 
-        final boolean displayWindowDecor =
-                newConfig.windowConfiguration.hasWindowDecorCaption();
+        updateDecorCaptionStatus(newConfig);
+
+        updateAvailableWidth();
+        initializeElevation();
+    }
+
+    /**
+     * Determines if the workspace is entirely covered by the window.
+     * @return {@code true} when the window is filling the entire screen/workspace.
+     **/
+    private boolean isFillingScreen(Configuration config) {
+        final boolean isFullscreen = config.windowConfiguration.getWindowingMode()
+                == WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+        return isFullscreen && (0 != ((getWindowSystemUiVisibility() | getSystemUiVisibility())
+                & (View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_LOW_PROFILE)));
+    }
+
+    private void updateDecorCaptionStatus(Configuration config) {
+        final boolean displayWindowDecor = config.windowConfiguration.hasWindowDecorCaption()
+                && !isFillingScreen(config);
         if (mDecorCaptionView == null && displayWindowDecor) {
             // Configuration now requires a caption.
             final LayoutInflater inflater = mWindow.getLayoutInflater();
@@ -1875,9 +1895,6 @@
             mDecorCaptionView.onConfigurationChanged(displayWindowDecor);
             enableCaption(displayWindowDecor);
         }
-
-        updateAvailableWidth();
-        initializeElevation();
     }
 
     void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
diff --git a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
index 100c6ee..adf7692 100644
--- a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
+++ b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
@@ -16,10 +16,10 @@
 
 package com.android.internal.policy;
 
-import com.android.internal.R;
-
 import android.content.res.Resources;
 
+import com.android.internal.R;
+
 /**
  * Utility functions for screen decorations used by both window manager and System UI.
  */
@@ -31,15 +31,19 @@
      * scaling, this means that we don't have to reload them on config changes.
      */
     public static float getWindowCornerRadius(Resources resources) {
+        if (!supportsRoundedCornersOnWindows(resources)) {
+            return 0f;
+        }
+
         // Radius that should be used in case top or bottom aren't defined.
         float defaultRadius = resources.getDimension(R.dimen.rounded_corner_radius);
 
         float topRadius = resources.getDimension(R.dimen.rounded_corner_radius_top);
-        if (topRadius == 0) {
+        if (topRadius == 0f) {
             topRadius = defaultRadius;
         }
         float bottomRadius = resources.getDimension(R.dimen.rounded_corner_radius_bottom);
-        if (bottomRadius == 0) {
+        if (bottomRadius == 0f) {
             bottomRadius = defaultRadius;
         }
 
@@ -47,4 +51,11 @@
         // completely cover the display.
         return Math.min(topRadius, bottomRadius);
     }
+
+    /**
+     * If live rounded corners are supported on windows.
+     */
+    public static boolean supportsRoundedCornersOnWindows(Resources resources) {
+        return resources.getBoolean(R.bool.config_supportsRoundedCornersOnWindows);
+    }
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 53b56f2..6a28059 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -153,13 +153,11 @@
     void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type,
             boolean requireConfirmation, int userId);
     // Used to hide the dialog when a biometric is authenticated
-    void onBiometricAuthenticated();
+    void onBiometricAuthenticated(boolean authenticated);
     // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
     void onBiometricHelp(String message);
     // Used to set a message - the dialog will dismiss after a certain amount of time
     void onBiometricError(String error);
     // Used to hide the biometric dialog when the AuthenticationClient is stopped
     void hideBiometricDialog();
-    // Used to request the "try again" button for authentications which requireConfirmation=true
-    void showBiometricTryAgain();
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 9087dd2..d61f10e 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -65,7 +65,7 @@
             int dismissalSurface, int dismissalSentiment, in NotificationVisibility nv);
     void onNotificationVisibilityChanged( in NotificationVisibility[] newlyVisibleKeys,
             in NotificationVisibility[] noLongerVisibleKeys);
-    void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded);
+    void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded, in int notificationLocation);
     void onNotificationDirectReplied(String key);
     void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount, int smartActionCount,
             boolean generatedByAsssistant);
@@ -97,13 +97,11 @@
     void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type,
             boolean requireConfirmation, int userId);
     // Used to hide the dialog when a biometric is authenticated
-    void onBiometricAuthenticated();
+    void onBiometricAuthenticated(boolean authenticated);
     // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
     void onBiometricHelp(String message);
     // Used to set a message - the dialog will dismiss after a certain amount of time
     void onBiometricError(String error);
     // Used to hide the biometric dialog when the AuthenticationClient is stopped
     void hideBiometricDialog();
-    // Used to request the "try again" button for authentications which requireConfirmation=true
-    void showBiometricTryAgain();
 }
diff --git a/core/java/com/android/internal/statusbar/NotificationVisibility.java b/core/java/com/android/internal/statusbar/NotificationVisibility.java
index a7203e7..24bb789 100644
--- a/core/java/com/android/internal/statusbar/NotificationVisibility.java
+++ b/core/java/com/android/internal/statusbar/NotificationVisibility.java
@@ -21,6 +21,8 @@
 import android.os.Parcelable;
 import android.util.Log;
 
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
 import java.util.ArrayDeque;
 import java.util.Collection;
 
@@ -33,18 +35,53 @@
     public int rank;
     public int count;
     public boolean visible = true;
+    /** The visible location of the notification, could be e.g. notification shade or HUN. */
+    public NotificationLocation location;
     /*package*/ int id;
 
+    /**
+     * The UI location of the notification.
+     *
+     * There is a one-to-one mapping between this enum and
+     * MetricsProto.MetricsEvent.NotificationLocation.
+     */
+    public enum NotificationLocation {
+        LOCATION_UNKNOWN(MetricsEvent.LOCATION_UNKNOWN),
+        LOCATION_FIRST_HEADS_UP(MetricsEvent.LOCATION_FIRST_HEADS_UP), // visible heads-up
+        LOCATION_HIDDEN_TOP(MetricsEvent.LOCATION_HIDDEN_TOP), // hidden/scrolled away on the top
+        LOCATION_MAIN_AREA(MetricsEvent.LOCATION_MAIN_AREA), // visible in the shade
+        // in the bottom stack, and peeking
+        LOCATION_BOTTOM_STACK_PEEKING(MetricsEvent.LOCATION_BOTTOM_STACK_PEEKING),
+        // in the bottom stack, and hidden
+        LOCATION_BOTTOM_STACK_HIDDEN(MetricsEvent.LOCATION_BOTTOM_STACK_HIDDEN),
+        LOCATION_GONE(MetricsEvent.LOCATION_GONE); // the view isn't laid out at all
+
+        private final int mMetricsEventNotificationLocation;
+
+        NotificationLocation(int metricsEventNotificationLocation) {
+            mMetricsEventNotificationLocation = metricsEventNotificationLocation;
+        }
+
+        /**
+         * Returns the field from MetricsEvent.NotificationLocation that corresponds to this object.
+         */
+        public int toMetricsEventEnum() {
+            return mMetricsEventNotificationLocation;
+        }
+    }
+
     private NotificationVisibility() {
         id = sNexrId++;
     }
 
-    private NotificationVisibility(String key, int rank, int count, boolean visibile) {
+    private NotificationVisibility(String key, int rank, int count, boolean visible,
+            NotificationLocation location) {
         this();
         this.key = key;
         this.rank = rank;
         this.count = count;
-        this.visible = visibile;
+        this.visible = visible;
+        this.location = location;
     }
 
     @Override
@@ -54,12 +91,13 @@
                 + " rank=" + rank
                 + " count=" + count
                 + (visible?" visible":"")
+                + " location=" + location.name()
                 + " )";
     }
 
     @Override
     public NotificationVisibility clone() {
-        return obtain(this.key, this.rank, this.count, this.visible);
+        return obtain(this.key, this.rank, this.count, this.visible, this.location);
     }
 
     @Override
@@ -89,6 +127,7 @@
         out.writeInt(this.rank);
         out.writeInt(this.count);
         out.writeInt(this.visible ? 1 : 0);
+        out.writeString(this.location.name());
     }
 
     private void readFromParcel(Parcel in) {
@@ -96,18 +135,28 @@
         this.rank = in.readInt();
         this.count = in.readInt();
         this.visible = in.readInt() != 0;
+        this.location = NotificationLocation.valueOf(in.readString());
     }
 
     /**
-     * Return a new NotificationVisibility instance from the global pool. Allows us to
-     * avoid allocating new objects in many cases.
+     * Create a new NotificationVisibility object.
      */
     public static NotificationVisibility obtain(String key, int rank, int count, boolean visible) {
+        return obtain(key, rank, count, visible,
+                NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN);
+    }
+
+    /**
+     * Create a new NotificationVisibility object.
+     */
+    public static NotificationVisibility obtain(String key, int rank, int count, boolean visible,
+            NotificationLocation location) {
         NotificationVisibility vo = obtain();
         vo.key = key;
         vo.rank = rank;
         vo.count = count;
         vo.visible = visible;
+        vo.location = location;
         return vo;
     }
 
diff --git a/core/java/com/android/internal/textservice/ITextServicesManager.aidl b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
index 20f2aa0..8022949 100644
--- a/core/java/com/android/internal/textservice/ITextServicesManager.aidl
+++ b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
@@ -29,12 +29,13 @@
  * @hide
  */
 interface ITextServicesManager {
-    SpellCheckerInfo getCurrentSpellChecker(String locale);
-    SpellCheckerSubtype getCurrentSpellCheckerSubtype(boolean allowImplicitlySelectedSubtype);
-    oneway void getSpellCheckerService(String sciId, in String locale,
+    SpellCheckerInfo getCurrentSpellChecker(int userId, String locale);
+    SpellCheckerSubtype getCurrentSpellCheckerSubtype(int userId,
+            boolean allowImplicitlySelectedSubtype);
+    oneway void getSpellCheckerService(int userId, String sciId, in String locale,
             in ITextServicesSessionListener tsListener,
             in ISpellCheckerSessionListener scListener, in Bundle bundle);
-    oneway void finishSpellCheckerService(in ISpellCheckerSessionListener listener);
-    boolean isSpellCheckerEnabled();
-    SpellCheckerInfo[] getEnabledSpellCheckers();
+    oneway void finishSpellCheckerService(int userId, in ISpellCheckerSessionListener listener);
+    boolean isSpellCheckerEnabled(int userId);
+    SpellCheckerInfo[] getEnabledSpellCheckers(int userId);
 }
diff --git a/core/java/com/android/internal/usb/DumpUtils.java b/core/java/com/android/internal/usb/DumpUtils.java
index 240c2e7..3260136 100644
--- a/core/java/com/android/internal/usb/DumpUtils.java
+++ b/core/java/com/android/internal/usb/DumpUtils.java
@@ -196,6 +196,15 @@
         }
     }
 
+    private static void writeContaminantPresenceStatus(@NonNull DualDumpOutputStream dump,
+            @NonNull String idName, long id, int contaminantPresenceStatus) {
+        if (dump.isProto()) {
+            dump.write(idName, id, contaminantPresenceStatus);
+        } else {
+            dump.write(idName, id,
+                    UsbPort.contaminantPresenceStatusToString(contaminantPresenceStatus));
+        }
+    }
 
     public static void writePortStatus(@NonNull DualDumpOutputStream dump, @NonNull String idName,
             long id, @NonNull UsbPortStatus status) {
@@ -232,6 +241,10 @@
             dump.end(roleCombinationToken);
         }
 
+        writeContaminantPresenceStatus(dump, "contaminant_presence_status",
+                UsbPortStatusProto.CONTAMINANT_PRESENCE_STATUS,
+                status.getContaminantDetectionStatus());
+
         dump.end(token);
     }
 }
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 470533f2..f91b837 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -327,7 +327,17 @@
         }
     }
 
-    public static @NonNull <T> List<T> defeatNullable(@Nullable List<T> val) {
-        return (val != null) ? val : Collections.emptyList();
+    /**
+     * @return the first element if not empty/null, null otherwise
+     */
+    public static @Nullable <T> T firstOrNull(@Nullable List<T> cur) {
+        return isEmpty(cur) ? null : cur.get(0);
+    }
+
+    /**
+     * @return list of single given element if it's not null, empty list otherwise
+     */
+    public static @NonNull <T> List<T> singletonOrEmpty(@Nullable T item) {
+        return item == null ? Collections.emptyList() : Collections.singletonList(item);
     }
 }
diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java
index a403c06..e0ba317f 100644
--- a/core/java/com/android/internal/util/ContrastColorUtil.java
+++ b/core/java/com/android/internal/util/ContrastColorUtil.java
@@ -586,7 +586,7 @@
      *
      * @param color the base color to use
      * @param amount the amount from 1 to 100 how much to modify the color
-     * @return the now color that was modified
+     * @return the new color that was modified
      */
     public static int getShiftedColor(int color, int amount) {
         final double[] result = ColorUtilsFromCompat.getTempDouble3Array();
@@ -599,6 +599,19 @@
         return ColorUtilsFromCompat.LABToColor(result[0], result[1], result[2]);
     }
 
+    /**
+     * Blends the provided color with white to create a muted version.
+     *
+     * @param color the color to mute
+     * @param alpha the amount from 0 to 1 to set the alpha component of the white scrim
+     * @return the new color that was modified
+     */
+    public static int getMutedColor(int color, float alpha) {
+        int whiteScrim = ColorUtilsFromCompat.setAlphaComponent(
+                Color.WHITE, (int) (255 * alpha));
+        return compositeColors(whiteScrim, color);
+    }
+
     private static boolean shouldUseDark(int backgroundColor, boolean defaultBackgroundIsDark) {
         if (backgroundColor == Notification.COLOR_DEFAULT) {
             return !defaultBackgroundIsDark;
@@ -675,6 +688,18 @@
         }
 
         /**
+         * Set the alpha component of {@code color} to be {@code alpha}.
+         */
+        @ColorInt
+        public static int setAlphaComponent(@ColorInt int color,
+                @IntRange(from = 0x0, to = 0xFF) int alpha) {
+            if (alpha < 0 || alpha > 255) {
+                throw new IllegalArgumentException("alpha must be between 0 and 255.");
+            }
+            return (color & 0x00ffffff) | (alpha << 24);
+        }
+
+        /**
          * Returns the luminance of a color as a float between {@code 0.0} and {@code 1.0}.
          * <p>Defined as the Y component in the XYZ representation of {@code color}.</p>
          */
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index 1aa32cc..276cad9 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -53,7 +53,6 @@
     public static final int BASE_WIFI_PASSPOINT_MANAGER                             = 0x00028000;
     public static final int BASE_WIFI_PASSPOINT_SERVICE                             = 0x00028100;
     public static final int BASE_WIFI_LOGGER                                        = 0x00028300;
-    public static final int BASE_DHCP                                               = 0x00030000;
     public static final int BASE_DATA_CONNECTION                                    = 0x00040000;
     public static final int BASE_DATA_CONNECTION_AC                                 = 0x00041000;
     public static final int BASE_DATA_CONNECTION_TRACKER                            = 0x00042000;
@@ -62,7 +61,6 @@
     public static final int BASE_NETWORK_STATE_TRACKER                              = 0x00070000;
     public static final int BASE_CONNECTIVITY_MANAGER                               = 0x00080000;
     public static final int BASE_NETWORK_AGENT                                      = 0x00081000;
-    public static final int BASE_NETWORK_MONITOR                                    = 0x00082000;
     public static final int BASE_NETWORK_FACTORY                                    = 0x00083000;
     public static final int BASE_ETHERNET                                           = 0x00084000;
     public static final int BASE_LOWPAN                                             = 0x00085000;
diff --git a/core/java/com/android/internal/util/SyncResultReceiver.java b/core/java/com/android/internal/util/SyncResultReceiver.java
new file mode 100644
index 0000000..9a346ac
--- /dev/null
+++ b/core/java/com/android/internal/util/SyncResultReceiver.java
@@ -0,0 +1,145 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import com.android.internal.os.IResultReceiver;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@code IResultReceiver} implementation that can be used to make "sync" Binder calls by blocking
+ * until it receives a result
+ *
+ * @hide
+ */
+public final class SyncResultReceiver extends IResultReceiver.Stub {
+
+    private static final String EXTRA = "EXTRA";
+
+    private final CountDownLatch mLatch  = new CountDownLatch(1);
+    private final int mTimeoutMs;
+    private int mResult;
+    private Bundle mBundle;
+
+    /**
+     * Default constructor.
+     *
+     * @param timeoutMs how long to block waiting for {@link IResultReceiver} callbacks.
+     */
+    public SyncResultReceiver(int timeoutMs) {
+        mTimeoutMs = timeoutMs;
+    }
+
+    private void waitResult() throws TimeoutException {
+        try {
+            if (!mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS)) {
+                throw new TimeoutException("Not called in " + mTimeoutMs + "ms");
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new TimeoutException("Interrupted");
+        }
+    }
+
+    /**
+     * Gets the result from an operation that returns an {@code int}.
+     */
+    public int getIntResult() throws TimeoutException {
+        waitResult();
+        return mResult;
+    }
+
+    /**
+     * Gets the result from an operation that returns an {@code String}.
+     */
+    @Nullable
+    public String getStringResult() throws TimeoutException {
+        waitResult();
+        return mBundle == null ? null : mBundle.getString(EXTRA);
+    }
+
+    /**
+     * Gets the result from an operation that returns a {@code String[]}.
+     */
+    @Nullable
+    public String[] getStringArrayResult() throws TimeoutException {
+        waitResult();
+        return mBundle == null ? null : mBundle.getStringArray(EXTRA);
+    }
+
+    /**
+     * Gets the result from an operation that returns a {@code Parcelable}.
+     */
+    @Nullable
+    public <P extends Parcelable> P getParcelableResult() throws TimeoutException {
+        waitResult();
+        return mBundle == null ? null : mBundle.getParcelable(EXTRA);
+    }
+
+    @Override
+    public void send(int resultCode, Bundle resultData) {
+        mResult = resultCode;
+        mBundle = resultData;
+        mLatch.countDown();
+    }
+
+    /**
+     * Creates a bundle for a {@code String} value so it can be retrieved by
+     * {@link #getStringResult()}.
+     */
+    @NonNull
+    public static Bundle bundleFor(@Nullable String value) {
+        final Bundle bundle = new Bundle();
+        bundle.putString(EXTRA, value);
+        return bundle;
+    }
+
+    /**
+     * Creates a bundle for a {@code String[]} value so it can be retrieved by
+     * {@link #getStringArrayResult()}.
+     */
+    @NonNull
+    public static Bundle bundleFor(@Nullable String[] value) {
+        final Bundle bundle = new Bundle();
+        bundle.putStringArray(EXTRA, value);
+        return bundle;
+    }
+
+    /**
+     * Creates a bundle for a {@code Parcelable} value so it can be retrieved by
+     * {@link #getParcelableResult()}.
+     */
+    @NonNull
+    public static Bundle bundleFor(@Nullable Parcelable value) {
+        final Bundle bundle = new Bundle();
+        bundle.putParcelable(EXTRA, value);
+        return bundle;
+    }
+
+    /** @hide */
+    public static final class TimeoutException extends RemoteException {
+        private TimeoutException(String msg) {
+            super(msg);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 70f4ed2..0752efe 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -17,7 +17,6 @@
 package com.android.internal.view;
 
 import android.os.ResultReceiver;
-import android.text.style.SuggestionSpan;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
 import android.view.inputmethod.EditorInfo;
@@ -36,7 +35,6 @@
 
     // TODO: Use ParceledListSlice instead
     List<InputMethodInfo> getInputMethodList();
-    List<InputMethodInfo> getVrInputMethodList();
     // TODO: Use ParceledListSlice instead
     List<InputMethodInfo> getEnabledInputMethodList();
     List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in String imiId,
@@ -65,10 +63,7 @@
             int displayId);
     void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
     boolean isInputMethodPickerShownForTest();
-    void registerSuggestionSpansForNotification(in SuggestionSpan[] spans);
-    boolean notifySuggestionPicked(in SuggestionSpan span, String originalString, int index);
     InputMethodSubtype getCurrentInputMethodSubtype();
-    boolean setCurrentInputMethodSubtype(in InputMethodSubtype subtype);
     void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
     // This is kept due to @UnsupportedAppUsage.
     // TODO(Bug 113914148): Consider removing this.
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index 901cfe3..9fe49b4 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -127,8 +127,10 @@
          */
         int ERROR_IME_NOT_CONNECTED = 8;
         /**
-         * Indicates that the caller is not the foreground user (or does not have
-         * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission).
+         * Indicates that the caller is not the foreground user, does not have
+         * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission, or the user
+         * specified in {@link android.view.inputmethod.EditorInfo#targetInputMethodUser} is not
+         * running.
          */
         int ERROR_INVALID_USER = 9;
         /**
diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java
index b419113..21558d3 100644
--- a/core/java/com/android/internal/widget/DecorCaptionView.java
+++ b/core/java/com/android/internal/widget/DecorCaptionView.java
@@ -319,23 +319,12 @@
         mOwner.notifyRestrictedCaptionAreaCallback(mMaximize.getLeft(), mMaximize.getTop(),
                 mClose.getRight(), mClose.getBottom());
     }
-    /**
-     * Determine if the workspace is entirely covered by the window.
-     * @return Returns true when the window is filling the entire screen/workspace.
-     **/
-    private boolean isFillingScreen() {
-        return (0 != ((getWindowSystemUiVisibility() | getSystemUiVisibility()) &
-                (View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
-                        View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_LOW_PROFILE)));
-    }
 
     /**
      * Updates the visibility of the caption.
      **/
     private void updateCaptionVisibility() {
-        // Don't show the caption if the window has e.g. entered full screen.
-        boolean invisible = isFillingScreen() || !mShow;
-        mCaption.setVisibility(invisible ? GONE : VISIBLE);
+        mCaption.setVisibility(mShow ? VISIBLE : GONE);
         mCaption.setOnTouchListener(this);
     }
 
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index 7f7528d..78688ed 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -18,9 +18,7 @@
 
 import android.os.Bundle;
 import android.text.Editable;
-import android.text.Spanned;
 import android.text.method.KeyListener;
-import android.text.style.SuggestionSpan;
 import android.util.Log;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.CompletionInfo;
@@ -173,12 +171,6 @@
         if (mTextView == null) {
             return super.commitText(text, newCursorPosition);
         }
-        if (text instanceof Spanned) {
-            Spanned spanned = ((Spanned) text);
-            SuggestionSpan[] spans = spanned.getSpans(0, text.length(), SuggestionSpan.class);
-            mIMM.registerSuggestionSpansForNotification(spans);
-        }
-
         mTextView.resetErrorChangedFlag();
         boolean success = super.commitText(text, newCursorPosition);
         mTextView.hideErrorIfUnchanged();
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 591f15f..9a77802 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -62,7 +62,9 @@
             in byte[] recoveryServiceCertFile, in byte[] recoveryServiceSigFile);
     KeyChainSnapshot getKeyChainSnapshot();
     String generateKey(String alias);
+    String generateKeyWithMetadata(String alias, in byte[] metadata);
     String importKey(String alias, in byte[] keyBytes);
+    String importKeyWithMetadata(String alias, in byte[] keyBytes, in byte[] metadata);
     String getKey(String alias);
     void removeKey(String alias);
     void setSnapshotCreatedPendingIntent(in PendingIntent intent);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index d5dc703..8d3c482 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -34,6 +34,7 @@
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.os.AsyncTask;
 import android.os.Handler;
@@ -176,6 +177,7 @@
     private UserManager mUserManager;
     private final Handler mHandler;
     private final SparseLongArray mLockoutDeadlines = new SparseLongArray();
+    private Boolean mHasSecureLockScreen;
 
     /**
      * Use {@link TrustManager#isTrustUsuallyManaged(int)}.
@@ -706,6 +708,10 @@
      * @param userId the user whose pattern is to be saved.
      */
     public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
+        if (!hasSecureLockScreen()) {
+            throw new UnsupportedOperationException(
+                    "This operation requires the lock screen feature.");
+        }
         if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
             throw new IllegalArgumentException("pattern must not be null and at least "
                     + MIN_LOCK_PATTERN_SIZE + " dots long.");
@@ -801,6 +807,10 @@
 
     /** Update the encryption password if it is enabled **/
     private void updateEncryptionPassword(final int type, final String password) {
+        if (!hasSecureLockScreen()) {
+            throw new UnsupportedOperationException(
+                    "This operation requires the lock screen feature.");
+        }
         if (!isDeviceEncryptionEnabled()) {
             return;
         }
@@ -835,6 +845,10 @@
      */
     public void saveLockPassword(String password, String savedPassword, int requestedQuality,
             int userHandle) {
+        if (!hasSecureLockScreen()) {
+            throw new UnsupportedOperationException(
+                    "This operation requires the lock screen feature.");
+        }
         if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
             throw new IllegalArgumentException("password must not be null and at least "
                     + "of length " + MIN_LOCK_PASSWORD_SIZE);
@@ -1621,6 +1635,10 @@
      */
     public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality,
             long tokenHandle, byte[] token, int userId) {
+        if (!hasSecureLockScreen()) {
+            throw new UnsupportedOperationException(
+                    "This operation requires the lock screen feature.");
+        }
         LockSettingsInternal localService = getLockSettingsInternal();
         if (type != CREDENTIAL_TYPE_NONE) {
             if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
@@ -1854,6 +1872,17 @@
         return getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM) != 0;
     }
 
+    /**
+     * Return true if the device supports the lock screen feature, false otherwise.
+     */
+    public boolean hasSecureLockScreen() {
+        if (mHasSecureLockScreen == null) {
+            mHasSecureLockScreen = Boolean.valueOf(mContext.getPackageManager()
+                    .hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN));
+        }
+        return mHasSecureLockScreen.booleanValue();
+    }
+
     public static boolean userOwnsFrpCredential(Context context, UserInfo info) {
         return info != null && info.isPrimary() && info.isAdmin() && frpCredentialEnabled(context);
     }
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 841e5b6..3537465 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -140,6 +140,10 @@
     // without throttling, as read from the configuration files.
     final ArraySet<String> mAllowUnthrottledLocation = new ArraySet<>();
 
+    // These are the packages that are white-listed to be able to retrieve location even when user
+    // location settings are off, for emergency purposes, as read from the configuration files.
+    final ArraySet<String> mAllowIgnoreLocationSettings = new ArraySet<>();
+
     // These are the action strings of broadcasts which are whitelisted to
     // be delivered anonymously even to apps which target O+.
     final ArraySet<String> mAllowImplicitBroadcasts = new ArraySet<>();
@@ -255,6 +259,10 @@
         return mAllowUnthrottledLocation;
     }
 
+    public ArraySet<String> getAllowIgnoreLocationSettings() {
+        return mAllowIgnoreLocationSettings;
+    }
+
     public ArraySet<String> getLinkedApps() {
         return mLinkedApps;
     }
@@ -682,6 +690,20 @@
                         }
                         XmlUtils.skipCurrentTag(parser);
                     } break;
+                    case "allow-ignore-location-settings": {
+                        if (allowAll) {
+                            String pkgname = parser.getAttributeValue(null, "package");
+                            if (pkgname == null) {
+                                Slog.w(TAG, "<" + name + "> without package in "
+                                        + permFile + " at " + parser.getPositionDescription());
+                            } else {
+                                mAllowIgnoreLocationSettings.add(pkgname);
+                            }
+                        } else {
+                            logNotAllowedInPartition(name, permFile, parser);
+                        }
+                        XmlUtils.skipCurrentTag(parser);
+                    } break;
                     case "allow-implicit-broadcast": {
                         if (allowAll) {
                             String action = parser.getAttributeValue(null, "action");
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index dc6a73a..be12700 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -41,7 +41,7 @@
         "com_google_android_gles_jni_EGLImpl.cpp",
         "com_google_android_gles_jni_GLImpl.cpp", // TODO: .arm
         "android_app_Activity.cpp",
-	"android_app_ActivityThread.cpp",
+        "android_app_ActivityThread.cpp",
         "android_app_NativeActivity.cpp",
         "android_app_admin_SecurityLog.cpp",
         "android_opengl_EGL14.cpp",
@@ -61,8 +61,11 @@
         "android_database_SQLiteConnection.cpp",
         "android_database_SQLiteGlobal.cpp",
         "android_database_SQLiteDebug.cpp",
+        "android_graphics_Canvas.cpp",
+        "android_graphics_ColorSpace.cpp",
         "android_graphics_drawable_AnimatedVectorDrawable.cpp",
         "android_graphics_drawable_VectorDrawable.cpp",
+        "android_graphics_Picture.cpp",
         "android_view_DisplayEventReceiver.cpp",
         "android_view_DisplayListCanvas.cpp",
         "android_view_TextureLayer.cpp",
@@ -117,8 +120,6 @@
         "android_util_StringBlock.cpp",
         "android_util_XmlBlock.cpp",
         "android_util_jar_StrictJarFile.cpp",
-        "android_graphics_Canvas.cpp",
-        "android_graphics_Picture.cpp",
         "android/graphics/AnimatedImageDrawable.cpp",
         "android/graphics/Bitmap.cpp",
         "android/graphics/BitmapFactory.cpp",
@@ -202,6 +203,7 @@
         "android_animation_PropertyValuesHolder.cpp",
         "android_security_Scrypt.cpp",
         "com_android_internal_net_NetworkStatsFactory.cpp",
+        "com_android_internal_os_AtomicDirectory.cpp",
         "com_android_internal_os_ClassLoaderFactory.cpp",
         "com_android_internal_os_FuseAppLoop.cpp",
         "com_android_internal_os_Zygote.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 687b105..f458299 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -131,6 +131,7 @@
 extern int register_android_graphics_Canvas(JNIEnv* env);
 extern int register_android_graphics_CanvasProperty(JNIEnv* env);
 extern int register_android_graphics_ColorFilter(JNIEnv* env);
+extern int register_android_graphics_ColorSpace(JNIEnv* env);
 extern int register_android_graphics_DrawFilter(JNIEnv* env);
 extern int register_android_graphics_FontFamily(JNIEnv* env);
 extern int register_android_graphics_Matrix(JNIEnv* env);
@@ -151,6 +152,8 @@
 extern int register_android_graphics_text_LineBreaker(JNIEnv *env);
 extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
 extern int register_android_view_DisplayListCanvas(JNIEnv* env);
+extern int register_android_view_InputApplicationHandle(JNIEnv* env);
+extern int register_android_view_InputWindowHandle(JNIEnv* env);
 extern int register_android_view_TextureLayer(JNIEnv* env);
 extern int register_android_view_RenderNode(JNIEnv* env);
 extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
@@ -218,6 +221,7 @@
 extern int register_android_security_Scrypt(JNIEnv *env);
 extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
 extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
+extern int register_com_android_internal_os_AtomicDirectory(JNIEnv *env);
 extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
 extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
 extern int register_com_android_internal_os_Zygote(JNIEnv *env);
@@ -1360,11 +1364,16 @@
     REG_JNI(register_android_os_VintfRuntimeInfo),
     REG_JNI(register_android_nio_utils),
     REG_JNI(register_android_graphics_Canvas),
+    // This needs to be before register_android_graphics_Graphics, or the latter
+    // will not be able to find the jmethodID for ColorSpace.get().
+    REG_JNI(register_android_graphics_ColorSpace),
     REG_JNI(register_android_graphics_Graphics),
     REG_JNI(register_android_view_DisplayEventReceiver),
     REG_JNI(register_android_view_RenderNode),
     REG_JNI(register_android_view_RenderNodeAnimator),
     REG_JNI(register_android_view_DisplayListCanvas),
+    REG_JNI(register_android_view_InputApplicationHandle),
+    REG_JNI(register_android_view_InputWindowHandle),
     REG_JNI(register_android_view_TextureLayer),
     REG_JNI(register_android_view_ThreadedRenderer),
     REG_JNI(register_android_view_Surface),
@@ -1495,6 +1504,7 @@
     REG_JNI(register_android_security_Scrypt),
     REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
     REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
+    REG_JNI(register_com_android_internal_os_AtomicDirectory),
     REG_JNI(register_com_android_internal_os_FuseAppLoop),
 };
 
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index eb7338a..ad51c47 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -8,7 +8,6 @@
 #include "SkImageInfo.h"
 #include "SkColor.h"
 #include "SkColorSpace.h"
-#include "SkMatrix44.h"
 #include "GraphicsJNI.h"
 #include "SkStream.h"
 
@@ -335,7 +334,7 @@
 static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
                               jint offset, jint stride, jint width, jint height,
                               jint configHandle, jboolean isMutable,
-                              jfloatArray xyzD50, jobject transferParameters) {
+                              jlong colorSpacePtr) {
     SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
     if (NULL != jColors) {
         size_t n = env->GetArrayLength(jColors);
@@ -351,17 +350,8 @@
     }
 
     SkBitmap bitmap;
-    sk_sp<SkColorSpace> colorSpace;
-
-    if (xyzD50 == nullptr || transferParameters == nullptr) {
-        colorSpace = SkColorSpace::MakeSRGB();
-    } else {
-        SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
-        SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
-        colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
-    }
-
-    bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType, colorSpace));
+    bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType,
+                GraphicsJNI::getNativeColorSpace(colorSpacePtr)));
 
     sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap);
     if (!nativeBitmap) {
@@ -549,8 +539,7 @@
     if (skbitmap.colorType() == kRGBA_F16_SkColorType) {
         // Convert to P3 before encoding. This matches SkAndroidCodec::computeOutputColorSpace
         // for wide gamuts.
-        auto cs = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
-                                        SkColorSpace::kDCIP3_D65_Gamut);
+        auto cs = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
         auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType)
                                    .makeColorSpace(std::move(cs));
         SkBitmap p3;
@@ -568,11 +557,31 @@
     return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE;
 }
 
+static inline void bitmapErase(SkBitmap bitmap, const SkColor4f& color,
+        const sk_sp<SkColorSpace>& colorSpace) {
+    SkPaint p;
+    p.setColor4f(color, colorSpace.get());
+    p.setBlendMode(SkBlendMode::kSrc);
+    SkCanvas canvas(bitmap);
+    canvas.drawPaint(p);
+}
+
 static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
     LocalScopedBitmap bitmap(bitmapHandle);
     SkBitmap skBitmap;
     bitmap->getSkBitmap(&skBitmap);
-    skBitmap.eraseColor(color);
+    bitmapErase(skBitmap, SkColor4f::FromColor(color), SkColorSpace::MakeSRGB());
+}
+
+static void Bitmap_eraseLong(JNIEnv* env, jobject, jlong bitmapHandle,
+        jlong colorSpaceHandle, jlong colorLong) {
+    LocalScopedBitmap bitmap(bitmapHandle);
+    SkBitmap skBitmap;
+    bitmap->getSkBitmap(&skBitmap);
+
+    SkColor4f color = GraphicsJNI::convertColorLong(colorLong);
+    sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
+    bitmapErase(skBitmap, color, cs);
 }
 
 static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
@@ -717,7 +726,7 @@
 #endif
         // Dup the file descriptor so we can keep a reference to it after the Parcel
         // is disposed.
-        int dupFd = dup(blob.fd());
+        int dupFd = fcntl(blob.fd(), F_DUPFD_CLOEXEC, 0);
         if (dupFd < 0) {
             ALOGE("Error allocating dup fd. Error:%d", errno);
             blob.release();
@@ -910,32 +919,32 @@
     SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
     if (colorSpace == nullptr) return JNI_FALSE;
 
-    SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
+    skcms_Matrix3x3 xyzMatrix;
     if (!colorSpace->toXYZD50(&xyzMatrix)) return JNI_FALSE;
 
     jfloat* xyz = env->GetFloatArrayElements(xyzArray, NULL);
-    xyz[0] = xyzMatrix.getFloat(0, 0);
-    xyz[1] = xyzMatrix.getFloat(1, 0);
-    xyz[2] = xyzMatrix.getFloat(2, 0);
-    xyz[3] = xyzMatrix.getFloat(0, 1);
-    xyz[4] = xyzMatrix.getFloat(1, 1);
-    xyz[5] = xyzMatrix.getFloat(2, 1);
-    xyz[6] = xyzMatrix.getFloat(0, 2);
-    xyz[7] = xyzMatrix.getFloat(1, 2);
-    xyz[8] = xyzMatrix.getFloat(2, 2);
+    xyz[0] = xyzMatrix.vals[0][0];
+    xyz[1] = xyzMatrix.vals[1][0];
+    xyz[2] = xyzMatrix.vals[2][0];
+    xyz[3] = xyzMatrix.vals[0][1];
+    xyz[4] = xyzMatrix.vals[1][1];
+    xyz[5] = xyzMatrix.vals[2][1];
+    xyz[6] = xyzMatrix.vals[0][2];
+    xyz[7] = xyzMatrix.vals[1][2];
+    xyz[8] = xyzMatrix.vals[2][2];
     env->ReleaseFloatArrayElements(xyzArray, xyz, 0);
 
-    SkColorSpaceTransferFn transferParams;
+    skcms_TransferFunction transferParams;
     if (!colorSpace->isNumericalTransferFn(&transferParams)) return JNI_FALSE;
 
     jfloat* params = env->GetFloatArrayElements(paramsArray, NULL);
-    params[0] = transferParams.fA;
-    params[1] = transferParams.fB;
-    params[2] = transferParams.fC;
-    params[3] = transferParams.fD;
-    params[4] = transferParams.fE;
-    params[5] = transferParams.fF;
-    params[6] = transferParams.fG;
+    params[0] = transferParams.a;
+    params[1] = transferParams.b;
+    params[2] = transferParams.c;
+    params[3] = transferParams.d;
+    params[4] = transferParams.e;
+    params[5] = transferParams.f;
+    params[6] = transferParams.g;
     env->ReleaseFloatArrayElements(paramsArray, params, 0);
 
     return JNI_TRUE;
@@ -1120,14 +1129,12 @@
 }
 
 static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject hardwareBuffer,
-                                               jfloatArray xyzD50, jobject transferParameters) {
-    SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
-    SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
-    sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
+                                               jlong colorSpacePtr) {
     AHardwareBuffer* hwBuf = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env,
         hardwareBuffer);
     sp<GraphicBuffer> buffer(AHardwareBuffer_to_GraphicBuffer(hwBuf));
-    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, colorSpace);
+    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer,
+            GraphicsJNI::getNativeColorSpace(colorSpacePtr));
     if (!bitmap.get()) {
         ALOGW("failed to create hardware bitmap from hardware buffer");
         return NULL;
@@ -1169,7 +1176,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 static const JNINativeMethod gBitmapMethods[] = {
-    {   "nativeCreate",             "([IIIIIIZ[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;",
+    {   "nativeCreate",             "([IIIIIIZJ)Landroid/graphics/Bitmap;",
         (void*)Bitmap_creator },
     {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
         (void*)Bitmap_copy },
@@ -1183,6 +1190,7 @@
     {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
         (void*)Bitmap_compress },
     {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },
+    {   "nativeErase",              "(JJJ)V", (void*)Bitmap_eraseLong },
     {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
     {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
     {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
@@ -1214,7 +1222,7 @@
         (void*)Bitmap_copyPreserveInternalConfig },
     {   "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;",
         (void*) Bitmap_createHardwareBitmap },
-    {   "nativeWrapHardwareBufferBitmap", "(Landroid/hardware/HardwareBuffer;[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;",
+    {   "nativeWrapHardwareBufferBitmap", "(Landroid/hardware/HardwareBuffer;J)Landroid/graphics/Bitmap;",
         (void*) Bitmap_wrapHardwareBufferBitmap },
     {   "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
         (void*) Bitmap_createGraphicBufferHandle },
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 9ae05f4..7d0d3d8 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -179,7 +179,7 @@
 }
 
 static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream,
-                        jobject padding, jobject options) {
+                        jobject padding, jobject options, jlong colorSpaceHandle) {
     // Set default values for the options parameters.
     int sampleSize = 1;
     bool onlyDecodeSize = false;
@@ -189,7 +189,7 @@
     float scale = 1.0f;
     bool requireUnpremultiplied = false;
     jobject javaBitmap = NULL;
-    sk_sp<SkColorSpace> prefColorSpace = nullptr;
+    sk_sp<SkColorSpace> prefColorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
 
     // Update with options supplied by the client.
     if (options != NULL) {
@@ -213,8 +213,6 @@
 
         jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
         prefColorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
-        jobject jcolorSpace = env->GetObjectField(options, gOptions_colorSpaceFieldID);
-        prefColorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace);
         isHardware = GraphicsJNI::isHardwareConfig(env, jconfig);
         isMutable = env->GetBooleanField(options, gOptions_mutableFieldID);
         requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
@@ -231,7 +229,7 @@
     }
 
     if (isMutable && isHardware) {
-        doThrowIAE(env, "Bitmaps with Config.HARWARE are always immutable");
+        doThrowIAE(env, "Bitmaps with Config.HARDWARE are always immutable");
         return nullObjectReturn("Cannot create mutable hardware bitmap");
     }
 
@@ -515,7 +513,7 @@
 }
 
 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
-        jobject padding, jobject options) {
+        jobject padding, jobject options, jlong colorSpaceHandle) {
 
     jobject bitmap = NULL;
     std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
@@ -524,13 +522,13 @@
         std::unique_ptr<SkStreamRewindable> bufferedStream(
                 SkFrontBufferedStream::Make(std::move(stream), SkCodec::MinBufferedBytesNeeded()));
         SkASSERT(bufferedStream.get() != NULL);
-        bitmap = doDecode(env, std::move(bufferedStream), padding, options);
+        bitmap = doDecode(env, std::move(bufferedStream), padding, options, colorSpaceHandle);
     }
     return bitmap;
 }
 
 static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor,
-        jobject padding, jobject bitmapFactoryOptions) {
+        jobject padding, jobject bitmapFactoryOptions, jlong colorSpaceHandle) {
 
     NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
 
@@ -566,7 +564,8 @@
     // If there is no offset for the file descriptor, we use SkFILEStream directly.
     if (::lseek(descriptor, 0, SEEK_CUR) == 0) {
         assert(isSeekable(dupDescriptor));
-        return doDecode(env, std::move(fileStream), padding, bitmapFactoryOptions);
+        return doDecode(env, std::move(fileStream), padding, bitmapFactoryOptions,
+                colorSpaceHandle);
     }
 
     // Use a buffered stream. Although an SkFILEStream can be rewound, this
@@ -575,24 +574,25 @@
     std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Make(std::move(fileStream),
             SkCodec::MinBufferedBytesNeeded()));
 
-    return doDecode(env, std::move(stream), padding, bitmapFactoryOptions);
+    return doDecode(env, std::move(stream), padding, bitmapFactoryOptions, colorSpaceHandle);
 }
 
 static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset,
-        jobject padding, jobject options) {
+        jobject padding, jobject options, jlong colorSpaceHandle) {
 
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
     // since we know we'll be done with the asset when we return, we can
     // just use a simple wrapper
-    return doDecode(env, skstd::make_unique<AssetStreamAdaptor>(asset), padding, options);
+    return doDecode(env, skstd::make_unique<AssetStreamAdaptor>(asset), padding, options,
+            colorSpaceHandle);
 }
 
 static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
-        jint offset, jint length, jobject options) {
+        jint offset, jint length, jobject options, jlong colorSpaceHandle) {
 
     AutoJavaByteArray ar(env, byteArray);
     return doDecode(env, skstd::make_unique<SkMemoryStream>(ar.ptr() + offset, length, false),
-                    nullptr, options);
+                    nullptr, options, colorSpaceHandle);
 }
 
 static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
@@ -600,31 +600,26 @@
     return isSeekable(descriptor) ? JNI_TRUE : JNI_FALSE;
 }
 
-jobject decodeBitmap(JNIEnv* env, void* data, size_t size) {
-    return doDecode(env, skstd::make_unique<SkMemoryStream>(data, size),
-                    nullptr, nullptr);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static const JNINativeMethod gMethods[] = {
     {   "nativeDecodeStream",
-        "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
+        "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;J)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeStream
     },
 
     {   "nativeDecodeFileDescriptor",
-        "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
+        "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;J)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeFileDescriptor
     },
 
     {   "nativeDecodeAsset",
-        "(JLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
+        "(JLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;J)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeAsset
     },
 
     {   "nativeDecodeByteArray",
-        "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
+        "([BIILandroid/graphics/BitmapFactory$Options;J)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeByteArray
     },
 
diff --git a/core/jni/android/graphics/BitmapFactory.h b/core/jni/android/graphics/BitmapFactory.h
index 1ee49fa..e37c98d 100644
--- a/core/jni/android/graphics/BitmapFactory.h
+++ b/core/jni/android/graphics/BitmapFactory.h
@@ -28,6 +28,4 @@
 
 jstring encodedFormatToString(JNIEnv* env, SkEncodedImageFormat format);
 
-jobject decodeBitmap(JNIEnv* env, void* data, size_t size);
-
 #endif  // _ANDROID_GRAPHICS_BITMAP_FACTORY_H_
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index f831c05..b4ba749 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -124,7 +124,7 @@
  * reportSizeToVM not supported
  */
 static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint inputX,
-        jint inputY, jint inputWidth, jint inputHeight, jobject options) {
+        jint inputY, jint inputWidth, jint inputHeight, jobject options, jlong colorSpaceHandle) {
 
     // Set default options.
     int sampleSize = 1;
@@ -132,14 +132,12 @@
     bool requireUnpremul = false;
     jobject javaBitmap = NULL;
     bool isHardware = false;
-    sk_sp<SkColorSpace> colorSpace = nullptr;
+    sk_sp<SkColorSpace> colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
     // Update the default options with any options supplied by the client.
     if (NULL != options) {
         sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
         jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
         colorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
-        jobject jcolorSpace = env->GetObjectField(options, gOptions_colorSpaceFieldID);
-        colorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace);
         isHardware = GraphicsJNI::isHardwareConfig(env, jconfig);
         requireUnpremul = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
         javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
@@ -255,7 +253,7 @@
 
 static const JNINativeMethod gBitmapRegionDecoderMethods[] = {
     {   "nativeDecodeRegion",
-        "(JIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
+        "(JIIIILandroid/graphics/BitmapFactory$Options;J)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeRegion},
 
     {   "nativeGetHeight", "(J)I", (void*)nativeGetHeight},
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 67d0c8a..6570992 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -178,23 +178,11 @@
 static jmethodID gVMRuntime_newNonMovableArray;
 static jmethodID gVMRuntime_addressOf;
 
-static jfieldID gTransferParams_aFieldID;
-static jfieldID gTransferParams_bFieldID;
-static jfieldID gTransferParams_cFieldID;
-static jfieldID gTransferParams_dFieldID;
-static jfieldID gTransferParams_eFieldID;
-static jfieldID gTransferParams_fFieldID;
-static jfieldID gTransferParams_gFieldID;
-
 static jclass gColorSpace_class;
-static jfieldID gColorSpace_IlluminantD50FieldID;
-static jmethodID gColorSpace_adaptMethodID;
 static jmethodID gColorSpace_getMethodID;
 static jmethodID gColorSpace_matchMethodID;
 
 static jclass gColorSpaceRGB_class;
-static jmethodID gColorSpaceRGB_getTransferParametersMethodID;
-static jmethodID gColorSpaceRGB_getTransformMethodID;
 static jmethodID gColorSpaceRGB_constructorMethodID;
 
 static jclass gColorSpace_Named_class;
@@ -424,61 +412,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkColorSpaceTransferFn GraphicsJNI::getNativeTransferParameters(JNIEnv* env, jobject transferParams) {
-    SkColorSpaceTransferFn p;
-    p.fA = (float) env->GetDoubleField(transferParams, gTransferParams_aFieldID);
-    p.fB = (float) env->GetDoubleField(transferParams, gTransferParams_bFieldID);
-    p.fC = (float) env->GetDoubleField(transferParams, gTransferParams_cFieldID);
-    p.fD = (float) env->GetDoubleField(transferParams, gTransferParams_dFieldID);
-    p.fE = (float) env->GetDoubleField(transferParams, gTransferParams_eFieldID);
-    p.fF = (float) env->GetDoubleField(transferParams, gTransferParams_fFieldID);
-    p.fG = (float) env->GetDoubleField(transferParams, gTransferParams_gFieldID);
-    return p;
-}
-
-SkMatrix44 GraphicsJNI::getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50) {
-    SkMatrix44 xyzMatrix(SkMatrix44::kIdentity_Constructor);
-    jfloat* array = env->GetFloatArrayElements(xyzD50, NULL);
-    xyzMatrix.setFloat(0, 0, array[0]);
-    xyzMatrix.setFloat(1, 0, array[1]);
-    xyzMatrix.setFloat(2, 0, array[2]);
-    xyzMatrix.setFloat(0, 1, array[3]);
-    xyzMatrix.setFloat(1, 1, array[4]);
-    xyzMatrix.setFloat(2, 1, array[5]);
-    xyzMatrix.setFloat(0, 2, array[6]);
-    xyzMatrix.setFloat(1, 2, array[7]);
-    xyzMatrix.setFloat(2, 2, array[8]);
-    env->ReleaseFloatArrayElements(xyzD50, array, 0);
-    return xyzMatrix;
-}
-
-sk_sp<SkColorSpace> GraphicsJNI::getNativeColorSpace(JNIEnv* env, jobject colorSpace) {
-    if (colorSpace == nullptr) return nullptr;
-    if (!env->IsInstanceOf(colorSpace, gColorSpaceRGB_class)) {
-        doThrowIAE(env, "The color space must be an RGB color space");
-    }
-
-    jobject transferParams = env->CallObjectMethod(colorSpace,
-            gColorSpaceRGB_getTransferParametersMethodID);
-    if (transferParams == nullptr) {
-        doThrowIAE(env, "The color space must use an ICC parametric transfer function");
-    }
-
-    jfloatArray illuminantD50 = (jfloatArray) env->GetStaticObjectField(gColorSpace_class,
-            gColorSpace_IlluminantD50FieldID);
-    jobject colorSpaceD50 = env->CallStaticObjectMethod(gColorSpace_class,
-            gColorSpace_adaptMethodID, colorSpace, illuminantD50);
-
-    jfloatArray xyzD50 = (jfloatArray) env->CallObjectMethod(colorSpaceD50,
-            gColorSpaceRGB_getTransformMethodID);
-
-    SkMatrix44 xyzMatrix = getNativeXYZMatrix(env, xyzD50);
-    SkColorSpaceTransferFn transferFunction = getNativeTransferParameters(env, transferParams);
-
-    return SkColorSpace::MakeRGB(transferFunction, xyzMatrix);
-}
-
-
 jobject GraphicsJNI::getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColorSpace,
         SkColorType decodeColorType) {
     jobject colorSpace = nullptr;
@@ -499,30 +432,30 @@
         } else if (decodeColorSpace.get() != nullptr) {
             // Try to match against known RGB color spaces using the CIE XYZ D50
             // conversion matrix and numerical transfer function parameters
-            SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
+            skcms_Matrix3x3 xyzMatrix;
             LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix));
 
-            SkColorSpaceTransferFn transferParams;
+            skcms_TransferFunction transferParams;
             // We can only handle numerical transfer functions at the moment
             LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams));
 
             jobject params = env->NewObject(gTransferParameters_class,
                     gTransferParameters_constructorMethodID,
-                    transferParams.fA, transferParams.fB, transferParams.fC,
-                    transferParams.fD, transferParams.fE, transferParams.fF,
-                    transferParams.fG);
+                    transferParams.a, transferParams.b, transferParams.c,
+                    transferParams.d, transferParams.e, transferParams.f,
+                    transferParams.g);
 
             jfloatArray xyzArray = env->NewFloatArray(9);
             jfloat xyz[9] = {
-                    xyzMatrix.getFloat(0, 0),
-                    xyzMatrix.getFloat(1, 0),
-                    xyzMatrix.getFloat(2, 0),
-                    xyzMatrix.getFloat(0, 1),
-                    xyzMatrix.getFloat(1, 1),
-                    xyzMatrix.getFloat(2, 1),
-                    xyzMatrix.getFloat(0, 2),
-                    xyzMatrix.getFloat(1, 2),
-                    xyzMatrix.getFloat(2, 2)
+                    xyzMatrix.vals[0][0],
+                    xyzMatrix.vals[1][0],
+                    xyzMatrix.vals[2][0],
+                    xyzMatrix.vals[0][1],
+                    xyzMatrix.vals[1][1],
+                    xyzMatrix.vals[2][1],
+                    xyzMatrix.vals[0][2],
+                    xyzMatrix.vals[1][2],
+                    xyzMatrix.vals[2][2]
             };
             env->SetFloatArrayRegion(xyzArray, 0, 9, xyz);
 
@@ -710,20 +643,7 @@
                                                      "(Ljava/lang/Class;I)Ljava/lang/Object;");
     gVMRuntime_addressOf = GetMethodIDOrDie(env, gVMRuntime_class, "addressOf", "(Ljava/lang/Object;)J");
 
-    jclass transfer_params_class = FindClassOrDie(env, "android/graphics/ColorSpace$Rgb$TransferParameters");
-    gTransferParams_aFieldID = GetFieldIDOrDie(env, transfer_params_class, "a", "D");
-    gTransferParams_bFieldID = GetFieldIDOrDie(env, transfer_params_class, "b", "D");
-    gTransferParams_cFieldID = GetFieldIDOrDie(env, transfer_params_class, "c", "D");
-    gTransferParams_dFieldID = GetFieldIDOrDie(env, transfer_params_class, "d", "D");
-    gTransferParams_eFieldID = GetFieldIDOrDie(env, transfer_params_class, "e", "D");
-    gTransferParams_fFieldID = GetFieldIDOrDie(env, transfer_params_class, "f", "D");
-    gTransferParams_gFieldID = GetFieldIDOrDie(env, transfer_params_class, "g", "D");
-
     gColorSpace_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ColorSpace"));
-    gColorSpace_IlluminantD50FieldID = GetStaticFieldIDOrDie(env,
-            gColorSpace_class, "ILLUMINANT_D50", "[F");
-    gColorSpace_adaptMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "adapt",
-            "(Landroid/graphics/ColorSpace;[F)Landroid/graphics/ColorSpace;");
     gColorSpace_getMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class,
             "get", "(Landroid/graphics/ColorSpace$Named;)Landroid/graphics/ColorSpace;");
     gColorSpace_matchMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "match",
@@ -733,10 +653,6 @@
             FindClassOrDie(env, "android/graphics/ColorSpace$Rgb"));
     gColorSpaceRGB_constructorMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class,
             "<init>", "(Ljava/lang/String;[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)V");
-    gColorSpaceRGB_getTransferParametersMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class,
-            "getTransferParameters", "()Landroid/graphics/ColorSpace$Rgb$TransferParameters;");
-    gColorSpaceRGB_getTransformMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class,
-            "getTransform", "()[F");
 
     gColorSpace_Named_class = MakeGlobalRefOrDie(env,
             FindClassOrDie(env, "android/graphics/ColorSpace$Named"));
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index b0bd683..dc0d022 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -10,7 +10,6 @@
 #include "SkPoint.h"
 #include "SkRect.h"
 #include "SkColorSpace.h"
-#include "SkMatrix44.h"
 #include <jni.h>
 #include <hwui/Canvas.h>
 #include <hwui/Bitmap.h>
@@ -101,12 +100,27 @@
             int srcStride, int x, int y, int width, int height,
             SkBitmap* dstBitmap);
 
-    static SkColorSpaceTransferFn getNativeTransferParameters(JNIEnv* env, jobject transferParams);
-    static SkMatrix44 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50);
-    static sk_sp<SkColorSpace> getNativeColorSpace(JNIEnv* env, jobject colorSpace);
+    /**
+     * Convert the native SkColorSpace retrieved from ColorSpace.Rgb.getNativeInstance().
+     *
+     * This will never throw an Exception. If the ColorSpace is one that Skia cannot
+     * use, ColorSpace.Rgb.getNativeInstance() would have thrown an Exception. It may,
+     * however, be nullptr, which may be acceptable.
+     */
+    static sk_sp<SkColorSpace> getNativeColorSpace(jlong colorSpaceHandle);
 
     static jobject getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColorSpace,
             SkColorType decodeColorType);
+
+    /**
+     * Convert from a Java @ColorLong to an SkColor4f that Skia can use directly.
+     *
+     * This ignores the encoded ColorSpace, besides checking to see if it is sRGB,
+     * which is encoded differently. The color space should be passed down separately
+     * via ColorSpace#getNativeInstance(), and converted with getNativeColorSpace(),
+     * above.
+     */
+    static SkColor4f convertColorLong(jlong color);
 };
 
 class HeapAllocator : public SkBRDAllocator {
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index df735ae..5f12665 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -202,7 +202,7 @@
                                           jint desiredWidth, jint desiredHeight, jobject jsubset,
                                           jboolean requireMutable, jint allocator,
                                           jboolean requireUnpremul, jboolean preferRamOverQuality,
-                                          jboolean asAlphaMask, jobject jcolorSpace) {
+                                          jboolean asAlphaMask, jlong colorSpaceHandle) {
     auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
     SkAndroidCodec* codec = decoder->mCodec.get();
     const SkISize desiredSize = SkISize::Make(desiredWidth, desiredHeight);
@@ -256,7 +256,7 @@
         // This is currently the only way to know that we should decode to F16.
         colorType = codec->computeOutputColorType(colorType);
     }
-    sk_sp<SkColorSpace> colorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace);
+    sk_sp<SkColorSpace> colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
     colorSpace = codec->computeOutputColorSpace(colorType, colorSpace);
     decodeInfo = decodeInfo.makeColorType(colorType).makeColorSpace(colorSpace);
 
@@ -508,7 +508,7 @@
     { "nCreate",        "([BIILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
     { "nCreate",        "(Ljava/io/InputStream;[BLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
     { "nCreate",        "(Ljava/io/FileDescriptor;Landroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
-    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZLandroid/graphics/ColorSpace;)Landroid/graphics/Bitmap;",
+    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZJ)Landroid/graphics/Bitmap;",
                                                                  (void*) ImageDecoder_nDecodeBitmap },
     { "nGetSampledSize","(JI)Landroid/util/Size;",               (void*) ImageDecoder_nGetSampledSize },
     { "nGetPadding",    "(JLandroid/graphics/Rect;)V",           (void*) ImageDecoder_nGetPadding },
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index e97c9bc..7679c5b 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -752,20 +752,11 @@
         obj->setStyle(style);
     }
 
-    static jint getColor(jlong paintHandle) {
-        int color;
-        color = reinterpret_cast<Paint*>(paintHandle)->getColor();
-        return static_cast<jint>(color);
-    }
-
-    static jint getAlpha(jlong paintHandle) {
-        int alpha;
-        alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha();
-        return static_cast<jint>(alpha);
-    }
-
-    static void setColor(jlong paintHandle, jint color) {
-        reinterpret_cast<Paint*>(paintHandle)->setColor(color);
+    static void setColor(jlong paintHandle, jlong colorSpaceHandle,
+            jfloat r, jfloat g, jfloat b, jfloat a) {
+        sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
+        SkColor4f color = SkColor4f{r, g, b, a};
+        reinterpret_cast<Paint*>(paintHandle)->setColor4f(color, cs.get());
     }
 
     static void setAlpha(jlong paintHandle, jint a) {
@@ -1016,14 +1007,18 @@
     }
 
     static void setShadowLayer(jlong paintHandle, jfloat radius,
-                               jfloat dx, jfloat dy, jint color) {
+                               jfloat dx, jfloat dy, jlong colorSpaceHandle,
+                               jfloat r, jfloat g, jfloat b, jfloat a) {
+        sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
+        SkColor4f color = SkColor4f{r, g, b, a};
+
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         if (radius <= 0) {
             paint->setLooper(nullptr);
         }
         else {
             SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
-            paint->setLooper(SkBlurDrawLooper::Make((SkColor)color, sigma, dx, dy));
+            paint->setLooper(SkBlurDrawLooper::Make(color, cs.get(), sigma, dx, dy));
         }
     }
 
@@ -1104,9 +1099,7 @@
     {"nSetDither","(JZ)V", (void*) PaintGlue::setDither},
     {"nGetStyle","(J)I", (void*) PaintGlue::getStyle},
     {"nSetStyle","(JI)V", (void*) PaintGlue::setStyle},
-    {"nGetColor","(J)I", (void*) PaintGlue::getColor},
-    {"nSetColor","(JI)V", (void*) PaintGlue::setColor},
-    {"nGetAlpha","(J)I", (void*) PaintGlue::getAlpha},
+    {"nSetColor","(JJFFFF)V", (void*) PaintGlue::setColor},
     {"nSetAlpha","(JI)V", (void*) PaintGlue::setAlpha},
     {"nGetStrokeWidth","(J)F", (void*) PaintGlue::getStrokeWidth},
     {"nSetStrokeWidth","(JF)V", (void*) PaintGlue::setStrokeWidth},
@@ -1147,7 +1140,7 @@
     {"nGetUnderlineThickness","(J)F", (void*) PaintGlue::getUnderlineThickness},
     {"nGetStrikeThruPosition","(J)F", (void*) PaintGlue::getStrikeThruPosition},
     {"nGetStrikeThruThickness","(J)F", (void*) PaintGlue::getStrikeThruThickness},
-    {"nSetShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer},
+    {"nSetShadowLayer", "(JFFFJFFFF)V", (void*)PaintGlue::setShadowLayer},
     {"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer},
     {"nEqualsForTextMeasurement", "(JJ)Z", (void*)PaintGlue::equalsForTextMeasurement},
 };
diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp
index fd1d87f..d29857d 100644
--- a/core/jni/android/graphics/Picture.cpp
+++ b/core/jni/android/graphics/Picture.cpp
@@ -37,6 +37,12 @@
     }
 }
 
+Picture::Picture(sk_sp<SkPicture>&& src) {
+    mPicture = std::move(src);
+    mWidth = 0;
+    mHeight = 0;
+}
+
 Canvas* Picture::beginRecording(int width, int height) {
     mPicture.reset(NULL);
     mRecorder.reset(new SkPictureRecorder);
diff --git a/core/jni/android/graphics/Picture.h b/core/jni/android/graphics/Picture.h
index 3068631..536f651 100644
--- a/core/jni/android/graphics/Picture.h
+++ b/core/jni/android/graphics/Picture.h
@@ -37,6 +37,7 @@
 class Picture {
 public:
     explicit Picture(const Picture* src = NULL);
+    explicit Picture(sk_sp<SkPicture>&& src);
 
     Canvas* beginRecording(int width, int height);
 
diff --git a/core/jni/android_app_ActivityThread.cpp b/core/jni/android_app_ActivityThread.cpp
index d56e4c5..93f2525 100644
--- a/core/jni/android_app_ActivityThread.cpp
+++ b/core/jni/android_app_ActivityThread.cpp
@@ -24,6 +24,8 @@
 #include "core_jni_helpers.h"
 #include <unistd.h>
 
+#include <bionic_malloc.h>
+
 namespace android {
 
 static void android_app_ActivityThread_purgePendingResources(JNIEnv* env, jobject clazz) {
@@ -38,13 +40,18 @@
     minikin::Layout::dumpMinikinStats(fd);
 }
 
+static void android_app_ActivityThread_initZygoteChildHeapProfiling(JNIEnv* env, jobject clazz) {
+    android_mallopt(M_INIT_ZYGOTE_CHILD_PROFILING, nullptr, 0);
+}
 
 static JNINativeMethod gActivityThreadMethods[] = {
     // ------------ Regular JNI ------------------
     { "nPurgePendingResources",        "()V",
       (void*) android_app_ActivityThread_purgePendingResources },
     { "nDumpGraphicsInfo",        "(Ljava/io/FileDescriptor;)V",
-      (void*) android_app_ActivityThread_dumpGraphics }
+      (void*) android_app_ActivityThread_dumpGraphics },
+    { "nInitZygoteChildHeapProfiling",        "()V",
+      (void*) android_app_ActivityThread_initZygoteChildHeapProfiling }
 };
 
 int register_android_app_ActivityThread(JNIEnv* env) {
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 49a24a3..21369f9 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -281,15 +281,19 @@
     std::unique_ptr<NativeCode> code;
     bool needs_native_bridge = false;
 
+    char* nativeloader_error_msg = nullptr;
     void* handle = OpenNativeLibrary(env,
                                      sdkVersion,
                                      pathStr.c_str(),
                                      classLoader,
+                                     nullptr,
                                      libraryPath,
                                      &needs_native_bridge,
-                                     &g_error_msg);
+                                     &nativeloader_error_msg);
 
     if (handle == nullptr) {
+        g_error_msg = nativeloader_error_msg;
+        NativeLoaderFreeErrorMessage(nativeloader_error_msg);
         ALOGW("NativeActivity LoadNativeLibrary(\"%s\") failed: %s",
               pathStr.c_str(),
               g_error_msg.c_str());
diff --git a/core/jni/android_graphics_ColorSpace.cpp b/core/jni/android_graphics_ColorSpace.cpp
new file mode 100644
index 0000000..7648fd0
--- /dev/null
+++ b/core/jni/android_graphics_ColorSpace.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include "core_jni_helpers.h"
+
+#include "SkColor.h"
+#include "SkColorSpace.h"
+
+using namespace android;
+
+static skcms_Matrix3x3 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50) {
+    skcms_Matrix3x3 xyzMatrix;
+    jfloat* array = env->GetFloatArrayElements(xyzD50, NULL);
+    xyzMatrix.vals[0][0] = array[0];
+    xyzMatrix.vals[1][0] = array[1];
+    xyzMatrix.vals[2][0] = array[2];
+    xyzMatrix.vals[0][1] = array[3];
+    xyzMatrix.vals[1][1] = array[4];
+    xyzMatrix.vals[2][1] = array[5];
+    xyzMatrix.vals[0][2] = array[6];
+    xyzMatrix.vals[1][2] = array[7];
+    xyzMatrix.vals[2][2] = array[8];
+    env->ReleaseFloatArrayElements(xyzD50, array, 0);
+    return xyzMatrix;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static float halfToFloat(uint16_t bits) {
+  __fp16 h;
+  memcpy(&h, &bits, 2);
+  return (float)h;
+}
+
+SkColor4f GraphicsJNI::convertColorLong(jlong color) {
+    if ((color & 0x3f) == 0) {
+        // This corresponds to sRGB, which is treated differently than the rest.
+        uint8_t a = color >> 56 & 0xff;
+        uint8_t r = color >> 48 & 0xff;
+        uint8_t g = color >> 40 & 0xff;
+        uint8_t b = color >> 32 & 0xff;
+        SkColor c = SkColorSetARGB(a, r, g, b);
+        return SkColor4f::FromColor(c);
+    }
+
+    // These match the implementation of android.graphics.Color#red(long) etc.
+    float r = halfToFloat((uint16_t)(color >> 48 & 0xffff));
+    float g = halfToFloat((uint16_t)(color >> 32 & 0xffff));
+    float b = halfToFloat((uint16_t)(color >> 16 & 0xffff));
+    float a =                       (color >>  6 &  0x3ff) / 1023.0f;
+
+    return SkColor4f{r, g, b, a};
+}
+
+sk_sp<SkColorSpace> GraphicsJNI::getNativeColorSpace(jlong colorSpaceHandle) {
+    if (colorSpaceHandle == 0) return nullptr;
+    return sk_ref_sp(reinterpret_cast<SkColorSpace*>(colorSpaceHandle));
+}
+
+static void unref_colorSpace(SkColorSpace* cs) {
+    SkSafeUnref(cs);
+}
+
+static jlong ColorSpace_getNativeFinalizer(JNIEnv*, jobject) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&unref_colorSpace));
+}
+
+static jlong ColorSpace_creator(JNIEnv* env, jobject, jfloat a, jfloat b, jfloat c,
+        jfloat d, jfloat e, jfloat f, jfloat g, jfloatArray xyzD50) {
+    skcms_TransferFunction p;
+    p.a = a;
+    p.b = b;
+    p.c = c;
+    p.d = d;
+    p.e = e;
+    p.f = f;
+    p.g = g;
+    skcms_Matrix3x3 xyzMatrix = getNativeXYZMatrix(env, xyzD50);
+
+    return reinterpret_cast<jlong>(SkColorSpace::MakeRGB(p, xyzMatrix).release());
+}
+
+static const JNINativeMethod gColorSpaceRgbMethods[] = {
+    {   "nativeGetNativeFinalizer", "()J", (void*)ColorSpace_getNativeFinalizer },
+    {   "nativeCreate", "(FFFFFFF[F)J", (void*)ColorSpace_creator }
+};
+
+namespace android {
+
+int register_android_graphics_ColorSpace(JNIEnv* env) {
+    return android::RegisterMethodsOrDie(env, "android/graphics/ColorSpace$Rgb",
+                                         gColorSpaceRgbMethods, NELEM(gColorSpaceRgbMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp
index 10005dd..1ab5843 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.cpp
+++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp
@@ -93,7 +93,7 @@
 
 // --- Global functions ---
 
-sp<InputApplicationHandle> android_server_InputApplicationHandle_getHandle(
+sp<InputApplicationHandle> android_view_InputApplicationHandle_getHandle(
         JNIEnv* env, jobject inputApplicationHandleObj) {
     if (!inputApplicationHandleObj) {
         return NULL;
@@ -108,7 +108,7 @@
     } else {
         jweak objWeak = env->NewWeakGlobalRef(inputApplicationHandleObj);
         handle = new NativeInputApplicationHandle(objWeak);
-        handle->incStrong((void*)android_server_InputApplicationHandle_getHandle);
+        handle->incStrong((void*)android_view_InputApplicationHandle_getHandle);
         env->SetLongField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr,
                 reinterpret_cast<jlong>(handle));
     }
@@ -118,7 +118,7 @@
 
 // --- JNI ---
 
-static void android_server_InputApplicationHandle_nativeDispose(JNIEnv* env, jobject obj) {
+static void android_view_InputApplicationHandle_nativeDispose(JNIEnv* env, jobject obj) {
     AutoMutex _l(gHandleMutex);
 
     jlong ptr = env->GetLongField(obj, gInputApplicationHandleClassInfo.ptr);
@@ -126,7 +126,7 @@
         env->SetLongField(obj, gInputApplicationHandleClassInfo.ptr, 0);
 
         NativeInputApplicationHandle* handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr);
-        handle->decStrong((void*)android_server_InputApplicationHandle_getHandle);
+        handle->decStrong((void*)android_view_InputApplicationHandle_getHandle);
     }
 }
 
@@ -134,7 +134,7 @@
 static const JNINativeMethod gInputApplicationHandleMethods[] = {
     /* name, signature, funcPtr */
     { "nativeDispose", "()V",
-            (void*) android_server_InputApplicationHandle_nativeDispose },
+            (void*) android_view_InputApplicationHandle_nativeDispose },
 };
 
 #define FIND_CLASS(var, className) \
@@ -145,7 +145,7 @@
         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
         LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
 
-int register_android_server_InputApplicationHandle(JNIEnv* env) {
+int register_android_view_InputApplicationHandle(JNIEnv* env) {
     int res = jniRegisterNativeMethods(env, "android/view/InputApplicationHandle",
             gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods));
     (void) res;  // Faked use when LOG_NDEBUG.
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.h b/core/jni/android_hardware_input_InputApplicationHandle.h
index 7115611..5abeab4 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.h
+++ b/core/jni/android_hardware_input_InputApplicationHandle.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H
-#define _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H
+#ifndef _ANDROID_VIEW_INPUT_APPLICATION_HANDLE_H
+#define _ANDROID_VIEW_INPUT_APPLICATION_HANDLE_H
 
 #include <string>
 
@@ -40,9 +40,9 @@
 };
 
 
-extern sp<InputApplicationHandle> android_server_InputApplicationHandle_getHandle(
+extern sp<InputApplicationHandle> android_view_InputApplicationHandle_getHandle(
         JNIEnv* env, jobject inputApplicationHandleObj);
 
 } // namespace android
 
-#endif // _ANDROID_SERVER_INPUT_APPLICATION_HANDLE_H
+#endif // _ANDROID_VIEW_INPUT_APPLICATION_HANDLE_H
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index 76920f5..c0e45b1 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -159,7 +159,7 @@
             gInputWindowHandleClassInfo.inputApplicationHandle);
     if (inputApplicationHandleObj) {
         sp<InputApplicationHandle> inputApplicationHandle =
-            android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
+            android_view_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
         if (inputApplicationHandle != nullptr) {
             inputApplicationHandle->updateInfo();
             mInfo.applicationInfo = *(inputApplicationHandle->getInfo());
@@ -174,7 +174,7 @@
 
 // --- Global functions ---
 
-sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle(
+sp<NativeInputWindowHandle> android_view_InputWindowHandle_getHandle(
         JNIEnv* env, jobject inputWindowHandleObj) {
     if (!inputWindowHandleObj) {
         return NULL;
@@ -189,7 +189,7 @@
     } else {
         jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj);
         handle = new NativeInputWindowHandle(objWeak);
-        handle->incStrong((void*)android_server_InputWindowHandle_getHandle);
+        handle->incStrong((void*)android_view_InputWindowHandle_getHandle);
         env->SetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr,
                 reinterpret_cast<jlong>(handle));
     }
@@ -199,7 +199,7 @@
 
 // --- JNI ---
 
-static void android_server_InputWindowHandle_nativeDispose(JNIEnv* env, jobject obj) {
+static void android_view_InputWindowHandle_nativeDispose(JNIEnv* env, jobject obj) {
     AutoMutex _l(gHandleMutex);
 
     jlong ptr = env->GetLongField(obj, gInputWindowHandleClassInfo.ptr);
@@ -207,7 +207,7 @@
         env->SetLongField(obj, gInputWindowHandleClassInfo.ptr, 0);
 
         NativeInputWindowHandle* handle = reinterpret_cast<NativeInputWindowHandle*>(ptr);
-        handle->decStrong((void*)android_server_InputWindowHandle_getHandle);
+        handle->decStrong((void*)android_view_InputWindowHandle_getHandle);
     }
 }
 
@@ -215,7 +215,7 @@
 static const JNINativeMethod gInputWindowHandleMethods[] = {
     /* name, signature, funcPtr */
     { "nativeDispose", "()V",
-            (void*) android_server_InputWindowHandle_nativeDispose },
+            (void*) android_view_InputWindowHandle_nativeDispose },
 };
 
 #define FIND_CLASS(var, className) \
@@ -226,7 +226,7 @@
         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
         LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
 
-int register_android_server_InputWindowHandle(JNIEnv* env) {
+int register_android_view_InputWindowHandle(JNIEnv* env) {
     int res = jniRegisterNativeMethods(env, "android/view/InputWindowHandle",
             gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods));
     (void) res;  // Faked use when LOG_NDEBUG.
diff --git a/core/jni/android_hardware_input_InputWindowHandle.h b/core/jni/android_hardware_input_InputWindowHandle.h
index 54b89f5..de5bd6e 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.h
+++ b/core/jni/android_hardware_input_InputWindowHandle.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H
-#define _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H
+#ifndef _ANDROID_VIEW_INPUT_WINDOW_HANDLE_H
+#define _ANDROID_VIEW_INPUT_WINDOW_HANDLE_H
 
 #include <input/InputWindow.h>
 
@@ -38,9 +38,9 @@
 };
 
 
-extern sp<NativeInputWindowHandle> android_server_InputWindowHandle_getHandle(
+extern sp<NativeInputWindowHandle> android_view_InputWindowHandle_getHandle(
         JNIEnv* env, jobject inputWindowHandleObj);
 
 } // namespace android
 
-#endif // _ANDROID_SERVER_INPUT_WINDOW_HANDLE_H
+#endif // _ANDROID_VIEW_INPUT_WINDOW_HANDLE_H
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 12a8343b4..67c3064 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -841,6 +841,43 @@
     return jStatus;
 }
 
+static int android_media_AudioRecord_set_microphone_direction(JNIEnv *env, jobject thiz,
+                                                              jint direction) {
+    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+    if (lpRecorder == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioRecord pointer for setMicrophoneDirection()");
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+
+    jint jStatus = AUDIO_JAVA_SUCCESS;
+    status_t status =
+        lpRecorder->setMicrophoneDirection(static_cast<audio_microphone_direction_t>(direction));
+    if (status != NO_ERROR) {
+        jStatus = nativeToJavaStatus(status);
+    }
+
+    return jStatus;
+}
+
+static int android_media_AudioRecord_set_microphone_field_dimension(JNIEnv *env, jobject thiz,
+                                                                    jfloat zoom) {
+    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+    if (lpRecorder == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioRecord pointer for setMicrophoneFieldDimension()");
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+
+    jint jStatus = AUDIO_JAVA_SUCCESS;
+    status_t status = lpRecorder->setMicrophoneFieldDimension(zoom);
+    if (status != NO_ERROR) {
+        jStatus = nativeToJavaStatus(status);
+    }
+
+    return jStatus;
+}
+
 // ----------------------------------------------------------------------------
 static jint android_media_AudioRecord_get_port_id(JNIEnv *env,  jobject thiz) {
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
@@ -896,6 +933,10 @@
     {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
                                         (void *)android_media_AudioRecord_get_active_microphones},
     {"native_getPortId", "()I", (void *)android_media_AudioRecord_get_port_id},
+    {"native_set_microphone_direction", "(I)I",
+                                (void *)android_media_AudioRecord_set_microphone_direction},
+    {"native_set_microphone_field_dimension", "(F)I",
+                                (void *)android_media_AudioRecord_set_microphone_field_dimension},
 };
 
 // field names found in android/media/AudioRecord.java
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 80560f8..0d8ede7 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -487,13 +487,15 @@
 }
 
 static jint
-android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name)
+android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name,
+                                                   jint codec)
 {
     const char *c_address = env->GetStringUTFChars(device_address, NULL);
     const char *c_name = env->GetStringUTFChars(device_name, NULL);
     int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
                                           static_cast <audio_policy_dev_state_t>(state),
-                                          c_address, c_name));
+                                          c_address, c_name,
+                                          static_cast <audio_format_t>(codec)));
     env->ReleaseStringUTFChars(device_address, c_address);
     env->ReleaseStringUTFChars(device_name, c_name);
     return (jint) status;
@@ -510,12 +512,13 @@
 }
 
 static jint
-android_media_AudioSystem_handleDeviceConfigChange(JNIEnv *env, jobject thiz, jint device, jstring device_address, jstring device_name)
+android_media_AudioSystem_handleDeviceConfigChange(JNIEnv *env, jobject thiz, jint device, jstring device_address, jstring device_name,
+                                                   jint codec)
 {
     const char *c_address = env->GetStringUTFChars(device_address, NULL);
     const char *c_name = env->GetStringUTFChars(device_name, NULL);
     int status = check_AudioSystem_Command(AudioSystem::handleDeviceConfigChange(static_cast <audio_devices_t>(device),
-                                          c_address, c_name));
+                                          c_address, c_name, static_cast <audio_format_t>(codec)));
     env->ReleaseStringUTFChars(device_address, c_address);
     env->ReleaseStringUTFChars(device_name, c_name);
     return (jint) status;
@@ -2004,7 +2007,7 @@
     std::vector<media::MicrophoneInfo> microphones;
     status_t status = AudioSystem::getMicrophones(&microphones);
     if (status != NO_ERROR) {
-        ALOGE_IF(status != NO_ERROR, "AudioSystem::getMicrophones error %d", status);
+        ALOGE("AudioSystem::getMicrophones error %d", status);
         jStatus = nativeToJavaStatus(status);
         return jStatus;
     }
@@ -2026,6 +2029,34 @@
 }
 
 static jint
+android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP(
+                        JNIEnv *env, jobject thiz, jobject jEncodingFormatList)
+{
+    ALOGV("%s", __FUNCTION__);
+    jint jStatus = AUDIO_JAVA_SUCCESS;
+    if (!env->IsInstanceOf(jEncodingFormatList, gArrayListClass)) {
+        ALOGE("%s: jEncodingFormatList not an ArrayList", __FUNCTION__);
+        return (jint)AUDIO_JAVA_BAD_VALUE;
+    }
+    std::vector<audio_format_t> encodingFormats;
+    status_t status = AudioSystem::getHwOffloadEncodingFormatsSupportedForA2DP(
+                          &encodingFormats);
+    if (status != NO_ERROR) {
+        ALOGE("%s: error %d", __FUNCTION__, status);
+        jStatus = nativeToJavaStatus(status);
+        return jStatus;
+    }
+
+    for (size_t i = 0; i < encodingFormats.size(); i++) {
+        ScopedLocalRef<jobject> jEncodingFormat(
+            env, env->NewObject(gIntegerClass, gIntegerCstor, encodingFormats[i]));
+        env->CallBooleanMethod(jEncodingFormatList, gArrayListMethods.add,
+                               jEncodingFormat.get());
+    }
+    return jStatus;
+}
+
+static jint
 android_media_AudioSystem_getSurroundFormats(JNIEnv *env, jobject thiz,
                                              jobject jSurroundFormats, jboolean reported)
 {
@@ -2142,9 +2173,9 @@
     {"isSourceActive",      "(I)Z",     (void *)android_media_AudioSystem_isSourceActive},
     {"newAudioSessionId",   "()I",      (void *)android_media_AudioSystem_newAudioSessionId},
     {"newAudioPlayerId",    "()I",      (void *)android_media_AudioSystem_newAudioPlayerId},
-    {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
+    {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;I)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
     {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState},
-    {"handleDeviceConfigChange", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_handleDeviceConfigChange},
+    {"handleDeviceConfigChange", "(ILjava/lang/String;Ljava/lang/String;I)I", (void *)android_media_AudioSystem_handleDeviceConfigChange},
     {"setPhoneState",       "(I)I",     (void *)android_media_AudioSystem_setPhoneState},
     {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},
     {"getForceUse",         "(I)I",     (void *)android_media_AudioSystem_getForceUse},
@@ -2197,6 +2228,8 @@
     {"setAssistantUid", "(I)I", (void *)android_media_AudioSystem_setAssistantUid},
     {"setA11yServicesUids", "([I)I", (void *)android_media_AudioSystem_setA11yServicesUids},
     {"isHapticPlaybackSupported", "()Z", (void *)android_media_AudioSystem_isHapticPlaybackSupported},
+    {"getHwOffloadEncodingFormatsSupportedForA2DP", "(Ljava/util/ArrayList;)I",
+                    (void*)android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP},
 };
 
 static const JNINativeMethod gEventHandlerMethods[] = {
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 9b138eb..7eddcfe 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -16,8 +16,11 @@
 
 #define LOG_TAG "NetUtils"
 
+#include <vector>
+
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
 #include "NetdClient.h"
 #include <utils/misc.h>
 #include <android_runtime/AndroidRuntime.h>
@@ -55,6 +58,31 @@
 static const uint32_t kUDPDstPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, dest);
 static const uint16_t kDhcpClientPort = 68;
 
+constexpr int MAXPACKETSIZE = 8 * 1024;
+// FrameworkListener limits the size of commands to 1024 bytes. TODO: fix this.
+constexpr int MAXCMDSIZE = 1024;
+
+static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
+    ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
+    if (detailMessage.get() == NULL) {
+        // Not really much we can do here. We're probably dead in the water,
+        // but let's try to stumble on...
+        env->ExceptionClear();
+    }
+    static jclass errnoExceptionClass =
+            MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/system/ErrnoException"));
+
+    static jmethodID errnoExceptionCtor =
+            GetMethodIDOrDie(env, errnoExceptionClass,
+            "<init>", "(Ljava/lang/String;I)V");
+
+    jobject exception = env->NewObject(errnoExceptionClass,
+                                       errnoExceptionCtor,
+                                       detailMessage.get(),
+                                       error);
+    env->Throw(reinterpret_cast<jthrowable>(exception));
+}
+
 static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
 {
     struct sock_filter filter_code[] = {
@@ -372,6 +400,63 @@
     }
 }
 
+static jobject android_net_utils_resNetworkQuery(JNIEnv *env, jobject thiz, jint netId,
+        jstring dname, jint ns_class, jint ns_type, jint flags) {
+    const jsize javaCharsCount = env->GetStringLength(dname);
+    const jsize byteCountUTF8 = env->GetStringUTFLength(dname);
+
+    // Only allow dname which could be simply formatted to UTF8.
+    // In native layer, res_mkquery would re-format the input char array to packet.
+    std::vector<char> queryname(byteCountUTF8 + 1, 0);
+
+    env->GetStringUTFRegion(dname, 0, javaCharsCount, queryname.data());
+    int fd = resNetworkQuery(netId, queryname.data(), ns_class, ns_type, flags);
+
+    if (fd < 0) {
+        throwErrnoException(env, "resNetworkQuery", -fd);
+        return nullptr;
+    }
+
+    return jniCreateFileDescriptor(env, fd);
+}
+
+static jobject android_net_utils_resNetworkSend(JNIEnv *env, jobject thiz, jint netId,
+        jbyteArray msg, jint msgLen, jint flags) {
+    uint8_t data[MAXCMDSIZE];
+
+    checkLenAndCopy(env, msg, msgLen, data);
+    int fd = resNetworkSend(netId, data, msgLen, flags);
+
+    if (fd < 0) {
+        throwErrnoException(env, "resNetworkSend", -fd);
+        return nullptr;
+    }
+
+    return jniCreateFileDescriptor(env, fd);
+}
+
+static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) {
+    int fd = jniGetFDFromFileDescriptor(env, javaFd);
+    int rcode;
+    std::vector<uint8_t> buf(MAXPACKETSIZE, 0);
+
+    int res = resNetworkResult(fd, &rcode, buf.data(), MAXPACKETSIZE);
+    if (res < 0) {
+        throwErrnoException(env, "resNetworkResult", -res);
+        return nullptr;
+    }
+
+    jbyteArray answer = env->NewByteArray(res);
+    if (answer == nullptr) {
+        throwErrnoException(env, "resNetworkResult", ENOMEM);
+        return nullptr;
+    } else {
+        env->SetByteArrayRegion(answer, 0, res,
+                reinterpret_cast<jbyte*>(buf.data()));
+    }
+
+    return answer;
+}
 
 // ----------------------------------------------------------------------------
 
@@ -391,6 +476,9 @@
     { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachRaFilter },
     { "attachControlPacketFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachControlPacketFilter },
     { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_setupRaSocket },
+    { "resNetworkSend", "(I[BII)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkSend },
+    { "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery },
+    { "resNetworkResult", "(Ljava/io/FileDescriptor;)[B", (void*) android_net_utils_resNetworkResult },
 };
 
 int register_android_net_NetworkUtils(JNIEnv* env)
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 888dab1..7837248 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -29,7 +29,6 @@
 #include <time.h>
 #include <unistd.h>
 
-#include <atomic>
 #include <iomanip>
 #include <string>
 #include <vector>
@@ -42,9 +41,11 @@
 #include <nativehelper/JNIHelp.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include "jni.h"
+#include <meminfo/procmeminfo.h>
 #include <meminfo/sysmeminfo.h>
 #include <memtrack/memtrack.h>
 #include <memunreachable/memunreachable.h>
+#include <android-base/strings.h>
 #include "android_os_Debug.h"
 
 namespace android
@@ -150,14 +151,6 @@
     int swappedOutPss;
 };
 
-enum pss_rollup_support {
-  PSS_ROLLUP_UNTRIED,
-  PSS_ROLLUP_SUPPORTED,
-  PSS_ROLLUP_UNSUPPORTED
-};
-
-static std::atomic<pss_rollup_support> g_pss_rollup_support;
-
 #define BINDER_STATS "/proc/binder/stats"
 
 static jlong android_os_Debug_getNativeHeapSize(JNIEnv *env, jobject clazz)
@@ -239,244 +232,162 @@
     return err;
 }
 
-static void read_mapinfo(FILE *fp, stats_t* stats, bool* foundSwapPss)
-{
-    char line[1024];
-    int len, nameLen;
-    bool skip, done = false;
-
-    unsigned pss = 0, swappable_pss = 0, rss = 0;
-    float sharing_proportion = 0.0;
-    unsigned shared_clean = 0, shared_dirty = 0;
-    unsigned private_clean = 0, private_dirty = 0;
-    unsigned swapped_out = 0, swapped_out_pss = 0;
-    bool is_swappable = false;
-    unsigned temp;
-
-    uint64_t start;
-    uint64_t end = 0;
-    uint64_t prevEnd = 0;
-    char* name;
-    int name_pos;
-
-    int whichHeap = HEAP_UNKNOWN;
-    int subHeap = HEAP_UNKNOWN;
-    int prevHeap = HEAP_UNKNOWN;
-
-    *foundSwapPss = false;
-
-    if(fgets(line, sizeof(line), fp) == 0) return;
-
-    while (!done) {
-        prevHeap = whichHeap;
-        prevEnd = end;
-        whichHeap = HEAP_UNKNOWN;
-        subHeap = HEAP_UNKNOWN;
-        skip = false;
-        is_swappable = false;
-
-        len = strlen(line);
-        if (len < 1) return;
-        line[--len] = 0;
-
-        if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
-            skip = true;
-        } else {
-            while (isspace(line[name_pos])) {
-                name_pos += 1;
-            }
-            name = line + name_pos;
-            nameLen = strlen(name);
-            // Trim the end of the line if it is " (deleted)".
-            const char* deleted_str = " (deleted)";
-            if (nameLen > (int)strlen(deleted_str) &&
-                strcmp(name+nameLen-strlen(deleted_str), deleted_str) == 0) {
-                nameLen -= strlen(deleted_str);
-                name[nameLen] = '\0';
-            }
-            if ((strstr(name, "[heap]") == name)) {
-                whichHeap = HEAP_NATIVE;
-            } else if (strncmp(name, "[anon:libc_malloc]", 18) == 0) {
-                whichHeap = HEAP_NATIVE;
-            } else if (strncmp(name, "[stack", 6) == 0) {
-                whichHeap = HEAP_STACK;
-            } else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) {
-                whichHeap = HEAP_SO;
-                is_swappable = true;
-            } else if (nameLen > 4 && strcmp(name+nameLen-4, ".jar") == 0) {
-                whichHeap = HEAP_JAR;
-                is_swappable = true;
-            } else if (nameLen > 4 && strcmp(name+nameLen-4, ".apk") == 0) {
-                whichHeap = HEAP_APK;
-                is_swappable = true;
-            } else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) {
-                whichHeap = HEAP_TTF;
-                is_swappable = true;
-            } else if ((nameLen > 4 && strstr(name, ".dex") != NULL) ||
-                       (nameLen > 5 && strcmp(name+nameLen-5, ".odex") == 0)) {
-                whichHeap = HEAP_DEX;
-                subHeap = HEAP_DEX_APP_DEX;
-                is_swappable = true;
-            } else if (nameLen > 5 && strcmp(name+nameLen-5, ".vdex") == 0) {
-                whichHeap = HEAP_DEX;
-                // Handle system@framework@boot* and system/framework/boot*
-                if (strstr(name, "@boot") != NULL || strstr(name, "/boot") != NULL) {
-                    subHeap = HEAP_DEX_BOOT_VDEX;
-                } else {
-                    subHeap = HEAP_DEX_APP_VDEX;
-                }
-                is_swappable = true;
-            } else if (nameLen > 4 && strcmp(name+nameLen-4, ".oat") == 0) {
-                whichHeap = HEAP_OAT;
-                is_swappable = true;
-            } else if (nameLen > 4 && strcmp(name+nameLen-4, ".art") == 0) {
-                whichHeap = HEAP_ART;
-                // Handle system@framework@boot* and system/framework/boot*
-                if (strstr(name, "@boot") != NULL || strstr(name, "/boot") != NULL) {
-                    subHeap = HEAP_ART_BOOT;
-                } else {
-                    subHeap = HEAP_ART_APP;
-                }
-                is_swappable = true;
-            } else if (strncmp(name, "/dev/", 5) == 0) {
-                whichHeap = HEAP_UNKNOWN_DEV;
-                if (strncmp(name, "/dev/kgsl-3d0", 13) == 0) {
-                    whichHeap = HEAP_GL_DEV;
-                } else if (strncmp(name, "/dev/ashmem/CursorWindow", 24) == 0) {
-                    whichHeap = HEAP_CURSOR;
-                } else if (strncmp(name, "/dev/ashmem", 11)) {
-                    whichHeap = HEAP_ASHMEM;
-                }
-            } else if (strncmp(name, "[anon:", 6) == 0) {
-                whichHeap = HEAP_UNKNOWN;
-                if (strncmp(name, "[anon:dalvik-", 13) == 0) {
-                    whichHeap = HEAP_DALVIK_OTHER;
-                    if (strstr(name, "[anon:dalvik-LinearAlloc") == name) {
-                        subHeap = HEAP_DALVIK_OTHER_LINEARALLOC;
-                    } else if ((strstr(name, "[anon:dalvik-alloc space") == name) ||
-                               (strstr(name, "[anon:dalvik-main space") == name)) {
-                        // This is the regular Dalvik heap.
-                        whichHeap = HEAP_DALVIK;
-                        subHeap = HEAP_DALVIK_NORMAL;
-                    } else if (strstr(name, "[anon:dalvik-large object space") == name ||
-                               strstr(name, "[anon:dalvik-free list large object space")
-                                   == name) {
-                        whichHeap = HEAP_DALVIK;
-                        subHeap = HEAP_DALVIK_LARGE;
-                    } else if (strstr(name, "[anon:dalvik-non moving space") == name) {
-                        whichHeap = HEAP_DALVIK;
-                        subHeap = HEAP_DALVIK_NON_MOVING;
-                    } else if (strstr(name, "[anon:dalvik-zygote space") == name) {
-                        whichHeap = HEAP_DALVIK;
-                        subHeap = HEAP_DALVIK_ZYGOTE;
-                    } else if (strstr(name, "[anon:dalvik-indirect ref") == name) {
-                        subHeap = HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE;
-                    } else if (strstr(name, "[anon:dalvik-jit-code-cache") == name ||
-                               strstr(name, "[anon:dalvik-data-code-cache") == name) {
-                        subHeap = HEAP_DALVIK_OTHER_CODE_CACHE;
-                    } else if (strstr(name, "[anon:dalvik-CompilerMetadata") == name) {
-                        subHeap = HEAP_DALVIK_OTHER_COMPILER_METADATA;
-                    } else {
-                        subHeap = HEAP_DALVIK_OTHER_ACCOUNTING;  // Default to accounting.
-                    }
-                }
-            } else if (nameLen > 0) {
-                whichHeap = HEAP_UNKNOWN_MAP;
-            } else if (start == prevEnd && prevHeap == HEAP_SO) {
-                // bss section of a shared library.
-                whichHeap = HEAP_SO;
-            }
-        }
-
-        //ALOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap,
-        //    isSqliteHeap, line);
-
-        shared_clean = 0;
-        shared_dirty = 0;
-        private_clean = 0;
-        private_dirty = 0;
-        swapped_out = 0;
-        swapped_out_pss = 0;
-
-        while (true) {
-            if (fgets(line, 1024, fp) == 0) {
-                done = true;
-                break;
-            }
-
-            if (line[0] == 'S' && sscanf(line, "Size: %d kB", &temp) == 1) {
-                /* size = temp; */
-            } else if (line[0] == 'R' && sscanf(line, "Rss: %d kB", &temp) == 1) {
-                rss = temp;
-            } else if (line[0] == 'P' && sscanf(line, "Pss: %d kB", &temp) == 1) {
-                pss = temp;
-            } else if (line[0] == 'S' && sscanf(line, "Shared_Clean: %d kB", &temp) == 1) {
-                shared_clean = temp;
-            } else if (line[0] == 'S' && sscanf(line, "Shared_Dirty: %d kB", &temp) == 1) {
-                shared_dirty = temp;
-            } else if (line[0] == 'P' && sscanf(line, "Private_Clean: %d kB", &temp) == 1) {
-                private_clean = temp;
-            } else if (line[0] == 'P' && sscanf(line, "Private_Dirty: %d kB", &temp) == 1) {
-                private_dirty = temp;
-            } else if (line[0] == 'R' && sscanf(line, "Referenced: %d kB", &temp) == 1) {
-                /* referenced = temp; */
-            } else if (line[0] == 'S' && sscanf(line, "Swap: %d kB", &temp) == 1) {
-                swapped_out = temp;
-            } else if (line[0] == 'S' && sscanf(line, "SwapPss: %d kB", &temp) == 1) {
-                *foundSwapPss = true;
-                swapped_out_pss = temp;
-            } else if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d", &start, &end) == 2) {
-                // looks like a new mapping
-                // example: "10000000-10001000 ---p 10000000 00:00 0"
-                break;
-            }
-        }
-
-        if (!skip) {
-            if (is_swappable && (pss > 0)) {
-                sharing_proportion = 0.0;
-                if ((shared_clean > 0) || (shared_dirty > 0)) {
-                    sharing_proportion = (pss - private_clean
-                            - private_dirty)/(shared_clean+shared_dirty);
-                }
-                swappable_pss = (sharing_proportion*shared_clean) + private_clean;
-            } else
-                swappable_pss = 0;
-
-            stats[whichHeap].pss += pss;
-            stats[whichHeap].swappablePss += swappable_pss;
-            stats[whichHeap].rss += rss;
-            stats[whichHeap].privateDirty += private_dirty;
-            stats[whichHeap].sharedDirty += shared_dirty;
-            stats[whichHeap].privateClean += private_clean;
-            stats[whichHeap].sharedClean += shared_clean;
-            stats[whichHeap].swappedOut += swapped_out;
-            stats[whichHeap].swappedOutPss += swapped_out_pss;
-            if (whichHeap == HEAP_DALVIK || whichHeap == HEAP_DALVIK_OTHER ||
-                    whichHeap == HEAP_DEX || whichHeap == HEAP_ART) {
-                stats[subHeap].pss += pss;
-                stats[subHeap].swappablePss += swappable_pss;
-                stats[subHeap].rss += rss;
-                stats[subHeap].privateDirty += private_dirty;
-                stats[subHeap].sharedDirty += shared_dirty;
-                stats[subHeap].privateClean += private_clean;
-                stats[subHeap].sharedClean += shared_clean;
-                stats[subHeap].swappedOut += swapped_out;
-                stats[subHeap].swappedOutPss += swapped_out_pss;
-            }
-        }
-    }
-}
-
 static void load_maps(int pid, stats_t* stats, bool* foundSwapPss)
 {
     *foundSwapPss = false;
+    uint64_t prev_end = 0;
+    int prev_heap = HEAP_UNKNOWN;
 
     std::string smaps_path = base::StringPrintf("/proc/%d/smaps", pid);
-    UniqueFile fp = MakeUniqueFile(smaps_path.c_str(), "re");
-    if (fp == nullptr) return;
+    auto vma_scan = [&](const meminfo::Vma& vma) {
+        int which_heap = HEAP_UNKNOWN;
+        int sub_heap = HEAP_UNKNOWN;
+        bool is_swappable = false;
+        std::string name;
+        if (base::EndsWith(vma.name, " (deleted)")) {
+            name = vma.name.substr(0, vma.name.size() - strlen(" (deleted)"));
+        } else {
+            name = vma.name;
+        }
 
-    read_mapinfo(fp.get(), stats, foundSwapPss);
+        uint32_t namesz = name.size();
+        if (base::StartsWith(name, "[heap]")) {
+            which_heap = HEAP_NATIVE;
+        } else if (base::StartsWith(name, "[anon:libc_malloc]")) {
+            which_heap = HEAP_NATIVE;
+        } else if (base::StartsWith(name, "[stack")) {
+            which_heap = HEAP_NATIVE;
+        } else if (base::EndsWith(name, ".so")) {
+            which_heap = HEAP_SO;
+            is_swappable = true;
+        } else if (base::EndsWith(name, ".jar")) {
+            which_heap = HEAP_JAR;
+            is_swappable = true;
+        } else if (base::EndsWith(name, ".apk")) {
+            which_heap = HEAP_APK;
+            is_swappable = true;
+        } else if (base::EndsWith(name, ".ttf")) {
+            which_heap = HEAP_TTF;
+            is_swappable = true;
+        } else if ((base::EndsWith(name, ".odex")) ||
+                (namesz > 4 && strstr(name.c_str(), ".dex") != nullptr)) {
+            which_heap = HEAP_DEX;
+            sub_heap = HEAP_DEX_APP_DEX;
+            is_swappable = true;
+        } else if (base::EndsWith(name, ".vdex")) {
+            which_heap = HEAP_DEX;
+            // Handle system@framework@boot and system/framework/boot
+            if ((strstr(name.c_str(), "@boot") != nullptr) ||
+                    (strstr(name.c_str(), "/boot"))) {
+                sub_heap = HEAP_DEX_BOOT_VDEX;
+            } else {
+                sub_heap = HEAP_DEX_APP_VDEX;
+            }
+            is_swappable = true;
+        } else if (base::EndsWith(name, ".oat")) {
+            which_heap = HEAP_OAT;
+            is_swappable = true;
+        } else if (base::EndsWith(name, ".art")) {
+            which_heap = HEAP_ART;
+            // Handle system@framework@boot* and system/framework/boot*
+            if ((strstr(name.c_str(), "@boot") != nullptr) ||
+                    (strstr(name.c_str(), "/boot"))) {
+                sub_heap = HEAP_DEX_BOOT_VDEX;
+            } else {
+                sub_heap = HEAP_DEX_APP_VDEX;
+            }
+            is_swappable = true;
+        } else if (base::StartsWith(name, "/dev/")) {
+            which_heap = HEAP_UNKNOWN_DEV;
+            if (base::StartsWith(name, "/dev/kgsl-3d0")) {
+                which_heap = HEAP_GL_DEV;
+            } else if (base::StartsWith(name, "/dev/ashmem/CursorWindow")) {
+                which_heap = HEAP_CURSOR;
+            } else if (base::StartsWith(name, "/dev/ashmem")) {
+                which_heap = HEAP_ASHMEM;
+            }
+        } else if (base::StartsWith(name, "[anon:")) {
+            which_heap = HEAP_UNKNOWN;
+            if (base::StartsWith(name, "[anon:dalvik-")) {
+                which_heap = HEAP_DALVIK_OTHER;
+                if (base::StartsWith(name, "[anon:dalvik-LinearAlloc")) {
+                    sub_heap = HEAP_DALVIK_OTHER_LINEARALLOC;
+                } else if (base::StartsWith(name, "[anon:dalvik-alloc space") ||
+                        base::StartsWith(name, "[anon:dalvik-main space")) {
+                    // This is the regular Dalvik heap.
+                    which_heap = HEAP_DALVIK;
+                    sub_heap = HEAP_DALVIK_NORMAL;
+                } else if (base::StartsWith(name,
+                            "[anon:dalvik-large object space") ||
+                        base::StartsWith(
+                            name, "[anon:dalvik-free list large object space")) {
+                    which_heap = HEAP_DALVIK;
+                    sub_heap = HEAP_DALVIK_LARGE;
+                } else if (base::StartsWith(name, "[anon:dalvik-non moving space")) {
+                    which_heap = HEAP_DALVIK;
+                    sub_heap = HEAP_DALVIK_NON_MOVING;
+                } else if (base::StartsWith(name, "[anon:dalvik-zygote space")) {
+                    which_heap = HEAP_DALVIK;
+                    sub_heap = HEAP_DALVIK_ZYGOTE;
+                } else if (base::StartsWith(name, "[anon:dalvik-indirect ref")) {
+                    sub_heap = HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE;
+                } else if (base::StartsWith(name, "[anon:dalvik-jit-code-cache") ||
+                        base::StartsWith(name, "[anon:dalvik-data-code-cache")) {
+                    sub_heap = HEAP_DALVIK_OTHER_CODE_CACHE;
+                } else if (base::StartsWith(name, "[anon:dalvik-CompilerMetadata")) {
+                    sub_heap = HEAP_DALVIK_OTHER_COMPILER_METADATA;
+                } else {
+                    sub_heap = HEAP_DALVIK_OTHER_ACCOUNTING;  // Default to accounting.
+                }
+            }
+        } else if (namesz > 0) {
+            which_heap = HEAP_UNKNOWN_MAP;
+        } else if (vma.start == prev_end && prev_heap == HEAP_SO) {
+            // bss section of a shared library
+            which_heap = HEAP_SO;
+        }
+
+        prev_end = vma.end;
+        prev_heap = which_heap;
+
+        const meminfo::MemUsage& usage = vma.usage;
+        if (usage.swap_pss > 0 && *foundSwapPss != true) {
+            *foundSwapPss = true;
+        }
+
+        uint64_t swapable_pss = 0;
+        if (is_swappable && (usage.pss > 0)) {
+            float sharing_proportion = 0.0;
+            if ((usage.shared_clean > 0) || (usage.shared_dirty > 0)) {
+                sharing_proportion = (usage.pss - usage.uss) / (usage.shared_clean + usage.shared_dirty);
+            }
+            swapable_pss = (sharing_proportion * usage.shared_clean) + usage.private_clean;
+        }
+
+        stats[which_heap].pss += usage.pss;
+        stats[which_heap].swappablePss += swapable_pss;
+        stats[which_heap].rss += usage.rss;
+        stats[which_heap].privateDirty += usage.private_dirty;
+        stats[which_heap].sharedDirty += usage.shared_dirty;
+        stats[which_heap].privateClean += usage.private_clean;
+        stats[which_heap].sharedClean += usage.shared_clean;
+        stats[which_heap].swappedOut += usage.swap;
+        stats[which_heap].swappedOutPss += usage.swap_pss;
+        if (which_heap == HEAP_DALVIK || which_heap == HEAP_DALVIK_OTHER ||
+                which_heap == HEAP_DEX || which_heap == HEAP_ART) {
+            stats[sub_heap].pss += usage.pss;
+            stats[sub_heap].swappablePss += swapable_pss;
+            stats[sub_heap].rss += usage.rss;
+            stats[sub_heap].privateDirty += usage.private_dirty;
+            stats[sub_heap].sharedDirty += usage.shared_dirty;
+            stats[sub_heap].privateClean += usage.private_clean;
+            stats[sub_heap].sharedClean += usage.shared_clean;
+            stats[sub_heap].swappedOut += usage.swap;
+            stats[sub_heap].swappedOutPss += usage.swap_pss;
+        }
+    };
+
+    meminfo::ForEachVmaFromFile(smaps_path, vma_scan);
 }
 
 static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
@@ -555,37 +466,9 @@
     android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
 }
 
-UniqueFile OpenSmapsOrRollup(int pid)
-{
-    enum pss_rollup_support rollup_support =
-            g_pss_rollup_support.load(std::memory_order_relaxed);
-    if (rollup_support != PSS_ROLLUP_UNSUPPORTED) {
-        std::string smaps_rollup_path =
-                base::StringPrintf("/proc/%d/smaps_rollup", pid);
-        UniqueFile fp_rollup = MakeUniqueFile(smaps_rollup_path.c_str(), "re");
-        if (fp_rollup == nullptr && errno != ENOENT) {
-            return fp_rollup;  // Actual error, not just old kernel.
-        }
-        if (fp_rollup != nullptr) {
-            if (rollup_support == PSS_ROLLUP_UNTRIED) {
-                ALOGI("using rollup pss collection");
-                g_pss_rollup_support.store(PSS_ROLLUP_SUPPORTED,
-                                           std::memory_order_relaxed);
-            }
-            return fp_rollup;
-        }
-        g_pss_rollup_support.store(PSS_ROLLUP_UNSUPPORTED,
-                                   std::memory_order_relaxed);
-    }
-
-    std::string smaps_path = base::StringPrintf("/proc/%d/smaps", pid);
-    return MakeUniqueFile(smaps_path.c_str(), "re");
-}
-
 static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid,
         jlongArray outUssSwapPssRss, jlongArray outMemtrack)
 {
-    char lineBuffer[1024];
     jlong pss = 0;
     jlong rss = 0;
     jlong swapPss = 0;
@@ -597,59 +480,14 @@
         pss = uss = rss = memtrack = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other;
     }
 
-    {
-        UniqueFile fp = OpenSmapsOrRollup(pid);
-
-        if (fp != nullptr) {
-            char* line;
-
-            while (true) {
-                if (fgets(lineBuffer, sizeof (lineBuffer), fp.get()) == NULL) {
-                    break;
-                }
-                line = lineBuffer;
-
-                switch (line[0]) {
-                    case 'P':
-                        if (strncmp(line, "Pss:", 4) == 0) {
-                            char* c = line + 4;
-                            while (*c != 0 && (*c < '0' || *c > '9')) {
-                                c++;
-                            }
-                            pss += atoi(c);
-                        } else if (strncmp(line, "Private_Clean:", 14) == 0
-                                    || strncmp(line, "Private_Dirty:", 14) == 0) {
-                            char* c = line + 14;
-                            while (*c != 0 && (*c < '0' || *c > '9')) {
-                                c++;
-                            }
-                            uss += atoi(c);
-                        }
-                        break;
-                    case 'R':
-                        if (strncmp(line, "Rss:", 4) == 0) {
-                            char* c = line + 4;
-                            while (*c != 0 && (*c < '0' || *c > '9')) {
-                                c++;
-                            }
-                            rss += atoi(c);
-                        }
-                        break;
-                    case 'S':
-                        if (strncmp(line, "SwapPss:", 8) == 0) {
-                            char* c = line + 8;
-                            jlong lSwapPss;
-                            while (*c != 0 && (*c < '0' || *c > '9')) {
-                                c++;
-                            }
-                            lSwapPss = atoi(c);
-                            swapPss += lSwapPss;
-                            pss += lSwapPss; // Also in swap, those pages would be accounted as Pss without SWAP
-                        }
-                        break;
-                }
-            }
-        }
+    ::android::meminfo::ProcMemInfo proc_mem(pid);
+    ::android::meminfo::MemUsage stats;
+    if (proc_mem.SmapsOrRollup(&stats)) {
+        pss += stats.pss;
+        uss += stats.uss;
+        rss += stats.rss;
+        swapPss = stats.swap_pss;
+        pss += swapPss; // Also in swap, those pages would be accounted as Pss without SWAP
     }
 
     if (outUssSwapPssRss != NULL) {
@@ -686,34 +524,6 @@
     return android_os_Debug_getPssPid(env, clazz, getpid(), NULL, NULL);
 }
 
-static long get_allocated_vmalloc_memory() {
-    char line[1024];
-
-    long vmalloc_allocated_size = 0;
-
-    UniqueFile fp = MakeUniqueFile("/proc/vmallocinfo", "re");
-    if (fp == nullptr) {
-        return 0;
-    }
-
-    while (true) {
-        if (fgets(line, 1024, fp.get()) == NULL) {
-            break;
-        }
-
-        // check to see if there are pages mapped in vmalloc area
-        if (!strstr(line, "pages=")) {
-            continue;
-        }
-
-        long nr_pages;
-        if (sscanf(line, "%*x-%*x %*ld %*s pages=%ld", &nr_pages) == 1) {
-            vmalloc_allocated_size += (nr_pages * getpagesize());
-        }
-    }
-    return vmalloc_allocated_size;
-}
-
 // The 1:1 mapping of MEMINFO_* enums here must match with the constants from
 // Debug.java.
 enum {
@@ -763,9 +573,8 @@
     if (outArray != NULL) {
         outLen = MEMINFO_COUNT;
         for (int i = 0; i < outLen; i++) {
-            // TODO: move get_allocated_vmalloc_memory() to libmeminfo
             if (i == MEMINFO_VMALLOC_USED) {
-                outArray[i] = get_allocated_vmalloc_memory() / 1024;
+                outArray[i] = smi.ReadVmallocInfo() / 1024;
                 continue;
             }
             outArray[i] = mem[i];
@@ -775,7 +584,6 @@
     env->ReleaseLongArrayElements(out, outArray, 0);
 }
 
-
 static jint read_binder_stat(const char* stat)
 {
     UniqueFile fp = MakeUniqueFile(BINDER_STATS, "re");
diff --git a/core/jni/android_os_Debug.h b/core/jni/android_os_Debug.h
index c7b731b..747776a 100644
--- a/core/jni/android_os_Debug.h
+++ b/core/jni/android_os_Debug.h
@@ -19,6 +19,7 @@
 
 #include <memory>
 #include <stdio.h>
+#include <meminfo/meminfo.h>
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
 
@@ -34,8 +35,6 @@
     return UniqueFile(fopen(path, mode), safeFclose);
 }
 
-UniqueFile OpenSmapsOrRollup(int pid);
-
 }  // namespace android
 
 #endif  // ANDROID_OS_HW_BLOB_H
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 163b86b..42e3942 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -329,7 +329,7 @@
         return NULL;
     }
 
-    LOG(INFO) << "HwBinder: Starting thread pool for " << serviceName << "::" << ifaceName;
+    LOG(INFO) << "HwBinder: Starting thread pool for getting: " << ifaceName << "/" << serviceName;
     ::android::hardware::ProcessState::self()->startThreadPool();
 
     return JHwRemoteBinder::NewObject(env, service);
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 7ef06dc..3b59321 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -473,7 +473,7 @@
     if (parcel != NULL) {
         int fd = parcel->readFileDescriptor();
         if (fd < 0) return NULL;
-        fd = dup(fd);
+        fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
         if (fd < 0) return NULL;
         return jniCreateFileDescriptor(env, fd);
     }
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 7b564ae..4101c04 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -44,6 +44,8 @@
 #include "androidfw/MutexGuard.h"
 #include "androidfw/PosixUtils.h"
 #include "androidfw/ResourceTypes.h"
+#include "androidfw/ResourceUtils.h"
+
 #include "core_jni_helpers.h"
 #include "jni.h"
 #include "nativehelper/JNIHelp.h"
@@ -975,34 +977,7 @@
     return nullptr;
   }
 
-  std::string result;
-  if (name.package != nullptr) {
-    result.append(name.package, name.package_len);
-  }
-
-  if (name.type != nullptr || name.type16 != nullptr) {
-    if (!result.empty()) {
-      result += ":";
-    }
-
-    if (name.type != nullptr) {
-      result.append(name.type, name.type_len);
-    } else {
-      result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
-    }
-  }
-
-  if (name.entry != nullptr || name.entry16 != nullptr) {
-    if (!result.empty()) {
-      result += "/";
-    }
-
-    if (name.entry != nullptr) {
-      result.append(name.entry, name.entry_len);
-    } else {
-      result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
-    }
-  }
+  std::string result = ToFormattedResourceString(&name);
   return env->NewStringUTF(result.c_str());
 }
 
@@ -1049,6 +1024,26 @@
   return nullptr;
 }
 
+static void NativeSetResourceResolutionLoggingEnabled(JNIEnv* /*env*/,
+                                                      jclass /*clazz*/,
+                                                      jlong ptr,
+                                                      jboolean enabled) {
+  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+  assetmanager->SetResourceResolutionLoggingEnabled(enabled);
+}
+
+static jstring NativeGetLastResourceResolution(JNIEnv* env,
+                                               jclass /*clazz*/,
+                                               jlong ptr) {
+  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+  std::string resolution = assetmanager->GetLastResourceResolution();
+  if (resolution.empty()) {
+    return nullptr;
+  } else {
+    return env->NewStringUTF(resolution.c_str());
+  }
+}
+
 static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
                                      jboolean exclude_system) {
   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
@@ -1452,6 +1447,10 @@
     {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
     {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
     {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
+    {"nativeSetResourceResolutionLoggingEnabled", "(JZ)V",
+     (void*) NativeSetResourceResolutionLoggingEnabled},
+    {"nativeGetLastResourceResolution", "(J)Ljava/lang/String;",
+     (void*) NativeGetLastResourceResolution},
     {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
     {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
      (void*)NativeGetSizeConfigurations},
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 3329e20..f201ceb 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -875,6 +875,11 @@
     return IPCThreadState::self()->getCallingUid();
 }
 
+static jboolean android_os_Binder_isHandlingTransaction()
+{
+    return IPCThreadState::self()->isServingCall();
+}
+
 static jlong android_os_Binder_clearCallingIdentity()
 {
     return IPCThreadState::self()->clearCallingIdentity();
@@ -960,6 +965,8 @@
     // @CriticalNative
     { "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },
     // @CriticalNative
+    { "isHandlingTransaction", "()Z", (void*)android_os_Binder_isHandlingTransaction },
+    // @CriticalNative
     { "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },
     { "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity },
     // @CriticalNative
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 0c1a8aa..26a474c 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -22,11 +22,12 @@
 #include <utils/Log.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
-#include <cutils/sched_policy.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
+#include <meminfo/procmeminfo.h>
 #include <meminfo/sysmeminfo.h>
 #include <processgroup/processgroup.h>
+#include <processgroup/sched_policy.h>
 
 #include <string>
 #include <vector>
@@ -1083,21 +1084,12 @@
 
 static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid)
 {
-    UniqueFile file = OpenSmapsOrRollup(pid);
-    if (file == nullptr) {
+    ::android::meminfo::ProcMemInfo proc_mem(pid);
+    uint64_t pss;
+    if (!proc_mem.SmapsOrRollupPss(&pss)) {
         return (jlong) -1;
     }
 
-    // Tally up all of the Pss from the various maps
-    char line[256];
-    jlong pss = 0;
-    while (fgets(line, sizeof(line), file.get())) {
-        jlong v;
-        if (sscanf(line, "Pss: %" SCNd64 " kB", &v) == 1) {
-            pss += v;
-        }
-    }
-
     // Return the Pss value in bytes, not kilobytes
     return pss * 1024;
 }
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index 10da892..aa10a2f 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -138,6 +138,7 @@
                 event->getDeviceId(), event->getSource(), event->getDisplayId(),
                 event->getAction(), event->getActionButton(), event->getFlags(),
                 event->getEdgeFlags(), event->getMetaState(), event->getButtonState(),
+                event->getClassification(),
                 event->getXOffset(), event->getYOffset(),
                 event->getXPrecision(), event->getYPrecision(),
                 event->getDownTime(), event->getHistoricalEventTime(i),
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index ecf8119..50cff5c 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -334,7 +334,7 @@
 static jlong android_view_MotionEvent_nativeInitialize(JNIEnv* env, jclass clazz,
         jlong nativePtr,
         jint deviceId, jint source, jint displayId, jint action, jint flags, jint edgeFlags,
-        jint metaState, jint buttonState,
+        jint metaState, jint buttonState, jint classification,
         jfloat xOffset, jfloat yOffset, jfloat xPrecision, jfloat yPrecision,
         jlong downTimeNanos, jlong eventTimeNanos,
         jint pointerCount, jobjectArray pointerPropertiesObjArray,
@@ -373,7 +373,8 @@
     }
 
     event->initialize(deviceId, source, displayId, action, 0, flags, edgeFlags, metaState,
-            buttonState, xOffset, yOffset, xPrecision, yPrecision,
+            buttonState, static_cast<MotionClassification>(classification),
+            xOffset, yOffset, xPrecision, yPrecision,
             downTimeNanos, eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords);
 
     return reinterpret_cast<jlong>(event);
@@ -668,6 +669,11 @@
     event->setButtonState(buttonState);
 }
 
+static jint android_view_MotionEvent_nativeGetClassification(jlong nativePtr) {
+    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+    return static_cast<jint>(event->getClassification());
+}
+
 static void android_view_MotionEvent_nativeOffsetLocation(jlong nativePtr, jfloat deltaX,
         jfloat deltaY) {
     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
@@ -747,7 +753,7 @@
 static const JNINativeMethod gMotionEventMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInitialize",
-            "(JIIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
+            "(JIIIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
                     "[Landroid/view/MotionEvent$PointerCoords;)J",
             (void*)android_view_MotionEvent_nativeInitialize },
     { "nativeDispose",
@@ -846,6 +852,9 @@
     { "nativeSetButtonState",
             "(JI)V",
             (void*)android_view_MotionEvent_nativeSetButtonState },
+    { "nativeGetClassification",
+            "(J)I",
+            (void*)android_view_MotionEvent_nativeGetClassification },
     { "nativeOffsetLocation",
             "(JFF)V",
             (void*)android_view_MotionEvent_nativeOffsetLocation },
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index c745c16..69877c7 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -126,7 +126,12 @@
         jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
         jint windowType, jint ownerUid) {
     ScopedUtfChars name(env, nameStr);
-    sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
+    sp<SurfaceComposerClient> client;
+    if (sessionObj != NULL) {
+        client = android_view_SurfaceSession_getClient(env, sessionObj);
+    } else {
+        client = SurfaceComposerClient::getDefault();
+    }
     SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
     sp<SurfaceControl> surface;
     status_t err = client->createSurfaceChecked(
@@ -277,6 +282,21 @@
     transaction->setPosition(ctrl, x, y);
 }
 
+static void nativeSetGeometry(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
+        jobject sourceObj, jobject dstObj, jlong orientation) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+
+    Rect source, dst;
+    if (sourceObj != NULL) {
+        source = rectFromObj(env, sourceObj);
+    }
+    if (dstObj != NULL) {
+        dst = rectFromObj(env, dstObj);
+    }
+    transaction->setGeometry(ctrl, source, dst, orientation);
+}
+
 static void nativeSetGeometryAppliesWithResize(JNIEnv* env, jclass clazz,
 jlong transactionObj,
         jlong nativeObject) {
@@ -340,7 +360,7 @@
         jlong nativeObject, jobject inputWindow) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
 
-    sp<NativeInputWindowHandle> handle = android_server_InputWindowHandle_getHandle(
+    sp<NativeInputWindowHandle> handle = android_view_InputWindowHandle_getHandle(
             env, inputWindow);
     handle->updateInfo();
 
@@ -348,6 +368,15 @@
     transaction->setInputWindowInfo(ctrl, *handle->getInfo());
 }
 
+static void nativeTransferTouchFocus(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jobject fromTokenObj, jobject toTokenObj) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+    sp<IBinder> fromToken(ibinderForJavaObject(env, fromTokenObj));
+    sp<IBinder> toToken(ibinderForJavaObject(env, toTokenObj));
+    transaction->transferTouchFocus(fromToken, toToken);
+}
+
 static void nativeSetColor(JNIEnv* env, jclass clazz, jlong transactionObj,
         jlong nativeObject, jfloatArray fColor) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -429,8 +458,9 @@
 static jboolean nativeSetDisplayedContentSamplingEnabled(JNIEnv* env, jclass clazz,
         jobject tokenObj, jboolean enable, jint componentMask, jint maxFrames) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
-    return SurfaceComposerClient::setDisplayContentSamplingEnabled(
+    status_t rc = SurfaceComposerClient::setDisplayContentSamplingEnabled(
             token, enable, componentMask, maxFrames);
+    return rc == OK;
 }
 
 static jobject nativeGetDisplayedContentSample(JNIEnv* env, jclass clazz, jobject tokenObj,
@@ -632,6 +662,27 @@
     return static_cast<jint>(SurfaceComposerClient::getActiveColorMode(token));
 }
 
+static jintArray nativeGetCompositionDataspaces(JNIEnv* env, jclass) {
+    ui::Dataspace defaultDataspace, wcgDataspace;
+    ui::PixelFormat defaultPixelFormat, wcgPixelFormat;
+    if (SurfaceComposerClient::getCompositionPreference(&defaultDataspace,
+                                                        &defaultPixelFormat,
+                                                        &wcgDataspace,
+                                                        &wcgPixelFormat) != NO_ERROR) {
+        return nullptr;
+    }
+    jintArray array = env->NewIntArray(2);
+    if (array == nullptr) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
+        return nullptr;
+    }
+    jint* arrayValues = env->GetIntArrayElements(array, 0);
+    arrayValues[0] = static_cast<jint>(defaultDataspace);
+    arrayValues[1] = static_cast<jint>(wcgDataspace);
+    env->ReleaseIntArrayElements(array, arrayValues, 0);
+    return array;
+}
+
 static jboolean nativeSetActiveColorMode(JNIEnv* env, jclass,
         jobject tokenObj, jint colorMode) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
@@ -650,6 +701,10 @@
     if (t.duration() > 100ms) ALOGD("Excessive delay in setPowerMode()");
 }
 
+static jboolean nativeGetProtectedContentSupport(JNIEnv* env, jclass) {
+    return static_cast<jboolean>(SurfaceComposerClient::getProtectedContentSupport());
+}
+
 static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) {
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     status_t err = ctrl->clearLayerFrameStats();
@@ -833,13 +888,13 @@
 
 static void nativeReparent(JNIEnv* env, jclass clazz, jlong transactionObj,
         jlong nativeObject,
-        jobject newParentObject) {
+        jlong newParentObject) {
     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
-    sp<IBinder> parentHandle = ibinderForJavaObject(env, newParentObject);
+    auto newParent = reinterpret_cast<SurfaceControl *>(newParentObject);
 
     {
         auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
-        transaction->reparent(ctrl, parentHandle);
+        transaction->reparent(ctrl, newParent != NULL ? newParent->getHandle() : NULL);
     }
 }
 
@@ -860,14 +915,6 @@
     transaction->setOverrideScalingMode(ctrl, scalingMode);
 }
 
-static void nativeDestroyInTransaction(JNIEnv* env, jclass clazz,
-                                       jlong transactionObj,
-                                       jlong nativeObject) {
-    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
-    auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
-    transaction->destroySurface(ctrl);
-}
-
 static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     return javaObjectForIBinder(env, ctrl->getHandle());
@@ -907,6 +954,17 @@
     return reinterpret_cast<jlong>(surface.get());
 }
 
+static jlong nativeCopyFromSurfaceControl(JNIEnv* env, jclass clazz, jlong surfaceControlNativeObj) {
+    sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
+    if (surface == nullptr) {
+        return 0;
+    }
+
+    sp<SurfaceControl> newSurface = new SurfaceControl(surface);
+    newSurface->incStrong((void *)nativeCreate);
+    return reinterpret_cast<jlong>(newSurface.get());
+}
+
 static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
         jlong nativeObject, jobject parcelObj) {
     Parcel* parcel = parcelForJavaObject(env, parcelObj);
@@ -915,7 +973,9 @@
         return;
     }
     SurfaceControl* const self = reinterpret_cast<SurfaceControl *>(nativeObject);
-    self->writeToParcel(parcel);
+    if (self != nullptr) {
+        self->writeToParcel(parcel);
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -925,6 +985,8 @@
             (void*)nativeCreate },
     {"nativeReadFromParcel", "(Landroid/os/Parcel;)J",
             (void*)nativeReadFromParcel },
+    {"nativeCopyFromSurfaceControl", "(J)J" ,
+            (void*)nativeCopyFromSurfaceControl },
     {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V",
             (void*)nativeWriteToParcel },
     {"nativeRelease", "(J)V",
@@ -999,6 +1061,8 @@
             (void*)nativeGetActiveColorMode},
     {"nativeSetActiveColorMode", "(Landroid/os/IBinder;I)Z",
             (void*)nativeSetActiveColorMode},
+    {"nativeGetCompositionDataspaces", "()[I",
+            (void*)nativeGetCompositionDataspaces},
     {"nativeGetHdrCapabilities", "(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities;",
             (void*)nativeGetHdrCapabilities },
     {"nativeClearContentFrameStats", "(J)Z",
@@ -1011,20 +1075,20 @@
             (void*)nativeGetAnimationFrameStats },
     {"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V",
             (void*)nativeSetDisplayPowerMode },
+    {"nativeGetProtectedContentSupport", "()Z",
+            (void*)nativeGetProtectedContentSupport },
     {"nativeDeferTransactionUntil", "(JJLandroid/os/IBinder;J)V",
             (void*)nativeDeferTransactionUntil },
     {"nativeDeferTransactionUntilSurface", "(JJJJ)V",
             (void*)nativeDeferTransactionUntilSurface },
     {"nativeReparentChildren", "(JJLandroid/os/IBinder;)V",
             (void*)nativeReparentChildren } ,
-    {"nativeReparent", "(JJLandroid/os/IBinder;)V",
+    {"nativeReparent", "(JJJ)V",
             (void*)nativeReparent },
     {"nativeSeverChildren", "(JJ)V",
             (void*)nativeSeverChildren } ,
     {"nativeSetOverrideScalingMode", "(JJI)V",
             (void*)nativeSetOverrideScalingMode },
-    {"nativeDestroy", "(JJ)V",
-            (void*)nativeDestroyInTransaction },
     {"nativeGetHandle", "(J)Landroid/os/IBinder;",
             (void*)nativeGetHandle },
     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIZI)Landroid/graphics/GraphicBuffer;",
@@ -1032,7 +1096,9 @@
     {"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/graphics/Rect;F)Landroid/graphics/GraphicBuffer;",
             (void*)nativeCaptureLayers },
     {"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V",
-     (void*)nativeSetInputWindowInfo },
+            (void*)nativeSetInputWindowInfo },
+    {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)V",
+            (void*)nativeTransferTouchFocus },
     {"nativeGetDisplayedContentSamplingAttributes",
             "(Landroid/os/IBinder;)Landroid/hardware/display/DisplayedContentSamplingAttributes;",
             (void*)nativeGetDisplayedContentSamplingAttributes },
@@ -1041,6 +1107,8 @@
     {"nativeGetDisplayedContentSample",
             "(Landroid/os/IBinder;JJ)Landroid/hardware/display/DisplayedContentSample;",
             (void*)nativeGetDisplayedContentSample },
+    {"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
+            (void*)nativeSetGeometry }
 };
 
 int register_android_view_SurfaceControl(JNIEnv* env)
diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp
index 30c0030..191f748 100644
--- a/core/jni/android_view_SurfaceSession.cpp
+++ b/core/jni/android_view_SurfaceSession.cpp
@@ -46,13 +46,6 @@
     return reinterpret_cast<jlong>(client);
 }
 
-static jlong nativeCreateScoped(JNIEnv* env, jclass clazz, jlong surfaceObject) {
-    Surface *parent = reinterpret_cast<Surface*>(surfaceObject);
-    SurfaceComposerClient* client = new SurfaceComposerClient(parent->getIGraphicBufferProducer());
-    client->incStrong((void*)nativeCreate);
-    return reinterpret_cast<jlong>(client);
-}
-
 static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
     SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr);
     client->decStrong((void*)nativeCreate);
@@ -67,8 +60,6 @@
     /* name, signature, funcPtr */
     { "nativeCreate", "()J",
             (void*)nativeCreate },
-    { "nativeCreateScoped", "(J)J",
-            (void*)nativeCreateScoped },
     { "nativeDestroy", "(J)V",
             (void*)nativeDestroy },
     { "nativeKill", "(J)V",
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 5a8ab3c..318ec9b 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -48,6 +48,7 @@
 #include <FrameInfo.h>
 #include <FrameMetricsObserver.h>
 #include <IContextFactory.h>
+#include <Picture.h>
 #include <Properties.h>
 #include <PropertyValuesAnimatorSet.h>
 #include <RenderNode.h>
@@ -71,6 +72,11 @@
 } gFrameMetricsObserverClassInfo;
 
 struct {
+    jclass clazz;
+    jmethodID invokePictureCapturedCallback;
+} gHardwareRenderer;
+
+struct {
     jmethodID onFrameDraw;
 } gFrameDrawingCallback;
 
@@ -905,6 +911,27 @@
     jobject mObject;
 };
 
+static void android_view_ThreadedRenderer_setPictureCapturedCallbackJNI(JNIEnv* env,
+        jobject clazz, jlong proxyPtr, jobject pictureCallback) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    if (!pictureCallback) {
+        proxy->setPictureCapturedCallback(nullptr);
+    } else {
+        JavaVM* vm = nullptr;
+        LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
+        auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(vm,
+                env->NewGlobalRef(pictureCallback));
+        proxy->setPictureCapturedCallback([globalCallbackRef](sk_sp<SkPicture>&& picture) {
+            JNIEnv* env = getenv(globalCallbackRef->vm());
+            Picture* wrapper = new Picture{std::move(picture)};
+            env->CallStaticVoidMethod(gHardwareRenderer.clazz,
+                    gHardwareRenderer.invokePictureCapturedCallback,
+                    static_cast<jlong>(reinterpret_cast<intptr_t>(wrapper)),
+                    globalCallbackRef->object());
+        });
+    }
+}
+
 static void android_view_ThreadedRenderer_setFrameCallback(JNIEnv* env,
         jobject clazz, jlong proxyPtr, jobject frameCallback) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -1145,6 +1172,8 @@
     { "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
     { "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode},
     { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds},
+    { "nSetPictureCaptureCallback", "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V",
+            (void*) android_view_ThreadedRenderer_setPictureCapturedCallbackJNI },
     { "nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V",
             (void*)android_view_ThreadedRenderer_setFrameCallback},
     { "nSetFrameCompleteCallback", "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V",
@@ -1198,6 +1227,13 @@
     gFrameMetricsObserverClassInfo.timingDataBuffer = GetFieldIDOrDie(
             env, metricsClass, "mTimingData", "[J");
 
+    jclass hardwareRenderer = FindClassOrDie(env,
+            "android/graphics/HardwareRenderer");
+    gHardwareRenderer.clazz = reinterpret_cast<jclass>(env->NewGlobalRef(hardwareRenderer));
+    gHardwareRenderer.invokePictureCapturedCallback = GetStaticMethodIDOrDie(env, hardwareRenderer,
+            "invokePictureCapturedCallback",
+            "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V");
+
     jclass frameCallbackClass = FindClassOrDie(env,
             "android/graphics/HardwareRenderer$FrameDrawingCallback");
     gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass,
diff --git a/core/jni/com_android_internal_os_AtomicDirectory.cpp b/core/jni/com_android_internal_os_AtomicDirectory.cpp
new file mode 100644
index 0000000..50b2288
--- /dev/null
+++ b/core/jni/com_android_internal_os_AtomicDirectory.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 <nativehelper/ScopedUtfChars.h>
+#include "jni.h"
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+static jint com_android_internal_os_AtomicDirectory_getDirectoryFd(JNIEnv* env,
+        jobject /*clazz*/, jstring path) {
+    ScopedUtfChars path8(env, path);
+    if (path8.c_str() == NULL) {
+        ALOGE("Invalid path: %s", path8.c_str());
+        return -1;
+    }
+    int fd;
+    if ((fd = TEMP_FAILURE_RETRY(open(path8.c_str(), O_DIRECTORY | O_RDONLY))) == -1) {
+        ALOGE("Cannot open directory %s, error: %s\n", path8.c_str(), strerror(errno));
+        return -1;
+    }
+    return fd;
+}
+
+static void com_android_internal_os_AtomicDirectory_fsyncDirectoryFd(JNIEnv* env,
+        jobject /*clazz*/, jint fd) {
+    if (TEMP_FAILURE_RETRY(fsync(fd)) == -1) {
+        ALOGE("Cannot fsync directory %d, error: %s\n", fd, strerror(errno));
+    }
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gRegisterMethods[] = {
+    /* name, signature, funcPtr */
+    { "fsyncDirectoryFd",
+      "(I)V",
+       (void*) com_android_internal_os_AtomicDirectory_fsyncDirectoryFd
+    },
+    { "getDirectoryFd",
+      "(Ljava/lang/String;)I",
+       (void*) com_android_internal_os_AtomicDirectory_getDirectoryFd
+    },
+};
+
+int register_com_android_internal_os_AtomicDirectory(JNIEnv* env) {
+    return RegisterMethodsOrDie(env, "com/android/internal/os/AtomicDirectory",
+            gRegisterMethods, NELEM(gRegisterMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index a8e1427..8681d4b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -14,19 +14,32 @@
  * limitations under the License.
  */
 
+/*
+ * Disable optimization of this file if we are compiling with the address
+ * sanitizer.  This is a mitigation for b/122921367 and can be removed once the
+ * bug is fixed.
+ */
+#if __has_feature(address_sanitizer)
+#pragma clang optimize off
+#endif
+
 #define LOG_TAG "Zygote"
 
 // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
 #include <sys/mount.h>
 #include <linux/fs.h>
 
+#include <array>
+#include <atomic>
 #include <functional>
 #include <list>
 #include <optional>
 #include <sstream>
 #include <string>
+#include <string_view>
 
 #include <android/fdsan.h>
+#include <arpa/inet.h>
 #include <fcntl.h>
 #include <grp.h>
 #include <inttypes.h>
@@ -37,9 +50,11 @@
 #include <stdlib.h>
 #include <sys/capability.h>
 #include <sys/cdefs.h>
+#include <sys/eventfd.h>
 #include <sys/personality.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
@@ -47,19 +62,20 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include "android-base/logging.h"
+#include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
 #include <cutils/fs.h>
 #include <cutils/multiuser.h>
-#include <cutils/sched_policy.h>
 #include <private/android_filesystem_config.h>
 #include <utils/String8.h>
 #include <selinux/android.h>
 #include <seccomp_policy.h>
 #include <stats_event_list.h>
 #include <processgroup/processgroup.h>
+#include <processgroup/sched_policy.h>
 
 #include "core_jni_helpers.h"
 #include <nativehelper/JNIHelp.h>
@@ -72,6 +88,9 @@
 
 namespace {
 
+// TODO (chriswailes): Add a function to initialize native Zygote data.
+// TODO (chriswailes): Fix mixed indentation style (2 and 4 spaces).
+
 using namespace std::placeholders;
 
 using android::String8;
@@ -83,9 +102,13 @@
 #define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \
                               append(StringPrintf(__VA_ARGS__))
 
+// This type is duplicated in fd_utils.h
+typedef const std::function<void(std::string)>& fail_fn_t;
+
 static pid_t gSystemServerPid = 0;
 
 static const char kIsolatedStorage[] = "persist.sys.isolated_storage";
+static const char kIsolatedStorageSnapshot[] = "sys.isolated_storage_snapshot";
 static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
 static jclass gZygoteClass;
 static jmethodID gCallPostForkSystemServerHooks;
@@ -93,14 +116,161 @@
 
 static bool g_is_security_enforced = true;
 
+/**
+ * The maximum number of characters (not including a null terminator) that a
+ * process name may contain.
+ */
+static constexpr size_t MAX_NAME_LENGTH = 15;
+
+/**
+ * The prefix string for environmental variables storing socket FDs created by
+ * init.
+ */
+
+static constexpr std::string_view ANDROID_SOCKET_PREFIX("ANDROID_SOCKET_");
+
+/**
+ * The file descriptor for the Zygote socket opened by init.
+ */
+
+static int gZygoteSocketFD = -1;
+
+/**
+ * The file descriptor for the Blastula pool socket opened by init.
+ */
+
+static int gBlastulaPoolSocketFD = -1;
+
+/**
+ * The number of Blastulas currently in this Zygote's pool.
+ */
+static std::atomic_uint32_t gBlastulaPoolCount = 0;
+
+/**
+ * Event file descriptor used to communicate reaped blastulas to the
+ * ZygoteServer.
+ */
+static int gBlastulaPoolEventFD = -1;
+
+/**
+ * The maximum value that the gBlastulaPoolMax variable may take.  This value
+ * is a mirror of Zygote.BLASTULA_POOL_MAX_LIMIT
+ */
+static constexpr int BLASTULA_POOL_MAX_LIMIT = 10;
+
+/**
+ * A helper class containing accounting information for Blastulas.
+ */
+class BlastulaTableEntry {
+ public:
+  struct EntryStorage {
+    int32_t pid;
+    int32_t read_pipe_fd;
+
+    bool operator!=(const EntryStorage& other) {
+      return pid != other.pid || read_pipe_fd != other.read_pipe_fd;
+    }
+  };
+
+ private:
+  static constexpr EntryStorage INVALID_ENTRY_VALUE = {-1, -1};
+
+  std::atomic<EntryStorage> mStorage;
+  static_assert(decltype(mStorage)::is_always_lock_free);
+
+ public:
+  constexpr BlastulaTableEntry() : mStorage(INVALID_ENTRY_VALUE) {}
+
+  /**
+   * If the provided PID matches the one stored in this entry, the entry will
+   * be invalidated and the associated file descriptor will be closed.  If the
+   * PIDs don't match nothing will happen.
+   *
+   * @param pid The ID of the process who's entry we want to clear.
+   * @return True if the entry was cleared; false otherwise
+   */
+  bool ClearForPID(int32_t pid) {
+    EntryStorage storage = mStorage.load();
+
+    if (storage.pid == pid) {
+      /*
+       * There are three possible outcomes from this compare-and-exchange:
+       *   1) It succeeds, in which case we close the FD
+       *   2) It fails and the new value is INVALID_ENTRY_VALUE, in which case
+       *      the entry has already been cleared.
+       *   3) It fails and the new value isn't INVALID_ENTRY_VALUE, in which
+       *      case the entry has already been cleared and re-used.
+       *
+       * In all three cases the goal of the caller has been met and we can
+       * return true.
+       */
+      if (mStorage.compare_exchange_strong(storage, INVALID_ENTRY_VALUE)) {
+        close(storage.read_pipe_fd);
+      }
+
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * @return A copy of the data stored in this entry.
+   */
+  std::optional<EntryStorage> GetValues() {
+    EntryStorage storage = mStorage.load();
+
+    if (storage != INVALID_ENTRY_VALUE) {
+      return storage;
+    } else {
+      return std::nullopt;
+    }
+  }
+
+  /**
+   * Sets the entry to the given values if it is currently invalid.
+   *
+   * @param pid  The process ID for the new entry.
+   * @param read_pipe_fd  The read end of the blastula control pipe for this
+   * process.
+   * @return True if the entry was set; false otherwise.
+   */
+  bool SetIfInvalid(int32_t pid, int32_t read_pipe_fd) {
+    EntryStorage new_value_storage;
+
+    new_value_storage.pid = pid;
+    new_value_storage.read_pipe_fd = read_pipe_fd;
+
+    EntryStorage expected = INVALID_ENTRY_VALUE;
+
+    return mStorage.compare_exchange_strong(expected, new_value_storage);
+  }
+};
+
+/**
+ * A table containing information about the Blastulas currently in the pool.
+ *
+ * Multiple threads may be attempting to modify the table, either from the
+ * signal handler or from the ZygoteServer poll loop.  Atomic loads/stores in
+ * the BlastulaTableEntry class prevent data races during these concurrent
+ * operations.
+ */
+static std::array<BlastulaTableEntry, BLASTULA_POOL_MAX_LIMIT> gBlastulaTable;
+
+/**
+ * The list of open zygote file descriptors.
+ */
+static FileDescriptorTable* gOpenFdTable = nullptr;
+
 // Must match values in com.android.internal.os.Zygote.
 enum MountExternalKind {
   MOUNT_EXTERNAL_NONE = 0,
   MOUNT_EXTERNAL_DEFAULT = 1,
   MOUNT_EXTERNAL_READ = 2,
   MOUNT_EXTERNAL_WRITE = 3,
-  MOUNT_EXTERNAL_INSTALLER = 4,
-  MOUNT_EXTERNAL_FULL = 5,
+  MOUNT_EXTERNAL_LEGACY = 4,
+  MOUNT_EXTERNAL_INSTALLER = 5,
+  MOUNT_EXTERNAL_FULL = 6,
 };
 
 // Must match values in com.android.internal.os.Zygote.
@@ -108,6 +278,9 @@
   DEBUG_ENABLE_JDWP = 1,
 };
 
+// Forward declaration so we don't have to move the signal handler.
+static bool RemoveBlastulaTableEntry(pid_t blastula_pid);
+
 static void RuntimeAbort(JNIEnv* env, int line, const char* msg) {
   std::ostringstream oss;
   oss << __FILE__ << ":" << line << ": " << msg;
@@ -118,6 +291,7 @@
 static void SigChldHandler(int /*signal_number*/) {
   pid_t pid;
   int status;
+  int64_t blastulas_removed = 0;
 
   // It's necessary to save and restore the errno during this function.
   // Since errno is stored per thread, changing it here modifies the errno
@@ -151,6 +325,11 @@
       ALOGE("Exit zygote because system server (%d) has terminated", pid);
       kill(getpid(), SIGKILL);
     }
+
+    // Check to see if the PID is in the blastula pool and remove it if it is.
+    if (RemoveBlastulaTableEntry(pid)) {
+      ++blastulas_removed;
+    }
   }
 
   // Note that we shouldn't consider ECHILD an error because
@@ -159,6 +338,15 @@
     ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno));
   }
 
+  if (blastulas_removed > 0) {
+    if (write(gBlastulaPoolEventFD, &blastulas_removed, sizeof(blastulas_removed)) == -1) {
+      // If this write fails something went terribly wrong.  We will now kill
+      // the zygote and let the system bring it back up.
+      ALOGE("Zygote failed to write to blastula pool event FD: %s", strerror(errno));
+      kill(getpid(), SIGKILL);
+    }
+  }
+
   errno = saved_errno;
 }
 
@@ -183,13 +371,13 @@
   struct sigaction sig_chld = {};
   sig_chld.sa_handler = SigChldHandler;
 
-  if (sigaction(SIGCHLD, &sig_chld, NULL) < 0) {
+  if (sigaction(SIGCHLD, &sig_chld, nullptr) < 0) {
     ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
   }
 
   struct sigaction sig_hup = {};
   sig_hup.sa_handler = SIG_IGN;
-  if (sigaction(SIGHUP, &sig_hup, NULL) < 0) {
+  if (sigaction(SIGHUP, &sig_hup, nullptr) < 0) {
     ALOGW("Error setting SIGHUP handler: %s", strerror(errno));
   }
 }
@@ -200,64 +388,57 @@
   memset(&sa, 0, sizeof(sa));
   sa.sa_handler = SIG_DFL;
 
-  if (sigaction(SIGCHLD, &sa, NULL) < 0) {
+  if (sigaction(SIGCHLD, &sa, nullptr) < 0) {
     ALOGW("Error unsetting SIGCHLD handler: %s", strerror(errno));
   }
 }
 
 // Calls POSIX setgroups() using the int[] object as an argument.
-// A NULL argument is tolerated.
-static bool SetGids(JNIEnv* env, jintArray javaGids, std::string* error_msg) {
-  if (javaGids == NULL) {
-    return true;
+// A nullptr argument is tolerated.
+static void SetGids(JNIEnv* env, jintArray managed_gids, fail_fn_t fail_fn) {
+  if (managed_gids == nullptr) {
+    return;
   }
 
-  ScopedIntArrayRO gids(env, javaGids);
-  if (gids.get() == NULL) {
-    *error_msg = CREATE_ERROR("Getting gids int array failed");
-    return false;
-  }
-  int rc = setgroups(gids.size(), reinterpret_cast<const gid_t*>(&gids[0]));
-  if (rc == -1) {
-    *error_msg = CREATE_ERROR("setgroups failed: %s, gids.size=%zu", strerror(errno), gids.size());
-    return false;
+  ScopedIntArrayRO gids(env, managed_gids);
+  if (gids.get() == nullptr) {
+    fail_fn(CREATE_ERROR("Getting gids int array failed"));
   }
 
-  return true;
+  if (setgroups(gids.size(), reinterpret_cast<const gid_t*>(&gids[0])) == -1) {
+    fail_fn(CREATE_ERROR("setgroups failed: %s, gids.size=%zu", strerror(errno), gids.size()));
+  }
 }
 
 // Sets the resource limits via setrlimit(2) for the values in the
 // two-dimensional array of integers that's passed in. The second dimension
-// contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
+// contains a tuple of length 3: (resource, rlim_cur, rlim_max). nullptr is
 // treated as an empty array.
-static bool SetRLimits(JNIEnv* env, jobjectArray javaRlimits, std::string* error_msg) {
-  if (javaRlimits == NULL) {
-    return true;
+static void SetRLimits(JNIEnv* env, jobjectArray managed_rlimits, fail_fn_t fail_fn) {
+  if (managed_rlimits == nullptr) {
+    return;
   }
 
   rlimit rlim;
   memset(&rlim, 0, sizeof(rlim));
 
-  for (int i = 0; i < env->GetArrayLength(javaRlimits); ++i) {
-    ScopedLocalRef<jobject> javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i));
-    ScopedIntArrayRO javaRlimit(env, reinterpret_cast<jintArray>(javaRlimitObject.get()));
-    if (javaRlimit.size() != 3) {
-      *error_msg = CREATE_ERROR("rlimits array must have a second dimension of size 3");
-      return false;
+  for (int i = 0; i < env->GetArrayLength(managed_rlimits); ++i) {
+    ScopedLocalRef<jobject>
+        managed_rlimit_object(env, env->GetObjectArrayElement(managed_rlimits, i));
+    ScopedIntArrayRO rlimit_handle(env, reinterpret_cast<jintArray>(managed_rlimit_object.get()));
+
+    if (rlimit_handle.size() != 3) {
+      fail_fn(CREATE_ERROR("rlimits array must have a second dimension of size 3"));
     }
 
-    rlim.rlim_cur = javaRlimit[1];
-    rlim.rlim_max = javaRlimit[2];
+    rlim.rlim_cur = rlimit_handle[1];
+    rlim.rlim_max = rlimit_handle[2];
 
-    int rc = setrlimit(javaRlimit[0], &rlim);
-    if (rc == -1) {
-      *error_msg = CREATE_ERROR("setrlimit(%d, {%ld, %ld}) failed", javaRlimit[0], rlim.rlim_cur,
-            rlim.rlim_max);
-      return false;
+    if (setrlimit(rlimit_handle[0], &rlim) == -1) {
+      fail_fn(CREATE_ERROR("setrlimit(%d, {%ld, %ld}) failed",
+                           rlimit_handle[0], rlim.rlim_cur, rlim.rlim_max));
     }
   }
-
-  return true;
 }
 
 static void EnableDebugger() {
@@ -303,7 +484,7 @@
   mallopt(M_DECAY_TIME, 1);
 }
 
-static void SetUpSeccompFilter(uid_t uid) {
+static void SetUpSeccompFilter(uid_t uid, bool is_child_zygote) {
   if (!g_is_security_enforced) {
     ALOGI("seccomp disabled by setenforce 0");
     return;
@@ -311,38 +492,36 @@
 
   // Apply system or app filter based on uid.
   if (uid >= AID_APP_START) {
-    set_app_seccomp_filter();
+    if (is_child_zygote) {
+      set_app_zygote_seccomp_filter();
+    } else {
+      set_app_seccomp_filter();
+    }
   } else {
     set_system_seccomp_filter();
   }
 }
 
-static bool EnableKeepCapabilities(std::string* error_msg) {
-  int rc = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
-  if (rc == -1) {
-    *error_msg = CREATE_ERROR("prctl(PR_SET_KEEPCAPS) failed: %s", strerror(errno));
-    return false;
+static void EnableKeepCapabilities(fail_fn_t fail_fn) {
+  if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
+    fail_fn(CREATE_ERROR("prctl(PR_SET_KEEPCAPS) failed: %s", strerror(errno)));
   }
-  return true;
 }
 
-static bool DropCapabilitiesBoundingSet(std::string* error_msg) {
-  for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
-    int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
-    if (rc == -1) {
+static void DropCapabilitiesBoundingSet(fail_fn_t fail_fn) {
+  for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {;
+    if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0) == -1) {
       if (errno == EINVAL) {
         ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
               "your kernel is compiled with file capabilities support");
       } else {
-        *error_msg = CREATE_ERROR("prctl(PR_CAPBSET_DROP, %d) failed: %s", i, strerror(errno));
-        return false;
+        fail_fn(CREATE_ERROR("prctl(PR_CAPBSET_DROP, %d) failed: %s", i, strerror(errno)));
       }
     }
   }
-  return true;
 }
 
-static bool SetInheritable(uint64_t inheritable, std::string* error_msg) {
+static void SetInheritable(uint64_t inheritable, fail_fn_t fail_fn) {
   __user_cap_header_struct capheader;
   memset(&capheader, 0, sizeof(capheader));
   capheader.version = _LINUX_CAPABILITY_VERSION_3;
@@ -350,23 +529,19 @@
 
   __user_cap_data_struct capdata[2];
   if (capget(&capheader, &capdata[0]) == -1) {
-    *error_msg = CREATE_ERROR("capget failed: %s", strerror(errno));
-    return false;
+    fail_fn(CREATE_ERROR("capget failed: %s", strerror(errno)));
   }
 
   capdata[0].inheritable = inheritable;
   capdata[1].inheritable = inheritable >> 32;
 
   if (capset(&capheader, &capdata[0]) == -1) {
-    *error_msg = CREATE_ERROR("capset(inh=%" PRIx64 ") failed: %s", inheritable, strerror(errno));
-    return false;
+    fail_fn(CREATE_ERROR("capset(inh=%" PRIx64 ") failed: %s", inheritable, strerror(errno)));
   }
-
-  return true;
 }
 
-static bool SetCapabilities(uint64_t permitted, uint64_t effective, uint64_t inheritable,
-                            std::string* error_msg) {
+static void SetCapabilities(uint64_t permitted, uint64_t effective, uint64_t inheritable,
+                            fail_fn_t fail_fn) {
   __user_cap_header_struct capheader;
   memset(&capheader, 0, sizeof(capheader));
   capheader.version = _LINUX_CAPABILITY_VERSION_3;
@@ -382,27 +557,23 @@
   capdata[1].inheritable = inheritable >> 32;
 
   if (capset(&capheader, &capdata[0]) == -1) {
-    *error_msg = CREATE_ERROR("capset(perm=%" PRIx64 ", eff=%" PRIx64 ", inh=%" PRIx64 ") "
-                              "failed: %s", permitted, effective, inheritable, strerror(errno));
-    return false;
+    fail_fn(CREATE_ERROR("capset(perm=%" PRIx64 ", eff=%" PRIx64 ", inh=%" PRIx64 ") "
+                         "failed: %s", permitted, effective, inheritable, strerror(errno)));
   }
-  return true;
 }
 
-static bool SetSchedulerPolicy(std::string* error_msg) {
+static void SetSchedulerPolicy(fail_fn_t fail_fn) {
   errno = -set_sched_policy(0, SP_DEFAULT);
   if (errno != 0) {
-    *error_msg = CREATE_ERROR("set_sched_policy(0, SP_DEFAULT) failed: %s", strerror(errno));
-    return false;
+    fail_fn(CREATE_ERROR("set_sched_policy(0, SP_DEFAULT) failed: %s", strerror(errno)));
   }
-  return true;
 }
 
 static int UnmountTree(const char* path) {
     size_t path_len = strlen(path);
 
     FILE* fp = setmntent("/proc/mounts", "r");
-    if (fp == NULL) {
+    if (fp == nullptr) {
         ALOGE("Error opening /proc/mounts: %s", strerror(errno));
         return -errno;
     }
@@ -411,7 +582,7 @@
     // reverse order to give us the best chance of success.
     std::list<std::string> toUnmount;
     mntent* mentry;
-    while ((mentry = getmntent(fp)) != NULL) {
+    while ((mentry = getmntent(fp)) != nullptr) {
         if (strncmp(mentry->mnt_dir, path, path_len) == 0) {
             toUnmount.push_front(std::string(mentry->mnt_dir));
         }
@@ -426,56 +597,55 @@
     return 0;
 }
 
-static bool createPkgSandbox(uid_t uid, const std::string& package_name, std::string* error_msg) {
+static void CreatePkgSandbox(uid_t uid, const std::string& package_name, fail_fn_t fail_fn) {
     // Create /mnt/user/0/package/<package-name>
     userid_t user_id = multiuser_get_user_id(uid);
     std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id);
     if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0751, AID_ROOT, AID_ROOT) != 0) {
-        *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str());
-        return false;
+        fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str()));
     }
+
     StringAppendF(&pkg_sandbox_dir, "/package");
     if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
-        *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str());
-        return false;
+        fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str()));
     }
+
     StringAppendF(&pkg_sandbox_dir, "/%s", package_name.c_str());
     if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0755, uid, uid) != 0) {
-        *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str());
-        return false;
+        fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str()));
     }
-    return true;
 }
 
-static bool bindMount(const std::string& sourceDir, const std::string& targetDir,
-        std::string* error_msg) {
-    if (TEMP_FAILURE_RETRY(mount(sourceDir.c_str(), targetDir.c_str(),
-            nullptr, MS_BIND | MS_REC, nullptr)) == -1) {
-        *error_msg = CREATE_ERROR("Failed to mount %s to %s: %s",
-                sourceDir.c_str(), targetDir.c_str(), strerror(errno));
-        return false;
+static void BindMount(const std::string& sourceDir, const std::string& targetDir,
+                      fail_fn_t fail_fn) {
+    if (TEMP_FAILURE_RETRY(mount(sourceDir.c_str(), targetDir.c_str(), nullptr,
+                                 MS_BIND | MS_REC, nullptr)) == -1) {
+        fail_fn(CREATE_ERROR("Failed to mount %s to %s: %s",
+                             sourceDir.c_str(), targetDir.c_str(), strerror(errno)));
     }
-    if (TEMP_FAILURE_RETRY(mount(nullptr, targetDir.c_str(),
-            nullptr, MS_SLAVE | MS_REC, nullptr)) == -1) {
-        *error_msg = CREATE_ERROR("Failed to set MS_SLAVE for %s", targetDir.c_str());
-        return false;
+
+    if (TEMP_FAILURE_RETRY(mount(nullptr, targetDir.c_str(), nullptr,
+                                 MS_SLAVE | MS_REC, nullptr)) == -1) {
+        fail_fn(CREATE_ERROR("Failed to set MS_SLAVE for %s", targetDir.c_str()));
     }
-    return true;
 }
 
-static bool mountPkgSpecificDir(const std::string& mntSourceRoot,
-        const std::string& mntTargetRoot, const std::string& packageName,
-        const char* dirName, std::string* error_msg) {
+static void MountPkgSpecificDir(const std::string& mntSourceRoot,
+                                const std::string& mntTargetRoot,
+                                const std::string& packageName,
+                                const char* dirName,
+                                fail_fn_t fail_fn) {
     std::string mntSourceDir = StringPrintf("%s/Android/%s/%s",
             mntSourceRoot.c_str(), dirName, packageName.c_str());
     std::string mntTargetDir = StringPrintf("%s/Android/%s/%s",
             mntTargetRoot.c_str(), dirName, packageName.c_str());
-    return bindMount(mntSourceDir, mntTargetDir, error_msg);
+
+    BindMount(mntSourceDir, mntTargetDir, fail_fn);
 }
 
-static bool preparePkgSpecificDirs(const std::vector<std::string>& packageNames,
-        const std::vector<std::string>& volumeLabels, bool mountAllObbs,
-        userid_t userId, std::string* error_msg) {
+static void PreparePkgSpecificDirs(const std::vector<std::string>& packageNames,
+                                   const std::vector<std::string>& volumeLabels,
+                                   bool mountAllObbs, userid_t userId, fail_fn_t fail_fn) {
     for (auto& label : volumeLabels) {
         std::string mntSource = StringPrintf("/mnt/runtime/write/%s", label.c_str());
         std::string mntTarget = StringPrintf("/storage/%s", label.c_str());
@@ -483,28 +653,29 @@
             StringAppendF(&mntSource, "/%d", userId);
             StringAppendF(&mntTarget, "/%d", userId);
         }
+
         for (auto& package : packageNames) {
-            mountPkgSpecificDir(mntSource, mntTarget, package, "data", error_msg);
-            mountPkgSpecificDir(mntSource, mntTarget, package, "media", error_msg);
+            MountPkgSpecificDir(mntSource, mntTarget, package, "data", fail_fn);
+            MountPkgSpecificDir(mntSource, mntTarget, package, "media", fail_fn);
             if (!mountAllObbs) {
-                mountPkgSpecificDir(mntSource, mntTarget, package, "obb", error_msg);
+                MountPkgSpecificDir(mntSource, mntTarget, package, "obb", fail_fn);
             }
         }
+
         if (mountAllObbs) {
             StringAppendF(&mntSource, "/Android/obb");
             StringAppendF(&mntTarget, "/Android/obb");
-            bindMount(mntSource, mntTarget, error_msg);
+            BindMount(mntSource, mntTarget, fail_fn);
         }
     }
-    return true;
 }
 
 // Create a private mount namespace and bind mount appropriate emulated
 // storage for the given user.
-static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
-        bool force_mount_namespace, std::string* error_msg, const std::string& package_name,
+static void MountEmulatedStorage(uid_t uid, jint mount_mode,
+        bool force_mount_namespace, const std::string& package_name,
         const std::vector<std::string>& packages_for_uid,
-        const std::vector<std::string>& visible_vol_ids) {
+        const std::vector<std::string>& visible_vol_ids, fail_fn_t fail_fn) {
     // See storage config details at http://source.android.com/tech/storage/
 
     String8 storageSource;
@@ -516,84 +687,82 @@
         storageSource = "/mnt/runtime/write";
     } else if (mount_mode == MOUNT_EXTERNAL_NONE && !force_mount_namespace) {
         // Sane default of no storage visible
-        return true;
+        return;
     }
 
     // Create a second private mount namespace for our process
     if (unshare(CLONE_NEWNS) == -1) {
-        *error_msg = CREATE_ERROR("Failed to unshare(): %s", strerror(errno));
-        return false;
+        fail_fn(CREATE_ERROR("Failed to unshare(): %s", strerror(errno)));
     }
 
     // Handle force_mount_namespace with MOUNT_EXTERNAL_NONE.
     if (mount_mode == MOUNT_EXTERNAL_NONE) {
-        return true;
+        return;
     }
 
-    if (GetBoolProperty(kIsolatedStorage, false)) {
-        if (mount_mode == MOUNT_EXTERNAL_FULL) {
-            storageSource = "/mnt/runtime/write";
+    if (GetBoolProperty(kIsolatedStorageSnapshot, GetBoolProperty(kIsolatedStorage, false))) {
+        if (mount_mode == MOUNT_EXTERNAL_FULL || mount_mode == MOUNT_EXTERNAL_LEGACY) {
+            storageSource = (mount_mode == MOUNT_EXTERNAL_FULL)
+                    ? "/mnt/runtime/full" : "/mnt/runtime/write";
             if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
-                    NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
-                *error_msg = CREATE_ERROR("Failed to mount %s to /storage: %s",
-                                          storageSource.string(),
-                                          strerror(errno));
-                return false;
+                                         NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
+                fail_fn(CREATE_ERROR("Failed to mount %s to /storage: %s",
+                                     storageSource.string(),
+                                     strerror(errno)));
             }
 
             // Mount user-specific symlink helper into place
             userid_t user_id = multiuser_get_user_id(uid);
             const String8 userSource(String8::format("/mnt/user/%d", user_id));
             if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) {
-                *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", userSource.string());
-                return false;
+                fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s (%s)",
+                                     userSource.string(), strerror(errno)));
             }
-            if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self",
-                    NULL, MS_BIND, NULL)) == -1) {
-                *error_msg = CREATE_ERROR("Failed to mount %s to /storage/self: %s",
-                                          userSource.string(),
-                                          strerror(errno));
-                return false;
+
+            if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self", nullptr, MS_BIND,
+                                         nullptr)) == -1) {
+                fail_fn(CREATE_ERROR("Failed to mount %s to /storage/self: %s",
+                                     userSource.string(),
+                                     strerror(errno)));
             }
         } else {
             if (package_name.empty()) {
-                return true;
+                return;
             }
+
             userid_t user_id = multiuser_get_user_id(uid);
-            std::string pkgSandboxDir = StringPrintf("/mnt/user/%d/package/%s",
-                    user_id, package_name.c_str());
+            std::string pkgSandboxDir =
+                StringPrintf("/mnt/user/%d/package/%s", user_id, package_name.c_str());
             struct stat sb;
             bool sandboxAlreadyCreated = true;
             if (TEMP_FAILURE_RETRY(lstat(pkgSandboxDir.c_str(), &sb)) == -1) {
                 if (errno == ENOENT) {
                     ALOGD("Sandbox not yet created for %s", pkgSandboxDir.c_str());
                     sandboxAlreadyCreated = false;
-                    if (!createPkgSandbox(uid, package_name, error_msg)) {
-                        return false;
-                    }
+                    CreatePkgSandbox(uid, package_name, fail_fn);
                 } else {
-                    ALOGE("Failed to lstat %s", pkgSandboxDir.c_str());
-                    return false;
+                    fail_fn(CREATE_ERROR("Failed to lstat %s: %s",
+                                         pkgSandboxDir.c_str(), strerror(errno)));
                 }
             }
+
             if (TEMP_FAILURE_RETRY(mount(pkgSandboxDir.c_str(), "/storage",
-                    nullptr, MS_BIND | MS_REC | MS_SLAVE, nullptr)) == -1) {
-                *error_msg = CREATE_ERROR("Failed to mount %s to /storage: %s",
-                        pkgSandboxDir.c_str(), strerror(errno));
-                return false;
+                                         nullptr, MS_BIND | MS_REC | MS_SLAVE, nullptr)) == -1) {
+                fail_fn(CREATE_ERROR("Failed to mount %s to /storage: %s",
+                                     pkgSandboxDir.c_str(), strerror(errno)));
             }
+
             if (access("/storage/obb_mount", F_OK) == 0) {
                 if (mount_mode != MOUNT_EXTERNAL_INSTALLER) {
                     remove("/storage/obb_mount");
                 }
             } else {
                 if (mount_mode == MOUNT_EXTERNAL_INSTALLER) {
-                    int fd = TEMP_FAILURE_RETRY(open("/storage/obb_mount",
-                            O_RDWR | O_CREAT, 0660));
+                    int fd =
+                        TEMP_FAILURE_RETRY(open("/storage/obb_mount", O_RDWR | O_CREAT, 0660));
                     if (fd == -1) {
-                        *error_msg = CREATE_ERROR("Couldn't create /storage/obb_mount: %s",
-                                strerror(errno));
-                        return false;
+                        fail_fn(CREATE_ERROR("Couldn't create /storage/obb_mount: %s",
+                                             strerror(errno)));
                     }
                     close(fd);
                 }
@@ -602,38 +771,32 @@
             // pkg specific directories. Otherwise, leave as is and bind mounts will be taken
             // care of by vold later.
             if (sandboxAlreadyCreated) {
-                if (!preparePkgSpecificDirs(packages_for_uid, visible_vol_ids,
-                        mount_mode == MOUNT_EXTERNAL_INSTALLER, user_id, error_msg)) {
-                    return false;
-                }
+                PreparePkgSpecificDirs(packages_for_uid, visible_vol_ids,
+                    mount_mode == MOUNT_EXTERNAL_INSTALLER, user_id, fail_fn);
             }
         }
     } else {
-        if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
-                NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
-            *error_msg = CREATE_ERROR("Failed to mount %s to /storage: %s",
-                                      storageSource.string(),
-                                      strerror(errno));
-            return false;
+        if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage", nullptr,
+                                     MS_BIND | MS_REC | MS_SLAVE, nullptr)) == -1) {
+            fail_fn(CREATE_ERROR("Failed to mount %s to /storage: %s",
+                                 storageSource.string(),
+                                 strerror(errno)));
         }
 
         // Mount user-specific symlink helper into place
         userid_t user_id = multiuser_get_user_id(uid);
         const String8 userSource(String8::format("/mnt/user/%d", user_id));
         if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) {
-            *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", userSource.string());
-            return false;
+          fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s",
+                               userSource.string()));
         }
+
         if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self",
-                NULL, MS_BIND, NULL)) == -1) {
-            *error_msg = CREATE_ERROR("Failed to mount %s to /storage/self: %s",
-                                      userSource.string(),
-                                      strerror(errno));
-            return false;
+                               nullptr, MS_BIND, nullptr)) == -1) {
+          fail_fn(CREATE_ERROR("Failed to mount %s to /storage/self: %s",
+                               userSource.string(), strerror(errno)));
         }
     }
-
-    return true;
 }
 
 static bool NeedsNoRandomizeWorkaround() {
@@ -661,55 +824,45 @@
 // descriptor (if any) is closed via dup2(), replacing it with a valid
 // (open) descriptor to /dev/null.
 
-static bool DetachDescriptors(JNIEnv* env, jintArray fdsToClose, std::string* error_msg) {
-  if (!fdsToClose) {
-    return true;
-  }
-  jsize count = env->GetArrayLength(fdsToClose);
-  ScopedIntArrayRO ar(env, fdsToClose);
-  if (ar.get() == NULL) {
-    *error_msg = "Bad fd array";
-    return false;
-  }
-  jsize i;
-  int devnull;
-  for (i = 0; i < count; i++) {
-    devnull = open("/dev/null", O_RDWR);
-    if (devnull < 0) {
-      *error_msg = std::string("Failed to open /dev/null: ").append(strerror(errno));
-      return false;
+static void DetachDescriptors(JNIEnv* env,
+                              const std::vector<int>& fds_to_close,
+                              fail_fn_t fail_fn) {
+
+  if (fds_to_close.size() > 0) {
+    android::base::unique_fd devnull_fd(open("/dev/null", O_RDWR));
+    if (devnull_fd == -1) {
+      fail_fn(std::string("Failed to open /dev/null: ").append(strerror(errno)));
     }
-    ALOGV("Switching descriptor %d to /dev/null: %s", ar[i], strerror(errno));
-    if (dup2(devnull, ar[i]) < 0) {
-      *error_msg = StringPrintf("Failed dup2() on descriptor %d: %s", ar[i], strerror(errno));
-      return false;
+
+    for (int fd : fds_to_close) {
+      ALOGV("Switching descriptor %d to /dev/null", fd);
+      if (dup2(devnull_fd, fd) == -1) {
+        fail_fn(StringPrintf("Failed dup2() on descriptor %d: %s", fd, strerror(errno)));
+      }
     }
-    close(devnull);
   }
-  return true;
 }
 
-void SetThreadName(const char* thread_name) {
+void SetThreadName(const std::string& thread_name) {
   bool hasAt = false;
   bool hasDot = false;
-  const char* s = thread_name;
-  while (*s) {
-    if (*s == '.') {
+
+  for (const char str_el : thread_name) {
+    if (str_el == '.') {
       hasDot = true;
-    } else if (*s == '@') {
+    } else if (str_el == '@') {
       hasAt = true;
     }
-    s++;
   }
-  const int len = s - thread_name;
-  if (len < 15 || hasAt || !hasDot) {
-    s = thread_name;
-  } else {
-    s = thread_name + len - 15;
+
+  const char* name_start_ptr = thread_name.c_str();
+  if (thread_name.length() >= MAX_NAME_LENGTH && !hasAt && hasDot) {
+    name_start_ptr += thread_name.length() - MAX_NAME_LENGTH;
   }
+
   // pthread_setname_np fails rather than truncating long strings.
   char buf[16];       // MAX_TASK_COMM_LEN=16 is hard-coded into bionic
-  strlcpy(buf, s, sizeof(buf)-1);
+  strlcpy(buf, name_start_ptr, sizeof(buf) - 1);
   errno = pthread_setname_np(pthread_self(), buf);
   if (errno != 0) {
     ALOGW("Unable to set the name of current thread to '%s': %s", buf, strerror(errno));
@@ -718,28 +871,16 @@
   android::base::SetDefaultTag(buf);
 }
 
-// The list of open zygote file descriptors.
-static FileDescriptorTable* gOpenFdTable = NULL;
-
-static bool FillFileDescriptorVector(JNIEnv* env,
-                                     jintArray managed_fds,
-                                     std::vector<int>* fds,
-                                     std::string* error_msg) {
-  CHECK(fds != nullptr);
-  if (managed_fds != nullptr) {
-    ScopedIntArrayRO ar(env, managed_fds);
-    if (ar.get() == nullptr) {
-      *error_msg = "Bad fd array";
-      return false;
-    }
-    fds->reserve(ar.size());
-    for (size_t i = 0; i < ar.size(); ++i) {
-      fds->push_back(ar[i]);
-    }
-  }
-  return true;
-}
-
+/**
+ * A failure function used to report fatal errors to the managed runtime.  This
+ * function is often curried with the process name information and then passed
+ * to called functions.
+ *
+ * @param env  Managed runtime environment
+ * @param process_name  A native representation of the process name
+ * @param managed_process_name  A managed representation of the process name
+ * @param msg  The error message to be reported
+ */
 [[noreturn]]
 static void ZygoteFailure(JNIEnv* env,
                           const char* process_name,
@@ -760,12 +901,25 @@
   __builtin_unreachable();
 }
 
+/**
+ * A helper method for converting managed strings to native strings.  A fatal
+ * error is generated if a problem is encountered in extracting a non-null
+ * string.
+ *
+ * @param env  Managed runtime environment
+ * @param process_name  A native representation of the process name
+ * @param managed_process_name  A managed representation of the process name
+ * @param managed_string  The managed string to extract
+ *
+ * @return An empty option if the managed string is null.  A optional-wrapped
+ * string otherwise.
+ */
 static std::optional<std::string> ExtractJString(JNIEnv* env,
                                                  const char* process_name,
                                                  jstring managed_process_name,
                                                  jstring managed_string) {
   if (managed_string == nullptr) {
-    return std::optional<std::string>();
+    return std::nullopt;
   } else {
     ScopedUtfChars scoped_string_chars(env, managed_string);
 
@@ -777,15 +931,124 @@
   }
 }
 
-// Utility routine to fork a zygote.
-static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
-                        jintArray managed_fds_to_close, jintArray managed_fds_to_ignore) {
-  SetSignalHandlers();
+/**
+ * A helper method for converting managed string arrays to native vectors.  A
+ * fatal error is generated if a problem is encountered in extracting a non-null array.
+ *
+ * @param env  Managed runtime environment
+ * @param process_name  A native representation of the process name
+ * @param managed_process_name  A managed representation of the process name
+ * @param managed_array  The managed integer array to extract
+ *
+ * @return An empty option if the managed array is null.  A optional-wrapped
+ * vector otherwise.
+ */
+static std::optional<std::vector<int>> ExtractJIntArray(JNIEnv* env,
+                                                        const char* process_name,
+                                                        jstring managed_process_name,
+                                                        jintArray managed_array) {
+  if (managed_array == nullptr) {
+    return std::nullopt;
+  } else {
+    ScopedIntArrayRO managed_array_handle(env, managed_array);
 
-  // Block SIGCHLD prior to fork.
-  sigset_t sigchld;
-  sigemptyset(&sigchld);
-  sigaddset(&sigchld, SIGCHLD);
+    if (managed_array_handle.get() != nullptr) {
+      std::vector<int> native_array;
+      native_array.reserve(managed_array_handle.size());
+
+      for (size_t array_index = 0; array_index < managed_array_handle.size(); ++array_index) {
+        native_array.push_back(managed_array_handle[array_index]);
+      }
+
+      return std::move(native_array);
+
+    } else {
+      ZygoteFailure(env, process_name, managed_process_name, "Failed to extract JIntArray.");
+    }
+  }
+}
+
+/**
+ * A helper method for converting managed string arrays to native vectors.  A
+ * fatal error is generated if a problem is encountered in extracting a non-null array.
+ *
+ * @param env  Managed runtime environment
+ * @param process_name  A native representation of the process name
+ * @param managed_process_name  A managed representation of the process name
+ * @param managed_array  The managed string array to extract
+ *
+ * @return An empty option if the managed array is null.  A optional-wrapped
+ * vector otherwise.
+ */
+static std::optional<std::vector<std::string>> ExtractJStringArray(JNIEnv* env,
+                                                                   const char* process_name,
+                                                                   jstring managed_process_name,
+                                                                   jobjectArray managed_array) {
+  if (managed_array == nullptr) {
+    return std::nullopt;
+  } else {
+    jsize element_count = env->GetArrayLength(managed_array);
+    std::vector<std::string> native_string_vector;
+    native_string_vector.reserve(element_count);
+
+    for (jsize array_index = 0; array_index < element_count; ++array_index) {
+      jstring managed_string = (jstring) env->GetObjectArrayElement(managed_array, array_index);
+      auto native_string = ExtractJString(env, process_name, managed_process_name, managed_string);
+
+      if (LIKELY(native_string.has_value())) {
+        native_string_vector.emplace_back(std::move(native_string.value()));
+      } else {
+        ZygoteFailure(env, process_name, managed_process_name,
+                      "Null string found in managed string array.");
+      }
+    }
+
+    return std::move(native_string_vector);
+  }
+}
+
+/**
+ * A utility function for blocking signals.
+ *
+ * @param signum  Signal number to block
+ * @param fail_fn  Fatal error reporting function
+ *
+ * @see ZygoteFailure
+ */
+static void BlockSignal(int signum, fail_fn_t fail_fn) {
+  sigset_t sigs;
+  sigemptyset(&sigs);
+  sigaddset(&sigs, signum);
+
+  if (sigprocmask(SIG_BLOCK, &sigs, nullptr) == -1) {
+    fail_fn(CREATE_ERROR("Failed to block signal %s: %s", strsignal(signum), strerror(errno)));
+  }
+}
+
+
+/**
+ * A utility function for unblocking signals.
+ *
+ * @param signum  Signal number to unblock
+ * @param fail_fn  Fatal error reporting function
+ *
+ * @see ZygoteFailure
+ */
+static void UnblockSignal(int signum, fail_fn_t fail_fn) {
+  sigset_t sigs;
+  sigemptyset(&sigs);
+  sigaddset(&sigs, signum);
+
+  if (sigprocmask(SIG_UNBLOCK, &sigs, nullptr) == -1) {
+    fail_fn(CREATE_ERROR("Failed to un-block signal %s: %s", strsignal(signum), strerror(errno)));
+  }
+}
+
+// Utility routine to fork a process from the zygote.
+static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
+                        const std::vector<int>& fds_to_close,
+                        const std::vector<int>& fds_to_ignore) {
+  SetSignalHandlers();
 
   // Curry a failure function.
   auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote",
@@ -796,9 +1059,7 @@
   // This would cause failures because the FDs are not whitelisted.
   //
   // Note that the zygote process is single threaded at this point.
-  if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) {
-    fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
-  }
+  BlockSignal(SIGCHLD, fail_fn);
 
   // Close any logging related FDs before we start evaluating the list of
   // file descriptors.
@@ -808,19 +1069,10 @@
   // If this is the first fork for this zygote, create the open FD table.  If
   // it isn't, we just need to check whether the list of open files has changed
   // (and it shouldn't in the normal case).
-  std::string error_msg;
-  std::vector<int> fds_to_ignore;
-  if (!FillFileDescriptorVector(env, managed_fds_to_ignore, &fds_to_ignore, &error_msg)) {
-    fail_fn(error_msg);
-  }
-
   if (gOpenFdTable == nullptr) {
-    gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, &error_msg);
-    if (gOpenFdTable == nullptr) {
-      fail_fn(error_msg);
-    }
-  } else if (!gOpenFdTable->Restat(fds_to_ignore, &error_msg)) {
-    fail_fn(error_msg);
+    gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn);
+  } else {
+    gOpenFdTable->Restat(fds_to_ignore, fail_fn);
   }
 
   android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level();
@@ -832,24 +1084,18 @@
     PreApplicationInit();
 
     // Clean up any descriptors which must be closed immediately
-    if (!DetachDescriptors(env, managed_fds_to_close, &error_msg)) {
-      fail_fn(error_msg);
-    }
+    DetachDescriptors(env, fds_to_close, fail_fn);
 
     // Re-open all remaining open file descriptors so that they aren't shared
     // with the zygote across a fork.
-    if (!gOpenFdTable->ReopenOrDetach(&error_msg)) {
-      fail_fn(error_msg);
-    }
+    gOpenFdTable->ReopenOrDetach(fail_fn);
 
     // Turn fdsan back on.
     android_fdsan_set_error_level(fdsan_error_level);
   }
 
   // We blocked SIGCHLD prior to a fork, we unblock it here.
-  if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
-    fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
-  }
+  UnblockSignal(SIGCHLD, fail_fn);
 
   return pid;
 }
@@ -864,10 +1110,9 @@
                              jstring managed_app_data_dir, jstring managed_package_name,
                              jobjectArray managed_pacakges_for_uid,
                              jobjectArray managed_visible_vol_ids) {
-  auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote",
-                           managed_nice_name, _1);
-  auto extract_fn = std::bind(ExtractJString, env, is_system_server ? "system_server" : "zygote",
-                              managed_nice_name, _1);
+  const char* process_name = is_system_server ? "system_server" : "zygote";
+  auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1);
+  auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
 
   auto se_info = extract_fn(managed_se_info);
   auto nice_name = extract_fn(managed_nice_name);
@@ -875,22 +1120,14 @@
   auto app_data_dir = extract_fn(managed_app_data_dir);
   auto package_name = extract_fn(managed_package_name);
 
-  std::string error_msg;
-
   // Keep capabilities across UID change, unless we're staying root.
   if (uid != 0) {
-    if (!EnableKeepCapabilities(&error_msg)) {
-      fail_fn(error_msg);
-    }
+    EnableKeepCapabilities(fail_fn);
   }
 
-  if (!SetInheritable(permitted_capabilities, &error_msg)) {
-    fail_fn(error_msg);
-  }
+  SetInheritable(permitted_capabilities, fail_fn);
 
-  if (!DropCapabilitiesBoundingSet(&error_msg)) {
-    fail_fn(error_msg);
-  }
+  DropCapabilitiesBoundingSet(fail_fn);
 
   bool use_native_bridge = !is_system_server &&
                            instruction_set.has_value() &&
@@ -915,56 +1152,21 @@
     }
   }
 
-  std::vector<std::string> packages_for_uid;
-  if (managed_pacakges_for_uid != nullptr) {
-    jsize count = env->GetArrayLength(managed_pacakges_for_uid);
-    for (jsize package_index = 0; package_index < count; ++package_index) {
-      jstring managed_package_for_uid =
-          (jstring) env->GetObjectArrayElement(managed_pacakges_for_uid, package_index);
+  std::vector<std::string> packages_for_uid =
+      ExtractJStringArray(env, process_name, managed_nice_name, managed_pacakges_for_uid).
+      value_or(std::vector<std::string>());
 
-      auto package_for_uid = extract_fn(managed_package_for_uid);
-      if (LIKELY(package_for_uid.has_value())) {
-        packages_for_uid.emplace_back(std::move(package_for_uid.value()));
-      } else {
-        fail_fn("Null string found in managed packages_for_uid.");
-      }
-    }
-  }
+  std::vector<std::string> visible_vol_ids =
+      ExtractJStringArray(env, process_name, managed_nice_name, managed_visible_vol_ids).
+      value_or(std::vector<std::string>());
 
-  std::vector<std::string> visible_vol_ids;
-  if (managed_visible_vol_ids != nullptr) {
-    jsize count = env->GetArrayLength(managed_visible_vol_ids);
-    for (jsize vol_id_index = 0; vol_id_index < count; ++vol_id_index) {
-      jstring managed_visible_vol_id =
-          (jstring) env->GetObjectArrayElement(managed_visible_vol_ids, vol_id_index);
-
-      auto visible_vol_id = extract_fn(managed_visible_vol_id);
-      if (LIKELY(visible_vol_id.has_value())) {
-        visible_vol_ids.emplace_back(std::move(visible_vol_id.value()));
-      } else {
-        fail_fn("Null string found in managed visible_vol_ids.");
-      }
-    }
-  }
-
-  if (!MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg,
-                            package_name.value(), packages_for_uid, visible_vol_ids)) {
-    ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno));
-    if (errno == ENOTCONN || errno == EROFS) {
-      // When device is actively encrypting, we get ENOTCONN here
-      // since FUSE was mounted before the framework restarted.
-      // When encrypted device is booting, we get EROFS since
-      // FUSE hasn't been created yet by init.
-      // In either case, continue without external storage.
-    } else {
-      fail_fn(error_msg);
-    }
-  }
+  MountEmulatedStorage(uid, mount_external, use_native_bridge, package_name.value(),
+                       packages_for_uid, visible_vol_ids, fail_fn);
 
   // If this zygote isn't root, it won't be able to create a process group,
   // since the directory is owned by root.
   if (!is_system_server && getuid() == 0) {
-    int rc = createProcessGroup(uid, getpid());
+    const int rc = createProcessGroup(uid, getpid());
     if (rc == -EROFS) {
       ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
     } else if (rc != 0) {
@@ -972,13 +1174,8 @@
     }
   }
 
-  if (!SetGids(env, gids, &error_msg)) {
-    fail_fn(error_msg);
-  }
-
-  if (!SetRLimits(env, rlimits, &error_msg)) {
-    fail_fn(error_msg);
-  }
+  SetGids(env, gids, fail_fn);
+  SetRLimits(env, rlimits, fail_fn);
 
   if (use_native_bridge) {
     // Due to the logic behind use_native_bridge we know that both app_data_dir
@@ -996,7 +1193,7 @@
   // alternative is to call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that
   // breaks SELinux domain transition (see b/71859146).  As the result,
   // privileged syscalls used below still need to be accessible in app process.
-  SetUpSeccompFilter(uid);
+  SetUpSeccompFilter(uid, is_child_zygote);
 
   if (setresuid(uid, uid, uid) == -1) {
     fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
@@ -1037,14 +1234,9 @@
     }
   }
 
-  if (!SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities,
-                       &error_msg)) {
-    fail_fn(error_msg);
-  }
+  SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities, fail_fn);
 
-  if (!SetSchedulerPolicy(&error_msg)) {
-    fail_fn(error_msg);
-  }
+  SetSchedulerPolicy(fail_fn);
 
   const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr;
   const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
@@ -1057,7 +1249,7 @@
   // Make it easier to debug audit logs by setting the main thread's name to the
   // nice name rather than "app_process".
   if (nice_name.has_value()) {
-    SetThreadName(nice_name.value().c_str());
+    SetThreadName(nice_name.value());
   } else if (is_system_server) {
     SetThreadName("system_server");
   }
@@ -1070,6 +1262,7 @@
     if (env->ExceptionCheck()) {
       fail_fn("Error calling post fork system server hooks.");
     }
+
     // TODO(oth): Remove hardcoded label here (b/117874058).
     static const char* kSystemServerLabel = "u:r:system_server:s0";
     if (selinux_android_setcon(kSystemServerLabel) != 0) {
@@ -1173,6 +1366,74 @@
 
   return capabilities & GetEffectiveCapabilityMask(env);
 }
+
+/**
+ * Adds the given information about a newly created blastula to the Zygote's
+ * blastula table.
+ *
+ * @param blastula_pid  Process ID of the newly created blastula
+ * @param read_pipe_fd  File descriptor for the read end of the blastula
+ * reporting pipe.  Used in the ZygoteServer poll loop to track blastula
+ * specialization.
+ */
+static void AddBlastulaTableEntry(pid_t blastula_pid, int read_pipe_fd) {
+  static int sBlastulaTableInsertIndex = 0;
+
+  int search_index = sBlastulaTableInsertIndex;
+
+  do {
+    if (gBlastulaTable[search_index].SetIfInvalid(blastula_pid, read_pipe_fd)) {
+      // Start our next search right after where we finished this one.
+      sBlastulaTableInsertIndex = (search_index + 1) % gBlastulaTable.size();
+
+      return;
+    }
+
+    search_index = (search_index + 1) % gBlastulaTable.size();
+  } while (search_index != sBlastulaTableInsertIndex);
+
+  // Much like money in the banana stand, there should always be an entry
+  // in the blastula table.
+  __builtin_unreachable();
+}
+
+/**
+ * Invalidates the entry in the BlastulaTable corresponding to the provided
+ * process ID if it is present.  If an entry was removed the blastula pool
+ * count is decremented.
+ *
+ * @param blastula_pid  Process ID of the blastula entry to invalidate
+ * @return True if an entry was invalidated; false otherwise
+ */
+static bool RemoveBlastulaTableEntry(pid_t blastula_pid) {
+  for (BlastulaTableEntry& entry : gBlastulaTable) {
+    if (entry.ClearForPID(blastula_pid)) {
+      --gBlastulaPoolCount;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+/**
+ * @return A vector of the read pipe FDs for each of the active blastulas.
+ */
+std::vector<int> MakeBlastulaPipeReadFDVector() {
+  std::vector<int> fd_vec;
+  fd_vec.reserve(gBlastulaTable.size());
+
+  for (BlastulaTableEntry& entry : gBlastulaTable) {
+    auto entry_values = entry.GetValues();
+
+    if (entry_values.has_value()) {
+      fd_vec.push_back(entry_values.value().read_pipe_fd);
+    }
+  }
+
+  return fd_vec;
+}
+
 }  // anonymous namespace
 
 namespace android {
@@ -1191,12 +1452,35 @@
         JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
         jint runtime_flags, jobjectArray rlimits,
         jint mount_external, jstring se_info, jstring nice_name,
-        jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote,
+        jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
         jstring instruction_set, jstring app_data_dir, jstring package_name,
         jobjectArray packages_for_uid, jobjectArray visible_vol_ids) {
     jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
 
+    if (UNLIKELY(managed_fds_to_close == nullptr)) {
+      ZygoteFailure(env, "zygote", nice_name, "Zygote received a null fds_to_close vector.");
+    }
+
+    std::vector<int> fds_to_close =
+        ExtractJIntArray(env, "zygote", nice_name, managed_fds_to_close).value();
+    std::vector<int> fds_to_ignore =
+        ExtractJIntArray(env, "zygote", nice_name, managed_fds_to_ignore)
+            .value_or(std::vector<int>());
+
+    std::vector<int> blastula_pipes = MakeBlastulaPipeReadFDVector();
+
+    fds_to_close.insert(fds_to_close.end(), blastula_pipes.begin(), blastula_pipes.end());
+    fds_to_ignore.insert(fds_to_ignore.end(), blastula_pipes.begin(), blastula_pipes.end());
+
+    fds_to_close.push_back(gBlastulaPoolSocketFD);
+
+    if (gBlastulaPoolEventFD != -1) {
+      fds_to_close.push_back(gBlastulaPoolEventFD);
+      fds_to_ignore.push_back(gBlastulaPoolEventFD);
+    }
+
     pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore);
+
     if (pid == 0) {
       SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
                        capabilities, capabilities,
@@ -1211,9 +1495,19 @@
         JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
         jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
         jlong effective_capabilities) {
+  std::vector<int> fds_to_close(MakeBlastulaPipeReadFDVector()),
+                   fds_to_ignore(fds_to_close);
+
+  fds_to_close.push_back(gBlastulaPoolSocketFD);
+
+  if (gBlastulaPoolEventFD != -1) {
+    fds_to_close.push_back(gBlastulaPoolEventFD);
+    fds_to_ignore.push_back(gBlastulaPoolEventFD);
+  }
+
   pid_t pid = ForkCommon(env, true,
-                         /* managed_fds_to_close= */ nullptr,
-                         /* managed_fds_to_ignore= */ nullptr);
+                         fds_to_close,
+                         fds_to_ignore);
   if (pid == 0) {
       SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
                        permitted_capabilities, effective_capabilities,
@@ -1247,6 +1541,52 @@
   return pid;
 }
 
+/**
+ * A JNI function that forks a blastula from the Zygote while ensuring proper
+ * file descriptor hygiene.
+ *
+ * @param env  Managed runtime environment
+ * @param read_pipe_fd  The read FD for the blastula reporting pipe.  Manually closed by blastlas
+ * in managed code.
+ * @param write_pipe_fd  The write FD for the blastula reporting pipe.  Manually closed by the
+ * zygote in managed code.
+ * @param managed_session_socket_fds  A list of anonymous session sockets that must be ignored by
+ * the FD hygiene code and automatically "closed" in the new blastula.
+ * @return
+ */
+static jint com_android_internal_os_Zygote_nativeForkBlastula(JNIEnv* env, jclass,
+    jint read_pipe_fd, jint write_pipe_fd, jintArray managed_session_socket_fds) {
+  std::vector<int> fds_to_close(MakeBlastulaPipeReadFDVector()),
+                   fds_to_ignore(fds_to_close);
+
+  std::vector<int> session_socket_fds =
+      ExtractJIntArray(env, "blastula", nullptr, managed_session_socket_fds)
+          .value_or(std::vector<int>());
+
+  // The Blastula Pool Event FD is created during the initialization of the
+  // blastula pool and should always be valid here.
+
+  fds_to_close.push_back(gZygoteSocketFD);
+  fds_to_close.push_back(gBlastulaPoolEventFD);
+  fds_to_close.insert(fds_to_close.end(), session_socket_fds.begin(), session_socket_fds.end());
+
+  fds_to_ignore.push_back(gZygoteSocketFD);
+  fds_to_ignore.push_back(gBlastulaPoolSocketFD);
+  fds_to_ignore.push_back(gBlastulaPoolEventFD);
+  fds_to_ignore.push_back(read_pipe_fd);
+  fds_to_ignore.push_back(write_pipe_fd);
+  fds_to_ignore.insert(fds_to_ignore.end(), session_socket_fds.begin(), session_socket_fds.end());
+
+  pid_t blastula_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore);
+
+  if (blastula_pid != 0) {
+    ++gBlastulaPoolCount;
+    AddBlastulaTableEntry(blastula_pid, read_pipe_fd);
+  }
+
+  return blastula_pid;
+}
+
 static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork(
         JNIEnv* env, jclass, jstring path) {
     ScopedUtfChars path_native(env, path);
@@ -1295,6 +1635,134 @@
     UnmountTree("/storage");
 }
 
+static void com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter(
+        JNIEnv* env, jclass, jint uidGidMin, jint uidGidMax) {
+  if (!g_is_security_enforced) {
+    ALOGI("seccomp disabled by setenforce 0");
+    return;
+  }
+
+  bool installed = install_setuidgid_seccomp_filter(uidGidMin, uidGidMax);
+  if (!installed) {
+      RuntimeAbort(env, __LINE__, "Could not install setuid/setgid seccomp filter.");
+  }
+}
+
+/**
+ * Called from a blastula to specialize the process for a specific application.
+ *
+ * @param env  Managed runtime environment
+ * @param uid  User ID of the new application
+ * @param gid  Group ID of the new application
+ * @param gids  Extra groups that the process belongs to
+ * @param runtime_flags  Flags for changing the behavior of the managed runtime
+ * @param rlimits  Resource limits
+ * @param mount_external  The mode (read/write/normal) that external storage will be mounted with
+ * @param se_info  SELinux policy information
+ * @param nice_name  New name for this process
+ * @param is_child_zygote  If the process is to become a WebViewZygote
+ * @param instruction_set  The instruction set expected/requested by the new application
+ * @param app_data_dir  Path to the application's data directory
+ */
+static void com_android_internal_os_Zygote_nativeSpecializeBlastula(
+    JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
+    jint runtime_flags, jobjectArray rlimits,
+    jint mount_external, jstring se_info, jstring nice_name,
+    jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir,
+    jstring package_name, jobjectArray packages_for_uid, jobjectArray visible_vol_ids) {
+  jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
+
+  SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
+                   capabilities, capabilities,
+                   mount_external, se_info, nice_name, false,
+                   is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
+                   package_name, packages_for_uid, visible_vol_ids);
+}
+
+/**
+ * A helper method for fetching socket file descriptors that were opened by init from the
+ * environment.
+ *
+ * @param env  Managed runtime environment
+ * @param is_primary  If this process is the primary or secondary Zygote; used to compute the name
+ * of the environment variable storing the file descriptors.
+ */
+static void com_android_internal_os_Zygote_nativeGetSocketFDs(JNIEnv* env, jclass,
+                                                              jboolean is_primary) {
+  std::string android_socket_prefix(ANDROID_SOCKET_PREFIX);
+  std::string env_var_name = android_socket_prefix + (is_primary ? "zygote" : "zygote_secondary");
+  char* env_var_val = getenv(env_var_name.c_str());
+
+  if (env_var_val != nullptr) {
+    gZygoteSocketFD = atoi(env_var_val);
+    ALOGV("Zygote:zygoteSocketFD = %d", gZygoteSocketFD);
+  } else {
+    ALOGE("Unable to fetch Zygote socket file descriptor");
+  }
+
+  env_var_name = android_socket_prefix + (is_primary ? "blastula_pool" : "blastula_pool_secondary");
+  env_var_val = getenv(env_var_name.c_str());
+
+  if (env_var_val != nullptr) {
+    gBlastulaPoolSocketFD = atoi(env_var_val);
+    ALOGV("Zygote:blastulaPoolSocketFD = %d", gBlastulaPoolSocketFD);
+  } else {
+    ALOGE("Unable to fetch Blastula pool socket file descriptor");
+  }
+}
+
+/**
+ * @param env  Managed runtime environment
+ * @return  A managed array of raw file descriptors for the read ends of the blastula reporting
+ * pipes.
+ */
+static jintArray com_android_internal_os_Zygote_nativeGetBlastulaPipeFDs(JNIEnv* env, jclass) {
+  std::vector<int> blastula_fds = MakeBlastulaPipeReadFDVector();
+
+  jintArray managed_blastula_fds = env->NewIntArray(blastula_fds.size());
+  env->SetIntArrayRegion(managed_blastula_fds, 0, blastula_fds.size(), blastula_fds.data());
+
+  return managed_blastula_fds;
+}
+
+/**
+ * A JNI wrapper around RemoveBlastulaTableEntry.
+ *
+ * @param env  Managed runtime environment
+ * @param blastula_pid  Process ID of the blastula entry to invalidate
+ * @return  True if an entry was invalidated; false otherwise.
+ */
+static jboolean com_android_internal_os_Zygote_nativeRemoveBlastulaTableEntry(JNIEnv* env, jclass,
+                                                                              jint blastula_pid) {
+  return RemoveBlastulaTableEntry(blastula_pid);
+}
+
+/**
+ * Creates the blastula pool event FD if it doesn't exist and returns it.  This is used by the
+ * ZygoteServer poll loop to know when to re-fill the blastula pool.
+ *
+ * @param env  Managed runtime environment
+ * @return A raw event file descriptor used to communicate (from the signal handler) when the
+ * Zygote receives a SIGCHLD for a blastula
+ */
+static jint com_android_internal_os_Zygote_nativeGetBlastulaPoolEventFD(JNIEnv* env, jclass) {
+  if (gBlastulaPoolEventFD == -1) {
+    if ((gBlastulaPoolEventFD = eventfd(0, 0)) == -1) {
+      ZygoteFailure(env, "zygote", nullptr, StringPrintf("Unable to create eventfd: %s", strerror(errno)));
+    }
+  }
+
+  return gBlastulaPoolEventFD;
+}
+
+/**
+ * @param env  Managed runtime environment
+ * @return The number of blastulas currently in the blastula pool
+ */
+static jint com_android_internal_os_Zygote_nativeGetBlastulaPoolCount(JNIEnv* env, jclass) {
+  return gBlastulaPoolCount;
+}
+
 static const JNINativeMethod gMethods[] = {
     { "nativeSecurityInit", "()V",
       (void *) com_android_internal_os_Zygote_nativeSecurityInit },
@@ -1308,7 +1776,24 @@
     { "nativeUnmountStorageOnInit", "()V",
       (void *) com_android_internal_os_Zygote_nativeUnmountStorageOnInit },
     { "nativePreApplicationInit", "()V",
-      (void *) com_android_internal_os_Zygote_nativePreApplicationInit }
+      (void *) com_android_internal_os_Zygote_nativePreApplicationInit },
+    { "nativeInstallSeccompUidGidFilter", "(II)V",
+      (void *) com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter },
+    { "nativeForkBlastula", "(II[I)I",
+      (void *) com_android_internal_os_Zygote_nativeForkBlastula },
+    { "nativeSpecializeBlastula",
+      "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
+      (void *) com_android_internal_os_Zygote_nativeSpecializeBlastula },
+    { "nativeGetSocketFDs", "(Z)V",
+      (void *) com_android_internal_os_Zygote_nativeGetSocketFDs },
+    { "nativeGetBlastulaPipeFDs", "()[I",
+      (void *) com_android_internal_os_Zygote_nativeGetBlastulaPipeFDs },
+    { "nativeRemoveBlastulaTableEntry", "(I)Z",
+      (void *) com_android_internal_os_Zygote_nativeRemoveBlastulaTableEntry },
+    { "nativeGetBlastulaPoolEventFD", "()I",
+      (void *) com_android_internal_os_Zygote_nativeGetBlastulaPoolEventFD },
+    { "nativeGetBlastulaPoolCount", "()I",
+      (void *) com_android_internal_os_Zygote_nativeGetBlastulaPoolCount }
 };
 
 int register_com_android_internal_os_Zygote(JNIEnv* env) {
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index bd87dcc..53dde80 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -33,9 +33,13 @@
 
 // Static whitelist of open paths that the zygote is allowed to keep open.
 static const char* kPathWhitelist[] = {
+  "/apex/com.android.conscrypt/javalib/conscrypt.jar",
+  "/apex/com.android.media/javalib/updatable-media.jar",
   "/dev/null",
   "/dev/socket/zygote",
   "/dev/socket/zygote_secondary",
+  "/dev/socket/blastula_pool",
+  "/dev/socket/blastula_pool_secondary",
   "/dev/socket/webview_zygote",
   "/dev/socket/heapprofd",
   "/sys/kernel/debug/tracing/trace_marker",
@@ -132,15 +136,14 @@
 // open zygote file descriptor.
 class FileDescriptorInfo {
  public:
-  // Create a FileDescriptorInfo for a given file descriptor. Returns
-  // |NULL| if an error occurred.
-  static FileDescriptorInfo* CreateFromFd(int fd, std::string* error_msg);
+  // Create a FileDescriptorInfo for a given file descriptor.
+  static FileDescriptorInfo* CreateFromFd(int fd, fail_fn_t fail_fn);
 
   // Checks whether the file descriptor associated with this object
   // refers to the same description.
-  bool Restat() const;
+  bool RefersToSameFile() const;
 
-  bool ReopenOrDetach(std::string* error_msg) const;
+  void ReopenOrDetach(fail_fn_t fail_fn) const;
 
   const int fd;
   const struct stat stat;
@@ -166,19 +169,18 @@
   //   address).
   static bool GetSocketName(const int fd, std::string* result);
 
-  bool DetachSocket(std::string* error_msg) const;
+  void DetachSocket(fail_fn_t fail_fn) const;
 
   DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
 };
 
 // static
-FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_msg) {
+FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn) {
   struct stat f_stat;
   // This should never happen; the zygote should always have the right set
   // of permissions required to stat all its open files.
   if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
-    *error_msg = android::base::StringPrintf("Unable to stat %d", fd);
-    return nullptr;
+    fail_fn(android::base::StringPrintf("Unable to stat %d", fd));
   }
 
   const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
@@ -186,15 +188,13 @@
   if (S_ISSOCK(f_stat.st_mode)) {
     std::string socket_name;
     if (!GetSocketName(fd, &socket_name)) {
-      *error_msg = "Unable to get socket name";
-      return nullptr;
+      fail_fn("Unable to get socket name");
     }
 
     if (!whitelist->IsAllowed(socket_name)) {
-      *error_msg = android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)",
-                                               socket_name.c_str(),
-                                               fd);
-      return nullptr;
+      fail_fn(android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)",
+                                          socket_name.c_str(),
+                                          fd));
     }
 
     return new FileDescriptorInfo(fd);
@@ -207,26 +207,35 @@
   // S_ISDIR : Not supported. (We could if we wanted to, but it's unused).
   // S_ISLINK : Not supported.
   // S_ISBLK : Not supported.
-  // S_ISFIFO : Not supported. Note that the zygote uses pipes to communicate
-  // with the child process across forks but those should have been closed
-  // before we got to this point.
+  // S_ISFIFO : Not supported. Note that the Zygote and blastulas use pipes to
+  // communicate with the child processes across forks but those should have been
+  // added to the redirection exemption list.
   if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
-    *error_msg = android::base::StringPrintf("Unsupported st_mode %u", f_stat.st_mode);
-    return nullptr;
+    std::string mode = "Unknown";
+
+    if (S_ISDIR(f_stat.st_mode)) {
+      mode = "DIR";
+    } else if (S_ISLNK(f_stat.st_mode)) {
+      mode = "LINK";
+    } else if (S_ISBLK(f_stat.st_mode)) {
+      mode = "BLOCK";
+    } else if (S_ISFIFO(f_stat.st_mode)) {
+      mode = "FIFO";
+    }
+
+    fail_fn(android::base::StringPrintf("Unsupported st_mode for FD %d:  %s", fd, mode.c_str()));
   }
 
   std::string file_path;
   const std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
   if (!android::base::Readlink(fd_path, &file_path)) {
-    *error_msg = android::base::StringPrintf("Could not read fd link %s: %s",
-                                             fd_path.c_str(),
-                                             strerror(errno));
-    return nullptr;
+    fail_fn(android::base::StringPrintf("Could not read fd link %s: %s",
+                                        fd_path.c_str(),
+                                        strerror(errno)));
   }
 
   if (!whitelist->IsAllowed(file_path)) {
-    *error_msg = std::string("Not whitelisted : ").append(file_path);
-    return nullptr;
+    fail_fn(std::string("Not whitelisted : ").append(file_path));
   }
 
   // File descriptor flags : currently on FD_CLOEXEC. We can set these
@@ -234,11 +243,10 @@
   // there won't be any races.
   const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
   if (fd_flags == -1) {
-    *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFD) (%s): %s",
-                                             fd,
-                                             file_path.c_str(),
-                                             strerror(errno));
-    return nullptr;
+    fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_GETFD) (%s): %s",
+                                        fd,
+                                        file_path.c_str(),
+                                        strerror(errno)));
   }
 
   // File status flags :
@@ -255,11 +263,10 @@
   //   their presence and pass them in to open().
   int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
   if (fs_flags == -1) {
-    *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFL) (%s): %s",
-                                             fd,
-                                             file_path.c_str(),
-                                             strerror(errno));
-    return nullptr;
+    fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_GETFL) (%s): %s",
+                                        fd,
+                                        file_path.c_str(),
+                                        strerror(errno)));
   }
 
   // File offset : Ignore the offset for non seekable files.
@@ -274,7 +281,7 @@
   return new FileDescriptorInfo(f_stat, file_path, fd, open_flags, fd_flags, fs_flags, offset);
 }
 
-bool FileDescriptorInfo::Restat() const {
+bool FileDescriptorInfo::RefersToSameFile() const {
   struct stat f_stat;
   if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
     PLOG(ERROR) << "Unable to restat fd " << fd;
@@ -284,9 +291,9 @@
   return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
 }
 
-bool FileDescriptorInfo::ReopenOrDetach(std::string* error_msg) const {
+void FileDescriptorInfo::ReopenOrDetach(fail_fn_t fail_fn) const {
   if (is_sock) {
-    return DetachSocket(error_msg);
+    return DetachSocket(fail_fn);
   }
 
   // NOTE: This might happen if the file was unlinked after being opened.
@@ -295,57 +302,50 @@
   const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));
 
   if (new_fd == -1) {
-    *error_msg = android::base::StringPrintf("Failed open(%s, %i): %s",
-                                             file_path.c_str(),
-                                             open_flags,
-                                             strerror(errno));
-    return false;
+    fail_fn(android::base::StringPrintf("Failed open(%s, %i): %s",
+                                        file_path.c_str(),
+                                        open_flags,
+                                        strerror(errno)));
   }
 
   if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
     close(new_fd);
-    *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFD, %d) (%s): %s",
-                                             new_fd,
-                                             fd_flags,
-                                             file_path.c_str(),
-                                             strerror(errno));
-    return false;
+    fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_SETFD, %d) (%s): %s",
+                                        new_fd,
+                                        fd_flags,
+                                        file_path.c_str(),
+                                        strerror(errno)));
   }
 
   if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
     close(new_fd);
-    *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFL, %d) (%s): %s",
-                                             new_fd,
-                                             fs_flags,
-                                             file_path.c_str(),
-                                             strerror(errno));
-    return false;
+    fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_SETFL, %d) (%s): %s",
+                                        new_fd,
+                                        fs_flags,
+                                        file_path.c_str(),
+                                        strerror(errno)));
   }
 
   if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
     close(new_fd);
-    *error_msg = android::base::StringPrintf("Failed lseek64(%d, SEEK_SET) (%s): %s",
-                                             new_fd,
-                                             file_path.c_str(),
-                                             strerror(errno));
-    return false;
+    fail_fn(android::base::StringPrintf("Failed lseek64(%d, SEEK_SET) (%s): %s",
+                                        new_fd,
+                                        file_path.c_str(),
+                                        strerror(errno)));
   }
 
-  int dupFlags = (fd_flags & FD_CLOEXEC) ? O_CLOEXEC : 0;
-  if (TEMP_FAILURE_RETRY(dup3(new_fd, fd, dupFlags)) == -1) {
+  int dup_flags = (fd_flags & FD_CLOEXEC) ? O_CLOEXEC : 0;
+  if (TEMP_FAILURE_RETRY(dup3(new_fd, fd, dup_flags)) == -1) {
     close(new_fd);
-    *error_msg = android::base::StringPrintf("Failed dup3(%d, %d, %d) (%s): %s",
-                                             fd,
-                                             new_fd,
-                                             dupFlags,
-                                             file_path.c_str(),
-                                             strerror(errno));
-    return false;
+    fail_fn(android::base::StringPrintf("Failed dup3(%d, %d, %d) (%s): %s",
+                                        fd,
+                                        new_fd,
+                                        dup_flags,
+                                        file_path.c_str(),
+                                        strerror(errno)));
   }
 
   close(new_fd);
-
-  return true;
 }
 
 FileDescriptorInfo::FileDescriptorInfo(int fd) :
@@ -371,7 +371,6 @@
   is_sock(false) {
 }
 
-// static
 bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
   sockaddr_storage ss;
   sockaddr* addr = reinterpret_cast<sockaddr*>(&ss);
@@ -415,86 +414,75 @@
   return true;
 }
 
-bool FileDescriptorInfo::DetachSocket(std::string* error_msg) const {
+void FileDescriptorInfo::DetachSocket(fail_fn_t fail_fn) const {
   const int dev_null_fd = open("/dev/null", O_RDWR);
   if (dev_null_fd < 0) {
-    *error_msg = std::string("Failed to open /dev/null: ").append(strerror(errno));
-    return false;
+    fail_fn(std::string("Failed to open /dev/null: ").append(strerror(errno)));
   }
 
   if (dup2(dev_null_fd, fd) == -1) {
-    *error_msg = android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s",
-                                             fd,
-                                             strerror(errno));
-    return false;
+    fail_fn(android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s",
+                                        fd,
+                                        strerror(errno)));
   }
 
   if (close(dev_null_fd) == -1) {
-    *error_msg = android::base::StringPrintf("Failed close(%d): %s", dev_null_fd, strerror(errno));
-    return false;
+    fail_fn(android::base::StringPrintf("Failed close(%d): %s", dev_null_fd, strerror(errno)));
   }
-
-  return true;
 }
 
 // static
 FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore,
-                                                 std::string* error_msg) {
-  DIR* d = opendir(kFdPath);
-  if (d == nullptr) {
-    *error_msg = std::string("Unable to open directory ").append(kFdPath);
-    return nullptr;
+                                                 fail_fn_t fail_fn) {
+  DIR* proc_fd_dir = opendir(kFdPath);
+  if (proc_fd_dir == nullptr) {
+    fail_fn(std::string("Unable to open directory ").append(kFdPath));
   }
-  int dir_fd = dirfd(d);
-  dirent* e;
+
+  int dir_fd = dirfd(proc_fd_dir);
+  dirent* dir_entry;
 
   std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
-  while ((e = readdir(d)) != NULL) {
-    const int fd = ParseFd(e, dir_fd);
+  while ((dir_entry = readdir(proc_fd_dir)) != nullptr) {
+    const int fd = ParseFd(dir_entry, dir_fd);
     if (fd == -1) {
       continue;
     }
+
     if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
       LOG(INFO) << "Ignoring open file descriptor " << fd;
       continue;
     }
 
-    FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
-    if (info == NULL) {
-      if (closedir(d) == -1) {
-        PLOG(ERROR) << "Unable to close directory";
-      }
-      return NULL;
-    }
-    open_fd_map[fd] = info;
+    open_fd_map[fd] = FileDescriptorInfo::CreateFromFd(fd, fail_fn);
   }
 
-  if (closedir(d) == -1) {
-    *error_msg = "Unable to close directory";
-    return nullptr;
+  if (closedir(proc_fd_dir) == -1) {
+    fail_fn("Unable to close directory");
   }
+
   return new FileDescriptorTable(open_fd_map);
 }
 
-bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, std::string* error_msg) {
+void FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, fail_fn_t fail_fn) {
   std::set<int> open_fds;
 
   // First get the list of open descriptors.
-  DIR* d = opendir(kFdPath);
-  if (d == NULL) {
-    *error_msg = android::base::StringPrintf("Unable to open directory %s: %s",
-                                             kFdPath,
-                                             strerror(errno));
-    return false;
+  DIR* proc_fd_dir = opendir(kFdPath);
+  if (proc_fd_dir == nullptr) {
+    fail_fn(android::base::StringPrintf("Unable to open directory %s: %s",
+                                        kFdPath,
+                                        strerror(errno)));
   }
 
-  int dir_fd = dirfd(d);
-  dirent* e;
-  while ((e = readdir(d)) != NULL) {
-    const int fd = ParseFd(e, dir_fd);
+  int dir_fd = dirfd(proc_fd_dir);
+  dirent* dir_entry;
+  while ((dir_entry = readdir(proc_fd_dir)) != nullptr) {
+    const int fd = ParseFd(dir_entry, dir_fd);
     if (fd == -1) {
       continue;
     }
+
     if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
       LOG(INFO) << "Ignoring open file descriptor " << fd;
       continue;
@@ -503,27 +491,24 @@
     open_fds.insert(fd);
   }
 
-  if (closedir(d) == -1) {
-    *error_msg = android::base::StringPrintf("Unable to close directory: %s", strerror(errno));
-    return false;
+  if (closedir(proc_fd_dir) == -1) {
+    fail_fn(android::base::StringPrintf("Unable to close directory: %s", strerror(errno)));
   }
 
-  return RestatInternal(open_fds, error_msg);
+  RestatInternal(open_fds, fail_fn);
 }
 
-// Reopens all file descriptors that are contained in the table. Returns true
-// if all descriptors were successfully re-opened or detached, and false if an
-// error occurred.
-bool FileDescriptorTable::ReopenOrDetach(std::string* error_msg) {
+// Reopens all file descriptors that are contained in the table.
+void FileDescriptorTable::ReopenOrDetach(fail_fn_t fail_fn) {
   std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
   for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
     const FileDescriptorInfo* info = it->second;
-    if (info == NULL || !info->ReopenOrDetach(error_msg)) {
-      return false;
+    if (info == nullptr) {
+      return;
+    } else {
+      info->ReopenOrDetach(fail_fn);
     }
   }
-
-  return true;
 }
 
 FileDescriptorTable::FileDescriptorTable(
@@ -531,9 +516,7 @@
     : open_fd_map_(map) {
 }
 
-bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds, std::string* error_msg) {
-  bool error = false;
-
+void FileDescriptorTable::RestatInternal(std::set<int>& open_fds, fail_fn_t fail_fn) {
   // Iterate through the list of file descriptors we've already recorded
   // and check whether :
   //
@@ -556,28 +539,18 @@
     } else {
       // The entry from the file descriptor table is still open. Restat
       // it and check whether it refers to the same file.
-      const bool same_file = it->second->Restat();
-      if (!same_file) {
+      if (!it->second->RefersToSameFile()) {
         // The file descriptor refers to a different description. We must
         // update our entry in the table.
         delete it->second;
-        it->second = FileDescriptorInfo::CreateFromFd(*element, error_msg);
-        if (it->second == NULL) {
-          // The descriptor no longer no longer refers to a whitelisted file.
-          // We flag an error and remove it from the list of files we're
-          // tracking.
-          error = true;
-          it = open_fd_map_.erase(it);
-        } else {
-          // Successfully restatted the file, move on to the next open FD.
-          ++it;
-        }
+        it->second = FileDescriptorInfo::CreateFromFd(*element, fail_fn);
       } else {
         // It's the same file. Nothing to do here. Move on to the next open
         // FD.
-        ++it;
       }
 
+      ++it;
+
       // Finally, remove the FD from the set of open_fds. We do this last because
       // |element| will not remain valid after a call to erase.
       open_fds.erase(element);
@@ -596,25 +569,15 @@
     std::set<int>::const_iterator it;
     for (it = open_fds.begin(); it != open_fds.end(); ++it) {
       const int fd = (*it);
-      FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
-      if (info == NULL) {
-        // A newly opened file is not on the whitelist. Flag an error and
-        // continue.
-        error = true;
-      } else {
-        // Track the newly opened file.
-        open_fd_map_[fd] = info;
-      }
+      open_fd_map_[fd] = FileDescriptorInfo::CreateFromFd(fd, fail_fn);
     }
   }
-
-  return !error;
 }
 
 // static
-int FileDescriptorTable::ParseFd(dirent* e, int dir_fd) {
+int FileDescriptorTable::ParseFd(dirent* dir_entry, int dir_fd) {
   char* end;
-  const int fd = strtol(e->d_name, &end, 10);
+  const int fd = strtol(dir_entry->d_name, &end, 10);
   if ((*end) != '\0') {
     return -1;
   }
diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h
index 09022a2..2caf157 100644
--- a/core/jni/fd_utils.h
+++ b/core/jni/fd_utils.h
@@ -30,6 +30,9 @@
 
 class FileDescriptorInfo;
 
+// This type is duplicated in com_android_internal_os_Zygote.cpp
+typedef const std::function<void(std::string)>& fail_fn_t;
+
 // Whitelist of open paths that the zygote is allowed to keep open.
 //
 // In addition to the paths listed in kPathWhitelist in file_utils.cpp, and
@@ -76,19 +79,19 @@
   // /proc/self/fd for the list of open file descriptors and collects
   // information about them. Returns NULL if an error occurs.
   static FileDescriptorTable* Create(const std::vector<int>& fds_to_ignore,
-                                     std::string* error_msg);
+                                     fail_fn_t fail_fn);
 
-  bool Restat(const std::vector<int>& fds_to_ignore, std::string* error_msg);
+  void Restat(const std::vector<int>& fds_to_ignore, fail_fn_t fail_fn);
 
   // Reopens all file descriptors that are contained in the table. Returns true
   // if all descriptors were successfully re-opened or detached, and false if an
   // error occurred.
-  bool ReopenOrDetach(std::string* error_msg);
+  void ReopenOrDetach(fail_fn_t fail_fn);
 
  private:
   explicit FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map);
 
-  bool RestatInternal(std::set<int>& open_fds, std::string* error_msg);
+  void RestatInternal(std::set<int>& open_fds, fail_fn_t fail_fn);
 
   static int ParseFd(dirent* e, int dir_fd);
 
diff --git a/core/proto/Android.bp b/core/proto/Android.bp
new file mode 100644
index 0000000..80cc2d4
--- /dev/null
+++ b/core/proto/Android.bp
@@ -0,0 +1,27 @@
+// 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.
+
+// C++ library for Bluetooth platform wide protobuf definitions
+cc_library_static {
+    name: "libbt-platform-protos-lite",
+    host_supported: true,
+    proto: {
+        export_proto_headers: true,
+        type: "lite",
+    },
+    srcs: [
+        "android/bluetooth/enums.proto",
+        "android/bluetooth/hci/enums.proto",
+    ],
+}
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 3e1c5a3..6cdba33 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -27,8 +27,574 @@
     PAGE_VISIBLE = 1;
     PAGE_HIDE = 2;
 
+    // ACTION: Settings > Wi-Fi > [Long press network] > Connect to network
+    //   SUBTYPE: true if connecting to a saved network, false if not
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_WIFI_CONNECT = 135;
+
+    // ACTION: Settings > Wi-Fi > [Long press network] > Forget network
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_WIFI_FORGET = 137;
+
+    // ACTION: Settings > Wi-Fi > Toggle off
+    //   SUBTYPE: true if connected to network before toggle, false if not
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_WIFI_OFF = 138;
+
+    // ACTION: Settings > Wi-Fi > Toggle on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_WIFI_ON = 139;
+
+    // ACTION: Settings > Bluetooth > Overflow > Rename this device
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_BLUETOOTH_RENAME = 161;
+
+    // ACTION: Settings > Bluetooth > Overflow > Show received files
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_BLUETOOTH_FILES = 162;
+
+    // ACTION: DND Settings > Priority only allows > Reminder toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_ALLOW_REMINDERS = 167;
+
+    // ACTION: DND Settings > Priority only allows > Event toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_ALLOW_EVENTS = 168;
+
+    // ACTION: DND Settings > Priority only allows > Messages
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_ALLOW_MESSAGES = 169;
+
+    // ACTION: DND Settings > Priority only allows > Calls
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_ALLOW_CALLS = 170;
+
+    // ACTION: DND Settings > Priority only allows > Repeat callers toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_ALLOW_REPEAT_CALLS = 171;
+
+    // ACTION: DND Settings > Automatic rules > [Rule] > Delete rule > Delete
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_DELETE_RULE_OK = 175;
+
+    // ACTION: Settings > More > Airplane mode toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_AIRPLANE_TOGGLE = 177;
+
+    // ACTION: Settings > Data usage > Cellular data toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_CELL_DATA_TOGGLE = 178;
+
+    // ACTION: Settings > Display > When device is rotated
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ROTATION_LOCK = 203;
+
+    // OPEN: Settings > Search > Perform search
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_SEARCH_RESULTS = 226;
+
+    // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Delete
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_FINGERPRINT_DELETE = 253;
+
+    // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Rename
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_FINGERPRINT_RENAME = 254;
+
+    // ACTION: Settings -> Developer Options -> Take bug report -> Interactive report
+    // CATEGORY: SETTINGS
+    // OS: N
+    // Interactive bug report initiated from Settings.
+    ACTION_BUGREPORT_FROM_SETTINGS_INTERACTIVE = 294;
+
+    // ACTION: Settings -> Developer Options -> Take bug report -> Full report
+    // CATEGORY: SETTINGS
+    // OS: N
+    // Interactive bug report initiated from Settings.
+    ACTION_BUGREPORT_FROM_SETTINGS_FULL = 295;
+
+    // click on collapsed conditional or clicks expand button
+    ACTION_SETTINGS_CONDITION_EXPAND = 373;
+
+    // click main area of expanded conditional
+    ACTION_SETTINGS_CONDITION_CLICK = 375;
+
+    // click a direct button on expanded conditional
+    ACTION_SETTINGS_CONDITION_BUTTON = 376;
+
+    // Action: user enable / disabled data saver using Settings
+    // OPEN: Settings -> Data Usage -> Data saver -> On/off toggle
+    // VALUE: 1 for enabled, 0 for disabled
+    // CATEGORY: SETTINGS
+    // OS: N
+    ACTION_DATA_SAVER_MODE = 394;
+
+    // User whitelisted an app for Data Saver mode; action pass package name of app
+    // Action: user enable / disabled data saver using Settings
+    // OPEN: Settings -> Data Usage -> Data saver -> Unrestricted data access > APP toggle turned on
+    //       or
+    //       Settings -> Apps -> APP -> Data usage -> Unrestricted data usage toggle turned on
+    // VALUE: package name of APP
+    // CATEGORY: SETTINGS
+    // OS: N
+    ACTION_DATA_SAVER_WHITELIST = 395;
+
+    // User blacklisted an app for Data Saver mode; action pass package name of app
+    // OPEN: Settings -> Apps -> APP -> Data usage -> Background data toggle turned off
+    // VALUE: package name of APP
+    // CATEGORY: SETTINGS
+    // OS: N
+    ACTION_DATA_SAVER_BLACKLIST = 396;
+
+    // ACTION: Settings -> Storage -> Manage storage -> Click Storage Manager
+    //   SUBTYPE: false is off, true is on
+    ACTION_TOGGLE_STORAGE_MANAGER = 489;
+
+    // OPEN: Settings > Display -> Ambient Display
+    // CATEGORY: SETTINGS
+    ACTION_AMBIENT_DISPLAY = 495;
+
+    // ACTION: Allow Battery optimization for an app
+    APP_SPECIAL_PERMISSION_BATTERY_ALLOW = 764;
+
+    // ACTION: Deny Battery optimization for an app
+    APP_SPECIAL_PERMISSION_BATTERY_DENY = 765;
+
+    // ACTION: Enable Device Admin app
+    APP_SPECIAL_PERMISSION_ADMIN_ALLOW = 766;
+
+    // ACTION: Disable Device Admin app
+    APP_SPECIAL_PERMISSION_ADMIN_DENY = 767;
+
+    // ACTION: Allow "Do Not Disturb access" for an app
+    APP_SPECIAL_PERMISSION_DND_ALLOW = 768;
+
+    // ACTION: Deny "Do Not Disturb access" for an app
+    APP_SPECIAL_PERMISSION_DND_DENY = 769;
+
+    // ACTION: Allow "Draw over other apps" for an app
+    APP_SPECIAL_PERMISSION_APPDRAW_ALLOW = 770;
+
+    // ACTION: Deny "Display over other apps" for an app
+    APP_SPECIAL_PERMISSION_APPDRAW_DENY = 771;
+
+    // ACTION: Allow "VR helper services" for an app
+    APP_SPECIAL_PERMISSION_VRHELPER_ALLOW = 772;
+
+    // ACTION: Deny "VR helper services" for an app
+    APP_SPECIAL_PERMISSION_VRHELPER_DENY = 773;
+
+    // ACTION: Allow "Modify system settings" for an app
+    APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_ALLOW = 774;
+
+    // ACTION: Deny "Modify system settings" for an app
+    APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_DENY = 775;
+
+    // ACTION: Allow "Notification access" for an app
+    APP_SPECIAL_PERMISSION_NOTIVIEW_ALLOW = 776;
+
+    // ACTION: Deny "Notification access" for an app
+    APP_SPECIAL_PERMISSION_NOTIVIEW_DENY = 777;
+
+    // ACTION: "Premium SMS access" for an app - "ask user" option
+    APP_SPECIAL_PERMISSION_PREMIUM_SMS_ASK = 778;
+
+    // ACTION: "Premium SMS access" for an app - "never allow" option
+    APP_SPECIAL_PERMISSION_PREMIUM_SMS_DENY = 779;
+
+    // ACTION: "Premium SMS access" for an app - "always allow" option
+    APP_SPECIAL_PERMISSION_PREMIUM_SMS_ALWAYS_ALLOW = 780;
+
+    // ACTION: Allow "Unrestricted data access" for an app
+    APP_SPECIAL_PERMISSION_UNL_DATA_ALLOW = 781;
+
+    // ACTION: Deny "Unrestricted data access" for an app
+    APP_SPECIAL_PERMISSION_UNL_DATA_DENY = 782;
+
+    // ACTION: Allow "Usage access" for an app
+    APP_SPECIAL_PERMISSION_USAGE_VIEW_ALLOW = 783;
+
+    // ACTION: Deny "Usage access" for an app
+    APP_SPECIAL_PERMISSION_USAGE_VIEW_DENY = 784;
+
+    // ACTION: "Force stop" action on an app
+    ACTION_APP_FORCE_STOP = 807;
+
+    // ACTION: Allow "Enable picture-in-picture" for an app
+    APP_PICTURE_IN_PICTURE_ALLOW = 813;
+
+    // ACTION: Create a Settings shortcut item.
+    ACTION_SETTINGS_CREATE_SHORTCUT = 829;
+
+    // ACTION: Settings advanced button is expanded
+    ACTION_SETTINGS_ADVANCED_BUTTON_EXPAND = 834;
+
+    // ACTION: Deny "Enable picture-in-picture" for an app
+    APP_PICTURE_IN_PICTURE_DENY = 814;
+
+    // ACTION: Settings -> Display -> Theme
+    ACTION_THEME = 816;
+
+    // ACTION: Settings > About device > Build number
+    ACTION_SETTINGS_BUILD_NUMBER_PREF = 847;
+
+    // ACTION: Settings > Battery > Menu > Optimization
+    ACTION_SETTINGS_MENU_BATTERY_OPTIMIZATION = 851;
+
+    // ACTION: Settings > Battery > Menu > Apps Toggle
+    ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE = 852;
+
     // ACTION: Settings > Any preference is changed
     ACTION_SETTINGS_PREFERENCE_CHANGE = 853;
+
+    // ACTION: Settings > Connected devices > Bluetooth -> Available devices
+    ACTION_SETTINGS_BLUETOOTH_PAIR = 866;
+
+    // ACTION: Settings > Connected devices > Bluetooth -> Paired devices
+    ACTION_SETTINGS_BLUETOOTH_CONNECT = 867;
+
+    // ACTION: Settings > Connected devices > Bluetooth -> Connected device
+    ACTION_SETTINGS_BLUETOOTH_DISCONNECT = 868;
+
+    // ACTION: Settings > Connected devices > Bluetooth -> Error dialog
+    ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR = 869;
+
+    // ACTION: Settings > Connected devices > Bluetooth master switch Toggle
+    ACTION_SETTINGS_MASTER_SWITCH_BLUETOOTH_TOGGLE = 870;
+
+    // ACTION: Settings > App detail > Uninstall
+    ACTION_SETTINGS_UNINSTALL_APP = 872;
+
+    // ACTION: Settings > App detail > Uninstall Device admin app
+    ACTION_SETTINGS_UNINSTALL_DEVICE_ADMIN = 873;
+
+    // ACTION: Settings > App detail > Disable app
+    ACTION_SETTINGS_DISABLE_APP = 874;
+
+    // ACTION: Settings > App detail > Enable app
+    ACTION_SETTINGS_ENABLE_APP = 875;
+
+    // ACTION: Settings > App detail > Clear data
+    ACTION_SETTINGS_CLEAR_APP_DATA = 876;
+
+    // ACTION: Settings > App detail > Clear cache
+    ACTION_SETTINGS_CLEAR_APP_CACHE = 877;
+
+    // ACTION: Logs pressing the "Clear app" button in the app info settings page for an instant
+    // app.
+    // VALUE: The package name of the app
+    ACTION_SETTINGS_CLEAR_INSTANT_APP = 923;
+
+    // OPEN: Assist Gesture training intro in Settings
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    SETTINGS_ASSIST_GESTURE_TRAINING_INTRO = 991;
+
+    // OPEN: Assist Gesture training enrolling in Settings
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    SETTINGS_ASSIST_GESTURE_TRAINING_ENROLLING = 992;
+
+    // OPEN: Assist Gesture training finished in Settings
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    SETTINGS_ASSIST_GESTURE_TRAINING_FINISHED = 993;
+
+    // ACTION: Update default app from Settings
+    ACTION_SETTINGS_UPDATE_DEFAULT_APP = 1000;
+
+    // ACTION: Settings > Wi-Fi > [Long press network] > Sign in to network
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    ACTION_WIFI_SIGNIN = 1008;
+
+    // ACTION: Settings > Notification Settings > Open application notification
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    ACTION_OPEN_APP_NOTIFICATION_SETTING = 1016;
+
+    // ACTION: Settings > App Info > Open app settings
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    ACTION_OPEN_APP_SETTING = 1017;
+
+    // ACTION: Collect PSD Signals
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    ACTION_PSD_LOADER = 1019;
+
+    // OPEN: Settings > Trampoline Intent > Settings page
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    TRAMPOLINE_SETTINGS_EVENT = 1033;
+
+    // ACTION: Logged when user tries to pair a Bluetooth device without name from Settings app
+    // CATEGORY: SETTINGS
+    // OS: O MR
+    ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES = 1096;
+
+    // ACTION: Settings > Network & Internet > Mobile network > Network
+    // CATEGORY: SETTINGS
+    ACTION_MOBILE_NETWORK_MANUAL_SELECT_NETWORK = 1210;
+
+    // ACTION: DND Settings > Priority only allows > Alarms toggle
+    // SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ALLOW_ALARMS = 1226;
+
+    // ACTION: DND Settings > Priority only allows > Media toggle
+    // SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ALLOW_MEDIA = 1227;
+
+    // ACTION: A private dns mode been selected by user
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_PRIVATE_DNS_MODE = 1249;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Select rule ("Event") > Rule name > OK
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK = 1267;
+
+    // OPEN: Settings > Sound > Do Not Disturb > TURN ON NOW/TURN OFF NOW
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_TOGGLE_DND_BUTTON = 1268;
+
+    // ACTION: DND Settings > What to block > full screen intents
+    //   SUBTYPE: false is allowed, true is blocked
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACTION_ZEN_BLOCK_FULL_SCREEN_INTENTS = 1332;
+
+    // ACTION: DND Settings > What to block
+    //   SUBTYPE: false is allowed, true is blocked
+    // OS: P
+    ACTION_ZEN_BLOCK_LIGHT = 1333;
+
+    // ACTION: DND Settings > What to block
+    //   SUBTYPE: false is allowed, true is blocked
+    // OS: P
+    ACTION_ZEN_BLOCK_PEEK = 1334;
+
+    // ACTION: DND Settings > What to block
+    //   SUBTYPE: false is allowed, true is blocked
+    // OS: P
+    ACTION_ZEN_BLOCK_STATUS = 1335;
+
+    // ACTION: DND Settings > What to block
+    //   SUBTYPE: false is allowed, true is blocked
+    // OS: P
+    ACTION_ZEN_BLOCK_BADGE = 1336;
+
+    // ACTION: DND Settings > What to block
+    //   SUBTYPE: false is allowed, true is blocked
+    // OS: P
+    ACTION_ZEN_BLOCK_AMBIENT = 1337;
+
+    // ACTION: DND Settings > What to block
+    //   SUBTYPE: false is allowed, true is blocked
+    // OS: P
+    ACTION_ZEN_BLOCK_NOTIFICATION_LIST = 1338;
+
+    // ACTION: DND Settings > Priority only allows > System toggle
+    // SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ALLOW_SYSTEM = 1340;
+
+    // ACTION: Settings > Battery settings > Battery tip > App restriction tip
+    // OS: P
+    ACTION_APP_RESTRICTION_TIP = 1347;
+
+    // ACTION: Settings > Battery settings > Battery tip > High usage tip
+    // OS: P
+    ACTION_HIGH_USAGE_TIP = 1348;
+
+    // ACTION: Settings > Battery settings > Battery tip > Summary tip
+    // OS: P
+    ACTION_SUMMARY_TIP = 1349;
+
+    // ACTION: Settings > Battery settings > Battery tip > Smart battery tip
+    // OS: P
+    ACTION_SMART_BATTERY_TIP = 1350;
+
+    // ACTION: Settings > Battery settings > Battery tip > Early warning tip
+    // OS: P
+    ACTION_EARLY_WARNING_TIP = 1351;
+
+    // ACTION: Settings > Battery settings > Battery tip > Low battery tip
+    // OS: P
+    ACTION_LOW_BATTERY_TIP = 1352;
+
+    // ACTION: Settings > Battery settings > Battery tip > App restriction list shown
+    // OS: P
+    ACTION_APP_RESTRICTION_TIP_LIST = 1353;
+
+    // ACTION: Settings > Battery settings > Battery tip > High usage list shown
+    // OS: P
+    ACTION_HIGH_USAGE_TIP_LIST = 1354;
+
+    // ACTION: Settings > Battery settings > Battery tip > Open app restriction page
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_TIP_OPEN_APP_RESTRICTION_PAGE = 1361;
+
+    // ACTION: Settings > Battery settings > Battery tip > Restrict app
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_TIP_RESTRICT_APP = 1362;
+
+    // ACTION: Settings > Battery settings > Battery tip > Unrestrict app
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_TIP_UNRESTRICT_APP = 1363;
+
+    // ACTION: Settings > Battery settings > Battery tip > Open smart battery page
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_TIP_OPEN_SMART_BATTERY = 1364;
+
+    // ACTION: Settings > Battery settings > Battery tip > Turn on battery saver
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_TIP_TURN_ON_BATTERY_SAVER = 1365;
+
+    // ACTION: Settings > Anomaly receiver > Anomaly received
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ANOMALY_TRIGGERED = 1367;
+
+    // ACTION: A Settings Slice is requested
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_SETTINGS_SLICE_REQUESTED = 1371;
+
+    // ACTION: A Settings Slice is updated with new value
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_SETTINGS_SLICE_CHANGED = 1372;
+
+    // OPEN: DND onboarding activity > Ok button
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ONBOARDING_OK = 1378;
+
+    // OPEN: DND onboarding activity > Settings link
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ONBOARDING_SETTINGS = 1379;
+
+    // ACTION: Settings > Anomaly receiver > Anomaly ignored, don't show up in battery settings
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ANOMALY_IGNORED = 1387;
+
+    // ACTION: Settings > Battery settings > Battery tip > Open battery saver page
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_TIP_OPEN_BATTERY_SAVER_PAGE = 1388;
+
+    // ACTION: DND Settings > What to block
+    // OS: P
+    ACTION_ZEN_SOUND_ONLY = 1396;
+
+    // ACTION: DND Settings > Notifications
+    // OS: P
+    ACTION_ZEN_SOUND_AND_VIS_EFFECTS = 1397;
+
+    // ACTION: DND Settings > Notifications
+    // OS: P
+    ACTION_ZEN_SHOW_CUSTOM = 1398;
+
+    // ACTION: DND Settings > Notifications
+    // OS: P
+    ACTION_ZEN_CUSTOM = 1399;
+
+    // OPEN: DND onboarding activity > don't update button
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS = 1406;
+
+    // ACTION: Storage initialization wizard initialization choice of external/portable
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_INIT_EXTERNAL = 1407;
+
+    // ACTION: Storage initialization wizard initialization choice of internal/adoptable
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_INIT_INTERNAL = 1408;
+
+    // ACTION: Storage initialization wizard benchmark fast choice of continue
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_BENCHMARK_FAST_CONTINUE = 1409;
+
+    // ACTION: Storage initialization wizard benchmark slow choice of continue
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_BENCHMARK_SLOW_CONTINUE = 1410;
+
+    // ACTION: Storage initialization wizard benchmark slow choice of abort
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_BENCHMARK_SLOW_ABORT = 1411;
+
+    // ACTION: Storage initialization wizard migration choice of now
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_MIGRATE_NOW = 1412;
+
+    // ACTION: Storage initialization wizard migration choice of later
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_STORAGE_MIGRATE_LATER = 1413;
+
+    // OPEN: Settings > Sound > Switch a2dp devices dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_SWITCH_A2DP_DEVICES = 1415;
+
+
+    // OPEN: Settings > Sound > Switch hfp devices dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_SWITCH_HFP_DEVICES = 1416;
+
+    // ACTION: Tap & Pay -> Default Application Setting -> Use Forground
+    ACTION_NFC_PAYMENT_FOREGROUND_SETTING = 1622;
+
+    // ACTION: Tap & Pay -> Default Application Setting -> Use Default
+    ACTION_NFC_PAYMENT_ALWAYS_SETTING = 1623;
 }
 
 /**
@@ -38,15 +604,1454 @@
     // Unknown page. Should not be used in production code.
     PAGE_UNKNOWN = 0;
 
+    // OPEN: Settings > Accessibility
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCESSIBILITY = 2;
+
+    // OPEN: Settings > Accessibility > Captions
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCESSIBILITY_CAPTION_PROPERTIES = 3;
+
+    // OPEN: Settings > Accessibility > [Service]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCESSIBILITY_SERVICE = 4;
+
+    // OPEN: Settings > Accessibility > Color correction
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCESSIBILITY_TOGGLE_DALTONIZER = 5;
+
+    // OPEN: Settings > Accessibility > Accessibility shortcut
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6;
+
+    // OPEN: Settings > Accessibility > Magnification gestures (Renamed in O)
+    // OPEN: Settings > Accessibility > Magnification > Magnify with triple-tap
+    // OPEN: Settings > Accessibility > Magnification > Magnify with button
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7;
+
+    // OPEN: Settings > Accounts
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCOUNT = 8;
+
+    // OPEN: Settings > Accounts > [Single Account Sync Settings]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCOUNTS_ACCOUNT_SYNC = 9;
+
+    // OPEN: Settings > Accounts > Add an account
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10;
+
+    // OPEN: Settings > Cellular network settings > APNs
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APN = 12;
+
+    // OPEN: Settings > More > Cellular network settings > APNs > [Edit APN]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APN_EDITOR = 13;
+
+    // OPEN: Settings > Apps > Configure apps > App links > [App]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_APP_LAUNCH = 17;
+
+    // OPEN: Settings > Internal storage > Apps storage > [App]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_APP_STORAGE = 19;
+
+    // OPEN: Settings > Apps > [App info]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_INSTALLED_APP_DETAILS = 20;
+
+    // OPEN: Settings > Memory > App usage > [App Memory usage]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_PROCESS_STATS_DETAIL = 21;
+
+    // OPEN: Settings > Memory > App usage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_PROCESS_STATS_UI = 23;
+
+    // OPEN: Choose Bluetooth device (ex: when sharing)
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    BLUETOOTH_DEVICE_PICKER = 25;
+
+    // OPEN: Settings > Security > Choose screen lock
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CHOOSE_LOCK_GENERIC = 27;
+
+    // OPEN: Settings > Security > Choose screen lock > Choose your password
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CHOOSE_LOCK_PASSWORD = 28;
+
+    // OPEN: Settings > Security > Choose screen lock > Choose your pattern
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CHOOSE_LOCK_PATTERN = 29;
+
+    // OPEN: Settings > Security > Choose screen lock > Confirm your password
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CONFIRM_LOCK_PASSWORD = 30;
+
+    // OPEN: Settings > Security > Choose screen lock > Confirm your pattern
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CONFIRM_LOCK_PATTERN = 31;
+
+    // OPEN: Settings > Security > Encrypt phone
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CRYPT_KEEPER = 32;
+
+    // OPEN: Settings > Security > Encrypt phone > Confirm
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    CRYPT_KEEPER_CONFIRM = 33;
+
+    // OPEN: Settings (Root page)
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DASHBOARD_SUMMARY = 35;
+
+    // OPEN: Settings > Data usage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DATA_USAGE_SUMMARY = 37;
+
+    // OPEN: Settings > Date & time
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DATE_TIME = 38;
+
+    // OPEN: Settings > Developer options
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DEVELOPMENT = 39;
+
+    // OPEN: Settings > About phone
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DEVICEINFO = 40;
+
+    // OPEN: Settings > Internal storage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DEVICEINFO_STORAGE = 42;
+
+    // OPEN: Settings > Display
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DISPLAY = 46;
+
+    // OPEN: Settings > Display > Daydream
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    DREAM = 47;
+
+    // OPEN: Settings > Security > Screen lock > Secure start-up
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ENCRYPTION = 48;
+
+    // OPEN: Settings > Security > Nexus Imprint
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT = 49;
+
+    // OPEN: Settings > Battery > History details
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FUELGAUGE_BATTERY_HISTORY_DETAIL = 51;
+
+    // OPEN: Settings > Battery > Battery saver
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FUELGAUGE_BATTERY_SAVER = 52;
+
+    // OPEN: Settings > Battery > [App Use details]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FUELGAUGE_POWER_USAGE_DETAIL = 53;
+
+    // OPEN: Settings > Security > SIM card lock settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ICC_LOCK = 56;
+
+    // OPEN: Settings > Language & input > Physical keyboard
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    INPUTMETHOD_KEYBOARD = 58;
+
+    // OPEN: Settings > Language & input > Spell checker
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    INPUTMETHOD_SPELL_CHECKERS = 59;
+
+    // OBSOLETE
+    INPUTMETHOD_SUBTYPE_ENABLER = 60;
+
+    // OPEN: Settings > Language & input > Personal dictionary
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    INPUTMETHOD_USER_DICTIONARY = 61;
+
+    // OPEN: Settings > Language & input > Add word
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62;
+
+    // OPEN: Settings > Location
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    LOCATION = 63;
+
+    // OPEN: Settings > Apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    MANAGE_APPLICATIONS = 65;
+
+    // OPEN: Settings > Backup & reset > Factory data reset
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    MASTER_CLEAR = 66;
+
+    // OPEN: Settings > Backup & reset > Factory data reset > Confirm
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    MASTER_CLEAR_CONFIRM = 67;
+
+    // OPEN: Settings > More > Android Beam
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NFC_BEAM = 69;
+
+    // OPEN: Settings > Tap & pay
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NFC_PAYMENT = 70;
+
+    // OPEN: Settings > Sound & notification > App notifications > [App]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_APP_NOTIFICATION = 72;
+
+    // OBSOLETE
+    NOTIFICATION_REDACTION = 74;
+
+    // OPEN: Settings Widget > Notification log
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_STATION = 75;
+
+    // OPEN: Settings > Sound & notification > Do not disturb
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ZEN_MODE = 76;
+
+
+    // OPEN: Print job notification > Print job settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    PRINT_JOB_SETTINGS = 78;
+
+    // OPEN: Settings > Printing > [Print Service]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    PRINT_SERVICE_SETTINGS = 79;
+
+    // OPEN: Settings > Printing
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    PRINT_SETTINGS = 80;
+
+    // OPEN: Settings > Backup & reset
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    PRIVACY = 81;
+
+    //OBSOLETE
+    PROXY_SELECTOR = 82;
+
+    // OPEN: Settings > Backup & reset > Network settings reset
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    RESET_NETWORK = 83;
+
+    // OPEN: Settings > Backup & reset > Network settings reset > Confirm
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    RESET_NETWORK_CONFIRM = 84;
+
+    // OPEN: Settings > Developer Options > Running Services
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    RUNNING_SERVICE_DETAILS = 85;
+
+    // OPEN: Settings > Security > Screen pinning
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    SCREEN_PINNING = 86;
+
+    // OPEN: Settings > Security
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    SECURITY = 87;
+
+    // OPEN: Settings > SIM cards
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    SIM = 88;
+
+    // OBSOLETE
+    TESTING = 89;
+
+    // OPEN: Settings > More > Tethering & portable hotspot
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    TETHER = 90;
+
+    // OPEN: Settings > Security > Trust agents
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    TRUST_AGENT = 91;
+
+    // OPEN: Settings > Security > Trusted credentials
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    TRUSTED_CREDENTIALS = 92;
+
+    // OPEN: Settings > Language & input > TTS output > [Engine] > Settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    TTS_ENGINE_SETTINGS = 93;
+
+    // OPEN: Settings > Language & input > Text-to-speech output
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    TTS_TEXT_TO_SPEECH = 94;
+
+    // OPEN: Settings > Security > Apps with usage access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    USAGE_ACCESS = 95;
+
+    // OPEN: Settings > Users
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    USER = 96;
+
+    // OPEN: Settings > Users > [Restricted profile app & content access]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    USERS_APP_RESTRICTIONS = 97;
+
+    // OPEN: Settings > Users > [User settings]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    USER_DETAILS = 98;
+
+    // OPEN: Settings > More > VPN
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    VPN = 100;
+
+    // OPEN: Settings > Display > Choose wallpaper from
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    WALLPAPER_TYPE = 101;
+
+    // OPEN: Settings > Display > Cast
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    WFD_WIFI_DISPLAY = 102;
+
+    // OPEN: Settings > Wi-Fi
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    WIFI = 103;
+
+    // OPEN: Settings > More > Wi-Fi Calling
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    WIFI_CALLING = 105;
+
+    // OPEN: Settings > Wi-Fi > Saved networks
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    WIFI_SAVED_ACCESS_POINTS = 106;
+
+    // OPEN: Settings > Wi-Fi > Advanced Wi-Fi > Wi-Fi Direct
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    WIFI_P2P = 109;
+
+    // OPEN: Settings > Apps > Configure apps > App permissions
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_ADVANCED = 130;
+
+    // OPEN: Settings > Location > Scanning
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    LOCATION_SCANNING = 131;
+
+    // OPEN: Settings > Sound & notification > App notifications
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    MANAGE_APPLICATIONS_NOTIFICATIONS = 133;
+
+    // OPEN: Settings > Sound & notification > DND > Priority only allows
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ZEN_MODE_PRIORITY = 141;
+
+    // OPEN: Settings > Sound & notification > DND > Automatic rules
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ZEN_MODE_AUTOMATION = 142;
+
+    // OPEN: Settings > Sound & notification > DND > [Time based rule]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
+
+    // OPEN: Settings > Apps > Configure apps > App links
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    MANAGE_DOMAIN_URLS = 143;
+
+    // OPEN: Settings > Sound & notification > DND > [Event rule]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ZEN_MODE_EVENT_RULE = 146;
+
+    // OPEN: Settings > Sound & notification > Notification access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ACCESS = 179;
+
+    // OPEN: Settings > Sound & notification > Do Not Disturb access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    NOTIFICATION_ZEN_MODE_ACCESS = 180;
+
+    // OPEN: Settings > Internal storage > Apps storage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_STORAGE_APPS = 182;
+
+    // OPEN: Settings > Security > Usage access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_USAGE_ACCESS_DETAIL = 183;
+
+    // OPEN: Settings > Battery > Battery optimization
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_HIGH_POWER_APPS = 184;
+
+    // OPEN: Settings > Apps > Configure > Default apps > Assist & voice input
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    APPLICATIONS_MANAGE_ASSIST = 201;
+
+    // OPEN: Settings > Memory
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    PROCESS_STATS_SUMMARY = 202;
+
+    // OPEN: Settings > Apps > Configure Apps > Display over other apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    SYSTEM_ALERT_WINDOW_APPS = 221;
+
+    // OPEN: Settings > About phone > Legal information
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    ABOUT_LEGAL_SETTINGS = 225;
+
+
+    // OPEN: Settings > Developer options > Inactive apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FUELGAUGE_INACTIVE_APPS = 238;
+
+    // OPEN: Settings > Security > Nexus Imprint > Add Fingerprint
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLLING = 240;
+    // OPEN: Fingerprint Enroll > Find Sensor
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_FIND_SENSOR = 241;
+
+    // OPEN: Fingerprint Enroll > Fingerprint Enrolled!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLL_FINISH = 242;
+
+    // OPEN: Fingerprint Enroll introduction
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLL_INTRO = 243;
+
+    // OPEN: Fingerprint Enroll > Let's Start!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLL_SIDECAR = 245;
+
+    // OPEN: Fingerprint Enroll SUW > Let's Start!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLLING_SETUP = 246;
+
+    // OPEN: Fingerprint Enroll SUW > Find Sensor
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_FIND_SENSOR_SETUP = 247;
+
+    // OPEN: Fingerprint Enroll SUW > Fingerprint Enrolled!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLL_FINISH_SETUP = 248;
+
+    // OPEN: Fingerprint Enroll SUW introduction
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    FINGERPRINT_ENROLL_INTRO_SETUP = 249;
+
+    // OPEN: Settings > Developer Options > Background Check
+    // CATEGORY: SETTINGS
+    // OS: N
+    BACKGROUND_CHECK_SUMMARY = 258;
+
+    // OPEN: Settings > Notifications > [App] > Channel Notifications
+    // CATEGORY: SETTINGS
+    // OS: N
+    NOTIFICATION_TOPIC_NOTIFICATION = 265;
+
+    // OPEN: Settings > Security > User credentials
+    // CATEGORY: Settings
+    // OS: N
+    USER_CREDENTIALS = 285;
+
+    // Logs that the user has edited the enabled VR listeners.
+    // CATEGORY: SETTINGS
+    // OS: N
+    VR_MANAGE_LISTENERS = 334;
+
+    // Settings -> Accessibility -> Click after pointer stops moving
+    // CATEGORY: SETTINGS
+    // OS: N
+    ACCESSIBILITY_TOGGLE_AUTOCLICK = 335;
+
+    // Settings -> Sound
+    // CATEGORY: SETTINGS
+    // OS: N
+    SOUND = 336;
+
+    // Settings -> Notifications -> Gear
+    // CATEGORY: SETTINGS
+    // OS: N
+    CONFIGURE_NOTIFICATION = 337;
+
+    // Settings -> Wi-Fi -> Gear
+    // CATEGORY: SETTINGS
+    // OS: N
+    CONFIGURE_WIFI = 338;
+
+    // Settings -> Display -> Display size
+    // OS: N
+    DISPLAY_SCREEN_ZOOM = 339;
+
+    // Settings -> Display -> Font size
+    // CATEGORY: SETTINGS
+    // OS: N
+    ACCESSIBILITY_FONT_SIZE = 340;
+
+    // Settings -> Data usage -> Cellular/Wi-Fi data usage
+    // CATEGORY: SETTINGS
+    // OS: N
+    DATA_USAGE_LIST = 341;
+
+    // Settings -> Data usage -> Billing cycle or DATA_USAGE_LIST -> Gear
+    // CATEGORY: SETTINGS
+    // OS: N
+    BILLING_CYCLE = 342;
+
+    // DATA_USAGE_LIST -> Any item or App info -> Data usage
+    // CATEGORY: SETTINGS
+    // OS: N
+    APP_DATA_USAGE = 343;
+
+    // Settings -> Language & input -> Language
+    // CATEGORY: SETTINGS
+    // OS: N
+    USER_LOCALE_LIST = 344;
+
+    // Settings -> Language & input -> Virtual keyboard
+    // CATEGORY: SETTINGS
+    // OS: N
+    VIRTUAL_KEYBOARDS = 345;
+
+    // Settings -> Language & input -> Physical keyboard
+    // CATEGORY: SETTINGS
+    // OS: N
+    PHYSICAL_KEYBOARDS = 346;
+
+    // Settings -> Language & input -> Virtual keyboard -> Add a virtual keyboard
+    // CATEGORY: SETTINGS
+    // OS: N
+    ENABLE_VIRTUAL_KEYBOARDS = 347;
+
+    // Settings -> Data usage -> Data Saver
+    // CATEGORY: SETTINGS
+    // OS: N
+    DATA_SAVER_SUMMARY = 348;
+
+    // Settings -> Data usage -> Data Saver -> Unrestricted data access
+    // CATEGORY: SETTINGS
+    // OS: N
+    DATA_USAGE_UNRESTRICTED_ACCESS = 349;
+
+    // Settings -> Apps -> Gear -> Special access
+    SPECIAL_ACCESS = 351;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY = 367;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification gestures (Renamed in O)
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification -> Magnify with triple-tap
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification -> Magnify with button
+    // ACTION: New magnification gesture configuration is chosen
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 368;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Font size
+    // ACTION: New font size is chosen
+    //  SUBTYPE: 0 is small, 1 is default, 2 is large, 3 is largest
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_FONT_SIZE = 369;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Display size
+    // ACTION: New display size is chosen
+    //  SUBTYPE: 0 is small, 1 is default, 2 is large, 3 is larger, 4 is largest
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_DISPLAY_SIZE = 370;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> TalkBack
+    // ACTION: New screen reader configuration is chosen
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_TOGGLE_SCREEN_READER = 371;
+
+    // Airplane mode on
+    SETTINGS_CONDITION_AIRPLANE_MODE = 377;
+    // AKA Data saver on
+    SETTINGS_CONDITION_BACKGROUND_DATA = 378;
+    // Battery saver on
+    SETTINGS_CONDITION_BATTERY_SAVER = 379;
+    // Cellular data off
+    SETTINGS_CONDITION_CELLULAR_DATA = 380;
+    // Do not disturb on
+    SETTINGS_CONDITION_DND = 381;
+    // Hotspot on
+    SETTINGS_CONDITION_HOTSPOT = 382;
+    // Work profile off
+    SETTINGS_CONDITION_WORK_MODE = 383;
+
+    // Settings > Apps > Gear > Special Access > Premium SMS access
+    PREMIUM_SMS_ACCESS = 388;
+
+    // OPEN: Settings > Accounts > Work profile settings
+    // CATEGORY: SETTINGS
+    ACCOUNTS_WORK_PROFILE_SETTINGS = 401;
+
+    // Settings -> Dev options -> Convert to file encryption
+    CONVERT_FBE = 402;
+
+    // Settings -> Dev options -> Convert to file encryption -> WIPE AND CONVERT...
+    CONVERT_FBE_CONFIRM = 403;
+
+    // Settings -> Dev options -> Running services
+    RUNNING_SERVICES = 404;
+
+    // The dialog shown by 3P intent to change current webview implementation.
+    WEBVIEW_IMPLEMENTATION = 405;
+
+    // OPEN: Settings > Internal storage > Storage manager
+    // CATEGORY: SETTINGS
+    STORAGE_MANAGER_SETTINGS = 458;
+
+    // OPEN: Settings -> Gestures
+    // CATEGORY: SETTINGS
+    SETTINGS_GESTURES = 459;
+
+    // OPEN: Settings > Display > Night Light
+    // CATEGORY: SETTINGS
+    NIGHT_DISPLAY_SETTINGS = 488;
+
+    // Night Light on
+    SETTINGS_CONDITION_NIGHT_DISPLAY = 492;
+
+    // OPEN: Settings > Language & input > Personal dictionary (single locale)
+    USER_DICTIONARY_SETTINGS = 514;
+
+    // OPEN: Settings > Date & time > Select time zone
+    ZONE_PICKER = 515;
+
+    // OPEN: Settings > Security > Device administrators
+    DEVICE_ADMIN_SETTINGS = 516;
+
+    // OPEN: Settings > Security > Factory Reset Protection dialog
+    DIALOG_FRP = 528;
+
+    // OPEN: Settings > Custom list preference with confirmation message
+    DIALOG_CUSTOM_LIST_CONFIRMATION = 529;
+
+    // OPEN: Settings > APN Editor > Error dialog
+    DIALOG_APN_EDITOR_ERROR = 530;
+
+    // OPEN: Settings > Users > Edit owner info dialog
+    DIALOG_OWNER_INFO_SETTINGS = 531;
+
+    // OPEN: Settings > Security > Use one lock dialog
+    DIALOG_UNIFICATION_CONFIRMATION = 532;
+
+    // OPEN: Settings > Security > User Credential
+    DIALOG_USER_CREDENTIAL = 533;
+
+    // OPEN: Settings > Accounts > Remove account
+    DIALOG_REMOVE_USER = 534;
+
+    // OPEN: Settings > Accounts > Confirm auto sync dialog
+    DIALOG_CONFIRM_AUTO_SYNC_CHANGE = 535;
+
+    // OPEN: Settings > Apps > Dialog for running service details
+    DIALOG_RUNNIGN_SERVICE = 536;
+
+    // OPEN: Settings > Bluetooth > Rename this device
+    DIALOG_BLUETOOTH_RENAME = 538;
+
+    // OPEN: Settings > Battery optimization > details for app
+    DIALOG_HIGH_POWER_DETAILS = 540;
+
+    // OPEN: Settings > Keyboard > Show keyboard layout dialog
+    DIALOG_KEYBOARD_LAYOUT = 541;
+
+    // OPEN: Settings > WIFI Scan permission dialog
+    DIALOG_WIFI_SCAN_MODE = 543;
+
+    // OPEN: Settings > Wireless > VPN > Config dialog
+    DIALOG_LEGACY_VPN_CONFIG = 545;
+
+    // OPEN: Settings > Wireless > VPN > Config dialog for app
+    DIALOG_VPN_APP_CONFIG = 546;
+
+    // OPEN: Settings > Wireless > VPN > Cannot connect dialog
+    DIALOG_VPN_CANNOT_CONNECT = 547;
+
+    // OPEN: Settings > Wireless > VPN > Replace existing VPN dialog
+    DIALOG_VPN_REPLACE_EXISTING = 548;
+
+    // OPEN: Settings > Billing cycle > Edit billing cycle dates dialog
+    DIALOG_BILLING_CYCLE = 549;
+
+    // OPEN: Settings > Billing cycle > Edit data limit/warning dialog
+    DIALOG_BILLING_BYTE_LIMIT = 550;
+
+    // OPEN: Settings > Billing cycle > turn on data limit dialog
+    DIALOG_BILLING_CONFIRM_LIMIT = 551;
+
+    // OPEN: Settings > Service > Turn off notification access dialog
+    DIALOG_DISABLE_NOTIFICATION_ACCESS = 552;
+
+    // OPEN: Settings > Sound > Use personal sound for work profile dialog
+    DIALOG_UNIFY_SOUND_SETTINGS = 553;
+
+    // OPEN: Settings > Zen mode > Dialog warning about the zen access privileges being granted.
+    DIALOG_ZEN_ACCESS_GRANT = 554;
+
+    // OPEN: Settings > Zen mode > Dialog warning about the zen access privileges being revoked.
+    DIALOG_ZEN_ACCESS_REVOKE = 555;
+
+    // OPEN: Settings > Zen mode > Dialog that picks time for zen mode.
+    DIALOG_ZEN_TIMEPICKER = 556;
+
+    // OPEN: Settings > Apps > Dialog that informs user to allow service access for app.
+    DIALOG_SERVICE_ACCESS_WARNING = 557;
+
+    // OPEN: Settings > Apps > Dialog for app actions (such as force stop/clear data)
+    DIALOG_APP_INFO_ACTION = 558;
+
+    // OPEN: Settings > Storage > Dialog for forgetting a storage device
+    DIALOG_VOLUME_FORGET = 559;
+
+    // OPEN: Settings > Storage > Dialog for initializing a volume
+    DIALOG_VOLUME_INIT = 561;
+
+    // OPEN: Settings > Storage > Dialog for unmounting a volume
+    DIALOG_VOLUME_UNMOUNT = 562;
+
+    // OPEN: Settings > Storage > Dialog for renaming a volume
+    DIALOG_VOLUME_RENAME = 563;
+
+    // OPEN: Settings > Storage > Dialog for clear cache
+    DIALOG_STORAGE_CLEAR_CACHE = 564;
+
+    // OPEN: Settings > Storage > Dialog for system info
+    DIALOG_STORAGE_SYSTEM_INFO = 565;
+
+    // OPEN: Settings > Storage > Dialog for other info
+    DIALOG_STORAGE_OTHER_INFO = 566;
+
+    // OPEN: Settings > Storage > Dialog for user info
+    DIALOG_STORAGE_USER_INFO = 567;
+    // OPEN: Settings > Add fingerprint > Dialog when user touches fingerprint icon.
+    DIALOG_FINGERPRINT_ICON_TOUCH = 568;
+
+    // OPEN: Settings > Add fingerprint > Error dialog
+    DIALOG_FINGERPINT_ERROR = 569;
+
+    // OPEN: Settings > Fingerprint > Rename or delete dialog
+    DIALOG_FINGERPINT_EDIT = 570;
+
+    // OPEN: Settings > Fingerprint > Dialog for deleting last fingerprint
+    DIALOG_FINGERPINT_DELETE_LAST = 571;
+
+    // OPEN: SUW > Fingerprint > Dialog to confirm skip fingerprint setup entirely.
+    DIALOG_FINGERPRINT_SKIP_SETUP = 573;
+
+    // OPEN: Settings > Proxy Selector error dialog
+    DIALOG_PROXY_SELECTOR_ERROR = 574;
+
+    // OPEN: Settings > Wifi > P2P Settings > Disconnect dialog
+    DIALOG_WIFI_P2P_DISCONNECT = 575;
+
+    // OPEN: Settings > Wifi > P2P Settings > Cancel connection dialog
+    DIALOG_WIFI_P2P_CANCEL_CONNECT = 576;
+
+    // OPEN: Settings > Wifi > P2P Settings > Rename dialog
+    DIALOG_WIFI_P2P_RENAME = 577;
+
+    // OPEN: Settings > Wifi > P2P Settings > Forget group dialog
+    DIALOG_WIFI_P2P_DELETE_GROUP = 578;
+
+    // OPEN: Settings > APN > Restore default dialog
+    DIALOG_APN_RESTORE_DEFAULT = 579;
+
+    // OPEN: Settings > Encryption interstitial accessibility warning dialog
+    DIALOG_ENCRYPTION_INTERSTITIAL_ACCESSIBILITY = 581;
+
+    // OPEN: Settings > Acessibility > Enable accessiblity service dialog
+    DIALOG_ACCESSIBILITY_SERVICE_ENABLE = 583;
+
+    // OPEN: Settings > Acessibility > Disable accessiblity service dialog
+    DIALOG_ACCESSIBILITY_SERVICE_DISABLE = 584;
+
+    // OPEN: Settings > Account > Remove account dialog
+    DIALOG_ACCOUNT_SYNC_REMOVE = 585;
+
+    // OPEN: Settings > Account > Remove account failed dialog
+    DIALOG_ACCOUNT_SYNC_FAILED_REMOVAL = 586;
+
+    // OPEN: Settings > Account > Cannot do onetime sync dialog
+    DIALOG_ACCOUNT_SYNC_CANNOT_ONETIME_SYNC = 587;
+
+    // OPEN: Settings > Display > Night light > Set start time dialog
+    DIALOG_NIGHT_DISPLAY_SET_START_TIME = 588;
+
+    // OPEN: Settings > Display > Night light > Set end time dialog
+    DIALOG_NIGHT_DISPLAY_SET_END_TIME = 589;
+
+
+
+        // OPEN: Settings > User > Edit info dialog
+        DIALOG_USER_EDIT = 590;
+
+        // OPEN: Settings > User > Confirm remove dialog
+        DIALOG_USER_REMOVE = 591;
+
+        // OPEN: Settings > User > Enable calling dialog
+        DIALOG_USER_ENABLE_CALLING = 592;
+
+        // OPEN: Settings > User > Enable calling and sms dialog
+        DIALOG_USER_ENABLE_CALLING_AND_SMS = 593;
+
+        // OPEN: Settings > User > Cannot manage device message dialog
+        DIALOG_USER_CANNOT_MANAGE = 594;
+
+        // OPEN: Settings > User > Add user dialog
+        DIALOG_USER_ADD = 595;
+
+        // OPEN: Settings > User > Setup user dialog
+        DIALOG_USER_SETUP = 596;
+
+        // OPEN: Settings > User > Setup profile dialog
+        DIALOG_USER_SETUP_PROFILE = 597;
+
+        // OPEN: Settings > User > Choose user type dialog
+        DIALOG_USER_CHOOSE_TYPE = 598;
+
+        // OPEN: Settings > User > Need lockscreen dialog
+        DIALOG_USER_NEED_LOCKSCREEN = 599;
+
+        // OPEN: Settings > User > Confirm exit guest mode dialog
+        DIALOG_USER_CONFIRM_EXIT_GUEST = 600;
+
+        // OPEN: Settings > User > Edit user profile dialog
+        DIALOG_USER_EDIT_PROFILE = 601;
+
+
+    // OPEN: Settings > Wifi > Saved AP > Edit dialog
+    DIALOG_WIFI_SAVED_AP_EDIT = 602;
+
+    // OPEN: Settings > Wifi > Edit AP dialog
+    DIALOG_WIFI_AP_EDIT = 603;
+
+    // OPEN: Settings > Wifi > Write config to NFC dialog
+    DIALOG_WIFI_WRITE_NFC = 606;
+
+    // OPEN: Settings > Date > Date picker dialog
+    DIALOG_DATE_PICKER = 607;
+
+    // OPEN: Settings > Date > Time picker dialog
+    DIALOG_TIME_PICKER = 608;
+
+    // OPEN: Settings > Wireless > Manage wireless plan dialog
+    DIALOG_MANAGE_MOBILE_PLAN = 609;
+
+    // OPEN Settings > Bluetooth > Attempt to connect to device that shows dialog
+    BLUETOOTH_DIALOG_FRAGMENT = 613;
+
+    // OPEN: Settings > Security
+    // CATEGORY: SETTINGS
+    // OS: O
+    ENTERPRISE_PRIVACY_SETTINGS = 628;
+
+    // OPEN: Settings > System
+    SETTINGS_SYSTEM_CATEGORY = 744;
+
+    // OPEN: Settings > Storage
+    SETTINGS_STORAGE_CATEGORY = 745;
+
+    // OPEN: Settings > Network & Internet
+    SETTINGS_NETWORK_CATEGORY = 746;
+
+    // OPEN: Settings > Connected Device
+    SETTINGS_CONNECTED_DEVICE_CATEGORY = 747;
+
+    // OPEN: Settings > App & Notification
+    SETTINGS_APP_NOTIF_CATEGORY = 748;
+
+    // OPEN: Settings > System > Language & Region
+    SETTINGS_LANGUAGE_CATEGORY = 750;
+
+    // OPEN: Settings > System > Input & Gesture > Swipe to notification gesture
+    SETTINGS_GESTURE_SWIPE_TO_NOTIFICATION = 751;
+
+    // OPEN: Settings > System > Input & Gesture > Double tap power button gesture
+    SETTINGS_GESTURE_DOUBLE_TAP_POWER = 752;
+
+    // OPEN: Settings > System > Input & Gesture > Pick up gesture
+    SETTINGS_GESTURE_PICKUP = 753;
+
+    // OPEN: Settings > System > Input & Gesture > Double tap screen gesture
+    SETTINGS_GESTURE_DOUBLE_TAP_SCREEN = 754;
+
+    // OPEN: Settings > System > Input & Gesture > Double twist gesture
+    SETTINGS_GESTURE_DOUBLE_TWIST = 755;
+
+    // OPEN: Settings > Apps > Default Apps > Default browser
+    DEFAULT_BROWSER_PICKER = 785;
+    // OPEN: Settings > Apps > Default Apps > Default emergency app
+    DEFAULT_EMERGENCY_APP_PICKER = 786;
+
+    // OPEN: Settings > Apps > Default Apps > Default home
+    DEFAULT_HOME_PICKER = 787;
+
+    // OPEN: Settings > Apps > Default Apps > Default phone
+    DEFAULT_PHONE_PICKER = 788;
+
+    // OPEN: Settings > Apps > Default Apps > Default sms
+    DEFAULT_SMS_PICKER = 789;
+
+    // OPEN: Settings > Apps > Default Apps > Warning dialog to confirm selection
+    DEFAULT_APP_PICKER_CONFIRMATION_DIALOG = 791;
+
+    // OPEN: Settings > Apps > Default Apps > Default autofill app
+    DEFAULT_AUTOFILL_PICKER = 792;
+
+    // OPEN: Settings > Apps > Gear > Special Access > Install other apps
+    // CATEGORY: SETTINGS
+    // OS: 8.0
+    MANAGE_EXTERNAL_SOURCES = 808;
+
+    // Logs that the user has edited the picture-in-picture settings.
+    // CATEGORY: SETTINGS
+    SETTINGS_MANAGE_PICTURE_IN_PICTURE = 812;
+
+    // OPEN: SUW Welcome Screen -> Vision Settings -> Select to Speak
+    // ACTION: Select to Speak configuration is chosen
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    SUW_ACCESSIBILITY_TOGGLE_SELECT_TO_SPEAK = 817;
+
+    // OPEN: Settings > System > Backup
+    // CATEGORY: SETTINGS
+    // OS: O
+    BACKUP_SETTINGS = 818;
+
+    // OPEN: Settings > Storage > Games
+    // CATEGORY: SETTINGS
+    // OS: O
+    APPLICATIONS_STORAGE_GAMES = 838;
+
+    // OPEN: Settings > Storage > Audio and Music
+    // CATEGORY: SETTINGS
+    // OS: O
+    APPLICATIONS_STORAGE_MUSIC = 839;
+
+    // ACTION: Settings > Storage > Free Up Space to launch Deletion Helper
+    // CATEGORY: SETTINGS
+    // OS: O
+    STORAGE_FREE_UP_SPACE_NOW = 840;
+
+    // ACTION: Settings > Storage > Files to open the File Manager
+    // CATEGORY: SETTINGS
+    // OS: O
+    STORAGE_FILES = 841;
+
+    // OPEN: Settings > Apps > Default Apps > Assist >  Default assist
+    DEFAULT_ASSIST_PICKER = 843;
+
+    // OPEN: Settings > Apps > Default Apps > Assist >  Default voice input
+    DEFAULT_VOICE_INPUT_PICKER = 844;
+
+    // OPEN: Settings > Storage > [Profile]
+    SETTINGS_STORAGE_PROFILE = 845;
+
+    // OPEN: Settings > Security & screen lock -> Encryption & crendentials
+    // CATEGORY: SETTINGS
+    // OS: O
+    ENCRYPTION_AND_CREDENTIAL = 846;
+
+    // OPEN: Settings > Wi-Fi > Network Details (click on Access Point)
+    // CATEGORY: SETTINGS
+    // OS: O
+    WIFI_NETWORK_DETAILS = 849;
+
+    // OPEN: Settings > Wi-Fi > Wifi Preferences -> Advanced -> Network Scorer
+    // CATEGORY: SETTINGS
+    // OS: O
+    SETTINGS_NETWORK_SCORER = 861;
+
+    // OPEN: Settings > About device > Model > Hardware info dialog
+    DIALOG_SETTINGS_HARDWARE_INFO = 862;
+
+    // OPEN: Settings > Security & screen lock -> Lock screen preferences
+    // CATEGORY: SETTINGS
+    SETTINGS_LOCK_SCREEN_PREFERENCES = 882;
+
+
+    // OPEN: Settings -> Display -> When in VR Mode
+    VR_DISPLAY_PREFERENCE = 921;
+
+    // OPEN: Settings > Accessibility > Magnification
+    // CATEGORY: SETTINGS
+    // OS: O
+    ACCESSIBILITY_SCREEN_MAGNIFICATION_SETTINGS = 922;
+
+    // OPEN: Settings -> System -> Reset options
+    RESET_DASHBOARD = 924;
+
+     // OPEN: Settings > Security > Nexus Imprint > [Fingerprint] > Delete
+    // CATEGORY: SETTINGS
+    // OS: O
+    FINGERPRINT_REMOVE_SIDECAR = 934;
+
+    // OPEN: Settings > Storage > Movies & TV
+    // CATEGORY: SETTINGS
+    // OS: O
+    APPLICATIONS_STORAGE_MOVIES = 935;
+
+    // OPEN: Settings > Security > Managed Device Info > Apps installed
+    // CATEGORY: SETTINGS
+    // OS: O
+    ENTERPRISE_PRIVACY_INSTALLED_APPS = 938;
+
+    // OPEN: Settings > Security > Managed Device Info > nnn permissions
+    // CATEGORY: SETTINGS
+    // OS: O
+    ENTERPRISE_PRIVACY_PERMISSIONS = 939;
+
+
+    // OPEN: Settings > Security > Managed Device Info > Default apps
+    // CATEGORY: SETTINGS
+    // OS: O
+    ENTERPRISE_PRIVACY_DEFAULT_APPS = 940;
+
+    // OPEN: Choose screen lock dialog in Settings
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    SETTINGS_CHOOSE_LOCK_DIALOG = 990;
+
+    // OPEN: Settings > System > Languages & input > Assist gesture
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    SETTINGS_ASSIST_GESTURE = 996;
+
     // OPEN: Settings > Connected Devices > Bluetooth > (click on details link for a paired device)
     BLUETOOTH_DEVICE_DETAILS = 1009;
 
+    // OPEN: Settings > credential pages - prompt for key guard configuration confirmation
+    CONFIGURE_KEYGUARD_DIALOG = 1010;
+
+    // OPEN: Settings > Network > Tether > Wi-Fi hotspot
+    WIFI_TETHER_SETTINGS = 1014;
+
+    // OPEN: Settings->Connected Devices->Bluetooth->(click on details link for a paired device)
+    // -> Edit name button.
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    DIALOG_BLUETOOTH_PAIRED_DEVICE_RENAME = 1015;
+
     // OPEN: Settings > Connected devices > Bluetooth > Pair new device
+    // CATEGORY: SETTINGS
+    // OS: O DR
     BLUETOOTH_PAIRING = 1018;
 
+    // OPEN: Settings->Connected Devices->Bluetooth->(click on details link for a paired device)
+    // -> Forget button.
+    // CATEGORY: SETTINGS
+    // OS: O DR
+    DIALOG_BLUETOOTH_PAIRED_DEVICE_FORGET = 1031;
+
+    // OPEN: Settings > Storage > Photos & Videos
+    // CATEGORY: SETTINGS
+    // OS: O MR
+    APPLICATIONS_STORAGE_PHOTOS = 1092;
+
+    // OPEN: Settings > Display > Colors
+    // CATEGORY: SETTINGS
+    // OS: O MR
+    COLOR_MODE_SETTINGS = 1143;
+
+    // OPEN: Settings > Developer Options > Experiment dashboard
+    // CATEGORY: SETTINGS
+    SETTINGS_FEATURE_FLAGS_DASHBOARD = 1217;
+
+    // OPEN: Settings > Notifications > [App] > Topic Notifications
+    // CATEGORY: SETTINGS
+    // OS: P
+    NOTIFICATION_CHANNEL_GROUP = 1218;
+
+    // OPEN: Settings > Developer options > Enable > Info dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_ENABLE_DEVELOPMENT_OPTIONS = 1219;
+
+    // OPEN: Settings > Developer options > OEM unlocking > Info dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_ENABLE_OEM_UNLOCKING = 1220;
+
+    // OPEN: Settings > Developer options > USB debugging > Info dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_ENABLE_ADB = 1222;
+
+    // OPEN: Settings > Security > Nexus Imprint > [Fingerprint]
+    // CATEGORY: SETTINGS
+    // OS: P
+    FINGERPRINT_AUTHENTICATE_SIDECAR = 1221;
+
+    // OPEN: Settings > Developer options > Revoke USB debugging authorizations > Info dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_CLEAR_ADB_KEYS = 1223;
+
+    // Open: Settings > Developer options > Quick setting tile config
+    // CATEGORY: SETTINGS
+    // OS: P
+    DEVELOPMENT_QS_TILE_CONFIG = 1224;
+
+    // OPEN: Settings > Developer options > Store logger data persistently on device > Info dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_LOG_PERSIST = 1225;
+
+    // OPEN: Settings > Network & Internet > Mobile network > Wi-Fi calling
+    // CATEGORY: SETTINGS
+    // OS: P
+    WIFI_CALLING_FOR_SUB = 1230;
+
+    // Open: Settings > Dev options > Oem unlock > lock it > warning dialog.
+    // OS: P
+    DIALOG_OEM_LOCK_INFO = 1238;
+
+    // Open: Settings > System > About phone > IMEI
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_IMEI_INFO = 1240;
+
+    // OPEN: Settings > System > About Phone > Sim status
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_SIM_STATUS = 1246;
+
+    // OPEN: Settings > System > About Phone > Android Version
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_FIRMWARE_VERSION = 1247;
+
+    // OPEN: Settings > Battery(version 2)
+    // CATEGORY: SETTINGS
+    // OS: P
+    FUELGAUGE_POWER_USAGE_SUMMARY_V2 = 1263;
+
+    // OPEN: Settings > Connected devices > Connection preferences
+    // CATEGORY: SETTINGS
+    // OS: P
+    CONNECTION_DEVICE_ADVANCED = 1264;
+
+    // OPEN: Settings > Security > Screen lock gear icon
+    // CATEGORY: SETTINGS
+    // OS: P
+    SCREEN_LOCK_SETTINGS = 1265;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Delete rule (trash can icon)
+    // CATEGORY: SETTINGS
+    // OS: P
+    NOTIFICATION_ZEN_MODE_DELETE_RULE_DIALOG = 1266;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Add rule > Event/Time
+    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Select rule ("Event") > Rule name
+    // CATEGORY: SETTINGS
+    // OS: P
+    NOTIFICATION_ZEN_MODE_RULE_NAME_DIALOG = 1269;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Add rule
+    // CATEGORY: SETTINGS
+    // OS: P
+    NOTIFICATION_ZEN_MODE_RULE_SELECTION_DIALOG = 1270;
+
+    // OPEN: Settings > Battery > Smart Battery
+    // CATEGORY: SETTINGS
+    // OS: P
+    FUELGAUGE_SMART_BATTERY = 1281;
+
+    // OPEN: Settings > Battery > Smart Battery > Restricted apps
+    // CATEGORY: SETTINGS
+    // OS: P
+    FUELGAUGE_RESTRICTED_APP_DETAILS = 1285;
+
+    // OPEN: Settings > Sound & notification > Do Not Disturb > Turn on now
+    // CATEGORY: SETTINGS
+    // OS: P
+    NOTIFICATION_ZEN_MODE_ENABLE_DIALOG = 1286;
+
+    // OPEN: Settings->Connected Devices->USB->(click on details link)
+    // CATEGORY: SETTINGS
+    // OS: P
+    USB_DEVICE_DETAILS = 1291;
+
+    // OPEN: Settings > Accessibility > Vibration
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACCESSIBILITY_VIBRATION = 1292;
+
+    // OPEN: Settings > Accessibility > Vibration > Notification vibration
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACCESSIBILITY_VIBRATION_NOTIFICATION = 1293;
+
+    // OPEN: Settings > Accessibility > Vibration > Touch vibration
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACCESSIBILITY_VIBRATION_TOUCH = 1294;
+
+    // OPEN: Settings->Developer Options->Default USB
+    // CATEGORY: SETTINGS
+    // OS: P
+    USB_DEFAULT = 1312;
+
+    // OPEN: Settings > Battery > Battery tip > Battery tip Dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    FUELGAUGE_BATTERY_TIP_DIALOG = 1323;
+
+    // OPEN: DND Settings > What to block
+    // OS: P
+    ZEN_WHAT_TO_BLOCK = 1339;
+
+    // OPEN: Settings > Sounds > Do Not Disturb > Duration
+    // CATEGORY: SETTINGS
+    // OS: P
+    NOTIFICATION_ZEN_MODE_DURATION_DIALOG = 1341;
+
+    // OPEN: Settings > Date & time > Select time zone -> Region
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_ZONE_PICKER_REGION = 1355;
+
+    // OPEN: Settings > Date & time > Select time zone -> Time Zone
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_ZONE_PICKER_TIME_ZONE = 1356;
+    // OPEN: Settings > Date & time > Select time zone -> Select UTC Offset
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_ZONE_PICKER_FIXED_OFFSET = 1357;
+
+    // OPEN: Settings > Gestures > Prevent Ringing
+    // OS: P
+    SETTINGS_PREVENT_RINGING = 1360;
+
+    // Settings > Condition > Device muted
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_CONDITION_DEVICE_MUTED = 1368;
+
+    // Settings > Condition > Device vibrate
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_CONDITION_DEVICE_VIBRATE = 1369;
+
+    // OPEN: Settings > Connected devices > previously connected devices
+    // CATEGORY: SETTINGS
+    // OS: P
+    PREVIOUSLY_CONNECTED_DEVICES = 1370;
+
+    // OPEN: Settings > Network & Internet > Wi-Fi > Wi-Fi Preferences > Turn on Wi-Fi automatically
+    //       note: Wifi Scanning must be off for this dialog to show
+    // CATEGORY: SETTINGS
+    // OS: P
+    WIFI_SCANNING_NEEDED_DIALOG = 1373;
+
+    // OPEN: Settings > System > Gestures > Swipe up gesture
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_GESTURE_SWIPE_UP = 1374;
+
+    // OPEN: Settings > Storage > Dialog to format a storage volume
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_VOLUME_FORMAT = 1375;
+
+    // OPEN: DND onboarding activity
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_ZEN_ONBOARDING = 1380;
+
+    // OPEN: Settings > Display > Auto brightness
+    // CATEGORY: SETTINGS
+    // OS: P
+    SETTINGS_AUTO_BRIGHTNESS = 1381;
+
+     // OPEN: Settings > Connected Devices > Bluetooth
+    // CATEGORY: SETTINGS
+    // OS: P
+    BLUETOOTH_FRAGMENT = 1390;
+
+    // Screen: DND Settings > Notifications
+    // OS: P
+    SETTINGS_ZEN_NOTIFICATIONS = 1400;
+
+    // An event category for slices.
+    // OPEN: Slice became visible.
+    // CLOSE: Slice became invisible.
+    // ACTION: Slice was tapped.
+    SLICE = 1401;
+
+    // OPEN: Settings -> Developer Options -> Disable Bluetooth A2DP hardware
+    // offload
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_BLUETOOTH_DISABLE_A2DP_HW_OFFLOAD = 1441;
+
     // OPEN: Settings homepage
     SETTINGS_HOMEPAGE = 1502;
 
+    // OPEN: Settings > Create shortcut(widget)
+    // CATEGORY: SETTINGS
+    // OS: Q
+    SETTINGS_CREATE_SHORTCUT = 1503;
+
+    // OPEN: Face Enroll introduction
+    // CATEGORY: SETTINGS
+    // OS: Q
+    FACE_ENROLL_INTRO = 1506;
+
+    // OPEN: Face Enroll introduction
+    // CATEGORY: SETTINGS
+    // OS: Q
+    FACE_ENROLL_ENROLLING = 1507;
+
+    // OPEN: Face Enroll introduction
+    // CATEGORY: SETTINGS
+    // OS: Q
+    FACE_ENROLL_FINISHED = 1508;
+
+    // OPEN: Face Enroll sidecar
+    // CATEGORY: SETTINGS
+    // OS: Q
+    FACE_ENROLL_SIDECAR = 1509;
+
+    // OPEN: Settings > Add face > Error dialog
+    // OS: Q
+    DIALOG_FACE_ERROR = 1510;
+
+    // OPEN: Settings > Security > Face
+    // CATEGORY: SETTINGS
+    // OS: Q
+    FACE = 1511;
+
+   // OPEN: Settings > Acessibility > HearingAid pairing instructions dialog
+    // CATEGORY: SETTINGS
+    // OS: Q
+    DIALOG_ACCESSIBILITY_HEARINGAID = 1512;
+
+    // OPEN: Settings > Add face
+    // OS: Q
+    FACE_ENROLL_PREVIEW = 1554;
+
+    // OPEN: Settings > Network & Internet > Wi-Fi > Add network
+    // CATEGORY: SETTINGS
+    // OS: Q
+    SETTINGS_WIFI_ADD_NETWORK = 1556;
+
+    // OPEN: Settings > System > Input & Gesture > Reach up gesture
+    // OS: Q
+    SETTINGS_GESTURE_WAKE_LOCK_SCREEN = 1557;
+
     // OPEN: Settings > System > Input & Gesture > Wake screen
     SETTINGS_GESTURE_WAKE_SCREEN = 1570;
 
@@ -74,6 +2079,19 @@
     // OPEN: Settings > Privacy
     TOP_LEVEL_PRIVACY = 1587;
 
+    // OPEN: Settings > Sound & notification > Do Not Disturb > See all exceptions >
+    // Allow apps to override
+    // CATEGORY: SETTINGS
+    // OS: Q
+    NOTIFICATION_ZEN_MODE_OVERRIDING_APPS = 1588;
+
+
+    // OPEN: Settings > Sound & notification > Do Not Disturb > See all exceptions >
+    // Allow apps to override > Choose app
+    // CATEGORY: SETTINGS
+    // OS: Q
+    NOTIFICATION_ZEN_MODE_OVERRIDING_APP = 1589;
+
     // OPEN: Settings > Developer options > Disable > Info dialog
     DIALOG_DISABLE_DEVELOPMENT_OPTIONS = 1591;
 
@@ -85,4 +2103,84 @@
 
     // OPEN: Settings > Apps & Notifications -> Special app access -> Financial Apps Sms Access
     SETTINGS_FINANCIAL_APPS_SMS_ACCESS = 1597;
+
+
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_SETTINGS = 1604;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior > Custom
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_SOUND_SETTINGS = 1605;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_DEFAULT_SETTINGS = 1606;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+    // > Notification restriction
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_NOTIFICATION_RESTRICTIONS = 1608;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+    // > Notification restriction > Custom
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_VIS_EFFECTS = 1609;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+    // > Notification restriction > Custom > Allow messages
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_MESSAGES = 1610;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule)
+    // > Do Not Disturb behavior > Use default Do Not Disturb behavior
+    // > Notification restriction > Custom > Allow calls
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_RULE_CALLS = 1611;
+
+    // OPEN: Settings > Sound > Do Not Disturb > Click footer link if custom settings applied
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ZEN_CUSTOM_SETTINGS_DIALOG = 1612;
+
+    // OPEN: Settings > Developer Options > Game Update Packages
+    // CATEGORY: SETTINGS
+    // OS: Q
+    SETTINGS_GUP_DASHBOARD = 1613;
+
+    // OPEN: Settings > Accessibility > Vibration > Ring vibration
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ACCESSIBILITY_VIBRATION_RING = 1620;
+
+    // OPEN: Settings > System > Input & Gesture > Skip songs
+    SETTINGS_GESTURE_SKIP = 1624;
+
+    // OPEN: Settings > System > Input & Gesture > Silence alerts
+    SETTINGS_GESTURE_SILENCE = 1625;
+
+    // OPEN: Settings > System > Input & Gesture > Tap to check
+    SETTINGS_GESTURE_TAP_SCREEN = 1626;
+
+    // OPEN: Settings > Network & internet > Click Mobile network to land on a page with a list of
+    // SIM/eSIM subscriptions.
+    MOBILE_NETWORK_LIST = 1627;
+
+    // OPEN: Settings > Display > Adaptive sleep
+    // OS: Q
+    SETTINGS_ADAPTIVE_SLEEP = 1628;
 }
diff --git a/core/proto/android/app/window_configuration.proto b/core/proto/android/app/window_configuration.proto
index 2d15552..6cc1a40 100644
--- a/core/proto/android/app/window_configuration.proto
+++ b/core/proto/android/app/window_configuration.proto
@@ -29,4 +29,5 @@
     optional .android.graphics.RectProto app_bounds = 1;
     optional int32 windowing_mode = 2;
     optional int32 activity_type = 3;
+    optional .android.graphics.RectProto bounds = 4;
 }
diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto
index d0c9226..76c240e 100644
--- a/core/proto/android/bluetooth/enums.proto
+++ b/core/proto/android/bluetooth/enums.proto
@@ -41,3 +41,18 @@
     ENABLE_DISABLE_REASON_USER_SWITCH = 8;
     ENABLE_DISABLE_REASON_RESTORE_USER_SETTING = 9;
 }
+
+enum DirectionEnum {
+    DIRECTION_UNKNOWN = 0;
+    DIRECTION_OUTGOING = 1;
+    DIRECTION_INCOMING = 2;
+}
+
+// First item is the default value, other values follow Bluetooth spec definition
+enum LinkTypeEnum {
+    // Link type is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
+    LINK_TYPE_UNKNOWN = 0xFFF;
+    LINK_TYPE_SCO = 0x00;
+    LINK_TYPE_ACL = 0x01;
+    LINK_TYPE_ESCO = 0x02;
+}
diff --git a/core/proto/android/bluetooth/hci/enums.proto b/core/proto/android/bluetooth/hci/enums.proto
new file mode 100644
index 0000000..e1d96bb
--- /dev/null
+++ b/core/proto/android/bluetooth/hci/enums.proto
@@ -0,0 +1,519 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.bluetooth.hci;
+
+option java_outer_classname = "BluetoothHciProtoEnums";
+option java_multiple_files = true;
+
+// HCI command opcodes (OCF+OGF) from Bluetooth 5.0 specification Vol 2, Part E, Section 7
+// Original definition: system/bt/stack/include/hcidefs.h
+enum CommandEnum {
+    // Opcode is at most 2 bytes (0xFFFF), thus 0xFFFFF must not be a valid value
+    CMD_UNKNOWN = 0xFFFFF;
+    // Link control commands 0x0400
+    CMD_INQUIRY = 0x0401;
+    CMD_INQUIRY_CANCEL = 0x0402;
+    CMD_PERIODIC_INQUIRY_MODE = 0x0403;
+    CMD_EXIT_PERIODIC_INQUIRY_MODE = 0x0404;
+    CMD_CREATE_CONNECTION = 0x0405;
+    CMD_DISCONNECT = 0x0406;
+    CMD_ADD_SCO_CONNECTION = 0x0407; // Deprecated since Bluetooth 1.2
+    CMD_CREATE_CONNECTION_CANCEL = 0x0408;
+    CMD_ACCEPT_CONNECTION_REQUEST = 0x0409;
+    CMD_REJECT_CONNECTION_REQUEST = 0x040A;
+    CMD_LINK_KEY_REQUEST_REPLY = 0x040B;
+    CMD_LINK_KEY_REQUEST_NEG_REPLY = 0x040C;
+    CMD_PIN_CODE_REQUEST_REPLY = 0x040D;
+    CMD_PIN_CODE_REQUEST_NEG_REPLY = 0x040E;
+    CMD_CHANGE_CONN_PACKET_TYPE = 0x040F;
+    CMD_AUTHENTICATION_REQUESTED = 0x0411;
+    CMD_SET_CONN_ENCRYPTION = 0x0413;
+    CMD_CHANGE_CONN_LINK_KEY = 0x0415;
+    CMD_MASTER_LINK_KEY = 0x0417;
+    CMD_RMT_NAME_REQUEST = 0x0419;
+    CMD_RMT_NAME_REQUEST_CANCEL = 0x041A;
+    CMD_READ_RMT_FEATURES = 0x041B;
+    CMD_READ_RMT_EXT_FEATURES = 0x041C;
+    CMD_READ_RMT_VERSION_INFO = 0x041D;
+    CMD_READ_RMT_CLOCK_OFFSET = 0x041F;
+    CMD_READ_LMP_HANDLE = 0x0420;
+    CMD_SETUP_ESCO_CONNECTION = 0x0428;
+    CMD_ACCEPT_ESCO_CONNECTION = 0x0429;
+    CMD_REJECT_ESCO_CONNECTION = 0x042A;
+    CMD_IO_CAPABILITY_REQUEST_REPLY = 0x042B;
+    CMD_USER_CONF_REQUEST_REPLY = 0x042C;
+    CMD_USER_CONF_VALUE_NEG_REPLY = 0x042D;
+    CMD_USER_PASSKEY_REQ_REPLY = 0x042E;
+    CMD_USER_PASSKEY_REQ_NEG_REPLY = 0x042F;
+    CMD_REM_OOB_DATA_REQ_REPLY = 0x0430;
+    CMD_REM_OOB_DATA_REQ_NEG_REPLY = 0x0433;
+    CMD_IO_CAP_REQ_NEG_REPLY = 0x0434;
+    // BEGIN: AMP commands (not used in system/bt)
+    CMD_CREATE_PHYSICAL_LINK = 0x0435;
+    CMD_ACCEPT_PHYSICAL_LINK = 0x0436;
+    CMD_DISCONNECT_PHYSICAL_LINK = 0x0437;
+    CMD_CREATE_LOGICAL_LINK = 0x0438;
+    CMD_ACCEPT_LOGICAL_LINK = 0x0439;
+    CMD_DISCONNECT_LOGICAL_LINK = 0x043A;
+    CMD_LOGICAL_LINK_CANCEL = 0x043B;
+    CMD_FLOW_SPEC_MODIFY = 0x043C;
+    // END: AMP commands
+    CMD_ENH_SETUP_ESCO_CONNECTION = 0x043D;
+    CMD_ENH_ACCEPT_ESCO_CONNECTION = 0x043E;
+    CMD_TRUNCATED_PAGE = 0x043F;
+    CMD_TRUNCATED_PAGE_CANCEL = 0x0440;
+    CMD_SET_CLB = 0x0441;
+    CMD_RECEIVE_CLB = 0x0442;
+    CMD_START_SYNC_TRAIN = 0x0443;
+    CMD_RECEIVE_SYNC_TRAIN = 0x0444;
+    CMD_REM_OOB_EXTENDED_DATA_REQ_REPLY = 0x0445; // Not currently used in system/bt
+    // Link policy commands 0x0800
+    CMD_HOLD_MODE = 0x0801;
+    CMD_SNIFF_MODE = 0x0803;
+    CMD_EXIT_SNIFF_MODE = 0x0804;
+    CMD_PARK_MODE = 0x0805;
+    CMD_EXIT_PARK_MODE = 0x0806;
+    CMD_QOS_SETUP = 0x0807;
+    CMD_ROLE_DISCOVERY = 0x0809;
+    CMD_SWITCH_ROLE = 0x080B;
+    CMD_READ_POLICY_SETTINGS = 0x080C;
+    CMD_WRITE_POLICY_SETTINGS = 0x080D;
+    CMD_READ_DEF_POLICY_SETTINGS = 0x080E;
+    CMD_WRITE_DEF_POLICY_SETTINGS = 0x080F;
+    CMD_FLOW_SPECIFICATION = 0x0810;
+    CMD_SNIFF_SUB_RATE = 0x0811;
+    // Host controller baseband commands 0x0C00
+    CMD_SET_EVENT_MASK = 0x0C01;
+    CMD_RESET = 0x0C03;
+    CMD_SET_EVENT_FILTER = 0x0C05;
+    CMD_FLUSH = 0x0C08;
+    CMD_READ_PIN_TYPE = 0x0C09;
+    CMD_WRITE_PIN_TYPE = 0x0C0A;
+    CMD_CREATE_NEW_UNIT_KEY = 0x0C0B;
+    CMD_GET_MWS_TRANS_LAYER_CFG = 0x0C0C; // Deprecated (not used in spec)
+    CMD_READ_STORED_LINK_KEY = 0x0C0D;
+    CMD_WRITE_STORED_LINK_KEY = 0x0C11;
+    CMD_DELETE_STORED_LINK_KEY = 0x0C12;
+    CMD_CHANGE_LOCAL_NAME = 0x0C13;
+    CMD_READ_LOCAL_NAME = 0x0C14;
+    CMD_READ_CONN_ACCEPT_TOUT = 0x0C15;
+    CMD_WRITE_CONN_ACCEPT_TOUT = 0x0C16;
+    CMD_READ_PAGE_TOUT = 0x0C17;
+    CMD_WRITE_PAGE_TOUT = 0x0C18;
+    CMD_READ_SCAN_ENABLE = 0x0C19;
+    CMD_WRITE_SCAN_ENABLE = 0x0C1A;
+    CMD_READ_PAGESCAN_CFG = 0x0C1B;
+    CMD_WRITE_PAGESCAN_CFG = 0x0C1C;
+    CMD_READ_INQUIRYSCAN_CFG = 0x0C1D;
+    CMD_WRITE_INQUIRYSCAN_CFG = 0x0C1E;
+    CMD_READ_AUTHENTICATION_ENABLE = 0x0C1F;
+    CMD_WRITE_AUTHENTICATION_ENABLE = 0x0C20;
+    CMD_READ_ENCRYPTION_MODE = 0x0C21; // Deprecated
+    CMD_WRITE_ENCRYPTION_MODE = 0x0C22; // Deprecated
+    CMD_READ_CLASS_OF_DEVICE = 0x0C23;
+    CMD_WRITE_CLASS_OF_DEVICE = 0x0C24;
+    CMD_READ_VOICE_SETTINGS = 0x0C25;
+    CMD_WRITE_VOICE_SETTINGS = 0x0C26;
+    CMD_READ_AUTOMATIC_FLUSH_TIMEOUT = 0x0C27;
+    CMD_WRITE_AUTOMATIC_FLUSH_TIMEOUT = 0x0C28;
+    CMD_READ_NUM_BCAST_REXMITS = 0x0C29;
+    CMD_WRITE_NUM_BCAST_REXMITS = 0x0C2A;
+    CMD_READ_HOLD_MODE_ACTIVITY = 0x0C2B;
+    CMD_WRITE_HOLD_MODE_ACTIVITY = 0x0C2C;
+    CMD_READ_TRANSMIT_POWER_LEVEL = 0x0C2D;
+    CMD_READ_SCO_FLOW_CTRL_ENABLE = 0x0C2E;
+    CMD_WRITE_SCO_FLOW_CTRL_ENABLE = 0x0C2F;
+    CMD_SET_HC_TO_HOST_FLOW_CTRL = 0x0C31;
+    CMD_HOST_BUFFER_SIZE = 0x0C33;
+    CMD_HOST_NUM_PACKETS_DONE = 0x0C35;
+    CMD_READ_LINK_SUPER_TOUT = 0x0C36;
+    CMD_WRITE_LINK_SUPER_TOUT = 0x0C37;
+    CMD_READ_NUM_SUPPORTED_IAC = 0x0C38;
+    CMD_READ_CURRENT_IAC_LAP = 0x0C39;
+    CMD_WRITE_CURRENT_IAC_LAP = 0x0C3A;
+    CMD_READ_PAGESCAN_PERIOD_MODE = 0x0C3B; // Deprecated
+    CMD_WRITE_PAGESCAN_PERIOD_MODE = 0x0C3C; // Deprecated
+    CMD_READ_PAGESCAN_MODE = 0x0C3D; // Deprecated
+    CMD_WRITE_PAGESCAN_MODE = 0x0C3E; // Deprecated
+    CMD_SET_AFH_CHANNELS = 0x0C3F;
+    CMD_READ_INQSCAN_TYPE = 0x0C42;
+    CMD_WRITE_INQSCAN_TYPE = 0x0C43;
+    CMD_READ_INQUIRY_MODE = 0x0C44;
+    CMD_WRITE_INQUIRY_MODE = 0x0C45;
+    CMD_READ_PAGESCAN_TYPE = 0x0C46;
+    CMD_WRITE_PAGESCAN_TYPE = 0x0C47;
+    CMD_READ_AFH_ASSESSMENT_MODE = 0x0C48;
+    CMD_WRITE_AFH_ASSESSMENT_MODE = 0x0C49;
+    CMD_READ_EXT_INQ_RESPONSE = 0x0C51;
+    CMD_WRITE_EXT_INQ_RESPONSE = 0x0C52;
+    CMD_REFRESH_ENCRYPTION_KEY = 0x0C53;
+    CMD_READ_SIMPLE_PAIRING_MODE = 0x0C55;
+    CMD_WRITE_SIMPLE_PAIRING_MODE = 0x0C56;
+    CMD_READ_LOCAL_OOB_DATA = 0x0C57;
+    CMD_READ_INQ_TX_POWER_LEVEL = 0x0C58;
+    CMD_WRITE_INQ_TX_POWER_LEVEL = 0x0C59;
+    CMD_READ_ERRONEOUS_DATA_RPT = 0x0C5A;
+    CMD_WRITE_ERRONEOUS_DATA_RPT = 0x0C5B;
+    CMD_ENHANCED_FLUSH = 0x0C5F;
+    CMD_SEND_KEYPRESS_NOTIF = 0x0C60;
+    CMD_READ_LOGICAL_LINK_ACCEPT_TIMEOUT = 0x0C61;
+    CMD_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT = 0x0C62;
+    CMD_SET_EVENT_MASK_PAGE_2 = 0x0C63;
+    CMD_READ_LOCATION_DATA = 0x0C64;
+    CMD_WRITE_LOCATION_DATA = 0x0C65;
+    CMD_READ_FLOW_CONTROL_MODE = 0x0C66;
+    CMD_WRITE_FLOW_CONTROL_MODE = 0x0C67;
+    CMD_READ_ENHANCED_TX_PWR_LEVEL = 0x0C68; // Not currently used in system/bt
+    CMD_READ_BE_FLUSH_TOUT = 0x0C69;
+    CMD_WRITE_BE_FLUSH_TOUT = 0x0C6A;
+    CMD_SHORT_RANGE_MODE = 0x0C6B;
+    CMD_READ_BLE_HOST_SUPPORT = 0x0C6C;
+    CMD_WRITE_BLE_HOST_SUPPORT = 0x0C6D;
+    CMD_SET_MWS_CHANNEL_PARAMETERS = 0x0C6E;
+    CMD_SET_EXTERNAL_FRAME_CONFIGURATION = 0x0C6F;
+    CMD_SET_MWS_SIGNALING = 0x0C70;
+    CMD_SET_MWS_TRANSPORT_LAYER = 0x0C71;
+    CMD_SET_MWS_SCAN_FREQUENCY_TABLE = 0x0C72;
+    CMD_SET_MWS_PATTERN_CONFIGURATION = 0x0C73;
+    CMD_SET_RESERVED_LT_ADDR = 0x0C74;
+    CMD_DELETE_RESERVED_LT_ADDR = 0x0C75;
+    CMD_WRITE_CLB_DATA = 0x0C76;
+    CMD_READ_SYNC_TRAIN_PARAM = 0x0C77;
+    CMD_WRITE_SYNC_TRAIN_PARAM = 0x0C78;
+    CMD_READ_SECURE_CONNS_SUPPORT = 0x0C79;
+    CMD_WRITE_SECURE_CONNS_SUPPORT = 0x0C7A;
+    CMD_READ_AUTHED_PAYLOAD_TIMEOUT = 0x0C7B; // Not currently used in system/bt
+    CMD_WRITE_AUTHED_PAYLOAD_TIMEOUT = 0x0C7C; // Not currently used in system/bt
+    CMD_READ_LOCAL_OOB_EXTENDED_DATA = 0x0C7D; // Not currently used in system/bt
+    CMD_READ_EXTENDED_PAGE_TIMEOUT = 0x0C7E; // Not currently used in system/bt
+    CMD_WRITE_EXTENDED_PAGE_TIMEOUT = 0x0C7F; // Not currently used in system/bt
+    CMD_READ_EXTENDED_INQUIRY_LENGTH = 0x0C80; // Not currently used in system/bt
+    CMD_WRITE_EXTENDED_INQUIRY_LENGTH = 0x0C81; // Not currently used in system/bt
+    // Informational parameter commands 0x1000
+    CMD_READ_LOCAL_VERSION_INFO = 0x1001;
+    CMD_READ_LOCAL_SUPPORTED_CMDS = 0x1002;
+    CMD_READ_LOCAL_FEATURES = 0x1003;
+    CMD_READ_LOCAL_EXT_FEATURES = 0x1004;
+    CMD_READ_BUFFER_SIZE = 0x1005;
+    CMD_READ_COUNTRY_CODE = 0x1007; // Deprecated
+    CMD_READ_BD_ADDR = 0x1009;
+    CMD_READ_DATA_BLOCK_SIZE = 0x100A;
+    CMD_READ_LOCAL_SUPPORTED_CODECS = 0x100B;
+    // Status parameter commands 0x1400
+    CMD_READ_FAILED_CONTACT_COUNTER = 0x1401;
+    CMD_RESET_FAILED_CONTACT_COUNTER = 0x1402;
+    CMD_GET_LINK_QUALITY = 0x1403;
+    CMD_READ_RSSI = 0x1405;
+    CMD_READ_AFH_CH_MAP = 0x1406;
+    CMD_READ_CLOCK = 0x1407;
+    CMD_READ_ENCR_KEY_SIZE = 0x1408;
+    CMD_READ_LOCAL_AMP_INFO = 0x1409;
+    CMD_READ_LOCAL_AMP_ASSOC = 0x140A;
+    CMD_WRITE_REMOTE_AMP_ASSOC = 0x140B;
+    CMD_GET_MWS_TRANSPORT_CFG = 0x140C; // Not currently used in system/bt
+    CMD_SET_TRIGGERED_CLK_CAPTURE = 0x140D; // Not currently used in system/bt
+    // Testing commands 0x1800
+    CMD_READ_LOOPBACK_MODE = 0x1801;
+    CMD_WRITE_LOOPBACK_MODE = 0x1802;
+    CMD_ENABLE_DEV_UNDER_TEST_MODE = 0x1803;
+    CMD_WRITE_SIMP_PAIR_DEBUG_MODE = 0x1804;
+    CMD_ENABLE_AMP_RCVR_REPORTS = 0x1807;
+    CMD_AMP_TEST_END = 0x1808;
+    CMD_AMP_TEST = 0x1809;
+    CMD_WRITE_SECURE_CONN_TEST_MODE = 0x180A; // Not currently used in system/bt
+    // BLE commands 0x2000
+    CMD_BLE_SET_EVENT_MASK = 0x2001;
+    CMD_BLE_READ_BUFFER_SIZE = 0x2002;
+    CMD_BLE_READ_LOCAL_SPT_FEAT = 0x2003;
+    CMD_BLE_WRITE_LOCAL_SPT_FEAT = 0x2004;
+    CMD_BLE_WRITE_RANDOM_ADDR = 0x2005;
+    CMD_BLE_WRITE_ADV_PARAMS = 0x2006;
+    CMD_BLE_READ_ADV_CHNL_TX_POWER = 0x2007;
+    CMD_BLE_WRITE_ADV_DATA = 0x2008;
+    CMD_BLE_WRITE_SCAN_RSP_DATA = 0x2009;
+    CMD_BLE_WRITE_ADV_ENABLE = 0x200A;
+    CMD_BLE_WRITE_SCAN_PARAMS = 0x200B;
+    CMD_BLE_WRITE_SCAN_ENABLE = 0x200C;
+    CMD_BLE_CREATE_LL_CONN = 0x200D;
+    CMD_BLE_CREATE_CONN_CANCEL = 0x200E;
+    CMD_BLE_READ_WHITE_LIST_SIZE = 0x200F;
+    CMD_BLE_CLEAR_WHITE_LIST = 0x2010;
+    CMD_BLE_ADD_WHITE_LIST = 0x2011;
+    CMD_BLE_REMOVE_WHITE_LIST = 0x2012;
+    CMD_BLE_UPD_LL_CONN_PARAMS = 0x2013;
+    CMD_BLE_SET_HOST_CHNL_CLASS = 0x2014;
+    CMD_BLE_READ_CHNL_MAP = 0x2015;
+    CMD_BLE_READ_REMOTE_FEAT = 0x2016;
+    CMD_BLE_ENCRYPT = 0x2017;
+    CMD_BLE_RAND = 0x2018;
+    CMD_BLE_START_ENC = 0x2019;
+    CMD_BLE_LTK_REQ_REPLY = 0x201A;
+    CMD_BLE_LTK_REQ_NEG_REPLY = 0x201B;
+    CMD_BLE_READ_SUPPORTED_STATES = 0x201C;
+    CMD_BLE_RECEIVER_TEST = 0x201D;
+    CMD_BLE_TRANSMITTER_TEST = 0x201E;
+    CMD_BLE_TEST_END = 0x201F;
+    CMD_BLE_RC_PARAM_REQ_REPLY = 0x2020;
+    CMD_BLE_RC_PARAM_REQ_NEG_REPLY = 0x2021;
+    CMD_BLE_SET_DATA_LENGTH = 0x2022;
+    CMD_BLE_READ_DEFAULT_DATA_LENGTH = 0x2023;
+    CMD_BLE_WRITE_DEFAULT_DATA_LENGTH = 0x2024;
+    CMD_BLE_GENERATE_DHKEY = 0x2026; // Not currently used in system/bt
+    CMD_BLE_ADD_DEV_RESOLVING_LIST = 0x2027;
+    CMD_BLE_RM_DEV_RESOLVING_LIST = 0x2028;
+    CMD_BLE_CLEAR_RESOLVING_LIST = 0x2029;
+    CMD_BLE_READ_RESOLVING_LIST_SIZE = 0x202A;
+    CMD_BLE_READ_RESOLVABLE_ADDR_PEER = 0x202B;
+    CMD_BLE_READ_RESOLVABLE_ADDR_LOCAL = 0x202C;
+    CMD_BLE_SET_ADDR_RESOLUTION_ENABLE = 0x202D;
+    CMD_BLE_SET_RAND_PRIV_ADDR_TIMOUT = 0x202E;
+    CMD_BLE_READ_MAXIMUM_DATA_LENGTH = 0x202F;
+    CMD_BLE_READ_PHY = 0x2030;
+    CMD_BLE_SET_DEFAULT_PHY = 0x2031;
+    CMD_BLE_SET_PHY = 0x2032;
+    CMD_BLE_ENH_RECEIVER_TEST = 0x2033;
+    CMD_BLE_ENH_TRANSMITTER_TEST = 0x2034;
+    CMD_BLE_SET_EXT_ADVERTISING_RANDOM_ADDRESS = 0x2035;
+    CMD_BLE_SET_EXT_ADVERTISING_PARAM = 0x2036;
+    CMD_BLE_SET_EXT_ADVERTISING_DATA = 0x2037;
+    CMD_BLE_SET_EXT_ADVERTISING_SCAN_RESP = 0x2038;
+    CMD_BLE_SET_EXT_ADVERTISING_ENABLE = 0x2039;
+    CMD_BLE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH = 0x203A;
+    CMD_BLE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS = 0x203B;
+    CMD_BLE_REMOVE_ADVERTISING_SET = 0x203C;
+    CMD_BLE_CLEAR_ADVERTISING_SETS = 0x203D;
+    CMD_BLE_SET_PERIODIC_ADVERTISING_PARAM = 0x203E;
+    CMD_BLE_SET_PERIODIC_ADVERTISING_DATA = 0x203F;
+    CMD_BLE_SET_PERIODIC_ADVERTISING_ENABLE = 0x2040;
+    CMD_BLE_SET_EXTENDED_SCAN_PARAMETERS = 0x2041;
+    CMD_BLE_SET_EXTENDED_SCAN_ENABLE = 0x2042;
+    CMD_BLE_EXTENDED_CREATE_CONNECTION = 0x2043;
+    CMD_BLE_PERIODIC_ADVERTISING_CREATE_SYNC = 0x2044;
+    CMD_BLE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL = 0x2045;
+    CMD_BLE_PERIODIC_ADVERTISING_TERMINATE_SYNC = 0x2046;
+    CMD_BLE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST = 0x2047;
+    CMD_BLE_RM_DEVICE_FROM_PERIODIC_ADVERTISING_LIST = 0x2048;
+    CMD_BLE_CLEAR_PERIODIC_ADVERTISING_LIST = 0x2049;
+    CMD_BLE_READ_PERIODIC_ADVERTISING_LIST_SIZE = 0x204A;
+    CMD_BLE_READ_TRANSMIT_POWER = 0x204B;
+    CMD_BLE_READ_RF_COMPENS_POWER = 0x204C;
+    CMD_BLE_WRITE_RF_COMPENS_POWER = 0x204D;
+    CMD_BLE_SET_PRIVACY_MODE = 0x204E;
+    // Vendor specific commands 0xFC00 and above
+    // Android vendor specific commands defined in
+    // https://source.android.com/devices/bluetooth/hci_requirements#vendor-specific-capabilities
+    CMD_BLE_VENDOR_CAP = 0xFD53;
+    CMD_BLE_MULTI_ADV = 0xFD54;
+    CMD_BLE_BATCH_SCAN = 0xFD56;
+    CMD_BLE_ADV_FILTER = 0xFD57;
+    CMD_BLE_TRACK_ADV = 0xFD58;
+    CMD_BLE_ENERGY_INFO = 0xFD59;
+    CMD_BLE_EXTENDED_SCAN_PARAMS = 0xFD5A;
+    CMD_CONTROLLER_DEBUG_INFO = 0xFD5B;
+    CMD_CONTROLLER_A2DP_OPCODE = 0xFD5D;
+    CMD_BRCM_SET_ACL_PRIORITY = 0xFC57;
+    // Other vendor specific commands below here
+}
+
+// HCI event codes from the Bluetooth 5.0 specification Vol 2, Part 7, Section 7
+// Original definition: system/bt/stack/include/hcidefs.h
+enum EventEnum {
+    // Event is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
+    EVT_UNKNOWN = 0xFFF;
+    EVT_INQUIRY_COMP = 0x01;
+    EVT_INQUIRY_RESULT = 0x02;
+    EVT_CONNECTION_COMP = 0x03;
+    EVT_CONNECTION_REQUEST = 0x04;
+    EVT_DISCONNECTION_COMP = 0x05;
+    EVT_AUTHENTICATION_COMP = 0x06;
+    EVT_RMT_NAME_REQUEST_COMP = 0x07;
+    EVT_ENCRYPTION_CHANGE = 0x08;
+    EVT_CHANGE_CONN_LINK_KEY = 0x09;
+    EVT_MASTER_LINK_KEY_COMP = 0x0A;
+    EVT_READ_RMT_FEATURES_COMP = 0x0B;
+    EVT_READ_RMT_VERSION_COMP = 0x0C;
+    EVT_QOS_SETUP_COMP = 0x0D;
+    EVT_COMMAND_COMPLETE = 0x0E;
+    EVT_COMMAND_STATUS = 0x0F;
+    EVT_HARDWARE_ERROR = 0x10;
+    EVT_FLUSH_OCCURED = 0x11;
+    EVT_ROLE_CHANGE = 0x12;
+    EVT_NUM_COMPL_DATA_PKTS = 0x13;
+    EVT_MODE_CHANGE = 0x14;
+    EVT_RETURN_LINK_KEYS = 0x15;
+    EVT_PIN_CODE_REQUEST = 0x16;
+    EVT_LINK_KEY_REQUEST = 0x17;
+    EVT_LINK_KEY_NOTIFICATION = 0x18;
+    EVT_LOOPBACK_COMMAND = 0x19;
+    EVT_DATA_BUF_OVERFLOW = 0x1A;
+    EVT_MAX_SLOTS_CHANGED = 0x1B;
+    EVT_READ_CLOCK_OFF_COMP = 0x1C;
+    EVT_CONN_PKT_TYPE_CHANGE = 0x1D;
+    EVT_QOS_VIOLATION = 0x1E;
+    EVT_PAGE_SCAN_MODE_CHANGE = 0x1F; // Deprecated
+    EVT_PAGE_SCAN_REP_MODE_CHNG = 0x20;
+    EVT_FLOW_SPECIFICATION_COMP = 0x21;
+    EVT_INQUIRY_RSSI_RESULT = 0x22;
+    EVT_READ_RMT_EXT_FEATURES_COMP = 0x23;
+    EVT_ESCO_CONNECTION_COMP = 0x2C;
+    EVT_ESCO_CONNECTION_CHANGED = 0x2D;
+    EVT_SNIFF_SUB_RATE = 0x2E;
+    EVT_EXTENDED_INQUIRY_RESULT = 0x2F;
+    EVT_ENCRYPTION_KEY_REFRESH_COMP = 0x30;
+    EVT_IO_CAPABILITY_REQUEST = 0x31;
+    EVT_IO_CAPABILITY_RESPONSE = 0x32;
+    EVT_USER_CONFIRMATION_REQUEST = 0x33;
+    EVT_USER_PASSKEY_REQUEST = 0x34;
+    EVT_REMOTE_OOB_DATA_REQUEST = 0x35;
+    EVT_SIMPLE_PAIRING_COMPLETE = 0x36;
+    EVT_LINK_SUPER_TOUT_CHANGED = 0x38;
+    EVT_ENHANCED_FLUSH_COMPLETE = 0x39;
+    EVT_USER_PASSKEY_NOTIFY = 0x3B;
+    EVT_KEYPRESS_NOTIFY = 0x3C;
+    EVT_RMT_HOST_SUP_FEAT_NOTIFY = 0x3D;
+    EVT_BLE_META = 0x3E;
+    EVT_PHYSICAL_LINK_COMP = 0x40;
+    EVT_CHANNEL_SELECTED = 0x41;
+    EVT_DISC_PHYSICAL_LINK_COMP = 0x42;
+    EVT_PHY_LINK_LOSS_EARLY_WARNING = 0x43;
+    EVT_PHY_LINK_RECOVERY = 0x44;
+    EVT_LOGICAL_LINK_COMP = 0x45;
+    EVT_DISC_LOGICAL_LINK_COMP = 0x46;
+    EVT_FLOW_SPEC_MODIFY_COMP = 0x47;
+    EVT_NUM_COMPL_DATA_BLOCKS = 0x48;
+    EVT_AMP_TEST_START = 0x49; // Not currently used in system/bt
+    EVT_AMP_TEST_END = 0x4A; // Not currently used in system/bt
+    EVT_AMP_RECEIVER_RPT = 0x4B; // Not currently used in system/bt
+    EVT_SHORT_RANGE_MODE_COMPLETE = 0x4C;
+    EVT_AMP_STATUS_CHANGE = 0x4D;
+    EVT_SET_TRIGGERED_CLOCK_CAPTURE = 0x4E;
+    EVT_SYNC_TRAIN_CMPL = 0x4F; // Not currently used in system/bt
+    EVT_SYNC_TRAIN_RCVD = 0x50; // Not currently used in system/bt
+    EVT_CONNLESS_SLAVE_BROADCAST_RCVD = 0x51; // Not currently used in system/bt
+    EVT_CONNLESS_SLAVE_BROADCAST_TIMEOUT = 0x52; // Not currently used in system/bt
+    EVT_TRUNCATED_PAGE_CMPL = 0x53; // Not currently used in system/bt
+    EVT_SLAVE_PAGE_RES_TIMEOUT = 0x54; // Not currently used in system/bt
+    EVT_CONNLESS_SLAVE_BROADCAST_CHNL_MAP_CHANGE = 0x55; // Not currently used in system/bt
+    EVT_INQUIRY_RES_NOTIFICATION = 0x56; // Not currently used in system/bt
+    EVT_AUTHED_PAYLOAD_TIMEOUT = 0x57; // Not currently used in system/bt
+    EVT_SAM_STATUS_CHANGE = 0x58; // Not currently used in system/bt
+}
+
+// Bluetooth low energy related meta event codes
+// from the Bluetooth 5.0 specification Vol 2, Part E, Section 7.7.65
+// Original definition: system/bt/stack/include/hcidefs.h
+enum BleMetaEventEnum {
+    // BLE meta event code is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
+    BLE_EVT_UNKNOWN = 0xFFF;
+    BLE_EVT_CONN_COMPLETE_EVT = 0x01;
+    BLE_EVT_ADV_PKT_RPT_EVT = 0x02;
+    BLE_EVT_LL_CONN_PARAM_UPD_EVT = 0x03;
+    BLE_EVT_READ_REMOTE_FEAT_CMPL_EVT = 0x04;
+    BLE_EVT_LTK_REQ_EVT = 0x05;
+    BLE_EVT_RC_PARAM_REQ_EVT = 0x06;
+    BLE_EVT_DATA_LENGTH_CHANGE_EVT = 0x07;
+    BLE_EVT_READ_LOCAL_P256_PUB_KEY = 0x08; // Not currently used in system/bt
+    BLE_EVT_GEN_DHKEY_CMPL = 0x09; // Not currently used in system/bt
+    BLE_EVT_ENHANCED_CONN_COMPLETE_EVT = 0x0a;
+    BLE_EVT_DIRECT_ADV_EVT = 0x0b;
+    BLE_EVT_PHY_UPDATE_COMPLETE_EVT = 0x0c;
+    BLE_EVT_EXTENDED_ADVERTISING_REPORT_EVT = 0x0D;
+    BLE_EVT_PERIODIC_ADV_SYNC_EST_EVT = 0x0E;
+    BLE_EVT_PERIODIC_ADV_REPORT_EVT = 0x0F;
+    BLE_EVT_PERIODIC_ADV_SYNC_LOST_EVT = 0x10;
+    BLE_EVT_SCAN_TIMEOUT_EVT = 0x11;
+    BLE_EVT_ADVERTISING_SET_TERMINATED_EVT = 0x12;
+    BLE_EVT_SCAN_REQ_RX_EVT = 0x13;
+    BLE_EVT_CHNL_SELECTION_ALGORITHM = 0x14; // Not currently used in system/bt
+}
+
+// HCI status code from the Bluetooth 5.0 specification Vol 2, Part D.
+// Original definition: system/bt/stack/include/hcidefs.h
+enum StatusEnum {
+    // Status is at most 1 byte (0xFF), thus 0xFFF must not be a valid value
+    STATUS_UNKNOWN = 0xFFF;
+    STATUS_SUCCESS = 0x00;
+    STATUS_ILLEGAL_COMMAND = 0x01;
+    STATUS_NO_CONNECTION = 0x02;
+    STATUS_HW_FAILURE = 0x03;
+    STATUS_PAGE_TIMEOUT = 0x04;
+    STATUS_AUTH_FAILURE = 0x05;
+    STATUS_KEY_MISSING = 0x06;
+    STATUS_MEMORY_FULL = 0x07;
+    STATUS_CONNECTION_TOUT = 0x08;
+    STATUS_MAX_NUM_OF_CONNECTIONS = 0x09;
+    STATUS_MAX_NUM_OF_SCOS = 0x0A;
+    STATUS_CONNECTION_EXISTS = 0x0B;
+    STATUS_COMMAND_DISALLOWED = 0x0C;
+    STATUS_HOST_REJECT_RESOURCES = 0x0D;
+    STATUS_HOST_REJECT_SECURITY = 0x0E;
+    STATUS_HOST_REJECT_DEVICE = 0x0F;
+    STATUS_HOST_TIMEOUT = 0x10;
+    STATUS_UNSUPPORTED_VALUE = 0x11;
+    STATUS_ILLEGAL_PARAMETER_FMT = 0x12;
+    STATUS_PEER_USER = 0x13;
+    STATUS_PEER_LOW_RESOURCES = 0x14;
+    STATUS_PEER_POWER_OFF = 0x15;
+    STATUS_CONN_CAUSE_LOCAL_HOST = 0x16;
+    STATUS_REPEATED_ATTEMPTS = 0x17;
+    STATUS_PAIRING_NOT_ALLOWED = 0x18;
+    STATUS_UNKNOWN_LMP_PDU = 0x19;
+    STATUS_UNSUPPORTED_REM_FEATURE = 0x1A;
+    STATUS_SCO_OFFSET_REJECTED = 0x1B;
+    STATUS_SCO_INTERVAL_REJECTED = 0x1C;
+    STATUS_SCO_AIR_MODE = 0x1D;
+    STATUS_INVALID_LMP_PARAM = 0x1E;
+    STATUS_UNSPECIFIED = 0x1F;
+    STATUS_UNSUPPORTED_LMP_FEATURE = 0x20;
+    STATUS_ROLE_CHANGE_NOT_ALLOWED = 0x21;
+    STATUS_LMP_RESPONSE_TIMEOUT = 0x22;
+    STATUS_LMP_STATUS_TRANS_COLLISION = 0x23;
+    STATUS_LMP_PDU_NOT_ALLOWED = 0x24;
+    STATUS_ENCRY_MODE_NOT_ACCEPTABLE = 0x25;
+    STATUS_UNIT_KEY_USED = 0x26;
+    STATUS_QOS_NOT_SUPPORTED = 0x27;
+    STATUS_INSTANT_PASSED = 0x28;
+    STATUS_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED = 0x29;
+    STATUS_DIFF_TRANSACTION_COLLISION = 0x2A;
+    STATUS_UNDEFINED_0x2B = 0x2B; // Not used
+    STATUS_QOS_UNACCEPTABLE_PARAM = 0x2C;
+    STATUS_QOS_REJECTED = 0x2D;
+    STATUS_CHAN_CLASSIF_NOT_SUPPORTED = 0x2E;
+    STATUS_INSUFFCIENT_SECURITY = 0x2F;
+    STATUS_PARAM_OUT_OF_RANGE = 0x30;
+    STATUS_UNDEFINED_0x31 = 0x31; // Not used
+    STATUS_ROLE_SWITCH_PENDING = 0x32;
+    STATUS_UNDEFINED_0x33 = 0x33;
+    STATUS_RESERVED_SLOT_VIOLATION = 0x34;
+    STATUS_ROLE_SWITCH_FAILED = 0x35;
+    STATUS_INQ_RSP_DATA_TOO_LARGE = 0x36;
+    STATUS_SIMPLE_PAIRING_NOT_SUPPORTED = 0x37;
+    STATUS_HOST_BUSY_PAIRING = 0x38;
+    STATUS_REJ_NO_SUITABLE_CHANNEL = 0x39;
+    STATUS_CONTROLLER_BUSY = 0x3A;
+    STATUS_UNACCEPT_CONN_INTERVAL = 0x3B;
+    STATUS_ADVERTISING_TIMEOUT = 0x3C;
+    STATUS_CONN_TOUT_DUE_TO_MIC_FAILURE = 0x3D;
+    STATUS_CONN_FAILED_ESTABLISHMENT = 0x3E;
+    STATUS_MAC_CONNECTION_FAILED = 0x3F;
+    STATUS_LT_ADDR_ALREADY_IN_USE = 0x40;
+    STATUS_LT_ADDR_NOT_ALLOCATED = 0x41;
+    STATUS_CLB_NOT_ENABLED = 0x42;
+    STATUS_CLB_DATA_TOO_BIG = 0x43;
+    STATUS_OPERATION_CANCELED_BY_HOST = 0x44; // Not currently used in system/bt
+}
diff --git a/core/proto/android/bluetooth/hfp/enums.proto b/core/proto/android/bluetooth/hfp/enums.proto
new file mode 100644
index 0000000..d286e4b
--- /dev/null
+++ b/core/proto/android/bluetooth/hfp/enums.proto
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.bluetooth.hfp;
+
+option java_outer_classname = "BluetoothHfpProtoEnums";
+option java_multiple_files = true;
+
+enum ScoCodec {
+    SCO_CODEC_UNKNOWN = 0;
+    SCO_CODEC_CVSD = 1;
+    // Default codec behind Wide Band Speech
+    SCO_CODEC_MSBC = 2;
+}
\ No newline at end of file
diff --git a/core/proto/android/debug/enums.proto b/core/proto/android/debug/enums.proto
new file mode 100644
index 0000000..6747bb7
--- /dev/null
+++ b/core/proto/android/debug/enums.proto
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package android.debug;
+
+option java_outer_classname = "AdbProtoEnums";
+option java_multiple_files = true;
+
+/**
+ * adb connection state used to track adb connection changes in AdbDebuggingManager.java.
+ */
+enum AdbConnectionStateEnum {
+    UNKNOWN = 0;
+
+    /**
+     * The adb connection is waiting for approval from the user.
+     */
+    AWAITING_USER_APPROVAL = 1;
+
+    /**
+     * The user allowed the adb connection from the system.
+     */
+    USER_ALLOWED = 2;
+
+    /**
+     * The user denied the adb connection from the system.
+     */
+    USER_DENIED = 3;
+
+    /**
+     * The adb connection was automatically allowed without user interaction due to the system
+     * being previously allowed by the user with the 'always allow' option selected, and the adb
+     * grant has not yet expired.
+     */
+    AUTOMATICALLY_ALLOWED = 4;
+
+    /**
+     * An empty or invalid base64 encoded key was provided to the framework; the connection was
+     * automatically denied.
+     */
+    DENIED_INVALID_KEY = 5;
+
+    /**
+     * vold decrypt has not yet occurred; the connection was automatically denied.
+     */
+    DENIED_VOLD_DECRYPT = 6;
+
+    /**
+     * The adb session has been disconnected.
+     */
+    DISCONNECTED = 7;
+}
+
diff --git a/core/proto/android/os/enums.proto b/core/proto/android/os/enums.proto
index db4a4c4..c357065 100644
--- a/core/proto/android/os/enums.proto
+++ b/core/proto/android/os/enums.proto
@@ -57,6 +57,7 @@
 }
 
 // These constants are defined in hardware/interfaces/thermal/1.0/types.hal
+// and in hardware/interfaces/thermal/2.0/types.hal
 // They are primarily used by android/os/HardwarePropertiesManager.java.
 // Any change to the types in the thermal hal should be made here as well.
 enum TemperatureTypeEnum {
@@ -65,6 +66,16 @@
     TEMPERATURE_TYPE_GPU = 1;
     TEMPERATURE_TYPE_BATTERY = 2;
     TEMPERATURE_TYPE_SKIN = 3;
+    TEMPERATURE_TYPE_USB_PORT = 4;
+    TEMPERATURE_TYPE_POWER_AMPLIFIER = 5;
+
+    // Battery Charge Limit - virtual thermal sensors.
+    TEMPERATURE_TYPE_BCL_VOLTAGE = 6;
+    TEMPERATURE_TYPE_BCL_CURRENT = 7;
+    TEMPERATURE_TYPE_BCL_PERCENTAGE = 8;
+
+    // Neural Processing Unit.
+    TEMPERATURE_TYPE_NPU = 9;
 }
 
 // Wakelock types, primarily used by android/os/PowerManager.java.
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 11bd43b..d79eb94 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -436,9 +436,21 @@
         // Ordered GPU debug layer list for GLES
         // i.e. <layer1>:<layer2>:...:<layerN>
         optional SettingProto debug_layers_gles = 7;
-        // App opt in to load updated graphics driver instead of
-        // native graphcis driver through developer options.
-        optional SettingProto updated_gfx_driver_dev_opt_in_app = 8;
+        // GUP - Game Update Package global preference for all Apps
+        // 0 = Default
+        // 1 = All Apps use Game Update Package
+        // 2 = All Apps use system graphics driver
+        optional SettingProto gup_dev_all_apps = 8;
+        // GUP - List of Apps selected to use Game Update Package
+        // i.e. <pkg1>,<pkg2>,...,<pkgN>
+        optional SettingProto gup_dev_opt_in_apps = 9;
+        // GUP - List of Apps selected not to use Game Update Package
+        // i.e. <pkg1>,<pkg2>,...,<pkgN>
+        optional SettingProto gup_dev_opt_out_apps = 10;
+        // GUP - List of Apps that are forbidden to use Game Update Package
+        optional SettingProto gup_blacklist = 11;
+        // List of Apps that are allowed to use Game Driver package.
+        optional SettingProto game_driver_whitelist = 12;
     }
     optional Gpu gpu = 59;
 
@@ -525,6 +537,16 @@
         // Whether automatic battery saver mode is controlled via percentage,
         // {@link #DYNAMIC_POWER_SAVINGS_ENABLED} or disabled.
         optional SettingProto automatic_power_saver_mode = 4 [ (android.privacy).dest = DEST_AUTOMATIC];
+        // If 1, battery saver (low_power_mode) will be re-activated after the device is
+        // unplugged from a charger or rebooted.
+        optional SettingProto sticky_enabled = 5;
+        // Whether sticky battery saver should be deactivated once the battery level has reached the
+        // threshold specified by sticky_disable_level.
+        optional SettingProto sticky_auto_disable_enabled = 6;
+        // When a device is unplugged from a changer (or is rebooted), do not re-activate battery
+        // saver even if {@link #LOW_POWER_MODE_STICKY} is 1, if the battery level is equal to or
+        // above this threshold.
+        optional SettingProto sticky_auto_disable_level = 7;
     }
     optional LowPowerMode low_power_mode = 70;
 
@@ -556,6 +578,8 @@
     // ringer mode.
     optional SettingProto mode_ringer = 75 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
+    optional SettingProto apply_ramping_ringer = 147 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
     message MultiSim {
         option (android.msg_privacy).dest = DEST_EXPLICIT;
 
@@ -719,8 +743,7 @@
     // Defines global runtime overrides to window policy.
     optional SettingProto policy_control = 92;
     optional SettingProto power_manager_constants = 93;
-    // If true, out-of-the-box execution for priv apps is enabled.
-    optional SettingProto priv_app_oob_enabled = 94 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    reserved 94; // Used to be priv_app_oob_enabled
 
     message PrepaidSetup {
         option (android.msg_privacy).dest = DEST_EXPLICIT;
@@ -1013,7 +1036,9 @@
 
     optional SettingProto zram_enabled = 139 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
+    optional SettingProto app_ops_constants = 148 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 147;
+    // Next tag = 149;
 }
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 0e052fe..c0d6139 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -182,6 +182,7 @@
         optional SettingProto pulse_on_pick_up = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto pulse_on_long_press = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto pulse_on_double_tap = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto pulse_on_tap = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Doze doze = 21;
 
@@ -525,7 +526,11 @@
     }
     optional Zen zen = 71;
 
+    optional SettingProto skip_gesture_enabled = 74 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto silence_gesture_enabled = 75 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto theme_customization_overlay_packages = 76 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 74;
+    // Next tag = 77;
 }
diff --git a/core/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto
new file mode 100644
index 0000000..21717d8
--- /dev/null
+++ b/core/proto/android/server/connectivity/data_stall_event.proto
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package com.android.server.connectivity;
+option java_multiple_files = true;
+option java_outer_classname = "DataStallEventProto";
+
+enum ProbeResult {
+    UNKNOWN = 0;
+    VALID = 1;
+    INVALID = 2;
+    PORTAL = 3;
+}
+
+enum ApBand {
+    AP_BAND_UNKNOWN = 0;
+    AP_BAND_2GHZ = 1;
+    AP_BAND_5GHZ = 2;
+}
+
+// Refer to definition in ServiceState.java.
+enum RadioTech {
+  RADIO_TECHNOLOGY_UNKNOWN = 0;
+  RADIO_TECHNOLOGY_GPRS = 1;
+  RADIO_TECHNOLOGY_EDGE = 2;
+  RADIO_TECHNOLOGY_UMTS = 3;
+  RADIO_TECHNOLOGY_IS95A = 4;
+  RADIO_TECHNOLOGY_IS95B = 5;
+  RADIO_TECHNOLOGY_1XRTT = 6;
+  RADIO_TECHNOLOGY_EVDO_0 = 7;
+  RADIO_TECHNOLOGY_EVDO_A = 8;
+  RADIO_TECHNOLOGY_HSDPA = 9;
+  RADIO_TECHNOLOGY_HSUPA = 10;
+  RADIO_TECHNOLOGY_HSPA = 11;
+  RADIO_TECHNOLOGY_EVDO_B = 12;
+  RADIO_TECHNOLOGY_EHRPD = 13;
+  RADIO_TECHNOLOGY_LTE = 14;
+  RADIO_TECHNOLOGY_HSPAP = 15;
+  RADIO_TECHNOLOGY_GSM = 16;
+  RADIO_TECHNOLOGY_TD_SCDMA = 17;
+  RADIO_TECHNOLOGY_IWLAN = 18;
+  RADIO_TECHNOLOGY_LTE_CA = 19;
+  RADIO_TECHNOLOGY_NR = 20;
+}
+
+// Cellular specific information.
+message CellularData {
+    // Indicate the radio technology at the time of data stall suspected.
+    optional RadioTech rat_type = 1;
+    // True if device is in roaming network at the time of data stall suspected.
+    optional bool is_roaming = 2;
+    // Registered network MccMnc when data stall happen
+    optional string network_mccmnc = 3;
+    // Indicate the SIM card carrier.
+    optional string sim_mccmnc = 4;
+    // Signal strength level at the time of data stall suspected.
+    optional int32 signal_strength = 5;
+}
+
+// Wifi specific information.
+message WifiData {
+    // Signal strength at the time of data stall suspected.
+    // RSSI range is between -55 to -110.
+    optional int32 signal_strength = 1;
+    // AP band.
+    optional ApBand wifi_band = 2;
+}
+
+message DnsEvent {
+    // The dns return code.
+    repeated int32 dns_return_code = 1;
+    // Indicate the timestamp of the dns event.
+    repeated int64 dns_time = 2;
+}
\ No newline at end of file
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 0ec8c1a..e68f9db 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -221,6 +221,8 @@
     optional bool use_heartbeats = 23;
 
     message TimeController {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         // Whether or not TimeController should skip setting wakeup alarms for jobs that aren't
         // ready now.
         optional bool skip_not_ready_jobs = 1;
@@ -228,6 +230,8 @@
     optional TimeController time_controller = 25;
 
     message QuotaController {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         // How much time each app will have to run jobs within their standby bucket window.
         optional int64 allowed_time_per_period_ms = 1;
         // How much time the package should have before transitioning from out-of-quota to in-quota.
@@ -251,6 +255,21 @@
         optional int64 rare_window_size_ms = 6;
         // The maximum amount of time an app can have its jobs running within a 24 hour window.
         optional int64 max_execution_time_ms = 7;
+        // The maximum number of jobs an app can run within this particular standby bucket's
+        // window size.
+        optional int32 max_job_count_active = 8;
+        // The maximum number of jobs an app can run within this particular standby bucket's
+        // window size.
+        optional int32 max_job_count_working = 9;
+        // The maximum number of jobs an app can run within this particular standby bucket's
+        // window size.
+        optional int32 max_job_count_frequent = 10;
+        // The maximum number of jobs an app can run within this particular standby bucket's
+        // window size.
+        optional int32 max_job_count_rare = 11;
+        // The maximum number of jobs that should be allowed to run in the past
+        // {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS}.
+        optional int32 max_job_count_per_allowed_time = 12;
     }
     optional QuotaController quota_controller = 24;
 
@@ -403,18 +422,23 @@
         optional bool is_charging = 1;
         optional bool is_in_parole = 2;
 
+        // List of UIDs currently in the foreground.
+        repeated int32 foreground_uids = 3;
+
         message TrackedJob {
             option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
             optional JobStatusShortInfoProto info = 1;
             optional int32 source_uid = 2;
             optional JobStatusDumpProto.Bucket effective_standby_bucket = 3;
-            optional bool has_quota = 4;
+            // If the job started while the app was in the TOP state.
+            optional bool is_top_started_job = 4;
+            optional bool has_quota = 5;
             // The amount of time that this job has remaining in its quota. This
             // can be negative if the job is out of quota.
-            optional int64 remaining_quota_ms = 5;
+            optional int64 remaining_quota_ms = 6;
         }
-        repeated TrackedJob tracked_jobs = 3;
+        repeated TrackedJob tracked_jobs = 4;
 
         message Package {
             option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -456,7 +480,7 @@
 
             repeated TimingSession saved_sessions = 3;
         }
-        repeated PackageStats package_stats = 4;
+        repeated PackageStats package_stats = 5;
     }
     message StorageController {
         option (.android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/proto/android/server/location/enums.proto b/core/proto/android/server/location/enums.proto
index b6dc589..943ff18 100644
--- a/core/proto/android/server/location/enums.proto
+++ b/core/proto/android/server/location/enums.proto
@@ -28,3 +28,105 @@
     GPS_SIGNAL_QUALITY_POOR = 0;
     GPS_SIGNAL_QUALITY_GOOD = 1;
 }
+
+// A type which distinguishes different categories of NI request, such as VOICE, UMTS_SUPL etc.
+enum GnssNiType {
+    VOICE = 1;
+    UMTS_SUPL = 2;
+    UMTS_CTRL_PLANE = 3;
+    EMERGENCY_SUPL = 4;
+};
+
+// GNSS NI responses, used to define the response in NI structures.
+enum GnssUserResponseType {
+    RESPONSE_ACCEPT = 1;
+    RESPONSE_DENY = 2;
+    RESPONSE_NORESP = 3;
+};
+
+// GNSS NI data encoding scheme.
+enum GnssNiEncodingType {
+    ENC_NONE = 0;
+    ENC_SUPL_GSM_DEFAULT = 1;
+    ENC_SUPL_UTF8 = 2;
+    ENC_SUPL_UCS2 = 3;
+    ENC_UNKNOWN = -1;
+};
+
+// Protocol stack that initiated the non-framework location request.
+enum NfwProtocolStack {
+    // Cellular control plane requests.
+    CTRL_PLANE = 0;
+    // All types of SUPL requests.
+    SUPL = 1;
+    // All types of requests from IMS.
+    IMS = 10;
+    // All types of requests from SIM.
+    SIM = 11;
+    // Requests from other protocol stacks.
+    OTHER_PROTOCOL_STACK = 100;
+};
+
+// Source initiating/receiving the location information.
+enum NfwRequestor  {
+    // Wireless service provider.
+    CARRIER = 0;
+    // Device manufacturer.
+    OEM = 10;
+    // Modem chipset vendor.
+    MODEM_CHIPSET_VENDOR = 11;
+    // GNSS chipset vendor.
+    GNSS_CHIPSET_VENDOR = 12;
+    // Other chipset vendor.
+    OTHER_CHIPSET_VENDOR = 13;
+    // Automobile client.
+    AUTOMOBILE_CLIENT = 20;
+    // Other sources.
+    OTHER_REQUESTOR = 100;
+};
+
+// Indicates whether location information was provided for this request.
+enum NfwResponseType {
+    // Request rejected because framework has not given permission for this use case.
+    REJECTED = 0;
+    // Request accepted but could not provide location because of a failure.
+    ACCEPTED_NO_LOCATION_PROVIDED = 1;
+    // Request accepted and location provided.
+    ACCEPTED_LOCATION_PROVIDED = 2;
+};
+
+// The SUPL mode.
+enum SuplMode {
+    // Mobile Station Based.
+    MSB = 0x01;
+    // Mobile Station Assisted.
+    MSA = 0x02;
+};
+
+// Enum that hold the bit masks for various LTE Positioning Profile settings (LPP_PROFILE
+// configuration parameter). If none of the bits in the enum are set, the default setting is
+// Radio Resource Location Protocol(RRLP).
+enum LppProfile {
+    // Enable LTE Positioning Protocol user plane.
+    USER_PLANE = 0x01;
+    // Enable LTE Positioning Protocol Control plane.
+    CONTROL_PLANE = 0x02;
+};
+
+// Positioning protocol on A-Glonass system.
+enum GlonassPosProtocol {
+    // Radio Resource Control(RRC) control-plane.
+    RRC_CPLANE = 0x01;
+    // Radio Resource Location user-plane.
+    RRLP_CPLANE = 0x02;
+    // LTE Positioning Protocol User plane.
+    LPP_UPLANE = 0x04;
+};
+
+// Configurations of how GPS functionalities should be locked when user turns off GPS On setting.
+enum GpsLock {
+    // Lock Mobile Originated GPS functionalitues.
+    MO = 0x01;
+    // Lock Network Initiated GPS functionalities.
+    NI = 0x02;
+};
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index cee556a..af0a942 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -350,4 +350,12 @@
     // The value of Global.LOW_POWER_MODE_TRIGGER_LEVEL. This is a cached value, so it could
     // be slightly different from what's in GlobalSettingsProto.LowPowerMode.
     optional int32 setting_battery_saver_trigger_threshold = 11;
+
+    // The value of Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED. This is a cached value, so
+    // it could be slightly different from what's in GlobalSettingsProto.LowPowerMode.
+    optional bool setting_battery_saver_sticky_auto_disable_enabled = 12;
+
+    // The value of Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL. This is a cached value, so it
+    // could be slightly different from what's in GlobalSettingsProto.LowPowerMode.
+    optional int32 setting_battery_saver_sticky_auto_disable_threshold = 13;
 }
diff --git a/core/proto/android/server/usagestatsservice.proto b/core/proto/android/server/usagestatsservice.proto
index 528c1a4..050ec7a 100644
--- a/core/proto/android/server/usagestatsservice.proto
+++ b/core/proto/android/server/usagestatsservice.proto
@@ -88,6 +88,11 @@
     // If class field is an Activity, instance_id is a unique id of the
     // Activity object.
     optional int32 instance_id = 14;
+    // task_root_package_index contains the index + 1 of the task root package name in the string
+    // pool
+    optional int32 task_root_package_index = 15;
+    // task_root_class_index contains the index + 1 of the task root class name in the string pool
+    optional int32 task_root_class_index = 16;
   }
 
   // The following fields contain supplemental data used to build IntervalStats, such as a string
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index 4ecf52c..7f96d70 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -111,6 +111,7 @@
         optional EnabledState enabled_state = 7;
         optional string last_disabled_app_caller = 8;
         optional string suspending_package = 9;
+        optional int32 distraction_flags = 10;
     }
 
     // Name of package. e.g. "com.android.providers.telephony".
diff --git a/core/proto/android/service/procstats.proto b/core/proto/android/service/procstats.proto
index 71ebcc1..da801ff 100644
--- a/core/proto/android/service/procstats.proto
+++ b/core/proto/android/service/procstats.proto
@@ -43,7 +43,7 @@
  * Data model from /frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
  * This proto is defined based on the writeToParcel method.
  *
- * Next Tag: 10
+ * Next Tag: 11
  */
 message ProcessStatsSectionProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -76,6 +76,9 @@
     }
     repeated Status status = 7;
 
+    // Number of pages available of various types and sizes, representation fragmentation.
+    repeated ProcessStatsAvailablePagesProto available_pages = 10;
+
     // Stats for each process.
     repeated ProcessStatsProto process_stats = 8;
 
@@ -83,6 +86,24 @@
     repeated ProcessStatsPackageProto package_stats = 9;
 }
 
+// Next Tag: 5
+message ProcessStatsAvailablePagesProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Node these pages are in (as per /proc/pagetypeinfo)
+    optional int32 node = 1;
+
+    // Zone these pages are in (as per /proc/pagetypeinfo)
+    optional string zone = 2;
+
+    // Label for the type of these pages (as per /proc/pagetypeinfo)
+    optional string label = 3;
+
+    // Distribution of number of pages available by order size.  First entry in array is
+    // order 0, second is order 1, etc.  Each order increase is a doubling of page size.
+    repeated int32 pages_per_order = 4;
+}
+
 // Next Tag: 10
 message ProcessStatsStateProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto
index f7dcee2..00fae3d 100644
--- a/core/proto/android/service/usb.proto
+++ b/core/proto/android/service/usb.proto
@@ -245,11 +245,20 @@
         DATA_ROLE_DEVICE = 2;
     }
 
+    /* Same as android.hardware.usb.V1_2.Constants.ContaminantPresenceStatus */
+    enum ContaminantPresenceStatus {
+        CONTAMINANT_STATUS_NOT_SUPPORTED = 0;
+        CONTAMINANT_STATUS_DISABLED = 1;
+        CONTAMINANT_STATUS_NOT_DETECTED = 2;
+        CONTAMINANT_STATUS_DETECTED = 3;
+    }
+
     optional bool connected = 1;
     optional UsbPortProto.Mode current_mode = 2;
     optional PowerRole power_role = 3;
     optional DataRole data_role = 4;
     repeated UsbPortStatusRoleCombinationProto role_combinations = 5;
+    optional ContaminantPresenceStatus contaminant_presence_status = 6;
 }
 
 message UsbPortStatusRoleCombinationProto {
diff --git a/core/proto/android/stats/docsui/docsui_enums.proto b/core/proto/android/stats/docsui/docsui_enums.proto
index 6cb606a..655b5e3 100644
--- a/core/proto/android/stats/docsui/docsui_enums.proto
+++ b/core/proto/android/stats/docsui/docsui_enums.proto
@@ -33,13 +33,14 @@
     MIME_UNKNOWN = 0;
     MIME_NONE = 1;
     MIME_ANY = 2;
-    MIME_AUDIO = 3;
-    MIME_IMAGE = 4;
-    MIME_MESSAGE = 5;
-    MIME_MULTIPART = 6;
-    MIME_TEXT = 7;
-    MIME_VIDEO = 8;
-    MIME_OTHER = 9;
+    MIME_APPLICATION = 3;
+    MIME_AUDIO = 4;
+    MIME_IMAGE = 5;
+    MIME_MESSAGE = 6;
+    MIME_MULTIPART = 7;
+    MIME_TEXT = 8;
+    MIME_VIDEO = 9;
+    MIME_OTHER = 10;
 }
 
 enum Root {
@@ -163,6 +164,8 @@
     ACTION_EXTRACT_TO = 29;
     ACTION_VIEW_IN_APPLICATION = 30;
     ACTION_INSPECTOR = 31;
+    ACTION_SEARCH_CHIP = 32;
+    ACTION_SEARCH_HISTORY = 33;
 }
 
 enum InvalidScopedAccess {
@@ -172,3 +175,20 @@
     SCOPED_DIR_ACCESS_ERROR = 3;
     SCOPED_DIR_ACCESS_DEPRECATED = 4;
 }
+
+enum SearchType {
+    TYPE_UNKNOWN = 0;
+    TYPE_CHIP_IMAGES = 1;
+    TYPE_CHIP_AUDIOS = 2;
+    TYPE_CHIP_VIDEOS = 3;
+    TYPE_CHIP_DOCS = 4;
+    TYPE_SEARCH_HISTORY = 5;
+    TYPE_SEARCH_STRING = 6;
+}
+
+enum SearchMode {
+    SEARCH_UNKNOWN = 0;
+    SEARCH_KEYWORD = 1;
+    SEARCH_CHIPS = 2;
+    SEARCH_KEYWORD_N_CHIPS = 3;
+}
diff --git a/core/proto/android/view/remote_animation_target.proto b/core/proto/android/view/remote_animation_target.proto
index fb4d5bd..808c514 100644
--- a/core/proto/android/view/remote_animation_target.proto
+++ b/core/proto/android/view/remote_animation_target.proto
@@ -42,4 +42,6 @@
     optional .android.graphics.PointProto position = 8;
     optional .android.graphics.RectProto source_container_bounds = 9;
     optional .android.app.WindowConfigurationProto window_configuration = 10;
+    optional .android.view.SurfaceControlProto start_leash = 11;
+    optional .android.graphics.RectProto start_bounds = 12;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b16c16d..f92df6a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -51,6 +51,7 @@
     <protected-broadcast android:name="android.intent.action.PACKAGE_VERIFIED" />
     <protected-broadcast android:name="android.intent.action.PACKAGES_SUSPENDED" />
     <protected-broadcast android:name="android.intent.action.PACKAGES_UNSUSPENDED" />
+    <protected-broadcast android:name="android.intent.action.DISTRACTING_PACKAGES_CHANGED" />
     <protected-broadcast android:name="android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED" />
     <protected-broadcast android:name="android.intent.action.UID_REMOVED" />
     <protected-broadcast android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
@@ -486,6 +487,7 @@
     <protected-broadcast android:name="android.security.action.TRUST_STORE_CHANGED" />
     <protected-broadcast android:name="android.security.action.KEYCHAIN_CHANGED" />
     <protected-broadcast android:name="android.security.action.KEY_ACCESS_CHANGED" />
+    <protected-broadcast android:name="android.telecom.action.NUISANCE_CALL_STATUS_CHANGED" />
     <protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_REGISTERED" />
     <protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_UNREGISTERED" />
     <protected-broadcast android:name="android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION" />
@@ -1185,6 +1187,7 @@
     <!-- Used for permissions that are associated with activity recognition.
          TODO(zezeozue). STOPSHIP: Add icon -->
     <permission-group android:name="android.permission-group.ACTIVITY_RECOGNITION"
+        android:icon="@drawable/perm_group_activity_recognition"
         android:label="@string/permgrouplab_activityRecognition"
         android:description="@string/permgroupdesc_activityRecognition"
         android:request="@string/permgrouprequest_activityRecognition"
@@ -1651,6 +1654,11 @@
     <permission android:name="android.permission.WIFI_SET_DEVICE_MOBILITY_STATE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- #SystemApi @hide Allows privileged system APK to update Wifi usability stats and score.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"
+        android:protectionLevel="signature|privileged" />
+
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
     <!-- ======================================= -->
@@ -1746,6 +1754,10 @@
     <permission android:name="android.permission.MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED"
         android:protectionLevel="signature" />
 
+    <!-- @hide Allows the device to be reset, clearing all data and enables Test Harness Mode. -->
+    <permission android:name="android.permission.ENABLE_TEST_HARNESS_MODE"
+        android:protectionLevel="signature" />
+
     <!-- ================================== -->
     <!-- Permissions for accessing accounts -->
     <!-- ================================== -->
@@ -2208,8 +2220,9 @@
     <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
         android:protectionLevel="signature|installer" />
 
-    <!-- @SystemApi Allows an application to start an activity within its managed profile from
-         the personal profile.
+    <!-- @SystemApi Allows an application to start its own activities, but on a different profile
+         associated with the user. For example, an application running on the main profile of a user
+         can start an activity on a managed profile of that user.
          This permission is not available to third party applications.
          @hide -->
     <permission android:name="android.permission.INTERACT_ACROSS_PROFILES"
@@ -2256,7 +2269,7 @@
 
     <!-- @SystemApi @TestApi @hide Allows an application to create/manage/remove stacks -->
     <permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi @TestApi @hide Allows an application to embed other activities -->
     <permission android:name="android.permission.ACTIVITY_EMBEDDING"
@@ -2268,6 +2281,11 @@
     <permission android:name="android.permission.START_ANY_ACTIVITY"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to start activities from background
+         @hide -->
+    <permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"
+        android:protectionLevel="signature|privileged|vendorPrivileged|oem" />
+
     <!-- @SystemApi Must be required by activities that handle the intent action
          {@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
          hold {@link Manifest.permission#SUSPEND_APPS} to interact with the system.
@@ -2526,6 +2544,16 @@
     <permission android:name="android.permission.WRITE_GSERVICES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi @hide Allows an application to modify config settings.
+    <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.WRITE_DEVICE_CONFIG"
+        android:protectionLevel="signature|configurator"/>
+
+    <!-- @SystemApi @hide Allows an application to read config settings.
+    <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.READ_DEVICE_CONFIG"
+        android:protectionLevel="signature|preinstalled" />
+
     <!-- @SystemApi @TestApi Allows an application to call
         {@link android.app.ActivityManager#forceStopPackage}.
         @hide -->
@@ -3039,6 +3067,15 @@
     <permission android:name="android.permission.BIND_TEXT_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Must be required by a AttentionService
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+         @hide
+    -->
+    <permission android:name="android.permission.BIND_ATTENTION_SERVICE"
+                android:protectionLevel="signature" />
+    <uses-permission android:name="android.permission.BIND_ATTENTION_SERVICE" />
+
     <!-- Must be required by a {@link android.net.VpnService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature
@@ -3190,9 +3227,10 @@
 
     <!-- @SystemApi Required to add or remove another application as a device admin.
          <p>Not for use by third-party applications.
-         @hide -->
+         @hide
+         @removed -->
     <permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an app to reset the device password.
          <p>Not for use by third-party applications.
@@ -3379,6 +3417,11 @@
     <permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS"
          android:protectionLevel="signature|installer|verifier" />
 
+    <!-- @SystemApi Allows the system to read runtime permission state.
+        @hide -->
+    <permission android:name="android.permission.GET_RUNTIME_PERMISSIONS"
+                android:protectionLevel="signature" />
+
     <!-- @hide Allows an application to observe permission changes. -->
     <permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
         android:protectionLevel="signature|privileged" />
@@ -3509,19 +3552,25 @@
     <permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to provide remote displays.
+         <p>Not for use by third-party applications.</p>
+         @hide -->
+    <permission android:name="android.permission.REMOTE_DISPLAY_PROVIDER"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows an application to capture video output.
          <p>Not for use by third-party applications.</p>
           @hide
           @removed -->
     <permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to capture secure video output.
          <p>Not for use by third-party applications.</p>
           @hide
           @removed -->
     <permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to know what content is playing and control its playback.
          <p>Not for use by third-party applications due to privacy of media consumption</p>  -->
@@ -3854,6 +3903,10 @@
     <permission android:name="android.permission.PACKAGE_ROLLBACK_AGENT"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi @hide Allows managing apk level rollbacks. -->
+    <permission android:name="android.permission.MANAGE_ROLLBACKS"
+        android:protectionLevel="signature|verifier" />
+
     <!-- @SystemApi @hide Allows an application to mark other applications as harmful -->
     <permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS"
         android:protectionLevel="signature|verifier" />
@@ -3897,7 +3950,8 @@
     <permission android:name="android.permission.ACCESS_NOTIFICATIONS"
         android:protectionLevel="signature|privileged|appop" />
 
-    <!-- Marker permission for applications that wish to access notification policy.
+    <!-- Marker permission for applications that wish to access notification policy. This permission
+        is not supported on managed profiles.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"
@@ -4245,6 +4299,16 @@
     <permission android:name="android.permission.MANAGE_CONTENT_CAPTURE"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows an application to manage the content suggestions service.
+         @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS"
+         android:protectionLevel="signature" />
+
+    <!-- @SystemApi Allows an application to manage the app predictions service.
+         @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.MANAGE_APP_PREDICTIONS"
+         android:protectionLevel="signature" />
+
     <!-- Allows an app to set the theme overlay in /vendor/overlay
          being used.
          @hide  <p>Not for use by third-party applications.</p> -->
@@ -4325,6 +4389,11 @@
     <permission android:name="android.permission.BIND_SMS_APP_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- @hide Permission that allows configuring appops.
+     <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.MANAGE_APPOPS"
+                android:protectionLevel="signature" />
+
     <!-- @hide Permission that allows background clipboard access.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND"
@@ -4706,6 +4775,11 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
+        <service android:name="com.android.server.ZramWriteback"
+                 android:exported="false"
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
+        </service>
+
         <service android:name="com.android.server.backup.FullBackupJob"
                  android:exported="true"
                  android:permission="android.permission.BIND_JOB_SERVICE" >
diff --git a/core/res/res/drawable/ic_account_circle.xml b/core/res/res/drawable/ic_account_circle.xml
index f7317db..71691ad 100644
--- a/core/res/res/drawable/ic_account_circle.xml
+++ b/core/res/res/drawable/ic_account_circle.xml
@@ -14,18 +14,14 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48.0dp"
-        android:height="48.0dp"
-        android:viewportWidth="20.0"
-        android:viewportHeight="20.0">
-    <group
-        android:translateX="-2"
-        android:translateY="-2" >
-        <path
-            android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM18.36,16.83c-1.43,-1.74 -4.9,-2.33 -6.36,-2.33s-4.93,0.59 -6.36,2.33C4.62,15.49 4,13.82 4,12c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,13.82 19.38,15.49 18.36,16.83z"
-            android:fillColor="#FFFFFFFF" />
-        <path
-            android:pathData="M12,6c-1.94,0 -3.5,1.56 -3.5,3.5S10.06,13 12,13c1.94,0 3.5,-1.56 3.5,-3.5S13.94,6 12,6z"
-            android:fillColor="#FFFFFFFF" />
-    </group>
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM18.36,16.83c-1.43,-1.74 -4.9,-2.33 -6.36,-2.33s-4.93,0.59 -6.36,2.33C4.62,15.49 4,13.82 4,12c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,13.82 19.38,15.49 18.36,16.83z"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,6c-1.94,0 -3.5,1.56 -3.5,3.5S10.06,13 12,13c1.94,0 3.5,-1.56 3.5,-3.5S13.94,6 12,6z"/>
 </vector>
diff --git a/core/res/res/drawable/ic_battery.xml b/core/res/res/drawable/ic_battery.xml
new file mode 100644
index 0000000..bd40f4d
--- /dev/null
+++ b/core/res/res/drawable/ic_battery.xml
@@ -0,0 +1,25 @@
+<!--
+    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:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V5.33C17,4.6 16.4,4 15.67,4z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_corp_badge.xml b/core/res/res/drawable/ic_corp_badge.xml
index 1dad977..5ab5045 100644
--- a/core/res/res/drawable/ic_corp_badge.xml
+++ b/core/res/res/drawable/ic_corp_badge.xml
@@ -15,22 +15,11 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="20dp"
-        android:height="20dp"
-        android:viewportWidth="48"
-        android:viewportHeight="48">
-
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
     <path
-        android:fillType="evenOdd"
-        android:strokeColor="#1A73E8"
-        android:strokeWidth="4"
-        android:pathData="M 24 2 C 36.1502644963 2 46 11.8497355037 46 24 C 46 36.1502644963 36.1502644963 46 24 46 C 11.8497355037 46 2 36.1502644963 2 24 C 2 11.8497355037 11.8497355037 2 24 2 Z" />
-    <group
-        android:translateX="10.400000"
-        android:translateY="10.400000">
-        <path
-            android:fillColor="#1A73E8"
-            android:strokeWidth="1"
-            android:pathData="M24.2971429,5.38947368 L18.9485714,5.38947368 L18.9485714,2.80902256 C18.9485714,1.37687218 17.7585143,0.228571429 16.2742857,0.228571429 L10.9257143,0.228571429 C9.44148571,0.228571429 8.25142857,1.37687218 8.25142857,2.80902256 L8.25142857,5.38947368 L2.90285714,5.38947368 C1.41862857,5.38947368 0.241942857,6.53777444 0.241942857,7.96992481 L0.228571429,22.162406 C0.228571429,23.5945564 1.41862857,24.7428571 2.90285714,24.7428571 L24.2971429,24.7428571 C25.7813714,24.7428571 26.9714286,23.5945564 26.9714286,22.162406 L26.9714286,7.96992481 C26.9714286,6.53777444 25.7813714,5.38947368 24.2971429,5.38947368 Z M13.6,17.0015038 C12.1291429,17.0015038 10.9257143,15.8403008 10.9257143,14.4210526 C10.9257143,13.0018045 12.1291429,11.8406015 13.6,11.8406015 C15.0708571,11.8406015 16.2742857,13.0018045 16.2742857,14.4210526 C16.2742857,15.8403008 15.0708571,17.0015038 13.6,17.0015038 Z M16.2742857,5.38947368 L10.9257143,5.38947368 L10.9257143,2.80902256 L16.2742857,2.80902256 L16.2742857,5.38947368 Z" />
-    </group>
+        android:fillColor="@*android:color/accent_device_default_light"
+        android:pathData="M20,6h-4V4c0,-1.11 -0.89,-2 -2,-2h-4C8.89,2 8,2.89 8,4v2H4C2.89,6 2.01,6.89 2.01,8L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V8C22,6.89 21.11,6 20,6zM10,4h4v2h-4V4zM20,19H4V8h16V19z"/>
 </vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/perm_group_activity_recognition.xml b/core/res/res/drawable/perm_group_activity_recognition.xml
new file mode 100644
index 0000000..0ade6c6
--- /dev/null
+++ b/core/res/res/drawable/perm_group_activity_recognition.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2019 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#000000"
+        android:pathData="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1
+2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9
+0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5 .1 -.8 .1 l-5.2
+2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z" />
+</vector>
diff --git a/core/res/res/drawable/perm_group_sensors.xml b/core/res/res/drawable/perm_group_sensors.xml
index ce36c13..e4663d7 100644
--- a/core/res/res/drawable/perm_group_sensors.xml
+++ b/core/res/res/drawable/perm_group_sensors.xml
@@ -19,11 +19,11 @@
     android:height="24dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
-
-    <path
-        android:fillColor="#000000"
-        android:pathData="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1
-2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9
-0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5 .1 -.8 .1 l-5.2
-2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z" />
-</vector>
\ No newline at end of file
+  <path
+      android:fillColor="#000000"
+      android:pathData="M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3C4.42,3 2,5.42 2,
+                        8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5C22,
+                        5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1l-0.1,-0.1C7.14,14.24 4,11.39 4,8.5C4,6.5 5.5,
+                        5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5C20,
+                        11.39 16.86,14.24 12.1,18.55z"/>
+</vector>
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 7dee2af..ded2b35 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -31,7 +31,7 @@
             android:layout_alwaysShow="true"
             android:elevation="8dp"
             android:paddingStart="16dp"
-            android:background="@color/white" >
+            android:background="?attr/colorBackgroundFloating" >
         <TextView android:id="@+id/profile_button"
                   android:layout_width="wrap_content"
                   android:layout_height="48dp"
@@ -73,7 +73,7 @@
             android:id="@+id/resolver_list"
             android:clipToPadding="false"
             android:scrollbarStyle="outsideOverlay"
-            android:background="@color/white"
+            android:background="?attr/colorBackgroundFloating"
             android:elevation="8dp"
             android:listSelector="@color/transparent"
             android:divider="@null"
@@ -84,7 +84,7 @@
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:layout_alwaysShow="true"
-              android:background="@color/white"
+              android:background="?attr/colorBackgroundFloating"
               android:text="@string/noApplications"
               android:padding="32dp"
               android:gravity="center"
diff --git a/core/res/res/layout/notification_template_ambient_header.xml b/core/res/res/layout/notification_template_ambient_header.xml
deleted file mode 100644
index be5d9b4..0000000
--- a/core/res/res/layout/notification_template_ambient_header.xml
+++ /dev/null
@@ -1,28 +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.
-  -->
-
-<!-- hack to work around <include /> not being supported at the top level -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:paddingStart="@dimen/notification_extra_margin_ambient"
-    android:paddingEnd="@dimen/notification_extra_margin_ambient"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content">
-    <include
-        layout="@layout/notification_template_header"
-        android:theme="@style/Theme.DeviceDefault.Notification.Ambient"/>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
deleted file mode 100644
index 2c6064e..0000000
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ /dev/null
@@ -1,94 +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.
-  -->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/status_bar_latest_event_content"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:tag="ambient"
-    android:paddingStart="@dimen/notification_extra_margin_ambient"
-    android:paddingEnd="@dimen/notification_extra_margin_ambient"
-    >
-    <include layout="@layout/notification_template_ambient_header"
-             android:theme="@style/Theme.DeviceDefault.Notification.Ambient" />
-
-    <LinearLayout
-            android:id="@+id/notification_action_list_margin_target"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_gravity="top"
-            android:layout_marginTop="@dimen/notification_content_margin_top"
-            android:layout_marginBottom="@dimen/notification_action_list_height"
-            android:paddingTop="4dp"
-            android:paddingBottom="6dp"
-            android:clipToPadding="false"
-            android:orientation="vertical">
-
-        <LinearLayout
-            android:id="@+id/notification_main_column"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="top"
-            android:layout_weight="1"
-            android:paddingStart="@dimen/notification_content_margin_start"
-            android:paddingEnd="@dimen/notification_content_margin_end"
-            android:clipToPadding="false"
-            android:minHeight="@dimen/notification_min_content_height"
-            android:orientation="vertical"
-            >
-            <TextView android:id="@+id/title"
-                android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:gravity="top|center_horizontal"
-                android:singleLine="true"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                android:textSize="@dimen/notification_ambient_title_text_size"
-                android:textColor="#ffffffff"
-            />
-            <TextView android:id="@+id/text"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:textAppearance="@style/TextAppearance.DeviceDefault.Notification"
-                android:singleLine="false"
-                android:layout_weight="1"
-                android:gravity="top|center_horizontal"
-                android:visibility="gone"
-                android:textSize="@dimen/notification_ambient_text_size"
-                android:textColor="#eeffffff"
-                android:layout_marginTop="4dp"
-                android:ellipsize="end"
-                android:maxLines="3"
-            />
-        </LinearLayout>
-        <FrameLayout android:id="@+id/actions_container"
-                     android:layout_width="match_parent"
-                     android:layout_height="wrap_content"
-                     android:layout_gravity="bottom">
-            <com.android.internal.widget.NotificationActionListLayout
-                android:id="@+id/actions"
-                android:layout_width="match_parent"
-                android:layout_height="@dimen/notification_action_list_height"
-                android:paddingEnd="4dp"
-                android:orientation="horizontal"
-                android:gravity="center"
-                android:visibility="gone"
-            />
-        </FrameLayout>
-    </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/time_picker_header_material.xml b/core/res/res/layout/time_picker_header_material.xml
index adb2b62..30c10b1 100644
--- a/core/res/res/layout/time_picker_header_material.xml
+++ b/core/res/res/layout/time_picker_header_material.xml
@@ -76,16 +76,14 @@
         android:layout_height="wrap_content"
         android:layout_toRightOf="@+id/minutes"
         android:layout_alignBaseline="@+id/minutes"
-        android:paddingStart="4dp"
-        android:paddingEnd="4dp"
+        android:layout_marginStart="8dp"
+        android:layout_marginEnd="0dp"
         android:orientation="vertical"
         android:baselineAlignedChildIndex="1">
         <RadioButton
             android:id="@+id/am_label"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:paddingLeft="4dp"
-            android:paddingRight="4dp"
             android:paddingTop="8dp"
             android:paddingBottom="8dp"
             android:layout_marginBottom="-8dp"
@@ -101,8 +99,6 @@
             android:id="@+id/pm_label"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:paddingLeft="4dp"
-            android:paddingRight="4dp"
             android:paddingTop="8dp"
             android:paddingBottom="8dp"
             android:textAppearance="@style/TextAppearance.Material.TimePicker.AmPmLabel"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 3f23da6..770a82e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Laat die program toe om liggings in jou mediaversameling te lees."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Die program <xliff:g id="APP">%s</xliff:g> wil staaf."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometriese hardeware is nie beskikbaar nie"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Stawing is gekanselleer"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nie herken nie"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Stawing is gekanselleer"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Gedeeltelike vingerafdruk is bespeur. Probeer asseblief weer."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Kon nie vingerafdruk verwerk nie. Probeer asseblief weer."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Vingerafdruksensor is vuil. Maak dit skoon en probeer weer."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Maak oop met"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Maak oop met %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Maak oop"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Gee toegang tot oop <xliff:g id="HOST">%1$s</xliff:g>-skakels met"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Gee toegang tot oop <xliff:g id="HOST">%1$s</xliff:g>-skakels met <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Verleen toegang"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Redigeer met"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redigeer met %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Wysig"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aanvaar oproep?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Altyd"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Net een keer"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Instellings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s steun nie werkprofiel nie"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Druk en hou albei volumesleutels drie sekondes lank om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruik"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofoon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"wys tans bo-oor ander programme op jou skerm"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Roetinemodus-inligtingkennisgewing"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Battery kan afloop voordat dit normaalweg gelaai word"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batterybespaarder is geaktiveer om batterylewe te verleng"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Laai tans"</string>
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index ca1aabd..8ec7cd0 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"መተግበሪያው አካባቢዎችን ከሚዲያ ስብስብዎ እንዲያነብብ ያስችለዋል።"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"መተግበሪያ <xliff:g id="APP">%s</xliff:g> ማረጋገጥ ይፈልጋል"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ባዮሜትራዊ ሃርድዌር አይገኝም"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ማረጋገጥ ተሰርዟል"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"አልታወቀም"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"ማረጋገጥ ተሰርዟል"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ክፈት በ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"ክፈት በ%1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ክፈት"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"የ<xliff:g id="HOST">%1$s</xliff:g> አገናኞችን በዚህ ለመክፈት መዳረሻ ይስጡ፦"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"የ<xliff:g id="HOST">%1$s</xliff:g> አገናኞችን በ<xliff:g id="APPLICATION">%2$s</xliff:g> ለመክፈት መዳረሻ ይስጡ"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"መዳረሻ ስጥ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ያርትዑ በ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"ያርትዑ በ%1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ያርትዑ"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ጥሪ ተቀበል?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ዘወትር"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"አንዴ ብቻ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ቅንብሮች"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s የስራ መገለጫ አይደግፍም"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ጡባዊ ተኮ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ቴሌቪዥን"</string>
@@ -1645,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን ለመጠቀም ለሦስት ሰከንዶች ሁለቱንም የድምፅ ቁልፎች ተጭነው ይያዙ"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ካሜራ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ማይክሮፎን"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"በማያዎ ላይ በሌሎች መተግበሪያዎች ላይ በማሳየት ላይ"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"የዕለት ተዕለት ሁነታ መረጃ ማሳወቂያዎች"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"ባትሪ ከተለመደው ኃይል መሙላት በፊት ሊያልቅ ይችላል"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"የባትሪ ቆጣቢ የባትሪ ዕድሜን ለማራዘም ገብሯል።"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"በመጫን ላይ"</string>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 4557563..8d7b801 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -545,11 +545,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"للسماح للتطبيق بقراءة المواقع من مجموعة الوسائط التابعة لك."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"يتطلَّب التطبيق <xliff:g id="APP">%s</xliff:g> المصادقة."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"معدّات المقاييس الحيوية غير متاحة."</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"تم إلغاء المصادقة."</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"لم يتم التعرف عليها."</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"تم إلغاء المصادقة."</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>
@@ -1208,6 +1206,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"فتح باستخدام"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏فتح باستخدام %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"فتح"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"منح إمكانية الوصول لفتح روابط <xliff:g id="HOST">%1$s</xliff:g> باستخدام"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"منح إمكانية الوصول لفتح روابط <xliff:g id="HOST">%1$s</xliff:g> باستخدام <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"منح إذن الوصول"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"تعديل باستخدام"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏تعديل باستخدام %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"تعديل"</string>
@@ -1539,7 +1540,7 @@
     <string name="vpn_lockdown_config" msgid="8151951501116759194">"‏تغيير إعدادات الشبكة أو الشبكة الافتراضية الخاصة (VPN)"</string>
     <string name="upload_file" msgid="2897957172366730416">"اختيار ملف"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"لم يتم اختيار أي ملف"</string>
-    <string name="reset" msgid="2448168080964209908">"إعادة تعيين"</string>
+    <string name="reset" msgid="2448168080964209908">"إعادة الضبط"</string>
     <string name="submit" msgid="1602335572089911941">"إرسال"</string>
     <string name="car_mode_disable_notification_title" msgid="5704265646471239078">"تطبيق القيادة قيد التشغيل"</string>
     <string name="car_mode_disable_notification_message" msgid="7647248420931129377">"انقر للخروج من تطبيق القيادة."</string>
@@ -1658,6 +1659,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"هل تريد قبول المكالمة؟"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"دومًا"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"مرة واحدة فقط"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"الإعدادات"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏لا يدعم %1$s الملفات الشخصية للعمل"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"الجهاز اللوحي"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"التلفزيون"</string>
@@ -1741,7 +1743,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_shortcut_spoken_feedback" msgid="8376923232350078434">"اضغط مع الاستمرار على مفتاحي مستوى الصوت لمدة 3 ثوانٍ لاستخدام <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</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>
@@ -2115,5 +2117,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"كاميرا"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ميكروفون"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"العرض فوق التطبيقات الأخرى على شاشتك"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"إشعار معلومات \"وضع سلسلة الإجراءات\""</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"قد تنفد طاقة البطارية قبل الشحن المعتاد"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"تم تفعيل \"توفير شحن البطارية\" لإطالة عمرها."</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"جارٍ التحميل"</string>
 </resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index a4f950a..74a4584 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"এপক আপোনাৰ মিডিয়া সংগ্ৰহৰ অৱস্থান পঢ়িবলৈ দিয়ে।"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> এপে বিশ্বাসযোগ্যতাৰ প্ৰমাণ কৰিব বিচাৰে।"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"বায়োমেট্ৰিক হাৰ্ডৱেৰ উপলব্ধ নহয়"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"বিশ্বাসযোগ্যতাৰ প্ৰমাণীকৰণ বাতিল কৰা হৈছে"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"চিনাক্ত কৰিব পৰা নাই"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"বিশ্বাসযোগ্যতাৰ প্ৰমাণীকৰণ বাতিল কৰা হৈছে"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ইয়াৰ জৰিয়তে খোলক"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sৰ জৰিয়তে খোলক"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"খোলক"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ইয়াৰ দ্বাৰা <xliff:g id="HOST">%1$s</xliff:g> লিংক খুলিবলৈ এক্সেছ দিয়ক"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g>ৰ দ্বাৰা <xliff:g id="HOST">%1$s</xliff:g> লিংক খুলিবলৈ এক্সেছ দিয়ক"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"এক্সেছ দিয়ক"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ইয়াৰ দ্বাৰা সম্পাদনা কৰক"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sৰদ্বাৰা সম্পাদনা কৰক"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"সম্পাদনা কৰক"</string>
@@ -1257,7 +1258,7 @@
     <string name="network_available_sign_in" msgid="1848877297365446605">"নেটৱৰ্কত ছাইন ইন কৰক"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
-    <string name="wifi_no_internet" msgid="8938267198124654938">"ৱাই-ফাইত ইন্টাৰনেট নাই"</string>
+    <string name="wifi_no_internet" msgid="8938267198124654938">"ৱাই-ফাইত ইণ্টাৰনেট নাই"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"অধিক বিকল্পৰ বাবে টিপক"</string>
     <string name="wifi_softap_config_change" msgid="8475911871165857607">"আপোনাৰ হটস্পট ছেটিংসমূহত কৰা সালসলনি"</string>
     <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"আপোনাৰ হটস্পটৰ বেণ্ড সলনি কৰা হ’ল।"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"কল স্বীকাৰ কৰিবনে?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"সদায়"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"মাত্ৰ এবাৰ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ছেটিংসমূহ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$sএ কৰ্মস্থানৰ প্ৰ\'ফাইল সমৰ্থন নকৰে।"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"টেবলেট"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"টিভি"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যৱহাৰ কৰিবলৈ দুয়োটা ভলিউম বুটাম তিনি ছেকেণ্ডৰ বাবে হেঁচি ৰাখক"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"কেমেৰা"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"মাইক্ৰ\'ফ\'ন"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"স্ক্ৰীণত অইন এপৰ ওপৰত দেখুৱাওক"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"ৰুটিন ম’ডৰ তথ্য জাননী"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"চ্চাৰ্জ কৰাৰ সচৰাচৰ সময়ৰ আগতেই বেটাৰি শেষ হ’ব পাৰে"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"বেটাৰিৰ খৰচ কমাবলৈ বেটাৰি সঞ্চয়কাৰী অন কৰা হৈছে"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"ল’ড হৈ আছে"</string>
 </resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 076ea8d..c941704 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Tətbiqin media kolleksiyanızdan məkanları oxumasına icazə verin."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> doğrulamaq istəyir."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrik proqram əlçatan deyil"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Doğrulama ləğv edildi"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Tanınmır"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Doğrulama ləğv edildi"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Barmaq qismən müəyyən olundu. Lütfən, yenidən cəhd edin."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Barmaq izi tanınmadı. Lütfən, yenidən cəhd edin."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Barmaq izi sensoru çirklidir. Lütfən, təmizləyin və yenidən cəhd edin."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Bununla açın"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ilə açın"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Açın"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Bu tətbiqlə <xliff:g id="HOST">%1$s</xliff:g> linklərini açmağa icazə verin:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ilə <xliff:g id="HOST">%1$s</xliff:g> linklərini açmağa icazə verin"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"İcazə verin"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Bununla düzəliş edin:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ilə düzəliş edin"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Redaktə edin"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Zəngi qəbul edək?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Həmişə"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Sadəcə bir dəfə"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ayarlar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s iş profilini dəstəkləmir"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Planşet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> istifadə etmək üçün hər iki səs düyməsini üç saniyə basıb saxlayın"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ekrandakı digər tətbiqlərdə göstərin"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Rejim üçün məlumat bildirişi"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Batareya həmişəki vaxtdan əvvəl bitə bilər"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Enerjiyə Qənaət rejimi batareya istifadəsinin müddətini artırmaq üçün aktiv edilir"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Yüklənir"</string>
 </resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 0a94acf..7de4e9e 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -536,11 +536,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Dozvoljava aplikaciji da čita lokacije iz medijske kolekcije."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Aplikacija <xliff:g id="APP">%s</xliff:g> želi da potvrdi vaš identitet."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrijski hardver nije dostupan"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Potvrda identiteta je otkazana"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Potvrda identiteta je otkazana"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je delimični otisak prsta. Probajte ponovo."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspela obrada otiska prsta. Probajte ponovo."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor za otiske prstiju je prljav. Očistite ga i pokušajte ponovo."</string>
@@ -1148,6 +1146,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otvorite pomoću"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvorite pomoću aplikacije %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Dozvolite da se linkovi <xliff:g id="HOST">%1$s</xliff:g> otvaraju pomoću"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Dozvolite da <xliff:g id="APPLICATION">%2$s</xliff:g> otvara linikove <xliff:g id="HOST">%1$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dozvoli pristup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Izmenite pomoću"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Izmenite pomoću aplikacije %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Izmeni"</string>
@@ -1589,6 +1590,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Želite li da prihvatite poziv?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvek"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo jednom"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Podešavanja"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava poslovni profil"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1669,7 +1671,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Pritisnite i zadržite oba tastera za jačinu zvuka tri sekunde da biste koristili <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="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>
@@ -2010,5 +2012,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"prikazuje se na ekranu dok koristite druge aplikacije"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Obaveštenje o informacijama Rutinskog režima"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Baterija će se možda isprazniti pre uobičajenog punjenja"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Ušteda baterije je aktivirana da bi se produžilo trajanje baterije"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Učitava se"</string>
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index cfe076d..4f98eaa 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -79,7 +79,7 @@
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Налады ідэнтыфікатару АВН па змаўчанні: не абмяжавана. Наступны выклік: не абмежавана"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Служба не прадастаўляецца."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Вы не можаце змяніць налады ідэнтыфікатара абанента, якi тэлефануе."</string>
-    <string name="RestrictedOnDataTitle" msgid="5221736429761078014">"Мабільны інтэрнэт недаступны"</string>
+    <string name="RestrictedOnDataTitle" msgid="5221736429761078014">"Мабільная перадача даных недаступная"</string>
     <string name="RestrictedOnEmergencyTitle" msgid="6855466023161191166">"Экстранныя выклікі недаступныя"</string>
     <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Няма сэрвісу галасавых выклікаў"</string>
     <string name="RestrictedOnAllVoiceTitle" msgid="8037246983606545202">"Галасавыя або экстранныя выклікі недаступныя"</string>
@@ -435,7 +435,7 @@
     <string name="permdesc_accessBackgroundLocation" msgid="1096394429579210251">"Акрамя доступу да прыкладнага ці дакладнага месцазнаходжання праграма можа мець доступ да вызначэння геалакацыі ў фонавым рэжыме працы. На гэта патрабуецца дазвол."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"змяняць налады аудыё"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Дазваляе прыкладанням змяняць глабальныя налады гуку, такія як моц і тое, што дынамік выкарыстоўваецца для выхаду."</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"запісваць аўдыё"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"запіс аўдыя"</string>
     <string name="permdesc_recordAudio" msgid="4245930455135321433">"Гэта праграма можа у любы час запісваць аўдыя, выкарыстоўваючы мікрафон."</string>
     <string name="permlab_sim_communication" msgid="2935852302216852065">"адпраўляць каманды на SIM-карту"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Дазваляе праграме адпраўляць каманды SIM-карце. Гэта вельмі небяспечна."</string>
@@ -539,11 +539,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Праграма зможа паказваць месцазнаходжанне ў калекцыі мультымедыя."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Праграма \"<xliff:g id="APP">%s</xliff:g>\" патрабуе аўтэнтыфікацыі."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Біяметрычнае абсталяванне недаступнае"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Аўтэнтыфікацыя скасавана"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Не распазнана"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Аўтэнтыфікацыя скасавана"</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>
@@ -1168,6 +1166,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Адкрыць з дапамогай"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Адкрыць з дапамогай %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Адкрыць"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Адкрываць спасылкі на сэрвіс <xliff:g id="HOST">%1$s</xliff:g> з дапамогай"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Адкрываць спасылкі на сэрвіс <xliff:g id="HOST">%1$s</xliff:g> з дапамогай праграмы \"<xliff:g id="APPLICATION">%2$s</xliff:g>\""</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Даць доступ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Рэдагаваць з дапамогай"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Рэдагаваць з дапамогай %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Рэдагаваць"</string>
@@ -1612,6 +1613,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Прыняць выклік?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Заўсёды"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Толькі адзін раз"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Налады"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не падтрымлівае працоўны профіль"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшэт"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ТБ"</string>
@@ -1693,7 +1695,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Каб карыстацца сэрвісам \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", націсніце і ўтрымлівайце на працягу трох секунд абедзве клавішы гучнасці"</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>
@@ -2045,5 +2047,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Мікрафон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"паказваецца паверх іншых праграм на экране"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Апавяшчэнне з інфармацыяй пра ўсталяваны рэжым"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Акумулятар можа разрадзіцца хутчэй, чым прыйдзе час звычайнай зарадкі"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Каб павялічыць тэрмін работы акумулятара, уключаны рэжым эканоміі зараду"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Загрузка"</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 8897bac..704dc52 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Разрешава на приложението да чете местоположенията от мултимедийната ви колекция."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Приложението <xliff:g id="APP">%s</xliff:g> изисква удостоверяване."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометричният хардуер не е налице"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Удостоверяването бе анулирано"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Не е разпознато"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Удостоверяването бе анулирано"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Отваряне чрез"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отваряне чрез %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отваряне"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Предоставяне на достъп за отваряне на връзките от <xliff:g id="HOST">%1$s</xliff:g> с(ъс)"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Предоставяне на достъп за отваряне на връзките от <xliff:g id="HOST">%1$s</xliff:g> с(ъс) <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Даване на достъп"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Редактиране чрез"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редактиране чрез %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Редактиране"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Да се приеме ли обаждането?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Винаги"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Само веднъж"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Настройки"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддържа служебен потребителски профил"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Таблет"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевизор"</string>
@@ -1645,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"За да използвате <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, натиснете двата бутона за силата на звука и ги задръжте за 3 секунди"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"се показва върху други приложения на екрана"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Известие с информация за режима на поредица"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Батерията може да се изтощи преди обичайното зареждане"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Режимът за запазване на батерията е активиран с цел удължаване на живота на батерията"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Зарежда се"</string>
 </resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 26a3ba0..b6ab1e6 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"আপনার মিডিয়া সংগ্রহ থেকে লোকেশন দেখতে অ্যাপকে অনুমতি দিন।"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> অ্যাপ্লিকেশন যাচাই করতে চাইছে।"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"বায়োমেট্রিক হার্ডওয়্যার পাওয়া যাবে না"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"যাচাইকরণ বাতিল হয়েছে"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"স্বীকৃত নয়"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"যাচাইকরণ বাতিল হয়েছে"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"এর মাধ্যমে খুলুন"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s দিয়ে খুলুন"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"খুলুন"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ব্যবহার করে <xliff:g id="HOST">%1$s</xliff:g> লিঙ্ক খুলতে অ্যাক্সেস দিন"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ব্যবহার করে <xliff:g id="HOST">%1$s</xliff:g> লিঙ্ক খুলতে অ্যাক্সেস দিন"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"অ্যাক্সেস দিন"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"এর মাধ্যমে সম্পাদনা করুন"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s দিয়ে সম্পাদনা করুন"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"সম্পাদনা করুন"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"কল গ্রহণ করবেন?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"সবসময়"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"শুধু একবার"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"সেটিংস"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s কর্মস্থলের প্রোফাইল সমর্থন করে না।"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ট্যাবলেট"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"টিভি"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যবহার করতে ভলিউম কী বোতাম ৩ সেকেন্ডের জন্য চেপে ধরে রাখুন"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ক্যামেরা"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"মাইক্রোফোন"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"স্ক্রিনে অন্যান্য অ্যাপের উপরে দেখানো হচ্ছে"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"রুটিন মোডের তথ্য সংক্রান্ত বিজ্ঞপ্তি"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"সাধারণত যখন চার্জ দেন, তার আগে চার্জ শেষ হয়ে যেতে পারে"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"ডিভাইস বেশিক্ষণ চালু রাখতে ব্যাটারি সেভার চালু করা হয়েছে"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"লোড হচ্ছে"</string>
 </resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index e336cd0..ab0df69 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -155,9 +155,9 @@
     <string name="httpErrorOk" msgid="1191919378083472204">"Uredu"</string>
     <string name="httpError" msgid="7956392511146698522">"Došlo je do greške na mreži."</string>
     <string name="httpErrorLookup" msgid="4711687456111963163">"Pronalaženje URL-a nije uspjelo."</string>
-    <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Shema za provjeru vjerodostojnosti stranice nije podržana."</string>
-    <string name="httpErrorAuth" msgid="1435065629438044534">"Došlo je do greške prilikom provjere vjerodostojnosti."</string>
-    <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Došlo je do greške prilikom provjere vjerodostojnosti preko proksi servera."</string>
+    <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Shema za autentifikaciju stranice nije podržana."</string>
+    <string name="httpErrorAuth" msgid="1435065629438044534">"Došlo je do greške prilikom autentifikacije."</string>
+    <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Došlo je do greške prilikom autentifikacije preko proksi servera."</string>
     <string name="httpErrorConnect" msgid="8714273236364640549">"Povezivanje sa serverom nije uspjelo."</string>
     <string name="httpErrorIO" msgid="2340558197489302188">"Veza sa serverom nije uspostavljena. Pokušajte ponovo kasnije."</string>
     <string name="httpErrorTimeout" msgid="4743403703762883954">"Vrijeme za uspostavljanje veze sa serverom je isteklo."</string>
@@ -519,7 +519,7 @@
     <string name="permlab_manageFingerprint" msgid="5640858826254575638">"upravljanje hardverom za otiske prstiju"</string>
     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Omogućava aplikaciji da koristi metode za dodavanje i brisanje šablona otisaka prstiju za upotrebu."</string>
     <string name="permlab_useFingerprint" msgid="3150478619915124905">"korištenje hardvera za otiske prstiju"</string>
-    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Omogućava aplikaciji da za provjeru vjerodostojnosti koristi hardver za otiske prstiju"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Omogućava aplikaciji da za autentifikaciju koristi hardver za otiske prstiju"</string>
     <string name="permlab_audioRead" msgid="6617225220728465565">"čitanje muzičke kolekcije"</string>
     <string name="permdesc_audioRead" msgid="5034032570243484805">"Omogućava aplikaciji da čita vašu muzičku kolekciju."</string>
     <string name="permlab_audioWrite" msgid="2661772059799779292">"izmjena muzičke kolekcije"</string>
@@ -536,11 +536,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Omogućava aplikaciji da čita lokacije iz vaše kolekcije medija."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Aplikacija <xliff:g id="APP">%s</xliff:g> traži autentifikaciju."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrijski hardver nije dostupan"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autentifikacija je otkazana"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autentifikacija je otkazana"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je djelomičan otisak prsta. Pokušajte ponovo."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspjela obrada otiska prsta. Pokušajte ponovo."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor za otisak prsta je prljav. Očistite ga i pokušajte ponovo."</string>
@@ -1148,6 +1146,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otvori koristeći"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvori koristeći %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Dozvolite pristup za otvaranje linkova hosta <xliff:g id="HOST">%1$s</xliff:g> pomoću"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Dozvolite pristup za otvaranje linkova hosta <xliff:g id="HOST">%1$s</xliff:g> pomoću aplikacije <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dozvoli pristup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Uredi koristeći"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uredi koristeći %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Uredi"</string>
@@ -1591,6 +1592,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prihvatiti poziv?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvijek"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo ovaj put"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Postavke"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava poslovni profil"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1641,7 +1643,7 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponovo unesite ispravan PUK kôd. Ponovljeni pokušaji će trajno onemogućiti SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-ovi se ne poklapaju"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Previše pokušaja otključavanja pomoću uzorka"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Da otključate, prijavite se sa svojim Google računom."</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Da otključate, prijavite se pomoću svog Google računa."</string>
     <string name="kg_login_username_hint" msgid="5718534272070920364">"Korisničko ime (adresa e-pošte)"</string>
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Lozinka"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Prijava"</string>
@@ -1671,7 +1673,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Pritisnite obje tipke za podešavanje jačine zvuka i držite ih pritisnutim tri sekunde da koristite uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -2012,5 +2014,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"prikazivanje preko drugih aplikacija na ekranu"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Obavještenje za informacije Rutinskog načina"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Moguće je da će se baterija isprazniti prije uobičajenog punjenja"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Ušteda baterije je aktivirana da bi se produžio vijek trajanja baterije"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Učitavanje"</string>
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 35c223b..e53f85e 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permet que l\'aplicació llegeixi les ubicacions de les teves col·leccions multimèdia."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"L\'aplicació <xliff:g id="APP">%s</xliff:g> vol que t\'autentiquis."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Maquinari biomètric no disponible"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"S\'ha cancel·lat l\'autenticació"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"No s\'ha reconegut"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"S\'ha cancel·lat l\'autenticació"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"S\'ha detectat una empremta digital parcial. Torna-ho a provar."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"No s\'ha pogut processar l\'empremta digital. Torna-ho a provar."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"El sensor d\'empremtes digitals està brut. Neteja\'l i torna-ho a provar."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Obre amb"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Obre amb %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Obre"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Dona accés per obrir enllaços de <xliff:g id="HOST">%1$s</xliff:g> amb"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Dona accés per obrir enllaços de <xliff:g id="HOST">%1$s</xliff:g> amb <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dona accés"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edita amb"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edita amb %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edita"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vols acceptar la trucada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Només una vegada"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuració"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admet perfils professionals."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tauleta"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televisor"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Mantén premudes les dues tecles de volum durant 3 segons per fer servir <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Càmera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micròfon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"es mostra sobre altres aplicacions a la pantalla"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificació d\'informació del mode de rutina"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"És possible que la bateria s\'esgoti abans de la càrrega habitual"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"S\'ha activat l\'estalvi de bateria per allargar-ne la durada"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"S\'està carregant"</string>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 0061ca7..55719e5 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -539,11 +539,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Umožňuje aplikaci číst místa z vaší sbírky médií."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Aplikace <xliff:g id="APP">%s</xliff:g> potřebuje provést ověření."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrický hardware není k dispozici"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Ověření bylo zrušeno"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nerozpoznáno"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Ověření bylo zrušeno"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Byla zjištěna jen část otisku prstu. Zkuste to znovu."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Zpracování otisku prstu se nezdařilo. Zkuste to znovu."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor otisků prstů je znečištěn. Vyčistěte jej a zkuste to znovu."</string>
@@ -1168,6 +1166,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otevřít v aplikaci"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otevřít v aplikaci %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otevřít"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Udělte přístup k otevírání odkazů <xliff:g id="HOST">%1$s</xliff:g> pomocí aplikace"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Udělte přístup k otevírání odkazů <xliff:g id="HOST">%1$s</xliff:g> pomocí aplikace <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udělit přístup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Upravit v aplikaci"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Upravit v aplikaci %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Upravit"</string>
@@ -1612,6 +1613,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Přijmout hovor?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vždy"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Pouze jednou"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavení"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s pracovní profily nepodporuje."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televize"</string>
@@ -1693,7 +1695,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Chcete-li používat službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, tři sekundy podržte stisknutá obě tlačítka hlasitosti"</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>
@@ -2045,5 +2047,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparát"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"zobrazení přes ostatní aplikace na obrazovce"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Informační oznámení režimu sledu činností"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Baterie se možná vybije před obvyklým časem nabití"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Byl aktivován spořič baterie za účelem prodloužení výdrže"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Načítání"</string>
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 2795efe..a5ddc78 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -87,7 +87,7 @@
     <string name="NetworkPreferenceSwitchSummary" msgid="509327194863482733">"Prøv at skifte dit foretrukne netværk. Tryk for skifte."</string>
     <string name="EmergencyCallWarningTitle" msgid="813380189532491336">"Det er ikke muligt at foretage nødopkald"</string>
     <string name="EmergencyCallWarningSummary" msgid="1899692069750260619">"Det er ikke muligt at foretage nødopkald via Wi‑Fi"</string>
-    <string name="notification_channel_network_alert" msgid="4427736684338074967">"Underretninger"</string>
+    <string name="notification_channel_network_alert" msgid="4427736684338074967">"Notifikationer"</string>
     <string name="notification_channel_call_forward" msgid="2419697808481833249">"Viderestilling af opkald"</string>
     <string name="notification_channel_emergency_callback" msgid="6686166232265733921">"Nødtilbagekaldstilstand"</string>
     <string name="notification_channel_mobile_data_status" msgid="4575131690860945836">"Status for mobildata"</string>
@@ -187,7 +187,7 @@
     <string name="work_profile_deleted_description_dpm_wipe" msgid="8823792115612348820">"Din arbejdsprofil er ikke længere tilgængelig på denne enhed"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="8986903510053359694">"For mange mislykkede adgangskodeforsøg"</string>
     <string name="network_logging_notification_title" msgid="6399790108123704477">"Dette er en administreret enhed"</string>
-    <string name="network_logging_notification_text" msgid="7930089249949354026">"Din organisation administrerer denne enhed og kan overvåge netværkstrafik. Tryk for at se oplysninger."</string>
+    <string name="network_logging_notification_text" msgid="7930089249949354026">"Din organisation administrerer denne enhed og kan overvåge netværkstrafik. Tryk for at se info."</string>
     <string name="factory_reset_warning" msgid="5423253125642394387">"Enheden slettes"</string>
     <string name="factory_reset_message" msgid="9024647691106150160">"Administrationsappen kan ikke bruges. Enheden vil nu blive ryddet. \n\nKontakt din organisations administrator, hvis du har spørgsmål."</string>
     <string name="printing_disabled_by" msgid="8936832919072486965">"Udskrivning er deaktiveret af <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
@@ -249,7 +249,7 @@
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Taleassistent"</string>
     <string name="global_action_lockdown" msgid="1099326950891078929">"Lukning"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
-    <string name="notification_hidden_text" msgid="6351207030447943784">"Ny underretning"</string>
+    <string name="notification_hidden_text" msgid="6351207030447943784">"Ny notifikation"</string>
     <string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"Virtuelt tastatur"</string>
     <string name="notification_channel_physical_keyboard" msgid="7297661826966861459">"Fysisk tastatur"</string>
     <string name="notification_channel_security" msgid="7345516133431326347">"Sikkerhed"</string>
@@ -262,22 +262,22 @@
     <string name="notification_channel_network_available" msgid="4531717914138179517">"Tilgængeligt netværk"</string>
     <string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-status"</string>
     <string name="notification_channel_device_admin" msgid="1568154104368069249">"Enhedsadministration"</string>
-    <string name="notification_channel_alerts" msgid="4496839309318519037">"Underretninger"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"Notifikationer"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo til udstilling i butik"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-forbindelse"</string>
     <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"Appen kører"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"Apps, der bruger batteri"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> bruger batteri"</string>
     <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> apps bruger batteri"</string>
-    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tryk for at se oplysninger om batteri- og dataforbrug"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tryk for at se info om batteri- og dataforbrug"</string>
     <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
     <string name="user_owner_label" msgid="8836124313744349203">"Skift til personlig profil"</string>
     <string name="managed_profile_label" msgid="8947929265267690522">"Skift til arbejdsprofil"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakter"</string>
-    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"have adgang til dine kontaktpersoner"</string>
-    <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til dine kontaktpersoner?"</string>
+    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"have adgang til dine kontakter"</string>
+    <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til dine kontakter?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Placering"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"få adgang til enhedens placering"</string>
     <string name="permgrouprequest_location" msgid="3788275734953323491">"Vil du give &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; adgang til enhedens placering?"</string>
@@ -393,11 +393,11 @@
     <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Tillader, at appen kan sende klæbende udsendelser, der forbliver tilbage, når udsendelsen er slut. Overdreven brug kan gøre din tablet langsom eller ustabil ved at tvinge den til at bruge for meget hukommelse."</string>
     <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Giver appen lov til at sende klæbende udsendelser, som ikke forsvinder, når udsendelsen er slut. Overdreven brug kan gøre fjernsynet langsomt eller ustabilt ved at få det til at bruge for meget hukommelse."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Tillader, at appen kan sende klæbende udsendelser, der forbliver tilbage, når udsendelsen er slut. Overdreven brug kan gøre din telefon langsom eller ustabil ved at tvinge den til at bruge for meget hukommelse."</string>
-    <string name="permlab_readContacts" msgid="8348481131899886131">"læse dine kontaktpersoner"</string>
+    <string name="permlab_readContacts" msgid="8348481131899886131">"læse dine kontakter"</string>
     <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Tillader, at appen kan læse data om de kontakter, der er gemt på din tablet, f.eks. hvor ofte du har ringet til, sendt mail til eller på anden måde kommunikeret med bestemte personer. Med denne tilladelse kan apps gemme dine kontaktdata, og skadelige apps kan dele kontaktdata uden din viden."</string>
     <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Giver appen lov til at læse data om dine kontakter, der er gemt på dit tv, herunder hvor ofte du har ringet, mailet eller på andre måder kommunikeret med bestemte personer. Denne tilladelse gør det muligt for apps at gemme dine kontaktoplysninger, og ondsindede apps kan dele kontaktoplysninger uden din viden."</string>
     <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Tillader, at appen kan læse data om de kontakter, der er gemt på din telefon, f.eks. hvor ofte du har ringet til, sendt mail til eller på anden måde kommunikeret med bestemte personer. Med denne tilladelse kan apps gemme dine kontaktdata, og skadelige apps kan dele kontaktdata uden din viden."</string>
-    <string name="permlab_writeContacts" msgid="5107492086416793544">"ændre dine kontaktpersoner"</string>
+    <string name="permlab_writeContacts" msgid="5107492086416793544">"ændre dine kontakter"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Tillader, at appen kan ændre data om de kontakter, der er gemt på din tablet, f.eks. hvor ofte du har ringet til dem, sendt dem en mail eller på anden måde kommunikeret med bestemte kontakter. Med denne tilladelse kan apps slette kontaktoplysninger."</string>
     <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Giver appen lov til at ændre data om dine kontakter, der er gemt på dit tv, herunder hvor ofte du har ringet, mailet eller på anden måde kommunikeret med bestemte kontakter. Denne tilladelse gør det muligt for apps at slette kontaktoplysninger."</string>
     <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Tillader, at appen kan ændre data om de kontakter, der er gemt på din telefon, f.eks. hvor ofte du har ringet til dem, sendt en mail til dem eller på anden måde kommunikeret med bestemte kontakter. Med denne tilladelse kan apps slette kontaktoplysninger."</string>
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Tillader, at appen kan læse placeringer fra din mediesamling."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g>-appen kræver din godkendelse."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrisk hardware er ikke tilgængelig"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Godkendelsen blev annulleret"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Ikke genkendt"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Godkendelsen blev annulleret"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Der blev registreret et delvist fingeraftryk. Prøv igen."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Fingeraftrykket kunne ikke behandles. Prøv igen."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sensoren til registrering af fingeraftryk er beskidt. Tør den af, og prøv igen."</string>
@@ -624,10 +622,10 @@
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillader, at appen kan administrere netværkspolitikker og definere appspecifikke regler."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"skift afregning af netværksbrug"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillader, at appen kan ændre den måde, som netværksforbrug udregnes på i forhold til apps. Anvendes ikke af normale apps."</string>
-    <string name="permlab_accessNotifications" msgid="7673416487873432268">"adgang til underretninger"</string>
-    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, f.eks. dem, der er sendt af andre apps."</string>
-    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en underretningslyttertjeneste"</string>
-    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader brugeren at forpligte sig til en underretningslyttertjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
+    <string name="permlab_accessNotifications" msgid="7673416487873432268">"adgang til notifikationer"</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde notifikationer, f.eks. dem, der er sendt af andre apps."</string>
+    <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en notifikationslyttertjeneste"</string>
+    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader brugeren at forpligte sig til en notifikationslyttertjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"oprette binding til en tjeneste til formidling af betingelser"</string>
     <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Tillader, at brugeren opretter en binding til det øverste niveau af grænsefladen i en tjeneste til formidling af betingelser. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"fastlås til en drømmetjeneste"</string>
@@ -1098,7 +1096,7 @@
     <string name="sms" msgid="4560537514610063430">"Send besked"</string>
     <string name="sms_desc" msgid="7526588350969638809">"Send en besked til det valgte telefonnummer"</string>
     <string name="add_contact" msgid="7867066569670597203">"Tilføj"</string>
-    <string name="add_contact_desc" msgid="4830217847004590345">"Føj til kontaktpersoner"</string>
+    <string name="add_contact_desc" msgid="4830217847004590345">"Føj til kontakter"</string>
     <string name="view_calendar" msgid="979609872939597838">"Se"</string>
     <string name="view_calendar_desc" msgid="5828320291870344584">"Se det valgte tidspunkt i kalenderen"</string>
     <string name="add_calendar_event" msgid="1953664627192056206">"Planlæg"</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Åbn med"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Åbn med %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Åbn"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Giv adgang til at åbne <xliff:g id="HOST">%1$s</xliff:g>-link med"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Giv adgang til at åbne <xliff:g id="HOST">%1$s</xliff:g>-links med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Giv adgang"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Rediger med"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediger med %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Rediger"</string>
@@ -1214,19 +1215,19 @@
     <string name="volume_call" msgid="3941680041282788711">"Lydstyrke for opkald"</string>
     <string name="volume_bluetooth_call" msgid="2002891926351151534">"Lydstyrke for Bluetooth under opkald"</string>
     <string name="volume_alarm" msgid="1985191616042689100">"Lydstyrke for alarm"</string>
-    <string name="volume_notification" msgid="2422265656744276715">"Lydstyrke for underretninger"</string>
+    <string name="volume_notification" msgid="2422265656744276715">"Lydstyrke for notifikationer"</string>
     <string name="volume_unknown" msgid="1400219669770445902">"Lydstyrke"</string>
     <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"Lydstyrke for bluetooth"</string>
     <string name="volume_icon_description_ringer" msgid="3326003847006162496">"Lydstyrke for ringetone"</string>
     <string name="volume_icon_description_incall" msgid="8890073218154543397">"Lydstyrke for opkald"</string>
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Lydstyrke for medier"</string>
-    <string name="volume_icon_description_notification" msgid="7044986546477282274">"Lydstyrke for underretninger"</string>
+    <string name="volume_icon_description_notification" msgid="7044986546477282274">"Lydstyrke for notifikationer"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Standardringetone"</string>
     <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Standard (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Ringetoner"</string>
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarmlyde"</string>
-    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Underretningslyde"</string>
+    <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notifikationslyde"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Ukendt"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
       <item quantity="one">Tilgængelige Wi-Fi-netværk</item>
@@ -1436,10 +1437,10 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Hjælpefunktioner"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Baggrund"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Skift baggrund"</string>
-    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Underretningslytter"</string>
+    <string name="notification_listener_binding_label" msgid="2014162835481906429">"Notifikationslytter"</string>
     <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR-lyttefunktion"</string>
     <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Tjeneste til formidling af betingelser"</string>
-    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Tjeneste til rangering af underretninger"</string>
+    <string name="notification_ranker_binding_label" msgid="774540592299064747">"Tjeneste til rangering af notifikationer"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN er aktiveret."</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveres af <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="1610714069627824309">"Tryk for at administrere netværket."</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vil du besvare opkaldet?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Altid"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Kun én gang"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Indstillinger"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s understøtter ikke arbejdsprofil"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tv"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Hold begge lydstyrkeknapper nede i tre sekunder for at bruge <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1858,7 +1860,7 @@
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valgt</item>
     </plurals>
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Uden kategori"</string>
-    <string name="importance_from_user" msgid="7318955817386549931">"Du angiver, hvor vigtige disse underretninger er."</string>
+    <string name="importance_from_user" msgid="7318955817386549931">"Du angiver, hvor vigtige disse notifikationer er."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dette er vigtigt på grund af de personer, det handler om."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g> (der findes allerede en bruger med denne konto)?"</string>
@@ -1873,7 +1875,7 @@
     <string name="app_suspended_default_message" msgid="123166680425711887">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ikke tilgængelig lige nu. Dette administreres af <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
     <string name="app_suspended_more_details" msgid="1131804827776778187">"Få flere oplysninger"</string>
     <string name="work_mode_off_title" msgid="1118691887588435530">"Skal arbejdsprofilen slås til?"</string>
-    <string name="work_mode_off_message" msgid="5130856710614337649">"Dine arbejdsapps, underretninger, data og andre funktioner til din arbejdsprofil deaktiveres"</string>
+    <string name="work_mode_off_message" msgid="5130856710614337649">"Dine arbejdsapps, notifikationer, data og andre funktioner til din arbejdsprofil deaktiveres"</string>
     <string name="work_mode_turn_on" msgid="2062544985670564875">"Slå til"</string>
     <string name="deprecated_target_sdk_message" msgid="1449696506742572767">"Denne app er lavet til en ældre version af Android og fungerer muligvis ikke korrekt. Prøv at søge efter opdateringer, eller kontakt udvikleren."</string>
     <string name="deprecated_target_sdk_app_store" msgid="5032340500368495077">"Søg efter opdatering"</string>
@@ -1962,11 +1964,11 @@
     <string name="harmful_app_warning_title" msgid="8982527462829423432">"Der er registreret en skadelig app"</string>
     <string name="slices_permission_request" msgid="8484943441501672932">"<xliff:g id="APP_0">%1$s</xliff:g> anmoder om tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7867478911006447565">"Rediger"</string>
-    <string name="volume_dialog_ringer_guidance_vibrate" msgid="8902050240801159042">"Telefonen vil vibrere ved opkald og underretninger"</string>
-    <string name="volume_dialog_ringer_guidance_silent" msgid="2128975224280276122">"Der afspilles ikke lyd ved opkald og underretninger"</string>
+    <string name="volume_dialog_ringer_guidance_vibrate" msgid="8902050240801159042">"Telefonen vil vibrere ved opkald og notifikationer"</string>
+    <string name="volume_dialog_ringer_guidance_silent" msgid="2128975224280276122">"Der afspilles ikke lyd ved opkald og notifikationer"</string>
     <string name="notification_channel_system_changes" msgid="5072715579030948646">"Systemændringer"</string>
     <string name="notification_channel_do_not_disturb" msgid="6766940333105743037">"Forstyr ikke"</string>
-    <string name="zen_upgrade_notification_visd_title" msgid="3288313883409759733">"Nyhed! Forstyr ikke skjuler underretninger"</string>
+    <string name="zen_upgrade_notification_visd_title" msgid="3288313883409759733">"Nyhed! Forstyr ikke skjuler notifikationer"</string>
     <string name="zen_upgrade_notification_visd_content" msgid="5533674060311631165">"Tryk for at få flere oplysninger og foretage ændringer."</string>
     <string name="zen_upgrade_notification_title" msgid="3799603322910377294">"Tilstanden Forstyr ikke blev ændret"</string>
     <string name="zen_upgrade_notification_content" msgid="1794994264692424562">"Tryk for at se, hvad der er blokeret."</string>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"vises over andre apps på din skærm"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notifikation med oplysninger om rutinetilstand"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Enheden løber muligvis tør for batteri, inden du normalt oplader den"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batterisparefunktion er aktiveret for at forlænge batteritiden"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Indlæser"</string>
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 6087438..205b373 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Ermöglicht der App, Standorte aus deiner Mediensammlung abzurufen."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> möchte, dass du dich authentifizierst."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrische Hardware nicht verfügbar"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Authentifizierung abgebrochen"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nicht erkannt"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Authentifizierung abgebrochen"</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>
@@ -679,7 +677,7 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Anforderung, dass gespeicherte App-Daten verschlüsselt werden"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Kameras deaktivieren"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Nutzung sämtlicher Gerätekameras unterbinden"</string>
-    <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"Einige Funktionen der Displaysperre deaktivieren"</string>
+    <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"Displaysperre teilweise deaktivieren"</string>
     <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"Verwendung einiger Funktionen der Displaysperre verhindern"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Privat"</item>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Öffnen mit"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Mit %1$s öffnen"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Öffnen"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Zugriff zum Öffnen von <xliff:g id="HOST">%1$s</xliff:g>-Links erlauben"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Zugriff zum Öffnen von <xliff:g id="HOST">%1$s</xliff:g>-Links mit <xliff:g id="APPLICATION">%2$s</xliff:g> erlauben"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Zugriff erlauben"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Bearbeiten mit"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Mit %1$s bearbeiten"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Bearbeiten"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Anruf annehmen?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Immer"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Nur diesmal"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Einstellungen"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Das Arbeitsprofil wird von %1$s nicht unterstützt."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Halten Sie beide Lautstärketasten drei Sekunden lang gedrückt, um <xliff:g id="SERVICE_NAME">%1$s</xliff:g> zu verwenden"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"wird über anderen Apps auf dem Bildschirm angezeigt"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Infomitteilung zum Ablaufmodus"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Dein Akku könnte vor der gewöhnlichen Ladezeit leer sein"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Energiesparmodus aktiviert, um die Akkulaufzeit zu verlängern"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Wird geladen"</string>
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index f899309..e4e7a76 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Επιτρέπει στην εφαρμογή να διαβάσει τοποθεσίες από τη συλλογή πολυμέσων σας."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Η εφαρμογή <xliff:g id="APP">%s</xliff:g> επιθυμεί έλεγχο ταυτότητας."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Δεν υπάρχει διαθέσιμος βιομετρικός εξοπλισμός"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Ο έλεγχος ταυτότητας ακυρώθηκε"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Δεν αναγνωρίστηκε"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Ο έλεγχος ταυτότητας ακυρώθηκε"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Άνοιγμα με"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Άνοιγμα με %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Άνοιγμα"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Παραχώρηση πρόσβασης για το άνοιγμα συνδέσμων <xliff:g id="HOST">%1$s</xliff:g> με"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Παραχώρηση πρόσβασης για το άνοιγμα συνδέσμων <xliff:g id="HOST">%1$s</xliff:g> με την εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Παροχή πρόσβασης"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Επεξεργασία με"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Επεξεργασία με %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Επεξεργασία"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Αποδοχή κλήσης;"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Πάντα"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Μόνο μία φορά"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ρυθμίσεις"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Το προφίλ εργασίας δεν υποστηρίζεται από %1$s"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Τηλεόραση"</string>
@@ -1645,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"Πατήστε παρατεταμένα και τα δύο κουμπιά έντασης ήχου για τρία δευτερόλεπτα, ώστε να χρησιμοποιήσετε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Κάμερα"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Μικρόφωνο"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"εμφανίζεται πάνω σε άλλες εφαρμογές στην οθόνη σας"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Ειδοποίηση πληροφοριών λειτουργίας Ρουτίνας"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Η μπαταρία μπορεί να εξαντληθεί πριν από τη συνηθισμένη φόρτιση"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Η Εξοικονόμηση μπαταρίας ενεργοποιήθηκε για την επέκταση της διάρκειας ζωής της μπαταρίας"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Φόρτωση"</string>
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 7288a80..7dd3da2 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Allows the app to read locations from your media collection."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Application <xliff:g id="APP">%s</xliff:g> wants to authenticate."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometric hardware unavailable"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Authentication cancelled"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Authentication cancelled"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Partial fingerprint detected. Please try again."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Couldn\'t process fingerprint. Please try again."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerprint sensor is dirty. Please clean and try again."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"displaying over other apps on your screen"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Routine Mode info notification"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Battery may run out before usual charge"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Battery Saver activated to extend battery life"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Loading"</string>
 </resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 0481755..21f6f1f 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Allows the app to read locations from your media collection."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Application <xliff:g id="APP">%s</xliff:g> wants to authenticate."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometric hardware unavailable"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Authentication cancelled"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Authentication cancelled"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Partial fingerprint detected. Please try again."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Couldn\'t process fingerprint. Please try again."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerprint sensor is dirty. Please clean and try again."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"displaying over other apps on your screen"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Routine Mode info notification"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Battery may run out before usual charge"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Battery Saver activated to extend battery life"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Loading"</string>
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 7288a80..7dd3da2 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Allows the app to read locations from your media collection."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Application <xliff:g id="APP">%s</xliff:g> wants to authenticate."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometric hardware unavailable"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Authentication cancelled"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Authentication cancelled"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Partial fingerprint detected. Please try again."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Couldn\'t process fingerprint. Please try again."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerprint sensor is dirty. Please clean and try again."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"displaying over other apps on your screen"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Routine Mode info notification"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Battery may run out before usual charge"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Battery Saver activated to extend battery life"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Loading"</string>
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 7288a80..7dd3da2 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Allows the app to read locations from your media collection."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Application <xliff:g id="APP">%s</xliff:g> wants to authenticate."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometric hardware unavailable"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Authentication cancelled"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Authentication cancelled"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Partial fingerprint detected. Please try again."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Couldn\'t process fingerprint. Please try again."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerprint sensor is dirty. Please clean and try again."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Give access to open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"displaying over other apps on your screen"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Routine Mode info notification"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Battery may run out before usual charge"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Battery Saver activated to extend battery life"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Loading"</string>
 </resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 5d3b466..b4f1156d0 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1126,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‎‏‏‎‎Open with‎‏‎‎‏‎"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎Open with %1$s‎‏‎‎‏‎"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎‎‏‎Open‎‏‎‎‏‎"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎Give access to open ‎‏‎‎‏‏‎<xliff:g id="HOST">%1$s</xliff:g>‎‏‎‎‏‏‏‎ links with‎‏‎‎‏‎"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‏‎Give access to open ‎‏‎‎‏‏‎<xliff:g id="HOST">%1$s</xliff:g>‎‏‎‎‏‏‏‎ links with ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‏‏‎‏‏‎‏‏‎Give access‎‏‎‎‏‎"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‏‏‎‏‎‎‏‏‎‎‏‏‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‏‏‏‏‎Edit with‎‏‎‎‏‎"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‎Edit with %1$s‎‏‎‎‏‎"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎Edit‎‏‎‎‏‎"</string>
@@ -1564,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‎‎‏‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‎Accept call?‎‏‎‎‏‎"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‏‏‎‎‎‎‏‎‎‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‎‏‎Always‎‏‎‎‏‎"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎Just once‎‏‎‎‏‎"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎Settings‎‏‎‎‏‎"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‎%1$s doesn\'t support work profile‎‏‎‎‏‎"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‎‎‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎Tablet‎‏‎‎‏‎"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‎TV‎‏‎‎‏‎"</string>
@@ -1643,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‎‎Press and hold both volume keys for three seconds to use ‎‏‎‎‏‏‎<xliff:g id="SERVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</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>
@@ -1973,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‎‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎Camera‎‏‎‎‏‎"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‏‎‏‎‎‎‎‏‏‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‏‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎Microphone‎‏‎‎‏‎"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‎‎‏‎displaying over other apps on your screen‎‏‎‎‏‎"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‏‎‎‎Routine Mode info notification‎‏‎‎‏‎"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‎‏‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‏‎‎‏‏‎Battery may run out before usual charge‎‏‎‎‏‎"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎Battery Saver activated to extend battery life‎‏‎‎‏‎"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎Loading‎‏‎‎‏‎"</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index d369da5..dc0a132 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que la app lea las ubicaciones de tu colección de contenido multimedia."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"La aplicación de <xliff:g id="APP">%s</xliff:g> quiere autenticarte"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"No hay hardware biométrico disponible"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Se canceló la autenticación"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"No se reconoció"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Se canceló la autenticación"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"La huella digital se detectó parcialmente. Vuelve a intentarlo."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"No se pudo procesar la huella digital. Vuelve a intentarlo."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"El sensor de huellas digitales está sucio. Limpia el sensor y vuelve a intentarlo."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Otorgar acceso para abrir vínculos de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Otorgar acceso para abrir vínculos de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Otorgar acceso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una vez"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuración"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admite perfiles de trabajo."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Mantén presionadas ambas teclas de volumen durante tres segundos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Cámara"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micrófono"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"se superpone a otras apps en tu pantalla"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificación de información del modo de Rutinas"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Es posible que la batería se agote antes de la carga habitual"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Se activó el Ahorro de batería para extender la duración de la batería"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Cargando"</string>
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 9174248..c819bb6 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que la aplicación lea las ubicaciones de tu colección de contenido multimedia."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> solicita tu autenticación."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biométrico no disponible"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autenticación cancelada"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"No se reconoce"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autenticación cancelada"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Se ha detectado una huella digital parcial. Vuelve a intentarlo."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"No se ha podido procesar la huella digital. Vuelve a intentarlo."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"El sensor de huellas digitales está sucio. Límpialo y vuelve a intentarlo."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Permitir acceso para abrir enlaces de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Permitir acceso para abrir enlaces de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Permitir acceso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Cambiar"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una vez"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ajustes"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admite perfiles de trabajo"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Para utilizar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, mantén pulsadas ambas teclas de volumen durante 3 segundos"</string>
     <string name="accessibility_button_prompt_text" msgid="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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Cámara"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micrófono"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"se muestra sobre otras aplicaciones que haya en la pantalla"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificación sobre el modo rutina"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Es posible que te quedes sin batería antes de lo habitual"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Se ha activado el ahorro de batería para aumentar la duración de la batería"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Cargando"</string>
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index f20b35f..f1c4106 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Võimaldab rakendusel lugeda teie meediakogus olevaid asukohti."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Rakendus <xliff:g id="APP">%s</xliff:g> soovib autentimist."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biomeetriline riistvara ei ole saadaval"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autentimine tühistati"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Ei tuvastatud"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autentimine tühistati"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Tuvastati osaline sõrmejälg. Proovige uuesti."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Sõrmejälge ei õnnestunud töödelda. Proovige uuesti."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sõrmejäljeandur on must. Puhastage see ja proovige uuesti."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Avamine:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Avamine rakendusega %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ava"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Juurdepääsu andmine, et avada üksuse <xliff:g id="HOST">%1$s</xliff:g> lingid"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Juurdepääsu andmine, et avada üksuse <xliff:g id="HOST">%1$s</xliff:g> lingid rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Juudep. andmine"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Muutmine:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Muutmine rakendusega %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Muuda"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Kas vastata kõnele?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alati"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Ainult üks kord"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Seaded"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ei toeta tööprofiili"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tahvelarvuti"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Teler"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kasutamiseks hoidke kolm sekundit all mõlemat helitugevuse klahvi"</string>
     <string name="accessibility_button_prompt_text" msgid="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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kaamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"teie ekraanil muude rakenduste peal kuvamine"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Rutiinirežiimi teabe märguanne"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Aku võib enne tavapärast laadimist tühjaks saada"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Akusäästja aktiveeriti aku tööea pikendamiseks"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Laadimine"</string>
 </resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 153eeae..c361164 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Multimedia-edukien bildumako kokapena irakurtzea baimentzen die aplikazioei."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> aplikazioak autentifikatu egin nahi du."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biometrikoa ez dago erabilgarri"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Utzi da autentifikazioa"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Ez da ezagutu"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Utzi egin da autentifikazioa"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Hatz-marka digitala ez da osorik hauteman. Saiatu berriro."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Ezin izan da prozesatu hatz-marka. Saiatu berriro."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Hatz-marka digitalen sentsorea zikina dago. Garbi ezazu, eta saiatu berriro."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Ireki honekin:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Irekin %1$s aplikazioarekin"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ireki"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Eman <xliff:g id="HOST">%1$s</xliff:g> estekak irekitzeko baimena aplikazio honi:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Eman <xliff:g id="APPLICATION">%2$s</xliff:g> aplikazioari <xliff:g id="HOST">%1$s</xliff:g> irekitzeko baimena"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Eman sarbidea"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editatu honekin:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editatu %1$s aplikazioarekin"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editatu"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Deia onartu nahi duzu?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Beti"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Behin soilik"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ezarpenak"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s abiarazleak ez du laneko profil hau onartzen"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tableta"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Telebista"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> erabiltzeko, eduki sakatuta bolumen-tekla biak hiru segundoz"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofonoa"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"pantailako beste aplikazioen gainean bistaratzen"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Ohitura moduaren informazio-jakinarazpena"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Baliteke bateria ohi baino lehenago agortzea"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Bateria-aurrezlea aktibatuta dago bateriaren iraupena luzatzeko"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Kargatzen"</string>
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 76845c8..5bf81fa 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"به برنامه اجازه می‌دهد مکان‌ها را از مجموعه رسانه‌تان بخواند."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"برنامه <xliff:g id="APP">%s</xliff:g> می‌خواهد احراز هویت کند."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"سخت‌افزار زیست‌سنجی دردسترس نیست"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"احراز هویت لغو شد"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"شناسایی نشد"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"احراز هویت لغو شد"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"باز کردن با"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏باز کردن با %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"باز کردن"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ارائه دسترسی برای باز کردن پیوندهای <xliff:g id="HOST">%1$s</xliff:g> با"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"ارائه دسترسی برای باز کردن پیوندهای <xliff:g id="HOST">%1$s</xliff:g> با<xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ارائه دسترسی"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ویرایش با"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏ویرایش با %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ویرایش"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"تماس را می‌پذیرید؟"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"همیشه"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"فقط این بار"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"تنظیمات"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏%1$s از نمایه کاری پشتیبانی نمی‌کند"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"رایانهٔ لوحی"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"تلویزیون"</string>
@@ -1645,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"برای استفاده از <xliff:g id="SERVICE_NAME">%1$s</xliff:g>، هر دو کلید صدا را فشار دهید و سه ثانیه نگه دارید"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"دوربین"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"میکروفون"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"نمایش روی برنامه‌های دیگر در صفحه‌نمایش"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"اعلان اطلاعات حالت روال معمول"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"ممکن است شارژ باتری قبل از شارژ معمول تمام شود"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"جهت افزایش عمر باتری، بهینه‌سازی باتری فعال شد"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"درحال بارگیری"</string>
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 16c96cc..9e2fde5 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Antaa sovelluksen lukea mediakokoelmasi sijainteja."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> pyytää todentamista"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrinen laitteisto ei käytettävissä"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Todennus peruutettu"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Ei tunnistettu"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Todennus peruutettu"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Sormenjälki havaittiin vain osittain. Yritä uudelleen."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Sormenjäljen käsittely epäonnistui. Yritä uudelleen."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sormenjälkitunnistin on likainen. Puhdista tunnistin ja yritä uudelleen."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Avaa sovelluksessa"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Avaa sovelluksessa %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Avaa"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Salli linkkien (<xliff:g id="HOST">%1$s</xliff:g>) avaaminen:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Salli linkkien (<xliff:g id="HOST">%1$s</xliff:g>) avaaminen: <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Salli"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Muokkaa sovelluksessa"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Muokkaa sovelluksessa %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Muokkaa"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vastataanko puheluun?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Aina"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Vain kerran"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Asetukset"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ei tue työprofiilia"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tabletti"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televisio"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Voit käyttää palvelua <xliff:g id="SERVICE_NAME">%1$s</xliff:g> painamalla molempia äänenvoimakkuuspainikkeita kolmen sekunnin ajan"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofoni"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"näkyy näytöllä muiden sovellusten päällä"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Ohjelmatilan tietoilmoitus"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Akku saattaa loppua ennen normaalia latausaikaa"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Virransäästö otettu käyttöön akunkeston pidentämiseksi"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Ladataan"</string>
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 6fb1f12..3b841d5 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Autorise l\'application à lire les positions indiquées dans votre collection multimédia."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> vous demande de vous authentifier."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Matériel biométrique indisponible"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Authentification annulée"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Données biométriques non reconnues"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Authentification annulée"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Empreinte digitale partielle détectée. Veuillez essayer de nouveau."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Impossible de traiter les empreintes digitales. Veuillez essayer de nouveau."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Le capteur d\'empreintes digitales est sale. Veuillez le nettoyer et essayer de nouveau."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Ouvrir avec"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Ouvrir avec %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ouvrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Accorder l\'accès pour ouvrir les liens de <xliff:g id="HOST">%1$s</xliff:g> avec"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Accorder l\'accès pour ouvrir les liens de <xliff:g id="HOST">%1$s</xliff:g> avec <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Accorder l\'accès"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Modifier avec"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifier avec %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Modifier"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prendre l\'appel?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Toujours"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Une seule fois"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Paramètres"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne prend pas en charge le profil professionnel"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablette"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Télévision"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Maintenez enfoncées les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Appareil photo"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microphone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"superpose du contenu par-dessus d\'autres applications à l\'écran"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notification d\'information du mode Routine"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"La pile pourrait s\'épuiser avant la charge habituelle"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Le mode Économiseur de pile est activé afin de prolonger l\'autonomie"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Chargement en cours…"</string>
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index fa8c7f0..28df3bf 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Autorise l\'application à consulter des positions issues de votre bibliothèque multimédia."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"L\'application <xliff:g id="APP">%s</xliff:g> veut vous authentifier."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Matériel biométrique indisponible"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Authentification annulée"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Non reconnu"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Authentification annulée"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Empreinte numérique partiellement détectée. Veuillez réessayer."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Impossible de reconnaître l\'empreinte numérique. Veuillez réessayer."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Le lecteur d\'empreintes numériques est sale. Veuillez le nettoyer, puis réessayer."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Ouvrir avec"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Ouvrir avec %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ouvrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Autoriser l\'ouverture des liens <xliff:g id="HOST">%1$s</xliff:g> avec"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Autoriser l\'ouverture des liens <xliff:g id="HOST">%1$s</xliff:g> avec <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Accorder l\'accès"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Modifier avec"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifier avec %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Modifier"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prendre l\'appel ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Toujours"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Une seule fois"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Paramètres"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s n\'est pas compatible avec le profil professionnel."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablette"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Téléviseur"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Appuyez de manière prolongée sur les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Caméra"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micro"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"se superpose aux autres applications sur l\'écran"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notification d\'information du mode Routine"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Vous risquez d\'être à court de batterie plus tôt que prévu"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Économiseur de batterie activé pour prolonger l\'autonomie"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Chargement…"</string>
 </resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 2c9b09d..339f0f4f 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -32,7 +32,7 @@
     <string name="unknownName" msgid="6867811765370350269">"Descoñecido"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Correo de voz"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
-    <string name="mmiError" msgid="5154499457739052907">"Problema de conexión ou código MMI non válido."</string>
+    <string name="mmiError" msgid="5154499457739052907">"Problema de conexión ou código MMI non-válido."</string>
     <string name="mmiFdnError" msgid="5224398216385316471">"A operación está restrinxida a números de marcación fixa."</string>
     <string name="mmiErrorWhileRoaming" msgid="762488890299284230">"Non se pode cambiar a configuración do desvío de chamadas desde o teléfono mentres estás en itinerancia."</string>
     <string name="serviceEnabled" msgid="8147278346414714315">"Activouse o servizo."</string>
@@ -150,7 +150,7 @@
     <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: non desviada"</string>
     <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: non reenviada"</string>
     <string name="fcComplete" msgid="3118848230966886575">"Código de función completo"</string>
-    <string name="fcError" msgid="3327560126588500777">"Problema de conexión ou código de función non válido"</string>
+    <string name="fcError" msgid="3327560126588500777">"Problema de conexión ou código de función non-válido"</string>
     <string name="httpErrorOk" msgid="1191919378083472204">"Aceptar"</string>
     <string name="httpError" msgid="7956392511146698522">"Produciuse un erro na rede."</string>
     <string name="httpErrorLookup" msgid="4711687456111963163">"Non se puido atopar o URL."</string>
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que a aplicación lea as localizacións da túa colección multimedia."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"A aplicación <xliff:g id="APP">%s</xliff:g> quere que te autentiques."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"O hardware biométrico non está dispoñible"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Cancelouse a autenticación"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Non se recoñeceu"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Cancelouse a autenticación"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Detectouse unha impresión dixital parcial. Téntao de novo."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Non se puido procesar a impresión dixital. Téntao de novo."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"O sensor de impresión dixital está sucio. Límpao e téntao de novo."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Conceder acceso para abrir ligazóns de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Conceder acceso para abrir ligazóns de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acceso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceptar chamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Só unha vez"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuración"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s non admite o perfil de traballo"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tableta"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televisión"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Mantén premidas as teclas do volume durante tres segudos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Cámara"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micrófono"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"mostrando outras aplicacións na pantalla"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificación da información do modo de rutina"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"A batería pode esgotarse antes do habitual"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Para ampliar a duración da batería activouse a función Aforro de batería"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Cargando"</string>
 </resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index da8a6e5..2124759 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"એપને તમારા મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવાની મંજૂરી આપે છે."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> ઍપ પ્રમાણીકરણ કરવા માગે છે."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"બાયોમેટ્રિક હાર્ડવેર ઉપલબ્ધ નથી"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"પ્રમાણીકરણ રદ કર્યું"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ઓળખાયેલ નથી"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"પ્રમાણીકરણ રદ કર્યું"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"આની સાથે ખોલો"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s સાથે ખોલો"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ખોલો"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"આના વડે <xliff:g id="HOST">%1$s</xliff:g>ની લિંક ખોલવા માટે ઍક્સેસ આપો"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> વડે <xliff:g id="HOST">%1$s</xliff:g>ની લિંક ખોલવા માટે ઍક્સેસ આપો"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ઍક્સેસ આપો"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"આનાથી સંપાદિત કરો"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s સાથે સંપાદિત કરો"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"સંપાદિત કરો"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"કૉલ સ્વીકારીએ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"હંમેશા"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ફક્ત એક વાર"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"સેટિંગ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s કાર્ય પ્રોફાઇલનું સમર્થન કરતું નથી"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ટેબ્લેટ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>નો ઉપયોગ કરવા માટે બન્ને વૉલ્યૂમ કીને ત્રણ સેકન્ડ સુધી દબાવી રાખો"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"કૅમેરા"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"માઇક્રોફોન"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"આ તમારી સ્ક્રીન પર અન્ય ઍપની ઉપર દેખાશે"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"રૂટિન મોડની માહિતીનું નોટિફિકેશન"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"સામાન્ય રીતે ચાર્જ કરવાના સમય પહેલાં બૅટરી સમાપ્ત થઈ શકે છે"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"બૅટરી આવરદા વધારવા માટે બૅટરી સેવર ચાલુ કર્યું"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"લોડિંગ"</string>
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 4349c09..db89c3e 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"इससे ऐप्लिकेशन को आपके मीडिया संग्रह से जगह की जानकारी एक्सेस करने की अनुमति दी जाती है."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"ऐप्लिकेशन <xliff:g id="APP">%s</xliff:g> पुष्टि करना चाहता है."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"बायोमेट्रिक हार्डवेयर उपलब्ध नहीं है"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"प्रमाणीकरण रद्द किया गया"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"पहचान नहीं हो पाई"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"प्रमाणीकरण रद्द किया गया"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"इसमें खोलें"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s में खोलें"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"खोलें"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"इससे <xliff:g id="HOST">%1$s</xliff:g> लिंक खोलने का एक्सेस दें"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> से <xliff:g id="HOST">%1$s</xliff:g> लिंक खोलने का एक्सेस दें"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"एक्सेस दें"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"इसके ज़रिये बदलाव करें"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s की मदद से बदलाव करें"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"बदलाव करें"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"कॉल स्वीकार करें?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"हमेशा"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"केवल एक बार"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिंग"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s कार्य प्रोफ़ाइल का समर्थन नहीं करता"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"टैबलेट"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"टीवी"</string>
@@ -1645,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> इस्तेमाल करने के लिए आवाज़ वाले दोनों बटन तीन सेकंड तक दबाकर रखें"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"कैमरा"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"माइक्रोफ़ोन"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"आपकी स्क्रीन पर, इस्तेमाल हो रहे दूसरे ऐप्लिकेशन के ऊपर दिखाया जा रहा है"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"रूटीन मोड जानकारी की सूचना"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"बैटरी आम तौर पर जितने समय चलती है, उससे पहले खत्म हो सकती है"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"बैटरी लाइफ़ बढ़ाने के लिए \'बैटरी सेवर\' चालू हो गया है"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"प्राेफ़ाइल लोड हो रही है"</string>
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 2747521..4cd699b 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -536,11 +536,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Omogućuje aplikaciji čitanje lokacija iz vaše medijske zbirke."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Aplikacija <xliff:g id="APP">%s</xliff:g> traži autentifikaciju."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrijski hardver nije dostupan"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autentifikacija otkazana"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autentifikacija otkazana"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je djelomični otisak prsta. Pokušajte ponovo."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Obrada otiska prsta nije uspjela. Pokušajte ponovo."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor otiska prsta nije čist. Očistite ga i pokušajte ponovo."</string>
@@ -1148,6 +1146,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otvaranje pomoću aplikacije"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvaranje pomoću aplikacije %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Omogućite pristup za otvaranje <xliff:g id="HOST">%1$s</xliff:g> veza pomoću aplikacije"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Omogućite pristup za otvaranje <xliff:g id="HOST">%1$s</xliff:g> veza pomoću aplikacije <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Omogući pristup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Uređivanje pomoću aplikacije"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uređivanje pomoću aplikacije %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Uredi"</string>
@@ -1589,6 +1590,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prihvatiti poziv?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvijek"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo jednom"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Postavke"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava radni profil"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tabletno računalo"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televizor"</string>
@@ -1669,7 +1671,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Pritisnite i zadržite tipke za glasnoću na tri sekunde da biste koristili uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -2010,5 +2012,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparat"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"prikazuje se preko drugih aplikacija na zaslonu"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Obavještavanje o informacijama u Rutinskom načinu rada"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Baterija se može isprazniti prije uobičajenog vremena punjenja"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Štednja baterije aktivirana je kako bi se produljilo trajanje baterije"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Učitavanje"</string>
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 10538f4..3d2ed09 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Engedélyezi az alkalmazásnak a helyek médiagyűjteményből való olvasását."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"A(z) <xliff:g id="APP">%s</xliff:g> alkalmazás hitelesítést kér."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrikus hardver nem áll rendelkezésre"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Hitelesítés megszakítva"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nem ismerhető fel"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Hitelesítés megszakítva"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"A rendszer az ujjlenyomatnak csak egy részletét érzékelte. Próbálkozzon újra."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nem sikerült feldolgozni az ujjlenyomatot. Próbálkozzon újra."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Az ujjlenyomat-olvasó koszos. Tisztítsa meg, majd próbálkozzon újra."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Megnyitás a következővel:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Megnyitás a következővel: %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Megnyitás"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Engedély megadása, hogy a(z) <xliff:g id="HOST">%1$s</xliff:g> linkek a következő alkalmazásban nyíljanak meg:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Engedély megadása, hogy a(z) <xliff:g id="HOST">%1$s</xliff:g> linkek a következő alkalmazásban nyíljanak meg: <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Engedély adása"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Szerkesztés a következővel:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Szerkesztés a következővel: %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Szerkesztés"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Fogadja a hívást?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Mindig"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Csak egyszer"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Beállítások"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"A(z) %1$s nem támogatja a munkaprofilokat."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Táblagép"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"A(z) <xliff:g id="SERVICE_NAME">%1$s</xliff:g> használatához tartsa lenyomva három másodpercig a két hangerőgombot"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"megjelenítés a képernyőn lévő egyéb alkalmazások előtt"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Információs értesítés a rutinmódról"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Előfordulhat, hogy az akkumulátor lemerül a szokásos töltési időszak előtt"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Akkumulátorkímélő mód aktiválva az akkumulátor üzemidejének növelése érdekében"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Betöltés"</string>
 </resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index fbb5f4b..e873140 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Թույլ է տալիս հավելվածին ճանաչել տեղադրության մասին տվյալները ձեր մեդիա բովանդակության հավաքածուից:"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> հավելվածը նույնականացում է հարցում"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Կենսաչափական սարքը հասանելի չէ"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Նույնականացումը չեղարկվեց"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Չհաջողվեց ճանաչել"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Նույնականացումը չեղարկվեց"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Բացել հետևյալ ծրագրով՝"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Բացել ծրագրով՝ %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Բացել"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Թույլատրեք, որ <xliff:g id="HOST">%1$s</xliff:g> տիրույթը հղումները բացվեն հետևյալ հավելվածում՝"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Թույլատրեք, որ <xliff:g id="HOST">%1$s</xliff:g> տիրույթի հղումները բացվեն <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածում"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Թույլատրել"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Խմբագրել հետևյալ ծրագրով՝"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Խմբագրել հետևյալով՝ %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Փոփոխել"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Ընդունե՞լ զանգը:"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Միշտ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Միայն մեկ անգամ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Կարգավորումներ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s-ը չի աջակցում աշխատանքային պրոֆիլներ"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Գրասալիկ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Հեռուստացույց"</string>
@@ -1645,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"«<xliff:g id="SERVICE_NAME">%1$s</xliff:g>» ծառայությունն օգտագործելու համար սեղմեք և 3 վայրկյան պահեք ձայնի ուժգնության երկու կոճակները"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Տեսախցիկ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Խոսափող"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ցուցադրվում է մյուս հավելվածների վերևում"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Ծանուցում լիցքավորման մասին"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Մարտկոցի լիցքը կարող է սովորականից շուտ սպառվել"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Մարտկոցի կյանքը երկարացնելու համար ակտիվացվել է մարտկոցի տնտեսման ռեժիմը"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Բեռնում"</string>
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 3c6e347..299305f 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Mengizinkan aplikasi untuk membaca lokasi dari koleksi media Anda."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Aplikasi <xliff:g id="APP">%s</xliff:g> meminta autentikasi."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biometrik tidak tersedia"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autentikasi dibatalkan"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Tidak dikenali"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autentikasi dibatalkan"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Sebagian sidik jari terdeteksi. Coba lagi."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Tidak dapat memproses sidik jari. Coba lagi."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sensor sidik jari kotor. Bersihkan dan coba lagi."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Buka dengan"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buka dengan %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buka"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Berikan akses untuk membuka link <xliff:g id="HOST">%1$s</xliff:g> dengan"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Berikan akses untuk membuka link <xliff:g id="HOST">%1$s</xliff:g> dengan <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Berikan akses"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit dengan"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit dengan %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Selalu"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Hanya sekali"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Setelan"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s tidak mendukung profil kerja"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Tekan dan tahan kedua tombol volume selama tiga detik untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ditampilkan di atas aplikasi lain di layar"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notifikasi info Mode Rutinitas"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Baterai mungkin habis sebelum pengisian daya biasanya"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Penghemat Baterai diaktifkan untuk memperpanjang masa pakai baterai"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Memuat"</string>
 </resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index f638ff8..94030bb 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Leyfir forritinu að lesa staðsetningar úr efnissafninu þínu."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> forritið vill staðfestingu."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Lífkennavélbúnaður ekki tiltækur"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Hætt við auðkenningu"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Þekktist ekki"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Hætt við auðkenningu"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Hluti fingrafars greindist. Reyndu aftur."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Ekki var hægt að vinna úr fingrafarinu. Reyndu aftur."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingrafaraskynjarinn er óhreinn. Hreinsaðu hann og reyndu aftur."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Opna með"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Opna með %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Opna"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Veita aðgang til að opna <xliff:g id="HOST">%1$s</xliff:g> tengla með"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Veita aðgang til að opna <xliff:g id="HOST">%1$s</xliff:g> tengla með <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Veita aðgang"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Breyta með"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Breyta með %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Breyta"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Samþykkja símtal?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltaf"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Bara einu sinni"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Stillingar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s styður ekki vinnusnið"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Spjaldtölva"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Sjónvarp"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Haltu báðum hljóðstyrkstökkunum inni í þrjár sekúndur til að nota <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Myndavél"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Hljóðnemi"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"birt yfir öðrum forritum á skjánum"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Upplýsingatilkynning aðgerðastillingar"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Rafhlaðan kann að tæmast áður en hún kemst í hleðslu"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Kveikt á rafhlöðusparnaði til að lengja endingu rafhlöðunnar"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Hleður"</string>
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index c9c8f0c..3be8acb 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Consente all\'app di leggere le posizioni dalla tua raccolta multimediale."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"L\'app <xliff:g id="APP">%s</xliff:g> richiede l\'autenticazione."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biometrico non disponibile"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autenticazione annullata"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Non riconosciuto"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autenticazione annullata"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Rilevata impronta digitale parziale. Riprova."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Impossibile elaborare l\'impronta digitale. Riprova."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Il sensore di impronte digitali è sporco. Puliscilo e riprova."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Apri con"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Apri con %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Apri"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Dai l\'accesso per aprire i link di <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Dai l\'accesso per aprire i link di <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Fornisci accesso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Modifica con"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifica con %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Modifica"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Accettare la chiamata?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una volta"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Impostazioni"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s non supporta il profilo di lavoro"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Tieni premuti entrambi i tasti del volume per tre secondi per utilizzare <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotocamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfono"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"si sovrappone ad altre app sullo schermo"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notifica di informazioni sulla modalità Routine"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"La batteria potrebbe esaurirsi prima della ricarica abituale"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Risparmio energetico attivo per far durare di più la batteria"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Caricamento"</string>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 26f6988f..d3cdd09 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -539,11 +539,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"מאפשרת לאפליקציה לקרוא מיקומים מאוסף המדיה שלך."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"האפליקציה <xliff:g id="APP">%s</xliff:g> רוצה לבצע אימות."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"חומרה ביומטרית לא זמינה"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"האימות בוטל"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"לא זוהתה"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"האימות בוטל"</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>
@@ -1168,6 +1166,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"פתח באמצעות"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏פתח באמצעות %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"פתח"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"הענקת גישה לפתיחת קישורים של <xliff:g id="HOST">%1$s</xliff:g> באמצעות"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"הענקת גישה לפתיחת קישורים של <xliff:g id="HOST">%1$s</xliff:g> באמצעות <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"הענקת גישה"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ערוך באמצעות"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏ערוך באמצעות %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"עריכה"</string>
@@ -1612,6 +1613,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"האם לקבל את השיחה?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"תמיד"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"רק פעם אחת"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"הגדרות"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏%1$s אינו תומך בפרופיל עבודה"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"טאבלט"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"טלוויזיה"</string>
@@ -1693,7 +1695,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_shortcut_spoken_feedback" msgid="8376923232350078434">"יש ללחוץ לחיצה ארוכה על שני לחצני עוצמת הקול למשך שלוש שניות כדי להשתמש בשירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -2045,5 +2047,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"מצלמה"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"מיקרופון"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"תצוגה מעל אפליקציות אחרות במסך"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"התראת מידע לגבי מצב שגרתי"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"הסוללה עלולה להתרוקן לפני המועד הרגיל של הטעינה"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"תכונת החיסכון בסוללה הופעלה כדי להאריך את חיי הסוללה"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"בטעינה"</string>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 45587cb..583ed78 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"メディア コレクションの位置情報の読み取りをアプリに許可します。"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"アプリ <xliff:g id="APP">%s</xliff:g> が認証を求めています。"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"生体認証ハードウェアが利用できません"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"認証をキャンセルしました"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"認識されませんでした"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"認証をキャンセルしました"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"アプリで開く"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sで開く"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"開く"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> のリンクを開くには、アクセス権を付与してください"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> で <xliff:g id="HOST">%1$s</xliff:g> のリンクを開くには、アクセス権を付与してください"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"アクセス権を付与"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"編集に使用"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sで編集"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"編集"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"通話を受けますか?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"常時"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"1回のみ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$sは仕事用プロファイルをサポートしていません"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"タブレット"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"テレビ"</string>
@@ -1645,7 +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> は 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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> を使用するには、音量大と音量小の両方のボタンを 3 秒間長押ししてください"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"カメラ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"マイク"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"画面の他のアプリの上に重ねて表示"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"ルーティン モード情報の通知"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"通常の充電を行う前に電池が切れる可能性があります"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"電池を長持ちさせるため、バッテリー セーバーが有効になりました"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"読み込んでいます"</string>
 </resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 07df9fc..2356fd4 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"აპი შეძლებს მდებარეობების გაცნობას თქვენი მედიაკოლექციიდან."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"აპლიკაცია <xliff:g id="APP">%s</xliff:g> ითხოვს ავტორიზაციას."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ბიომეტრიული აპარატურა მიუწვდომელია"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ავტორიზაცია გაუქმდა"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"არ არის ამოცნობილი"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"ავტორიზაცია გაუქმდა"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"გახსნა აპით"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s-ით გახსნა"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"გახსნა"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> ბმულების შემდეგი აპით გახსნის წვდომის მინიჭება:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g> ბმულების <xliff:g id="APPLICATION">%2$s</xliff:g>-ით გახსნის წვდომის მინიჭება"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"წვდომის მინიჭება"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"რედაქტირება აპით:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"რედაქტირება %1$s-ით"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"რედაქტირება"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"უპასუხებთ ზარს?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ყოველთვის"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"მხოლოდ ერთხელ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"პარამეტრები"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s მხარს არ უჭერს სამუშაო პროფილს"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ტაბლეტი"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ტელევიზია"</string>
@@ -1645,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> რომ გამოიყენოთ, დააჭირეთ ხმის ორივე ღილაკზე 3 წამის განმავლობაში"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"კამერა"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"მიკროფონი"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"სხვა აპების გადაფარვით ჩანს თქვენს ეკრანზე"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"რუტინის რეჟიმის საინფორმაციო შეტყობინება"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"ბატარეა შეიძლება დაჯდეს დატენის ჩვეულ დრომდე"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"ბატარეის დამზოგი გააქტიურდა ბატარეის მუშაობის გასახანგრძლივლებლად"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"იტვირთება"</string>
 </resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index c622094..f714ebe 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Қолданбаға медиамазмұн жинағынан геодеректерді оқуға мүмкіндік береді."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> қолданбасына аутентификация қажет."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометрикалық жабдық жоқ"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Аутентификациядан бас тартылды."</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Танылмады"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Аутентификациядан бас тартылды."</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Басқаша ашу"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s қолданбасымен ашу"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ашу"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> сілтемелерін келесі қолданбамен ашу үшін рұқсат беру:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g> сілтемелерін <xliff:g id="APPLICATION">%2$s</xliff:g> қолданбасымен ашу үшін рұқсат беру"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Рұқсат беру"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Келесімен өңдеу"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s көмегімен өңдеу"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Өңдеу"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Қоңырауды қабылдау?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Үнемі"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Бір рет қана"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Параметрлер"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s жұмыс профилін қолдамайды"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшет"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ТД"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін пайдалану үшін дыбыс деңгейін реттейтін екі түймені де 3 секунд басып тұрыңыз"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"экранда басқа қолданбалардың үстінен көрсету"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Режим туралы хабарландыру"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Батарея заряды азаюы мүмкін"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Батарея ұзаққа жетуі үшін, Battery Saver іске қосылды"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Жүктелуде"</string>
 </resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index ccc243d..aa1adc8 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"អនុញ្ញាតឱ្យ​កម្មវិធី​អាន​ទីតាំង​ពីបណ្ដុំ​មេឌៀ​របស់​អ្នក។"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"កម្មវិធី <xliff:g id="APP">%s</xliff:g> ចង់​ធ្វើ​កា​រផ្ទៀងផ្ទាត់។"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"មិនអាច​ប្រើឧបករណ៍​ស្កេន​ស្នាមម្រាមដៃ​បានទេ"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"បាន​បោះបង់​ការ​ផ្ទៀងផ្ទាត់"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"មិនអាចសម្គាល់បានទេ"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"បាន​បោះបង់​ការ​ផ្ទៀងផ្ទាត់"</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>
@@ -1130,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"បើក​ជា​មួយ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"បើក​ជាមួយ %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"បើក"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ផ្ដល់​សិទ្ធិ​ចូលប្រើ ដើម្បី​បើកតំណ <xliff:g id="HOST">%1$s</xliff:g> តាមរយៈ"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"ផ្ដល់​សិទ្ធិ​ចូល​ប្រើ ដើម្បី​បើកតំណ <xliff:g id="HOST">%1$s</xliff:g> តាមរយៈ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ផ្តល់​សិទ្ធិ​ចូល​ប្រើ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"កែសម្រួល​ជាមួយ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"កែសម្រួល​ជាមួយ​ %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"កែសម្រួល"</string>
@@ -1568,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ទទួល​ការ​ហៅ​?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ជា​និច្ច"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"តែ​ម្ដង"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ការកំណត់"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s មិន​គាំទ្រ​ប្រវត្តិរូប​ការងារ"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"កុំព្យូទ័រ​បន្ទះ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ទូរទស្សន៍"</string>
@@ -1647,7 +1649,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_shortcut_spoken_feedback" msgid="8376923232350078434">"ចុចគ្រាប់ចុច​កម្រិត​សំឡេងទាំងពីរ​ឱ្យជាប់រយៈពេលបីវិនាទី ដើម្បីប្រើ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1977,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"កាមេរ៉ា"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"មីក្រូហ្វូន"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"កំពុងបង្ហាញ​ពីលើកម្មវិធីផ្សេងទៀត​នៅលើអេក្រង់​របស់អ្នក"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"ការ​ជូនដំណឹង​ព័ត៌មាន​របស់​មុខងារ​ទម្លាប់"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"ថ្ម​អាច​នឹង​អស់ មុនពេល​សាកថ្មធម្មតា"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"បាន​បើក​ដំណើរការកម្មវិធី​សន្សំ​ថ្ម ដើម្បីបង្កើនកម្រិត​ថាមពល​​ថ្ម"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"កំពុងផ្ទុក"</string>
 </resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 835070a..f33e297 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ನಿಮ್ಮ ಮೀಡಿಯಾ ಸಂಗ್ರಹಣೆಯಿಂದ ಸ್ಥಳಗಳನ್ನು ಓದಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> ಆ್ಯಪ್‌ಗೆ ದೃಢೀಕರಣದ ಅಗತ್ಯವಿದೆ."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ಬಯೋಮೆಟ್ರಿಕ್ ಹಾರ್ಡ್‌ವೇರ್‌ ಲಭ್ಯವಿಲ್ಲ"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ಪ್ರಮಾಣೀಕರಣವನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"ಪ್ರಮಾಣೀಕರಣವನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ಇದರ ಮೂಲಕ ತೆರೆಯಿರಿ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ಜೊತೆಗೆ ತೆರೆಯಿರಿ"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ತೆರೆ"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ಮೂಲಕ <xliff:g id="HOST">%1$s</xliff:g> ಲಿಂಕ್‌ಗಳನ್ನು ತೆರೆಯಲು ಪ್ರವೇಶವನ್ನು ನೀಡಿ"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ಮೂಲಕ <xliff:g id="HOST">%1$s</xliff:g> ಲಿಂಕ್‌ಗಳನ್ನು ತೆರೆಯಲು ಪ್ರವೇಶವನ್ನು ನೀಡಿ"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ಪ್ರವೇಶ ಅನುಮತಿಸಿ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ಇವರ ಜೊತೆಗೆ ಎಡಿಟ್ ಮಾಡಿ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ಜೊತೆಗೆ ಎಡಿಟ್ ಮಾಡಿ"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ಎಡಿಟ್"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ಕರೆ ಸ್ವೀಕರಿಸುವುದೇ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ಯಾವಾಗಲೂ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ಒಮ್ಮೆ ಮಾತ್ರ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ಟ್ಯಾಬ್ಲೆಟ್‌‌"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ಟಿವಿ"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸಲು ಎರಡೂ ಧ್ವನಿ ಕೀಗಳನ್ನು ಮೂರು ಸೆಕೆಂಡ್‌ಗಳ ಕಾಲ ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ಕ್ಯಾಮರಾ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ಮೈಕ್ರೋಫೋನ್‌"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ಇತರ ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಮೂಲಕ ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತಿದೆ"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"ದೈನಂದಿನ ಸ್ಥಿತಿಯ ಮಾಹಿತಿಯ ಅಧಿಸೂಚನೆ"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"ಚಾರ್ಜ್‌ಗೆ ಮೊದಲೆ ಬ್ಯಾಟರಿ ಮುಗಿದು ಬಿಡಬಹುದು"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"ಬ್ಯಾಟರಿ ಅವಧಿ ಹೆಚ್ಚಿಸಲು ಬ್ಯಾಟರಿ ಸೇವರ್ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"ಲೋಡ್ ಆಗುತ್ತಿದೆ"</string>
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 8886815..0e725a3 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"앱에서 미디어 컬렉션의 위치를 읽도록 허용합니다."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> 애플리케이션에서 인증을 요청합니다"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"생체 인식 하드웨어를 사용할 수 없음"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"인증이 취소되었습니다."</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"인식할 수 없음"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"인증이 취소되었습니다."</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"연결 프로그램"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s(으)로 열기"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"열기"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"다음으로 <xliff:g id="HOST">%1$s</xliff:g> 링크를 열려면 액세스 권한 부여"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g>(으)로 <xliff:g id="HOST">%1$s</xliff:g> 링크를 열려면 액세스 권한 부여"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"권한 부여"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"편집 프로그램:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s(으)로 수정"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"수정"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"통화를 수락하시겠습니까?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"항상"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"한 번만"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"설정"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s에서 직장 프로필을 지원하지 않습니다."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"태블릿"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 서비스를 사용하려면 두 볼륨 키를 3초 동안 길게 누르세요"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"카메라"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"마이크"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"화면에서 다른 앱 위에 표시"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"루틴 모드 정보 알림"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"평소에 충전하는 시간 전에 배터리가 소진될 수 있습니다."</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"배터리 수명을 연장하기 위해 배터리 세이버가 활성화되었습니다."</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"로드 중"</string>
 </resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index de49741..3e3ef6a 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Колдонмого медиа жыйнагыңыз сакталган жерлерди окууга мүмкүнчүлүк берет."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> колдонмосунда аутентификациядан өтүңүз."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометрикалык аппарат жеткиликсиз"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Аныктыгын текшерүү жокко чыгарылды"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Таанылган жок"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Аныктыгын текшерүү жокко чыгарылды"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Төмөнкү менен ачуу"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s менен ачуу"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ачуу"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Төмөнкү колдонмо менен <xliff:g id="HOST">%1$s</xliff:g> шилтемелерин  ачууга уруксат берүү"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> колдонмосу менен <xliff:g id="HOST">%1$s</xliff:g> шилтемелерин  ачууга уруксат берүү"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Мүмкүнчүлүк берүү"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Төмөнкү менен түзөтүү"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s менен түзөтүү"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Түзөтүү"</string>
@@ -1568,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Чалуу кабыл алынсынбы?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Дайыма"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Бир жолу гана"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Жөндөөлөр"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s жумуш профилин колдоого албайт"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшет"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Сыналгы"</string>
@@ -1647,7 +1649,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын колдонуу үчүн үнүн чоңойтуп/кичирейтүү баскычтарын үч секунд коё бербей басып туруңуз"</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>
@@ -1977,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"экрандагы башка терезелердин үстүнөн көрсөтүлүүдө"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Режимдин адаттагы билдирмеси"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Батарея кубаттоого чейин отуруп калышы мүмкүн"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Батареянын отуруп калбашы үчүн Батареяны үнөмдөгүч режими иштетилди"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Жүктөлүүдө"</string>
 </resources>
diff --git a/core/res/res/values-land/dimens_permission_controller.xml b/core/res/res/values-land/dimens_permission_controller.xml
deleted file mode 100644
index 2146241..0000000
--- a/core/res/res/values-land/dimens_permission_controller.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2018 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<!-- Landscape dimensions for the permission grant dialog. -->
-<resources>
-    <!-- Assuming the dimension of a sailfish, this yields 95% width in splitscreen and 65% in
-         landscape -->
-    <dimen name="permissionGrantDialogWeight">8.6</dimen>
-    <dimen name="permissionGrantDialogWidth">334dp</dimen>
-</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 9356302..a63cd59 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ອະນຸຍາດໃຫ້ແອັບອ່ານສະຖານທີ່ຈາກຄໍເລັກຊັນມີເດຍຂອງທ່ານ."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"ແອັບພລິເຄຊັນ <xliff:g id="APP">%s</xliff:g> ຕ້ອງການກວດຮັບຮອງຄວາມຖືກຕ້ອງ."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ຮາດແວຊີວະມິຕິບໍ່ສາມາດໃຊ້ໄດ້"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ຍົກເລີກການຮັບຮອງຄວາມຖືກຕ້ອງແລ້ວ"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ບໍ່ຮັບຮູ້"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"ຍົກເລີກການຮັບຮອງຄວາມຖືກຕ້ອງແລ້ວ"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ເປີດໂດຍໃຊ້"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"ເປີດ​ໂດຍ​ໃຊ້ %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ເປີດ"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ໃຫ້ສິດອະນຸຍາດເພື່ອເປີດລິ້ງ <xliff:g id="HOST">%1$s</xliff:g> ດ້ວຍ"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"ໃຫ້ສິດອະນຸຍາດເພື່ອເປີດລິ້ງ <xliff:g id="HOST">%1$s</xliff:g> ດ້ວຍ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ໃຫ້ສິດອະນຸຍາດ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"​ແກ້​ໄຂ​ໃນ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"ແກ້​ໄຂ​ໃນ %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ແກ້ໄຂ"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ຮັບການໂທບໍ່?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ທຸກຄັ້ງ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ຄັ້ງດຽວ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ການຕັ້ງຄ່າ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ບໍ່​ຮອງ​ຮັບ​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກ​ຂອງ​ທ່ານ"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ແທັບເລັດ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ໂທລະພາບ"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"ກົດປຸ່ມສຽງທັງສອງພ້ອມກັນຄ້າງໄວ້ສາມວິນາທີເພື່ອໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ກ້ອງ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ໄມໂຄຣໂຟນ"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ສະແດງຜົນບັງແອັບອື່ນຢູ່ໜ້າຈໍຂອງທ່ານ"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"ການແຈ້ງເຕືອນຂໍ້ມູນໂໝດກິດຈະວັດປະຈຳວັນ"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"ແບັດເຕີຣີອາດໝົດກ່ອນການສາກຕາມປົກກະຕິ"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"ເປີດຕົວປະຢັດແບັດເຕີຣີເພື່ອຂະຫຍາຍອາຍຸແບັດເຕີຣີ"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"ກຳລັງໂຫລດ"</string>
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 8870ebb..0c0887b 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -539,11 +539,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Programai leidžiama skaityti vietoves iš medijos kolekcijos."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Programa „<xliff:g id="APP">%s</xliff:g>“ nori jus autentifikuoti."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrinė aparatinė įranga nepasiekiama"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autentifikavimas atšauktas"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Neatpažinta"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autentifikavimas atšauktas"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Aptiktas dalinis piršto antspaudas. Bandykite dar kartą."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nepavyko apdoroti piršto antspaudo. Bandykite dar kartą."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Piršto antspaudo jutiklis purvinas. Nuvalykite ir bandykite dar kartą."</string>
@@ -1168,6 +1166,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Atidaryti naudojant"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Atidaryti naudojant %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Atidaryti"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Suteikite prieigą atidaryti <xliff:g id="HOST">%1$s</xliff:g> nuorodas naudojant"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Suteikite prieigą atidaryti <xliff:g id="HOST">%1$s</xliff:g> nuorodas naudojant „<xliff:g id="APPLICATION">%2$s</xliff:g>“"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Suteikti prieigą"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Redaguoti naudojant"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redaguoti naudojant %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Redaguoti"</string>
@@ -1612,6 +1613,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Priimti skambutį?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Visada"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Tik kartą"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nustatymai"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nepalaiko darbo profilio"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Planšetinis kompiuteris"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1693,7 +1695,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Jei norite naudoti „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“, paspauskite abu garsumo klavišus ir palaikykite tris sekundes"</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>
@@ -2045,5 +2047,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparatas"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofonas"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"rodo virš kitų programų jūsų ekrane"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Veiksmų sekos režimo informacijos pranešimas"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Akumuliatoriaus energija gali išsekti prieš įprastą įkrovimą"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Akumuliatoriaus tausojimo priemonė suaktyvinta, kad akumuliatorius veiktų ilgiau"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Įkeliama"</string>
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5a1432b..b802fee 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -536,11 +536,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Ļauj lietotnei lasīt atrašanās vietas no jūsu multivides kolekcijas."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Lietotne <xliff:g id="APP">%s</xliff:g> pieprasa autentificēt."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrisko datu aparatūra nav pieejama"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autentifikācija ir atcelta"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Dati nav atpazīti"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autentifikācija ir atcelta"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Noteikts daļējs pirksta nospiedums. Lūdzu, mēģiniet vēlreiz."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nevarēja apstrādāt pirksta nospiedumu. Lūdzu, mēģiniet vēlreiz."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Pirkstu nospiedumu sensors ir netīrs. Lūdzu, notīriet to un mēģiniet vēlreiz."</string>
@@ -1148,6 +1146,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Atvērt, izmantojot"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Atvērt, izmantojot %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Atvērt"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Piekļuves piešķiršana, lai atvērtu <xliff:g id="HOST">%1$s</xliff:g> saites lietojumprogrammā"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Piekļuves piešķiršana, lai atvērtu <xliff:g id="HOST">%1$s</xliff:g> saites lietojumprogrammā <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Atļaut piekļuvi"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Rediģēt, izmantojot"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediģēt, izmantojot %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Rediģēt"</string>
@@ -1589,6 +1590,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vai atbildēt uz zvanu?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vienmēr"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Tikai vienreiz"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Iestatījumi"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Programma %1$s neatbalsta darba profilus"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Planšetdators"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1669,7 +1671,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Lai izmantotu pakalpojumu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, nospiediet abus skaļuma taustiņus un turiet tos trīs sekundes."</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>
@@ -2010,5 +2012,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofons"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"rāda pāri citām lietotnēm jūsu ekrānā"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Informatīvs paziņojums par akumulatoru"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Akumulators var izlādēties pirms parastā uzlādes laika"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Aktivizēts akumulatora jaudas taupīšanas režīms, lai palielinātu akumulatora darbības ilgumu"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Ielāde"</string>
 </resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 769ac43..9c66edc 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Дозволува апликацијата да чита локации од вашата збирка на аудиовизуелни содржини."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Апликацијата <xliff:g id="APP">%s</xliff:g> сака да ве провери."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометрискиот хардвер е недостапен"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Проверката е откажана"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Непознат"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Проверката е откажана"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Отвори со"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отвори со %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отвори"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Дајте пристап да се отвораат линкови на <xliff:g id="HOST">%1$s</xliff:g> со"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Дајте пристап да се отвораат линкови на <xliff:g id="HOST">%1$s</xliff:g> со <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволи пристап"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Измени со"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Измени со %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Измени"</string>
@@ -1569,6 +1570,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Прифати повик?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Секогаш"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Само еднаш"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Поставки"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддржува работен профил"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Таблет"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевизор"</string>
@@ -1648,7 +1650,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Притиснете ги и задржете ги двете копчиња за јачина на звукот во траење од три секунди за да користите <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1978,5 +1980,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"се прикажува преку други апликации на вашиот екран"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Известување за информации за режимот за рутини"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Батеријата може да се потроши пред вообичаеното време за полнење"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Активиран е „Штедачот на батерија“ за да се продолжи траењето на батеријата"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Се вчитува"</string>
 </resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 620718d..76d2daf 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"നിങ്ങളുടെ മീഡിയ ശേഖരത്തിൽ നിന്നും ലൊക്കേഷനുകൾ റീഡ് ചെയ്യുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> ആപ്പിന് നിങ്ങളെ പരിശോധിച്ചുറപ്പിക്കണം."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ബയോമെട്രിക് ഹാർ‌ഡ്‌വെയർ ലഭ്യമല്ല"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"പരിശോധിച്ചുറപ്പിക്കൽ റദ്ദാക്കി"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"തിരിച്ചറിഞ്ഞില്ല"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"പരിശോധിച്ചുറപ്പിക്കൽ റദ്ദാക്കി"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ഇത് ഉപയോഗിച്ച് തുറക്കുക"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ഉപയോഗിച്ച് തുറക്കുക"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"തുറക്കുക"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ഇനിപ്പറയുന്നത് ഉപയോഗിച്ച്, <xliff:g id="HOST">%1$s</xliff:g> ലിങ്കുകൾ തുറക്കാൻ ആക്‌സ‌സ് നൽകുക"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ഉപയോഗിച്ച്, <xliff:g id="HOST">%1$s</xliff:g> ലിങ്കുകൾ തുറക്കാൻ ആക്‌സ‌സ് നൽകുക"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ആക്‌സസ് നൽകുക"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ഇത് ഉപയോഗിച്ച് എഡിറ്റുചെയ്യുക"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ഉപയോഗിച്ച് എഡിറ്റുചെയ്യുക"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"എഡിറ്റുചെയ്യുക"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"കോൾ സ്വീകരിക്കണോ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"എല്ലായ്പ്പോഴും"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ഒരിക്കൽ മാത്രം"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ക്രമീകരണം"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s, ഔദ്യോഗിക പ്രൊഫൈലിനെ പിന്തുണയ്‌ക്കുന്നില്ല"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ടാബ്‌ലെറ്റ്"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ടിവി"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഉപയോഗിക്കാൻ, രണ്ട് വോളിയം കീകളും മൂന്ന് സെക്കൻഡ് അമർത്തിപ്പിടിക്കുക"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ക്യാമറ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"മൈക്രോഫോൺ"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"നിങ്ങളുടെ സ്‌ക്രീനിലെ മറ്റ് ആപ്പുകൾക്ക് മുകളിൽ പ്രദർശിപ്പിക്കുന്നു"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"ദിനചര്യ മോഡ് വിവരത്തെ കുറിച്ചുള്ള അറിയിപ്പ്"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"സാധാരണയുള്ളതിലും നേരത്തെ ബാറ്ററിയുടെ ചാർജ് തീർന്നേക്കാം"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"ബാറ്ററി ലൈഫ് വര്‍ദ്ധിപ്പിക്കാൻ, ബാറ്ററി ലാഭിക്കൽ സജീവമാക്കി"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"ലോഡ് ചെയ്യുന്നു"</string>
 </resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index c0b23fc..1e2746c 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Таны медиа цуглуулгаас байршлыг унших зөвшөөрлийг аппад олгодог."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> апп баталгаажуулахыг хүсэж байна."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометрийн техник хангамж боломжгүй байна"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Нотолгоог цуцаллаа"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Таниагүй"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Нотолгоог цуцаллаа"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Нээх"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ашиглан нээх"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Нээх"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g>-н холбоосыг дараахаар нээх хандалт өгөх"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g>-н холбоосыг <xliff:g id="APPLICATION">%2$s</xliff:g>-р нээх хандалт өгөх"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Хандалт өгөх"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Засварлах"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ашиглан засварлах"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Засах"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Дуудлагыг зөвшөөрөх үү?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Байнга"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Нэг удаа"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Тохиргоо"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ажлын профайлыг дэмждэггүй"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Таблет"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tелевиз"</string>
@@ -1645,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г ашиглахын тулд дууны түвшнийг ихэсгэх, багасгах түлхүүрийг 3 секундийн турш зэрэг дарна уу"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камер"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"таны дэлгэцэд бусад аппын дээр харуулж байна"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Хэвшлийн горимын мэдээллийн мэдэгдэл"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Батарей ихэвчлэн цэнэглэдэг хугацаанаас өмнө дуусаж болзошгүй"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Батарейны ажиллах хугацааг уртасгахын тулд Батарей хэмнэгчийг идэвхжүүллээ"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Ачаалж байна"</string>
 </resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index f3d6b4b..240a3bf 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"अॅपला तुमच्या मीडिया संग्रहामध्येील स्थाने वाचण्यासाठी अनुमती देते."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"अॅप्लिकेशन <xliff:g id="APP">%s</xliff:g>ला ऑथेंटिकेट करायचे आहे."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"बायोमेट्रिक हार्डवेअर उपलब्ध नाही"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ऑथेंटिकेशन रद्द केले"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ओळखले नाही"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"ऑथेंटिकेशन रद्द केले"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"यासह उघडा"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s सह उघडा"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"उघडा"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"सह <xliff:g id="HOST">%1$s</xliff:g> लिंक उघडण्याचा अ‍ॅक्सेस द्या"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> सह <xliff:g id="HOST">%1$s</xliff:g> लिंक उघडण्याचा अ‍ॅक्सेस द्या"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"अ‍ॅक्सेस द्या"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"सह संपादित करा"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s सह संपादित करा"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"संपादित करा"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"कॉल स्वीकारायचा?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"नेहमी"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"फक्त एकदाच"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिंग्ज"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s कार्य प्रोफाईलचे समर्थन करीत नाही"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"टॅबलेट"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"टीव्ही"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> वापरण्यासाठी दोन्ही व्हॉल्युम की तीन सेकंद दाबा आणि धरून ठेवा"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"कॅमेरा"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"मायक्रोफोन"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"तुमच्‍या स्‍क्रीनवर इतर अॅप्‍सवर डिस्‍प्‍ले करत आहे"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"दिनक्रम मोडची माहिती सूचना"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"चार्जिंगची सामान्य पातळी गाठेपर्यंत कदाचित बॅटरी संपू शकते"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"बॅटरी लाइफ वाढवण्यासाठी बॅटरी सेव्हर सुरू केला आहे"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"लोड होत आहे"</string>
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 0eb022a..c3c863a 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Membenarkan apl membaca lokasi daripada koleksi media anda."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Aplikasi <xliff:g id="APP">%s</xliff:g> mahu membuat pengesahan."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Perkakasan biometrik tidak tersedia"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Pengesahan dibatalkan"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Tidak dikenali"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Pengesahan dibatalkan"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Cap jari separa dikesan. Sila cuba lagi."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Tidak dapat memproses cap jari. Sila cuba lagi."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Penderia cap jari kotor. Sila bersihkan dan cuba lagi."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Buka dengan"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buka dengan %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buka"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Berikan akses untuk membuka pautan <xliff:g id="HOST">%1$s</xliff:g> dengan"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Berikan akses untuk membuka pautan <xliff:g id="HOST">%1$s</xliff:g> dengan <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Berikan akses"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edit dengan"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit dengan %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edit"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sentiasa"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Hanya sekali"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Tetapan"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s tidak menyokong profil kerja"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Tekan dan tahan kedua-dua kekunci kelantangan selama tiga saat untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"dipaparkan di atas apl lain pada skrin anda"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Pemberitahuan maklumat Mod Rutin"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Bateri mungkin habis sebelum pengecasan biasa"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Penjimat Bateri diaktifkan untuk memanjangkan hayat bateri"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Memuatkan"</string>
 </resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 1c5f0c7..c036730 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"အက်ပ်အား သင့်မီဒီယာစုစည်းမှုမှ တည်နေရာများကို ဖတ်ခွင့်ပေးသည်။"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"အပလီကေးရှင်း <xliff:g id="APP">%s</xliff:g> က အထောက်အထားစိစစ်လိုသည်။"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ဇီဝအချက်အလက်သုံး ကွန်ပျူတာစက်ပစ္စည်း မရရှိနိုင်ပါ"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"အထောက်အထားစိစစ်ခြင်းကို ပယ်ဖျက်လိုက်သည်"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"မသိပါ"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"အထောက်အထားစိစစ်ခြင်းကို ပယ်ဖျက်လိုက်သည်"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"...ဖြင့် ဖွင့်မည်"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ဖြင့် ဖွင့်မည်"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ဖွင့်ပါ"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> လင့်ခ်များကို အ​ောက်ပါဖြင့် ဖွင့်ခွင့်ပေးပါ-"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g> လင့်ခ်များကို <xliff:g id="APPLICATION">%2$s</xliff:g> ဖြင့် ဖွင့်ခွင့်ပေးပါ"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ဖွင့်ခွင့်ပေးရန်"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"...နှင့် တည်းဖြတ်ရန်"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s နှင့် တည်းဖြတ်ရန်"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"တည်းဖြတ်ပါ"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ဖုန်းခေါ်ဆိုမှုကို လက်ခံမလား?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"အမြဲတမ်း"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"တစ်ခါတည်း"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ဆက်တင်များ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s က အလုပ်ပရိုဖိုင်ကို မပံ့ပိုးပါ။"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"တက်ဘလက်"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"တီဗွီ"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို သုံးရန် အသံအတိုးအလျှော့ ခလုတ်နှစ်ခုလုံးကို သုံးစက္ကန့်ကြာ ဖိထားပါ"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ကင်မရာ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"မိုက်ခရိုဖုန်း"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"သင့်မျက်နှာပြင်ပေါ်ရှိ အခြားအက်ပ်များပေါ်တွင် ပြသခြင်း"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"ပုံမှန်မုဒ်အတွက် အချက်အလက်ပြသည့် အကြောင်းကြားချက်"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"ပုံမှန်အားသွင်းမှုမပြုလုပ်မီ ဘက်ထရီကုန်သွားနိုင်သည်"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"ဘက်ထရီသက်တမ်းကို တိုးမြှင့်ရန် \'ဘက်ထရီအားထိန်း\' စတင်ပြီးပါပြီ"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"တင်နေသည်"</string>
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 233b98a..e479834 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Lar appen lese posisjoner fra mediesamlingen din."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Appen <xliff:g id="APP">%s</xliff:g> vil autentisere."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrisk maskinvare er utilgjengelig"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autentiseringen er avbrutt"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Ikke gjenkjent"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autentiseringen er avbrutt"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Deler av fingeravtrykket er registrert. Prøv på nytt."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Kunne ikke registrere fingeravtrykket. Prøv på nytt."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingeravtrykksensoren er skitten. Rengjør den og prøv på nytt."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Åpne med"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Åpne med %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Åpne"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Gi tilgang til å åpne <xliff:g id="HOST">%1$s</xliff:g>-linker med"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Gi tilgang til å åpne <xliff:g id="HOST">%1$s</xliff:g>-linker med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Gi tilgang"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Rediger med"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediger med %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Endre"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vil du besvare anropet?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Bare én gang"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Innstillinger"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s støtter ikke arbeidsprofiler"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Nettbrett"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Google TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Trykk og hold inne begge volumtastene i tre sekunder for å bruke <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"vises over andre apper på skjermen"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Varsel med informasjon om rutinemodus"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Batteriet kan gå tomt før den vanlige ladingen"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batterisparing er aktivert for å forlenge batterilevetiden"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Laster inn"</string>
 </resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 0b2362a..b892255 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"यसले अनुप्रयोगलाई तपाईंको मिडिया सङ्ग्रहका स्थानहरू पढ्न दिन्छ।"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"अनुप्रयोग <xliff:g id="APP">%s</xliff:g> ले प्रमाणीकरण गर्न चाहन्छ।"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"बायोमेट्रिक हार्डवेयर उपलब्ध छैन"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"प्रमाणीकरण रद्द गरियो"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"पहिचान भएन"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"प्रमाणीकरण रद्द गरियो"</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>
@@ -1132,6 +1130,9 @@
     <!-- no translation found for whichViewApplicationNamed (2286418824011249620) -->
     <skip />
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"खोल्नुहोस्"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"निम्नमार्फत <xliff:g id="HOST">%1$s</xliff:g>का लिंकहरू खोल्न पहुँच दिनुहोस्‌"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g>मार्फत <xliff:g id="HOST">%1$s</xliff:g>का लिंकहरू खोल्न पहुँच दिनुहोस्‌"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"पहुँच दिनुहोस्"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"सँग सम्पादन गर्नुहोस्"</string>
     <!-- String.format failed for translation -->
     <!-- no translation found for whichEditApplicationNamed (1775815530156447790) -->
@@ -1572,6 +1573,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"कल स्वीकार गर्नुहुन्छ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"सधैँ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"एक पटक मात्र"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिङहरू"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s  कार्य प्रोफाइल समर्थन गर्दैन"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ट्याब्लेट"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1651,7 +1653,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> प्रयोग गर्न दुवै भोल्युम कुञ्जीहरूलाई तीन सेकेन्डसम्म थिचिराख्नुहोस्"</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>
@@ -1981,5 +1983,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"क्यामेरा"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"माइक्रोफोन"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"तपाईंको स्क्रिनका अन्य अनुप्रयोगहरूमा प्रदर्शन गरिँदै छ"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"दिनचर्या मोडको जानकारीमूलक सूचना"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"प्रायः चार्ज गर्ने समय हुनुभन्दा पहिले नै ब्याट्री सकिन सक्छ"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"ब्याट्रीको आयु बढाउन ब्याट्री सेभर सक्रिय गरियो"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"लोड गर्दै"</string>
 </resources>
diff --git a/core/res/res/values-night/themes_permission_controller.xml b/core/res/res/values-night/themes_permission_controller.xml
deleted file mode 100644
index a071927..0000000
--- a/core/res/res/values-night/themes_permission_controller.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2018 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<!-- themes for the permission grant dialog. -->
-<resources>
-    <style name="Theme.DeviceDefault.PermissionGrantApp"
-           parent="@style/Theme.DeviceDefault.Panel">
-        <item name="windowIsFloating">false</item>
-        <item name="windowTranslucentStatus">true</item>
-        <item name="backgroundDimEnabled">true</item>
-        <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
-    </style>
-
-    <style name="Theme.DeviceDefault.PermissionGrant"
-           parent="@style/Theme.DeviceDefault.Dialog">
-        <item name="titleTextStyle">@style/PermissionGrantTitleMessage</item>
-    </style>
-</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 996b700..c552f00 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Hiermee sta je de app toe locaties van je mediacollectie te bekijken."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"App <xliff:g id="APP">%s</xliff:g> wil een verificatie uitvoeren."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrische hardware niet beschikbaar"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Verificatie geannuleerd"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Niet herkend"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Verificatie geannuleerd"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Gedeeltelijke vingerafdruk gedetecteerd. Probeer het opnieuw."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Kan vingerafdruk niet verwerken. Probeer het opnieuw."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"De vingerafdruksensor moet worden schoongemaakt. Probeer het daarna opnieuw."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Openen met"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Openen met %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Openen"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Toegang verlenen om links naar <xliff:g id="HOST">%1$s</xliff:g> te openen met"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Toegang verlenen om links naar <xliff:g id="HOST">%1$s</xliff:g> te openen met <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Toegang geven"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Bewerken met"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Bewerken met %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Bewerken"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Gesprek accepteren?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Altijd"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Één keer"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Instellingen"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ondersteunt werkprofielen niet"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tv"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Houd beide volumetoetsen drie seconden ingedrukt om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruiken"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfoon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"wordt weergegeven vóór andere apps op je scherm"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Informatiemelding voor routinemodus"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"De batterij raakt mogelijk leeg voordat deze normaal gesproken wordt opgeladen"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batterijbesparing is geactiveerd om de batterijduur te verlengen"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Laden"</string>
 </resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 27b7d5d..57d39ce 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ଆପଣଙ୍କ ମିଡିଆ ସଂଗ୍ରହ ଠାରୁ ଅବସ୍ଥାନଗୁଡିକୁ ପଢିବାକୁ ଆପ୍‍ ଅନୁମତି ଦେଇଥାଏ।"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"ଆପ୍ଲିକେସନ୍ <xliff:g id="APP">%s</xliff:g> ପ୍ରମାଣିତକୃତ କରିବାକୁ ଚାହୁଁଛି।"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ବାୟୋମେଟ୍ରିକ୍‌ ହାର୍ଡୱେର୍‌ ଉପଲବ୍ଧ ନାହିଁ"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ପ୍ରାମାଣିକତାକୁ ବାତିଲ୍ କରାଯାଇଛି"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"ପ୍ରାମାଣିକତାକୁ ବାତିଲ୍ କରାଯାଇଛି"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ସହିତ ଖୋଲନ୍ତୁ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ସହିତ ଖୋଲନ୍ତୁ"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ଖୋଲନ୍ତୁ"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ଏହା ସହିତ ଲିଙ୍କ ଥିବା <xliff:g id="HOST">%1$s</xliff:g> ଖୋଲିବା ପାଇଁ ଆକ୍ସେସ୍ ଦିଅନ୍ତୁ"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ସହିତ ଲିଙ୍କ ଥିବା <xliff:g id="HOST">%1$s</xliff:g> ଖୋଲିବା ପାଇଁ ଆକ୍ସେସ୍ ଦିଅନ୍ତୁ"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ଆକ୍ସେସ୍‌ ଦିଅନ୍ତୁ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ସହିତ ଏଡିଟ୍‌ କରନ୍ତୁ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sରେ ସଂଶୋଧନ କରନ୍ତୁ"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ଏଡିଟ୍‌ କରନ୍ତୁ"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"କଲ୍‍ ସ୍ୱୀକାର କରିବେ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ସର୍ବଦା"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ଥରେ ମାତ୍ର"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ସେଟିଂସ୍"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ୱର୍କ ପ୍ରୋଫାଇଲ୍‌କୁ ସପୋର୍ଟ କରୁନାହିଁ"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ଟାବଲେଟ୍‌"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବ୍ୟବହାର କରିବାକୁ ତିନି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍‍ କୀ ଦବାଇ ଧରି ରଖନ୍ତୁ"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"କ୍ୟାମେରା"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ମାଇକ୍ରୋଫୋନ୍"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ଆପଣଙ୍କ ସ୍କ୍ରୀନ୍ ଉପରେ ଥିବା ଅନ୍ୟ ଆପ୍‌ ଉପରେ ଦେଖାଦେବ"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"ନିୟମିତ ମୋଡ୍‍ ସୂଚନା ବିଜ୍ଞପ୍ତି"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"ସାଧାରଣ ଭାବରେ ଚାର୍ଜ୍ କରିବା ପୂର୍ବରୁ ବ୍ୟାଟେରୀ ସରିଯାଇପାରେ"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"ବ୍ୟାଟେରୀର ସମୟକୁ ବଢ଼ାଇବା ପାଇଁ ବ୍ୟଟେରୀ ସେଭର୍‍କୁ କାର୍ଯ୍ୟକାରୀ କରାଯାଇଛି"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"ଲୋଡ୍ ହେଉଛି"</string>
 </resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index eacf006..85afacb 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਮੀਡੀਆ ਸੰਗ੍ਰਹਿ ਦੇ ਟਿਕਾਣਿਆਂ ਨੂੰ ਪੜ੍ਹਨ ਦਿੰਦੀ ਹੈ।"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"ਐਪਲੀਕੇਸ਼ਨ <xliff:g id="APP">%s</xliff:g> ਪ੍ਰਮਾਣੀਕਰਨ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ।"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ਬਾਇਓਮੈਟ੍ਰਿਕ ਹਾਰਡਵੇਅਰ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ਪ੍ਰਮਾਣੀਕਰਨ ਰੱਦ ਕੀਤਾ ਗਿਆ"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"ਪ੍ਰਮਾਣੀਕਰਨ ਰੱਦ ਕੀਤਾ ਗਿਆ"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"ਨਾਲ ਖੋਲ੍ਹੋ"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ਨਾਲ ਖੋਲ੍ਹੋ"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"ਖੋਲ੍ਹੋ"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ਇਸ ਨਾਲ <xliff:g id="HOST">%1$s</xliff:g> ਲਿੰਕਾਂ ਨੂੰ ਖੋਲ੍ਹਣ ਦੀ ਪਹੁੰਚ ਦਿਓ"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ <xliff:g id="HOST">%1$s</xliff:g> ਲਿੰਕਾਂ ਨੂੰ ਖੋਲ੍ਹਣ ਦੀ ਪਹੁੰਚ ਦਿਓ"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ਪਹੁੰਚ ਦਿਓ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"ਇਸ ਨਾਲ ਸੰਪਾਦਨ ਕਰੋ"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ਨਾਲ ਸੰਪਾਦਨ ਕਰੋ"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ਸੰਪਾਦਨ ਕਰੋ"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ਕੀ ਕਾਲ ਸਵੀਕਾਰ ਕਰਨੀ ਹੈ?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ਹਮੇਸ਼ਾਂ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ਕੇਵਲ ਇੱਕ ਵਾਰ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ਸੈਟਿੰਗਾਂ"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ਟੈਬਲੈੱਟ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ ਕੁੰਜੀਆਂ ਨੂੰ 3 ਸਕਿੰਟਾਂ ਲਈ ਦਬਾਈ ਰੱਖੋ"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"ਕੈਮਰਾ"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਹੋਰਾਂ ਐਪਾਂ ਉੱਪਰ ਦਿਖਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"ਨਿਯਮਬੱਧ ਮੋਡ ਦੀ ਜਾਣਕਾਰੀ ਵਾਲੀ ਸੂਚਨਾ"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"ਬੈਟਰੀ ਚਾਰਜ ਕਰਨ ਦੇ ਮਿੱਥੇ ਸਮੇਂ ਤੋਂ ਪਹਿਲਾਂ ਸ਼ਾਇਦ ਬੈਟਰੀ ਖਤਮ ਹੋ ਜਾਵੇ"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index b2bb7b0..08d56e4 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -539,11 +539,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Zezwala aplikacji na odczytywanie lokalizacji z kolekcji multimediów."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Aplikacja <xliff:g id="APP">%s</xliff:g> wymaga uwierzytelnienia."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Sprzęt biometryczny niedostępny"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Anulowano uwierzytelnianie"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nie rozpoznano"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Anulowano uwierzytelnianie"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Odcisk palca został odczytany tylko częściowo. Spróbuj ponownie."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nie udało się przetworzyć odcisku palca. Spróbuj ponownie."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Czytnik linii papilarnych jest zabrudzony. Wyczyść go i spróbuj ponownie."</string>
@@ -1168,6 +1166,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otwórz w aplikacji"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otwórz w aplikacji %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otwórz"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Przyznaj uprawnienia do otwierania linków z <xliff:g id="HOST">%1$s</xliff:g> w:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Przyznaj uprawnienia do otwierania linków z <xliff:g id="HOST">%1$s</xliff:g> w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udziel uprawnień"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Edytuj w aplikacji"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edytuj w aplikacji %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Edytuj"</string>
@@ -1612,6 +1613,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Odebrać połączenie?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Zawsze"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Tylko raz"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ustawienia"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nie obsługuje profilu do pracy"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Telewizor"</string>
@@ -1693,7 +1695,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Naciśnij i przytrzymaj oba przyciski głośności przez trzy sekundy, by użyć usługi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -2045,5 +2047,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Aparat"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"wyświetla się nad innymi aplikacjami na ekranie"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Powiadomienie z informacją o trybie rutynowym"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Bateria może się wyczerpać przed zwykłą porą ładowania"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Włączono Oszczędzanie baterii, by wydłużyć czas pracy na baterii"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Ładuję"</string>
 </resources>
diff --git a/core/res/res/values-port/dimens_permission_controller.xml b/core/res/res/values-port/dimens_permission_controller.xml
deleted file mode 100644
index af28713..0000000
--- a/core/res/res/values-port/dimens_permission_controller.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2018 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<!-- portrait dimensions for the permission grant dialog. -->
-<resources>
-    <!-- This yields 95% width -->
-    <dimen name="permissionGrantDialogWeight">380</dimen>
-    <dimen name="permissionGrantDialogWidth">0dp</dimen>
-</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index b1a1d39..38368d3 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que o app leia os locais na sua coleção de mídias."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"O app <xliff:g id="APP">%s</xliff:g> está solicitando autenticação."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biométrico indisponível"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autenticação cancelada"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autenticação cancelada"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Impressão digital parcial detectada. Tente novamente."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Não foi possível processar a impressão digital. Tente novamente."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"O sensor de impressão digital está sujo. Limpe-o e tente novamente."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Conceder acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Conceder acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com o app <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Só uma vez"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configurações"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não aceita perfis de trabalho"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Câmera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"exibindo sobre outros apps na sua tela"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificação de informação do modo rotina"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"A bateria pode acabar antes da recarga normal"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"A \"Economia de bateria\" foi ativada para aumentar a duração da carga"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Carregando"</string>
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index ec4cf8c..67fe5b6 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que a aplicação leia as localizações a partir da sua coleção de multimédia."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"A aplicação <xliff:g id="APP">%s</xliff:g> pretende uma autenticação"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biométrico indisponível."</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autenticação cancelada"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido."</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autenticação cancelada"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Impressão digital detetada. Tente novamente."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Não foi possível processar a impressão digital. Tente novamente."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"O sensor de impressões digitais está sujo. Limpe-o e tente novamente."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Conceda acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Conceda acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com a aplicação <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Apenas uma vez"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Definições"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não suporta o perfil de trabalho"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Prima sem soltar as teclas de volume durante três segundos para utilizar o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Câmara"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"sobrepõe-se a outras aplicações no ecrã"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificação de informações do Modo rotina"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Pode ficar sem bateria antes do carregamento habitual"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Poupança de bateria ativada para prolongar a duração da bateria"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"A carregar…"</string>
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index b1a1d39..38368d3 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite que o app leia os locais na sua coleção de mídias."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"O app <xliff:g id="APP">%s</xliff:g> está solicitando autenticação."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biométrico indisponível"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autenticação cancelada"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autenticação cancelada"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Impressão digital parcial detectada. Tente novamente."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Não foi possível processar a impressão digital. Tente novamente."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"O sensor de impressão digital está sujo. Limpe-o e tente novamente."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Conceder acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Conceder acesso para abrir links de <xliff:g id="HOST">%1$s</xliff:g> com o app <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editar"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Só uma vez"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configurações"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não aceita perfis de trabalho"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Câmera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfone"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"exibindo sobre outros apps na sua tela"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificação de informação do modo rotina"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"A bateria pode acabar antes da recarga normal"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"A \"Economia de bateria\" foi ativada para aumentar a duração da carga"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Carregando"</string>
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 5b36b9a..501d7cc 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -536,11 +536,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Permite aplicației să citească locațiile din colecția dvs. media."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Aplicația <xliff:g id="APP">%s</xliff:g> dorește să se autentifice."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biometric indisponibil"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autentificarea a fost anulată"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nu este recunoscut"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autentificarea a fost anulată"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"S-a detectat parțial amprenta. Încercați din nou."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Amprenta nu a putut fi procesată. Încercați din nou."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzorul pentru amprente este murdar. Curățați-l și încercați din nou."</string>
@@ -1148,6 +1146,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Deschideți cu"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Deschideți cu %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Deschideți"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Permiteți accesul pentru a deschide linkurile <xliff:g id="HOST">%1$s</xliff:g> cu"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Permiteți accesul pentru a deschide linkurile <xliff:g id="HOST">%1$s</xliff:g> cu <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Permiteți accesul"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Editați cu"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editați cu %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Editați"</string>
@@ -1589,6 +1590,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Acceptați apelul?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Întotdeauna"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Numai o dată"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Setări"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nu acceptă profilul de serviciu"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tabletă"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1669,7 +1671,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Apăsați ambele butoane de volum timp de trei secunde pentru a folosi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -2010,5 +2012,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Cameră foto"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Microfon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"se afișează peste alte aplicații de pe ecran"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notificare pentru informații despre modul Rutină"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Bateria se poate descărca înainte de încărcarea obișnuită"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Economisirea bateriei este activată pentru a prelungi durata de funcționare a bateriei"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Se încarcă"</string>
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index ac7908c..8cb2d69 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -539,11 +539,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Приложение получит доступ к геоданным в вашей медиаколлекции."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" запрашивает аутентификацию"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометрическое оборудование недоступно"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Аутентификация отменена"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Не распознано"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Аутентификация отменена"</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>
@@ -1168,6 +1166,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Открыть с помощью приложения:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Открыть с помощью приложения \"%1$s\""</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Открыть"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Предоставьте доступ, чтобы открывать ссылки <xliff:g id="HOST">%1$s</xliff:g> в приложении"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Предоставьте доступ, чтобы открывать ссылки <xliff:g id="HOST">%1$s</xliff:g> в приложении <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Открыть доступ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Редактировать с помощью приложения:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редактировать с помощью приложения \"%1$s\""</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Изменить"</string>
@@ -1612,6 +1613,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Ответить?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Всегда"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Только сейчас"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Настройки"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддерживает рабочие профили"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшетный ПК"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевизор"</string>
@@ -1693,7 +1695,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Чтобы использовать сервис \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", нажмите и удерживайте обе клавиши громкости в течение трех секунд."</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>
@@ -2045,5 +2047,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"показ поверх других окон"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Уведомление о батарее"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Батарея может разрядиться"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Чтобы увеличить время работы от батареи, был включен режим энергосбережения."</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Загрузка"</string>
 </resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 6486f3a..4163033 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ඔබගේ මාධ්‍ය එකතුවෙන් ස්ථාන කියවීමට යෙදුමට ඉඩ දෙයි."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> යෙදුම වෙත සත්‍යාපනය කිරීමට අවශ්‍යයි."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ජීවමිතික දෘඪාංග ලබා ගත නොහැකිය"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"සත්‍යාපනය අවලංගු කළා"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"හඳුනා නොගන්නා ලදී"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"සත්‍යාපනය අවලංගු කළා"</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>
@@ -1130,6 +1128,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"සමඟ විවෘත කරන්න"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s සමඟ විවෘත කරන්න"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"විවෘත කරන්න"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"මේවා මඟින් <xliff:g id="HOST">%1$s</xliff:g> සබැඳි විවෘත කිරීමට ප්‍රවේශය දෙන්න"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> මඟින් <xliff:g id="HOST">%1$s</xliff:g> සබැඳි විවෘත කිරීමට ප්‍රවේශය දෙන්න"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ප්‍රවේශය දෙන්න"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"සමඟ සංස්කරණය කරන්න"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s සමඟ සංස්කරණය කරන්න"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"සංස්කරණය"</string>
@@ -1568,6 +1569,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"ඇමතුම පිළිගන්නවාද?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"සැම විටම"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"එක් වාරයයි"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"සැකසීම්"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s කාර්යාල පැතිකඩ සඳහා සහාය ලබනොදේ."</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ටැබ්ලට්ය"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"රූපවාහිනී"</string>
@@ -1647,7 +1649,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> භාවිත කිරීමට හඬ පරිමා යතුරු දෙකම තත්පර තුනකට ඔබාගෙන සිටින්න"</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>
@@ -1977,5 +1979,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"කැමරාව"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"මයික්‍රෆෝනය"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ඔබගේ තිරය මත වෙනත් යෙදුම්වලට උඩින් සංදර්ශනය කරමින්"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"දිනචරියා ප්‍රකාර තතු දැනුම්දීම"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"බැටරිය සුපුරුදු ආරෝපණයට පෙර ඉවර විය හැක"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"බැටරි සුරැකුම බැටරි ආයු කාලය දීර්ඝ කිරීමට සක්‍රිය කෙරිණි"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"පූරණය කරමින්"</string>
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 66d6ef6..8905d2a 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -539,11 +539,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Umožňuje aplikácii čítať polohy zo zbierky médií."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Aplikácia <xliff:g id="APP">%s</xliff:g> chce overiť totožnosť"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrický hardvér nie je k dispozícii"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Overenie bolo zrušené"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nerozpoznané"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Overenie bolo zrušené"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Podarilo sa rozpoznať iba časť odtlačku prsta. Skúste to znova."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Odtlačok prsta sa nepodarilo spracovať. Skúste to znova."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Snímač odtlačkov je špinavý. Vyčistite ho a skúste to znova."</string>
@@ -1168,6 +1166,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Otvoriť v aplikácii"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvoriť v aplikácii %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvoriť"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Udeľte prístup na otváranie odkazov <xliff:g id="HOST">%1$s</xliff:g> pomocou aplikácie"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Udeľte prístup na otváranie odkazov <xliff:g id="HOST">%1$s</xliff:g> pomocou aplikácie <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udeliť prístup"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Upraviť pomocou"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Upraviť v aplikácii %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Upraviť"</string>
@@ -1612,6 +1613,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Prijať hovor?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vždy"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Len raz"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavenia"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Spúšťač %1$s nepodporuje pracovné profily"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televízor"</string>
@@ -1693,7 +1695,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Ak chcete používať službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, pridržte tri sekundy oba klávesy hlasitosti"</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>
@@ -2045,5 +2047,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparát"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofón"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"sa zobrazuje cez ďalšie aplikácie na obrazovke"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Upozornenie s informáciami o rutinnom režime"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Batéria sa môže vybiť pred obvyklým nabitím"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Bol aktivovaný šetrič batérie na predĺženie výdrže batérie"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Načítava sa"</string>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index dcaa4f5..9c20748 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -539,11 +539,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Aplikaciji omogoča branje lokacij v predstavnostni zbirki."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Aplikacija <xliff:g id="APP">%s</xliff:g> želi preveriti pristnost."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Strojna oprema za biometrične podatke ni na voljo"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Preverjanje pristnosti je preklicano"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Ni prepoznano"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Preverjanje pristnosti je preklicano"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Zaznan delni prstni odtis. Poskusite znova."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Prstnega odtisa ni bilo mogoče obdelati. Poskusite znova."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Tipalo prstnih odtisov je umazano. Očistite ga in poskusite znova."</string>
@@ -1168,6 +1166,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Odpiranje z aplikacijo"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Odpiranje z aplikacijo %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Odpiranje"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Omogočanje dostopa za odpiranje povezav <xliff:g id="HOST">%1$s</xliff:g> z aplikacijo"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Omogočanje dostopa za odpiranje povezav <xliff:g id="HOST">%1$s</xliff:g> z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Omogoči dostop"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Urejanje z aplikacijo"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Urejanje z aplikacijo %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Urejanje"</string>
@@ -1612,6 +1613,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Ali želite sprejeti klic?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Vedno"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo tokrat"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavitve"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podpira delovnega profila"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablični računalnik"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televizor"</string>
@@ -1693,7 +1695,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Za uporabo storitve <xliff:g id="SERVICE_NAME">%1$s</xliff:g> pritisnite obe tipki za glasnost in ju pridržite tri sekunde"</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>
@@ -2045,5 +2047,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Fotoaparat"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"prekriva druge aplikacije na zaslonu"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Rutinsko informativno obvestilo o načinu delovanja"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Akumulator se bo morda izpraznil, preden ga običajno priključite na polnjenje"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Vklopilo se je varčevanje z energijo akumulatorja za podaljšanje časa delovanja akumulatorja"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Nalaganje"</string>
 </resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 413ff8a..222b1d2 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Lejon aplikacionin të lexojë vendndodhjet nga koleksioni yt i medias."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Aplikacioni <xliff:g id="APP">%s</xliff:g> dëshiron të vërtetojë."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Nuk ofrohet harduer biometrik"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Vërtetimi u anulua"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Nuk njihet"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Vërtetimi u anulua"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"U zbulua një gjurmë gishti e pjesshme. Provo përsëri."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Gjurma e gishtit nuk mund të përpunohej. Provo përsëri."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sensori i gjurmës së gishtit nuk është i pastër. Pastroje dhe provo përsëri."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Hap me"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Hap me %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Hap"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Jep qasje për të hapur lidhjet e <xliff:g id="HOST">%1$s</xliff:g> me"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Jep qasje për të hapur lidhjet e <xliff:g id="HOST">%1$s</xliff:g> me <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Jep qasje"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Redakto me"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redakto me %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Redakto"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Dëshiron ta pranosh telefonatën?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Gjithmonë"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Vetëm një herë"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Cilësimet"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nuk e mbështet profilin e punës"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Televizori"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Shtyp dhe mbaj shtypur të dy butonat e volumit për tre sekonda për të përdorur <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofoni"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"po shfaqet mbi aplikacionet e tjera në ekranin tënd"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Njoftimi i informacionit të \"Modalitetit rutinë\""</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Bateria mund të mbarojë përpara ngarkimit të zakonshëm"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"\"Kursyesi i baterisë\" u aktivizua për të zgjatur jetëgjatësinë e baterisë"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Po ngarkohet"</string>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 8f8fe0e..58fde19 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -536,11 +536,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Дозвољава апликацији да чита локације из медијске колекције."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Апликација <xliff:g id="APP">%s</xliff:g> жели да потврди ваш идентитет."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Биометријски хардвер није доступан"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Потврда идентитета је отказана"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Није препознато"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Потврда идентитета је отказана"</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>
@@ -1148,6 +1146,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Отворите помоћу"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отворите помоћу апликације %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отвори"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Дозволите да се линкови <xliff:g id="HOST">%1$s</xliff:g> отварају помоћу"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Дозволите да <xliff:g id="APPLICATION">%2$s</xliff:g> отвара линикове <xliff:g id="HOST">%1$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволи приступ"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Измените помоћу"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Измените помоћу апликације %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Измени"</string>
@@ -1589,6 +1590,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Желите ли да прихватите позив?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Увек"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Само једном"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Подешавања"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не подржава пословни профил"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Таблет"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ТВ"</string>
@@ -1669,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"Притисните и задржите оба тастера за јачину звука три секунде да бисте користили <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -2010,5 +2012,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Микрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"приказује се на екрану док користите друге апликације"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Обавештење о информацијама Рутинског режима"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Батерија ће се можда испразнити пре уобичајеног пуњења"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Уштеда батерије је активирана да би се продужило трајање батерије"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Учитава се"</string>
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index cd5580d..2412f64 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Tillåter att appen läser av platser i din mediesamling."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Appen <xliff:g id="APP">%s</xliff:g> vill autentisera"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrisk maskinvara är inte tillgänglig"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autentiseringen avbröts"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Identifierades inte"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autentiseringen avbröts"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Ofullständigt fingeravtryck. Försök igen."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Det gick inte att bearbeta fingeravtrycket. Försök igen."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingeravtryckssensorn är smutsig. Rengör den och försök igen."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Öppna med"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Öppna med %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Öppna"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Tillåt att länkar från <xliff:g id="HOST">%1$s</xliff:g> öppnas med"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Tillåt att länkar från <xliff:g id="HOST">%1$s</xliff:g> öppnas med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Ge åtkomst"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Redigera med"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redigera med %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Redigera"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vill du ta emot samtal?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Bara en gång"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Inställningar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s har inte stöd för arbetsprofil"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Surfplatta"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Tryck och håll båda volymknapparna i tre sekunder för att använda <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"visar över andra appar på mobilen"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Avisering om rutinläge"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Batteriet kan ta slut innan du brukar ladda det"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batterisparläget har aktiverats för att utöka batteritiden"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Läser in"</string>
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index bc3e4ad..2e2904d 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Inaruhusu programu kusoma maeneo kwenye mkusanyiko wa vipengee vyako."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Programu ya <xliff:g id="APP">%s</xliff:g> inataka kuthibitishwa."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Maunzi ya bayometriki hayapatikani"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Imeghairi uthibitishaji"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Hayatambuliki"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Imeghairi uthibitishaji"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Kitambuzi kimegundua sehemu ya kitambulisho. Tafadhali jaribu tena."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Haikuweza kuchakata kitambulisho. Tafadhali jaribu tena."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Kitambuzi alama ya kidole ni kichafu. Tafadhali kisafishe na ujaribu tena."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Fungua ukitumia"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Fungua ukitumia %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Fungua"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Ipe <xliff:g id="HOST">%1$s</xliff:g> ruhusa ya kufungua viungo kwa kutumia"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Ipe <xliff:g id="HOST">%1$s</xliff:g> ruhusa ya kufungua viungo kwa kutumia <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Idhinisha ufikiaji"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Badilisha kwa"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Badilisha kwa %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Badilisha"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Kubali simu?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Kila mara"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Mara moja tu"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Mipangilio"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s haitumii wasifu wa kazini"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Kompyuta kibao"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Runinga"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Bonyeza na ushikilie vitufe vyote viwili vya sauti kwa sekunde tatu ili utumie <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Maikrofoni"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"inachomoza kwenye programu zingine katika skrini yako"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Arifa ya maelezo ya Hali ya Kawaida"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Huenda betri itakwisha chaji mapema"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Imewasha Kiokoa Betri ili kurefusha muda wa matumizi ya betri"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Inapakia"</string>
 </resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 22da7b0..b3c2ebf 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"உங்களின் மீடியா தொகுப்பிலிருந்து இடங்களை அறிந்துகொள்ள ஆப்ஸை அனுமதிக்கும்."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g>ஐப் பயன்படுத்த அங்கீகாரத்தை உறுதிசெய்க."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"பயோமெட்ரிக் வன்பொருள் இல்லை"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"அங்கீகரிப்பு ரத்தானது"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"அடையாளங்காணபடவில்லை"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"அங்கீகரிப்பு ரத்தானது"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"இதன்மூலம் திற"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s மூலம் திற"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"திற"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"மூலம் <xliff:g id="HOST">%1$s</xliff:g> இணைப்புகளைத் திறப்பதற்கான அணுகலை வழங்குதல்"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> மூலம் <xliff:g id="HOST">%1$s</xliff:g> இணைப்புகளைத் திறப்பதற்கான அணுகலை வழங்குதல்"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"அணுகலை வழங்கு"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"இதன் மூலம் திருத்து"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s மூலம் திருத்து"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"மாற்று"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"அழைப்பை ஏற்கவா?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"எப்போதும்"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"இப்போது மட்டும்"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"அமைப்புகள்"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s பணி சுயவிவரத்தை ஆதரிக்காது"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"டேப்லெட்"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"டிவி"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐப் பயன்படுத்த 3 விநாடிகளுக்கு இரண்டு ஒலியளவு பட்டன்களையும் அழுத்திப் பிடிக்கவும்"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"கேமரா"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"மைக்ரோஃபோன்"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"உங்கள் திரையில் உள்ள பிற பயன்பாடுகளின் மேல் காட்டுகிறது"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"வழக்கமான பேட்டரி சேமிப்பானுக்கான விவர அறிவிப்பு"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"வழக்கமாகச் சார்ஜ் செய்வதற்கு முன்பே பேட்டரி தீர்ந்துபோகக்கூடும்"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"பேட்டரி நிலையை நீட்டிக்க பேட்டரி சேமிப்பான் இயக்கப்பட்டுள்ளது"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"ஏற்றுகிறது"</string>
 </resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 1cc0274..5d8c0a8 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవడానికి యాప్‌ను అనుమతిస్తుంది."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"అప్లికేషన్ <xliff:g id="APP">%s</xliff:g>కు ప్రమాణీకరణ అవసరం."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"బయోమెట్రిక్ హార్డ్‌వేర్‌ అందుబాటులో లేదు"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ప్రమాణీకరణ రద్దు చేయబడింది"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"గుర్తించలేదు"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"ప్రమాణీకరణ రద్దు చేయబడింది"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"దీనితో తెరువు"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sతో తెరువు"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"తెరువు"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> లింక్‌లను తెరవడానికి యాక్సెస్ ఇవ్వండి"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g>తో <xliff:g id="HOST">%1$s</xliff:g> లింక్‌లను తెరవడానికి యాక్సెస్ ఇవ్వండి"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"యాక్సెస్ ఇవ్వండి"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"దీనితో సవరించు"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sతో సవరించు"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"సవరించు"</string>
@@ -1525,7 +1526,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"మరిన్ని ఎంపికలు"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="3570990907910199483">"అంతర్గత భాగస్వామ్య నిల్వ"</string>
+    <string name="storage_internal" msgid="3570990907910199483">"షేర్ చేయబడిన అంతర్గత నిల్వ"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD కార్డు"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD కార్డ్"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB డ్రైవ్"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"కాల్‌ను ఆమోదించాలా?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ఎల్లప్పుడూ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"ఒకసారి"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"సెట్టింగ్‌లు"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s కార్యాలయ ప్రొఫైల్‌కు మద్దతు ఇవ్వదు"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"టాబ్లెట్"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"టీవీ"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ని ఉపయోగించడానికి వాల్యూమ్ కీలు రెండింటినీ 3 సెకన్లు నొక్కి ఉంచండి"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"కెమెరా"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"మైక్రోఫోన్"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"మీ స్క్రీన్‌పై ఇతర యాప్‌ల ద్వారా ప్రదర్శించబడుతోంది"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"రొటీన్ మోడ్ సమాచార నోటిఫికేషన్"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"మామూలుగా ఛార్జ్ చేసేలోపు బ్యాటరీ ఖాళీ కావచ్చు"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"బ్యాటరీ జీవితకాలాన్ని పెంచడానికి బ్యాటరీ సేవర్ యాక్టివేట్ చేయబడింది"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"లోడవుతోంది"</string>
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 2edf57c..427793a 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"อนุญาตให้แอปอ่านตำแหน่งจากคอลเล็กชันสื่อของคุณ"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"แอปพลิเคชัน <xliff:g id="APP">%s</xliff:g> ต้องการตรวจสอบสิทธิ์"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ฮาร์ดแวร์ไบโอเมตริกไม่พร้อมใช้งาน"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ยกเลิกการตรวจสอบสิทธิ์แล้ว"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"ไม่รู้จัก"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"ยกเลิกการตรวจสอบสิทธิ์แล้ว"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"เปิดด้วย"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"เปิดด้วย %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"เปิด"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"ให้สิทธิ์ในการเปิดลิงก์ของ <xliff:g id="HOST">%1$s</xliff:g> โดยใช้"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"ให้สิทธิ์ในการเปิดลิงก์ของ <xliff:g id="HOST">%1$s</xliff:g> โดยใช้ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ให้สิทธิ์"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"แก้ไขด้วย"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"แก้ไขด้วย %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"แก้ไข"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"รับสายหรือไม่"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ทุกครั้ง"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"เฉพาะครั้งนี้"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"การตั้งค่า"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ไม่สนับสนุนโปรไฟล์งาน"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"แท็บเล็ต"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"ทีวี"</string>
@@ -1645,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"กดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 3 วินาทีเพื่อใช้ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"กล้อง"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"ไมโครโฟน"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"แสดงทับแอปอื่นๆ บนหน้าจอ"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"การแจ้งเตือนข้อมูลโหมดกิจวัตร"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"แบตเตอรี่อาจหมดก่อนการชาร์จปกติ"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"เปิดใช้งานโหมดประหยัดแบตเตอรี่แล้วเพื่อยืดอายุการใช้งานแบตเตอรี่"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"กำลังโหลด"</string>
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index f7995f7..cd4818f6 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Pinapayagan ang app na basahin ang mga lokasyon mula sa iyong koleksyon ng media."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Gustong mag-authenticate ng app na <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Walang biometric hardware"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Nakansela ang pag-authenticate"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Hindi nakilala"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Nakansela ang pag-authenticate"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Hindi buo ang natukoy na fingerprint. Pakisubukang muli."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Hindi maproseso ang fingerprint. Pakisubukang muli."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Marumi ang sensor ng fingerprint. Pakilinis at subukang muli."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Buksan gamit ang"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buksan gamit ang %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buksan"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Magbigay ng access para buksan ang mga link ng <xliff:g id="HOST">%1$s</xliff:g> sa"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Magbigay ng access para buksan ang mga link ng <xliff:g id="HOST">%1$s</xliff:g> sa <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Bigyan ng access"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"I-edit gamit ang"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"I-edit gamit ang %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"I-edit"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Tanggapin ang tawag?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Palagi"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Isang beses lang"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Mga Setting"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Hindi sinusuportahan ng %1$s ang profile sa trabaho"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Pindutin nang matagal ang parehong volume key sa loob ng tatlong segundo para magamit ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Camera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikropono"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ipinapakita sa ibabaw ng ibang app sa iyong screen"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Notification ng impormasyon ng Routine Mode"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Maaaring maubos ang baterya bago ang karaniwang pag-charge"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Na-activate ang Pangtipid sa Baterya para patagalin ang buhay ng baterya"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Naglo-load"</string>
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 761eba6..92d3ba6 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Uygulamanın medya koleksiyonunuzdaki konumları okumasına izin verir."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> uygulaması kimlik doğrulamak istiyor."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biyometrik donanım kullanılamıyor"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Kimlik doğrulama iptal edildi"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Tanınmadı"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Kimlik doğrulama iptal edildi"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Parmak izinin tümü algılanamadı. Lütfen tekrar deneyin."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Parmak izi işlenemedi. Lütfen tekrar deneyin."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Parmak izi sensörü kirli. Lütfen temizleyin ve tekrar deneyin."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Şununla aç:"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ile aç"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Aç"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Şununla <xliff:g id="HOST">%1$s</xliff:g> bağlantılarını açma izni verin"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasıyla <xliff:g id="HOST">%1$s</xliff:g> bağlantılarını açma izni verin"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Erişim ver"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Şununla düzenle:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ile düzenle"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Düzenle"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Çağrı kabul edilsin mi?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Her zaman"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Yalnızca bir defa"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ayarlar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s, iş profilini desteklemiyor"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kullanmak için her iki ses tuşunu basılı tutun"</string>
     <string name="accessibility_button_prompt_text" msgid="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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ekranınızdaki diğer uygulamaların üzerinde görüntüleniyor"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Rutin Modu bilgi bildirimi"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Pil normal şarjdan önce bitebilir"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Pilin ömrünü uzatmak için Pil Tasarrufu etkinleştirildi"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Yükleniyor"</string>
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index e7e99ae..80927ae 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -539,11 +539,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Додаток зможе розпізнавати геодані з вашої колекції медіа-вмісту."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Для додатка <xliff:g id="APP">%s</xliff:g> потрібна автентифікація."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Біометричне апаратне забезпечення недоступне"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Автентифікацію скасовано"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Не розпізнано"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Автентифікацію скасовано"</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>
@@ -1168,6 +1166,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Відкрити за допомогою"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Відкрити за допомогою %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Відкрити"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Дозвольте відкривати посилання на сайт <xliff:g id="HOST">%1$s</xliff:g> у додатку"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Дозвольте відкривати посилання на сайт <xliff:g id="HOST">%1$s</xliff:g> у додатку <xliff:g id="APPLICATION">%2$s</xliff:g>."</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволити"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Редагувати за допомогою"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редагувати за допомогою %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Редагувати"</string>
@@ -1612,6 +1613,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Прийняти виклик?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Завжди"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Лише цього разу"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Налаштування"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не підтримує робочий профіль"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Планшетний ПК"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Телевізор"</string>
@@ -1693,7 +1695,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Щоб скористатися службою <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, утримуйте обидві клавіші гучності впродовж трьох секунд"</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>
@@ -2045,5 +2047,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Камера"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Мікрофон"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"показ поверх інших додатків на екрані"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Сповіщення про послідовнсть дій"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Акумулятор може розрядитися раніше ніж зазвичай"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Режим економії заряду акумулятора активовано для збільшення часу його роботи"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Завантаження"</string>
 </resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index e33f3f2..9c99929 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ایپ کو آپ کی میڈيا کے مجموعے سے مقامات پڑھنے کی اجازت دیتا ہے۔"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"ایپلیکیشن <xliff:g id="APP">%s</xliff:g> تصدیق کرنا چاہتی ہے۔"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"بایومیٹرک ہارڈ ویئر دستیاب نہیں ہے"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"تصدیق کا عمل منسوخ ہو گیا"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"تسلیم شدہ نہیں ہے"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"تصدیق کا عمل منسوخ ہو گیا"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"اس کے ساتھ کھولیں"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏%1$s کے ساتھ کھولیں"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"کھولیں"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"اس کے ساتھ <xliff:g id="HOST">%1$s</xliff:g> لنکس کو کھولنے کے لیے رسائی ديں"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="APPLICATION">%2$s</xliff:g> کے ساتھ <xliff:g id="HOST">%1$s</xliff:g> لنکس کو کھولنے کے لیے رسائی ديں"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"رسائی دیں"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"اس کے ساتھ ترمیم کریں"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏%1$s کے ساتھ ترمیم کریں"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"ترمیم کریں"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"کال قبول کریں؟"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"ہمیشہ"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"بس ایک مرتبہ"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"ترتیبات"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏%1$s دفتری پروفائل کا تعاون نہیں کرتا ہے"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"ٹیبلیٹ"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> کا استعمال کرنے کے لیے 3 سیکنڈ تک والیوم کی دونوں کلیدوں کو چھوئیں اور دبائے رکھیں"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"کیمرا"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"مائیکروفون"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"آپ کی اسکرین پر دیگر ایپس پر دکھایا جا رہا ہے"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"روٹین موڈ معلومات کی اطلاع"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"معمول چارج سے پہلے بیٹری ختم ہو سکتی ہے"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"بیٹری لائف کو بڑھانے کے لیے بیٹری سیور کو فعال کر دیا گیا ہے"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"لوڈ ہو رہا ہے"</string>
 </resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 7742c3e..1b9982a 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Ilovaga multimedia to‘plamingizdan joylashuv axborotini o‘qishga ruxsat beradi."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g> ilovasi qurilma qulfini ochmoqchi."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrik sensor ishlamayapti"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Autentifikatsiya bekor qilindi"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Aniqlanmadi"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Autentifikatsiya bekor qilindi"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Barmoq izi qisman aniqlandi. Qayta urinib ko‘ring."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Barmoq izi aniqlanmadi. Qayta urinib ko‘ring."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Barmoq izi skaneri kirlangan. Uni tozalab, keyin qayta urinib ko‘ring."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Ochish…"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s bilan ochish"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ochish"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"<xliff:g id="HOST">%1$s</xliff:g> havolalarini ushbu ilova bilan ochishga ruxsat bering:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"<xliff:g id="HOST">%1$s</xliff:g> havolalarini <xliff:g id="APPLICATION">%2$s</xliff:g> bilan ochishga ruxsat bering"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Ruxsat berish"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Tahrirlash…"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"“%1$s” yordamida tahrirlash"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Tahrirlash"</string>
@@ -1567,6 +1568,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Qo‘ng‘iroqni qabul qilasizmi?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Har doim"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Faqat hozir"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Sozlamalar"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"“%1$s” ishchi profilni qo‘llab-quvvatlamaydi"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Planshet"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1646,7 +1648,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_shortcut_spoken_feedback" msgid="8376923232350078434">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmatidan foydalanish uchun ikkala ovoz balandligi tugmalarini uzoq bosib turing"</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>
@@ -1976,5 +1978,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Kamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Mikrofon"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"ekranda boshqa ilovalar ustidan ochiladi"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Kun tartibi rejimi haqidagi bildirishnoma"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Batareya quvvati odatdagidan ertaroq tugashi mumkin"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Batareya quvvati uzoqroq ishlashi uchun Tejamkor rejim yoqildi"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Yuklanmoqda"</string>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 86bb532..ca283aa 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Cho phép ứng dụng này đọc vị trí từ bộ sưu tập phương tiện của bạn."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Ứng dụng <xliff:g id="APP">%s</xliff:g> muốn xác thực."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Không có phần cứng sinh trắc học"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Đã hủy xác thực"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Không nhận dạng được"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Đã hủy xác thực"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Đã phát hiện được một phần vân tay. Vui lòng thử lại."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Không thể xử lý vân tay. Vui lòng thử lại."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Cảm biến vân tay bị bẩn. Hãy làm sạch và thử lại."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Mở bằng"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Mở bằng %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Mở"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Cấp quyền truy cập để mở đường dẫn liên kết <xliff:g id="HOST">%1$s</xliff:g> bằng"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Cấp quyền truy cập để mở đường dẫn liên kết <xliff:g id="HOST">%1$s</xliff:g> bằng <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Cấp quyền truy cập"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Chỉnh sửa bằng"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Chỉnh sửa bằng %1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Chỉnh sửa"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Chấp nhận cuộc gọi?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Luôn chọn"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Chỉ một lần"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Cài đặt"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s không hỗ trợ hồ sơ công việc"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Máy tính bảng"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Nhấn và giữ đồng thời cả hai phím âm lượng trong 3 giây để sử dụng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Máy ảnh"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Micrô"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"hiển thị qua các ứng dụng khác trên màn hình của bạn"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Thông báo cung cấp thông tin về chế độ sạc thông thường"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Pin có thể hết trước khi sạc bình thường"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Trình tiết kiệm pin được kích hoạt để kéo dài thời lượng pin"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Đang tải"</string>
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index dbb7834..c280ea8 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"允许该应用从您的媒体收藏中读取位置信息。"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"<xliff:g id="APP">%s</xliff:g>应用需要进行身份验证。"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"生物识别硬件无法使用"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"身份验证已取消"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"无法识别"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"身份验证已取消"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"打开方式"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"使用%1$s打开"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"打开"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"授权使用以下应用打开 <xliff:g id="HOST">%1$s</xliff:g> 链接:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"授权使用<xliff:g id="APPLICATION">%2$s</xliff:g>打开 <xliff:g id="HOST">%1$s</xliff:g> 链接"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"授予访问权限"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"编辑方式"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用%1$s编辑"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"编辑"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"要接听电话吗?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"始终"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"仅此一次"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"设置"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s不支持工作资料"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"平板电脑"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"电视"</string>
@@ -1645,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"同时按住两个音量键 3 秒钟即可使用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"相机"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"麦克风"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"显示在屏幕上其他应用的上层"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"日常安排模式信息通知"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"电池电量可能会在您平时的充电时间之前耗尽"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"已启用省电模式以延长电池续航时间"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"正在加载"</string>
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 6248db5..c2167b5 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"允許應用程式讀取媒體集的位置。"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"「<xliff:g id="APP">%s</xliff:g>」應用程式需要驗證。"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"無法使用生物識別硬件"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"已取消驗證"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"未能識別"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"已取消驗證"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"用於開啟的應用程式"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"使用 %1$s 開啟"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"開啟"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"授予存取權以透過以下應用程式開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結:"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"授予存取權以透過<xliff:g id="APPLICATION">%2$s</xliff:g>開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"授予存取權"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"使用以下選擇器編輯:"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"編輯"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"接聽電話嗎?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"一律採用"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"只此一次"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s 不支援公司檔案"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"平板電腦"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"電視"</string>
@@ -1645,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"㩒住兩個音量鍵 3 秒就可以用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"相機"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"麥克風"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"顯示在畫面上的其他應用程式上層"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"「日常安排模式」資料通知"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"電量可能會在日常充電前耗盡"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"「省電模式」已啟用,以便延長電池壽命"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"正在載入"</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 74da200..231a7e9 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"允許應用程式讀取你的媒體收藏的位置資訊。"</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"「<xliff:g id="APP">%s</xliff:g>」應用程式需要驗證使用者身分。"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"無法使用生物特徵辨識硬體"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"已取消驗證"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"無法辨識"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"已取消驗證"</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>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"選擇開啟工具"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"透過 %1$s 開啟"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"開啟"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"授權系統使用以下應用程式開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"授權系統使用「<xliff:g id="APPLICATION">%2$s</xliff:g>」開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"授予存取權"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"選擇編輯工具"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"編輯"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"接聽電話嗎?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"一律採用"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"僅限一次"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s 不支援工作設定檔"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"平板電腦"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"電視"</string>
@@ -1645,7 +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_shortcut_spoken_feedback" msgid="8376923232350078434">"同時按住調低及調高音量鍵三秒即可使用「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"相機"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"麥克風"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"顯示在畫面上的其他應用程式上層"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"日常安排模式資訊通知"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"電池電力可能會在你平常的充電時間前耗盡"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"已啟用節約耗電量模式以延長電池續航力"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"載入中"</string>
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 93b2ae6..0f570b0 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -533,11 +533,9 @@
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Ivumela uhlelo lokusebenza ukuthi lifunde izindawo kusukela kuqoqo lakho lemidiya."</string>
     <string name="biometric_dialog_default_title" msgid="4229778503907743328">"Uhlelo lokusebenza lwe-<xliff:g id="APP">%s</xliff:g> lifuna ukufakazela ubuqiniso."</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"I-Biometric hardware ayitholakali"</string>
-    <!-- no translation found for biometric_error_user_canceled (2260175018114348727) -->
-    <skip />
+    <string name="biometric_error_user_canceled" msgid="2260175018114348727">"Ukufakazela ubuqiniso kukhanseliwe"</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"Akwaziwa"</string>
-    <!-- no translation found for biometric_error_canceled (349665227864885880) -->
-    <skip />
+    <string name="biometric_error_canceled" msgid="349665227864885880">"Ukufakazela ubuqiniso kukhanseliwe"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Izigxivizo zeminwe ezincane zitholiwe. Sicela uzame futhi."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Ayikwazanga ukucubungula izigxivizo zeminwe. Sicela uzame futhi."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Inzwa yezigxivizo zeminwe ingcolile. Sicela uyihlanze uphinde uzame futhi."</string>
@@ -1128,6 +1126,9 @@
     <string name="whichViewApplication" msgid="3272778576700572102">"Vula nge-"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Vula nge-%1$s"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Kuvuliwe"</string>
+    <string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Nika ukufinyelela kuzixhumanisi ezivulekile ze-<xliff:g id="HOST">%1$s</xliff:g> nge-"</string>
+    <string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Nika ukufinyelela kuzixhumanisi ze-<xliff:g id="HOST">%1$s</xliff:g> ezivulekile nge-<xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
+    <string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Nikeza ukufinyel"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Hlela nge-"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Hlela nge-%1$s"</string>
     <string name="whichEditApplicationLabel" msgid="7183524181625290300">"Hlela"</string>
@@ -1566,6 +1567,7 @@
     <string name="SetupCallDefault" msgid="5834948469253758575">"Amukela ucingo?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Njalo"</string>
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Kanye nje"</string>
+    <string name="activity_resolver_app_settings" msgid="8965806928986509855">"Izilungiselelo"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ayisekeli iphrofayela yomsebenzi"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Ithebulethi"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"I-TV"</string>
@@ -1645,7 +1647,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_shortcut_spoken_feedback" msgid="8376923232350078434">"Cindezela uphinde ubambe bobabili okhiye bevolumu ngamasekhondi amathathu ukuze usebenzise i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</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>
@@ -1975,5 +1977,8 @@
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"Ikhamera"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"Imakrofoni"</string>
     <string name="notification_appops_overlay_active" msgid="633813008357934729">"iboniswa ngaphezulu kwezinye izinhlelo zokusebenza kusikrini sakho"</string>
+    <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Isaziso solwazi lwe-Routine Mode"</string>
+    <string name="dynamic_mode_notification_title" msgid="508815255807182035">"Ibhethri lingaphela ngaphambi kokushaja okuvamile"</string>
+    <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Isilondolozi sebhethri siyasebenza ngaphandle kwempilo yebhethri"</string>
     <string name="car_loading_profile" msgid="3545132581795684027">"Iyalayisha"</string>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 91faa55..fa3a549 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3660,7 +3660,12 @@
              the settings for this service. This setting cannot be changed at runtime. -->
         <attr name="settingsActivity" />
         <!-- Attribute whether the accessibility service wants to be able to retrieve the
-             active window content. This setting cannot be changed at runtime. -->
+             active window content. This setting cannot be changed at runtime.
+             <p>
+             Required to allow setting the {@link android.accessibilityservice
+             #AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag.
+             </p>
+         -->
         <attr name="canRetrieveWindowContent" format="boolean" />
         <!-- Attribute whether the accessibility service wants to be able to request touch
              exploration mode in which touched items are spoken aloud and the UI can be
@@ -3755,6 +3760,8 @@
         <!-- Component name of an activity that allows the user to modify
              the settings for this service. -->
         <attr name="settingsActivity"/>
+        <!-- Secure Element which the AIDs should be routed to -->
+        <attr name="secureElementName"/>
     </declare-styleable>
 
     <!-- Specify one or more <code>aid-group</code> elements inside a
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 54f6c63..de6468d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -274,6 +274,9 @@
         <!-- Additional flag from base permission type: this permission can be automatically
             granted to the document manager -->
         <flag name="documenter" value="0x40000" />
+        <!-- Additional flag from base permission type: this permission automatically
+            granted to device configurator -->
+        <flag name="configurator" value="0x80000" />
     </attr>
 
     <!-- Flags indicating more context for a permission group. -->
@@ -593,7 +596,7 @@
          to be set for all windows of this activity -->
     <attr name="showForAllUsers" format="boolean" />
 
-    <!-- Specifies whether an {@link android.app.Activity} should be shown on top of the the lock screen
+    <!-- Specifies whether an {@link android.app.Activity} should be shown on top of the lock screen
          whenever the lockscreen is up and the activity is resumed. Normally an activity will be
          transitioned to the stopped state if it is started while the lockscreen is up, but with
          this flag set the activity will remain in the resumed state visible on-top of the lock
@@ -947,6 +950,17 @@
          <p>The default value of this attribute is <code>false</code>. -->
     <attr name="allowEmbedded" format="boolean" />
 
+    <!-- @hide @SystemApi Specifies whether this {@link android.app.Activity} should be shown on
+         top of the lock screen whenever the lockscreen is up and this activity has another
+         activity behind it with the {@link android.R.attr#showWhenLocked} attribute set. That
+         is, this activity is only visible on the lock screen if there is another activity with
+         the {@link android.R.attr#showWhenLocked} attribute visible at the same time on the
+         lock screen. A use case for this is permission dialogs, that should only be visible on
+         the lock screen if their requesting activity is also visible.
+
+         <p>The default value of this attribute is <code>false</code>. -->
+    <attr name="inheritShowWhenLocked" format="boolean" />
+
     <!-- Descriptive text for the associated data. -->
     <attr name="description" format="reference" />
 
@@ -2412,6 +2426,7 @@
         <attr name="showForAllUsers" />
 
         <attr name="showWhenLocked" />
+        <attr name="inheritShowWhenLocked" />
         <attr name="turnScreenOn" />
 
         <attr name="directBootAware" />
@@ -2781,6 +2796,9 @@
         <attr name="requiredSystemPropertyName" format="string" />
         <!-- @hide This shouldn't be public. -->
         <attr name="requiredSystemPropertyValue" format="string" />
+
+        <!-- The name of the overlayable whose resources will be overlaid. -->
+        <attr name="targetName" />
     </declare-styleable>
 
     <!-- Declaration of an {@link android.content.Intent} object in XML.  May
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index ded916f..824b4b5 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -43,6 +43,6 @@
     <color name="error_color_device_default_dark">@color/error_color_material_dark</color>
     <color name="error_color_device_default_light">@color/error_color_material_light</color>
 
-    <color name="list_divider_color_light">#64000000</color>
+    <color name="list_divider_color_light">#ffdadce0</color>
     <color name="list_divider_color_dark">#85ffffff</color>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e4abf8f..dd8ecdb 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -126,6 +126,9 @@
          be sent during a change to the audio output device. -->
     <bool name="config_sendAudioBecomingNoisy">true</bool>
 
+    <!-- Whether Hearing Aid profile is supported -->
+    <bool name="config_hearing_aid_profile_supported">true</bool>
+
     <!-- Flag to disable all transition animations -->
     <bool name="config_disableTransitionAnimation">false</bool>
 
@@ -381,7 +384,7 @@
 
 
     <!-- Configuration of Ethernet interfaces in the following format:
-         <interface name|mac address>;[Network Capabilities];[IP config]
+         <interface name|mac address>;[Network Capabilities];[IP config];[Override Transport]
          Where
                [Network Capabilities] Optional. A comma seprated list of network capabilities.
                    Values must be from NetworkCapabilities#NET_CAPABILITIES_* constants.
@@ -389,11 +392,16 @@
                    use the following format to specify static IP configuration:
                        ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses>
                        domains=<comma-sep-domains>
+               [Override Transport] Optional. An override network transport type to allow
+                    the propagation of an interface type on the other end of a local Ethernet
+                    interface. Value must be from NetworkCapabilities#TRANSPORT_* constants. If
+                    left out, this will default to TRANSPORT_ETHERNET.
          -->
     <string-array translatable="false" name="config_ethernet_interfaces">
         <!--
         <item>eth1;12,13,14,15;ip=192.168.0.10/24 gateway=192.168.0.1 dns=4.4.4.4,8.8.8.8</item>
         <item>eth2;;ip=192.168.0.11/24</item>
+        <item>eth3;12,13,14,15;ip=192.168.0.12/24;1</item>
         -->
     </string-array>
 
@@ -525,6 +533,9 @@
     <!-- Boolean indicating whether the wifi chipset has dual frequency band support -->
     <bool translatable="false" name="config_wifi_dual_band_support">false</bool>
 
+    <!-- Maximum number of concurrent WiFi interfaces in AP mode -->
+    <integer translatable="false" name="config_wifi_max_ap_interfaces">1</integer>
+
     <!-- Boolean indicating whether the wifi chipset requires the softap band be -->
     <!-- converted from 5GHz to ANY due to hardware restrictions -->
     <bool translatable="false" name="config_wifi_convert_apband_5ghz_to_any">false</bool>
@@ -618,15 +629,6 @@
     <!-- Integer indicating wpa_supplicant scan interval when p2p is connected in milliseconds -->
     <integer translatable="false" name="config_wifi_scan_interval_p2p_connected">60000</integer>
 
-    <!-- Integer indicating the framework scan interval in milliseconds. This is used in the scenario
-         where the chipset does not support background scanning (config_wifi_background_scan_suport
-         is false) to set up a periodic wake up scan so that the device can connect to a new access
-         point on the move. A value of 0 means no periodic scans will be used in the framework. -->
-    <integer translatable="false" name="config_wifi_framework_scan_interval">300000</integer>
-
-    <!-- Integer indicating the framework no networks periodic scan interval in milliseconds. -->
-    <integer translatable="false" name="config_wifi_no_network_periodic_scan_interval">300000</integer>
-
     <!-- Integer indicating disconnect mode short scan interval in milliseconds -->
     <integer translatable="false" name="config_wifi_disconnected_short_scan_interval">15000</integer>
 
@@ -648,6 +650,9 @@
     <!-- Integer indicating RSSI boost given to current network -->
     <integer translatable="false" name="config_wifi_framework_current_network_boost">16</integer>
 
+    <!-- Integer delay in milliseconds before set wlan interface up during watchdog recovery -->
+    <integer translatable="false" name="config_wifi_framework_recovery_timeout_delay">2000</integer>
+
     <!-- Integer indicating how to handle beacons with uninitialized RSSI value of 0 -->
     <integer translatable="false" name="config_wifi_framework_scan_result_rssi_level_patchup_value">-85</integer>
 
@@ -692,6 +697,11 @@
     <!-- Wifi driver supports Automatic channel selection (ACS) for softap -->
     <bool translatable="false" name="config_wifi_softap_acs_supported">false</bool>
 
+    <!-- Channel list restriction to Automatic channel selection (ACS) for softap. If the device
+         doesn't want to restrict channels this should be empty. Value is a comma separated channel
+         string and/or channel range string like '1-6,11' -->
+    <string translatable="false" name="config_wifi_softap_acs_supported_channel_list"></string>
+
     <!-- Wifi driver supports IEEE80211AC for softap -->
     <bool translatable="false" name="config_wifi_softap_ieee80211ac_supported">false</bool>
 
@@ -699,10 +709,16 @@
          for automotive builds only (the one that have PackageManager#FEATURE_AUTOMOTIVE) -->
     <bool translatable="false" name="config_wifi_local_only_hotspot_5ghz">false</bool>
 
+    <!-- Indicates that connected MAC randomization is supported on this device -->
+    <bool translatable="false" name="config_wifi_connected_mac_randomization_supported">false</bool>
+
     <!-- Flag indicating whether we should enable the automatic brightness.
          Software implementation will be used if config_hardware_auto_brightness_available is not set -->
     <bool name="config_automatic_brightness_available">false</bool>
 
+    <!-- Flag indicating whether we should enable the adaptive sleep.-->
+    <bool name="config_adaptive_sleep_available">false</bool>
+
     <!-- Flag indicating whether we should enable smart battery. -->
     <bool name="config_smart_battery_available">false</bool>
 
@@ -929,8 +945,9 @@
          in hardware. -->
     <bool name="config_setColorTransformAccelerated">false</bool>
 
-    <!-- Boolean indicating whether display white balance is supported. -->
-    <bool name="config_displayWhiteBalanceAvailable">false</bool>
+    <!-- Boolean indicating whether the HWC setColorTransform function can be performed efficiently
+         in hardware for individual layers. -->
+    <bool name="config_setColorTransformAcceleratedPerLayer">false</bool>
 
     <!-- Control whether Night display is available. This should only be enabled on devices
          that have a HWC implementation that can apply the matrix passed to setColorTransform
@@ -987,6 +1004,44 @@
         <!-- B y-intercept --> <item>-0.198650895</item>
     </string-array>
 
+    <!-- Boolean indicating whether display white balance is supported. -->
+    <bool name="config_displayWhiteBalanceAvailable">false</bool>
+
+    <!-- Minimum color temperature, in Kelvin, supported by display white balance. -->
+    <integer name="config_displayWhiteBalanceColorTemperatureMin">4000</integer>
+
+    <!-- Maximum color temperature, in Kelvin, supported by display white balance. -->
+    <integer name="config_displayWhiteBalanceColorTemperatureMax">8000</integer>
+
+    <!-- Default color temperature, in Kelvin, used by display white balance. -->
+    <integer name="config_displayWhiteBalanceColorTemperatureDefault">6500</integer>
+
+    <!-- The display primaries, in CIE1931 XYZ color space, for display
+         white balance to use in its calculations. -->
+    <string-array name="config_displayWhiteBalanceDisplayPrimaries">
+        <!-- Red X -->   <item>0.412315</item>
+        <!-- Red Y -->   <item>0.212600</item>
+        <!-- Red Z -->   <item>0.019327</item>
+        <!-- Green X --> <item>0.357600</item>
+        <!-- Green Y --> <item>0.715200</item>
+        <!-- Green Z --> <item>0.119200</item>
+        <!-- Blue X -->  <item>0.180500</item>
+        <!-- Blue Y -->  <item>0.072200</item>
+        <!-- Blue Z -->  <item>0.950633</item>
+        <!-- White X --> <item>0.950456</item>
+        <!-- White Y --> <item>1.000000</item>
+        <!-- White Z --> <item>1.089058</item>
+    </string-array>
+
+    <!-- The nominal white coordinates, in CIE1931 XYZ color space, for Display White Balance to
+         use in its calculations. AWB will adapt this white point to the target ambient white
+         point. -->
+    <string-array name="config_displayWhiteBalanceDisplayNominalWhite">
+        <!-- Nominal White X --> <item>0.950456</item>
+        <!-- Nominal White Y --> <item>1.000000</item>
+        <!-- Nominal White Z --> <item>1.089058</item>
+    </string-array>
+
 
     <!-- Indicate available ColorDisplayController.COLOR_MODE_xxx. -->
     <integer-array name="config_availableColorModes">
@@ -1152,6 +1207,10 @@
          Settings.System.NOTIFICATION_VIBRATION_INTENSITY more details on the constant values and
          meanings. -->
     <integer name="config_defaultNotificationVibrationIntensity">2</integer>
+    <!-- The default intensity level for ring vibrations. See
+         Settings.System.RING_VIBRATION_INTENSITY more details on the constant values and
+         meanings. -->
+    <integer name="config_defaultRingVibrationIntensity">2</integer>
 
     <bool name="config_use_strict_phone_number_comparation">false</bool>
 
@@ -1169,7 +1228,7 @@
     <integer name="config_lowBatteryAutoTriggerDefaultLevel">15</integer>
 
     <!-- The app which will handle routine based automatic battery saver, if empty the UI for
-             routine based battery saver will be hidden -->
+         routine based battery saver will be hidden -->
     <string name="config_batterySaverScheduleProvider"></string>
 
     <!-- Close low battery warning when battery level reaches the lowBatteryWarningLevel
@@ -1404,6 +1463,13 @@
     <integer-array name="config_autoBrightnessLevels">
     </integer-array>
 
+    <!-- Timeout (in milliseconds) after which we remove the effects any user interactions might've
+         had on the brightness mapping. This timeout doesn't start until we transition to a
+         non-interactive display policy so that we don't reset while users are using their devices,
+         but also so that we don't erroneously keep the short-term model if the device is dozing
+         but the display is fully on. -->
+    <integer name="config_autoBrightnessShortTermModelTimeout">300000</integer>
+
     <!-- Array of output values for LCD backlight corresponding to the lux values
          in the config_autoBrightnessLevels array.  This array should have size one greater
          than the size of the config_autoBrightnessLevels array.
@@ -1643,6 +1709,8 @@
          config_enableFusedLocationOverlay is false. -->
     <string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
 
+    <string-array name="config_locationExtraPackageNames" translatable="false"></string-array>
+
     <!-- The package name of the default network recommendation app.
          A network recommendation provider must:
              * Be granted the SCORE_NETWORKS permission.
@@ -1844,6 +1912,8 @@
                cell broadcasting sms, and MMS. -->
     <bool name="config_sms_capable">true</bool>
 
+    <!-- TODO: STOPSHIP(b/110557011): Remove this from framework and overlays as we use
+         config_defaultRoleHolders now. -->
     <!-- Default SMS Application. This will be the default SMS application when
          the phone first boots. The user can then change the default app to one
          of their choosing.
@@ -1862,6 +1932,12 @@
          the behavior will be as though no app was named as an explicit default. -->
     <string name="default_browser" translatable="false"></string>
 
+    <!-- Default role holders. This will be an array of roles and package names of their default
+         holders, with each item in the format of "ROLE_NAME: PACKAGE_NAME_1, PACKAGE_NAME_2". -->
+    <string-array name="config_defaultRoleHolders" translatable="false">
+        <item>android.app.role.SMS: com.android.messaging</item>
+    </string-array>
+
     <!-- Enable/disable default bluetooth profiles:
         HSP_AG, ObexObjectPush, Audio, NAP -->
     <bool name="config_bluetooth_default_profiles">true</bool>
@@ -2157,6 +2233,9 @@
     <!-- Type of the double tap sensor. Empty if double tap is not supported. -->
     <string name="config_dozeDoubleTapSensorType" translatable="false"></string>
 
+    <!-- Type of the tap sensor. Empty if tap is not supported. -->
+    <string name="config_dozeTapSensorType" translatable="false"></string>
+
     <!-- Type of the long press sensor. Empty if long press is not supported. -->
     <string name="config_dozeLongPressSensorType" translatable="false"></string>
 
@@ -2754,6 +2833,9 @@
     <!-- Flag indicating which package name can access the persistent data partition -->
     <string name="config_persistentDataPackageName" translatable="false"></string>
 
+    <!-- Flag indicating which package name can access DeviceConfig table -->
+    <string name="config_deviceConfiguratorPackageName" translatable="false"></string>
+
     <!-- Flag indicating apps will skip sending hold request before merge. In this case
         IMS service implementation will do both.i.e.hold followed by merge. -->
     <bool name="skipHoldBeforeMerge">true</bool>
@@ -3388,7 +3470,7 @@
          See android.view.textclassifier.TextClassificationManager.
     -->
     <string name="config_defaultTextClassifierPackage" translatable="false"></string>
-    
+
     <!-- The package name for the default wellbeing app.
          This package must be trusted, as it has the permissions to control other applications
          on the device.
@@ -3396,6 +3478,12 @@
      -->
     <string name="config_defaultWellbeingPackage" translatable="false"></string>
 
+    <!-- The component name for the default system attention service.
+         This service must be trusted, as it can be activated without explicit consent of the user.
+         See android.attention.AttentionManagerService.
+    -->
+    <string name="config_defaultAttentionService" translatable="false"></string>
+
     <!-- The package name for the system's content capture service.
          This service must be trusted, as it can be activated without explicit consent of the user.
          If no service with the specified name exists on the device, content capture will be
@@ -3412,6 +3500,23 @@
     -->
     <string name="config_defaultAugmentedAutofillService" translatable="false"></string>
 
+    <!-- The package name for the system's app prediction service.
+         This service must be trusted, as it can be activated without explicit consent of the user.
+         Example: "com.android.intelligence/.AppPredictionService"
+    -->
+    <string name="config_defaultAppPredictionService" translatable="false"></string>
+
+    <!-- The package name for the system's content suggestions service.
+         Provides suggestions for text and image selection regions in snapshots of apps and should
+         be able to classify the type of entities in those selections.
+
+         This service must be trusted, as it can be activated without explicit consent of the user.
+         If no service with the specified name exists on the device, content suggestions wil be
+         disabled.
+         Example: "com.android.contentsuggestions/.ContentSuggestionsService"
+    -->
+    <string name="config_defaultContentSuggestionsService" translatable="false"></string>
+
     <!-- Whether the device uses the default focus highlight when focus state isn't specified. -->
     <bool name="config_useDefaultFocusHighlight">true</bool>
 
@@ -3633,7 +3738,7 @@
     <string name="config_inputEventCompatProcessorOverrideClassName" translatable="false"></string>
 
     <!-- Component name for the default module metadata provider on this device -->
-    <string name="config_defaultModuleMetadataProvider">com.android.modulemetadata</string>
+    <string name="config_defaultModuleMetadataProvider" translatable="false">com.android.modulemetadata</string>
 
     <!-- This is the default launcher component to use on secondary displays that support system
          decorations.
@@ -3641,4 +3746,20 @@
          set in AndroidManifest.
          {@see android.view.Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS} -->
     <string name="config_secondaryHomeComponent" translatable="false">com.android.launcher3/com.android.launcher3.SecondaryDisplayLauncher</string>
+
+    <!-- If device supports corner radius on windows.
+         This should be turned off on low-end devices to improve animation performance. -->
+    <bool name="config_supportsRoundedCornersOnWindows">true</bool>
+
+    <!-- If the sensor that skips media is available or not. -->
+    <bool name="config_skipSensorAvailable">false</bool>
+
+    <!-- If the sensor that silences alerts is available or not. -->
+    <bool name="config_silenceSensorAvailable">false</bool>
+
+    <!-- Enable Zram writeback feature to allow unused pages in zram be written to flash. -->
+    <bool name="config_zramWriteback">false</bool>
+
+    <!-- Whether cbrs is supported on the device or not -->
+    <bool translatable="false" name="config_cbrs_supported">false</bool>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 05a156b..c870683 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -194,9 +194,6 @@
     <!-- The margin for text at the end of the image view for media notifications -->
     <dimen name="notification_media_image_margin_end">72dp</dimen>
 
-    <!-- The additional margin on the sides of the ambient view. -->
-    <dimen name="notification_extra_margin_ambient">16dp</dimen>
-
     <!-- The height of the notification action list -->
     <dimen name="notification_action_list_height">60dp</dimen>
 
@@ -233,9 +230,6 @@
     <!-- The bottom padding for the notification header -->
     <dimen name="notification_header_padding_bottom">16dp</dimen>
 
-    <!-- The margin at the top of the notification header when dozing. -->
-    <dimen name="notification_header_margin_top_ambient">3dp</dimen>
-
     <!-- The margin at the bottom of the notification header. -->
     <dimen name="notification_header_margin_bottom">0dp</dimen>
 
@@ -400,11 +394,6 @@
     <dimen name="notification_title_text_size">14sp</dimen>
     <!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
     <dimen name="notification_subtext_size">12sp</dimen>
-    <!-- Size of notification text (see TextAppearance.StatusBar.EventContent) -->
-    <dimen name="notification_ambient_text_size">16sp</dimen>
-    <!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
-    <dimen name="notification_ambient_title_text_size">24sp</dimen>
-
     <!-- Top padding for notifications in the standard layout. -->
     <dimen name="notification_top_pad">10dp</dimen>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 799d9d8..4235341 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2934,6 +2934,8 @@
         <public name="foregroundServiceType" />
         <public name="hasFragileUserData" />
         <public name="minAspectRatio" />
+        <!-- @hide @SystemApi -->
+        <public name="inheritShowWhenLocked" />
     </public-group>
 
     <public-group type="drawable" first-id="0x010800b4">
@@ -2942,6 +2944,8 @@
     </public-group>
 
     <public-group type="style" first-id="0x010302e2">
+        <!-- @hide @SystemApi -->
+        <public name="Theme.DeviceDefault.DocumentsUI" />
     </public-group>
 
     <public-group type="id" first-id="0x01020046">
@@ -2983,6 +2987,11 @@
         <public name="system_notification_accent_color" />
     </public-group>
 
+    <public-group type="array" first-id="0x01070006">
+      <!-- @hide @SystemApi -->
+      <public name="config_defaultRoleHolders" />
+    </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 2b95dd0..65a8959 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3353,9 +3353,9 @@
     <string name="wifi_available_action_all_networks">All networks</string>
 
     <!-- Notification title for a connection to a app suggested wireless network.-->
-    <string name="wifi_suggestion_title">Connected to Wi\u2011Fi network proposed by <xliff:g id="name" example="App123">%s</xliff:g></string>
+    <string name="wifi_suggestion_title">A Wi\u2011Fi network proposed by <xliff:g id="name" example="App123">%s</xliff:g> is available</string>
     <!-- Notification content for a connection to a app suggested wireless network.-->
-    <string name="wifi_suggestion_content">Do you want to let <xliff:g id="name" example="App123">%s</xliff:g> propose networks for you?</string>
+    <string name="wifi_suggestion_content">Do you want to connect to networks proposed by <xliff:g id="name" example="App123">%s</xliff:g>?</string>
     <!-- Notification action for allowing app specified in the notification body.-->
     <string name="wifi_suggestion_action_allow_app">Yes</string>
     <!-- Notification action for disallowing app specified in the notification body.-->
@@ -3573,6 +3573,15 @@
     <string name="adb_active_notification_message">Tap to turn off USB debugging</string>
     <string name="adb_active_notification_message" product="tv">Select to disable USB debugging.</string>
 
+    <!-- Title of notification shown when contaminant is detected on the USB port. [CHAR LIMIT=NONE] -->
+    <string name="usb_contaminant_detected_title">Liquid or debris in USB port</string>
+    <!-- Message of notification shown when contaminant is detected on the USB port. [CHAR LIMIT=NONE] -->
+    <string name="usb_contaminant_detected_message">USB port is automatically disabled. Tap to learn more.</string>
+    <!-- Title of notification shown when contaminant is no longer detected on the USB port. [CHAR LIMIT=NONE] -->
+    <string name="usb_contaminant_not_detected_title">Safe to use USB port</string>
+    <!-- Message of notification shown when contaminant is no longer detected on the USB port. [CHAR LIMIT=NONE] -->
+    <string name="usb_contaminant_not_detected_message">Phone no longer detects liquid or debris.</string>
+
     <!-- Title of notification shown to indicate that bug report is being collected. -->
     <string name="taking_remote_bugreport_notification_title">Taking bug report\u2026</string>
     <!-- Title of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
@@ -4436,7 +4445,8 @@
         <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>
+    <string name="accessibility_shortcut_spoken_feedback">Press and hold both volume keys for three seconds to use
+        <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g></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>
@@ -5237,6 +5247,15 @@
     <!-- Content description of the overlay icon in the notification. [CHAR LIMIT=NONE] -->
     <string name="notification_appops_overlay_active">displaying over other apps on your screen</string>
 
+    <!-- Dynamic mode battery saver strings -->
+    <!-- The user visible name of the notification channel for the routine mode battery saver fyi notification [CHAR_LIMIT=80]-->
+    <string name="dynamic_mode_notification_channel_name">Routine Mode info notification</string>
+    <!-- Title of notification letting users know why battery saver was turned on automatically [CHAR_LIMIT=NONE]-->
+    <string name="dynamic_mode_notification_title">Battery may run out before usual charge</string>
+    <!-- Summary of notification letting users know why battery saver was turned on automatically [CHAR_LIMIT=NONE]-->
+    <string name="dynamic_mode_notification_summary">Battery Saver activated to extend battery life</string>
+
+
     <!-- Strings for car -->
     <!-- String displayed when loading a user in the car [CHAR LIMIT=30] -->
     <string name="car_loading_profile">Loading</string>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 200ef2f..79afe69 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -271,9 +271,6 @@
     <style name="TextAppearance.DeviceDefault.Notification.Info" parent="TextAppearance.Material.Notification.Info">
         <item name="fontFamily">@string/config_bodyFontFamily</item>
     </style>
-    <style name="TextAppearance.DeviceDefault.Notification.Info.Ambient" parent="TextAppearance.Material.Notification.Info.Ambient">
-        <item name="fontFamily">@string/config_bodyFontFamily</item>
-    </style>
     <style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Material.Widget">
         <item name="fontFamily">@string/config_bodyFontFamily</item>
     </style>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 5a7199d..63ac0e6 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -487,10 +487,6 @@
 
     <style name="TextAppearance.Material.Notification.Time" parent="TextAppearance.Material.Notification.Info" />
 
-    <style name="TextAppearance.Material.Notification.Info.Ambient">
-        <item name="textSize">@dimen/notification_text_size</item>
-    </style>
-
     <style name="TextAppearance.Material.Notification.Emphasis">
         <item name="textColor">#66000000</item>
     </style>
@@ -1308,10 +1304,5 @@
         <item name="gravity">top</item>
     </style>
 
-    <style name="Notification.Header.Ambient">
-        <item name="layout_marginTop">@dimen/notification_header_margin_top_ambient</item>
-        <item name="gravity">top|center_horizontal</item>
-    </style>
-
 
 </resources>
diff --git a/core/res/res/values/styles_permission_controller.xml b/core/res/res/values/styles_permission_controller.xml
deleted file mode 100644
index 5a9d3e6..0000000
--- a/core/res/res/values/styles_permission_controller.xml
+++ /dev/null
@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2018 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<resources>
-    <!-- styles for the permission grant dialog. -->
-    <style name="PermissionGrantDialog">
-        <item name="background">?attr/windowBackground</item>
-        <item name="elevation">?attr/windowElevation</item>
-        <item name="layout_weight">@dimen/permissionGrantDialogWeight</item>
-        <item name="layout_width">@dimen/permissionGrantDialogWidth</item>
-    </style>
-
-    <style name="PermissionGrantTitleIcon">
-        <item name="layout_width">24dp</item>
-        <item name="layout_height">24dp</item>
-        <item name="layout_marginBottom">12dp</item>
-        <item name="tint">?attr/colorAccent</item>
-        <item name="scaleType">fitCenter</item>
-    </style>
-
-    <style name="PermissionGrantTitleMessage"
-           parent="@style/TextAppearance.DeviceDefault">
-        <item name="gravity">center</item>
-        <item name="textSize">20sp</item>
-        <item name="textColor">?attr/textColorPrimary</item>
-    </style>
-
-    <style name="PermissionGrantIndex"
-           parent="@style/TextAppearance.DeviceDefault">
-        <item name="paddingEnd">12dp</item>
-        <item name="singleLine">true</item>
-        <item name="textColor">?attr/textColorSecondary</item>
-    </style>
-
-    <style name="PermissionGrantDescription">
-        <item name="layout_marginStart">24dp</item>
-        <item name="layout_marginEnd">24dp</item>
-    </style>
-
-    <style name="PermissionGrantContent">
-        <item name="layout_marginStart">24dp</item>
-        <item name="layout_marginEnd">24dp</item>
-    </style>
-
-    <style name="PermissionGrantDetailMessage"
-           parent="@style/TextAppearance.DeviceDefault">
-        <item name="layout_marginTop">18dp</item>
-        <item name="textColor">?attr/textColorPrimary</item>
-        <item name="textSize">16sp</item>
-    </style>
-
-    <!-- styles for the permission review screen. -->
-    <style name="PermissionReviewDescription">
-        <item name="layout_marginTop">20dp</item>
-        <item name="layout_marginStart">24dp</item>
-        <item name="layout_marginBottom">16dp</item>
-        <item name="layout_marginEnd">24dp</item>
-    </style>
-
-    <style name="PermissionReviewTitleIcon">
-        <item name="layout_marginTop">4dp</item>
-        <item name="layout_width">36dp</item>
-        <item name="layout_height">36dp</item>
-        <item name="scaleType">fitCenter</item>
-    </style>
-
-    <style name="PermissionReviewTitleMessage"
-           parent="@style/TextAppearance.DeviceDefault">
-        <item name="paddingStart">22dp</item>
-        <item name="textSize">20sp</item>
-        <item name="textColor">?attr/textColorPrimary</item>
-    </style>
-
-    <style name="PermissionReviewSettings">
-        <item name="layout_marginStart">8dp</item>
-        <item name="layout_marginEnd">8dp</item>
-    </style>
-
-    <style name="PermissionReviewButtonBar">
-        <item name="layout_marginStart">24dp</item>
-        <item name="layout_marginEnd">16dp</item>
-        <item name="layout_marginBottom">4dp</item>
-    </style>
-</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e8cbf66..5991d88 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -325,6 +325,7 @@
   <java-symbol type="bool" name="config_forceDefaultOrientation" />
   <java-symbol type="bool" name="config_wifi_batched_scan_supported" />
   <java-symbol type="bool" name="config_wifi_softap_acs_supported" />
+  <java-symbol type="string" name="config_wifi_softap_acs_supported_channel_list" />
   <java-symbol type="bool" name="config_wifi_softap_ieee80211ac_supported" />
   <java-symbol type="bool" name="config_enableMultiUserUI"/>
   <java-symbol type="bool" name="config_enableNewAutoSelectNetworkUI"/>
@@ -421,6 +422,7 @@
   <java-symbol type="integer" name="config_wifi_framework_network_switch_tx_packet_threshold" />
   <java-symbol type="integer" name="config_wifi_framework_network_switch_rx_packet_threshold" />
   <java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
+  <java-symbol type="integer" name="config_wifi_framework_recovery_timeout_delay" />
   <java-symbol type="integer" name="config_bluetooth_max_advertisers" />
   <java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
   <java-symbol type="integer" name="config_bluetooth_max_connected_audio_devices" />
@@ -435,6 +437,7 @@
   <java-symbol type="integer" name="config_bluetooth_operating_voltage_mv" />
   <java-symbol type="bool" name="config_bluetooth_pan_enable_autoconnect" />
   <java-symbol type="bool" name="config_bluetooth_reload_supported_profiles_when_enabled" />
+  <java-symbol type="bool" name="config_hearing_aid_profile_supported" />
   <java-symbol type="integer" name="config_cursorWindowSize" />
   <java-symbol type="integer" name="config_drawLockTimeoutMillis" />
   <java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
@@ -458,9 +461,7 @@
   <java-symbol type="integer" name="config_toastDefaultGravity" />
   <java-symbol type="integer" name="config_triplePressOnPowerBehavior" />
   <java-symbol type="integer" name="config_shortPressOnSleepBehavior" />
-  <java-symbol type="integer" name="config_wifi_framework_scan_interval" />
   <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
-  <java-symbol type="integer" name="config_wifi_no_network_periodic_scan_interval" />
   <java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
   <java-symbol type="integer" name="config_windowOutsetBottom" />
   <java-symbol type="integer" name="db_connection_pool_size" />
@@ -1840,10 +1841,12 @@
   <java-symbol type="array" name="radioAttributes" />
   <java-symbol type="array" name="config_oemUsbModeOverride" />
   <java-symbol type="array" name="config_locationProviderPackageNames" />
+  <java-symbol type="array" name="config_locationExtraPackageNames" />
   <java-symbol type="array" name="config_testLocationProviders" />
   <java-symbol type="array" name="config_defaultNotificationVibePattern" />
   <java-symbol type="array" name="config_notificationFallbackVibePattern" />
   <java-symbol type="bool" name="config_useAttentionLight" />
+  <java-symbol type="bool" name="config_adaptive_sleep_available" />
   <java-symbol type="bool" name="config_animateScreenLights" />
   <java-symbol type="bool" name="config_automatic_brightness_available" />
   <java-symbol type="bool" name="config_smart_battery_available" />
@@ -1877,8 +1880,10 @@
   <java-symbol type="bool" name="config_supportLongPressPowerWhenNonInteractive" />
   <java-symbol type="bool" name="config_wifi_background_scan_support" />
   <java-symbol type="bool" name="config_wifi_dual_band_support" />
+  <java-symbol type="integer" name="config_wifi_max_ap_interfaces" />
   <java-symbol type="bool" name="config_wifi_convert_apband_5ghz_to_any" />
   <java-symbol type="bool" name="config_wifi_local_only_hotspot_5ghz" />
+  <java-symbol type="bool" name="config_wifi_connected_mac_randomization_supported" />
   <java-symbol type="bool" name="config_wifi_fast_bss_transition_enabled" />
   <java-symbol type="bool" name="config_wimaxEnabled" />
   <java-symbol type="bool" name="show_ongoing_ime_switcher" />
@@ -1964,6 +1969,7 @@
   <java-symbol type="integer" name="config_screenBrightnessDark" />
   <java-symbol type="integer" name="config_screenBrightnessDim" />
   <java-symbol type="integer" name="config_screenBrightnessDoze" />
+  <java-symbol type="integer" name="config_autoBrightnessShortTermModelTimeout" />
   <java-symbol type="integer" name="config_shutdownBatteryTemperature" />
   <java-symbol type="integer" name="config_undockedHdmiRotation" />
   <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
@@ -2099,6 +2105,10 @@
   <java-symbol type="string" name="usb_supplying_notification_title" />
   <java-symbol type="string" name="usb_unsupported_audio_accessory_title" />
   <java-symbol type="string" name="usb_unsupported_audio_accessory_message" />
+  <java-symbol type="string" name="usb_contaminant_detected_title" />
+  <java-symbol type="string" name="usb_contaminant_detected_message" />
+  <java-symbol type="string" name="usb_contaminant_not_detected_title" />
+  <java-symbol type="string" name="usb_contaminant_not_detected_message" />
   <java-symbol type="string" name="config_UsbDeviceConnectionHandling_component" />
   <java-symbol type="string" name="vpn_text" />
   <java-symbol type="string" name="vpn_text_long" />
@@ -2138,6 +2148,7 @@
   <java-symbol type="string" name="config_carrierAppInstallDialogComponent" />
   <java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
   <java-symbol type="string" name="config_persistentDataPackageName" />
+  <java-symbol type="string" name="config_deviceConfiguratorPackageName" />
 
   <java-symbol type="layout" name="resolver_list" />
   <java-symbol type="id" name="resolver_list" />
@@ -3000,6 +3011,7 @@
   <java-symbol type="array" name="config_emergency_mcc_codes" />
 
   <java-symbol type="string" name="config_dozeDoubleTapSensorType" />
+  <java-symbol type="string" name="config_dozeTapSensorType" />
   <java-symbol type="bool" name="config_dozePulsePickup" />
 
   <!-- Used for MimeIconUtils. -->
@@ -3028,6 +3040,7 @@
   <java-symbol type="drawable" name="ic_doc_generic" />
 
   <java-symbol type="bool" name="config_setColorTransformAccelerated" />
+  <java-symbol type="bool" name="config_setColorTransformAcceleratedPerLayer" />
   <java-symbol type="bool" name="config_displayWhiteBalanceAvailable" />
   <java-symbol type="bool" name="config_nightDisplayAvailable" />
   <java-symbol type="bool" name="config_allowDisablingAssistDisclosure" />
@@ -3041,6 +3054,13 @@
   <java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficientsNative" />
   <java-symbol type="array" name="config_availableColorModes" />
 
+  <java-symbol type="bool" name="config_displayWhiteBalanceAvailable" />
+  <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMin" />
+  <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMax" />
+  <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureDefault" />
+  <java-symbol type="array" name="config_displayWhiteBalanceDisplayPrimaries" />
+  <java-symbol type="array" name="config_displayWhiteBalanceDisplayNominalWhite" />
+
   <!-- Default first user restrictions -->
   <java-symbol type="array" name="config_defaultFirstUserRestrictions" />
 
@@ -3065,8 +3085,6 @@
 
   <java-symbol type="dimen" name="config_appTransitionAnimationDurationScaleDefault" />
 
-  <java-symbol type="layout" name="notification_template_material_ambient" />
-
   <!-- Network Recommendation -->
   <java-symbol type="string" name="config_defaultNetworkRecommendationProviderPackage" />
 
@@ -3226,8 +3244,6 @@
   <java-symbol type="string" name="time_picker_text_input_mode_description"/>
   <java-symbol type="string" name="time_picker_radial_mode_description"/>
 
-  <java-symbol type="layout" name="notification_template_ambient_header" />
-
   <!-- resolver activity -->
   <java-symbol type="drawable" name="resolver_icon_placeholder" />
 
@@ -3274,6 +3290,9 @@
   <java-symbol type="string" name="config_defaultWellbeingPackage" />
   <java-symbol type="string" name="config_defaultContentCaptureService" />
   <java-symbol type="string" name="config_defaultAugmentedAutofillService" />
+  <java-symbol type="string" name="config_defaultAppPredictionService" />
+  <java-symbol type="string" name="config_defaultContentSuggestionsService" />
+  <java-symbol type="string" name="config_defaultAttentionService" />
 
   <java-symbol type="string" name="notification_channel_foreground_service" />
   <java-symbol type="string" name="foreground_service_app_in_background" />
@@ -3488,6 +3507,7 @@
 
   <java-symbol type="integer" name="config_defaultHapticFeedbackIntensity" />
   <java-symbol type="integer" name="config_defaultNotificationVibrationIntensity" />
+  <java-symbol type="integer" name="config_defaultRingVibrationIntensity" />
 
   <java-symbol type="bool" name="config_maskMainBuiltInDisplayCutout" />
 
@@ -3514,9 +3534,23 @@
   <java-symbol type="dimen" name="rounded_corner_radius" />
   <java-symbol type="dimen" name="rounded_corner_radius_top" />
   <java-symbol type="dimen" name="rounded_corner_radius_bottom" />
+  <java-symbol type="bool" name="config_supportsRoundedCornersOnWindows" />
 
   <java-symbol type="string" name="config_defaultModuleMetadataProvider" />
 
   <!-- For Secondary Launcher -->
   <java-symbol type="string" name="config_secondaryHomeComponent" />
+  
+  <java-symbol type="string" name="dynamic_mode_notification_channel_name" />
+  <java-symbol type="string" name="dynamic_mode_notification_title" />
+  <java-symbol type="string" name="dynamic_mode_notification_summary" />
+  <java-symbol type="drawable" name="ic_battery" />
+
+  <java-symbol type="bool" name="config_skipSensorAvailable" />
+  <java-symbol type="bool" name="config_silenceSensorAvailable" />
+
+  <java-symbol type="bool" name="config_zramWriteback" />
+
+  <!-- For CBRS -->
+  <java-symbol type="bool" name="config_cbrs_supported" />
 </resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 0f4ca66..1603508 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1454,12 +1454,17 @@
         <item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
 
         <!-- action bar -->
+        <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.Solid</item>
         <item name="actionBarTheme">@style/ThemeOverlay.DeviceDefault.ActionBar</item>
         <item name="popupTheme">@style/ThemeOverlay.DeviceDefault.Popup.Light</item>
 
         <!-- Color palette -->
+        <item name="colorBackground">@color/background_device_default_light</item>
+        <item name="colorPrimary">@color/primary_device_default_settings_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings_light</item>
         <item name="colorSecondary">@color/secondary_device_default_settings_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="colorError">@color/error_color_device_default_light</item>
         <item name="colorEdgeEffect">@android:color/black</item>
 
         <!-- Add white nav bar with divider that matches material -->
@@ -1467,9 +1472,16 @@
         <item name="navigationBarColor">@android:color/white</item>
         <item name="windowLightNavigationBar">true</item>
 
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+
         <!-- Button styles -->
+        <item name="buttonCornerRadius">@dimen/config_buttonCornerRadius</item>
         <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
 
+        <!-- Progress bar attributes -->
+        <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item>
+
         <item name="listDivider">@color/list_divider_color_light</item>
     </style>
 
@@ -1699,8 +1711,6 @@
         <item name="notificationHeaderTextAppearance">@style/TextAppearance.DeviceDefault.Notification.Info</item>
     </style>
 
-    <style name="Theme.DeviceDefault.Notification.Ambient" parent="@style/Theme.Material.Notification.Ambient">
-        <item name="notificationHeaderTextAppearance">@style/TextAppearance.DeviceDefault.Notification.Info.Ambient</item>
-    </style>
-
+    <!-- @hide DeviceDefault theme for the DocumentsUI app.  -->
+    <style name="Theme.DeviceDefault.DocumentsUI" parent="Theme.DeviceDefault.DayNight" />
 </resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index ccaf041..6b7698e 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -1341,14 +1341,6 @@
         <item name="notificationHeaderIconSize">@dimen/notification_header_icon_size</item>
     </style>
 
-    <!-- Theme for inflating ambient notification -->
-    <style name="Theme.Material.Notification.Ambient">
-        <item name="notificationHeaderStyle">@style/Notification.Header.Ambient</item>
-        <item name="notificationHeaderTextAppearance">@style/TextAppearance.Material.Notification.Info.Ambient</item>
-        <item name="notificationHeaderAppNameVisibility">gone</item>
-        <item name="notificationHeaderIconSize">@dimen/notification_header_icon_size_ambient</item>
-    </style>
-
     <!-- Default theme for Settings and activities launched from Settings. -->
     <style name="Theme.Material.Settings" parent="Theme.Material.Light.LightStatusBar">
         <item name="homeAsUpIndicator">@drawable/ic_ab_back_material_settings</item>
diff --git a/core/res/res/values/themes_permission_controller.xml b/core/res/res/values/themes_permission_controller.xml
deleted file mode 100644
index 205c4eb..0000000
--- a/core/res/res/values/themes_permission_controller.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2018 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<resources>
-    <!-- themes for the permission grant dialog. -->
-    <style name="Theme.DeviceDefault.PermissionGrantApp"
-           parent="@style/Theme.DeviceDefault.Light.Panel">
-        <item name="windowIsFloating">false</item>
-        <item name="windowTranslucentStatus">true</item>
-        <item name="backgroundDimEnabled">true</item>
-        <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
-    </style>
-
-    <style name="Theme.DeviceDefault.PermissionGrant"
-           parent="@style/Theme.DeviceDefault.Light.Dialog">
-        <item name="titleTextStyle">@style/PermissionGrantTitleMessage</item>
-    </style>
-
-    <!-- themes for the permission review dialog. -->
-    <style name="Theme.DeviceDefault.PermissionReviewApp"
-           parent="@style/Theme.DeviceDefault.Settings">
-        <item name="windowActionBar">false</item>
-        <item name="windowNoTitle">true</item>
-        <item name="titleTextStyle">@style/PermissionReviewTitleMessage</item>
-    </style>
-</resources>
diff --git a/core/tests/BroadcastRadioTests/Android.mk b/core/tests/BroadcastRadioTests/Android.mk
index 24f0cf0..6b0484e 100644
--- a/core/tests/BroadcastRadioTests/Android.mk
+++ b/core/tests/BroadcastRadioTests/Android.mk
@@ -25,7 +25,7 @@
 # LOCAL_SDK_VERSION := current
 LOCAL_PRIVATE_PLATFORM_APIS := true
 
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test testng
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util androidx.test.rules testng
 
 LOCAL_JAVA_LIBRARIES := android.test.base
 
diff --git a/core/tests/BroadcastRadioTests/AndroidManifest.xml b/core/tests/BroadcastRadioTests/AndroidManifest.xml
index d9b5522..ce12cc9 100644
--- a/core/tests/BroadcastRadioTests/AndroidManifest.xml
+++ b/core/tests/BroadcastRadioTests/AndroidManifest.xml
@@ -24,7 +24,7 @@
     </application>
 
     <instrumentation
-        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="android.hardware.radio.tests"
         android:label="Tests for Broadcast Radio APIs" >
     </instrumentation>
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
index fdaba08..11eb158 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
@@ -15,22 +15,29 @@
  */
 package android.hardware.radio.tests.functional;
 
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.testng.Assert.assertThrows;
+
 import android.Manifest;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
 import android.hardware.radio.RadioTuner;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
@@ -41,19 +48,10 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.atMost;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.testng.Assert.assertThrows;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * A test for broadcast radio API.
@@ -121,10 +119,9 @@
     }
 
     private void resetCallback() {
-        verify(mCallback, atLeast(0)).onMetadataChanged(any());
-        verify(mCallback, atLeast(0)).onProgramInfoChanged(any());
-        verify(mCallback, atLeast(0)).onProgramListChanged();
-        verifyNoMoreInteractions(mCallback);
+        verify(mCallback, never()).onError(anyInt());
+        verify(mCallback, never()).onTuneFailed(anyInt(), any());
+        verify(mCallback, never()).onControlChanged(anyBoolean());
         Mockito.reset(mCallback);
     }
 
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 041fb7e..0fc3bd2 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -36,14 +36,15 @@
     frameworks-core-util-lib \
     mockwebserver \
     guava \
-    android-support-test \
+    androidx.test.runner \
+    androidx.test.rules \
     mockito-target-minus-junit4 \
     espresso-core \
     ub-uiautomator \
     platform-test-annotations \
-    compatibility-device-util \
     truth-prebuilt \
-    print-test-util-lib
+    print-test-util-lib \
+    testng # TODO: remove once Android migrates to JUnit 4.12, which provide assertThrows
 
 LOCAL_JAVA_LIBRARIES := \
     android.test.runner \
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 46d4a47..86818c6 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -56,6 +56,7 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.READ_DREAM_STATE" />
     <uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
     <uses-permission android:name="android.permission.READ_LOGS"/>
@@ -65,6 +66,7 @@
     <uses-permission android:name="android.permission.USE_CREDENTIALS" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
@@ -1425,7 +1427,7 @@
 
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
             android:targetPackage="com.android.frameworks.coretests"
             android:label="Frameworks Core Tests" />
     <key-sets>
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
index 68ef34b..b40aa87 100644
--- a/core/tests/coretests/AndroidTest.xml
+++ b/core/tests/coretests/AndroidTest.xml
@@ -25,6 +25,7 @@
     <option name="test-tag" value="FrameworksCoreTests" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.frameworks.coretests" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
 </configuration>
diff --git a/core/tests/coretests/README b/core/tests/coretests/README
index ea282a0..34beb45 100644
--- a/core/tests/coretests/README
+++ b/core/tests/coretests/README
@@ -30,9 +30,9 @@
 
   adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
   adb shell am instrument -w \
-    com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+    com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
 
-To run a tests within a specific package, add the following argument AFTER -w:
+To run a tests within a specific package, add -e AFTER -w and before the runner class:
 
     -e package android.content.pm
 
diff --git a/core/tests/coretests/res/color/drawable_in_color_dir_invalid.xml b/core/tests/coretests/res/color/drawable_in_color_dir_invalid.xml
new file mode 100644
index 0000000..8d630b0
--- /dev/null
+++ b/core/tests/coretests/res/color/drawable_in_color_dir_invalid.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This drawable is purposely in the color directory to test a backwards compatible fallback. -->
+<layer-list
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@android:id/icon" android:drawable="@string/app_name" />
+</layer-list>
\ No newline at end of file
diff --git a/core/tests/coretests/res/color/drawable_in_color_dir_valid.xml b/core/tests/coretests/res/color/drawable_in_color_dir_valid.xml
new file mode 100644
index 0000000..d140475
--- /dev/null
+++ b/core/tests/coretests/res/color/drawable_in_color_dir_valid.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This drawable is purposely in the color directory to test a backwards compatible fallback. -->
+<layer-list
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@android:id/background" android:drawable="@drawable/test32x24" />
+    <item android:id="@android:id/icon" android:drawable="@drawable/test16x12" />
+</layer-list>
\ No newline at end of file
diff --git a/core/tests/coretests/res/raw/com_android_tzdata.apex b/core/tests/coretests/res/raw/com_android_tzdata.apex
new file mode 100644
index 0000000..72294de
--- /dev/null
+++ b/core/tests/coretests/res/raw/com_android_tzdata.apex
Binary files differ
diff --git a/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
index e26bdf5..be1d44c 100644
--- a/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java
@@ -13,17 +13,17 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
+
 package android.animation;
 
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase2;
 
+import androidx.test.filters.LargeTest;
+
+import com.android.frameworks.coretests.R;
+
 import java.util.HashSet;
 import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import com.android.frameworks.coretests.R;
 
 @LargeTest
 public class AnimatorInflaterTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity>  {
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetActivity.java b/core/tests/coretests/src/android/animation/AnimatorSetActivity.java
index 501ea48..af265af 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetActivity.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetActivity.java
@@ -1,10 +1,26 @@
-package android.animation;
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
-import com.android.frameworks.coretests.R;
+package android.animation;
 
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 public class AnimatorSetActivity extends Activity {
     @Override
     public void onCreate(Bundle savedBundleInstance) {
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java b/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
index 922bc59..55837ba 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
@@ -1,12 +1,29 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.animation;
 
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.View;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.SmallTest;
+
+import com.android.frameworks.coretests.R;
+
 import java.util.ArrayList;
 
 public class AnimatorSetActivityTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
index 7eb32ee..4e90d1a 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
@@ -13,12 +13,14 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
+
 package android.animation;
 
 import android.os.Handler;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.widget.Button;
+
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.util.concurrent.TimeUnit;
diff --git a/core/tests/coretests/src/android/animation/AutoCancelTest.java b/core/tests/coretests/src/android/animation/AutoCancelTest.java
index b1f88db..b3ec92c 100644
--- a/core/tests/coretests/src/android/animation/AutoCancelTest.java
+++ b/core/tests/coretests/src/android/animation/AutoCancelTest.java
@@ -13,11 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.animation;
 
 import android.os.Handler;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import java.util.HashMap;
 import java.util.concurrent.TimeUnit;
diff --git a/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
index 0e1e6ac..2b9866d 100644
--- a/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
+++ b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
@@ -13,14 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.animation;
 
-import com.android.frameworks.coretests.R;
+package android.animation;
 
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.Button;
 
+import com.android.frameworks.coretests.R;
+
 public class BasicAnimatorActivity extends Activity {
     public Button mAnimatingButton;
     @Override
diff --git a/core/tests/coretests/src/android/animation/EventsTest.java b/core/tests/coretests/src/android/animation/EventsTest.java
index 28cfe3d..ba7413a 100644
--- a/core/tests/coretests/src/android/animation/EventsTest.java
+++ b/core/tests/coretests/src/android/animation/EventsTest.java
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.animation;
 
 import android.os.Handler;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
 
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
diff --git a/core/tests/coretests/src/android/animation/FutureWaiter.java b/core/tests/coretests/src/android/animation/FutureWaiter.java
index 0c65e20..0c09a4a 100644
--- a/core/tests/coretests/src/android/animation/FutureWaiter.java
+++ b/core/tests/coretests/src/android/animation/FutureWaiter.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.animation;
 
 import com.google.common.util.concurrent.AbstractFuture;
diff --git a/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java b/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
index 606a939..53f9472 100644
--- a/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
+++ b/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
@@ -13,9 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.animation;
 
 import android.widget.Button;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/animation/StateListAnimatorTest.java b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
index a9961e1..e755b89 100644
--- a/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
+++ b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
@@ -14,16 +14,16 @@
 * limitations under the License.
 */
 
-
 package android.animation;
 
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
 import android.util.StateSet;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.util.concurrent.atomic.AtomicInteger;
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java b/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
index c25d050..f6d71b8 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.animation;
 
 /**
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
index 4facf77..dee0a3e 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -13,8 +13,11 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
+
 package android.animation;
 
+import static android.test.MoreAsserts.assertNotEqual;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
@@ -24,23 +27,20 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.SystemClock;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.Choreographer;
 import android.view.animation.LinearInterpolator;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 
-import static android.test.MoreAsserts.assertNotEqual;
-
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class ValueAnimatorTests {
diff --git a/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java b/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
index 30ec182..997af00 100644
--- a/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
+++ b/core/tests/coretests/src/android/animation/ViewPropertyAnimatorTest.java
@@ -13,15 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.animation;
 
 import android.os.Handler;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.ViewPropertyAnimator;
 import android.widget.Button;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.util.concurrent.TimeUnit;
diff --git a/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java b/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java
index 19a390a..8dc5ad6 100644
--- a/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java
+++ b/core/tests/coretests/src/android/app/ApplicationErrorReportTest.java
@@ -16,16 +16,17 @@
 
 package android.app;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import android.app.ApplicationErrorReport.CrashInfo;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.app.ApplicationErrorReport.CrashInfo;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class ApplicationErrorReportTest {
diff --git a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
index 063bef7..4b0ed65 100644
--- a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
+++ b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
@@ -16,13 +16,17 @@
 
 package android.app;
 
+import static android.os.storage.VolumeInfo.STATE_MOUNTED;
+import static android.os.storage.VolumeInfo.STATE_UNMOUNTED;
+
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
@@ -32,9 +36,6 @@
 import java.util.Arrays;
 import java.util.List;
 
-import static android.os.storage.VolumeInfo.STATE_MOUNTED;
-import static android.os.storage.VolumeInfo.STATE_UNMOUNTED;
-
 @LargeTest
 public class ApplicationPackageManagerTest extends TestCase {
     private static final String sInternalVolPath = "/data";
diff --git a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
index c1d4be0..33e0402 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
@@ -22,7 +22,8 @@
 import android.net.Uri;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import com.google.mockwebserver.MockResponse;
 
diff --git a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
index 39d9a8e..adfe76f 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
@@ -23,10 +23,11 @@
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.StatFs;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
diff --git a/core/tests/coretests/src/android/app/InstrumentationTest.java b/core/tests/coretests/src/android/app/InstrumentationTest.java
index 9b59da4..93b5aec 100644
--- a/core/tests/coretests/src/android/app/InstrumentationTest.java
+++ b/core/tests/coretests/src/android/app/InstrumentationTest.java
@@ -17,9 +17,10 @@
 package android.app;
 
 import android.os.Bundle;
-import android.support.test.filters.LargeTest;
 import android.test.InstrumentationTestCase;
 
+import androidx.test.filters.LargeTest;
+
 @LargeTest
 public class InstrumentationTest extends InstrumentationTestCase {
 
diff --git a/core/tests/coretests/src/android/app/LoaderLifecycleTest.java b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
index c83e798..e343383 100644
--- a/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
+++ b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 package android.app;
 
 import static junit.framework.TestCase.assertNotNull;
@@ -27,11 +26,12 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.Parcelable;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index e89a4d3..c17aa92 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -33,11 +33,12 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.widget.RemoteViews;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/SearchManagerTest.java b/core/tests/coretests/src/android/app/SearchManagerTest.java
index 08b7f60..14370c8 100644
--- a/core/tests/coretests/src/android/app/SearchManagerTest.java
+++ b/core/tests/coretests/src/android/app/SearchManagerTest.java
@@ -17,17 +17,13 @@
 package android.app;
 
 import android.app.activity.LocalActivity;
-
-import android.app.Activity;
-import android.app.ISearchManager;
-import android.app.SearchManager;
-import android.app.SearchableInfo;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.ServiceManager;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 /**
  * To launch this test from the command line:
diff --git a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
index 61d73bc..bbd442d 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java
@@ -21,8 +21,9 @@
 import android.content.pm.ConfigurationInfo;
 import android.content.res.Configuration;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
 
 import java.util.Iterator;
 import java.util.List;
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 1750dac..9cb3489 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -19,28 +19,36 @@
 import static android.content.Intent.ACTION_EDIT;
 import static android.content.Intent.ACTION_VIEW;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
 import android.app.ActivityThread;
 import android.app.IApplicationThread;
+import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.app.servertransaction.ActivityRelaunchItem;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.ClientTransactionItem;
 import android.app.servertransaction.ResumeActivityItem;
 import android.app.servertransaction.StopActivityItem;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.os.IBinder;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.MergedConfiguration;
+import android.view.Display;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.CountDownLatch;
+
 /**
  * Test for verifying {@link android.app.ActivityThread} class.
  * Build/Install/Run:
@@ -50,8 +58,12 @@
 @MediumTest
 public class ActivityThreadTest {
 
-    private final ActivityTestRule mActivityTestRule =
-            new ActivityTestRule(TestActivity.class, true /* initialTouchMode */,
+    // The first sequence number to try with. Use a large number to avoid conflicts with the first a
+    // few sequence numbers the framework used to launch the test activity.
+    private static final int BASE_SEQ = 10000;
+
+    private final ActivityTestRule<TestActivity> mActivityTestRule =
+            new ActivityTestRule<>(TestActivity.class, true /* initialTouchMode */,
                     false /* launchActivity */);
 
     @Test
@@ -129,6 +141,179 @@
         });
     }
 
+    @Test
+    public void testHandleActivityConfigurationChanged() {
+        final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            final int numOfConfig = activity.mNumOfConfigChanges;
+            applyConfigurationChange(activity, BASE_SEQ);
+            assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
+        });
+    }
+
+    @Test
+    public void testHandleActivityConfigurationChanged_DropStaleConfigurations() {
+        final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            // Set the sequence number to BASE_SEQ.
+            applyConfigurationChange(activity, BASE_SEQ);
+
+            final int orientation = activity.mConfig.orientation;
+            final int numOfConfig = activity.mNumOfConfigChanges;
+
+            // Try to apply an old configuration change.
+            applyConfigurationChange(activity, BASE_SEQ - 1);
+            assertEquals(numOfConfig, activity.mNumOfConfigChanges);
+            assertEquals(orientation, activity.mConfig.orientation);
+        });
+    }
+
+    @Test
+    public void testHandleActivityConfigurationChanged_ApplyNewConfigurations() {
+        final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            // Set the sequence number to BASE_SEQ and record the final sequence number it used.
+            final int seq = applyConfigurationChange(activity, BASE_SEQ);
+
+            final int orientation = activity.mConfig.orientation;
+            final int numOfConfig = activity.mNumOfConfigChanges;
+
+            // Try to apply an new configuration change.
+            applyConfigurationChange(activity, seq + 1);
+            assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
+            assertNotEquals(orientation, activity.mConfig.orientation);
+        });
+    }
+
+    @Test
+    public void testHandleActivityConfigurationChanged_PickNewerPendingConfiguration() {
+        final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            // Set the sequence number to BASE_SEQ and record the final sequence number it used.
+            final int seq = applyConfigurationChange(activity, BASE_SEQ);
+
+            final int orientation = activity.mConfig.orientation;
+            final int numOfConfig = activity.mNumOfConfigChanges;
+
+            final ActivityThread activityThread = activity.getActivityThread();
+
+            final Configuration pendingConfig = new Configuration();
+            pendingConfig.orientation = orientation == Configuration.ORIENTATION_LANDSCAPE
+                    ? Configuration.ORIENTATION_PORTRAIT
+                    : Configuration.ORIENTATION_LANDSCAPE;
+            pendingConfig.seq = seq + 2;
+            activityThread.updatePendingActivityConfiguration(activity.getActivityToken(),
+                    pendingConfig);
+
+            final Configuration newConfig = new Configuration();
+            newConfig.orientation = orientation;
+            newConfig.seq = seq + 1;
+
+            activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
+                    newConfig, Display.INVALID_DISPLAY);
+            assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
+            assertEquals(pendingConfig.orientation, activity.mConfig.orientation);
+        });
+    }
+
+    @Test
+    public void testHandleActivityConfigurationChanged_OnlyAppliesNewestConfiguration()
+            throws Exception {
+        final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+
+        final ActivityThread activityThread = activity.getActivityThread();
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            final Configuration config = new Configuration();
+            config.seq = BASE_SEQ;
+            config.orientation = Configuration.ORIENTATION_PORTRAIT;
+
+            activityThread.handleActivityConfigurationChanged(activity.getActivityToken(),
+                    config, Display.INVALID_DISPLAY);
+        });
+
+        final int numOfConfig = activity.mNumOfConfigChanges;
+        final IApplicationThread appThread = activityThread.getApplicationThread();
+
+        activity.mConfigLatch = new CountDownLatch(1);
+        activity.mTestLatch = new CountDownLatch(1);
+
+        Configuration config = new Configuration();
+        config.seq = BASE_SEQ + 1;
+        config.smallestScreenWidthDp = 100;
+        appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
+
+        // Wait until the main thread is performing the configuration change for the configuration
+        // with sequence number BASE_SEQ + 1 before proceeding. This is to mimic the situation where
+        // the activity takes very long time to process configuration changes.
+        activity.mTestLatch.await();
+
+        config = new Configuration();
+        config.seq = BASE_SEQ + 2;
+        config.smallestScreenWidthDp = 200;
+        appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
+
+        config = new Configuration();
+        config.seq = BASE_SEQ + 3;
+        config.smallestScreenWidthDp = 300;
+        appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
+
+        config = new Configuration();
+        config.seq = BASE_SEQ + 4;
+        config.smallestScreenWidthDp = 400;
+        appThread.scheduleTransaction(newActivityConfigTransaction(activity, config));
+
+        activity.mConfigLatch.countDown();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        activity.mConfigLatch = null;
+        activity.mTestLatch = null;
+
+        // Only two more configuration changes: one with seq BASE_SEQ + 1; another with seq
+        // BASE_SEQ + 4. Configurations scheduled in between should be dropped.
+        assertEquals(numOfConfig + 2, activity.mNumOfConfigChanges);
+        assertEquals(400, activity.mConfig.smallestScreenWidthDp);
+    }
+
+    /**
+     * Calls {@link ActivityThread#handleActivityConfigurationChanged(IBinder, Configuration, int)}
+     * to try to push activity configuration to the activity for the given sequence number.
+     * <p>
+     * It uses orientation to push the configuration and it tries a different orientation if the
+     * first attempt doesn't make through, to rule out the possibility that the previous
+     * configuration already has the same orientation.
+     *
+     * @param activity the test target activity
+     * @param seq the specified sequence number
+     * @return the sequence number this method tried with the last time, so that the caller can use
+     * the next sequence number for next configuration update.
+     */
+    private int applyConfigurationChange(TestActivity activity, int seq) {
+        final ActivityThread activityThread = activity.getActivityThread();
+
+        final int numOfConfig = activity.mNumOfConfigChanges;
+        Configuration config = new Configuration();
+        config.orientation = Configuration.ORIENTATION_PORTRAIT;
+        config.seq = seq;
+        activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config,
+                Display.INVALID_DISPLAY);
+
+        if (activity.mNumOfConfigChanges > numOfConfig) {
+            return config.seq;
+        }
+
+        config = new Configuration();
+        config.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        config.seq = seq + 1;
+        activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config,
+                Display.INVALID_DISPLAY);
+
+        return config.seq;
+    }
+
     private static ClientTransaction newRelaunchResumeTransaction(Activity activity) {
         final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null,
                 null, 0, new MergedConfiguration(), false /* preserveWindow */);
@@ -162,6 +347,16 @@
         return transaction;
     }
 
+    private static ClientTransaction newActivityConfigTransaction(Activity activity,
+            Configuration config) {
+        final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem.obtain(config);
+
+        final ClientTransaction transaction = newTransaction(activity);
+        transaction.addCallback(item);
+
+        return transaction;
+    }
+
     private static ClientTransaction newTransaction(Activity activity) {
         final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
         return ClientTransaction.obtain(appThread, activity.getActivityToken());
@@ -169,5 +364,37 @@
 
     // Test activity
     public static class TestActivity extends Activity {
+        int mNumOfConfigChanges;
+        final Configuration mConfig = new Configuration();
+
+        /**
+         * A latch used to notify tests that we're about to wait for configuration latch. This
+         * is used to notify test code that preExecute phase for activity configuration change
+         * transaction has passed.
+         */
+        volatile CountDownLatch mTestLatch;
+        /**
+         * If not {@code null} {@link #onConfigurationChanged(Configuration)} won't return until the
+         * latch reaches 0.
+         */
+        volatile CountDownLatch mConfigLatch;
+
+        @Override
+        public void onConfigurationChanged(Configuration config) {
+            super.onConfigurationChanged(config);
+            mConfig.setTo(config);
+            ++mNumOfConfigChanges;
+
+            if (mConfigLatch != null) {
+                if (mTestLatch != null) {
+                    mTestLatch.countDown();
+                }
+                try {
+                    mConfigLatch.await();
+                } catch (InterruptedException e) {
+                    throw new IllegalStateException(e);
+                }
+            }
+        }
     }
 }
diff --git a/core/tests/coretests/src/android/app/activity/BroadcastTest.java b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
index 13e70eb..0f81896 100644
--- a/core/tests/coretests/src/android/app/activity/BroadcastTest.java
+++ b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
@@ -27,11 +27,10 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.UserHandle;
-import android.support.test.filters.LargeTest;
-import android.test.FlakyTest;
 import android.util.Log;
 
-import java.util.Arrays;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.LargeTest;
 
 @LargeTest
 public class BroadcastTest extends ActivityTestsBase {
@@ -231,7 +230,7 @@
     };
 
     // Mark flaky until http://b/issue?id=1191607 is resolved.
-    @FlakyTest(tolerance=2)
+    @FlakyTest
     public void testRegistered() throws Exception {
         runLaunchpad(LaunchpadActivity.BROADCAST_REGISTERED);
     }
@@ -248,12 +247,12 @@
         runLaunchpad(LaunchpadActivity.BROADCAST_ABORT);
     }
 
-    @FlakyTest(tolerance=2)
+    @FlakyTest
     public void testAll() throws Exception {
         runLaunchpad(LaunchpadActivity.BROADCAST_ALL);
     }
 
-    @FlakyTest(tolerance=2)
+    @FlakyTest
     public void testMulti() throws Exception {
         runLaunchpad(LaunchpadActivity.BROADCAST_MULTI);
     }
@@ -348,7 +347,7 @@
     }
 
     // Marking flaky until http://b/issue?id=1191337 is resolved
-    @FlakyTest(tolerance=2)
+    @FlakyTest
     public void testReceiveSticky() throws Exception {
         Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
         intent.putExtra("test", LaunchpadActivity.DATA_1);
@@ -358,7 +357,7 @@
     }
 
     // Marking flaky until http://b/issue?id=1191337 is resolved
-    @FlakyTest(tolerance=2)
+    @FlakyTest
     public void testReceive2Sticky() throws Exception {
         Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
         intent.putExtra("test", LaunchpadActivity.DATA_1);
diff --git a/core/tests/coretests/src/android/app/activity/IntentSenderTest.java b/core/tests/coretests/src/android/app/activity/IntentSenderTest.java
index 8c1d79b..19ddb52 100644
--- a/core/tests/coretests/src/android/app/activity/IntentSenderTest.java
+++ b/core/tests/coretests/src/android/app/activity/IntentSenderTest.java
@@ -21,7 +21,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 @LargeTest
 public class IntentSenderTest extends BroadcastTest {
diff --git a/core/tests/coretests/src/android/app/activity/LaunchTest.java b/core/tests/coretests/src/android/app/activity/LaunchTest.java
index 5b86dce..6846ea7 100644
--- a/core/tests/coretests/src/android/app/activity/LaunchTest.java
+++ b/core/tests/coretests/src/android/app/activity/LaunchTest.java
@@ -17,8 +17,9 @@
 package android.app.activity;
 
 import android.content.ComponentName;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
 
 @Suppress  // Flaky.
 public class LaunchTest extends ActivityTestsBase {
diff --git a/core/tests/coretests/src/android/app/activity/LifecycleTest.java b/core/tests/coretests/src/android/app/activity/LifecycleTest.java
index ed01fac..5aa0380 100644
--- a/core/tests/coretests/src/android/app/activity/LifecycleTest.java
+++ b/core/tests/coretests/src/android/app/activity/LifecycleTest.java
@@ -18,8 +18,9 @@
 
 import android.content.ComponentName;
 import android.content.Intent;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 public class LifecycleTest extends ActivityTestsBase {
     private Intent mTopIntent;
diff --git a/core/tests/coretests/src/android/app/activity/MetaDataTest.java b/core/tests/coretests/src/android/app/activity/MetaDataTest.java
index 5b9c0e9..cf27878 100644
--- a/core/tests/coretests/src/android/app/activity/MetaDataTest.java
+++ b/core/tests/coretests/src/android/app/activity/MetaDataTest.java
@@ -27,8 +27,11 @@
 import android.content.res.XmlResourceParser;
 import android.os.Bundle;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
diff --git a/core/tests/coretests/src/android/app/activity/RemoteSubActivityScreen.java b/core/tests/coretests/src/android/app/activity/RemoteSubActivityScreen.java
index 9f402a5..8184627 100644
--- a/core/tests/coretests/src/android/app/activity/RemoteSubActivityScreen.java
+++ b/core/tests/coretests/src/android/app/activity/RemoteSubActivityScreen.java
@@ -1,19 +1,18 @@
-/* //device/apps/AndroidTests/src/com.android.unit_tests/activity/TestedScreen.java
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 package android.app.activity;
 
@@ -21,7 +20,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Process;
-import android.util.Log;
+
+//device/apps/AndroidTests/src/com.android.unit_tests/activity/TestedScreen.java
 
 public class RemoteSubActivityScreen extends SubActivityScreen {
     Handler mHandler = new Handler();
diff --git a/core/tests/coretests/src/android/app/activity/ServiceTest.java b/core/tests/coretests/src/android/app/activity/ServiceTest.java
index d3ae415..9d2aebd 100644
--- a/core/tests/coretests/src/android/app/activity/ServiceTest.java
+++ b/core/tests/coretests/src/android/app/activity/ServiceTest.java
@@ -22,13 +22,12 @@
 import android.content.ServiceConnection;
 import android.os.Binder;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.Parcel;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.util.Log;
+import android.os.RemoteException;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 // These test binders purport to support an interface whose canonical
 // interface name is ServiceTest.SERVICE_LOCAL
diff --git a/core/tests/coretests/src/android/app/activity/SetTimeZonePermissionsTest.java b/core/tests/coretests/src/android/app/activity/SetTimeZonePermissionsTest.java
index 41b9547..8e17295 100644
--- a/core/tests/coretests/src/android/app/activity/SetTimeZonePermissionsTest.java
+++ b/core/tests/coretests/src/android/app/activity/SetTimeZonePermissionsTest.java
@@ -19,7 +19,8 @@
 import android.app.AlarmManager;
 import android.content.Context;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import java.util.TimeZone;
 
diff --git a/core/tests/coretests/src/android/app/activity/SubActivityTest.java b/core/tests/coretests/src/android/app/activity/SubActivityTest.java
index 35dde8a..53f89fe 100644
--- a/core/tests/coretests/src/android/app/activity/SubActivityTest.java
+++ b/core/tests/coretests/src/android/app/activity/SubActivityTest.java
@@ -16,9 +16,10 @@
 
 package android.app.activity;
 
-import android.test.suitebuilder.annotation.Suppress;
 import android.content.ComponentName;
 
+import androidx.test.filters.Suppress;
+
 @Suppress
 public class SubActivityTest extends ActivityTestsBase {
 
diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
index 9b5b725..5731daa 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
@@ -20,15 +20,27 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+import static android.app.admin.PasswordMetrics.complexityLevelToMinQuality;
+import static android.app.admin.PasswordMetrics.getActualRequiredQuality;
+import static android.app.admin.PasswordMetrics.getMinimumMetrics;
+import static android.app.admin.PasswordMetrics.getTargetQualityMetrics;
+import static android.app.admin.PasswordMetrics.sanitizeComplexityLevel;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
 
-import android.app.admin.PasswordMetrics.PasswordComplexityBucket;
 import android.os.Parcel;
-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;
@@ -108,7 +120,7 @@
         assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX,
                 PasswordMetrics.computeForPassword("1").quality);
         // contains a long sequence so isn't complex
-        assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
+        assertEquals(PASSWORD_QUALITY_NUMERIC,
                 PasswordMetrics.computeForPassword("1234").quality);
         assertEquals(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
                 PasswordMetrics.computeForPassword("").quality);
@@ -144,7 +156,7 @@
                 new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 5));
 
         assertNotEquals(new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4),
-                new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 4));
+                new PasswordMetrics(PASSWORD_QUALITY_COMPLEX, 4));
 
         metrics0 = PasswordMetrics.computeForPassword("1234abcd,./");
         metrics1 = PasswordMetrics.computeForPassword("1234abcd,./");
@@ -175,9 +187,9 @@
     @Test
     public void testConstructQuality() {
         PasswordMetrics expected = new PasswordMetrics();
-        expected.quality = DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+        expected.quality = PASSWORD_QUALITY_COMPLEX;
 
-        PasswordMetrics actual = new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
+        PasswordMetrics actual = new PasswordMetrics(PASSWORD_QUALITY_COMPLEX);
 
         assertEquals(expected, actual);
     }
@@ -255,42 +267,178 @@
     }
 
     @Test
-    public void testComplexityLevelToBucket_none() {
-        PasswordMetrics[] bucket = PasswordComplexityBucket.complexityLevelToBucket(
-                PASSWORD_COMPLEXITY_NONE).getMetrics();
+    public void testSanitizeComplexityLevel_none() {
+        assertEquals(PASSWORD_COMPLEXITY_NONE, sanitizeComplexityLevel(PASSWORD_COMPLEXITY_NONE));
 
-        for (PasswordMetrics metrics : bucket) {
-            assertEquals(PASSWORD_COMPLEXITY_NONE, metrics.determineComplexity());
-        }
     }
 
     @Test
-    public void testComplexityLevelToBucket_low() {
-        PasswordMetrics[] bucket = PasswordComplexityBucket.complexityLevelToBucket(
-                PASSWORD_COMPLEXITY_LOW).getMetrics();
-
-        for (PasswordMetrics metrics : bucket) {
-            assertEquals(PASSWORD_COMPLEXITY_LOW, metrics.determineComplexity());
-        }
+    public void testSanitizeComplexityLevel_low() {
+        assertEquals(PASSWORD_COMPLEXITY_LOW, sanitizeComplexityLevel(PASSWORD_COMPLEXITY_LOW));
     }
 
     @Test
-    public void testComplexityLevelToBucket_medium() {
-        PasswordMetrics[] bucket = PasswordComplexityBucket.complexityLevelToBucket(
-                PASSWORD_COMPLEXITY_MEDIUM).getMetrics();
-
-        for (PasswordMetrics metrics : bucket) {
-            assertEquals(PASSWORD_COMPLEXITY_MEDIUM, metrics.determineComplexity());
-        }
+    public void testSanitizeComplexityLevel_medium() {
+        assertEquals(
+                PASSWORD_COMPLEXITY_MEDIUM, sanitizeComplexityLevel(PASSWORD_COMPLEXITY_MEDIUM));
     }
 
     @Test
-    public void testComplexityLevelToBucket_high() {
-        PasswordMetrics[] bucket = PasswordComplexityBucket.complexityLevelToBucket(
-                PASSWORD_COMPLEXITY_HIGH).getMetrics();
+    public void testSanitizeComplexityLevel_high() {
+        assertEquals(PASSWORD_COMPLEXITY_HIGH, sanitizeComplexityLevel(PASSWORD_COMPLEXITY_HIGH));
+    }
 
-        for (PasswordMetrics metrics : bucket) {
-            assertEquals(PASSWORD_COMPLEXITY_HIGH, metrics.determineComplexity());
-        }
+    @Test
+    public void testSanitizeComplexityLevel_invalid() {
+        assertEquals(PASSWORD_COMPLEXITY_NONE, sanitizeComplexityLevel(-1));
+    }
+
+    @Test
+    public void testComplexityLevelToMinQuality_none() {
+        assertEquals(PASSWORD_QUALITY_UNSPECIFIED,
+                complexityLevelToMinQuality(PASSWORD_COMPLEXITY_NONE));
+    }
+
+    @Test
+    public void testComplexityLevelToMinQuality_low() {
+        assertEquals(PASSWORD_QUALITY_SOMETHING,
+                complexityLevelToMinQuality(PASSWORD_COMPLEXITY_LOW));
+    }
+
+    @Test
+    public void testComplexityLevelToMinQuality_medium() {
+        assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX,
+                complexityLevelToMinQuality(PASSWORD_COMPLEXITY_MEDIUM));
+    }
+
+    @Test
+    public void testComplexityLevelToMinQuality_high() {
+        assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX,
+                complexityLevelToMinQuality(PASSWORD_COMPLEXITY_HIGH));
+    }
+
+    @Test
+    public void testComplexityLevelToMinQuality_invalid() {
+        assertEquals(PASSWORD_QUALITY_UNSPECIFIED, complexityLevelToMinQuality(-1));
+    }
+
+    @Test
+    public void testGetTargetQualityMetrics_noneComplexityReturnsDefaultMetrics() {
+        PasswordMetrics metrics =
+                getTargetQualityMetrics(PASSWORD_COMPLEXITY_NONE, PASSWORD_QUALITY_ALPHANUMERIC);
+
+        assertTrue(metrics.isDefault());
+    }
+
+    @Test
+    public void testGetTargetQualityMetrics_qualityNotAllowedReturnsMinQualityMetrics() {
+        PasswordMetrics metrics =
+                getTargetQualityMetrics(PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_QUALITY_NUMERIC);
+
+        assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX, metrics.quality);
+        assertEquals(/* expected= */ 4, metrics.length);
+    }
+
+    @Test
+    public void testGetTargetQualityMetrics_highComplexityNumericComplex() {
+        PasswordMetrics metrics = getTargetQualityMetrics(
+                PASSWORD_COMPLEXITY_HIGH, PASSWORD_QUALITY_NUMERIC_COMPLEX);
+
+        assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX, metrics.quality);
+        assertEquals(/* expected= */ 8, metrics.length);
+    }
+
+    @Test
+    public void testGetTargetQualityMetrics_mediumComplexityAlphabetic() {
+        PasswordMetrics metrics = getTargetQualityMetrics(
+                PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_QUALITY_ALPHABETIC);
+
+        assertEquals(PASSWORD_QUALITY_ALPHABETIC, metrics.quality);
+        assertEquals(/* expected= */ 4, metrics.length);
+    }
+
+    @Test
+    public void testGetTargetQualityMetrics_lowComplexityAlphanumeric() {
+        PasswordMetrics metrics = getTargetQualityMetrics(
+                PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_QUALITY_ALPHANUMERIC);
+
+        assertEquals(PASSWORD_QUALITY_ALPHANUMERIC, metrics.quality);
+        assertEquals(/* expected= */ 4, metrics.length);
+    }
+
+    @Test
+    public void testGetActualRequiredQuality_nonComplex() {
+        int actual = getActualRequiredQuality(
+                PASSWORD_QUALITY_NUMERIC_COMPLEX,
+                /* requiresNumeric= */ false,
+                /* requiresLettersOrSymbols= */ false);
+
+        assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX, actual);
+    }
+
+    @Test
+    public void testGetActualRequiredQuality_complexRequiresNone() {
+        int actual = getActualRequiredQuality(
+                PASSWORD_QUALITY_COMPLEX,
+                /* requiresNumeric= */ false,
+                /* requiresLettersOrSymbols= */ false);
+
+        assertEquals(PASSWORD_QUALITY_UNSPECIFIED, actual);
+    }
+
+    @Test
+    public void testGetActualRequiredQuality_complexRequiresNumeric() {
+        int actual = getActualRequiredQuality(
+                PASSWORD_QUALITY_COMPLEX,
+                /* requiresNumeric= */ true,
+                /* requiresLettersOrSymbols= */ false);
+
+        assertEquals(PASSWORD_QUALITY_NUMERIC, actual);
+    }
+
+    @Test
+    public void testGetActualRequiredQuality_complexRequiresLetters() {
+        int actual = getActualRequiredQuality(
+                PASSWORD_QUALITY_COMPLEX,
+                /* requiresNumeric= */ false,
+                /* requiresLettersOrSymbols= */ true);
+
+        assertEquals(PASSWORD_QUALITY_ALPHABETIC, actual);
+    }
+
+    @Test
+    public void testGetActualRequiredQuality_complexRequiresNumericAndLetters() {
+        int actual = getActualRequiredQuality(
+                PASSWORD_QUALITY_COMPLEX,
+                /* requiresNumeric= */ true,
+                /* requiresLettersOrSymbols= */ true);
+
+        assertEquals(PASSWORD_QUALITY_ALPHANUMERIC, actual);
+    }
+
+    @Test
+    public void testGetMinimumMetrics_userInputStricter() {
+        PasswordMetrics metrics = getMinimumMetrics(
+                PASSWORD_COMPLEXITY_HIGH,
+                PASSWORD_QUALITY_ALPHANUMERIC,
+                PASSWORD_QUALITY_NUMERIC,
+                /* requiresNumeric= */ false,
+                /* requiresLettersOrSymbols= */ false);
+
+        assertEquals(PASSWORD_QUALITY_ALPHANUMERIC, metrics.quality);
+        assertEquals(/* expected= */ 6, metrics.length);
+    }
+
+    @Test
+    public void testGetMinimumMetrics_actualRequiredQualityStricter() {
+        PasswordMetrics metrics = getMinimumMetrics(
+                PASSWORD_COMPLEXITY_HIGH,
+                PASSWORD_QUALITY_UNSPECIFIED,
+                PASSWORD_QUALITY_NUMERIC,
+                /* requiresNumeric= */ false,
+                /* requiresLettersOrSymbols= */ false);
+
+        assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX, metrics.quality);
+        assertEquals(/* expected= */ 8, metrics.length);
     }
 }
diff --git a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
index 689e683..1f4e5df 100644
--- a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
+++ b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.app.assist;
 
 import static android.view.View.AUTOFILL_TYPE_TEXT;
@@ -22,13 +23,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.app.assist.AssistStructure.ViewNode;
-import android.content.ComponentName;
 import android.content.Context;
 import android.os.Parcel;
 import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.InputFilter;
 import android.util.Log;
 import android.view.autofill.AutofillId;
@@ -37,6 +34,10 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java b/core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java
index f4b6bed..defec43 100644
--- a/core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java
+++ b/core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.app.assist;
 
 import android.app.Activity;
diff --git a/core/tests/coretests/src/android/app/backup/BackupDataTest.java b/core/tests/coretests/src/android/app/backup/BackupDataTest.java
index 5b8e481..18ff54f 100644
--- a/core/tests/coretests/src/android/app/backup/BackupDataTest.java
+++ b/core/tests/coretests/src/android/app/backup/BackupDataTest.java
@@ -16,31 +16,22 @@
 
 package android.app.backup;
 
-import android.app.backup.BackupDataInput;
-import android.app.backup.BackupDataOutput;
-import android.content.res.AssetFileDescriptor;
 import android.content.res.AssetManager;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
-import android.test.InstrumentationTestCase;
 import android.util.Base64;
-import android.util.Log;
-import org.json.JSONObject;
+
+import androidx.test.filters.LargeTest;
 
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
-import java.io.FileReader;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.lang.Exception;
-import java.nio.ByteBuffer;
 
 @LargeTest
 public class BackupDataTest extends AndroidTestCase {
diff --git a/core/tests/coretests/src/android/app/backup/FullBackupTest.java b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
index 5db416b..08edb4e 100644
--- a/core/tests/coretests/src/android/app/backup/FullBackupTest.java
+++ b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
@@ -18,11 +18,12 @@
 
 import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
 import android.content.Context;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
+import androidx.test.filters.LargeTest;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlPullParserFactory;
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
index b1f8552..52b2658 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionTests.java
@@ -23,8 +23,9 @@
 import android.app.ClientTransactionHandler;
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
-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/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index fb0f534..ad28d13 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -35,8 +35,9 @@
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.platform.test.annotations.Presubmit;
-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/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
index a788a93..f730a24 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -45,10 +45,11 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 2801f324..8604b0c 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -50,8 +50,9 @@
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.app.IVoiceInteractor;
 
diff --git a/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java b/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
index e20645c..0efc0ab 100644
--- a/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
+++ b/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
@@ -21,7 +21,8 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.Test;
 
diff --git a/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java b/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
index b69054c..b519bf8 100644
--- a/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
+++ b/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
@@ -21,7 +21,8 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.Test;
 
diff --git a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
index dd46240..bb535b6 100644
--- a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
+++ b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
@@ -16,14 +16,13 @@
 
 package android.app.timezone;
 
-import static junit.framework.Assert.fail;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.Test;
 
diff --git a/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java b/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
index 4004086..df9ddea 100644
--- a/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
+++ b/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
@@ -25,7 +25,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.UserHandle;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
diff --git a/core/tests/coretests/src/android/app/usage/EventListTest.java b/core/tests/coretests/src/android/app/usage/EventListTest.java
index 9dc0d43..685fcae 100644
--- a/core/tests/coretests/src/android/app/usage/EventListTest.java
+++ b/core/tests/coretests/src/android/app/usage/EventListTest.java
@@ -20,10 +20,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
index 28aaf1e..1633e1a 100644
--- a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
+++ b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
@@ -21,6 +21,7 @@
 import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
 import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED;
 import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE;
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
 import static android.app.usage.UsageEvents.Event.END_OF_DAY;
 import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK;
 import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START;
@@ -33,8 +34,9 @@
 
 import android.app.usage.UsageEvents.Event;
 import android.os.Parcel;
-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.Before;
 import org.junit.Test;
@@ -528,6 +530,11 @@
     }
 
     @Test
+    public void testEvent_DEVICE_SHUTDOWN() {
+        testClosingEvent(DEVICE_SHUTDOWN);
+    }
+
+    @Test
     public void testEvent_FLUSH_TO_DISK() {
         testClosingEvent(FLUSH_TO_DISK);
     }
@@ -535,8 +542,9 @@
     private void testClosingEvent(int eventType) {
         // When these three closing events are received, all open activities/services need to be
         // closed and usage stats are updated.
-        if (eventType != FLUSH_TO_DISK) {
-            fail("Closing eventType must be one of FLUSH_TO_DISK");
+        if (eventType != DEVICE_SHUTDOWN
+                && eventType != FLUSH_TO_DISK) {
+            fail("Closing eventType must be one of DEVICE_SHUTDOWN, FLUSH_TO_DISK");
         }
 
         left.mPackageName = "com.test";
diff --git a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
index 978ea7a..c307e64 100644
--- a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
@@ -16,7 +16,6 @@
 
 package android.content;
 
-
 import static org.junit.Assert.fail;
 
 import android.app.ActivityManager;
@@ -30,9 +29,10 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/content/AssetTest.java b/core/tests/coretests/src/android/content/AssetTest.java
index b66574c..8e55e8a 100644
--- a/core/tests/coretests/src/android/content/AssetTest.java
+++ b/core/tests/coretests/src/android/content/AssetTest.java
@@ -18,7 +18,8 @@
 
 import android.content.res.AssetManager;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/core/tests/coretests/src/android/content/BrickDeniedTest.java b/core/tests/coretests/src/android/content/BrickDeniedTest.java
index 3d246b4..d8c9baa 100644
--- a/core/tests/coretests/src/android/content/BrickDeniedTest.java
+++ b/core/tests/coretests/src/android/content/BrickDeniedTest.java
@@ -17,7 +17,8 @@
 package android.content;
 
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 /** Test to make sure brick intents <b>don't</b> work without permission. */
 public class BrickDeniedTest extends AndroidTestCase {
diff --git a/core/tests/coretests/src/android/content/BroadcastReceiverTests.java b/core/tests/coretests/src/android/content/BroadcastReceiverTests.java
index 8deccb7..1509ff9 100644
--- a/core/tests/coretests/src/android/content/BroadcastReceiverTests.java
+++ b/core/tests/coretests/src/android/content/BroadcastReceiverTests.java
@@ -18,9 +18,9 @@
 
 import static org.junit.Assert.fail;
 
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/content/ContentProviderOperationTest.java b/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
index aea124b..b142761 100644
--- a/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
+++ b/core/tests/coretests/src/android/content/ContentProviderOperationTest.java
@@ -16,22 +16,23 @@
 
 package android.content;
 
-import android.content.ContentValues;
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.net.Uri;
 import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.text.TextUtils;
+
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.util.HashMap;
-import java.util.Set;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 
 @SmallTest
 public class ContentProviderOperationTest extends TestCase {
diff --git a/core/tests/coretests/src/android/content/ContentProviderTest.java b/core/tests/coretests/src/android/content/ContentProviderTest.java
index 2142f27..8895f9b 100644
--- a/core/tests/coretests/src/android/content/ContentProviderTest.java
+++ b/core/tests/coretests/src/android/content/ContentProviderTest.java
@@ -23,7 +23,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ProviderInfo;
 import android.net.Uri;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/content/ContentQueryMapTest.java b/core/tests/coretests/src/android/content/ContentQueryMapTest.java
index f47bfdb..7106234 100644
--- a/core/tests/coretests/src/android/content/ContentQueryMapTest.java
+++ b/core/tests/coretests/src/android/content/ContentQueryMapTest.java
@@ -16,16 +16,14 @@
 
 package android.content;
 
-import android.content.ContentQueryMap;
-import android.content.ContentResolver;
-import android.content.ContentValues;
 import android.database.Cursor;
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.Settings;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 import java.util.Observable;
 import java.util.Observer;
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 9940bf7..f14f289 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -31,10 +31,11 @@
 import android.net.Uri;
 import android.os.MemoryFile;
 import android.os.ParcelFileDescriptor;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Size;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/content/ContentValuesTest.java b/core/tests/coretests/src/android/content/ContentValuesTest.java
index 7b39939..0ab79e7 100644
--- a/core/tests/coretests/src/android/content/ContentValuesTest.java
+++ b/core/tests/coretests/src/android/content/ContentValuesTest.java
@@ -17,8 +17,8 @@
 package android.content;
 
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.filters.SmallTest;
 
 /*
   runtest -c android.content.ContentValuesTest frameworks-core
@@ -29,7 +29,7 @@
     adb shell pm uninstall -k com.android.frameworks.coretests && \
     adb install out/target/product/bullhead/testcases/FrameworksCoreTests/FrameworksCoreTests.apk && \
     adb shell am instrument -w -e package android.content \
-      com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+      com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
 */
 public class ContentValuesTest extends AndroidTestCase {
 
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index c8a3098..2f442c3 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -19,11 +19,12 @@
 import static org.junit.Assert.assertEquals;
 
 import android.app.ActivityThread;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.WindowManager;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
index 4362ec3..22b2314 100644
--- a/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
@@ -19,7 +19,8 @@
 import android.content.pm.UserInfo;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * To run the tests, use
@@ -32,7 +33,7 @@
  * Install: adb install -r \
  *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class android.content.ManagedUserContentResolverTest -w \
- *     com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ *     com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  */
 @LargeTest
 public class ManagedUserContentResolverTest extends AbstractCrossUserContentResolverTest {
diff --git a/core/tests/coretests/src/android/content/MemoryFileProviderTest.java b/core/tests/coretests/src/android/content/MemoryFileProviderTest.java
index bbe7c10..7cd4862 100644
--- a/core/tests/coretests/src/android/content/MemoryFileProviderTest.java
+++ b/core/tests/coretests/src/android/content/MemoryFileProviderTest.java
@@ -18,9 +18,10 @@
 
 import android.net.Uri;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
 
 import java.io.InputStream;
 import java.util.Arrays;
diff --git a/core/tests/coretests/src/android/content/RestrictionsManagerTest.java b/core/tests/coretests/src/android/content/RestrictionsManagerTest.java
index 10d74f7..fd5de32 100644
--- a/core/tests/coretests/src/android/content/RestrictionsManagerTest.java
+++ b/core/tests/coretests/src/android/content/RestrictionsManagerTest.java
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License
  */
+
 package android.content;
 
 import android.os.Bundle;
 import android.os.Parcelable;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 
+import androidx.test.filters.LargeTest;
+
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
diff --git a/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
index f8b13f0..dbe0278 100644
--- a/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
@@ -18,7 +18,8 @@
 
 import android.content.pm.UserInfo;
 import android.os.RemoteException;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 /**
  * To run the tests, use
@@ -31,7 +32,7 @@
  * Install: adb install -r \
  *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class android.content.SecondaryUserContentResolverTest -w \
- *     com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ *     com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  */
 @LargeTest
 public class SecondaryUserContentResolverTest extends AbstractCrossUserContentResolverTest {
diff --git a/core/tests/coretests/src/android/content/UriMatcherTest.java b/core/tests/coretests/src/android/content/UriMatcherTest.java
index f3b9e76..6cef46b 100644
--- a/core/tests/coretests/src/android/content/UriMatcherTest.java
+++ b/core/tests/coretests/src/android/content/UriMatcherTest.java
@@ -17,14 +17,14 @@
 package android.content;
 
 import android.net.Uri;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
 
-
 public class UriMatcherTest extends TestCase {
 
     static final int ROOT = 0;
diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
index 2acb08d..9b360db 100644
--- a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
@@ -13,6 +13,7 @@
  * 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;
@@ -20,7 +21,8 @@
 import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
 
 import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
index dce22ce..0ed76dc 100644
--- a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import static android.content.pm.PackageBuilder.builder;
 import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
 
 import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
index 866de93..7f817d6 100644
--- a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
@@ -13,6 +13,7 @@
  * 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;
@@ -20,7 +21,8 @@
 import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
 
 import android.content.pm.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/ComponentTest.java b/core/tests/coretests/src/android/content/pm/ComponentTest.java
index cc75641..f31f0b5 100644
--- a/core/tests/coretests/src/android/content/pm/ComponentTest.java
+++ b/core/tests/coretests/src/android/content/pm/ComponentTest.java
@@ -21,7 +21,14 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 import static android.content.pm.PackageManager.GET_DISABLED_COMPONENTS;
 
-import android.test.suitebuilder.annotation.Suppress;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+
 import com.android.frameworks.coretests.enabled_app.DisabledActivity;
 import com.android.frameworks.coretests.enabled_app.DisabledProvider;
 import com.android.frameworks.coretests.enabled_app.DisabledReceiver;
@@ -31,12 +38,6 @@
 import com.android.frameworks.coretests.enabled_app.EnabledReceiver;
 import com.android.frameworks.coretests.enabled_app.EnabledService;
 
-import android.content.ComponentName;
-import android.content.Intent;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-
 import java.util.List;
 
 /**
diff --git a/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java b/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java
index 1f762fd..1c703ab 100644
--- a/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java
+++ b/core/tests/coretests/src/android/content/pm/LimitedLengthInputStreamTest.java
@@ -17,7 +17,8 @@
 package android.content.pm;
 
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
diff --git a/core/tests/coretests/src/android/content/pm/MacAuthenticatedInputStreamTest.java b/core/tests/coretests/src/android/content/pm/MacAuthenticatedInputStreamTest.java
index 659f9ea..1ddd753 100644
--- a/core/tests/coretests/src/android/content/pm/MacAuthenticatedInputStreamTest.java
+++ b/core/tests/coretests/src/android/content/pm/MacAuthenticatedInputStreamTest.java
@@ -16,9 +16,12 @@
 
 package android.content.pm;
 
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 
+import androidx.test.filters.LargeTest;
+
+import libcore.io.Streams;
+
 import java.io.ByteArrayInputStream;
 import java.util.Arrays;
 
@@ -26,8 +29,6 @@
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
 
-import libcore.io.Streams;
-
 @LargeTest
 public class MacAuthenticatedInputStreamTest extends AndroidTestCase {
 
diff --git a/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java b/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java
index 91697c0..05db8ee 100644
--- a/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java
+++ b/core/tests/coretests/src/android/content/pm/OptionalClassRunner.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import org.junit.Assume;
diff --git a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java b/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
index dcd2707..834a0bb 100644
--- a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import static android.content.pm.PackageBuilder.builder;
 import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
 
 import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
index c64d520..3d7aab0 100644
--- a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
@@ -24,7 +24,8 @@
 
 import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
 import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Assume;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/content/pm/PackageBuilder.java b/core/tests/coretests/src/android/content/pm/PackageBuilder.java
index 4ceed83..c5db962 100644
--- a/core/tests/coretests/src/android/content/pm/PackageBuilder.java
+++ b/core/tests/coretests/src/android/content/pm/PackageBuilder.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import static org.junit.Assert.assertEquals;
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 8ac9451d..0ab5367 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -54,11 +54,12 @@
 import android.system.Os;
 import android.system.StructStat;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+
 import com.android.frameworks.coretests.R;
 import com.android.internal.content.PackageHelper;
 
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserCacheHelperTest.java b/core/tests/coretests/src/android/content/pm/PackageParserCacheHelperTest.java
index 00be822..e852f98 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserCacheHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserCacheHelperTest.java
@@ -22,8 +22,9 @@
 import android.content.pm.PackageParserCacheHelper.WriteHelper;
 import android.os.Bundle;
 import android.os.Parcel;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 267267e..7b92cf5 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -29,9 +29,10 @@
 import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.SystemProperties;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
 
@@ -51,6 +52,12 @@
     private static final String PRE_RELEASE = "B";
     private static final String NEWER_PRE_RELEASE = "C";
 
+    // Codenames with a fingerprint attached to them. These may only be present in the apps
+    // declared min SDK and not as platform codenames.
+    private static final String OLDER_PRE_RELEASE_WITH_FINGERPRINT = "A.fingerprint";
+    private static final String PRE_RELEASE_WITH_FINGERPRINT = "B.fingerprint";
+    private static final String NEWER_PRE_RELEASE_WITH_FINGERPRINT = "C.fingerprint";
+
     private static final String[] CODENAMES_RELEASED = { /* empty */ };
     private static final String[] CODENAMES_PRE_RELEASE = { PRE_RELEASE };
 
@@ -68,7 +75,7 @@
                 isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
                 outError);
 
-        assertEquals(result, expectedMinSdk);
+        assertEquals("Error msg: " + outError[0], expectedMinSdk, result);
 
         if (expectedMinSdk == -1) {
             assertNotNull(outError[0]);
@@ -98,6 +105,7 @@
         // APP: Pre-release API 10
         // DEV: Pre-release API 20
         verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1);
+        verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1);
 
         // Do allow same pre-release minSdkVersion on pre-release platform,
         // but overwrite the specified version with CUR_DEVELOPMENT.
@@ -105,11 +113,15 @@
         // DEV: Pre-release API 20
         verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false,
                 Build.VERSION_CODES.CUR_DEVELOPMENT);
+        verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, false,
+                Build.VERSION_CODES.CUR_DEVELOPMENT);
+
 
         // Don't allow newer pre-release minSdkVersion on pre-release platform.
         // APP: Pre-release API 30
         // DEV: Pre-release API 20
         verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1);
+        verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1);
     }
 
     @Test
@@ -133,16 +145,20 @@
         // APP: Pre-release API 10
         // DEV: Released API 20
         verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1);
+        verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1);
 
         // Don't allow same pre-release minSdkVersion on released platform.
         // APP: Pre-release API 20
         // DEV: Released API 20
         verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1);
+        verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1);
+
 
         // Don't allow newer pre-release minSdkVersion on released platform.
         // APP: Pre-release API 30
         // DEV: Released API 20
         verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1);
+        verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1);
     }
 
     private void verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename,
@@ -189,6 +205,9 @@
         // DEV: Pre-release API 20
         verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1,
                 false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1,
+                false /* forceCurrentDev */);
+
 
         // Do allow same pre-release targetSdkVersion on pre-release platform,
         // but overwrite the specified version with CUR_DEVELOPMENT.
@@ -196,18 +215,26 @@
         // DEV: Pre-release API 20
         verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false,
                 Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, false,
+                Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */);
+
 
         // Don't allow newer pre-release targetSdkVersion on pre-release platform.
         // APP: Pre-release API 30
         // DEV: Pre-release API 20
         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1,
                 false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1,
+                false /* forceCurrentDev */);
+
 
         // Force newer pre-release targetSdkVersion to current pre-release platform.
         // APP: Pre-release API 30
         // DEV: Pre-release API 20
         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false,
                 Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false,
+                Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */);
     }
 
     @Test
@@ -235,18 +262,25 @@
         // DEV: Released API 20
         verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1,
                 false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1,
+                false /* forceCurrentDev */);
 
         // Don't allow same pre-release targetSdkVersion on released platform.
         // APP: Pre-release API 20
         // DEV: Released API 20
         verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1,
                 false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1,
+                false /* forceCurrentDev */);
+
 
         // Don't allow newer pre-release targetSdkVersion on released platform.
         // APP: Pre-release API 30
         // DEV: Released API 20
         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1,
                 false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1,
+                false /* forceCurrentDev */);
     }
 
     /**
@@ -296,6 +330,28 @@
     }
 
     /**
+     * Copies a specified {@code resourceId} to a file. Returns a non-null file if the copy
+     * succeeded, or {@code null} otherwise.
+     */
+    File copyRawResourceToFile(String baseName, int resourceId) throws Exception {
+        // Copy the resource to a file.
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        InputStream is = context.getResources().openRawResource(resourceId);
+        File outFile = null;
+        try {
+            outFile = new File(context.getFilesDir(), baseName);
+            assertTrue(FileUtils.copyToFile(is, outFile));
+            return outFile;
+        } catch (Exception e) {
+            if (outFile != null) {
+                outFile.delete();
+            }
+
+            return null;
+        }
+    }
+
+    /**
      * Attempts to parse a package.
      *
      * APKs are put into coretests/apks/packageparser_*.
@@ -306,14 +362,14 @@
     Package parsePackage(String apkFileName, int apkResourceId,
             Function<Package, Package> converter) throws Exception {
         // Copy the resource to a file.
-        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        File outFile = new File(context.getFilesDir(), apkFileName);
+        File outFile = null;
         try {
-            InputStream is = context.getResources().openRawResource(apkResourceId);
-            assertTrue(FileUtils.copyToFile(is, outFile));
+            outFile = copyRawResourceToFile(apkFileName, apkResourceId);
             return converter.apply(new PackageParser().parsePackage(outFile, 0 /* flags */));
         } finally {
-            outFile.delete();
+            if (outFile != null) {
+                outFile.delete();
+            }
         }
     }
 
@@ -464,4 +520,22 @@
                         "android.permission.READ_CONTACTS"),
                 secondChild.requestedPermissions);
     }
+
+    @Test
+    public void testApexPackageInfoGeneration() throws Exception {
+        File apexFile = copyRawResourceToFile("com.android.tzdata.apex",
+                R.raw.com_android_tzdata);
+        PackageInfo pi = PackageParser.generatePackageInfoFromApex(apexFile, false);
+        assertEquals("com.google.android.tzdata", pi.packageName);
+        assertEquals(1, pi.getLongVersionCode());
+        assertEquals(1, pi.applicationInfo.longVersionCode);
+        assertNull(pi.signingInfo);
+
+        pi = PackageParser.generatePackageInfoFromApex(apexFile, true);
+        assertEquals("com.google.android.tzdata", pi.packageName);
+        assertEquals(1, pi.getLongVersionCode());
+        assertEquals(1, pi.applicationInfo.longVersionCode);
+        assertNotNull(pi.signingInfo);
+        assertTrue(pi.signingInfo.getApkContentsSigners().length > 0);
+    }
 }
diff --git a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java b/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
index d5d3d7a..71a0e5e 100644
--- a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.pm;
 
 import java.util.function.Supplier;
diff --git a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
index 952bb55..8874525 100644
--- a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
+++ b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
@@ -1,8 +1,25 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.content.pm;
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
index d3d1f22a..365e97d 100644
--- a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
+++ b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
@@ -21,11 +21,12 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.SparseArray;
 
+import androidx.test.filters.LargeTest;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
index 3dba440..216b0c8 100644
--- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
+++ b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
@@ -13,6 +13,7 @@
  * 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;
@@ -20,7 +21,8 @@
 
 import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
 import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
index 15b27d7..fc60980 100644
--- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
+++ b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
@@ -13,6 +13,7 @@
  * 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;
@@ -20,7 +21,8 @@
 
 import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
 import android.os.Build;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/content/pm/SignatureTest.java b/core/tests/coretests/src/android/content/pm/SignatureTest.java
index a3fa1a9..f0b4af6 100644
--- a/core/tests/coretests/src/android/content/pm/SignatureTest.java
+++ b/core/tests/coretests/src/android/content/pm/SignatureTest.java
@@ -16,7 +16,7 @@
 
 package android.content.pm;
 
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
index 68942cb..f6527da 100644
--- a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
+++ b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
@@ -16,12 +16,12 @@
 
 package android.content.pm;
 
-import android.content.pm.VerificationParams;
 import android.net.Uri;
 import android.os.Parcel;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 
+import androidx.test.filters.LargeTest;
+
 /**
  * Tests the android.content.pm.VerificationParams class
  *
diff --git a/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java b/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java
index 88d7a59..e7cd02d 100644
--- a/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java
+++ b/core/tests/coretests/src/android/content/pm/VerifierDeviceIdentityTest.java
@@ -17,7 +17,8 @@
 package android.content.pm;
 
 import android.os.Parcel;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import java.util.Random;
 
diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
index e248a77..1ca879c 100644
--- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
@@ -29,12 +29,21 @@
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
 
+import libcore.testing.io.TestIoUtils;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -45,14 +54,6 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
-import libcore.testing.io.TestIoUtils;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DexMetadataHelperTest {
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
index 47554a6..47b14bb 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
@@ -17,9 +17,10 @@
 package android.content.res;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.TypedValue;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.lang.reflect.InvocationTargetException;
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationTest.java b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
index 72b9197..2fc3e36 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
@@ -13,19 +13,18 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package android.content.res;
 
-import org.junit.runner.RunWith;
-import org.junit.Test;
-import org.junit.runners.JUnit4;
-
-import android.content.res.Configuration;
-import android.support.test.filters.SmallTest;
 import android.platform.test.annotations.Presubmit;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
-import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 /**
  * Build/install/run: bit FrameworksCoreTests:android.content.res.ConfigurationTest
diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
index 42ff2e9..7ab9d7f 100644
--- a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
+++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.content.res;
 
 import static android.content.res.FontResourcesParser.FamilyResourceEntry;
@@ -26,9 +27,10 @@
 import static org.junit.Assert.assertNotNull;
 
 import android.app.Instrumentation;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/content/res/ResourcesDrawableTest.java b/core/tests/coretests/src/android/content/res/ResourcesDrawableTest.java
new file mode 100644
index 0000000..c4df88b
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/ResourcesDrawableTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.res;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.graphics.drawable.ColorStateListDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ResourcesDrawableTest {
+
+    @Test
+    public void testLoadColorAsDrawable() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        Resources resources = context.getResources();
+        Drawable drawable = resources.getDrawable(R.color.color1);
+        assertTrue(drawable instanceof ColorStateListDrawable);
+    }
+
+    @Test
+    public void testLoadColorAsDrawableFailureThrowsOriginalException() throws Throwable {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        Resources resources = context.getResources();
+
+        Exception exception = null;
+
+        try {
+            resources.getDrawable(R.color.drawable_in_color_dir_invalid);
+        } catch (Exception e) {
+            exception = e;
+        }
+
+        assertNotNull(
+                "Loading drawable_in_color_dir_invalid should throw an exception",
+                exception
+        );
+
+        assertEquals(
+                "Can't find ColorStateList from drawable resource ID #0x"
+                        + Integer.toHexString(R.color.drawable_in_color_dir_invalid),
+                exception.getCause().getCause().getMessage()
+        );
+    }
+
+    @Test
+    public void testLoadNormalDrawableInColorDir() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        Resources resources = context.getResources();
+        Drawable drawable = resources.getDrawable(R.color.drawable_in_color_dir_valid);
+        assertTrue(drawable instanceof LayerDrawable);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java b/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
index e85666e..aa1a534 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java
@@ -13,14 +13,15 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package android.content.res;
 
 import android.os.FileUtils;
 import android.os.LocaleList;
-import android.support.test.filters.SmallTest;
 import android.test.AndroidTestCase;
 import android.util.DisplayMetrics;
-import android.view.Display;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index b2ff927..a2dab99 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -13,18 +13,20 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package android.content.res;
 
 import android.annotation.NonNull;
 import android.app.ResourcesManager;
 import android.os.Binder;
 import android.os.LocaleList;
-import android.support.test.filters.SmallTest;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
 import android.view.Display;
 import android.view.DisplayAdjustments;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 public class ResourcesManagerTest extends TestCase {
diff --git a/core/tests/coretests/src/android/database/CursorWindowTest.java b/core/tests/coretests/src/android/database/CursorWindowTest.java
index 075f5b7..123da3e 100644
--- a/core/tests/coretests/src/android/database/CursorWindowTest.java
+++ b/core/tests/coretests/src/android/database/CursorWindowTest.java
@@ -16,14 +16,14 @@
 
 package android.database;
 
-import android.test.suitebuilder.annotation.SmallTest;
-import android.database.CursorWindow;
 import android.test.PerformanceTestCase;
 
-import java.util.Arrays;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
+import java.util.Arrays;
+
 public class CursorWindowTest extends TestCase implements PerformanceTestCase {
     public boolean isPerformanceOnly() {
         return false;
diff --git a/core/tests/coretests/src/android/database/DatabaseCursorTest.java b/core/tests/coretests/src/android/database/DatabaseCursorTest.java
index 3507223..eb4fd70 100644
--- a/core/tests/coretests/src/android/database/DatabaseCursorTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseCursorTest.java
@@ -18,10 +18,6 @@
 
 import android.content.ContentValues;
 import android.content.Context;
-import android.database.Cursor;
-import android.database.CursorIndexOutOfBoundsException;
-import android.database.DataSetObserver;
-import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteCursor;
 import android.database.sqlite.SQLiteCursorDriver;
 import android.database.sqlite.SQLiteDatabase;
@@ -29,11 +25,12 @@
 import android.os.Looper;
 import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
index 9d75c78..49fb75b 100644
--- a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
@@ -25,16 +25,17 @@
 import android.database.sqlite.SQLiteDebug;
 import android.database.sqlite.SQLiteException;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.uiautomator.UiDevice;
 import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import android.util.Pair;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
 import junit.framework.Assert;
 
 import java.io.File;
diff --git a/core/tests/coretests/src/android/database/DatabaseLocaleTest.java b/core/tests/coretests/src/android/database/DatabaseLocaleTest.java
index b3282941..ee7936f 100644
--- a/core/tests/coretests/src/android/database/DatabaseLocaleTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseLocaleTest.java
@@ -17,17 +17,17 @@
 package android.database;
 
 import android.database.sqlite.SQLiteDatabase;
-import android.database.Cursor;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
 import android.test.MoreAsserts;
+import android.util.Log;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
 
 import java.util.ArrayList;
 import java.util.Locale;
 
-import junit.framework.TestCase;
-
 public class DatabaseLocaleTest extends TestCase {
 
     private SQLiteDatabase mDatabase;
diff --git a/core/tests/coretests/src/android/database/DatabaseLockTest.java b/core/tests/coretests/src/android/database/DatabaseLockTest.java
index 8d3cf5a..e8936c9 100644
--- a/core/tests/coretests/src/android/database/DatabaseLockTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseLockTest.java
@@ -17,11 +17,13 @@
 package android.database;
 
 import android.database.sqlite.SQLiteDatabase;
-import android.test.suitebuilder.annotation.Suppress;
+import android.test.AndroidTestCase;
 import android.util.Log;
+
+import androidx.test.filters.Suppress;
+
 import java.io.File;
 import java.util.concurrent.atomic.AtomicInteger;
-import android.test.AndroidTestCase;
 
 /* 
  * This is a series of unit tests for database locks.
diff --git a/core/tests/coretests/src/android/database/DatabaseStatementTest.java b/core/tests/coretests/src/android/database/DatabaseStatementTest.java
index 895d715..4b34650 100644
--- a/core/tests/coretests/src/android/database/DatabaseStatementTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseStatementTest.java
@@ -17,14 +17,14 @@
 package android.database;
 
 import android.content.Context;
-import android.database.Cursor;
 import android.database.sqlite.SQLiteConstraintException;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteDoneException;
 import android.database.sqlite.SQLiteStatement;
 import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
 
 import java.io.File;
 
diff --git a/core/tests/coretests/src/android/database/DatabaseStressTest.java b/core/tests/coretests/src/android/database/DatabaseStressTest.java
index 30e46e7..bfea1fc 100644
--- a/core/tests/coretests/src/android/database/DatabaseStressTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseStressTest.java
@@ -17,11 +17,11 @@
 package android.database;
 
 import android.content.Context;
-import android.database.sqlite.*;
+import android.database.sqlite.SQLiteDatabase;
+import android.test.AndroidTestCase;
 import android.util.Log;
 
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.Suppress;
+import androidx.test.filters.Suppress;
 
 import java.io.File;
 
diff --git a/core/tests/coretests/src/android/database/DatabaseUtilsTest.java b/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
index 7c206d7..be156c8 100644
--- a/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
@@ -20,7 +20,7 @@
 
 import static org.junit.Assert.assertEquals;
 
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/database/RedactingCursorTest.java b/core/tests/coretests/src/android/database/RedactingCursorTest.java
index 93998f3..e2d2bae 100644
--- a/core/tests/coretests/src/android/database/RedactingCursorTest.java
+++ b/core/tests/coretests/src/android/database/RedactingCursorTest.java
@@ -22,8 +22,9 @@
 
 import android.content.Context;
 import android.net.Uri;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java b/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
index 9ed3f11b..730a3cb 100644
--- a/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
+++ b/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
@@ -26,11 +26,12 @@
 import android.database.sqlite.SQLiteDatabaseConfiguration;
 import android.database.sqlite.SQLiteDebug;
 import android.database.sqlite.SQLiteOpenHelper;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/database/run_newdb_perf_test.sh b/core/tests/coretests/src/android/database/run_newdb_perf_test.sh
index c5b2c97..95f1f83 100755
--- a/core/tests/coretests/src/android/database/run_newdb_perf_test.sh
+++ b/core/tests/coretests/src/android/database/run_newdb_perf_test.sh
@@ -23,7 +23,7 @@
 
 for (( i=0; i<$RUN_N; i++ ))
 do
-    adb  shell am instrument -e class 'android.database.NewDatabasePerformanceTestSuite' -w 'com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner'
+    adb  shell am instrument -e class 'android.database.NewDatabasePerformanceTestSuite' -w 'com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner'
 done
 
 adb logcat -d > /tmp/testlogcat.txt
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
index 551a58e..5dbcb3c 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
@@ -22,9 +22,10 @@
 
 import android.content.Context;
 import android.database.DatabaseUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java
index ed14a53..f1d27d4 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteConnectionPoolTest.java
@@ -21,11 +21,12 @@
 
 import android.content.Context;
 import android.os.HandlerThread;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
index c52cf6e..78d3c41 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCursorTest.java
@@ -23,7 +23,8 @@
 import android.database.CursorWindow;
 import android.platform.test.annotations.Presubmit;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import java.io.File;
 import java.util.Arrays;
diff --git a/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
index e9e2a4d..564460e 100644
--- a/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
+++ b/core/tests/coretests/src/android/graphics/BitmapFactoryTest.java
@@ -17,14 +17,14 @@
 package android.graphics;
 
 import android.os.ParcelFileDescriptor;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
 import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
 
-
 public class BitmapFactoryTest extends TestCase {
 
     // tests that we can decode bitmaps from MemoryFiles
diff --git a/core/tests/coretests/src/android/graphics/BitmapTest.java b/core/tests/coretests/src/android/graphics/BitmapTest.java
index 3666ddd..e79d2ae 100644
--- a/core/tests/coretests/src/android/graphics/BitmapTest.java
+++ b/core/tests/coretests/src/android/graphics/BitmapTest.java
@@ -16,11 +16,10 @@
 
 package android.graphics;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
-
 public class BitmapTest extends TestCase {
 
     @SmallTest
diff --git a/core/tests/coretests/src/android/graphics/ColorSpaceRendererTest.java b/core/tests/coretests/src/android/graphics/ColorSpaceRendererTest.java
index 6e38fb6..8e9b38c 100644
--- a/core/tests/coretests/src/android/graphics/ColorSpaceRendererTest.java
+++ b/core/tests/coretests/src/android/graphics/ColorSpaceRendererTest.java
@@ -19,8 +19,8 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
-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/core/tests/coretests/src/android/graphics/ColorStateListTest.java b/core/tests/coretests/src/android/graphics/ColorStateListTest.java
index 374d142..1d34f93 100644
--- a/core/tests/coretests/src/android/graphics/ColorStateListTest.java
+++ b/core/tests/coretests/src/android/graphics/ColorStateListTest.java
@@ -19,7 +19,8 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/graphics/FontFileUtilTest.java b/core/tests/coretests/src/android/graphics/FontFileUtilTest.java
index 76267b2..1771671 100644
--- a/core/tests/coretests/src/android/graphics/FontFileUtilTest.java
+++ b/core/tests/coretests/src/android/graphics/FontFileUtilTest.java
@@ -22,11 +22,12 @@
 import android.content.res.AssetManager;
 import android.graphics.fonts.FontFileUtil;
 import android.graphics.fonts.FontVariationAxis;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
 import android.util.Log;
 import android.util.Pair;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 
 import java.io.File;
diff --git a/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java b/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
index 164c1aa..3cfeb25 100644
--- a/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
+++ b/core/tests/coretests/src/android/graphics/GraphicsPerformanceTests.java
@@ -20,7 +20,8 @@
 import android.content.res.Resources;
 import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.Suppress;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java
index b5ed01f..bf56df1 100644
--- a/core/tests/coretests/src/android/graphics/PaintTest.java
+++ b/core/tests/coretests/src/android/graphics/PaintTest.java
@@ -18,9 +18,9 @@
 
 import static org.junit.Assert.assertNotEquals;
 
-import android.graphics.Paint;
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import java.util.Arrays;
 import java.util.HashSet;
diff --git a/core/tests/coretests/src/android/graphics/PathOffsetTest.java b/core/tests/coretests/src/android/graphics/PathOffsetTest.java
index 950f873..6cc42f6 100644
--- a/core/tests/coretests/src/android/graphics/PathOffsetTest.java
+++ b/core/tests/coretests/src/android/graphics/PathOffsetTest.java
@@ -16,13 +16,13 @@
 
 package android.graphics;
 
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap.Config;
 import android.graphics.Path.Direction;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 
-import static org.junit.Assert.assertTrue;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/graphics/PathTest.java b/core/tests/coretests/src/android/graphics/PathTest.java
index 78e4959..c6d6d1f 100644
--- a/core/tests/coretests/src/android/graphics/PathTest.java
+++ b/core/tests/coretests/src/android/graphics/PathTest.java
@@ -16,11 +16,10 @@
 
 package android.graphics;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
-
 public class PathTest extends TestCase {
 
     @SmallTest
diff --git a/core/tests/coretests/src/android/graphics/RectTest.java b/core/tests/coretests/src/android/graphics/RectTest.java
index d31d7d5..2918f44 100644
--- a/core/tests/coretests/src/android/graphics/RectTest.java
+++ b/core/tests/coretests/src/android/graphics/RectTest.java
@@ -23,8 +23,9 @@
 import static org.junit.Assert.assertNull;
 
 import android.platform.test.annotations.Presubmit;
-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/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java b/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
index 909a8d9..e1ca7df 100644
--- a/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
+++ b/core/tests/coretests/src/android/graphics/ThreadBitmapTest.java
@@ -16,7 +16,7 @@
 
 package android.graphics;
 
-import android.test.suitebuilder.annotation.LargeTest;
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index 6fdb71f..c66bac6 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -27,12 +27,13 @@
 import android.graphics.fonts.FontCustomizationParser;
 import android.graphics.fonts.FontFamily;
 import android.graphics.fonts.SystemFonts;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.FontConfig;
 import android.util.ArrayMap;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java
index b0c7976..2d16f82 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java
@@ -22,13 +22,12 @@
 import android.content.Context;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
-import android.graphics.Paint;
-import android.graphics.Typeface;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java b/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
index 781e343..3dc9987 100644
--- a/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java
@@ -1,3 +1,19 @@
+/*
+ * 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.graphics.drawable;
 
 import android.content.res.Resources;
@@ -11,11 +27,12 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 import android.util.Log;
 import android.util.PathParser;
 
+import androidx.test.filters.LargeTest;
+
 import org.junit.Test;
 
 import java.io.File;
diff --git a/core/tests/coretests/src/android/graphics/drawable/DrawableWrapperTest.java b/core/tests/coretests/src/android/graphics/drawable/DrawableWrapperTest.java
index 655efb5..d0a6ff9 100644
--- a/core/tests/coretests/src/android/graphics/drawable/DrawableWrapperTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/DrawableWrapperTest.java
@@ -24,8 +24,9 @@
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Xfermode;
-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/core/tests/coretests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
index 64fadc0..2bdcc28 100644
--- a/core/tests/coretests/src/android/graphics/drawable/IconTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
@@ -25,9 +25,10 @@
 import android.os.HandlerThread;
 import android.os.Parcel;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.io.ByteArrayOutputStream;
diff --git a/core/tests/coretests/src/android/hardware/display/AmbientBrightnessDayStatsTest.java b/core/tests/coretests/src/android/hardware/display/AmbientBrightnessDayStatsTest.java
index f90ae34..0a25bd7 100644
--- a/core/tests/coretests/src/android/hardware/display/AmbientBrightnessDayStatsTest.java
+++ b/core/tests/coretests/src/android/hardware/display/AmbientBrightnessDayStatsTest.java
@@ -23,8 +23,9 @@
 import static org.junit.Assert.fail;
 
 import android.os.Parcel;
-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/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
index dcc51e1..823fca5 100644
--- a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
+++ b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
@@ -22,10 +22,11 @@
 import static org.junit.Assert.fail;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Pair;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
index f30b1a2..daf6139 100644
--- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
+++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java
@@ -22,15 +22,12 @@
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.drawable.ColorDrawable;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.VirtualDisplay;
 import android.media.Image;
 import android.media.ImageReader;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -40,6 +37,8 @@
 import android.view.WindowManager;
 import android.widget.ImageView;
 
+import androidx.test.filters.LargeTest;
+
 import java.nio.ByteBuffer;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
diff --git a/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
new file mode 100644
index 0000000..16be0b0
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.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 android.hardware.hdmi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/** Tests for {@link HdmiUtils} class. */
+public class HdmiUtilsTest {
+
+    @Test
+    public void pathToPort_isMe() {
+        int targetPhysicalAddress = 0x1000;
+        int myPhysicalAddress = 0x1000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                HdmiUtils.TARGET_SAME_PHYSICAL_ADDRESS);
+    }
+
+    @Test
+    public void pathToPort_isDirectlyBelow() {
+        int targetPhysicalAddress = 0x1100;
+        int myPhysicalAddress = 0x1000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+            targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+    }
+
+    @Test
+    public void pathToPort_isBelow() {
+        int targetPhysicalAddress = 0x1110;
+        int myPhysicalAddress = 0x1000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+            targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+    }
+
+    @Test
+    public void pathToPort_neitherMeNorBelow() {
+        int targetPhysicalAddress = 0x3000;
+        int myPhysicalAddress = 0x2000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+        targetPhysicalAddress = 0x2200;
+        myPhysicalAddress = 0x3300;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+        targetPhysicalAddress = 0x2213;
+        myPhysicalAddress = 0x2212;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+        targetPhysicalAddress = 0x2340;
+        myPhysicalAddress = 0x2310;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+    }
+}
diff --git a/core/tests/coretests/src/android/metrics/LogMakerTest.java b/core/tests/coretests/src/android/metrics/LogMakerTest.java
index 3be776d..aabfc28 100644
--- a/core/tests/coretests/src/android/metrics/LogMakerTest.java
+++ b/core/tests/coretests/src/android/metrics/LogMakerTest.java
@@ -13,9 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.metrics;
 
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
diff --git a/core/tests/coretests/src/android/metrics/MetricsReaderTest.java b/core/tests/coretests/src/android/metrics/MetricsReaderTest.java
index 784a12f..96dac64 100644
--- a/core/tests/coretests/src/android/metrics/MetricsReaderTest.java
+++ b/core/tests/coretests/src/android/metrics/MetricsReaderTest.java
@@ -13,10 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.metrics;
 
 import android.metrics.MetricsReader.Event;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
diff --git a/core/tests/coretests/src/android/net/LocalSocketTest.java b/core/tests/coretests/src/android/net/LocalSocketTest.java
index 1286b13..9172237 100644
--- a/core/tests/coretests/src/android/net/LocalSocketTest.java
+++ b/core/tests/coretests/src/android/net/LocalSocketTest.java
@@ -16,12 +16,9 @@
 
 package android.net;
 
-import android.net.Credentials;
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
 import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/net/NetworkKeyTest.java b/core/tests/coretests/src/android/net/NetworkKeyTest.java
index fff23a0..0f1c71d 100644
--- a/core/tests/coretests/src/android/net/NetworkKeyTest.java
+++ b/core/tests/coretests/src/android/net/NetworkKeyTest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.net;
 
 import static org.junit.Assert.assertEquals;
@@ -7,7 +23,8 @@
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiSsid;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java b/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
index c6758ce..29e212f 100644
--- a/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkPolicyManagerTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.net;
 
 import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
diff --git a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
index ff9816a..3e45a79 100644
--- a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
+++ b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.net;
 
 import static junit.framework.Assert.assertFalse;
@@ -9,7 +25,8 @@
 
 import android.Manifest.permission;
 import android.content.Context;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java b/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java
index 5cbf02a..bc12e72 100644
--- a/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java
+++ b/core/tests/coretests/src/android/net/SSLCertificateSocketFactoryTest.java
@@ -19,7 +19,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/net/SSLSessionCacheTest.java b/core/tests/coretests/src/android/net/SSLSessionCacheTest.java
index 11d066b..eec09e6 100644
--- a/core/tests/coretests/src/android/net/SSLSessionCacheTest.java
+++ b/core/tests/coretests/src/android/net/SSLSessionCacheTest.java
@@ -19,10 +19,10 @@
 import com.android.org.conscrypt.ClientSessionContext;
 import com.android.org.conscrypt.SSLClientSessionCache;
 
-import org.mockito.Mockito;
-
 import junit.framework.TestCase;
 
+import org.mockito.Mockito;
+
 import java.security.KeyManagementException;
 import java.security.SecureRandom;
 
diff --git a/core/tests/coretests/src/android/net/ScoredNetworkTest.java b/core/tests/coretests/src/android/net/ScoredNetworkTest.java
index 109f32e..d984d86 100644
--- a/core/tests/coretests/src/android/net/ScoredNetworkTest.java
+++ b/core/tests/coretests/src/android/net/ScoredNetworkTest.java
@@ -16,11 +16,17 @@
 
 package android.net;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.os.Bundle;
 import android.os.Parcel;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/net/SntpClientTest.java b/core/tests/coretests/src/android/net/SntpClientTest.java
index d72738c..87edb6e 100644
--- a/core/tests/coretests/src/android/net/SntpClientTest.java
+++ b/core/tests/coretests/src/android/net/SntpClientTest.java
@@ -20,9 +20,10 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import libcore.util.HexEncoding;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index ea0347d..a33de7b 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -18,7 +18,8 @@
 
 import android.content.ContentUris;
 import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/net/WebAddressTest.java b/core/tests/coretests/src/android/net/WebAddressTest.java
index 6fcb97e..70a6253 100644
--- a/core/tests/coretests/src/android/net/WebAddressTest.java
+++ b/core/tests/coretests/src/android/net/WebAddressTest.java
@@ -16,8 +16,8 @@
 
 package android.net;
 
-import android.net.WebAddress;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 public class WebAddressTest extends TestCase {
diff --git a/core/tests/coretests/src/android/net/http/SslCertificateTest.java b/core/tests/coretests/src/android/net/http/SslCertificateTest.java
index 6a30c6c..1beb1de 100644
--- a/core/tests/coretests/src/android/net/http/SslCertificateTest.java
+++ b/core/tests/coretests/src/android/net/http/SslCertificateTest.java
@@ -17,12 +17,13 @@
 
 package android.net.http;
 
-import android.net.http.SslCertificate;
-import android.test.suitebuilder.annotation.LargeTest;
+import androidx.test.filters.LargeTest;
+
+import junit.framework.TestCase;
+
 import java.io.ByteArrayInputStream;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
-import junit.framework.TestCase;
 
 public class SslCertificateTest extends TestCase {
 
diff --git a/core/tests/coretests/src/android/os/AidlTest.java b/core/tests/coretests/src/android/os/AidlTest.java
index bf11d56..4c51415 100644
--- a/core/tests/coretests/src/android/os/AidlTest.java
+++ b/core/tests/coretests/src/android/os/AidlTest.java
@@ -16,11 +16,10 @@
 
 package android.os;
 
-import android.os.IInterface;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
 import com.google.android.collect.Lists;
+
 import junit.framework.TestCase;
 
 import java.util.List;
diff --git a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
index 6cdb35ab..ce6ad87 100644
--- a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
+++ b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 package android.os;
 
 import static org.junit.Assert.assertEquals;
@@ -25,12 +24,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.support.test.uiautomator.UiDevice;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.aidl.IBpcCallbackObserver;
 import com.android.frameworks.coretests.aidl.IBpcTestAppCmdService;
 import com.android.frameworks.coretests.aidl.IBpcTestServiceCmdService;
@@ -63,7 +63,7 @@
  * Install: adb install -r \
  * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class android.os.BinderProxyCountingTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ * com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  *
  * or
  *
diff --git a/core/tests/coretests/src/android/os/BinderProxyTest.java b/core/tests/coretests/src/android/os/BinderProxyTest.java
index 4c36b5c..aceda2d 100644
--- a/core/tests/coretests/src/android/os/BinderProxyTest.java
+++ b/core/tests/coretests/src/android/os/BinderProxyTest.java
@@ -19,7 +19,8 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
 
 public class BinderProxyTest extends AndroidTestCase {
     private static class CountingListener implements Binder.ProxyTransactListener {
diff --git a/core/tests/coretests/src/android/os/BinderTest.java b/core/tests/coretests/src/android/os/BinderTest.java
index 534c5cd..a354195 100644
--- a/core/tests/coretests/src/android/os/BinderTest.java
+++ b/core/tests/coretests/src/android/os/BinderTest.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
@@ -43,4 +43,13 @@
         Binder.restoreCallingWorkSource(token);
         assertEquals(UID, Binder.getCallingWorkSourceUid());
     }
+
+    @SmallTest
+    public void testGetCallingUidOrThrow() throws Exception {
+        try {
+            Binder.getCallingUidOrThrow();
+            throw new AssertionError("IllegalStateException expected");
+        } catch (IllegalStateException expected) {
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/os/BinderThreadPriorityService.java b/core/tests/coretests/src/android/os/BinderThreadPriorityService.java
index 47a4483..ed42058 100644
--- a/core/tests/coretests/src/android/os/BinderThreadPriorityService.java
+++ b/core/tests/coretests/src/android/os/BinderThreadPriorityService.java
@@ -18,7 +18,6 @@
 
 import android.app.Service;
 import android.content.Intent;
-import android.text.TextUtils;
 import android.util.Log;
 
 /**
diff --git a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
index 56e977c..48c9df6 100644
--- a/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
+++ b/core/tests/coretests/src/android/os/BinderThreadPriorityTest.java
@@ -21,7 +21,6 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 
 import java.io.File;
diff --git a/core/tests/coretests/src/android/os/BinderWorkSourceTest.java b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
index 5664df6..e16a3db 100644
--- a/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
+++ b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
@@ -24,9 +24,10 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/os/BrightnessLimit.java b/core/tests/coretests/src/android/os/BrightnessLimit.java
index fabcf3d..5a3724f 100644
--- a/core/tests/coretests/src/android/os/BrightnessLimit.java
+++ b/core/tests/coretests/src/android/os/BrightnessLimit.java
@@ -18,7 +18,6 @@
 
 import android.app.Activity;
 import android.hardware.display.DisplayManager;
-import android.os.Bundle;
 import android.provider.Settings;
 import android.view.View;
 import android.view.View.OnClickListener;
diff --git a/core/tests/coretests/src/android/os/BroadcasterTest.java b/core/tests/coretests/src/android/os/BroadcasterTest.java
index 551ea8d..b4c47af9 100644
--- a/core/tests/coretests/src/android/os/BroadcasterTest.java
+++ b/core/tests/coretests/src/android/os/BroadcasterTest.java
@@ -16,11 +16,8 @@
 
 package android.os;
 
-import android.os.Broadcaster;
-import android.os.Handler;
-import android.os.Message;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.MediumTest;
+
 import junit.framework.TestCase;
 
 public class BroadcasterTest extends TestCase {
diff --git a/core/tests/coretests/src/android/os/BuildTest.java b/core/tests/coretests/src/android/os/BuildTest.java
index 3758627..decc768 100644
--- a/core/tests/coretests/src/android/os/BuildTest.java
+++ b/core/tests/coretests/src/android/os/BuildTest.java
@@ -16,9 +16,8 @@
 
 package android.os;
 
-import android.os.Build;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
+import androidx.test.filters.SmallTest;
+
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java
index 9fcf96d..e4dc993 100644
--- a/core/tests/coretests/src/android/os/BundleTest.java
+++ b/core/tests/coretests/src/android/os/BundleTest.java
@@ -20,8 +20,8 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/os/EnvironmentTest.java b/core/tests/coretests/src/android/os/EnvironmentTest.java
index 5189df5..d98ceaf 100644
--- a/core/tests/coretests/src/android/os/EnvironmentTest.java
+++ b/core/tests/coretests/src/android/os/EnvironmentTest.java
@@ -25,8 +25,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/os/FileObserverTest.java b/core/tests/coretests/src/android/os/FileObserverTest.java
index 93e27af..ece7645 100644
--- a/core/tests/coretests/src/android/os/FileObserverTest.java
+++ b/core/tests/coretests/src/android/os/FileObserverTest.java
@@ -16,13 +16,14 @@
 
 package android.os;
 
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import androidx.test.filters.MediumTest;
+
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.util.Log;
-
 import java.io.File;
 import java.io.FileOutputStream;
 import java.util.Iterator;
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 514ea0c..5bce227c 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -51,8 +51,9 @@
 import android.content.Context;
 import android.os.FileUtils.MemoryPipe;
 import android.provider.DocumentsContract.Document;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
 import libcore.io.Streams;
 
diff --git a/core/tests/coretests/src/android/os/HandlerTester.java b/core/tests/coretests/src/android/os/HandlerTester.java
index a216a0b..fa442f4 100644
--- a/core/tests/coretests/src/android/os/HandlerTester.java
+++ b/core/tests/coretests/src/android/os/HandlerTester.java
@@ -16,10 +16,6 @@
 
 package android.os;
 
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-
 public abstract class HandlerTester extends Thread {
     public abstract void go();
     public abstract void handleMessage(Message msg);
diff --git a/core/tests/coretests/src/android/os/HandlerThreadTest.java b/core/tests/coretests/src/android/os/HandlerThreadTest.java
index 9772aa4..93cfc40 100644
--- a/core/tests/coretests/src/android/os/HandlerThreadTest.java
+++ b/core/tests/coretests/src/android/os/HandlerThreadTest.java
@@ -16,13 +16,9 @@
 
 package android.os;
 
+import androidx.test.filters.MediumTest;
+
 import junit.framework.TestCase;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Message;
-import android.os.Process;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
 
 public class HandlerThreadTest extends TestCase {
     private static final int TEST_WHAT = 1;
diff --git a/core/tests/coretests/src/android/os/IdleHandlerTest.java b/core/tests/coretests/src/android/os/IdleHandlerTest.java
index 6c0a862..d8886c9 100644
--- a/core/tests/coretests/src/android/os/IdleHandlerTest.java
+++ b/core/tests/coretests/src/android/os/IdleHandlerTest.java
@@ -16,11 +16,10 @@
 
 package android.os;
 
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
 import android.os.MessageQueue.IdleHandler;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
+
 import junit.framework.TestCase;
 
 public class IdleHandlerTest extends TestCase {
diff --git a/core/tests/coretests/src/android/os/LocaleListTest.java b/core/tests/coretests/src/android/os/LocaleListTest.java
index 17ef773..1f00a7a 100644
--- a/core/tests/coretests/src/android/os/LocaleListTest.java
+++ b/core/tests/coretests/src/android/os/LocaleListTest.java
@@ -13,14 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.os;
 
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.util.Locale;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
+import java.util.Locale;
+
 public class LocaleListTest extends TestCase {
     @SmallTest
     public void testConstructor() throws Exception {
diff --git a/core/tests/coretests/src/android/os/MemoryFileTest.java b/core/tests/coretests/src/android/os/MemoryFileTest.java
index 20b298d..05c2995 100644
--- a/core/tests/coretests/src/android/os/MemoryFileTest.java
+++ b/core/tests/coretests/src/android/os/MemoryFileTest.java
@@ -17,8 +17,9 @@
 package android.os;
 
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/core/tests/coretests/src/android/os/MessageQueueTest.java b/core/tests/coretests/src/android/os/MessageQueueTest.java
index 1cd1020..2c5588e 100644
--- a/core/tests/coretests/src/android/os/MessageQueueTest.java
+++ b/core/tests/coretests/src/android/os/MessageQueueTest.java
@@ -16,11 +16,9 @@
 
 package android.os;
 
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 import junit.framework.TestCase;
 
 @Suppress  // Failing.
diff --git a/core/tests/coretests/src/android/os/MessengerService.java b/core/tests/coretests/src/android/os/MessengerService.java
index f15e134..db33471 100644
--- a/core/tests/coretests/src/android/os/MessengerService.java
+++ b/core/tests/coretests/src/android/os/MessengerService.java
@@ -18,11 +18,6 @@
 
 import android.app.Service;
 import android.content.Intent;
-import android.os.RemoteException;
-import android.os.IBinder;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
 
 public class MessengerService extends Service {
     private final Handler mHandler = new Handler() {
diff --git a/core/tests/coretests/src/android/os/MessengerTest.java b/core/tests/coretests/src/android/os/MessengerTest.java
index 473ffe2..9143ff1 100644
--- a/core/tests/coretests/src/android/os/MessengerTest.java
+++ b/core/tests/coretests/src/android/os/MessengerTest.java
@@ -20,13 +20,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.os.RemoteException;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
 
 public class MessengerTest extends AndroidTestCase {
     private Messenger mServiceMessenger;
diff --git a/core/tests/coretests/src/android/os/OsTests.java b/core/tests/coretests/src/android/os/OsTests.java
index 2b84126..08fb945 100644
--- a/core/tests/coretests/src/android/os/OsTests.java
+++ b/core/tests/coretests/src/android/os/OsTests.java
@@ -16,12 +16,8 @@
 
 package android.os;
 
-import com.google.android.collect.Lists;
 import junit.framework.TestSuite;
 
-import java.util.Enumeration;
-import java.util.List;
-
 public class OsTests {
     public static TestSuite suite() {
         TestSuite suite = new TestSuite(OsTests.class.getName());
diff --git a/core/tests/coretests/src/android/os/ParcelNullabilityTest.java b/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
index 516dc0a..a6b296d 100644
--- a/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
+++ b/core/tests/coretests/src/android/os/ParcelNullabilityTest.java
@@ -20,10 +20,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArrayMap;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/os/PatternMatcherTest.java b/core/tests/coretests/src/android/os/PatternMatcherTest.java
index 9645ccc..82350cd 100644
--- a/core/tests/coretests/src/android/os/PatternMatcherTest.java
+++ b/core/tests/coretests/src/android/os/PatternMatcherTest.java
@@ -1,9 +1,27 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.os;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
-import org.junit.runner.RunWith;
+
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 @RunWith(JUnit4.class)
diff --git a/core/tests/coretests/src/android/os/PerformanceCollectorTest.java b/core/tests/coretests/src/android/os/PerformanceCollectorTest.java
index 7533c84..38ad90f 100644
--- a/core/tests/coretests/src/android/os/PerformanceCollectorTest.java
+++ b/core/tests/coretests/src/android/os/PerformanceCollectorTest.java
@@ -17,15 +17,16 @@
 package android.os;
 
 import android.os.PerformanceCollector.PerformanceResultsWriter;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Random;
 
-import junit.framework.TestCase;
-
 public class PerformanceCollectorTest extends TestCase {
 
     private PerformanceCollector mPerfCollector;
diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java
index a828f44..1b587dd 100644
--- a/core/tests/coretests/src/android/os/PowerManagerTest.java
+++ b/core/tests/coretests/src/android/os/PowerManagerTest.java
@@ -21,10 +21,11 @@
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.uiautomator.UiDevice;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 
 import org.junit.After;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/os/PowerManagerVrTest.java b/core/tests/coretests/src/android/os/PowerManagerVrTest.java
index e01e5fa..5d2c65b 100644
--- a/core/tests/coretests/src/android/os/PowerManagerVrTest.java
+++ b/core/tests/coretests/src/android/os/PowerManagerVrTest.java
@@ -19,16 +19,14 @@
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.provider.Settings;
-import android.service.dreams.IDreamManager;
 import android.service.dreams.DreamService;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
+import android.service.dreams.IDreamManager;
 import android.test.ActivityInstrumentationTestCase2;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+
 /**
  * Tests dream aspects of PowerManager.
  */
diff --git a/core/tests/coretests/src/android/os/ProcessTest.java b/core/tests/coretests/src/android/os/ProcessTest.java
index 1f5b7c8..b749e71 100644
--- a/core/tests/coretests/src/android/os/ProcessTest.java
+++ b/core/tests/coretests/src/android/os/ProcessTest.java
@@ -17,14 +17,10 @@
 
 package android.os;
 
-import android.os.Process;
-import android.os.UserHandle;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.MediumTest;
 
 import junit.framework.TestCase;
 
-
 public class ProcessTest extends TestCase {
 
     @MediumTest
diff --git a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
index 9e15231..d5163e1 100644
--- a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
+++ b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
@@ -24,10 +24,11 @@
 import static org.junit.Assert.assertEquals;
 
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
 import android.system.Os;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java b/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java
index 9e44554..8085993 100644
--- a/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java
+++ b/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.os;
 
 import android.app.ActivityManager;
@@ -20,10 +21,10 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.os.Process;
 import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 /**
  * Tests ActivityManager#setPersistentVrThread and ActivityManager#setVrThread's
diff --git a/core/tests/coretests/src/android/os/TestHandlerThread.java b/core/tests/coretests/src/android/os/TestHandlerThread.java
index 7e84af3..8c0330b 100644
--- a/core/tests/coretests/src/android/os/TestHandlerThread.java
+++ b/core/tests/coretests/src/android/os/TestHandlerThread.java
@@ -16,11 +16,6 @@
 
 package android.os;
 
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.MessageQueue.IdleHandler;
-
 abstract class TestHandlerThread {
     private boolean mDone = false;
     private boolean mSuccess = false;
diff --git a/core/tests/coretests/src/android/os/TestVrActivity.java b/core/tests/coretests/src/android/os/TestVrActivity.java
index 33ff164..75df7c2 100644
--- a/core/tests/coretests/src/android/os/TestVrActivity.java
+++ b/core/tests/coretests/src/android/os/TestVrActivity.java
@@ -17,7 +17,6 @@
 package android.os;
 
 import android.app.Activity;
-import android.os.Bundle;
 import android.service.vr.VrListenerService;
 
 import java.util.concurrent.CountDownLatch;
diff --git a/core/tests/coretests/src/android/os/TraceTest.java b/core/tests/coretests/src/android/os/TraceTest.java
index 1541553..5cad549 100644
--- a/core/tests/coretests/src/android/os/TraceTest.java
+++ b/core/tests/coretests/src/android/os/TraceTest.java
@@ -16,13 +16,13 @@
 
 package android.os;
 
-import android.os.Debug;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+
 /**
  * This class is used to test the native tracing support.  Run this test
  * while tracing on the emulator and then run traceview to view the trace.
diff --git a/core/tests/coretests/src/android/os/UserHandleTest.java b/core/tests/coretests/src/android/os/UserHandleTest.java
index af559fd..4a1cdbf 100644
--- a/core/tests/coretests/src/android/os/UserHandleTest.java
+++ b/core/tests/coretests/src/android/os/UserHandleTest.java
@@ -25,7 +25,7 @@
 
 import static org.junit.Assert.assertEquals;
 
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/os/VintfObjectTest.java b/core/tests/coretests/src/android/os/VintfObjectTest.java
index 44510c2..af3660a 100644
--- a/core/tests/coretests/src/android/os/VintfObjectTest.java
+++ b/core/tests/coretests/src/android/os/VintfObjectTest.java
@@ -16,7 +16,6 @@
 
 package android.os;
 
-import junit.framework.Assert;
 import junit.framework.TestCase;
 
 public class VintfObjectTest extends TestCase {
diff --git a/core/tests/coretests/src/android/os/WorkSourceTest.java b/core/tests/coretests/src/android/os/WorkSourceTest.java
index 425ab89..e94d60c 100644
--- a/core/tests/coretests/src/android/os/WorkSourceTest.java
+++ b/core/tests/coretests/src/android/os/WorkSourceTest.java
@@ -341,12 +341,37 @@
     }
 
     public void testGetAttributionId() {
-        WorkSource ws1 = new WorkSource();
-        WorkChain wc = ws1.createWorkChain();
-        wc.addNode(100, "tag");
-        assertEquals(100, wc.getAttributionUid());
-        wc.addNode(200, "tag2");
-        assertEquals(100, wc.getAttributionUid());
+        WorkSource ws = new WorkSource();
+        WorkChain wc1 = ws.createWorkChain();
+        wc1.addNode(100, "tag");
+        assertEquals(100, wc1.getAttributionUid());
+        assertEquals(100, ws.getAttributionUid());
+        wc1.addNode(200, "tag2");
+        assertEquals(100, wc1.getAttributionUid());
+        assertEquals(100, ws.getAttributionUid());
+        WorkChain wc2 = ws.createWorkChain();
+        wc2.addNode(300, "tag3");
+        assertEquals(300, wc2.getAttributionUid());
+        assertEquals(100, ws.getAttributionUid());
+    }
+
+    public void testGetAttributionIdWithoutWorkChain() {
+        WorkSource ws1 = new WorkSource(100);
+        ws1.add(200);
+        WorkSource ws2 = new WorkSource();
+        ws2.add(100);
+        ws2.add(200);
+        assertEquals(100, ws1.getAttributionUid());
+        assertEquals(100, ws2.getAttributionUid());
+    }
+
+    public void testGetAttributionWhenEmpty() {
+        WorkSource ws = new WorkSource();
+        assertEquals(-1, ws.getAttributionUid());
+        WorkChain wc = ws.createWorkChain();
+        assertEquals(-1, ws.getAttributionUid());
+        assertEquals(-1, wc.getAttributionUid());
+        assertNull(wc.getAttributionTag());
     }
 
     public void testGetAttributionTag() {
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
index 3ec297c..62f2ac2 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
@@ -19,7 +19,8 @@
 import android.os.ParcelFileDescriptor;
 import android.os.ProxyFileDescriptorCallback;
 import android.system.ErrnoException;
-import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/preference/ListPreferenceTest.java b/core/tests/coretests/src/android/preference/ListPreferenceTest.java
index 72f62f1..51dbb64 100644
--- a/core/tests/coretests/src/android/preference/ListPreferenceTest.java
+++ b/core/tests/coretests/src/android/preference/ListPreferenceTest.java
@@ -16,10 +16,10 @@
 
 package android.preference;
 
-import android.preference.ListPreference;
-import android.support.test.filters.LargeTest;
 import android.test.AndroidTestCase;
 
+import androidx.test.filters.LargeTest;
+
 @LargeTest
 public class ListPreferenceTest extends AndroidTestCase {
     public void testListPreferenceSummaryFromEntries() {
diff --git a/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java b/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java
index 654474c..0deb77e 100644
--- a/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java
+++ b/core/tests/coretests/src/android/preference/PreferenceIconSpaceTest.java
@@ -16,20 +16,20 @@
 
 package android.preference;
 
-
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
index 5d12f7e..94d85e6 100644
--- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -41,9 +41,10 @@
 import android.print.test.services.PrinterDiscoverySessionCallbacks;
 import android.print.test.services.StubbablePrinterDiscoverySession;
 import android.printservice.recommendation.IRecommendationsChangeListener;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index 800b864..17e9654 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -28,9 +28,10 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/provider/DocumentsProviderTest.java b/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
index 1465d0a9..02a9adf 100644
--- a/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/DocumentsProviderTest.java
@@ -20,9 +20,10 @@
 import android.content.ContentResolver;
 import android.net.Uri;
 import android.provider.DocumentsContract.Path;
-import android.support.test.filters.SmallTest;
 import android.test.ProviderTestCase2;
 
+import androidx.test.filters.SmallTest;
+
 import java.util.Arrays;
 
 /**
diff --git a/core/tests/coretests/src/android/provider/FontsContractE2ETest.java b/core/tests/coretests/src/android/provider/FontsContractE2ETest.java
index 2955869..7e02be8 100644
--- a/core/tests/coretests/src/android/provider/FontsContractE2ETest.java
+++ b/core/tests/coretests/src/android/provider/FontsContractE2ETest.java
@@ -25,25 +25,25 @@
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.Signature;
 import android.graphics.Typeface;
 import android.os.Handler;
-import android.provider.FontsContract.Columns;
 import android.provider.FontsContract.FontFamilyResult;
-import android.provider.FontsContract.FontInfo;
-import android.provider.FontsContract;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import java.util.ArrayList;
-import java.util.List;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class FontsContractE2ETest {
diff --git a/core/tests/coretests/src/android/provider/FontsContractTest.java b/core/tests/coretests/src/android/provider/FontsContractTest.java
index d42d79e..c5d6f7f 100644
--- a/core/tests/coretests/src/android/provider/FontsContractTest.java
+++ b/core/tests/coretests/src/android/provider/FontsContractTest.java
@@ -13,31 +13,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.provider;
 
+import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_NOT_FOUND;
+import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_UNAVAILABLE;
+import static android.provider.FontsContract.Columns.RESULT_CODE_MALFORMED_QUERY;
+import static android.provider.FontsContract.Columns.RESULT_CODE_OK;
+
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import static android.provider.FontsContract.Columns.RESULT_CODE_OK;
-import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_NOT_FOUND;
-import static android.provider.FontsContract.Columns.RESULT_CODE_FONT_UNAVAILABLE;
-import static android.provider.FontsContract.Columns.RESULT_CODE_MALFORMED_QUERY;
-
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ProviderInfo;
 import android.content.pm.Signature;
 import android.database.MatrixCursor;
 import android.graphics.fonts.FontVariationAxis;
 import android.provider.FontsContract.FontInfo;
-import android.support.test.filters.SmallTest;
 import android.test.ProviderTestCase2;
 import android.util.Base64;
 
+import androidx.test.filters.SmallTest;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
diff --git a/core/tests/coretests/src/android/provider/MockFontProvider.java b/core/tests/coretests/src/android/provider/MockFontProvider.java
index ad5b130..e527dec 100644
--- a/core/tests/coretests/src/android/provider/MockFontProvider.java
+++ b/core/tests/coretests/src/android/provider/MockFontProvider.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.provider;
 
 import static android.provider.FontsContract.Columns;
@@ -21,16 +22,13 @@
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.res.AssetFileDescriptor;
 import android.content.res.AssetManager;
 import android.database.Cursor;
 import android.database.MatrixCursor;
-import android.graphics.fonts.FontVariationAxis;
 import android.net.Uri;
-import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
-import android.util.ArraySet;
-import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -46,8 +44,6 @@
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
-import com.android.internal.annotations.GuardedBy;
-
 public class MockFontProvider extends ContentProvider {
     final static String AUTHORITY = "android.provider.fonts.font";
 
diff --git a/core/tests/coretests/src/android/provider/SearchRecentSuggestionsProviderTest.java b/core/tests/coretests/src/android/provider/SearchRecentSuggestionsProviderTest.java
index 7458de5..f84355f 100644
--- a/core/tests/coretests/src/android/provider/SearchRecentSuggestionsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SearchRecentSuggestionsProviderTest.java
@@ -21,9 +21,9 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.test.ProviderTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 /**
  * ProviderTestCase that performs unit tests of SearchRecentSuggestionsProvider.
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index f8bd4e3..a010cb6 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -27,8 +27,9 @@
 import static java.lang.reflect.Modifier.isStatic;
 
 import android.platform.test.annotations.Presubmit;
-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;
@@ -99,6 +100,7 @@
                     Settings.Global.ACTIVITY_MANAGER_CONSTANTS,
                     Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED,
                     Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED,
+                    Settings.Global.ADB_ALLOWED_CONNECTION_TIME,
                     Settings.Global.ADB_ENABLED,
                     Settings.Global.ADD_USERS_WHEN_LOCKED,
                     Settings.Global.AIRPLANE_MODE_ON,
@@ -114,10 +116,12 @@
                     Settings.Global.ANOMALY_CONFIG_VERSION,
                     Settings.Global.APN_DB_UPDATE_CONTENT_URL,
                     Settings.Global.APN_DB_UPDATE_METADATA_URL,
+                    Settings.Global.APPLY_RAMPING_RINGER,
                     Settings.Global.APP_BINDING_CONSTANTS,
                     Settings.Global.APP_IDLE_CONSTANTS,
                     Settings.Global.APP_OPS_CONSTANTS,
                     Settings.Global.APP_STANDBY_ENABLED,
+                    Settings.Global.APP_TIME_LIMIT_USAGE_SOURCE,
                     Settings.Global.ASSISTED_GPS_ENABLED,
                     Settings.Global.AUDIO_SAFE_VOLUME_STATE,
                     Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
@@ -143,6 +147,7 @@
                     Settings.Global.BLOCKED_SLICES,
                     Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT,
                     Settings.Global.BLOCKING_HELPER_STREAK_LIMIT,
+                    Settings.Global.BLUETOOTH_BTSNOOP_DEFAULT_MODE,
                     Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
                     Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
                     Settings.Global.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX,
@@ -197,6 +202,7 @@
                     Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
                     Settings.Global.DATA_STALL_EVALUATION_TYPE,
                     Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL,
+                    Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK,
                     Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD,
                     Settings.Global.DEBUG_APP,
                     Settings.Global.DEBUG_VIEW_ATTRIBUTES,
@@ -268,6 +274,7 @@
                     Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS,
                     Settings.Global.GNSS_SATELLITE_BLACKLIST,
                     Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
+                    Settings.Global.HDMI_CEC_SWITCH_ENABLED,
                     Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
                     Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
                     Settings.Global.HDMI_CONTROL_ENABLED,
@@ -291,6 +298,7 @@
                     Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
                     Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
                     Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
+                    Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST,
                     Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS,
                     Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
                     Settings.Global.LOCATION_GLOBAL_KILL_SWITCH,
@@ -309,6 +317,7 @@
                     Settings.Global.MDC_INITIAL_MAX_RETRY,
                     Settings.Global.MHL_INPUT_SWITCHING_ENABLED,
                     Settings.Global.MHL_POWER_CHARGE_ENABLED,
+                    Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS,
                     Settings.Global.MOBILE_DATA, // Candidate for backup?
                     Settings.Global.MOBILE_DATA_ALWAYS_ON,
                     Settings.Global.MODE_RINGER,
@@ -380,8 +389,6 @@
                     Settings.Global.POLICY_CONTROL,
                     Settings.Global.POWER_MANAGER_CONSTANTS,
                     Settings.Global.PREFERRED_NETWORK_MODE,
-                    Settings.Global.PRIV_APP_OOB_ENABLED,
-                    Settings.Global.PRIV_APP_OOB_LIST,
                     Settings.Global.PRIVATE_DNS_DEFAULT_MODE,
                     Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED,
                     Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED,
@@ -475,7 +482,11 @@
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
-                    Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP,
+                    Settings.Global.GUP_DEV_ALL_APPS,
+                    Settings.Global.GUP_DEV_OPT_IN_APPS,
+                    Settings.Global.GUP_DEV_OPT_OUT_APPS,
+                    Settings.Global.GUP_BLACKLIST,
+                    Settings.Global.GAME_DRIVER_WHITELIST,
                     Settings.Global.GPU_DEBUG_LAYER_APP,
                     Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
                     Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
@@ -546,7 +557,16 @@
                     Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS,
                     Settings.Global.BACKUP_MULTI_USER_ENABLED,
                     Settings.Global.ISOLATED_STORAGE_LOCAL,
-                    Settings.Global.ISOLATED_STORAGE_REMOTE);
+                    Settings.Global.ISOLATED_STORAGE_REMOTE,
+                    Settings.Global.APPOP_HISTORY_PARAMETERS,
+                    Settings.Global.APPOP_HISTORY_MODE,
+                    Settings.Global.APPOP_HISTORY_INTERVAL_MULTIPLIER,
+                    Settings.Global.APPOP_HISTORY_BASE_INTERVAL_MILLIS,
+                    Settings.Global.ENABLE_RADIO_BUG_DETECTION,
+                    Settings.Global.RADIO_BUG_WAKELOCK_TIMEOUT_COUNT_THRESHOLD,
+                    Settings.Global.RADIO_BUG_SYSTEM_ERROR_COUNT_THRESHOLD,
+                    Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT,
+                    Settings.Global.MODEM_STACK_ENABLED_FOR_SLOT);
     private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
              newHashSet(
                  Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
@@ -655,6 +675,7 @@
                  Settings.Secure.SMS_DEFAULT_APPLICATION,
                  Settings.Secure.SPELL_CHECKER_ENABLED,  // Intentionally removed in Q
                  Settings.Secure.TRUST_AGENTS_INITIALIZED,
+                 Settings.Secure.TV_APP_USES_NON_SYSTEM_INPUTS,
                  Settings.Secure.TV_INPUT_CUSTOM_LABELS,
                  Settings.Secure.TV_INPUT_HIDDEN_INPUTS,
                  Settings.Secure.TV_USER_SETUP_COMPLETE,
diff --git a/core/tests/coretests/src/android/provider/SettingsProviderTest.java b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
index cb6f0e6..a5f5f67 100644
--- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
@@ -34,9 +34,10 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
 
 import java.util.HashMap;
 import java.util.List;
diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
index b0d29bd..08f9de6 100644
--- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
@@ -22,8 +22,9 @@
 
 import android.platform.test.annotations.Presubmit;
 import android.provider.SettingsValidators.Validator;
-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/core/tests/coretests/src/android/provider/SmsProviderTest.java b/core/tests/coretests/src/android/provider/SmsProviderTest.java
index af4d1a6..67ac8ea 100644
--- a/core/tests/coretests/src/android/provider/SmsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SmsProviderTest.java
@@ -22,8 +22,9 @@
 import android.net.Uri;
 import android.provider.Telephony.Sms;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
 
 import java.util.GregorianCalendar;
 
diff --git a/core/tests/coretests/src/android/provider/TestFontsProvider.java b/core/tests/coretests/src/android/provider/TestFontsProvider.java
index 46906df..c3457fa 100644
--- a/core/tests/coretests/src/android/provider/TestFontsProvider.java
+++ b/core/tests/coretests/src/android/provider/TestFontsProvider.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.provider;
 
 import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
@@ -23,7 +24,6 @@
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.database.MatrixCursor;
-import android.graphics.Typeface;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/KeyChainProtectionParamsTest.java b/core/tests/coretests/src/android/security/keystore/recovery/KeyChainProtectionParamsTest.java
index 0c9c4c1..ce0bf30 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/KeyChainProtectionParamsTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/KeyChainProtectionParamsTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-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/core/tests/coretests/src/android/security/keystore/recovery/KeyChainSnapshotTest.java b/core/tests/coretests/src/android/security/keystore/recovery/KeyChainSnapshotTest.java
index 61ab152..37fe22f 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/KeyChainSnapshotTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/KeyChainSnapshotTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.google.common.collect.Lists;
 
@@ -44,6 +45,7 @@
     private static final int USER_SECRET_TYPE = KeyChainProtectionParams.TYPE_LOCKSCREEN;
     private static final String KEY_ALIAS = "steph";
     private static final byte[] KEY_MATERIAL = new byte[] { 3, 5, 7, 9, 1 };
+    private static final byte[] KEY_METADATA = new byte[] { 5, 3, 11, 13 };
     private static final CertPath CERT_PATH = TestData.getThmCertPath();
 
     @Test
@@ -99,6 +101,7 @@
         WrappedApplicationKey wrappedApplicationKey = snapshot.getWrappedApplicationKeys().get(0);
         assertEquals(KEY_ALIAS, wrappedApplicationKey.getAlias());
         assertArrayEquals(KEY_MATERIAL, wrappedApplicationKey.getEncryptedKeyMaterial());
+        assertArrayEquals(KEY_METADATA, wrappedApplicationKey.getMetadata());
     }
 
     @Test
@@ -165,6 +168,7 @@
         WrappedApplicationKey wrappedApplicationKey = snapshot.getWrappedApplicationKeys().get(0);
         assertEquals(KEY_ALIAS, wrappedApplicationKey.getAlias());
         assertArrayEquals(KEY_MATERIAL, wrappedApplicationKey.getEncryptedKeyMaterial());
+        assertArrayEquals(KEY_METADATA, wrappedApplicationKey.getMetadata());
     }
 
     private static KeyChainSnapshot createKeyChainSnapshot() throws Exception {
@@ -196,6 +200,7 @@
         return new WrappedApplicationKey.Builder()
                 .setAlias(KEY_ALIAS)
                 .setEncryptedKeyMaterial(KEY_MATERIAL)
+                .setMetadata(KEY_METADATA)
                 .build();
     }
 
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/KeyDerivationParamsTest.java b/core/tests/coretests/src/android/security/keystore/recovery/KeyDerivationParamsTest.java
index b6af9bb..2b37b52 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/KeyDerivationParamsTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/KeyDerivationParamsTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-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/core/tests/coretests/src/android/security/keystore/recovery/RecoveryCertPathTest.java b/core/tests/coretests/src/android/security/keystore/recovery/RecoveryCertPathTest.java
index dd8cd8d..3b8f715 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/RecoveryCertPathTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/RecoveryCertPathTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.fail;
 
 import android.os.Parcel;
-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/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java b/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
index a5a3ca9..2b15d73 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/TrustedRootCertificatesTest.java
@@ -20,8 +20,8 @@
 
 import static org.junit.Assert.assertTrue;
 
-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/core/tests/coretests/src/android/security/keystore/recovery/WrappedApplicationKeyTest.java b/core/tests/coretests/src/android/security/keystore/recovery/WrappedApplicationKeyTest.java
index 15afbdd..aec54e1 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/WrappedApplicationKeyTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/WrappedApplicationKeyTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-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.After;
 import org.junit.Before;
@@ -34,6 +35,7 @@
 
     private static final String ALIAS = "karlin";
     private static final byte[] KEY_MATERIAL = new byte[] { 0, 1, 2, 3, 4 };
+    private static final byte[] METADATA = new byte[] {3, 2, 1, 0};
 
     private Parcel mParcel;
 
@@ -58,8 +60,18 @@
     }
 
     @Test
+    public void build_setsMetadata_nonNull() {
+        assertArrayEquals(METADATA, buildTestKeyWithMetadata(METADATA).getMetadata());
+    }
+
+    @Test
+    public void build_setsMetadata_null() {
+        assertArrayEquals(null, buildTestKeyWithMetadata(null).getMetadata());
+    }
+
+    @Test
     public void writeToParcel_writesAliasToParcel() {
-        buildTestKey().writeToParcel(mParcel, /*flags=*/ 0);
+        buildTestKeyWithMetadata(/*metadata=*/ null).writeToParcel(mParcel, /*flags=*/ 0);
 
         mParcel.setDataPosition(0);
         WrappedApplicationKey readFromParcel =
@@ -69,7 +81,7 @@
 
     @Test
     public void writeToParcel_writesKeyMaterial() {
-        buildTestKey().writeToParcel(mParcel, /*flags=*/ 0);
+        buildTestKeyWithMetadata(/*metadata=*/ null).writeToParcel(mParcel, /*flags=*/ 0);
 
         mParcel.setDataPosition(0);
         WrappedApplicationKey readFromParcel =
@@ -77,10 +89,48 @@
         assertArrayEquals(KEY_MATERIAL, readFromParcel.getEncryptedKeyMaterial());
     }
 
+    @Test
+    public void writeToParcel_writesMetadata_nonNull() {
+        buildTestKeyWithMetadata(METADATA).writeToParcel(mParcel, /*flags=*/ 0);
+
+        mParcel.setDataPosition(0);
+        WrappedApplicationKey readFromParcel =
+                WrappedApplicationKey.CREATOR.createFromParcel(mParcel);
+        assertArrayEquals(METADATA, readFromParcel.getMetadata());
+    }
+
+    @Test
+    public void writeToParcel_writesMetadata_null() {
+        buildTestKeyWithMetadata(/*metadata=*/ null).writeToParcel(mParcel, /*flags=*/ 0);
+
+        mParcel.setDataPosition(0);
+        WrappedApplicationKey readFromParcel =
+                WrappedApplicationKey.CREATOR.createFromParcel(mParcel);
+        assertArrayEquals(null, readFromParcel.getMetadata());
+    }
+
+    @Test
+    public void writeToParcel_writesMetadata_absent() {
+        buildTestKey().writeToParcel(mParcel, /*flags=*/ 0);
+
+        mParcel.setDataPosition(0);
+        WrappedApplicationKey readFromParcel =
+                WrappedApplicationKey.CREATOR.createFromParcel(mParcel);
+        assertArrayEquals(null, readFromParcel.getMetadata());
+    }
+
     private WrappedApplicationKey buildTestKey() {
         return new WrappedApplicationKey.Builder()
                 .setAlias(ALIAS)
                 .setEncryptedKeyMaterial(KEY_MATERIAL)
                 .build();
     }
+
+    private WrappedApplicationKey buildTestKeyWithMetadata(byte[] metadata) {
+        return new WrappedApplicationKey.Builder()
+                .setAlias(ALIAS)
+                .setEncryptedKeyMaterial(KEY_MATERIAL)
+                .setMetadata(metadata)
+                .build();
+    }
 }
diff --git a/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java b/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java
index 7f0eb43..17486d5 100644
--- a/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java
+++ b/core/tests/coretests/src/android/security/keystore/recovery/X509CertificateParsingUtilsTest.java
@@ -21,8 +21,8 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 
-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/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
index e69d1e7..d00d052 100644
--- a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
+++ b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.service.euicc;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -23,10 +24,11 @@
 
 import android.os.Parcel;
 import android.service.carrier.CarrierIdentifier;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.telephony.UiccAccessRule;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
new file mode 100644
index 0000000..4aa1000
--- /dev/null
+++ b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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 static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.metrics.LogMaker;
+import android.os.UserHandle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class StatusBarNotificationTest {
+
+    private final Context mMockContext = mock(Context.class);
+    @Mock
+    private PackageManager mPm;
+
+    private static final String PKG = "com.example.o";
+    private static final int UID = 9583;
+    private static final int ID = 1;
+    private static final String TAG = "tag1";
+    private static final String CHANNEL_ID = "channel";
+    private static final String CHANNEL_ID_LONG =
+            "give_a_developer_a_string_argument_and_who_knows_what_they_will_pass_in_there";
+    private static final String GROUP_ID_1 = "group1";
+    private static final String GROUP_ID_2 = "group2";
+    private static final String GROUP_ID_LONG =
+            "0|com.foo.bar|g:content://com.foo.bar.ui/account%3A-0000000/account/";
+    private static final android.os.UserHandle USER =
+            UserHandle.of(ActivityManager.getCurrentUser());
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mMockContext.getResources()).thenReturn(
+                InstrumentationRegistry.getContext().getResources());
+        when(mMockContext.getPackageManager()).thenReturn(mPm);
+        when(mMockContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
+    }
+
+    @Test
+    public void testLogMaker() {
+        final LogMaker logMaker = getNotification(PKG, GROUP_ID_1, CHANNEL_ID).getLogMaker();
+
+        assertEquals(CHANNEL_ID,
+                (String) logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID));
+        assertEquals(PKG, logMaker.getPackageName());
+        assertEquals(ID, logMaker.getTaggedData(MetricsEvent.NOTIFICATION_ID));
+        assertEquals(TAG, logMaker.getTaggedData(MetricsEvent.NOTIFICATION_TAG));
+        assertEquals(GROUP_ID_1,
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
+    }
+
+    @Test
+    public void testLogMakerNoChannel() {
+        final LogMaker logMaker = getNotification(PKG, GROUP_ID_1, null).getLogMaker();
+
+        assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID));
+    }
+
+    @Test
+    public void testLogMakerLongChannel() {
+        final LogMaker logMaker = getNotification(PKG, null, CHANNEL_ID_LONG).getLogMaker();
+        final String loggedId = (String) logMaker
+                .getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID);
+        assertEquals(StatusBarNotification.MAX_LOG_TAG_LENGTH, loggedId.length());
+        assertEquals(CHANNEL_ID_LONG.substring(0, 10), loggedId.substring(0, 10));
+    }
+
+    @Test
+    public void testLogMakerNoGroup() {
+        final LogMaker logMaker = getNotification(PKG, null, CHANNEL_ID).getLogMaker();
+
+        assertNull(
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
+    }
+
+    @Test
+    public void testLogMakerLongGroup() {
+        final LogMaker logMaker = getNotification(PKG, GROUP_ID_LONG, CHANNEL_ID)
+                .getLogMaker();
+
+        final String loggedId = (String)
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID);
+        assertEquals(StatusBarNotification.MAX_LOG_TAG_LENGTH, loggedId.length());
+        assertEquals(GROUP_ID_LONG.substring(0, 10), loggedId.substring(0, 10));
+    }
+
+    @Test
+    public void testLogMakerOverrideGroup() {
+        StatusBarNotification sbn = getNotification(PKG, GROUP_ID_1, CHANNEL_ID);
+        assertEquals(GROUP_ID_1,
+                sbn.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
+
+        sbn.setOverrideGroupKey(GROUP_ID_2);
+        assertEquals(GROUP_ID_2,
+                sbn.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
+
+        sbn.setOverrideGroupKey(null);
+        assertEquals(GROUP_ID_1,
+                sbn.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
+    }
+
+    private StatusBarNotification getNotification(String pkg, String group, String channelId) {
+        final Notification.Builder builder = new Notification.Builder(mMockContext, channelId)
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+        if (group != null) {
+            builder.setGroup(group);
+        }
+
+        Notification n = builder.build();
+        return new StatusBarNotification(
+                pkg, pkg, ID, TAG, UID, UID, n, USER, null, UID);
+    }
+
+}
diff --git a/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java b/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java
index ab541a1..9c8e868 100644
--- a/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java
+++ b/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java
@@ -16,16 +16,12 @@
 
 package android.service.settings.suggestions;
 
-import android.support.annotation.VisibleForTesting;
-
 import java.util.ArrayList;
 import java.util.List;
 
 public class MockSuggestionService extends SuggestionService {
 
-    @VisibleForTesting
     static boolean sOnSuggestionLaunchedCalled;
-    @VisibleForTesting
     static boolean sOnSuggestionDismissedCalled;
 
     public static void reset() {
diff --git a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java
index dca8c09..64edda5 100644
--- a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java
+++ b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java
@@ -21,10 +21,11 @@
 import android.content.Intent;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.rule.ServiceTestRule;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ServiceTestRule;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java
index b0ec55d..8c47fcb 100644
--- a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java
+++ b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionTest.java
@@ -24,9 +24,10 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.Icon;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/text/AndroidCharacterTest.java b/core/tests/coretests/src/android/text/AndroidCharacterTest.java
index 0c7e730..1c5986a 100644
--- a/core/tests/coretests/src/android/text/AndroidCharacterTest.java
+++ b/core/tests/coretests/src/android/text/AndroidCharacterTest.java
@@ -19,7 +19,8 @@
 import static org.junit.Assert.assertArrayEquals;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 
diff --git a/core/tests/coretests/src/android/text/BidiFormatterTest.java b/core/tests/coretests/src/android/text/BidiFormatterTest.java
index 1b936c7..312fb68 100644
--- a/core/tests/coretests/src/android/text/BidiFormatterTest.java
+++ b/core/tests/coretests/src/android/text/BidiFormatterTest.java
@@ -19,8 +19,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.platform.test.annotations.Presubmit;
-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/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java b/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
index c69f4f5..cca1ad3 100644
--- a/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
+++ b/core/tests/coretests/src/android/text/DynamicLayoutBlocksTest.java
@@ -22,8 +22,9 @@
 import static org.junit.Assert.assertTrue;
 
 import android.platform.test.annotations.Presubmit;
-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/core/tests/coretests/src/android/text/DynamicLayoutTest.java b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
index ea954f6..699243b 100644
--- a/core/tests/coretests/src/android/text/DynamicLayoutTest.java
+++ b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
@@ -27,11 +27,12 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.style.ReplacementSpan;
 import android.util.ArraySet;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/EmojiTest.java b/core/tests/coretests/src/android/text/EmojiTest.java
index 313f1b6..1948994 100644
--- a/core/tests/coretests/src/android/text/EmojiTest.java
+++ b/core/tests/coretests/src/android/text/EmojiTest.java
@@ -21,8 +21,9 @@
 
 import android.icu.lang.UCharacterDirection;
 import android.icu.text.Bidi;
-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/core/tests/coretests/src/android/text/FontFallbackSetup.java b/core/tests/coretests/src/android/text/FontFallbackSetup.java
index 5592aac..cc51ec3 100644
--- a/core/tests/coretests/src/android/text/FontFallbackSetup.java
+++ b/core/tests/coretests/src/android/text/FontFallbackSetup.java
@@ -24,9 +24,10 @@
 import android.graphics.fonts.FontCustomizationParser;
 import android.graphics.fonts.FontFamily;
 import android.graphics.fonts.SystemFonts;
-import android.support.test.InstrumentationRegistry;
 import android.util.ArrayMap;
 
+import androidx.test.InstrumentationRegistry;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
diff --git a/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java b/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java
index 1208d7c..96e7fb9 100644
--- a/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java
+++ b/core/tests/coretests/src/android/text/LayoutBidiCursorPathTest.java
@@ -22,12 +22,13 @@
 import android.graphics.Path;
 import android.graphics.Typeface;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.method.MetaKeyKeyListener;
 import android.view.KeyEvent;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/LayoutTest.java b/core/tests/coretests/src/android/text/LayoutTest.java
index 97937a4..990161a 100644
--- a/core/tests/coretests/src/android/text/LayoutTest.java
+++ b/core/tests/coretests/src/android/text/LayoutTest.java
@@ -31,11 +31,12 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.Alignment;
 import android.text.style.StrikethroughSpan;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
index a0dca2c..57bb434 100644
--- a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
+++ b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
@@ -23,9 +23,10 @@
 
 import android.content.Context;
 import android.graphics.Typeface;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/PackedIntVectorTest.java b/core/tests/coretests/src/android/text/PackedIntVectorTest.java
index d9dc6fc..ba15b92 100644
--- a/core/tests/coretests/src/android/text/PackedIntVectorTest.java
+++ b/core/tests/coretests/src/android/text/PackedIntVectorTest.java
@@ -19,8 +19,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.platform.test.annotations.Presubmit;
-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/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java b/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java
index d0f2d46..91b8c6a 100644
--- a/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java
+++ b/core/tests/coretests/src/android/text/SpannableStringBuilderTest.java
@@ -16,18 +16,18 @@
 
 package android.text;
 
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.style.BulletSpan;
 import android.text.style.QuoteSpan;
 import android.text.style.SubscriptSpan;
 import android.text.style.UnderlineSpan;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java b/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java
index 6c05601..9149f7b 100644
--- a/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java
+++ b/core/tests/coretests/src/android/text/SpannableStringNoCopyTest.java
@@ -21,11 +21,12 @@
 import static org.junit.Assert.assertNotNull;
 
 import android.annotation.NonNull;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.style.QuoteSpan;
 import android.text.style.UnderlineSpan;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/SpannableTest.java b/core/tests/coretests/src/android/text/SpannableTest.java
index f368428..d248a1f 100644
--- a/core/tests/coretests/src/android/text/SpannableTest.java
+++ b/core/tests/coretests/src/android/text/SpannableTest.java
@@ -19,10 +19,11 @@
 import static org.junit.Assert.assertEquals;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.MoreAsserts;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java b/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java
index 380e315..ca43733 100644
--- a/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java
+++ b/core/tests/coretests/src/android/text/SpannedStringNoCopyTest.java
@@ -21,11 +21,12 @@
 import static org.junit.Assert.assertNotNull;
 
 import android.annotation.NonNull;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.style.QuoteSpan;
 import android.text.style.UnderlineSpan;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/SpannedTest.java b/core/tests/coretests/src/android/text/SpannedTest.java
index 5737571..3ab0755 100644
--- a/core/tests/coretests/src/android/text/SpannedTest.java
+++ b/core/tests/coretests/src/android/text/SpannedTest.java
@@ -21,13 +21,14 @@
 import android.graphics.Typeface;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.style.CharacterStyle;
 import android.text.style.StyleSpan;
 import android.text.style.TextAppearanceSpan;
 import android.text.style.TypefaceSpan;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
index bf0d427..32370b3e 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
@@ -19,10 +19,11 @@
 import static org.junit.Assert.assertEquals;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
index 5cf5426..4221ac2 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutDirectionsTest.java
@@ -19,11 +19,12 @@
 import static org.junit.Assert.fail;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.Directions;
 import android.text.StaticLayoutTest.LayoutBuilder;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index 2521712..b1c896e 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -25,13 +25,14 @@
 import android.graphics.Paint.FontMetricsInt;
 import android.os.LocaleList;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.Alignment;
 import android.text.method.EditorState;
 import android.text.style.LocaleSpan;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java b/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
index f6888e3..0d42326 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTextMeasuringTest.java
@@ -19,10 +19,11 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.Alignment;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/TextLayoutTest.java b/core/tests/coretests/src/android/text/TextLayoutTest.java
index 24020ce..15fbc9e 100644
--- a/core/tests/coretests/src/android/text/TextLayoutTest.java
+++ b/core/tests/coretests/src/android/text/TextLayoutTest.java
@@ -17,8 +17,9 @@
 package android.text;
 
 import android.platform.test.annotations.Presubmit;
-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.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/text/TextLineTest.java b/core/tests/coretests/src/android/text/TextLineTest.java
index 61f976a..90ce305 100644
--- a/core/tests/coretests/src/android/text/TextLineTest.java
+++ b/core/tests/coretests/src/android/text/TextLineTest.java
@@ -25,14 +25,15 @@
 import android.graphics.Paint;
 import android.graphics.Typeface;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.filters.Suppress;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.Layout.TabStops;
 import android.text.style.ReplacementSpan;
 import android.text.style.TabStopSpan;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -254,6 +255,18 @@
     }
 
     @Test
+    public void testMeasure_wordSpacing() {
+        final TextPaint paint = new TextPaint();
+        paint.setTypeface(TYPEFACE);
+        paint.setTextSize(10.0f);  // make 1em = 10px
+        paint.setWordSpacing(10.0f);
+
+        TextLine tl = getTextLine("I I", paint);
+        assertMeasurements(tl, 3, false,
+                new float[]{0.0f, 10.0f, 120.0f, 130.0f});
+    }
+
+    @Test
     public void testHandleRun_ellipsizedReplacementSpan_isSkipped() {
         final Spannable text = new SpannableStringBuilder("This is a... text");
 
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index 72290bf..be6ef19 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -26,15 +26,16 @@
 
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.MoreAsserts;
 import android.text.style.StyleSpan;
 import android.text.util.Rfc822Token;
 import android.text.util.Rfc822Tokenizer;
 import android.view.View;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.google.android.collect.Lists;
 
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/text/VariationParserTest.java b/core/tests/coretests/src/android/text/VariationParserTest.java
index fbd2412..0afe811 100644
--- a/core/tests/coretests/src/android/text/VariationParserTest.java
+++ b/core/tests/coretests/src/android/text/VariationParserTest.java
@@ -21,8 +21,9 @@
 
 import android.graphics.fonts.FontVariationAxis;
 import android.platform.test.annotations.Presubmit;
-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/core/tests/coretests/src/android/text/format/DateFormatTest.java b/core/tests/coretests/src/android/text/format/DateFormatTest.java
index 9000ed0..5a0a84d 100644
--- a/core/tests/coretests/src/android/text/format/DateFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateFormatTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.assertTrue;
 
 import android.platform.test.annotations.Presubmit;
-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/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
index 872b71a..381c051 100644
--- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java
+++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
@@ -22,8 +22,9 @@
 import android.content.res.Resources;
 import android.os.LocaleList;
 import android.platform.test.annotations.Presubmit;
-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.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index 82e4bff..068d047 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -25,11 +25,12 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.format.Formatter.BytesResult;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/text/format/TimeTest.java b/core/tests/coretests/src/android/text/format/TimeTest.java
index d563f2e..ac00411 100644
--- a/core/tests/coretests/src/android/text/format/TimeTest.java
+++ b/core/tests/coretests/src/android/text/format/TimeTest.java
@@ -21,12 +21,13 @@
 import static org.junit.Assert.fail;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.filters.Suppress;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 import android.util.TimeFormatException;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/method/BackspaceTest.java b/core/tests/coretests/src/android/text/method/BackspaceTest.java
index df4609f..ddae652 100644
--- a/core/tests/coretests/src/android/text/method/BackspaceTest.java
+++ b/core/tests/coretests/src/android/text/method/BackspaceTest.java
@@ -17,15 +17,16 @@
 package android.text.method;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.util.KeyUtils;
 import android.view.KeyEvent;
 import android.widget.EditText;
 import android.widget.TextView.BufferType;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/method/EditorState.java b/core/tests/coretests/src/android/text/method/EditorState.java
index 12bb8c8..4eff7a4 100644
--- a/core/tests/coretests/src/android/text/method/EditorState.java
+++ b/core/tests/coretests/src/android/text/method/EditorState.java
@@ -21,8 +21,6 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import android.graphics.Canvas;
-import android.graphics.Paint;
 import android.text.Editable;
 import android.text.Spannable;
 import android.text.SpannableString;
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
index 45a5010..45b63e0 100644
--- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -17,15 +17,16 @@
 package android.text.method;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
 import android.util.KeyUtils;
 import android.view.KeyEvent;
 import android.widget.EditText;
 import android.widget.TextView.BufferType;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/text/method/WordIteratorTest.java b/core/tests/coretests/src/android/text/method/WordIteratorTest.java
index 6845863..cc345f5 100644
--- a/core/tests/coretests/src/android/text/method/WordIteratorTest.java
+++ b/core/tests/coretests/src/android/text/method/WordIteratorTest.java
@@ -22,8 +22,9 @@
 import static org.junit.Assert.fail;
 
 import android.platform.test.annotations.Presubmit;
-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/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java b/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java
index 3d7e5ba..a0d2f85 100644
--- a/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java
+++ b/core/tests/coretests/src/android/text/style/UnderlineSpanTest.java
@@ -16,17 +16,17 @@
 
 package android.text.style;
 
-
 import static org.junit.Assert.assertEquals;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.StaticLayout;
 import android.text.TextPaint;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/text/util/LinkifyTest.java b/core/tests/coretests/src/android/text/util/LinkifyTest.java
index be3a0be..107ecd7 100644
--- a/core/tests/coretests/src/android/text/util/LinkifyTest.java
+++ b/core/tests/coretests/src/android/text/util/LinkifyTest.java
@@ -23,9 +23,6 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.LocaleList;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.method.LinkMovementMethod;
@@ -33,6 +30,10 @@
 import android.util.Patterns;
 import android.widget.TextView;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/transition/AutoTransitionTest.java b/core/tests/coretests/src/android/transition/AutoTransitionTest.java
index 834fb7a..deae967 100644
--- a/core/tests/coretests/src/android/transition/AutoTransitionTest.java
+++ b/core/tests/coretests/src/android/transition/AutoTransitionTest.java
@@ -16,16 +16,16 @@
 
 package android.transition;
 
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @RunWith(AndroidJUnit4.class)
 public class AutoTransitionTest {
     @Test
diff --git a/core/tests/coretests/src/android/transition/FadeTransitionTest.java b/core/tests/coretests/src/android/transition/FadeTransitionTest.java
index 22365ba..2077d94 100644
--- a/core/tests/coretests/src/android/transition/FadeTransitionTest.java
+++ b/core/tests/coretests/src/android/transition/FadeTransitionTest.java
@@ -22,13 +22,14 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.transition.Transition.TransitionListener;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.util.concurrent.CountDownLatch;
diff --git a/core/tests/coretests/src/android/transition/SlideTransitionTest.java b/core/tests/coretests/src/android/transition/SlideTransitionTest.java
index 8b9ec74..046e49d 100644
--- a/core/tests/coretests/src/android/transition/SlideTransitionTest.java
+++ b/core/tests/coretests/src/android/transition/SlideTransitionTest.java
@@ -19,18 +19,18 @@
 import android.animation.AnimatorSetActivity;
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-
 public class SlideTransitionTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
 
     Activity mActivity;
diff --git a/core/tests/coretests/src/android/transition/TransitionTest.java b/core/tests/coretests/src/android/transition/TransitionTest.java
index 7e629f9..f59c406 100644
--- a/core/tests/coretests/src/android/transition/TransitionTest.java
+++ b/core/tests/coretests/src/android/transition/TransitionTest.java
@@ -19,7 +19,6 @@
 import android.animation.AnimatorSetActivity;
 import android.app.Activity;
 import android.graphics.Rect;
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase2;
 import android.transition.Transition.EpicenterCallback;
 import android.util.ArrayMap;
@@ -27,6 +26,8 @@
 import android.view.animation.AccelerateInterpolator;
 import android.widget.TextView;
 
+import androidx.test.filters.LargeTest;
+
 import com.android.frameworks.coretests.R;
 
 import java.lang.reflect.Field;
diff --git a/core/tests/coretests/src/android/util/ArrayMapTest.java b/core/tests/coretests/src/android/util/ArrayMapTest.java
index f0cc7f7..b212cf6 100644
--- a/core/tests/coretests/src/android/util/ArrayMapTest.java
+++ b/core/tests/coretests/src/android/util/ArrayMapTest.java
@@ -14,10 +14,10 @@
 
 package android.util;
 
-import android.support.test.filters.LargeTest;
-import android.util.ArrayMap;
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
+
 import org.junit.Test;
 
 import java.util.ConcurrentModificationException;
diff --git a/core/tests/coretests/src/android/util/Base64Test.java b/core/tests/coretests/src/android/util/Base64Test.java
index af608c3..15c51af 100644
--- a/core/tests/coretests/src/android/util/Base64Test.java
+++ b/core/tests/coretests/src/android/util/Base64Test.java
@@ -16,7 +16,7 @@
 
 package android.util;
 
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/util/DataUnitTest.java b/core/tests/coretests/src/android/util/DataUnitTest.java
index 4eae8b4..ec296b7 100644
--- a/core/tests/coretests/src/android/util/DataUnitTest.java
+++ b/core/tests/coretests/src/android/util/DataUnitTest.java
@@ -16,7 +16,7 @@
 
 package android.util;
 
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java b/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
index 4c5ad76..572e9b0 100644
--- a/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
+++ b/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
@@ -16,10 +16,11 @@
 
 package android.util;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 import java.util.Calendar;
-import android.test.suitebuilder.annotation.SmallTest;
 
 /**
  * Unit tests for {@link DayOfMonthCursor}.
diff --git a/core/tests/coretests/src/android/util/InternalSelectionView.java b/core/tests/coretests/src/android/util/InternalSelectionView.java
index a0fb0f1..4a1baef 100644
--- a/core/tests/coretests/src/android/util/InternalSelectionView.java
+++ b/core/tests/coretests/src/android/util/InternalSelectionView.java
@@ -16,19 +16,16 @@
 
 package android.util;
 
-import com.android.frameworks.coretests.R;
-
-import android.view.View;
-import android.view.KeyEvent;
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.graphics.Paint;
 import android.graphics.Canvas;
-import android.graphics.Rect;
 import android.graphics.Color;
-import android.util.AttributeSet;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.view.KeyEvent;
+import android.view.View;
 
-
+import com.android.frameworks.coretests.R;
 
 /**
  * A view that has a known number of selectable rows, and maintains a notion of which
diff --git a/core/tests/coretests/src/android/util/KeyUtils.java b/core/tests/coretests/src/android/util/KeyUtils.java
index 593f727..612643e 100644
--- a/core/tests/coretests/src/android/util/KeyUtils.java
+++ b/core/tests/coretests/src/android/util/KeyUtils.java
@@ -17,16 +17,10 @@
 package android.util;
 
 import android.app.Instrumentation;
-import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.InstrumentationTestCase;
-import android.view.Gravity;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.ViewGroup;
 
 /**
  * Reusable methods for generating key events.
diff --git a/core/tests/coretests/src/android/util/KeyValueListParserTest.java b/core/tests/coretests/src/android/util/KeyValueListParserTest.java
index 038f0b7..f65c4c7 100644
--- a/core/tests/coretests/src/android/util/KeyValueListParserTest.java
+++ b/core/tests/coretests/src/android/util/KeyValueListParserTest.java
@@ -19,8 +19,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.platform.test.annotations.Presubmit;
-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.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/util/ListUtil.java b/core/tests/coretests/src/android/util/ListUtil.java
index 2a7cb96..3748cf8 100644
--- a/core/tests/coretests/src/android/util/ListUtil.java
+++ b/core/tests/coretests/src/android/util/ListUtil.java
@@ -20,13 +20,11 @@
 import android.view.KeyEvent;
 import android.widget.ListView;
 
-
 /**
  * Various useful stuff for instrumentation testing listview.
  */
 public class ListUtil {
 
-
     private final ListView mListView;
     private final Instrumentation mInstrumentation;
 
diff --git a/core/tests/coretests/src/android/util/LocalLogTest.java b/core/tests/coretests/src/android/util/LocalLogTest.java
index 5144c85..6cdcb5e 100644
--- a/core/tests/coretests/src/android/util/LocalLogTest.java
+++ b/core/tests/coretests/src/android/util/LocalLogTest.java
@@ -16,7 +16,7 @@
 
 package android.util;
 
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/util/LogNullabilityTest.java b/core/tests/coretests/src/android/util/LogNullabilityTest.java
index 3f4776d..370885d 100644
--- a/core/tests/coretests/src/android/util/LogNullabilityTest.java
+++ b/core/tests/coretests/src/android/util/LogNullabilityTest.java
@@ -19,8 +19,8 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/util/LogTest.java b/core/tests/coretests/src/android/util/LogTest.java
index 30c81b0..d783c12 100644
--- a/core/tests/coretests/src/android/util/LogTest.java
+++ b/core/tests/coretests/src/android/util/LogTest.java
@@ -16,13 +16,12 @@
 
 package android.util;
 
-import junit.framework.Assert;
-import junit.framework.TestCase;
-
 import android.os.SystemProperties;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.Suppress;
-import android.util.Log;
+
+import androidx.test.filters.Suppress;
+
+import junit.framework.TestCase;
 
 //This is an empty TestCase.
 @Suppress
diff --git a/core/tests/coretests/src/android/util/LongArrayQueueTest.java b/core/tests/coretests/src/android/util/LongArrayQueueTest.java
new file mode 100644
index 0000000..77e8d60
--- /dev/null
+++ b/core/tests/coretests/src/android/util/LongArrayQueueTest.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.fail;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.NoSuchElementException;
+
+/**
+ * Internal tests for {@link LongArrayQueue}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LongArrayQueueTest {
+
+    private LongArrayQueue mQueueUnderTest;
+
+    @Before
+    public void setUp() {
+        mQueueUnderTest = new LongArrayQueue();
+    }
+
+    @Test
+    public void removeFirstOnEmptyQueue() {
+        try {
+            mQueueUnderTest.removeFirst();
+            fail("removeFirst() succeeded on an empty queue!");
+        } catch (NoSuchElementException e) {
+        }
+        mQueueUnderTest.addLast(5);
+        mQueueUnderTest.removeFirst();
+        try {
+            mQueueUnderTest.removeFirst();
+            fail("removeFirst() succeeded on an empty queue!");
+        } catch (NoSuchElementException e) {
+        }
+    }
+
+    @Test
+    public void addLastRemoveFirstFifo() {
+        mQueueUnderTest.addLast(1);
+        assertEquals(1, mQueueUnderTest.removeFirst());
+        int n = 890;
+        int removes = 0;
+        for (int i = 0; i < n; i++) {
+            mQueueUnderTest.addLast(i);
+            if ((i % 3) == 0) {
+                assertEquals(removes++, mQueueUnderTest.removeFirst());
+            }
+        }
+        while (removes < n) {
+            assertEquals(removes++, mQueueUnderTest.removeFirst());
+        }
+    }
+
+    @Test
+    public void peekFirstOnEmptyQueue() {
+        try {
+            mQueueUnderTest.peekFirst();
+            fail("peekFirst() succeeded on an empty queue!");
+        } catch (NoSuchElementException e) {
+        }
+        mQueueUnderTest.addLast(5);
+        mQueueUnderTest.removeFirst();
+        try {
+            mQueueUnderTest.peekFirst();
+            fail("peekFirst() succeeded on an empty queue!");
+        } catch (NoSuchElementException e) {
+        }
+    }
+
+    @Test
+    public void peekFirstChanges() {
+        mQueueUnderTest.addLast(1);
+        assertEquals(1, mQueueUnderTest.peekFirst());
+        mQueueUnderTest.addLast(2);
+        mQueueUnderTest.addLast(3);
+        mQueueUnderTest.addLast(4);
+        // addLast() has no effect on peekFirst().
+        assertEquals(1, mQueueUnderTest.peekFirst());
+        mQueueUnderTest.removeFirst();
+        mQueueUnderTest.removeFirst();
+        assertEquals(3, mQueueUnderTest.peekFirst());
+    }
+
+    @Test
+    public void peekLastOnEmptyQueue() {
+        try {
+            mQueueUnderTest.peekLast();
+            fail("peekLast() succeeded on an empty queue!");
+        } catch (NoSuchElementException e) {
+        }
+        mQueueUnderTest.addLast(5);
+        mQueueUnderTest.removeFirst();
+        try {
+            mQueueUnderTest.peekLast();
+            fail("peekLast() succeeded on an empty queue!");
+        } catch (NoSuchElementException e) {
+        }
+    }
+
+    @Test
+    public void peekLastChanges() {
+        mQueueUnderTest.addLast(1);
+        assertEquals(1, mQueueUnderTest.peekLast());
+        mQueueUnderTest.addLast(2);
+        mQueueUnderTest.addLast(3);
+        mQueueUnderTest.addLast(4);
+        assertEquals(4, mQueueUnderTest.peekLast());
+        mQueueUnderTest.removeFirst();
+        mQueueUnderTest.removeFirst();
+        // removeFirst() has no effect on peekLast().
+        assertEquals(4, mQueueUnderTest.peekLast());
+    }
+
+    @Test
+    public void peekFirstVsPeekLast() {
+        mQueueUnderTest.addLast(2);
+        assertEquals(mQueueUnderTest.peekFirst(), mQueueUnderTest.peekLast());
+        mQueueUnderTest.addLast(3);
+        assertNotEquals(mQueueUnderTest.peekFirst(), mQueueUnderTest.peekLast());
+        mQueueUnderTest.removeFirst();
+        assertEquals(mQueueUnderTest.peekFirst(), mQueueUnderTest.peekLast());
+    }
+
+    @Test
+    public void peekFirstVsRemoveFirst() {
+        int n = 25;
+        for (int i = 0; i < n; i++) {
+            mQueueUnderTest.addLast(i + 1);
+        }
+        for (int i = 0; i < n; i++) {
+            long peekVal = mQueueUnderTest.peekFirst();
+            assertEquals(peekVal, mQueueUnderTest.removeFirst());
+        }
+    }
+
+    @Test
+    public void sizeOfEmptyQueue() {
+        assertEquals(0, mQueueUnderTest.size());
+        mQueueUnderTest = new LongArrayQueue(1000);
+        // capacity doesn't affect size.
+        assertEquals(0, mQueueUnderTest.size());
+    }
+
+    @Test
+    public void sizeAfterOperations() {
+        final int added = 1200;
+        for (int i = 0; i < added; i++) {
+            mQueueUnderTest.addLast(i);
+        }
+        // each add increments the size by 1.
+        assertEquals(added, mQueueUnderTest.size());
+        mQueueUnderTest.peekLast();
+        mQueueUnderTest.peekFirst();
+        // peeks don't change the size.
+        assertEquals(added, mQueueUnderTest.size());
+        final int removed = 345;
+        for (int i = 0; i < removed; i++) {
+            mQueueUnderTest.removeFirst();
+        }
+        // each remove decrements the size by 1.
+        assertEquals(added - removed, mQueueUnderTest.size());
+        mQueueUnderTest.clear();
+        // clear reduces the size to 0.
+        assertEquals(0, mQueueUnderTest.size());
+    }
+
+    @Test
+    public void getInvalidPositions() {
+        try {
+            mQueueUnderTest.get(0);
+            fail("get(0) succeeded on an empty queue!");
+        } catch (IndexOutOfBoundsException e) {
+        }
+        int n = 520;
+        for (int i = 0; i < 2 * n; i++) {
+            mQueueUnderTest.addLast(i + 1);
+        }
+        for (int i = 0; i < n; i++) {
+            mQueueUnderTest.removeFirst();
+        }
+        try {
+            mQueueUnderTest.get(-3);
+            fail("get(-3) succeeded");
+        } catch (IndexOutOfBoundsException e) {
+        }
+        assertEquals(n, mQueueUnderTest.size());
+        try {
+            mQueueUnderTest.get(n);
+            fail("get(" + n + ") succeeded on a queue with " + n + " elements");
+        } catch (IndexOutOfBoundsException e) {
+        }
+        try {
+            mQueueUnderTest.get(n + 3);
+            fail("get(" + (n + 3) + ") succeeded on a queue with " + n + " elements");
+        } catch (IndexOutOfBoundsException e) {
+        }
+    }
+
+    @Test
+    public void getValidPositions() {
+        int added = 423;
+        int removed = 212;
+        for (int i = 0; i < added; i++) {
+            mQueueUnderTest.addLast(i);
+        }
+        for (int i = 0; i < removed; i++) {
+            mQueueUnderTest.removeFirst();
+        }
+        for (int i = 0; i < (added - removed); i++) {
+            assertEquals(removed + i, mQueueUnderTest.get(i));
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java b/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java
index 3f03db9..a1d48e6 100644
--- a/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java
+++ b/core/tests/coretests/src/android/util/LongSparseLongArrayTest.java
@@ -16,7 +16,7 @@
 
 package android.util;
 
-import android.support.test.filters.LargeTest;
+import androidx.test.filters.LargeTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/util/LruCacheTest.java b/core/tests/coretests/src/android/util/LruCacheTest.java
index 5a97158..1928bfd 100644
--- a/core/tests/coretests/src/android/util/LruCacheTest.java
+++ b/core/tests/coretests/src/android/util/LruCacheTest.java
@@ -16,12 +16,13 @@
 
 package android.util;
 
+import junit.framework.TestCase;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import junit.framework.TestCase;
 
 public final class LruCacheTest extends TestCase {
     private int expectedCreateCount;
diff --git a/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java b/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
index 55da665..30d5f77 100644
--- a/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
+++ b/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
@@ -16,12 +16,12 @@
 
 package android.util;
 
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.util.Calendar;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
+import java.util.Calendar;
+
 /**
  * Unit tests for {@link MonthDisplayHelper}.
  */
diff --git a/core/tests/coretests/src/android/util/OrientationUtil.java b/core/tests/coretests/src/android/util/OrientationUtil.java
index ecdca5d..0361194 100644
--- a/core/tests/coretests/src/android/util/OrientationUtil.java
+++ b/core/tests/coretests/src/android/util/OrientationUtil.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.pm.ActivityInfo;
-
 import android.test.ActivityInstrumentationTestCase2;
 
 import com.android.internal.util.Preconditions;
diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java
index 360b875..6cea2f3 100644
--- a/core/tests/coretests/src/android/util/PatternsTest.java
+++ b/core/tests/coretests/src/android/util/PatternsTest.java
@@ -13,15 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.util;
 
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
 
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import junit.framework.TestCase;
-
 public class PatternsTest extends TestCase {
 
     // Tests for Patterns.TOP_LEVEL_DOMAIN
diff --git a/core/tests/coretests/src/android/util/RecurrenceRuleTest.java b/core/tests/coretests/src/android/util/RecurrenceRuleTest.java
index 39d492d..caa1208 100644
--- a/core/tests/coretests/src/android/util/RecurrenceRuleTest.java
+++ b/core/tests/coretests/src/android/util/RecurrenceRuleTest.java
@@ -16,7 +16,7 @@
 
 package android.util;
 
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/util/SparseLongArrayTest.java b/core/tests/coretests/src/android/util/SparseLongArrayTest.java
index 5a5e893..df2d752 100644
--- a/core/tests/coretests/src/android/util/SparseLongArrayTest.java
+++ b/core/tests/coretests/src/android/util/SparseLongArrayTest.java
@@ -19,9 +19,10 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.support.annotation.NonNull;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import android.annotation.NonNull;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/util/StateSetTest.java b/core/tests/coretests/src/android/util/StateSetTest.java
index e481ce0..b5d6270 100644
--- a/core/tests/coretests/src/android/util/StateSetTest.java
+++ b/core/tests/coretests/src/android/util/StateSetTest.java
@@ -16,8 +16,9 @@
 
 package android.util;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 
 /**
  * Tests for {@link StateSet}
diff --git a/core/tests/coretests/src/android/util/TimestampedValueTest.java b/core/tests/coretests/src/android/util/TimestampedValueTest.java
index 03b4abd..6e3ab79 100644
--- a/core/tests/coretests/src/android/util/TimestampedValueTest.java
+++ b/core/tests/coretests/src/android/util/TimestampedValueTest.java
@@ -21,7 +21,8 @@
 import static org.junit.Assert.fail;
 
 import android.os.Parcel;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/util/TimingsTraceLogTest.java b/core/tests/coretests/src/android/util/TimingsTraceLogTest.java
index 7bb4ab8..77d0552 100644
--- a/core/tests/coretests/src/android/util/TimingsTraceLogTest.java
+++ b/core/tests/coretests/src/android/util/TimingsTraceLogTest.java
@@ -19,8 +19,9 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Trace;
-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;
@@ -28,7 +29,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-
 /**
  * Tests for {@link TimingsTraceLog}.
  * <p>Usage: bit FrameworksCoreTests:android.util.TimingsTraceLogTest
diff --git a/core/tests/coretests/src/android/util/TokenBucketTest.java b/core/tests/coretests/src/android/util/TokenBucketTest.java
deleted file mode 100644
index f7ac20c..0000000
--- a/core/tests/coretests/src/android/util/TokenBucketTest.java
+++ /dev/null
@@ -1,179 +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.internal.util;
-
-import android.os.SystemClock;
-import android.text.format.DateUtils;
-import junit.framework.TestCase;
-
-public class TokenBucketTest extends TestCase {
-
-    static final int FILL_DELTA_VERY_SHORT  = 1;
-    static final int FILL_DELTA_VERY_LONG   = Integer.MAX_VALUE;
-
-    public void testArgumentValidation() {
-        assertThrow(() -> new TokenBucket(0, 1, 1));
-        assertThrow(() -> new TokenBucket(1, 0, 1));
-        assertThrow(() -> new TokenBucket(1, 1, 0));
-        assertThrow(() -> new TokenBucket(0, 1));
-        assertThrow(() -> new TokenBucket(1, 0));
-        assertThrow(() -> new TokenBucket(-1, 1, 1));
-        assertThrow(() -> new TokenBucket(1, -1, 1));
-        assertThrow(() -> new TokenBucket(1, 1, -1));
-        assertThrow(() -> new TokenBucket(-1, 1));
-        assertThrow(() -> new TokenBucket(1, -1));
-
-        new TokenBucket(1000, 100, 0);
-        new TokenBucket(1000, 100, 10);
-        new TokenBucket(5000, 50);
-        new TokenBucket(5000, 1);
-    }
-
-    public void testInitialCapacity() {
-        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 1), 1);
-        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10), 10);
-        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 1000), 1000);
-
-        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 0), 0);
-        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 3), 3);
-        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 10), 10);
-
-        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 100), 10);
-
-        drain(new TokenBucket((int)DateUtils.MINUTE_IN_MILLIS, 50), 50);
-        drain(new TokenBucket((int)DateUtils.HOUR_IN_MILLIS, 10), 10);
-        drain(new TokenBucket((int)DateUtils.DAY_IN_MILLIS, 200), 200);
-    }
-
-    public void testReset() {
-        TokenBucket tb = new TokenBucket(FILL_DELTA_VERY_LONG, 100, 10);
-        drain(tb, 10);
-
-        tb.reset(50);
-        drain(tb, 50);
-
-        tb.reset(50);
-        getOneByOne(tb, 10);
-        assertTrue(tb.has());
-
-        tb.reset(30);
-        drain(tb, 30);
-    }
-
-    public void testFill() throws Exception {
-        int delta = 50;
-        TokenBucket tb = new TokenBucket(delta, 10, 0);
-
-        assertEmpty(tb);
-
-        Thread.sleep(3 * delta / 2);
-
-        assertTrue(tb.has());
-    }
-
-    public void testRefill() throws Exception {
-        TokenBucket tb = new TokenBucket(FILL_DELTA_VERY_SHORT, 10, 10);
-
-        assertEquals(5, tb.get(5));
-        assertEquals(5, tb.get(5));
-
-        while (tb.available() < 10) {
-            Thread.sleep(2);
-        }
-
-        assertEquals(10, tb.get(10));
-
-        while (tb.available() < 10) {
-            Thread.sleep(2);
-        }
-
-        assertEquals(10, tb.get(100));
-    }
-
-    public void testAverage() throws Exception {
-        final int delta = 3;
-        final int want = 60;
-
-        long start = SystemClock.elapsedRealtime();
-        TokenBucket tb = new TokenBucket(delta, 20, 0);
-
-        for (int i = 0; i < want; i++) {
-            while (!tb.has()) {
-                Thread.sleep(5 * delta);
-            }
-            tb.get();
-        }
-
-        assertDuration(want * delta, SystemClock.elapsedRealtime() - start);
-    }
-
-    public void testBurst() throws Exception {
-        final int delta = 2;
-        final int capacity = 20;
-        final int want = 100;
-
-        long start = SystemClock.elapsedRealtime();
-        TokenBucket tb = new TokenBucket(delta, capacity, 0);
-
-        int total = 0;
-        while (total < want) {
-            while (!tb.has()) {
-                Thread.sleep(capacity * delta - 2);
-            }
-            total += tb.get(tb.available());
-        }
-
-        assertDuration(total * delta, SystemClock.elapsedRealtime() - start);
-    }
-
-    static void getOneByOne(TokenBucket tb, int n) {
-        while (n > 0) {
-            assertTrue(tb.has());
-            assertTrue(tb.available() >= n);
-            assertTrue(tb.get());
-            assertTrue(tb.available() >= n - 1);
-            n--;
-        }
-    }
-
-    void assertEmpty(TokenBucket tb) {
-        assertFalse(tb.has());
-        assertEquals(0, tb.available());
-        assertFalse(tb.get());
-    }
-
-    void drain(TokenBucket tb, int n) {
-        getOneByOne(tb, n);
-        assertEmpty(tb);
-    }
-
-    void assertDuration(long expected, long elapsed) {
-        String msg = String.format(
-            "expected elapsed time at least %d ms, but was %d ms", expected, elapsed);
-        elapsed += 1; // one millisecond extra guard
-        assertTrue(msg, elapsed >= expected);
-    }
-
-    void assertThrow(Fn fn)     {
-      try {
-          fn.call();
-          fail("expected n exception to be thrown.");
-      } catch (Throwable t) {}
-    }
-
-    interface Fn { void call(); }
-}
diff --git a/core/tests/coretests/src/android/util/TouchModeFlexibleAsserts.java b/core/tests/coretests/src/android/util/TouchModeFlexibleAsserts.java
index ca12a15..fc08235 100644
--- a/core/tests/coretests/src/android/util/TouchModeFlexibleAsserts.java
+++ b/core/tests/coretests/src/android/util/TouchModeFlexibleAsserts.java
@@ -16,12 +16,12 @@
 
 package android.util;
 
-import junit.framework.Assert;
-
 import android.test.InstrumentationTestCase;
 import android.test.TouchUtils;
 import android.view.View;
 
+import junit.framework.Assert;
+
 /**
  * When entering touch mode via touch, the tests can be flaky.  These asserts
  * are more flexible (allowing up to MAX_ATTEMPTS touches to enter touch mode via touch or
diff --git a/core/tests/coretests/src/android/view/BigCache.java b/core/tests/coretests/src/android/view/BigCache.java
index 2182176..6a1bcaa 100644
--- a/core/tests/coretests/src/android/view/BigCache.java
+++ b/core/tests/coretests/src/android/view/BigCache.java
@@ -16,16 +16,12 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
 import android.app.Activity;
+import android.os.Bundle;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
-import android.view.ViewGroup;
-import android.view.View;
-import android.view.Display;
-import android.view.ViewConfiguration;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * This activity contains two Views, one as big as the screen, one much larger. The large one
diff --git a/core/tests/coretests/src/android/view/BigCacheTest.java b/core/tests/coretests/src/android/view/BigCacheTest.java
index 8c2c865..ed4b996 100644
--- a/core/tests/coretests/src/android/view/BigCacheTest.java
+++ b/core/tests/coretests/src/android/view/BigCacheTest.java
@@ -16,14 +16,12 @@
 
 package android.view;
 
-import android.view.BigCache;
-import com.android.frameworks.coretests.R;
-
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
-import android.view.ViewConfiguration;
 import android.graphics.Bitmap;
+import android.test.ActivityInstrumentationTestCase;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Builds the drawing cache of two Views, one smaller than the maximum cache size,
diff --git a/core/tests/coretests/src/android/view/BitmapDrawable.java b/core/tests/coretests/src/android/view/BitmapDrawable.java
index f7bad84..42c176f 100644
--- a/core/tests/coretests/src/android/view/BitmapDrawable.java
+++ b/core/tests/coretests/src/android/view/BitmapDrawable.java
@@ -16,19 +16,10 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AbsoluteLayout;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
 
 public class BitmapDrawable extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/view/CreateViewTest.java b/core/tests/coretests/src/android/view/CreateViewTest.java
index 16656f6..520f83f 100644
--- a/core/tests/coretests/src/android/view/CreateViewTest.java
+++ b/core/tests/coretests/src/android/view/CreateViewTest.java
@@ -16,16 +16,17 @@
 
 package android.view;
 
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
 import android.content.Context;
 import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.View;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.test.filters.SmallTest;
+
 public class CreateViewTest extends AndroidTestCase implements PerformanceTestCase {
 
     public boolean isPerformanceOnly() {
diff --git a/core/tests/coretests/src/android/view/Disabled.java b/core/tests/coretests/src/android/view/Disabled.java
index d3c7470..ce90039 100644
--- a/core/tests/coretests/src/android/view/Disabled.java
+++ b/core/tests/coretests/src/android/view/Disabled.java
@@ -16,13 +16,12 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
-import android.widget.Button;
-import android.view.View;
-import android.view.View.OnClickListener;
 import android.app.Activity;
+import android.os.Bundle;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise View's disabled state.
diff --git a/core/tests/coretests/src/android/view/DisabledLongpressTest.java b/core/tests/coretests/src/android/view/DisabledLongpressTest.java
index faa0865..a9fec01 100644
--- a/core/tests/coretests/src/android/view/DisabledLongpressTest.java
+++ b/core/tests/coretests/src/android/view/DisabledLongpressTest.java
@@ -18,11 +18,12 @@
 
 import android.test.ActivityInstrumentationTestCase;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.KeyUtils;
 import android.view.View.OnLongClickListener;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/view/DisabledTest.java b/core/tests/coretests/src/android/view/DisabledTest.java
index 291a11c..8922e5f 100644
--- a/core/tests/coretests/src/android/view/DisabledTest.java
+++ b/core/tests/coretests/src/android/view/DisabledTest.java
@@ -18,12 +18,11 @@
 
 import android.test.ActivityInstrumentationTestCase;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.KeyEvent;
-import android.view.View;
 import android.widget.Button;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index 8e4f2cd..dd50af877 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -33,17 +33,17 @@
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.DisplayCutout.ParcelableWrapper;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.util.Arrays;
 import java.util.Collections;
 
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 @Presubmit
diff --git a/core/tests/coretests/src/android/view/DrawableBgMinSize.java b/core/tests/coretests/src/android/view/DrawableBgMinSize.java
index 58bfb8a..ba9ba00 100644
--- a/core/tests/coretests/src/android/view/DrawableBgMinSize.java
+++ b/core/tests/coretests/src/android/view/DrawableBgMinSize.java
@@ -16,12 +16,9 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.AbsoluteLayout;
 import android.widget.Button;
@@ -30,6 +27,8 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Views should obey their background {@link Drawable}'s minimum size
  * requirements ({@link Drawable#getMinimumHeight()} and
diff --git a/core/tests/coretests/src/android/view/DrawableBgMinSizeTest.java b/core/tests/coretests/src/android/view/DrawableBgMinSizeTest.java
index e705c87..1735e8c 100644
--- a/core/tests/coretests/src/android/view/DrawableBgMinSizeTest.java
+++ b/core/tests/coretests/src/android/view/DrawableBgMinSizeTest.java
@@ -16,14 +16,9 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-import android.view.DrawableBgMinSize;
-import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.MediumTest;
-
 import android.graphics.drawable.Drawable;
 import android.test.ActivityInstrumentationTestCase;
-import android.view.View;
+import android.test.TouchUtils;
 import android.widget.AbsoluteLayout;
 import android.widget.Button;
 import android.widget.FrameLayout;
@@ -31,6 +26,10 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link DrawableBgMinSize} exercises Views to obey their background drawable's
  * minimum sizes.
diff --git a/core/tests/coretests/src/android/view/FocusFinderTest.java b/core/tests/coretests/src/android/view/FocusFinderTest.java
index 2732a04..b35c64a 100644
--- a/core/tests/coretests/src/android/view/FocusFinderTest.java
+++ b/core/tests/coretests/src/android/view/FocusFinderTest.java
@@ -18,7 +18,8 @@
 
 import android.graphics.Rect;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 public class FocusFinderTest extends AndroidTestCase {
 
diff --git a/core/tests/coretests/src/android/view/GlobalFocusChange.java b/core/tests/coretests/src/android/view/GlobalFocusChange.java
index 041c0de..ee92b64 100644
--- a/core/tests/coretests/src/android/view/GlobalFocusChange.java
+++ b/core/tests/coretests/src/android/view/GlobalFocusChange.java
@@ -16,12 +16,10 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.ViewTreeObserver;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class GlobalFocusChange extends Activity implements ViewTreeObserver.OnGlobalFocusChangeListener {
     public View mOldFocus;
diff --git a/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java b/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java
index dab7b90..960654a 100644
--- a/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java
+++ b/core/tests/coretests/src/android/view/GlobalFocusChangeTest.java
@@ -17,13 +17,13 @@
 package android.view;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.FlakyTest;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.Suppress;
-import android.view.View;
-import android.view.KeyEvent;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 import com.android.frameworks.coretests.R;
 
 @Suppress // Flaky
@@ -50,7 +50,7 @@
         super.tearDown();
     }
 
-    @FlakyTest(tolerance = 4)
+    @FlakyTest
     @LargeTest
     public void testFocusChange() throws Exception {
         sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
@@ -62,7 +62,7 @@
         assertSame(mRight, mActivity.mNewFocus);        
     }
 
-    @FlakyTest(tolerance = 4)
+    @FlakyTest
     @MediumTest
     public void testEnterTouchMode() throws Exception {
         assertTrue(mLeft.isFocused());
@@ -73,7 +73,7 @@
         assertSame(null, mActivity.mNewFocus);        
     }
 
-    @FlakyTest(tolerance = 4)
+    @FlakyTest
     @MediumTest
     public void testLeaveTouchMode() throws Exception {
         assertTrue(mLeft.isFocused());
diff --git a/core/tests/coretests/src/android/view/HandlerActionQueueTest.java b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
index fd8f23a..bedb75b 100644
--- a/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
+++ b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
@@ -17,7 +17,8 @@
 package android.view;
 
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 public class HandlerActionQueueTest extends AndroidTestCase {
 
diff --git a/core/tests/coretests/src/android/view/Include.java b/core/tests/coretests/src/android/view/Include.java
index e90c484..4b6aefb 100644
--- a/core/tests/coretests/src/android/view/Include.java
+++ b/core/tests/coretests/src/android/view/Include.java
@@ -16,10 +16,10 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
 import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise <include /> tag in XML files.
diff --git a/core/tests/coretests/src/android/view/IncludeTest.java b/core/tests/coretests/src/android/view/IncludeTest.java
index cdcfa3c..e490559 100644
--- a/core/tests/coretests/src/android/view/IncludeTest.java
+++ b/core/tests/coretests/src/android/view/IncludeTest.java
@@ -16,13 +16,11 @@
 
 package android.view;
 
-import android.view.Include;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
-import android.view.ViewGroup;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 public class IncludeTest extends ActivityInstrumentationTestCase<Include> {
     public IncludeTest() {
diff --git a/core/tests/coretests/src/android/view/InflateTest.java b/core/tests/coretests/src/android/view/InflateTest.java
index cb4f8e2..939d6ea 100644
--- a/core/tests/coretests/src/android/view/InflateTest.java
+++ b/core/tests/coretests/src/android/view/InflateTest.java
@@ -20,13 +20,11 @@
 import android.content.res.Resources;
 import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import com.android.frameworks.coretests.R;
 
-import java.util.Map;
+import androidx.test.filters.SmallTest;
+
+import com.android.frameworks.coretests.R;
 
 public class InflateTest extends AndroidTestCase implements PerformanceTestCase {
     private LayoutInflater mInflater;
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index d520f15..7cd3c44 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -18,7 +18,10 @@
 
 import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.TYPE_TOP_BAR;
+
 import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
 import android.graphics.Insets;
@@ -26,12 +29,13 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 import android.view.SurfaceControl.Transaction;
 import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -83,7 +87,7 @@
         consumers.put(TYPE_NAVIGATION_BAR, navConsumer);
         mController = new InsetsAnimationControlImpl(consumers,
                 new Rect(0, 0, 500, 500), state, mMockListener, WindowInsets.Type.systemBars(),
-                () -> mMockTransactionApplier);
+                () -> mMockTransactionApplier, mock(InsetsController.class));
     }
 
     @Test
@@ -97,6 +101,7 @@
     @Test
     public void testChangeInsets() {
         mController.changeInsets(Insets.of(0, 30, 40, 0));
+        mController.applyChangeInsets(new InsetsState());
         assertEquals(Insets.of(0, 30, 40, 0), mController.getCurrentInsets());
 
         ArgumentCaptor<SurfaceParams> captor = ArgumentCaptor.forClass(SurfaceParams.class);
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index d3d274a..d447451 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -17,18 +17,20 @@
 package android.view;
 
 import static android.view.InsetsState.TYPE_TOP_BAR;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNull;
+
 import static org.mockito.Mockito.mock;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mockito;
 
 @Presubmit
 @FlakyTest(detail = "Promote once confirmed non-flaky")
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 6d0f984..82cd213 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import static android.view.InsetsState.TYPE_TOP_BAR;
+
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.reset;
@@ -24,10 +25,11 @@
 import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.SurfaceControl.Transaction;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/InsetsSourceTest.java b/core/tests/coretests/src/android/view/InsetsSourceTest.java
index ed472d2..98ab3e7 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceTest.java
@@ -17,13 +17,15 @@
 package android.view;
 
 import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
+
 import static junit.framework.Assert.assertEquals;
 
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 9807f26..2db2f5f 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -24,17 +24,22 @@
 import static android.view.InsetsState.TYPE_SIDE_BAR_2;
 import static android.view.InsetsState.TYPE_SIDE_BAR_3;
 import static android.view.InsetsState.TYPE_TOP_BAR;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
+
 import static org.junit.Assert.assertNotEquals;
 
+import android.graphics.Insets;
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseIntArray;
+import android.view.WindowInsets.Type;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -55,10 +60,13 @@
         mState.getSource(TYPE_IME).setVisible(true);
         SparseIntArray typeSideMap = new SparseIntArray();
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
-                DisplayCutout.NO_CUTOUT, typeSideMap);
-        assertEquals(new Rect(0, 100, 0, 100), insets.getSystemWindowInsets());
+                DisplayCutout.NO_CUTOUT, null, null, typeSideMap);
+        assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets());
+        assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all()));
         assertEquals(INSET_SIDE_TOP, typeSideMap.get(TYPE_TOP_BAR));
         assertEquals(INSET_SIDE_BOTTOM, typeSideMap.get(TYPE_IME));
+        assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.topBar()));
+        assertEquals(Insets.of(0, 0, 0, 100), insets.getInsets(Type.ime()));
     }
 
     @Test
@@ -68,9 +76,13 @@
         mState.getSource(TYPE_IME).setFrame(new Rect(0, 100, 100, 300));
         mState.getSource(TYPE_IME).setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
-                DisplayCutout.NO_CUTOUT, null);
+                DisplayCutout.NO_CUTOUT, null, null, null);
         assertEquals(100, insets.getStableInsetBottom());
-        assertEquals(new Rect(0, 0, 0, 200), insets.getSystemWindowInsets());
+        assertEquals(Insets.of(0, 0, 0, 100), insets.getMaxInsets(Type.all()));
+        assertEquals(Insets.of(0, 0, 0, 200), insets.getSystemWindowInsets());
+        assertEquals(Insets.of(0, 0, 0, 200), insets.getInsets(Type.all()));
+        assertEquals(Insets.of(0, 0, 0, 100), insets.getInsets(Type.sideBars()));
+        assertEquals(Insets.of(0, 0, 0, 200), insets.getInsets(Type.ime()));
     }
 
     @Test
@@ -80,8 +92,10 @@
         mState.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
         mState.getSource(TYPE_NAVIGATION_BAR).setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
-                DisplayCutout.NO_CUTOUT, null);
-        assertEquals(new Rect(0, 100, 20, 0), insets.getSystemWindowInsets());
+                DisplayCutout.NO_CUTOUT, null, null, null);
+        assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
+        assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.topBar()));
+        assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.sideBars()));
     }
 
     @Test
@@ -92,7 +106,7 @@
         mState.getSource(TYPE_IME).setVisible(true);
         mState.removeSource(TYPE_IME);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
-                DisplayCutout.NO_CUTOUT, null);
+                DisplayCutout.NO_CUTOUT, null, null, null);
         assertEquals(0, insets.getSystemWindowInsetBottom());
     }
 
diff --git a/core/tests/coretests/src/android/view/KeyEventTest.java b/core/tests/coretests/src/android/view/KeyEventTest.java
index b9d95e5..88d3bdb 100644
--- a/core/tests/coretests/src/android/view/KeyEventTest.java
+++ b/core/tests/coretests/src/android/view/KeyEventTest.java
@@ -20,8 +20,8 @@
 
 import static org.junit.Assert.assertEquals;
 
-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/core/tests/coretests/src/android/view/ListContextMenu.java b/core/tests/coretests/src/android/view/ListContextMenu.java
index 1b4ece6..e333b96 100644
--- a/core/tests/coretests/src/android/view/ListContextMenu.java
+++ b/core/tests/coretests/src/android/view/ListContextMenu.java
@@ -16,24 +16,17 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.ListActivity;
 import android.content.Context;
 import android.os.Bundle;
 import android.util.Log;
-import android.view.ContextMenu;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.SubMenu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercises context menus in lists
  */
diff --git a/core/tests/coretests/src/android/view/Longpress.java b/core/tests/coretests/src/android/view/Longpress.java
index e8e6f13..86fa9e5 100644
--- a/core/tests/coretests/src/android/view/Longpress.java
+++ b/core/tests/coretests/src/android/view/Longpress.java
@@ -16,11 +16,11 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 public class Longpress extends Activity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/core/tests/coretests/src/android/view/LongpressTest.java b/core/tests/coretests/src/android/view/LongpressTest.java
index d3d7589..4dfecd0 100644
--- a/core/tests/coretests/src/android/view/LongpressTest.java
+++ b/core/tests/coretests/src/android/view/LongpressTest.java
@@ -18,11 +18,12 @@
 
 import android.test.ActivityInstrumentationTestCase;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.KeyUtils;
 import android.view.View.OnLongClickListener;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/view/MenuTest.java b/core/tests/coretests/src/android/view/MenuTest.java
index 116b38a..794769cc 100644
--- a/core/tests/coretests/src/android/view/MenuTest.java
+++ b/core/tests/coretests/src/android/view/MenuTest.java
@@ -17,7 +17,8 @@
 package android.view;
 
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.frameworks.coretests.R;
 import com.android.internal.view.menu.MenuBuilder;
diff --git a/core/tests/coretests/src/android/view/Merge.java b/core/tests/coretests/src/android/view/Merge.java
index bdacd81..8020e4b 100644
--- a/core/tests/coretests/src/android/view/Merge.java
+++ b/core/tests/coretests/src/android/view/Merge.java
@@ -16,13 +16,11 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
 import android.app.Activity;
+import android.os.Bundle;
 import android.widget.LinearLayout;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise <merge /> tag in XML files.
diff --git a/core/tests/coretests/src/android/view/MergeTest.java b/core/tests/coretests/src/android/view/MergeTest.java
index acfee7e..eccc9cb 100644
--- a/core/tests/coretests/src/android/view/MergeTest.java
+++ b/core/tests/coretests/src/android/view/MergeTest.java
@@ -16,11 +16,9 @@
 
 package android.view;
 
-import android.view.Merge;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.ViewGroup;
+
+import androidx.test.filters.MediumTest;
 
 public class MergeTest extends ActivityInstrumentationTestCase<Merge> {
     public MergeTest() {
diff --git a/core/tests/coretests/src/android/view/MotionEventTest.java b/core/tests/coretests/src/android/view/MotionEventTest.java
index 023526f..cadf37e 100644
--- a/core/tests/coretests/src/android/view/MotionEventTest.java
+++ b/core/tests/coretests/src/android/view/MotionEventTest.java
@@ -22,11 +22,12 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/MutateDrawable.java b/core/tests/coretests/src/android/view/MutateDrawable.java
index 39b5789..1ec525d 100644
--- a/core/tests/coretests/src/android/view/MutateDrawable.java
+++ b/core/tests/coretests/src/android/view/MutateDrawable.java
@@ -18,8 +18,9 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.widget.LinearLayout;
 import android.widget.Button;
+import android.widget.LinearLayout;
+
 import com.android.frameworks.coretests.R;
 
 public class MutateDrawable extends Activity {
diff --git a/core/tests/coretests/src/android/view/MutateDrawableTest.java b/core/tests/coretests/src/android/view/MutateDrawableTest.java
index 74e011d..d63ffb1 100644
--- a/core/tests/coretests/src/android/view/MutateDrawableTest.java
+++ b/core/tests/coretests/src/android/view/MutateDrawableTest.java
@@ -17,9 +17,8 @@
 package android.view;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
-import android.view.MutateDrawable;
+
+import androidx.test.filters.MediumTest;
 
 public class MutateDrawableTest extends ActivityInstrumentationTestCase2<MutateDrawable> {
     private View mFirstButton;
diff --git a/core/tests/coretests/src/android/view/PinchZoomAction.java b/core/tests/coretests/src/android/view/PinchZoomAction.java
index 97fe980..bec9b55 100644
--- a/core/tests/coretests/src/android/view/PinchZoomAction.java
+++ b/core/tests/coretests/src/android/view/PinchZoomAction.java
@@ -30,8 +30,6 @@
 import android.support.test.espresso.ViewAction;
 import android.support.test.espresso.action.Swiper;
 import android.support.test.espresso.util.HumanReadables;
-import android.view.MotionEvent;
-import android.view.View;
 
 import org.hamcrest.Matcher;
 
diff --git a/core/tests/coretests/src/android/view/PopupWindowVisibility.java b/core/tests/coretests/src/android/view/PopupWindowVisibility.java
index 85ce04f..e6430d3 100644
--- a/core/tests/coretests/src/android/view/PopupWindowVisibility.java
+++ b/core/tests/coretests/src/android/view/PopupWindowVisibility.java
@@ -18,7 +18,6 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.ArrayAdapter;
 import android.widget.AutoCompleteTextView;
diff --git a/core/tests/coretests/src/android/view/PreDrawListener.java b/core/tests/coretests/src/android/view/PreDrawListener.java
index 60bbee4..77bd36c 100644
--- a/core/tests/coretests/src/android/view/PreDrawListener.java
+++ b/core/tests/coretests/src/android/view/PreDrawListener.java
@@ -20,15 +20,12 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewTreeObserver;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.LinearLayout;
 
 import com.android.frameworks.coretests.R;
 
-
 /**
  * Tests views with popupWindows becoming invisible
  */
diff --git a/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java b/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
index b52d98c..786c22b 100644
--- a/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
+++ b/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
@@ -21,10 +21,11 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/RunQueue.java b/core/tests/coretests/src/android/view/RunQueue.java
index 85dd32e..7544433 100644
--- a/core/tests/coretests/src/android/view/RunQueue.java
+++ b/core/tests/coretests/src/android/view/RunQueue.java
@@ -19,8 +19,7 @@
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.TextView;
-import android.view.View;
-import android.view.ViewTreeObserver;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/view/RunQueueTest.java b/core/tests/coretests/src/android/view/RunQueueTest.java
index d69860b..f42f590 100644
--- a/core/tests/coretests/src/android/view/RunQueueTest.java
+++ b/core/tests/coretests/src/android/view/RunQueueTest.java
@@ -17,7 +17,8 @@
 package android.view;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.MediumTest;
 
 public class RunQueueTest extends ActivityInstrumentationTestCase<RunQueue> {
     public RunQueueTest() {
diff --git a/core/tests/coretests/src/android/view/ScaleGesture.java b/core/tests/coretests/src/android/view/ScaleGesture.java
index a954a4a..235b224 100644
--- a/core/tests/coretests/src/android/view/ScaleGesture.java
+++ b/core/tests/coretests/src/android/view/ScaleGesture.java
@@ -16,16 +16,11 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
 import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
-import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
 
 public class ScaleGesture extends Activity {
     private ScaleGestureDetector mScaleGestureDetector;
diff --git a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
index fba8eae..1990135 100644
--- a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
+++ b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
@@ -16,26 +16,22 @@
 
 package android.view;
 
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
 import android.content.Context;
-import android.support.test.filters.LargeTest;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.DisplayMetrics;
-import android.view.PinchZoomAction;
-import android.view.ScaleGesture;
-import android.view.WindowManager;
 import android.widget.TextView;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.Espresso.onView;
 
 @LargeTest
 public class ScaleGestureDetectorTest extends ActivityInstrumentationTestCase2<ScaleGesture> {
diff --git a/core/tests/coretests/src/android/view/SetTagsTest.java b/core/tests/coretests/src/android/view/SetTagsTest.java
index 373dce6..1699713 100644
--- a/core/tests/coretests/src/android/view/SetTagsTest.java
+++ b/core/tests/coretests/src/android/view/SetTagsTest.java
@@ -16,12 +16,13 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-import android.test.suitebuilder.annotation.MediumTest;
-
 import android.test.ActivityInstrumentationTestCase2;
 import android.widget.Button;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercises {@link android.view.View}'s tags property.
  */
diff --git a/core/tests/coretests/src/android/view/StubbedView.java b/core/tests/coretests/src/android/view/StubbedView.java
index 612095c..c96b9b7 100644
--- a/core/tests/coretests/src/android/view/StubbedView.java
+++ b/core/tests/coretests/src/android/view/StubbedView.java
@@ -16,11 +16,10 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
 import android.app.Activity;
-import android.view.View;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise <ViewStub /> tag in XML files.
diff --git a/core/tests/coretests/src/android/view/VelocityTest.java b/core/tests/coretests/src/android/view/VelocityTest.java
index 7f32208..c116f4d 100644
--- a/core/tests/coretests/src/android/view/VelocityTest.java
+++ b/core/tests/coretests/src/android/view/VelocityTest.java
@@ -16,16 +16,17 @@
 
 package android.view;
 
-import android.test.suitebuilder.annotation.Suppress;
-import junit.framework.Assert;
-
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import junit.framework.Assert;
+
 /**
  * Exercises {@link android.view.VelocityTracker} to compute correct velocity.<br>
  * To launch this test, use :<br>
diff --git a/core/tests/coretests/src/android/view/ViewAttachTest.java b/core/tests/coretests/src/android/view/ViewAttachTest.java
index aa8f8d8..1a8dd99 100644
--- a/core/tests/coretests/src/android/view/ViewAttachTest.java
+++ b/core/tests/coretests/src/android/view/ViewAttachTest.java
@@ -16,16 +16,13 @@
 
 package android.view;
 
-import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.graphics.PixelFormat;
 import android.os.SystemClock;
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/view/ViewAttachTestActivity.java b/core/tests/coretests/src/android/view/ViewAttachTestActivity.java
index 59e25ae..bcbc813 100644
--- a/core/tests/coretests/src/android/view/ViewAttachTestActivity.java
+++ b/core/tests/coretests/src/android/view/ViewAttachTestActivity.java
@@ -16,11 +16,11 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 public class ViewAttachTestActivity extends Activity {
     public static final String TAG = "OnAttachedTest";
     @Override
diff --git a/core/tests/coretests/src/android/view/ViewAttachView.java b/core/tests/coretests/src/android/view/ViewAttachView.java
index 5af2d8f..2f3ff8f 100644
--- a/core/tests/coretests/src/android/view/ViewAttachView.java
+++ b/core/tests/coretests/src/android/view/ViewAttachView.java
@@ -22,7 +22,6 @@
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.View;
 
 /**
  * A View that will throw a RuntimeException if onAttachedToWindow and
diff --git a/core/tests/coretests/src/android/view/ViewCaptureTest.java b/core/tests/coretests/src/android/view/ViewCaptureTest.java
index 4405934..218047c 100644
--- a/core/tests/coretests/src/android/view/ViewCaptureTest.java
+++ b/core/tests/coretests/src/android/view/ViewCaptureTest.java
@@ -21,14 +21,15 @@
 import android.app.Activity;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.support.test.filters.SmallTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseIntArray;
 import android.view.ViewDebug.CanvasProvider;
 import android.view.ViewDebug.HardwareCanvasProvider;
 import android.view.ViewDebug.SoftwareCanvasProvider;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.Assert;
diff --git a/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java b/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
index 20e3eb5..2f51c24 100644
--- a/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
+++ b/core/tests/coretests/src/android/view/ViewCaptureTestActivity.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.os.Bundle;
+
 import com.android.frameworks.coretests.R;
 
 public class ViewCaptureTestActivity extends Activity {
diff --git a/core/tests/coretests/src/android/view/ViewGroupAttributesTest.java b/core/tests/coretests/src/android/view/ViewGroupAttributesTest.java
index b4ef0e7..c24cd35 100644
--- a/core/tests/coretests/src/android/view/ViewGroupAttributesTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupAttributesTest.java
@@ -18,7 +18,8 @@
 
 import android.content.Context;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 public class ViewGroupAttributesTest extends AndroidTestCase {
 
diff --git a/core/tests/coretests/src/android/view/ViewGroupChildren.java b/core/tests/coretests/src/android/view/ViewGroupChildren.java
index f39720b..d5d9879 100644
--- a/core/tests/coretests/src/android/view/ViewGroupChildren.java
+++ b/core/tests/coretests/src/android/view/ViewGroupChildren.java
@@ -16,12 +16,10 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
-import android.widget.Button;
-import android.view.View;
 import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise ViewGroup's ability to add and remove children.
diff --git a/core/tests/coretests/src/android/view/ViewGroupChildrenTest.java b/core/tests/coretests/src/android/view/ViewGroupChildrenTest.java
index d1665ef..07cb2a1 100644
--- a/core/tests/coretests/src/android/view/ViewGroupChildrenTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupChildrenTest.java
@@ -16,18 +16,16 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-import android.view.ViewGroupChildren;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
-import android.test.UiThreadTest;
-import android.view.View;
-import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercises {@link android.view.ViewGroup}'s ability to add/remove children.
  */
diff --git a/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java b/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java
index 93ad41f0..54524b2 100644
--- a/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupTransientViewTest.java
@@ -22,12 +22,13 @@
 import android.app.Activity;
 import android.content.Context;
 import android.graphics.Canvas;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.widget.FrameLayout;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/ViewInvalidateTest.java b/core/tests/coretests/src/android/view/ViewInvalidateTest.java
index 115504b..c25a2deb 100644
--- a/core/tests/coretests/src/android/view/ViewInvalidateTest.java
+++ b/core/tests/coretests/src/android/view/ViewInvalidateTest.java
@@ -21,24 +21,30 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.content.Context;
 import android.graphics.Rect;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
+import android.view.ViewTreeObserver.OnDrawListener;
 import android.widget.FrameLayout;
 
-import com.android.compatibility.common.util.WidgetTestUtils;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Test of invalidates, drawing, and the flags that support them
  */
@@ -281,4 +287,42 @@
                 View.PFLAG_DRAWN);
         assertTrue(getViewRoot(mParent).mIsAnimating);
     }
+
+    /** Copied from cts/common/device-side/util. */
+    static class WidgetTestUtils {
+        public static void runOnMainAndDrawSync(@NonNull final ActivityTestRule activityTestRule,
+                @NonNull final View view, @Nullable final Runnable runner) throws Throwable {
+            final CountDownLatch latch = new CountDownLatch(1);
+
+            activityTestRule.runOnUiThread(() -> {
+                final OnDrawListener listener = new OnDrawListener() {
+                    @Override
+                    public void onDraw() {
+                        // posting so that the sync happens after the draw that's about to happen
+                        view.post(() -> {
+                            activityTestRule.getActivity().getWindow().getDecorView()
+                                    .getViewTreeObserver().removeOnDrawListener(this);
+                            latch.countDown();
+                        });
+                    }
+                };
+
+                activityTestRule.getActivity().getWindow().getDecorView()
+                        .getViewTreeObserver().addOnDrawListener(listener);
+
+                if (runner != null) {
+                    runner.run();
+                }
+                view.invalidate();
+            });
+
+            try {
+                Assert.assertTrue("Expected draw pass occurred within 5 seconds",
+                        latch.await(5, TimeUnit.SECONDS));
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+    }
 }
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index ca6d6cf..9a57847 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -23,9 +23,10 @@
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/ViewStubTest.java b/core/tests/coretests/src/android/view/ViewStubTest.java
index ebd52a6..504a4ec 100644
--- a/core/tests/coretests/src/android/view/ViewStubTest.java
+++ b/core/tests/coretests/src/android/view/ViewStubTest.java
@@ -16,14 +16,12 @@
 
 package android.view;
 
-import android.view.StubbedView;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.UiThreadTest;
-import android.view.View;
-import android.view.ViewStub;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 public class ViewStubTest extends ActivityInstrumentationTestCase<StubbedView> {
     public ViewStubTest() {
diff --git a/core/tests/coretests/src/android/view/ViewTransientStateTest.java b/core/tests/coretests/src/android/view/ViewTransientStateTest.java
index 36ea01d..3f73b07 100644
--- a/core/tests/coretests/src/android/view/ViewTransientStateTest.java
+++ b/core/tests/coretests/src/android/view/ViewTransientStateTest.java
@@ -18,13 +18,12 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
 
 import com.android.frameworks.coretests.R;
 
-import static org.junit.Assert.assertFalse;
-
 /**
  * Exercise set View's transient state
  */
diff --git a/core/tests/coretests/src/android/view/Visibility.java b/core/tests/coretests/src/android/view/Visibility.java
index 031568c..8e3de4e 100644
--- a/core/tests/coretests/src/android/view/Visibility.java
+++ b/core/tests/coretests/src/android/view/Visibility.java
@@ -16,12 +16,11 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
+import android.app.Activity;
 import android.os.Bundle;
 import android.widget.Button;
-import android.view.View;
-import android.app.Activity;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise View's ability to change their visibility: GONE, INVISIBLE and
diff --git a/core/tests/coretests/src/android/view/VisibilityCallback.java b/core/tests/coretests/src/android/view/VisibilityCallback.java
index f98a0a8..c965973 100644
--- a/core/tests/coretests/src/android/view/VisibilityCallback.java
+++ b/core/tests/coretests/src/android/view/VisibilityCallback.java
@@ -16,16 +16,15 @@
 
 package android.view;
 
+import android.app.Activity;
 import android.content.Context;
+import android.os.Bundle;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.widget.TextView;
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
 import android.widget.Button;
-import android.view.View;
-import android.app.Activity;
+import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercise View's ability to change their visibility: GONE, INVISIBLE and
diff --git a/core/tests/coretests/src/android/view/VisibilityCallbackTest.java b/core/tests/coretests/src/android/view/VisibilityCallbackTest.java
index ec956d2..d7c7b4c 100644
--- a/core/tests/coretests/src/android/view/VisibilityCallbackTest.java
+++ b/core/tests/coretests/src/android/view/VisibilityCallbackTest.java
@@ -17,12 +17,12 @@
 package android.view;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
-import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.TextView;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/view/VisibilityTest.java b/core/tests/coretests/src/android/view/VisibilityTest.java
index 29c1c8a..83a7702 100644
--- a/core/tests/coretests/src/android/view/VisibilityTest.java
+++ b/core/tests/coretests/src/android/view/VisibilityTest.java
@@ -20,11 +20,12 @@
 import static android.view.KeyEvent.KEYCODE_DPAD_LEFT;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.Button;
 import android.widget.TextView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index 1c2df2c..d57fa8f 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -16,12 +16,19 @@
 
 package android.view;
 
+import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.sideBars;
+import static android.view.WindowInsets.Type.topBar;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.graphics.Insets;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import android.view.WindowInsets.Builder;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -33,13 +40,13 @@
 
     @Test
     public void systemWindowInsets_afterConsuming_isConsumed() {
-        assertTrue(new WindowInsets(new Rect(1, 2, 3, 4), null, null, false, false, null)
+        assertTrue(new WindowInsets(new Rect(1, 2, 3, 4), null, false, false, null)
                 .consumeSystemWindowInsets().isConsumed());
     }
 
     @Test
     public void multiNullConstructor_isConsumed() {
-        assertTrue(new WindowInsets(null, null, null, false, false, null).isConsumed());
+        assertTrue(new WindowInsets((Rect) null, null, false, false, null).isConsumed());
     }
 
     @Test
@@ -47,4 +54,23 @@
         assertTrue(new WindowInsets((Rect) null).isConsumed());
     }
 
+    // TODO: Move this to CTS once API made public
+    @Test
+    public void typeMap() {
+        Builder b = new WindowInsets.Builder();
+        b.setInsets(sideBars(), Insets.of(0, 0, 0, 100));
+        b.setInsets(ime(), Insets.of(0, 0, 0, 300));
+        WindowInsets insets = b.build();
+        assertEquals(300, insets.getSystemWindowInsets().bottom);
+    }
+
+    // TODO: Move this to CTS once API made public
+    @Test
+    public void compatInsets() {
+        Builder b = new WindowInsets.Builder();
+        b.setSystemWindowInsets(Insets.of(0, 50, 30, 10));
+        WindowInsets insets = b.build();
+        assertEquals(Insets.of(0, 50, 0, 0), insets.getInsets(topBar()));
+        assertEquals(Insets.of(0, 0, 30, 10), insets.getInsets(sideBars()));
+    }
 }
diff --git a/core/tests/coretests/src/android/view/ZeroSized.java b/core/tests/coretests/src/android/view/ZeroSized.java
index f2a6b3e..9e2dfcb 100644
--- a/core/tests/coretests/src/android/view/ZeroSized.java
+++ b/core/tests/coretests/src/android/view/ZeroSized.java
@@ -16,10 +16,10 @@
 
 package android.view;
 
-import com.android.frameworks.coretests.R;
-
-import android.os.Bundle;
 import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * This activity contains Views with various widths and heights. The goal is to exercise the
diff --git a/core/tests/coretests/src/android/view/ZeroSizedTest.java b/core/tests/coretests/src/android/view/ZeroSizedTest.java
index 193fc98..946bf68 100644
--- a/core/tests/coretests/src/android/view/ZeroSizedTest.java
+++ b/core/tests/coretests/src/android/view/ZeroSizedTest.java
@@ -16,13 +16,12 @@
 
 package android.view;
 
-import android.view.ZeroSized;
-import com.android.frameworks.coretests.R;
-
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
 import android.graphics.Bitmap;
+import android.test.ActivityInstrumentationTestCase;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Builds the drawing cache of Views of various dimension. The assumption is that
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
index 7f675ff..a88968b 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
@@ -28,10 +28,11 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
index 3e03414..46c96c9 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
@@ -21,7 +21,8 @@
 import static junit.framework.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
index 318d122..ab24f89 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
@@ -22,10 +22,12 @@
 
 import android.os.Bundle;
 import android.os.RemoteException;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import libcore.util.EmptyArray;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 506e544..0ed690c 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -25,11 +25,12 @@
 import static org.junit.Assert.fail;
 
 import android.os.Parcel;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArraySet;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.util.CollectionUtils;
 
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index 0dd7685..683d16b 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -88,32 +88,32 @@
 
     public void setOnKeyEventResult(boolean handled, int sequence) {}
 
-    public float getMagnificationScale() {
+    public float getMagnificationScale(int displayId) {
         return 0.0f;
     }
 
-    public float getMagnificationCenterX() {
+    public float getMagnificationCenterX(int displayId) {
         return 0.0f;
     }
 
-    public float getMagnificationCenterY() {
+    public float getMagnificationCenterY(int displayId) {
         return 0.0f;
     }
 
-    public Region getMagnificationRegion() {
+    public Region getMagnificationRegion(int displayId) {
         return null;
     }
 
-    public boolean resetMagnification(boolean animate) {
+    public boolean resetMagnification(int displayId, boolean animate) {
         return false;
     }
 
-    public boolean setMagnificationScaleAndCenter(float scale, float centerX, float centerY,
-            boolean animate) {
+    public boolean setMagnificationScaleAndCenter(int displayId, float scale, float centerX,
+            float centerY, boolean animate) {
         return false;
     }
 
-    public void setMagnificationCallbackEnabled(boolean enabled) {}
+    public void setMagnificationCallbackEnabled(int displayId, boolean enabled) {}
 
     public boolean setSoftKeyboardShowMode(int showMode) {
         return false;
diff --git a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
index 4814c61..11f4e3c 100644
--- a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
@@ -14,7 +14,7 @@
 
 package android.view.accessibility;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java b/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
new file mode 100644
index 0000000..2f17b32
--- /dev/null
+++ b/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.os.Parcel;
+import android.view.View;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class AutofillIdTest {
+
+    @Test
+    public void testNonVirtual() {
+        final AutofillId id = new AutofillId(42);
+        assertThat(id.getViewId()).isEqualTo(42);
+        assertThat(id.isNonVirtual()).isTrue();
+        assertThat(id.isVirtualInt()).isFalse();
+        assertThat(id.isVirtualLong()).isFalse();
+        assertThat(id.getVirtualChildIntId()).isEqualTo(View.NO_ID);
+        assertThat(id.getVirtualChildLongId()).isEqualTo(View.NO_ID);
+
+        final AutofillId clone = cloneThroughParcel(id);
+        assertThat(clone.getViewId()).isEqualTo(42);
+        assertThat(clone.isNonVirtual()).isTrue();
+        assertThat(clone.isVirtualInt()).isFalse();
+        assertThat(clone.isVirtualLong()).isFalse();
+        assertThat(clone.getVirtualChildIntId()).isEqualTo(View.NO_ID);
+        assertThat(clone.getVirtualChildLongId()).isEqualTo(View.NO_ID);
+    }
+
+    @Test
+    public void testVirtual_int() {
+        final AutofillId id = new AutofillId(42, 108);
+        assertThat(id.getViewId()).isEqualTo(42);
+        assertThat(id.isVirtualInt()).isTrue();
+        assertThat(id.isVirtualLong()).isFalse();
+        assertThat(id.isNonVirtual()).isFalse();
+        assertThat(id.getVirtualChildIntId()).isEqualTo(108);
+        assertThat(id.getVirtualChildLongId()).isEqualTo(View.NO_ID);
+
+        final AutofillId clone = cloneThroughParcel(id);
+        assertThat(clone.getViewId()).isEqualTo(42);
+        assertThat(clone.isVirtualLong()).isFalse();
+        assertThat(clone.isVirtualInt()).isTrue();
+        assertThat(clone.isNonVirtual()).isFalse();
+        assertThat(clone.getVirtualChildIntId()).isEqualTo(108);
+        assertThat(clone.getVirtualChildLongId()).isEqualTo(View.NO_ID);
+    }
+
+    @Test
+    public void testVirtual_long() {
+        final AutofillId id = new AutofillId(new AutofillId(42), 4815162342L, 108);
+        assertThat(id.getViewId()).isEqualTo(42);
+        assertThat(id.isVirtualLong()).isTrue();
+        assertThat(id.isVirtualInt()).isFalse();
+        assertThat(id.isNonVirtual()).isFalse();
+        assertThat(id.getVirtualChildIntId()).isEqualTo(View.NO_ID);
+        assertThat(id.getVirtualChildLongId()).isEqualTo(4815162342L);
+
+        final AutofillId clone = cloneThroughParcel(id);
+        assertThat(clone.getViewId()).isEqualTo(42);
+        assertThat(clone.isVirtualLong()).isTrue();
+        assertThat(clone.isVirtualInt()).isFalse();
+        assertThat(clone.isNonVirtual()).isFalse();
+        assertThat(clone.getVirtualChildIntId()).isEqualTo(View.NO_ID);
+        assertThat(clone.getVirtualChildLongId()).isEqualTo(4815162342L);
+    }
+
+    @Test
+    public void testVirtual_parentObjectConstructor() {
+        assertThrows(NullPointerException.class, () -> new AutofillId(null, 108));
+
+        final AutofillId id = new AutofillId(new AutofillId(42), 108);
+        assertThat(id.getViewId()).isEqualTo(42);
+        assertThat(id.isVirtualInt()).isTrue();
+        assertThat(id.getVirtualChildIntId()).isEqualTo(108);
+
+        final AutofillId clone = cloneThroughParcel(id);
+        assertThat(clone.getViewId()).isEqualTo(42);
+        assertThat(clone.isVirtualInt()).isTrue();
+        assertThat(clone.getVirtualChildIntId()).isEqualTo(108);
+    }
+
+    @Test
+    public void testVirtual_withSession() {
+        final AutofillId id = new AutofillId(new AutofillId(42), 108L, 666);
+        assertThat(id.getViewId()).isEqualTo(42);
+        assertThat(id.isVirtualLong()).isTrue();
+        assertThat(id.isVirtualInt()).isFalse();
+        assertThat(id.isNonVirtual()).isFalse();
+        assertThat(id.getVirtualChildLongId()).isEqualTo(108L);
+        assertThat(id.getVirtualChildIntId()).isEqualTo(View.NO_ID);
+        assertThat(id.getSessionId()).isEqualTo(666);
+
+        final AutofillId clone = cloneThroughParcel(id);
+        assertThat(clone.getViewId()).isEqualTo(42);
+        assertThat(clone.isVirtualLong()).isTrue();
+        assertThat(clone.isVirtualInt()).isFalse();
+        assertThat(clone.isNonVirtual()).isFalse();
+        assertThat(clone.getVirtualChildLongId()).isEqualTo(108L);
+        assertThat(clone.getVirtualChildIntId()).isEqualTo(View.NO_ID);
+        assertThat(clone.getSessionId()).isEqualTo(666);
+    }
+
+    @Test
+    public void testEqualsHashCode() {
+        final AutofillId realId = new AutofillId(42);
+        final AutofillId realIdSame = new AutofillId(42);
+        assertThat(realId).isEqualTo(realIdSame);
+        assertThat(realIdSame).isEqualTo(realId);
+        assertThat(realId.hashCode()).isEqualTo(realIdSame.hashCode());
+
+        final AutofillId realIdDifferent = new AutofillId(108);
+        assertThat(realId).isNotEqualTo(realIdDifferent);
+        assertThat(realIdDifferent).isNotEqualTo(realId);
+
+        final AutofillId virtualId = new AutofillId(42, 1);
+        final AutofillId virtualIdSame = new AutofillId(42, 1);
+        assertThat(virtualId).isEqualTo(virtualIdSame);
+        assertThat(virtualIdSame).isEqualTo(virtualId);
+        assertThat(virtualId.hashCode()).isEqualTo(virtualIdSame.hashCode());
+        assertThat(virtualId).isNotEqualTo(realId);
+        assertThat(realId).isNotEqualTo(virtualId);
+
+        final AutofillId virtualIdDifferentChild = new AutofillId(42, 2);
+        assertThat(virtualIdDifferentChild).isNotEqualTo(virtualId);
+        assertThat(virtualId).isNotEqualTo(virtualIdDifferentChild);
+        assertThat(virtualIdDifferentChild).isNotEqualTo(realId);
+        assertThat(realId).isNotEqualTo(virtualIdDifferentChild);
+
+        final AutofillId virtualIdDifferentParent = new AutofillId(108, 1);
+        assertThat(virtualIdDifferentParent).isNotEqualTo(virtualId);
+        assertThat(virtualId).isNotEqualTo(virtualIdDifferentParent);
+        assertThat(virtualIdDifferentParent).isNotEqualTo(virtualIdDifferentChild);
+        assertThat(virtualIdDifferentChild).isNotEqualTo(virtualIdDifferentParent);
+
+        final AutofillId virtualIdDifferentSession = new AutofillId(new AutofillId(42), 1L, 108);
+        assertThat(virtualIdDifferentSession).isNotEqualTo(virtualId);
+        assertThat(virtualId).isNotEqualTo(virtualIdDifferentSession);
+        assertThat(virtualIdDifferentSession).isNotEqualTo(realId);
+        assertThat(realId).isNotEqualTo(virtualIdDifferentSession);
+
+        final AutofillId sameVirtualIdDifferentSession =
+                new AutofillId(new AutofillId(42), 1L, 108);
+        assertThat(sameVirtualIdDifferentSession).isEqualTo(virtualIdDifferentSession);
+        assertThat(virtualIdDifferentSession).isEqualTo(sameVirtualIdDifferentSession);
+        assertThat(sameVirtualIdDifferentSession.hashCode())
+                .isEqualTo(virtualIdDifferentSession.hashCode());
+    }
+
+    private AutofillId cloneThroughParcel(AutofillId id) {
+        Parcel parcel = Parcel.obtain();
+
+        try {
+            // Write to parcel
+            parcel.setDataPosition(0); // Sanity / paranoid check
+            id.writeToParcel(parcel, 0);
+
+            // Read from parcel
+            parcel.setDataPosition(0);
+            AutofillId clone = AutofillId.CREATOR.createFromParcel(parcel);
+            assertThat(clone).isNotNull();
+            return clone;
+        } finally {
+            parcel.recycle();
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
new file mode 100644
index 0000000..312e0e0
--- /dev/null
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.contentcapture;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+/**
+ * Unit test for {@link ContentCaptureManager}.
+ *
+ * <p>To run it:
+ * {@code atest FrameworksCoreTests:android.view.contentcapture.ContentCaptureManagerTest}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ContentCaptureManagerTest {
+
+    @Mock
+    private Context mMockContext;
+
+    private ContentCaptureManager mManager;
+
+    @Before
+    public void before() {
+        mManager = new ContentCaptureManager(mMockContext, null);
+    }
+
+    @Test
+    public void testRemoveUserData_invalid() {
+        assertThrows(NullPointerException.class, () -> mManager.removeUserData(null));
+    }
+}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
new file mode 100644
index 0000000..bfa6e06
--- /dev/null
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.contentcapture;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.view.View;
+import android.view.ViewStructure;
+import android.view.autofill.AutofillId;
+import android.view.contentcapture.ViewNode.ViewStructureImpl;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+/**
+ * Unit tests for {@link ContentCaptureSession}.
+ *
+ * <p>To run it:
+ * {@code atest FrameworksCoreTests:android.view.contentcapture.ContentCaptureSessionTest}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ContentCaptureSessionTest {
+
+    private ContentCaptureSession mSession1 = new MyContentCaptureSession("111");
+
+    private ContentCaptureSession mSession2 = new MyContentCaptureSession("2222");
+
+    @Mock
+    private View mMockView;
+
+    @Test
+    public void testNewAutofillId_invalid() {
+        assertThrows(NullPointerException.class, () -> mSession1.newAutofillId(null, 42L));
+        assertThrows(IllegalArgumentException.class,
+                () -> mSession1.newAutofillId(new AutofillId(42, 42), 42L));
+    }
+
+    @Test
+    public void testNewAutofillId_valid() {
+        final AutofillId parentId = new AutofillId(42);
+        final AutofillId childId = mSession1.newAutofillId(parentId, 108L);
+        assertThat(childId.getViewId()).isEqualTo(42);
+        assertThat(childId.getVirtualChildLongId()).isEqualTo(108L);
+        assertThat(childId.getVirtualChildIntId()).isEqualTo(View.NO_ID);
+        assertThat(childId.getSessionId()).isEqualTo(mSession1.getIdAsInt());
+    }
+
+    @Test
+    public void testNewAutofillId_differentSessions() {
+        assertThat(mSession1.getIdAsInt()).isNotSameAs(mSession2.getIdAsInt()); //sanity check
+        final AutofillId parentId = new AutofillId(42);
+        final AutofillId childId1 = mSession1.newAutofillId(parentId, 108L);
+        final AutofillId childId2 = mSession2.newAutofillId(parentId, 108L);
+        assertThat(childId1).isNotEqualTo(childId2);
+        assertThat(childId2).isNotEqualTo(childId1);
+    }
+
+    @Test
+    public void testNotifyXXX_null() {
+        assertThrows(NullPointerException.class, () -> mSession1.notifyViewAppeared(null));
+        assertThrows(NullPointerException.class, () -> mSession1.notifyViewDisappeared(null));
+        assertThrows(NullPointerException.class,
+                () -> mSession1.notifyViewTextChanged(null, "whatever", 0));
+    }
+
+    @Test
+    public void testNewViewStructure() {
+        assertThat(mMockView.getAutofillId()).isNotNull(); // sanity check
+        final ViewStructure structure = mSession1.newViewStructure(mMockView);
+        assertThat(structure).isNotNull();
+        assertThat(structure.getAutofillId()).isEqualTo(mMockView.getAutofillId());
+    }
+
+    @Test
+    public void testNewVirtualViewStructure() {
+        final AutofillId parentId = new AutofillId(42);
+        final ViewStructure structure = mSession1.newVirtualViewStructure(parentId, 108L);
+        assertThat(structure).isNotNull();
+        final AutofillId childId = mSession1.newAutofillId(parentId, 108L);
+        assertThat(structure.getAutofillId()).isEqualTo(childId);
+    }
+
+    @Test
+    public void testNotifyViewsDisappeared_invalid() {
+        // Null parent
+        assertThrows(NullPointerException.class,
+                () -> mSession1.notifyViewsDisappeared(null, new long[] {42}));
+        // Null child
+        assertThrows(IllegalArgumentException.class,
+                () -> mSession1.notifyViewsDisappeared(new AutofillId(42), null));
+        // Empty child
+        assertThrows(IllegalArgumentException.class,
+                () -> mSession1.notifyViewsDisappeared(new AutofillId(42), new long[] {}));
+        // Virtual parent
+        assertThrows(IllegalArgumentException.class,
+                () -> mSession1.notifyViewsDisappeared(new AutofillId(42, 108), new long[] {666}));
+    }
+
+    // Cannot use @Spy because we need to pass the session id on constructor
+    private class MyContentCaptureSession extends ContentCaptureSession {
+
+        private MyContentCaptureSession(String id) {
+            super(id);
+        }
+
+        @Override
+        MainContentCaptureSession getMainCaptureSession() {
+            throw new UnsupportedOperationException("should not have been called");
+        }
+
+        @Override
+        ContentCaptureSession newChild(ContentCaptureContext context) {
+            throw new UnsupportedOperationException("should not have been called");
+        }
+
+        @Override
+        void flush(int reason) {
+            throw new UnsupportedOperationException("should not have been called");
+        }
+
+        @Override
+        void onDestroy() {
+            throw new UnsupportedOperationException("should not have been called");
+        }
+
+        @Override
+        void internalNotifyViewAppeared(ViewStructureImpl node) {
+            throw new UnsupportedOperationException("should not have been called");
+        }
+
+        @Override
+        void internalNotifyViewDisappeared(AutofillId id) {
+            throw new UnsupportedOperationException("should not have been called");
+        }
+
+        @Override
+        void internalNotifyViewTextChanged(AutofillId id, CharSequence text) {
+            throw new UnsupportedOperationException("should not have been called");
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/view/contentcapture/UserDataRemovalRequestTest.java b/core/tests/coretests/src/android/view/contentcapture/UserDataRemovalRequestTest.java
new file mode 100644
index 0000000..bebb2a8
--- /dev/null
+++ b/core/tests/coretests/src/android/view/contentcapture/UserDataRemovalRequestTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.contentcapture;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.net.Uri;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+/**
+ * Unit test for {@link UserDataRemovalRequest}.
+ *
+ * <p>To run it:
+ * {@code atest FrameworksCoreTests:android.view.contentcapture.UserDataRemovalRequestTest}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class UserDataRemovalRequestTest {
+
+    @Mock
+    private final Uri mUri = Uri.parse("content://com.example/");
+
+    private UserDataRemovalRequest.Builder mBuilder = new UserDataRemovalRequest.Builder();
+
+    @Test
+    public void testBuilder_addUri_invalid() {
+        assertThrows(NullPointerException.class, () -> mBuilder.addUri(null, false));
+    }
+
+    @Test
+    public void testBuilder_addUri_valid() {
+        assertThat(mBuilder.addUri(mUri, false)).isNotNull();
+        assertThat(mBuilder.addUri(Uri.parse("content://com.example2"), true)).isNotNull();
+    }
+
+    @Test
+    public void testBuilder_addUriAfterForEverything() {
+        assertThat(mBuilder.forEverything()).isNotNull();
+        assertThrows(IllegalStateException.class, () -> mBuilder.addUri(mUri, false));
+    }
+
+    @Test
+    public void testBuilder_forEverythingAfterAddingUri() {
+        assertThat(mBuilder.addUri(mUri, false)).isNotNull();
+        assertThrows(IllegalStateException.class, () -> mBuilder.forEverything());
+    }
+
+    @Test
+    public void testBuild_invalid() {
+        assertThrows(IllegalStateException.class, () -> mBuilder.build());
+    }
+
+    @Test
+    public void testBuild_valid() {
+        assertThat(new UserDataRemovalRequest.Builder().forEverything().build())
+                .isNotNull();
+        assertThat(new UserDataRemovalRequest.Builder().addUri(mUri, false).build())
+                .isNotNull();
+    }
+
+    @Test
+    public void testNoMoreInteractionsAfterBuild() {
+        assertThat(mBuilder.forEverything().build()).isNotNull();
+
+        assertThrows(IllegalStateException.class, () -> mBuilder.addUri(mUri, false));
+        assertThrows(IllegalStateException.class, () -> mBuilder.forEverything());
+        assertThrows(IllegalStateException.class, () -> mBuilder.build());
+
+    }
+}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
new file mode 100644
index 0000000..b84a098
--- /dev/null
+++ b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.contentcapture;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+import android.graphics.Matrix;
+import android.os.Bundle;
+import android.os.LocaleList;
+import android.os.Parcel;
+import android.view.View;
+import android.view.ViewStructure.HtmlInfo;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.view.contentcapture.ViewNode.ViewStructureImpl;
+import android.widget.FrameLayout;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Locale;
+
+/**
+ * Unit tests for {@link ViewNode}.
+ *
+ * <p>To run it: {@code atest FrameworksCoreTests:android.view.contentcapture.ViewNodeTest}
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ViewNodeTest {
+
+    private final Context mContext = InstrumentationRegistry.getTargetContext();
+
+    @Mock
+    private HtmlInfo mHtmlInfoMock;
+
+    @Test
+    public void testAutofillIdMethods_orphanView() {
+        View view = new View(mContext);
+        AutofillId initialId = new AutofillId(42);
+        view.setAutofillId(initialId);
+
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        ViewNode node = structure.getNode();
+
+        assertThat(node.getAutofillId()).isEqualTo(initialId);
+        assertThat(node.getParentAutofillId()).isNull();
+
+        AutofillId newId = new AutofillId(108);
+        structure.setAutofillId(newId);
+        assertThat(node.getAutofillId()).isEqualTo(newId);
+        assertThat(node.getParentAutofillId()).isNull();
+
+        structure.setAutofillId(new AutofillId(66), 6);
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
+        assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
+    }
+
+    @Test
+    public void testAutofillIdMethods_parentedView() {
+        FrameLayout parent = new FrameLayout(mContext);
+        AutofillId initialParentId = new AutofillId(48);
+        parent.setAutofillId(initialParentId);
+
+        View child = new View(mContext);
+        AutofillId initialChildId = new AutofillId(42);
+        child.setAutofillId(initialChildId);
+
+        parent.addView(child);
+
+        ViewStructureImpl structure = new ViewStructureImpl(child);
+        ViewNode node = structure.getNode();
+
+        assertThat(node.getAutofillId()).isEqualTo(initialChildId);
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        AutofillId newChildId = new AutofillId(108);
+        structure.setAutofillId(newChildId);
+        assertThat(node.getAutofillId()).isEqualTo(newChildId);
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        AutofillId newParentId = new AutofillId(15162342);
+        parent.setAutofillId(newParentId);
+        assertThat(node.getAutofillId()).isEqualTo(newChildId);
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        structure.setAutofillId(new AutofillId(66), 6);
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
+        assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
+    }
+
+    @Test
+    public void testAutofillIdMethods_explicitIdsConstructor() {
+        AutofillId initialParentId = new AutofillId(42);
+        ViewStructureImpl structure = new ViewStructureImpl(initialParentId, 108, 666);
+        ViewNode node = structure.getNode();
+
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(initialParentId, 108, 666));
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        AutofillId newChildId = new AutofillId(108);
+        structure.setAutofillId(newChildId);
+        assertThat(node.getAutofillId()).isEqualTo(newChildId);
+        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
+
+        structure.setAutofillId(new AutofillId(66), 6);
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
+        assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
+    }
+
+    @Test
+    public void testInvalidSetters() {
+        View view = new View(mContext);
+        AutofillId initialId = new AutofillId(42);
+        view.setAutofillId(initialId);
+
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        ViewNode node = structure.getNode();
+        assertThat(node.getAutofillId()).isEqualTo(initialId); // sanity check
+
+        assertThrows(NullPointerException.class, () -> structure.setAutofillId(null));
+        assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
+
+        assertThrows(NullPointerException.class, () -> structure.setAutofillId(null, 666));
+        assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
+
+        assertThrows(NullPointerException.class, () -> structure.setTextIdEntry(null));
+        assertThat(node.getTextIdEntry()).isNull();
+    }
+
+    @Test
+    public void testUnsupportedProperties() {
+        View view = new View(mContext);
+
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        ViewNode node = structure.getNode();
+
+        structure.setChildCount(1);
+        assertThat(node.getChildCount()).isEqualTo(0);
+
+        structure.addChildCount(1);
+        assertThat(node.getChildCount()).isEqualTo(0);
+
+        assertThat(structure.newChild(0)).isNull();
+        assertThat(node.getChildCount()).isEqualTo(0);
+
+        assertThat(structure.asyncNewChild(0)).isNull();
+        assertThat(node.getChildCount()).isEqualTo(0);
+
+        structure.asyncCommit();
+        assertThat(node.getChildCount()).isEqualTo(0);
+
+        structure.setWebDomain("Y U NO SET?");
+        assertThat(node.getWebDomain()).isNull();
+
+        assertThat(structure.newHtmlInfoBuilder("WHATEVER")).isNull();
+
+        structure.setHtmlInfo(mHtmlInfoMock);
+        assertThat(node.getHtmlInfo()).isNull();
+
+        structure.setDataIsSensitive(true);
+
+        assertThat(structure.getTempRect()).isNull();
+
+        // Graphic properties
+        structure.setElevation(6.66f);
+        assertThat(node.getElevation()).isWithin(1.0e-10f).of(0f);
+        structure.setAlpha(66.6f);
+        assertThat(node.getAlpha()).isWithin(1.0e-10f).of(1.0f);
+        structure.setTransformation(Matrix.IDENTITY_MATRIX);
+        assertThat(node.getTransformation()).isNull();
+    }
+
+    @Test
+    public void testValidProperties_directly() {
+        ViewStructureImpl structure = newSimpleStructure();
+        assertSimpleStructure(structure);
+        assertSimpleNode(structure.getNode());
+    }
+
+    @Test
+    public void testValidProperties_throughParcel() {
+        ViewStructureImpl structure = newSimpleStructure();
+        final ViewNode node = structure.getNode();
+        assertSimpleNode(node); // sanity check
+
+        final ViewNode clone = cloneThroughParcel(node);
+        assertSimpleNode(clone);
+    }
+
+    @Test
+    public void testComplexText_directly() {
+        ViewStructureImpl structure = newStructureWithComplexText();
+        assertStructureWithComplexText(structure);
+        assertNodeWithComplexText(structure.getNode());
+    }
+
+    @Test
+    public void testComplexText_throughParcel() {
+        ViewStructureImpl structure = newStructureWithComplexText();
+        final ViewNode node = structure.getNode();
+        assertNodeWithComplexText(node); // sanity check
+
+        ViewNode clone = cloneThroughParcel(node);
+        assertNodeWithComplexText(clone);
+    }
+
+    @Test
+    public void testVisibility() {
+        // Visibility is a special case becase it use flag masks, so we want to make sure it works
+        // fine
+        View view = new View(mContext);
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        ViewNode node = structure.getNode();
+
+        structure.setVisibility(View.VISIBLE);
+        assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
+
+        structure.setVisibility(View.GONE);
+        assertThat(node.getVisibility()).isEqualTo(View.GONE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
+
+        structure.setVisibility(View.VISIBLE);
+        assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
+
+        structure.setVisibility(View.INVISIBLE);
+        assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE);
+
+        structure.setVisibility(View.INVISIBLE | View.GONE);
+        assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
+
+
+        final int invalidValue = Math.max(Math.max(View.VISIBLE, View.INVISIBLE), View.GONE) * 2;
+        structure.setVisibility(View.VISIBLE);
+        structure.setVisibility(invalidValue); // should be ignored
+        assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
+
+        structure.setVisibility(View.GONE | invalidValue);
+        assertThat(node.getVisibility()).isEqualTo(View.GONE);
+        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
+    }
+
+    /**
+     * Creates a {@link ViewStructureImpl} that can be asserted through
+     * {@link #assertSimpleNode(ViewNode)}.
+     */
+    private ViewStructureImpl newSimpleStructure() {
+        View view = new View(mContext);
+        view.setAutofillId(new AutofillId(42));
+
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+
+        // Basic properties
+        structure.setText("Text is set!");
+        structure.setClassName("Classy!");
+        structure.setContentDescription("Described I am!");
+        structure.setVisibility(View.INVISIBLE);
+
+        // Autofill properties
+        structure.setAutofillType(View.AUTOFILL_TYPE_TEXT);
+        structure.setAutofillHints(new String[] { "Auto", "Man" });
+        structure.setAutofillOptions(new String[] { "Maybe" });
+        structure.setAutofillValue(AutofillValue.forText("Malkovich"));
+
+        // Extra text properties
+        structure.setMinTextEms(6);
+        structure.setMaxTextLength(66);
+        structure.setMaxTextEms(666);
+        structure.setInputType(42);
+        structure.setTextIdEntry("TEXT, Y U NO ENTRY?");
+        structure.setLocaleList(new LocaleList(Locale.US, Locale.ENGLISH));
+
+        // Resource id
+        structure.setId(16, "package.name", "type.name", "entry.name");
+
+        // Dimensions
+        structure.setDimens(4, 8, 15, 16, 23, 42);
+
+        // Boolean properties
+        structure.setAssistBlocked(true);
+        structure.setEnabled(true);
+        structure.setClickable(true);
+        structure.setLongClickable(true);
+        structure.setContextClickable(true);
+        structure.setFocusable(true);
+        structure.setFocused(true);
+        structure.setAccessibilityFocused(true);
+        structure.setChecked(true);
+        structure.setActivated(true);
+        structure.setOpaque(true);
+
+        // Bundle
+        assertThat(structure.hasExtras()).isFalse();
+        final Bundle bundle = structure.getExtras();
+        assertThat(bundle).isNotNull();
+        bundle.putString("Marlon", "Bundle");
+        assertThat(structure.hasExtras()).isTrue();
+        return structure;
+    }
+
+    /**
+     * Asserts the properties of a {@link ViewNode} that was created by
+     * {@link #newSimpleStructure()}.
+     */
+    private void assertSimpleNode(ViewNode node) {
+
+        // Basic properties
+        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(42));
+        assertThat(node.getParentAutofillId()).isNull();
+        assertThat(node.getText()).isEqualTo("Text is set!");
+        assertThat(node.getClassName()).isEqualTo("Classy!");
+        assertThat(node.getContentDescription().toString()).isEqualTo("Described I am!");
+        assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
+
+        // Autofill properties
+        assertThat(node.getAutofillType()).isEqualTo(View.AUTOFILL_TYPE_TEXT);
+        assertThat(node.getAutofillHints()).asList().containsExactly("Auto", "Man").inOrder();
+        assertThat(node.getAutofillOptions()).asList().containsExactly("Maybe").inOrder();
+        assertThat(node.getAutofillValue().getTextValue()).isEqualTo("Malkovich");
+
+        // Extra text properties
+        assertThat(node.getMinTextEms()).isEqualTo(6);
+        assertThat(node.getMaxTextLength()).isEqualTo(66);
+        assertThat(node.getMaxTextEms()).isEqualTo(666);
+        assertThat(node.getInputType()).isEqualTo(42);
+        assertThat(node.getTextIdEntry()).isEqualTo("TEXT, Y U NO ENTRY?");
+        assertThat(node.getLocaleList()).isEqualTo(new LocaleList(Locale.US, Locale.ENGLISH));
+
+        // Resource id
+        assertThat(node.getId()).isEqualTo(16);
+        assertThat(node.getIdPackage()).isEqualTo("package.name");
+        assertThat(node.getIdType()).isEqualTo("type.name");
+        assertThat(node.getIdEntry()).isEqualTo("entry.name");
+
+        // Dimensions
+        assertThat(node.getLeft()).isEqualTo(4);
+        assertThat(node.getTop()).isEqualTo(8);
+        assertThat(node.getScrollX()).isEqualTo(15);
+        assertThat(node.getScrollY()).isEqualTo(16);
+        assertThat(node.getWidth()).isEqualTo(23);
+        assertThat(node.getHeight()).isEqualTo(42);
+
+        // Boolean properties
+        assertThat(node.isAssistBlocked()).isTrue();
+        assertThat(node.isEnabled()).isTrue();
+        assertThat(node.isClickable()).isTrue();
+        assertThat(node.isLongClickable()).isTrue();
+        assertThat(node.isContextClickable()).isTrue();
+        assertThat(node.isFocusable()).isTrue();
+        assertThat(node.isFocused()).isTrue();
+        assertThat(node.isAccessibilityFocused()).isTrue();
+        assertThat(node.isChecked()).isTrue();
+        assertThat(node.isActivated()).isTrue();
+        assertThat(node.isOpaque()).isTrue();
+
+        // Bundle
+        final Bundle bundle = node.getExtras();
+        assertThat(bundle).isNotNull();
+        assertThat(bundle.size()).isEqualTo(1);
+        assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
+    }
+
+    /**
+     * Asserts the properties of a {@link ViewStructureImpl} that was created by
+     * {@link #newSimpleStructure()}.
+     */
+    private void assertSimpleStructure(ViewStructureImpl structure) {
+        assertThat(structure.getAutofillId()).isEqualTo(new AutofillId(42));
+        assertThat(structure.getText()).isEqualTo("Text is set!");
+
+        // Bundle
+        final Bundle bundle = structure.getExtras();
+        assertThat(bundle.size()).isEqualTo(1);
+        assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
+    }
+
+    /**
+     * Creates a {@link ViewStructureImpl} with "complex" text properties (such as selection); it
+     * can be asserted through {@link #assertNodeWithComplexText(ViewNode)}.
+     */
+    private ViewStructureImpl newStructureWithComplexText() {
+        View view = new View(mContext);
+        ViewStructureImpl structure = new ViewStructureImpl(view);
+        structure.setText("IGNORE ME!");
+        structure.setText("Now we're talking!", 4, 8);
+        structure.setHint("Soylent Green is SPOILER ALERT");
+        structure.setTextStyle(15.0f, 16, 23, 42);
+        structure.setTextLines(new int[] {4,  8, 15} , new int[] {16, 23, 42});
+        return structure;
+    }
+
+    /**
+     * Asserts the properties of a {@link ViewNode} that was created by
+     * {@link #newStructureWithComplexText()}.
+     */
+    private void assertNodeWithComplexText(ViewNode node) {
+        assertThat(node.getText()).isEqualTo("Now we're talking!");
+        assertThat(node.getTextSelectionStart()).isEqualTo(4);
+        assertThat(node.getTextSelectionEnd()).isEqualTo(8);
+        assertThat(node.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
+        assertThat(node.getTextSize()).isWithin(1.0e-10f).of(15.0f);
+        assertThat(node.getTextColor()).isEqualTo(16);
+        assertThat(node.getTextBackgroundColor()).isEqualTo(23);
+        assertThat(node.getTextStyle()).isEqualTo(42);
+        assertThat(node.getTextLineCharOffsets()).asList().containsExactly(4, 8, 15).inOrder();
+        assertThat(node.getTextLineBaselines()).asList().containsExactly(16, 23, 42).inOrder();
+    }
+
+    /**
+     * Asserts the properties of a {@link ViewStructureImpl} that was created by
+     * {@link #newStructureWithComplexText()}.
+     */
+    private void assertStructureWithComplexText(ViewStructureImpl structure) {
+        assertThat(structure.getText()).isEqualTo("Now we're talking!");
+        assertThat(structure.getTextSelectionStart()).isEqualTo(4);
+        assertThat(structure.getTextSelectionEnd()).isEqualTo(8);
+        assertThat(structure.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
+    }
+
+    private ViewNode cloneThroughParcel(ViewNode node) {
+        Parcel parcel = Parcel.obtain();
+
+        try {
+            // Write to parcel
+            parcel.setDataPosition(0); // Sanity / paranoid check
+            ViewNode.writeToParcel(parcel, node, 0);
+
+            // Read from parcel
+            parcel.setDataPosition(0);
+            ViewNode clone = ViewNode.readFromParcel(parcel);
+            assertThat(clone).isNotNull();
+            return clone;
+        } finally {
+            parcel.recycle();
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
index 0fd0136..ace6611 100644
--- a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
@@ -28,11 +28,12 @@
 import android.graphics.Matrix;
 import android.graphics.RectF;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
 import android.view.inputmethod.CursorAnchorInfo.Builder;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
index 1b00e09..f24e232 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -26,9 +26,10 @@
 import android.content.pm.ServiceInfo;
 import android.os.Bundle;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
index 55e5e36..9f259a8 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
@@ -20,11 +20,12 @@
 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 androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
index 8df1848..e2fb46a 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeArrayTest.java
@@ -19,10 +19,11 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
index c76359e..1e0e1235 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodSubtypeTest.java
@@ -23,10 +23,11 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
index 8c96b58..453ad72 100644
--- a/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/SparseRectFArrayTest.java
@@ -23,10 +23,11 @@
 
 import android.graphics.RectF;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
index 657a7fc..ba85d76 100644
--- a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
+++ b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.graphics.Point;
-import android.support.test.filters.MediumTest;
 import android.test.ActivityInstrumentationTestCase;
 import android.util.PollingCheck;
 import android.view.Display;
@@ -26,6 +25,8 @@
 import android.view.WindowManager;
 import android.widget.espresso.ContextMenuUtils;
 
+import androidx.test.filters.MediumTest;
+
 @MediumTest
 public class ContextMenuTest extends ActivityInstrumentationTestCase<ContextMenuActivity> {
 
diff --git a/core/tests/coretests/src/android/view/menu/MenuLayout.java b/core/tests/coretests/src/android/view/menu/MenuLayout.java
index 356c948..33ee515 100644
--- a/core/tests/coretests/src/android/view/menu/MenuLayout.java
+++ b/core/tests/coretests/src/android/view/menu/MenuLayout.java
@@ -16,8 +16,6 @@
 
 package android.view.menu;
 
-import android.view.menu.MenuScenario.Params;
-
 import android.os.Bundle;
 import android.view.Menu;
 import android.widget.Button;
diff --git a/core/tests/coretests/src/android/view/menu/MenuLayoutLandscapeTest.java b/core/tests/coretests/src/android/view/menu/MenuLayoutLandscapeTest.java
index 8ed0d86..ff9f166 100644
--- a/core/tests/coretests/src/android/view/menu/MenuLayoutLandscapeTest.java
+++ b/core/tests/coretests/src/android/view/menu/MenuLayoutLandscapeTest.java
@@ -16,13 +16,10 @@
 
 package android.view.menu;
 
-import android.util.KeyUtils;
-import com.android.internal.view.menu.IconMenuView;
-import com.android.internal.view.menu.MenuBuilder;
-
-import android.content.pm.ActivityInfo;
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase;
+import android.util.KeyUtils;
+
+import androidx.test.filters.LargeTest;
 
 @LargeTest
 public class MenuLayoutLandscapeTest extends ActivityInstrumentationTestCase<MenuLayoutLandscape> {
diff --git a/core/tests/coretests/src/android/view/menu/MenuLayoutPortraitTest.java b/core/tests/coretests/src/android/view/menu/MenuLayoutPortraitTest.java
index ccf1264..360be53 100644
--- a/core/tests/coretests/src/android/view/menu/MenuLayoutPortraitTest.java
+++ b/core/tests/coretests/src/android/view/menu/MenuLayoutPortraitTest.java
@@ -16,11 +16,11 @@
 
 package android.view.menu;
 
-import android.content.pm.ActivityInfo;
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase;
 import android.util.KeyUtils;
 
+import androidx.test.filters.LargeTest;
+
 @LargeTest
 public class MenuLayoutPortraitTest extends ActivityInstrumentationTestCase<MenuLayoutPortrait> {
     private static final String LONG_TITLE = "Really really really really really really really really really really long title";
diff --git a/core/tests/coretests/src/android/view/menu/MenuWith1ItemTest.java b/core/tests/coretests/src/android/view/menu/MenuWith1ItemTest.java
index 82ad858..c18e361 100644
--- a/core/tests/coretests/src/android/view/menu/MenuWith1ItemTest.java
+++ b/core/tests/coretests/src/android/view/menu/MenuWith1ItemTest.java
@@ -16,17 +16,12 @@
 
 package android.view.menu;
 
-import android.view.menu.MenuWith1Item;
-import android.util.KeyUtils;
-import com.android.internal.view.menu.MenuBuilder;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.TouchUtils;
-
 import android.test.ActivityInstrumentationTestCase;
+import android.util.KeyUtils;
 import android.view.KeyEvent;
-import android.view.View;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 public class MenuWith1ItemTest extends ActivityInstrumentationTestCase<MenuWith1Item> {
     private MenuWith1Item mActivity;
diff --git a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
index 4a6c093..780e15a 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
@@ -22,8 +22,9 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.app.Person;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.google.android.textclassifier.ActionsSuggestionsModel;
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
index 0180856..fef6583 100644
--- a/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
+++ b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
@@ -21,6 +21,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -29,9 +30,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.support.test.InstrumentationRegistry;
 
-import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
 
 import com.google.common.base.Preconditions;
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java
index aaadefb..3fc8e4c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/IntentFactoryTest.java
@@ -13,14 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.view.textclassifier;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Intent;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.google.android.textclassifier.AnnotatorModel;
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
index 88d162b..74b8e3b 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.view.textclassifier;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -20,9 +21,10 @@
 import static org.mockito.Mockito.when;
 
 import android.os.LocaleList;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java b/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
index a3c6179..46e3a4c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/SelectionEventTest.java
@@ -19,8 +19,9 @@
 import static org.junit.Assert.assertEquals;
 
 import android.os.Parcel;
-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/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
index 54007fb..9662182 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
@@ -20,8 +20,8 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-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/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index a3f69d9..4fcd51c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -26,9 +26,10 @@
 import android.content.Intent;
 import android.os.LocaleList;
 import android.service.textclassifier.TextClassifierService;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index aaf7312..99c959e 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -32,11 +32,12 @@
 import android.os.Bundle;
 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.View;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index 81ec85e..7009fb2 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -24,11 +24,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.LocaleList;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
 import android.text.Spannable;
 import android.text.SpannableString;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
@@ -368,6 +369,7 @@
         assertThat(textLanguage, isTextLanguage("ja"));
     }
 
+    /* DISABLED: b/122467291
     @Test
     public void testSuggestConversationActions_textReplyOnly_maxThree() {
         if (isTextClassifierDisabled()) return;
@@ -376,10 +378,10 @@
                         ConversationActions.Message.PERSON_USER_REMOTE)
                         .setText("Where are you?")
                         .build();
-        ConversationActions.TypeConfig typeConfig =
-                new ConversationActions.TypeConfig.Builder().includeTypesFromTextClassifier(false)
+        TextClassifier.EntityConfig typeConfig =
+                new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
                         .setIncludedTypes(
-                                Collections.singletonList(ConversationActions.TYPE_TEXT_REPLY))
+                                Collections.singletonList(ConversationAction.TYPE_TEXT_REPLY))
                         .build();
         ConversationActions.Request request =
                 new ConversationActions.Request.Builder(Collections.singletonList(message))
@@ -390,12 +392,12 @@
         ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
         assertTrue(conversationActions.getConversationActions().size() > 0);
         assertTrue(conversationActions.getConversationActions().size() == 1);
-        for (ConversationActions.ConversationAction conversationAction :
+        for (ConversationAction conversationAction :
                 conversationActions.getConversationActions()) {
             assertThat(conversationAction,
-                    isConversationAction(ConversationActions.TYPE_TEXT_REPLY));
+                    isConversationAction(ConversationAction.TYPE_TEXT_REPLY));
         }
-    }
+    }*/
 
     @Test
     public void testSuggestConversationActions_textReplyOnly_noMax() {
@@ -405,10 +407,10 @@
                         ConversationActions.Message.PERSON_USER_REMOTE)
                         .setText("Where are you?")
                         .build();
-        ConversationActions.TypeConfig typeConfig =
-                new ConversationActions.TypeConfig.Builder().includeTypesFromTextClassifier(false)
+        TextClassifier.EntityConfig typeConfig =
+                new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
                         .setIncludedTypes(
-                                Collections.singletonList(ConversationActions.TYPE_TEXT_REPLY))
+                                Collections.singletonList(ConversationAction.TYPE_TEXT_REPLY))
                         .build();
         ConversationActions.Request request =
                 new ConversationActions.Request.Builder(Collections.singletonList(message))
@@ -417,10 +419,10 @@
 
         ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
         assertTrue(conversationActions.getConversationActions().size() > 1);
-        for (ConversationActions.ConversationAction conversationAction :
+        for (ConversationAction conversationAction :
                 conversationActions.getConversationActions()) {
             assertThat(conversationAction,
-                    isConversationAction(ConversationActions.TYPE_TEXT_REPLY));
+                    isConversationAction(ConversationAction.TYPE_TEXT_REPLY));
         }
     }
 
@@ -523,20 +525,19 @@
         };
     }
 
-    private static Matcher<ConversationActions.ConversationAction> isConversationAction(
-            String actionType) {
-        return new BaseMatcher<ConversationActions.ConversationAction>() {
+    private static Matcher<ConversationAction> isConversationAction(String actionType) {
+        return new BaseMatcher<ConversationAction>() {
             @Override
             public boolean matches(Object o) {
-                if (!(o instanceof ConversationActions.ConversationAction)) {
+                if (!(o instanceof ConversationAction)) {
                     return false;
                 }
-                ConversationActions.ConversationAction conversationAction =
-                        (ConversationActions.ConversationAction) o;
+                ConversationAction conversationAction =
+                        (ConversationAction) o;
                 if (!actionType.equals(conversationAction.getType())) {
                     return false;
                 }
-                if (ConversationActions.TYPE_TEXT_REPLY.equals(actionType)) {
+                if (ConversationAction.TYPE_TEXT_REPLY.equals(actionType)) {
                     if (conversationAction.getTextReply() == null) {
                         return false;
                     }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
index 1dcaed6..d0d32e3 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
@@ -21,8 +21,9 @@
 import android.icu.util.ULocale;
 import android.os.Bundle;
 import android.os.Parcel;
-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/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
index f022d04..b9cc8f4 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
@@ -21,10 +21,11 @@
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
index 2ea49f7..30cc4e8 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
@@ -21,8 +21,9 @@
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
-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/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
index 8e4f02c..5e8e582 100644
--- a/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/GenerateLinksLoggerTest.java
@@ -23,13 +23,14 @@
 import static org.mockito.Mockito.mock;
 
 import android.metrics.LogMaker;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 import android.view.textclassifier.GenerateLinksLogger;
 import android.view.textclassifier.TextClassifier;
 import android.view.textclassifier.TextLinks;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
new file mode 100644
index 0000000..b1b7416
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.textclassifier.logging;
+
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_TEXT_SELECTION_SMART_SHARE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.CONVERSATION_ACTIONS;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_ENTITY_TYPE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SELECTION_WIDGET_TYPE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_EVENT_TIME;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.metrics.LogMaker;
+import android.view.textclassifier.ConversationAction;
+import android.view.textclassifier.TextClassificationContext;
+import android.view.textclassifier.TextClassifierEvent;
+import android.view.textclassifier.TextClassifierEventTronLogger;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.logging.MetricsLogger;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TextClassifierEventTronLoggerTest {
+    private static final String WIDGET_TYPE = "notification";
+    private static final String PACKAGE_NAME = "pkg";
+    private static final long EVENT_TIME = System.currentTimeMillis();
+
+
+    @Mock
+    private MetricsLogger mMetricsLogger;
+    private TextClassifierEventTronLogger mTextClassifierEventTronLogger;
+
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mTextClassifierEventTronLogger = new TextClassifierEventTronLogger(mMetricsLogger);
+    }
+
+    @Test
+    public void testWriteEvent() {
+        TextClassificationContext textClassificationContext =
+                new TextClassificationContext.Builder(PACKAGE_NAME, WIDGET_TYPE)
+                        .build();
+        TextClassifierEvent textClassifierEvent =
+                new TextClassifierEvent.Builder(
+                        TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS,
+                        TextClassifierEvent.TYPE_SMART_ACTION)
+                        .setEntityType(ConversationAction.TYPE_CALL_PHONE)
+                        .setEventTime(EVENT_TIME)
+                        .setEventContext(textClassificationContext)
+                        .build();
+
+        mTextClassifierEventTronLogger.writeEvent(textClassifierEvent);
+
+        ArgumentCaptor<LogMaker> captor = ArgumentCaptor.forClass(LogMaker.class);
+        Mockito.verify(mMetricsLogger).write(captor.capture());
+        LogMaker logMaker = captor.getValue();
+        assertThat(logMaker.getCategory()).isEqualTo(
+                CONVERSATION_ACTIONS);
+        assertThat(logMaker.getType()).isEqualTo(
+                ACTION_TEXT_SELECTION_SMART_SHARE);
+        assertThat(logMaker.getTaggedData(FIELD_SELECTION_ENTITY_TYPE))
+                .isEqualTo(ConversationAction.TYPE_CALL_PHONE);
+        assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME))
+                .isEqualTo(EVENT_TIME);
+        assertThat(logMaker.getPackageName()).isEqualTo(PACKAGE_NAME);
+        assertThat(logMaker.getTaggedData(FIELD_SELECTION_WIDGET_TYPE))
+                .isEqualTo(WIDGET_TYPE);
+    }
+
+    @Test
+    public void testWriteEvent_unsupportedCategory() {
+        TextClassifierEvent textClassifierEvent =
+                new TextClassifierEvent.Builder(
+                        TextClassifierEvent.CATEGORY_SELECTION,
+                        TextClassifierEvent.TYPE_SMART_ACTION)
+                        .build();
+
+        mTextClassifierEventTronLogger.writeEvent(textClassifierEvent);
+
+        Mockito.verify(mMetricsLogger, Mockito.never()).write(Mockito.any(LogMaker.class));
+    }
+}
diff --git a/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java b/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java
index 4a1c414..638d894 100644
--- a/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java
+++ b/core/tests/coretests/src/android/view/textservice/SpellCheckerSubtypeTest.java
@@ -16,15 +16,16 @@
 
 package android.view.textservice;
 
+import static android.test.MoreAsserts.assertNotEqual;
+
 import android.os.Parcel;
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import java.util.Arrays;
 import java.util.Locale;
 
-import static android.test.MoreAsserts.assertNotEqual;
-
 /**
  * TODO: Most of part can be, and probably should be, moved to CTS.
  */
diff --git a/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java b/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java
index 4f31c4e..6edc162 100644
--- a/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java
+++ b/core/tests/coretests/src/android/widget/AppWidgetHostViewTest.java
@@ -24,18 +24,14 @@
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.view.ViewGroup.OnHierarchyChangeListener;
 
-import com.android.frameworks.coretests.R;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
-import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Future;
+import com.android.frameworks.coretests.R;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -43,6 +39,11 @@
 import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+
 /**
  * Tests for AppWidgetHostView
  */
diff --git a/core/tests/coretests/src/android/widget/AutoCompleteTextViewCallbacks.java b/core/tests/coretests/src/android/widget/AutoCompleteTextViewCallbacks.java
index 8e73b52..01e82a5 100644
--- a/core/tests/coretests/src/android/widget/AutoCompleteTextViewCallbacks.java
+++ b/core/tests/coretests/src/android/widget/AutoCompleteTextViewCallbacks.java
@@ -18,7 +18,8 @@
 
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.FlakyTest;
+
+import androidx.test.filters.FlakyTest;
 
 // TODO: tests fail intermittently. Add back MediumTest annotation when fixed
 public class AutoCompleteTextViewCallbacks
@@ -32,7 +33,7 @@
 
     /** Test that the initial popup of the suggestions does not select anything.
      */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupNoSelection() throws Exception {
         AutoCompleteTextViewSimple theActivity = getActivity();
         AutoCompleteTextView textView = theActivity.getTextView();
@@ -57,7 +58,7 @@
     }
 
     /** Test that arrow-down into the popup calls the onSelected callback. */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupEnterSelection() throws Exception {
         final AutoCompleteTextViewSimple theActivity = getActivity();
         AutoCompleteTextView textView = theActivity.getTextView();
@@ -106,7 +107,7 @@
     }
 
     /** Test that arrow-up out of the popup calls the onNothingSelected callback */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupLeaveSelection() {
         final AutoCompleteTextViewSimple theActivity = getActivity();
         AutoCompleteTextView textView = theActivity.getTextView();
diff --git a/core/tests/coretests/src/android/widget/AutoCompleteTextViewPopup.java b/core/tests/coretests/src/android/widget/AutoCompleteTextViewPopup.java
index ee0abae..21e4184 100644
--- a/core/tests/coretests/src/android/widget/AutoCompleteTextViewPopup.java
+++ b/core/tests/coretests/src/android/widget/AutoCompleteTextViewPopup.java
@@ -18,8 +18,8 @@
 
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.FlakyTest;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.FlakyTest;
 
 /**
  * A collection of tests on aspects of the AutoCompleteTextView's popup
@@ -41,7 +41,7 @@
     }
 
     /** Test that we can move the selection and it responds as expected */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupSetListSelection() throws Throwable {
         AutoCompleteTextViewSimple theActivity = getActivity();
         final AutoCompleteTextView textView = theActivity.getTextView();
@@ -73,7 +73,7 @@
     }
 
     /** Test that we can look at the selection as we move around */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupGetListSelection() throws Throwable {
         AutoCompleteTextViewSimple theActivity = getActivity();
         final AutoCompleteTextView textView = theActivity.getTextView();
@@ -100,7 +100,7 @@
     }
 
     /** Test that we can clear the selection */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupClearListSelection() throws Throwable {
         AutoCompleteTextViewSimple theActivity = getActivity();
         final AutoCompleteTextView textView = theActivity.getTextView();
@@ -133,7 +133,7 @@
     }
 
     /** Make sure we handle an empty adapter properly */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupNavigateNoAdapter() throws Throwable {
         AutoCompleteTextViewSimple theActivity = getActivity();
         final AutoCompleteTextView textView = theActivity.getTextView();
@@ -167,7 +167,7 @@
     }
 
     /** Test the show/hide behavior of the drop-down. */
-    @FlakyTest(tolerance=3)
+    @FlakyTest
     public void testPopupShow() throws Throwable {
         AutoCompleteTextViewSimple theActivity = getActivity();
         final AutoCompleteTextView textView = theActivity.getTextView();
diff --git a/core/tests/coretests/src/android/widget/AutoCompleteTextViewSimple.java b/core/tests/coretests/src/android/widget/AutoCompleteTextViewSimple.java
index b4e05aa..063bec5 100644
--- a/core/tests/coretests/src/android/widget/AutoCompleteTextViewSimple.java
+++ b/core/tests/coretests/src/android/widget/AutoCompleteTextViewSimple.java
@@ -16,8 +16,6 @@
 
 package android.widget;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.util.Log;
@@ -25,6 +23,8 @@
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemSelectedListener;
 
+import com.android.frameworks.coretests.R;
+
 public class AutoCompleteTextViewSimple extends Activity 
         implements OnItemClickListener, OnItemSelectedListener {
 
diff --git a/core/tests/coretests/src/android/widget/DatePickerActivity.java b/core/tests/coretests/src/android/widget/DatePickerActivity.java
index c3b25a1..9e455b2 100644
--- a/core/tests/coretests/src/android/widget/DatePickerActivity.java
+++ b/core/tests/coretests/src/android/widget/DatePickerActivity.java
@@ -18,6 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/DatePickerFocusTest.java b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
index be85450..f067230 100644
--- a/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
+++ b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
@@ -19,11 +19,12 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.os.SystemClock;
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.KeyEvent;
 import android.view.View;
 
+import androidx.test.filters.LargeTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/DateTimeViewTest.java b/core/tests/coretests/src/android/widget/DateTimeViewTest.java
index 40a6b7a..d0bd4b8 100644
--- a/core/tests/coretests/src/android/widget/DateTimeViewTest.java
+++ b/core/tests/coretests/src/android/widget/DateTimeViewTest.java
@@ -16,10 +16,10 @@
 
 package android.widget;
 
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/widget/EditorCursorTest.java b/core/tests/coretests/src/android/widget/EditorCursorTest.java
index 9186827b..e4f55df 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorTest.java
@@ -31,10 +31,11 @@
 
 import android.app.Activity;
 import android.app.Instrumentation;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/widget/ListViewTest.java b/core/tests/coretests/src/android/widget/ListViewTest.java
index 449b696..254af2a 100644
--- a/core/tests/coretests/src/android/widget/ListViewTest.java
+++ b/core/tests/coretests/src/android/widget/ListViewTest.java
@@ -16,20 +16,19 @@
 
 package android.widget;
 
-import android.test.suitebuilder.annotation.Suppress;
-import com.google.android.collect.Lists;
-
-import junit.framework.Assert;
-
 import android.content.Context;
 import android.content.res.Resources;
 import android.test.InstrumentationTestCase;
 import android.test.mock.MockContext;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import com.google.android.collect.Lists;
+
+import junit.framework.Assert;
 
 import java.util.List;
 
diff --git a/core/tests/coretests/src/android/widget/RadioGroupActivity.java b/core/tests/coretests/src/android/widget/RadioGroupActivity.java
index c87aa3a..dd3b30a 100644
--- a/core/tests/coretests/src/android/widget/RadioGroupActivity.java
+++ b/core/tests/coretests/src/android/widget/RadioGroupActivity.java
@@ -17,11 +17,11 @@
 
 package android.widget;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 public class RadioGroupActivity extends Activity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/core/tests/coretests/src/android/widget/RadioGroupPreCheckedTest.java b/core/tests/coretests/src/android/widget/RadioGroupPreCheckedTest.java
index 1ab3628..18c1ea1 100644
--- a/core/tests/coretests/src/android/widget/RadioGroupPreCheckedTest.java
+++ b/core/tests/coretests/src/android/widget/RadioGroupPreCheckedTest.java
@@ -16,12 +16,13 @@
 
 package android.widget;
 
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercises {@link android.widget.RadioGroup}'s check feature.
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java b/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
index 06b860a..da53f6d 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
@@ -38,11 +38,12 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.R;
 import com.android.internal.widget.IRemoteViewsFactory;
 
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index 36792bb..8cb7e1b 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -32,12 +32,13 @@
 import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java b/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java
index 2add221..74aad9a 100644
--- a/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java
+++ b/core/tests/coretests/src/android/widget/SelectionActionModeHelperTest.java
@@ -22,7 +22,8 @@
 
 import android.graphics.PointF;
 import android.graphics.RectF;
-import android.support.test.filters.LargeTest;
+
+import androidx.test.filters.LargeTest;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java b/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
index 1731c08..a79b30d 100644
--- a/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
+++ b/core/tests/coretests/src/android/widget/SimpleCursorAdapterTest.java
@@ -16,14 +16,15 @@
 
 package android.widget;
 
-import android.test.suitebuilder.annotation.Suppress;
-import com.google.android.collect.Lists;
-
 import android.content.Context;
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.Suppress;
+
+import com.google.android.collect.Lists;
 
 import java.util.ArrayList;
 import java.util.Random;
diff --git a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
index eafe427..483270e 100644
--- a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
+++ b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
@@ -36,13 +36,13 @@
 import static android.widget.espresso.SuggestionsPopupwindowUtils.onSuggestionsPopup;
 import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
 import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
+
 import static org.hamcrest.Matchers.is;
+
 import android.content.res.TypedArray;
 import android.support.test.espresso.NoMatchingViewException;
 import android.support.test.espresso.ViewAssertion;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.Spanned;
@@ -51,6 +51,8 @@
 import android.text.style.TextAppearanceSpan;
 import android.view.View;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
index ff4a7da..41fa08b 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
@@ -43,14 +43,15 @@
 import static android.widget.espresso.TextViewAssertions.hasSelection;
 
 import android.app.Activity;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.Suppress;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.MotionEvent;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textclassifier.TextClassifier;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 90758ba..9d93421 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -27,10 +27,8 @@
 import static android.support.test.espresso.matcher.ViewMatchers.withText;
 import static android.widget.espresso.CustomViewActions.longPressAtRelativeCoordinates;
 import static android.widget.espresso.DragHandleUtils.onHandleView;
-import static android.widget.espresso.FloatingToolbarEspressoUtils
-        .assertFloatingToolbarContainsItem;
-import static android.widget.espresso.FloatingToolbarEspressoUtils
-        .assertFloatingToolbarDoesNotContainItem;
+import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarContainsItem;
+import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarDoesNotContainItem;
 import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed;
 import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarItemIndex;
 import static android.widget.espresso.FloatingToolbarEspressoUtils.clickFloatingToolbarItem;
@@ -62,13 +60,8 @@
 import android.app.Instrumentation;
 import android.content.ClipData;
 import android.content.ClipboardManager;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.espresso.action.EspressoKey;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.support.test.uiautomator.UiDevice;
-import android.test.suitebuilder.annotation.Suppress;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.Spannable;
@@ -85,6 +78,12 @@
 import android.view.textclassifier.TextLinksParams;
 import android.widget.espresso.CustomViewActions.RelativeCoordinatesProvider;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/android/widget/TextViewFallbackLineSpacingTest.java b/core/tests/coretests/src/android/widget/TextViewFallbackLineSpacingTest.java
index e9d1d3e..113db9d 100644
--- a/core/tests/coretests/src/android/widget/TextViewFallbackLineSpacingTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewFallbackLineSpacingTest.java
@@ -21,8 +21,6 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
 import android.text.DynamicLayout;
 import android.text.FontFallbackSetup;
 import android.text.Layout;
@@ -31,6 +29,9 @@
 import android.view.View;
 import android.widget.TextView.BufferType;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/widget/TextViewPerformanceTest.java b/core/tests/coretests/src/android/widget/TextViewPerformanceTest.java
index cf173fb..a769ea4 100644
--- a/core/tests/coretests/src/android/widget/TextViewPerformanceTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewPerformanceTest.java
@@ -20,14 +20,15 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.SpannedString;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 1c5610b..585360f 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -27,11 +27,6 @@
 import android.content.Intent;
 import android.graphics.Paint;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.GetChars;
 import android.text.Layout;
 import android.text.PrecomputedText;
@@ -40,6 +35,12 @@
 import android.view.View;
 import android.widget.TextView.BufferType;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java b/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java
index 75da6fe..85a4509 100644
--- a/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java
+++ b/core/tests/coretests/src/android/widget/focus/AdjacentVerticalRectLists.java
@@ -16,12 +16,11 @@
 
 package android.widget.focus;
 
-import android.util.InternalSelectionView;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.widget.LinearLayout;
+import android.util.InternalSelectionView;
 import android.view.ViewGroup;
+import android.widget.LinearLayout;
 
 /**
  * {@link android.view.FocusFinder#findNextFocus(android.view.ViewGroup, android.view.View, int)}
diff --git a/core/tests/coretests/src/android/widget/focus/DescendantFocusability.java b/core/tests/coretests/src/android/widget/focus/DescendantFocusability.java
index f6b0520..fe6d3c8 100644
--- a/core/tests/coretests/src/android/widget/focus/DescendantFocusability.java
+++ b/core/tests/coretests/src/android/widget/focus/DescendantFocusability.java
@@ -16,13 +16,13 @@
 
 package android.widget.focus;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.ViewGroup;
 import android.widget.Button;
 
+import com.android.frameworks.coretests.R;
+
 public class DescendantFocusability extends Activity {
 
     public ViewGroup beforeDescendants;
diff --git a/core/tests/coretests/src/android/widget/focus/DescendantFocusabilityTest.java b/core/tests/coretests/src/android/widget/focus/DescendantFocusabilityTest.java
index 2af42ac..1c570df 100644
--- a/core/tests/coretests/src/android/widget/focus/DescendantFocusabilityTest.java
+++ b/core/tests/coretests/src/android/widget/focus/DescendantFocusabilityTest.java
@@ -16,15 +16,14 @@
 
 package android.widget.focus;
 
-import android.widget.focus.DescendantFocusability;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.UiThreadTest;
 import android.test.TouchUtils;
 import android.view.ViewGroup;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class DescendantFocusabilityTest extends ActivityInstrumentationTestCase<DescendantFocusability> {
 
     private DescendantFocusability a;
diff --git a/core/tests/coretests/src/android/widget/focus/FocusAfterRemoval.java b/core/tests/coretests/src/android/widget/focus/FocusAfterRemoval.java
index b3d5ec5..0cb80ce 100644
--- a/core/tests/coretests/src/android/widget/focus/FocusAfterRemoval.java
+++ b/core/tests/coretests/src/android/widget/focus/FocusAfterRemoval.java
@@ -16,13 +16,13 @@
 
 package android.widget.focus;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.widget.LinearLayout;
-import android.widget.Button;
 import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Exercises cases where elements of the UI are removed (and
diff --git a/core/tests/coretests/src/android/widget/focus/FocusAfterRemovalTest.java b/core/tests/coretests/src/android/widget/focus/FocusAfterRemovalTest.java
index a1b7bcb..6c46d08 100644
--- a/core/tests/coretests/src/android/widget/focus/FocusAfterRemovalTest.java
+++ b/core/tests/coretests/src/android/widget/focus/FocusAfterRemovalTest.java
@@ -16,15 +16,15 @@
 
 package android.widget.focus;
 
-import android.widget.focus.FocusAfterRemoval;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.Button;
-import android.widget.LinearLayout;
 import android.view.KeyEvent;
 import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * {@link FocusAfterRemoval} is set up to exercise cases where the views that
diff --git a/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java b/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java
index 8f8f184..26dc233 100644
--- a/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java
+++ b/core/tests/coretests/src/android/widget/focus/FocusChangeWithInterestingRectHintTest.java
@@ -16,14 +16,13 @@
 
 package android.widget.focus;
 
-import android.widget.focus.AdjacentVerticalRectLists;
-import android.util.InternalSelectionView;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.util.InternalSelectionView;
 import android.view.KeyEvent;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * {@link android.view.FocusFinder#findNextFocus(android.view.ViewGroup, android.view.View, int)}
  * and
diff --git a/core/tests/coretests/src/android/widget/focus/GoneParentFocusedChildTest.java b/core/tests/coretests/src/android/widget/focus/GoneParentFocusedChildTest.java
index dcbddef..b7974e3 100644
--- a/core/tests/coretests/src/android/widget/focus/GoneParentFocusedChildTest.java
+++ b/core/tests/coretests/src/android/widget/focus/GoneParentFocusedChildTest.java
@@ -17,10 +17,10 @@
 package android.widget.focus;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.view.View;
-import android.widget.focus.GoneParentFocusedChild;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * When a parent is GONE, key events shouldn't go to its children, even if they
diff --git a/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearch.java b/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearch.java
index 11cac1e..aab9119 100644
--- a/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearch.java
+++ b/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearch.java
@@ -17,12 +17,12 @@
 package android.widget.focus;
 
 import android.app.Activity;
-import android.widget.LinearLayout;
-import android.widget.Button;
-import android.widget.TextView;
+import android.content.Context;
 import android.os.Bundle;
 import android.view.ViewGroup;
-import android.content.Context;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
 
 public class HorizontalFocusSearch extends Activity {
 
diff --git a/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearchTest.java b/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearchTest.java
index 43986ee..855a3219 100644
--- a/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearchTest.java
+++ b/core/tests/coretests/src/android/widget/focus/HorizontalFocusSearchTest.java
@@ -16,18 +16,17 @@
 
 package android.widget.focus;
 
-import android.widget.focus.HorizontalFocusSearch;
-
-import android.support.test.filters.LargeTest;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.LinearLayout;
-import android.widget.Button;
-import android.view.View;
-
 import static android.widget.focus.VerticalFocusSearchTest.FocusSearchAlg;
 import static android.widget.focus.VerticalFocusSearchTest.NewFocusSearchAlg;
 
+import android.test.ActivityInstrumentationTestCase;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
+
 /**
  * Tests that focus searching works on a horizontal linear layout of buttons of
  * various widths and vertical placements.
diff --git a/core/tests/coretests/src/android/widget/focus/LinearLayoutGrid.java b/core/tests/coretests/src/android/widget/focus/LinearLayoutGrid.java
index acd632f..ec234bc 100644
--- a/core/tests/coretests/src/android/widget/focus/LinearLayoutGrid.java
+++ b/core/tests/coretests/src/android/widget/focus/LinearLayoutGrid.java
@@ -21,6 +21,7 @@
 import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.LinearLayout;
+
 import com.android.frameworks.coretests.R;
 
 public class LinearLayoutGrid extends Activity {
diff --git a/core/tests/coretests/src/android/widget/focus/LinearLayoutGridTest.java b/core/tests/coretests/src/android/widget/focus/LinearLayoutGridTest.java
index 89cb8bb..c81317c 100644
--- a/core/tests/coretests/src/android/widget/focus/LinearLayoutGridTest.java
+++ b/core/tests/coretests/src/android/widget/focus/LinearLayoutGridTest.java
@@ -17,11 +17,11 @@
 package android.widget.focus;
 
 import android.test.SingleLaunchActivityTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.FocusFinder;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.focus.LinearLayoutGrid;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * Tests focus searching between buttons within a grid that are touching, for example,
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfButtons.java b/core/tests/coretests/src/android/widget/focus/ListOfButtons.java
index 308861d..5663ed2 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfButtons.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfButtons.java
@@ -16,8 +16,6 @@
 
 package android.widget.focus;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.ListActivity;
 import android.content.Context;
 import android.os.Bundle;
@@ -26,6 +24,8 @@
 import android.widget.ArrayAdapter;
 import android.widget.Button;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * A layout with a ListView containing buttons.
  */
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java b/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
index bec6f80..4cf4a3a 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfButtonsTest.java
@@ -16,17 +16,17 @@
 
 package android.widget.focus;
 
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.focus.ListOfButtons;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListAdapter;
-import android.widget.Button;
-import android.widget.ListView;
 import android.view.KeyEvent;
 import android.view.View;
+import android.widget.Button;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * Tests that focus works as expected when navigating into and out of
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java b/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java
index c2e7a26..936c999 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java
@@ -21,7 +21,12 @@
 import android.os.Bundle;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.*;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+
 import com.google.android.collect.Lists;
 
 import java.util.List;
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
index 53b866c..73e4ea8 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
@@ -19,11 +19,11 @@
 import android.app.Activity;
 import android.graphics.Point;
 import android.os.Bundle;
+import android.util.InternalSelectionView;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
 import android.widget.ListView;
-import android.util.InternalSelectionView;
 
 /**
  * A list of {@link InternalSelectionView}s paramatarized by the number of items,
diff --git a/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabels.java b/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabels.java
index b908201..8accf21 100644
--- a/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabels.java
+++ b/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabels.java
@@ -27,9 +27,10 @@
 import android.widget.Button;
 import android.widget.TextView;
 
-import com.google.android.collect.Lists;
 import com.android.frameworks.coretests.R;
 
+import com.google.android.collect.Lists;
+
 import java.util.List;
 
 public class ListWithFooterViewAndNewLabels extends ListActivity {
diff --git a/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabelsTest.java b/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabelsTest.java
index 57dbb78..d0fcde5 100644
--- a/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabelsTest.java
+++ b/core/tests/coretests/src/android/widget/focus/ListWithFooterViewAndNewLabelsTest.java
@@ -16,14 +16,13 @@
 
 package android.widget.focus;
 
-import android.widget.focus.ListWithFooterViewAndNewLabels;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
 import android.widget.Button;
 import android.widget.ListAdapter;
 import android.widget.ListView;
 
+import com.android.frameworks.coretests.R;
+
 public class ListWithFooterViewAndNewLabelsTest
         extends ActivityInstrumentationTestCase<ListWithFooterViewAndNewLabels> {
 
diff --git a/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java b/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
index 5c891f9..50a8614 100644
--- a/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
+++ b/core/tests/coretests/src/android/widget/focus/ListWithMailMessages.java
@@ -16,19 +16,20 @@
 
 package android.widget.focus;
 
-import com.android.frameworks.coretests.R;
-import com.google.android.collect.Lists;
-
 import android.app.ListActivity;
+import android.content.Context;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
 import android.widget.ArrayAdapter;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
-import android.webkit.WebView;
+
+import com.android.frameworks.coretests.R;
+
+import com.google.android.collect.Lists;
 
 import java.util.List;
 
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocus.java b/core/tests/coretests/src/android/widget/focus/RequestFocus.java
index 4daf0b4..5042efd 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocus.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocus.java
@@ -16,13 +16,13 @@
 
 package android.widget.focus;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.os.Handler;
 import android.widget.Button;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercises cases where elements of the UI are requestFocus()ed.
  */
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
index cdfa217..bc770c5 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
@@ -21,16 +21,18 @@
 
 import android.os.Handler;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.AndroidRuntimeException;
 import android.view.View;
 import android.view.View.OnFocusChangeListener;
 import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
 import android.widget.Button;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
+
 import org.mockito.InOrder;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java b/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
index 06cb75d..e6e76cc 100644
--- a/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
+++ b/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
@@ -18,12 +18,12 @@
 
 import android.graphics.Rect;
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.InternalSelectionView;
 import android.view.KeyEvent;
 import android.widget.ListView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 /**
  * TODO: extract base test case that launches {@link ListOfInternalSelectionViews} with
diff --git a/core/tests/coretests/src/android/widget/focus/VerticalFocusSearch.java b/core/tests/coretests/src/android/widget/focus/VerticalFocusSearch.java
index 4a809e0..2ca9f6d 100644
--- a/core/tests/coretests/src/android/widget/focus/VerticalFocusSearch.java
+++ b/core/tests/coretests/src/android/widget/focus/VerticalFocusSearch.java
@@ -17,13 +17,13 @@
 package android.widget.focus;
 
 import android.app.Activity;
+import android.content.Context;
 import android.os.Bundle;
-import android.widget.LinearLayout;
-import android.widget.Button;
-import android.widget.TextView;
 import android.view.Gravity;
 import android.view.ViewGroup;
-import android.content.Context;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
 
 /**
  * Holds a few buttons of various sizes and horizontal placements in a
diff --git a/core/tests/coretests/src/android/widget/focus/VerticalFocusSearchTest.java b/core/tests/coretests/src/android/widget/focus/VerticalFocusSearchTest.java
index f01422e..319756c 100644
--- a/core/tests/coretests/src/android/widget/focus/VerticalFocusSearchTest.java
+++ b/core/tests/coretests/src/android/widget/focus/VerticalFocusSearchTest.java
@@ -16,17 +16,16 @@
 
 package android.widget.focus;
 
-import android.widget.focus.VerticalFocusSearch;
-
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.FocusFinder;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.LinearLayout;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.Suppress;
+
 /**
  * Tests that focus searching works on a vertical linear layout of buttons of
  * various widths and horizontal placements.
diff --git a/core/tests/coretests/src/android/widget/gridview/GridDelete.java b/core/tests/coretests/src/android/widget/gridview/GridDelete.java
index 57ae8f39..b040f69 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridDelete.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridDelete.java
@@ -16,6 +16,7 @@
 
 package android.widget.gridview;
 
+import android.util.GridScenario;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -23,8 +24,6 @@
 import android.widget.GridView;
 import android.widget.ListAdapter;
 
-import android.util.GridScenario;
-
 import java.util.ArrayList;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/gridview/GridInHorizontalTest.java b/core/tests/coretests/src/android/widget/gridview/GridInHorizontalTest.java
index 21ca655..5247009 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridInHorizontalTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridInHorizontalTest.java
@@ -17,10 +17,9 @@
 package android.widget.gridview;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.GridView;
 
-import android.widget.gridview.GridInHorizontal;
+import androidx.test.filters.MediumTest;
 
 public class GridInHorizontalTest extends ActivityInstrumentationTestCase<GridInHorizontal> {
 
diff --git a/core/tests/coretests/src/android/widget/gridview/GridInVerticalTest.java b/core/tests/coretests/src/android/widget/gridview/GridInVerticalTest.java
index a674db2..290f70e 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridInVerticalTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridInVerticalTest.java
@@ -17,10 +17,9 @@
 package android.widget.gridview;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.GridView;
 
-import android.widget.gridview.GridInVertical;
+import androidx.test.filters.MediumTest;
 
 public class GridInVerticalTest extends ActivityInstrumentationTestCase<GridInVertical> {
 
diff --git a/core/tests/coretests/src/android/widget/gridview/GridPaddingTest.java b/core/tests/coretests/src/android/widget/gridview/GridPaddingTest.java
index ecd4b1c..d2ae7cf 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridPaddingTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridPaddingTest.java
@@ -17,9 +17,10 @@
 package android.widget.gridview;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.GridView;
 
+import androidx.test.filters.MediumTest;
+
 public class GridPaddingTest extends ActivityInstrumentationTestCase2<GridPadding> {
     private GridView mGridView;
 
diff --git a/core/tests/coretests/src/android/widget/gridview/GridScrollListenerTest.java b/core/tests/coretests/src/android/widget/gridview/GridScrollListenerTest.java
index 53eeb48..466c55f 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridScrollListenerTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridScrollListenerTest.java
@@ -19,12 +19,13 @@
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.AbsListView;
 import android.widget.GridView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class GridScrollListenerTest extends ActivityInstrumentationTestCase<GridScrollListener> implements
         AbsListView.OnScrollListener {
     private GridScrollListener mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java
index 0e362b6..db4f2dc 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionBaseTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.gridview;
 
-import android.util.GridScenario;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
+import android.util.GridScenario;
 import android.widget.GridView;
 
+import androidx.test.filters.MediumTest;
+
 public class GridSetSelectionBaseTest<T extends GridScenario> extends ActivityInstrumentationTestCase<T> {
     private T mActivity;
     private GridView mGridView;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionManyTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionManyTest.java
index 6739645..17a6044 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionManyTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionManyTest.java
@@ -16,8 +16,6 @@
 
 package android.widget.gridview;
 
-import android.widget.gridview.GridSetSelectionMany;
-
 public class GridSetSelectionManyTest extends GridSetSelectionBaseTest<GridSetSelectionMany> {
     public GridSetSelectionManyTest() {
         super(GridSetSelectionMany.class);
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomManyTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomManyTest.java
index 46922b9..a71f732 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomManyTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomManyTest.java
@@ -16,8 +16,6 @@
 
 package android.widget.gridview;
 
-import android.widget.gridview.GridSetSelectionStackFromBottomMany;
-
 public class GridSetSelectionStackFromBottomManyTest extends GridSetSelectionBaseTest<GridSetSelectionStackFromBottomMany> {
     public GridSetSelectionStackFromBottomManyTest() {
         super(GridSetSelectionStackFromBottomMany.class);
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomTest.java
index 67dd6f1..4e6e8aa 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionStackFromBottomTest.java
@@ -16,8 +16,6 @@
 
 package android.widget.gridview;
 
-import android.widget.gridview.GridSetSelectionStackFromBottom;
-
 public class GridSetSelectionStackFromBottomTest extends GridSetSelectionBaseTest<GridSetSelectionStackFromBottom> {
     public GridSetSelectionStackFromBottomTest() {
         super(GridSetSelectionStackFromBottom.class);
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionTest.java b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionTest.java
index 2127b3c..68802fe 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSetSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSetSelectionTest.java
@@ -16,8 +16,6 @@
 
 package android.widget.gridview;
 
-import android.widget.gridview.GridSetSelection;
-
 public class GridSetSelectionTest extends GridSetSelectionBaseTest<GridSetSelection> {
     public GridSetSelectionTest() {
         super(GridSetSelection.class);
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSimple.java b/core/tests/coretests/src/android/widget/gridview/GridSimple.java
index 7c2c696..67bb751 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSimple.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSimple.java
@@ -18,12 +18,11 @@
 
 import android.graphics.drawable.PaintDrawable;
 import android.os.Bundle;
+import android.util.GridScenario;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
-import android.util.GridScenario;
-
 public class GridSimple extends GridScenario {
     @Override
     protected void init(Params params) {
diff --git a/core/tests/coretests/src/android/widget/gridview/GridSingleColumnTest.java b/core/tests/coretests/src/android/widget/gridview/GridSingleColumnTest.java
index 3b2504e..0f67522 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridSingleColumnTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridSingleColumnTest.java
@@ -17,10 +17,9 @@
 package android.widget.gridview;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.GridView;
 
-import android.widget.gridview.GridSingleColumn;
+import androidx.test.filters.MediumTest;
 
 public class GridSingleColumnTest extends ActivityInstrumentationTestCase<GridSingleColumn> {
     private GridSingleColumn mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomManyTest.java b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomManyTest.java
index 640737e..a369616 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomManyTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomManyTest.java
@@ -16,11 +16,10 @@
 
 package android.widget.gridview;
 
-import android.widget.gridview.GridStackFromBottomMany;
-
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.GridView;
 import android.test.ActivityInstrumentationTestCase;
+import android.widget.GridView;
+
+import androidx.test.filters.MediumTest;
 
 public class GridStackFromBottomManyTest extends ActivityInstrumentationTestCase<GridStackFromBottomMany> {
     private GridStackFromBottomMany mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomTest.java
index 8fec241..da1b638 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridStackFromBottomTest.java
@@ -16,12 +16,11 @@
 
 package android.widget.gridview;
 
-import android.widget.gridview.GridStackFromBottom;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.GridView;
 
+import androidx.test.filters.MediumTest;
+
 public class GridStackFromBottomTest extends ActivityInstrumentationTestCase<GridStackFromBottom> {
     private GridStackFromBottom mActivity;
     private GridView mGridView;
diff --git a/core/tests/coretests/src/android/widget/gridview/GridThrasher.java b/core/tests/coretests/src/android/widget/gridview/GridThrasher.java
index ad89bb6..34c19c3 100644
--- a/core/tests/coretests/src/android/widget/gridview/GridThrasher.java
+++ b/core/tests/coretests/src/android/widget/gridview/GridThrasher.java
@@ -16,20 +16,20 @@
 
 package android.widget.gridview;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.LayoutInflater;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.GridView;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 import java.util.Random;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchSetSelectionTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchSetSelectionTest.java
index ca789af..ab5fcfa 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchSetSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchSetSelectionTest.java
@@ -17,14 +17,14 @@
 package android.widget.gridview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.View;
 import android.widget.GridView;
-
 import android.widget.gridview.GridSimple;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * Tests setting the selection in touch mode
  */
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomManyTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomManyTest.java
index 9a8d307..e312873 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomManyTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomManyTest.java
@@ -16,14 +16,14 @@
 
 package android.widget.gridview.touch;
 
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ActivityInstrumentationTestCase;
 import android.test.TouchUtils;
+import android.view.View;
+import android.widget.GridView;
 import android.widget.gridview.GridStackFromBottomMany;
 
-import android.widget.GridView;
-import android.view.View;
-import android.test.ActivityInstrumentationTestCase;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 public class GridTouchStackFromBottomManyTest extends ActivityInstrumentationTestCase<GridStackFromBottomMany> {
     private GridStackFromBottomMany mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomTest.java
index d8d4e43..c98c10a 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchStackFromBottomTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.gridview.touch;
 
-import android.widget.gridview.GridStackFromBottom;
-import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.MediumTest;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.widget.GridView;
+import android.test.TouchUtils;
 import android.view.View;
+import android.widget.GridView;
+import android.widget.gridview.GridStackFromBottom;
+
+import androidx.test.filters.MediumTest;
 
 public class GridTouchStackFromBottomTest extends ActivityInstrumentationTestCase<GridStackFromBottom> {
     private GridStackFromBottom mActivity;
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
index 55a66d9..0d3092c 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
@@ -18,16 +18,16 @@
 
 import android.content.Context;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.GridView;
-
 import android.widget.gridview.GridVerticalSpacingStackFromBottom;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class GridTouchVerticalSpacingStackFromBottomTest extends ActivityInstrumentationTestCase<GridVerticalSpacingStackFromBottom> {
     private GridVerticalSpacingStackFromBottom mActivity;
     private GridView mGridView;
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingTest.java
index bae4ee7..e831e62 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingTest.java
@@ -17,16 +17,16 @@
 package android.widget.gridview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.GridView;
-
 import android.widget.gridview.GridVerticalSpacing;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class GridTouchVerticalSpacingTest extends ActivityInstrumentationTestCase<GridVerticalSpacing> {
     private GridVerticalSpacing mActivity;
     private GridView mGridView;
diff --git a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravity.java b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravity.java
index 9791e36..d159be8 100644
--- a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravity.java
+++ b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravity.java
@@ -16,11 +16,10 @@
 
 package android.widget.layout.frame;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class FrameLayoutGravity extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravityTest.java b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravityTest.java
index fe4e932..0cab660 100644
--- a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravityTest.java
+++ b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutGravityTest.java
@@ -16,12 +16,13 @@
 
 package android.widget.layout.frame;
 
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.ViewAsserts;
 import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.ViewAsserts;
 import android.view.View;
-import android.widget.layout.frame.FrameLayoutGravity;
+
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 public class FrameLayoutGravityTest extends ActivityInstrumentationTestCase<FrameLayoutGravity> {
diff --git a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMargin.java b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMargin.java
index 81b3ea1..8c54557 100644
--- a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMargin.java
+++ b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMargin.java
@@ -16,11 +16,10 @@
 
 package android.widget.layout.frame;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class FrameLayoutMargin extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMarginTest.java b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMarginTest.java
index c052d65..4973078 100644
--- a/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMarginTest.java
+++ b/core/tests/coretests/src/android/widget/layout/frame/FrameLayoutMarginTest.java
@@ -16,13 +16,14 @@
 
 package android.widget.layout.frame;
 
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.ViewAsserts;
 import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.ViewAsserts;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.layout.frame.FrameLayoutMargin;
+
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 public class FrameLayoutMarginTest extends ActivityInstrumentationTestCase<FrameLayoutMargin> {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravity.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravity.java
index 766dd0a..79a34e5 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravity.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravity.java
@@ -16,11 +16,10 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class BaselineAlignmentCenterGravity extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravityTest.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravityTest.java
index 079e9d0..60b7c2f 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravityTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentCenterGravityTest.java
@@ -18,13 +18,13 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
 import android.view.View;
 import android.widget.Button;
 
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.BaselineAlignmentCenterGravity;
 
 public class BaselineAlignmentCenterGravityTest extends ActivityInstrumentationTestCase<BaselineAlignmentCenterGravity> {
     private Button mButton1;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentSpinnerButton.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentSpinnerButton.java
index c3bfe3a..a429b75 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentSpinnerButton.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentSpinnerButton.java
@@ -18,12 +18,12 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.HorizontalOrientationVerticalAlignment;
 
 public class BaselineAlignmentSpinnerButton extends ActivityInstrumentationTestCase<HorizontalOrientationVerticalAlignment> {
     private View mSpinner;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeight.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeight.java
index 5ed5e71..f33feb0 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeight.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeight.java
@@ -16,12 +16,12 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.View;
 
+import com.android.frameworks.coretests.R;
+
 public class BaselineAlignmentZeroWidthAndWeight extends Activity {
     @Override
     protected void onCreate(Bundle icicle) {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java
index 2dd2bb8..443b0f7 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java
@@ -16,16 +16,15 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.BaselineAlignmentZeroWidthAndWeight;
-import android.widget.layout.linear.ExceptionTextView;
-
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.Button;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 public class BaselineAlignmentZeroWidthAndWeightTest extends ActivityInstrumentationTestCase<BaselineAlignmentZeroWidthAndWeight> {
     private Button mShowButton;
 
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineButtons.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineButtons.java
index c9ad831..9d91316 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineButtons.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineButtons.java
@@ -16,11 +16,10 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class BaselineButtons extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/widget/layout/linear/BaselineButtonsTest.java b/core/tests/coretests/src/android/widget/layout/linear/BaselineButtonsTest.java
index 6f1fc90..ac3c5d8 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/BaselineButtonsTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/BaselineButtonsTest.java
@@ -18,12 +18,12 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 import android.widget.ImageButton;
 
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.BaselineButtons;
 
 public class BaselineButtonsTest extends ActivityInstrumentationTestCase<BaselineButtons> {
     private View mCurrentTime;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java b/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java
index 6129b5b..c684501 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/ExceptionTextView.java
@@ -21,7 +21,6 @@
 import android.util.AttributeSet;
 import android.widget.EditText;
 
-
 /**
  * A special EditText that sets {@link #isFailed()} to true as its internal makeNewLayout() method is called
  * with a width lower than 0. This is used to fail the unit test in
diff --git a/core/tests/coretests/src/android/widget/layout/linear/FillInWrap.java b/core/tests/coretests/src/android/widget/layout/linear/FillInWrap.java
index 50aa5b7..c8a5f34 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/FillInWrap.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/FillInWrap.java
@@ -16,12 +16,12 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 public class FillInWrap extends Activity {
     @Override
     protected void onCreate(Bundle icicle) {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/FillInWrapTest.java b/core/tests/coretests/src/android/widget/layout/linear/FillInWrapTest.java
index f161802..0e69efc 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/FillInWrapTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/FillInWrapTest.java
@@ -18,9 +18,10 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
 
 public class FillInWrapTest extends ActivityInstrumentationTestCase<FillInWrap> {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/HorizontalOrientationVerticalAlignment.java b/core/tests/coretests/src/android/widget/layout/linear/HorizontalOrientationVerticalAlignment.java
index 9f937a9..255f7b3 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/HorizontalOrientationVerticalAlignment.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/HorizontalOrientationVerticalAlignment.java
@@ -16,11 +16,10 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class HorizontalOrientationVerticalAlignment extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LLEditTextThenButton.java b/core/tests/coretests/src/android/widget/layout/linear/LLEditTextThenButton.java
index 83331ca..a0745dd 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LLEditTextThenButton.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LLEditTextThenButton.java
@@ -16,14 +16,14 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.LinearLayout;
 
+import com.android.frameworks.coretests.R;
+
 public class LLEditTextThenButton extends Activity {
     private EditText mEditText;
     private Button mButton;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons1.java b/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons1.java
index ab2f060..1153062 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons1.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons1.java
@@ -18,10 +18,10 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.view.View;
 import android.widget.Button;
 import android.widget.LinearLayout;
+
 import com.android.frameworks.coretests.R;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons2.java b/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons2.java
index 77f564d..0aca699 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons2.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LLOfButtons2.java
@@ -22,5 +22,4 @@
  */
 public class LLOfButtons2  extends LLOfButtons1 {
 
-
 }
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTexts.java b/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTexts.java
index 90db788..5d37245 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTexts.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTexts.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 public class LinearLayoutEditTexts extends Activity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTextsTest.java b/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTextsTest.java
index d5998b7..966ed6d 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTextsTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LinearLayoutEditTextsTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.layout.linear;
 
-import android.widget.layout.linear.LinearLayoutEditTexts;
-import com.android.frameworks.coretests.R;
-
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.View;
 import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.view.View;
+
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
 
 public class LinearLayoutEditTextsTest extends ActivityInstrumentationTestCase<LinearLayoutEditTexts> {
     private View mChild;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/Weight.java b/core/tests/coretests/src/android/widget/layout/linear/Weight.java
index 20edd7c..3722a14f 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/Weight.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/Weight.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 public class Weight extends Activity {
     @Override
     protected void onCreate(Bundle icicle) {
diff --git a/core/tests/coretests/src/android/widget/layout/linear/WeightSum.java b/core/tests/coretests/src/android/widget/layout/linear/WeightSum.java
index 2e421da..144600b 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/WeightSum.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/WeightSum.java
@@ -16,11 +16,10 @@
 
 package android.widget.layout.linear;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.View;
+
+import com.android.frameworks.coretests.R;
 
 public class WeightSum extends Activity {
     @Override
diff --git a/core/tests/coretests/src/android/widget/layout/linear/WeightSumTest.java b/core/tests/coretests/src/android/widget/layout/linear/WeightSumTest.java
index f9a94ce..1d07db2 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/WeightSumTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/WeightSumTest.java
@@ -18,11 +18,11 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.WeightSum;
 
 public class WeightSumTest extends ActivityInstrumentationTestCase<WeightSum> {
     private View mChild;
diff --git a/core/tests/coretests/src/android/widget/layout/linear/WeightTest.java b/core/tests/coretests/src/android/widget/layout/linear/WeightTest.java
index 1c42e7c..db52495 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/WeightTest.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/WeightTest.java
@@ -18,13 +18,13 @@
 
 import android.app.Activity;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 import com.android.frameworks.coretests.R;
-import android.widget.layout.linear.Weight;
 
 @Suppress // Failing.
 public class WeightTest extends ActivityInstrumentationTestCase<Weight> {
diff --git a/core/tests/coretests/src/android/widget/layout/table/AddColumn.java b/core/tests/coretests/src/android/widget/layout/table/AddColumn.java
index 400c32c..b407941 100644
--- a/core/tests/coretests/src/android/widget/layout/table/AddColumn.java
+++ b/core/tests/coretests/src/android/widget/layout/table/AddColumn.java
@@ -16,8 +16,6 @@
 
 package android.widget.layout.table;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.View;
@@ -26,6 +24,8 @@
 import android.widget.TableRow;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * This test adds an extra row with an extra column in the table.
  */
diff --git a/core/tests/coretests/src/android/widget/layout/table/AddColumnTest.java b/core/tests/coretests/src/android/widget/layout/table/AddColumnTest.java
index bfb4d17..08ae030 100644
--- a/core/tests/coretests/src/android/widget/layout/table/AddColumnTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/AddColumnTest.java
@@ -16,16 +16,16 @@
 
 package android.widget.layout.table;
 
-import android.widget.layout.table.AddColumn;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.TableLayout;
 import android.widget.TableRow;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link android.widget.layout.table.AddColumn} is
  * setup to exercise the case of adding row programmatically in a table.
diff --git a/core/tests/coretests/src/android/widget/layout/table/CellSpan.java b/core/tests/coretests/src/android/widget/layout/table/CellSpan.java
index d91cf56..3102ac1 100644
--- a/core/tests/coretests/src/android/widget/layout/table/CellSpan.java
+++ b/core/tests/coretests/src/android/widget/layout/table/CellSpan.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.table;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercise table layout with cells spanning.
  */
diff --git a/core/tests/coretests/src/android/widget/layout/table/CellSpanTest.java b/core/tests/coretests/src/android/widget/layout/table/CellSpanTest.java
index 331ec45..aa8e66c 100644
--- a/core/tests/coretests/src/android/widget/layout/table/CellSpanTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/CellSpanTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.layout.table;
 
-import android.widget.layout.table.CellSpan;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link android.widget.layout.table.CellSpan} is
  * setup to exercise tables in which cells use spanning.
diff --git a/core/tests/coretests/src/android/widget/layout/table/FixedWidth.java b/core/tests/coretests/src/android/widget/layout/table/FixedWidth.java
index 435815a..c587f74 100644
--- a/core/tests/coretests/src/android/widget/layout/table/FixedWidth.java
+++ b/core/tests/coretests/src/android/widget/layout/table/FixedWidth.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.table;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercise table layout with cells having a fixed width and height.
  */
diff --git a/core/tests/coretests/src/android/widget/layout/table/FixedWidthTest.java b/core/tests/coretests/src/android/widget/layout/table/FixedWidthTest.java
index b20ec84..7d02453 100644
--- a/core/tests/coretests/src/android/widget/layout/table/FixedWidthTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/FixedWidthTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.layout.table;
 
-import android.widget.layout.table.FixedWidth;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link android.widget.layout.table.FixedWidth} is
  * setup to exercise tables in which cells use fixed width and height.
diff --git a/core/tests/coretests/src/android/widget/layout/table/HorizontalGravity.java b/core/tests/coretests/src/android/widget/layout/table/HorizontalGravity.java
index 1444f60..6f5148b 100644
--- a/core/tests/coretests/src/android/widget/layout/table/HorizontalGravity.java
+++ b/core/tests/coretests/src/android/widget/layout/table/HorizontalGravity.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.table;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercise table layout with cells using a horizontal gravity.
  */
diff --git a/core/tests/coretests/src/android/widget/layout/table/HorizontalGravityTest.java b/core/tests/coretests/src/android/widget/layout/table/HorizontalGravityTest.java
index 964df82..73e8334 100644
--- a/core/tests/coretests/src/android/widget/layout/table/HorizontalGravityTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/HorizontalGravityTest.java
@@ -16,14 +16,14 @@
 
 package android.widget.layout.table;
 
-import android.widget.layout.table.HorizontalGravity;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link android.widget.layout.table.HorizontalGravity} is
  * setup to exercise tables in which cells use horizontal gravity.
diff --git a/core/tests/coretests/src/android/widget/layout/table/VerticalGravity.java b/core/tests/coretests/src/android/widget/layout/table/VerticalGravity.java
index 4fdb378..9055b32 100644
--- a/core/tests/coretests/src/android/widget/layout/table/VerticalGravity.java
+++ b/core/tests/coretests/src/android/widget/layout/table/VerticalGravity.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.table;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercise table layout with cells using a vertical gravity.
  */
diff --git a/core/tests/coretests/src/android/widget/layout/table/VerticalGravityTest.java b/core/tests/coretests/src/android/widget/layout/table/VerticalGravityTest.java
index 1d6be3f..f14fa1c 100644
--- a/core/tests/coretests/src/android/widget/layout/table/VerticalGravityTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/VerticalGravityTest.java
@@ -16,15 +16,15 @@
 
 package android.widget.layout.table;
 
-import android.widget.layout.table.VerticalGravity;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.test.ViewAsserts;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link android.widget.layout.table.VerticalGravity} is
  * setup to exercise tables in which cells use vertical gravity.
diff --git a/core/tests/coretests/src/android/widget/layout/table/Weight.java b/core/tests/coretests/src/android/widget/layout/table/Weight.java
index 6d4d51d..5c08247 100644
--- a/core/tests/coretests/src/android/widget/layout/table/Weight.java
+++ b/core/tests/coretests/src/android/widget/layout/table/Weight.java
@@ -16,11 +16,11 @@
 
 package android.widget.layout.table;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercise table layout with cells having a weight.
  */
diff --git a/core/tests/coretests/src/android/widget/layout/table/WeightTest.java b/core/tests/coretests/src/android/widget/layout/table/WeightTest.java
index b665573..fcf3de2 100644
--- a/core/tests/coretests/src/android/widget/layout/table/WeightTest.java
+++ b/core/tests/coretests/src/android/widget/layout/table/WeightTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.layout.table;
 
-import android.widget.layout.table.Weight;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * {@link android.widget.layout.table.Weight} is
  * setup to exercise tables in which cells use a weight.
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java
index a386ebd..cd76d70 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravity.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import android.view.Gravity;
-
 import android.util.ListScenario;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java
index 519816c..e048e3e 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravityMany.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import android.view.Gravity;
-
 import android.util.ListScenario;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravityManyTest.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravityManyTest.java
index e1171eb..bd8dbe4 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravityManyTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravityManyTest.java
@@ -17,10 +17,9 @@
 package android.widget.listview;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.ListView;
 
-import android.widget.listview.ListBottomGravityMany;
+import androidx.test.filters.MediumTest;
 
 public class ListBottomGravityManyTest extends ActivityInstrumentationTestCase<ListBottomGravityMany> {
     private ListBottomGravityMany mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListBottomGravityTest.java b/core/tests/coretests/src/android/widget/listview/ListBottomGravityTest.java
index c595f62..8da7358 100644
--- a/core/tests/coretests/src/android/widget/listview/ListBottomGravityTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListBottomGravityTest.java
@@ -17,10 +17,9 @@
 package android.widget.listview;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.ListView;
 
-import android.widget.listview.ListBottomGravity;
+import androidx.test.filters.MediumTest;
 
 public class ListBottomGravityTest extends ActivityInstrumentationTestCase<ListBottomGravity> {
     private ListBottomGravity mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java b/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java
index bbed73c..8640741 100644
--- a/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java
+++ b/core/tests/coretests/src/android/widget/listview/ListButtonsDiagonalAcrossItems.java
@@ -16,10 +16,10 @@
 
 package android.widget.listview;
 
-import android.util.ListItemFactory;
 import static android.util.ListItemFactory.Slot;
-import android.util.ListScenario;
 
+import android.util.ListItemFactory;
+import android.util.ListScenario;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
diff --git a/core/tests/coretests/src/android/widget/listview/ListEmptyViewTest.java b/core/tests/coretests/src/android/widget/listview/ListEmptyViewTest.java
index 258d3ef..81d71a9 100644
--- a/core/tests/coretests/src/android/widget/listview/ListEmptyViewTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListEmptyViewTest.java
@@ -19,12 +19,13 @@
 import android.app.Instrumentation;
 import android.content.Intent;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class ListEmptyViewTest extends ActivityInstrumentationTestCase<ListWithEmptyView> {
     private ListWithEmptyView mActivity;
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/ListFilter.java b/core/tests/coretests/src/android/widget/listview/ListFilter.java
index c2ac90e..1cda717 100644
--- a/core/tests/coretests/src/android/widget/listview/ListFilter.java
+++ b/core/tests/coretests/src/android/widget/listview/ListFilter.java
@@ -25,7 +25,6 @@
 
 import com.android.frameworks.coretests.R;
 
-
 /**
  * Tests hiding and showing the list filter by hiding and showing an ancestor of the 
  * ListView
diff --git a/core/tests/coretests/src/android/widget/listview/ListFocusableTest.java b/core/tests/coretests/src/android/widget/listview/ListFocusableTest.java
index bf18a13..10b4a79 100644
--- a/core/tests/coretests/src/android/widget/listview/ListFocusableTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListFocusableTest.java
@@ -17,10 +17,11 @@
 package android.widget.listview;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
-import android.widget.ListAdapter;
 import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import androidx.test.filters.MediumTest;
 
 public class ListFocusableTest extends ActivityInstrumentationTestCase<ListTopGravity> {
     private ListTopGravity mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java b/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java
index 33d61a0..c691ed7 100644
--- a/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java
@@ -17,10 +17,11 @@
 package android.widget.listview;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.ListView;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
 import java.util.Arrays;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java b/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java
index 1f59c30..74eda3b 100644
--- a/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java
+++ b/core/tests/coretests/src/android/widget/listview/ListHeterogeneous.java
@@ -16,11 +16,10 @@
 
 package android.widget.listview;
 
-import android.view.View;
-import android.view.ViewGroup;
-
 import android.util.ListItemFactory;
 import android.util.ListScenario;
+import android.view.View;
+import android.view.ViewGroup;
 
 /**
  * List that has different view types
diff --git a/core/tests/coretests/src/android/widget/listview/ListHeterogeneousTest.java b/core/tests/coretests/src/android/widget/listview/ListHeterogeneousTest.java
index 01b39db..dbd58d7 100644
--- a/core/tests/coretests/src/android/widget/listview/ListHeterogeneousTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListHeterogeneousTest.java
@@ -18,12 +18,11 @@
 
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.ListView;
 
-import android.widget.listview.ListHeterogeneous;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 public class ListHeterogeneousTest extends ActivityInstrumentationTestCase<ListHeterogeneous> {
     private ListHeterogeneous mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java b/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java
index 2ff65de..e98de9c 100644
--- a/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java
+++ b/core/tests/coretests/src/android/widget/listview/ListHorizontalFocusWithinItemWins.java
@@ -16,11 +16,11 @@
 
 package android.widget.listview;
 
-import android.util.ListItemFactory;
 import static android.util.ListItemFactory.Slot;
-import android.util.ListScenario;
 
 import android.content.Context;
+import android.util.ListItemFactory;
+import android.util.ListScenario;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
diff --git a/core/tests/coretests/src/android/widget/listview/ListInHorizontal.java b/core/tests/coretests/src/android/widget/listview/ListInHorizontal.java
index a373a5b..6622c0d 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInHorizontal.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInHorizontal.java
@@ -18,10 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.os.Handler;
 import android.widget.ArrayAdapter;
-import android.widget.GridView;
-import android.widget.TextView;
 import android.widget.ListView;
 
 import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/widget/listview/ListInHorizontalTest.java b/core/tests/coretests/src/android/widget/listview/ListInHorizontalTest.java
index 3643f79..d8508ec 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInHorizontalTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInHorizontalTest.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import android.widget.listview.ListInHorizontal;
-
 public class ListInHorizontalTest extends ListUnspecifiedMeasure<ListInHorizontal> {
     public ListInHorizontalTest() {
         super(ListInHorizontal.class);
diff --git a/core/tests/coretests/src/android/widget/listview/ListInVertical.java b/core/tests/coretests/src/android/widget/listview/ListInVertical.java
index 3b4885a..4ecf25d 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInVertical.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInVertical.java
@@ -18,10 +18,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.os.Handler;
 import android.widget.ArrayAdapter;
-import android.widget.GridView;
-import android.widget.TextView;
 import android.widget.ListView;
 
 import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/widget/listview/ListInVerticalTest.java b/core/tests/coretests/src/android/widget/listview/ListInVerticalTest.java
index 8586429..5e385a3 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInVerticalTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInVerticalTest.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import android.widget.listview.ListInVertical;
-
 public class ListInVerticalTest extends ListUnspecifiedMeasure<ListInVertical> {
     public ListInVerticalTest() {
         super(ListInVertical.class);
diff --git a/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java b/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java
index d5da28e..0ec7a24 100644
--- a/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java
+++ b/core/tests/coretests/src/android/widget/listview/ListInterleaveFocusables.java
@@ -16,13 +16,14 @@
 
 package android.widget.listview;
 
+import android.util.ListItemFactory;
+import android.util.ListScenario;
 import android.view.View;
- import android.view.ViewGroup;
- import com.google.android.collect.Sets;
- import android.util.ListScenario;
- import android.util.ListItemFactory;
+import android.view.ViewGroup;
 
- import java.util.Set;
+import com.google.android.collect.Sets;
+
+import java.util.Set;
 
 /**
  * List that interleaves focusable items.
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java b/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java
index f7c01b1..3159e53 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemFocusableAboveUnfocusable.java
@@ -16,12 +16,10 @@
 
 package android.widget.listview;
 
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
 import android.util.ListItemFactory;
 import android.util.ListScenario;
+import android.view.View;
+import android.view.ViewGroup;
 
 /**
  * A list where the items may befocusable, but the second item isn't actually focusabe.
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java
index b529b2e..861e2a91 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesClose.java
@@ -16,8 +16,8 @@
 
 package android.widget.listview;
 
-import android.util.ListScenario;
 import android.util.ListItemFactory;
+import android.util.ListScenario;
 import android.view.View;
 import android.view.ViewGroup;
 
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java
index 59987ec..e9c9c1d 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemFocusablesFarApart.java
@@ -16,10 +16,10 @@
 
 package android.widget.listview;
 
-import android.view.View;
-import android.view.ViewGroup;
 import android.util.ListItemFactory;
 import android.util.ListScenario;
+import android.view.View;
+import android.view.ViewGroup;
 
 /**
  * A list where each item is tall with buttons that are farther apart than the screen
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java b/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java
index ea2c5f2..2a0e013 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemISVAndButton.java
@@ -17,13 +17,13 @@
 package android.widget.listview;
 
 import android.content.Context;
+import android.util.InternalSelectionView;
+import android.util.ListScenario;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-import android.util.InternalSelectionView;
-import android.util.ListScenario;
 
 /**
  * Each item is an internal selection view, a button, and some filler
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemRequestRectAboveThinFirstItemTest.java b/core/tests/coretests/src/android/widget/listview/ListItemRequestRectAboveThinFirstItemTest.java
index 73eb0a8..91ff06b 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemRequestRectAboveThinFirstItemTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemRequestRectAboveThinFirstItemTest.java
@@ -18,13 +18,13 @@
 
 import android.graphics.Rect;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.view.View;
 import android.view.KeyEvent;
+import android.view.View;
 import android.widget.ListView;
-import android.widget.listview.ListOfThinItems;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 public class ListItemRequestRectAboveThinFirstItemTest
         extends ActivityInstrumentationTestCase<ListOfThinItems> {
diff --git a/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java b/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java
index a5fe17a..d80fd90 100644
--- a/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java
+++ b/core/tests/coretests/src/android/widget/listview/ListItemsExpandOnSelection.java
@@ -17,13 +17,12 @@
 package android.widget.listview;
 
 import android.content.Context;
+import android.util.ListScenario;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AbsListView;
 import android.widget.TextView;
 
-import android.util.ListScenario;
-
 /**
  * A list where each item expands by 1.5 when selected.
  */
diff --git a/core/tests/coretests/src/android/widget/listview/ListManagedCursor.java b/core/tests/coretests/src/android/widget/listview/ListManagedCursor.java
index 12b5ef4..54f302c 100644
--- a/core/tests/coretests/src/android/widget/listview/ListManagedCursor.java
+++ b/core/tests/coretests/src/android/widget/listview/ListManagedCursor.java
@@ -20,14 +20,13 @@
 import android.content.Intent;
 import android.database.Cursor;
 import android.os.Bundle;
-import android.provider.Settings;
 import android.provider.Contacts.People;
+import android.provider.Settings;
 import android.view.View;
 import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ListAdapter;
 import android.widget.SimpleCursorAdapter;
-import android.widget.AdapterView.OnItemClickListener;
-
 
 public class ListManagedCursor extends ListActivity implements OnItemClickListener {
     
diff --git a/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java b/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java
index bc3776c..8e0b6fe 100644
--- a/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java
@@ -18,11 +18,12 @@
 
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
 import android.view.KeyEvent;
 import android.widget.ListView;
-import android.test.TouchUtils;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 /**
  * Tests restoring the scroll position in a list with a managed cursor.
diff --git a/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java b/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java
index 919ef69..70b9081 100644
--- a/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java
+++ b/core/tests/coretests/src/android/widget/listview/ListOfTouchables.java
@@ -16,12 +16,11 @@
 
 package android.widget.listview;
 
+import android.util.ListScenario;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
 
-import android.util.ListScenario;
-
 /**
  * Each list item has two focusables that are close enough together that
  * it shouldn't require panning to move focus.
diff --git a/core/tests/coretests/src/android/widget/listview/ListRecyclerProfiling.java b/core/tests/coretests/src/android/widget/listview/ListRecyclerProfiling.java
index 76814fb..075712e 100644
--- a/core/tests/coretests/src/android/widget/listview/ListRecyclerProfiling.java
+++ b/core/tests/coretests/src/android/widget/listview/ListRecyclerProfiling.java
@@ -18,11 +18,11 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.ImageButton;
-import android.view.ViewDebug;
 import android.view.View;
+import android.view.ViewDebug;
+import android.widget.ArrayAdapter;
+import android.widget.ImageButton;
+import android.widget.ListView;
 
 import com.android.frameworks.coretests.R;
 
diff --git a/core/tests/coretests/src/android/widget/listview/ListRetainsFocusAcrossLayoutsTest.java b/core/tests/coretests/src/android/widget/listview/ListRetainsFocusAcrossLayoutsTest.java
index 896bd19..be14de8 100644
--- a/core/tests/coretests/src/android/widget/listview/ListRetainsFocusAcrossLayoutsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListRetainsFocusAcrossLayoutsTest.java
@@ -16,12 +16,11 @@
 
 package android.widget.listview;
 
-import android.widget.listview.ListItemFocusablesClose;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 
+import androidx.test.filters.MediumTest;
+
 public class ListRetainsFocusAcrossLayoutsTest extends ActivityInstrumentationTestCase<ListItemFocusablesClose> {
 
     public ListRetainsFocusAcrossLayoutsTest() {
diff --git a/core/tests/coretests/src/android/widget/listview/ListScrollListenerTest.java b/core/tests/coretests/src/android/widget/listview/ListScrollListenerTest.java
index 7b29a66..28addd6 100644
--- a/core/tests/coretests/src/android/widget/listview/ListScrollListenerTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListScrollListenerTest.java
@@ -19,12 +19,13 @@
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.AbsListView;
 import android.widget.ListView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class ListScrollListenerTest extends ActivityInstrumentationTestCase<ListScrollListener> implements
         AbsListView.OnScrollListener {
     private ListScrollListener mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListSetSelection.java b/core/tests/coretests/src/android/widget/listview/ListSetSelection.java
index 6c2e264..af8e899 100644
--- a/core/tests/coretests/src/android/widget/listview/ListSetSelection.java
+++ b/core/tests/coretests/src/android/widget/listview/ListSetSelection.java
@@ -16,12 +16,12 @@
 
 package android.widget.listview;
 
+import android.os.Bundle;
 import android.util.ListScenario;
 import android.view.KeyEvent;
 import android.view.View;
-import android.os.Bundle;
-import android.widget.LinearLayout;
 import android.widget.Button;
+import android.widget.LinearLayout;
 
 /**
  * List of 1,000 items used to test calls to setSelection() in touch mode.
diff --git a/core/tests/coretests/src/android/widget/listview/ListSetSelectionTest.java b/core/tests/coretests/src/android/widget/listview/ListSetSelectionTest.java
index 4cef164..2caca13 100644
--- a/core/tests/coretests/src/android/widget/listview/ListSetSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListSetSelectionTest.java
@@ -17,10 +17,11 @@
 package android.widget.listview;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.ListView;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * Basic tests of setting & clearing the selection
  */
diff --git a/core/tests/coretests/src/android/widget/listview/ListSimple.java b/core/tests/coretests/src/android/widget/listview/ListSimple.java
index 6accae1..f53638e 100644
--- a/core/tests/coretests/src/android/widget/listview/ListSimple.java
+++ b/core/tests/coretests/src/android/widget/listview/ListSimple.java
@@ -16,11 +16,10 @@
 
 package android.widget.listview;
 
+import android.os.Bundle;
 import android.util.ListScenario;
-
 import android.view.View;
 import android.view.ViewGroup;
-import android.os.Bundle;
 import android.widget.TextView;
 
 public class ListSimple extends ListScenario {
diff --git a/core/tests/coretests/src/android/widget/listview/ListTakeFocusFromSide.java b/core/tests/coretests/src/android/widget/listview/ListTakeFocusFromSide.java
index 95f09f6..c4e9fe9 100644
--- a/core/tests/coretests/src/android/widget/listview/ListTakeFocusFromSide.java
+++ b/core/tests/coretests/src/android/widget/listview/ListTakeFocusFromSide.java
@@ -16,17 +16,17 @@
 
 package android.widget.listview;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.ListActivity;
 import android.content.Context;
 import android.os.Bundle;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.LayoutInflater;
 import android.widget.BaseAdapter;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Exercises moving focus into the list from the side
  */
diff --git a/core/tests/coretests/src/android/widget/listview/ListThrasher.java b/core/tests/coretests/src/android/widget/listview/ListThrasher.java
index 0237a95..d82f68d 100644
--- a/core/tests/coretests/src/android/widget/listview/ListThrasher.java
+++ b/core/tests/coretests/src/android/widget/listview/ListThrasher.java
@@ -16,19 +16,19 @@
 
 package android.widget.listview;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.ListActivity;
 import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.LayoutInflater;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 import java.util.Random;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/listview/ListTopGravity.java b/core/tests/coretests/src/android/widget/listview/ListTopGravity.java
index 986cc57..31339e9 100644
--- a/core/tests/coretests/src/android/widget/listview/ListTopGravity.java
+++ b/core/tests/coretests/src/android/widget/listview/ListTopGravity.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import android.view.Gravity;
-
 import android.util.ListScenario;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/listview/ListUnspecifiedMeasure.java b/core/tests/coretests/src/android/widget/listview/ListUnspecifiedMeasure.java
index 199d069..0fc87ea 100644
--- a/core/tests/coretests/src/android/widget/listview/ListUnspecifiedMeasure.java
+++ b/core/tests/coretests/src/android/widget/listview/ListUnspecifiedMeasure.java
@@ -16,13 +16,14 @@
 
 package android.widget.listview;
 
-import com.android.frameworks.coretests.R;
-
-import android.test.ActivityInstrumentationTestCase;
 import android.app.Activity;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ActivityInstrumentationTestCase;
 import android.widget.ListView;
 
+import androidx.test.filters.MediumTest;
+
+import com.android.frameworks.coretests.R;
+
 public class ListUnspecifiedMeasure<T extends Activity> extends ActivityInstrumentationTestCase<T> {
     private T mActivity;
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/ListViewHeightTest.java b/core/tests/coretests/src/android/widget/listview/ListViewHeightTest.java
index 5ab2757..63941f1 100644
--- a/core/tests/coretests/src/android/widget/listview/ListViewHeightTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListViewHeightTest.java
@@ -18,12 +18,12 @@
 
 import android.app.Instrumentation;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.Button;
 import android.widget.ListView;
 
+import androidx.test.filters.MediumTest;
+
 import com.android.frameworks.coretests.R;
-import android.widget.listview.ListViewHeight;
 
 public class ListViewHeightTest extends ActivityInstrumentationTestCase<ListViewHeight> {
     private ListViewHeight mActivity;
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithDisappearingItemBug.java b/core/tests/coretests/src/android/widget/listview/ListWithDisappearingItemBug.java
index 348ea1b..10ba8b7 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithDisappearingItemBug.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithDisappearingItemBug.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.ListActivity;
 import android.database.Cursor;
 import android.os.Bundle;
@@ -32,6 +30,8 @@
 import android.widget.SimpleCursorAdapter;
 import android.widget.Toast;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * See 1080989. You need some contacts for this adapter.
  */
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithEmptyView.java b/core/tests/coretests/src/android/widget/listview/ListWithEmptyView.java
index 74dd06c..52273fd 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithEmptyView.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithEmptyView.java
@@ -16,8 +16,6 @@
 
 package android.widget.listview;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.ListActivity;
 import android.content.Context;
 import android.os.Bundle;
@@ -26,6 +24,8 @@
 import android.view.View;
 import android.widget.ArrayAdapter;
 
+import com.android.frameworks.coretests.R;
+
 
 /**
  * Tests using an empty view with a list */
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java b/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java
index aea091a..6030582 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithHeaders.java
@@ -16,9 +16,8 @@
 
 package android.widget.listview;
 
-import android.util.ListScenario;
-
 import android.os.Bundle;
+import android.util.ListScenario;
 import android.widget.Button;
 import android.widget.ListAdapter;
 import android.widget.ListView;
diff --git a/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java b/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java
index 26e1d5d..13e770c 100644
--- a/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java
+++ b/core/tests/coretests/src/android/widget/listview/ListWithOnItemSelectedAction.java
@@ -16,8 +16,8 @@
 
 package android.widget.listview;
 
-import android.widget.TextView;
 import android.util.ListScenario;
+import android.widget.TextView;
 
 /**
  * The header text view echos the value of the selected item by using (indirectly)
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListInterleaveFocusablesTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListInterleaveFocusablesTest.java
index ec8ab7e..22c28c2 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListInterleaveFocusablesTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListInterleaveFocusablesTest.java
@@ -17,13 +17,14 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.util.ListUtil;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.listview.ListInterleaveFocusables;
 
+import androidx.test.filters.MediumTest;
+
 public class ListInterleaveFocusablesTest extends ActivityInstrumentationTestCase2<ListInterleaveFocusables> {
     private ListView mListView;
     private ListUtil mListUtil;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java
index 82f48801..c645b7c 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java
@@ -17,11 +17,12 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
 import android.view.KeyEvent;
+import android.widget.ListView;
 import android.widget.listview.ListItemFocusableAboveUnfocusable;
 
+import androidx.test.filters.MediumTest;
+
 public class ListItemFocusableAboveUnfocusableTest extends ActivityInstrumentationTestCase<ListItemFocusableAboveUnfocusable> {
     private ListView mListView;
 
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesCloseTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesCloseTest.java
index 3b30ebe..c7525b3 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesCloseTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesCloseTest.java
@@ -17,12 +17,13 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.listview.ListItemFocusablesClose;
 
+import androidx.test.filters.MediumTest;
+
 public class ListItemFocusablesCloseTest extends ActivityInstrumentationTestCase<ListItemFocusablesClose> {
     private ListView mListView;
     private int mListTop;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesFarApartTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesFarApartTest.java
index 475930d..4bb2206 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesFarApartTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemFocusablesFarApartTest.java
@@ -17,7 +17,6 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -25,6 +24,8 @@
 import android.widget.ListView;
 import android.widget.listview.ListItemFocusablesFarApart;
 
+import androidx.test.filters.MediumTest;
+
 public class ListItemFocusablesFarApartTest extends ActivityInstrumentationTestCase<ListItemFocusablesFarApart> {
     private ListView mListView;
     private int mListTop;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemsExpandOnSelectionTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemsExpandOnSelectionTest.java
index 91a1eba..7605291 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemsExpandOnSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListItemsExpandOnSelectionTest.java
@@ -17,13 +17,14 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.ListView;
 import android.view.KeyEvent;
+import android.widget.ListView;
 import android.widget.listview.ListItemsExpandOnSelection;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListItemsExpandOnSelectionTest extends ActivityInstrumentationTestCase<ListItemsExpandOnSelection> {
     private ListView mListView;
     private int mListTop;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java
index 5bc121a..fdae483 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java
@@ -17,12 +17,13 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
-import android.view.View;
 import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
 import android.widget.listview.ListLastItemPartiallyVisible;
 
+import androidx.test.filters.MediumTest;
+
 public class ListLastItemPartiallyVisibleTest extends ActivityInstrumentationTestCase<ListLastItemPartiallyVisible> {
     private ListView mListView;
     private int mListBottom;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java
index bda71d0..d44b130 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java
@@ -17,14 +17,15 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.listview.ListOfItemsShorterThanScreen;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListOfItemsShorterThanScreenTest
         extends ActivityInstrumentationTestCase<ListOfItemsShorterThanScreen> {
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java
index 2135445..1decdad 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java
@@ -17,13 +17,14 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.listview.ListOfItemsTallerThanScreen;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListOfItemsTallerThanScreenTest
         extends ActivityInstrumentationTestCase2<ListOfItemsTallerThanScreen> {
 
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortShortTallShortShortTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortShortTallShortShortTest.java
index ef70b5a..67808f1 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortShortTallShortShortTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortShortTallShortShortTest.java
@@ -17,13 +17,14 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.util.ListUtil;
 import android.view.KeyEvent;
 import android.widget.ListView;
 import android.widget.listview.ListOfShortShortTallShortShort;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListOfShortShortTallShortShortTest extends ActivityInstrumentationTestCase2<ListOfShortShortTallShortShort> {
     private ListView mListView;
     private ListUtil mListUtil;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortTallShortTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortTallShortTest.java
index c958591..f9aa6dc 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortTallShortTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfShortTallShortTest.java
@@ -17,11 +17,12 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
 import android.view.KeyEvent;
+import android.widget.ListView;
 import android.widget.listview.ListOfShortTallShort;
 
+import androidx.test.filters.MediumTest;
+
 public class ListOfShortTallShortTest extends ActivityInstrumentationTestCase<ListOfShortTallShort> {
     private ListView mListView;
 
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfThinItemsTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfThinItemsTest.java
index c191d71..6bd1cb5 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfThinItemsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListOfThinItemsTest.java
@@ -17,14 +17,15 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.listview.ListOfThinItems;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListOfThinItemsTest extends ActivityInstrumentationTestCase<ListOfThinItems> {
     private ListView mListView;
 
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
index 9a8e634..60bc115 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
@@ -16,12 +16,13 @@
 
 package android.widget.listview.arrowscroll;
 
-import android.support.test.filters.LargeTest;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.KeyEvent;
+import android.widget.AdapterView;
 import android.widget.ListView;
 import android.widget.listview.ListWithFirstScreenUnSelectable;
-import android.widget.AdapterView;
+
+import androidx.test.filters.LargeTest;
 
 @LargeTest
 public class ListWithFirstScreenUnSelectableTest
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithNoFadingEdgeTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithNoFadingEdgeTest.java
index 56ca009..a60054e 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithNoFadingEdgeTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithNoFadingEdgeTest.java
@@ -17,12 +17,13 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.ListView;
 import android.widget.listview.ListWithNoFadingEdge;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 public class ListWithNoFadingEdgeTest extends ActivityInstrumentationTestCase<ListWithNoFadingEdge> {
 
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java
index cf319d1..80e70c6 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java
@@ -17,14 +17,15 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.listview.ListWithOffScreenNextSelectable;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 @Suppress // Failing.
 public class ListWithOffScreenNextSelectableTest
         extends ActivityInstrumentationTestCase<ListWithOffScreenNextSelectable> {
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOnItemSelectedActionTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOnItemSelectedActionTest.java
index feea9b2..819b739 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOnItemSelectedActionTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithOnItemSelectedActionTest.java
@@ -17,12 +17,13 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
 import android.widget.ListView;
 import android.widget.TextView;
-import android.view.KeyEvent;
 import android.widget.listview.ListWithOnItemSelectedAction;
 
+import androidx.test.filters.MediumTest;
+
 public class ListWithOnItemSelectedActionTest extends ActivityInstrumentationTestCase<ListWithOnItemSelectedAction> {
     private ListView mListView;
 
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java
index 211c8c8..9bbdc2a 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java
@@ -17,13 +17,14 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.listview.ListWithScreenOfNoSelectables;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListWithScreenOfNoSelectablesTest extends ActivityInstrumentationTestCase2<ListWithScreenOfNoSelectables> {
 
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithSeparatorsTest.java b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithSeparatorsTest.java
index 42058f0..21fa51d 100644
--- a/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithSeparatorsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/arrowscroll/ListWithSeparatorsTest.java
@@ -17,11 +17,12 @@
 package android.widget.listview.arrowscroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.ListView;
 import android.view.KeyEvent;
+import android.widget.ListView;
 import android.widget.listview.ListWithSeparators;
 
+import androidx.test.filters.MediumTest;
+
 public class ListWithSeparatorsTest extends ActivityInstrumentationTestCase<ListWithSeparators> {
     private ListWithSeparators mActivity;
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java b/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
index 6a7466b..e9baabf 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
@@ -16,14 +16,14 @@
 
 package android.widget.listview.focus;
 
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.listview.AdjacentListsWithAdjacentISVsInside;
-import android.util.InternalSelectionView;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.util.InternalSelectionView;
 import android.view.KeyEvent;
 import android.widget.ListView;
+import android.widget.listview.AdjacentListsWithAdjacentISVsInside;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 public class AdjacentListsWithAdjacentISVsInsideTest extends ActivityInstrumentationTestCase<AdjacentListsWithAdjacentISVsInside> {
 
diff --git a/core/tests/coretests/src/android/widget/listview/focus/ListButtonsDiagonalAcrossItemsTest.java b/core/tests/coretests/src/android/widget/listview/focus/ListButtonsDiagonalAcrossItemsTest.java
index 5540d65..3fbdacc 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/ListButtonsDiagonalAcrossItemsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/ListButtonsDiagonalAcrossItemsTest.java
@@ -16,15 +16,15 @@
 
 package android.widget.listview.focus;
 
-import android.widget.listview.ListButtonsDiagonalAcrossItems;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.FocusFinder;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.Button;
 import android.widget.ListView;
+import android.widget.listview.ListButtonsDiagonalAcrossItems;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * Test that ListView will override default behavior of focus searching to
diff --git a/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java b/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
index edc60b5..5448952 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
@@ -17,12 +17,13 @@
 package android.widget.listview.focus;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.ListView;
 import android.widget.listview.ListHorizontalFocusWithinItemWins;
 
+import androidx.test.filters.MediumTest;
+
 public class ListHorizontalFocusWithinItemWinsTest extends ActivityInstrumentationTestCase<ListHorizontalFocusWithinItemWins> {
 
     private ListView mListView;
diff --git a/core/tests/coretests/src/android/widget/listview/focus/ListWithEditTextHeaderTest.java b/core/tests/coretests/src/android/widget/listview/focus/ListWithEditTextHeaderTest.java
index b449b61..0b17aaf 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/ListWithEditTextHeaderTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/ListWithEditTextHeaderTest.java
@@ -17,17 +17,18 @@
 package android.widget.listview.focus;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.FlakyTest;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.AbsListView;
 import android.widget.ListView;
 import android.widget.listview.ListWithEditTextHeader;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 public class ListWithEditTextHeaderTest extends ActivityInstrumentationTestCase2<ListWithEditTextHeader> {
     private ListView mListView;
 
@@ -49,7 +50,7 @@
         assertTrue("header does not have focus", mListView.getChildAt(0).isFocused());
     }
 
-    @FlakyTest(tolerance=2)
+    @FlakyTest
     @LargeTest
     public void testClickingHeaderKeepsFocus() {
         TouchUtils.clickView(this, mListView.getChildAt(0));
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListGetSelectedViewTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListGetSelectedViewTest.java
index 28f899e..262d0f4 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListGetSelectedViewTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListGetSelectedViewTest.java
@@ -17,14 +17,14 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
-import android.widget.ListView;
 import android.view.View;
-
+import android.widget.ListView;
 import android.widget.listview.ListGetSelectedView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * This test is made to check that getSelectedView() will return
  * null in touch mode.
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListOfTouchablesTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListOfTouchablesTest.java
index ffa9a5e..48e8c5e 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListOfTouchablesTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListOfTouchablesTest.java
@@ -17,15 +17,14 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.ListView;
-
 import android.widget.listview.ListOfTouchables;
-import android.test.TouchUtils;
+
+import androidx.test.filters.MediumTest;
 
 /**
  * Touch tests for a list where all of the items fit on the screen.
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListSetSelectionTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListSetSelectionTest.java
index aed513a..716683a 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListSetSelectionTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListSetSelectionTest.java
@@ -17,15 +17,15 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.View;
 import android.widget.ListView;
-
 import android.widget.listview.ListSimple;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 /**
  * Tests setting the selection in touch mode
  */
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityManyTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityManyTest.java
index 7daf64e..6a1f076 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityManyTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityManyTest.java
@@ -17,16 +17,16 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.ListView;
-
 import android.widget.listview.ListBottomGravityMany;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * Touch tests for a list where all of the items do not fit on the screen, and the list 
  * stacks from the bottom.
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityTest.java
index 4086cf0..89498d66 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListTouchBottomGravityTest.java
@@ -17,13 +17,13 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.View;
 import android.widget.ListView;
-
 import android.widget.listview.ListBottomGravity;
 
+import androidx.test.filters.MediumTest;
+
 /**
  * Touch tests for a list where all of the items fit on the screen, and the list 
  * stacks from the bottom.
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListTouchManyTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListTouchManyTest.java
index 30d56ca..c7f2371 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListTouchManyTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListTouchManyTest.java
@@ -17,16 +17,16 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.ListView;
-
 import android.widget.listview.ListTopGravityMany;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * Touch tests for a list where all of the items do not fit on the screen.
  */
diff --git a/core/tests/coretests/src/android/widget/listview/touch/ListTouchTest.java b/core/tests/coretests/src/android/widget/listview/touch/ListTouchTest.java
index 5b064b3..8a557ab 100644
--- a/core/tests/coretests/src/android/widget/listview/touch/ListTouchTest.java
+++ b/core/tests/coretests/src/android/widget/listview/touch/ListTouchTest.java
@@ -17,13 +17,13 @@
 package android.widget.listview.touch;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.TouchUtils;
 import android.view.View;
 import android.widget.ListView;
-
 import android.widget.listview.ListTopGravity;
 
+import androidx.test.filters.MediumTest;
+
 /**
  * Touch tests for a list where all of the items fit on the screen.
  */
diff --git a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java
index a7f5c05..a30985b 100644
--- a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java
+++ b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionView.java
@@ -18,7 +18,6 @@
 
 import android.util.InternalSelectionView;
 import android.util.ScrollViewScenario;
-
 import android.widget.Button;
 
 /**
diff --git a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java
index 8123228..825aa1a 100644
--- a/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/ButtonAboveTallInternalSelectionViewTest.java
@@ -16,14 +16,13 @@
 
 package android.widget.scroll;
 
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.scroll.ButtonAboveTallInternalSelectionView;
-import android.util.InternalSelectionView;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.util.InternalSelectionView;
 import android.view.KeyEvent;
 
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
 @Suppress // Failing.
 public class ButtonAboveTallInternalSelectionViewTest extends
         ActivityInstrumentationTestCase<ButtonAboveTallInternalSelectionView> {
diff --git a/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java b/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java
index 3d5f86d..47d36dd 100644
--- a/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java
+++ b/core/tests/coretests/src/android/widget/scroll/ButtonsWithTallTextViewInBetween.java
@@ -17,7 +17,6 @@
 package android.widget.scroll;
 
 import android.util.ScrollViewScenario;
-
 import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.TextView;
diff --git a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisible.java b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisible.java
index afc275f..dba07a0 100644
--- a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisible.java
+++ b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisible.java
@@ -16,15 +16,15 @@
 
 package android.widget.scroll;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
-import android.os.Bundle;
 import android.graphics.Rect;
+import android.os.Bundle;
 import android.view.View;
 import android.widget.ScrollView;
 import android.widget.TextView;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * A screen with some scenarios that exercise {@link ScrollView}'s implementation
  * of {@link android.view.ViewGroup#requestChildRectangleOnScreen}:
diff --git a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleTest.java b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleTest.java
index f8abdb2..7c3df91 100644
--- a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleTest.java
@@ -16,19 +16,19 @@
 
 package android.widget.scroll;
 
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.scroll.RequestRectangleVisible;
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.test.ViewAsserts;
+import android.view.KeyEvent;
+import android.view.View;
 import android.widget.Button;
 import android.widget.ScrollView;
 import android.widget.TextView;
-import android.view.View;
-import android.view.KeyEvent;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
+
+import com.android.frameworks.coretests.R;
 
 /**
  * {@link RequestRectangleVisible} is set up to exercise the cases of moving a
diff --git a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScroll.java b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScroll.java
index 731b25a..105686a 100644
--- a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScroll.java
+++ b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScroll.java
@@ -16,15 +16,14 @@
 
 package android.widget.scroll;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
-import android.os.Bundle;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.Button;
-import android.view.View;
 import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.frameworks.coretests.R;
 
 public class RequestRectangleVisibleWithInternalScroll extends Activity {
 
diff --git a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScrollTest.java b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScrollTest.java
index 5e9b520..1a221ff 100644
--- a/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScrollTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/RequestRectangleVisibleWithInternalScrollTest.java
@@ -16,16 +16,17 @@
 
 package android.widget.scroll;
 
-import com.android.frameworks.coretests.R;
-
 import android.test.ActivityInstrumentationTestCase;
 import android.test.ViewAsserts;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.ScrollView;
 import android.widget.TextView;
 
+import androidx.test.filters.Suppress;
+
+import com.android.frameworks.coretests.R;
+
 /**
  * This is suppressed because {@link TextView#scrollBy} isn't working.
  */
diff --git a/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabels.java b/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabels.java
index 027ea0f..92a3152 100644
--- a/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabels.java
+++ b/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabels.java
@@ -16,15 +16,14 @@
 
 package android.widget.scroll;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
+import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
 import android.widget.TextView;
-import android.widget.Button;
 
+import com.android.frameworks.coretests.R;
 
 /**
  * Basic scroll view example
diff --git a/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabelsTest.java b/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabelsTest.java
index 3fd17ee..8d71f84 100644
--- a/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabelsTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/ScrollViewButtonsAndLabelsTest.java
@@ -17,14 +17,14 @@
 package android.widget.scroll;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 public class ScrollViewButtonsAndLabelsTest
         extends ActivityInstrumentationTestCase<ScrollViewButtonsAndLabels> {
diff --git a/core/tests/coretests/src/android/widget/scroll/ShortButtons.java b/core/tests/coretests/src/android/widget/scroll/ShortButtons.java
index 3a0f29a..90ede7d 100644
--- a/core/tests/coretests/src/android/widget/scroll/ShortButtons.java
+++ b/core/tests/coretests/src/android/widget/scroll/ShortButtons.java
@@ -17,7 +17,6 @@
 package android.widget.scroll;
 
 import android.util.ScrollViewScenario;
-
 import android.widget.Button;
 import android.widget.LinearLayout;
 
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java
index 56d7ed2..04f5ac8 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java
@@ -16,16 +16,16 @@
 
 package android.widget.scroll.arrowscroll;
 
-import android.widget.scroll.ButtonsWithTallTextViewInBetween;
-
 import android.graphics.Rect;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.Button;
 import android.widget.ScrollView;
 import android.widget.TextView;
+import android.widget.scroll.ButtonsWithTallTextViewInBetween;
+
+import androidx.test.filters.MediumTest;
 
 public class ButtonsWithTallTextViewInBetweenTest
         extends ActivityInstrumentationTestCase<ButtonsWithTallTextViewInBetween> {
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
index 6ce4c15..2f45098 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/MultiPageTextWithPaddingTest.java
@@ -16,14 +16,14 @@
 
 package android.widget.scroll.arrowscroll;
 
-import android.test.suitebuilder.annotation.Suppress;
-import android.widget.scroll.arrowscroll.MultiPageTextWithPadding;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
-import android.widget.TextView;
 import android.widget.ScrollView;
+import android.widget.TextView;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.Suppress;
 
 @Suppress // Flaky
 public class MultiPageTextWithPaddingTest extends
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/ShortButtonsTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/ShortButtonsTest.java
index 267d8ee..a2928cb 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/ShortButtonsTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/ShortButtonsTest.java
@@ -16,15 +16,15 @@
 
 package android.widget.scroll.arrowscroll;
 
-import android.widget.scroll.ShortButtons;
-
 import android.graphics.Rect;
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.ScrollView;
+import android.widget.scroll.ShortButtons;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 public class ShortButtonsTest extends ActivityInstrumentationTestCase<ShortButtons> {
 
diff --git a/core/tests/coretests/src/android/widget/scroll/arrowscroll/TallTextAboveButtonTest.java b/core/tests/coretests/src/android/widget/scroll/arrowscroll/TallTextAboveButtonTest.java
index 5351839..0681081 100644
--- a/core/tests/coretests/src/android/widget/scroll/arrowscroll/TallTextAboveButtonTest.java
+++ b/core/tests/coretests/src/android/widget/scroll/arrowscroll/TallTextAboveButtonTest.java
@@ -16,13 +16,13 @@
 
 package android.widget.scroll.arrowscroll;
 
-import android.widget.scroll.TallTextAboveButton;
-
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.ScrollView;
 import android.widget.TextView;
+import android.widget.scroll.TallTextAboveButton;
+
+import androidx.test.filters.MediumTest;
 
 public class TallTextAboveButtonTest extends ActivityInstrumentationTestCase<TallTextAboveButton> {
     private ScrollView mScrollView;
diff --git a/core/tests/coretests/src/android/widget/touchmode/ChangeTouchModeTest.java b/core/tests/coretests/src/android/widget/touchmode/ChangeTouchModeTest.java
index 449c95c..aa20c9b 100644
--- a/core/tests/coretests/src/android/widget/touchmode/ChangeTouchModeTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/ChangeTouchModeTest.java
@@ -16,16 +16,17 @@
 
 package android.widget.touchmode;
 
-import android.widget.layout.linear.LLOfButtons1;
-import android.widget.layout.linear.LLOfButtons2;
 import static android.util.TouchModeFlexibleAsserts.assertInTouchModeAfterClick;
-import static android.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
 import static android.util.TouchModeFlexibleAsserts.assertInTouchModeAfterTap;
+import static android.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
+import android.widget.layout.linear.LLOfButtons1;
+import android.widget.layout.linear.LLOfButtons2;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 /**
  * Tests that the touch mode changes from various events, and that the state
diff --git a/core/tests/coretests/src/android/widget/touchmode/FocusableInTouchModeClickTest.java b/core/tests/coretests/src/android/widget/touchmode/FocusableInTouchModeClickTest.java
index 691b25a..97c982f 100644
--- a/core/tests/coretests/src/android/widget/touchmode/FocusableInTouchModeClickTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/FocusableInTouchModeClickTest.java
@@ -16,12 +16,12 @@
 
 package android.widget.touchmode;
 
-import android.widget.layout.linear.LLOfTwoFocusableInTouchMode;
-
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.TouchUtils;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.layout.linear.LLOfTwoFocusableInTouchMode;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
 
 public class FocusableInTouchModeClickTest extends ActivityInstrumentationTestCase2<LLOfTwoFocusableInTouchMode> {
 
diff --git a/core/tests/coretests/src/android/widget/touchmode/StartInTouchWithViewInFocusTest.java b/core/tests/coretests/src/android/widget/touchmode/StartInTouchWithViewInFocusTest.java
index 5339188..88aa9ca 100644
--- a/core/tests/coretests/src/android/widget/touchmode/StartInTouchWithViewInFocusTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/StartInTouchWithViewInFocusTest.java
@@ -16,14 +16,15 @@
 
 package android.widget.touchmode;
 
-import android.widget.layout.linear.LLEditTextThenButton;
 import static android.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.EditText;
+import android.widget.layout.linear.LLEditTextThenButton;
+
+import androidx.test.filters.MediumTest;
 
 public class StartInTouchWithViewInFocusTest extends 
         ActivityInstrumentationTestCase2<LLEditTextThenButton> {
diff --git a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java
index 5a6110c..f192f68 100644
--- a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java
@@ -21,11 +21,11 @@
 import static android.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 import android.widget.Button;
 import android.widget.layout.linear.LLOfButtons1;
 
+import androidx.test.filters.MediumTest;
 
 /**
  * Make sure focus isn't kept by buttons when entering touch mode.
diff --git a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusableTest.java b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusableTest.java
index 3ddeef0..87f33a4 100644
--- a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusableTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusableTest.java
@@ -20,12 +20,13 @@
 import static android.util.TouchModeFlexibleAsserts.assertInTouchModeAfterTap;
 
 import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.layout.linear.LLEditTextThenButton;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+
 /**
  * Some views, like edit texts, can keep and gain focus even when in touch mode.
  */
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 a302657..aadfcbc 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -57,7 +57,6 @@
 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;
@@ -66,6 +65,8 @@
 import android.view.accessibility.IAccessibilityManager;
 import android.widget.Toast;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.R;
 import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkObjectProvider;
 import com.android.internal.util.test.FakeSettingsProvider;
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 1859378..aaa624e 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -16,6 +16,30 @@
 
 package com.android.internal.app;
 
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.usage.UsageStatsManager;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.R;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 
@@ -25,32 +49,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 
-import android.app.usage.UsageStats;
-import android.app.usage.UsageStatsManager;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.os.UserHandle;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.times;
 
 /**
  * Chooser activity instrumentation tests
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index c446f3c..60529f6 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -16,14 +16,14 @@
 
 package com.android.internal.app;
 
+import static org.mockito.Mockito.mock;
+
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 
 import java.util.function.Function;
 
-import static org.mockito.Mockito.mock;
-
 public class ChooserWrapperActivity extends ChooserActivity {
     /*
      * Simple wrapper around chooser activity to be able to initiate it under test
diff --git a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
index cfb6bdd..9b13af2 100644
--- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
@@ -46,9 +46,10 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 404c99c..fe2fb85 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -16,6 +16,29 @@
 
 package com.android.internal.app;
 
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static com.android.internal.app.ResolverWrapperActivity.sOverrides;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.R;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 import com.android.internal.widget.ResolverDrawerLayout;
@@ -26,37 +49,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 
-import android.app.usage.UsageStats;
-import android.app.usage.UsageStatsManager;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.os.UserHandle;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.view.View;
-import android.widget.RelativeLayout;
-
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
-
-import static android.os.SystemClock.sleep;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static com.android.internal.app.ResolverWrapperActivity.sOverrides;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 /**
  * Resolver activity instrumentation tests
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
index c710b9a..850b466 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
@@ -23,10 +23,6 @@
 import android.content.pm.ResolveInfo;
 import android.os.UserHandle;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
 /**
  * Utility class used by resolver tests to create mock data
  */
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
index 284ab60..fcec00e 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
@@ -25,34 +25,31 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.when;
 
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
-
 import android.app.usage.IUsageStatsManager;
 import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.content.Intent;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 
-import java.io.File;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
index 163211e..83f6bc2 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
@@ -16,17 +16,12 @@
 
 package com.android.internal.app;
 
-import android.app.usage.UsageStatsManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-
-import java.util.function.Function;
-
 import static org.mockito.Mockito.mock;
 
+import android.app.usage.UsageStatsManager;
+import android.content.pm.PackageManager;
+
+import java.util.function.Function;
 
 /*
  * Simple wrapper around chooser activity to be able to initiate it under test
diff --git a/core/tests/coretests/src/com/android/internal/app/WindowDecorActionBarTest.java b/core/tests/coretests/src/com/android/internal/app/WindowDecorActionBarTest.java
index 472958a..87ad124 100644
--- a/core/tests/coretests/src/com/android/internal/app/WindowDecorActionBarTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/WindowDecorActionBarTest.java
@@ -17,12 +17,13 @@
 package com.android.internal.app;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.ActionMode;
 import android.view.Menu;
 import android.view.MenuItem;
 
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.SmallTest;
+
 /**
  * Tests for {@link WindowDecorActionBar}.
  */
diff --git a/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java b/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java
index 115af5e..f7fea3b 100644
--- a/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/procstats/SparseMappingTableTest.java
@@ -16,20 +16,14 @@
 
 package com.android.internal.app.procstats;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-
-import android.os.BatteryStats;
 import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
-import org.mockito.Mockito;
-
 /**
  * Provides test cases for SparseMappingTable.
  */
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
index 629f7b6..222e494 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodDebugTest.java
@@ -18,10 +18,11 @@
 
 import static org.junit.Assert.assertEquals;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.WindowManager.LayoutParams;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
index 8179328..ba63908 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/SubtypeLocaleUtilsTest.java
@@ -18,8 +18,8 @@
 
 import static org.junit.Assert.assertEquals;
 
-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/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
index 992b46f..b687801 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
@@ -13,6 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import static android.os.BatteryStats.STATS_SINCE_CHARGED;
@@ -20,10 +21,11 @@
 import android.app.ActivityManager;
 import android.os.BatteryStats;
 import android.os.WorkSource;
-import android.support.test.filters.SmallTest;
 import android.util.ArrayMap;
 import android.view.Display;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 /**
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
index 08f8dd1..37f818a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
@@ -13,11 +13,13 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import android.os.BatteryStats;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index ee8d508..9cac7e7 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static android.os.BatteryStats.STATS_SINCE_CHARGED;
@@ -36,11 +37,16 @@
 
 import android.os.BatteryStats;
 import android.os.UserHandle;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseLongArray;
 import android.view.Display;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
 import com.android.internal.util.ArrayUtils;
 
 import org.junit.Before;
@@ -64,7 +70,7 @@
  * Install: adb install -r \
  * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class com.android.internal.os.BatteryStatsCpuTimesTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ * com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  *
  * or
  *
@@ -74,13 +80,13 @@
 @RunWith(AndroidJUnit4.class)
 public class BatteryStatsCpuTimesTest {
     @Mock
-    KernelUidCpuTimeReader mKernelUidCpuTimeReader;
+    KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader;
     @Mock
-    KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader;
+    KernelCpuUidFreqTimeReader mCpuUidFreqTimeReader;
     @Mock
-    KernelUidCpuActiveTimeReader mKernelUidCpuActiveTimeReader;
+    KernelCpuUidActiveTimeReader mCpuUidActiveTimeReader;
     @Mock
-    KernelUidCpuClusterTimeReader mKernelUidCpuClusterTimeReader;
+    KernelCpuUidClusterTimeReader mCpuUidClusterTimeReader;
     @Mock
     BatteryStatsImpl.UserInfoProvider mUserInfoProvider;
     @Mock
@@ -96,10 +102,10 @@
 
         mClocks = new MockClocks();
         mBatteryStatsImpl = new MockBatteryStatsImpl(mClocks)
-                .setKernelUidCpuTimeReader(mKernelUidCpuTimeReader)
-                .setKernelUidCpuFreqTimeReader(mKernelUidCpuFreqTimeReader)
-                .setKernelUidCpuActiveTimeReader(mKernelUidCpuActiveTimeReader)
-                .setKernelUidCpuClusterTimeReader(mKernelUidCpuClusterTimeReader)
+                .setKernelCpuUidUserSysTimeReader(mCpuUidUserSysTimeReader)
+                .setKernelCpuUidFreqTimeReader(mCpuUidFreqTimeReader)
+                .setKernelCpuUidActiveTimeReader(mCpuUidActiveTimeReader)
+                .setKernelCpuUidClusterTimeReader(mCpuUidClusterTimeReader)
                 .setUserInfoProvider(mUserInfoProvider);
     }
 
@@ -111,21 +117,21 @@
         final int numClusters = 3;
         initKernelCpuSpeedReaders(numClusters);
         final long[] freqs = {1, 12, 123, 12, 1234};
-        when(mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile)).thenReturn(freqs);
+        when(mCpuUidFreqTimeReader.readFreqs(mPowerProfile)).thenReturn(freqs);
 
         // RUN
         mBatteryStatsImpl.updateCpuTimeLocked(false, false);
 
         // VERIFY
         assertArrayEquals("Unexpected cpu freqs", freqs, mBatteryStatsImpl.getCpuFreqs());
-        verify(mKernelUidCpuTimeReader).readDelta(null);
-        verify(mKernelUidCpuFreqTimeReader).readDelta(null);
+        verify(mCpuUidUserSysTimeReader).readDelta(null);
+        verify(mCpuUidFreqTimeReader).readDelta(null);
         for (int i = 0; i < numClusters; ++i) {
             verify(mKernelCpuSpeedReaders[i]).readDelta();
         }
 
         // Prepare for next test
-        Mockito.reset(mUserInfoProvider, mKernelUidCpuFreqTimeReader, mKernelUidCpuTimeReader);
+        Mockito.reset(mUserInfoProvider, mCpuUidFreqTimeReader, mCpuUidUserSysTimeReader);
         for (int i = 0; i < numClusters; ++i) {
             Mockito.reset(mKernelCpuSpeedReaders[i]);
         }
@@ -138,17 +144,18 @@
 
         // VERIFY
         verify(mUserInfoProvider).refreshUserIds();
-        verify(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
+        verify(mCpuUidUserSysTimeReader).readDelta(
+                any(KernelCpuUidUserSysTimeReader.Callback.class));
         // perClusterTimesAvailable is called twice, once in updateCpuTimeLocked() and the other
         // in readKernelUidCpuFreqTimesLocked.
-        verify(mKernelUidCpuFreqTimeReader, times(2)).perClusterTimesAvailable();
-        verify(mKernelUidCpuFreqTimeReader).readDelta(
-                any(KernelUidCpuFreqTimeReader.Callback.class));
-        verify(mKernelUidCpuActiveTimeReader).readDelta(
-                any(KernelUidCpuActiveTimeReader.Callback.class));
-        verify(mKernelUidCpuClusterTimeReader).readDelta(
-                any(KernelUidCpuClusterTimeReader.Callback.class));
-        verifyNoMoreInteractions(mKernelUidCpuFreqTimeReader);
+        verify(mCpuUidFreqTimeReader, times(2)).perClusterTimesAvailable();
+        verify(mCpuUidFreqTimeReader).readDelta(
+                any(KernelCpuUidFreqTimeReader.Callback.class));
+        verify(mCpuUidActiveTimeReader).readDelta(
+                any(KernelCpuUidActiveTimeReader.Callback.class));
+        verify(mCpuUidClusterTimeReader).readDelta(
+                any(KernelCpuUidClusterTimeReader.Callback.class));
+        verifyNoMoreInteractions(mCpuUidFreqTimeReader);
         for (int i = 0; i < numClusters; ++i) {
             verify(mKernelCpuSpeedReaders[i]).readDelta();
         }
@@ -251,13 +258,14 @@
                 {12, 34}, {34897394, 3123983}, {79775429834l, 8430434903489l}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuTimeReader.Callback callback =
-                    (KernelUidCpuTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
+                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuTime(testUids[i], uidTimesUs[i][0], uidTimesUs[i][1]);
+                callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
             }
             return null;
-        }).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
+        }).when(mCpuUidUserSysTimeReader).readDelta(
+                any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
         final SparseLongArray updatedUids = new SparseLongArray();
@@ -285,13 +293,14 @@
                 {9379, 3332409833484l}, {493247, 723234}, {3247819, 123348}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuTimeReader.Callback callback =
-                    (KernelUidCpuTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
+                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuTime(testUids[i], deltasUs[i][0], deltasUs[i][1]);
+                callback.onUidCpuTime(testUids[i], deltasUs[i]);
             }
             return null;
-        }).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
+        }).when(mCpuUidUserSysTimeReader).readDelta(
+                any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
@@ -324,13 +333,14 @@
                 {12, 34}, {34897394, 3123983}, {79775429834l, 8430434903489l}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuTimeReader.Callback callback =
-                    (KernelUidCpuTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
+                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuTime(testUids[i], uidTimesUs[i][0], uidTimesUs[i][1]);
+                callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
             }
             return null;
-        }).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
+        }).when(mCpuUidUserSysTimeReader).readDelta(
+                any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
@@ -348,7 +358,7 @@
             assertEquals("Unexpected system cpu time for uid=" + testUids[i],
                     uidTimesUs[i][1], u.getSystemCpuTimeUs(STATS_SINCE_CHARGED));
         }
-        verify(mKernelUidCpuTimeReader).removeUid(isolatedUid);
+        verify(mCpuUidUserSysTimeReader).removeUid(isolatedUid);
 
         // Add an isolated uid mapping and repeat the test.
 
@@ -359,13 +369,14 @@
                 {9379, 3332409833484l}, {493247, 723234}, {3247819, 123348}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuTimeReader.Callback callback =
-                    (KernelUidCpuTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
+                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuTime(testUids[i], deltasUs[i][0], deltasUs[i][1]);
+                callback.onUidCpuTime(testUids[i], deltasUs[i]);
             }
             return null;
-        }).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
+        }).when(mCpuUidUserSysTimeReader).readDelta(
+                any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
@@ -412,15 +423,16 @@
                 {12, 34}, {34897394, 3123983}, {79775429834l, 8430434903489l}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuTimeReader.Callback callback =
-                    (KernelUidCpuTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
+                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuTime(testUids[i], uidTimesUs[i][0], uidTimesUs[i][1]);
+                callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
             }
             // And one for the invalid uid
-            callback.onUidCpuTime(invalidUid, 3879, 239);
+            callback.onUidCpuTime(invalidUid, new long[]{3879, 239});
             return null;
-        }).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
+        }).when(mCpuUidUserSysTimeReader).readDelta(
+                any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuTimesLocked(null, null, true);
@@ -436,7 +448,7 @@
         }
         assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
                 mBatteryStatsImpl.getUidStats().get(invalidUid));
-        verify(mKernelUidCpuTimeReader).removeUid(invalidUid);
+        verify(mCpuUidUserSysTimeReader).removeUid(invalidUid);
     }
 
     @Test
@@ -460,13 +472,14 @@
                 {12, 34}, {3394, 3123}, {7977, 80434}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuTimeReader.Callback callback =
-                    (KernelUidCpuTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidUserSysTimeReader.Callback<long[]> callback =
+                    (KernelCpuUidUserSysTimeReader.Callback<long[]>) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuTime(testUids[i], uidTimesUs[i][0], uidTimesUs[i][1]);
+                callback.onUidCpuTime(testUids[i], uidTimesUs[i]);
             }
             return null;
-        }).when(mKernelUidCpuTimeReader).readDelta(any(KernelUidCpuTimeReader.Callback.class));
+        }).when(mCpuUidUserSysTimeReader).readDelta(
+                any(KernelCpuUidUserSysTimeReader.Callback.class));
 
         // RUN
         final SparseLongArray updatedUids = new SparseLongArray();
@@ -539,14 +552,14 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuFreqTimeReader.Callback callback =
-                    (KernelUidCpuFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback callback =
+                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuFreqTime(testUids[i], uidTimesMs[i]);
+                callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mKernelUidCpuFreqTimeReader).readDelta(
-                any(KernelUidCpuFreqTimeReader.Callback.class));
+        }).when(mCpuUidFreqTimeReader).readDelta(
+                any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
@@ -572,14 +585,14 @@
                 {43, 3345, 2143, 123, 4554}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuFreqTimeReader.Callback callback =
-                    (KernelUidCpuFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback callback =
+                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuFreqTime(testUids[i], deltasMs[i]);
+                callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mKernelUidCpuFreqTimeReader).readDelta(
-                any(KernelUidCpuFreqTimeReader.Callback.class));
+        }).when(mCpuUidFreqTimeReader).readDelta(
+                any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
@@ -622,15 +635,15 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuFreqTimeReader.Callback callback =
-                    (KernelUidCpuFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback callback =
+                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuFreqTime(testUids[i], uidTimesMs[i]);
+                callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mKernelUidCpuFreqTimeReader).readDelta(
-                any(KernelUidCpuFreqTimeReader.Callback.class));
-        when(mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
+        }).when(mCpuUidFreqTimeReader).readDelta(
+                any(KernelCpuUidFreqTimeReader.Callback.class));
+        when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
@@ -666,14 +679,14 @@
                 {43, 3345, 2143, 123, 4554}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuFreqTimeReader.Callback callback =
-                    (KernelUidCpuFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback callback =
+                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuFreqTime(testUids[i], deltasMs[i]);
+                callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mKernelUidCpuFreqTimeReader).readDelta(
-                any(KernelUidCpuFreqTimeReader.Callback.class));
+        }).when(mCpuUidFreqTimeReader).readDelta(
+                any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
@@ -732,15 +745,15 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuFreqTimeReader.Callback callback =
-                    (KernelUidCpuFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback callback =
+                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuFreqTime(testUids[i], uidTimesMs[i]);
+                callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mKernelUidCpuFreqTimeReader).readDelta(
-                any(KernelUidCpuFreqTimeReader.Callback.class));
-        when(mKernelUidCpuFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
+        }).when(mCpuUidFreqTimeReader).readDelta(
+                any(KernelCpuUidFreqTimeReader.Callback.class));
+        when(mCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(true);
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(partialTimers, true, false);
@@ -822,14 +835,14 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuFreqTimeReader.Callback callback =
-                    (KernelUidCpuFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback callback =
+                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuFreqTime(testUids[i], uidTimesMs[i]);
+                callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mKernelUidCpuFreqTimeReader).readDelta(
-                any(KernelUidCpuFreqTimeReader.Callback.class));
+        }).when(mCpuUidFreqTimeReader).readDelta(
+                any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
@@ -855,14 +868,14 @@
                 {43, 3345, 2143, 123, 4554, 9374983794839l, 979875}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuFreqTimeReader.Callback callback =
-                    (KernelUidCpuFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback callback =
+                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuFreqTime(testUids[i], deltasMs[i]);
+                callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mKernelUidCpuFreqTimeReader).readDelta(
-                any(KernelUidCpuFreqTimeReader.Callback.class));
+        }).when(mCpuUidFreqTimeReader).readDelta(
+                any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, true);
@@ -899,14 +912,14 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuFreqTimeReader.Callback callback =
-                    (KernelUidCpuFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback callback =
+                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuFreqTime(testUids[i], uidTimesMs[i]);
+                callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mKernelUidCpuFreqTimeReader).readDelta(
-                any(KernelUidCpuFreqTimeReader.Callback.class));
+        }).when(mCpuUidFreqTimeReader).readDelta(
+                any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
@@ -925,7 +938,7 @@
             assertNull("Unexpected screen-off cpu times for uid=" + testUids[i],
                     u.getScreenOffCpuFreqTimes(STATS_SINCE_CHARGED));
         }
-        verify(mKernelUidCpuFreqTimeReader).removeUid(isolatedUid);
+        verify(mCpuUidFreqTimeReader).removeUid(isolatedUid);
 
 
         // Add an isolated uid mapping and repeat the test.
@@ -939,14 +952,14 @@
                 {43, 3345, 2143, 123, 4554}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuFreqTimeReader.Callback callback =
-                    (KernelUidCpuFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback callback =
+                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuFreqTime(testUids[i], deltasMs[i]);
+                callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mKernelUidCpuFreqTimeReader).readDelta(
-                any(KernelUidCpuFreqTimeReader.Callback.class));
+        }).when(mCpuUidFreqTimeReader).readDelta(
+                any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
@@ -994,16 +1007,16 @@
                 {8, 25, 3, 0, 42}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuFreqTimeReader.Callback callback =
-                    (KernelUidCpuFreqTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidFreqTimeReader.Callback callback =
+                    (KernelCpuUidFreqTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuFreqTime(testUids[i], uidTimesMs[i]);
+                callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             // And one for the invalid uid
-            callback.onUidCpuFreqTime(invalidUid, new long[]{12, 839, 32, 34, 21});
+            callback.onUidCpuTime(invalidUid, new long[]{12, 839, 32, 34, 21});
             return null;
-        }).when(mKernelUidCpuFreqTimeReader).readDelta(
-                any(KernelUidCpuFreqTimeReader.Callback.class));
+        }).when(mCpuUidFreqTimeReader).readDelta(
+                any(KernelCpuUidFreqTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuFreqTimesLocked(null, true, false);
@@ -1020,7 +1033,7 @@
         }
         assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
                 mBatteryStatsImpl.getUidStats().get(invalidUid));
-        verify(mKernelUidCpuFreqTimeReader).removeUid(invalidUid);
+        verify(mCpuUidFreqTimeReader).removeUid(invalidUid);
     }
 
     @Test
@@ -1037,14 +1050,14 @@
         });
         final long[] uidTimesMs = {8000, 25000, 3000, 0, 42000};
         doAnswer(invocation -> {
-            final KernelUidCpuActiveTimeReader.Callback callback =
-                    (KernelUidCpuActiveTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidActiveTimeReader.Callback callback =
+                    (KernelCpuUidActiveTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuActiveTime(testUids[i], uidTimesMs[i]);
+                callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mKernelUidCpuActiveTimeReader).readDelta(
-                any(KernelUidCpuActiveTimeReader.Callback.class));
+        }).when(mCpuUidActiveTimeReader).readDelta(
+                any(KernelCpuUidActiveTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
@@ -1063,14 +1076,14 @@
         updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
         final long[] deltasMs = {43000, 3345000, 2143000, 123000, 4554000};
         doAnswer(invocation -> {
-            final KernelUidCpuActiveTimeReader.Callback callback =
-                    (KernelUidCpuActiveTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidActiveTimeReader.Callback callback =
+                    (KernelCpuUidActiveTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuActiveTime(testUids[i], deltasMs[i]);
+                callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mKernelUidCpuActiveTimeReader).readDelta(
-                any(KernelUidCpuActiveTimeReader.Callback.class));
+        }).when(mCpuUidActiveTimeReader).readDelta(
+                any(KernelCpuUidActiveTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
@@ -1101,16 +1114,16 @@
         });
         final long[] uidTimesMs = {8000, 25000, 3000, 0, 42000};
         doAnswer(invocation -> {
-            final KernelUidCpuActiveTimeReader.Callback callback =
-                    (KernelUidCpuActiveTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidActiveTimeReader.Callback callback =
+                    (KernelCpuUidActiveTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuActiveTime(testUids[i], uidTimesMs[i]);
+                callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             // And one for the invalid uid
-            callback.onUidCpuActiveTime(invalidUid, 1200L);
+            callback.onUidCpuTime(invalidUid, 1200L);
             return null;
-        }).when(mKernelUidCpuActiveTimeReader).readDelta(
-                any(KernelUidCpuActiveTimeReader.Callback.class));
+        }).when(mCpuUidActiveTimeReader).readDelta(
+                any(KernelCpuUidActiveTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuActiveTimesLocked(true);
@@ -1124,7 +1137,7 @@
         }
         assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
                 mBatteryStatsImpl.getUidStats().get(invalidUid));
-        verify(mKernelUidCpuActiveTimeReader).removeUid(invalidUid);
+        verify(mCpuUidActiveTimeReader).removeUid(invalidUid);
     }
 
     @Test
@@ -1145,14 +1158,14 @@
                 {8000, 0}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuClusterTimeReader.Callback callback =
-                    (KernelUidCpuClusterTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidClusterTimeReader.Callback callback =
+                    (KernelCpuUidClusterTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuPolicyTime(testUids[i], uidTimesMs[i]);
+                callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             return null;
-        }).when(mKernelUidCpuClusterTimeReader).readDelta(
-                any(KernelUidCpuClusterTimeReader.Callback.class));
+        }).when(mCpuUidClusterTimeReader).readDelta(
+                any(KernelCpuUidClusterTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
@@ -1175,14 +1188,14 @@
                 {43000, 3345000}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuClusterTimeReader.Callback callback =
-                    (KernelUidCpuClusterTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidClusterTimeReader.Callback callback =
+                    (KernelCpuUidClusterTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuPolicyTime(testUids[i], deltasMs[i]);
+                callback.onUidCpuTime(testUids[i], deltasMs[i]);
             }
             return null;
-        }).when(mKernelUidCpuClusterTimeReader).readDelta(
-                any(KernelUidCpuClusterTimeReader.Callback.class));
+        }).when(mCpuUidClusterTimeReader).readDelta(
+                any(KernelCpuUidClusterTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
@@ -1191,7 +1204,8 @@
         for (int i = 0; i < testUids.length; ++i) {
             final BatteryStats.Uid u = mBatteryStatsImpl.getUidStats().get(testUids[i]);
             assertNotNull("No entry for uid=" + testUids[i], u);
-            assertArrayEquals("Unexpected cpu cluster time for uid=" + testUids[i], sum(uidTimesMs[i], deltasMs[i]),
+            assertArrayEquals("Unexpected cpu cluster time for uid=" + testUids[i],
+                    sum(uidTimesMs[i], deltasMs[i]),
                     u.getCpuClusterTimes());
         }
     }
@@ -1217,16 +1231,16 @@
                 {8000, 0}
         };
         doAnswer(invocation -> {
-            final KernelUidCpuClusterTimeReader.Callback callback =
-                    (KernelUidCpuClusterTimeReader.Callback) invocation.getArguments()[0];
+            final KernelCpuUidClusterTimeReader.Callback callback =
+                    (KernelCpuUidClusterTimeReader.Callback) invocation.getArguments()[0];
             for (int i = 0; i < testUids.length; ++i) {
-                callback.onUidCpuPolicyTime(testUids[i], uidTimesMs[i]);
+                callback.onUidCpuTime(testUids[i], uidTimesMs[i]);
             }
             // And one for the invalid uid
-            callback.onUidCpuPolicyTime(invalidUid, new long[] {400, 1000});
+            callback.onUidCpuTime(invalidUid, new long[]{400, 1000});
             return null;
-        }).when(mKernelUidCpuClusterTimeReader).readDelta(
-                any(KernelUidCpuClusterTimeReader.Callback.class));
+        }).when(mCpuUidClusterTimeReader).readDelta(
+                any(KernelCpuUidClusterTimeReader.Callback.class));
 
         // RUN
         mBatteryStatsImpl.readKernelUidCpuClusterTimesLocked(true);
@@ -1240,7 +1254,7 @@
         }
         assertNull("There shouldn't be an entry for invalid uid=" + invalidUid,
                 mBatteryStatsImpl.getUidStats().get(invalidUid));
-        verify(mKernelUidCpuClusterTimeReader).removeUid(invalidUid);
+        verify(mCpuUidClusterTimeReader).removeUid(invalidUid);
     }
 
     @Test
@@ -1266,25 +1280,25 @@
         mClocks.realtime = mClocks.uptime = 400_000;
         mBatteryStatsImpl.clearPendingRemovedUids();
         assertEquals(1, mBatteryStatsImpl.getPendingRemovedUids().size());
-        verify(mKernelUidCpuActiveTimeReader).removeUid(1);
-        verify(mKernelUidCpuActiveTimeReader).removeUidsInRange(5, 10);
-        verify(mKernelUidCpuClusterTimeReader).removeUid(1);
-        verify(mKernelUidCpuClusterTimeReader).removeUidsInRange(5, 10);
-        verify(mKernelUidCpuFreqTimeReader).removeUid(1);
-        verify(mKernelUidCpuFreqTimeReader).removeUidsInRange(5, 10);
-        verify(mKernelUidCpuTimeReader).removeUid(1);
-        verify(mKernelUidCpuTimeReader).removeUidsInRange(5, 10);
+        verify(mCpuUidActiveTimeReader).removeUid(1);
+        verify(mCpuUidActiveTimeReader).removeUidsInRange(5, 10);
+        verify(mCpuUidClusterTimeReader).removeUid(1);
+        verify(mCpuUidClusterTimeReader).removeUidsInRange(5, 10);
+        verify(mCpuUidFreqTimeReader).removeUid(1);
+        verify(mCpuUidFreqTimeReader).removeUidsInRange(5, 10);
+        verify(mCpuUidUserSysTimeReader).removeUid(1);
+        verify(mCpuUidUserSysTimeReader).removeUidsInRange(5, 10);
 
         mClocks.realtime = mClocks.uptime = 800_000;
         mBatteryStatsImpl.clearPendingRemovedUids();
         assertEquals(0, mBatteryStatsImpl.getPendingRemovedUids().size());
-        verify(mKernelUidCpuActiveTimeReader).removeUid(100);
-        verify(mKernelUidCpuClusterTimeReader).removeUid(100);
-        verify(mKernelUidCpuFreqTimeReader).removeUid(100);
-        verify(mKernelUidCpuTimeReader).removeUid(100);
+        verify(mCpuUidActiveTimeReader).removeUid(100);
+        verify(mCpuUidClusterTimeReader).removeUid(100);
+        verify(mCpuUidFreqTimeReader).removeUid(100);
+        verify(mCpuUidUserSysTimeReader).removeUid(100);
 
-        verifyNoMoreInteractions(mKernelUidCpuActiveTimeReader, mKernelUidCpuClusterTimeReader,
-                mKernelUidCpuFreqTimeReader, mKernelUidCpuTimeReader);
+        verifyNoMoreInteractions(mCpuUidActiveTimeReader, mCpuUidClusterTimeReader,
+                mCpuUidFreqTimeReader, mCpuUidUserSysTimeReader);
     }
 
     private void updateTimeBasesLocked(boolean unplugged, int screenState,
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java
index 3a5a9f5..efb8710 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDualTimerTest.java
@@ -13,10 +13,12 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import android.os.BatteryStats;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
index 19dab79..a42286f 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
@@ -13,11 +13,13 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import android.os.BatteryStats;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
index 7467114..355601c 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
@@ -17,7 +17,6 @@
 
 package com.android.internal.os;
 
-
 import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -37,12 +36,13 @@
 import android.content.pm.PackageManager;
 import android.os.BatteryStats;
 import android.os.Process;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.text.format.DateUtils;
 import android.util.StatsLog;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import junit.framework.TestCase;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java
index 10a3189..cc0ddb7 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryTest.java
@@ -13,18 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import static org.junit.Assert.assertEquals;
-
 import android.content.Context;
 import android.os.Parcel;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
index 613de45..0771829 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static android.os.BatteryStats.STATS_SINCE_CHARGED;
@@ -31,12 +32,14 @@
 import static org.mockito.Mockito.when;
 
 import android.os.BatteryStats;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.Display;
 
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
 import com.android.internal.util.ArrayUtils;
 
 import org.junit.Before;
@@ -52,7 +55,7 @@
 @RunWith(AndroidJUnit4.class)
 public class BatteryStatsImplTest {
     @Mock
-    private KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader;
+    private KernelCpuUidFreqTimeReader mKernelUidCpuFreqTimeReader;
     @Mock
     private KernelSingleUidTimeReader mKernelSingleUidTimeReader;
 
@@ -65,7 +68,7 @@
         when(mKernelUidCpuFreqTimeReader.allUidTimesAvailable()).thenReturn(true);
         when(mKernelSingleUidTimeReader.singleUidCpuTimesAvailable()).thenReturn(true);
         mBatteryStatsImpl = new MockBatteryStatsImpl()
-                .setKernelUidCpuFreqTimeReader(mKernelUidCpuFreqTimeReader)
+                .setKernelCpuUidFreqTimeReader(mKernelUidCpuFreqTimeReader)
                 .setKernelSingleUidTimeReader(mKernelSingleUidTimeReader);
     }
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 8cbe5d6..3e33273 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -13,6 +13,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import static android.os.BatteryStats.STATS_CURRENT;
@@ -20,21 +21,20 @@
 import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
 
 import android.app.ActivityManager;
-import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.BatteryStats.HistoryItem;
 import android.os.BatteryStats.Uid.Sensor;
 import android.os.WorkSource;
-import android.support.test.filters.SmallTest;
 import android.view.Display;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.internal.os.BatteryStatsImpl.DualTimer;
 import com.android.internal.os.BatteryStatsImpl.Uid;
+
 import junit.framework.TestCase;
 
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -47,7 +47,7 @@
  * Install: adb install -r \
  *      ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class com.android.internal.os.BatteryStatsNoteTest -w \
- *      com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ *      com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  */
 public class BatteryStatsNoteTest extends TestCase {
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
index 251ceb0..61d20df 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
@@ -13,11 +13,13 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import android.os.BatteryStats;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
index a751f90..b851f0a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
@@ -13,13 +13,15 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import android.app.ActivityManager;
 import android.os.BatteryStats;
-import android.support.test.filters.SmallTest;
 import android.view.Display;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 /**
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
index 5fd8225..b9995c4 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
@@ -18,7 +18,8 @@
 
 import android.os.BatteryStats;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.Assert;
 import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java
index 015314e..f76f316 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsStopwatchTimerTest.java
@@ -13,10 +13,12 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
 import android.os.BatteryStats;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 225515e..a6329298 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import org.junit.runner.RunWith;
@@ -37,7 +38,6 @@
         BatteryStatsTimerTest.class,
         BatteryStatsUidTest.class,
         BatteryStatsUserLifecycleTests.class,
-        KernelCpuProcReaderTest.class,
         KernelCpuProcStringReaderTest.class,
         KernelCpuUidActiveTimeReaderTest.class,
         KernelCpuUidClusterTimeReaderTest.class,
@@ -45,9 +45,6 @@
         KernelCpuUidUserSysTimeReaderTest.class,
         KernelMemoryBandwidthStatsTest.class,
         KernelSingleUidTimeReaderTest.class,
-        KernelUidCpuFreqTimeReaderTest.class,
-        KernelUidCpuActiveTimeReaderTest.class,
-        KernelUidCpuClusterTimeReaderTest.class,
         KernelWakelockReaderTest.class,
         LongSamplingCounterTest.class,
         LongSamplingCounterArrayTest.class,
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
index 3190d9e..bce8b40 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
@@ -16,19 +16,20 @@
 
 package com.android.internal.os;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
 import android.os.BatteryStats;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
 import android.util.Log;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
 import org.mockito.Mockito;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
 /**
  * Provides test cases for android.os.BatteryStats.
  */
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
index 98d0f7f..87dc2f3 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
@@ -18,16 +18,17 @@
 
 import android.os.BatteryStats;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
 import android.util.StringBuilderPrinter;
 
-import junit.framework.Assert;
-import junit.framework.TestCase;
+import androidx.test.filters.SmallTest;
 
 import com.android.internal.os.BatteryStatsImpl.Clocks;
 import com.android.internal.os.BatteryStatsImpl.TimeBase;
 import com.android.internal.os.BatteryStatsImpl.Timer;
 
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
 /**
  * Provides test cases for android.os.BatteryStats.
  */
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
index a7e75a2..4df3190 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUidTest.java
@@ -16,22 +16,10 @@
 
 package com.android.internal.os;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
+import androidx.test.filters.SmallTest;
 
-import android.os.BatteryStats;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import junit.framework.Assert;
 import junit.framework.TestCase;
 
-import com.android.internal.os.BatteryStatsImpl;
-
-import org.mockito.Mockito;
-
 /**
  * Provides test cases for android.os.BatteryStats.
  */
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
index 450473d..e7a1bca 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsUserLifecycleTests.java
@@ -28,12 +28,13 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.support.test.uiautomator.UiDevice;
 import android.util.ArraySet;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.BeforeClass;
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index dc3a12f..1d35143 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -22,11 +22,12 @@
 import android.os.Binder;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.ArrayMap;
 import android.util.SparseArray;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.os.BinderInternal.CallSession;
 
 import org.junit.Assert;
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index 42c9139..01515bd 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static android.os.BatteryStats.UID_TIMES_TYPE_ALL;
@@ -33,9 +34,6 @@
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
 
-import com.android.frameworks.coretests.aidl.ICmdCallback;
-import com.android.frameworks.coretests.aidl.ICmdReceiver;
-
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.content.ComponentName;
@@ -52,14 +50,18 @@
 import android.os.Process;
 import android.os.SystemClock;
 import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.support.test.uiautomator.UiDevice;
 import android.text.TextUtils;
 import android.util.DebugUtils;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.coretests.aidl.ICmdCallback;
+import com.android.frameworks.coretests.aidl.ICmdReceiver;
+
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Rule;
diff --git a/core/tests/coretests/src/com/android/internal/os/DebugTest.java b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
index efb78d7..2a8a857 100644
--- a/core/tests/coretests/src/com/android/internal/os/DebugTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
@@ -18,7 +18,8 @@
 
 import android.os.Debug;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 @SmallTest
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java
deleted file mode 100644
index 8360126..0000000
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcReaderTest.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.os.FileUtils;
-import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.file.Files;
-import java.util.Arrays;
-import java.util.Random;
-
-/**
- * Test class for {@link KernelCpuProcReader}.
- *
- * $ atest FrameworksCoreTests:com.android.internal.os.KernelCpuProcReaderTest
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class KernelCpuProcReaderTest {
-
-    private File mRoot;
-    private File mTestDir;
-    private File mTestFile;
-    private Random mRand = new Random();
-
-    private KernelCpuProcReader mKernelCpuProcReader;
-
-    private Context getContext() {
-        return InstrumentationRegistry.getContext();
-    }
-
-    @Before
-    public void setUp() {
-        mTestDir = getContext().getDir("test", Context.MODE_PRIVATE);
-        mRoot = getContext().getFilesDir();
-        mTestFile = new File(mTestDir, "test.file");
-        mKernelCpuProcReader = new KernelCpuProcReader(mTestFile.getAbsolutePath());
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        FileUtils.deleteContents(mTestDir);
-        FileUtils.deleteContents(mRoot);
-    }
-
-
-    /**
-     * Tests that reading will return null if the file does not exist.
-     */
-    @Test
-    public void testReadInvalidFile() throws Exception {
-        assertEquals(null, mKernelCpuProcReader.readBytes());
-    }
-
-    /**
-     * Tests that reading will always return null after 5 failures.
-     */
-    @Test
-    public void testReadErrorsLimit() throws Exception {
-        mKernelCpuProcReader.setThrottleInterval(0);
-        for (int i = 0; i < 3; i++) {
-            assertNull(mKernelCpuProcReader.readBytes());
-            SystemClock.sleep(50);
-        }
-
-        final byte[] data = new byte[1024];
-        mRand.nextBytes(data);
-        try (OutputStream os = Files.newOutputStream(mTestFile.toPath())) {
-            os.write(data);
-        }
-        assertTrue(Arrays.equals(data, toArray(mKernelCpuProcReader.readBytes())));
-
-        assertTrue(mTestFile.delete());
-        for (int i = 0; i < 3; i++) {
-            assertNull(mKernelCpuProcReader.readBytes());
-            SystemClock.sleep(50);
-        }
-        try (OutputStream os = Files.newOutputStream(mTestFile.toPath())) {
-            os.write(data);
-        }
-        assertNull(mKernelCpuProcReader.readBytes());
-    }
-
-    /**
-     * Tests reading functionality.
-     */
-    @Test
-    public void testSimpleRead() throws Exception {
-        final byte[] data = new byte[1024];
-        mRand.nextBytes(data);
-        try (OutputStream os = Files.newOutputStream(mTestFile.toPath())) {
-            os.write(data);
-        }
-        assertTrue(Arrays.equals(data, toArray(mKernelCpuProcReader.readBytes())));
-    }
-
-    /**
-     * Tests multiple reading functionality.
-     */
-    @Test
-    public void testMultipleRead() throws Exception {
-        mKernelCpuProcReader.setThrottleInterval(0);
-        for (int i = 0; i < 100; i++) {
-            final byte[] data = new byte[mRand.nextInt(102400) + 4];
-            mRand.nextBytes(data);
-            try (OutputStream os = Files.newOutputStream(mTestFile.toPath())) {
-                os.write(data);
-            }
-            assertTrue(Arrays.equals(data, toArray(mKernelCpuProcReader.readBytes())));
-            assertTrue(mTestFile.delete());
-        }
-    }
-
-    /**
-     * Tests reading with resizing.
-     */
-    @Test
-    public void testReadWithResize() throws Exception {
-        final byte[] data = new byte[128001];
-        mRand.nextBytes(data);
-        try (OutputStream os = Files.newOutputStream(mTestFile.toPath())) {
-            os.write(data);
-        }
-        assertTrue(Arrays.equals(data, toArray(mKernelCpuProcReader.readBytes())));
-    }
-
-    /**
-     * Tests that reading a file over the limit (1MB) will return null.
-     */
-    @Test
-    public void testReadOverLimit() throws Exception {
-        final byte[] data = new byte[1228800];
-        mRand.nextBytes(data);
-        try (OutputStream os = Files.newOutputStream(mTestFile.toPath())) {
-            os.write(data);
-        }
-        assertNull(mKernelCpuProcReader.readBytes());
-    }
-
-    /**
-     * Tests throttling. Deleting underlying file should not affect cache.
-     */
-    @Test
-    public void testThrottle() throws Exception {
-        mKernelCpuProcReader.setThrottleInterval(3000);
-        final byte[] data = new byte[20001];
-        mRand.nextBytes(data);
-        try (OutputStream os = Files.newOutputStream(mTestFile.toPath())) {
-            os.write(data);
-        }
-        assertTrue(Arrays.equals(data, toArray(mKernelCpuProcReader.readBytes())));
-        assertTrue(mTestFile.delete());
-        for (int i = 0; i < 5; i++) {
-            assertTrue(Arrays.equals(data, toArray(mKernelCpuProcReader.readBytes())));
-            SystemClock.sleep(10);
-        }
-        SystemClock.sleep(5000);
-        assertNull(mKernelCpuProcReader.readBytes());
-    }
-
-    private byte[] toArray(ByteBuffer buffer) {
-        assertNotNull(buffer);
-        byte[] arr = new byte[buffer.remaining()];
-        buffer.get(arr);
-        return arr;
-    }
-}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java
index 2663f2b..cbd2ba4 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuProcStringReaderTest.java
@@ -24,9 +24,10 @@
 import android.content.Context;
 import android.os.FileUtils;
 import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
@@ -298,9 +299,10 @@
             assertTrue(mTestFile.delete());
             try (BufferedWriter w = Files.newBufferedWriter(mTestFile.toPath())) {
                 w.write(data1);
-                modify.countDown();
             } catch (Throwable e) {
                 errs.add(e);
+            } finally {
+                modify.countDown();
             }
         }, 600, TimeUnit.MILLISECONDS);
 
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
new file mode 100644
index 0000000..c03d1f3
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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.os;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.SystemClock;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.KernelCpuThreadReader.ProcessCpuUsage;
+import com.android.internal.os.KernelCpuThreadReader.ThreadCpuUsage;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.List;
+import java.util.OptionalDouble;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+/**
+ * End to end test for {@link KernelCpuThreadReader} that checks the accuracy of the reported times
+ * by spawning threads that do a predictable amount of work
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class KernelCpuThreadReaderEndToEndTest {
+
+    private static final int TIMED_NUM_SAMPLES = 5;
+    private static final int TIMED_START_MILLIS = 500;
+    private static final int TIMED_END_MILLIS = 2000;
+    private static final int TIMED_INCREMENT_MILLIS = 500;
+    private static final int TIMED_COMPARISON_DELTA_MILLIS = 200;
+
+    private static final int ITERATIVE_NUM_SAMPLES = 100;
+    private static final long ITERATIVE_LOW_ITERATIONS = (long) 1e8;
+    private static final long ITERATIVE_HIGH_ITERATIONS = (long) 2e8;
+    private static final double ITERATIONS_COMPARISONS_DELTA = 0.25;
+
+    /**
+     * Test that when we busy-wait for the thread-local time to reach N seconds, the time reported
+     * is also N seconds. Takes ~10s.
+     */
+    @Test
+    public void testTimedWork() throws InterruptedException {
+        for (int millis = TIMED_START_MILLIS;
+                millis <= TIMED_END_MILLIS;
+                millis += TIMED_INCREMENT_MILLIS) {
+            final Duration targetDuration = Duration.ofMillis(millis);
+            final Runnable work = timedWork(targetDuration);
+            Duration resultDuration = getAverageWorkTime(
+                    work, String.format("timed%dms", millis), TIMED_NUM_SAMPLES);
+            assertEquals(
+                    "Time worked according to currentThreadTimeMillis doesn't match "
+                            + "KernelCpuThreadReader",
+                    targetDuration.toMillis(), resultDuration.toMillis(),
+                    TIMED_COMPARISON_DELTA_MILLIS);
+        }
+    }
+
+    /**
+     * Test that when we scale up the amount of work by N, the time reported also scales by N. Takes
+     * ~15s.
+     */
+    @Test
+    public void testIterativeWork() throws InterruptedException {
+        final Runnable lowAmountWork = iterativeWork(ITERATIVE_LOW_ITERATIONS);
+        final Runnable highAmountWork = iterativeWork(ITERATIVE_HIGH_ITERATIONS);
+        final Duration lowResultDuration =
+                getAverageWorkTime(lowAmountWork, "iterlow", ITERATIVE_NUM_SAMPLES);
+        final Duration highResultDuration =
+                getAverageWorkTime(highAmountWork, "iterhigh", ITERATIVE_NUM_SAMPLES);
+        assertEquals(
+                "Work scale and CPU time scale do not match",
+                ((double) ITERATIVE_HIGH_ITERATIONS) / ((double) ITERATIVE_LOW_ITERATIONS),
+                ((double) highResultDuration.toMillis()) / ((double) lowResultDuration.toMillis()),
+                ITERATIONS_COMPARISONS_DELTA);
+    }
+
+    /**
+     * Run some work {@code numSamples} times, and take the average CPU duration used for that work
+     * according to {@link KernelCpuThreadReader}
+     */
+    private Duration getAverageWorkTime(
+            Runnable work, String tag, int numSamples) throws InterruptedException {
+        // Count down every time a thread finishes work, so that we can wait for work to complete
+        final CountDownLatch workFinishedLatch = new CountDownLatch(numSamples);
+        // Count down once when threads can terminate (after we get them from
+        // `KernelCpuThreadReader`)
+        final CountDownLatch threadFinishedLatch = new CountDownLatch(1);
+
+        // Start `NUM_SAMPLE` threads to do the work
+        for (int i = 0; i < numSamples; i++) {
+            final String threadName = String.format("%s%d", tag, i);
+            // Check the thread name, as we rely on it later to identify threads
+            assertTrue("Max name length for linux threads is 15", threadName.length() <= 15);
+            doWork(work, threadName, workFinishedLatch, threadFinishedLatch);
+        }
+
+        // Wait for threads to finish
+        workFinishedLatch.await();
+
+        // Get thread data from KernelCpuThreadReader
+        final KernelCpuThreadReader kernelCpuThreadReader = KernelCpuThreadReader.create();
+        assertNotNull(kernelCpuThreadReader);
+        final ProcessCpuUsage currentProcessCpuUsage =
+                kernelCpuThreadReader.getCurrentProcessCpuUsage();
+
+        // Threads can terminate, as we've finished crawling them from /proc
+        threadFinishedLatch.countDown();
+
+        // Check that we've got times for every thread we spawned
+        final List<ThreadCpuUsage> threadCpuUsages = currentProcessCpuUsage.threadCpuUsages
+                .stream()
+                .filter((thread) -> thread.threadName.startsWith(tag))
+                .collect(Collectors.toList());
+        assertEquals(
+                "Incorrect number of threads returned by KernelCpuThreadReader",
+                numSamples, threadCpuUsages.size());
+
+        // Calculate the average time spent working
+        final OptionalDouble averageWorkTimeMillis = threadCpuUsages.stream()
+                .mapToDouble((t) -> Arrays.stream(t.usageTimesMillis).sum())
+                .average();
+        assertTrue(averageWorkTimeMillis.isPresent());
+        return Duration.ofMillis((long) averageWorkTimeMillis.getAsDouble());
+    }
+
+    /**
+     * Work that lasts {@code duration} according to {@link SystemClock#currentThreadTimeMillis()}
+     */
+    private Runnable timedWork(Duration duration) {
+        return () -> {
+            // Busy loop until `duration` has elapsed for the thread timer
+            final long startTimeMillis = SystemClock.currentThreadTimeMillis();
+            final long durationMillis = duration.toMillis();
+            while (true) {
+                final long elapsedMillis = SystemClock.currentThreadTimeMillis() - startTimeMillis;
+                if (elapsedMillis >= durationMillis) {
+                    break;
+                }
+            }
+        };
+    }
+
+    /**
+     * Work that iterates {@code iterations} times
+     */
+    private Runnable iterativeWork(long iterations) {
+        Consumer<Long> empty = (i) -> {
+        };
+        return () -> {
+            long count = 0;
+            for (long i = 0; i < iterations; i++) {
+                // Alternate branching to reduce effect of branch prediction
+                if (i % 2 == 0) {
+                    count++;
+                }
+            }
+            // Call empty function with value to avoid loop getting optimized away
+            empty.accept(count);
+        };
+    }
+
+    /**
+     * Perform some work in another thread
+     *
+     * @param work                the work to perform
+     * @param threadName          the name of the spawned thread
+     * @param workFinishedLatch   latch to register that the work has been completed
+     * @param threadFinishedLatch latch to pause termination of the thread until the latch is
+     *                            decremented
+     */
+    private void doWork(
+            Runnable work,
+            String threadName,
+            CountDownLatch workFinishedLatch,
+            CountDownLatch threadFinishedLatch) {
+        Runnable workWrapped = () -> {
+            // Do the work
+            work.run();
+            // Notify that the work is finished
+            workFinishedLatch.countDown();
+            // Wait until `threadFinishLatch` has been released in order to keep the thread alive so
+            // we can see it in `proc` filesystem
+            try {
+                threadFinishedLatch.await();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        };
+        new Thread(workWrapped, threadName).start();
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
index b242a34..0c56b8a 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
@@ -23,9 +23,10 @@
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
index adafda0..1b13a99 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static org.junit.Assert.assertEquals;
@@ -20,11 +21,12 @@
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseLongArray;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
 
 import org.junit.After;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
index ad20d84..2ea80da 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -22,11 +23,12 @@
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
 
 import org.junit.After;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
index 1d3a98a..0b6fed3 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -24,11 +25,12 @@
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
 
 import org.junit.After;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
index 9b4512b..8f81ea2 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidUserSysTimeReaderTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.os;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -23,11 +24,12 @@
 import android.content.Context;
 import android.os.FileUtils;
 import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
 
 import org.junit.After;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java b/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java
index 32317ee..60dac85 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelMemoryBandwidthStatsTest.java
@@ -1,11 +1,27 @@
+/*
+ * 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.internal.os;
 
-import android.support.test.filters.SmallTest;
 import android.util.LongSparseLongArray;
 
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
-import org.junit.Assert;
 import org.mockito.Mockito;
 
 import java.io.BufferedReader;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
index 29227f9..479e19e 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
@@ -21,10 +21,11 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.SparseArray;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.internal.os.KernelSingleUidTimeReader.Injector;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java
deleted file mode 100644
index 28570e8..0000000
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuActiveTimeReaderTest.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Random;
-
-/**
- * Test class for {@link KernelUidCpuActiveTimeReader}.
- *
- * To run it:
- * bit FrameworksCoreTests:com.android.internal.os.KernelUidCpuActiveTimeReaderTest
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class KernelUidCpuActiveTimeReaderTest {
-    @Mock
-    private KernelCpuProcReader mProcReader;
-    @Mock
-    private KernelUidCpuActiveTimeReader.Callback mCallback;
-    private KernelUidCpuActiveTimeReader mReader;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mReader = new KernelUidCpuActiveTimeReader(mProcReader);
-        mReader.setThrottleInterval(0);
-    }
-
-    @Test
-    public void testReadDelta() {
-        final int cores = 8;
-        final int[] uids = {1, 22, 333, 4444, 5555};
-
-        final long[][] times = increaseTime(new long[uids.length][cores]);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times));
-        mReader.readDelta(mCallback);
-        for (int i = 0; i < uids.length; i++) {
-            verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(times[i]));
-        }
-        verifyNoMoreInteractions(mCallback);
-
-        // Verify that a second call will only return deltas.
-        Mockito.reset(mCallback);
-        final long[][] times1 = increaseTime(times);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times1));
-        mReader.readDelta(mCallback);
-        for (int i = 0; i < uids.length; i++) {
-            verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times1[i], times[i])));
-        }
-        verifyNoMoreInteractions(mCallback);
-
-        // Verify that there won't be a callback if the proc file values didn't change.
-        Mockito.reset(mCallback);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times1));
-        mReader.readDelta(mCallback);
-        verifyNoMoreInteractions(mCallback);
-
-        // Verify that calling with a null callback doesn't result in any crashes
-        Mockito.reset(mCallback);
-        final long[][] times2 = increaseTime(times1);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times2));
-        mReader.readDelta(null);
-
-        // Verify that the readDelta call will only return deltas when
-        // the previous call had null callback.
-        Mockito.reset(mCallback);
-        final long[][] times3 = increaseTime(times2);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times3));
-        mReader.readDelta(mCallback);
-        for (int i = 0; i < uids.length; ++i) {
-            verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times3[i], times2[i])));
-        }
-        verifyNoMoreInteractions(mCallback);
-    }
-
-    @Test
-    public void testReadAbsolute() {
-        final int cores = 8;
-        final int[] uids = {1, 22, 333, 4444, 5555};
-
-        final long[][] times = increaseTime(new long[uids.length][cores]);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times));
-        mReader.readAbsolute(mCallback);
-        for (int i = 0; i < uids.length; i++) {
-            verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(times[i]));
-        }
-        verifyNoMoreInteractions(mCallback);
-
-        // Verify that a second call still returns absolute values
-        Mockito.reset(mCallback);
-        final long[][] times1 = increaseTime(times);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times1));
-        mReader.readAbsolute(mCallback);
-        for (int i = 0; i < uids.length; i++) {
-            verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(times1[i]));
-        }
-        verifyNoMoreInteractions(mCallback);
-    }
-
-    @Test
-    public void testReadDelta_malformedData() {
-        final int cores = 8;
-        final int[] uids = {1, 22, 333, 4444, 5555};
-        final long[][] times = increaseTime(new long[uids.length][cores]);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times));
-        mReader.readDelta(mCallback);
-        for (int i = 0; i < uids.length; i++) {
-            verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(times[i]));
-        }
-        verifyNoMoreInteractions(mCallback);
-
-        // Verify that there is no callback if subsequent call is in wrong format.
-        Mockito.reset(mCallback);
-        final long[][] times1 = increaseTime(times);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times1).putInt(0, 5));
-        mReader.readDelta(mCallback);
-        verifyNoMoreInteractions(mCallback);
-
-        // Verify that the internal state was not modified if the given core count does not match
-        // the following # of entries.
-        Mockito.reset(mCallback);
-        final long[][] times2 = increaseTime(times);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times2));
-        mReader.readDelta(mCallback);
-        for (int i = 0; i < uids.length; i++) {
-            verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times2[i], times[i])));
-        }
-        verifyNoMoreInteractions(mCallback);
-
-        // Verify that there is no callback if any value in the proc file is -ve.
-        Mockito.reset(mCallback);
-        final long[][] times3 = increaseTime(times2);
-        times3[uids.length - 1][cores - 1] *= -1;
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times3));
-        mReader.readDelta(mCallback);
-        for (int i = 0; i < uids.length - 1; ++i) {
-            verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times3[i], times2[i])));
-        }
-        verifyNoMoreInteractions(mCallback);
-
-        // Verify that the internal state was not modified when the proc file had -ve value.
-        Mockito.reset(mCallback);
-        for (int i = 0; i < cores; i++) {
-            times3[uids.length - 1][i] = times2[uids.length - 1][i] + uids[uids.length - 1] * 2520;
-        }
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times3));
-        mReader.readDelta(mCallback);
-        verify(mCallback).onUidCpuActiveTime(uids[uids.length - 1],
-                getTotal(subtract(times3[uids.length - 1], times2[uids.length - 1])));
-        verifyNoMoreInteractions(mCallback);
-
-        // Verify that there is no callback if the values in the proc file are decreased.
-        Mockito.reset(mCallback);
-        final long[][] times4 = increaseTime(times3);
-        System.arraycopy(times3[uids.length - 1], 0, times4[uids.length - 1], 0, cores);
-        times4[uids.length - 1][cores - 1] -= 100;
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times4));
-        mReader.readDelta(mCallback);
-        for (int i = 0; i < uids.length - 1; ++i) {
-            verify(mCallback).onUidCpuActiveTime(uids[i], getTotal(subtract(times4[i], times3[i])));
-        }
-        verifyNoMoreInteractions(mCallback);
-
-        // Verify that the internal state was not modified when the proc file had decreased values.
-        Mockito.reset(mCallback);
-        for (int i = 0; i < cores; i++) {
-            times4[uids.length - 1][i] = times3[uids.length - 1][i] + uids[uids.length - 1] * 2520;
-        }
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times4));
-        mReader.readDelta(mCallback);
-        verify(mCallback).onUidCpuActiveTime(uids[uids.length - 1],
-                getTotal(subtract(times4[uids.length - 1], times3[uids.length - 1])));
-        verifyNoMoreInteractions(mCallback);
-    }
-
-    private long[] subtract(long[] a1, long[] a2) {
-        long[] val = new long[a1.length];
-        for (int i = 0; i < val.length; ++i) {
-            val[i] = a1[i] - a2[i];
-        }
-        return val;
-    }
-
-    /**
-     * Unit of original and return value is 10ms. What's special about 2520? 2520 is LCM of 1, 2, 3,
-     * ..., 10. So that when wedivide shared cpu time by concurrent thread count, we always get a
-     * nice integer, avoiding rounding errors.
-     */
-    private long[][] increaseTime(long[][] original) {
-        long[][] newTime = new long[original.length][original[0].length];
-        Random rand = new Random();
-        for (int i = 0; i < original.length; i++) {
-            for (int j = 0; j < original[0].length; j++) {
-                newTime[i][j] = original[i][j] + rand.nextInt(1000) * 2520 + 2520;
-            }
-        }
-        return newTime;
-    }
-
-    // Unit of times is 10ms
-    private long getTotal(long[] times) {
-        long sum = 0;
-        for (int i = 0; i < times.length; i++) {
-            sum += times[i] * 10 / (i + 1);
-        }
-        return sum;
-    }
-
-    /**
-     * Format uids and times (in 10ms) into the following format:
-     * [n, uid0, time0a, time0b, ..., time0n,
-     * uid1, time1a, time1b, ..., time1n,
-     * uid2, time2a, time2b, ..., time2n, etc.]
-     * where n is the total number of cpus (num_possible_cpus)
-     */
-    private ByteBuffer getUidTimesBytes(int[] uids, long[][] times) {
-        int size = (1 + uids.length * (times[0].length + 1)) * 4;
-        ByteBuffer buf = ByteBuffer.allocate(size);
-        buf.order(ByteOrder.nativeOrder());
-        buf.putInt(times[0].length);
-        for (int i = 0; i < uids.length; i++) {
-            buf.putInt(uids[i]);
-            for (int j = 0; j < times[i].length; j++) {
-                buf.putInt((int) times[i][j]);
-            }
-        }
-        buf.flip();
-        return buf.order(ByteOrder.nativeOrder());
-    }
-}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java
deleted file mode 100644
index 85dce02..0000000
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuClusterTimeReaderTest.java
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.when;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.util.SparseArray;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-import java.util.Random;
-
-/**
- * Test class for {@link KernelUidCpuClusterTimeReader}.
- *
- * To run it:
- * bit FrameworksCoreTests:com.android.internal.os.KernelUidCpuClusterTimeReaderTest
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class KernelUidCpuClusterTimeReaderTest {
-    @Mock
-    private KernelCpuProcReader mProcReader;
-    private KernelUidCpuClusterTimeReader mReader;
-    private VerifiableCallback mCallback;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mReader = new KernelUidCpuClusterTimeReader(mProcReader);
-        mCallback = new VerifiableCallback();
-        mReader.setThrottleInterval(0);
-    }
-
-    @Test
-    public void testReadDelta() throws Exception {
-        VerifiableCallback cb = new VerifiableCallback();
-        final int cores = 6;
-        final int[] clusters = {2, 4};
-        final int[] uids = {1, 22, 333, 4444, 5555};
-
-        // Verify initial call
-        final long[][] times = increaseTime(new long[uids.length][cores]);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times));
-        mReader.readDelta(cb);
-        for (int i = 0; i < uids.length; i++) {
-            cb.verify(uids[i], getTotal(clusters, times[i]));
-        }
-        cb.verifyNoMoreInteractions();
-
-        // Verify that a second call will only return deltas.
-        cb.clear();
-        Mockito.reset(mProcReader);
-        final long[][] times1 = increaseTime(times);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times1));
-        mReader.readDelta(cb);
-        for (int i = 0; i < uids.length; i++) {
-            cb.verify(uids[i], getTotal(clusters, subtract(times1[i], times[i])));
-        }
-        cb.verifyNoMoreInteractions();
-
-        // Verify that there won't be a callback if the proc file values didn't change.
-        cb.clear();
-        Mockito.reset(mProcReader);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times1));
-        mReader.readDelta(cb);
-        cb.verifyNoMoreInteractions();
-
-        // Verify that calling with a null callback doesn't result in any crashes
-        Mockito.reset(mProcReader);
-        final long[][] times2 = increaseTime(times1);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times2));
-        mReader.readDelta(null);
-
-        // Verify that the readDelta call will only return deltas when
-        // the previous call had null callback.
-        cb.clear();
-        Mockito.reset(mProcReader);
-        final long[][] times3 = increaseTime(times2);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times3));
-        mReader.readDelta(cb);
-        for (int i = 0; i < uids.length; i++) {
-            cb.verify(uids[i], getTotal(clusters, subtract(times3[i], times2[i])));
-        }
-        cb.verifyNoMoreInteractions();
-
-    }
-
-    @Test
-    public void testReadAbsolute() throws Exception {
-        VerifiableCallback cb = new VerifiableCallback();
-        final int cores = 6;
-        final int[] clusters = {2, 4};
-        final int[] uids = {1, 22, 333, 4444, 5555};
-
-        // Verify return absolute value
-        final long[][] times = increaseTime(new long[uids.length][cores]);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times));
-        mReader.readAbsolute(cb);
-        for (int i = 0; i < uids.length; i++) {
-            cb.verify(uids[i], getTotal(clusters, times[i]));
-        }
-        cb.verifyNoMoreInteractions();
-
-        // Verify that a second call should return the same absolute value
-        cb.clear();
-        Mockito.reset(mProcReader);
-        final long[][] times1 = increaseTime(times);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times1));
-        mReader.readAbsolute(cb);
-        for (int i = 0; i < uids.length; i++) {
-            cb.verify(uids[i], getTotal(clusters, times1[i]));
-        }
-        cb.verifyNoMoreInteractions();
-    }
-
-    @Test
-    public void testReadDelta_malformedData() throws Exception {
-        final int cores = 6;
-        final int[] clusters = {2, 4};
-        final int[] uids = {1, 22, 333, 4444, 5555};
-
-        // Verify initial call
-        final long[][] times = increaseTime(new long[uids.length][cores]);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times));
-        mReader.readDelta(mCallback);
-        for (int i = 0; i < uids.length; i++) {
-            mCallback.verify(uids[i], getTotal(clusters, times[i]));
-        }
-        mCallback.verifyNoMoreInteractions();
-
-        // Verify that there is no callback if a call has wrong format
-        mCallback.clear();
-        Mockito.reset(mProcReader);
-        final long[][] temp = increaseTime(times);
-        final long[][] times1 = new long[uids.length][];
-        for (int i = 0; i < temp.length; i++) {
-            times1[i] = Arrays.copyOfRange(temp[i], 0, 4);
-        }
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times1));
-        mReader.readDelta(mCallback);
-        mCallback.verifyNoMoreInteractions();
-
-        // Verify that the internal state was not modified if the given core count does not match
-        // the following # of entries.
-        mCallback.clear();
-        Mockito.reset(mProcReader);
-        final long[][] times2 = increaseTime(times);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times2));
-        mReader.readDelta(mCallback);
-        for (int i = 0; i < uids.length; i++) {
-            mCallback.verify(uids[i], getTotal(clusters, subtract(times2[i], times[i])));
-        }
-        mCallback.verifyNoMoreInteractions();
-
-        // Verify that there is no callback if any value in the proc file is -ve.
-        mCallback.clear();
-        Mockito.reset(mProcReader);
-        final long[][] times3 = increaseTime(times2);
-        times3[uids.length - 1][cores - 1] *= -1;
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times3));
-        mReader.readDelta(mCallback);
-        for (int i = 0; i < uids.length - 1; i++) {
-            mCallback.verify(uids[i], getTotal(clusters, subtract(times3[i], times2[i])));
-        }
-        mCallback.verifyNoMoreInteractions();
-
-        // Verify that the internal state was not modified when the proc file had -ve value.
-        mCallback.clear();
-        Mockito.reset(mProcReader);
-        for (int i = 0; i < cores; i++) {
-            times3[uids.length - 1][i] = times2[uids.length - 1][i] + uids[uids.length - 1] * 2520;
-        }
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times3));
-        mReader.readDelta(mCallback);
-        mCallback.verify(uids[uids.length - 1],
-                getTotal(clusters, subtract(times3[uids.length - 1], times2[uids.length - 1])));
-
-        // Verify that there is no callback if the values in the proc file are decreased.
-        mCallback.clear();
-        Mockito.reset(mProcReader);
-        final long[][] times4 = increaseTime(times3);
-        System.arraycopy(times3[uids.length - 1], 0, times4[uids.length - 1], 0, cores);
-        times4[uids.length - 1][cores - 1] -= 100;
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times4));
-        mReader.readDelta(mCallback);
-        for (int i = 0; i < uids.length - 1; i++) {
-            mCallback.verify(uids[i], getTotal(clusters, subtract(times4[i], times3[i])));
-        }
-        mCallback.verifyNoMoreInteractions();
-
-        // Verify that the internal state was not modified when the proc file had decreased values.
-        mCallback.clear();
-        Mockito.reset(mProcReader);
-        for (int i = 0; i < cores; i++) {
-            times4[uids.length - 1][i] = times3[uids.length - 1][i] + uids[uids.length - 1] * 2520;
-        }
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, clusters, times4));
-        mReader.readDelta(mCallback);
-        mCallback.verify(uids[uids.length - 1],
-                getTotal(clusters, subtract(times3[uids.length - 1], times2[uids.length - 1])));
-        mCallback.verifyNoMoreInteractions();
-    }
-
-
-    private long[] subtract(long[] a1, long[] a2) {
-        long[] val = new long[a1.length];
-        for (int i = 0; i < val.length; ++i) {
-            val[i] = a1[i] - a2[i];
-        }
-        return val;
-    }
-
-    /**
-     * Unit is 10ms. What's special about 2520? 2520 is LCM of 1, 2, 3, ..., 10. So that when we
-     * divide shared cpu time by concurrent thread count, we always get a nice integer, avoiding
-     * rounding errors.
-     */
-    private long[][] increaseTime(long[][] original) {
-        long[][] newTime = new long[original.length][original[0].length];
-        Random rand = new Random();
-        for (int i = 0; i < original.length; i++) {
-            for (int j = 0; j < original[0].length; j++) {
-                newTime[i][j] = original[i][j] + rand.nextInt(1000) * 2520 + 2520;
-            }
-        }
-        return newTime;
-    }
-
-    // Format an array of cluster times according to the algorithm in KernelUidCpuClusterTimeReader
-    private long[] getTotal(int[] cluster, long[] times) {
-        int core = 0;
-        long[] sumTimes = new long[cluster.length];
-        for (int i = 0; i < cluster.length; i++) {
-            double sum = 0;
-            for (int j = 0; j < cluster[i]; j++) {
-                sum += (double) times[core++] * 10 / (j + 1);
-            }
-            sumTimes[i] = (long) sum;
-        }
-        return sumTimes;
-    }
-
-    private class VerifiableCallback implements KernelUidCpuClusterTimeReader.Callback {
-
-        SparseArray<long[]> mData = new SparseArray<>();
-        int count = 0;
-
-        public void verify(int uid, long[] cpuClusterTimeMs) {
-            long[] array = mData.get(uid);
-            assertNotNull(array);
-            assertArrayEquals(cpuClusterTimeMs, array);
-            count++;
-        }
-
-        public void clear() {
-            mData.clear();
-            count = 0;
-        }
-
-        @Override
-        public void onUidCpuPolicyTime(int uid, long[] cpuClusterTimeMs) {
-            long[] array = new long[cpuClusterTimeMs.length];
-            System.arraycopy(cpuClusterTimeMs, 0, array, 0, array.length);
-            mData.put(uid, array);
-        }
-
-        public void verifyNoMoreInteractions() {
-            assertEquals(mData.size(), count);
-        }
-    }
-
-    /**
-     * Format uids and times (in 10ms) into the following format:
-     * [n, x0, ..., xn, uid0, time0a, time0b, ..., time0n,
-     * uid1, time1a, time1b, ..., time1n,
-     * uid2, time2a, time2b, ..., time2n, etc.]
-     * where n is the number of policies
-     * xi is the number cpus on a particular policy
-     */
-    private ByteBuffer getUidTimesBytes(int[] uids, int[] clusters, long[][] times) {
-        int size = (1 + clusters.length + uids.length * (times[0].length + 1)) * 4;
-        ByteBuffer buf = ByteBuffer.allocate(size);
-        buf.order(ByteOrder.nativeOrder());
-        buf.putInt(clusters.length);
-        for (int i = 0; i < clusters.length; i++) {
-            buf.putInt(clusters[i]);
-        }
-        for (int i = 0; i < uids.length; i++) {
-            buf.putInt(uids[i]);
-            for (int j = 0; j < times[i].length; j++) {
-                buf.putInt((int) (times[i][j]));
-            }
-        }
-        buf.flip();
-        return buf.order(ByteOrder.nativeOrder());
-    }
-}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
deleted file mode 100644
index 67c4e61..0000000
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.util.SparseArray;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.io.BufferedReader;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-
-/**
- * Test class for {@link KernelUidCpuFreqTimeReader}.
- *
- * To run the tests, use
- *
- * runtest -c com.android.internal.os.KernelUidCpuFreqTimeReaderTest frameworks-core
- *
- * or the following steps:
- *
- * Build: m FrameworksCoreTests
- * Install: adb install -r \
- * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
- * Run: adb shell am instrument -e class com.android.internal.os.KernelUidCpuFreqTimeReaderTest -w \
- * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
- *
- * or
- *
- * bit FrameworksCoreTests:com.android.internal.os.KernelUidCpuFreqTimeReaderTest
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class KernelUidCpuFreqTimeReaderTest {
-    @Mock
-    private BufferedReader mBufferedReader;
-    @Mock
-    private KernelUidCpuFreqTimeReader.Callback mCallback;
-    @Mock
-    private PowerProfile mPowerProfile;
-    @Mock
-    private KernelCpuProcReader mProcReader;
-
-    private KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mKernelUidCpuFreqTimeReader = new KernelUidCpuFreqTimeReader(mProcReader);
-        mKernelUidCpuFreqTimeReader.setThrottleInterval(0);
-    }
-
-    @Test
-    public void testReadFreqs_perClusterTimesNotAvailable() throws Exception {
-        final long[][] freqs = {
-                {1, 12, 123, 1234},
-                {1, 12, 123, 23, 123, 1234, 12345, 123456},
-                {1, 12, 123, 23, 123, 1234, 12345, 123456, 12, 123, 12345},
-                {1, 12, 123, 23, 2345, 234567}
-        };
-        final int[] numClusters = {2, 2, 3, 1};
-        final int[][] numFreqs = {{3, 6}, {4, 5}, {3, 5, 4}, {3}};
-        for (int i = 0; i < freqs.length; ++i) {
-            setCpuClusterFreqs(numClusters[i], numFreqs[i]);
-            when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs[i]));
-            long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(
-                    mBufferedReader, mPowerProfile);
-            assertArrayEquals(freqs[i], actualFreqs);
-            verifyZeroInteractions(mCallback);
-            final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s",
-                    Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i]));
-            assertFalse(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable());
-
-            // Verify that a second call won't read the proc file again
-            Mockito.reset(mBufferedReader);
-            actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile);
-            assertArrayEquals(freqs[i], actualFreqs);
-            assertFalse(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable());
-
-            // Prepare for next iteration
-            Mockito.reset(mBufferedReader, mPowerProfile);
-        }
-    }
-
-    @Test
-    public void testReadFreqs_perClusterTimesAvailable() throws Exception {
-        final long[][] freqs = {
-                {1, 12, 123, 1234},
-                {1, 12, 123, 23, 123, 1234, 12345, 123456},
-                {1, 12, 123, 23, 123, 1234, 12345, 123456, 12, 123, 12345, 1234567}
-        };
-        final int[] numClusters = {1, 2, 3};
-        final int[][] numFreqs = {{4}, {3, 5}, {3, 5, 4}};
-        for (int i = 0; i < freqs.length; ++i) {
-            setCpuClusterFreqs(numClusters[i], numFreqs[i]);
-            when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs[i]));
-            long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(
-                    mBufferedReader, mPowerProfile);
-            assertArrayEquals(freqs[i], actualFreqs);
-            verifyZeroInteractions(mCallback);
-            final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s",
-                    Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i]));
-            assertTrue(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable());
-
-            // Verify that a second call won't read the proc file again
-            Mockito.reset(mBufferedReader);
-            actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mPowerProfile);
-            assertArrayEquals(freqs[i], actualFreqs);
-            assertTrue(errMsg, mKernelUidCpuFreqTimeReader.perClusterTimesAvailable());
-
-            // Prepare for next iteration
-            Mockito.reset(mBufferedReader, mPowerProfile);
-        }
-    }
-
-    @Test
-    public void testReadDelta_Binary() throws Exception {
-        VerifiableCallback cb = new VerifiableCallback();
-        final long[] freqs = {110, 123, 145, 167, 289, 997};
-        final int[] uids = {1, 22, 333, 444, 555};
-        final long[][] times = new long[uids.length][freqs.length];
-        for (int i = 0; i < uids.length; ++i) {
-            for (int j = 0; j < freqs.length; ++j) {
-                times[i][j] = uids[i] * freqs[j] * 10;
-            }
-        }
-        when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs));
-        long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mBufferedReader, mPowerProfile);
-
-        assertArrayEquals(freqs, actualFreqs);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times));
-        mKernelUidCpuFreqTimeReader.readDeltaImpl(cb);
-        for (int i = 0; i < uids.length; ++i) {
-            cb.verify(uids[i], times[i]);
-        }
-        cb.verifyNoMoreInteractions();
-
-        // Verify that a second call will only return deltas.
-        cb.clear();
-        Mockito.reset(mProcReader);
-        final long[][] newTimes1 = new long[uids.length][freqs.length];
-        for (int i = 0; i < uids.length; ++i) {
-            for (int j = 0; j < freqs.length; ++j) {
-                newTimes1[i][j] = times[i][j] + (uids[i] + freqs[j]) * 50;
-            }
-        }
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes1));
-        mKernelUidCpuFreqTimeReader.readDeltaImpl(cb);
-        for (int i = 0; i < uids.length; ++i) {
-            cb.verify(uids[i], subtract(newTimes1[i], times[i]));
-        }
-        cb.verifyNoMoreInteractions();
-
-        // Verify that there won't be a callback if the proc file values didn't change.
-        cb.clear();
-        Mockito.reset(mProcReader);
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes1));
-        mKernelUidCpuFreqTimeReader.readDeltaImpl(cb);
-        cb.verifyNoMoreInteractions();
-
-        // Verify that calling with a null callback doesn't result in any crashes
-        cb.clear();
-        Mockito.reset(mProcReader);
-        final long[][] newTimes2 = new long[uids.length][freqs.length];
-        for (int i = 0; i < uids.length; ++i) {
-            for (int j = 0; j < freqs.length; ++j) {
-                newTimes2[i][j] = newTimes1[i][j] + (uids[i] * freqs[j]) * 30;
-            }
-        }
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes2));
-        mKernelUidCpuFreqTimeReader.readDeltaImpl(null);
-        cb.verifyNoMoreInteractions();
-
-        // Verify that the readDelta call will only return deltas when
-        // the previous call had null callback.
-        cb.clear();
-        Mockito.reset(mProcReader);
-        final long[][] newTimes3 = new long[uids.length][freqs.length];
-        for (int i = 0; i < uids.length; ++i) {
-            for (int j = 0; j < freqs.length; ++j) {
-                newTimes3[i][j] = newTimes2[i][j] + (uids[i] + freqs[j]) * 40;
-            }
-        }
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes3));
-        mKernelUidCpuFreqTimeReader.readDeltaImpl(cb);
-        for (int i = 0; i < uids.length; ++i) {
-            cb.verify(uids[i], subtract(newTimes3[i], newTimes2[i]));
-        }
-        cb.verifyNoMoreInteractions();
-    }
-
-    @Test
-    public void testReadAbsolute() throws Exception {
-        VerifiableCallback cb = new VerifiableCallback();
-        final long[] freqs = {110, 123, 145, 167, 289, 997};
-        final int[] uids = {1, 22, 333, 444, 555};
-        final long[][] times = new long[uids.length][freqs.length];
-        for (int i = 0; i < uids.length; ++i) {
-            for (int j = 0; j < freqs.length; ++j) {
-                times[i][j] = uids[i] * freqs[j] * 10;
-            }
-        }
-        when(mBufferedReader.readLine()).thenReturn(getFreqsLine(freqs));
-        long[] actualFreqs = mKernelUidCpuFreqTimeReader.readFreqs(mBufferedReader, mPowerProfile);
-
-        assertArrayEquals(freqs, actualFreqs);
-        // Verify that the absolute values are returned
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, times));
-        mKernelUidCpuFreqTimeReader.readAbsolute(cb);
-        for (int i = 0; i < uids.length; ++i) {
-            cb.verify(uids[i], times[i]);
-        }
-        cb.verifyNoMoreInteractions();
-
-        // Verify that a second call should still return absolute values
-        cb.clear();
-        Mockito.reset(mProcReader);
-        final long[][] newTimes1 = new long[uids.length][freqs.length];
-        for (int i = 0; i < uids.length; ++i) {
-            for (int j = 0; j < freqs.length; ++j) {
-                newTimes1[i][j] = times[i][j] + (uids[i] + freqs[j]) * 50;
-            }
-        }
-        when(mProcReader.readBytes()).thenReturn(getUidTimesBytes(uids, newTimes1));
-        mKernelUidCpuFreqTimeReader.readAbsolute(cb);
-        for (int i = 0; i < uids.length; ++i) {
-            cb.verify(uids[i], newTimes1[i]);
-        }
-        cb.verifyNoMoreInteractions();
-    }
-
-    private long[] subtract(long[] a1, long[] a2) {
-        long[] val = new long[a1.length];
-        for (int i = 0; i < val.length; ++i) {
-            val[i] = a1[i] - a2[i];
-        }
-        return val;
-    }
-
-    private String getFreqsLine(long[] freqs) {
-        final StringBuilder sb = new StringBuilder();
-        sb.append("uid:");
-        for (int i = 0; i < freqs.length; ++i) {
-            sb.append(" " + freqs[i]);
-        }
-        return sb.toString();
-    }
-
-    private ByteBuffer getUidTimesBytes(int[] uids, long[][] times) {
-        int size = (1 + uids.length + uids.length * times[0].length) * 4;
-        ByteBuffer buf = ByteBuffer.allocate(size);
-        buf.order(ByteOrder.nativeOrder());
-        buf.putInt(times[0].length);
-        for (int i = 0; i < uids.length; i++) {
-            buf.putInt(uids[i]);
-            for (int j = 0; j < times[i].length; j++) {
-                buf.putInt((int) (times[i][j] / 10));
-            }
-        }
-        buf.flip();
-        return buf.asReadOnlyBuffer().order(ByteOrder.nativeOrder());
-    }
-
-    private void setCpuClusterFreqs(int numClusters, int... clusterFreqs) {
-        assertEquals(numClusters, clusterFreqs.length);
-        when(mPowerProfile.getNumCpuClusters()).thenReturn(numClusters);
-        for (int i = 0; i < numClusters; ++i) {
-            when(mPowerProfile.getNumSpeedStepsInCpuCluster(i)).thenReturn(clusterFreqs[i]);
-        }
-    }
-
-    private class VerifiableCallback implements KernelUidCpuFreqTimeReader.Callback {
-
-        SparseArray<long[]> mData = new SparseArray<>();
-        int count = 0;
-
-        public void verify(int uid, long[] cpuFreqTimeMs) {
-            long[] array = mData.get(uid);
-            assertNotNull(array);
-            assertArrayEquals(cpuFreqTimeMs, array);
-            count++;
-        }
-
-        public void clear() {
-            mData.clear();
-            count = 0;
-        }
-
-        @Override
-        public void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs) {
-            long[] array = new long[cpuFreqTimeMs.length];
-            System.arraycopy(cpuFreqTimeMs, 0, array, 0, array.length);
-            mData.put(uid, array);
-        }
-
-        public void verifyNoMoreInteractions() {
-            assertEquals(mData.size(), count);
-        }
-    }
-}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
index 4e4bb3507..78b6843 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
@@ -13,9 +13,10 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.os;
 
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java b/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java
index fe62764..cb8a62c 100644
--- a/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LoggingPrintStreamTest.java
@@ -16,7 +16,9 @@
 
 package com.android.internal.os;
 
-import android.test.suitebuilder.annotation.Suppress;
+import androidx.test.filters.Suppress;
+
+import junit.framework.TestCase;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -25,8 +27,6 @@
 import java.util.Collections;
 import java.util.List;
 
-import junit.framework.TestCase;
-
 // this test causes a IllegalAccessError: superclass not accessible
 @Suppress
 public class LoggingPrintStreamTest extends TestCase {
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
index 37b4e41a..0516bb7 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
@@ -30,8 +30,9 @@
 import static org.mockito.Mockito.when;
 
 import android.os.Parcel;
-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.Before;
 import org.junit.Test;
@@ -55,7 +56,7 @@
  * Install: adb install -r \
  *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class com.android.internal.os.LongSamplingCounterArrayTest -w \
- *     com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ *     com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
index 853bf8a..d2f5735 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
@@ -28,8 +28,9 @@
 import static org.mockito.Mockito.when;
 
 import android.os.Parcel;
-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.Before;
 import org.junit.Test;
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 b65c1e6..2c597b1 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -23,8 +23,9 @@
 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;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Assert;
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index b68f6b1..bc0e0a4 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -21,6 +21,11 @@
 import android.util.SparseIntArray;
 
 import com.android.internal.location.gnssmetrics.GnssMetrics;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
+
 import java.util.ArrayList;
 import java.util.Queue;
 import java.util.concurrent.Future;
@@ -42,13 +47,14 @@
         mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
         setExternalStatsSyncLocked(new DummyExternalStatsSync());
 
-        for (int i=0; i< GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
-            mGpsSignalQualityTimer[i] = new StopwatchTimer(clocks, null, -1000-i, null,
-                mOnBatteryTimeBase);
+        for (int i = 0; i < GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+            mGpsSignalQualityTimer[i] = new StopwatchTimer(clocks, null, -1000 - i, null,
+                    mOnBatteryTimeBase);
         }
 
         // A no-op handler.
-        mHandler = new Handler(Looper.getMainLooper()) {};
+        mHandler = new Handler(Looper.getMainLooper()) {
+        };
     }
 
     MockBatteryStatsImpl() {
@@ -94,23 +100,26 @@
         return this;
     }
 
-    public MockBatteryStatsImpl setKernelUidCpuFreqTimeReader(KernelUidCpuFreqTimeReader reader) {
-        mKernelUidCpuFreqTimeReader = reader;
+    public MockBatteryStatsImpl setKernelCpuUidFreqTimeReader(KernelCpuUidFreqTimeReader reader) {
+        mCpuUidFreqTimeReader = reader;
         return this;
     }
 
-    public MockBatteryStatsImpl setKernelUidCpuActiveTimeReader(KernelUidCpuActiveTimeReader reader) {
-        mKernelUidCpuActiveTimeReader = reader;
+    public MockBatteryStatsImpl setKernelCpuUidActiveTimeReader(
+            KernelCpuUidActiveTimeReader reader) {
+        mCpuUidActiveTimeReader = reader;
         return this;
     }
 
-    public MockBatteryStatsImpl setKernelUidCpuClusterTimeReader(KernelUidCpuClusterTimeReader reader) {
-        mKernelUidCpuClusterTimeReader = reader;
+    public MockBatteryStatsImpl setKernelCpuUidClusterTimeReader(
+            KernelCpuUidClusterTimeReader reader) {
+        mCpuUidClusterTimeReader = reader;
         return this;
     }
 
-    public MockBatteryStatsImpl setKernelUidCpuTimeReader(KernelUidCpuTimeReader reader) {
-        mKernelUidCpuTimeReader = reader;
+    public MockBatteryStatsImpl setKernelCpuUidUserSysTimeReader(
+            KernelCpuUidUserSysTimeReader reader) {
+        mCpuUidUserSysTimeReader = reader;
         return this;
     }
 
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java
index 14d62e0..c592ab6 100644
--- a/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/PowerCalculatorTest.java
@@ -17,13 +17,13 @@
 
 package com.android.internal.os;
 
-
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.os.BatteryStats;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
index 2853c96..5862368 100644
--- a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java
@@ -17,8 +17,8 @@
 
 package com.android.internal.os;
 
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
 
 import junit.framework.TestCase;
 
diff --git a/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java b/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java
index 489e164..e97caf8 100644
--- a/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ProcStatsUtilTest.java
@@ -20,9 +20,10 @@
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java b/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
index 2893066..9db3f8a 100644
--- a/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
@@ -22,9 +22,10 @@
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java b/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
index c051a1c..85eafc5 100644
--- a/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
@@ -15,15 +15,17 @@
  */
 
 package com.android.internal.os;
+
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.content.Context;
 import android.os.FileUtils;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
@@ -36,7 +38,6 @@
 import java.io.File;
 import java.nio.file.Files;
 
-
 /**
  * Test class for {@link StoragedUidIoStatsReader}.
  *
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
index 2a24881..8e0c1fe 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowActionModeTest.java
@@ -17,8 +17,6 @@
 package com.android.internal.policy;
 
 import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.ActionMode;
 import android.view.ActionMode.Callback;
 import android.view.KeyEvent;
@@ -32,7 +30,8 @@
 import android.view.WindowManager.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
 
-import java.util.List;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.SmallTest;
 
 /**
  * Tests {@link PhoneWindow}'s {@link ActionMode} related methods.
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
index d4b8566..6c2d630 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
@@ -28,12 +28,13 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.platform.test.annotations.Presubmit;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.ActionMode;
 import android.view.ContextThemeWrapper;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/NotificationVisibilityTest.java b/core/tests/coretests/src/com/android/internal/statusbar/NotificationVisibilityTest.java
new file mode 100644
index 0000000..b740ecc
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/statusbar/NotificationVisibilityTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class NotificationVisibilityTest {
+
+    @Test
+    public void testNotificationLocation_sameValuesAsMetricsProto() throws Exception {
+        for (NotificationVisibility.NotificationLocation location :
+                NotificationVisibility.NotificationLocation.values()) {
+            Field locationField = MetricsEvent.class.getField(location.name());
+            int metricsValue = locationField.getInt(null);
+            assertThat(metricsValue, is(location.toMetricsEventEnum()));
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
index b3897ce..d026735 100644
--- a/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
@@ -13,9 +13,11 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package com.android.internal.util;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
+
 import junit.framework.TestCase;
 
 import java.util.ArrayList;
diff --git a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
index a44b860..4716312 100644
--- a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.util;
 
 import static com.android.internal.util.DumpUtils.CRITICAL_SECTION_COMPONENTS;
diff --git a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
index 4845c4e..b2a2265 100644
--- a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
@@ -19,11 +19,8 @@
 import junit.framework.TestCase;
 
 import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
 import java.io.Writer;
 import java.util.ArrayList;
-import java.util.LinkedList;
 import java.util.List;
 
 /**
diff --git a/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
index f00c48c..867152e 100644
--- a/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/ParseUtilsTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.internal.util;
 
 import junit.framework.TestCase;
diff --git a/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java b/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java
new file mode 100644
index 0000000..6c50bce
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/TokenBucketTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.internal.util;
+
+import android.os.SystemClock;
+import android.text.format.DateUtils;
+
+import junit.framework.TestCase;
+
+public class TokenBucketTest extends TestCase {
+
+    static final int FILL_DELTA_VERY_SHORT  = 1;
+    static final int FILL_DELTA_VERY_LONG   = Integer.MAX_VALUE;
+
+    public void testArgumentValidation() {
+        assertThrow(() -> new TokenBucket(0, 1, 1));
+        assertThrow(() -> new TokenBucket(1, 0, 1));
+        assertThrow(() -> new TokenBucket(1, 1, 0));
+        assertThrow(() -> new TokenBucket(0, 1));
+        assertThrow(() -> new TokenBucket(1, 0));
+        assertThrow(() -> new TokenBucket(-1, 1, 1));
+        assertThrow(() -> new TokenBucket(1, -1, 1));
+        assertThrow(() -> new TokenBucket(1, 1, -1));
+        assertThrow(() -> new TokenBucket(-1, 1));
+        assertThrow(() -> new TokenBucket(1, -1));
+
+        new TokenBucket(1000, 100, 0);
+        new TokenBucket(1000, 100, 10);
+        new TokenBucket(5000, 50);
+        new TokenBucket(5000, 1);
+    }
+
+    public void testInitialCapacity() {
+        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 1), 1);
+        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10), 10);
+        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 1000), 1000);
+
+        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 0), 0);
+        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 3), 3);
+        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 10), 10);
+
+        drain(new TokenBucket(FILL_DELTA_VERY_LONG, 10, 100), 10);
+
+        drain(new TokenBucket((int) DateUtils.MINUTE_IN_MILLIS, 50), 50);
+        drain(new TokenBucket((int) DateUtils.HOUR_IN_MILLIS, 10), 10);
+        drain(new TokenBucket((int) DateUtils.DAY_IN_MILLIS, 200), 200);
+    }
+
+    public void testReset() {
+        TokenBucket tb = new TokenBucket(FILL_DELTA_VERY_LONG, 100, 10);
+        drain(tb, 10);
+
+        tb.reset(50);
+        drain(tb, 50);
+
+        tb.reset(50);
+        getOneByOne(tb, 10);
+        assertTrue(tb.has());
+
+        tb.reset(30);
+        drain(tb, 30);
+    }
+
+    public void testFill() throws Exception {
+        int delta = 50;
+        TokenBucket tb = new TokenBucket(delta, 10, 0);
+
+        assertEmpty(tb);
+
+        Thread.sleep(3 * delta / 2);
+
+        assertTrue(tb.has());
+    }
+
+    public void testRefill() throws Exception {
+        TokenBucket tb = new TokenBucket(FILL_DELTA_VERY_SHORT, 10, 10);
+
+        assertEquals(5, tb.get(5));
+        assertEquals(5, tb.get(5));
+
+        while (tb.available() < 10) {
+            Thread.sleep(2);
+        }
+
+        assertEquals(10, tb.get(10));
+
+        while (tb.available() < 10) {
+            Thread.sleep(2);
+        }
+
+        assertEquals(10, tb.get(100));
+    }
+
+    public void testAverage() throws Exception {
+        final int delta = 3;
+        final int want = 60;
+
+        long start = SystemClock.elapsedRealtime();
+        TokenBucket tb = new TokenBucket(delta, 20, 0);
+
+        for (int i = 0; i < want; i++) {
+            while (!tb.has()) {
+                Thread.sleep(5 * delta);
+            }
+            tb.get();
+        }
+
+        assertDuration(want * delta, SystemClock.elapsedRealtime() - start);
+    }
+
+    public void testBurst() throws Exception {
+        final int delta = 2;
+        final int capacity = 20;
+        final int want = 100;
+
+        long start = SystemClock.elapsedRealtime();
+        TokenBucket tb = new TokenBucket(delta, capacity, 0);
+
+        int total = 0;
+        while (total < want) {
+            while (!tb.has()) {
+                Thread.sleep(capacity * delta - 2);
+            }
+            total += tb.get(tb.available());
+        }
+
+        assertDuration(total * delta, SystemClock.elapsedRealtime() - start);
+    }
+
+    static void getOneByOne(TokenBucket tb, int n) {
+        while (n > 0) {
+            assertTrue(tb.has());
+            assertTrue(tb.available() >= n);
+            assertTrue(tb.get());
+            assertTrue(tb.available() >= n - 1);
+            n--;
+        }
+    }
+
+    void assertEmpty(TokenBucket tb) {
+        assertFalse(tb.has());
+        assertEquals(0, tb.available());
+        assertFalse(tb.get());
+    }
+
+    void drain(TokenBucket tb, int n) {
+        getOneByOne(tb, n);
+        assertEmpty(tb);
+    }
+
+    void assertDuration(long expected, long elapsed) {
+        String msg = String.format(
+                "expected elapsed time at least %d ms, but was %d ms", expected, elapsed);
+        elapsed += 1; // one millisecond extra guard
+        assertTrue(msg, elapsed >= expected);
+    }
+
+    void assertThrow(Fn fn) {
+        try {
+            fn.call();
+            fail("expected n exception to be thrown.");
+        } catch (Throwable t) { }
+    }
+
+    interface Fn { void call(); }
+}
diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java
index 912b7ec..b372366 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarContainerTest.java
@@ -18,11 +18,12 @@
 
 import android.content.Context;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.view.ActionMode;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.test.filters.SmallTest;
+
 /**
  * Tests for {@link ActionBarContainer}.
  */
diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
index 218566e..d10f173 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
@@ -29,9 +29,6 @@
 import android.content.Context;
 import android.graphics.Insets;
 import android.graphics.Rect;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.view.DisplayCutout;
 import android.view.View;
 import android.view.View.OnApplyWindowInsetsListener;
@@ -40,6 +37,10 @@
 import android.widget.FrameLayout;
 import android.widget.Toolbar;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -167,7 +168,7 @@
     }
 
     private WindowInsets insetsWith(Insets content, DisplayCutout cutout) {
-        return new WindowInsets(content.toRect(), null, null, false, false, cutout);
+        return new WindowInsets(content.toRect(), null, false, false, cutout);
     }
 
     private ViewGroup createViewGroupWithId(int id) {
diff --git a/core/tests/coretests/src/com/android/internal/widget/BackgroundFallbackTest.java b/core/tests/coretests/src/com/android/internal/widget/BackgroundFallbackTest.java
index e21143d..0fada06 100644
--- a/core/tests/coretests/src/com/android/internal/widget/BackgroundFallbackTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/BackgroundFallbackTest.java
@@ -32,10 +32,11 @@
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.support.test.InstrumentationRegistry;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import androidx.test.InstrumentationRegistry;
+
 import org.junit.Before;
 import org.junit.Test;
 
diff --git a/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java b/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java
index 1806b22..2e0dbb4 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java
@@ -19,12 +19,13 @@
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
 import android.text.Layout;
 import android.view.View.MeasureSpec;
 import android.widget.TextView;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
index f73950a..6167c4b 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
@@ -20,8 +20,9 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.UserHandle;
-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/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
index 41082b7..6af7c88 100644
--- a/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
@@ -21,12 +21,12 @@
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.text.Layout;
 import android.view.LayoutInflater;
 import android.view.View.MeasureSpec;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
 import com.android.frameworks.coretests.R;
 
 import org.junit.Before;
diff --git a/core/tests/coretests/src/com/android/server/wm/test/filters/CoreTestsFilter.java b/core/tests/coretests/src/com/android/server/wm/test/filters/CoreTestsFilter.java
new file mode 100644
index 0000000..1a81c2c
--- /dev/null
+++ b/core/tests/coretests/src/com/android/server/wm/test/filters/CoreTestsFilter.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.test.filters;
+
+import android.os.Bundle;
+
+import com.android.test.filters.SelectTest;
+
+/**
+ * JUnit test filter that select Window Manager Service related tests from FrameworksCoreTests.
+ *
+ * <p>Use this filter when running FrameworksCoreTests as
+ * <pre>
+ * adb shell am instrument -w \
+ *     -e filter com.android.server.wm.test.filters.CoreTestsFilter  \
+ *     -e selectTest_verbose true \
+ *     com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
+ * </pre>
+ */
+public final class CoreTestsFilter extends SelectTest {
+
+    private static final String[] SELECTED_CORE_TESTS = {
+            "android.app.servertransaction.", // all tests under the package.
+            "android.view.DisplayCutoutTest",
+            "android.view.InsetsControllerTest",
+            "android.view.InsetsSourceTest",
+            "android.view.InsetsSourceConsumerTest",
+            "android.view.InsetsStateTest",
+    };
+
+    public CoreTestsFilter(Bundle testArgs) {
+        super(addSelectTest(testArgs, SELECTED_CORE_TESTS));
+    }
+}
diff --git a/core/tests/featureflagtests/Android.mk b/core/tests/featureflagtests/Android.mk
index 5e518b6..ce7cb18 100644
--- a/core/tests/featureflagtests/Android.mk
+++ b/core/tests/featureflagtests/Android.mk
@@ -9,7 +9,7 @@
     $(call all-java-files-under, src)
 
 LOCAL_DX_FLAGS := --core-library
-LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib androidx.test.rules
 LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
 LOCAL_PACKAGE_NAME := FrameworksCoreFeatureFlagTests
 LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/core/tests/featureflagtests/AndroidManifest.xml b/core/tests/featureflagtests/AndroidManifest.xml
index b8ffacb..326374e 100644
--- a/core/tests/featureflagtests/AndroidManifest.xml
+++ b/core/tests/featureflagtests/AndroidManifest.xml
@@ -26,7 +26,7 @@
     </application>
 
     <instrumentation
-        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.frameworks.coretests.featureflagtests"
         android:label="Frameworks FeatureFlagUtils Tests" />
 
diff --git a/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java b/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
index 0b1b333..3160428 100644
--- a/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
+++ b/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
@@ -24,10 +24,11 @@
 import android.content.Context;
 import android.os.SystemProperties;
 import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/core/tests/hdmitests/Android.mk b/core/tests/hdmitests/Android.mk
index e0d2c09..f155feb 100644
--- a/core/tests/hdmitests/Android.mk
+++ b/core/tests/hdmitests/Android.mk
@@ -20,7 +20,7 @@
 # Include all test java files
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test frameworks-base-testutils
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules frameworks-base-testutils truth-prebuilt
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 LOCAL_PACKAGE_NAME := HdmiCecTests
diff --git a/core/tests/hdmitests/AndroidManifest.xml b/core/tests/hdmitests/AndroidManifest.xml
index 1460b41..f8ed118 100644
--- a/core/tests/hdmitests/AndroidManifest.xml
+++ b/core/tests/hdmitests/AndroidManifest.xml
@@ -22,7 +22,7 @@
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="android.hardware.hdmi"
         android:label="HDMI CEC Tests"/>
 
diff --git a/core/tests/hdmitests/AndroidTest.xml b/core/tests/hdmitests/AndroidTest.xml
index 7ef672d..0c8da28 100644
--- a/core/tests/hdmitests/AndroidTest.xml
+++ b/core/tests/hdmitests/AndroidTest.xml
@@ -29,6 +29,6 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.hardware.hdmi" />
         <option name="hidden-api-checks" value="false"/>
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
     </test>
 </configuration>
\ No newline at end of file
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index 7b76a08..28a8afe 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -18,15 +18,18 @@
 
 import android.os.Handler;
 import android.os.test.TestLooper;
-import android.support.test.filters.SmallTest;
 import android.util.Log;
-import java.util.List;
+
+import androidx.test.filters.SmallTest;
+
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.util.List;
+
 /**
  * Tests for {@link HdmiAudioSystemClient}
  */
@@ -315,6 +318,27 @@
             mMaxVolume = maxVolume;
             mIsMute = isMute;
         }
+
+        @Override
+        public void setSystemAudioModeOnForAudioOnlySource() {
+        }
+
+        @Override
+        public int getPhysicalAddress() {
+            return 0x0000;
+        }
+
+        @Override
+        public void powerOffRemoteDevice(int logicalAddress, int powerStatus) {
+        }
+
+        @Override
+        public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {
+        }
+
+        @Override
+        public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) {
+        }
     }
 
 }
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java
new file mode 100644
index 0000000..fdc6b84
--- /dev/null
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.hdmi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+/**
+ * Tests for {@link HdmiUtils}.
+ */
+@RunWith(JUnit4.class)
+@SmallTest
+public class HdmiUtilsTest {
+    @Test
+    public void testInvalidAddress() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0, -1))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_UNKNOWN);
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0xFFFF, 0xFFFF))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_UNKNOWN);
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0xFFFFF, 0))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_UNKNOWN);
+    }
+
+    @Test
+    public void testSameAddress() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x1000, 0x1000))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_SAME);
+    }
+
+    @Test
+    public void testDirectlyAbove() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x1000, 0x1200))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE);
+    }
+
+    @Test
+    public void testDirectlyAbove_rootDevice() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x0000, 0x2000))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE);
+    }
+
+    @Test
+    public void testDirectlyAbove_leafDevice() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x1240, 0x1245))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_ABOVE);
+    }
+
+    @Test
+    public void testAbove() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x1000, 0x1210))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_ABOVE);
+    }
+
+    @Test
+    public void testAbove_rootDevice() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x0000, 0x1200))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_ABOVE);
+    }
+
+    @Test
+    public void testDirectlyBelow() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x2250, 0x2200))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_BELOW);
+    }
+
+    @Test
+    public void testDirectlyBelow_rootDevice() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x5000, 0x0000))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_BELOW);
+    }
+
+    @Test
+    public void testDirectlyBelow_leafDevice() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x3249, 0x3240))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_BELOW);
+    }
+
+    @Test
+    public void testBelow() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x5143, 0x5100))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_BELOW);
+    }
+
+    @Test
+    public void testBelow_rootDevice() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x3420, 0x0000))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_BELOW);
+    }
+
+    @Test
+    public void testSibling() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x4000, 0x5000))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_SIBLING);
+    }
+
+    @Test
+    public void testSibling_leafDevice() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x798A, 0x798F))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_SIBLING);
+    }
+
+    @Test
+    public void testDifferentBranch() {
+        assertThat(HdmiUtils.getHdmiAddressRelativePosition(0x798A, 0x7970))
+                .isEqualTo(HdmiUtils.HDMI_RELATIVE_POSITION_DIFFERENT_BRANCH);
+    }
+
+    @Test
+    public void isValidPysicalAddress_true() {
+        assertThat(HdmiUtils.isValidPhysicalAddress(0)).isTrue();
+        assertThat(HdmiUtils.isValidPhysicalAddress(0xFFFE)).isTrue();
+        assertThat(HdmiUtils.isValidPhysicalAddress(0x1200)).isTrue();
+    }
+
+    @Test
+    public void isValidPysicalAddress_outOfRange() {
+        assertThat(HdmiUtils.isValidPhysicalAddress(-1)).isFalse();
+        assertThat(HdmiUtils.isValidPhysicalAddress(0xFFFF)).isFalse();
+        assertThat(HdmiUtils.isValidPhysicalAddress(0x10000)).isFalse();
+    }
+
+    @Test
+    public void isValidPysicalAddress_nonTrailingZeros() {
+        assertThat(HdmiUtils.isValidPhysicalAddress(0x0001)).isFalse();
+        assertThat(HdmiUtils.isValidPhysicalAddress(0x0213)).isFalse();
+    }
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
index 80ab4ea..cc2d8d2 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -18,7 +18,7 @@
 ## The application with a minimal main dex
 include $(CLEAR_VARS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex android-support-multidex-instrumentation android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex android-support-multidex-instrumentation androidx.test.rules
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -38,16 +38,11 @@
 
 LOCAL_MIN_SDK_VERSION := 8
 
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex \
-     -D jack.dex.output.multidex.legacy=true
-
 include $(BUILD_PACKAGE)
 
-ifndef LOCAL_JACK_ENABLED
-$(mainDexList): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
 	$(hide) mkdir -p $(dir $@)
-	$(MAINDEXCLASSES) $< 1>$@
+	PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
 	echo "com/android/multidexlegacyandexception/Test.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
-endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
index 98d8f27..d9d9eb2 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/AndroidManifest.xml
@@ -30,7 +30,7 @@
                      android:targetPackage="com.android.multidexlegacyandexception"
                      android:label="Test for MultiDexLegacyAndException" />
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="com.android.multidexlegacyandexception"
                      android:label="Test for MultiDexLegacyAndException" />
 </manifest>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java
index 92a3b0c..fae345f 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/MultiDexAndroidJUnitRunner.java
@@ -17,8 +17,9 @@
 package com.android.multidexlegacyandexception.tests;
 
 import android.os.Bundle;
+
 import androidx.multidex.MultiDex;
-import android.support.test.runner.AndroidJUnitRunner;
+import androidx.test.runner.AndroidJUnitRunner;
 
 public class MultiDexAndroidJUnitRunner extends AndroidJUnitRunner {
 
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/NoActivityJUnit4Test.java b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/NoActivityJUnit4Test.java
index 94a5b7f..f4b02d0 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/NoActivityJUnit4Test.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/src/com/android/multidexlegacyandexception/tests/NoActivityJUnit4Test.java
@@ -16,7 +16,8 @@
 
 package com.android.multidexlegacyandexception.tests;
 
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.runner.RunWith;
 
 /**
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index cf8fc92..c577eef 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -38,9 +38,9 @@
 
 include $(BUILD_PACKAGE)
 
-$(mainDexList): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
 	$(hide) mkdir -p $(dir $@)
-	$(MAINDEXCLASSES) $< 1>$@
+	PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
 	echo "com/android/multidexlegacytestapp/Test.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
@@ -69,9 +69,9 @@
 
 include $(BUILD_PACKAGE)
 
-$(mainDexList2): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList2): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
 	$(hide) mkdir -p $(dir $@)
-	$(MAINDEXCLASSES) $< 1>$@
+	PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
 	echo "com/android/multidexlegacytestapp/Test.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList2)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.mk
index f2bd353..2dc30ea 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/Android.mk
@@ -18,7 +18,7 @@
 ## The tests with only one dex
 include $(CLEAR_VARS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex-instrumentation android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex-instrumentation androidx.test.rules
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -41,7 +41,7 @@
 ## The tests with a minimal main dex
 include $(CLEAR_VARS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex-instrumentation android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex-instrumentation androidx.test.rules
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/InstrumentationTest.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/InstrumentationTest.java
index 4e6ec14..7812c58 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/InstrumentationTest.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/InstrumentationTest.java
@@ -15,10 +15,13 @@
  */
 package com.android.multidexlegacytestapp.test2;
 
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.multidexlegacytestapp.manymethods.Big001;
 import com.android.multidexlegacytestapp.manymethods.Big079;
+
 import junit.framework.Assert;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/MultiDexAndroidJUnitRunner.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/MultiDexAndroidJUnitRunner.java
index 9e41a92..b3044dc 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/MultiDexAndroidJUnitRunner.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestAppTests2/src/com/android/multidexlegacytestapp/test2/MultiDexAndroidJUnitRunner.java
@@ -1,8 +1,9 @@
 package com.android.multidexlegacytestapp.test2;
 
 import android.os.Bundle;
+
 import androidx.multidex.MultiDex;
-import android.support.test.runner.AndroidJUnitRunner;
+import androidx.test.runner.AndroidJUnitRunner;
 
 public class MultiDexAndroidJUnitRunner extends AndroidJUnitRunner {
 
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
index 2ce50b3..da40940 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
@@ -30,14 +30,13 @@
 	$(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
 
 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
-LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.dex.output.multidex.legacy=true
 
 LOCAL_DEX_PREOPT := false
 
 include $(BUILD_PACKAGE)
 
-$(mainDexList): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
 	$(hide) mkdir -p $(dir $@)
-	$(MAINDEXCLASSES) $< 1>$@
+	PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
 
 $(built_dex_intermediate): $(mainDexList)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk
index f3d98a8..afbcd46 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/Android.mk
@@ -23,7 +23,7 @@
 LOCAL_PACKAGE_NAME := MultiDexLegacyTestServicesTests2
 
 LOCAL_JAVA_LIBRARIES := android-support-multidex
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
 
 LOCAL_SDK_VERSION := 9
 
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
index 0ab2959..01285e7 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/AndroidManifest.xml
@@ -7,7 +7,7 @@
     <uses-sdk android:minSdkVersion="9" />
     <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
     <instrumentation
-        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.framework.multidexlegacytestservices" />
 
     <application
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java
index 900f203..f2c72f0 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests2/src/com/android/framework/multidexlegacytestservices/test2/ServicesTests.java
@@ -19,22 +19,26 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.File;
 import java.io.FileFilter;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.util.concurrent.TimeoutException;
-import junit.framework.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
 
 /**
  * Run the tests with: <code>adb shell am instrument -w
- * com.android.framework.multidexlegacytestservices.test2/android.support.test.runner.AndroidJUnitRunner
+ * com.android.framework.multidexlegacytestservices.test2/androidx.test.runner.AndroidJUnitRunner
  * </code>
  */
 @RunWith(AndroidJUnit4.class)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
index 8b0c750..665e22d 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
@@ -35,9 +35,9 @@
 
 include $(BUILD_PACKAGE)
 
-$(mainDexList): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
 	$(hide) mkdir -p $(dir $@)
-	$(MAINDEXCLASSES) $< 1>$@
+	PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
 	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
index a36c993..c827fa8 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
@@ -35,9 +35,9 @@
 
 include $(BUILD_PACKAGE)
 
-$(mainDexList): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
 	$(hide) mkdir -p $(dir $@)
-	$(MAINDEXCLASSES) $< 1>$@
+	PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
 	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
index 6b7418c..3d6ad7d 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
@@ -35,9 +35,9 @@
 
 include $(BUILD_PACKAGE)
 
-$(mainDexList): $(full_classes_pre_proguard_jar) | $(MAINDEXCLASSES)
+$(mainDexList): $(full_classes_pre_proguard_jar) $(MAINDEXCLASSES) $(PROGUARD_DEPS)
 	$(hide) mkdir -p $(dir $@)
-	$(MAINDEXCLASSES) $< 1>$@
+	PROGUARD_HOME=$(PROGUARD_HOME) $(MAINDEXCLASSES) $< 1>$@
 	echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
 
 $(built_dex_intermediate): $(mainDexList)
diff --git a/core/tests/overlaytests/device/Android.mk b/core/tests/overlaytests/device/Android.mk
index 680ebeb..5630749 100644
--- a/core/tests/overlaytests/device/Android.mk
+++ b/core/tests/overlaytests/device/Android.mk
@@ -19,7 +19,7 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_PACKAGE_NAME := OverlayDeviceTests
 LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
 LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_TARGET_REQUIRED_MODULES := \
     OverlayDeviceTests_AppOverlayOne \
diff --git a/core/tests/overlaytests/device/AndroidManifest.xml b/core/tests/overlaytests/device/AndroidManifest.xml
index d14fdf5..4881636 100644
--- a/core/tests/overlaytests/device/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/AndroidManifest.xml
@@ -23,7 +23,7 @@
         <uses-library android:name="android.test.runner"/>
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.overlaytest"
         android:label="Runtime resource overlay tests" />
 </manifest>
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
index 5a86885..91fcdbb 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
@@ -25,10 +25,11 @@
 import android.content.res.XmlResourceParser;
 import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
-import android.support.test.InstrumentationRegistry;
 import android.util.AttributeSet;
 import android.util.Xml;
 
+import androidx.test.InstrumentationRegistry;
+
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
index f35e511..cd3ed9d 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
@@ -16,7 +16,7 @@
 
 package com.android.overlaytest;
 
-import android.support.test.filters.MediumTest;
+import androidx.test.filters.MediumTest;
 
 import org.junit.BeforeClass;
 import org.junit.runner.RunWith;
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
index 037449f..c0d4281 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
@@ -16,7 +16,7 @@
 
 package com.android.overlaytest;
 
-import android.support.test.filters.MediumTest;
+import androidx.test.filters.MediumTest;
 
 import org.junit.BeforeClass;
 import org.junit.runner.RunWith;
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
index f657b5c..33c7b25 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
@@ -16,7 +16,7 @@
 
 package com.android.overlaytest;
 
-import android.support.test.filters.MediumTest;
+import androidx.test.filters.MediumTest;
 
 import org.junit.BeforeClass;
 import org.junit.runner.RunWith;
diff --git a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
index 03cf3eb..9913531 100644
--- a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java
@@ -21,6 +21,7 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
@@ -67,6 +68,7 @@
         // TODO(b/63758238): stop spying the class under test
         mLockPatternUtils = spy(new LockPatternUtils(context));
         when(mLockPatternUtils.getLockSettings()).thenReturn(ils);
+        doReturn(true).when(mLockPatternUtils).hasSecureLockScreen();
 
         final UserInfo userInfo = Mockito.mock(UserInfo.class);
         when(userInfo.isDemo()).thenReturn(isDemoUser);
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 25dabad..035ee10 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -42,6 +42,38 @@
 }
 
 prebuilt_etc {
+    name: "privapp_whitelist_com.android.carrierconfig",
+    product_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.carrierconfig.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
+    name: "privapp_whitelist_com.android.contacts",
+    product_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.contacts.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
+    name: "privapp_whitelist_com.android.launcher3",
+    product_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.launcher3.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
+    name: "privapp_whitelist_com.android.provision",
+    product_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.provision.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
     name: "privapp_whitelist_com.android.settings",
     product_specific: true,
     sub_dir: "permissions",
@@ -50,6 +82,22 @@
 }
 
 prebuilt_etc {
+    name: "privapp_whitelist_com.android.settings.intelligence",
+    product_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.settings.intelligence.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
+    name: "privapp_whitelist_com.android.storagemanager",
+    product_specific: true,
+    sub_dir: "permissions",
+    src: "com.android.storagemanager.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
     name: "privapp_whitelist_com.android.systemui",
     product_specific: true,
     sub_dir: "permissions",
diff --git a/data/etc/com.android.carrierconfig.xml b/data/etc/com.android.carrierconfig.xml
new file mode 100644
index 0000000..17efb03
--- /dev/null
+++ b/data/etc/com.android.carrierconfig.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<permissions>
+    <privapp-permissions package="com.android.carrierconfig">
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.contacts.xml b/data/etc/com.android.contacts.xml
new file mode 100644
index 0000000..78eae40
--- /dev/null
+++ b/data/etc/com.android.contacts.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<permissions>
+    <privapp-permissions package="com.android.contacts">
+        <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+        <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.launcher3.xml b/data/etc/com.android.launcher3.xml
new file mode 100644
index 0000000..337e153
--- /dev/null
+++ b/data/etc/com.android.launcher3.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<permissions>
+    <privapp-permissions package="com.android.launcher3">
+        <permission name="android.permission.BIND_APPWIDGET"/>
+        <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
+        <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.provision.xml b/data/etc/com.android.provision.xml
new file mode 100644
index 0000000..05404ef
--- /dev/null
+++ b/data/etc/com.android.provision.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<permissions>
+    <privapp-permissions package="com.android.provision">
+        <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.settings.intelligence.xml b/data/etc/com.android.settings.intelligence.xml
new file mode 100644
index 0000000..6ca30c1
--- /dev/null
+++ b/data/etc/com.android.settings.intelligence.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<permissions>
+    <privapp-permissions package="com.android.settings.intelligence">
+        <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>
+</permissions>
diff --git a/data/etc/com.android.storagemanager.xml b/data/etc/com.android.storagemanager.xml
new file mode 100644
index 0000000..e85a82c
--- /dev/null
+++ b/data/etc/com.android.storagemanager.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<permissions>
+    <privapp-permissions package="com.android.storagemanager">
+        <permission name="android.permission.DELETE_PACKAGES"/>
+        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+        <permission name="android.permission.MANAGE_USERS"/>
+        <permission name="android.permission.PACKAGE_USAGE_STATS"/>
+        <permission name="android.permission.USE_RESERVED_DISK"/>
+        <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index b65bc1d..3562a8f 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -29,7 +29,6 @@
         <permission name="android.permission.DUMP"/>
         <permission name="android.permission.GET_APP_OPS_STATS"/>
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
-        <permission name="android.permission.MANAGE_ACTIVITY_STACKS"/>
         <permission name="android.permission.MANAGE_DEBUGGING"/>
         <permission name="android.permission.MANAGE_SENSOR_PRIVACY"/>
         <permission name="android.permission.MANAGE_USB"/>
@@ -45,6 +44,7 @@
         <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.REAL_GET_TASKS"/>
         <permission name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"/>
+        <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
         <permission name="android.permission.START_ACTIVITY_AS_CALLER"/>
         <permission name="android.permission.START_TASKS_FROM_RECENTS"/>
         <permission name="android.permission.STATUS_BAR"/>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 4a2db0a..fb43e41 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -223,12 +223,12 @@
          code to link against. -->
 
     <library name="android.test.base"
-            file="/system/framework/android.test.base.impl.jar" />
+            file="/system/framework/android.test.base.jar" />
     <library name="android.test.mock"
-            file="/system/framework/android.test.mock.impl.jar"
+            file="/system/framework/android.test.mock.jar"
             dependency="android.test.base" />
     <library name="android.test.runner"
-            file="/system/framework/android.test.runner.impl.jar"
+            file="/system/framework/android.test.runner.jar"
             dependency="android.test.base:android.test.mock" />
 
     <!-- In BOOT_JARS historically, and now added to legacy applications. -->
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 58b57e5..904c3fb 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -33,10 +33,6 @@
         <permission name="android.permission.CRYPT_KEEPER"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.carrierconfig">
-        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.cellbroadcastreceiver">
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MANAGE_USERS"/>
@@ -45,11 +41,6 @@
         <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.contacts">
-        <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
-        <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.defcontainer">
         <permission name="android.permission.ACCESS_CACHE_FILESYSTEM"/>
         <permission name="android.permission.ALLOCATE_AGGRESSIVE"/>
@@ -79,12 +70,6 @@
         <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.launcher3">
-        <permission name="android.permission.BIND_APPWIDGET"/>
-        <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
-        <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.location.fused">
         <permission name="android.permission.INSTALL_LOCATION_PROVIDER"/>
     </privapp-permissions>
@@ -195,6 +180,7 @@
         <permission name="android.permission.WRITE_APN_SETTINGS"/>
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
         <permission name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"/>
+        <permission name="android.permission.READ_PRECISE_PHONE_STATE"/>
         <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
         <permission name="com.android.voicemail.permission.WRITE_VOICEMAIL"/>
     </privapp-permissions>
@@ -238,7 +224,29 @@
         <permission name="android.permission.USE_RESERVED_DISK"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.provision">
+    <privapp-permissions package="com.android.mainline.networkstack">
+        <permission name="android.permission.ACCESS_NETWORK_CONDITIONS"/>
+        <permission name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"/>
+        <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+        <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
+        <permission name="android.permission.CONTROL_VPN"/>
+        <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
+        <permission name="android.permission.MANAGE_IPSEC_TUNNELS"/>
+        <permission name="android.permission.MANAGE_NETWORK_POLICY"/>
+        <permission name="android.permission.MANAGE_SUBSCRIPTION_PLANS"/>
+        <permission name="android.permission.MANAGE_USB"/>
+        <permission name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"/>
+        <permission name="android.permission.NETWORK_SETTINGS"/>
+        <permission name="android.permission.NETWORK_STACK" />
+        <permission name="android.permission.NET_TUNNELING"/>
+        <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD"/>
+        <permission name="android.permission.PEERS_MAC_ADDRESS"/>
+        <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
+        <permission name="android.permission.READ_PRECISE_PHONE_STATE"/>
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+        <permission name="android.permission.READ_WIFI_CREDENTIAL"/>
+        <permission name="android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"/>
+        <permission name="android.permission.TETHER_PRIVILEGED"/>
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
     </privapp-permissions>
 
@@ -254,13 +262,6 @@
         <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.settings.intelligence">
-        <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">
         <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
     </privapp-permissions>
@@ -289,7 +290,6 @@
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
         <permission name="android.permission.MANAGE_ACCESSIBILITY"/>
-        <permission name="android.permission.MANAGE_ACTIVITY_STACKS"/>
         <permission name="android.permission.MANAGE_DEVICE_ADMINS"/>
         <permission name="android.permission.MANAGE_USB"/>
         <permission name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
@@ -317,6 +317,7 @@
         <permission name="android.permission.SET_TIME"/>
         <permission name="android.permission.SET_TIME_ZONE"/>
         <permission name="android.permission.SIGNAL_PERSISTENT_PROCESSES"/>
+        <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
         <permission name="android.permission.START_TASKS_FROM_RECENTS" />
         <permission name="android.permission.STOP_APP_SWITCHES"/>
         <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
@@ -331,15 +332,6 @@
         <permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.storagemanager">
-        <permission name="android.permission.DELETE_PACKAGES"/>
-        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
-        <permission name="android.permission.MANAGE_USERS"/>
-        <permission name="android.permission.PACKAGE_USAGE_STATS"/>
-        <permission name="android.permission.USE_RESERVED_DISK"/>
-        <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.tv">
         <permission name="android.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE"/>
         <permission name="android.permission.DVB_DEVICE"/>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 6a40792..21531ab 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -99,6 +99,46 @@
         <font weight="400" style="normal">CarroisGothicSC-Regular.ttf</font>
     </family>
 
+    <family name="arbutus-slab">
+        <font weight="400" style="normal">ArbutusSlab-Regular.ttf</font>
+    </family>
+
+    <family name="arvo">
+        <font weight="400" style="normal">Arvo-Regular.ttf</font>
+        <font weight="400" style="italic">Arvo-Italic.ttf</font>
+        <font weight="700" style="normal">Arvo-Bold.ttf</font>
+        <font weight="700" style="italic">Arvo-BoldItalic.ttf</font>
+    </family>
+    <alias name="arvo-bold" to="arvo" weight="700" />
+
+    <family name="lato">
+        <font weight="400" style="normal">Lato-Regular.ttf</font>
+        <font weight="400" style="italic">Lato-Italic.ttf</font>
+        <font weight="700" style="normal">Lato-Bold.ttf</font>
+        <font weight="700" style="italic">Lato-BoldItalic.ttf</font>
+    </family>
+    <alias name="lato-bold" to="lato" weight="700" />
+
+    <family name="rubik">
+        <font weight="400" style="normal">Rubik-Regular.ttf</font>
+        <font weight="400" style="italic">Rubik-Italic.ttf</font>
+        <font weight="500" style="normal">Rubik-Medium.ttf</font>
+        <font weight="500" style="italic">Rubik-MediumItalic.ttf</font>
+        <font weight="700" style="normal">Rubik-Bold.ttf</font>
+        <font weight="700" style="italic">Rubik-BoldItalic.ttf</font>
+    </family>
+    <alias name="rubik-medium" to="rubik" weight="500" />
+
+    <family name="source-sans-pro">
+        <font weight="400" style="normal">SourceSansPro-Regular.ttf</font>
+        <font weight="400" style="italic">SourceSansPro-Italic.ttf</font>
+        <font weight="600" style="normal">SourceSansPro-SemiBold.ttf</font>
+        <font weight="600" style="italic">SourceSansPro-SemiBoldItalic.ttf</font>
+        <font weight="700" style="normal">SourceSansPro-Bold.ttf</font>
+        <font weight="700" style="italic">SourceSansPro-BoldItalic.ttf</font>
+    </family>
+    <alias name="source-sans-pro-semi-bold" to="source-sans-pro" weight="600" />
+
     <!-- fallback fonts -->
     <family lang="und-Arab" variant="elegant">
         <font weight="400" style="normal">NotoNaskhArabic-Regular.ttf</font>
@@ -312,9 +352,8 @@
         <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
     </family>
     <family lang="und-Mymr" variant="elegant">
-        <font weight="400" style="normal">NotoSansMyanmar-Regular.otf</font>
-        <font weight="500" style="normal">NotoSansMyanmar-Medium.otf</font>
-        <font weight="700" style="normal">NotoSansMyanmar-Bold.otf</font>
+        <font weight="400" style="normal">NotoSansMyanmar-Regular-ZawDecode.ttf</font>
+        <font weight="700" style="normal">NotoSansMyanmar-Bold-ZawDecode.ttf</font>
         <font weight="400" style="normal" fallbackFor="serif">NotoSerifMyanmar-Regular.otf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifMyanmar-Bold.otf</font>
     </family>
diff --git a/data/sounds/AllAudio.mk b/data/sounds/AllAudio.mk
index bb8add1..c6c7d3b 100644
--- a/data/sounds/AllAudio.mk
+++ b/data/sounds/AllAudio.mk
@@ -15,227 +15,227 @@
 LOCAL_PATH := frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-    $(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \
-    $(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \
-    $(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \
-    $(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \
-    $(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \
-    $(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Argon.ogg:system/media/audio/alarms/Argon.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Barium.ogg:system/media/audio/alarms/Barium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:system/media/audio/alarms/Carbon.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:system/media/audio/alarms/Fermium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:system/media/audio/alarms/Hassium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Helium.ogg:system/media/audio/alarms/Helium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:system/media/audio/alarms/Krypton.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Neon.ogg:system/media/audio/alarms/Neon.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:system/media/audio/alarms/Neptunium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:system/media/audio/alarms/Nobelium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Promethium.ogg:system/media/audio/alarms/Promethium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Scandium.ogg:system/media/audio/alarms/Scandium.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
-    $(LOCAL_PATH)/notifications/Aldebaran.ogg:system/media/audio/notifications/Aldebaran.ogg \
-    $(LOCAL_PATH)/notifications/Altair.ogg:system/media/audio/notifications/Altair.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
-    $(LOCAL_PATH)/notifications/Antares.ogg:system/media/audio/notifications/Antares.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Antimony.ogg:system/media/audio/notifications/Antimony.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Argon.ogg:system/media/audio/notifications/Argon.ogg \
-    $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:system/media/audio/notifications/Beat_Box_Android.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Beryllium.ogg:system/media/audio/notifications/Beryllium.ogg \
-    $(LOCAL_PATH)/notifications/Betelgeuse.ogg:system/media/audio/notifications/Betelgeuse.ogg \
-    $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:system/media/audio/notifications/CaffeineSnake.ogg \
-    $(LOCAL_PATH)/notifications/Canopus.ogg:system/media/audio/notifications/Canopus.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \
-    $(LOCAL_PATH)/notifications/Castor.ogg:system/media/audio/notifications/Castor.ogg \
-    $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Cobalt.ogg:system/media/audio/notifications/Cobalt.ogg \
-    $(LOCAL_PATH)/notifications/Cricket.ogg:system/media/audio/notifications/Cricket.ogg \
-    $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:system/media/audio/notifications/DearDeer.ogg \
-    $(LOCAL_PATH)/notifications/Deneb.ogg:system/media/audio/notifications/Deneb.ogg \
-    $(LOCAL_PATH)/notifications/Doink.ogg:system/media/audio/notifications/Doink.ogg \
-    $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:system/media/audio/notifications/DontPanic.ogg \
-    $(LOCAL_PATH)/notifications/Drip.ogg:system/media/audio/notifications/Drip.ogg \
-    $(LOCAL_PATH)/notifications/Electra.ogg:system/media/audio/notifications/Electra.ogg \
-    $(LOCAL_PATH)/F1_MissedCall.ogg:system/media/audio/notifications/F1_MissedCall.ogg \
-    $(LOCAL_PATH)/F1_New_MMS.ogg:system/media/audio/notifications/F1_New_MMS.ogg \
-    $(LOCAL_PATH)/F1_New_SMS.ogg:system/media/audio/notifications/F1_New_SMS.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Fluorine.ogg:system/media/audio/notifications/Fluorine.ogg \
-    $(LOCAL_PATH)/notifications/Fomalhaut.ogg:system/media/audio/notifications/Fomalhaut.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Gallium.ogg:system/media/audio/notifications/Gallium.ogg \
-    $(LOCAL_PATH)/notifications/Heaven.ogg:system/media/audio/notifications/Heaven.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Helium.ogg:system/media/audio/notifications/Helium.ogg \
-    $(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Iridium.ogg:system/media/audio/notifications/Iridium.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Krypton.ogg:system/media/audio/notifications/Krypton.ogg \
-    $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:system/media/audio/notifications/KzurbSonar.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:system/media/audio/notifications/Lalande.ogg \
-    $(LOCAL_PATH)/notifications/Merope.ogg:system/media/audio/notifications/Merope.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \
-    $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:system/media/audio/notifications/OnTheHunt.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Palladium.ogg:system/media/audio/notifications/Palladium.ogg \
-    $(LOCAL_PATH)/notifications/Plastic_Pipe.ogg:system/media/audio/notifications/Plastic_Pipe.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Radon.ogg:system/media/audio/notifications/Radon.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Rubidium.ogg:system/media/audio/notifications/Rubidium.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Selenium.ogg:system/media/audio/notifications/Selenium.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \
-    $(LOCAL_PATH)/notifications/Sirrah.ogg:system/media/audio/notifications/Sirrah.ogg \
-    $(LOCAL_PATH)/notifications/SpaceSeed.ogg:system/media/audio/notifications/SpaceSeed.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Strontium.ogg:system/media/audio/notifications/Strontium.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \
-    $(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Thallium.ogg:system/media/audio/notifications/Thallium.ogg \
-    $(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
-    $(LOCAL_PATH)/newwavelabs/Voila.ogg:system/media/audio/notifications/Voila.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Xenon.ogg:system/media/audio/notifications/Xenon.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Zirconium.ogg:system/media/audio/notifications/Zirconium.ogg \
-    $(LOCAL_PATH)/notifications/arcturus.ogg:system/media/audio/notifications/arcturus.ogg \
-    $(LOCAL_PATH)/notifications/moonbeam.ogg:system/media/audio/notifications/moonbeam.ogg \
-    $(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \
-    $(LOCAL_PATH)/notifications/pizzicato.ogg:system/media/audio/notifications/pizzicato.ogg \
-    $(LOCAL_PATH)/notifications/regulus.ogg:system/media/audio/notifications/regulus.ogg \
-    $(LOCAL_PATH)/notifications/sirius.ogg:system/media/audio/notifications/sirius.ogg \
-    $(LOCAL_PATH)/notifications/tweeters.ogg:system/media/audio/notifications/tweeters.ogg \
-    $(LOCAL_PATH)/notifications/vega.ogg:system/media/audio/notifications/vega.ogg \
-    $(LOCAL_PATH)/ringtones/ANDROMEDA.ogg:system/media/audio/ringtones/ANDROMEDA.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Atria.ogg:system/media/audio/ringtones/Atria.ogg \
-    $(LOCAL_PATH)/ringtones/BOOTES.ogg:system/media/audio/ringtones/BOOTES.ogg \
-    $(LOCAL_PATH)/newwavelabs/Backroad.ogg:system/media/audio/ringtones/Backroad.ogg \
-    $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
-    $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \
-    $(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:system/media/audio/ringtones/Big_Easy.ogg \
-    $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
-    $(LOCAL_PATH)/newwavelabs/Bollywood.ogg:system/media/audio/ringtones/Bollywood.ogg \
-    $(LOCAL_PATH)/newwavelabs/BussaMove.ogg:system/media/audio/ringtones/BussaMove.ogg \
-    $(LOCAL_PATH)/ringtones/CANISMAJOR.ogg:system/media/audio/ringtones/CANISMAJOR.ogg \
-    $(LOCAL_PATH)/ringtones/CASSIOPEIA.ogg:system/media/audio/ringtones/CASSIOPEIA.ogg \
-    $(LOCAL_PATH)/newwavelabs/Cairo.ogg:system/media/audio/ringtones/Cairo.ogg \
-    $(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:system/media/audio/ringtones/Calypso_Steel.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \
-    $(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:system/media/audio/ringtones/CaribbeanIce.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \
-    $(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:system/media/audio/ringtones/Champagne_Edition.ogg \
-    $(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:system/media/audio/ringtones/Club_Cubano.ogg \
-    $(LOCAL_PATH)/newwavelabs/CrayonRock.ogg:system/media/audio/ringtones/CrayonRock.ogg \
-    $(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:system/media/audio/ringtones/CrazyDream.ogg \
-    $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:system/media/audio/ringtones/CurveBall.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \
-    $(LOCAL_PATH)/newwavelabs/DancinFool.ogg:system/media/audio/ringtones/DancinFool.ogg \
-    $(LOCAL_PATH)/newwavelabs/Ding.ogg:system/media/audio/ringtones/Ding.ogg \
-    $(LOCAL_PATH)/newwavelabs/DonMessWivIt.ogg:system/media/audio/ringtones/DonMessWivIt.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \
-    $(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:system/media/audio/ringtones/DreamTheme.ogg \
-    $(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:system/media/audio/ringtones/Eastern_Sky.ogg \
-    $(LOCAL_PATH)/newwavelabs/Enter_the_Nexus.ogg:system/media/audio/ringtones/Enter_the_Nexus.ogg \
-    $(LOCAL_PATH)/ringtones/Eridani.ogg:system/media/audio/ringtones/Eridani.ogg \
-    $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:system/media/audio/ringtones/EtherShake.ogg \
-    $(LOCAL_PATH)/ringtones/FreeFlight.ogg:system/media/audio/ringtones/FreeFlight.ogg \
-    $(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:system/media/audio/ringtones/FriendlyGhost.ogg \
-    $(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:system/media/audio/ringtones/Funk_Yall.ogg \
-    $(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:system/media/audio/ringtones/GameOverGuitar.ogg \
-    $(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:system/media/audio/ringtones/Gimme_Mo_Town.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \
-    $(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:system/media/audio/ringtones/Glacial_Groove.ogg \
-    $(LOCAL_PATH)/newwavelabs/Growl.ogg:system/media/audio/ringtones/Growl.ogg \
-    $(LOCAL_PATH)/newwavelabs/HalfwayHome.ogg:system/media/audio/ringtones/HalfwayHome.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \
-    $(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:system/media/audio/ringtones/InsertCoin.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:system/media/audio/ringtones/Kuma.ogg \
-    $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:system/media/audio/ringtones/LoopyLounge.ogg \
-    $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:system/media/audio/ringtones/LoveFlute.ogg \
-    $(LOCAL_PATH)/ringtones/Lyra.ogg:system/media/audio/ringtones/Lyra.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \
-    $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:system/media/audio/ringtones/MidEvilJaunt.ogg \
-    $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:system/media/audio/ringtones/MildlyAlarming.ogg \
-    $(LOCAL_PATH)/newwavelabs/Nairobi.ogg:system/media/audio/ringtones/Nairobi.ogg \
-    $(LOCAL_PATH)/newwavelabs/Nassau.ogg:system/media/audio/ringtones/Nassau.ogg \
-    $(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:system/media/audio/ringtones/NewPlayer.ogg \
-    $(LOCAL_PATH)/newwavelabs/No_Limits.ogg:system/media/audio/ringtones/No_Limits.ogg \
-    $(LOCAL_PATH)/newwavelabs/Noises1.ogg:system/media/audio/ringtones/Noises1.ogg \
-    $(LOCAL_PATH)/newwavelabs/Noises2.ogg:system/media/audio/ringtones/Noises2.ogg \
-    $(LOCAL_PATH)/newwavelabs/Noises3.ogg:system/media/audio/ringtones/Noises3.ogg \
-    $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \
-    $(LOCAL_PATH)/ringtones/PERSEUS.ogg:system/media/audio/ringtones/PERSEUS.ogg \
-    $(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:system/media/audio/ringtones/Paradise_Island.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \
-    $(LOCAL_PATH)/newwavelabs/Playa.ogg:system/media/audio/ringtones/Playa.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:system/media/audio/ringtones/Rasalas.ogg \
-    $(LOCAL_PATH)/newwavelabs/Revelation.ogg:system/media/audio/ringtones/Revelation.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \
-    $(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \
-    $(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
-    $(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
-    $(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
-    $(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:system/media/audio/ringtones/Road_Trip.ogg \
-    $(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:system/media/audio/ringtones/RomancingTheTone.ogg \
-    $(LOCAL_PATH)/newwavelabs/Safari.ogg:system/media/audio/ringtones/Safari.ogg \
-    $(LOCAL_PATH)/newwavelabs/Savannah.ogg:system/media/audio/ringtones/Savannah.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \
-    $(LOCAL_PATH)/newwavelabs/Seville.ogg:system/media/audio/ringtones/Seville.ogg \
-    $(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:system/media/audio/ringtones/Shes_All_That.ogg \
-    $(LOCAL_PATH)/newwavelabs/SilkyWay.ogg:system/media/audio/ringtones/SilkyWay.ogg \
-    $(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:system/media/audio/ringtones/SitarVsSitar.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \
-    $(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:system/media/audio/ringtones/SpringyJalopy.ogg \
-    $(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:system/media/audio/ringtones/Steppin_Out.ogg \
-    $(LOCAL_PATH)/newwavelabs/Terminated.ogg:system/media/audio/ringtones/Terminated.ogg \
-    $(LOCAL_PATH)/ringtones/Testudo.ogg:system/media/audio/ringtones/Testudo.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \
-    $(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:system/media/audio/ringtones/Third_Eye.ogg \
-    $(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:system/media/audio/ringtones/Thunderfoot.ogg \
-    $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \
-    $(LOCAL_PATH)/ringtones/URSAMINOR.ogg:system/media/audio/ringtones/URSAMINOR.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \
-    $(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:system/media/audio/ringtones/VeryAlarmed.ogg \
-    $(LOCAL_PATH)/ringtones/Vespa.ogg:system/media/audio/ringtones/Vespa.ogg \
-    $(LOCAL_PATH)/newwavelabs/World.ogg:system/media/audio/ringtones/World.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg \
-    $(LOCAL_PATH)/ringtones/hydra.ogg:system/media/audio/ringtones/hydra.ogg \
-    $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
-    $(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-    $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
-    $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
-    $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
-    $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
-    $(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:system/media/audio/ui/Trusted.ogg \
-    $(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \
-    $(LOCAL_PATH)/effects/ogg/VideoStop_48k.ogg:system/media/audio/ui/VideoStop.ogg \
-    $(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
-    $(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
-    $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
-    $(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:system/media/audio/ui/ChargingStarted.ogg \
-    $(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:system/media/audio/ui/InCallNotification.ogg \
-    $(LOCAL_PATH)/effects/ogg/NFCFailure.ogg:system/media/audio/ui/NFCFailure.ogg \
-    $(LOCAL_PATH)/effects/ogg/NFCInitiated.ogg:system/media/audio/ui/NFCInitiated.ogg \
-    $(LOCAL_PATH)/effects/ogg/NFCSuccess.ogg:system/media/audio/ui/NFCSuccess.ogg \
-    $(LOCAL_PATH)/effects/ogg/NFCTransferComplete.ogg:system/media/audio/ui/NFCTransferComplete.ogg \
-    $(LOCAL_PATH)/effects/ogg/NFCTransferInitiated.ogg:system/media/audio/ui/NFCTransferInitiated.ogg \
+    $(LOCAL_PATH)/Alarm_Beep_01.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_01.ogg \
+    $(LOCAL_PATH)/Alarm_Beep_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_02.ogg \
+    $(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \
+    $(LOCAL_PATH)/Alarm_Buzzer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Buzzer.ogg \
+    $(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \
+    $(LOCAL_PATH)/Alarm_Rooster_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Rooster_02.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Argon.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Barium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Barium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Carbon.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Cesium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Fermium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Hassium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Helium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Krypton.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Neon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neon.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neptunium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Nobelium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Osmium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Oxygen.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Platinum.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Plutonium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Promethium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Promethium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Scandium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Scandium.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \
+    $(LOCAL_PATH)/notifications/Aldebaran.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Aldebaran.ogg \
+    $(LOCAL_PATH)/notifications/Altair.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Altair.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Alya.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Alya.ogg \
+    $(LOCAL_PATH)/notifications/Antares.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Antares.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Antimony.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Antimony.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Argon.ogg \
+    $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beat_Box_Android.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Bellatrix.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Beryllium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beryllium.ogg \
+    $(LOCAL_PATH)/notifications/Betelgeuse.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Betelgeuse.ogg \
+    $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CaffeineSnake.ogg \
+    $(LOCAL_PATH)/notifications/Canopus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Canopus.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \
+    $(LOCAL_PATH)/notifications/Castor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Castor.ogg \
+    $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Cobalt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Cobalt.ogg \
+    $(LOCAL_PATH)/notifications/Cricket.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Cricket.ogg \
+    $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DearDeer.ogg \
+    $(LOCAL_PATH)/notifications/Deneb.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Deneb.ogg \
+    $(LOCAL_PATH)/notifications/Doink.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Doink.ogg \
+    $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DontPanic.ogg \
+    $(LOCAL_PATH)/notifications/Drip.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Drip.ogg \
+    $(LOCAL_PATH)/notifications/Electra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Electra.ogg \
+    $(LOCAL_PATH)/F1_MissedCall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_MissedCall.ogg \
+    $(LOCAL_PATH)/F1_New_MMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_MMS.ogg \
+    $(LOCAL_PATH)/F1_New_SMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_SMS.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Fluorine.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Fluorine.ogg \
+    $(LOCAL_PATH)/notifications/Fomalhaut.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Fomalhaut.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Gallium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Gallium.ogg \
+    $(LOCAL_PATH)/notifications/Heaven.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Heaven.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Helium.ogg \
+    $(LOCAL_PATH)/newwavelabs/Highwire.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Highwire.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Iridium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Iridium.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Krypton.ogg \
+    $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/KzurbSonar.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Lalande.ogg \
+    $(LOCAL_PATH)/notifications/Merope.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Merope.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \
+    $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/OnTheHunt.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Palladium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Palladium.ogg \
+    $(LOCAL_PATH)/notifications/Plastic_Pipe.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Plastic_Pipe.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Polaris.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Proxima.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Radon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Radon.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Rubidium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Rubidium.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Selenium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Selenium.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \
+    $(LOCAL_PATH)/notifications/Sirrah.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Sirrah.ogg \
+    $(LOCAL_PATH)/notifications/SpaceSeed.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/SpaceSeed.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Strontium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Strontium.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Syrma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Syrma.ogg \
+    $(LOCAL_PATH)/notifications/TaDa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/TaDa.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Talitha.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Thallium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Thallium.ogg \
+    $(LOCAL_PATH)/notifications/Tinkerbell.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tinkerbell.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Upsilon.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \
+    $(LOCAL_PATH)/newwavelabs/Voila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Voila.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Xenon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Xenon.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Zirconium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Zirconium.ogg \
+    $(LOCAL_PATH)/notifications/arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/arcturus.ogg \
+    $(LOCAL_PATH)/notifications/moonbeam.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/moonbeam.ogg \
+    $(LOCAL_PATH)/notifications/pixiedust.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pixiedust.ogg \
+    $(LOCAL_PATH)/notifications/pizzicato.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pizzicato.ogg \
+    $(LOCAL_PATH)/notifications/regulus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/regulus.ogg \
+    $(LOCAL_PATH)/notifications/sirius.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/sirius.ogg \
+    $(LOCAL_PATH)/notifications/tweeters.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/tweeters.ogg \
+    $(LOCAL_PATH)/notifications/vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/vega.ogg \
+    $(LOCAL_PATH)/ringtones/ANDROMEDA.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ANDROMEDA.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Andromeda.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Atria.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Atria.ogg \
+    $(LOCAL_PATH)/ringtones/BOOTES.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BOOTES.ogg \
+    $(LOCAL_PATH)/newwavelabs/Backroad.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Backroad.ogg \
+    $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BeatPlucker.ogg \
+    $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BentleyDubs.ogg \
+    $(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Big_Easy.ogg \
+    $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BirdLoop.ogg \
+    $(LOCAL_PATH)/newwavelabs/Bollywood.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Bollywood.ogg \
+    $(LOCAL_PATH)/newwavelabs/BussaMove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BussaMove.ogg \
+    $(LOCAL_PATH)/ringtones/CANISMAJOR.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CANISMAJOR.ogg \
+    $(LOCAL_PATH)/ringtones/CASSIOPEIA.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CASSIOPEIA.ogg \
+    $(LOCAL_PATH)/newwavelabs/Cairo.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cairo.ogg \
+    $(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Calypso_Steel.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CanisMajor.ogg \
+    $(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CaribbeanIce.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Carina.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \
+    $(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Champagne_Edition.ogg \
+    $(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Club_Cubano.ogg \
+    $(LOCAL_PATH)/newwavelabs/CrayonRock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CrayonRock.ogg \
+    $(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CrazyDream.ogg \
+    $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CurveBall.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cygnus.ogg \
+    $(LOCAL_PATH)/newwavelabs/DancinFool.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DancinFool.ogg \
+    $(LOCAL_PATH)/newwavelabs/Ding.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ding.ogg \
+    $(LOCAL_PATH)/newwavelabs/DonMessWivIt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DonMessWivIt.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Draco.ogg \
+    $(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DreamTheme.ogg \
+    $(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Eastern_Sky.ogg \
+    $(LOCAL_PATH)/newwavelabs/Enter_the_Nexus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Enter_the_Nexus.ogg \
+    $(LOCAL_PATH)/ringtones/Eridani.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Eridani.ogg \
+    $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/EtherShake.ogg \
+    $(LOCAL_PATH)/ringtones/FreeFlight.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/FreeFlight.ogg \
+    $(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/FriendlyGhost.ogg \
+    $(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Funk_Yall.ogg \
+    $(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/GameOverGuitar.ogg \
+    $(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Gimme_Mo_Town.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg \
+    $(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Glacial_Groove.ogg \
+    $(LOCAL_PATH)/newwavelabs/Growl.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Growl.ogg \
+    $(LOCAL_PATH)/newwavelabs/HalfwayHome.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/HalfwayHome.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Hydra.ogg \
+    $(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/InsertCoin.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Kuma.ogg \
+    $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoopyLounge.ogg \
+    $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoveFlute.ogg \
+    $(LOCAL_PATH)/ringtones/Lyra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Lyra.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \
+    $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MidEvilJaunt.ogg \
+    $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MildlyAlarming.ogg \
+    $(LOCAL_PATH)/newwavelabs/Nairobi.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Nairobi.ogg \
+    $(LOCAL_PATH)/newwavelabs/Nassau.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Nassau.ogg \
+    $(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/NewPlayer.ogg \
+    $(LOCAL_PATH)/newwavelabs/No_Limits.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/No_Limits.ogg \
+    $(LOCAL_PATH)/newwavelabs/Noises1.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises1.ogg \
+    $(LOCAL_PATH)/newwavelabs/Noises2.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises2.ogg \
+    $(LOCAL_PATH)/newwavelabs/Noises3.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises3.ogg \
+    $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/OrganDub.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \
+    $(LOCAL_PATH)/ringtones/PERSEUS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/PERSEUS.ogg \
+    $(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Paradise_Island.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Perseus.ogg \
+    $(LOCAL_PATH)/newwavelabs/Playa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Playa.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rasalas.ogg \
+    $(LOCAL_PATH)/newwavelabs/Revelation.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Revelation.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rigel.ogg \
+    $(LOCAL_PATH)/Ring_Classic_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Classic_02.ogg \
+    $(LOCAL_PATH)/Ring_Digital_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Digital_02.ogg \
+    $(LOCAL_PATH)/Ring_Synth_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_02.ogg \
+    $(LOCAL_PATH)/Ring_Synth_04.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_04.ogg \
+    $(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Road_Trip.ogg \
+    $(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/RomancingTheTone.ogg \
+    $(LOCAL_PATH)/newwavelabs/Safari.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Safari.ogg \
+    $(LOCAL_PATH)/newwavelabs/Savannah.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Savannah.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \
+    $(LOCAL_PATH)/newwavelabs/Seville.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Seville.ogg \
+    $(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Shes_All_That.ogg \
+    $(LOCAL_PATH)/newwavelabs/SilkyWay.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SilkyWay.ogg \
+    $(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SitarVsSitar.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \
+    $(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SpringyJalopy.ogg \
+    $(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Steppin_Out.ogg \
+    $(LOCAL_PATH)/newwavelabs/Terminated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Terminated.ogg \
+    $(LOCAL_PATH)/ringtones/Testudo.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Testudo.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \
+    $(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Third_Eye.ogg \
+    $(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Thunderfoot.ogg \
+    $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/TwirlAway.ogg \
+    $(LOCAL_PATH)/ringtones/URSAMINOR.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/URSAMINOR.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/UrsaMinor.ogg \
+    $(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/VeryAlarmed.ogg \
+    $(LOCAL_PATH)/ringtones/Vespa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Vespa.ogg \
+    $(LOCAL_PATH)/newwavelabs/World.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/World.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Zeta.ogg \
+    $(LOCAL_PATH)/ringtones/hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/hydra.ogg \
+    $(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+    $(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+    $(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+    $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \
+    $(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \
+    $(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+    $(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+    $(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \
+    $(LOCAL_PATH)/effects/ogg/VideoStop_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \
+    $(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/WirelessChargingStarted.ogg \
+    $(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \
+    $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \
+    $(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/ChargingStarted.ogg \
+    $(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/InCallNotification.ogg \
+    $(LOCAL_PATH)/effects/ogg/NFCFailure.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/NFCFailure.ogg \
+    $(LOCAL_PATH)/effects/ogg/NFCInitiated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/NFCInitiated.ogg \
+    $(LOCAL_PATH)/effects/ogg/NFCSuccess.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/NFCSuccess.ogg \
+    $(LOCAL_PATH)/effects/ogg/NFCTransferComplete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/NFCTransferComplete.ogg \
+    $(LOCAL_PATH)/effects/ogg/NFCTransferInitiated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/NFCTransferInitiated.ogg \
diff --git a/data/sounds/AudioPackage10.mk b/data/sounds/AudioPackage10.mk
index 72aa7fe..699dbd6 100644
--- a/data/sounds/AudioPackage10.mk
+++ b/data/sounds/AudioPackage10.mk
@@ -8,63 +8,63 @@
 LOCAL_PATH:= frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-        $(LOCAL_PATH)/alarms/ogg/Argon.ogg:system/media/audio/alarms/Argon.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:system/media/audio/alarms/Carbon.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Helium.ogg:system/media/audio/alarms/Helium.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:system/media/audio/alarms/Krypton.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Neon.ogg:system/media/audio/alarms/Neon.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
-	$(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressStandard_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressDelete_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressReturn_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/VideoStop_48k.ogg:system/media/audio/ui/VideoStop.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
-	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/LowBattery_48k.ogg:system/media/audio/ui/LowBattery.ogg \
-	$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:system/media/audio/ui/Unlock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:system/media/audio/ui/Trusted.ogg \
-	$(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:system/media/audio/ui/ChargingStarted.ogg \
-	$(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:system/media/audio/ui/InCallNotification.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/WirelessChargingStarted_48k.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \
-	$(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Atria.ogg:system/media/audio/ringtones/Atria.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:system/media/audio/ringtones/Kuma.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:system/media/audio/ringtones/Rasalas.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg
+        $(LOCAL_PATH)/alarms/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Argon.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Carbon.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Helium.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Krypton.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Neon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neon.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Oxygen.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Osmium.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Platinum.ogg \
+	$(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressStandard_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressDelete_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressReturn_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/VideoRecord_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/VideoStop_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/camera_click_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/LowBattery_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+	$(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/ChargingStarted.ogg \
+	$(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/InCallNotification.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/WirelessChargingStarted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/WirelessChargingStarted.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Alya.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \
+	$(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Syrma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Syrma.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Talitha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Talitha.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Tejat.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Andromeda.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Atria.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Atria.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Hydra.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Kuma.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rasalas.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Zeta.ogg
diff --git a/data/sounds/AudioPackage11.mk b/data/sounds/AudioPackage11.mk
index 665ce52..99dfd0a 100644
--- a/data/sounds/AudioPackage11.mk
+++ b/data/sounds/AudioPackage11.mk
@@ -8,63 +8,63 @@
 LOCAL_PATH:= frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/alarms/ogg/Argon.ogg:system/media/audio/alarms/Argon.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Carbon.ogg:system/media/audio/alarms/Carbon.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Helium.ogg:system/media/audio/alarms/Helium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Krypton.ogg:system/media/audio/alarms/Krypton.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Neon.ogg:system/media/audio/alarms/Neon.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
-	$(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressStandard_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressDelete_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressReturn_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/VideoStop_48k.ogg:system/media/audio/ui/VideoStop.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
-	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/LowBattery_48k.ogg:system/media/audio/ui/LowBattery.ogg \
-	$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:system/media/audio/ui/Unlock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:system/media/audio/ui/Trusted.ogg \
-	$(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:system/media/audio/ui/ChargingStarted.ogg \.
-	$(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:system/media/audio/ui/InCallNotification.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/WirelessChargingStarted_48k.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \
-	$(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Tejat_proc48.ogg:system/media/audio/notifications/Tejat.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Atria.ogg:system/media/audio/ringtones/Atria.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:system/media/audio/ringtones/Kuma.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:system/media/audio/ringtones/Rasalas.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg
+	$(LOCAL_PATH)/alarms/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Argon.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Carbon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Carbon.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Helium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Krypton.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Neon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neon.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Oxygen.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Osmium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Osmium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Platinum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Platinum.ogg \
+	$(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressStandard_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressDelete_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressReturn_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/VideoRecord_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/VideoStop_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/camera_click_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/LowBattery_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+	$(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/ChargingStarted.ogg \.
+	$(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/InCallNotification.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/WirelessChargingStarted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/WirelessChargingStarted.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Alya.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \
+	$(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Syrma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Syrma.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Talitha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Talitha.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Tejat_proc48.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Andromeda.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Atria.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Atria.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Hydra.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Kuma.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rasalas.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Zeta.ogg
diff --git a/data/sounds/AudioPackage12.mk b/data/sounds/AudioPackage12.mk
index 44a8f9e..6159a89 100644
--- a/data/sounds/AudioPackage12.mk
+++ b/data/sounds/AudioPackage12.mk
@@ -16,15 +16,15 @@
 MATERIAL_EFFECT_FILES := camera_click VideoRecord LowBattery WirelessChargingStarted VideoStop
 
 PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\
-	$(LOCAL_PATH)/alarms/ogg/$(fn).ogg:system/media/audio/alarms/$(fn).ogg)
+	$(LOCAL_PATH)/alarms/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(NOTIFICATION_FILES),\
-	$(LOCAL_PATH)/notifications/ogg/$(fn).ogg:system/media/audio/notifications/$(fn).ogg)
+	$(LOCAL_PATH)/notifications/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(RINGTONE_FILES),\
-	$(LOCAL_PATH)/ringtones/ogg/$(fn).ogg:system/media/audio/ringtones/$(fn).ogg)
+	$(LOCAL_PATH)/ringtones/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(EFFECT_FILES),\
-	$(LOCAL_PATH)/effects/ogg/$(fn).ogg:system/media/audio/ui/$(fn).ogg)
+	$(LOCAL_PATH)/effects/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg)
 PRODUCT_COPY_FILES += $(foreach fn,$(MATERIAL_EFFECT_FILES),\
-	$(LOCAL_PATH)/effects/material/ogg/$(fn).ogg:system/media/audio/ui/$(fn).ogg)
+	$(LOCAL_PATH)/effects/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg)
diff --git a/data/sounds/AudioPackage12_48.mk b/data/sounds/AudioPackage12_48.mk
index 09fab04..2899cd1 100644
--- a/data/sounds/AudioPackage12_48.mk
+++ b/data/sounds/AudioPackage12_48.mk
@@ -17,21 +17,21 @@
 
 # Alarms not yet available in 48 kHz
 PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\
-	$(LOCAL_PATH)/alarms/ogg/$(fn).ogg:system/media/audio/alarms/$(fn).ogg)
+	$(LOCAL_PATH)/alarms/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(NOTIFICATION_FILES),\
-	$(LOCAL_PATH)/notifications/ogg/$(fn)_48k.ogg:system/media/audio/notifications/$(fn).ogg)
+	$(LOCAL_PATH)/notifications/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(RINGTONE_FILES),\
-	$(LOCAL_PATH)/ringtones/ogg/$(fn)_48k.ogg:system/media/audio/ringtones/$(fn).ogg)
+	$(LOCAL_PATH)/ringtones/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(EFFECT_FILES),\
-	$(LOCAL_PATH)/effects/ogg/$(fn)_48k.ogg:system/media/audio/ui/$(fn).ogg)
+	$(LOCAL_PATH)/effects/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg)
 PRODUCT_COPY_FILES += $(foreach fn,$(MATERIAL_EFFECT_FILES),\
-	$(LOCAL_PATH)/effects/material/ogg/$(fn)_48k.ogg:system/media/audio/ui/$(fn).ogg)
+	$(LOCAL_PATH)/effects/material/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg)
 
 # no gold-plated version yet
 PRODUCT_COPY_FILES += \
-    $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
-    $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
-    $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg
+    $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \
+    $(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+    $(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg
diff --git a/data/sounds/AudioPackage13.mk b/data/sounds/AudioPackage13.mk
index de4ee04..9423c0b 100644
--- a/data/sounds/AudioPackage13.mk
+++ b/data/sounds/AudioPackage13.mk
@@ -17,15 +17,15 @@
 MATERIAL_EFFECT_FILES := camera_click VideoRecord WirelessChargingStarted LowBattery VideoStop
 
 PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\
-	$(LOCAL_PATH)/alarms/material/ogg/$(fn).ogg:system/media/audio/alarms/$(fn).ogg)
+	$(LOCAL_PATH)/alarms/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(NOTIFICATION_FILES),\
-	$(LOCAL_PATH)/notifications/material/ogg/$(fn).ogg:system/media/audio/notifications/$(fn).ogg)
+	$(LOCAL_PATH)/notifications/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(RINGTONE_FILES),\
-	$(LOCAL_PATH)/ringtones/material/ogg/$(fn).ogg:system/media/audio/ringtones/$(fn).ogg)
+	$(LOCAL_PATH)/ringtones/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(EFFECT_FILES),\
-	$(LOCAL_PATH)/effects/ogg/$(fn).ogg:system/media/audio/ui/$(fn).ogg)
+	$(LOCAL_PATH)/effects/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg)
 PRODUCT_COPY_FILES += $(foreach fn,$(MATERIAL_EFFECT_FILES),\
-	$(LOCAL_PATH)/effects/material/ogg/$(fn).ogg:system/media/audio/ui/$(fn).ogg)
+	$(LOCAL_PATH)/effects/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg)
diff --git a/data/sounds/AudioPackage13_48.mk b/data/sounds/AudioPackage13_48.mk
index 889d581..806c4e2 100644
--- a/data/sounds/AudioPackage13_48.mk
+++ b/data/sounds/AudioPackage13_48.mk
@@ -17,21 +17,21 @@
 MATERIAL_EFFECT_FILES := camera_click VideoRecord WirelessChargingStarted LowBattery VideoStop
 
 PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\
-	$(LOCAL_PATH)/alarms/material/ogg/$(fn)_48k.ogg:system/media/audio/alarms/$(fn).ogg)
+	$(LOCAL_PATH)/alarms/material/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(NOTIFICATION_FILES),\
-	$(LOCAL_PATH)/notifications/material/ogg/$(fn)_48k.ogg:system/media/audio/notifications/$(fn).ogg)
+	$(LOCAL_PATH)/notifications/material/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(RINGTONE_FILES),\
-	$(LOCAL_PATH)/ringtones/material/ogg/$(fn)_48k.ogg:system/media/audio/ringtones/$(fn).ogg)
+	$(LOCAL_PATH)/ringtones/material/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(EFFECT_FILES),\
-	$(LOCAL_PATH)/effects/ogg/$(fn)_48k.ogg:system/media/audio/ui/$(fn).ogg)
+	$(LOCAL_PATH)/effects/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg)
 PRODUCT_COPY_FILES += $(foreach fn,$(MATERIAL_EFFECT_FILES),\
-	$(LOCAL_PATH)/effects/material/ogg/$(fn)_48k.ogg:system/media/audio/ui/$(fn).ogg)
+	$(LOCAL_PATH)/effects/material/ogg/$(fn)_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg)
 
 # no gold-plated version yet
 PRODUCT_COPY_FILES += \
-    $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
-    $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
-    $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg
+    $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \
+    $(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+    $(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg
diff --git a/data/sounds/AudioPackage14.mk b/data/sounds/AudioPackage14.mk
index c903a2b..3d161aa 100644
--- a/data/sounds/AudioPackage14.mk
+++ b/data/sounds/AudioPackage14.mk
@@ -18,15 +18,15 @@
 MATERIAL_EFFECT_FILES := camera_click VideoRecord WirelessChargingStarted LowBattery VideoStop
 
 PRODUCT_COPY_FILES += $(foreach fn,$(ALARM_FILES),\
-	$(LOCAL_PATH)/alarms/material/ogg/$(fn).ogg:system/media/audio/alarms/$(fn).ogg)
+	$(LOCAL_PATH)/alarms/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(NOTIFICATION_FILES),\
-	$(LOCAL_PATH)/notifications/material/ogg/$(fn).ogg:system/media/audio/notifications/$(fn).ogg)
+	$(LOCAL_PATH)/notifications/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(RINGTONE_FILES),\
-	$(LOCAL_PATH)/ringtones/material/ogg/$(fn).ogg:system/media/audio/ringtones/$(fn).ogg)
+	$(LOCAL_PATH)/ringtones/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/$(fn).ogg)
 
 PRODUCT_COPY_FILES += $(foreach fn,$(EFFECT_FILES),\
-	$(LOCAL_PATH)/effects/ogg/$(fn).ogg:system/media/audio/ui/$(fn).ogg)
+	$(LOCAL_PATH)/effects/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg)
 PRODUCT_COPY_FILES += $(foreach fn,$(MATERIAL_EFFECT_FILES),\
-	$(LOCAL_PATH)/effects/material/ogg/$(fn).ogg:system/media/audio/ui/$(fn).ogg)
+	$(LOCAL_PATH)/effects/material/ogg/$(fn).ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/$(fn).ogg)
diff --git a/data/sounds/AudioPackage2.mk b/data/sounds/AudioPackage2.mk
index 40319c4..bc4e8fb 100644
--- a/data/sounds/AudioPackage2.mk
+++ b/data/sounds/AudioPackage2.mk
@@ -10,98 +10,98 @@
 LOCAL_PATH:= frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/F1_MissedCall.ogg:system/media/audio/notifications/F1_MissedCall.ogg \
-	$(LOCAL_PATH)/F1_New_MMS.ogg:system/media/audio/notifications/F1_New_MMS.ogg \
-	$(LOCAL_PATH)/F1_New_SMS.ogg:system/media/audio/notifications/F1_New_SMS.ogg \
-	$(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \
-	$(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \
-	$(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \
-	$(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \
-	$(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
-	$(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
-	$(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
-	$(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:system/media/audio/notifications/Beat_Box_Android.ogg \
-	$(LOCAL_PATH)/notifications/Heaven.ogg:system/media/audio/notifications/Heaven.ogg \
-	$(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \
-	$(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \
-	$(LOCAL_PATH)/effects/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
-	$(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
-	$(LOCAL_PATH)/effects/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \
-	$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
-	$(LOCAL_PATH)/effects/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
-	$(LOCAL_PATH)/effects/Dock.ogg:system/media/audio/ui/Dock.ogg \
-	$(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
-	$(LOCAL_PATH)/notifications/moonbeam.ogg:system/media/audio/notifications/moonbeam.ogg \
-	$(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \
-	$(LOCAL_PATH)/notifications/pizzicato.ogg:system/media/audio/notifications/pizzicato.ogg \
-	$(LOCAL_PATH)/notifications/tweeters.ogg:system/media/audio/notifications/tweeters.ogg \
-	$(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
-	$(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:system/media/audio/notifications/CaffeineSnake.ogg
+	$(LOCAL_PATH)/F1_MissedCall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_MissedCall.ogg \
+	$(LOCAL_PATH)/F1_New_MMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_MMS.ogg \
+	$(LOCAL_PATH)/F1_New_SMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_SMS.ogg \
+	$(LOCAL_PATH)/Alarm_Buzzer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Buzzer.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_01.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_01.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_02.ogg \
+	$(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \
+	$(LOCAL_PATH)/Alarm_Rooster_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Rooster_02.ogg \
+	$(LOCAL_PATH)/Ring_Classic_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Classic_02.ogg \
+	$(LOCAL_PATH)/Ring_Digital_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Digital_02.ogg \
+	$(LOCAL_PATH)/Ring_Synth_04.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_04.ogg \
+	$(LOCAL_PATH)/Ring_Synth_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_02.ogg \
+	$(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beat_Box_Android.ogg \
+	$(LOCAL_PATH)/notifications/Heaven.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Heaven.ogg \
+	$(LOCAL_PATH)/notifications/TaDa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/TaDa.ogg \
+	$(LOCAL_PATH)/notifications/Tinkerbell.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tinkerbell.ogg \
+	$(LOCAL_PATH)/effects/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+	$(LOCAL_PATH)/effects/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \
+	$(LOCAL_PATH)/effects/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \
+	$(LOCAL_PATH)/effects/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+	$(LOCAL_PATH)/notifications/moonbeam.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/moonbeam.ogg \
+	$(LOCAL_PATH)/notifications/pixiedust.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pixiedust.ogg \
+	$(LOCAL_PATH)/notifications/pizzicato.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pizzicato.ogg \
+	$(LOCAL_PATH)/notifications/tweeters.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/tweeters.ogg \
+	$(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BeatPlucker.ogg \
+	$(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CaffeineSnake.ogg
 
 ifneq ($(MINIMAL_NEWWAVELABS),true)
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \
-	$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
-	$(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:system/media/audio/ringtones/CaribbeanIce.ogg \
-	$(LOCAL_PATH)/newwavelabs/CurveBall.ogg:system/media/audio/ringtones/CurveBall.ogg \
-	$(LOCAL_PATH)/newwavelabs/EtherShake.ogg:system/media/audio/ringtones/EtherShake.ogg \
-	$(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:system/media/audio/ringtones/FriendlyGhost.ogg \
-	$(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:system/media/audio/ringtones/GameOverGuitar.ogg \
-	$(LOCAL_PATH)/newwavelabs/Growl.ogg:system/media/audio/ringtones/Growl.ogg \
-	$(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:system/media/audio/ringtones/InsertCoin.ogg \
-	$(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:system/media/audio/ringtones/LoopyLounge.ogg \
-	$(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:system/media/audio/ringtones/LoveFlute.ogg \
-	$(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:system/media/audio/ringtones/MidEvilJaunt.ogg \
-	$(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:system/media/audio/ringtones/MildlyAlarming.ogg \
-	$(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:system/media/audio/ringtones/NewPlayer.ogg \
-	$(LOCAL_PATH)/newwavelabs/Noises1.ogg:system/media/audio/ringtones/Noises1.ogg \
-	$(LOCAL_PATH)/newwavelabs/Noises2.ogg:system/media/audio/ringtones/Noises2.ogg \
-	$(LOCAL_PATH)/newwavelabs/Noises3.ogg:system/media/audio/ringtones/Noises3.ogg \
-	$(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \
-	$(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:system/media/audio/ringtones/RomancingTheTone.ogg \
-	$(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:system/media/audio/ringtones/SitarVsSitar.ogg \
-	$(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:system/media/audio/ringtones/SpringyJalopy.ogg \
-	$(LOCAL_PATH)/newwavelabs/Terminated.ogg:system/media/audio/ringtones/Terminated.ogg \
-	$(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \
-	$(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:system/media/audio/ringtones/VeryAlarmed.ogg \
-	$(LOCAL_PATH)/newwavelabs/World.ogg:system/media/audio/ringtones/World.ogg \
-	$(LOCAL_PATH)/newwavelabs/DearDeer.ogg:system/media/audio/notifications/DearDeer.ogg \
-	$(LOCAL_PATH)/newwavelabs/DontPanic.ogg:system/media/audio/notifications/DontPanic.ogg \
-	$(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \
-	$(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:system/media/audio/notifications/KzurbSonar.ogg \
-	$(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:system/media/audio/notifications/OnTheHunt.ogg \
-	$(LOCAL_PATH)/newwavelabs/Voila.ogg:system/media/audio/notifications/Voila.ogg \
-	$(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:system/media/audio/ringtones/CrazyDream.ogg \
-	$(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:system/media/audio/ringtones/DreamTheme.ogg \
-	$(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:system/media/audio/ringtones/Big_Easy.ogg \
-	$(LOCAL_PATH)/newwavelabs/Bollywood.ogg:system/media/audio/ringtones/Bollywood.ogg \
-	$(LOCAL_PATH)/newwavelabs/Cairo.ogg:system/media/audio/ringtones/Cairo.ogg \
-	$(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:system/media/audio/ringtones/Calypso_Steel.ogg \
-	$(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:system/media/audio/ringtones/Champagne_Edition.ogg \
-	$(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:system/media/audio/ringtones/Club_Cubano.ogg \
-	$(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:system/media/audio/ringtones/Eastern_Sky.ogg \
-	$(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:system/media/audio/ringtones/Funk_Yall.ogg \
-	$(LOCAL_PATH)/newwavelabs/Savannah.ogg:system/media/audio/ringtones/Savannah.ogg \
-	$(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:system/media/audio/ringtones/Gimme_Mo_Town.ogg \
-	$(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:system/media/audio/ringtones/Glacial_Groove.ogg \
-	$(LOCAL_PATH)/newwavelabs/Seville.ogg:system/media/audio/ringtones/Seville.ogg \
-	$(LOCAL_PATH)/newwavelabs/No_Limits.ogg:system/media/audio/ringtones/No_Limits.ogg \
-	$(LOCAL_PATH)/newwavelabs/Revelation.ogg:system/media/audio/ringtones/Revelation.ogg \
-	$(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:system/media/audio/ringtones/Paradise_Island.ogg \
-	$(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:system/media/audio/ringtones/Road_Trip.ogg \
-	$(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:system/media/audio/ringtones/Shes_All_That.ogg \
-	$(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:system/media/audio/ringtones/Steppin_Out.ogg \
-	$(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:system/media/audio/ringtones/Third_Eye.ogg \
-	$(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:system/media/audio/ringtones/Thunderfoot.ogg
+	$(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BentleyDubs.ogg \
+	$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BirdLoop.ogg \
+	$(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CaribbeanIce.ogg \
+	$(LOCAL_PATH)/newwavelabs/CurveBall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CurveBall.ogg \
+	$(LOCAL_PATH)/newwavelabs/EtherShake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/EtherShake.ogg \
+	$(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/FriendlyGhost.ogg \
+	$(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/GameOverGuitar.ogg \
+	$(LOCAL_PATH)/newwavelabs/Growl.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Growl.ogg \
+	$(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/InsertCoin.ogg \
+	$(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoopyLounge.ogg \
+	$(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoveFlute.ogg \
+	$(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MidEvilJaunt.ogg \
+	$(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MildlyAlarming.ogg \
+	$(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/NewPlayer.ogg \
+	$(LOCAL_PATH)/newwavelabs/Noises1.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises1.ogg \
+	$(LOCAL_PATH)/newwavelabs/Noises2.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises2.ogg \
+	$(LOCAL_PATH)/newwavelabs/Noises3.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises3.ogg \
+	$(LOCAL_PATH)/newwavelabs/OrganDub.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/OrganDub.ogg \
+	$(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/RomancingTheTone.ogg \
+	$(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SitarVsSitar.ogg \
+	$(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SpringyJalopy.ogg \
+	$(LOCAL_PATH)/newwavelabs/Terminated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Terminated.ogg \
+	$(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/TwirlAway.ogg \
+	$(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/VeryAlarmed.ogg \
+	$(LOCAL_PATH)/newwavelabs/World.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/World.ogg \
+	$(LOCAL_PATH)/newwavelabs/DearDeer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DearDeer.ogg \
+	$(LOCAL_PATH)/newwavelabs/DontPanic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DontPanic.ogg \
+	$(LOCAL_PATH)/newwavelabs/Highwire.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Highwire.ogg \
+	$(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/KzurbSonar.ogg \
+	$(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/OnTheHunt.ogg \
+	$(LOCAL_PATH)/newwavelabs/Voila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Voila.ogg \
+	$(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CrazyDream.ogg \
+	$(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DreamTheme.ogg \
+	$(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Big_Easy.ogg \
+	$(LOCAL_PATH)/newwavelabs/Bollywood.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Bollywood.ogg \
+	$(LOCAL_PATH)/newwavelabs/Cairo.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cairo.ogg \
+	$(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Calypso_Steel.ogg \
+	$(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Champagne_Edition.ogg \
+	$(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Club_Cubano.ogg \
+	$(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Eastern_Sky.ogg \
+	$(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Funk_Yall.ogg \
+	$(LOCAL_PATH)/newwavelabs/Savannah.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Savannah.ogg \
+	$(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Gimme_Mo_Town.ogg \
+	$(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Glacial_Groove.ogg \
+	$(LOCAL_PATH)/newwavelabs/Seville.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Seville.ogg \
+	$(LOCAL_PATH)/newwavelabs/No_Limits.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/No_Limits.ogg \
+	$(LOCAL_PATH)/newwavelabs/Revelation.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Revelation.ogg \
+	$(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Paradise_Island.ogg \
+	$(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Road_Trip.ogg \
+	$(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Shes_All_That.ogg \
+	$(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Steppin_Out.ogg \
+	$(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Third_Eye.ogg \
+	$(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Thunderfoot.ogg
 endif
diff --git a/data/sounds/AudioPackage3.mk b/data/sounds/AudioPackage3.mk
index a05de72..a98fb74 100644
--- a/data/sounds/AudioPackage3.mk
+++ b/data/sounds/AudioPackage3.mk
@@ -10,94 +10,94 @@
 LOCAL_PATH:= frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/F1_MissedCall.ogg:system/media/audio/notifications/F1_MissedCall.ogg \
-	$(LOCAL_PATH)/F1_New_MMS.ogg:system/media/audio/notifications/F1_New_MMS.ogg \
-	$(LOCAL_PATH)/F1_New_SMS.ogg:system/media/audio/notifications/F1_New_SMS.ogg \
-	$(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \
-	$(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \
-	$(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \
-	$(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \
-	$(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
-	$(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
-	$(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
-	$(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:system/media/audio/notifications/Beat_Box_Android.ogg \
-	$(LOCAL_PATH)/notifications/Heaven.ogg:system/media/audio/notifications/Heaven.ogg \
-	$(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \
-	$(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \
-	$(LOCAL_PATH)/effects/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
-	$(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
-	$(LOCAL_PATH)/effects/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \
-	$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
-	$(LOCAL_PATH)/effects/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
-	$(LOCAL_PATH)/effects/Dock.ogg:system/media/audio/ui/Dock.ogg \
-	$(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
-	$(LOCAL_PATH)/notifications/moonbeam.ogg:system/media/audio/notifications/moonbeam.ogg \
-	$(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \
-	$(LOCAL_PATH)/notifications/pizzicato.ogg:system/media/audio/notifications/pizzicato.ogg \
-	$(LOCAL_PATH)/notifications/tweeters.ogg:system/media/audio/notifications/tweeters.ogg \
-	$(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
-	$(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:system/media/audio/notifications/CaffeineSnake.ogg
+	$(LOCAL_PATH)/F1_MissedCall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_MissedCall.ogg \
+	$(LOCAL_PATH)/F1_New_MMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_MMS.ogg \
+	$(LOCAL_PATH)/F1_New_SMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_SMS.ogg \
+	$(LOCAL_PATH)/Alarm_Buzzer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Buzzer.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_01.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_01.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_02.ogg \
+	$(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \
+	$(LOCAL_PATH)/Alarm_Rooster_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Rooster_02.ogg \
+	$(LOCAL_PATH)/Ring_Classic_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Classic_02.ogg \
+	$(LOCAL_PATH)/Ring_Digital_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Digital_02.ogg \
+	$(LOCAL_PATH)/Ring_Synth_04.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_04.ogg \
+	$(LOCAL_PATH)/Ring_Synth_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_02.ogg \
+	$(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beat_Box_Android.ogg \
+	$(LOCAL_PATH)/notifications/Heaven.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Heaven.ogg \
+	$(LOCAL_PATH)/notifications/TaDa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/TaDa.ogg \
+	$(LOCAL_PATH)/notifications/Tinkerbell.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tinkerbell.ogg \
+	$(LOCAL_PATH)/effects/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+	$(LOCAL_PATH)/effects/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \
+	$(LOCAL_PATH)/effects/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \
+	$(LOCAL_PATH)/effects/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+	$(LOCAL_PATH)/notifications/moonbeam.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/moonbeam.ogg \
+	$(LOCAL_PATH)/notifications/pixiedust.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pixiedust.ogg \
+	$(LOCAL_PATH)/notifications/pizzicato.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pizzicato.ogg \
+	$(LOCAL_PATH)/notifications/tweeters.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/tweeters.ogg \
+	$(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BeatPlucker.ogg \
+	$(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CaffeineSnake.ogg
 
 ifneq ($(MINIMAL_NEWWAVELABS),true)
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \
-	$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
-	$(LOCAL_PATH)/newwavelabs/CurveBall.ogg:system/media/audio/ringtones/CurveBall.ogg \
-	$(LOCAL_PATH)/newwavelabs/EtherShake.ogg:system/media/audio/ringtones/EtherShake.ogg \
-	$(LOCAL_PATH)/newwavelabs/Growl.ogg:system/media/audio/ringtones/Growl.ogg \
-	$(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:system/media/audio/ringtones/LoopyLounge.ogg \
-	$(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:system/media/audio/ringtones/LoveFlute.ogg \
-	$(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:system/media/audio/ringtones/MidEvilJaunt.ogg \
-	$(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:system/media/audio/ringtones/MildlyAlarming.ogg \
-	$(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:system/media/audio/ringtones/NewPlayer.ogg \
-	$(LOCAL_PATH)/newwavelabs/Noises1.ogg:system/media/audio/ringtones/Noises1.ogg \
-	$(LOCAL_PATH)/newwavelabs/Noises2.ogg:system/media/audio/ringtones/Noises2.ogg \
-	$(LOCAL_PATH)/newwavelabs/Noises3.ogg:system/media/audio/ringtones/Noises3.ogg \
-	$(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \
-	$(LOCAL_PATH)/newwavelabs/Terminated.ogg:system/media/audio/ringtones/Terminated.ogg \
-	$(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \
-	$(LOCAL_PATH)/newwavelabs/World.ogg:system/media/audio/ringtones/World.ogg \
-	$(LOCAL_PATH)/newwavelabs/DearDeer.ogg:system/media/audio/notifications/DearDeer.ogg \
-	$(LOCAL_PATH)/newwavelabs/DontPanic.ogg:system/media/audio/notifications/DontPanic.ogg \
-	$(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \
-	$(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:system/media/audio/notifications/KzurbSonar.ogg \
-	$(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:system/media/audio/notifications/OnTheHunt.ogg \
-	$(LOCAL_PATH)/newwavelabs/Voila.ogg:system/media/audio/notifications/Voila.ogg \
-	$(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:system/media/audio/ringtones/Big_Easy.ogg \
-	$(LOCAL_PATH)/newwavelabs/Bollywood.ogg:system/media/audio/ringtones/Bollywood.ogg \
-	$(LOCAL_PATH)/newwavelabs/Cairo.ogg:system/media/audio/ringtones/Cairo.ogg \
-	$(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:system/media/audio/ringtones/Calypso_Steel.ogg \
-	$(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:system/media/audio/ringtones/Champagne_Edition.ogg \
-	$(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:system/media/audio/ringtones/Club_Cubano.ogg \
-	$(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:system/media/audio/ringtones/Eastern_Sky.ogg \
-	$(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:system/media/audio/ringtones/Funk_Yall.ogg \
-	$(LOCAL_PATH)/newwavelabs/Savannah.ogg:system/media/audio/ringtones/Savannah.ogg \
-	$(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:system/media/audio/ringtones/Gimme_Mo_Town.ogg \
-	$(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:system/media/audio/ringtones/Glacial_Groove.ogg \
-	$(LOCAL_PATH)/newwavelabs/Seville.ogg:system/media/audio/ringtones/Seville.ogg \
-	$(LOCAL_PATH)/newwavelabs/No_Limits.ogg:system/media/audio/ringtones/No_Limits.ogg \
-	$(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:system/media/audio/ringtones/Paradise_Island.ogg \
-	$(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:system/media/audio/ringtones/Road_Trip.ogg \
-	$(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:system/media/audio/ringtones/Shes_All_That.ogg \
-	$(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:system/media/audio/ringtones/Steppin_Out.ogg \
-	$(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:system/media/audio/ringtones/Third_Eye.ogg \
-	$(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:system/media/audio/ringtones/Thunderfoot.ogg \
-	$(LOCAL_PATH)/newwavelabs/HalfwayHome.ogg:system/media/audio/ringtones/HalfwayHome.ogg \
-	$(LOCAL_PATH)/newwavelabs/CrayonRock.ogg:system/media/audio/ringtones/CrayonRock.ogg \
-	$(LOCAL_PATH)/newwavelabs/DancinFool.ogg:system/media/audio/ringtones/DancinFool.ogg \
-	$(LOCAL_PATH)/newwavelabs/BussaMove.ogg:system/media/audio/ringtones/BussaMove.ogg \
-	$(LOCAL_PATH)/newwavelabs/DonMessWivIt.ogg:system/media/audio/ringtones/DonMessWivIt.ogg \
-	$(LOCAL_PATH)/newwavelabs/SilkyWay.ogg:system/media/audio/ringtones/SilkyWay.ogg \
-	$(LOCAL_PATH)/newwavelabs/Playa.ogg:system/media/audio/ringtones/Playa.ogg
+	$(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BentleyDubs.ogg \
+	$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BirdLoop.ogg \
+	$(LOCAL_PATH)/newwavelabs/CurveBall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CurveBall.ogg \
+	$(LOCAL_PATH)/newwavelabs/EtherShake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/EtherShake.ogg \
+	$(LOCAL_PATH)/newwavelabs/Growl.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Growl.ogg \
+	$(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoopyLounge.ogg \
+	$(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoveFlute.ogg \
+	$(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MidEvilJaunt.ogg \
+	$(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MildlyAlarming.ogg \
+	$(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/NewPlayer.ogg \
+	$(LOCAL_PATH)/newwavelabs/Noises1.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises1.ogg \
+	$(LOCAL_PATH)/newwavelabs/Noises2.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises2.ogg \
+	$(LOCAL_PATH)/newwavelabs/Noises3.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises3.ogg \
+	$(LOCAL_PATH)/newwavelabs/OrganDub.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/OrganDub.ogg \
+	$(LOCAL_PATH)/newwavelabs/Terminated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Terminated.ogg \
+	$(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/TwirlAway.ogg \
+	$(LOCAL_PATH)/newwavelabs/World.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/World.ogg \
+	$(LOCAL_PATH)/newwavelabs/DearDeer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DearDeer.ogg \
+	$(LOCAL_PATH)/newwavelabs/DontPanic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DontPanic.ogg \
+	$(LOCAL_PATH)/newwavelabs/Highwire.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Highwire.ogg \
+	$(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/KzurbSonar.ogg \
+	$(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/OnTheHunt.ogg \
+	$(LOCAL_PATH)/newwavelabs/Voila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Voila.ogg \
+	$(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Big_Easy.ogg \
+	$(LOCAL_PATH)/newwavelabs/Bollywood.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Bollywood.ogg \
+	$(LOCAL_PATH)/newwavelabs/Cairo.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cairo.ogg \
+	$(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Calypso_Steel.ogg \
+	$(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Champagne_Edition.ogg \
+	$(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Club_Cubano.ogg \
+	$(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Eastern_Sky.ogg \
+	$(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Funk_Yall.ogg \
+	$(LOCAL_PATH)/newwavelabs/Savannah.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Savannah.ogg \
+	$(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Gimme_Mo_Town.ogg \
+	$(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Glacial_Groove.ogg \
+	$(LOCAL_PATH)/newwavelabs/Seville.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Seville.ogg \
+	$(LOCAL_PATH)/newwavelabs/No_Limits.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/No_Limits.ogg \
+	$(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Paradise_Island.ogg \
+	$(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Road_Trip.ogg \
+	$(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Shes_All_That.ogg \
+	$(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Steppin_Out.ogg \
+	$(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Third_Eye.ogg \
+	$(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Thunderfoot.ogg \
+	$(LOCAL_PATH)/newwavelabs/HalfwayHome.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/HalfwayHome.ogg \
+	$(LOCAL_PATH)/newwavelabs/CrayonRock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CrayonRock.ogg \
+	$(LOCAL_PATH)/newwavelabs/DancinFool.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DancinFool.ogg \
+	$(LOCAL_PATH)/newwavelabs/BussaMove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BussaMove.ogg \
+	$(LOCAL_PATH)/newwavelabs/DonMessWivIt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DonMessWivIt.ogg \
+	$(LOCAL_PATH)/newwavelabs/SilkyWay.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SilkyWay.ogg \
+	$(LOCAL_PATH)/newwavelabs/Playa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Playa.ogg
 endif
diff --git a/data/sounds/AudioPackage4.mk b/data/sounds/AudioPackage4.mk
index d376a2d..54c3c02 100644
--- a/data/sounds/AudioPackage4.mk
+++ b/data/sounds/AudioPackage4.mk
@@ -10,98 +10,98 @@
 LOCAL_PATH:= frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/F1_MissedCall.ogg:system/media/audio/notifications/F1_MissedCall.ogg \
-	$(LOCAL_PATH)/F1_New_MMS.ogg:system/media/audio/notifications/F1_New_MMS.ogg \
-	$(LOCAL_PATH)/F1_New_SMS.ogg:system/media/audio/notifications/F1_New_SMS.ogg \
-	$(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \
-	$(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \
-	$(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \
-	$(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:system/media/audio/notifications/Beat_Box_Android.ogg \
-	$(LOCAL_PATH)/notifications/Cricket.ogg:system/media/audio/notifications/Cricket.ogg \
-	$(LOCAL_PATH)/notifications/Doink.ogg:system/media/audio/notifications/Doink.ogg \
-	$(LOCAL_PATH)/notifications/Drip.ogg:system/media/audio/notifications/Drip.ogg \
-	$(LOCAL_PATH)/notifications/Heaven.ogg:system/media/audio/notifications/Heaven.ogg \
-	$(LOCAL_PATH)/notifications/SpaceSeed.ogg:system/media/audio/notifications/SpaceSeed.ogg \
-	$(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \
-	$(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \
-	$(LOCAL_PATH)/notifications/moonbeam.ogg:system/media/audio/notifications/moonbeam.ogg \
-	$(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \
-	$(LOCAL_PATH)/notifications/pizzicato.ogg:system/media/audio/notifications/pizzicato.ogg \
-	$(LOCAL_PATH)/notifications/Plastic_Pipe.ogg:system/media/audio/notifications/Plastic_Pipe.ogg \
-	$(LOCAL_PATH)/notifications/tweeters.ogg:system/media/audio/notifications/tweeters.ogg \
-	$(LOCAL_PATH)/effects/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
-	$(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
-	$(LOCAL_PATH)/effects/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \
-	$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
-	$(LOCAL_PATH)/effects/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
-	$(LOCAL_PATH)/effects/Dock.ogg:system/media/audio/ui/Dock.ogg \
-	$(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
-	$(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \
-	$(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
-	$(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
-	$(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
-	$(LOCAL_PATH)/ringtones/FreeFlight.ogg:system/media/audio/ringtones/FreeFlight.ogg \
-	$(LOCAL_PATH)/newwavelabs/Backroad.ogg:system/media/audio/ringtones/Backroad.ogg \
-	$(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:system/media/audio/notifications/CaffeineSnake.ogg
+	$(LOCAL_PATH)/F1_MissedCall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_MissedCall.ogg \
+	$(LOCAL_PATH)/F1_New_MMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_MMS.ogg \
+	$(LOCAL_PATH)/F1_New_SMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_SMS.ogg \
+	$(LOCAL_PATH)/Alarm_Buzzer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Buzzer.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_01.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_01.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_02.ogg \
+	$(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \
+	$(LOCAL_PATH)/Alarm_Rooster_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Rooster_02.ogg \
+	$(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beat_Box_Android.ogg \
+	$(LOCAL_PATH)/notifications/Cricket.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Cricket.ogg \
+	$(LOCAL_PATH)/notifications/Doink.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Doink.ogg \
+	$(LOCAL_PATH)/notifications/Drip.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Drip.ogg \
+	$(LOCAL_PATH)/notifications/Heaven.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Heaven.ogg \
+	$(LOCAL_PATH)/notifications/SpaceSeed.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/SpaceSeed.ogg \
+	$(LOCAL_PATH)/notifications/TaDa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/TaDa.ogg \
+	$(LOCAL_PATH)/notifications/Tinkerbell.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tinkerbell.ogg \
+	$(LOCAL_PATH)/notifications/moonbeam.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/moonbeam.ogg \
+	$(LOCAL_PATH)/notifications/pixiedust.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pixiedust.ogg \
+	$(LOCAL_PATH)/notifications/pizzicato.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pizzicato.ogg \
+	$(LOCAL_PATH)/notifications/Plastic_Pipe.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Plastic_Pipe.ogg \
+	$(LOCAL_PATH)/notifications/tweeters.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/tweeters.ogg \
+	$(LOCAL_PATH)/effects/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+	$(LOCAL_PATH)/effects/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \
+	$(LOCAL_PATH)/effects/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \
+	$(LOCAL_PATH)/effects/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+	$(LOCAL_PATH)/Ring_Classic_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Classic_02.ogg \
+	$(LOCAL_PATH)/Ring_Digital_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Digital_02.ogg \
+	$(LOCAL_PATH)/Ring_Synth_04.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_04.ogg \
+	$(LOCAL_PATH)/Ring_Synth_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_02.ogg \
+	$(LOCAL_PATH)/ringtones/FreeFlight.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/FreeFlight.ogg \
+	$(LOCAL_PATH)/newwavelabs/Backroad.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Backroad.ogg \
+	$(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CaffeineSnake.ogg
 
 ifneq ($(MINIMAL_NEWWAVELABS),true)
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/newwavelabs/DearDeer.ogg:system/media/audio/notifications/DearDeer.ogg \
-	$(LOCAL_PATH)/newwavelabs/DontPanic.ogg:system/media/audio/notifications/DontPanic.ogg \
-	$(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \
-	$(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:system/media/audio/notifications/KzurbSonar.ogg \
-	$(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:system/media/audio/notifications/OnTheHunt.ogg \
-	$(LOCAL_PATH)/newwavelabs/Voila.ogg:system/media/audio/notifications/Voila.ogg \
-	$(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:system/media/audio/ringtones/Big_Easy.ogg \
-	$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
-	$(LOCAL_PATH)/newwavelabs/Bollywood.ogg:system/media/audio/ringtones/Bollywood.ogg \
-	$(LOCAL_PATH)/newwavelabs/BussaMove.ogg:system/media/audio/ringtones/BussaMove.ogg \
-	$(LOCAL_PATH)/newwavelabs/Cairo.ogg:system/media/audio/ringtones/Cairo.ogg \
-	$(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:system/media/audio/ringtones/Calypso_Steel.ogg \
-	$(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:system/media/audio/ringtones/Champagne_Edition.ogg \
-	$(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:system/media/audio/ringtones/Club_Cubano.ogg \
-	$(LOCAL_PATH)/newwavelabs/CrayonRock.ogg:system/media/audio/ringtones/CrayonRock.ogg \
-	$(LOCAL_PATH)/newwavelabs/CurveBall.ogg:system/media/audio/ringtones/CurveBall.ogg \
-	$(LOCAL_PATH)/newwavelabs/DancinFool.ogg:system/media/audio/ringtones/DancinFool.ogg \
-	$(LOCAL_PATH)/newwavelabs/Ding.ogg:system/media/audio/ringtones/Ding.ogg \
-	$(LOCAL_PATH)/newwavelabs/DonMessWivIt.ogg:system/media/audio/ringtones/DonMessWivIt.ogg \
-	$(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:system/media/audio/ringtones/Eastern_Sky.ogg \
-	$(LOCAL_PATH)/newwavelabs/Enter_the_Nexus.ogg:system/media/audio/ringtones/Enter_the_Nexus.ogg \
-	$(LOCAL_PATH)/newwavelabs/EtherShake.ogg:system/media/audio/ringtones/EtherShake.ogg \
-	$(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:system/media/audio/ringtones/Funk_Yall.ogg \
-	$(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:system/media/audio/ringtones/Gimme_Mo_Town.ogg \
-	$(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:system/media/audio/ringtones/Glacial_Groove.ogg \
-	$(LOCAL_PATH)/newwavelabs/Growl.ogg:system/media/audio/ringtones/Growl.ogg \
-	$(LOCAL_PATH)/newwavelabs/HalfwayHome.ogg:system/media/audio/ringtones/HalfwayHome.ogg \
-	$(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:system/media/audio/ringtones/LoopyLounge.ogg \
-	$(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:system/media/audio/ringtones/LoveFlute.ogg \
-	$(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:system/media/audio/ringtones/MidEvilJaunt.ogg \
-	$(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:system/media/audio/ringtones/MildlyAlarming.ogg \
-	$(LOCAL_PATH)/newwavelabs/Nairobi.ogg:system/media/audio/ringtones/Nairobi.ogg \
-	$(LOCAL_PATH)/newwavelabs/Nassau.ogg:system/media/audio/ringtones/Nassau.ogg \
-	$(LOCAL_PATH)/newwavelabs/No_Limits.ogg:system/media/audio/ringtones/No_Limits.ogg \
-	$(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \
-	$(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:system/media/audio/ringtones/Paradise_Island.ogg \
-	$(LOCAL_PATH)/newwavelabs/Playa.ogg:system/media/audio/ringtones/Playa.ogg \
-	$(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:system/media/audio/ringtones/Road_Trip.ogg \
-	$(LOCAL_PATH)/newwavelabs/Safari.ogg:system/media/audio/ringtones/Safari.ogg \
-	$(LOCAL_PATH)/newwavelabs/Seville.ogg:system/media/audio/ringtones/Seville.ogg \
-	$(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:system/media/audio/ringtones/Shes_All_That.ogg \
-	$(LOCAL_PATH)/newwavelabs/SilkyWay.ogg:system/media/audio/ringtones/SilkyWay.ogg \
-	$(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:system/media/audio/ringtones/Steppin_Out.ogg \
-	$(LOCAL_PATH)/newwavelabs/Terminated.ogg:system/media/audio/ringtones/Terminated.ogg \
-	$(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:system/media/audio/ringtones/Third_Eye.ogg \
-	$(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \
-	$(LOCAL_PATH)/newwavelabs/World.ogg:system/media/audio/ringtones/World.ogg
+	$(LOCAL_PATH)/newwavelabs/DearDeer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DearDeer.ogg \
+	$(LOCAL_PATH)/newwavelabs/DontPanic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DontPanic.ogg \
+	$(LOCAL_PATH)/newwavelabs/Highwire.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Highwire.ogg \
+	$(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/KzurbSonar.ogg \
+	$(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/OnTheHunt.ogg \
+	$(LOCAL_PATH)/newwavelabs/Voila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Voila.ogg \
+	$(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Big_Easy.ogg \
+	$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BirdLoop.ogg \
+	$(LOCAL_PATH)/newwavelabs/Bollywood.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Bollywood.ogg \
+	$(LOCAL_PATH)/newwavelabs/BussaMove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BussaMove.ogg \
+	$(LOCAL_PATH)/newwavelabs/Cairo.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cairo.ogg \
+	$(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Calypso_Steel.ogg \
+	$(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Champagne_Edition.ogg \
+	$(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Club_Cubano.ogg \
+	$(LOCAL_PATH)/newwavelabs/CrayonRock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CrayonRock.ogg \
+	$(LOCAL_PATH)/newwavelabs/CurveBall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CurveBall.ogg \
+	$(LOCAL_PATH)/newwavelabs/DancinFool.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DancinFool.ogg \
+	$(LOCAL_PATH)/newwavelabs/Ding.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ding.ogg \
+	$(LOCAL_PATH)/newwavelabs/DonMessWivIt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DonMessWivIt.ogg \
+	$(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Eastern_Sky.ogg \
+	$(LOCAL_PATH)/newwavelabs/Enter_the_Nexus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Enter_the_Nexus.ogg \
+	$(LOCAL_PATH)/newwavelabs/EtherShake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/EtherShake.ogg \
+	$(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Funk_Yall.ogg \
+	$(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Gimme_Mo_Town.ogg \
+	$(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Glacial_Groove.ogg \
+	$(LOCAL_PATH)/newwavelabs/Growl.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Growl.ogg \
+	$(LOCAL_PATH)/newwavelabs/HalfwayHome.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/HalfwayHome.ogg \
+	$(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoopyLounge.ogg \
+	$(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoveFlute.ogg \
+	$(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MidEvilJaunt.ogg \
+	$(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MildlyAlarming.ogg \
+	$(LOCAL_PATH)/newwavelabs/Nairobi.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Nairobi.ogg \
+	$(LOCAL_PATH)/newwavelabs/Nassau.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Nassau.ogg \
+	$(LOCAL_PATH)/newwavelabs/No_Limits.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/No_Limits.ogg \
+	$(LOCAL_PATH)/newwavelabs/OrganDub.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/OrganDub.ogg \
+	$(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Paradise_Island.ogg \
+	$(LOCAL_PATH)/newwavelabs/Playa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Playa.ogg \
+	$(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Road_Trip.ogg \
+	$(LOCAL_PATH)/newwavelabs/Safari.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Safari.ogg \
+	$(LOCAL_PATH)/newwavelabs/Seville.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Seville.ogg \
+	$(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Shes_All_That.ogg \
+	$(LOCAL_PATH)/newwavelabs/SilkyWay.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SilkyWay.ogg \
+	$(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Steppin_Out.ogg \
+	$(LOCAL_PATH)/newwavelabs/Terminated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Terminated.ogg \
+	$(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Third_Eye.ogg \
+	$(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/TwirlAway.ogg \
+	$(LOCAL_PATH)/newwavelabs/World.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/World.ogg
 endif
diff --git a/data/sounds/AudioPackage5.mk b/data/sounds/AudioPackage5.mk
index 72384c8..8a03a2e1 100644
--- a/data/sounds/AudioPackage5.mk
+++ b/data/sounds/AudioPackage5.mk
@@ -8,69 +8,69 @@
 LOCAL_PATH:= frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \
-	$(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \
-	$(LOCAL_PATH)/effects/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
-	$(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
-	$(LOCAL_PATH)/effects/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \
-	$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
-	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
-	$(LOCAL_PATH)/effects/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
-	$(LOCAL_PATH)/effects/Dock.ogg:system/media/audio/ui/Dock.ogg \
-	$(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/Lock.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
-	$(LOCAL_PATH)/notifications/Aldebaran.ogg:system/media/audio/notifications/Aldebaran.ogg \
-	$(LOCAL_PATH)/notifications/Altair.ogg:system/media/audio/notifications/Altair.ogg \
-	$(LOCAL_PATH)/notifications/Antares.ogg:system/media/audio/notifications/Antares.ogg \
-	$(LOCAL_PATH)/notifications/arcturus.ogg:system/media/audio/notifications/arcturus.ogg \
-	$(LOCAL_PATH)/notifications/Betelgeuse.ogg:system/media/audio/notifications/Betelgeuse.ogg \
-	$(LOCAL_PATH)/notifications/Canopus.ogg:system/media/audio/notifications/Canopus.ogg \
-	$(LOCAL_PATH)/notifications/Capella.ogg:system/media/audio/notifications/Capella.ogg \
-	$(LOCAL_PATH)/notifications/Castor.ogg:system/media/audio/notifications/Castor.ogg \
-	$(LOCAL_PATH)/notifications/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \
-	$(LOCAL_PATH)/notifications/Deneb.ogg:system/media/audio/notifications/Deneb.ogg \
-	$(LOCAL_PATH)/notifications/Electra.ogg:system/media/audio/notifications/Electra.ogg \
-	$(LOCAL_PATH)/notifications/Fomalhaut.ogg:system/media/audio/notifications/Fomalhaut.ogg \
-	$(LOCAL_PATH)/notifications/Merope.ogg:system/media/audio/notifications/Merope.ogg \
-	$(LOCAL_PATH)/notifications/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \
-	$(LOCAL_PATH)/notifications/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \
-	$(LOCAL_PATH)/notifications/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \
-	$(LOCAL_PATH)/notifications/regulus.ogg:system/media/audio/notifications/regulus.ogg \
-	$(LOCAL_PATH)/notifications/sirius.ogg:system/media/audio/notifications/sirius.ogg \
-	$(LOCAL_PATH)/notifications/Sirrah.ogg:system/media/audio/notifications/Sirrah.ogg \
-	$(LOCAL_PATH)/notifications/vega.ogg:system/media/audio/notifications/vega.ogg \
-	$(LOCAL_PATH)/ringtones/ANDROMEDA.ogg:system/media/audio/ringtones/ANDROMEDA.ogg \
-	$(LOCAL_PATH)/ringtones/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
-	$(LOCAL_PATH)/ringtones/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \
-	$(LOCAL_PATH)/ringtones/BOOTES.ogg:system/media/audio/ringtones/BOOTES.ogg \
-	$(LOCAL_PATH)/ringtones/CANISMAJOR.ogg:system/media/audio/ringtones/CANISMAJOR.ogg \
-	$(LOCAL_PATH)/ringtones/Carina.ogg:system/media/audio/ringtones/Carina.ogg \
-	$(LOCAL_PATH)/ringtones/CASSIOPEIA.ogg:system/media/audio/ringtones/CASSIOPEIA.ogg \
-	$(LOCAL_PATH)/ringtones/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \
-	$(LOCAL_PATH)/ringtones/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \
-	$(LOCAL_PATH)/ringtones/Draco.ogg:system/media/audio/ringtones/Draco.ogg \
-	$(LOCAL_PATH)/ringtones/Eridani.ogg:system/media/audio/ringtones/Eridani.ogg \
-	$(LOCAL_PATH)/ringtones/hydra.ogg:system/media/audio/ringtones/hydra.ogg \
-	$(LOCAL_PATH)/ringtones/Lyra.ogg:system/media/audio/ringtones/Lyra.ogg \
-	$(LOCAL_PATH)/ringtones/Machina.ogg:system/media/audio/ringtones/Machina.ogg \
-	$(LOCAL_PATH)/ringtones/Orion.ogg:system/media/audio/ringtones/Orion.ogg \
-	$(LOCAL_PATH)/ringtones/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \
-	$(LOCAL_PATH)/ringtones/PERSEUS.ogg:system/media/audio/ringtones/PERSEUS.ogg \
-	$(LOCAL_PATH)/ringtones/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \
-	$(LOCAL_PATH)/ringtones/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \
-	$(LOCAL_PATH)/ringtones/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \
-	$(LOCAL_PATH)/ringtones/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \
-	$(LOCAL_PATH)/ringtones/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \
-	$(LOCAL_PATH)/ringtones/Testudo.ogg:system/media/audio/ringtones/Testudo.ogg \
-	$(LOCAL_PATH)/ringtones/URSAMINOR.ogg:system/media/audio/ringtones/URSAMINOR.ogg \
-	$(LOCAL_PATH)/ringtones/Vespa.ogg:system/media/audio/ringtones/Vespa.ogg
+	$(LOCAL_PATH)/Alarm_Buzzer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Buzzer.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_01.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_01.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_02.ogg \
+	$(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \
+	$(LOCAL_PATH)/effects/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+	$(LOCAL_PATH)/effects/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \
+	$(LOCAL_PATH)/effects/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \
+	$(LOCAL_PATH)/effects/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \
+	$(LOCAL_PATH)/effects/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+	$(LOCAL_PATH)/notifications/Aldebaran.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Aldebaran.ogg \
+	$(LOCAL_PATH)/notifications/Altair.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Altair.ogg \
+	$(LOCAL_PATH)/notifications/Antares.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Antares.ogg \
+	$(LOCAL_PATH)/notifications/arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/arcturus.ogg \
+	$(LOCAL_PATH)/notifications/Betelgeuse.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Betelgeuse.ogg \
+	$(LOCAL_PATH)/notifications/Canopus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Canopus.ogg \
+	$(LOCAL_PATH)/notifications/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \
+	$(LOCAL_PATH)/notifications/Castor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Castor.ogg \
+	$(LOCAL_PATH)/notifications/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \
+	$(LOCAL_PATH)/notifications/Deneb.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Deneb.ogg \
+	$(LOCAL_PATH)/notifications/Electra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Electra.ogg \
+	$(LOCAL_PATH)/notifications/Fomalhaut.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Fomalhaut.ogg \
+	$(LOCAL_PATH)/notifications/Merope.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Merope.ogg \
+	$(LOCAL_PATH)/notifications/Polaris.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Polaris.ogg \
+	$(LOCAL_PATH)/notifications/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \
+	$(LOCAL_PATH)/notifications/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \
+	$(LOCAL_PATH)/notifications/regulus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/regulus.ogg \
+	$(LOCAL_PATH)/notifications/sirius.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/sirius.ogg \
+	$(LOCAL_PATH)/notifications/Sirrah.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Sirrah.ogg \
+	$(LOCAL_PATH)/notifications/vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/vega.ogg \
+	$(LOCAL_PATH)/ringtones/ANDROMEDA.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ANDROMEDA.ogg \
+	$(LOCAL_PATH)/ringtones/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \
+	$(LOCAL_PATH)/ringtones/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \
+	$(LOCAL_PATH)/ringtones/BOOTES.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BOOTES.ogg \
+	$(LOCAL_PATH)/ringtones/CANISMAJOR.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CANISMAJOR.ogg \
+	$(LOCAL_PATH)/ringtones/Carina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Carina.ogg \
+	$(LOCAL_PATH)/ringtones/CASSIOPEIA.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CASSIOPEIA.ogg \
+	$(LOCAL_PATH)/ringtones/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \
+	$(LOCAL_PATH)/ringtones/Cygnus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cygnus.ogg \
+	$(LOCAL_PATH)/ringtones/Draco.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Draco.ogg \
+	$(LOCAL_PATH)/ringtones/Eridani.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Eridani.ogg \
+	$(LOCAL_PATH)/ringtones/hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/hydra.ogg \
+	$(LOCAL_PATH)/ringtones/Lyra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Lyra.ogg \
+	$(LOCAL_PATH)/ringtones/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \
+	$(LOCAL_PATH)/ringtones/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \
+	$(LOCAL_PATH)/ringtones/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \
+	$(LOCAL_PATH)/ringtones/PERSEUS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/PERSEUS.ogg \
+	$(LOCAL_PATH)/ringtones/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \
+	$(LOCAL_PATH)/ringtones/Rigel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rigel.ogg \
+	$(LOCAL_PATH)/ringtones/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \
+	$(LOCAL_PATH)/ringtones/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \
+	$(LOCAL_PATH)/ringtones/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \
+	$(LOCAL_PATH)/ringtones/Testudo.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Testudo.ogg \
+	$(LOCAL_PATH)/ringtones/URSAMINOR.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/URSAMINOR.ogg \
+	$(LOCAL_PATH)/ringtones/Vespa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Vespa.ogg
diff --git a/data/sounds/AudioPackage6.mk b/data/sounds/AudioPackage6.mk
index 5413704..a778261 100644
--- a/data/sounds/AudioPackage6.mk
+++ b/data/sounds/AudioPackage6.mk
@@ -8,41 +8,41 @@
 LOCAL_PATH:= frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/alarms/ogg/Barium.ogg:system/media/audio/alarms/Barium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Scandium.ogg:system/media/audio/alarms/Scandium.ogg \
-	$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
-	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
-	$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Antimony.ogg:system/media/audio/notifications/Antimony.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Argon.ogg:system/media/audio/notifications/Argon.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Beryllium.ogg:system/media/audio/notifications/Beryllium.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Cobalt.ogg:system/media/audio/notifications/Cobalt.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Fluorine.ogg:system/media/audio/notifications/Fluorine.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Gallium.ogg:system/media/audio/notifications/Gallium.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Helium.ogg:system/media/audio/notifications/Helium.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Iridium.ogg:system/media/audio/notifications/Iridium.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Krypton.ogg:system/media/audio/notifications/Krypton.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Palladium.ogg:system/media/audio/notifications/Palladium.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Radon.ogg:system/media/audio/notifications/Radon.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Rubidium.ogg:system/media/audio/notifications/Rubidium.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Selenium.ogg:system/media/audio/notifications/Selenium.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Strontium.ogg:system/media/audio/notifications/Strontium.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Thallium.ogg:system/media/audio/notifications/Thallium.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Xenon.ogg:system/media/audio/notifications/Xenon.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Zirconium.ogg:system/media/audio/notifications/Zirconium.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Barium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Barium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Cesium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Cesium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Plutonium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Scandium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Scandium.ogg \
+	$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Antimony.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Antimony.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Argon.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Beryllium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beryllium.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Cobalt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Cobalt.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Fluorine.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Fluorine.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Gallium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Gallium.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Helium.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Iridium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Iridium.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Krypton.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Palladium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Palladium.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Radon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Radon.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Rubidium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Rubidium.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Selenium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Selenium.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Strontium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Strontium.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Thallium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Thallium.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Xenon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Xenon.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Zirconium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Zirconium.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \
diff --git a/data/sounds/AudioPackage7.mk b/data/sounds/AudioPackage7.mk
index e4763be..27e349d2 100644
--- a/data/sounds/AudioPackage7.mk
+++ b/data/sounds/AudioPackage7.mk
@@ -8,64 +8,64 @@
 LOCAL_PATH:= frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Fermium.ogg:system/media/audio/alarms/Fermium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Hassium.ogg:system/media/audio/alarms/Hassium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:system/media/audio/alarms/Neptunium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:system/media/audio/alarms/Nobelium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \
-	$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
-	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
-	$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \
-	$(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Lalande.ogg:system/media/audio/notifications/Lalande.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg
+	$(LOCAL_PATH)/alarms/ogg/Cesium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Cesium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Fermium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Fermium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Hassium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Hassium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neptunium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Nobelium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Plutonium.ogg \
+	$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Bellatrix.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \
+	$(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Lalande.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Lalande.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Polaris.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Polaris.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Proxima.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Proxima.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Tejat.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Upsilon.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Andromeda.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CanisMajor.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Carina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Carina.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cygnus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Draco.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Draco.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Hydra.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Perseus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rigel.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/UrsaMinor.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Zeta.ogg
diff --git a/data/sounds/AudioPackage7alt.mk b/data/sounds/AudioPackage7alt.mk
index 30e6173..a0f4d89 100644
--- a/data/sounds/AudioPackage7alt.mk
+++ b/data/sounds/AudioPackage7alt.mk
@@ -8,63 +8,63 @@
 LOCAL_PATH:= frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/alarms/ogg-jp/Argon.ogg:system/media/audio/alarms/Argon.ogg \
-	$(LOCAL_PATH)/alarms/ogg-jp/Carbon.ogg:system/media/audio/alarms/Carbon.ogg \
-	$(LOCAL_PATH)/alarms/ogg-jp/Helium.ogg:system/media/audio/alarms/Helium.ogg \
-	$(LOCAL_PATH)/alarms/ogg-jp/Krypton.ogg:system/media/audio/alarms/Krypton.ogg \
-	$(LOCAL_PATH)/alarms/ogg-jp/Neon.ogg:system/media/audio/alarms/Neon.ogg \
-	$(LOCAL_PATH)/alarms/ogg-jp/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \
-	$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \
-	$(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
-	$(LOCAL_PATH)/effects/ogg/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
-	$(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
-	$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \
-	$(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Lalande.ogg:system/media/audio/notifications/Lalande.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg
+	$(LOCAL_PATH)/alarms/ogg-jp/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Argon.ogg \
+	$(LOCAL_PATH)/alarms/ogg-jp/Carbon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Carbon.ogg \
+	$(LOCAL_PATH)/alarms/ogg-jp/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Helium.ogg \
+	$(LOCAL_PATH)/alarms/ogg-jp/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Krypton.ogg \
+	$(LOCAL_PATH)/alarms/ogg-jp/Neon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neon.ogg \
+	$(LOCAL_PATH)/alarms/ogg-jp/Oxygen.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Oxygen.ogg \
+	$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \
+	$(LOCAL_PATH)/effects/ogg/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/ogg/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Bellatrix.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \
+	$(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Lalande.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Lalande.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Polaris.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Polaris.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Proxima.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Proxima.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Tejat.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Upsilon.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Andromeda.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CanisMajor.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Carina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Carina.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cygnus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Draco.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Draco.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Hydra.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Perseus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rigel.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/UrsaMinor.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Zeta.ogg
diff --git a/data/sounds/AudioPackage8.mk b/data/sounds/AudioPackage8.mk
index b38e62d..032b4d2 100644
--- a/data/sounds/AudioPackage8.mk
+++ b/data/sounds/AudioPackage8.mk
@@ -8,66 +8,66 @@
 LOCAL_PATH:= frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Fermium.ogg:system/media/audio/alarms/Fermium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Hassium.ogg:system/media/audio/alarms/Hassium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:system/media/audio/alarms/Neptunium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:system/media/audio/alarms/Nobelium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \
-	$(LOCAL_PATH)/alarms/ogg/Promethium.ogg:system/media/audio/alarms/Promethium.ogg \
-	$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
-	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
-	$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \
-	$(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Lalande.ogg:system/media/audio/notifications/Lalande.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg
+	$(LOCAL_PATH)/alarms/ogg/Cesium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Cesium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Fermium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Fermium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Hassium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Hassium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neptunium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Nobelium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Osmium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Osmium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Plutonium.ogg \
+	$(LOCAL_PATH)/alarms/ogg/Promethium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Promethium.ogg \
+	$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Bellatrix.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \
+	$(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Lalande.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Lalande.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Polaris.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Polaris.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Proxima.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Proxima.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Tejat.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Upsilon.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Andromeda.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Aquila.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/ArgoNavis.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CanisMajor.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Carina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Carina.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Centaurus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cygnus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Draco.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Draco.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Hydra.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Machina.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Machina.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Orion.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pegasus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Perseus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Pyxis.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Rigel.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Scarabaeus.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Sceptrum.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Solarium.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/UrsaMinor.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Zeta.ogg
diff --git a/data/sounds/AudioPackage9.mk b/data/sounds/AudioPackage9.mk
index dbe1350..53cc8c0 100644
--- a/data/sounds/AudioPackage9.mk
+++ b/data/sounds/AudioPackage9.mk
@@ -8,43 +8,43 @@
 LOCAL_PATH:= frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-        $(LOCAL_PATH)/alarms/ogg/Argon.ogg:system/media/audio/alarms/Argon.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:system/media/audio/alarms/Carbon.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Helium.ogg:system/media/audio/alarms/Helium.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:system/media/audio/alarms/Krypton.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Neon.ogg:system/media/audio/alarms/Neon.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
-        $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
-	$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
-	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
-	$(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
-	$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:system/media/audio/ui/Trusted.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \
-	$(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
-	$(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg
+        $(LOCAL_PATH)/alarms/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Argon.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Carbon.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Helium.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Krypton.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Neon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Neon.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Oxygen.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Osmium.ogg \
+        $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Platinum.ogg \
+	$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_focus.ogg \
+	$(LOCAL_PATH)/effects/material/ogg/LowBattery.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/LowBattery.ogg \
+	$(LOCAL_PATH)/effects/ogg/Dock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Dock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Undock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Undock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Trusted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Alya.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Arcturus.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Capella.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Capella.ogg \
+	$(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CetiAlpha.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Hojus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Hojus.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Mira.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Mira.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Pollux.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Pollux.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Procyon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Procyon.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Shaula.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Shaula.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Spica.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Spica.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Syrma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Syrma.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Talitha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Talitha.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Tejat.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tejat.ogg \
+	$(LOCAL_PATH)/notifications/ogg/Vega.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Vega.ogg \
+	$(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Girtab.ogg
diff --git a/data/sounds/AudioPackageGo.mk b/data/sounds/AudioPackageGo.mk
index 0296219..e3b27f2 100644
--- a/data/sounds/AudioPackageGo.mk
+++ b/data/sounds/AudioPackageGo.mk
@@ -20,30 +20,30 @@
 # Ring_Synth_04 : Flutey Phone
 # Alarm_Beep_03 : Beep Beep Beep
 PRODUCT_COPY_FILES += \
-    $(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Argon.ogg:system/media/audio/notifications/Argon.ogg \
-    $(LOCAL_PATH)/notifications/Canopus.ogg:system/media/audio/notifications/Canopus.ogg \
-    $(LOCAL_PATH)/notifications/Deneb.ogg:system/media/audio/notifications/Deneb.ogg \
-    $(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Iridium.ogg:system/media/audio/notifications/Iridium.ogg \
-    $(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \
-    $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \
-    $(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \
-    $(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \
-    $(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
-    $(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:system/media/audio/ringtones/Kuma.ogg \
-    $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \
-    $(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Argon.ogg:system/media/audio/alarms/Argon.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
-    $(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Helium.ogg:system/media/audio/alarms/Helium.ogg \
-    $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \
-    $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Alya.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Alya.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Argon.ogg \
+    $(LOCAL_PATH)/notifications/Canopus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Canopus.ogg \
+    $(LOCAL_PATH)/notifications/Deneb.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Deneb.ogg \
+    $(LOCAL_PATH)/newwavelabs/Highwire.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Highwire.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Iridium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Iridium.ogg \
+    $(LOCAL_PATH)/notifications/pixiedust.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/pixiedust.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Talitha.ogg \
+    $(LOCAL_PATH)/Ring_Classic_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Classic_02.ogg \
+    $(LOCAL_PATH)/Ring_Synth_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_02.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Cygnus.ogg \
+    $(LOCAL_PATH)/Ring_Digital_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Digital_02.ogg \
+    $(LOCAL_PATH)/Ring_Synth_04.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_04.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Kuma.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Themos.ogg \
+    $(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Argon.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Argon.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Platinum.ogg \
+    $(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Helium.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Helium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Oxygen.ogg \
+    $(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
diff --git a/data/sounds/AudioTv.mk b/data/sounds/AudioTv.mk
index 91265af..d0006b7 100644
--- a/data/sounds/AudioTv.mk
+++ b/data/sounds/AudioTv.mk
@@ -15,8 +15,8 @@
 LOCAL_PATH := frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-    $(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-    $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg
+    $(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg
diff --git a/data/sounds/OriginalAudio.mk b/data/sounds/OriginalAudio.mk
index f683752..4d74d12 100644
--- a/data/sounds/OriginalAudio.mk
+++ b/data/sounds/OriginalAudio.mk
@@ -9,67 +9,67 @@
 LOCAL_PATH:= frameworks/base/data/sounds
 
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/F1_MissedCall.ogg:system/media/audio/notifications/F1_MissedCall.ogg \
-	$(LOCAL_PATH)/F1_New_MMS.ogg:system/media/audio/notifications/F1_New_MMS.ogg \
-	$(LOCAL_PATH)/F1_New_SMS.ogg:system/media/audio/notifications/F1_New_SMS.ogg \
-	$(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \
-	$(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \
-	$(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \
-	$(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \
-	$(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \
-	$(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
-	$(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
-	$(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
-	$(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:system/media/audio/notifications/Beat_Box_Android.ogg \
-	$(LOCAL_PATH)/notifications/Heaven.ogg:system/media/audio/notifications/Heaven.ogg \
-	$(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \
-	$(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \
-	$(LOCAL_PATH)/effects/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
-	$(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
-	$(LOCAL_PATH)/effects/VideoStop.ogg:system/media/audio/ui/VideoStop.ogg \
-	$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
-	$(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
-	$(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:system/media/audio/notifications/CaffeineSnake.ogg
+	$(LOCAL_PATH)/F1_MissedCall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_MissedCall.ogg \
+	$(LOCAL_PATH)/F1_New_MMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_MMS.ogg \
+	$(LOCAL_PATH)/F1_New_SMS.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/F1_New_SMS.ogg \
+	$(LOCAL_PATH)/Alarm_Buzzer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Buzzer.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_01.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_01.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_02.ogg \
+	$(LOCAL_PATH)/Alarm_Classic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Classic.ogg \
+	$(LOCAL_PATH)/Alarm_Beep_03.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_03.ogg \
+	$(LOCAL_PATH)/Alarm_Rooster_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Rooster_02.ogg \
+	$(LOCAL_PATH)/Ring_Classic_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Classic_02.ogg \
+	$(LOCAL_PATH)/Ring_Digital_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Digital_02.ogg \
+	$(LOCAL_PATH)/Ring_Synth_04.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_04.ogg \
+	$(LOCAL_PATH)/Ring_Synth_02.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Ring_Synth_02.ogg \
+	$(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Beat_Box_Android.ogg \
+	$(LOCAL_PATH)/notifications/Heaven.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Heaven.ogg \
+	$(LOCAL_PATH)/notifications/TaDa.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/TaDa.ogg \
+	$(LOCAL_PATH)/notifications/Tinkerbell.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Tinkerbell.ogg \
+	$(LOCAL_PATH)/effects/Effect_Tick.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \
+	$(LOCAL_PATH)/effects/KeypressStandard.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/KeypressSpacebar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/VideoRecord.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoRecord.ogg \
+	$(LOCAL_PATH)/effects/VideoStop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/VideoStop.ogg \
+	$(LOCAL_PATH)/effects/camera_click.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/camera_click.ogg \
+	$(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BeatPlucker.ogg \
+	$(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/CaffeineSnake.ogg
 
 ifneq ($(MINIMAL_NEWWAVELABS),true)
 PRODUCT_COPY_FILES += \
-	$(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \
-	$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
-	$(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:system/media/audio/ringtones/CaribbeanIce.ogg \
-	$(LOCAL_PATH)/newwavelabs/CurveBall.ogg:system/media/audio/ringtones/CurveBall.ogg \
-	$(LOCAL_PATH)/newwavelabs/EtherShake.ogg:system/media/audio/ringtones/EtherShake.ogg \
-	$(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:system/media/audio/ringtones/FriendlyGhost.ogg \
-	$(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:system/media/audio/ringtones/GameOverGuitar.ogg \
-	$(LOCAL_PATH)/newwavelabs/Growl.ogg:system/media/audio/ringtones/Growl.ogg \
-	$(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:system/media/audio/ringtones/InsertCoin.ogg \
-	$(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:system/media/audio/ringtones/LoopyLounge.ogg \
-	$(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:system/media/audio/ringtones/LoveFlute.ogg \
-	$(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:system/media/audio/ringtones/MidEvilJaunt.ogg \
-	$(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:system/media/audio/ringtones/MildlyAlarming.ogg \
-	$(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:system/media/audio/ringtones/NewPlayer.ogg \
-	$(LOCAL_PATH)/newwavelabs/Noises1.ogg:system/media/audio/ringtones/Noises1.ogg \
-	$(LOCAL_PATH)/newwavelabs/Noises2.ogg:system/media/audio/ringtones/Noises2.ogg \
-	$(LOCAL_PATH)/newwavelabs/Noises3.ogg:system/media/audio/ringtones/Noises3.ogg \
-	$(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \
-	$(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:system/media/audio/ringtones/RomancingTheTone.ogg \
-	$(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:system/media/audio/ringtones/SitarVsSitar.ogg \
-	$(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:system/media/audio/ringtones/SpringyJalopy.ogg \
-	$(LOCAL_PATH)/newwavelabs/Terminated.ogg:system/media/audio/ringtones/Terminated.ogg \
-	$(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \
-	$(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:system/media/audio/ringtones/VeryAlarmed.ogg \
-	$(LOCAL_PATH)/newwavelabs/World.ogg:system/media/audio/ringtones/World.ogg \
-	$(LOCAL_PATH)/newwavelabs/DearDeer.ogg:system/media/audio/notifications/DearDeer.ogg \
-	$(LOCAL_PATH)/newwavelabs/DontPanic.ogg:system/media/audio/notifications/DontPanic.ogg \
-	$(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \
-	$(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:system/media/audio/notifications/KzurbSonar.ogg \
-	$(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:system/media/audio/notifications/OnTheHunt.ogg \
-	$(LOCAL_PATH)/newwavelabs/Voila.ogg:system/media/audio/notifications/Voila.ogg \
-	$(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:system/media/audio/ringtones/CrazyDream.ogg \
-	$(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:system/media/audio/ringtones/DreamTheme.ogg
+	$(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BentleyDubs.ogg \
+	$(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/BirdLoop.ogg \
+	$(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CaribbeanIce.ogg \
+	$(LOCAL_PATH)/newwavelabs/CurveBall.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CurveBall.ogg \
+	$(LOCAL_PATH)/newwavelabs/EtherShake.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/EtherShake.ogg \
+	$(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/FriendlyGhost.ogg \
+	$(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/GameOverGuitar.ogg \
+	$(LOCAL_PATH)/newwavelabs/Growl.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Growl.ogg \
+	$(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/InsertCoin.ogg \
+	$(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoopyLounge.ogg \
+	$(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/LoveFlute.ogg \
+	$(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MidEvilJaunt.ogg \
+	$(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/MildlyAlarming.ogg \
+	$(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/NewPlayer.ogg \
+	$(LOCAL_PATH)/newwavelabs/Noises1.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises1.ogg \
+	$(LOCAL_PATH)/newwavelabs/Noises2.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises2.ogg \
+	$(LOCAL_PATH)/newwavelabs/Noises3.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Noises3.ogg \
+	$(LOCAL_PATH)/newwavelabs/OrganDub.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/OrganDub.ogg \
+	$(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/RomancingTheTone.ogg \
+	$(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SitarVsSitar.ogg \
+	$(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/SpringyJalopy.ogg \
+	$(LOCAL_PATH)/newwavelabs/Terminated.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/Terminated.ogg \
+	$(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/TwirlAway.ogg \
+	$(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/VeryAlarmed.ogg \
+	$(LOCAL_PATH)/newwavelabs/World.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/World.ogg \
+	$(LOCAL_PATH)/newwavelabs/DearDeer.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DearDeer.ogg \
+	$(LOCAL_PATH)/newwavelabs/DontPanic.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/DontPanic.ogg \
+	$(LOCAL_PATH)/newwavelabs/Highwire.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Highwire.ogg \
+	$(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/KzurbSonar.ogg \
+	$(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/OnTheHunt.ogg \
+	$(LOCAL_PATH)/newwavelabs/Voila.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Voila.ogg \
+	$(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/CrazyDream.ogg \
+	$(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ringtones/DreamTheme.ogg
 endif
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index 76eab4a..fcebad3 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -831,6 +831,7 @@
      *     content://media/<table_name>/<row_index> (or)
      *     file://sdcard/test.mp4
      *     http://test.com/test.mp4
+     *     https://test.com/test.mp4
      *
      * Here <table_name> shall be "video" or "audio" or "images"
      * <row_index> the index of the content in given table
@@ -843,7 +844,7 @@
                     scheme.equals(ContentResolver.SCHEME_FILE)) {
                 path = uri.getPath();
 
-            } else if (scheme.equals("http")) {
+            } else if (scheme.equals("http") || scheme.equals("https")) {
                 path = uri.toString();
 
             } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index ca9dc47..65aaba1 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -22,6 +22,7 @@
 import android.annotation.Size;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Canvas.VertexMode;
+import android.graphics.text.MeasuredText;
 import android.text.GraphicsOperations;
 import android.text.MeasuredParagraph;
 import android.text.PrecomputedText;
@@ -554,14 +555,12 @@
                     final int paraStart = pt.getParagraphStart(paraIndex);
                     final MeasuredParagraph mp = pt.getMeasuredParagraph(paraIndex);
                     // Only support the text in the same paragraph.
-                    nDrawTextRun(mNativeCanvasWrapper,
-                            mp.getChars(),
-                            start - paraStart,
-                            end - start,
-                            contextStart - paraStart,
-                            contextEnd - contextStart,
-                            x, y, isRtl, paint.getNativeInstance(),
-                            mp.getMeasuredText().getNativePtr());
+                    drawTextRun(mp.getMeasuredText(),
+                                start - paraStart,
+                                end - paraStart,
+                                contextStart - paraStart,
+                                contextEnd - paraStart,
+                                x, y, isRtl, paint);
                     return;
                 }
             }
@@ -576,6 +575,14 @@
         }
     }
 
+    public void drawTextRun(@NonNull MeasuredText measuredText, int start, int end,
+            int contextStart, int contextEnd, float x, float y, boolean isRtl,
+            @NonNull Paint paint) {
+        nDrawTextRun(mNativeCanvasWrapper, measuredText.getChars(), start, end - start,
+                contextStart, contextEnd - contextStart, x, y, isRtl, paint.getNativeInstance(),
+                measuredText.getNativePtr());
+    }
+
     public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts,
             int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors,
             int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount,
diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java
index 901c211..4f60935 100644
--- a/graphics/java/android/graphics/BaseRecordingCanvas.java
+++ b/graphics/java/android/graphics/BaseRecordingCanvas.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
+import android.graphics.text.MeasuredText;
 import android.text.GraphicsOperations;
 import android.text.MeasuredParagraph;
 import android.text.PrecomputedText;
@@ -522,14 +523,12 @@
                     final int paraStart = pt.getParagraphStart(paraIndex);
                     final MeasuredParagraph mp = pt.getMeasuredParagraph(paraIndex);
                     // Only support if the target is in the same paragraph.
-                    nDrawTextRun(mNativeCanvasWrapper,
-                            mp.getChars(),
+                    drawTextRun(mp.getMeasuredText(),
                             start - paraStart,
-                            end - start,
+                            end - paraStart,
                             contextStart - paraStart,
-                            contextEnd - contextStart,
-                            x, y, isRtl, paint.getNativeInstance(),
-                            mp.getMeasuredText().getNativePtr());
+                            contextEnd - paraStart,
+                            x, y, isRtl, paint);
                     return;
                 }
             }
@@ -545,6 +544,15 @@
     }
 
     @Override
+    public void drawTextRun(@NonNull MeasuredText measuredText, int start, int end,
+            int contextStart, int contextEnd, float x, float y, boolean isRtl,
+            @NonNull Paint paint) {
+        nDrawTextRun(mNativeCanvasWrapper, measuredText.getChars(), start, end - start,
+                contextStart, contextEnd - contextStart, x, y, isRtl, paint.getNativeInstance(),
+                measuredText.getNativePtr());
+    }
+
+    @Override
     public final void drawVertices(@NonNull VertexMode mode, int vertexCount,
             @NonNull float[] verts, int vertOffset, @Nullable float[] texs, int texOffset,
             @Nullable int[] colors, int colorOffset, @Nullable short[] indices, int indexOffset,
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 790b37e..bfbdbc5 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -18,9 +18,10 @@
 
 import android.annotation.CheckResult;
 import android.annotation.ColorInt;
+import android.annotation.ColorLong;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.Size;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.annotation.WorkerThread;
 import android.content.res.ResourcesImpl;
@@ -746,22 +747,10 @@
             throw new IllegalArgumentException("usage flags must contain USAGE_GPU_SAMPLED_IMAGE.");
         }
         int format = hardwareBuffer.getFormat();
-        ColorSpace.Rgb rgb = null;
-        if (colorSpace != null) {
-            if (!(colorSpace instanceof ColorSpace.Rgb)) {
-                throw new IllegalArgumentException("colorSpace must be an RGB color space");
-            }
-            rgb = (ColorSpace.Rgb) colorSpace;
-        } else {
-            rgb = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+        if (colorSpace == null) {
+            colorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
         }
-        ColorSpace.Rgb.TransferParameters parameters = rgb.getTransferParameters();
-        if (parameters == null) {
-            throw new IllegalArgumentException("colorSpace must use an ICC "
-                    + "parametric transfer function");
-        }
-        ColorSpace.Rgb d50 = (ColorSpace.Rgb) ColorSpace.adapt(rgb, ColorSpace.ILLUMINANT_D50);
-        return nativeWrapHardwareBufferBitmap(hardwareBuffer, d50.getTransform(), parameters);
+        return nativeWrapHardwareBufferBitmap(hardwareBuffer, colorSpace.getNativeInstance());
     }
 
     /**
@@ -1101,26 +1090,18 @@
             throw new IllegalArgumentException("can't create bitmap without a color space");
         }
 
-        Bitmap bm;
-        // nullptr color spaces have a particular meaning in native and are interpreted as sRGB
-        // (we also avoid the unnecessary extra work of the else branch)
-        if (config != Config.ARGB_8888 || colorSpace == ColorSpace.get(ColorSpace.Named.SRGB)) {
-            bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true, null, null);
-        } else {
-            if (!(colorSpace instanceof ColorSpace.Rgb)) {
-                throw new IllegalArgumentException("colorSpace must be an RGB color space");
+        if (config != Config.ARGB_8888) {
+            if (config == Config.RGBA_F16) {
+                // FIXME: This should be LINEAR_EXTENDED_SRGB, but that would fail a CTS test. See
+                // b/120960866. SRGB matches the old (incorrect) behavior.
+                //colorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
+                colorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
+            } else {
+                colorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
             }
-            ColorSpace.Rgb rgb = (ColorSpace.Rgb) colorSpace;
-            ColorSpace.Rgb.TransferParameters parameters = rgb.getTransferParameters();
-            if (parameters == null) {
-                throw new IllegalArgumentException("colorSpace must use an ICC "
-                        + "parametric transfer function");
-            }
-
-            ColorSpace.Rgb d50 = (ColorSpace.Rgb) ColorSpace.adapt(rgb, ColorSpace.ILLUMINANT_D50);
-            bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true,
-                    d50.getTransform(), parameters);
         }
+        Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true,
+                colorSpace.getNativeInstance());
 
         if (display != null) {
             bm.mDensity = display.densityDpi;
@@ -1198,8 +1179,9 @@
         if (width <= 0 || height <= 0) {
             throw new IllegalArgumentException("width and height must be > 0");
         }
+        ColorSpace sRGB = ColorSpace.get(ColorSpace.Named.SRGB);
         Bitmap bm = nativeCreate(colors, offset, stride, width, height,
-                            config.nativeInt, false, null, null);
+                            config.nativeInt, false, sRGB.getNativeInstance());
         if (display != null) {
             bm.mDensity = display.densityDpi;
         }
@@ -1780,6 +1762,26 @@
     }
 
     /**
+     * Fills the bitmap's pixels with the specified {@link Color}.
+     *
+     * @throws IllegalStateException if the bitmap is not mutable.
+     * @throws IllegalArgumentException if the color space encoded in the long
+     *                                  is invalid or unknown.
+     *
+     * @hide pending API approval
+     */
+    @TestApi
+    public void eraseColor(@ColorLong long c) {
+        checkRecycled("Can't erase a recycled bitmap");
+        if (!isMutable()) {
+            throw new IllegalStateException("cannot erase immutable bitmaps");
+        }
+
+        ColorSpace cs = Color.colorSpace(c);
+        nativeErase(mNativePtr, cs.getNativeInstance(), c);
+    }
+
+    /**
      * Returns the {@link Color} at the specified location. Throws an exception
      * if x or y are out of bounds (negative or >= to the width or height
      * respectively). The returned color is a non-premultiplied ARGB value in
@@ -2107,8 +2109,7 @@
     private static native Bitmap nativeCreate(int[] colors, int offset,
                                               int stride, int width, int height,
                                               int nativeConfig, boolean mutable,
-                                              @Nullable @Size(9) float[] xyzD50,
-                                              @Nullable ColorSpace.Rgb.TransferParameters p);
+                                              long nativeColorSpace);
     private static native Bitmap nativeCopy(long nativeSrcBitmap, int nativeConfig,
                                             boolean isMutable);
     private static native Bitmap nativeCopyAshmem(long nativeSrcBitmap);
@@ -2123,6 +2124,7 @@
                                             int quality, OutputStream stream,
                                             byte[] tempStorage);
     private static native void nativeErase(long nativeBitmap, int color);
+    private static native void nativeErase(long nativeBitmap, long colorSpacePtr, long color);
     private static native int nativeRowBytes(long nativeBitmap);
     private static native int nativeConfig(long nativeBitmap);
 
@@ -2166,8 +2168,7 @@
     private static native Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap);
     private static native Bitmap nativeCreateHardwareBitmap(GraphicBuffer buffer);
     private static native Bitmap nativeWrapHardwareBufferBitmap(HardwareBuffer buffer,
-                                                              @Size(9) float[] xyzD50,
-                                                              ColorSpace.Rgb.TransferParameters p);
+                                                                long nativeColorSpace);
     private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap);
     private static native boolean nativeGetColorSpace(long nativePtr, float[] xyz, float[] params);
     private static native boolean nativeIsSRGB(long nativePtr);
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index adab1a9c..7aff041 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -440,7 +440,8 @@
             if (opts == null) return;
 
             if (opts.inBitmap != null && opts.inBitmap.getConfig() == Bitmap.Config.HARDWARE) {
-                throw new IllegalArgumentException("Bitmaps with Config.HARWARE are always immutable");
+                throw new IllegalArgumentException(
+                        "Bitmaps with Config.HARDWARE are always immutable");
             }
 
             if (opts.inMutable && opts.inPreferredConfig == Bitmap.Config.HARDWARE) {
@@ -459,6 +460,21 @@
                 }
             }
         }
+
+        /**
+         *  Helper for passing SkColorSpace pointer to native.
+         *
+         *  @throws IllegalArgumentException if the ColorSpace is not Rgb or does
+         *          not have TransferParameters.
+         */
+        static long nativeColorSpace(Options opts) {
+            if (opts == null || opts.inPreferredColorSpace == null) {
+                return 0;
+            }
+
+            return opts.inPreferredColorSpace.getNativeInstance();
+        }
+
     }
 
     /**
@@ -632,7 +648,8 @@
 
         Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap");
         try {
-            bm = nativeDecodeByteArray(data, offset, length, opts);
+            bm = nativeDecodeByteArray(data, offset, length, opts,
+                    Options.nativeColorSpace(opts));
 
             if (bm == null && opts != null && opts.inBitmap != null) {
                 throw new IllegalArgumentException("Problem decoding into existing bitmap");
@@ -727,7 +744,7 @@
         try {
             if (is instanceof AssetManager.AssetInputStream) {
                 final long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
-                bm = nativeDecodeAsset(asset, outPadding, opts);
+                bm = nativeDecodeAsset(asset, outPadding, opts, Options.nativeColorSpace(opts));
             } else {
                 bm = decodeStreamInternal(is, outPadding, opts);
             }
@@ -754,7 +771,8 @@
         byte [] tempStorage = null;
         if (opts != null) tempStorage = opts.inTempStorage;
         if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
-        return nativeDecodeStream(is, tempStorage, outPadding, opts);
+        return nativeDecodeStream(is, tempStorage, outPadding, opts,
+                Options.nativeColorSpace(opts));
     }
 
     /**
@@ -797,7 +815,8 @@
         Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeFileDescriptor");
         try {
             if (nativeIsSeekable(fd)) {
-                bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
+                bm = nativeDecodeFileDescriptor(fd, outPadding, opts,
+                        Options.nativeColorSpace(opts));
             } else {
                 FileInputStream fis = new FileInputStream(fd);
                 try {
@@ -834,14 +853,15 @@
 
     @UnsupportedAppUsage
     private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
-            Rect padding, Options opts);
+            Rect padding, Options opts, long colorSpaceHandle);
     @UnsupportedAppUsage
     private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
-            Rect padding, Options opts);
+            Rect padding, Options opts, long colorSpaceHandle);
     @UnsupportedAppUsage
-    private static native Bitmap nativeDecodeAsset(long nativeAsset, Rect padding, Options opts);
+    private static native Bitmap nativeDecodeAsset(long nativeAsset, Rect padding, Options opts,
+            long colorSpaceHandle);
     @UnsupportedAppUsage
     private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
-            int length, Options opts);
+            int length, Options opts, long colorSpaceHandle);
     private static native boolean nativeIsSeekable(FileDescriptor fd);
 }
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
index 43282d3..1410423 100644
--- a/graphics/java/android/graphics/BitmapRegionDecoder.java
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -195,7 +195,8 @@
                     || rect.top >= getHeight())
                 throw new IllegalArgumentException("rectangle is outside the image");
             return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top,
-                    rect.right - rect.left, rect.bottom - rect.top, options);
+                    rect.right - rect.left, rect.bottom - rect.top, options,
+                    BitmapFactory.Options.nativeColorSpace(options));
         }
     }
 
@@ -265,7 +266,7 @@
 
     private static native Bitmap nativeDecodeRegion(long lbm,
             int start_x, int start_y, int width, int height,
-            BitmapFactory.Options options);
+            BitmapFactory.Options options, long colorSpaceHandle);
     private static native int nativeGetWidth(long lbm);
     private static native int nativeGetHeight(long lbm);
     private static native void nativeClean(long lbm);
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 63a806e..8c1bae2 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.Size;
 import android.annotation.UnsupportedAppUsage;
+import android.graphics.text.MeasuredText;
 import android.os.Build;
 
 import dalvik.annotation.optimization.CriticalNative;
@@ -2122,7 +2123,8 @@
      * the text next to it.
      * <p>
      * All text outside the range {@code contextStart..contextEnd} is ignored. The text between
-     * {@code start} and {@code end} will be laid out and drawn.
+     * {@code start} and {@code end} will be laid out and drawn. The context range is useful for
+     * contextual shaping, e.g. Kerning, Arabic contextural form.
      * <p>
      * The direction of the run is explicitly specified by {@code isRtl}. Thus, this method is
      * suitable only for runs of a single direction. Alignment of the text is as determined by the
@@ -2151,6 +2153,31 @@
     }
 
     /**
+     * Draw a run of text, all in a single direction, with optional context for complex text
+     * shaping.
+     * <p>
+     * See {@link #drawTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)} for
+     * more details. This method uses a {@link MeasuredText} rather than CharSequence to represent
+     * the string.
+     *
+     * @param text the text to render
+     * @param start the start of the text to render. Data before this position can be used for
+     *            shaping context.
+     * @param end the end of the text to render. Data at or after this position can be used for
+     *            shaping context.
+     * @param contextStart the index of the start of the shaping context
+     * @param contextEnd the index of the end of the shaping context
+     * @param x the x position at which to draw the text
+     * @param y the y position at which to draw the text
+     * @param isRtl whether the run is in RTL direction
+     * @param paint the paint
+     */
+    public void drawTextRun(@NonNull MeasuredText text, int start, int end, int contextStart,
+            int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) {
+        super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, isRtl, paint);
+    }
+
+    /**
      * Draw the array of vertices, interpreted as triangles (based on mode). The verts array is
      * required, and specifies the x,y pairs for each vertex. If texs is non-null, then it is used
      * to specify the coordinate in shader coordinates to use at each vertex (the paint must have a
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 2227cf5..4755d45 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -25,6 +25,8 @@
 import android.annotation.SuppressAutoDoc;
 import android.util.Pair;
 
+import libcore.util.NativeAllocationRegistry;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -199,6 +201,9 @@
     private static final float[] NTSC_1953_PRIMARIES = { 0.67f, 0.33f, 0.21f, 0.71f, 0.14f, 0.08f };
     private static final float[] ILLUMINANT_D50_XYZ = { 0.964212f, 1.0f, 0.825188f };
 
+    private static final Rgb.TransferParameters SRGB_TRANSFER_PARAMETERS =
+            new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4);
+
     // See static initialization block next to #get(Named)
     private static final ColorSpace[] sNamedColorSpaces = new ColorSpace[Named.values().length];
 
@@ -984,11 +989,12 @@
      *         {@link Named#SRGB sRGB} primaries.
      *     </li>
      *     <li>
-     *         Its white point is withing 1e-3 of the CIE standard
+     *         Its white point is within 1e-3 of the CIE standard
      *         illuminant {@link #ILLUMINANT_D65 D65}.
      *     </li>
      *     <li>Its opto-electronic transfer function is not linear.</li>
      *     <li>Its electro-optical transfer function is not linear.</li>
+     *     <li>Its transfer functions yield values within 1e-3 of {@link Named#SRGB}.</li>
      *     <li>Its range is \([0..1]\).</li>
      * </ul>
      * <p>This method always returns true for {@link Named#SRGB}.</p>
@@ -1340,6 +1346,26 @@
     }
 
     /**
+     * Helper method for creating native SkColorSpace.
+     *
+     * This essentially calls adapt on a ColorSpace that has not been fully
+     * created. It also does not fully create the adapted ColorSpace, but
+     * just returns the transform.
+     */
+    @NonNull @Size(9)
+    private static float[] adaptToIlluminantD50(
+            @NonNull @Size(2) float[] origWhitePoint,
+            @NonNull @Size(9) float[] origTransform) {
+        float[] desired = ILLUMINANT_D50;
+        if (compare(origWhitePoint, desired)) return origTransform;
+
+        float[] xyz = xyYToXyz(desired);
+        float[] adaptationTransform = chromaticAdaptation(Adaptation.BRADFORD.mTransform,
+                    xyYToXyz(origWhitePoint), xyz);
+        return mul3x3(adaptationTransform, origTransform);
+    }
+
+    /**
      * <p>Returns an instance of {@link ColorSpace} whose ID matches the
      * specified ID.</p>
      *
@@ -1354,9 +1380,9 @@
      */
     @NonNull
     static ColorSpace get(@IntRange(from = MIN_ID, to = MAX_ID) int index) {
-        if (index < 0 || index > Named.values().length) {
+        if (index < 0 || index >= Named.values().length) {
             throw new IllegalArgumentException("Invalid ID, must be in the range [0.." +
-                    Named.values().length + "]");
+                    Named.values().length + ")");
         }
         return sNamedColorSpaces[index];
     }
@@ -1430,7 +1456,7 @@
                 "sRGB IEC61966-2.1",
                 SRGB_PRIMARIES,
                 ILLUMINANT_D65,
-                new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4),
+                SRGB_TRANSFER_PARAMETERS,
                 Named.SRGB.ordinal()
         );
         sNamedColorSpaces[Named.LINEAR_SRGB.ordinal()] = new ColorSpace.Rgb(
@@ -1445,9 +1471,11 @@
                 "scRGB-nl IEC 61966-2-2:2003",
                 SRGB_PRIMARIES,
                 ILLUMINANT_D65,
+                null,
                 x -> absRcpResponse(x, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4),
                 x -> absResponse(x, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4),
                 -0.799f, 2.399f,
+                null, // FIXME: Use SRGB_TRANSFER_PARAMETERS
                 Named.EXTENDED_SRGB.ordinal()
         );
         sNamedColorSpaces[Named.LINEAR_EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb(
@@ -1484,7 +1512,7 @@
                 "Display P3",
                 new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
                 ILLUMINANT_D65,
-                new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4),
+                SRGB_TRANSFER_PARAMETERS,
                 Named.DISPLAY_P3.ordinal()
         );
         sNamedColorSpaces[Named.NTSC_1953.ordinal()] = new ColorSpace.Rgb(
@@ -1660,10 +1688,12 @@
      * @param rhs 3x3 matrix, as a non-null array of 9 floats
      * @return A new array of 9 floats containing the result of the multiplication
      *         of rhs by lhs
+     *
+     * @hide
      */
     @NonNull
     @Size(9)
-    private static float[] mul3x3(@NonNull @Size(9) float[] lhs, @NonNull @Size(9) float[] rhs) {
+    public static float[] mul3x3(@NonNull @Size(9) float[] lhs, @NonNull @Size(9) float[] rhs) {
         float[] r = new float[9];
         r[0] = lhs[0] * rhs[0] + lhs[3] * rhs[1] + lhs[6] * rhs[2];
         r[1] = lhs[1] * rhs[0] + lhs[4] * rhs[1] + lhs[7] * rhs[2];
@@ -1964,6 +1994,15 @@
     }
 
     /**
+     * Retrieve the native SkColorSpace object for passing to native.
+     *
+     * Only valid on ColorSpace.Rgb.
+     */
+    long getNativeInstance() {
+        throw new IllegalArgumentException("colorSpace must be an RGB color space");
+    }
+
+    /**
      * {@usesMathJax}
      *
      * <p>An RGB color space is an additive color space using the
@@ -2266,7 +2305,22 @@
         private final boolean mIsWideGamut;
         private final boolean mIsSrgb;
 
-        @Nullable private TransferParameters mTransferParameters;
+        @Nullable private final TransferParameters mTransferParameters;
+        private final long mNativePtr;
+
+        @Override
+        long getNativeInstance() {
+            if (mNativePtr == 0) {
+                // If this object has TransferParameters, it must have a native object.
+                throw new IllegalArgumentException("ColorSpace must use an ICC "
+                        + "parametric transfer function! used " + this);
+            }
+            return mNativePtr;
+        }
+
+        private static native long nativeGetNativeFinalizer();
+        private static native long nativeCreate(float a, float b, float c, float d,
+                float e, float f, float g, float[] xyz);
 
         /**
          * <p>Creates a new RGB color space using a 3x3 column-major transform matrix.
@@ -2295,8 +2349,8 @@
                 @NonNull @Size(9) float[] toXYZ,
                 @NonNull DoubleUnaryOperator oetf,
                 @NonNull DoubleUnaryOperator eotf) {
-            this(name, computePrimaries(toXYZ), computeWhitePoint(toXYZ),
-                    oetf, eotf, 0.0f, 1.0f, MIN_ID);
+            this(name, computePrimaries(toXYZ), computeWhitePoint(toXYZ), null,
+                    oetf, eotf, 0.0f, 1.0f, null, MIN_ID);
         }
 
         /**
@@ -2346,7 +2400,7 @@
                 @NonNull DoubleUnaryOperator eotf,
                 float min,
                 float max) {
-            this(name, primaries, whitePoint, oetf, eotf, min, max, MIN_ID);
+            this(name, primaries, whitePoint, null, oetf, eotf, min, max, null, MIN_ID);
         }
 
         /**
@@ -2456,7 +2510,7 @@
                 @NonNull @Size(min = 2, max = 3) float[] whitePoint,
                 @NonNull TransferParameters function,
                 @IntRange(from = MIN_ID, to = MAX_ID) int id) {
-            this(name, primaries, whitePoint,
+            this(name, primaries, whitePoint, null,
                     function.e == 0.0 && function.f == 0.0 ?
                             x -> rcpResponse(x, function.a, function.b,
                                     function.c, function.d, function.g) :
@@ -2467,8 +2521,7 @@
                                     function.c, function.d, function.g) :
                             x -> response(x, function.a, function.b, function.c,
                                     function.d, function.e, function.f, function.g),
-                    0.0f, 1.0f, id);
-            mTransferParameters = function;
+                    0.0f, 1.0f, function, id);
         }
 
         /**
@@ -2583,13 +2636,12 @@
                 float min,
                 float max,
                 @IntRange(from = MIN_ID, to = MAX_ID) int id) {
-            this(name, primaries, whitePoint,
+            this(name, primaries, whitePoint, null,
                     gamma == 1.0 ? DoubleUnaryOperator.identity() :
                             x -> Math.pow(x < 0.0 ? 0.0 : x, 1 / gamma),
                     gamma == 1.0 ? DoubleUnaryOperator.identity() :
                             x -> Math.pow(x < 0.0 ? 0.0 : x, gamma),
-                    min, max, id);
-            mTransferParameters = new TransferParameters(1.0, 0.0, 0.0, 0.0, gamma);
+                    min, max, new TransferParameters(1.0, 0.0, 0.0, 0.0, gamma), id);
         }
 
         /**
@@ -2612,10 +2664,13 @@
          * @param name Name of the color space, cannot be null, its length must be >= 1
          * @param primaries RGB primaries as an array of 6 (xy) or 9 (XYZ) floats
          * @param whitePoint Reference white as an array of 2 (xy) or 3 (XYZ) floats
+         * @param transform Computed transform matrix that converts from RGB to XYZ, or
+         *      {@code null} to compute it from {@code primaries} and {@code whitePoint}.
          * @param oetf Opto-electronic transfer function, cannot be null
          * @param eotf Electro-optical transfer function, cannot be null
          * @param min The minimum valid value in this color space's RGB range
          * @param max The maximum valid value in this color space's RGB range
+         * @param transferParameters Parameters for the transfer functions
          * @param id ID of this color space as an integer between {@link #MIN_ID} and {@link #MAX_ID}
          *
          * @throws IllegalArgumentException If any of the following conditions is met:
@@ -2634,10 +2689,12 @@
                 @NonNull @Size(min = 1) String name,
                 @NonNull @Size(min = 6, max = 9) float[] primaries,
                 @NonNull @Size(min = 2, max = 3) float[] whitePoint,
+                @Nullable @Size(9) float[] transform,
                 @NonNull DoubleUnaryOperator oetf,
                 @NonNull DoubleUnaryOperator eotf,
                 float min,
                 float max,
+                @Nullable TransferParameters transferParameters,
                 @IntRange(from = MIN_ID, to = MAX_ID) int id) {
 
             super(name, Model.RGB, id);
@@ -2665,7 +2722,15 @@
             mWhitePoint = xyWhitePoint(whitePoint);
             mPrimaries =  xyPrimaries(primaries);
 
-            mTransform = computeXYZMatrix(mPrimaries, mWhitePoint);
+            if (transform == null) {
+                mTransform = computeXYZMatrix(mPrimaries, mWhitePoint);
+            } else {
+                if (transform.length != 9) {
+                    throw new IllegalArgumentException("Transform must have 9 entries! Has "
+                            + transform.length);
+                }
+                mTransform = transform;
+            }
             mInverseTransform = inverse3x3(mTransform);
 
             mOetf = oetf;
@@ -2678,10 +2743,39 @@
             mClampedOetf = oetf.andThen(clamp);
             mClampedEotf = clamp.andThen(eotf);
 
+            mTransferParameters = transferParameters;
+
             // A color space is wide-gamut if its area is >90% of NTSC 1953 and
             // if it entirely contains the Color space definition in xyY
             mIsWideGamut = isWideGamut(mPrimaries, min, max);
             mIsSrgb = isSrgb(mPrimaries, mWhitePoint, oetf, eotf, min, max, id);
+
+            if (mTransferParameters != null) {
+                if (mWhitePoint == null || mTransform == null) {
+                    throw new IllegalStateException(
+                            "ColorSpace (" + this + ") cannot create native object! mWhitePoint: "
+                            + mWhitePoint + " mTransform: " + mTransform);
+                }
+
+                // This mimics the old code that was in native.
+                float[] nativeTransform = adaptToIlluminantD50(mWhitePoint, mTransform);
+                mNativePtr = nativeCreate((float) mTransferParameters.a,
+                                          (float) mTransferParameters.b,
+                                          (float) mTransferParameters.c,
+                                          (float) mTransferParameters.d,
+                                          (float) mTransferParameters.e,
+                                          (float) mTransferParameters.f,
+                                          (float) mTransferParameters.g,
+                                          nativeTransform);
+                NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePtr);
+            } else {
+                mNativePtr = 0;
+            }
+        }
+
+        private static class NoImagePreloadHolder {
+            public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+                ColorSpace.Rgb.class.getClassLoader(), nativeGetNativeFinalizer(), 0);
         }
 
         /**
@@ -2692,27 +2786,9 @@
         private Rgb(Rgb colorSpace,
                 @NonNull @Size(9) float[] transform,
                 @NonNull @Size(min = 2, max = 3) float[] whitePoint) {
-            super(colorSpace.getName(), Model.RGB, -1);
-
-            mWhitePoint = xyWhitePoint(whitePoint);
-            mPrimaries = colorSpace.mPrimaries;
-
-            mTransform = transform;
-            mInverseTransform = inverse3x3(transform);
-
-            mMin = colorSpace.mMin;
-            mMax = colorSpace.mMax;
-
-            mOetf = colorSpace.mOetf;
-            mEotf = colorSpace.mEotf;
-
-            mClampedOetf = colorSpace.mClampedOetf;
-            mClampedEotf = colorSpace.mClampedEotf;
-
-            mIsWideGamut = colorSpace.mIsWideGamut;
-            mIsSrgb = colorSpace.mIsSrgb;
-
-            mTransferParameters = colorSpace.mTransferParameters;
+            this(colorSpace.getName(), colorSpace.mPrimaries, whitePoint, transform,
+                    colorSpace.mOetf, colorSpace.mEotf, colorSpace.mMin, colorSpace.mMax,
+                    colorSpace.mTransferParameters, MIN_ID);
         }
 
         /**
@@ -3145,19 +3221,35 @@
                 float max,
                 @IntRange(from = MIN_ID, to = MAX_ID) int id) {
             if (id == 0) return true;
-            if (!compare(primaries, SRGB_PRIMARIES)) {
+            if (!ColorSpace.compare(primaries, SRGB_PRIMARIES)) {
                 return false;
             }
-            if (!compare(whitePoint, ILLUMINANT_D65)) {
+            if (!ColorSpace.compare(whitePoint, ILLUMINANT_D65)) {
                 return false;
             }
-            if (OETF.applyAsDouble(0.5) < 0.5001) return false;
-            if (EOTF.applyAsDouble(0.5) > 0.5001) return false;
+
             if (min != 0.0f) return false;
             if (max != 1.0f) return false;
+
+            // We would have already returned true if this was SRGB itself, so
+            // it is safe to reference it here.
+            ColorSpace.Rgb srgb = (ColorSpace.Rgb) get(Named.SRGB);
+
+            for (double x = 0.0; x <= 1.0; x += 1 / 255.0) {
+                if (!compare(x, OETF, srgb.mOetf)) return false;
+                if (!compare(x, EOTF, srgb.mEotf)) return false;
+            }
+
             return true;
         }
 
+        private static boolean compare(double point, @NonNull DoubleUnaryOperator a,
+                @NonNull DoubleUnaryOperator b) {
+            double rA = a.applyAsDouble(point);
+            double rB = b.applyAsDouble(point);
+            return Math.abs(rA - rB) <= 1e-3;
+        }
+
         /**
          * Computes whether the specified CIE xyY or XYZ primaries (with Y set to 1) form
          * a wide color gamut. A color gamut is considered wide if its area is &gt; 90%
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index e402055..c4ddd50 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -20,6 +20,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.os.IBinder;
@@ -667,6 +668,17 @@
         nSetContentDrawBounds(mNativeProxy, left, top, right, bottom);
     }
 
+    /** @hide */
+    public void setPictureCaptureCallback(@Nullable PictureCapturedCallback callback) {
+        nSetPictureCaptureCallback(mNativeProxy, callback);
+    }
+
+    /** called by native */
+    static void invokePictureCapturedCallback(long picturePtr, PictureCapturedCallback callback) {
+        Picture picture = new Picture(picturePtr);
+        callback.onPictureCaptured(picture);
+    }
+
     /**
      * Interface used to receive callbacks when a frame is being drawn.
      *
@@ -695,6 +707,17 @@
         void onFrameComplete(long frameNr);
     }
 
+    /**
+     * Interface for listening to picture captures
+     * @hide
+     */
+    @TestApi
+    public interface PictureCapturedCallback {
+        /** @hide */
+        @TestApi
+        void onPictureCaptured(Picture picture);
+    }
+
     private static void validateAlpha(float alpha, String argumentName) {
         if (!(alpha >= 0.0f && alpha <= 1.0f)) {
             throw new IllegalArgumentException(argumentName + " must be a valid alpha, "
@@ -998,6 +1021,9 @@
     private static native void nSetContentDrawBounds(long nativeProxy, int left,
             int top, int right, int bottom);
 
+    private static native void nSetPictureCaptureCallback(long nativeProxy,
+            PictureCapturedCallback callback);
+
     private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback);
 
     private static native void nSetFrameCompleteCallback(long nativeProxy,
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index e3b165c..466a5fc 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -1628,17 +1628,6 @@
         if (mPostProcessor != null && mUnpremultipliedRequired) {
             throw new IllegalStateException("Cannot draw to unpremultiplied pixels!");
         }
-
-        if (mDesiredColorSpace != null) {
-            if (!(mDesiredColorSpace instanceof ColorSpace.Rgb)) {
-                throw new IllegalArgumentException("The target color space must use the "
-                            + "RGB color model - provided: " + mDesiredColorSpace);
-            }
-            if (((ColorSpace.Rgb) mDesiredColorSpace).getTransferParameters() == null) {
-                throw new IllegalArgumentException("The target color space must use an "
-                            + "ICC parametric transfer function - provided: " + mDesiredColorSpace);
-            }
-        }
     }
 
     private static void checkSubset(int width, int height, Rect r) {
@@ -1655,10 +1644,12 @@
     @NonNull
     private Bitmap decodeBitmapInternal() throws IOException {
         checkState();
+        long colorSpacePtr = mDesiredColorSpace == null ? 0 :
+                mDesiredColorSpace.getNativeInstance();
         return nDecodeBitmap(mNativePtr, this, mPostProcessor != null,
                 mDesiredWidth, mDesiredHeight, mCropRect,
                 mMutable, mAllocator, mUnpremultipliedRequired,
-                mConserveMemory, mDecodeAsAlphaMask, mDesiredColorSpace);
+                mConserveMemory, mDecodeAsAlphaMask, colorSpacePtr);
     }
 
     private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
@@ -1946,7 +1937,7 @@
             @Nullable Rect cropRect, boolean mutable,
             int allocator, boolean unpremulRequired,
             boolean conserveMemory, boolean decodeAsAlphaMask,
-            @Nullable ColorSpace desiredColorSpace)
+            long desiredColorSpace)
         throws IOException;
     private static native Size nGetSampledSize(long nativePtr,
                                                int sampleSize);
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 3342fd2..7eee6f4 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -17,12 +17,14 @@
 package android.graphics;
 
 import android.annotation.ColorInt;
+import android.annotation.ColorLong;
 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.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.fonts.FontVariationAxis;
 import android.os.Build;
@@ -66,26 +68,27 @@
                 Paint.class.getClassLoader(), nGetNativeFinalizer(), NATIVE_PAINT_SIZE);
     }
 
-    private ColorFilter mColorFilter;
-    private MaskFilter  mMaskFilter;
-    private PathEffect  mPathEffect;
-    private Shader      mShader;
+    @ColorLong private long mColor;
+    private ColorFilter     mColorFilter;
+    private MaskFilter      mMaskFilter;
+    private PathEffect      mPathEffect;
+    private Shader          mShader;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    private Typeface    mTypeface;
-    private Xfermode    mXfermode;
+    private Typeface        mTypeface;
+    private Xfermode        mXfermode;
 
-    private boolean     mHasCompatScaling;
-    private float       mCompatScaling;
-    private float       mInvCompatScaling;
+    private boolean         mHasCompatScaling;
+    private float           mCompatScaling;
+    private float           mInvCompatScaling;
 
-    private LocaleList  mLocales;
-    private String      mFontFeatureSettings;
-    private String      mFontVariationSettings;
+    private LocaleList      mLocales;
+    private String          mFontFeatureSettings;
+    private String          mFontVariationSettings;
 
-    private float mShadowLayerRadius;
-    private float mShadowLayerDx;
-    private float mShadowLayerDy;
-    private int mShadowLayerColor;
+    private float           mShadowLayerRadius;
+    private float           mShadowLayerDx;
+    private float           mShadowLayerDy;
+    @ColorLong private long mShadowLayerColor;
 
     private static final Object sCacheLock = new Object();
 
@@ -503,6 +506,7 @@
         //        ? HINTING_OFF : HINTING_ON);
         mCompatScaling = mInvCompatScaling = 1;
         setTextLocales(LocaleList.getAdjustedDefault());
+        mColor = Color.pack(Color.BLACK);
     }
 
     /**
@@ -528,6 +532,7 @@
         // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
         //        ? HINTING_OFF : HINTING_ON);
 
+        mColor = Color.pack(Color.BLACK);
         mColorFilter = null;
         mMaskFilter = null;
         mPathEffect = null;
@@ -549,7 +554,7 @@
         mShadowLayerRadius = 0.0f;
         mShadowLayerDx = 0.0f;
         mShadowLayerDy = 0.0f;
-        mShadowLayerColor = 0;
+        mShadowLayerColor = Color.pack(0);
     }
 
     /**
@@ -570,6 +575,7 @@
      * {@link Paint}.
      */
     private void setClassVariablesFrom(Paint paint) {
+        mColor = paint.mColor;
         mColorFilter = paint.mColorFilter;
         mMaskFilter = paint.mMaskFilter;
         mPathEffect = paint.mPathEffect;
@@ -947,7 +953,7 @@
     }
 
     /**
-     * Return the paint's color. Note that the color is a 32bit value
+     * Return the paint's color in sRGB. Note that the color is a 32bit value
      * containing alpha as well as r,g,b. This 32bit value is not premultiplied,
      * meaning that its alpha can be any value, regardless of the values of
      * r,g,b. See the Color class for more details.
@@ -956,7 +962,25 @@
      */
     @ColorInt
     public int getColor() {
-        return nGetColor(mNativePaint);
+        return Color.toArgb(mColor);
+    }
+
+    /**
+     * Return the paint's color. Note that the color is a long with an encoded
+     * {@link ColorSpace} as well as alpha and r,g,b. These values are not
+     * premultiplied, meaning that alpha can be any value, regardless of the
+     * values of r,g,b. See the {@link Color} class for more details.
+     *
+     * @see Color for APIs that help manipulate a color long.
+     *
+     * @return the paint's color (and alpha).
+     *
+     * @hide pending API approval
+     */
+    @TestApi
+    @ColorLong
+    public long getColorLong() {
+        return mColor;
     }
 
     /**
@@ -968,7 +992,33 @@
      * @param color The new color (including alpha) to set in the paint.
      */
     public void setColor(@ColorInt int color) {
-        nSetColor(mNativePaint, color);
+        setColor(Color.pack(color));
+    }
+
+    /**
+     * Set the paint's color with a {@link ColorLong}. Note that the color is
+     * a long with an encoded {@link ColorSpace} as well as alpha and r,g,b.
+     * These values are not premultiplied, meaning that alpha can be any value,
+     * regardless of the values of r,g,b. See the {@link Color} class for more
+     * details.
+     *
+     * @param color The new color (including alpha and {@link ColorSpace})
+     *      to set in the paint.
+     * @throws IllegalArgumentException if the color space encoded in the long
+     *      is invalid or unknown.
+     *
+     * @hide pending API approval
+     */
+    @TestApi
+    public void setColor(@ColorLong long color) {
+        ColorSpace cs = Color.colorSpace(color);
+        float r = Color.red(color);
+        float g = Color.green(color);
+        float b = Color.blue(color);
+        float a = Color.alpha(color);
+
+        nSetColor(mNativePaint, cs.getNativeInstance(), r, g, b, a);
+        mColor = color;
     }
 
     /**
@@ -979,7 +1029,7 @@
      * @return the alpha component of the paint's color.
      */
     public int getAlpha() {
-        return nGetAlpha(mNativePaint);
+        return Math.round(Color.alpha(mColor) * 255.0f);
     }
 
     /**
@@ -990,6 +1040,13 @@
      * @param a set the alpha component [0..255] of the paint's color.
      */
     public void setAlpha(int a) {
+        // FIXME: No need to unpack this. Instead, just update the alpha bits.
+        // b/122959599
+        ColorSpace cs = Color.colorSpace(mColor);
+        float r = Color.red(mColor);
+        float g = Color.green(mColor);
+        float b = Color.blue(mColor);
+        mColor = Color.pack(r, g, b, a * (1.0f / 255), cs);
         nSetAlpha(mNativePaint, a);
     }
 
@@ -1370,12 +1427,40 @@
      * The alpha of the shadow will be the paint's alpha if the shadow color is
      * opaque, or the alpha from the shadow color if not.
      */
-    public void setShadowLayer(float radius, float dx, float dy, int shadowColor) {
-      mShadowLayerRadius = radius;
-      mShadowLayerDx = dx;
-      mShadowLayerDy = dy;
-      mShadowLayerColor = shadowColor;
-      nSetShadowLayer(mNativePaint, radius, dx, dy, shadowColor);
+    public void setShadowLayer(float radius, float dx, float dy, @ColorInt int shadowColor) {
+        setShadowLayer(radius, dx, dy, Color.pack(shadowColor));
+    }
+
+    /**
+     * This draws a shadow layer below the main layer, with the specified
+     * offset and color, and blur radius. If radius is 0, then the shadow
+     * layer is removed.
+     * <p>
+     * Can be used to create a blurred shadow underneath text. Support for use
+     * with other drawing operations is constrained to the software rendering
+     * pipeline.
+     * <p>
+     * The alpha of the shadow will be the paint's alpha if the shadow color is
+     * opaque, or the alpha from the shadow color if not.
+     *
+     * @throws IllegalArgumentException if the color space encoded in the long
+     *      is invalid or unknown.
+     *
+     * @hide pending API approval
+     */
+    @TestApi
+    public void setShadowLayer(float radius, float dx, float dy, @ColorLong long shadowColor) {
+        ColorSpace cs = Color.colorSpace(shadowColor);
+        float r = Color.red(shadowColor);
+        float g = Color.green(shadowColor);
+        float b = Color.blue(shadowColor);
+        float a = Color.alpha(shadowColor);
+        nSetShadowLayer(mNativePaint, radius, dx, dy, cs.getNativeInstance(), r, g, b, a);
+
+        mShadowLayerRadius = radius;
+        mShadowLayerDx = dx;
+        mShadowLayerDy = dy;
+        mShadowLayerColor = shadowColor;
     }
 
     /**
@@ -1422,8 +1507,20 @@
     /**
      * Returns the color of the shadow layer.
      * @see #setShadowLayer(float,float,float,int)
+     * @see #setShadowLayer(float,float,float,long)
      */
     public @ColorInt int getShadowLayerColor() {
+        return Color.toArgb(mShadowLayerColor);
+    }
+
+    /**
+     * Returns the color of the shadow layer.
+     * @see #setShadowLayer(float,float,float,int)
+     * @see #setShadowLayer(float,float,float,long)
+     * @hide pending API approval
+     */
+    @TestApi
+    public @ColorLong long getShadowLayerColorLong() {
         return mShadowLayerColor;
     }
 
@@ -2961,7 +3058,8 @@
             int mMinikinLocaleListId);
     @CriticalNative
     private static native void nSetShadowLayer(long paintPtr,
-            float radius, float dx, float dy, int color);
+            float radius, float dx, float dy, long colorSpaceHandle,
+            float r, float g, float b, float a);
     @CriticalNative
     private static native boolean nHasShadowLayer(long paintPtr);
     @CriticalNative
@@ -3009,11 +3107,8 @@
     @CriticalNative
     private static native void nSetFilterBitmap(long paintPtr, boolean filter);
     @CriticalNative
-    private static native int nGetColor(long paintPtr);
-    @CriticalNative
-    private static native void nSetColor(long paintPtr, @ColorInt int color);
-    @CriticalNative
-    private static native int nGetAlpha(long paintPtr);
+    private static native void nSetColor(long paintPtr, long colorSpaceHandle,
+            float r, float g, float b, float a);
     @CriticalNative
     private static native void nSetStrikeThruText(long paintPtr, boolean strikeThruText);
     @CriticalNative
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index f6d801b..8d12cbf 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 
 import java.io.InputStream;
@@ -34,7 +35,8 @@
  */
 public class Picture {
     private PictureCanvas mRecordingCanvas;
-    @UnsupportedAppUsage
+    // TODO: Figure out if this was a false-positive
+    @UnsupportedAppUsage(maxTargetSdk = 28)
     private long mNativePicture;
     private boolean mRequiresHwAcceleration;
 
@@ -56,23 +58,43 @@
         this(nativeConstructor(src != null ? src.mNativePicture : 0));
     }
 
-    private Picture(long nativePicture) {
+    /** @hide */
+    public Picture(long nativePicture) {
         if (nativePicture == 0) {
-            throw new RuntimeException();
+            throw new IllegalArgumentException();
         }
         mNativePicture = nativePicture;
     }
 
+    /**
+     * Immediately releases the backing data of the Picture. This object will no longer
+     * be usable after calling this, and any further calls on the Picture will throw an
+     * IllegalStateException.
+     * // TODO: Support?
+     * @hide
+     */
+    public void close() {
+        if (mNativePicture != 0) {
+            nativeDestructor(mNativePicture);
+            mNativePicture = 0;
+        }
+    }
+
     @Override
     protected void finalize() throws Throwable {
         try {
-            nativeDestructor(mNativePicture);
-            mNativePicture = 0;
+            close();
         } finally {
             super.finalize();
         }
     }
 
+    private void verifyValid() {
+        if (mNativePicture == 0) {
+            throw new IllegalStateException("Picture is destroyed");
+        }
+    }
+
     /**
      * To record a picture, call beginRecording() and then draw into the Canvas
      * that is returned. Nothing we appear on screen, but all of the draw
@@ -81,7 +103,9 @@
      * that was returned must no longer be used, and nothing should be drawn
      * into it.
      */
+    @NonNull
     public Canvas beginRecording(int width, int height) {
+        verifyValid();
         if (mRecordingCanvas != null) {
             throw new IllegalStateException("Picture already recording, must call #endRecording()");
         }
@@ -98,6 +122,7 @@
      * or {@link Canvas#drawPicture(Picture)} is called.
      */
     public void endRecording() {
+        verifyValid();
         if (mRecordingCanvas != null) {
             mRequiresHwAcceleration = mRecordingCanvas.mHoldsHwBitmap;
             mRecordingCanvas = null;
@@ -110,7 +135,8 @@
      * does not reflect (per se) the content of the picture.
      */
     public int getWidth() {
-      return nativeGetWidth(mNativePicture);
+        verifyValid();
+        return nativeGetWidth(mNativePicture);
     }
 
     /**
@@ -118,7 +144,8 @@
      * does not reflect (per se) the content of the picture.
      */
     public int getHeight() {
-      return nativeGetHeight(mNativePicture);
+        verifyValid();
+        return nativeGetHeight(mNativePicture);
     }
 
     /**
@@ -133,6 +160,7 @@
      *         false otherwise.
      */
     public boolean requiresHardwareAcceleration() {
+        verifyValid();
         return mRequiresHwAcceleration;
     }
 
@@ -149,7 +177,8 @@
      *
      * @param canvas  The picture is drawn to this canvas
      */
-    public void draw(Canvas canvas) {
+    public void draw(@NonNull Canvas canvas) {
+        verifyValid();
         if (mRecordingCanvas != null) {
             endRecording();
         }
@@ -172,7 +201,7 @@
      * raw or compressed pixels.
      */
     @Deprecated
-    public static Picture createFromStream(InputStream stream) {
+    public static Picture createFromStream(@NonNull InputStream stream) {
         return new Picture(nativeCreateFromStream(stream, new byte[WORKING_STREAM_STORAGE]));
     }
 
@@ -188,10 +217,11 @@
      * Bitmap from which you can persist it as raw or compressed pixels.
      */
     @Deprecated
-    public void writeToStream(OutputStream stream) {
+    public void writeToStream(@NonNull OutputStream stream) {
+        verifyValid();
         // do explicit check before calling the native method
         if (stream == null) {
-            throw new NullPointerException();
+            throw new IllegalArgumentException("stream cannot be null");
         }
         if (!nativeWriteToStream(mNativePicture, stream, new byte[WORKING_STREAM_STORAGE])) {
             throw new RuntimeException();
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 3b1d44b..09b18b7 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -184,7 +184,7 @@
      *
      * @param name The name of the RenderNode, used for debugging purpose. May be null.
      */
-    public RenderNode(String name) {
+    public RenderNode(@Nullable String name) {
         this(name, null);
     }
 
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 9b86b77..25f6775 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -1075,6 +1075,11 @@
                 continue; // If alias and named family are conflict, use named family.
             }
             final Typeface base = systemFontMap.get(alias.getToName());
+            if (base == null) {
+                // The missing target is a valid thing, some configuration don't have font files,
+                // e.g. wear devices. Just skip this alias.
+                continue;
+            }
             final int weight = alias.getWeight();
             final Typeface newFace = weight == 400 ? base :
                     new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
diff --git a/graphics/proto/Android.bp b/graphics/proto/Android.bp
new file mode 100644
index 0000000..1d06348
--- /dev/null
+++ b/graphics/proto/Android.bp
@@ -0,0 +1,11 @@
+java_library_static {
+    name: "game-driver-protos",
+    host_supported: true,
+    proto: {
+        type: "lite",
+    },
+    srcs: ["game_driver.proto"],
+    no_framework_libs: true,
+    jarjar_rules: "jarjar-rules.txt",
+    sdk_version: "28",
+}
diff --git a/graphics/proto/game_driver.proto b/graphics/proto/game_driver.proto
new file mode 100644
index 0000000..fd7ffcc
--- /dev/null
+++ b/graphics/proto/game_driver.proto
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.gamedriver;
+
+option java_package = "android.gamedriver";
+option java_outer_classname = "GameDriverProto";
+
+message Blacklist {
+    optional int64 version_code = 1;
+    repeated string package_names = 2;
+}
+
+message Blacklists {
+    repeated Blacklist blacklists = 1;
+}
diff --git a/graphics/proto/jarjar-rules.txt b/graphics/proto/jarjar-rules.txt
new file mode 100644
index 0000000..4e40637
--- /dev/null
+++ b/graphics/proto/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.google.protobuf.** com.android.framework.protobuf.@1
diff --git a/jarjar_rules_hidl.txt b/jarjar_rules_hidl.txt
new file mode 100644
index 0000000..4b2331d
--- /dev/null
+++ b/jarjar_rules_hidl.txt
@@ -0,0 +1 @@
+rule android.hidl.** android.internal.hidl.@1
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index ad9ec02..3c35d9b 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -20,8 +20,9 @@
 
 #include <algorithm>
 #include <iterator>
-#include <set>
 #include <map>
+#include <set>
+#include <sstream>
 
 #include "android-base/logging.h"
 #include "android-base/stringprintf.h"
@@ -372,6 +373,9 @@
   uint32_t best_offset = 0u;
   uint32_t type_flags = 0u;
 
+  Resolution::Step::Type resolution_type;
+  std::vector<Resolution::Step> resolution_steps;
+
   // If desired_config is the same as the set configuration, then we can use our filtered list
   // and we don't need to match the configurations, since they already matched.
   const bool use_fast_path = desired_config == &configuration_;
@@ -403,8 +407,8 @@
     // If the package is an overlay, then even configurations that are the same MUST be chosen.
     const bool package_is_overlay = loaded_package->IsOverlay();
 
-    const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
     if (use_fast_path) {
+      const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
       const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations;
       const size_t type_count = candidate_configs.size();
       for (uint32_t i = 0; i < type_count; i++) {
@@ -412,21 +416,34 @@
 
         // We can skip calling ResTable_config::match() because we know that all candidate
         // configurations that do NOT match have been filtered-out.
-        if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
-            (package_is_overlay && this_config.compare(*best_config) == 0)) {
-          // The configuration matches and is better than the previous selection.
-          // Find the entry value if it exists for this configuration.
-          const ResTable_type* type_chunk = filtered_group.types[i];
-          const uint32_t offset = LoadedPackage::GetEntryOffset(type_chunk, local_entry_idx);
-          if (offset == ResTable_type::NO_ENTRY) {
-            continue;
-          }
+        if (best_config == nullptr) {
+          resolution_type = Resolution::Step::Type::INITIAL;
+        } else if (this_config.isBetterThan(*best_config, desired_config)) {
+          resolution_type = Resolution::Step::Type::BETTER_MATCH;
+        } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
+          resolution_type = Resolution::Step::Type::OVERLAID;
+        } else {
+          continue;
+        }
 
-          best_cookie = cookie;
-          best_package = loaded_package;
-          best_type = type_chunk;
-          best_config = &this_config;
-          best_offset = offset;
+        // The configuration matches and is better than the previous selection.
+        // Find the entry value if it exists for this configuration.
+        const ResTable_type* type = filtered_group.types[i];
+        const uint32_t offset = LoadedPackage::GetEntryOffset(type, local_entry_idx);
+        if (offset == ResTable_type::NO_ENTRY) {
+          continue;
+        }
+
+        best_cookie = cookie;
+        best_package = loaded_package;
+        best_type = type;
+        best_config = &this_config;
+        best_offset = offset;
+
+        if (resource_resolution_logging_enabled_) {
+          resolution_steps.push_back(Resolution::Step{resolution_type,
+                                                      this_config.toString(),
+                                                      &loaded_package->GetPackageName()});
         }
       }
     } else {
@@ -440,23 +457,38 @@
         ResTable_config this_config;
         this_config.copyFromDtoH((*iter)->config);
 
-        if (this_config.match(*desired_config)) {
-          if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
-              (package_is_overlay && this_config.compare(*best_config) == 0)) {
-            // The configuration matches and is better than the previous selection.
-            // Find the entry value if it exists for this configuration.
-            const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx);
-            if (offset == ResTable_type::NO_ENTRY) {
-              continue;
-            }
+        if (!this_config.match(*desired_config)) {
+          continue;
+        }
 
-            best_cookie = cookie;
-            best_package = loaded_package;
-            best_type = *iter;
-            best_config_copy = this_config;
-            best_config = &best_config_copy;
-            best_offset = offset;
-          }
+        if (best_config == nullptr) {
+          resolution_type = Resolution::Step::Type::INITIAL;
+        } else if (this_config.isBetterThan(*best_config, desired_config)) {
+          resolution_type = Resolution::Step::Type::BETTER_MATCH;
+        } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
+          resolution_type = Resolution::Step::Type::OVERLAID;
+        } else {
+          continue;
+        }
+
+        // The configuration matches and is better than the previous selection.
+        // Find the entry value if it exists for this configuration.
+        const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx);
+        if (offset == ResTable_type::NO_ENTRY) {
+          continue;
+        }
+
+        best_cookie = cookie;
+        best_package = loaded_package;
+        best_type = *iter;
+        best_config_copy = this_config;
+        best_config = &best_config_copy;
+        best_offset = offset;
+
+        if (resource_resolution_logging_enabled_) {
+          resolution_steps.push_back(Resolution::Step{resolution_type,
+                                                      this_config.toString(),
+                                                      &loaded_package->GetPackageName()});
         }
       }
     }
@@ -478,9 +510,95 @@
   out_entry->entry_string_ref =
       StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
   out_entry->dynamic_ref_table = &package_group.dynamic_ref_table;
+
+  if (resource_resolution_logging_enabled_) {
+    last_resolution.resid = resid;
+    last_resolution.cookie = best_cookie;
+    last_resolution.steps = resolution_steps;
+
+    // Cache only the type/entry refs since that's all that's needed to build name
+    last_resolution.type_string_ref =
+        StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1);
+    last_resolution.entry_string_ref =
+        StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
+  }
+
   return best_cookie;
 }
 
+void AssetManager2::SetResourceResolutionLoggingEnabled(bool enabled) {
+  resource_resolution_logging_enabled_ = enabled;
+
+  if (!enabled) {
+    last_resolution.cookie = kInvalidCookie;
+    last_resolution.resid = 0;
+    last_resolution.steps.clear();
+    last_resolution.type_string_ref = StringPoolRef();
+    last_resolution.entry_string_ref = StringPoolRef();
+  }
+}
+
+std::string AssetManager2::GetLastResourceResolution() const {
+  if (!resource_resolution_logging_enabled_) {
+    LOG(ERROR) << "Must enable resource resolution logging before getting path.";
+    return std::string();
+  }
+
+  auto cookie = last_resolution.cookie;
+  if (cookie == kInvalidCookie) {
+    LOG(ERROR) << "AssetManager hasn't resolved a resource to read resolution path.";
+    return std::string();
+  }
+
+  uint32_t resid = last_resolution.resid;
+  std::vector<Resolution::Step>& steps = last_resolution.steps;
+
+  ResourceName resource_name;
+  std::string resource_name_string;
+
+  const LoadedPackage* package =
+      apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
+
+  if (package != nullptr) {
+    ToResourceName(last_resolution.type_string_ref,
+                   last_resolution.entry_string_ref,
+                   package,
+                   &resource_name);
+    resource_name_string = ToFormattedResourceString(&resource_name);
+  }
+
+  std::stringstream log_stream;
+  log_stream << base::StringPrintf("Resolution for 0x%08x ", resid)
+            << resource_name_string
+            << "\n\tFor config -"
+            << configuration_.toString();
+
+  std::string prefix;
+  for (Resolution::Step step : steps) {
+    switch (step.type) {
+      case Resolution::Step::Type::INITIAL:
+        prefix = "Found initial";
+        break;
+      case Resolution::Step::Type::BETTER_MATCH:
+        prefix = "Found better";
+        break;
+      case Resolution::Step::Type::OVERLAID:
+        prefix = "Overlaid";
+        break;
+    }
+
+    if (!prefix.empty()) {
+      log_stream << "\n\t" << prefix << ": " << *step.package_name;
+
+      if (!step.config_name.isEmpty()) {
+        log_stream << " -" << step.config_name;
+      }
+    }
+  }
+
+  return log_stream.str();
+}
+
 bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const {
   FindEntryResult entry;
   ApkAssetsCookie cookie =
@@ -495,27 +613,10 @@
     return false;
   }
 
-  out_name->package = package->GetPackageName().data();
-  out_name->package_len = package->GetPackageName().size();
-
-  out_name->type = entry.type_string_ref.string8(&out_name->type_len);
-  out_name->type16 = nullptr;
-  if (out_name->type == nullptr) {
-    out_name->type16 = entry.type_string_ref.string16(&out_name->type_len);
-    if (out_name->type16 == nullptr) {
-      return false;
-    }
-  }
-
-  out_name->entry = entry.entry_string_ref.string8(&out_name->entry_len);
-  out_name->entry16 = nullptr;
-  if (out_name->entry == nullptr) {
-    out_name->entry16 = entry.entry_string_ref.string16(&out_name->entry_len);
-    if (out_name->entry16 == nullptr) {
-      return false;
-    }
-  }
-  return true;
+  return ToResourceName(entry.type_string_ref,
+                        entry.entry_string_ref,
+                        package,
+                        out_name);
 }
 
 bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const {
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index 57e3491..18d74ef 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -51,7 +51,7 @@
 class BagAttributeFinder
     : public BackTrackingAttributeFinder<BagAttributeFinder, const ResolvedBag::Entry*> {
  public:
-  BagAttributeFinder(const ResolvedBag* bag)
+  explicit BagAttributeFinder(const ResolvedBag* bag)
       : BackTrackingAttributeFinder(bag != nullptr ? bag->entries : nullptr,
                                     bag != nullptr ? bag->entries + bag->entry_count : nullptr) {
   }
@@ -286,6 +286,7 @@
     value.dataType = Res_value::TYPE_NULL;
     value.data = Res_value::DATA_NULL_UNDEFINED;
     config.density = 0;
+    uint32_t source_style_resid = 0;
 
     // Try to find a value for this attribute...  we prioritize values
     // coming from, first XML attributes, then XML style, then default
@@ -309,6 +310,7 @@
         cookie = entry->cookie;
         type_set_flags = style_flags;
         value = entry->value;
+        source_style_resid = entry->style;
         if (kDebugStyles) {
           ALOGI("-> From style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
               entry->style);
@@ -325,8 +327,10 @@
         type_set_flags = def_style_flags;
         value = entry->value;
         if (kDebugStyles) {
-          ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
+          ALOGI("-> From def style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
+              entry->style);
         }
+        source_style_resid = entry->style;
       }
     }
 
@@ -382,6 +386,7 @@
     out_values[STYLE_RESOURCE_ID] = resid;
     out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
     out_values[STYLE_DENSITY] = config.density;
+    out_values[SYTLE_SOURCE_STYLE] = source_style_resid;
 
     if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
       indices_idx++;
diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp
index 5694115..a99e77f 100644
--- a/libs/androidfw/CursorWindow.cpp
+++ b/libs/androidfw/CursorWindow.cpp
@@ -94,7 +94,7 @@
         if (size < 0) {
             result = UNKNOWN_ERROR;
         } else {
-            int dupAshmemFd = ::dup(ashmemFd);
+            int dupAshmemFd = ::fcntl(ashmemFd, F_DUPFD_CLOEXEC, 0);
             if (dupAshmemFd < 0) {
                 result = -errno;
             } else {
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 5a26780..70ce9bc 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -593,7 +593,12 @@
           return {};
         }
 
-        // Iterate over the overlayable policy chunks
+        std::string name;
+        util::ReadUtf16StringFromDevice(header->name, arraysize(header->name), &name);
+        std::string actor;
+        util::ReadUtf16StringFromDevice(header->actor, arraysize(header->actor), &actor);
+
+        // Iterate over the overlayable policy chunks contained within the overlayable chunk data
         ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
         while (overlayable_iter.HasNext()) {
           const Chunk overlayable_child_chunk = overlayable_iter.Next();
@@ -613,7 +618,7 @@
                 return {};
               }
 
-              // Retrieve all the ids belonging to this policy
+              // Retrieve all the resource ids belonging to this policy chunk
               std::unordered_set<uint32_t> ids;
               const auto ids_begin =
                   reinterpret_cast<const ResTable_ref*>(overlayable_child_chunk.data_ptr());
@@ -622,8 +627,10 @@
                 ids.insert(dtohl(id_iter->ident));
               }
 
-              // Add the pairing of overlayable properties to resource ids to the package
+              // Add the pairing of overlayable properties and resource ids to the package
               OverlayableInfo overlayable_info{};
+              overlayable_info.name = name;
+              overlayable_info.actor = actor;
               overlayable_info.policy_flags = policy_header->policy_flags;
               loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids));
               break;
@@ -636,7 +643,7 @@
         }
 
         if (overlayable_iter.HadError()) {
-          LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_POLICY_TYPE: %s",
+          LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_TYPE: %s",
                                      overlayable_iter.GetLastError().c_str());
           if (overlayable_iter.HadFatalError()) {
             return {};
diff --git a/libs/androidfw/ResourceUtils.cpp b/libs/androidfw/ResourceUtils.cpp
index d63feb01..645984d 100644
--- a/libs/androidfw/ResourceUtils.cpp
+++ b/libs/androidfw/ResourceUtils.cpp
@@ -48,4 +48,65 @@
          !(has_type_separator && out_type->empty());
 }
 
+bool ToResourceName(StringPoolRef& type_string_ref,
+                    StringPoolRef& entry_string_ref,
+                    const LoadedPackage* package,
+                    AssetManager2::ResourceName* out_name) {
+  out_name->package = package->GetPackageName().data();
+  out_name->package_len = package->GetPackageName().size();
+
+  out_name->type = type_string_ref.string8(&out_name->type_len);
+  out_name->type16 = nullptr;
+  if (out_name->type == nullptr) {
+    out_name->type16 = type_string_ref.string16(&out_name->type_len);
+    if (out_name->type16 == nullptr) {
+      return false;
+    }
+  }
+
+  out_name->entry = entry_string_ref.string8(&out_name->entry_len);
+  out_name->entry16 = nullptr;
+  if (out_name->entry == nullptr) {
+    out_name->entry16 = entry_string_ref.string16(&out_name->entry_len);
+    if (out_name->entry16 == nullptr) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name) {
+  std::string result;
+  if (resource_name->package != nullptr) {
+    result.append(resource_name->package, resource_name->package_len);
+  }
+
+  if (resource_name->type != nullptr || resource_name->type16 != nullptr) {
+    if (!result.empty()) {
+      result += ":";
+    }
+
+    if (resource_name->type != nullptr) {
+      result.append(resource_name->type, resource_name->type_len);
+    } else {
+      result += util::Utf16ToUtf8(StringPiece16(resource_name->type16, resource_name->type_len));
+    }
+  }
+
+  if (resource_name->entry != nullptr || resource_name->entry16 != nullptr) {
+    if (!result.empty()) {
+      result += "/";
+    }
+
+    if (resource_name->entry != nullptr) {
+      result.append(resource_name->entry, resource_name->entry_len);
+    } else {
+      result += util::Utf16ToUtf8(StringPiece16(resource_name->entry16, resource_name->entry_len));
+    }
+  }
+
+  return result;
+}
+
 }  // namespace android
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
index 5d243da..5be2105 100644
--- a/libs/androidfw/ZipUtils.cpp
+++ b/libs/androidfw/ZipUtils.cpp
@@ -37,7 +37,7 @@
 // TODO: This can go away once the only remaining usage in aapt goes away.
 class FileReader : public zip_archive::Reader {
   public:
-    FileReader(FILE* fp) : Reader(), mFp(fp), mCurrentOffset(0) {
+    explicit FileReader(FILE* fp) : Reader(), mFp(fp), mCurrentOffset(0) {
     }
 
     bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
diff --git a/libs/androidfw/include/androidfw/AssetDir.h b/libs/androidfw/include/androidfw/AssetDir.h
index 7aef02d..ce6e066 100644
--- a/libs/androidfw/include/androidfw/AssetDir.h
+++ b/libs/androidfw/include/androidfw/AssetDir.h
@@ -78,7 +78,7 @@
     class FileInfo {
     public:
         FileInfo(void) {}
-        FileInfo(const String8& path)      // useful for e.g. svect.indexOf
+        explicit FileInfo(const String8& path)      // useful for e.g. svect.indexOf
             : mFileName(path), mFileType(kFileTypeUnknown)
             {}
         ~FileInfo(void) {}
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 0d49298..f29769b 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -229,6 +229,14 @@
                                    ResTable_config* in_out_selected_config, uint32_t* in_out_flags,
                                    uint32_t* out_last_reference) const;
 
+  // Enables or disables resource resolution logging. Clears stored steps when
+  // disabled.
+  void SetResourceResolutionLoggingEnabled(bool enabled);
+
+  // Returns formatted log of last resource resolution path, or empty if no
+  // resource has been resolved yet.
+  std::string GetLastResourceResolution() const;
+
   // Retrieves the best matching bag/map resource with ID `resid`.
   // This method will resolve all parent references for this bag and merge keys with the child.
   // To iterate over the keys, use the following idiom:
@@ -346,6 +354,48 @@
   // Cached set of bags. These are cached because they can inherit keys from parent bags,
   // which involves some calculation.
   std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_;
+
+  // Whether or not to save resource resolution steps
+  bool resource_resolution_logging_enabled_ = false;
+
+  struct Resolution {
+
+    struct Step {
+
+      enum class Type {
+        INITIAL,
+        BETTER_MATCH,
+        OVERLAID
+      };
+
+      // Marks what kind of override this step was.
+      Type type;
+
+      // Built name of configuration for this step.
+      String8 config_name;
+
+      // Marks the package name of the better resource found in this step.
+      const std::string* package_name;
+    };
+
+    // Last resolved resource ID.
+    uint32_t resid;
+
+    // Last resolved resource result cookie.
+    ApkAssetsCookie cookie = kInvalidCookie;
+
+    // Last resolved resource type.
+    StringPoolRef type_string_ref;
+
+    // Last resolved resource entry.
+    StringPoolRef entry_string_ref;
+
+    // Steps taken to resolve last resource.
+    std::vector<Step> steps;
+  };
+
+  // Record of the last resolved resource's resolution path.
+  mutable Resolution last_resolution;
 };
 
 class Theme {
diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
index 35ef98d..c88004c 100644
--- a/libs/androidfw/include/androidfw/AttributeResolution.h
+++ b/libs/androidfw/include/androidfw/AttributeResolution.h
@@ -23,15 +23,17 @@
 namespace android {
 
 // Offsets into the outValues array populated by the methods below. outValues is a uint32_t
-// array, but each logical element takes up 6 uint32_t-sized physical elements.
+// array, but each logical element takes up 7 uint32_t-sized physical elements.
+// Keep these in sync with android.content.res.TypedArray java class
 enum {
-  STYLE_NUM_ENTRIES = 6,
+  STYLE_NUM_ENTRIES = 7,
   STYLE_TYPE = 0,
   STYLE_DATA = 1,
   STYLE_ASSET_COOKIE = 2,
   STYLE_RESOURCE_ID = 3,
   STYLE_CHANGING_CONFIGURATIONS = 4,
-  STYLE_DENSITY = 5
+  STYLE_DENSITY = 5,
+  SYTLE_SOURCE_STYLE = 6
 };
 
 // These are all variations of the same method. They each perform the exact same operation,
diff --git a/libs/androidfw/include/androidfw/BackupHelpers.h b/libs/androidfw/include/androidfw/BackupHelpers.h
index fc1ad47..2da247b 100644
--- a/libs/androidfw/include/androidfw/BackupHelpers.h
+++ b/libs/androidfw/include/androidfw/BackupHelpers.h
@@ -67,7 +67,7 @@
 class BackupDataWriter
 {
 public:
-    BackupDataWriter(int fd);
+    explicit BackupDataWriter(int fd);
     // does not close fd
     ~BackupDataWriter();
 
@@ -104,7 +104,7 @@
 class BackupDataReader
 {
 public:
-    BackupDataReader(int fd);
+    explicit BackupDataReader(int fd);
     // does not close fd
     ~BackupDataReader();
 
diff --git a/libs/androidfw/include/androidfw/ConfigDescription.h b/libs/androidfw/include/androidfw/ConfigDescription.h
index 29424c4..6fa089a 100644
--- a/libs/androidfw/include/androidfw/ConfigDescription.h
+++ b/libs/androidfw/include/androidfw/ConfigDescription.h
@@ -82,7 +82,7 @@
   static void ApplyVersionForCompatibility(ConfigDescription* config);
 
   ConfigDescription();
-  ConfigDescription(const android::ResTable_config& o);  // NOLINT(implicit)
+  ConfigDescription(const android::ResTable_config& o);  // NOLINT(google-explicit-constructor)
   ConfigDescription(const ConfigDescription& o);
   ConfigDescription(ConfigDescription&& o) noexcept;
 
diff --git a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
index e1dfb94..bf35aa3 100644
--- a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
+++ b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
@@ -22,7 +22,7 @@
 
 class DisplayEventDispatcher : public LooperCallback {
 public:
-    DisplayEventDispatcher(const sp<Looper>& looper,
+    explicit DisplayEventDispatcher(const sp<Looper>& looper,
             ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
 
     status_t initialize();
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 8c5c3b7..be62f30 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -78,6 +78,8 @@
 using TypeSpecPtr = util::unique_cptr<TypeSpec>;
 
 struct OverlayableInfo {
+  std::string name;
+  std::string actor;
   uint32_t policy_flags;
 };
 
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index cf2d8fb..1655e89 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -693,7 +693,7 @@
 class ResXMLParser
 {
 public:
-    ResXMLParser(const ResXMLTree& tree);
+    explicit ResXMLParser(const ResXMLTree& tree);
 
     enum event_code_t {
         BAD_DOCUMENT = -1,
@@ -806,7 +806,7 @@
      * The tree stores a clone of the specified DynamicRefTable, so any changes to the original
      * DynamicRefTable will not affect this tree after instantiation.
      **/
-    ResXMLTree(const DynamicRefTable* dynamicRefTable);
+    explicit ResXMLTree(const DynamicRefTable* dynamicRefTable);
     ResXMLTree();
     ~ResXMLTree();
 
@@ -1611,6 +1611,12 @@
 struct ResTable_overlayable_header
 {
   struct ResChunk_header header;
+
+  // The name of the overlayable set of resources that overlays target.
+  uint16_t name[256];
+
+ // The component responsible for enabling and disabling overlays targeting this chunk.
+  uint16_t actor[256];
 };
 
 /**
@@ -1637,10 +1643,6 @@
     // The overlay must reside of the product partition or must have existed on the product
     // partition before an upgrade to overlay these resources.
     POLICY_PRODUCT_PARTITION = 0x00000008,
-
-    // The overlay must reside of the product services partition or must have existed on the product
-    // services partition before an upgrade to overlay these resources.
-    POLICY_PRODUCT_SERVICES_PARTITION = 0x00000010,
   };
   uint32_t policy_flags;
 
@@ -1844,7 +1846,7 @@
 
     class Theme {
     public:
-        Theme(const ResTable& table);
+        explicit Theme(const ResTable& table);
         ~Theme();
 
         inline const ResTable& getResTable() const { return mTable; }
diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h
index d94779b..eb6eb8e 100644
--- a/libs/androidfw/include/androidfw/ResourceUtils.h
+++ b/libs/androidfw/include/androidfw/ResourceUtils.h
@@ -17,6 +17,7 @@
 #ifndef ANDROIDFW_RESOURCEUTILS_H
 #define ANDROIDFW_RESOURCEUTILS_H
 
+#include "androidfw/AssetManager2.h"
 #include "androidfw/StringPiece.h"
 
 namespace android {
@@ -27,6 +28,17 @@
 bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type,
                          StringPiece* out_entry);
 
+// Convert a type_string_ref, entry_string_ref, and package
+// to AssetManager2::ResourceName. Useful for getting
+// resource name without re-running AssetManager2::FindEntry searches.
+bool ToResourceName(StringPoolRef& type_string_ref,
+                    StringPoolRef& entry_string_ref,
+                    const LoadedPackage* package,
+                    AssetManager2::ResourceName* out_name);
+
+// Formats a ResourceName to "package:type/entry_name".
+std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name);
+
 inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) {
   return (resid & 0x00ffffffu) | (static_cast<uint32_t>(package_id) << 24);
 }
diff --git a/libs/androidfw/include/androidfw/StringPiece.h b/libs/androidfw/include/androidfw/StringPiece.h
index a33865f..921877d 100644
--- a/libs/androidfw/include/androidfw/StringPiece.h
+++ b/libs/androidfw/include/androidfw/StringPiece.h
@@ -52,8 +52,8 @@
 
   BasicStringPiece();
   BasicStringPiece(const BasicStringPiece<TChar>& str);
-  BasicStringPiece(const std::basic_string<TChar>& str);  // NOLINT(implicit)
-  BasicStringPiece(const TChar* str);                     // NOLINT(implicit)
+  BasicStringPiece(const std::basic_string<TChar>& str);  // NOLINT(google-explicit-constructor)
+  BasicStringPiece(const TChar* str);                     // NOLINT(google-explicit-constructor)
   BasicStringPiece(const TChar* str, size_t len);
 
   BasicStringPiece<TChar>& operator=(const BasicStringPiece<TChar>& rhs);
diff --git a/libs/androidfw/include/androidfw/TypeWrappers.h b/libs/androidfw/include/androidfw/TypeWrappers.h
index 5cfe54e5..fb2fad6 100644
--- a/libs/androidfw/include/androidfw/TypeWrappers.h
+++ b/libs/androidfw/include/androidfw/TypeWrappers.h
@@ -23,7 +23,7 @@
 namespace android {
 
 struct TypeVariant {
-    TypeVariant(const ResTable_type* data);
+    explicit TypeVariant(const ResTable_type* data);
 
     class iterator {
     public:
diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h
index 10d088e..aa1466f 100644
--- a/libs/androidfw/include/androidfw/Util.h
+++ b/libs/androidfw/include/androidfw/Util.h
@@ -46,7 +46,7 @@
   using pointer = typename std::add_pointer<T>::type;
 
   constexpr unique_cptr() : ptr_(nullptr) {}
-  constexpr unique_cptr(std::nullptr_t) : ptr_(nullptr) {}
+  constexpr explicit unique_cptr(std::nullptr_t) : ptr_(nullptr) {}
   explicit unique_cptr(pointer ptr) : ptr_(ptr) {}
   unique_cptr(unique_cptr&& o) noexcept : ptr_(o.ptr_) { o.ptr_ = nullptr; }
 
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 5449a54..105dcd2 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -586,4 +586,111 @@
   EXPECT_THAT(asset_dir->getFileType(2), Eq(FileType::kFileTypeDirectory));
 }
 
+TEST_F(AssetManager2Test, GetLastPathWithoutEnablingReturnsEmpty) {
+  ResTable_config desired_config;
+
+  AssetManager2 assetmanager;
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get()});
+  assetmanager.SetResourceResolutionLoggingEnabled(false);
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ApkAssetsCookie cookie =
+      assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+                               0 /*density_override*/, &value, &selected_config, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+
+  auto result = assetmanager.GetLastResourceResolution();
+  EXPECT_EQ("", result);
+}
+
+TEST_F(AssetManager2Test, GetLastPathWithoutResolutionReturnsEmpty) {
+  ResTable_config desired_config;
+
+  AssetManager2 assetmanager;
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get()});
+
+  auto result = assetmanager.GetLastResourceResolution();
+  EXPECT_EQ("", result);
+}
+
+TEST_F(AssetManager2Test, GetLastPathWithSingleApkAssets) {
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+  desired_config.language[0] = 'd';
+  desired_config.language[1] = 'e';
+
+  AssetManager2 assetmanager;
+  assetmanager.SetResourceResolutionLoggingEnabled(true);
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get()});
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ApkAssetsCookie cookie =
+      assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+                               0 /*density_override*/, &value, &selected_config, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+
+  auto result = assetmanager.GetLastResourceResolution();
+  EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic", result);
+}
+
+TEST_F(AssetManager2Test, GetLastPathWithMultipleApkAssets) {
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+  desired_config.language[0] = 'd';
+  desired_config.language[1] = 'e';
+
+  AssetManager2 assetmanager;
+  assetmanager.SetResourceResolutionLoggingEnabled(true);
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get(), basic_de_fr_assets_.get()});
+
+  Res_value value = Res_value();
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ApkAssetsCookie cookie =
+      assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+                               0 /*density_override*/, &value, &selected_config, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+
+  auto result = assetmanager.GetLastResourceResolution();
+  EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic\n\tFound better: com.android.basic -de", result);
+}
+
+TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) {
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+
+  AssetManager2 assetmanager;
+  assetmanager.SetResourceResolutionLoggingEnabled(true);
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get()});
+
+  Res_value value = Res_value();
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ApkAssetsCookie cookie =
+      assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+                               0 /*density_override*/, &value, &selected_config, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+
+  auto resultEnabled = assetmanager.GetLastResourceResolution();
+  ASSERT_NE("", resultEnabled);
+
+  assetmanager.SetResourceResolutionLoggingEnabled(false);
+
+  auto resultDisabled = assetmanager.GetLastResourceResolution();
+  EXPECT_EQ("", resultDisabled);
+}
+
 }  // namespace android
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 22d587a..b8d3c6b 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -294,22 +294,29 @@
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable1);
   ASSERT_THAT(info, NotNull());
+  EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+  EXPECT_THAT(info->actor, Eq("overlay://theme"));
   EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable2);
   ASSERT_THAT(info, NotNull());
+  EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+  EXPECT_THAT(info->actor, Eq("overlay://theme"));
   EXPECT_THAT(info->policy_flags,
               Eq(ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION
                  | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable3);
   ASSERT_THAT(info, NotNull());
+  EXPECT_THAT(info->name, Eq("OverlayableResources2"));
+  EXPECT_THAT(info->actor, Eq("overlay://com.android.overlayable"));
   EXPECT_THAT(info->policy_flags,
               Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION
-                 | ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION
                  | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
 
   info = package->GetOverlayableInfo(overlayable::R::string::overlayable4);
+  EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+  EXPECT_THAT(info->actor, Eq("overlay://theme"));
   ASSERT_THAT(info, NotNull());
   EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
 }
diff --git a/libs/androidfw/tests/data/overlayable/overlayable.apk b/libs/androidfw/tests/data/overlayable/overlayable.apk
index 85ab4be..047e6af 100644
--- a/libs/androidfw/tests/data/overlayable/overlayable.apk
+++ b/libs/androidfw/tests/data/overlayable/overlayable.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
index 11aa735..fcdbe94 100644
--- a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
+++ b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
@@ -15,7 +15,7 @@
 -->
 
 <resources>
-<overlayable>
+<overlayable name="OverlayableResources1" actor="overlay://theme">
     <!-- Any overlay can overlay the value of @string/overlayable1 -->
     <item type="string" name="overlayable1" />
 
@@ -31,10 +31,10 @@
     </policy>
 </overlayable>
 
-<overlayable>
-    <!-- Any overlay on the product_services, vendor, or product partition can overlay the value of
-   @string/overlayable3 -->
-    <policy type="product_services|vendor|product">
+<overlayable name="OverlayableResources2" actor="overlay://com.android.overlayable">
+    <!-- Any overlay on the vendor or product partition can overlay the value of
+        @string/overlayable3 -->
+    <policy type="vendor|product">
         <item type="string" name="overlayable3" />
     </policy>
 </overlayable>
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 7e69e3a..96798f9 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -61,6 +61,7 @@
         "libstatslog",
         "libutils",
         "libEGL",
+        "libGLESv1_CM",
         "libGLESv2",
         "libGLESv3",
         "libvulkan",
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index ed167e5..56b1885 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -79,8 +79,7 @@
     switch (wcgDataspace) {
         case ui::Dataspace::DISPLAY_P3:
             *colorGamut = SkColorSpace::Gamut::kDCIP3_D65_Gamut;
-            *colorSpace = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
-                                                SkColorSpace::Gamut::kDCIP3_D65_Gamut);
+            *colorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
             break;
         case ui::Dataspace::V0_SCRGB:
             *colorGamut = SkColorSpace::Gamut::kSRGB_Gamut;
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index b9860ad..635d0ec 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -34,7 +34,7 @@
 namespace android::uirenderer {
 
 static std::mutex sLock{};
-static ThreadBase* sUploadThread = nullptr;
+static sp<ThreadBase> sUploadThread = nullptr;
 static renderthread::EglManager sEglManager;
 static int sPendingUploads = 0;
 static nsecs_t sLastUpload = 0;
@@ -257,4 +257,15 @@
                               Bitmap::computePalette(bitmap));
 }
 
+void HardwareBitmapUploader::terminate() {
+    std::lock_guard _lock{sLock};
+    LOG_ALWAYS_FATAL_IF(sPendingUploads, "terminate called while uploads in progress");
+    if (sUploadThread) {
+        sUploadThread->requestExit();
+        sUploadThread->join();
+        sUploadThread = nullptr;
+    }
+    sEglManager.destroy();
+}
+
 }  // namespace android::uirenderer
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 6298013..40f2b0c 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -23,6 +23,7 @@
 class HardwareBitmapUploader {
 public:
     static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap);
+    static void terminate();
 };
 
 }  // namespace android::uirenderer
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index b33cfe2..0c515a4 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -81,7 +81,7 @@
 
     explicit Matrix4(const float* v) { load(v); }
 
-    Matrix4(const SkMatrix& v) {  // NOLINT, implicit
+    Matrix4(const SkMatrix& v) {  // NOLINT(google-explicit-constructor)
         load(v);
     }
 
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index d6362ef..24443c8 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -57,15 +57,15 @@
 
     inline Rect(float width, float height) : left(0.0f), top(0.0f), right(width), bottom(height) {}
 
-    inline Rect(const SkIRect& rect)
-            :  // NOLINT, implicit
+    inline Rect(const SkIRect& rect) // NOLINT(google-explicit-constructor)
+            :
             left(rect.fLeft)
             , top(rect.fTop)
             , right(rect.fRight)
             , bottom(rect.fBottom) {}
 
-    inline Rect(const SkRect& rect)
-            :  // NOLINT, implicit
+    inline Rect(const SkRect& rect) // NOLINT(google-explicit-constructor)
+            :
             left(rect.fLeft)
             , top(rect.fTop)
             , right(rect.fRight)
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index ab95e69..cc62fdc 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -678,15 +678,15 @@
 // Canvas draw operations: Text
 // ----------------------------------------------------------------------------
 
-void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
+void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& paint, float x,
                             float y, float boundsLeft, float boundsTop, float boundsRight,
                             float boundsBottom, float totalAdvance) {
     if (count <= 0 || paint.nothingToDraw()) return;
-    SkFont font = SkFont::LEGACY_ExtractFromPaint(paint);
     SkPaint paintCopy(paint);
     if (mPaintFilter) {
         mPaintFilter->filter(&paintCopy);
     }
+    SkFont font = SkFont::LEGACY_ExtractFromPaint(paintCopy);
     SkASSERT(paintCopy.getTextEncoding() == kGlyphID_SkTextEncoding);
     // Stroke with a hairline is drawn on HW with a fill style for compatibility with Android O and
     // older.
@@ -708,13 +708,13 @@
 }
 
 void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
-                                  const SkPaint& paint, const SkPath& path, size_t start,
+                                  const Paint& paint, const SkPath& path, size_t start,
                                   size_t end) {
-    SkFont font = SkFont::LEGACY_ExtractFromPaint(paint);
     SkPaint paintCopy(paint);
     if (mPaintFilter) {
         mPaintFilter->filter(&paintCopy);
     }
+    SkFont font = SkFont::LEGACY_ExtractFromPaint(paintCopy);
     SkASSERT(paintCopy.getTextEncoding() == kGlyphID_SkTextEncoding);
 
     const int N = end - start;
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 4ab0a59..3fe2bce 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -158,11 +158,11 @@
     void reset(SkCanvas* skiaCanvas);
     void drawDrawable(SkDrawable* drawable) { mCanvas->drawDrawable(drawable); }
 
-    virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
+    virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& paint, float x,
                             float y, float boundsLeft, float boundsTop, float boundsRight,
                             float boundsBottom, float totalAdvance) override;
     virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
-                                  const SkPaint& paint, const SkPath& path, size_t start,
+                                  const Paint& paint, const SkPath& path, size_t start,
                                   size_t end) override;
 
     /** This class acts as a copy on write SkPaint.
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index dd62bbb..7265692 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -551,6 +551,19 @@
     SkPaint paint = inPaint;
     paint.setAlpha(mProperties.getRootAlpha() * 255);
 
+    if (canvas->getGrContext() == nullptr) {
+        // Recording to picture, don't use the SkSurface which won't work off of renderthread.
+        Bitmap& bitmap = getBitmapUpdateIfDirty();
+        SkBitmap skiaBitmap;
+        bitmap.getSkBitmap(&skiaBitmap);
+
+        int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
+        int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
+        canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
+                               &paint, SkCanvas::kFast_SrcRectConstraint);
+        return;
+    }
+
     SkRect src;
     sk_sp<SkSurface> vdSurface = mCache.getSurface(&src);
     if (vdSurface) {
diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp
index 20e77b4..68541b4 100644
--- a/libs/hwui/WebViewFunctorManager.cpp
+++ b/libs/hwui/WebViewFunctorManager.cpp
@@ -18,6 +18,7 @@
 
 #include <private/hwui/WebViewFunctor.h>
 #include "Properties.h"
+#include "renderthread/RenderThread.h"
 
 #include <log/log.h>
 #include <utils/Trace.h>
@@ -37,7 +38,8 @@
     }
 }
 
-int WebViewFunctor_create(const WebViewFunctorCallbacks& prototype, RenderMode functorMode) {
+int WebViewFunctor_create(void* data, const WebViewFunctorCallbacks& prototype,
+                          RenderMode functorMode) {
     if (functorMode != RenderMode::OpenGL_ES && functorMode != RenderMode::Vulkan) {
         ALOGW("Unknown rendermode %d", (int)functorMode);
         return -1;
@@ -47,7 +49,7 @@
         ALOGW("Unable to map from GLES platform to a vulkan functor");
         return -1;
     }
-    return WebViewFunctorManager::instance().createFunctor(prototype, functorMode);
+    return WebViewFunctorManager::instance().createFunctor(data, prototype, functorMode);
 }
 
 void WebViewFunctor_release(int functor) {
@@ -56,7 +58,9 @@
 
 static std::atomic_int sNextId{1};
 
-WebViewFunctor::WebViewFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode) {
+WebViewFunctor::WebViewFunctor(void* data, const WebViewFunctorCallbacks& callbacks,
+                               RenderMode functorMode)
+        : mData(data) {
     mFunctor = sNextId++;
     mCallbacks = callbacks;
     mMode = functorMode;
@@ -66,12 +70,12 @@
     destroyContext();
 
     ATRACE_NAME("WebViewFunctor::onDestroy");
-    mCallbacks.onDestroyed(mFunctor);
+    mCallbacks.onDestroyed(mFunctor, mData);
 }
 
 void WebViewFunctor::sync(const WebViewSyncData& syncData) const {
     ATRACE_NAME("WebViewFunctor::sync");
-    mCallbacks.onSync(mFunctor, syncData);
+    mCallbacks.onSync(mFunctor, mData, syncData);
 }
 
 void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) {
@@ -79,14 +83,38 @@
     if (!mHasContext) {
         mHasContext = true;
     }
-    mCallbacks.gles.draw(mFunctor, drawInfo);
+    mCallbacks.gles.draw(mFunctor, mData, drawInfo);
+}
+
+void WebViewFunctor::initVk(const VkFunctorInitParams& params) {
+    ATRACE_NAME("WebViewFunctor::initVk");
+    if (!mHasContext) {
+        mHasContext = true;
+    } else {
+        return;
+    }
+    mCallbacks.vk.initialize(mFunctor, mData, params);
+}
+
+void WebViewFunctor::drawVk(const VkFunctorDrawParams& params) {
+    ATRACE_NAME("WebViewFunctor::drawVk");
+    mCallbacks.vk.draw(mFunctor, mData, params);
+}
+
+void WebViewFunctor::postDrawVk() {
+    ATRACE_NAME("WebViewFunctor::postDrawVk");
+    mCallbacks.vk.postDraw(mFunctor, mData);
 }
 
 void WebViewFunctor::destroyContext() {
     if (mHasContext) {
         mHasContext = false;
         ATRACE_NAME("WebViewFunctor::onContextDestroyed");
-        mCallbacks.onContextDestroyed(mFunctor);
+        mCallbacks.onContextDestroyed(mFunctor, mData);
+
+        // grContext may be null in unit tests.
+        auto* grContext = renderthread::RenderThread::getInstance().getGrContext();
+        if (grContext) grContext->resetContext();
     }
 }
 
@@ -95,9 +123,9 @@
     return sInstance;
 }
 
-int WebViewFunctorManager::createFunctor(const WebViewFunctorCallbacks& callbacks,
+int WebViewFunctorManager::createFunctor(void* data, const WebViewFunctorCallbacks& callbacks,
                                          RenderMode functorMode) {
-    auto object = std::make_unique<WebViewFunctor>(callbacks, functorMode);
+    auto object = std::make_unique<WebViewFunctor>(data, callbacks, functorMode);
     int id = object->id();
     auto handle = object->createHandle();
     {
@@ -164,4 +192,4 @@
     return nullptr;
 }
 
-}  // namespace android::uirenderer
\ No newline at end of file
+}  // namespace android::uirenderer
diff --git a/libs/hwui/WebViewFunctorManager.h b/libs/hwui/WebViewFunctorManager.h
index 2a621dd..2846cb1 100644
--- a/libs/hwui/WebViewFunctorManager.h
+++ b/libs/hwui/WebViewFunctorManager.h
@@ -29,7 +29,7 @@
 
 class WebViewFunctor {
 public:
-    WebViewFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
+    WebViewFunctor(void* data, const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
     ~WebViewFunctor();
 
     class Handle : public LightRefBase<Handle> {
@@ -42,6 +42,12 @@
 
         void drawGl(const DrawGlInfo& drawInfo) const { mReference.drawGl(drawInfo); }
 
+        void initVk(const VkFunctorInitParams& params) { mReference.initVk(params); }
+
+        void drawVk(const VkFunctorDrawParams& params) { mReference.drawVk(params); }
+
+        void postDrawVk() { mReference.postDrawVk(); }
+
     private:
         friend class WebViewFunctor;
 
@@ -53,6 +59,9 @@
     int id() const { return mFunctor; }
     void sync(const WebViewSyncData& syncData) const;
     void drawGl(const DrawGlInfo& drawInfo);
+    void initVk(const VkFunctorInitParams& params);
+    void drawVk(const VkFunctorDrawParams& params);
+    void postDrawVk();
     void destroyContext();
 
     sp<Handle> createHandle() {
@@ -63,6 +72,7 @@
 
 private:
     WebViewFunctorCallbacks mCallbacks;
+    void* const mData;
     int mFunctor;
     RenderMode mMode;
     bool mHasContext = false;
@@ -73,7 +83,7 @@
 public:
     static WebViewFunctorManager& instance();
 
-    int createFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
+    int createFunctor(void* data, const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
     void releaseFunctor(int functor);
     void onContextDestroyed();
     void destroyFunctor(int functor);
diff --git a/libs/hwui/debug/GlesErrorCheckWrapper.h b/libs/hwui/debug/GlesErrorCheckWrapper.h
index ee5cc1f..791400b 100644
--- a/libs/hwui/debug/GlesErrorCheckWrapper.h
+++ b/libs/hwui/debug/GlesErrorCheckWrapper.h
@@ -24,7 +24,7 @@
 
 class GlesErrorCheckWrapper : public GlesDriver {
 public:
-    GlesErrorCheckWrapper(GlesDriver& base) : mBase(base) {}
+    explicit GlesErrorCheckWrapper(GlesDriver& base) : mBase(base) {}
 
 #define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) override;
 #include "gles_decls.in"
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index a09da6b..277148e 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -38,7 +38,7 @@
     canvas->drawRect(left, top, right, bottom, paint);
 }
 
-void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) {
+void Canvas::drawTextDecorations(float x, float y, float length, const Paint& paint) {
     uint32_t flags;
     PaintFilter* paintFilter = getPaintFilter();
     if (paintFilter) {
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 4c5365d..11e8579 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -303,18 +303,18 @@
     static int GetApiLevel() { return sApiLevel; }
 
 protected:
-    void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
+    void drawTextDecorations(float x, float y, float length, const Paint& paint);
 
     /**
      * glyphFunc: valid only for the duration of the call and should not be cached.
      * drawText: count is of glyphs
      * totalAdvance: used to define width of text decorations (underlines, strikethroughs).
      */
-    virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
+    virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& paint, float x,
                             float y, float boundsLeft, float boundsTop, float boundsRight,
                             float boundsBottom, float totalAdvance) = 0;
     virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
-                                  const SkPaint& paint, const SkPath& path, size_t start,
+                                  const Paint& paint, const SkPath& path, size_t start,
                                   size_t end) = 0;
     static int sApiLevel;
 
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index c1a3b6d..92ffda9 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -46,7 +46,7 @@
 
     Paint();
     Paint(const Paint& paint);
-    Paint(const SkPaint& paint);  // NOLINT(implicit)
+    Paint(const SkPaint& paint);  // NOLINT(google-explicit-constructor)
     ~Paint();
 
     Paint& operator=(const Paint& other);
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 240efb4..60c8057 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -74,7 +74,13 @@
 
 void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
     if (canvas->getGrContext() == nullptr) {
-        SkDEBUGF(("Attempting to draw GLFunctor into an unsupported surface"));
+        // We're dumping a picture, render a light-blue rectangle instead
+        // TODO: Draw the WebView text on top? Seemingly complicated as SkPaint doesn't
+        // seem to have a default typeface that works. We only ever use drawGlyphs, which
+        // requires going through minikin & hwui's canvas which we don't have here.
+        SkPaint paint;
+        paint.setColor(0xFF81D4FA);
+        canvas->drawRect(mBounds, paint);
         return;
     }
 
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index 562a3b2..1661905 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -23,6 +23,7 @@
 #include "FileBlobCache.h"
 #include "Properties.h"
 #include "utils/TraceUtils.h"
+#include <GrContext.h>
 
 namespace android {
 namespace uirenderer {
@@ -168,6 +169,24 @@
     const void* value = data.data();
 
     BlobCache* bc = getBlobCacheLocked();
+    if (mInStoreVkPipelineInProgress) {
+        if (mOldPipelineCacheSize == -1) {
+            // Record the initial pipeline cache size stored in the file.
+            mOldPipelineCacheSize = bc->get(key.data(), keySize, nullptr, 0);
+        }
+        if (mNewPipelineCacheSize != -1 && mNewPipelineCacheSize == valueSize) {
+            // There has not been change in pipeline cache size. Stop trying to save.
+            mTryToStorePipelineCache = false;
+            return;
+        }
+        mNewPipelineCacheSize = valueSize;
+    } else {
+        mCacheDirty = true;
+        // If there are new shaders compiled, we probably have new pipeline state too.
+        // Store pipeline cache on the next flush.
+        mNewPipelineCacheSize = -1;
+        mTryToStorePipelineCache = true;
+    }
     bc->set(key.data(), keySize, value, valueSize);
 
     if (!mSavePending && mDeferredSaveDelay > 0) {
@@ -175,12 +194,31 @@
         std::thread deferredSaveThread([this]() {
             sleep(mDeferredSaveDelay);
             std::lock_guard<std::mutex> lock(mMutex);
-            saveToDiskLocked();
+            // Store file on disk if there a new shader or Vulkan pipeline cache size changed.
+            if (mCacheDirty || mNewPipelineCacheSize != mOldPipelineCacheSize) {
+                saveToDiskLocked();
+                mOldPipelineCacheSize = mNewPipelineCacheSize;
+                mTryToStorePipelineCache = false;
+                mCacheDirty = false;
+            }
         });
         deferredSaveThread.detach();
     }
 }
 
+void ShaderCache::onVkFrameFlushed(GrContext* context) {
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+
+        if (!mInitialized || !mTryToStorePipelineCache) {
+            return;
+        }
+    }
+    mInStoreVkPipelineInProgress = true;
+    context->storeVkPipelineCacheData();
+    mInStoreVkPipelineInProgress = false;
+}
+
 } /* namespace skiapipeline */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h
index d41aadb..0898017 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.h
+++ b/libs/hwui/pipeline/skia/ShaderCache.h
@@ -75,6 +75,13 @@
      */
     void store(const SkData& key, const SkData& data) override;
 
+    /**
+     * "onVkFrameFlushed" tries to store Vulkan pipeline cache state.
+     * Pipeline cache is saved on disk only if the size of the data has changed or there was
+     * a new shader compiled.
+     */
+    void onVkFrameFlushed(GrContext* context);
+
 private:
     // Creation and (the lack of) destruction is handled internally.
     ShaderCache();
@@ -167,6 +174,33 @@
     mutable std::mutex mMutex;
 
     /**
+     *  If set to "true", the next call to onVkFrameFlushed, will invoke
+     * GrCanvas::storeVkPipelineCacheData. This does not guarantee that data will be stored on disk.
+     */
+    bool mTryToStorePipelineCache = true;
+
+    /**
+     * This flag is used by "ShaderCache::store" to distinguish between shader data and
+     * Vulkan pipeline data.
+     */
+    bool mInStoreVkPipelineInProgress = false;
+
+    /**
+     *  "mNewPipelineCacheSize" has the size of the new Vulkan pipeline cache data. It is used
+     *  to prevent unnecessary disk writes, if the pipeline cache size has not changed.
+     */
+    size_t mNewPipelineCacheSize = -1;
+    /**
+     *  "mOldPipelineCacheSize" has the size of the Vulkan pipeline cache data stored on disk.
+     */
+    size_t mOldPipelineCacheSize = -1;
+
+    /**
+     *  "mCacheDirty" is true when there is new shader cache data, which is not saved to disk.
+     */
+    bool mCacheDirty = false;
+
+    /**
      * "sCache" is the singleton ShaderCache object.
      */
     static ShaderCache sCache;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 4338b1c..cfbb995 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -96,11 +96,12 @@
 
     SkASSERT(mRenderThread.getGrContext() != nullptr);
     sk_sp<SkSurface> surface(SkSurface::MakeFromBackendRenderTarget(
-            mRenderThread.getGrContext(), backendRT, kBottomLeft_GrSurfaceOrigin, colorType,
+            mRenderThread.getGrContext(), backendRT, this->getSurfaceOrigin(), colorType,
             mSurfaceColorSpace, &props));
 
     SkiaPipeline::updateLighting(lightGeometry, lightInfo);
-    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
+            SkMatrix::I());
     layerUpdateQueue->clear();
 
     // Draw visual debugging features
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 47991069..6692922 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -39,6 +39,7 @@
               const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
               const std::vector<sp<RenderNode> >& renderNodes,
               FrameInfoVisualizer* profiler) override;
+    GrSurfaceOrigin getSurfaceOrigin() override { return kBottomLeft_GrSurfaceOrigin; }
     bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
                      FrameInfo* currentFrameInfo, bool* requireSwap) override;
     DeferredLayerUpdater* createTextureLayer() override;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 2e7850d..47c9094 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -111,7 +111,7 @@
 
             const Rect& layerDamage = layers.entries()[i].damage;
 
-            SkCanvas* layerCanvas = tryCapture(layerNode->getLayerSurface());
+            SkCanvas* layerCanvas = layerNode->getLayerSurface()->getCanvas();
 
             int saveCount = layerCanvas->save();
             SkASSERT(saveCount == 1);
@@ -139,8 +139,6 @@
             layerCanvas->restoreToCount(saveCount);
             mLightCenter = savedLightCenter;
 
-            endCapture(layerNode->getLayerSurface());
-
             // cache the current context so that we can defer flushing it until
             // either all the layers have been rendered or the context changes
             GrContext* currentContext = layerNode->getLayerSurface()->getCanvas()->getGrContext();
@@ -174,7 +172,8 @@
         SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
         SkASSERT(mRenderThread.getGrContext() != nullptr);
         node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
-                                                          SkBudgeted::kYes, info, 0, &props));
+                                                          SkBudgeted::kYes, info, 0,
+                                                          this->getSurfaceOrigin(), &props));
         if (node->getLayerSurface()) {
             // update the transform in window of the layer to reset its origin wrt light source
             // position
@@ -243,6 +242,7 @@
     }
 
     virtual void onProcess(const sp<Task<bool>>& task) override {
+        ATRACE_NAME("SavePictureTask");
         SavePictureTask* t = static_cast<SavePictureTask*>(task.get());
 
         if (0 == access(t->filename.c_str(), F_OK)) {
@@ -264,46 +264,56 @@
 
 SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) {
     if (CC_UNLIKELY(Properties::skpCaptureEnabled)) {
-        bool recordingPicture = mCaptureSequence > 0;
         char prop[PROPERTY_VALUE_MAX] = {'\0'};
-        if (!recordingPicture) {
+        if (mCaptureSequence <= 0) {
             property_get(PROPERTY_CAPTURE_SKP_FILENAME, prop, "0");
-            recordingPicture = prop[0] != '0' &&
-                               mCapturedFile != prop;  // ensure we capture only once per filename
-            if (recordingPicture) {
+            if (prop[0] != '0' && mCapturedFile != prop) {
                 mCapturedFile = prop;
                 mCaptureSequence = property_get_int32(PROPERTY_CAPTURE_SKP_FRAMES, 1);
             }
         }
-        if (recordingPicture) {
+        if (mCaptureSequence > 0 || mPictureCapturedCallback) {
             mRecorder.reset(new SkPictureRecorder());
-            return mRecorder->beginRecording(surface->width(), surface->height(), nullptr,
-                                             SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
+            SkCanvas* pictureCanvas = mRecorder->beginRecording(surface->width(), surface->height(), nullptr,
+                                                                SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
+            mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
+            mNwayCanvas->addCanvas(surface->getCanvas());
+            mNwayCanvas->addCanvas(pictureCanvas);
+            return mNwayCanvas.get();
         }
     }
     return surface->getCanvas();
 }
 
 void SkiaPipeline::endCapture(SkSurface* surface) {
+    mNwayCanvas.reset();
     if (CC_UNLIKELY(mRecorder.get())) {
+        ATRACE_CALL();
         sk_sp<SkPicture> picture = mRecorder->finishRecordingAsPicture();
-        surface->getCanvas()->drawPicture(picture);
         if (picture->approximateOpCount() > 0) {
-            auto data = picture->serialize();
+            if (mCaptureSequence > 0) {
+                ATRACE_BEGIN("picture->serialize");
+                auto data = picture->serialize();
+                ATRACE_END();
 
-            // offload saving to file in a different thread
-            if (!mSavePictureProcessor.get()) {
-                TaskManager* taskManager = getTaskManager();
-                mSavePictureProcessor = new SavePictureProcessor(
-                        taskManager->canRunTasks() ? taskManager : nullptr);
+                // offload saving to file in a different thread
+                if (!mSavePictureProcessor.get()) {
+                    TaskManager* taskManager = getTaskManager();
+                    mSavePictureProcessor = new SavePictureProcessor(
+                            taskManager->canRunTasks() ? taskManager : nullptr);
+                }
+                if (1 == mCaptureSequence) {
+                    mSavePictureProcessor->savePicture(data, mCapturedFile);
+                } else {
+                    mSavePictureProcessor->savePicture(
+                            data,
+                            mCapturedFile + "_" + std::to_string(mCaptureSequence));
+                }
+                mCaptureSequence--;
             }
-            if (1 == mCaptureSequence) {
-                mSavePictureProcessor->savePicture(data, mCapturedFile);
-            } else {
-                mSavePictureProcessor->savePicture(
-                        data, mCapturedFile + "_" + std::to_string(mCaptureSequence));
+            if (mPictureCapturedCallback) {
+                std::invoke(mPictureCapturedCallback, std::move(picture));
             }
-            mCaptureSequence--;
         }
         mRecorder.reset();
     }
@@ -311,7 +321,13 @@
 
 void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
                                const std::vector<sp<RenderNode>>& nodes, bool opaque,
-                               const Rect& contentDrawBounds, sk_sp<SkSurface> surface) {
+                               const Rect& contentDrawBounds, sk_sp<SkSurface> surface,
+                               const SkMatrix& preTransform) {
+    bool previousSkpEnabled = Properties::skpCaptureEnabled;
+    if (mPictureCapturedCallback) {
+        Properties::skpCaptureEnabled = true;
+    }
+
     renderVectorDrawableCache();
 
     // draw all layers up front
@@ -322,16 +338,18 @@
     std::unique_ptr<SkPictureRecorder> recorder;
     SkCanvas* canvas = tryCapture(surface.get());
 
-    renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas);
+    renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas, preTransform);
 
     endCapture(surface.get());
 
     if (CC_UNLIKELY(Properties::debugOverdraw)) {
-        renderOverdraw(layers, clip, nodes, contentDrawBounds, surface);
+        renderOverdraw(layers, clip, nodes, contentDrawBounds, surface, preTransform);
     }
 
     ATRACE_NAME("flush commands");
     surface->getCanvas()->flush();
+
+    Properties::skpCaptureEnabled = previousSkpEnabled;
 }
 
 namespace {
@@ -343,9 +361,11 @@
 
 void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
                                    const std::vector<sp<RenderNode>>& nodes, bool opaque,
-                                   const Rect& contentDrawBounds, SkCanvas* canvas) {
+                                   const Rect& contentDrawBounds, SkCanvas* canvas,
+                                   const SkMatrix& preTransform) {
     SkAutoCanvasRestore saver(canvas, true);
-    canvas->androidFramework_setDeviceClipRestriction(clip.roundOut());
+    canvas->androidFramework_setDeviceClipRestriction(preTransform.mapRect(clip).roundOut());
+    canvas->concat(preTransform);
 
     // STOPSHIP: Revert, temporary workaround to clear always F16 frame buffer for b/74976293
     if (!opaque || getSurfaceColorType() == kRGBA_F16_SkColorType) {
@@ -485,7 +505,8 @@
 
 void SkiaPipeline::renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
                                   const std::vector<sp<RenderNode>>& nodes,
-                                  const Rect& contentDrawBounds, sk_sp<SkSurface> surface) {
+                                  const Rect& contentDrawBounds, sk_sp<SkSurface> surface,
+                                  const SkMatrix& preTransform) {
     // Set up the overdraw canvas.
     SkImageInfo offscreenInfo = SkImageInfo::MakeA8(surface->width(), surface->height());
     sk_sp<SkSurface> offscreen = surface->makeSurface(offscreenInfo);
@@ -495,7 +516,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, contentDrawBounds, &overdrawCanvas);
+    renderFrameImpl(layers, clip, nodes, true, contentDrawBounds, &overdrawCanvas, preTransform);
     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 ff87313..e9957df 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -48,12 +48,13 @@
     bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
                              ErrorHandler* errorHandler) override;
 
-    SkColorType getSurfaceColorType() const { return mSurfaceColorType; }
+    SkColorType getSurfaceColorType() const override { return mSurfaceColorType; }
     sk_sp<SkColorSpace> getSurfaceColorSpace() override { return mSurfaceColorSpace; }
 
     void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
                      const std::vector<sp<RenderNode>>& nodes, bool opaque,
-                     const Rect& contentDrawBounds, sk_sp<SkSurface> surface);
+                     const Rect& contentDrawBounds, sk_sp<SkSurface> surface,
+                     const SkMatrix& preTransform);
 
     std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; }
 
@@ -104,6 +105,11 @@
         mLightCenter = lightGeometry.center;
     }
 
+    void setPictureCapturedCallback(
+            const std::function<void(sk_sp<SkPicture>&&)>& callback) override {
+        mPictureCapturedCallback = callback;
+    }
+
 protected:
     void dumpResourceCacheUsage() const;
     void setSurfaceColorProperties(renderthread::ColorMode colorMode);
@@ -116,7 +122,8 @@
 private:
     void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
                          const std::vector<sp<RenderNode>>& nodes, bool opaque,
-                         const Rect& contentDrawBounds, SkCanvas* canvas);
+                         const Rect& contentDrawBounds, SkCanvas* canvas,
+                         const SkMatrix& preTransform);
 
     /**
      *  Debugging feature.  Draws a semi-transparent overlay on each pixel, indicating
@@ -124,7 +131,7 @@
      */
     void renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
                         const std::vector<sp<RenderNode>>& nodes, const Rect& contentDrawBounds,
-                        sk_sp<SkSurface>);
+                        sk_sp<SkSurface> surface, const SkMatrix& preTransform);
 
     /**
      *  Render mVectorDrawables into offscreen buffers.
@@ -161,6 +168,8 @@
      *  parallel tryCapture calls (not really needed).
      */
     std::unique_ptr<SkPictureRecorder> mRecorder;
+    std::unique_ptr<SkNWayCanvas> mNwayCanvas;
+    std::function<void(sk_sp<SkPicture>&&)> mPictureCapturedCallback;
 
     static float mLightRadius;
     static uint8_t mAmbientShadowAlpha;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 6eefed9..d54275f 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -125,8 +125,6 @@
                                              uirenderer::GlFunctorLifecycleListener* listener) {
     FunctorDrawable* functorDrawable;
     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
-        // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the
-        // interop is disabled/moved.
         functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(
                 functor, listener, asSkCanvas());
     } else {
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 1d3a244..53495a7 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -23,6 +23,7 @@
 #include "VkInteropFunctorDrawable.h"
 #include "renderstate/RenderState.h"
 #include "renderthread/Frame.h"
+#include "ShaderCache.h"
 
 #include <SkSurface.h>
 #include <SkTypes.h>
@@ -57,7 +58,8 @@
         return Frame(-1, -1, 0);
     }
 
-    Frame frame(backBuffer->width(), backBuffer->height(), mVkManager.getAge(mVkSurface));
+    Frame frame(mVkSurface->windowWidth(), mVkSurface->windowHeight(),
+                mVkManager.getAge(mVkSurface));
     return frame;
 }
 
@@ -72,7 +74,9 @@
         return false;
     }
     SkiaPipeline::updateLighting(lightGeometry, lightInfo);
-    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer);
+    renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
+            backBuffer, mVkSurface->preTransform());
+    ShaderCache::get().onVkFrameFlushed(mRenderThread.getGrContext());
     layerUpdateQueue->clear();
 
     // Draw visual debugging features
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 53ffc44..9343076 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -35,6 +35,7 @@
               const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
               const std::vector<sp<RenderNode> >& renderNodes,
               FrameInfoVisualizer* profiler) override;
+    GrSurfaceOrigin getSurfaceOrigin() override { return kTopLeft_GrSurfaceOrigin; }
     bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
                      FrameInfo* currentFrameInfo, bool* requireSwap) override;
     DeferredLayerUpdater* createTextureLayer() override;
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index 156f74a..2f8d381 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -17,6 +17,8 @@
 #include "VkFunctorDrawable.h"
 #include <private/hwui/DrawVkInfo.h>
 
+#include "renderthread/VulkanManager.h"
+#include "renderthread/RenderThread.h"
 #include <GrBackendDrawableInfo.h>
 #include <SkImage.h>
 #include <utils/Color.h>
@@ -31,34 +33,58 @@
 namespace uirenderer {
 namespace skiapipeline {
 
-VkFunctorDrawHandler::VkFunctorDrawHandler(Functor* functor) : INHERITED(), mFunctor(functor) {}
+VkFunctorDrawHandler::VkFunctorDrawHandler(sp<WebViewFunctor::Handle> functor_handle,
+                                           const SkMatrix& matrix, const SkIRect& clip,
+                                           const SkImageInfo& image_info)
+        : INHERITED()
+        , mFunctorHandle(functor_handle)
+        , mMatrix(matrix)
+        , mClip(clip)
+        , mImageInfo(image_info) {}
 
 VkFunctorDrawHandler::~VkFunctorDrawHandler() {
-    // TODO(cblume) Fill in the DrawVkInfo parameters.
-    (*mFunctor)(DrawVkInfo::kModePostComposite, nullptr);
+    mFunctorHandle->postDrawVk();
 }
 
 void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) {
     ATRACE_CALL();
+    if (!renderthread::RenderThread::isCurrent())
+        LOG_ALWAYS_FATAL("VkFunctorDrawHandler::draw not called on render thread");
 
     GrVkDrawableInfo vulkan_info;
     if (!info.getVkDrawableInfo(&vulkan_info)) {
         return;
     }
+    renderthread::VulkanManager& vk_manager =
+            renderthread::RenderThread::getInstance().vulkanManager();
+    mFunctorHandle->initVk(vk_manager.getVkFunctorInitParams());
 
-    DrawVkInfo draw_vk_info;
-    // TODO(cblume) Fill in the rest of the parameters and test the actual call.
-    draw_vk_info.isLayer = true;
+    SkMatrix44 mat4(mMatrix);
+    VkFunctorDrawParams params{
+      .width = mImageInfo.width(),
+      .height = mImageInfo.height(),
+      .is_layer = false,  // TODO(boliu): Populate is_layer.
+      .color_space_ptr = mImageInfo.colorSpace(),
+      .clip_left = mClip.fLeft,
+      .clip_top = mClip.fTop,
+      .clip_right = mClip.fRight,
+      .clip_bottom = mClip.fBottom,
+    };
+    mat4.asColMajorf(&params.transform[0]);
+    params.secondary_command_buffer = vulkan_info.fSecondaryCommandBuffer;
+    params.color_attachment_index = vulkan_info.fColorAttachmentIndex;
+    params.compatible_render_pass = vulkan_info.fCompatibleRenderPass;
+    params.format = vulkan_info.fFormat;
 
-    (*mFunctor)(DrawVkInfo::kModeComposite, &draw_vk_info);
+    mFunctorHandle->drawVk(params);
+
+    vulkan_info.fDrawBounds->offset.x = mClip.fLeft;
+    vulkan_info.fDrawBounds->offset.y = mClip.fTop;
+    vulkan_info.fDrawBounds->extent.width = mClip.fRight - mClip.fLeft;
+    vulkan_info.fDrawBounds->extent.height = mClip.fBottom - mClip.fTop;
 }
 
 VkFunctorDrawable::~VkFunctorDrawable() {
-    if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) {
-        if (lp->listener) {
-            lp->listener->onGlFunctorReleased(lp->functor);
-        }
-    }
 }
 
 void VkFunctorDrawable::onDraw(SkCanvas* /*canvas*/) {
@@ -67,16 +93,17 @@
 }
 
 std::unique_ptr<FunctorDrawable::GpuDrawHandler> VkFunctorDrawable::onSnapGpuDrawHandler(
-        GrBackendApi backendApi, const SkMatrix& matrix) {
+        GrBackendApi backendApi, const SkMatrix& matrix, const SkIRect& clip,
+        const SkImageInfo& image_info) {
     if (backendApi != GrBackendApi::kVulkan) {
         return nullptr;
     }
     std::unique_ptr<VkFunctorDrawHandler> draw;
     if (mAnyFunctor.index() == 0) {
-        LOG_ALWAYS_FATAL("Not implemented");
-        return nullptr;
+        return std::make_unique<VkFunctorDrawHandler>(std::get<0>(mAnyFunctor).handle, matrix, clip,
+                                                      image_info);
     } else {
-        return std::make_unique<VkFunctorDrawHandler>(std::get<1>(mAnyFunctor).functor);
+        LOG_ALWAYS_FATAL("Not implemented");
     }
 }
 
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
index d6fefc1..1a53c8f 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
@@ -32,15 +32,18 @@
  */
 class VkFunctorDrawHandler : public FunctorDrawable::GpuDrawHandler {
 public:
-    explicit VkFunctorDrawHandler(Functor* functor);
+    VkFunctorDrawHandler(sp<WebViewFunctor::Handle> functor_handle, const SkMatrix& matrix,
+                         const SkIRect& clip, const SkImageInfo& image_info);
     ~VkFunctorDrawHandler() override;
 
     void draw(const GrBackendDrawableInfo& info) override;
 
 private:
     typedef GpuDrawHandler INHERITED;
-
-    Functor* mFunctor;
+    sp<WebViewFunctor::Handle> mFunctorHandle;
+    const SkMatrix mMatrix;
+    const SkIRect mClip;
+    const SkImageInfo mImageInfo;
 };
 
 /**
@@ -57,7 +60,8 @@
     // SkDrawable functions:
     void onDraw(SkCanvas* canvas) override;
     std::unique_ptr<FunctorDrawable::GpuDrawHandler> onSnapGpuDrawHandler(
-            GrBackendApi backendApi, const SkMatrix& matrix) override;
+            GrBackendApi backendApi, const SkMatrix& matrix, const SkIRect& clip,
+            const SkImageInfo& image_info) override;
 };
 
 }  // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index a5faae7..c3563db 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -36,8 +36,6 @@
 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.
@@ -47,32 +45,20 @@
 
 private:
     void beginDraw() {
-        std::lock_guard _lock{sLock};
-
-        if (!sGLDrawThread) {
-            sGLDrawThread = new ThreadBase{};
-        }
-
-        if (!sGLDrawThread->isRunning()) {
-            sGLDrawThread->start("GLFunctorThread");
-        }
-
         if (!sEglManager.hasEglContext()) {
-            sGLDrawThread->queue().runSync([]() { sEglManager.initialize(); });
+            sEglManager.initialize();
         }
     }
 };
 
 void VkInteropFunctorDrawable::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);
-    });
+    EGLDisplay display = sEglManager.eglDisplay();
+    DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
+    if (display != EGL_NO_DISPLAY) {
+        mode = DrawGlInfo::kModeProcess;
+    }
+    (*functor)(mode, nullptr);
 }
 
 #define FENCE_TIMEOUT 2000000000
@@ -113,7 +99,7 @@
     // 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",
@@ -125,7 +111,7 @@
         if (autoImage.image == EGL_NO_IMAGE_KHR) {
             ALOGW("Could not create EGL image, err =%s",
                   uirenderer::renderthread::EglManager::eglErrorString());
-            return false;
+            return;
         }
 
         AutoSkiaGlTexture glTexture;
@@ -156,7 +142,7 @@
         if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
             ALOGE("Failed framebuffer check for created target buffer: %s",
                   GLUtils::getGLFramebufferError());
-            return false;
+            return;
         }
 
         glDisable(GL_STENCIL_TEST);
@@ -183,11 +169,6 @@
         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;
@@ -208,15 +189,14 @@
     if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) {
         if (lp->listener) {
             ScopedDrawRequest _drawRequest{};
-            sGLDrawThread->queue().runSync(
-                    [&]() { lp->listener->onGlFunctorReleased(lp->functor); });
+            lp->listener->onGlFunctorReleased(lp->functor);
         }
     }
 }
 
 void VkInteropFunctorDrawable::syncFunctor(const WebViewSyncData& data) const {
     ScopedDrawRequest _drawRequest{};
-    sGLDrawThread->queue().runSync([&]() { FunctorDrawable::syncFunctor(data); });
+    FunctorDrawable::syncFunctor(data);
 }
 
 }  // namespace skiapipeline
diff --git a/libs/hwui/private/hwui/DrawVkInfo.h b/libs/hwui/private/hwui/DrawVkInfo.h
index 019950f..abc4dbf 100644
--- a/libs/hwui/private/hwui/DrawVkInfo.h
+++ b/libs/hwui/private/hwui/DrawVkInfo.h
@@ -17,89 +17,61 @@
 #ifndef ANDROID_HWUI_DRAW_VK_INFO_H
 #define ANDROID_HWUI_DRAW_VK_INFO_H
 
+#include <SkColorSpace.h>
 #include <vulkan/vulkan.h>
 
 namespace android {
 namespace uirenderer {
 
-/**
- * Structure used by VulkanRenderer::callDrawVKFunction() to pass and receive data from Vulkan
- * functors.
- */
-struct DrawVkInfo {
-    // Input: current width/height of destination surface
-    int width;
-    int height;
+struct VkFunctorInitParams {
+  VkInstance instance;
+  VkPhysicalDevice physical_device;
+  VkDevice device;
+  VkQueue queue;
+  uint32_t graphics_queue_index;
+  uint32_t instance_version;
+  const char* const* enabled_instance_extension_names;
+  uint32_t enabled_instance_extension_names_length;
+  const char* const* enabled_device_extension_names;
+  uint32_t enabled_device_extension_names_length;
+  const VkPhysicalDeviceFeatures2* device_features_2;
+};
 
-    // Input: is the render target an FBO
-    bool isLayer;
+struct VkFunctorDrawParams {
+  // Input: current width/height of destination surface.
+  int width;
+  int height;
 
-    // Input: current transform matrix, in OpenGL format
-    float transform[16];
+  // Input: is the render target a FBO
+  bool is_layer;
 
-    // Input: WebView should do its main compositing draws into this. It cannot do anything that
-    // would require stopping the render pass.
-    VkCommandBuffer secondaryCommandBuffer;
+  // Input: current transform matrix
+  float transform[16];
 
-    // Input: The main color attachment index where secondaryCommandBuffer will eventually be
-    // submitted.
-    uint32_t colorAttachmentIndex;
+  // Input WebView should do its main compositing draws into this. It cannot do
+  // anything that would require stopping the render pass.
+  VkCommandBuffer secondary_command_buffer;
 
-    // Input: A render pass which will be compatible to the one which the secondaryCommandBuffer
-    // will be submitted into.
-    VkRenderPass compatibleRenderPass;
+  // Input: The main color attachment index where secondary_command_buffer will
+  // eventually be submitted.
+  uint32_t color_attachment_index;
 
-    // Input: Format of the destination surface.
-    VkFormat format;
+  // Input: A render pass which will be compatible to the one which the
+  // secondary_command_buffer will be submitted into.
+  VkRenderPass compatible_render_pass;
 
-    // Input: Color space transfer params
-    float G;
-    float A;
-    float B;
-    float C;
-    float D;
-    float E;
-    float F;
+  // Input: Format of the destination surface.
+  VkFormat format;
 
-    // Input: Color space transformation from linear RGB to D50-adapted XYZ
-    float matrix[9];
+  // Input: Color space.
+  const SkColorSpace* color_space_ptr;
 
-    // Input: current clip rect
-    int clipLeft;
-    int clipTop;
-    int clipRight;
-    int clipBottom;
-
-    /**
-     * Values used as the "what" parameter of the functor.
-     */
-    enum Mode {
-        // Called once at WebView start
-        kModeInit,
-        // Called when things need to be re-created
-        kModeReInit,
-        // Notifies the app that the composite functor will be called soon. This allows WebView to
-        // begin work early.
-        kModePreComposite,
-        // Do the actual composite work
-        kModeComposite,
-        // This allows WebView to begin using the previously submitted objects in future work.
-        kModePostComposite,
-        // Invoked every time the UI thread pushes over a frame to the render thread and the owning
-        // view has a dirty display list*. This is a signal to sync any data that needs to be
-        // shared between the UI thread and the render thread. During this time the UI thread is
-        // blocked.
-        kModeSync
-    };
-
-    /**
-     * Values used by Vulkan functors to tell the framework what to do next.
-     */
-    enum Status {
-        // The functor is done
-        kStatusDone = 0x0,
-    };
-};  // struct DrawVkInfo
+  // Input: current clip rect
+  int clip_left;
+  int clip_top;
+  int clip_right;
+  int clip_bottom;
+};
 
 }  // namespace uirenderer
 }  // namespace android
diff --git a/libs/hwui/private/hwui/WebViewFunctor.h b/libs/hwui/private/hwui/WebViewFunctor.h
index e5346aa..96da947 100644
--- a/libs/hwui/private/hwui/WebViewFunctor.h
+++ b/libs/hwui/private/hwui/WebViewFunctor.h
@@ -17,7 +17,9 @@
 #ifndef FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H
 #define FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H
 
+#include <cutils/compiler.h>
 #include <private/hwui/DrawGlInfo.h>
+#include <private/hwui/DrawVkInfo.h>
 
 namespace android::uirenderer {
 
@@ -27,7 +29,7 @@
 };
 
 // Static for the lifetime of the process
-RenderMode WebViewFunctor_queryPlatformRenderMode();
+ANDROID_API RenderMode WebViewFunctor_queryPlatformRenderMode();
 
 struct WebViewSyncData {
     bool applyForceDark;
@@ -35,34 +37,28 @@
 
 struct WebViewFunctorCallbacks {
     // kModeSync, called on RenderThread
-    void (*onSync)(int functor, const WebViewSyncData& syncData);
+    void (*onSync)(int functor, void* data, const WebViewSyncData& syncData);
 
     // Called when either the context is destroyed _or_ when the functor's last reference goes
     // away. Will always be called with an active context and always on renderthread.
-    void (*onContextDestroyed)(int functor);
+    void (*onContextDestroyed)(int functor, void* data);
 
     // Called when the last reference to the handle goes away and the handle is considered
     // irrevocably destroyed. Will always be proceeded by a call to onContextDestroyed if
     // this functor had ever been drawn.
-    void (*onDestroyed)(int functor);
+    void (*onDestroyed)(int functor, void* data);
 
     union {
         struct {
             // Called on RenderThread. initialize is guaranteed to happen before this call
-            void (*draw)(int functor, const DrawGlInfo& params);
+            void (*draw)(int functor, void* data, const DrawGlInfo& params);
         } gles;
-        // TODO: VK support. The current DrawVkInfo is monolithic and needs to be split up for
-        // what params are valid on what callbacks
         struct {
             // Called either the first time the functor is used or the first time it's used after
             // a call to onContextDestroyed.
-            // void (*initialize)(int functor, const InitParams& params);
-            // void (*frameStart)(int functor, /* todo: what params are actually needed for this to
-            // be useful? Is this useful? */)
-            // void (*draw)(int functor, const CompositeParams& params /* todo: rename - composite
-            // almost always means something else, and we aren't compositing */);
-            // void (*frameEnd)(int functor, const PostCompositeParams& params /* todo: same as
-            // CompositeParams - rename */);
+            void (*initialize)(int functor, void* data, const VkFunctorInitParams& params);
+            void (*draw)(int functor, void* data, const VkFunctorDrawParams& params);
+            void (*postDraw)(int functor, void*);
         } vk;
     };
 };
@@ -70,12 +66,12 @@
 // Creates a new WebViewFunctor from the given prototype. The prototype is copied after
 // this function returns. Caller retains full ownership of it.
 // Returns -1 if the creation fails (such as an unsupported functorMode + platform mode combination)
-int WebViewFunctor_create(const WebViewFunctorCallbacks& prototype, RenderMode functorMode);
+ANDROID_API int WebViewFunctor_create(void* data, const WebViewFunctorCallbacks& prototype, RenderMode functorMode);
 
 // May be called on any thread to signal that the functor should be destroyed.
 // The functor will receive an onDestroyed when the last usage of it is released,
 // and it should be considered alive & active until that point.
-void WebViewFunctor_release(int functor);
+ANDROID_API void WebViewFunctor_release(int functor);
 
 }  // namespace android::uirenderer
 
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 7acc44c..6c04232 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -30,6 +30,7 @@
 #include <gui/Surface.h>
 #include <math.h>
 #include <set>
+#include <SkMathPriv.h>
 
 namespace android {
 namespace uirenderer {
@@ -42,11 +43,6 @@
 #define SURFACE_SIZE_MULTIPLIER (12.0f * 4.0f)
 #define BACKGROUND_RETENTION_PERCENTAGE (0.5f)
 
-// for super large fonts we will draw them as paths so no need to keep linearly
-// increasing the font cache size.
-#define FONT_CACHE_MIN_MB (0.5f)
-#define FONT_CACHE_MAX_MB (4.0f)
-
 CacheManager::CacheManager(const DisplayInfo& display) : mMaxSurfaceArea(display.w * display.h) {
     mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
             mMaxSurfaceArea / 2,
@@ -106,25 +102,10 @@
 void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity, ssize_t size) {
     contextOptions->fAllowPathMaskCaching = true;
 
-    float screenMP = mMaxSurfaceArea / 1024.0f / 1024.0f;
-    float fontCacheMB = 0;
-    float decimalVal = std::modf(screenMP, &fontCacheMB);
-
-    // This is a basic heuristic to size the cache to a multiple of 512 KB
-    if (decimalVal > 0.8f) {
-        fontCacheMB += 1.0f;
-    } else if (decimalVal > 0.5f) {
-        fontCacheMB += 0.5f;
-    }
-
-    // set limits on min/max size of the cache
-    fontCacheMB = std::max(FONT_CACHE_MIN_MB, std::min(FONT_CACHE_MAX_MB, fontCacheMB));
-
-    // We must currently set the size of the text cache based on the size of the
-    // display even though we like to  be dynamicallysizing it to the size of the window.
-    // Skia's implementation doesn't provide a mechanism to resize the font cache due to
-    // the potential cost of recreating the glyphs.
-    contextOptions->fGlyphCacheTextureMaximumBytes = fontCacheMB * 1024 * 1024;
+    // This sets the maximum size for a single texture atlas in the GPU font cache.  If necessary,
+    // the cache can allocate additional textures that are counted against the total cache limits
+    // provided to Skia.
+    contextOptions->fGlyphCacheTextureMaximumBytes = GrNextSizePow2(mMaxSurfaceArea);
 
     if (mTaskManager.canRunTasks()) {
         if (!mTaskProcessor.get()) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 9e7abf4..db97763 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -184,6 +184,10 @@
         mFrameCompleteCallbacks.push_back(std::move(func));
     }
 
+    void setPictureCapturedCallback(const std::function<void(sk_sp<SkPicture>&&)>& callback) {
+        mRenderPipeline->setPictureCapturedCallback(callback);
+    }
+
     void setForceDark(bool enable) {
         mUseForceDark = enable;
     }
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 56eedff..8cd97ed 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -93,7 +93,9 @@
         , mHasWideColorGamutSupport(false) {}
 
 EglManager::~EglManager() {
-    destroy();
+    if (hasEglContext()) {
+        ALOGW("~EglManager() leaked an EGL context");
+    }
 }
 
 void EglManager::initialize() {
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 42e17b273..2cfc8df3 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -59,15 +59,15 @@
     virtual MakeCurrentResult makeCurrent() = 0;
     virtual Frame getFrame() = 0;
     virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
-                      const LightGeometry& lightGeometry,
-                      LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
-                      bool opaque, const LightInfo& lightInfo,
+                      const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
+                      const Rect& contentDrawBounds, 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,
                              FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
     virtual DeferredLayerUpdater* createTextureLayer() = 0;
-    virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0;
+    virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior,
+                            ColorMode colorMode) = 0;
     virtual void onStop() = 0;
     virtual bool isSurfaceReady() = 0;
     virtual bool isContextReady() = 0;
@@ -84,6 +84,9 @@
     virtual void onPrepareTree() = 0;
     virtual SkColorType getSurfaceColorType() const = 0;
     virtual sk_sp<SkColorSpace> getSurfaceColorSpace() = 0;
+    virtual GrSurfaceOrigin getSurfaceOrigin() = 0;
+    virtual void setPictureCapturedCallback(
+            const std::function<void(sk_sp<SkPicture>&&)>& callback) = 0;
 
     virtual ~IRenderPipeline() {}
 };
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index aa6af23..720c603 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -21,6 +21,7 @@
 #include "Properties.h"
 #include "Readback.h"
 #include "Rect.h"
+#include "WebViewFunctorManager.h"
 #include "pipeline/skia/SkiaOpenGLPipeline.h"
 #include "pipeline/skia/VectorDrawableAtlas.h"
 #include "renderstate/RenderState.h"
@@ -30,7 +31,6 @@
 #include "renderthread/RenderThread.h"
 #include "utils/Macros.h"
 #include "utils/TimeUtils.h"
-#include "WebViewFunctorManager.h"
 
 #include <ui/GraphicBuffer.h>
 
@@ -147,9 +147,7 @@
 void RenderProxy::destroyFunctor(int functor) {
     ATRACE_CALL();
     RenderThread& thread = RenderThread::getInstance();
-    thread.queue().post([=]() {
-        WebViewFunctorManager::instance().destroyFunctor(functor);
-    });
+    thread.queue().post([=]() { WebViewFunctorManager::instance().destroyFunctor(functor); });
 }
 
 DeferredLayerUpdater* RenderProxy::createTextureLayer() {
@@ -164,9 +162,9 @@
 
 bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) {
     auto& thread = RenderThread::getInstance();
-    return thread.queue().runSync(
-            [&]() -> bool { return thread.readback().copyLayerInto(layer, &bitmap)
-                                   == CopyResult::Success; });
+    return thread.queue().runSync([&]() -> bool {
+        return thread.readback().copyLayerInto(layer, &bitmap) == CopyResult::Success;
+    });
 }
 
 void RenderProxy::pushLayerUpdate(DeferredLayerUpdater* layer) {
@@ -204,9 +202,8 @@
 }
 
 int RenderProxy::maxTextureSize() {
-    static int maxTextureSize = RenderThread::getInstance().queue().runSync([]() {
-        return DeviceInfo::get()->maxTextureSize();
-    });
+    static int maxTextureSize = RenderThread::getInstance().queue().runSync(
+            []() { return DeviceInfo::get()->maxTextureSize(); });
     return maxTextureSize;
 }
 
@@ -244,8 +241,10 @@
 }
 
 void RenderProxy::dumpGraphicsMemory(int fd) {
-    auto& thread = RenderThread::getInstance();
-    thread.queue().runSync([&]() { thread.dumpGraphicsMemory(fd); });
+    if (RenderThread::hasInstance()) {
+        auto& thread = RenderThread::getInstance();
+        thread.queue().runSync([&]() { thread.dumpGraphicsMemory(fd); });
+    }
 }
 
 void RenderProxy::setProcessStatsBuffer(int fd) {
@@ -281,6 +280,12 @@
     mDrawFrameTask.setContentDrawBounds(left, top, right, bottom);
 }
 
+void RenderProxy::setPictureCapturedCallback(
+        const std::function<void(sk_sp<SkPicture>&&)>& callback) {
+    mRenderThread.queue().post(
+            [ this, cb = callback ]() { mContext->setPictureCapturedCallback(cb); });
+}
+
 void RenderProxy::setFrameCallback(std::function<void(int64_t)>&& callback) {
     mDrawFrameTask.setFrameCallback(std::move(callback));
 }
@@ -302,9 +307,7 @@
 }
 
 void RenderProxy::setForceDark(bool enable) {
-    mRenderThread.queue().post([this, enable]() {
-        mContext->setForceDark(enable);
-    });
+    mRenderThread.queue().post([this, enable]() { mContext->setForceDark(enable); });
 }
 
 int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
@@ -348,9 +351,8 @@
         // TODO: fix everything that hits this. We should never be triggering a readback ourselves.
         return (int)thread.readback().copyHWBitmapInto(hwBitmap, bitmap);
     } else {
-        return thread.queue().runSync([&]() -> int {
-            return (int)thread.readback().copyHWBitmapInto(hwBitmap, bitmap);
-        });
+        return thread.queue().runSync(
+                [&]() -> int { return (int)thread.readback().copyHWBitmapInto(hwBitmap, bitmap); });
     }
 }
 
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 9dc9181..6e1bfd7 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -114,6 +114,8 @@
     ANDROID_API void removeRenderNode(RenderNode* node);
     ANDROID_API void drawRenderNode(RenderNode* node);
     ANDROID_API void setContentDrawBounds(int left, int top, int right, int bottom);
+    ANDROID_API void setPictureCapturedCallback(
+            const std::function<void(sk_sp<SkPicture>&&)>& callback);
     ANDROID_API void setFrameCallback(std::function<void(int64_t)>&& callback);
     ANDROID_API void setFrameCompleteCallback(std::function<void(int64_t)>&& callback);
 
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index c06fadd..8bef359 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -171,6 +171,9 @@
     mRenderState = new RenderState(*this);
     mVkManager = new VulkanManager(*this);
     mCacheManager = new CacheManager(mDisplayInfo);
+    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+        mVkManager->initialize();
+    }
 }
 
 void RenderThread::requireGlContext() {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 12666b3..1ef83fb 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -47,6 +47,10 @@
 class RenderState;
 class TestUtils;
 
+namespace skiapipeline {
+class VkFunctorDrawHandler;
+}
+
 namespace renderthread {
 
 class CanvasContext;
@@ -123,6 +127,8 @@
     friend class RenderProxy;
     friend class DummyVsyncSource;
     friend class android::uirenderer::TestUtils;
+    friend class android::uirenderer::WebViewFunctor;
+    friend class android::uirenderer::skiapipeline::VkFunctorDrawHandler;
 
     RenderThread();
     virtual ~RenderThread();
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index aa7a141..5c6cb9a 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -34,6 +34,23 @@
 namespace uirenderer {
 namespace renderthread {
 
+static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& features) {
+    // All Vulkan structs that could be part of the features chain will start with the
+    // structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
+    // so we can get access to the pNext for the next struct.
+    struct CommonVulkanHeader {
+        VkStructureType sType;
+        void*           pNext;
+    };
+
+    void* pNext = features.pNext;
+    while (pNext) {
+        void* current = pNext;
+        pNext = static_cast<CommonVulkanHeader*>(current)->pNext;
+        free(current);
+    }
+}
+
 #define GET_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vk" #F)
 #define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
 #define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
@@ -66,6 +83,11 @@
     mDevice = VK_NULL_HANDLE;
     mPhysicalDevice = VK_NULL_HANDLE;
     mInstance = VK_NULL_HANDLE;
+    mInstanceVersion = 0u;
+    mInstanceExtensions.clear();
+    mDeviceExtensions.clear();
+    free_features_extensions_structs(mPhysicalDeviceFeatures2);
+    mPhysicalDeviceFeatures2 = {};
 }
 
 bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFeatures2& features) {
@@ -81,7 +103,6 @@
         VK_MAKE_VERSION(1, 1, 0),           // apiVersion
     };
 
-    std::vector<const char*> instanceExtensions;
     {
         GET_PROC(EnumerateInstanceExtensionProperties);
 
@@ -99,7 +120,7 @@
         bool hasKHRSurfaceExtension = false;
         bool hasKHRAndroidSurfaceExtension = false;
         for (uint32_t i = 0; i < extensionCount; ++i) {
-            instanceExtensions.push_back(extensions[i].extensionName);
+            mInstanceExtensions.push_back(extensions[i].extensionName);
             if (!strcmp(extensions[i].extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) {
                 hasKHRSurfaceExtension = true;
             }
@@ -120,8 +141,8 @@
         &app_info,                                 // pApplicationInfo
         0,                                         // enabledLayerNameCount
         nullptr,                                   // ppEnabledLayerNames
-        (uint32_t) instanceExtensions.size(),      // enabledExtensionNameCount
-        instanceExtensions.data(),                 // ppEnabledExtensionNames
+        (uint32_t) mInstanceExtensions.size(),     // enabledExtensionNameCount
+        mInstanceExtensions.data(),                // ppEnabledExtensionNames
     };
 
     GET_PROC(CreateInstance);
@@ -201,7 +222,6 @@
     // presentation with any native window. So just use the first one.
     mPresentQueueIndex = 0;
 
-    std::vector<const char*> deviceExtensions;
     {
         uint32_t extensionCount = 0;
         err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount,
@@ -220,7 +240,7 @@
         }
         bool hasKHRSwapchainExtension = false;
         for (uint32_t i = 0; i < extensionCount; ++i) {
-            deviceExtensions.push_back(extensions[i].extensionName);
+            mDeviceExtensions.push_back(extensions[i].extensionName);
             if (!strcmp(extensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
                 hasKHRSwapchainExtension = true;
             }
@@ -237,8 +257,8 @@
         }
         return vkGetInstanceProcAddr(instance, proc_name);
     };
-    grExtensions.init(getProc, mInstance, mPhysicalDevice, instanceExtensions.size(),
-            instanceExtensions.data(), deviceExtensions.size(), deviceExtensions.data());
+    grExtensions.init(getProc, mInstance, mPhysicalDevice, mInstanceExtensions.size(),
+            mInstanceExtensions.data(), mDeviceExtensions.size(), mDeviceExtensions.data());
 
     if (!grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
         this->destroy();
@@ -308,8 +328,8 @@
         queueInfo,                               // pQueueCreateInfos
         0,                                       // layerCount
         nullptr,                                 // ppEnabledLayerNames
-        (uint32_t) deviceExtensions.size(),      // extensionCount
-        deviceExtensions.data(),                 // ppEnabledExtensionNames
+        (uint32_t) mDeviceExtensions.size(),     // extensionCount
+        mDeviceExtensions.data(),                // ppEnabledExtensionNames
         nullptr,                                 // ppEnabledFeatures
     };
 
@@ -351,36 +371,17 @@
     return true;
 }
 
-static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& features) {
-    // All Vulkan structs that could be part of the features chain will start with the
-    // structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
-    // so we can get access to the pNext for the next struct.
-    struct CommonVulkanHeader {
-        VkStructureType sType;
-        void*           pNext;
-    };
-
-    void* pNext = features.pNext;
-    while (pNext) {
-        void* current = pNext;
-        pNext = static_cast<CommonVulkanHeader*>(current)->pNext;
-        free(current);
-    }
-}
-
 void VulkanManager::initialize() {
     if (mDevice != VK_NULL_HANDLE) {
         return;
     }
 
     GET_PROC(EnumerateInstanceVersion);
-    uint32_t instanceVersion = 0;
-    LOG_ALWAYS_FATAL_IF(mEnumerateInstanceVersion(&instanceVersion));
-    LOG_ALWAYS_FATAL_IF(instanceVersion < VK_MAKE_VERSION(1, 1, 0));
+    LOG_ALWAYS_FATAL_IF(mEnumerateInstanceVersion(&mInstanceVersion));
+    LOG_ALWAYS_FATAL_IF(mInstanceVersion < VK_MAKE_VERSION(1, 1, 0));
 
     GrVkExtensions extensions;
-    VkPhysicalDeviceFeatures2 features;
-    LOG_ALWAYS_FATAL_IF(!this->setupDevice(extensions, features));
+    LOG_ALWAYS_FATAL_IF(!this->setupDevice(extensions, mPhysicalDeviceFeatures2));
 
     mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
 
@@ -397,9 +398,9 @@
     backendContext.fDevice = mDevice;
     backendContext.fQueue = mGraphicsQueue;
     backendContext.fGraphicsQueueIndex = mGraphicsQueueIndex;
-    backendContext.fInstanceVersion = instanceVersion;
+    backendContext.fInstanceVersion = mInstanceVersion;
     backendContext.fVkExtensions = &extensions;
-    backendContext.fDeviceFeatures2 = &features;
+    backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
     backendContext.fGetProc = std::move(getProc);
 
     // create the command pool for the command buffers
@@ -433,13 +434,29 @@
     LOG_ALWAYS_FATAL_IF(!grContext.get());
     mRenderThread.setGrContext(grContext);
 
-    free_features_extensions_structs(features);
-
     if (Properties::enablePartialUpdates && Properties::useBufferAge) {
         mSwapBehavior = SwapBehavior::BufferAge;
     }
 }
 
+VkFunctorInitParams VulkanManager::getVkFunctorInitParams() const {
+    return VkFunctorInitParams{
+            .instance = mInstance,
+            .physical_device = mPhysicalDevice,
+            .device = mDevice,
+            .queue = mGraphicsQueue,
+            .graphics_queue_index = mGraphicsQueueIndex,
+            .instance_version = mInstanceVersion,
+            .enabled_instance_extension_names = mInstanceExtensions.data(),
+            .enabled_instance_extension_names_length =
+                    static_cast<uint32_t>(mInstanceExtensions.size()),
+            .enabled_device_extension_names = mDeviceExtensions.data(),
+            .enabled_device_extension_names_length =
+                    static_cast<uint32_t>(mDeviceExtensions.size()),
+            .device_features_2 = &mPhysicalDeviceFeatures2,
+    };
+}
+
 // Returns the next BackbufferInfo to use for the next draw. The function will make sure all
 // previous uses have finished before returning.
 VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) {
@@ -463,6 +480,32 @@
     return backbuffer;
 }
 
+static SkMatrix getPreTransformMatrix(int width, int height,
+                                      VkSurfaceTransformFlagBitsKHR transform) {
+    switch (transform) {
+        case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
+            return SkMatrix::I();
+        case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
+            return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
+        case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
+            return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
+        case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
+            return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
+        case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
+            return SkMatrix::MakeAll(-1, 0, width, 0, 1, 0, 0, 0, 1);
+        case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR:
+            return SkMatrix::MakeAll(0, -1, height, -1, 0, width, 0, 0, 1);
+        case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
+            return SkMatrix::MakeAll(1, 0, 0, 0, -1, height, 0, 0, 1);
+        case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR:
+            return SkMatrix::MakeAll(0, 1, 0, 1, 0, 0, 0, 0, 1);
+        default:
+            LOG_ALWAYS_FATAL("Unsupported pre transform of swapchain.");
+    }
+    return SkMatrix::I();
+}
+
+
 SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface** surfaceOut) {
     // Recreate VulkanSurface, if ANativeWindow has been resized.
     VulkanSurface* surface = *surfaceOut;
@@ -499,7 +542,7 @@
         // maybe use attach somehow? but need a Window
         return nullptr;
     }
-    if (VK_ERROR_OUT_OF_DATE_KHR == res) {
+    if (VK_ERROR_OUT_OF_DATE_KHR == res || VK_SUBOPTIMAL_KHR == res) {
         // tear swapchain down and try again
         if (!createSwapchain(surface)) {
             return nullptr;
@@ -578,6 +621,10 @@
     }
     backendRT.setVkImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
 
+    surface->mPreTransform = getPreTransformMatrix(surface->windowWidth(),
+                                                   surface->windowHeight(),
+                                                   surface->mTransform);
+
     surface->mBackbuffer = std::move(skSurface);
     return surface->mBackbuffer.get();
 }
@@ -732,6 +779,17 @@
         return false;
     }
 
+    if (!SkToBool(caps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)) {
+        return false;
+    }
+    VkSurfaceTransformFlagBitsKHR transform;
+    if (SkToBool(caps.supportedTransforms & caps.currentTransform) &&
+        !SkToBool(caps.currentTransform & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR)) {
+        transform = caps.currentTransform;
+    } else {
+        transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+    }
+
     VkExtent2D extent = caps.currentExtent;
     // clamp width; to handle currentExtent of -1 and  protect us from broken hints
     if (extent.width < caps.minImageExtent.width) {
@@ -743,6 +801,16 @@
         extent.height = caps.minImageExtent.height;
     }
     SkASSERT(extent.height <= caps.maxImageExtent.height);
+
+    VkExtent2D swapExtent = extent;
+    if (transform == VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR ||
+        transform == VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR ||
+        transform == VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR ||
+        transform == VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) {
+        swapExtent.width = extent.height;
+        swapExtent.height = extent.width;
+    }
+
     surface->mWindowWidth = extent.width;
     surface->mWindowHeight = extent.height;
 
@@ -758,7 +826,7 @@
                                    VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
                                    VK_IMAGE_USAGE_TRANSFER_DST_BIT;
     SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
-    SkASSERT(caps.supportedTransforms & caps.currentTransform);
+
     SkASSERT(caps.supportedCompositeAlpha &
              (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
     VkCompositeAlphaFlagBitsKHR composite_alpha =
@@ -805,7 +873,7 @@
     swapchainCreateInfo.minImageCount = imageCount;
     swapchainCreateInfo.imageFormat = surfaceFormat;
     swapchainCreateInfo.imageColorSpace = colorSpace;
-    swapchainCreateInfo.imageExtent = extent;
+    swapchainCreateInfo.imageExtent = swapExtent;
     swapchainCreateInfo.imageArrayLayers = 1;
     swapchainCreateInfo.imageUsage = usageFlags;
 
@@ -820,7 +888,7 @@
         swapchainCreateInfo.pQueueFamilyIndices = nullptr;
     }
 
-    swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+    swapchainCreateInfo.preTransform = transform;
     swapchainCreateInfo.compositeAlpha = composite_alpha;
     swapchainCreateInfo.presentMode = mode;
     swapchainCreateInfo.clipped = true;
@@ -831,6 +899,8 @@
         return false;
     }
 
+    surface->mTransform = transform;
+
     // destroy the old swapchain
     if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
         mDeviceWaitIdle(mDevice);
@@ -840,7 +910,7 @@
         mDestroySwapchainKHR(mDevice, swapchainCreateInfo.oldSwapchain, nullptr);
     }
 
-    createBuffers(surface, surfaceFormat, extent);
+    createBuffers(surface, surfaceFormat, swapExtent);
 
     // The window content is not updated (frozen) until a buffer of the window size is received.
     // This prevents temporary stretching of the window after it is resized, but before the first
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 9eb942c..b06eb82 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -45,6 +45,14 @@
 
     sk_sp<SkSurface> getBackBufferSurface() { return mBackbuffer; }
 
+    // The width and height are are the logical width and height for when submitting draws to the
+    // surface. In reality if the window is rotated the underlying VkImage may have the width and
+    // height swapped.
+    int windowWidth() const { return mWindowWidth; }
+    int windowHeight() const { return mWindowHeight; }
+
+    SkMatrix& preTransform() { return mPreTransform; }
+
 private:
     friend class VulkanManager;
     struct BackbufferInfo {
@@ -84,6 +92,8 @@
     sk_sp<SkColorSpace> mColorSpace;
     SkColorSpace::Gamut mColorGamut;
     SkColorType mColorType;
+    VkSurfaceTransformFlagBitsKHR mTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+    SkMatrix mPreTransform;
 };
 
 // This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue,
@@ -132,6 +142,9 @@
     // Creates a fence that is signaled, when all the pending Vulkan commands are flushed.
     status_t createReleaseFence(sp<Fence>& nativeFence);
 
+    // Returned pointers are owned by VulkanManager.
+    VkFunctorInitParams getVkFunctorInitParams() const;
+
 private:
     friend class RenderThread;
 
@@ -234,6 +247,12 @@
 
     VkCommandBuffer mDummyCB = VK_NULL_HANDLE;
 
+    // Variables saved to populate VkFunctorInitParams.
+    uint32_t mInstanceVersion = 0u;
+    std::vector<const char*> mInstanceExtensions;
+    std::vector<const char*> mDeviceExtensions;
+    VkPhysicalDeviceFeatures2 mPhysicalDeviceFeatures2{};
+
     enum class SwapBehavior {
         Discard,
         BufferAge,
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index 3d50d2d..8a16b20 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -48,7 +48,7 @@
 
 class FileDescriptor {
 public:
-    FileDescriptor(int fd) : mFd(fd) {}
+    explicit FileDescriptor(int fd) : mFd(fd) {}
     ~FileDescriptor() {
         if (mFd != -1) {
             close(mFd);
@@ -56,7 +56,7 @@
         }
     }
     bool valid() { return mFd != -1; }
-    operator int() { return mFd; }
+    operator int() { return mFd; } // NOLINT(google-explicit-constructor)
 
 private:
     int mFd;
@@ -64,7 +64,7 @@
 
 class FileOutputStreamLite : public io::ZeroCopyOutputStream {
 public:
-    FileOutputStreamLite(int fd) : mCopyAdapter(fd), mImpl(&mCopyAdapter) {}
+    explicit FileOutputStreamLite(int fd) : mCopyAdapter(fd), mImpl(&mCopyAdapter) {}
     virtual ~FileOutputStreamLite() {}
 
     int GetErrno() { return mCopyAdapter.mErrno; }
@@ -82,7 +82,7 @@
         int mFd;
         int mErrno = 0;
 
-        FDAdapter(int fd) : mFd(fd) {}
+        explicit FDAdapter(int fd) : mFd(fd) {}
         virtual ~FDAdapter() {}
 
         virtual bool Write(const void* buffer, int size) override {
@@ -139,6 +139,7 @@
     uint32_t file_version = *reinterpret_cast<uint32_t*>(addr);
     if (file_version != sCurrentFileVersion) {
         ALOGW("file_version mismatch! expected %d got %d", sCurrentFileVersion, file_version);
+        munmap(addr, sb.st_size);
         return false;
     }
 
@@ -150,6 +151,7 @@
         ALOGW("Parse failed on '%s' error='%s'", path.c_str(),
               output->InitializationErrorString().c_str());
     }
+    munmap(addr, sb.st_size);
     return success;
 }
 
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 7aa9b82..16a27598 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -82,7 +82,7 @@
                                  float y) {
     auto utf16 = asciiToUtf16(text);
     uint32_t length = strlen(text);
-    SkPaint glyphPaint(paint);
+    Paint glyphPaint(paint);
     glyphPaint.setTextEncoding(kGlyphID_SkTextEncoding);
     canvas->drawText(utf16.get(), length,  // text buffer
                      0, length,            // draw range
@@ -93,7 +93,7 @@
 void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint,
                                  const SkPath& path) {
     auto utf16 = asciiToUtf16(text);
-    SkPaint glyphPaint(paint);
+    Paint glyphPaint(paint);
     glyphPaint.setTextEncoding(kGlyphID_SkTextEncoding);
     canvas->drawTextOnPath(utf16.get(), strlen(text), minikin::Bidi::LTR, path, 0, 0, glyphPaint,
                            nullptr);
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 5ff8993..6a1ca5a 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -315,24 +315,24 @@
     static WebViewFunctorCallbacks createMockFunctor(RenderMode mode) {
         auto callbacks = WebViewFunctorCallbacks{
                 .onSync =
-                        [](int functor, const WebViewSyncData& data) {
+                        [](int functor, void* client_data, const WebViewSyncData& data) {
                             expectOnRenderThread();
                             sMockFunctorCounts[functor].sync++;
                         },
                 .onContextDestroyed =
-                        [](int functor) {
+                        [](int functor, void* client_data) {
                             expectOnRenderThread();
                             sMockFunctorCounts[functor].contextDestroyed++;
                         },
                 .onDestroyed =
-                        [](int functor) {
+                        [](int functor, void* client_data) {
                             expectOnRenderThread();
                             sMockFunctorCounts[functor].destroyed++;
                         },
         };
         switch (mode) {
             case RenderMode::OpenGL_ES:
-                callbacks.gles.draw = [](int functor, const DrawGlInfo& params) {
+                callbacks.gles.draw = [](int functor, void* client_data, const DrawGlInfo& params) {
                     expectOnRenderThread();
                     sMockFunctorCounts[functor].glesDraw++;
                 };
diff --git a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
index 1d3d607..5af7d43 100644
--- a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
@@ -31,7 +31,7 @@
 
 class BitmapFillrate : public TestScene {
 public:
-    BitmapFillrate(BitmapAllocationTestUtils::BitmapAllocator allocator)
+    explicit BitmapFillrate(BitmapAllocationTestUtils::BitmapAllocator allocator)
             : TestScene(), mAllocator(allocator) {}
 
     void createContent(int width, int height, Canvas& canvas) override {
@@ -70,4 +70,4 @@
 
     BitmapAllocationTestUtils::BitmapAllocator mAllocator;
     std::vector<sp<RenderNode> > mNodes;
-};
\ No newline at end of file
+};
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index ad11a1d..5107660 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -26,7 +26,7 @@
 
 class BitmapShaders : public TestScene {
 public:
-    BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator)
+    explicit BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator)
             : TestScene(), mAllocator(allocator) {}
 
     sp<RenderNode> card;
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index a64e844..286f5f1 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -48,7 +48,7 @@
 
 class TvApp : public TestScene {
 public:
-    TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
+    explicit TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
             : TestScene(), mAllocator(allocator) {}
 
     sp<RenderNode> mBg;
@@ -232,7 +232,7 @@
 
 class TvAppNoRoundedCorner : public TvApp {
 public:
-    TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
+    explicit TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
 
 private:
     virtual float roundedCornerRadius() override { return dp(0); }
@@ -240,7 +240,7 @@
 
 class TvAppColorFilter : public TvApp {
 public:
-    TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
+    explicit TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
 
 private:
     virtual bool useOverlay() override { return false; }
@@ -248,7 +248,7 @@
 
 class TvAppNoRoundedCornerColorFilter : public TvApp {
 public:
-    TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
+    explicit TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
             : TvApp(allocator) {}
 
 private:
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 524dfb0..174a140 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -19,6 +19,8 @@
 
 #include "Properties.h"
 #include "hwui/Typeface.h"
+#include "HardwareBitmapUploader.h"
+#include "renderthread/RenderProxy.h"
 
 #include <benchmark/benchmark.h>
 #include <getopt.h>
@@ -353,6 +355,9 @@
         gBenchmarkReporter->Finalize();
     }
 
+    renderthread::RenderProxy::trimMemory(100);
+    HardwareBitmapUploader::terminate();
+
     LeakChecker::checkForLeaks();
     return 0;
 }
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index f3a7648..f6178af 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -44,8 +44,8 @@
 }
 
 TEST(SkiaCanvas, colorSpaceXform) {
-    sk_sp<SkColorSpace> adobe = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
-                                                      SkColorSpace::kAdobeRGB_Gamut);
+    sk_sp<SkColorSpace> adobe = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
+                                                      SkNamedGamut::kAdobeRGB);
 
     SkImageInfo adobeInfo = SkImageInfo::Make(1, 1, kN32_SkColorType, kOpaque_SkAlphaType, adobe);
     sk_sp<Bitmap> adobeBitmap = Bitmap::allocateHeapBitmap(adobeInfo);
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index 53bf84f..1b4cf7e 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -100,8 +100,8 @@
     GLFunctorDrawable functorDrawable(&functor, nullptr, &dummyCanvas);
     skiaDL.mChildFunctors.push_back(&functorDrawable);
 
-    int functor2 = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
-                                         RenderMode::OpenGL_ES);
+    int functor2 = WebViewFunctor_create(
+            nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
     auto& counts = TestUtils::countsForFunctor(functor2);
     skiaDL.mChildFunctors.push_back(
             skiaDL.allocateDrawable<GLFunctorDrawable>(functor2, &dummyCanvas));
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 3c06dab..e86cf42 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -51,7 +51,8 @@
     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, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
+            SkMatrix::I());
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
 }
 
@@ -83,7 +84,8 @@
     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, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
+            SkMatrix::I());
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
 }
 
@@ -104,10 +106,12 @@
     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, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface,
+            SkMatrix::I());
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds, surface,
+            SkMatrix::I());
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
 }
@@ -126,7 +130,8 @@
     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, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface,
+            SkMatrix::I());
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
     ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE);
     ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorRED);
@@ -198,32 +203,38 @@
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
 
     // Single draw, should be white.
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
+            SkMatrix::I());
     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, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
+            SkMatrix::I());
     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, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
+            SkMatrix::I());
     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, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
+            SkMatrix::I());
     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, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
+            SkMatrix::I());
     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, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
+            SkMatrix::I());
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080);
 }
 
@@ -308,7 +319,8 @@
     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, contentDrawBounds, surface);
+    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, contentDrawBounds, surface,
+            SkMatrix::I());
     EXPECT_EQ(4, surface->canvas()->mDrawCounter);
 }
 
@@ -339,7 +351,43 @@
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
     sk_sp<DeferLayer<ClippedTestCanvas>> surface(new DeferLayer<ClippedTestCanvas>());
     pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
-                          SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
+                          SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface, SkMatrix::I());
+    EXPECT_EQ(1, surface->canvas()->mDrawCounter);
+}
+
+// Test renderFrame with a dirty clip and a pre-transform matrix.
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clipped_rotated) {
+    static const int CANVAS_WIDTH = 200;
+    static const int CANVAS_HEIGHT = 100;
+    static const SkMatrix rotateMatrix = SkMatrix::MakeAll(0, -1, CANVAS_HEIGHT, 1, 0, 0, 0, 0, 1);
+    static const SkRect dirty = SkRect::MakeLTRB(10, 20, 20, 40);
+    class ClippedTestCanvas : public SkCanvas {
+    public:
+        ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
+        void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override {
+            EXPECT_EQ(0, mDrawCounter++);
+            // Expect clip to be rotated.
+            EXPECT_EQ(SkRect::MakeLTRB(CANVAS_HEIGHT - dirty.fTop - dirty.height(), dirty.fLeft,
+                    CANVAS_HEIGHT - dirty.fTop, dirty.fLeft + dirty.width()),
+                    TestUtils::getClipBounds(this));
+            EXPECT_EQ(rotateMatrix, getTotalMatrix());
+        }
+        int mDrawCounter = 0;
+    };
+
+    std::vector<sp<RenderNode>> nodes;
+    nodes.push_back(TestUtils::createSkiaNode(
+            0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+                sk_sp<Bitmap> bitmap(TestUtils::createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT));
+                canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+            }));
+
+    LayerUpdateQueue layerUpdateQueue;
+    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
+    sk_sp<DeferLayer<ClippedTestCanvas>> surface(new DeferLayer<ClippedTestCanvas>());
+    pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
+                          SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface, rotateMatrix);
     EXPECT_EQ(1, surface->canvas()->mDrawCounter);
 }
 
@@ -369,7 +417,7 @@
     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
     sk_sp<DeferLayer<ClipReplaceTestCanvas>> surface(new DeferLayer<ClipReplaceTestCanvas>());
     pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
-                          SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
+                          SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface, SkMatrix::I());
     EXPECT_EQ(1, surface->canvas()->mDrawCounter);
 }
 
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index 479c462..635429d 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -44,7 +44,7 @@
     static const int CANVAS_HEIGHT = 100;
     class PropertyTestCanvas : public TestCanvasBase {
     public:
-        PropertyTestCanvas(std::function<void(const SkCanvas&)> callback)
+        explicit PropertyTestCanvas(std::function<void(const SkCanvas&)> callback)
                 : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT), mCallback(callback) {}
         void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
             EXPECT_EQ(mDrawCounter++, 0);
diff --git a/libs/hwui/tests/unit/ThreadBaseTests.cpp b/libs/hwui/tests/unit/ThreadBaseTests.cpp
index 1168ff2..817c1f3 100644
--- a/libs/hwui/tests/unit/ThreadBaseTests.cpp
+++ b/libs/hwui/tests/unit/ThreadBaseTests.cpp
@@ -95,7 +95,7 @@
     };
 
     struct Counter {
-        Counter(EventCount* count) : mCount(count) { mCount->construct++; }
+        explicit Counter(EventCount* count) : mCount(count) { mCount->construct++; }
 
         Counter(const Counter& other) : mCount(other.mCount) {
             if (mCount) mCount->copy++;
@@ -148,4 +148,4 @@
     ASSERT_EQ(1, dummyObject->getStrongCount());
     ASSERT_EQ(2, lifecycleTestHelper(dummyObject));
     ASSERT_EQ(1, dummyObject->getStrongCount());
-}
\ No newline at end of file
+}
diff --git a/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp b/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp
index c8169af..e1fb8b7 100644
--- a/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp
+++ b/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp
@@ -27,8 +27,8 @@
 using namespace android::uirenderer;
 
 TEST(WebViewFunctor, createDestroyGLES) {
-    int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
-                                        RenderMode::OpenGL_ES);
+    int functor = WebViewFunctor_create(
+            nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
     ASSERT_NE(-1, functor);
     WebViewFunctor_release(functor);
     TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) {
@@ -41,8 +41,8 @@
 }
 
 TEST(WebViewFunctor, createSyncHandleGLES) {
-    int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
-                                        RenderMode::OpenGL_ES);
+    int functor = WebViewFunctor_create(
+            nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
     ASSERT_NE(-1, functor);
     auto handle = WebViewFunctorManager::instance().handleFor(functor);
     ASSERT_TRUE(handle);
@@ -82,8 +82,8 @@
 }
 
 TEST(WebViewFunctor, createSyncDrawGLES) {
-    int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
-                                        RenderMode::OpenGL_ES);
+    int functor = WebViewFunctor_create(
+            nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
     ASSERT_NE(-1, functor);
     auto handle = WebViewFunctorManager::instance().handleFor(functor);
     ASSERT_TRUE(handle);
@@ -109,8 +109,8 @@
 }
 
 TEST(WebViewFunctor, contextDestroyed) {
-    int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES),
-                                        RenderMode::OpenGL_ES);
+    int functor = WebViewFunctor_create(
+            nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
     ASSERT_NE(-1, functor);
     auto handle = WebViewFunctorManager::instance().handleFor(functor);
     ASSERT_TRUE(handle);
@@ -151,4 +151,4 @@
     EXPECT_EQ(2, counts.glesDraw);
     EXPECT_EQ(2, counts.contextDestroyed);
     EXPECT_EQ(1, counts.destroyed);
-}
\ No newline at end of file
+}
diff --git a/libs/hwui/thread/ThreadBase.h b/libs/hwui/thread/ThreadBase.h
index f9de8a5..8cdcc46 100644
--- a/libs/hwui/thread/ThreadBase.h
+++ b/libs/hwui/thread/ThreadBase.h
@@ -27,7 +27,7 @@
 
 namespace android::uirenderer {
 
-class ThreadBase : protected Thread {
+class ThreadBase : public Thread {
     PREVENT_COPY_AND_ASSIGN(ThreadBase);
 
 public:
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index dc347f6..4415a59 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -25,38 +25,6 @@
 namespace android {
 namespace uirenderer {
 
-static inline bool almostEqual(float a, float b) {
-    return std::abs(a - b) < 1e-2f;
-}
-
-bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace) {
-    if (colorSpace == nullptr) return true;
-    if (colorSpace->isSRGB()) return true;
-
-    SkColorSpaceTransferFn transferFunction;
-    if (colorSpace->isNumericalTransferFn(&transferFunction)) {
-        // sRGB transfer function params:
-        const float sRGBParamA = 1 / 1.055f;
-        const float sRGBParamB = 0.055f / 1.055f;
-        const float sRGBParamC = 1 / 12.92f;
-        const float sRGBParamD = 0.04045f;
-        const float sRGBParamE = 0.0f;
-        const float sRGBParamF = 0.0f;
-        const float sRGBParamG = 2.4f;
-
-        // This comparison will catch Display P3
-        return almostEqual(sRGBParamA, transferFunction.fA) &&
-               almostEqual(sRGBParamB, transferFunction.fB) &&
-               almostEqual(sRGBParamC, transferFunction.fC) &&
-               almostEqual(sRGBParamD, transferFunction.fD) &&
-               almostEqual(sRGBParamE, transferFunction.fE) &&
-               almostEqual(sRGBParamF, transferFunction.fF) &&
-               almostEqual(sRGBParamG, transferFunction.fG);
-    }
-
-    return false;
-}
-
 android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) {
     switch (colorType) {
         case kRGBA_8888_SkColorType:
@@ -79,19 +47,19 @@
 
 sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
 
-    SkColorSpace::Gamut gamut;
+    skcms_Matrix3x3 gamut;
     switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
         case HAL_DATASPACE_STANDARD_BT709:
-            gamut = SkColorSpace::kSRGB_Gamut;
+            gamut = SkNamedGamut::kSRGB;
             break;
         case HAL_DATASPACE_STANDARD_BT2020:
-            gamut = SkColorSpace::kRec2020_Gamut;
+            gamut = SkNamedGamut::kRec2020;
             break;
         case HAL_DATASPACE_STANDARD_DCI_P3:
-            gamut = SkColorSpace::kDCIP3_D65_Gamut;
+            gamut = SkNamedGamut::kDCIP3;
             break;
         case HAL_DATASPACE_STANDARD_ADOBE_RGB:
-            gamut = SkColorSpace::kAdobeRGB_Gamut;
+            gamut = SkNamedGamut::kAdobeRGB;
             break;
         case HAL_DATASPACE_STANDARD_UNSPECIFIED:
             return nullptr;
@@ -109,9 +77,9 @@
 
     switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
         case HAL_DATASPACE_TRANSFER_LINEAR:
-            return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, gamut);
+            return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut);
         case HAL_DATASPACE_TRANSFER_SRGB:
-            return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, gamut);
+            return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
         case HAL_DATASPACE_TRANSFER_GAMMA2_2:
             return SkColorSpace::MakeRGB({2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
         case HAL_DATASPACE_TRANSFER_GAMMA2_6:
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 4473ce6..3880252 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -111,11 +111,6 @@
 #endif
 }
 
-// Returns whether the specified color space's transfer function can be
-// approximated with the native sRGB transfer function. This method
-// returns true for sRGB, gamma 2.2 and Display P3 for instance
-bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
-
 android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType);
 
 ANDROID_API sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index b401fcf..9c4a1be 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -168,7 +168,7 @@
     };
     // enable allocators to be constructed from other templated types
     template <class U>
-    LinearStdAllocator(const LinearStdAllocator<U>& other)  // NOLINT(implicit)
+    LinearStdAllocator(const LinearStdAllocator<U>& other)  // NOLINT(google-explicit-constructor)
             : linearAllocator(other.linearAllocator) {}
 
     T* allocate(size_t num, const void* = 0) {
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 0a90f85..d742cc3 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -39,7 +39,7 @@
     virtual ~WeakLooperCallback() { }
 
 public:
-    WeakLooperCallback(const wp<LooperCallback>& callback) :
+    explicit WeakLooperCallback(const wp<LooperCallback>& callback) :
         mCallback(callback) {
     }
 
@@ -89,10 +89,6 @@
 
     mLocked.animationPending = false;
 
-    mLocked.displayWidth = -1;
-    mLocked.displayHeight = -1;
-    mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
-
     mLocked.presentation = PRESENTATION_POINTER;
     mLocked.presentationChanged = false;
 
@@ -110,15 +106,6 @@
     mLocked.lastFrameUpdatedTime = 0;
 
     mLocked.buttonState = 0;
-
-    mPolicy->loadPointerIcon(&mLocked.pointerIcon);
-
-    loadResources();
-
-    if (mLocked.pointerIcon.isValid()) {
-        mLocked.pointerIconChanged = true;
-        updatePointerLocked();
-    }
 }
 
 PointerController::~PointerController() {
@@ -144,23 +131,15 @@
 
 bool PointerController::getBoundsLocked(float* outMinX, float* outMinY,
         float* outMaxX, float* outMaxY) const {
-    if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) {
+
+    if (!mLocked.viewport.isValid()) {
         return false;
     }
 
-    *outMinX = 0;
-    *outMinY = 0;
-    switch (mLocked.displayOrientation) {
-    case DISPLAY_ORIENTATION_90:
-    case DISPLAY_ORIENTATION_270:
-        *outMaxX = mLocked.displayHeight - 1;
-        *outMaxY = mLocked.displayWidth - 1;
-        break;
-    default:
-        *outMaxX = mLocked.displayWidth - 1;
-        *outMaxY = mLocked.displayHeight - 1;
-        break;
-    }
+    *outMinX = mLocked.viewport.logicalLeft;
+    *outMinY = mLocked.viewport.logicalTop;
+    *outMaxX = mLocked.viewport.logicalRight - 1;
+    *outMaxY = mLocked.viewport.logicalBottom - 1;
     return true;
 }
 
@@ -231,6 +210,12 @@
     *outY = mLocked.pointerY;
 }
 
+int32_t PointerController::getDisplayId() const {
+    AutoMutex _l(mLock);
+
+    return mLocked.viewport.displayId;
+}
+
 void PointerController::fade(Transition transition) {
     AutoMutex _l(mLock);
 
@@ -270,7 +255,7 @@
 
     if (presentation == PRESENTATION_POINTER && mLocked.additionalMouseResources.empty()) {
         mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
-                                              &mLocked.animationResources);
+                &mLocked.animationResources, mLocked.viewport.displayId);
     }
 
     if (mLocked.presentation != presentation) {
@@ -355,48 +340,56 @@
 void PointerController::reloadPointerResources() {
     AutoMutex _l(mLock);
 
-    loadResources();
-
-    if (mLocked.presentation == PRESENTATION_POINTER) {
-        mLocked.additionalMouseResources.clear();
-        mLocked.animationResources.clear();
-        mPolicy->loadPointerIcon(&mLocked.pointerIcon);
-        mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
-                                              &mLocked.animationResources);
-    }
-
-    mLocked.presentationChanged = true;
+    loadResourcesLocked();
     updatePointerLocked();
 }
 
-void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) {
-    AutoMutex _l(mLock);
+/**
+ * The viewport values for deviceHeight and deviceWidth have already been adjusted for rotation,
+ * so here we are getting the dimensions in the original, unrotated orientation (orientation 0).
+ */
+static void getNonRotatedSize(const DisplayViewport& viewport, int32_t& width, int32_t& height) {
+    width = viewport.deviceWidth;
+    height = viewport.deviceHeight;
 
-    // Adjust to use the display's unrotated coordinate frame.
-    if (orientation == DISPLAY_ORIENTATION_90
-            || orientation == DISPLAY_ORIENTATION_270) {
-        int32_t temp = height;
-        height = width;
-        width = temp;
+    if (viewport.orientation == DISPLAY_ORIENTATION_90
+            || viewport.orientation == DISPLAY_ORIENTATION_270) {
+        std::swap(width, height);
+    }
+}
+
+void PointerController::setDisplayViewport(const DisplayViewport& viewport) {
+    AutoMutex _l(mLock);
+    if (viewport == mLocked.viewport) {
+        return;
     }
 
-    if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
-        mLocked.displayWidth = width;
-        mLocked.displayHeight = height;
+    const DisplayViewport oldViewport = mLocked.viewport;
+    mLocked.viewport = viewport;
+
+    int32_t oldDisplayWidth, oldDisplayHeight;
+    getNonRotatedSize(oldViewport, oldDisplayWidth, oldDisplayHeight);
+    int32_t newDisplayWidth, newDisplayHeight;
+    getNonRotatedSize(viewport, newDisplayWidth, newDisplayHeight);
+
+    // Reset cursor position to center if size or display changed.
+    if (oldViewport.displayId != viewport.displayId
+            || oldDisplayWidth != newDisplayWidth
+            || oldDisplayHeight != newDisplayHeight) {
 
         float minX, minY, maxX, maxY;
         if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
             mLocked.pointerX = (minX + maxX) * 0.5f;
             mLocked.pointerY = (minY + maxY) * 0.5f;
+            // Reload icon resources for density may be changed.
+            loadResourcesLocked();
         } else {
             mLocked.pointerX = 0;
             mLocked.pointerY = 0;
         }
 
         fadeOutAndReleaseAllSpotsLocked();
-    }
-
-    if (mLocked.displayOrientation != orientation) {
+    } else if (oldViewport.orientation != viewport.orientation) {
         // Apply offsets to convert from the pixel top-left corner position to the pixel center.
         // This creates an invariant frame of reference that we can easily rotate when
         // taking into account that the pointer may be located at fractional pixel offsets.
@@ -405,37 +398,37 @@
         float temp;
 
         // Undo the previous rotation.
-        switch (mLocked.displayOrientation) {
+        switch (oldViewport.orientation) {
         case DISPLAY_ORIENTATION_90:
             temp = x;
-            x = mLocked.displayWidth - y;
+            x =  oldViewport.deviceHeight - y;
             y = temp;
             break;
         case DISPLAY_ORIENTATION_180:
-            x = mLocked.displayWidth - x;
-            y = mLocked.displayHeight - y;
+            x = oldViewport.deviceWidth - x;
+            y = oldViewport.deviceHeight - y;
             break;
         case DISPLAY_ORIENTATION_270:
             temp = x;
             x = y;
-            y = mLocked.displayHeight - temp;
+            y = oldViewport.deviceWidth - temp;
             break;
         }
 
         // Perform the new rotation.
-        switch (orientation) {
+        switch (viewport.orientation) {
         case DISPLAY_ORIENTATION_90:
             temp = x;
             x = y;
-            y = mLocked.displayWidth - temp;
+            y = viewport.deviceHeight - temp;
             break;
         case DISPLAY_ORIENTATION_180:
-            x = mLocked.displayWidth - x;
-            y = mLocked.displayHeight - y;
+            x = viewport.deviceWidth - x;
+            y = viewport.deviceHeight - y;
             break;
         case DISPLAY_ORIENTATION_270:
             temp = x;
-            x = mLocked.displayHeight - y;
+            x = viewport.deviceWidth - y;
             y = temp;
             break;
         }
@@ -444,7 +437,6 @@
         // and save the results.
         mLocked.pointerX = x - 0.5f;
         mLocked.pointerY = y - 0.5f;
-        mLocked.displayOrientation = orientation;
     }
 
     updatePointerLocked();
@@ -614,11 +606,16 @@
     mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
 }
 
-void PointerController::updatePointerLocked() {
+void PointerController::updatePointerLocked() REQUIRES(mLock) {
+    if (!mLocked.viewport.isValid()) {
+        return;
+    }
+
     mSpriteController->openTransaction();
 
     mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
     mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
+    mLocked.pointerSprite->setDisplayId(mLocked.viewport.displayId);
 
     if (mLocked.pointerAlpha > 0) {
         mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha);
@@ -729,8 +726,18 @@
     }
 }
 
-void PointerController::loadResources() {
-    mPolicy->loadPointerResources(&mResources);
+void PointerController::loadResourcesLocked() REQUIRES(mLock) {
+    mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId);
+
+    if (mLocked.presentation == PRESENTATION_POINTER) {
+        mLocked.additionalMouseResources.clear();
+        mLocked.animationResources.clear();
+        mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);
+        mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
+                &mLocked.animationResources, mLocked.viewport.displayId);
+    }
+
+    mLocked.pointerIconChanged = true;
 }
 
 
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 7f4e5a5..be05786 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -23,6 +23,7 @@
 #include <vector>
 
 #include <ui/DisplayInfo.h>
+#include <input/DisplayViewport.h>
 #include <input/Input.h>
 #include <PointerControllerInterface.h>
 #include <utils/BitSet.h>
@@ -61,10 +62,10 @@
     virtual ~PointerControllerPolicyInterface() { }
 
 public:
-    virtual void loadPointerIcon(SpriteIcon* icon) = 0;
-    virtual void loadPointerResources(PointerResources* outResources) = 0;
+    virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) = 0;
+    virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) = 0;
     virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
-            std::map<int32_t, PointerAnimation>* outAnimationResources) = 0;
+            std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) = 0;
     virtual int32_t getDefaultPointerIconId() = 0;
     virtual int32_t getCustomPointerIconId() = 0;
 };
@@ -96,6 +97,7 @@
     virtual int32_t getButtonState() const;
     virtual void setPosition(float x, float y);
     virtual void getPosition(float* outX, float* outY) const;
+    virtual int32_t getDisplayId() const;
     virtual void fade(Transition transition);
     virtual void unfade(Transition transition);
 
@@ -106,7 +108,7 @@
 
     void updatePointerIcon(int32_t iconId);
     void setCustomPointerIcon(const SpriteIcon& icon);
-    void setDisplayViewport(int32_t width, int32_t height, int32_t orientation);
+    void setDisplayViewport(const DisplayViewport& viewport);
     void setInactivityTimeout(InactivityTimeout inactivityTimeout);
     void reloadPointerResources();
 
@@ -156,9 +158,7 @@
         size_t animationFrameIndex;
         nsecs_t lastFrameUpdatedTime;
 
-        int32_t displayWidth;
-        int32_t displayHeight;
-        int32_t displayOrientation;
+        DisplayViewport viewport;
 
         InactivityTimeout inactivityTimeout;
 
@@ -182,7 +182,7 @@
 
         Vector<Spot*> spots;
         Vector<sp<Sprite> > recycledSprites;
-    } mLocked;
+    } mLocked GUARDED_BY(mLock);
 
     bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
     void setPositionLocked(float x, float y);
@@ -207,7 +207,7 @@
     void fadeOutAndReleaseSpotLocked(Spot* spot);
     void fadeOutAndReleaseAllSpotsLocked();
 
-    void loadResources();
+    void loadResourcesLocked();
 };
 
 } // namespace android
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index eb2bc98..c1868d3 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -144,13 +144,16 @@
         }
     }
 
-    // Resize sprites if needed.
+    // Resize and/or reparent sprites if needed.
     SurfaceComposerClient::Transaction t;
     bool needApplyTransaction = false;
     for (size_t i = 0; i < numSprites; i++) {
         SpriteUpdate& update = updates.editItemAt(i);
+        if (update.state.surfaceControl == nullptr) {
+            continue;
+        }
 
-        if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) {
+        if (update.state.wantSurfaceVisible()) {
             int32_t desiredWidth = update.state.icon.bitmap.width();
             int32_t desiredHeight = update.state.icon.bitmap.height();
             if (update.state.surfaceWidth < desiredWidth
@@ -170,6 +173,12 @@
                 }
             }
         }
+
+        // If surface is a new one, we have to set right layer stack.
+        if (update.surfaceChanged || update.state.dirty & DIRTY_DISPLAY_ID) {
+            t.setLayerStack(update.state.surfaceControl, update.state.displayId);
+            needApplyTransaction = true;
+        }
     }
     if (needApplyTransaction) {
         t.apply();
@@ -236,7 +245,7 @@
         if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
                 || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
                         | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
-                        | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) {
+                        | DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID))))) {
             needApplyTransaction = true;
 
             if (wantSurfaceVisibleAndDrawn
@@ -445,6 +454,15 @@
     }
 }
 
+void SpriteController::SpriteImpl::setDisplayId(int32_t displayId) {
+    AutoMutex _l(mController->mLock);
+
+    if (mLocked.state.displayId != displayId) {
+        mLocked.state.displayId = displayId;
+        invalidateLocked(DIRTY_DISPLAY_ID);
+    }
+}
+
 void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) {
     bool wasDirty = mLocked.state.dirty;
     mLocked.state.dirty |= dirty;
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index 31e43e9..5b216f5 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -125,6 +125,9 @@
 
     /* Sets the sprite transformation matrix. */
     virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0;
+
+    /* Sets the id of the display where the sprite should be shown. */
+    virtual void setDisplayId(int32_t displayId) = 0;
 };
 
 /*
@@ -170,6 +173,7 @@
         DIRTY_LAYER = 1 << 4,
         DIRTY_VISIBILITY = 1 << 5,
         DIRTY_HOTSPOT = 1 << 6,
+        DIRTY_DISPLAY_ID = 1 << 7,
     };
 
     /* Describes the state of a sprite.
@@ -180,7 +184,7 @@
     struct SpriteState {
         inline SpriteState() :
                 dirty(0), visible(false),
-                positionX(0), positionY(0), layer(0), alpha(1.0f),
+                positionX(0), positionY(0), layer(0), alpha(1.0f), displayId(ADISPLAY_ID_DEFAULT),
                 surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) {
         }
 
@@ -193,6 +197,7 @@
         int32_t layer;
         float alpha;
         SpriteTransformationMatrix transformationMatrix;
+        int32_t displayId;
 
         sp<SurfaceControl> surfaceControl;
         int32_t surfaceWidth;
@@ -225,6 +230,7 @@
         virtual void setLayer(int32_t layer);
         virtual void setAlpha(float alpha);
         virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix);
+        virtual void setDisplayId(int32_t displayId);
 
         inline const SpriteState& getStateLocked() const {
             return mLocked.state;
diff --git a/libs/protoutil/include/android/util/EncodedBuffer.h b/libs/protoutil/include/android/util/EncodedBuffer.h
index c84de4c..0b7f6e46 100644
--- a/libs/protoutil/include/android/util/EncodedBuffer.h
+++ b/libs/protoutil/include/android/util/EncodedBuffer.h
@@ -38,13 +38,13 @@
 {
 public:
     EncodedBuffer();
-    EncodedBuffer(size_t chunkSize);
+    explicit EncodedBuffer(size_t chunkSize);
     ~EncodedBuffer();
 
     class Pointer {
     public:
         Pointer();
-        Pointer(size_t chunkSize);
+        explicit Pointer(size_t chunkSize);
 
         size_t pos() const;
         size_t index() const;
@@ -161,7 +161,7 @@
     friend class iterator;
     class iterator {
     public:
-        iterator(const EncodedBuffer& buffer);
+        explicit iterator(const EncodedBuffer& buffer);
 
         /**
          * Returns the number of bytes written in the buffer
diff --git a/libs/services/include/android/os/DropBoxManager.h b/libs/services/include/android/os/DropBoxManager.h
index 75b26c6..0747243 100644
--- a/libs/services/include/android/os/DropBoxManager.h
+++ b/libs/services/include/android/os/DropBoxManager.h
@@ -62,7 +62,7 @@
     // file descriptor.
     Status addFile(const String16& tag, int fd, int flags);
 
-    class Entry : public virtual RefBase, public Parcelable {
+    class Entry : public Parcelable {
     public:
         Entry();
         virtual ~Entry();
@@ -89,9 +89,6 @@
         friend class DropBoxManager;
     };
 
-    // Get the next entry from the drop box after the specified time.
-    Status getNextEntry(const String16& tag, long msec, Entry* entry);
-
 private:
     enum {
         HAS_BYTE_ARRAY = 8
diff --git a/libs/services/src/os/DropBoxManager.cpp b/libs/services/src/os/DropBoxManager.cpp
index 8282518..681d5f7 100644
--- a/libs/services/src/os/DropBoxManager.cpp
+++ b/libs/services/src/os/DropBoxManager.cpp
@@ -228,15 +228,4 @@
     return service->add(entry);
 }
 
-Status
-DropBoxManager::getNextEntry(const String16& tag, long msec, Entry* entry)
-{
-    sp<IDropBoxManagerService> service = interface_cast<IDropBoxManagerService>(
-        defaultServiceManager()->getService(android::String16("dropbox")));
-    if (service == NULL) {
-        return Status::fromExceptionCode(Status::EX_NULL_POINTER, "can't find dropbox service");
-    }
-    return service->getNextEntry(tag, msec, android::String16("android"), entry);
-}
-
 }} // namespace android::os
diff --git a/libs/usb/api/current.txt b/libs/usb/api/current.txt
index 8488db5..f17b65a 100644
--- a/libs/usb/api/current.txt
+++ b/libs/usb/api/current.txt
@@ -1,12 +1,13 @@
+// Signature format: 2.0
 package com.android.future.usb {
 
   public class UsbAccessory {
-    method public java.lang.String getDescription();
-    method public java.lang.String getManufacturer();
-    method public java.lang.String getModel();
-    method public java.lang.String getSerial();
-    method public java.lang.String getUri();
-    method public java.lang.String getVersion();
+    method public String getDescription();
+    method public String getManufacturer();
+    method public String getModel();
+    method public String getSerial();
+    method public String getUri();
+    method public String getVersion();
   }
 
   public class UsbManager {
@@ -16,9 +17,9 @@
     method public boolean hasPermission(com.android.future.usb.UsbAccessory);
     method public android.os.ParcelFileDescriptor openAccessory(com.android.future.usb.UsbAccessory);
     method public void requestPermission(com.android.future.usb.UsbAccessory, android.app.PendingIntent);
-    field public static final java.lang.String ACTION_USB_ACCESSORY_ATTACHED = "android.hardware.usb.action.USB_ACCESSORY_ATTACHED";
-    field public static final java.lang.String ACTION_USB_ACCESSORY_DETACHED = "android.hardware.usb.action.USB_ACCESSORY_DETACHED";
-    field public static final java.lang.String EXTRA_PERMISSION_GRANTED = "permission";
+    field public static final String ACTION_USB_ACCESSORY_ATTACHED = "android.hardware.usb.action.USB_ACCESSORY_ATTACHED";
+    field public static final String ACTION_USB_ACCESSORY_DETACHED = "android.hardware.usb.action.USB_ACCESSORY_DETACHED";
+    field public static final String EXTRA_PERMISSION_GRANTED = "permission";
   }
 
 }
diff --git a/libs/usb/api/removed.txt b/libs/usb/api/removed.txt
index e69de29..d802177 100644
--- a/libs/usb/api/removed.txt
+++ b/libs/usb/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/usb/api/system-current.txt b/libs/usb/api/system-current.txt
index e69de29..d802177 100644
--- a/libs/usb/api/system-current.txt
+++ b/libs/usb/api/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/usb/api/system-removed.txt b/libs/usb/api/system-removed.txt
index e69de29..d802177 100644
--- a/libs/usb/api/system-removed.txt
+++ b/libs/usb/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/usb/api/test-current.txt b/libs/usb/api/test-current.txt
index e69de29..d802177 100644
--- a/libs/usb/api/test-current.txt
+++ b/libs/usb/api/test-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/libs/usb/api/test-removed.txt b/libs/usb/api/test-removed.txt
index e69de29..d802177 100644
--- a/libs/usb/api/test-removed.txt
+++ b/libs/usb/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index f179bc3..602cc3e 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -48,6 +48,7 @@
     private int mMultipathIndicator;
     private double mSnrInDb;
     private double mAutomaticGainControlLevelInDb;
+    private int mCodeType;
 
     // The following enumerations must be in sync with the values declared in gps.h
 
@@ -58,6 +59,7 @@
     private static final int HAS_CARRIER_PHASE = (1<<11);
     private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12);
     private static final int HAS_AUTOMATIC_GAIN_CONTROL = (1<<13);
+    private static final int HAS_CODE_TYPE = (1 << 14);
 
     /**
      * The status of the multipath indicator.
@@ -202,6 +204,104 @@
     public static final int ADR_STATE_HALF_CYCLE_REPORTED = (1<<4);
 
     /**
+     * GNSS measurement code type.
+     * @hide
+     */
+    @IntDef(prefix = { "CODE_TYPE_" }, value = {
+            CODE_TYPE_UNKNOWN, CODE_TYPE_A, CODE_TYPE_B, CODE_TYPE_C, CODE_TYPE_I, CODE_TYPE_L,
+            CODE_TYPE_M, CODE_TYPE_P, CODE_TYPE_Q, CODE_TYPE_S, CODE_TYPE_W, CODE_TYPE_X,
+            CODE_TYPE_Y, CODE_TYPE_Z, CODE_TYPE_CODELESS
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CodeType {}
+
+    /** The GNSS Measurement's code type is unknown. */
+    public static final int CODE_TYPE_UNKNOWN = -1;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GALILEO E1A, GALILEO E6A, IRNSS
+     * L5A, IRNSS SA.
+     */
+    public static final int CODE_TYPE_A = 0;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GALILEO E1B, GALILEO E6B, IRNSS
+     * L5B, IRNSS SB.
+     */
+    public static final int CODE_TYPE_B = 1;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1 C/A,  GPS L2 C/A, GLONASS G1
+     * C/A, GLONASS G2 C/A, GALILEO E1C, GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C.
+     */
+    public static final int CODE_TYPE_C = 2;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L5 I, GLONASS G3 I, GALILEO E5a
+     * I, GALILEO E5b I, GALILEO E5a+b I, SBAS L5 I, QZSS L5 I, BDS B1 I, BDS B2 I, BDS B3 I.
+     */
+    public static final int CODE_TYPE_I = 3;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1C (P), GPS L2C (L), QZSS L1C
+     * (P), QZSS L2C (L), LEX(6) L.
+     */
+    public static final int CODE_TYPE_L = 4;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1M, GPS L2M.
+     */
+    public static final int CODE_TYPE_M = 5;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1P, GPS L2P, GLONASS G1P,
+     * GLONASS G2P.
+     */
+    public static final int CODE_TYPE_P = 6;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L5 Q, GLONASS G3 Q, GALILEO E5a
+     * Q, GALILEO E5b Q, GALILEO E5a+b Q, SBAS L5 Q, QZSS L5 Q, BDS B1 Q, BDS B2 Q, BDS B3 Q.
+     */
+    public static final int CODE_TYPE_Q = 7;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1C (D), GPS L2C (M), QZSS L1C
+     * (D), QZSS L2C (M), LEX(6) S.
+     */
+    public static final int CODE_TYPE_S = 8;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1 Z-tracking, GPS L2
+     * Z-tracking.
+     */
+    public static final int CODE_TYPE_W = 9;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1C (D+P), GPS L2C (M+L), GPS
+     * L5 (I+Q), GLONASS G3 (I+Q), GALILEO E1 (B+C), GALILEO E5a (I+Q), GALILEO E5b (I+Q), GALILEO
+     * E5a+b(I+Q), GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q),
+     * LEX(6) (S+L), BDS B1 (I+Q), BDS B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C).
+     */
+    public static final int CODE_TYPE_X = 10;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1Y, GPS L2Y.
+     */
+    public static final int CODE_TYPE_Y = 11;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GALILEO E1 (A+B+C), GALILEO E6
+     * (A+B+C), QZSS L1-SAIF.
+     */
+    public static final int CODE_TYPE_Z = 12;
+
+    /**
+     * The GNSS Measurement's code type is one of the following: GPS L1 codeless, GPS L2 codeless.
+     */
+    public static final int CODE_TYPE_CODELESS = 13;
+
+    /**
      * All the 'Accumulated Delta Range' flags.
      * @hide
      */
@@ -248,6 +348,7 @@
         mMultipathIndicator = measurement.mMultipathIndicator;
         mSnrInDb = measurement.mSnrInDb;
         mAutomaticGainControlLevelInDb = measurement.mAutomaticGainControlLevelInDb;
+        mCodeType = measurement.mCodeType;
     }
 
     /**
@@ -967,7 +1068,7 @@
      * <p>For internal and logging use only.
      */
     private String getMultipathIndicatorString() {
-        switch(mMultipathIndicator) {
+        switch (mMultipathIndicator) {
             case MULTIPATH_INDICATOR_UNKNOWN:
                 return "Unknown";
             case MULTIPATH_INDICATOR_DETECTED:
@@ -1063,6 +1164,89 @@
         mAutomaticGainControlLevelInDb = Double.NaN;
     }
 
+    /**
+     * Returns {@code true} if {@link #getCodeType()} is available,
+     * {@code false} otherwise.
+     */
+    public boolean hasCodeType() {
+        return isFlagSet(HAS_CODE_TYPE);
+    }
+
+    /**
+     * Gets the GNSS measurement's code type.
+     *
+     * <p>Similar to the Attribute field described in Rinex 3.03, e.g., in Tables 4-10, and Table
+     * A2 at the Rinex 3.03 Update 1 Document.
+     */
+    @CodeType
+    public int getCodeType() {
+        return mCodeType;
+    }
+
+    /**
+     * Sets the GNSS measurement's code type.
+     *
+     * @hide
+     */
+    @TestApi
+    public void setCodeType(@CodeType int codeType) {
+        setFlag(HAS_CODE_TYPE);
+        mCodeType = codeType;
+    }
+
+    /**
+     * Resets the GNSS measurement's code type.
+     *
+     * @hide
+     */
+    @TestApi
+    public void resetCodeType() {
+        resetFlag(HAS_CODE_TYPE);
+        mCodeType = CODE_TYPE_UNKNOWN;
+    }
+
+    /**
+     * Gets a string representation of the 'code type'.
+     *
+     * <p>For internal and logging use only.
+     */
+    private String getCodeTypeString() {
+        switch (mCodeType) {
+            case CODE_TYPE_UNKNOWN:
+                return "CODE_TYPE_UNKNOWN";
+            case CODE_TYPE_A:
+                return "CODE_TYPE_A";
+            case CODE_TYPE_B:
+                return "CODE_TYPE_B";
+            case CODE_TYPE_C:
+                return "CODE_TYPE_C";
+            case CODE_TYPE_I:
+                return "CODE_TYPE_I";
+            case CODE_TYPE_L:
+                return "CODE_TYPE_L";
+            case CODE_TYPE_M:
+                return "CODE_TYPE_M";
+            case CODE_TYPE_P:
+                return "CODE_TYPE_P";
+            case CODE_TYPE_Q:
+                return "CODE_TYPE_Q";
+            case CODE_TYPE_S:
+                return "CODE_TYPE_S";
+            case CODE_TYPE_W:
+                return "CODE_TYPE_W";
+            case CODE_TYPE_X:
+                return "CODE_TYPE_X";
+            case CODE_TYPE_Y:
+                return "CODE_TYPE_Y";
+            case CODE_TYPE_Z:
+                return "CODE_TYPE_Z";
+            case CODE_TYPE_CODELESS:
+                return "CODE_TYPE_CODELESS";
+            default:
+                return "<Invalid: " + mCodeType + ">";
+        }
+    }
+
     public static final Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() {
         @Override
         public GnssMeasurement createFromParcel(Parcel parcel) {
@@ -1088,6 +1272,7 @@
             gnssMeasurement.mMultipathIndicator = parcel.readInt();
             gnssMeasurement.mSnrInDb = parcel.readDouble();
             gnssMeasurement.mAutomaticGainControlLevelInDb = parcel.readDouble();
+            gnssMeasurement.mCodeType = parcel.readInt();
 
             return gnssMeasurement;
         }
@@ -1120,6 +1305,7 @@
         parcel.writeInt(mMultipathIndicator);
         parcel.writeDouble(mSnrInDb);
         parcel.writeDouble(mAutomaticGainControlLevelInDb);
+        parcel.writeInt(mCodeType);
     }
 
     @Override
@@ -1191,9 +1377,13 @@
                 "SnrInDb",
                 hasSnrInDb() ? mSnrInDb : null));
         builder.append(String.format(
-            format,
-            "AgcLevelDb",
-            hasAutomaticGainControlLevelDb() ? mAutomaticGainControlLevelInDb : null));
+                format,
+                "AgcLevelDb",
+                hasAutomaticGainControlLevelDb() ? mAutomaticGainControlLevelInDb : null));
+        builder.append(String.format(
+                format,
+                "CodeType",
+                hasCodeType() ? getCodeTypeString() : null));
 
         return builder.toString();
     }
@@ -1218,6 +1408,7 @@
         setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN);
         resetSnrInDb();
         resetAutomaticGainControlLevel();
+        resetCodeType();
     }
 
     private void setFlag(int flag) {
diff --git a/location/java/android/location/GnssSingleSatCorrection.java b/location/java/android/location/GnssSingleSatCorrection.java
index 6c757f9..3922d2f 100644
--- a/location/java/android/location/GnssSingleSatCorrection.java
+++ b/location/java/android/location/GnssSingleSatCorrection.java
@@ -16,11 +16,14 @@
 
 package android.location;
 
+import android.annotation.FloatRange;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.util.Preconditions;
+
 /**
  * A container with measurement corrections for a single visible satellite
  *
@@ -31,9 +34,9 @@
 
     /**
      * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
-     * #mSatIsLos}.
+     * #mProbSatIsLos}.
      */
-    public static final int HAS_SAT_IS_LOS_MASK = 1 << 0;
+    public static final int HAS_PROB_SAT_IS_LOS_MASK = 1 << 0;
 
     /**
      * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
@@ -78,9 +81,11 @@
     private float mCarrierFrequencyHz;
 
     /**
-     * True if the satellite is estimated to be in Line-of-Sight condition at the given location.
+     * The probability that the satellite is estimated to be in Line-of-Sight condition at the given
+     * location.
      */
-    private boolean mSatIsLos;
+    @FloatRange(from = 0f, to = 1f)
+    private float mProbSatIsLos;
 
     /**
      * Excess path length to be subtracted from pseudorange before using it in calculating location.
@@ -103,7 +108,7 @@
         mSatId = builder.mSatId;
         mConstellationType = builder.mConstellationType;
         mCarrierFrequencyHz = builder.mCarrierFrequencyHz;
-        mSatIsLos = builder.mSatIsLos;
+        mProbSatIsLos = builder.mProbSatIsLos;
         mExcessPathLengthMeters = builder.mExcessPathLengthMeters;
         mExcessPathLengthUncertaintyMeters = builder.mExcessPathLengthUncertaintyMeters;
         mReflectingPlane = builder.mReflectingPlane;
@@ -152,9 +157,13 @@
         return mCarrierFrequencyHz;
     }
 
-    /** True if the satellite is line-of-sight */
-    public boolean isSatelliteLineOfSight() {
-        return mSatIsLos;
+    /**
+     * Returns the probability that the satellite is in line-of-sight condition at the given
+     * location.
+     */
+    @FloatRange(from = 0f, to = 1f)
+    public float getProbSatIsLos() {
+        return mProbSatIsLos;
     }
 
     /**
@@ -180,9 +189,9 @@
         return mReflectingPlane;
     }
 
-    /** Returns {@code true} if {@link #isSatelliteLineOfSight()} is valid. */
+    /** Returns {@code true} if {@link #getProbSatIsLos()} is valid. */
     public boolean hasSatelliteLineOfSight() {
-        return (mSingleSatCorrectionFlags & HAS_SAT_IS_LOS_MASK) != 0;
+        return (mSingleSatCorrectionFlags & HAS_PROB_SAT_IS_LOS_MASK) != 0;
     }
 
     /** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
@@ -215,7 +224,7 @@
                                     .setConstellationType(parcel.readInt())
                                     .setSatId(parcel.readInt())
                                     .setCarrierFrequencyHz(parcel.readFloat())
-                                    .setSatIsLos(parcel.readBoolean())
+                                    .setProbSatIsLos(parcel.readFloat())
                                     .setExcessPathLengthMeters(parcel.readFloat())
                                     .setExcessPathLengthUncertaintyMeters(parcel.readFloat())
                                     .setReflectingPlane(
@@ -239,7 +248,7 @@
         builder.append(String.format(format, "ConstellationType = ", mConstellationType));
         builder.append(String.format(format, "SatId = ", mSatId));
         builder.append(String.format(format, "CarrierFrequencyHz = ", mCarrierFrequencyHz));
-        builder.append(String.format(format, "SatIsLos = ", mSatIsLos));
+        builder.append(String.format(format, "ProbSatIsLos = ", mProbSatIsLos));
         builder.append(String.format(format, "ExcessPathLengthMeters = ", mExcessPathLengthMeters));
         builder.append(
                 String.format(
@@ -256,7 +265,7 @@
         parcel.writeInt(mConstellationType);
         parcel.writeInt(mSatId);
         parcel.writeFloat(mCarrierFrequencyHz);
-        parcel.writeBoolean(mSatIsLos);
+        parcel.writeFloat(mProbSatIsLos);
         parcel.writeFloat(mExcessPathLengthMeters);
         parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
         mReflectingPlane.writeToParcel(parcel, flags);
@@ -274,7 +283,7 @@
         private int mConstellationType;
         private int mSatId;
         private float mCarrierFrequencyHz;
-        private boolean mSatIsLos;
+        private float mProbSatIsLos;
         private float mExcessPathLengthMeters;
         private float mExcessPathLengthUncertaintyMeters;
         private GnssReflectingPlane mReflectingPlane;
@@ -303,10 +312,16 @@
             return this;
         }
 
-        /** Sets the line=of-sight state of the satellite */
-        public Builder setSatIsLos(boolean satIsLos) {
-            mSatIsLos = satIsLos;
-            mSingleSatCorrectionFlags = (byte) (mSingleSatCorrectionFlags | HAS_SAT_IS_LOS_MASK);
+        /**
+         * Sets the line-of-sight probability of the satellite at the given location in the range
+         * between 0 and 1.
+         */
+        public Builder setProbSatIsLos(@FloatRange(from = 0f, to = 1f) float probSatIsLos) {
+            Preconditions.checkArgumentInRange(probSatIsLos, 0, 1,
+                    "probSatIsLos should be between 0 and 1.");
+            mProbSatIsLos = probSatIsLos;
+            mSingleSatCorrectionFlags =
+                    (byte) (mSingleSatCorrectionFlags | HAS_PROB_SAT_IS_LOS_MASK);
             return this;
         }
 
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index bdc84da..e795b81 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -89,7 +89,6 @@
     List<String> getAllProviders();
     List<String> getProviders(in Criteria criteria, boolean enabledOnly);
     String getBestProvider(in Criteria criteria, boolean enabledOnly);
-    boolean providerMeetsCriteria(String provider, in Criteria criteria);
     ProviderProperties getProviderProperties(String provider);
     String getNetworkProviderPackage();
     void setLocationControllerExtraPackage(String packageName);
@@ -98,9 +97,7 @@
     boolean isLocationControllerExtraPackageEnabled();
 
     boolean isProviderEnabledForUser(String provider, int userId);
-    boolean setProviderEnabledForUser(String provider, boolean enabled, int userId);
     boolean isLocationEnabledForUser(int userId);
-    void setLocationEnabledForUser(boolean enabled, int userId);
     void addTestProvider(String name, in ProviderProperties properties, String opPackageName);
     void removeTestProvider(String provider, String opPackageName);
     void setTestProviderLocation(String provider, in Location loc, String opPackageName);
@@ -114,10 +111,6 @@
 
     // --- internal ---
 
-    // --- deprecated ---
-    void reportLocation(in Location location, boolean passive);
-    void reportLocationBatch(in List<Location> locations);
-
     // for reporting callback completion
     void locationCallbackFinished(ILocationListener listener);
 
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index d96597b..59c6a0a 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -43,6 +43,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.Log;
 
 import com.android.internal.location.ProviderProperties;
@@ -1282,11 +1283,13 @@
     @SystemApi
     @RequiresPermission(WRITE_SECURE_SETTINGS)
     public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) {
-        try {
-            mService.setLocationEnabledForUser(enabled, userHandle.getIdentifier());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        Settings.Secure.putIntForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.LOCATION_MODE,
+                enabled
+                        ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
+                        : Settings.Secure.LOCATION_MODE_OFF,
+                userHandle.getIdentifier());
     }
 
     /**
@@ -1372,20 +1375,22 @@
      * @return true if the value was set, false on database errors
      *
      * @throws IllegalArgumentException if provider is null
+     * @deprecated Do not manipulate providers individually, use
+     * {@link #setLocationEnabledForUser(boolean, UserHandle)} instead.
      * @hide
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(WRITE_SECURE_SETTINGS)
     public boolean setProviderEnabledForUser(
             String provider, boolean enabled, UserHandle userHandle) {
         checkProvider(provider);
 
-        try {
-            return mService.setProviderEnabledForUser(
-                    provider, enabled, userHandle.getIdentifier());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return Settings.Secure.setLocationProviderEnabledForUser(
+                mContext.getContentResolver(),
+                provider,
+                enabled,
+                userHandle.getIdentifier());
     }
 
     /**
@@ -1578,7 +1583,7 @@
      */
     @Deprecated
     public void clearTestProviderEnabled(String provider) {
-        setTestProviderEnabled(provider, true);
+        setTestProviderEnabled(provider, false);
     }
 
     /**
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 154bd56..3d0afb09 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -16,6 +16,8 @@
 
 package android.location;
 
+import android.Manifest;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
@@ -161,6 +163,7 @@
     private WorkSource mWorkSource = null;
     @UnsupportedAppUsage
     private boolean mHideFromAppOps = false; // True if this request shouldn't be counted by AppOps
+    private boolean mLocationSettingsIgnored = false;
 
     @UnsupportedAppUsage
     private String mProvider = LocationManager.FUSED_PROVIDER;
@@ -261,6 +264,7 @@
         mWorkSource = src.mWorkSource;
         mHideFromAppOps = src.mHideFromAppOps;
         mLowPowerMode = src.mLowPowerMode;
+        mLocationSettingsIgnored = src.mLocationSettingsIgnored;
     }
 
     /**
@@ -375,6 +379,32 @@
     }
 
     /**
+     * Requests that user location settings be ignored in order to satisfy this request. This API
+     * is only for use in extremely rare scenarios where it is appropriate to ignore user location
+     * settings, such as a user initiated emergency (dialing 911 for instance).
+     *
+     * @param locationSettingsIgnored Whether to ignore location settings
+     * @return the same object, so that setters can be chained
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+    @SystemApi
+    public LocationRequest setLocationSettingsIgnored(boolean locationSettingsIgnored) {
+        mLocationSettingsIgnored = locationSettingsIgnored;
+        return this;
+    }
+
+    /**
+     * Returns true if location settings will be ignored in order to satisfy this request.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isLocationSettingsIgnored() {
+        return mLocationSettingsIgnored;
+    }
+
+    /**
      * Explicitly set the fastest interval for location updates, in
      * milliseconds.
      *
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index b531325..866634e 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -16,9 +16,6 @@
 
 package com.android.internal.location;
 
-import java.io.UnsupportedEncodingException;
-import java.util.concurrent.TimeUnit;
-
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -26,20 +23,23 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.location.LocationManager;
 import android.location.INetInitiatedListener;
+import android.location.LocationManager;
+import android.os.RemoteException;
 import android.os.SystemClock;
-import android.telephony.TelephonyManager;
+import android.os.UserHandle;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.PhoneStateListener;
-import android.os.RemoteException;
-import android.os.UserHandle;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
-import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.R;
+import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.telephony.GsmAlphabet;
 
+import java.io.UnsupportedEncodingException;
+import java.util.concurrent.TimeUnit;
+
 /**
  * A GPS Network-initiated Handler class used by LocationManager.
  *
@@ -92,9 +92,6 @@
     public static final int GPS_ENC_SUPL_UCS2 = 3;
     public static final int GPS_ENC_UNKNOWN = -1;
 
-    // Limit on SUPL NI emergency mode time extension after emergency sessions ends
-    private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300;  // 5 minute maximum
-
     private final Context mContext;
     private final TelephonyManager mTelephonyManager;
     private final PhoneStateListener mPhoneStateListener;
@@ -252,19 +249,9 @@
     }
 
     public void setEmergencyExtensionSeconds(int emergencyExtensionSeconds) {
-        if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) {
-            Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds
-                    + " too high, reset to " + MAX_EMERGENCY_MODE_EXTENSION_SECONDS);
-            emergencyExtensionSeconds = MAX_EMERGENCY_MODE_EXTENSION_SECONDS;
-        } else if (emergencyExtensionSeconds < 0) {
-            Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds
-                    + " is negative, reset to zero.");
-            emergencyExtensionSeconds = 0;
-        }
         mEmergencyExtensionMillis = TimeUnit.SECONDS.toMillis(emergencyExtensionSeconds);
     }
 
-
     // Handles NI events from HAL
     public void handleNiNotification(GpsNiNotification notif) {
         if (DEBUG) Log.d(TAG, "in handleNiNotification () :"
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
index b09335c..35f2877 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -18,5 +18,7 @@
     name: "com.android.location.provider",
     srcs: ["java/**/*.java"],
     api_packages: ["com.android.location.provider"],
-    metalava_enabled: false,
+    srcs_lib: "framework",
+    srcs_lib_whitelist_dirs: ["location/java"],
+    srcs_lib_whitelist_pkgs: ["com.android.internal.location"],
 }
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index 10c3447..c721218 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -1,27 +1,28 @@
+// Signature format: 2.0
 package com.android.location.provider {
 
-  public abstract deprecated class FusedProvider {
-    ctor public FusedProvider();
-    method public android.os.IBinder getBinder();
+  @Deprecated public abstract class FusedProvider {
+    ctor @Deprecated public FusedProvider();
+    method @Deprecated public android.os.IBinder getBinder();
   }
 
   public abstract class LocationProviderBase {
-    ctor public LocationProviderBase(java.lang.String, com.android.location.provider.ProviderPropertiesUnbundled);
+    ctor public LocationProviderBase(String, com.android.location.provider.ProviderPropertiesUnbundled);
     method public android.os.IBinder getBinder();
     method public boolean isEnabled();
-    method protected deprecated void onDisable();
-    method protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method protected deprecated void onEnable();
-    method protected deprecated int onGetStatus(android.os.Bundle);
-    method protected deprecated long onGetStatusUpdateTime();
+    method @Deprecated protected void onDisable();
+    method protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
+    method @Deprecated protected void onEnable();
+    method @Deprecated protected int onGetStatus(android.os.Bundle);
+    method @Deprecated protected long onGetStatusUpdateTime();
     method protected void onInit();
-    method protected boolean onSendExtraCommand(java.lang.String, android.os.Bundle);
+    method protected boolean onSendExtraCommand(@Nullable String, @Nullable android.os.Bundle);
     method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
     method public void reportLocation(android.location.Location);
     method public void setEnabled(boolean);
     method public void setProperties(com.android.location.provider.ProviderPropertiesUnbundled);
-    field public static final java.lang.String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
-    field public static final java.lang.String FUSED_PROVIDER = "fused";
+    field public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
+    field public static final String FUSED_PROVIDER = "fused";
   }
 
   public final class LocationRequestUnbundled {
diff --git a/location/lib/api/removed.txt b/location/lib/api/removed.txt
index e69de29..d802177 100644
--- a/location/lib/api/removed.txt
+++ b/location/lib/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/location/lib/api/system-current.txt b/location/lib/api/system-current.txt
index e69de29..d802177 100644
--- a/location/lib/api/system-current.txt
+++ b/location/lib/api/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/location/lib/api/system-removed.txt b/location/lib/api/system-removed.txt
index e69de29..d802177 100644
--- a/location/lib/api/system-removed.txt
+++ b/location/lib/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/location/lib/api/test-current.txt b/location/lib/api/test-current.txt
index e69de29..d802177 100644
--- a/location/lib/api/test-current.txt
+++ b/location/lib/api/test-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/location/lib/api/test-removed.txt b/location/lib/api/test-removed.txt
index e69de29..d802177 100644
--- a/location/lib/api/test-removed.txt
+++ b/location/lib/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java b/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java
index c18d58f..d6227bb 100644
--- a/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java
+++ b/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java
@@ -59,7 +59,7 @@
         assertEquals(GnssStatus.CONSTELLATION_GPS, singleSatCorrection.getConstellationType());
         assertEquals(11, singleSatCorrection.getSatId());
         assertEquals(1575430000f, singleSatCorrection.getCarrierFrequencyHz());
-        assertEquals(false, singleSatCorrection.isSatelliteLineOfSight());
+        assertEquals(0.9f, singleSatCorrection.getProbSatIsLos());
         assertEquals(50.0f, singleSatCorrection.getExcessPathLengthMeters());
         assertEquals(55.0f, singleSatCorrection.getExcessPathLengthUncertaintyMeters());
         GnssReflectingPlane reflectingPlane = singleSatCorrection.getReflectingPlane();
@@ -88,7 +88,7 @@
                 .setConstellationType(GnssStatus.CONSTELLATION_GPS)
                 .setSatId(11)
                 .setCarrierFrequencyHz(1575430000f)
-                .setSatIsLos(false)
+                .setProbSatIsLos(0.9f)
                 .setExcessPathLengthMeters(50.0f)
                 .setExcessPathLengthUncertaintyMeters(55.0f)
                 .setReflectingPlane(generateTestReflectingPlane());
diff --git a/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java b/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java
index 2e54ae4..f358806 100644
--- a/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java
+++ b/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java
@@ -44,7 +44,7 @@
         assertEquals(GnssStatus.CONSTELLATION_GALILEO, singleSatCorrection.getConstellationType());
         assertEquals(12, singleSatCorrection.getSatId());
         assertEquals(1575420000f, singleSatCorrection.getCarrierFrequencyHz());
-        assertEquals(true, singleSatCorrection.isSatelliteLineOfSight());
+        assertEquals(0.1f, singleSatCorrection.getProbSatIsLos());
         assertEquals(10.0f, singleSatCorrection.getExcessPathLengthMeters());
         assertEquals(5.0f, singleSatCorrection.getExcessPathLengthUncertaintyMeters());
         GnssReflectingPlane reflectingPlane = singleSatCorrection.getReflectingPlane();
@@ -58,7 +58,7 @@
                 .setConstellationType(singleSatCorr.getConstellationType())
                 .setSatId(singleSatCorr.getSatId())
                 .setCarrierFrequencyHz(singleSatCorr.getCarrierFrequencyHz())
-                .setSatIsLos(singleSatCorr.isSatelliteLineOfSight())
+                .setProbSatIsLos(singleSatCorr.getProbSatIsLos())
                 .setExcessPathLengthMeters(singleSatCorr.getExcessPathLengthMeters())
                 .setExcessPathLengthUncertaintyMeters(
                         singleSatCorr.getExcessPathLengthUncertaintyMeters())
@@ -72,7 +72,7 @@
                         .setConstellationType(GnssStatus.CONSTELLATION_GALILEO)
                         .setSatId(12)
                         .setCarrierFrequencyHz(1575420000f)
-                        .setSatIsLos(true)
+                        .setProbSatIsLos(0.1f)
                         .setExcessPathLengthMeters(10.0f)
                         .setExcessPathLengthUncertaintyMeters(5.0f)
                         .setReflectingPlane(GnssReflectingPlaneTest.generateTestReflectingPlane());
diff --git a/lowpan/tests/Android.mk b/lowpan/tests/Android.mk
index 67727a7..832ed2f 100644
--- a/lowpan/tests/Android.mk
+++ b/lowpan/tests/Android.mk
@@ -45,7 +45,7 @@
 LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude)
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-	android-support-test \
+	androidx.test.rules \
 	guava \
 	mockito-target-minus-junit4 \
 	frameworks-base-testutils \
diff --git a/lowpan/tests/AndroidManifest.xml b/lowpan/tests/AndroidManifest.xml
index a216214..4225613 100644
--- a/lowpan/tests/AndroidManifest.xml
+++ b/lowpan/tests/AndroidManifest.xml
@@ -30,7 +30,7 @@
         </activity>
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="android.net.lowpan.test"
         android:label="Frameworks LoWPAN API Tests">
     </instrumentation>
diff --git a/lowpan/tests/AndroidTest.xml b/lowpan/tests/AndroidTest.xml
index 72ad050..978cc02 100644
--- a/lowpan/tests/AndroidTest.xml
+++ b/lowpan/tests/AndroidTest.xml
@@ -22,6 +22,6 @@
     <option name="test-tag" value="FrameworksLowpanApiTests" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.net.lowpan.test" />
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
     </test>
 </configuration>
diff --git a/lowpan/tests/README.md b/lowpan/tests/README.md
index d0eed95..cb5772e 100644
--- a/lowpan/tests/README.md
+++ b/lowpan/tests/README.md
@@ -37,7 +37,7 @@
 If you manually build and push the test APK to the device you can run tests using
 
 ```
-adb shell am instrument -w 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner'
+adb shell am instrument -w 'android.net.wifi.test/androidx.test.runner.AndroidJUnitRunner'
 ```
 
 ## Adding Tests
diff --git a/lowpan/tests/runtests.sh b/lowpan/tests/runtests.sh
index 040f4f0..8267a79 100755
--- a/lowpan/tests/runtests.sh
+++ b/lowpan/tests/runtests.sh
@@ -21,4 +21,4 @@
 
 adb install -r -g "$OUT/data/app/FrameworksLowpanApiTests/FrameworksLowpanApiTests.apk"
 
-adb shell am instrument -w "$@" 'android.net.lowpan.test/android.support.test.runner.AndroidJUnitRunner'
+adb shell am instrument -w "$@" 'android.net.lowpan.test/androidx.test.runner.AndroidJUnitRunner'
diff --git a/lowpan/tests/src/android/net/lowpan/LowpanInterfaceTest.java b/lowpan/tests/src/android/net/lowpan/LowpanInterfaceTest.java
index a495d3d..86f9d0e 100644
--- a/lowpan/tests/src/android/net/lowpan/LowpanInterfaceTest.java
+++ b/lowpan/tests/src/android/net/lowpan/LowpanInterfaceTest.java
@@ -23,15 +23,18 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.test.TestLooper;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
-import java.util.Map;
+
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Map;
+
 /** Unit tests for android.net.lowpan.LowpanInterface. */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
diff --git a/lowpan/tests/src/android/net/lowpan/LowpanManagerTest.java b/lowpan/tests/src/android/net/lowpan/LowpanManagerTest.java
index 3dd7504..998e8a5 100644
--- a/lowpan/tests/src/android/net/lowpan/LowpanManagerTest.java
+++ b/lowpan/tests/src/android/net/lowpan/LowpanManagerTest.java
@@ -26,8 +26,10 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.test.TestLooper;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/media/Android.bp b/media/Android.bp
index d5da6f2..88ed9c6a 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -1,9 +1,59 @@
 java_library {
-    // TODO: include media2.jar in the media apex and add it to the bootclasspath.
-    name: "media2",
+    name: "updatable-media1",
 
     srcs: [
-        ":media2-srcs",
+        ":media1-srcs",
+        ":framework-media-annotation-srcs",
+    ],
+
+    aidl: {
+        export_include_dirs: [
+            "apex/java",
+        ],
+
+        // TODO: find out a way to include only the necessary aidl files instead of dirs.
+        include_dirs: [
+            "frameworks/base/core/java",
+            "frameworks/base/media/java",
+        ],
+    },
+
+    installable: true,
+
+    // Make sure that the implementaion only relies on SDK or system APIs.
+    sdk_version: "system_current",
+}
+
+java_library {
+    name: "updatable-mediasession2",
+
+    srcs: [
+        ":mediasession2-srcs",
+        ":framework-media-annotation-srcs",
+    ],
+
+    aidl: {
+        export_include_dirs: [
+            "apex/java",
+        ],
+
+        // TODO: find out a way to include only the necessary aidl files instead of dirs.
+        include_dirs: [
+            "frameworks/base/core/java",
+        ],
+    },
+
+    installable: true,
+
+    // Make sure that the implementaion only relies on SDK or system APIs.
+    sdk_version: "system_current",
+}
+
+java_library {
+    name: "updatable-media",
+
+    srcs: [
+        ":mediaplayer2-srcs",
         ":framework-media-annotation-srcs",
     ],
 
@@ -11,26 +61,109 @@
         "mediaplayer2-protos",
     ],
 
+    installable: true,
+
     // Make sure that the implementaion only relies on SDK or system APIs.
     sdk_version: "system_current",
 }
 
 filegroup {
-    name: "media2-srcs",
+    name: "media-srcs-without-aidls",
+    srcs : [
+        ":media1-srcs-without-aidls",
+        ":mediasession2-srcs-without-aidls",
+        ":mediaplayer2-srcs",
+    ],
+}
+
+filegroup {
+    name: "media1-srcs",
     srcs: [
-        "java/android/media/CloseGuard.java",
-        "java/android/media/DataSourceCallback.java",
-        "java/android/media/DataSourceDesc.java",
-        "java/android/media/UriDataSourceDesc.java",
-        "java/android/media/FileDataSourceDesc.java",
-        "java/android/media/CallbackDataSourceDesc.java",
-        "java/android/media/VideoSize.java",
-        "java/android/media/Media2Utils.java",
-        "java/android/media/MediaPlayer2Utils.java",
-        "java/android/media/MediaPlayer2.java",
-        "java/android/media/Media2HTTPService.java",
-        "java/android/media/Media2HTTPConnection.java",
-        "java/android/media/RoutingDelegate.java",
-        "java/android/media/BufferingParams.java",
+        "apex/java/android/media/MediaMetadata.java",
+        "apex/java/android/media/MediaParceledListSlice.java",
+        "apex/java/android/media/VolumeProvider.java",
+        "apex/java/android/media/browse/MediaBrowser.java",
+        "apex/java/android/media/browse/MediaBrowserUtils.java",
+        "apex/java/android/media/session/ControllerCallbackLink.java",
+        "apex/java/android/media/session/ControllerLink.java",
+        "apex/java/android/media/session/ISession.aidl",
+        "apex/java/android/media/session/ISessionCallback.aidl",
+        "apex/java/android/media/session/ISessionController.aidl",
+        "apex/java/android/media/session/ISessionControllerCallback.aidl",
+        "apex/java/android/media/session/MediaController.java",
+        "apex/java/android/media/session/MediaSessionEngine.java",
+        "apex/java/android/media/session/MediaSessionProviderService.java",
+        "apex/java/android/media/session/PlaybackState.java",
+        "apex/java/android/media/session/SessionCallbackLink.java",
+        "apex/java/android/media/session/SessionLink.java",
+        "apex/java/android/service/media/IMediaBrowserService.aidl",
+        "apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl",
+        "apex/java/android/service/media/MediaBrowserService.java",
+    ],
+}
+
+filegroup {
+    name: "media1-srcs-without-aidls",
+    srcs: [
+        ":media1-srcs",
+    ],
+    exclude_srcs: [
+        "apex/java/android/media/session/ISession.aidl",
+        "apex/java/android/media/session/ISessionCallback.aidl",
+        "apex/java/android/media/session/ISessionController.aidl",
+        "apex/java/android/media/session/ISessionControllerCallback.aidl",
+        "apex/java/android/service/media/IMediaBrowserService.aidl",
+        "apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl",
+    ],
+}
+
+filegroup {
+    name: "mediasession2-srcs",
+    srcs: [
+        "apex/java/android/media/Controller2Link.java",
+        "apex/java/android/media/IMediaController2.aidl",
+        "apex/java/android/media/IMediaSession2.aidl",
+        "apex/java/android/media/IMediaSession2Service.aidl",
+        "apex/java/android/media/MediaConstants.java",
+        "apex/java/android/media/MediaController2.java",
+        "apex/java/android/media/MediaItem2.java",
+        "apex/java/android/media/MediaSession2.java",
+        "apex/java/android/media/MediaSession2Service.java",
+        "apex/java/android/media/Session2Command.java",
+        "apex/java/android/media/Session2CommandGroup.java",
+        "apex/java/android/media/Session2Link.java",
+        "apex/java/android/media/Session2Token.java",
+    ],
+}
+
+filegroup {
+    name: "mediasession2-srcs-without-aidls",
+    srcs: [
+        ":mediasession2-srcs",
+    ],
+    exclude_srcs: [
+        "apex/java/android/media/IMediaController2.aidl",
+        "apex/java/android/media/IMediaSession2.aidl",
+        "apex/java/android/media/IMediaSession2Service.aidl",
+    ],
+}
+
+filegroup {
+    name: "mediaplayer2-srcs",
+    srcs: [
+        "apex/java/android/media/CloseGuard.java",
+        "apex/java/android/media/DataSourceCallback.java",
+        "apex/java/android/media/DataSourceDesc.java",
+        "apex/java/android/media/UriDataSourceDesc.java",
+        "apex/java/android/media/FileDataSourceDesc.java",
+        "apex/java/android/media/CallbackDataSourceDesc.java",
+        "apex/java/android/media/VideoSize.java",
+        "apex/java/android/media/Media2Utils.java",
+        "apex/java/android/media/MediaPlayer2Utils.java",
+        "apex/java/android/media/MediaPlayer2.java",
+        "apex/java/android/media/Media2HTTPService.java",
+        "apex/java/android/media/Media2HTTPConnection.java",
+        "apex/java/android/media/RoutingDelegate.java",
+        "apex/java/android/media/BufferingParams.java",
     ],
 }
diff --git a/media/java/android/media/BufferingParams.java b/media/apex/java/android/media/BufferingParams.java
similarity index 100%
rename from media/java/android/media/BufferingParams.java
rename to media/apex/java/android/media/BufferingParams.java
diff --git a/media/java/android/media/CallbackDataSourceDesc.java b/media/apex/java/android/media/CallbackDataSourceDesc.java
similarity index 100%
rename from media/java/android/media/CallbackDataSourceDesc.java
rename to media/apex/java/android/media/CallbackDataSourceDesc.java
diff --git a/media/java/android/media/CloseGuard.java b/media/apex/java/android/media/CloseGuard.java
similarity index 100%
rename from media/java/android/media/CloseGuard.java
rename to media/apex/java/android/media/CloseGuard.java
diff --git a/media/java/android/media/Controller2Link.aidl b/media/apex/java/android/media/Controller2Link.aidl
similarity index 100%
rename from media/java/android/media/Controller2Link.aidl
rename to media/apex/java/android/media/Controller2Link.aidl
diff --git a/media/apex/java/android/media/Controller2Link.java b/media/apex/java/android/media/Controller2Link.java
new file mode 100644
index 0000000..d11f776
--- /dev/null
+++ b/media/apex/java/android/media/Controller2Link.java
@@ -0,0 +1,216 @@
+/*
+ * 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.media;
+
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+
+import java.util.Objects;
+
+/**
+ * Handles incoming commands from {@link MediaSession2} to both {@link MediaController2}.
+ * @hide
+ */
+// @SystemApi
+public final class Controller2Link implements Parcelable {
+    private static final String TAG = "Controller2Link";
+    private static final boolean DEBUG = MediaController2.DEBUG;
+
+    public static final Parcelable.Creator<Controller2Link> CREATOR =
+            new Parcelable.Creator<Controller2Link>() {
+                @Override
+                public Controller2Link createFromParcel(Parcel in) {
+                    return new Controller2Link(in);
+                }
+
+                @Override
+                public Controller2Link[] newArray(int size) {
+                    return new Controller2Link[size];
+                }
+            };
+
+
+    private final MediaController2 mController;
+    private final IMediaController2 mIController;
+
+    public Controller2Link(MediaController2 controller) {
+        mController = controller;
+        mIController = new Controller2Stub();
+    }
+
+    Controller2Link(Parcel in) {
+        mController = null;
+        mIController = IMediaController2.Stub.asInterface(in.readStrongBinder());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(mIController.asBinder());
+    }
+
+    @Override
+    public int hashCode() {
+        return mIController.asBinder().hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof Controller2Link)) {
+            return false;
+        }
+        Controller2Link other = (Controller2Link) obj;
+        return Objects.equals(mIController.asBinder(), other.mIController.asBinder());
+    }
+
+    /** Interface method for IMediaController2.notifyConnected */
+    public void notifyConnected(int seq, Bundle connectionResult) {
+        try {
+            mIController.notifyConnected(seq, connectionResult);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Interface method for IMediaController2.notifyDisonnected */
+    public void notifyDisconnected(int seq) {
+        try {
+            mIController.notifyDisconnected(seq);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Interface method for IMediaController2.notifyPlaybackActiveChanged */
+    public void notifyPlaybackActiveChanged(int seq, boolean playbackActive) {
+        try {
+            mIController.notifyPlaybackActiveChanged(seq, playbackActive);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Interface method for IMediaController2.sendSessionCommand */
+    public void sendSessionCommand(int seq, Session2Command command, Bundle args,
+            ResultReceiver resultReceiver) {
+        try {
+            mIController.sendSessionCommand(seq, command, args, resultReceiver);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Interface method for IMediaController2.cancelSessionCommand */
+    public void cancelSessionCommand(int seq) {
+        try {
+            mIController.cancelSessionCommand(seq);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Stub implementation for IMediaController2.notifyConnected */
+    public void onConnected(int seq, Bundle connectionResult) {
+        if (connectionResult == null) {
+            onDisconnected(seq);
+            return;
+        }
+        mController.onConnected(seq, connectionResult);
+    }
+
+    /** Stub implementation for IMediaController2.notifyDisonnected */
+    public void onDisconnected(int seq) {
+        mController.onDisconnected(seq);
+    }
+
+    /** Stub implementation for IMediaController2.notifyPlaybackActiveChanged */
+    public void onPlaybackActiveChanged(int seq, boolean playbackActive) {
+        mController.onPlaybackActiveChanged(seq, playbackActive);
+    }
+
+    /** Stub implementation for IMediaController2.sendSessionCommand */
+    public void onSessionCommand(int seq, Session2Command command, Bundle args,
+            ResultReceiver resultReceiver) {
+        mController.onSessionCommand(seq, command, args, resultReceiver);
+    }
+
+    /** Stub implementation for IMediaController2.cancelSessionCommand */
+    public void onCancelCommand(int seq) {
+        mController.onCancelCommand(seq);
+    }
+
+    private class Controller2Stub extends IMediaController2.Stub {
+        @Override
+        public void notifyConnected(int seq, Bundle connectionResult) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Controller2Link.this.onConnected(seq, connectionResult);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyDisconnected(int seq) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Controller2Link.this.onDisconnected(seq);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyPlaybackActiveChanged(int seq, boolean playbackActive) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Controller2Link.this.onPlaybackActiveChanged(seq, playbackActive);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void sendSessionCommand(int seq, Session2Command command, Bundle args,
+                ResultReceiver resultReceiver) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Controller2Link.this.onSessionCommand(seq, command, args, resultReceiver);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void cancelSessionCommand(int seq) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Controller2Link.this.onCancelCommand(seq);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/DataSourceCallback.java b/media/apex/java/android/media/DataSourceCallback.java
similarity index 100%
rename from media/java/android/media/DataSourceCallback.java
rename to media/apex/java/android/media/DataSourceCallback.java
diff --git a/media/java/android/media/DataSourceDesc.java b/media/apex/java/android/media/DataSourceDesc.java
similarity index 100%
rename from media/java/android/media/DataSourceDesc.java
rename to media/apex/java/android/media/DataSourceDesc.java
diff --git a/media/java/android/media/FileDataSourceDesc.java b/media/apex/java/android/media/FileDataSourceDesc.java
similarity index 100%
rename from media/java/android/media/FileDataSourceDesc.java
rename to media/apex/java/android/media/FileDataSourceDesc.java
diff --git a/media/apex/java/android/media/IMediaController2.aidl b/media/apex/java/android/media/IMediaController2.aidl
new file mode 100644
index 0000000..42c6e70
--- /dev/null
+++ b/media/apex/java/android/media/IMediaController2.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.media;
+
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.media.Session2Command;
+
+/**
+ * Interface from MediaSession2 to MediaController2.
+ * <p>
+ * Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
+ * and holds calls from session to make session owner(s) frozen.
+ * @hide
+ */
+ // Code for AML only
+oneway interface IMediaController2 {
+    void notifyConnected(int seq, in Bundle connectionResult) = 0;
+    void notifyDisconnected(int seq) = 1;
+    void notifyPlaybackActiveChanged(int seq, boolean playbackActive) = 2;
+    void sendSessionCommand(int seq, in Session2Command command, in Bundle args,
+            in ResultReceiver resultReceiver) = 3;
+    void cancelSessionCommand(int seq) = 4;
+    // Next Id : 5
+}
diff --git a/media/java/android/media/IMediaSession2.aidl b/media/apex/java/android/media/IMediaSession2.aidl
similarity index 100%
rename from media/java/android/media/IMediaSession2.aidl
rename to media/apex/java/android/media/IMediaSession2.aidl
diff --git a/media/apex/java/android/media/IMediaSession2Service.aidl b/media/apex/java/android/media/IMediaSession2Service.aidl
new file mode 100644
index 0000000..10ac1be
--- /dev/null
+++ b/media/apex/java/android/media/IMediaSession2Service.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.Bundle;
+import android.media.Controller2Link;
+
+/**
+ * Interface from MediaController2 to MediaSession2Service.
+ * <p>
+ * Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
+ * and holds calls from controller to make controller owner(s) frozen.
+ * @hide
+ */
+oneway interface IMediaSession2Service {
+    void connect(in Controller2Link caller, int seq, in Bundle connectionRequest) = 0;
+    // Next Id : 1
+}
diff --git a/media/java/android/media/Media2HTTPConnection.java b/media/apex/java/android/media/Media2HTTPConnection.java
similarity index 100%
rename from media/java/android/media/Media2HTTPConnection.java
rename to media/apex/java/android/media/Media2HTTPConnection.java
diff --git a/media/java/android/media/Media2HTTPService.java b/media/apex/java/android/media/Media2HTTPService.java
similarity index 100%
rename from media/java/android/media/Media2HTTPService.java
rename to media/apex/java/android/media/Media2HTTPService.java
diff --git a/media/java/android/media/Media2Utils.java b/media/apex/java/android/media/Media2Utils.java
similarity index 100%
rename from media/java/android/media/Media2Utils.java
rename to media/apex/java/android/media/Media2Utils.java
diff --git a/media/apex/java/android/media/MediaConstants.java b/media/apex/java/android/media/MediaConstants.java
new file mode 100644
index 0000000..65b6f55
--- /dev/null
+++ b/media/apex/java/android/media/MediaConstants.java
@@ -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.media;
+
+class MediaConstants {
+    // Bundle key for int
+    static final String KEY_PID = "android.media.key.PID";
+
+    // Bundle key for String
+    static final String KEY_PACKAGE_NAME = "android.media.key.PACKAGE_NAME";
+
+    // Bundle key for Parcelable
+    static final String KEY_SESSION2LINK = "android.media.key.SESSION2LINK";
+    static final String KEY_ALLOWED_COMMANDS = "android.media.key.ALLOWED_COMMANDS";
+    static final String KEY_PLAYBACK_ACTIVE = "android.media.key.PLAYBACK_ACTIVE";
+
+    private MediaConstants() {
+    }
+}
diff --git a/media/apex/java/android/media/MediaController2.java b/media/apex/java/android/media/MediaController2.java
new file mode 100644
index 0000000..887b447
--- /dev/null
+++ b/media/apex/java/android/media/MediaController2.java
@@ -0,0 +1,519 @@
+/*
+ * 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.media;
+
+import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS;
+import static android.media.MediaConstants.KEY_PACKAGE_NAME;
+import static android.media.MediaConstants.KEY_PID;
+import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE;
+import static android.media.MediaConstants.KEY_SESSION2LINK;
+import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
+import static android.media.Session2Command.RESULT_INFO_SKIPPED;
+import static android.media.Session2Token.TYPE_SESSION;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Allows an app to interact with an active {@link MediaSession2} or a
+ * {@link MediaSession2Service} which would provide {@link MediaSession2}. Media buttons and other
+ * commands can be sent to the session.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
+ */
+public class MediaController2 implements AutoCloseable {
+    static final String TAG = "MediaController2";
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    final ControllerCallback mCallback;
+
+    private final IBinder.DeathRecipient mDeathRecipient = () -> close();
+    private final Context mContext;
+    private final Session2Token mSessionToken;
+    private final Executor mCallbackExecutor;
+    private final Controller2Link mControllerStub;
+    private final Handler mResultHandler;
+    private final SessionServiceConnection mServiceConnection;
+
+    private final Object mLock = new Object();
+    //@GuardedBy("mLock")
+    private boolean mClosed;
+    //@GuardedBy("mLock")
+    private int mNextSeqNumber;
+    //@GuardedBy("mLock")
+    private Session2Link mSessionBinder;
+    //@GuardedBy("mLock")
+    private Session2CommandGroup mAllowedCommands;
+    //@GuardedBy("mLock")
+    private Session2Token mConnectedToken;
+    //@GuardedBy("mLock")
+    private ArrayMap<ResultReceiver, Integer> mPendingCommands;
+    //@GuardedBy("mLock")
+    private ArraySet<Integer> mRequestedCommandSeqNumbers;
+    //@GuardedBy("mLock")
+    private boolean mPlaybackActive;
+
+    /**
+     * Create a {@link MediaController2} from the {@link Session2Token}.
+     * This connects to the session and may wake up the service if it's not available.
+     *
+     * @param context Context
+     * @param token token to connect to
+     */
+    public MediaController2(@NonNull Context context, @NonNull Session2Token token) {
+        this(context, token, context.getMainExecutor(), new ControllerCallback() {});
+    }
+
+    /**
+     * Create a {@link MediaController2} from the {@link Session2Token}.
+     * This connects to the session and may wake up the service if it's not available.
+     *
+     * @param context Context
+     * @param token token to connect to
+     * @param executor executor to run callbacks on.
+     * @param callback controller callback to receive changes in.
+     */
+    public MediaController2(@NonNull Context context, @NonNull Session2Token token,
+            @NonNull Executor executor, @NonNull ControllerCallback callback) {
+        if (context == null) {
+            throw new IllegalArgumentException("context shouldn't be null");
+        }
+        if (token == null) {
+            throw new IllegalArgumentException("token shouldn't be null");
+        }
+        mContext = context;
+        mSessionToken = token;
+        mCallbackExecutor = (executor == null) ? context.getMainExecutor() : executor;
+        mCallback = (callback == null) ? new ControllerCallback() {} : callback;
+        mControllerStub = new Controller2Link(this);
+        // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
+        mResultHandler = new Handler(context.getMainLooper());
+
+        mNextSeqNumber = 0;
+        mPendingCommands = new ArrayMap<>();
+        mRequestedCommandSeqNumbers = new ArraySet<>();
+
+        boolean connectRequested;
+        if (token.getType() == TYPE_SESSION) {
+            mServiceConnection = null;
+            connectRequested = requestConnectToSession();
+        } else {
+            mServiceConnection = new SessionServiceConnection();
+            connectRequested = requestConnectToService();
+        }
+        if (!connectRequested) {
+            close();
+        }
+    }
+
+    @Override
+    public void close() {
+        synchronized (mLock) {
+            if (mClosed) {
+                // Already closed. Ignore rest of clean up code.
+                // Note: unbindService() throws IllegalArgumentException when it's called twice.
+                return;
+            }
+            mClosed = true;
+            if (mServiceConnection != null) {
+                // Note: This should be called even when the bindService() has returned false.
+                mContext.unbindService(mServiceConnection);
+            }
+            if (mSessionBinder != null) {
+                try {
+                    mSessionBinder.disconnect(mControllerStub, getNextSeqNumber());
+                    mSessionBinder.unlinkToDeath(mDeathRecipient, 0);
+                } catch (RuntimeException e) {
+                    // No-op
+                }
+            }
+            mConnectedToken = null;
+            mPendingCommands.clear();
+            mRequestedCommandSeqNumbers.clear();
+            mCallbackExecutor.execute(() -> {
+                mCallback.onDisconnected(MediaController2.this);
+            });
+            mSessionBinder = null;
+        }
+    }
+
+    /**
+     * Returns {@link Session2Token} of the connected session.
+     * If it is not connected yet, it returns {@code null}.
+     * <p>
+     * This may differ with the {@link Session2Token} from the constructor. For example, if the
+     * controller is created with the token for {@link MediaSession2Service}, this would return
+     * token for the {@link MediaSession2} in the service.
+     *
+     * @return Session2Token of the connected session, or {@code null} if not connected
+     */
+    public Session2Token getConnectedSessionToken() {
+        synchronized (mLock) {
+            return mConnectedToken;
+        }
+    }
+
+    /**
+     * Returns whether the session's playback is active.
+     *
+     * @return {@code true} if playback active. {@code false} otherwise.
+     * @see ControllerCallback#onPlaybackActiveChanged(MediaController2, boolean)
+     */
+    public boolean isPlaybackActive() {
+        synchronized (mLock) {
+            return mPlaybackActive;
+        }
+    }
+
+    /**
+     * Sends a session command to the session
+     * <p>
+     * @param command the session command
+     * @param args optional arguments
+     * @return a token which will be sent together in {@link ControllerCallback#onCommandResult}
+     *        when its result is received.
+     */
+    @NonNull
+    public Object sendSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
+        if (command == null) {
+            throw new IllegalArgumentException("command shouldn't be null");
+        }
+
+        ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) {
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                synchronized (mLock) {
+                    mPendingCommands.remove(this);
+                }
+                mCallbackExecutor.execute(() -> {
+                    mCallback.onCommandResult(MediaController2.this, this,
+                            command, new Session2Command.Result(resultCode, resultData));
+                });
+            }
+        };
+
+        synchronized (mLock) {
+            if (mSessionBinder != null) {
+                int seq = getNextSeqNumber();
+                mPendingCommands.put(resultReceiver, seq);
+                try {
+                    mSessionBinder.sendSessionCommand(mControllerStub, seq, command, args,
+                            resultReceiver);
+                } catch (RuntimeException e)  {
+                    mPendingCommands.remove(resultReceiver);
+                    resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null);
+                }
+            }
+        }
+        return resultReceiver;
+    }
+
+    /**
+     * Cancels the session command previously sent.
+     *
+     * @param token the token which is returned from {@link #sendSessionCommand}.
+     */
+    public void cancelSessionCommand(@NonNull Object token) {
+        if (token == null) {
+            throw new IllegalArgumentException("token shouldn't be null");
+        }
+        synchronized (mLock) {
+            if (mSessionBinder == null) return;
+            Integer seq = mPendingCommands.remove(token);
+            if (seq != null) {
+                mSessionBinder.cancelSessionCommand(mControllerStub, seq);
+            }
+        }
+    }
+
+    // Called by Controller2Link.onConnected
+    void onConnected(int seq, Bundle connectionResult) {
+        Session2Link sessionBinder = connectionResult.getParcelable(KEY_SESSION2LINK);
+        Session2CommandGroup allowedCommands =
+                connectionResult.getParcelable(KEY_ALLOWED_COMMANDS);
+        boolean playbackActive = connectionResult.getBoolean(KEY_PLAYBACK_ACTIVE);
+        if (DEBUG) {
+            Log.d(TAG, "notifyConnected sessionBinder=" + sessionBinder
+                    + ", allowedCommands=" + allowedCommands);
+        }
+        if (sessionBinder == null || allowedCommands == null) {
+            // Connection rejected.
+            close();
+            return;
+        }
+        synchronized (mLock) {
+            mSessionBinder = sessionBinder;
+            mAllowedCommands = allowedCommands;
+            mPlaybackActive = playbackActive;
+
+            // Implementation for the local binder is no-op,
+            // so can be used without worrying about deadlock.
+            sessionBinder.linkToDeath(mDeathRecipient, 0);
+            mConnectedToken = new Session2Token(mSessionToken.getUid(), TYPE_SESSION,
+                    mSessionToken.getPackageName(), sessionBinder);
+        }
+        mCallbackExecutor.execute(() -> {
+            mCallback.onConnected(MediaController2.this, allowedCommands);
+        });
+    }
+
+    // Called by Controller2Link.onDisconnected
+    void onDisconnected(int seq) {
+        // close() will call mCallback.onDisconnected
+        close();
+    }
+
+    // Called by Controller2Link.onPlaybackActiveChanged
+    void onPlaybackActiveChanged(int seq, boolean playbackActive) {
+        synchronized (mLock) {
+            mPlaybackActive = playbackActive;
+        }
+        mCallbackExecutor.execute(() -> {
+            mCallback.onPlaybackActiveChanged(MediaController2.this, playbackActive);
+        });
+    }
+
+    // Called by Controller2Link.onSessionCommand
+    void onSessionCommand(int seq, Session2Command command, Bundle args,
+            @Nullable ResultReceiver resultReceiver) {
+        synchronized (mLock) {
+            mRequestedCommandSeqNumbers.add(seq);
+        }
+        mCallbackExecutor.execute(() -> {
+            boolean isCanceled;
+            synchronized (mLock) {
+                isCanceled = !mRequestedCommandSeqNumbers.remove(seq);
+            }
+            if (isCanceled) {
+                resultReceiver.send(RESULT_INFO_SKIPPED, null);
+                return;
+            }
+            Session2Command.Result result = mCallback.onSessionCommand(
+                    MediaController2.this, command, args);
+            if (resultReceiver != null) {
+                if (result == null) {
+                    resultReceiver.send(Session2Command.RESULT_INFO_SKIPPED, null);
+                } else {
+                    resultReceiver.send(result.getResultCode(), result.getResultData());
+                }
+            }
+        });
+    }
+
+    // Called by Controller2Link.onSessionCommand
+    void onCancelCommand(int seq) {
+        synchronized (mLock) {
+            mRequestedCommandSeqNumbers.remove(seq);
+        }
+    }
+
+    private int getNextSeqNumber() {
+        synchronized (mLock) {
+            return mNextSeqNumber++;
+        }
+    }
+
+    private Bundle createConnectionRequest() {
+        Bundle connectionRequest = new Bundle();
+        connectionRequest.putString(KEY_PACKAGE_NAME, mContext.getPackageName());
+        connectionRequest.putInt(KEY_PID, Process.myPid());
+        return connectionRequest;
+    }
+
+    private boolean requestConnectToSession() {
+        Session2Link sessionBinder = mSessionToken.getSessionLink();
+        Bundle connectionRequest = createConnectionRequest();
+        try {
+            sessionBinder.connect(mControllerStub, getNextSeqNumber(), connectionRequest);
+        } catch (RuntimeException e) {
+            Log.w(TAG, "Failed to call connection request", e);
+            return false;
+        }
+        return true;
+    }
+
+    private boolean requestConnectToService() {
+        // Service. Needs to get fresh binder whenever connection is needed.
+        final Intent intent = new Intent(MediaSession2Service.SERVICE_INTERFACE);
+        intent.setClassName(mSessionToken.getPackageName(), mSessionToken.getServiceName());
+
+        // Use bindService() instead of startForegroundService() to start session service for three
+        // reasons.
+        // 1. Prevent session service owner's stopSelf() from destroying service.
+        //    With the startForegroundService(), service's call of stopSelf() will trigger immediate
+        //    onDestroy() calls on the main thread even when onConnect() is running in another
+        //    thread.
+        // 2. Minimize APIs for developers to take care about.
+        //    With bindService(), developers only need to take care about Service.onBind()
+        //    but Service.onStartCommand() should be also taken care about with the
+        //    startForegroundService().
+        // 3. Future support for UI-less playback
+        //    If a service wants to keep running, it should be either foreground service or
+        //    bound service. But there had been request for the feature for system apps
+        //    and using bindService() will be better fit with it.
+        synchronized (mLock) {
+            boolean result = mContext.bindService(
+                    intent, mServiceConnection, Context.BIND_AUTO_CREATE);
+            if (!result) {
+                Log.w(TAG, "bind to " + mSessionToken + " failed");
+                return false;
+            } else if (DEBUG) {
+                Log.d(TAG, "bind to " + mSessionToken + " succeeded");
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Interface for listening to change in activeness of the {@link MediaSession2}.
+     * <p>
+     * This API is not generally intended for third party application developers.
+     */
+    public abstract static class ControllerCallback {
+        /**
+         * Called when the controller is successfully connected to the session. The controller
+         * becomes available afterwards.
+         *
+         * @param controller the controller for this event
+         * @param allowedCommands commands that's allowed by the session.
+         */
+        public void onConnected(@NonNull MediaController2 controller,
+                @NonNull Session2CommandGroup allowedCommands) {}
+
+        /**
+         * Called when the session refuses the controller or the controller is disconnected from
+         * the session. The controller becomes unavailable afterwards and the callback wouldn't
+         * be called.
+         * <p>
+         * It will be also called after the {@link #close()}, so you can put clean up code here.
+         * You don't need to call {@link #close()} after this.
+         *
+         * @param controller the controller for this event
+         */
+        public void onDisconnected(@NonNull MediaController2 controller) {}
+
+        /**
+         * Called when the playback of the session's playback activeness is changed.
+         *
+         * @param controller the controller for this event
+         * @param playbackActive {@code true} if the session's playback is active.
+         *                       {@code false} otherwise.
+         * @see MediaController2#isPlaybackActive()
+         */
+        public void onPlaybackActiveChanged(@NonNull MediaController2 controller,
+                boolean playbackActive) {}
+
+        /**
+         * Called when the connected session sent a session command.
+         *
+         * @param controller the controller for this event
+         * @param command the session command
+         * @param args optional arguments
+         * @return the result for the session command. If {@code null}, RESULT_INFO_SKIPPED
+         *         will be sent to the session.
+         */
+        @Nullable
+        public Session2Command.Result onSessionCommand(@NonNull MediaController2 controller,
+                @NonNull Session2Command command, @Nullable Bundle args) {
+            return null;
+        }
+
+        /**
+         * Called when the command sent to the connected session is finished.
+         *
+         * @param controller the controller for this event
+         * @param token the token got from {@link MediaController2#sendSessionCommand}
+         * @param command the session command
+         * @param result the result of the session command
+         */
+        public void onCommandResult(@NonNull MediaController2 controller, @NonNull Object token,
+                @NonNull Session2Command command, @NonNull Session2Command.Result result) {}
+    }
+
+    // This will be called on the main thread.
+    private class SessionServiceConnection implements ServiceConnection {
+        SessionServiceConnection() {
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            // Note that it's always main-thread.
+            boolean connectRequested = false;
+            try {
+                if (DEBUG) {
+                    Log.d(TAG, "onServiceConnected " + name + " " + this);
+                }
+                // Sanity check
+                if (!mSessionToken.getPackageName().equals(name.getPackageName())) {
+                    Log.wtf(TAG, "Expected connection to " + mSessionToken.getPackageName()
+                            + " but is connected to " + name);
+                    return;
+                }
+                IMediaSession2Service iService = IMediaSession2Service.Stub.asInterface(service);
+                if (iService == null) {
+                    Log.wtf(TAG, "Service interface is missing.");
+                    return;
+                }
+                Bundle connectionRequest = createConnectionRequest();
+                iService.connect(mControllerStub, getNextSeqNumber(), connectionRequest);
+                connectRequested = true;
+            } catch (RemoteException e) {
+                Log.w(TAG, "Service " + name + " has died prematurely", e);
+            } finally {
+                if (!connectRequested) {
+                    close();
+                }
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            // Temporal lose of the binding because of the service crash. System will automatically
+            // rebind, so just no-op.
+            if (DEBUG) {
+                Log.w(TAG, "Session service " + name + " is disconnected.");
+            }
+            close();
+        }
+
+        @Override
+        public void onBindingDied(ComponentName name) {
+            // Permanent lose of the binding because of the service package update or removed.
+            // This SessionServiceRecord will be removed accordingly, but forget session binder here
+            // for sure.
+            close();
+        }
+    }
+}
diff --git a/media/apex/java/android/media/MediaItem2.java b/media/apex/java/android/media/MediaItem2.java
new file mode 100644
index 0000000..c496cf7
--- /dev/null
+++ b/media/apex/java/android/media/MediaItem2.java
@@ -0,0 +1,310 @@
+/*
+ * 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.media;
+
+import static android.media.MediaMetadata.METADATA_KEY_MEDIA_ID;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * A class with information on a single media item with the metadata information.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
+ * <p>
+ */
+public final class MediaItem2 implements Parcelable {
+    private static final String TAG = "MediaItem2";
+
+    // intentionally less than long.MAX_VALUE.
+    // Declare this first to avoid 'illegal forward reference'.
+    static final long LONG_MAX = 0x7ffffffffffffffL;
+
+    /**
+     * Used when a position is unknown.
+     *
+     * @see #getEndPosition()
+     */
+    public static final long POSITION_UNKNOWN = LONG_MAX;
+
+    public static final Parcelable.Creator<MediaItem2> CREATOR =
+            new Parcelable.Creator<MediaItem2>() {
+                @Override
+                public MediaItem2 createFromParcel(Parcel in) {
+                    return new MediaItem2(in);
+                }
+
+                @Override
+                public MediaItem2[] newArray(int size) {
+                    return new MediaItem2[size];
+                }
+            };
+
+    private static final long UNKNOWN_TIME = -1;
+
+    private final long mStartPositionMs;
+    private final long mEndPositionMs;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private MediaMetadata mMetadata;
+    @GuardedBy("mLock")
+    private final List<Pair<OnMetadataChangedListener, Executor>> mListeners = new ArrayList<>();
+
+    /**
+     * Used by {@link MediaItem2.Builder}.
+     */
+    // Note: Needs to be protected when we want to allow 3rd party player to define customized
+    //       MediaItem2.
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    MediaItem2(Builder builder) {
+        this(builder.mMetadata, builder.mStartPositionMs, builder.mEndPositionMs);
+    }
+
+    /**
+     * Used by Parcelable.Creator.
+     */
+    // Note: Needs to be protected when we want to allow 3rd party player to define customized
+    //       MediaItem2.
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    MediaItem2(Parcel in) {
+        this(in.readParcelable(MediaItem2.class.getClassLoader()), in.readLong(), in.readLong());
+    }
+
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    MediaItem2(MediaItem2 item) {
+        this(item.mMetadata, item.mStartPositionMs, item.mEndPositionMs);
+    }
+
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    MediaItem2(@Nullable MediaMetadata metadata, long startPositionMs, long endPositionMs) {
+        if (startPositionMs > endPositionMs) {
+            throw new IllegalArgumentException("Illegal start/end position: "
+                    + startPositionMs + " : " + endPositionMs);
+        }
+        if (metadata != null && metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
+            long durationMs = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
+            if (durationMs != UNKNOWN_TIME && endPositionMs != POSITION_UNKNOWN
+                    && endPositionMs > durationMs) {
+                throw new IllegalArgumentException("endPositionMs shouldn't be greater than"
+                        + " duration in the metdata, endPositionMs=" + endPositionMs
+                        + ", durationMs=" + durationMs);
+            }
+        }
+        mMetadata = metadata;
+        mStartPositionMs = startPositionMs;
+        mEndPositionMs = endPositionMs;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder(getClass().getSimpleName());
+        synchronized (mLock) {
+            sb.append("{mMetadata=").append(mMetadata);
+            sb.append(", mStartPositionMs=").append(mStartPositionMs);
+            sb.append(", mEndPositionMs=").append(mEndPositionMs);
+            sb.append('}');
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Sets metadata. If the metadata is not {@code null}, its id should be matched with this
+     * instance's media id.
+     *
+     * @param metadata metadata to update
+     * @see MediaMetadata#METADATA_KEY_MEDIA_ID
+     */
+    public void setMetadata(@Nullable MediaMetadata metadata) {
+        List<Pair<OnMetadataChangedListener, Executor>> listeners = new ArrayList<>();
+        synchronized (mLock) {
+            if (mMetadata != null && metadata != null
+                    && !TextUtils.equals(getMediaId(), metadata.getString(METADATA_KEY_MEDIA_ID))) {
+                Log.d(TAG, "MediaItem2's media ID shouldn't be changed");
+                return;
+            }
+            mMetadata = metadata;
+            listeners.addAll(mListeners);
+        }
+
+        for (Pair<OnMetadataChangedListener, Executor> pair : listeners) {
+            final OnMetadataChangedListener listener = pair.first;
+            pair.second.execute(new Runnable() {
+                @Override
+                public void run() {
+                    listener.onMetadataChanged(MediaItem2.this);
+                }
+            });
+        }
+    }
+
+    /**
+     * Gets the metadata of the media.
+     *
+     * @return metadata from the session
+     */
+    public @Nullable MediaMetadata getMetadata() {
+        synchronized (mLock) {
+            return mMetadata;
+        }
+    }
+
+    /**
+     * Return the position in milliseconds at which the playback will start.
+     * @return the position in milliseconds at which the playback will start
+     */
+    public long getStartPosition() {
+        return mStartPositionMs;
+    }
+
+    /**
+     * Return the position in milliseconds at which the playback will end.
+     * {@link #POSITION_UNKNOWN} means ending at the end of source content.
+     * @return the position in milliseconds at which the playback will end
+     */
+    public long getEndPosition() {
+        return mEndPositionMs;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mMetadata, 0);
+        dest.writeLong(mStartPositionMs);
+        dest.writeLong(mEndPositionMs);
+    }
+
+    /**
+     * Gets the media id for this item. If it's not {@code null}, it's a persistent unique key
+     * for the underlying media content.
+     *
+     * @return media Id from the session
+     */
+    @Nullable String getMediaId() {
+        synchronized (mLock) {
+            return mMetadata != null
+                    ? mMetadata.getString(METADATA_KEY_MEDIA_ID) : null;
+        }
+    }
+
+    void addOnMetadataChangedListener(Executor executor, OnMetadataChangedListener listener) {
+        synchronized (mLock) {
+            for (Pair<OnMetadataChangedListener, Executor> pair : mListeners) {
+                if (pair.first == listener) {
+                    return;
+                }
+            }
+            mListeners.add(new Pair<>(listener, executor));
+        }
+    }
+
+    void removeOnMetadataChangedListener(OnMetadataChangedListener listener) {
+        synchronized (mLock) {
+            for (int i = mListeners.size() - 1; i >= 0; i--) {
+                if (mListeners.get(i).first == listener) {
+                    mListeners.remove(i);
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
+     * Builder for {@link MediaItem2}.
+     */
+    public static class Builder {
+        @SuppressWarnings("WeakerAccess") /* synthetic access */
+        MediaMetadata mMetadata;
+        @SuppressWarnings("WeakerAccess") /* synthetic access */
+        long mStartPositionMs = 0;
+        @SuppressWarnings("WeakerAccess") /* synthetic access */
+        long mEndPositionMs = POSITION_UNKNOWN;
+
+        /**
+         * Set the metadata of this instance. {@code null} for unset.
+         *
+         * @param metadata metadata
+         * @return this instance for chaining
+         */
+        public @NonNull Builder setMetadata(@Nullable MediaMetadata metadata) {
+            mMetadata = metadata;
+            return this;
+        }
+
+        /**
+         * Sets the start position in milliseconds at which the playback will start.
+         * Any negative number is treated as 0.
+         *
+         * @param position the start position in milliseconds at which the playback will start
+         * @return the same Builder instance.
+         */
+        public @NonNull Builder setStartPosition(long position) {
+            if (position < 0) {
+                position = 0;
+            }
+            mStartPositionMs = position;
+            return this;
+        }
+
+        /**
+         * Sets the end position in milliseconds at which the playback will end.
+         * Any negative number is treated as maximum length of the media item.
+         *
+         * @param position the end position in milliseconds at which the playback will end
+         * @return the same Builder instance.
+         */
+        public @NonNull Builder setEndPosition(long position) {
+            if (position < 0) {
+                position = POSITION_UNKNOWN;
+            }
+            mEndPositionMs = position;
+            return this;
+        }
+
+        /**
+         * Build {@link MediaItem2}.
+         *
+         * @return a new {@link MediaItem2}.
+         */
+        public @NonNull MediaItem2 build() {
+            return new MediaItem2(this);
+        }
+    }
+
+    interface OnMetadataChangedListener {
+        void onMetadataChanged(MediaItem2 item);
+    }
+}
diff --git a/media/java/android/media/MediaMetadata.aidl b/media/apex/java/android/media/MediaMetadata.aidl
similarity index 100%
rename from media/java/android/media/MediaMetadata.aidl
rename to media/apex/java/android/media/MediaMetadata.aidl
diff --git a/media/apex/java/android/media/MediaMetadata.java b/media/apex/java/android/media/MediaMetadata.java
new file mode 100644
index 0000000..dea98d5
--- /dev/null
+++ b/media/apex/java/android/media/MediaMetadata.java
@@ -0,0 +1,941 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media;
+
+import android.annotation.NonNull;
+import android.annotation.StringDef;
+import android.annotation.UnsupportedAppUsage;
+import android.content.ContentResolver;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.browse.MediaBrowser;
+import android.media.session.MediaController;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Contains metadata about an item, such as the title, artist, etc.
+ */
+public final class MediaMetadata implements Parcelable {
+    private static final String TAG = "MediaMetadata";
+
+    /**
+     * @hide
+     */
+    @StringDef(prefix = { "METADATA_KEY_" }, value = {
+            METADATA_KEY_TITLE,
+            METADATA_KEY_ARTIST,
+            METADATA_KEY_ALBUM,
+            METADATA_KEY_AUTHOR,
+            METADATA_KEY_WRITER,
+            METADATA_KEY_COMPOSER,
+            METADATA_KEY_COMPILATION,
+            METADATA_KEY_DATE,
+            METADATA_KEY_GENRE,
+            METADATA_KEY_ALBUM_ARTIST,
+            METADATA_KEY_ART_URI,
+            METADATA_KEY_ALBUM_ART_URI,
+            METADATA_KEY_DISPLAY_TITLE,
+            METADATA_KEY_DISPLAY_SUBTITLE,
+            METADATA_KEY_DISPLAY_DESCRIPTION,
+            METADATA_KEY_DISPLAY_ICON_URI,
+            METADATA_KEY_MEDIA_ID,
+            METADATA_KEY_MEDIA_URI,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TextKey {}
+
+    /**
+     * @hide
+     */
+    @StringDef(prefix = { "METADATA_KEY_" }, value = {
+            METADATA_KEY_DURATION,
+            METADATA_KEY_YEAR,
+            METADATA_KEY_TRACK_NUMBER,
+            METADATA_KEY_NUM_TRACKS,
+            METADATA_KEY_DISC_NUMBER,
+            METADATA_KEY_BT_FOLDER_TYPE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LongKey {}
+
+    /**
+     * @hide
+     */
+    @StringDef(prefix = { "METADATA_KEY_" }, value = {
+            METADATA_KEY_ART,
+            METADATA_KEY_ALBUM_ART,
+            METADATA_KEY_DISPLAY_ICON,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface BitmapKey {}
+
+    /**
+     * @hide
+     */
+    @StringDef(prefix = { "METADATA_KEY_" }, value = {
+            METADATA_KEY_USER_RATING,
+            METADATA_KEY_RATING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RatingKey {}
+
+    /**
+     * The title of the media.
+     */
+    public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+
+    /**
+     * The artist of the media.
+     */
+    public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+
+    /**
+     * The duration of the media in ms. A negative duration indicates that the
+     * duration is unknown (or infinite).
+     */
+    public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+
+    /**
+     * The album title for the media.
+     */
+    public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+
+    /**
+     * The author of the media.
+     */
+    public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+
+    /**
+     * The writer of the media.
+     */
+    public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+
+    /**
+     * The composer of the media.
+     */
+    public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+
+    /**
+     * The compilation status of the media.
+     */
+    public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+
+    /**
+     * The date the media was created or published. The format is unspecified
+     * but RFC 3339 is recommended.
+     */
+    public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
+
+    /**
+     * The year the media was created or published as a long.
+     */
+    public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+
+    /**
+     * The genre of the media.
+     */
+    public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+
+    /**
+     * The track number for the media.
+     */
+    public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+
+    /**
+     * The number of tracks in the media's original source.
+     */
+    public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+
+    /**
+     * The disc number for the media's original source.
+     */
+    public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+
+    /**
+     * The artist for the album of the media's original source.
+     */
+    public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+
+    /**
+     * The artwork for the media as a {@link Bitmap}.
+     * <p>
+     * The artwork should be relatively small and may be scaled down by the
+     * system if it is too large. For higher resolution artwork
+     * {@link #METADATA_KEY_ART_URI} should be used instead.
+     */
+    public static final String METADATA_KEY_ART = "android.media.metadata.ART";
+
+    /**
+     * The artwork for the media as a Uri formatted String. The artwork can be
+     * loaded using a combination of {@link ContentResolver#openInputStream} and
+     * {@link BitmapFactory#decodeStream}.
+     * <p>
+     * For the best results, Uris should use the content:// style and support
+     * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
+     * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
+     */
+    public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+
+    /**
+     * The artwork for the album of the media's original source as a
+     * {@link Bitmap}.
+     * <p>
+     * The artwork should be relatively small and may be scaled down by the
+     * system if it is too large. For higher resolution artwork
+     * {@link #METADATA_KEY_ALBUM_ART_URI} should be used instead.
+     */
+    public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+
+    /**
+     * The artwork for the album of the media's original source as a Uri
+     * formatted String. The artwork can be loaded using a combination of
+     * {@link ContentResolver#openInputStream} and
+     * {@link BitmapFactory#decodeStream}.
+     * <p>
+     * For the best results, Uris should use the content:// style and support
+     * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
+     * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
+     */
+    public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+
+    /**
+     * The user's rating for the media.
+     *
+     * @see Rating
+     */
+    public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+
+    /**
+     * The overall rating for the media.
+     *
+     * @see Rating
+     */
+    public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
+
+    /**
+     * A title that is suitable for display to the user. This will generally be
+     * the same as {@link #METADATA_KEY_TITLE} but may differ for some formats.
+     * When displaying media described by this metadata this should be preferred
+     * if present.
+     */
+    public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
+
+    /**
+     * A subtitle that is suitable for display to the user. When displaying a
+     * second line for media described by this metadata this should be preferred
+     * to other fields if present.
+     */
+    public static final String METADATA_KEY_DISPLAY_SUBTITLE =
+            "android.media.metadata.DISPLAY_SUBTITLE";
+
+    /**
+     * A description that is suitable for display to the user. When displaying
+     * more information for media described by this metadata this should be
+     * preferred to other fields if present.
+     */
+    public static final String METADATA_KEY_DISPLAY_DESCRIPTION =
+            "android.media.metadata.DISPLAY_DESCRIPTION";
+
+    /**
+     * An icon or thumbnail that is suitable for display to the user. When
+     * displaying an icon for media described by this metadata this should be
+     * preferred to other fields if present. This must be a {@link Bitmap}.
+     * <p>
+     * The icon should be relatively small and may be scaled down by the system
+     * if it is too large. For higher resolution artwork
+     * {@link #METADATA_KEY_DISPLAY_ICON_URI} should be used instead.
+     */
+    public static final String METADATA_KEY_DISPLAY_ICON =
+            "android.media.metadata.DISPLAY_ICON";
+
+    /**
+     * A Uri formatted String for an icon or thumbnail that is suitable for
+     * display to the user. When displaying more information for media described
+     * by this metadata the display description should be preferred to other
+     * fields when present. The icon can be loaded using a combination of
+     * {@link ContentResolver#openInputStream} and
+     * {@link BitmapFactory#decodeStream}.
+     * <p>
+     * For the best results, Uris should use the content:// style and support
+     * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
+     * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
+     */
+    public static final String METADATA_KEY_DISPLAY_ICON_URI =
+            "android.media.metadata.DISPLAY_ICON_URI";
+
+    /**
+     * A String key for identifying the content. This value is specific to the
+     * service providing the content. If used, this should be a persistent
+     * unique key for the underlying content. It may be used with
+     * {@link MediaController.TransportControls#playFromMediaId(String, Bundle)}
+     * to initiate playback when provided by a {@link MediaBrowser} connected to
+     * the same app.
+     */
+    public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+
+    /**
+     * A Uri formatted String representing the content. This value is specific to the
+     * service providing the content. It may be used with
+     * {@link MediaController.TransportControls#playFromUri(Uri, Bundle)}
+     * to initiate playback when provided by a {@link MediaBrowser} connected to
+     * the same app.
+     */
+    public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
+
+    /**
+     * The bluetooth folder type of the media specified in the section 6.10.2.2 of the Bluetooth
+     * AVRCP 1.5. It should be one of the following:
+     * <ul>
+     * <li>{@link MediaDescription#BT_FOLDER_TYPE_MIXED}</li>
+     * <li>{@link MediaDescription#BT_FOLDER_TYPE_TITLES}</li>
+     * <li>{@link MediaDescription#BT_FOLDER_TYPE_ALBUMS}</li>
+     * <li>{@link MediaDescription#BT_FOLDER_TYPE_ARTISTS}</li>
+     * <li>{@link MediaDescription#BT_FOLDER_TYPE_GENRES}</li>
+     * <li>{@link MediaDescription#BT_FOLDER_TYPE_PLAYLISTS}</li>
+     * <li>{@link MediaDescription#BT_FOLDER_TYPE_YEARS}</li>
+     * </ul>
+     */
+    public static final String METADATA_KEY_BT_FOLDER_TYPE =
+            "android.media.metadata.BT_FOLDER_TYPE";
+
+    private static final @TextKey String[] PREFERRED_DESCRIPTION_ORDER = {
+            METADATA_KEY_TITLE,
+            METADATA_KEY_ARTIST,
+            METADATA_KEY_ALBUM,
+            METADATA_KEY_ALBUM_ARTIST,
+            METADATA_KEY_WRITER,
+            METADATA_KEY_AUTHOR,
+            METADATA_KEY_COMPOSER
+    };
+
+    private static final @BitmapKey String[] PREFERRED_BITMAP_ORDER = {
+            METADATA_KEY_DISPLAY_ICON,
+            METADATA_KEY_ART,
+            METADATA_KEY_ALBUM_ART
+    };
+
+    private static final @TextKey String[] PREFERRED_URI_ORDER = {
+            METADATA_KEY_DISPLAY_ICON_URI,
+            METADATA_KEY_ART_URI,
+            METADATA_KEY_ALBUM_ART_URI
+    };
+
+    private static final int METADATA_TYPE_INVALID = -1;
+    private static final int METADATA_TYPE_LONG = 0;
+    private static final int METADATA_TYPE_TEXT = 1;
+    private static final int METADATA_TYPE_BITMAP = 2;
+    private static final int METADATA_TYPE_RATING = 3;
+    private static final ArrayMap<String, Integer> METADATA_KEYS_TYPE;
+
+    static {
+        METADATA_KEYS_TYPE = new ArrayMap<String, Integer>();
+        METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_TITLE, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_SUBTITLE, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON, METADATA_TYPE_BITMAP);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON_URI, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_BT_FOLDER_TYPE, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_ID, METADATA_TYPE_TEXT);
+        METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_URI, METADATA_TYPE_TEXT);
+    }
+
+    private static final SparseArray<String> EDITOR_KEY_MAPPING;
+
+    static {
+        EDITOR_KEY_MAPPING = new SparseArray<String>();
+        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.BITMAP_KEY_ARTWORK, METADATA_KEY_ART);
+        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_OTHERS, METADATA_KEY_RATING);
+        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_USER, METADATA_KEY_USER_RATING);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_KEY_ALBUM);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
+                METADATA_KEY_ALBUM_ARTIST);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_KEY_ARTIST);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_KEY_AUTHOR);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
+                METADATA_KEY_TRACK_NUMBER);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_KEY_COMPOSER);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPILATION,
+                METADATA_KEY_COMPILATION);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_KEY_DATE);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
+                METADATA_KEY_DISC_NUMBER);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_KEY_DURATION);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_KEY_GENRE);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS,
+                METADATA_KEY_NUM_TRACKS);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_KEY_TITLE);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_KEY_WRITER);
+        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_KEY_YEAR);
+    }
+
+    private final Bundle mBundle;
+    private MediaDescription mDescription;
+
+    private MediaMetadata(Bundle bundle) {
+        mBundle = new Bundle(bundle);
+    }
+
+    private MediaMetadata(Parcel in) {
+        mBundle = in.readBundle();
+    }
+
+    /**
+     * Returns true if the given key is contained in the metadata
+     *
+     * @param key a String key
+     * @return true if the key exists in this metadata, false otherwise
+     */
+    public boolean containsKey(String key) {
+        return mBundle.containsKey(key);
+    }
+
+    /**
+     * Returns the value associated with the given key, or null if no mapping of
+     * the desired type exists for the given key or a null value is explicitly
+     * associated with the key.
+     *
+     * @param key The key the value is stored under
+     * @return a CharSequence value, or null
+     */
+    public CharSequence getText(@TextKey String key) {
+        return mBundle.getCharSequence(key);
+    }
+
+    /**
+     * Returns the text value associated with the given key as a String, or null
+     * if no mapping of the desired type exists for the given key or a null
+     * value is explicitly associated with the key. This is equivalent to
+     * calling {@link #getText getText().toString()} if the value is not null.
+     *
+     * @param key The key the value is stored under
+     * @return a String value, or null
+     */
+    public String getString(@TextKey String key) {
+        CharSequence text = getText(key);
+        if (text != null) {
+            return text.toString();
+        }
+        return null;
+    }
+
+    /**
+     * Returns the value associated with the given key, or 0L if no long exists
+     * for the given key.
+     *
+     * @param key The key the value is stored under
+     * @return a long value
+     */
+    public long getLong(@LongKey String key) {
+        return mBundle.getLong(key, 0);
+    }
+
+    /**
+     * Returns a {@link Rating} for the given key or null if no rating exists
+     * for the given key.
+     *
+     * @param key The key the value is stored under
+     * @return A {@link Rating} or null
+     */
+    public Rating getRating(@RatingKey String key) {
+        Rating rating = null;
+        try {
+            rating = mBundle.getParcelable(key);
+        } catch (Exception e) {
+            // ignore, value was not a bitmap
+            Log.w(TAG, "Failed to retrieve a key as Rating.", e);
+        }
+        return rating;
+    }
+
+    /**
+     * Returns a {@link Bitmap} for the given key or null if no bitmap exists
+     * for the given key.
+     *
+     * @param key The key the value is stored under
+     * @return A {@link Bitmap} or null
+     */
+    public Bitmap getBitmap(@BitmapKey String key) {
+        Bitmap bmp = null;
+        try {
+            bmp = mBundle.getParcelable(key);
+        } catch (Exception e) {
+            // ignore, value was not a bitmap
+            Log.w(TAG, "Failed to retrieve a key as Bitmap.", e);
+        }
+        return bmp;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeBundle(mBundle);
+    }
+
+    /**
+     * Returns the number of fields in this metadata.
+     *
+     * @return The number of fields in the metadata.
+     */
+    public int size() {
+        return mBundle.size();
+    }
+
+    /**
+     * Returns a Set containing the Strings used as keys in this metadata.
+     *
+     * @return a Set of String keys
+     */
+    public Set<String> keySet() {
+        return mBundle.keySet();
+    }
+
+    /**
+     * Returns a simple description of this metadata for display purposes.
+     *
+     * @return A simple description of this metadata.
+     */
+    public @NonNull MediaDescription getDescription() {
+        if (mDescription != null) {
+            return mDescription;
+        }
+
+        String mediaId = getString(METADATA_KEY_MEDIA_ID);
+
+        CharSequence[] text = new CharSequence[3];
+        Bitmap icon = null;
+        Uri iconUri = null;
+
+        // First handle the case where display data is set already
+        CharSequence displayText = getText(METADATA_KEY_DISPLAY_TITLE);
+        if (!TextUtils.isEmpty(displayText)) {
+            // If they have a display title use only display data, otherwise use
+            // our best bets
+            text[0] = displayText;
+            text[1] = getText(METADATA_KEY_DISPLAY_SUBTITLE);
+            text[2] = getText(METADATA_KEY_DISPLAY_DESCRIPTION);
+        } else {
+            // Use whatever fields we can
+            int textIndex = 0;
+            int keyIndex = 0;
+            while (textIndex < text.length && keyIndex < PREFERRED_DESCRIPTION_ORDER.length) {
+                CharSequence next = getText(PREFERRED_DESCRIPTION_ORDER[keyIndex++]);
+                if (!TextUtils.isEmpty(next)) {
+                    // Fill in the next empty bit of text
+                    text[textIndex++] = next;
+                }
+            }
+        }
+
+        // Get the best art bitmap we can find
+        for (int i = 0; i < PREFERRED_BITMAP_ORDER.length; i++) {
+            Bitmap next = getBitmap(PREFERRED_BITMAP_ORDER[i]);
+            if (next != null) {
+                icon = next;
+                break;
+            }
+        }
+
+        // Get the best Uri we can find
+        for (int i = 0; i < PREFERRED_URI_ORDER.length; i++) {
+            String next = getString(PREFERRED_URI_ORDER[i]);
+            if (!TextUtils.isEmpty(next)) {
+                iconUri = Uri.parse(next);
+                break;
+            }
+        }
+
+        Uri mediaUri = null;
+        String mediaUriStr = getString(METADATA_KEY_MEDIA_URI);
+        if (!TextUtils.isEmpty(mediaUriStr)) {
+            mediaUri = Uri.parse(mediaUriStr);
+        }
+
+        MediaDescription.Builder bob = new MediaDescription.Builder();
+        bob.setMediaId(mediaId);
+        bob.setTitle(text[0]);
+        bob.setSubtitle(text[1]);
+        bob.setDescription(text[2]);
+        bob.setIconBitmap(icon);
+        bob.setIconUri(iconUri);
+        bob.setMediaUri(mediaUri);
+        if (mBundle.containsKey(METADATA_KEY_BT_FOLDER_TYPE)) {
+            Bundle bundle = new Bundle();
+            bundle.putLong(MediaDescription.EXTRA_BT_FOLDER_TYPE,
+                    getLong(METADATA_KEY_BT_FOLDER_TYPE));
+            bob.setExtras(bundle);
+        }
+        mDescription = bob.build();
+
+        return mDescription;
+    }
+
+    /**
+     * Helper for getting the String key used by {@link MediaMetadata} from the
+     * integer key that {@link MediaMetadataEditor} uses.
+     *
+     * @param editorKey The key used by the editor
+     * @return The key used by this class or null if no mapping exists
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public static String getKeyFromMetadataEditorKey(int editorKey) {
+        return EDITOR_KEY_MAPPING.get(editorKey, null);
+    }
+
+    public static final Parcelable.Creator<MediaMetadata> CREATOR =
+            new Parcelable.Creator<MediaMetadata>() {
+                @Override
+                public MediaMetadata createFromParcel(Parcel in) {
+                    return new MediaMetadata(in);
+                }
+
+                @Override
+                public MediaMetadata[] newArray(int size) {
+                    return new MediaMetadata[size];
+                }
+            };
+
+    /**
+     * Compares the contents of this object to another MediaMetadata object. It
+     * does not compare Bitmaps and Ratings as the media player can choose to
+     * forgo these fields depending on how you retrieve the MediaMetadata.
+     *
+     * @param o The Metadata object to compare this object against
+     * @return Whether or not the two objects have matching fields (excluding
+     * Bitmaps and Ratings)
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+
+        if (!(o instanceof MediaMetadata)) {
+            return false;
+        }
+
+        final MediaMetadata m = (MediaMetadata) o;
+
+        for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
+            String key = METADATA_KEYS_TYPE.keyAt(i);
+            switch (METADATA_KEYS_TYPE.valueAt(i)) {
+                case METADATA_TYPE_TEXT:
+                    if (!Objects.equals(getString(key), m.getString(key))) {
+                        return false;
+                    }
+                    break;
+                case METADATA_TYPE_LONG:
+                    if (getLong(key) != m.getLong(key)) {
+                        return false;
+                    }
+                    break;
+                default:
+                    // Ignore ratings and bitmaps when comparing
+                    break;
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int hashCode = 17;
+
+        for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
+            String key = METADATA_KEYS_TYPE.keyAt(i);
+            switch (METADATA_KEYS_TYPE.valueAt(i)) {
+                case METADATA_TYPE_TEXT:
+                    hashCode = 31 * hashCode + Objects.hash(getString(key));
+                    break;
+                case METADATA_TYPE_LONG:
+                    hashCode = 31 * hashCode + Long.hashCode(getLong(key));
+                    break;
+                default:
+                    // Ignore ratings and bitmaps when comparing
+                    break;
+            }
+        }
+
+        return hashCode;
+    }
+
+    /**
+     * Use to build MediaMetadata objects. The system defined metadata keys must
+     * use the appropriate data type.
+     */
+    public static final class Builder {
+        private final Bundle mBundle;
+
+        /**
+         * Create an empty Builder. Any field that should be included in the
+         * {@link MediaMetadata} must be added.
+         */
+        public Builder() {
+            mBundle = new Bundle();
+        }
+
+        /**
+         * Create a Builder using a {@link MediaMetadata} instance to set the
+         * initial values. All fields in the source metadata will be included in
+         * the new metadata. Fields can be overwritten by adding the same key.
+         *
+         * @param source
+         */
+        public Builder(MediaMetadata source) {
+            mBundle = new Bundle(source.mBundle);
+        }
+
+        /**
+         * Create a Builder using a {@link MediaMetadata} instance to set
+         * initial values, but replace bitmaps with a scaled down copy if they
+         * are larger than maxBitmapSize.
+         *
+         * @param source The original metadata to copy.
+         * @param maxBitmapSize The maximum height/width for bitmaps contained
+         *            in the metadata.
+         * @hide
+         */
+        public Builder(MediaMetadata source, int maxBitmapSize) {
+            this(source);
+            for (String key : mBundle.keySet()) {
+                Object value = mBundle.get(key);
+                if (value != null && value instanceof Bitmap) {
+                    Bitmap bmp = (Bitmap) value;
+                    if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) {
+                        putBitmap(key, scaleBitmap(bmp, maxBitmapSize));
+                    }
+                }
+            }
+        }
+
+        /**
+         * Put a CharSequence value into the metadata. Custom keys may be used,
+         * but if the METADATA_KEYs defined in this class are used they may only
+         * be one of the following:
+         * <ul>
+         * <li>{@link #METADATA_KEY_TITLE}</li>
+         * <li>{@link #METADATA_KEY_ARTIST}</li>
+         * <li>{@link #METADATA_KEY_ALBUM}</li>
+         * <li>{@link #METADATA_KEY_AUTHOR}</li>
+         * <li>{@link #METADATA_KEY_WRITER}</li>
+         * <li>{@link #METADATA_KEY_COMPOSER}</li>
+         * <li>{@link #METADATA_KEY_DATE}</li>
+         * <li>{@link #METADATA_KEY_GENRE}</li>
+         * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
+         * <li>{@link #METADATA_KEY_ART_URI}</li>
+         * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
+         * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
+         * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
+         * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
+         * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
+         * </ul>
+         *
+         * @param key The key for referencing this value
+         * @param value The CharSequence value to store
+         * @return The Builder to allow chaining
+         */
+        public Builder putText(@TextKey String key, CharSequence value) {
+            if (METADATA_KEYS_TYPE.containsKey(key)) {
+                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
+                    throw new IllegalArgumentException("The " + key
+                            + " key cannot be used to put a CharSequence");
+                }
+            }
+            mBundle.putCharSequence(key, value);
+            return this;
+        }
+
+        /**
+         * Put a String value into the metadata. Custom keys may be used, but if
+         * the METADATA_KEYs defined in this class are used they may only be one
+         * of the following:
+         * <ul>
+         * <li>{@link #METADATA_KEY_TITLE}</li>
+         * <li>{@link #METADATA_KEY_ARTIST}</li>
+         * <li>{@link #METADATA_KEY_ALBUM}</li>
+         * <li>{@link #METADATA_KEY_AUTHOR}</li>
+         * <li>{@link #METADATA_KEY_WRITER}</li>
+         * <li>{@link #METADATA_KEY_COMPOSER}</li>
+         * <li>{@link #METADATA_KEY_DATE}</li>
+         * <li>{@link #METADATA_KEY_GENRE}</li>
+         * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
+         * <li>{@link #METADATA_KEY_ART_URI}</li>
+         * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
+         * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
+         * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
+         * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
+         * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
+         * </ul>
+         * <p>
+         * Uris for artwork should use the content:// style and support
+         * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork
+         * through {@link ContentResolver#openTypedAssetFileDescriptor(Uri,
+         * String, Bundle)}.
+         *
+         * @param key The key for referencing this value
+         * @param value The String value to store
+         * @return The Builder to allow chaining
+         */
+        public Builder putString(@TextKey String key, String value) {
+            if (METADATA_KEYS_TYPE.containsKey(key)) {
+                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
+                    throw new IllegalArgumentException("The " + key
+                            + " key cannot be used to put a String");
+                }
+            }
+            mBundle.putCharSequence(key, value);
+            return this;
+        }
+
+        /**
+         * Put a long value into the metadata. Custom keys may be used, but if
+         * the METADATA_KEYs defined in this class are used they may only be one
+         * of the following:
+         * <ul>
+         * <li>{@link #METADATA_KEY_DURATION}</li>
+         * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li>
+         * <li>{@link #METADATA_KEY_NUM_TRACKS}</li>
+         * <li>{@link #METADATA_KEY_DISC_NUMBER}</li>
+         * <li>{@link #METADATA_KEY_YEAR}</li>
+         * </ul>
+         *
+         * @param key The key for referencing this value
+         * @param value The long value to store
+         * @return The Builder to allow chaining
+         */
+        public Builder putLong(@LongKey String key, long value) {
+            if (METADATA_KEYS_TYPE.containsKey(key)) {
+                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) {
+                    throw new IllegalArgumentException("The " + key
+                            + " key cannot be used to put a long");
+                }
+            }
+            mBundle.putLong(key, value);
+            return this;
+        }
+
+        /**
+         * Put a {@link Rating} into the metadata. Custom keys may be used, but
+         * if the METADATA_KEYs defined in this class are used they may only be
+         * one of the following:
+         * <ul>
+         * <li>{@link #METADATA_KEY_RATING}</li>
+         * <li>{@link #METADATA_KEY_USER_RATING}</li>
+         * </ul>
+         *
+         * @param key The key for referencing this value
+         * @param value The Rating value to store
+         * @return The Builder to allow chaining
+         */
+        public Builder putRating(@RatingKey String key, Rating value) {
+            if (METADATA_KEYS_TYPE.containsKey(key)) {
+                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) {
+                    throw new IllegalArgumentException("The " + key
+                            + " key cannot be used to put a Rating");
+                }
+            }
+            mBundle.putParcelable(key, value);
+            return this;
+        }
+
+        /**
+         * Put a {@link Bitmap} into the metadata. Custom keys may be used, but
+         * if the METADATA_KEYs defined in this class are used they may only be
+         * one of the following:
+         * <ul>
+         * <li>{@link #METADATA_KEY_ART}</li>
+         * <li>{@link #METADATA_KEY_ALBUM_ART}</li>
+         * <li>{@link #METADATA_KEY_DISPLAY_ICON}</li>
+         * </ul>
+         * <p>
+         * Large bitmaps may be scaled down by the system when
+         * {@link android.media.session.MediaSession#setMetadata} is called.
+         * To pass full resolution images {@link Uri Uris} should be used with
+         * {@link #putString}.
+         *
+         * @param key The key for referencing this value
+         * @param value The Bitmap to store
+         * @return The Builder to allow chaining
+         */
+        public Builder putBitmap(@BitmapKey String key, Bitmap value) {
+            if (METADATA_KEYS_TYPE.containsKey(key)) {
+                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) {
+                    throw new IllegalArgumentException("The " + key
+                            + " key cannot be used to put a Bitmap");
+                }
+            }
+            mBundle.putParcelable(key, value);
+            return this;
+        }
+
+        /**
+         * Creates a {@link MediaMetadata} instance with the specified fields.
+         *
+         * @return The new MediaMetadata instance
+         */
+        public MediaMetadata build() {
+            return new MediaMetadata(mBundle);
+        }
+
+        private Bitmap scaleBitmap(Bitmap bmp, int maxSize) {
+            float maxSizeF = maxSize;
+            float widthScale = maxSizeF / bmp.getWidth();
+            float heightScale = maxSizeF / bmp.getHeight();
+            float scale = Math.min(widthScale, heightScale);
+            int height = (int) (bmp.getHeight() * scale);
+            int width = (int) (bmp.getWidth() * scale);
+            return Bitmap.createScaledBitmap(bmp, width, height, true);
+        }
+    }
+}
diff --git a/media/apex/java/android/media/MediaParceledListSlice.aidl b/media/apex/java/android/media/MediaParceledListSlice.aidl
new file mode 100644
index 0000000..5c0e5bc
--- /dev/null
+++ b/media/apex/java/android/media/MediaParceledListSlice.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/** @hide */
+parcelable MediaParceledListSlice;
diff --git a/media/apex/java/android/media/MediaParceledListSlice.java b/media/apex/java/android/media/MediaParceledListSlice.java
new file mode 100644
index 0000000..16a37d9
--- /dev/null
+++ b/media/apex/java/android/media/MediaParceledListSlice.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Transfer a large list of objects across an IPC. Splits into multiple transactions if needed.
+ * Note: Only use classes declared final in order to avoid subclasses overriding reading/writing
+ * parcel logic.
+ *
+ * TODO: Add test for sending large data
+ * @param <T> A Parcelable class which will be sent over the binder calls.
+ * @hide
+ */
+public class MediaParceledListSlice<T extends Parcelable> implements Parcelable {
+    private static final String TAG = "MediaParceledListSlice";
+    private static final boolean DEBUG = false;
+
+    private static final int MAX_IPC_SIZE = 64 * 1024; // IBinder.MAX_IPC_SIZE
+
+    final List<T> mList;
+
+    public MediaParceledListSlice(List<T> list) {
+        if (list == null) {
+            throw new IllegalArgumentException("list shouldn't be null");
+        }
+        mList = list;
+    }
+
+    MediaParceledListSlice(Parcel p) {
+        final int itemCount = p.readInt();
+        mList = new ArrayList<>(itemCount);
+        if (DEBUG) {
+            Log.d(TAG, "Retrieving " + itemCount + " items");
+        }
+        if (itemCount <= 0) {
+            return;
+        }
+
+        int i = 0;
+        while (i < itemCount) {
+            if (p.readInt() == 0) {
+                break;
+            }
+
+            final T parcelable = p.readParcelable(null);
+            mList.add(parcelable);
+
+            if (DEBUG) {
+                Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size() - 1));
+            }
+            i++;
+        }
+        if (i >= itemCount) {
+            return;
+        }
+        final IBinder retriever = p.readStrongBinder();
+        while (i < itemCount) {
+            if (DEBUG) {
+                Log.d(TAG, "Reading more @" + i + " of " + itemCount + ": retriever=" + retriever);
+            }
+            Parcel data = Parcel.obtain();
+            Parcel reply = Parcel.obtain();
+            data.writeInt(i);
+            try {
+                retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failure retrieving array; only received " + i + " of " + itemCount, e);
+                return;
+            }
+            while (i < itemCount && reply.readInt() != 0) {
+                final T parcelable = reply.readParcelable(null);
+                mList.add(parcelable);
+
+                if (DEBUG) {
+                    Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size() - 1));
+                }
+                i++;
+            }
+            reply.recycle();
+            data.recycle();
+        }
+    }
+
+    public List<T> getList() {
+        return mList;
+    }
+
+    /**
+     * Write this to another Parcel. Note that this discards the internal Parcel
+     * and should not be used anymore. This is so we can pass this to a Binder
+     * where we won't have a chance to call recycle on this.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        final int itemCount = mList.size();
+        dest.writeInt(itemCount);
+        if (DEBUG) {
+            Log.d(TAG, "Writing " + itemCount + " items");
+        }
+        if (itemCount > 0) {
+            int i = 0;
+            while (i < itemCount && dest.dataSize() < MAX_IPC_SIZE) {
+                dest.writeInt(1);
+
+                final T parcelable = mList.get(i);
+                dest.writeParcelable(parcelable, flags);
+
+                if (DEBUG) {
+                    Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
+                }
+                i++;
+            }
+            if (i < itemCount) {
+                dest.writeInt(0);
+                Binder retriever = new Binder() {
+                    @Override
+                    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                            throws RemoteException {
+                        if (code != FIRST_CALL_TRANSACTION) {
+                            return super.onTransact(code, data, reply, flags);
+                        }
+                        int i = data.readInt();
+                        if (DEBUG) {
+                            Log.d(TAG, "Writing more @" + i + " of " + itemCount);
+                        }
+                        while (i < itemCount && reply.dataSize() < MAX_IPC_SIZE) {
+                            reply.writeInt(1);
+
+                            final T parcelable = mList.get(i);
+                            reply.writeParcelable(parcelable, flags);
+
+                            if (DEBUG) {
+                                Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
+                            }
+                            i++;
+                        }
+                        if (i < itemCount) {
+                            if (DEBUG) {
+                                Log.d(TAG, "Breaking @" + i + " of " + itemCount);
+                            }
+                            reply.writeInt(0);
+                        }
+                        return true;
+                    }
+                };
+                if (DEBUG) {
+                    Log.d(TAG, "Breaking @" + i + " of " + itemCount + ": retriever=" + retriever);
+                }
+                dest.writeStrongBinder(retriever);
+            }
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        int contents = 0;
+        final List<T> list = getList();
+        for (int i = 0; i < list.size(); i++) {
+            contents |= list.get(i).describeContents();
+        }
+        return contents;
+    }
+
+    public static final Parcelable.Creator<MediaParceledListSlice> CREATOR =
+            new Parcelable.Creator<MediaParceledListSlice>() {
+        @Override
+        public MediaParceledListSlice createFromParcel(Parcel in) {
+            return new MediaParceledListSlice(in);
+        }
+
+        @Override
+        public MediaParceledListSlice[] newArray(int size) {
+            return new MediaParceledListSlice[size];
+        }
+    };
+}
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
new file mode 100644
index 0000000..a2feec2
--- /dev/null
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -0,0 +1,5304 @@
+/*
+ * 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.media;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.media.MediaDrm.KeyRequest;
+import android.media.MediaPlayer2.DrmInfo;
+import android.media.MediaPlayer2Proto.PlayerMessage;
+import android.media.MediaPlayer2Proto.Value;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+import android.os.PowerManager;
+import android.util.Log;
+import android.util.Pair;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+
+import com.android.framework.protobuf.InvalidProtocolBufferException;
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.net.HttpCookie;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * MediaPlayer2 class can be used to control playback of audio/video files and streams.
+ *
+ * <p>Topics covered here are:
+ * <ol>
+ * <li><a href="#PlayerStates">Player states</a>
+ * <li><a href="#InvalidStates">Invalid method calls</a>
+ * <li><a href="#Permissions">Permissions</a>
+ * <li><a href="#Callbacks">Callbacks</a>
+ * </ol>
+ *
+ *
+ * <h3 id="PlayerStates">Player states</h3>
+ *
+ * <p>The playback control of audio/video files is managed as a state machine.</p>
+ * <p><div style="text-align:center;"><img src="../../../images/mediaplayer2_state_diagram.png"
+ *         alt="MediaPlayer2 State diagram"
+ *         border="0" /></div></p>
+ * <p>The MediaPlayer2 object has five states:</p>
+ * <ol>
+ *     <li><p>{@link #PLAYER_STATE_IDLE}: MediaPlayer2 is in the <strong>Idle</strong>
+ *         state after it's created, or after calling {@link #reset()}.</p>
+ *
+ *         <p>While in this state, you should call
+ *         {@link #setDataSource setDataSource}. It is a good
+ *         programming practice to register an {@link EventCallback#onCallCompleted onCallCompleted}
+ *         <a href="#Callbacks">callback</a> and watch for {@link #CALL_STATUS_BAD_VALUE} and
+ *         {@link #CALL_STATUS_ERROR_IO}, which might be caused by <code>setDataSource</code>.
+ *         </p>
+ *
+ *         <p>Calling {@link #prepare()} transfers a MediaPlayer2 object to
+ *         the <strong>Prepared</strong> state. Note
+ *         that {@link #prepare()} is asynchronous. When the preparation completes,
+ *         if you register an {@link EventCallback#onInfo onInfo} <a href="#Callbacks">callback</a>,
+ *         the player executes the callback
+ *         with {@link #MEDIA_INFO_PREPARED} and transitions to the
+ *         <strong>Prepared</strong> state.</p>
+ *         </li>
+ *
+ *     <li>{@link #PLAYER_STATE_PREPARED}: A MediaPlayer object must be in the
+ *         <strong>Prepared</strong> state before playback can be started for the first time.
+ *         While in this state, you can set player properties
+ *         such as audio/sound volume and looping by invoking the corresponding set methods.
+ *         Calling {@link #play()} transfers a MediaPlayer2 object to
+ *         the <strong>Playing</strong> state.
+ *      </li>
+ *
+ *     <li>{@link #PLAYER_STATE_PLAYING}:
+ *         <p>The player plays the data source while in this state.
+ *         If you register an {@link EventCallback#onInfo onInfo} <a href="#Callbacks">callback</a>,
+ *         the player regularly executes the callback with
+ *         {@link #MEDIA_INFO_BUFFERING_UPDATE}.
+ *         This allows applications to keep track of the buffering status
+ *         while streaming audio/video.</p>
+ *
+ *         <p> When the playback reaches the end of stream, the behavior depends on whether or
+ *         not you've enabled looping by calling {@link #loopCurrent}:</p>
+ *         <ul>
+ *         <li>If the looping mode was set to <code>false</code>, the player will transfer
+ *         to the <strong>Paused</strong> state. If you registered an {@link EventCallback#onInfo
+ *         onInfo} <a href="#Callbacks">callback</a>
+ *         the player calls the callback with {@link #MEDIA_INFO_DATA_SOURCE_END} and enters
+ *         the <strong>Paused</strong> state.
+ *         </li>
+ *         <li>If the looping mode was set to <code>true</code>,
+ *         the MediaPlayer2 object remains in the <strong>Playing</strong> state and replays its
+ *         data source from the beginning.</li>
+ *         </ul>
+ *         </li>
+ *
+ *     <li>{@link #PLAYER_STATE_PAUSED}: Audio/video playback pauses while in this state.
+ *         Call {@link #play()} to resume playback from the position where it paused.</li>
+ *
+ *     <li>{@link #PLAYER_STATE_ERROR}: <p>In general, playback might fail due to various
+ *          reasons such as unsupported audio/video format, poorly interleaved
+ *          audio/video, resolution too high, streaming timeout, and others.
+ *          In addition, due to programming errors, a playback
+ *          control operation might be performed from an <a href="#InvalidStates">invalid state</a>.
+ *          In these cases the player transitions to the <strong>Error</strong> state.</p>
+ *
+ *          <p>If you register an {@link EventCallback#onError onError}}
+ *          <a href="#Callbacks">callback</a>,
+ *          the callback will be performed when entering the state. When programming errors happen,
+ *          such as calling {@link #prepare()} and
+ *          {@link #setDataSource} methods
+ *          from an <a href="#InvalidStates">invalid state</a>, the callback is called with
+ *          {@link #CALL_STATUS_INVALID_OPERATION}. The MediaPlayer2 object enters the
+ *          <strong>Error</strong> state whether or not a callback exists. </p>
+ *
+ *          <p>To recover from an error and reuse a MediaPlayer2 object that is in the <strong>
+ *          Error</strong> state,
+ *          call {@link #reset()}. The object will return to the <strong>Idle</strong>
+ *          state and all state information will be lost.</p>
+ *          </li>
+ * </ol>
+ *
+ * <p>You should follow these best practices when coding an app that uses MediaPlayer2:</p>
+ *
+ * <ul>
+ *
+ * <li>Use <a href="#Callbacks">callbacks</a> to respond to state changes and errors.</li>
+ *
+ * <li>When  a MediaPlayer2 object is no longer being used, call {@link #close()} as soon as
+ * possible to release the resources used by the internal player engine associated with the
+ * MediaPlayer2. Failure to call {@link #close()} may cause subsequent instances of
+ * MediaPlayer2 objects to fallback to software implementations or fail altogether.
+ * You cannot use MediaPlayer2
+ * after you call {@link #close()}. There is no way to bring it back to any other state.</li>
+ *
+ * <li>The current playback position can be retrieved with a call to
+ * {@link #getCurrentPosition()},
+ * which is helpful for applications such as a Music player that need to keep track of the playback
+ * progress.</li>
+ *
+ * <li>The playback position can be adjusted with a call to {@link #seekTo}. Although the
+ * asynchronous {@link #seekTo} call returns right away, the actual seek operation may take a
+ * while to finish, especially for audio/video being streamed. If you register an
+ * {@link EventCallback#onCallCompleted onCallCompleted} <a href="#Callbacks">callback</a>,
+ * the callback is
+ * called When the seek operation completes with {@link #CALL_COMPLETED_SEEK_TO}.</li>
+ *
+ * <li>You can call {@link #seekTo} from the <strong>Paused</strong> state.
+ * In this case, if you are playing a video stream and
+ * the requested position is valid  one video frame is displayed.</li>
+ *
+ * </ul>
+ *
+ * <h3 id="InvalidStates">Invalid method calls</h3>
+ *
+ * <p>The only methods you safely call from the <strong>Error</strong> state are
+ * {@link #close},
+ * {@link #reset},
+ * {@link #notifyWhenCommandLabelReached},
+ * {@link #clearPendingCommands},
+ * {@link #registerEventCallback},
+ * {@link #unregisterEventCallback}
+ * and {@link #getState}.
+ * Any other methods might throw an exception, return meaningless data, or invoke a
+ * {@link EventCallback#onCallCompleted onCallCompleted} with an error code.</p>
+ *
+ * <p>Most methods can be called from any non-Error state. They will either perform their work or
+ * silently have no effect. The following table lists the methods that will invoke a
+ * {@link EventCallback#onCallCompleted onCallCompleted} with an error code
+ * or throw an exception when they are called from the associated invalid states.</p>
+ *
+ * <table border="0" cellspacing="0" cellpadding="0">
+ * <tr><th>Method Name</th>
+ * <th>Invalid States</th></tr>
+ *
+ * <tr><td>setDataSource</td> <td>{Prepared, Paused, Playing}</td></tr>
+ * <tr><td>prepare</td> <td>{Prepared, Paused, Playing}</td></tr>
+ * <tr><td>play</td> <td>{Idle}</td></tr>
+ * <tr><td>pause</td> <td>{Idle}</td></tr>
+ * <tr><td>seekTo</td> <td>{Idle}</td></tr>
+ * <tr><td>getCurrentPosition</td> <td>{Idle}</td></tr>
+ * <tr><td>getDuration</td> <td>{Idle}</td></tr>
+ * <tr><td>getBufferedPosition</td> <td>{Idle}</td></tr>
+ * <tr><td>getTrackInfo</td> <td>{Idle}</td></tr>
+ * <tr><td>getSelectedTrack</td> <td>{Idle}</td></tr>
+ * <tr><td>selectTrack</td> <td>{Idle}</td></tr>
+ * <tr><td>deselectTrack</td> <td>{Idle}</td></tr>
+ * </table>
+ *
+ * <h3 id="Permissions">Permissions</h3>
+ * <p>This class requires the {@link android.Manifest.permission#INTERNET} permission
+ * when used with network-based content.
+ *
+ * <h3 id="Callbacks">Callbacks</h3>
+ * <p>Many errors do not result in a transition to the  <strong>Error</strong> state.
+ * It is good programming practice to register callback listeners using
+ * {@link #registerEventCallback}.
+ * You can receive a callback at any time and from any state.</p>
+ *
+ * <p>If it's important for your app to respond to state changes (for instance, to update the
+ * controls on a transport UI), you should register an
+ * {@link EventCallback#onCallCompleted onCallCompleted} and
+ * detect state change commands by testing the <code>what</code> parameter for a callback from one
+ * of the state transition methods: {@link #CALL_COMPLETED_PREPARE}, {@link #CALL_COMPLETED_PLAY},
+ * and {@link #CALL_COMPLETED_PAUSE}.
+ * Then check the <code>status</code> parameter. The value {@link #CALL_STATUS_NO_ERROR} indicates a
+ * successful transition. Any other value will be an error. Call {@link #getState()} to
+ * determine the current state. </p>
+ */
+public class MediaPlayer2 implements AutoCloseable
+                                            , AudioRouting {
+    static {
+        System.loadLibrary("media2_jni");
+        native_init();
+    }
+
+    private static native void native_init();
+
+    private static final int NEXT_SOURCE_STATE_ERROR = -1;
+    private static final int NEXT_SOURCE_STATE_INIT = 0;
+    private static final int NEXT_SOURCE_STATE_PREPARING = 1;
+    private static final int NEXT_SOURCE_STATE_PREPARED = 2;
+
+    private static final String TAG = "MediaPlayer2";
+
+    private Context mContext;
+
+    private long mNativeContext;  // accessed by native methods
+    private long mNativeSurfaceTexture;  // accessed by native methods
+    private int mListenerContext;  // accessed by native methods
+    private SurfaceHolder mSurfaceHolder;
+    private PowerManager.WakeLock mWakeLock = null;
+    private boolean mScreenOnWhilePlaying;
+    private boolean mStayAwake;
+
+    private final Object mSrcLock = new Object();
+    //--- guarded by |mSrcLock| start
+    private SourceInfo mCurrentSourceInfo;
+    private final Queue<SourceInfo> mNextSourceInfos = new ConcurrentLinkedQueue<>();
+    //--- guarded by |mSrcLock| end
+    private final AtomicLong mSrcIdGenerator = new AtomicLong(0);
+
+    private volatile float mVolume = 1.0f;
+    private VideoSize mVideoSize = new VideoSize(0, 0);
+
+    private static ExecutorService sDrmThreadPool = Executors.newCachedThreadPool();
+
+    // Creating a dummy audio track, used for keeping session id alive
+    private final Object mSessionIdLock = new Object();
+    @GuardedBy("mSessionIdLock")
+    private AudioTrack mDummyAudioTrack;
+
+    private HandlerThread mHandlerThread;
+    private final TaskHandler mTaskHandler;
+    private final Object mTaskLock = new Object();
+    @GuardedBy("mTaskLock")
+    private final List<Task> mPendingTasks = new LinkedList<>();
+    @GuardedBy("mTaskLock")
+    private Task mCurrentTask;
+    private final AtomicLong mTaskIdGenerator = new AtomicLong(0);
+
+    @GuardedBy("mTaskLock")
+    boolean mIsPreviousCommandSeekTo = false;
+    // |mPreviousSeekPos| and |mPreviousSeekMode| are valid only when |mIsPreviousCommandSeekTo|
+    // is true, and they are accessed on |mHandlerThread| only.
+    long mPreviousSeekPos = -1;
+    int mPreviousSeekMode = SEEK_PREVIOUS_SYNC;
+
+    @GuardedBy("this")
+    private boolean mReleased;
+
+    private final CloseGuard mGuard = CloseGuard.get();
+
+    /**
+     * Default constructor.
+     * <p>When done with the MediaPlayer2, you should call {@link #close()},
+     * to free the resources. If not released, too many MediaPlayer2 instances may
+     * result in an exception.</p>
+     */
+    public MediaPlayer2(Context context) {
+        mGuard.open("close");
+
+        mContext = context;
+        mHandlerThread = new HandlerThread("MediaPlayer2TaskThread");
+        mHandlerThread.start();
+        Looper looper = mHandlerThread.getLooper();
+        mTaskHandler = new TaskHandler(this, looper);
+        AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        int sessionId = am.generateAudioSessionId();
+        keepAudioSessionIdAlive(sessionId);
+
+        /* Native setup requires a weak reference to our object.
+         * It's easier to create it here than in C++.
+         */
+        native_setup(sessionId, new WeakReference<MediaPlayer2>(this));
+    }
+
+    private native void native_setup(int sessionId, Object mediaplayer2This);
+
+    /**
+     * Releases the resources held by this {@code MediaPlayer2} object.
+     *
+     * It is considered good practice to call this method when you're
+     * done using the MediaPlayer2. In particular, whenever an Activity
+     * of an application is paused (its onPause() method is called),
+     * or stopped (its onStop() method is called), this method should be
+     * invoked to release the MediaPlayer2 object, unless the application
+     * has a special need to keep the object around. In addition to
+     * unnecessary resources (such as memory and instances of codecs)
+     * being held, failure to call this method immediately if a
+     * MediaPlayer2 object is no longer needed may also lead to
+     * continuous battery consumption for mobile devices, and playback
+     * failure for other applications if no multiple instances of the
+     * same codec are supported on a device. Even if multiple instances
+     * of the same codec are supported, some performance degradation
+     * may be expected when unnecessary multiple instances are used
+     * at the same time.
+     *
+     * {@code close()} may be safely called after a prior {@code close()}.
+     * This class implements the Java {@code AutoCloseable} interface and
+     * may be used with try-with-resources.
+     */
+    // This is a synchronous call.
+    @Override
+    public void close() {
+        synchronized (mGuard) {
+            mGuard.close();
+        }
+        release();
+    }
+
+    private synchronized void release() {
+        if (mReleased) {
+            return;
+        }
+        stayAwake(false);
+        updateSurfaceScreenOn();
+        synchronized (mEventCbLock) {
+            mEventCallbackRecords.clear();
+        }
+        if (mHandlerThread != null) {
+            mHandlerThread.quitSafely();
+            mHandlerThread = null;
+        }
+
+        clearSourceInfos();
+
+        // Modular DRM clean up
+        synchronized (mDrmEventCallbackLock) {
+            mDrmEventCallback = null;
+        }
+
+        native_release();
+
+        synchronized (mSessionIdLock) {
+            mDummyAudioTrack.release();
+        }
+
+        mReleased = true;
+    }
+
+    private native void native_release();
+
+    // Have to declare protected for finalize() since it is protected
+    // in the base class Object.
+    @Override
+    protected void finalize() throws Throwable {
+        if (mGuard != null) {
+            mGuard.warnIfOpen();
+        }
+
+        close();
+        native_finalize();
+    }
+
+    private native void native_finalize();
+
+    /**
+     * 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().
+     */
+    // This is a synchronous call.
+    public void reset() {
+        clearSourceInfos();
+
+        stayAwake(false);
+        native_reset();
+
+        AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        int sessionId = am.generateAudioSessionId();
+        keepAudioSessionIdAlive(sessionId);
+
+        // make sure none of the listeners get called anymore
+        if (mTaskHandler != null) {
+            mTaskHandler.removeCallbacksAndMessages(null);
+        }
+
+    }
+
+    private native void native_reset();
+
+    /**
+     * Starts or resumes playback. If playback had previously been paused,
+     * playback will continue from where it was paused. If playback had
+     * reached end of stream and been paused, or never started before,
+     * playback will start at the beginning.
+     *
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object play() {
+        return addTask(new Task(CALL_COMPLETED_PLAY, false) {
+            @Override
+            void process() {
+                stayAwake(true);
+                native_start();
+            }
+        });
+    }
+
+    private native void native_start() throws IllegalStateException;
+
+    /**
+     * Prepares the player for playback, asynchronously.
+     *
+     * After setting the datasource and the display surface, you need to call prepare().
+     *
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object prepare() {
+        return addTask(new Task(CALL_COMPLETED_PREPARE, true) {
+            @Override
+            void process() {
+                native_prepare();
+            }
+        });
+    }
+
+    private native void native_prepare();
+
+    /**
+     * Pauses playback. Call play() to resume.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object pause() {
+        return addTask(new Task(CALL_COMPLETED_PAUSE, false) {
+            @Override
+            void process() {
+                stayAwake(false);
+
+                native_pause();
+            }
+        });
+    }
+
+    private native void native_pause() throws IllegalStateException;
+
+    /**
+     * Tries to play next data source if applicable.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object skipToNext() {
+        return addTask(new Task(CALL_COMPLETED_SKIP_TO_NEXT, false) {
+            @Override
+            void process() {
+                if (getState() == PLAYER_STATE_PLAYING) {
+                    pause();
+                }
+                playNextDataSource();
+            }
+        });
+    }
+
+    /**
+     * Gets the current playback position.
+     *
+     * @return the current position in milliseconds
+     */
+    public native long getCurrentPosition();
+
+    /**
+     * Gets the duration of the current data source.
+     * Same as {@link #getDuration(DataSourceDesc)} with
+     * {@code dsd = getCurrentDataSource()}.
+     *
+     * @return the duration in milliseconds, if no duration is available
+     *         (for example, if streaming live content), -1 is returned.
+     * @throws NullPointerException if current data source is null
+     */
+    public long getDuration() {
+        return getDuration(getCurrentDataSource());
+    }
+
+    /**
+     * Gets the duration of the dsd.
+     *
+     * @param dsd the descriptor of data source of which you want to get duration
+     * @return the duration in milliseconds, if no duration is available
+     *         (for example, if streaming live content), -1 is returned.
+     * @throws NullPointerException if dsd is null
+     */
+    public long getDuration(@NonNull DataSourceDesc dsd) {
+        if (dsd == null) {
+            throw new NullPointerException("non-null dsd is expected");
+        }
+        SourceInfo sourceInfo = getSourceInfo(dsd);
+        if (sourceInfo == null) {
+            return -1;
+        }
+
+        return native_getDuration(sourceInfo.mId);
+    }
+
+    private native long native_getDuration(long srcId);
+
+    /**
+     * Gets the buffered media source position of current data source.
+     * Same as {@link #getBufferedPosition(DataSourceDesc)} with
+     * {@code dsd = getCurrentDataSource()}.
+     *
+     * @return the current buffered media source position in milliseconds
+     * @throws NullPointerException if current data source is null
+     */
+    public long getBufferedPosition() {
+        return getBufferedPosition(getCurrentDataSource());
+    }
+
+    /**
+     * Gets the buffered media source position of given dsd.
+     * For example a buffering update of 8000 milliseconds when 5000 milliseconds of the content
+     * has already been played indicates that the next 3000 milliseconds of the
+     * content to play has been buffered.
+     *
+     * @param dsd the descriptor of data source of which you want to get buffered position
+     * @return the current buffered media source position in milliseconds
+     * @throws NullPointerException if dsd is null
+     */
+    public long getBufferedPosition(@NonNull DataSourceDesc dsd) {
+        if (dsd == null) {
+            throw new NullPointerException("non-null dsd is expected");
+        }
+        SourceInfo sourceInfo = getSourceInfo(dsd);
+        if (sourceInfo == null) {
+            return 0;
+        }
+
+        // Use cached buffered percent for now.
+        int bufferedPercentage = sourceInfo.mBufferedPercentage.get();
+
+        long duration = getDuration(dsd);
+        if (duration < 0) {
+            duration = 0;
+        }
+
+        return duration * bufferedPercentage / 100;
+    }
+
+    /**
+     * MediaPlayer2 has not been prepared or just has been reset.
+     * In this state, MediaPlayer2 doesn't fetch data.
+     */
+    public static final int PLAYER_STATE_IDLE = 1001;
+
+    /**
+     * MediaPlayer2 has been just prepared.
+     * In this state, MediaPlayer2 just fetches data from media source,
+     * but doesn't actively render data.
+     */
+    public static final int PLAYER_STATE_PREPARED = 1002;
+
+    /**
+     * MediaPlayer2 is paused.
+     * In this state, MediaPlayer2 has allocated resources to construct playback
+     * pipeline, but it doesn't actively render data.
+     */
+    public static final int PLAYER_STATE_PAUSED = 1003;
+
+    /**
+     * MediaPlayer2 is actively playing back data.
+     */
+    public static final int PLAYER_STATE_PLAYING = 1004;
+
+    /**
+     * MediaPlayer2 has hit some fatal error and cannot continue playback.
+     */
+    public static final int PLAYER_STATE_ERROR = 1005;
+
+    /**
+     * @hide
+     */
+    @IntDef(flag = false, prefix = "MEDIAPLAYER2_STATE", value = {
+        PLAYER_STATE_IDLE,
+        PLAYER_STATE_PREPARED,
+        PLAYER_STATE_PAUSED,
+        PLAYER_STATE_PLAYING,
+        PLAYER_STATE_ERROR })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MediaPlayer2State {}
+
+    /**
+     * Gets the current player state.
+     *
+     * @return the current player state.
+     */
+    public @MediaPlayer2State int getState() {
+        return native_getState();
+    }
+
+    private native int native_getState();
+
+    /**
+     * Sets the audio attributes for this MediaPlayer2.
+     * See {@link AudioAttributes} for how to build and configure an instance of this class.
+     * You must call this method before {@link #play()} and {@link #pause()} in order
+     * for the audio attributes to become effective thereafter.
+     * @param attributes a non-null set of audio attributes
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object setAudioAttributes(@NonNull AudioAttributes attributes) {
+        return addTask(new Task(CALL_COMPLETED_SET_AUDIO_ATTRIBUTES, false) {
+            @Override
+            void process() {
+                if (attributes == null) {
+                    final String msg = "Cannot set AudioAttributes to null";
+                    throw new IllegalArgumentException(msg);
+                }
+                native_setAudioAttributes(attributes);
+            }
+        });
+    }
+
+    // return true if the parameter is set successfully, false otherwise
+    private native boolean native_setAudioAttributes(AudioAttributes audioAttributes);
+
+    /**
+     * Gets the audio attributes for this MediaPlayer2.
+     * @return attributes a set of audio attributes
+     */
+    public @NonNull AudioAttributes getAudioAttributes() {
+        return native_getAudioAttributes();
+    }
+
+    private native AudioAttributes native_getAudioAttributes();
+
+    /**
+     * Sets the data source as described by a DataSourceDesc.
+     * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor}
+     * in the {@link FileDataSourceDesc} will be closed by the player.
+     *
+     * @param dsd the descriptor of data source you want to play
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object setDataSource(@NonNull DataSourceDesc dsd) {
+        return addTask(new Task(CALL_COMPLETED_SET_DATA_SOURCE, false) {
+            @Override
+            void process() throws IOException {
+                checkDataSourceDesc(dsd);
+                int state = getState();
+                try {
+                    if (state != PLAYER_STATE_ERROR && state != PLAYER_STATE_IDLE) {
+                        throw new IllegalStateException("called in wrong state " + state);
+                    }
+
+                    synchronized (mSrcLock) {
+                        setCurrentSourceInfo_l(new SourceInfo(dsd));
+                        handleDataSource(true /* isCurrent */, dsd, mCurrentSourceInfo.mId);
+                    }
+                } finally {
+                    dsd.close();
+                }
+            }
+
+        });
+    }
+
+    /**
+     * Sets a single data source as described by a DataSourceDesc which will be played
+     * after current data source is finished.
+     * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor}
+     * in the {@link FileDataSourceDesc} will be closed by the player.
+     *
+     * @param dsd the descriptor of data source you want to play after current one
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object setNextDataSource(@NonNull DataSourceDesc dsd) {
+        return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCE, false) {
+            @Override
+            void process() {
+                checkDataSourceDesc(dsd);
+                synchronized (mSrcLock) {
+                    clearNextSourceInfos_l();
+                    mNextSourceInfos.add(new SourceInfo(dsd));
+                }
+                prepareNextDataSource();
+            }
+        });
+    }
+
+    /**
+     * Sets a list of data sources to be played sequentially after current data source is done.
+     * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor}
+     * in the {@link FileDataSourceDesc} will be closed by the player.
+     *
+     * @param dsds the list of data sources you want to play after current one
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object setNextDataSources(@NonNull List<DataSourceDesc> dsds) {
+        return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCES, false) {
+            @Override
+            void process() {
+                if (dsds == null || dsds.size() == 0) {
+                    throw new IllegalArgumentException("data source list cannot be null or empty.");
+                }
+                boolean hasError = false;
+                for (DataSourceDesc dsd : dsds) {
+                    if (dsd == null) {
+                        hasError = true;
+                        continue;
+                    }
+                    if (dsd instanceof FileDataSourceDesc) {
+                        FileDataSourceDesc fdsd = (FileDataSourceDesc) dsd;
+                        if (fdsd.isPFDClosed()) {
+                            hasError = true;
+                            continue;
+                        }
+
+                        fdsd.incCount();
+                    }
+                }
+                if (hasError) {
+                    for (DataSourceDesc dsd : dsds) {
+                        if (dsd != null) {
+                            dsd.close();
+                        }
+                    }
+                    throw new IllegalArgumentException("invalid data source list");
+                }
+
+                synchronized (mSrcLock) {
+                    clearNextSourceInfos_l();
+                    for (DataSourceDesc dsd : dsds) {
+                        mNextSourceInfos.add(new SourceInfo(dsd));
+                    }
+                }
+                prepareNextDataSource();
+            }
+        });
+    }
+
+    // throws IllegalArgumentException if dsd is null or underline PFD of dsd has been closed.
+    private void checkDataSourceDesc(DataSourceDesc dsd) {
+        if (dsd == null) {
+            throw new IllegalArgumentException("dsd is expected to be non null");
+        }
+        if (dsd instanceof FileDataSourceDesc) {
+            FileDataSourceDesc fdsd = (FileDataSourceDesc) dsd;
+            if (fdsd.isPFDClosed()) {
+                throw new IllegalArgumentException("the underline FileDescriptor has been closed");
+            }
+            fdsd.incCount();
+        }
+    }
+
+    /**
+     * Removes all data sources pending to be played.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object clearNextDataSources() {
+        return addTask(new Task(CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, false) {
+            @Override
+            void process() {
+                synchronized (mSrcLock) {
+                    clearNextSourceInfos_l();
+                }
+            }
+        });
+    }
+
+    /**
+     * Gets the current data source as described by a DataSourceDesc.
+     *
+     * @return the current DataSourceDesc
+     */
+    public @Nullable DataSourceDesc getCurrentDataSource() {
+        synchronized (mSrcLock) {
+            return mCurrentSourceInfo == null ? null : mCurrentSourceInfo.mDSD;
+        }
+    }
+
+    private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd, long srcId)
+            throws IOException {
+        Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null");
+
+        if (dsd instanceof CallbackDataSourceDesc) {
+            CallbackDataSourceDesc cbDSD = (CallbackDataSourceDesc) dsd;
+            handleDataSource(isCurrent,
+                             srcId,
+                             cbDSD.getDataSourceCallback(),
+                             cbDSD.getStartPosition(),
+                             cbDSD.getEndPosition());
+        } else if (dsd instanceof FileDataSourceDesc) {
+            FileDataSourceDesc fileDSD = (FileDataSourceDesc) dsd;
+            handleDataSource(isCurrent,
+                             srcId,
+                             fileDSD.getParcelFileDescriptor(),
+                             fileDSD.getOffset(),
+                             fileDSD.getLength(),
+                             fileDSD.getStartPosition(),
+                             fileDSD.getEndPosition());
+        } else if (dsd instanceof UriDataSourceDesc) {
+            UriDataSourceDesc uriDSD = (UriDataSourceDesc) dsd;
+            handleDataSource(isCurrent,
+                             srcId,
+                             uriDSD.getContext(),
+                             uriDSD.getUri(),
+                             uriDSD.getHeaders(),
+                             uriDSD.getCookies(),
+                             uriDSD.getStartPosition(),
+                             uriDSD.getEndPosition());
+        } else {
+            throw new IllegalArgumentException("Unsupported DataSourceDesc. " + dsd.toString());
+        }
+    }
+
+    /**
+     * To provide cookies for the subsequent HTTP requests, you can install your own default cookie
+     * handler and use other variants of setDataSource APIs instead. Alternatively, you can use
+     * this API to pass the cookies as a list of HttpCookie. If the app has not installed
+     * a CookieHandler already, this API creates a CookieManager and populates its CookieStore with
+     * the provided cookies. If the app has installed its own handler already, this API requires the
+     * handler to be of CookieManager type such that the API can update the manager’s CookieStore.
+     *
+     * <p><strong>Note</strong> that the cross domain redirection is allowed by default,
+     * but that can be changed with key/value pairs through the headers parameter with
+     * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to
+     * disallow or allow cross domain redirection.
+     *
+     * @throws IllegalArgumentException if cookies are provided and the installed handler is not
+     *                                  a CookieManager
+     * @throws IllegalStateException    if it is called in an invalid state
+     * @throws NullPointerException     if context or uri is null
+     * @throws IOException              if uri has a file scheme and an I/O error occurs
+     */
+    private void handleDataSource(
+            boolean isCurrent, long srcId,
+            @NonNull Context context, @NonNull Uri uri,
+            @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies,
+            long startPos, long endPos)
+            throws IOException {
+        // The context and URI usually belong to the calling user. Get a resolver for that user.
+        final ContentResolver resolver = context.getContentResolver();
+        final String scheme = uri.getScheme();
+        if (ContentResolver.SCHEME_FILE.equals(scheme)) {
+            handleDataSource(isCurrent, srcId, uri.getPath(), null, null, startPos, endPos);
+            return;
+        }
+
+        final int ringToneType = RingtoneManager.getDefaultType(uri);
+        try {
+            AssetFileDescriptor afd;
+            // Try requested Uri locally first
+            if (ContentResolver.SCHEME_CONTENT.equals(scheme) && ringToneType != -1) {
+                afd = RingtoneManager.openDefaultRingtoneUri(context, uri);
+                if (attemptDataSource(isCurrent, srcId, afd, startPos, endPos)) {
+                    return;
+                }
+                final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(
+                        context, ringToneType);
+                afd = resolver.openAssetFileDescriptor(actualUri, "r");
+            } else {
+                afd = resolver.openAssetFileDescriptor(uri, "r");
+            }
+            if (attemptDataSource(isCurrent, srcId, afd, startPos, endPos)) {
+                return;
+            }
+        } catch (NullPointerException | SecurityException | IOException ex) {
+            Log.w(TAG, "Couldn't open " + uri + ": " + ex);
+            // Fallback to media server
+        }
+        handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies, startPos, endPos);
+    }
+
+    private boolean attemptDataSource(boolean isCurrent, long srcId, AssetFileDescriptor afd,
+            long startPos, long endPos) throws IOException {
+        try {
+            if (afd.getDeclaredLength() < 0) {
+                handleDataSource(isCurrent,
+                        srcId,
+                        ParcelFileDescriptor.dup(afd.getFileDescriptor()),
+                        0,
+                        DataSourceDesc.LONG_MAX,
+                        startPos,
+                        endPos);
+            } else {
+                handleDataSource(isCurrent,
+                        srcId,
+                        ParcelFileDescriptor.dup(afd.getFileDescriptor()),
+                        afd.getStartOffset(),
+                        afd.getDeclaredLength(),
+                        startPos,
+                        endPos);
+            }
+            return true;
+        } catch (NullPointerException | SecurityException | IOException ex) {
+            Log.w(TAG, "Couldn't open srcId:" + srcId + ": " + ex);
+            return false;
+        } finally {
+            if (afd != null) {
+                afd.close();
+            }
+        }
+    }
+
+    private void handleDataSource(
+            boolean isCurrent, long srcId,
+            String path, Map<String, String> headers, List<HttpCookie> cookies,
+            long startPos, long endPos)
+            throws IOException {
+        String[] keys = null;
+        String[] values = null;
+
+        if (headers != null) {
+            keys = new String[headers.size()];
+            values = new String[headers.size()];
+
+            int i = 0;
+            for (Map.Entry<String, String> entry: headers.entrySet()) {
+                keys[i] = entry.getKey();
+                values[i] = entry.getValue();
+                ++i;
+            }
+        }
+        handleDataSource(isCurrent, srcId, path, keys, values, cookies, startPos, endPos);
+    }
+
+    private void handleDataSource(boolean isCurrent, long srcId,
+            String path, String[] keys, String[] values, List<HttpCookie> cookies,
+            long startPos, long endPos)
+            throws IOException {
+        final Uri uri = Uri.parse(path);
+        final String scheme = uri.getScheme();
+        if ("file".equals(scheme)) {
+            path = uri.getPath();
+        } else if (scheme != null) {
+            // handle non-file sources
+            Media2Utils.storeCookies(cookies);
+            nativeHandleDataSourceUrl(
+                    isCurrent,
+                    srcId,
+                    Media2HTTPService.createHTTPService(path),
+                    path,
+                    keys,
+                    values,
+                    startPos,
+                    endPos);
+            return;
+        }
+
+        final File file = new File(path);
+        if (file.exists()) {
+            FileInputStream is = new FileInputStream(file);
+            FileDescriptor fd = is.getFD();
+            handleDataSource(isCurrent, srcId, ParcelFileDescriptor.dup(fd),
+                    0, DataSourceDesc.LONG_MAX, startPos, endPos);
+            is.close();
+        } else {
+            throw new IOException("handleDataSource failed.");
+        }
+    }
+
+    private native void nativeHandleDataSourceUrl(
+            boolean isCurrent, long srcId,
+            Media2HTTPService httpService, String path, String[] keys, String[] values,
+            long startPos, long endPos)
+            throws IOException;
+
+    /**
+     * Sets the data source (FileDescriptor) to use. The FileDescriptor must be
+     * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
+     * to close the file descriptor. It is safe to do so as soon as this call returns.
+     *
+     * @throws IllegalStateException if it is called in an invalid state
+     * @throws IllegalArgumentException if fd is not a valid FileDescriptor
+     * @throws IOException if fd can not be read
+     */
+    private void handleDataSource(
+            boolean isCurrent, long srcId,
+            ParcelFileDescriptor pfd, long offset, long length,
+            long startPos, long endPos) throws IOException {
+        nativeHandleDataSourceFD(isCurrent, srcId, pfd.getFileDescriptor(), offset, length,
+                startPos, endPos);
+    }
+
+    private native void nativeHandleDataSourceFD(boolean isCurrent, long srcId,
+            FileDescriptor fd, long offset, long length,
+            long startPos, long endPos) throws IOException;
+
+    /**
+     * @throws IllegalStateException if it is called in an invalid state
+     * @throws IllegalArgumentException if dataSource is not a valid DataSourceCallback
+     */
+    private void handleDataSource(boolean isCurrent, long srcId, DataSourceCallback dataSource,
+            long startPos, long endPos) {
+        nativeHandleDataSourceCallback(isCurrent, srcId, dataSource, startPos, endPos);
+    }
+
+    private native void nativeHandleDataSourceCallback(
+            boolean isCurrent, long srcId, DataSourceCallback dataSource,
+            long startPos, long endPos);
+
+    // return true if there is a next data source, false otherwise.
+    // This function should be always called on |mHandlerThread|.
+    private boolean prepareNextDataSource() {
+        HandlerThread handlerThread = mHandlerThread;
+        if (handlerThread != null && Looper.myLooper() != handlerThread.getLooper()) {
+            Log.e(TAG, "prepareNextDataSource: called on wrong looper");
+        }
+
+        boolean hasNextDSD;
+        int state = getState();
+        synchronized (mSrcLock) {
+            hasNextDSD = !mNextSourceInfos.isEmpty();
+            if (state == PLAYER_STATE_ERROR || state == PLAYER_STATE_IDLE) {
+                // Current source has not been prepared yet.
+                return hasNextDSD;
+            }
+
+            SourceInfo nextSource = mNextSourceInfos.peek();
+            if (!hasNextDSD || nextSource.mStateAsNextSource != NEXT_SOURCE_STATE_INIT) {
+                // There is no next source or it's in preparing or prepared state.
+                return hasNextDSD;
+            }
+
+            try {
+                nextSource.mStateAsNextSource = NEXT_SOURCE_STATE_PREPARING;
+                handleDataSource(false /* isCurrent */, nextSource.mDSD, nextSource.mId);
+            } catch (Exception e) {
+                Message msg = mTaskHandler.obtainMessage(
+                        MEDIA_ERROR, MEDIA_ERROR_IO, MEDIA_ERROR_UNKNOWN, null);
+                mTaskHandler.handleMessage(msg, nextSource.mId);
+
+                SourceInfo nextSourceInfo = mNextSourceInfos.poll();
+                if (nextSource != null) {
+                    nextSourceInfo.close();
+                }
+                return prepareNextDataSource();
+            }
+        }
+        return hasNextDSD;
+    }
+
+    // This function should be always called on |mHandlerThread|.
+    private void playNextDataSource() {
+        HandlerThread handlerThread = mHandlerThread;
+        if (handlerThread != null && Looper.myLooper() != handlerThread.getLooper()) {
+            Log.e(TAG, "playNextDataSource: called on wrong looper");
+        }
+
+        boolean hasNextDSD = false;
+        synchronized (mSrcLock) {
+            if (!mNextSourceInfos.isEmpty()) {
+                hasNextDSD = true;
+                SourceInfo nextSourceInfo = mNextSourceInfos.peek();
+                if (nextSourceInfo.mStateAsNextSource == NEXT_SOURCE_STATE_PREPARED) {
+                    // Switch to next source only when it has been prepared.
+                    setCurrentSourceInfo_l(mNextSourceInfos.poll());
+
+                    long srcId = mCurrentSourceInfo.mId;
+                    try {
+                        nativePlayNextDataSource(srcId);
+                    } catch (Exception e) {
+                        Message msg2 = mTaskHandler.obtainMessage(
+                                MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
+                        mTaskHandler.handleMessage(msg2, srcId);
+                        // Keep |mNextSourcePlayPending|
+                        hasNextDSD = prepareNextDataSource();
+                    }
+                    if (hasNextDSD) {
+                        stayAwake(true);
+
+                        // Now a new current src is playing.
+                        // Wait for MEDIA_INFO_DATA_SOURCE_START to prepare next source.
+                    }
+                } else if (nextSourceInfo.mStateAsNextSource == NEXT_SOURCE_STATE_INIT) {
+                    hasNextDSD = prepareNextDataSource();
+                }
+            }
+        }
+
+        if (!hasNextDSD) {
+            sendEvent(new EventNotifier() {
+                @Override
+                public void notify(EventCallback callback) {
+                    callback.onInfo(
+                            MediaPlayer2.this, null, MEDIA_INFO_DATA_SOURCE_LIST_END, 0);
+                }
+            });
+        }
+    }
+
+    private native void nativePlayNextDataSource(long srcId);
+
+    /**
+     * Configures the player to loop on the current data source.
+     * @param loop true if the current data source is meant to loop.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object loopCurrent(boolean loop) {
+        return addTask(new Task(CALL_COMPLETED_LOOP_CURRENT, false) {
+            @Override
+            void process() {
+                setLooping(loop);
+            }
+        });
+    }
+
+    private native void setLooping(boolean looping);
+
+    /**
+     * Sets the volume of the audio of the media to play, expressed as a linear multiplier
+     * on the audio samples.
+     * Note that this volume is specific to the player, and is separate from stream volume
+     * used across the platform.<br>
+     * A value of 0.0f indicates muting, a value of 1.0f is the nominal unattenuated and unamplified
+     * gain. See {@link #getMaxPlayerVolume()} for the volume range supported by this player.
+     * @param volume a value between 0.0f and {@link #getMaxPlayerVolume()}.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object setPlayerVolume(float volume) {
+        return addTask(new Task(CALL_COMPLETED_SET_PLAYER_VOLUME, false) {
+            @Override
+            void process() {
+                mVolume = volume;
+                native_setVolume(volume);
+            }
+        });
+    }
+
+    private native void native_setVolume(float volume);
+
+    /**
+     * Returns the current volume of this player.
+     * Note that it does not take into account the associated stream volume.
+     * @return the player volume.
+     */
+    public float getPlayerVolume() {
+        return mVolume;
+    }
+
+    /**
+     * @return the maximum volume that can be used in {@link #setPlayerVolume(float)}.
+     */
+    public float getMaxPlayerVolume() {
+        return 1.0f;
+    }
+
+    /**
+     * Insert a task in the command queue to help the client to identify whether a batch
+     * of commands has been finished. When this command is processed, a notification
+     * {@link EventCallback#onCommandLabelReached onCommandLabelReached} will be fired with the
+     * given {@code label}.
+     *
+     * @see EventCallback#onCommandLabelReached
+     *
+     * @param label An application specific Object used to help to identify the completeness
+     * of a batch of commands.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object notifyWhenCommandLabelReached(@NonNull Object label) {
+        return addTask(new Task(CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED, false) {
+            @Override
+            void process() {
+                sendEvent(new EventNotifier() {
+                    @Override
+                    public void notify(EventCallback callback) {
+                        callback.onCommandLabelReached(
+                                MediaPlayer2.this, label);
+                    }
+                });
+            }
+        });
+    }
+
+    /**
+     * Sets the {@link SurfaceHolder} to use for displaying the video
+     * portion of the media.
+     *
+     * Either a surface holder or surface must be set if a display or video sink
+     * is needed. Not calling this method or {@link #setSurface(Surface)}
+     * when playing back a video will result in only the audio track being played.
+     * A null surface holder or surface will result in only the audio track being
+     * played.
+     *
+     * @param sh the SurfaceHolder to use for video display
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    public Object setDisplay(SurfaceHolder sh) {
+        return addTask(new Task(CALL_COMPLETED_SET_DISPLAY, false) {
+            @Override
+            void process() {
+                mSurfaceHolder = sh;
+                Surface surface;
+                if (sh != null) {
+                    surface = sh.getSurface();
+                } else {
+                    surface = null;
+                }
+                native_setVideoSurface(surface);
+                updateSurfaceScreenOn();
+            }
+        });
+    }
+
+    /**
+     * Sets the {@link Surface} to be used as the sink for the video portion of
+     * the media.  Setting a
+     * Surface will un-set any Surface or SurfaceHolder that was previously set.
+     * A null surface will result in only the audio track being played.
+     *
+     * If the Surface sends frames to a {@link SurfaceTexture}, the timestamps
+     * returned from {@link SurfaceTexture#getTimestamp()} will have an
+     * unspecified zero point.  These timestamps cannot be directly compared
+     * between different media sources, different instances of the same media
+     * source, or multiple runs of the same program.  The timestamp is normally
+     * monotonically increasing and is unaffected by time-of-day adjustments,
+     * but it is reset when the position is set.
+     *
+     * @param surface The {@link Surface} to be used for the video portion of
+     * the media.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object setSurface(Surface surface) {
+        return addTask(new Task(CALL_COMPLETED_SET_SURFACE, false) {
+            @Override
+            void process() {
+                if (mScreenOnWhilePlaying && surface != null) {
+                    Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface");
+                }
+                mSurfaceHolder = null;
+                native_setVideoSurface(surface);
+                updateSurfaceScreenOn();
+            }
+        });
+    }
+
+    private native void native_setVideoSurface(Surface surface);
+
+    /**
+     * Set the low-level power management behavior for this MediaPlayer2. This
+     * can be used when the MediaPlayer2 is not playing through a SurfaceHolder
+     * set with {@link #setDisplay(SurfaceHolder)} and thus can use the
+     * high-level {@link #setScreenOnWhilePlaying(boolean)} feature.
+     *
+     * <p>This function has the MediaPlayer2 access the low-level power manager
+     * service to control the device's power usage while playing is occurring.
+     * The parameter is a {@link android.os.PowerManager.WakeLock}.
+     * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
+     * permission.
+     * By default, no attempt is made to keep the device awake during playback.
+     *
+     * @param wakeLock the power wake lock used during playback.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     * @see android.os.PowerManager
+     */
+    // This is an asynchronous call.
+    public Object setWakeLock(@NonNull PowerManager.WakeLock wakeLock) {
+        return addTask(new Task(CALL_COMPLETED_SET_WAKE_LOCK, false) {
+            @Override
+            void process() {
+                boolean wasHeld = false;
+
+                if (mWakeLock != null) {
+                    if (mWakeLock.isHeld()) {
+                        wasHeld = true;
+                        mWakeLock.release();
+                    }
+                }
+
+                mWakeLock = wakeLock;
+                if (mWakeLock != null) {
+                    mWakeLock.setReferenceCounted(false);
+                    if (wasHeld) {
+                        mWakeLock.acquire();
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Control whether we should use the attached SurfaceHolder to keep the
+     * screen on while video playback is occurring.  This is the preferred
+     * method over {@link #setWakeLock} where possible, since it doesn't
+     * require that the application have permission for low-level wake lock
+     * access.
+     *
+     * @param screenOn Supply true to keep the screen on, false to allow it to turn off.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object setScreenOnWhilePlaying(boolean screenOn) {
+        return addTask(new Task(CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING, false) {
+            @Override
+            void process() {
+                if (mScreenOnWhilePlaying != screenOn) {
+                    if (screenOn && mSurfaceHolder == null) {
+                        Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective"
+                                + " without a SurfaceHolder");
+                    }
+                    mScreenOnWhilePlaying = screenOn;
+                    updateSurfaceScreenOn();
+                }
+            }
+        });
+    }
+
+    private void stayAwake(boolean awake) {
+        if (mWakeLock != null) {
+            if (awake && !mWakeLock.isHeld()) {
+                mWakeLock.acquire();
+            } else if (!awake && mWakeLock.isHeld()) {
+                mWakeLock.release();
+            }
+        }
+        mStayAwake = awake;
+        updateSurfaceScreenOn();
+    }
+
+    private void updateSurfaceScreenOn() {
+        if (mSurfaceHolder != null) {
+            mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake);
+        }
+    }
+
+    /**
+     * Cancels a pending command.
+     *
+     * @param token the command to be canceled. This is the returned Object when command is issued.
+     * @return {@code false} if the task could not be cancelled; {@code true} otherwise.
+     * @throws IllegalArgumentException if argument token is null.
+     */
+    // This is a synchronous call.
+    public boolean cancelCommand(@NonNull Object token) {
+        if (token == null) {
+            throw new IllegalArgumentException("command token should not be null");
+        }
+        synchronized (mTaskLock) {
+            return mPendingTasks.remove(token);
+        }
+    }
+
+    /**
+     * Discards all pending commands.
+     */
+    // This is a synchronous call.
+    public void clearPendingCommands() {
+        synchronized (mTaskLock) {
+            mPendingTasks.clear();
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    // Explicit Routing
+    //--------------------
+    private AudioDeviceInfo mPreferredDevice = null;
+
+    /**
+     * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
+     * the output from this MediaPlayer2.
+     * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio sink or source.
+     *  If deviceInfo is null, default routing is restored.
+     * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
+     * does not correspond to a valid audio device.
+     */
+    // This is a synchronous call.
+    @Override
+    public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
+        boolean status = native_setPreferredDevice(deviceInfo);
+        if (status) {
+            synchronized (this) {
+                mPreferredDevice = deviceInfo;
+            }
+        }
+        return status;
+    }
+
+    private native boolean native_setPreferredDevice(AudioDeviceInfo device);
+
+    /**
+     * Returns the selected output specified by {@link #setPreferredDevice}. Note that this
+     * is not guaranteed to correspond to the actual device being used for playback.
+     */
+    @Override
+    public AudioDeviceInfo getPreferredDevice() {
+        synchronized (this) {
+            return mPreferredDevice;
+        }
+    }
+
+    /**
+     * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer2
+     * Note: The query is only valid if the MediaPlayer2 is currently playing.
+     * If the player is not playing, the returned device can be null or correspond to previously
+     * selected device when the player was last active.
+     */
+    @Override
+    public native AudioDeviceInfo getRoutedDevice();
+
+    /**
+     * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
+     * changes on this MediaPlayer2.
+     * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
+     * notifications of rerouting events.
+     * @param handler  Specifies the {@link Handler} object for the thread on which to execute
+     * the callback. If <code>null</code>, the handler on the main looper will be used.
+     */
+    // This is a synchronous call.
+    @Override
+    public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
+            Handler handler) {
+        if (listener == null) {
+            throw new IllegalArgumentException("addOnRoutingChangedListener: listener is NULL");
+        }
+        RoutingDelegate routingDelegate = new RoutingDelegate(this, listener, handler);
+        native_addDeviceCallback(routingDelegate);
+    }
+
+    private native void native_addDeviceCallback(RoutingDelegate rd);
+
+    /**
+     * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
+     * to receive rerouting notifications.
+     * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
+     * to remove.
+     */
+    // This is a synchronous call.
+    @Override
+    public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("removeOnRoutingChangedListener: listener is NULL");
+        }
+        native_removeDeviceCallback(listener);
+    }
+
+    private native void native_removeDeviceCallback(
+            AudioRouting.OnRoutingChangedListener listener);
+
+    /**
+     * Returns the size of the video.
+     *
+     * @return the size of the video. The width and height of size could be 0 if there is no video,
+     * no display surface was set, or the size has not been determined yet.
+     * The {@code EventCallback} can be registered via
+     * {@link #registerEventCallback(Executor, EventCallback)} to provide a
+     * notification {@code EventCallback.onVideoSizeChanged} when the size
+     * is available.
+     */
+    public VideoSize getVideoSize() {
+        return mVideoSize;
+    }
+
+    /**
+     * Return Metrics data about the current player.
+     *
+     * @return a {@link PersistableBundle} containing the set of attributes and values
+     * available for the media being handled by this instance of MediaPlayer2
+     * The attributes are descibed in {@link MetricsConstants}.
+     *
+     * Additional vendor-specific fields may also be present in the return value.
+     */
+    public PersistableBundle getMetrics() {
+        PersistableBundle bundle = native_getMetrics();
+        return bundle;
+    }
+
+    private native PersistableBundle native_getMetrics();
+
+    /**
+     * Gets the current buffering management params used by the source component.
+     * Calling it only after {@code setDataSource} has been called.
+     * Each type of data source might have different set of default params.
+     *
+     * @return the current buffering management params used by the source component.
+     * @throws IllegalStateException if the internal player engine has not been
+     * initialized, or {@code setDataSource} has not been called.
+     */
+    // TODO: make it public when ready
+    @NonNull
+    native BufferingParams getBufferingParams();
+
+    /**
+     * Sets buffering management params.
+     * The object sets its internal BufferingParams to the input, except that the input is
+     * invalid or not supported.
+     * Call it only after {@code setDataSource} has been called.
+     * The input is a hint to MediaPlayer2.
+     *
+     * @param params the buffering management params.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // TODO: make it public when ready
+    // This is an asynchronous call.
+    Object setBufferingParams(@NonNull BufferingParams params) {
+        return addTask(new Task(CALL_COMPLETED_SET_BUFFERING_PARAMS, false) {
+            @Override
+            void process() {
+                Media2Utils.checkArgument(params != null, "the BufferingParams cannot be null");
+                native_setBufferingParams(params);
+            }
+        });
+    }
+
+    private native void native_setBufferingParams(@NonNull BufferingParams params);
+
+    /**
+     * Sets playback rate using {@link PlaybackParams}. The object sets its internal
+     * 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.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object setPlaybackParams(@NonNull PlaybackParams params) {
+        return addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_PARAMS, false) {
+            @Override
+            void process() {
+                Media2Utils.checkArgument(params != null, "the PlaybackParams cannot be null");
+                native_setPlaybackParams(params);
+            }
+        });
+    }
+
+    private native void native_setPlaybackParams(@NonNull PlaybackParams params);
+
+    /**
+     * Gets the playback params, containing the current playback rate.
+     *
+     * @return the playback params.
+     * @throws IllegalStateException if the internal player engine has not been initialized.
+     */
+    @NonNull
+    public native PlaybackParams getPlaybackParams();
+
+    /**
+     * Sets A/V sync mode.
+     *
+     * @param params the A/V sync params to apply
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object setSyncParams(@NonNull SyncParams params) {
+        return addTask(new Task(CALL_COMPLETED_SET_SYNC_PARAMS, false) {
+            @Override
+            void process() {
+                Media2Utils.checkArgument(params != null, "the SyncParams cannot be null");
+                native_setSyncParams(params);
+            }
+        });
+    }
+
+    private native void native_setSyncParams(@NonNull SyncParams params);
+
+    /**
+     * Gets the A/V sync mode.
+     *
+     * @return the A/V sync params
+     * @throws IllegalStateException if the internal player engine has not been initialized.
+     */
+    @NonNull
+    public native SyncParams getSyncParams();
+
+    /**
+     * Moves the media to specified time position.
+     * Same as {@link #seekTo(long, int)} with {@code mode = SEEK_PREVIOUS_SYNC}.
+     *
+     * @param msec the offset in milliseconds from the start to seek to
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object seekTo(long msec) {
+        return seekTo(msec, SEEK_PREVIOUS_SYNC /* mode */);
+    }
+
+    /**
+     * Seek modes used in method seekTo(long, int) to move media position
+     * to a specified location.
+     *
+     * Do not change these mode values without updating their counterparts
+     * in include/media/IMediaSource.h!
+     */
+    /**
+     * This mode is used with {@link #seekTo(long, int)} to move media position to
+     * a sync (or key) frame associated with a data source that is located
+     * right before or at the given time.
+     *
+     * @see #seekTo(long, int)
+     */
+    public static final int SEEK_PREVIOUS_SYNC    = 0x00;
+    /**
+     * This mode is used with {@link #seekTo(long, int)} to move media position to
+     * a sync (or key) frame associated with a data source that is located
+     * right after or at the given time.
+     *
+     * @see #seekTo(long, int)
+     */
+    public static final int SEEK_NEXT_SYNC        = 0x01;
+    /**
+     * This mode is used with {@link #seekTo(long, int)} to move media position to
+     * a sync (or key) frame associated with a data source that is located
+     * closest to (in time) or at the given time.
+     *
+     * @see #seekTo(long, int)
+     */
+    public static final int SEEK_CLOSEST_SYNC     = 0x02;
+    /**
+     * This mode is used with {@link #seekTo(long, int)} to move media position to
+     * a frame (not necessarily a key frame) associated with a data source that
+     * is located closest to or at the given time.
+     *
+     * @see #seekTo(long, int)
+     */
+    public static final int SEEK_CLOSEST          = 0x03;
+
+    /** @hide */
+    @IntDef(flag = false, prefix = "SEEK", value = {
+            SEEK_PREVIOUS_SYNC,
+            SEEK_NEXT_SYNC,
+            SEEK_CLOSEST_SYNC,
+            SEEK_CLOSEST,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SeekMode {}
+
+    /**
+     * Moves the media to specified time position by considering the given mode.
+     * <p>
+     * When seekTo is finished, the user will be notified via
+     * {@link EventCallback#onCallCompleted} with {@link #CALL_COMPLETED_SEEK_TO}.
+     * There is at most one active seekTo processed at any time. If there is a to-be-completed
+     * seekTo, new seekTo requests will be queued in such a way that only the last request
+     * is kept. When current seekTo is completed, the queued request will be processed if
+     * that request is different from just-finished seekTo operation, i.e., the requested
+     * position or mode is different.
+     *
+     * @param msec the offset in milliseconds from the start to seek to.
+     * When seeking to the given time position, there is no guarantee that the data source
+     * has a frame located at the position. When this happens, a frame nearby will be rendered.
+     * If msec is negative, time position zero will be used.
+     * If msec is larger than duration, duration will be used.
+     * @param mode the mode indicating where exactly to seek to.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object seekTo(long msec, @SeekMode int mode) {
+        return addTask(new Task(CALL_COMPLETED_SEEK_TO, true) {
+            @Override
+            void process() {
+                if (mode < SEEK_PREVIOUS_SYNC || mode > SEEK_CLOSEST) {
+                    final String msg = "Illegal seek mode: " + mode;
+                    throw new IllegalArgumentException(msg);
+                }
+                // TODO: pass long to native, instead of truncating here.
+                long posMs = msec;
+                if (posMs > Integer.MAX_VALUE) {
+                    Log.w(TAG, "seekTo offset " + posMs + " is too large, cap to "
+                            + Integer.MAX_VALUE);
+                    posMs = Integer.MAX_VALUE;
+                } else if (posMs < Integer.MIN_VALUE) {
+                    Log.w(TAG, "seekTo offset " + posMs + " is too small, cap to "
+                            + Integer.MIN_VALUE);
+                    posMs = Integer.MIN_VALUE;
+                }
+
+                synchronized (mTaskLock) {
+                    if (mIsPreviousCommandSeekTo
+                            && mPreviousSeekPos == posMs
+                            && mPreviousSeekMode == mode) {
+                        throw new CommandSkippedException(
+                                "same as previous seekTo");
+                    }
+                }
+
+                native_seekTo(posMs, mode);
+
+                synchronized (mTaskLock) {
+                    mIsPreviousCommandSeekTo = true;
+                    mPreviousSeekPos = posMs;
+                    mPreviousSeekMode = mode;
+                }
+            }
+        });
+    }
+
+    private native void native_seekTo(long msec, int mode);
+
+    /**
+     * Get current playback position as a {@link MediaTimestamp}.
+     * <p>
+     * The MediaTimestamp represents how the media time correlates to the system time in
+     * a linear fashion using an anchor and a clock rate. During regular playback, the media
+     * time moves fairly constantly (though the anchor frame may be rebased to a current
+     * system time, the linear correlation stays steady). Therefore, this method does not
+     * need to be called often.
+     * <p>
+     * To help users get current playback position, this method always anchors the timestamp
+     * to the current {@link System#nanoTime system time}, so
+     * {@link MediaTimestamp#getAnchorMediaTimeUs} can be used as current playback position.
+     *
+     * @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp
+     *         is available, e.g. because the media player has not been initialized.
+     *
+     * @see MediaTimestamp
+     */
+    @Nullable
+    public MediaTimestamp getTimestamp() {
+        try {
+            // TODO: get the timestamp from native side
+            return new MediaTimestamp.Builder()
+                    .setMediaTimestamp(
+                        getCurrentPosition() * 1000L,
+                        System.nanoTime(),
+                        getState() == PLAYER_STATE_PLAYING ? getPlaybackParams().getSpeed() : 0.f)
+                    .build();
+        } catch (IllegalStateException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Checks whether the MediaPlayer2 is looping or non-looping.
+     *
+     * @return true if the MediaPlayer2 is currently looping, false otherwise
+     */
+    // This is a synchronous call.
+    public native boolean isLooping();
+
+    /**
+     * Sets the audio session ID.
+     *
+     * @param sessionId the audio session ID.
+     * The audio session ID is a system wide unique identifier for the audio stream played by
+     * this MediaPlayer2 instance.
+     * The primary use of the audio session ID  is to associate audio effects to a particular
+     * instance of MediaPlayer2: if an audio session ID is provided when creating an audio effect,
+     * this effect will be applied only to the audio content of media players within the same
+     * audio session and not to the output mix.
+     * When created, a MediaPlayer2 instance automatically generates its own audio session ID.
+     * However, it is possible to force this player to be part of an already existing audio session
+     * by calling this method.
+     * This method must be called when player is in {@link #PLAYER_STATE_IDLE} or
+     * {@link #PLAYER_STATE_PREPARED} state in order to have sessionId take effect.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object setAudioSessionId(int sessionId) {
+        final AudioTrack dummyAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
+                    AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, 2,
+                    AudioTrack.MODE_STATIC, sessionId);
+        return addTask(new Task(CALL_COMPLETED_SET_AUDIO_SESSION_ID, false) {
+            @Override
+            void process() {
+                keepAudioSessionIdAlive(dummyAudioTrack);
+                native_setAudioSessionId(sessionId);
+            }
+        });
+    }
+
+    private native void native_setAudioSessionId(int sessionId);
+
+    /**
+     * Returns the audio session ID.
+     *
+     * @return the audio session ID. {@see #setAudioSessionId(int)}
+     * Note that the audio session ID is 0 only if a problem occured when the MediaPlayer2 was
+     * contructed.
+     */
+    // This is a synchronous call.
+    public native int getAudioSessionId();
+
+    /**
+     * Attaches an auxiliary effect to the player. A typical auxiliary effect is a reverberation
+     * effect which can be applied on any sound source that directs a certain amount of its
+     * energy to this effect. This amount is defined by setAuxEffectSendLevel().
+     * See {@link #setAuxEffectSendLevel(float)}.
+     * <p>After creating an auxiliary effect (e.g.
+     * {@link android.media.audiofx.EnvironmentalReverb}), retrieve its ID with
+     * {@link android.media.audiofx.AudioEffect#getId()} and use it when calling this method
+     * to attach the player to the effect.
+     * <p>To detach the effect from the player, call this method with a null effect id.
+     * <p>This method must be called after one of the overloaded <code> setDataSource </code>
+     * methods.
+     * @param effectId system wide unique id of the effect to attach
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object attachAuxEffect(int effectId) {
+        return addTask(new Task(CALL_COMPLETED_ATTACH_AUX_EFFECT, false) {
+            @Override
+            void process() {
+                native_attachAuxEffect(effectId);
+            }
+        });
+    }
+
+    private native void native_attachAuxEffect(int effectId);
+
+    /**
+     * Sets the send level of the player to the attached auxiliary effect.
+     * See {@link #attachAuxEffect(int)}. The level value range is 0 to 1.0.
+     * <p>By default the send level is 0, so even if an effect is attached to the player
+     * this method must be called for the effect to be applied.
+     * <p>Note that the passed level value is a raw scalar. UI controls should be scaled
+     * logarithmically: the gain applied by audio framework ranges from -72dB to 0dB,
+     * so an appropriate conversion from linear UI input x to level is:
+     * x == 0 -> level = 0
+     * 0 < x <= R -> level = 10^(72*(x-R)/20/R)
+     * @param level send level scalar
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     */
+    // This is an asynchronous call.
+    public Object setAuxEffectSendLevel(float level) {
+        return addTask(new Task(CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL, false) {
+            @Override
+            void process() {
+                native_setAuxEffectSendLevel(level);
+            }
+        });
+    }
+
+    private native void native_setAuxEffectSendLevel(float level);
+
+    private static native void native_stream_event_onTearDown(
+            long nativeCallbackPtr, long userDataPtr);
+    private static native void native_stream_event_onStreamPresentationEnd(
+            long nativeCallbackPtr, long userDataPtr);
+    private static native void native_stream_event_onStreamDataRequest(
+            long jAudioTrackPtr, long nativeCallbackPtr, long userDataPtr);
+
+    /* Do not change these values (starting with INVOKE_ID) without updating
+     * their counterparts in include/media/mediaplayer2.h!
+     */
+    private static final int INVOKE_ID_GET_TRACK_INFO = 1;
+    private static final int INVOKE_ID_ADD_EXTERNAL_SOURCE = 2;
+    private static final int INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3;
+    private static final int INVOKE_ID_SELECT_TRACK = 4;
+    private static final int INVOKE_ID_DESELECT_TRACK = 5;
+    private static final int INVOKE_ID_GET_SELECTED_TRACK = 7;
+
+    /**
+     * 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 msg PlayerMessage for the extension.
+     *
+     * @return PlayerMessage with the data returned by the
+     * native player.
+     */
+    private PlayerMessage invoke(PlayerMessage msg) {
+        byte[] ret = native_invoke(msg.toByteArray());
+        if (ret == null) {
+            return null;
+        }
+        try {
+            return PlayerMessage.parseFrom(ret);
+        } catch (InvalidProtocolBufferException e) {
+            return null;
+        }
+    }
+
+    private native byte[] native_invoke(byte[] request);
+
+    /**
+     * Class for MediaPlayer2 to return each audio/video/subtitle track's metadata.
+     *
+     * @see MediaPlayer2#getTrackInfo
+     */
+    public static class TrackInfo {
+        /**
+         * Gets the track type.
+         * @return TrackType which indicates if the track is video, audio, timed text.
+         */
+        public int getTrackType() {
+            return mTrackType;
+        }
+
+        /**
+         * Gets the language code of the track.
+         * @return a language code in either way of ISO-639-1 or ISO-639-2.
+         * When the language is unknown or could not be determined,
+         * ISO-639-2 language code, "und", is returned.
+         */
+        public String getLanguage() {
+            String language = mFormat.getString(MediaFormat.KEY_LANGUAGE);
+            return language == null ? "und" : language;
+        }
+
+        /**
+         * Gets the {@link MediaFormat} of the track.  If the format is
+         * unknown or could not be determined, null is returned.
+         */
+        public MediaFormat getFormat() {
+            if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT
+                    || mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+                return mFormat;
+            }
+            return null;
+        }
+
+        public static final int MEDIA_TRACK_TYPE_UNKNOWN = 0;
+        public static final int MEDIA_TRACK_TYPE_VIDEO = 1;
+        public static final int MEDIA_TRACK_TYPE_AUDIO = 2;
+
+        /** @hide */
+        public static final int MEDIA_TRACK_TYPE_TIMEDTEXT = 3;
+
+        public static final int MEDIA_TRACK_TYPE_SUBTITLE = 4;
+        public static final int MEDIA_TRACK_TYPE_METADATA = 5;
+
+        final int mTrackType;
+        final MediaFormat mFormat;
+
+        static TrackInfo create(Iterator<Value> in) {
+            int trackType = in.next().getInt32Value();
+            // TODO: build the full MediaFormat; currently we are using createSubtitleFormat
+            // even for audio/video tracks, meaning we only set the mime and language.
+            String mime = in.next().getStringValue();
+            String language = in.next().getStringValue();
+            MediaFormat format = MediaFormat.createSubtitleFormat(mime, language);
+
+            if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+                format.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.next().getInt32Value());
+                format.setInteger(MediaFormat.KEY_IS_DEFAULT, in.next().getInt32Value());
+                format.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.next().getInt32Value());
+            }
+            return new TrackInfo(trackType, format);
+        }
+
+        /** @hide */
+        TrackInfo(int type, MediaFormat format) {
+            mTrackType = type;
+            mFormat = format;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder out = new StringBuilder(128);
+            out.append(getClass().getName());
+            out.append('{');
+            switch (mTrackType) {
+                case MEDIA_TRACK_TYPE_VIDEO:
+                    out.append("VIDEO");
+                    break;
+                case MEDIA_TRACK_TYPE_AUDIO:
+                    out.append("AUDIO");
+                    break;
+                case MEDIA_TRACK_TYPE_TIMEDTEXT:
+                    out.append("TIMEDTEXT");
+                    break;
+                case MEDIA_TRACK_TYPE_SUBTITLE:
+                    out.append("SUBTITLE");
+                    break;
+                default:
+                    out.append("UNKNOWN");
+                    break;
+            }
+            out.append(", " + mFormat.toString());
+            out.append("}");
+            return out.toString();
+        }
+    };
+
+    /**
+     * Returns a List of track information of current data source.
+     * Same as {@link #getTrackInfo(DataSourceDesc)} with
+     * {@code dsd = getCurrentDataSource()}.
+     *
+     * @return List of track info. The total number of tracks is the array length.
+     * Must be called again if an external timed text source has been added after
+     * addTimedTextSource method is called.
+     * @throws IllegalStateException if it is called in an invalid state.
+     * @throws NullPointerException if current data source is null
+     */
+    public @NonNull List<TrackInfo> getTrackInfo() {
+        return getTrackInfo(getCurrentDataSource());
+    }
+
+    /**
+     * Returns a List of track information.
+     *
+     * @param dsd the descriptor of data source of which you want to get track info
+     * @return List of track info. The total number of tracks is the array length.
+     * Must be called again if an external timed text source has been added after
+     * addTimedTextSource method is called.
+     * @throws IllegalStateException if it is called in an invalid state.
+     * @throws NullPointerException if dsd is null
+     */
+    public @NonNull List<TrackInfo> getTrackInfo(@NonNull DataSourceDesc dsd) {
+        if (dsd == null) {
+            throw new NullPointerException("non-null dsd is expected");
+        }
+        SourceInfo sourceInfo = getSourceInfo(dsd);
+        if (sourceInfo == null) {
+            return new ArrayList<TrackInfo>(0);
+        }
+
+        TrackInfo[] trackInfo = getInbandTrackInfo(sourceInfo);
+        return (trackInfo != null ? Arrays.asList(trackInfo) : new ArrayList<TrackInfo>(0));
+    }
+
+    private TrackInfo[] getInbandTrackInfo(SourceInfo sourceInfo) throws IllegalStateException {
+        PlayerMessage request = PlayerMessage.newBuilder()
+                .addValues(Value.newBuilder().setInt32Value(INVOKE_ID_GET_TRACK_INFO))
+                .addValues(Value.newBuilder().setInt64Value(sourceInfo.mId))
+                .build();
+        PlayerMessage response = invoke(request);
+        if (response == null) {
+            return null;
+        }
+        Iterator<Value> in = response.getValuesList().iterator();
+        int size = in.next().getInt32Value();
+        if (size == 0) {
+            return null;
+        }
+        TrackInfo[] trackInfo = new TrackInfo[size];
+        for (int i = 0; i < size; ++i) {
+            trackInfo[i] = TrackInfo.create(in);
+        }
+        return trackInfo;
+    }
+
+    /**
+     * Returns the index of the audio, video, or subtitle track currently selected for playback.
+     * The return value is an index into the array returned by {@link #getTrackInfo}, and can
+     * be used in calls to {@link #selectTrack(int)} or {@link #deselectTrack(int)}.
+     * Same as {@link #getSelectedTrack(DataSourceDesc, int)} with
+     * {@code dsd = getCurrentDataSource()}.
+     *
+     * @param trackType should be one of {@link TrackInfo#MEDIA_TRACK_TYPE_VIDEO},
+     * {@link TrackInfo#MEDIA_TRACK_TYPE_AUDIO}, or
+     * {@link TrackInfo#MEDIA_TRACK_TYPE_SUBTITLE}
+     * @return index of the audio, video, or subtitle track currently selected for playback;
+     * a negative integer is returned when there is no selected track for {@code trackType} or
+     * when {@code trackType} is not one of audio, video, or subtitle.
+     * @throws IllegalStateException if called after {@link #close()}
+     * @throws NullPointerException if current data source is null
+     *
+     * @see #getTrackInfo()
+     * @see #selectTrack(int)
+     * @see #deselectTrack(int)
+     */
+    public int getSelectedTrack(int trackType) {
+        return getSelectedTrack(getCurrentDataSource(), trackType);
+    }
+
+    /**
+     * Returns the index of the audio, video, or subtitle track currently selected for playback.
+     * The return value is an index into the array returned by {@link #getTrackInfo}, and can
+     * be used in calls to {@link #selectTrack(DataSourceDesc, int)} or
+     * {@link #deselectTrack(DataSourceDesc, int)}.
+     *
+     * @param dsd the descriptor of data source of which you want to get selected track
+     * @param trackType should be one of {@link TrackInfo#MEDIA_TRACK_TYPE_VIDEO},
+     * {@link TrackInfo#MEDIA_TRACK_TYPE_AUDIO}, or
+     * {@link TrackInfo#MEDIA_TRACK_TYPE_SUBTITLE}
+     * @return index of the audio, video, or subtitle track currently selected for playback;
+     * a negative integer is returned when there is no selected track for {@code trackType} or
+     * when {@code trackType} is not one of audio, video, or subtitle.
+     * @throws IllegalStateException if called after {@link #close()}
+     * @throws NullPointerException if dsd is null
+     *
+     * @see #getTrackInfo(DataSourceDesc)
+     * @see #selectTrack(DataSourceDesc, int)
+     * @see #deselectTrack(DataSourceDesc, int)
+     */
+    public int getSelectedTrack(@NonNull DataSourceDesc dsd, int trackType) {
+        if (dsd == null) {
+            throw new NullPointerException("non-null dsd is expected");
+        }
+        SourceInfo sourceInfo = getSourceInfo(dsd);
+        if (sourceInfo == null) {
+            return -1;
+        }
+
+        PlayerMessage request = PlayerMessage.newBuilder()
+                .addValues(Value.newBuilder().setInt32Value(INVOKE_ID_GET_SELECTED_TRACK))
+                .addValues(Value.newBuilder().setInt64Value(sourceInfo.mId))
+                .addValues(Value.newBuilder().setInt32Value(trackType))
+                .build();
+        PlayerMessage response = invoke(request);
+        if (response == null) {
+            return -1;
+        }
+        return response.getValues(0).getInt32Value();
+    }
+
+    /**
+     * Selects a track of current data source.
+     * Same as {@link #selectTrack(DataSourceDesc, int)} with
+     * {@code dsd = getCurrentDataSource()}.
+     *
+     * @param index the index of the track to be selected. The valid range of the index
+     * is 0..total number of track - 1. The total number of tracks as well as the type of
+     * each individual track can be found by calling {@link #getTrackInfo()} method.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     *
+     * @see MediaPlayer2#getTrackInfo()
+     */
+    // This is an asynchronous call.
+    public Object selectTrack(int index) {
+        return selectTrack(getCurrentDataSource(), index);
+    }
+
+    /**
+     * Selects a track.
+     * <p>
+     * If a MediaPlayer2 is in invalid state, it throws an IllegalStateException exception.
+     * If a MediaPlayer2 is in <em>Started</em> state, the selected track is presented immediately.
+     * If a MediaPlayer2 is not in Started state, it just marks the track to be played.
+     * </p>
+     * <p>
+     * In any valid state, if it is called multiple times on the same type of track (ie. Video,
+     * Audio, Timed Text), the most recent one will be chosen.
+     * </p>
+     * <p>
+     * The first audio and video tracks are selected by default if available, even though
+     * this method is not called. However, no timed text track will be selected until
+     * this function is called.
+     * </p>
+     * <p>
+     * Currently, only timed text tracks or audio tracks can be selected via this method.
+     * In addition, the support for selecting an audio track at runtime is pretty limited
+     * in that an audio track can only be selected in the <em>Prepared</em> state.
+     * </p>
+     * @param dsd the descriptor of data source of which you want to select track
+     * @param index the index of the track to be selected. The valid range of the index
+     * is 0..total number of track - 1. The total number of tracks as well as the type of
+     * each individual track can be found by calling {@link #getTrackInfo(DataSourceDesc)} method.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     *
+     * @see MediaPlayer2#getTrackInfo(DataSourceDesc)
+     */
+    // This is an asynchronous call.
+    public Object selectTrack(@NonNull DataSourceDesc dsd, int index) {
+        return addTask(new Task(CALL_COMPLETED_SELECT_TRACK, false) {
+            @Override
+            void process() {
+                selectOrDeselectTrack(dsd, index, true /* select */);
+            }
+        });
+    }
+
+    /**
+     * Deselect a track of current data source.
+     * Same as {@link #deselectTrack(DataSourceDesc, int)} with
+     * {@code dsd = getCurrentDataSource()}.
+     *
+     * @param index the index of the track to be deselected. The valid range of the index
+     * is 0..total number of tracks - 1. The total number of tracks as well as the type of
+     * each individual track can be found by calling {@link #getTrackInfo()} method.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     *
+     * @see MediaPlayer2#getTrackInfo()
+     */
+    // This is an asynchronous call.
+    public Object deselectTrack(int index) {
+        return deselectTrack(getCurrentDataSource(), index);
+    }
+
+    /**
+     * Deselect a track.
+     * <p>
+     * Currently, the track must be a timed text track and no audio or video tracks can be
+     * deselected. If the timed text track identified by index has not been
+     * selected before, it throws an exception.
+     * </p>
+     * @param dsd the descriptor of data source of which you want to deselect track
+     * @param index the index of the track to be deselected. The valid range of the index
+     * is 0..total number of tracks - 1. The total number of tracks as well as the type of
+     * each individual track can be found by calling {@link #getTrackInfo} method.
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     *
+     * @see MediaPlayer2#getTrackInfo(DataSourceDesc)
+     */
+    // This is an asynchronous call.
+    public Object deselectTrack(@NonNull DataSourceDesc dsd, int index) {
+        return addTask(new Task(CALL_COMPLETED_DESELECT_TRACK, false) {
+            @Override
+            void process() {
+                selectOrDeselectTrack(dsd, index, false /* select */);
+            }
+        });
+    }
+
+    private void selectOrDeselectTrack(@NonNull DataSourceDesc dsd, int index, boolean select) {
+        if (dsd == null) {
+            throw new IllegalArgumentException("non-null dsd is expected");
+        }
+        SourceInfo sourceInfo = getSourceInfo(dsd);
+        if (sourceInfo == null) {
+            return;
+        }
+
+        PlayerMessage request = PlayerMessage.newBuilder()
+                .addValues(Value.newBuilder().setInt32Value(
+                            select ? INVOKE_ID_SELECT_TRACK : INVOKE_ID_DESELECT_TRACK))
+                .addValues(Value.newBuilder().setInt64Value(sourceInfo.mId))
+                .addValues(Value.newBuilder().setInt32Value(index))
+                .build();
+        invoke(request);
+    }
+
+    /* Do not change these values without updating their counterparts
+     * in include/media/mediaplayer2.h!
+     */
+    private static final int MEDIA_NOP = 0; // interface test message
+    private static final int MEDIA_PREPARED = 1;
+    private static final int MEDIA_PLAYBACK_COMPLETE = 2;
+    private static final int MEDIA_BUFFERING_UPDATE = 3;
+    private static final int MEDIA_SEEK_COMPLETE = 4;
+    private static final int MEDIA_SET_VIDEO_SIZE = 5;
+    private static final int MEDIA_STARTED = 6;
+    private static final int MEDIA_PAUSED = 7;
+    private static final int MEDIA_STOPPED = 8;
+    private static final int MEDIA_SKIPPED = 9;
+    private static final int MEDIA_DRM_PREPARED = 10;
+    private static final int MEDIA_NOTIFY_TIME = 98;
+    private static final int MEDIA_TIMED_TEXT = 99;
+    private static final int MEDIA_ERROR = 100;
+    private static final int MEDIA_INFO = 200;
+    private static final int MEDIA_SUBTITLE_DATA = 201;
+    private static final int MEDIA_META_DATA = 202;
+    private static final int MEDIA_DRM_INFO = 210;
+
+    private class TaskHandler extends Handler {
+        private MediaPlayer2 mMediaPlayer;
+
+        TaskHandler(MediaPlayer2 mp, Looper looper) {
+            super(looper);
+            mMediaPlayer = mp;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            handleMessage(msg, 0);
+        }
+
+        public void handleMessage(Message msg, long srcId) {
+            if (mMediaPlayer.mNativeContext == 0) {
+                Log.w(TAG, "mediaplayer2 went away with unhandled events");
+                return;
+            }
+            final int what = msg.arg1;
+            final int extra = msg.arg2;
+
+            final SourceInfo sourceInfo = getSourceInfo(srcId);
+            if (sourceInfo == null) {
+                return;
+            }
+            final DataSourceDesc dsd = sourceInfo.mDSD;
+
+            switch(msg.what) {
+                case MEDIA_PREPARED:
+                case MEDIA_DRM_PREPARED:
+                {
+                    sourceInfo.mPrepareBarrier--;
+                    if (sourceInfo.mPrepareBarrier > 0) {
+                        break;
+                    } else if (sourceInfo.mPrepareBarrier < 0) {
+                        Log.w(TAG, "duplicated (drm) prepared events");
+                        break;
+                    }
+
+                    if (dsd != null) {
+                        sendEvent(new EventNotifier() {
+                            @Override
+                            public void notify(EventCallback callback) {
+                                callback.onInfo(
+                                        mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0);
+                            }
+                        });
+                    }
+
+                    synchronized (mSrcLock) {
+                        SourceInfo nextSourceInfo = mNextSourceInfos.peek();
+                        Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
+                                + ", curSrc=" + mCurrentSourceInfo
+                                + ", nextSrc=" + nextSourceInfo);
+
+                        if (isCurrentSource(srcId)) {
+                            prepareNextDataSource();
+                        } else if (isNextSource(srcId)) {
+                            nextSourceInfo.mStateAsNextSource = NEXT_SOURCE_STATE_PREPARED;
+                            if (nextSourceInfo.mPlayPendingAsNextSource) {
+                                playNextDataSource();
+                            }
+                        }
+                    }
+
+                    synchronized (mTaskLock) {
+                        if (mCurrentTask != null
+                                && mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE
+                                && mCurrentTask.mDSD == dsd
+                                && mCurrentTask.mNeedToWaitForEventToComplete) {
+                            mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
+                            mCurrentTask = null;
+                            processPendingTask_l();
+                        }
+                    }
+                    return;
+                }
+
+                case MEDIA_DRM_INFO:
+                {
+                    if (msg.obj == null) {
+                        Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
+                    } else if (msg.obj instanceof byte[]) {
+                        // The PlayerMessage was parsed already in postEventFromNative
+
+                        final DrmInfo drmInfo;
+                        synchronized (sourceInfo) {
+                            if (sourceInfo.mDrmInfo != null) {
+                                drmInfo = sourceInfo.mDrmInfo.makeCopy();
+                            } else {
+                                drmInfo = null;
+                            }
+                        }
+
+                        // notifying the client outside the lock
+                        DrmPreparationInfo drmPrepareInfo = null;
+                        if (drmInfo != null) {
+                            try {
+                                drmPrepareInfo = sendDrmEventWait(
+                                        new DrmEventNotifier<DrmPreparationInfo>() {
+                                            @Override
+                                            public DrmPreparationInfo notifyWait(
+                                                    DrmEventCallback callback) {
+                                                return callback.onDrmInfo(mMediaPlayer, dsd,
+                                                        drmInfo);
+                                            }
+                                        });
+                            } catch (InterruptedException | ExecutionException
+                                    | TimeoutException e) {
+                                Log.w(TAG, "Exception while waiting for DrmPreparationInfo", e);
+                            }
+                        }
+                        if (sourceInfo.mDrmHandle.setPreparationInfo(drmPrepareInfo)) {
+                            sourceInfo.mPrepareBarrier++;
+                            final Task prepareDrmTask;
+                            prepareDrmTask = newPrepareDrmTask(dsd, drmPrepareInfo.mUUID);
+                            mTaskHandler.post(new Runnable() {
+                                @Override
+                                public void run() {
+                                    // Run as simple Runnable, not Task
+                                    try {
+                                        prepareDrmTask.process();
+                                    } catch (NoDrmSchemeException | IOException e) {
+                                        final String errMsg;
+                                        errMsg = "Unexpected Exception during prepareDrm";
+                                        throw new RuntimeException(errMsg, e);
+                                    }
+                                }
+                            });
+                        } else {
+                            Log.w(TAG, "No valid DrmPreparationInfo set");
+                        }
+                    } else {
+                        Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + msg.obj);
+                    }
+                    return;
+                }
+
+                case MEDIA_PLAYBACK_COMPLETE:
+                {
+                    if (isCurrentSource(srcId)) {
+                        sendEvent(new EventNotifier() {
+                            @Override
+                            public void notify(EventCallback callback) {
+                                callback.onInfo(
+                                        mMediaPlayer, dsd, MEDIA_INFO_DATA_SOURCE_END, 0);
+                            }
+                        });
+                        stayAwake(false);
+
+                        synchronized (mSrcLock) {
+                            SourceInfo nextSourceInfo = mNextSourceInfos.peek();
+                            if (nextSourceInfo != null) {
+                                nextSourceInfo.mPlayPendingAsNextSource = true;
+                            }
+                            Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
+                                    + ", curSrc=" + mCurrentSourceInfo
+                                    + ", nextSrc=" + nextSourceInfo);
+                        }
+
+                        playNextDataSource();
+                    }
+
+                    return;
+                }
+
+                case MEDIA_STOPPED:
+                case MEDIA_STARTED:
+                case MEDIA_PAUSED:
+                case MEDIA_SKIPPED:
+                case MEDIA_NOTIFY_TIME:
+                {
+                    // Do nothing. The client should have enough information with
+                    // {@link EventCallback#onMediaTimeDiscontinuity}.
+                    break;
+                }
+
+                case MEDIA_BUFFERING_UPDATE:
+                {
+                    final int percent = msg.arg1;
+                    sendEvent(new EventNotifier() {
+                        @Override
+                        public void notify(EventCallback callback) {
+                            callback.onInfo(
+                                    mMediaPlayer, dsd, MEDIA_INFO_BUFFERING_UPDATE, percent);
+                        }
+                    });
+
+                    SourceInfo src = getSourceInfo(srcId);
+                    if (src != null) {
+                        src.mBufferedPercentage.set(percent);
+                    }
+
+                    return;
+                }
+
+                case MEDIA_SEEK_COMPLETE:
+                {
+                    synchronized (mTaskLock) {
+                        if (!mPendingTasks.isEmpty()
+                                && mPendingTasks.get(0).mMediaCallType != CALL_COMPLETED_SEEK_TO
+                                && getState() == PLAYER_STATE_PLAYING) {
+                            mIsPreviousCommandSeekTo = false;
+                        }
+
+                        if (mCurrentTask != null
+                                && mCurrentTask.mMediaCallType == CALL_COMPLETED_SEEK_TO
+                                && mCurrentTask.mNeedToWaitForEventToComplete) {
+                            mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
+                            mCurrentTask = null;
+                            processPendingTask_l();
+                        }
+                    }
+                    return;
+                }
+
+                case MEDIA_SET_VIDEO_SIZE:
+                {
+                    final int width = msg.arg1;
+                    final int height = msg.arg2;
+
+                    mVideoSize = new VideoSize(width, height);
+                    sendEvent(new EventNotifier() {
+                        @Override
+                        public void notify(EventCallback callback) {
+                            callback.onVideoSizeChanged(
+                                    mMediaPlayer, dsd, mVideoSize);
+                        }
+                    });
+                    return;
+                }
+
+                case MEDIA_ERROR:
+                {
+                    Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
+                    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;
+                }
+
+                case MEDIA_INFO:
+                {
+                    switch (msg.arg1) {
+                        case MEDIA_INFO_VIDEO_TRACK_LAGGING:
+                            Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
+                            break;
+                    }
+
+                    sendEvent(new EventNotifier() {
+                        @Override
+                        public void notify(EventCallback callback) {
+                            callback.onInfo(
+                                    mMediaPlayer, dsd, what, extra);
+                        }
+                    });
+
+                    if (msg.arg1 == MEDIA_INFO_DATA_SOURCE_START) {
+                        if (isCurrentSource(srcId)) {
+                            prepareNextDataSource();
+                        }
+                    }
+
+                    // No real default action so far.
+                    return;
+                }
+
+                case MEDIA_TIMED_TEXT:
+                {
+                    final TimedText text;
+                    if (msg.obj instanceof byte[]) {
+                        PlayerMessage playerMsg;
+                        try {
+                            playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
+                        } catch (InvalidProtocolBufferException e) {
+                            Log.w(TAG, "Failed to parse timed text.", e);
+                            return;
+                        }
+                        text = TimedTextUtil.parsePlayerMessage(playerMsg);
+                    } else {
+                        text = null;
+                    }
+
+                    sendEvent(new EventNotifier() {
+                        @Override
+                        public void notify(EventCallback callback) {
+                            callback.onTimedText(
+                                    mMediaPlayer, dsd, text);
+                        }
+                    });
+                    return;
+                }
+
+                case MEDIA_SUBTITLE_DATA:
+                {
+                    if (msg.obj instanceof byte[]) {
+                        PlayerMessage playerMsg;
+                        try {
+                            playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
+                        } catch (InvalidProtocolBufferException e) {
+                            Log.w(TAG, "Failed to parse subtitle data.", e);
+                            return;
+                        }
+                        Iterator<Value> in = playerMsg.getValuesList().iterator();
+                        SubtitleData data = new SubtitleData.Builder()
+                                .setSubtitleData(
+                                    in.next().getInt32Value(),  // trackIndex
+                                    in.next().getInt64Value(),  // startTimeUs
+                                    in.next().getInt64Value(),  // durationUs
+                                    in.next().getBytesValue().toByteArray())  // data
+                                .build();
+                        sendEvent(new EventNotifier() {
+                            @Override
+                            public void notify(EventCallback callback) {
+                                callback.onSubtitleData(
+                                        mMediaPlayer, dsd, data);
+                            }
+                        });
+                    }
+                    return;
+                }
+
+                case MEDIA_META_DATA:
+                {
+                    final TimedMetaData data;
+                    if (msg.obj instanceof byte[]) {
+                        PlayerMessage playerMsg;
+                        try {
+                            playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
+                        } catch (InvalidProtocolBufferException e) {
+                            Log.w(TAG, "Failed to parse timed meta data.", e);
+                            return;
+                        }
+                        Iterator<Value> in = playerMsg.getValuesList().iterator();
+                        data = new TimedMetaData.Builder()
+                                .setTimedMetaData(
+                                    in.next().getInt64Value(),  // timestampUs
+                                    in.next().getBytesValue().toByteArray())  // metaData
+                                .build();
+                    } else {
+                        data = null;
+                    }
+
+                    sendEvent(new EventNotifier() {
+                        @Override
+                        public void notify(EventCallback callback) {
+                            callback.onTimedMetaDataAvailable(
+                                    mMediaPlayer, dsd, data);
+                        }
+                    });
+                    return;
+                }
+
+                case MEDIA_NOP: // interface test message - ignore
+                {
+                    break;
+                }
+
+                default:
+                {
+                    Log.e(TAG, "Unknown message type " + msg.what);
+                    return;
+                }
+            }
+        }
+    }
+
+    /*
+     * Called from native code when an interesting event happens.  This method
+     * just uses the TaskHandler system to post the event back to the main app thread.
+     * We use a weak reference to the original MediaPlayer2 object so that the native
+     * code is safe from the object disappearing from underneath it.  (This is
+     * the cookie passed to native_setup().)
+     */
+    private static void postEventFromNative(Object mediaplayer2Ref, long srcId,
+                                            int what, int arg1, int arg2, byte[] obj) {
+        final MediaPlayer2 mp = (MediaPlayer2) ((WeakReference) mediaplayer2Ref).get();
+        if (mp == null) {
+            return;
+        }
+
+        final SourceInfo sourceInfo = mp.getSourceInfo(srcId);
+        switch (what) {
+            case MEDIA_DRM_INFO:
+                // We need to derive mDrmInfo before prepare() returns so processing it here
+                // before the notification is sent to TaskHandler below. TaskHandler runs in the
+                // notification looper so its handleMessage might process the event after prepare()
+                // has returned.
+                Log.v(TAG, "postEventFromNative MEDIA_DRM_INFO");
+                if (obj != null && sourceInfo != null) {
+                    PlayerMessage playerMsg;
+                    try {
+                        playerMsg = PlayerMessage.parseFrom(obj);
+                    } catch (InvalidProtocolBufferException e) {
+                        Log.w(TAG, "MEDIA_DRM_INFO failed to parse msg.obj " + obj);
+                        break;
+                    }
+                    DrmInfo drmInfo = DrmInfo.create(playerMsg);
+                    synchronized (sourceInfo) {
+                        sourceInfo.mDrmInfo = drmInfo;
+                    }
+                } else {
+                    Log.w(TAG, "MEDIA_DRM_INFO sourceInfo " + sourceInfo
+                            + " msg.obj of unexpected type " + obj);
+                }
+                break;
+
+            case MEDIA_PREPARED:
+                // By this time, we've learned about DrmInfo's presence or absence. This is meant
+                // mainly for prepare() use case. For prepare(), this still can run to a race
+                // condition b/c MediaPlayerNative releases the prepare() lock before calling notify
+                // so we also set mDrmInfoResolved in prepare().
+                if (sourceInfo != null) {
+                    synchronized (sourceInfo) {
+                        sourceInfo.mDrmInfoResolved = true;
+                    }
+                }
+                break;
+        }
+
+        if (mp.mTaskHandler != null) {
+            Message m = mp.mTaskHandler.obtainMessage(what, arg1, arg2, obj);
+
+            mp.mTaskHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mp.mTaskHandler.handleMessage(m, srcId);
+                }
+            });
+        }
+    }
+
+    /**
+     * Interface definition for callbacks to be invoked when the player has the corresponding
+     * events.
+     */
+    public static class EventCallback {
+        /**
+         * Called to indicate the video size
+         *
+         * The video size (width and height) could be 0 if there was no video,
+         * no display surface was set, or the value was not determined yet.
+         *
+         * @param mp the MediaPlayer2 associated with this callback
+         * @param dsd the DataSourceDesc of this data source
+         * @param size the size of the video
+         */
+        public void onVideoSizeChanged(
+                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd, @NonNull VideoSize size) { }
+
+        /**
+         * Called to indicate an avaliable timed text
+         *
+         * @param mp the MediaPlayer2 associated with this callback
+         * @param dsd the DataSourceDesc of this data source
+         * @param text the timed text sample which contains the text
+         *             needed to be displayed and the display format.
+         * @hide
+         */
+        public void onTimedText(
+                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd, @NonNull TimedText text) { }
+
+        /**
+         * Called to indicate avaliable timed metadata
+         * <p>
+         * This method will be called as timed metadata is extracted from the media,
+         * in the same order as it occurs in the media. The timing of this event is
+         * not controlled by the associated timestamp.
+         * <p>
+         * Currently only HTTP live streaming data URI's embedded with timed ID3 tags generates
+         * {@link TimedMetaData}.
+         *
+         * @see MediaPlayer2#selectTrack
+         * @see MediaPlayer2.OnTimedMetaDataAvailableListener
+         * @see TimedMetaData
+         *
+         * @param mp the MediaPlayer2 associated with this callback
+         * @param dsd the DataSourceDesc of this data source
+         * @param data the timed metadata sample associated with this event
+         */
+        public void onTimedMetaDataAvailable(
+                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+                @NonNull TimedMetaData data) { }
+
+        /**
+         * Called to indicate an error.
+         *
+         * @param mp the MediaPlayer2 the error pertains to
+         * @param dsd the DataSourceDesc of this data source
+         * @param what the type of error that has occurred.
+         * @param extra an extra code, specific to the error. Typically
+         * implementation dependent.
+         */
+        public void onError(
+                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+                @MediaError int what, int extra) { }
+
+        /**
+         * Called to indicate an info or a warning.
+         *
+         * @param mp the MediaPlayer2 the info pertains to.
+         * @param dsd the DataSourceDesc of this data source
+         * @param what the type of info or warning.
+         * @param extra an extra code, specific to the info. Typically
+         * implementation dependent.
+         */
+        public void onInfo(
+                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+                @MediaInfo int what, int extra) { }
+
+        /**
+         * Called to acknowledge an API call.
+         *
+         * @param mp the MediaPlayer2 the call was made on.
+         * @param dsd the DataSourceDesc of this data source
+         * @param what the enum for the API call.
+         * @param status the returned status code for the call.
+         */
+        public void onCallCompleted(
+                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd, @CallCompleted int what,
+                @CallStatus int status) { }
+
+        /**
+         * Called to indicate media clock has changed.
+         *
+         * @param mp the MediaPlayer2 the media time pertains to.
+         * @param dsd the DataSourceDesc of this data source
+         * @param timestamp the new media clock.
+         */
+        public void onMediaTimeDiscontinuity(
+                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+                @NonNull MediaTimestamp timestamp) { }
+
+        /**
+         * Called to indicate {@link #notifyWhenCommandLabelReached(Object)} has been processed.
+         *
+         * @param mp the MediaPlayer2 {@link #notifyWhenCommandLabelReached(Object)} was called on.
+         * @param label the application specific Object given by
+         *        {@link #notifyWhenCommandLabelReached(Object)}.
+         */
+        public void onCommandLabelReached(@NonNull MediaPlayer2 mp, @NonNull Object label) { }
+
+        /**
+         * Called when when a player subtitle track has new subtitle data available.
+         * @param mp the player that reports the new subtitle data
+         * @param dsd the DataSourceDesc of this data source
+         * @param data the subtitle data
+         */
+        public void onSubtitleData(
+                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+                @NonNull SubtitleData data) { }
+    }
+
+    private final Object mEventCbLock = new Object();
+    private ArrayList<Pair<Executor, EventCallback>> mEventCallbackRecords =
+            new ArrayList<Pair<Executor, EventCallback>>();
+
+    /**
+     * Registers the callback to be invoked for various events covered by {@link EventCallback}.
+     *
+     * @param executor the executor through which the callback should be invoked
+     * @param eventCallback the callback that will be run
+     */
+    // This is a synchronous call.
+    public void registerEventCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull EventCallback eventCallback) {
+        if (eventCallback == null) {
+            throw new IllegalArgumentException("Illegal null EventCallback");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException(
+                    "Illegal null Executor for the EventCallback");
+        }
+        synchronized (mEventCbLock) {
+            for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
+                if (cb.first == executor && cb.second == eventCallback) {
+                    Log.w(TAG, "The callback has been registered before.");
+                    return;
+                }
+            }
+            mEventCallbackRecords.add(new Pair(executor, eventCallback));
+        }
+    }
+
+    /**
+     * Unregisters the {@link EventCallback}.
+     *
+     * @param eventCallback the callback to be unregistered
+     */
+    // This is a synchronous call.
+    public void unregisterEventCallback(EventCallback eventCallback) {
+        synchronized (mEventCbLock) {
+            for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
+                if (cb.second == eventCallback) {
+                    mEventCallbackRecords.remove(cb);
+                }
+            }
+        }
+    }
+
+    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 (mDrmEventCallbackLock) {
+            try {
+                Pair<Executor, DrmEventCallback> cb = mDrmEventCallback;
+                if (cb != null) {
+                    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 <T> T sendDrmEventWait(final DrmEventNotifier<T> notifier)
+            throws InterruptedException, ExecutionException, TimeoutException {
+        return sendDrmEventWait(notifier, 0);
+    }
+
+    private <T> T sendDrmEventWait(final DrmEventNotifier<T> notifier, final long timeoutMs)
+            throws InterruptedException, ExecutionException, TimeoutException {
+        synchronized (mDrmEventCallbackLock) {
+            Pair<Executor, DrmEventCallback> cb = mDrmEventCallback;
+            if (cb != null) {
+                CompletableFuture<T> ret = new CompletableFuture<>();
+                cb.first.execute(() -> ret.complete(notifier.notifyWait(cb.second)));
+                return timeoutMs <= 0 ? ret.get() : ret.get(timeoutMs, TimeUnit.MILLISECONDS);
+            }
+        }
+        return null;
+    }
+
+    private interface EventNotifier {
+        void notify(EventCallback callback);
+    }
+
+    private interface DrmEventNotifier<T> {
+        default void notify(DrmEventCallback callback) { }
+        default T notifyWait(DrmEventCallback callback) {
+            return null;
+        }
+    }
+
+    /* Do not change these values without updating their counterparts
+     * in include/media/MediaPlayer2Types.h!
+     */
+    /** Unspecified media player error.
+     * @see EventCallback#onError
+     */
+    public static final int MEDIA_ERROR_UNKNOWN = 1;
+
+    /**
+     * The video is streamed and its container is not valid for progressive
+     * playback i.e the video's index (e.g moov atom) is not at the start of the
+     * file.
+     * @see EventCallback#onError
+     */
+    public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;
+
+    /** File or network related operation errors. */
+    public static final int MEDIA_ERROR_IO = -1004;
+    /** Bitstream is not conforming to the related coding standard or file spec. */
+    public static final int MEDIA_ERROR_MALFORMED = -1007;
+    /** Bitstream is conforming to the related coding standard or file spec, but
+     * the media framework does not support the feature. */
+    public static final int MEDIA_ERROR_UNSUPPORTED = -1010;
+    /** Some operation takes too long to complete, usually more than 3-5 seconds. */
+    public static final int MEDIA_ERROR_TIMED_OUT = -110;
+
+    /** Unspecified low-level system error. This value originated from UNKNOWN_ERROR in
+     * system/core/include/utils/Errors.h
+     * @see EventCallback#onError
+     * @hide
+     */
+    public static final int MEDIA_ERROR_SYSTEM = -2147483648;
+
+    /**
+     * @hide
+     */
+    @IntDef(flag = false, prefix = "MEDIA_ERROR", value = {
+            MEDIA_ERROR_UNKNOWN,
+            MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK,
+            MEDIA_ERROR_IO,
+            MEDIA_ERROR_MALFORMED,
+            MEDIA_ERROR_UNSUPPORTED,
+            MEDIA_ERROR_TIMED_OUT,
+            MEDIA_ERROR_SYSTEM
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MediaError {}
+
+    /* Do not change these values without updating their counterparts
+     * in include/media/MediaPlayer2Types.h!
+     */
+    /** Unspecified media player info.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_UNKNOWN = 1;
+
+    /** The player just started the playback of this datas source.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_DATA_SOURCE_START = 2;
+
+    /** The player just pushed the very first video frame for rendering.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3;
+
+    /** The player just rendered the very first audio sample.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_AUDIO_RENDERING_START = 4;
+
+    /** The player just completed the playback of this data source.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_DATA_SOURCE_END = 5;
+
+    /** The player just completed the playback of all data sources set by {@link #setDataSource},
+     * {@link #setNextDataSource} and {@link #setNextDataSources}.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_DATA_SOURCE_LIST_END = 6;
+
+    /** The player just completed an iteration of playback loop. This event is sent only when
+     *  looping is enabled by {@link #loopCurrent}.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_DATA_SOURCE_REPEAT = 7;
+
+    /** The player just prepared a data source.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_PREPARED = 100;
+
+    /** The video is too complex for the decoder: it can't decode frames fast
+     *  enough. Possibly only the audio plays fine at this stage.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;
+
+    /** MediaPlayer2 is temporarily pausing playback internally in order to
+     * buffer more data.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_BUFFERING_START = 701;
+
+    /** MediaPlayer2 is resuming playback after filling buffers.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_BUFFERING_END = 702;
+
+    /** Estimated network bandwidth information (kbps) is available; currently this event fires
+     * simultaneously as {@link #MEDIA_INFO_BUFFERING_START} and {@link #MEDIA_INFO_BUFFERING_END}
+     * when playing network files.
+     * @see EventCallback#onInfo
+     * @hide
+     */
+    public static final int MEDIA_INFO_NETWORK_BANDWIDTH = 703;
+
+    /**
+     * Update status in buffering a media source received through progressive downloading.
+     * The received buffering percentage indicates how much of the content has been buffered
+     * or played. For example a buffering update of 80 percent when half the content
+     * has already been played indicates that the next 30 percent of the
+     * content to play has been buffered.
+     *
+     * The {@code extra} parameter in {@code EventCallback.onInfo} is the
+     * percentage (0-100) of the content that has been buffered or played thus far.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_BUFFERING_UPDATE = 704;
+
+    /** Bad interleaving means that a media has been improperly interleaved or
+     * not interleaved at all, e.g has all the video samples first then all the
+     * audio ones. Video is playing but a lot of disk seeks may be happening.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_BAD_INTERLEAVING = 800;
+
+    /** The media cannot be seeked (e.g live stream)
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_NOT_SEEKABLE = 801;
+
+    /** A new set of metadata is available.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_METADATA_UPDATE = 802;
+
+    /** Informs that audio is not playing. Note that playback of the video
+     * is not interrupted.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_AUDIO_NOT_PLAYING = 804;
+
+    /** Informs that video is not playing. Note that playback of the audio
+     * is not interrupted.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_VIDEO_NOT_PLAYING = 805;
+
+    /** Failed to handle timed text track properly.
+     * @see EventCallback#onInfo
+     *
+     * {@hide}
+     */
+    public static final int MEDIA_INFO_TIMED_TEXT_ERROR = 900;
+
+    /** Subtitle track was not supported by the media framework.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901;
+
+    /** Reading the subtitle track takes too long.
+     * @see EventCallback#onInfo
+     */
+    public static final int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902;
+
+    /**
+     * @hide
+     */
+    @IntDef(flag = false, prefix = "MEDIA_INFO", value = {
+            MEDIA_INFO_UNKNOWN,
+            MEDIA_INFO_DATA_SOURCE_START,
+            MEDIA_INFO_VIDEO_RENDERING_START,
+            MEDIA_INFO_AUDIO_RENDERING_START,
+            MEDIA_INFO_DATA_SOURCE_END,
+            MEDIA_INFO_DATA_SOURCE_LIST_END,
+            MEDIA_INFO_PREPARED,
+            MEDIA_INFO_VIDEO_TRACK_LAGGING,
+            MEDIA_INFO_BUFFERING_START,
+            MEDIA_INFO_BUFFERING_END,
+            MEDIA_INFO_NETWORK_BANDWIDTH,
+            MEDIA_INFO_BUFFERING_UPDATE,
+            MEDIA_INFO_BAD_INTERLEAVING,
+            MEDIA_INFO_NOT_SEEKABLE,
+            MEDIA_INFO_METADATA_UPDATE,
+            MEDIA_INFO_AUDIO_NOT_PLAYING,
+            MEDIA_INFO_VIDEO_NOT_PLAYING,
+            MEDIA_INFO_TIMED_TEXT_ERROR,
+            MEDIA_INFO_UNSUPPORTED_SUBTITLE,
+            MEDIA_INFO_SUBTITLE_TIMED_OUT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MediaInfo {}
+
+    //--------------------------------------------------------------------------
+    /** The player just completed a call {@link #attachAuxEffect}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_ATTACH_AUX_EFFECT = 1;
+
+    /** The player just completed a call {@link #deselectTrack}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_DESELECT_TRACK = 2;
+
+    /** The player just completed a call {@link #loopCurrent}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_LOOP_CURRENT = 3;
+
+    /** The player just completed a call {@link #pause}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_PAUSE = 4;
+
+    /** The player just completed a call {@link #play}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_PLAY = 5;
+
+    /** The player just completed a call {@link #prepare}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_PREPARE = 6;
+
+    /** The player just completed a call {@link #seekTo}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SEEK_TO = 14;
+
+    /** The player just completed a call {@link #selectTrack}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SELECT_TRACK = 15;
+
+    /** The player just completed a call {@link #setAudioAttributes}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_AUDIO_ATTRIBUTES = 16;
+
+    /** The player just completed a call {@link #setAudioSessionId}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_AUDIO_SESSION_ID = 17;
+
+    /** The player just completed a call {@link #setAuxEffectSendLevel}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL = 18;
+
+    /** The player just completed a call {@link #setDataSource}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_DATA_SOURCE = 19;
+
+    /** The player just completed a call {@link #setNextDataSource}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCE = 22;
+
+    /** The player just completed a call {@link #setNextDataSources}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCES = 23;
+
+    /** The player just completed a call {@link #setPlaybackParams}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_PLAYBACK_PARAMS = 24;
+
+    /** The player just completed a call {@link #setPlayerVolume}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_PLAYER_VOLUME = 26;
+
+    /** The player just completed a call {@link #setSurface}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_SURFACE = 27;
+
+    /** The player just completed a call {@link #setSyncParams}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_SYNC_PARAMS = 28;
+
+    /** The player just completed a call {@link #skipToNext}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SKIP_TO_NEXT = 29;
+
+    /** The player just completed a call {@link #clearNextDataSources}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES = 30;
+
+    /** The player just completed a call {@link #setBufferingParams}.
+     * @see EventCallback#onCallCompleted
+     * @hide
+     */
+    public static final int CALL_COMPLETED_SET_BUFFERING_PARAMS = 31;
+
+    /** The player just completed a call {@link #setDisplay}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_DISPLAY = 33;
+
+    /** The player just completed a call {@link #setWakeLock}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_WAKE_LOCK = 34;
+
+    /** The player just completed a call {@link #setScreenOnWhilePlaying}.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING = 35;
+
+    /**
+     * The start of the methods which have separate call complete callback.
+     * @hide
+     */
+    public static final int SEPARATE_CALL_COMPLETED_CALLBACK_START = 1000;
+
+    /** The player just completed a call {@link #notifyWhenCommandLabelReached}.
+     * @see EventCallback#onCommandLabelReached
+     * @hide
+     */
+    public static final int CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED =
+            SEPARATE_CALL_COMPLETED_CALLBACK_START;
+
+    /** The player just completed a call {@link #prepareDrm}.
+     * @see DrmEventCallback#onDrmPrepared
+     * @hide
+     */
+    public static final int CALL_COMPLETED_PREPARE_DRM =
+            SEPARATE_CALL_COMPLETED_CALLBACK_START + 1;
+
+    /**
+     * @hide
+     */
+    @IntDef(flag = false, prefix = "CALL_COMPLETED", value = {
+            CALL_COMPLETED_ATTACH_AUX_EFFECT,
+            CALL_COMPLETED_DESELECT_TRACK,
+            CALL_COMPLETED_LOOP_CURRENT,
+            CALL_COMPLETED_PAUSE,
+            CALL_COMPLETED_PLAY,
+            CALL_COMPLETED_PREPARE,
+            CALL_COMPLETED_SEEK_TO,
+            CALL_COMPLETED_SELECT_TRACK,
+            CALL_COMPLETED_SET_AUDIO_ATTRIBUTES,
+            CALL_COMPLETED_SET_AUDIO_SESSION_ID,
+            CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL,
+            CALL_COMPLETED_SET_DATA_SOURCE,
+            CALL_COMPLETED_SET_NEXT_DATA_SOURCE,
+            CALL_COMPLETED_SET_NEXT_DATA_SOURCES,
+            CALL_COMPLETED_SET_PLAYBACK_PARAMS,
+            CALL_COMPLETED_SET_PLAYER_VOLUME,
+            CALL_COMPLETED_SET_SURFACE,
+            CALL_COMPLETED_SET_SYNC_PARAMS,
+            CALL_COMPLETED_SKIP_TO_NEXT,
+            CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES,
+            CALL_COMPLETED_SET_BUFFERING_PARAMS,
+            CALL_COMPLETED_SET_DISPLAY,
+            CALL_COMPLETED_SET_WAKE_LOCK,
+            CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING,
+            CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED,
+            CALL_COMPLETED_PREPARE_DRM,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CallCompleted {}
+
+    /** Status code represents that call is completed without an error.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_NO_ERROR = 0;
+
+    /** Status code represents that call is ended with an unknown error.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_ERROR_UNKNOWN = Integer.MIN_VALUE;
+
+    /** Status code represents that the player is not in valid state for the operation.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_INVALID_OPERATION = 1;
+
+    /** Status code represents that the argument is illegal.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_BAD_VALUE = 2;
+
+    /** Status code represents that the operation is not allowed.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_PERMISSION_DENIED = 3;
+
+    /** Status code represents a file or network related operation error.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_ERROR_IO = 4;
+
+    /** Status code represents that the call has been skipped. For example, a {@link #seekTo}
+     * request may be skipped if it is followed by another {@link #seekTo} request.
+     * @see EventCallback#onCallCompleted
+     */
+    public static final int CALL_STATUS_SKIPPED = 5;
+
+    /** Status code represents that DRM operation is called before preparing a DRM scheme through
+     *  {@code prepareDrm}.
+     * @see EventCallback#onCallCompleted
+     */
+    // TODO: change @code to @link when DRM is unhidden
+    public static final int CALL_STATUS_NO_DRM_SCHEME = 6;
+
+    /**
+     * @hide
+     */
+    @IntDef(flag = false, prefix = "CALL_STATUS", value = {
+            CALL_STATUS_NO_ERROR,
+            CALL_STATUS_ERROR_UNKNOWN,
+            CALL_STATUS_INVALID_OPERATION,
+            CALL_STATUS_BAD_VALUE,
+            CALL_STATUS_PERMISSION_DENIED,
+            CALL_STATUS_ERROR_IO,
+            CALL_STATUS_SKIPPED,
+            CALL_STATUS_NO_DRM_SCHEME})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CallStatus {}
+
+    // Modular DRM begin
+
+    /**
+     * An immutable structure per {@link DataSourceDesc} with settings required to initiate a DRM
+     * protected playback session.
+     *
+     * @see DrmPreparationInfo.Builder
+     */
+    public static final class DrmPreparationInfo {
+
+        /**
+         * Mutable builder to create a {@link MediaPlayer2.DrmPreparationInfo} object.
+         */
+        public static final class Builder {
+
+            private UUID mUUID;
+            private byte[] mKeySetId;
+            private byte[] mInitData;
+            private String mMimeType;
+            private int mKeyType;
+            private Map<String, String> mOptionalParameters;
+
+            /**
+             * Set UUID of the crypto scheme selected to decrypt content. An UUID can be retrieved
+             * from the source listening to {@link MediaPlayer2.DrmEventCallback#onDrmInfo}.
+             *
+             * @param uuid of selected crypto scheme
+             * @return this
+             */
+            public Builder setUuid(@NonNull UUID uuid) {
+                this.mUUID = uuid;
+                return this;
+            }
+
+            /**
+             * Set identifier of a persisted offline key obtained from
+             * {@link MediaPlayer2.DrmEventCallback#onDrmPrepared}.
+             *
+             * A {@code keySetId} can be used to restore persisted offline keys into a new playback
+             * session of a DRM protected data source. When {@code keySetId} is set,
+             * {@code initData}, {@code mimeType}, {@code keyType}, {@code optionalParameters} are
+             * ignored.
+             *
+             * @param keySetId identifier of a persisted offline key
+             * @return this
+             */
+            public Builder setKeySetId(@Nullable byte[] keySetId) {
+                this.mKeySetId = keySetId;
+                return this;
+            }
+
+            /**
+             * Set container-specific DRM initialization data. Its meaning is interpreted based on
+             * {@code mimeType}. For example, it could contain the content ID, key ID or other data
+             * obtained from the content metadata that is required to generate a
+             * {@link MediaDrm.KeyRequest}.
+             *
+             * @param initData container-specific DRM initialization data
+             * @return this
+             */
+            public Builder setInitData(@Nullable byte[] initData) {
+                this.mInitData = initData;
+                return this;
+            }
+
+            /**
+             * Set mime type of the content
+             *
+             * @param mimeType mime type to the content
+             * @return this
+             */
+            public Builder setMimeType(@Nullable String mimeType) {
+                this.mMimeType = mimeType;
+                return this;
+            }
+
+            /**
+             * Set type of the key request. The request may be to acquire keys
+             * for streaming, {@link MediaDrm#KEY_TYPE_STREAMING}, or for offline content,
+             * {@link MediaDrm#KEY_TYPE_OFFLINE}. Releasing previously acquired keys
+             * ({@link MediaDrm#KEY_TYPE_RELEASE}) is not allowed.
+             *
+             * @param keyType type of the key request
+             * @return this
+             */
+            public Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) {
+                this.mKeyType = keyType;
+                return this;
+            }
+
+            /**
+             * Set optional parameters to be included in a {@link MediaDrm.KeyRequest} message sent
+             * to the license server.
+             *
+             * @param optionalParameters optional parameters to be included in a key request
+             * @return this
+             */
+            public Builder setOptionalParameters(@Nullable Map<String, String> optionalParameters) {
+                this.mOptionalParameters = optionalParameters;
+                return this;
+            }
+
+            /**
+             * @return an immutable {@link MediaPlayer2.DrmPreparationInfo} representing the
+             *         settings of this builder
+             */
+            public MediaPlayer2.DrmPreparationInfo build() {
+                return new MediaPlayer2.DrmPreparationInfo(mUUID, mKeySetId, mInitData, mMimeType,
+                        mKeyType, mOptionalParameters);
+            }
+
+        }
+
+        private final UUID mUUID;
+        private final byte[] mKeySetId;
+        private final byte[] mInitData;
+        private final String mMimeType;
+        private final int mKeyType;
+        private final Map<String, String> mOptionalParameters;
+
+        private DrmPreparationInfo(UUID mUUID, byte[] mKeySetId, byte[] mInitData, String mMimeType,
+                int mKeyType, Map<String, String> optionalParameters) {
+            this.mUUID = mUUID;
+            this.mKeySetId = mKeySetId;
+            this.mInitData = mInitData;
+            this.mMimeType = mMimeType;
+            this.mKeyType = mKeyType;
+            this.mOptionalParameters = optionalParameters;
+        }
+
+        boolean isValid() {
+            if (mUUID == null) {
+                return false;
+            }
+            if (mKeySetId != null) {
+                // offline restore case
+                return true;
+            }
+            if (mInitData != null && mMimeType != null) {
+                // new streaming license case
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Interface definition for callbacks to be invoked when the player has the corresponding
+     * DRM events.
+     */
+    public static class DrmEventCallback {
+
+        /**
+         * Called to indicate DRM info is available. Return a {@link DrmPreparationInfo} object that
+         * bundles DRM initialization parameters.
+         *
+         * @param mp the {@code MediaPlayer2} associated with this callback
+         * @param dsd the {@link DataSourceDesc} of this data source
+         * @param drmInfo DRM info of the source including PSSH, and subset of crypto schemes
+         *        supported by this device
+         * @return a {@link DrmPreparationInfo} object to initialize DRM playback, or null to skip
+         *         DRM initialization
+         */
+        public DrmPreparationInfo onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) {
+            return null;
+        }
+
+        /**
+         * Called to give the app the opportunity to configure DRM before the session is created.
+         *
+         * This facilitates configuration of the properties, like 'securityLevel', which
+         * has to be set after DRM scheme creation but before the DRM session is opened.
+         *
+         * The only allowed DRM calls in this listener are
+         * {@link MediaDrm#getPropertyString(String)},
+         * {@link MediaDrm#getPropertyByteArray(String)},
+         * {@link MediaDrm#setPropertyString(String, String)},
+         * {@link MediaDrm#setPropertyByteArray(String, byte[])},
+         * {@link MediaDrm#setOnExpirationUpdateListener},
+         * and {@link MediaDrm#setOnKeyStatusChangeListener}.
+         *
+         * @param mp the {@code MediaPlayer2} associated with this callback
+         * @param dsd the {@link DataSourceDesc} of this data source
+         * @param drm handle to get/set DRM properties and listeners for this data source
+         */
+        public void onDrmConfig(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+                @NonNull MediaDrm drm) { }
+
+        /**
+         * Called to indicate the DRM session for {@code dsd} is ready for key request/response
+         *
+         * @param mp the {@code MediaPlayer2} associated with this callback
+         * @param dsd the {@link DataSourceDesc} of this data source
+         * @param request a {@link MediaDrm.KeyRequest} prepared using the
+         *        {@link DrmPreparationInfo} returned from
+         *        {@link #onDrmInfo(MediaPlayer2, DataSourceDesc, DrmInfo)}
+         * @return the response to {@code request} (from license server)
+         */
+        public byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+                @NonNull MediaDrm.KeyRequest request) {
+            return null;
+        }
+
+        /**
+         * Called to notify the client that {@code mp} is ready to decrypt DRM protected data source
+         * {@code dsd} or if there is an error during DRM preparation
+         *
+         * @param mp the {@code MediaPlayer2} associated with this callback
+         * @param dsd the {@link DataSourceDesc} of this data source
+         * @param status the result of DRM preparation.
+         * @param keySetId optional identifier that can be used to restore DRM playback initiated
+         *        with a {@link MediaDrm#KEY_TYPE_OFFLINE} key request.
+         *
+         * @see DrmPreparationInfo.Builder#setKeySetId(byte[])
+         */
+        public void onDrmPrepared(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+                @PrepareDrmStatusCode int status, @Nullable byte[] keySetId) { }
+
+    }
+
+    private final Object mDrmEventCallbackLock = new Object();
+    private Pair<Executor, DrmEventCallback> mDrmEventCallback;
+
+    /**
+     * Registers the callback to be invoked for various DRM events.
+     *
+     * @param eventCallback the callback that will be run
+     * @param executor the executor through which the callback should be invoked
+     */
+    // This is a synchronous call.
+    public void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull DrmEventCallback eventCallback) {
+        if (eventCallback == null) {
+            throw new IllegalArgumentException("Illegal null EventCallback");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException(
+                    "Illegal null Executor for the EventCallback");
+        }
+        synchronized (mDrmEventCallbackLock) {
+            mDrmEventCallback = new Pair<Executor, DrmEventCallback>(executor, eventCallback);
+        }
+    }
+
+    /**
+     * Clear the {@link DrmEventCallback}.
+     */
+    // This is a synchronous call.
+    public void clearDrmEventCallback() {
+        synchronized (mDrmEventCallbackLock) {
+            mDrmEventCallback = null;
+        }
+    }
+
+    /**
+     * The status codes for {@link DrmEventCallback#onDrmPrepared} listener.
+     * <p>
+     *
+     * DRM preparation has succeeded.
+     * @hide
+     */
+    public static final int PREPARE_DRM_STATUS_SUCCESS = 0;
+
+    /**
+     * The device required DRM provisioning but couldn't reach the provisioning server.
+     * @hide
+     */
+    public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1;
+
+    /**
+     * The device required DRM provisioning but the provisioning server denied the request.
+     * @hide
+     */
+    public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2;
+
+    /**
+     * The DRM preparation has failed .
+     * @hide
+     */
+    public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3;
+
+    /**
+     * The crypto scheme UUID is not supported by the device.
+     * @hide
+     */
+    public static final int PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME = 4;
+
+    /**
+     * The hardware resources are not available, due to being in use.
+     * @hide
+     */
+    public static final int PREPARE_DRM_STATUS_RESOURCE_BUSY = 5;
+
+    /**
+     * Restoring persisted offline keys failed.
+     * @hide
+     */
+    public static final int PREPARE_DRM_STATUS_RESTORE_ERROR = 6;
+
+    /**
+     * Error during key request/response exchange with license server.
+     * @hide
+     */
+    public static final int PREPARE_DRM_STATUS_KEY_EXCHANGE_ERROR = 7;
+
+    /** @hide */
+    @IntDef(flag = false, prefix = "PREPARE_DRM_STATUS", value = {
+        PREPARE_DRM_STATUS_SUCCESS,
+        PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR,
+        PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR,
+        PREPARE_DRM_STATUS_PREPARATION_ERROR,
+        PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME,
+        PREPARE_DRM_STATUS_RESOURCE_BUSY,
+        PREPARE_DRM_STATUS_RESTORE_ERROR,
+        PREPARE_DRM_STATUS_KEY_EXCHANGE_ERROR,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PrepareDrmStatusCode {}
+
+    /** @hide */
+    @IntDef({
+        MediaDrm.KEY_TYPE_STREAMING,
+        MediaDrm.KEY_TYPE_OFFLINE,
+        MediaDrm.KEY_TYPE_RELEASE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MediaDrmKeyType {}
+
+    /** @hide */
+    @StringDef({
+        MediaDrm.PROPERTY_VENDOR,
+        MediaDrm.PROPERTY_VERSION,
+        MediaDrm.PROPERTY_DESCRIPTION,
+        MediaDrm.PROPERTY_ALGORITHMS,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MediaDrmStringProperty {}
+
+    /**
+     * Retrieves the DRM Info associated with the given source
+     *
+     * @param dsd The DRM protected data source
+     *
+     * @throws IllegalStateException if called before being prepared
+     * @hide
+     */
+    public DrmInfo getDrmInfo(@NonNull DataSourceDesc dsd) {
+        final SourceInfo sourceInfo = getSourceInfo(dsd);
+        if (sourceInfo != null) {
+            DrmInfo drmInfo = null;
+
+            // there is not much point if the app calls getDrmInfo within an OnDrmInfoListener;
+            // regardless below returns drmInfo anyway instead of raising an exception
+            synchronized (sourceInfo) {
+                if (!sourceInfo.mDrmInfoResolved && sourceInfo.mDrmInfo == null) {
+                    final String msg = "The Player has not been prepared yet";
+                    Log.v(TAG, msg);
+                    throw new IllegalStateException(msg);
+                }
+
+                if (sourceInfo.mDrmInfo != null) {
+                    drmInfo  = sourceInfo.mDrmInfo.makeCopy();
+                }
+            }   // synchronized
+
+            return drmInfo;
+        }
+        return null;
+    }
+
+    /**
+     * Prepares the DRM for the given data source
+     * <p>
+     * If {@link DrmEventCallback} is registered, it will be called during
+     * preparation to allow configuration of the DRM properties before opening the
+     * DRM session. It should be used only for a series of
+     * {@link #getDrmPropertyString(DataSourceDesc, String)} and
+     * {@link #setDrmPropertyString(DataSourceDesc, String, String)} calls
+     * and refrain from any lengthy operation.
+     * <p>
+     * If the device has not been provisioned before, this call also provisions the device
+     * which involves accessing the provisioning server and can take a variable time to
+     * complete depending on the network connectivity.
+     * When needed, the provisioning will be launched  in the background.
+     * The listener {@link DrmEventCallback#onDrmPrepared}
+     * will be called when provisioning and preparation are finished. The application should
+     * check the status code returned with {@link DrmEventCallback#onDrmPrepared} to proceed.
+     * <p>
+     * The registered {@link DrmEventCallback#onDrmPrepared} is called to indicate the DRM
+     * session being ready. The application should not make any assumption about its call
+     * sequence (e.g., before or after prepareDrm returns).
+     * <p>
+     *
+     * @param dsd The DRM protected data source
+     *
+     * @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
+     * from the source listening to {@link DrmEventCallback#onDrmInfo}.
+     *
+     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+     * @hide
+     */
+    // This is an asynchronous call.
+    public Object prepareDrm(@NonNull DataSourceDesc dsd, @NonNull UUID uuid) {
+        return addTask(newPrepareDrmTask(dsd, uuid));
+    }
+
+    private Task newPrepareDrmTask(DataSourceDesc dsd, UUID uuid) {
+        return new Task(CALL_COMPLETED_PREPARE_DRM, true) {
+            @Override
+            void process() {
+                final SourceInfo sourceInfo = getSourceInfo(dsd);
+                int status = PREPARE_DRM_STATUS_PREPARATION_ERROR;
+                boolean finishPrepare = true;
+
+                if (sourceInfo == null) {
+                    Log.e(TAG, "prepareDrm(): DataSource not found.");
+                } else if (sourceInfo.mDrmInfo == null) {
+                    // only allowing if tied to a protected source;
+                    // might relax for releasing offline keys
+                    Log.e(TAG, "prepareDrm(): Wrong usage: The player must be prepared and "
+                            + "DRM info be retrieved before this call.");
+                } else {
+                    status = PREPARE_DRM_STATUS_SUCCESS;
+                }
+
+                try {
+                    if (status == PREPARE_DRM_STATUS_SUCCESS) {
+                        sourceInfo.mDrmHandle.prepare(uuid);
+                    }
+                } catch (ResourceBusyException e) {
+                    status = PREPARE_DRM_STATUS_RESOURCE_BUSY;
+                } catch (UnsupportedSchemeException e) {
+                    status = PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME;
+                } catch (NotProvisionedException e) {
+                    Log.w(TAG, "prepareDrm: NotProvisionedException");
+
+                    // handle provisioning internally; it'll reset mPrepareDrmInProgress
+                    status = sourceInfo.mDrmHandle.handleProvisioninig(uuid, mTaskId);
+
+                    if (status == PREPARE_DRM_STATUS_SUCCESS) {
+                        // License will be setup in provisioning
+                        finishPrepare = false;
+                    } else {
+                        synchronized (sourceInfo.mDrmHandle) {
+                            sourceInfo.mDrmHandle.cleanDrmObj();
+                        }
+
+                        switch (status) {
+                            case PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR:
+                                Log.e(TAG, "prepareDrm: Provisioning was required but failed "
+                                        + "due to a network error.");
+                                break;
+
+                            case PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR:
+                                Log.e(TAG, "prepareDrm: Provisioning was required but the request "
+                                        + "was denied by the server.");
+                                break;
+
+                            case PREPARE_DRM_STATUS_PREPARATION_ERROR:
+                            default:
+                                Log.e(TAG, "prepareDrm: Post-provisioning preparation failed.");
+                                break;
+                        }
+                    }
+                } catch (Exception e) {
+                    status = PREPARE_DRM_STATUS_PREPARATION_ERROR;
+                }
+
+                if (finishPrepare) {
+                    sourceInfo.mDrmHandle.finishPrepare(status);
+                    synchronized (mTaskLock) {
+                        mCurrentTask = null;
+                        processPendingTask_l();
+                    }
+                }
+
+            }
+        };
+    }
+
+    /**
+     * Releases the DRM session for the given data source
+     * <p>
+     * The player has to have an active DRM session and be in stopped, or prepared
+     * state before this call is made.
+     * A {@link #reset()} call will release the DRM session implicitly.
+     *
+     * @param dsd The DRM protected data source
+     *
+     * @throws NoDrmSchemeException if there is no active DRM session to release
+     * @hide
+     */
+    // This is a synchronous call.
+    public void releaseDrm(@NonNull DataSourceDesc dsd)
+            throws NoDrmSchemeException {
+        final SourceInfo sourceInfo = getSourceInfo(dsd);
+        if (sourceInfo != null) {
+            sourceInfo.mDrmHandle.release();
+        }
+    }
+
+    private native void native_releaseDrm(long mSrcId);
+
+    /**
+     * A key request/response exchange occurs between the app and a license server
+     * to obtain or release keys used to decrypt the given data source.
+     * <p>
+     * {@code getDrmKeyRequest()} is used to obtain an opaque key request byte array that is
+     * delivered to the license server.  The opaque key request byte array is returned
+     * in KeyRequest.data.  The recommended URL to deliver the key request to is
+     * returned in {@code KeyRequest.defaultUrl}.
+     * <p>
+     * After the app has received the key request response from the server,
+     * it should deliver to the response to the DRM engine plugin using the method
+     * {@link #provideDrmKeyResponse(DataSourceDesc, byte[], byte[])}.
+     *
+     * @param dsd the DRM protected data source
+     *
+     * @param keySetId is the key-set identifier of the offline keys being released when keyType is
+     * {@link MediaDrm#KEY_TYPE_RELEASE}. It should be set to null for other key requests, when
+     * keyType is {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}.
+     *
+     * @param initData is the container-specific initialization data when the keyType is
+     * {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}. Its meaning is
+     * interpreted based on the mime type provided in the mimeType parameter.  It could
+     * contain, for example, the content ID, key ID or other data obtained from the content
+     * metadata that is required in generating the key request.
+     * When the keyType is {@link MediaDrm#KEY_TYPE_RELEASE}, it should be set to null.
+     *
+     * @param mimeType identifies the mime type of the content
+     *
+     * @param keyType specifies the type of the request. The request may be to acquire
+     * keys for streaming, {@link MediaDrm#KEY_TYPE_STREAMING}, or for offline content
+     * {@link MediaDrm#KEY_TYPE_OFFLINE}, or to release previously acquired
+     * keys ({@link MediaDrm#KEY_TYPE_RELEASE}), which are identified by a keySetId.
+     *
+     * @param optionalParameters are included in the key request message to
+     * allow a client application to provide additional message parameters to the server.
+     * This may be {@code null} if no additional parameters are to be sent.
+     *
+     * @throws NoDrmSchemeException if there is no active DRM session
+     * @hide
+     */
+    public MediaDrm.KeyRequest getDrmKeyRequest(
+            @NonNull DataSourceDesc dsd,
+            @Nullable byte[] keySetId, @Nullable byte[] initData,
+            @Nullable String mimeType, @MediaDrmKeyType int keyType,
+            @Nullable Map<String, String> optionalParameters)
+            throws NoDrmSchemeException {
+        Log.v(TAG, "getDrmKeyRequest: " +
+                " keySetId: " + keySetId + " initData:" + initData + " mimeType: " + mimeType +
+                " keyType: " + keyType + " optionalParameters: " + optionalParameters);
+
+        final SourceInfo sourceInfo = getSourceInfo(dsd);
+        if (sourceInfo != null) {
+            return sourceInfo.mDrmHandle.getDrmKeyRequest(
+                    keySetId, initData, mimeType, keyType, optionalParameters);
+        }
+        return null;
+    }
+
+    /**
+     * A key response is received from the license server by the app for the given DRM protected
+     * data source, then provided to the DRM engine plugin using {@code provideDrmKeyResponse}.
+     * <p>
+     * When the response is for an offline key request, a key-set identifier is returned that
+     * can be used to later restore the keys to a new session with the method
+     * {@link #restoreDrmKeys(DataSourceDesc, byte[])}.
+     * When the response is for a streaming or release request, null is returned.
+     *
+     * @param dsd the DRM protected data source
+     *
+     * @param keySetId When the response is for a release request, keySetId identifies the saved
+     * key associated with the release request (i.e., the same keySetId passed to the earlier
+     * {@link # getDrmKeyRequest(DataSourceDesc, byte[], byte[], String, int, Map)} call).
+     * It MUST be null when the response is for either streaming or offline key requests.
+     *
+     * @param response the byte array response from the server
+     *
+     * @throws NoDrmSchemeException if there is no active DRM session
+     * @throws DeniedByServerException if the response indicates that the
+     * server rejected the request
+     * @hide
+     */
+    // This is a synchronous call.
+    public byte[] provideDrmKeyResponse(
+            @NonNull DataSourceDesc dsd,
+            @Nullable byte[] keySetId, @NonNull byte[] response)
+            throws NoDrmSchemeException, DeniedByServerException {
+        Log.v(TAG, "provideDrmKeyResponse: keySetId: " + keySetId + " response: " + response);
+
+        final SourceInfo sourceInfo = getSourceInfo(dsd);
+        if (sourceInfo != null) {
+            return sourceInfo.mDrmHandle.provideDrmKeyResponse(keySetId, response);
+        }
+        return null;
+    }
+
+    /**
+     * Restore persisted offline keys into a new session for the given DRM protected data source.
+     * {@code keySetId} identifies the keys to load, obtained from a prior call to
+     * {@link #provideDrmKeyResponse(DataSourceDesc, byte[], byte[])}.
+     *
+     * @param dsd the DRM protected data source
+     *
+     * @param keySetId identifies the saved key set to restore
+     *
+     * @throws NoDrmSchemeException if there is no active DRM session
+     * @hide
+     */
+    // This is a synchronous call.
+    public void restoreDrmKeys(
+            @NonNull DataSourceDesc dsd,
+            @NonNull byte[] keySetId)
+            throws NoDrmSchemeException {
+        Log.v(TAG, "restoreDrmKeys: keySetId: " + keySetId);
+
+        final SourceInfo sourceInfo = getSourceInfo(dsd);
+        if (sourceInfo != null) {
+            sourceInfo.mDrmHandle.restoreDrmKeys(keySetId);
+        }
+    }
+
+    /**
+     * Read a DRM engine plugin String property value, given the DRM protected data source
+     * and property name string.
+     *
+     * @param dsd the DRM protected data source
+     *
+     * @param propertyName the property name
+     *
+     * Standard fields names are:
+     * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
+     * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
+     *
+     * @throws NoDrmSchemeException if there is no active DRM session
+     * @hide
+     */
+    public String getDrmPropertyString(
+            @NonNull DataSourceDesc dsd,
+            @NonNull @MediaDrmStringProperty String propertyName)
+            throws NoDrmSchemeException {
+        Log.v(TAG, "getDrmPropertyString: propertyName: " + propertyName);
+
+        final SourceInfo sourceInfo = getSourceInfo(dsd);
+        if (sourceInfo != null) {
+            return sourceInfo.mDrmHandle.getDrmPropertyString(propertyName);
+        }
+        return null;
+    }
+
+    /**
+     * Set a DRM engine plugin String property value for the given data source.
+     *
+     * @param dsd the DRM protected data source
+     * @param propertyName the property name
+     * @param value the property value
+     *
+     * Standard fields names are:
+     * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
+     * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
+     *
+     * @throws NoDrmSchemeException if there is no active DRM session
+     * @hide
+     */
+    // This is a synchronous call.
+    public void setDrmPropertyString(
+            @NonNull DataSourceDesc dsd,
+            @NonNull @MediaDrmStringProperty String propertyName, @NonNull String value)
+            throws NoDrmSchemeException {
+        // TODO: this implementation only works when dsd is the only data source
+        Log.v(TAG, "setDrmPropertyString: propertyName: " + propertyName + " value: " + value);
+
+        final SourceInfo sourceInfo = getSourceInfo(dsd);
+        if (sourceInfo != null) {
+            sourceInfo.mDrmHandle.setDrmPropertyString(propertyName, value);
+        }
+    }
+
+    /**
+     * Encapsulates the DRM properties of the source.
+     */
+    public static final class DrmInfo {
+        private Map<UUID, byte[]> mMapPssh;
+        private UUID[] mSupportedSchemes;
+
+        /**
+         * Returns the PSSH info of the data source for each supported DRM scheme.
+         */
+        public Map<UUID, byte[]> getPssh() {
+            return mMapPssh;
+        }
+
+        /**
+         * Returns the intersection of the data source and the device DRM schemes.
+         * It effectively identifies the subset of the source's DRM schemes which
+         * are supported by the device too.
+         */
+        public List<UUID> getSupportedSchemes() {
+            return Arrays.asList(mSupportedSchemes);
+        }
+
+        private DrmInfo(Map<UUID, byte[]> pssh, UUID[] supportedSchemes) {
+            mMapPssh = pssh;
+            mSupportedSchemes = supportedSchemes;
+        }
+
+        private static DrmInfo create(PlayerMessage msg) {
+            Log.v(TAG, "DrmInfo.create(" + msg + ")");
+
+            Iterator<Value> in = msg.getValuesList().iterator();
+            byte[] pssh = in.next().getBytesValue().toByteArray();
+
+            Log.v(TAG, "DrmInfo.create() PSSH: " + DrmInfo.arrToHex(pssh));
+            Map<UUID, byte[]> mapPssh = DrmInfo.parsePSSH(pssh, pssh.length);
+            Log.v(TAG, "DrmInfo.create() PSSH: " + mapPssh);
+
+            int supportedDRMsCount = in.next().getInt32Value();
+            UUID[] supportedSchemes = new UUID[supportedDRMsCount];
+            for (int i = 0; i < supportedDRMsCount; i++) {
+                byte[] uuid = new byte[16];
+                in.next().getBytesValue().copyTo(uuid, 0);
+
+                supportedSchemes[i] = DrmInfo.bytesToUUID(uuid);
+
+                Log.v(TAG, "DrmInfo() supportedScheme[" + i + "]: " + supportedSchemes[i]);
+            }
+
+            Log.v(TAG, "DrmInfo.create() psshsize: " + pssh.length
+                    + " supportedDRMsCount: " + supportedDRMsCount);
+            return new DrmInfo(mapPssh, supportedSchemes);
+        }
+
+        private DrmInfo makeCopy() {
+            return new DrmInfo(this.mMapPssh, this.mSupportedSchemes);
+        }
+
+        private static String arrToHex(byte[] bytes) {
+            String out = "0x";
+            for (int i = 0; i < bytes.length; i++) {
+                out += String.format("%02x", bytes[i]);
+            }
+
+            return out;
+        }
+
+        private static UUID bytesToUUID(byte[] uuid) {
+            long msb = 0, lsb = 0;
+            for (int i = 0; i < 8; i++) {
+                msb |= (((long) uuid[i]     & 0xff) << (8 * (7 - i)));
+                lsb |= (((long) uuid[i + 8] & 0xff) << (8 * (7 - i)));
+            }
+
+            return new UUID(msb, lsb);
+        }
+
+        private static Map<UUID, byte[]> parsePSSH(byte[] pssh, int psshsize) {
+            Map<UUID, byte[]> result = new HashMap<UUID, byte[]>();
+
+            final int uuidSize = 16;
+            final int dataLenSize = 4;
+
+            int len = psshsize;
+            int numentries = 0;
+            int i = 0;
+
+            while (len > 0) {
+                if (len < uuidSize) {
+                    Log.w(TAG, String.format("parsePSSH: len is too short to parse "
+                                             + "UUID: (%d < 16) pssh: %d", len, psshsize));
+                    return null;
+                }
+
+                byte[] subset = Arrays.copyOfRange(pssh, i, i + uuidSize);
+                UUID uuid = bytesToUUID(subset);
+                i += uuidSize;
+                len -= uuidSize;
+
+                // get data length
+                if (len < 4) {
+                    Log.w(TAG, String.format("parsePSSH: len is too short to parse "
+                                             + "datalen: (%d < 4) pssh: %d", len, psshsize));
+                    return null;
+                }
+
+                subset = Arrays.copyOfRange(pssh, i, i + dataLenSize);
+                int datalen = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN)
+                        ? ((subset[3] & 0xff) << 24) | ((subset[2] & 0xff) << 16)
+                        | ((subset[1] & 0xff) <<  8) |  (subset[0] & 0xff)        :
+                        ((subset[0] & 0xff) << 24) | ((subset[1] & 0xff) << 16)
+                        | ((subset[2] & 0xff) <<  8) |  (subset[3] & 0xff);
+                i += dataLenSize;
+                len -= dataLenSize;
+
+                if (len < datalen) {
+                    Log.w(TAG, String.format("parsePSSH: len is too short to parse "
+                                             + "data: (%d < %d) pssh: %d", len, datalen, psshsize));
+                    return null;
+                }
+
+                byte[] data = Arrays.copyOfRange(pssh, i, i + datalen);
+
+                // skip the data
+                i += datalen;
+                len -= datalen;
+
+                Log.v(TAG, String.format("parsePSSH[%d]: <%s, %s> pssh: %d",
+                                         numentries, uuid, arrToHex(data), psshsize));
+                numentries++;
+                result.put(uuid, data);
+            }
+
+            return result;
+        }
+    };  // DrmInfo
+
+    /**
+     * Thrown when a DRM method is called when there is no active DRM session.
+     * Extends MediaDrm.MediaDrmException
+     */
+    public static final class NoDrmSchemeException extends MediaDrmException {
+        public NoDrmSchemeException(String detailMessage) {
+            super(detailMessage);
+        }
+    }
+
+    private native void native_prepareDrm(
+            long srcId, @NonNull byte[] uuid, @NonNull byte[] drmSessionId);
+
+    // Instantiated from the native side
+    @SuppressWarnings("unused")
+    private static class StreamEventCallback extends AudioTrack.StreamEventCallback {
+        public long mJAudioTrackPtr;
+        public long mNativeCallbackPtr;
+        public long mUserDataPtr;
+
+        StreamEventCallback(long jAudioTrackPtr, long nativeCallbackPtr, long userDataPtr) {
+            super();
+            mJAudioTrackPtr = jAudioTrackPtr;
+            mNativeCallbackPtr = nativeCallbackPtr;
+            mUserDataPtr = userDataPtr;
+        }
+
+        @Override
+        public void onTearDown(AudioTrack track) {
+            native_stream_event_onTearDown(mNativeCallbackPtr, mUserDataPtr);
+        }
+
+        @Override
+        public void onPresentationEnded(AudioTrack track) {
+            native_stream_event_onStreamPresentationEnd(mNativeCallbackPtr, mUserDataPtr);
+        }
+
+        @Override
+        public void onDataRequest(AudioTrack track, int size) {
+            native_stream_event_onStreamDataRequest(
+                    mJAudioTrackPtr, mNativeCallbackPtr, mUserDataPtr);
+        }
+    }
+
+    /**
+     * Returns a byte[] containing the remainder of 'in', closing it when done.
+     */
+    private static byte[] readInputStreamFully(InputStream in) throws IOException {
+        try {
+            return readInputStreamFullyNoClose(in);
+        } finally {
+            in.close();
+        }
+    }
+
+    /**
+     * Returns a byte[] containing the remainder of 'in'.
+     */
+    private static byte[] readInputStreamFullyNoClose(InputStream in) throws IOException {
+        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        byte[] buffer = new byte[1024];
+        int count;
+        while ((count = in.read(buffer)) != -1) {
+            bytes.write(buffer, 0, count);
+        }
+        return bytes.toByteArray();
+    }
+
+    private static byte[] getByteArrayFromUUID(@NonNull UUID uuid) {
+        long msb = uuid.getMostSignificantBits();
+        long lsb = uuid.getLeastSignificantBits();
+
+        byte[] uuidBytes = new byte[16];
+        for (int i = 0; i < 8; ++i) {
+            uuidBytes[i] = (byte) (msb >>> (8 * (7 - i)));
+            uuidBytes[8 + i] = (byte) (lsb >>> (8 * (7 - i)));
+        }
+
+        return uuidBytes;
+    }
+
+    private static class TimedTextUtil {
+        // These keys must be in sync with the keys in TextDescription2.h
+        private static final int KEY_START_TIME                     = 7; // int
+        private static final int KEY_STRUCT_TEXT_POS               = 14; // TextPos
+        private static final int KEY_STRUCT_TEXT                   = 16; // Text
+        private static final int KEY_GLOBAL_SETTING               = 101;
+        private static final int KEY_LOCAL_SETTING                = 102;
+
+        private static TimedText parsePlayerMessage(PlayerMessage playerMsg) {
+            if (playerMsg.getValuesCount() == 0) {
+                return null;
+            }
+
+            String textChars = null;
+            Rect textBounds = null;
+            Iterator<Value> in = playerMsg.getValuesList().iterator();
+            int type = in.next().getInt32Value();
+            if (type == KEY_LOCAL_SETTING) {
+                type = in.next().getInt32Value();
+                if (type != KEY_START_TIME) {
+                    return null;
+                }
+                int startTimeMs = in.next().getInt32Value();
+
+                type = in.next().getInt32Value();
+                if (type != KEY_STRUCT_TEXT) {
+                    return null;
+                }
+
+                byte[] text = in.next().getBytesValue().toByteArray();
+                if (text == null || text.length == 0) {
+                    textChars = null;
+                } else {
+                    textChars = new String(text);
+                }
+
+            } else if (type != KEY_GLOBAL_SETTING) {
+                Log.w(TAG, "Invalid timed text key found: " + type);
+                return null;
+            }
+            if (in.hasNext()) {
+                type = in.next().getInt32Value();
+                if (type == KEY_STRUCT_TEXT_POS) {
+                    int top = in.next().getInt32Value();
+                    int left = in.next().getInt32Value();
+                    int bottom = in.next().getInt32Value();
+                    int right = in.next().getInt32Value();
+                    textBounds = new Rect(left, top, right, bottom);
+                }
+            }
+            return null;
+            /* TimedText c-tor usage is temporarily commented out.
+             * TODO(b/117527789): use SUBTITLE path for MEDIA_MIMETYPE_TEXT_3GPP track
+             *                    and remove TimedText path from MediaPlayer2.
+            return new TimedText(textChars, textBounds);
+            */
+        }
+    }
+
+    private Object addTask(Task task) {
+        synchronized (mTaskLock) {
+            mPendingTasks.add(task);
+            processPendingTask_l();
+        }
+        return task;
+    }
+
+    @GuardedBy("mTaskLock")
+    private void processPendingTask_l() {
+        if (mCurrentTask != null) {
+            return;
+        }
+        if (!mPendingTasks.isEmpty()) {
+            Task task = mPendingTasks.remove(0);
+            mCurrentTask = task;
+            mTaskHandler.post(task);
+        }
+    }
+
+    private abstract class Task implements Runnable {
+        final long mTaskId = mTaskIdGenerator.getAndIncrement();
+        private final int mMediaCallType;
+        private final boolean mNeedToWaitForEventToComplete;
+        private DataSourceDesc mDSD;
+
+        Task(int mediaCallType, boolean needToWaitForEventToComplete) {
+            mMediaCallType = mediaCallType;
+            mNeedToWaitForEventToComplete = needToWaitForEventToComplete;
+        }
+
+        abstract void process() throws IOException, NoDrmSchemeException;
+
+        @Override
+        public void run() {
+            int status = CALL_STATUS_NO_ERROR;
+            try {
+                if (mMediaCallType != CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED
+                        && getState() == PLAYER_STATE_ERROR) {
+                    status = CALL_STATUS_INVALID_OPERATION;
+                } else {
+                    if (mMediaCallType == CALL_COMPLETED_SEEK_TO) {
+                        synchronized (mTaskLock) {
+                            if (!mPendingTasks.isEmpty()) {
+                                Task nextTask = mPendingTasks.get(0);
+                                if (nextTask.mMediaCallType == mMediaCallType) {
+                                    throw new CommandSkippedException(
+                                            "consecutive seekTo is skipped except last one");
+                                }
+                            }
+                        }
+                    }
+                    process();
+                }
+            } catch (IllegalStateException e) {
+                status = CALL_STATUS_INVALID_OPERATION;
+            } catch (IllegalArgumentException e) {
+                status = CALL_STATUS_BAD_VALUE;
+            } catch (SecurityException e) {
+                status = CALL_STATUS_PERMISSION_DENIED;
+            } catch (IOException e) {
+                status = CALL_STATUS_ERROR_IO;
+            } catch (NoDrmSchemeException e) {
+                status = CALL_STATUS_NO_DRM_SCHEME;
+            } catch (CommandSkippedException e) {
+                status = CALL_STATUS_SKIPPED;
+            } catch (Exception e) {
+                status = CALL_STATUS_ERROR_UNKNOWN;
+            }
+            mDSD = getCurrentDataSource();
+
+            if (mMediaCallType != CALL_COMPLETED_SEEK_TO) {
+                synchronized (mTaskLock) {
+                    mIsPreviousCommandSeekTo = false;
+                }
+            }
+
+            // TODO: Make native implementations asynchronous and let them send notifications.
+            if (!mNeedToWaitForEventToComplete || status != CALL_STATUS_NO_ERROR) {
+
+                sendCompleteNotification(status);
+
+                synchronized (mTaskLock) {
+                    mCurrentTask = null;
+                    processPendingTask_l();
+                }
+            }
+        }
+
+        private void sendCompleteNotification(int status) {
+            // In {@link #notifyWhenCommandLabelReached} case, a separate callback
+            // {@link #onCommandLabelReached} is already called in {@code process()}.
+            // CALL_COMPLETED_PREPARE_DRM is sent via DrmEventCallback#onDrmPrepared
+            if (mMediaCallType == CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED
+                    || mMediaCallType == CALL_COMPLETED_PREPARE_DRM) {
+                return;
+            }
+            sendEvent(new EventNotifier() {
+                @Override
+                public void notify(EventCallback callback) {
+                    callback.onCallCompleted(
+                            MediaPlayer2.this, mDSD, mMediaCallType, status);
+                }
+            });
+        }
+    };
+
+    private final class CommandSkippedException extends RuntimeException {
+        CommandSkippedException(String detailMessage) {
+            super(detailMessage);
+        }
+    };
+
+    // Modular DRM
+    private class DrmHandle {
+
+        static final int PROVISION_TIMEOUT_MS = 60000;
+
+        final DataSourceDesc mDSD;
+        final long mSrcId;
+
+        //--- guarded by |this| start
+        MediaDrm mDrmObj;
+        byte[] mDrmSessionId;
+        UUID mActiveDrmUUID;
+        boolean mDrmConfigAllowed;
+        boolean mDrmProvisioningInProgress;
+        boolean mPrepareDrmInProgress;
+        Future<?> mProvisionResult;
+        DrmPreparationInfo mPrepareInfo;
+        //--- guarded by |this| end
+
+        DrmHandle(DataSourceDesc dsd, long srcId) {
+            mDSD = dsd;
+            mSrcId = srcId;
+        }
+
+        void prepare(UUID uuid) throws UnsupportedSchemeException,
+                ResourceBusyException, NotProvisionedException, InterruptedException,
+                ExecutionException, TimeoutException {
+            Log.v(TAG, "prepareDrm: uuid: " + uuid);
+
+            synchronized (this) {
+                if (mActiveDrmUUID != null) {
+                    final String msg = "prepareDrm(): Wrong usage: There is already "
+                            + "an active DRM scheme with " + uuid;
+                    Log.e(TAG, msg);
+                    throw new IllegalStateException(msg);
+                }
+
+                if (mPrepareDrmInProgress) {
+                    final String msg = "prepareDrm(): Wrong usage: There is already "
+                            + "a pending prepareDrm call.";
+                    Log.e(TAG, msg);
+                    throw new IllegalStateException(msg);
+                }
+
+                if (mDrmProvisioningInProgress) {
+                    final String msg = "prepareDrm(): Unexpectd: Provisioning already in progress";
+                    Log.e(TAG, msg);
+                    throw new IllegalStateException(msg);
+                }
+
+                // shouldn't need this; just for safeguard
+                cleanDrmObj();
+
+                mPrepareDrmInProgress = true;
+
+                try {
+                    // only creating the DRM object to allow pre-openSession configuration
+                    prepareDrm_createDrmStep(uuid);
+                } catch (Exception e) {
+                    Log.w(TAG, "prepareDrm(): Exception ", e);
+                    mPrepareDrmInProgress = false;
+                    throw e;
+                }
+
+                mDrmConfigAllowed = true;
+            }  // synchronized
+
+            // call the callback outside the lock
+            sendDrmEventWait(new DrmEventNotifier<Void>() {
+                @Override
+                public Void notifyWait(DrmEventCallback callback) {
+                    callback.onDrmConfig(MediaPlayer2.this, mDSD, mDrmObj);
+                    return null;
+                }
+            });
+
+            synchronized (this) {
+                mDrmConfigAllowed = false;
+                boolean earlyExit = false;
+
+                try {
+                    prepareDrm_openSessionStep(uuid);
+
+                    this.mActiveDrmUUID = uuid;
+                    mPrepareDrmInProgress = false;
+                } catch (IllegalStateException e) {
+                    final String msg = "prepareDrm(): Wrong usage: The player must be "
+                            + "in the prepared state to call prepareDrm().";
+                    Log.e(TAG, msg);
+                    earlyExit = true;
+                    mPrepareDrmInProgress = false;
+                    throw new IllegalStateException(msg);
+                } catch (NotProvisionedException e) {
+                    Log.w(TAG, "prepareDrm: NotProvisionedException", e);
+                    throw e;
+                } catch (Exception e) {
+                    Log.e(TAG, "prepareDrm: Exception " + e);
+                    earlyExit = true;
+                    mPrepareDrmInProgress = false;
+                    throw e;
+                } finally {
+                    if (earlyExit) {  // clean up object if didn't succeed
+                        cleanDrmObj();
+                    }
+                }  // finally
+            }  // synchronized
+        }
+
+        void prepareDrm_createDrmStep(UUID uuid)
+                throws UnsupportedSchemeException {
+            Log.v(TAG, "prepareDrm_createDrmStep: UUID: " + uuid);
+
+            try {
+                mDrmObj = new MediaDrm(uuid);
+                Log.v(TAG, "prepareDrm_createDrmStep: Created mDrmObj=" + mDrmObj);
+            } catch (Exception e) { // UnsupportedSchemeException
+                Log.e(TAG, "prepareDrm_createDrmStep: MediaDrm failed with " + e);
+                throw e;
+            }
+        }
+
+        void prepareDrm_openSessionStep(UUID uuid)
+                throws NotProvisionedException, ResourceBusyException {
+            Log.v(TAG, "prepareDrm_openSessionStep: uuid: " + uuid);
+
+            // TODO:
+            // don't need an open session for a future specialKeyReleaseDrm mode but we should do
+            // it anyway so it raises provisioning error if needed. We'd rather handle provisioning
+            // at prepareDrm/openSession rather than getDrmKeyRequest/provideDrmKeyResponse
+            try {
+                mDrmSessionId = mDrmObj.openSession();
+                Log.v(TAG, "prepareDrm_openSessionStep: mDrmSessionId=" + mDrmSessionId);
+
+                // Sending it down to native/mediaserver to create the crypto object
+                // This call could simply fail due to bad player state, e.g., after play().
+                final MediaPlayer2 mp2 = MediaPlayer2.this;
+                mp2.native_prepareDrm(mSrcId, getByteArrayFromUUID(uuid), mDrmSessionId);
+                Log.v(TAG, "prepareDrm_openSessionStep: native_prepareDrm/Crypto succeeded");
+
+            } catch (Exception e) { //ResourceBusyException, NotProvisionedException
+                Log.e(TAG, "prepareDrm_openSessionStep: open/crypto failed with " + e);
+                throw e;
+            }
+
+        }
+
+        int handleProvisioninig(UUID uuid, long taskId) {
+            synchronized (this) {
+                if (mDrmProvisioningInProgress) {
+                    Log.e(TAG, "handleProvisioninig: Unexpected mDrmProvisioningInProgress");
+                    return PREPARE_DRM_STATUS_PREPARATION_ERROR;
+                }
+
+                MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest();
+                if (provReq == null) {
+                    Log.e(TAG, "handleProvisioninig: getProvisionRequest returned null.");
+                    return PREPARE_DRM_STATUS_PREPARATION_ERROR;
+                }
+
+                Log.v(TAG, "handleProvisioninig provReq "
+                        + " data: " + provReq.getData() + " url: " + provReq.getDefaultUrl());
+
+                // networking in a background thread
+                mDrmProvisioningInProgress = true;
+
+                mProvisionResult = sDrmThreadPool.submit(newProvisioningTask(uuid, taskId));
+
+                return PREPARE_DRM_STATUS_SUCCESS;
+            }
+        }
+
+        void provision(UUID uuid, long taskId) {
+
+            MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest();
+            String urlStr = provReq.getDefaultUrl();
+            urlStr += "&signedRequest=" + new String(provReq.getData());
+            Log.v(TAG, "handleProvisioninig: Thread is initialised url: " + urlStr);
+
+            byte[] response = null;
+            boolean provisioningSucceeded = false;
+            int status = PREPARE_DRM_STATUS_PREPARATION_ERROR;
+            try {
+                URL url = new URL(urlStr);
+                final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+                try {
+                    connection.setRequestMethod("POST");
+                    connection.setDoOutput(false);
+                    connection.setDoInput(true);
+                    connection.setConnectTimeout(PROVISION_TIMEOUT_MS);
+                    connection.setReadTimeout(PROVISION_TIMEOUT_MS);
+
+                    connection.connect();
+                    response = readInputStreamFully(connection.getInputStream());
+
+                    Log.v(TAG, "handleProvisioninig: Thread run: response " +
+                            response.length + " " + response);
+                } catch (Exception e) {
+                    status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR;
+                    Log.w(TAG, "handleProvisioninig: Thread run: connect " + e + " url: " + url);
+                } finally {
+                    connection.disconnect();
+                }
+            } catch (Exception e)   {
+                status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR;
+                Log.w(TAG, "handleProvisioninig: Thread run: openConnection " + e);
+            }
+
+            if (response != null) {
+                try {
+                    mDrmObj.provideProvisionResponse(response);
+                    Log.v(TAG, "handleProvisioninig: Thread run: " +
+                            "provideProvisionResponse SUCCEEDED!");
+
+                    provisioningSucceeded = true;
+                } catch (Exception e) {
+                    status = PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR;
+                    Log.w(TAG, "handleProvisioninig: Thread run: " +
+                            "provideProvisionResponse " + e);
+                }
+            }
+
+            boolean succeeded = false;
+
+            synchronized (this) {
+                // continuing with prepareDrm
+                if (provisioningSucceeded) {
+                    succeeded = resumePrepare(uuid);
+                    status = (succeeded) ?
+                            PREPARE_DRM_STATUS_SUCCESS :
+                            PREPARE_DRM_STATUS_PREPARATION_ERROR;
+                }
+                mDrmProvisioningInProgress = false;
+                mPrepareDrmInProgress = false;
+                if (!succeeded) {
+                    cleanDrmObj();  // cleaning up if it hasn't gone through while in the lock
+                }
+            }  // synchronized
+
+            // calling the callback outside the lock
+            finishPrepare(status);
+
+            synchronized (mTaskLock) {
+                if (mCurrentTask != null
+                        && mCurrentTask.mTaskId == taskId
+                        && mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE_DRM
+                        && mCurrentTask.mNeedToWaitForEventToComplete) {
+                    mCurrentTask = null;
+                    processPendingTask_l();
+                }
+            }
+        }
+
+        Runnable newProvisioningTask(UUID uuid, long taskId) {
+            return new Runnable() {
+                @Override
+                public void run() {
+                    provision(uuid, taskId);
+                }
+            };
+        }
+
+        boolean resumePrepare(UUID uuid) {
+            Log.v(TAG, "resumePrepareDrm: uuid: " + uuid);
+
+            // mDrmLock is guaranteed to be held
+            boolean success = false;
+            try {
+                // resuming
+                prepareDrm_openSessionStep(uuid);
+
+                this.mActiveDrmUUID = uuid;
+
+                success = true;
+            } catch (Exception e) {
+                Log.w(TAG, "handleProvisioninig: Thread run native_prepareDrm resume failed:" + e);
+                // mDrmObj clean up is done by the caller
+            }
+
+            return success;
+        }
+
+        synchronized boolean setPreparationInfo(DrmPreparationInfo prepareInfo) {
+            if (prepareInfo == null || !prepareInfo.isValid() || mPrepareInfo != null) {
+                return false;
+            }
+            mPrepareInfo = prepareInfo;
+            return true;
+        }
+
+        void finishPrepare(int status) {
+            if (status != PREPARE_DRM_STATUS_SUCCESS) {
+                notifyPrepared(status, null);
+                return;
+            }
+
+            if (mPrepareInfo == null) {
+                // Deprecated: this can only happen when using MediaPlayer Version 1 APIs
+                notifyPrepared(status, null);
+                return;
+            }
+
+            final byte[] keySetId = mPrepareInfo.mKeySetId;
+            if (keySetId != null) {
+                try {
+                    mDrmObj.restoreKeys(mDrmSessionId, keySetId);
+                    notifyPrepared(PREPARE_DRM_STATUS_SUCCESS, keySetId);
+                } catch (Exception e) {
+                    notifyPrepared(PREPARE_DRM_STATUS_RESTORE_ERROR, keySetId);
+                }
+                return;
+            }
+
+            sDrmThreadPool.submit(newKeyExchangeTask());
+        }
+
+        Runnable newKeyExchangeTask() {
+            return new Runnable() {
+                @Override
+                public void run() {
+                    final byte[] initData = mPrepareInfo.mInitData;
+                    final String mimeType = mPrepareInfo.mMimeType;
+                    final int keyType = mPrepareInfo.mKeyType;
+                    final Map<String, String> optionalParams = mPrepareInfo.mOptionalParameters;
+                    byte[] keySetId = null;
+                    try {
+                        KeyRequest req;
+                        req = getDrmKeyRequest(null, initData, mimeType, keyType, optionalParams);
+                        byte[] response = sendDrmEventWait(new DrmEventNotifier<byte[]>() {
+                            @Override
+                            public byte[] notifyWait(DrmEventCallback callback) {
+                                final MediaPlayer2 mp = MediaPlayer2.this;
+                                return callback.onDrmKeyRequest(mp, mDSD, req);
+                            }
+                        });
+                        keySetId = provideDrmKeyResponse(null, response);
+                    } catch (Exception e) {
+                    }
+                    if (keySetId == null) {
+                        notifyPrepared(PREPARE_DRM_STATUS_KEY_EXCHANGE_ERROR, null);
+                    } else {
+                        notifyPrepared(PREPARE_DRM_STATUS_SUCCESS, keySetId);
+                    }
+                }
+            };
+        }
+
+        void notifyPrepared(final int status, byte[] keySetId) {
+
+            Message msg;
+            if (status == PREPARE_DRM_STATUS_SUCCESS) {
+                msg = mTaskHandler.obtainMessage(
+                        MEDIA_DRM_PREPARED, 0, 0, null);
+            } else {
+                msg = mTaskHandler.obtainMessage(
+                        MEDIA_ERROR, status, MEDIA_ERROR_UNKNOWN, null);
+            }
+            mTaskHandler.sendMessage(msg);
+
+            sendDrmEvent(new DrmEventNotifier() {
+                @Override
+                public void notify(DrmEventCallback callback) {
+                    callback.onDrmPrepared(MediaPlayer2.this, mDSD, status,
+                            keySetId);
+                }
+            });
+
+        }
+
+        void cleanDrmObj() {
+            // the caller holds mDrmLock
+            Log.v(TAG, "cleanDrmObj: mDrmObj=" + mDrmObj + " mDrmSessionId=" + mDrmSessionId);
+
+            if (mDrmSessionId != null)    {
+                mDrmObj.closeSession(mDrmSessionId);
+                mDrmSessionId = null;
+            }
+            if (mDrmObj != null) {
+                mDrmObj.close();
+                mDrmObj = null;
+            }
+        }
+
+        void release() throws NoDrmSchemeException {
+            synchronized (this) {
+                Log.v(TAG, "releaseDrm:");
+
+                if (mActiveDrmUUID == null) {
+                    Log.e(TAG, "releaseDrm(): No active DRM scheme to release.");
+                    throw new NoDrmSchemeException(
+                            "releaseDrm: No active DRM scheme to release.");
+                }
+
+                try {
+                    // we don't have the player's state in this layer. The below call raises
+                    // exception if we're in a non-stopped/prepared state.
+
+                    // for cleaning native/mediaserver crypto object
+                    native_releaseDrm(mSrcId);
+
+                    // for cleaning client-side MediaDrm object; only called if above has succeeded
+                    cleanDrmObj();
+
+                    this.mActiveDrmUUID = null;
+                } catch (IllegalStateException e) {
+                    Log.w(TAG, "releaseDrm: Exception ", e);
+                    throw new IllegalStateException(
+                            "releaseDrm: The player is not in a valid state.");
+                } catch (Exception e) {
+                    Log.e(TAG, "releaseDrm: Exception ", e);
+                }
+            }  // synchronized
+        }
+
+        void cleanup() {
+            synchronized (this) {
+                Log.v(TAG, "cleanupDrm: " +
+                        " mProvisioningTask=" + mProvisionResult +
+                        " mPrepareDrmInProgress=" + mPrepareDrmInProgress +
+                        " mActiveDrmScheme=" + mActiveDrmUUID);
+
+                if (mProvisionResult != null) {
+                    // timeout; relying on HttpUrlConnection
+                    try {
+                        mProvisionResult.get();
+                    }
+                    catch (InterruptedException | ExecutionException e) {
+                        Log.w(TAG, "resetDrmState: ProvThread.join Exception " + e);
+                    }
+                }
+
+                // set to false to avoid duplicate release calls
+                this.mActiveDrmUUID = null;
+
+                native_releaseDrm(mSrcId);
+                cleanDrmObj();
+            }   // synchronized
+        }
+
+        Runnable newCleanupTask() {
+            return new Runnable() {
+                @Override
+                public void run() {
+                    cleanup();
+                }
+            };
+        }
+
+        MediaDrm.KeyRequest getDrmKeyRequest(
+                byte[] keySetId, byte[] initData,
+                String mimeType, int keyType,
+                Map<String, String> optionalParameters)
+                throws NoDrmSchemeException {
+            synchronized (this) {
+                if (mActiveDrmUUID == null) {
+                    Log.e(TAG, "getDrmKeyRequest NoDrmSchemeException");
+                    throw new NoDrmSchemeException(
+                            "getDrmKeyRequest: Has to set a DRM scheme first.");
+                }
+
+                try {
+                    byte[] scope = (keyType != MediaDrm.KEY_TYPE_RELEASE) ?
+                            mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE
+                            keySetId;                  // keySetId for KEY_TYPE_RELEASE
+
+                    HashMap<String, String> hmapOptionalParameters =
+                            (optionalParameters != null)
+                            ? new HashMap<String, String>(optionalParameters)
+                            : null;
+
+                    MediaDrm.KeyRequest request = mDrmObj.getKeyRequest(
+                            scope, initData, mimeType, keyType, hmapOptionalParameters);
+                    Log.v(TAG, "getDrmKeyRequest:   --> request: " + request);
+
+                    return request;
+
+                } catch (NotProvisionedException e) {
+                    Log.w(TAG, "getDrmKeyRequest NotProvisionedException: " +
+                            "Unexpected. Shouldn't have reached here.");
+                    throw new IllegalStateException("getDrmKeyRequest: provisioning error.");
+                } catch (Exception e) {
+                    Log.w(TAG, "getDrmKeyRequest Exception " + e);
+                    throw e;
+                }
+
+            }
+        }
+
+        byte[] provideDrmKeyResponse(byte[] keySetId, byte[] response)
+                throws NoDrmSchemeException, DeniedByServerException {
+            synchronized (this) {
+
+                if (mActiveDrmUUID == null) {
+                    Log.e(TAG, "getDrmKeyRequest NoDrmSchemeException");
+                    throw new NoDrmSchemeException(
+                            "getDrmKeyRequest: Has to set a DRM scheme first.");
+                }
+
+                try {
+                    byte[] scope = (keySetId == null) ?
+                                    mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE
+                                    keySetId;                  // keySetId for KEY_TYPE_RELEASE
+
+                    byte[] keySetResult = mDrmObj.provideKeyResponse(scope, response);
+
+                    Log.v(TAG, "provideDrmKeyResponse: keySetId: " + keySetId
+                            + " response: " + response + " --> " + keySetResult);
+
+
+                    return keySetResult;
+
+                } catch (NotProvisionedException e) {
+                    Log.w(TAG, "provideDrmKeyResponse NotProvisionedException: " +
+                            "Unexpected. Shouldn't have reached here.");
+                    throw new IllegalStateException("provideDrmKeyResponse: " +
+                            "Unexpected provisioning error.");
+                } catch (Exception e) {
+                    Log.w(TAG, "provideDrmKeyResponse Exception " + e);
+                    throw e;
+                }
+            }
+        }
+
+        void restoreDrmKeys(byte[] keySetId)
+                throws NoDrmSchemeException {
+            synchronized (this) {
+                if (mActiveDrmUUID == null) {
+                    Log.w(TAG, "restoreDrmKeys NoDrmSchemeException");
+                    throw new NoDrmSchemeException(
+                            "restoreDrmKeys: Has to set a DRM scheme first.");
+                }
+
+                try {
+                    mDrmObj.restoreKeys(mDrmSessionId, keySetId);
+                } catch (Exception e) {
+                    Log.w(TAG, "restoreKeys Exception " + e);
+                    throw e;
+                }
+            }
+        }
+
+        String getDrmPropertyString(String propertyName)
+                throws NoDrmSchemeException {
+            String v;
+            synchronized (this) {
+
+                if (mActiveDrmUUID == null && !mDrmConfigAllowed) {
+                    Log.w(TAG, "getDrmPropertyString NoDrmSchemeException");
+                    throw new NoDrmSchemeException(
+                            "getDrmPropertyString: Has to prepareDrm() first.");
+                }
+
+                try {
+                    v = mDrmObj.getPropertyString(propertyName);
+                } catch (Exception e) {
+                    Log.w(TAG, "getDrmPropertyString Exception " + e);
+                    throw e;
+                }
+            }   // synchronized
+
+            Log.v(TAG, "getDrmPropertyString: propertyName: " + propertyName + " --> value: " + v);
+
+            return v;
+        }
+
+        void setDrmPropertyString(String propertyName, String value)
+                throws NoDrmSchemeException {
+            synchronized (this) {
+
+                if ( mActiveDrmUUID == null && !mDrmConfigAllowed ) {
+                    Log.w(TAG, "setDrmPropertyString NoDrmSchemeException");
+                    throw new NoDrmSchemeException(
+                            "setDrmPropertyString: Has to prepareDrm() first.");
+                }
+
+                try {
+                    mDrmObj.setPropertyString(propertyName, value);
+                } catch ( Exception e ) {
+                    Log.w(TAG, "setDrmPropertyString Exception " + e);
+                    throw e;
+                }
+            }
+        }
+
+    }
+
+    final class SourceInfo {
+        final DataSourceDesc mDSD;
+        final long mId = mSrcIdGenerator.getAndIncrement();
+        AtomicInteger mBufferedPercentage = new AtomicInteger(0);
+        boolean mClosed = false;
+        int mPrepareBarrier = 1;
+
+        // m*AsNextSource (below) only applies to pending data sources in the playlist;
+        // the meanings of mCurrentSourceInfo.{mStateAsNextSource,mPlayPendingAsNextSource}
+        // are undefined.
+        int mStateAsNextSource = NEXT_SOURCE_STATE_INIT;
+        boolean mPlayPendingAsNextSource = false;
+
+        // Modular DRM
+        final DrmHandle mDrmHandle;
+        DrmInfo mDrmInfo;
+        boolean mDrmInfoResolved;
+
+        SourceInfo(DataSourceDesc dsd) {
+            this.mDSD = dsd;
+            mDrmHandle = new DrmHandle(dsd, mId);
+        }
+
+        void close() {
+            synchronized (this) {
+                if (!mClosed) {
+                    if (mDSD != null) {
+                        mDSD.close();
+                    }
+                    mClosed = true;
+                }
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%s(%d)", SourceInfo.class.getName(), mId);
+        }
+
+    }
+
+    private SourceInfo getSourceInfo(long srcId) {
+        synchronized (mSrcLock) {
+            if (isCurrentSource(srcId)) {
+                return mCurrentSourceInfo;
+            }
+            if (isNextSource(srcId)) {
+                return mNextSourceInfos.peek();
+            }
+        }
+        return null;
+    }
+
+    private SourceInfo getSourceInfo(DataSourceDesc dsd) {
+        synchronized (mSrcLock) {
+            if (isCurrentSource(dsd)) {
+                return mCurrentSourceInfo;
+            }
+            if (isNextSource(dsd)) {
+                return mNextSourceInfos.peek();
+            }
+        }
+        return null;
+    }
+
+    private boolean isCurrentSource(long srcId) {
+        synchronized (mSrcLock) {
+            return mCurrentSourceInfo != null && mCurrentSourceInfo.mId == srcId;
+        }
+    }
+
+    private boolean isCurrentSource(DataSourceDesc dsd) {
+        synchronized (mSrcLock) {
+            return mCurrentSourceInfo != null && mCurrentSourceInfo.mDSD == dsd;
+        }
+    }
+
+    private boolean isNextSource(long srcId) {
+        SourceInfo nextSourceInfo = mNextSourceInfos.peek();
+        return nextSourceInfo != null && nextSourceInfo.mId == srcId;
+    }
+
+    private boolean isNextSource(DataSourceDesc dsd) {
+        SourceInfo nextSourceInfo = mNextSourceInfos.peek();
+        return nextSourceInfo != null && nextSourceInfo.mDSD == dsd;
+    }
+
+    @GuardedBy("mSrcLock")
+    private void setCurrentSourceInfo_l(SourceInfo sourceInfo) {
+        cleanupSourceInfo(mCurrentSourceInfo);
+        mCurrentSourceInfo = sourceInfo;
+    }
+
+    @GuardedBy("mSrcLock")
+    private void clearNextSourceInfos_l() {
+        while (!mNextSourceInfos.isEmpty()) {
+            cleanupSourceInfo(mNextSourceInfos.poll());
+        }
+    }
+
+    private void cleanupSourceInfo(SourceInfo sourceInfo) {
+        if (sourceInfo != null) {
+            sourceInfo.close();
+            Runnable task = sourceInfo.mDrmHandle.newCleanupTask();
+            sDrmThreadPool.submit(task);
+        }
+    }
+
+    private void clearSourceInfos() {
+        synchronized (mSrcLock) {
+            setCurrentSourceInfo_l(null);
+            clearNextSourceInfos_l();
+        }
+    }
+
+    public static final class MetricsConstants {
+        private MetricsConstants() {}
+
+        /**
+         * Key to extract the MIME type of the video track
+         * from the {@link MediaPlayer2#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime";
+
+        /**
+         * Key to extract the codec being used to decode the video track
+         * from the {@link MediaPlayer2#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String CODEC_VIDEO = "android.media.mediaplayer.video.codec";
+
+        /**
+         * Key to extract the width (in pixels) of the video track
+         * from the {@link MediaPlayer2#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String WIDTH = "android.media.mediaplayer.width";
+
+        /**
+         * Key to extract the height (in pixels) of the video track
+         * from the {@link MediaPlayer2#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String HEIGHT = "android.media.mediaplayer.height";
+
+        /**
+         * Key to extract the count of video frames played
+         * from the {@link MediaPlayer2#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String FRAMES = "android.media.mediaplayer.frames";
+
+        /**
+         * Key to extract the count of video frames dropped
+         * from the {@link MediaPlayer2#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String FRAMES_DROPPED = "android.media.mediaplayer.dropped";
+
+        /**
+         * Key to extract the MIME type of the audio track
+         * from the {@link MediaPlayer2#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime";
+
+        /**
+         * Key to extract the codec being used to decode the audio track
+         * from the {@link MediaPlayer2#getMetrics} return value.
+         * The value is a String.
+         */
+        public static final String CODEC_AUDIO = "android.media.mediaplayer.audio.codec";
+
+        /**
+         * Key to extract the duration (in milliseconds) of the
+         * media being played
+         * from the {@link MediaPlayer2#getMetrics} return value.
+         * The value is a long.
+         */
+        public static final String DURATION = "android.media.mediaplayer.durationMs";
+
+        /**
+         * Key to extract the playing time (in milliseconds) of the
+         * media being played
+         * from the {@link MediaPlayer2#getMetrics} return value.
+         * The value is a long.
+         */
+        public static final String PLAYING = "android.media.mediaplayer.playingMs";
+
+        /**
+         * Key to extract the count of errors encountered while
+         * playing the media
+         * from the {@link MediaPlayer2#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String ERRORS = "android.media.mediaplayer.err";
+
+        /**
+         * Key to extract an (optional) error code detected while
+         * playing the media
+         * from the {@link MediaPlayer2#getMetrics} return value.
+         * The value is an integer.
+         */
+        public static final String ERROR_CODE = "android.media.mediaplayer.errcode";
+
+    }
+
+    private void keepAudioSessionIdAlive(int sessionId) {
+        synchronized (mSessionIdLock) {
+            if (mDummyAudioTrack != null) {
+                if (mDummyAudioTrack.getAudioSessionId() == sessionId) {
+                    return;
+                }
+                mDummyAudioTrack.release();
+            }
+            // TODO: parameters can be optimized
+            mDummyAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
+                    AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, 2,
+                    AudioTrack.MODE_STATIC, sessionId);
+        }
+    }
+
+    private void keepAudioSessionIdAlive(AudioTrack at) {
+        synchronized (mSessionIdLock) {
+            if (mDummyAudioTrack != null) {
+                if (mDummyAudioTrack.getAudioSessionId() == at.getAudioSessionId()) {
+                    at.release();
+                    return;
+                }
+                mDummyAudioTrack.release();
+            }
+            mDummyAudioTrack = at;
+        }
+    }
+}
diff --git a/media/java/android/media/MediaPlayer2Utils.java b/media/apex/java/android/media/MediaPlayer2Utils.java
similarity index 100%
rename from media/java/android/media/MediaPlayer2Utils.java
rename to media/apex/java/android/media/MediaPlayer2Utils.java
diff --git a/media/apex/java/android/media/MediaSession2.java b/media/apex/java/android/media/MediaSession2.java
new file mode 100644
index 0000000..fdd07fd
--- /dev/null
+++ b/media/apex/java/android/media/MediaSession2.java
@@ -0,0 +1,784 @@
+/*
+ * 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.media;
+
+import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS;
+import static android.media.MediaConstants.KEY_PACKAGE_NAME;
+import static android.media.MediaConstants.KEY_PID;
+import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE;
+import static android.media.MediaConstants.KEY_SESSION2LINK;
+import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
+import static android.media.Session2Command.RESULT_INFO_SKIPPED;
+import static android.media.Session2Token.TYPE_SESSION;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.media.session.MediaSessionManager;
+import android.media.session.MediaSessionManager.RemoteUserInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Process;
+import android.os.ResultReceiver;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Allows a media app to expose its transport controls and playback information in a process to
+ * other processes including the Android framework and other apps.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
+ */
+public class MediaSession2 implements AutoCloseable {
+    static final String TAG = "MediaSession2";
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    // Note: This checks the uniqueness of a session ID only in a single process.
+    // When the framework becomes able to check the uniqueness, this logic should be removed.
+    //@GuardedBy("MediaSession.class")
+    private static final List<String> SESSION_ID_LIST = new ArrayList<>();
+
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    final Object mLock = new Object();
+    //@GuardedBy("mLock")
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    final Map<Controller2Link, ControllerInfo> mConnectedControllers = new HashMap<>();
+
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    final Context mContext;
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    final Executor mCallbackExecutor;
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    final SessionCallback mCallback;
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    final Session2Link mSessionStub;
+
+    private final String mSessionId;
+    private final PendingIntent mSessionActivity;
+    private final Session2Token mSessionToken;
+    private final MediaSessionManager mSessionManager;
+    private final Handler mResultHandler;
+
+    //@GuardedBy("mLock")
+    private boolean mClosed;
+    //@GuardedBy("mLock")
+    private boolean mPlaybackActive;
+    //@GuardedBy("mLock")
+    private ForegroundServiceEventCallback mForegroundServiceEventCallback;
+
+    MediaSession2(@NonNull Context context, @NonNull String id, PendingIntent sessionActivity,
+            @NonNull Executor callbackExecutor, @NonNull SessionCallback callback) {
+        synchronized (MediaSession2.class) {
+            if (SESSION_ID_LIST.contains(id)) {
+                throw new IllegalStateException("Session ID must be unique. ID=" + id);
+            }
+            SESSION_ID_LIST.add(id);
+        }
+
+        mContext = context;
+        mSessionId = id;
+        mSessionActivity = sessionActivity;
+        mCallbackExecutor = callbackExecutor;
+        mCallback = callback;
+        mSessionStub = new Session2Link(this);
+        mSessionToken = new Session2Token(Process.myUid(), TYPE_SESSION, context.getPackageName(),
+                mSessionStub);
+        mSessionManager = (MediaSessionManager) mContext.getSystemService(
+                Context.MEDIA_SESSION_SERVICE);
+        // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
+        mResultHandler = new Handler(context.getMainLooper());
+        mClosed = false;
+    }
+
+    @Override
+    public void close() {
+        try {
+            List<ControllerInfo> controllerInfos;
+            ForegroundServiceEventCallback callback;
+            synchronized (mLock) {
+                if (mClosed) {
+                    return;
+                }
+                mClosed = true;
+                controllerInfos = getConnectedControllers();
+                mConnectedControllers.clear();
+                callback = mForegroundServiceEventCallback;
+                mForegroundServiceEventCallback = null;
+            }
+            synchronized (MediaSession2.class) {
+                SESSION_ID_LIST.remove(mSessionId);
+            }
+            if (callback != null) {
+                callback.onSessionClosed(this);
+            }
+            for (ControllerInfo info : controllerInfos) {
+                info.notifyDisconnected();
+            }
+        } catch (Exception e) {
+            // Should not be here.
+        }
+    }
+
+    /**
+     * Returns the session ID
+     */
+    @NonNull
+    public String getSessionId() {
+        return mSessionId;
+    }
+
+    /**
+     * Returns the {@link Session2Token} for creating {@link MediaController2}.
+     */
+    @NonNull
+    public Session2Token getSessionToken() {
+        return mSessionToken;
+    }
+
+    /**
+     * Broadcasts a session command to all the connected controllers
+     * <p>
+     * @param command the session command
+     * @param args optional arguments
+     */
+    public void broadcastSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
+        if (command == null) {
+            throw new IllegalArgumentException("command shouldn't be null");
+        }
+        List<ControllerInfo> controllerInfos = getConnectedControllers();
+        for (ControllerInfo controller : controllerInfos) {
+            controller.sendSessionCommand(command, args, null);
+        }
+    }
+
+    /**
+     * Sends a session command to a specific controller
+     * <p>
+     * @param controller the controller to get the session command
+     * @param command the session command
+     * @param args optional arguments
+     * @return a token which will be sent together in {@link SessionCallback#onCommandResult}
+     *     when its result is received.
+     */
+    @NonNull
+    public Object sendSessionCommand(@NonNull ControllerInfo controller,
+            @NonNull Session2Command command, @Nullable Bundle args) {
+        if (controller == null) {
+            throw new IllegalArgumentException("controller shouldn't be null");
+        }
+        if (command == null) {
+            throw new IllegalArgumentException("command shouldn't be null");
+        }
+        ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) {
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                controller.receiveCommandResult(this);
+                mCallbackExecutor.execute(() -> {
+                    mCallback.onCommandResult(MediaSession2.this, controller, this,
+                            command, new Session2Command.Result(resultCode, resultData));
+                });
+            }
+        };
+        controller.sendSessionCommand(command, args, resultReceiver);
+        return resultReceiver;
+    }
+
+    /**
+     * Cancels the session command previously sent.
+     *
+     * @param controller the controller to get the session command
+     * @param token the token which is returned from {@link #sendSessionCommand}.
+     */
+    public void cancelSessionCommand(@NonNull ControllerInfo controller, @NonNull Object token) {
+        if (controller == null) {
+            throw new IllegalArgumentException("controller shouldn't be null");
+        }
+        if (token == null) {
+            throw new IllegalArgumentException("token shouldn't be null");
+        }
+        controller.cancelSessionCommand(token);
+    }
+
+    /**
+     * Sets whether the playback is active (i.e. playing something)
+     *
+     * @param playbackActive {@code true} if the playback active, {@code false} otherwise.
+     **/
+    public void setPlaybackActive(boolean playbackActive) {
+        final ForegroundServiceEventCallback serviceCallback;
+        synchronized (mLock) {
+            if (mPlaybackActive == playbackActive) {
+                return;
+            }
+            mPlaybackActive = playbackActive;
+            serviceCallback = mForegroundServiceEventCallback;
+        }
+        if (serviceCallback != null) {
+            serviceCallback.onPlaybackActiveChanged(this, playbackActive);
+        }
+        List<ControllerInfo> controllerInfos = getConnectedControllers();
+        for (ControllerInfo controller : controllerInfos) {
+            controller.notifyPlaybackActiveChanged(playbackActive);
+        }
+    }
+
+    /**
+     * Returns whehther the playback is active (i.e. playing something)
+     *
+     * @return {@code true} if the playback active, {@code false} otherwise.
+     */
+    public boolean isPlaybackActive() {
+        synchronized (mLock) {
+            return mPlaybackActive;
+        }
+    }
+
+    boolean isClosed() {
+        synchronized (mLock) {
+            return mClosed;
+        }
+    }
+
+    SessionCallback getCallback() {
+        return mCallback;
+    }
+
+    void setForegroundServiceEventCallback(ForegroundServiceEventCallback callback) {
+        synchronized (mLock) {
+            if (mForegroundServiceEventCallback == callback) {
+                return;
+            }
+            if (mForegroundServiceEventCallback != null && callback != null) {
+                throw new IllegalStateException("A session cannot be added to multiple services");
+            }
+            mForegroundServiceEventCallback = callback;
+        }
+    }
+
+    // Called by Session2Link.onConnect and MediaSession2Service.MediaSession2ServiceStub.connect
+    void onConnect(final Controller2Link controller, int callingPid, int callingUid, int seq,
+            Bundle connectionRequest) {
+        if (callingPid == 0) {
+            // The pid here is from Binder.getCallingPid(), which can be 0 for an oneway call from
+            // the remote process. If it's the case, use PID from the connectionRequest.
+            callingPid = connectionRequest.getInt(KEY_PID);
+        }
+        String callingPkg = connectionRequest.getString(KEY_PACKAGE_NAME);
+
+        RemoteUserInfo remoteUserInfo = new RemoteUserInfo(callingPkg, callingPid, callingUid);
+        final ControllerInfo controllerInfo = new ControllerInfo(remoteUserInfo,
+                mSessionManager.isTrustedForMediaControl(remoteUserInfo), controller);
+        mCallbackExecutor.execute(() -> {
+            boolean connected = false;
+            try {
+                if (isClosed()) {
+                    return;
+                }
+                controllerInfo.mAllowedCommands =
+                        mCallback.onConnect(MediaSession2.this, controllerInfo);
+                // Don't reject connection for the request from trusted app.
+                // Otherwise server will fail to retrieve session's information to dispatch
+                // media keys to.
+                if (controllerInfo.mAllowedCommands == null && !controllerInfo.isTrusted()) {
+                    return;
+                }
+                if (controllerInfo.mAllowedCommands == null) {
+                    // For trusted apps, send non-null allowed commands to keep
+                    // connection.
+                    controllerInfo.mAllowedCommands =
+                            new Session2CommandGroup.Builder().build();
+                }
+                if (DEBUG) {
+                    Log.d(TAG, "Accepting connection: " + controllerInfo);
+                }
+                synchronized (mLock) {
+                    if (mConnectedControllers.containsKey(controller)) {
+                        Log.w(TAG, "Controller " + controllerInfo + " has sent connection"
+                                + " request multiple times");
+                    }
+                    mConnectedControllers.put(controller, controllerInfo);
+                }
+                // If connection is accepted, notify the current state to the controller.
+                // It's needed because we cannot call synchronous calls between
+                // session/controller.
+                Bundle connectionResult = new Bundle();
+                connectionResult.putParcelable(KEY_SESSION2LINK, mSessionStub);
+                connectionResult.putParcelable(KEY_ALLOWED_COMMANDS,
+                        controllerInfo.mAllowedCommands);
+                connectionResult.putBoolean(KEY_PLAYBACK_ACTIVE, isPlaybackActive());
+
+                // Double check if session is still there, because close() can be called in
+                // another thread.
+                if (isClosed()) {
+                    return;
+                }
+                controllerInfo.notifyConnected(connectionResult);
+                connected = true;
+            } finally {
+                if (!connected) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Rejecting connection or notifying that session is closed"
+                                + ", controllerInfo=" + controllerInfo);
+                    }
+                    synchronized (mLock) {
+                        mConnectedControllers.remove(controller);
+                    }
+                    controllerInfo.notifyDisconnected();
+                }
+            }
+        });
+    }
+
+    // Called by Session2Link.onDisconnect
+    void onDisconnect(@NonNull final Controller2Link controller, int seq) {
+        final ControllerInfo controllerInfo;
+        synchronized (mLock) {
+            controllerInfo = mConnectedControllers.remove(controller);
+        }
+        if (controllerInfo == null) {
+            return;
+        }
+        mCallbackExecutor.execute(() -> {
+            mCallback.onDisconnected(MediaSession2.this, controllerInfo);
+        });
+    }
+
+    // Called by Session2Link.onSessionCommand
+    void onSessionCommand(@NonNull final Controller2Link controller, final int seq,
+            final Session2Command command, final Bundle args,
+            @Nullable ResultReceiver resultReceiver) {
+        if (controller == null) {
+            return;
+        }
+        final ControllerInfo controllerInfo;
+        synchronized (mLock) {
+            controllerInfo = mConnectedControllers.get(controller);
+        }
+        if (controllerInfo == null) {
+            return;
+        }
+
+        // TODO: check allowed commands.
+        synchronized (mLock) {
+            controllerInfo.addRequestedCommandSeqNumber(seq);
+        }
+        mCallbackExecutor.execute(() -> {
+            if (!controllerInfo.removeRequestedCommandSeqNumber(seq)) {
+                resultReceiver.send(RESULT_INFO_SKIPPED, null);
+                return;
+            }
+            Session2Command.Result result = mCallback.onSessionCommand(
+                    MediaSession2.this, controllerInfo, command, args);
+            if (resultReceiver != null) {
+                if (result == null) {
+                    resultReceiver.send(Session2Command.RESULT_INFO_SKIPPED, null);
+                } else {
+                    resultReceiver.send(result.getResultCode(), result.getResultData());
+                }
+            }
+        });
+    }
+
+    // Called by Session2Link.onCancelCommand
+    void onCancelCommand(@NonNull final Controller2Link controller, final int seq) {
+        final ControllerInfo controllerInfo;
+        synchronized (mLock) {
+            controllerInfo = mConnectedControllers.get(controller);
+        }
+        if (controllerInfo == null) {
+            return;
+        }
+        controllerInfo.removeRequestedCommandSeqNumber(seq);
+    }
+
+    private List<ControllerInfo> getConnectedControllers() {
+        List<ControllerInfo> controllers = new ArrayList<>();
+        synchronized (mLock) {
+            controllers.addAll(mConnectedControllers.values());
+        }
+        return controllers;
+    }
+
+    /**
+     * Builder for {@link MediaSession2}.
+     * <p>
+     * Any incoming event from the {@link MediaController2} will be handled on the callback
+     * executor. If it's not set, {@link Context#getMainExecutor()} will be used by default.
+     */
+    public static final class Builder {
+        private Context mContext;
+        private String mId;
+        private PendingIntent mSessionActivity;
+        private Executor mCallbackExecutor;
+        private SessionCallback mCallback;
+
+        /**
+         * Creates a builder for {@link MediaSession2}.
+         *
+         * @param context Context
+         * @throws IllegalArgumentException if context is {@code null}.
+         */
+        public Builder(@NonNull Context context) {
+            if (context == null) {
+                throw new IllegalArgumentException("context shouldn't be null");
+            }
+            mContext = context;
+        }
+
+        /**
+         * Set an intent for launching UI for this Session. This can be used as a
+         * quick link to an ongoing media screen. The intent should be for an
+         * activity that may be started using {@link Context#startActivity(Intent)}.
+         *
+         * @param pi The intent to launch to show UI for this session.
+         * @return The Builder to allow chaining
+         */
+        @NonNull
+        public Builder setSessionActivity(@Nullable PendingIntent pi) {
+            mSessionActivity = pi;
+            return this;
+        }
+
+        /**
+         * Set ID of the session. If it's not set, an empty string will be used to create a session.
+         * <p>
+         * Use this if and only if your app supports multiple playback at the same time and also
+         * wants to provide external apps to have finer controls of them.
+         *
+         * @param id id of the session. Must be unique per package.
+         * @throws IllegalArgumentException if id is {@code null}.
+         * @return The Builder to allow chaining
+         */
+        @NonNull
+        public Builder setId(@NonNull String id) {
+            if (id == null) {
+                throw new IllegalArgumentException("id shouldn't be null");
+            }
+            mId = id;
+            return this;
+        }
+
+        /**
+         * Set callback for the session and its executor.
+         *
+         * @param executor callback executor
+         * @param callback session callback.
+         * @return The Builder to allow chaining
+         */
+        @NonNull
+        public Builder setSessionCallback(@NonNull Executor executor,
+                @NonNull SessionCallback callback) {
+            mCallbackExecutor = executor;
+            mCallback = callback;
+            return this;
+        }
+
+        /**
+         * Build {@link MediaSession2}.
+         *
+         * @return a new session
+         * @throws IllegalStateException if the session with the same id is already exists for the
+         *      package.
+         */
+        @NonNull
+        public MediaSession2 build() {
+            if (mCallbackExecutor == null) {
+                mCallbackExecutor = mContext.getMainExecutor();
+            }
+            if (mCallback == null) {
+                mCallback = new SessionCallback() {};
+            }
+            if (mId == null) {
+                mId = "";
+            }
+            MediaSession2 session2 = new MediaSession2(mContext, mId, mSessionActivity,
+                    mCallbackExecutor, mCallback);
+
+            // Notify framework about the newly create session after the constructor is finished.
+            // Otherwise, framework may access the session before the initialization is finished.
+            try {
+                MediaSessionManager manager = (MediaSessionManager) mContext.getSystemService(
+                        Context.MEDIA_SESSION_SERVICE);
+                manager.notifySession2Created(session2.getSessionToken());
+            } catch (Exception e) {
+                session2.close();
+                throw e;
+            }
+
+            return session2;
+        }
+    }
+
+    /**
+     * Information of a controller.
+     * <p>
+     * This API is not generally intended for third party application developers.
+     */
+    public static final class ControllerInfo {
+        private final RemoteUserInfo mRemoteUserInfo;
+        private final boolean mIsTrusted;
+        private final Controller2Link mControllerBinder;
+        private final Object mLock = new Object();
+        //@GuardedBy("mLock")
+        private int mNextSeqNumber;
+        //@GuardedBy("mLock")
+        private ArrayMap<ResultReceiver, Integer> mPendingCommands;
+        //@GuardedBy("mLock")
+        private ArraySet<Integer> mRequestedCommandSeqNumbers;
+
+        @SuppressWarnings("WeakerAccess") /* synthetic access */
+        Session2CommandGroup mAllowedCommands;
+
+        /**
+         * @param remoteUserInfo remote user info
+         * @param trusted {@code true} if trusted, {@code false} otherwise
+         * @param controllerBinder Controller2Link for the connected controller.
+         */
+        ControllerInfo(@NonNull RemoteUserInfo remoteUserInfo, boolean trusted,
+                @Nullable Controller2Link controllerBinder) {
+            mRemoteUserInfo = remoteUserInfo;
+            mIsTrusted = trusted;
+            mControllerBinder = controllerBinder;
+            mPendingCommands = new ArrayMap<>();
+            mRequestedCommandSeqNumbers = new ArraySet<>();
+        }
+
+        /**
+         * @return remote user info of the controller.
+         */
+        @NonNull
+        public RemoteUserInfo getRemoteUserInfo() {
+            return mRemoteUserInfo;
+        }
+
+        /**
+         * @return package name of the controller.
+         */
+        @NonNull
+        public String getPackageName() {
+            return mRemoteUserInfo.getPackageName();
+        }
+
+        /**
+         * @return uid of the controller. Can be a negative value if the uid cannot be obtained.
+         */
+        public int getUid() {
+            return mRemoteUserInfo.getUid();
+        }
+
+        /**
+         * Return if the controller has granted {@code android.permission.MEDIA_CONTENT_CONTROL} or
+         * has a enabled notification listener so can be trusted to accept connection and incoming
+         * command request.
+         *
+         * @return {@code true} if the controller is trusted.
+         * @hide
+         */
+        public boolean isTrusted() {
+            return mIsTrusted;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mControllerBinder, mRemoteUserInfo);
+        }
+
+        @Override
+        public boolean equals(@Nullable Object obj) {
+            if (!(obj instanceof ControllerInfo)) return false;
+            if (this == obj) return true;
+
+            ControllerInfo other = (ControllerInfo) obj;
+            if (mControllerBinder != null || other.mControllerBinder != null) {
+                return Objects.equals(mControllerBinder, other.mControllerBinder);
+            }
+            return mRemoteUserInfo.equals(other.mRemoteUserInfo);
+        }
+
+        @Override
+        @NonNull
+        public String toString() {
+            return "ControllerInfo {pkg=" + mRemoteUserInfo.getPackageName() + ", uid="
+                    + mRemoteUserInfo.getUid() + ", allowedCommands=" + mAllowedCommands + "})";
+        }
+
+        void notifyConnected(Bundle connectionResult) {
+            if (mControllerBinder == null) return;
+
+            try {
+                mControllerBinder.notifyConnected(getNextSeqNumber(), connectionResult);
+            } catch (RuntimeException e) {
+                // Controller may be died prematurely.
+            }
+        }
+
+        void notifyDisconnected() {
+            if (mControllerBinder == null) return;
+
+            try {
+                mControllerBinder.notifyDisconnected(getNextSeqNumber());
+            } catch (RuntimeException e) {
+                // Controller may be died prematurely.
+            }
+        }
+
+        void notifyPlaybackActiveChanged(boolean playbackActive) {
+            if (mControllerBinder == null) return;
+
+            try {
+                mControllerBinder.notifyPlaybackActiveChanged(getNextSeqNumber(), playbackActive);
+            } catch (RuntimeException e) {
+                // Controller may be died prematurely.
+            }
+        }
+
+        void sendSessionCommand(Session2Command command, Bundle args,
+                ResultReceiver resultReceiver) {
+            if (mControllerBinder == null) return;
+
+            try {
+                int seq = getNextSeqNumber();
+                synchronized (mLock) {
+                    mPendingCommands.put(resultReceiver, seq);
+                }
+                mControllerBinder.sendSessionCommand(seq, command, args, resultReceiver);
+            } catch (RuntimeException e) {
+                // Controller may be died prematurely.
+                synchronized (mLock) {
+                    mPendingCommands.remove(resultReceiver);
+                }
+                resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null);
+            }
+        }
+
+        void cancelSessionCommand(@NonNull Object token) {
+            if (mControllerBinder == null) return;
+            Integer seq;
+            synchronized (mLock) {
+                seq = mPendingCommands.remove(token);
+            }
+            if (seq != null) {
+                mControllerBinder.cancelSessionCommand(seq);
+            }
+        }
+
+        void receiveCommandResult(ResultReceiver resultReceiver) {
+            synchronized (mLock) {
+                mPendingCommands.remove(resultReceiver);
+            }
+        }
+
+        void addRequestedCommandSeqNumber(int seq) {
+            synchronized (mLock) {
+                mRequestedCommandSeqNumbers.add(seq);
+            }
+        }
+
+        boolean removeRequestedCommandSeqNumber(int seq) {
+            synchronized (mLock) {
+                return mRequestedCommandSeqNumbers.remove(seq);
+            }
+        }
+
+        private int getNextSeqNumber() {
+            synchronized (mLock) {
+                return mNextSeqNumber++;
+            }
+        }
+    }
+
+    /**
+     * Callback to be called for all incoming commands from {@link MediaController2}s.
+     * <p>
+     * This API is not generally intended for third party application developers.
+     */
+    public abstract static class SessionCallback {
+        /**
+         * Called when a controller is created for this session. Return allowed commands for
+         * controller. By default it returns {@code null}.
+         * <p>
+         * You can reject the connection by returning {@code null}. In that case, controller
+         * receives {@link MediaController2.ControllerCallback#onDisconnected(MediaController2)}
+         * and cannot be used.
+         *
+         * @param session the session for this event
+         * @param controller controller information.
+         * @return allowed commands. Can be {@code null} to reject connection.
+         */
+        @Nullable
+        public Session2CommandGroup onConnect(@NonNull MediaSession2 session,
+                @NonNull ControllerInfo controller) {
+            return null;
+        }
+
+        /**
+         * Called when a controller is disconnected
+         *
+         * @param session the session for this event
+         * @param controller controller information
+         */
+        public void onDisconnected(@NonNull MediaSession2 session,
+                @NonNull ControllerInfo controller) {}
+
+        /**
+         * Called when a controller sent a session command.
+         *
+         * @param session the session for this event
+         * @param controller controller information
+         * @param command the session command
+         * @param args optional arguments
+         * @return the result for the session command. If {@code null}, RESULT_INFO_SKIPPED
+         *         will be sent to the session.
+         */
+        @Nullable
+        public Session2Command.Result onSessionCommand(@NonNull MediaSession2 session,
+                @NonNull ControllerInfo controller, @NonNull Session2Command command,
+                @Nullable Bundle args) {
+            return null;
+        }
+
+        /**
+         * Called when the command sent to the controller is finished.
+         *
+         * @param session the session for this event
+         * @param controller controller information
+         * @param token the token got from {@link MediaSession2#sendSessionCommand}
+         * @param command the session command
+         * @param result the result of the session command
+         */
+        public void onCommandResult(@NonNull MediaSession2 session,
+                @NonNull ControllerInfo controller, @NonNull Object token,
+                @NonNull Session2Command command, @NonNull Session2Command.Result result) {}
+    }
+
+    abstract static class ForegroundServiceEventCallback {
+        public void onPlaybackActiveChanged(MediaSession2 session, boolean playbackActive) {}
+        public void onSessionClosed(MediaSession2 session) {}
+    }
+}
diff --git a/media/apex/java/android/media/MediaSession2Service.java b/media/apex/java/android/media/MediaSession2Service.java
new file mode 100644
index 0000000..5bb746a
--- /dev/null
+++ b/media/apex/java/android/media/MediaSession2Service.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Service containing {@link MediaSession2}.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
+ */
+public abstract class MediaSession2Service extends Service {
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    public static final String SERVICE_INTERFACE = "android.media.MediaSession2Service";
+
+    private static final String TAG = "MediaSession2Service";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final MediaSession2.ForegroundServiceEventCallback mForegroundServiceEventCallback =
+            new MediaSession2.ForegroundServiceEventCallback() {
+                @Override
+                public void onPlaybackActiveChanged(MediaSession2 session, boolean playbackActive) {
+                    MediaSession2Service.this.onPlaybackActiveChanged(session, playbackActive);
+                }
+
+                @Override
+                public void onSessionClosed(MediaSession2 session) {
+                    removeSession(session);
+                }
+            };
+
+    private final Object mLock = new Object();
+    //@GuardedBy("mLock")
+    private NotificationManager mNotificationManager;
+    //@GuardedBy("mLock")
+    private Intent mStartSelfIntent;
+    //@GuardedBy("mLock")
+    private Map<String, MediaSession2> mSessions = new ArrayMap<>();
+    //@GuardedBy("mLock")
+    private Map<MediaSession2, MediaNotification> mNotifications = new ArrayMap<>();
+    //@GuardedBy("mLock")
+    private MediaSession2ServiceStub mStub;
+
+    /**
+     * Called by the system when the service is first created. Do not call this method directly.
+     * <p>
+     * Override this method if you need your own initialization. Derived classes MUST call through
+     * to the super class's implementation of this method.
+     */
+    @CallSuper
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        synchronized (mLock) {
+            mStub = new MediaSession2ServiceStub(this);
+            mStartSelfIntent = new Intent(this, this.getClass());
+            mNotificationManager =
+                    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+        }
+    }
+
+    @CallSuper
+    @Override
+    @Nullable
+    public IBinder onBind(@NonNull Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            synchronized (mLock) {
+                return mStub;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Called by the system to notify that it is no longer used and is being removed. Do not call
+     * this method directly.
+     * <p>
+     * Override this method if you need your own clean up. Derived classes MUST call through
+     * to the super class's implementation of this method.
+     */
+    @CallSuper
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        synchronized (mLock) {
+            List<MediaSession2> sessions = getSessions();
+            for (MediaSession2 session : sessions) {
+                removeSession(session);
+            }
+            mSessions.clear();
+            mNotifications.clear();
+        }
+        mStub.close();
+    }
+
+    /**
+     * Called when a {@link MediaController2} is created with the this service's
+     * {@link Session2Token}. Return the primary session for telling the controller which session to
+     * connect.
+     * <p>
+     * Primary session is the highest priority session that this service manages. Here are some
+     * recommendations of the primary session.
+     * <ol>
+     * <li>When there's no {@link MediaSession2}, create and return a new session. Resume the
+     * playback that the app has the lastly played with the new session. The behavior is what
+     * framework expects when the framework sends key events to the service.</li>
+     * <li>When there's multiple {@link MediaSession2}s, pick the session that has the lastly
+     * started the playback. This is the same way as the framework prioritize sessions to receive
+     * media key events.</li>
+     * </ol>
+     * <p>
+     * Session returned here will be added to this service automatically. You don't need to call
+     * {@link #addSession(MediaSession2)} for that.
+     * <p>
+     * Session service will accept or reject the connection with the
+     * {@link MediaSession2.SessionCallback} in the session returned here.
+     * <p>
+     * This method is always called on the main thread.
+     *
+     * @return a new session
+     * @see MediaSession2.Builder
+     * @see #getSessions()
+     */
+    @NonNull
+    public abstract MediaSession2 onGetPrimarySession();
+
+    /**
+     * Called when notification UI needs update. Override this method to show or cancel your own
+     * notification UI.
+     * <p>
+     * This would be called on {@link MediaSession2}'s callback executor when playback state is
+     * changed.
+     * <p>
+     * With the notification returned here, the service becomes foreground service when the playback
+     * is started. Apps must request the permission
+     * {@link android.Manifest.permission#FOREGROUND_SERVICE} in order to use this API. It becomes
+     * background service after the playback is stopped.
+     *
+     * @param session a session that needs notification update.
+     * @return a {@link MediaNotification}. Can be {@code null}.
+     */
+    @Nullable
+    public abstract MediaNotification onUpdateNotification(@NonNull MediaSession2 session);
+
+    /**
+     * Adds a session to this service.
+     * <p>
+     * Added session will be removed automatically when it's closed, or removed when
+     * {@link #removeSession} is called.
+     *
+     * @param session a session to be added.
+     * @see #removeSession(MediaSession2)
+     */
+    public final void addSession(@NonNull MediaSession2 session) {
+        if (session == null) {
+            throw new IllegalArgumentException("session shouldn't be null");
+        }
+        if (session.isClosed()) {
+            throw new IllegalArgumentException("session is already closed");
+        }
+        synchronized (mLock) {
+            MediaSession2 previousSession = mSessions.get(session.getSessionId());
+            if (previousSession != null) {
+                if (previousSession != session) {
+                    Log.w(TAG, "Session ID should be unique, ID=" + session.getSessionId()
+                            + ", previous=" + previousSession + ", session=" + session);
+                }
+                return;
+            }
+            mSessions.put(session.getSessionId(), session);
+            session.setForegroundServiceEventCallback(mForegroundServiceEventCallback);
+        }
+    }
+
+    /**
+     * Removes a session from this service.
+     *
+     * @param session a session to be removed.
+     * @see #addSession(MediaSession2)
+     */
+    public final void removeSession(@NonNull MediaSession2 session) {
+        if (session == null) {
+            throw new IllegalArgumentException("session shouldn't be null");
+        }
+        MediaNotification notification;
+        synchronized (mLock) {
+            if (mSessions.get(session.getSessionId()) != session) {
+                // Session isn't added or removed already.
+                return;
+            }
+            mSessions.remove(session.getSessionId());
+            notification = mNotifications.remove(session);
+        }
+        session.setForegroundServiceEventCallback(null);
+        if (notification != null) {
+            mNotificationManager.cancel(notification.getNotificationId());
+        }
+        if (getSessions().isEmpty()) {
+            stopForeground(false);
+        }
+    }
+
+    /**
+     * Gets the list of {@link MediaSession2}s that you've added to this service.
+     *
+     * @return sessions
+     */
+    public final @NonNull List<MediaSession2> getSessions() {
+        List<MediaSession2> list = new ArrayList<>();
+        synchronized (mLock) {
+            list.addAll(mSessions.values());
+        }
+        return list;
+    }
+
+    /**
+     * Called by registered {@link MediaSession2.ForegroundServiceEventCallback}
+     *
+     * @param session session with change
+     * @param playbackActive {@code true} if playback is active.
+     */
+    void onPlaybackActiveChanged(MediaSession2 session, boolean playbackActive) {
+        MediaNotification mediaNotification = onUpdateNotification(session);
+        if (mediaNotification == null) {
+            // The service implementation doesn't want to use the automatic start/stopForeground
+            // feature.
+            return;
+        }
+        synchronized (mLock) {
+            mNotifications.put(session, mediaNotification);
+        }
+        int id = mediaNotification.getNotificationId();
+        Notification notification = mediaNotification.getNotification();
+        if (!playbackActive) {
+            mNotificationManager.notify(id, notification);
+            return;
+        }
+        // playbackActive == true
+        startForegroundService(mStartSelfIntent);
+        startForeground(id, notification);
+    }
+
+    /**
+     * Returned by {@link #onUpdateNotification(MediaSession2)} for making session service
+     * foreground service to keep playback running in the background. It's highly recommended to
+     * show media style notification here.
+     */
+    public static class MediaNotification {
+        private final int mNotificationId;
+        private final Notification mNotification;
+
+        /**
+         * Default constructor
+         *
+         * @param notificationId notification id to be used for
+         *        {@link NotificationManager#notify(int, Notification)}.
+         * @param notification a notification to make session service run in the foreground. Media
+         *        style notification is recommended here.
+         */
+        public MediaNotification(int notificationId, @NonNull Notification notification) {
+            if (notification == null) {
+                throw new IllegalArgumentException("notification shouldn't be null");
+            }
+            mNotificationId = notificationId;
+            mNotification = notification;
+        }
+
+        /**
+         * Gets the id of the notification.
+         *
+         * @return the notification id
+         */
+        public int getNotificationId() {
+            return mNotificationId;
+        }
+
+        /**
+         * Gets the notification.
+         *
+         * @return the notification
+         */
+        @NonNull
+        public Notification getNotification() {
+            return mNotification;
+        }
+    }
+
+    private static final class MediaSession2ServiceStub extends IMediaSession2Service.Stub
+            implements AutoCloseable {
+        final WeakReference<MediaSession2Service> mService;
+        final Handler mHandler;
+
+        MediaSession2ServiceStub(MediaSession2Service service) {
+            mService = new WeakReference<>(service);
+            mHandler = new Handler(service.getMainLooper());
+        }
+
+        @Override
+        public void connect(Controller2Link caller, int seq, Bundle connectionRequest) {
+            if (mService.get() == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "Service is already destroyed");
+                }
+                return;
+            }
+            if (caller == null || connectionRequest == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "Ignoring calls with illegal arguments, caller=" + caller
+                            + ", connectionRequest=" + connectionRequest);
+                }
+                return;
+            }
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mHandler.post(() -> {
+                    boolean shouldNotifyDisconnected = true;
+                    try {
+                        final MediaSession2Service service = mService.get();
+                        if (service == null) {
+                            if (DEBUG) {
+                                Log.d(TAG, "Service isn't available");
+                            }
+                            return;
+                        }
+                        if (DEBUG) {
+                            Log.d(TAG, "Handling incoming connection request from the"
+                                    + " controller, controller=" + caller + ", uid=" + uid);
+                        }
+                        final MediaSession2 session;
+                        session = service.onGetPrimarySession();
+                        service.addSession(session);
+                        shouldNotifyDisconnected = false;
+                        session.onConnect(caller, pid, uid, seq, connectionRequest);
+                    } catch (Exception e) {
+                        // Don't propagate exception in service to the controller.
+                        Log.w(TAG, "Failed to add a session to session service", e);
+                    } finally {
+                        // Trick to call onDisconnected() in one place.
+                        if (shouldNotifyDisconnected) {
+                            if (DEBUG) {
+                                Log.d(TAG, "Service has destroyed prematurely."
+                                        + " Rejecting connection");
+                            }
+                            try {
+                                caller.notifyDisconnected(0);
+                            } catch (RuntimeException e) {
+                                // Controller may be died prematurely.
+                                // Not an issue because we'll ignore it anyway.
+                            }
+                        }
+                    }
+                });
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void close() {
+            mHandler.removeCallbacksAndMessages(null);
+            mService.clear();
+        }
+    }
+}
diff --git a/media/java/android/media/RoutingDelegate.java b/media/apex/java/android/media/RoutingDelegate.java
similarity index 100%
rename from media/java/android/media/RoutingDelegate.java
rename to media/apex/java/android/media/RoutingDelegate.java
diff --git a/media/java/android/media/Session2Command.aidl b/media/apex/java/android/media/Session2Command.aidl
similarity index 100%
rename from media/java/android/media/Session2Command.aidl
rename to media/apex/java/android/media/Session2Command.aidl
diff --git a/media/apex/java/android/media/Session2Command.java b/media/apex/java/android/media/Session2Command.java
new file mode 100644
index 0000000..8b285f2
--- /dev/null
+++ b/media/apex/java/android/media/Session2Command.java
@@ -0,0 +1,209 @@
+/*
+ * 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.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.Objects;
+
+/**
+ * Define a command that a {@link MediaController2} can send to a {@link MediaSession2}.
+ * <p>
+ * If {@link #getCommandCode()} isn't {@link #COMMAND_CODE_CUSTOM}), it's predefined command.
+ * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and
+ * {@link #getCustomCommand()} shouldn't be {@code null}.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
+ */
+public final class Session2Command implements Parcelable {
+    /**
+     * Command code for the custom command which can be defined by string action in the
+     * {@link Session2Command}.
+     */
+    public static final int COMMAND_CODE_CUSTOM = 0;
+
+    /**
+     * Result code representing that the command is skipped or canceled. For an example, a seek
+     * command can be skipped if it is followed by another seek command.
+     */
+    public static final int RESULT_INFO_SKIPPED = 1;
+
+    /**
+     * Result code representing that the command is successfully completed.
+     */
+    public static final int RESULT_SUCCESS = 0;
+
+    /**
+     * Result code represents that call is ended with an unknown error.
+     */
+    public static final int RESULT_ERROR_UNKNOWN_ERROR = -1;
+
+    public static final Parcelable.Creator<Session2Command> CREATOR =
+            new Parcelable.Creator<Session2Command>() {
+                @Override
+                public Session2Command createFromParcel(Parcel in) {
+                    return new Session2Command(in);
+                }
+
+                @Override
+                public Session2Command[] newArray(int size) {
+                    return new Session2Command[size];
+                }
+            };
+
+    private final int mCommandCode;
+    // Nonnull if it's custom command
+    private final String mCustomCommand;
+    private final Bundle mExtras;
+
+    /**
+     * Constructor for creating a command predefined in AndroidX media2.
+     *
+     * @param commandCode A command code for a command predefined in AndroidX media2.
+     */
+    public Session2Command(int commandCode) {
+        if (commandCode == COMMAND_CODE_CUSTOM) {
+            throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM");
+        }
+        mCommandCode = commandCode;
+        mCustomCommand = null;
+        mExtras = null;
+    }
+
+    /**
+     * Constructor for creating a custom command.
+     *
+     * @param action The action of this custom command.
+     * @param extras An extra bundle for this custom command.
+     */
+    public Session2Command(@NonNull String action, @Nullable Bundle extras) {
+        if (action == null) {
+            throw new IllegalArgumentException("action shouldn't be null");
+        }
+        mCommandCode = COMMAND_CODE_CUSTOM;
+        mCustomCommand = action;
+        mExtras = extras;
+    }
+
+    /**
+     * Used by parcelable creator.
+     */
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    Session2Command(Parcel in) {
+        mCommandCode = in.readInt();
+        mCustomCommand = in.readString();
+        mExtras = in.readBundle();
+    }
+
+    /**
+     * Gets the command code of a predefined command.
+     * This will return {@link #COMMAND_CODE_CUSTOM} for a custom command.
+     */
+    public int getCommandCode() {
+        return mCommandCode;
+    }
+
+    /**
+     * Gets the action of a custom command.
+     * This will return {@code null} for a predefined command.
+     */
+    @Nullable
+    public String getCustomCommand() {
+        return mCustomCommand;
+    }
+
+    /**
+     * Gets the extra bundle of a custom command.
+     * This will return {@code null} for a predefined command.
+     */
+    @Nullable
+    public Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        if (dest == null) {
+            throw new IllegalArgumentException("parcel shouldn't be null");
+        }
+        dest.writeInt(mCommandCode);
+        dest.writeString(mCustomCommand);
+        dest.writeBundle(mExtras);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (!(obj instanceof Session2Command)) {
+            return false;
+        }
+        Session2Command other = (Session2Command) obj;
+        return mCommandCode == other.mCommandCode
+                && TextUtils.equals(mCustomCommand, other.mCustomCommand);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mCustomCommand, mCommandCode);
+    }
+
+    /**
+     * Contains the result of {@link Session2Command}.
+     */
+    public static final class Result {
+        private final int mResultCode;
+        private final Bundle mResultData;
+
+        /**
+         * Constructor of {@link Result}.
+         *
+         * @param resultCode result code
+         * @param resultData result data
+         */
+        public Result(int resultCode, @Nullable Bundle resultData) {
+            mResultCode = resultCode;
+            mResultData = resultData;
+        }
+
+        /**
+         * Returns the result code.
+         */
+        public int getResultCode() {
+            return mResultCode;
+        }
+
+        /**
+         * Returns the result data.
+         */
+        @Nullable
+        public Bundle getResultData() {
+            return mResultData;
+        }
+    }
+}
diff --git a/media/apex/java/android/media/Session2CommandGroup.java b/media/apex/java/android/media/Session2CommandGroup.java
new file mode 100644
index 0000000..2dab697
--- /dev/null
+++ b/media/apex/java/android/media/Session2CommandGroup.java
@@ -0,0 +1,224 @@
+/*
+ * 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.media;
+
+import static android.media.Session2Command.COMMAND_CODE_CUSTOM;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A set of {@link Session2Command} which represents a command group.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
+ * </p>
+ */
+public final class Session2CommandGroup implements Parcelable {
+    private static final String TAG = "Session2CommandGroup";
+
+    public static final Parcelable.Creator<Session2CommandGroup> CREATOR =
+            new Parcelable.Creator<Session2CommandGroup>() {
+                @Override
+                public Session2CommandGroup createFromParcel(Parcel in) {
+                    return new Session2CommandGroup(in);
+                }
+
+                @Override
+                public Session2CommandGroup[] newArray(int size) {
+                    return new Session2CommandGroup[size];
+                }
+            };
+
+    Set<Session2Command> mCommands = new HashSet<>();
+
+    /**
+     * Creates a new Session2CommandGroup with commands copied from another object.
+     *
+     * @param commands The collection of commands to copy.
+     */
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    Session2CommandGroup(@Nullable Collection<Session2Command> commands) {
+        if (commands != null) {
+            mCommands.addAll(commands);
+        }
+    }
+
+    /**
+     * Used by parcelable creator.
+     */
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    Session2CommandGroup(Parcel in) {
+        Parcelable[] commands = in.readParcelableArray(Session2Command.class.getClassLoader());
+        if (commands != null) {
+            for (Parcelable command : commands) {
+                mCommands.add((Session2Command) command);
+            }
+        }
+    }
+
+    /**
+     * Checks whether this command group has a command that matches given {@code command}.
+     *
+     * @param command A command to find. Shouldn't be {@code null}.
+     */
+    public boolean hasCommand(@NonNull Session2Command command) {
+        if (command == null) {
+            throw new IllegalArgumentException("command shouldn't be null");
+        }
+        return mCommands.contains(command);
+    }
+
+    /**
+     * Checks whether this command group has a command that matches given {@code commandCode}.
+     *
+     * @param commandCode A command code to find.
+     *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
+     */
+    public boolean hasCommand(int commandCode) {
+        if (commandCode == COMMAND_CODE_CUSTOM) {
+            throw new IllegalArgumentException("Use hasCommand(Command) for custom command");
+        }
+        for (Session2Command command : mCommands) {
+            if (command.getCommandCode() == commandCode) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Gets all commands of this command group.
+     */
+    @NonNull
+    public Set<Session2Command> getCommands() {
+        return new HashSet<>(mCommands);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        if (dest == null) {
+            throw new IllegalArgumentException("parcel shouldn't be null");
+        }
+        dest.writeParcelableArray(mCommands.toArray(new Session2Command[0]), 0);
+    }
+
+    /**
+     * Builds a {@link Session2CommandGroup} object.
+     */
+    public static final class Builder {
+        private Set<Session2Command> mCommands;
+
+        public Builder() {
+            mCommands = new HashSet<>();
+        }
+
+        /**
+         * Creates a new builder for {@link Session2CommandGroup} with commands copied from another
+         * {@link Session2CommandGroup} object.
+         * @param commandGroup
+         */
+        public Builder(@NonNull Session2CommandGroup commandGroup) {
+            if (commandGroup == null) {
+                throw new IllegalArgumentException("command group shouldn't be null");
+            }
+            mCommands = commandGroup.getCommands();
+        }
+
+        /**
+         * Adds a command to this command group.
+         *
+         * @param command A command to add. Shouldn't be {@code null}.
+         */
+        @NonNull
+        public Builder addCommand(@NonNull Session2Command command) {
+            if (command == null) {
+                throw new IllegalArgumentException("command shouldn't be null");
+            }
+            mCommands.add(command);
+            return this;
+        }
+
+        /**
+         * Adds a predefined command with given {@code commandCode} to this command group.
+         *
+         * @param commandCode A command code to add.
+         *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
+         */
+        @NonNull
+        public Builder addCommand(int commandCode) {
+            if (commandCode == COMMAND_CODE_CUSTOM) {
+                throw new IllegalArgumentException(
+                        "Use addCommand(Session2Command) for COMMAND_CODE_CUSTOM.");
+            }
+            mCommands.add(new Session2Command(commandCode));
+            return this;
+        }
+
+        /**
+         * Removes a command from this group which matches given {@code command}.
+         *
+         * @param command A command to find. Shouldn't be {@code null}.
+         */
+        @NonNull
+        public Builder removeCommand(@NonNull Session2Command command) {
+            if (command == null) {
+                throw new IllegalArgumentException("command shouldn't be null");
+            }
+            mCommands.remove(command);
+            return this;
+        }
+
+        /**
+         * Removes a command from this group which matches given {@code commandCode}.
+         *
+         * @param commandCode A command code to find.
+         *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
+         */
+        @NonNull
+        public Builder removeCommand(int commandCode) {
+            if (commandCode == COMMAND_CODE_CUSTOM) {
+                throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM");
+            }
+            mCommands.remove(new Session2Command(commandCode));
+            return this;
+        }
+
+        /**
+         * Builds {@link Session2CommandGroup}.
+         *
+         * @return a new {@link Session2CommandGroup}.
+         */
+        @NonNull
+        public Session2CommandGroup build() {
+            return new Session2CommandGroup(mCommands);
+        }
+    }
+}
diff --git a/media/apex/java/android/media/Session2Link.java b/media/apex/java/android/media/Session2Link.java
new file mode 100644
index 0000000..08664aa
--- /dev/null
+++ b/media/apex/java/android/media/Session2Link.java
@@ -0,0 +1,226 @@
+/*
+ * 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.media;
+
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+import java.util.Objects;
+
+/**
+ * Handles incoming commands from {@link MediaController2} to {@link MediaSession2}.
+ * @hide
+ */
+// @SystemApi
+public final class Session2Link implements Parcelable {
+    private static final String TAG = "Session2Link";
+    private static final boolean DEBUG = MediaSession2.DEBUG;
+
+    public static final Parcelable.Creator<Session2Link> CREATOR =
+            new Parcelable.Creator<Session2Link>() {
+                @Override
+                public Session2Link createFromParcel(Parcel in) {
+                    return new Session2Link(in);
+                }
+
+                @Override
+                public Session2Link[] newArray(int size) {
+                    return new Session2Link[size];
+                }
+            };
+
+    private final MediaSession2 mSession;
+    private final IMediaSession2 mISession;
+
+    public Session2Link(MediaSession2 session) {
+        mSession = session;
+        mISession = new Session2Stub();
+    }
+
+    Session2Link(Parcel in) {
+        mSession = null;
+        mISession = IMediaSession2.Stub.asInterface(in.readStrongBinder());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(mISession.asBinder());
+    }
+
+    @Override
+    public int hashCode() {
+        return mISession.asBinder().hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof Session2Link)) {
+            return false;
+        }
+        Session2Link other = (Session2Link) obj;
+        return Objects.equals(mISession.asBinder(), other.mISession.asBinder());
+    }
+
+    /** Link to death with mISession */
+    public void linkToDeath(@NonNull IBinder.DeathRecipient recipient, int flags) {
+        if (mISession != null) {
+            try {
+                mISession.asBinder().linkToDeath(recipient, flags);
+            } catch (RemoteException e) {
+                if (DEBUG) {
+                    Log.d(TAG, "Session died too early.", e);
+                }
+            }
+        }
+    }
+
+    /** Unlink to death with mISession */
+    public boolean unlinkToDeath(@NonNull IBinder.DeathRecipient recipient, int flags) {
+        if (mISession != null) {
+            return mISession.asBinder().unlinkToDeath(recipient, flags);
+        }
+        return true;
+    }
+
+    /** Interface method for IMediaSession2.connect */
+    public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) {
+        try {
+            mISession.connect(caller, seq, connectionRequest);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Interface method for IMediaSession2.disconnect */
+    public void disconnect(final Controller2Link caller, int seq) {
+        try {
+            mISession.disconnect(caller, seq);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Interface method for IMediaSession2.sendSessionCommand */
+    public void sendSessionCommand(final Controller2Link caller, final int seq,
+            final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
+        try {
+            mISession.sendSessionCommand(caller, seq, command, args, resultReceiver);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Interface method for IMediaSession2.sendSessionCommand */
+    public void cancelSessionCommand(final Controller2Link caller, final int seq) {
+        try {
+            mISession.cancelSessionCommand(caller, seq);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Stub implementation for IMediaSession2.connect */
+    public void onConnect(final Controller2Link caller, int pid, int uid, int seq,
+            Bundle connectionRequest) {
+        mSession.onConnect(caller, pid, uid, seq, connectionRequest);
+    }
+
+    /** Stub implementation for IMediaSession2.disconnect */
+    public void onDisconnect(final Controller2Link caller, int seq) {
+        mSession.onDisconnect(caller, seq);
+    }
+
+    /** Stub implementation for IMediaSession2.sendSessionCommand */
+    public void onSessionCommand(final Controller2Link caller, final int seq,
+            final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
+        mSession.onSessionCommand(caller, seq, command, args, resultReceiver);
+    }
+
+    /** Stub implementation for IMediaSession2.cancelSessionCommand */
+    public void onCancelCommand(final Controller2Link caller, final int seq) {
+        mSession.onCancelCommand(caller, seq);
+    }
+
+    private class Session2Stub extends IMediaSession2.Stub {
+        @Override
+        public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) {
+            if (caller == null || connectionRequest == null) {
+                return;
+            }
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Session2Link.this.onConnect(caller, pid, uid, seq, connectionRequest);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void disconnect(final Controller2Link caller, int seq) {
+            if (caller == null) {
+                return;
+            }
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Session2Link.this.onDisconnect(caller, seq);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void sendSessionCommand(final Controller2Link caller, final int seq,
+                final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
+            if (caller == null) {
+                return;
+            }
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Session2Link.this.onSessionCommand(caller, seq, command, args, resultReceiver);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void cancelSessionCommand(final Controller2Link caller, final int seq) {
+            if (caller == null) {
+                return;
+            }
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Session2Link.this.onCancelCommand(caller, seq);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    }
+}
diff --git a/media/apex/java/android/media/Session2Token.aidl b/media/apex/java/android/media/Session2Token.aidl
new file mode 100644
index 0000000..c5980e9
--- /dev/null
+++ b/media/apex/java/android/media/Session2Token.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+parcelable Session2Token;
diff --git a/media/apex/java/android/media/Session2Token.java b/media/apex/java/android/media/Session2Token.java
new file mode 100644
index 0000000..238cc2b
--- /dev/null
+++ b/media/apex/java/android/media/Session2Token.java
@@ -0,0 +1,246 @@
+/*
+ * 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.media;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents an ongoing {@link MediaSession2} or a {@link MediaSession2Service}.
+ * If it's representing a session service, it may not be ongoing.
+ * <p>
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+ * for consistent behavior across all devices.
+ * <p>
+ * This may be passed to apps by the session owner to allow them to create a
+ * {@link MediaController2} to communicate with the session.
+ * <p>
+ * It can be also obtained by {@link android.media.session.MediaSessionManager}.
+ */
+public final class Session2Token implements Parcelable {
+    private static final String TAG = "Session2Token";
+
+    public static final Creator<Session2Token> CREATOR = new Creator<Session2Token>() {
+        @Override
+        public Session2Token createFromParcel(Parcel p) {
+            return new Session2Token(p);
+        }
+
+        @Override
+        public Session2Token[] newArray(int size) {
+            return new Session2Token[size];
+        }
+    };
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "TYPE_", value = {TYPE_SESSION, TYPE_SESSION_SERVICE})
+    public @interface TokenType {
+    }
+
+    /**
+     * Type for {@link MediaSession2}.
+     */
+    public static final int TYPE_SESSION = 0;
+
+    /**
+     * Type for {@link MediaSession2Service}.
+     */
+    public static final int TYPE_SESSION_SERVICE = 1;
+
+    private final int mUid;
+    @TokenType
+    private final int mType;
+    private final String mPackageName;
+    private final String mServiceName;
+    private final Session2Link mSessionLink;
+    private final ComponentName mComponentName;
+
+    /**
+     * Constructor for the token with type {@link #TYPE_SESSION_SERVICE}.
+     *
+     * @param context The context.
+     * @param serviceComponent The component name of the service.
+     */
+    public Session2Token(@NonNull Context context, @NonNull ComponentName serviceComponent) {
+        if (context == null) {
+            throw new IllegalArgumentException("context shouldn't be null");
+        }
+        if (serviceComponent == null) {
+            throw new IllegalArgumentException("serviceComponent shouldn't be null");
+        }
+
+        final PackageManager manager = context.getPackageManager();
+        final int uid = getUid(manager, serviceComponent.getPackageName());
+
+        if (!isInterfaceDeclared(manager, MediaSession2Service.SERVICE_INTERFACE,
+                serviceComponent)) {
+            Log.w(TAG, serviceComponent + " doesn't implement MediaSession2Service.");
+        }
+        mComponentName = serviceComponent;
+        mPackageName = serviceComponent.getPackageName();
+        mServiceName = serviceComponent.getClassName();
+        mUid = uid;
+        mType = TYPE_SESSION_SERVICE;
+        mSessionLink = null;
+    }
+
+    Session2Token(int uid, int type, String packageName, Session2Link sessionLink) {
+        mUid = uid;
+        mType = type;
+        mPackageName = packageName;
+        mServiceName = null;
+        mComponentName = null;
+        mSessionLink = sessionLink;
+    }
+
+    Session2Token(Parcel in) {
+        mUid = in.readInt();
+        mType = in.readInt();
+        mPackageName = in.readString();
+        mServiceName = in.readString();
+        mSessionLink = in.readParcelable(null);
+        mComponentName = ComponentName.unflattenFromString(in.readString());
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mUid);
+        dest.writeInt(mType);
+        dest.writeString(mPackageName);
+        dest.writeString(mServiceName);
+        dest.writeParcelable(mSessionLink, flags);
+        dest.writeString(mComponentName == null ? "" : mComponentName.flattenToString());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mType, mUid, mPackageName, mServiceName, mSessionLink);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof Session2Token)) {
+            return false;
+        }
+        Session2Token other = (Session2Token) obj;
+        return mUid == other.mUid
+                && TextUtils.equals(mPackageName, other.mPackageName)
+                && TextUtils.equals(mServiceName, other.mServiceName)
+                && mType == other.mType
+                && Objects.equals(mSessionLink, other.mSessionLink);
+    }
+
+    @Override
+    public String toString() {
+        return "Session2Token {pkg=" + mPackageName + " type=" + mType
+                + " service=" + mServiceName + " Session2Link=" + mSessionLink + "}";
+    }
+
+    /**
+     * @return uid of the session
+     */
+    public int getUid() {
+        return mUid;
+    }
+
+    /**
+     * @return package name of the session
+     */
+    @NonNull
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * @return service name of the session. Can be {@code null} for {@link #TYPE_SESSION}.
+     */
+    @Nullable
+    public String getServiceName() {
+        return mServiceName;
+    }
+
+    /**
+     * @return type of the token
+     * @see #TYPE_SESSION
+     * @see #TYPE_SESSION_SERVICE
+     */
+    public @TokenType int getType() {
+        return mType;
+    }
+
+    Session2Link getSessionLink() {
+        return mSessionLink;
+    }
+
+    private static boolean isInterfaceDeclared(PackageManager manager, String serviceInterface,
+            ComponentName serviceComponent) {
+        Intent serviceIntent = new Intent(serviceInterface);
+        // Use queryIntentServices to find services with MediaSession2Service.SERVICE_INTERFACE.
+        // We cannot use resolveService with intent specified class name, because resolveService
+        // ignores actions if Intent.setClassName() is specified.
+        serviceIntent.setPackage(serviceComponent.getPackageName());
+
+        List<ResolveInfo> list = manager.queryIntentServices(
+                serviceIntent, PackageManager.GET_META_DATA);
+        if (list != null) {
+            for (int i = 0; i < list.size(); i++) {
+                ResolveInfo resolveInfo = list.get(i);
+                if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+                    continue;
+                }
+                if (TextUtils.equals(
+                        resolveInfo.serviceInfo.name, serviceComponent.getClassName())) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static int getUid(PackageManager manager, String packageName) {
+        try {
+            return manager.getApplicationInfo(packageName, 0).uid;
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalArgumentException("Cannot find package " + packageName);
+        }
+    }
+}
diff --git a/media/java/android/media/UriDataSourceDesc.java b/media/apex/java/android/media/UriDataSourceDesc.java
similarity index 100%
rename from media/java/android/media/UriDataSourceDesc.java
rename to media/apex/java/android/media/UriDataSourceDesc.java
diff --git a/media/java/android/media/VideoSize.java b/media/apex/java/android/media/VideoSize.java
similarity index 100%
rename from media/java/android/media/VideoSize.java
rename to media/apex/java/android/media/VideoSize.java
diff --git a/media/apex/java/android/media/VolumeProvider.java b/media/apex/java/android/media/VolumeProvider.java
new file mode 100644
index 0000000..49202ee
--- /dev/null
+++ b/media/apex/java/android/media/VolumeProvider.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.media.session.MediaSession;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Handles requests to adjust or set the volume on a session. This is also used
+ * to push volume updates back to the session. The provider must call
+ * {@link #setCurrentVolume(int)} each time the volume being provided changes.
+ * <p>
+ * You can set a volume provider on a session by calling
+ * {@link MediaSession#setPlaybackToRemote}.
+ */
+public abstract class VolumeProvider {
+
+    /**
+     * @hide
+     */
+    @IntDef({VOLUME_CONTROL_FIXED, VOLUME_CONTROL_RELATIVE, VOLUME_CONTROL_ABSOLUTE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ControlType {}
+
+    /**
+     * The volume is fixed and can not be modified. Requests to change volume
+     * should be ignored.
+     */
+    public static final int VOLUME_CONTROL_FIXED = 0;
+
+    /**
+     * The volume control uses relative adjustment via
+     * {@link #onAdjustVolume(int)}. Attempts to set the volume to a specific
+     * value should be ignored.
+     */
+    public static final int VOLUME_CONTROL_RELATIVE = 1;
+
+    /**
+     * The volume control uses an absolute value. It may be adjusted using
+     * {@link #onAdjustVolume(int)} or set directly using
+     * {@link #onSetVolumeTo(int)}.
+     */
+    public static final int VOLUME_CONTROL_ABSOLUTE = 2;
+
+    private final int mControlType;
+    private final int mMaxVolume;
+    private int mCurrentVolume;
+    private Callback mCallback;
+
+    /**
+     * Create a new volume provider for handling volume events. You must specify
+     * the type of volume control, the maximum volume that can be used, and the
+     * current volume on the output.
+     *
+     * @param volumeControl The method for controlling volume that is used by
+     *            this provider.
+     * @param maxVolume The maximum allowed volume.
+     * @param currentVolume The current volume on the output.
+     */
+    public VolumeProvider(@ControlType int volumeControl, int maxVolume, int currentVolume) {
+        mControlType = volumeControl;
+        mMaxVolume = maxVolume;
+        mCurrentVolume = currentVolume;
+    }
+
+    /**
+     * Get the volume control type that this volume provider uses.
+     *
+     * @return The volume control type for this volume provider
+     */
+    @ControlType
+    public final int getVolumeControl() {
+        return mControlType;
+    }
+
+    /**
+     * Get the maximum volume this provider allows.
+     *
+     * @return The max allowed volume.
+     */
+    public final int getMaxVolume() {
+        return mMaxVolume;
+    }
+
+    /**
+     * Gets the current volume. This will be the last value set by
+     * {@link #setCurrentVolume(int)}.
+     *
+     * @return The current volume.
+     */
+    public final int getCurrentVolume() {
+        return mCurrentVolume;
+    }
+
+    /**
+     * Notify the system that the current volume has been changed. This must be
+     * called every time the volume changes to ensure it is displayed properly.
+     *
+     * @param currentVolume The current volume on the output.
+     */
+    public final void setCurrentVolume(int currentVolume) {
+        mCurrentVolume = currentVolume;
+        if (mCallback != null) {
+            mCallback.onVolumeChanged(this);
+        }
+    }
+
+    /**
+     * Override to handle requests to set the volume of the current output.
+     * After the volume has been modified {@link #setCurrentVolume} must be
+     * called to notify the system.
+     *
+     * @param volume The volume to set the output to.
+     */
+    public void onSetVolumeTo(int volume) {
+    }
+
+    /**
+     * Override to handle requests to adjust the volume of the current output.
+     * Direction will be one of {@link AudioManager#ADJUST_LOWER},
+     * {@link AudioManager#ADJUST_RAISE}, {@link AudioManager#ADJUST_SAME}.
+     * After the volume has been modified {@link #setCurrentVolume} must be
+     * called to notify the system.
+     *
+     * @param direction The direction to change the volume in.
+     */
+    public void onAdjustVolume(int direction) {
+    }
+
+    /**
+     * Sets a callback to receive volume changes.
+     * @hide
+     */
+    @SystemApi
+    public void setCallback(Callback callback) {
+        mCallback = callback;
+    }
+
+    /**
+     * Listens for changes to the volume.
+     * @hide
+     */
+    @SystemApi
+    public abstract static class Callback {
+        /**
+         * Called when volume changed.
+         */
+        public abstract void onVolumeChanged(VolumeProvider volumeProvider);
+    }
+}
diff --git a/media/java/android/media/browse/MediaBrowser.aidl b/media/apex/java/android/media/browse/MediaBrowser.aidl
similarity index 100%
rename from media/java/android/media/browse/MediaBrowser.aidl
rename to media/apex/java/android/media/browse/MediaBrowser.aidl
diff --git a/media/apex/java/android/media/browse/MediaBrowser.java b/media/apex/java/android/media/browse/MediaBrowser.java
new file mode 100644
index 0000000..2dffef9
--- /dev/null
+++ b/media/apex/java/android/media/browse/MediaBrowser.java
@@ -0,0 +1,1171 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.browse;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.media.MediaDescription;
+import android.media.MediaParceledListSlice;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.service.media.IMediaBrowserService;
+import android.service.media.IMediaBrowserServiceCallbacks;
+import android.service.media.MediaBrowserService;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+/**
+ * Browses media content offered by a link MediaBrowserService.
+ * <p>
+ * This object is not thread-safe. All calls should happen on the thread on which the browser
+ * was constructed.
+ * </p>
+ * <h3>Standard Extra Data</h3>
+ *
+ * <p>These are the current standard fields that can be used as extra data via
+ * {@link #subscribe(String, Bundle, SubscriptionCallback)},
+ * {@link #unsubscribe(String, SubscriptionCallback)}, and
+ * {@link SubscriptionCallback#onChildrenLoaded(String, List, Bundle)}.
+ *
+ * <ul>
+ *     <li> {@link #EXTRA_PAGE}
+ *     <li> {@link #EXTRA_PAGE_SIZE}
+ * </ul>
+ */
+public final class MediaBrowser {
+    private static final String TAG = "MediaBrowser";
+    private static final boolean DBG = false;
+
+    /**
+     * Used as an int extra field to denote the page number to subscribe.
+     * The value of {@code EXTRA_PAGE} should be greater than or equal to 0.
+     *
+     * @see #EXTRA_PAGE_SIZE
+     */
+    public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
+
+    /**
+     * Used as an int extra field to denote the number of media items in a page.
+     * The value of {@code EXTRA_PAGE_SIZE} should be greater than or equal to 1.
+     *
+     * @see #EXTRA_PAGE
+     */
+    public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
+
+    private static final int CONNECT_STATE_DISCONNECTING = 0;
+    private static final int CONNECT_STATE_DISCONNECTED = 1;
+    private static final int CONNECT_STATE_CONNECTING = 2;
+    private static final int CONNECT_STATE_CONNECTED = 3;
+    private static final int CONNECT_STATE_SUSPENDED = 4;
+
+    private final Context mContext;
+    private final ComponentName mServiceComponent;
+    private final ConnectionCallback mCallback;
+    private final Bundle mRootHints;
+    private final Handler mHandler = new Handler();
+    private final ArrayMap<String, Subscription> mSubscriptions = new ArrayMap<>();
+
+    private volatile int mState = CONNECT_STATE_DISCONNECTED;
+    private volatile String mRootId;
+    private volatile MediaSession.Token mMediaSessionToken;
+    private volatile Bundle mExtras;
+
+    private MediaServiceConnection mServiceConnection;
+    private IMediaBrowserService mServiceBinder;
+    private IMediaBrowserServiceCallbacks mServiceCallbacks;
+
+    /**
+     * Creates a media browser for the specified media browser service.
+     *
+     * @param context The context.
+     * @param serviceComponent The component name of the media browser service.
+     * @param callback The connection callback.
+     * @param rootHints An optional bundle of service-specific arguments to send
+     * to the media browser service when connecting and retrieving the root id
+     * for browsing, or null if none. The contents of this bundle may affect
+     * the information returned when browsing.
+     * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_RECENT
+     * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
+     * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
+     */
+    public MediaBrowser(Context context, ComponentName serviceComponent,
+            ConnectionCallback callback, Bundle rootHints) {
+        if (context == null) {
+            throw new IllegalArgumentException("context must not be null");
+        }
+        if (serviceComponent == null) {
+            throw new IllegalArgumentException("service component must not be null");
+        }
+        if (callback == null) {
+            throw new IllegalArgumentException("connection callback must not be null");
+        }
+        mContext = context;
+        mServiceComponent = serviceComponent;
+        mCallback = callback;
+        mRootHints = rootHints == null ? null : new Bundle(rootHints);
+    }
+
+    /**
+     * Connects to the media browser service.
+     * <p>
+     * The connection callback specified in the constructor will be invoked
+     * when the connection completes or fails.
+     * </p>
+     */
+    public void connect() {
+        if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
+            throw new IllegalStateException("connect() called while neither disconnecting nor "
+                    + "disconnected (state=" + getStateLabel(mState) + ")");
+        }
+
+        mState = CONNECT_STATE_CONNECTING;
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (mState == CONNECT_STATE_DISCONNECTING) {
+                    return;
+                }
+                mState = CONNECT_STATE_CONNECTING;
+                // TODO: remove this extra check.
+                if (DBG) {
+                    if (mServiceConnection != null) {
+                        throw new RuntimeException("mServiceConnection should be null. Instead it"
+                                + " is " + mServiceConnection);
+                    }
+                }
+                if (mServiceBinder != null) {
+                    throw new RuntimeException("mServiceBinder should be null. Instead it is "
+                            + mServiceBinder);
+                }
+                if (mServiceCallbacks != null) {
+                    throw new RuntimeException("mServiceCallbacks should be null. Instead it is "
+                            + mServiceCallbacks);
+                }
+
+                final Intent intent = new Intent(MediaBrowserService.SERVICE_INTERFACE);
+                intent.setComponent(mServiceComponent);
+
+                mServiceConnection = new MediaServiceConnection();
+
+                boolean bound = false;
+                try {
+                    bound = mContext.bindService(intent, mServiceConnection,
+                            Context.BIND_AUTO_CREATE);
+                } catch (Exception ex) {
+                    Log.e(TAG, "Failed binding to service " + mServiceComponent);
+                }
+
+                if (!bound) {
+                    // Tell them that it didn't work.
+                    forceCloseConnection();
+                    mCallback.onConnectionFailed();
+                }
+
+                if (DBG) {
+                    Log.d(TAG, "connect...");
+                    dump();
+                }
+            }
+        });
+    }
+
+    /**
+     * Disconnects from the media browser service.
+     * After this, no more callbacks will be received.
+     */
+    public void disconnect() {
+        // It's ok to call this any state, because allowing this lets apps not have
+        // to check isConnected() unnecessarily. They won't appreciate the extra
+        // assertions for this. We do everything we can here to go back to a sane state.
+        mState = CONNECT_STATE_DISCONNECTING;
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                // connect() could be called before this. Then we will disconnect and reconnect.
+                if (mServiceCallbacks != null) {
+                    try {
+                        mServiceBinder.disconnect(mServiceCallbacks);
+                    } catch (RemoteException ex) {
+                        // We are disconnecting anyway. Log, just for posterity but it's not
+                        // a big problem.
+                        Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
+                    }
+                }
+                int state = mState;
+                forceCloseConnection();
+                // If the state was not CONNECT_STATE_DISCONNECTING, keep the state so that
+                // the operation came after disconnect() can be handled properly.
+                if (state != CONNECT_STATE_DISCONNECTING) {
+                    mState = state;
+                }
+                if (DBG) {
+                    Log.d(TAG, "disconnect...");
+                    dump();
+                }
+            }
+        });
+    }
+
+    /**
+     * Null out the variables and unbind from the service. This doesn't include
+     * calling disconnect on the service, because we only try to do that in the
+     * clean shutdown cases.
+     * <p>
+     * Everywhere that calls this EXCEPT for disconnect() should follow it with
+     * a call to mCallback.onConnectionFailed(). Disconnect doesn't do that callback
+     * for a clean shutdown, but everywhere else is a dirty shutdown and should
+     * notify the app.
+     * <p>
+     * Also, mState should be updated properly. Mostly it should be CONNECT_STATE_DIACONNECTED
+     * except for disconnect().
+     */
+    private void forceCloseConnection() {
+        if (mServiceConnection != null) {
+            try {
+                mContext.unbindService(mServiceConnection);
+            } catch (IllegalArgumentException e) {
+                if (DBG) {
+                    Log.d(TAG, "unbindService failed", e);
+                }
+            }
+        }
+        mState = CONNECT_STATE_DISCONNECTED;
+        mServiceConnection = null;
+        mServiceBinder = null;
+        mServiceCallbacks = null;
+        mRootId = null;
+        mMediaSessionToken = null;
+    }
+
+    /**
+     * Returns whether the browser is connected to the service.
+     */
+    public boolean isConnected() {
+        return mState == CONNECT_STATE_CONNECTED;
+    }
+
+    /**
+     * Gets the service component that the media browser is connected to.
+     */
+    public @NonNull ComponentName getServiceComponent() {
+        if (!isConnected()) {
+            throw new IllegalStateException("getServiceComponent() called while not connected"
+                    + " (state=" + mState + ")");
+        }
+        return mServiceComponent;
+    }
+
+    /**
+     * Gets the root id.
+     * <p>
+     * Note that the root id may become invalid or change when the
+     * browser is disconnected.
+     * </p>
+     *
+     * @throws IllegalStateException if not connected.
+     */
+    public @NonNull String getRoot() {
+        if (!isConnected()) {
+            throw new IllegalStateException("getRoot() called while not connected (state="
+                    + getStateLabel(mState) + ")");
+        }
+        return mRootId;
+    }
+
+    /**
+     * Gets any extras for the media service.
+     *
+     * @throws IllegalStateException if not connected.
+     */
+    public @Nullable Bundle getExtras() {
+        if (!isConnected()) {
+            throw new IllegalStateException("getExtras() called while not connected (state="
+                    + getStateLabel(mState) + ")");
+        }
+        return mExtras;
+    }
+
+    /**
+     * Gets the media session token associated with the media browser.
+     * <p>
+     * Note that the session token may become invalid or change when the
+     * browser is disconnected.
+     * </p>
+     *
+     * @return The session token for the browser, never null.
+     *
+     * @throws IllegalStateException if not connected.
+     */
+    public @NonNull MediaSession.Token getSessionToken() {
+        if (!isConnected()) {
+            throw new IllegalStateException("getSessionToken() called while not connected (state="
+                    + mState + ")");
+        }
+        return mMediaSessionToken;
+    }
+
+    /**
+     * Queries for information about the media items that are contained within
+     * the specified id and subscribes to receive updates when they change.
+     * <p>
+     * The list of subscriptions is maintained even when not connected and is
+     * restored after the reconnection. It is ok to subscribe while not connected
+     * but the results will not be returned until the connection completes.
+     * </p>
+     * <p>
+     * If the id is already subscribed with a different callback then the new
+     * callback will replace the previous one and the child data will be
+     * reloaded.
+     * </p>
+     *
+     * @param parentId The id of the parent media item whose list of children
+     *            will be subscribed.
+     * @param callback The callback to receive the list of children.
+     */
+    public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
+        subscribeInternal(parentId, null, callback);
+    }
+
+    /**
+     * Queries with service-specific arguments for information about the media items
+     * that are contained within the specified id and subscribes to receive updates
+     * when they change.
+     * <p>
+     * The list of subscriptions is maintained even when not connected and is
+     * restored after the reconnection. It is ok to subscribe while not connected
+     * but the results will not be returned until the connection completes.
+     * </p>
+     * <p>
+     * If the id is already subscribed with a different callback then the new
+     * callback will replace the previous one and the child data will be
+     * reloaded.
+     * </p>
+     *
+     * @param parentId The id of the parent media item whose list of children
+     *            will be subscribed.
+     * @param options The bundle of service-specific arguments to send to the media
+     *            browser service. The contents of this bundle may affect the
+     *            information returned when browsing.
+     * @param callback The callback to receive the list of children.
+     */
+    public void subscribe(@NonNull String parentId, @NonNull Bundle options,
+            @NonNull SubscriptionCallback callback) {
+        if (options == null) {
+            throw new IllegalArgumentException("options cannot be null");
+        }
+        subscribeInternal(parentId, new Bundle(options), callback);
+    }
+
+    /**
+     * Unsubscribes for changes to the children of the specified media id.
+     * <p>
+     * The query callback will no longer be invoked for results associated with
+     * this id once this method returns.
+     * </p>
+     *
+     * @param parentId The id of the parent media item whose list of children
+     *            will be unsubscribed.
+     */
+    public void unsubscribe(@NonNull String parentId) {
+        unsubscribeInternal(parentId, null);
+    }
+
+    /**
+     * Unsubscribes for changes to the children of the specified media id through a callback.
+     * <p>
+     * The query callback will no longer be invoked for results associated with
+     * this id once this method returns.
+     * </p>
+     *
+     * @param parentId The id of the parent media item whose list of children
+     *            will be unsubscribed.
+     * @param callback A callback sent to the media browser service to subscribe.
+     */
+    public void unsubscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback cannot be null");
+        }
+        unsubscribeInternal(parentId, callback);
+    }
+
+    /**
+     * Retrieves a specific {@link MediaItem} from the connected service. Not
+     * all services may support this, so falling back to subscribing to the
+     * parent's id should be used when unavailable.
+     *
+     * @param mediaId The id of the item to retrieve.
+     * @param cb The callback to receive the result on.
+     */
+    public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
+        if (TextUtils.isEmpty(mediaId)) {
+            throw new IllegalArgumentException("mediaId cannot be empty.");
+        }
+        if (cb == null) {
+            throw new IllegalArgumentException("cb cannot be null.");
+        }
+        if (mState != CONNECT_STATE_CONNECTED) {
+            Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    cb.onError(mediaId);
+                }
+            });
+            return;
+        }
+        ResultReceiver receiver = new ResultReceiver(mHandler) {
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                if (!isConnected()) {
+                    return;
+                }
+                if (resultCode != 0 || resultData == null
+                        || !resultData.containsKey(MediaBrowserService.KEY_MEDIA_ITEM)) {
+                    cb.onError(mediaId);
+                    return;
+                }
+                Parcelable item = resultData.getParcelable(MediaBrowserService.KEY_MEDIA_ITEM);
+                if (item != null && !(item instanceof MediaItem)) {
+                    cb.onError(mediaId);
+                    return;
+                }
+                cb.onItemLoaded((MediaItem) item);
+            }
+        };
+        try {
+            mServiceBinder.getMediaItem(mediaId, receiver, mServiceCallbacks);
+        } catch (RemoteException e) {
+            Log.i(TAG, "Remote error getting media item.");
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    cb.onError(mediaId);
+                }
+            });
+        }
+    }
+
+    private void subscribeInternal(String parentId, Bundle options, SubscriptionCallback callback) {
+        // Check arguments.
+        if (TextUtils.isEmpty(parentId)) {
+            throw new IllegalArgumentException("parentId cannot be empty.");
+        }
+        if (callback == null) {
+            throw new IllegalArgumentException("callback cannot be null");
+        }
+        // Update or create the subscription.
+        Subscription sub = mSubscriptions.get(parentId);
+        if (sub == null) {
+            sub = new Subscription();
+            mSubscriptions.put(parentId, sub);
+        }
+        sub.putCallback(mContext, options, callback);
+
+        // If we are connected, tell the service that we are watching. If we aren't connected,
+        // the service will be told when we connect.
+        if (isConnected()) {
+            try {
+                if (options == null) {
+                    mServiceBinder.addSubscriptionDeprecated(parentId, mServiceCallbacks);
+                }
+                mServiceBinder.addSubscription(parentId, callback.mToken, options,
+                        mServiceCallbacks);
+            } catch (RemoteException ex) {
+                // Process is crashing. We will disconnect, and upon reconnect we will
+                // automatically reregister. So nothing to do here.
+                Log.d(TAG, "addSubscription failed with RemoteException parentId=" + parentId);
+            }
+        }
+    }
+
+    private void unsubscribeInternal(String parentId, SubscriptionCallback callback) {
+        // Check arguments.
+        if (TextUtils.isEmpty(parentId)) {
+            throw new IllegalArgumentException("parentId cannot be empty.");
+        }
+
+        Subscription sub = mSubscriptions.get(parentId);
+        if (sub == null) {
+            return;
+        }
+        // Tell the service if necessary.
+        try {
+            if (callback == null) {
+                if (isConnected()) {
+                    mServiceBinder.removeSubscriptionDeprecated(parentId, mServiceCallbacks);
+                    mServiceBinder.removeSubscription(parentId, null, mServiceCallbacks);
+                }
+            } else {
+                final List<SubscriptionCallback> callbacks = sub.getCallbacks();
+                final List<Bundle> optionsList = sub.getOptionsList();
+                for (int i = callbacks.size() - 1; i >= 0; --i) {
+                    if (callbacks.get(i) == callback) {
+                        if (isConnected()) {
+                            mServiceBinder.removeSubscription(
+                                    parentId, callback.mToken, mServiceCallbacks);
+                        }
+                        callbacks.remove(i);
+                        optionsList.remove(i);
+                    }
+                }
+            }
+        } catch (RemoteException ex) {
+            // Process is crashing. We will disconnect, and upon reconnect we will
+            // automatically reregister. So nothing to do here.
+            Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId);
+        }
+
+        if (sub.isEmpty() || callback == null) {
+            mSubscriptions.remove(parentId);
+        }
+    }
+
+    /**
+     * For debugging.
+     */
+    private static String getStateLabel(int state) {
+        switch (state) {
+            case CONNECT_STATE_DISCONNECTING:
+                return "CONNECT_STATE_DISCONNECTING";
+            case CONNECT_STATE_DISCONNECTED:
+                return "CONNECT_STATE_DISCONNECTED";
+            case CONNECT_STATE_CONNECTING:
+                return "CONNECT_STATE_CONNECTING";
+            case CONNECT_STATE_CONNECTED:
+                return "CONNECT_STATE_CONNECTED";
+            case CONNECT_STATE_SUSPENDED:
+                return "CONNECT_STATE_SUSPENDED";
+            default:
+                return "UNKNOWN/" + state;
+        }
+    }
+
+    private void onServiceConnected(final IMediaBrowserServiceCallbacks callback,
+            final String root, final MediaSession.Token session, final Bundle extra) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                // Check to make sure there hasn't been a disconnect or a different
+                // ServiceConnection.
+                if (!isCurrent(callback, "onConnect")) {
+                    return;
+                }
+                // Don't allow them to call us twice.
+                if (mState != CONNECT_STATE_CONNECTING) {
+                    Log.w(TAG, "onConnect from service while mState="
+                            + getStateLabel(mState) + "... ignoring");
+                    return;
+                }
+                mRootId = root;
+                mMediaSessionToken = session;
+                mExtras = extra;
+                mState = CONNECT_STATE_CONNECTED;
+
+                if (DBG) {
+                    Log.d(TAG, "ServiceCallbacks.onConnect...");
+                    dump();
+                }
+                mCallback.onConnected();
+
+                // we may receive some subscriptions before we are connected, so re-subscribe
+                // everything now
+                for (Entry<String, Subscription> subscriptionEntry : mSubscriptions.entrySet()) {
+                    String id = subscriptionEntry.getKey();
+                    Subscription sub = subscriptionEntry.getValue();
+                    List<SubscriptionCallback> callbackList = sub.getCallbacks();
+                    List<Bundle> optionsList = sub.getOptionsList();
+                    for (int i = 0; i < callbackList.size(); ++i) {
+                        try {
+                            mServiceBinder.addSubscription(id, callbackList.get(i).mToken,
+                                    optionsList.get(i), mServiceCallbacks);
+                        } catch (RemoteException ex) {
+                            // Process is crashing. We will disconnect, and upon reconnect we will
+                            // automatically reregister. So nothing to do here.
+                            Log.d(TAG, "addSubscription failed with RemoteException parentId="
+                                    + id);
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    private void onConnectionFailed(final IMediaBrowserServiceCallbacks callback) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                Log.e(TAG, "onConnectFailed for " + mServiceComponent);
+
+                // Check to make sure there hasn't been a disconnect or a different
+                // ServiceConnection.
+                if (!isCurrent(callback, "onConnectFailed")) {
+                    return;
+                }
+                // Don't allow them to call us twice.
+                if (mState != CONNECT_STATE_CONNECTING) {
+                    Log.w(TAG, "onConnect from service while mState="
+                            + getStateLabel(mState) + "... ignoring");
+                    return;
+                }
+
+                // Clean up
+                forceCloseConnection();
+
+                // Tell the app.
+                mCallback.onConnectionFailed();
+            }
+        });
+    }
+
+    private void onLoadChildren(final IMediaBrowserServiceCallbacks callback,
+            final String parentId, final MediaParceledListSlice list, final Bundle options) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                // Check that there hasn't been a disconnect or a different
+                // ServiceConnection.
+                if (!isCurrent(callback, "onLoadChildren")) {
+                    return;
+                }
+
+                if (DBG) {
+                    Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId);
+                }
+
+                // Check that the subscription is still subscribed.
+                final Subscription subscription = mSubscriptions.get(parentId);
+                if (subscription != null) {
+                    // Tell the app.
+                    SubscriptionCallback subscriptionCallback =
+                            subscription.getCallback(mContext, options);
+                    if (subscriptionCallback != null) {
+                        List<MediaItem> data = list == null ? null : list.getList();
+                        if (options == null) {
+                            if (data == null) {
+                                subscriptionCallback.onError(parentId);
+                            } else {
+                                subscriptionCallback.onChildrenLoaded(parentId, data);
+                            }
+                        } else {
+                            if (data == null) {
+                                subscriptionCallback.onError(parentId, options);
+                            } else {
+                                subscriptionCallback.onChildrenLoaded(parentId, data, options);
+                            }
+                        }
+                        return;
+                    }
+                }
+                if (DBG) {
+                    Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" + parentId);
+                }
+            }
+        });
+    }
+
+    /**
+     * Return true if {@code callback} is the current ServiceCallbacks. Also logs if it's not.
+     */
+    private boolean isCurrent(IMediaBrowserServiceCallbacks callback, String funcName) {
+        if (mServiceCallbacks != callback || mState == CONNECT_STATE_DISCONNECTING
+                || mState == CONNECT_STATE_DISCONNECTED) {
+            if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
+                Log.i(TAG, funcName + " for " + mServiceComponent + " with mServiceConnection="
+                        + mServiceCallbacks + " this=" + this);
+            }
+            return false;
+        }
+        return true;
+    }
+
+    private ServiceCallbacks getNewServiceCallbacks() {
+        return new ServiceCallbacks(this);
+    }
+
+    /**
+     * Log internal state.
+     * @hide
+     */
+    void dump() {
+        Log.d(TAG, "MediaBrowser...");
+        Log.d(TAG, "  mServiceComponent=" + mServiceComponent);
+        Log.d(TAG, "  mCallback=" + mCallback);
+        Log.d(TAG, "  mRootHints=" + mRootHints);
+        Log.d(TAG, "  mState=" + getStateLabel(mState));
+        Log.d(TAG, "  mServiceConnection=" + mServiceConnection);
+        Log.d(TAG, "  mServiceBinder=" + mServiceBinder);
+        Log.d(TAG, "  mServiceCallbacks=" + mServiceCallbacks);
+        Log.d(TAG, "  mRootId=" + mRootId);
+        Log.d(TAG, "  mMediaSessionToken=" + mMediaSessionToken);
+    }
+
+    /**
+     * A class with information on a single media item for use in browsing/searching media.
+     * MediaItems are application dependent so we cannot guarantee that they contain the
+     * right values.
+     */
+    public static class MediaItem implements Parcelable {
+        private final int mFlags;
+        private final MediaDescription mDescription;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(flag = true, value = { FLAG_BROWSABLE, FLAG_PLAYABLE })
+        public @interface Flags { }
+
+        /**
+         * Flag: Indicates that the item has children of its own.
+         */
+        public static final int FLAG_BROWSABLE = 1 << 0;
+
+        /**
+         * Flag: Indicates that the item is playable.
+         * <p>
+         * The id of this item may be passed to
+         * {@link MediaController.TransportControls#playFromMediaId(String, Bundle)}
+         * to start playing it.
+         * </p>
+         */
+        public static final int FLAG_PLAYABLE = 1 << 1;
+
+        /**
+         * Create a new MediaItem for use in browsing media.
+         * @param description The description of the media, which must include a
+         *            media id.
+         * @param flags The flags for this item.
+         */
+        public MediaItem(@NonNull MediaDescription description, @Flags int flags) {
+            if (description == null) {
+                throw new IllegalArgumentException("description cannot be null");
+            }
+            if (TextUtils.isEmpty(description.getMediaId())) {
+                throw new IllegalArgumentException("description must have a non-empty media id");
+            }
+            mFlags = flags;
+            mDescription = description;
+        }
+
+        /**
+         * Private constructor.
+         */
+        private MediaItem(Parcel in) {
+            mFlags = in.readInt();
+            mDescription = MediaDescription.CREATOR.createFromParcel(in);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeInt(mFlags);
+            mDescription.writeToParcel(out, flags);
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("MediaItem{");
+            sb.append("mFlags=").append(mFlags);
+            sb.append(", mDescription=").append(mDescription);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        public static final Parcelable.Creator<MediaItem> CREATOR =
+                new Parcelable.Creator<MediaItem>() {
+                    @Override
+                    public MediaItem createFromParcel(Parcel in) {
+                        return new MediaItem(in);
+                    }
+
+                    @Override
+                    public MediaItem[] newArray(int size) {
+                        return new MediaItem[size];
+                    }
+                };
+
+        /**
+         * Gets the flags of the item.
+         */
+        public @Flags int getFlags() {
+            return mFlags;
+        }
+
+        /**
+         * Returns whether this item is browsable.
+         * @see #FLAG_BROWSABLE
+         */
+        public boolean isBrowsable() {
+            return (mFlags & FLAG_BROWSABLE) != 0;
+        }
+
+        /**
+         * Returns whether this item is playable.
+         * @see #FLAG_PLAYABLE
+         */
+        public boolean isPlayable() {
+            return (mFlags & FLAG_PLAYABLE) != 0;
+        }
+
+        /**
+         * Returns the description of the media.
+         */
+        public @NonNull MediaDescription getDescription() {
+            return mDescription;
+        }
+
+        /**
+         * Returns the media id in the {@link MediaDescription} for this item.
+         * @see android.media.MediaMetadata#METADATA_KEY_MEDIA_ID
+         */
+        public @Nullable String getMediaId() {
+            return mDescription.getMediaId();
+        }
+    }
+
+    /**
+     * Callbacks for connection related events.
+     */
+    public static class ConnectionCallback {
+        /**
+         * Invoked after {@link MediaBrowser#connect()} when the request has successfully completed.
+         */
+        public void onConnected() {
+        }
+
+        /**
+         * Invoked when the client is disconnected from the media browser.
+         */
+        public void onConnectionSuspended() {
+        }
+
+        /**
+         * Invoked when the connection to the media browser failed.
+         */
+        public void onConnectionFailed() {
+        }
+    }
+
+    /**
+     * Callbacks for subscription related events.
+     */
+    public abstract static class SubscriptionCallback {
+        Binder mToken;
+
+        public SubscriptionCallback() {
+            mToken = new Binder();
+        }
+
+        /**
+         * Called when the list of children is loaded or updated.
+         *
+         * @param parentId The media id of the parent media item.
+         * @param children The children which were loaded.
+         */
+        public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children) {
+        }
+
+        /**
+         * Called when the list of children is loaded or updated.
+         *
+         * @param parentId The media id of the parent media item.
+         * @param children The children which were loaded.
+         * @param options The bundle of service-specific arguments sent to the media
+         *            browser service. The contents of this bundle may affect the
+         *            information returned when browsing.
+         */
+        public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children,
+                @NonNull Bundle options) {
+        }
+
+        /**
+         * Called when the id doesn't exist or other errors in subscribing.
+         * <p>
+         * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
+         * called, because some errors may heal themselves.
+         * </p>
+         *
+         * @param parentId The media id of the parent media item whose children could
+         *            not be loaded.
+         */
+        public void onError(@NonNull String parentId) {
+        }
+
+        /**
+         * Called when the id doesn't exist or other errors in subscribing.
+         * <p>
+         * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
+         * called, because some errors may heal themselves.
+         * </p>
+         *
+         * @param parentId The media id of the parent media item whose children could
+         *            not be loaded.
+         * @param options The bundle of service-specific arguments sent to the media
+         *            browser service.
+         */
+        public void onError(@NonNull String parentId, @NonNull Bundle options) {
+        }
+    }
+
+    /**
+     * Callback for receiving the result of {@link #getItem}.
+     */
+    public abstract static class ItemCallback {
+        /**
+         * Called when the item has been returned by the connected service.
+         *
+         * @param item The item that was returned or null if it doesn't exist.
+         */
+        public void onItemLoaded(MediaItem item) {
+        }
+
+        /**
+         * Called there was an error retrieving it or the connected service doesn't support
+         * {@link #getItem}.
+         *
+         * @param mediaId The media id of the media item which could not be loaded.
+         */
+        public void onError(@NonNull String mediaId) {
+        }
+    }
+
+    /**
+     * ServiceConnection to the other app.
+     */
+    private class MediaServiceConnection implements ServiceConnection {
+        @Override
+        public void onServiceConnected(final ComponentName name, final IBinder binder) {
+            postOrRun(new Runnable() {
+                @Override
+                public void run() {
+                    if (DBG) {
+                        Log.d(TAG, "MediaServiceConnection.onServiceConnected name=" + name
+                                + " binder=" + binder);
+                        dump();
+                    }
+
+                    // Make sure we are still the current connection, and that they haven't called
+                    // disconnect().
+                    if (!isCurrent("onServiceConnected")) {
+                        return;
+                    }
+
+                    // Save their binder
+                    mServiceBinder = IMediaBrowserService.Stub.asInterface(binder);
+
+                    // We make a new mServiceCallbacks each time we connect so that we can drop
+                    // responses from previous connections.
+                    mServiceCallbacks = getNewServiceCallbacks();
+                    mState = CONNECT_STATE_CONNECTING;
+
+                    // Call connect, which is async. When we get a response from that we will
+                    // say that we're connected.
+                    try {
+                        if (DBG) {
+                            Log.d(TAG, "ServiceCallbacks.onConnect...");
+                            dump();
+                        }
+                        mServiceBinder.connect(mContext.getPackageName(), mRootHints,
+                                mServiceCallbacks);
+                    } catch (RemoteException ex) {
+                        // Connect failed, which isn't good. But the auto-reconnect on the service
+                        // will take over and we will come back. We will also get the
+                        // onServiceDisconnected, which has all the cleanup code. So let that do
+                        // it.
+                        Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
+                        if (DBG) {
+                            Log.d(TAG, "ServiceCallbacks.onConnect...");
+                            dump();
+                        }
+                    }
+                }
+            });
+        }
+
+        @Override
+        public void onServiceDisconnected(final ComponentName name) {
+            postOrRun(new Runnable() {
+                @Override
+                public void run() {
+                    if (DBG) {
+                        Log.d(TAG, "MediaServiceConnection.onServiceDisconnected name=" + name
+                                + " this=" + this + " mServiceConnection=" + mServiceConnection);
+                        dump();
+                    }
+
+                    // Make sure we are still the current connection, and that they haven't called
+                    // disconnect().
+                    if (!isCurrent("onServiceDisconnected")) {
+                        return;
+                    }
+
+                    // Clear out what we set in onServiceConnected
+                    mServiceBinder = null;
+                    mServiceCallbacks = null;
+
+                    // And tell the app that it's suspended.
+                    mState = CONNECT_STATE_SUSPENDED;
+                    mCallback.onConnectionSuspended();
+                }
+            });
+        }
+
+        private void postOrRun(Runnable r) {
+            if (Thread.currentThread() == mHandler.getLooper().getThread()) {
+                r.run();
+            } else {
+                mHandler.post(r);
+            }
+        }
+
+        /**
+         * Return true if this is the current ServiceConnection. Also logs if it's not.
+         */
+        private boolean isCurrent(String funcName) {
+            if (mServiceConnection != this || mState == CONNECT_STATE_DISCONNECTING
+                    || mState == CONNECT_STATE_DISCONNECTED) {
+                if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
+                    // Check mState, because otherwise this log is noisy.
+                    Log.i(TAG, funcName + " for " + mServiceComponent + " with mServiceConnection="
+                            + mServiceConnection + " this=" + this);
+                }
+                return false;
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Callbacks from the service.
+     */
+    private static class ServiceCallbacks extends IMediaBrowserServiceCallbacks.Stub {
+        private WeakReference<MediaBrowser> mMediaBrowser;
+
+        ServiceCallbacks(MediaBrowser mediaBrowser) {
+            mMediaBrowser = new WeakReference<MediaBrowser>(mediaBrowser);
+        }
+
+        /**
+         * The other side has acknowledged our connection. The parameters to this function
+         * are the initial data as requested.
+         */
+        @Override
+        public void onConnect(String root, MediaSession.Token session,
+                final Bundle extras) {
+            MediaBrowser mediaBrowser = mMediaBrowser.get();
+            if (mediaBrowser != null) {
+                mediaBrowser.onServiceConnected(this, root, session, extras);
+            }
+        }
+
+        /**
+         * The other side does not like us. Tell the app via onConnectionFailed.
+         */
+        @Override
+        public void onConnectFailed() {
+            MediaBrowser mediaBrowser = mMediaBrowser.get();
+            if (mediaBrowser != null) {
+                mediaBrowser.onConnectionFailed(this);
+            }
+        }
+
+        @Override
+        public void onLoadChildren(String parentId, MediaParceledListSlice list) {
+            onLoadChildrenWithOptions(parentId, list, null);
+        }
+
+        @Override
+        public void onLoadChildrenWithOptions(String parentId, MediaParceledListSlice list,
+                final Bundle options) {
+            MediaBrowser mediaBrowser = mMediaBrowser.get();
+            if (mediaBrowser != null) {
+                mediaBrowser.onLoadChildren(this, parentId, list, options);
+            }
+        }
+    }
+
+    private static class Subscription {
+        private final List<SubscriptionCallback> mCallbacks;
+        private final List<Bundle> mOptionsList;
+
+        Subscription() {
+            mCallbacks = new ArrayList<>();
+            mOptionsList = new ArrayList<>();
+        }
+
+        public boolean isEmpty() {
+            return mCallbacks.isEmpty();
+        }
+
+        public List<Bundle> getOptionsList() {
+            return mOptionsList;
+        }
+
+        public List<SubscriptionCallback> getCallbacks() {
+            return mCallbacks;
+        }
+
+        public SubscriptionCallback getCallback(Context context, Bundle options) {
+            if (options != null) {
+                options.setClassLoader(context.getClassLoader());
+            }
+            for (int i = 0; i < mOptionsList.size(); ++i) {
+                if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
+                    return mCallbacks.get(i);
+                }
+            }
+            return null;
+        }
+
+        public void putCallback(Context context, Bundle options, SubscriptionCallback callback) {
+            if (options != null) {
+                options.setClassLoader(context.getClassLoader());
+            }
+            for (int i = 0; i < mOptionsList.size(); ++i) {
+                if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
+                    mCallbacks.set(i, callback);
+                    return;
+                }
+            }
+            mCallbacks.add(callback);
+            mOptionsList.add(options);
+        }
+    }
+}
diff --git a/media/apex/java/android/media/browse/MediaBrowserUtils.java b/media/apex/java/android/media/browse/MediaBrowserUtils.java
new file mode 100644
index 0000000..19d9f00
--- /dev/null
+++ b/media/apex/java/android/media/browse/MediaBrowserUtils.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.browse;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+public class MediaBrowserUtils {
+    /**
+     * Compares whether two bundles are the same.
+     */
+    public static boolean areSameOptions(Bundle options1, Bundle options2) {
+        if (options1 == options2) {
+            return true;
+        } else if (options1 == null) {
+            return options2.getInt(MediaBrowser.EXTRA_PAGE, -1) == -1
+                    && options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1) == -1;
+        } else if (options2 == null) {
+            return options1.getInt(MediaBrowser.EXTRA_PAGE, -1) == -1
+                    && options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1) == -1;
+        } else {
+            return options1.getInt(MediaBrowser.EXTRA_PAGE, -1)
+                    == options2.getInt(MediaBrowser.EXTRA_PAGE, -1)
+                    && options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1)
+                    == options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
+        }
+    }
+
+    /**
+     * Returnes true if the page options has duplicated items.
+     */
+    public static boolean hasDuplicatedItems(Bundle options1, Bundle options2) {
+        int page1 = options1 == null ? -1 : options1.getInt(MediaBrowser.EXTRA_PAGE, -1);
+        int page2 = options2 == null ? -1 : options2.getInt(MediaBrowser.EXTRA_PAGE, -1);
+        int pageSize1 = options1 == null ? -1 : options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
+        int pageSize2 = options2 == null ? -1 : options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
+
+        int startIndex1, startIndex2, endIndex1, endIndex2;
+        if (page1 == -1 || pageSize1 == -1) {
+            startIndex1 = 0;
+            endIndex1 = Integer.MAX_VALUE;
+        } else {
+            startIndex1 = pageSize1 * page1;
+            endIndex1 = startIndex1 + pageSize1 - 1;
+        }
+
+        if (page2 == -1 || pageSize2 == -1) {
+            startIndex2 = 0;
+            endIndex2 = Integer.MAX_VALUE;
+        } else {
+            startIndex2 = pageSize2 * page2;
+            endIndex2 = startIndex2 + pageSize2 - 1;
+        }
+
+        if (startIndex1 <= startIndex2 && startIndex2 <= endIndex1) {
+            return true;
+        } else if (startIndex1 <= endIndex2 && endIndex2 <= endIndex1) {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/media/apex/java/android/media/session/ControllerCallbackLink.aidl b/media/apex/java/android/media/session/ControllerCallbackLink.aidl
new file mode 100644
index 0000000..8ee8c7d
--- /dev/null
+++ b/media/apex/java/android/media/session/ControllerCallbackLink.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.session;
+
+parcelable ControllerCallbackLink;
diff --git a/media/apex/java/android/media/session/ControllerCallbackLink.java b/media/apex/java/android/media/session/ControllerCallbackLink.java
new file mode 100644
index 0000000..adc14a5
--- /dev/null
+++ b/media/apex/java/android/media/session/ControllerCallbackLink.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.media.MediaMetadata;
+import android.media.MediaParceledListSlice;
+import android.media.session.MediaController.PlaybackInfo;
+import android.media.session.MediaSession.QueueItem;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.Process;
+import android.os.RemoteException;
+
+import java.util.List;
+
+/**
+ * Handles incoming commands to {@link MediaController.Callback}.
+ * @hide
+ */
+@SystemApi
+public final class ControllerCallbackLink implements Parcelable {
+    final Context mContext;
+    final CallbackStub mCallbackStub;
+    final ISessionControllerCallback mIControllerCallback;
+
+    /**
+     * Constructor for stub (Callee)
+     */
+    public ControllerCallbackLink(@NonNull Context context, @NonNull CallbackStub callbackStub) {
+        mContext = context;
+        mCallbackStub = callbackStub;
+        mIControllerCallback = new CallbackStubProxy();
+    }
+
+    /**
+     * Constructor for interface (Caller)
+     */
+    public ControllerCallbackLink(IBinder binder) {
+        mContext = null;
+        mCallbackStub = null;
+        mIControllerCallback = ISessionControllerCallback.Stub.asInterface(binder);
+    }
+
+    /**
+     * Notify controller that the connected session is destroyed.
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifySessionDestroyed() {
+        try {
+            mIControllerCallback.notifySessionDestroyed();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the connected session sends an event.
+     *
+     * @param event the name of the event
+     * @param extras the extras included with the event
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyEvent(@NonNull String event, @Nullable Bundle extras) {
+        try {
+            mIControllerCallback.notifyEvent(event, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the current playback state is changed.
+     *
+     * @param state the new playback state
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyPlaybackStateChanged(@Nullable PlaybackState state) {
+        try {
+            mIControllerCallback.notifyPlaybackStateChanged(state);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the current metadata is changed.
+     *
+     * @param metadata the new metadata
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyMetadataChanged(@Nullable MediaMetadata metadata) {
+        try {
+            mIControllerCallback.notifyMetadataChanged(metadata);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the current queue is changed.
+     *
+     * @param queue the new queue
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyQueueChanged(@Nullable List<QueueItem> queue) {
+        try {
+            mIControllerCallback.notifyQueueChanged(queue == null ? null :
+                    new MediaParceledListSlice(queue));
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the current queue title is changed.
+     *
+     * @param title the new queue title
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyQueueTitleChanged(@Nullable CharSequence title) {
+        try {
+            mIControllerCallback.notifyQueueTitleChanged(title);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the extras are changed.
+     *
+     * @param extras the new extras
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyExtrasChanged(@Nullable Bundle extras) {
+        try {
+            mIControllerCallback.notifyExtrasChanged(extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify controller that the playback info is changed.
+     *
+     * @param info the new playback info
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyVolumeInfoChanged(@NonNull PlaybackInfo info) {
+        try {
+            mIControllerCallback.notifyVolumeInfoChanged(info);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Gets the binder */
+    @NonNull
+    public IBinder getBinder() {
+        return mIControllerCallback.asBinder();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(mIControllerCallback.asBinder());
+    }
+
+    public static final Parcelable.Creator<ControllerCallbackLink> CREATOR =
+            new Parcelable.Creator<ControllerCallbackLink>() {
+        @Override
+        public ControllerCallbackLink createFromParcel(Parcel in) {
+            return new ControllerCallbackLink(in.readStrongBinder());
+        }
+
+        @Override
+        public ControllerCallbackLink[] newArray(int size) {
+            return new ControllerCallbackLink[size];
+        }
+    };
+
+    /**
+     * Class for Stub implementation
+     */
+    public abstract static class CallbackStub {
+        /** Stub method for ISessionControllerCallback.notifySessionDestroyed */
+        public void onSessionDestroyed() {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyEvent */
+        public void onEvent(@NonNull String event, @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyPlaybackStateChanged */
+        public void onPlaybackStateChanged(@Nullable PlaybackState state) {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyMetadataChanged */
+        public void onMetadataChanged(@Nullable MediaMetadata metadata) {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyQueueChanged */
+        public void onQueueChanged(@Nullable List<QueueItem> queue) {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyQueueTitleChanged */
+        public void onQueueTitleChanged(@Nullable CharSequence title) {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyExtrasChanged */
+        public void onExtrasChanged(@Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionControllerCallback.notifyVolumeInfoChanged */
+        public void onVolumeInfoChanged(@NonNull PlaybackInfo info) {
+        }
+    }
+
+    private class CallbackStubProxy extends ISessionControllerCallback.Stub {
+        @Override
+        public void notifyEvent(String event, Bundle extras) {
+            mCallbackStub.onEvent(event, extras);
+        }
+
+        @Override
+        public void notifySessionDestroyed() {
+            mCallbackStub.onSessionDestroyed();
+        }
+
+        @Override
+        public void notifyPlaybackStateChanged(PlaybackState state) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onPlaybackStateChanged(state);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyMetadataChanged(MediaMetadata metadata) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onMetadataChanged(metadata);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyQueueChanged(MediaParceledListSlice queue) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onQueueChanged(queue == null ? null : queue.getList());
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyQueueTitleChanged(CharSequence title) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onQueueTitleChanged(title);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyExtrasChanged(Bundle extras) {
+            mCallbackStub.onExtrasChanged(extras);
+        }
+
+        @Override
+        public void notifyVolumeInfoChanged(PlaybackInfo info) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onVolumeInfoChanged(info);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        private void ensureMediaControlPermission() {
+            // Check if it's system server or has MEDIA_CONTENT_CONTROL.
+            // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
+            // check here.
+            if (getCallingUid() == Process.SYSTEM_UID || mContext.checkCallingPermission(
+                    android.Manifest.permission.MEDIA_CONTENT_CONTROL)
+                    == PackageManager.PERMISSION_GRANTED) {
+                return;
+            }
+            throw new SecurityException("Must hold the MEDIA_CONTENT_CONTROL permission.");
+        }
+    }
+}
diff --git a/media/apex/java/android/media/session/ControllerLink.aidl b/media/apex/java/android/media/session/ControllerLink.aidl
new file mode 100644
index 0000000..532df59
--- /dev/null
+++ b/media/apex/java/android/media/session/ControllerLink.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+parcelable ControllerLink;
diff --git a/media/apex/java/android/media/session/ControllerLink.java b/media/apex/java/android/media/session/ControllerLink.java
new file mode 100644
index 0000000..937df20
--- /dev/null
+++ b/media/apex/java/android/media/session/ControllerLink.java
@@ -0,0 +1,986 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.PendingIntent;
+import android.media.MediaMetadata;
+import android.media.MediaParceledListSlice;
+import android.media.Rating;
+import android.media.session.MediaController.PlaybackInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.view.KeyEvent;
+
+import java.util.List;
+
+/**
+ * Handles incoming commands from {@link MediaController}.
+ * @hide
+ */
+@SystemApi
+public final class ControllerLink implements Parcelable {
+    public static final Parcelable.Creator<ControllerLink> CREATOR =
+            new Parcelable.Creator<ControllerLink>() {
+                @Override
+                public ControllerLink createFromParcel(Parcel in) {
+                    return new ControllerLink(in.readStrongBinder());
+                }
+
+                @Override
+                public ControllerLink[] newArray(int size) {
+                    return new ControllerLink[size];
+                }
+            };
+
+    final ControllerStub mControllerStub;
+    final ISessionController mISessionController;
+
+    /**
+     * Constructor for stub (Callee)
+     */
+    public ControllerLink(@NonNull ControllerStub controllerStub) {
+        mControllerStub = controllerStub;
+        mISessionController = new StubProxy();
+    }
+
+    /**
+     * Constructor for interface (Caller)
+     */
+    public ControllerLink(IBinder binder) {
+        mControllerStub = null;
+        mISessionController = ISessionController.Stub.asInterface(binder);
+    }
+
+    /**
+     * Tell system that a controller sends a command.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param command the name of the command
+     * @param args the arguments included with the command
+     * @param cb the result receiver for getting the result of the command
+     */
+    void sendCommand(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
+            @NonNull String command, @Nullable Bundle args, @Nullable ResultReceiver cb) {
+        try {
+            mISessionController.sendCommand(packageName, caller, command, args, cb);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller sends a media button event.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param asSystemService whether this event should be considered as from system service
+     * @param mediaButton the media button key event
+     */
+    boolean sendMediaButton(@NonNull String packageName,
+            @NonNull ControllerCallbackLink caller, boolean asSystemService,
+            @NonNull KeyEvent mediaButton) {
+        try {
+            return mISessionController.sendMediaButton(packageName, caller, asSystemService,
+                    mediaButton);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Registers a controller callback link to the system.
+     *
+     * @param packageName the package name of the controller
+     * @param cb the controller callback link to register
+     */
+    void registerCallback(@NonNull String packageName, @NonNull ControllerCallbackLink cb) {
+        try {
+            mISessionController.registerCallback(packageName, cb);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Unregisters a controller callback link from the system.
+     *
+     * @param cb the controller callback link to register
+     */
+    void unregisterCallback(@NonNull ControllerCallbackLink cb) {
+        try {
+            mISessionController.unregisterCallback(cb);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Gets the package name of the connected session.
+     */
+    @NonNull
+    String getPackageName() {
+        try {
+            return mISessionController.getPackageName();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Gets the tag of the connected session.
+     */
+    @NonNull
+    String getTag() {
+        try {
+            return mISessionController.getTag();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Gets the {@link PendingIntent} for launching UI of the connected session.
+     */
+    @Nullable
+    PendingIntent getLaunchPendingIntent() {
+        try {
+            return mISessionController.getLaunchPendingIntent();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Gets the flags of the connected session.
+     */
+    long getFlags() {
+        try {
+            return mISessionController.getFlags();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Gets the volume attributes of the connected session.
+     */
+    @NonNull
+    PlaybackInfo getVolumeAttributes() {
+        try {
+            return mISessionController.getVolumeAttributes();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests adjusting the volume.
+     *
+     * @param packageName the package name of the controller
+     * @param opPackageName the op package name of this request
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param asSystemService whether this event should be considered as from system service
+     * @param direction the direction to adjust the volume in
+     * @param flags the flags with this volume change request
+     */
+    void adjustVolume(@NonNull String packageName, @NonNull String opPackageName,
+            @NonNull ControllerCallbackLink caller, boolean asSystemService, int direction,
+            int flags) {
+        try {
+            mISessionController.adjustVolume(packageName, opPackageName, caller, asSystemService,
+                    direction, flags);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests setting the volume.
+     *
+     * @param packageName the package name of the controller
+     * @param opPackageName the op package name of this request
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param flags the flags with this volume change request
+     */
+    void setVolumeTo(@NonNull String packageName, @NonNull String opPackageName,
+            @NonNull ControllerCallbackLink caller, int value, int flags) {
+        try {
+            mISessionController.setVolumeTo(packageName, opPackageName, caller, value, flags);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests preparing media.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    void prepare(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionController.prepare(packageName, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests preparing media from given media ID.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param mediaId the ID of the media
+     * @param extras the extras included with this request.
+     */
+    void prepareFromMediaId(@NonNull String packageName,
+            @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+            @Nullable Bundle extras) {
+        try {
+            mISessionController.prepareFromMediaId(packageName, caller, mediaId, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests preparing media from given search query.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param query the search query
+     * @param extras the extras included with this request.
+     */
+    void prepareFromSearch(@NonNull String packageName,
+            @NonNull ControllerCallbackLink caller, @NonNull String query,
+            @Nullable Bundle extras) {
+        try {
+            mISessionController.prepareFromSearch(packageName, caller, query, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests preparing media from given uri.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param uri the uri of the media
+     * @param extras the extras included with this request.
+     */
+    void prepareFromUri(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
+            @NonNull Uri uri, @Nullable Bundle extras) {
+        try {
+            mISessionController.prepareFromUri(packageName, caller, uri, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests playing media.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    void play(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionController.play(packageName, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests playing media from given media ID.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param mediaId the ID of the media
+     * @param extras the extras included with this request.
+     */
+    void playFromMediaId(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
+            @NonNull String mediaId, @Nullable Bundle extras) {
+        try {
+            mISessionController.playFromMediaId(packageName, caller, mediaId, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests playing media from given search query.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param query the search query
+     * @param extras the extras included with this request.
+     */
+    void playFromSearch(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
+            @NonNull String query, @Nullable Bundle extras) {
+        try {
+            mISessionController.playFromSearch(packageName, caller, query, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests playing media from given uri.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param uri the uri of the media
+     * @param extras the extras included with this request.
+     */
+    void playFromUri(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
+            @NonNull Uri uri, @Nullable Bundle extras) {
+        try {
+            mISessionController.playFromUri(packageName, caller, uri, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests skipping to the queue item with given ID.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param id the queue id of the item
+     */
+    void skipToQueueItem(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
+            long id) {
+        try {
+            mISessionController.skipToQueueItem(packageName, caller, id);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests pausing media.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    void pause(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionController.pause(packageName, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests stopping media.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    void stop(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionController.stop(packageName, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests skipping to the next queue item.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    void next(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionController.next(packageName, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests skipping to the previous queue item.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    void previous(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionController.previous(packageName, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests fast-forwarding.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    void fastForward(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionController.fastForward(packageName, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests rewinding.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    void rewind(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionController.rewind(packageName, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests seeking to the specific position.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param pos the position to move to, in milliseconds
+     */
+    void seekTo(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
+            long pos) {
+        try {
+            mISessionController.seekTo(packageName, caller, pos);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller requests rating of the current media.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param rating the rating of the current media
+     */
+    void rate(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
+            @NonNull Rating rating) {
+        try {
+            mISessionController.rate(packageName, caller, rating);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that a controller sends a custom action.
+     *
+     * @param packageName the package name of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param action the name of the action
+     * @param args the arguments included with this action
+     */
+    void sendCustomAction(@NonNull String packageName,
+            @NonNull ControllerCallbackLink caller, @NonNull String action, @Nullable Bundle args) {
+        try {
+            mISessionController.sendCustomAction(packageName, caller, action, args);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Gets the current metadata of the connected session.
+     */
+    @Nullable
+    public MediaMetadata getMetadata() {
+        try {
+            return mISessionController.getMetadata();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Gets the current playback state of the connected session.
+     */
+    @Nullable
+    public PlaybackState getPlaybackState() {
+        try {
+            return mISessionController.getPlaybackState();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Gets the current queue of the connected session.
+     */
+    @Nullable
+    public List<MediaSession.QueueItem> getQueue() {
+        try {
+            MediaParceledListSlice queue = mISessionController.getQueue();
+            return queue == null ? null : queue.getList();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Gets the current queue title of the connected session.
+     */
+    @Nullable
+    public CharSequence getQueueTitle() {
+        try {
+            return mISessionController.getQueueTitle();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Gets the current extras of the connected session.
+     */
+    @Nullable
+    public Bundle getExtras() {
+        try {
+            return mISessionController.getExtras();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Gets the current rating type of the connected session.
+     */
+    public int getRatingType() {
+        try {
+            return mISessionController.getRatingType();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Gets the binder */
+    @NonNull
+    public IBinder getBinder() {
+        return mISessionController.asBinder();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(mISessionController.asBinder());
+    }
+
+    /**
+     * Class for Stub implementation
+     */
+    public abstract static class ControllerStub {
+        /** Stub method for ISessionController.sendCommand */
+        public void sendCommand(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
+                @NonNull String command, @Nullable Bundle args, @Nullable ResultReceiver cb) {
+        }
+
+        /** Stub method for ISessionController.sendMediaButton */
+        public boolean sendMediaButton(@NonNull String packageName,
+                @NonNull ControllerCallbackLink caller, boolean asSystemService,
+                @NonNull KeyEvent mediaButton) {
+            return false;
+        }
+
+        /** Stub method for ISessionController.registerCallback */
+        public void registerCallback(@NonNull String packageName,
+                @NonNull ControllerCallbackLink cb) {
+        }
+
+        /** Stub method for ISessionController.unregisterCallback */
+        public void unregisterCallback(@NonNull ControllerCallbackLink cb) {
+        }
+
+        /** Stub method for ISessionController.getPackageName */
+        @NonNull
+        public String getPackageName() {
+            return null;
+        }
+
+        /** Stub method for ISessionController.getTag */
+        @NonNull
+        public String getTag() {
+            return null;
+        }
+
+        /** Stub method for ISessionController.getLaunchPendingIntent */
+        @Nullable
+        public PendingIntent getLaunchPendingIntent() {
+            return null;
+        }
+
+        /** Stub method for ISessionController.getFlags */
+        public long getFlags() {
+            return 0;
+        }
+
+        /** Stub method for ISessionController.getVolumeAttributes */
+        @NonNull
+        public PlaybackInfo getVolumeAttributes() {
+            return null;
+        }
+
+        /** Stub method for ISessionController.adjustVolume */
+        public void adjustVolume(@NonNull String packageName, @NonNull String opPackageName,
+                @NonNull ControllerCallbackLink caller, boolean asSystemService, int direction,
+                int flags) {
+        }
+
+        /** Stub method for ISessionController.setVolumeTo */
+        public void setVolumeTo(@NonNull String packageName, @NonNull String opPackageName,
+                @NonNull ControllerCallbackLink caller, int value, int flags) {
+        }
+
+        /** Stub method for ISessionController.prepare */
+        public void prepare(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionController.prepareFromMediaId */
+        public void prepareFromMediaId(@NonNull String packageName,
+                @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+                @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionController.prepareFromSearch */
+        public void prepareFromSearch(@NonNull String packageName,
+                @NonNull ControllerCallbackLink caller, @NonNull String query,
+                @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionController.prepareFromUri */
+        public void prepareFromUri(@NonNull String packageName,
+                @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionController.play */
+        public void play(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionController.playFromMediaId */
+        public void playFromMediaId(@NonNull String packageName,
+                @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+                @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionController.playFromSearch */
+        public void playFromSearch(@NonNull String packageName,
+                @NonNull ControllerCallbackLink caller, @NonNull String query,
+                @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionController.playFromUri */
+        public void playFromUri(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
+                @NonNull Uri uri, @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionController.skipToQueueItem */
+        public void skipToQueueItem(@NonNull String packageName,
+                @NonNull ControllerCallbackLink caller, long id) {
+        }
+
+        /** Stub method for ISessionController.pause */
+        public void pause(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionController.stop */
+        public void stop(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionController.next */
+        public void next(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionController.previous */
+        public void previous(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionController.fastForward */
+        public void fastForward(@NonNull String packageName,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionController.rewind */
+        public void rewind(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionController.seekTo */
+        public void seekTo(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
+                long pos) {
+        }
+
+        /** Stub method for ISessionController.rate */
+        public void rate(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
+                @NonNull Rating rating) {
+        }
+
+        /** Stub method for ISessionController.sendCustomAction */
+        public void sendCustomAction(@NonNull String packageName,
+                @NonNull ControllerCallbackLink caller, @NonNull String action,
+                @Nullable Bundle args) {
+        }
+
+        /** Stub method for ISessionController.getMetadata */
+        @Nullable
+        public MediaMetadata getMetadata() {
+            return null;
+        }
+
+        /** Stub method for ISessionController.getPlaybackState */
+        @Nullable
+        public PlaybackState getPlaybackState() {
+            return null;
+        }
+
+        /** Stub method for ISessionController.getQueue */
+        @Nullable
+        public List<MediaSession.QueueItem> getQueue() {
+            return null;
+        }
+
+        /** Stub method for ISessionController.getQueueTitle */
+        @Nullable
+        public CharSequence getQueueTitle() {
+            return null;
+        }
+
+        /** Stub method for ISessionController.getExtras */
+        @Nullable
+        public Bundle getExtras() {
+            return null;
+        }
+
+        /** Stub method for ISessionController.getRatingType */
+        public int getRatingType() {
+            return Rating.RATING_NONE;
+        }
+    }
+
+    private class StubProxy extends ISessionController.Stub {
+        @Override
+        public void sendCommand(String packageName, ControllerCallbackLink caller,
+                String command, Bundle args, ResultReceiver cb) {
+            mControllerStub.sendCommand(packageName, caller, command, args, cb);
+        }
+
+        @Override
+        public boolean sendMediaButton(String packageName, ControllerCallbackLink caller,
+                boolean asSystemService, KeyEvent mediaButton) {
+            return mControllerStub.sendMediaButton(packageName, caller, asSystemService,
+                    mediaButton);
+        }
+
+        @Override
+        public void registerCallback(String packageName, ControllerCallbackLink cb) {
+            mControllerStub.registerCallback(packageName, cb);
+        }
+
+        @Override
+        public void unregisterCallback(ControllerCallbackLink cb) {
+            mControllerStub.unregisterCallback(cb);
+        }
+
+        @Override
+        public String getPackageName() {
+            return mControllerStub.getPackageName();
+        }
+
+        @Override
+        public String getTag() {
+            return mControllerStub.getTag();
+        }
+
+        @Override
+        public PendingIntent getLaunchPendingIntent() {
+            return mControllerStub.getLaunchPendingIntent();
+        }
+
+        @Override
+        public long getFlags() {
+            return mControllerStub.getFlags();
+        }
+
+        @Override
+        public PlaybackInfo getVolumeAttributes() {
+            return mControllerStub.getVolumeAttributes();
+        }
+
+        @Override
+        public void adjustVolume(String packageName, String opPackageName,
+                ControllerCallbackLink caller, boolean asSystemService, int direction,
+                int flags) {
+            mControllerStub.adjustVolume(packageName, opPackageName, caller, asSystemService,
+                    direction, flags);
+        }
+
+        @Override
+        public void setVolumeTo(String packageName, String opPackageName,
+                ControllerCallbackLink caller, int value, int flags) {
+            mControllerStub.setVolumeTo(packageName, opPackageName, caller, value, flags);
+        }
+
+        @Override
+        public void prepare(String packageName, ControllerCallbackLink caller) {
+            mControllerStub.prepare(packageName, caller);
+        }
+
+        @Override
+        public void prepareFromMediaId(String packageName, ControllerCallbackLink caller,
+                String mediaId, Bundle extras) {
+            mControllerStub.prepareFromMediaId(packageName, caller, mediaId, extras);
+        }
+
+        @Override
+        public void prepareFromSearch(String packageName, ControllerCallbackLink caller,
+                String query, Bundle extras) {
+            mControllerStub.prepareFromSearch(packageName, caller, query, extras);
+        }
+
+        @Override
+        public void prepareFromUri(String packageName, ControllerCallbackLink caller,
+                Uri uri, Bundle extras) {
+            mControllerStub.prepareFromUri(packageName, caller, uri, extras);
+        }
+
+        @Override
+        public void play(String packageName, ControllerCallbackLink caller) {
+            mControllerStub.play(packageName, caller);
+        }
+
+        @Override
+        public void playFromMediaId(String packageName, ControllerCallbackLink caller,
+                String mediaId, Bundle extras) {
+            mControllerStub.playFromMediaId(packageName, caller, mediaId, extras);
+        }
+
+        @Override
+        public void playFromSearch(String packageName, ControllerCallbackLink caller,
+                String query, Bundle extras) {
+            mControllerStub.playFromSearch(packageName, caller, query, extras);
+        }
+
+        @Override
+        public void playFromUri(String packageName, ControllerCallbackLink caller,
+                Uri uri, Bundle extras) {
+            mControllerStub.playFromUri(packageName, caller, uri, extras);
+        }
+
+        @Override
+        public void skipToQueueItem(String packageName, ControllerCallbackLink caller, long id) {
+            mControllerStub.skipToQueueItem(packageName, caller, id);
+        }
+
+        @Override
+        public void pause(String packageName, ControllerCallbackLink caller) {
+            mControllerStub.pause(packageName, caller);
+        }
+
+        @Override
+        public void stop(String packageName, ControllerCallbackLink caller) {
+            mControllerStub.stop(packageName, caller);
+        }
+
+        @Override
+        public void next(String packageName, ControllerCallbackLink caller) {
+            mControllerStub.next(packageName, caller);
+        }
+
+        @Override
+        public void previous(String packageName, ControllerCallbackLink caller) {
+            mControllerStub.previous(packageName, caller);
+        }
+
+        @Override
+        public void fastForward(String packageName, ControllerCallbackLink caller) {
+            mControllerStub.fastForward(packageName, caller);
+        }
+
+        @Override
+        public void rewind(String packageName, ControllerCallbackLink caller) {
+            mControllerStub.rewind(packageName, caller);
+        }
+
+        @Override
+        public void seekTo(String packageName, ControllerCallbackLink caller, long pos) {
+            mControllerStub.seekTo(packageName, caller, pos);
+        }
+
+        @Override
+        public void rate(String packageName, ControllerCallbackLink caller, Rating rating) {
+            mControllerStub.rate(packageName, caller, rating);
+        }
+
+        @Override
+        public void sendCustomAction(String packageName, ControllerCallbackLink caller,
+                String action, Bundle args) {
+            mControllerStub.sendCustomAction(packageName, caller, action, args);
+        }
+
+        @Override
+        public MediaMetadata getMetadata() {
+            return mControllerStub.getMetadata();
+        }
+
+        @Override
+        public PlaybackState getPlaybackState() {
+            return mControllerStub.getPlaybackState();
+        }
+
+        @Override
+        public MediaParceledListSlice getQueue() {
+            List<MediaSession.QueueItem> queue = mControllerStub.getQueue();
+            return queue == null ? null : new MediaParceledListSlice(queue);
+        }
+
+        @Override
+        public CharSequence getQueueTitle() {
+            return mControllerStub.getQueueTitle();
+        }
+
+        @Override
+        public Bundle getExtras() {
+            return mControllerStub.getExtras();
+        }
+
+        @Override
+        public int getRatingType() {
+            return mControllerStub.getRatingType();
+        }
+    }
+}
diff --git a/media/apex/java/android/media/session/ISession.aidl b/media/apex/java/android/media/session/ISession.aidl
new file mode 100644
index 0000000..9b1ad7b
--- /dev/null
+++ b/media/apex/java/android/media/session/ISession.aidl
@@ -0,0 +1,53 @@
+/* Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.app.PendingIntent;
+import android.media.AudioAttributes;
+import android.media.MediaMetadata;
+import android.media.MediaParceledListSlice;
+import android.media.session.ControllerLink;
+import android.media.session.PlaybackState;
+import android.media.session.MediaSession;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+
+/**
+ * Interface to a MediaSession in the system.
+ * @hide
+ */
+interface ISession {
+    void sendEvent(String event, in Bundle data);
+    ControllerLink getController();
+    void setFlags(int flags);
+    void setActive(boolean active);
+    void setMediaButtonReceiver(in PendingIntent mbr);
+    void setLaunchPendingIntent(in PendingIntent pi);
+    void destroySession();
+
+    // These commands are for the TransportPerformer
+    void setMetadata(in MediaMetadata metadata, long duration, String metadataDescription);
+    void setPlaybackState(in PlaybackState state);
+    void setQueue(in MediaParceledListSlice queue);
+    void setQueueTitle(CharSequence title);
+    void setExtras(in Bundle extras);
+    void setRatingType(int type);
+
+    // These commands relate to volume handling
+    void setPlaybackToLocal(in AudioAttributes attributes);
+    void setPlaybackToRemote(int control, int max);
+    void setCurrentVolume(int currentVolume);
+}
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/apex/java/android/media/session/ISessionCallback.aidl
similarity index 100%
rename from media/java/android/media/session/ISessionCallback.aidl
rename to media/apex/java/android/media/session/ISessionCallback.aidl
diff --git a/media/apex/java/android/media/session/ISessionController.aidl b/media/apex/java/android/media/session/ISessionController.aidl
new file mode 100644
index 0000000..a3439a1
--- /dev/null
+++ b/media/apex/java/android/media/session/ISessionController.aidl
@@ -0,0 +1,88 @@
+/* Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.media.MediaMetadata;
+import android.media.MediaParceledListSlice;
+import android.media.Rating;
+import android.media.session.ControllerCallbackLink;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.view.KeyEvent;
+
+import java.util.List;
+
+/**
+ * Interface to MediaSessionRecord in the system.
+ * @hide
+ */
+interface ISessionController {
+    void sendCommand(String packageName, in ControllerCallbackLink caller,
+            String command, in Bundle args, in ResultReceiver cb);
+    boolean sendMediaButton(String packageName, in ControllerCallbackLink caller,
+            boolean asSystemService, in KeyEvent mediaButton);
+    void registerCallback(String packageName, in ControllerCallbackLink cb);
+    void unregisterCallback(in ControllerCallbackLink cb);
+    String getPackageName();
+    String getTag();
+    PendingIntent getLaunchPendingIntent();
+    long getFlags();
+    MediaController.PlaybackInfo getVolumeAttributes();
+    void adjustVolume(String packageName, String opPackageName,
+            in ControllerCallbackLink caller, boolean asSystemService, int direction,
+            int flags);
+    void setVolumeTo(String packageName, String opPackageName, in ControllerCallbackLink caller,
+            int value, int flags);
+
+    // These commands are for the TransportControls
+    void prepare(String packageName, in ControllerCallbackLink caller);
+    void prepareFromMediaId(String packageName, in ControllerCallbackLink caller,
+            String mediaId, in Bundle extras);
+    void prepareFromSearch(String packageName, in ControllerCallbackLink caller,
+            String string, in Bundle extras);
+    void prepareFromUri(String packageName, in ControllerCallbackLink caller,
+            in Uri uri, in Bundle extras);
+    void play(String packageName, in ControllerCallbackLink caller);
+    void playFromMediaId(String packageName, in ControllerCallbackLink caller,
+            String mediaId, in Bundle extras);
+    void playFromSearch(String packageName, in ControllerCallbackLink caller,
+            String string, in Bundle extras);
+    void playFromUri(String packageName, in ControllerCallbackLink caller,
+            in Uri uri, in Bundle extras);
+    void skipToQueueItem(String packageName, in ControllerCallbackLink caller, long id);
+    void pause(String packageName, in ControllerCallbackLink caller);
+    void stop(String packageName, in ControllerCallbackLink caller);
+    void next(String packageName, in ControllerCallbackLink caller);
+    void previous(String packageName, in ControllerCallbackLink caller);
+    void fastForward(String packageName, in ControllerCallbackLink caller);
+    void rewind(String packageName, in ControllerCallbackLink caller);
+    void seekTo(String packageName, in ControllerCallbackLink caller, long pos);
+    void rate(String packageName, in ControllerCallbackLink caller, in Rating rating);
+    void sendCustomAction(String packageName, in ControllerCallbackLink caller,
+            String action, in Bundle args);
+    MediaMetadata getMetadata();
+    PlaybackState getPlaybackState();
+    MediaParceledListSlice getQueue();
+    CharSequence getQueueTitle();
+    Bundle getExtras();
+    int getRatingType();
+}
diff --git a/media/apex/java/android/media/session/ISessionControllerCallback.aidl b/media/apex/java/android/media/session/ISessionControllerCallback.aidl
new file mode 100644
index 0000000..56ae852
--- /dev/null
+++ b/media/apex/java/android/media/session/ISessionControllerCallback.aidl
@@ -0,0 +1,38 @@
+/* Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.media.MediaMetadata;
+import android.media.MediaParceledListSlice;
+import android.media.session.MediaController;
+import android.media.session.PlaybackState;
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface ISessionControllerCallback {
+    void notifyEvent(String event, in Bundle extras);
+    void notifySessionDestroyed();
+
+    // These callbacks are for the TransportController
+    void notifyPlaybackStateChanged(in PlaybackState state);
+    void notifyMetadataChanged(in MediaMetadata metadata);
+    void notifyQueueChanged(in MediaParceledListSlice queue);
+    void notifyQueueTitleChanged(CharSequence title);
+    void notifyExtrasChanged(in Bundle extras);
+    void notifyVolumeInfoChanged(in MediaController.PlaybackInfo info);
+}
diff --git a/media/apex/java/android/media/session/MediaController.aidl b/media/apex/java/android/media/session/MediaController.aidl
new file mode 100644
index 0000000..17167f4
--- /dev/null
+++ b/media/apex/java/android/media/session/MediaController.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.media.session;
+
+parcelable MediaController.PlaybackInfo;
diff --git a/media/apex/java/android/media/session/MediaController.java b/media/apex/java/android/media/session/MediaController.java
new file mode 100644
index 0000000..d43acf4
--- /dev/null
+++ b/media/apex/java/android/media/session/MediaController.java
@@ -0,0 +1,1245 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.MediaMetadata;
+import android.media.Rating;
+import android.media.VolumeProvider;
+import android.media.session.MediaSession.QueueItem;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ResultReceiver;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Allows an app to interact with an ongoing media session. Media buttons and
+ * other commands can be sent to the session. A callback may be registered to
+ * receive updates from the session, such as metadata and play state changes.
+ * <p>
+ * A MediaController can be created through {@link MediaSessionManager} if you
+ * hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or are an
+ * enabled notification listener or by getting a {@link MediaSession.Token}
+ * directly from the session owner.
+ * <p>
+ * MediaController objects are thread-safe.
+ */
+public final class MediaController {
+    private static final String TAG = "MediaController";
+
+    private static final int MSG_EVENT = 1;
+    private static final int MSG_UPDATE_PLAYBACK_STATE = 2;
+    private static final int MSG_UPDATE_METADATA = 3;
+    private static final int MSG_UPDATE_VOLUME = 4;
+    private static final int MSG_UPDATE_QUEUE = 5;
+    private static final int MSG_UPDATE_QUEUE_TITLE = 6;
+    private static final int MSG_UPDATE_EXTRAS = 7;
+    private static final int MSG_DESTROYED = 8;
+
+    private final ControllerLink mSessionBinder;
+
+    private final MediaSession.Token mToken;
+    private final Context mContext;
+    private final ControllerCallbackLink mCbStub;
+    private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>();
+    private final Object mLock = new Object();
+
+    private boolean mCbRegistered = false;
+    private String mPackageName;
+    private String mTag;
+
+    private final TransportControls mTransportControls;
+
+    /**
+     * Call for creating a MediaController directly from a controller link. Should only
+     * be used by framework code.
+     * @hide
+     */
+    public MediaController(Context context, ControllerLink sessionBinder) {
+        if (sessionBinder == null) {
+            throw new IllegalArgumentException("Session token cannot be null");
+        }
+        if (context == null) {
+            throw new IllegalArgumentException("Context cannot be null");
+        }
+        mSessionBinder = sessionBinder;
+        mTransportControls = new TransportControls();
+        mToken = new MediaSession.Token(sessionBinder);
+        mContext = context;
+        mCbStub = new ControllerCallbackLink(context, new CallbackStub(this));
+    }
+
+    /**
+     * Call for creating a MediaController directly from a binder. Should only
+     * be used by framework code.
+     * @hide
+     * TODO: remove this constructor
+     */
+    public MediaController(Context context, ISessionController sessionBinder) {
+        this(context, new ControllerLink(sessionBinder.asBinder()));
+    }
+
+    /**
+     * Create a new MediaController from a session's token.
+     *
+     * @param context The caller's context.
+     * @param token The token for the session.
+     */
+    public MediaController(@NonNull Context context, @NonNull MediaSession.Token token) {
+        this(context, token.getControllerLink());
+    }
+
+    /**
+     * Get a {@link TransportControls} instance to send transport actions to
+     * the associated session.
+     *
+     * @return A transport controls instance.
+     */
+    public @NonNull TransportControls getTransportControls() {
+        return mTransportControls;
+    }
+
+    /**
+     * Send the specified media button event to the session. Only media keys can
+     * be sent by this method, other keys will be ignored.
+     *
+     * @param keyEvent The media button event to dispatch.
+     * @return true if the event was sent to the session, false otherwise.
+     */
+    public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) {
+        return dispatchMediaButtonEventInternal(false, keyEvent);
+    }
+
+    /**
+     * Dispatches the media button event as system service to the session.
+     * <p>
+     * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
+     * foreground activity didn't consume the key from the hardware devices.
+     *
+     * @param keyEvent media key event
+     * @return {@code true} if the event was sent to the session, {@code false} otherwise
+     * @hide
+     */
+    public boolean dispatchMediaButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
+        return dispatchMediaButtonEventInternal(true, keyEvent);
+    }
+
+    private boolean dispatchMediaButtonEventInternal(boolean asSystemService,
+            @NonNull KeyEvent keyEvent) {
+        if (keyEvent == null) {
+            throw new IllegalArgumentException("KeyEvent may not be null");
+        }
+        if (!KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
+            return false;
+        }
+        try {
+            return mSessionBinder.sendMediaButton(mContext.getPackageName(), mCbStub,
+                    asSystemService, keyEvent);
+        } catch (RuntimeException e) {
+            // System is dead. =(
+        }
+        return false;
+    }
+
+    /**
+     * Dispatches the volume button event as system service to the session.
+     * <p>
+     * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
+     * foreground activity didn't consume the key from the hardware devices.
+     *
+     * @param keyEvent volume key event
+     * @hide
+     */
+    public void dispatchVolumeButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
+        switch (keyEvent.getAction()) {
+            case KeyEvent.ACTION_DOWN: {
+                int direction = 0;
+                switch (keyEvent.getKeyCode()) {
+                    case KeyEvent.KEYCODE_VOLUME_UP:
+                        direction = AudioManager.ADJUST_RAISE;
+                        break;
+                    case KeyEvent.KEYCODE_VOLUME_DOWN:
+                        direction = AudioManager.ADJUST_LOWER;
+                        break;
+                    case KeyEvent.KEYCODE_VOLUME_MUTE:
+                        direction = AudioManager.ADJUST_TOGGLE_MUTE;
+                        break;
+                }
+                try {
+                    // Note: Need both package name and OP package name. Package name is used for
+                    //       RemoteUserInfo, and OP package name is used for AudioService's internal
+                    //       AppOpsManager usages.
+                    mSessionBinder.adjustVolume(mContext.getPackageName(),
+                            mContext.getOpPackageName(), mCbStub, true, direction,
+                            AudioManager.FLAG_SHOW_UI);
+                } catch (RuntimeException e) {
+                    Log.wtf(TAG, "Error calling adjustVolumeBy", e);
+                }
+                break;
+            }
+
+            case KeyEvent.ACTION_UP: {
+                final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
+                        | AudioManager.FLAG_FROM_KEY;
+                try {
+                    // Note: Need both package name and OP package name. Package name is used for
+                    //       RemoteUserInfo, and OP package name is used for AudioService's internal
+                    //       AppOpsManager usages.
+                    mSessionBinder.adjustVolume(mContext.getPackageName(),
+                            mContext.getOpPackageName(), mCbStub, true, 0, flags);
+                } catch (RuntimeException e) {
+                    Log.wtf(TAG, "Error calling adjustVolumeBy", e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Get the current playback state for this session.
+     *
+     * @return The current PlaybackState or null
+     */
+    public @Nullable PlaybackState getPlaybackState() {
+        try {
+            return mSessionBinder.getPlaybackState();
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Error calling getPlaybackState.", e);
+            return null;
+        }
+    }
+
+    /**
+     * Get the current metadata for this session.
+     *
+     * @return The current MediaMetadata or null.
+     */
+    public @Nullable MediaMetadata getMetadata() {
+        try {
+            return mSessionBinder.getMetadata();
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Error calling getMetadata.", e);
+            return null;
+        }
+    }
+
+    /**
+     * Get the current play queue for this session if one is set. If you only
+     * care about the current item {@link #getMetadata()} should be used.
+     *
+     * @return The current play queue or null.
+     */
+    public @Nullable List<MediaSession.QueueItem> getQueue() {
+        try {
+            return mSessionBinder.getQueue();
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Error calling getQueue.", e);
+        }
+        return null;
+    }
+
+    /**
+     * Get the queue title for this session.
+     */
+    public @Nullable CharSequence getQueueTitle() {
+        try {
+            return mSessionBinder.getQueueTitle();
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Error calling getQueueTitle", e);
+        }
+        return null;
+    }
+
+    /**
+     * Get the extras for this session.
+     */
+    public @Nullable Bundle getExtras() {
+        try {
+            return mSessionBinder.getExtras();
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Error calling getExtras", e);
+        }
+        return null;
+    }
+
+    /**
+     * Get the rating type supported by the session. One of:
+     * <ul>
+     * <li>{@link Rating#RATING_NONE}</li>
+     * <li>{@link Rating#RATING_HEART}</li>
+     * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
+     * <li>{@link Rating#RATING_3_STARS}</li>
+     * <li>{@link Rating#RATING_4_STARS}</li>
+     * <li>{@link Rating#RATING_5_STARS}</li>
+     * <li>{@link Rating#RATING_PERCENTAGE}</li>
+     * </ul>
+     *
+     * @return The supported rating type
+     */
+    public int getRatingType() {
+        try {
+            return mSessionBinder.getRatingType();
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Error calling getRatingType.", e);
+            return Rating.RATING_NONE;
+        }
+    }
+
+    /**
+     * Get the flags for this session. Flags are defined in {@link MediaSession}.
+     *
+     * @return The current set of flags for the session.
+     */
+    public long getFlags() {
+        try {
+            return mSessionBinder.getFlags();
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Error calling getFlags.", e);
+        }
+        return 0;
+    }
+
+    /**
+     * Get the current playback info for this session.
+     *
+     * @return The current playback info or null.
+     */
+    public @Nullable PlaybackInfo getPlaybackInfo() {
+        try {
+            return mSessionBinder.getVolumeAttributes();
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Error calling getAudioInfo.", e);
+        }
+        return null;
+    }
+
+    /**
+     * Get an intent for launching UI associated with this session if one
+     * exists.
+     *
+     * @return A {@link PendingIntent} to launch UI or null.
+     */
+    public @Nullable PendingIntent getSessionActivity() {
+        try {
+            return mSessionBinder.getLaunchPendingIntent();
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Error calling getPendingIntent.", e);
+        }
+        return null;
+    }
+
+    /**
+     * Get the token for the session this is connected to.
+     *
+     * @return The token for the connected session.
+     */
+    public @NonNull MediaSession.Token getSessionToken() {
+        return mToken;
+    }
+
+    /**
+     * Set the volume of the output this session is playing on. The command will
+     * be ignored if it does not support
+     * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
+     * {@link AudioManager} may be used to affect the handling.
+     *
+     * @see #getPlaybackInfo()
+     * @param value The value to set it to, between 0 and the reported max.
+     * @param flags Flags from {@link AudioManager} to include with the volume
+     *            request.
+     */
+    public void setVolumeTo(int value, int flags) {
+        try {
+            // Note: Need both package name and OP package name. Package name is used for
+            //       RemoteUserInfo, and OP package name is used for AudioService's internal
+            //       AppOpsManager usages.
+            mSessionBinder.setVolumeTo(mContext.getPackageName(), mContext.getOpPackageName(),
+                    mCbStub, value, flags);
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Error calling setVolumeTo.", e);
+        }
+    }
+
+    /**
+     * Adjust the volume of the output this session is playing on. The direction
+     * must be one of {@link AudioManager#ADJUST_LOWER},
+     * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}.
+     * The command will be ignored if the session does not support
+     * {@link VolumeProvider#VOLUME_CONTROL_RELATIVE} or
+     * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
+     * {@link AudioManager} may be used to affect the handling.
+     *
+     * @see #getPlaybackInfo()
+     * @param direction The direction to adjust the volume in.
+     * @param flags Any flags to pass with the command.
+     */
+    public void adjustVolume(int direction, int flags) {
+        try {
+            // Note: Need both package name and OP package name. Package name is used for
+            //       RemoteUserInfo, and OP package name is used for AudioService's internal
+            //       AppOpsManager usages.
+            mSessionBinder.adjustVolume(mContext.getPackageName(), mContext.getOpPackageName(),
+                    mCbStub, false, direction, flags);
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
+        }
+    }
+
+    /**
+     * Registers a callback to receive updates from the Session. Updates will be
+     * posted on the caller's thread.
+     *
+     * @param callback The callback object, must not be null.
+     */
+    public void registerCallback(@NonNull Callback callback) {
+        registerCallback(callback, null);
+    }
+
+    /**
+     * Registers a callback to receive updates from the session. Updates will be
+     * posted on the specified handler's thread.
+     *
+     * @param callback The callback object, must not be null.
+     * @param handler The handler to post updates on. If null the callers thread
+     *            will be used.
+     */
+    public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback must not be null");
+        }
+        if (handler == null) {
+            handler = new Handler();
+        }
+        synchronized (mLock) {
+            addCallbackLocked(callback, handler);
+        }
+    }
+
+    /**
+     * Unregisters the specified callback. If an update has already been posted
+     * you may still receive it after calling this method.
+     *
+     * @param callback The callback to remove.
+     */
+    public void unregisterCallback(@NonNull Callback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback must not be null");
+        }
+        synchronized (mLock) {
+            removeCallbackLocked(callback);
+        }
+    }
+
+    /**
+     * Sends a generic command to the session. It is up to the session creator
+     * to decide what commands and parameters they will support. As such,
+     * commands should only be sent to sessions that the controller owns.
+     *
+     * @param command The command to send
+     * @param args Any parameters to include with the command
+     * @param cb The callback to receive the result on
+     */
+    public void sendCommand(@NonNull String command, @Nullable Bundle args,
+            @Nullable ResultReceiver cb) {
+        if (TextUtils.isEmpty(command)) {
+            throw new IllegalArgumentException("command cannot be null or empty");
+        }
+        try {
+            mSessionBinder.sendCommand(mContext.getPackageName(), mCbStub, command, args, cb);
+        } catch (RuntimeException e) {
+            Log.d(TAG, "Dead object in sendCommand.", e);
+        }
+    }
+
+    /**
+     * Get the session owner's package name.
+     *
+     * @return The package name of of the session owner.
+     */
+    public String getPackageName() {
+        if (mPackageName == null) {
+            try {
+                mPackageName = mSessionBinder.getPackageName();
+            } catch (RuntimeException e) {
+                Log.d(TAG, "Dead object in getPackageName.", e);
+            }
+        }
+        return mPackageName;
+    }
+
+    /**
+     * Get the session's tag for debugging purposes.
+     *
+     * @return The session's tag.
+     * @hide
+     */
+    public String getTag() {
+        if (mTag == null) {
+            try {
+                mTag = mSessionBinder.getTag();
+            } catch (RuntimeException e) {
+                Log.d(TAG, "Dead object in getTag.", e);
+            }
+        }
+        return mTag;
+    }
+
+    /*
+     * @hide
+     */
+    ControllerLink getSessionBinder() {
+        return mSessionBinder;
+    }
+
+    /**
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public boolean controlsSameSession(MediaController other) {
+        if (other == null) return false;
+        return mSessionBinder.getBinder() == other.getSessionBinder().getBinder();
+    }
+
+    private void addCallbackLocked(Callback cb, Handler handler) {
+        if (getHandlerForCallbackLocked(cb) != null) {
+            Log.w(TAG, "Callback is already added, ignoring");
+            return;
+        }
+        MessageHandler holder = new MessageHandler(handler.getLooper(), cb);
+        mCallbacks.add(holder);
+        holder.mRegistered = true;
+
+        if (!mCbRegistered) {
+            try {
+                mSessionBinder.registerCallback(mContext.getPackageName(), mCbStub);
+                mCbRegistered = true;
+            } catch (RuntimeException e) {
+                Log.e(TAG, "Dead object in registerCallback", e);
+            }
+        }
+    }
+
+    private boolean removeCallbackLocked(Callback cb) {
+        boolean success = false;
+        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+            MessageHandler handler = mCallbacks.get(i);
+            if (cb == handler.mCallback) {
+                mCallbacks.remove(i);
+                success = true;
+                handler.mRegistered = false;
+            }
+        }
+        if (mCbRegistered && mCallbacks.size() == 0) {
+            try {
+                mSessionBinder.unregisterCallback(mCbStub);
+            } catch (RuntimeException e) {
+                Log.e(TAG, "Dead object in removeCallbackLocked");
+            }
+            mCbRegistered = false;
+        }
+        return success;
+    }
+
+    private MessageHandler getHandlerForCallbackLocked(Callback cb) {
+        if (cb == null) {
+            throw new IllegalArgumentException("Callback cannot be null");
+        }
+        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+            MessageHandler handler = mCallbacks.get(i);
+            if (cb == handler.mCallback) {
+                return handler;
+            }
+        }
+        return null;
+    }
+
+    private void postMessage(int what, Object obj, Bundle data) {
+        synchronized (mLock) {
+            for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+                mCallbacks.get(i).post(what, obj, data);
+            }
+        }
+    }
+
+    /**
+     * Callback for receiving updates from the session. A Callback can be
+     * registered using {@link #registerCallback}.
+     */
+    public abstract static class Callback {
+        /**
+         * Override to handle the session being destroyed. The session is no
+         * longer valid after this call and calls to it will be ignored.
+         */
+        public void onSessionDestroyed() {
+        }
+
+        /**
+         * Override to handle custom events sent by the session owner without a
+         * specified interface. Controllers should only handle these for
+         * sessions they own.
+         *
+         * @param event The event from the session.
+         * @param extras Optional parameters for the event, may be null.
+         */
+        public void onSessionEvent(@NonNull String event, @Nullable Bundle extras) {
+        }
+
+        /**
+         * Override to handle changes in playback state.
+         *
+         * @param state The new playback state of the session
+         */
+        public void onPlaybackStateChanged(@Nullable PlaybackState state) {
+        }
+
+        /**
+         * Override to handle changes to the current metadata.
+         *
+         * @param metadata The current metadata for the session or null if none.
+         * @see MediaMetadata
+         */
+        public void onMetadataChanged(@Nullable MediaMetadata metadata) {
+        }
+
+        /**
+         * Override to handle changes to items in the queue.
+         *
+         * @param queue A list of items in the current play queue. It should
+         *            include the currently playing item as well as previous and
+         *            upcoming items if applicable.
+         * @see MediaSession.QueueItem
+         */
+        public void onQueueChanged(@Nullable List<MediaSession.QueueItem> queue) {
+        }
+
+        /**
+         * Override to handle changes to the queue title.
+         *
+         * @param title The title that should be displayed along with the play queue such as
+         *              "Now Playing". May be null if there is no such title.
+         */
+        public void onQueueTitleChanged(@Nullable CharSequence title) {
+        }
+
+        /**
+         * Override to handle changes to the {@link MediaSession} extras.
+         *
+         * @param extras The extras that can include other information associated with the
+         *               {@link MediaSession}.
+         */
+        public void onExtrasChanged(@Nullable Bundle extras) {
+        }
+
+        /**
+         * Override to handle changes to the audio info.
+         *
+         * @param info The current audio info for this session.
+         */
+        public void onAudioInfoChanged(PlaybackInfo info) {
+        }
+    }
+
+    /**
+     * Interface for controlling media playback on a session. This allows an app
+     * to send media transport commands to the session.
+     */
+    public final class TransportControls {
+        private static final String TAG = "TransportController";
+
+        private TransportControls() {
+        }
+
+        /**
+         * Request that the player prepare its playback. In other words, other sessions can continue
+         * to play during the preparation of this session. This method can be used to speed up the
+         * start of the playback. Once the preparation is done, the session will change its playback
+         * state to {@link PlaybackState#STATE_PAUSED}. Afterwards, {@link #play} can be called to
+         * start playback.
+         */
+        public void prepare() {
+            try {
+                mSessionBinder.prepare(mContext.getPackageName(), mCbStub);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling prepare.", e);
+            }
+        }
+
+        /**
+         * Request that the player prepare playback for a specific media id. In other words, other
+         * sessions can continue to play during the preparation of this session. This method can be
+         * used to speed up the start of the playback. Once the preparation is done, the session
+         * will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
+         * {@link #play} can be called to start playback. If the preparation is not needed,
+         * {@link #playFromMediaId} can be directly called without this method.
+         *
+         * @param mediaId The id of the requested media.
+         * @param extras Optional extras that can include extra information about the media item
+         *               to be prepared.
+         */
+        public void prepareFromMediaId(String mediaId, Bundle extras) {
+            if (TextUtils.isEmpty(mediaId)) {
+                throw new IllegalArgumentException(
+                        "You must specify a non-empty String for prepareFromMediaId.");
+            }
+            try {
+                mSessionBinder.prepareFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
+                        extras);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
+            }
+        }
+
+        /**
+         * Request that the player prepare playback for a specific search query. An empty or null
+         * query should be treated as a request to prepare any music. In other words, other sessions
+         * can continue to play during the preparation of this session. This method can be used to
+         * speed up the start of the playback. Once the preparation is done, the session will
+         * change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
+         * {@link #play} can be called to start playback. If the preparation is not needed,
+         * {@link #playFromSearch} can be directly called without this method.
+         *
+         * @param query The search query.
+         * @param extras Optional extras that can include extra information
+         *               about the query.
+         */
+        public void prepareFromSearch(String query, Bundle extras) {
+            if (query == null) {
+                // This is to remain compatible with
+                // INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
+                query = "";
+            }
+            try {
+                mSessionBinder.prepareFromSearch(mContext.getPackageName(), mCbStub, query,
+                        extras);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
+            }
+        }
+
+        /**
+         * Request that the player prepare playback for a specific {@link Uri}. In other words,
+         * other sessions can continue to play during the preparation of this session. This method
+         * can be used to speed up the start of the playback. Once the preparation is done, the
+         * session will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
+         * {@link #play} can be called to start playback. If the preparation is not needed,
+         * {@link #playFromUri} can be directly called without this method.
+         *
+         * @param uri The URI of the requested media.
+         * @param extras Optional extras that can include extra information about the media item
+         *               to be prepared.
+         */
+        public void prepareFromUri(Uri uri, Bundle extras) {
+            if (uri == null || Uri.EMPTY.equals(uri)) {
+                throw new IllegalArgumentException(
+                        "You must specify a non-empty Uri for prepareFromUri.");
+            }
+            try {
+                mSessionBinder.prepareFromUri(mContext.getPackageName(), mCbStub, uri, extras);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
+            }
+        }
+
+        /**
+         * Request that the player start its playback at its current position.
+         */
+        public void play() {
+            try {
+                mSessionBinder.play(mContext.getPackageName(), mCbStub);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling play.", e);
+            }
+        }
+
+        /**
+         * Request that the player start playback for a specific media id.
+         *
+         * @param mediaId The id of the requested media.
+         * @param extras Optional extras that can include extra information about the media item
+         *               to be played.
+         */
+        public void playFromMediaId(String mediaId, Bundle extras) {
+            if (TextUtils.isEmpty(mediaId)) {
+                throw new IllegalArgumentException(
+                        "You must specify a non-empty String for playFromMediaId.");
+            }
+            try {
+                mSessionBinder.playFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
+                        extras);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
+            }
+        }
+
+        /**
+         * Request that the player start playback for a specific search query.
+         * An empty or null query should be treated as a request to play any
+         * music.
+         *
+         * @param query The search query.
+         * @param extras Optional extras that can include extra information
+         *               about the query.
+         */
+        public void playFromSearch(String query, Bundle extras) {
+            if (query == null) {
+                // This is to remain compatible with
+                // INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
+                query = "";
+            }
+            try {
+                mSessionBinder.playFromSearch(mContext.getPackageName(), mCbStub, query, extras);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling play(" + query + ").", e);
+            }
+        }
+
+        /**
+         * Request that the player start playback for a specific {@link Uri}.
+         *
+         * @param uri The URI of the requested media.
+         * @param extras Optional extras that can include extra information about the media item
+         *               to be played.
+         */
+        public void playFromUri(Uri uri, Bundle extras) {
+            if (uri == null || Uri.EMPTY.equals(uri)) {
+                throw new IllegalArgumentException(
+                        "You must specify a non-empty Uri for playFromUri.");
+            }
+            try {
+                mSessionBinder.playFromUri(mContext.getPackageName(), mCbStub, uri, extras);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling play(" + uri + ").", e);
+            }
+        }
+
+        /**
+         * Play an item with a specific id in the play queue. If you specify an
+         * id that is not in the play queue, the behavior is undefined.
+         */
+        public void skipToQueueItem(long id) {
+            try {
+                mSessionBinder.skipToQueueItem(mContext.getPackageName(), mCbStub, id);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
+            }
+        }
+
+        /**
+         * Request that the player pause its playback and stay at its current
+         * position.
+         */
+        public void pause() {
+            try {
+                mSessionBinder.pause(mContext.getPackageName(), mCbStub);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling pause.", e);
+            }
+        }
+
+        /**
+         * Request that the player stop its playback; it may clear its state in
+         * whatever way is appropriate.
+         */
+        public void stop() {
+            try {
+                mSessionBinder.stop(mContext.getPackageName(), mCbStub);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling stop.", e);
+            }
+        }
+
+        /**
+         * Move to a new location in the media stream.
+         *
+         * @param pos Position to move to, in milliseconds.
+         */
+        public void seekTo(long pos) {
+            try {
+                mSessionBinder.seekTo(mContext.getPackageName(), mCbStub, pos);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling seekTo.", e);
+            }
+        }
+
+        /**
+         * Start fast forwarding. If playback is already fast forwarding this
+         * may increase the rate.
+         */
+        public void fastForward() {
+            try {
+                mSessionBinder.fastForward(mContext.getPackageName(), mCbStub);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling fastForward.", e);
+            }
+        }
+
+        /**
+         * Skip to the next item.
+         */
+        public void skipToNext() {
+            try {
+                mSessionBinder.next(mContext.getPackageName(), mCbStub);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling next.", e);
+            }
+        }
+
+        /**
+         * Start rewinding. If playback is already rewinding this may increase
+         * the rate.
+         */
+        public void rewind() {
+            try {
+                mSessionBinder.rewind(mContext.getPackageName(), mCbStub);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling rewind.", e);
+            }
+        }
+
+        /**
+         * Skip to the previous item.
+         */
+        public void skipToPrevious() {
+            try {
+                mSessionBinder.previous(mContext.getPackageName(), mCbStub);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling previous.", e);
+            }
+        }
+
+        /**
+         * Rate the current content. This will cause the rating to be set for
+         * the current user. The Rating type must match the type returned by
+         * {@link #getRatingType()}.
+         *
+         * @param rating The rating to set for the current content
+         */
+        public void setRating(Rating rating) {
+            try {
+                mSessionBinder.rate(mContext.getPackageName(), mCbStub, rating);
+            } catch (RuntimeException e) {
+                Log.wtf(TAG, "Error calling rate.", e);
+            }
+        }
+
+        /**
+         * Send a custom action back for the {@link MediaSession} to perform.
+         *
+         * @param customAction The action to perform.
+         * @param args Optional arguments to supply to the {@link MediaSession} for this
+         *             custom action.
+         */
+        public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction,
+                @Nullable Bundle args) {
+            if (customAction == null) {
+                throw new IllegalArgumentException("CustomAction cannot be null.");
+            }
+            sendCustomAction(customAction.getAction(), args);
+        }
+
+        /**
+         * Send the id and args from a custom action back for the {@link MediaSession} to perform.
+         *
+         * @see #sendCustomAction(PlaybackState.CustomAction action, Bundle args)
+         * @param action The action identifier of the {@link PlaybackState.CustomAction} as
+         *               specified by the {@link MediaSession}.
+         * @param args Optional arguments to supply to the {@link MediaSession} for this
+         *             custom action.
+         */
+        public void sendCustomAction(@NonNull String action, @Nullable Bundle args) {
+            if (TextUtils.isEmpty(action)) {
+                throw new IllegalArgumentException("CustomAction cannot be null.");
+            }
+            try {
+                mSessionBinder.sendCustomAction(mContext.getPackageName(), mCbStub, action, args);
+            } catch (RuntimeException e) {
+                Log.d(TAG, "Dead object in sendCustomAction.", e);
+            }
+        }
+    }
+
+    /**
+     * Holds information about the current playback and how audio is handled for
+     * this session.
+     */
+    public static final class PlaybackInfo implements Parcelable {
+        /**
+         * The session uses local playback.
+         */
+        public static final int PLAYBACK_TYPE_LOCAL = 1;
+        /**
+         * The session uses remote playback.
+         */
+        public static final int PLAYBACK_TYPE_REMOTE = 2;
+
+        private final int mVolumeType;
+        private final int mVolumeControl;
+        private final int mMaxVolume;
+        private final int mCurrentVolume;
+        private final AudioAttributes mAudioAttrs;
+
+        /**
+         * @hide
+         */
+        public PlaybackInfo(int type, int control, int max, int current, AudioAttributes attrs) {
+            mVolumeType = type;
+            mVolumeControl = control;
+            mMaxVolume = max;
+            mCurrentVolume = current;
+            mAudioAttrs = attrs;
+        }
+
+        PlaybackInfo(Parcel in) {
+            mVolumeType = in.readInt();
+            mVolumeControl = in.readInt();
+            mMaxVolume = in.readInt();
+            mCurrentVolume = in.readInt();
+            mAudioAttrs = in.readParcelable(null);
+        }
+
+        /**
+         * Get the type of playback which affects volume handling. One of:
+         * <ul>
+         * <li>{@link #PLAYBACK_TYPE_LOCAL}</li>
+         * <li>{@link #PLAYBACK_TYPE_REMOTE}</li>
+         * </ul>
+         *
+         * @return The type of playback this session is using.
+         */
+        public int getPlaybackType() {
+            return mVolumeType;
+        }
+
+        /**
+         * Get the type of volume control that can be used. One of:
+         * <ul>
+         * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li>
+         * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li>
+         * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li>
+         * </ul>
+         *
+         * @return The type of volume control that may be used with this
+         *         session.
+         */
+        public int getVolumeControl() {
+            return mVolumeControl;
+        }
+
+        /**
+         * Get the maximum volume that may be set for this session.
+         *
+         * @return The maximum allowed volume where this session is playing.
+         */
+        public int getMaxVolume() {
+            return mMaxVolume;
+        }
+
+        /**
+         * Get the current volume for this session.
+         *
+         * @return The current volume where this session is playing.
+         */
+        public int getCurrentVolume() {
+            return mCurrentVolume;
+        }
+
+        /**
+         * Get the audio attributes for this session. The attributes will affect
+         * volume handling for the session. When the volume type is
+         * {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} these may be ignored by the
+         * remote volume handler.
+         *
+         * @return The attributes for this session.
+         */
+        public AudioAttributes getAudioAttributes() {
+            return mAudioAttrs;
+        }
+
+        @Override
+        public String toString() {
+            return "volumeType=" + mVolumeType + ", volumeControl=" + mVolumeControl
+                    + ", maxVolume=" + mMaxVolume + ", currentVolume=" + mCurrentVolume
+                    + ", audioAttrs=" + mAudioAttrs;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mVolumeType);
+            dest.writeInt(mVolumeControl);
+            dest.writeInt(mMaxVolume);
+            dest.writeInt(mCurrentVolume);
+            dest.writeParcelable(mAudioAttrs, flags);
+        }
+
+        public static final Parcelable.Creator<PlaybackInfo> CREATOR =
+                new Parcelable.Creator<PlaybackInfo>() {
+            @Override
+            public PlaybackInfo createFromParcel(Parcel in) {
+                return new PlaybackInfo(in);
+            }
+
+            @Override
+            public PlaybackInfo[] newArray(int size) {
+                return new PlaybackInfo[size];
+            }
+        };
+    }
+
+    private static final class CallbackStub extends ControllerCallbackLink.CallbackStub {
+        private final WeakReference<MediaController> mController;
+
+        CallbackStub(MediaController controller) {
+            mController = new WeakReference<MediaController>(controller);
+        }
+
+        @Override
+        public void onSessionDestroyed() {
+            MediaController controller = mController.get();
+            if (controller != null) {
+                controller.postMessage(MSG_DESTROYED, null, null);
+            }
+        }
+
+        @Override
+        public void onEvent(String event, Bundle extras) {
+            MediaController controller = mController.get();
+            if (controller != null) {
+                controller.postMessage(MSG_EVENT, event, extras);
+            }
+        }
+
+        @Override
+        public void onPlaybackStateChanged(PlaybackState state) {
+            MediaController controller = mController.get();
+            if (controller != null) {
+                controller.postMessage(MSG_UPDATE_PLAYBACK_STATE, state, null);
+            }
+        }
+
+        @Override
+        public void onMetadataChanged(MediaMetadata metadata) {
+            MediaController controller = mController.get();
+            if (controller != null) {
+                controller.postMessage(MSG_UPDATE_METADATA, metadata, null);
+            }
+        }
+
+        @Override
+        public void onQueueChanged(List<QueueItem> queue) {
+            MediaController controller = mController.get();
+            if (controller != null) {
+                controller.postMessage(MSG_UPDATE_QUEUE, queue, null);
+            }
+        }
+
+        @Override
+        public void onQueueTitleChanged(CharSequence title) {
+            MediaController controller = mController.get();
+            if (controller != null) {
+                controller.postMessage(MSG_UPDATE_QUEUE_TITLE, title, null);
+            }
+        }
+
+        @Override
+        public void onExtrasChanged(Bundle extras) {
+            MediaController controller = mController.get();
+            if (controller != null) {
+                controller.postMessage(MSG_UPDATE_EXTRAS, extras, null);
+            }
+        }
+
+        @Override
+        public void onVolumeInfoChanged(PlaybackInfo info) {
+            MediaController controller = mController.get();
+            if (controller != null) {
+                controller.postMessage(MSG_UPDATE_VOLUME, info, null);
+            }
+        }
+    }
+
+    private static final class MessageHandler extends Handler {
+        private final MediaController.Callback mCallback;
+        private boolean mRegistered = false;
+
+        MessageHandler(Looper looper, MediaController.Callback cb) {
+            super(looper);
+            mCallback = cb;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (!mRegistered) {
+                return;
+            }
+            switch (msg.what) {
+                case MSG_EVENT:
+                    mCallback.onSessionEvent((String) msg.obj, msg.getData());
+                    break;
+                case MSG_UPDATE_PLAYBACK_STATE:
+                    mCallback.onPlaybackStateChanged((PlaybackState) msg.obj);
+                    break;
+                case MSG_UPDATE_METADATA:
+                    mCallback.onMetadataChanged((MediaMetadata) msg.obj);
+                    break;
+                case MSG_UPDATE_QUEUE:
+                    mCallback.onQueueChanged((List<MediaSession.QueueItem>) msg.obj);
+                    break;
+                case MSG_UPDATE_QUEUE_TITLE:
+                    mCallback.onQueueTitleChanged((CharSequence) msg.obj);
+                    break;
+                case MSG_UPDATE_EXTRAS:
+                    mCallback.onExtrasChanged((Bundle) msg.obj);
+                    break;
+                case MSG_UPDATE_VOLUME:
+                    mCallback.onAudioInfoChanged((PlaybackInfo) msg.obj);
+                    break;
+                case MSG_DESTROYED:
+                    mCallback.onSessionDestroyed();
+                    break;
+            }
+        }
+
+        public void post(int what, Object obj, Bundle data) {
+            Message msg = obtainMessage(what, obj);
+            msg.setAsynchronous(true);
+            msg.setData(data);
+            msg.sendToTarget();
+        }
+    }
+
+}
diff --git a/media/apex/java/android/media/session/MediaSessionEngine.java b/media/apex/java/android/media/session/MediaSessionEngine.java
new file mode 100644
index 0000000..1f5fa5f
--- /dev/null
+++ b/media/apex/java/android/media/session/MediaSessionEngine.java
@@ -0,0 +1,1479 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.UnsupportedAppUsage;
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.media.AudioAttributes;
+import android.media.MediaDescription;
+import android.media.MediaMetadata;
+import android.media.Rating;
+import android.media.VolumeProvider;
+import android.media.session.MediaSessionManager.RemoteUserInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.ResultReceiver;
+import android.service.media.MediaBrowserService;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @hide
+ */
+@SystemApi
+public final class MediaSessionEngine implements AutoCloseable {
+    private static final String TAG = "MediaSession";
+
+    private final Object mLock = new Object();
+    private final int mMaxBitmapSize;
+
+    private final MediaSession.Token mSessionToken;
+    private final MediaController mController;
+    private final SessionLink mSessionLink;
+    private final SessionCallbackLink mCbLink;
+
+    // Do not change the name of mCallbackWrapper. Support lib accesses this by using reflection.
+    @UnsupportedAppUsage
+    private CallbackMessageHandler mCallbackHandler;
+    private VolumeProvider mVolumeProvider;
+    private PlaybackState mPlaybackState;
+
+    private boolean mActive = false;
+
+    /**
+     * Creates a new session. The session will automatically be registered with
+     * the system but will not be published until {@link #setActive(boolean)
+     * setActive(true)} is called. You must call {@link #close()} when
+     * finished with the session.
+     *
+     * @param context The context to use to create the session.
+     * @param sessionLink A session link for the binder of MediaSessionRecord
+     * @param cbStub A callback link that handles incoming command to {@link MediaSession.Callback}.
+     */
+    public MediaSessionEngine(@NonNull Context context, @NonNull SessionLink sessionLink,
+            @NonNull SessionCallbackLink cbLink, @NonNull CallbackStub cbStub, int maxBitmapSize) {
+        mSessionLink = sessionLink;
+        mCbLink = cbLink;
+        mMaxBitmapSize = maxBitmapSize;
+
+        cbStub.setSessionImpl(this);
+        mSessionToken = new MediaSession.Token(mSessionLink.getController());
+        mController = new MediaController(context, mSessionToken);
+    }
+
+    /**
+     * Set the callback to receive updates for the MediaSession. This includes
+     * media button events and transport controls. The caller's thread will be
+     * used to post updates.
+     * <p>
+     * Set the callback to null to stop receiving updates.
+     *
+     * @param callback The callback object
+     */
+    public void setCallback(@Nullable MediaSession.Callback callback) {
+        setCallback(callback, new Handler());
+    }
+
+    /**
+     * Set the callback to receive updates for the MediaSession. This includes
+     * media button events and transport controls.
+     * <p>
+     * Set the callback to null to stop receiving updates.
+     *
+     * @param callback The callback to receive updates on.
+     * @param handler The handler that events should be posted on.
+     */
+    public void setCallback(@Nullable MediaSession.Callback callback, @NonNull Handler handler) {
+        setCallbackInternal(callback == null ? null : new CallbackWrapper(callback), handler);
+    }
+
+    private void setCallbackInternal(CallbackWrapper callback, Handler handler) {
+        synchronized (mLock) {
+            if (mCallbackHandler != null) {
+                // We're updating the callback, clear the session from the old one.
+                mCallbackHandler.mCallbackWrapper.mSessionImpl = null;
+                mCallbackHandler.removeCallbacksAndMessages(null);
+            }
+            if (callback == null) {
+                mCallbackHandler = null;
+                return;
+            }
+            callback.mSessionImpl = this;
+            CallbackMessageHandler msgHandler = new CallbackMessageHandler(handler.getLooper(),
+                    callback);
+            mCallbackHandler = msgHandler;
+        }
+    }
+
+    /**
+     * Set an intent for launching UI for this Session. This can be used as a
+     * quick link to an ongoing media screen. The intent should be for an
+     * activity that may be started using {@link Activity#startActivity(Intent)}.
+     *
+     * @param pi The intent to launch to show UI for this Session.
+     */
+    public void setSessionActivity(@Nullable PendingIntent pi) {
+        try {
+            mSessionLink.setLaunchPendingIntent(pi);
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
+        }
+    }
+
+    /**
+     * Set a pending intent for your media button receiver to allow restarting
+     * playback after the session has been stopped. If your app is started in
+     * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
+     * the pending intent.
+     *
+     * @param mbr The {@link PendingIntent} to send the media button event to.
+     */
+    public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
+        try {
+            mSessionLink.setMediaButtonReceiver(mbr);
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
+        }
+    }
+
+    /**
+     * Set any flags for the session.
+     *
+     * @param flags The flags to set for this session.
+     */
+    public void setFlags(int flags) {
+        try {
+            mSessionLink.setFlags(flags);
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Failure in setFlags.", e);
+        }
+    }
+
+    /**
+     * Set the attributes for this session's audio. This will affect the
+     * system's volume handling for this session. If
+     * {@link #setPlaybackToRemote} was previously called it will stop receiving
+     * volume commands and the system will begin sending volume changes to the
+     * appropriate stream.
+     * <p>
+     * By default sessions use attributes for media.
+     *
+     * @param attributes The {@link AudioAttributes} for this session's audio.
+     */
+    public void setPlaybackToLocal(AudioAttributes attributes) {
+        if (attributes == null) {
+            throw new IllegalArgumentException("Attributes cannot be null for local playback.");
+        }
+        try {
+            mSessionLink.setPlaybackToLocal(attributes);
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Failure in setPlaybackToLocal.", e);
+        }
+    }
+
+    /**
+     * Configure this session to use remote volume handling. This must be called
+     * to receive volume button events, otherwise the system will adjust the
+     * appropriate stream volume for this session. If
+     * {@link #setPlaybackToLocal} was previously called the system will stop
+     * handling volume changes for this session and pass them to the volume
+     * provider instead.
+     *
+     * @param volumeProvider The provider that will handle volume changes. May
+     *            not be null.
+     */
+    public void setPlaybackToRemote(@NonNull VolumeProvider volumeProvider) {
+        if (volumeProvider == null) {
+            throw new IllegalArgumentException("volumeProvider may not be null!");
+        }
+        synchronized (mLock) {
+            mVolumeProvider = volumeProvider;
+        }
+        volumeProvider.setCallback(new VolumeProvider.Callback() {
+            @Override
+            public void onVolumeChanged(VolumeProvider volumeProvider) {
+                notifyRemoteVolumeChanged(volumeProvider);
+            }
+        });
+
+        try {
+            mSessionLink.setPlaybackToRemote(volumeProvider.getVolumeControl(),
+                    volumeProvider.getMaxVolume());
+            mSessionLink.setCurrentVolume(volumeProvider.getCurrentVolume());
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Failure in setPlaybackToRemote.", e);
+        }
+    }
+
+    /**
+     * Set if this session is currently active and ready to receive commands. If
+     * set to false your session's controller may not be discoverable. You must
+     * set the session to active before it can start receiving media button
+     * events or transport commands.
+     *
+     * @param active Whether this session is active or not.
+     */
+    public void setActive(boolean active) {
+        if (mActive == active) {
+            return;
+        }
+        try {
+            mSessionLink.setActive(active);
+            mActive = active;
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Failure in setActive.", e);
+        }
+    }
+
+    /**
+     * Get the current active state of this session.
+     *
+     * @return True if the session is active, false otherwise.
+     */
+    public boolean isActive() {
+        return mActive;
+    }
+
+    /**
+     * Send a proprietary event to all MediaControllers listening to this
+     * Session. It's up to the Controller/Session owner to determine the meaning
+     * of any events.
+     *
+     * @param event The name of the event to send
+     * @param extras Any extras included with the event
+     */
+    public void sendSessionEvent(@NonNull String event, @Nullable Bundle extras) {
+        if (TextUtils.isEmpty(event)) {
+            throw new IllegalArgumentException("event cannot be null or empty");
+        }
+        try {
+            mSessionLink.sendEvent(event, extras);
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Error sending event", e);
+        }
+    }
+
+    /**
+     * This must be called when an app has finished performing playback. If
+     * playback is expected to start again shortly the session can be left open,
+     * but it must be released if your activity or service is being destroyed.
+     */
+    public void close() {
+        try {
+            mSessionLink.destroySession();
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Error releasing session: ", e);
+        }
+    }
+
+    /**
+     * Retrieve a token object that can be used by apps to create a
+     * {@link MediaController} for interacting with this session. The owner of
+     * the session is responsible for deciding how to distribute these tokens.
+     *
+     * @return A token that can be used to create a MediaController for this
+     *         session
+     */
+    public @NonNull MediaSession.Token getSessionToken() {
+        return mSessionToken;
+    }
+
+    /**
+     * Get a controller for this session. This is a convenience method to avoid
+     * having to cache your own controller in process.
+     *
+     * @return A controller for this session.
+     */
+    public @NonNull MediaController getController() {
+        return mController;
+    }
+
+    /**
+     * Update the current playback state.
+     *
+     * @param state The current state of playback
+     */
+    public void setPlaybackState(@Nullable PlaybackState state) {
+        mPlaybackState = state;
+        try {
+            mSessionLink.setPlaybackState(state);
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
+        }
+    }
+
+    /**
+     * Update the current metadata. New metadata can be created using
+     * {@link android.media.MediaMetadata.Builder}. This operation may take time proportional to
+     * the size of the bitmap to replace large bitmaps with a scaled down copy.
+     *
+     * @param metadata The new metadata
+     * @see android.media.MediaMetadata.Builder#putBitmap
+     */
+    public void setMetadata(@Nullable MediaMetadata metadata) {
+        long duration = -1;
+        int fields = 0;
+        MediaDescription description = null;
+        if (metadata != null) {
+            metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build();
+            if (metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
+                duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
+            }
+            fields = metadata.size();
+            description = metadata.getDescription();
+        }
+        String metadataDescription = "size=" + fields + ", description=" + description;
+
+        try {
+            mSessionLink.setMetadata(metadata, duration, metadataDescription);
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
+        }
+    }
+
+    /**
+     * Update the list of items in the play queue. It is an ordered list and
+     * should contain the current item, and previous or upcoming items if they
+     * exist. Specify null if there is no current play queue.
+     * <p>
+     * The queue should be of reasonable size. If the play queue is unbounded
+     * within your app, it is better to send a reasonable amount in a sliding
+     * window instead.
+     *
+     * @param queue A list of items in the play queue.
+     */
+    public void setQueue(@Nullable List<MediaSession.QueueItem> queue) {
+        try {
+            mSessionLink.setQueue(queue);
+        } catch (RuntimeException e) {
+            Log.wtf("Dead object in setQueue.", e);
+        }
+    }
+
+    /**
+     * Set the title of the play queue. The UI should display this title along
+     * with the play queue itself.
+     * e.g. "Play Queue", "Now Playing", or an album name.
+     *
+     * @param title The title of the play queue.
+     */
+    public void setQueueTitle(@Nullable CharSequence title) {
+        try {
+            mSessionLink.setQueueTitle(title);
+        } catch (RuntimeException e) {
+            Log.wtf("Dead object in setQueueTitle.", e);
+        }
+    }
+
+    /**
+     * Set the style of rating used by this session. Apps trying to set the
+     * rating should use this style. Must be one of the following:
+     * <ul>
+     * <li>{@link Rating#RATING_NONE}</li>
+     * <li>{@link Rating#RATING_3_STARS}</li>
+     * <li>{@link Rating#RATING_4_STARS}</li>
+     * <li>{@link Rating#RATING_5_STARS}</li>
+     * <li>{@link Rating#RATING_HEART}</li>
+     * <li>{@link Rating#RATING_PERCENTAGE}</li>
+     * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
+     * </ul>
+     */
+    public void setRatingType(int type) {
+        try {
+            mSessionLink.setRatingType(type);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Error in setRatingType.", e);
+        }
+    }
+
+    /**
+     * Set some extras that can be associated with the {@link MediaSession}. No assumptions should
+     * be made as to how a {@link MediaController} will handle these extras.
+     * Keys should be fully qualified (e.g. com.example.MY_EXTRA) to avoid conflicts.
+     *
+     * @param extras The extras associated with the {@link MediaSession}.
+     */
+    public void setExtras(@Nullable Bundle extras) {
+        try {
+            mSessionLink.setExtras(extras);
+        } catch (RuntimeException e) {
+            Log.wtf("Dead object in setExtras.", e);
+        }
+    }
+
+    /**
+     * Gets the controller information who sent the current request.
+     * <p>
+     * Note: This is only valid while in a request callback, such as
+     * {@link MediaSession.Callback#onPlay}.
+     *
+     * @throws IllegalStateException If this method is called outside of
+     * {@link MediaSession.Callback} methods.
+     * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
+     */
+    public @NonNull RemoteUserInfo getCurrentControllerInfo() {
+        if (mCallbackHandler == null || mCallbackHandler.mCurrentControllerInfo == null) {
+            throw new IllegalStateException(
+                    "This should be called inside of MediaSession.Callback methods");
+        }
+        return mCallbackHandler.mCurrentControllerInfo;
+    }
+
+    /**
+     * Notify the system that the remote volume changed.
+     *
+     * @param provider The provider that is handling volume changes.
+     * @hide
+     */
+    public void notifyRemoteVolumeChanged(VolumeProvider provider) {
+        synchronized (mLock) {
+            if (provider == null || provider != mVolumeProvider) {
+                Log.w(TAG, "Received update from stale volume provider");
+                return;
+            }
+        }
+        try {
+            mSessionLink.setCurrentVolume(provider.getCurrentVolume());
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Error in notifyVolumeChanged", e);
+        }
+    }
+
+    /**
+     * Returns the name of the package that sent the last media button, transport control, or
+     * command from controllers and the system. This is only valid while in a request callback, such
+     * as {@link MediaSession.Callback#onPlay}.
+     */
+    public String getCallingPackage() {
+        if (mCallbackHandler != null && mCallbackHandler.mCurrentControllerInfo != null) {
+            return mCallbackHandler.mCurrentControllerInfo.getPackageName();
+        }
+        return null;
+    }
+
+    private void dispatchPrepare(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null);
+    }
+
+    private void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
+    }
+
+    private void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
+    }
+
+    private void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
+    }
+
+    private void dispatchPlay(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PLAY, null, null);
+    }
+
+    private void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
+    }
+
+    private void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
+    }
+
+    private void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
+    }
+
+    private void dispatchSkipToItem(RemoteUserInfo caller, long id) {
+        postToCallback(caller, CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, null);
+    }
+
+    private void dispatchPause(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PAUSE, null, null);
+    }
+
+    private void dispatchStop(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_STOP, null, null);
+    }
+
+    private void dispatchNext(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_NEXT, null, null);
+    }
+
+    private void dispatchPrevious(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_PREVIOUS, null, null);
+    }
+
+    private void dispatchFastForward(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_FAST_FORWARD, null, null);
+    }
+
+    private void dispatchRewind(RemoteUserInfo caller) {
+        postToCallback(caller, CallbackMessageHandler.MSG_REWIND, null, null);
+    }
+
+    private void dispatchSeekTo(RemoteUserInfo caller, long pos) {
+        postToCallback(caller, CallbackMessageHandler.MSG_SEEK_TO, pos, null);
+    }
+
+    private void dispatchRate(RemoteUserInfo caller, Rating rating) {
+        postToCallback(caller, CallbackMessageHandler.MSG_RATE, rating, null);
+    }
+
+    private void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) {
+        postToCallback(caller, CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
+    }
+
+    private void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) {
+        postToCallback(caller, CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, null);
+    }
+
+    private void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent,
+            long delay) {
+        postToCallbackDelayed(info, CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
+                mediaButtonIntent, null, delay);
+    }
+
+    private void dispatchAdjustVolume(RemoteUserInfo caller, int direction) {
+        postToCallback(caller, CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, null);
+    }
+
+    private void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) {
+        postToCallback(caller, CallbackMessageHandler.MSG_SET_VOLUME, volume, null);
+    }
+
+    private void dispatchCommand(RemoteUserInfo caller, String command, Bundle args,
+            ResultReceiver resultCb) {
+        Command cmd = new Command(command, args, resultCb);
+        postToCallback(caller, CallbackMessageHandler.MSG_COMMAND, cmd, null);
+    }
+
+    private void postToCallback(RemoteUserInfo caller, int what, Object obj, Bundle data) {
+        postToCallbackDelayed(caller, what, obj, data, 0);
+    }
+
+    private void postToCallbackDelayed(RemoteUserInfo caller, int what, Object obj, Bundle data,
+            long delay) {
+        synchronized (mLock) {
+            if (mCallbackHandler != null) {
+                mCallbackHandler.post(caller, what, obj, data, delay);
+            }
+        }
+    }
+
+    /**
+     * Return true if this is considered an active playback state.
+     */
+    public static boolean isActiveState(int state) {
+        switch (state) {
+            case PlaybackState.STATE_FAST_FORWARDING:
+            case PlaybackState.STATE_REWINDING:
+            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
+            case PlaybackState.STATE_SKIPPING_TO_NEXT:
+            case PlaybackState.STATE_BUFFERING:
+            case PlaybackState.STATE_CONNECTING:
+            case PlaybackState.STATE_PLAYING:
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Interface for handling MediaButtoneEvent
+     */
+    public interface MediaButtonEventDelegate {
+        /**
+         * Called when a media button is pressed and this session has the
+         * highest priority or a controller sends a media button event to the
+         * session.
+         *
+         * @param mediaButtonIntent an intent containing the KeyEvent as an extra
+         * @return True if the event was handled, false otherwise.
+         */
+        boolean onMediaButtonIntent(Intent mediaButtonIntent);
+    }
+
+    /**
+     * Receives media buttons, transport controls, and commands from controllers
+     * and the system. A callback may be set using {@link #setCallback}.
+     * @hide
+     */
+    public static class CallbackWrapper implements MediaButtonEventDelegate {
+
+        private final MediaSession.Callback mCallback;
+
+        @SuppressWarnings("WeakerAccess") /* synthetic access */
+                MediaSessionEngine mSessionImpl;
+        @SuppressWarnings("WeakerAccess") /* synthetic access */
+        CallbackMessageHandler mHandler;
+        private boolean mMediaPlayPauseKeyPending;
+
+        public CallbackWrapper(MediaSession.Callback callback) {
+            mCallback = callback;
+            if (mCallback != null) {
+                mCallback.onSetMediaButtonEventDelegate(this);
+            }
+        }
+
+        /**
+         * Called when a controller has sent a command to this session.
+         * The owner of the session may handle custom commands but is not
+         * required to.
+         *
+         * @param command The command name.
+         * @param args Optional parameters for the command, may be null.
+         * @param cb A result receiver to which a result may be sent by the command, may be null.
+         */
+        public void onCommand(@NonNull String command, @Nullable Bundle args,
+                @Nullable ResultReceiver cb) {
+            if (mCallback != null) {
+                mCallback.onCommand(command, args, cb);
+            }
+        }
+
+        /**
+         * Called when a media button is pressed and this session has the
+         * highest priority or a controller sends a media button event to the
+         * session. The default behavior will call the relevant method if the
+         * action for it was set.
+         * <p>
+         * The intent will be of type {@link Intent#ACTION_MEDIA_BUTTON} with a
+         * KeyEvent in {@link Intent#EXTRA_KEY_EVENT}
+         *
+         * @param mediaButtonIntent an intent containing the KeyEvent as an
+         *            extra
+         * @return True if the event was handled, false otherwise.
+         */
+        public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {
+            return mCallback == null ? false : mCallback.onMediaButtonEvent(mediaButtonIntent);
+        }
+
+        private void handleMediaPlayPauseKeySingleTapIfPending() {
+            if (!mMediaPlayPauseKeyPending) {
+                return;
+            }
+            mMediaPlayPauseKeyPending = false;
+            mHandler.removeMessages(CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
+            PlaybackState state = mSessionImpl.mPlaybackState;
+            long validActions = state == null ? 0 : state.getActions();
+            boolean isPlaying = state != null
+                    && state.getState() == PlaybackState.STATE_PLAYING;
+            boolean canPlay = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
+                    | PlaybackState.ACTION_PLAY)) != 0;
+            boolean canPause = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
+                    | PlaybackState.ACTION_PAUSE)) != 0;
+            if (isPlaying && canPause) {
+                onPause();
+            } else if (!isPlaying && canPlay) {
+                onPlay();
+            }
+        }
+
+        /**
+         * Override to handle requests to prepare playback. During the preparation, a session should
+         * not hold audio focus in order to allow other sessions play seamlessly. The state of
+         * playback should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is
+         * done.
+         */
+        public void onPrepare() {
+            if (mCallback != null) {
+                mCallback.onPrepare();
+            }
+        }
+
+        /**
+         * Override to handle requests to prepare for playing a specific mediaId that was provided
+         * by your app's {@link MediaBrowserService}. During the preparation, a session should not
+         * hold audio focus in order to allow other sessions play seamlessly. The state of playback
+         * should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done.
+         * The playback of the prepared content should start in the implementation of
+         * {@link #onPlay}. Override {@link #onPlayFromMediaId} to handle requests for starting
+         * playback without preparation.
+         */
+        public void onPrepareFromMediaId(String mediaId, Bundle extras) {
+            if (mCallback != null) {
+                mCallback.onPrepareFromMediaId(mediaId, extras);
+            }
+        }
+
+        /**
+         * Override to handle requests to prepare playback from a search query. An empty query
+         * indicates that the app may prepare any music. The implementation should attempt to make a
+         * smart choice about what to play. During the preparation, a session should not hold audio
+         * focus in order to allow other sessions play seamlessly. The state of playback should be
+         * updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done. The playback
+         * of the prepared content should start in the implementation of {@link #onPlay}. Override
+         * {@link #onPlayFromSearch} to handle requests for starting playback without preparation.
+         */
+        public void onPrepareFromSearch(String query, Bundle extras) {
+            if (mCallback != null) {
+                mCallback.onPrepareFromSearch(query, extras);
+            }
+        }
+
+        /**
+         * Override to handle requests to prepare a specific media item represented by a URI.
+         * During the preparation, a session should not hold audio focus in order to allow
+         * other sessions play seamlessly. The state of playback should be updated to
+         * {@link PlaybackState#STATE_PAUSED} after the preparation is done.
+         * The playback of the prepared content should start in the implementation of
+         * {@link #onPlay}. Override {@link #onPlayFromUri} to handle requests
+         * for starting playback without preparation.
+         */
+        public void onPrepareFromUri(Uri uri, Bundle extras) {
+            if (mCallback != null) {
+                mCallback.onPrepareFromUri(uri, extras);
+            }
+        }
+
+        /**
+         * Override to handle requests to begin playback.
+         */
+        public void onPlay() {
+            if (mCallback != null) {
+                mCallback.onPlay();
+            }
+        }
+
+        /**
+         * Override to handle requests to begin playback from a search query. An
+         * empty query indicates that the app may play any music. The
+         * implementation should attempt to make a smart choice about what to
+         * play.
+         */
+        public void onPlayFromSearch(String query, Bundle extras) {
+            if (mCallback != null) {
+                mCallback.onPlayFromSearch(query, extras);
+            }
+        }
+
+        /**
+         * Override to handle requests to play a specific mediaId that was
+         * provided by your app's {@link MediaBrowserService}.
+         */
+        public void onPlayFromMediaId(String mediaId, Bundle extras) {
+            if (mCallback != null) {
+                mCallback.onPlayFromMediaId(mediaId, extras);
+            }
+        }
+
+        /**
+         * Override to handle requests to play a specific media item represented by a URI.
+         */
+        public void onPlayFromUri(Uri uri, Bundle extras) {
+            if (mCallback != null) {
+                mCallback.onPlayFromUri(uri, extras);
+            }
+        }
+
+        /**
+         * Override to handle requests to play an item with a given id from the
+         * play queue.
+         */
+        public void onSkipToQueueItem(long id) {
+            if (mCallback != null) {
+                mCallback.onSkipToQueueItem(id);
+            }
+        }
+
+        /**
+         * Override to handle requests to pause playback.
+         */
+        public void onPause() {
+            if (mCallback != null) {
+                mCallback.onPause();
+            }
+        }
+
+        /**
+         * Override to handle requests to skip to the next media item.
+         */
+        public void onSkipToNext() {
+            if (mCallback != null) {
+                mCallback.onSkipToNext();
+            }
+        }
+
+        /**
+         * Override to handle requests to skip to the previous media item.
+         */
+        public void onSkipToPrevious() {
+            if (mCallback != null) {
+                mCallback.onSkipToPrevious();
+            }
+        }
+
+        /**
+         * Override to handle requests to fast forward.
+         */
+        public void onFastForward() {
+            if (mCallback != null) {
+                mCallback.onFastForward();
+            }
+        }
+
+        /**
+         * Override to handle requests to rewind.
+         */
+        public void onRewind() {
+            if (mCallback != null) {
+                mCallback.onRewind();
+            }
+        }
+
+        /**
+         * Override to handle requests to stop playback.
+         */
+        public void onStop() {
+            if (mCallback != null) {
+                mCallback.onStop();
+            }
+        }
+
+        /**
+         * Override to handle requests to seek to a specific position in ms.
+         *
+         * @param pos New position to move to, in milliseconds.
+         */
+        public void onSeekTo(long pos) {
+            if (mCallback != null) {
+                mCallback.onSeekTo(pos);
+            }
+        }
+
+        /**
+         * Override to handle the item being rated.
+         *
+         * @param rating
+         */
+        public void onSetRating(@NonNull Rating rating) {
+            if (mCallback != null) {
+                mCallback.onSetRating(rating);
+            }
+        }
+
+        /**
+         * Called when a {@link MediaController} wants a {@link PlaybackState.CustomAction} to be
+         * performed.
+         *
+         * @param action The action that was originally sent in the
+         *               {@link PlaybackState.CustomAction}.
+         * @param extras Optional extras specified by the {@link MediaController}.
+         */
+        public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
+            if (mCallback != null) {
+                mCallback.onCustomAction(action, extras);
+            }
+        }
+
+        @Override
+        public boolean onMediaButtonIntent(Intent mediaButtonIntent) {
+            if (mSessionImpl != null && mHandler != null
+                    && Intent.ACTION_MEDIA_BUTTON.equals(mediaButtonIntent.getAction())) {
+                KeyEvent ke = mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
+                if (ke != null && ke.getAction() == KeyEvent.ACTION_DOWN) {
+                    PlaybackState state = mSessionImpl.mPlaybackState;
+                    long validActions = state == null ? 0 : state.getActions();
+                    switch (ke.getKeyCode()) {
+                        case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                        case KeyEvent.KEYCODE_HEADSETHOOK:
+                            if (ke.getRepeatCount() > 0) {
+                                // Consider long-press as a single tap.
+                                handleMediaPlayPauseKeySingleTapIfPending();
+                            } else if (mMediaPlayPauseKeyPending) {
+                                // Consider double tap as the next.
+                                mHandler.removeMessages(CallbackMessageHandler
+                                        .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
+                                mMediaPlayPauseKeyPending = false;
+                                if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
+                                    onSkipToNext();
+                                }
+                            } else {
+                                mMediaPlayPauseKeyPending = true;
+                                mSessionImpl.dispatchMediaButtonDelayed(
+                                        mSessionImpl.getCurrentControllerInfo(),
+                                        mediaButtonIntent, ViewConfiguration.getDoubleTapTimeout());
+                            }
+                            return true;
+                        default:
+                            // If another key is pressed within double tap timeout, consider the
+                            // pending play/pause as a single tap to handle media keys in order.
+                            handleMediaPlayPauseKeySingleTapIfPending();
+                            break;
+                    }
+
+                    switch (ke.getKeyCode()) {
+                        case KeyEvent.KEYCODE_MEDIA_PLAY:
+                            if ((validActions & PlaybackState.ACTION_PLAY) != 0) {
+                                onPlay();
+                                return true;
+                            }
+                            break;
+                        case KeyEvent.KEYCODE_MEDIA_PAUSE:
+                            if ((validActions & PlaybackState.ACTION_PAUSE) != 0) {
+                                onPause();
+                                return true;
+                            }
+                            break;
+                        case KeyEvent.KEYCODE_MEDIA_NEXT:
+                            if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
+                                onSkipToNext();
+                                return true;
+                            }
+                            break;
+                        case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+                            if ((validActions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0) {
+                                onSkipToPrevious();
+                                return true;
+                            }
+                            break;
+                        case KeyEvent.KEYCODE_MEDIA_STOP:
+                            if ((validActions & PlaybackState.ACTION_STOP) != 0) {
+                                onStop();
+                                return true;
+                            }
+                            break;
+                        case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+                            if ((validActions & PlaybackState.ACTION_FAST_FORWARD) != 0) {
+                                onFastForward();
+                                return true;
+                            }
+                            break;
+                        case KeyEvent.KEYCODE_MEDIA_REWIND:
+                            if ((validActions & PlaybackState.ACTION_REWIND) != 0) {
+                                onRewind();
+                                return true;
+                            }
+                            break;
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @SystemApi
+    public static final class CallbackStub extends SessionCallbackLink.CallbackStub {
+        private WeakReference<MediaSessionEngine> mSessionImpl;
+
+        private static RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid) {
+            return new RemoteUserInfo(packageName, pid, uid);
+        }
+
+        public CallbackStub() {
+        }
+
+        @Override
+        public void onCommand(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchCommand(createRemoteUserInfo(packageName, pid, uid),
+                        command, args, cb);
+            }
+        }
+
+        @Override
+        public void onMediaButton(String packageName, int pid, int uid, Intent mediaButtonIntent,
+                int sequenceNumber, ResultReceiver cb) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            try {
+                if (sessionImpl != null) {
+                    sessionImpl.dispatchMediaButton(
+                            createRemoteUserInfo(packageName, pid, uid), mediaButtonIntent);
+                }
+            } finally {
+                if (cb != null) {
+                    cb.send(sequenceNumber, null);
+                }
+            }
+        }
+
+        @Override
+        public void onMediaButtonFromController(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, Intent mediaButtonIntent) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid),
+                        mediaButtonIntent);
+            }
+        }
+
+        @Override
+        public void onPrepare(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid));
+            }
+        }
+
+        @Override
+        public void onPrepareFromMediaId(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String mediaId,
+                Bundle extras) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchPrepareFromMediaId(
+                        createRemoteUserInfo(packageName, pid, uid), mediaId, extras);
+            }
+        }
+
+        @Override
+        public void onPrepareFromSearch(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String query,
+                Bundle extras) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchPrepareFromSearch(
+                        createRemoteUserInfo(packageName, pid, uid), query, extras);
+            }
+        }
+
+        @Override
+        public void onPrepareFromUri(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, Uri uri, Bundle extras) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchPrepareFromUri(
+                        createRemoteUserInfo(packageName, pid, uid), uri, extras);
+            }
+        }
+
+        @Override
+        public void onPlay(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchPlay(createRemoteUserInfo(packageName, pid, uid));
+            }
+        }
+
+        @Override
+        public void onPlayFromMediaId(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String mediaId,
+                Bundle extras) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchPlayFromMediaId(
+                        createRemoteUserInfo(packageName, pid, uid), mediaId, extras);
+            }
+        }
+
+        @Override
+        public void onPlayFromSearch(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String query,
+                Bundle extras) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchPlayFromSearch(
+                        createRemoteUserInfo(packageName, pid, uid), query, extras);
+            }
+        }
+
+        @Override
+        public void onPlayFromUri(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, Uri uri, Bundle extras) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchPlayFromUri(
+                        createRemoteUserInfo(packageName, pid, uid), uri, extras);
+            }
+        }
+
+        @Override
+        public void onSkipToTrack(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, long id) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchSkipToItem(
+                        createRemoteUserInfo(packageName, pid, uid), id);
+            }
+        }
+
+        @Override
+        public void onPause(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchPause(createRemoteUserInfo(packageName, pid, uid));
+            }
+        }
+
+        @Override
+        public void onStop(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchStop(createRemoteUserInfo(packageName, pid, uid));
+            }
+        }
+
+        @Override
+        public void onNext(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchNext(createRemoteUserInfo(packageName, pid, uid));
+            }
+        }
+
+        @Override
+        public void onPrevious(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid));
+            }
+        }
+
+        @Override
+        public void onFastForward(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchFastForward(
+                        createRemoteUserInfo(packageName, pid, uid));
+            }
+        }
+
+        @Override
+        public void onRewind(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchRewind(createRemoteUserInfo(packageName, pid, uid));
+            }
+        }
+
+        @Override
+        public void onSeekTo(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, long pos) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchSeekTo(
+                        createRemoteUserInfo(packageName, pid, uid), pos);
+            }
+        }
+
+        @Override
+        public void onRate(String packageName, int pid, int uid, ControllerCallbackLink caller,
+                Rating rating) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchRate(
+                        createRemoteUserInfo(packageName, pid, uid), rating);
+            }
+        }
+
+        @Override
+        public void onCustomAction(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String action, Bundle args) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchCustomAction(
+                        createRemoteUserInfo(packageName, pid, uid), action, args);
+            }
+        }
+
+        @Override
+        public void onAdjustVolume(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, int direction) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchAdjustVolume(
+                        createRemoteUserInfo(packageName, pid, uid), direction);
+            }
+        }
+
+        @Override
+        public void onSetVolumeTo(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, int value) {
+            MediaSessionEngine sessionImpl = mSessionImpl.get();
+            if (sessionImpl != null) {
+                sessionImpl.dispatchSetVolumeTo(
+                        createRemoteUserInfo(packageName, pid, uid), value);
+            }
+        }
+
+        void setSessionImpl(MediaSessionEngine sessionImpl) {
+            mSessionImpl = new WeakReference<>(sessionImpl);
+        }
+    }
+
+    /**
+     * A single item that is part of the play queue. It contains a description
+     * of the item and its id in the queue.
+     */
+    public static final class QueueItem {
+        /**
+         * This id is reserved. No items can be explicitly assigned this id.
+         */
+        public static final int UNKNOWN_ID = -1;
+
+        private final MediaDescription mDescription;
+        private final long mId;
+
+        /**
+         * Create a new {@link MediaSession.QueueItem}.
+         *
+         * @param description The {@link MediaDescription} for this item.
+         * @param id An identifier for this item. It must be unique within the
+         *            play queue and cannot be {@link #UNKNOWN_ID}.
+         */
+        public QueueItem(MediaDescription description, long id) {
+            if (description == null) {
+                throw new IllegalArgumentException("Description cannot be null.");
+            }
+            if (id == UNKNOWN_ID) {
+                throw new IllegalArgumentException("Id cannot be QueueItem.UNKNOWN_ID");
+            }
+            mDescription = description;
+            mId = id;
+        }
+
+        public QueueItem(Parcel in) {
+            mDescription = MediaDescription.CREATOR.createFromParcel(in);
+            mId = in.readLong();
+        }
+
+        /**
+         * Get the description for this item.
+         */
+        public MediaDescription getDescription() {
+            return mDescription;
+        }
+
+        /**
+         * Get the queue id for this item.
+         */
+        public long getQueueId() {
+            return mId;
+        }
+
+        /**
+         * 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.
+         */
+        public void writeToParcel(Parcel dest, int flags) {
+            mDescription.writeToParcel(dest, flags);
+            dest.writeLong(mId);
+        }
+
+        @Override
+        public String toString() {
+            return "MediaSession.QueueItem {" + "Description=" + mDescription + ", Id=" + mId
+                    + " }";
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == null) {
+                return false;
+            }
+
+            if (!(o instanceof QueueItem)) {
+                return false;
+            }
+
+            final QueueItem item = (QueueItem) o;
+            if (mId != item.mId) {
+                return false;
+            }
+
+            if (!Objects.equals(mDescription, item.mDescription)) {
+                return false;
+            }
+
+            return true;
+        }
+    }
+
+    private static final class Command {
+        public final String command;
+        public final Bundle extras;
+        public final ResultReceiver stub;
+
+        Command(String command, Bundle extras, ResultReceiver stub) {
+            this.command = command;
+            this.extras = extras;
+            this.stub = stub;
+        }
+    }
+
+    private class CallbackMessageHandler extends Handler {
+        private static final int MSG_COMMAND = 1;
+        private static final int MSG_MEDIA_BUTTON = 2;
+        private static final int MSG_PREPARE = 3;
+        private static final int MSG_PREPARE_MEDIA_ID = 4;
+        private static final int MSG_PREPARE_SEARCH = 5;
+        private static final int MSG_PREPARE_URI = 6;
+        private static final int MSG_PLAY = 7;
+        private static final int MSG_PLAY_MEDIA_ID = 8;
+        private static final int MSG_PLAY_SEARCH = 9;
+        private static final int MSG_PLAY_URI = 10;
+        private static final int MSG_SKIP_TO_ITEM = 11;
+        private static final int MSG_PAUSE = 12;
+        private static final int MSG_STOP = 13;
+        private static final int MSG_NEXT = 14;
+        private static final int MSG_PREVIOUS = 15;
+        private static final int MSG_FAST_FORWARD = 16;
+        private static final int MSG_REWIND = 17;
+        private static final int MSG_SEEK_TO = 18;
+        private static final int MSG_RATE = 19;
+        private static final int MSG_CUSTOM_ACTION = 20;
+        private static final int MSG_ADJUST_VOLUME = 21;
+        private static final int MSG_SET_VOLUME = 22;
+        private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 23;
+
+        @SuppressWarnings("WeakerAccess") /* synthetic access */
+        CallbackWrapper mCallbackWrapper;
+        @SuppressWarnings("WeakerAccess") /* synthetic access */
+        RemoteUserInfo mCurrentControllerInfo;
+
+        CallbackMessageHandler(Looper looper, CallbackWrapper callbackWrapper) {
+            super(looper);
+            mCallbackWrapper = callbackWrapper;
+            mCallbackWrapper.mHandler = this;
+        }
+
+        void post(RemoteUserInfo caller, int what, Object obj, Bundle data, long delayMs) {
+            Pair<RemoteUserInfo, Object> objWithCaller = Pair.create(caller, obj);
+            Message msg = obtainMessage(what, objWithCaller);
+            msg.setAsynchronous(true);
+            msg.setData(data);
+            if (delayMs > 0) {
+                sendMessageDelayed(msg, delayMs);
+            } else {
+                sendMessage(msg);
+            }
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            mCurrentControllerInfo = ((Pair<RemoteUserInfo, Object>) msg.obj).first;
+
+            VolumeProvider vp;
+            Object obj = ((Pair<RemoteUserInfo, Object>) msg.obj).second;
+
+            switch (msg.what) {
+                case MSG_COMMAND:
+                    Command cmd = (Command) obj;
+                    mCallbackWrapper.onCommand(cmd.command, cmd.extras, cmd.stub);
+                    break;
+                case MSG_MEDIA_BUTTON:
+                    mCallbackWrapper.onMediaButtonEvent((Intent) obj);
+                    break;
+                case MSG_PREPARE:
+                    mCallbackWrapper.onPrepare();
+                    break;
+                case MSG_PREPARE_MEDIA_ID:
+                    mCallbackWrapper.onPrepareFromMediaId((String) obj, msg.getData());
+                    break;
+                case MSG_PREPARE_SEARCH:
+                    mCallbackWrapper.onPrepareFromSearch((String) obj, msg.getData());
+                    break;
+                case MSG_PREPARE_URI:
+                    mCallbackWrapper.onPrepareFromUri((Uri) obj, msg.getData());
+                    break;
+                case MSG_PLAY:
+                    mCallbackWrapper.onPlay();
+                    break;
+                case MSG_PLAY_MEDIA_ID:
+                    mCallbackWrapper.onPlayFromMediaId((String) obj, msg.getData());
+                    break;
+                case MSG_PLAY_SEARCH:
+                    mCallbackWrapper.onPlayFromSearch((String) obj, msg.getData());
+                    break;
+                case MSG_PLAY_URI:
+                    mCallbackWrapper.onPlayFromUri((Uri) obj, msg.getData());
+                    break;
+                case MSG_SKIP_TO_ITEM:
+                    mCallbackWrapper.onSkipToQueueItem((Long) obj);
+                    break;
+                case MSG_PAUSE:
+                    mCallbackWrapper.onPause();
+                    break;
+                case MSG_STOP:
+                    mCallbackWrapper.onStop();
+                    break;
+                case MSG_NEXT:
+                    mCallbackWrapper.onSkipToNext();
+                    break;
+                case MSG_PREVIOUS:
+                    mCallbackWrapper.onSkipToPrevious();
+                    break;
+                case MSG_FAST_FORWARD:
+                    mCallbackWrapper.onFastForward();
+                    break;
+                case MSG_REWIND:
+                    mCallbackWrapper.onRewind();
+                    break;
+                case MSG_SEEK_TO:
+                    mCallbackWrapper.onSeekTo((Long) obj);
+                    break;
+                case MSG_RATE:
+                    mCallbackWrapper.onSetRating((Rating) obj);
+                    break;
+                case MSG_CUSTOM_ACTION:
+                    mCallbackWrapper.onCustomAction((String) obj, msg.getData());
+                    break;
+                case MSG_ADJUST_VOLUME:
+                    synchronized (mLock) {
+                        vp = mVolumeProvider;
+                    }
+                    if (vp != null) {
+                        vp.onAdjustVolume((int) obj);
+                    }
+                    break;
+                case MSG_SET_VOLUME:
+                    synchronized (mLock) {
+                        vp = mVolumeProvider;
+                    }
+                    if (vp != null) {
+                        vp.onSetVolumeTo((int) obj);
+                    }
+                    break;
+                case MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT:
+                    mCallbackWrapper.handleMediaPlayPauseKeySingleTapIfPending();
+                    break;
+            }
+            mCurrentControllerInfo = null;
+        }
+    }
+}
diff --git a/media/apex/java/android/media/session/MediaSessionProviderService.java b/media/apex/java/android/media/session/MediaSessionProviderService.java
new file mode 100644
index 0000000..9a346ff
--- /dev/null
+++ b/media/apex/java/android/media/session/MediaSessionProviderService.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Abstract class for mainline module services.
+ *
+ * @hide  // TODO: Make it as a @SystemApi
+ */
+public abstract class MediaSessionProviderService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        // TODO: Return IMediaSessionProviderService.Stub()
+        return null;
+    }
+}
diff --git a/media/java/android/media/session/PlaybackState.aidl b/media/apex/java/android/media/session/PlaybackState.aidl
similarity index 100%
rename from media/java/android/media/session/PlaybackState.aidl
rename to media/apex/java/android/media/session/PlaybackState.aidl
diff --git a/media/apex/java/android/media/session/PlaybackState.java b/media/apex/java/android/media/session/PlaybackState.java
new file mode 100644
index 0000000..6b28c97
--- /dev/null
+++ b/media/apex/java/android/media/session/PlaybackState.java
@@ -0,0 +1,920 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.session;
+
+import android.annotation.DrawableRes;
+import android.annotation.IntDef;
+import android.annotation.LongDef;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.text.TextUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Playback state for a {@link MediaSession}. This includes a state like
+ * {@link PlaybackState#STATE_PLAYING}, the current playback position,
+ * and the current control capabilities.
+ */
+public final class PlaybackState implements Parcelable {
+    private static final String TAG = "PlaybackState";
+
+    /**
+     * @hide
+     */
+    @LongDef(flag = true, value = {ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
+            ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
+            ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
+            ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
+            ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Actions {}
+
+    /**
+     * Indicates this session supports the stop command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_STOP = 1 << 0;
+
+    /**
+     * Indicates this session supports the pause command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_PAUSE = 1 << 1;
+
+    /**
+     * Indicates this session supports the play command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_PLAY = 1 << 2;
+
+    /**
+     * Indicates this session supports the rewind command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_REWIND = 1 << 3;
+
+    /**
+     * Indicates this session supports the previous command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4;
+
+    /**
+     * Indicates this session supports the next command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_SKIP_TO_NEXT = 1 << 5;
+
+    /**
+     * Indicates this session supports the fast forward command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_FAST_FORWARD = 1 << 6;
+
+    /**
+     * Indicates this session supports the set rating command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_SET_RATING = 1 << 7;
+
+    /**
+     * Indicates this session supports the seek to command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_SEEK_TO = 1 << 8;
+
+    /**
+     * Indicates this session supports the play/pause toggle command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_PLAY_PAUSE = 1 << 9;
+
+    /**
+     * Indicates this session supports the play from media id command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_PLAY_FROM_MEDIA_ID = 1 << 10;
+
+    /**
+     * Indicates this session supports the play from search command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11;
+
+    /**
+     * Indicates this session supports the skip to queue item command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12;
+
+    /**
+     * Indicates this session supports the play from URI command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_PLAY_FROM_URI = 1 << 13;
+
+    /**
+     * Indicates this session supports the prepare command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_PREPARE = 1 << 14;
+
+    /**
+     * Indicates this session supports the prepare from media id command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_PREPARE_FROM_MEDIA_ID = 1 << 15;
+
+    /**
+     * Indicates this session supports the prepare from search command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_PREPARE_FROM_SEARCH = 1 << 16;
+
+    /**
+     * Indicates this session supports the prepare from URI command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_PREPARE_FROM_URI = 1 << 17;
+
+    /**
+     * @hide
+     */
+    @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_FAST_FORWARDING,
+            STATE_REWINDING, STATE_BUFFERING, STATE_ERROR, STATE_CONNECTING,
+            STATE_SKIPPING_TO_PREVIOUS, STATE_SKIPPING_TO_NEXT, STATE_SKIPPING_TO_QUEUE_ITEM})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface State {}
+
+    /**
+     * This is the default playback state and indicates that no media has been
+     * added yet, or the performer has been reset and has no content to play.
+     *
+     * @see Builder#setState(int, long, float)
+     * @see Builder#setState(int, long, float, long)
+     */
+    public static final int STATE_NONE = 0;
+
+    /**
+     * State indicating this item is currently stopped.
+     *
+     * @see Builder#setState
+     */
+    public static final int STATE_STOPPED = 1;
+
+    /**
+     * State indicating this item is currently paused.
+     *
+     * @see Builder#setState
+     */
+    public static final int STATE_PAUSED = 2;
+
+    /**
+     * State indicating this item is currently playing.
+     *
+     * @see Builder#setState
+     */
+    public static final int STATE_PLAYING = 3;
+
+    /**
+     * State indicating this item is currently fast forwarding.
+     *
+     * @see Builder#setState
+     */
+    public static final int STATE_FAST_FORWARDING = 4;
+
+    /**
+     * State indicating this item is currently rewinding.
+     *
+     * @see Builder#setState
+     */
+    public static final int STATE_REWINDING = 5;
+
+    /**
+     * State indicating this item is currently buffering and will begin playing
+     * when enough data has buffered.
+     *
+     * @see Builder#setState
+     */
+    public static final int STATE_BUFFERING = 6;
+
+    /**
+     * State indicating this item is currently in an error state. The error
+     * message should also be set when entering this state.
+     *
+     * @see Builder#setState
+     */
+    public static final int STATE_ERROR = 7;
+
+    /**
+     * State indicating the class doing playback is currently connecting to a
+     * new destination.  Depending on the implementation you may return to the previous
+     * state when the connection finishes or enter {@link #STATE_NONE}.
+     * If the connection failed {@link #STATE_ERROR} should be used.
+     *
+     * @see Builder#setState
+     */
+    public static final int STATE_CONNECTING = 8;
+
+    /**
+     * State indicating the player is currently skipping to the previous item.
+     *
+     * @see Builder#setState
+     */
+    public static final int STATE_SKIPPING_TO_PREVIOUS = 9;
+
+    /**
+     * State indicating the player is currently skipping to the next item.
+     *
+     * @see Builder#setState
+     */
+    public static final int STATE_SKIPPING_TO_NEXT = 10;
+
+    /**
+     * State indicating the player is currently skipping to a specific item in
+     * the queue.
+     *
+     * @see Builder#setState
+     */
+    public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11;
+
+    /**
+     * Use this value for the position to indicate the position is not known.
+     */
+    public static final long PLAYBACK_POSITION_UNKNOWN = -1;
+
+    private final int mState;
+    private final long mPosition;
+    private final long mBufferedPosition;
+    private final float mSpeed;
+    private final long mActions;
+    private List<PlaybackState.CustomAction> mCustomActions;
+    private final CharSequence mErrorMessage;
+    private final long mUpdateTime;
+    private final long mActiveItemId;
+    private final Bundle mExtras;
+
+    private PlaybackState(int state, long position, long updateTime, float speed,
+            long bufferedPosition, long transportControls,
+            List<PlaybackState.CustomAction> customActions, long activeItemId,
+            CharSequence error, Bundle extras) {
+        mState = state;
+        mPosition = position;
+        mSpeed = speed;
+        mUpdateTime = updateTime;
+        mBufferedPosition = bufferedPosition;
+        mActions = transportControls;
+        mCustomActions = new ArrayList<>(customActions);
+        mActiveItemId = activeItemId;
+        mErrorMessage = error;
+        mExtras = extras;
+    }
+
+    private PlaybackState(Parcel in) {
+        mState = in.readInt();
+        mPosition = in.readLong();
+        mSpeed = in.readFloat();
+        mUpdateTime = in.readLong();
+        mBufferedPosition = in.readLong();
+        mActions = in.readLong();
+        mCustomActions = in.createTypedArrayList(CustomAction.CREATOR);
+        mActiveItemId = in.readLong();
+        mErrorMessage = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mExtras = in.readBundle();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder bob = new StringBuilder("PlaybackState {");
+        bob.append("state=").append(mState);
+        bob.append(", position=").append(mPosition);
+        bob.append(", buffered position=").append(mBufferedPosition);
+        bob.append(", speed=").append(mSpeed);
+        bob.append(", updated=").append(mUpdateTime);
+        bob.append(", actions=").append(mActions);
+        bob.append(", custom actions=").append(mCustomActions);
+        bob.append(", active item id=").append(mActiveItemId);
+        bob.append(", error=").append(mErrorMessage);
+        bob.append("}");
+        return bob.toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mState);
+        dest.writeLong(mPosition);
+        dest.writeFloat(mSpeed);
+        dest.writeLong(mUpdateTime);
+        dest.writeLong(mBufferedPosition);
+        dest.writeLong(mActions);
+        dest.writeTypedList(mCustomActions);
+        dest.writeLong(mActiveItemId);
+        TextUtils.writeToParcel(mErrorMessage, dest, 0);
+        dest.writeBundle(mExtras);
+    }
+
+    /**
+     * Get the current state of playback. One of the following:
+     * <ul>
+     * <li> {@link PlaybackState#STATE_NONE}</li>
+     * <li> {@link PlaybackState#STATE_STOPPED}</li>
+     * <li> {@link PlaybackState#STATE_PLAYING}</li>
+     * <li> {@link PlaybackState#STATE_PAUSED}</li>
+     * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
+     * <li> {@link PlaybackState#STATE_REWINDING}</li>
+     * <li> {@link PlaybackState#STATE_BUFFERING}</li>
+     * <li> {@link PlaybackState#STATE_ERROR}</li>
+     * <li> {@link PlaybackState#STATE_CONNECTING}</li>
+     * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
+     * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
+     * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
+     * </ul>
+     */
+    @State
+    public int getState() {
+        return mState;
+    }
+
+    /**
+     * Get the current playback position in ms.
+     */
+    public long getPosition() {
+        return mPosition;
+    }
+
+    /**
+     * Get the current buffered position in ms. This is the farthest playback
+     * point that can be reached from the current position using only buffered
+     * content.
+     */
+    public long getBufferedPosition() {
+        return mBufferedPosition;
+    }
+
+    /**
+     * Get the current playback speed as a multiple of normal playback. This
+     * should be negative when rewinding. A value of 1 means normal playback and
+     * 0 means paused.
+     *
+     * @return The current speed of playback.
+     */
+    public float getPlaybackSpeed() {
+        return mSpeed;
+    }
+
+    /**
+     * Get the current actions available on this session. This should use a
+     * bitmask of the available actions.
+     * <ul>
+     * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
+     * <li> {@link PlaybackState#ACTION_REWIND}</li>
+     * <li> {@link PlaybackState#ACTION_PLAY}</li>
+     * <li> {@link PlaybackState#ACTION_PAUSE}</li>
+     * <li> {@link PlaybackState#ACTION_STOP}</li>
+     * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
+     * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
+     * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
+     * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
+     * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
+     * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
+     * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
+     * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
+     * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
+     * <li> {@link PlaybackState#ACTION_PREPARE}</li>
+     * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
+     * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
+     * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
+     * </ul>
+     */
+    @Actions
+    public long getActions() {
+        return mActions;
+    }
+
+    /**
+     * Get the list of custom actions.
+     */
+    public List<PlaybackState.CustomAction> getCustomActions() {
+        return mCustomActions;
+    }
+
+    /**
+     * Get a user readable error message. This should be set when the state is
+     * {@link PlaybackState#STATE_ERROR}.
+     */
+    public CharSequence getErrorMessage() {
+        return mErrorMessage;
+    }
+
+    /**
+     * Get the elapsed real time at which position was last updated. If the
+     * position has never been set this will return 0;
+     *
+     * @return The last time the position was updated.
+     */
+    public long getLastPositionUpdateTime() {
+        return mUpdateTime;
+    }
+
+    /**
+     * Get the id of the currently active item in the queue. If there is no
+     * queue or a queue is not supported by the session this will be
+     * {@link MediaSession.QueueItem#UNKNOWN_ID}.
+     *
+     * @return The id of the currently active item in the queue or
+     *         {@link MediaSession.QueueItem#UNKNOWN_ID}.
+     */
+    public long getActiveQueueItemId() {
+        return mActiveItemId;
+    }
+
+    /**
+     * Get any custom extras that were set on this playback state.
+     *
+     * @return The extras for this state or null.
+     */
+    public @Nullable Bundle getExtras() {
+        return mExtras;
+    }
+
+    public static final Parcelable.Creator<PlaybackState> CREATOR =
+            new Parcelable.Creator<PlaybackState>() {
+        @Override
+        public PlaybackState createFromParcel(Parcel in) {
+            return new PlaybackState(in);
+        }
+
+        @Override
+        public PlaybackState[] newArray(int size) {
+            return new PlaybackState[size];
+        }
+    };
+
+    /**
+     * {@link PlaybackState.CustomAction CustomActions} can be used to extend the capabilities of
+     * the standard transport controls by exposing app specific actions to
+     * {@link MediaController MediaControllers}.
+     */
+    public static final class CustomAction implements Parcelable {
+        private final String mAction;
+        private final CharSequence mName;
+        private final int mIcon;
+        private final Bundle mExtras;
+
+        /**
+         * Use {@link PlaybackState.CustomAction.Builder#build()}.
+         */
+        private CustomAction(String action, CharSequence name, int icon, Bundle extras) {
+            mAction = action;
+            mName = name;
+            mIcon = icon;
+            mExtras = extras;
+        }
+
+        private CustomAction(Parcel in) {
+            mAction = in.readString();
+            mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+            mIcon = in.readInt();
+            mExtras = in.readBundle();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(mAction);
+            TextUtils.writeToParcel(mName, dest, flags);
+            dest.writeInt(mIcon);
+            dest.writeBundle(mExtras);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Parcelable.Creator<PlaybackState.CustomAction> CREATOR =
+                new Parcelable.Creator<PlaybackState.CustomAction>() {
+
+                    @Override
+                    public PlaybackState.CustomAction createFromParcel(Parcel p) {
+                        return new PlaybackState.CustomAction(p);
+                    }
+
+                    @Override
+                    public PlaybackState.CustomAction[] newArray(int size) {
+                        return new PlaybackState.CustomAction[size];
+                    }
+                };
+
+        /**
+         * Returns the action of the {@link CustomAction}.
+         *
+         * @return The action of the {@link CustomAction}.
+         */
+        public String getAction() {
+            return mAction;
+        }
+
+        /**
+         * Returns the display name of this action. e.g. "Favorite"
+         *
+         * @return The display name of this {@link CustomAction}.
+         */
+        public CharSequence getName() {
+            return mName;
+        }
+
+        /**
+         * Returns the resource id of the icon in the {@link MediaSession MediaSession's} package.
+         *
+         * @return The resource id of the icon in the {@link MediaSession MediaSession's} package.
+         */
+        public int getIcon() {
+            return mIcon;
+        }
+
+        /**
+         * Returns extras which provide additional application-specific information about the
+         * action, or null if none. These arguments are meant to be consumed by a
+         * {@link MediaController} if it knows how to handle them.
+         *
+         * @return Optional arguments for the {@link CustomAction}.
+         */
+        public Bundle getExtras() {
+            return mExtras;
+        }
+
+        @Override
+        public String toString() {
+            return "Action:" + "mName='" + mName + ", mIcon=" + mIcon + ", mExtras=" + mExtras;
+        }
+
+        /**
+         * Builder for {@link CustomAction} objects.
+         */
+        public static final class Builder {
+            private final String mAction;
+            private final CharSequence mName;
+            private final int mIcon;
+            private Bundle mExtras;
+
+            /**
+             * Creates a {@link CustomAction} builder with the id, name, and icon set.
+             *
+             * @param action The action of the {@link CustomAction}.
+             * @param name The display name of the {@link CustomAction}. This name will be displayed
+             *             along side the action if the UI supports it.
+             * @param icon The icon resource id of the {@link CustomAction}. This resource id
+             *             must be in the same package as the {@link MediaSession}. It will be
+             *             displayed with the custom action if the UI supports it.
+             */
+            public Builder(String action, CharSequence name, @DrawableRes int icon) {
+                if (TextUtils.isEmpty(action)) {
+                    throw new IllegalArgumentException(
+                            "You must specify an action to build a CustomAction.");
+                }
+                if (TextUtils.isEmpty(name)) {
+                    throw new IllegalArgumentException(
+                            "You must specify a name to build a CustomAction.");
+                }
+                if (icon == 0) {
+                    throw new IllegalArgumentException(
+                            "You must specify an icon resource id to build a CustomAction.");
+                }
+                mAction = action;
+                mName = name;
+                mIcon = icon;
+            }
+
+            /**
+             * Set optional extras for the {@link CustomAction}. These extras are meant to be
+             * consumed by a {@link MediaController} if it knows how to handle them.
+             * Keys should be fully qualified (e.g. "com.example.MY_ARG") to avoid collisions.
+             *
+             * @param extras Optional extras for the {@link CustomAction}.
+             * @return this.
+             */
+            public Builder setExtras(Bundle extras) {
+                mExtras = extras;
+                return this;
+            }
+
+            /**
+             * Build and return the {@link CustomAction} instance with the specified values.
+             *
+             * @return A new {@link CustomAction} instance.
+             */
+            public CustomAction build() {
+                return new CustomAction(mAction, mName, mIcon, mExtras);
+            }
+        }
+    }
+
+    /**
+     * Builder for {@link PlaybackState} objects.
+     */
+    public static final class Builder {
+        private final List<PlaybackState.CustomAction> mCustomActions = new ArrayList<>();
+
+        private int mState;
+        private long mPosition;
+        private long mBufferedPosition;
+        private float mSpeed;
+        private long mActions;
+        private CharSequence mErrorMessage;
+        private long mUpdateTime;
+        private long mActiveItemId = MediaSession.QueueItem.UNKNOWN_ID;
+        private Bundle mExtras;
+
+        /**
+         * Creates an initially empty state builder.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Creates a builder with the same initial values as those in the from
+         * state.
+         *
+         * @param from The state to use for initializing the builder.
+         */
+        public Builder(PlaybackState from) {
+            if (from == null) {
+                return;
+            }
+            mState = from.mState;
+            mPosition = from.mPosition;
+            mBufferedPosition = from.mBufferedPosition;
+            mSpeed = from.mSpeed;
+            mActions = from.mActions;
+            if (from.mCustomActions != null) {
+                mCustomActions.addAll(from.mCustomActions);
+            }
+            mErrorMessage = from.mErrorMessage;
+            mUpdateTime = from.mUpdateTime;
+            mActiveItemId = from.mActiveItemId;
+            mExtras = from.mExtras;
+        }
+
+        /**
+         * Set the current state of playback.
+         * <p>
+         * The position must be in ms and indicates the current playback
+         * position within the item. If the position is unknown use
+         * {@link #PLAYBACK_POSITION_UNKNOWN}. When not using an unknown
+         * position the time at which the position was updated must be provided.
+         * It is okay to use {@link SystemClock#elapsedRealtime()} if the
+         * current position was just retrieved.
+         * <p>
+         * The speed is a multiple of normal playback and should be 0 when
+         * paused and negative when rewinding. Normal playback speed is 1.0.
+         * <p>
+         * The state must be one of the following:
+         * <ul>
+         * <li> {@link PlaybackState#STATE_NONE}</li>
+         * <li> {@link PlaybackState#STATE_STOPPED}</li>
+         * <li> {@link PlaybackState#STATE_PLAYING}</li>
+         * <li> {@link PlaybackState#STATE_PAUSED}</li>
+         * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
+         * <li> {@link PlaybackState#STATE_REWINDING}</li>
+         * <li> {@link PlaybackState#STATE_BUFFERING}</li>
+         * <li> {@link PlaybackState#STATE_ERROR}</li>
+         * <li> {@link PlaybackState#STATE_CONNECTING}</li>
+         * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
+         * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
+         * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
+         * </ul>
+         *
+         * @param state The current state of playback.
+         * @param position The position in the current item in ms.
+         * @param playbackSpeed The current speed of playback as a multiple of
+         *            normal playback.
+         * @param updateTime The time in the {@link SystemClock#elapsedRealtime}
+         *            timebase that the position was updated at.
+         * @return this
+         */
+        public Builder setState(@State int state, long position, float playbackSpeed,
+                long updateTime) {
+            mState = state;
+            mPosition = position;
+            mUpdateTime = updateTime;
+            mSpeed = playbackSpeed;
+            return this;
+        }
+
+        /**
+         * Set the current state of playback.
+         * <p>
+         * The position must be in ms and indicates the current playback
+         * position within the item. If the position is unknown use
+         * {@link #PLAYBACK_POSITION_UNKNOWN}. The update time will be set to
+         * the current {@link SystemClock#elapsedRealtime()}.
+         * <p>
+         * The speed is a multiple of normal playback and should be 0 when
+         * paused and negative when rewinding. Normal playback speed is 1.0.
+         * <p>
+         * The state must be one of the following:
+         * <ul>
+         * <li> {@link PlaybackState#STATE_NONE}</li>
+         * <li> {@link PlaybackState#STATE_STOPPED}</li>
+         * <li> {@link PlaybackState#STATE_PLAYING}</li>
+         * <li> {@link PlaybackState#STATE_PAUSED}</li>
+         * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
+         * <li> {@link PlaybackState#STATE_REWINDING}</li>
+         * <li> {@link PlaybackState#STATE_BUFFERING}</li>
+         * <li> {@link PlaybackState#STATE_ERROR}</li>
+         * <li> {@link PlaybackState#STATE_CONNECTING}</li>
+         * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
+         * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
+         * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
+         * </ul>
+         *
+         * @param state The current state of playback.
+         * @param position The position in the current item in ms.
+         * @param playbackSpeed The current speed of playback as a multiple of
+         *            normal playback.
+         * @return this
+         */
+        public Builder setState(@State int state, long position, float playbackSpeed) {
+            return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime());
+        }
+
+        /**
+         * Set the current actions available on this session. This should use a
+         * bitmask of possible actions.
+         * <ul>
+         * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
+         * <li> {@link PlaybackState#ACTION_REWIND}</li>
+         * <li> {@link PlaybackState#ACTION_PLAY}</li>
+         * <li> {@link PlaybackState#ACTION_PAUSE}</li>
+         * <li> {@link PlaybackState#ACTION_STOP}</li>
+         * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
+         * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
+         * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
+         * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
+         * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
+         * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
+         * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
+         * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
+         * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
+         * <li> {@link PlaybackState#ACTION_PREPARE}</li>
+         * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
+         * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
+         * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
+         * </ul>
+         *
+         * @param actions The set of actions allowed.
+         * @return this
+         */
+        public Builder setActions(@Actions long actions) {
+            mActions = actions;
+            return this;
+        }
+
+        /**
+         * Add a custom action to the playback state. Actions can be used to
+         * expose additional functionality to {@link MediaController
+         * MediaControllers} beyond what is offered by the standard transport
+         * controls.
+         * <p>
+         * e.g. start a radio station based on the current item or skip ahead by
+         * 30 seconds.
+         *
+         * @param action An identifier for this action. It can be sent back to
+         *            the {@link MediaSession} through
+         *            {@link MediaController.TransportControls#sendCustomAction(String, Bundle)}.
+         * @param name The display name for the action. If text is shown with
+         *            the action or used for accessibility, this is what should
+         *            be used.
+         * @param icon The resource action of the icon that should be displayed
+         *            for the action. The resource should be in the package of
+         *            the {@link MediaSession}.
+         * @return this
+         */
+        public Builder addCustomAction(String action, String name, int icon) {
+            return addCustomAction(new PlaybackState.CustomAction(action, name, icon, null));
+        }
+
+        /**
+         * Add a custom action to the playback state. Actions can be used to expose additional
+         * functionality to {@link MediaController MediaControllers} beyond what is offered by the
+         * standard transport controls.
+         * <p>
+         * An example of an action would be to start a radio station based on the current item
+         * or to skip ahead by 30 seconds.
+         *
+         * @param customAction The custom action to add to the {@link PlaybackState}.
+         * @return this
+         */
+        public Builder addCustomAction(PlaybackState.CustomAction customAction) {
+            if (customAction == null) {
+                throw new IllegalArgumentException(
+                        "You may not add a null CustomAction to PlaybackState.");
+            }
+            mCustomActions.add(customAction);
+            return this;
+        }
+
+        /**
+         * Set the current buffered position in ms. This is the farthest
+         * playback point that can be reached from the current position using
+         * only buffered content.
+         *
+         * @param bufferedPosition The position in ms that playback is buffered
+         *            to.
+         * @return this
+         */
+        public Builder setBufferedPosition(long bufferedPosition) {
+            mBufferedPosition = bufferedPosition;
+            return this;
+        }
+
+        /**
+         * Set the active item in the play queue by specifying its id. The
+         * default value is {@link MediaSession.QueueItem#UNKNOWN_ID}
+         *
+         * @param id The id of the active item.
+         * @return this
+         */
+        public Builder setActiveQueueItemId(long id) {
+            mActiveItemId = id;
+            return this;
+        }
+
+        /**
+         * Set a user readable error message. This should be set when the state
+         * is {@link PlaybackState#STATE_ERROR}.
+         *
+         * @param error The error message for display to the user.
+         * @return this
+         */
+        public Builder setErrorMessage(CharSequence error) {
+            mErrorMessage = error;
+            return this;
+        }
+
+        /**
+         * Set any custom extras to be included with the playback state.
+         *
+         * @param extras The extras to include.
+         * @return this
+         */
+        public Builder setExtras(Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        /**
+         * Build and return the {@link PlaybackState} instance with these
+         * values.
+         *
+         * @return A new state instance.
+         */
+        public PlaybackState build() {
+            return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferedPosition,
+                    mActions, mCustomActions, mActiveItemId, mErrorMessage, mExtras);
+        }
+    }
+}
diff --git a/media/apex/java/android/media/session/SessionCallbackLink.aidl b/media/apex/java/android/media/session/SessionCallbackLink.aidl
new file mode 100644
index 0000000..c489e5b
--- /dev/null
+++ b/media/apex/java/android/media/session/SessionCallbackLink.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.session;
+
+parcelable SessionCallbackLink;
diff --git a/media/apex/java/android/media/session/SessionCallbackLink.java b/media/apex/java/android/media/session/SessionCallbackLink.java
new file mode 100644
index 0000000..3bcb65c
--- /dev/null
+++ b/media/apex/java/android/media/session/SessionCallbackLink.java
@@ -0,0 +1,958 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.media.Rating;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+
+/**
+ * Handles incoming commands to {@link MediaSession.Callback}.
+ * @hide
+ */
+@SystemApi
+public final class SessionCallbackLink implements Parcelable {
+    final Context mContext;
+    final CallbackStub mCallbackStub;
+    final ISessionCallback mISessionCallback;
+
+    /**
+     * Constructor for stub (Callee)
+     */
+    SessionCallbackLink(@NonNull Context context, @NonNull CallbackStub callbackStub) {
+        mContext = context;
+        mCallbackStub = callbackStub;
+        mISessionCallback = new CallbackStubProxy();
+    }
+
+    /**
+     * Constructor for interface (Caller)
+     */
+    public SessionCallbackLink(IBinder binder) {
+        mContext = null;
+        mCallbackStub = null;
+        mISessionCallback = ISessionCallback.Stub.asInterface(binder);
+    }
+
+    /**
+     * Notify session that a controller sends a command.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param command the name of the command
+     * @param args the arguments included with the command
+     * @param cb the result receiver for getting the result of the command
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyCommand(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull String command,
+            @Nullable Bundle args, @Nullable ResultReceiver cb) {
+        try {
+            mISessionCallback.notifyCommand(packageName, pid, uid, caller, command, args, cb);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that the android system sends a media button event.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param mediaButtonIntent the media button intent
+     * @param sequenceNumber the sequence number of this call
+     * @param cb the result receiver for getting the result of the command
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyMediaButton(@NonNull String packageName, int pid, int uid,
+            @NonNull Intent mediaButtonIntent, int sequenceNumber,
+            @Nullable ResultReceiver cb) {
+        try {
+            mISessionCallback.notifyMediaButton(packageName, pid, uid, mediaButtonIntent,
+                    sequenceNumber, cb);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller sends a media button event.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param mediaButtonIntent the media button intent
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyMediaButtonFromController(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull Intent mediaButtonIntent) {
+        try {
+            mISessionCallback.notifyMediaButtonFromController(packageName, pid, uid, caller,
+                    mediaButtonIntent);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests preparing media.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyPrepare(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyPrepare(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests preparing media from given media ID.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param mediaId the ID of the media
+     * @param extras the extras included with this request.
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyPrepareFromMediaId(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+            @Nullable Bundle extras) {
+        try {
+            mISessionCallback.notifyPrepareFromMediaId(packageName, pid, uid, caller, mediaId,
+                    extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests preparing media from given search query.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param query the search query
+     * @param extras the extras included with this request.
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyPrepareFromSearch(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull String query,
+            @Nullable Bundle extras) {
+        try {
+            mISessionCallback.notifyPrepareFromSearch(packageName, pid, uid, caller, query, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests preparing media from given uri.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param uri the uri of the media
+     * @param extras the extras included with this request.
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyPrepareFromUri(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
+        try {
+            mISessionCallback.notifyPrepareFromUri(packageName, pid, uid, caller, uri, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests playing media.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyPlay(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyPlay(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests playing media from given media ID.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param mediaId the ID of the media
+     * @param extras the extras included with this request.
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyPlayFromMediaId(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+            @Nullable Bundle extras) {
+        try {
+            mISessionCallback.notifyPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests playing media from given search query.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param query the search query
+     * @param extras the extras included with this request.
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyPlayFromSearch(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull String query,
+            @Nullable Bundle extras) {
+        try {
+            mISessionCallback.notifyPlayFromSearch(packageName, pid, uid, caller, query, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests playing media from given uri.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param uri the uri of the media
+     * @param extras the extras included with this request.
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyPlayFromUri(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
+        try {
+            mISessionCallback.notifyPlayFromUri(packageName, pid, uid, caller, uri, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests skipping to the queue item with given ID.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param id the queue id of the item
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifySkipToTrack(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, long id) {
+        try {
+            mISessionCallback.notifySkipToTrack(packageName, pid, uid, caller, id);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests pausing media.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyPause(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyPause(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests stopping media.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyStop(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyStop(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests skipping to the next queue item.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyNext(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyNext(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests skipping to the previous queue item.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyPrevious(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyPrevious(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests fast-forwarding.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyFastForward(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyFastForward(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests rewinding.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyRewind(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller) {
+        try {
+            mISessionCallback.notifyRewind(packageName, pid, uid, caller);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests seeking to the specific position.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param pos the position to move to, in milliseconds
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifySeekTo(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, long pos) {
+        try {
+            mISessionCallback.notifySeekTo(packageName, pid, uid, caller, pos);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests rating of the current media.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param rating the rating of the current media
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyRate(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull Rating rating) {
+        try {
+            mISessionCallback.notifyRate(packageName, pid, uid, caller, rating);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller sends a custom action.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param action the name of the action
+     * @param args the arguments included with this action
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyCustomAction(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, @NonNull String action, @Nullable Bundle args) {
+        try {
+            mISessionCallback.notifyCustomAction(packageName, pid, uid, caller, action, args);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests adjusting volume.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param direction the direction of the volume change.
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifyAdjustVolume(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, int direction) {
+        try {
+            mISessionCallback.notifyAdjustVolume(packageName, pid, uid, caller, direction);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notify session that a controller requests setting volume.
+     *
+     * @param packageName the package name of the controller
+     * @param pid the pid of the controller
+     * @param uid the uid of the controller
+     * @param caller the {@link ControllerCallbackLink} of the controller
+     * @param value the volume value to set
+     */
+    @RequiresPermission(Manifest.permission.MEDIA_CONTENT_CONTROL)
+    public void notifySetVolumeTo(@NonNull String packageName, int pid, int uid,
+            @NonNull ControllerCallbackLink caller, int value) {
+        try {
+            mISessionCallback.notifySetVolumeTo(packageName, pid, uid, caller, value);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Gets the binder */
+    @NonNull
+    public IBinder getBinder() {
+        return mISessionCallback.asBinder();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(mISessionCallback.asBinder());
+    }
+
+    public static final Parcelable.Creator<SessionCallbackLink> CREATOR =
+            new Parcelable.Creator<SessionCallbackLink>() {
+                @Override
+                public SessionCallbackLink createFromParcel(Parcel in) {
+                    return new SessionCallbackLink(in.readStrongBinder());
+                }
+
+                @Override
+                public SessionCallbackLink[] newArray(int size) {
+                    return new SessionCallbackLink[size];
+                }
+            };
+
+    /**
+     * Class for Stub implementation
+     */
+    abstract static class CallbackStub {
+        /** Stub method for ISessionCallback.notifyCommand */
+        public void onCommand(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull String command,
+                @Nullable Bundle args, @Nullable ResultReceiver cb) {
+        }
+
+        /** Stub method for ISessionCallback.notifyMediaButton */
+        public void onMediaButton(@NonNull String packageName, int pid, int uid,
+                @NonNull Intent mediaButtonIntent, int sequenceNumber,
+                @Nullable ResultReceiver cb) {
+        }
+
+        /** Stub method for ISessionCallback.notifyMediaButtonFromController */
+        public void onMediaButtonFromController(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull Intent mediaButtonIntent) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPrepare */
+        public void onPrepare(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPrepareFromMediaId */
+        public void onPrepareFromMediaId(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+                @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPrepareFromSearch */
+        public void onPrepareFromSearch(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, String query, @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPrepareFromUri */
+        public void onPrepareFromUri(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPlay */
+        public void onPlay(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPlayFromMediaId */
+        public void onPlayFromMediaId(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
+                @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPlayFromSearch */
+        public void onPlayFromSearch(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, String query, @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPlayFromUri */
+        public void onPlayFromUri(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISessionCallback.notifySkipToTrack */
+        public void onSkipToTrack(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, long id) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPause */
+        public void onPause(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyStop */
+        public void onStop(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyNext */
+        public void onNext(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyPrevious */
+        public void onPrevious(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyFastForward */
+        public void onFastForward(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifyRewind */
+        public void onRewind(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller) {
+        }
+
+        /** Stub method for ISessionCallback.notifySeekTo */
+        public void onSeekTo(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, long pos) {
+        }
+
+        /** Stub method for ISessionCallback.notifyRate */
+        public void onRate(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull Rating rating) {
+        }
+
+        /** Stub method for ISessionCallback.notifyCustomAction */
+        public void onCustomAction(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, @NonNull String action,
+                @Nullable Bundle args) {
+        }
+
+        /** Stub method for ISessionCallback.notifyAdjustVolume */
+        public void onAdjustVolume(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, int direction) {
+        }
+
+        /** Stub method for ISessionCallback.notifySetVolumeTo */
+        public void onSetVolumeTo(@NonNull String packageName, int pid, int uid,
+                @NonNull ControllerCallbackLink caller, int value) {
+        }
+    }
+
+    private class CallbackStubProxy extends ISessionCallback.Stub {
+        @Override
+        public void notifyCommand(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onCommand(packageName, pid, uid, caller, command, args, cb);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyMediaButton(String packageName, int pid, int uid,
+                Intent mediaButtonIntent, int sequenceNumber, ResultReceiver cb) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onMediaButton(packageName, pid, uid, mediaButtonIntent,
+                        sequenceNumber, cb);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyMediaButtonFromController(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, Intent mediaButtonIntent) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onMediaButtonFromController(packageName, pid, uid, caller,
+                        mediaButtonIntent);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyPrepare(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onPrepare(packageName, pid, uid, caller);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyPrepareFromMediaId(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String mediaId, Bundle extras) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyPrepareFromSearch(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String query, Bundle extras) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onPrepareFromSearch(packageName, pid, uid, caller, query, extras);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyPrepareFromUri(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, Uri uri, Bundle extras) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onPrepareFromUri(packageName, pid, uid, caller, uri, extras);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyPlay(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onPlay(packageName, pid, uid, caller);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyPlayFromMediaId(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String mediaId, Bundle extras) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyPlayFromSearch(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String query, Bundle extras) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onPlayFromSearch(packageName, pid, uid, caller, query, extras);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyPlayFromUri(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, Uri uri, Bundle extras) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onPlayFromUri(packageName, pid, uid, caller, uri, extras);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifySkipToTrack(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, long id) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onSkipToTrack(packageName, pid, uid, caller, id);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyPause(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onPause(packageName, pid, uid, caller);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyStop(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onStop(packageName, pid, uid, caller);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyNext(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onNext(packageName, pid, uid, caller);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyPrevious(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onPrevious(packageName, pid, uid, caller);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyFastForward(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onFastForward(packageName, pid, uid, caller);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyRewind(String packageName, int pid, int uid,
+                ControllerCallbackLink caller) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onRewind(packageName, pid, uid, caller);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifySeekTo(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, long pos) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onSeekTo(packageName, pid, uid, caller, pos);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyRate(String packageName, int pid, int uid, ControllerCallbackLink caller,
+                Rating rating) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onRate(packageName, pid, uid, caller, rating);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        public void notifyCustomAction(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, String action, Bundle args) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onCustomAction(packageName, pid, uid, caller, action, args);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyAdjustVolume(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, int direction) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onAdjustVolume(packageName, pid, uid, caller, direction);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifySetVolumeTo(String packageName, int pid, int uid,
+                ControllerCallbackLink caller, int value) {
+            ensureMediaControlPermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mCallbackStub.onSetVolumeTo(packageName, pid, uid, caller, value);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        private void ensureMediaControlPermission() {
+            // Check if it's system server or has MEDIA_CONTENT_CONTROL.
+            // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
+            // check here.
+            if (getCallingUid() == Process.SYSTEM_UID || mContext.checkCallingPermission(
+                    android.Manifest.permission.MEDIA_CONTENT_CONTROL)
+                    == PackageManager.PERMISSION_GRANTED) {
+                return;
+            }
+            throw new SecurityException("Must hold the MEDIA_CONTENT_CONTROL permission.");
+        }
+    }
+}
diff --git a/media/apex/java/android/media/session/SessionLink.aidl b/media/apex/java/android/media/session/SessionLink.aidl
new file mode 100644
index 0000000..c3be23e
--- /dev/null
+++ b/media/apex/java/android/media/session/SessionLink.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+parcelable SessionLink;
diff --git a/media/apex/java/android/media/session/SessionLink.java b/media/apex/java/android/media/session/SessionLink.java
new file mode 100644
index 0000000..4ea7623
--- /dev/null
+++ b/media/apex/java/android/media/session/SessionLink.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.PendingIntent;
+import android.media.AudioAttributes;
+import android.media.MediaMetadata;
+import android.media.MediaParceledListSlice;
+import android.media.session.MediaSession.QueueItem;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import java.util.List;
+
+/**
+ * Handles incoming commands from {@link MediaSession}.
+ * @hide
+ */
+@SystemApi
+public final class SessionLink implements Parcelable {
+    public static final Parcelable.Creator<SessionLink> CREATOR =
+            new Parcelable.Creator<SessionLink>() {
+                @Override
+                public SessionLink createFromParcel(Parcel in) {
+                    return new SessionLink(in.readStrongBinder());
+                }
+
+                @Override
+                public SessionLink[] newArray(int size) {
+                    return new SessionLink[size];
+                }
+            };
+
+    final SessionStub mSessionStub;
+    final ISession mISession;
+
+    /**
+     * Constructor for stub (Callee)
+     */
+    public SessionLink(@NonNull SessionStub sessionStub) {
+        mSessionStub = sessionStub;
+        mISession = new StubProxy();
+    }
+
+    /**
+     * Constructor for interface (Caller)
+     */
+    public SessionLink(IBinder binder) {
+        mSessionStub = null;
+        mISession = ISession.Stub.asInterface(binder);
+    }
+
+    /**
+     * Tell system that the session sends an event to all the connected controllers.
+     *
+     * @param event the name of the event
+     * @param extras the extras included with the event
+     */
+    void sendEvent(@NonNull String event, @Nullable Bundle extras) {
+        try {
+            mISession.sendEvent(event, extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Gets the controller link from the system.
+     */
+    @NonNull
+    ControllerLink getController() {
+        try {
+            return mISession.getController();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session sets the flags.
+     *
+     * @param flags the new session flags
+     */
+    void setFlags(int flags) {
+        try {
+            mISession.setFlags(flags);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session is (in)active.
+     *
+     * @param active the new activeness state
+     */
+    void setActive(boolean active) {
+        try {
+            mISession.setActive(active);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session sets the media button receiver.
+     *
+     * @param mbr the pending intent for media button receiver
+     */
+    void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
+        try {
+            mISession.setMediaButtonReceiver(mbr);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session sets the pending intent for launching UI.
+     *
+     * @param pi the pending intent for launching UI
+     */
+    void setLaunchPendingIntent(@Nullable PendingIntent pi) {
+        try {
+            mISession.setLaunchPendingIntent(pi);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session is destroyed.
+     */
+    void destroySession() {
+        try {
+            mISession.destroySession();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session sets the new metadata.
+     *
+     * @param metadata the new metadata
+     * @param duration the duration of the media in milliseconds
+     * @param metadataDescription the description of the metadata
+     */
+    void setMetadata(@Nullable MediaMetadata metadata, long duration,
+            @Nullable String metadataDescription) {
+        try {
+            mISession.setMetadata(metadata, duration, metadataDescription);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session sets the new playback state.
+     *
+     * @param state the new playback state
+     */
+    void setPlaybackState(@Nullable PlaybackState state) {
+        try {
+            mISession.setPlaybackState(state);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session sets the new queue.
+     *
+     * @param queue the new queue
+     */
+    void setQueue(@Nullable List<QueueItem> queue) {
+        try {
+            mISession.setQueue(queue == null ? null : new MediaParceledListSlice(queue));
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session sets the new queue title.
+     *
+     * @param title the new queue title
+     */
+    void setQueueTitle(@Nullable CharSequence title) {
+        try {
+            mISession.setQueueTitle(title);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session sets the new extras.
+     *
+     * @param extras the new extras
+     */
+    void setExtras(@Nullable Bundle extras) {
+        try {
+            mISession.setExtras(extras);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session sets the new rating type of the current media.
+     *
+     * @param type the rating type.
+     */
+    void setRatingType(int type) {
+        try {
+            mISession.setRatingType(type);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session represents a local playback.
+     *
+     * @param attributes the audio attributes of the local playback.
+     */
+    void setPlaybackToLocal(@NonNull AudioAttributes attributes) {
+        try {
+            mISession.setPlaybackToLocal(attributes);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session represents a remote playback.
+     *
+     * @param control the volume control type
+     * @param max the max volume
+     */
+    void setPlaybackToRemote(int control, int max) {
+        try {
+            mISession.setPlaybackToRemote(control, max);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Tell system that the session sets the new current volume.
+     *
+     * @param currentVolume the new current volume
+     */
+    void setCurrentVolume(int currentVolume) {
+        try {
+            mISession.setCurrentVolume(currentVolume);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Gets the binder */
+    @NonNull
+    public IBinder getBinder() {
+        return mISession.asBinder();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeStrongBinder(mISession.asBinder());
+    }
+
+    /**
+     * Class for Stub implementation
+     */
+    public abstract static class SessionStub {
+        /** Stub method for ISession.sendEvent */
+        public void sendEvent(@NonNull String event, @Nullable Bundle data) {
+        }
+
+        /** Stub method for ISession.getController */
+        @NonNull
+        public ControllerLink getController() {
+            return null;
+        }
+
+        /** Stub method for ISession.setFlags */
+        public void setFlags(int flags) {
+        }
+
+        /** Stub method for ISession.setActive */
+        public void setActive(boolean active) {
+        }
+
+        /** Stub method for ISession.setMediaButtonReceiver */
+        public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
+        }
+
+        /** Stub method for ISession.setLaunchPendingIntent */
+        public void setLaunchPendingIntent(@Nullable PendingIntent pi) {
+        }
+
+        /** Stub method for ISession.destroySession */
+        public void destroySession() {
+        }
+
+        /** Stub method for ISession.setMetadata */
+        public void setMetadata(@Nullable MediaMetadata metadata, long duration,
+                @Nullable String metadataDescription) {
+        }
+
+        /** Stub method for ISession.setPlaybackState */
+        public void setPlaybackState(@Nullable PlaybackState state) {
+        }
+
+        /** Stub method for ISession.setQueue */
+        public void setQueue(@Nullable List<QueueItem> queue) {
+        }
+
+        /** Stub method for ISession.setQueueTitle */
+        public void setQueueTitle(@Nullable CharSequence title) {
+        }
+
+        /** Stub method for ISession.setExtras */
+        public void setExtras(@Nullable Bundle extras) {
+        }
+
+        /** Stub method for ISession.setRatingType */
+        public void setRatingType(int type) {
+        }
+
+        /** Stub method for ISession.setPlaybackToLocal */
+        public void setPlaybackToLocal(@NonNull AudioAttributes attributes) {
+        }
+
+        /** Stub method for ISession.setPlaybackToRemote */
+        public void setPlaybackToRemote(int control, int max) {
+        }
+
+        /** Stub method for ISession.setCurrentVolume */
+        public void setCurrentVolume(int currentVolume) {
+        }
+    }
+
+    private class StubProxy extends ISession.Stub {
+        @Override
+        public void sendEvent(String event, Bundle data) {
+            mSessionStub.sendEvent(event, data);
+        }
+
+        @Override
+        public ControllerLink getController() {
+            return mSessionStub.getController();
+        }
+
+        @Override
+        public void setFlags(int flags) {
+            mSessionStub.setFlags(flags);
+        }
+
+        @Override
+        public void setActive(boolean active) {
+            mSessionStub.setActive(active);
+        }
+
+        @Override
+        public void setMediaButtonReceiver(PendingIntent mbr) {
+            mSessionStub.setMediaButtonReceiver(mbr);
+        }
+
+        @Override
+        public void setLaunchPendingIntent(PendingIntent pi) {
+            mSessionStub.setLaunchPendingIntent(pi);
+        }
+
+        @Override
+        public void destroySession() {
+            mSessionStub.destroySession();
+        }
+
+        @Override
+        public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription) {
+            mSessionStub.setMetadata(metadata, duration, metadataDescription);
+        }
+
+        @Override
+        public void setPlaybackState(PlaybackState state) {
+            mSessionStub.setPlaybackState(state);
+        }
+
+        @Override
+        public void setQueue(MediaParceledListSlice queue) {
+            mSessionStub.setQueue(queue == null ? null : queue.getList());
+        }
+
+        @Override
+        public void setQueueTitle(CharSequence title) {
+            mSessionStub.setQueueTitle(title);
+        }
+
+        @Override
+        public void setExtras(Bundle extras) {
+            mSessionStub.setExtras(extras);
+        }
+
+        @Override
+        public void setRatingType(int type) {
+            mSessionStub.setRatingType(type);
+        }
+
+        @Override
+        public void setPlaybackToLocal(AudioAttributes attributes) {
+            mSessionStub.setPlaybackToLocal(attributes);
+        }
+
+        @Override
+        public void setPlaybackToRemote(int control, int max) {
+            mSessionStub.setPlaybackToRemote(control, max);
+        }
+
+        @Override
+        public void setCurrentVolume(int currentVolume) {
+            mSessionStub.setCurrentVolume(currentVolume);
+        }
+    }
+}
diff --git a/media/apex/java/android/service/media/IMediaBrowserService.aidl b/media/apex/java/android/service/media/IMediaBrowserService.aidl
new file mode 100644
index 0000000..1c50ec7
--- /dev/null
+++ b/media/apex/java/android/service/media/IMediaBrowserService.aidl
@@ -0,0 +1,25 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+
+package android.service.media;
+
+import android.service.media.IMediaBrowserServiceCallbacks;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+
+/**
+ * Media API allows clients to browse through hierarchy of a user’s media collection,
+ * playback a specific media entry and interact with the now playing queue.
+ * @hide
+ */
+oneway interface IMediaBrowserService {
+    void connect(String pkg, in Bundle rootHints, IMediaBrowserServiceCallbacks callbacks);
+    void disconnect(IMediaBrowserServiceCallbacks callbacks);
+
+    void addSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks);
+    void removeSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks);
+
+    void getMediaItem(String uri, in ResultReceiver cb, IMediaBrowserServiceCallbacks callbacks);
+    void addSubscription(String uri, in IBinder token, in Bundle options,
+            IMediaBrowserServiceCallbacks callbacks);
+    void removeSubscription(String uri, in IBinder token, IMediaBrowserServiceCallbacks callbacks);
+}
diff --git a/media/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/media/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
new file mode 100644
index 0000000..507a8f7
--- /dev/null
+++ b/media/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
@@ -0,0 +1,27 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+
+package android.service.media;
+
+import android.media.MediaParceledListSlice;
+import android.media.session.MediaSession;
+import android.os.Bundle;
+
+/**
+ * Media API allows clients to browse through hierarchy of a user’s media collection,
+ * playback a specific media entry and interact with the now playing queue.
+ * @hide
+ */
+oneway interface IMediaBrowserServiceCallbacks {
+    /**
+     * Invoked when the connected has been established.
+     * @param root The root media id for browsing.
+     * @param session The {@link MediaSession.Token media session token} that can be used to control
+     *         the playback of the media app.
+     * @param extra Extras returned by the media service.
+     */
+    void onConnect(String root, in MediaSession.Token session, in Bundle extras);
+    void onConnectFailed();
+    void onLoadChildren(String mediaId, in MediaParceledListSlice list);
+    void onLoadChildrenWithOptions(String mediaId, in MediaParceledListSlice list,
+            in Bundle options);
+}
diff --git a/media/apex/java/android/service/media/MediaBrowserService.java b/media/apex/java/android/service/media/MediaBrowserService.java
new file mode 100644
index 0000000..d9ef6ae
--- /dev/null
+++ b/media/apex/java/android/service/media/MediaBrowserService.java
@@ -0,0 +1,854 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.media;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.UnsupportedAppUsage;
+import android.app.Service;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.media.MediaParceledListSlice;
+import android.media.browse.MediaBrowser;
+import android.media.browse.MediaBrowserUtils;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
+import android.media.session.MediaSessionManager.RemoteUserInfo;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Base class for media browser services.
+ * <p>
+ * Media browser services enable applications to browse media content provided by an application
+ * and ask the application to start playing it. They may also be used to control content that
+ * is already playing by way of a {@link MediaSession}.
+ * </p>
+ *
+ * To extend this class, you must declare the service in your manifest file with
+ * an intent filter with the {@link #SERVICE_INTERFACE} action.
+ *
+ * For example:
+ * </p><pre>
+ * &lt;service android:name=".MyMediaBrowserService"
+ *          android:label="&#64;string/service_name" >
+ *     &lt;intent-filter>
+ *         &lt;action android:name="android.media.browse.MediaBrowserService" />
+ *     &lt;/intent-filter>
+ * &lt;/service>
+ * </pre>
+ *
+ */
+public abstract class MediaBrowserService extends Service {
+    private static final String TAG = "MediaBrowserService";
+    private static final boolean DBG = false;
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
+
+    /**
+     * A key for passing the MediaItem to the ResultReceiver in getItem.
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public static final String KEY_MEDIA_ITEM = "media_item";
+
+    private static final int RESULT_FLAG_OPTION_NOT_HANDLED = 1 << 0;
+    private static final int RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED = 1 << 1;
+
+    private static final int RESULT_ERROR = -1;
+    private static final int RESULT_OK = 0;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = { RESULT_FLAG_OPTION_NOT_HANDLED,
+            RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED })
+    private @interface ResultFlags { }
+
+    private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>();
+    private ConnectionRecord mCurConnection;
+    private final Handler mHandler = new Handler();
+    private ServiceBinder mBinder;
+    MediaSession.Token mSession;
+
+    /**
+     * All the info about a connection.
+     */
+    private class ConnectionRecord implements IBinder.DeathRecipient {
+        String pkg;
+        int uid;
+        int pid;
+        Bundle rootHints;
+        IMediaBrowserServiceCallbacks callbacks;
+        BrowserRoot root;
+        HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>();
+
+        @Override
+        public void binderDied() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mConnections.remove(callbacks.asBinder());
+                }
+            });
+        }
+    }
+
+    /**
+     * Completion handler for asynchronous callback methods in {@link MediaBrowserService}.
+     * <p>
+     * Each of the methods that takes one of these to send the result must call
+     * {@link #sendResult} to respond to the caller with the given results. If those
+     * functions return without calling {@link #sendResult}, they must instead call
+     * {@link #detach} before returning, and then may call {@link #sendResult} when
+     * they are done. If more than one of those methods is called, an exception will
+     * be thrown.
+     *
+     * @see #onLoadChildren
+     * @see #onLoadItem
+     */
+    public class Result<T> {
+        private Object mDebug;
+        private boolean mDetachCalled;
+        private boolean mSendResultCalled;
+        @UnsupportedAppUsage
+        private int mFlags;
+
+        Result(Object debug) {
+            mDebug = debug;
+        }
+
+        /**
+         * Send the result back to the caller.
+         */
+        public void sendResult(T result) {
+            if (mSendResultCalled) {
+                throw new IllegalStateException("sendResult() called twice for: " + mDebug);
+            }
+            mSendResultCalled = true;
+            onResultSent(result, mFlags);
+        }
+
+        /**
+         * Detach this message from the current thread and allow the {@link #sendResult}
+         * call to happen later.
+         */
+        public void detach() {
+            if (mDetachCalled) {
+                throw new IllegalStateException("detach() called when detach() had already"
+                        + " been called for: " + mDebug);
+            }
+            if (mSendResultCalled) {
+                throw new IllegalStateException("detach() called when sendResult() had already"
+                        + " been called for: " + mDebug);
+            }
+            mDetachCalled = true;
+        }
+
+        boolean isDone() {
+            return mDetachCalled || mSendResultCalled;
+        }
+
+        void setFlags(@ResultFlags int flags) {
+            mFlags = flags;
+        }
+
+        /**
+         * Called when the result is sent, after assertions about not being called twice
+         * have happened.
+         */
+        void onResultSent(T result, @ResultFlags int flags) {
+        }
+    }
+
+    private class ServiceBinder extends IMediaBrowserService.Stub {
+        @Override
+        public void connect(final String pkg, final Bundle rootHints,
+                final IMediaBrowserServiceCallbacks callbacks) {
+
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            if (!isValidPackage(pkg, uid)) {
+                throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid
+                        + " package=" + pkg);
+            }
+
+            mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        final IBinder b = callbacks.asBinder();
+
+                        // Clear out the old subscriptions. We are getting new ones.
+                        mConnections.remove(b);
+
+                        final ConnectionRecord connection = new ConnectionRecord();
+                        connection.pkg = pkg;
+                        connection.pid = pid;
+                        connection.uid = uid;
+                        connection.rootHints = rootHints;
+                        connection.callbacks = callbacks;
+
+                        mCurConnection = connection;
+                        connection.root = MediaBrowserService.this.onGetRoot(pkg, uid, rootHints);
+                        mCurConnection = null;
+
+                        // If they didn't return something, don't allow this client.
+                        if (connection.root == null) {
+                            Log.i(TAG, "No root for client " + pkg + " from service "
+                                    + getClass().getName());
+                            try {
+                                callbacks.onConnectFailed();
+                            } catch (RemoteException ex) {
+                                Log.w(TAG, "Calling onConnectFailed() failed. Ignoring. "
+                                        + "pkg=" + pkg);
+                            }
+                        } else {
+                            try {
+                                mConnections.put(b, connection);
+                                b.linkToDeath(connection, 0);
+                                if (mSession != null) {
+                                    callbacks.onConnect(connection.root.getRootId(),
+                                            mSession, connection.root.getExtras());
+                                }
+                            } catch (RemoteException ex) {
+                                Log.w(TAG, "Calling onConnect() failed. Dropping client. "
+                                        + "pkg=" + pkg);
+                                mConnections.remove(b);
+                            }
+                        }
+                    }
+                });
+        }
+
+        @Override
+        public void disconnect(final IMediaBrowserServiceCallbacks callbacks) {
+            mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        final IBinder b = callbacks.asBinder();
+
+                        // Clear out the old subscriptions. We are getting new ones.
+                        final ConnectionRecord old = mConnections.remove(b);
+                        if (old != null) {
+                            // TODO
+                            old.callbacks.asBinder().unlinkToDeath(old, 0);
+                        }
+                    }
+                });
+        }
+
+        @Override
+        public void addSubscriptionDeprecated(String id, IMediaBrowserServiceCallbacks callbacks) {
+            // do-nothing
+        }
+
+        @Override
+        public void addSubscription(final String id, final IBinder token, final Bundle options,
+                final IMediaBrowserServiceCallbacks callbacks) {
+            mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        final IBinder b = callbacks.asBinder();
+
+                        // Get the record for the connection
+                        final ConnectionRecord connection = mConnections.get(b);
+                        if (connection == null) {
+                            Log.w(TAG, "addSubscription for callback that isn't registered id="
+                                    + id);
+                            return;
+                        }
+
+                        MediaBrowserService.this.addSubscription(id, connection, token, options);
+                    }
+                });
+        }
+
+        @Override
+        public void removeSubscriptionDeprecated(
+                String id, IMediaBrowserServiceCallbacks callbacks) {
+            // do-nothing
+        }
+
+        @Override
+        public void removeSubscription(final String id, final IBinder token,
+                final IMediaBrowserServiceCallbacks callbacks) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    final IBinder b = callbacks.asBinder();
+
+                    ConnectionRecord connection = mConnections.get(b);
+                    if (connection == null) {
+                        Log.w(TAG, "removeSubscription for callback that isn't registered id="
+                                + id);
+                        return;
+                    }
+                    if (!MediaBrowserService.this.removeSubscription(id, connection, token)) {
+                        Log.w(TAG, "removeSubscription called for " + id
+                                + " which is not subscribed");
+                    }
+                }
+            });
+        }
+
+        @Override
+        public void getMediaItem(final String mediaId, final ResultReceiver receiver,
+                final IMediaBrowserServiceCallbacks callbacks) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    final IBinder b = callbacks.asBinder();
+                    ConnectionRecord connection = mConnections.get(b);
+                    if (connection == null) {
+                        Log.w(TAG, "getMediaItem for callback that isn't registered id=" + mediaId);
+                        return;
+                    }
+                    performLoadItem(mediaId, connection, receiver);
+                }
+            });
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mBinder = new ServiceBinder();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            return mBinder;
+        }
+        return null;
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+    }
+
+    /**
+     * Called to get the root information for browsing by a particular client.
+     * <p>
+     * The implementation should verify that the client package has permission
+     * to access browse media information before returning the root id; it
+     * should return null if the client is not allowed to access this
+     * information.
+     * </p>
+     *
+     * @param clientPackageName The package name of the application which is
+     *            requesting access to browse media.
+     * @param clientUid The uid of the application which is requesting access to
+     *            browse media.
+     * @param rootHints An optional bundle of service-specific arguments to send
+     *            to the media browser service when connecting and retrieving the
+     *            root id for browsing, or null if none. The contents of this
+     *            bundle may affect the information returned when browsing.
+     * @return The {@link BrowserRoot} for accessing this app's content or null.
+     * @see BrowserRoot#EXTRA_RECENT
+     * @see BrowserRoot#EXTRA_OFFLINE
+     * @see BrowserRoot#EXTRA_SUGGESTED
+     */
+    public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
+            int clientUid, @Nullable Bundle rootHints);
+
+    /**
+     * Called to get information about the children of a media item.
+     * <p>
+     * Implementations must call {@link Result#sendResult result.sendResult}
+     * with the list of children. If loading the children will be an expensive
+     * operation that should be performed on another thread,
+     * {@link Result#detach result.detach} may be called before returning from
+     * this function, and then {@link Result#sendResult result.sendResult}
+     * called when the loading is complete.
+     * </p><p>
+     * In case the media item does not have any children, call {@link Result#sendResult}
+     * with an empty list. When the given {@code parentId} is invalid, implementations must
+     * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
+     * {@link MediaBrowser.SubscriptionCallback#onError}.
+     * </p>
+     *
+     * @param parentId The id of the parent media item whose children are to be
+     *            queried.
+     * @param result The Result to send the list of children to.
+     */
+    public abstract void onLoadChildren(@NonNull String parentId,
+            @NonNull Result<List<MediaBrowser.MediaItem>> result);
+
+    /**
+     * Called to get information about the children of a media item.
+     * <p>
+     * Implementations must call {@link Result#sendResult result.sendResult}
+     * with the list of children. If loading the children will be an expensive
+     * operation that should be performed on another thread,
+     * {@link Result#detach result.detach} may be called before returning from
+     * this function, and then {@link Result#sendResult result.sendResult}
+     * called when the loading is complete.
+     * </p><p>
+     * In case the media item does not have any children, call {@link Result#sendResult}
+     * with an empty list. When the given {@code parentId} is invalid, implementations must
+     * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
+     * {@link MediaBrowser.SubscriptionCallback#onError}.
+     * </p>
+     *
+     * @param parentId The id of the parent media item whose children are to be
+     *            queried.
+     * @param result The Result to send the list of children to.
+     * @param options The bundle of service-specific arguments sent from the media
+     *            browser. The information returned through the result should be
+     *            affected by the contents of this bundle.
+     */
+    public void onLoadChildren(@NonNull String parentId,
+            @NonNull Result<List<MediaBrowser.MediaItem>> result, @NonNull Bundle options) {
+        // To support backward compatibility, when the implementation of MediaBrowserService doesn't
+        // override onLoadChildren() with options, onLoadChildren() without options will be used
+        // instead, and the options will be applied in the implementation of result.onResultSent().
+        result.setFlags(RESULT_FLAG_OPTION_NOT_HANDLED);
+        onLoadChildren(parentId, result);
+    }
+
+    /**
+     * Called to get information about a specific media item.
+     * <p>
+     * Implementations must call {@link Result#sendResult result.sendResult}. If
+     * loading the item will be an expensive operation {@link Result#detach
+     * result.detach} may be called before returning from this function, and
+     * then {@link Result#sendResult result.sendResult} called when the item has
+     * been loaded.
+     * </p><p>
+     * When the given {@code itemId} is invalid, implementations must call
+     * {@link Result#sendResult result.sendResult} with {@code null}.
+     * </p><p>
+     * The default implementation will invoke {@link MediaBrowser.ItemCallback#onError}.
+     * </p>
+     *
+     * @param itemId The id for the specific
+     *            {@link android.media.browse.MediaBrowser.MediaItem}.
+     * @param result The Result to send the item to.
+     */
+    public void onLoadItem(String itemId, Result<MediaBrowser.MediaItem> result) {
+        result.setFlags(RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED);
+        result.sendResult(null);
+    }
+
+    /**
+     * Call to set the media session.
+     * <p>
+     * This should be called as soon as possible during the service's startup.
+     * It may only be called once.
+     *
+     * @param token The token for the service's {@link MediaSession}.
+     */
+    public void setSessionToken(final MediaSession.Token token) {
+        if (token == null) {
+            throw new IllegalArgumentException("Session token may not be null.");
+        }
+        if (mSession != null) {
+            throw new IllegalStateException("The session token has already been set.");
+        }
+        mSession = token;
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                Iterator<ConnectionRecord> iter = mConnections.values().iterator();
+                while (iter.hasNext()) {
+                    ConnectionRecord connection = iter.next();
+                    try {
+                        connection.callbacks.onConnect(connection.root.getRootId(), token,
+                                connection.root.getExtras());
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Connection for " + connection.pkg + " is no longer valid.");
+                        iter.remove();
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Gets the session token, or null if it has not yet been created
+     * or if it has been destroyed.
+     */
+    public @Nullable MediaSession.Token getSessionToken() {
+        return mSession;
+    }
+
+    /**
+     * Gets the root hints sent from the currently connected {@link MediaBrowser}.
+     * The root hints are service-specific arguments included in an optional bundle sent to the
+     * media browser service when connecting and retrieving the root id for browsing, or null if
+     * none. The contents of this bundle may affect the information returned when browsing.
+     *
+     * @throws IllegalStateException If this method is called outside of {@link #onGetRoot} or
+     *             {@link #onLoadChildren} or {@link #onLoadItem}.
+     * @see MediaBrowserService.BrowserRoot#EXTRA_RECENT
+     * @see MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
+     * @see MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
+     */
+    public final Bundle getBrowserRootHints() {
+        if (mCurConnection == null) {
+            throw new IllegalStateException("This should be called inside of onGetRoot or"
+                    + " onLoadChildren or onLoadItem methods");
+        }
+        return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints);
+    }
+
+    /**
+     * Gets the browser information who sent the current request.
+     *
+     * @throws IllegalStateException If this method is called outside of {@link #onGetRoot} or
+     *             {@link #onLoadChildren} or {@link #onLoadItem}.
+     * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
+     */
+    public final RemoteUserInfo getCurrentBrowserInfo() {
+        if (mCurConnection == null) {
+            throw new IllegalStateException("This should be called inside of onGetRoot or"
+                    + " onLoadChildren or onLoadItem methods");
+        }
+        return new RemoteUserInfo(mCurConnection.pkg, mCurConnection.pid, mCurConnection.uid);
+    }
+
+    /**
+     * Notifies all connected media browsers that the children of
+     * the specified parent id have changed in some way.
+     * This will cause browsers to fetch subscribed content again.
+     *
+     * @param parentId The id of the parent media item whose
+     * children changed.
+     */
+    public void notifyChildrenChanged(@NonNull String parentId) {
+        notifyChildrenChangedInternal(parentId, null);
+    }
+
+    /**
+     * Notifies all connected media browsers that the children of
+     * the specified parent id have changed in some way.
+     * This will cause browsers to fetch subscribed content again.
+     *
+     * @param parentId The id of the parent media item whose
+     *            children changed.
+     * @param options The bundle of service-specific arguments to send
+     *            to the media browser. The contents of this bundle may
+     *            contain the information about the change.
+     */
+    public void notifyChildrenChanged(@NonNull String parentId, @NonNull Bundle options) {
+        if (options == null) {
+            throw new IllegalArgumentException("options cannot be null in notifyChildrenChanged");
+        }
+        notifyChildrenChangedInternal(parentId, options);
+    }
+
+    private void notifyChildrenChangedInternal(final String parentId, final Bundle options) {
+        if (parentId == null) {
+            throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged");
+        }
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                for (IBinder binder : mConnections.keySet()) {
+                    ConnectionRecord connection = mConnections.get(binder);
+                    List<Pair<IBinder, Bundle>> callbackList =
+                            connection.subscriptions.get(parentId);
+                    if (callbackList != null) {
+                        for (Pair<IBinder, Bundle> callback : callbackList) {
+                            if (MediaBrowserUtils.hasDuplicatedItems(options, callback.second)) {
+                                performLoadChildren(parentId, connection, callback.second);
+                            }
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Return whether the given package is one of the ones that is owned by the uid.
+     */
+    private boolean isValidPackage(String pkg, int uid) {
+        if (pkg == null) {
+            return false;
+        }
+        final PackageManager pm = getPackageManager();
+        final String[] packages = pm.getPackagesForUid(uid);
+        final int N = packages.length;
+        for (int i = 0; i < N; i++) {
+            if (packages[i].equals(pkg)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Save the subscription and if it is a new subscription send the results.
+     */
+    private void addSubscription(String id, ConnectionRecord connection, IBinder token,
+            Bundle options) {
+        // Save the subscription
+        List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id);
+        if (callbackList == null) {
+            callbackList = new ArrayList<>();
+        }
+        for (Pair<IBinder, Bundle> callback : callbackList) {
+            if (token == callback.first
+                    && MediaBrowserUtils.areSameOptions(options, callback.second)) {
+                return;
+            }
+        }
+        callbackList.add(new Pair<>(token, options));
+        connection.subscriptions.put(id, callbackList);
+        // send the results
+        performLoadChildren(id, connection, options);
+    }
+
+    /**
+     * Remove the subscription.
+     */
+    private boolean removeSubscription(String id, ConnectionRecord connection, IBinder token) {
+        if (token == null) {
+            return connection.subscriptions.remove(id) != null;
+        }
+        boolean removed = false;
+        List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id);
+        if (callbackList != null) {
+            Iterator<Pair<IBinder, Bundle>> iter = callbackList.iterator();
+            while (iter.hasNext()) {
+                if (token == iter.next().first) {
+                    removed = true;
+                    iter.remove();
+                }
+            }
+            if (callbackList.size() == 0) {
+                connection.subscriptions.remove(id);
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Call onLoadChildren and then send the results back to the connection.
+     * <p>
+     * Callers must make sure that this connection is still connected.
+     */
+    private void performLoadChildren(final String parentId, final ConnectionRecord connection,
+            final Bundle options) {
+        final Result<List<MediaBrowser.MediaItem>> result =
+                new Result<List<MediaBrowser.MediaItem>>(parentId) {
+            @Override
+            void onResultSent(List<MediaBrowser.MediaItem> list, @ResultFlags int flag) {
+                if (mConnections.get(connection.callbacks.asBinder()) != connection) {
+                    if (DBG) {
+                        Log.d(TAG, "Not sending onLoadChildren result for connection that has"
+                                + " been disconnected. pkg=" + connection.pkg + " id=" + parentId);
+                    }
+                    return;
+                }
+
+                List<MediaBrowser.MediaItem> filteredList =
+                        (flag & RESULT_FLAG_OPTION_NOT_HANDLED) != 0
+                                ? applyOptions(list, options) : list;
+                final MediaParceledListSlice<MediaBrowser.MediaItem> pls =
+                        filteredList == null ? null : new MediaParceledListSlice<>(filteredList);
+                try {
+                    connection.callbacks.onLoadChildrenWithOptions(parentId, pls, options);
+                } catch (RemoteException ex) {
+                    // The other side is in the process of crashing.
+                    Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId
+                            + " package=" + connection.pkg);
+                }
+            }
+        };
+
+        mCurConnection = connection;
+        if (options == null) {
+            onLoadChildren(parentId, result);
+        } else {
+            onLoadChildren(parentId, result, options);
+        }
+        mCurConnection = null;
+
+        if (!result.isDone()) {
+            throw new IllegalStateException("onLoadChildren must call detach() or sendResult()"
+                    + " before returning for package=" + connection.pkg + " id=" + parentId);
+        }
+    }
+
+    private List<MediaBrowser.MediaItem> applyOptions(List<MediaBrowser.MediaItem> list,
+            final Bundle options) {
+        if (list == null) {
+            return null;
+        }
+        int page = options.getInt(MediaBrowser.EXTRA_PAGE, -1);
+        int pageSize = options.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
+        if (page == -1 && pageSize == -1) {
+            return list;
+        }
+        int fromIndex = pageSize * page;
+        int toIndex = fromIndex + pageSize;
+        if (page < 0 || pageSize < 1 || fromIndex >= list.size()) {
+            return Collections.EMPTY_LIST;
+        }
+        if (toIndex > list.size()) {
+            toIndex = list.size();
+        }
+        return list.subList(fromIndex, toIndex);
+    }
+
+    private void performLoadItem(String itemId, final ConnectionRecord connection,
+            final ResultReceiver receiver) {
+        final Result<MediaBrowser.MediaItem> result =
+                new Result<MediaBrowser.MediaItem>(itemId) {
+            @Override
+            void onResultSent(MediaBrowser.MediaItem item, @ResultFlags int flag) {
+                if (mConnections.get(connection.callbacks.asBinder()) != connection) {
+                    if (DBG) {
+                        Log.d(TAG, "Not sending onLoadItem result for connection that has"
+                                + " been disconnected. pkg=" + connection.pkg + " id=" + itemId);
+                    }
+                    return;
+                }
+                if ((flag & RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED) != 0) {
+                    receiver.send(RESULT_ERROR, null);
+                    return;
+                }
+                Bundle bundle = new Bundle();
+                bundle.putParcelable(KEY_MEDIA_ITEM, item);
+                receiver.send(RESULT_OK, bundle);
+            }
+        };
+
+        mCurConnection = connection;
+        onLoadItem(itemId, result);
+        mCurConnection = null;
+
+        if (!result.isDone()) {
+            throw new IllegalStateException("onLoadItem must call detach() or sendResult()"
+                    + " before returning for id=" + itemId);
+        }
+    }
+
+    /**
+     * Contains information that the browser service needs to send to the client
+     * when first connected.
+     */
+    public static final class BrowserRoot {
+        /**
+         * The lookup key for a boolean that indicates whether the browser service should return a
+         * browser root for recently played media items.
+         *
+         * <p>When creating a media browser for a given media browser service, this key can be
+         * supplied as a root hint for retrieving media items that are recently played.
+         * If the media browser service can provide such media items, the implementation must return
+         * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
+         *
+         * <p>The root hint may contain multiple keys.
+         *
+         * @see #EXTRA_OFFLINE
+         * @see #EXTRA_SUGGESTED
+         */
+        public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
+
+        /**
+         * The lookup key for a boolean that indicates whether the browser service should return a
+         * browser root for offline media items.
+         *
+         * <p>When creating a media browser for a given media browser service, this key can be
+         * supplied as a root hint for retrieving media items that are can be played without an
+         * internet connection.
+         * If the media browser service can provide such media items, the implementation must return
+         * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
+         *
+         * <p>The root hint may contain multiple keys.
+         *
+         * @see #EXTRA_RECENT
+         * @see #EXTRA_SUGGESTED
+         */
+        public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+
+        /**
+         * The lookup key for a boolean that indicates whether the browser service should return a
+         * browser root for suggested media items.
+         *
+         * <p>When creating a media browser for a given media browser service, this key can be
+         * supplied as a root hint for retrieving the media items suggested by the media browser
+         * service. The list of media items passed in {@link android.media.browse.MediaBrowser.SubscriptionCallback#onChildrenLoaded(String, List)}
+         * is considered ordered by relevance, first being the top suggestion.
+         * If the media browser service can provide such media items, the implementation must return
+         * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
+         *
+         * <p>The root hint may contain multiple keys.
+         *
+         * @see #EXTRA_RECENT
+         * @see #EXTRA_OFFLINE
+         */
+        public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
+
+        private final String mRootId;
+        private final Bundle mExtras;
+
+        /**
+         * Constructs a browser root.
+         * @param rootId The root id for browsing.
+         * @param extras Any extras about the browser service.
+         */
+        public BrowserRoot(@NonNull String rootId, @Nullable Bundle extras) {
+            if (rootId == null) {
+                throw new IllegalArgumentException("The root id in BrowserRoot cannot be null. "
+                        + "Use null for BrowserRoot instead.");
+            }
+            mRootId = rootId;
+            mExtras = extras;
+        }
+
+        /**
+         * Gets the root id for browsing.
+         */
+        public String getRootId() {
+            return mRootId;
+        }
+
+        /**
+         * Gets any extras about the browser service.
+         */
+        public Bundle getExtras() {
+            return mExtras;
+        }
+    }
+}
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 4f23cca..f5a6f86 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -736,8 +736,9 @@
          * @param preset one of {@link MediaRecorder.AudioSource#DEFAULT},
          *     {@link MediaRecorder.AudioSource#MIC}, {@link MediaRecorder.AudioSource#CAMCORDER},
          *     {@link MediaRecorder.AudioSource#VOICE_RECOGNITION},
-         *     {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION} or
-         *     {@link MediaRecorder.AudioSource#UNPROCESSED}
+         *     {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION},
+         *     {@link MediaRecorder.AudioSource#UNPROCESSED} or
+         *     {@link MediaRecorder.AudioSource#VOICE_PERFORMANCE}
          * @return the same Builder instance.
          */
         @SystemApi
@@ -749,6 +750,7 @@
                 case MediaRecorder.AudioSource.VOICE_RECOGNITION:
                 case MediaRecorder.AudioSource.VOICE_COMMUNICATION:
                 case MediaRecorder.AudioSource.UNPROCESSED:
+                case MediaRecorder.AudioSource.VOICE_PERFORMANCE:
                     mSource = preset;
                     break;
                 default:
@@ -760,7 +762,7 @@
         /**
          * @hide
          * Same as {@link #setCapturePreset(int)} but authorizes the use of HOTWORD,
-         * REMOTE_SUBMIX, RADIO_TUNER, VOICE_DOWNLINK, VOICE_UPLINK and VOICE_CALL.
+         * REMOTE_SUBMIX, RADIO_TUNER, VOICE_DOWNLINK, VOICE_UPLINK, VOICE_CALL and ECHO_REFERENCE.
          * @param preset
          * @return the same Builder instance.
          */
@@ -771,7 +773,8 @@
                     || (preset == MediaRecorder.AudioSource.RADIO_TUNER)
                     || (preset == MediaRecorder.AudioSource.VOICE_DOWNLINK)
                     || (preset == MediaRecorder.AudioSource.VOICE_UPLINK)
-                    || (preset == MediaRecorder.AudioSource.VOICE_CALL)) {
+                    || (preset == MediaRecorder.AudioSource.VOICE_CALL)
+                    || (preset == MediaRecorder.AudioSource.ECHO_REFERENCE)) {
                 mSource = preset;
             } else {
                 setCapturePreset(preset);
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 793aa27..5516086 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -816,7 +817,7 @@
      *
      * @return The audio frame size in bytes corresponding to the encoding and the channel mask.
      */
-    public int getFrameSizeInBytes() {
+    public @IntRange(from = 1) int getFrameSizeInBytes() {
         return mFrameSizeInBytes;
     }
 
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 30b5480..b7f042b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -28,6 +28,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.bluetooth.BluetoothCodecConfig;
 import android.bluetooth.BluetoothDevice;
 import android.content.ComponentName;
 import android.content.Context;
@@ -3802,6 +3803,12 @@
     public static final int DEVICE_IN_HDMI =
                                     AudioSystem.DEVICE_IN_HDMI;
     /** @hide
+     * The audio input device code for HDMI ARC
+     */
+    public static final int DEVICE_IN_HDMI_ARC =
+                                    AudioSystem.DEVICE_IN_HDMI_ARC;
+
+    /** @hide
      * The audio input device code for telephony voice RX path
      */
     public static final int DEVICE_IN_TELEPHONY_RX =
@@ -4047,6 +4054,36 @@
         }
     }
 
+     /**
+     * Indicate A2DP source or sink active device change and eventually suppress
+     * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
+     * @param device Bluetooth device connected/disconnected
+     * @param state  new connection state (BluetoothProfile.STATE_xxx)
+     * @param profile profile for the A2DP device
+     * (either {@link android.bluetooth.BluetoothProfile.A2DP} or
+     * {@link android.bluetooth.BluetoothProfile.A2DP_SINK})
+     * @param a2dpVolume New volume for the connecting device. Does nothing if
+     * disconnecting. Pass value -1 in case you want this field to be ignored
+     * @param suppressNoisyIntent if true the
+     * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
+     * @return a delay in ms that the caller should wait before broadcasting
+     * BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED intent.
+     * {@hide}
+     */
+    public int handleBluetoothA2dpActiveDeviceChange(
+                BluetoothDevice device, int state, int profile,
+                boolean suppressNoisyIntent, int a2dpVolume) {
+        final IAudioService service = getService();
+        int delay = 0;
+        try {
+            delay = service.handleBluetoothA2dpActiveDeviceChange(device,
+                state, profile, suppressNoisyIntent, a2dpVolume);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return delay;
+    }
+
     /** {@hide} */
     public IRingtonePlayer getRingtonePlayer() {
         try {
@@ -4910,6 +4947,34 @@
         return microphones;
     }
 
+    /**
+     * Returns a list of audio formats that corresponds to encoding formats
+     * supported on offload path for A2DP playback.
+     *
+     * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
+     * supported for offload A2DP playback
+     * @hide
+     */
+    public List<BluetoothCodecConfig> getHwOffloadEncodingFormatsSupportedForA2DP() {
+        ArrayList<Integer> formatsList = new ArrayList<Integer>();
+        ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<BluetoothCodecConfig>();
+
+        int status = AudioSystem.getHwOffloadEncodingFormatsSupportedForA2DP(formatsList);
+        if (status != AudioManager.SUCCESS) {
+            Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
+            return codecConfigList;
+        }
+
+        for (Integer format : formatsList) {
+            int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
+            if (btSourceCodec
+                    != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
+                codecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
+            }
+        }
+        return codecConfigList;
+    }
+
     // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
     // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
     // of the ports that exist at the time of the last notification.
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 33f81f1..92afe7e 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -61,7 +61,8 @@
  * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
  * the total recording buffer size.
  */
-public class AudioRecord implements AudioRouting, AudioRecordingMonitor, AudioRecordingMonitorClient
+public class AudioRecord implements AudioRouting, MicrophoneDirection,
+        AudioRecordingMonitor, AudioRecordingMonitorClient
 {
     //---------------------------------------------------------
     // Constants
@@ -1657,7 +1658,6 @@
         return activeMicrophones;
     }
 
-
     //--------------------------------------------------------------------------
     // Implementation of AudioRecordingMonitor interface
     //--------------------
@@ -1707,6 +1707,33 @@
         return native_getPortId();
     }
 
+    //--------------------------------------------------------------------------
+    // MicrophoneDirection
+    //--------------------
+    /**
+     * Specifies the logical microphone (for processing).
+     *
+     * @param direction Direction constant (MicrophoneDirection.MIC_DIRECTION_*)
+     * @return retval OK if the call is successful, an error code otherwise.
+     * @hide
+     */
+    public int setMicrophoneDirection(int direction) {
+        return native_set_microphone_direction(direction);
+    }
+
+    /**
+     * Specifies the zoom factor (i.e. the field dimension) for the selected microphone
+     * (for processing). The selected microphone is determined by the use-case for the stream.
+     *
+     * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle),
+     * though 0 (no zoom) to 1 (maximum zoom).
+     * @return retval OK if the call is successful, an error code otherwise.
+     * @hide
+     */
+    public int setMicrophoneFieldDimension(float zoom) {
+        return native_set_microphone_field_dimension(zoom);
+    }
+
     //---------------------------------------------------------
     // Interface definitions
     //--------------------
@@ -1860,6 +1887,9 @@
 
     private native int native_getPortId();
 
+    private native int native_set_microphone_direction(int direction);
+    private native int native_set_microphone_field_dimension(float zoom);
+
     //---------------------------------------------------------
     // Utility methods
     //------------------
diff --git a/media/java/android/media/AudioRecordingConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java
index de76aef..1d763ce 100644
--- a/media/java/android/media/AudioRecordingConfiguration.java
+++ b/media/java/android/media/AudioRecordingConfiguration.java
@@ -172,7 +172,8 @@
         MediaRecorder.AudioSource.CAMCORDER,
         MediaRecorder.AudioSource.VOICE_RECOGNITION,
         MediaRecorder.AudioSource.VOICE_COMMUNICATION,
-        MediaRecorder.AudioSource.UNPROCESSED
+        MediaRecorder.AudioSource.UNPROCESSED,
+        MediaRecorder.AudioSource.VOICE_PERFORMANCE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AudioSource {}
@@ -355,11 +356,11 @@
         dest.writeInt(mDeviceSource);
         dest.writeInt(mClientEffects.length);
         for (int i = 0; i < mClientEffects.length; i++) {
-            mClientEffects[i].writeToParcel(dest, 0);
+            mClientEffects[i].writeToParcel(dest);
         }
         dest.writeInt(mDeviceEffects.length);
         for (int i = 0; i < mDeviceEffects.length; i++) {
-            mDeviceEffects[i].writeToParcel(dest, 0);
+            mDeviceEffects[i].writeToParcel(dest);
         }
     }
 
@@ -374,13 +375,13 @@
         mClientPortId = in.readInt();
         mClientSilenced = in.readBoolean();
         mDeviceSource = in.readInt();
-        mClientEffects = AudioEffect.Descriptor.CREATOR.newArray(in.readInt());
+        mClientEffects = new AudioEffect.Descriptor[in.readInt()];
         for (int i = 0; i < mClientEffects.length; i++) {
-            mClientEffects[i] = AudioEffect.Descriptor.CREATOR.createFromParcel(in);
+            mClientEffects[i] = new AudioEffect.Descriptor(in);
         }
-        mDeviceEffects = AudioEffect.Descriptor.CREATOR.newArray(in.readInt());
-        for (int i = 0; i < mClientEffects.length; i++) {
-            mDeviceEffects[i] = AudioEffect.Descriptor.CREATOR.createFromParcel(in);
+        mDeviceEffects = new AudioEffect.Descriptor[in.readInt()];
+        for (int i = 0; i < mDeviceEffects.length; i++) {
+            mDeviceEffects[i] = new AudioEffect.Descriptor(in);
         }
     }
 
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 45cde0f..af016d5 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
+import android.bluetooth.BluetoothCodecConfig;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.media.audiofx.AudioEffect;
@@ -140,6 +141,29 @@
         }
     }
 
+    /* Formats for A2DP codecs, must match system/audio-base.h audio_format_t */
+    public static final int AUDIO_FORMAT_INVALID        = 0xFFFFFFFF;
+    public static final int AUDIO_FORMAT_DEFAULT        = 0;
+    public static final int AUDIO_FORMAT_AAC            = 0x04000000;
+    public static final int AUDIO_FORMAT_SBC            = 0x1F000000;
+    public static final int AUDIO_FORMAT_APTX           = 0x20000000;
+    public static final int AUDIO_FORMAT_APTX_HD        = 0x21000000;
+    public static final int AUDIO_FORMAT_LDAC           = 0x23000000;
+
+    /**
+     * Convert audio format enum values to Bluetooth codec values
+     */
+    public static int audioFormatToBluetoothSourceCodec(int audioFormat) {
+        switch (audioFormat) {
+            case AUDIO_FORMAT_AAC: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC;
+            case AUDIO_FORMAT_SBC: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC;
+            case AUDIO_FORMAT_APTX: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX;
+            case AUDIO_FORMAT_APTX_HD: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD;
+            case AUDIO_FORMAT_LDAC: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC;
+            default: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID;
+        }
+    }
+
     /* Routing bits for the former setRouting/getRouting API */
     /** @deprecated */
     @Deprecated public static final int ROUTE_EARPIECE          = (1 << 0);
@@ -541,6 +565,9 @@
     public static final int DEVICE_IN_BUS = DEVICE_BIT_IN | 0x100000;
     public static final int DEVICE_IN_PROXY = DEVICE_BIT_IN | 0x1000000;
     public static final int DEVICE_IN_USB_HEADSET = DEVICE_BIT_IN | 0x2000000;
+    public static final int DEVICE_IN_BLUETOOTH_BLE = DEVICE_BIT_IN | 0x4000000;
+    public static final int DEVICE_IN_HDMI_ARC = DEVICE_BIT_IN | 0x8000000;
+    public static final int DEVICE_IN_ECHO_REFERENCE = DEVICE_BIT_IN | 0x10000000;
     @UnsupportedAppUsage
     public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
 
@@ -567,6 +594,9 @@
                                              DEVICE_IN_BUS |
                                              DEVICE_IN_PROXY |
                                              DEVICE_IN_USB_HEADSET |
+                                             DEVICE_IN_BLUETOOTH_BLE |
+                                             DEVICE_IN_HDMI_ARC |
+                                             DEVICE_IN_ECHO_REFERENCE |
                                              DEVICE_IN_DEFAULT);
     public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
     public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
@@ -641,6 +671,9 @@
     public static final String DEVICE_IN_BUS_NAME = "bus";
     public static final String DEVICE_IN_PROXY_NAME = "proxy";
     public static final String DEVICE_IN_USB_HEADSET_NAME = "usb_headset";
+    public static final String DEVICE_IN_BLUETOOTH_BLE_NAME = "bt_ble";
+    public static final String DEVICE_IN_ECHO_REFERENCE_NAME = "echo_reference";
+    public static final String DEVICE_IN_HDMI_ARC_NAME = "hdmi_arc";
 
     @UnsupportedAppUsage
     public static String getOutputDeviceName(int device)
@@ -757,6 +790,12 @@
             return DEVICE_IN_PROXY_NAME;
         case DEVICE_IN_USB_HEADSET:
             return DEVICE_IN_USB_HEADSET_NAME;
+        case DEVICE_IN_BLUETOOTH_BLE:
+            return DEVICE_IN_BLUETOOTH_BLE_NAME;
+        case DEVICE_IN_ECHO_REFERENCE:
+            return DEVICE_IN_ECHO_REFERENCE_NAME;
+        case DEVICE_IN_HDMI_ARC:
+            return DEVICE_IN_HDMI_ARC_NAME;
         case DEVICE_IN_DEFAULT:
         default:
             return Integer.toString(device);
@@ -850,12 +889,14 @@
      */
     @UnsupportedAppUsage
     public static native int setDeviceConnectionState(int device, int state,
-                                                      String device_address, String device_name);
+                                                      String device_address, String device_name,
+                                                      int codecFormat);
     @UnsupportedAppUsage
     public static native int getDeviceConnectionState(int device, String device_address);
     public static native int handleDeviceConfigChange(int device,
                                                       String device_address,
-                                                      String device_name);
+                                                      String device_name,
+                                                      int codecFormat);
     @UnsupportedAppUsage
     public static native int setPhoneState(int state);
     @UnsupportedAppUsage
@@ -940,6 +981,12 @@
     public static native int getSurroundFormats(Map<Integer, Boolean> surroundFormats,
                                                 boolean reported);
 
+    /**
+     * Returns a list of audio formats (codec) supported on the A2DP offload path.
+     */
+    public static native int getHwOffloadEncodingFormatsSupportedForA2DP(
+            ArrayList<Integer> formatList);
+
     public static native int setSurroundFormatEnabled(int audioFormat, boolean enabled);
 
     /**
@@ -1053,7 +1100,8 @@
             (1 << STREAM_RING) |
             (1 << STREAM_NOTIFICATION) |
             (1 << STREAM_SYSTEM) |
-            (1 << STREAM_VOICE_CALL);
+            (1 << STREAM_VOICE_CALL) |
+            (1 << STREAM_BLUETOOTH_SCO);
 
     /**
      * Event posted by AudioTrack and AudioRecord JNI (JNIDeviceCallback) when routing changes.
diff --git a/media/java/android/media/Controller2Link.java b/media/java/android/media/Controller2Link.java
deleted file mode 100644
index a62db5f..0000000
--- a/media/java/android/media/Controller2Link.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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.media;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-
-import java.util.Objects;
-
-/**
- * Handles incoming commands from {@link MediaSession2} to both {@link MediaController2}.
- * @hide
- */
-// @SystemApi
-public final class Controller2Link implements Parcelable {
-    private static final String TAG = "Controller2Link";
-    private static final boolean DEBUG = MediaController2.DEBUG;
-
-    public static final Parcelable.Creator<Controller2Link> CREATOR =
-            new Parcelable.Creator<Controller2Link>() {
-                @Override
-                public Controller2Link createFromParcel(Parcel in) {
-                    return new Controller2Link(in);
-                }
-
-                @Override
-                public Controller2Link[] newArray(int size) {
-                    return new Controller2Link[size];
-                }
-            };
-
-
-    private final MediaController2 mController;
-    private final IMediaController2 mIController;
-
-    public Controller2Link(MediaController2 controller) {
-        mController = controller;
-        mIController = new Controller2Stub();
-    }
-
-    Controller2Link(Parcel in) {
-        mController = null;
-        mIController = IMediaController2.Stub.asInterface(in.readStrongBinder());
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongBinder(mIController.asBinder());
-    }
-
-    @Override
-    public int hashCode() {
-        return mIController.asBinder().hashCode();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof Controller2Link)) {
-            return false;
-        }
-        Controller2Link other = (Controller2Link) obj;
-        return Objects.equals(mIController.asBinder(), other.mIController.asBinder());
-    }
-
-    /** Interface method for IMediaController2.notifyConnected */
-    public void notifyConnected(int seq, Bundle connectionResult) {
-        try {
-            mIController.notifyConnected(seq, connectionResult);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for IMediaController2.notifyDisonnected */
-    public void notifyDisconnected(int seq) {
-        try {
-            mIController.notifyDisconnected(seq);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for IMediaController2.sendSessionCommand */
-    public void sendSessionCommand(int seq, Session2Command command, Bundle args,
-            ResultReceiver resultReceiver) {
-        try {
-            mIController.sendSessionCommand(seq, command, args, resultReceiver);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for IMediaController2.cancelSessionCommand */
-    public void cancelSessionCommand(int seq) {
-        try {
-            mIController.cancelSessionCommand(seq);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Stub implementation for IMediaController2.notifyConnected */
-    public void onConnected(int seq, Bundle connectionResult) {
-        if (connectionResult == null) {
-            onDisconnected(seq);
-            return;
-        }
-        mController.onConnected(seq, connectionResult);
-    }
-
-    /** Stub implementation for IMediaController2.notifyDisonnected */
-    public void onDisconnected(int seq) {
-        mController.onDisconnected(seq);
-    }
-
-    /** Stub implementation for IMediaController2.sendSessionCommand */
-    public void onSessionCommand(int seq, Session2Command command, Bundle args,
-            ResultReceiver resultReceiver) {
-        mController.onSessionCommand(seq, command, args, resultReceiver);
-    }
-
-    /** Stub implementation for IMediaController2.cancelSessionCommand */
-    public void onCancelCommand(int seq) {
-        mController.onCancelCommand(seq);
-    }
-
-    private class Controller2Stub extends IMediaController2.Stub {
-        @Override
-        public void notifyConnected(int seq, Bundle connectionResult) {
-            Controller2Link.this.onConnected(seq, connectionResult);
-        }
-
-        @Override
-        public void notifyDisconnected(int seq) {
-            Controller2Link.this.onDisconnected(seq);
-        }
-
-        @Override
-        public void sendSessionCommand(int seq, Session2Command command, Bundle args,
-                ResultReceiver resultReceiver) {
-            Controller2Link.this.onSessionCommand(seq, command, args, resultReceiver);
-        }
-
-        @Override
-        public void cancelSessionCommand(int seq) {
-            Controller2Link.this.onCancelCommand(seq);
-        }
-    }
-}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 9fbd7ea..14bdab9 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -155,6 +155,9 @@
 
     void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device);
 
+    int handleBluetoothA2dpActiveDeviceChange(in BluetoothDevice device,
+            int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
+
     AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
 
     boolean isCameraSoundForced();
diff --git a/media/java/android/media/IMediaController2.aidl b/media/java/android/media/IMediaController2.aidl
deleted file mode 100644
index ca5394f..0000000
--- a/media/java/android/media/IMediaController2.aidl
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.media;
-
-import android.os.Bundle;
-import android.os.ResultReceiver;
-import android.media.Session2Command;
-
-/**
- * Interface from MediaSession2 to MediaController2.
- * <p>
- * Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
- * and holds calls from session to make session owner(s) frozen.
- * @hide
- */
- // Code for AML only
-oneway interface IMediaController2 {
-    void notifyConnected(int seq, in Bundle connectionResult) = 0;
-    void notifyDisconnected(int seq) = 1;
-    void sendSessionCommand(int seq, in Session2Command command, in Bundle args,
-            in ResultReceiver resultReceiver) = 2;
-    void cancelSessionCommand(int seq) = 3;
-    // Next Id : 4
-}
diff --git a/media/java/android/media/IRemoteVolumeController.aidl b/media/java/android/media/IRemoteVolumeController.aidl
index e4a4a42..74c05c4 100644
--- a/media/java/android/media/IRemoteVolumeController.aidl
+++ b/media/java/android/media/IRemoteVolumeController.aidl
@@ -9,6 +9,7 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
+ *
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
@@ -16,7 +17,7 @@
 
 package android.media;
 
-import android.media.session.ISessionController;
+import android.media.session.MediaSession;
 
 /**
  * AIDL for the MediaSessionService to report interesting events on remote playback
@@ -25,8 +26,8 @@
  * @hide
  */
 oneway interface IRemoteVolumeController {
-    void remoteVolumeChanged(ISessionController session, int flags);
+    void remoteVolumeChanged(in MediaSession.Token sessionToken, int flags);
     // sets the default session to use with the slider, replaces remoteSliderVisibility
     // on IVolumeController
-    void updateRemoteController(ISessionController session);
+    void updateRemoteController(in MediaSession.Token sessionToken);
 }
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 8ec0e35..9ac147b 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -150,7 +150,7 @@
      * consumer end-points. For example, if the application intends to send the images to
      * {@link android.media.MediaCodec} or {@link android.media.MediaRecorder} for hardware video
      * encoding, the format and usage flag combination needs to be
-     * {@link ImageFormat#PRIVATE PRIVATE} and {@link HardwareBuffer#USAGE0_VIDEO_ENCODE}. When an
+     * {@link ImageFormat#PRIVATE PRIVATE} and {@link HardwareBuffer#USAGE_VIDEO_ENCODE}. When an
      * {@link ImageReader} object is created with a valid size and such format/usage flag
      * combination, the application can send the {@link Image images} to an {@link ImageWriter} that
      * is created with the input {@link android.view.Surface} provided by the
@@ -173,7 +173,7 @@
      * ImageReaders using other format such as {@link ImageFormat#YUV_420_888 YUV_420_888}.
      * </p>
      * <p>
-     * Note that not all format and usage flag combination is supported by the
+     * Note that not all format and usage flag combinations are supported by the
      * {@link ImageReader}. Below are the supported combinations by the {@link ImageReader}
      * (assuming the consumer end-points support the such image consumption, e.g., hardware video
      * encoding).
@@ -186,13 +186,13 @@
      *   <td>non-{@link android.graphics.ImageFormat#PRIVATE PRIVATE} formats defined by
      *   {@link android.graphics.ImageFormat ImageFormat} or
      *   {@link android.graphics.PixelFormat PixelFormat}</td>
-     *   <td>{@link HardwareBuffer#USAGE0_CPU_READ} or
-     *   {@link HardwareBuffer#USAGE0_CPU_READ_OFTEN}</td>
+     *   <td>{@link HardwareBuffer#USAGE_CPU_READ_RARELY} or
+     *   {@link HardwareBuffer#USAGE_CPU_READ_OFTEN}</td>
      * </tr>
      * <tr>
      *   <td>{@link android.graphics.ImageFormat#PRIVATE}</td>
-     *   <td>{@link HardwareBuffer#USAGE0_VIDEO_ENCODE} or
-     *   {@link HardwareBuffer#USAGE0_GPU_SAMPLED_IMAGE}, or combined</td>
+     *   <td>{@link HardwareBuffer#USAGE_VIDEO_ENCODE} or
+     *   {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE}, or combined</td>
      * </tr>
      * </table>
      * Using other combinations may result in {@link IllegalArgumentException}.
@@ -208,11 +208,10 @@
      *            become available for access through {@link #acquireLatestImage()} or
      *            {@link #acquireNextImage()}. Must be greater than 0.
      * @param usage The intended usage of the images produced by this ImageReader. It needs
-     *            to be one of the Usage0 defined by {@link HardwareBuffer}, or an
+     *            to be one of the Usage defined by {@link HardwareBuffer}, or an
      *            {@link IllegalArgumentException} will be thrown.
      * @see Image
      * @see HardwareBuffer
-     * @hide
      */
     public static ImageReader newInstance(int width, int height, int format, int maxImages,
             long usage) {
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 4c0153f..dd09afc 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -168,7 +168,6 @@
      *            {@link ImageFormat} or {@link PixelFormat}.
      *
      * @return a new ImageWriter instance.
-     * @hide
      */
     public static ImageWriter newInstance(Surface surface, int maxImages, int format) {
         if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 0375de3..f756658 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1829,9 +1829,14 @@
 
         mBufferLock = new Object();
 
+        // save name used at creation
+        mNameAtCreation = nameIsType ? null : name;
+
         native_setup(name, nameIsType, encoder);
     }
 
+    private String mNameAtCreation;
+
     @Override
     protected void finalize() {
         native_finalize();
@@ -2289,6 +2294,30 @@
          */
         public static final int ERROR_UNSUPPORTED_OPERATION = 6;
 
+        /**
+         * This indicates that the security level of the device is not
+         * sufficient to meet the requirements set by the content owner
+         * in the license policy.
+         */
+        public static final int ERROR_INSUFFICIENT_SECURITY = 7;
+
+        /**
+         * This indicates that the video frame being decrypted exceeds
+         * the size of the device's protected output buffers. When
+         * encountering this error the app should try playing content
+         * of a lower resolution.
+         */
+        public static final int ERROR_FRAME_TOO_LARGE = 8;
+
+        /**
+         * This error indicates that session state has been
+         * invalidated. It can occur on devices that are not capable
+         * of retaining crypto session state across device
+         * suspend/resume. The session must be closed and a new
+         * session opened to resume operation.
+         */
+        public static final int ERROR_LOST_STATE = 9;
+
         /** @hide */
         @IntDef({
             ERROR_NO_KEY,
@@ -2296,7 +2325,10 @@
             ERROR_RESOURCE_BUSY,
             ERROR_INSUFFICIENT_OUTPUT_PROTECTION,
             ERROR_SESSION_NOT_OPENED,
-            ERROR_UNSUPPORTED_OPERATION
+            ERROR_UNSUPPORTED_OPERATION,
+            ERROR_INSUFFICIENT_SECURITY,
+            ERROR_FRAME_TOO_LARGE,
+            ERROR_LOST_STATE
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface CryptoErrorCode {}
@@ -3290,12 +3322,36 @@
     private native void native_setAudioPresentation(int presentationId, int programId);
 
     /**
-     * Get the component name. If the codec was created by createDecoderByType
-     * or createEncoderByType, what component is chosen is not known beforehand.
+     * Retrieve the codec name.
+     *
+     * If the codec was created by createDecoderByType or createEncoderByType, what component is
+     * chosen is not known beforehand. This method returns the name of the codec that was
+     * selected by the platform.
+     *
+     * <strong>Note:</strong> Implementations may provide multiple aliases (codec
+     * names) for the same underlying codec, any of which can be used to instantiate the same
+     * underlying codec in {@link MediaCodec#createByCodecName}. This method returns the
+     * name used to create the codec in this case.
+     *
      * @throws IllegalStateException if in the Released state.
      */
     @NonNull
-    public native final String getName();
+    public final String getName() {
+        // get canonical name to handle exception
+        String canonicalName = getCanonicalName();
+        return mNameAtCreation != null ? mNameAtCreation : canonicalName;
+    }
+
+    /**
+     * Retrieve the underlying codec name.
+     *
+     * This method is similar to {@link #getName}, except that it returns the underlying component
+     * name even if an alias was used to create this MediaCodec object by name,
+     *
+     * @throws IllegalStateException if in the Released state.
+     */
+    @NonNull
+    public native final String getCanonicalName();
 
     /**
      *  Return Metrics data about the current codec instance.
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 10a1e3a..751d57b 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -32,8 +32,10 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Vector;
 
 /**
  * Provides information about a given media codec available on the device. You can
@@ -61,15 +63,25 @@
  *
  */
 public final class MediaCodecInfo {
-    private boolean mIsEncoder;
+    private static final String TAG = "MediaCodecInfo";
+
+    private static final int FLAG_IS_ENCODER = (1 << 0);
+    private static final int FLAG_IS_VENDOR = (1 << 1);
+    private static final int FLAG_IS_SOFTWARE_ONLY = (1 << 2);
+    private static final int FLAG_IS_HARDWARE_ACCELERATED = (1 << 3);
+
+    private int mFlags;
     private String mName;
+    private String mCanonicalName;
     private Map<String, CodecCapabilities> mCaps;
 
     /* package private */ MediaCodecInfo(
-            String name, boolean isEncoder, CodecCapabilities[] caps) {
+            String name, String canonicalName, int flags, CodecCapabilities[] caps) {
         mName = name;
-        mIsEncoder = isEncoder;
+        mCanonicalName = canonicalName;
+        mFlags = flags;
         mCaps = new HashMap<String, CodecCapabilities>();
+
         for (CodecCapabilities c: caps) {
             mCaps.put(c.getMimeType(), c);
         }
@@ -77,16 +89,69 @@
 
     /**
      * Retrieve the codec name.
+     *
+     * <strong>Note:</strong> Implementations may provide multiple aliases (codec
+     * names) for the same underlying codec, any of which can be used to instantiate the same
+     * underlying codec in {@link MediaCodec#createByCodecName}.
+     *
+     * Applications targeting SDK < {@link android.os.Build.VERSION_CODES#Q}, cannot determine if
+     * the multiple codec names listed in MediaCodecList are in-fact for the same codec.
      */
+    @NonNull
     public final String getName() {
         return mName;
     }
 
     /**
+     * Retrieve the underlying codec name.
+     *
+     * Device implementations may provide multiple aliases (codec names) for the same underlying
+     * codec to maintain backward app compatibility. This method returns the name of the underlying
+     * codec name, which must not be another alias. For non-aliases this is always the name of the
+     * codec.
+     */
+    @NonNull
+    public final String getCanonicalName() {
+        return mCanonicalName;
+    }
+
+    /**
+     * Query if the codec is an alias for another underlying codec.
+     */
+    public final boolean isAlias() {
+        return !mName.equals(mCanonicalName);
+    }
+
+    /**
      * Query if the codec is an encoder.
      */
     public final boolean isEncoder() {
-        return mIsEncoder;
+        return (mFlags & FLAG_IS_ENCODER) != 0;
+    }
+
+    /**
+     * Query if the codec is provided by the Android platform (false) or the device manufacturer
+     * (true).
+     */
+    public final boolean isVendor() {
+        return (mFlags & FLAG_IS_VENDOR) != 0;
+    }
+
+    /**
+     * Query if the codec is software only. Software-only codecs are more secure as they run in
+     * a tighter security sandbox. On the other hand, software-only codecs do not provide any
+     * performance guarantees.
+     */
+    public final boolean isSoftwareOnly() {
+        return (mFlags & FLAG_IS_SOFTWARE_ONLY) != 0;
+    }
+
+    /**
+     * Query if the codec is hardware accelerated. This attribute is provided by the device
+     * manufacturer. Note that it cannot be tested for correctness.
+     */
+    public final boolean isHardwareAccelerated() {
+        return (mFlags & FLAG_IS_HARDWARE_ACCELERATED) != 0;
     }
 
     /**
@@ -163,7 +228,7 @@
         // such as B-frame support, arithmetic coding...
         public CodecProfileLevel[] profileLevels;  // NOTE this array is modifiable by user
 
-        // from OMX_COLOR_FORMATTYPE
+        // from MediaCodecConstants
         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
         public static final int COLOR_FormatMonochrome              = 1;
         /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */
@@ -344,7 +409,7 @@
         /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */
         public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
         // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference.
-        // In OMX this is called OMX_COLOR_FormatAndroidOpaque.
+        // Note: in OMX this is called OMX_COLOR_FormatAndroidOpaque.
         public static final int COLOR_FormatSurface                   = 0x7F000789;
 
         /**
@@ -435,8 +500,7 @@
         public static final int COLOR_QCOM_FormatYUV420SemiPlanar     = 0x7fa30c00;
 
         /**
-         * Defined in the OpenMAX IL specs, color format values are drawn from
-         * OMX_COLOR_FORMATTYPE.
+         * The color format for the media. This is one of the color constants defined in this class.
          */
         public int[] colorFormats; // NOTE this array is modifiable by user
 
@@ -462,6 +526,26 @@
         public static final String FEATURE_TunneledPlayback       = "tunneled-playback";
 
         /**
+         * If true, the timestamp of each output buffer is derived from the timestamp of the input
+         * buffer that produced the output. If false, the timestamp of each output buffer is
+         * derived from the timestamp of the first input buffer.
+         */
+        public static final String FEATURE_DynamicTimestamp = "dynamic-timestamp";
+
+        /**
+         * <b>decoder only</b>If true, the codec supports partial (including multiple) access units
+         * per input buffer.
+         */
+        public static final String FEATURE_FrameParsing = "frame-parsing";
+
+        /**
+         * If true, the codec supports multiple access units (for decoding, or to output for
+         * encoders). If false, the codec only supports single access units. Producing multiple
+         * access units for output is an optional feature.
+         */
+        public static final String FEATURE_MultipleFrames = "multiple-frames";
+
+        /**
          * <b>video decoder only</b>: codec supports queuing partial frames.
          */
         public static final String FEATURE_PartialFrame = "partial-frame";
@@ -497,10 +581,15 @@
             new Feature(FEATURE_SecurePlayback,   (1 << 1), false),
             new Feature(FEATURE_TunneledPlayback, (1 << 2), false),
             new Feature(FEATURE_PartialFrame,     (1 << 3), false),
+            new Feature(FEATURE_FrameParsing,     (1 << 4), false),
+            new Feature(FEATURE_MultipleFrames,   (1 << 5), false),
+            new Feature(FEATURE_DynamicTimestamp, (1 << 6), false),
         };
 
         private static final Feature[] encoderFeatures = {
             new Feature(FEATURE_IntraRefresh, (1 << 0), false),
+            new Feature(FEATURE_MultipleFrames, (1 << 1), false),
+            new Feature(FEATURE_DynamicTimestamp, (1 << 2), false),
         };
 
         /** @hide */
@@ -869,7 +958,7 @@
 
             CodecCapabilities ret = new CodecCapabilities(
                 new CodecProfileLevel[] { pl }, new int[0], true /* encoder */,
-                0 /* flags */, defaultFormat, new MediaFormat() /* info */);
+                defaultFormat, new MediaFormat() /* info */);
             if (ret.mError != 0) {
                 return null;
             }
@@ -878,10 +967,10 @@
 
         /* package private */ CodecCapabilities(
                 CodecProfileLevel[] profLevs, int[] colFmts,
-                boolean encoder, int flags,
+                boolean encoder,
                 Map<String, Object>defaultFormatMap,
                 Map<String, Object>capabilitiesMap) {
-            this(profLevs, colFmts, encoder, flags,
+            this(profLevs, colFmts, encoder,
                     new MediaFormat(defaultFormatMap),
                     new MediaFormat(capabilitiesMap));
         }
@@ -889,11 +978,11 @@
         private MediaFormat mCapabilitiesInfo;
 
         /* package private */ CodecCapabilities(
-                CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags,
+                CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder,
                 MediaFormat defaultFormat, MediaFormat info) {
             final Map<String, Object> map = info.getMap();
             colorFormats = colFmts;
-            mFlagsVerified = flags;
+            mFlagsVerified = 0; // TODO: remove as it is unused
             mDefaultFormat = defaultFormat;
             mCapabilitiesInfo = info;
             mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME);
@@ -1243,6 +1332,7 @@
         private Range<Rational> mBlockAspectRatioRange;
         private Range<Long> mBlocksPerSecondRange;
         private Map<Size, Range<Long>> mMeasuredFrameRates;
+        private Vector<PerformancePoint> mPerformancePoints;
         private Range<Integer> mFrameRateRange;
 
         private int mBlockWidth;
@@ -1524,6 +1614,158 @@
         }
 
         /**
+         * Video performance points are a set of standard performance points defined by pixel rate.
+         */
+        public static final class PerformancePoint {
+            /**
+             * Frame width in pixels.
+             */
+            public final int width;
+
+            /**
+             * Frame height in pixels.
+             */
+            public final int height;
+
+            /**
+             * Frame rate in frames per second.
+             */
+            public final int frameRate;
+
+            /* package private */
+            PerformancePoint(int width_, int height_, int frameRate_) {
+                width = width_;
+                height = height_;
+                frameRate = frameRate_;
+            }
+
+            /**
+             * Checks whether the performance point covers a media format.
+             *
+             * @param format Stream format considered
+             *
+             * @return {@code true} if the performance point covers the format.
+             */
+            public boolean covers(@NonNull MediaFormat format) {
+                // for simplicity, this code assumes a 16x16 block size.
+                long macroBlocks = ((width + 15) / 16) * (long)((height + 15) / 16);
+                long mbps = macroBlocks * frameRate;
+
+                long formatMacroBlocks =
+                    (long)((format.getInteger(MediaFormat.KEY_WIDTH, 0) + 15) / 16)
+                            * ((format.getInteger(MediaFormat.KEY_HEIGHT, 0) + 15) / 16);
+                double formatMbps =
+                    Math.ceil(formatMacroBlocks
+                              * format.getNumber(MediaFormat.KEY_FRAME_RATE, 0).doubleValue());
+                return formatMacroBlocks > 0 && formatMacroBlocks <= macroBlocks
+                        && formatMbps <= mbps;
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                if (o instanceof PerformancePoint) {
+                    PerformancePoint other = (PerformancePoint)o;
+                    return ((long)width * height) == ((long)other.width * other.height)
+                            && frameRate == other.frameRate;
+                }
+                return false;
+            }
+
+            /** 480p 24fps */
+            public static final PerformancePoint SD_24 = new PerformancePoint(720, 480, 24);
+            /** 576p 25fps */
+            public static final PerformancePoint SD_25 = new PerformancePoint(720, 576, 25);
+            /** 480p 30fps */
+            public static final PerformancePoint SD_30 = new PerformancePoint(720, 480, 30);
+            /** 480p 48fps */
+            public static final PerformancePoint SD_48 = new PerformancePoint(720, 480, 48);
+            /** 576p 50fps */
+            public static final PerformancePoint SD_50 = new PerformancePoint(720, 576, 50);
+            /** 480p 60fps */
+            public static final PerformancePoint SD_60 = new PerformancePoint(720, 480, 60);
+
+            /** 720p 24fps */
+            public static final PerformancePoint HD_24 = new PerformancePoint(1280, 720, 24);
+            /** 720p 25fps */
+            public static final PerformancePoint HD_25 = new PerformancePoint(1280, 720, 25);
+            /** 720p 30fps */
+            public static final PerformancePoint HD_30 = new PerformancePoint(1280, 720, 30);
+            /** 720p 50fps */
+            public static final PerformancePoint HD_50 = new PerformancePoint(1280, 720, 50);
+            /** 720p 60fps */
+            public static final PerformancePoint HD_60 = new PerformancePoint(1280, 720, 60);
+            /** 720p 100fps */
+            public static final PerformancePoint HD_100 = new PerformancePoint(1280, 720, 100);
+            /** 720p 120fps */
+            public static final PerformancePoint HD_120 = new PerformancePoint(1280, 720, 120);
+            /** 720p 200fps */
+            public static final PerformancePoint HD_200 = new PerformancePoint(1280, 720, 200);
+            /** 720p 240fps */
+            public static final PerformancePoint HD_240 = new PerformancePoint(1280, 720, 240);
+
+            /** 1080p 24fps */
+            public static final PerformancePoint FHD_24 = new PerformancePoint(1920, 1080, 24);
+            /** 1080p 25fps */
+            public static final PerformancePoint FHD_25 = new PerformancePoint(1920, 1080, 25);
+            /** 1080p 30fps */
+            public static final PerformancePoint FHD_30 = new PerformancePoint(1920, 1080, 30);
+            /** 1080p 50fps */
+            public static final PerformancePoint FHD_50 = new PerformancePoint(1920, 1080, 50);
+            /** 1080p 60fps */
+            public static final PerformancePoint FHD_60 = new PerformancePoint(1920, 1080, 60);
+            /** 1080p 100fps */
+            public static final PerformancePoint FHD_100 = new PerformancePoint(1920, 1080, 100);
+            /** 1080p 120fps */
+            public static final PerformancePoint FHD_120 = new PerformancePoint(1920, 1080, 120);
+            /** 1080p 200fps */
+            public static final PerformancePoint FHD_200 = new PerformancePoint(1920, 1080, 200);
+            /** 1080p 240fps */
+            public static final PerformancePoint FHD_240 = new PerformancePoint(1920, 1080, 240);
+
+            /** 2160p 24fps */
+            public static final PerformancePoint UHD_24 = new PerformancePoint(3840, 2160, 24);
+            /** 2160p 25fps */
+            public static final PerformancePoint UHD_25 = new PerformancePoint(3840, 2160, 25);
+            /** 2160p 30fps */
+            public static final PerformancePoint UHD_30 = new PerformancePoint(3840, 2160, 30);
+            /** 2160p 50fps */
+            public static final PerformancePoint UHD_50 = new PerformancePoint(3840, 2160, 50);
+            /** 2160p 60fps */
+            public static final PerformancePoint UHD_60 = new PerformancePoint(3840, 2160, 60);
+            /** 2160p 100fps */
+            public static final PerformancePoint UHD_100 = new PerformancePoint(3840, 2160, 100);
+            /** 2160p 120fps */
+            public static final PerformancePoint UHD_120 = new PerformancePoint(3840, 2160, 120);
+            /** 2160p 200fps */
+            public static final PerformancePoint UHD_200 = new PerformancePoint(3840, 2160, 200);
+            /** 2160p 240fps */
+            public static final PerformancePoint UHD_240 = new PerformancePoint(3840, 2160, 240);
+        }
+
+        /**
+         * Returns the supported performance points. May return {@code null} if the codec did not
+         * publish any performance point information (e.g. the vendor codecs have not been updated
+         * to the latest android release). May return an empty list if the codec published that
+         * if does not guarantee any performance points.
+         * <p>
+         * This is a performance guarantee provided by the device manufacturer for hardware codecs
+         * based on hardware capabilities of the device.
+         * <p>
+         * The returned list is sorted first by decreasing number of pixels, then by decreasing
+         * width, and finally by decreasing frame rate.
+         * Performance points assume a single active codec. For use cases where multiple
+         * codecs are active, should use that highest pixel count, and add the frame rates of
+         * each individual codec.
+         */
+        @Nullable
+        public List<PerformancePoint> getSupportedPerformancePoints() {
+            if (mPerformancePoints == null) {
+                return null;
+            }
+            return new ArrayList<PerformancePoint>(mPerformancePoints);
+        }
+
+        /**
          * Returns whether a given video size ({@code width} and
          * {@code height}) and {@code frameRate} combination is supported.
          */
@@ -1659,6 +1901,50 @@
             mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
         }
 
+        private @Nullable Vector<PerformancePoint> getPerformancePoints(Map<String, Object> map) {
+            Vector<PerformancePoint> ret = new Vector<>();
+            final String prefix = "performance-point-";
+            Set<String> keys = map.keySet();
+            for (String key : keys) {
+                // looking for: performance-point-WIDTHxHEIGHT-range
+                if (!key.startsWith(prefix)) {
+                    continue;
+                }
+                String subKey = key.substring(prefix.length());
+                if (subKey.equals("none") && ret.size() == 0) {
+                    // This means that component knowingly did not publish performance points.
+                    // This is different from when the component forgot to publish performance
+                    // points.
+                    return ret;
+                }
+                String[] temp = key.split("-");
+                if (temp.length != 4) {
+                    continue;
+                }
+                String sizeStr = temp[2];
+                Size size = Utils.parseSize(sizeStr, null);
+                if (size == null || size.getWidth() * size.getHeight() <= 0) {
+                    continue;
+                }
+                Range<Long> range = Utils.parseLongRange(map.get(key), null);
+                if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
+                    continue;
+                }
+                ret.add(new PerformancePoint(
+                        size.getWidth(), size.getHeight(), range.getLower().intValue()));
+            }
+            // check if the component specified no performance point indication
+            if (ret.size() == 0) {
+                return null;
+            }
+
+            // sort reversed by area first, then by frame rate
+            ret.sort((a, b) -> (a.width * a.height != b.width * b.height ?
+                                    (b.width * b.height - a.width * a.height) :
+                                    (b.frameRate - a.frameRate)));
+            return ret;
+        }
+
         private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
             Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>();
             final String prefix = "measured-frame-rate-";
@@ -1770,6 +2056,7 @@
             blockRates =
                 Utils.parseLongRange(map.get("blocks-per-second-range"), null);
             mMeasuredFrameRates = getMeasuredFrameRates(map);
+            mPerformancePoints = getPerformancePoints(map);
             Pair<Range<Integer>, Range<Integer>> sizeRanges =
                 parseWidthHeightRanges(map.get("size-range"));
             if (sizeRanges != null) {
@@ -2879,7 +3166,9 @@
      * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field.
      */
     public static final class CodecProfileLevel {
-        // from OMX_VIDEO_AVCPROFILETYPE
+        // These constants were originally in-line with OMX values, but this
+        // correspondence is no longer maintained.
+
         public static final int AVCProfileBaseline = 0x01;
         public static final int AVCProfileMain     = 0x02;
         public static final int AVCProfileExtended = 0x04;
@@ -2890,7 +3179,6 @@
         public static final int AVCProfileConstrainedBaseline = 0x10000;
         public static final int AVCProfileConstrainedHigh     = 0x80000;
 
-        // from OMX_VIDEO_AVCLEVELTYPE
         public static final int AVCLevel1       = 0x01;
         public static final int AVCLevel1b      = 0x02;
         public static final int AVCLevel11      = 0x04;
@@ -2908,8 +3196,10 @@
         public static final int AVCLevel5       = 0x4000;
         public static final int AVCLevel51      = 0x8000;
         public static final int AVCLevel52      = 0x10000;
+        public static final int AVCLevel6       = 0x20000;
+        public static final int AVCLevel61      = 0x40000;
+        public static final int AVCLevel62      = 0x80000;
 
-        // from OMX_VIDEO_H263PROFILETYPE
         public static final int H263ProfileBaseline             = 0x01;
         public static final int H263ProfileH320Coding           = 0x02;
         public static final int H263ProfileBackwardCompatible   = 0x04;
@@ -2920,7 +3210,6 @@
         public static final int H263ProfileInterlace            = 0x80;
         public static final int H263ProfileHighLatency          = 0x100;
 
-        // from OMX_VIDEO_H263LEVELTYPE
         public static final int H263Level10      = 0x01;
         public static final int H263Level20      = 0x02;
         public static final int H263Level30      = 0x04;
@@ -2930,7 +3219,6 @@
         public static final int H263Level60      = 0x40;
         public static final int H263Level70      = 0x80;
 
-        // from OMX_VIDEO_MPEG4PROFILETYPE
         public static final int MPEG4ProfileSimple              = 0x01;
         public static final int MPEG4ProfileSimpleScalable      = 0x02;
         public static final int MPEG4ProfileCore                = 0x04;
@@ -2948,7 +3236,6 @@
         public static final int MPEG4ProfileAdvancedScalable    = 0x4000;
         public static final int MPEG4ProfileAdvancedSimple      = 0x8000;
 
-        // from OMX_VIDEO_MPEG4LEVELTYPE
         public static final int MPEG4Level0      = 0x01;
         public static final int MPEG4Level0b     = 0x02;
         public static final int MPEG4Level1      = 0x04;
@@ -2960,7 +3247,6 @@
         public static final int MPEG4Level5      = 0x80;
         public static final int MPEG4Level6      = 0x100;
 
-        // from OMX_VIDEO_MPEG2PROFILETYPE
         public static final int MPEG2ProfileSimple              = 0x00;
         public static final int MPEG2ProfileMain                = 0x01;
         public static final int MPEG2Profile422                 = 0x02;
@@ -2968,14 +3254,12 @@
         public static final int MPEG2ProfileSpatial             = 0x04;
         public static final int MPEG2ProfileHigh                = 0x05;
 
-        // from OMX_VIDEO_MPEG2LEVELTYPE
         public static final int MPEG2LevelLL     = 0x00;
         public static final int MPEG2LevelML     = 0x01;
         public static final int MPEG2LevelH14    = 0x02;
         public static final int MPEG2LevelHL     = 0x03;
         public static final int MPEG2LevelHP     = 0x04;
 
-        // from OMX_AUDIO_AACPROFILETYPE
         public static final int AACObjectMain       = 1;
         public static final int AACObjectLC         = 2;
         public static final int AACObjectSSR        = 3;
@@ -2990,16 +3274,13 @@
         /** xHE-AAC (includes USAC) */
         public static final int AACObjectXHE        = 42;
 
-        // from OMX_VIDEO_VP8LEVELTYPE
         public static final int VP8Level_Version0 = 0x01;
         public static final int VP8Level_Version1 = 0x02;
         public static final int VP8Level_Version2 = 0x04;
         public static final int VP8Level_Version3 = 0x08;
 
-        // from OMX_VIDEO_VP8PROFILETYPE
         public static final int VP8ProfileMain = 0x01;
 
-        // from OMX_VIDEO_VP9PROFILETYPE
         public static final int VP9Profile0 = 0x01;
         public static final int VP9Profile1 = 0x02;
         public static final int VP9Profile2 = 0x04;
@@ -3010,7 +3291,6 @@
         public static final int VP9Profile2HDR10Plus = 0x4000;
         public static final int VP9Profile3HDR10Plus = 0x8000;
 
-        // from OMX_VIDEO_VP9LEVELTYPE
         public static final int VP9Level1  = 0x1;
         public static final int VP9Level11 = 0x2;
         public static final int VP9Level2  = 0x4;
@@ -3026,14 +3306,12 @@
         public static final int VP9Level61 = 0x1000;
         public static final int VP9Level62 = 0x2000;
 
-        // from OMX_VIDEO_HEVCPROFILETYPE
         public static final int HEVCProfileMain        = 0x01;
         public static final int HEVCProfileMain10      = 0x02;
         public static final int HEVCProfileMainStill   = 0x04;
         public static final int HEVCProfileMain10HDR10 = 0x1000;
         public static final int HEVCProfileMain10HDR10Plus = 0x2000;
 
-        // from OMX_VIDEO_HEVCLEVELTYPE
         public static final int HEVCMainTierLevel1  = 0x1;
         public static final int HEVCHighTierLevel1  = 0x2;
         public static final int HEVCMainTierLevel2  = 0x4;
@@ -3067,7 +3345,6 @@
             HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 |
             HEVCHighTierLevel62;
 
-        // from OMX_VIDEO_DOLBYVISIONPROFILETYPE
         public static final int DolbyVisionProfileDvavPer = 0x1;
         public static final int DolbyVisionProfileDvavPen = 0x2;
         public static final int DolbyVisionProfileDvheDer = 0x4;
@@ -3079,7 +3356,6 @@
         public static final int DolbyVisionProfileDvheSt = 0x100;
         public static final int DolbyVisionProfileDvavSe = 0x200;
 
-        // from OMX_VIDEO_DOLBYVISIONLEVELTYPE
         public static final int DolbyVisionLevelHd24    = 0x1;
         public static final int DolbyVisionLevelHd30    = 0x2;
         public static final int DolbyVisionLevelFhd24   = 0x4;
@@ -3090,17 +3366,44 @@
         public static final int DolbyVisionLevelUhd48   = 0x80;
         public static final int DolbyVisionLevelUhd60   = 0x100;
 
+        public static final int AV1Profile0     = 0x1;
+        public static final int AV1Profile1     = 0x2;
+        public static final int AV1Profile2     = 0x4;
+
+        public static final int AV1Level2       = 0x1;
+        public static final int AV1Level21      = 0x2;
+        public static final int AV1Level22      = 0x4;
+        public static final int AV1Level23      = 0x8;
+        public static final int AV1Level3       = 0x10;
+        public static final int AV1Level31      = 0x20;
+        public static final int AV1Level32      = 0x40;
+        public static final int AV1Level33      = 0x80;
+        public static final int AV1Level4       = 0x100;
+        public static final int AV1Level41      = 0x200;
+        public static final int AV1Level42      = 0x400;
+        public static final int AV1Level43      = 0x800;
+        public static final int AV1Level5       = 0x1000;
+        public static final int AV1Level51      = 0x2000;
+        public static final int AV1Level52      = 0x4000;
+        public static final int AV1Level53      = 0x8000;
+        public static final int AV1Level6       = 0x10000;
+        public static final int AV1Level61      = 0x20000;
+        public static final int AV1Level62      = 0x40000;
+        public static final int AV1Level63      = 0x80000;
+        public static final int AV1Level7       = 0x100000;
+        public static final int AV1Level71      = 0x200000;
+        public static final int AV1Level72      = 0x400000;
+        public static final int AV1Level73      = 0x800000;
+
         /**
-         * Defined in the OpenMAX IL specs, depending on the type of media
-         * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
-         * OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_VP8PROFILETYPE or OMX_VIDEO_VP9PROFILETYPE.
+         * The profile of the media content. Depending on the type of media this can be
+         * one of the profile values defined in this class.
          */
         public int profile;
 
         /**
-         * Defined in the OpenMAX IL specs, depending on the type of media
-         * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
-         * OMX_VIDEO_MPEG4LEVELTYPE, OMX_VIDEO_VP8LEVELTYPE or OMX_VIDEO_VP9LEVELTYPE.
+         * The level of the media content. Depending on the type of media this can be
+         * one of the level values defined in this class.
          *
          * Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may
          * not advertise a profile level support. For those VP9 decoders, please use
@@ -3157,7 +3460,7 @@
         }
 
         return new MediaCodecInfo(
-                mName, mIsEncoder,
+                mName, mCanonicalName, mFlags,
                 caps.toArray(new CodecCapabilities[caps.size()]));
     }
 }
diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java
index 2e47865..a460954 100644
--- a/media/java/android/media/MediaCodecList.java
+++ b/media/java/android/media/MediaCodecList.java
@@ -111,12 +111,14 @@
             caps[typeIx++] = getCodecCapabilities(index, type);
         }
         return new MediaCodecInfo(
-                getCodecName(index), isEncoder(index), caps);
+                getCodecName(index), getCanonicalName(index), getAttributes(index), caps);
     }
 
     /* package private */ static native final String getCodecName(int index);
 
-    /* package private */ static native final boolean isEncoder(int index);
+    /* package private */ static native final String getCanonicalName(int index);
+
+    /* package private */ static native final int getAttributes(int index);
 
     /* package private */ static native final String[] getSupportedTypes(int index);
 
diff --git a/media/java/android/media/MediaConstants.java b/media/java/android/media/MediaConstants.java
deleted file mode 100644
index 275b0ac..0000000
--- a/media/java/android/media/MediaConstants.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.media;
-
-class MediaConstants {
-    // Bundle key for int
-    static final String KEY_PID = "android.media.key.PID";
-
-    // Bundle key for String
-    static final String KEY_PACKAGE_NAME = "android.media.key.PACKAGE_NAME";
-
-    // Bundle key for Parcelable
-    static final String KEY_SESSION2_STUB = "android.media.key.SESSION2_STUB";
-    static final String KEY_ALLOWED_COMMANDS = "android.media.key.ALLOWED_COMMANDS";
-
-    private MediaConstants() {
-    }
-}
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
deleted file mode 100644
index 7665c92..0000000
--- a/media/java/android/media/MediaController2.java
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * 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.media;
-
-import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS;
-import static android.media.MediaConstants.KEY_PACKAGE_NAME;
-import static android.media.MediaConstants.KEY_PID;
-import static android.media.MediaConstants.KEY_SESSION2_STUB;
-import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
-import static android.media.Session2Command.RESULT_INFO_SKIPPED;
-import static android.media.Session2Token.TYPE_SESSION;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.ResultReceiver;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-
-import java.util.concurrent.Executor;
-
-/**
- * Allows an app to interact with an active {@link MediaSession2} or a
- * {@link MediaSession2Service} which would provide {@link MediaSession2}. Media buttons and other
- * commands can be sent to the session.
- * <p>
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
- * @hide
- */
-public class MediaController2 implements AutoCloseable {
-    static final String TAG = "MediaController2";
-    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final ControllerCallback mCallback;
-
-    private final IBinder.DeathRecipient mDeathRecipient = () -> close();
-    private final Context mContext;
-    private final Session2Token mSessionToken;
-    private final Executor mCallbackExecutor;
-    private final Controller2Link mControllerStub;
-    private final Handler mResultHandler;
-
-    private final Object mLock = new Object();
-    //@GuardedBy("mLock")
-    private int mNextSeqNumber;
-    //@GuardedBy("mLock")
-    private Session2Link mSessionBinder;
-    //@GuardedBy("mLock")
-    private Session2CommandGroup mAllowedCommands;
-    //@GuardedBy("mLock")
-    private Session2Token mConnectedToken;
-    //@GuardedBy("mLock")
-    private ArrayMap<ResultReceiver, Integer> mPendingCommands;
-    //@GuardedBy("mLock")
-    private ArraySet<Integer> mRequestedCommandSeqNumbers;
-
-    /**
-     * Create a {@link MediaController2} from the {@link Session2Token}.
-     * This connects to the session and may wake up the service if it's not available.
-     *
-     * @param context Context
-     * @param token token to connect to
-     */
-    public MediaController2(@NonNull Context context, @NonNull Session2Token token) {
-        this(context, token, context.getMainExecutor(), new ControllerCallback() {});
-    }
-
-    /**
-     * Create a {@link MediaController2} from the {@link Session2Token}.
-     * This connects to the session and may wake up the service if it's not available.
-     *
-     * @param context Context
-     * @param token token to connect to
-     * @param executor executor to run callbacks on.
-     * @param callback controller callback to receive changes in.
-     */
-    public MediaController2(@NonNull Context context, @NonNull Session2Token token,
-            @NonNull Executor executor, @NonNull ControllerCallback callback) {
-        if (context == null) {
-            throw new IllegalArgumentException("context shouldn't be null");
-        }
-        if (token == null) {
-            throw new IllegalArgumentException("token shouldn't be null");
-        }
-        mContext = context;
-        mSessionToken = token;
-        mCallbackExecutor = (executor == null) ? context.getMainExecutor() : executor;
-        mCallback = (callback == null) ? new ControllerCallback() { } : callback;
-        mControllerStub = new Controller2Link(this);
-        // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
-        mResultHandler = new Handler(context.getMainLooper());
-
-        mNextSeqNumber = 0;
-        mPendingCommands = new ArrayMap<>();
-        mRequestedCommandSeqNumbers = new ArraySet<>();
-
-        if (token.getType() == TYPE_SESSION) {
-            connectToSession();
-        } else {
-            // TODO: Handle connect to session service.
-        }
-    }
-
-    @Override
-    public void close() {
-        synchronized (mLock) {
-            if (mSessionBinder != null) {
-                try {
-                    mSessionBinder.unlinkToDeath(mDeathRecipient, 0);
-                    mSessionBinder.disconnect(mControllerStub, getNextSeqNumber());
-                } catch (RuntimeException e)  {
-                    // No-op
-                }
-            }
-            mPendingCommands.clear();
-            mRequestedCommandSeqNumbers.clear();
-            mCallbackExecutor.execute(() -> {
-                mCallback.onDisconnected(MediaController2.this);
-            });
-            mSessionBinder = null;
-        }
-    }
-
-    /**
-     * Sends a session command to the session
-     * <p>
-     * @param command the session command
-     * @param args optional arguments
-     * @return a token which will be sent together in {@link ControllerCallback#onCommandResult}
-     *        when its result is received.
-     */
-    public Object sendSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-
-        ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) {
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                synchronized (mLock) {
-                    mPendingCommands.remove(this);
-                }
-                mCallbackExecutor.execute(() -> {
-                    mCallback.onCommandResult(MediaController2.this, this,
-                            command, new Session2Command.Result(resultCode, resultData));
-                });
-            }
-        };
-
-        synchronized (mLock) {
-            if (mSessionBinder != null) {
-                int seq = getNextSeqNumber();
-                mPendingCommands.put(resultReceiver, seq);
-                try {
-                    mSessionBinder.sendSessionCommand(mControllerStub, seq, command, args,
-                            resultReceiver);
-                } catch (RuntimeException e)  {
-                    mPendingCommands.remove(resultReceiver);
-                    resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null);
-                }
-            }
-        }
-        return resultReceiver;
-    }
-
-    /**
-     * Cancels the session command previously sent.
-     *
-     * @param token the token which is returned from {@link #sendSessionCommand}.
-     */
-    public void cancelSessionCommand(@NonNull Object token) {
-        if (token == null) {
-            throw new IllegalArgumentException("token shouldn't be null");
-        }
-        synchronized (mLock) {
-            if (mSessionBinder == null) return;
-            Integer seq = mPendingCommands.remove(token);
-            if (seq != null) {
-                mSessionBinder.cancelSessionCommand(mControllerStub, seq);
-            }
-        }
-    }
-
-    // Called by Controller2Link.onConnected
-    void onConnected(int seq, Bundle connectionResult) {
-        final long token = Binder.clearCallingIdentity();
-        try {
-            Session2Link sessionBinder = connectionResult.getParcelable(KEY_SESSION2_STUB);
-            Session2CommandGroup allowedCommands =
-                    connectionResult.getParcelable(KEY_ALLOWED_COMMANDS);
-            if (DEBUG) {
-                Log.d(TAG, "notifyConnected sessionBinder=" + sessionBinder
-                        + ", allowedCommands=" + allowedCommands);
-            }
-            if (sessionBinder == null || allowedCommands == null) {
-                // Connection rejected.
-                close();
-                return;
-            }
-            synchronized (mLock) {
-                mSessionBinder = sessionBinder;
-                mAllowedCommands = allowedCommands;
-                // Implementation for the local binder is no-op,
-                // so can be used without worrying about deadlock.
-                sessionBinder.linkToDeath(mDeathRecipient, 0);
-                mConnectedToken = new Session2Token(mSessionToken.getUid(), TYPE_SESSION,
-                        mSessionToken.getPackageName(), sessionBinder);
-            }
-            mCallbackExecutor.execute(() -> {
-                mCallback.onConnected(MediaController2.this, allowedCommands);
-            });
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    // Called by Controller2Link.onDisconnected
-    void onDisconnected(int seq) {
-        final long token = Binder.clearCallingIdentity();
-        try {
-            // close() will call mCallback.onDisconnected
-            close();
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    // Called by Controller2Link.onSessionCommand
-    void onSessionCommand(int seq, Session2Command command, Bundle args,
-            @Nullable ResultReceiver resultReceiver) {
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                mRequestedCommandSeqNumbers.add(seq);
-            }
-            mCallbackExecutor.execute(() -> {
-                boolean isCanceled;
-                synchronized (mLock) {
-                    isCanceled = !mRequestedCommandSeqNumbers.remove(seq);
-                }
-                if (isCanceled) {
-                    resultReceiver.send(RESULT_INFO_SKIPPED, null);
-                    return;
-                }
-                Session2Command.Result result = mCallback.onSessionCommand(
-                        MediaController2.this, command, args);
-                if (resultReceiver != null) {
-                    if (result == null) {
-                        throw new RuntimeException("onSessionCommand shouldn't return null");
-                    } else {
-                        resultReceiver.send(result.getResultCode(), result.getResultData());
-                    }
-                }
-            });
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    // Called by Controller2Link.onSessionCommand
-    void onCancelCommand(int seq) {
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                mRequestedCommandSeqNumbers.remove(seq);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    private int getNextSeqNumber() {
-        synchronized (mLock) {
-            return mNextSeqNumber++;
-        }
-    }
-
-    private void connectToSession() {
-        Session2Link sessionBinder = mSessionToken.getSessionLink();
-        Bundle connectionRequest = new Bundle();
-        connectionRequest.putString(KEY_PACKAGE_NAME, mContext.getPackageName());
-        connectionRequest.putInt(KEY_PID, Process.myPid());
-
-        try {
-            sessionBinder.connect(mControllerStub, getNextSeqNumber(), connectionRequest);
-        } catch (RuntimeException e) {
-            Log.w(TAG, "Failed to call connection request. Framework will retry"
-                    + " automatically");
-        }
-    }
-
-    /**
-     * Interface for listening to change in activeness of the {@link MediaSession2}.
-     * <p>
-     * This API is not generally intended for third party application developers.
-     */
-    public abstract static class ControllerCallback {
-        /**
-         * Called when the controller is successfully connected to the session. The controller
-         * becomes available afterwards.
-         *
-         * @param controller the controller for this event
-         * @param allowedCommands commands that's allowed by the session.
-         */
-        public void onConnected(@NonNull MediaController2 controller,
-                @NonNull Session2CommandGroup allowedCommands) { }
-
-        /**
-         * Called when the session refuses the controller or the controller is disconnected from
-         * the session. The controller becomes unavailable afterwards and the callback wouldn't
-         * be called.
-         * <p>
-         * It will be also called after the {@link #close()}, so you can put clean up code here.
-         * You don't need to call {@link #close()} after this.
-         *
-         * @param controller the controller for this event
-         */
-        public void onDisconnected(@NonNull MediaController2 controller) { }
-
-        /**
-         * Called when the connected session sent a session command.
-         *
-         * @param controller the controller for this event
-         * @param command the session command
-         * @param args optional arguments
-         * @return the result for the session command. A runtime exception will be thrown if null
-         *         is returned.
-         */
-        @NonNull
-        public Session2Command.Result onSessionCommand(@NonNull MediaController2 controller,
-                @NonNull Session2Command command, @Nullable Bundle args) {
-            return null;
-        }
-
-        /**
-         * Called when the command sent to the connected session is finished.
-         *
-         * @param controller the controller for this event
-         * @param token the token got from {@link MediaController2#sendSessionCommand}
-         * @param command the session command
-         * @param result the result of the session command
-         */
-        public void onCommandResult(@NonNull MediaController2 controller, @NonNull Object token,
-                @NonNull Session2Command command, @NonNull Session2Command.Result result) { }
-    }
-}
diff --git a/media/java/android/media/MediaDescription.java b/media/java/android/media/MediaDescription.java
index e6aea99..31079e5 100644
--- a/media/java/android/media/MediaDescription.java
+++ b/media/java/android/media/MediaDescription.java
@@ -7,6 +7,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 
 /**
  * A simple set of metadata for a media item suitable for display. This can be
@@ -122,9 +123,9 @@
 
     private MediaDescription(Parcel in) {
         mMediaId = in.readString();
-        mTitle = in.readCharSequence();
-        mSubtitle = in.readCharSequence();
-        mDescription = in.readCharSequence();
+        mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mIcon = in.readParcelable(null);
         mIconUri = in.readParcelable(null);
         mExtras = in.readBundle();
@@ -210,9 +211,9 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mMediaId);
-        dest.writeCharSequence(mTitle);
-        dest.writeCharSequence(mSubtitle);
-        dest.writeCharSequence(mDescription);
+        TextUtils.writeToParcel(mTitle, dest, 0);
+        TextUtils.writeToParcel(mSubtitle, dest, 0);
+        TextUtils.writeToParcel(mDescription, dest, 0);
         dest.writeParcelable(mIcon, flags);
         dest.writeParcelable(mIconUri, flags);
         dest.writeBundle(mExtras);
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index cdbc7b44..2d2c4a8 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -132,11 +132,19 @@
     private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES;
 
     private EventHandler mEventHandler;
-    private EventHandler mOnKeyStatusChangeEventHandler;
-    private EventHandler mOnExpirationUpdateEventHandler;
+    private EventHandler mKeyStatusChangeHandler;
+    private EventHandler mExpirationUpdateHandler;
+    private EventHandler mSessionLostStateHandler;
+
     private OnEventListener mOnEventListener;
     private OnKeyStatusChangeListener mOnKeyStatusChangeListener;
     private OnExpirationUpdateListener mOnExpirationUpdateListener;
+    private OnSessionLostStateListener mOnSessionLostStateListener;
+
+    private final Object mEventLock = new Object();
+    private final Object mKeyStatusChangeLock = new Object();
+    private final Object mExpirationUpdateLock = new Object();
+    private final Object mSessionLostStateLock = new Object();
 
     private long mNativeContext;
 
@@ -168,7 +176,8 @@
      * @param uuid The UUID of the crypto scheme.
      */
     public static final boolean isCryptoSchemeSupported(@NonNull UUID uuid) {
-        return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid), null);
+        return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid), null,
+                SECURITY_LEVEL_UNKNOWN);
     }
 
     /**
@@ -181,7 +190,25 @@
      */
     public static final boolean isCryptoSchemeSupported(
             @NonNull UUID uuid, @NonNull String mimeType) {
-        return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid), mimeType);
+        return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid),
+                mimeType, SECURITY_LEVEL_UNKNOWN);
+    }
+
+    /**
+     * Query if the given scheme identified by its UUID is supported on
+     * this device, and whether the DRM plugin is able to handle the
+     * media container format specified by mimeType at the requested
+     * security level.
+     *
+     * @param uuid The UUID of the crypto scheme.
+     * @param mimeType The MIME type of the media container, e.g. "video/mp4"
+     *   or "video/webm"
+     * @param securityLevel the security level requested
+     */
+    public static final boolean isCryptoSchemeSupported(
+            @NonNull UUID uuid, @NonNull String mimeType, @SecurityLevel int securityLevel) {
+        return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid), mimeType,
+                securityLevel);
     }
 
     private static final byte[] getByteArrayFromUUID(@NonNull UUID uuid) {
@@ -198,7 +225,36 @@
     }
 
     private static final native boolean isCryptoSchemeSupportedNative(
-            @NonNull byte[] uuid, @Nullable String mimeType);
+            @NonNull byte[] uuid, @Nullable String mimeType, @SecurityLevel int securityLevel);
+
+    private EventHandler createHandler() {
+        Looper looper;
+        EventHandler handler;
+        if ((looper = Looper.myLooper()) != null) {
+            handler = new EventHandler(this, looper);
+        } else if ((looper = Looper.getMainLooper()) != null) {
+            handler = new EventHandler(this, looper);
+        } else {
+            handler = null;
+        }
+        return handler;
+    }
+
+    private EventHandler updateHandler(Handler handler) {
+        Looper looper;
+        EventHandler newHandler = null;
+        if (handler != null) {
+            looper = handler.getLooper();
+        } else {
+            looper = Looper.myLooper();
+        }
+        if (looper != null) {
+            if (handler == null || handler.getLooper() != looper) {
+                newHandler = new EventHandler(this, looper);
+            }
+        }
+        return newHandler;
+    }
 
     /**
      * Instantiate a MediaDrm object
@@ -209,14 +265,10 @@
      * specified scheme UUID
      */
     public MediaDrm(@NonNull UUID uuid) throws UnsupportedSchemeException {
-        Looper looper;
-        if ((looper = Looper.myLooper()) != null) {
-            mEventHandler = new EventHandler(this, looper);
-        } else if ((looper = Looper.getMainLooper()) != null) {
-            mEventHandler = new EventHandler(this, looper);
-        } else {
-            mEventHandler = null;
-        }
+        mEventHandler = createHandler();
+        mKeyStatusChangeHandler = createHandler();
+        mExpirationUpdateHandler = createHandler();
+        mSessionLostStateHandler = createHandler();
 
         /* Native setup requires a weak reference to our object.
          * It's easier to create it here than in C++.
@@ -272,6 +324,40 @@
     }
 
     /**
+     * Thrown when an error occurs in any method that has a session context.
+     */
+    public static final class SessionException extends RuntimeException {
+        public SessionException(int errorCode, @Nullable String detailMessage) {
+            super(detailMessage);
+            mErrorCode = errorCode;
+        }
+
+        /**
+         * This indicates that apps using MediaDrm sessions are
+         * temporarily exceeding the capacity of available crypto
+         * resources. The app should retry the operation later.
+         */
+        public static final int ERROR_RESOURCE_CONTENTION = 1;
+
+        /** @hide */
+        @IntDef({
+            ERROR_RESOURCE_CONTENTION,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface SessionErrorCode {}
+
+        /**
+         * Retrieve the error code associated with the SessionException
+         */
+        @SessionErrorCode
+        public int getErrorCode() {
+            return mErrorCode;
+        }
+
+        private final int mErrorCode;
+    }
+
+    /**
      * Register a callback to be invoked when a session expiration update
      * occurs.  The app's OnExpirationUpdateListener will be notified
      * when the expiration time of the keys in the session have changed.
@@ -282,15 +368,12 @@
      */
     public void setOnExpirationUpdateListener(
             @Nullable OnExpirationUpdateListener listener, @Nullable Handler handler) {
-        if (listener != null) {
-            Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
-            if (looper != null) {
-                if (mEventHandler == null || mEventHandler.getLooper() != looper) {
-                    mEventHandler = new EventHandler(this, looper);
-                }
+        synchronized(mExpirationUpdateLock) {
+            if (listener != null) {
+                mExpirationUpdateHandler = updateHandler(handler);
             }
+            mOnExpirationUpdateListener = listener;
         }
-        mOnExpirationUpdateListener = listener;
     }
 
     /**
@@ -324,15 +407,12 @@
      */
     public void setOnKeyStatusChangeListener(
             @Nullable OnKeyStatusChangeListener listener, @Nullable Handler handler) {
-        if (listener != null) {
-            Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
-            if (looper != null) {
-                if (mEventHandler == null || mEventHandler.getLooper() != looper) {
-                    mEventHandler = new EventHandler(this, looper);
-                }
+        synchronized(mKeyStatusChangeLock) {
+            if (listener != null) {
+                mKeyStatusChangeHandler = updateHandler(handler);
             }
+            mOnKeyStatusChangeListener = listener;
         }
-        mOnKeyStatusChangeListener = listener;
     }
 
     /**
@@ -360,6 +440,46 @@
     }
 
     /**
+     * Register a callback to be invoked when session state has been
+     * lost. This event can occur on devices that are not capable of
+     * retaining crypto session state across device suspend/resume
+     * cycles.  When this event occurs, the session must be closed and
+     * a new session opened to resume operation.
+     *
+     * @param listener the callback that will be run, or {@code null} to unregister the
+     *     previously registered callback.
+     * @param handler the handler on which the listener should be invoked, or
+     *     {@code null} if the listener should be invoked on the calling thread's looper.
+     */
+    public void setOnSessionLostStateListener(
+            @Nullable OnSessionLostStateListener listener, @Nullable Handler handler) {
+        synchronized(mSessionLostStateLock) {
+            if (listener != null) {
+                mSessionLostStateHandler = updateHandler(handler);
+            }
+            mOnSessionLostStateListener = listener;
+        }
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when the
+     * session state has been lost and is now invalid
+     */
+    public interface OnSessionLostStateListener
+    {
+        /**
+         * Called when session state has lost state, to inform the app
+         * about the condition so it can close the session and open a new
+         * one to resume operation.
+         *
+         * @param md the MediaDrm object on which the event occurred
+         * @param sessionId the DRM session ID on which the event occurred
+         */
+        void onSessionLostState(
+                @NonNull MediaDrm md, @NonNull byte[] sessionId);
+    }
+
+    /**
      * Defines the status of a key.
      * A KeyStatus for each key in a session is provided to the
      * {@link OnKeyStatusChangeListener#onKeyStatusChange}
@@ -437,7 +557,9 @@
      */
     public void setOnEventListener(@Nullable OnEventListener listener)
     {
-        mOnEventListener = listener;
+        synchronized(mEventLock) {
+            mOnEventListener = listener;
+        }
     }
 
     /**
@@ -513,6 +635,7 @@
     private static final int DRM_EVENT = 200;
     private static final int EXPIRATION_UPDATE = 201;
     private static final int KEY_STATUS_CHANGE = 202;
+    private static final int SESSION_LOST_STATE = 203;
 
     private class EventHandler extends Handler
     {
@@ -532,52 +655,72 @@
             switch(msg.what) {
 
             case DRM_EVENT:
-                if (mOnEventListener != null) {
-                    if (msg.obj != null && msg.obj instanceof Parcel) {
-                        Parcel parcel = (Parcel)msg.obj;
-                        byte[] sessionId = parcel.createByteArray();
-                        if (sessionId.length == 0) {
-                            sessionId = null;
-                        }
-                        byte[] data = parcel.createByteArray();
-                        if (data.length == 0) {
-                            data = null;
-                        }
+                synchronized(mEventLock) {
+                    if (mOnEventListener != null) {
+                        if (msg.obj != null && msg.obj instanceof Parcel) {
+                            Parcel parcel = (Parcel)msg.obj;
+                            byte[] sessionId = parcel.createByteArray();
+                            if (sessionId.length == 0) {
+                                sessionId = null;
+                            }
+                            byte[] data = parcel.createByteArray();
+                            if (data.length == 0) {
+                                data = null;
+                            }
 
-                        Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
-                        mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
+                            Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
+                            mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
+                        }
                     }
                 }
                 return;
 
             case KEY_STATUS_CHANGE:
-                if (mOnKeyStatusChangeListener != null) {
-                    if (msg.obj != null && msg.obj instanceof Parcel) {
-                        Parcel parcel = (Parcel)msg.obj;
-                        byte[] sessionId = parcel.createByteArray();
-                        if (sessionId.length > 0) {
-                            List<KeyStatus> keyStatusList = keyStatusListFromParcel(parcel);
-                            boolean hasNewUsableKey = (parcel.readInt() != 0);
+                synchronized(mKeyStatusChangeLock) {
+                    if (mOnKeyStatusChangeListener != null) {
+                        if (msg.obj != null && msg.obj instanceof Parcel) {
+                            Parcel parcel = (Parcel)msg.obj;
+                            byte[] sessionId = parcel.createByteArray();
+                            if (sessionId.length > 0) {
+                                List<KeyStatus> keyStatusList = keyStatusListFromParcel(parcel);
+                                boolean hasNewUsableKey = (parcel.readInt() != 0);
 
-                            Log.i(TAG, "Drm key status changed");
-                            mOnKeyStatusChangeListener.onKeyStatusChange(mMediaDrm, sessionId,
-                                    keyStatusList, hasNewUsableKey);
+                                Log.i(TAG, "Drm key status changed");
+                                mOnKeyStatusChangeListener.onKeyStatusChange(mMediaDrm, sessionId,
+                                        keyStatusList, hasNewUsableKey);
+                            }
                         }
                     }
                 }
                 return;
 
             case EXPIRATION_UPDATE:
-                if (mOnExpirationUpdateListener != null) {
-                    if (msg.obj != null && msg.obj instanceof Parcel) {
-                        Parcel parcel = (Parcel)msg.obj;
-                        byte[] sessionId = parcel.createByteArray();
-                        if (sessionId.length > 0) {
-                            long expirationTime = parcel.readLong();
+                synchronized(mExpirationUpdateLock) {
+                    if (mOnExpirationUpdateListener != null) {
+                        if (msg.obj != null && msg.obj instanceof Parcel) {
+                            Parcel parcel = (Parcel)msg.obj;
+                            byte[] sessionId = parcel.createByteArray();
+                            if (sessionId.length > 0) {
+                                long expirationTime = parcel.readLong();
 
-                            Log.i(TAG, "Drm key expiration update: " + expirationTime);
-                            mOnExpirationUpdateListener.onExpirationUpdate(mMediaDrm, sessionId,
-                                    expirationTime);
+                                Log.i(TAG, "Drm key expiration update: " + expirationTime);
+                                mOnExpirationUpdateListener.onExpirationUpdate(mMediaDrm, sessionId,
+                                        expirationTime);
+                            }
+                        }
+                    }
+                }
+                return;
+
+            case SESSION_LOST_STATE:
+                synchronized(mSessionLostStateLock) {
+                    if (mOnSessionLostStateListener != null) {
+                        if (msg.obj != null && msg.obj instanceof Parcel) {
+                            Parcel parcel = (Parcel)msg.obj;
+                            byte[] sessionId = parcel.createByteArray();
+                            Log.i(TAG, "Drm session lost state event: ");
+                            mOnSessionLostStateListener.onSessionLostState(mMediaDrm,
+                                    sessionId);
                         }
                     }
                 }
@@ -619,9 +762,42 @@
         if (md == null) {
             return;
         }
-        if (md.mEventHandler != null) {
-            Message m = md.mEventHandler.obtainMessage(what, eventType, extra, obj);
-            md.mEventHandler.sendMessage(m);
+        switch (what) {
+            case DRM_EVENT:
+                synchronized(md.mEventLock) {
+                    if (md.mEventHandler != null) {
+                        Message m = md.mEventHandler.obtainMessage(what, eventType, extra, obj);
+                        md.mEventHandler.sendMessage(m);
+                    }
+                }
+                break;
+            case EXPIRATION_UPDATE:
+                synchronized(md.mExpirationUpdateLock) {
+                    if (md.mExpirationUpdateHandler != null) {
+                        Message m = md.mExpirationUpdateHandler.obtainMessage(what, obj);
+                        md.mExpirationUpdateHandler.sendMessage(m);
+                    }
+                }
+                break;
+            case KEY_STATUS_CHANGE:
+                synchronized(md.mKeyStatusChangeLock) {
+                    if (md.mKeyStatusChangeHandler != null) {
+                        Message m = md.mKeyStatusChangeHandler.obtainMessage(what, obj);
+                        md.mKeyStatusChangeHandler.sendMessage(m);
+                    }
+                }
+                break;
+            case SESSION_LOST_STATE:
+                synchronized(md.mSessionLostStateLock) {
+                    if (md.mSessionLostStateHandler != null) {
+                        Message m = md.mSessionLostStateHandler.obtainMessage(what, obj);
+                        md.mSessionLostStateHandler.sendMessage(m);
+                    }
+                }
+                break;
+            default:
+                Log.e(TAG, "Unknown message type " + what);
+                break;
         }
     }
 
@@ -1128,7 +1304,7 @@
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({HDCP_LEVEL_UNKNOWN, HDCP_NONE, HDCP_V1, HDCP_V2,
-                        HDCP_V2_1, HDCP_V2_2, HDCP_NO_DIGITAL_OUTPUT})
+                        HDCP_V2_1, HDCP_V2_2, HDCP_V2_3, HDCP_NO_DIGITAL_OUTPUT})
     public @interface HdcpLevel {}
 
 
@@ -1164,6 +1340,11 @@
     public static final int HDCP_V2_2 = 5;
 
     /**
+     *  HDCP version 2.3 Type 1.
+     */
+    public static final int HDCP_V2_3 = 6;
+
+    /**
      * No digital output, implicitly secure
      */
     public static final int HDCP_NO_DIGITAL_OUTPUT = Integer.MAX_VALUE;
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 594a224..c82b5f6 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -124,6 +124,7 @@
 public final class MediaFormat {
     public static final String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
     public static final String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
+    public static final String MIMETYPE_VIDEO_AV1 = "video/av01";
     public static final String MIMETYPE_VIDEO_AVC = "video/avc";
     public static final String MIMETYPE_VIDEO_HEVC = "video/hevc";
     public static final String MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
diff --git a/media/java/android/media/MediaItem2.java b/media/java/android/media/MediaItem2.java
deleted file mode 100644
index 235325e..0000000
--- a/media/java/android/media/MediaItem2.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * 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.media;
-
-import static android.media.MediaMetadata.METADATA_KEY_MEDIA_ID;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * A class with information on a single media item with the metadata information.
- * <p>
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
- * <p>
- * @hide
- */
-public class MediaItem2 implements Parcelable {
-    private static final String TAG = "MediaItem2";
-
-    // intentionally less than long.MAX_VALUE.
-    // Declare this first to avoid 'illegal forward reference'.
-    static final long LONG_MAX = 0x7ffffffffffffffL;
-
-    /**
-     * Used when a position is unknown.
-     *
-     * @see #getEndPosition()
-     */
-    public static final long POSITION_UNKNOWN = LONG_MAX;
-
-    public static final Parcelable.Creator<MediaItem2> CREATOR =
-            new Parcelable.Creator<MediaItem2>() {
-                @Override
-                public MediaItem2 createFromParcel(Parcel in) {
-                    return new MediaItem2(in);
-                }
-
-                @Override
-                public MediaItem2[] newArray(int size) {
-                    return new MediaItem2[size];
-                }
-            };
-
-    // TODO: Use SessionPlayer2.UNKNOWN_TIME instead
-    private static final long UNKNOWN_TIME = -1;
-
-    private final long mStartPositionMs;
-    private final long mEndPositionMs;
-
-    private final Object mLock = new Object();
-
-    @GuardedBy("mLock")
-    private MediaMetadata mMetadata;
-    @GuardedBy("mLock")
-    private final List<Pair<OnMetadataChangedListener, Executor>> mListeners = new ArrayList<>();
-
-    /**
-     * Used by {@link MediaItem2.Builder}.
-     */
-    // Note: Needs to be protected when we want to allow 3rd party player to define customized
-    //       MediaItem2.
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    MediaItem2(Builder builder) {
-        this(builder.mMetadata, builder.mStartPositionMs, builder.mEndPositionMs);
-    }
-
-    /**
-     * Used by Parcelable.Creator.
-     */
-    // Note: Needs to be protected when we want to allow 3rd party player to define customized
-    //       MediaItem2.
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    MediaItem2(Parcel in) {
-        this(in.readParcelable(MediaItem2.class.getClassLoader()), in.readLong(), in.readLong());
-    }
-
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    MediaItem2(MediaItem2 item) {
-        this(item.mMetadata, item.mStartPositionMs, item.mEndPositionMs);
-    }
-
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    MediaItem2(@Nullable MediaMetadata metadata, long startPositionMs, long endPositionMs) {
-        if (startPositionMs > endPositionMs) {
-            throw new IllegalArgumentException("Illegal start/end position: "
-                    + startPositionMs + " : " + endPositionMs);
-        }
-        if (metadata != null && metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
-            long durationMs = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
-            if (durationMs != UNKNOWN_TIME && endPositionMs != POSITION_UNKNOWN
-                    && endPositionMs > durationMs) {
-                throw new IllegalArgumentException("endPositionMs shouldn't be greater than"
-                        + " duration in the metdata, endPositionMs=" + endPositionMs
-                        + ", durationMs=" + durationMs);
-            }
-        }
-        mMetadata = metadata;
-        mStartPositionMs = startPositionMs;
-        mEndPositionMs = endPositionMs;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder(getClass().getSimpleName());
-        synchronized (mLock) {
-            sb.append("{mMetadata=").append(mMetadata);
-            sb.append(", mStartPositionMs=").append(mStartPositionMs);
-            sb.append(", mEndPositionMs=").append(mEndPositionMs);
-            sb.append('}');
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Sets metadata. If the metadata is not {@code null}, its id should be matched with this
-     * instance's media id.
-     *
-     * @param metadata metadata to update
-     * @see MediaMetadata#METADATA_KEY_MEDIA_ID
-     */
-    public void setMetadata(@Nullable MediaMetadata metadata) {
-        List<Pair<OnMetadataChangedListener, Executor>> listeners = new ArrayList<>();
-        synchronized (mLock) {
-            if (mMetadata != null && metadata != null
-                    && !TextUtils.equals(getMediaId(), metadata.getString(METADATA_KEY_MEDIA_ID))) {
-                Log.d(TAG, "MediaItem2's media ID shouldn't be changed");
-                return;
-            }
-            mMetadata = metadata;
-            listeners.addAll(mListeners);
-        }
-
-        for (Pair<OnMetadataChangedListener, Executor> pair : listeners) {
-            final OnMetadataChangedListener listener = pair.first;
-            pair.second.execute(new Runnable() {
-                @Override
-                public void run() {
-                    listener.onMetadataChanged(MediaItem2.this);
-                }
-            });
-        }
-    }
-
-    /**
-     * Gets the metadata of the media.
-     *
-     * @return metadata from the session
-     */
-    public @Nullable MediaMetadata getMetadata() {
-        synchronized (mLock) {
-            return mMetadata;
-        }
-    }
-
-    /**
-     * Return the position in milliseconds at which the playback will start.
-     * @return the position in milliseconds at which the playback will start
-     */
-    public long getStartPosition() {
-        return mStartPositionMs;
-    }
-
-    /**
-     * Return the position in milliseconds at which the playback will end.
-     * {@link #POSITION_UNKNOWN} means ending at the end of source content.
-     * @return the position in milliseconds at which the playback will end
-     */
-    public long getEndPosition() {
-        return mEndPositionMs;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeParcelable(mMetadata, 0);
-        dest.writeLong(mStartPositionMs);
-        dest.writeLong(mEndPositionMs);
-    }
-
-    /**
-     * Gets the media id for this item. If it's not {@code null}, it's a persistent unique key
-     * for the underlying media content.
-     *
-     * @return media Id from the session
-     */
-    @Nullable String getMediaId() {
-        synchronized (mLock) {
-            return mMetadata != null
-                    ? mMetadata.getString(METADATA_KEY_MEDIA_ID) : null;
-        }
-    }
-
-    void addOnMetadataChangedListener(Executor executor, OnMetadataChangedListener listener) {
-        synchronized (mLock) {
-            for (Pair<OnMetadataChangedListener, Executor> pair : mListeners) {
-                if (pair.first == listener) {
-                    return;
-                }
-            }
-            mListeners.add(new Pair<>(listener, executor));
-        }
-    }
-
-    void removeOnMetadataChangedListener(OnMetadataChangedListener listener) {
-        synchronized (mLock) {
-            for (int i = mListeners.size() - 1; i >= 0; i--) {
-                if (mListeners.get(i).first == listener) {
-                    mListeners.remove(i);
-                    return;
-                }
-            }
-        }
-    }
-
-    /**
-     * Builder for {@link MediaItem2}.
-     */
-    public static class Builder {
-        @SuppressWarnings("WeakerAccess") /* synthetic access */
-        MediaMetadata mMetadata;
-        @SuppressWarnings("WeakerAccess") /* synthetic access */
-        long mStartPositionMs = 0;
-        @SuppressWarnings("WeakerAccess") /* synthetic access */
-        long mEndPositionMs = POSITION_UNKNOWN;
-
-        /**
-         * Set the metadata of this instance. {@code null} for unset.
-         *
-         * @param metadata metadata
-         * @return this instance for chaining
-         */
-        public @NonNull Builder setMetadata(@Nullable MediaMetadata metadata) {
-            mMetadata = metadata;
-            return this;
-        }
-
-        /**
-         * Sets the start position in milliseconds at which the playback will start.
-         * Any negative number is treated as 0.
-         *
-         * @param position the start position in milliseconds at which the playback will start
-         * @return the same Builder instance.
-         */
-        public @NonNull Builder setStartPosition(long position) {
-            if (position < 0) {
-                position = 0;
-            }
-            mStartPositionMs = position;
-            return this;
-        }
-
-        /**
-         * Sets the end position in milliseconds at which the playback will end.
-         * Any negative number is treated as maximum length of the media item.
-         *
-         * @param position the end position in milliseconds at which the playback will end
-         * @return the same Builder instance.
-         */
-        public @NonNull Builder setEndPosition(long position) {
-            if (position < 0) {
-                position = POSITION_UNKNOWN;
-            }
-            mEndPositionMs = position;
-            return this;
-        }
-
-        /**
-         * Build {@link MediaItem2}.
-         *
-         * @return a new {@link MediaItem2}.
-         */
-        public @NonNull MediaItem2 build() {
-            return new MediaItem2(this);
-        }
-    }
-
-    interface OnMetadataChangedListener {
-        void onMetadataChanged(MediaItem2 item);
-    }
-}
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
deleted file mode 100644
index 2721ad1..0000000
--- a/media/java/android/media/MediaMetadata.java
+++ /dev/null
@@ -1,941 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media;
-
-import android.annotation.NonNull;
-import android.annotation.StringDef;
-import android.annotation.UnsupportedAppUsage;
-import android.content.ContentResolver;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.media.browse.MediaBrowser;
-import android.media.session.MediaController;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Set;
-import java.util.Objects;
-
-/**
- * Contains metadata about an item, such as the title, artist, etc.
- */
-public final class MediaMetadata implements Parcelable {
-    private static final String TAG = "MediaMetadata";
-
-    /**
-     * @hide
-     */
-    @StringDef(prefix = { "METADATA_KEY_" }, value = {
-            METADATA_KEY_TITLE,
-            METADATA_KEY_ARTIST,
-            METADATA_KEY_ALBUM,
-            METADATA_KEY_AUTHOR,
-            METADATA_KEY_WRITER,
-            METADATA_KEY_COMPOSER,
-            METADATA_KEY_COMPILATION,
-            METADATA_KEY_DATE,
-            METADATA_KEY_GENRE,
-            METADATA_KEY_ALBUM_ARTIST,
-            METADATA_KEY_ART_URI,
-            METADATA_KEY_ALBUM_ART_URI,
-            METADATA_KEY_DISPLAY_TITLE,
-            METADATA_KEY_DISPLAY_SUBTITLE,
-            METADATA_KEY_DISPLAY_DESCRIPTION,
-            METADATA_KEY_DISPLAY_ICON_URI,
-            METADATA_KEY_MEDIA_ID,
-            METADATA_KEY_MEDIA_URI,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface TextKey {}
-
-    /**
-     * @hide
-     */
-    @StringDef(prefix = { "METADATA_KEY_" }, value = {
-            METADATA_KEY_DURATION,
-            METADATA_KEY_YEAR,
-            METADATA_KEY_TRACK_NUMBER,
-            METADATA_KEY_NUM_TRACKS,
-            METADATA_KEY_DISC_NUMBER,
-            METADATA_KEY_BT_FOLDER_TYPE,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface LongKey {}
-
-    /**
-     * @hide
-     */
-    @StringDef(prefix = { "METADATA_KEY_" }, value = {
-            METADATA_KEY_ART,
-            METADATA_KEY_ALBUM_ART,
-            METADATA_KEY_DISPLAY_ICON,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface BitmapKey {}
-
-    /**
-     * @hide
-     */
-    @StringDef(prefix = { "METADATA_KEY_" }, value = {
-            METADATA_KEY_USER_RATING,
-            METADATA_KEY_RATING,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface RatingKey {}
-
-    /**
-     * The title of the media.
-     */
-    public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
-
-    /**
-     * The artist of the media.
-     */
-    public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
-
-    /**
-     * The duration of the media in ms. A negative duration indicates that the
-     * duration is unknown (or infinite).
-     */
-    public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
-
-    /**
-     * The album title for the media.
-     */
-    public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
-
-    /**
-     * The author of the media.
-     */
-    public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
-
-    /**
-     * The writer of the media.
-     */
-    public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
-
-    /**
-     * The composer of the media.
-     */
-    public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
-
-    /**
-     * The compilation status of the media.
-     */
-    public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
-
-    /**
-     * The date the media was created or published. The format is unspecified
-     * but RFC 3339 is recommended.
-     */
-    public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
-
-    /**
-     * The year the media was created or published as a long.
-     */
-    public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
-
-    /**
-     * The genre of the media.
-     */
-    public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
-
-    /**
-     * The track number for the media.
-     */
-    public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
-
-    /**
-     * The number of tracks in the media's original source.
-     */
-    public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
-
-    /**
-     * The disc number for the media's original source.
-     */
-    public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
-
-    /**
-     * The artist for the album of the media's original source.
-     */
-    public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
-
-    /**
-     * The artwork for the media as a {@link Bitmap}.
-     * <p>
-     * The artwork should be relatively small and may be scaled down by the
-     * system if it is too large. For higher resolution artwork
-     * {@link #METADATA_KEY_ART_URI} should be used instead.
-     */
-    public static final String METADATA_KEY_ART = "android.media.metadata.ART";
-
-    /**
-     * The artwork for the media as a Uri formatted String. The artwork can be
-     * loaded using a combination of {@link ContentResolver#openInputStream} and
-     * {@link BitmapFactory#decodeStream}.
-     * <p>
-     * For the best results, Uris should use the content:// style and support
-     * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
-     * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
-     */
-    public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
-
-    /**
-     * The artwork for the album of the media's original source as a
-     * {@link Bitmap}.
-     * <p>
-     * The artwork should be relatively small and may be scaled down by the
-     * system if it is too large. For higher resolution artwork
-     * {@link #METADATA_KEY_ALBUM_ART_URI} should be used instead.
-     */
-    public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
-
-    /**
-     * The artwork for the album of the media's original source as a Uri
-     * formatted String. The artwork can be loaded using a combination of
-     * {@link ContentResolver#openInputStream} and
-     * {@link BitmapFactory#decodeStream}.
-     * <p>
-     * For the best results, Uris should use the content:// style and support
-     * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
-     * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
-     */
-    public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
-
-    /**
-     * The user's rating for the media.
-     *
-     * @see Rating
-     */
-    public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
-
-    /**
-     * The overall rating for the media.
-     *
-     * @see Rating
-     */
-    public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
-
-    /**
-     * A title that is suitable for display to the user. This will generally be
-     * the same as {@link #METADATA_KEY_TITLE} but may differ for some formats.
-     * When displaying media described by this metadata this should be preferred
-     * if present.
-     */
-    public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
-
-    /**
-     * A subtitle that is suitable for display to the user. When displaying a
-     * second line for media described by this metadata this should be preferred
-     * to other fields if present.
-     */
-    public static final String METADATA_KEY_DISPLAY_SUBTITLE
-            = "android.media.metadata.DISPLAY_SUBTITLE";
-
-    /**
-     * A description that is suitable for display to the user. When displaying
-     * more information for media described by this metadata this should be
-     * preferred to other fields if present.
-     */
-    public static final String METADATA_KEY_DISPLAY_DESCRIPTION
-            = "android.media.metadata.DISPLAY_DESCRIPTION";
-
-    /**
-     * An icon or thumbnail that is suitable for display to the user. When
-     * displaying an icon for media described by this metadata this should be
-     * preferred to other fields if present. This must be a {@link Bitmap}.
-     * <p>
-     * The icon should be relatively small and may be scaled down by the system
-     * if it is too large. For higher resolution artwork
-     * {@link #METADATA_KEY_DISPLAY_ICON_URI} should be used instead.
-     */
-    public static final String METADATA_KEY_DISPLAY_ICON
-            = "android.media.metadata.DISPLAY_ICON";
-
-    /**
-     * A Uri formatted String for an icon or thumbnail that is suitable for
-     * display to the user. When displaying more information for media described
-     * by this metadata the display description should be preferred to other
-     * fields when present. The icon can be loaded using a combination of
-     * {@link ContentResolver#openInputStream} and
-     * {@link BitmapFactory#decodeStream}.
-     * <p>
-     * For the best results, Uris should use the content:// style and support
-     * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
-     * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
-     */
-    public static final String METADATA_KEY_DISPLAY_ICON_URI
-            = "android.media.metadata.DISPLAY_ICON_URI";
-
-    /**
-     * A String key for identifying the content. This value is specific to the
-     * service providing the content. If used, this should be a persistent
-     * unique key for the underlying content. It may be used with
-     * {@link MediaController.TransportControls#playFromMediaId(String, Bundle)}
-     * to initiate playback when provided by a {@link MediaBrowser} connected to
-     * the same app.
-     */
-    public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
-
-    /**
-     * A Uri formatted String representing the content. This value is specific to the
-     * service providing the content. It may be used with
-     * {@link MediaController.TransportControls#playFromUri(Uri, Bundle)}
-     * to initiate playback when provided by a {@link MediaBrowser} connected to
-     * the same app.
-     */
-    public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
-
-    /**
-     * The bluetooth folder type of the media specified in the section 6.10.2.2 of the Bluetooth
-     * AVRCP 1.5. It should be one of the following:
-     * <ul>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_MIXED}</li>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_TITLES}</li>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_ALBUMS}</li>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_ARTISTS}</li>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_GENRES}</li>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_PLAYLISTS}</li>
-     * <li>{@link MediaDescription#BT_FOLDER_TYPE_YEARS}</li>
-     * </ul>
-     */
-    public static final String METADATA_KEY_BT_FOLDER_TYPE
-            = "android.media.metadata.BT_FOLDER_TYPE";
-
-    private static final @TextKey String[] PREFERRED_DESCRIPTION_ORDER = {
-            METADATA_KEY_TITLE,
-            METADATA_KEY_ARTIST,
-            METADATA_KEY_ALBUM,
-            METADATA_KEY_ALBUM_ARTIST,
-            METADATA_KEY_WRITER,
-            METADATA_KEY_AUTHOR,
-            METADATA_KEY_COMPOSER
-    };
-
-    private static final @BitmapKey String[] PREFERRED_BITMAP_ORDER = {
-            METADATA_KEY_DISPLAY_ICON,
-            METADATA_KEY_ART,
-            METADATA_KEY_ALBUM_ART
-    };
-
-    private static final @TextKey String[] PREFERRED_URI_ORDER = {
-            METADATA_KEY_DISPLAY_ICON_URI,
-            METADATA_KEY_ART_URI,
-            METADATA_KEY_ALBUM_ART_URI
-    };
-
-    private static final int METADATA_TYPE_INVALID = -1;
-    private static final int METADATA_TYPE_LONG = 0;
-    private static final int METADATA_TYPE_TEXT = 1;
-    private static final int METADATA_TYPE_BITMAP = 2;
-    private static final int METADATA_TYPE_RATING = 3;
-    private static final ArrayMap<String, Integer> METADATA_KEYS_TYPE;
-
-    static {
-        METADATA_KEYS_TYPE = new ArrayMap<String, Integer>();
-        METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_TITLE, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_SUBTITLE, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON, METADATA_TYPE_BITMAP);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON_URI, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_BT_FOLDER_TYPE, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_ID, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_URI, METADATA_TYPE_TEXT);
-    }
-
-    private static final SparseArray<String> EDITOR_KEY_MAPPING;
-
-    static {
-        EDITOR_KEY_MAPPING = new SparseArray<String>();
-        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.BITMAP_KEY_ARTWORK, METADATA_KEY_ART);
-        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_OTHERS, METADATA_KEY_RATING);
-        EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_USER, METADATA_KEY_USER_RATING);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_KEY_ALBUM);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
-                METADATA_KEY_ALBUM_ARTIST);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_KEY_ARTIST);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_KEY_AUTHOR);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
-                METADATA_KEY_TRACK_NUMBER);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_KEY_COMPOSER);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPILATION,
-                METADATA_KEY_COMPILATION);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_KEY_DATE);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
-                METADATA_KEY_DISC_NUMBER);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_KEY_DURATION);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_KEY_GENRE);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS,
-                METADATA_KEY_NUM_TRACKS);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_KEY_TITLE);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_KEY_WRITER);
-        EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_KEY_YEAR);
-    }
-
-    private final Bundle mBundle;
-    private MediaDescription mDescription;
-
-    private MediaMetadata(Bundle bundle) {
-        mBundle = new Bundle(bundle);
-    }
-
-    private MediaMetadata(Parcel in) {
-        mBundle = Bundle.setDefusable(in.readBundle(), true);
-    }
-
-    /**
-     * Returns true if the given key is contained in the metadata
-     *
-     * @param key a String key
-     * @return true if the key exists in this metadata, false otherwise
-     */
-    public boolean containsKey(String key) {
-        return mBundle.containsKey(key);
-    }
-
-    /**
-     * Returns the value associated with the given key, or null if no mapping of
-     * the desired type exists for the given key or a null value is explicitly
-     * associated with the key.
-     *
-     * @param key The key the value is stored under
-     * @return a CharSequence value, or null
-     */
-    public CharSequence getText(@TextKey String key) {
-        return mBundle.getCharSequence(key);
-    }
-
-    /**
-     * Returns the text value associated with the given key as a String, or null
-     * if no mapping of the desired type exists for the given key or a null
-     * value is explicitly associated with the key. This is equivalent to
-     * calling {@link #getText getText().toString()} if the value is not null.
-     *
-     * @param key The key the value is stored under
-     * @return a String value, or null
-     */
-    public String getString(@TextKey String key) {
-        CharSequence text = getText(key);
-        if (text != null) {
-            return text.toString();
-        }
-        return null;
-    }
-
-    /**
-     * Returns the value associated with the given key, or 0L if no long exists
-     * for the given key.
-     *
-     * @param key The key the value is stored under
-     * @return a long value
-     */
-    public long getLong(@LongKey String key) {
-        return mBundle.getLong(key, 0);
-    }
-
-    /**
-     * Returns a {@link Rating} for the given key or null if no rating exists
-     * for the given key.
-     *
-     * @param key The key the value is stored under
-     * @return A {@link Rating} or null
-     */
-    public Rating getRating(@RatingKey String key) {
-        Rating rating = null;
-        try {
-            rating = mBundle.getParcelable(key);
-        } catch (Exception e) {
-            // ignore, value was not a bitmap
-            Log.w(TAG, "Failed to retrieve a key as Rating.", e);
-        }
-        return rating;
-    }
-
-    /**
-     * Returns a {@link Bitmap} for the given key or null if no bitmap exists
-     * for the given key.
-     *
-     * @param key The key the value is stored under
-     * @return A {@link Bitmap} or null
-     */
-    public Bitmap getBitmap(@BitmapKey String key) {
-        Bitmap bmp = null;
-        try {
-            bmp = mBundle.getParcelable(key);
-        } catch (Exception e) {
-            // ignore, value was not a bitmap
-            Log.w(TAG, "Failed to retrieve a key as Bitmap.", e);
-        }
-        return bmp;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeBundle(mBundle);
-    }
-
-    /**
-     * Returns the number of fields in this metadata.
-     *
-     * @return The number of fields in the metadata.
-     */
-    public int size() {
-        return mBundle.size();
-    }
-
-    /**
-     * Returns a Set containing the Strings used as keys in this metadata.
-     *
-     * @return a Set of String keys
-     */
-    public Set<String> keySet() {
-        return mBundle.keySet();
-    }
-
-    /**
-     * Returns a simple description of this metadata for display purposes.
-     *
-     * @return A simple description of this metadata.
-     */
-    public @NonNull MediaDescription getDescription() {
-        if (mDescription != null) {
-            return mDescription;
-        }
-
-        String mediaId = getString(METADATA_KEY_MEDIA_ID);
-
-        CharSequence[] text = new CharSequence[3];
-        Bitmap icon = null;
-        Uri iconUri = null;
-
-        // First handle the case where display data is set already
-        CharSequence displayText = getText(METADATA_KEY_DISPLAY_TITLE);
-        if (!TextUtils.isEmpty(displayText)) {
-            // If they have a display title use only display data, otherwise use
-            // our best bets
-            text[0] = displayText;
-            text[1] = getText(METADATA_KEY_DISPLAY_SUBTITLE);
-            text[2] = getText(METADATA_KEY_DISPLAY_DESCRIPTION);
-        } else {
-            // Use whatever fields we can
-            int textIndex = 0;
-            int keyIndex = 0;
-            while (textIndex < text.length && keyIndex < PREFERRED_DESCRIPTION_ORDER.length) {
-                CharSequence next = getText(PREFERRED_DESCRIPTION_ORDER[keyIndex++]);
-                if (!TextUtils.isEmpty(next)) {
-                    // Fill in the next empty bit of text
-                    text[textIndex++] = next;
-                }
-            }
-        }
-
-        // Get the best art bitmap we can find
-        for (int i = 0; i < PREFERRED_BITMAP_ORDER.length; i++) {
-            Bitmap next = getBitmap(PREFERRED_BITMAP_ORDER[i]);
-            if (next != null) {
-                icon = next;
-                break;
-            }
-        }
-
-        // Get the best Uri we can find
-        for (int i = 0; i < PREFERRED_URI_ORDER.length; i++) {
-            String next = getString(PREFERRED_URI_ORDER[i]);
-            if (!TextUtils.isEmpty(next)) {
-                iconUri = Uri.parse(next);
-                break;
-            }
-        }
-
-        Uri mediaUri = null;
-        String mediaUriStr = getString(METADATA_KEY_MEDIA_URI);
-        if (!TextUtils.isEmpty(mediaUriStr)) {
-            mediaUri = Uri.parse(mediaUriStr);
-        }
-
-        MediaDescription.Builder bob = new MediaDescription.Builder();
-        bob.setMediaId(mediaId);
-        bob.setTitle(text[0]);
-        bob.setSubtitle(text[1]);
-        bob.setDescription(text[2]);
-        bob.setIconBitmap(icon);
-        bob.setIconUri(iconUri);
-        bob.setMediaUri(mediaUri);
-        if (mBundle.containsKey(METADATA_KEY_BT_FOLDER_TYPE)) {
-            Bundle bundle = new Bundle();
-            bundle.putLong(MediaDescription.EXTRA_BT_FOLDER_TYPE,
-                    getLong(METADATA_KEY_BT_FOLDER_TYPE));
-            bob.setExtras(bundle);
-        }
-        mDescription = bob.build();
-
-        return mDescription;
-    }
-
-    /**
-     * Helper for getting the String key used by {@link MediaMetadata} from the
-     * integer key that {@link MediaMetadataEditor} uses.
-     *
-     * @param editorKey The key used by the editor
-     * @return The key used by this class or null if no mapping exists
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public static String getKeyFromMetadataEditorKey(int editorKey) {
-        return EDITOR_KEY_MAPPING.get(editorKey, null);
-    }
-
-    public static final Parcelable.Creator<MediaMetadata> CREATOR =
-            new Parcelable.Creator<MediaMetadata>() {
-                @Override
-                public MediaMetadata createFromParcel(Parcel in) {
-                    return new MediaMetadata(in);
-                }
-
-                @Override
-                public MediaMetadata[] newArray(int size) {
-                    return new MediaMetadata[size];
-                }
-            };
-
-    /**
-     * Compares the contents of this object to another MediaMetadata object. It
-     * does not compare Bitmaps and Ratings as the media player can choose to
-     * forgo these fields depending on how you retrieve the MediaMetadata.
-     *
-     * @param o The Metadata object to compare this object against
-     * @return Whether or not the two objects have matching fields (excluding
-     * Bitmaps and Ratings)
-     */
-    @Override
-    public boolean equals(Object o) {
-        if (o == this) {
-            return true;
-        }
-
-        if (!(o instanceof MediaMetadata)) {
-            return false;
-        }
-
-        final MediaMetadata m = (MediaMetadata) o;
-
-        for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
-            String key = METADATA_KEYS_TYPE.keyAt(i);
-            switch (METADATA_KEYS_TYPE.valueAt(i)) {
-                case METADATA_TYPE_TEXT:
-                    if (!Objects.equals(getString(key), m.getString(key))) {
-                        return false;
-                    }
-                    break;
-                case METADATA_TYPE_LONG:
-                    if (getLong(key) != m.getLong(key)) {
-                        return false;
-                    }
-                    break;
-                default:
-                    // Ignore ratings and bitmaps when comparing
-                    break;
-            }
-        }
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int hashCode = 17;
-
-        for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
-            String key = METADATA_KEYS_TYPE.keyAt(i);
-            switch (METADATA_KEYS_TYPE.valueAt(i)) {
-                case METADATA_TYPE_TEXT:
-                    hashCode = 31 * hashCode + Objects.hash(getString(key));
-                    break;
-                case METADATA_TYPE_LONG:
-                    hashCode = 31 * hashCode + Long.hashCode(getLong(key));
-                    break;
-                default:
-                    // Ignore ratings and bitmaps when comparing
-                    break;
-            }
-        }
-
-        return hashCode;
-    }
-
-    /**
-     * Use to build MediaMetadata objects. The system defined metadata keys must
-     * use the appropriate data type.
-     */
-    public static final class Builder {
-        private final Bundle mBundle;
-
-        /**
-         * Create an empty Builder. Any field that should be included in the
-         * {@link MediaMetadata} must be added.
-         */
-        public Builder() {
-            mBundle = new Bundle();
-        }
-
-        /**
-         * Create a Builder using a {@link MediaMetadata} instance to set the
-         * initial values. All fields in the source metadata will be included in
-         * the new metadata. Fields can be overwritten by adding the same key.
-         *
-         * @param source
-         */
-        public Builder(MediaMetadata source) {
-            mBundle = new Bundle(source.mBundle);
-        }
-
-        /**
-         * Create a Builder using a {@link MediaMetadata} instance to set
-         * initial values, but replace bitmaps with a scaled down copy if they
-         * are larger than maxBitmapSize.
-         *
-         * @param source The original metadata to copy.
-         * @param maxBitmapSize The maximum height/width for bitmaps contained
-         *            in the metadata.
-         * @hide
-         */
-        public Builder(MediaMetadata source, int maxBitmapSize) {
-            this(source);
-            for (String key : mBundle.keySet()) {
-                Object value = mBundle.get(key);
-                if (value != null && value instanceof Bitmap) {
-                    Bitmap bmp = (Bitmap) value;
-                    if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) {
-                        putBitmap(key, scaleBitmap(bmp, maxBitmapSize));
-                    }
-                }
-            }
-        }
-
-        /**
-         * Put a CharSequence value into the metadata. Custom keys may be used,
-         * but if the METADATA_KEYs defined in this class are used they may only
-         * be one of the following:
-         * <ul>
-         * <li>{@link #METADATA_KEY_TITLE}</li>
-         * <li>{@link #METADATA_KEY_ARTIST}</li>
-         * <li>{@link #METADATA_KEY_ALBUM}</li>
-         * <li>{@link #METADATA_KEY_AUTHOR}</li>
-         * <li>{@link #METADATA_KEY_WRITER}</li>
-         * <li>{@link #METADATA_KEY_COMPOSER}</li>
-         * <li>{@link #METADATA_KEY_DATE}</li>
-         * <li>{@link #METADATA_KEY_GENRE}</li>
-         * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
-         * <li>{@link #METADATA_KEY_ART_URI}</li>
-         * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
-         * </ul>
-         *
-         * @param key The key for referencing this value
-         * @param value The CharSequence value to store
-         * @return The Builder to allow chaining
-         */
-        public Builder putText(@TextKey String key, CharSequence value) {
-            if (METADATA_KEYS_TYPE.containsKey(key)) {
-                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
-                    throw new IllegalArgumentException("The " + key
-                            + " key cannot be used to put a CharSequence");
-                }
-            }
-            mBundle.putCharSequence(key, value);
-            return this;
-        }
-
-        /**
-         * Put a String value into the metadata. Custom keys may be used, but if
-         * the METADATA_KEYs defined in this class are used they may only be one
-         * of the following:
-         * <ul>
-         * <li>{@link #METADATA_KEY_TITLE}</li>
-         * <li>{@link #METADATA_KEY_ARTIST}</li>
-         * <li>{@link #METADATA_KEY_ALBUM}</li>
-         * <li>{@link #METADATA_KEY_AUTHOR}</li>
-         * <li>{@link #METADATA_KEY_WRITER}</li>
-         * <li>{@link #METADATA_KEY_COMPOSER}</li>
-         * <li>{@link #METADATA_KEY_DATE}</li>
-         * <li>{@link #METADATA_KEY_GENRE}</li>
-         * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
-         * <li>{@link #METADATA_KEY_ART_URI}</li>
-         * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
-         * </ul>
-         * <p>
-         * Uris for artwork should use the content:// style and support
-         * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork
-         * through {@link ContentResolver#openTypedAssetFileDescriptor(Uri,
-         * String, Bundle)}.
-         *
-         * @param key The key for referencing this value
-         * @param value The String value to store
-         * @return The Builder to allow chaining
-         */
-        public Builder putString(@TextKey String key, String value) {
-            if (METADATA_KEYS_TYPE.containsKey(key)) {
-                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
-                    throw new IllegalArgumentException("The " + key
-                            + " key cannot be used to put a String");
-                }
-            }
-            mBundle.putCharSequence(key, value);
-            return this;
-        }
-
-        /**
-         * Put a long value into the metadata. Custom keys may be used, but if
-         * the METADATA_KEYs defined in this class are used they may only be one
-         * of the following:
-         * <ul>
-         * <li>{@link #METADATA_KEY_DURATION}</li>
-         * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li>
-         * <li>{@link #METADATA_KEY_NUM_TRACKS}</li>
-         * <li>{@link #METADATA_KEY_DISC_NUMBER}</li>
-         * <li>{@link #METADATA_KEY_YEAR}</li>
-         * </ul>
-         *
-         * @param key The key for referencing this value
-         * @param value The long value to store
-         * @return The Builder to allow chaining
-         */
-        public Builder putLong(@LongKey String key, long value) {
-            if (METADATA_KEYS_TYPE.containsKey(key)) {
-                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) {
-                    throw new IllegalArgumentException("The " + key
-                            + " key cannot be used to put a long");
-                }
-            }
-            mBundle.putLong(key, value);
-            return this;
-        }
-
-        /**
-         * Put a {@link Rating} into the metadata. Custom keys may be used, but
-         * if the METADATA_KEYs defined in this class are used they may only be
-         * one of the following:
-         * <ul>
-         * <li>{@link #METADATA_KEY_RATING}</li>
-         * <li>{@link #METADATA_KEY_USER_RATING}</li>
-         * </ul>
-         *
-         * @param key The key for referencing this value
-         * @param value The Rating value to store
-         * @return The Builder to allow chaining
-         */
-        public Builder putRating(@RatingKey String key, Rating value) {
-            if (METADATA_KEYS_TYPE.containsKey(key)) {
-                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) {
-                    throw new IllegalArgumentException("The " + key
-                            + " key cannot be used to put a Rating");
-                }
-            }
-            mBundle.putParcelable(key, value);
-            return this;
-        }
-
-        /**
-         * Put a {@link Bitmap} into the metadata. Custom keys may be used, but
-         * if the METADATA_KEYs defined in this class are used they may only be
-         * one of the following:
-         * <ul>
-         * <li>{@link #METADATA_KEY_ART}</li>
-         * <li>{@link #METADATA_KEY_ALBUM_ART}</li>
-         * <li>{@link #METADATA_KEY_DISPLAY_ICON}</li>
-         * </ul>
-         * <p>
-         * Large bitmaps may be scaled down by the system when
-         * {@link android.media.session.MediaSession#setMetadata} is called.
-         * To pass full resolution images {@link Uri Uris} should be used with
-         * {@link #putString}.
-         *
-         * @param key The key for referencing this value
-         * @param value The Bitmap to store
-         * @return The Builder to allow chaining
-         */
-        public Builder putBitmap(@BitmapKey String key, Bitmap value) {
-            if (METADATA_KEYS_TYPE.containsKey(key)) {
-                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) {
-                    throw new IllegalArgumentException("The " + key
-                            + " key cannot be used to put a Bitmap");
-                }
-            }
-            mBundle.putParcelable(key, value);
-            return this;
-        }
-
-        /**
-         * Creates a {@link MediaMetadata} instance with the specified fields.
-         *
-         * @return The new MediaMetadata instance
-         */
-        public MediaMetadata build() {
-            return new MediaMetadata(mBundle);
-        }
-
-        private Bitmap scaleBitmap(Bitmap bmp, int maxSize) {
-            float maxSizeF = maxSize;
-            float widthScale = maxSizeF / bmp.getWidth();
-            float heightScale = maxSizeF / bmp.getHeight();
-            float scale = Math.min(widthScale, heightScale);
-            int height = (int) (bmp.getHeight() * scale);
-            int width = (int) (bmp.getWidth() * scale);
-            return Bitmap.createScaledBitmap(bmp, width, height, true);
-        }
-    }
-}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 0057875..fb18c3b 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -25,8 +25,10 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
+import android.graphics.SurfaceTexture;
+import android.media.SubtitleController.Anchor;
+import android.media.SubtitleTrack.RenderingWidget;
 import android.net.Uri;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -35,30 +37,19 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
-import android.os.Process;
 import android.os.PowerManager;
+import android.os.Process;
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
-import android.util.ArrayMap;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.widget.VideoView;
-import android.graphics.SurfaceTexture;
-import android.media.AudioManager;
-import android.media.MediaDrm;
-import android.media.MediaFormat;
-import android.media.MediaTimeProvider;
-import android.media.PlaybackParams;
-import android.media.SubtitleController;
-import android.media.SubtitleController.Anchor;
-import android.media.SubtitleData;
-import android.media.SubtitleTrack.RenderingWidget;
-import android.media.SyncParams;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
@@ -72,7 +63,6 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.lang.Runnable;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
@@ -2105,9 +2095,11 @@
         mOnInfoListener = null;
         mOnVideoSizeChangedListener = null;
         mOnTimedTextListener = null;
-        if (mTimeProvider != null) {
-            mTimeProvider.close();
-            mTimeProvider = null;
+        synchronized (mTimeProviderLock) {
+            if (mTimeProvider != null) {
+                mTimeProvider.close();
+                mTimeProvider = null;
+            }
         }
         synchronized(this) {
             mSubtitleDataListenerDisabled = false;
@@ -2147,9 +2139,11 @@
         if (mSubtitleController != null) {
             mSubtitleController.reset();
         }
-        if (mTimeProvider != null) {
-            mTimeProvider.close();
-            mTimeProvider = null;
+        synchronized (mTimeProviderLock) {
+            if (mTimeProvider != null) {
+                mTimeProvider.close();
+                mTimeProvider = null;
+            }
         }
 
         stayAwake(false);
@@ -2790,12 +2784,17 @@
                 synchronized (mIndexTrackPairs) {
                     mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
                 }
-                Handler h = mTimeProvider.mEventHandler;
-                int what = TimeProvider.NOTIFY;
-                int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
-                Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, contents.getBytes());
-                Message m = h.obtainMessage(what, arg1, 0, trackData);
-                h.sendMessage(m);
+                synchronized (mTimeProviderLock) {
+                    if (mTimeProvider != null) {
+                        Handler h = mTimeProvider.mEventHandler;
+                        int what = TimeProvider.NOTIFY;
+                        int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
+                        Pair<SubtitleTrack, byte[]> trackData =
+                                Pair.create(track, contents.getBytes());
+                        Message m = h.obtainMessage(what, arg1, 0, trackData);
+                        h.sendMessage(m);
+                    }
+                }
                 return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
             }
 
@@ -3020,12 +3019,17 @@
                             total += bytes;
                         }
                     }
-                    Handler h = mTimeProvider.mEventHandler;
-                    int what = TimeProvider.NOTIFY;
-                    int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
-                    Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, bos.toByteArray());
-                    Message m = h.obtainMessage(what, arg1, 0, trackData);
-                    h.sendMessage(m);
+                    synchronized (mTimeProviderLock) {
+                        if (mTimeProvider != null) {
+                            Handler h = mTimeProvider.mEventHandler;
+                            int what = TimeProvider.NOTIFY;
+                            int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
+                            Pair<SubtitleTrack, byte[]> trackData =
+                                    Pair.create(track, bos.toByteArray());
+                            Message m = h.obtainMessage(what, arg1, 0, trackData);
+                            h.sendMessage(m);
+                        }
+                    }
                     return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
                 } catch (Exception e) {
                     Log.e(TAG, e.getMessage(), e);
@@ -3308,14 +3312,17 @@
     private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
 
     private TimeProvider mTimeProvider;
+    private final Object mTimeProviderLock = new Object();
 
     /** @hide */
     @UnsupportedAppUsage
     public MediaTimeProvider getMediaTimeProvider() {
-        if (mTimeProvider == null) {
-            mTimeProvider = new TimeProvider(this);
+        synchronized (mTimeProviderLock) {
+            if (mTimeProvider == null) {
+                mTimeProvider = new TimeProvider(this);
+            }
+            return mTimeProvider;
         }
-        return mTimeProvider;
     }
 
     private class EventHandler extends Handler
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
deleted file mode 100644
index cef6614..0000000
--- a/media/java/android/media/MediaPlayer2.java
+++ /dev/null
@@ -1,4905 +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.
- */
-
-package android.media;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringDef;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.graphics.Rect;
-import android.graphics.SurfaceTexture;
-import android.media.MediaPlayer2.DrmInfo;
-import android.media.MediaPlayer2Proto.PlayerMessage;
-import android.media.MediaPlayer2Proto.Value;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.os.PersistableBundle;
-import android.os.PowerManager;
-import android.util.Log;
-import android.util.Pair;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-
-import com.android.framework.protobuf.InvalidProtocolBufferException;
-import com.android.internal.annotations.GuardedBy;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.net.HttpCookie;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.nio.ByteOrder;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Queue;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * MediaPlayer2 class can be used to control playback of audio/video files and streams.
- *
- * <p>Topics covered here are:
- * <ol>
- * <li><a href="#PlayerStates">Player states</a>
- * <li><a href="#InvalidStates">Invalid method calls</a>
- * <li><a href="#Permissions">Permissions</a>
- * <li><a href="#Callbacks">Callbacks</a>
- * </ol>
- *
- *
- * <h3 id="PlayerStates">Player states</h3>
- *
- * <p>The playback control of audio/video files is managed as a state machine.</p>
- * <p><div style="text-align:center;"><img src="../../../images/mediaplayer2_state_diagram.png"
- *         alt="MediaPlayer2 State diagram"
- *         border="0" /></div></p>
- * <p>The MediaPlayer2 object has five states:</p>
- * <ol>
- *     <li><p>{@link #PLAYER_STATE_IDLE}: MediaPlayer2 is in the <strong>Idle</strong>
- *         state after it's created, or after calling {@link #reset()}.</p>
- *
- *         <p>While in this state, you should call
- *         {@link #setDataSource setDataSource}. It is a good
- *         programming practice to register an {@link EventCallback#onCallCompleted onCallCompleted}
- *         <a href="#Callbacks">callback</a> and watch for {@link #CALL_STATUS_BAD_VALUE} and
- *         {@link #CALL_STATUS_ERROR_IO}, which might be caused by <code>setDataSource</code>.
- *         </p>
- *
- *         <p>Calling {@link #prepare()} transfers a MediaPlayer2 object to
- *         the <strong>Prepared</strong> state. Note
- *         that {@link #prepare()} is asynchronous. When the preparation completes,
- *         if you register an {@link EventCallback#onInfo onInfo} <a href="#Callbacks">callback</a>,
- *         the player executes the callback
- *         with {@link #MEDIA_INFO_PREPARED} and transitions to the
- *         <strong>Prepared</strong> state.</p>
- *         </li>
- *
- *     <li>{@link #PLAYER_STATE_PREPARED}: A MediaPlayer object must be in the
- *         <strong>Prepared</strong> state before playback can be started for the first time.
- *         While in this state, you can set player properties
- *         such as audio/sound volume and looping by invoking the corresponding set methods.
- *         Calling {@link #play()} transfers a MediaPlayer2 object to
- *         the <strong>Playing</strong> state.
- *      </li>
- *
- *     <li>{@link #PLAYER_STATE_PLAYING}:
- *         <p>The player plays the data source while in this state.
- *         If you register an {@link EventCallback#onInfo onInfo} <a href="#Callbacks">callback</a>,
- *         the player regularly executes the callback with
- *         {@link #MEDIA_INFO_BUFFERING_UPDATE}.
- *         This allows applications to keep track of the buffering status
- *         while streaming audio/video.</p>
- *
- *         <p> When the playback reaches the end of stream, the behavior depends on whether or
- *         not you've enabled looping by calling {@link #loopCurrent}:</p>
- *         <ul>
- *         <li>If the looping mode was set to <code>false</code>, the player will transfer
- *         to the <strong>Paused</strong> state. If you registered an {@link EventCallback#onInfo
- *         onInfo} <a href="#Callbacks">callback</a>
- *         the player calls the callback with {@link #MEDIA_INFO_DATA_SOURCE_END} and enters
- *         the <strong>Paused</strong> state.
- *         </li>
- *         <li>If the looping mode was set to <code>true</code>,
- *         the MediaPlayer2 object remains in the <strong>Playing</strong> state and replays its
- *         data source from the beginning.</li>
- *         </ul>
- *         </li>
- *
- *     <li>{@link #PLAYER_STATE_PAUSED}: Audio/video playback pauses while in this state.
- *         Call {@link #play()} to resume playback from the position where it paused.</li>
- *
- *     <li>{@link #PLAYER_STATE_ERROR}: <p>In general, playback might fail due to various
- *          reasons such as unsupported audio/video format, poorly interleaved
- *          audio/video, resolution too high, streaming timeout, and others.
- *          In addition, due to programming errors, a playback
- *          control operation might be performed from an <a href="#InvalidStates">invalid state</a>.
- *          In these cases the player transitions to the <strong>Error</strong> state.</p>
- *
- *          <p>If you register an {@link EventCallback#onError onError}}
- *          <a href="#Callbacks">callback</a>,
- *          the callback will be performed when entering the state. When programming errors happen,
- *          such as calling {@link #prepare()} and
- *          {@link #setDataSource} methods
- *          from an <a href="#InvalidStates">invalid state</a>, the callback is called with
- *          {@link #CALL_STATUS_INVALID_OPERATION}. The MediaPlayer2 object enters the
- *          <strong>Error</strong> state whether or not a callback exists. </p>
- *
- *          <p>To recover from an error and reuse a MediaPlayer2 object that is in the <strong>
- *          Error</strong> state,
- *          call {@link #reset()}. The object will return to the <strong>Idle</strong>
- *          state and all state information will be lost.</p>
- *          </li>
- * </ol>
- *
- * <p>You should follow these best practices when coding an app that uses MediaPlayer2:</p>
- *
- * <ul>
- *
- * <li>Use <a href="#Callbacks">callbacks</a> to respond to state changes and errors.</li>
- *
- * <li>When  a MediaPlayer2 object is no longer being used, call {@link #close()} as soon as
- * possible to release the resources used by the internal player engine associated with the
- * MediaPlayer2. Failure to call {@link #close()} may cause subsequent instances of
- * MediaPlayer2 objects to fallback to software implementations or fail altogether.
- * You cannot use MediaPlayer2
- * after you call {@link #close()}. There is no way to bring it back to any other state.</li>
- *
- * <li>The current playback position can be retrieved with a call to
- * {@link #getCurrentPosition()},
- * which is helpful for applications such as a Music player that need to keep track of the playback
- * progress.</li>
- *
- * <li>The playback position can be adjusted with a call to {@link #seekTo}. Although the
- * asynchronous {@link #seekTo} call returns right away, the actual seek operation may take a
- * while to finish, especially for audio/video being streamed. If you register an
- * {@link EventCallback#onCallCompleted onCallCompleted} <a href="#Callbacks">callback</a>,
- * the callback is
- * called When the seek operation completes with {@link #CALL_COMPLETED_SEEK_TO}.</li>
- *
- * <li>You can call {@link #seekTo} from the <strong>Paused</strong> state.
- * In this case, if you are playing a video stream and
- * the requested position is valid  one video frame is displayed.</li>
- *
- * </ul>
- *
- * <h3 id="InvalidStates">Invalid method calls</h3>
- *
- * <p>The only methods you safely call from the <strong>Error</strong> state are
- * {@link #close},
- * {@link #reset},
- * {@link #notifyWhenCommandLabelReached},
- * {@link #clearPendingCommands},
- * {@link #registerEventCallback},
- * {@link #unregisterEventCallback}
- * and {@link #getState}.
- * Any other methods might throw an exception, return meaningless data, or invoke a
- * {@link EventCallback#onCallCompleted onCallCompleted} with an error code.</p>
- *
- * <p>Most methods can be called from any non-Error state. They will either perform their work or
- * silently have no effect. The following table lists the methods that will invoke a
- * {@link EventCallback#onCallCompleted onCallCompleted} with an error code
- * or throw an exception when they are called from the associated invalid states.</p>
- *
- * <table border="0" cellspacing="0" cellpadding="0">
- * <tr><th>Method Name</th>
- * <th>Invalid States</th></tr>
- *
- * <tr><td>setDataSource</td> <td>{Prepared, Paused, Playing}</td></tr>
- * <tr><td>prepare</td> <td>{Prepared, Paused, Playing}</td></tr>
- * <tr><td>play</td> <td>{Idle}</td></tr>
- * <tr><td>pause</td> <td>{Idle}</td></tr>
- * <tr><td>seekTo</td> <td>{Idle}</td></tr>
- * <tr><td>getCurrentPosition</td> <td>{Idle}</td></tr>
- * <tr><td>getDuration</td> <td>{Idle}</td></tr>
- * <tr><td>getBufferedPosition</td> <td>{Idle}</td></tr>
- * <tr><td>getTrackInfo</td> <td>{Idle}</td></tr>
- * <tr><td>getSelectedTrack</td> <td>{Idle}</td></tr>
- * <tr><td>selectTrack</td> <td>{Idle}</td></tr>
- * <tr><td>deselectTrack</td> <td>{Idle}</td></tr>
- * </table>
- *
- * <h3 id="Permissions">Permissions</h3>
- * <p>This class requires the {@link android.Manifest.permission#INTERNET} permission
- * when used with network-based content.
- *
- * <h3 id="Callbacks">Callbacks</h3>
- * <p>Many errors do not result in a transition to the  <strong>Error</strong> state.
- * It is good programming practice to register callback listeners using
- * {@link #registerEventCallback}.
- * You can receive a callback at any time and from any state.</p>
- *
- * <p>If it's important for your app to respond to state changes (for instance, to update the
- * controls on a transport UI), you should register an
- * {@link EventCallback#onCallCompleted onCallCompleted} and
- * detect state change commands by testing the <code>what</code> parameter for a callback from one
- * of the state transition methods: {@link #CALL_COMPLETED_PREPARE}, {@link #CALL_COMPLETED_PLAY},
- * and {@link #CALL_COMPLETED_PAUSE}.
- * Then check the <code>status</code> parameter. The value {@link #CALL_STATUS_NO_ERROR} indicates a
- * successful transition. Any other value will be an error. Call {@link #getState()} to
- * determine the current state. </p>
- */
-public class MediaPlayer2 implements AutoCloseable
-                                            , AudioRouting {
-    static {
-        System.loadLibrary("media2_jni");
-        native_init();
-    }
-
-    private static native void native_init();
-
-    private static final int NEXT_SOURCE_STATE_ERROR = -1;
-    private static final int NEXT_SOURCE_STATE_INIT = 0;
-    private static final int NEXT_SOURCE_STATE_PREPARING = 1;
-    private static final int NEXT_SOURCE_STATE_PREPARED = 2;
-
-    private static final String TAG = "MediaPlayer2";
-
-    private Context mContext;
-
-    private long mNativeContext;  // accessed by native methods
-    private long mNativeSurfaceTexture;  // accessed by native methods
-    private int mListenerContext;  // accessed by native methods
-    private SurfaceHolder mSurfaceHolder;
-    private PowerManager.WakeLock mWakeLock = null;
-    private boolean mScreenOnWhilePlaying;
-    private boolean mStayAwake;
-
-    private final Object mSrcLock = new Object();
-    //--- guarded by |mSrcLock| start
-    private SourceInfo mCurrentSourceInfo;
-    private final Queue<SourceInfo> mNextSourceInfos = new ConcurrentLinkedQueue<>();
-    //--- guarded by |mSrcLock| end
-    private final AtomicLong mSrcIdGenerator = new AtomicLong(0);
-
-    private volatile float mVolume = 1.0f;
-    private VideoSize mVideoSize = new VideoSize(0, 0);
-
-    private ExecutorService mDrmThreadPool = Executors.newCachedThreadPool();
-
-    // Creating a dummy audio track, used for keeping session id alive
-    private final Object mSessionIdLock = new Object();
-    @GuardedBy("mSessionIdLock")
-    private AudioTrack mDummyAudioTrack;
-
-    private HandlerThread mHandlerThread;
-    private final TaskHandler mTaskHandler;
-    private final Object mTaskLock = new Object();
-    @GuardedBy("mTaskLock")
-    private final List<Task> mPendingTasks = new LinkedList<>();
-    @GuardedBy("mTaskLock")
-    private Task mCurrentTask;
-    private final AtomicLong mTaskIdGenerator = new AtomicLong(0);
-
-    @GuardedBy("mTaskLock")
-    boolean mIsPreviousCommandSeekTo = false;
-    // |mPreviousSeekPos| and |mPreviousSeekMode| are valid only when |mIsPreviousCommandSeekTo|
-    // is true, and they are accessed on |mHandlerThread| only.
-    long mPreviousSeekPos = -1;
-    int mPreviousSeekMode = SEEK_PREVIOUS_SYNC;
-
-    @GuardedBy("this")
-    private boolean mReleased;
-
-    private final CloseGuard mGuard = CloseGuard.get();
-
-    /**
-     * Default constructor.
-     * <p>When done with the MediaPlayer2, you should call {@link #close()},
-     * to free the resources. If not released, too many MediaPlayer2 instances may
-     * result in an exception.</p>
-     */
-    public MediaPlayer2(Context context) {
-        mGuard.open("close");
-
-        mContext = context;
-        mHandlerThread = new HandlerThread("MediaPlayer2TaskThread");
-        mHandlerThread.start();
-        Looper looper = mHandlerThread.getLooper();
-        mTaskHandler = new TaskHandler(this, looper);
-        AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        int sessionId = am.generateAudioSessionId();
-        keepAudioSessionIdAlive(sessionId);
-
-        /* Native setup requires a weak reference to our object.
-         * It's easier to create it here than in C++.
-         */
-        native_setup(sessionId, new WeakReference<MediaPlayer2>(this));
-    }
-
-    private native void native_setup(int sessionId, Object mediaplayer2This);
-
-    /**
-     * Releases the resources held by this {@code MediaPlayer2} object.
-     *
-     * It is considered good practice to call this method when you're
-     * done using the MediaPlayer2. In particular, whenever an Activity
-     * of an application is paused (its onPause() method is called),
-     * or stopped (its onStop() method is called), this method should be
-     * invoked to release the MediaPlayer2 object, unless the application
-     * has a special need to keep the object around. In addition to
-     * unnecessary resources (such as memory and instances of codecs)
-     * being held, failure to call this method immediately if a
-     * MediaPlayer2 object is no longer needed may also lead to
-     * continuous battery consumption for mobile devices, and playback
-     * failure for other applications if no multiple instances of the
-     * same codec are supported on a device. Even if multiple instances
-     * of the same codec are supported, some performance degradation
-     * may be expected when unnecessary multiple instances are used
-     * at the same time.
-     *
-     * {@code close()} may be safely called after a prior {@code close()}.
-     * This class implements the Java {@code AutoCloseable} interface and
-     * may be used with try-with-resources.
-     */
-    // This is a synchronous call.
-    @Override
-    public void close() {
-        synchronized (mGuard) {
-            mGuard.close();
-        }
-        release();
-    }
-
-    private synchronized void release() {
-        if (mReleased) {
-            return;
-        }
-        stayAwake(false);
-        updateSurfaceScreenOn();
-        synchronized (mEventCbLock) {
-            mEventCallbackRecords.clear();
-        }
-        if (mHandlerThread != null) {
-            mHandlerThread.quitSafely();
-            mHandlerThread = null;
-        }
-
-        clearSourceInfos();
-
-        // Modular DRM clean up
-        mOnDrmConfigHelper = null;
-        synchronized (mDrmEventCbLock) {
-            mDrmEventCallbackRecords.clear();
-        }
-
-        native_release();
-
-        synchronized (mSessionIdLock) {
-            mDummyAudioTrack.release();
-        }
-
-        mReleased = true;
-    }
-
-    private native void native_release();
-
-    // Have to declare protected for finalize() since it is protected
-    // in the base class Object.
-    @Override
-    protected void finalize() throws Throwable {
-        if (mGuard != null) {
-            mGuard.warnIfOpen();
-        }
-
-        close();
-        native_finalize();
-    }
-
-    private native void native_finalize();
-
-    /**
-     * 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().
-     */
-    // This is a synchronous call.
-    public void reset() {
-        clearSourceInfos();
-
-        stayAwake(false);
-        native_reset();
-
-        AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        int sessionId = am.generateAudioSessionId();
-        keepAudioSessionIdAlive(sessionId);
-
-        // make sure none of the listeners get called anymore
-        if (mTaskHandler != null) {
-            mTaskHandler.removeCallbacksAndMessages(null);
-        }
-
-    }
-
-    private native void native_reset();
-
-    /**
-     * Starts or resumes playback. If playback had previously been paused,
-     * playback will continue from where it was paused. If playback had
-     * reached end of stream and been paused, or never started before,
-     * playback will start at the beginning.
-     *
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object play() {
-        return addTask(new Task(CALL_COMPLETED_PLAY, false) {
-            @Override
-            void process() {
-                stayAwake(true);
-                native_start();
-            }
-        });
-    }
-
-    private native void native_start() throws IllegalStateException;
-
-    /**
-     * Prepares the player for playback, asynchronously.
-     *
-     * After setting the datasource and the display surface, you need to call prepare().
-     *
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object prepare() {
-        return addTask(new Task(CALL_COMPLETED_PREPARE, true) {
-            @Override
-            void process() {
-                native_prepare();
-            }
-        });
-    }
-
-    private native void native_prepare();
-
-    /**
-     * Pauses playback. Call play() to resume.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object pause() {
-        return addTask(new Task(CALL_COMPLETED_PAUSE, false) {
-            @Override
-            void process() {
-                stayAwake(false);
-
-                native_pause();
-            }
-        });
-    }
-
-    private native void native_pause() throws IllegalStateException;
-
-    /**
-     * Tries to play next data source if applicable.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object skipToNext() {
-        return addTask(new Task(CALL_COMPLETED_SKIP_TO_NEXT, false) {
-            @Override
-            void process() {
-                if (getState() == PLAYER_STATE_PLAYING) {
-                    pause();
-                }
-                playNextDataSource();
-            }
-        });
-    }
-
-    /**
-     * Gets the current playback position.
-     *
-     * @return the current position in milliseconds
-     */
-    public native long getCurrentPosition();
-
-    /**
-     * Gets the duration of the dsd.
-     *
-     * @param dsd the descriptor of data source of which you want to get duration
-     * @return the duration in milliseconds, if no duration is available
-     *         (for example, if streaming live content), -1 is returned.
-     * @throws NullPointerException if dsd is null
-     */
-    public long getDuration(@NonNull DataSourceDesc dsd) {
-        if (dsd == null) {
-            throw new NullPointerException("non-null dsd is expected");
-        }
-        SourceInfo sourceInfo = getSourceInfo(dsd);
-        if (sourceInfo == null) {
-            return -1;
-        }
-
-        return native_getDuration(sourceInfo.mId);
-    }
-
-    private native long native_getDuration(long srcId);
-
-    /**
-     * Gets the buffered media source position of given dsd.
-     * For example a buffering update of 8000 milliseconds when 5000 milliseconds of the content
-     * has already been played indicates that the next 3000 milliseconds of the
-     * content to play has been buffered.
-     *
-     * @param dsd the descriptor of data source of which you want to get buffered position
-     * @return the current buffered media source position in milliseconds
-     * @throws NullPointerException if dsd is null
-     */
-    public long getBufferedPosition(@NonNull DataSourceDesc dsd) {
-        if (dsd == null) {
-            throw new NullPointerException("non-null dsd is expected");
-        }
-        SourceInfo sourceInfo = getSourceInfo(dsd);
-        if (sourceInfo == null) {
-            return 0;
-        }
-
-        // Use cached buffered percent for now.
-        int bufferedPercentage = sourceInfo.mBufferedPercentage.get();
-
-        long duration = getDuration(dsd);
-        if (duration < 0) {
-            duration = 0;
-        }
-
-        return duration * bufferedPercentage / 100;
-    }
-
-    /**
-     * MediaPlayer2 has not been prepared or just has been reset.
-     * In this state, MediaPlayer2 doesn't fetch data.
-     */
-    public static final int PLAYER_STATE_IDLE = 1001;
-
-    /**
-     * MediaPlayer2 has been just prepared.
-     * In this state, MediaPlayer2 just fetches data from media source,
-     * but doesn't actively render data.
-     */
-    public static final int PLAYER_STATE_PREPARED = 1002;
-
-    /**
-     * MediaPlayer2 is paused.
-     * In this state, MediaPlayer2 has allocated resources to construct playback
-     * pipeline, but it doesn't actively render data.
-     */
-    public static final int PLAYER_STATE_PAUSED = 1003;
-
-    /**
-     * MediaPlayer2 is actively playing back data.
-     */
-    public static final int PLAYER_STATE_PLAYING = 1004;
-
-    /**
-     * MediaPlayer2 has hit some fatal error and cannot continue playback.
-     */
-    public static final int PLAYER_STATE_ERROR = 1005;
-
-    /**
-     * @hide
-     */
-    @IntDef(flag = false, prefix = "MEDIAPLAYER2_STATE", value = {
-        PLAYER_STATE_IDLE,
-        PLAYER_STATE_PREPARED,
-        PLAYER_STATE_PAUSED,
-        PLAYER_STATE_PLAYING,
-        PLAYER_STATE_ERROR })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface MediaPlayer2State {}
-
-    /**
-     * Gets the current player state.
-     *
-     * @return the current player state.
-     */
-    public @MediaPlayer2State int getState() {
-        return native_getState();
-    }
-
-    private native int native_getState();
-
-    /**
-     * Sets the audio attributes for this MediaPlayer2.
-     * See {@link AudioAttributes} for how to build and configure an instance of this class.
-     * You must call this method before {@link #play()} and {@link #pause()} in order
-     * for the audio attributes to become effective thereafter.
-     * @param attributes a non-null set of audio attributes
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object setAudioAttributes(@NonNull AudioAttributes attributes) {
-        return addTask(new Task(CALL_COMPLETED_SET_AUDIO_ATTRIBUTES, false) {
-            @Override
-            void process() {
-                if (attributes == null) {
-                    final String msg = "Cannot set AudioAttributes to null";
-                    throw new IllegalArgumentException(msg);
-                }
-                native_setAudioAttributes(attributes);
-            }
-        });
-    }
-
-    // return true if the parameter is set successfully, false otherwise
-    private native boolean native_setAudioAttributes(AudioAttributes audioAttributes);
-
-    /**
-     * Gets the audio attributes for this MediaPlayer2.
-     * @return attributes a set of audio attributes
-     */
-    public @NonNull AudioAttributes getAudioAttributes() {
-        return native_getAudioAttributes();
-    }
-
-    private native AudioAttributes native_getAudioAttributes();
-
-    /**
-     * Sets the data source as described by a DataSourceDesc.
-     * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor}
-     * in the {@link FileDataSourceDesc} will be closed by the player.
-     *
-     * @param dsd the descriptor of data source you want to play
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object setDataSource(@NonNull DataSourceDesc dsd) {
-        return addTask(new Task(CALL_COMPLETED_SET_DATA_SOURCE, false) {
-            @Override
-            void process() throws IOException {
-                checkDataSourceDesc(dsd);
-                int state = getState();
-                try {
-                    if (state != PLAYER_STATE_ERROR && state != PLAYER_STATE_IDLE) {
-                        throw new IllegalStateException("called in wrong state " + state);
-                    }
-
-                    synchronized (mSrcLock) {
-                        setCurrentSourceInfo_l(new SourceInfo(dsd));
-                        handleDataSource(true /* isCurrent */, dsd, mCurrentSourceInfo.mId);
-                    }
-                } finally {
-                    dsd.close();
-                }
-            }
-
-        });
-    }
-
-    /**
-     * Sets a single data source as described by a DataSourceDesc which will be played
-     * after current data source is finished.
-     * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor}
-     * in the {@link FileDataSourceDesc} will be closed by the player.
-     *
-     * @param dsd the descriptor of data source you want to play after current one
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object setNextDataSource(@NonNull DataSourceDesc dsd) {
-        return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCE, false) {
-            @Override
-            void process() {
-                checkDataSourceDesc(dsd);
-                synchronized (mSrcLock) {
-                    clearNextSourceInfos_l();
-                    mNextSourceInfos.add(new SourceInfo(dsd));
-                }
-                prepareNextDataSource();
-            }
-        });
-    }
-
-    /**
-     * Sets a list of data sources to be played sequentially after current data source is done.
-     * When the data source is of {@link FileDataSourceDesc} type, the {@link ParcelFileDescriptor}
-     * in the {@link FileDataSourceDesc} will be closed by the player.
-     *
-     * @param dsds the list of data sources you want to play after current one
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object setNextDataSources(@NonNull List<DataSourceDesc> dsds) {
-        return addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCES, false) {
-            @Override
-            void process() {
-                if (dsds == null || dsds.size() == 0) {
-                    throw new IllegalArgumentException("data source list cannot be null or empty.");
-                }
-                boolean hasError = false;
-                for (DataSourceDesc dsd : dsds) {
-                    if (dsd != null) {
-                        hasError = true;
-                        continue;
-                    }
-                    if (dsd instanceof FileDataSourceDesc) {
-                        FileDataSourceDesc fdsd = (FileDataSourceDesc) dsd;
-                        if (fdsd.isPFDClosed()) {
-                            hasError = true;
-                            continue;
-                        }
-
-                        fdsd.incCount();
-                    }
-                }
-                if (hasError) {
-                    for (DataSourceDesc dsd : dsds) {
-                        if (dsd != null) {
-                            dsd.close();
-                        }
-                    }
-                    throw new IllegalArgumentException("invalid data source list");
-                }
-
-                synchronized (mSrcLock) {
-                    clearNextSourceInfos_l();
-                    for (DataSourceDesc dsd : dsds) {
-                        mNextSourceInfos.add(new SourceInfo(dsd));
-                    }
-                }
-                prepareNextDataSource();
-            }
-        });
-    }
-
-    // throws IllegalArgumentException if dsd is null or underline PFD of dsd has been closed.
-    private void checkDataSourceDesc(DataSourceDesc dsd) {
-        if (dsd == null) {
-            throw new IllegalArgumentException("dsd is expected to be non null");
-        }
-        if (dsd instanceof FileDataSourceDesc) {
-            FileDataSourceDesc fdsd = (FileDataSourceDesc) dsd;
-            if (fdsd.isPFDClosed()) {
-                throw new IllegalArgumentException("the underline FileDescriptor has been closed");
-            }
-            fdsd.incCount();
-        }
-    }
-
-    /**
-     * Removes all data sources pending to be played.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object clearNextDataSources() {
-        return addTask(new Task(CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES, false) {
-            @Override
-            void process() {
-                synchronized (mSrcLock) {
-                    clearNextSourceInfos_l();
-                }
-            }
-        });
-    }
-
-    /**
-     * Gets the current data source as described by a DataSourceDesc.
-     *
-     * @return the current DataSourceDesc
-     */
-    public @Nullable DataSourceDesc getCurrentDataSource() {
-        synchronized (mSrcLock) {
-            return mCurrentSourceInfo == null ? null : mCurrentSourceInfo.mDSD;
-        }
-    }
-
-    private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd, long srcId)
-            throws IOException {
-        Media2Utils.checkArgument(dsd != null, "the DataSourceDesc cannot be null");
-
-        if (dsd instanceof CallbackDataSourceDesc) {
-            CallbackDataSourceDesc cbDSD = (CallbackDataSourceDesc) dsd;
-            handleDataSource(isCurrent,
-                             srcId,
-                             cbDSD.getDataSourceCallback(),
-                             cbDSD.getStartPosition(),
-                             cbDSD.getEndPosition());
-        } else if (dsd instanceof FileDataSourceDesc) {
-            FileDataSourceDesc fileDSD = (FileDataSourceDesc) dsd;
-            handleDataSource(isCurrent,
-                             srcId,
-                             fileDSD.getParcelFileDescriptor(),
-                             fileDSD.getOffset(),
-                             fileDSD.getLength(),
-                             fileDSD.getStartPosition(),
-                             fileDSD.getEndPosition());
-        } else if (dsd instanceof UriDataSourceDesc) {
-            UriDataSourceDesc uriDSD = (UriDataSourceDesc) dsd;
-            handleDataSource(isCurrent,
-                             srcId,
-                             uriDSD.getContext(),
-                             uriDSD.getUri(),
-                             uriDSD.getHeaders(),
-                             uriDSD.getCookies(),
-                             uriDSD.getStartPosition(),
-                             uriDSD.getEndPosition());
-        } else {
-            throw new IllegalArgumentException("Unsupported DataSourceDesc. " + dsd.toString());
-        }
-    }
-
-    /**
-     * To provide cookies for the subsequent HTTP requests, you can install your own default cookie
-     * handler and use other variants of setDataSource APIs instead. Alternatively, you can use
-     * this API to pass the cookies as a list of HttpCookie. If the app has not installed
-     * a CookieHandler already, this API creates a CookieManager and populates its CookieStore with
-     * the provided cookies. If the app has installed its own handler already, this API requires the
-     * handler to be of CookieManager type such that the API can update the manager’s CookieStore.
-     *
-     * <p><strong>Note</strong> that the cross domain redirection is allowed by default,
-     * but that can be changed with key/value pairs through the headers parameter with
-     * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to
-     * disallow or allow cross domain redirection.
-     *
-     * @throws IllegalArgumentException if cookies are provided and the installed handler is not
-     *                                  a CookieManager
-     * @throws IllegalStateException    if it is called in an invalid state
-     * @throws NullPointerException     if context or uri is null
-     * @throws IOException              if uri has a file scheme and an I/O error occurs
-     */
-    private void handleDataSource(
-            boolean isCurrent, long srcId,
-            @NonNull Context context, @NonNull Uri uri,
-            @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies,
-            long startPos, long endPos)
-            throws IOException {
-        // The context and URI usually belong to the calling user. Get a resolver for that user.
-        final ContentResolver resolver = context.getContentResolver();
-        final String scheme = uri.getScheme();
-        if (ContentResolver.SCHEME_FILE.equals(scheme)) {
-            handleDataSource(isCurrent, srcId, uri.getPath(), null, null, startPos, endPos);
-            return;
-        }
-
-        final int ringToneType = RingtoneManager.getDefaultType(uri);
-        try {
-            AssetFileDescriptor afd;
-            // Try requested Uri locally first
-            if (ContentResolver.SCHEME_CONTENT.equals(scheme) && ringToneType != -1) {
-                afd = RingtoneManager.openDefaultRingtoneUri(context, uri);
-                if (attemptDataSource(isCurrent, srcId, afd, startPos, endPos)) {
-                    return;
-                }
-                final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(
-                        context, ringToneType);
-                afd = resolver.openAssetFileDescriptor(actualUri, "r");
-            } else {
-                afd = resolver.openAssetFileDescriptor(uri, "r");
-            }
-            if (attemptDataSource(isCurrent, srcId, afd, startPos, endPos)) {
-                return;
-            }
-        } catch (NullPointerException | SecurityException | IOException ex) {
-            Log.w(TAG, "Couldn't open " + uri + ": " + ex);
-            // Fallback to media server
-        }
-        handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies, startPos, endPos);
-    }
-
-    private boolean attemptDataSource(boolean isCurrent, long srcId, AssetFileDescriptor afd,
-            long startPos, long endPos) throws IOException {
-        try {
-            if (afd.getDeclaredLength() < 0) {
-                handleDataSource(isCurrent,
-                        srcId,
-                        ParcelFileDescriptor.dup(afd.getFileDescriptor()),
-                        0,
-                        DataSourceDesc.LONG_MAX,
-                        startPos,
-                        endPos);
-            } else {
-                handleDataSource(isCurrent,
-                        srcId,
-                        ParcelFileDescriptor.dup(afd.getFileDescriptor()),
-                        afd.getStartOffset(),
-                        afd.getDeclaredLength(),
-                        startPos,
-                        endPos);
-            }
-            return true;
-        } catch (NullPointerException | SecurityException | IOException ex) {
-            Log.w(TAG, "Couldn't open srcId:" + srcId + ": " + ex);
-            return false;
-        } finally {
-            if (afd != null) {
-                afd.close();
-            }
-        }
-    }
-
-    private void handleDataSource(
-            boolean isCurrent, long srcId,
-            String path, Map<String, String> headers, List<HttpCookie> cookies,
-            long startPos, long endPos)
-            throws IOException {
-        String[] keys = null;
-        String[] values = null;
-
-        if (headers != null) {
-            keys = new String[headers.size()];
-            values = new String[headers.size()];
-
-            int i = 0;
-            for (Map.Entry<String, String> entry: headers.entrySet()) {
-                keys[i] = entry.getKey();
-                values[i] = entry.getValue();
-                ++i;
-            }
-        }
-        handleDataSource(isCurrent, srcId, path, keys, values, cookies, startPos, endPos);
-    }
-
-    private void handleDataSource(boolean isCurrent, long srcId,
-            String path, String[] keys, String[] values, List<HttpCookie> cookies,
-            long startPos, long endPos)
-            throws IOException {
-        final Uri uri = Uri.parse(path);
-        final String scheme = uri.getScheme();
-        if ("file".equals(scheme)) {
-            path = uri.getPath();
-        } else if (scheme != null) {
-            // handle non-file sources
-            Media2Utils.storeCookies(cookies);
-            nativeHandleDataSourceUrl(
-                    isCurrent,
-                    srcId,
-                    Media2HTTPService.createHTTPService(path),
-                    path,
-                    keys,
-                    values,
-                    startPos,
-                    endPos);
-            return;
-        }
-
-        final File file = new File(path);
-        if (file.exists()) {
-            FileInputStream is = new FileInputStream(file);
-            FileDescriptor fd = is.getFD();
-            handleDataSource(isCurrent, srcId, ParcelFileDescriptor.dup(fd),
-                    0, DataSourceDesc.LONG_MAX, startPos, endPos);
-            is.close();
-        } else {
-            throw new IOException("handleDataSource failed.");
-        }
-    }
-
-    private native void nativeHandleDataSourceUrl(
-            boolean isCurrent, long srcId,
-            Media2HTTPService httpService, String path, String[] keys, String[] values,
-            long startPos, long endPos)
-            throws IOException;
-
-    /**
-     * Sets the data source (FileDescriptor) to use. The FileDescriptor must be
-     * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
-     * to close the file descriptor. It is safe to do so as soon as this call returns.
-     *
-     * @throws IllegalStateException if it is called in an invalid state
-     * @throws IllegalArgumentException if fd is not a valid FileDescriptor
-     * @throws IOException if fd can not be read
-     */
-    private void handleDataSource(
-            boolean isCurrent, long srcId,
-            ParcelFileDescriptor pfd, long offset, long length,
-            long startPos, long endPos) throws IOException {
-        nativeHandleDataSourceFD(isCurrent, srcId, pfd.getFileDescriptor(), offset, length,
-                startPos, endPos);
-    }
-
-    private native void nativeHandleDataSourceFD(boolean isCurrent, long srcId,
-            FileDescriptor fd, long offset, long length,
-            long startPos, long endPos) throws IOException;
-
-    /**
-     * @throws IllegalStateException if it is called in an invalid state
-     * @throws IllegalArgumentException if dataSource is not a valid DataSourceCallback
-     */
-    private void handleDataSource(boolean isCurrent, long srcId, DataSourceCallback dataSource,
-            long startPos, long endPos) {
-        nativeHandleDataSourceCallback(isCurrent, srcId, dataSource, startPos, endPos);
-    }
-
-    private native void nativeHandleDataSourceCallback(
-            boolean isCurrent, long srcId, DataSourceCallback dataSource,
-            long startPos, long endPos);
-
-    // return true if there is a next data source, false otherwise.
-    // This function should be always called on |mHandlerThread|.
-    private boolean prepareNextDataSource() {
-        HandlerThread handlerThread = mHandlerThread;
-        if (handlerThread != null && Looper.myLooper() != handlerThread.getLooper()) {
-            Log.e(TAG, "prepareNextDataSource: called on wrong looper");
-        }
-
-        boolean hasNextDSD;
-        int state = getState();
-        synchronized (mSrcLock) {
-            hasNextDSD = !mNextSourceInfos.isEmpty();
-            if (state == PLAYER_STATE_ERROR || state == PLAYER_STATE_IDLE) {
-                // Current source has not been prepared yet.
-                return hasNextDSD;
-            }
-
-            SourceInfo nextSource = mNextSourceInfos.peek();
-            if (!hasNextDSD || nextSource.mStateAsNextSource != NEXT_SOURCE_STATE_INIT) {
-                // There is no next source or it's in preparing or prepared state.
-                return hasNextDSD;
-            }
-
-            try {
-                nextSource.mStateAsNextSource = NEXT_SOURCE_STATE_PREPARING;
-                handleDataSource(false /* isCurrent */, nextSource.mDSD, nextSource.mId);
-            } catch (Exception e) {
-                Message msg = mTaskHandler.obtainMessage(
-                        MEDIA_ERROR, MEDIA_ERROR_IO, MEDIA_ERROR_UNKNOWN, null);
-                mTaskHandler.handleMessage(msg, nextSource.mId);
-
-                SourceInfo nextSourceInfo = mNextSourceInfos.poll();
-                if (nextSource != null) {
-                    nextSourceInfo.close();
-                }
-                return prepareNextDataSource();
-            }
-        }
-        return hasNextDSD;
-    }
-
-    // This function should be always called on |mHandlerThread|.
-    private void playNextDataSource() {
-        HandlerThread handlerThread = mHandlerThread;
-        if (handlerThread != null && Looper.myLooper() != handlerThread.getLooper()) {
-            Log.e(TAG, "playNextDataSource: called on wrong looper");
-        }
-
-        boolean hasNextDSD = false;
-        synchronized (mSrcLock) {
-            if (!mNextSourceInfos.isEmpty()) {
-                hasNextDSD = true;
-                SourceInfo nextSourceInfo = mNextSourceInfos.peek();
-                if (nextSourceInfo.mStateAsNextSource == NEXT_SOURCE_STATE_PREPARED) {
-                    // Switch to next source only when it has been prepared.
-                    setCurrentSourceInfo_l(mNextSourceInfos.poll());
-
-                    long srcId = mCurrentSourceInfo.mId;
-                    try {
-                        nativePlayNextDataSource(srcId);
-                    } catch (Exception e) {
-                        Message msg2 = mTaskHandler.obtainMessage(
-                                MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
-                        mTaskHandler.handleMessage(msg2, srcId);
-                        // Keep |mNextSourcePlayPending|
-                        hasNextDSD = prepareNextDataSource();
-                    }
-                    if (hasNextDSD) {
-                        stayAwake(true);
-
-                        // Now a new current src is playing.
-                        // Wait for MEDIA_INFO_DATA_SOURCE_START to prepare next source.
-                    }
-                } else if (nextSourceInfo.mStateAsNextSource == NEXT_SOURCE_STATE_INIT) {
-                    hasNextDSD = prepareNextDataSource();
-                }
-            }
-        }
-
-        if (!hasNextDSD) {
-            sendEvent(new EventNotifier() {
-                @Override
-                public void notify(EventCallback callback) {
-                    callback.onInfo(
-                            MediaPlayer2.this, null, MEDIA_INFO_DATA_SOURCE_LIST_END, 0);
-                }
-            });
-        }
-    }
-
-    private native void nativePlayNextDataSource(long srcId);
-
-    /**
-     * Configures the player to loop on the current data source.
-     * @param loop true if the current data source is meant to loop.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object loopCurrent(boolean loop) {
-        return addTask(new Task(CALL_COMPLETED_LOOP_CURRENT, false) {
-            @Override
-            void process() {
-                setLooping(loop);
-            }
-        });
-    }
-
-    private native void setLooping(boolean looping);
-
-    /**
-     * Sets the volume of the audio of the media to play, expressed as a linear multiplier
-     * on the audio samples.
-     * Note that this volume is specific to the player, and is separate from stream volume
-     * used across the platform.<br>
-     * A value of 0.0f indicates muting, a value of 1.0f is the nominal unattenuated and unamplified
-     * gain. See {@link #getMaxPlayerVolume()} for the volume range supported by this player.
-     * @param volume a value between 0.0f and {@link #getMaxPlayerVolume()}.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object setPlayerVolume(float volume) {
-        return addTask(new Task(CALL_COMPLETED_SET_PLAYER_VOLUME, false) {
-            @Override
-            void process() {
-                mVolume = volume;
-                native_setVolume(volume);
-            }
-        });
-    }
-
-    private native void native_setVolume(float volume);
-
-    /**
-     * Returns the current volume of this player.
-     * Note that it does not take into account the associated stream volume.
-     * @return the player volume.
-     */
-    public float getPlayerVolume() {
-        return mVolume;
-    }
-
-    /**
-     * @return the maximum volume that can be used in {@link #setPlayerVolume(float)}.
-     */
-    public float getMaxPlayerVolume() {
-        return 1.0f;
-    }
-
-    /**
-     * Insert a task in the command queue to help the client to identify whether a batch
-     * of commands has been finished. When this command is processed, a notification
-     * {@link EventCallback#onCommandLabelReached onCommandLabelReached} will be fired with the
-     * given {@code label}.
-     *
-     * @see EventCallback#onCommandLabelReached
-     *
-     * @param label An application specific Object used to help to identify the completeness
-     * of a batch of commands.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object notifyWhenCommandLabelReached(@NonNull Object label) {
-        return addTask(new Task(CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED, false) {
-            @Override
-            void process() {
-                sendEvent(new EventNotifier() {
-                    @Override
-                    public void notify(EventCallback callback) {
-                        callback.onCommandLabelReached(
-                                MediaPlayer2.this, label);
-                    }
-                });
-            }
-        });
-    }
-
-    /**
-     * Sets the {@link SurfaceHolder} to use for displaying the video
-     * portion of the media.
-     *
-     * Either a surface holder or surface must be set if a display or video sink
-     * is needed. Not calling this method or {@link #setSurface(Surface)}
-     * when playing back a video will result in only the audio track being played.
-     * A null surface holder or surface will result in only the audio track being
-     * played.
-     *
-     * @param sh the SurfaceHolder to use for video display
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    public Object setDisplay(SurfaceHolder sh) {
-        return addTask(new Task(CALL_COMPLETED_SET_DISPLAY, false) {
-            @Override
-            void process() {
-                mSurfaceHolder = sh;
-                Surface surface;
-                if (sh != null) {
-                    surface = sh.getSurface();
-                } else {
-                    surface = null;
-                }
-                native_setVideoSurface(surface);
-                updateSurfaceScreenOn();
-            }
-        });
-    }
-
-    /**
-     * Sets the {@link Surface} to be used as the sink for the video portion of
-     * the media.  Setting a
-     * Surface will un-set any Surface or SurfaceHolder that was previously set.
-     * A null surface will result in only the audio track being played.
-     *
-     * If the Surface sends frames to a {@link SurfaceTexture}, the timestamps
-     * returned from {@link SurfaceTexture#getTimestamp()} will have an
-     * unspecified zero point.  These timestamps cannot be directly compared
-     * between different media sources, different instances of the same media
-     * source, or multiple runs of the same program.  The timestamp is normally
-     * monotonically increasing and is unaffected by time-of-day adjustments,
-     * but it is reset when the position is set.
-     *
-     * @param surface The {@link Surface} to be used for the video portion of
-     * the media.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object setSurface(Surface surface) {
-        return addTask(new Task(CALL_COMPLETED_SET_SURFACE, false) {
-            @Override
-            void process() {
-                if (mScreenOnWhilePlaying && surface != null) {
-                    Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface");
-                }
-                mSurfaceHolder = null;
-                native_setVideoSurface(surface);
-                updateSurfaceScreenOn();
-            }
-        });
-    }
-
-    private native void native_setVideoSurface(Surface surface);
-
-    /**
-     * Set the low-level power management behavior for this MediaPlayer2. This
-     * can be used when the MediaPlayer2 is not playing through a SurfaceHolder
-     * set with {@link #setDisplay(SurfaceHolder)} and thus can use the
-     * high-level {@link #setScreenOnWhilePlaying(boolean)} feature.
-     *
-     * <p>This function has the MediaPlayer2 access the low-level power manager
-     * service to control the device's power usage while playing is occurring.
-     * The parameter is a {@link android.os.PowerManager.WakeLock}.
-     * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
-     * permission.
-     * By default, no attempt is made to keep the device awake during playback.
-     *
-     * @param wakeLock the power wake lock used during playback.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     * @see android.os.PowerManager
-     */
-    // This is an asynchronous call.
-    public Object setWakeLock(@NonNull PowerManager.WakeLock wakeLock) {
-        return addTask(new Task(CALL_COMPLETED_SET_WAKE_LOCK, false) {
-            @Override
-            void process() {
-                boolean washeld = false;
-
-                if (mWakeLock != null) {
-                    if (mWakeLock.isHeld()) {
-                        washeld = true;
-                        mWakeLock.release();
-                    }
-                }
-
-                mWakeLock = wakeLock;
-                if (mWakeLock != null) {
-                    mWakeLock.setReferenceCounted(false);
-                    if (washeld) {
-                        mWakeLock.acquire();
-                    }
-                }
-            }
-        });
-    }
-
-    /**
-     * Control whether we should use the attached SurfaceHolder to keep the
-     * screen on while video playback is occurring.  This is the preferred
-     * method over {@link #setWakeLock} where possible, since it doesn't
-     * require that the application have permission for low-level wake lock
-     * access.
-     *
-     * @param screenOn Supply true to keep the screen on, false to allow it to turn off.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object setScreenOnWhilePlaying(boolean screenOn) {
-        return addTask(new Task(CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING, false) {
-            @Override
-            void process() {
-                if (mScreenOnWhilePlaying != screenOn) {
-                    if (screenOn && mSurfaceHolder == null) {
-                        Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective"
-                                + " without a SurfaceHolder");
-                    }
-                    mScreenOnWhilePlaying = screenOn;
-                    updateSurfaceScreenOn();
-                }
-            }
-        });
-    }
-
-    private void stayAwake(boolean awake) {
-        if (mWakeLock != null) {
-            if (awake && !mWakeLock.isHeld()) {
-                mWakeLock.acquire();
-            } else if (!awake && mWakeLock.isHeld()) {
-                mWakeLock.release();
-            }
-        }
-        mStayAwake = awake;
-        updateSurfaceScreenOn();
-    }
-
-    private void updateSurfaceScreenOn() {
-        if (mSurfaceHolder != null) {
-            mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake);
-        }
-    }
-
-    /**
-     * Cancels a pending command.
-     *
-     * @param token the command to be canceled. This is the returned Object when command is issued.
-     * @return {@code false} if the task could not be cancelled; {@code true} otherwise.
-     * @throws IllegalArgumentException if argument token is null.
-     */
-    // This is a synchronous call.
-    public boolean cancelCommand(@NonNull Object token) {
-        if (token == null) {
-            throw new IllegalArgumentException("command token should not be null");
-        }
-        synchronized (mTaskLock) {
-            return mPendingTasks.remove(token);
-        }
-    }
-
-    /**
-     * Discards all pending commands.
-     */
-    // This is a synchronous call.
-    public void clearPendingCommands() {
-        synchronized (mTaskLock) {
-            mPendingTasks.clear();
-        }
-    }
-
-    //--------------------------------------------------------------------------
-    // Explicit Routing
-    //--------------------
-    private AudioDeviceInfo mPreferredDevice = null;
-
-    /**
-     * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
-     * the output from this MediaPlayer2.
-     * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio sink or source.
-     *  If deviceInfo is null, default routing is restored.
-     * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
-     * does not correspond to a valid audio device.
-     */
-    // This is a synchronous call.
-    @Override
-    public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
-        boolean status = native_setPreferredDevice(deviceInfo);
-        if (status) {
-            synchronized (this) {
-                mPreferredDevice = deviceInfo;
-            }
-        }
-        return status;
-    }
-
-    private native boolean native_setPreferredDevice(AudioDeviceInfo device);
-
-    /**
-     * Returns the selected output specified by {@link #setPreferredDevice}. Note that this
-     * is not guaranteed to correspond to the actual device being used for playback.
-     */
-    @Override
-    public AudioDeviceInfo getPreferredDevice() {
-        synchronized (this) {
-            return mPreferredDevice;
-        }
-    }
-
-    /**
-     * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer2
-     * Note: The query is only valid if the MediaPlayer2 is currently playing.
-     * If the player is not playing, the returned device can be null or correspond to previously
-     * selected device when the player was last active.
-     */
-    @Override
-    public native AudioDeviceInfo getRoutedDevice();
-
-    /**
-     * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
-     * changes on this MediaPlayer2.
-     * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
-     * notifications of rerouting events.
-     * @param handler  Specifies the {@link Handler} object for the thread on which to execute
-     * the callback. If <code>null</code>, the handler on the main looper will be used.
-     */
-    // This is a synchronous call.
-    @Override
-    public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
-            Handler handler) {
-        if (listener == null) {
-            throw new IllegalArgumentException("addOnRoutingChangedListener: listener is NULL");
-        }
-        RoutingDelegate routingDelegate = new RoutingDelegate(this, listener, handler);
-        native_addDeviceCallback(routingDelegate);
-    }
-
-    private native void native_addDeviceCallback(RoutingDelegate rd);
-
-    /**
-     * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
-     * to receive rerouting notifications.
-     * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
-     * to remove.
-     */
-    // This is a synchronous call.
-    @Override
-    public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("removeOnRoutingChangedListener: listener is NULL");
-        }
-        native_removeDeviceCallback(listener);
-    }
-
-    private native void native_removeDeviceCallback(
-            AudioRouting.OnRoutingChangedListener listener);
-
-    /**
-     * Returns the size of the video.
-     *
-     * @return the size of the video. The width and height of size could be 0 if there is no video,
-     * no display surface was set, or the size has not been determined yet.
-     * The {@code EventCallback} can be registered via
-     * {@link #registerEventCallback(Executor, EventCallback)} to provide a
-     * notification {@code EventCallback.onVideoSizeChanged} when the size
-     * is available.
-     */
-    public VideoSize getVideoSize() {
-        return mVideoSize;
-    }
-
-    /**
-     * Return Metrics data about the current player.
-     *
-     * @return a {@link PersistableBundle} containing the set of attributes and values
-     * available for the media being handled by this instance of MediaPlayer2
-     * The attributes are descibed in {@link MetricsConstants}.
-     *
-     * Additional vendor-specific fields may also be present in the return value.
-     */
-    public PersistableBundle getMetrics() {
-        PersistableBundle bundle = native_getMetrics();
-        return bundle;
-    }
-
-    private native PersistableBundle native_getMetrics();
-
-    /**
-     * Gets the current buffering management params used by the source component.
-     * Calling it only after {@code setDataSource} has been called.
-     * Each type of data source might have different set of default params.
-     *
-     * @return the current buffering management params used by the source component.
-     * @throws IllegalStateException if the internal player engine has not been
-     * initialized, or {@code setDataSource} has not been called.
-     */
-    // TODO: make it public when ready
-    @NonNull
-    native BufferingParams getBufferingParams();
-
-    /**
-     * Sets buffering management params.
-     * The object sets its internal BufferingParams to the input, except that the input is
-     * invalid or not supported.
-     * Call it only after {@code setDataSource} has been called.
-     * The input is a hint to MediaPlayer2.
-     *
-     * @param params the buffering management params.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // TODO: make it public when ready
-    // This is an asynchronous call.
-    Object setBufferingParams(@NonNull BufferingParams params) {
-        return addTask(new Task(CALL_COMPLETED_SET_BUFFERING_PARAMS, false) {
-            @Override
-            void process() {
-                Media2Utils.checkArgument(params != null, "the BufferingParams cannot be null");
-                native_setBufferingParams(params);
-            }
-        });
-    }
-
-    private native void native_setBufferingParams(@NonNull BufferingParams params);
-
-    /**
-     * Sets playback rate using {@link PlaybackParams}. The object sets its internal
-     * 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.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object setPlaybackParams(@NonNull PlaybackParams params) {
-        return addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_PARAMS, false) {
-            @Override
-            void process() {
-                Media2Utils.checkArgument(params != null, "the PlaybackParams cannot be null");
-                native_setPlaybackParams(params);
-            }
-        });
-    }
-
-    private native void native_setPlaybackParams(@NonNull PlaybackParams params);
-
-    /**
-     * Gets the playback params, containing the current playback rate.
-     *
-     * @return the playback params.
-     * @throws IllegalStateException if the internal player engine has not been initialized.
-     */
-    @NonNull
-    public native PlaybackParams getPlaybackParams();
-
-    /**
-     * Sets A/V sync mode.
-     *
-     * @param params the A/V sync params to apply
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object setSyncParams(@NonNull SyncParams params) {
-        return addTask(new Task(CALL_COMPLETED_SET_SYNC_PARAMS, false) {
-            @Override
-            void process() {
-                Media2Utils.checkArgument(params != null, "the SyncParams cannot be null");
-                native_setSyncParams(params);
-            }
-        });
-    }
-
-    private native void native_setSyncParams(@NonNull SyncParams params);
-
-    /**
-     * Gets the A/V sync mode.
-     *
-     * @return the A/V sync params
-     * @throws IllegalStateException if the internal player engine has not been initialized.
-     */
-    @NonNull
-    public native SyncParams getSyncParams();
-
-    /**
-     * Moves the media to specified time position.
-     * Same as {@link #seekTo(long, int)} with {@code mode = SEEK_PREVIOUS_SYNC}.
-     *
-     * @param msec the offset in milliseconds from the start to seek to
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object seekTo(long msec) {
-        return seekTo(msec, SEEK_PREVIOUS_SYNC /* mode */);
-    }
-
-    /**
-     * Seek modes used in method seekTo(long, int) to move media position
-     * to a specified location.
-     *
-     * Do not change these mode values without updating their counterparts
-     * in include/media/IMediaSource.h!
-     */
-    /**
-     * This mode is used with {@link #seekTo(long, int)} to move media position to
-     * a sync (or key) frame associated with a data source that is located
-     * right before or at the given time.
-     *
-     * @see #seekTo(long, int)
-     */
-    public static final int SEEK_PREVIOUS_SYNC    = 0x00;
-    /**
-     * This mode is used with {@link #seekTo(long, int)} to move media position to
-     * a sync (or key) frame associated with a data source that is located
-     * right after or at the given time.
-     *
-     * @see #seekTo(long, int)
-     */
-    public static final int SEEK_NEXT_SYNC        = 0x01;
-    /**
-     * This mode is used with {@link #seekTo(long, int)} to move media position to
-     * a sync (or key) frame associated with a data source that is located
-     * closest to (in time) or at the given time.
-     *
-     * @see #seekTo(long, int)
-     */
-    public static final int SEEK_CLOSEST_SYNC     = 0x02;
-    /**
-     * This mode is used with {@link #seekTo(long, int)} to move media position to
-     * a frame (not necessarily a key frame) associated with a data source that
-     * is located closest to or at the given time.
-     *
-     * @see #seekTo(long, int)
-     */
-    public static final int SEEK_CLOSEST          = 0x03;
-
-    /** @hide */
-    @IntDef(flag = false, prefix = "SEEK", value = {
-            SEEK_PREVIOUS_SYNC,
-            SEEK_NEXT_SYNC,
-            SEEK_CLOSEST_SYNC,
-            SEEK_CLOSEST,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface SeekMode {}
-
-    /**
-     * Moves the media to specified time position by considering the given mode.
-     * <p>
-     * When seekTo is finished, the user will be notified via
-     * {@link EventCallback#onCallCompleted} with {@link #CALL_COMPLETED_SEEK_TO}.
-     * There is at most one active seekTo processed at any time. If there is a to-be-completed
-     * seekTo, new seekTo requests will be queued in such a way that only the last request
-     * is kept. When current seekTo is completed, the queued request will be processed if
-     * that request is different from just-finished seekTo operation, i.e., the requested
-     * position or mode is different.
-     *
-     * @param msec the offset in milliseconds from the start to seek to.
-     * When seeking to the given time position, there is no guarantee that the data source
-     * has a frame located at the position. When this happens, a frame nearby will be rendered.
-     * If msec is negative, time position zero will be used.
-     * If msec is larger than duration, duration will be used.
-     * @param mode the mode indicating where exactly to seek to.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object seekTo(long msec, @SeekMode int mode) {
-        return addTask(new Task(CALL_COMPLETED_SEEK_TO, true) {
-            @Override
-            void process() {
-                if (mode < SEEK_PREVIOUS_SYNC || mode > SEEK_CLOSEST) {
-                    final String msg = "Illegal seek mode: " + mode;
-                    throw new IllegalArgumentException(msg);
-                }
-                // TODO: pass long to native, instead of truncating here.
-                long posMs = msec;
-                if (posMs > Integer.MAX_VALUE) {
-                    Log.w(TAG, "seekTo offset " + posMs + " is too large, cap to "
-                            + Integer.MAX_VALUE);
-                    posMs = Integer.MAX_VALUE;
-                } else if (posMs < Integer.MIN_VALUE) {
-                    Log.w(TAG, "seekTo offset " + posMs + " is too small, cap to "
-                            + Integer.MIN_VALUE);
-                    posMs = Integer.MIN_VALUE;
-                }
-
-                synchronized (mTaskLock) {
-                    if (mIsPreviousCommandSeekTo
-                            && mPreviousSeekPos == posMs
-                            && mPreviousSeekMode == mode) {
-                        throw new CommandSkippedException(
-                                "same as previous seekTo");
-                    }
-                }
-
-                native_seekTo(posMs, mode);
-
-                synchronized (mTaskLock) {
-                    mIsPreviousCommandSeekTo = true;
-                    mPreviousSeekPos = posMs;
-                    mPreviousSeekMode = mode;
-                }
-            }
-        });
-    }
-
-    private native void native_seekTo(long msec, int mode);
-
-    /**
-     * Get current playback position as a {@link MediaTimestamp}.
-     * <p>
-     * The MediaTimestamp represents how the media time correlates to the system time in
-     * a linear fashion using an anchor and a clock rate. During regular playback, the media
-     * time moves fairly constantly (though the anchor frame may be rebased to a current
-     * system time, the linear correlation stays steady). Therefore, this method does not
-     * need to be called often.
-     * <p>
-     * To help users get current playback position, this method always anchors the timestamp
-     * to the current {@link System#nanoTime system time}, so
-     * {@link MediaTimestamp#getAnchorMediaTimeUs} can be used as current playback position.
-     *
-     * @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp
-     *         is available, e.g. because the media player has not been initialized.
-     *
-     * @see MediaTimestamp
-     */
-    @Nullable
-    public MediaTimestamp getTimestamp() {
-        try {
-            // TODO: get the timestamp from native side
-            return new MediaTimestamp.Builder()
-                    .setMediaTimestamp(
-                        getCurrentPosition() * 1000L,
-                        System.nanoTime(),
-                        getState() == PLAYER_STATE_PLAYING ? getPlaybackParams().getSpeed() : 0.f)
-                    .build();
-        } catch (IllegalStateException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Checks whether the MediaPlayer2 is looping or non-looping.
-     *
-     * @return true if the MediaPlayer2 is currently looping, false otherwise
-     */
-    // This is a synchronous call.
-    public native boolean isLooping();
-
-    /**
-     * Sets the audio session ID.
-     *
-     * @param sessionId the audio session ID.
-     * The audio session ID is a system wide unique identifier for the audio stream played by
-     * this MediaPlayer2 instance.
-     * The primary use of the audio session ID  is to associate audio effects to a particular
-     * instance of MediaPlayer2: if an audio session ID is provided when creating an audio effect,
-     * this effect will be applied only to the audio content of media players within the same
-     * audio session and not to the output mix.
-     * When created, a MediaPlayer2 instance automatically generates its own audio session ID.
-     * However, it is possible to force this player to be part of an already existing audio session
-     * by calling this method.
-     * This method must be called when player is in {@link #PLAYER_STATE_IDLE} or
-     * {@link #PLAYER_STATE_PREPARED} state in order to have sessionId take effect.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object setAudioSessionId(int sessionId) {
-        final AudioTrack dummyAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
-                    AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, 2,
-                    AudioTrack.MODE_STATIC, sessionId);
-        return addTask(new Task(CALL_COMPLETED_SET_AUDIO_SESSION_ID, false) {
-            @Override
-            void process() {
-                keepAudioSessionIdAlive(dummyAudioTrack);
-                native_setAudioSessionId(sessionId);
-            }
-        });
-    }
-
-    private native void native_setAudioSessionId(int sessionId);
-
-    /**
-     * Returns the audio session ID.
-     *
-     * @return the audio session ID. {@see #setAudioSessionId(int)}
-     * Note that the audio session ID is 0 only if a problem occured when the MediaPlayer2 was
-     * contructed.
-     */
-    // This is a synchronous call.
-    public native int getAudioSessionId();
-
-    /**
-     * Attaches an auxiliary effect to the player. A typical auxiliary effect is a reverberation
-     * effect which can be applied on any sound source that directs a certain amount of its
-     * energy to this effect. This amount is defined by setAuxEffectSendLevel().
-     * See {@link #setAuxEffectSendLevel(float)}.
-     * <p>After creating an auxiliary effect (e.g.
-     * {@link android.media.audiofx.EnvironmentalReverb}), retrieve its ID with
-     * {@link android.media.audiofx.AudioEffect#getId()} and use it when calling this method
-     * to attach the player to the effect.
-     * <p>To detach the effect from the player, call this method with a null effect id.
-     * <p>This method must be called after one of the overloaded <code> setDataSource </code>
-     * methods.
-     * @param effectId system wide unique id of the effect to attach
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object attachAuxEffect(int effectId) {
-        return addTask(new Task(CALL_COMPLETED_ATTACH_AUX_EFFECT, false) {
-            @Override
-            void process() {
-                native_attachAuxEffect(effectId);
-            }
-        });
-    }
-
-    private native void native_attachAuxEffect(int effectId);
-
-    /**
-     * Sets the send level of the player to the attached auxiliary effect.
-     * See {@link #attachAuxEffect(int)}. The level value range is 0 to 1.0.
-     * <p>By default the send level is 0, so even if an effect is attached to the player
-     * this method must be called for the effect to be applied.
-     * <p>Note that the passed level value is a raw scalar. UI controls should be scaled
-     * logarithmically: the gain applied by audio framework ranges from -72dB to 0dB,
-     * so an appropriate conversion from linear UI input x to level is:
-     * x == 0 -> level = 0
-     * 0 < x <= R -> level = 10^(72*(x-R)/20/R)
-     * @param level send level scalar
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     */
-    // This is an asynchronous call.
-    public Object setAuxEffectSendLevel(float level) {
-        return addTask(new Task(CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL, false) {
-            @Override
-            void process() {
-                native_setAuxEffectSendLevel(level);
-            }
-        });
-    }
-
-    private native void native_setAuxEffectSendLevel(float level);
-
-    private static native void native_stream_event_onTearDown(
-            long nativeCallbackPtr, long userDataPtr);
-    private static native void native_stream_event_onStreamPresentationEnd(
-            long nativeCallbackPtr, long userDataPtr);
-    private static native void native_stream_event_onStreamDataRequest(
-            long jAudioTrackPtr, long nativeCallbackPtr, long userDataPtr);
-
-    /* Do not change these values (starting with INVOKE_ID) without updating
-     * their counterparts in include/media/mediaplayer2.h!
-     */
-    private static final int INVOKE_ID_GET_TRACK_INFO = 1;
-    private static final int INVOKE_ID_ADD_EXTERNAL_SOURCE = 2;
-    private static final int INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3;
-    private static final int INVOKE_ID_SELECT_TRACK = 4;
-    private static final int INVOKE_ID_DESELECT_TRACK = 5;
-    private static final int INVOKE_ID_GET_SELECTED_TRACK = 7;
-
-    /**
-     * 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 msg PlayerMessage for the extension.
-     *
-     * @return PlayerMessage with the data returned by the
-     * native player.
-     */
-    private PlayerMessage invoke(PlayerMessage msg) {
-        byte[] ret = native_invoke(msg.toByteArray());
-        if (ret == null) {
-            return null;
-        }
-        try {
-            return PlayerMessage.parseFrom(ret);
-        } catch (InvalidProtocolBufferException e) {
-            return null;
-        }
-    }
-
-    private native byte[] native_invoke(byte[] request);
-
-    /**
-     * Class for MediaPlayer2 to return each audio/video/subtitle track's metadata.
-     *
-     * @see MediaPlayer2#getTrackInfo
-     */
-    public static class TrackInfo {
-        /**
-         * Gets the track type.
-         * @return TrackType which indicates if the track is video, audio, timed text.
-         */
-        public int getTrackType() {
-            return mTrackType;
-        }
-
-        /**
-         * Gets the language code of the track.
-         * @return a language code in either way of ISO-639-1 or ISO-639-2.
-         * When the language is unknown or could not be determined,
-         * ISO-639-2 language code, "und", is returned.
-         */
-        public String getLanguage() {
-            String language = mFormat.getString(MediaFormat.KEY_LANGUAGE);
-            return language == null ? "und" : language;
-        }
-
-        /**
-         * Gets the {@link MediaFormat} of the track.  If the format is
-         * unknown or could not be determined, null is returned.
-         */
-        public MediaFormat getFormat() {
-            if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT
-                    || mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
-                return mFormat;
-            }
-            return null;
-        }
-
-        public static final int MEDIA_TRACK_TYPE_UNKNOWN = 0;
-        public static final int MEDIA_TRACK_TYPE_VIDEO = 1;
-        public static final int MEDIA_TRACK_TYPE_AUDIO = 2;
-
-        /** @hide */
-        public static final int MEDIA_TRACK_TYPE_TIMEDTEXT = 3;
-
-        public static final int MEDIA_TRACK_TYPE_SUBTITLE = 4;
-        public static final int MEDIA_TRACK_TYPE_METADATA = 5;
-
-        final int mTrackType;
-        final MediaFormat mFormat;
-
-        static TrackInfo create(Iterator<Value> in) {
-            int trackType = in.next().getInt32Value();
-            // TODO: build the full MediaFormat; currently we are using createSubtitleFormat
-            // even for audio/video tracks, meaning we only set the mime and language.
-            String mime = in.next().getStringValue();
-            String language = in.next().getStringValue();
-            MediaFormat format = MediaFormat.createSubtitleFormat(mime, language);
-
-            if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
-                format.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.next().getInt32Value());
-                format.setInteger(MediaFormat.KEY_IS_DEFAULT, in.next().getInt32Value());
-                format.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.next().getInt32Value());
-            }
-            return new TrackInfo(trackType, format);
-        }
-
-        /** @hide */
-        TrackInfo(int type, MediaFormat format) {
-            mTrackType = type;
-            mFormat = format;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder out = new StringBuilder(128);
-            out.append(getClass().getName());
-            out.append('{');
-            switch (mTrackType) {
-                case MEDIA_TRACK_TYPE_VIDEO:
-                    out.append("VIDEO");
-                    break;
-                case MEDIA_TRACK_TYPE_AUDIO:
-                    out.append("AUDIO");
-                    break;
-                case MEDIA_TRACK_TYPE_TIMEDTEXT:
-                    out.append("TIMEDTEXT");
-                    break;
-                case MEDIA_TRACK_TYPE_SUBTITLE:
-                    out.append("SUBTITLE");
-                    break;
-                default:
-                    out.append("UNKNOWN");
-                    break;
-            }
-            out.append(", " + mFormat.toString());
-            out.append("}");
-            return out.toString();
-        }
-    };
-
-    /**
-     * Returns a List of track information.
-     *
-     * @param dsd the descriptor of data source of which you want to get track info
-     * @return List of track info. The total number of tracks is the array length.
-     * Must be called again if an external timed text source has been added after
-     * addTimedTextSource method is called.
-     * @throws IllegalStateException if it is called in an invalid state.
-     * @throws NullPointerException if dsd is null
-     */
-
-    public @NonNull List<TrackInfo> getTrackInfo(@NonNull DataSourceDesc dsd) {
-        if (dsd == null) {
-            throw new NullPointerException("non-null dsd is expected");
-        }
-        SourceInfo sourceInfo = getSourceInfo(dsd);
-        if (sourceInfo == null) {
-            return new ArrayList<TrackInfo>(0);
-        }
-
-        TrackInfo[] trackInfo = getInbandTrackInfo(sourceInfo);
-        return (trackInfo != null ? Arrays.asList(trackInfo) : new ArrayList<TrackInfo>(0));
-    }
-
-    private TrackInfo[] getInbandTrackInfo(SourceInfo sourceInfo) throws IllegalStateException {
-        PlayerMessage request = PlayerMessage.newBuilder()
-                .addValues(Value.newBuilder().setInt32Value(INVOKE_ID_GET_TRACK_INFO))
-                .addValues(Value.newBuilder().setInt64Value(sourceInfo.mId))
-                .build();
-        PlayerMessage response = invoke(request);
-        if (response == null) {
-            return null;
-        }
-        Iterator<Value> in = response.getValuesList().iterator();
-        int size = in.next().getInt32Value();
-        if (size == 0) {
-            return null;
-        }
-        TrackInfo[] trackInfo = new TrackInfo[size];
-        for (int i = 0; i < size; ++i) {
-            trackInfo[i] = TrackInfo.create(in);
-        }
-        return trackInfo;
-    }
-
-    /**
-     * Returns the index of the audio, video, or subtitle track currently selected for playback,
-     * The return value is an index into the array returned by {@link #getTrackInfo}, and can
-     * be used in calls to {@link #selectTrack} or {@link #deselectTrack}.
-     *
-     * @param dsd the descriptor of data source of which you want to get selected track
-     * @param trackType should be one of {@link TrackInfo#MEDIA_TRACK_TYPE_VIDEO},
-     * {@link TrackInfo#MEDIA_TRACK_TYPE_AUDIO}, or
-     * {@link TrackInfo#MEDIA_TRACK_TYPE_SUBTITLE}
-     * @return index of the audio, video, or subtitle track currently selected for playback;
-     * a negative integer is returned when there is no selected track for {@code trackType} or
-     * when {@code trackType} is not one of audio, video, or subtitle.
-     * @throws IllegalStateException if called after {@link #close()}
-     * @throws NullPointerException if dsd is null
-     *
-     * @see #getTrackInfo
-     * @see #selectTrack
-     * @see #deselectTrack
-     */
-    public int getSelectedTrack(@NonNull DataSourceDesc dsd, int trackType) {
-        if (dsd == null) {
-            throw new NullPointerException("non-null dsd is expected");
-        }
-        SourceInfo sourceInfo = getSourceInfo(dsd);
-        if (sourceInfo == null) {
-            return -1;
-        }
-
-        PlayerMessage request = PlayerMessage.newBuilder()
-                .addValues(Value.newBuilder().setInt32Value(INVOKE_ID_GET_SELECTED_TRACK))
-                .addValues(Value.newBuilder().setInt64Value(sourceInfo.mId))
-                .addValues(Value.newBuilder().setInt32Value(trackType))
-                .build();
-        PlayerMessage response = invoke(request);
-        if (response == null) {
-            return -1;
-        }
-        return response.getValues(0).getInt32Value();
-    }
-
-    /**
-     * Selects a track.
-     * <p>
-     * If a MediaPlayer2 is in invalid state, it throws an IllegalStateException exception.
-     * If a MediaPlayer2 is in <em>Started</em> state, the selected track is presented immediately.
-     * If a MediaPlayer2 is not in Started state, it just marks the track to be played.
-     * </p>
-     * <p>
-     * In any valid state, if it is called multiple times on the same type of track (ie. Video,
-     * Audio, Timed Text), the most recent one will be chosen.
-     * </p>
-     * <p>
-     * The first audio and video tracks are selected by default if available, even though
-     * this method is not called. However, no timed text track will be selected until
-     * this function is called.
-     * </p>
-     * <p>
-     * Currently, only timed text tracks or audio tracks can be selected via this method.
-     * In addition, the support for selecting an audio track at runtime is pretty limited
-     * in that an audio track can only be selected in the <em>Prepared</em> state.
-     * </p>
-     * @param dsd the descriptor of data source of which you want to select track
-     * @param index the index of the track to be selected. The valid range of the index
-     * is 0..total number of track - 1. The total number of tracks as well as the type of
-     * each individual track can be found by calling {@link #getTrackInfo} method.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     *
-     * @see MediaPlayer2#getTrackInfo
-     */
-    // This is an asynchronous call.
-    public Object selectTrack(@NonNull DataSourceDesc dsd, int index) {
-        return addTask(new Task(CALL_COMPLETED_SELECT_TRACK, false) {
-            @Override
-            void process() {
-                selectOrDeselectTrack(dsd, index, true /* select */);
-            }
-        });
-    }
-
-    /**
-     * Deselect a track.
-     * <p>
-     * Currently, the track must be a timed text track and no audio or video tracks can be
-     * deselected. If the timed text track identified by index has not been
-     * selected before, it throws an exception.
-     * </p>
-     * @param dsd the descriptor of data source of which you want to deselect track
-     * @param index the index of the track to be deselected. The valid range of the index
-     * is 0..total number of tracks - 1. The total number of tracks as well as the type of
-     * each individual track can be found by calling {@link #getTrackInfo} method.
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     *
-     * @see MediaPlayer2#getTrackInfo
-     */
-    // This is an asynchronous call.
-    public Object deselectTrack(@NonNull DataSourceDesc dsd, int index) {
-        return addTask(new Task(CALL_COMPLETED_DESELECT_TRACK, false) {
-            @Override
-            void process() {
-                selectOrDeselectTrack(dsd, index, false /* select */);
-            }
-        });
-    }
-
-    private void selectOrDeselectTrack(@NonNull DataSourceDesc dsd, int index, boolean select) {
-        if (dsd == null) {
-            throw new IllegalArgumentException("non-null dsd is expected");
-        }
-        SourceInfo sourceInfo = getSourceInfo(dsd);
-        if (sourceInfo == null) {
-            return;
-        }
-
-        PlayerMessage request = PlayerMessage.newBuilder()
-                .addValues(Value.newBuilder().setInt32Value(
-                            select ? INVOKE_ID_SELECT_TRACK : INVOKE_ID_DESELECT_TRACK))
-                .addValues(Value.newBuilder().setInt64Value(sourceInfo.mId))
-                .addValues(Value.newBuilder().setInt32Value(index))
-                .build();
-        invoke(request);
-    }
-
-    /* Do not change these values without updating their counterparts
-     * in include/media/mediaplayer2.h!
-     */
-    private static final int MEDIA_NOP = 0; // interface test message
-    private static final int MEDIA_PREPARED = 1;
-    private static final int MEDIA_PLAYBACK_COMPLETE = 2;
-    private static final int MEDIA_BUFFERING_UPDATE = 3;
-    private static final int MEDIA_SEEK_COMPLETE = 4;
-    private static final int MEDIA_SET_VIDEO_SIZE = 5;
-    private static final int MEDIA_STARTED = 6;
-    private static final int MEDIA_PAUSED = 7;
-    private static final int MEDIA_STOPPED = 8;
-    private static final int MEDIA_SKIPPED = 9;
-    private static final int MEDIA_NOTIFY_TIME = 98;
-    private static final int MEDIA_TIMED_TEXT = 99;
-    private static final int MEDIA_ERROR = 100;
-    private static final int MEDIA_INFO = 200;
-    private static final int MEDIA_SUBTITLE_DATA = 201;
-    private static final int MEDIA_META_DATA = 202;
-    private static final int MEDIA_DRM_INFO = 210;
-
-    private class TaskHandler extends Handler {
-        private MediaPlayer2 mMediaPlayer;
-
-        TaskHandler(MediaPlayer2 mp, Looper looper) {
-            super(looper);
-            mMediaPlayer = mp;
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            handleMessage(msg, 0);
-        }
-
-        public void handleMessage(Message msg, long srcId) {
-            if (mMediaPlayer.mNativeContext == 0) {
-                Log.w(TAG, "mediaplayer2 went away with unhandled events");
-                return;
-            }
-            final int what = msg.arg1;
-            final int extra = msg.arg2;
-
-            final SourceInfo sourceInfo = getSourceInfo(srcId);
-            if (sourceInfo == null) {
-                return;
-            }
-            final DataSourceDesc dsd = sourceInfo.mDSD;
-
-            switch(msg.what) {
-                case MEDIA_PREPARED:
-                {
-                    if (dsd != null) {
-                        sendEvent(new EventNotifier() {
-                            @Override
-                            public void notify(EventCallback callback) {
-                                callback.onInfo(
-                                        mMediaPlayer, dsd, MEDIA_INFO_PREPARED, 0);
-                            }
-                        });
-                    }
-
-                    synchronized (mSrcLock) {
-                        SourceInfo nextSourceInfo = mNextSourceInfos.peek();
-                        Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
-                                + ", curSrc=" + mCurrentSourceInfo
-                                + ", nextSrc=" + nextSourceInfo);
-
-                        if (isCurrentSource(srcId)) {
-                            prepareNextDataSource();
-                        } else if (isNextSource(srcId)) {
-                            nextSourceInfo.mStateAsNextSource = NEXT_SOURCE_STATE_PREPARED;
-                            if (nextSourceInfo.mPlayPendingAsNextSource) {
-                                playNextDataSource();
-                            }
-                        }
-                    }
-
-                    synchronized (mTaskLock) {
-                        if (mCurrentTask != null
-                                && mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE
-                                && mCurrentTask.mDSD == dsd
-                                && mCurrentTask.mNeedToWaitForEventToComplete) {
-                            mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
-                            mCurrentTask = null;
-                            processPendingTask_l();
-                        }
-                    }
-                    return;
-                }
-
-                case MEDIA_DRM_INFO:
-                {
-                    if (msg.obj == null) {
-                        Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
-                    } else if (msg.obj instanceof byte[]) {
-                        // The PlayerMessage was parsed already in postEventFromNative
-
-                        final DrmInfo drmInfo;
-                        synchronized (sourceInfo) {
-                            if (sourceInfo.mDrmInfo != null) {
-                                drmInfo = sourceInfo.mDrmInfo.makeCopy();
-                            } else {
-                                drmInfo = null;
-                            }
-                        }
-
-                        // notifying the client outside the lock
-                        if (drmInfo != null) {
-                            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);
-                    }
-                    return;
-                }
-
-                case MEDIA_PLAYBACK_COMPLETE:
-                {
-                    if (isCurrentSource(srcId)) {
-                        sendEvent(new EventNotifier() {
-                            @Override
-                            public void notify(EventCallback callback) {
-                                callback.onInfo(
-                                        mMediaPlayer, dsd, MEDIA_INFO_DATA_SOURCE_END, 0);
-                            }
-                        });
-                        stayAwake(false);
-
-                        synchronized (mSrcLock) {
-                            SourceInfo nextSourceInfo = mNextSourceInfos.peek();
-                            if (nextSourceInfo != null) {
-                                nextSourceInfo.mPlayPendingAsNextSource = true;
-                            }
-                            Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
-                                    + ", curSrc=" + mCurrentSourceInfo
-                                    + ", nextSrc=" + nextSourceInfo);
-                        }
-
-                        playNextDataSource();
-                    }
-
-                    return;
-                }
-
-                case MEDIA_STOPPED:
-                case MEDIA_STARTED:
-                case MEDIA_PAUSED:
-                case MEDIA_SKIPPED:
-                case MEDIA_NOTIFY_TIME:
-                {
-                    // Do nothing. The client should have enough information with
-                    // {@link EventCallback#onMediaTimeDiscontinuity}.
-                    break;
-                }
-
-                case MEDIA_BUFFERING_UPDATE:
-                {
-                    final int percent = msg.arg1;
-                    sendEvent(new EventNotifier() {
-                        @Override
-                        public void notify(EventCallback callback) {
-                            callback.onInfo(
-                                    mMediaPlayer, dsd, MEDIA_INFO_BUFFERING_UPDATE, percent);
-                        }
-                    });
-
-                    SourceInfo src = getSourceInfo(srcId);
-                    if (src != null) {
-                        src.mBufferedPercentage.set(percent);
-                    }
-
-                    return;
-                }
-
-                case MEDIA_SEEK_COMPLETE:
-                {
-                    synchronized (mTaskLock) {
-                        if (!mPendingTasks.isEmpty()
-                                && mPendingTasks.get(0).mMediaCallType != CALL_COMPLETED_SEEK_TO
-                                && getState() == PLAYER_STATE_PLAYING) {
-                            mIsPreviousCommandSeekTo = false;
-                        }
-
-                        if (mCurrentTask != null
-                                && mCurrentTask.mMediaCallType == CALL_COMPLETED_SEEK_TO
-                                && mCurrentTask.mNeedToWaitForEventToComplete) {
-                            mCurrentTask.sendCompleteNotification(CALL_STATUS_NO_ERROR);
-                            mCurrentTask = null;
-                            processPendingTask_l();
-                        }
-                    }
-                    return;
-                }
-
-                case MEDIA_SET_VIDEO_SIZE:
-                {
-                    final int width = msg.arg1;
-                    final int height = msg.arg2;
-
-                    mVideoSize = new VideoSize(width, height);
-                    sendEvent(new EventNotifier() {
-                        @Override
-                        public void notify(EventCallback callback) {
-                            callback.onVideoSizeChanged(
-                                    mMediaPlayer, dsd, mVideoSize);
-                        }
-                    });
-                    return;
-                }
-
-                case MEDIA_ERROR:
-                {
-                    Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
-                    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;
-                }
-
-                case MEDIA_INFO:
-                {
-                    switch (msg.arg1) {
-                        case MEDIA_INFO_VIDEO_TRACK_LAGGING:
-                            Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
-                            break;
-                    }
-
-                    sendEvent(new EventNotifier() {
-                        @Override
-                        public void notify(EventCallback callback) {
-                            callback.onInfo(
-                                    mMediaPlayer, dsd, what, extra);
-                        }
-                    });
-
-                    if (msg.arg1 == MEDIA_INFO_DATA_SOURCE_START) {
-                        if (isCurrentSource(srcId)) {
-                            prepareNextDataSource();
-                        }
-                    }
-
-                    // No real default action so far.
-                    return;
-                }
-
-                case MEDIA_TIMED_TEXT:
-                {
-                    final TimedText text;
-                    if (msg.obj instanceof byte[]) {
-                        PlayerMessage playerMsg;
-                        try {
-                            playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
-                        } catch (InvalidProtocolBufferException e) {
-                            Log.w(TAG, "Failed to parse timed text.", e);
-                            return;
-                        }
-                        text = TimedTextUtil.parsePlayerMessage(playerMsg);
-                    } else {
-                        text = null;
-                    }
-
-                    sendEvent(new EventNotifier() {
-                        @Override
-                        public void notify(EventCallback callback) {
-                            callback.onTimedText(
-                                    mMediaPlayer, dsd, text);
-                        }
-                    });
-                    return;
-                }
-
-                case MEDIA_SUBTITLE_DATA:
-                {
-                    if (msg.obj instanceof byte[]) {
-                        PlayerMessage playerMsg;
-                        try {
-                            playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
-                        } catch (InvalidProtocolBufferException e) {
-                            Log.w(TAG, "Failed to parse subtitle data.", e);
-                            return;
-                        }
-                        Iterator<Value> in = playerMsg.getValuesList().iterator();
-                        SubtitleData data = new SubtitleData.Builder()
-                                .setSubtitleData(
-                                    in.next().getInt32Value(),  // trackIndex
-                                    in.next().getInt64Value(),  // startTimeUs
-                                    in.next().getInt64Value(),  // durationUs
-                                    in.next().getBytesValue().toByteArray())  // data
-                                .build();
-                        sendEvent(new EventNotifier() {
-                            @Override
-                            public void notify(EventCallback callback) {
-                                callback.onSubtitleData(
-                                        mMediaPlayer, dsd, data);
-                            }
-                        });
-                    }
-                    return;
-                }
-
-                case MEDIA_META_DATA:
-                {
-                    final TimedMetaData data;
-                    if (msg.obj instanceof byte[]) {
-                        PlayerMessage playerMsg;
-                        try {
-                            playerMsg = PlayerMessage.parseFrom((byte[]) msg.obj);
-                        } catch (InvalidProtocolBufferException e) {
-                            Log.w(TAG, "Failed to parse timed meta data.", e);
-                            return;
-                        }
-                        Iterator<Value> in = playerMsg.getValuesList().iterator();
-                        data = new TimedMetaData.Builder()
-                                .setTimedMetaData(
-                                    in.next().getInt64Value(),  // timestampUs
-                                    in.next().getBytesValue().toByteArray())  // metaData
-                                .build();
-                    } else {
-                        data = null;
-                    }
-
-                    sendEvent(new EventNotifier() {
-                        @Override
-                        public void notify(EventCallback callback) {
-                            callback.onTimedMetaDataAvailable(
-                                    mMediaPlayer, dsd, data);
-                        }
-                    });
-                    return;
-                }
-
-                case MEDIA_NOP: // interface test message - ignore
-                {
-                    break;
-                }
-
-                default:
-                {
-                    Log.e(TAG, "Unknown message type " + msg.what);
-                    return;
-                }
-            }
-        }
-    }
-
-    /*
-     * Called from native code when an interesting event happens.  This method
-     * just uses the TaskHandler system to post the event back to the main app thread.
-     * We use a weak reference to the original MediaPlayer2 object so that the native
-     * code is safe from the object disappearing from underneath it.  (This is
-     * the cookie passed to native_setup().)
-     */
-    private static void postEventFromNative(Object mediaplayer2Ref, long srcId,
-                                            int what, int arg1, int arg2, byte[] obj) {
-        final MediaPlayer2 mp = (MediaPlayer2) ((WeakReference) mediaplayer2Ref).get();
-        if (mp == null) {
-            return;
-        }
-
-        final SourceInfo sourceInfo = mp.getSourceInfo(srcId);
-        switch (what) {
-            case MEDIA_DRM_INFO:
-                // We need to derive mDrmInfo before prepare() returns so processing it here
-                // before the notification is sent to TaskHandler below. TaskHandler runs in the
-                // notification looper so its handleMessage might process the event after prepare()
-                // has returned.
-                Log.v(TAG, "postEventFromNative MEDIA_DRM_INFO");
-                if (obj != null && sourceInfo != null) {
-                    PlayerMessage playerMsg;
-                    try {
-                        playerMsg = PlayerMessage.parseFrom(obj);
-                    } catch (InvalidProtocolBufferException e) {
-                        Log.w(TAG, "MEDIA_DRM_INFO failed to parse msg.obj " + obj);
-                        break;
-                    }
-                    DrmInfo drmInfo = DrmInfo.create(playerMsg);
-                    synchronized (sourceInfo) {
-                        sourceInfo.mDrmInfo = drmInfo;
-                    }
-                } else {
-                    Log.w(TAG, "MEDIA_DRM_INFO sourceInfo " + sourceInfo
-                            + " msg.obj of unexpected type " + obj);
-                }
-                break;
-
-            case MEDIA_PREPARED:
-                // By this time, we've learned about DrmInfo's presence or absence. This is meant
-                // mainly for prepare() use case. For prepare(), this still can run to a race
-                // condition b/c MediaPlayerNative releases the prepare() lock before calling notify
-                // so we also set mDrmInfoResolved in prepare().
-                if (sourceInfo != null) {
-                    synchronized (sourceInfo) {
-                        sourceInfo.mDrmInfoResolved = true;
-                    }
-                }
-                break;
-        }
-
-        if (mp.mTaskHandler != null) {
-            Message m = mp.mTaskHandler.obtainMessage(what, arg1, arg2, obj);
-
-            mp.mTaskHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mp.mTaskHandler.handleMessage(m, srcId);
-                }
-            });
-        }
-    }
-
-    /**
-     * Interface definition for callbacks to be invoked when the player has the corresponding
-     * events.
-     */
-    public static class EventCallback {
-        /**
-         * Called to indicate the video size
-         *
-         * The video size (width and height) could be 0 if there was no video,
-         * no display surface was set, or the value was not determined yet.
-         *
-         * @param mp the MediaPlayer2 associated with this callback
-         * @param dsd the DataSourceDesc of this data source
-         * @param size the size of the video
-         */
-        public void onVideoSizeChanged(
-                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd, @NonNull VideoSize size) { }
-
-        /**
-         * Called to indicate an avaliable timed text
-         *
-         * @param mp the MediaPlayer2 associated with this callback
-         * @param dsd the DataSourceDesc of this data source
-         * @param text the timed text sample which contains the text
-         *             needed to be displayed and the display format.
-         * @hide
-         */
-        public void onTimedText(
-                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd, @NonNull TimedText text) { }
-
-        /**
-         * Called to indicate avaliable timed metadata
-         * <p>
-         * This method will be called as timed metadata is extracted from the media,
-         * in the same order as it occurs in the media. The timing of this event is
-         * not controlled by the associated timestamp.
-         * <p>
-         * Currently only HTTP live streaming data URI's embedded with timed ID3 tags generates
-         * {@link TimedMetaData}.
-         *
-         * @see MediaPlayer2#selectTrack
-         * @see MediaPlayer2.OnTimedMetaDataAvailableListener
-         * @see TimedMetaData
-         *
-         * @param mp the MediaPlayer2 associated with this callback
-         * @param dsd the DataSourceDesc of this data source
-         * @param data the timed metadata sample associated with this event
-         */
-        public void onTimedMetaDataAvailable(
-                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
-                @NonNull TimedMetaData data) { }
-
-        /**
-         * Called to indicate an error.
-         *
-         * @param mp the MediaPlayer2 the error pertains to
-         * @param dsd the DataSourceDesc of this data source
-         * @param what the type of error that has occurred.
-         * @param extra an extra code, specific to the error. Typically
-         * implementation dependent.
-         */
-        public void onError(
-                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
-                @MediaError int what, int extra) { }
-
-        /**
-         * Called to indicate an info or a warning.
-         *
-         * @param mp the MediaPlayer2 the info pertains to.
-         * @param dsd the DataSourceDesc of this data source
-         * @param what the type of info or warning.
-         * @param extra an extra code, specific to the info. Typically
-         * implementation dependent.
-         */
-        public void onInfo(
-                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
-                @MediaInfo int what, int extra) { }
-
-        /**
-         * Called to acknowledge an API call.
-         *
-         * @param mp the MediaPlayer2 the call was made on.
-         * @param dsd the DataSourceDesc of this data source
-         * @param what the enum for the API call.
-         * @param status the returned status code for the call.
-         */
-        public void onCallCompleted(
-                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd, @CallCompleted int what,
-                @CallStatus int status) { }
-
-        /**
-         * Called to indicate media clock has changed.
-         *
-         * @param mp the MediaPlayer2 the media time pertains to.
-         * @param dsd the DataSourceDesc of this data source
-         * @param timestamp the new media clock.
-         */
-        public void onMediaTimeDiscontinuity(
-                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
-                @NonNull MediaTimestamp timestamp) { }
-
-        /**
-         * Called to indicate {@link #notifyWhenCommandLabelReached(Object)} has been processed.
-         *
-         * @param mp the MediaPlayer2 {@link #notifyWhenCommandLabelReached(Object)} was called on.
-         * @param label the application specific Object given by
-         *        {@link #notifyWhenCommandLabelReached(Object)}.
-         */
-        public void onCommandLabelReached(@NonNull MediaPlayer2 mp, @NonNull Object label) { }
-
-        /**
-         * Called when when a player subtitle track has new subtitle data available.
-         * @param mp the player that reports the new subtitle data
-         * @param dsd the DataSourceDesc of this data source
-         * @param data the subtitle data
-         */
-        public void onSubtitleData(
-                @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
-                @NonNull SubtitleData data) { }
-    }
-
-    private final Object mEventCbLock = new Object();
-    private ArrayList<Pair<Executor, EventCallback>> mEventCallbackRecords =
-            new ArrayList<Pair<Executor, EventCallback>>();
-
-    /**
-     * Registers the callback to be invoked for various events covered by {@link EventCallback}.
-     *
-     * @param executor the executor through which the callback should be invoked
-     * @param eventCallback the callback that will be run
-     */
-    // This is a synchronous call.
-    public void registerEventCallback(@NonNull @CallbackExecutor Executor executor,
-            @NonNull EventCallback eventCallback) {
-        if (eventCallback == null) {
-            throw new IllegalArgumentException("Illegal null EventCallback");
-        }
-        if (executor == null) {
-            throw new IllegalArgumentException(
-                    "Illegal null Executor for the EventCallback");
-        }
-        synchronized (mEventCbLock) {
-            for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                if (cb.first == executor && cb.second == eventCallback) {
-                    Log.w(TAG, "The callback has been registered before.");
-                    return;
-                }
-            }
-            mEventCallbackRecords.add(new Pair(executor, eventCallback));
-        }
-    }
-
-    /**
-     * Unregisters the {@link EventCallback}.
-     *
-     * @param eventCallback the callback to be unregistered
-     */
-    // This is a synchronous call.
-    public void unregisterEventCallback(EventCallback eventCallback) {
-        synchronized (mEventCbLock) {
-            for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                if (cb.second == eventCallback) {
-                    mEventCallbackRecords.remove(cb);
-                }
-            }
-        }
-    }
-
-    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);
-    }
-
-    /* Do not change these values without updating their counterparts
-     * in include/media/MediaPlayer2Types.h!
-     */
-    /** Unspecified media player error.
-     * @see EventCallback#onError
-     */
-    public static final int MEDIA_ERROR_UNKNOWN = 1;
-
-    /**
-     * The video is streamed and its container is not valid for progressive
-     * playback i.e the video's index (e.g moov atom) is not at the start of the
-     * file.
-     * @see EventCallback#onError
-     */
-    public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;
-
-    /** File or network related operation errors. */
-    public static final int MEDIA_ERROR_IO = -1004;
-    /** Bitstream is not conforming to the related coding standard or file spec. */
-    public static final int MEDIA_ERROR_MALFORMED = -1007;
-    /** Bitstream is conforming to the related coding standard or file spec, but
-     * the media framework does not support the feature. */
-    public static final int MEDIA_ERROR_UNSUPPORTED = -1010;
-    /** Some operation takes too long to complete, usually more than 3-5 seconds. */
-    public static final int MEDIA_ERROR_TIMED_OUT = -110;
-
-    /** Unspecified low-level system error. This value originated from UNKNOWN_ERROR in
-     * system/core/include/utils/Errors.h
-     * @see EventCallback#onError
-     * @hide
-     */
-    public static final int MEDIA_ERROR_SYSTEM = -2147483648;
-
-    /**
-     * @hide
-     */
-    @IntDef(flag = false, prefix = "MEDIA_ERROR", value = {
-            MEDIA_ERROR_UNKNOWN,
-            MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK,
-            MEDIA_ERROR_IO,
-            MEDIA_ERROR_MALFORMED,
-            MEDIA_ERROR_UNSUPPORTED,
-            MEDIA_ERROR_TIMED_OUT,
-            MEDIA_ERROR_SYSTEM
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface MediaError {}
-
-    /* Do not change these values without updating their counterparts
-     * in include/media/MediaPlayer2Types.h!
-     */
-    /** Unspecified media player info.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_UNKNOWN = 1;
-
-    /** The player just started the playback of this datas source.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_DATA_SOURCE_START = 2;
-
-    /** The player just pushed the very first video frame for rendering.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3;
-
-    /** The player just rendered the very first audio sample.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_AUDIO_RENDERING_START = 4;
-
-    /** The player just completed the playback of this data source.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_DATA_SOURCE_END = 5;
-
-    /** The player just completed the playback of all data sources set by {@link #setDataSource},
-     * {@link #setNextDataSource} and {@link #setNextDataSources}.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_DATA_SOURCE_LIST_END = 6;
-
-    /** The player just completed an iteration of playback loop. This event is sent only when
-     *  looping is enabled by {@link #loopCurrent}.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_DATA_SOURCE_REPEAT = 7;
-
-    /** The player just prepared a data source.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_PREPARED = 100;
-
-    /** The video is too complex for the decoder: it can't decode frames fast
-     *  enough. Possibly only the audio plays fine at this stage.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;
-
-    /** MediaPlayer2 is temporarily pausing playback internally in order to
-     * buffer more data.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_BUFFERING_START = 701;
-
-    /** MediaPlayer2 is resuming playback after filling buffers.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_BUFFERING_END = 702;
-
-    /** Estimated network bandwidth information (kbps) is available; currently this event fires
-     * simultaneously as {@link #MEDIA_INFO_BUFFERING_START} and {@link #MEDIA_INFO_BUFFERING_END}
-     * when playing network files.
-     * @see EventCallback#onInfo
-     * @hide
-     */
-    public static final int MEDIA_INFO_NETWORK_BANDWIDTH = 703;
-
-    /**
-     * Update status in buffering a media source received through progressive downloading.
-     * The received buffering percentage indicates how much of the content has been buffered
-     * or played. For example a buffering update of 80 percent when half the content
-     * has already been played indicates that the next 30 percent of the
-     * content to play has been buffered.
-     *
-     * The {@code extra} parameter in {@code EventCallback.onInfo} is the
-     * percentage (0-100) of the content that has been buffered or played thus far.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_BUFFERING_UPDATE = 704;
-
-    /** Bad interleaving means that a media has been improperly interleaved or
-     * not interleaved at all, e.g has all the video samples first then all the
-     * audio ones. Video is playing but a lot of disk seeks may be happening.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_BAD_INTERLEAVING = 800;
-
-    /** The media cannot be seeked (e.g live stream)
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_NOT_SEEKABLE = 801;
-
-    /** A new set of metadata is available.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_METADATA_UPDATE = 802;
-
-    /** Informs that audio is not playing. Note that playback of the video
-     * is not interrupted.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_AUDIO_NOT_PLAYING = 804;
-
-    /** Informs that video is not playing. Note that playback of the audio
-     * is not interrupted.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_VIDEO_NOT_PLAYING = 805;
-
-    /** Failed to handle timed text track properly.
-     * @see EventCallback#onInfo
-     *
-     * {@hide}
-     */
-    public static final int MEDIA_INFO_TIMED_TEXT_ERROR = 900;
-
-    /** Subtitle track was not supported by the media framework.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901;
-
-    /** Reading the subtitle track takes too long.
-     * @see EventCallback#onInfo
-     */
-    public static final int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902;
-
-    /**
-     * @hide
-     */
-    @IntDef(flag = false, prefix = "MEDIA_INFO", value = {
-            MEDIA_INFO_UNKNOWN,
-            MEDIA_INFO_DATA_SOURCE_START,
-            MEDIA_INFO_VIDEO_RENDERING_START,
-            MEDIA_INFO_AUDIO_RENDERING_START,
-            MEDIA_INFO_DATA_SOURCE_END,
-            MEDIA_INFO_DATA_SOURCE_LIST_END,
-            MEDIA_INFO_PREPARED,
-            MEDIA_INFO_VIDEO_TRACK_LAGGING,
-            MEDIA_INFO_BUFFERING_START,
-            MEDIA_INFO_BUFFERING_END,
-            MEDIA_INFO_NETWORK_BANDWIDTH,
-            MEDIA_INFO_BUFFERING_UPDATE,
-            MEDIA_INFO_BAD_INTERLEAVING,
-            MEDIA_INFO_NOT_SEEKABLE,
-            MEDIA_INFO_METADATA_UPDATE,
-            MEDIA_INFO_AUDIO_NOT_PLAYING,
-            MEDIA_INFO_VIDEO_NOT_PLAYING,
-            MEDIA_INFO_TIMED_TEXT_ERROR,
-            MEDIA_INFO_UNSUPPORTED_SUBTITLE,
-            MEDIA_INFO_SUBTITLE_TIMED_OUT
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface MediaInfo {}
-
-    //--------------------------------------------------------------------------
-    /** The player just completed a call {@link #attachAuxEffect}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_ATTACH_AUX_EFFECT = 1;
-
-    /** The player just completed a call {@link #deselectTrack}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_DESELECT_TRACK = 2;
-
-    /** The player just completed a call {@link #loopCurrent}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_LOOP_CURRENT = 3;
-
-    /** The player just completed a call {@link #pause}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_PAUSE = 4;
-
-    /** The player just completed a call {@link #play}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_PLAY = 5;
-
-    /** The player just completed a call {@link #prepare}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_PREPARE = 6;
-
-    /** The player just completed a call {@link #seekTo}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SEEK_TO = 14;
-
-    /** The player just completed a call {@link #selectTrack}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SELECT_TRACK = 15;
-
-    /** The player just completed a call {@link #setAudioAttributes}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SET_AUDIO_ATTRIBUTES = 16;
-
-    /** The player just completed a call {@link #setAudioSessionId}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SET_AUDIO_SESSION_ID = 17;
-
-    /** The player just completed a call {@link #setAuxEffectSendLevel}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL = 18;
-
-    /** The player just completed a call {@link #setDataSource}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SET_DATA_SOURCE = 19;
-
-    /** The player just completed a call {@link #setNextDataSource}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCE = 22;
-
-    /** The player just completed a call {@link #setNextDataSources}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCES = 23;
-
-    /** The player just completed a call {@link #setPlaybackParams}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SET_PLAYBACK_PARAMS = 24;
-
-    /** The player just completed a call {@link #setPlayerVolume}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SET_PLAYER_VOLUME = 26;
-
-    /** The player just completed a call {@link #setSurface}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SET_SURFACE = 27;
-
-    /** The player just completed a call {@link #setSyncParams}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SET_SYNC_PARAMS = 28;
-
-    /** The player just completed a call {@link #skipToNext}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SKIP_TO_NEXT = 29;
-
-    /** The player just completed a call {@link #clearNextDataSources}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES = 30;
-
-    /** The player just completed a call {@link #setBufferingParams}.
-     * @see EventCallback#onCallCompleted
-     * @hide
-     */
-    public static final int CALL_COMPLETED_SET_BUFFERING_PARAMS = 31;
-
-    /** The player just completed a call {@link #setDisplay}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SET_DISPLAY = 33;
-
-    /** The player just completed a call {@link #setWakeLock}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SET_WAKE_LOCK = 34;
-
-    /** The player just completed a call {@link #setScreenOnWhilePlaying}.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING = 35;
-
-    /**
-     * The start of the methods which have separate call complete callback.
-     * @hide
-     */
-    public static final int SEPARATE_CALL_COMPLETED_CALLBACK_START = 1000;
-
-    /** The player just completed a call {@link #notifyWhenCommandLabelReached}.
-     * @see EventCallback#onCommandLabelReached
-     * @hide
-     */
-    public static final int CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED =
-            SEPARATE_CALL_COMPLETED_CALLBACK_START;
-
-    /** The player just completed a call {@link #prepareDrm}.
-     * @see DrmEventCallback#onDrmPrepared
-     * @hide
-     */
-    public static final int CALL_COMPLETED_PREPARE_DRM =
-            SEPARATE_CALL_COMPLETED_CALLBACK_START + 1;
-
-    /**
-     * @hide
-     */
-    @IntDef(flag = false, prefix = "CALL_COMPLETED", value = {
-            CALL_COMPLETED_ATTACH_AUX_EFFECT,
-            CALL_COMPLETED_DESELECT_TRACK,
-            CALL_COMPLETED_LOOP_CURRENT,
-            CALL_COMPLETED_PAUSE,
-            CALL_COMPLETED_PLAY,
-            CALL_COMPLETED_PREPARE,
-            CALL_COMPLETED_SEEK_TO,
-            CALL_COMPLETED_SELECT_TRACK,
-            CALL_COMPLETED_SET_AUDIO_ATTRIBUTES,
-            CALL_COMPLETED_SET_AUDIO_SESSION_ID,
-            CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL,
-            CALL_COMPLETED_SET_DATA_SOURCE,
-            CALL_COMPLETED_SET_NEXT_DATA_SOURCE,
-            CALL_COMPLETED_SET_NEXT_DATA_SOURCES,
-            CALL_COMPLETED_SET_PLAYBACK_PARAMS,
-            CALL_COMPLETED_SET_PLAYER_VOLUME,
-            CALL_COMPLETED_SET_SURFACE,
-            CALL_COMPLETED_SET_SYNC_PARAMS,
-            CALL_COMPLETED_SKIP_TO_NEXT,
-            CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES,
-            CALL_COMPLETED_SET_BUFFERING_PARAMS,
-            CALL_COMPLETED_SET_DISPLAY,
-            CALL_COMPLETED_SET_WAKE_LOCK,
-            CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING,
-            CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED,
-            CALL_COMPLETED_PREPARE_DRM,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface CallCompleted {}
-
-    /** Status code represents that call is completed without an error.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_STATUS_NO_ERROR = 0;
-
-    /** Status code represents that call is ended with an unknown error.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_STATUS_ERROR_UNKNOWN = Integer.MIN_VALUE;
-
-    /** Status code represents that the player is not in valid state for the operation.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_STATUS_INVALID_OPERATION = 1;
-
-    /** Status code represents that the argument is illegal.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_STATUS_BAD_VALUE = 2;
-
-    /** Status code represents that the operation is not allowed.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_STATUS_PERMISSION_DENIED = 3;
-
-    /** Status code represents a file or network related operation error.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_STATUS_ERROR_IO = 4;
-
-    /** Status code represents that the call has been skipped. For example, a {@link #seekTo}
-     * request may be skipped if it is followed by another {@link #seekTo} request.
-     * @see EventCallback#onCallCompleted
-     */
-    public static final int CALL_STATUS_SKIPPED = 5;
-
-    /** Status code represents that DRM operation is called before preparing a DRM scheme through
-     *  {@code prepareDrm}.
-     * @see EventCallback#onCallCompleted
-     */
-    // TODO: change @code to @link when DRM is unhidden
-    public static final int CALL_STATUS_NO_DRM_SCHEME = 6;
-
-    /**
-     * @hide
-     */
-    @IntDef(flag = false, prefix = "CALL_STATUS", value = {
-            CALL_STATUS_NO_ERROR,
-            CALL_STATUS_ERROR_UNKNOWN,
-            CALL_STATUS_INVALID_OPERATION,
-            CALL_STATUS_BAD_VALUE,
-            CALL_STATUS_PERMISSION_DENIED,
-            CALL_STATUS_ERROR_IO,
-            CALL_STATUS_SKIPPED,
-            CALL_STATUS_NO_DRM_SCHEME})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface CallStatus {}
-
-    // Modular DRM begin
-
-    /**
-     * Interface definition of a callback to be invoked when the app
-     * can do DRM configuration (get/set properties) before the session
-     * is opened. This facilitates configuration of the properties, like
-     * 'securityLevel', which has to be set after DRM scheme creation but
-     * before the DRM session is opened.
-     *
-     * The only allowed DRM calls in this listener are
-     * {@link MediaPlayer2#getDrmPropertyString(DataSourceDesc, String)}
-     * and {@link MediaPlayer2#setDrmPropertyString(DataSourceDesc, String, String)}.
-     * @hide
-     */
-    public interface OnDrmConfigHelper {
-        /**
-         * Called to give the app the opportunity to configure DRM before the session is created
-         *
-         * @param mp the {@code MediaPlayer2} associated with this callback
-         * @param dsd the DataSourceDesc of this data source
-         */
-        public void onDrmConfig(MediaPlayer2 mp, DataSourceDesc dsd);
-    }
-
-    /**
-     * Register a callback to be invoked for configuration of the DRM object before
-     * the session is created.
-     * The callback will be invoked synchronously during the execution
-     * of {@link #prepareDrm}.
-     *
-     * @param listener the callback that will be run
-     * @hide
-     */
-    // This is a synchronous call.
-    public void setOnDrmConfigHelper(OnDrmConfigHelper listener) {
-        mOnDrmConfigHelper = listener;
-    }
-
-    private OnDrmConfigHelper mOnDrmConfigHelper;
-
-    /**
-     * Interface definition for callbacks to be invoked when the player has the corresponding
-     * DRM events.
-     * @hide
-     */
-    public static class DrmEventCallback {
-        /**
-         * Called to indicate DRM info is available
-         *
-         * @param mp the {@code MediaPlayer2} associated with this callback
-         * @param dsd the DataSourceDesc of this data source
-         * @param drmInfo DRM info of the source including PSSH, and subset
-         *                of crypto schemes supported by this device
-         */
-        public void onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) { }
-
-        /**
-         * Called to notify the client that {@link MediaPlayer2#prepareDrm(DataSourceDesc, UUID)}
-         * is finished and ready for key request/response.
-         *
-         * @param mp the {@code MediaPlayer2} associated with this callback
-         * @param dsd the DataSourceDesc of this data source
-         * @param status the result of DRM preparation.
-         */
-        public void onDrmPrepared(
-                MediaPlayer2 mp, DataSourceDesc dsd, @PrepareDrmStatusCode int status) { }
-    }
-
-    private final Object mDrmEventCbLock = new Object();
-    private ArrayList<Pair<Executor, DrmEventCallback>> mDrmEventCallbackRecords =
-            new ArrayList<Pair<Executor, DrmEventCallback>>();
-
-    /**
-     * Registers the callback to be invoked for various DRM events.
-     *
-     * @param eventCallback the callback that will be run
-     * @param executor the executor through which the callback should be invoked
-     * @hide
-     */
-    // This is a synchronous call.
-    public void registerDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
-            @NonNull DrmEventCallback eventCallback) {
-        if (eventCallback == null) {
-            throw new IllegalArgumentException("Illegal null EventCallback");
-        }
-        if (executor == null) {
-            throw new IllegalArgumentException(
-                    "Illegal null Executor for the EventCallback");
-        }
-        synchronized (mDrmEventCbLock) {
-            mDrmEventCallbackRecords.add(new Pair(executor, eventCallback));
-        }
-    }
-
-    /**
-     * Unregisters the {@link DrmEventCallback}.
-     *
-     * @param eventCallback the callback to be unregistered
-     * @hide
-     */
-    // This is a synchronous call.
-    public void unregisterDrmEventCallback(DrmEventCallback eventCallback) {
-        synchronized (mDrmEventCbLock) {
-            for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
-                if (cb.second == eventCallback) {
-                    mDrmEventCallbackRecords.remove(cb);
-                }
-            }
-        }
-    }
-
-    /**
-     * The status codes for {@link DrmEventCallback#onDrmPrepared} listener.
-     * <p>
-     *
-     * DRM preparation has succeeded.
-     * @hide
-     */
-    public static final int PREPARE_DRM_STATUS_SUCCESS = 0;
-
-    /**
-     * The device required DRM provisioning but couldn't reach the provisioning server.
-     * @hide
-     */
-    public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1;
-
-    /**
-     * The device required DRM provisioning but the provisioning server denied the request.
-     * @hide
-     */
-    public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2;
-
-    /**
-     * The DRM preparation has failed .
-     * @hide
-     */
-    public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3;
-
-    /**
-     * The crypto scheme UUID is not supported by the device.
-     * @hide
-     */
-    public static final int PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME = 4;
-
-    /**
-     * The hardware resources are not available, due to being in use.
-     * @hide
-     */
-    public static final int PREPARE_DRM_STATUS_RESOURCE_BUSY = 5;
-
-    /** @hide */
-    @IntDef(flag = false, prefix = "PREPARE_DRM_STATUS", value = {
-        PREPARE_DRM_STATUS_SUCCESS,
-        PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR,
-        PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR,
-        PREPARE_DRM_STATUS_PREPARATION_ERROR,
-        PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME,
-        PREPARE_DRM_STATUS_RESOURCE_BUSY,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface PrepareDrmStatusCode {}
-
-    /** @hide */
-    @IntDef({
-        MediaDrm.KEY_TYPE_STREAMING,
-        MediaDrm.KEY_TYPE_OFFLINE,
-        MediaDrm.KEY_TYPE_RELEASE,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface MediaDrmKeyType {}
-
-    /** @hide */
-    @StringDef({
-        MediaDrm.PROPERTY_VENDOR,
-        MediaDrm.PROPERTY_VERSION,
-        MediaDrm.PROPERTY_DESCRIPTION,
-        MediaDrm.PROPERTY_ALGORITHMS,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface MediaDrmStringProperty {}
-
-    /**
-     * Retrieves the DRM Info associated with the given source
-     *
-     * @param dsd The DRM protected data source
-     *
-     * @throws IllegalStateException if called before being prepared
-     * @hide
-     */
-    public DrmInfo getDrmInfo(@NonNull DataSourceDesc dsd) {
-        final SourceInfo sourceInfo = getSourceInfo(dsd);
-        if (sourceInfo != null) {
-            DrmInfo drmInfo = null;
-
-            // there is not much point if the app calls getDrmInfo within an OnDrmInfoListener;
-            // regardless below returns drmInfo anyway instead of raising an exception
-            synchronized (sourceInfo) {
-                if (!sourceInfo.mDrmInfoResolved && sourceInfo.mDrmInfo == null) {
-                    final String msg = "The Player has not been prepared yet";
-                    Log.v(TAG, msg);
-                    throw new IllegalStateException(msg);
-                }
-
-                if (sourceInfo.mDrmInfo != null) {
-                    drmInfo  = sourceInfo.mDrmInfo.makeCopy();
-                }
-            }   // synchronized
-
-            return drmInfo;
-        }
-        return null;
-    }
-
-    /**
-     * Prepares the DRM for the given data source
-     * <p>
-     * If {@link OnDrmConfigHelper} is registered, it will be called during
-     * preparation to allow configuration of the DRM properties before opening the
-     * DRM session. It should be used only for a series of
-     * {@link #getDrmPropertyString(DataSourceDesc, String)} and
-     * {@link #setDrmPropertyString(DataSourceDesc, String, String)} calls
-     * and refrain from any lengthy operation.
-     * <p>
-     * If the device has not been provisioned before, this call also provisions the device
-     * which involves accessing the provisioning server and can take a variable time to
-     * complete depending on the network connectivity.
-     * When needed, the provisioning will be launched  in the background.
-     * The listener {@link DrmEventCallback#onDrmPrepared}
-     * will be called when provisioning and preparation are finished. The application should
-     * check the status code returned with {@link DrmEventCallback#onDrmPrepared} to proceed.
-     * <p>
-     * The registered {@link DrmEventCallback#onDrmPrepared} is called to indicate the DRM
-     * session being ready. The application should not make any assumption about its call
-     * sequence (e.g., before or after prepareDrm returns).
-     * <p>
-     *
-     * @param dsd The DRM protected data source
-     *
-     * @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
-     * from the source through {@link #getDrmInfo(DataSourceDesc)} or registering a
-     * {@link DrmEventCallback#onDrmInfo}.
-     *
-     * @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
-     * @hide
-     */
-    // This is an asynchronous call.
-    public Object prepareDrm(@NonNull DataSourceDesc dsd, @NonNull UUID uuid) {
-        return addTask(new Task(CALL_COMPLETED_PREPARE_DRM, true) {
-            @Override
-            void process() {
-                final SourceInfo sourceInfo = getSourceInfo(dsd);
-                int status = PREPARE_DRM_STATUS_PREPARATION_ERROR;
-                boolean sendEvent = true;
-
-                if (sourceInfo == null) {
-                    Log.e(TAG, "prepareDrm(): DataSource not found.");
-                } else if (sourceInfo.mDrmInfo == null) {
-                    // only allowing if tied to a protected source;
-                    // might relax for releasing offline keys
-                    Log.e(TAG, "prepareDrm(): Wrong usage: The player must be prepared and "
-                            + "DRM info be retrieved before this call.");
-                } else {
-                    status = PREPARE_DRM_STATUS_SUCCESS;
-                }
-
-                try {
-                    if (status == PREPARE_DRM_STATUS_SUCCESS) {
-                        sourceInfo.mDrmHandle.prepare(uuid);
-                    }
-                } catch (ResourceBusyException e) {
-                    status = PREPARE_DRM_STATUS_RESOURCE_BUSY;
-                } catch (UnsupportedSchemeException e) {
-                    status = PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME;
-                } catch (NotProvisionedException e) {
-                    Log.w(TAG, "prepareDrm: NotProvisionedException");
-
-                    // handle provisioning internally; it'll reset mPrepareDrmInProgress
-                    status = sourceInfo.mDrmHandle.handleProvisioninig(uuid, mTaskId);
-
-                    if (status == PREPARE_DRM_STATUS_SUCCESS) {
-                        // DrmEventCallback will be fired in provisioning
-                        sendEvent = false;
-                    } else {
-                        synchronized (sourceInfo.mDrmHandle) {
-                            sourceInfo.mDrmHandle.cleanDrmObj();
-                        }
-
-                        switch (status) {
-                            case PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR:
-                                Log.e(TAG, "prepareDrm: Provisioning was required but failed "
-                                        + "due to a network error.");
-                                break;
-
-                            case PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR:
-                                Log.e(TAG, "prepareDrm: Provisioning was required but the request "
-                                        + "was denied by the server.");
-                                break;
-
-                            case PREPARE_DRM_STATUS_PREPARATION_ERROR:
-                            default:
-                                Log.e(TAG, "prepareDrm: Post-provisioning preparation failed.");
-                                break;
-                        }
-                    }
-                } catch (Exception e) {
-                    status = PREPARE_DRM_STATUS_PREPARATION_ERROR;
-                }
-
-                if (sendEvent) {
-                    final int prepareDrmStatus = status;
-                    sendDrmEvent(new DrmEventNotifier() {
-                        @Override
-                        public void notify(DrmEventCallback callback) {
-                            callback.onDrmPrepared(
-                                    MediaPlayer2.this, dsd, prepareDrmStatus);
-                        }
-                    });
-
-                    synchronized (mTaskLock) {
-                        mCurrentTask = null;
-                        processPendingTask_l();
-                    }
-                }
-            }
-        });
-    }
-
-    /**
-     * Releases the DRM session for the given data source
-     * <p>
-     * The player has to have an active DRM session and be in stopped, or prepared
-     * state before this call is made.
-     * A {@link #reset()} call will release the DRM session implicitly.
-     *
-     * @param dsd The DRM protected data source
-     *
-     * @throws NoDrmSchemeException if there is no active DRM session to release
-     * @hide
-     */
-    // This is a synchronous call.
-    public void releaseDrm(@NonNull DataSourceDesc dsd)
-            throws NoDrmSchemeException {
-        final SourceInfo sourceInfo = getSourceInfo(dsd);
-        if (sourceInfo != null) {
-            sourceInfo.mDrmHandle.release();
-        }
-    }
-
-    private native void native_releaseDrm(long mSrcId);
-
-    /**
-     * A key request/response exchange occurs between the app and a license server
-     * to obtain or release keys used to decrypt the given data source.
-     * <p>
-     * {@code getDrmKeyRequest()} is used to obtain an opaque key request byte array that is
-     * delivered to the license server.  The opaque key request byte array is returned
-     * in KeyRequest.data.  The recommended URL to deliver the key request to is
-     * returned in {@code KeyRequest.defaultUrl}.
-     * <p>
-     * After the app has received the key request response from the server,
-     * it should deliver to the response to the DRM engine plugin using the method
-     * {@link #provideDrmKeyResponse(DataSourceDesc, byte[], byte[])}.
-     *
-     * @param dsd the DRM protected data source
-     *
-     * @param keySetId is the key-set identifier of the offline keys being released when keyType is
-     * {@link MediaDrm#KEY_TYPE_RELEASE}. It should be set to null for other key requests, when
-     * keyType is {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}.
-     *
-     * @param initData is the container-specific initialization data when the keyType is
-     * {@link MediaDrm#KEY_TYPE_STREAMING} or {@link MediaDrm#KEY_TYPE_OFFLINE}. Its meaning is
-     * interpreted based on the mime type provided in the mimeType parameter.  It could
-     * contain, for example, the content ID, key ID or other data obtained from the content
-     * metadata that is required in generating the key request.
-     * When the keyType is {@link MediaDrm#KEY_TYPE_RELEASE}, it should be set to null.
-     *
-     * @param mimeType identifies the mime type of the content
-     *
-     * @param keyType specifies the type of the request. The request may be to acquire
-     * keys for streaming, {@link MediaDrm#KEY_TYPE_STREAMING}, or for offline content
-     * {@link MediaDrm#KEY_TYPE_OFFLINE}, or to release previously acquired
-     * keys ({@link MediaDrm#KEY_TYPE_RELEASE}), which are identified by a keySetId.
-     *
-     * @param optionalParameters are included in the key request message to
-     * allow a client application to provide additional message parameters to the server.
-     * This may be {@code null} if no additional parameters are to be sent.
-     *
-     * @throws NoDrmSchemeException if there is no active DRM session
-     * @hide
-     */
-    public MediaDrm.KeyRequest getDrmKeyRequest(
-            @NonNull DataSourceDesc dsd,
-            @Nullable byte[] keySetId, @Nullable byte[] initData,
-            @Nullable String mimeType, @MediaDrmKeyType int keyType,
-            @Nullable Map<String, String> optionalParameters)
-            throws NoDrmSchemeException {
-        Log.v(TAG, "getDrmKeyRequest: " +
-                " keySetId: " + keySetId + " initData:" + initData + " mimeType: " + mimeType +
-                " keyType: " + keyType + " optionalParameters: " + optionalParameters);
-
-        final SourceInfo sourceInfo = getSourceInfo(dsd);
-        if (sourceInfo != null) {
-            return sourceInfo.mDrmHandle.getDrmKeyRequest(
-                    keySetId, initData, mimeType, keyType, optionalParameters);
-        }
-        return null;
-    }
-
-    /**
-     * A key response is received from the license server by the app for the given DRM protected
-     * data source, then provided to the DRM engine plugin using {@code provideDrmKeyResponse}.
-     * <p>
-     * When the response is for an offline key request, a key-set identifier is returned that
-     * can be used to later restore the keys to a new session with the method
-     * {@link #restoreDrmKeys(DataSourceDesc, byte[])}.
-     * When the response is for a streaming or release request, null is returned.
-     *
-     * @param dsd the DRM protected data source
-     *
-     * @param keySetId When the response is for a release request, keySetId identifies the saved
-     * key associated with the release request (i.e., the same keySetId passed to the earlier
-     * {@link # getDrmKeyRequest(DataSourceDesc, byte[], byte[], String, int, Map)} call).
-     * It MUST be null when the response is for either streaming or offline key requests.
-     *
-     * @param response the byte array response from the server
-     *
-     * @throws NoDrmSchemeException if there is no active DRM session
-     * @throws DeniedByServerException if the response indicates that the
-     * server rejected the request
-     * @hide
-     */
-    // This is a synchronous call.
-    public byte[] provideDrmKeyResponse(
-            @NonNull DataSourceDesc dsd,
-            @Nullable byte[] keySetId, @NonNull byte[] response)
-            throws NoDrmSchemeException, DeniedByServerException {
-        Log.v(TAG, "provideDrmKeyResponse: keySetId: " + keySetId + " response: " + response);
-
-        final SourceInfo sourceInfo = getSourceInfo(dsd);
-        if (sourceInfo != null) {
-            return sourceInfo.mDrmHandle.provideDrmKeyResponse(keySetId, response);
-        }
-        return null;
-    }
-
-    /**
-     * Restore persisted offline keys into a new session for the given DRM protected data source.
-     * {@code keySetId} identifies the keys to load, obtained from a prior call to
-     * {@link #provideDrmKeyResponse(DataSourceDesc, byte[], byte[])}.
-     *
-     * @param dsd the DRM protected data source
-     *
-     * @param keySetId identifies the saved key set to restore
-     *
-     * @throws NoDrmSchemeException if there is no active DRM session
-     * @hide
-     */
-    // This is a synchronous call.
-    public void restoreDrmKeys(
-            @NonNull DataSourceDesc dsd,
-            @NonNull byte[] keySetId)
-            throws NoDrmSchemeException {
-        Log.v(TAG, "restoreDrmKeys: keySetId: " + keySetId);
-
-        final SourceInfo sourceInfo = getSourceInfo(dsd);
-        if (sourceInfo != null) {
-            sourceInfo.mDrmHandle.restoreDrmKeys(keySetId);
-        }
-    }
-
-    /**
-     * Read a DRM engine plugin String property value, given the DRM protected data source
-     * and property name string.
-     *
-     * @param dsd the DRM protected data source
-     *
-     * @param propertyName the property name
-     *
-     * Standard fields names are:
-     * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
-     * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
-     *
-     * @throws NoDrmSchemeException if there is no active DRM session
-     * @hide
-     */
-    public String getDrmPropertyString(
-            @NonNull DataSourceDesc dsd,
-            @NonNull @MediaDrmStringProperty String propertyName)
-            throws NoDrmSchemeException {
-        Log.v(TAG, "getDrmPropertyString: propertyName: " + propertyName);
-
-        final SourceInfo sourceInfo = getSourceInfo(dsd);
-        if (sourceInfo != null) {
-            return sourceInfo.mDrmHandle.getDrmPropertyString(propertyName);
-        }
-        return null;
-    }
-
-    /**
-     * Set a DRM engine plugin String property value for the given data source.
-     *
-     * @param dsd the DRM protected data source
-     * @param propertyName the property name
-     * @param value the property value
-     *
-     * Standard fields names are:
-     * {@link MediaDrm#PROPERTY_VENDOR}, {@link MediaDrm#PROPERTY_VERSION},
-     * {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
-     *
-     * @throws NoDrmSchemeException if there is no active DRM session
-     * @hide
-     */
-    // This is a synchronous call.
-    public void setDrmPropertyString(
-            @NonNull DataSourceDesc dsd,
-            @NonNull @MediaDrmStringProperty String propertyName, @NonNull String value)
-            throws NoDrmSchemeException {
-        // TODO: this implementation only works when dsd is the only data source
-        Log.v(TAG, "setDrmPropertyString: propertyName: " + propertyName + " value: " + value);
-
-        final SourceInfo sourceInfo = getSourceInfo(dsd);
-        if (sourceInfo != null) {
-            sourceInfo.mDrmHandle.setDrmPropertyString(propertyName, value);
-        }
-    }
-
-    /**
-     * Encapsulates the DRM properties of the source.
-     * @hide
-     */
-    public static final class DrmInfo {
-        private Map<UUID, byte[]> mMapPssh;
-        private UUID[] mSupportedSchemes;
-
-        /**
-         * Returns the PSSH info of the data source for each supported DRM scheme.
-         */
-        public Map<UUID, byte[]> getPssh() {
-            return mMapPssh;
-        }
-
-        /**
-         * Returns the intersection of the data source and the device DRM schemes.
-         * It effectively identifies the subset of the source's DRM schemes which
-         * are supported by the device too.
-         */
-        public List<UUID> getSupportedSchemes() {
-            return Arrays.asList(mSupportedSchemes);
-        }
-
-        private DrmInfo(Map<UUID, byte[]> pssh, UUID[] supportedSchemes) {
-            mMapPssh = pssh;
-            mSupportedSchemes = supportedSchemes;
-        }
-
-        private static DrmInfo create(PlayerMessage msg) {
-            Log.v(TAG, "DrmInfo.create(" + msg + ")");
-
-            Iterator<Value> in = msg.getValuesList().iterator();
-            byte[] pssh = in.next().getBytesValue().toByteArray();
-
-            Log.v(TAG, "DrmInfo.create() PSSH: " + DrmInfo.arrToHex(pssh));
-            Map<UUID, byte[]> mapPssh = DrmInfo.parsePSSH(pssh, pssh.length);
-            Log.v(TAG, "DrmInfo.create() PSSH: " + mapPssh);
-
-            int supportedDRMsCount = in.next().getInt32Value();
-            UUID[] supportedSchemes = new UUID[supportedDRMsCount];
-            for (int i = 0; i < supportedDRMsCount; i++) {
-                byte[] uuid = new byte[16];
-                in.next().getBytesValue().copyTo(uuid, 0);
-
-                supportedSchemes[i] = DrmInfo.bytesToUUID(uuid);
-
-                Log.v(TAG, "DrmInfo() supportedScheme[" + i + "]: " + supportedSchemes[i]);
-            }
-
-            Log.v(TAG, "DrmInfo.create() psshsize: " + pssh.length
-                    + " supportedDRMsCount: " + supportedDRMsCount);
-            return new DrmInfo(mapPssh, supportedSchemes);
-        }
-
-        private DrmInfo makeCopy() {
-            return new DrmInfo(this.mMapPssh, this.mSupportedSchemes);
-        }
-
-        private static String arrToHex(byte[] bytes) {
-            String out = "0x";
-            for (int i = 0; i < bytes.length; i++) {
-                out += String.format("%02x", bytes[i]);
-            }
-
-            return out;
-        }
-
-        private static UUID bytesToUUID(byte[] uuid) {
-            long msb = 0, lsb = 0;
-            for (int i = 0; i < 8; i++) {
-                msb |= (((long) uuid[i]     & 0xff) << (8 * (7 - i)));
-                lsb |= (((long) uuid[i + 8] & 0xff) << (8 * (7 - i)));
-            }
-
-            return new UUID(msb, lsb);
-        }
-
-        private static Map<UUID, byte[]> parsePSSH(byte[] pssh, int psshsize) {
-            Map<UUID, byte[]> result = new HashMap<UUID, byte[]>();
-
-            final int uuidSize = 16;
-            final int dataLenSize = 4;
-
-            int len = psshsize;
-            int numentries = 0;
-            int i = 0;
-
-            while (len > 0) {
-                if (len < uuidSize) {
-                    Log.w(TAG, String.format("parsePSSH: len is too short to parse "
-                                             + "UUID: (%d < 16) pssh: %d", len, psshsize));
-                    return null;
-                }
-
-                byte[] subset = Arrays.copyOfRange(pssh, i, i + uuidSize);
-                UUID uuid = bytesToUUID(subset);
-                i += uuidSize;
-                len -= uuidSize;
-
-                // get data length
-                if (len < 4) {
-                    Log.w(TAG, String.format("parsePSSH: len is too short to parse "
-                                             + "datalen: (%d < 4) pssh: %d", len, psshsize));
-                    return null;
-                }
-
-                subset = Arrays.copyOfRange(pssh, i, i + dataLenSize);
-                int datalen = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN)
-                        ? ((subset[3] & 0xff) << 24) | ((subset[2] & 0xff) << 16)
-                        | ((subset[1] & 0xff) <<  8) |  (subset[0] & 0xff)        :
-                        ((subset[0] & 0xff) << 24) | ((subset[1] & 0xff) << 16)
-                        | ((subset[2] & 0xff) <<  8) |  (subset[3] & 0xff);
-                i += dataLenSize;
-                len -= dataLenSize;
-
-                if (len < datalen) {
-                    Log.w(TAG, String.format("parsePSSH: len is too short to parse "
-                                             + "data: (%d < %d) pssh: %d", len, datalen, psshsize));
-                    return null;
-                }
-
-                byte[] data = Arrays.copyOfRange(pssh, i, i + datalen);
-
-                // skip the data
-                i += datalen;
-                len -= datalen;
-
-                Log.v(TAG, String.format("parsePSSH[%d]: <%s, %s> pssh: %d",
-                                         numentries, uuid, arrToHex(data), psshsize));
-                numentries++;
-                result.put(uuid, data);
-            }
-
-            return result;
-        }
-    };  // DrmInfo
-
-    /**
-     * Thrown when a DRM method is called before preparing a DRM scheme through
-     * {@link MediaPlayer2#prepareDrm(DataSourceDesc, UUID)}.
-     * Extends MediaDrm.MediaDrmException
-     * @hide
-     */
-    public static final class NoDrmSchemeException extends MediaDrmException {
-        public NoDrmSchemeException(String detailMessage) {
-            super(detailMessage);
-        }
-    }
-
-    private native void native_prepareDrm(
-            long srcId, @NonNull byte[] uuid, @NonNull byte[] drmSessionId);
-
-    // Instantiated from the native side
-    @SuppressWarnings("unused")
-    private static class StreamEventCallback extends AudioTrack.StreamEventCallback {
-        public long mJAudioTrackPtr;
-        public long mNativeCallbackPtr;
-        public long mUserDataPtr;
-
-        StreamEventCallback(long jAudioTrackPtr, long nativeCallbackPtr, long userDataPtr) {
-            super();
-            mJAudioTrackPtr = jAudioTrackPtr;
-            mNativeCallbackPtr = nativeCallbackPtr;
-            mUserDataPtr = userDataPtr;
-        }
-
-        @Override
-        public void onTearDown(AudioTrack track) {
-            native_stream_event_onTearDown(mNativeCallbackPtr, mUserDataPtr);
-        }
-
-        @Override
-        public void onPresentationEnded(AudioTrack track) {
-            native_stream_event_onStreamPresentationEnd(mNativeCallbackPtr, mUserDataPtr);
-        }
-
-        @Override
-        public void onDataRequest(AudioTrack track, int size) {
-            native_stream_event_onStreamDataRequest(
-                    mJAudioTrackPtr, mNativeCallbackPtr, mUserDataPtr);
-        }
-    }
-
-    /**
-     * Returns a byte[] containing the remainder of 'in', closing it when done.
-     */
-    private static byte[] readInputStreamFully(InputStream in) throws IOException {
-        try {
-            return readInputStreamFullyNoClose(in);
-        } finally {
-            in.close();
-        }
-    }
-
-    /**
-     * Returns a byte[] containing the remainder of 'in'.
-     */
-    private static byte[] readInputStreamFullyNoClose(InputStream in) throws IOException {
-        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-        byte[] buffer = new byte[1024];
-        int count;
-        while ((count = in.read(buffer)) != -1) {
-            bytes.write(buffer, 0, count);
-        }
-        return bytes.toByteArray();
-    }
-
-    private static byte[] getByteArrayFromUUID(@NonNull UUID uuid) {
-        long msb = uuid.getMostSignificantBits();
-        long lsb = uuid.getLeastSignificantBits();
-
-        byte[] uuidBytes = new byte[16];
-        for (int i = 0; i < 8; ++i) {
-            uuidBytes[i] = (byte) (msb >>> (8 * (7 - i)));
-            uuidBytes[8 + i] = (byte) (lsb >>> (8 * (7 - i)));
-        }
-
-        return uuidBytes;
-    }
-
-    private static class TimedTextUtil {
-        // These keys must be in sync with the keys in TextDescription2.h
-        private static final int KEY_START_TIME                     = 7; // int
-        private static final int KEY_STRUCT_TEXT_POS               = 14; // TextPos
-        private static final int KEY_STRUCT_TEXT                   = 16; // Text
-        private static final int KEY_GLOBAL_SETTING               = 101;
-        private static final int KEY_LOCAL_SETTING                = 102;
-
-        private static TimedText parsePlayerMessage(PlayerMessage playerMsg) {
-            if (playerMsg.getValuesCount() == 0) {
-                return null;
-            }
-
-            String textChars = null;
-            Rect textBounds = null;
-            Iterator<Value> in = playerMsg.getValuesList().iterator();
-            int type = in.next().getInt32Value();
-            if (type == KEY_LOCAL_SETTING) {
-                type = in.next().getInt32Value();
-                if (type != KEY_START_TIME) {
-                    return null;
-                }
-                int startTimeMs = in.next().getInt32Value();
-
-                type = in.next().getInt32Value();
-                if (type != KEY_STRUCT_TEXT) {
-                    return null;
-                }
-
-                byte[] text = in.next().getBytesValue().toByteArray();
-                if (text == null || text.length == 0) {
-                    textChars = null;
-                } else {
-                    textChars = new String(text);
-                }
-
-            } else if (type != KEY_GLOBAL_SETTING) {
-                Log.w(TAG, "Invalid timed text key found: " + type);
-                return null;
-            }
-            if (in.hasNext()) {
-                type = in.next().getInt32Value();
-                if (type == KEY_STRUCT_TEXT_POS) {
-                    int top = in.next().getInt32Value();
-                    int left = in.next().getInt32Value();
-                    int bottom = in.next().getInt32Value();
-                    int right = in.next().getInt32Value();
-                    textBounds = new Rect(left, top, right, bottom);
-                }
-            }
-            return null;
-            /* TimedText c-tor usage is temporarily commented out.
-             * TODO(b/117527789): use SUBTITLE path for MEDIA_MIMETYPE_TEXT_3GPP track
-             *                    and remove TimedText path from MediaPlayer2.
-            return new TimedText(textChars, textBounds);
-            */
-        }
-    }
-
-    private Object addTask(Task task) {
-        synchronized (mTaskLock) {
-            mPendingTasks.add(task);
-            processPendingTask_l();
-        }
-        return task;
-    }
-
-    @GuardedBy("mTaskLock")
-    private void processPendingTask_l() {
-        if (mCurrentTask != null) {
-            return;
-        }
-        if (!mPendingTasks.isEmpty()) {
-            Task task = mPendingTasks.remove(0);
-            mCurrentTask = task;
-            mTaskHandler.post(task);
-        }
-    }
-
-    private abstract class Task implements Runnable {
-        final long mTaskId = mTaskIdGenerator.getAndIncrement();
-        private final int mMediaCallType;
-        private final boolean mNeedToWaitForEventToComplete;
-        private DataSourceDesc mDSD;
-
-        Task(int mediaCallType, boolean needToWaitForEventToComplete) {
-            mMediaCallType = mediaCallType;
-            mNeedToWaitForEventToComplete = needToWaitForEventToComplete;
-        }
-
-        abstract void process() throws IOException, NoDrmSchemeException;
-
-        @Override
-        public void run() {
-            int status = CALL_STATUS_NO_ERROR;
-            try {
-                if (mMediaCallType != CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED
-                        && getState() == PLAYER_STATE_ERROR) {
-                    status = CALL_STATUS_INVALID_OPERATION;
-                } else {
-                    if (mMediaCallType == CALL_COMPLETED_SEEK_TO) {
-                        synchronized (mTaskLock) {
-                            if (!mPendingTasks.isEmpty()) {
-                                Task nextTask = mPendingTasks.get(0);
-                                if (nextTask.mMediaCallType == mMediaCallType) {
-                                    throw new CommandSkippedException(
-                                            "consecutive seekTo is skipped except last one");
-                                }
-                            }
-                        }
-                    }
-                    process();
-                }
-            } catch (IllegalStateException e) {
-                status = CALL_STATUS_INVALID_OPERATION;
-            } catch (IllegalArgumentException e) {
-                status = CALL_STATUS_BAD_VALUE;
-            } catch (SecurityException e) {
-                status = CALL_STATUS_PERMISSION_DENIED;
-            } catch (IOException e) {
-                status = CALL_STATUS_ERROR_IO;
-            } catch (NoDrmSchemeException e) {
-                status = CALL_STATUS_NO_DRM_SCHEME;
-            } catch (CommandSkippedException e) {
-                status = CALL_STATUS_SKIPPED;
-            } catch (Exception e) {
-                status = CALL_STATUS_ERROR_UNKNOWN;
-            }
-            mDSD = getCurrentDataSource();
-
-            if (mMediaCallType != CALL_COMPLETED_SEEK_TO) {
-                synchronized (mTaskLock) {
-                    mIsPreviousCommandSeekTo = false;
-                }
-            }
-
-            // TODO: Make native implementations asynchronous and let them send notifications.
-            if (!mNeedToWaitForEventToComplete || status != CALL_STATUS_NO_ERROR) {
-
-                sendCompleteNotification(status);
-
-                synchronized (mTaskLock) {
-                    mCurrentTask = null;
-                    processPendingTask_l();
-                }
-            }
-        }
-
-        private void sendCompleteNotification(int status) {
-            // In {@link #notifyWhenCommandLabelReached} case, a separate callback
-            // {@link #onCommandLabelReached} is already called in {@code process()}.
-            // CALL_COMPLETED_PREPARE_DRM is sent via DrmEventCallback#onDrmPrepared
-            if (mMediaCallType == CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED
-                    || mMediaCallType == CALL_COMPLETED_PREPARE_DRM) {
-                return;
-            }
-            sendEvent(new EventNotifier() {
-                @Override
-                public void notify(EventCallback callback) {
-                    callback.onCallCompleted(
-                            MediaPlayer2.this, mDSD, mMediaCallType, status);
-                }
-            });
-        }
-    };
-
-    private final class CommandSkippedException extends RuntimeException {
-        CommandSkippedException(String detailMessage) {
-            super(detailMessage);
-        }
-    };
-
-    // Modular DRM
-    final class DrmHandle {
-
-        static final int PROVISION_TIMEOUT_MS = 60000;
-
-        final DataSourceDesc mDSD;
-        final long mSrcId;
-
-        //--- guarded by |this| start
-        MediaDrm mDrmObj;
-        byte[] mDrmSessionId;
-        UUID mActiveDrmUUID;
-        boolean mDrmConfigAllowed;
-        boolean mDrmProvisioningInProgress;
-        boolean mPrepareDrmInProgress;
-        Future<?> mProvisionResult;
-        //--- guarded by |this| end
-
-        DrmHandle(DataSourceDesc dsd, long srcId) {
-            mDSD = dsd;
-            mSrcId = srcId;
-        }
-
-        void prepare(UUID uuid) throws UnsupportedSchemeException,
-                ResourceBusyException, NotProvisionedException {
-            final OnDrmConfigHelper onDrmConfigHelper = mOnDrmConfigHelper;
-            Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigHelper: " + onDrmConfigHelper);
-
-            synchronized (this) {
-                if (mActiveDrmUUID != null) {
-                    final String msg = "prepareDrm(): Wrong usage: There is already "
-                            + "an active DRM scheme with " + uuid;
-                    Log.e(TAG, msg);
-                    throw new IllegalStateException(msg);
-                }
-
-                if (mPrepareDrmInProgress) {
-                    final String msg = "prepareDrm(): Wrong usage: There is already "
-                            + "a pending prepareDrm call.";
-                    Log.e(TAG, msg);
-                    throw new IllegalStateException(msg);
-                }
-
-                if (mDrmProvisioningInProgress) {
-                    final String msg = "prepareDrm(): Unexpectd: Provisioning already in progress";
-                    Log.e(TAG, msg);
-                    throw new IllegalStateException(msg);
-                }
-
-                // shouldn't need this; just for safeguard
-                cleanDrmObj();
-
-                mPrepareDrmInProgress = true;
-
-                try {
-                    // only creating the DRM object to allow pre-openSession configuration
-                    prepareDrm_createDrmStep(uuid);
-                } catch (Exception e) {
-                    Log.w(TAG, "prepareDrm(): Exception ", e);
-                    mPrepareDrmInProgress = false;
-                    throw e;
-                }
-
-                mDrmConfigAllowed = true;
-            }  // synchronized
-
-            // call the callback outside the lock
-            if (onDrmConfigHelper != null)  {
-                onDrmConfigHelper.onDrmConfig(MediaPlayer2.this, mDSD);
-            }
-
-            synchronized (this) {
-                mDrmConfigAllowed = false;
-                boolean earlyExit = false;
-
-                try {
-                    prepareDrm_openSessionStep(uuid);
-
-                    this.mActiveDrmUUID = uuid;
-                    mPrepareDrmInProgress = false;
-                } catch (IllegalStateException e) {
-                    final String msg = "prepareDrm(): Wrong usage: The player must be "
-                            + "in the prepared state to call prepareDrm().";
-                    Log.e(TAG, msg);
-                    earlyExit = true;
-                    mPrepareDrmInProgress = false;
-                    throw new IllegalStateException(msg);
-                } catch (NotProvisionedException e) {
-                    Log.w(TAG, "prepareDrm: NotProvisionedException", e);
-                    throw e;
-                } catch (Exception e) {
-                    Log.e(TAG, "prepareDrm: Exception " + e);
-                    earlyExit = true;
-                    mPrepareDrmInProgress = false;
-                    throw e;
-                } finally {
-                    if (earlyExit) {  // clean up object if didn't succeed
-                        cleanDrmObj();
-                    }
-                }  // finally
-            }  // synchronized
-        }
-
-        void prepareDrm_createDrmStep(UUID uuid)
-                throws UnsupportedSchemeException {
-            Log.v(TAG, "prepareDrm_createDrmStep: UUID: " + uuid);
-
-            try {
-                mDrmObj = new MediaDrm(uuid);
-                Log.v(TAG, "prepareDrm_createDrmStep: Created mDrmObj=" + mDrmObj);
-            } catch (Exception e) { // UnsupportedSchemeException
-                Log.e(TAG, "prepareDrm_createDrmStep: MediaDrm failed with " + e);
-                throw e;
-            }
-        }
-
-        void prepareDrm_openSessionStep(UUID uuid)
-                throws NotProvisionedException, ResourceBusyException {
-            Log.v(TAG, "prepareDrm_openSessionStep: uuid: " + uuid);
-
-            // TODO:
-            // don't need an open session for a future specialKeyReleaseDrm mode but we should do
-            // it anyway so it raises provisioning error if needed. We'd rather handle provisioning
-            // at prepareDrm/openSession rather than getDrmKeyRequest/provideDrmKeyResponse
-            try {
-                mDrmSessionId = mDrmObj.openSession();
-                Log.v(TAG, "prepareDrm_openSessionStep: mDrmSessionId=" + mDrmSessionId);
-
-                // Sending it down to native/mediaserver to create the crypto object
-                // This call could simply fail due to bad player state, e.g., after play().
-                final MediaPlayer2 mp2 = MediaPlayer2.this;
-                mp2.native_prepareDrm(mSrcId, getByteArrayFromUUID(uuid), mDrmSessionId);
-                Log.v(TAG, "prepareDrm_openSessionStep: native_prepareDrm/Crypto succeeded");
-
-            } catch (Exception e) { //ResourceBusyException, NotProvisionedException
-                Log.e(TAG, "prepareDrm_openSessionStep: open/crypto failed with " + e);
-                throw e;
-            }
-
-        }
-
-        int handleProvisioninig(UUID uuid, long taskId) {
-            synchronized (this) {
-                if (mDrmProvisioningInProgress) {
-                    Log.e(TAG, "handleProvisioninig: Unexpected mDrmProvisioningInProgress");
-                    return PREPARE_DRM_STATUS_PREPARATION_ERROR;
-                }
-
-                MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest();
-                if (provReq == null) {
-                    Log.e(TAG, "handleProvisioninig: getProvisionRequest returned null.");
-                    return PREPARE_DRM_STATUS_PREPARATION_ERROR;
-                }
-
-                Log.v(TAG, "handleProvisioninig provReq "
-                        + " data: " + provReq.getData() + " url: " + provReq.getDefaultUrl());
-
-                // networking in a background thread
-                mDrmProvisioningInProgress = true;
-
-                mProvisionResult = mDrmThreadPool.submit(newProvisioningTask(uuid, taskId));
-
-                return PREPARE_DRM_STATUS_SUCCESS;
-            }
-        }
-
-        void provision(UUID uuid, long taskId) {
-
-            MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest();
-            String urlStr = provReq.getDefaultUrl();
-            urlStr += "&signedRequest=" + new String(provReq.getData());
-            Log.v(TAG, "handleProvisioninig: Thread is initialised url: " + urlStr);
-
-            byte[] response = null;
-            boolean provisioningSucceeded = false;
-            int status = PREPARE_DRM_STATUS_PREPARATION_ERROR;
-            try {
-                URL url = new URL(urlStr);
-                final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-                try {
-                    connection.setRequestMethod("POST");
-                    connection.setDoOutput(false);
-                    connection.setDoInput(true);
-                    connection.setConnectTimeout(PROVISION_TIMEOUT_MS);
-                    connection.setReadTimeout(PROVISION_TIMEOUT_MS);
-
-                    connection.connect();
-                    response = readInputStreamFully(connection.getInputStream());
-
-                    Log.v(TAG, "handleProvisioninig: Thread run: response " +
-                            response.length + " " + response);
-                } catch (Exception e) {
-                    status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR;
-                    Log.w(TAG, "handleProvisioninig: Thread run: connect " + e + " url: " + url);
-                } finally {
-                    connection.disconnect();
-                }
-            } catch (Exception e)   {
-                status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR;
-                Log.w(TAG, "handleProvisioninig: Thread run: openConnection " + e);
-            }
-
-            if (response != null) {
-                try {
-                    mDrmObj.provideProvisionResponse(response);
-                    Log.v(TAG, "handleProvisioninig: Thread run: " +
-                            "provideProvisionResponse SUCCEEDED!");
-
-                    provisioningSucceeded = true;
-                } catch (Exception e) {
-                    status = PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR;
-                    Log.w(TAG, "handleProvisioninig: Thread run: " +
-                            "provideProvisionResponse " + e);
-                }
-            }
-
-            boolean succeeded = false;
-
-            synchronized (this) {
-                // continuing with prepareDrm
-                if (provisioningSucceeded) {
-                    succeeded = resumePrepare(uuid);
-                    status = (succeeded) ?
-                            PREPARE_DRM_STATUS_SUCCESS :
-                            PREPARE_DRM_STATUS_PREPARATION_ERROR;
-                }
-                mDrmProvisioningInProgress = false;
-                mPrepareDrmInProgress = false;
-                if (!succeeded) {
-                    cleanDrmObj();  // cleaning up if it hasn't gone through while in the lock
-                }
-            }  // synchronized
-
-            // calling the callback outside the lock
-            final int finalStatus = status;
-            sendDrmEvent(new DrmEventNotifier() {
-                @Override
-                public void notify(DrmEventCallback callback) {
-                    callback.onDrmPrepared(
-                            MediaPlayer2.this, mDSD, finalStatus);
-                }
-            });
-
-            synchronized (mTaskLock) {
-                if (mCurrentTask != null
-                        && mCurrentTask.mTaskId == taskId
-                        && mCurrentTask.mMediaCallType == CALL_COMPLETED_PREPARE_DRM
-                        && mCurrentTask.mNeedToWaitForEventToComplete) {
-                    mCurrentTask = null;
-                    processPendingTask_l();
-                }
-            }
-        }
-
-        Runnable newProvisioningTask(UUID uuid, long taskId) {
-            return new Runnable() {
-                @Override
-                public void run() {
-                    provision(uuid, taskId);
-                }
-            };
-        }
-
-        boolean resumePrepare(UUID uuid) {
-            Log.v(TAG, "resumePrepareDrm: uuid: " + uuid);
-
-            // mDrmLock is guaranteed to be held
-            boolean success = false;
-            try {
-                // resuming
-                prepareDrm_openSessionStep(uuid);
-
-                this.mActiveDrmUUID = uuid;
-
-                success = true;
-            } catch (Exception e) {
-                Log.w(TAG, "handleProvisioninig: Thread run native_prepareDrm resume failed:" + e);
-                // mDrmObj clean up is done by the caller
-            }
-
-            return success;
-        }
-
-        void cleanDrmObj() {
-            // the caller holds mDrmLock
-            Log.v(TAG, "cleanDrmObj: mDrmObj=" + mDrmObj + " mDrmSessionId=" + mDrmSessionId);
-
-            if (mDrmSessionId != null)    {
-                mDrmObj.closeSession(mDrmSessionId);
-                mDrmSessionId = null;
-            }
-            if (mDrmObj != null) {
-                mDrmObj.close();
-                mDrmObj = null;
-            }
-        }
-
-        void release() throws NoDrmSchemeException {
-            synchronized (this) {
-                Log.v(TAG, "releaseDrm:");
-
-                if (mActiveDrmUUID == null) {
-                    Log.e(TAG, "releaseDrm(): No active DRM scheme to release.");
-                    throw new NoDrmSchemeException(
-                            "releaseDrm: No active DRM scheme to release.");
-                }
-
-                try {
-                    // we don't have the player's state in this layer. The below call raises
-                    // exception if we're in a non-stopped/prepared state.
-
-                    // for cleaning native/mediaserver crypto object
-                    native_releaseDrm(mSrcId);
-
-                    // for cleaning client-side MediaDrm object; only called if above has succeeded
-                    cleanDrmObj();
-
-                    this.mActiveDrmUUID = null;
-                } catch (IllegalStateException e) {
-                    Log.w(TAG, "releaseDrm: Exception ", e);
-                    throw new IllegalStateException(
-                            "releaseDrm: The player is not in a valid state.");
-                } catch (Exception e) {
-                    Log.e(TAG, "releaseDrm: Exception ", e);
-                }
-            }  // synchronized
-        }
-
-        void cleanup() {
-            synchronized (this) {
-                Log.v(TAG, "cleanupDrm: " +
-                        " mProvisioningTask=" + mProvisionResult +
-                        " mPrepareDrmInProgress=" + mPrepareDrmInProgress +
-                        " mActiveDrmScheme=" + mActiveDrmUUID);
-
-                if (mProvisionResult != null) {
-                    // timeout; relying on HttpUrlConnection
-                    try {
-                        mProvisionResult.get();
-                    }
-                    catch (InterruptedException | ExecutionException e) {
-                        Log.w(TAG, "resetDrmState: ProvThread.join Exception " + e);
-                    }
-                }
-
-                // set to false to avoid duplicate release calls
-                this.mActiveDrmUUID = null;
-
-                cleanDrmObj();
-            }   // synchronized
-        }
-
-        Runnable newCleanupTask() {
-            return new Runnable() {
-                @Override
-                public void run() {
-                    cleanup();
-                }
-            };
-        }
-
-        MediaDrm.KeyRequest getDrmKeyRequest(
-                byte[] keySetId, byte[] initData,
-                String mimeType, int keyType,
-                Map<String, String> optionalParameters)
-                throws NoDrmSchemeException {
-            synchronized (this) {
-                if (mActiveDrmUUID == null) {
-                    Log.e(TAG, "getDrmKeyRequest NoDrmSchemeException");
-                    throw new NoDrmSchemeException(
-                            "getDrmKeyRequest: Has to set a DRM scheme first.");
-                }
-
-                try {
-                    byte[] scope = (keyType != MediaDrm.KEY_TYPE_RELEASE) ?
-                            mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE
-                            keySetId;                  // keySetId for KEY_TYPE_RELEASE
-
-                    HashMap<String, String> hmapOptionalParameters =
-                            (optionalParameters != null)
-                            ? new HashMap<String, String>(optionalParameters)
-                            : null;
-
-                    MediaDrm.KeyRequest request = mDrmObj.getKeyRequest(
-                            scope, initData, mimeType, keyType, hmapOptionalParameters);
-                    Log.v(TAG, "getDrmKeyRequest:   --> request: " + request);
-
-                    return request;
-
-                } catch (NotProvisionedException e) {
-                    Log.w(TAG, "getDrmKeyRequest NotProvisionedException: " +
-                            "Unexpected. Shouldn't have reached here.");
-                    throw new IllegalStateException("getDrmKeyRequest: provisioning error.");
-                } catch (Exception e) {
-                    Log.w(TAG, "getDrmKeyRequest Exception " + e);
-                    throw e;
-                }
-
-            }
-        }
-
-        byte[] provideDrmKeyResponse(byte[] keySetId, byte[] response)
-                throws NoDrmSchemeException, DeniedByServerException {
-            synchronized (this) {
-
-                if (mActiveDrmUUID == null) {
-                    Log.e(TAG, "getDrmKeyRequest NoDrmSchemeException");
-                    throw new NoDrmSchemeException(
-                            "getDrmKeyRequest: Has to set a DRM scheme first.");
-                }
-
-                try {
-                    byte[] scope = (keySetId == null) ?
-                                    mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE
-                                    keySetId;                  // keySetId for KEY_TYPE_RELEASE
-
-                    byte[] keySetResult = mDrmObj.provideKeyResponse(scope, response);
-
-                    Log.v(TAG, "provideDrmKeyResponse: keySetId: " + keySetId
-                            + " response: " + response + " --> " + keySetResult);
-
-
-                    return keySetResult;
-
-                } catch (NotProvisionedException e) {
-                    Log.w(TAG, "provideDrmKeyResponse NotProvisionedException: " +
-                            "Unexpected. Shouldn't have reached here.");
-                    throw new IllegalStateException("provideDrmKeyResponse: " +
-                            "Unexpected provisioning error.");
-                } catch (Exception e) {
-                    Log.w(TAG, "provideDrmKeyResponse Exception " + e);
-                    throw e;
-                }
-            }
-        }
-
-        void restoreDrmKeys(byte[] keySetId)
-                throws NoDrmSchemeException {
-            synchronized (this) {
-                if (mActiveDrmUUID == null) {
-                    Log.w(TAG, "restoreDrmKeys NoDrmSchemeException");
-                    throw new NoDrmSchemeException(
-                            "restoreDrmKeys: Has to set a DRM scheme first.");
-                }
-
-                try {
-                    mDrmObj.restoreKeys(mDrmSessionId, keySetId);
-                } catch (Exception e) {
-                    Log.w(TAG, "restoreKeys Exception " + e);
-                    throw e;
-                }
-            }
-        }
-
-        String getDrmPropertyString(String propertyName)
-                throws NoDrmSchemeException {
-            String v;
-            synchronized (this) {
-
-                if (mActiveDrmUUID == null && !mDrmConfigAllowed) {
-                    Log.w(TAG, "getDrmPropertyString NoDrmSchemeException");
-                    throw new NoDrmSchemeException(
-                            "getDrmPropertyString: Has to prepareDrm() first.");
-                }
-
-                try {
-                    v = mDrmObj.getPropertyString(propertyName);
-                } catch (Exception e) {
-                    Log.w(TAG, "getDrmPropertyString Exception " + e);
-                    throw e;
-                }
-            }   // synchronized
-
-            Log.v(TAG, "getDrmPropertyString: propertyName: " + propertyName + " --> value: " + v);
-
-            return v;
-        }
-
-        void setDrmPropertyString(String propertyName, String value)
-                throws NoDrmSchemeException {
-            synchronized (this) {
-
-                if ( mActiveDrmUUID == null && !mDrmConfigAllowed ) {
-                    Log.w(TAG, "setDrmPropertyString NoDrmSchemeException");
-                    throw new NoDrmSchemeException(
-                            "setDrmPropertyString: Has to prepareDrm() first.");
-                }
-
-                try {
-                    mDrmObj.setPropertyString(propertyName, value);
-                } catch ( Exception e ) {
-                    Log.w(TAG, "setDrmPropertyString Exception " + e);
-                    throw e;
-                }
-            }
-        }
-
-    }
-
-    final class SourceInfo {
-        final DataSourceDesc mDSD;
-        final long mId = mSrcIdGenerator.getAndIncrement();
-        AtomicInteger mBufferedPercentage = new AtomicInteger(0);
-        boolean mClosed = false;
-
-        // m*AsNextSource (below) only applies to pending data sources in the playlist;
-        // the meanings of mCurrentSourceInfo.{mStateAsNextSource,mPlayPendingAsNextSource}
-        // are undefined.
-        int mStateAsNextSource = NEXT_SOURCE_STATE_INIT;
-        boolean mPlayPendingAsNextSource = false;
-
-        // Modular DRM
-        final DrmHandle mDrmHandle;
-        DrmInfo mDrmInfo;
-        boolean mDrmInfoResolved;
-
-        SourceInfo(DataSourceDesc dsd) {
-            this.mDSD = dsd;
-            mDrmHandle = new DrmHandle(dsd, mId);
-        }
-
-        void close() {
-            synchronized (this) {
-                if (!mClosed) {
-                    if (mDSD != null) {
-                        mDSD.close();
-                    }
-                    mClosed = true;
-                }
-            }
-        }
-
-        @Override
-        public String toString() {
-            return String.format("%s(%d)", SourceInfo.class.getName(), mId);
-        }
-
-    }
-
-    private SourceInfo getSourceInfo(long srcId) {
-        synchronized (mSrcLock) {
-            if (isCurrentSource(srcId)) {
-                return mCurrentSourceInfo;
-            }
-            if (isNextSource(srcId)) {
-                return mNextSourceInfos.peek();
-            }
-        }
-        return null;
-    }
-
-    private SourceInfo getSourceInfo(DataSourceDesc dsd) {
-        synchronized (mSrcLock) {
-            if (isCurrentSource(dsd)) {
-                return mCurrentSourceInfo;
-            }
-            if (isNextSource(dsd)) {
-                return mNextSourceInfos.peek();
-            }
-        }
-        return null;
-    }
-
-    private boolean isCurrentSource(long srcId) {
-        synchronized (mSrcLock) {
-            return mCurrentSourceInfo != null && mCurrentSourceInfo.mId == srcId;
-        }
-    }
-
-    private boolean isCurrentSource(DataSourceDesc dsd) {
-        synchronized (mSrcLock) {
-            return mCurrentSourceInfo != null && mCurrentSourceInfo.mDSD == dsd;
-        }
-    }
-
-    private boolean isNextSource(long srcId) {
-        SourceInfo nextSourceInfo = mNextSourceInfos.peek();
-        return nextSourceInfo != null && nextSourceInfo.mId == srcId;
-    }
-
-    private boolean isNextSource(DataSourceDesc dsd) {
-        SourceInfo nextSourceInfo = mNextSourceInfos.peek();
-        return nextSourceInfo != null && nextSourceInfo.mDSD == dsd;
-    }
-
-    @GuardedBy("mSrcLock")
-    private void setCurrentSourceInfo_l(SourceInfo sourceInfo) {
-        cleanupSourceInfo(mCurrentSourceInfo);
-        mCurrentSourceInfo = sourceInfo;
-    }
-
-    @GuardedBy("mSrcLock")
-    private void clearNextSourceInfos_l() {
-        while (!mNextSourceInfos.isEmpty()) {
-            cleanupSourceInfo(mNextSourceInfos.poll());
-        }
-    }
-
-    private void cleanupSourceInfo(SourceInfo sourceInfo) {
-        if (sourceInfo != null) {
-            sourceInfo.close();
-            Runnable task = sourceInfo.mDrmHandle.newCleanupTask();
-            mDrmThreadPool.submit(task);
-        }
-    }
-
-    private void clearSourceInfos() {
-        synchronized (mSrcLock) {
-            setCurrentSourceInfo_l(null);
-            clearNextSourceInfos_l();
-        }
-    }
-
-    public static final class MetricsConstants {
-        private MetricsConstants() {}
-
-        /**
-         * Key to extract the MIME type of the video track
-         * from the {@link MediaPlayer2#getMetrics} return value.
-         * The value is a String.
-         */
-        public static final String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime";
-
-        /**
-         * Key to extract the codec being used to decode the video track
-         * from the {@link MediaPlayer2#getMetrics} return value.
-         * The value is a String.
-         */
-        public static final String CODEC_VIDEO = "android.media.mediaplayer.video.codec";
-
-        /**
-         * Key to extract the width (in pixels) of the video track
-         * from the {@link MediaPlayer2#getMetrics} return value.
-         * The value is an integer.
-         */
-        public static final String WIDTH = "android.media.mediaplayer.width";
-
-        /**
-         * Key to extract the height (in pixels) of the video track
-         * from the {@link MediaPlayer2#getMetrics} return value.
-         * The value is an integer.
-         */
-        public static final String HEIGHT = "android.media.mediaplayer.height";
-
-        /**
-         * Key to extract the count of video frames played
-         * from the {@link MediaPlayer2#getMetrics} return value.
-         * The value is an integer.
-         */
-        public static final String FRAMES = "android.media.mediaplayer.frames";
-
-        /**
-         * Key to extract the count of video frames dropped
-         * from the {@link MediaPlayer2#getMetrics} return value.
-         * The value is an integer.
-         */
-        public static final String FRAMES_DROPPED = "android.media.mediaplayer.dropped";
-
-        /**
-         * Key to extract the MIME type of the audio track
-         * from the {@link MediaPlayer2#getMetrics} return value.
-         * The value is a String.
-         */
-        public static final String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime";
-
-        /**
-         * Key to extract the codec being used to decode the audio track
-         * from the {@link MediaPlayer2#getMetrics} return value.
-         * The value is a String.
-         */
-        public static final String CODEC_AUDIO = "android.media.mediaplayer.audio.codec";
-
-        /**
-         * Key to extract the duration (in milliseconds) of the
-         * media being played
-         * from the {@link MediaPlayer2#getMetrics} return value.
-         * The value is a long.
-         */
-        public static final String DURATION = "android.media.mediaplayer.durationMs";
-
-        /**
-         * Key to extract the playing time (in milliseconds) of the
-         * media being played
-         * from the {@link MediaPlayer2#getMetrics} return value.
-         * The value is a long.
-         */
-        public static final String PLAYING = "android.media.mediaplayer.playingMs";
-
-        /**
-         * Key to extract the count of errors encountered while
-         * playing the media
-         * from the {@link MediaPlayer2#getMetrics} return value.
-         * The value is an integer.
-         */
-        public static final String ERRORS = "android.media.mediaplayer.err";
-
-        /**
-         * Key to extract an (optional) error code detected while
-         * playing the media
-         * from the {@link MediaPlayer2#getMetrics} return value.
-         * The value is an integer.
-         */
-        public static final String ERROR_CODE = "android.media.mediaplayer.errcode";
-
-    }
-
-    private void keepAudioSessionIdAlive(int sessionId) {
-        synchronized (mSessionIdLock) {
-            if (mDummyAudioTrack != null) {
-                if (mDummyAudioTrack.getAudioSessionId() == sessionId) {
-                    return;
-                }
-                mDummyAudioTrack.release();
-            }
-            // TODO: parameters can be optimized
-            mDummyAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
-                    AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, 2,
-                    AudioTrack.MODE_STATIC, sessionId);
-        }
-    }
-
-    private void keepAudioSessionIdAlive(AudioTrack at) {
-        synchronized (mSessionIdLock) {
-            if (mDummyAudioTrack != null) {
-                if (mDummyAudioTrack.getAudioSessionId() == at.getAudioSessionId()) {
-                    at.release();
-                    return;
-                }
-                mDummyAudioTrack.release();
-            }
-            mDummyAudioTrack = at;
-        }
-    }
-}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index b160029..1304afe 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -302,6 +302,34 @@
          *  {@link #DEFAULT} otherwise. */
         public static final int UNPROCESSED = 9;
 
+
+        /**
+         * Source for capturing audio meant to be processed in real time and played back for live
+         * performance (e.g karaoke).
+         * <p>
+         * The capture path will minimize latency and coupling with
+         * playback path.
+         * </p>
+         */
+        public static final int VOICE_PERFORMANCE = 10;
+
+        /**
+         * Source for an echo canceller to capture the reference signal to be cancelled.
+         * <p>
+         * The echo reference signal will be captured as close as possible to the DAC in order
+         * to include all post processing applied to the playback path.
+         * </p><p>
+         * Capturing the echo reference requires the
+         * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
+         * This permission is reserved for use by system components and is not available to
+         * third-party applications.
+         * </p>
+         * @hide
+         */
+        @SystemApi
+        @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)
+        public static final int ECHO_REFERENCE = 1997;
+
         /**
          * Audio source for capturing broadcast radio tuner output.
          * @hide
@@ -343,6 +371,7 @@
         case AudioSource.VOICE_COMMUNICATION:
         //case REMOTE_SUBMIX:  considered "system" as it requires system permissions
         case AudioSource.UNPROCESSED:
+        case AudioSource.VOICE_PERFORMANCE:
             return false;
         default:
             return true;
@@ -372,6 +401,10 @@
             return "REMOTE_SUBMIX";
         case AudioSource.UNPROCESSED:
             return "UNPROCESSED";
+        case AudioSource.ECHO_REFERENCE:
+            return "ECHO_REFERENCE";
+        case AudioSource.VOICE_PERFORMANCE:
+            return "VOICE_PERFORMANCE";
         case AudioSource.RADIO_TUNER:
             return "RADIO_TUNER";
         case AudioSource.HOTWORD:
@@ -456,6 +489,9 @@
         /** VP8/VORBIS data in a WEBM container */
         public static final int WEBM = 9;
 
+        /** @hide HEIC data in a HEIF container */
+        public static final int HEIF = 10;
+
         /** Opus data in a Ogg container */
         public static final int OGG = 11;
     };
@@ -521,7 +557,7 @@
      * @see android.media.MediaRecorder.AudioSource
      */
     public static final int getAudioSourceMax() {
-        return AudioSource.UNPROCESSED;
+        return AudioSource.VOICE_PERFORMANCE;
     }
 
     /**
@@ -699,6 +735,12 @@
      * is no guarantee that the recorder will have stopped by the time the
      * listener is notified.
      *
+     * <p>When using MPEG-4 container ({@link #setOutputFormat(int)} with
+     * {@link OutputFormat#MPEG_4}), it is recommended to set maximum duration that fits the use
+     * case. Setting a larger than required duration may result in a larger than needed output file
+     * because of space reserved for MOOV box expecting large movie data in this recording session.
+     *  Unused space of MOOV box is turned into FREE box in the output file.</p>
+     *
      * @param max_duration_ms the maximum duration in ms (if zero or negative, disables the duration limit)
      *
      */
@@ -714,6 +756,12 @@
      * is no guarantee that the recorder will have stopped by the time the
      * listener is notified.
      *
+     * <p>When using MPEG-4 container ({@link #setOutputFormat(int)} with
+     * {@link OutputFormat#MPEG_4}), it is recommended to set maximum filesize that fits the use
+     * case. Setting a larger than required filesize may result in a larger than needed output file
+     * because of space reserved for MOOV box expecting large movie data in this recording session.
+     * Unused space of MOOV box is turned into FREE box in the output file.</p>
+     *
      * @param max_filesize_bytes the maximum filesize in bytes (if zero or negative, disables the limit)
      *
      */
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 90cfc53..4eed12f 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -902,6 +902,7 @@
             map.put(MediaStore.MediaColumns.SIZE, mFileSize);
             map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType);
             map.put(MediaStore.MediaColumns.IS_DRM, mIsDrm);
+            map.putNull(MediaStore.MediaColumns.HASH);
 
             String resolution = null;
             if (mWidth > 0 && mHeight > 0) {
@@ -934,7 +935,7 @@
                     }
                 } else if (MediaFile.isImageMimeType(mMimeType)) {
                     // FIXME - add DESCRIPTION
-                } else if (mScanSuccess && MediaFile.isAudioMimeType(mMimeType)) {
+                } else if (MediaFile.isAudioMimeType(mMimeType)) {
                     map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0) ?
                             mArtist : MediaStore.UNKNOWN_STRING);
                     map.put(Audio.Media.ALBUM_ARTIST, (mAlbumArtist != null &&
@@ -950,10 +951,6 @@
                     map.put(Audio.Media.DURATION, mDuration);
                     map.put(Audio.Media.COMPILATION, mCompilation);
                 }
-                if (!mScanSuccess) {
-                    // force mediaprovider to not determine the media type from the mime type
-                    map.put(Files.FileColumns.MEDIA_TYPE, 0);
-                }
             }
             return map;
         }
@@ -1056,7 +1053,7 @@
             Uri tableUri = mFilesUri;
             int mediaType = FileColumns.MEDIA_TYPE_NONE;
             MediaInserter inserter = mMediaInserter;
-            if (mScanSuccess && !mNoMedia) {
+            if (!mNoMedia) {
                 if (MediaFile.isVideoMimeType(mMimeType)) {
                     tableUri = mVideoUri;
                     mediaType = FileColumns.MEDIA_TYPE_VIDEO;
@@ -1131,7 +1128,7 @@
                 // with squashed lower case paths
                 values.remove(MediaStore.MediaColumns.DATA);
 
-                if (mScanSuccess && !mNoMedia) {
+                if (!mNoMedia) {
                     // Changing media type must be done as separate update
                     if (mediaType != entry.mMediaType) {
                         final ContentValues mediaTypeValues = new ContentValues();
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
deleted file mode 100644
index b874ba46..0000000
--- a/media/java/android/media/MediaSession2.java
+++ /dev/null
@@ -1,704 +0,0 @@
-/*
- * 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.media;
-
-import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS;
-import static android.media.MediaConstants.KEY_PACKAGE_NAME;
-import static android.media.MediaConstants.KEY_PID;
-import static android.media.MediaConstants.KEY_SESSION2_STUB;
-import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
-import static android.media.Session2Command.RESULT_INFO_SKIPPED;
-import static android.media.Session2Token.TYPE_SESSION;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.media.session.MediaSessionManager;
-import android.media.session.MediaSessionManager.RemoteUserInfo;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Process;
-import android.os.ResultReceiver;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-
-/**
- * Allows a media app to expose its transport controls and playback information in a process to
- * other processes including the Android framework and other apps.
- * <p>
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
- * @hide
- */
-public class MediaSession2 implements AutoCloseable {
-    static final String TAG = "MediaSession";
-    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    // Note: This checks the uniqueness of a session ID only in a single process.
-    // When the framework becomes able to check the uniqueness, this logic should be removed.
-    //@GuardedBy("MediaSession.class")
-    private static final List<String> SESSION_ID_LIST = new ArrayList<>();
-
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final Object mLock = new Object();
-    //@GuardedBy("mLock")
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final Map<Controller2Link, ControllerInfo> mConnectedControllers = new HashMap<>();
-
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final Context mContext;
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final Executor mCallbackExecutor;
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final SessionCallback mCallback;
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final Session2Link mSessionStub;
-
-    private final String mSessionId;
-    private final PendingIntent mSessionActivity;
-    private final Session2Token mSessionToken;
-    private final MediaSessionManager mSessionManager;
-    private final Handler mResultHandler;
-
-    //@GuardedBy("mLock")
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    private boolean mClosed;
-
-    MediaSession2(@NonNull Context context, @NonNull String id, PendingIntent sessionActivity,
-            @NonNull Executor callbackExecutor, @NonNull SessionCallback callback) {
-        synchronized (MediaSession2.class) {
-            if (SESSION_ID_LIST.contains(id)) {
-                throw new IllegalStateException("Session ID must be unique. ID=" + id);
-            }
-            SESSION_ID_LIST.add(id);
-        }
-
-        mContext = context;
-        mSessionId = id;
-        mSessionActivity = sessionActivity;
-        mCallbackExecutor = callbackExecutor;
-        mCallback = callback;
-        mSessionStub = new Session2Link(this);
-        mSessionToken = new Session2Token(Process.myUid(), TYPE_SESSION, context.getPackageName(),
-                mSessionStub);
-        mSessionManager = (MediaSessionManager) mContext.getSystemService(
-                Context.MEDIA_SESSION_SERVICE);
-        // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
-        mResultHandler = new Handler(context.getMainLooper());
-    }
-
-    @Override
-    public void close() {
-        try {
-            synchronized (MediaSession2.class) {
-                SESSION_ID_LIST.remove(mSessionId);
-            }
-            Collection<ControllerInfo> controllerInfos;
-            synchronized (mLock) {
-                controllerInfos = mConnectedControllers.values();
-                mConnectedControllers.clear();
-                mClosed = true;
-            }
-            for (ControllerInfo info : controllerInfos) {
-                info.notifyDisconnected();
-            }
-        } catch (Exception e) {
-            // Should not be here.
-        }
-    }
-
-    /**
-     * Returns the session ID
-     */
-    @NonNull
-    public String getSessionId() {
-        return mSessionId;
-    }
-
-    /**
-     * Returns the {@link Session2Token} for creating {@link MediaController2}.
-     */
-    @NonNull
-    public Session2Token getSessionToken() {
-        return mSessionToken;
-    }
-
-    /**
-     * Broadcasts a session command to all the connected controllers
-     * <p>
-     * @param command the session command
-     * @param args optional arguments
-     */
-    public void broadcastSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-        Collection<ControllerInfo> controllerInfos;
-        synchronized (mLock) {
-            controllerInfos = mConnectedControllers.values();
-        }
-        for (ControllerInfo controller : controllerInfos) {
-            controller.sendSessionCommand(command, args, null);
-        }
-    }
-
-    /**
-     * Sends a session command to a specific controller
-     * <p>
-     * @param controller the controller to get the session command
-     * @param command the session command
-     * @param args optional arguments
-     * @return a token which will be sent together in {@link SessionCallback#onCommandResult}
-     *     when its result is received.
-     */
-    public Object sendSessionCommand(@NonNull ControllerInfo controller,
-            @NonNull Session2Command command, @Nullable Bundle args) {
-        if (controller == null) {
-            throw new IllegalArgumentException("controller shouldn't be null");
-        }
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-        ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) {
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                controller.receiveCommandResult(this);
-                mCallbackExecutor.execute(() -> {
-                    mCallback.onCommandResult(MediaSession2.this, controller, this,
-                            command, new Session2Command.Result(resultCode, resultData));
-                });
-            }
-        };
-        controller.sendSessionCommand(command, args, resultReceiver);
-        return resultReceiver;
-    }
-
-    /**
-     * Cancels the session command previously sent.
-     *
-     * @param controller the controller to get the session command
-     * @param token the token which is returned from {@link #sendSessionCommand}.
-     */
-    public void cancelSessionCommand(ControllerInfo controller, Object token) {
-        if (token == null) {
-            throw new IllegalArgumentException("token shouldn't be null");
-        }
-        controller.cancelSessionCommand(token);
-    }
-
-    boolean isClosed() {
-        synchronized (mLock) {
-            return mClosed;
-        }
-    }
-
-    // Called by Session2Link.onConnect
-    void onConnect(final Controller2Link controller, int seq, Bundle connectionRequest) {
-        if (controller == null || connectionRequest == null) {
-            return;
-        }
-        final int uid = Binder.getCallingUid();
-        final int callingPid = Binder.getCallingPid();
-        final long token = Binder.clearCallingIdentity();
-        // Binder.getCallingPid() can be 0 for an oneway call from the remote process.
-        // If it's the case, use PID from the ConnectionRequest.
-        final int pid = (callingPid != 0) ? callingPid : connectionRequest.getInt(KEY_PID);
-        final String pkg = connectionRequest.getString(KEY_PACKAGE_NAME);
-        try {
-            RemoteUserInfo remoteUserInfo = new RemoteUserInfo(pkg, pid, uid);
-            final ControllerInfo controllerInfo = new ControllerInfo(remoteUserInfo,
-                    mSessionManager.isTrustedForMediaControl(remoteUserInfo), controller);
-            mCallbackExecutor.execute(() -> {
-                if (isClosed()) {
-                    return;
-                }
-                controllerInfo.mAllowedCommands =
-                        mCallback.onConnect(MediaSession2.this, controllerInfo);
-                // Don't reject connection for the request from trusted app.
-                // Otherwise server will fail to retrieve session's information to dispatch
-                // media keys to.
-                boolean accept =
-                        controllerInfo.mAllowedCommands != null || controllerInfo.isTrusted();
-                if (accept) {
-                    if (controllerInfo.mAllowedCommands == null) {
-                        // For trusted apps, send non-null allowed commands to keep
-                        // connection.
-                        controllerInfo.mAllowedCommands = new Session2CommandGroup();
-                    }
-                    if (DEBUG) {
-                        Log.d(TAG, "Accepting connection: " + controllerInfo);
-                    }
-                    synchronized (mLock) {
-                        if (mConnectedControllers.containsKey(controller)) {
-                            Log.w(TAG, "Controller " + controllerInfo + " has sent connection"
-                                    + " request multiple times");
-                        }
-                        mConnectedControllers.put(controller, controllerInfo);
-                    }
-                    // If connection is accepted, notify the current state to the controller.
-                    // It's needed because we cannot call synchronous calls between
-                    // session/controller.
-                    Bundle connectionResult = new Bundle();
-                    connectionResult.putParcelable(KEY_SESSION2_STUB, mSessionStub);
-                    connectionResult.putParcelable(KEY_ALLOWED_COMMANDS,
-                            controllerInfo.mAllowedCommands);
-
-                    // Double check if session is still there, because close() can be called in
-                    // another thread.
-                    if (isClosed()) {
-                        return;
-                    }
-                    controllerInfo.notifyConnected(connectionResult);
-                } else {
-                    if (DEBUG) {
-                        Log.d(TAG, "Rejecting connection, controllerInfo=" + controllerInfo);
-                    }
-                    controllerInfo.notifyDisconnected();
-                }
-            });
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    // Called by Session2Link.onDisconnect
-    void onDisconnect(final Controller2Link controller, int seq) {
-        if (controller == null) {
-            return;
-        }
-        final ControllerInfo controllerInfo;
-        synchronized (mLock) {
-            controllerInfo = mConnectedControllers.get(controller);
-        }
-        if (controllerInfo == null) {
-            return;
-        }
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            mCallbackExecutor.execute(() -> {
-                mCallback.onDisconnected(MediaSession2.this, controllerInfo);
-            });
-            mConnectedControllers.remove(controller);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    // Called by Session2Link.onSessionCommand
-    void onSessionCommand(final Controller2Link controller, final int seq,
-            final Session2Command command, final Bundle args,
-            @Nullable ResultReceiver resultReceiver) {
-        if (controller == null) {
-            return;
-        }
-        final ControllerInfo controllerInfo;
-        synchronized (mLock) {
-            controllerInfo = mConnectedControllers.get(controller);
-        }
-        if (controllerInfo == null) {
-            return;
-        }
-
-        // TODO: check allowed commands.
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                controllerInfo.addRequestedCommandSeqNumber(seq);
-            }
-
-            mCallbackExecutor.execute(() -> {
-                if (!controllerInfo.removeRequestedCommandSeqNumber(seq)) {
-                    resultReceiver.send(RESULT_INFO_SKIPPED, null);
-                    return;
-                }
-                Session2Command.Result result = mCallback.onSessionCommand(
-                        MediaSession2.this, controllerInfo, command, args);
-                if (resultReceiver != null) {
-                    if (result == null) {
-                        throw new RuntimeException("onSessionCommand shouldn't return null");
-                    } else {
-                        resultReceiver.send(result.getResultCode(), result.getResultData());
-                    }
-                }
-            });
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    // Called by Session2Link.onCancelCommand
-    void onCancelCommand(final Controller2Link controller, final int seq) {
-        final ControllerInfo controllerInfo;
-        synchronized (mLock) {
-            controllerInfo = mConnectedControllers.get(controller);
-        }
-        if (controllerInfo == null) {
-            return;
-        }
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            controllerInfo.removeRequestedCommandSeqNumber(seq);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    /**
-     * Builder for {@link MediaSession2}.
-     * <p>
-     * Any incoming event from the {@link MediaController2} will be handled on the callback
-     * executor. If it's not set, {@link Context#getMainExecutor()} will be used by default.
-     */
-    public static final class Builder {
-        private Context mContext;
-        private String mId;
-        private PendingIntent mSessionActivity;
-        private Executor mCallbackExecutor;
-        private SessionCallback mCallback;
-
-        /**
-         * Creates a builder for {@link MediaSession2}.
-         *
-         * @param context Context
-         * @throws IllegalArgumentException if context is {@code null}.
-         */
-        public Builder(@NonNull Context context) {
-            if (context == null) {
-                throw new IllegalArgumentException("context shouldn't be null");
-            }
-            mContext = context;
-        }
-
-        /**
-         * Set an intent for launching UI for this Session. This can be used as a
-         * quick link to an ongoing media screen. The intent should be for an
-         * activity that may be started using {@link Context#startActivity(Intent)}.
-         *
-         * @param pi The intent to launch to show UI for this session.
-         * @return The Builder to allow chaining
-         */
-        @NonNull
-        public Builder setSessionActivity(@Nullable PendingIntent pi) {
-            mSessionActivity = pi;
-            return this;
-        }
-
-        /**
-         * Set ID of the session. If it's not set, an empty string will be used to create a session.
-         * <p>
-         * Use this if and only if your app supports multiple playback at the same time and also
-         * wants to provide external apps to have finer controls of them.
-         *
-         * @param id id of the session. Must be unique per package.
-         * @throws IllegalArgumentException if id is {@code null}.
-         * @return The Builder to allow chaining
-         */
-        @NonNull
-        public Builder setId(@NonNull String id) {
-            if (id == null) {
-                throw new IllegalArgumentException("id shouldn't be null");
-            }
-            mId = id;
-            return this;
-        }
-
-        /**
-         * Set callback for the session and its executor.
-         *
-         * @param executor callback executor
-         * @param callback session callback.
-         * @return The Builder to allow chaining
-         */
-        @NonNull
-        public Builder setSessionCallback(@NonNull Executor executor,
-                @NonNull SessionCallback callback) {
-            mCallbackExecutor = executor;
-            mCallback = callback;
-            return this;
-        }
-
-        /**
-         * Build {@link MediaSession2}.
-         *
-         * @return a new session
-         * @throws IllegalStateException if the session with the same id is already exists for the
-         *      package.
-         */
-        @NonNull
-        public MediaSession2 build() {
-            if (mCallbackExecutor == null) {
-                mCallbackExecutor = mContext.getMainExecutor();
-            }
-            if (mCallback == null) {
-                mCallback = new SessionCallback() {};
-            }
-            if (mId == null) {
-                mId = "";
-            }
-            return new MediaSession2(mContext, mId, mSessionActivity, mCallbackExecutor, mCallback);
-        }
-    }
-
-    /**
-     * Information of a controller.
-     * <p>
-     * This API is not generally intended for third party application developers.
-     */
-    public static final class ControllerInfo {
-        private final RemoteUserInfo mRemoteUserInfo;
-        private final boolean mIsTrusted;
-        private final Controller2Link mControllerBinder;
-        private final Object mLock = new Object();
-        //@GuardedBy("mLock")
-        private int mNextSeqNumber;
-        //@GuardedBy("mLock")
-        private ArrayMap<ResultReceiver, Integer> mPendingCommands;
-        //@GuardedBy("mLock")
-        private ArraySet<Integer> mRequestedCommandSeqNumbers;
-
-        @SuppressWarnings("WeakerAccess") /* synthetic access */
-        Session2CommandGroup mAllowedCommands;
-
-        /**
-         * @param remoteUserInfo remote user info
-         * @param trusted {@code true} if trusted, {@code false} otherwise
-         * @param controllerBinder Controller2Link for the connected controller.
-         */
-        ControllerInfo(@NonNull RemoteUserInfo remoteUserInfo, boolean trusted,
-                @Nullable Controller2Link controllerBinder) {
-            mRemoteUserInfo = remoteUserInfo;
-            mIsTrusted = trusted;
-            mControllerBinder = controllerBinder;
-            mPendingCommands = new ArrayMap<>();
-            mRequestedCommandSeqNumbers = new ArraySet<>();
-        }
-
-        /**
-         * @return remote user info of the controller.
-         */
-        @NonNull
-        public RemoteUserInfo getRemoteUserInfo() {
-            return mRemoteUserInfo;
-        }
-
-        /**
-         * @return package name of the controller.
-         */
-        @NonNull
-        public String getPackageName() {
-            return mRemoteUserInfo.getPackageName();
-        }
-
-        /**
-         * @return uid of the controller. Can be a negative value if the uid cannot be obtained.
-         */
-        public int getUid() {
-            return mRemoteUserInfo.getUid();
-        }
-
-        /**
-         * Return if the controller has granted {@code android.permission.MEDIA_CONTENT_CONTROL} or
-         * has a enabled notification listener so can be trusted to accept connection and incoming
-         * command request.
-         *
-         * @return {@code true} if the controller is trusted.
-         * @hide
-         */
-        public boolean isTrusted() {
-            return mIsTrusted;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(mControllerBinder, mRemoteUserInfo);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof ControllerInfo)) return false;
-            if (this == obj) return true;
-
-            ControllerInfo other = (ControllerInfo) obj;
-            if (mControllerBinder != null || other.mControllerBinder != null) {
-                return Objects.equals(mControllerBinder, other.mControllerBinder);
-            }
-            return mRemoteUserInfo.equals(other.mRemoteUserInfo);
-        }
-
-        @Override
-        public String toString() {
-            return "ControllerInfo {pkg=" + mRemoteUserInfo.getPackageName() + ", uid="
-                    + mRemoteUserInfo.getUid() + ", allowedCommands=" + mAllowedCommands + "})";
-        }
-
-        void notifyConnected(Bundle connectionResult) {
-            if (mControllerBinder == null) return;
-
-            try {
-                mControllerBinder.notifyConnected(getNextSeqNumber(), connectionResult);
-            } catch (RuntimeException e) {
-                // Controller may be died prematurely.
-            }
-        }
-
-        void notifyDisconnected() {
-            if (mControllerBinder == null) return;
-
-            try {
-                mControllerBinder.notifyDisconnected(getNextSeqNumber());
-            } catch (RuntimeException e) {
-                // Controller may be died prematurely.
-            }
-        }
-
-        void sendSessionCommand(Session2Command command, Bundle args,
-                ResultReceiver resultReceiver) {
-            if (mControllerBinder == null) return;
-
-            try {
-                int seq = getNextSeqNumber();
-                synchronized (mLock) {
-                    mPendingCommands.put(resultReceiver, seq);
-                }
-                mControllerBinder.sendSessionCommand(seq, command, args, resultReceiver);
-            } catch (RuntimeException e) {
-                // Controller may be died prematurely.
-                synchronized (mLock) {
-                    mPendingCommands.remove(resultReceiver);
-                }
-                resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null);
-            }
-        }
-
-        void cancelSessionCommand(@NonNull Object token) {
-            if (mControllerBinder == null) return;
-            Integer seq;
-            synchronized (mLock) {
-                seq = mPendingCommands.remove(token);
-            }
-            if (seq != null) {
-                mControllerBinder.cancelSessionCommand(seq);
-            }
-        }
-
-        void receiveCommandResult(ResultReceiver resultReceiver) {
-            synchronized (mLock) {
-                mPendingCommands.remove(resultReceiver);
-            }
-        }
-
-        void addRequestedCommandSeqNumber(int seq) {
-            synchronized (mLock) {
-                mRequestedCommandSeqNumbers.add(seq);
-            }
-        }
-
-        boolean removeRequestedCommandSeqNumber(int seq) {
-            synchronized (mLock) {
-                return mRequestedCommandSeqNumbers.remove(seq);
-            }
-        }
-
-        private int getNextSeqNumber() {
-            synchronized (mLock) {
-                return mNextSeqNumber++;
-            }
-        }
-    }
-
-    /**
-     * Callback to be called for all incoming commands from {@link MediaController2}s.
-     * <p>
-     * This API is not generally intended for third party application developers.
-     */
-    public abstract static class SessionCallback {
-        /**
-         * Called when a controller is created for this session. Return allowed commands for
-         * controller. By default it allows all connection requests and commands.
-         * <p>
-         * You can reject the connection by returning {@code null}. In that case, controller
-         * receives {@link MediaController2.ControllerCallback#onDisconnected(MediaController2)}
-         * and cannot be used.
-         *
-         * @param session the session for this event
-         * @param controller controller information.
-         * @return allowed commands. Can be {@code null} to reject connection.
-         */
-        @Nullable
-        public Session2CommandGroup onConnect(@NonNull MediaSession2 session,
-                @NonNull ControllerInfo controller) {
-            Session2CommandGroup commands = new Session2CommandGroup.Builder()
-                    .addAllPredefinedCommands(Session2Command.COMMAND_VERSION_1)
-                    .build();
-            return commands;
-        }
-
-        /**
-         * Called when a controller is disconnected
-         *
-         * @param session the session for this event
-         * @param controller controller information
-         */
-        public void onDisconnected(@NonNull MediaSession2 session,
-                @NonNull ControllerInfo controller) { }
-
-        /**
-         * Called when a controller sent a session command.
-         *
-         * @param session the session for this event
-         * @param controller controller information
-         * @param command the session command
-         * @param args optional arguments
-         * @return the result for the session command. A runtime exception will be thrown if null
-         *         is returned.
-         */
-        @NonNull
-        public Session2Command.Result onSessionCommand(@NonNull MediaSession2 session,
-                @NonNull ControllerInfo controller, @NonNull Session2Command command,
-                @Nullable Bundle args) {
-            return null;
-        }
-
-        /**
-         * Called when the command sent to the controller is finished.
-         *
-         * @param session the session for this event
-         * @param controller controller information
-         * @param token the token got from {@link MediaSession2#sendSessionCommand}
-         * @param command the session command
-         * @param result the result of the session command
-         */
-        public void onCommandResult(@NonNull MediaSession2 session,
-                @NonNull ControllerInfo controller, @NonNull Object token,
-                @NonNull Session2Command command, @NonNull Session2Command.Result result) { }
-    }
-}
diff --git a/media/java/android/media/MicrophoneDirection.java b/media/java/android/media/MicrophoneDirection.java
new file mode 100644
index 0000000..99201c0
--- /dev/null
+++ b/media/java/android/media/MicrophoneDirection.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 android.media;
+
+/**
+ * @hide
+ */
+public interface MicrophoneDirection {
+    /**
+     * @hide
+     */
+    int MIC_DIRECTION_UNSPECIFIED = 0;
+
+    /**
+     * @hide
+     */
+    int MIC_DIRECTION_FRONT = 1;
+
+    /**
+     * @hide
+     */
+    int MIC_DIRECTION_BACK = 2;
+
+    /**
+     * @hide
+     */
+    int MIC_DIRECTION_EXTERNAL = 3;
+
+    /**
+     * Specifies the logical microphone (for processing).
+     *
+     * @param direction Direction constant (MicrophoneDirection.MIC_DIRECTION_*)
+     * @return retval OK if the call is successful, an error code otherwise.
+     * @hide
+     */
+    int setMicrophoneDirection(int direction);
+
+    /**
+     * Specifies the zoom factor (i.e. the field dimension) for the selected microphone
+     * (for processing). The selected microphone is determined by the use-case for the stream.
+     *
+     * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle),
+     * though 0 (no zoom) to 1 (maximum zoom).
+     * @return retval OK if the call is successful, an error code otherwise.
+     * @hide
+     */
+    int setMicrophoneFieldDimension(float zoom);
+}
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 3b51c82..325420b 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -21,18 +21,14 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.media.session.MediaSession;
 import android.media.session.MediaSessionLegacyHelper;
 import android.media.session.PlaybackState;
-import android.media.session.MediaSession;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.Looper;
-import android.os.Message;
 import android.os.SystemClock;
 import android.util.Log;
 
-import java.lang.IllegalArgumentException;
-
 /**
  * RemoteControlClient enables exposing information meant to be consumed by remote controls
  * capable of displaying metadata, artwork and media transport control buttons.
@@ -682,7 +678,7 @@
 
                 // USE_SESSIONS
                 if (mSession != null) {
-                    int pbState = PlaybackState.getStateFromRccState(state);
+                    int pbState = getStateFromRccState(state);
                     long position = hasPosition ? mPlaybackPositionMs
                             : PlaybackState.PLAYBACK_POSITION_UNKNOWN;
 
@@ -718,8 +714,7 @@
             // USE_SESSIONS
             if (mSession != null) {
                 PlaybackState.Builder bob = new PlaybackState.Builder(mSessionPlaybackState);
-                bob.setActions(
-                        PlaybackState.getActionsFromRccControlFlags(transportControlFlags));
+                bob.setActions(getActionsFromRccControlFlags(transportControlFlags));
                 mSessionPlaybackState = bob.build();
                 mSession.setPlaybackState(mSessionPlaybackState);
             }
@@ -1001,16 +996,19 @@
      * Period for playback position drift checks, 15s when playing at 1x or slower.
      */
     private final static long POSITION_REFRESH_PERIOD_PLAYING_MS = 15000;
+
     /**
      * Minimum period for playback position drift checks, never more often when every 2s, when
      * fast forwarding or rewinding.
      */
     private final static long POSITION_REFRESH_PERIOD_MIN_MS = 2000;
+
     /**
      * The value above which the difference between client-reported playback position and
      * estimated position is considered a drift.
      */
     private final static long POSITION_DRIFT_MAX_MS = 500;
+
     /**
      * Compute the period at which the estimated playback position should be compared against the
      * actual playback position. Is a funciton of playback speed.
@@ -1025,4 +1023,151 @@
                     POSITION_REFRESH_PERIOD_MIN_MS);
         }
     }
+
+    /**
+     * Get the {@link PlaybackState} state for the given
+     * {@link RemoteControlClient} state.
+     *
+     * @param rccState The state used by {@link RemoteControlClient}.
+     * @return The equivalent state used by {@link PlaybackState}.
+     */
+    private static int getStateFromRccState(int rccState) {
+        switch (rccState) {
+            case PLAYSTATE_BUFFERING:
+                return PlaybackState.STATE_BUFFERING;
+            case PLAYSTATE_ERROR:
+                return PlaybackState.STATE_ERROR;
+            case PLAYSTATE_FAST_FORWARDING:
+                return PlaybackState.STATE_FAST_FORWARDING;
+            case PLAYSTATE_NONE:
+                return PlaybackState.STATE_NONE;
+            case PLAYSTATE_PAUSED:
+                return PlaybackState.STATE_PAUSED;
+            case PLAYSTATE_PLAYING:
+                return PlaybackState.STATE_PLAYING;
+            case PLAYSTATE_REWINDING:
+                return PlaybackState.STATE_REWINDING;
+            case PLAYSTATE_SKIPPING_BACKWARDS:
+                return PlaybackState.STATE_SKIPPING_TO_PREVIOUS;
+            case PLAYSTATE_SKIPPING_FORWARDS:
+                return PlaybackState.STATE_SKIPPING_TO_NEXT;
+            case PLAYSTATE_STOPPED:
+                return PlaybackState.STATE_STOPPED;
+            default:
+                return -1;
+        }
+    }
+
+    /**
+     * Get the {@link RemoteControlClient} state for the given
+     * {@link PlaybackState} state.
+     *
+     * @param state The state used by {@link PlaybackState}.
+     * @return The equivalent state used by {@link RemoteControlClient}.
+     */
+    static int getRccStateFromState(int state) {
+        switch (state) {
+            case PlaybackState.STATE_BUFFERING:
+                return PLAYSTATE_BUFFERING;
+            case PlaybackState.STATE_ERROR:
+                return PLAYSTATE_ERROR;
+            case PlaybackState.STATE_FAST_FORWARDING:
+                return PLAYSTATE_FAST_FORWARDING;
+            case PlaybackState.STATE_NONE:
+                return PLAYSTATE_NONE;
+            case PlaybackState.STATE_PAUSED:
+                return PLAYSTATE_PAUSED;
+            case PlaybackState.STATE_PLAYING:
+                return PLAYSTATE_PLAYING;
+            case PlaybackState.STATE_REWINDING:
+                return PLAYSTATE_REWINDING;
+            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
+                return PLAYSTATE_SKIPPING_BACKWARDS;
+            case PlaybackState.STATE_SKIPPING_TO_NEXT:
+                return PLAYSTATE_SKIPPING_FORWARDS;
+            case PlaybackState.STATE_STOPPED:
+                return PLAYSTATE_STOPPED;
+            default:
+                return -1;
+        }
+    }
+
+    private static long getActionsFromRccControlFlags(int rccFlags) {
+        long actions = 0;
+        long flag = 1;
+        while (flag <= rccFlags) {
+            if ((flag & rccFlags) != 0) {
+                actions |= getActionForRccFlag((int) flag);
+            }
+            flag = flag << 1;
+        }
+        return actions;
+    }
+
+    static int getRccControlFlagsFromActions(long actions) {
+        int rccFlags = 0;
+        long action = 1;
+        while (action <= actions && action < Integer.MAX_VALUE) {
+            if ((action & actions) != 0) {
+                rccFlags |= getRccFlagForAction(action);
+            }
+            action = action << 1;
+        }
+        return rccFlags;
+    }
+
+    private static long getActionForRccFlag(int flag) {
+        switch (flag) {
+            case FLAG_KEY_MEDIA_PREVIOUS:
+                return PlaybackState.ACTION_SKIP_TO_PREVIOUS;
+            case FLAG_KEY_MEDIA_REWIND:
+                return PlaybackState.ACTION_REWIND;
+            case FLAG_KEY_MEDIA_PLAY:
+                return PlaybackState.ACTION_PLAY;
+            case FLAG_KEY_MEDIA_PLAY_PAUSE:
+                return PlaybackState.ACTION_PLAY_PAUSE;
+            case FLAG_KEY_MEDIA_PAUSE:
+                return PlaybackState.ACTION_PAUSE;
+            case FLAG_KEY_MEDIA_STOP:
+                return PlaybackState.ACTION_STOP;
+            case FLAG_KEY_MEDIA_FAST_FORWARD:
+                return PlaybackState.ACTION_FAST_FORWARD;
+            case FLAG_KEY_MEDIA_NEXT:
+                return PlaybackState.ACTION_SKIP_TO_NEXT;
+            case FLAG_KEY_MEDIA_POSITION_UPDATE:
+                return PlaybackState.ACTION_SEEK_TO;
+            case FLAG_KEY_MEDIA_RATING:
+                return PlaybackState.ACTION_SET_RATING;
+        }
+        return 0;
+    }
+
+    private static int getRccFlagForAction(long action) {
+        // We only care about the lower set of actions that can map to rcc
+        // flags.
+        int testAction = action < Integer.MAX_VALUE ? (int) action : 0;
+        switch (testAction) {
+            case (int) PlaybackState.ACTION_SKIP_TO_PREVIOUS:
+                return FLAG_KEY_MEDIA_PREVIOUS;
+            case (int) PlaybackState.ACTION_REWIND:
+                return FLAG_KEY_MEDIA_REWIND;
+            case (int) PlaybackState.ACTION_PLAY:
+                return FLAG_KEY_MEDIA_PLAY;
+            case (int) PlaybackState.ACTION_PLAY_PAUSE:
+                return FLAG_KEY_MEDIA_PLAY_PAUSE;
+            case (int) PlaybackState.ACTION_PAUSE:
+                return FLAG_KEY_MEDIA_PAUSE;
+            case (int) PlaybackState.ACTION_STOP:
+                return FLAG_KEY_MEDIA_STOP;
+            case (int) PlaybackState.ACTION_FAST_FORWARD:
+                return FLAG_KEY_MEDIA_FAST_FORWARD;
+            case (int) PlaybackState.ACTION_SKIP_TO_NEXT:
+                return FLAG_KEY_MEDIA_NEXT;
+            case (int) PlaybackState.ACTION_SEEK_TO:
+                return FLAG_KEY_MEDIA_POSITION_UPDATE;
+            case (int) PlaybackState.ACTION_SET_RATING:
+                return FLAG_KEY_MEDIA_RATING;
+        }
+        return 0;
+    }
 }
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index 5e9eed7..f70963a 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -632,8 +632,8 @@
             l = this.mOnClientUpdateListener;
         }
         if (l != null) {
-            int playstate = state == null ? RemoteControlClient.PLAYSTATE_NONE : PlaybackState
-                    .getRccStateFromState(state.getState());
+            int playstate = state == null ? RemoteControlClient.PLAYSTATE_NONE
+                    : RemoteControlClient.getRccStateFromState(state.getState());
             if (state == null || state.getPosition() == PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
                 l.onClientPlaybackStateUpdate(playstate);
             } else {
@@ -642,7 +642,7 @@
             }
             if (state != null) {
                 l.onClientTransportControlUpdate(
-                        PlaybackState.getRccControlFlagsFromActions(state.getActions()));
+                        RemoteControlClient.getRccControlFlagsFromActions(state.getActions()));
             }
         }
     }
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 42597aa..73d3d88 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -138,7 +138,7 @@
         mAudioAttributes = attributes;
         // The audio attributes have to be set before the media player is prepared.
         // Re-initialize it.
-        setUri(mUri);
+        setUri(mUri, mVolumeShaperConfig);
     }
 
     /**
@@ -415,6 +415,7 @@
             mLocalPlayer.reset();
             mLocalPlayer.release();
             mLocalPlayer = null;
+            mVolumeShaper = null;
             synchronized (sActiveRingtones) {
                 sActiveRingtones.remove(this);
             }
diff --git a/media/java/android/media/Session2Command.java b/media/java/android/media/Session2Command.java
deleted file mode 100644
index e46e64e..0000000
--- a/media/java/android/media/Session2Command.java
+++ /dev/null
@@ -1,735 +0,0 @@
-/*
- * 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.media;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Define a command that a {@link MediaController2} can send to a {@link MediaSession2}.
- * <p>
- * If {@link #getCommandCode()} isn't {@link #COMMAND_CODE_CUSTOM}), it's predefined command.
- * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and
- * {@link #getCustomCommand()} shouldn't be {@code null}.
- * <p>
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
- * </p>
- * @hide
- */
-public final class Session2Command implements Parcelable {
-    /**
-     * The first version of session commands. This version is for commands introduced in API 29.
-     * <p>
-     * This would be used to specify which commands should be added by
-     * {@link Session2CommandGroup.Builder#addAllPredefinedCommands(int)}
-     *
-     * @see Session2CommandGroup.Builder#addAllPredefinedCommands(int)
-     */
-    public static final int COMMAND_VERSION_1 = 1;
-
-    /**
-     * @hide
-     */
-    public static final int COMMAND_VERSION_CURRENT = COMMAND_VERSION_1;
-
-    /**
-     * @hide
-     */
-    @IntDef({COMMAND_VERSION_1})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface CommandVersion {}
-
-    /**
-     * @hide
-     */
-    @IntDef({COMMAND_CODE_CUSTOM,
-            COMMAND_CODE_PLAYER_PLAY,
-            COMMAND_CODE_PLAYER_PAUSE,
-            COMMAND_CODE_PLAYER_PREPARE,
-            COMMAND_CODE_PLAYER_SEEK_TO,
-            COMMAND_CODE_PLAYER_SET_SPEED,
-            COMMAND_CODE_PLAYER_GET_PLAYLIST,
-            COMMAND_CODE_PLAYER_SET_PLAYLIST,
-            COMMAND_CODE_PLAYER_SKIP_TO_PLAYLIST_ITEM,
-            COMMAND_CODE_PLAYER_SKIP_TO_PREVIOUS_PLAYLIST_ITEM,
-            COMMAND_CODE_PLAYER_SKIP_TO_NEXT_PLAYLIST_ITEM,
-            COMMAND_CODE_PLAYER_SET_SHUFFLE_MODE,
-            COMMAND_CODE_PLAYER_SET_REPEAT_MODE,
-            COMMAND_CODE_PLAYER_GET_PLAYLIST_METADATA,
-            COMMAND_CODE_PLAYER_ADD_PLAYLIST_ITEM,
-            COMMAND_CODE_PLAYER_REMOVE_PLAYLIST_ITEM,
-            COMMAND_CODE_PLAYER_REPLACE_PLAYLIST_ITEM,
-            COMMAND_CODE_PLAYER_GET_CURRENT_MEDIA_ITEM,
-            COMMAND_CODE_PLAYER_UPDATE_LIST_METADATA,
-            COMMAND_CODE_PLAYER_SET_MEDIA_ITEM,
-            COMMAND_CODE_VOLUME_SET_VOLUME,
-            COMMAND_CODE_VOLUME_ADJUST_VOLUME,
-            COMMAND_CODE_SESSION_FAST_FORWARD,
-            COMMAND_CODE_SESSION_REWIND,
-            COMMAND_CODE_SESSION_SKIP_FORWARD,
-            COMMAND_CODE_SESSION_SKIP_BACKWARD,
-            COMMAND_CODE_SESSION_SET_RATING,
-            COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT,
-            COMMAND_CODE_LIBRARY_SUBSCRIBE,
-            COMMAND_CODE_LIBRARY_UNSUBSCRIBE,
-            COMMAND_CODE_LIBRARY_GET_CHILDREN,
-            COMMAND_CODE_LIBRARY_GET_ITEM,
-            COMMAND_CODE_LIBRARY_SEARCH,
-            COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface CommandCode {}
-
-    /**
-     * Command code for the custom command which can be defined by string action in the
-     * {@link Session2Command}.
-     */
-    public static final int COMMAND_CODE_CUSTOM = 0;
-
-    ////////////////////////////////////////////////////////////////////////////////////////////////
-    // Player commands (i.e. commands to {@link Session2Player})
-    ////////////////////////////////////////////////////////////////////////////////////////////////
-    static final ArrayMap<Integer, Range> VERSION_PLAYER_COMMANDS_MAP = new ArrayMap<>();
-    static final ArrayMap<Integer, Range> VERSION_PLAYER_PLAYLIST_COMMANDS_MAP = new ArrayMap<>();
-
-    // TODO: check the link tag, and reassign int values properly.
-    /**
-     * Command code for {@link MediaController2#play()}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info,
-     * Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_PLAY = 10000;
-
-    /**
-     * Command code for {@link MediaController2#pause()}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info,
-     * Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_PAUSE = 10001;
-
-    /**
-     * Command code for {@link MediaController2#prepare()}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info,
-     * Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_PREPARE = 10002;
-
-    /**
-     * Command code for {@link MediaController2#seekTo(long)}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info,
-     * Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_SEEK_TO = 10003;
-
-    /**
-     * Command code for {@link MediaController2#setPlaybackSpeed(float)}}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the {@link Session22Callback#onCommandRequest(MediaSession2, Controller2Info,
-     * Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_SET_SPEED = 10004;
-
-    /**
-     * Command code for {@link MediaController2#getPlaylist()}. This will expose metadata
-     * information to the controller.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_GET_PLAYLIST = 10005;
-
-    /**
-     * Command code for {@link MediaController2#setPlaylist(List, MediaMetadata)}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the
-     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_SET_PLAYLIST = 10006;
-
-    /**
-     * Command code for {@link MediaController2#skipToPlaylistItem(int)}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the
-     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_SKIP_TO_PLAYLIST_ITEM = 10007;
-
-    /**
-     * Command code for {@link MediaController2#skipToPreviousPlaylistItem()}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the {@link Session2Callback#onCommandRequest(
-     * MediaSession2, Controller2Info, Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_SKIP_TO_PREVIOUS_PLAYLIST_ITEM = 10008;
-
-    /**
-     * Command code for {@link MediaController2#skipToNextPlaylistItem()}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the {@link Session2Callback#onCommandRequest(
-     * MediaSession2, Controller2Info, Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-
-    public static final int COMMAND_CODE_PLAYER_SKIP_TO_NEXT_PLAYLIST_ITEM = 10009;
-
-    /**
-     * Command code for {@link MediaController2#setShuffleMode(int)}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the
-     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_SET_SHUFFLE_MODE = 10010;
-
-    /**
-     * Command code for {@link MediaController2#setRepeatMode(int)}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the
-     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_SET_REPEAT_MODE = 10011;
-
-    /**
-     * Command code for {@link MediaController2#getPlaylistMetadata()}. This will expose metadata
-     * information to the controller.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_GET_PLAYLIST_METADATA = 10012;
-
-    /**
-     * Command code for {@link MediaController2#addPlaylistItem(int, String)}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the
-     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_ADD_PLAYLIST_ITEM = 10013;
-
-    /**
-     * Command code for {@link MediaController2#removePlaylistItem(int, String)}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the
-     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_REMOVE_PLAYLIST_ITEM = 10014;
-
-    /**
-     * Command code for {@link MediaController2#replacePlaylistItem(int, String)}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the
-     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_REPLACE_PLAYLIST_ITEM = 10015;
-
-    /**
-     * Command code for {@link MediaController2#getCurrentMediaItem()}. This will expose metadata
-     * information to the controller.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_GET_CURRENT_MEDIA_ITEM = 10016;
-
-    /**
-     * Command code for {@link MediaController2#updatePlaylistMetadata(MediaMetadata)}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the
-     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_UPDATE_LIST_METADATA = 10017;
-
-    /**
-     * Command code for {@link MediaController2#setMediaItem(String)}.
-     * <p>
-     * Command would be sent directly to the player if the session doesn't reject the request
-     * through the
-     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_PLAYER_SET_MEDIA_ITEM = 10018;
-
-    static {
-        VERSION_PLAYER_COMMANDS_MAP.put(COMMAND_VERSION_1,
-                new Range(COMMAND_CODE_PLAYER_PLAY, COMMAND_CODE_PLAYER_SET_MEDIA_ITEM));
-    }
-
-    static {
-        VERSION_PLAYER_PLAYLIST_COMMANDS_MAP.put(COMMAND_VERSION_1,
-                new Range(COMMAND_CODE_PLAYER_GET_PLAYLIST,
-                        COMMAND_CODE_PLAYER_SET_MEDIA_ITEM));
-    }
-
-    ////////////////////////////////////////////////////////////////////////////////////////////////
-    // Volume commands (i.e. commands to {@link AudioManager} or {@link RouteMediaPlayer})
-    ////////////////////////////////////////////////////////////////////////////////////////////////
-    static final ArrayMap<Integer, Range> VERSION_VOLUME_COMMANDS_MAP = new ArrayMap<>();
-
-    /**
-     * Command code for {@link MediaController2#setVolumeTo(int, int)}.
-     * <p>
-     * <p>
-     * If the session doesn't reject the request through the
-     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)},
-     * command would adjust the device volume. It would send to the player directly only if it's
-     * remote player. See RouteMediaPlayer for a remote player.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_VOLUME_SET_VOLUME = 30000;
-
-    /**
-     * Command code for {@link MediaController2#adjustVolume(int, int)}.
-     * <p>
-     * If the session doesn't reject the request through the
-     * {@link Session2Callback#onCommandRequest(MediaSession2, Controller2Info, Session2Command)},
-     * command would adjust the device volume. It would send to the player directly only if it's
-     * remote player. See RouteMediaPlayer for a remote player.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_VOLUME_ADJUST_VOLUME = 30001;
-
-    static {
-        VERSION_VOLUME_COMMANDS_MAP.put(COMMAND_VERSION_1,
-                new Range(COMMAND_CODE_VOLUME_SET_VOLUME,
-                        COMMAND_CODE_VOLUME_ADJUST_VOLUME));
-    }
-
-    ////////////////////////////////////////////////////////////////////////////////////////////////
-    // Session commands (i.e. commands to {@link MediaSession2#Session2Callback})
-    ////////////////////////////////////////////////////////////////////////////////////////////////
-    static final ArrayMap<Integer, Range> VERSION_SESSION_COMMANDS_MAP = new ArrayMap<>();
-
-    /**
-     * Command code for {@link MediaController2#fastForward()}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_SESSION_FAST_FORWARD = 40000;
-
-    /**
-     * Command code for {@link MediaController2#rewind()}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_SESSION_REWIND = 40001;
-
-    /**
-     * Command code for {@link MediaController2#skipForward()}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_SESSION_SKIP_FORWARD = 40002;
-
-    /**
-     * Command code for {@link MediaController2#skipBackward()}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_SESSION_SKIP_BACKWARD = 40003;
-
-    /**
-     * Command code for {@link MediaController2#setRating(String, Rating)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_SESSION_SET_RATING = 40010;
-
-    /**
-     * @hide
-     */
-    @IntDef(flag = false, /*prefix = "RESULT_CODE",*/ value = {
-            RESULT_SUCCESS,
-            RESULT_ERROR_UNKNOWN_ERROR,
-            RESULT_ERROR_INVALID_STATE,
-            RESULT_ERROR_BAD_VALUE,
-            RESULT_ERROR_PERMISSION_DENIED,
-            RESULT_ERROR_IO_ERROR,
-            RESULT_INFO_SKIPPED,
-            RESULT_ERROR_SESSION_DISCONNECTED,
-            RESULT_ERROR_NOT_SUPPORTED,
-            RESULT_ERROR_SESSION_AUTHENTICATION_EXPIRED,
-            RESULT_ERROR_SESSION_PREMIUM_ACCOUNT_REQUIRED,
-            RESULT_ERROR_SESSION_CONCURRENT_STREAM_LIMIT,
-            RESULT_ERROR_SESSION_PARENTAL_CONTROL_RESTRICTED,
-            RESULT_ERROR_SESSION_NOT_AVAILABLE_IN_REGION,
-            RESULT_ERROR_SESSION_SKIP_LIMIT_REACHED,
-            RESULT_ERROR_SESSION_SETUP_REQUIRED})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface ResultCode {}
-
-    /**
-     * Result code representing that the command is skipped or canceled. For an example, a seek
-     * command can be skipped if it is followed by another seek command.
-     */
-    public static final int RESULT_INFO_SKIPPED = 1;
-
-    /**
-     * Result code representing that the command is successfully completed.
-     */
-    public static final int RESULT_SUCCESS = 0;
-
-    /**
-     * Result code represents that call is ended with an unknown error.
-     */
-    public static final int RESULT_ERROR_UNKNOWN_ERROR = -1;
-
-    /**
-     * Result code representing that the command cannot be completed because the current state is
-     * not valid for the command.
-     */
-    public static final int RESULT_ERROR_INVALID_STATE = -2;
-
-    /**
-     * Result code representing that an argument is illegal.
-     */
-    public static final int RESULT_ERROR_BAD_VALUE = -3;
-
-    /**
-     * Result code representing that the command is not allowed.
-     */
-    public static final int RESULT_ERROR_PERMISSION_DENIED = -4;
-
-    /**
-     * Result code representing a file or network related command error.
-     */
-    public static final int RESULT_ERROR_IO_ERROR = -5;
-
-    /**
-     * Result code representing that the command is not supported nor implemented.
-     */
-    public static final int RESULT_ERROR_NOT_SUPPORTED = -6;
-
-    /**
-     * Result code representing that the session and controller were disconnected.
-     */
-    public static final int RESULT_ERROR_SESSION_DISCONNECTED = -100;
-
-    /**
-     * Result code representing that the authentication has expired.
-     */
-    public static final int RESULT_ERROR_SESSION_AUTHENTICATION_EXPIRED = -102;
-
-    /**
-     * Result code representing that a premium account is required.
-     */
-    public static final int RESULT_ERROR_SESSION_PREMIUM_ACCOUNT_REQUIRED = -103;
-
-    /**
-     * Result code representing that too many concurrent streams are detected.
-     */
-    public static final int RESULT_ERROR_SESSION_CONCURRENT_STREAM_LIMIT = -104;
-
-    /**
-     * Result code representing that the content is blocked due to parental controls.
-     */
-    public static final int RESULT_ERROR_SESSION_PARENTAL_CONTROL_RESTRICTED = -105;
-
-    /**
-     * Result code representing that the content is blocked due to being regionally unavailable.
-     */
-    public static final int RESULT_ERROR_SESSION_NOT_AVAILABLE_IN_REGION = -106;
-
-    /**
-     * Result code representing that the application cannot skip any more because the skip limit is
-     * reached.
-     */
-    public static final int RESULT_ERROR_SESSION_SKIP_LIMIT_REACHED = -107;
-
-    /**
-     * Result code representing that the session needs user's manual intervention.
-     */
-    public static final int RESULT_ERROR_SESSION_SETUP_REQUIRED = -108;
-
-    public static final Parcelable.Creator<Session2Command> CREATOR =
-            new Parcelable.Creator<Session2Command>() {
-                @Override
-                public Session2Command createFromParcel(Parcel in) {
-                    return new Session2Command(in);
-                }
-
-                @Override
-                public Session2Command[] newArray(int size) {
-                    return new Session2Command[size];
-                }
-            };
-
-    static {
-        VERSION_SESSION_COMMANDS_MAP.put(COMMAND_VERSION_1,
-                new Range(COMMAND_CODE_SESSION_FAST_FORWARD, COMMAND_CODE_SESSION_SET_RATING));
-    }
-
-    ////////////////////////////////////////////////////////////////////////////////////////////////
-    // Session commands (i.e. commands to {@link MediaLibrarySession#MediaLibrarySessionCallback})
-    ////////////////////////////////////////////////////////////////////////////////////////////////
-    static final ArrayMap<Integer, Range> VERSION_LIBRARY_COMMANDS_MAP = new ArrayMap<>();
-
-    /**
-     * Command code for {@link MediaBrowser2#getLibraryRoot(Library2Params)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT = 50000;
-
-    /**
-     * Command code for {@link MediaBrowser2#subscribe(String, Library2Params)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_LIBRARY_SUBSCRIBE = 50001;
-
-    /**
-     * Command code for {@link MediaBrowser2#unsubscribe(String)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_LIBRARY_UNSUBSCRIBE = 50002;
-
-    /**
-     * Command code for {@link MediaBrowser2#getChildren(String, int, int, Library2Params)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_LIBRARY_GET_CHILDREN = 50003;
-
-    /**
-     * Command code for {@link MediaBrowser2#getItem(String)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_LIBRARY_GET_ITEM = 50004;
-
-    /**
-     * Command code for {@link MediaBrowser2#search(String, LibraryParams)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_LIBRARY_SEARCH = 50005;
-
-    /**
-     * Command code for {@link MediaBrowser2#getSearchResult(String, int, int, Library2Params)}.
-     * <p>
-     * Code version is {@link #COMMAND_VERSION_1}.
-     */
-    public static final int COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT = 50006;
-
-    static {
-        VERSION_LIBRARY_COMMANDS_MAP.put(COMMAND_VERSION_1,
-                new Range(COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT,
-                        COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT));
-    }
-
-    @CommandCode private final int mCommandCode;
-    // Nonnull if it's custom command
-    private final String mCustomCommand;
-    private final Bundle mExtras;
-
-    /**
-     * Constructor for creating a predefined command.
-     *
-     * @param commandCode A command code for predefined command.
-     */
-    public Session2Command(@CommandCode int commandCode) {
-        if (commandCode == COMMAND_CODE_CUSTOM) {
-            throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM");
-        }
-        mCommandCode = commandCode;
-        mCustomCommand = null;
-        mExtras = null;
-    }
-
-    /**
-     * Constructor for creating a custom command.
-     *
-     * @param action The action of this custom command.
-     * @param extras An extra bundle for this custom command.
-     */
-    public Session2Command(@NonNull String action, @Nullable Bundle extras) {
-        if (action == null) {
-            throw new IllegalArgumentException("action shouldn't be null");
-        }
-        mCommandCode = COMMAND_CODE_CUSTOM;
-        mCustomCommand = action;
-        mExtras = extras;
-    }
-
-    /**
-     * Used by parcelable creator.
-     */
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    Session2Command(Parcel in) {
-        mCommandCode = in.readInt();
-        mCustomCommand = in.readString();
-        mExtras = in.readBundle();
-    }
-
-    /**
-     * Gets the command code of a predefined command.
-     * This will return {@link #COMMAND_CODE_CUSTOM} for a custom command.
-     */
-    public @CommandCode int getCommandCode() {
-        return mCommandCode;
-    }
-
-    /**
-     * Gets the action of a custom command.
-     * This will return {@code null} for a predefined command.
-     */
-    public @Nullable String getCustomCommand() {
-        return mCustomCommand;
-    }
-
-    /**
-     * Gets the extra bundle of a custom command.
-     * This will return {@code null} for a predefined command.
-     */
-    public @Nullable Bundle getExtras() {
-        return mExtras;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mCommandCode);
-        dest.writeString(mCustomCommand);
-        dest.writeBundle(mExtras);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof Session2Command)) {
-            return false;
-        }
-        Session2Command other = (Session2Command) obj;
-        return mCommandCode == other.mCommandCode
-                && TextUtils.equals(mCustomCommand, other.mCustomCommand);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mCustomCommand, mCommandCode);
-    }
-
-    /**
-     * Contains the result of {@link Session2Command}.
-     */
-    public static final class Result {
-        private final int mResultCode;
-        private final Bundle mResultData;
-
-        /**
-         * Constructor of {@link Result}.
-         *
-         * @param resultCode result code
-         * @param resultData result data
-         */
-        public Result(int resultCode, Bundle resultData) {
-            mResultCode = resultCode;
-            mResultData = resultData;
-        }
-
-        /**
-         * Returns the result code.
-         */
-        public int getResultCode() {
-            return mResultCode;
-        }
-
-        /**
-         * Returns the result data.
-         */
-        public Bundle getResultData() {
-            return mResultData;
-        }
-    }
-
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    static final class Range {
-        public final int lower;
-        public final int upper;
-
-        Range(int lower, int upper) {
-            this.lower = lower;
-            this.upper = upper;
-        }
-    }
-}
-
diff --git a/media/java/android/media/Session2CommandGroup.java b/media/java/android/media/Session2CommandGroup.java
deleted file mode 100644
index 18aff30..0000000
--- a/media/java/android/media/Session2CommandGroup.java
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * 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.media;
-
-import static android.media.Session2Command.COMMAND_CODE_CUSTOM;
-import static android.media.Session2Command.COMMAND_VERSION_1;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.media.Session2Command.Range;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.ArrayMap;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * A set of {@link Session2Command} which represents a command group.
- * <p>
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
- * </p>
- * @hide
- */
-public final class Session2CommandGroup implements Parcelable {
-    private static final String TAG = "Session2CommandGroup";
-
-    public static final Parcelable.Creator<Session2CommandGroup> CREATOR =
-            new Parcelable.Creator<Session2CommandGroup>() {
-                @Override
-                public Session2CommandGroup createFromParcel(Parcel in) {
-                    return new Session2CommandGroup(in);
-                }
-
-                @Override
-                public Session2CommandGroup[] newArray(int size) {
-                    return new Session2CommandGroup[size];
-                }
-            };
-
-    Set<Session2Command> mCommands = new HashSet<>();
-
-    /**
-     * Default Constructor.
-     */
-    public Session2CommandGroup() { }
-
-    /**
-     * Creates a new Session2CommandGroup with commands copied from another object.
-     *
-     * @param commands The collection of commands to copy.
-     */
-    public Session2CommandGroup(@Nullable Collection<Session2Command> commands) {
-        if (commands != null) {
-            mCommands.addAll(commands);
-        }
-    }
-
-    /**
-     * Used by parcelable creator.
-     */
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    Session2CommandGroup(Parcel in) {
-        Session2Command[] commands = in.readParcelableArray(
-                Session2Command.class.getClassLoader(), Session2Command.class);
-        if (commands != null) {
-            for (Session2Command command : commands) {
-                mCommands.add(command);
-            }
-        }
-    }
-
-    /**
-     * Adds a command to this command group.
-     *
-     * @param command A command to add. Shouldn't be {@code null}.
-     * @hide TODO remove this method
-     */
-    public void addCommand(@NonNull Session2Command command) {
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-        if (!hasCommand(command)) {
-            mCommands.add(command);
-        }
-    }
-
-    /**
-     * Adds a predefined command with given {@code commandCode} to this command group.
-     *
-     * @param commandCode A command code to add.
-     *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
-     * @hide TODO remove this method
-     */
-    public void addCommand(@Session2Command.CommandCode int commandCode) {
-        if (commandCode == COMMAND_CODE_CUSTOM) {
-            throw new IllegalArgumentException(
-                    "Use addCommand(Session2Command) for COMMAND_CODE_CUSTOM.");
-        }
-        if (!hasCommand(commandCode)) {
-            mCommands.add(new Session2Command(commandCode));
-        }
-    }
-
-    /**
-     * Checks whether this command group has a command that matches given {@code command}.
-     *
-     * @param command A command to find. Shouldn't be {@code null}.
-     */
-    public boolean hasCommand(@NonNull Session2Command command) {
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-        return mCommands.contains(command);
-    }
-
-    /**
-     * Checks whether this command group has a command that matches given {@code commandCode}.
-     *
-     * @param commandCode A command code to find.
-     *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
-     */
-    public boolean hasCommand(@Session2Command.CommandCode int commandCode) {
-        if (commandCode == COMMAND_CODE_CUSTOM) {
-            throw new IllegalArgumentException("Use hasCommand(Command) for custom command");
-        }
-        for (Session2Command command : mCommands) {
-            if (command.getCommandCode() == commandCode) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Gets all commands of this command group.
-     */
-    public @NonNull Set<Session2Command> getCommands() {
-        return new HashSet<>(mCommands);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeParcelableArray((Session2Command[]) mCommands.toArray(), 0);
-    }
-
-    /**
-     * Builds a {@link Session2CommandGroup} object.
-     */
-    public static final class Builder {
-        private Set<Session2Command> mCommands;
-
-        public Builder() {
-            mCommands = new HashSet<>();
-        }
-
-        /**
-         * Creates a new builder for {@link Session2CommandGroup} with commands copied from another
-         * {@link Session2CommandGroup} object.
-         * @param commandGroup
-         */
-        public Builder(@NonNull Session2CommandGroup commandGroup) {
-            mCommands = commandGroup.getCommands();
-        }
-
-        /**
-         * Adds a command to this command group.
-         *
-         * @param command A command to add. Shouldn't be {@code null}.
-         */
-        public @NonNull Builder addCommand(@NonNull Session2Command command) {
-            if (command == null) {
-                throw new IllegalArgumentException("command shouldn't be null");
-            }
-            mCommands.add(command);
-            return this;
-        }
-
-        /**
-         * Adds a predefined command with given {@code commandCode} to this command group.
-         *
-         * @param commandCode A command code to add.
-         *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
-         */
-        public @NonNull Builder addCommand(@Session2Command.CommandCode int commandCode) {
-            if (commandCode == COMMAND_CODE_CUSTOM) {
-                throw new IllegalArgumentException(
-                        "Use addCommand(Session2Command) for COMMAND_CODE_CUSTOM.");
-            }
-            mCommands.add(new Session2Command(commandCode));
-            return this;
-        }
-
-        /**
-         * Adds all predefined session commands except for the commands added after the specified
-         * version without default implementation. This provides convenient way to add commands
-         * with implementation.
-         *
-         * @param version command version
-         * @see Session2Command#COMMAND_VERSION_1
-         * @see
-         * MediaSession2.Session2Callback#onConnect
-         */
-        public @NonNull Builder addAllPredefinedCommands(
-                @Session2Command.CommandVersion int version) {
-            if (version != COMMAND_VERSION_1) {
-                throw new IllegalArgumentException("Unknown command version " + version);
-            }
-            addAllPlayerCommands(version);
-            addAllVolumeCommands(version);
-            addAllSessionCommands(version);
-            addAllLibraryCommands(version);
-            return this;
-        }
-
-        /**
-         * Removes a command from this group which matches given {@code command}.
-         *
-         * @param command A command to find. Shouldn't be {@code null}.
-         */
-        public @NonNull Builder removeCommand(@NonNull Session2Command command) {
-            if (command == null) {
-                throw new IllegalArgumentException("command shouldn't be null");
-            }
-            mCommands.remove(command);
-            return this;
-        }
-
-        /**
-         * Removes a command from this group which matches given {@code commandCode}.
-         *
-         * @param commandCode A command code to find.
-         *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
-         */
-        public @NonNull Builder removeCommand(@Session2Command.CommandCode int commandCode) {
-            if (commandCode == COMMAND_CODE_CUSTOM) {
-                throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM");
-            }
-            mCommands.remove(new Session2Command(commandCode));
-            return this;
-        }
-
-        @NonNull Builder addAllPlayerCommands(@Session2Command.CommandVersion int version) {
-            addCommands(version, Session2Command.VERSION_PLAYER_COMMANDS_MAP);
-            return this;
-        }
-
-        @NonNull Builder addAllPlayerCommands(@Session2Command.CommandVersion int version,
-                boolean includePlaylistCommands) {
-            if (includePlaylistCommands) {
-                return addAllPlayerCommands(version);
-            }
-            for (int i = COMMAND_VERSION_1; i <= version; i++) {
-                Range include = Session2Command.VERSION_PLAYER_COMMANDS_MAP.get(i);
-                Range exclude = Session2Command.VERSION_PLAYER_PLAYLIST_COMMANDS_MAP.get(i);
-                for (int code = include.lower; code <= include.upper; code++) {
-                    if (code < exclude.lower && code > exclude.upper) {
-                        addCommand(code);
-                    }
-                }
-            }
-            return this;
-        }
-
-        @NonNull Builder addAllVolumeCommands(@Session2Command.CommandVersion int version) {
-            addCommands(version, Session2Command.VERSION_VOLUME_COMMANDS_MAP);
-            return this;
-        }
-
-        @NonNull Builder addAllSessionCommands(@Session2Command.CommandVersion int version) {
-            addCommands(version, Session2Command.VERSION_SESSION_COMMANDS_MAP);
-            return this;
-        }
-
-        @NonNull Builder addAllLibraryCommands(@Session2Command.CommandVersion int version) {
-            addCommands(version, Session2Command.VERSION_LIBRARY_COMMANDS_MAP);
-            return this;
-        }
-
-        private void addCommands(
-                @Session2Command.CommandVersion int version, ArrayMap<Integer, Range> map) {
-            for (int i = COMMAND_VERSION_1; i <= version; i++) {
-                Range range = map.get(i);
-                for (int code = range.lower; code <= range.upper; code++) {
-                    addCommand(code);
-                }
-            }
-        }
-
-        /**
-         * Builds {@link Session2CommandGroup}.
-         *
-         * @return a new {@link Session2CommandGroup}.
-         */
-        public @NonNull Session2CommandGroup build() {
-            return new Session2CommandGroup(mCommands);
-        }
-    }
-}
diff --git a/media/java/android/media/Session2Link.java b/media/java/android/media/Session2Link.java
deleted file mode 100644
index 5fe558d..0000000
--- a/media/java/android/media/Session2Link.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * 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.media;
-
-import android.annotation.NonNull;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.util.Log;
-
-import java.util.Objects;
-
-/**
- * Handles incoming commands from {@link MediaController2} to {@link MediaSession2}.
- * @hide
- */
-// @SystemApi
-public final class Session2Link implements Parcelable {
-    private static final String TAG = "Session2Link";
-    private static final boolean DEBUG = MediaSession2.DEBUG;
-
-    public static final Parcelable.Creator<Session2Link> CREATOR =
-            new Parcelable.Creator<Session2Link>() {
-                @Override
-                public Session2Link createFromParcel(Parcel in) {
-                    return new Session2Link(in);
-                }
-
-                @Override
-                public Session2Link[] newArray(int size) {
-                    return new Session2Link[size];
-                }
-            };
-
-    private final MediaSession2 mSession;
-    private final IMediaSession2 mISession;
-
-    public Session2Link(MediaSession2 session) {
-        mSession = session;
-        mISession = new Session2Stub();
-    }
-
-    Session2Link(Parcel in) {
-        mSession = null;
-        mISession = IMediaSession2.Stub.asInterface(in.readStrongBinder());
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongBinder(mISession.asBinder());
-    }
-
-    @Override
-    public int hashCode() {
-        return mISession.asBinder().hashCode();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof Session2Link)) {
-            return false;
-        }
-        Session2Link other = (Session2Link) obj;
-        return Objects.equals(mISession.asBinder(), other.mISession.asBinder());
-    }
-
-    /** Link to death with mISession */
-    public void linkToDeath(@NonNull IBinder.DeathRecipient recipient, int flags) {
-        if (mISession != null) {
-            try {
-                mISession.asBinder().linkToDeath(recipient, flags);
-            } catch (RemoteException e) {
-                if (DEBUG) {
-                    Log.d(TAG, "Session died too early.", e);
-                }
-            }
-        }
-    }
-
-    /** Unlink to death with mISession */
-    public boolean unlinkToDeath(@NonNull IBinder.DeathRecipient recipient, int flags) {
-        if (mISession != null) {
-            return mISession.asBinder().unlinkToDeath(recipient, flags);
-        }
-        return true;
-    }
-
-    /** Interface method for IMediaSession2.connect */
-    public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) {
-        try {
-            mISession.connect(caller, seq, connectionRequest);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for IMediaSession2.disconnect */
-    public void disconnect(final Controller2Link caller, int seq) {
-        try {
-            mISession.disconnect(caller, seq);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for IMediaSession2.sendSessionCommand */
-    public void sendSessionCommand(final Controller2Link caller, final int seq,
-            final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
-        try {
-            mISession.sendSessionCommand(caller, seq, command, args, resultReceiver);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for IMediaSession2.sendSessionCommand */
-    public void cancelSessionCommand(final Controller2Link caller, final int seq) {
-        try {
-            mISession.cancelSessionCommand(caller, seq);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Stub implementation for IMediaSession2.connect */
-    public void onConnect(final Controller2Link caller, int seq, Bundle connectionRequest) {
-        mSession.onConnect(caller, seq, connectionRequest);
-    }
-
-    /** Stub implementation for IMediaSession2.disconnect */
-    public void onDisconnect(final Controller2Link caller, int seq) {
-        mSession.onDisconnect(caller, seq);
-    }
-
-    /** Stub implementation for IMediaSession2.sendSessionCommand */
-    public void onSessionCommand(final Controller2Link caller, final int seq,
-            final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
-        mSession.onSessionCommand(caller, seq, command, args, resultReceiver);
-    }
-
-    /** Stub implementation for IMediaSession2.cancelSessionCommand */
-    public void onCancelCommand(final Controller2Link caller, final int seq) {
-        mSession.onCancelCommand(caller, seq);
-    }
-
-    private class Session2Stub extends IMediaSession2.Stub {
-        @Override
-        public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) {
-            Session2Link.this.onConnect(caller, seq, connectionRequest);
-        }
-
-        @Override
-        public void disconnect(final Controller2Link caller, int seq) {
-            Session2Link.this.onDisconnect(caller, seq);
-        }
-
-        @Override
-        public void sendSessionCommand(final Controller2Link caller, final int seq,
-                final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
-            Session2Link.this.onSessionCommand(caller, seq, command, args, resultReceiver);
-        }
-
-        @Override
-        public void cancelSessionCommand(final Controller2Link caller, final int seq) {
-            Session2Link.this.onCancelCommand(caller, seq);
-        }
-    }
-}
diff --git a/media/java/android/media/Session2Token.java b/media/java/android/media/Session2Token.java
deleted file mode 100644
index 552cc0f..0000000
--- a/media/java/android/media/Session2Token.java
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * 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.media;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Represents an ongoing {@link MediaSession2} or a {@link MediaSession2Service}.
- * If it's representing a session service, it may not be ongoing.
- * <p>
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
- * <p>
- * This may be passed to apps by the session owner to allow them to create a
- * {@link MediaController2} to communicate with the session.
- * <p>
- * It can be also obtained by {@link MediaSessionManager}.
- *
- * @hide
- */
-// New version of MediaSession2.Token for following reasons
-//   - Stop implementing Parcelable for updatable support
-//   - Represent session and library service (formerly browser service) in one class.
-//     Previously MediaSession2.Token was for session and ComponentName was for service.
-//     This helps controller apps to keep target of dispatching media key events in uniform way.
-//     For details about the reason, see following. (Android O+)
-//         android.media.session.MediaSessionManager.Callback#onAddressedPlayerChanged
-public final class Session2Token implements Parcelable {
-    private static final String TAG = "Session2Token";
-
-    public static final Creator<Session2Token> CREATOR = new Creator<Session2Token>() {
-        @Override
-        public Session2Token createFromParcel(Parcel p) {
-            return new Session2Token(p);
-        }
-
-        @Override
-        public Session2Token[] newArray(int size) {
-            return new Session2Token[size];
-        }
-    };
-
-    /**
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "TYPE_", value = {TYPE_SESSION, TYPE_SESSION_SERVICE, TYPE_LIBRARY_SERVICE})
-    public @interface TokenType {
-    }
-
-    /**
-     * Type for {@link MediaSession2}.
-     */
-    public static final int TYPE_SESSION = 0;
-
-    /**
-     * Type for {@link MediaSession2Service}.
-     */
-    public static final int TYPE_SESSION_SERVICE = 1;
-
-    /**
-     * Type for {@link MediaLibrary2Service}.
-     */
-    public static final int TYPE_LIBRARY_SERVICE = 2;
-
-    private final int mUid;
-    private final @TokenType int mType;
-    private final String mPackageName;
-    private final String mServiceName;
-    private final Session2Link mSessionLink;
-    private final ComponentName mComponentName;
-
-    /**
-     * Constructor for the token.
-     *
-     * @param context The context.
-     * @param serviceComponent The component name of the service.
-     */
-    public Session2Token(@NonNull Context context, @NonNull ComponentName serviceComponent) {
-        if (context == null) {
-            throw new IllegalArgumentException("context shouldn't be null");
-        }
-        if (serviceComponent == null) {
-            throw new IllegalArgumentException("serviceComponent shouldn't be null");
-        }
-
-        final PackageManager manager = context.getPackageManager();
-        final int uid = getUid(manager, serviceComponent.getPackageName());
-
-        // TODO: Uncomment below to stop hardcode type.
-        final int type = TYPE_SESSION;
-//        final int type;
-//        if (isInterfaceDeclared(manager, MediaLibraryService2.SERVICE_INTERFACE,
-//                serviceComponent)) {
-//            type = TYPE_LIBRARY_SERVICE;
-//        } else if (isInterfaceDeclared(manager, MediaSessionService2.SERVICE_INTERFACE,
-//                    serviceComponent)) {
-//            type = TYPE_SESSION_SERVICE;
-//        } else if (isInterfaceDeclared(manager,
-//                        MediaBrowserServiceCompat.SERVICE_INTERFACE, serviceComponent)) {
-//            type = TYPE_BROWSER_SERVICE_LEGACY;
-//        } else {
-//            throw new IllegalArgumentException(serviceComponent + " doesn't implement none of"
-//                    + " MediaSessionService2, MediaLibraryService2, MediaBrowserService nor"
-//                    + " MediaBrowserServiceCompat. Use service's full name.");
-//        }
-        mComponentName = serviceComponent;
-        mPackageName = serviceComponent.getPackageName();
-        mServiceName = serviceComponent.getClassName();
-        mUid = uid;
-        mType = type;
-        mSessionLink = null;
-    }
-
-    Session2Token(int uid, int type, String packageName, Session2Link sessionLink) {
-        mUid = uid;
-        mType = type;
-        mPackageName = packageName;
-        mServiceName = null;
-        mComponentName = null;
-        mSessionLink = sessionLink;
-    }
-
-    Session2Token(Parcel in) {
-        mUid = in.readInt();
-        mType = in.readInt();
-        mPackageName = in.readString();
-        mServiceName = in.readString();
-        // TODO: Uncomment below and stop hardcode mSessionLink
-        mSessionLink = null;
-        //mSessionLink = ISession.Stub.asInterface(in.readStrongBinder());
-        mComponentName = ComponentName.unflattenFromString(in.readString());
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mUid);
-        dest.writeInt(mType);
-        dest.writeString(mPackageName);
-        dest.writeString(mServiceName);
-        // TODO: Uncomment below
-        //dest.writeStrongBinder(mSessionLink.getBinder());
-        dest.writeString(mComponentName == null ? "" : mComponentName.flattenToString());
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mType, mUid, mPackageName, mServiceName, mSessionLink);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof Session2Token)) {
-            return false;
-        }
-        Session2Token other = (Session2Token) obj;
-        return mUid == other.mUid
-                && TextUtils.equals(mPackageName, other.mPackageName)
-                && TextUtils.equals(mServiceName, other.mServiceName)
-                && mType == other.mType
-                && Objects.equals(mSessionLink, other.mSessionLink);
-    }
-
-    @Override
-    public String toString() {
-        return "Session2Token {pkg=" + mPackageName + " type=" + mType
-                + " service=" + mServiceName + " Session2Link=" + mSessionLink + "}";
-    }
-
-    /**
-     * @return uid of the session
-     */
-    public int getUid() {
-        return mUid;
-    }
-
-    /**
-     * @return package name of the session
-     */
-    @NonNull
-    public String getPackageName() {
-        return mPackageName;
-    }
-
-    /**
-     * @return service name of the session. Can be {@code null} for {@link #TYPE_SESSION}.
-     */
-    @Nullable
-    public String getServiceName() {
-        return mServiceName;
-    }
-
-    /**
-     * @hide
-     * @return component name of the session. Can be {@code null} for {@link #TYPE_SESSION}.
-     */
-    public ComponentName getComponentName() {
-        return mComponentName;
-    }
-
-    /**
-     * @return type of the token
-     * @see #TYPE_SESSION
-     * @see #TYPE_SESSION_SERVICE
-     * @see #TYPE_LIBRARY_SERVICE
-     */
-    public @TokenType int getType() {
-        return mType;
-    }
-
-    /**
-     * @hide
-     */
-    public Session2Link getSessionLink() {
-        return mSessionLink;
-    }
-
-    private static boolean isInterfaceDeclared(PackageManager manager, String serviceInterface,
-            ComponentName serviceComponent) {
-        Intent serviceIntent = new Intent(serviceInterface);
-        // Use queryIntentServices to find services with MediaLibraryService2.SERVICE_INTERFACE.
-        // We cannot use resolveService with intent specified class name, because resolveService
-        // ignores actions if Intent.setClassName() is specified.
-        serviceIntent.setPackage(serviceComponent.getPackageName());
-
-        List<ResolveInfo> list = manager.queryIntentServices(
-                serviceIntent, PackageManager.GET_META_DATA);
-        if (list != null) {
-            for (int i = 0; i < list.size(); i++) {
-                ResolveInfo resolveInfo = list.get(i);
-                if (resolveInfo == null || resolveInfo.serviceInfo == null) {
-                    continue;
-                }
-                if (TextUtils.equals(
-                        resolveInfo.serviceInfo.name, serviceComponent.getClassName())) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private static int getUid(PackageManager manager, String packageName) {
-        try {
-            return manager.getApplicationInfo(packageName, 0).uid;
-        } catch (PackageManager.NameNotFoundException e) {
-            throw new IllegalArgumentException("Cannot find package " + packageName);
-        }
-    }
-}
diff --git a/media/java/android/media/VolumeProvider.java b/media/java/android/media/VolumeProvider.java
deleted file mode 100644
index 1c017c5..0000000
--- a/media/java/android/media/VolumeProvider.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media;
-
-import android.annotation.IntDef;
-import android.media.session.MediaSession;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Handles requests to adjust or set the volume on a session. This is also used
- * to push volume updates back to the session. The provider must call
- * {@link #setCurrentVolume(int)} each time the volume being provided changes.
- * <p>
- * You can set a volume provider on a session by calling
- * {@link MediaSession#setPlaybackToRemote}.
- */
-public abstract class VolumeProvider {
-
-    /**
-     * @hide
-     */
-    @IntDef({VOLUME_CONTROL_FIXED, VOLUME_CONTROL_RELATIVE, VOLUME_CONTROL_ABSOLUTE})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface ControlType {}
-
-    /**
-     * The volume is fixed and can not be modified. Requests to change volume
-     * should be ignored.
-     */
-    public static final int VOLUME_CONTROL_FIXED = 0;
-
-    /**
-     * The volume control uses relative adjustment via
-     * {@link #onAdjustVolume(int)}. Attempts to set the volume to a specific
-     * value should be ignored.
-     */
-    public static final int VOLUME_CONTROL_RELATIVE = 1;
-
-    /**
-     * The volume control uses an absolute value. It may be adjusted using
-     * {@link #onAdjustVolume(int)} or set directly using
-     * {@link #onSetVolumeTo(int)}.
-     */
-    public static final int VOLUME_CONTROL_ABSOLUTE = 2;
-
-    private final int mControlType;
-    private final int mMaxVolume;
-    private int mCurrentVolume;
-    private Callback mCallback;
-
-    /**
-     * Create a new volume provider for handling volume events. You must specify
-     * the type of volume control, the maximum volume that can be used, and the
-     * current volume on the output.
-     *
-     * @param volumeControl The method for controlling volume that is used by
-     *            this provider.
-     * @param maxVolume The maximum allowed volume.
-     * @param currentVolume The current volume on the output.
-     */
-    public VolumeProvider(@ControlType int volumeControl, int maxVolume, int currentVolume) {
-        mControlType = volumeControl;
-        mMaxVolume = maxVolume;
-        mCurrentVolume = currentVolume;
-    }
-
-    /**
-     * Get the volume control type that this volume provider uses.
-     *
-     * @return The volume control type for this volume provider
-     */
-    @ControlType
-    public final int getVolumeControl() {
-        return mControlType;
-    }
-
-    /**
-     * Get the maximum volume this provider allows.
-     *
-     * @return The max allowed volume.
-     */
-    public final int getMaxVolume() {
-        return mMaxVolume;
-    }
-
-    /**
-     * Gets the current volume. This will be the last value set by
-     * {@link #setCurrentVolume(int)}.
-     *
-     * @return The current volume.
-     */
-    public final int getCurrentVolume() {
-        return mCurrentVolume;
-    }
-
-    /**
-     * Notify the system that the current volume has been changed. This must be
-     * called every time the volume changes to ensure it is displayed properly.
-     *
-     * @param currentVolume The current volume on the output.
-     */
-    public final void setCurrentVolume(int currentVolume) {
-        mCurrentVolume = currentVolume;
-        if (mCallback != null) {
-            mCallback.onVolumeChanged(this);
-        }
-    }
-
-    /**
-     * Override to handle requests to set the volume of the current output.
-     * After the volume has been modified {@link #setCurrentVolume} must be
-     * called to notify the system.
-     *
-     * @param volume The volume to set the output to.
-     */
-    public void onSetVolumeTo(int volume) {
-    }
-
-    /**
-     * Override to handle requests to adjust the volume of the current output.
-     * Direction will be one of {@link AudioManager#ADJUST_LOWER},
-     * {@link AudioManager#ADJUST_RAISE}, {@link AudioManager#ADJUST_SAME}.
-     * After the volume has been modified {@link #setCurrentVolume} must be
-     * called to notify the system.
-     *
-     * @param direction The direction to change the volume in.
-     */
-    public void onAdjustVolume(int direction) {
-    }
-
-    /**
-     * Sets a callback to receive volume changes.
-     * @hide
-     */
-    public void setCallback(Callback callback) {
-        mCallback = callback;
-    }
-
-    /**
-     * Listens for changes to the volume.
-     * @hide
-     */
-    public static abstract class Callback {
-        public abstract void onVolumeChanged(VolumeProvider volumeProvider);
-    }
-}
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 52e9ae1..5b4bbce 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -26,7 +26,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
-import android.os.Parcelable;
 import android.util.Log;
 
 import java.lang.ref.WeakReference;
@@ -229,7 +228,7 @@
      * The method {@link #queryEffects()} returns an array of Descriptors to facilitate effects
      * enumeration.
      */
-    public static final class Descriptor implements Parcelable {
+    public static class Descriptor {
 
         public Descriptor() {
         }
@@ -294,7 +293,9 @@
             this.implementor = implementor;
         }
 
-        private Descriptor(Parcel in) {
+        /** @hide */
+        @TestApi
+        public Descriptor(Parcel in) {
             type = UUID.fromString(in.readString());
             uuid = UUID.fromString(in.readString());
             connectMode = in.readString();
@@ -302,33 +303,14 @@
             implementor = in.readString();
         }
 
-        public static final Parcelable.Creator<Descriptor> CREATOR =
-                new Parcelable.Creator<Descriptor>() {
-                    /**
-                     * Rebuilds a Descriptor previously stored with writeToParcel().
-                     * @param p Parcel object to read the Descriptor from
-                     * @return a new Descriptor created from the data in the parcel
-                     */
-                    public Descriptor createFromParcel(Parcel p) {
-                        return new Descriptor(p);
-                    }
-                    public Descriptor[] newArray(int size) {
-                        return new Descriptor[size];
-                    }
-        };
-
         @Override
         public int hashCode() {
             return Objects.hash(type, uuid, connectMode, name, implementor);
         }
 
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
+        /** @hide */
+        @TestApi
+        public void writeToParcel(Parcel dest) {
             dest.writeString(type.toString());
             dest.writeString(uuid.toString());
             dest.writeString(connectMode);
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
deleted file mode 100644
index 2bccd88..0000000
--- a/media/java/android/media/browse/MediaBrowser.java
+++ /dev/null
@@ -1,1171 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.browse;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.ParceledListSlice;
-import android.media.MediaDescription;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.service.media.IMediaBrowserService;
-import android.service.media.IMediaBrowserServiceCallbacks;
-import android.service.media.MediaBrowserService;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map.Entry;
-
-/**
- * Browses media content offered by a link MediaBrowserService.
- * <p>
- * This object is not thread-safe. All calls should happen on the thread on which the browser
- * was constructed.
- * </p>
- * <h3>Standard Extra Data</h3>
- *
- * <p>These are the current standard fields that can be used as extra data via
- * {@link #subscribe(String, Bundle, SubscriptionCallback)},
- * {@link #unsubscribe(String, SubscriptionCallback)}, and
- * {@link SubscriptionCallback#onChildrenLoaded(String, List, Bundle)}.
- *
- * <ul>
- *     <li> {@link #EXTRA_PAGE}
- *     <li> {@link #EXTRA_PAGE_SIZE}
- * </ul>
- */
-public final class MediaBrowser {
-    private static final String TAG = "MediaBrowser";
-    private static final boolean DBG = false;
-
-    /**
-     * Used as an int extra field to denote the page number to subscribe.
-     * The value of {@code EXTRA_PAGE} should be greater than or equal to 0.
-     *
-     * @see #EXTRA_PAGE_SIZE
-     */
-    public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
-
-    /**
-     * Used as an int extra field to denote the number of media items in a page.
-     * The value of {@code EXTRA_PAGE_SIZE} should be greater than or equal to 1.
-     *
-     * @see #EXTRA_PAGE
-     */
-    public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
-
-    private static final int CONNECT_STATE_DISCONNECTING = 0;
-    private static final int CONNECT_STATE_DISCONNECTED = 1;
-    private static final int CONNECT_STATE_CONNECTING = 2;
-    private static final int CONNECT_STATE_CONNECTED = 3;
-    private static final int CONNECT_STATE_SUSPENDED = 4;
-
-    private final Context mContext;
-    private final ComponentName mServiceComponent;
-    private final ConnectionCallback mCallback;
-    private final Bundle mRootHints;
-    private final Handler mHandler = new Handler();
-    private final ArrayMap<String, Subscription> mSubscriptions = new ArrayMap<>();
-
-    private volatile int mState = CONNECT_STATE_DISCONNECTED;
-    private volatile String mRootId;
-    private volatile MediaSession.Token mMediaSessionToken;
-    private volatile Bundle mExtras;
-
-    private MediaServiceConnection mServiceConnection;
-    private IMediaBrowserService mServiceBinder;
-    private IMediaBrowserServiceCallbacks mServiceCallbacks;
-
-    /**
-     * Creates a media browser for the specified media browser service.
-     *
-     * @param context The context.
-     * @param serviceComponent The component name of the media browser service.
-     * @param callback The connection callback.
-     * @param rootHints An optional bundle of service-specific arguments to send
-     * to the media browser service when connecting and retrieving the root id
-     * for browsing, or null if none. The contents of this bundle may affect
-     * the information returned when browsing.
-     * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_RECENT
-     * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
-     * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
-     */
-    public MediaBrowser(Context context, ComponentName serviceComponent,
-            ConnectionCallback callback, Bundle rootHints) {
-        if (context == null) {
-            throw new IllegalArgumentException("context must not be null");
-        }
-        if (serviceComponent == null) {
-            throw new IllegalArgumentException("service component must not be null");
-        }
-        if (callback == null) {
-            throw new IllegalArgumentException("connection callback must not be null");
-        }
-        mContext = context;
-        mServiceComponent = serviceComponent;
-        mCallback = callback;
-        mRootHints = rootHints == null ? null : new Bundle(rootHints);
-    }
-
-    /**
-     * Connects to the media browser service.
-     * <p>
-     * The connection callback specified in the constructor will be invoked
-     * when the connection completes or fails.
-     * </p>
-     */
-    public void connect() {
-        if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
-            throw new IllegalStateException("connect() called while neither disconnecting nor "
-                    + "disconnected (state=" + getStateLabel(mState) + ")");
-        }
-
-        mState = CONNECT_STATE_CONNECTING;
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                if (mState == CONNECT_STATE_DISCONNECTING) {
-                    return;
-                }
-                mState = CONNECT_STATE_CONNECTING;
-                // TODO: remove this extra check.
-                if (DBG) {
-                    if (mServiceConnection != null) {
-                        throw new RuntimeException("mServiceConnection should be null. Instead it"
-                                + " is " + mServiceConnection);
-                    }
-                }
-                if (mServiceBinder != null) {
-                    throw new RuntimeException("mServiceBinder should be null. Instead it is "
-                            + mServiceBinder);
-                }
-                if (mServiceCallbacks != null) {
-                    throw new RuntimeException("mServiceCallbacks should be null. Instead it is "
-                            + mServiceCallbacks);
-                }
-
-                final Intent intent = new Intent(MediaBrowserService.SERVICE_INTERFACE);
-                intent.setComponent(mServiceComponent);
-
-                mServiceConnection = new MediaServiceConnection();
-
-                boolean bound = false;
-                try {
-                    bound = mContext.bindService(intent, mServiceConnection,
-                            Context.BIND_AUTO_CREATE);
-                } catch (Exception ex) {
-                    Log.e(TAG, "Failed binding to service " + mServiceComponent);
-                }
-
-                if (!bound) {
-                    // Tell them that it didn't work.
-                    forceCloseConnection();
-                    mCallback.onConnectionFailed();
-                }
-
-                if (DBG) {
-                    Log.d(TAG, "connect...");
-                    dump();
-                }
-            }
-        });
-    }
-
-    /**
-     * Disconnects from the media browser service.
-     * After this, no more callbacks will be received.
-     */
-    public void disconnect() {
-        // It's ok to call this any state, because allowing this lets apps not have
-        // to check isConnected() unnecessarily. They won't appreciate the extra
-        // assertions for this. We do everything we can here to go back to a sane state.
-        mState = CONNECT_STATE_DISCONNECTING;
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                // connect() could be called before this. Then we will disconnect and reconnect.
-                if (mServiceCallbacks != null) {
-                    try {
-                        mServiceBinder.disconnect(mServiceCallbacks);
-                    } catch (RemoteException ex) {
-                        // We are disconnecting anyway. Log, just for posterity but it's not
-                        // a big problem.
-                        Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
-                    }
-                }
-                int state = mState;
-                forceCloseConnection();
-                // If the state was not CONNECT_STATE_DISCONNECTING, keep the state so that
-                // the operation came after disconnect() can be handled properly.
-                if (state != CONNECT_STATE_DISCONNECTING) {
-                    mState = state;
-                }
-                if (DBG) {
-                    Log.d(TAG, "disconnect...");
-                    dump();
-                }
-            }
-        });
-    }
-
-    /**
-     * Null out the variables and unbind from the service. This doesn't include
-     * calling disconnect on the service, because we only try to do that in the
-     * clean shutdown cases.
-     * <p>
-     * Everywhere that calls this EXCEPT for disconnect() should follow it with
-     * a call to mCallback.onConnectionFailed(). Disconnect doesn't do that callback
-     * for a clean shutdown, but everywhere else is a dirty shutdown and should
-     * notify the app.
-     * <p>
-     * Also, mState should be updated properly. Mostly it should be CONNECT_STATE_DIACONNECTED
-     * except for disconnect().
-     */
-    private void forceCloseConnection() {
-        if (mServiceConnection != null) {
-            try {
-                mContext.unbindService(mServiceConnection);
-            } catch (IllegalArgumentException e) {
-                if (DBG) {
-                    Log.d(TAG, "unbindService failed", e);
-                }
-            }
-        }
-        mState = CONNECT_STATE_DISCONNECTED;
-        mServiceConnection = null;
-        mServiceBinder = null;
-        mServiceCallbacks = null;
-        mRootId = null;
-        mMediaSessionToken = null;
-    }
-
-    /**
-     * Returns whether the browser is connected to the service.
-     */
-    public boolean isConnected() {
-        return mState == CONNECT_STATE_CONNECTED;
-    }
-
-    /**
-     * Gets the service component that the media browser is connected to.
-     */
-    public @NonNull ComponentName getServiceComponent() {
-        if (!isConnected()) {
-            throw new IllegalStateException("getServiceComponent() called while not connected" +
-                    " (state=" + mState + ")");
-        }
-        return mServiceComponent;
-    }
-
-    /**
-     * Gets the root id.
-     * <p>
-     * Note that the root id may become invalid or change when the
-     * browser is disconnected.
-     * </p>
-     *
-     * @throws IllegalStateException if not connected.
-     */
-    public @NonNull String getRoot() {
-        if (!isConnected()) {
-            throw new IllegalStateException("getRoot() called while not connected (state="
-                    + getStateLabel(mState) + ")");
-        }
-        return mRootId;
-    }
-
-    /**
-     * Gets any extras for the media service.
-     *
-     * @throws IllegalStateException if not connected.
-     */
-    public @Nullable Bundle getExtras() {
-        if (!isConnected()) {
-            throw new IllegalStateException("getExtras() called while not connected (state="
-                    + getStateLabel(mState) + ")");
-        }
-        return mExtras;
-    }
-
-    /**
-     * Gets the media session token associated with the media browser.
-     * <p>
-     * Note that the session token may become invalid or change when the
-     * browser is disconnected.
-     * </p>
-     *
-     * @return The session token for the browser, never null.
-     *
-     * @throws IllegalStateException if not connected.
-     */
-     public @NonNull MediaSession.Token getSessionToken() {
-        if (!isConnected()) {
-            throw new IllegalStateException("getSessionToken() called while not connected (state="
-                    + mState + ")");
-        }
-        return mMediaSessionToken;
-    }
-
-    /**
-     * Queries for information about the media items that are contained within
-     * the specified id and subscribes to receive updates when they change.
-     * <p>
-     * The list of subscriptions is maintained even when not connected and is
-     * restored after the reconnection. It is ok to subscribe while not connected
-     * but the results will not be returned until the connection completes.
-     * </p>
-     * <p>
-     * If the id is already subscribed with a different callback then the new
-     * callback will replace the previous one and the child data will be
-     * reloaded.
-     * </p>
-     *
-     * @param parentId The id of the parent media item whose list of children
-     *            will be subscribed.
-     * @param callback The callback to receive the list of children.
-     */
-    public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
-        subscribeInternal(parentId, null, callback);
-    }
-
-    /**
-     * Queries with service-specific arguments for information about the media items
-     * that are contained within the specified id and subscribes to receive updates
-     * when they change.
-     * <p>
-     * The list of subscriptions is maintained even when not connected and is
-     * restored after the reconnection. It is ok to subscribe while not connected
-     * but the results will not be returned until the connection completes.
-     * </p>
-     * <p>
-     * If the id is already subscribed with a different callback then the new
-     * callback will replace the previous one and the child data will be
-     * reloaded.
-     * </p>
-     *
-     * @param parentId The id of the parent media item whose list of children
-     *            will be subscribed.
-     * @param options The bundle of service-specific arguments to send to the media
-     *            browser service. The contents of this bundle may affect the
-     *            information returned when browsing.
-     * @param callback The callback to receive the list of children.
-     */
-    public void subscribe(@NonNull String parentId, @NonNull Bundle options,
-            @NonNull SubscriptionCallback callback) {
-        if (options == null) {
-            throw new IllegalArgumentException("options cannot be null");
-        }
-        subscribeInternal(parentId, new Bundle(options), callback);
-    }
-
-    /**
-     * Unsubscribes for changes to the children of the specified media id.
-     * <p>
-     * The query callback will no longer be invoked for results associated with
-     * this id once this method returns.
-     * </p>
-     *
-     * @param parentId The id of the parent media item whose list of children
-     *            will be unsubscribed.
-     */
-    public void unsubscribe(@NonNull String parentId) {
-        unsubscribeInternal(parentId, null);
-    }
-
-    /**
-     * Unsubscribes for changes to the children of the specified media id through a callback.
-     * <p>
-     * The query callback will no longer be invoked for results associated with
-     * this id once this method returns.
-     * </p>
-     *
-     * @param parentId The id of the parent media item whose list of children
-     *            will be unsubscribed.
-     * @param callback A callback sent to the media browser service to subscribe.
-     */
-    public void unsubscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
-        if (callback == null) {
-            throw new IllegalArgumentException("callback cannot be null");
-        }
-        unsubscribeInternal(parentId, callback);
-    }
-
-    /**
-     * Retrieves a specific {@link MediaItem} from the connected service. Not
-     * all services may support this, so falling back to subscribing to the
-     * parent's id should be used when unavailable.
-     *
-     * @param mediaId The id of the item to retrieve.
-     * @param cb The callback to receive the result on.
-     */
-    public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
-        if (TextUtils.isEmpty(mediaId)) {
-            throw new IllegalArgumentException("mediaId cannot be empty.");
-        }
-        if (cb == null) {
-            throw new IllegalArgumentException("cb cannot be null.");
-        }
-        if (mState != CONNECT_STATE_CONNECTED) {
-            Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    cb.onError(mediaId);
-                }
-            });
-            return;
-        }
-        ResultReceiver receiver = new ResultReceiver(mHandler) {
-            @Override
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                if (!isConnected()) {
-                    return;
-                }
-                if (resultCode != 0 || resultData == null
-                        || !resultData.containsKey(MediaBrowserService.KEY_MEDIA_ITEM)) {
-                    cb.onError(mediaId);
-                    return;
-                }
-                Parcelable item = resultData.getParcelable(MediaBrowserService.KEY_MEDIA_ITEM);
-                if (item != null && !(item instanceof MediaItem)) {
-                    cb.onError(mediaId);
-                    return;
-                }
-                cb.onItemLoaded((MediaItem)item);
-            }
-        };
-        try {
-            mServiceBinder.getMediaItem(mediaId, receiver, mServiceCallbacks);
-        } catch (RemoteException e) {
-            Log.i(TAG, "Remote error getting media item.");
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    cb.onError(mediaId);
-                }
-            });
-        }
-    }
-
-    private void subscribeInternal(String parentId, Bundle options, SubscriptionCallback callback) {
-        // Check arguments.
-        if (TextUtils.isEmpty(parentId)) {
-            throw new IllegalArgumentException("parentId cannot be empty.");
-        }
-        if (callback == null) {
-            throw new IllegalArgumentException("callback cannot be null");
-        }
-        // Update or create the subscription.
-        Subscription sub = mSubscriptions.get(parentId);
-        if (sub == null) {
-            sub = new Subscription();
-            mSubscriptions.put(parentId, sub);
-        }
-        sub.putCallback(mContext, options, callback);
-
-        // If we are connected, tell the service that we are watching. If we aren't connected,
-        // the service will be told when we connect.
-        if (isConnected()) {
-            try {
-                if (options == null) {
-                    mServiceBinder.addSubscriptionDeprecated(parentId, mServiceCallbacks);
-                }
-                mServiceBinder.addSubscription(parentId, callback.mToken, options,
-                        mServiceCallbacks);
-            } catch (RemoteException ex) {
-                // Process is crashing. We will disconnect, and upon reconnect we will
-                // automatically reregister. So nothing to do here.
-                Log.d(TAG, "addSubscription failed with RemoteException parentId=" + parentId);
-            }
-        }
-    }
-
-    private void unsubscribeInternal(String parentId, SubscriptionCallback callback) {
-        // Check arguments.
-        if (TextUtils.isEmpty(parentId)) {
-            throw new IllegalArgumentException("parentId cannot be empty.");
-        }
-
-        Subscription sub = mSubscriptions.get(parentId);
-        if (sub == null) {
-            return;
-        }
-        // Tell the service if necessary.
-        try {
-            if (callback == null) {
-                if (isConnected()) {
-                    mServiceBinder.removeSubscriptionDeprecated(parentId, mServiceCallbacks);
-                    mServiceBinder.removeSubscription(parentId, null, mServiceCallbacks);
-                }
-            } else {
-                final List<SubscriptionCallback> callbacks = sub.getCallbacks();
-                final List<Bundle> optionsList = sub.getOptionsList();
-                for (int i = callbacks.size() - 1; i >= 0; --i) {
-                    if (callbacks.get(i) == callback) {
-                        if (isConnected()) {
-                            mServiceBinder.removeSubscription(
-                                    parentId, callback.mToken, mServiceCallbacks);
-                        }
-                        callbacks.remove(i);
-                        optionsList.remove(i);
-                    }
-                }
-            }
-        } catch (RemoteException ex) {
-            // Process is crashing. We will disconnect, and upon reconnect we will
-            // automatically reregister. So nothing to do here.
-            Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId);
-        }
-
-        if (sub.isEmpty() || callback == null) {
-            mSubscriptions.remove(parentId);
-        }
-    }
-
-    /**
-     * For debugging.
-     */
-    private static String getStateLabel(int state) {
-        switch (state) {
-            case CONNECT_STATE_DISCONNECTING:
-                return "CONNECT_STATE_DISCONNECTING";
-            case CONNECT_STATE_DISCONNECTED:
-                return "CONNECT_STATE_DISCONNECTED";
-            case CONNECT_STATE_CONNECTING:
-                return "CONNECT_STATE_CONNECTING";
-            case CONNECT_STATE_CONNECTED:
-                return "CONNECT_STATE_CONNECTED";
-            case CONNECT_STATE_SUSPENDED:
-                return "CONNECT_STATE_SUSPENDED";
-            default:
-                return "UNKNOWN/" + state;
-        }
-    }
-
-    private final void onServiceConnected(final IMediaBrowserServiceCallbacks callback,
-            final String root, final MediaSession.Token session, final Bundle extra) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                // Check to make sure there hasn't been a disconnect or a different
-                // ServiceConnection.
-                if (!isCurrent(callback, "onConnect")) {
-                    return;
-                }
-                // Don't allow them to call us twice.
-                if (mState != CONNECT_STATE_CONNECTING) {
-                    Log.w(TAG, "onConnect from service while mState="
-                            + getStateLabel(mState) + "... ignoring");
-                    return;
-                }
-                mRootId = root;
-                mMediaSessionToken = session;
-                mExtras = extra;
-                mState = CONNECT_STATE_CONNECTED;
-
-                if (DBG) {
-                    Log.d(TAG, "ServiceCallbacks.onConnect...");
-                    dump();
-                }
-                mCallback.onConnected();
-
-                // we may receive some subscriptions before we are connected, so re-subscribe
-                // everything now
-                for (Entry<String, Subscription> subscriptionEntry : mSubscriptions.entrySet()) {
-                    String id = subscriptionEntry.getKey();
-                    Subscription sub = subscriptionEntry.getValue();
-                    List<SubscriptionCallback> callbackList = sub.getCallbacks();
-                    List<Bundle> optionsList = sub.getOptionsList();
-                    for (int i = 0; i < callbackList.size(); ++i) {
-                        try {
-                            mServiceBinder.addSubscription(id, callbackList.get(i).mToken,
-                                    optionsList.get(i), mServiceCallbacks);
-                        } catch (RemoteException ex) {
-                            // Process is crashing. We will disconnect, and upon reconnect we will
-                            // automatically reregister. So nothing to do here.
-                            Log.d(TAG, "addSubscription failed with RemoteException parentId="
-                                    + id);
-                        }
-                    }
-                }
-            }
-        });
-    }
-
-    private final void onConnectionFailed(final IMediaBrowserServiceCallbacks callback) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                Log.e(TAG, "onConnectFailed for " + mServiceComponent);
-
-                // Check to make sure there hasn't been a disconnect or a different
-                // ServiceConnection.
-                if (!isCurrent(callback, "onConnectFailed")) {
-                    return;
-                }
-                // Don't allow them to call us twice.
-                if (mState != CONNECT_STATE_CONNECTING) {
-                    Log.w(TAG, "onConnect from service while mState="
-                            + getStateLabel(mState) + "... ignoring");
-                    return;
-                }
-
-                // Clean up
-                forceCloseConnection();
-
-                // Tell the app.
-                mCallback.onConnectionFailed();
-            }
-        });
-    }
-
-    private final void onLoadChildren(final IMediaBrowserServiceCallbacks callback,
-            final String parentId, final ParceledListSlice list, final Bundle options) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                // Check that there hasn't been a disconnect or a different
-                // ServiceConnection.
-                if (!isCurrent(callback, "onLoadChildren")) {
-                    return;
-                }
-
-                if (DBG) {
-                    Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId);
-                }
-
-                // Check that the subscription is still subscribed.
-                final Subscription subscription = mSubscriptions.get(parentId);
-                if (subscription != null) {
-                    // Tell the app.
-                    SubscriptionCallback subscriptionCallback =
-                            subscription.getCallback(mContext, options);
-                    if (subscriptionCallback != null) {
-                        List<MediaItem> data = list == null ? null : list.getList();
-                        if (options == null) {
-                            if (data == null) {
-                                subscriptionCallback.onError(parentId);
-                            } else {
-                                subscriptionCallback.onChildrenLoaded(parentId, data);
-                            }
-                        } else {
-                            if (data == null) {
-                                subscriptionCallback.onError(parentId, options);
-                            } else {
-                                subscriptionCallback.onChildrenLoaded(parentId, data, options);
-                            }
-                        }
-                        return;
-                    }
-                }
-                if (DBG) {
-                    Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" + parentId);
-                }
-            }
-        });
-    }
-
-    /**
-     * Return true if {@code callback} is the current ServiceCallbacks. Also logs if it's not.
-     */
-    private boolean isCurrent(IMediaBrowserServiceCallbacks callback, String funcName) {
-        if (mServiceCallbacks != callback || mState == CONNECT_STATE_DISCONNECTING
-                || mState == CONNECT_STATE_DISCONNECTED) {
-            if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
-                Log.i(TAG, funcName + " for " + mServiceComponent + " with mServiceConnection="
-                        + mServiceCallbacks + " this=" + this);
-            }
-            return false;
-        }
-        return true;
-    }
-
-    private ServiceCallbacks getNewServiceCallbacks() {
-        return new ServiceCallbacks(this);
-    }
-
-    /**
-     * Log internal state.
-     * @hide
-     */
-    void dump() {
-        Log.d(TAG, "MediaBrowser...");
-        Log.d(TAG, "  mServiceComponent=" + mServiceComponent);
-        Log.d(TAG, "  mCallback=" + mCallback);
-        Log.d(TAG, "  mRootHints=" + mRootHints);
-        Log.d(TAG, "  mState=" + getStateLabel(mState));
-        Log.d(TAG, "  mServiceConnection=" + mServiceConnection);
-        Log.d(TAG, "  mServiceBinder=" + mServiceBinder);
-        Log.d(TAG, "  mServiceCallbacks=" + mServiceCallbacks);
-        Log.d(TAG, "  mRootId=" + mRootId);
-        Log.d(TAG, "  mMediaSessionToken=" + mMediaSessionToken);
-    }
-
-    /**
-     * A class with information on a single media item for use in browsing/searching media.
-     * MediaItems are application dependent so we cannot guarantee that they contain the
-     * right values.
-     */
-    public static class MediaItem implements Parcelable {
-        private final int mFlags;
-        private final MediaDescription mDescription;
-
-        /** @hide */
-        @Retention(RetentionPolicy.SOURCE)
-        @IntDef(flag=true, value = { FLAG_BROWSABLE, FLAG_PLAYABLE })
-        public @interface Flags { }
-
-        /**
-         * Flag: Indicates that the item has children of its own.
-         */
-        public static final int FLAG_BROWSABLE = 1 << 0;
-
-        /**
-         * Flag: Indicates that the item is playable.
-         * <p>
-         * The id of this item may be passed to
-         * {@link MediaController.TransportControls#playFromMediaId(String, Bundle)}
-         * to start playing it.
-         * </p>
-         */
-        public static final int FLAG_PLAYABLE = 1 << 1;
-
-        /**
-         * Create a new MediaItem for use in browsing media.
-         * @param description The description of the media, which must include a
-         *            media id.
-         * @param flags The flags for this item.
-         */
-        public MediaItem(@NonNull MediaDescription description, @Flags int flags) {
-            if (description == null) {
-                throw new IllegalArgumentException("description cannot be null");
-            }
-            if (TextUtils.isEmpty(description.getMediaId())) {
-                throw new IllegalArgumentException("description must have a non-empty media id");
-            }
-            mFlags = flags;
-            mDescription = description;
-        }
-
-        /**
-         * Private constructor.
-         */
-        private MediaItem(Parcel in) {
-            mFlags = in.readInt();
-            mDescription = MediaDescription.CREATOR.createFromParcel(in);
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeInt(mFlags);
-            mDescription.writeToParcel(out, flags);
-        }
-
-        @Override
-        public String toString() {
-            final StringBuilder sb = new StringBuilder("MediaItem{");
-            sb.append("mFlags=").append(mFlags);
-            sb.append(", mDescription=").append(mDescription);
-            sb.append('}');
-            return sb.toString();
-        }
-
-        public static final Parcelable.Creator<MediaItem> CREATOR =
-                new Parcelable.Creator<MediaItem>() {
-                    @Override
-                    public MediaItem createFromParcel(Parcel in) {
-                        return new MediaItem(in);
-                    }
-
-                    @Override
-                    public MediaItem[] newArray(int size) {
-                        return new MediaItem[size];
-                    }
-                };
-
-        /**
-         * Gets the flags of the item.
-         */
-        public @Flags int getFlags() {
-            return mFlags;
-        }
-
-        /**
-         * Returns whether this item is browsable.
-         * @see #FLAG_BROWSABLE
-         */
-        public boolean isBrowsable() {
-            return (mFlags & FLAG_BROWSABLE) != 0;
-        }
-
-        /**
-         * Returns whether this item is playable.
-         * @see #FLAG_PLAYABLE
-         */
-        public boolean isPlayable() {
-            return (mFlags & FLAG_PLAYABLE) != 0;
-        }
-
-        /**
-         * Returns the description of the media.
-         */
-        public @NonNull MediaDescription getDescription() {
-            return mDescription;
-        }
-
-        /**
-         * Returns the media id in the {@link MediaDescription} for this item.
-         * @see android.media.MediaMetadata#METADATA_KEY_MEDIA_ID
-         */
-        public @Nullable String getMediaId() {
-            return mDescription.getMediaId();
-        }
-    }
-
-    /**
-     * Callbacks for connection related events.
-     */
-    public static class ConnectionCallback {
-        /**
-         * Invoked after {@link MediaBrowser#connect()} when the request has successfully completed.
-         */
-        public void onConnected() {
-        }
-
-        /**
-         * Invoked when the client is disconnected from the media browser.
-         */
-        public void onConnectionSuspended() {
-        }
-
-        /**
-         * Invoked when the connection to the media browser failed.
-         */
-        public void onConnectionFailed() {
-        }
-    }
-
-    /**
-     * Callbacks for subscription related events.
-     */
-    public static abstract class SubscriptionCallback {
-        Binder mToken;
-
-        public SubscriptionCallback() {
-            mToken = new Binder();
-        }
-
-        /**
-         * Called when the list of children is loaded or updated.
-         *
-         * @param parentId The media id of the parent media item.
-         * @param children The children which were loaded.
-         */
-        public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children) {
-        }
-
-        /**
-         * Called when the list of children is loaded or updated.
-         *
-         * @param parentId The media id of the parent media item.
-         * @param children The children which were loaded.
-         * @param options The bundle of service-specific arguments sent to the media
-         *            browser service. The contents of this bundle may affect the
-         *            information returned when browsing.
-         */
-        public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children,
-                @NonNull Bundle options) {
-        }
-
-        /**
-         * Called when the id doesn't exist or other errors in subscribing.
-         * <p>
-         * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
-         * called, because some errors may heal themselves.
-         * </p>
-         *
-         * @param parentId The media id of the parent media item whose children could
-         *            not be loaded.
-         */
-        public void onError(@NonNull String parentId) {
-        }
-
-        /**
-         * Called when the id doesn't exist or other errors in subscribing.
-         * <p>
-         * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
-         * called, because some errors may heal themselves.
-         * </p>
-         *
-         * @param parentId The media id of the parent media item whose children could
-         *            not be loaded.
-         * @param options The bundle of service-specific arguments sent to the media
-         *            browser service.
-         */
-        public void onError(@NonNull String parentId, @NonNull Bundle options) {
-        }
-    }
-
-    /**
-     * Callback for receiving the result of {@link #getItem}.
-     */
-    public static abstract class ItemCallback {
-        /**
-         * Called when the item has been returned by the connected service.
-         *
-         * @param item The item that was returned or null if it doesn't exist.
-         */
-        public void onItemLoaded(MediaItem item) {
-        }
-
-        /**
-         * Called there was an error retrieving it or the connected service doesn't support
-         * {@link #getItem}.
-         *
-         * @param mediaId The media id of the media item which could not be loaded.
-         */
-        public void onError(@NonNull String mediaId) {
-        }
-    }
-
-    /**
-     * ServiceConnection to the other app.
-     */
-    private class MediaServiceConnection implements ServiceConnection {
-        @Override
-        public void onServiceConnected(final ComponentName name, final IBinder binder) {
-            postOrRun(new Runnable() {
-                @Override
-                public void run() {
-                    if (DBG) {
-                        Log.d(TAG, "MediaServiceConnection.onServiceConnected name=" + name
-                                + " binder=" + binder);
-                        dump();
-                    }
-
-                    // Make sure we are still the current connection, and that they haven't called
-                    // disconnect().
-                    if (!isCurrent("onServiceConnected")) {
-                        return;
-                    }
-
-                    // Save their binder
-                    mServiceBinder = IMediaBrowserService.Stub.asInterface(binder);
-
-                    // We make a new mServiceCallbacks each time we connect so that we can drop
-                    // responses from previous connections.
-                    mServiceCallbacks = getNewServiceCallbacks();
-                    mState = CONNECT_STATE_CONNECTING;
-
-                    // Call connect, which is async. When we get a response from that we will
-                    // say that we're connected.
-                    try {
-                        if (DBG) {
-                            Log.d(TAG, "ServiceCallbacks.onConnect...");
-                            dump();
-                        }
-                        mServiceBinder.connect(mContext.getPackageName(), mRootHints,
-                                mServiceCallbacks);
-                    } catch (RemoteException ex) {
-                        // Connect failed, which isn't good. But the auto-reconnect on the service
-                        // will take over and we will come back. We will also get the
-                        // onServiceDisconnected, which has all the cleanup code. So let that do
-                        // it.
-                        Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
-                        if (DBG) {
-                            Log.d(TAG, "ServiceCallbacks.onConnect...");
-                            dump();
-                        }
-                    }
-                }
-            });
-        }
-
-        @Override
-        public void onServiceDisconnected(final ComponentName name) {
-            postOrRun(new Runnable() {
-                @Override
-                public void run() {
-                    if (DBG) {
-                        Log.d(TAG, "MediaServiceConnection.onServiceDisconnected name=" + name
-                                + " this=" + this + " mServiceConnection=" + mServiceConnection);
-                        dump();
-                    }
-
-                    // Make sure we are still the current connection, and that they haven't called
-                    // disconnect().
-                    if (!isCurrent("onServiceDisconnected")) {
-                        return;
-                    }
-
-                    // Clear out what we set in onServiceConnected
-                    mServiceBinder = null;
-                    mServiceCallbacks = null;
-
-                    // And tell the app that it's suspended.
-                    mState = CONNECT_STATE_SUSPENDED;
-                    mCallback.onConnectionSuspended();
-                }
-            });
-        }
-
-        private void postOrRun(Runnable r) {
-            if (Thread.currentThread() == mHandler.getLooper().getThread()) {
-                r.run();
-            } else {
-                mHandler.post(r);
-            }
-        }
-
-        /**
-         * Return true if this is the current ServiceConnection. Also logs if it's not.
-         */
-        private boolean isCurrent(String funcName) {
-            if (mServiceConnection != this || mState == CONNECT_STATE_DISCONNECTING
-                    || mState == CONNECT_STATE_DISCONNECTED) {
-                if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
-                    // Check mState, because otherwise this log is noisy.
-                    Log.i(TAG, funcName + " for " + mServiceComponent + " with mServiceConnection="
-                            + mServiceConnection + " this=" + this);
-                }
-                return false;
-            }
-            return true;
-        }
-    }
-
-    /**
-     * Callbacks from the service.
-     */
-    private static class ServiceCallbacks extends IMediaBrowserServiceCallbacks.Stub {
-        private WeakReference<MediaBrowser> mMediaBrowser;
-
-        public ServiceCallbacks(MediaBrowser mediaBrowser) {
-            mMediaBrowser = new WeakReference<MediaBrowser>(mediaBrowser);
-        }
-
-        /**
-         * The other side has acknowledged our connection. The parameters to this function
-         * are the initial data as requested.
-         */
-        @Override
-        public void onConnect(String root, MediaSession.Token session,
-                final Bundle extras) {
-            MediaBrowser mediaBrowser = mMediaBrowser.get();
-            if (mediaBrowser != null) {
-                mediaBrowser.onServiceConnected(this, root, session, extras);
-            }
-        }
-
-        /**
-         * The other side does not like us. Tell the app via onConnectionFailed.
-         */
-        @Override
-        public void onConnectFailed() {
-            MediaBrowser mediaBrowser = mMediaBrowser.get();
-            if (mediaBrowser != null) {
-                mediaBrowser.onConnectionFailed(this);
-            }
-        }
-
-        @Override
-        public void onLoadChildren(String parentId, ParceledListSlice list) {
-            onLoadChildrenWithOptions(parentId, list, null);
-        }
-
-        @Override
-        public void onLoadChildrenWithOptions(String parentId, ParceledListSlice list,
-                final Bundle options) {
-            MediaBrowser mediaBrowser = mMediaBrowser.get();
-            if (mediaBrowser != null) {
-                mediaBrowser.onLoadChildren(this, parentId, list, options);
-            }
-        }
-    }
-
-    private static class Subscription {
-        private final List<SubscriptionCallback> mCallbacks;
-        private final List<Bundle> mOptionsList;
-
-        public Subscription() {
-            mCallbacks = new ArrayList<>();
-            mOptionsList = new ArrayList<>();
-        }
-
-        public boolean isEmpty() {
-            return mCallbacks.isEmpty();
-        }
-
-        public List<Bundle> getOptionsList() {
-            return mOptionsList;
-        }
-
-        public List<SubscriptionCallback> getCallbacks() {
-            return mCallbacks;
-        }
-
-        public SubscriptionCallback getCallback(Context context, Bundle options) {
-            if (options != null) {
-                options.setClassLoader(context.getClassLoader());
-            }
-            for (int i = 0; i < mOptionsList.size(); ++i) {
-                if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
-                    return mCallbacks.get(i);
-                }
-            }
-            return null;
-        }
-
-        public void putCallback(Context context, Bundle options, SubscriptionCallback callback) {
-            if (options != null) {
-                options.setClassLoader(context.getClassLoader());
-            }
-            for (int i = 0; i < mOptionsList.size(); ++i) {
-                if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
-                    mCallbacks.set(i, callback);
-                    return;
-                }
-            }
-            mCallbacks.add(callback);
-            mOptionsList.add(options);
-        }
-    }
-}
diff --git a/media/java/android/media/browse/MediaBrowserUtils.java b/media/java/android/media/browse/MediaBrowserUtils.java
deleted file mode 100644
index 2943e60..0000000
--- a/media/java/android/media/browse/MediaBrowserUtils.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.browse;
-
-import android.os.Bundle;
-
-/**
- * @hide
- */
-public class MediaBrowserUtils {
-    public static boolean areSameOptions(Bundle options1, Bundle options2) {
-        if (options1 == options2) {
-            return true;
-        } else if (options1 == null) {
-            return options2.getInt(MediaBrowser.EXTRA_PAGE, -1) == -1
-                    && options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1) == -1;
-        } else if (options2 == null) {
-            return options1.getInt(MediaBrowser.EXTRA_PAGE, -1) == -1
-                    && options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1) == -1;
-        } else {
-            return options1.getInt(MediaBrowser.EXTRA_PAGE, -1)
-                    == options2.getInt(MediaBrowser.EXTRA_PAGE, -1)
-                    && options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1)
-                    == options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
-        }
-    }
-
-    public static boolean hasDuplicatedItems(Bundle options1, Bundle options2) {
-        int page1 = options1 == null ? -1 : options1.getInt(MediaBrowser.EXTRA_PAGE, -1);
-        int page2 = options2 == null ? -1 : options2.getInt(MediaBrowser.EXTRA_PAGE, -1);
-        int pageSize1 = options1 == null ? -1 : options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
-        int pageSize2 = options2 == null ? -1 : options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
-
-        int startIndex1, startIndex2, endIndex1, endIndex2;
-        if (page1 == -1 || pageSize1 == -1) {
-            startIndex1 = 0;
-            endIndex1 = Integer.MAX_VALUE;
-        } else {
-            startIndex1 = pageSize1 * page1;
-            endIndex1 = startIndex1 + pageSize1 - 1;
-        }
-
-        if (page2 == -1 || pageSize2 == -1) {
-            startIndex2 = 0;
-            endIndex2 = Integer.MAX_VALUE;
-        } else {
-            startIndex2 = pageSize2 * page2;
-            endIndex2 = startIndex2 + pageSize2 - 1;
-        }
-
-        if (startIndex1 <= startIndex2 && startIndex2 <= endIndex1) {
-            return true;
-        } else if (startIndex1 <= endIndex2 && endIndex2 <= endIndex1) {
-            return true;
-        }
-        return false;
-    }
-}
diff --git a/media/java/android/media/session/ControllerCallbackLink.aidl b/media/java/android/media/session/ControllerCallbackLink.aidl
deleted file mode 100644
index 788f5d3..0000000
--- a/media/java/android/media/session/ControllerCallbackLink.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * 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.media.session;
-
-parcelable ControllerCallbackLink;
diff --git a/media/java/android/media/session/ControllerCallbackLink.java b/media/java/android/media/session/ControllerCallbackLink.java
deleted file mode 100644
index 19da7ce..0000000
--- a/media/java/android/media/session/ControllerCallbackLink.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * 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.media.session;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.media.AudioAttributes;
-import android.media.MediaMetadata;
-import android.media.session.MediaSession.QueueItem;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-
-import java.util.List;
-
-/**
- * Handles incoming commands to {@link MediaController.Callback}.
- * @hide
- */
-@SystemApi
-public final class ControllerCallbackLink implements Parcelable {
-    CallbackStub mCallbackStub;
-    ISessionControllerCallback mIControllerCallback;
-
-    /**
-     * Creator for stub (Callee)
-     */
-    public ControllerCallbackLink(@NonNull CallbackStub callbackStub) {
-        mCallbackStub = callbackStub;
-        mIControllerCallback = new CallbackStubProxy();
-    }
-
-    /**
-     * Creator for interface (Caller)
-     */
-    ControllerCallbackLink(Parcel in) {
-        mCallbackStub = null;
-        mIControllerCallback = ISessionControllerCallback.Stub.asInterface(in.readStrongBinder());
-    }
-
-    /** Interface method for ISessionControllerCallback.notifySessionDestroyed */
-    public void notifySessionDestroyed() {
-        try {
-            mIControllerCallback.notifySessionDestroyed();
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionControllerCallback.notifyEvent */
-    public void notifyEvent(String event, Bundle extras) {
-        try {
-            mIControllerCallback.notifyEvent(event, extras);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionControllerCallback.notifyPlaybackStateChanged */
-    public void notifyPlaybackStateChanged(PlaybackState state) {
-        try {
-            mIControllerCallback.notifyPlaybackStateChanged(state);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionControllerCallback.notifyMetadataChanged */
-    public void notifyMetadataChanged(MediaMetadata metadata) {
-        try {
-            mIControllerCallback.notifyMetadataChanged(metadata);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionControllerCallback.notifyQueueChanged */
-    public void notifyQueueChanged(List<QueueItem> queue) {
-        try {
-            mIControllerCallback.notifyQueueChanged(queue);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionControllerCallback.notifyQueueTitleChanged */
-    public void notifyQueueTitleChanged(CharSequence title) {
-        try {
-            mIControllerCallback.notifyQueueTitleChanged(title);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionControllerCallback.notifyExtrasChanged */
-    public void notifyExtrasChanged(Bundle extras) {
-        try {
-            mIControllerCallback.notifyExtrasChanged(extras);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionControllerCallback.notifyVolumeInfoChanged */
-    public void notifyVolumeInfoChanged(int volumeType, AudioAttributes attrs, int controlType,
-            int maxVolume, int currentVolume) {
-        try {
-            mIControllerCallback.notifyVolumeInfoChanged(volumeType, attrs, controlType, maxVolume,
-                    currentVolume);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Gets the binder */
-    public IBinder getBinder() {
-        return mIControllerCallback.asBinder();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongBinder(mIControllerCallback.asBinder());
-    }
-
-    public static final Parcelable.Creator<ControllerCallbackLink> CREATOR =
-            new Parcelable.Creator<ControllerCallbackLink>() {
-        @Override
-        public ControllerCallbackLink createFromParcel(Parcel in) {
-            return new ControllerCallbackLink(in);
-        }
-
-        @Override
-        public ControllerCallbackLink[] newArray(int size) {
-            return new ControllerCallbackLink[size];
-        }
-    };
-
-    /**
-     * Class for Stub implementation
-     */
-    public abstract static class CallbackStub {
-        /** Stub method for ISessionControllerCallback.notifySessionDestroyed */
-        public void onSessionDestroyed() {
-        }
-
-        /** Stub method for ISessionControllerCallback.notifyEvent */
-        public void onEvent(String event, Bundle extras) {
-        }
-
-        /** Stub method for ISessionControllerCallback.notifyPlaybackStateChanged */
-        public void onPlaybackStateChanged(PlaybackState state) {
-        }
-
-        /** Stub method for ISessionControllerCallback.notifyMetadataChanged */
-        public void onMetadataChanged(MediaMetadata metadata) {
-        }
-
-        /** Stub method for ISessionControllerCallback.notifyQueueChanged */
-        public void onQueueChanged(List<QueueItem> queue) {
-        }
-
-        /** Stub method for ISessionControllerCallback.notifyQueueTitleChanged */
-        public void onQueueTitleChanged(CharSequence title) {
-        }
-
-        /** Stub method for ISessionControllerCallback.notifyExtrasChanged */
-        public void onExtrasChanged(Bundle extras) {
-        }
-
-        /** Stub method for ISessionControllerCallback.notifyVolumeInfoChanged */
-        public void onVolumeInfoChanged(int volumeType, AudioAttributes attrs, int controlType,
-                int maxVolume, int currentVolume) {
-        }
-    }
-
-    private class CallbackStubProxy extends ISessionControllerCallback.Stub {
-        @Override
-        public void notifyEvent(String event, Bundle extras) {
-            mCallbackStub.onEvent(event, extras);
-        }
-
-        @Override
-        public void notifySessionDestroyed() {
-            mCallbackStub.onSessionDestroyed();
-        }
-
-        @Override
-        public void notifyPlaybackStateChanged(PlaybackState state) {
-            mCallbackStub.onPlaybackStateChanged(state);
-        }
-
-        @Override
-        public void notifyMetadataChanged(MediaMetadata metadata) {
-            mCallbackStub.onMetadataChanged(metadata);
-        }
-
-        @Override
-        public void notifyQueueChanged(List<QueueItem> queue) {
-            mCallbackStub.onQueueChanged(queue);
-        }
-
-        @Override
-        public void notifyQueueTitleChanged(CharSequence title) {
-            mCallbackStub.onQueueTitleChanged(title);
-        }
-
-        @Override
-        public void notifyExtrasChanged(Bundle extras) {
-            mCallbackStub.onExtrasChanged(extras);
-        }
-
-        @Override
-        public void notifyVolumeInfoChanged(int volumeType, AudioAttributes attrs, int controlType,
-                int maxVolume, int currentVolume) {
-            mCallbackStub.onVolumeInfoChanged(volumeType, attrs, controlType, maxVolume,
-                    currentVolume);
-        }
-    }
-}
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
deleted file mode 100644
index 5cf6dfe..0000000
--- a/media/java/android/media/session/ISession.aidl
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.session;
-
-import android.app.PendingIntent;
-import android.media.AudioAttributes;
-import android.media.MediaMetadata;
-import android.media.session.ISessionController;
-import android.media.session.PlaybackState;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-/**
- * Interface to a MediaSession in the system.
- * @hide
- */
-interface ISession {
-    void sendEvent(String event, in Bundle data);
-    ISessionController getController();
-    void setFlags(int flags);
-    void setActive(boolean active);
-    void setMediaButtonReceiver(in PendingIntent mbr);
-    void setLaunchPendingIntent(in PendingIntent pi);
-    void destroy();
-
-    // These commands are for the TransportPerformer
-    void setMetadata(in MediaMetadata metadata, long duration, String metadataDescription);
-    void setPlaybackState(in PlaybackState state);
-    void setQueue(in List<MediaSession.QueueItem> queue);
-    void setQueueTitle(CharSequence title);
-    void setExtras(in Bundle extras);
-    void setRatingType(int type);
-
-    // These commands relate to volume handling
-    void setPlaybackToLocal(in AudioAttributes attributes);
-    void setPlaybackToRemote(int control, int max);
-    void setCurrentVolume(int currentVolume);
-}
diff --git a/media/java/android/media/session/ISession2TokensListener.aidl b/media/java/android/media/session/ISession2TokensListener.aidl
new file mode 100644
index 0000000..7d1a4aa
--- /dev/null
+++ b/media/java/android/media/session/ISession2TokensListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.session;
+
+import android.media.Session2Token;
+
+/**
+ * Listens for changes to the list of session2 tokens.
+ * @hide
+ */
+oneway interface ISession2TokensListener {
+    void onSession2TokensChanged(in List<Session2Token> tokens);
+}
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
deleted file mode 100644
index 5c1915b..0000000
--- a/media/java/android/media/session/ISessionController.aidl
+++ /dev/null
@@ -1,87 +0,0 @@
-/* Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.session;
-
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.media.MediaMetadata;
-import android.media.Rating;
-import android.media.session.ControllerCallbackLink;
-import android.media.session.MediaSession;
-import android.media.session.ParcelableVolumeInfo;
-import android.media.session.PlaybackState;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-import android.view.KeyEvent;
-
-import java.util.List;
-
-/**
- * Interface to MediaSessionRecord in the system.
- * @hide
- */
-interface ISessionController {
-    void sendCommand(String packageName, in ControllerCallbackLink caller,
-            String command, in Bundle args, in ResultReceiver cb);
-    boolean sendMediaButton(String packageName, in ControllerCallbackLink caller,
-            boolean asSystemService, in KeyEvent mediaButton);
-    void registerCallbackListener(String packageName, in ControllerCallbackLink cb);
-    void unregisterCallbackListener(in ControllerCallbackLink cb);
-    boolean isTransportControlEnabled();
-    String getPackageName();
-    String getTag();
-    PendingIntent getLaunchPendingIntent();
-    long getFlags();
-    ParcelableVolumeInfo getVolumeAttributes();
-    void adjustVolume(String packageName, in ControllerCallbackLink caller,
-            boolean asSystemService, int direction, int flags);
-    void setVolumeTo(String packageName, in ControllerCallbackLink caller,
-            int value, int flags);
-
-    // These commands are for the TransportControls
-    void prepare(String packageName, in ControllerCallbackLink caller);
-    void prepareFromMediaId(String packageName, in ControllerCallbackLink caller,
-            String mediaId, in Bundle extras);
-    void prepareFromSearch(String packageName, in ControllerCallbackLink caller,
-            String string, in Bundle extras);
-    void prepareFromUri(String packageName, in ControllerCallbackLink caller,
-            in Uri uri, in Bundle extras);
-    void play(String packageName, in ControllerCallbackLink caller);
-    void playFromMediaId(String packageName, in ControllerCallbackLink caller,
-            String mediaId, in Bundle extras);
-    void playFromSearch(String packageName, in ControllerCallbackLink caller,
-            String string, in Bundle extras);
-    void playFromUri(String packageName, in ControllerCallbackLink caller,
-            in Uri uri, in Bundle extras);
-    void skipToQueueItem(String packageName, in ControllerCallbackLink caller, long id);
-    void pause(String packageName, in ControllerCallbackLink caller);
-    void stop(String packageName, in ControllerCallbackLink caller);
-    void next(String packageName, in ControllerCallbackLink caller);
-    void previous(String packageName, in ControllerCallbackLink caller);
-    void fastForward(String packageName, in ControllerCallbackLink caller);
-    void rewind(String packageName, in ControllerCallbackLink caller);
-    void seekTo(String packageName, in ControllerCallbackLink caller, long pos);
-    void rate(String packageName, in ControllerCallbackLink caller, in Rating rating);
-    void sendCustomAction(String packageName, in ControllerCallbackLink caller,
-            String action, in Bundle args);
-    MediaMetadata getMetadata();
-    PlaybackState getPlaybackState();
-    List<MediaSession.QueueItem> getQueue();
-    CharSequence getQueueTitle();
-    Bundle getExtras();
-    int getRatingType();
-}
diff --git a/media/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl
deleted file mode 100644
index 2f86c6c..0000000
--- a/media/java/android/media/session/ISessionControllerCallback.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.session;
-
-import android.media.AudioAttributes;
-import android.media.MediaMetadata;
-import android.media.session.MediaSession;
-import android.media.session.ParcelableVolumeInfo;
-import android.media.session.PlaybackState;
-import android.os.Bundle;
-
-/**
- * @hide
- */
-oneway interface ISessionControllerCallback {
-    void notifyEvent(String event, in Bundle extras);
-    void notifySessionDestroyed();
-
-    // These callbacks are for the TransportController
-    void notifyPlaybackStateChanged(in PlaybackState state);
-    void notifyMetadataChanged(in MediaMetadata metadata);
-    void notifyQueueChanged(in List<MediaSession.QueueItem> queue);
-    void notifyQueueTitleChanged(CharSequence title);
-    void notifyExtrasChanged(in Bundle extras);
-    void notifyVolumeInfoChanged(int volumeType, in AudioAttributes attrs, int controlType,
-            int maxVolume, int currentVolume);
-}
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 5801967..ed16250 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -17,12 +17,15 @@
 
 import android.content.ComponentName;
 import android.media.IRemoteVolumeController;
+import android.media.Session2Token;
+import android.media.session.ControllerLink;
 import android.media.session.IActiveSessionsListener;
 import android.media.session.ICallback;
 import android.media.session.IOnMediaKeyListener;
 import android.media.session.IOnVolumeKeyLongPressListener;
-import android.media.session.ISession;
+import android.media.session.ISession2TokensListener;
 import android.media.session.SessionCallbackLink;
+import android.media.session.SessionLink;
 import android.os.Bundle;
 import android.view.KeyEvent;
 
@@ -31,16 +34,22 @@
  * @hide
  */
 interface ISessionManager {
-    ISession createSession(String packageName, in SessionCallbackLink cb, String tag, int userId);
-    List<IBinder> getSessions(in ComponentName compName, int userId);
+    SessionLink createSession(String packageName, in SessionCallbackLink sessionCb, String tag,
+            int userId);
+    void notifySession2Created(in Session2Token sessionToken);
+    List<ControllerLink> getSessions(in ComponentName compName, int userId);
+    List<Session2Token> getSession2Tokens(int userId);
     void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
             boolean needWakeLock);
-    void dispatchVolumeKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
-            int stream, boolean musicOnly);
-    void dispatchAdjustVolume(String packageName, int suggestedStream, int delta, int flags);
+    void dispatchVolumeKeyEvent(String packageName, String opPackageName, boolean asSystemService,
+            in KeyEvent keyEvent, int stream, boolean musicOnly);
+    void dispatchAdjustVolume(String packageName, String opPackageName, int suggestedStream,
+            int delta, int flags);
     void addSessionsListener(in IActiveSessionsListener listener, in ComponentName compName,
             int userId);
     void removeSessionsListener(in IActiveSessionsListener listener);
+    void addSession2TokensListener(in ISession2TokensListener listener, int userId);
+    void removeSession2TokensListener(in ISession2TokensListener listener);
 
     // This is for the system volume UI only
     void setRemoteVolumeController(in IRemoteVolumeController rvc);
@@ -52,6 +61,5 @@
     void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener);
     void setOnMediaKeyListener(in IOnMediaKeyListener listener);
 
-    // MediaSession2
     boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
 }
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
deleted file mode 100644
index 5eb77f9..0000000
--- a/media/java/android/media/session/MediaController.java
+++ /dev/null
@@ -1,1183 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.session;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.MediaMetadata;
-import android.media.Rating;
-import android.media.VolumeProvider;
-import android.media.session.MediaSession.QueueItem;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.KeyEvent;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Allows an app to interact with an ongoing media session. Media buttons and
- * other commands can be sent to the session. A callback may be registered to
- * receive updates from the session, such as metadata and play state changes.
- * <p>
- * A MediaController can be created through {@link MediaSessionManager} if you
- * hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or are an
- * enabled notification listener or by getting a {@link MediaSession.Token}
- * directly from the session owner.
- * <p>
- * MediaController objects are thread-safe.
- */
-public final class MediaController {
-    private static final String TAG = "MediaController";
-
-    private static final int MSG_EVENT = 1;
-    private static final int MSG_UPDATE_PLAYBACK_STATE = 2;
-    private static final int MSG_UPDATE_METADATA = 3;
-    private static final int MSG_UPDATE_VOLUME = 4;
-    private static final int MSG_UPDATE_QUEUE = 5;
-    private static final int MSG_UPDATE_QUEUE_TITLE = 6;
-    private static final int MSG_UPDATE_EXTRAS = 7;
-    private static final int MSG_DESTROYED = 8;
-
-    private final ISessionController mSessionBinder;
-
-    private final MediaSession.Token mToken;
-    private final Context mContext;
-    private final ControllerCallbackLink mCbStub =
-            new ControllerCallbackLink(new CallbackStub(this));
-    private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>();
-    private final Object mLock = new Object();
-
-    private boolean mCbRegistered = false;
-    private String mPackageName;
-    private String mTag;
-
-    private final TransportControls mTransportControls;
-
-    /**
-     * Call for creating a MediaController directly from a binder. Should only
-     * be used by framework code.
-     *
-     * @hide
-     */
-    public MediaController(Context context, ISessionController sessionBinder) {
-        if (sessionBinder == null) {
-            throw new IllegalArgumentException("Session token cannot be null");
-        }
-        if (context == null) {
-            throw new IllegalArgumentException("Context cannot be null");
-        }
-        mSessionBinder = sessionBinder;
-        mTransportControls = new TransportControls();
-        mToken = new MediaSession.Token(sessionBinder);
-        mContext = context;
-    }
-
-    /**
-     * Create a new MediaController from a session's token.
-     *
-     * @param context The caller's context.
-     * @param token The token for the session.
-     */
-    public MediaController(@NonNull Context context, @NonNull MediaSession.Token token) {
-        this(context, token.getBinder());
-    }
-
-    /**
-     * Get a {@link TransportControls} instance to send transport actions to
-     * the associated session.
-     *
-     * @return A transport controls instance.
-     */
-    public @NonNull TransportControls getTransportControls() {
-        return mTransportControls;
-    }
-
-    /**
-     * Send the specified media button event to the session. Only media keys can
-     * be sent by this method, other keys will be ignored.
-     *
-     * @param keyEvent The media button event to dispatch.
-     * @return true if the event was sent to the session, false otherwise.
-     */
-    public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) {
-        return dispatchMediaButtonEventInternal(false, keyEvent);
-    }
-
-    /**
-     * Dispatches the media button event as system service to the session.
-     * <p>
-     * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
-     * foreground activity didn't consume the key from the hardware devices.
-     *
-     * @param keyEvent media key event
-     * @return {@code true} if the event was sent to the session, {@code false} otherwise
-     * @hide
-     */
-    public boolean dispatchMediaButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
-        return dispatchMediaButtonEventInternal(true, keyEvent);
-    }
-
-    private boolean dispatchMediaButtonEventInternal(boolean asSystemService,
-            @NonNull KeyEvent keyEvent) {
-        if (keyEvent == null) {
-            throw new IllegalArgumentException("KeyEvent may not be null");
-        }
-        if (!KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
-            return false;
-        }
-        try {
-            return mSessionBinder.sendMediaButton(mContext.getOpPackageName(), mCbStub,
-                    asSystemService, keyEvent);
-        } catch (RemoteException e) {
-            // System is dead. =(
-        }
-        return false;
-    }
-
-    /**
-     * Dispatches the volume button event as system service to the session.
-     * <p>
-     * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
-     * foreground activity didn't consume the key from the hardware devices.
-     *
-     * @param keyEvent volume key event
-     * @hide
-     */
-    public void dispatchVolumeButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
-        switch (keyEvent.getAction()) {
-            case KeyEvent.ACTION_DOWN: {
-                int direction = 0;
-                switch (keyEvent.getKeyCode()) {
-                    case KeyEvent.KEYCODE_VOLUME_UP:
-                        direction = AudioManager.ADJUST_RAISE;
-                        break;
-                    case KeyEvent.KEYCODE_VOLUME_DOWN:
-                        direction = AudioManager.ADJUST_LOWER;
-                        break;
-                    case KeyEvent.KEYCODE_VOLUME_MUTE:
-                        direction = AudioManager.ADJUST_TOGGLE_MUTE;
-                        break;
-                }
-                try {
-                    mSessionBinder.adjustVolume(mContext.getOpPackageName(), mCbStub, true,
-                            direction, AudioManager.FLAG_SHOW_UI);
-                } catch (RemoteException e) {
-                    Log.wtf(TAG, "Error calling adjustVolumeBy", e);
-                }
-            }
-
-            case KeyEvent.ACTION_UP: {
-                final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
-                        | AudioManager.FLAG_FROM_KEY;
-                try {
-                    mSessionBinder.adjustVolume(mContext.getOpPackageName(), mCbStub, true, 0,
-                            flags);
-                } catch (RemoteException e) {
-                    Log.wtf(TAG, "Error calling adjustVolumeBy", e);
-                }
-            }
-        }
-    }
-
-    /**
-     * Get the current playback state for this session.
-     *
-     * @return The current PlaybackState or null
-     */
-    public @Nullable PlaybackState getPlaybackState() {
-        try {
-            return mSessionBinder.getPlaybackState();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getPlaybackState.", e);
-            return null;
-        }
-    }
-
-    /**
-     * Get the current metadata for this session.
-     *
-     * @return The current MediaMetadata or null.
-     */
-    public @Nullable MediaMetadata getMetadata() {
-        try {
-            return mSessionBinder.getMetadata();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getMetadata.", e);
-            return null;
-        }
-    }
-
-    /**
-     * Get the current play queue for this session if one is set. If you only
-     * care about the current item {@link #getMetadata()} should be used.
-     *
-     * @return The current play queue or null.
-     */
-    public @Nullable List<MediaSession.QueueItem> getQueue() {
-        try {
-            return mSessionBinder.getQueue();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getQueue.", e);
-        }
-        return null;
-    }
-
-    /**
-     * Get the queue title for this session.
-     */
-    public @Nullable CharSequence getQueueTitle() {
-        try {
-            return mSessionBinder.getQueueTitle();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getQueueTitle", e);
-        }
-        return null;
-    }
-
-    /**
-     * Get the extras for this session.
-     */
-    public @Nullable Bundle getExtras() {
-        try {
-            return mSessionBinder.getExtras();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getExtras", e);
-        }
-        return null;
-    }
-
-    /**
-     * Get the rating type supported by the session. One of:
-     * <ul>
-     * <li>{@link Rating#RATING_NONE}</li>
-     * <li>{@link Rating#RATING_HEART}</li>
-     * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
-     * <li>{@link Rating#RATING_3_STARS}</li>
-     * <li>{@link Rating#RATING_4_STARS}</li>
-     * <li>{@link Rating#RATING_5_STARS}</li>
-     * <li>{@link Rating#RATING_PERCENTAGE}</li>
-     * </ul>
-     *
-     * @return The supported rating type
-     */
-    public int getRatingType() {
-        try {
-            return mSessionBinder.getRatingType();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getRatingType.", e);
-            return Rating.RATING_NONE;
-        }
-    }
-
-    /**
-     * Get the flags for this session. Flags are defined in {@link MediaSession}.
-     *
-     * @return The current set of flags for the session.
-     */
-    public @MediaSession.SessionFlags long getFlags() {
-        try {
-            return mSessionBinder.getFlags();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getFlags.", e);
-        }
-        return 0;
-    }
-
-    /**
-     * Get the current playback info for this session.
-     *
-     * @return The current playback info or null.
-     */
-    public @Nullable PlaybackInfo getPlaybackInfo() {
-        try {
-            ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes();
-            return new PlaybackInfo(result.volumeType, result.audioAttrs, result.controlType,
-                    result.maxVolume, result.currentVolume);
-
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getAudioInfo.", e);
-        }
-        return null;
-    }
-
-    /**
-     * Get an intent for launching UI associated with this session if one
-     * exists.
-     *
-     * @return A {@link PendingIntent} to launch UI or null.
-     */
-    public @Nullable PendingIntent getSessionActivity() {
-        try {
-            return mSessionBinder.getLaunchPendingIntent();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling getPendingIntent.", e);
-        }
-        return null;
-    }
-
-    /**
-     * Get the token for the session this is connected to.
-     *
-     * @return The token for the connected session.
-     */
-    public @NonNull MediaSession.Token getSessionToken() {
-        return mToken;
-    }
-
-    /**
-     * Set the volume of the output this session is playing on. The command will
-     * be ignored if it does not support
-     * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
-     * {@link AudioManager} may be used to affect the handling.
-     *
-     * @see #getPlaybackInfo()
-     * @param value The value to set it to, between 0 and the reported max.
-     * @param flags Flags from {@link AudioManager} to include with the volume
-     *            request.
-     */
-    public void setVolumeTo(int value, int flags) {
-        try {
-            mSessionBinder.setVolumeTo(mContext.getOpPackageName(), mCbStub, value, flags);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling setVolumeTo.", e);
-        }
-    }
-
-    /**
-     * Adjust the volume of the output this session is playing on. The direction
-     * must be one of {@link AudioManager#ADJUST_LOWER},
-     * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}.
-     * The command will be ignored if the session does not support
-     * {@link VolumeProvider#VOLUME_CONTROL_RELATIVE} or
-     * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
-     * {@link AudioManager} may be used to affect the handling.
-     *
-     * @see #getPlaybackInfo()
-     * @param direction The direction to adjust the volume in.
-     * @param flags Any flags to pass with the command.
-     */
-    public void adjustVolume(int direction, int flags) {
-        try {
-            mSessionBinder.adjustVolume(mContext.getOpPackageName(), mCbStub, false, direction,
-                    flags);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
-        }
-    }
-
-    /**
-     * Registers a callback to receive updates from the Session. Updates will be
-     * posted on the caller's thread.
-     *
-     * @param callback The callback object, must not be null.
-     */
-    public void registerCallback(@NonNull Callback callback) {
-        registerCallback(callback, null);
-    }
-
-    /**
-     * Registers a callback to receive updates from the session. Updates will be
-     * posted on the specified handler's thread.
-     *
-     * @param callback The callback object, must not be null.
-     * @param handler The handler to post updates on. If null the callers thread
-     *            will be used.
-     */
-    public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) {
-        if (callback == null) {
-            throw new IllegalArgumentException("callback must not be null");
-        }
-        if (handler == null) {
-            handler = new Handler();
-        }
-        synchronized (mLock) {
-            addCallbackLocked(callback, handler);
-        }
-    }
-
-    /**
-     * Unregisters the specified callback. If an update has already been posted
-     * you may still receive it after calling this method.
-     *
-     * @param callback The callback to remove.
-     */
-    public void unregisterCallback(@NonNull Callback callback) {
-        if (callback == null) {
-            throw new IllegalArgumentException("callback must not be null");
-        }
-        synchronized (mLock) {
-            removeCallbackLocked(callback);
-        }
-    }
-
-    /**
-     * Sends a generic command to the session. It is up to the session creator
-     * to decide what commands and parameters they will support. As such,
-     * commands should only be sent to sessions that the controller owns.
-     *
-     * @param command The command to send
-     * @param args Any parameters to include with the command
-     * @param cb The callback to receive the result on
-     */
-    public void sendCommand(@NonNull String command, @Nullable Bundle args,
-            @Nullable ResultReceiver cb) {
-        if (TextUtils.isEmpty(command)) {
-            throw new IllegalArgumentException("command cannot be null or empty");
-        }
-        try {
-            mSessionBinder.sendCommand(mContext.getOpPackageName(), mCbStub, command, args, cb);
-        } catch (RemoteException e) {
-            Log.d(TAG, "Dead object in sendCommand.", e);
-        }
-    }
-
-    /**
-     * Get the session owner's package name.
-     *
-     * @return The package name of of the session owner.
-     */
-    public String getPackageName() {
-        if (mPackageName == null) {
-            try {
-                mPackageName = mSessionBinder.getPackageName();
-            } catch (RemoteException e) {
-                Log.d(TAG, "Dead object in getPackageName.", e);
-            }
-        }
-        return mPackageName;
-    }
-
-    /**
-     * Get the session's tag for debugging purposes.
-     *
-     * @return The session's tag.
-     * @hide
-     */
-    public String getTag() {
-        if (mTag == null) {
-            try {
-                mTag = mSessionBinder.getTag();
-            } catch (RemoteException e) {
-                Log.d(TAG, "Dead object in getTag.", e);
-            }
-        }
-        return mTag;
-    }
-
-    /*
-     * @hide
-     */
-    ISessionController getSessionBinder() {
-        return mSessionBinder;
-    }
-
-    /**
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public boolean controlsSameSession(MediaController other) {
-        if (other == null) return false;
-        return mSessionBinder.asBinder() == other.getSessionBinder().asBinder();
-    }
-
-    private void addCallbackLocked(Callback cb, Handler handler) {
-        if (getHandlerForCallbackLocked(cb) != null) {
-            Log.w(TAG, "Callback is already added, ignoring");
-            return;
-        }
-        MessageHandler holder = new MessageHandler(handler.getLooper(), cb);
-        mCallbacks.add(holder);
-        holder.mRegistered = true;
-
-        if (!mCbRegistered) {
-            try {
-                mSessionBinder.registerCallbackListener(mContext.getOpPackageName(), mCbStub);
-                mCbRegistered = true;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Dead object in registerCallback", e);
-            }
-        }
-    }
-
-    private boolean removeCallbackLocked(Callback cb) {
-        boolean success = false;
-        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-            MessageHandler handler = mCallbacks.get(i);
-            if (cb == handler.mCallback) {
-                mCallbacks.remove(i);
-                success = true;
-                handler.mRegistered = false;
-            }
-        }
-        if (mCbRegistered && mCallbacks.size() == 0) {
-            try {
-                mSessionBinder.unregisterCallbackListener(mCbStub);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Dead object in removeCallbackLocked");
-            }
-            mCbRegistered = false;
-        }
-        return success;
-    }
-
-    private MessageHandler getHandlerForCallbackLocked(Callback cb) {
-        if (cb == null) {
-            throw new IllegalArgumentException("Callback cannot be null");
-        }
-        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-            MessageHandler handler = mCallbacks.get(i);
-            if (cb == handler.mCallback) {
-                return handler;
-            }
-        }
-        return null;
-    }
-
-    private final void postMessage(int what, Object obj, Bundle data) {
-        synchronized (mLock) {
-            for (int i = mCallbacks.size() - 1; i >= 0; i--) {
-                mCallbacks.get(i).post(what, obj, data);
-            }
-        }
-    }
-
-    /**
-     * Callback for receiving updates from the session. A Callback can be
-     * registered using {@link #registerCallback}.
-     */
-    public static abstract class Callback {
-        /**
-         * Override to handle the session being destroyed. The session is no
-         * longer valid after this call and calls to it will be ignored.
-         */
-        public void onSessionDestroyed() {
-        }
-
-        /**
-         * Override to handle custom events sent by the session owner without a
-         * specified interface. Controllers should only handle these for
-         * sessions they own.
-         *
-         * @param event The event from the session.
-         * @param extras Optional parameters for the event, may be null.
-         */
-        public void onSessionEvent(@NonNull String event, @Nullable Bundle extras) {
-        }
-
-        /**
-         * Override to handle changes in playback state.
-         *
-         * @param state The new playback state of the session
-         */
-        public void onPlaybackStateChanged(@Nullable PlaybackState state) {
-        }
-
-        /**
-         * Override to handle changes to the current metadata.
-         *
-         * @param metadata The current metadata for the session or null if none.
-         * @see MediaMetadata
-         */
-        public void onMetadataChanged(@Nullable MediaMetadata metadata) {
-        }
-
-        /**
-         * Override to handle changes to items in the queue.
-         *
-         * @param queue A list of items in the current play queue. It should
-         *            include the currently playing item as well as previous and
-         *            upcoming items if applicable.
-         * @see MediaSession.QueueItem
-         */
-        public void onQueueChanged(@Nullable List<MediaSession.QueueItem> queue) {
-        }
-
-        /**
-         * Override to handle changes to the queue title.
-         *
-         * @param title The title that should be displayed along with the play queue such as
-         *              "Now Playing". May be null if there is no such title.
-         */
-        public void onQueueTitleChanged(@Nullable CharSequence title) {
-        }
-
-        /**
-         * Override to handle changes to the {@link MediaSession} extras.
-         *
-         * @param extras The extras that can include other information associated with the
-         *               {@link MediaSession}.
-         */
-        public void onExtrasChanged(@Nullable Bundle extras) {
-        }
-
-        /**
-         * Override to handle changes to the audio info.
-         *
-         * @param info The current audio info for this session.
-         */
-        public void onAudioInfoChanged(PlaybackInfo info) {
-        }
-    }
-
-    /**
-     * Interface for controlling media playback on a session. This allows an app
-     * to send media transport commands to the session.
-     */
-    public final class TransportControls {
-        private static final String TAG = "TransportController";
-
-        private TransportControls() {
-        }
-
-        /**
-         * Request that the player prepare its playback. In other words, other sessions can continue
-         * to play during the preparation of this session. This method can be used to speed up the
-         * start of the playback. Once the preparation is done, the session will change its playback
-         * state to {@link PlaybackState#STATE_PAUSED}. Afterwards, {@link #play} can be called to
-         * start playback.
-         */
-        public void prepare() {
-            try {
-                mSessionBinder.prepare(mContext.getOpPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling prepare.", e);
-            }
-        }
-
-        /**
-         * Request that the player prepare playback for a specific media id. In other words, other
-         * sessions can continue to play during the preparation of this session. This method can be
-         * used to speed up the start of the playback. Once the preparation is done, the session
-         * will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
-         * {@link #play} can be called to start playback. If the preparation is not needed,
-         * {@link #playFromMediaId} can be directly called without this method.
-         *
-         * @param mediaId The id of the requested media.
-         * @param extras Optional extras that can include extra information about the media item
-         *               to be prepared.
-         */
-        public void prepareFromMediaId(String mediaId, Bundle extras) {
-            if (TextUtils.isEmpty(mediaId)) {
-                throw new IllegalArgumentException(
-                        "You must specify a non-empty String for prepareFromMediaId.");
-            }
-            try {
-                mSessionBinder.prepareFromMediaId(mContext.getOpPackageName(), mCbStub, mediaId,
-                        extras);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
-            }
-        }
-
-        /**
-         * Request that the player prepare playback for a specific search query. An empty or null
-         * query should be treated as a request to prepare any music. In other words, other sessions
-         * can continue to play during the preparation of this session. This method can be used to
-         * speed up the start of the playback. Once the preparation is done, the session will
-         * change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
-         * {@link #play} can be called to start playback. If the preparation is not needed,
-         * {@link #playFromSearch} can be directly called without this method.
-         *
-         * @param query The search query.
-         * @param extras Optional extras that can include extra information
-         *               about the query.
-         */
-        public void prepareFromSearch(String query, Bundle extras) {
-            if (query == null) {
-                // This is to remain compatible with
-                // INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
-                query = "";
-            }
-            try {
-                mSessionBinder.prepareFromSearch(mContext.getOpPackageName(), mCbStub, query,
-                        extras);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
-            }
-        }
-
-        /**
-         * Request that the player prepare playback for a specific {@link Uri}. In other words,
-         * other sessions can continue to play during the preparation of this session. This method
-         * can be used to speed up the start of the playback. Once the preparation is done, the
-         * session will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
-         * {@link #play} can be called to start playback. If the preparation is not needed,
-         * {@link #playFromUri} can be directly called without this method.
-         *
-         * @param uri The URI of the requested media.
-         * @param extras Optional extras that can include extra information about the media item
-         *               to be prepared.
-         */
-        public void prepareFromUri(Uri uri, Bundle extras) {
-            if (uri == null || Uri.EMPTY.equals(uri)) {
-                throw new IllegalArgumentException(
-                        "You must specify a non-empty Uri for prepareFromUri.");
-            }
-            try {
-                mSessionBinder.prepareFromUri(mContext.getOpPackageName(), mCbStub, uri, extras);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
-            }
-        }
-
-        /**
-         * Request that the player start its playback at its current position.
-         */
-        public void play() {
-            try {
-                mSessionBinder.play(mContext.getOpPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling play.", e);
-            }
-        }
-
-        /**
-         * Request that the player start playback for a specific media id.
-         *
-         * @param mediaId The id of the requested media.
-         * @param extras Optional extras that can include extra information about the media item
-         *               to be played.
-         */
-        public void playFromMediaId(String mediaId, Bundle extras) {
-            if (TextUtils.isEmpty(mediaId)) {
-                throw new IllegalArgumentException(
-                        "You must specify a non-empty String for playFromMediaId.");
-            }
-            try {
-                mSessionBinder.playFromMediaId(mContext.getOpPackageName(), mCbStub, mediaId,
-                        extras);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
-            }
-        }
-
-        /**
-         * Request that the player start playback for a specific search query.
-         * An empty or null query should be treated as a request to play any
-         * music.
-         *
-         * @param query The search query.
-         * @param extras Optional extras that can include extra information
-         *               about the query.
-         */
-        public void playFromSearch(String query, Bundle extras) {
-            if (query == null) {
-                // This is to remain compatible with
-                // INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
-                query = "";
-            }
-            try {
-                mSessionBinder.playFromSearch(mContext.getOpPackageName(), mCbStub, query, extras);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling play(" + query + ").", e);
-            }
-        }
-
-        /**
-         * Request that the player start playback for a specific {@link Uri}.
-         *
-         * @param uri The URI of the requested media.
-         * @param extras Optional extras that can include extra information about the media item
-         *               to be played.
-         */
-        public void playFromUri(Uri uri, Bundle extras) {
-            if (uri == null || Uri.EMPTY.equals(uri)) {
-                throw new IllegalArgumentException(
-                        "You must specify a non-empty Uri for playFromUri.");
-            }
-            try {
-                mSessionBinder.playFromUri(mContext.getOpPackageName(), mCbStub, uri, extras);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling play(" + uri + ").", e);
-            }
-        }
-
-        /**
-         * Play an item with a specific id in the play queue. If you specify an
-         * id that is not in the play queue, the behavior is undefined.
-         */
-        public void skipToQueueItem(long id) {
-            try {
-                mSessionBinder.skipToQueueItem(mContext.getOpPackageName(), mCbStub, id);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
-            }
-        }
-
-        /**
-         * Request that the player pause its playback and stay at its current
-         * position.
-         */
-        public void pause() {
-            try {
-                mSessionBinder.pause(mContext.getOpPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling pause.", e);
-            }
-        }
-
-        /**
-         * Request that the player stop its playback; it may clear its state in
-         * whatever way is appropriate.
-         */
-        public void stop() {
-            try {
-                mSessionBinder.stop(mContext.getOpPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling stop.", e);
-            }
-        }
-
-        /**
-         * Move to a new location in the media stream.
-         *
-         * @param pos Position to move to, in milliseconds.
-         */
-        public void seekTo(long pos) {
-            try {
-                mSessionBinder.seekTo(mContext.getOpPackageName(), mCbStub, pos);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling seekTo.", e);
-            }
-        }
-
-        /**
-         * Start fast forwarding. If playback is already fast forwarding this
-         * may increase the rate.
-         */
-        public void fastForward() {
-            try {
-                mSessionBinder.fastForward(mContext.getOpPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling fastForward.", e);
-            }
-        }
-
-        /**
-         * Skip to the next item.
-         */
-        public void skipToNext() {
-            try {
-                mSessionBinder.next(mContext.getOpPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling next.", e);
-            }
-        }
-
-        /**
-         * Start rewinding. If playback is already rewinding this may increase
-         * the rate.
-         */
-        public void rewind() {
-            try {
-                mSessionBinder.rewind(mContext.getOpPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling rewind.", e);
-            }
-        }
-
-        /**
-         * Skip to the previous item.
-         */
-        public void skipToPrevious() {
-            try {
-                mSessionBinder.previous(mContext.getOpPackageName(), mCbStub);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling previous.", e);
-            }
-        }
-
-        /**
-         * Rate the current content. This will cause the rating to be set for
-         * the current user. The Rating type must match the type returned by
-         * {@link #getRatingType()}.
-         *
-         * @param rating The rating to set for the current content
-         */
-        public void setRating(Rating rating) {
-            try {
-                mSessionBinder.rate(mContext.getOpPackageName(), mCbStub, rating);
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling rate.", e);
-            }
-        }
-
-        /**
-         * Send a custom action back for the {@link MediaSession} to perform.
-         *
-         * @param customAction The action to perform.
-         * @param args Optional arguments to supply to the {@link MediaSession} for this
-         *             custom action.
-         */
-        public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction,
-                @Nullable Bundle args) {
-            if (customAction == null) {
-                throw new IllegalArgumentException("CustomAction cannot be null.");
-            }
-            sendCustomAction(customAction.getAction(), args);
-        }
-
-        /**
-         * Send the id and args from a custom action back for the {@link MediaSession} to perform.
-         *
-         * @see #sendCustomAction(PlaybackState.CustomAction action, Bundle args)
-         * @param action The action identifier of the {@link PlaybackState.CustomAction} as
-         *               specified by the {@link MediaSession}.
-         * @param args Optional arguments to supply to the {@link MediaSession} for this
-         *             custom action.
-         */
-        public void sendCustomAction(@NonNull String action, @Nullable Bundle args) {
-            if (TextUtils.isEmpty(action)) {
-                throw new IllegalArgumentException("CustomAction cannot be null.");
-            }
-            try {
-                mSessionBinder.sendCustomAction(mContext.getOpPackageName(), mCbStub, action, args);
-            } catch (RemoteException e) {
-                Log.d(TAG, "Dead object in sendCustomAction.", e);
-            }
-        }
-    }
-
-    /**
-     * Holds information about the current playback and how audio is handled for
-     * this session.
-     */
-    public static final class PlaybackInfo {
-        /**
-         * The session uses remote playback.
-         */
-        public static final int PLAYBACK_TYPE_REMOTE = 2;
-        /**
-         * The session uses local playback.
-         */
-        public static final int PLAYBACK_TYPE_LOCAL = 1;
-
-        private final int mVolumeType;
-        private final int mVolumeControl;
-        private final int mMaxVolume;
-        private final int mCurrentVolume;
-        private final AudioAttributes mAudioAttrs;
-
-        /**
-         * @hide
-         */
-        public PlaybackInfo(int type, AudioAttributes attrs, int control, int max, int current) {
-            mVolumeType = type;
-            mAudioAttrs = attrs;
-            mVolumeControl = control;
-            mMaxVolume = max;
-            mCurrentVolume = current;
-        }
-
-        /**
-         * Get the type of playback which affects volume handling. One of:
-         * <ul>
-         * <li>{@link #PLAYBACK_TYPE_LOCAL}</li>
-         * <li>{@link #PLAYBACK_TYPE_REMOTE}</li>
-         * </ul>
-         *
-         * @return The type of playback this session is using.
-         */
-        public int getPlaybackType() {
-            return mVolumeType;
-        }
-
-        /**
-         * Get the audio attributes for this session. The attributes will affect
-         * volume handling for the session. When the volume type is
-         * {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} these may be ignored by the
-         * remote volume handler.
-         *
-         * @return The attributes for this session.
-         */
-        public AudioAttributes getAudioAttributes() {
-            return mAudioAttrs;
-        }
-
-        /**
-         * Get the type of volume control that can be used. One of:
-         * <ul>
-         * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li>
-         * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li>
-         * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li>
-         * </ul>
-         *
-         * @return The type of volume control that may be used with this
-         *         session.
-         */
-        public int getVolumeControl() {
-            return mVolumeControl;
-        }
-
-        /**
-         * Get the maximum volume that may be set for this session.
-         *
-         * @return The maximum allowed volume where this session is playing.
-         */
-        public int getMaxVolume() {
-            return mMaxVolume;
-        }
-
-        /**
-         * Get the current volume for this session.
-         *
-         * @return The current volume where this session is playing.
-         */
-        public int getCurrentVolume() {
-            return mCurrentVolume;
-        }
-    }
-
-    private static final class CallbackStub extends ControllerCallbackLink.CallbackStub {
-        private final WeakReference<MediaController> mController;
-
-        CallbackStub(MediaController controller) {
-            mController = new WeakReference<MediaController>(controller);
-        }
-
-        @Override
-        public void onSessionDestroyed() {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_DESTROYED, null, null);
-            }
-        }
-
-        @Override
-        public void onEvent(String event, Bundle extras) {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_EVENT, event, extras);
-            }
-        }
-
-        @Override
-        public void onPlaybackStateChanged(PlaybackState state) {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_UPDATE_PLAYBACK_STATE, state, null);
-            }
-        }
-
-        @Override
-        public void onMetadataChanged(MediaMetadata metadata) {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_UPDATE_METADATA, metadata, null);
-            }
-        }
-
-        @Override
-        public void onQueueChanged(List<QueueItem> queue) {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_UPDATE_QUEUE, queue, null);
-            }
-        }
-
-        @Override
-        public void onQueueTitleChanged(CharSequence title) {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_UPDATE_QUEUE_TITLE, title, null);
-            }
-        }
-
-        @Override
-        public void onExtrasChanged(Bundle extras) {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                controller.postMessage(MSG_UPDATE_EXTRAS, extras, null);
-            }
-        }
-
-        @Override
-        public void onVolumeInfoChanged(int volumeType, AudioAttributes attrs, int controlType,
-                int maxVolume, int currentVolume) {
-            MediaController controller = mController.get();
-            if (controller != null) {
-                PlaybackInfo info = new PlaybackInfo(volumeType, attrs, controlType, maxVolume,
-                        currentVolume);
-                controller.postMessage(MSG_UPDATE_VOLUME, info, null);
-            }
-        }
-    }
-
-    private final static class MessageHandler extends Handler {
-        private final MediaController.Callback mCallback;
-        private boolean mRegistered = false;
-
-        public MessageHandler(Looper looper, MediaController.Callback cb) {
-            super(looper, null, true);
-            mCallback = cb;
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            if (!mRegistered) {
-                return;
-            }
-            switch (msg.what) {
-                case MSG_EVENT:
-                    mCallback.onSessionEvent((String) msg.obj, msg.getData());
-                    break;
-                case MSG_UPDATE_PLAYBACK_STATE:
-                    mCallback.onPlaybackStateChanged((PlaybackState) msg.obj);
-                    break;
-                case MSG_UPDATE_METADATA:
-                    mCallback.onMetadataChanged((MediaMetadata) msg.obj);
-                    break;
-                case MSG_UPDATE_QUEUE:
-                    mCallback.onQueueChanged((List<MediaSession.QueueItem>) msg.obj);
-                    break;
-                case MSG_UPDATE_QUEUE_TITLE:
-                    mCallback.onQueueTitleChanged((CharSequence) msg.obj);
-                    break;
-                case MSG_UPDATE_EXTRAS:
-                    mCallback.onExtrasChanged((Bundle) msg.obj);
-                    break;
-                case MSG_UPDATE_VOLUME:
-                    mCallback.onAudioInfoChanged((PlaybackInfo) msg.obj);
-                    break;
-                case MSG_DESTROYED:
-                    mCallback.onSessionDestroyed();
-                    break;
-            }
-        }
-
-        public void post(int what, Object obj, Bundle data) {
-            Message msg = obtainMessage(what, obj);
-            msg.setData(data);
-            msg.sendToTarget();
-        }
-    }
-
-}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 0332f4c..1a185e9 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.PendingIntent;
@@ -33,25 +34,15 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.RemoteException;
 import android.os.ResultReceiver;
-import android.os.UserHandle;
 import android.service.media.MediaBrowserService;
 import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
 import java.util.List;
-import java.util.Objects;
 
 /**
  * Allows interaction with media controllers, volume keys, media buttons, and
@@ -76,7 +67,7 @@
  * MediaSession objects are thread safe.
  */
 public final class MediaSession {
-    private static final String TAG = "MediaSession";
+    static final String TAG = "MediaSession";
 
     /**
      * Set this flag on the session to indicate that it can handle media button
@@ -123,21 +114,11 @@
             FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
     public @interface SessionFlags { }
 
-    private final Object mLock = new Object();
-    private final int mMaxBitmapSize;
-
-    private final MediaSession.Token mSessionToken;
-    private final MediaController mController;
-    private final ISession mBinder;
-    private final SessionCallbackLink mCbStub;
+    private final MediaSessionEngine mImpl;
 
     // Do not change the name of mCallback. Support lib accesses this by using reflection.
     @UnsupportedAppUsage
-    private CallbackMessageHandler mCallback;
-    private VolumeProvider mVolumeProvider;
-    private PlaybackState mPlaybackState;
-
-    private boolean mActive = false;
+    private Object mCallback;
 
     /**
      * Creates a new session. The session will automatically be registered with
@@ -149,37 +130,22 @@
      * @param tag A short name for debugging purposes.
      */
     public MediaSession(@NonNull Context context, @NonNull String tag) {
-        this(context, tag, UserHandle.myUserId());
-    }
-
-    /**
-     * Creates a new session as the specified user. To create a session as a
-     * user other than your own you must hold the
-     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}
-     * permission.
-     *
-     * @param context The context to use to create the session.
-     * @param tag A short name for debugging purposes.
-     * @param userId The user id to create the session as.
-     * @hide
-     */
-    public MediaSession(@NonNull Context context, @NonNull String tag, int userId) {
         if (context == null) {
             throw new IllegalArgumentException("context cannot be null.");
         }
         if (TextUtils.isEmpty(tag)) {
             throw new IllegalArgumentException("tag cannot be null or empty");
         }
-        mMaxBitmapSize = context.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
-        mCbStub = new SessionCallbackLink(new CallbackStub(this));
         MediaSessionManager manager = (MediaSessionManager) context
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
         try {
-            mBinder = manager.createSession(mCbStub, tag, userId);
-            mSessionToken = new Token(mBinder.getController());
-            mController = new MediaController(context, mSessionToken);
-        } catch (RemoteException e) {
+            MediaSessionEngine.CallbackStub cbStub = new MediaSessionEngine.CallbackStub();
+            SessionCallbackLink cbLink = new SessionCallbackLink(context, cbStub);
+            SessionLink sessionLink = manager.createSession(cbLink, tag);
+            mImpl = new MediaSessionEngine(context, sessionLink, cbLink, cbStub,
+                    context.getResources().getDimensionPixelSize(
+                            android.R.dimen.config_mediaMetadataBitmapMaxSize));
+        } catch (RuntimeException e) {
             throw new RuntimeException("Remote error creating session.", e);
         }
     }
@@ -194,7 +160,8 @@
      * @param callback The callback object
      */
     public void setCallback(@Nullable Callback callback) {
-        setCallback(callback, null);
+        mCallback = callback == null ? null : new Object();
+        mImpl.setCallback(callback);
     }
 
     /**
@@ -207,24 +174,8 @@
      * @param handler The handler that events should be posted on.
      */
     public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
-        synchronized (mLock) {
-            if (mCallback != null) {
-                // We're updating the callback, clear the session from the old one.
-                mCallback.mCallback.mSession = null;
-                mCallback.removeCallbacksAndMessages(null);
-            }
-            if (callback == null) {
-                mCallback = null;
-                return;
-            }
-            if (handler == null) {
-                handler = new Handler();
-            }
-            callback.mSession = this;
-            CallbackMessageHandler msgHandler = new CallbackMessageHandler(handler.getLooper(),
-                    callback);
-            mCallback = msgHandler;
-        }
+        mCallback = callback == null ? null : new Object();
+        mImpl.setCallback(callback, handler);
     }
 
     /**
@@ -235,11 +186,7 @@
      * @param pi The intent to launch to show UI for this Session.
      */
     public void setSessionActivity(@Nullable PendingIntent pi) {
-        try {
-            mBinder.setLaunchPendingIntent(pi);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
-        }
+        mImpl.setSessionActivity(pi);
     }
 
     /**
@@ -251,11 +198,7 @@
      * @param mbr The {@link PendingIntent} to send the media button event to.
      */
     public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
-        try {
-            mBinder.setMediaButtonReceiver(mbr);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
-        }
+        mImpl.setMediaButtonReceiver(mbr);
     }
 
     /**
@@ -264,11 +207,7 @@
      * @param flags The flags to set for this session.
      */
     public void setFlags(@SessionFlags int flags) {
-        try {
-            mBinder.setFlags(flags);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setFlags.", e);
-        }
+        mImpl.setFlags(flags);
     }
 
     /**
@@ -283,14 +222,7 @@
      * @param attributes The {@link AudioAttributes} for this session's audio.
      */
     public void setPlaybackToLocal(AudioAttributes attributes) {
-        if (attributes == null) {
-            throw new IllegalArgumentException("Attributes cannot be null for local playback.");
-        }
-        try {
-            mBinder.setPlaybackToLocal(attributes);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setPlaybackToLocal.", e);
-        }
+        mImpl.setPlaybackToLocal(attributes);
     }
 
     /**
@@ -305,26 +237,7 @@
      *            not be null.
      */
     public void setPlaybackToRemote(@NonNull VolumeProvider volumeProvider) {
-        if (volumeProvider == null) {
-            throw new IllegalArgumentException("volumeProvider may not be null!");
-        }
-        synchronized (mLock) {
-            mVolumeProvider = volumeProvider;
-        }
-        volumeProvider.setCallback(new VolumeProvider.Callback() {
-            @Override
-            public void onVolumeChanged(VolumeProvider volumeProvider) {
-                notifyRemoteVolumeChanged(volumeProvider);
-            }
-        });
-
-        try {
-            mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(),
-                    volumeProvider.getMaxVolume());
-            mBinder.setCurrentVolume(volumeProvider.getCurrentVolume());
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setPlaybackToRemote.", e);
-        }
+        mImpl.setPlaybackToRemote(volumeProvider);
     }
 
     /**
@@ -336,15 +249,7 @@
      * @param active Whether this session is active or not.
      */
     public void setActive(boolean active) {
-        if (mActive == active) {
-            return;
-        }
-        try {
-            mBinder.setActive(active);
-            mActive = active;
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setActive.", e);
-        }
+        mImpl.setActive(active);
     }
 
     /**
@@ -353,7 +258,7 @@
      * @return True if the session is active, false otherwise.
      */
     public boolean isActive() {
-        return mActive;
+        return mImpl.isActive();
     }
 
     /**
@@ -365,14 +270,7 @@
      * @param extras Any extras included with the event
      */
     public void sendSessionEvent(@NonNull String event, @Nullable Bundle extras) {
-        if (TextUtils.isEmpty(event)) {
-            throw new IllegalArgumentException("event cannot be null or empty");
-        }
-        try {
-            mBinder.sendEvent(event, extras);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error sending event", e);
-        }
+        mImpl.sendSessionEvent(event, extras);
     }
 
     /**
@@ -381,11 +279,7 @@
      * but it must be released if your activity or service is being destroyed.
      */
     public void release() {
-        try {
-            mBinder.destroy();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Error releasing session: ", e);
-        }
+        mImpl.close();
     }
 
     /**
@@ -397,7 +291,7 @@
      *         session
      */
     public @NonNull Token getSessionToken() {
-        return mSessionToken;
+        return mImpl.getSessionToken();
     }
 
     /**
@@ -407,7 +301,7 @@
      * @return A controller for this session.
      */
     public @NonNull MediaController getController() {
-        return mController;
+        return mImpl.getController();
     }
 
     /**
@@ -416,12 +310,7 @@
      * @param state The current state of playback
      */
     public void setPlaybackState(@Nullable PlaybackState state) {
-        mPlaybackState = state;
-        try {
-            mBinder.setPlaybackState(state);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
-        }
+        mImpl.setPlaybackState(state);
     }
 
     /**
@@ -433,24 +322,7 @@
      * @see android.media.MediaMetadata.Builder#putBitmap
      */
     public void setMetadata(@Nullable MediaMetadata metadata) {
-        long duration = -1;
-        int fields = 0;
-        MediaDescription description = null;
-        if (metadata != null) {
-            metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build();
-            if (metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
-                duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
-            }
-            fields = metadata.size();
-            description = metadata.getDescription();
-        }
-        String metadataDescription = "size=" + fields + ", description=" + description;
-
-        try {
-            mBinder.setMetadata(metadata, duration, metadataDescription);
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Dead object in setPlaybackState.", e);
-        }
+        mImpl.setMetadata(metadata);
     }
 
     /**
@@ -465,11 +337,7 @@
      * @param queue A list of items in the play queue.
      */
     public void setQueue(@Nullable List<QueueItem> queue) {
-        try {
-            mBinder.setQueue(queue);
-        } catch (RemoteException e) {
-            Log.wtf("Dead object in setQueue.", e);
-        }
+        mImpl.setQueue(queue);
     }
 
     /**
@@ -480,11 +348,7 @@
      * @param title The title of the play queue.
      */
     public void setQueueTitle(@Nullable CharSequence title) {
-        try {
-            mBinder.setQueueTitle(title);
-        } catch (RemoteException e) {
-            Log.wtf("Dead object in setQueueTitle.", e);
-        }
+        mImpl.setQueueTitle(title);
     }
 
     /**
@@ -501,11 +365,7 @@
      * </ul>
      */
     public void setRatingType(@Rating.Style int type) {
-        try {
-            mBinder.setRatingType(type);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error in setRatingType.", e);
-        }
+        mImpl.setRatingType(type);
     }
 
     /**
@@ -516,11 +376,7 @@
      * @param extras The extras associated with the {@link MediaSession}.
      */
     public void setExtras(@Nullable Bundle extras) {
-        try {
-            mBinder.setExtras(extras);
-        } catch (RemoteException e) {
-            Log.wtf("Dead object in setExtras.", e);
-        }
+        mImpl.setExtras(extras);
     }
 
     /**
@@ -532,11 +388,7 @@
      * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
      */
     public final @NonNull RemoteUserInfo getCurrentControllerInfo() {
-        if (mCallback == null || mCallback.mCurrentControllerInfo == null) {
-            throw new IllegalStateException(
-                    "This should be called inside of MediaSession.Callback methods");
-        }
-        return mCallback.mCurrentControllerInfo;
+        return mImpl.getCurrentControllerInfo();
     }
 
     /**
@@ -546,17 +398,7 @@
      * @hide
      */
     public void notifyRemoteVolumeChanged(VolumeProvider provider) {
-        synchronized (mLock) {
-            if (provider == null || provider != mVolumeProvider) {
-                Log.w(TAG, "Received update from stale volume provider");
-                return;
-            }
-        }
-        try {
-            mBinder.setCurrentVolume(provider.getCurrentVolume());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error in notifyVolumeChanged", e);
-        }
+        mImpl.notifyRemoteVolumeChanged(provider);
     }
 
     /**
@@ -568,119 +410,7 @@
      */
     @UnsupportedAppUsage
     public String getCallingPackage() {
-        if (mCallback != null && mCallback.mCurrentControllerInfo != null) {
-            return mCallback.mCurrentControllerInfo.getPackageName();
-        }
-        return null;
-    }
-
-    private void dispatchPrepare(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null);
-    }
-
-    private void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
-    }
-
-    private void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
-    }
-
-    private void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
-    }
-
-    private void dispatchPlay(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PLAY, null, null);
-    }
-
-    private void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
-    }
-
-    private void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
-    }
-
-    private void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
-    }
-
-    private void dispatchSkipToItem(RemoteUserInfo caller, long id) {
-        postToCallback(caller, CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, null);
-    }
-
-    private void dispatchPause(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PAUSE, null, null);
-    }
-
-    private void dispatchStop(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_STOP, null, null);
-    }
-
-    private void dispatchNext(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_NEXT, null, null);
-    }
-
-    private void dispatchPrevious(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_PREVIOUS, null, null);
-    }
-
-    private void dispatchFastForward(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_FAST_FORWARD, null, null);
-    }
-
-    private void dispatchRewind(RemoteUserInfo caller) {
-        postToCallback(caller, CallbackMessageHandler.MSG_REWIND, null, null);
-    }
-
-    private void dispatchSeekTo(RemoteUserInfo caller, long pos) {
-        postToCallback(caller, CallbackMessageHandler.MSG_SEEK_TO, pos, null);
-    }
-
-    private void dispatchRate(RemoteUserInfo caller, Rating rating) {
-        postToCallback(caller, CallbackMessageHandler.MSG_RATE, rating, null);
-    }
-
-    private void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) {
-        postToCallback(caller, CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
-    }
-
-    private void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) {
-        postToCallback(caller, CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, null);
-    }
-
-    private void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent,
-            long delay) {
-        postToCallbackDelayed(info, CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
-                mediaButtonIntent, null, delay);
-    }
-
-    private void dispatchAdjustVolume(RemoteUserInfo caller, int direction) {
-        postToCallback(caller, CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, null);
-    }
-
-    private void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) {
-        postToCallback(caller, CallbackMessageHandler.MSG_SET_VOLUME, volume, null);
-    }
-
-    private void dispatchCommand(RemoteUserInfo caller, String command, Bundle args,
-            ResultReceiver resultCb) {
-        Command cmd = new Command(command, args, resultCb);
-        postToCallback(caller, CallbackMessageHandler.MSG_COMMAND, cmd, null);
-    }
-
-    private void postToCallback(RemoteUserInfo caller, int what, Object obj, Bundle data) {
-        postToCallbackDelayed(caller, what, obj, data, 0);
-    }
-
-    private void postToCallbackDelayed(RemoteUserInfo caller, int what, Object obj, Bundle data,
-            long delay) {
-        synchronized (mLock) {
-            if (mCallback != null) {
-                mCallback.post(caller, what, obj, data, delay);
-            }
-        }
+        return mImpl.getCallingPackage();
     }
 
     /**
@@ -689,17 +419,7 @@
      * @hide
      */
     public static boolean isActiveState(int state) {
-        switch (state) {
-            case PlaybackState.STATE_FAST_FORWARDING:
-            case PlaybackState.STATE_REWINDING:
-            case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
-            case PlaybackState.STATE_SKIPPING_TO_NEXT:
-            case PlaybackState.STATE_BUFFERING:
-            case PlaybackState.STATE_CONNECTING:
-            case PlaybackState.STATE_PLAYING:
-                return true;
-        }
-        return false;
+        return MediaSessionEngine.isActiveState(state);
     }
 
     /**
@@ -709,13 +429,13 @@
      */
     public static final class Token implements Parcelable {
 
-        private ISessionController mBinder;
+        private ControllerLink mControllerLink;
 
         /**
          * @hide
          */
-        public Token(ISessionController binder) {
-            mBinder = binder;
+        public Token(ControllerLink controllerLink) {
+            mControllerLink = controllerLink;
         }
 
         @Override
@@ -725,14 +445,15 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeStrongBinder(mBinder.asBinder());
+            dest.writeParcelable(mControllerLink, flags);
         }
 
         @Override
         public int hashCode() {
             final int prime = 31;
             int result = 1;
-            result = prime * result + ((mBinder == null) ? 0 : mBinder.asBinder().hashCode());
+            result = prime * result + ((mControllerLink == null)
+                    ? 0 : mControllerLink.getBinder().hashCode());
             return result;
         }
 
@@ -745,23 +466,31 @@
             if (getClass() != obj.getClass())
                 return false;
             Token other = (Token) obj;
-            if (mBinder == null) {
-                if (other.mBinder != null)
+            if (mControllerLink == null) {
+                if (other.mControllerLink != null) {
                     return false;
-            } else if (!mBinder.asBinder().equals(other.mBinder.asBinder()))
+                }
+            } else if (!mControllerLink.getBinder().equals(other.mControllerLink.getBinder())) {
                 return false;
+            }
             return true;
         }
 
-        ISessionController getBinder() {
-            return mBinder;
+        /**
+         * Gets the controller link in this token.
+         * @hide
+         */
+        @SystemApi
+        public ControllerLink getControllerLink() {
+            return mControllerLink;
         }
 
-        public static final Parcelable.Creator<Token> CREATOR
-                = new Parcelable.Creator<Token>() {
+        public static final Parcelable.Creator<Token> CREATOR =
+                new Parcelable.Creator<Token>() {
             @Override
             public Token createFromParcel(Parcel in) {
-                return new Token(ISessionController.Stub.asInterface(in.readStrongBinder()));
+                ControllerLink link = in.readParcelable(null);
+                return new Token(link);
             }
 
             @Override
@@ -777,9 +506,7 @@
      */
     public abstract static class Callback {
 
-        private MediaSession mSession;
-        private CallbackMessageHandler mHandler;
-        private boolean mMediaPlayPauseKeyPending;
+        MediaSessionEngine.MediaButtonEventDelegate mMediaButtonEventDelegate;
 
         public Callback() {
         }
@@ -811,110 +538,12 @@
          * @return True if the event was handled, false otherwise.
          */
         public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {
-            if (mSession != null && mHandler != null
-                    && Intent.ACTION_MEDIA_BUTTON.equals(mediaButtonIntent.getAction())) {
-                KeyEvent ke = mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
-                if (ke != null && ke.getAction() == KeyEvent.ACTION_DOWN) {
-                    PlaybackState state = mSession.mPlaybackState;
-                    long validActions = state == null ? 0 : state.getActions();
-                    switch (ke.getKeyCode()) {
-                        case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                        case KeyEvent.KEYCODE_HEADSETHOOK:
-                            if (ke.getRepeatCount() > 0) {
-                                // Consider long-press as a single tap.
-                                handleMediaPlayPauseKeySingleTapIfPending();
-                            } else if (mMediaPlayPauseKeyPending) {
-                                // Consider double tap as the next.
-                                mHandler.removeMessages(CallbackMessageHandler
-                                        .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
-                                mMediaPlayPauseKeyPending = false;
-                                if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
-                                    onSkipToNext();
-                                }
-                            } else {
-                                mMediaPlayPauseKeyPending = true;
-                                mSession.dispatchMediaButtonDelayed(
-                                        mSession.getCurrentControllerInfo(),
-                                        mediaButtonIntent, ViewConfiguration.getDoubleTapTimeout());
-                            }
-                            return true;
-                        default:
-                            // If another key is pressed within double tap timeout, consider the
-                            // pending play/pause as a single tap to handle media keys in order.
-                            handleMediaPlayPauseKeySingleTapIfPending();
-                            break;
-                    }
-
-                    switch (ke.getKeyCode()) {
-                        case KeyEvent.KEYCODE_MEDIA_PLAY:
-                            if ((validActions & PlaybackState.ACTION_PLAY) != 0) {
-                                onPlay();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_PAUSE:
-                            if ((validActions & PlaybackState.ACTION_PAUSE) != 0) {
-                                onPause();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_NEXT:
-                            if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
-                                onSkipToNext();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-                            if ((validActions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0) {
-                                onSkipToPrevious();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_STOP:
-                            if ((validActions & PlaybackState.ACTION_STOP) != 0) {
-                                onStop();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-                            if ((validActions & PlaybackState.ACTION_FAST_FORWARD) != 0) {
-                                onFastForward();
-                                return true;
-                            }
-                            break;
-                        case KeyEvent.KEYCODE_MEDIA_REWIND:
-                            if ((validActions & PlaybackState.ACTION_REWIND) != 0) {
-                                onRewind();
-                                return true;
-                            }
-                            break;
-                    }
-                }
+            if (mMediaButtonEventDelegate != null) {
+                return mMediaButtonEventDelegate.onMediaButtonIntent(mediaButtonIntent);
             }
             return false;
         }
 
-        private void handleMediaPlayPauseKeySingleTapIfPending() {
-            if (!mMediaPlayPauseKeyPending) {
-                return;
-            }
-            mMediaPlayPauseKeyPending = false;
-            mHandler.removeMessages(CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
-            PlaybackState state = mSession.mPlaybackState;
-            long validActions = state == null ? 0 : state.getActions();
-            boolean isPlaying = state != null
-                    && state.getState() == PlaybackState.STATE_PLAYING;
-            boolean canPlay = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
-                        | PlaybackState.ACTION_PLAY)) != 0;
-            boolean canPause = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
-                        | PlaybackState.ACTION_PAUSE)) != 0;
-            if (isPlaying && canPause) {
-                onPause();
-            } else if (!isPlaying && canPlay) {
-                onPlay();
-            }
-        }
-
         /**
          * Override to handle requests to prepare playback. During the preparation, a session should
          * not hold audio focus in order to allow other sessions play seamlessly. The state of
@@ -1057,251 +686,14 @@
          */
         public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
         }
-    }
 
-    /**
-     * @hide
-     */
-    public static final class CallbackStub extends SessionCallbackLink.CallbackStub {
-        private WeakReference<MediaSession> mMediaSession;
-
-        public CallbackStub(MediaSession session) {
-            mMediaSession = new WeakReference<>(session);
-        }
-
-        private static RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            return new RemoteUserInfo(packageName, pid, uid,
-                    caller != null ? caller.getBinder() : null);
-        }
-
-        @Override
-        public void onCommand(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchCommand(createRemoteUserInfo(packageName, pid, uid, caller),
-                        command, args, cb);
-            }
-        }
-
-        @Override
-        public void onMediaButton(String packageName, int pid, int uid, Intent mediaButtonIntent,
-                int sequenceNumber, ResultReceiver cb) {
-            MediaSession session = mMediaSession.get();
-            try {
-                if (session != null) {
-                    session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, null),
-                            mediaButtonIntent);
-                }
-            } finally {
-                if (cb != null) {
-                    cb.send(sequenceNumber, null);
-                }
-            }
-        }
-
-        @Override
-        public void onMediaButtonFromController(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, Intent mediaButtonIntent) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, caller),
-                        mediaButtonIntent);
-            }
-        }
-
-        @Override
-        public void onPrepare(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onPrepareFromMediaId(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String mediaId,
-                Bundle extras) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPrepareFromMediaId(
-                        createRemoteUserInfo(packageName, pid, uid, caller), mediaId, extras);
-            }
-        }
-
-        @Override
-        public void onPrepareFromSearch(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String query,
-                Bundle extras) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPrepareFromSearch(
-                        createRemoteUserInfo(packageName, pid, uid, caller), query, extras);
-            }
-        }
-
-        @Override
-        public void onPrepareFromUri(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, Uri uri, Bundle extras) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPrepareFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
-                        uri, extras);
-            }
-        }
-
-        @Override
-        public void onPlay(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPlay(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onPlayFromMediaId(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String mediaId,
-                Bundle extras) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPlayFromMediaId(createRemoteUserInfo(packageName, pid, uid, caller),
-                        mediaId, extras);
-            }
-        }
-
-        @Override
-        public void onPlayFromSearch(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String query,
-                Bundle extras) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPlayFromSearch(createRemoteUserInfo(packageName, pid, uid, caller),
-                        query, extras);
-            }
-        }
-
-        @Override
-        public void onPlayFromUri(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, Uri uri, Bundle extras) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPlayFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
-                        uri, extras);
-            }
-        }
-
-        @Override
-        public void onSkipToTrack(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, long id) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchSkipToItem(createRemoteUserInfo(packageName, pid, uid, caller), id);
-            }
-        }
-
-        @Override
-        public void onPause(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPause(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onStop(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchStop(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onNext(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchNext(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onPrevious(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onFastForward(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchFastForward(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onRewind(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchRewind(createRemoteUserInfo(packageName, pid, uid, caller));
-            }
-        }
-
-        @Override
-        public void onSeekTo(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, long pos) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchSeekTo(createRemoteUserInfo(packageName, pid, uid, caller), pos);
-            }
-        }
-
-        @Override
-        public void onRate(String packageName, int pid, int uid, ControllerCallbackLink caller,
-                Rating rating) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchRate(createRemoteUserInfo(packageName, pid, uid, caller), rating);
-            }
-        }
-
-        @Override
-        public void onCustomAction(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String action, Bundle args) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchCustomAction(createRemoteUserInfo(packageName, pid, uid, caller),
-                        action, args);
-            }
-        }
-
-        @Override
-        public void onAdjustVolume(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, int direction) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchAdjustVolume(createRemoteUserInfo(packageName, pid, uid, caller),
-                        direction);
-            }
-        }
-
-        @Override
-        public void onSetVolumeTo(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, int value) {
-            MediaSession session = mMediaSession.get();
-            if (session != null) {
-                session.dispatchSetVolumeTo(createRemoteUserInfo(packageName, pid, uid, caller),
-                        value);
-            }
+        /**
+         * @hide
+         */
+        @SystemApi
+        public void onSetMediaButtonEventDelegate(
+                @NonNull MediaSessionEngine.MediaButtonEventDelegate delegate) {
+            mMediaButtonEventDelegate = delegate;
         }
     }
 
@@ -1315,7 +707,7 @@
          */
         public static final int UNKNOWN_ID = -1;
 
-        private final MediaDescription mDescription;
+        private final MediaSessionEngine.QueueItem mImpl;
         @UnsupportedAppUsage
         private final long mId;
 
@@ -1327,39 +719,32 @@
          *            play queue and cannot be {@link #UNKNOWN_ID}.
          */
         public QueueItem(MediaDescription description, long id) {
-            if (description == null) {
-                throw new IllegalArgumentException("Description cannot be null.");
-            }
-            if (id == UNKNOWN_ID) {
-                throw new IllegalArgumentException("Id cannot be QueueItem.UNKNOWN_ID");
-            }
-            mDescription = description;
+            mImpl = new MediaSessionEngine.QueueItem(description, id);
             mId = id;
         }
 
         private QueueItem(Parcel in) {
-            mDescription = MediaDescription.CREATOR.createFromParcel(in);
-            mId = in.readLong();
+            mImpl = new MediaSessionEngine.QueueItem(in);
+            mId = mImpl.getQueueId();
         }
 
         /**
          * Get the description for this item.
          */
         public MediaDescription getDescription() {
-            return mDescription;
+            return mImpl.getDescription();
         }
 
         /**
          * Get the queue id for this item.
          */
         public long getQueueId() {
-            return mId;
+            return mImpl.getQueueId();
         }
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            mDescription.writeToParcel(dest, flags);
-            dest.writeLong(mId);
+            mImpl.writeToParcel(dest, flags);
         }
 
         @Override
@@ -1383,9 +768,7 @@
 
         @Override
         public String toString() {
-            return "MediaSession.QueueItem {" +
-                    "Description=" + mDescription +
-                    ", Id=" + mId + " }";
+            return mImpl.toString();
         }
 
         @Override
@@ -1398,166 +781,7 @@
                 return false;
             }
 
-            final QueueItem item = (QueueItem) o;
-            if (mId != item.mId) {
-                return false;
-            }
-
-            if (!Objects.equals(mDescription, item.mDescription)) {
-                return false;
-            }
-
-            return true;
-        }
-    }
-
-    private static final class Command {
-        public final String command;
-        public final Bundle extras;
-        public final ResultReceiver stub;
-
-        public Command(String command, Bundle extras, ResultReceiver stub) {
-            this.command = command;
-            this.extras = extras;
-            this.stub = stub;
-        }
-    }
-
-    private class CallbackMessageHandler extends Handler {
-        private static final int MSG_COMMAND = 1;
-        private static final int MSG_MEDIA_BUTTON = 2;
-        private static final int MSG_PREPARE = 3;
-        private static final int MSG_PREPARE_MEDIA_ID = 4;
-        private static final int MSG_PREPARE_SEARCH = 5;
-        private static final int MSG_PREPARE_URI = 6;
-        private static final int MSG_PLAY = 7;
-        private static final int MSG_PLAY_MEDIA_ID = 8;
-        private static final int MSG_PLAY_SEARCH = 9;
-        private static final int MSG_PLAY_URI = 10;
-        private static final int MSG_SKIP_TO_ITEM = 11;
-        private static final int MSG_PAUSE = 12;
-        private static final int MSG_STOP = 13;
-        private static final int MSG_NEXT = 14;
-        private static final int MSG_PREVIOUS = 15;
-        private static final int MSG_FAST_FORWARD = 16;
-        private static final int MSG_REWIND = 17;
-        private static final int MSG_SEEK_TO = 18;
-        private static final int MSG_RATE = 19;
-        private static final int MSG_CUSTOM_ACTION = 20;
-        private static final int MSG_ADJUST_VOLUME = 21;
-        private static final int MSG_SET_VOLUME = 22;
-        private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 23;
-
-        private MediaSession.Callback mCallback;
-        private RemoteUserInfo mCurrentControllerInfo;
-
-        public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
-            super(looper, null, true);
-            mCallback = callback;
-            mCallback.mHandler = this;
-        }
-
-        public void post(RemoteUserInfo caller, int what, Object obj, Bundle data, long delayMs) {
-            Pair<RemoteUserInfo, Object> objWithCaller = Pair.create(caller, obj);
-            Message msg = obtainMessage(what, objWithCaller);
-            msg.setData(data);
-            if (delayMs > 0) {
-                sendMessageDelayed(msg, delayMs);
-            } else {
-                sendMessage(msg);
-            }
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            mCurrentControllerInfo = ((Pair<RemoteUserInfo, Object>) msg.obj).first;
-
-            VolumeProvider vp;
-            Object obj = ((Pair<RemoteUserInfo, Object>) msg.obj).second;
-
-            switch (msg.what) {
-                case MSG_COMMAND:
-                    Command cmd = (Command) obj;
-                    mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
-                    break;
-                case MSG_MEDIA_BUTTON:
-                    mCallback.onMediaButtonEvent((Intent) obj);
-                    break;
-                case MSG_PREPARE:
-                    mCallback.onPrepare();
-                    break;
-                case MSG_PREPARE_MEDIA_ID:
-                    mCallback.onPrepareFromMediaId((String) obj, msg.getData());
-                    break;
-                case MSG_PREPARE_SEARCH:
-                    mCallback.onPrepareFromSearch((String) obj, msg.getData());
-                    break;
-                case MSG_PREPARE_URI:
-                    mCallback.onPrepareFromUri((Uri) obj, msg.getData());
-                    break;
-                case MSG_PLAY:
-                    mCallback.onPlay();
-                    break;
-                case MSG_PLAY_MEDIA_ID:
-                    mCallback.onPlayFromMediaId((String) obj, msg.getData());
-                    break;
-                case MSG_PLAY_SEARCH:
-                    mCallback.onPlayFromSearch((String) obj, msg.getData());
-                    break;
-                case MSG_PLAY_URI:
-                    mCallback.onPlayFromUri((Uri) obj, msg.getData());
-                    break;
-                case MSG_SKIP_TO_ITEM:
-                    mCallback.onSkipToQueueItem((Long) obj);
-                    break;
-                case MSG_PAUSE:
-                    mCallback.onPause();
-                    break;
-                case MSG_STOP:
-                    mCallback.onStop();
-                    break;
-                case MSG_NEXT:
-                    mCallback.onSkipToNext();
-                    break;
-                case MSG_PREVIOUS:
-                    mCallback.onSkipToPrevious();
-                    break;
-                case MSG_FAST_FORWARD:
-                    mCallback.onFastForward();
-                    break;
-                case MSG_REWIND:
-                    mCallback.onRewind();
-                    break;
-                case MSG_SEEK_TO:
-                    mCallback.onSeekTo((Long) obj);
-                    break;
-                case MSG_RATE:
-                    mCallback.onSetRating((Rating) obj);
-                    break;
-                case MSG_CUSTOM_ACTION:
-                    mCallback.onCustomAction((String) obj, msg.getData());
-                    break;
-                case MSG_ADJUST_VOLUME:
-                    synchronized (mLock) {
-                        vp = mVolumeProvider;
-                    }
-                    if (vp != null) {
-                        vp.onAdjustVolume((int) obj);
-                    }
-                    break;
-                case MSG_SET_VOLUME:
-                    synchronized (mLock) {
-                        vp = mVolumeProvider;
-                    }
-                    if (vp != null) {
-                        vp.onSetVolumeTo((int) obj);
-                    }
-                    break;
-                case MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT:
-                    mCallback.handleMediaPlayPauseKeySingleTapIfPending();
-                    break;
-            }
-            mCurrentControllerInfo = null;
+            return mImpl.equals(((QueueItem) o).mImpl);
         }
     }
 }
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 73dd55c..c64c452 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -26,7 +26,8 @@
 import android.content.Context;
 import android.media.AudioManager;
 import android.media.IRemoteVolumeController;
-import android.media.browse.MediaBrowser;
+import android.media.MediaSession2;
+import android.media.Session2Token;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -35,10 +36,13 @@
 import android.os.UserHandle;
 import android.service.media.MediaBrowserService;
 import android.service.notification.NotificationListenerService;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.KeyEvent;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -67,9 +71,13 @@
      */
     public static final int RESULT_MEDIA_KEY_HANDLED = 1;
 
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
     private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners
             = new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>();
-    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private final ArrayMap<OnSession2TokensChangedListener, Session2TokensChangedWrapper>
+            mSession2TokensListeners = new ArrayMap<>();
     private final ISessionManager mService;
 
     private Context mContext;
@@ -96,9 +104,37 @@
      * @return The binder object from the system
      * @hide
      */
-    public @NonNull ISession createSession(@NonNull SessionCallbackLink cbStub,
-            @NonNull String tag, int userId) throws RemoteException {
-        return mService.createSession(mContext.getPackageName(), cbStub, tag, userId);
+    @NonNull
+    public SessionLink createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag) {
+        try {
+            return mService.createSession(mContext.getPackageName(), cbStub, tag,
+                    UserHandle.myUserId());
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Notifies that a new {@link MediaSession2} with type {@link Session2Token#TYPE_SESSION} is
+     * created.
+     * <p>
+     * Do not use this API directly, but create a new instance through the
+     * {@link MediaSession2.Builder} instead.
+     *
+     * @param token newly created session2 token
+     */
+    public void notifySession2Created(@NonNull Session2Token token) {
+        if (token == null) {
+            throw new IllegalArgumentException("token shouldn't be null");
+        }
+        if (token.getType() != Session2Token.TYPE_SESSION) {
+            throw new IllegalArgumentException("token's type should be TYPE_SESSION");
+        }
+        try {
+            mService.notifySession2Created(token);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -139,11 +175,10 @@
             @Nullable ComponentName notificationListener, int userId) {
         ArrayList<MediaController> controllers = new ArrayList<MediaController>();
         try {
-            List<IBinder> binders = mService.getSessions(notificationListener, userId);
+            List<ControllerLink> binders = mService.getSessions(notificationListener, userId);
             int size = binders.size();
             for (int i = 0; i < size; i++) {
-                MediaController controller = new MediaController(mContext, ISessionController.Stub
-                        .asInterface(binders.get(i)));
+                MediaController controller = new MediaController(mContext, binders.get(i));
                 controllers.add(controller);
             }
         } catch (RemoteException e) {
@@ -153,6 +188,41 @@
     }
 
     /**
+     * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
+     * current user.
+     * <p>
+     * Although this API can be used without any restriction, each session owners can accept or
+     * reject your uses of {@link MediaSession2}.
+     *
+     * @return A list of {@link Session2Token}.
+     */
+    @NonNull
+    public List<Session2Token> getSession2Tokens() {
+        return getSession2Tokens(UserHandle.myUserId());
+    }
+
+    /**
+     * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
+     * given user.
+     * <p>
+     * If you want to get tokens for another user, you must hold the
+     * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL permission.
+     *
+     * @param userId The user id to fetch sessions for.
+     * @return A list of {@link Session2Token}
+     * @hide
+     */
+    @NonNull
+    public List<Session2Token> getSession2Tokens(int userId) {
+        try {
+            return mService.getSession2Tokens(userId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get session tokens", e);
+        }
+        return new ArrayList<>();
+    }
+
+    /**
      * Add a listener to be notified when the list of active sessions
      * changes.This requires the
      * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
@@ -260,6 +330,97 @@
     }
 
     /**
+     * Adds a listener to be notified when the {@link #getSession2Tokens()} changes.
+     * <p>
+     * This API is not generally intended for third party application developers.
+     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+     * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+     * for consistent behavior across all devices.
+     *
+     * @param listener The listener to add
+     */
+    public void addOnSession2TokensChangedListener(
+            @NonNull OnSession2TokensChangedListener listener) {
+        addOnSession2TokensChangedListener(UserHandle.myUserId(), listener, new Handler());
+    }
+
+    /**
+     * Adds a listener to be notified when the {@link #getSession2Tokens()} changes.
+     * <p>
+     * This API is not generally intended for third party application developers.
+     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+     * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+     * for consistent behavior across all devices.
+     *
+     * @param listener The listener to add
+     * @param handler The handler to call listener on.
+     */
+    public void addOnSession2TokensChangedListener(
+            @NonNull OnSession2TokensChangedListener listener, @NonNull Handler handler) {
+        addOnSession2TokensChangedListener(UserHandle.myUserId(), listener, handler);
+    }
+
+    /**
+     * Adds a listener to be notified when the {@link #getSession2Tokens()} changes.
+     * <p>
+     * This API is not generally intended for third party application developers.
+     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+     * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+     * for consistent behavior across all devices.
+     *
+     * @param userId The userId to listen for changes on
+     * @param listener The listener to add
+     * @param handler The handler to call listener on. If {@code null}, calling thread's looper will
+     *                be used.
+     * @hide
+     */
+    public void addOnSession2TokensChangedListener(int userId,
+            @NonNull OnSession2TokensChangedListener listener, @Nullable Handler handler) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener shouldn't be null");
+        }
+        synchronized (mLock) {
+            if (mSession2TokensListeners.get(listener) != null) {
+                Log.w(TAG, "Attempted to add session listener twice, ignoring.");
+                return;
+            }
+            Session2TokensChangedWrapper wrapper =
+                    new Session2TokensChangedWrapper(listener, handler);
+            try {
+                mService.addSession2TokensListener(wrapper.getStub(), userId);
+                mSession2TokensListeners.put(listener, wrapper);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in addSessionTokensListener.", e);
+                e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Removes the {@link OnSession2TokensChangedListener} to stop receiving session token updates.
+     *
+     * @param listener The listener to remove.
+     */
+    public void removeOnSession2TokensChangedListener(
+            @NonNull OnSession2TokensChangedListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener may not be null");
+        }
+        final Session2TokensChangedWrapper wrapper;
+        synchronized (mLock) {
+            wrapper = mSession2TokensListeners.remove(listener);
+        }
+        if (wrapper != null) {
+            try {
+                mService.removeSession2TokensListener(wrapper.getStub());
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error in removeSessionTokensListener.", e);
+                e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
      * Set the remote volume controller to receive volume updates on. Only for
      * use by system UI.
      *
@@ -312,7 +473,7 @@
     private void dispatchMediaKeyEventInternal(boolean asSystemService, @NonNull KeyEvent keyEvent,
             boolean needWakeLock) {
         try {
-            mService.dispatchMediaKeyEvent(mContext.getOpPackageName(), asSystemService, keyEvent,
+            mService.dispatchMediaKeyEvent(mContext.getPackageName(), asSystemService, keyEvent,
                     needWakeLock);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to send key event.", e);
@@ -348,8 +509,8 @@
     private void dispatchVolumeKeyEventInternal(boolean asSystemService, @NonNull KeyEvent keyEvent,
             int stream, boolean musicOnly) {
         try {
-            mService.dispatchVolumeKeyEvent(mContext.getOpPackageName(), asSystemService, keyEvent,
-                    stream, musicOnly);
+            mService.dispatchVolumeKeyEvent(mContext.getPackageName(), mContext.getOpPackageName(),
+                    asSystemService, keyEvent, stream, musicOnly);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to send volume key event.", e);
         }
@@ -369,8 +530,8 @@
      */
     public void dispatchAdjustVolume(int suggestedStream, int direction, int flags) {
         try {
-            mService.dispatchAdjustVolume(mContext.getOpPackageName(), suggestedStream, direction,
-                    flags);
+            mService.dispatchAdjustVolume(mContext.getPackageName(), mContext.getOpPackageName(),
+                    suggestedStream, direction, flags);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to send adjust volume.", e);
         }
@@ -526,6 +687,24 @@
     }
 
     /**
+     * Listens for changes to the {@link #getSession2Tokens()}. This can be added
+     * using {@link #addOnSession2TokensChangedListener(OnSession2TokensChangedListener, Handler)}.
+     * <p>
+     * This API is not generally intended for third party application developers.
+     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+     * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
+     * for consistent behavior across all devices.
+     */
+    public interface OnSession2TokensChangedListener {
+        /**
+         * Called when the {@link #getSession2Tokens()} is changed.
+         *
+         * @param tokens list of {@link Session2Token}
+         */
+        void onSession2TokensChanged(@NonNull List<Session2Token> tokens);
+    }
+
+    /**
      * Listens the volume key long-presses.
      * @hide
      */
@@ -618,7 +797,6 @@
         private final String mPackageName;
         private final int mPid;
         private final int mUid;
-        private final IBinder mCallerBinder;
 
         /**
          * Create a new remote user information.
@@ -628,22 +806,9 @@
          * @param uid The uid of the remote user
          */
         public RemoteUserInfo(@NonNull String packageName, int pid, int uid) {
-            this(packageName, pid, uid, null);
-        }
-
-        /**
-         * Create a new remote user information.
-         *
-         * @param packageName The package name of the remote user
-         * @param pid The pid of the remote user
-         * @param uid The uid of the remote user
-         * @param callerBinder The binder of the remote user. Can be {@code null}.
-         */
-        public RemoteUserInfo(String packageName, int pid, int uid, IBinder callerBinder) {
             mPackageName = packageName;
             mPid = pid;
             mUid = uid;
-            mCallerBinder = callerBinder;
         }
 
         /**
@@ -668,13 +833,8 @@
         }
 
         /**
-         * Returns equality of two RemoteUserInfo. Two RemoteUserInfos are the same only if they're
-         * sent to the same controller (either {@link MediaController} or
-         * {@link MediaBrowser}. If it's not nor one of them is triggered by the key presses, they
-         * would be considered as different one.
-         * <p>
-         * If you only want to compare the caller's package, compare them with the
-         * {@link #getPackageName()}, {@link #getPid()}, and/or {@link #getUid()} directly.
+         * Returns equality of two RemoteUserInfo. Two RemoteUserInfo objects are equal
+         * if and only if they have the same package name, same pid, and same uid.
          *
          * @param obj the reference object with which to compare.
          * @return {@code true} if equals, {@code false} otherwise
@@ -688,8 +848,9 @@
                 return true;
             }
             RemoteUserInfo otherUserInfo = (RemoteUserInfo) obj;
-            return (mCallerBinder == null || otherUserInfo.mCallerBinder == null) ? false
-                    : mCallerBinder.equals(otherUserInfo.mCallerBinder);
+            return TextUtils.equals(mPackageName, otherUserInfo.mPackageName)
+                    && mPid == otherUserInfo.mPid
+                    && mUid == otherUserInfo.mUid;
         }
 
         @Override
@@ -743,6 +904,27 @@
         }
     }
 
+    private static final class Session2TokensChangedWrapper {
+        private final OnSession2TokensChangedListener mListener;
+        private final Handler mHandler;
+        private final ISession2TokensListener.Stub mStub =
+                new ISession2TokensListener.Stub() {
+                    @Override
+                    public void onSession2TokensChanged(final List<Session2Token> tokens) {
+                        mHandler.post(() -> mListener.onSession2TokensChanged(tokens));
+                    }
+                };
+
+        Session2TokensChangedWrapper(OnSession2TokensChangedListener listener, Handler handler) {
+            mListener = listener;
+            mHandler = (handler == null) ? new Handler() : new Handler(handler.getLooper());
+        }
+
+        public ISession2TokensListener.Stub getStub() {
+            return mStub;
+        }
+    }
+
     private static final class OnVolumeKeyLongPressListenerImpl
             extends IOnVolumeKeyLongPressListener.Stub {
         private OnVolumeKeyLongPressListener mListener;
diff --git a/media/java/android/media/session/ParcelableVolumeInfo.aidl b/media/java/android/media/session/ParcelableVolumeInfo.aidl
deleted file mode 100644
index c4250f0..0000000
--- a/media/java/android/media/session/ParcelableVolumeInfo.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.media.session;
-
-parcelable ParcelableVolumeInfo;
diff --git a/media/java/android/media/session/ParcelableVolumeInfo.java b/media/java/android/media/session/ParcelableVolumeInfo.java
deleted file mode 100644
index f59c975..0000000
--- a/media/java/android/media/session/ParcelableVolumeInfo.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Copyright 2014, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-package android.media.session;
-
-import android.media.AudioAttributes;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Convenience class for passing information about the audio configuration of a
- * session. The public implementation is {@link MediaController.PlaybackInfo}.
- *
- * @hide
- */
-public class ParcelableVolumeInfo implements Parcelable {
-    public int volumeType;
-    public AudioAttributes audioAttrs;
-    public int controlType;
-    public int maxVolume;
-    public int currentVolume;
-
-    public ParcelableVolumeInfo(int volumeType, AudioAttributes audioAttrs, int controlType,
-            int maxVolume,
-            int currentVolume) {
-        this.volumeType = volumeType;
-        this.audioAttrs = audioAttrs;
-        this.controlType = controlType;
-        this.maxVolume = maxVolume;
-        this.currentVolume = currentVolume;
-    }
-
-    public ParcelableVolumeInfo(Parcel from) {
-        volumeType = from.readInt();
-        controlType = from.readInt();
-        maxVolume = from.readInt();
-        currentVolume = from.readInt();
-        audioAttrs = AudioAttributes.CREATOR.createFromParcel(from);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(volumeType);
-        dest.writeInt(controlType);
-        dest.writeInt(maxVolume);
-        dest.writeInt(currentVolume);
-        audioAttrs.writeToParcel(dest, flags);
-    }
-
-
-    public static final Parcelable.Creator<ParcelableVolumeInfo> CREATOR
-            = new Parcelable.Creator<ParcelableVolumeInfo>() {
-        @Override
-        public ParcelableVolumeInfo createFromParcel(Parcel in) {
-            return new ParcelableVolumeInfo(in);
-        }
-
-        @Override
-        public ParcelableVolumeInfo[] newArray(int size) {
-            return new ParcelableVolumeInfo[size];
-        }
-    };
-}
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
deleted file mode 100644
index 17d16b8..0000000
--- a/media/java/android/media/session/PlaybackState.java
+++ /dev/null
@@ -1,1079 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.session;
-
-import android.annotation.DrawableRes;
-import android.annotation.IntDef;
-import android.annotation.LongDef;
-import android.annotation.Nullable;
-import android.media.RemoteControlClient;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import java.util.ArrayList;
-import java.util.List;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Playback state for a {@link MediaSession}. This includes a state like
- * {@link PlaybackState#STATE_PLAYING}, the current playback position,
- * and the current control capabilities.
- */
-public final class PlaybackState implements Parcelable {
-    private static final String TAG = "PlaybackState";
-
-    /**
-     * @hide
-     */
-    @LongDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
-            ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
-            ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
-            ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
-            ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Actions {}
-
-    /**
-     * Indicates this session supports the stop command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_STOP = 1 << 0;
-
-    /**
-     * Indicates this session supports the pause command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PAUSE = 1 << 1;
-
-    /**
-     * Indicates this session supports the play command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PLAY = 1 << 2;
-
-    /**
-     * Indicates this session supports the rewind command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_REWIND = 1 << 3;
-
-    /**
-     * Indicates this session supports the previous command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4;
-
-    /**
-     * Indicates this session supports the next command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_SKIP_TO_NEXT = 1 << 5;
-
-    /**
-     * Indicates this session supports the fast forward command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_FAST_FORWARD = 1 << 6;
-
-    /**
-     * Indicates this session supports the set rating command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_SET_RATING = 1 << 7;
-
-    /**
-     * Indicates this session supports the seek to command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_SEEK_TO = 1 << 8;
-
-    /**
-     * Indicates this session supports the play/pause toggle command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PLAY_PAUSE = 1 << 9;
-
-    /**
-     * Indicates this session supports the play from media id command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PLAY_FROM_MEDIA_ID = 1 << 10;
-
-    /**
-     * Indicates this session supports the play from search command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11;
-
-    /**
-     * Indicates this session supports the skip to queue item command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12;
-
-    /**
-     * Indicates this session supports the play from URI command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PLAY_FROM_URI = 1 << 13;
-
-    /**
-     * Indicates this session supports the prepare command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PREPARE = 1 << 14;
-
-    /**
-     * Indicates this session supports the prepare from media id command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PREPARE_FROM_MEDIA_ID = 1 << 15;
-
-    /**
-     * Indicates this session supports the prepare from search command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PREPARE_FROM_SEARCH = 1 << 16;
-
-    /**
-     * Indicates this session supports the prepare from URI command.
-     *
-     * @see Builder#setActions(long)
-     */
-    public static final long ACTION_PREPARE_FROM_URI = 1 << 17;
-
-    /**
-     * @hide
-     */
-    @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_FAST_FORWARDING,
-            STATE_REWINDING, STATE_BUFFERING, STATE_ERROR, STATE_CONNECTING,
-            STATE_SKIPPING_TO_PREVIOUS, STATE_SKIPPING_TO_NEXT, STATE_SKIPPING_TO_QUEUE_ITEM})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface State {}
-
-    /**
-     * This is the default playback state and indicates that no media has been
-     * added yet, or the performer has been reset and has no content to play.
-     *
-     * @see Builder#setState(int, long, float)
-     * @see Builder#setState(int, long, float, long)
-     */
-    public final static int STATE_NONE = 0;
-
-    /**
-     * State indicating this item is currently stopped.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_STOPPED = 1;
-
-    /**
-     * State indicating this item is currently paused.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_PAUSED = 2;
-
-    /**
-     * State indicating this item is currently playing.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_PLAYING = 3;
-
-    /**
-     * State indicating this item is currently fast forwarding.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_FAST_FORWARDING = 4;
-
-    /**
-     * State indicating this item is currently rewinding.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_REWINDING = 5;
-
-    /**
-     * State indicating this item is currently buffering and will begin playing
-     * when enough data has buffered.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_BUFFERING = 6;
-
-    /**
-     * State indicating this item is currently in an error state. The error
-     * message should also be set when entering this state.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_ERROR = 7;
-
-    /**
-     * State indicating the class doing playback is currently connecting to a
-     * new destination.  Depending on the implementation you may return to the previous
-     * state when the connection finishes or enter {@link #STATE_NONE}.
-     * If the connection failed {@link #STATE_ERROR} should be used.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_CONNECTING = 8;
-
-    /**
-     * State indicating the player is currently skipping to the previous item.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_SKIPPING_TO_PREVIOUS = 9;
-
-    /**
-     * State indicating the player is currently skipping to the next item.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_SKIPPING_TO_NEXT = 10;
-
-    /**
-     * State indicating the player is currently skipping to a specific item in
-     * the queue.
-     *
-     * @see Builder#setState
-     */
-    public final static int STATE_SKIPPING_TO_QUEUE_ITEM = 11;
-
-    /**
-     * Use this value for the position to indicate the position is not known.
-     */
-    public final static long PLAYBACK_POSITION_UNKNOWN = -1;
-
-    private final int mState;
-    private final long mPosition;
-    private final long mBufferedPosition;
-    private final float mSpeed;
-    private final long mActions;
-    private List<PlaybackState.CustomAction> mCustomActions;
-    private final CharSequence mErrorMessage;
-    private final long mUpdateTime;
-    private final long mActiveItemId;
-    private final Bundle mExtras;
-
-    private PlaybackState(int state, long position, long updateTime, float speed,
-            long bufferedPosition, long transportControls,
-            List<PlaybackState.CustomAction> customActions, long activeItemId,
-            CharSequence error, Bundle extras) {
-        mState = state;
-        mPosition = position;
-        mSpeed = speed;
-        mUpdateTime = updateTime;
-        mBufferedPosition = bufferedPosition;
-        mActions = transportControls;
-        mCustomActions = new ArrayList<>(customActions);
-        mActiveItemId = activeItemId;
-        mErrorMessage = error;
-        mExtras = extras;
-    }
-
-    private PlaybackState(Parcel in) {
-        mState = in.readInt();
-        mPosition = in.readLong();
-        mSpeed = in.readFloat();
-        mUpdateTime = in.readLong();
-        mBufferedPosition = in.readLong();
-        mActions = in.readLong();
-        mCustomActions = in.createTypedArrayList(CustomAction.CREATOR);
-        mActiveItemId = in.readLong();
-        mErrorMessage = in.readCharSequence();
-        mExtras = in.readBundle();
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder bob = new StringBuilder("PlaybackState {");
-        bob.append("state=").append(mState);
-        bob.append(", position=").append(mPosition);
-        bob.append(", buffered position=").append(mBufferedPosition);
-        bob.append(", speed=").append(mSpeed);
-        bob.append(", updated=").append(mUpdateTime);
-        bob.append(", actions=").append(mActions);
-        bob.append(", custom actions=").append(mCustomActions);
-        bob.append(", active item id=").append(mActiveItemId);
-        bob.append(", error=").append(mErrorMessage);
-        bob.append("}");
-        return bob.toString();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mState);
-        dest.writeLong(mPosition);
-        dest.writeFloat(mSpeed);
-        dest.writeLong(mUpdateTime);
-        dest.writeLong(mBufferedPosition);
-        dest.writeLong(mActions);
-        dest.writeTypedList(mCustomActions);
-        dest.writeLong(mActiveItemId);
-        dest.writeCharSequence(mErrorMessage);
-        dest.writeBundle(mExtras);
-    }
-
-    /**
-     * Get the current state of playback. One of the following:
-     * <ul>
-     * <li> {@link PlaybackState#STATE_NONE}</li>
-     * <li> {@link PlaybackState#STATE_STOPPED}</li>
-     * <li> {@link PlaybackState#STATE_PLAYING}</li>
-     * <li> {@link PlaybackState#STATE_PAUSED}</li>
-     * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
-     * <li> {@link PlaybackState#STATE_REWINDING}</li>
-     * <li> {@link PlaybackState#STATE_BUFFERING}</li>
-     * <li> {@link PlaybackState#STATE_ERROR}</li>
-     * <li> {@link PlaybackState#STATE_CONNECTING}</li>
-     * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
-     * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
-     * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
-     * </ul>
-     */
-    @State
-    public int getState() {
-        return mState;
-    }
-
-    /**
-     * Get the current playback position in ms.
-     */
-    public long getPosition() {
-        return mPosition;
-    }
-
-    /**
-     * Get the current buffered position in ms. This is the farthest playback
-     * point that can be reached from the current position using only buffered
-     * content.
-     */
-    public long getBufferedPosition() {
-        return mBufferedPosition;
-    }
-
-    /**
-     * Get the current playback speed as a multiple of normal playback. This
-     * should be negative when rewinding. A value of 1 means normal playback and
-     * 0 means paused.
-     *
-     * @return The current speed of playback.
-     */
-    public float getPlaybackSpeed() {
-        return mSpeed;
-    }
-
-    /**
-     * Get the current actions available on this session. This should use a
-     * bitmask of the available actions.
-     * <ul>
-     * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
-     * <li> {@link PlaybackState#ACTION_REWIND}</li>
-     * <li> {@link PlaybackState#ACTION_PLAY}</li>
-     * <li> {@link PlaybackState#ACTION_PAUSE}</li>
-     * <li> {@link PlaybackState#ACTION_STOP}</li>
-     * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
-     * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
-     * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
-     * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
-     * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
-     * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
-     * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
-     * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
-     * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
-     * <li> {@link PlaybackState#ACTION_PREPARE}</li>
-     * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
-     * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
-     * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
-     * </ul>
-     */
-    @Actions
-    public long getActions() {
-        return mActions;
-    }
-
-    /**
-     * Get the list of custom actions.
-     */
-    public List<PlaybackState.CustomAction> getCustomActions() {
-        return mCustomActions;
-    }
-
-    /**
-     * Get a user readable error message. This should be set when the state is
-     * {@link PlaybackState#STATE_ERROR}.
-     */
-    public CharSequence getErrorMessage() {
-        return mErrorMessage;
-    }
-
-    /**
-     * Get the elapsed real time at which position was last updated. If the
-     * position has never been set this will return 0;
-     *
-     * @return The last time the position was updated.
-     */
-    public long getLastPositionUpdateTime() {
-        return mUpdateTime;
-    }
-
-    /**
-     * Get the id of the currently active item in the queue. If there is no
-     * queue or a queue is not supported by the session this will be
-     * {@link MediaSession.QueueItem#UNKNOWN_ID}.
-     *
-     * @return The id of the currently active item in the queue or
-     *         {@link MediaSession.QueueItem#UNKNOWN_ID}.
-     */
-    public long getActiveQueueItemId() {
-        return mActiveItemId;
-    }
-
-    /**
-     * Get any custom extras that were set on this playback state.
-     *
-     * @return The extras for this state or null.
-     */
-    public @Nullable Bundle getExtras() {
-        return mExtras;
-    }
-
-    /**
-     * Get the {@link PlaybackState} state for the given
-     * {@link RemoteControlClient} state.
-     *
-     * @param rccState The state used by {@link RemoteControlClient}.
-     * @return The equivalent state used by {@link PlaybackState}.
-     * @hide
-     */
-    public static int getStateFromRccState(int rccState) {
-        switch (rccState) {
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-                return STATE_BUFFERING;
-            case RemoteControlClient.PLAYSTATE_ERROR:
-                return STATE_ERROR;
-            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-                return STATE_FAST_FORWARDING;
-            case RemoteControlClient.PLAYSTATE_NONE:
-                return STATE_NONE;
-            case RemoteControlClient.PLAYSTATE_PAUSED:
-                return STATE_PAUSED;
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-                return STATE_PLAYING;
-            case RemoteControlClient.PLAYSTATE_REWINDING:
-                return STATE_REWINDING;
-            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-                return STATE_SKIPPING_TO_PREVIOUS;
-            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-                return STATE_SKIPPING_TO_NEXT;
-            case RemoteControlClient.PLAYSTATE_STOPPED:
-                return STATE_STOPPED;
-            default:
-                return -1;
-        }
-    }
-
-    /**
-     * Get the {@link RemoteControlClient} state for the given
-     * {@link PlaybackState} state.
-     *
-     * @param state The state used by {@link PlaybackState}.
-     * @return The equivalent state used by {@link RemoteControlClient}.
-     * @hide
-     */
-    public static int getRccStateFromState(int state) {
-        switch (state) {
-            case STATE_BUFFERING:
-                return RemoteControlClient.PLAYSTATE_BUFFERING;
-            case STATE_ERROR:
-                return RemoteControlClient.PLAYSTATE_ERROR;
-            case STATE_FAST_FORWARDING:
-                return RemoteControlClient.PLAYSTATE_FAST_FORWARDING;
-            case STATE_NONE:
-                return RemoteControlClient.PLAYSTATE_NONE;
-            case STATE_PAUSED:
-                return RemoteControlClient.PLAYSTATE_PAUSED;
-            case STATE_PLAYING:
-                return RemoteControlClient.PLAYSTATE_PLAYING;
-            case STATE_REWINDING:
-                return RemoteControlClient.PLAYSTATE_REWINDING;
-            case STATE_SKIPPING_TO_PREVIOUS:
-                return RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS;
-            case STATE_SKIPPING_TO_NEXT:
-                return RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS;
-            case STATE_STOPPED:
-                return RemoteControlClient.PLAYSTATE_STOPPED;
-            default:
-                return -1;
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public static long getActionsFromRccControlFlags(int rccFlags) {
-        long actions = 0;
-        long flag = 1;
-        while (flag <= rccFlags) {
-            if ((flag & rccFlags) != 0) {
-                actions |= getActionForRccFlag((int) flag);
-            }
-            flag = flag << 1;
-        }
-        return actions;
-    }
-
-    /**
-     * @hide
-     */
-    public static int getRccControlFlagsFromActions(long actions) {
-        int rccFlags = 0;
-        long action = 1;
-        while (action <= actions && action < Integer.MAX_VALUE) {
-            if ((action & actions) != 0) {
-                rccFlags |= getRccFlagForAction(action);
-            }
-            action = action << 1;
-        }
-        return rccFlags;
-    }
-
-    private static long getActionForRccFlag(int flag) {
-        switch (flag) {
-            case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS:
-                return ACTION_SKIP_TO_PREVIOUS;
-            case RemoteControlClient.FLAG_KEY_MEDIA_REWIND:
-                return ACTION_REWIND;
-            case RemoteControlClient.FLAG_KEY_MEDIA_PLAY:
-                return ACTION_PLAY;
-            case RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE:
-                return ACTION_PLAY_PAUSE;
-            case RemoteControlClient.FLAG_KEY_MEDIA_PAUSE:
-                return ACTION_PAUSE;
-            case RemoteControlClient.FLAG_KEY_MEDIA_STOP:
-                return ACTION_STOP;
-            case RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD:
-                return ACTION_FAST_FORWARD;
-            case RemoteControlClient.FLAG_KEY_MEDIA_NEXT:
-                return ACTION_SKIP_TO_NEXT;
-            case RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE:
-                return ACTION_SEEK_TO;
-            case RemoteControlClient.FLAG_KEY_MEDIA_RATING:
-                return ACTION_SET_RATING;
-        }
-        return 0;
-    }
-
-    private static int getRccFlagForAction(long action) {
-        // We only care about the lower set of actions that can map to rcc
-        // flags.
-        int testAction = action < Integer.MAX_VALUE ? (int) action : 0;
-        switch (testAction) {
-            case (int) ACTION_SKIP_TO_PREVIOUS:
-                return RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS;
-            case (int) ACTION_REWIND:
-                return RemoteControlClient.FLAG_KEY_MEDIA_REWIND;
-            case (int) ACTION_PLAY:
-                return RemoteControlClient.FLAG_KEY_MEDIA_PLAY;
-            case (int) ACTION_PLAY_PAUSE:
-                return RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE;
-            case (int) ACTION_PAUSE:
-                return RemoteControlClient.FLAG_KEY_MEDIA_PAUSE;
-            case (int) ACTION_STOP:
-                return RemoteControlClient.FLAG_KEY_MEDIA_STOP;
-            case (int) ACTION_FAST_FORWARD:
-                return RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD;
-            case (int) ACTION_SKIP_TO_NEXT:
-                return RemoteControlClient.FLAG_KEY_MEDIA_NEXT;
-            case (int) ACTION_SEEK_TO:
-                return RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE;
-            case (int) ACTION_SET_RATING:
-                return RemoteControlClient.FLAG_KEY_MEDIA_RATING;
-        }
-        return 0;
-    }
-
-    public static final Parcelable.Creator<PlaybackState> CREATOR =
-            new Parcelable.Creator<PlaybackState>() {
-        @Override
-        public PlaybackState createFromParcel(Parcel in) {
-            return new PlaybackState(in);
-        }
-
-        @Override
-        public PlaybackState[] newArray(int size) {
-            return new PlaybackState[size];
-        }
-    };
-
-    /**
-     * {@link PlaybackState.CustomAction CustomActions} can be used to extend the capabilities of
-     * the standard transport controls by exposing app specific actions to
-     * {@link MediaController MediaControllers}.
-     */
-    public static final class CustomAction implements Parcelable {
-        private final String mAction;
-        private final CharSequence mName;
-        private final int mIcon;
-        private final Bundle mExtras;
-
-        /**
-         * Use {@link PlaybackState.CustomAction.Builder#build()}.
-         */
-        private CustomAction(String action, CharSequence name, int icon, Bundle extras) {
-            mAction = action;
-            mName = name;
-            mIcon = icon;
-            mExtras = extras;
-        }
-
-        private CustomAction(Parcel in) {
-            mAction = in.readString();
-            mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-            mIcon = in.readInt();
-            mExtras = in.readBundle();
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeString(mAction);
-            TextUtils.writeToParcel(mName, dest, flags);
-            dest.writeInt(mIcon);
-            dest.writeBundle(mExtras);
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        public static final Parcelable.Creator<PlaybackState.CustomAction> CREATOR
-                = new Parcelable.Creator<PlaybackState.CustomAction>() {
-
-            @Override
-            public PlaybackState.CustomAction createFromParcel(Parcel p) {
-                return new PlaybackState.CustomAction(p);
-            }
-
-            @Override
-            public PlaybackState.CustomAction[] newArray(int size) {
-                return new PlaybackState.CustomAction[size];
-            }
-        };
-
-        /**
-         * Returns the action of the {@link CustomAction}.
-         *
-         * @return The action of the {@link CustomAction}.
-         */
-        public String getAction() {
-            return mAction;
-        }
-
-        /**
-         * Returns the display name of this action. e.g. "Favorite"
-         *
-         * @return The display name of this {@link CustomAction}.
-         */
-        public CharSequence getName() {
-            return mName;
-        }
-
-        /**
-         * Returns the resource id of the icon in the {@link MediaSession MediaSession's} package.
-         *
-         * @return The resource id of the icon in the {@link MediaSession MediaSession's} package.
-         */
-        public int getIcon() {
-            return mIcon;
-        }
-
-        /**
-         * Returns extras which provide additional application-specific information about the
-         * action, or null if none. These arguments are meant to be consumed by a
-         * {@link MediaController} if it knows how to handle them.
-         *
-         * @return Optional arguments for the {@link CustomAction}.
-         */
-        public Bundle getExtras() {
-            return mExtras;
-        }
-
-        @Override
-        public String toString() {
-            return "Action:" +
-                    "mName='" + mName +
-                    ", mIcon=" + mIcon +
-                    ", mExtras=" + mExtras;
-        }
-
-        /**
-         * Builder for {@link CustomAction} objects.
-         */
-        public static final class Builder {
-            private final String mAction;
-            private final CharSequence mName;
-            private final int mIcon;
-            private Bundle mExtras;
-
-            /**
-             * Creates a {@link CustomAction} builder with the id, name, and icon set.
-             *
-             * @param action The action of the {@link CustomAction}.
-             * @param name The display name of the {@link CustomAction}. This name will be displayed
-             *             along side the action if the UI supports it.
-             * @param icon The icon resource id of the {@link CustomAction}. This resource id
-             *             must be in the same package as the {@link MediaSession}. It will be
-             *             displayed with the custom action if the UI supports it.
-             */
-            public Builder(String action, CharSequence name, @DrawableRes int icon) {
-                if (TextUtils.isEmpty(action)) {
-                    throw new IllegalArgumentException(
-                            "You must specify an action to build a CustomAction.");
-                }
-                if (TextUtils.isEmpty(name)) {
-                    throw new IllegalArgumentException(
-                            "You must specify a name to build a CustomAction.");
-                }
-                if (icon == 0) {
-                    throw new IllegalArgumentException(
-                            "You must specify an icon resource id to build a CustomAction.");
-                }
-                mAction = action;
-                mName = name;
-                mIcon = icon;
-            }
-
-            /**
-             * Set optional extras for the {@link CustomAction}. These extras are meant to be
-             * consumed by a {@link MediaController} if it knows how to handle them.
-             * Keys should be fully qualified (e.g. "com.example.MY_ARG") to avoid collisions.
-             *
-             * @param extras Optional extras for the {@link CustomAction}.
-             * @return this.
-             */
-            public Builder setExtras(Bundle extras) {
-                mExtras = extras;
-                return this;
-            }
-
-            /**
-             * Build and return the {@link CustomAction} instance with the specified values.
-             *
-             * @return A new {@link CustomAction} instance.
-             */
-            public CustomAction build() {
-                return new CustomAction(mAction, mName, mIcon, mExtras);
-            }
-        }
-    }
-
-    /**
-     * Builder for {@link PlaybackState} objects.
-     */
-    public static final class Builder {
-        private final List<PlaybackState.CustomAction> mCustomActions = new ArrayList<>();
-
-        private int mState;
-        private long mPosition;
-        private long mBufferedPosition;
-        private float mSpeed;
-        private long mActions;
-        private CharSequence mErrorMessage;
-        private long mUpdateTime;
-        private long mActiveItemId = MediaSession.QueueItem.UNKNOWN_ID;
-        private Bundle mExtras;
-
-        /**
-         * Creates an initially empty state builder.
-         */
-        public Builder() {
-        }
-
-        /**
-         * Creates a builder with the same initial values as those in the from
-         * state.
-         *
-         * @param from The state to use for initializing the builder.
-         */
-        public Builder(PlaybackState from) {
-            if (from == null) {
-                return;
-            }
-            mState = from.mState;
-            mPosition = from.mPosition;
-            mBufferedPosition = from.mBufferedPosition;
-            mSpeed = from.mSpeed;
-            mActions = from.mActions;
-            if (from.mCustomActions != null) {
-                mCustomActions.addAll(from.mCustomActions);
-            }
-            mErrorMessage = from.mErrorMessage;
-            mUpdateTime = from.mUpdateTime;
-            mActiveItemId = from.mActiveItemId;
-            mExtras = from.mExtras;
-        }
-
-        /**
-         * Set the current state of playback.
-         * <p>
-         * The position must be in ms and indicates the current playback
-         * position within the item. If the position is unknown use
-         * {@link #PLAYBACK_POSITION_UNKNOWN}. When not using an unknown
-         * position the time at which the position was updated must be provided.
-         * It is okay to use {@link SystemClock#elapsedRealtime()} if the
-         * current position was just retrieved.
-         * <p>
-         * The speed is a multiple of normal playback and should be 0 when
-         * paused and negative when rewinding. Normal playback speed is 1.0.
-         * <p>
-         * The state must be one of the following:
-         * <ul>
-         * <li> {@link PlaybackState#STATE_NONE}</li>
-         * <li> {@link PlaybackState#STATE_STOPPED}</li>
-         * <li> {@link PlaybackState#STATE_PLAYING}</li>
-         * <li> {@link PlaybackState#STATE_PAUSED}</li>
-         * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
-         * <li> {@link PlaybackState#STATE_REWINDING}</li>
-         * <li> {@link PlaybackState#STATE_BUFFERING}</li>
-         * <li> {@link PlaybackState#STATE_ERROR}</li>
-         * <li> {@link PlaybackState#STATE_CONNECTING}</li>
-         * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
-         * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
-         * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
-         * </ul>
-         *
-         * @param state The current state of playback.
-         * @param position The position in the current item in ms.
-         * @param playbackSpeed The current speed of playback as a multiple of
-         *            normal playback.
-         * @param updateTime The time in the {@link SystemClock#elapsedRealtime}
-         *            timebase that the position was updated at.
-         * @return this
-         */
-        public Builder setState(@State int state, long position, float playbackSpeed,
-                long updateTime) {
-            mState = state;
-            mPosition = position;
-            mUpdateTime = updateTime;
-            mSpeed = playbackSpeed;
-            return this;
-        }
-
-        /**
-         * Set the current state of playback.
-         * <p>
-         * The position must be in ms and indicates the current playback
-         * position within the item. If the position is unknown use
-         * {@link #PLAYBACK_POSITION_UNKNOWN}. The update time will be set to
-         * the current {@link SystemClock#elapsedRealtime()}.
-         * <p>
-         * The speed is a multiple of normal playback and should be 0 when
-         * paused and negative when rewinding. Normal playback speed is 1.0.
-         * <p>
-         * The state must be one of the following:
-         * <ul>
-         * <li> {@link PlaybackState#STATE_NONE}</li>
-         * <li> {@link PlaybackState#STATE_STOPPED}</li>
-         * <li> {@link PlaybackState#STATE_PLAYING}</li>
-         * <li> {@link PlaybackState#STATE_PAUSED}</li>
-         * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
-         * <li> {@link PlaybackState#STATE_REWINDING}</li>
-         * <li> {@link PlaybackState#STATE_BUFFERING}</li>
-         * <li> {@link PlaybackState#STATE_ERROR}</li>
-         * <li> {@link PlaybackState#STATE_CONNECTING}</li>
-         * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
-         * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
-         * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
-         * </ul>
-         *
-         * @param state The current state of playback.
-         * @param position The position in the current item in ms.
-         * @param playbackSpeed The current speed of playback as a multiple of
-         *            normal playback.
-         * @return this
-         */
-        public Builder setState(@State int state, long position, float playbackSpeed) {
-            return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime());
-        }
-
-        /**
-         * Set the current actions available on this session. This should use a
-         * bitmask of possible actions.
-         * <ul>
-         * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
-         * <li> {@link PlaybackState#ACTION_REWIND}</li>
-         * <li> {@link PlaybackState#ACTION_PLAY}</li>
-         * <li> {@link PlaybackState#ACTION_PAUSE}</li>
-         * <li> {@link PlaybackState#ACTION_STOP}</li>
-         * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
-         * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
-         * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
-         * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
-         * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
-         * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
-         * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
-         * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
-         * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
-         * <li> {@link PlaybackState#ACTION_PREPARE}</li>
-         * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
-         * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
-         * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
-         * </ul>
-         *
-         * @param actions The set of actions allowed.
-         * @return this
-         */
-        public Builder setActions(@Actions long actions) {
-            mActions = actions;
-            return this;
-        }
-
-        /**
-         * Add a custom action to the playback state. Actions can be used to
-         * expose additional functionality to {@link MediaController
-         * MediaControllers} beyond what is offered by the standard transport
-         * controls.
-         * <p>
-         * e.g. start a radio station based on the current item or skip ahead by
-         * 30 seconds.
-         *
-         * @param action An identifier for this action. It can be sent back to
-         *            the {@link MediaSession} through
-         *            {@link MediaController.TransportControls#sendCustomAction(String, Bundle)}.
-         * @param name The display name for the action. If text is shown with
-         *            the action or used for accessibility, this is what should
-         *            be used.
-         * @param icon The resource action of the icon that should be displayed
-         *            for the action. The resource should be in the package of
-         *            the {@link MediaSession}.
-         * @return this
-         */
-        public Builder addCustomAction(String action, String name, int icon) {
-            return addCustomAction(new PlaybackState.CustomAction(action, name, icon, null));
-        }
-
-        /**
-         * Add a custom action to the playback state. Actions can be used to expose additional
-         * functionality to {@link MediaController MediaControllers} beyond what is offered by the
-         * standard transport controls.
-         * <p>
-         * An example of an action would be to start a radio station based on the current item
-         * or to skip ahead by 30 seconds.
-         *
-         * @param customAction The custom action to add to the {@link PlaybackState}.
-         * @return this
-         */
-        public Builder addCustomAction(PlaybackState.CustomAction customAction) {
-            if (customAction == null) {
-                throw new IllegalArgumentException(
-                        "You may not add a null CustomAction to PlaybackState.");
-            }
-            mCustomActions.add(customAction);
-            return this;
-        }
-
-        /**
-         * Set the current buffered position in ms. This is the farthest
-         * playback point that can be reached from the current position using
-         * only buffered content.
-         *
-         * @param bufferedPosition The position in ms that playback is buffered
-         *            to.
-         * @return this
-         */
-        public Builder setBufferedPosition(long bufferedPosition) {
-            mBufferedPosition = bufferedPosition;
-            return this;
-        }
-
-        /**
-         * Set the active item in the play queue by specifying its id. The
-         * default value is {@link MediaSession.QueueItem#UNKNOWN_ID}
-         *
-         * @param id The id of the active item.
-         * @return this
-         */
-        public Builder setActiveQueueItemId(long id) {
-            mActiveItemId = id;
-            return this;
-        }
-
-        /**
-         * Set a user readable error message. This should be set when the state
-         * is {@link PlaybackState#STATE_ERROR}.
-         *
-         * @param error The error message for display to the user.
-         * @return this
-         */
-        public Builder setErrorMessage(CharSequence error) {
-            mErrorMessage = error;
-            return this;
-        }
-
-        /**
-         * Set any custom extras to be included with the playback state.
-         *
-         * @param extras The extras to include.
-         * @return this
-         */
-        public Builder setExtras(Bundle extras) {
-            mExtras = extras;
-            return this;
-        }
-
-        /**
-         * Build and return the {@link PlaybackState} instance with these
-         * values.
-         *
-         * @return A new state instance.
-         */
-        public PlaybackState build() {
-            return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferedPosition,
-                    mActions, mCustomActions, mActiveItemId, mErrorMessage, mExtras);
-        }
-    }
-}
diff --git a/media/java/android/media/session/SessionCallbackLink.aidl b/media/java/android/media/session/SessionCallbackLink.aidl
deleted file mode 100644
index 9c0ae05..0000000
--- a/media/java/android/media/session/SessionCallbackLink.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * 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.media.session;
-
-parcelable SessionCallbackLink;
diff --git a/media/java/android/media/session/SessionCallbackLink.java b/media/java/android/media/session/SessionCallbackLink.java
deleted file mode 100644
index b13afb5..0000000
--- a/media/java/android/media/session/SessionCallbackLink.java
+++ /dev/null
@@ -1,572 +0,0 @@
-/*
- * 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.media.session;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.content.Intent;
-import android.media.Rating;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-
-/**
- * Handles incoming commands to {@link MediaSession.Callback}.
- * @hide
- */
-@SystemApi
-public final class SessionCallbackLink implements Parcelable {
-    CallbackStub mCallbackStub;
-    ISessionCallback mISessionCallback;
-
-    /**
-     * Creator for stub (Callee)
-     */
-    public SessionCallbackLink(@NonNull CallbackStub callbackStub) {
-        mCallbackStub = callbackStub;
-        mISessionCallback = new CallbackStubProxy();
-    }
-
-    /**
-     * Creator for interface (Caller)
-     */
-    SessionCallbackLink(Parcel in) {
-        mCallbackStub = null;
-        mISessionCallback = ISessionCallback.Stub.asInterface(in.readStrongBinder());
-    }
-
-    /** Interface method for ISessionCallback.notifyCommand */
-    public void notifyCommand(String packageName, int pid, int uid,
-            ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) {
-        try {
-            mISessionCallback.notifyCommand(packageName, pid, uid, caller, command, args, cb);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyMediaButton */
-    public void notifyMediaButton(String packageName, int pid, int uid,
-            Intent mediaButtonIntent, int sequenceNumber, ResultReceiver cb) {
-        try {
-            mISessionCallback.notifyMediaButton(packageName, pid, uid, mediaButtonIntent,
-                    sequenceNumber, cb);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyMediaButtonFromController */
-    public void notifyMediaButtonFromController(String packageName, int pid, int uid,
-            ControllerCallbackLink caller, Intent mediaButtonIntent) {
-        try {
-            mISessionCallback.notifyMediaButtonFromController(packageName, pid, uid, caller,
-                    mediaButtonIntent);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyPrepare */
-    public void notifyPrepare(String packageName, int pid, int uid,
-            ControllerCallbackLink caller) {
-        try {
-            mISessionCallback.notifyPrepare(packageName, pid, uid, caller);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyPrepareFromMediaId */
-    public void notifyPrepareFromMediaId(String packageName, int pid, int uid,
-            ControllerCallbackLink caller, String mediaId, Bundle extras) {
-        try {
-            mISessionCallback.notifyPrepareFromMediaId(packageName, pid, uid, caller, mediaId,
-                    extras);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyPrepareFromSearch */
-    public void notifyPrepareFromSearch(String packageName, int pid, int uid,
-            ControllerCallbackLink caller, String query, Bundle extras) {
-        try {
-            mISessionCallback.notifyPrepareFromSearch(packageName, pid, uid, caller, query, extras);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyPrepareFromUri */
-    public void notifyPrepareFromUri(String packageName, int pid, int uid,
-            ControllerCallbackLink caller, Uri uri, Bundle extras) {
-        try {
-            mISessionCallback.notifyPrepareFromUri(packageName, pid, uid, caller, uri, extras);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyPlay */
-    public void notifyPlay(String packageName, int pid, int uid,
-            ControllerCallbackLink caller) {
-        try {
-            mISessionCallback.notifyPlay(packageName, pid, uid, caller);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyPlayFromMediaId */
-    public void notifyPlayFromMediaId(String packageName, int pid, int uid,
-            ControllerCallbackLink caller, String mediaId, Bundle extras) {
-        try {
-            mISessionCallback.notifyPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyPlayFromSearch */
-    public void notifyPlayFromSearch(String packageName, int pid, int uid,
-            ControllerCallbackLink caller, String query, Bundle extras) {
-        try {
-            mISessionCallback.notifyPlayFromSearch(packageName, pid, uid, caller, query, extras);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyPlayFromUri */
-    public void notifyPlayFromUri(String packageName, int pid, int uid,
-            ControllerCallbackLink caller, Uri uri, Bundle extras) {
-        try {
-            mISessionCallback.notifyPlayFromUri(packageName, pid, uid, caller, uri, extras);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifySkipToTrack */
-    public void notifySkipToTrack(String packageName, int pid, int uid,
-            ControllerCallbackLink caller, long id) {
-        try {
-            mISessionCallback.notifySkipToTrack(packageName, pid, uid, caller, id);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyPause */
-    public void notifyPause(String packageName, int pid, int uid,
-            ControllerCallbackLink caller) {
-        try {
-            mISessionCallback.notifyPause(packageName, pid, uid, caller);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyStop */
-    public void notifyStop(String packageName, int pid, int uid,
-            ControllerCallbackLink caller) {
-        try {
-            mISessionCallback.notifyStop(packageName, pid, uid, caller);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyNext */
-    public void notifyNext(String packageName, int pid, int uid,
-            ControllerCallbackLink caller) {
-        try {
-            mISessionCallback.notifyNext(packageName, pid, uid, caller);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyPrevious */
-    public void notifyPrevious(String packageName, int pid, int uid,
-            ControllerCallbackLink caller) {
-        try {
-            mISessionCallback.notifyPrevious(packageName, pid, uid, caller);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyFastForward */
-    public void notifyFastForward(String packageName, int pid, int uid,
-            ControllerCallbackLink caller) {
-        try {
-            mISessionCallback.notifyFastForward(packageName, pid, uid, caller);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyRewind */
-    public void notifyRewind(String packageName, int pid, int uid,
-            ControllerCallbackLink caller) {
-        try {
-            mISessionCallback.notifyRewind(packageName, pid, uid, caller);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifySeekTo */
-    public void notifySeekTo(String packageName, int pid, int uid,
-            ControllerCallbackLink caller, long pos) {
-        try {
-            mISessionCallback.notifySeekTo(packageName, pid, uid, caller, pos);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyRate */
-    public void notifyRate(String packageName, int pid, int uid, ControllerCallbackLink caller,
-            Rating rating) {
-        try {
-            mISessionCallback.notifyRate(packageName, pid, uid, caller, rating);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyCustomAction */
-    public void notifyCustomAction(String packageName, int pid, int uid,
-            ControllerCallbackLink caller, String action, Bundle args) {
-        try {
-            mISessionCallback.notifyCustomAction(packageName, pid, uid, caller, action, args);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifyAdjustVolume */
-    public void notifyAdjustVolume(String packageName, int pid, int uid,
-            ControllerCallbackLink caller, int direction) {
-        try {
-            mISessionCallback.notifyAdjustVolume(packageName, pid, uid, caller, direction);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for ISessionCallback.notifySetVolumeTo */
-    public void notifySetVolumeTo(String packageName, int pid, int uid,
-            ControllerCallbackLink caller, int value) {
-        try {
-            mISessionCallback.notifySetVolumeTo(packageName, pid, uid, caller, value);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Gets the binder */
-    public IBinder getBinder() {
-        return mISessionCallback.asBinder();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongBinder(mISessionCallback.asBinder());
-    }
-
-    public static final Parcelable.Creator<SessionCallbackLink> CREATOR =
-            new Parcelable.Creator<SessionCallbackLink>() {
-                @Override
-                public SessionCallbackLink createFromParcel(Parcel in) {
-                    return new SessionCallbackLink(in);
-                }
-
-                @Override
-                public SessionCallbackLink[] newArray(int size) {
-                    return new SessionCallbackLink[size];
-                }
-            };
-
-    /**
-     * Class for Stub implementation
-     */
-    public abstract static class CallbackStub {
-        /** Stub method for ISessionCallback.notifyCommand */
-        public void onCommand(String packageName, int pid, int uid, ControllerCallbackLink caller,
-                String command, Bundle args, ResultReceiver cb) {
-        }
-
-        /** Stub method for ISessionCallback.notifyMediaButton */
-        public void onMediaButton(String packageName, int pid, int uid, Intent mediaButtonIntent,
-                int sequenceNumber, ResultReceiver cb) {
-        }
-
-        /** Stub method for ISessionCallback.notifyMediaButtonFromController */
-        public void onMediaButtonFromController(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, Intent mediaButtonIntent) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPrepare */
-        public void onPrepare(String packageName, int pid, int uid, ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPrepareFromMediaId */
-        public void onPrepareFromMediaId(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String mediaId, Bundle extras) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPrepareFromSearch */
-        public void onPrepareFromSearch(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String query, Bundle extras) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPrepareFromUri */
-        public void onPrepareFromUri(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, Uri uri, Bundle extras) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPlay */
-        public void onPlay(String packageName, int pid, int uid, ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPlayFromMediaId */
-        public void onPlayFromMediaId(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String mediaId, Bundle extras) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPlayFromSearch */
-        public void onPlayFromSearch(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String query, Bundle extras) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPlayFromUri */
-        public void onPlayFromUri(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, Uri uri, Bundle extras) {
-        }
-
-        /** Stub method for ISessionCallback.notifySkipToTrack */
-        public void onSkipToTrack(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, long id) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPause */
-        public void onPause(String packageName, int pid, int uid, ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyStop */
-        public void onStop(String packageName, int pid, int uid, ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyNext */
-        public void onNext(String packageName, int pid, int uid, ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyPrevious */
-        public void onPrevious(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyFastForward */
-        public void onFastForward(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifyRewind */
-        public void onRewind(String packageName, int pid, int uid, ControllerCallbackLink caller) {
-        }
-
-        /** Stub method for ISessionCallback.notifySeekTo */
-        public void onSeekTo(String packageName, int pid, int uid, ControllerCallbackLink caller,
-                long pos) {
-        }
-
-        /** Stub method for ISessionCallback.notifyRate */
-        public void onRate(String packageName, int pid, int uid, ControllerCallbackLink caller,
-                Rating rating) {
-        }
-
-        /** Stub method for ISessionCallback.notifyCustomAction */
-        public void onCustomAction(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String action, Bundle args) {
-        }
-
-        /** Stub method for ISessionCallback.notifyAdjustVolume */
-        public void onAdjustVolume(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, int direction) {
-        }
-
-        /** Stub method for ISessionCallback.notifySetVolumeTo */
-        public void onSetVolumeTo(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, int value) {
-        }
-    }
-
-    private class CallbackStubProxy extends ISessionCallback.Stub {
-        @Override
-        public void notifyCommand(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) {
-            mCallbackStub.onCommand(packageName, pid, uid, caller, command, args, cb);
-        }
-
-        @Override
-        public void notifyMediaButton(String packageName, int pid, int uid,
-                Intent mediaButtonIntent, int sequenceNumber, ResultReceiver cb) {
-            mCallbackStub.onMediaButton(packageName, pid, uid, mediaButtonIntent, sequenceNumber,
-                    cb);
-        }
-
-        @Override
-        public void notifyMediaButtonFromController(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, Intent mediaButtonIntent) {
-            mCallbackStub.onMediaButtonFromController(packageName, pid, uid, caller,
-                    mediaButtonIntent);
-        }
-
-        @Override
-        public void notifyPrepare(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            mCallbackStub.onPrepare(packageName, pid, uid, caller);
-        }
-
-        @Override
-        public void notifyPrepareFromMediaId(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String mediaId, Bundle extras) {
-            mCallbackStub.onPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras);
-        }
-
-        @Override
-        public void notifyPrepareFromSearch(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String query, Bundle extras) {
-            mCallbackStub.onPrepareFromSearch(packageName, pid, uid, caller, query, extras);
-        }
-
-        @Override
-        public void notifyPrepareFromUri(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, Uri uri, Bundle extras) {
-            mCallbackStub.onPrepareFromUri(packageName, pid, uid, caller, uri, extras);
-        }
-
-        @Override
-        public void notifyPlay(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            mCallbackStub.onPlay(packageName, pid, uid, caller);
-        }
-
-        @Override
-        public void notifyPlayFromMediaId(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String mediaId, Bundle extras) {
-            mCallbackStub.onPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras);
-        }
-
-        @Override
-        public void notifyPlayFromSearch(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String query, Bundle extras) {
-            mCallbackStub.onPlayFromSearch(packageName, pid, uid, caller, query, extras);
-        }
-
-        @Override
-        public void notifyPlayFromUri(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, Uri uri, Bundle extras) {
-            mCallbackStub.onPlayFromUri(packageName, pid, uid, caller, uri, extras);
-        }
-
-        @Override
-        public void notifySkipToTrack(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, long id) {
-            mCallbackStub.onSkipToTrack(packageName, pid, uid, caller, id);
-        }
-
-        @Override
-        public void notifyPause(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            mCallbackStub.onPause(packageName, pid, uid, caller);
-        }
-
-        @Override
-        public void notifyStop(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            mCallbackStub.onStop(packageName, pid, uid, caller);
-        }
-
-        @Override
-        public void notifyNext(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            mCallbackStub.onNext(packageName, pid, uid, caller);
-        }
-
-        @Override
-        public void notifyPrevious(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            mCallbackStub.onPrevious(packageName, pid, uid, caller);
-        }
-
-        @Override
-        public void notifyFastForward(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            mCallbackStub.onFastForward(packageName, pid, uid, caller);
-        }
-
-        @Override
-        public void notifyRewind(String packageName, int pid, int uid,
-                ControllerCallbackLink caller) {
-            mCallbackStub.onRewind(packageName, pid, uid, caller);
-        }
-
-        @Override
-        public void notifySeekTo(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, long pos) {
-            mCallbackStub.onSeekTo(packageName, pid, uid, caller, pos);
-        }
-
-        @Override
-        public void notifyRate(String packageName, int pid, int uid, ControllerCallbackLink caller,
-                Rating rating) {
-            mCallbackStub.onRate(packageName, pid, uid, caller, rating);
-        }
-
-        @Override
-        public void notifyCustomAction(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, String action, Bundle args) {
-            mCallbackStub.onCustomAction(packageName, pid, uid, caller, action, args);
-        }
-
-        @Override
-        public void notifyAdjustVolume(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, int direction) {
-            mCallbackStub.onAdjustVolume(packageName, pid, uid, caller, direction);
-        }
-
-        @Override
-        public void notifySetVolumeTo(String packageName, int pid, int uid,
-                ControllerCallbackLink caller, int value) {
-            mCallbackStub.onSetVolumeTo(packageName, pid, uid, caller, value);
-        }
-    }
-}
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index fa69062..ada77c5 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -372,6 +372,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+    @UnsupportedAppUsage
     public int getModelState(UUID soundModelId) {
         if (soundModelId == null) {
             return STATUS_ERROR;
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 5cb8fb8..30907a5 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -33,7 +33,10 @@
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.HdmiUtils;
+import android.hardware.hdmi.HdmiUtils.HdmiAddressRelativePosition;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -49,7 +52,6 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.annotation.Retention;
@@ -145,6 +147,8 @@
     // Attributes specific to HDMI
     private final HdmiDeviceInfo mHdmiDeviceInfo;
     private final boolean mIsConnectedToHdmiSwitch;
+    @HdmiAddressRelativePosition
+    private final int mHdmiConnectionRelativePosition;
     private final String mParentId;
 
     private final Bundle mExtras;
@@ -260,7 +264,9 @@
     private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput,
             CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected,
             String setupActivity, boolean canRecord, int tunerCount, HdmiDeviceInfo hdmiDeviceInfo,
-            boolean isConnectedToHdmiSwitch, String parentId, Bundle extras) {
+            boolean isConnectedToHdmiSwitch,
+            @HdmiAddressRelativePosition int hdmiConnectionRelativePosition, String parentId,
+            Bundle extras) {
         mService = service;
         mId = id;
         mType = type;
@@ -275,6 +281,7 @@
         mTunerCount = tunerCount;
         mHdmiDeviceInfo = hdmiDeviceInfo;
         mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch;
+        mHdmiConnectionRelativePosition = hdmiConnectionRelativePosition;
         mParentId = parentId;
         mExtras = extras;
     }
@@ -419,6 +426,7 @@
     /**
      * Returns {@code true}, if a CEC device for this TV input is connected to an HDMI switch, i.e.,
      * the device isn't directly connected to a HDMI port.
+     * TODO(b/110094868): add @Deprecated for Q
      * @hide
      */
     @SystemApi
@@ -427,6 +435,16 @@
     }
 
     /**
+     * Returns the relative position of this HDMI input.
+     * TODO(b/110094868): unhide for Q
+     * @hide
+     */
+    @HdmiAddressRelativePosition
+    public int getHdmiConnectionRelativePosition() {
+        return mHdmiConnectionRelativePosition;
+    }
+
+    /**
      * Checks if this TV input is marked hidden by the user in the settings.
      *
      * @param context Supplies a {@link Context} used to check if this TV input is hidden.
@@ -555,6 +573,7 @@
                 && mTunerCount == obj.mTunerCount
                 && Objects.equals(mHdmiDeviceInfo, obj.mHdmiDeviceInfo)
                 && mIsConnectedToHdmiSwitch == obj.mIsConnectedToHdmiSwitch
+                && mHdmiConnectionRelativePosition == obj.mHdmiConnectionRelativePosition
                 && TextUtils.equals(mParentId, obj.mParentId)
                 && Objects.equals(mExtras, obj.mExtras);
     }
@@ -589,6 +608,7 @@
         dest.writeInt(mTunerCount);
         dest.writeParcelable(mHdmiDeviceInfo, flags);
         dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0);
+        dest.writeInt(mHdmiConnectionRelativePosition);
         dest.writeString(mParentId);
         dest.writeBundle(mExtras);
     }
@@ -630,6 +650,7 @@
         mTunerCount = in.readInt();
         mHdmiDeviceInfo = in.readParcelable(null);
         mIsConnectedToHdmiSwitch = in.readByte() == 1;
+        mHdmiConnectionRelativePosition = in.readInt();
         mParentId = in.readString();
         mExtras = in.readBundle();
     }
@@ -883,12 +904,17 @@
             int type;
             boolean isHardwareInput = false;
             boolean isConnectedToHdmiSwitch = false;
+            @HdmiAddressRelativePosition
+            int hdmiConnectionRelativePosition = HdmiUtils.HDMI_RELATIVE_POSITION_UNKNOWN;
 
             if (mHdmiDeviceInfo != null) {
                 id = generateInputId(componentName, mHdmiDeviceInfo);
                 type = TYPE_HDMI;
                 isHardwareInput = true;
-                isConnectedToHdmiSwitch = (mHdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
+                hdmiConnectionRelativePosition = getRelativePosition(mContext, mHdmiDeviceInfo);
+                isConnectedToHdmiSwitch =
+                        hdmiConnectionRelativePosition
+                                != HdmiUtils.HDMI_RELATIVE_POSITION_DIRECTLY_BELOW;
             } else if (mTvInputHardwareInfo != null) {
                 id = generateInputId(componentName, mTvInputHardwareInfo);
                 type = sHardwareTypeToTvInputType.get(mTvInputHardwareInfo.getType(), TYPE_TUNER);
@@ -901,7 +927,8 @@
             return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabel, mLabelResId,
                     mIcon, mIconStandby, mIconDisconnected, mSetupActivity,
                     mCanRecord == null ? false : mCanRecord, mTunerCount == null ? 0 : mTunerCount,
-                    mHdmiDeviceInfo, isConnectedToHdmiSwitch, mParentId, mExtras);
+                    mHdmiDeviceInfo, isConnectedToHdmiSwitch, hdmiConnectionRelativePosition,
+                    mParentId, mExtras);
         }
 
         private static String generateInputId(ComponentName name) {
@@ -923,6 +950,16 @@
                     + tvInputHardwareInfo.getDeviceId();
         }
 
+        private static int getRelativePosition(Context context, HdmiDeviceInfo info) {
+            HdmiControlManager hcm =
+                    (HdmiControlManager) context.getSystemService(Context.HDMI_CONTROL_SERVICE);
+            if (hcm == null) {
+                return HdmiUtils.HDMI_RELATIVE_POSITION_UNKNOWN;
+            }
+            return HdmiUtils.getHdmiAddressRelativePosition(
+                    info.getPhysicalAddress(), hcm.getPhysicalAddress());
+        }
+
         private void parseServiceMetadata(int inputType) {
             ServiceInfo si = mResolveInfo.serviceInfo;
             PackageManager pm = mContext.getPackageManager();
diff --git a/media/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl
deleted file mode 100644
index 84f41f6..0000000
--- a/media/java/android/service/media/IMediaBrowserService.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 Google Inc. All Rights Reserved.
-
-package android.service.media;
-
-import android.content.res.Configuration;
-import android.service.media.IMediaBrowserServiceCallbacks;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-/**
- * Media API allows clients to browse through hierarchy of a user’s media collection,
- * playback a specific media entry and interact with the now playing queue.
- * @hide
- */
-oneway interface IMediaBrowserService {
-    void connect(String pkg, in Bundle rootHints, IMediaBrowserServiceCallbacks callbacks);
-    void disconnect(IMediaBrowserServiceCallbacks callbacks);
-
-    void addSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks);
-    void removeSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks);
-
-    void getMediaItem(String uri, in ResultReceiver cb, IMediaBrowserServiceCallbacks callbacks);
-    void addSubscription(String uri, in IBinder token, in Bundle options,
-            IMediaBrowserServiceCallbacks callbacks);
-    void removeSubscription(String uri, in IBinder token, IMediaBrowserServiceCallbacks callbacks);
-}
diff --git a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
deleted file mode 100644
index deeab1a..0000000
--- a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 Google Inc. All Rights Reserved.
-
-package android.service.media;
-
-import android.content.pm.ParceledListSlice;
-import android.graphics.Bitmap;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-
-/**
- * Media API allows clients to browse through hierarchy of a user’s media collection,
- * playback a specific media entry and interact with the now playing queue.
- * @hide
- */
-oneway interface IMediaBrowserServiceCallbacks {
-    /**
-     * Invoked when the connected has been established.
-     * @param root The root media id for browsing.
-     * @param session The {@link MediaSession.Token media session token} that can be used to control
-     *         the playback of the media app.
-     * @param extra Extras returned by the media service.
-     */
-    void onConnect(String root, in MediaSession.Token session, in Bundle extras);
-    void onConnectFailed();
-    void onLoadChildren(String mediaId, in ParceledListSlice list);
-    void onLoadChildrenWithOptions(String mediaId, in ParceledListSlice list, in Bundle options);
-}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
deleted file mode 100644
index 5a60ac1..0000000
--- a/media/java/android/service/media/MediaBrowserService.java
+++ /dev/null
@@ -1,857 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.media;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.UnsupportedAppUsage;
-import android.app.Service;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
-import android.media.browse.MediaBrowser;
-import android.media.browse.MediaBrowserUtils;
-import android.media.session.MediaSession;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.media.session.MediaSessionManager;
-import android.media.session.MediaSessionManager.RemoteUserInfo;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.service.media.IMediaBrowserService;
-import android.service.media.IMediaBrowserServiceCallbacks;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.Pair;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Base class for media browser services.
- * <p>
- * Media browser services enable applications to browse media content provided by an application
- * and ask the application to start playing it. They may also be used to control content that
- * is already playing by way of a {@link MediaSession}.
- * </p>
- *
- * To extend this class, you must declare the service in your manifest file with
- * an intent filter with the {@link #SERVICE_INTERFACE} action.
- *
- * For example:
- * </p><pre>
- * &lt;service android:name=".MyMediaBrowserService"
- *          android:label="&#64;string/service_name" >
- *     &lt;intent-filter>
- *         &lt;action android:name="android.media.browse.MediaBrowserService" />
- *     &lt;/intent-filter>
- * &lt;/service>
- * </pre>
- *
- */
-public abstract class MediaBrowserService extends Service {
-    private static final String TAG = "MediaBrowserService";
-    private static final boolean DBG = false;
-
-    /**
-     * The {@link Intent} that must be declared as handled by the service.
-     */
-    @SdkConstant(SdkConstantType.SERVICE_ACTION)
-    public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
-
-    /**
-     * A key for passing the MediaItem to the ResultReceiver in getItem.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public static final String KEY_MEDIA_ITEM = "media_item";
-
-    private static final int RESULT_FLAG_OPTION_NOT_HANDLED = 1 << 0;
-    private static final int RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED = 1 << 1;
-
-    private static final int RESULT_ERROR = -1;
-    private static final int RESULT_OK = 0;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag=true, value = { RESULT_FLAG_OPTION_NOT_HANDLED,
-            RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED })
-    private @interface ResultFlags { }
-
-    private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>();
-    private ConnectionRecord mCurConnection;
-    private final Handler mHandler = new Handler();
-    private ServiceBinder mBinder;
-    MediaSession.Token mSession;
-
-    /**
-     * All the info about a connection.
-     */
-    private class ConnectionRecord implements IBinder.DeathRecipient {
-        String pkg;
-        int uid;
-        int pid;
-        Bundle rootHints;
-        IMediaBrowserServiceCallbacks callbacks;
-        BrowserRoot root;
-        HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>();
-
-        @Override
-        public void binderDied() {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mConnections.remove(callbacks.asBinder());
-                }
-            });
-        }
-    }
-
-    /**
-     * Completion handler for asynchronous callback methods in {@link MediaBrowserService}.
-     * <p>
-     * Each of the methods that takes one of these to send the result must call
-     * {@link #sendResult} to respond to the caller with the given results. If those
-     * functions return without calling {@link #sendResult}, they must instead call
-     * {@link #detach} before returning, and then may call {@link #sendResult} when
-     * they are done. If more than one of those methods is called, an exception will
-     * be thrown.
-     *
-     * @see #onLoadChildren
-     * @see #onLoadItem
-     */
-    public class Result<T> {
-        private Object mDebug;
-        private boolean mDetachCalled;
-        private boolean mSendResultCalled;
-        @UnsupportedAppUsage
-        private int mFlags;
-
-        Result(Object debug) {
-            mDebug = debug;
-        }
-
-        /**
-         * Send the result back to the caller.
-         */
-        public void sendResult(T result) {
-            if (mSendResultCalled) {
-                throw new IllegalStateException("sendResult() called twice for: " + mDebug);
-            }
-            mSendResultCalled = true;
-            onResultSent(result, mFlags);
-        }
-
-        /**
-         * Detach this message from the current thread and allow the {@link #sendResult}
-         * call to happen later.
-         */
-        public void detach() {
-            if (mDetachCalled) {
-                throw new IllegalStateException("detach() called when detach() had already"
-                        + " been called for: " + mDebug);
-            }
-            if (mSendResultCalled) {
-                throw new IllegalStateException("detach() called when sendResult() had already"
-                        + " been called for: " + mDebug);
-            }
-            mDetachCalled = true;
-        }
-
-        boolean isDone() {
-            return mDetachCalled || mSendResultCalled;
-        }
-
-        void setFlags(@ResultFlags int flags) {
-            mFlags = flags;
-        }
-
-        /**
-         * Called when the result is sent, after assertions about not being called twice
-         * have happened.
-         */
-        void onResultSent(T result, @ResultFlags int flags) {
-        }
-    }
-
-    private class ServiceBinder extends IMediaBrowserService.Stub {
-        @Override
-        public void connect(final String pkg, final Bundle rootHints,
-                final IMediaBrowserServiceCallbacks callbacks) {
-
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            if (!isValidPackage(pkg, uid)) {
-                throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid
-                        + " package=" + pkg);
-            }
-
-            mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        final IBinder b = callbacks.asBinder();
-
-                        // Clear out the old subscriptions. We are getting new ones.
-                        mConnections.remove(b);
-
-                        final ConnectionRecord connection = new ConnectionRecord();
-                        connection.pkg = pkg;
-                        connection.pid = pid;
-                        connection.uid = uid;
-                        connection.rootHints = rootHints;
-                        connection.callbacks = callbacks;
-
-                        mCurConnection = connection;
-                        connection.root = MediaBrowserService.this.onGetRoot(pkg, uid, rootHints);
-                        mCurConnection = null;
-
-                        // If they didn't return something, don't allow this client.
-                        if (connection.root == null) {
-                            Log.i(TAG, "No root for client " + pkg + " from service "
-                                    + getClass().getName());
-                            try {
-                                callbacks.onConnectFailed();
-                            } catch (RemoteException ex) {
-                                Log.w(TAG, "Calling onConnectFailed() failed. Ignoring. "
-                                        + "pkg=" + pkg);
-                            }
-                        } else {
-                            try {
-                                mConnections.put(b, connection);
-                                b.linkToDeath(connection, 0);
-                                if (mSession != null) {
-                                    callbacks.onConnect(connection.root.getRootId(),
-                                            mSession, connection.root.getExtras());
-                                }
-                            } catch (RemoteException ex) {
-                                Log.w(TAG, "Calling onConnect() failed. Dropping client. "
-                                        + "pkg=" + pkg);
-                                mConnections.remove(b);
-                            }
-                        }
-                    }
-                });
-        }
-
-        @Override
-        public void disconnect(final IMediaBrowserServiceCallbacks callbacks) {
-            mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        final IBinder b = callbacks.asBinder();
-
-                        // Clear out the old subscriptions. We are getting new ones.
-                        final ConnectionRecord old = mConnections.remove(b);
-                        if (old != null) {
-                            // TODO
-                            old.callbacks.asBinder().unlinkToDeath(old, 0);
-                        }
-                    }
-                });
-        }
-
-        @Override
-        public void addSubscriptionDeprecated(String id, IMediaBrowserServiceCallbacks callbacks) {
-            // do-nothing
-        }
-
-        @Override
-        public void addSubscription(final String id, final IBinder token, final Bundle options,
-                final IMediaBrowserServiceCallbacks callbacks) {
-            mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        final IBinder b = callbacks.asBinder();
-
-                        // Get the record for the connection
-                        final ConnectionRecord connection = mConnections.get(b);
-                        if (connection == null) {
-                            Log.w(TAG, "addSubscription for callback that isn't registered id="
-                                + id);
-                            return;
-                        }
-
-                        MediaBrowserService.this.addSubscription(id, connection, token, options);
-                    }
-                });
-        }
-
-        @Override
-        public void removeSubscriptionDeprecated(String id, IMediaBrowserServiceCallbacks callbacks) {
-            // do-nothing
-        }
-
-        @Override
-        public void removeSubscription(final String id, final IBinder token,
-                final IMediaBrowserServiceCallbacks callbacks) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    final IBinder b = callbacks.asBinder();
-
-                    ConnectionRecord connection = mConnections.get(b);
-                    if (connection == null) {
-                        Log.w(TAG, "removeSubscription for callback that isn't registered id="
-                                + id);
-                        return;
-                    }
-                    if (!MediaBrowserService.this.removeSubscription(id, connection, token)) {
-                        Log.w(TAG, "removeSubscription called for " + id
-                                + " which is not subscribed");
-                    }
-                }
-            });
-        }
-
-        @Override
-        public void getMediaItem(final String mediaId, final ResultReceiver receiver,
-                final IMediaBrowserServiceCallbacks callbacks) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    final IBinder b = callbacks.asBinder();
-                    ConnectionRecord connection = mConnections.get(b);
-                    if (connection == null) {
-                        Log.w(TAG, "getMediaItem for callback that isn't registered id=" + mediaId);
-                        return;
-                    }
-                    performLoadItem(mediaId, connection, receiver);
-                }
-            });
-        }
-    }
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mBinder = new ServiceBinder();
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        if (SERVICE_INTERFACE.equals(intent.getAction())) {
-            return mBinder;
-        }
-        return null;
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-    }
-
-    /**
-     * Called to get the root information for browsing by a particular client.
-     * <p>
-     * The implementation should verify that the client package has permission
-     * to access browse media information before returning the root id; it
-     * should return null if the client is not allowed to access this
-     * information.
-     * </p>
-     *
-     * @param clientPackageName The package name of the application which is
-     *            requesting access to browse media.
-     * @param clientUid The uid of the application which is requesting access to
-     *            browse media.
-     * @param rootHints An optional bundle of service-specific arguments to send
-     *            to the media browser service when connecting and retrieving the
-     *            root id for browsing, or null if none. The contents of this
-     *            bundle may affect the information returned when browsing.
-     * @return The {@link BrowserRoot} for accessing this app's content or null.
-     * @see BrowserRoot#EXTRA_RECENT
-     * @see BrowserRoot#EXTRA_OFFLINE
-     * @see BrowserRoot#EXTRA_SUGGESTED
-     */
-    public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
-            int clientUid, @Nullable Bundle rootHints);
-
-    /**
-     * Called to get information about the children of a media item.
-     * <p>
-     * Implementations must call {@link Result#sendResult result.sendResult}
-     * with the list of children. If loading the children will be an expensive
-     * operation that should be performed on another thread,
-     * {@link Result#detach result.detach} may be called before returning from
-     * this function, and then {@link Result#sendResult result.sendResult}
-     * called when the loading is complete.
-     * </p><p>
-     * In case the media item does not have any children, call {@link Result#sendResult}
-     * with an empty list. When the given {@code parentId} is invalid, implementations must
-     * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
-     * {@link MediaBrowser.SubscriptionCallback#onError}.
-     * </p>
-     *
-     * @param parentId The id of the parent media item whose children are to be
-     *            queried.
-     * @param result The Result to send the list of children to.
-     */
-    public abstract void onLoadChildren(@NonNull String parentId,
-            @NonNull Result<List<MediaBrowser.MediaItem>> result);
-
-    /**
-     * Called to get information about the children of a media item.
-     * <p>
-     * Implementations must call {@link Result#sendResult result.sendResult}
-     * with the list of children. If loading the children will be an expensive
-     * operation that should be performed on another thread,
-     * {@link Result#detach result.detach} may be called before returning from
-     * this function, and then {@link Result#sendResult result.sendResult}
-     * called when the loading is complete.
-     * </p><p>
-     * In case the media item does not have any children, call {@link Result#sendResult}
-     * with an empty list. When the given {@code parentId} is invalid, implementations must
-     * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
-     * {@link MediaBrowser.SubscriptionCallback#onError}.
-     * </p>
-     *
-     * @param parentId The id of the parent media item whose children are to be
-     *            queried.
-     * @param result The Result to send the list of children to.
-     * @param options The bundle of service-specific arguments sent from the media
-     *            browser. The information returned through the result should be
-     *            affected by the contents of this bundle.
-     */
-    public void onLoadChildren(@NonNull String parentId,
-            @NonNull Result<List<MediaBrowser.MediaItem>> result, @NonNull Bundle options) {
-        // To support backward compatibility, when the implementation of MediaBrowserService doesn't
-        // override onLoadChildren() with options, onLoadChildren() without options will be used
-        // instead, and the options will be applied in the implementation of result.onResultSent().
-        result.setFlags(RESULT_FLAG_OPTION_NOT_HANDLED);
-        onLoadChildren(parentId, result);
-    }
-
-    /**
-     * Called to get information about a specific media item.
-     * <p>
-     * Implementations must call {@link Result#sendResult result.sendResult}. If
-     * loading the item will be an expensive operation {@link Result#detach
-     * result.detach} may be called before returning from this function, and
-     * then {@link Result#sendResult result.sendResult} called when the item has
-     * been loaded.
-     * </p><p>
-     * When the given {@code itemId} is invalid, implementations must call
-     * {@link Result#sendResult result.sendResult} with {@code null}.
-     * </p><p>
-     * The default implementation will invoke {@link MediaBrowser.ItemCallback#onError}.
-     * </p>
-     *
-     * @param itemId The id for the specific
-     *            {@link android.media.browse.MediaBrowser.MediaItem}.
-     * @param result The Result to send the item to.
-     */
-    public void onLoadItem(String itemId, Result<MediaBrowser.MediaItem> result) {
-        result.setFlags(RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED);
-        result.sendResult(null);
-    }
-
-    /**
-     * Call to set the media session.
-     * <p>
-     * This should be called as soon as possible during the service's startup.
-     * It may only be called once.
-     *
-     * @param token The token for the service's {@link MediaSession}.
-     */
-    public void setSessionToken(final MediaSession.Token token) {
-        if (token == null) {
-            throw new IllegalArgumentException("Session token may not be null.");
-        }
-        if (mSession != null) {
-            throw new IllegalStateException("The session token has already been set.");
-        }
-        mSession = token;
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                Iterator<ConnectionRecord> iter = mConnections.values().iterator();
-                while (iter.hasNext()){
-                    ConnectionRecord connection = iter.next();
-                    try {
-                        connection.callbacks.onConnect(connection.root.getRootId(), token,
-                                connection.root.getExtras());
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Connection for " + connection.pkg + " is no longer valid.");
-                        iter.remove();
-                    }
-                }
-            }
-        });
-    }
-
-    /**
-     * Gets the session token, or null if it has not yet been created
-     * or if it has been destroyed.
-     */
-    public @Nullable MediaSession.Token getSessionToken() {
-        return mSession;
-    }
-
-    /**
-     * Gets the root hints sent from the currently connected {@link MediaBrowser}.
-     * The root hints are service-specific arguments included in an optional bundle sent to the
-     * media browser service when connecting and retrieving the root id for browsing, or null if
-     * none. The contents of this bundle may affect the information returned when browsing.
-     *
-     * @throws IllegalStateException If this method is called outside of {@link #onGetRoot} or
-     *             {@link #onLoadChildren} or {@link #onLoadItem}.
-     * @see MediaBrowserService.BrowserRoot#EXTRA_RECENT
-     * @see MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
-     * @see MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
-     */
-    public final Bundle getBrowserRootHints() {
-        if (mCurConnection == null) {
-            throw new IllegalStateException("This should be called inside of onGetRoot or"
-                    + " onLoadChildren or onLoadItem methods");
-        }
-        return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints);
-    }
-
-    /**
-     * Gets the browser information who sent the current request.
-     *
-     * @throws IllegalStateException If this method is called outside of {@link #onGetRoot} or
-     *             {@link #onLoadChildren} or {@link #onLoadItem}.
-     * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
-     */
-    public final RemoteUserInfo getCurrentBrowserInfo() {
-        if (mCurConnection == null) {
-            throw new IllegalStateException("This should be called inside of onGetRoot or"
-                    + " onLoadChildren or onLoadItem methods");
-        }
-        return new RemoteUserInfo(mCurConnection.pkg, mCurConnection.pid, mCurConnection.uid,
-                mCurConnection.callbacks.asBinder());
-    }
-
-    /**
-     * Notifies all connected media browsers that the children of
-     * the specified parent id have changed in some way.
-     * This will cause browsers to fetch subscribed content again.
-     *
-     * @param parentId The id of the parent media item whose
-     * children changed.
-     */
-    public void notifyChildrenChanged(@NonNull String parentId) {
-        notifyChildrenChangedInternal(parentId, null);
-    }
-
-    /**
-     * Notifies all connected media browsers that the children of
-     * the specified parent id have changed in some way.
-     * This will cause browsers to fetch subscribed content again.
-     *
-     * @param parentId The id of the parent media item whose
-     *            children changed.
-     * @param options The bundle of service-specific arguments to send
-     *            to the media browser. The contents of this bundle may
-     *            contain the information about the change.
-     */
-    public void notifyChildrenChanged(@NonNull String parentId, @NonNull Bundle options) {
-        if (options == null) {
-            throw new IllegalArgumentException("options cannot be null in notifyChildrenChanged");
-        }
-        notifyChildrenChangedInternal(parentId, options);
-    }
-
-    private void notifyChildrenChangedInternal(final String parentId, final Bundle options) {
-        if (parentId == null) {
-            throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged");
-        }
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                for (IBinder binder : mConnections.keySet()) {
-                    ConnectionRecord connection = mConnections.get(binder);
-                    List<Pair<IBinder, Bundle>> callbackList =
-                            connection.subscriptions.get(parentId);
-                    if (callbackList != null) {
-                        for (Pair<IBinder, Bundle> callback : callbackList) {
-                            if (MediaBrowserUtils.hasDuplicatedItems(options, callback.second)) {
-                                performLoadChildren(parentId, connection, callback.second);
-                            }
-                        }
-                    }
-                }
-            }
-        });
-    }
-
-    /**
-     * Return whether the given package is one of the ones that is owned by the uid.
-     */
-    private boolean isValidPackage(String pkg, int uid) {
-        if (pkg == null) {
-            return false;
-        }
-        final PackageManager pm = getPackageManager();
-        final String[] packages = pm.getPackagesForUid(uid);
-        final int N = packages.length;
-        for (int i=0; i<N; i++) {
-            if (packages[i].equals(pkg)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Save the subscription and if it is a new subscription send the results.
-     */
-    private void addSubscription(String id, ConnectionRecord connection, IBinder token,
-            Bundle options) {
-        // Save the subscription
-        List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id);
-        if (callbackList == null) {
-            callbackList = new ArrayList<>();
-        }
-        for (Pair<IBinder, Bundle> callback : callbackList) {
-            if (token == callback.first
-                    && MediaBrowserUtils.areSameOptions(options, callback.second)) {
-                return;
-            }
-        }
-        callbackList.add(new Pair<>(token, options));
-        connection.subscriptions.put(id, callbackList);
-        // send the results
-        performLoadChildren(id, connection, options);
-    }
-
-    /**
-     * Remove the subscription.
-     */
-    private boolean removeSubscription(String id, ConnectionRecord connection, IBinder token) {
-        if (token == null) {
-            return connection.subscriptions.remove(id) != null;
-        }
-        boolean removed = false;
-        List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id);
-        if (callbackList != null) {
-            Iterator<Pair<IBinder, Bundle>> iter = callbackList.iterator();
-            while (iter.hasNext()){
-                if (token == iter.next().first) {
-                    removed = true;
-                    iter.remove();
-                }
-            }
-            if (callbackList.size() == 0) {
-                connection.subscriptions.remove(id);
-            }
-        }
-        return removed;
-    }
-
-    /**
-     * Call onLoadChildren and then send the results back to the connection.
-     * <p>
-     * Callers must make sure that this connection is still connected.
-     */
-    private void performLoadChildren(final String parentId, final ConnectionRecord connection,
-            final Bundle options) {
-        final Result<List<MediaBrowser.MediaItem>> result
-                = new Result<List<MediaBrowser.MediaItem>>(parentId) {
-            @Override
-            void onResultSent(List<MediaBrowser.MediaItem> list, @ResultFlags int flag) {
-                if (mConnections.get(connection.callbacks.asBinder()) != connection) {
-                    if (DBG) {
-                        Log.d(TAG, "Not sending onLoadChildren result for connection that has"
-                                + " been disconnected. pkg=" + connection.pkg + " id=" + parentId);
-                    }
-                    return;
-                }
-
-                List<MediaBrowser.MediaItem> filteredList =
-                        (flag & RESULT_FLAG_OPTION_NOT_HANDLED) != 0
-                        ? applyOptions(list, options) : list;
-                final ParceledListSlice<MediaBrowser.MediaItem> pls =
-                        filteredList == null ? null : new ParceledListSlice<>(filteredList);
-                try {
-                    connection.callbacks.onLoadChildrenWithOptions(parentId, pls, options);
-                } catch (RemoteException ex) {
-                    // The other side is in the process of crashing.
-                    Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId
-                            + " package=" + connection.pkg);
-                }
-            }
-        };
-
-        mCurConnection = connection;
-        if (options == null) {
-            onLoadChildren(parentId, result);
-        } else {
-            onLoadChildren(parentId, result, options);
-        }
-        mCurConnection = null;
-
-        if (!result.isDone()) {
-            throw new IllegalStateException("onLoadChildren must call detach() or sendResult()"
-                    + " before returning for package=" + connection.pkg + " id=" + parentId);
-        }
-    }
-
-    private List<MediaBrowser.MediaItem> applyOptions(List<MediaBrowser.MediaItem> list,
-            final Bundle options) {
-        if (list == null) {
-            return null;
-        }
-        int page = options.getInt(MediaBrowser.EXTRA_PAGE, -1);
-        int pageSize = options.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
-        if (page == -1 && pageSize == -1) {
-            return list;
-        }
-        int fromIndex = pageSize * page;
-        int toIndex = fromIndex + pageSize;
-        if (page < 0 || pageSize < 1 || fromIndex >= list.size()) {
-            return Collections.EMPTY_LIST;
-        }
-        if (toIndex > list.size()) {
-            toIndex = list.size();
-        }
-        return list.subList(fromIndex, toIndex);
-    }
-
-    private void performLoadItem(String itemId, final ConnectionRecord connection,
-            final ResultReceiver receiver) {
-        final Result<MediaBrowser.MediaItem> result =
-                new Result<MediaBrowser.MediaItem>(itemId) {
-            @Override
-            void onResultSent(MediaBrowser.MediaItem item, @ResultFlags int flag) {
-                if (mConnections.get(connection.callbacks.asBinder()) != connection) {
-                    if (DBG) {
-                        Log.d(TAG, "Not sending onLoadItem result for connection that has"
-                                + " been disconnected. pkg=" + connection.pkg + " id=" + itemId);
-                    }
-                    return;
-                }
-                if ((flag & RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED) != 0) {
-                    receiver.send(RESULT_ERROR, null);
-                    return;
-                }
-                Bundle bundle = new Bundle();
-                bundle.putParcelable(KEY_MEDIA_ITEM, item);
-                receiver.send(RESULT_OK, bundle);
-            }
-        };
-
-        mCurConnection = connection;
-        onLoadItem(itemId, result);
-        mCurConnection = null;
-
-        if (!result.isDone()) {
-            throw new IllegalStateException("onLoadItem must call detach() or sendResult()"
-                    + " before returning for id=" + itemId);
-        }
-    }
-
-    /**
-     * Contains information that the browser service needs to send to the client
-     * when first connected.
-     */
-    public static final class BrowserRoot {
-        /**
-         * The lookup key for a boolean that indicates whether the browser service should return a
-         * browser root for recently played media items.
-         *
-         * <p>When creating a media browser for a given media browser service, this key can be
-         * supplied as a root hint for retrieving media items that are recently played.
-         * If the media browser service can provide such media items, the implementation must return
-         * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
-         *
-         * <p>The root hint may contain multiple keys.
-         *
-         * @see #EXTRA_OFFLINE
-         * @see #EXTRA_SUGGESTED
-         */
-        public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
-
-        /**
-         * The lookup key for a boolean that indicates whether the browser service should return a
-         * browser root for offline media items.
-         *
-         * <p>When creating a media browser for a given media browser service, this key can be
-         * supplied as a root hint for retrieving media items that are can be played without an
-         * internet connection.
-         * If the media browser service can provide such media items, the implementation must return
-         * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
-         *
-         * <p>The root hint may contain multiple keys.
-         *
-         * @see #EXTRA_RECENT
-         * @see #EXTRA_SUGGESTED
-         */
-        public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
-
-        /**
-         * The lookup key for a boolean that indicates whether the browser service should return a
-         * browser root for suggested media items.
-         *
-         * <p>When creating a media browser for a given media browser service, this key can be
-         * supplied as a root hint for retrieving the media items suggested by the media browser
-         * service. The list of media items passed in {@link android.media.browse.MediaBrowser.SubscriptionCallback#onChildrenLoaded(String, List)}
-         * is considered ordered by relevance, first being the top suggestion.
-         * If the media browser service can provide such media items, the implementation must return
-         * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
-         *
-         * <p>The root hint may contain multiple keys.
-         *
-         * @see #EXTRA_RECENT
-         * @see #EXTRA_OFFLINE
-         */
-        public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
-
-        final private String mRootId;
-        final private Bundle mExtras;
-
-        /**
-         * Constructs a browser root.
-         * @param rootId The root id for browsing.
-         * @param extras Any extras about the browser service.
-         */
-        public BrowserRoot(@NonNull String rootId, @Nullable Bundle extras) {
-            if (rootId == null) {
-                throw new IllegalArgumentException("The root id in BrowserRoot cannot be null. " +
-                        "Use null for BrowserRoot instead.");
-            }
-            mRootId = rootId;
-            mExtras = extras;
-        }
-
-        /**
-         * Gets the root id for browsing.
-         */
-        public String getRootId() {
-            return mRootId;
-        }
-
-        /**
-         * Gets any extras about the browser service.
-         */
-        public Bundle getExtras() {
-            return mExtras;
-        }
-    }
-}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 7481fff..48dbf55 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -34,7 +34,6 @@
         "libutils",
         "libbinder",
         "libmedia",
-        "libmediaextractor",
         "libmedia_omx",
         "libmediametrics",
         "libmediadrm",
@@ -95,27 +94,32 @@
     ],
 
     shared_libs: [
-        "android.hardware.cas@1.0",  // for CasManager. VNDK???
-        "android.hardware.cas.native@1.0",  // CasManager. VNDK???
+        // MediaCas
+        "android.hardware.cas@1.0",
+        "android.hardware.cas.native@1.0",
         "android.hidl.allocator@1.0",
+        "libhidlbase",
         "libhidlmemory",
-        "libbinder",
-        "libgui",  // for VideoFrameScheduler
-        "libhidlbase",  // VNDK???
-        "libpowermanager",  // for JWakeLock. to be removed
+
+        "libmediametrics",  // Used by MediaMetrics. Will be replaced with stable C API.
+        "libbinder",  // Used by JWakeLock and MediaMetrics.
 
         "libutils",  // Have to use shared lib to make libandroid_runtime behave correctly.
                      // Otherwise, AndroidRuntime::getJNIEnv() will return NULL.
 
         // NDK or NDK-compliant
         "libandroid",
+        "libbinder_ndk",
         "libmediandk",
         "libnativehelper_compat_libc++",
         "liblog",
         "libz",
     ],
 
-    header_libs: ["libhardware_headers"],
+    header_libs: [
+        "libhardware_headers",
+        "libnativewindow_headers",
+    ],
 
     static_libs: [
         "libbase",
@@ -123,13 +127,12 @@
         "libcutils",
         "libmedia_helper",
         "libmedia_player2_util",
-        "libmediaextractor",
-        "libmediametrics",
         "libmediaplayer2",
         "libmediaplayer2-protos",
         "libmediandk_utils",
         "libmediautils",
         "libprotobuf-cpp-lite",
+        "libstagefright",
         "libstagefright_esds",
         "libstagefright_foundation",
         "libstagefright_httplive",
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 2578608..406f9dd 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -72,7 +72,10 @@
     jint cryptoErrorResourceBusy;
     jint cryptoErrorInsufficientOutputProtection;
     jint cryptoErrorSessionNotOpened;
+    jint cryptoErrorInsufficientSecurity;
     jint cryptoErrorUnsupportedOperation;
+    jint cryptoErrorFrameTooLarge;
+    jint cryptoErrorLostState;
 } gCryptoErrorCodes;
 
 static struct CodecActionCodes {
@@ -645,7 +648,6 @@
 
     capabilities->getSupportedColorFormats(&colorFormats);
     capabilities->getSupportedProfileLevels(&profileLevels);
-    uint32_t flags = capabilities->getFlags();
     sp<AMessage> details = capabilities->getDetails();
 
     jobject defaultFormatObj = NULL;
@@ -684,7 +686,7 @@
 
     return env->NewObject(
             gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
-            profileLevelArray.get(), colorFormatsArray.get(), isEncoder, flags,
+            profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
             defaultFormatRef.get(), detailsRef.get());
 }
 
@@ -697,23 +699,28 @@
         return err;
     }
 
+    // TODO: get alias
     ScopedLocalRef<jstring> nameObject(env,
             env->NewStringUTF(codecInfo->getCodecName()));
 
+    ScopedLocalRef<jstring> canonicalNameObject(env,
+            env->NewStringUTF(codecInfo->getCodecName()));
+
+    MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
     bool isEncoder = codecInfo->isEncoder();
 
-    Vector<AString> mimes;
-    codecInfo->getSupportedMimes(&mimes);
+    Vector<AString> mediaTypes;
+    codecInfo->getSupportedMediaTypes(&mediaTypes);
 
     ScopedLocalRef<jobjectArray> capsArrayObj(env,
-        env->NewObjectArray(mimes.size(), gCodecInfo.capsClazz, NULL));
+        env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
 
-    for (size_t i = 0; i < mimes.size(); i++) {
+    for (size_t i = 0; i < mediaTypes.size(); i++) {
         const sp<MediaCodecInfo::Capabilities> caps =
-                codecInfo->getCapabilitiesFor(mimes[i].c_str());
+                codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
 
         ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
-                env, mimes[i].c_str(), isEncoder, caps));
+                env, mediaTypes[i].c_str(), isEncoder, caps));
 
         env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
     }
@@ -723,10 +730,10 @@
     CHECK(codecInfoClazz.get() != NULL);
 
     jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>",
-            "(Ljava/lang/String;Z[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
+            "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
 
     *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
-            nameObject.get(), isEncoder, capsArrayObj.get());
+            nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
 
     return OK;
 }
@@ -1005,10 +1012,22 @@
             err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
             defaultMsg = "Attempted to use a closed session";
             break;
+        case ERROR_DRM_INSUFFICIENT_SECURITY:
+            err = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
+            defaultMsg = "Required security level is not met";
+            break;
         case ERROR_DRM_CANNOT_HANDLE:
             err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
             defaultMsg = "Operation not supported in this configuration";
             break;
+        case ERROR_DRM_FRAME_TOO_LARGE:
+            err = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
+            defaultMsg = "Decrytped frame exceeds size of output buffer";
+            break;
+        case ERROR_DRM_SESSION_LOST_STATE:
+            err = gCryptoErrorCodes.cryptoErrorLostState;
+            defaultMsg = "Session state was lost, open a new session and retry";
+            break;
         default:  /* Other negative DRM error codes go out as is. */
             break;
     }
@@ -1994,11 +2013,26 @@
     gCryptoErrorCodes.cryptoErrorSessionNotOpened =
         env->GetStaticIntField(clazz.get(), field);
 
+    field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
+    CHECK(field != NULL);
+    gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
+        env->GetStaticIntField(clazz.get(), field);
+
     field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
     CHECK(field != NULL);
     gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
         env->GetStaticIntField(clazz.get(), field);
 
+    field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
+    CHECK(field != NULL);
+    gCryptoErrorCodes.cryptoErrorFrameTooLarge =
+        env->GetStaticIntField(clazz.get(), field);
+
+    field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
+    CHECK(field != NULL);
+    gCryptoErrorCodes.cryptoErrorLostState =
+        env->GetStaticIntField(clazz.get(), field);
+
     clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
     CHECK(clazz.get() != NULL);
     field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
@@ -2049,7 +2083,7 @@
     gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
 
     method = env->GetMethodID(clazz.get(), "<init>",
-            "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZI"
+            "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
             "Ljava/util/Map;Ljava/util/Map;)V");
     CHECK(method != NULL);
     gCodecInfo.capsCtorId = method;
@@ -2187,7 +2221,7 @@
     { "getImage", "(ZI)Landroid/media/Image;",
       (void *)android_media_MediaCodec_getImage },
 
-    { "getName", "()Ljava/lang/String;",
+    { "getCanonicalName", "()Ljava/lang/String;",
       (void *)android_media_MediaCodec_getName },
 
     { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 8de11ca..cf14942 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -41,6 +41,21 @@
     return mcl;
 }
 
+static sp<MediaCodecInfo> getCodecInfo(JNIEnv *env, jint index) {
+    sp<IMediaCodecList> mcl = getCodecList(env);
+    if (mcl == NULL) {
+        // Runtime exception already pending.
+        return NULL;
+    }
+
+    sp<MediaCodecInfo> info = mcl->getCodecInfo(index);
+    if (info == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+    }
+
+    return info;
+}
+
 static jint android_media_MediaCodecList_getCodecCount(
         JNIEnv *env, jobject /* thiz */) {
     sp<IMediaCodecList> mcl = getCodecList(env);
@@ -53,15 +68,22 @@
 
 static jstring android_media_MediaCodecList_getCodecName(
         JNIEnv *env, jobject /* thiz */, jint index) {
-    sp<IMediaCodecList> mcl = getCodecList(env);
-    if (mcl == NULL) {
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
+    if (info == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
 
-    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
+    // TODO: support aliases
+    const char *name = info->getCodecName();
+    return env->NewStringUTF(name);
+}
+
+static jstring android_media_MediaCodecList_getCanonicalName(
+        JNIEnv *env, jobject /* thiz */, jint index) {
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
     if (info == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        // Runtime exception already pending.
         return NULL;
     }
 
@@ -94,39 +116,27 @@
     return ret;
 }
 
-static jboolean android_media_MediaCodecList_isEncoder(
+static jboolean android_media_MediaCodecList_getAttributes(
         JNIEnv *env, jobject /* thiz */, jint index) {
-    sp<IMediaCodecList> mcl = getCodecList(env);
-    if (mcl == NULL) {
-        // Runtime exception already pending.
-        return false;
-    }
-
-    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
     if (info == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return false;
+        // Runtime exception already pending.
+        return 0;
     }
 
-    return info->isEncoder();
+    return info->getAttributes();
 }
 
 static jarray android_media_MediaCodecList_getSupportedTypes(
         JNIEnv *env, jobject /* thiz */, jint index) {
-    sp<IMediaCodecList> mcl = getCodecList(env);
-    if (mcl == NULL) {
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
+    if (info == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
 
-    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
-    if (info == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return NULL;
-    }
-
     Vector<AString> types;
-    info->getSupportedMimes(&types);
+    info->getSupportedMediaTypes(&types);
 
     jclass clazz = env->FindClass("java/lang/String");
     CHECK(clazz != NULL);
@@ -150,17 +160,12 @@
         return NULL;
     }
 
-    sp<IMediaCodecList> mcl = getCodecList(env);
-    if (mcl == NULL) {
+    sp<MediaCodecInfo> info = getCodecInfo(env, index);
+    if (info == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
 
-    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
-    if (info == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return NULL;
-    }
 
     const char *typeStr = env->GetStringUTFChars(type, NULL);
     if (typeStr == NULL) {
@@ -186,7 +191,6 @@
 
     capabilities->getSupportedColorFormats(&colorFormats);
     capabilities->getSupportedProfileLevels(&profileLevels);
-    uint32_t flags = capabilities->getFlags();
     sp<AMessage> details = capabilities->getDetails();
     bool isEncoder = info->isEncoder();
 
@@ -240,11 +244,11 @@
     }
 
     jmethodID capsConstructID = env->GetMethodID(capsClazz, "<init>",
-            "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZI"
+            "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
             "Ljava/util/Map;Ljava/util/Map;)V");
 
     jobject caps = env->NewObject(capsClazz, capsConstructID,
-            profileLevelArray, colorFormatsArray, isEncoder, flags,
+            profileLevelArray, colorFormatsArray, isEncoder,
             defaultFormatObj, infoObj);
 
     env->DeleteLocalRef(profileLevelArray);
@@ -288,9 +292,15 @@
 
 static const JNINativeMethod gMethods[] = {
     { "native_getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount },
+
+    { "getCanonicalName", "(I)Ljava/lang/String;",
+      (void *)android_media_MediaCodecList_getCanonicalName },
+
     { "getCodecName", "(I)Ljava/lang/String;",
       (void *)android_media_MediaCodecList_getCodecName },
-    { "isEncoder", "(I)Z", (void *)android_media_MediaCodecList_isEncoder },
+
+    { "getAttributes", "(I)I", (void *)android_media_MediaCodecList_getAttributes },
+
     { "getSupportedTypes", "(I)[Ljava/lang/String;",
       (void *)android_media_MediaCodecList_getSupportedTypes },
 
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index be71dad5..81fce8a 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -110,6 +110,7 @@
     jint kWhatDrmEvent;
     jint kWhatExpirationUpdate;
     jint kWhatKeyStatusChange;
+    jint kWhatSessionLostState;
 } gEventWhat;
 
 struct KeyTypes {
@@ -141,6 +142,16 @@
     jclass classId;
 };
 
+struct SessionExceptionFields {
+    jmethodID init;
+    jclass classId;
+    jfieldID errorCode;
+};
+
+struct SessionExceptionErrorCodes {
+    jint kResourceContention;
+} gSessionExceptionErrorCodes;
+
 struct HDCPLevels {
     jint kHdcpLevelUnknown;
     jint kHdcpNone;
@@ -148,6 +159,7 @@
     jint kHdcpV2;
     jint kHdcpV2_1;
     jint kHdcpV2_2;
+    jint kHdcpV2_3;
     jint kHdcpNoOutput;
 } gHdcpLevels;
 
@@ -180,6 +192,7 @@
     EntryFields entry;
     CertificateFields certificate;
     StateExceptionFields stateException;
+    SessionExceptionFields sessionException;
     jclass certificateClassId;
     jclass hashmapClassId;
     jclass arraylistClassId;
@@ -310,6 +323,9 @@
          case DrmPlugin::kDrmPluginEventKeysChange:
             jwhat = gEventWhat.kWhatKeyStatusChange;
             break;
+         case DrmPlugin::kDrmPluginEventSessionLostState:
+            jwhat = gEventWhat.kWhatSessionLostState;
+            break;
         default:
             ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
             return;
@@ -343,6 +359,30 @@
     env->Throw(static_cast<jthrowable>(exception));
 }
 
+static void throwSessionException(JNIEnv *env, const char *msg, status_t err) {
+    ALOGE("Session exception: %s (%d)", msg, err);
+
+    jint jErrorCode = 0;
+    switch(err) {
+        case ERROR_DRM_RESOURCE_CONTENTION:
+            jErrorCode = gSessionExceptionErrorCodes.kResourceContention;
+            break;
+        default:
+            break;
+    }
+
+    jobject exception = env->NewObject(gFields.sessionException.classId,
+            gFields.sessionException.init, static_cast<int>(err),
+            env->NewStringUTF(msg));
+
+    env->SetIntField(exception, gFields.sessionException.errorCode, jErrorCode);
+    env->Throw(static_cast<jthrowable>(exception));
+}
+
+static bool isSessionException(status_t err) {
+    return err == ERROR_DRM_RESOURCE_CONTENTION;
+}
+
 static bool throwExceptionAsNecessary(
         JNIEnv *env, status_t err, const char *msg = NULL) {
 
@@ -370,7 +410,7 @@
     case ERROR_DRM_CANNOT_HANDLE:
         drmMessage = "Invalid parameter or data format";
         break;
-    case ERROR_DRM_TAMPER_DETECTED:
+    case ERROR_DRM_INVALID_STATE:
         drmMessage = "Invalid state";
         break;
     default:
@@ -399,6 +439,9 @@
         jniThrowException(env, "android/media/MediaDrmResetException",
                 "mediaserver died");
         return true;
+    } else if (isSessionException(err)) {
+        throwSessionException(env, msg, err);
+        return true;
     } else if (err != OK) {
         String8 errbuf;
         if (drmMessage != NULL) {
@@ -499,14 +542,15 @@
 
 
 // static
-bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
+bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
+                                   DrmPlugin::SecurityLevel securityLevel) {
     sp<IDrm> drm = MakeDrm();
 
     if (drm == NULL) {
         return false;
     }
 
-    return drm->isCryptoSchemeSupported(uuid, mimeType);
+    return drm->isCryptoSchemeSupported(uuid, mimeType, securityLevel);
 }
 
 status_t JDrm::initCheck() const {
@@ -705,6 +749,8 @@
     gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
     GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
     gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
+    GET_STATIC_FIELD_ID(field, clazz, "SESSION_LOST_STATE", "I");
+    gEventWhat.kWhatSessionLostState = env->GetStaticIntField(clazz, field);
 
     GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
     gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
@@ -730,6 +776,8 @@
     gHdcpLevels.kHdcpV2_1 = env->GetStaticIntField(clazz, field);
     GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_2", "I");
     gHdcpLevels.kHdcpV2_2 = env->GetStaticIntField(clazz, field);
+    GET_STATIC_FIELD_ID(field, clazz, "HDCP_V2_3", "I");
+    gHdcpLevels.kHdcpV2_3 = env->GetStaticIntField(clazz, field);
     GET_STATIC_FIELD_ID(field, clazz, "HDCP_NO_DIGITAL_OUTPUT", "I");
     gHdcpLevels.kHdcpNoOutput = env->GetStaticIntField(clazz, field);
 
@@ -831,6 +879,14 @@
     FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
     GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
     gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+    FIND_CLASS(clazz, "android/media/MediaDrm$SessionException");
+    GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(ILjava/lang/String;)V");
+    gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
+    GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
+
+    GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
+    gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
 }
 
 static void android_media_MediaDrm_native_setup(
@@ -875,8 +931,30 @@
     setDrm(env, thiz, drm);
 }
 
+DrmPlugin::SecurityLevel jintToSecurityLevel(jint jlevel) {
+    DrmPlugin::SecurityLevel level;
+
+    if (jlevel == gSecurityLevels.kSecurityLevelMax) {
+        level = DrmPlugin::kSecurityLevelMax;
+    }  else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
+        level = DrmPlugin::kSecurityLevelSwSecureCrypto;
+    } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
+        level = DrmPlugin::kSecurityLevelSwSecureDecode;
+    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
+        level = DrmPlugin::kSecurityLevelHwSecureCrypto;
+    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
+        level = DrmPlugin::kSecurityLevelHwSecureDecode;
+    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
+        level = DrmPlugin::kSecurityLevelHwSecureAll;
+    } else {
+        level = DrmPlugin::kSecurityLevelUnknown;
+    }
+    return level;
+}
+
 static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
-    JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType) {
+        JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType,
+        jint jSecurityLevel) {
 
     if (uuidObj == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
@@ -897,8 +975,9 @@
     if (jmimeType != NULL) {
         mimeType = JStringToString8(env, jmimeType);
     }
+    DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
 
-    return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType);
+    return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType, securityLevel);
 }
 
 static jbyteArray android_media_MediaDrm_openSession(
@@ -910,21 +989,8 @@
     }
 
     Vector<uint8_t> sessionId;
-    DrmPlugin::SecurityLevel level;
-
-    if (jlevel == gSecurityLevels.kSecurityLevelMax) {
-        level = DrmPlugin::kSecurityLevelMax;
-    }  else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
-        level = DrmPlugin::kSecurityLevelSwSecureCrypto;
-    } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
-        level = DrmPlugin::kSecurityLevelSwSecureDecode;
-    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
-        level = DrmPlugin::kSecurityLevelHwSecureCrypto;
-    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
-        level = DrmPlugin::kSecurityLevelHwSecureDecode;
-    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
-        level = DrmPlugin::kSecurityLevelHwSecureAll;
-    } else {
+    DrmPlugin::SecurityLevel level = jintToSecurityLevel(jlevel);
+    if (level == DrmPlugin::kSecurityLevelUnknown) {
         jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
         return NULL;
     }
@@ -1338,6 +1404,8 @@
         return gHdcpLevels.kHdcpV2_1;
     case DrmPlugin::kHdcpV2_2:
         return gHdcpLevels.kHdcpV2_2;
+    case DrmPlugin::kHdcpV2_3:
+        return gHdcpLevels.kHdcpV2_3;
     case DrmPlugin::kHdcpNoOutput:
         return gHdcpLevels.kHdcpNoOutput;
     }
@@ -1846,7 +1914,7 @@
     { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
       (void *)android_media_MediaDrm_native_setup },
 
-    { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
+    { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;I)Z",
       (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
 
     { "openSession", "(I)[B",
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
index b9356f3..9338861 100644
--- a/media/jni/android_media_MediaDrm.h
+++ b/media/jni/android_media_MediaDrm.h
@@ -37,7 +37,9 @@
 };
 
 struct JDrm : public BnDrmClient {
-    static bool IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType);
+    static bool IsCryptoSchemeSupported(const uint8_t uuid[16],
+                                        const String8 &mimeType,
+                                        DrmPlugin::SecurityLevel level);
 
     JDrm(JNIEnv *env, jobject thiz, const uint8_t uuid[16], const String8 &appPackageName);
 
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 7e6a8ab..9b4e730 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -86,7 +86,8 @@
 // ----------------------------------------------------------------------------
 
 struct fields_t {
-    jfieldID    context;
+    jfieldID    context;               // passed from Java to native, used for creating JWakeLock
+    jfieldID    nativeContext;         // mNativeContext in MediaPlayer2.java
     jfieldID    surface_texture;
 
     jmethodID   post_event;
@@ -225,21 +226,21 @@
 static sp<MediaPlayer2> getMediaPlayer(JNIEnv* env, jobject thiz)
 {
     Mutex::Autolock l(sLock);
-    MediaPlayer2* const p = (MediaPlayer2*)env->GetLongField(thiz, fields.context);
+    MediaPlayer2* const p = (MediaPlayer2*)env->GetLongField(thiz, fields.nativeContext);
     return sp<MediaPlayer2>(p);
 }
 
 static sp<MediaPlayer2> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer2>& player)
 {
     Mutex::Autolock l(sLock);
-    sp<MediaPlayer2> old = (MediaPlayer2*)env->GetLongField(thiz, fields.context);
+    sp<MediaPlayer2> old = (MediaPlayer2*)env->GetLongField(thiz, fields.nativeContext);
     if (player.get()) {
         player->incStrong((void*)setMediaPlayer);
     }
     if (old != 0) {
         old->decStrong((void*)setMediaPlayer);
     }
-    env->SetLongField(thiz, fields.context, (jlong)player.get());
+    env->SetLongField(thiz, fields.nativeContext, (jlong)player.get());
     return old;
 }
 
@@ -955,11 +956,16 @@
         return;
     }
 
-    fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
+    fields.context = env->GetFieldID(clazz, "mContext", "Landroid/content/Context;");
     if (fields.context == NULL) {
         return;
     }
 
+    fields.nativeContext = env->GetFieldID(clazz, "mNativeContext", "J");
+    if (fields.nativeContext == NULL) {
+        return;
+    }
+
     fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
                                                "(Ljava/lang/Object;JIII[B)V");
     if (fields.post_event == NULL) {
@@ -1013,7 +1019,8 @@
         jint sessionId, jobject weak_this)
 {
     ALOGV("native_setup");
-    sp<MediaPlayer2> mp = MediaPlayer2::Create(sessionId);
+    jobject context = env->GetObjectField(thiz, fields.context);
+    sp<MediaPlayer2> mp = MediaPlayer2::Create(sessionId, context);
     if (mp == NULL) {
         jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
         return;
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 56b85b5..06a7182 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -708,6 +708,24 @@
             int type = dataTypes[i];
             packet.putUInt16(type);
 
+            if (type == MTP_TYPE_STR) {
+                jstring value = (jstring)env->GetObjectArrayElement(stringValuesArray, i);
+                const char *valueStr = (value ? env->GetStringUTFChars(value, NULL) : NULL);
+                if (valueStr) {
+                    packet.putString(valueStr);
+                    env->ReleaseStringUTFChars(value, valueStr);
+                } else {
+                    packet.putEmptyString();
+                }
+                env->DeleteLocalRef(value);
+                continue;
+            }
+
+            if (!longValues) {
+                ALOGE("bad longValuesArray value in MyMtpDatabase::getObjectPropertyList");
+                continue;
+            }
+
             switch (type) {
                 case MTP_TYPE_INT8:
                     packet.putInt8(longValues[i]);
@@ -739,18 +757,6 @@
                 case MTP_TYPE_UINT128:
                     packet.putUInt128(longValues[i]);
                     break;
-                case MTP_TYPE_STR: {
-                    jstring value = (jstring)env->GetObjectArrayElement(stringValuesArray, i);
-                    const char *valueStr = (value ? env->GetStringUTFChars(value, NULL) : NULL);
-                    if (valueStr) {
-                        packet.putString(valueStr);
-                        env->ReleaseStringUTFChars(value, valueStr);
-                    } else {
-                        packet.putEmptyString();
-                    }
-                    env->DeleteLocalRef(value);
-                    break;
-                }
                 default:
                     ALOGE("bad or unsupported data type in MtpDatabase::getObjectPropertyList");
                     break;
diff --git a/media/lib/remotedisplay/api/current.txt b/media/lib/remotedisplay/api/current.txt
index e69de29..d802177 100644
--- a/media/lib/remotedisplay/api/current.txt
+++ b/media/lib/remotedisplay/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/remotedisplay/api/removed.txt b/media/lib/remotedisplay/api/removed.txt
index e69de29..d802177 100644
--- a/media/lib/remotedisplay/api/removed.txt
+++ b/media/lib/remotedisplay/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/remotedisplay/api/system-current.txt b/media/lib/remotedisplay/api/system-current.txt
index 69bbd35..3619fcf 100644
--- a/media/lib/remotedisplay/api/system-current.txt
+++ b/media/lib/remotedisplay/api/system-current.txt
@@ -1,17 +1,18 @@
+// Signature format: 2.0
 package com.android.media.remotedisplay {
 
   public class RemoteDisplay {
-    ctor public RemoteDisplay(java.lang.String, java.lang.String);
-    method public java.lang.String getDescription();
-    method public java.lang.String getId();
-    method public java.lang.String getName();
+    ctor public RemoteDisplay(String, String);
+    method public String getDescription();
+    method public String getId();
+    method public String getName();
     method public int getPresentationDisplayId();
     method public int getStatus();
     method public int getVolume();
     method public int getVolumeHandling();
     method public int getVolumeMax();
-    method public void setDescription(java.lang.String);
-    method public void setName(java.lang.String);
+    method public void setDescription(String);
+    method public void setName(String);
     method public void setPresentationDisplayId(int);
     method public void setStatus(int);
     method public void setVolume(int);
@@ -29,7 +30,7 @@
   public abstract class RemoteDisplayProvider {
     ctor public RemoteDisplayProvider(android.content.Context);
     method public void addDisplay(com.android.media.remotedisplay.RemoteDisplay);
-    method public com.android.media.remotedisplay.RemoteDisplay findRemoteDisplay(java.lang.String);
+    method public com.android.media.remotedisplay.RemoteDisplay findRemoteDisplay(String);
     method public android.os.IBinder getBinder();
     method public final android.content.Context getContext();
     method public int getDiscoveryMode();
@@ -45,7 +46,7 @@
     field public static final int DISCOVERY_MODE_ACTIVE = 2; // 0x2
     field public static final int DISCOVERY_MODE_NONE = 0; // 0x0
     field public static final int DISCOVERY_MODE_PASSIVE = 1; // 0x1
-    field public static final java.lang.String SERVICE_INTERFACE = "com.android.media.remotedisplay.RemoteDisplayProvider";
+    field public static final String SERVICE_INTERFACE = "com.android.media.remotedisplay.RemoteDisplayProvider";
   }
 
 }
diff --git a/media/lib/remotedisplay/api/system-removed.txt b/media/lib/remotedisplay/api/system-removed.txt
index e69de29..d802177 100644
--- a/media/lib/remotedisplay/api/system-removed.txt
+++ b/media/lib/remotedisplay/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/remotedisplay/api/test-current.txt b/media/lib/remotedisplay/api/test-current.txt
index e69de29..d802177 100644
--- a/media/lib/remotedisplay/api/test-current.txt
+++ b/media/lib/remotedisplay/api/test-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/remotedisplay/api/test-removed.txt b/media/lib/remotedisplay/api/test-removed.txt
index e69de29..d802177 100644
--- a/media/lib/remotedisplay/api/test-removed.txt
+++ b/media/lib/remotedisplay/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/signer/Android.bp b/media/lib/signer/Android.bp
index 8c43683..44f8725 100644
--- a/media/lib/signer/Android.bp
+++ b/media/lib/signer/Android.bp
@@ -18,5 +18,7 @@
     name: "com.android.mediadrm.signer",
     srcs: ["java/**/*.java"],
     api_packages: ["com.android.mediadrm.signer"],
-    metalava_enabled: false,
+    srcs_lib: "framework",
+    srcs_lib_whitelist_dirs: ["media/java"],
+    srcs_lib_whitelist_pkgs: ["android.media"],
 }
diff --git a/media/lib/signer/api/current.txt b/media/lib/signer/api/current.txt
index 4aa912d..c9298dd 100644
--- a/media/lib/signer/api/current.txt
+++ b/media/lib/signer/api/current.txt
@@ -1,9 +1,10 @@
+// Signature format: 2.0
 package com.android.mediadrm.signer {
 
   public final class MediaDrmSigner {
-    method public static com.android.mediadrm.signer.MediaDrmSigner.CertificateRequest getCertificateRequest(android.media.MediaDrm, int, java.lang.String);
+    method public static com.android.mediadrm.signer.MediaDrmSigner.CertificateRequest getCertificateRequest(android.media.MediaDrm, int, String);
     method public static com.android.mediadrm.signer.MediaDrmSigner.Certificate provideCertificateResponse(android.media.MediaDrm, byte[]) throws android.media.DeniedByServerException;
-    method public static byte[] signRSA(android.media.MediaDrm, byte[], java.lang.String, byte[], byte[]);
+    method public static byte[] signRSA(android.media.MediaDrm, byte[], String, byte[], byte[]);
     field public static final int CERTIFICATE_TYPE_X509 = 1; // 0x1
   }
 
@@ -14,7 +15,7 @@
 
   public static final class MediaDrmSigner.CertificateRequest {
     method public byte[] getData();
-    method public java.lang.String getDefaultUrl();
+    method public String getDefaultUrl();
   }
 
 }
diff --git a/media/lib/signer/api/removed.txt b/media/lib/signer/api/removed.txt
index e69de29..d802177 100644
--- a/media/lib/signer/api/removed.txt
+++ b/media/lib/signer/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/signer/api/system-current.txt b/media/lib/signer/api/system-current.txt
index e69de29..d802177 100644
--- a/media/lib/signer/api/system-current.txt
+++ b/media/lib/signer/api/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/signer/api/system-removed.txt b/media/lib/signer/api/system-removed.txt
index e69de29..d802177 100644
--- a/media/lib/signer/api/system-removed.txt
+++ b/media/lib/signer/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/signer/api/test-current.txt b/media/lib/signer/api/test-current.txt
index e69de29..d802177 100644
--- a/media/lib/signer/api/test-current.txt
+++ b/media/lib/signer/api/test-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/signer/api/test-removed.txt b/media/lib/signer/api/test-removed.txt
index e69de29..d802177 100644
--- a/media/lib/signer/api/test-removed.txt
+++ b/media/lib/signer/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/tvremote/api/current.txt b/media/lib/tvremote/api/current.txt
index eea9e9c..1086d58 100644
--- a/media/lib/tvremote/api/current.txt
+++ b/media/lib/tvremote/api/current.txt
@@ -1,3 +1,4 @@
+// Signature format: 2.0
 package com.android.media.tv.remoteprovider {
 
   public abstract class TvRemoteProvider {
@@ -7,14 +8,14 @@
     method public android.os.IBinder getBinder();
     method public final android.content.Context getContext();
     method public void onInputBridgeConnected(android.os.IBinder);
-    method public void openRemoteInputBridge(android.os.IBinder, java.lang.String, int, int, int) throws java.lang.RuntimeException;
+    method public void openRemoteInputBridge(android.os.IBinder, String, int, int, int) throws java.lang.RuntimeException;
     method public void sendKeyDown(android.os.IBinder, int) throws java.lang.RuntimeException;
     method public void sendKeyUp(android.os.IBinder, int) throws java.lang.RuntimeException;
     method public void sendPointerDown(android.os.IBinder, int, int, int) throws java.lang.RuntimeException;
     method public void sendPointerSync(android.os.IBinder) throws java.lang.RuntimeException;
     method public void sendPointerUp(android.os.IBinder, int) throws java.lang.RuntimeException;
     method public void sendTimestamp(android.os.IBinder, long) throws java.lang.RuntimeException;
-    field public static final java.lang.String SERVICE_INTERFACE = "com.android.media.tv.remoteprovider.TvRemoteProvider";
+    field public static final String SERVICE_INTERFACE = "com.android.media.tv.remoteprovider.TvRemoteProvider";
   }
 
 }
diff --git a/media/lib/tvremote/api/removed.txt b/media/lib/tvremote/api/removed.txt
index e69de29..d802177 100644
--- a/media/lib/tvremote/api/removed.txt
+++ b/media/lib/tvremote/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/tvremote/api/system-current.txt b/media/lib/tvremote/api/system-current.txt
index e69de29..d802177 100644
--- a/media/lib/tvremote/api/system-current.txt
+++ b/media/lib/tvremote/api/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/tvremote/api/system-removed.txt b/media/lib/tvremote/api/system-removed.txt
index e69de29..d802177 100644
--- a/media/lib/tvremote/api/system-removed.txt
+++ b/media/lib/tvremote/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/tvremote/api/test-current.txt b/media/lib/tvremote/api/test-current.txt
index e69de29..d802177 100644
--- a/media/lib/tvremote/api/test-current.txt
+++ b/media/lib/tvremote/api/test-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/lib/tvremote/api/test-removed.txt b/media/lib/tvremote/api/test-removed.txt
index e69de29..d802177 100644
--- a/media/lib/tvremote/api/test-removed.txt
+++ b/media/lib/tvremote/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/packages/MediaCore/Android.bp.bak b/media/packages/MediaCore/Android.bp.bak
new file mode 100644
index 0000000..c7fd58b
--- /dev/null
+++ b/media/packages/MediaCore/Android.bp.bak
@@ -0,0 +1,21 @@
+android_app {
+    name: "MediaCore",
+
+    srcs: [
+        "src/**/*.java",
+    ],
+
+    static_libs: [
+        // TODO: Temporarily statically linked. Should go into "libs"
+        "media1",
+    ],
+
+    // System app
+    platform_apis: true,
+
+    // Privileged app
+    privileged: true,
+
+    // Make sure that the implementation only relies on SDK or system APIs.
+    sdk_version: "system_current",
+}
diff --git a/media/packages/MediaCore/AndroidManifest.xml b/media/packages/MediaCore/AndroidManifest.xml
new file mode 100644
index 0000000..4e2b274
--- /dev/null
+++ b/media/packages/MediaCore/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/AndroidManifest.xml
+**
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.media" coreApp="true" android:sharedUserId="android.uid.system"
+    android:sharedUserLabel="@string/android_system_label">
+    <application android:process="system"
+        android:persistent="true"
+        android:directBootAware="true">
+        <service android:name="AmlMediaSessionProviderService" android:singleUser="true">
+            <intent-filter>
+                <action android:name="android.media.session.MediaSessionProviderService"/>
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
diff --git a/media/packages/MediaCore/res/values/strings.xml b/media/packages/MediaCore/res/values/strings.xml
new file mode 100644
index 0000000..59fd635
--- /dev/null
+++ b/media/packages/MediaCore/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <!-- Label for the Android system components when they are shown to the user. -->
+    <string name="android_system_label" translatable="false">Android System</string>
+</resources>
+
diff --git a/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java
new file mode 100644
index 0000000..43b95ab
--- /dev/null
+++ b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media;
+
+import android.content.Context;
+import android.media.session.MediaSessionProviderService;
+import android.os.PowerManager;
+import android.util.Log;
+
+/**
+ * System implementation of MediaSessionProviderService
+ */
+public class AmlMediaSessionProviderService extends MediaSessionProviderService {
+    private static final String TAG = "AmlMediaSessionProviderS";
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private Context mContext;
+
+    public AmlMediaSessionProviderService(Context context) {
+        mContext = context;
+        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+    }
+}
diff --git a/media/tests/MtpTests/Android.mk b/media/tests/MtpTests/Android.mk
index 6375ed3..4cee62e 100644
--- a/media/tests/MtpTests/Android.mk
+++ b/media/tests/MtpTests/Android.mk
@@ -5,7 +5,7 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
 
 LOCAL_PACKAGE_NAME := MtpTests
 LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/media/tests/MtpTests/AndroidManifest.xml b/media/tests/MtpTests/AndroidManifest.xml
index 21e2b01..72e03f1 100644
--- a/media/tests/MtpTests/AndroidManifest.xml
+++ b/media/tests/MtpTests/AndroidManifest.xml
@@ -25,7 +25,7 @@
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.mtp"
                      android:label="MtpTests"/>
 </manifest>
diff --git a/media/tests/MtpTests/AndroidTest.xml b/media/tests/MtpTests/AndroidTest.xml
index a61a3b4..22638bc 100644
--- a/media/tests/MtpTests/AndroidTest.xml
+++ b/media/tests/MtpTests/AndroidTest.xml
@@ -10,6 +10,6 @@
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest">
         <option name="package" value="android.mtp"/>
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
     </test>
 </configuration>
\ No newline at end of file
diff --git a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
index 566d1c6..1f58bde 100644
--- a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
+++ b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
@@ -18,20 +18,19 @@
 import android.os.FileUtils;
 import android.os.UserHandle;
 import android.os.storage.StorageVolume;
-import android.support.test.filters.SmallTest;
-import android.support.test.InstrumentationRegistry;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
 import org.junit.After;
-import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.FixMethodOrder;
 import org.junit.Test;
-import org.junit.runners.MethodSorters;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.junit.runners.MethodSorters;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -39,8 +38,6 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
 
 /**
  * Tests for MtpStorageManager functionality.
diff --git a/media/tests/players/Android.mk b/media/tests/players/Android.mk
index 35aba4d..ee9d850 100644
--- a/media/tests/players/Android.mk
+++ b/media/tests/players/Android.mk
@@ -25,7 +25,7 @@
     liblog
 
 LOCAL_MODULE:= invoke_mock_media_player
-LOCAL_MODULE_TAGS := tests eng
+LOCAL_MODULE_TAGS := tests
 
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 5cfb09b..7c1af4a 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -49,12 +49,14 @@
         "sharedmem.cpp",
         "storage_manager.cpp",
         "surface_texture.cpp",
+        "surface_control.cpp",
         "system_fonts.cpp",
         "trace.cpp",
     ],
 
     shared_libs: [
         "liblog",
+        "libhidlbase",
         "libcutils",
         "libandroidfw",
         "libinput",
@@ -69,6 +71,8 @@
         "libnetd_client",
         "libhwui",
         "libxml2",
+        "android.hardware.configstore@1.0",
+        "android.hardware.configstore-utils",
     ],
 
     static_libs: [
@@ -83,6 +87,10 @@
     include_dirs: ["bionic/libc/dns/include"],
 
     version_script: "libandroid.map.txt",
+    stubs: {
+        symbol_file: "libandroid.map.txt",
+        versions: ["29"],
+    },
 }
 
 // Network library.
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 537aed4..51afbc7 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -172,6 +172,7 @@
     ASensorEventQueue_hasEvents;
     ASensorEventQueue_registerSensor; # introduced=26
     ASensorEventQueue_setEventRate;
+    ASensorEventQueue_requestAdditionalInfoEvents; # introduced=29
     ASensorManager_configureDirectReport; # introduced=26
     ASensorManager_createEventQueue;
     ASensorManager_createHardwareBufferDirectChannel; # introduced=26
@@ -185,6 +186,7 @@
     ASensorManager_getSensorList;
     ASensor_getFifoMaxEventCount; # introduced=21
     ASensor_getFifoReservedEventCount; # introduced=21
+    ASensor_getHandle; # introduced=29
     ASensor_getHighestDirectReportRateLevel; # introduced=26
     ASensor_getMinDelay;
     ASensor_getName;
@@ -205,6 +207,9 @@
     AStorageManager_mountObb;
     AStorageManager_new;
     AStorageManager_unmountObb;
+    ASurfaceControl_create; # introduced=29
+    ASurfaceControl_createFromWindow; # introduced=29
+    ASurfaceControl_release; # introduced=29
     ASurfaceTexture_acquireANativeWindow; # introduced=28
     ASurfaceTexture_attachToGLContext; # introduced=28
     ASurfaceTexture_detachFromGLContext; # introduced=28
@@ -213,6 +218,28 @@
     ASurfaceTexture_getTransformMatrix; # introduced=28
     ASurfaceTexture_release; # introduced=28
     ASurfaceTexture_updateTexImage; # introduced=28
+    ASurfaceTransactionStats_getAcquireTime; # introduced=29
+    ASurfaceTransactionStats_getASurfaceControls; # introduced=29
+    ASurfaceTransactionStats_getLatchTime; # introduced=29
+    ASurfaceTransactionStats_getPresentFenceFd; # introduced=29
+    ASurfaceTransactionStats_getPreviousReleaseFenceFd; # introduced=29
+    ASurfaceTransactionStats_releaseASurfaceControls; # introduced=29
+    ASurfaceTransaction_apply; # introduced=29
+    ASurfaceTransaction_create; # introduced=29
+    ASurfaceTransaction_delete; # introduced=29
+    ASurfaceTransaction_reparent; # introduced=29
+    ASurfaceTransaction_setBuffer; # introduced=29
+    ASurfaceTransaction_setBufferAlpha; # introduced=29
+    ASurfaceTransaction_setBufferTransparency; # introduced=29
+    ASurfaceTransaction_setColor; # introduced=29
+    ASurfaceTransaction_setDamageRegion; # introduced=29
+    ASurfaceTransaction_setDesiredPresentTime; # introduced=29
+    ASurfaceTransaction_setGeometry; # introduced=29
+    ASurfaceTransaction_setHdrMetadata_cta861_3; # introduced=29
+    ASurfaceTransaction_setHdrMetadata_smpte2086; # introduced=29
+    ASurfaceTransaction_setOnComplete; # introduced=29
+    ASurfaceTransaction_setVisibility; # introduced=29
+    ASurfaceTransaction_setZOrder; # introduced=29
     ASystemFontIterator_open; # introduced=29
     ASystemFontIterator_close; # introduced=29
     ASystemFontIterator_next; # introduced=29
diff --git a/native/android/net.c b/native/android/net.c
index 4cac371..a8104fc 100644
--- a/native/android/net.c
+++ b/native/android/net.c
@@ -84,26 +84,28 @@
     return android_getaddrinfofornet(node, service, hints, netid, 0, res);
 }
 
-int android_res_nquery(net_handle_t network, const char *dname, int ns_class, int ns_type) {
+int android_res_nquery(net_handle_t network, const char *dname,
+        int ns_class, int ns_type, enum ResNsendFlags flags) {
     unsigned netid;
     if (!getnetidfromhandle(network, &netid)) {
         return -ENONET;
     }
 
-    return resNetworkQuery(netid, dname, ns_class, ns_type);
+    return resNetworkQuery(netid, dname, ns_class, ns_type, flags);
 }
 
 int android_res_nresult(int fd, int *rcode, uint8_t *answer, size_t anslen) {
     return resNetworkResult(fd, rcode, answer, anslen);
 }
 
-int android_res_nsend(net_handle_t network, const uint8_t *msg, size_t msglen) {
+int android_res_nsend(net_handle_t network, const uint8_t *msg, size_t msglen,
+        enum ResNsendFlags flags) {
     unsigned netid;
     if (!getnetidfromhandle(network, &netid)) {
         return -ENONET;
     }
 
-    return resNetworkSend(netid, msg, msglen);
+    return resNetworkSend(netid, msg, msglen, flags);
 }
 
 void android_res_cancel(int nsend_fd) {
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 8e58210..63082fd 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -115,6 +115,7 @@
     if (queue != 0) {
         ALooper_addFd(looper, queue->getFd(), ident, ALOOPER_EVENT_INPUT, callback, data);
         queue->looper = looper;
+        queue->requestAdditionalInfo = false;
         queue->incStrong(manager);
     }
     return static_cast<ASensorEventQueue*>(queue.get());
@@ -274,11 +275,19 @@
         return android::BAD_VALUE;
     }
 
-    ssize_t actual = static_cast<SensorEventQueue*>(queue)->read(events, count);
+    SensorEventQueue* sensorQueue = static_cast<SensorEventQueue*>(queue);
+    ssize_t actual = sensorQueue->read(events, count);
     if (actual > 0) {
-        static_cast<SensorEventQueue*>(queue)->sendAck(events, actual);
+        sensorQueue->sendAck(events, actual);
     }
-    return actual;
+
+    return sensorQueue->filterEvents(events, actual);
+}
+
+int ASensorEventQueue_requestAdditionalInfoEvents(ASensorEventQueue* queue, bool enable) {
+    RETURN_IF_QUEUE_IS_NULL(android::BAD_VALUE);
+    queue->requestAdditionalInfo = enable;
+    return android::OK;
 }
 
 /*****************************************************************************/
@@ -342,3 +351,8 @@
     RETURN_IF_SENSOR_IS_NULL(ASENSOR_DIRECT_RATE_STOP);
     return static_cast<Sensor const *>(sensor)->getHighestDirectReportRateLevel();
 }
+
+int ASensor_getHandle(ASensor const* sensor) {
+    RETURN_IF_SENSOR_IS_NULL(ASENSOR_INVALID);
+    return static_cast<Sensor const*>(sensor)->getHandle();
+}
diff --git a/native/android/sharedmem.cpp b/native/android/sharedmem.cpp
index 757aaec..4410bd6 100644
--- a/native/android/sharedmem.cpp
+++ b/native/android/sharedmem.cpp
@@ -71,7 +71,7 @@
     }
     int fd = env->CallIntMethod(javaSharedMemory, sSharedMemory.getFd);
     if (fd != -1) {
-        fd = dup(fd);
+        fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
     }
     return fd;
 }
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
new file mode 100644
index 0000000..5fae9d5
--- /dev/null
+++ b/native/android/surface_control.cpp
@@ -0,0 +1,524 @@
+/*
+ * 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.
+ */
+
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <android/native_window.h>
+#include <android/surface_control.h>
+
+#include <configstore/Utils.h>
+
+#include <gui/HdrMetadata.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+
+#include <ui/HdrCapabilities.h>
+
+#include <utils/Timers.h>
+
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+using namespace android;
+using android::hardware::configstore::V1_0::ISurfaceFlingerConfigs;
+
+using Transaction = SurfaceComposerClient::Transaction;
+
+#define CHECK_NOT_NULL(name) \
+    LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
+
+#define CHECK_VALID_RECT(name)                                     \
+    LOG_ALWAYS_FATAL_IF(!static_cast<const Rect&>(name).isValid(), \
+                        "invalid arg passed as " #name " argument");
+
+static bool getWideColorSupport(const sp<SurfaceControl>& surfaceControl) {
+    sp<SurfaceComposerClient> client = surfaceControl->getClient();
+    sp<IBinder> display(client->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+
+    Vector<ui::ColorMode> colorModes;
+    status_t err = client->getDisplayColorModes(display, &colorModes);
+    if (err) {
+        ALOGE("unable to get wide color support");
+        return false;
+    }
+
+    bool wideColorBoardConfig =
+        getBool<ISurfaceFlingerConfigs,
+                &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+
+    for (android::ui::ColorMode colorMode : colorModes) {
+        switch (colorMode) {
+            case ui::ColorMode::DISPLAY_P3:
+            case ui::ColorMode::ADOBE_RGB:
+            case ui::ColorMode::DCI_P3:
+                if (wideColorBoardConfig) {
+                    return true;
+                }
+                break;
+            default:
+                break;
+        }
+    }
+    return false;
+}
+
+static bool getHdrSupport(const sp<SurfaceControl>& surfaceControl) {
+    sp<SurfaceComposerClient> client = surfaceControl->getClient();
+    sp<IBinder> display(client->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+
+    HdrCapabilities hdrCapabilities;
+    status_t err = client->getHdrCapabilities(display, &hdrCapabilities);
+    if (err) {
+        ALOGE("unable to get hdr capabilities");
+        return false;
+    }
+
+    return !hdrCapabilities.getSupportedHdrTypes().empty();
+}
+
+static bool isDataSpaceValid(const sp<SurfaceControl>& surfaceControl, ADataSpace dataSpace) {
+    static_assert(static_cast<int>(ADATASPACE_UNKNOWN) == static_cast<int>(HAL_DATASPACE_UNKNOWN));
+    static_assert(static_cast<int>(ADATASPACE_SCRGB_LINEAR) == static_cast<int>(HAL_DATASPACE_V0_SCRGB_LINEAR));
+    static_assert(static_cast<int>(ADATASPACE_SRGB) == static_cast<int>(HAL_DATASPACE_V0_SRGB));
+    static_assert(static_cast<int>(ADATASPACE_SCRGB) == static_cast<int>(HAL_DATASPACE_V0_SCRGB));
+    static_assert(static_cast<int>(ADATASPACE_DISPLAY_P3) == static_cast<int>(HAL_DATASPACE_DISPLAY_P3));
+    static_assert(static_cast<int>(ADATASPACE_BT2020_PQ) == static_cast<int>(HAL_DATASPACE_BT2020_PQ));
+
+    switch (static_cast<android_dataspace_t>(dataSpace)) {
+        case HAL_DATASPACE_UNKNOWN:
+        case HAL_DATASPACE_V0_SRGB:
+            return true;
+        // These data space need wide gamut support.
+        case HAL_DATASPACE_V0_SCRGB_LINEAR:
+        case HAL_DATASPACE_V0_SCRGB:
+        case HAL_DATASPACE_DISPLAY_P3:
+            return getWideColorSupport(surfaceControl);
+        // These data space need HDR support.
+        case HAL_DATASPACE_BT2020_PQ:
+            return getHdrSupport(surfaceControl);
+        default:
+            return false;
+    }
+}
+
+Transaction* ASurfaceTransaction_to_Transaction(ASurfaceTransaction* aSurfaceTransaction) {
+    return reinterpret_cast<Transaction*>(aSurfaceTransaction);
+}
+
+SurfaceControl* ASurfaceControl_to_SurfaceControl(ASurfaceControl* aSurfaceControl) {
+    return reinterpret_cast<SurfaceControl*>(aSurfaceControl);
+}
+
+void SurfaceControl_acquire(SurfaceControl* surfaceControl) {
+    // incStrong/decStrong token must be the same, doesn't matter what it is
+    surfaceControl->incStrong((void*)SurfaceControl_acquire);
+}
+
+void SurfaceControl_release(SurfaceControl* surfaceControl) {
+    // incStrong/decStrong token must be the same, doesn't matter what it is
+    surfaceControl->decStrong((void*)SurfaceControl_acquire);
+}
+
+ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* window, const char* debug_name) {
+    CHECK_NOT_NULL(window);
+    CHECK_NOT_NULL(debug_name);
+
+    sp<SurfaceComposerClient> client = new SurfaceComposerClient();
+    if (client->initCheck() != NO_ERROR) {
+        return nullptr;
+    }
+
+    uint32_t flags = ISurfaceComposerClient::eFXSurfaceBufferState;
+    sp<SurfaceControl> surfaceControl =
+            client->createWithSurfaceParent(String8(debug_name), 0 /* width */, 0 /* height */,
+                                            // Format is only relevant for buffer queue layers.
+                                            PIXEL_FORMAT_UNKNOWN /* format */, flags,
+                                            static_cast<Surface*>(window));
+    if (!surfaceControl) {
+        return nullptr;
+    }
+
+    SurfaceControl_acquire(surfaceControl.get());
+    return reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
+}
+
+ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name) {
+    CHECK_NOT_NULL(parent);
+    CHECK_NOT_NULL(debug_name);
+
+    SurfaceComposerClient* client = ASurfaceControl_to_SurfaceControl(parent)->getClient().get();
+
+    SurfaceControl* surfaceControlParent = ASurfaceControl_to_SurfaceControl(parent);
+
+    uint32_t flags = ISurfaceComposerClient::eFXSurfaceBufferState;
+    sp<SurfaceControl> surfaceControl =
+            client->createSurface(String8(debug_name), 0 /* width */, 0 /* height */,
+                                  // Format is only relevant for buffer queue layers.
+                                  PIXEL_FORMAT_UNKNOWN /* format */, flags,
+                                  surfaceControlParent);
+    if (!surfaceControl) {
+        return nullptr;
+    }
+
+    SurfaceControl_acquire(surfaceControl.get());
+    return reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
+}
+
+void ASurfaceControl_release(ASurfaceControl* aSurfaceControl) {
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+
+    SurfaceControl_release(surfaceControl.get());
+}
+
+ASurfaceTransaction* ASurfaceTransaction_create() {
+    Transaction* transaction = new Transaction;
+    return reinterpret_cast<ASurfaceTransaction*>(transaction);
+}
+
+void ASurfaceTransaction_delete(ASurfaceTransaction* aSurfaceTransaction) {
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+    delete transaction;
+}
+
+void ASurfaceTransaction_apply(ASurfaceTransaction* aSurfaceTransaction) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    transaction->apply();
+}
+
+typedef struct ASurfaceControlStats {
+    int64_t acquireTime;
+    sp<Fence> previousReleaseFence;
+} ASurfaceControlStats;
+
+struct ASurfaceTransactionStats {
+    std::unordered_map<ASurfaceControl*, ASurfaceControlStats> aSurfaceControlStats;
+    int64_t latchTime;
+    sp<Fence> presentFence;
+};
+
+int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* aSurfaceTransactionStats) {
+    CHECK_NOT_NULL(aSurfaceTransactionStats);
+    return aSurfaceTransactionStats->latchTime;
+}
+
+int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* aSurfaceTransactionStats) {
+    CHECK_NOT_NULL(aSurfaceTransactionStats);
+    auto& presentFence = aSurfaceTransactionStats->presentFence;
+    return (presentFence) ? presentFence->dup() : -1;
+}
+
+void ASurfaceTransactionStats_getASurfaceControls(ASurfaceTransactionStats* aSurfaceTransactionStats,
+                                                  ASurfaceControl*** outASurfaceControls,
+                                                  size_t* outASurfaceControlsSize) {
+    CHECK_NOT_NULL(aSurfaceTransactionStats);
+    CHECK_NOT_NULL(outASurfaceControls);
+    CHECK_NOT_NULL(outASurfaceControlsSize);
+
+    size_t size = aSurfaceTransactionStats->aSurfaceControlStats.size();
+
+    SurfaceControl** surfaceControls = new SurfaceControl*[size];
+    ASurfaceControl** aSurfaceControls = reinterpret_cast<ASurfaceControl**>(surfaceControls);
+
+    size_t i = 0;
+    for (auto& [aSurfaceControl, aSurfaceControlStats] : aSurfaceTransactionStats->aSurfaceControlStats) {
+        aSurfaceControls[i] = aSurfaceControl;
+        i++;
+    }
+
+    *outASurfaceControls = aSurfaceControls;
+    *outASurfaceControlsSize = size;
+}
+
+int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* aSurfaceTransactionStats,
+                                                ASurfaceControl* aSurfaceControl) {
+    CHECK_NOT_NULL(aSurfaceTransactionStats);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    const auto& aSurfaceControlStats =
+            aSurfaceTransactionStats->aSurfaceControlStats.find(aSurfaceControl);
+    LOG_ALWAYS_FATAL_IF(
+            aSurfaceControlStats == aSurfaceTransactionStats->aSurfaceControlStats.end(),
+            "ASurfaceControl not found");
+
+    return aSurfaceControlStats->second.acquireTime;
+}
+
+int ASurfaceTransactionStats_getPreviousReleaseFenceFd(
+            ASurfaceTransactionStats* aSurfaceTransactionStats, ASurfaceControl* aSurfaceControl) {
+    CHECK_NOT_NULL(aSurfaceTransactionStats);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    const auto& aSurfaceControlStats =
+            aSurfaceTransactionStats->aSurfaceControlStats.find(aSurfaceControl);
+    LOG_ALWAYS_FATAL_IF(
+            aSurfaceControlStats == aSurfaceTransactionStats->aSurfaceControlStats.end(),
+            "ASurfaceControl not found");
+
+    auto& previousReleaseFence = aSurfaceControlStats->second.previousReleaseFence;
+    return (previousReleaseFence) ? previousReleaseFence->dup() : -1;
+}
+
+void ASurfaceTransactionStats_releaseASurfaceControls(ASurfaceControl** aSurfaceControls) {
+    CHECK_NOT_NULL(aSurfaceControls);
+
+    SurfaceControl** surfaceControls = reinterpret_cast<SurfaceControl**>(aSurfaceControls);
+    delete[] surfaceControls;
+}
+
+void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* aSurfaceTransaction, void* context,
+                                       ASurfaceTransaction_OnComplete func) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(context);
+    CHECK_NOT_NULL(func);
+
+    TransactionCompletedCallbackTakesContext callback = [func](void* callback_context,
+                                                               nsecs_t latchTime,
+                                                               const sp<Fence>& presentFence,
+                                                               const std::vector<SurfaceControlStats>& surfaceControlStats) {
+        ASurfaceTransactionStats aSurfaceTransactionStats;
+
+        aSurfaceTransactionStats.latchTime = latchTime;
+        aSurfaceTransactionStats.presentFence = presentFence;
+
+        auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats;
+
+        for (const auto& [surfaceControl, acquireTime, previousReleaseFence] : surfaceControlStats) {
+            ASurfaceControl* aSurfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
+            aSurfaceControlStats[aSurfaceControl].acquireTime = acquireTime;
+            aSurfaceControlStats[aSurfaceControl].previousReleaseFence = previousReleaseFence;
+        }
+
+        (*func)(callback_context, &aSurfaceTransactionStats);
+    };
+
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    transaction->addTransactionCompletedCallback(callback, context);
+}
+
+void ASurfaceTransaction_reparent(ASurfaceTransaction* aSurfaceTransaction,
+                                  ASurfaceControl* aSurfaceControl,
+                                  ASurfaceControl* newParentASurfaceControl) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    sp<SurfaceControl> newParentSurfaceControl = ASurfaceControl_to_SurfaceControl(
+            newParentASurfaceControl);
+    sp<IBinder> newParentHandle = (newParentSurfaceControl)? newParentSurfaceControl->getHandle() : nullptr;
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    transaction->reparent(surfaceControl, newParentHandle);
+}
+
+void ASurfaceTransaction_setVisibility(ASurfaceTransaction* aSurfaceTransaction,
+                                       ASurfaceControl* aSurfaceControl,
+                                       int8_t visibility) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    switch (visibility) {
+    case ASURFACE_TRANSACTION_VISIBILITY_SHOW:
+        transaction->show(surfaceControl);
+        break;
+    case ASURFACE_TRANSACTION_VISIBILITY_HIDE:
+        transaction->hide(surfaceControl);
+        break;
+    default:
+        LOG_ALWAYS_FATAL("invalid visibility %d", visibility);
+    }
+}
+
+void ASurfaceTransaction_setZOrder(ASurfaceTransaction* aSurfaceTransaction,
+                                   ASurfaceControl* aSurfaceControl,
+                                   int32_t z_order) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    transaction->setLayer(surfaceControl, z_order);
+}
+
+void ASurfaceTransaction_setBuffer(ASurfaceTransaction* aSurfaceTransaction,
+                                   ASurfaceControl* aSurfaceControl,
+                                   AHardwareBuffer* buffer, int acquire_fence_fd) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    sp<GraphicBuffer> graphic_buffer(reinterpret_cast<GraphicBuffer*>(buffer));
+
+    transaction->setBuffer(surfaceControl, graphic_buffer);
+    if (acquire_fence_fd != -1) {
+        sp<Fence> fence = new Fence(acquire_fence_fd);
+        transaction->setAcquireFence(surfaceControl, fence);
+    }
+}
+
+void ASurfaceTransaction_setGeometry(ASurfaceTransaction* aSurfaceTransaction,
+                                     ASurfaceControl* aSurfaceControl, const ARect& source,
+                                     const ARect& destination, int32_t transform) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+    CHECK_VALID_RECT(source);
+    CHECK_VALID_RECT(destination);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    transaction->setCrop(surfaceControl, static_cast<const Rect&>(source));
+    transaction->setFrame(surfaceControl, static_cast<const Rect&>(destination));
+    transaction->setTransform(surfaceControl, transform);
+}
+
+void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* aSurfaceTransaction,
+                                               ASurfaceControl* aSurfaceControl,
+                                               int8_t transparency) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    uint32_t flags = (transparency == ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE) ?
+                      layer_state_t::eLayerOpaque : 0;
+    transaction->setFlags(surfaceControl, flags, layer_state_t::eLayerOpaque);
+}
+
+void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* aSurfaceTransaction,
+                                         ASurfaceControl* aSurfaceControl,
+                                         const ARect rects[], uint32_t count) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    Region region;
+    for (uint32_t i = 0; i < count; ++i) {
+        region.merge(static_cast<const Rect&>(rects[i]));
+    }
+
+    transaction->setSurfaceDamageRegion(surfaceControl, region);
+}
+
+void ASurfaceTransaction_setDesiredPresentTime(ASurfaceTransaction* aSurfaceTransaction,
+                                         int64_t desiredPresentTime) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    transaction->setDesiredPresentTime(static_cast<nsecs_t>(desiredPresentTime));
+}
+
+void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* aSurfaceTransaction,
+                                         ASurfaceControl* aSurfaceControl,
+                                         float alpha) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    LOG_ALWAYS_FATAL_IF(alpha < 0.0 || alpha > 1.0, "invalid alpha");
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    transaction->setAlpha(surfaceControl, alpha);
+}
+
+void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* aSurfaceTransaction,
+                                                  ASurfaceControl* aSurfaceControl,
+                                                  struct AHdrMetadata_smpte2086* metadata) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    HdrMetadata hdrMetadata;
+
+    if (metadata) {
+        hdrMetadata.smpte2086.displayPrimaryRed.x = metadata->displayPrimaryRed.x;
+        hdrMetadata.smpte2086.displayPrimaryRed.y = metadata->displayPrimaryRed.y;
+        hdrMetadata.smpte2086.displayPrimaryGreen.x = metadata->displayPrimaryGreen.x;
+        hdrMetadata.smpte2086.displayPrimaryGreen.y = metadata->displayPrimaryGreen.y;
+        hdrMetadata.smpte2086.displayPrimaryBlue.x = metadata->displayPrimaryBlue.x;
+        hdrMetadata.smpte2086.displayPrimaryBlue.y = metadata->displayPrimaryBlue.y;
+        hdrMetadata.smpte2086.whitePoint.x = metadata->whitePoint.x;
+        hdrMetadata.smpte2086.whitePoint.y = metadata->whitePoint.y;
+        hdrMetadata.smpte2086.minLuminance = metadata->minLuminance;
+        hdrMetadata.smpte2086.maxLuminance = metadata->maxLuminance;
+
+        hdrMetadata.validTypes |= HdrMetadata::SMPTE2086;
+    } else {
+        hdrMetadata.validTypes &= ~HdrMetadata::SMPTE2086;
+    }
+
+    transaction->setHdrMetadata(surfaceControl, hdrMetadata);
+}
+
+void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* aSurfaceTransaction,
+                                                 ASurfaceControl* aSurfaceControl,
+                                                 struct AHdrMetadata_cta861_3* metadata) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    HdrMetadata hdrMetadata;
+
+    if (metadata) {
+        hdrMetadata.cta8613.maxContentLightLevel = metadata->maxContentLightLevel;
+        hdrMetadata.cta8613.maxFrameAverageLightLevel = metadata->maxFrameAverageLightLevel;
+
+        hdrMetadata.validTypes |= HdrMetadata::CTA861_3;
+    } else {
+        hdrMetadata.validTypes &= ~HdrMetadata::CTA861_3;
+    }
+
+    transaction->setHdrMetadata(surfaceControl, hdrMetadata);
+}
+
+void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction,
+                                  ASurfaceControl* aSurfaceControl,
+                                  float r, float g, float b, float alpha,
+                                  ADataSpace dataspace) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    LOG_ALWAYS_FATAL_IF(!isDataSpaceValid(surfaceControl, dataspace), "invalid dataspace");
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    half3 color;
+    color.r = r;
+    color.g = g;
+    color.b = b;
+
+    transaction->setColor(surfaceControl, color)
+                .setColorAlpha(surfaceControl, alpha)
+                .setColorDataspace(surfaceControl, static_cast<ui::Dataspace>(dataspace));
+}
diff --git a/native/webview/plat_support/Android.bp b/native/webview/plat_support/Android.bp
index 96c9c1c..88decc8 100644
--- a/native/webview/plat_support/Android.bp
+++ b/native/webview/plat_support/Android.bp
@@ -22,8 +22,8 @@
     name: "libwebviewchromium_plat_support",
 
     srcs: [
+        "draw_functor.cpp",
         "draw_gl_functor.cpp",
-        "draw_vk_functor.cpp",
         "functor_utils.cpp",
         "jni_entry_point.cpp",
         "graphics_utils.cpp",
diff --git a/native/webview/plat_support/draw_fn.h b/native/webview/plat_support/draw_fn.h
index 8d48a58..0490e65 100644
--- a/native/webview/plat_support/draw_fn.h
+++ b/native/webview/plat_support/draw_fn.h
@@ -74,7 +74,10 @@
   VkQueue queue;
   uint32_t graphics_queue_index;
   uint32_t instance_version;
-  const char* const* enabled_extension_names;
+  const char* const* enabled_instance_extension_names;
+  uint32_t enabled_instance_extension_names_length;
+  const char* const* enabled_device_extension_names;
+  uint32_t enabled_device_extension_names_length;
   // Only one of device_features and device_features_2 should be non-null.
   // If both are null then no features are enabled.
   VkPhysicalDeviceFeatures* device_features;
@@ -109,8 +112,15 @@
   // Input: Format of the destination surface.
   VkFormat format;
 
-  // Input: Color space transformation from linear RGB to D50-adapted XYZ
-  float matrix[9];
+  // Input: Color space parameters.
+  float transfer_function_g;
+  float transfer_function_a;
+  float transfer_function_b;
+  float transfer_function_c;
+  float transfer_function_d;
+  float transfer_function_e;
+  float transfer_function_f;
+  float color_space_toXYZD50[9];
 
   // Input: current clip rect
   int clip_left;
@@ -121,39 +131,44 @@
 
 struct AwDrawFn_PostDrawVkParams {
   int version;
-
-  // Input: Fence for the composite command buffer to signal it has finished its
-  // work on the GPU.
-  int fd;
 };
 
 // Called on render thread while UI thread is blocked. Called for both GL and
 // VK.
-typedef void AwDrawFn_OnSync(int functor, AwDrawFn_OnSyncParams* params);
+typedef void AwDrawFn_OnSync(int functor,
+                             void* data,
+                             AwDrawFn_OnSyncParams* params);
 
 // Called on render thread when either the context is destroyed _or_ when the
 // functor's last reference goes away. Will always be called with an active
 // context. Called for both GL and VK.
-typedef void AwDrawFn_OnContextDestroyed(int functor);
+typedef void AwDrawFn_OnContextDestroyed(int functor, void* data);
 
 // Called on render thread when the last reference to the handle goes away and
-// the handle is considered irrevocably destroyed. Will always be proceeded by
+// the handle is considered irrevocably destroyed. Will always be preceded by
 // a call to OnContextDestroyed if this functor had ever been drawn. Called for
 // both GL and VK.
-typedef void AwDrawFn_OnDestroyed(int functor);
+typedef void AwDrawFn_OnDestroyed(int functor, void* data);
 
 // Only called for GL.
-typedef void AwDrawFn_DrawGL(int functor, AwDrawFn_DrawGLParams* params);
+typedef void AwDrawFn_DrawGL(int functor,
+                             void* data,
+                             AwDrawFn_DrawGLParams* params);
 
 // Initialize vulkan state. Needs to be called again after any
 // OnContextDestroyed. Only called for Vulkan.
-typedef void AwDrawFn_InitVk(int functor, AwDrawFn_InitVkParams* params);
+typedef void AwDrawFn_InitVk(int functor,
+                             void* data,
+                             AwDrawFn_InitVkParams* params);
 
 // Only called for Vulkan.
-typedef void AwDrawFn_DrawVk(int functor, AwDrawFn_DrawVkParams* params);
+typedef void AwDrawFn_DrawVk(int functor,
+                             void* data,
+                             AwDrawFn_DrawVkParams* params);
 
 // Only called for Vulkan.
 typedef void AwDrawFn_PostDrawVk(int functor,
+                                 void* data,
                                  AwDrawFn_PostDrawVkParams* params);
 
 struct AwDrawFnFunctorCallbacks {
@@ -176,7 +191,8 @@
 typedef AwDrawFnRenderMode AwDrawFn_QueryRenderMode(void);
 
 // Create a functor. |functor_callbacks| should be valid until OnDestroyed.
-typedef int AwDrawFn_CreateFunctor(AwDrawFnFunctorCallbacks* functor_callbacks);
+typedef int AwDrawFn_CreateFunctor(void* data,
+                                   AwDrawFnFunctorCallbacks* functor_callbacks);
 
 // May be called on any thread to signal that the functor should be destroyed.
 // The functor will receive an onDestroyed when the last usage of it is
diff --git a/native/webview/plat_support/draw_functor.cpp b/native/webview/plat_support/draw_functor.cpp
new file mode 100644
index 0000000..b97bbc3
--- /dev/null
+++ b/native/webview/plat_support/draw_functor.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 "draw_fn.h"
+
+#include <jni.h>
+#include <private/hwui/WebViewFunctor.h>
+#include <utils/Log.h>
+
+#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+#define COMPILE_ASSERT(expr, err) \
+__unused static const char (err)[(expr) ? 1 : -1] = "";
+
+namespace android {
+namespace {
+
+struct SupportData {
+  void* const data;
+  AwDrawFnFunctorCallbacks callbacks;
+};
+
+void onSync(int functor, void* data,
+            const uirenderer::WebViewSyncData& syncData) {
+  AwDrawFn_OnSyncParams params = {
+      .version = kAwDrawFnVersion,
+      .apply_force_dark = syncData.applyForceDark,
+  };
+  SupportData* support = static_cast<SupportData*>(data);
+  support->callbacks.on_sync(functor, support->data, &params);
+}
+
+void onContextDestroyed(int functor, void* data) {
+  SupportData* support = static_cast<SupportData*>(data);
+  support->callbacks.on_context_destroyed(functor, support->data);
+}
+
+void onDestroyed(int functor, void* data) {
+  SupportData* support = static_cast<SupportData*>(data);
+  support->callbacks.on_destroyed(functor, support->data);
+  delete support;
+}
+
+void draw_gl(int functor, void* data,
+             const uirenderer::DrawGlInfo& draw_gl_params) {
+  AwDrawFn_DrawGLParams params = {
+      .version = kAwDrawFnVersion,
+      .clip_left = draw_gl_params.clipLeft,
+      .clip_top = draw_gl_params.clipTop,
+      .clip_right = draw_gl_params.clipRight,
+      .clip_bottom = draw_gl_params.clipBottom,
+      .width = draw_gl_params.width,
+      .height = draw_gl_params.height,
+      .is_layer = draw_gl_params.isLayer,
+  };
+  COMPILE_ASSERT(NELEM(params.transform) == NELEM(draw_gl_params.transform),
+                 mismatched_transform_matrix_sizes);
+  for (int i = 0; i < NELEM(params.transform); ++i) {
+    params.transform[i] = draw_gl_params.transform[i];
+  }
+  SupportData* support = static_cast<SupportData*>(data);
+  support->callbacks.draw_gl(functor, support->data, &params);
+}
+
+void initializeVk(int functor, void* data,
+                  const uirenderer::VkFunctorInitParams& init_vk_params) {
+  SupportData* support = static_cast<SupportData*>(data);
+  VkPhysicalDeviceFeatures2 device_features_2;
+  if (init_vk_params.device_features_2)
+    device_features_2 = *init_vk_params.device_features_2;
+
+  AwDrawFn_InitVkParams params{
+      .version = kAwDrawFnVersion,
+      .instance = init_vk_params.instance,
+      .physical_device = init_vk_params.physical_device,
+      .device = init_vk_params.device,
+      .queue = init_vk_params.queue,
+      .graphics_queue_index = init_vk_params.graphics_queue_index,
+      .instance_version = init_vk_params.instance_version,
+      .enabled_instance_extension_names =
+          init_vk_params.enabled_instance_extension_names,
+      .enabled_instance_extension_names_length =
+          init_vk_params.enabled_instance_extension_names_length,
+      .enabled_device_extension_names =
+          init_vk_params.enabled_device_extension_names,
+      .enabled_device_extension_names_length =
+          init_vk_params.enabled_device_extension_names_length,
+      .device_features = nullptr,
+      .device_features_2 =
+          init_vk_params.device_features_2 ? &device_features_2 : nullptr,
+  };
+  support->callbacks.init_vk(functor, support->data, &params);
+}
+
+void drawVk(int functor, void* data, const uirenderer::VkFunctorDrawParams& draw_vk_params) {
+  SupportData* support = static_cast<SupportData*>(data);
+  float gabcdef[7];
+  draw_vk_params.color_space_ptr->transferFn(gabcdef);
+  AwDrawFn_DrawVkParams params{
+      .version = kAwDrawFnVersion,
+      .width = draw_vk_params.width,
+      .height = draw_vk_params.height,
+      .is_layer = draw_vk_params.is_layer,
+      .secondary_command_buffer = draw_vk_params.secondary_command_buffer,
+      .color_attachment_index = draw_vk_params.color_attachment_index,
+      .compatible_render_pass = draw_vk_params.compatible_render_pass,
+      .format = draw_vk_params.format,
+      .transfer_function_g = gabcdef[0],
+      .transfer_function_a = gabcdef[1],
+      .transfer_function_b = gabcdef[2],
+      .transfer_function_c = gabcdef[3],
+      .transfer_function_d = gabcdef[4],
+      .transfer_function_e = gabcdef[5],
+      .transfer_function_f = gabcdef[6],
+      .clip_left = draw_vk_params.clip_left,
+      .clip_top = draw_vk_params.clip_top,
+      .clip_right = draw_vk_params.clip_right,
+      .clip_bottom = draw_vk_params.clip_bottom,
+  };
+  COMPILE_ASSERT(sizeof(params.color_space_toXYZD50) == sizeof(skcms_Matrix3x3),
+                 gamut_transform_size_mismatch);
+  draw_vk_params.color_space_ptr->toXYZD50(
+      reinterpret_cast<skcms_Matrix3x3*>(&params.color_space_toXYZD50));
+  COMPILE_ASSERT(NELEM(params.transform) == NELEM(draw_vk_params.transform),
+                 mismatched_transform_matrix_sizes);
+  for (int i = 0; i < NELEM(params.transform); ++i) {
+    params.transform[i] = draw_vk_params.transform[i];
+  }
+  support->callbacks.draw_vk(functor, support->data, &params);
+}
+
+void postDrawVk(int functor, void* data) {
+  SupportData* support = static_cast<SupportData*>(data);
+  AwDrawFn_PostDrawVkParams params{.version = kAwDrawFnVersion};
+  support->callbacks.post_draw_vk(functor, support->data, &params);
+}
+
+int CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks) {
+  static bool callbacks_initialized = false;
+  static uirenderer::WebViewFunctorCallbacks webview_functor_callbacks = {
+      .onSync = &onSync,
+      .onContextDestroyed = &onContextDestroyed,
+      .onDestroyed = &onDestroyed,
+  };
+  if (!callbacks_initialized) {
+    switch (uirenderer::WebViewFunctor_queryPlatformRenderMode()) {
+      case uirenderer::RenderMode::OpenGL_ES:
+        webview_functor_callbacks.gles.draw = &draw_gl;
+        break;
+      case uirenderer::RenderMode::Vulkan:
+        webview_functor_callbacks.vk.initialize = &initializeVk;
+        webview_functor_callbacks.vk.draw = &drawVk;
+        webview_functor_callbacks.vk.postDraw = &postDrawVk;
+        // TODO(boliu): Remove this once SkiaRecordingCanvas::drawWebViewFunctor
+        // no longer uses GL interop.
+        webview_functor_callbacks.gles.draw = &draw_gl;
+        break;
+    }
+    callbacks_initialized = true;
+  }
+  SupportData* support = new SupportData{
+      .data = data,
+      .callbacks = *functor_callbacks,
+  };
+  int functor = uirenderer::WebViewFunctor_create(
+      support, webview_functor_callbacks,
+      uirenderer::WebViewFunctor_queryPlatformRenderMode());
+  if (functor <= 0) delete support;
+  return functor;
+}
+
+void ReleaseFunctor(int functor) {
+  uirenderer::WebViewFunctor_release(functor);
+}
+
+AwDrawFnRenderMode QueryRenderMode(void) {
+  switch (uirenderer::WebViewFunctor_queryPlatformRenderMode()) {
+    case uirenderer::RenderMode::OpenGL_ES:
+      return AW_DRAW_FN_RENDER_MODE_OPENGL_ES;
+    case uirenderer::RenderMode::Vulkan:
+      return AW_DRAW_FN_RENDER_MODE_VULKAN;
+  }
+}
+
+jlong GetDrawFnFunctionTable() {
+  static AwDrawFnFunctionTable function_table = {
+    .version = kAwDrawFnVersion,
+    .query_render_mode = &QueryRenderMode,
+    .create_functor = &CreateFunctor,
+    .release_functor = &ReleaseFunctor,
+  };
+  return reinterpret_cast<intptr_t>(&function_table);
+}
+
+const char kClassName[] = "com/android/webview/chromium/DrawFunctor";
+const JNINativeMethod kJniMethods[] = {
+    {"nativeGetFunctionTable", "()J",
+     reinterpret_cast<void*>(GetDrawFnFunctionTable)},
+};
+
+}  // namespace
+
+void RegisterDrawFunctor(JNIEnv* env) {
+  jclass clazz = env->FindClass(kClassName);
+  LOG_ALWAYS_FATAL_IF(!clazz, "Unable to find class '%s'", kClassName);
+
+  int res = env->RegisterNatives(clazz, kJniMethods, NELEM(kJniMethods));
+  LOG_ALWAYS_FATAL_IF(res < 0, "register native methods failed: res=%d", res);
+}
+
+}  // namespace android
diff --git a/native/webview/plat_support/draw_vk.h b/native/webview/plat_support/draw_vk.h
deleted file mode 100644
index 6b7d8d0..0000000
--- a/native/webview/plat_support/draw_vk.h
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-//******************************************************************************
-// This is a copy of the coresponding android_webview/public/browser header.
-// Any changes to the interface should be made there.
-//
-// The purpose of having the copy is twofold:
-//  - it removes the need to have Chromium sources present in the tree in order
-//    to build the plat_support library,
-//  - it captures API that the corresponding Android release supports.
-//******************************************************************************
-
-#ifndef ANDROID_WEBVIEW_PUBLIC_BROWSER_DRAW_VK_H_
-#define ANDROID_WEBVIEW_PUBLIC_BROWSER_DRAW_VK_H_
-
-#include <vulkan/vulkan.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-static const int kAwDrawVKInfoVersion = 1;
-
-// Holds the information required to trigger initialization of the Vulkan
-// functor.
-struct InitParams {
-  // All params are input
-  VkInstance instance;
-  VkPhysicalDevice physical_device;
-  VkDevice device;
-  VkQueue queue;
-  uint32_t graphics_queue_index;
-  uint32_t instance_version;
-  const char* const* enabled_extension_names;
-  // Only one of device_features and device_features_2 should be non-null.
-  // If both are null then no features are enabled.
-  VkPhysicalDeviceFeatures* device_features;
-  VkPhysicalDeviceFeatures2* device_features_2;
-};
-
-// Holds the information required to trigger an Vulkan composite operation.
-struct CompositeParams {
-  // Input: current width/height of destination surface.
-  int width;
-  int height;
-
-  // Input: is the render target a FBO
-  bool is_layer;
-
-  // Input: current transform matrix
-  float transform[16];
-
-  // Input WebView should do its main compositing draws into this. It cannot do
-  // anything that would require stopping the render pass.
-  VkCommandBuffer secondary_command_buffer;
-
-  // Input: The main color attachment index where secondary_command_buffer will
-  // eventually be submitted.
-  uint32_t color_attachment_index;
-
-  // Input: A render pass which will be compatible to the one which the
-  // secondary_command_buffer will be submitted into.
-  VkRenderPass compatible_render_pass;
-
-  // Input: Format of the destination surface.
-  VkFormat format;
-
-  // Input: Color space transfer params
-  float G;
-  float A;
-  float B;
-  float C;
-  float D;
-  float E;
-  float F;
-
-  // Input: Color space transformation from linear RGB to D50-adapted XYZ
-  float matrix[9];
-
-  // Input: current clip rect
-  int clip_left;
-  int clip_top;
-  int clip_right;
-  int clip_bottom;
-};
-
-// Holds the information for the post-submission callback of main composite
-// draw.
-struct PostCompositeParams {
-  // Input: Fence for the composite command buffer to signal it has finished its
-  // work on the GPU.
-  int fd;
-};
-
-// Holds the information required to trigger an Vulkan operation.
-struct AwDrawVKInfo {
-  int version;  // The AwDrawVKInfo this struct was built with.
-
-  // Input: tells the draw function what action to perform.
-  enum Mode {
-    kModeInit = 0,
-    kModeReInit = 1,
-    kModePreComposite = 2,
-    kModeComposite = 3,
-    kModePostComposite = 4,
-    kModeSync = 5,
-  } mode;
-
-  // Input: The parameters for the functor being called
-  union ParamUnion {
-    struct InitParams init_params;
-    struct CompositeParams composite_params;
-    struct PostCompositeParams post_composite_params;
-  } info;
-};
-
-typedef void(AwDrawVKFunction)(long view_context, AwDrawVKInfo* draw_info);
-
-#ifdef __cplusplus
-}  // extern "C"
-#endif
-
-#endif  // ANDROID_WEBVIEW_PUBLIC_BROWSER_DRAW_VK_H_
diff --git a/native/webview/plat_support/draw_vk_functor.cpp b/native/webview/plat_support/draw_vk_functor.cpp
deleted file mode 100644
index eab1340..0000000
--- a/native/webview/plat_support/draw_vk_functor.cpp
+++ /dev/null
@@ -1,142 +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.
- */
-
-// Provides a webviewchromium glue layer adapter from the internal Android
-// Vulkan Functor data types into the types the chromium stack expects, and
-// back.
-
-#define LOG_TAG "webviewchromium_plat_support"
-
-#include "draw_fn.h"
-#include "draw_vk.h"
-
-#include <jni.h>
-#include <private/hwui/DrawVkInfo.h>
-#include <utils/Functor.h>
-#include <utils/Log.h>
-
-#include "functor_utils.h"
-
-#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
-
-namespace android {
-namespace {
-
-AwDrawVKFunction* g_aw_drawvk_function = NULL;
-
-class DrawVKFunctor : public Functor {
- public:
-  explicit DrawVKFunctor(jlong view_context) : view_context_(view_context) {}
-  ~DrawVKFunctor() override {}
-
-  // Functor
-  status_t operator ()(int what, void* data) override {
-    using uirenderer::DrawVkInfo;
-    if (!g_aw_drawvk_function) {
-      ALOGE("Cannot draw: no DrawVK Function installed");
-      return DrawVkInfo::kStatusDone;
-    }
-
-    AwDrawVKInfo aw_info;
-    aw_info.version = kAwDrawVKInfoVersion;
-    switch (what) {
-      case DrawVkInfo::kModeComposite: {
-        aw_info.mode = AwDrawVKInfo::kModeComposite;
-        DrawVkInfo* vk_info = reinterpret_cast<DrawVkInfo*>(data);
-
-        // Map across the input values.
-        CompositeParams& params = aw_info.info.composite_params;
-        params.width = vk_info->width;
-        params.height = vk_info->height;
-        params.is_layer = vk_info->isLayer;
-        for (size_t i = 0; i < 16; i++) {
-            params.transform[i] = vk_info->transform[i];
-        }
-        params.secondary_command_buffer = vk_info->secondaryCommandBuffer;
-        params.color_attachment_index = vk_info->colorAttachmentIndex;
-        params.compatible_render_pass = vk_info->compatibleRenderPass;
-        params.format = vk_info->format;
-        params.G = vk_info->G;
-        params.A = vk_info->A;
-        params.B = vk_info->B;
-        params.C = vk_info->C;
-        params.D = vk_info->D;
-        params.E = vk_info->E;
-        params.F = vk_info->F;
-        for (size_t i = 0; i < 9; i++) {
-            params.matrix[i] = vk_info->matrix[i];
-        }
-        params.clip_left = vk_info->clipLeft;
-        params.clip_top = vk_info->clipTop;
-        params.clip_right = vk_info->clipRight;
-        params.clip_bottom = vk_info->clipBottom;
-
-        break;
-      }
-      case DrawVkInfo::kModePostComposite:
-        break;
-      case DrawVkInfo::kModeSync:
-        aw_info.mode = AwDrawVKInfo::kModeSync;
-        break;
-      default:
-        ALOGE("Unexpected DrawVKInfo type %d", what);
-        return DrawVkInfo::kStatusDone;
-    }
-
-    // Invoke the DrawVK method.
-    g_aw_drawvk_function(view_context_, &aw_info);
-
-    return DrawVkInfo::kStatusDone;
-  }
-
- private:
-  intptr_t view_context_;
-};
-
-jlong CreateVKFunctor(JNIEnv*, jclass, jlong view_context) {
-  RaiseFileNumberLimit();
-  return reinterpret_cast<jlong>(new DrawVKFunctor(view_context));
-}
-
-void DestroyVKFunctor(JNIEnv*, jclass, jlong functor) {
-  delete reinterpret_cast<DrawVKFunctor*>(functor);
-}
-
-void SetChromiumAwDrawVKFunction(JNIEnv*, jclass, jlong draw_function) {
-  g_aw_drawvk_function = reinterpret_cast<AwDrawVKFunction*>(draw_function);
-}
-
-const char kClassName[] = "com/android/webview/chromium/DrawVKFunctor";
-const JNINativeMethod kJniMethods[] = {
-    { "nativeCreateVKFunctor", "(J)J",
-        reinterpret_cast<void*>(CreateVKFunctor) },
-    { "nativeDestroyVKFunctor", "(J)V",
-        reinterpret_cast<void*>(DestroyVKFunctor) },
-    { "nativeSetChromiumAwDrawVKFunction", "(J)V",
-        reinterpret_cast<void*>(SetChromiumAwDrawVKFunction) },
-};
-
-}  // namespace
-
-void RegisterDrawVKFunctor(JNIEnv* env) {
-  jclass clazz = env->FindClass(kClassName);
-  LOG_ALWAYS_FATAL_IF(!clazz, "Unable to find class '%s'", kClassName);
-
-  int res = env->RegisterNatives(clazz, kJniMethods, NELEM(kJniMethods));
-  LOG_ALWAYS_FATAL_IF(res < 0, "register native methods failed: res=%d", res);
-}
-
-}  // namespace android
diff --git a/native/webview/plat_support/jni_entry_point.cpp b/native/webview/plat_support/jni_entry_point.cpp
index 4771be1..9599fa6 100644
--- a/native/webview/plat_support/jni_entry_point.cpp
+++ b/native/webview/plat_support/jni_entry_point.cpp
@@ -21,6 +21,7 @@
 
 namespace android {
 
+void RegisterDrawFunctor(JNIEnv* env);
 void RegisterDrawGLFunctor(JNIEnv* env);
 void RegisterGraphicsUtils(JNIEnv* env);
 
@@ -30,6 +31,7 @@
   JNIEnv* env = NULL;
   jint ret = vm->AttachCurrentThread(&env, NULL);
   LOG_ALWAYS_FATAL_IF(ret != JNI_OK, "AttachCurrentThread failed");
+  android::RegisterDrawFunctor(env);
   android::RegisterDrawGLFunctor(env);
   android::RegisterGraphicsUtils(env);
 
diff --git a/nfc-extras/api/current.txt b/nfc-extras/api/current.txt
index 066b7b5..47ccddf 100644
--- a/nfc-extras/api/current.txt
+++ b/nfc-extras/api/current.txt
@@ -1,44 +1,45 @@
+// Signature format: 2.0
 package com.android.nfc_extras {
 
   public class EeAlreadyOpenException extends com.android.nfc_extras.EeIOException {
     ctor public EeAlreadyOpenException();
-    ctor public EeAlreadyOpenException(java.lang.String);
+    ctor public EeAlreadyOpenException(String);
   }
 
   public class EeExternalFieldException extends com.android.nfc_extras.EeIOException {
     ctor public EeExternalFieldException();
-    ctor public EeExternalFieldException(java.lang.String);
+    ctor public EeExternalFieldException(String);
   }
 
   public class EeIOException extends java.io.IOException {
     ctor public EeIOException();
-    ctor public EeIOException(java.lang.String);
+    ctor public EeIOException(String);
   }
 
   public class EeInitializationException extends com.android.nfc_extras.EeIOException {
     ctor public EeInitializationException();
-    ctor public EeInitializationException(java.lang.String);
+    ctor public EeInitializationException(String);
   }
 
   public class EeListenModeException extends com.android.nfc_extras.EeIOException {
     ctor public EeListenModeException();
-    ctor public EeListenModeException(java.lang.String);
+    ctor public EeListenModeException(String);
   }
 
   public class EeNfcDisabledException extends com.android.nfc_extras.EeIOException {
     ctor public EeNfcDisabledException();
-    ctor public EeNfcDisabledException(java.lang.String);
+    ctor public EeNfcDisabledException(String);
   }
 
   public final class NfcAdapterExtras {
     method public void authenticate(byte[]);
     method public static com.android.nfc_extras.NfcAdapterExtras get(android.nfc.NfcAdapter);
     method public com.android.nfc_extras.NfcAdapterExtras.CardEmulationRoute getCardEmulationRoute();
-    method public java.lang.String getDriverName();
+    method public String getDriverName();
     method public com.android.nfc_extras.NfcExecutionEnvironment getEmbeddedExecutionEnvironment();
     method public void setCardEmulationRoute(com.android.nfc_extras.NfcAdapterExtras.CardEmulationRoute);
-    field public static final java.lang.String ACTION_RF_FIELD_OFF_DETECTED = "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
-    field public static final java.lang.String ACTION_RF_FIELD_ON_DETECTED = "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
+    field public static final String ACTION_RF_FIELD_OFF_DETECTED = "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
+    field public static final String ACTION_RF_FIELD_ON_DETECTED = "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
   }
 
   public static final class NfcAdapterExtras.CardEmulationRoute {
@@ -53,7 +54,7 @@
     method public void close() throws java.io.IOException;
     method public void open() throws com.android.nfc_extras.EeIOException;
     method public byte[] transceive(byte[]) throws java.io.IOException;
-    field public static final java.lang.String ACTION_AID_SELECTED = "com.android.nfc_extras.action.AID_SELECTED";
+    field public static final String ACTION_AID_SELECTED = "com.android.nfc_extras.action.AID_SELECTED";
   }
 
 }
diff --git a/nfc-extras/api/removed.txt b/nfc-extras/api/removed.txt
index e69de29..d802177 100644
--- a/nfc-extras/api/removed.txt
+++ b/nfc-extras/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/nfc-extras/api/system-current.txt b/nfc-extras/api/system-current.txt
index e69de29..d802177 100644
--- a/nfc-extras/api/system-current.txt
+++ b/nfc-extras/api/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/nfc-extras/api/system-removed.txt b/nfc-extras/api/system-removed.txt
index e69de29..d802177 100644
--- a/nfc-extras/api/system-removed.txt
+++ b/nfc-extras/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/nfc-extras/api/test-current.txt b/nfc-extras/api/test-current.txt
index e69de29..d802177 100644
--- a/nfc-extras/api/test-current.txt
+++ b/nfc-extras/api/test-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/nfc-extras/api/test-removed.txt b/nfc-extras/api/test-removed.txt
index e69de29..d802177 100644
--- a/nfc-extras/api/test-removed.txt
+++ b/nfc-extras/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/obex/api/current.txt b/obex/api/current.txt
index 1cd562f..f142bc8 100644
--- a/obex/api/current.txt
+++ b/obex/api/current.txt
@@ -1,3 +1,4 @@
+// Signature format: 2.0
 package javax.obex {
 
   public class ObexPacket {
diff --git a/obex/api/removed.txt b/obex/api/removed.txt
index e69de29..d802177 100644
--- a/obex/api/removed.txt
+++ b/obex/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/obex/api/system-current.txt b/obex/api/system-current.txt
index e69de29..d802177 100644
--- a/obex/api/system-current.txt
+++ b/obex/api/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/obex/api/system-removed.txt b/obex/api/system-removed.txt
index e69de29..d802177 100644
--- a/obex/api/system-removed.txt
+++ b/obex/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/obex/api/test-current.txt b/obex/api/test-current.txt
index e69de29..d802177 100644
--- a/obex/api/test-current.txt
+++ b/obex/api/test-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/obex/api/test-removed.txt b/obex/api/test-removed.txt
index e69de29..d802177 100644
--- a/obex/api/test-removed.txt
+++ b/obex/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/packages/AppPredictionLib/Android.bp b/packages/AppPredictionLib/Android.bp
new file mode 100644
index 0000000..e0f4ded
--- /dev/null
+++ b/packages/AppPredictionLib/Android.bp
@@ -0,0 +1,24 @@
+// 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.
+
+android_library {
+    name: "app_prediction",
+
+    sdk_version: "system_current",
+    min_sdk_version: "system_current",
+
+    srcs: [
+        "src/**/*.java",
+    ],
+}
diff --git a/packages/AppPredictionLib/AndroidManifest.xml b/packages/AppPredictionLib/AndroidManifest.xml
new file mode 100644
index 0000000..b992788
--- /dev/null
+++ b/packages/AppPredictionLib/AndroidManifest.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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.app.prediction">
+</manifest>
diff --git a/packages/AppPredictionLib/src/com/android/app/prediction/Constants.java b/packages/AppPredictionLib/src/com/android/app/prediction/Constants.java
new file mode 100644
index 0000000..0993c9a
--- /dev/null
+++ b/packages/AppPredictionLib/src/com/android/app/prediction/Constants.java
@@ -0,0 +1,71 @@
+/*
+ * 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.app.prediction;
+
+/**
+ * Constants to be used with {@link android.app.prediction.AppPredictor}.
+ */
+public class Constants {
+
+    /**
+     * UI surface for predictions displayed on the user's home screen
+     */
+    public static final String UI_SURFACE_HOME = "home";
+
+    /**
+     * UI surface for predictions displayed on the recents/task switcher view
+     */
+    public static final String UI_SURFACE_RECENTS = "recents";
+
+    /**
+     * UI surface for predictions displayed on the share sheet.
+     */
+    public static final String UI_SURFACE_SHARE = "share";
+
+    /**
+     * Location constant when an app target or shortcut is started from the apps list
+     */
+    public static final String LAUNCH_LOCATION_APPS_LIST = "apps_list";
+
+    /**
+     * Location constant when an app target or shortcut is started from the user's home screen
+     */
+    public static final String LAUNCH_LOCATION_APPS_HOME = "home";
+
+    /**
+     * Location constant when an app target or shortcut is started from task switcher
+     */
+    public static final String LAUNCH_LOCATION_APPS_RECENTS = "recents";
+
+    /**
+     * Location constant when an app target or shortcut is started in the share sheet while it is
+     * in collapsed state (showing a limited set of result).
+     */
+    public static final String LAUNCH_LOCATION_APPS_SHARE_COLLAPSED = "share_collapsed";
+
+    /**
+     * Location constant when an app target or shortcut is started in the share sheet while it is
+     * in expended state and showing all the results.
+     */
+    public static final String LAUNCH_LOCATION_APPS_SHARE_EXPANDED = "shared_expanded";
+
+    /**
+     * Location constant when an app target or shortcut is started in the share sheet when the
+     * target is displayed as a placeholder for an deprecated object.
+     */
+    public static final String LAUNCH_LOCATION_APPS_SHARE_LEGACY = "share_legacy";
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
index 3c0a297..0c35204 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
@@ -20,11 +20,9 @@
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.car.CarNotificationEntryManager;
 import com.android.systemui.car.CarNotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.car.CarFacetButtonController;
 import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.volume.CarVolumeDialogComponent;
@@ -65,16 +63,16 @@
     }
 
     @Override
-    public NotificationEntryManager provideNotificationEntryManager(Context context) {
-        return new CarNotificationEntryManager(context);
-    }
-
-    @Override
     public NotificationInterruptionStateProvider provideNotificationInterruptionStateProvider(
             Context context) {
         return new CarNotificationInterruptionStateProvider(context);
     }
 
+    @Override
+    public boolean provideAllowNotificationLongPress() {
+        return false;
+    }
+
     @Module
     protected static class ContextHolder {
         private Context mContext;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
deleted file mode 100644
index 323cae0..0000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.car;
-
-import android.content.Context;
-
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-
-public class CarNotificationEntryManager extends NotificationEntryManager {
-    public CarNotificationEntryManager(Context context) {
-        super(context);
-    }
-
-    /**
-     * Returns the
-     * {@link ExpandableNotificationRow.LongPressListener} that will
-     * be triggered when a notification card is long-pressed.
-     */
-    @Override
-    public ExpandableNotificationRow.LongPressListener getNotificationLongClicker() {
-        // For the automative use case, we do not want to the user to be able to interact with
-        // a notification other than a regular click. As a result, just return null for the
-        // long click listener.
-        return null;
-    }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
index 62502ef..6d960d7 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
@@ -18,8 +18,8 @@
 
 import android.content.Context;
 
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 /** Auto-specific implementation of {@link NotificationInterruptionStateProvider}. */
 public class CarNotificationInterruptionStateProvider extends
@@ -29,7 +29,7 @@
     }
 
     @Override
-    public boolean shouldHeadsUp(NotificationData.Entry entry) {
+    public boolean shouldHeadsUp(NotificationEntry 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.
diff --git a/packages/CarrierDefaultApp/tests/unit/Android.mk b/packages/CarrierDefaultApp/tests/unit/Android.mk
index 8e3785e..4c638811 100644
--- a/packages/CarrierDefaultApp/tests/unit/Android.mk
+++ b/packages/CarrierDefaultApp/tests/unit/Android.mk
@@ -21,7 +21,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.test.base
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target-minus-junit4
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules mockito-target-minus-junit4
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/packages/CarrierDefaultApp/tests/unit/AndroidManifest.xml b/packages/CarrierDefaultApp/tests/unit/AndroidManifest.xml
index 3a06a09..7a26d95 100644
--- a/packages/CarrierDefaultApp/tests/unit/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/tests/unit/AndroidManifest.xml
@@ -21,7 +21,7 @@
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.carrierdefaultapp"
         android:label="CarrierDefaultApp Unit Test Cases">
     </instrumentation>
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index af52c00..f346b00 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -286,6 +286,9 @@
             if (!isForCurrentUser(sbn)) {
                 return;
             }
+
+            mAgingHelper.onNotificationRemoved(sbn.getKey());
+
             boolean updatedImpressions = false;
             String channelId = mLiveNotifications.remove(sbn.getKey()).getChannel().getId();
             String key = getKey(sbn.getPackageName(), sbn.getUserId(), channelId);
@@ -341,7 +344,6 @@
                 if (entry != null) {
                     entry.setSeen();
                     mAgingHelper.onNotificationSeen(entry);
-                    mSmartActionsHelper.onNotificationSeen(entry);
                 }
             }
         } catch (Throwable e) {
@@ -366,9 +368,9 @@
     }
 
     @Override
-    public void onNotificationDirectReply(@NonNull String key) {
-        if (DEBUG) Log.i(TAG, "onNotificationDirectReply " + key);
-        mSmartActionsHelper.onNotificationDirectReply(key);
+    public void onNotificationDirectReplied(@NonNull String key) {
+        if (DEBUG) Log.i(TAG, "onNotificationDirectReplied " + key);
+        mSmartActionsHelper.onNotificationDirectReplied(key);
     }
 
     @Override
@@ -382,11 +384,11 @@
     }
 
     @Override
-    public void onActionClicked(@NonNull String key, @NonNull Notification.Action action,
+    public void onActionInvoked(@NonNull String key, @NonNull Notification.Action action,
             @Source int source) {
         if (DEBUG) {
             Log.d(TAG,
-                    "onActionClicked() called with: key = [" + key + "], action = [" + action.title
+                    "onActionInvoked() called with: key = [" + key + "], action = [" + action.title
                             + "], source = [" + source + "]");
         }
         mSmartActionsHelper.onActionClicked(key, action, source);
diff --git a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
index 39a1676..406b44d 100644
--- a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
+++ b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
@@ -20,8 +20,11 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.KeyValueListParser;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -29,6 +32,7 @@
  * Observes the settings for {@link Assistant}.
  */
 final class AssistantSettings extends ContentObserver {
+    private static final String LOG_TAG = "AssistantSettings";
     public static Factory FACTORY = AssistantSettings::createAndRegister;
     private static final boolean DEFAULT_GENERATE_REPLIES = true;
     private static final boolean DEFAULT_GENERATE_ACTIONS = true;
@@ -39,19 +43,33 @@
     private static final Uri DISMISS_TO_VIEW_RATIO_LIMIT_URI =
             Settings.Global.getUriFor(
                     Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT);
-    private static final Uri SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS_URI =
-            Settings.Global.getUriFor(
-                    Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS);
     private static final Uri NOTIFICATION_NEW_INTERRUPTION_MODEL_URI =
             Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL);
 
-    private static final String KEY_GENERATE_REPLIES = "generate_replies";
-    private static final String KEY_GENERATE_ACTIONS = "generate_actions";
+    /**
+     * Flag determining whether the Notification Assistant should generate replies for
+     * notifications.
+     * <p>
+     * This flag belongs to the namespace: {@link DeviceConfig#NAMESPACE_NOTIFICATION_ASSISTANT}.
+     */
+    @VisibleForTesting
+    static final String KEY_GENERATE_REPLIES = "notification_assistant_generate_replies";
+
+    /**
+     * Flag determining whether the Notification Assistant should generate contextual actions in
+     * notifications.
+     * <p>
+     * This flag belongs to the namespace: {@link DeviceConfig#NAMESPACE_NOTIFICATION_ASSISTANT}.
+     */
+    @VisibleForTesting
+    static final String KEY_GENERATE_ACTIONS = "notification_assistant_generate_actions";
 
     private final KeyValueListParser mParser = new KeyValueListParser(',');
     private final ContentResolver mResolver;
     private final int mUserId;
 
+    private final Handler mHandler;
+
     @VisibleForTesting
     protected final Runnable mOnUpdateRunnable;
 
@@ -65,6 +83,7 @@
     private AssistantSettings(Handler handler, ContentResolver resolver, int userId,
             Runnable onUpdateRunnable) {
         super(handler);
+        mHandler = handler;
         mResolver = resolver;
         mUserId = userId;
         mOnUpdateRunnable = onUpdateRunnable;
@@ -75,6 +94,7 @@
         AssistantSettings assistantSettings =
                 new AssistantSettings(handler, resolver, userId, onUpdateRunnable);
         assistantSettings.register();
+        assistantSettings.registerDeviceConfigs();
         return assistantSettings;
     }
 
@@ -91,13 +111,62 @@
         mResolver.registerContentObserver(
                 DISMISS_TO_VIEW_RATIO_LIMIT_URI, false, this, mUserId);
         mResolver.registerContentObserver(STREAK_LIMIT_URI, false, this, mUserId);
-        mResolver.registerContentObserver(
-                SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS_URI, false, this, mUserId);
 
         // Update all uris on creation.
         update(null);
     }
 
+    private void registerDeviceConfigs() {
+        DeviceConfig.addOnPropertyChangedListener(
+                DeviceConfig.NAMESPACE_NOTIFICATION_ASSISTANT,
+                this::postToHandler,
+                this::onDeviceConfigPropertyChanged);
+
+        // Update the fields in this class from the current state of the device config.
+        updateFromDeviceConfigFlags();
+    }
+
+    private void postToHandler(Runnable r) {
+        this.mHandler.post(r);
+    }
+
+    @VisibleForTesting
+    void onDeviceConfigPropertyChanged(String namespace, String name, String value) {
+        if (!DeviceConfig.NAMESPACE_NOTIFICATION_ASSISTANT.equals(namespace)) {
+            Log.e(LOG_TAG, "Received update from DeviceConfig for unrelated namespace: "
+                    + namespace + " " + name + "=" + value);
+            return;
+        }
+
+        updateFromDeviceConfigFlags();
+    }
+
+    private void updateFromDeviceConfigFlags() {
+        String generateRepliesFlag = DeviceConfig.getProperty(
+                DeviceConfig.NAMESPACE_NOTIFICATION_ASSISTANT,
+                KEY_GENERATE_REPLIES);
+        if (TextUtils.isEmpty(generateRepliesFlag)) {
+            mGenerateReplies = DEFAULT_GENERATE_REPLIES;
+        } else {
+            // parseBoolean returns false for everything that isn't 'true' so there's no need to
+            // sanitise the flag string here.
+            mGenerateReplies = Boolean.parseBoolean(generateRepliesFlag);
+        }
+
+        String generateActionsFlag = DeviceConfig.getProperty(
+                DeviceConfig.NAMESPACE_NOTIFICATION_ASSISTANT,
+                KEY_GENERATE_ACTIONS);
+        if (TextUtils.isEmpty(generateActionsFlag)) {
+            mGenerateActions = DEFAULT_GENERATE_ACTIONS;
+        } else {
+            // parseBoolean returns false for everything that isn't 'true' so there's no need to
+            // sanitise the flag string here.
+            mGenerateActions = Boolean.parseBoolean(generateActionsFlag);
+        }
+
+        mOnUpdateRunnable.run();
+    }
+
     @Override
     public void onChange(boolean selfChange, Uri uri) {
         update(uri);
@@ -114,15 +183,6 @@
                     mResolver, Settings.Global.BLOCKING_HELPER_STREAK_LIMIT,
                     ChannelImpressions.DEFAULT_STREAK_LIMIT);
         }
-        if (uri == null || SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS_URI.equals(uri)) {
-            mParser.setString(
-                    Settings.Global.getString(mResolver,
-                            Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS));
-            mGenerateReplies =
-                    mParser.getBoolean(KEY_GENERATE_REPLIES, DEFAULT_GENERATE_REPLIES);
-            mGenerateActions =
-                    mParser.getBoolean(KEY_GENERATE_ACTIONS, DEFAULT_GENERATE_ACTIONS);
-        }
         if (uri == null || NOTIFICATION_NEW_INTERRUPTION_MODEL_URI.equals(uri)) {
             int mNewInterruptionModelInt = Settings.Secure.getInt(
                     mResolver, Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL,
diff --git a/packages/ExtServices/src/android/ext/services/notification/EntityTypeCounter.java b/packages/ExtServices/src/android/ext/services/notification/EntityTypeCounter.java
new file mode 100644
index 0000000..50cb0ab
--- /dev/null
+++ b/packages/ExtServices/src/android/ext/services/notification/EntityTypeCounter.java
@@ -0,0 +1,73 @@
+/**
+ * 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.ext.services.notification;
+
+import android.annotation.NonNull;
+import android.util.ArrayMap;
+import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextLinks;
+
+/**
+ * Counts the entity types for smart actions. Some entity types are considered the same
+ * type, like {@link TextClassifier#TYPE_DATE} and {@link TextClassifier#TYPE_DATE_TIME}.
+ */
+class EntityTypeCounter {
+
+    private static final ArrayMap<String, String> ENTITY_TYPE_MAPPING = new ArrayMap<>();
+
+    static {
+        ENTITY_TYPE_MAPPING.put(TextClassifier.TYPE_DATE_TIME, TextClassifier.TYPE_DATE);
+    }
+
+    private final ArrayMap<String, Integer> mEntityTypeCount = new ArrayMap<>();
+
+
+    void increment(@NonNull String entityType) {
+        entityType = convertToBaseEntityType(entityType);
+        if (mEntityTypeCount.containsKey(entityType)) {
+            mEntityTypeCount.put(entityType, mEntityTypeCount.get(entityType) + 1);
+        } else {
+            mEntityTypeCount.put(entityType, 1);
+        }
+    }
+
+    int getCount(@NonNull String entityType) {
+        entityType = convertToBaseEntityType(entityType);
+        return mEntityTypeCount.getOrDefault(entityType, 0);
+    }
+
+    @NonNull
+    private String convertToBaseEntityType(@NonNull String entityType) {
+        return ENTITY_TYPE_MAPPING.getOrDefault(entityType, entityType);
+    }
+
+    /**
+     * Given the links extracted from a piece of text, returns the frequency of each entity
+     * type.
+     */
+    @NonNull
+    static EntityTypeCounter fromTextLinks(@NonNull TextLinks links) {
+        EntityTypeCounter counter = new EntityTypeCounter();
+        for (TextLinks.TextLink link : links.getLinks()) {
+            if (link.getEntityCount() == 0) {
+                continue;
+            }
+            String entityType = link.getEntity(0);
+            counter.increment(entityType);
+        }
+        return counter;
+    }
+}
diff --git a/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java b/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
index 71fd9ce..ce2c409 100644
--- a/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
+++ b/packages/ExtServices/src/android/ext/services/notification/NotificationEntry.java
@@ -27,7 +27,9 @@
 import android.app.NotificationChannel;
 import android.app.Person;
 import android.app.RemoteInput;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
 import android.media.AudioAttributes;
 import android.media.AudioSystem;
 import android.os.Build;
@@ -67,8 +69,12 @@
 
     private boolean isPreChannelsNotification() {
         try {
-            mTargetSdkVersion = mPackageManager.getApplicationInfo(
-                    mSbn.getPackageName(), 0, mSbn.getUserId()).targetSdkVersion;
+            ApplicationInfo info = mPackageManager.getApplicationInfo(
+                    mSbn.getPackageName(), PackageManager.MATCH_ALL,
+                    mSbn.getUserId());
+            if (info != null) {
+                mTargetSdkVersion = info.targetSdkVersion;
+            }
         } catch (RemoteException e) {
             Log.w(TAG, "Couldn't look up " + mSbn.getPackageName());
         }
@@ -230,10 +236,6 @@
         return mSeen;
     }
 
-    public boolean isExpanded() {
-        return mExpanded;
-    }
-
     public boolean isShowActionEventLogged() {
         return mIsShowActionEventLogged;
     }
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index b041842..0d528e7 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -26,8 +26,8 @@
 import android.os.Process;
 import android.service.notification.NotificationAssistantService;
 import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.LruCache;
+import android.view.textclassifier.ConversationAction;
 import android.view.textclassifier.ConversationActions;
 import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextClassificationContext;
@@ -66,13 +66,13 @@
     private static final int MAX_MESSAGES_TO_EXTRACT = 5;
     private static final int MAX_RESULT_ID_TO_CACHE = 20;
 
-    private static final ConversationActions.TypeConfig TYPE_CONFIG =
-            new ConversationActions.TypeConfig.Builder().setIncludedTypes(
-                    Collections.singletonList(ConversationActions.TYPE_TEXT_REPLY))
+    private static final TextClassifier.EntityConfig TYPE_CONFIG =
+            new TextClassifier.EntityConfig.Builder().setIncludedTypes(
+                    Collections.singletonList(ConversationAction.TYPE_TEXT_REPLY))
                     .includeTypesFromTextClassifier(false)
                     .build();
     private static final List<String> HINTS =
-            Collections.singletonList(ConversationActions.HINT_FOR_NOTIFICATION);
+            Collections.singletonList(ConversationActions.Request.HINT_FOR_NOTIFICATION);
 
     private Context mContext;
     @Nullable
@@ -138,7 +138,7 @@
 
         ConversationActions conversationActionsResult =
                 mTextClassifier.suggestConversationActions(request);
-        List<ConversationActions.ConversationAction> conversationActions =
+        List<ConversationAction> conversationActions =
                 conversationActionsResult.getConversationActions();
         ArrayList<CharSequence> replies = conversationActions.stream()
                 .map(conversationAction -> conversationAction.getTextReply())
@@ -152,21 +152,29 @@
         return replies;
     }
 
-    void onNotificationSeen(@NonNull NotificationEntry entry) {
-        if (entry.isExpanded()) {
-            maybeSendActionShownEvent(entry);
-        }
-    }
-
     void onNotificationExpansionChanged(@NonNull NotificationEntry entry, boolean isUserAction,
             boolean isExpanded) {
-        // Notification can be expanded in the background, and thus the isUserAction check.
-        if (isUserAction && isExpanded) {
-            maybeSendActionShownEvent(entry);
+        if (!isExpanded) {
+            return;
         }
+        String resultId = mNotificationKeyToResultIdCache.get(entry.getSbn().getKey());
+        if (resultId == null) {
+            return;
+        }
+        // Only report if this is the first time the user sees these suggestions.
+        if (entry.isShowActionEventLogged()) {
+            return;
+        }
+        entry.setShowActionEventLogged();
+        TextClassifierEvent textClassifierEvent =
+                createTextClassifierEventBuilder(TextClassifierEvent.TYPE_ACTIONS_SHOWN,
+                        resultId)
+                        .build();
+        // TODO: If possible, report which replies / actions are actually seen by user.
+        mTextClassifier.onTextClassifierEvent(textClassifierEvent);
     }
 
-    void onNotificationDirectReply(@NonNull String key) {
+    void onNotificationDirectReplied(@NonNull String key) {
         if (mTextClassifier == null) {
             return;
         }
@@ -194,7 +202,7 @@
         }
         TextClassifierEvent textClassifierEvent =
                 createTextClassifierEventBuilder(TextClassifierEvent.TYPE_SMART_ACTION, resultId)
-                        .setEntityType(ConversationActions.TYPE_TEXT_REPLY)
+                        .setEntityType(ConversationAction.TYPE_TEXT_REPLY)
                         .build();
         mTextClassifier.onTextClassifierEvent(textClassifierEvent);
     }
@@ -234,26 +242,6 @@
                 .setResultId(resultId);
     }
 
-    private void maybeSendActionShownEvent(@NonNull NotificationEntry entry) {
-        if (mTextClassifier == null) {
-            return;
-        }
-        String resultId = mNotificationKeyToResultIdCache.get(entry.getSbn().getKey());
-        if (resultId == null) {
-            return;
-        }
-        // Only report if this is the first time the user sees these suggestions.
-        if (entry.isShowActionEventLogged()) {
-            return;
-        }
-        entry.setShowActionEventLogged();
-        TextClassifierEvent textClassifierEvent =
-                createTextClassifierEventBuilder(TextClassifierEvent.TYPE_ACTIONS_SHOWN, resultId)
-                        .build();
-        // TODO: If possible, report which replies / actions are actually seen by user.
-        mTextClassifier.onTextClassifierEvent(textClassifierEvent);
-    }
-
     /**
      * Returns whether a notification is eligible for action adjustments.
      *
@@ -356,7 +344,7 @@
                                         TextClassifier.HINT_TEXT_IS_NOT_EDITABLE)))
                 .build();
         TextLinks links = mTextClassifier.generateLinks(textLinksRequest);
-        ArrayMap<String, Integer> entityTypeFrequency = getEntityTypeFrequency(links);
+        EntityTypeCounter entityTypeCounter = EntityTypeCounter.fromTextLinks(links);
 
         ArrayList<Notification.Action> actions = new ArrayList<>();
         for (TextLinks.TextLink link : links.getLinks()) {
@@ -364,7 +352,7 @@
             // case where a notification contains e.g. a list of phone numbers. In such cases, the
             // user likely wants to act on the whole list rather than an individual entity.
             if (link.getEntityCount() == 0
-                    || entityTypeFrequency.get(link.getEntity(0)) != 1) {
+                    || entityTypeCounter.getCount(link.getEntity(0)) != 1) {
                 continue;
             }
 
@@ -384,8 +372,7 @@
                         remoteAction.getIcon(),
                         remoteAction.getTitle(),
                         remoteAction.getActionIntent())
-                        .setSemanticAction(
-                                Notification.Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION)
+                        .setContextual(true)
                         .addExtras(Bundle.forPair(KEY_ACTION_TYPE, classification.getEntity(0)))
                         .build();
                 actions.add(action);
@@ -398,25 +385,4 @@
         }
         return actions;
     }
-
-    /**
-     * Given the links extracted from a piece of text, returns the frequency of each entity
-     * type.
-     */
-    @NonNull
-    private ArrayMap<String, Integer> getEntityTypeFrequency(@NonNull TextLinks links) {
-        ArrayMap<String, Integer> entityTypeCount = new ArrayMap<>();
-        for (TextLinks.TextLink link : links.getLinks()) {
-            if (link.getEntityCount() == 0) {
-                continue;
-            }
-            String entityType = link.getEntity(0);
-            if (entityTypeCount.containsKey(entityType)) {
-                entityTypeCount.put(entityType, entityTypeCount.get(entityType) + 1);
-            } else {
-                entityTypeCount.put(entityType, 1);
-            }
-        }
-        return entityTypeCount;
-    }
 }
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
index fd23f2b..51b723d 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
@@ -26,6 +26,7 @@
 import android.content.ContentResolver;
 import android.os.Handler;
 import android.os.Looper;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
@@ -62,9 +63,6 @@
         Settings.Global.putFloat(mResolver,
                 Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT, 0.8f);
         Settings.Global.putInt(mResolver, Settings.Global.BLOCKING_HELPER_STREAK_LIMIT, 2);
-        Settings.Global.putString(mResolver,
-                Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
-                "generate_replies=true,generate_actions=true");
         Settings.Secure.putInt(mResolver, Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
 
         mAssistantSettings = AssistantSettings.createForTesting(
@@ -73,56 +71,78 @@
 
     @Test
     public void testGenerateRepliesDisabled() {
-        Settings.Global.putString(mResolver,
-                Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
-                "generate_replies=false");
-
-        // Notify for the settings values we updated.
-        mAssistantSettings.onChange(false,
-                Settings.Global.getUriFor(
-                        Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS));
-
+        mAssistantSettings.onDeviceConfigPropertyChanged(
+                DeviceConfig.NAMESPACE_NOTIFICATION_ASSISTANT,
+                AssistantSettings.KEY_GENERATE_REPLIES,
+                "false");
 
         assertFalse(mAssistantSettings.mGenerateReplies);
     }
 
     @Test
     public void testGenerateRepliesEnabled() {
-        Settings.Global.putString(mResolver,
-                Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS, "generate_replies=true");
+        mAssistantSettings.onDeviceConfigPropertyChanged(
+                DeviceConfig.NAMESPACE_NOTIFICATION_ASSISTANT,
+                AssistantSettings.KEY_GENERATE_REPLIES,
+                "true");
 
-        // Notify for the settings values we updated.
-        mAssistantSettings.onChange(false,
-                Settings.Global.getUriFor(
-                        Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS));
+        assertTrue(mAssistantSettings.mGenerateReplies);
+    }
 
+    @Test
+    public void testGenerateRepliesEmptyFlag() {
+        mAssistantSettings.onDeviceConfigPropertyChanged(
+                DeviceConfig.NAMESPACE_NOTIFICATION_ASSISTANT,
+                AssistantSettings.KEY_GENERATE_REPLIES,
+                "false");
+
+        assertFalse(mAssistantSettings.mGenerateReplies);
+
+        mAssistantSettings.onDeviceConfigPropertyChanged(
+                DeviceConfig.NAMESPACE_NOTIFICATION_ASSISTANT,
+                AssistantSettings.KEY_GENERATE_REPLIES,
+                "");
+
+        // Go back to the default value.
         assertTrue(mAssistantSettings.mGenerateReplies);
     }
 
     @Test
     public void testGenerateActionsDisabled() {
-        Settings.Global.putString(mResolver,
-                Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS, "generate_actions=false");
+        mAssistantSettings.onDeviceConfigPropertyChanged(
+                DeviceConfig.NAMESPACE_NOTIFICATION_ASSISTANT,
+                AssistantSettings.KEY_GENERATE_ACTIONS,
+                "false");
 
-        // Notify for the settings values we updated.
-        mAssistantSettings.onChange(false,
-                Settings.Global.getUriFor(
-                        Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS));
-
-        assertTrue(mAssistantSettings.mGenerateReplies);
+        assertFalse(mAssistantSettings.mGenerateActions);
     }
 
     @Test
     public void testGenerateActionsEnabled() {
-        Settings.Global.putString(mResolver,
-                Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS, "generate_actions=true");
+        mAssistantSettings.onDeviceConfigPropertyChanged(
+                DeviceConfig.NAMESPACE_NOTIFICATION_ASSISTANT,
+                AssistantSettings.KEY_GENERATE_ACTIONS,
+                "true");
 
-        // Notify for the settings values we updated.
-        mAssistantSettings.onChange(false,
-                Settings.Global.getUriFor(
-                        Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS));
+        assertTrue(mAssistantSettings.mGenerateActions);
+    }
 
-        assertTrue(mAssistantSettings.mGenerateReplies);
+    @Test
+    public void testGenerateActionsEmptyFlag() {
+        mAssistantSettings.onDeviceConfigPropertyChanged(
+                DeviceConfig.NAMESPACE_NOTIFICATION_ASSISTANT,
+                AssistantSettings.KEY_GENERATE_ACTIONS,
+                "false");
+
+        assertFalse(mAssistantSettings.mGenerateActions);
+
+        mAssistantSettings.onDeviceConfigPropertyChanged(
+                DeviceConfig.NAMESPACE_NOTIFICATION_ASSISTANT,
+                AssistantSettings.KEY_GENERATE_ACTIONS,
+                "");
+
+        // Go back to the default value.
+        assertTrue(mAssistantSettings.mGenerateActions);
     }
 
     @Test
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/EntityTypeCounterTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/EntityTypeCounterTest.java
new file mode 100644
index 0000000..2d29c7b
--- /dev/null
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/EntityTypeCounterTest.java
@@ -0,0 +1,58 @@
+/**
+ * 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.ext.services.notification;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.view.textclassifier.TextClassifier;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class EntityTypeCounterTest {
+    private EntityTypeCounter mCounter;
+
+    @Before
+    public void setup() {
+        mCounter = new EntityTypeCounter();
+    }
+
+    @Test
+    public void testIncrementAndGetCount() {
+        mCounter.increment(TextClassifier.TYPE_URL);
+        mCounter.increment(TextClassifier.TYPE_URL);
+        mCounter.increment(TextClassifier.TYPE_URL);
+
+        mCounter.increment(TextClassifier.TYPE_PHONE);
+        mCounter.increment(TextClassifier.TYPE_PHONE);
+
+        assertThat(mCounter.getCount(TextClassifier.TYPE_URL)).isEqualTo(3);
+        assertThat(mCounter.getCount(TextClassifier.TYPE_PHONE)).isEqualTo(2);
+        assertThat(mCounter.getCount(TextClassifier.TYPE_DATE_TIME)).isEqualTo(0);
+    }
+
+    @Test
+    public void testIncrementAndGetCount_typeDateAndDateTime() {
+        mCounter.increment(TextClassifier.TYPE_DATE_TIME);
+        mCounter.increment(TextClassifier.TYPE_DATE);
+
+        assertThat(mCounter.getCount(TextClassifier.TYPE_DATE_TIME)).isEqualTo(2);
+        assertThat(mCounter.getCount(TextClassifier.TYPE_DATE)).isEqualTo(2);
+    }
+}
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
index da382a0..707349b 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
@@ -32,6 +32,7 @@
 import android.service.notification.StatusBarNotification;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.textclassifier.ConversationAction;
 import android.view.textclassifier.ConversationActions;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textclassifier.TextClassifier;
@@ -65,9 +66,10 @@
     private static final String NOTIFICATION_KEY = "key";
     private static final String RESULT_ID = "id";
 
-    private static final ConversationActions.ConversationAction REPLY_ACTION =
-            new ConversationActions.ConversationAction.Builder(
-                    ConversationActions.TYPE_TEXT_REPLY).setTextReply("Home").build();
+    private static final ConversationAction REPLY_ACTION =
+            new ConversationAction.Builder(ConversationAction.TYPE_TEXT_REPLY)
+            .setTextReply("Home")
+            .build();
 
     private SmartActionsHelper mSmartActionsHelper;
     private Context mContext;
@@ -241,7 +243,7 @@
         when(mNotificationEntry.getNotification()).thenReturn(notification);
 
         mSmartActionsHelper.suggestReplies(mNotificationEntry);
-        mSmartActionsHelper.onNotificationDirectReply(NOTIFICATION_KEY);
+        mSmartActionsHelper.onNotificationDirectReplied(NOTIFICATION_KEY);
 
         ArgumentCaptor<TextClassifierEvent> argumentCaptor =
                 ArgumentCaptor.forClass(TextClassifierEvent.class);
@@ -271,24 +273,22 @@
         final String message = "Where are you?";
         Notification notification = mNotificationBuilder.setContentText(message).build();
         when(mNotificationEntry.getNotification()).thenReturn(notification);
-        when(mNotificationEntry.isExpanded()).thenReturn(false);
 
         mSmartActionsHelper.suggestReplies(mNotificationEntry);
-        mSmartActionsHelper.onNotificationSeen(mNotificationEntry);
+        mSmartActionsHelper.onNotificationExpansionChanged(mNotificationEntry, false, false);
 
         verify(mTextClassifier, never()).onTextClassifierEvent(
                 Mockito.any(TextClassifierEvent.class));
     }
 
     @Test
-    public void testOnNotificationsSeen_expanded() {
+    public void testOnNotifications_expanded() {
         final String message = "Where are you?";
         Notification notification = mNotificationBuilder.setContentText(message).build();
         when(mNotificationEntry.getNotification()).thenReturn(notification);
-        when(mNotificationEntry.isExpanded()).thenReturn(true);
 
         mSmartActionsHelper.suggestReplies(mNotificationEntry);
-        mSmartActionsHelper.onNotificationSeen(mNotificationEntry);
+        mSmartActionsHelper.onNotificationExpansionChanged(mNotificationEntry, false, true);
 
         ArgumentCaptor<TextClassifierEvent> argumentCaptor =
                 ArgumentCaptor.forClass(TextClassifierEvent.class);
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 8d04702..da3416b 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -76,7 +76,7 @@
 
     private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
             Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE,
-            Root.COLUMN_DOCUMENT_ID, Root.COLUMN_AVAILABLE_BYTES,
+            Root.COLUMN_DOCUMENT_ID, Root.COLUMN_AVAILABLE_BYTES, Root.COLUMN_QUERY_ARGS
     };
 
     private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
@@ -444,6 +444,7 @@
                 row.add(Root.COLUMN_FLAGS, root.flags);
                 row.add(Root.COLUMN_TITLE, root.title);
                 row.add(Root.COLUMN_DOCUMENT_ID, root.docId);
+                row.add(Root.COLUMN_QUERY_ARGS, SUPPORTED_QUERY_ARGS);
 
                 long availableBytes = -1;
                 if (root.reportAvailableBytes) {
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index 55bb517..a2da0a0 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -21,7 +21,11 @@
     installable: true,
     srcs: [
         "src/**/*.java",
+        ":services-networkstack-shared-srcs",
     ],
+    static_libs: [
+        "services-netlink-lib",
+    ]
 }
 
 // Updatable network stack packaged as an application
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index d1c5cb6..5ab833b 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -17,13 +17,18 @@
  */
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.google.android.networkstack"
+          package="com.android.mainline.networkstack"
           android:sharedUserId="android.uid.networkstack">
     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
     <!-- Launch captive portal app as specific user -->
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.NETWORK_STACK" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
     <application
         android:label="NetworkStack"
         android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/NetworkStack/src/android/net/apf/ApfFilter.java b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
new file mode 100644
index 0000000..50c4dfc
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
@@ -0,0 +1,1591 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.apf;
+
+import static android.net.util.SocketUtils.makePacketSocketAddress;
+import static android.system.OsConstants.AF_PACKET;
+import static android.system.OsConstants.ARPHRD_ETHER;
+import static android.system.OsConstants.ETH_P_ARP;
+import static android.system.OsConstants.ETH_P_IP;
+import static android.system.OsConstants.ETH_P_IPV6;
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.SOCK_RAW;
+
+import static com.android.internal.util.BitUtils.bytesToBEInt;
+import static com.android.internal.util.BitUtils.getUint16;
+import static com.android.internal.util.BitUtils.getUint32;
+import static com.android.internal.util.BitUtils.getUint8;
+import static com.android.internal.util.BitUtils.uint32;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
+
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.NetworkUtils;
+import android.net.apf.ApfGenerator.IllegalInstructionException;
+import android.net.apf.ApfGenerator.Register;
+import android.net.ip.IpClient.IpClientCallbacksWrapper;
+import android.net.metrics.ApfProgramEvent;
+import android.net.metrics.ApfStats;
+import android.net.metrics.IpConnectivityLog;
+import android.net.metrics.RaEvent;
+import android.net.util.InterfaceParams;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.HexDump;
+import com.android.internal.util.IndentingPrintWriter;
+
+import libcore.io.IoBridge;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * For networks that support packet filtering via APF programs, {@code ApfFilter}
+ * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
+ * filter out redundant duplicate ones.
+ *
+ * Threading model:
+ * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to
+ * know what RAs to filter for, thus generating APF programs is dependent on mRas.
+ * mRas can be accessed by multiple threads:
+ * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs.
+ * - callers of:
+ *    - setMulticastFilter(), which can cause an APF program to be generated.
+ *    - dump(), which dumps mRas among other things.
+ *    - shutdown(), which clears mRas.
+ * So access to mRas is synchronized.
+ *
+ * @hide
+ */
+public class ApfFilter {
+
+    // Helper class for specifying functional filter parameters.
+    public static class ApfConfiguration {
+        public ApfCapabilities apfCapabilities;
+        public boolean multicastFilter;
+        public boolean ieee802_3Filter;
+        public int[] ethTypeBlackList;
+    }
+
+    // Enums describing the outcome of receiving an RA packet.
+    private static enum ProcessRaResult {
+        MATCH,          // Received RA matched a known RA
+        DROPPED,        // Received RA ignored due to MAX_RAS
+        PARSE_ERROR,    // Received RA could not be parsed
+        ZERO_LIFETIME,  // Received RA had 0 lifetime
+        UPDATE_NEW_RA,  // APF program updated for new RA
+        UPDATE_EXPIRY   // APF program updated for expiry
+    }
+
+    /**
+     * APF packet counters.
+     *
+     * Packet counters are 32bit big-endian values, and allocated near the end of the APF data
+     * buffer, using negative byte offsets, where -4 is equivalent to maximumApfProgramSize - 4,
+     * the last writable 32bit word.
+     */
+    @VisibleForTesting
+    public static enum Counter {
+        RESERVED_OOB,  // Points to offset 0 from the end of the buffer (out-of-bounds)
+        TOTAL_PACKETS,
+        PASSED_ARP,
+        PASSED_DHCP,
+        PASSED_IPV4,
+        PASSED_IPV6_NON_ICMP,
+        PASSED_IPV4_UNICAST,
+        PASSED_IPV6_ICMP,
+        PASSED_IPV6_UNICAST_NON_ICMP,
+        PASSED_ARP_NON_IPV4,
+        PASSED_ARP_UNKNOWN,
+        PASSED_ARP_UNICAST_REPLY,
+        PASSED_NON_IP_UNICAST,
+        DROPPED_ETH_BROADCAST,
+        DROPPED_RA,
+        DROPPED_GARP_REPLY,
+        DROPPED_ARP_OTHER_HOST,
+        DROPPED_IPV4_L2_BROADCAST,
+        DROPPED_IPV4_BROADCAST_ADDR,
+        DROPPED_IPV4_BROADCAST_NET,
+        DROPPED_IPV4_MULTICAST,
+        DROPPED_IPV6_ROUTER_SOLICITATION,
+        DROPPED_IPV6_MULTICAST_NA,
+        DROPPED_IPV6_MULTICAST,
+        DROPPED_IPV6_MULTICAST_PING,
+        DROPPED_IPV6_NON_ICMP_MULTICAST,
+        DROPPED_802_3_FRAME,
+        DROPPED_ETHERTYPE_BLACKLISTED,
+        DROPPED_ARP_REPLY_SPA_NO_HOST;
+
+        // Returns the negative byte offset from the end of the APF data segment for
+        // a given counter.
+        public int offset() {
+            return - this.ordinal() * 4;  // Currently, all counters are 32bit long.
+        }
+
+        // Returns the total size of the data segment in bytes.
+        public static int totalSize() {
+            return (Counter.class.getEnumConstants().length - 1) * 4;
+        }
+    }
+
+    /**
+     * When APFv4 is supported, loads R1 with the offset of the specified counter.
+     */
+    private void maybeSetupCounter(ApfGenerator gen, Counter c) {
+        if (mApfCapabilities.hasDataAccess()) {
+            gen.addLoadImmediate(Register.R1, c.offset());
+        }
+    }
+
+    // When APFv4 is supported, these point to the trampolines generated by emitEpilogue().
+    // Otherwise, they're just aliases for PASS_LABEL and DROP_LABEL.
+    private final String mCountAndPassLabel;
+    private final String mCountAndDropLabel;
+
+    // Thread to listen for RAs.
+    @VisibleForTesting
+    class ReceiveThread extends Thread {
+        private final byte[] mPacket = new byte[1514];
+        private final FileDescriptor mSocket;
+        private final long mStart = SystemClock.elapsedRealtime();
+
+        private int mReceivedRas = 0;
+        private int mMatchingRas = 0;
+        private int mDroppedRas = 0;
+        private int mParseErrors = 0;
+        private int mZeroLifetimeRas = 0;
+        private int mProgramUpdates = 0;
+
+        private volatile boolean mStopped;
+
+        public ReceiveThread(FileDescriptor socket) {
+            mSocket = socket;
+        }
+
+        public void halt() {
+            mStopped = true;
+            try {
+                // Interrupts the read() call the thread is blocked in.
+                IoBridge.closeAndSignalBlockedThreads(mSocket);
+            } catch (IOException ignored) {}
+        }
+
+        @Override
+        public void run() {
+            log("begin monitoring");
+            while (!mStopped) {
+                try {
+                    int length = Os.read(mSocket, mPacket, 0, mPacket.length);
+                    updateStats(processRa(mPacket, length));
+                } catch (IOException|ErrnoException e) {
+                    if (!mStopped) {
+                        Log.e(TAG, "Read error", e);
+                    }
+                }
+            }
+            logStats();
+        }
+
+        private void updateStats(ProcessRaResult result) {
+            mReceivedRas++;
+            switch(result) {
+                case MATCH:
+                    mMatchingRas++;
+                    return;
+                case DROPPED:
+                    mDroppedRas++;
+                    return;
+                case PARSE_ERROR:
+                    mParseErrors++;
+                    return;
+                case ZERO_LIFETIME:
+                    mZeroLifetimeRas++;
+                    return;
+                case UPDATE_EXPIRY:
+                    mMatchingRas++;
+                    mProgramUpdates++;
+                    return;
+                case UPDATE_NEW_RA:
+                    mProgramUpdates++;
+                    return;
+            }
+        }
+
+        private void logStats() {
+            final long nowMs = SystemClock.elapsedRealtime();
+            synchronized (this) {
+                final ApfStats stats = new ApfStats.Builder()
+                        .setReceivedRas(mReceivedRas)
+                        .setMatchingRas(mMatchingRas)
+                        .setDroppedRas(mDroppedRas)
+                        .setParseErrors(mParseErrors)
+                        .setZeroLifetimeRas(mZeroLifetimeRas)
+                        .setProgramUpdates(mProgramUpdates)
+                        .setDurationMs(nowMs - mStart)
+                        .setMaxProgramSize(mApfCapabilities.maximumApfProgramSize)
+                        .setProgramUpdatesAll(mNumProgramUpdates)
+                        .setProgramUpdatesAllowingMulticast(mNumProgramUpdatesAllowingMulticast)
+                        .build();
+                mMetricsLog.log(stats);
+                logApfProgramEventLocked(nowMs / DateUtils.SECOND_IN_MILLIS);
+            }
+        }
+    }
+
+    private static final String TAG = "ApfFilter";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    private static final int ETH_HEADER_LEN = 14;
+    private static final int ETH_DEST_ADDR_OFFSET = 0;
+    private static final int ETH_ETHERTYPE_OFFSET = 12;
+    private static final int ETH_TYPE_MIN = 0x0600;
+    private static final int ETH_TYPE_MAX = 0xFFFF;
+    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
+            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
+    // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
+    private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
+    // Endianness is not an issue for this constant because the APF interpreter always operates in
+    // network byte order.
+    private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff;
+    private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
+    private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
+    private static final int IPV4_ANY_HOST_ADDRESS = 0;
+    private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
+
+    // Traffic class and Flow label are not byte aligned. Luckily we
+    // don't care about either value so we'll consider bytes 1-3 of the
+    // IPv6 header as don't care.
+    private static final int IPV6_FLOW_LABEL_OFFSET = ETH_HEADER_LEN + 1;
+    private static final int IPV6_FLOW_LABEL_LEN = 3;
+    private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
+    private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
+    private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
+    private static final int IPV6_HEADER_LEN = 40;
+    // The IPv6 all nodes address ff02::1
+    private static final byte[] IPV6_ALL_NODES_ADDRESS =
+            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+
+    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
+
+    // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
+    private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
+    private static final int UDP_HEADER_LEN = 8;
+
+    private static final int DHCP_CLIENT_PORT = 68;
+    // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
+    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
+
+    private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
+    private static final byte[] ARP_IPV4_HEADER = {
+            0, 1, // Hardware type: Ethernet (1)
+            8, 0, // Protocol type: IP (0x0800)
+            6,    // Hardware size: 6
+            4,    // Protocol size: 4
+    };
+    private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
+    // Opcode: ARP request (0x0001), ARP reply (0x0002)
+    private static final short ARP_OPCODE_REQUEST = 1;
+    private static final short ARP_OPCODE_REPLY = 2;
+    private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
+    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
+    // Do not log ApfProgramEvents whose actual lifetimes was less than this.
+    private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2;
+    // Limit on the Black List size to cap on program usage for this
+    // TODO: Select a proper max length
+    private static final int APF_MAX_ETH_TYPE_BLACK_LIST_LEN = 20;
+
+    private final ApfCapabilities mApfCapabilities;
+    private final IpClientCallbacksWrapper mIpClientCallback;
+    private final InterfaceParams mInterfaceParams;
+    private final IpConnectivityLog mMetricsLog;
+
+    @VisibleForTesting
+    byte[] mHardwareAddress;
+    @VisibleForTesting
+    ReceiveThread mReceiveThread;
+    @GuardedBy("this")
+    private long mUniqueCounter;
+    @GuardedBy("this")
+    private boolean mMulticastFilter;
+    @GuardedBy("this")
+    private boolean mInDozeMode;
+    private final boolean mDrop802_3Frames;
+    private final int[] mEthTypeBlackList;
+
+    // Detects doze mode state transitions.
+    private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
+                PowerManager powerManager =
+                        (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+                final boolean deviceIdle = powerManager.isDeviceIdleMode();
+                setDozeMode(deviceIdle);
+            }
+        }
+    };
+    private final Context mContext;
+
+    // Our IPv4 address, if we have just one, otherwise null.
+    @GuardedBy("this")
+    private byte[] mIPv4Address;
+    // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
+    @GuardedBy("this")
+    private int mIPv4PrefixLength;
+
+    @VisibleForTesting
+    ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
+            IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log) {
+        mApfCapabilities = config.apfCapabilities;
+        mIpClientCallback = ipClientCallback;
+        mInterfaceParams = ifParams;
+        mMulticastFilter = config.multicastFilter;
+        mDrop802_3Frames = config.ieee802_3Filter;
+        mContext = context;
+
+        if (mApfCapabilities.hasDataAccess()) {
+            mCountAndPassLabel = "countAndPass";
+            mCountAndDropLabel = "countAndDrop";
+        } else {
+            // APFv4 unsupported: turn jumps to the counter trampolines to immediately PASS or DROP,
+            // preserving the original pre-APFv4 behavior.
+            mCountAndPassLabel = ApfGenerator.PASS_LABEL;
+            mCountAndDropLabel = ApfGenerator.DROP_LABEL;
+        }
+
+        // Now fill the black list from the passed array
+        mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
+
+        mMetricsLog = log;
+
+        // TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
+        maybeStartFilter();
+
+        // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter.
+        mContext.registerReceiver(mDeviceIdleReceiver,
+                new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
+    }
+
+    public synchronized void setDataSnapshot(byte[] data) {
+        mDataSnapshot = data;
+    }
+
+    private void log(String s) {
+        Log.d(TAG, "(" + mInterfaceParams.name + "): " + s);
+    }
+
+    @GuardedBy("this")
+    private long getUniqueNumberLocked() {
+        return mUniqueCounter++;
+    }
+
+    @GuardedBy("this")
+    private static int[] filterEthTypeBlackList(int[] ethTypeBlackList) {
+        ArrayList<Integer> bl = new ArrayList<Integer>();
+
+        for (int p : ethTypeBlackList) {
+            // Check if the protocol is a valid ether type
+            if ((p < ETH_TYPE_MIN) || (p > ETH_TYPE_MAX)) {
+                continue;
+            }
+
+            // Check if the protocol is not repeated in the passed array
+            if (bl.contains(p)) {
+                continue;
+            }
+
+            // Check if list reach its max size
+            if (bl.size() == APF_MAX_ETH_TYPE_BLACK_LIST_LEN) {
+                Log.w(TAG, "Passed EthType Black List size too large (" + bl.size() +
+                        ") using top " + APF_MAX_ETH_TYPE_BLACK_LIST_LEN + " protocols");
+                break;
+            }
+
+            // Now add the protocol to the list
+            bl.add(p);
+        }
+
+        return bl.stream().mapToInt(Integer::intValue).toArray();
+    }
+
+    /**
+     * Attempt to start listening for RAs and, if RAs are received, generating and installing
+     * filters to ignore useless RAs.
+     */
+    @VisibleForTesting
+    void maybeStartFilter() {
+        FileDescriptor socket;
+        try {
+            mHardwareAddress = mInterfaceParams.macAddr.toByteArray();
+            synchronized(this) {
+                // Clear the APF memory to reset all counters upon connecting to the first AP
+                // in an SSID. This is limited to APFv4 devices because this large write triggers
+                // a crash on some older devices (b/78905546).
+                if (mApfCapabilities.hasDataAccess()) {
+                    byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize];
+                    mIpClientCallback.installPacketFilter(zeroes);
+                }
+
+                // Install basic filters
+                installNewProgramLocked();
+            }
+            socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
+            SocketAddress addr = makePacketSocketAddress(
+                    (short) ETH_P_IPV6, mInterfaceParams.index);
+            Os.bind(socket, addr);
+            NetworkUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat);
+        } catch(SocketException|ErrnoException e) {
+            Log.e(TAG, "Error starting filter", e);
+            return;
+        }
+        mReceiveThread = new ReceiveThread(socket);
+        mReceiveThread.start();
+    }
+
+    // Returns seconds since device boot.
+    @VisibleForTesting
+    protected long currentTimeSeconds() {
+        return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
+    }
+
+    public static class InvalidRaException extends Exception {
+        public InvalidRaException(String m) {
+            super(m);
+        }
+    }
+
+    // A class to hold information about an RA.
+    @VisibleForTesting
+    class Ra {
+        // From RFC4861:
+        private static final int ICMP6_RA_HEADER_LEN = 16;
+        private static final int ICMP6_RA_CHECKSUM_OFFSET =
+                ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
+        private static final int ICMP6_RA_CHECKSUM_LEN = 2;
+        private static final int ICMP6_RA_OPTION_OFFSET =
+                ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
+        private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
+                ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
+        private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2;
+        // Prefix information option.
+        private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
+        private static final int ICMP6_PREFIX_OPTION_LEN = 32;
+        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
+        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4;
+        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
+        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4;
+
+        // From RFC6106: Recursive DNS Server option
+        private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
+        // From RFC6106: DNS Search List option
+        private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
+
+        // From RFC4191: Route Information option
+        private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
+        // Above three options all have the same format:
+        private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
+        private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
+
+        // Note: mPacket's position() cannot be assumed to be reset.
+        private final ByteBuffer mPacket;
+        // List of binary ranges that include the whole packet except the lifetimes.
+        // Pairs consist of offset and length.
+        private final ArrayList<Pair<Integer, Integer>> mNonLifetimes =
+                new ArrayList<Pair<Integer, Integer>>();
+        // Minimum lifetime in packet
+        long mMinLifetime;
+        // When the packet was last captured, in seconds since Unix Epoch
+        long mLastSeen;
+
+        // For debugging only. Offsets into the packet where PIOs are.
+        private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>();
+
+        // For debugging only. Offsets into the packet where RDNSS options are.
+        private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>();
+
+        // For debugging only. How many times this RA was seen.
+        int seenCount = 0;
+
+        // For debugging only. Returns the hex representation of the last matching packet.
+        String getLastMatchingPacket() {
+            return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(),
+                    false /* lowercase */);
+        }
+
+        // For debugging only. Returns the string representation of the IPv6 address starting at
+        // position pos in the packet.
+        private String IPv6AddresstoString(int pos) {
+            try {
+                byte[] array = mPacket.array();
+                // Can't just call copyOfRange() and see if it throws, because if it reads past the
+                // end it pads with zeros instead of throwing.
+                if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) {
+                    return "???";
+                }
+                byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16);
+                InetAddress address = (Inet6Address) InetAddress.getByAddress(addressBytes);
+                return address.getHostAddress();
+            } catch (UnsupportedOperationException e) {
+                // array() failed. Cannot happen, mPacket is array-backed and read-write.
+                return "???";
+            } catch (ClassCastException|UnknownHostException e) {
+                // Cannot happen.
+                return "???";
+            }
+        }
+
+        // Can't be static because it's in a non-static inner class.
+        // TODO: Make this static once RA is its own class.
+        private void prefixOptionToString(StringBuffer sb, int offset) {
+            String prefix = IPv6AddresstoString(offset + 16);
+            int length = getUint8(mPacket, offset + 2);
+            long valid = getUint32(mPacket, offset + 4);
+            long preferred = getUint32(mPacket, offset + 8);
+            sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
+        }
+
+        private void rdnssOptionToString(StringBuffer sb, int offset) {
+            int optLen = getUint8(mPacket, offset + 1) * 8;
+            if (optLen < 24) return;  // Malformed or empty.
+            long lifetime = getUint32(mPacket, offset + 4);
+            int numServers = (optLen - 8) / 16;
+            sb.append("DNS ").append(lifetime).append("s");
+            for (int server = 0; server < numServers; server++) {
+                sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server));
+            }
+        }
+
+        public String toString() {
+            try {
+                StringBuffer sb = new StringBuffer();
+                sb.append(String.format("RA %s -> %s %ds ",
+                        IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
+                        IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
+                        getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)));
+                for (int i: mPrefixOptionOffsets) {
+                    prefixOptionToString(sb, i);
+                }
+                for (int i: mRdnssOptionOffsets) {
+                    rdnssOptionToString(sb, i);
+                }
+                return sb.toString();
+            } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
+                return "<Malformed RA>";
+            }
+        }
+
+        /**
+         * Add a binary range of the packet that does not include a lifetime to mNonLifetimes.
+         * Assumes mPacket.position() is as far as we've parsed the packet.
+         * @param lastNonLifetimeStart offset within packet of where the last binary range of
+         *                             data not including a lifetime.
+         * @param lifetimeOffset offset from mPacket.position() to the next lifetime data.
+         * @param lifetimeLength length of the next lifetime data.
+         * @return offset within packet of where the next binary range of data not including
+         *         a lifetime. This can be passed into the next invocation of this function
+         *         via {@code lastNonLifetimeStart}.
+         */
+        private int addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset,
+                int lifetimeLength) {
+            lifetimeOffset += mPacket.position();
+            mNonLifetimes.add(new Pair<Integer, Integer>(lastNonLifetimeStart,
+                    lifetimeOffset - lastNonLifetimeStart));
+            return lifetimeOffset + lifetimeLength;
+        }
+
+        private int addNonLifetimeU32(int lastNonLifetimeStart) {
+            return addNonLifetime(lastNonLifetimeStart,
+                    ICMP6_4_BYTE_LIFETIME_OFFSET, ICMP6_4_BYTE_LIFETIME_LEN);
+        }
+
+        // Note that this parses RA and may throw InvalidRaException (from
+        // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
+        // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
+        // specifications.
+        Ra(byte[] packet, int length) throws InvalidRaException {
+            if (length < ICMP6_RA_OPTION_OFFSET) {
+                throw new InvalidRaException("Not an ICMP6 router advertisement");
+            }
+
+            mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
+            mLastSeen = currentTimeSeconds();
+
+            // Sanity check packet in case a packet arrives before we attach RA filter
+            // to our packet socket. b/29586253
+            if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
+                    getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
+                    getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) {
+                throw new InvalidRaException("Not an ICMP6 router advertisement");
+            }
+
+
+            RaEvent.Builder builder = new RaEvent.Builder();
+
+            // Ignore the flow label and low 4 bits of traffic class.
+            int lastNonLifetimeStart = addNonLifetime(0,
+                    IPV6_FLOW_LABEL_OFFSET,
+                    IPV6_FLOW_LABEL_LEN);
+
+            // Ignore the checksum.
+            lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+                    ICMP6_RA_CHECKSUM_OFFSET,
+                    ICMP6_RA_CHECKSUM_LEN);
+
+            // Parse router lifetime
+            lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+                    ICMP6_RA_ROUTER_LIFETIME_OFFSET,
+                    ICMP6_RA_ROUTER_LIFETIME_LEN);
+            builder.updateRouterLifetime(getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET));
+
+            // Ensures that the RA is not truncated.
+            mPacket.position(ICMP6_RA_OPTION_OFFSET);
+            while (mPacket.hasRemaining()) {
+                final int position = mPacket.position();
+                final int optionType = getUint8(mPacket, position);
+                final int optionLength = getUint8(mPacket, position + 1) * 8;
+                long lifetime;
+                switch (optionType) {
+                    case ICMP6_PREFIX_OPTION_TYPE:
+                        // Parse valid lifetime
+                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
+                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN);
+                        lifetime = getUint32(mPacket,
+                                position + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
+                        builder.updatePrefixValidLifetime(lifetime);
+                        // Parse preferred lifetime
+                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
+                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN);
+                        lifetime = getUint32(mPacket,
+                                position + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET);
+                        builder.updatePrefixPreferredLifetime(lifetime);
+                        mPrefixOptionOffsets.add(position);
+                        break;
+                    // These three options have the same lifetime offset and size, and
+                    // are processed with the same specialized addNonLifetimeU32:
+                    case ICMP6_RDNSS_OPTION_TYPE:
+                        mRdnssOptionOffsets.add(position);
+                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
+                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
+                        builder.updateRdnssLifetime(lifetime);
+                        break;
+                    case ICMP6_ROUTE_INFO_OPTION_TYPE:
+                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
+                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
+                        builder.updateRouteInfoLifetime(lifetime);
+                        break;
+                    case ICMP6_DNSSL_OPTION_TYPE:
+                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
+                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
+                        builder.updateDnsslLifetime(lifetime);
+                        break;
+                    default:
+                        // RFC4861 section 4.2 dictates we ignore unknown options for fowards
+                        // compatibility.
+                        break;
+                }
+                if (optionLength <= 0) {
+                    throw new InvalidRaException(String.format(
+                        "Invalid option length opt=%d len=%d", optionType, optionLength));
+                }
+                mPacket.position(position + optionLength);
+            }
+            // Mark non-lifetime bytes since last lifetime.
+            addNonLifetime(lastNonLifetimeStart, 0, 0);
+            mMinLifetime = minLifetime(packet, length);
+            mMetricsLog.log(builder.build());
+        }
+
+        // Ignoring lifetimes (which may change) does {@code packet} match this RA?
+        boolean matches(byte[] packet, int length) {
+            if (length != mPacket.capacity()) return false;
+            byte[] referencePacket = mPacket.array();
+            for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) {
+                for (int i = nonLifetime.first; i < (nonLifetime.first + nonLifetime.second); i++) {
+                    if (packet[i] != referencePacket[i]) return false;
+                }
+            }
+            return true;
+        }
+
+        // What is the minimum of all lifetimes within {@code packet} in seconds?
+        // Precondition: matches(packet, length) already returned true.
+        long minLifetime(byte[] packet, int length) {
+            long minLifetime = Long.MAX_VALUE;
+            // Wrap packet in ByteBuffer so we can read big-endian values easily
+            ByteBuffer byteBuffer = ByteBuffer.wrap(packet);
+            for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) {
+                int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second;
+
+                // The flow label is in mNonLifetimes, but it's not a lifetime.
+                if (offset == IPV6_FLOW_LABEL_OFFSET) {
+                    continue;
+                }
+
+                // The checksum is in mNonLifetimes, but it's not a lifetime.
+                if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
+                    continue;
+                }
+
+                final int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
+                final long optionLifetime;
+                switch (lifetimeLength) {
+                    case 2:
+                        optionLifetime = getUint16(byteBuffer, offset);
+                        break;
+                    case 4:
+                        optionLifetime = getUint32(byteBuffer, offset);
+                        break;
+                    default:
+                        throw new IllegalStateException("bogus lifetime size " + lifetimeLength);
+                }
+                minLifetime = Math.min(minLifetime, optionLifetime);
+            }
+            return minLifetime;
+        }
+
+        // How many seconds does this RA's have to live, taking into account the fact
+        // that we might have seen it a while ago.
+        long currentLifetime() {
+            return mMinLifetime - (currentTimeSeconds() - mLastSeen);
+        }
+
+        boolean isExpired() {
+            // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll
+            // have to calculte the filter lifetime specially as a fraction of 0 is still 0.
+            return currentLifetime() <= 0;
+        }
+
+        // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
+        // Jump to the next filter if packet doesn't match this RA.
+        @GuardedBy("ApfFilter.this")
+        long generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+            String nextFilterLabel = "Ra" + getUniqueNumberLocked();
+            // Skip if packet is not the right size
+            gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
+            gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
+            int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
+            // Skip filter if expired
+            gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
+            gen.addJumpIfR0GreaterThan(filterLifetime, nextFilterLabel);
+            for (int i = 0; i < mNonLifetimes.size(); i++) {
+                // Generate code to match the packet bytes
+                Pair<Integer, Integer> nonLifetime = mNonLifetimes.get(i);
+                // Don't generate JNEBS instruction for 0 bytes as it always fails the
+                // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check where cmp_imm is
+                // the number of bytes to compare. nonLifetime is zero between the
+                // valid and preferred lifetimes in the prefix option.
+                if (nonLifetime.second != 0) {
+                    gen.addLoadImmediate(Register.R0, nonLifetime.first);
+                    gen.addJumpIfBytesNotEqual(Register.R0,
+                            Arrays.copyOfRange(mPacket.array(), nonLifetime.first,
+                                               nonLifetime.first + nonLifetime.second),
+                            nextFilterLabel);
+                }
+                // Generate code to test the lifetimes haven't gone down too far
+                if ((i + 1) < mNonLifetimes.size()) {
+                    Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1);
+                    int offset = nonLifetime.first + nonLifetime.second;
+
+                    // Skip the Flow label.
+                    if (offset == IPV6_FLOW_LABEL_OFFSET) {
+                        continue;
+                    }
+                    // Skip the checksum.
+                    if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
+                        continue;
+                    }
+                    int length = nextNonLifetime.first - offset;
+                    switch (length) {
+                        case 4: gen.addLoad32(Register.R0, offset); break;
+                        case 2: gen.addLoad16(Register.R0, offset); break;
+                        default: throw new IllegalStateException("bogus lifetime size " + length);
+                    }
+                    gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel);
+                }
+            }
+            maybeSetupCounter(gen, Counter.DROPPED_RA);
+            gen.addJump(mCountAndDropLabel);
+            gen.defineLabel(nextFilterLabel);
+            return filterLifetime;
+        }
+    }
+
+    // Maximum number of RAs to filter for.
+    private static final int MAX_RAS = 10;
+
+    @GuardedBy("this")
+    private ArrayList<Ra> mRas = new ArrayList<Ra>();
+
+    // There is always some marginal benefit to updating the installed APF program when an RA is
+    // seen because we can extend the program's lifetime slightly, but there is some cost to
+    // updating the program, so don't bother unless the program is going to expire soon. This
+    // constant defines "soon" in seconds.
+    private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30;
+    // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
+    // see a refresh.  Using half the lifetime might be a good idea except for the fact that
+    // packets may be dropped, so let's use 6.
+    private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
+
+    // When did we last install a filter program? In seconds since Unix Epoch.
+    @GuardedBy("this")
+    private long mLastTimeInstalledProgram;
+    // How long should the last installed filter program live for? In seconds.
+    @GuardedBy("this")
+    private long mLastInstalledProgramMinLifetime;
+    @GuardedBy("this")
+    private ApfProgramEvent.Builder mLastInstallEvent;
+
+    // For debugging only. The last program installed.
+    @GuardedBy("this")
+    private byte[] mLastInstalledProgram;
+
+    /**
+     * For debugging only. Contains the latest APF buffer snapshot captured from the firmware.
+     *
+     * A typical size for this buffer is 4KB. It is present only if the WiFi HAL supports
+     * IWifiStaIface#readApfPacketFilterData(), and the APF interpreter advertised support for
+     * the opcodes to access the data buffer (LDDW and STDW).
+     */
+    @GuardedBy("this") @Nullable
+    private byte[] mDataSnapshot;
+
+    // How many times the program was updated since we started.
+    @GuardedBy("this")
+    private int mNumProgramUpdates = 0;
+    // How many times the program was updated since we started for allowing multicast traffic.
+    @GuardedBy("this")
+    private int mNumProgramUpdatesAllowingMulticast = 0;
+
+    /**
+     * Generate filter code to process ARP packets. Execution of this code ends in either the
+     * DROP_LABEL or PASS_LABEL and does not fall off the end.
+     * Preconditions:
+     *  - Packet being filtered is ARP
+     */
+    @GuardedBy("this")
+    private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+        // Here's a basic summary of what the ARP filter program does:
+        //
+        // if not ARP IPv4
+        //   pass
+        // if not ARP IPv4 reply or request
+        //   pass
+        // if ARP reply source ip is 0.0.0.0
+        //   drop
+        // if unicast ARP reply
+        //   pass
+        // if interface has no IPv4 address
+        //   if target ip is 0.0.0.0
+        //      drop
+        // else
+        //   if target ip is not the interface ip
+        //      drop
+        // pass
+
+        final String checkTargetIPv4 = "checkTargetIPv4";
+
+        // Pass if not ARP IPv4.
+        gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
+        maybeSetupCounter(gen, Counter.PASSED_ARP_NON_IPV4);
+        gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, mCountAndPassLabel);
+
+        // Pass if unknown ARP opcode.
+        gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET);
+        gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check
+        maybeSetupCounter(gen, Counter.PASSED_ARP_UNKNOWN);
+        gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, mCountAndPassLabel);
+
+        // Drop if ARP reply source IP is 0.0.0.0
+        gen.addLoad32(Register.R0, ARP_SOURCE_IP_ADDRESS_OFFSET);
+        maybeSetupCounter(gen, Counter.DROPPED_ARP_REPLY_SPA_NO_HOST);
+        gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
+
+        // Pass if unicast reply.
+        gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
+        maybeSetupCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY);
+        gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
+
+        // Either a unicast request, a unicast reply, or a broadcast reply.
+        gen.defineLabel(checkTargetIPv4);
+        if (mIPv4Address == null) {
+            // When there is no IPv4 address, drop GARP replies (b/29404209).
+            gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
+            maybeSetupCounter(gen, Counter.DROPPED_GARP_REPLY);
+            gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
+        } else {
+            // When there is an IPv4 address, drop unicast/broadcast requests
+            // and broadcast replies with a different target IPv4 address.
+            gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
+            maybeSetupCounter(gen, Counter.DROPPED_ARP_OTHER_HOST);
+            gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, mCountAndDropLabel);
+        }
+
+        maybeSetupCounter(gen, Counter.PASSED_ARP);
+        gen.addJump(mCountAndPassLabel);
+    }
+
+    /**
+     * Generate filter code to process IPv4 packets. Execution of this code ends in either the
+     * DROP_LABEL or PASS_LABEL and does not fall off the end.
+     * Preconditions:
+     *  - Packet being filtered is IPv4
+     */
+    @GuardedBy("this")
+    private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+        // Here's a basic summary of what the IPv4 filter program does:
+        //
+        // if filtering multicast (i.e. multicast lock not held):
+        //   if it's DHCP destined to our MAC:
+        //     pass
+        //   if it's L2 broadcast:
+        //     drop
+        //   if it's IPv4 multicast:
+        //     drop
+        //   if it's IPv4 broadcast:
+        //     drop
+        // pass
+
+        if (mMulticastFilter) {
+            final String skipDhcpv4Filter = "skip_dhcp_v4_filter";
+
+            // Pass DHCP addressed to us.
+            // Check it's UDP.
+            gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
+            gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter);
+            // Check it's not a fragment. This matches the BPF filter installed by the DHCP client.
+            gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
+            gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter);
+            // Check it's addressed to DHCP client port.
+            gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
+            gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
+            gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
+            // Check it's DHCP to our MAC address.
+            gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
+            // NOTE: Relies on R1 containing IPv4 header offset.
+            gen.addAddR1();
+            gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
+            maybeSetupCounter(gen, Counter.PASSED_DHCP);
+            gen.addJump(mCountAndPassLabel);
+
+            // Drop all multicasts/broadcasts.
+            gen.defineLabel(skipDhcpv4Filter);
+
+            // If IPv4 destination address is in multicast range, drop.
+            gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
+            gen.addAnd(0xf0);
+            maybeSetupCounter(gen, Counter.DROPPED_IPV4_MULTICAST);
+            gen.addJumpIfR0Equals(0xe0, mCountAndDropLabel);
+
+            // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
+            maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_ADDR);
+            gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
+            gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, mCountAndDropLabel);
+            if (mIPv4Address != null && mIPv4PrefixLength < 31) {
+                maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_NET);
+                int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
+                gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
+            }
+
+            // If L2 broadcast packet, drop.
+            // TODO: can we invert this condition to fall through to the common pass case below?
+            maybeSetupCounter(gen, Counter.PASSED_IPV4_UNICAST);
+            gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
+            gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
+            maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
+            gen.addJump(mCountAndDropLabel);
+        }
+
+        // Otherwise, pass
+        maybeSetupCounter(gen, Counter.PASSED_IPV4);
+        gen.addJump(mCountAndPassLabel);
+    }
+
+
+    /**
+     * Generate filter code to process IPv6 packets. Execution of this code ends in either the
+     * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
+     * Preconditions:
+     *  - Packet being filtered is IPv6
+     */
+    @GuardedBy("this")
+    private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+        // Here's a basic summary of what the IPv6 filter program does:
+        //
+        // if we're dropping multicast
+        //   if it's not IPCMv6 or it's ICMPv6 but we're in doze mode:
+        //     if it's multicast:
+        //       drop
+        //     pass
+        // if it's ICMPv6 RS to any:
+        //   drop
+        // if it's ICMPv6 NA to ff02::1:
+        //   drop
+
+        gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
+
+        // Drop multicast if the multicast filter is enabled.
+        if (mMulticastFilter) {
+            final String skipIPv6MulticastFilterLabel = "skipIPv6MulticastFilter";
+            final String dropAllIPv6MulticastsLabel = "dropAllIPv6Multicast";
+
+            // While in doze mode, drop ICMPv6 multicast pings, let the others pass.
+            // While awake, let all ICMPv6 multicasts through.
+            if (mInDozeMode) {
+                // Not ICMPv6? -> Proceed to multicast filtering
+                gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel);
+
+                // ICMPv6 but not ECHO? -> Skip the multicast filter.
+                // (ICMPv6 ECHO requests will go through the multicast filter below).
+                gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
+                gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel);
+            } else {
+                gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel);
+            }
+
+            // Drop all other packets sent to ff00::/8 (multicast prefix).
+            gen.defineLabel(dropAllIPv6MulticastsLabel);
+            maybeSetupCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
+            gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
+            gen.addJumpIfR0Equals(0xff, mCountAndDropLabel);
+            // Not multicast. Pass.
+            maybeSetupCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP);
+            gen.addJump(mCountAndPassLabel);
+            gen.defineLabel(skipIPv6MulticastFilterLabel);
+        } else {
+            // If not ICMPv6, pass.
+            maybeSetupCounter(gen, Counter.PASSED_IPV6_NON_ICMP);
+            gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel);
+        }
+
+        // If we got this far, the packet is ICMPv6.  Drop some specific types.
+
+        // Add unsolicited multicast neighbor announcements filter
+        String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
+        gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
+        // Drop all router solicitations (b/32833400)
+        maybeSetupCounter(gen, Counter.DROPPED_IPV6_ROUTER_SOLICITATION);
+        gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, mCountAndDropLabel);
+        // If not neighbor announcements, skip filter.
+        gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
+        // If to ff02::1, drop.
+        // TODO: Drop only if they don't contain the address of on-link neighbours.
+        gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
+        gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
+                skipUnsolicitedMulticastNALabel);
+        maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
+        gen.addJump(mCountAndDropLabel);
+        gen.defineLabel(skipUnsolicitedMulticastNALabel);
+    }
+
+    /**
+     * Begin generating an APF program to:
+     * <ul>
+     * <li>Drop/Pass 802.3 frames (based on policy)
+     * <li>Drop packets with EtherType within the Black List
+     * <li>Drop ARP requests not for us, if mIPv4Address is set,
+     * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
+     * <li>Drop IPv4 multicast packets, if mMulticastFilter,
+     * <li>Pass all other IPv4 packets,
+     * <li>Drop all broadcast non-IP non-ARP packets.
+     * <li>Pass all non-ICMPv6 IPv6 packets,
+     * <li>Pass all non-IPv4 and non-IPv6 packets,
+     * <li>Drop IPv6 ICMPv6 NAs to ff02::1.
+     * <li>Drop IPv6 ICMPv6 RSs.
+     * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
+     *     insertion of RA filters here, or if there aren't any, just passes the packets.
+     * </ul>
+     */
+    @GuardedBy("this")
+    private ApfGenerator emitPrologueLocked() throws IllegalInstructionException {
+        // This is guaranteed to succeed because of the check in maybeCreate.
+        ApfGenerator gen = new ApfGenerator(mApfCapabilities.apfVersionSupported);
+
+        if (mApfCapabilities.hasDataAccess()) {
+            // Increment TOTAL_PACKETS
+            maybeSetupCounter(gen, Counter.TOTAL_PACKETS);
+            gen.addLoadData(Register.R0, 0);  // load counter
+            gen.addAdd(1);
+            gen.addStoreData(Register.R0, 0);  // write-back counter
+        }
+
+        // Here's a basic summary of what the initial program does:
+        //
+        // if it's a 802.3 Frame (ethtype < 0x0600):
+        //    drop or pass based on configurations
+        // if it has a ether-type that belongs to the black list
+        //    drop
+        // if it's ARP:
+        //   insert ARP filter to drop or pass these appropriately
+        // if it's IPv4:
+        //   insert IPv4 filter to drop or pass these appropriately
+        // if it's not IPv6:
+        //   if it's broadcast:
+        //     drop
+        //   pass
+        // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
+
+        gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
+
+        if (mDrop802_3Frames) {
+            // drop 802.3 frames (ethtype < 0x0600)
+            maybeSetupCounter(gen, Counter.DROPPED_802_3_FRAME);
+            gen.addJumpIfR0LessThan(ETH_TYPE_MIN, mCountAndDropLabel);
+        }
+
+        // Handle ether-type black list
+        maybeSetupCounter(gen, Counter.DROPPED_ETHERTYPE_BLACKLISTED);
+        for (int p : mEthTypeBlackList) {
+            gen.addJumpIfR0Equals(p, mCountAndDropLabel);
+        }
+
+        // Add ARP filters:
+        String skipArpFiltersLabel = "skipArpFilters";
+        gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
+        generateArpFilterLocked(gen);
+        gen.defineLabel(skipArpFiltersLabel);
+
+        // Add IPv4 filters:
+        String skipIPv4FiltersLabel = "skipIPv4Filters";
+        // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
+        // execute the ARP filter, since that filter does not fall through, but either drops or
+        // passes.
+        gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
+        generateIPv4FilterLocked(gen);
+        gen.defineLabel(skipIPv4FiltersLabel);
+
+        // Check for IPv6:
+        // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
+        // execute the ARP or IPv4 filters, since those filters do not fall through, but either
+        // drop or pass.
+        String ipv6FilterLabel = "IPv6Filters";
+        gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel);
+
+        // Drop non-IP non-ARP broadcasts, pass the rest
+        gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
+        maybeSetupCounter(gen, Counter.PASSED_NON_IP_UNICAST);
+        gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
+        maybeSetupCounter(gen, Counter.DROPPED_ETH_BROADCAST);
+        gen.addJump(mCountAndDropLabel);
+
+        // Add IPv6 filters:
+        gen.defineLabel(ipv6FilterLabel);
+        generateIPv6FilterLocked(gen);
+        return gen;
+    }
+
+    /**
+     * Append packet counting epilogue to the APF program.
+     *
+     * Currently, the epilogue consists of two trampolines which count passed and dropped packets
+     * before jumping to the actual PASS and DROP labels.
+     */
+    @GuardedBy("this")
+    private void emitEpilogue(ApfGenerator gen) throws IllegalInstructionException {
+        // If APFv4 is unsupported, no epilogue is necessary: if execution reached this far, it
+        // will just fall-through to the PASS label.
+        if (!mApfCapabilities.hasDataAccess()) return;
+
+        // Execution will reach the bottom of the program if none of the filters match,
+        // which will pass the packet to the application processor.
+        maybeSetupCounter(gen, Counter.PASSED_IPV6_ICMP);
+
+        // Append the count & pass trampoline, which increments the counter at the data address
+        // pointed to by R1, then jumps to the pass label. This saves a few bytes over inserting
+        // the entire sequence inline for every counter.
+        gen.defineLabel(mCountAndPassLabel);
+        gen.addLoadData(Register.R0, 0);   // R0 = *(R1 + 0)
+        gen.addAdd(1);                     // R0++
+        gen.addStoreData(Register.R0, 0);  // *(R1 + 0) = R0
+        gen.addJump(gen.PASS_LABEL);
+
+        // Same as above for the count & drop trampoline.
+        gen.defineLabel(mCountAndDropLabel);
+        gen.addLoadData(Register.R0, 0);   // R0 = *(R1 + 0)
+        gen.addAdd(1);                     // R0++
+        gen.addStoreData(Register.R0, 0);  // *(R1 + 0) = R0
+        gen.addJump(gen.DROP_LABEL);
+    }
+
+    /**
+     * Generate and install a new filter program.
+     */
+    @GuardedBy("this")
+    @VisibleForTesting
+    void installNewProgramLocked() {
+        purgeExpiredRasLocked();
+        ArrayList<Ra> rasToFilter = new ArrayList<>();
+        final byte[] program;
+        long programMinLifetime = Long.MAX_VALUE;
+        long maximumApfProgramSize = mApfCapabilities.maximumApfProgramSize;
+        if (mApfCapabilities.hasDataAccess()) {
+            // Reserve space for the counters.
+            maximumApfProgramSize -= Counter.totalSize();
+        }
+
+        try {
+            // Step 1: Determine how many RA filters we can fit in the program.
+            ApfGenerator gen = emitPrologueLocked();
+
+            // The epilogue normally goes after the RA filters, but add it early to include its
+            // length when estimating the total.
+            emitEpilogue(gen);
+
+            // Can't fit the program even without any RA filters?
+            if (gen.programLengthOverEstimate() > maximumApfProgramSize) {
+                Log.e(TAG, "Program exceeds maximum size " + maximumApfProgramSize);
+                return;
+            }
+
+            for (Ra ra : mRas) {
+                ra.generateFilterLocked(gen);
+                // Stop if we get too big.
+                if (gen.programLengthOverEstimate() > maximumApfProgramSize) break;
+                rasToFilter.add(ra);
+            }
+
+            // Step 2: Actually generate the program
+            gen = emitPrologueLocked();
+            for (Ra ra : rasToFilter) {
+                programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen));
+            }
+            emitEpilogue(gen);
+            program = gen.generate();
+        } catch (IllegalInstructionException|IllegalStateException e) {
+            Log.e(TAG, "Failed to generate APF program.", e);
+            return;
+        }
+        final long now = currentTimeSeconds();
+        mLastTimeInstalledProgram = now;
+        mLastInstalledProgramMinLifetime = programMinLifetime;
+        mLastInstalledProgram = program;
+        mNumProgramUpdates++;
+
+        if (VDBG) {
+            hexDump("Installing filter: ", program, program.length);
+        }
+        mIpClientCallback.installPacketFilter(program);
+        logApfProgramEventLocked(now);
+        mLastInstallEvent = new ApfProgramEvent.Builder()
+                .setLifetime(programMinLifetime)
+                .setFilteredRas(rasToFilter.size())
+                .setCurrentRas(mRas.size())
+                .setProgramLength(program.length)
+                .setFlags(mIPv4Address != null, mMulticastFilter);
+    }
+
+    @GuardedBy("this")
+    private void logApfProgramEventLocked(long now) {
+        if (mLastInstallEvent == null) {
+            return;
+        }
+        ApfProgramEvent.Builder ev = mLastInstallEvent;
+        mLastInstallEvent = null;
+        final long actualLifetime = now - mLastTimeInstalledProgram;
+        ev.setActualLifetime(actualLifetime);
+        if (actualLifetime < APF_PROGRAM_EVENT_LIFETIME_THRESHOLD) {
+            return;
+        }
+        mMetricsLog.log(ev.build());
+    }
+
+    /**
+     * Returns {@code true} if a new program should be installed because the current one dies soon.
+     */
+    private boolean shouldInstallnewProgram() {
+        long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
+        return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
+    }
+
+    private void hexDump(String msg, byte[] packet, int length) {
+        log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */));
+    }
+
+    @GuardedBy("this")
+    private void purgeExpiredRasLocked() {
+        for (int i = 0; i < mRas.size();) {
+            if (mRas.get(i).isExpired()) {
+                log("Expiring " + mRas.get(i));
+                mRas.remove(i);
+            } else {
+                i++;
+            }
+        }
+    }
+
+    /**
+     * Process an RA packet, updating the list of known RAs and installing a new APF program
+     * if the current APF program should be updated.
+     * @return a ProcessRaResult enum describing what action was performed.
+     */
+    @VisibleForTesting
+    synchronized ProcessRaResult processRa(byte[] packet, int length) {
+        if (VDBG) hexDump("Read packet = ", packet, length);
+
+        // Have we seen this RA before?
+        for (int i = 0; i < mRas.size(); i++) {
+            Ra ra = mRas.get(i);
+            if (ra.matches(packet, length)) {
+                if (VDBG) log("matched RA " + ra);
+                // Update lifetimes.
+                ra.mLastSeen = currentTimeSeconds();
+                ra.mMinLifetime = ra.minLifetime(packet, length);
+                ra.seenCount++;
+
+                // Keep mRas in LRU order so as to prioritize generating filters for recently seen
+                // RAs. LRU prioritizes this because RA filters are generated in order from mRas
+                // until the filter program exceeds the maximum filter program size allowed by the
+                // chipset, so RAs appearing earlier in mRas are more likely to make it into the
+                // filter program.
+                // TODO: consider sorting the RAs in order of increasing expiry time as well.
+                // Swap to front of array.
+                mRas.add(0, mRas.remove(i));
+
+                // If the current program doesn't expire for a while, don't update.
+                if (shouldInstallnewProgram()) {
+                    installNewProgramLocked();
+                    return ProcessRaResult.UPDATE_EXPIRY;
+                }
+                return ProcessRaResult.MATCH;
+            }
+        }
+        purgeExpiredRasLocked();
+        // TODO: figure out how to proceed when we've received more then MAX_RAS RAs.
+        if (mRas.size() >= MAX_RAS) {
+            return ProcessRaResult.DROPPED;
+        }
+        final Ra ra;
+        try {
+            ra = new Ra(packet, length);
+        } catch (Exception e) {
+            Log.e(TAG, "Error parsing RA", e);
+            return ProcessRaResult.PARSE_ERROR;
+        }
+        // Ignore 0 lifetime RAs.
+        if (ra.isExpired()) {
+            return ProcessRaResult.ZERO_LIFETIME;
+        }
+        log("Adding " + ra);
+        mRas.add(ra);
+        installNewProgramLocked();
+        return ProcessRaResult.UPDATE_NEW_RA;
+    }
+
+    /**
+     * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
+     * filtering using APF programs.
+     */
+    public static ApfFilter maybeCreate(Context context, ApfConfiguration config,
+            InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback) {
+        if (context == null || config == null || ifParams == null) return null;
+        ApfCapabilities apfCapabilities =  config.apfCapabilities;
+        if (apfCapabilities == null) return null;
+        if (apfCapabilities.apfVersionSupported == 0) return null;
+        if (apfCapabilities.maximumApfProgramSize < 512) {
+            Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize);
+            return null;
+        }
+        // For now only support generating programs for Ethernet frames. If this restriction is
+        // lifted:
+        //   1. the program generator will need its offsets adjusted.
+        //   2. the packet filter attached to our packet socket will need its offset adjusted.
+        if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null;
+        if (!ApfGenerator.supportsVersion(apfCapabilities.apfVersionSupported)) {
+            Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
+            return null;
+        }
+
+        return new ApfFilter(context, config, ifParams, ipClientCallback, new IpConnectivityLog());
+    }
+
+    public synchronized void shutdown() {
+        if (mReceiveThread != null) {
+            log("shutting down");
+            mReceiveThread.halt();  // Also closes socket.
+            mReceiveThread = null;
+        }
+        mRas.clear();
+        mContext.unregisterReceiver(mDeviceIdleReceiver);
+    }
+
+    public synchronized void setMulticastFilter(boolean isEnabled) {
+        if (mMulticastFilter == isEnabled) return;
+        mMulticastFilter = isEnabled;
+        if (!isEnabled) {
+            mNumProgramUpdatesAllowingMulticast++;
+        }
+        installNewProgramLocked();
+    }
+
+    @VisibleForTesting
+    public synchronized void setDozeMode(boolean isEnabled) {
+        if (mInDozeMode == isEnabled) return;
+        mInDozeMode = isEnabled;
+        installNewProgramLocked();
+    }
+
+    /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
+    private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
+        LinkAddress ipv4Address = null;
+        for (LinkAddress address : lp.getLinkAddresses()) {
+            if (!(address.getAddress() instanceof Inet4Address)) {
+                continue;
+            }
+            if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
+                // More than one IPv4 address, abort.
+                return null;
+            }
+            ipv4Address = address;
+        }
+        return ipv4Address;
+    }
+
+    public synchronized void setLinkProperties(LinkProperties lp) {
+        // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
+        final LinkAddress ipv4Address = findIPv4LinkAddress(lp);
+        final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
+        final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
+        if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) {
+            return;
+        }
+        mIPv4Address = addr;
+        mIPv4PrefixLength = prefix;
+        installNewProgramLocked();
+    }
+
+    static public long counterValue(byte[] data, Counter counter)
+            throws ArrayIndexOutOfBoundsException {
+        // Follow the same wrap-around addressing scheme of the interpreter.
+        int offset = counter.offset();
+        if (offset < 0) {
+            offset = data.length + offset;
+        }
+
+        // Decode 32bit big-endian integer into a long so we can count up beyond 2^31.
+        long value = 0;
+        for (int i = 0; i < 4; i++) {
+            value = value << 8 | (data[offset] & 0xFF);
+            offset++;
+        }
+        return value;
+    }
+
+    public synchronized void dump(IndentingPrintWriter pw) {
+        pw.println("Capabilities: " + mApfCapabilities);
+        pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
+        pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW"));
+        try {
+            pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress());
+        } catch (UnknownHostException|NullPointerException e) {}
+
+        if (mLastTimeInstalledProgram == 0) {
+            pw.println("No program installed.");
+            return;
+        }
+        pw.println("Program updates: " + mNumProgramUpdates);
+        pw.println(String.format(
+                "Last program length %d, installed %ds ago, lifetime %ds",
+                mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram,
+                mLastInstalledProgramMinLifetime));
+
+        pw.println("RA filters:");
+        pw.increaseIndent();
+        for (Ra ra: mRas) {
+            pw.println(ra);
+            pw.increaseIndent();
+            pw.println(String.format(
+                    "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen));
+            if (DBG) {
+                pw.println("Last match:");
+                pw.increaseIndent();
+                pw.println(ra.getLastMatchingPacket());
+                pw.decreaseIndent();
+            }
+            pw.decreaseIndent();
+        }
+        pw.decreaseIndent();
+
+        if (DBG) {
+            pw.println("Last program:");
+            pw.increaseIndent();
+            pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
+            pw.decreaseIndent();
+        }
+
+        pw.println("APF packet counters: ");
+        pw.increaseIndent();
+        if (!mApfCapabilities.hasDataAccess()) {
+            pw.println("APF counters not supported");
+        } else if (mDataSnapshot == null) {
+            pw.println("No last snapshot.");
+        } else {
+            try {
+                Counter[] counters = Counter.class.getEnumConstants();
+                for (Counter c : Arrays.asList(counters).subList(1, counters.length)) {
+                    long value = counterValue(mDataSnapshot, c);
+                    // Only print non-zero counters
+                    if (value != 0) {
+                        pw.println(c.toString() + ": " + value);
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                pw.println("Uh-oh: " + e);
+            }
+            if (VDBG) {
+                pw.println("Raw data dump: ");
+                pw.println(HexDump.dumpHexString(mDataSnapshot));
+            }
+        }
+        pw.decreaseIndent();
+    }
+
+    // TODO: move to android.net.NetworkUtils
+    @VisibleForTesting
+    public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
+        return bytesToBEInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
+    }
+}
diff --git a/services/net/java/android/net/apf/ApfGenerator.java b/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
similarity index 100%
rename from services/net/java/android/net/apf/ApfGenerator.java
rename to packages/NetworkStack/src/android/net/apf/ApfGenerator.java
diff --git a/services/net/java/android/net/dhcp/DhcpAckPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpAckPacket.java
similarity index 100%
rename from services/net/java/android/net/dhcp/DhcpAckPacket.java
rename to packages/NetworkStack/src/android/net/dhcp/DhcpAckPacket.java
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
new file mode 100644
index 0000000..04ac9a3
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
@@ -0,0 +1,1052 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.dhcp;
+
+import static android.net.dhcp.DhcpPacket.DHCP_BROADCAST_ADDRESS;
+import static android.net.dhcp.DhcpPacket.DHCP_DNS_SERVER;
+import static android.net.dhcp.DhcpPacket.DHCP_DOMAIN_NAME;
+import static android.net.dhcp.DhcpPacket.DHCP_LEASE_TIME;
+import static android.net.dhcp.DhcpPacket.DHCP_MTU;
+import static android.net.dhcp.DhcpPacket.DHCP_REBINDING_TIME;
+import static android.net.dhcp.DhcpPacket.DHCP_RENEWAL_TIME;
+import static android.net.dhcp.DhcpPacket.DHCP_ROUTER;
+import static android.net.dhcp.DhcpPacket.DHCP_SUBNET_MASK;
+import static android.net.dhcp.DhcpPacket.DHCP_VENDOR_INFO;
+import static android.net.dhcp.DhcpPacket.INADDR_ANY;
+import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST;
+import static android.net.util.SocketUtils.makePacketSocketAddress;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_PACKET;
+import static android.system.OsConstants.ETH_P_IP;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_RAW;
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_BROADCAST;
+import static android.system.OsConstants.SO_RCVBUF;
+import static android.system.OsConstants.SO_REUSEADDR;
+
+import android.content.Context;
+import android.net.DhcpResults;
+import android.net.NetworkUtils;
+import android.net.TrafficStats;
+import android.net.ip.IpClient;
+import android.net.metrics.DhcpClientEvent;
+import android.net.metrics.DhcpErrorEvent;
+import android.net.metrics.IpConnectivityLog;
+import android.net.util.InterfaceParams;
+import android.net.util.SocketUtils;
+import android.os.Message;
+import android.os.SystemClock;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.util.HexDump;
+import com.android.internal.util.MessageUtils;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.internal.util.WakeupMessage;
+
+import libcore.io.IoBridge;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * A DHCPv4 client.
+ *
+ * Written to behave similarly to the DhcpStateMachine + dhcpcd 5.5.6 combination used in Android
+ * 5.1 and below, as configured on Nexus 6. The interface is the same as DhcpStateMachine.
+ *
+ * TODO:
+ *
+ * - Exponential backoff when receiving NAKs (not specified by the RFC, but current behaviour).
+ * - Support persisting lease state and support INIT-REBOOT. Android 5.1 does this, but it does not
+ *   do so correctly: instead of requesting the lease last obtained on a particular network (e.g., a
+ *   given SSID), it requests the last-leased IP address on the same interface, causing a delay if
+ *   the server NAKs or a timeout if it doesn't.
+ *
+ * Known differences from current behaviour:
+ *
+ * - Does not request the "static routes" option.
+ * - Does not support BOOTP servers. DHCP has been around since 1993, should be everywhere now.
+ * - Requests the "broadcast" option, but does nothing with it.
+ * - Rejects invalid subnet masks such as 255.255.255.1 (current code treats that as 255.255.255.0).
+ *
+ * @hide
+ */
+public class DhcpClient extends StateMachine {
+
+    private static final String TAG = "DhcpClient";
+    private static final boolean DBG = true;
+    private static final boolean STATE_DBG = false;
+    private static final boolean MSG_DBG = false;
+    private static final boolean PACKET_DBG = false;
+
+    // Timers and timeouts.
+    private static final int SECONDS = 1000;
+    private static final int FIRST_TIMEOUT_MS   =   2 * SECONDS;
+    private static final int MAX_TIMEOUT_MS     = 128 * SECONDS;
+
+    // This is not strictly needed, since the client is asynchronous and implements exponential
+    // backoff. It's maintained for backwards compatibility with the previous DHCP code, which was
+    // a blocking operation with a 30-second timeout. We pick 36 seconds so we can send packets at
+    // t=0, t=2, t=6, t=14, t=30, allowing for 10% jitter.
+    private static final int DHCP_TIMEOUT_MS    =  36 * SECONDS;
+
+    // DhcpClient uses IpClient's handler.
+    private static final int PUBLIC_BASE = IpClient.DHCPCLIENT_CMD_BASE;
+
+    /* Commands from controller to start/stop DHCP */
+    public static final int CMD_START_DHCP                  = PUBLIC_BASE + 1;
+    public static final int CMD_STOP_DHCP                   = PUBLIC_BASE + 2;
+
+    /* Notification from DHCP state machine prior to DHCP discovery/renewal */
+    public static final int CMD_PRE_DHCP_ACTION             = PUBLIC_BASE + 3;
+    /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
+     * success/failure */
+    public static final int CMD_POST_DHCP_ACTION            = PUBLIC_BASE + 4;
+    /* Notification from DHCP state machine before quitting */
+    public static final int CMD_ON_QUIT                     = PUBLIC_BASE + 5;
+
+    /* Command from controller to indicate DHCP discovery/renewal can continue
+     * after pre DHCP action is complete */
+    public static final int CMD_PRE_DHCP_ACTION_COMPLETE    = PUBLIC_BASE + 6;
+
+    /* Command and event notification to/from IpManager requesting the setting
+     * (or clearing) of an IPv4 LinkAddress.
+     */
+    public static final int CMD_CLEAR_LINKADDRESS           = PUBLIC_BASE + 7;
+    public static final int CMD_CONFIGURE_LINKADDRESS       = PUBLIC_BASE + 8;
+    public static final int EVENT_LINKADDRESS_CONFIGURED    = PUBLIC_BASE + 9;
+
+    /* Message.arg1 arguments to CMD_POST_DHCP_ACTION notification */
+    public static final int DHCP_SUCCESS = 1;
+    public static final int DHCP_FAILURE = 2;
+
+    // Internal messages.
+    private static final int PRIVATE_BASE         = IpClient.DHCPCLIENT_CMD_BASE + 100;
+    private static final int CMD_KICK             = PRIVATE_BASE + 1;
+    private static final int CMD_RECEIVED_PACKET  = PRIVATE_BASE + 2;
+    private static final int CMD_TIMEOUT          = PRIVATE_BASE + 3;
+    private static final int CMD_RENEW_DHCP       = PRIVATE_BASE + 4;
+    private static final int CMD_REBIND_DHCP      = PRIVATE_BASE + 5;
+    private static final int CMD_EXPIRE_DHCP      = PRIVATE_BASE + 6;
+
+    // For message logging.
+    private static final Class[] sMessageClasses = { DhcpClient.class };
+    private static final SparseArray<String> sMessageNames =
+            MessageUtils.findMessageNames(sMessageClasses);
+
+    // DHCP parameters that we request.
+    /* package */ static final byte[] REQUESTED_PARAMS = new byte[] {
+        DHCP_SUBNET_MASK,
+        DHCP_ROUTER,
+        DHCP_DNS_SERVER,
+        DHCP_DOMAIN_NAME,
+        DHCP_MTU,
+        DHCP_BROADCAST_ADDRESS,  // TODO: currently ignored.
+        DHCP_LEASE_TIME,
+        DHCP_RENEWAL_TIME,
+        DHCP_REBINDING_TIME,
+        DHCP_VENDOR_INFO,
+    };
+
+    // DHCP flag that means "yes, we support unicast."
+    private static final boolean DO_UNICAST   = false;
+
+    // System services / libraries we use.
+    private final Context mContext;
+    private final Random mRandom;
+    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
+
+    // Sockets.
+    // - We use a packet socket to receive, because servers send us packets bound for IP addresses
+    //   which we have not yet configured, and the kernel protocol stack drops these.
+    // - We use a UDP socket to send, so the kernel handles ARP and routing for us (DHCP servers can
+    //   be off-link as well as on-link).
+    private FileDescriptor mPacketSock;
+    private FileDescriptor mUdpSock;
+    private ReceiveThread mReceiveThread;
+
+    // State variables.
+    private final StateMachine mController;
+    private final WakeupMessage mKickAlarm;
+    private final WakeupMessage mTimeoutAlarm;
+    private final WakeupMessage mRenewAlarm;
+    private final WakeupMessage mRebindAlarm;
+    private final WakeupMessage mExpiryAlarm;
+    private final String mIfaceName;
+
+    private boolean mRegisteredForPreDhcpNotification;
+    private InterfaceParams mIface;
+    // TODO: MacAddress-ify more of this class hierarchy.
+    private byte[] mHwAddr;
+    private SocketAddress mInterfaceBroadcastAddr;
+    private int mTransactionId;
+    private long mTransactionStartMillis;
+    private DhcpResults mDhcpLease;
+    private long mDhcpLeaseExpiry;
+    private DhcpResults mOffer;
+
+    // Milliseconds SystemClock timestamps used to record transition times to DhcpBoundState.
+    private long mLastInitEnterTime;
+    private long mLastBoundExitTime;
+
+    // States.
+    private State mStoppedState = new StoppedState();
+    private State mDhcpState = new DhcpState();
+    private State mDhcpInitState = new DhcpInitState();
+    private State mDhcpSelectingState = new DhcpSelectingState();
+    private State mDhcpRequestingState = new DhcpRequestingState();
+    private State mDhcpHaveLeaseState = new DhcpHaveLeaseState();
+    private State mConfiguringInterfaceState = new ConfiguringInterfaceState();
+    private State mDhcpBoundState = new DhcpBoundState();
+    private State mDhcpRenewingState = new DhcpRenewingState();
+    private State mDhcpRebindingState = new DhcpRebindingState();
+    private State mDhcpInitRebootState = new DhcpInitRebootState();
+    private State mDhcpRebootingState = new DhcpRebootingState();
+    private State mWaitBeforeStartState = new WaitBeforeStartState(mDhcpInitState);
+    private State mWaitBeforeRenewalState = new WaitBeforeRenewalState(mDhcpRenewingState);
+
+    private WakeupMessage makeWakeupMessage(String cmdName, int cmd) {
+        cmdName = DhcpClient.class.getSimpleName() + "." + mIfaceName + "." + cmdName;
+        return new WakeupMessage(mContext, getHandler(), cmdName, cmd);
+    }
+
+    // TODO: Take an InterfaceParams instance instead of an interface name String.
+    private DhcpClient(Context context, StateMachine controller, String iface) {
+        super(TAG, controller.getHandler());
+
+        mContext = context;
+        mController = controller;
+        mIfaceName = iface;
+
+        addState(mStoppedState);
+        addState(mDhcpState);
+            addState(mDhcpInitState, mDhcpState);
+            addState(mWaitBeforeStartState, mDhcpState);
+            addState(mDhcpSelectingState, mDhcpState);
+            addState(mDhcpRequestingState, mDhcpState);
+            addState(mDhcpHaveLeaseState, mDhcpState);
+                addState(mConfiguringInterfaceState, mDhcpHaveLeaseState);
+                addState(mDhcpBoundState, mDhcpHaveLeaseState);
+                addState(mWaitBeforeRenewalState, mDhcpHaveLeaseState);
+                addState(mDhcpRenewingState, mDhcpHaveLeaseState);
+                addState(mDhcpRebindingState, mDhcpHaveLeaseState);
+            addState(mDhcpInitRebootState, mDhcpState);
+            addState(mDhcpRebootingState, mDhcpState);
+
+        setInitialState(mStoppedState);
+
+        mRandom = new Random();
+
+        // Used to schedule packet retransmissions.
+        mKickAlarm = makeWakeupMessage("KICK", CMD_KICK);
+        // Used to time out PacketRetransmittingStates.
+        mTimeoutAlarm = makeWakeupMessage("TIMEOUT", CMD_TIMEOUT);
+        // Used to schedule DHCP reacquisition.
+        mRenewAlarm = makeWakeupMessage("RENEW", CMD_RENEW_DHCP);
+        mRebindAlarm = makeWakeupMessage("REBIND", CMD_REBIND_DHCP);
+        mExpiryAlarm = makeWakeupMessage("EXPIRY", CMD_EXPIRE_DHCP);
+    }
+
+    public void registerForPreDhcpNotification() {
+        mRegisteredForPreDhcpNotification = true;
+    }
+
+    public static DhcpClient makeDhcpClient(
+            Context context, StateMachine controller, InterfaceParams ifParams) {
+        DhcpClient client = new DhcpClient(context, controller, ifParams.name);
+        client.mIface = ifParams;
+        client.start();
+        return client;
+    }
+
+    private boolean initInterface() {
+        if (mIface == null) mIface = InterfaceParams.getByName(mIfaceName);
+        if (mIface == null) {
+            Log.e(TAG, "Can't determine InterfaceParams for " + mIfaceName);
+            return false;
+        }
+
+        mHwAddr = mIface.macAddr.toByteArray();
+        mInterfaceBroadcastAddr = makePacketSocketAddress(mIface.index, DhcpPacket.ETHER_BROADCAST);
+        return true;
+    }
+
+    private void startNewTransaction() {
+        mTransactionId = mRandom.nextInt();
+        mTransactionStartMillis = SystemClock.elapsedRealtime();
+    }
+
+    private boolean initSockets() {
+        return initPacketSocket() && initUdpSocket();
+    }
+
+    private boolean initPacketSocket() {
+        try {
+            mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP);
+            SocketAddress addr = makePacketSocketAddress((short) ETH_P_IP, mIface.index);
+            Os.bind(mPacketSock, addr);
+            NetworkUtils.attachDhcpFilter(mPacketSock);
+        } catch(SocketException|ErrnoException e) {
+            Log.e(TAG, "Error creating packet socket", e);
+            return false;
+        }
+        return true;
+    }
+
+    private boolean initUdpSocket() {
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_DHCP);
+        try {
+            mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+            SocketUtils.bindSocketToInterface(mUdpSock, mIfaceName);
+            Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1);
+            Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_BROADCAST, 1);
+            Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_RCVBUF, 0);
+            Os.bind(mUdpSock, Inet4Address.ANY, DhcpPacket.DHCP_CLIENT);
+        } catch(SocketException|ErrnoException e) {
+            Log.e(TAG, "Error creating UDP socket", e);
+            return false;
+        } finally {
+            TrafficStats.setThreadStatsTag(oldTag);
+        }
+        return true;
+    }
+
+    private boolean connectUdpSock(Inet4Address to) {
+        try {
+            Os.connect(mUdpSock, to, DhcpPacket.DHCP_SERVER);
+            return true;
+        } catch (SocketException|ErrnoException e) {
+            Log.e(TAG, "Error connecting UDP socket", e);
+            return false;
+        }
+    }
+
+    private static void closeQuietly(FileDescriptor fd) {
+        try {
+            IoBridge.closeAndSignalBlockedThreads(fd);
+        } catch (IOException ignored) {}
+    }
+
+    private void closeSockets() {
+        closeQuietly(mUdpSock);
+        closeQuietly(mPacketSock);
+    }
+
+    class ReceiveThread extends Thread {
+
+        private final byte[] mPacket = new byte[DhcpPacket.MAX_LENGTH];
+        private volatile boolean mStopped = false;
+
+        public void halt() {
+            mStopped = true;
+            closeSockets();  // Interrupts the read() call the thread is blocked in.
+        }
+
+        @Override
+        public void run() {
+            if (DBG) Log.d(TAG, "Receive thread started");
+            while (!mStopped) {
+                int length = 0;  // Or compiler can't tell it's initialized if a parse error occurs.
+                try {
+                    length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
+                    DhcpPacket packet = null;
+                    packet = DhcpPacket.decodeFullPacket(mPacket, length, DhcpPacket.ENCAP_L2);
+                    if (DBG) Log.d(TAG, "Received packet: " + packet);
+                    sendMessage(CMD_RECEIVED_PACKET, packet);
+                } catch (IOException|ErrnoException e) {
+                    if (!mStopped) {
+                        Log.e(TAG, "Read error", e);
+                        logError(DhcpErrorEvent.RECEIVE_ERROR);
+                    }
+                } catch (DhcpPacket.ParseException e) {
+                    Log.e(TAG, "Can't parse packet: " + e.getMessage());
+                    if (PACKET_DBG) {
+                        Log.d(TAG, HexDump.dumpHexString(mPacket, 0, length));
+                    }
+                    if (e.errorCode == DhcpErrorEvent.DHCP_NO_COOKIE) {
+                        int snetTagId = 0x534e4554;
+                        String bugId = "31850211";
+                        int uid = -1;
+                        String data = DhcpPacket.ParseException.class.getName();
+                        EventLog.writeEvent(snetTagId, bugId, uid, data);
+                    }
+                    logError(e.errorCode);
+                }
+            }
+            if (DBG) Log.d(TAG, "Receive thread stopped");
+        }
+    }
+
+    private short getSecs() {
+        return (short) ((SystemClock.elapsedRealtime() - mTransactionStartMillis) / 1000);
+    }
+
+    private boolean transmitPacket(ByteBuffer buf, String description, int encap, Inet4Address to) {
+        try {
+            if (encap == DhcpPacket.ENCAP_L2) {
+                if (DBG) Log.d(TAG, "Broadcasting " + description);
+                Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr);
+            } else if (encap == DhcpPacket.ENCAP_BOOTP && to.equals(INADDR_BROADCAST)) {
+                if (DBG) Log.d(TAG, "Broadcasting " + description);
+                // We only send L3-encapped broadcasts in DhcpRebindingState,
+                // where we have an IP address and an unconnected UDP socket.
+                //
+                // N.B.: We only need this codepath because DhcpRequestPacket
+                // hardcodes the source IP address to 0.0.0.0. We could reuse
+                // the packet socket if this ever changes.
+                Os.sendto(mUdpSock, buf, 0, to, DhcpPacket.DHCP_SERVER);
+            } else {
+                // It's safe to call getpeername here, because we only send unicast packets if we
+                // have an IP address, and we connect the UDP socket in DhcpBoundState#enter.
+                if (DBG) Log.d(TAG, String.format("Unicasting %s to %s",
+                        description, Os.getpeername(mUdpSock)));
+                Os.write(mUdpSock, buf);
+            }
+        } catch(ErrnoException|IOException e) {
+            Log.e(TAG, "Can't send packet: ", e);
+            return false;
+        }
+        return true;
+    }
+
+    private boolean sendDiscoverPacket() {
+        ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
+                DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
+                DO_UNICAST, REQUESTED_PARAMS);
+        return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST);
+    }
+
+    private boolean sendRequestPacket(
+            Inet4Address clientAddress, Inet4Address requestedAddress,
+            Inet4Address serverAddress, Inet4Address to) {
+        // TODO: should we use the transaction ID from the server?
+        final int encap = INADDR_ANY.equals(clientAddress)
+                ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP;
+
+        ByteBuffer packet = DhcpPacket.buildRequestPacket(
+                encap, mTransactionId, getSecs(), clientAddress,
+                DO_UNICAST, mHwAddr, requestedAddress,
+                serverAddress, REQUESTED_PARAMS, null);
+        String serverStr = (serverAddress != null) ? serverAddress.getHostAddress() : null;
+        String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() +
+                             " request=" + requestedAddress.getHostAddress() +
+                             " serverid=" + serverStr;
+        return transmitPacket(packet, description, encap, to);
+    }
+
+    private void scheduleLeaseTimers() {
+        if (mDhcpLeaseExpiry == 0) {
+            Log.d(TAG, "Infinite lease, no timer scheduling needed");
+            return;
+        }
+
+        final long now = SystemClock.elapsedRealtime();
+
+        // TODO: consider getting the renew and rebind timers from T1 and T2.
+        // See also:
+        //     https://tools.ietf.org/html/rfc2131#section-4.4.5
+        //     https://tools.ietf.org/html/rfc1533#section-9.9
+        //     https://tools.ietf.org/html/rfc1533#section-9.10
+        final long remainingDelay = mDhcpLeaseExpiry - now;
+        final long renewDelay = remainingDelay / 2;
+        final long rebindDelay = remainingDelay * 7 / 8;
+        mRenewAlarm.schedule(now + renewDelay);
+        mRebindAlarm.schedule(now + rebindDelay);
+        mExpiryAlarm.schedule(now + remainingDelay);
+        Log.d(TAG, "Scheduling renewal in " + (renewDelay / 1000) + "s");
+        Log.d(TAG, "Scheduling rebind in " + (rebindDelay / 1000) + "s");
+        Log.d(TAG, "Scheduling expiry in " + (remainingDelay / 1000) + "s");
+    }
+
+    private void notifySuccess() {
+        mController.sendMessage(
+                CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
+    }
+
+    private void notifyFailure() {
+        mController.sendMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0, null);
+    }
+
+    private void acceptDhcpResults(DhcpResults results, String msg) {
+        mDhcpLease = results;
+        mOffer = null;
+        Log.d(TAG, msg + " lease: " + mDhcpLease);
+        notifySuccess();
+    }
+
+    private void clearDhcpState() {
+        mDhcpLease = null;
+        mDhcpLeaseExpiry = 0;
+        mOffer = null;
+    }
+
+    /**
+     * Quit the DhcpStateMachine.
+     *
+     * @hide
+     */
+    public void doQuit() {
+        Log.d(TAG, "doQuit");
+        quit();
+    }
+
+    @Override
+    protected void onQuitting() {
+        Log.d(TAG, "onQuitting");
+        mController.sendMessage(CMD_ON_QUIT);
+    }
+
+    abstract class LoggingState extends State {
+        private long mEnterTimeMs;
+
+        @Override
+        public void enter() {
+            if (STATE_DBG) Log.d(TAG, "Entering state " + getName());
+            mEnterTimeMs = SystemClock.elapsedRealtime();
+        }
+
+        @Override
+        public void exit() {
+            long durationMs = SystemClock.elapsedRealtime() - mEnterTimeMs;
+            logState(getName(), (int) durationMs);
+        }
+
+        private String messageName(int what) {
+            return sMessageNames.get(what, Integer.toString(what));
+        }
+
+        private String messageToString(Message message) {
+            long now = SystemClock.uptimeMillis();
+            return new StringBuilder(" ")
+                    .append(message.getWhen() - now)
+                    .append(messageName(message.what))
+                    .append(" ").append(message.arg1)
+                    .append(" ").append(message.arg2)
+                    .append(" ").append(message.obj)
+                    .toString();
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            if (MSG_DBG) {
+                Log.d(TAG, getName() + messageToString(message));
+            }
+            return NOT_HANDLED;
+        }
+
+        @Override
+        public String getName() {
+            // All DhcpClient's states are inner classes with a well defined name.
+            // Use getSimpleName() and avoid super's getName() creating new String instances.
+            return getClass().getSimpleName();
+        }
+    }
+
+    // Sends CMD_PRE_DHCP_ACTION to the controller, waits for the controller to respond with
+    // CMD_PRE_DHCP_ACTION_COMPLETE, and then transitions to mOtherState.
+    abstract class WaitBeforeOtherState extends LoggingState {
+        protected State mOtherState;
+
+        @Override
+        public void enter() {
+            super.enter();
+            mController.sendMessage(CMD_PRE_DHCP_ACTION);
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            super.processMessage(message);
+            switch (message.what) {
+                case CMD_PRE_DHCP_ACTION_COMPLETE:
+                    transitionTo(mOtherState);
+                    return HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+    }
+
+    class StoppedState extends State {
+        @Override
+        public boolean processMessage(Message message) {
+            switch (message.what) {
+                case CMD_START_DHCP:
+                    if (mRegisteredForPreDhcpNotification) {
+                        transitionTo(mWaitBeforeStartState);
+                    } else {
+                        transitionTo(mDhcpInitState);
+                    }
+                    return HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+    }
+
+    class WaitBeforeStartState extends WaitBeforeOtherState {
+        public WaitBeforeStartState(State otherState) {
+            super();
+            mOtherState = otherState;
+        }
+    }
+
+    class WaitBeforeRenewalState extends WaitBeforeOtherState {
+        public WaitBeforeRenewalState(State otherState) {
+            super();
+            mOtherState = otherState;
+        }
+    }
+
+    class DhcpState extends State {
+        @Override
+        public void enter() {
+            clearDhcpState();
+            if (initInterface() && initSockets()) {
+                mReceiveThread = new ReceiveThread();
+                mReceiveThread.start();
+            } else {
+                notifyFailure();
+                transitionTo(mStoppedState);
+            }
+        }
+
+        @Override
+        public void exit() {
+            if (mReceiveThread != null) {
+                mReceiveThread.halt();  // Also closes sockets.
+                mReceiveThread = null;
+            }
+            clearDhcpState();
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            super.processMessage(message);
+            switch (message.what) {
+                case CMD_STOP_DHCP:
+                    transitionTo(mStoppedState);
+                    return HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+    }
+
+    public boolean isValidPacket(DhcpPacket packet) {
+        // TODO: check checksum.
+        int xid = packet.getTransactionId();
+        if (xid != mTransactionId) {
+            Log.d(TAG, "Unexpected transaction ID " + xid + ", expected " + mTransactionId);
+            return false;
+        }
+        if (!Arrays.equals(packet.getClientMac(), mHwAddr)) {
+            Log.d(TAG, "MAC addr mismatch: got " +
+                    HexDump.toHexString(packet.getClientMac()) + ", expected " +
+                    HexDump.toHexString(packet.getClientMac()));
+            return false;
+        }
+        return true;
+    }
+
+    public void setDhcpLeaseExpiry(DhcpPacket packet) {
+        long leaseTimeMillis = packet.getLeaseTimeMillis();
+        mDhcpLeaseExpiry =
+                (leaseTimeMillis > 0) ? SystemClock.elapsedRealtime() + leaseTimeMillis : 0;
+    }
+
+    /**
+     * Retransmits packets using jittered exponential backoff with an optional timeout. Packet
+     * transmission is triggered by CMD_KICK, which is sent by an AlarmManager alarm. If a subclass
+     * sets mTimeout to a positive value, then timeout() is called by an AlarmManager alarm mTimeout
+     * milliseconds after entering the state. Kicks and timeouts are cancelled when leaving the
+     * state.
+     *
+     * Concrete subclasses must implement sendPacket, which is called when the alarm fires and a
+     * packet needs to be transmitted, and receivePacket, which is triggered by CMD_RECEIVED_PACKET
+     * sent by the receive thread. They may also set mTimeout and implement timeout.
+     */
+    abstract class PacketRetransmittingState extends LoggingState {
+
+        private int mTimer;
+        protected int mTimeout = 0;
+
+        @Override
+        public void enter() {
+            super.enter();
+            initTimer();
+            maybeInitTimeout();
+            sendMessage(CMD_KICK);
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            super.processMessage(message);
+            switch (message.what) {
+                case CMD_KICK:
+                    sendPacket();
+                    scheduleKick();
+                    return HANDLED;
+                case CMD_RECEIVED_PACKET:
+                    receivePacket((DhcpPacket) message.obj);
+                    return HANDLED;
+                case CMD_TIMEOUT:
+                    timeout();
+                    return HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+
+        @Override
+        public void exit() {
+            super.exit();
+            mKickAlarm.cancel();
+            mTimeoutAlarm.cancel();
+        }
+
+        abstract protected boolean sendPacket();
+        abstract protected void receivePacket(DhcpPacket packet);
+        protected void timeout() {}
+
+        protected void initTimer() {
+            mTimer = FIRST_TIMEOUT_MS;
+        }
+
+        protected int jitterTimer(int baseTimer) {
+            int maxJitter = baseTimer / 10;
+            int jitter = mRandom.nextInt(2 * maxJitter) - maxJitter;
+            return baseTimer + jitter;
+        }
+
+        protected void scheduleKick() {
+            long now = SystemClock.elapsedRealtime();
+            long timeout = jitterTimer(mTimer);
+            long alarmTime = now + timeout;
+            mKickAlarm.schedule(alarmTime);
+            mTimer *= 2;
+            if (mTimer > MAX_TIMEOUT_MS) {
+                mTimer = MAX_TIMEOUT_MS;
+            }
+        }
+
+        protected void maybeInitTimeout() {
+            if (mTimeout > 0) {
+                long alarmTime = SystemClock.elapsedRealtime() + mTimeout;
+                mTimeoutAlarm.schedule(alarmTime);
+            }
+        }
+    }
+
+    class DhcpInitState extends PacketRetransmittingState {
+        public DhcpInitState() {
+            super();
+        }
+
+        @Override
+        public void enter() {
+            super.enter();
+            startNewTransaction();
+            mLastInitEnterTime = SystemClock.elapsedRealtime();
+        }
+
+        protected boolean sendPacket() {
+            return sendDiscoverPacket();
+        }
+
+        protected void receivePacket(DhcpPacket packet) {
+            if (!isValidPacket(packet)) return;
+            if (!(packet instanceof DhcpOfferPacket)) return;
+            mOffer = packet.toDhcpResults();
+            if (mOffer != null) {
+                Log.d(TAG, "Got pending lease: " + mOffer);
+                transitionTo(mDhcpRequestingState);
+            }
+        }
+    }
+
+    // Not implemented. We request the first offer we receive.
+    class DhcpSelectingState extends LoggingState {
+    }
+
+    class DhcpRequestingState extends PacketRetransmittingState {
+        public DhcpRequestingState() {
+            mTimeout = DHCP_TIMEOUT_MS / 2;
+        }
+
+        protected boolean sendPacket() {
+            return sendRequestPacket(
+                    INADDR_ANY,                                    // ciaddr
+                    (Inet4Address) mOffer.ipAddress.getAddress(),  // DHCP_REQUESTED_IP
+                    (Inet4Address) mOffer.serverAddress,           // DHCP_SERVER_IDENTIFIER
+                    INADDR_BROADCAST);                             // packet destination address
+        }
+
+        protected void receivePacket(DhcpPacket packet) {
+            if (!isValidPacket(packet)) return;
+            if ((packet instanceof DhcpAckPacket)) {
+                DhcpResults results = packet.toDhcpResults();
+                if (results != null) {
+                    setDhcpLeaseExpiry(packet);
+                    acceptDhcpResults(results, "Confirmed");
+                    transitionTo(mConfiguringInterfaceState);
+                }
+            } else if (packet instanceof DhcpNakPacket) {
+                // TODO: Wait a while before returning into INIT state.
+                Log.d(TAG, "Received NAK, returning to INIT");
+                mOffer = null;
+                transitionTo(mDhcpInitState);
+            }
+        }
+
+        @Override
+        protected void timeout() {
+            // After sending REQUESTs unsuccessfully for a while, go back to init.
+            transitionTo(mDhcpInitState);
+        }
+    }
+
+    class DhcpHaveLeaseState extends State {
+        @Override
+        public boolean processMessage(Message message) {
+            switch (message.what) {
+                case CMD_EXPIRE_DHCP:
+                    Log.d(TAG, "Lease expired!");
+                    notifyFailure();
+                    transitionTo(mDhcpInitState);
+                    return HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+
+        @Override
+        public void exit() {
+            // Clear any extant alarms.
+            mRenewAlarm.cancel();
+            mRebindAlarm.cancel();
+            mExpiryAlarm.cancel();
+            clearDhcpState();
+            // Tell IpManager to clear the IPv4 address. There is no need to
+            // wait for confirmation since any subsequent packets are sent from
+            // INADDR_ANY anyway (DISCOVER, REQUEST).
+            mController.sendMessage(CMD_CLEAR_LINKADDRESS);
+        }
+    }
+
+    class ConfiguringInterfaceState extends LoggingState {
+        @Override
+        public void enter() {
+            super.enter();
+            mController.sendMessage(CMD_CONFIGURE_LINKADDRESS, mDhcpLease.ipAddress);
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            super.processMessage(message);
+            switch (message.what) {
+                case EVENT_LINKADDRESS_CONFIGURED:
+                    transitionTo(mDhcpBoundState);
+                    return HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+    }
+
+    class DhcpBoundState extends LoggingState {
+        @Override
+        public void enter() {
+            super.enter();
+            if (mDhcpLease.serverAddress != null && !connectUdpSock(mDhcpLease.serverAddress)) {
+                // There's likely no point in going into DhcpInitState here, we'll probably
+                // just repeat the transaction, get the same IP address as before, and fail.
+                //
+                // NOTE: It is observed that connectUdpSock() basically never fails, due to
+                // SO_BINDTODEVICE. Examining the local socket address shows it will happily
+                // return an IPv4 address from another interface, or even return "0.0.0.0".
+                //
+                // TODO: Consider deleting this check, following testing on several kernels.
+                notifyFailure();
+                transitionTo(mStoppedState);
+            }
+
+            scheduleLeaseTimers();
+            logTimeToBoundState();
+        }
+
+        @Override
+        public void exit() {
+            super.exit();
+            mLastBoundExitTime = SystemClock.elapsedRealtime();
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            super.processMessage(message);
+            switch (message.what) {
+                case CMD_RENEW_DHCP:
+                    if (mRegisteredForPreDhcpNotification) {
+                        transitionTo(mWaitBeforeRenewalState);
+                    } else {
+                        transitionTo(mDhcpRenewingState);
+                    }
+                    return HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+
+        private void logTimeToBoundState() {
+            long now = SystemClock.elapsedRealtime();
+            if (mLastBoundExitTime > mLastInitEnterTime) {
+                logState(DhcpClientEvent.RENEWING_BOUND, (int)(now - mLastBoundExitTime));
+            } else {
+                logState(DhcpClientEvent.INITIAL_BOUND, (int)(now - mLastInitEnterTime));
+            }
+        }
+    }
+
+    abstract class DhcpReacquiringState extends PacketRetransmittingState {
+        protected String mLeaseMsg;
+
+        @Override
+        public void enter() {
+            super.enter();
+            startNewTransaction();
+        }
+
+        abstract protected Inet4Address packetDestination();
+
+        protected boolean sendPacket() {
+            return sendRequestPacket(
+                    (Inet4Address) mDhcpLease.ipAddress.getAddress(),  // ciaddr
+                    INADDR_ANY,                                        // DHCP_REQUESTED_IP
+                    null,                                              // DHCP_SERVER_IDENTIFIER
+                    packetDestination());                              // packet destination address
+        }
+
+        protected void receivePacket(DhcpPacket packet) {
+            if (!isValidPacket(packet)) return;
+            if ((packet instanceof DhcpAckPacket)) {
+                final DhcpResults results = packet.toDhcpResults();
+                if (results != null) {
+                    if (!mDhcpLease.ipAddress.equals(results.ipAddress)) {
+                        Log.d(TAG, "Renewed lease not for our current IP address!");
+                        notifyFailure();
+                        transitionTo(mDhcpInitState);
+                    }
+                    setDhcpLeaseExpiry(packet);
+                    // Updating our notion of DhcpResults here only causes the
+                    // DNS servers and routes to be updated in LinkProperties
+                    // in IpManager and by any overridden relevant handlers of
+                    // the registered IpManager.Callback.  IP address changes
+                    // are not supported here.
+                    acceptDhcpResults(results, mLeaseMsg);
+                    transitionTo(mDhcpBoundState);
+                }
+            } else if (packet instanceof DhcpNakPacket) {
+                Log.d(TAG, "Received NAK, returning to INIT");
+                notifyFailure();
+                transitionTo(mDhcpInitState);
+            }
+        }
+    }
+
+    class DhcpRenewingState extends DhcpReacquiringState {
+        public DhcpRenewingState() {
+            mLeaseMsg = "Renewed";
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            if (super.processMessage(message) == HANDLED) {
+                return HANDLED;
+            }
+
+            switch (message.what) {
+                case CMD_REBIND_DHCP:
+                    transitionTo(mDhcpRebindingState);
+                    return HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+
+        @Override
+        protected Inet4Address packetDestination() {
+            // Not specifying a SERVER_IDENTIFIER option is a violation of RFC 2131, but...
+            // http://b/25343517 . Try to make things work anyway by using broadcast renews.
+            return (mDhcpLease.serverAddress != null) ?
+                    mDhcpLease.serverAddress : INADDR_BROADCAST;
+        }
+    }
+
+    class DhcpRebindingState extends DhcpReacquiringState {
+        public DhcpRebindingState() {
+            mLeaseMsg = "Rebound";
+        }
+
+        @Override
+        public void enter() {
+            super.enter();
+
+            // We need to broadcast and possibly reconnect the socket to a
+            // completely different server.
+            closeQuietly(mUdpSock);
+            if (!initUdpSocket()) {
+                Log.e(TAG, "Failed to recreate UDP socket");
+                transitionTo(mDhcpInitState);
+            }
+        }
+
+        @Override
+        protected Inet4Address packetDestination() {
+            return INADDR_BROADCAST;
+        }
+    }
+
+    class DhcpInitRebootState extends LoggingState {
+    }
+
+    class DhcpRebootingState extends LoggingState {
+    }
+
+    private void logError(int errorCode) {
+        mMetricsLog.log(mIfaceName, new DhcpErrorEvent(errorCode));
+    }
+
+    private void logState(String name, int durationMs) {
+        final DhcpClientEvent event = new DhcpClientEvent.Builder()
+                .setMsg(name)
+                .setDurationMs(durationMs)
+                .build();
+        mMetricsLog.log(mIfaceName, event);
+    }
+}
diff --git a/services/net/java/android/net/dhcp/DhcpDeclinePacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpDeclinePacket.java
similarity index 100%
rename from services/net/java/android/net/dhcp/DhcpDeclinePacket.java
rename to packages/NetworkStack/src/android/net/dhcp/DhcpDeclinePacket.java
diff --git a/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpDiscoverPacket.java
similarity index 100%
rename from services/net/java/android/net/dhcp/DhcpDiscoverPacket.java
rename to packages/NetworkStack/src/android/net/dhcp/DhcpDiscoverPacket.java
diff --git a/services/net/java/android/net/dhcp/DhcpInformPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpInformPacket.java
similarity index 100%
rename from services/net/java/android/net/dhcp/DhcpInformPacket.java
rename to packages/NetworkStack/src/android/net/dhcp/DhcpInformPacket.java
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpLease.java b/packages/NetworkStack/src/android/net/dhcp/DhcpLease.java
new file mode 100644
index 0000000..6849cfa
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpLease.java
@@ -0,0 +1,153 @@
+/*
+ * 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.dhcp;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.MacAddress;
+import android.os.SystemClock;
+import android.text.TextUtils;
+
+import com.android.internal.util.HexDump;
+
+import java.net.Inet4Address;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * An IPv4 address assignment done through DHCPv4.
+ * @hide
+ */
+public class DhcpLease {
+    public static final long EXPIRATION_NEVER = Long.MAX_VALUE;
+    public static final String HOSTNAME_NONE = null;
+
+    @Nullable
+    private final byte[] mClientId;
+    @NonNull
+    private final MacAddress mHwAddr;
+    @NonNull
+    private final Inet4Address mNetAddr;
+    /**
+     * Expiration time for the lease, to compare with {@link SystemClock#elapsedRealtime()}.
+     */
+    private final long mExpTime;
+    @Nullable
+    private final String mHostname;
+
+    public DhcpLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
+            @NonNull Inet4Address netAddr, long expTime, @Nullable String hostname) {
+        mClientId = (clientId == null ? null : Arrays.copyOf(clientId, clientId.length));
+        mHwAddr = hwAddr;
+        mNetAddr = netAddr;
+        mExpTime = expTime;
+        mHostname = hostname;
+    }
+
+    /**
+     * Get the clientId associated with this lease, if any.
+     *
+     * <p>If the lease is not associated to a clientId, this returns null.
+     */
+    @Nullable
+    public byte[] getClientId() {
+        if (mClientId == null) {
+            return null;
+        }
+        return Arrays.copyOf(mClientId, mClientId.length);
+    }
+
+    @NonNull
+    public MacAddress getHwAddr() {
+        return mHwAddr;
+    }
+
+    @Nullable
+    public String getHostname() {
+        return mHostname;
+    }
+
+    @NonNull
+    public Inet4Address getNetAddr() {
+        return mNetAddr;
+    }
+
+    public long getExpTime() {
+        return mExpTime;
+    }
+
+    /**
+     * Push back the expiration time of this lease. If the provided time is sooner than the original
+     * expiration time, the lease time will not be updated.
+     *
+     * <p>The lease hostname is updated with the provided one if set.
+     * @return A {@link DhcpLease} with expiration time set to max(expTime, currentExpTime)
+     */
+    public DhcpLease renewedLease(long expTime, @Nullable String hostname) {
+        return new DhcpLease(mClientId, mHwAddr, mNetAddr, Math.max(expTime, mExpTime),
+                (hostname == null ? mHostname : hostname));
+    }
+
+    /**
+     * Determine whether this lease matches a client with the specified parameters.
+     * @param clientId clientId of the client if any, or null otherwise.
+     * @param hwAddr Hardware address of the client.
+     */
+    public boolean matchesClient(@Nullable byte[] clientId, @NonNull MacAddress hwAddr) {
+        if (mClientId != null) {
+            return Arrays.equals(mClientId, clientId);
+        } else {
+            return clientId == null && mHwAddr.equals(hwAddr);
+        }
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof DhcpLease)) {
+            return false;
+        }
+        final DhcpLease other = (DhcpLease) obj;
+        return Arrays.equals(mClientId, other.mClientId)
+                && mHwAddr.equals(other.mHwAddr)
+                && mNetAddr.equals(other.mNetAddr)
+                && mExpTime == other.mExpTime
+                && TextUtils.equals(mHostname, other.mHostname);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mClientId, mHwAddr, mNetAddr, mHostname, mExpTime);
+    }
+
+    static String clientIdToString(byte[] bytes) {
+        if (bytes == null) {
+            return "null";
+        }
+        return HexDump.toHexString(bytes);
+    }
+
+    static String inet4AddrToString(@Nullable Inet4Address addr) {
+        return (addr == null) ? "null" : addr.getHostAddress();
+    }
+
+    @Override
+    public String toString() {
+        return String.format("clientId: %s, hwAddr: %s, netAddr: %s, expTime: %d, hostname: %s",
+                clientIdToString(mClientId), mHwAddr.toString(), inet4AddrToString(mNetAddr),
+                mExpTime, mHostname);
+    }
+}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java b/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java
new file mode 100644
index 0000000..0d298de
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java
@@ -0,0 +1,545 @@
+/*
+ * 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.dhcp;
+
+import static android.net.NetworkUtils.inet4AddressToIntHTH;
+import static android.net.NetworkUtils.intToInet4AddressHTH;
+import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH;
+import static android.net.dhcp.DhcpLease.EXPIRATION_NEVER;
+import static android.net.dhcp.DhcpLease.inet4AddrToString;
+
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_BITS;
+
+import static java.lang.Math.min;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.IpPrefix;
+import android.net.MacAddress;
+import android.net.dhcp.DhcpServer.Clock;
+import android.net.util.SharedLog;
+import android.util.ArrayMap;
+
+import java.net.Inet4Address;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.function.Function;
+
+/**
+ * A repository managing IPv4 address assignments through DHCPv4.
+ *
+ * <p>This class is not thread-safe. All public methods should be called on a common thread or
+ * use some synchronization mechanism.
+ *
+ * <p>Methods are optimized for a small number of allocated leases, assuming that most of the time
+ * only 2~10 addresses will be allocated, which is the common case. Managing a large number of
+ * addresses is supported but will be slower: some operations have complexity in O(num_leases).
+ * @hide
+ */
+class DhcpLeaseRepository {
+    public static final byte[] CLIENTID_UNSPEC = null;
+    public static final Inet4Address INETADDR_UNSPEC = null;
+
+    @NonNull
+    private final SharedLog mLog;
+    @NonNull
+    private final Clock mClock;
+
+    @NonNull
+    private IpPrefix mPrefix;
+    @NonNull
+    private Set<Inet4Address> mReservedAddrs;
+    private int mSubnetAddr;
+    private int mSubnetMask;
+    private int mNumAddresses;
+    private long mLeaseTimeMs;
+
+    /**
+     * Next timestamp when committed or declined leases should be checked for expired ones. This
+     * will always be lower than or equal to the time for the first lease to expire: it's OK not to
+     * update this when removing entries, but it must always be updated when adding/updating.
+     */
+    private long mNextExpirationCheck = EXPIRATION_NEVER;
+
+    static class DhcpLeaseException extends Exception {
+        DhcpLeaseException(String message) {
+            super(message);
+        }
+    }
+
+    static class OutOfAddressesException extends DhcpLeaseException {
+        OutOfAddressesException(String message) {
+            super(message);
+        }
+    }
+
+    static class InvalidAddressException extends DhcpLeaseException {
+        InvalidAddressException(String message) {
+            super(message);
+        }
+    }
+
+    static class InvalidSubnetException extends DhcpLeaseException {
+        InvalidSubnetException(String message) {
+            super(message);
+        }
+    }
+
+    /**
+     * Leases by IP address
+     */
+    private final ArrayMap<Inet4Address, DhcpLease> mCommittedLeases = new ArrayMap<>();
+
+    /**
+     * Map address -> expiration timestamp in ms. Addresses are guaranteed to be valid as defined
+     * by {@link #isValidAddress(Inet4Address)}, but are not necessarily otherwise available for
+     * assignment.
+     */
+    private final LinkedHashMap<Inet4Address, Long> mDeclinedAddrs = new LinkedHashMap<>();
+
+    DhcpLeaseRepository(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs,
+            long leaseTimeMs, @NonNull SharedLog log, @NonNull Clock clock) {
+        updateParams(prefix, reservedAddrs, leaseTimeMs);
+        mLog = log;
+        mClock = clock;
+    }
+
+    public void updateParams(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs,
+            long leaseTimeMs) {
+        mPrefix = prefix;
+        mReservedAddrs = Collections.unmodifiableSet(new HashSet<>(reservedAddrs));
+        mSubnetMask = prefixLengthToV4NetmaskIntHTH(prefix.getPrefixLength());
+        mSubnetAddr = inet4AddressToIntHTH((Inet4Address) prefix.getAddress()) & mSubnetMask;
+        mNumAddresses = 1 << (IPV4_ADDR_BITS - prefix.getPrefixLength());
+        mLeaseTimeMs = leaseTimeMs;
+
+        cleanMap(mCommittedLeases);
+        cleanMap(mDeclinedAddrs);
+    }
+
+    /**
+     * From a map keyed by {@link Inet4Address}, remove entries where the key is invalid (as
+     * specified by {@link #isValidAddress(Inet4Address)}), or is a reserved address.
+     */
+    private <T> void cleanMap(Map<Inet4Address, T> map) {
+        final Iterator<Entry<Inet4Address, T>> it = map.entrySet().iterator();
+        while (it.hasNext()) {
+            final Inet4Address addr = it.next().getKey();
+            if (!isValidAddress(addr) || mReservedAddrs.contains(addr)) {
+                it.remove();
+            }
+        }
+    }
+
+    /**
+     * Get a DHCP offer, to reply to a DHCPDISCOVER. Follows RFC2131 #4.3.1.
+     *
+     * @param clientId Client identifier option if specified, or {@link #CLIENTID_UNSPEC}
+     * @param relayAddr Internet address of the relay (giaddr), can be {@link Inet4Address#ANY}
+     * @param reqAddr Requested address by the client (option 50), or {@link #INETADDR_UNSPEC}
+     * @param hostname Client-provided hostname, or {@link DhcpLease#HOSTNAME_NONE}
+     * @throws OutOfAddressesException The server does not have any available address
+     * @throws InvalidSubnetException The lease was requested from an unsupported subnet
+     */
+    @NonNull
+    public DhcpLease getOffer(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
+            @NonNull Inet4Address relayAddr, @Nullable Inet4Address reqAddr,
+            @Nullable String hostname) throws OutOfAddressesException, InvalidSubnetException {
+        final long currentTime = mClock.elapsedRealtime();
+        final long expTime = currentTime + mLeaseTimeMs;
+
+        removeExpiredLeases(currentTime);
+        checkValidRelayAddr(relayAddr);
+
+        final DhcpLease currentLease = findByClient(clientId, hwAddr);
+        final DhcpLease newLease;
+        if (currentLease != null) {
+            newLease = currentLease.renewedLease(expTime, hostname);
+            mLog.log("Offering extended lease " + newLease);
+            // Do not update lease time in the map: the offer is not committed yet.
+        } else if (reqAddr != null && isValidAddress(reqAddr) && isAvailable(reqAddr)) {
+            newLease = new DhcpLease(clientId, hwAddr, reqAddr, expTime, hostname);
+            mLog.log("Offering requested lease " + newLease);
+        } else {
+            newLease = makeNewOffer(clientId, hwAddr, expTime, hostname);
+            mLog.log("Offering new generated lease " + newLease);
+        }
+        return newLease;
+    }
+
+    private void checkValidRelayAddr(@Nullable Inet4Address relayAddr)
+            throws InvalidSubnetException {
+        // As per #4.3.1, addresses are assigned based on the relay address if present. This
+        // implementation only assigns addresses if the relayAddr is inside our configured subnet.
+        // This also applies when the client requested a specific address for consistency between
+        // requests, and with older behavior.
+        if (isIpAddrOutsidePrefix(mPrefix, relayAddr)) {
+            throw new InvalidSubnetException("Lease requested by relay from outside of subnet");
+        }
+    }
+
+    private static boolean isIpAddrOutsidePrefix(@NonNull IpPrefix prefix,
+            @Nullable Inet4Address addr) {
+        return addr != null && !addr.equals(Inet4Address.ANY) && !prefix.contains(addr);
+    }
+
+    @Nullable
+    private DhcpLease findByClient(@Nullable byte[] clientId, @NonNull MacAddress hwAddr) {
+        for (DhcpLease lease : mCommittedLeases.values()) {
+            if (lease.matchesClient(clientId, hwAddr)) {
+                return lease;
+            }
+        }
+
+        // Note this differs from dnsmasq behavior, which would match by hwAddr if clientId was
+        // given but no lease keyed on clientId matched. This would prevent one interface from
+        // obtaining multiple leases with different clientId.
+        return null;
+    }
+
+    /**
+     * Make a lease conformant to a client DHCPREQUEST or renew the client's existing lease,
+     * commit it to the repository and return it.
+     *
+     * <p>This method always succeeds and commits the lease if it does not throw, and has no side
+     * effects if it throws.
+     *
+     * @param clientId Client identifier option if specified, or {@link #CLIENTID_UNSPEC}
+     * @param reqAddr Requested address by the client (option 50), or {@link #INETADDR_UNSPEC}
+     * @param sidSet Whether the server identifier was set in the request
+     * @return The newly created or renewed lease
+     * @throws InvalidAddressException The client provided an address that conflicts with its
+     *                                 current configuration, or other committed/reserved leases.
+     */
+    @NonNull
+    public DhcpLease requestLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
+            @NonNull Inet4Address clientAddr, @NonNull Inet4Address relayAddr,
+            @Nullable Inet4Address reqAddr, boolean sidSet, @Nullable String hostname)
+            throws InvalidAddressException, InvalidSubnetException {
+        final long currentTime = mClock.elapsedRealtime();
+        removeExpiredLeases(currentTime);
+        checkValidRelayAddr(relayAddr);
+        final DhcpLease assignedLease = findByClient(clientId, hwAddr);
+
+        final Inet4Address leaseAddr = reqAddr != null ? reqAddr : clientAddr;
+        if (assignedLease != null) {
+            if (sidSet && reqAddr != null) {
+                // Client in SELECTING state; remove any current lease before creating a new one.
+                mCommittedLeases.remove(assignedLease.getNetAddr());
+            } else if (!assignedLease.getNetAddr().equals(leaseAddr)) {
+                // reqAddr null (RENEWING/REBINDING): client renewing its own lease for clientAddr.
+                // reqAddr set with sid not set (INIT-REBOOT): client verifying configuration.
+                // In both cases, throw if clientAddr or reqAddr does not match the known lease.
+                throw new InvalidAddressException("Incorrect address for client in "
+                        + (reqAddr != null ? "INIT-REBOOT" : "RENEWING/REBINDING"));
+            }
+        }
+
+        // In the init-reboot case, RFC2131 #4.3.2 says that the server must not reply if
+        // assignedLease == null, but dnsmasq will let the client use the requested address if
+        // available, when configured with --dhcp-authoritative. This is preferable to avoid issues
+        // if the server lost the lease DB: the client would not get a reply because the server
+        // does not know their lease.
+        // Similarly in RENEWING/REBINDING state, create a lease when possible if the
+        // client-provided lease is unknown.
+        final DhcpLease lease =
+                checkClientAndMakeLease(clientId, hwAddr, leaseAddr, hostname, currentTime);
+        mLog.logf("DHCPREQUEST assignedLease %s, reqAddr=%s, sidSet=%s: created/renewed lease %s",
+                assignedLease, inet4AddrToString(reqAddr), sidSet, lease);
+        return lease;
+    }
+
+    /**
+     * Check that the client can request the specified address, make or renew the lease if yes, and
+     * commit it.
+     *
+     * <p>This method always succeeds and returns the lease if it does not throw, and has no
+     * side-effect if it throws.
+     *
+     * @return The newly created or renewed, committed lease
+     * @throws InvalidAddressException The client provided an address that conflicts with its
+     *                                 current configuration, or other committed/reserved leases.
+     */
+    private DhcpLease checkClientAndMakeLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
+            @NonNull Inet4Address addr, @Nullable String hostname, long currentTime)
+            throws InvalidAddressException {
+        final long expTime = currentTime + mLeaseTimeMs;
+        final DhcpLease currentLease = mCommittedLeases.getOrDefault(addr, null);
+        if (currentLease != null && !currentLease.matchesClient(clientId, hwAddr)) {
+            throw new InvalidAddressException("Address in use");
+        }
+
+        final DhcpLease lease;
+        if (currentLease == null) {
+            if (isValidAddress(addr) && !mReservedAddrs.contains(addr)) {
+                lease = new DhcpLease(clientId, hwAddr, addr, expTime, hostname);
+            } else {
+                throw new InvalidAddressException("Lease not found and address unavailable");
+            }
+        } else {
+            lease = currentLease.renewedLease(expTime, hostname);
+        }
+        commitLease(lease);
+        return lease;
+    }
+
+    private void commitLease(@NonNull DhcpLease lease) {
+        mCommittedLeases.put(lease.getNetAddr(), lease);
+        maybeUpdateEarliestExpiration(lease.getExpTime());
+    }
+
+    /**
+     * Delete a committed lease from the repository.
+     *
+     * @return true if a lease matching parameters was found.
+     */
+    public boolean releaseLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
+            @NonNull Inet4Address addr) {
+        final DhcpLease currentLease = mCommittedLeases.getOrDefault(addr, null);
+        if (currentLease == null) {
+            mLog.w("Could not release unknown lease for " + inet4AddrToString(addr));
+            return false;
+        }
+        if (currentLease.matchesClient(clientId, hwAddr)) {
+            mCommittedLeases.remove(addr);
+            mLog.log("Released lease " + currentLease);
+            return true;
+        }
+        mLog.w(String.format("Not releasing lease %s: does not match client (cid %s, hwAddr %s)",
+                currentLease, DhcpLease.clientIdToString(clientId), hwAddr));
+        return false;
+    }
+
+    public void markLeaseDeclined(@NonNull Inet4Address addr) {
+        if (mDeclinedAddrs.containsKey(addr) || !isValidAddress(addr)) {
+            mLog.logf("Not marking %s as declined: already declined or not assignable",
+                    inet4AddrToString(addr));
+            return;
+        }
+        final long expTime = mClock.elapsedRealtime() + mLeaseTimeMs;
+        mDeclinedAddrs.put(addr, expTime);
+        mLog.logf("Marked %s as declined expiring %d", inet4AddrToString(addr), expTime);
+        maybeUpdateEarliestExpiration(expTime);
+    }
+
+    /**
+     * Get the list of currently valid committed leases in the repository.
+     */
+    @NonNull
+    public List<DhcpLease> getCommittedLeases() {
+        removeExpiredLeases(mClock.elapsedRealtime());
+        return new ArrayList<>(mCommittedLeases.values());
+    }
+
+    /**
+     * Get the set of addresses that have been marked as declined in the repository.
+     */
+    @NonNull
+    public Set<Inet4Address> getDeclinedAddresses() {
+        removeExpiredLeases(mClock.elapsedRealtime());
+        return new HashSet<>(mDeclinedAddrs.keySet());
+    }
+
+    /**
+     * Given the expiration time of a new committed lease or declined address, update
+     * {@link #mNextExpirationCheck} so it stays lower than or equal to the time for the first lease
+     * to expire.
+     */
+    private void maybeUpdateEarliestExpiration(long expTime) {
+        if (expTime < mNextExpirationCheck) {
+            mNextExpirationCheck = expTime;
+        }
+    }
+
+    /**
+     * Remove expired entries from a map keyed by {@link Inet4Address}.
+     *
+     * @param tag Type of lease in the map, for logging
+     * @param getExpTime Functor returning the expiration time for an object in the map.
+     *                   Must not return null.
+     * @return The lowest expiration time among entries remaining in the map
+     */
+    private <T> long removeExpired(long currentTime, @NonNull Map<Inet4Address, T> map,
+            @NonNull String tag, @NonNull Function<T, Long> getExpTime) {
+        final Iterator<Entry<Inet4Address, T>> it = map.entrySet().iterator();
+        long firstExpiration = EXPIRATION_NEVER;
+        while (it.hasNext()) {
+            final Entry<Inet4Address, T> lease = it.next();
+            final long expTime = getExpTime.apply(lease.getValue());
+            if (expTime <= currentTime) {
+                mLog.logf("Removing expired %s lease for %s (expTime=%s, currentTime=%s)",
+                        tag, lease.getKey(), expTime, currentTime);
+                it.remove();
+            } else {
+                firstExpiration = min(firstExpiration, expTime);
+            }
+        }
+        return firstExpiration;
+    }
+
+    /**
+     * Go through committed and declined leases and remove the expired ones.
+     */
+    private void removeExpiredLeases(long currentTime) {
+        if (currentTime < mNextExpirationCheck) {
+            return;
+        }
+
+        final long commExp = removeExpired(
+                currentTime, mCommittedLeases, "committed", DhcpLease::getExpTime);
+        final long declExp = removeExpired(
+                currentTime, mDeclinedAddrs, "declined", Function.identity());
+
+        mNextExpirationCheck = min(commExp, declExp);
+    }
+
+    private boolean isAvailable(@NonNull Inet4Address addr) {
+        return !mReservedAddrs.contains(addr) && !mCommittedLeases.containsKey(addr);
+    }
+
+    /**
+     * Get the 0-based index of an address in the subnet.
+     *
+     * <p>Given ordering of addresses 5.6.7.8 < 5.6.7.9 < 5.6.8.0, the index on a subnet is defined
+     * so that the first address is 0, the second 1, etc. For example on a /16, 192.168.0.0 -> 0,
+     * 192.168.0.1 -> 1, 192.168.1.0 -> 256
+     *
+     */
+    private int getAddrIndex(int addr) {
+        return addr & ~mSubnetMask;
+    }
+
+    private int getAddrByIndex(int index) {
+        return mSubnetAddr | index;
+    }
+
+    /**
+     * Get a valid address starting from the supplied one.
+     *
+     * <p>This only checks that the address is numerically valid for assignment, not whether it is
+     * already in use. The return value is always inside the configured prefix, even if the supplied
+     * address is not.
+     *
+     * <p>If the provided address is valid, it is returned as-is. Otherwise, the next valid
+     * address (with the ordering in {@link #getAddrIndex(int)}) is returned.
+     */
+    private int getValidAddress(int addr) {
+        final int lastByteMask = 0xff;
+        int addrIndex = getAddrIndex(addr); // 0-based index of the address in the subnet
+
+        // Some OSes do not handle addresses in .255 or .0 correctly: avoid those.
+        final int lastByte = getAddrByIndex(addrIndex) & lastByteMask;
+        if (lastByte == lastByteMask) {
+            // Avoid .255 address, and .0 address that follows
+            addrIndex = (addrIndex + 2) % mNumAddresses;
+        } else if (lastByte == 0) {
+            // Avoid .0 address
+            addrIndex = (addrIndex + 1) % mNumAddresses;
+        }
+
+        // Do not use first or last address of range
+        if (addrIndex == 0 || addrIndex == mNumAddresses - 1) {
+            // Always valid and not end of range since prefixLength is at most 30 in serving params
+            addrIndex = 1;
+        }
+        return getAddrByIndex(addrIndex);
+    }
+
+    /**
+     * Returns whether the address is in the configured subnet and part of the assignable range.
+     */
+    private boolean isValidAddress(Inet4Address addr) {
+        final int intAddr = inet4AddressToIntHTH(addr);
+        return getValidAddress(intAddr) == intAddr;
+    }
+
+    private int getNextAddress(int addr) {
+        final int addrIndex = getAddrIndex(addr);
+        final int nextAddress = getAddrByIndex((addrIndex + 1) % mNumAddresses);
+        return getValidAddress(nextAddress);
+    }
+
+    /**
+     * Calculate a first candidate address for a client by hashing the hardware address.
+     *
+     * <p>This will be a valid address as checked by {@link #getValidAddress(int)}, but may be
+     * in use.
+     *
+     * @return An IPv4 address encoded as 32-bit int
+     */
+    private int getFirstClientAddress(MacAddress hwAddr) {
+        // This follows dnsmasq behavior. Advantages are: clients will often get the same
+        // offers for different DISCOVER even if the lease was not yet accepted or has expired,
+        // and address generation will generally not need to loop through many allocated addresses
+        // until it finds a free one.
+        int hash = 0;
+        for (byte b : hwAddr.toByteArray()) {
+            hash += b + (b << 8) + (b << 16);
+        }
+        // This implementation will not always result in the same IPs as dnsmasq would give out in
+        // Android <= P, because it includes invalid and reserved addresses in mNumAddresses while
+        // the configured ranges for dnsmasq did not.
+        final int addrIndex = hash % mNumAddresses;
+        return getValidAddress(getAddrByIndex(addrIndex));
+    }
+
+    /**
+     * Create a lease that can be offered to respond to a client DISCOVER.
+     *
+     * <p>This method always succeeds and returns the lease if it does not throw. If no non-declined
+     * address is available, it will try to offer the oldest declined address if valid.
+     *
+     * @throws OutOfAddressesException The server has no address left to offer
+     */
+    private DhcpLease makeNewOffer(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
+            long expTime, @Nullable String hostname) throws OutOfAddressesException {
+        int intAddr = getFirstClientAddress(hwAddr);
+        // Loop until a free address is found, or there are no more addresses.
+        // There is slightly less than this many usable addresses, but some extra looping is OK
+        for (int i = 0; i < mNumAddresses; i++) {
+            final Inet4Address addr = intToInet4AddressHTH(intAddr);
+            if (isAvailable(addr) && !mDeclinedAddrs.containsKey(addr)) {
+                return new DhcpLease(clientId, hwAddr, addr, expTime, hostname);
+            }
+            intAddr = getNextAddress(intAddr);
+        }
+
+        // Try freeing DECLINEd addresses if out of addresses.
+        final Iterator<Inet4Address> it = mDeclinedAddrs.keySet().iterator();
+        while (it.hasNext()) {
+            final Inet4Address addr = it.next();
+            it.remove();
+            mLog.logf("Out of addresses in address pool: dropped declined addr %s",
+                    inet4AddrToString(addr));
+            // isValidAddress() is always verified for entries in mDeclinedAddrs.
+            // However declined addresses may have been requested (typically by the machine that was
+            // already using the address) after being declined.
+            if (isAvailable(addr)) {
+                return new DhcpLease(clientId, hwAddr, addr, expTime, hostname);
+            }
+        }
+
+        throw new OutOfAddressesException("No address available for offer");
+    }
+}
diff --git a/services/net/java/android/net/dhcp/DhcpNakPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpNakPacket.java
similarity index 100%
rename from services/net/java/android/net/dhcp/DhcpNakPacket.java
rename to packages/NetworkStack/src/android/net/dhcp/DhcpNakPacket.java
diff --git a/services/net/java/android/net/dhcp/DhcpOfferPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpOfferPacket.java
similarity index 100%
rename from services/net/java/android/net/dhcp/DhcpOfferPacket.java
rename to packages/NetworkStack/src/android/net/dhcp/DhcpOfferPacket.java
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
new file mode 100644
index 0000000..ce8b7e7
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
@@ -0,0 +1,1364 @@
+package android.net.dhcp;
+
+import android.annotation.Nullable;
+import android.net.DhcpResults;
+import android.net.LinkAddress;
+import android.net.NetworkUtils;
+import android.net.metrics.DhcpErrorEvent;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.system.OsConstants;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.UnsupportedEncodingException;
+import java.net.Inet4Address;
+import java.net.UnknownHostException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ShortBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Defines basic data and operations needed to build and use packets for the
+ * DHCP protocol.  Subclasses create the specific packets used at each
+ * stage of the negotiation.
+ *
+ * @hide
+ */
+public abstract class DhcpPacket {
+    protected static final String TAG = "DhcpPacket";
+
+    // TODO: use NetworkStackConstants.IPV4_MIN_MTU once this class is moved to the network stack.
+    private static final int IPV4_MIN_MTU = 68;
+
+    // dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the
+    // CPU for anything shorter than 5 minutes. For sanity's sake, this must be higher than the
+    // DHCP client timeout.
+    public static final int MINIMUM_LEASE = 60;
+    public static final int INFINITE_LEASE = (int) 0xffffffff;
+
+    public static final Inet4Address INADDR_ANY = (Inet4Address) Inet4Address.ANY;
+    public static final Inet4Address INADDR_BROADCAST = (Inet4Address) Inet4Address.ALL;
+    public static final byte[] ETHER_BROADCAST = new byte[] {
+            (byte) 0xff, (byte) 0xff, (byte) 0xff,
+            (byte) 0xff, (byte) 0xff, (byte) 0xff,
+    };
+
+    /**
+     * Packet encapsulations.
+     */
+    public static final int ENCAP_L2 = 0;    // EthernetII header included
+    public static final int ENCAP_L3 = 1;    // IP/UDP header included
+    public static final int ENCAP_BOOTP = 2; // BOOTP contents only
+
+    /**
+     * Minimum length of a DHCP packet, excluding options, in the above encapsulations.
+     */
+    public static final int MIN_PACKET_LENGTH_BOOTP = 236;  // See diagram in RFC 2131, section 2.
+    public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8;
+    public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14;
+
+    public static final int HWADDR_LEN = 16;
+    public static final int MAX_OPTION_LEN = 255;
+
+    /**
+     * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum
+     * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280,
+     * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500
+     * because in general it is risky to assume that the hardware is able to send/receive packets
+     * larger than 1500 bytes even if the network supports it.
+     */
+    private static final int MIN_MTU = 1280;
+    private static final int MAX_MTU = 1500;
+
+    /**
+     * IP layer definitions.
+     */
+    private static final byte IP_TYPE_UDP = (byte) 0x11;
+
+    /**
+     * IP: Version 4, Header Length 20 bytes
+     */
+    private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45;
+
+    /**
+     * IP: Flags 0, Fragment Offset 0, Don't Fragment
+     */
+    private static final short IP_FLAGS_OFFSET = (short) 0x4000;
+
+    /**
+     * IP: TOS
+     */
+    private static final byte IP_TOS_LOWDELAY = (byte) 0x10;
+
+    /**
+     * IP: TTL -- use default 64 from RFC1340
+     */
+    private static final byte IP_TTL = (byte) 0x40;
+
+    /**
+     * The client DHCP port.
+     */
+    static final short DHCP_CLIENT = (short) 68;
+
+    /**
+     * The server DHCP port.
+     */
+    static final short DHCP_SERVER = (short) 67;
+
+    /**
+     * The message op code indicating a request from a client.
+     */
+    protected static final byte DHCP_BOOTREQUEST = (byte) 1;
+
+    /**
+     * The message op code indicating a response from the server.
+     */
+    protected static final byte DHCP_BOOTREPLY = (byte) 2;
+
+    /**
+     * The code type used to identify an Ethernet MAC address in the
+     * Client-ID field.
+     */
+    protected static final byte CLIENT_ID_ETHER = (byte) 1;
+
+    /**
+     * The maximum length of a packet that can be constructed.
+     */
+    protected static final int MAX_LENGTH = 1500;
+
+    /**
+     * The magic cookie that identifies this as a DHCP packet instead of BOOTP.
+     */
+    private static final int DHCP_MAGIC_COOKIE = 0x63825363;
+
+    /**
+     * DHCP Optional Type: DHCP Subnet Mask
+     */
+    protected static final byte DHCP_SUBNET_MASK = 1;
+    protected Inet4Address mSubnetMask;
+
+    /**
+     * DHCP Optional Type: DHCP Router
+     */
+    protected static final byte DHCP_ROUTER = 3;
+    protected List <Inet4Address> mGateways;
+
+    /**
+     * DHCP Optional Type: DHCP DNS Server
+     */
+    protected static final byte DHCP_DNS_SERVER = 6;
+    protected List<Inet4Address> mDnsServers;
+
+    /**
+     * DHCP Optional Type: DHCP Host Name
+     */
+    protected static final byte DHCP_HOST_NAME = 12;
+    protected String mHostName;
+
+    /**
+     * DHCP Optional Type: DHCP DOMAIN NAME
+     */
+    protected static final byte DHCP_DOMAIN_NAME = 15;
+    protected String mDomainName;
+
+    /**
+     * DHCP Optional Type: DHCP Interface MTU
+     */
+    protected static final byte DHCP_MTU = 26;
+    protected Short mMtu;
+
+    /**
+     * DHCP Optional Type: DHCP BROADCAST ADDRESS
+     */
+    protected static final byte DHCP_BROADCAST_ADDRESS = 28;
+    protected Inet4Address mBroadcastAddress;
+
+    /**
+     * DHCP Optional Type: Vendor specific information
+     */
+    protected static final byte DHCP_VENDOR_INFO = 43;
+    protected String mVendorInfo;
+
+    /**
+     * Value of the vendor specific option used to indicate that the network is metered
+     */
+    public static final String VENDOR_INFO_ANDROID_METERED = "ANDROID_METERED";
+
+    /**
+     * DHCP Optional Type: DHCP Requested IP Address
+     */
+    protected static final byte DHCP_REQUESTED_IP = 50;
+    protected Inet4Address mRequestedIp;
+
+    /**
+     * DHCP Optional Type: DHCP Lease Time
+     */
+    protected static final byte DHCP_LEASE_TIME = 51;
+    protected Integer mLeaseTime;
+
+    /**
+     * DHCP Optional Type: DHCP Message Type
+     */
+    protected static final byte DHCP_MESSAGE_TYPE = 53;
+    // the actual type values
+    protected static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1;
+    protected static final byte DHCP_MESSAGE_TYPE_OFFER = 2;
+    protected static final byte DHCP_MESSAGE_TYPE_REQUEST = 3;
+    protected static final byte DHCP_MESSAGE_TYPE_DECLINE = 4;
+    protected static final byte DHCP_MESSAGE_TYPE_ACK = 5;
+    protected static final byte DHCP_MESSAGE_TYPE_NAK = 6;
+    protected static final byte DHCP_MESSAGE_TYPE_RELEASE = 7;
+    protected static final byte DHCP_MESSAGE_TYPE_INFORM = 8;
+
+    /**
+     * DHCP Optional Type: DHCP Server Identifier
+     */
+    protected static final byte DHCP_SERVER_IDENTIFIER = 54;
+    protected Inet4Address mServerIdentifier;
+
+    /**
+     * DHCP Optional Type: DHCP Parameter List
+     */
+    protected static final byte DHCP_PARAMETER_LIST = 55;
+    protected byte[] mRequestedParams;
+
+    /**
+     * DHCP Optional Type: DHCP MESSAGE
+     */
+    protected static final byte DHCP_MESSAGE = 56;
+    protected String mMessage;
+
+    /**
+     * DHCP Optional Type: Maximum DHCP Message Size
+     */
+    protected static final byte DHCP_MAX_MESSAGE_SIZE = 57;
+    protected Short mMaxMessageSize;
+
+    /**
+     * DHCP Optional Type: DHCP Renewal Time Value
+     */
+    protected static final byte DHCP_RENEWAL_TIME = 58;
+    protected Integer mT1;
+
+    /**
+     * DHCP Optional Type: Rebinding Time Value
+     */
+    protected static final byte DHCP_REBINDING_TIME = 59;
+    protected Integer mT2;
+
+    /**
+     * DHCP Optional Type: Vendor Class Identifier
+     */
+    protected static final byte DHCP_VENDOR_CLASS_ID = 60;
+    protected String mVendorId;
+
+    /**
+     * DHCP Optional Type: DHCP Client Identifier
+     */
+    protected static final byte DHCP_CLIENT_IDENTIFIER = 61;
+    protected byte[] mClientId;
+
+    /**
+     * DHCP zero-length option code: pad
+     */
+    protected static final byte DHCP_OPTION_PAD = 0x00;
+
+    /**
+     * DHCP zero-length option code: end of options
+     */
+    protected static final byte DHCP_OPTION_END = (byte) 0xff;
+
+    /**
+     * The transaction identifier used in this particular DHCP negotiation
+     */
+    protected final int mTransId;
+
+    /**
+     * The seconds field in the BOOTP header. Per RFC, should be nonzero in client requests only.
+     */
+    protected final short mSecs;
+
+    /**
+     * The IP address of the client host.  This address is typically
+     * proposed by the client (from an earlier DHCP negotiation) or
+     * supplied by the server.
+     */
+    protected final Inet4Address mClientIp;
+    protected final Inet4Address mYourIp;
+    private final Inet4Address mNextIp;
+    protected final Inet4Address mRelayIp;
+
+    /**
+     * Does the client request a broadcast response?
+     */
+    protected boolean mBroadcast;
+
+    /**
+     * The six-octet MAC of the client.
+     */
+    protected final byte[] mClientMac;
+
+    /**
+     * Asks the packet object to create a ByteBuffer serialization of
+     * the packet for transmission.
+     */
+    public abstract ByteBuffer buildPacket(int encap, short destUdp,
+        short srcUdp);
+
+    /**
+     * Allows the concrete class to fill in packet-type-specific details,
+     * typically optional parameters at the end of the packet.
+     */
+    abstract void finishPacket(ByteBuffer buffer);
+
+    // Set in unit tests, to ensure that the test does not break when run on different devices and
+    // on different releases.
+    static String testOverrideVendorId = null;
+    static String testOverrideHostname = null;
+
+    protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
+                         Inet4Address nextIp, Inet4Address relayIp,
+                         byte[] clientMac, boolean broadcast) {
+        mTransId = transId;
+        mSecs = secs;
+        mClientIp = clientIp;
+        mYourIp = yourIp;
+        mNextIp = nextIp;
+        mRelayIp = relayIp;
+        mClientMac = clientMac;
+        mBroadcast = broadcast;
+    }
+
+    /**
+     * Returns the transaction ID.
+     */
+    public int getTransactionId() {
+        return mTransId;
+    }
+
+    /**
+     * Returns the client MAC.
+     */
+    public byte[] getClientMac() {
+        return mClientMac;
+    }
+
+    // TODO: refactor DhcpClient to set clientId when constructing packets and remove
+    // hasExplicitClientId logic
+    /**
+     * Returns whether a client ID was set in the options for this packet.
+     */
+    public boolean hasExplicitClientId() {
+        return mClientId != null;
+    }
+
+    /**
+     * Convenience method to return the client ID if it was set explicitly, or null otherwise.
+     */
+    @Nullable
+    public byte[] getExplicitClientIdOrNull() {
+        return hasExplicitClientId() ? getClientId() : null;
+    }
+
+    /**
+     * Returns the client ID. If not set explicitly, this follows RFC 2132 and creates a client ID
+     * based on the hardware address.
+     */
+    public byte[] getClientId() {
+        final byte[] clientId;
+        if (hasExplicitClientId()) {
+            clientId = Arrays.copyOf(mClientId, mClientId.length);
+        } else {
+            clientId = new byte[mClientMac.length + 1];
+            clientId[0] = CLIENT_ID_ETHER;
+            System.arraycopy(mClientMac, 0, clientId, 1, mClientMac.length);
+        }
+        return clientId;
+    }
+
+    /**
+     * Returns whether a parameter is included in the parameter request list option of this packet.
+     *
+     * <p>If there is no parameter request list option in the packet, false is returned.
+     *
+     * @param paramId ID of the parameter, such as {@link #DHCP_MTU} or {@link #DHCP_HOST_NAME}.
+     */
+    public boolean hasRequestedParam(byte paramId) {
+        if (mRequestedParams == null) {
+            return false;
+        }
+
+        for (byte reqParam : mRequestedParams) {
+            if (reqParam == paramId) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Creates a new L3 packet (including IP header) containing the
+     * DHCP udp packet.  This method relies upon the delegated method
+     * finishPacket() to insert the per-packet contents.
+     */
+    protected void fillInPacket(int encap, Inet4Address destIp,
+        Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf,
+        byte requestCode, boolean broadcast) {
+        byte[] destIpArray = destIp.getAddress();
+        byte[] srcIpArray = srcIp.getAddress();
+        int ipHeaderOffset = 0;
+        int ipLengthOffset = 0;
+        int ipChecksumOffset = 0;
+        int endIpHeader = 0;
+        int udpHeaderOffset = 0;
+        int udpLengthOffset = 0;
+        int udpChecksumOffset = 0;
+
+        buf.clear();
+        buf.order(ByteOrder.BIG_ENDIAN);
+
+        if (encap == ENCAP_L2) {
+            buf.put(ETHER_BROADCAST);
+            buf.put(mClientMac);
+            buf.putShort((short) OsConstants.ETH_P_IP);
+        }
+
+        // if a full IP packet needs to be generated, put the IP & UDP
+        // headers in place, and pre-populate with artificial values
+        // needed to seed the IP checksum.
+        if (encap <= ENCAP_L3) {
+            ipHeaderOffset = buf.position();
+            buf.put(IP_VERSION_HEADER_LEN);
+            buf.put(IP_TOS_LOWDELAY);    // tos: IPTOS_LOWDELAY
+            ipLengthOffset = buf.position();
+            buf.putShort((short)0);  // length
+            buf.putShort((short)0);  // id
+            buf.putShort(IP_FLAGS_OFFSET); // ip offset: don't fragment
+            buf.put(IP_TTL);    // TTL: use default 64 from RFC1340
+            buf.put(IP_TYPE_UDP);
+            ipChecksumOffset = buf.position();
+            buf.putShort((short) 0); // checksum
+
+            buf.put(srcIpArray);
+            buf.put(destIpArray);
+            endIpHeader = buf.position();
+
+            // UDP header
+            udpHeaderOffset = buf.position();
+            buf.putShort(srcUdp);
+            buf.putShort(destUdp);
+            udpLengthOffset = buf.position();
+            buf.putShort((short) 0); // length
+            udpChecksumOffset = buf.position();
+            buf.putShort((short) 0); // UDP checksum -- initially zero
+        }
+
+        // DHCP payload
+        buf.put(requestCode);
+        buf.put((byte) 1); // Hardware Type: Ethernet
+        buf.put((byte) mClientMac.length); // Hardware Address Length
+        buf.put((byte) 0); // Hop Count
+        buf.putInt(mTransId);  // Transaction ID
+        buf.putShort(mSecs); // Elapsed Seconds
+
+        if (broadcast) {
+            buf.putShort((short) 0x8000); // Flags
+        } else {
+            buf.putShort((short) 0x0000); // Flags
+        }
+
+        buf.put(mClientIp.getAddress());
+        buf.put(mYourIp.getAddress());
+        buf.put(mNextIp.getAddress());
+        buf.put(mRelayIp.getAddress());
+        buf.put(mClientMac);
+        buf.position(buf.position() +
+                     (HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes
+                     + 64     // empty server host name (64 bytes)
+                     + 128);  // empty boot file name (128 bytes)
+        buf.putInt(DHCP_MAGIC_COOKIE); // magic number
+        finishPacket(buf);
+
+        // round up to an even number of octets
+        if ((buf.position() & 1) == 1) {
+            buf.put((byte) 0);
+        }
+
+        // If an IP packet is being built, the IP & UDP checksums must be
+        // computed.
+        if (encap <= ENCAP_L3) {
+            // fix UDP header: insert length
+            short udpLen = (short)(buf.position() - udpHeaderOffset);
+            buf.putShort(udpLengthOffset, udpLen);
+            // fix UDP header: checksum
+            // checksum for UDP at udpChecksumOffset
+            int udpSeed = 0;
+
+            // apply IPv4 pseudo-header.  Read IP address src and destination
+            // values from the IP header and accumulate checksum.
+            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 2));
+            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 4));
+            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 6));
+            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 8));
+
+            // accumulate extra data for the pseudo-header
+            udpSeed += IP_TYPE_UDP;
+            udpSeed += udpLen;
+            // and compute UDP checksum
+            buf.putShort(udpChecksumOffset, (short) checksum(buf, udpSeed,
+                                                             udpHeaderOffset,
+                                                             buf.position()));
+            // fix IP header: insert length
+            buf.putShort(ipLengthOffset, (short)(buf.position() - ipHeaderOffset));
+            // fixup IP-header checksum
+            buf.putShort(ipChecksumOffset,
+                         (short) checksum(buf, 0, ipHeaderOffset, endIpHeader));
+        }
+    }
+
+    /**
+     * Converts a signed short value to an unsigned int value.  Needed
+     * because Java does not have unsigned types.
+     */
+    private static int intAbs(short v) {
+        return v & 0xFFFF;
+    }
+
+    /**
+     * Performs an IP checksum (used in IP header and across UDP
+     * payload) on the specified portion of a ByteBuffer.  The seed
+     * allows the checksum to commence with a specified value.
+     */
+    private int checksum(ByteBuffer buf, int seed, int start, int end) {
+        int sum = seed;
+        int bufPosition = buf.position();
+
+        // set position of original ByteBuffer, so that the ShortBuffer
+        // will be correctly initialized
+        buf.position(start);
+        ShortBuffer shortBuf = buf.asShortBuffer();
+
+        // re-set ByteBuffer position
+        buf.position(bufPosition);
+
+        short[] shortArray = new short[(end - start) / 2];
+        shortBuf.get(shortArray);
+
+        for (short s : shortArray) {
+            sum += intAbs(s);
+        }
+
+        start += shortArray.length * 2;
+
+        // see if a singleton byte remains
+        if (end != start) {
+            short b = buf.get(start);
+
+            // make it unsigned
+            if (b < 0) {
+                b += 256;
+            }
+
+            sum += b * 256;
+        }
+
+        sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF);
+        sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF);
+        int negated = ~sum;
+        return intAbs((short) negated);
+    }
+
+    /**
+     * Adds an optional parameter containing a single byte value.
+     */
+    protected static void addTlv(ByteBuffer buf, byte type, byte value) {
+        buf.put(type);
+        buf.put((byte) 1);
+        buf.put(value);
+    }
+
+    /**
+     * Adds an optional parameter containing an array of bytes.
+     *
+     * <p>This method is a no-op if the payload argument is null.
+     */
+    protected static void addTlv(ByteBuffer buf, byte type, @Nullable byte[] payload) {
+        if (payload != null) {
+            if (payload.length > MAX_OPTION_LEN) {
+                throw new IllegalArgumentException("DHCP option too long: "
+                        + payload.length + " vs. " + MAX_OPTION_LEN);
+            }
+            buf.put(type);
+            buf.put((byte) payload.length);
+            buf.put(payload);
+        }
+    }
+
+    /**
+     * Adds an optional parameter containing an IP address.
+     *
+     * <p>This method is a no-op if the address argument is null.
+     */
+    protected static void addTlv(ByteBuffer buf, byte type, @Nullable Inet4Address addr) {
+        if (addr != null) {
+            addTlv(buf, type, addr.getAddress());
+        }
+    }
+
+    /**
+     * Adds an optional parameter containing a list of IP addresses.
+     *
+     * <p>This method is a no-op if the addresses argument is null or empty.
+     */
+    protected static void addTlv(ByteBuffer buf, byte type, @Nullable List<Inet4Address> addrs) {
+        if (addrs == null || addrs.size() == 0) return;
+
+        int optionLen = 4 * addrs.size();
+        if (optionLen > MAX_OPTION_LEN) {
+            throw new IllegalArgumentException("DHCP option too long: "
+                    + optionLen + " vs. " + MAX_OPTION_LEN);
+        }
+
+        buf.put(type);
+        buf.put((byte)(optionLen));
+
+        for (Inet4Address addr : addrs) {
+            buf.put(addr.getAddress());
+        }
+    }
+
+    /**
+     * Adds an optional parameter containing a short integer.
+     *
+     * <p>This method is a no-op if the value argument is null.
+     */
+    protected static void addTlv(ByteBuffer buf, byte type, @Nullable Short value) {
+        if (value != null) {
+            buf.put(type);
+            buf.put((byte) 2);
+            buf.putShort(value.shortValue());
+        }
+    }
+
+    /**
+     * Adds an optional parameter containing a simple integer.
+     *
+     * <p>This method is a no-op if the value argument is null.
+     */
+    protected static void addTlv(ByteBuffer buf, byte type, @Nullable Integer value) {
+        if (value != null) {
+            buf.put(type);
+            buf.put((byte) 4);
+            buf.putInt(value.intValue());
+        }
+    }
+
+    /**
+     * Adds an optional parameter containing an ASCII string.
+     *
+     * <p>This method is a no-op if the string argument is null.
+     */
+    protected static void addTlv(ByteBuffer buf, byte type, @Nullable String str) {
+        if (str != null) {
+            try {
+                addTlv(buf, type, str.getBytes("US-ASCII"));
+            } catch (UnsupportedEncodingException e) {
+                throw new IllegalArgumentException("String is not US-ASCII: " + str);
+            }
+        }
+    }
+
+    /**
+     * Adds the special end-of-optional-parameters indicator.
+     */
+    protected static void addTlvEnd(ByteBuffer buf) {
+        buf.put((byte) 0xFF);
+    }
+
+    private String getVendorId() {
+        if (testOverrideVendorId != null) return testOverrideVendorId;
+        return "android-dhcp-" + Build.VERSION.RELEASE;
+    }
+
+    private String getHostname() {
+        if (testOverrideHostname != null) return testOverrideHostname;
+        return SystemProperties.get("net.hostname");
+    }
+
+    /**
+     * Adds common client TLVs.
+     *
+     * TODO: Does this belong here? The alternative would be to modify all the buildXyzPacket
+     * methods to take them.
+     */
+    protected void addCommonClientTlvs(ByteBuffer buf) {
+        addTlv(buf, DHCP_MAX_MESSAGE_SIZE, (short) MAX_LENGTH);
+        addTlv(buf, DHCP_VENDOR_CLASS_ID, getVendorId());
+        final String hn = getHostname();
+        if (!TextUtils.isEmpty(hn)) addTlv(buf, DHCP_HOST_NAME, hn);
+    }
+
+    protected void addCommonServerTlvs(ByteBuffer buf) {
+        addTlv(buf, DHCP_LEASE_TIME, mLeaseTime);
+        if (mLeaseTime != null && mLeaseTime != INFINITE_LEASE) {
+            // The client should renew at 1/2 the lease-expiry interval
+            addTlv(buf, DHCP_RENEWAL_TIME, (int) (Integer.toUnsignedLong(mLeaseTime) / 2));
+            // Default rebinding time is set as below by RFC2131
+            addTlv(buf, DHCP_REBINDING_TIME,
+                    (int) (Integer.toUnsignedLong(mLeaseTime) * 875L / 1000L));
+        }
+        addTlv(buf, DHCP_SUBNET_MASK, mSubnetMask);
+        addTlv(buf, DHCP_BROADCAST_ADDRESS, mBroadcastAddress);
+        addTlv(buf, DHCP_ROUTER, mGateways);
+        addTlv(buf, DHCP_DNS_SERVER, mDnsServers);
+        addTlv(buf, DHCP_DOMAIN_NAME, mDomainName);
+        addTlv(buf, DHCP_HOST_NAME, mHostName);
+        addTlv(buf, DHCP_VENDOR_INFO, mVendorInfo);
+        if (mMtu != null && Short.toUnsignedInt(mMtu) >= IPV4_MIN_MTU) {
+            addTlv(buf, DHCP_MTU, mMtu);
+        }
+    }
+
+    /**
+     * Converts a MAC from an array of octets to an ASCII string.
+     */
+    public static String macToString(byte[] mac) {
+        String macAddr = "";
+
+        for (int i = 0; i < mac.length; i++) {
+            String hexString = "0" + Integer.toHexString(mac[i]);
+
+            // substring operation grabs the last 2 digits: this
+            // allows signed bytes to be converted correctly.
+            macAddr += hexString.substring(hexString.length() - 2);
+
+            if (i != (mac.length - 1)) {
+                macAddr += ":";
+            }
+        }
+
+        return macAddr;
+    }
+
+    public String toString() {
+        String macAddr = macToString(mClientMac);
+
+        return macAddr;
+    }
+
+    /**
+     * Reads a four-octet value from a ByteBuffer and construct
+     * an IPv4 address from that value.
+     */
+    private static Inet4Address readIpAddress(ByteBuffer packet) {
+        Inet4Address result = null;
+        byte[] ipAddr = new byte[4];
+        packet.get(ipAddr);
+
+        try {
+            result = (Inet4Address) Inet4Address.getByAddress(ipAddr);
+        } catch (UnknownHostException ex) {
+            // ipAddr is numeric, so this should not be
+            // triggered.  However, if it is, just nullify
+            result = null;
+        }
+
+        return result;
+    }
+
+    /**
+     * Reads a string of specified length from the buffer.
+     */
+    private static String readAsciiString(ByteBuffer buf, int byteCount, boolean nullOk) {
+        byte[] bytes = new byte[byteCount];
+        buf.get(bytes);
+        int length = bytes.length;
+        if (!nullOk) {
+            // Stop at the first null byte. This is because some DHCP options (e.g., the domain
+            // name) are passed to netd via FrameworkListener, which refuses arguments containing
+            // null bytes. We don't do this by default because vendorInfo is an opaque string which
+            // could in theory contain null bytes.
+            for (length = 0; length < bytes.length; length++) {
+                if (bytes[length] == 0) {
+                    break;
+                }
+            }
+        }
+        return new String(bytes, 0, length, StandardCharsets.US_ASCII);
+    }
+
+    private static boolean isPacketToOrFromClient(short udpSrcPort, short udpDstPort) {
+        return (udpSrcPort == DHCP_CLIENT) || (udpDstPort == DHCP_CLIENT);
+    }
+
+    private static boolean isPacketServerToServer(short udpSrcPort, short udpDstPort) {
+        return (udpSrcPort == DHCP_SERVER) && (udpDstPort == DHCP_SERVER);
+    }
+
+    public static class ParseException extends Exception {
+        public final int errorCode;
+        public ParseException(int errorCode, String msg, Object... args) {
+            super(String.format(msg, args));
+            this.errorCode = errorCode;
+        }
+    }
+
+    /**
+     * Creates a concrete DhcpPacket from the supplied ByteBuffer.  The
+     * buffer may have an L2 encapsulation (which is the full EthernetII
+     * format starting with the source-address MAC) or an L3 encapsulation
+     * (which starts with the IP header).
+     * <br>
+     * A subset of the optional parameters are parsed and are stored
+     * in object fields.
+     */
+    @VisibleForTesting
+    static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
+    {
+        // bootp parameters
+        int transactionId;
+        short secs;
+        Inet4Address clientIp;
+        Inet4Address yourIp;
+        Inet4Address nextIp;
+        Inet4Address relayIp;
+        byte[] clientMac;
+        byte[] clientId = null;
+        List<Inet4Address> dnsServers = new ArrayList<>();
+        List<Inet4Address> gateways = new ArrayList<>();  // aka router
+        Inet4Address serverIdentifier = null;
+        Inet4Address netMask = null;
+        String message = null;
+        String vendorId = null;
+        String vendorInfo = null;
+        byte[] expectedParams = null;
+        String hostName = null;
+        String domainName = null;
+        Inet4Address ipSrc = null;
+        Inet4Address ipDst = null;
+        Inet4Address bcAddr = null;
+        Inet4Address requestedIp = null;
+
+        // The following are all unsigned integers. Internally we store them as signed integers of
+        // the same length because that way we're guaranteed that they can't be out of the range of
+        // the unsigned field in the packet. Callers wanting to pass in an unsigned value will need
+        // to cast it.
+        Short mtu = null;
+        Short maxMessageSize = null;
+        Integer leaseTime = null;
+        Integer T1 = null;
+        Integer T2 = null;
+
+        // dhcp options
+        byte dhcpType = (byte) 0xFF;
+
+        packet.order(ByteOrder.BIG_ENDIAN);
+
+        // check to see if we need to parse L2, IP, and UDP encaps
+        if (pktType == ENCAP_L2) {
+            if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
+                throw new ParseException(DhcpErrorEvent.L2_TOO_SHORT,
+                        "L2 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L2);
+            }
+
+            byte[] l2dst = new byte[6];
+            byte[] l2src = new byte[6];
+
+            packet.get(l2dst);
+            packet.get(l2src);
+
+            short l2type = packet.getShort();
+
+            if (l2type != OsConstants.ETH_P_IP) {
+                throw new ParseException(DhcpErrorEvent.L2_WRONG_ETH_TYPE,
+                        "Unexpected L2 type 0x%04x, expected 0x%04x", l2type, OsConstants.ETH_P_IP);
+            }
+        }
+
+        if (pktType <= ENCAP_L3) {
+            if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
+                throw new ParseException(DhcpErrorEvent.L3_TOO_SHORT,
+                        "L3 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L3);
+            }
+
+            byte ipTypeAndLength = packet.get();
+            int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
+            if (ipVersion != 4) {
+                throw new ParseException(
+                        DhcpErrorEvent.L3_NOT_IPV4, "Invalid IP version %d", ipVersion);
+            }
+
+            // System.out.println("ipType is " + ipType);
+            byte ipDiffServicesField = packet.get();
+            short ipTotalLength = packet.getShort();
+            short ipIdentification = packet.getShort();
+            byte ipFlags = packet.get();
+            byte ipFragOffset = packet.get();
+            byte ipTTL = packet.get();
+            byte ipProto = packet.get();
+            short ipChksm = packet.getShort();
+
+            ipSrc = readIpAddress(packet);
+            ipDst = readIpAddress(packet);
+
+            if (ipProto != IP_TYPE_UDP) {
+                throw new ParseException(
+                        DhcpErrorEvent.L4_NOT_UDP, "Protocol not UDP: %d", ipProto);
+            }
+
+            // Skip options. This cannot cause us to read beyond the end of the buffer because the
+            // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than
+            // MIN_PACKET_LENGTH_L3.
+            int optionWords = ((ipTypeAndLength & 0x0f) - 5);
+            for (int i = 0; i < optionWords; i++) {
+                packet.getInt();
+            }
+
+            // assume UDP
+            short udpSrcPort = packet.getShort();
+            short udpDstPort = packet.getShort();
+            short udpLen = packet.getShort();
+            short udpChkSum = packet.getShort();
+
+            // Only accept packets to or from the well-known client port (expressly permitting
+            // packets from ports other than the well-known server port; http://b/24687559), and
+            // server-to-server packets, e.g. for relays.
+            if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) &&
+                !isPacketServerToServer(udpSrcPort, udpDstPort)) {
+                // This should almost never happen because we use SO_ATTACH_FILTER on the packet
+                // socket to drop packets that don't have the right source ports. However, it's
+                // possible that a packet arrives between when the socket is bound and when the
+                // filter is set. http://b/26696823 .
+                throw new ParseException(DhcpErrorEvent.L4_WRONG_PORT,
+                        "Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
+            }
+        }
+
+        // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
+        if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
+            throw new ParseException(DhcpErrorEvent.BOOTP_TOO_SHORT,
+                        "Invalid type or BOOTP packet too short, %d < %d",
+                        packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
+        }
+
+        byte type = packet.get();
+        byte hwType = packet.get();
+        int addrLen = packet.get() & 0xff;
+        byte hops = packet.get();
+        transactionId = packet.getInt();
+        secs = packet.getShort();
+        short bootpFlags = packet.getShort();
+        boolean broadcast = (bootpFlags & 0x8000) != 0;
+        byte[] ipv4addr = new byte[4];
+
+        try {
+            packet.get(ipv4addr);
+            clientIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
+            packet.get(ipv4addr);
+            yourIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
+            packet.get(ipv4addr);
+            nextIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
+            packet.get(ipv4addr);
+            relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
+        } catch (UnknownHostException ex) {
+            throw new ParseException(DhcpErrorEvent.L3_INVALID_IP,
+                    "Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
+        }
+
+        // Some DHCP servers have been known to announce invalid client hardware address values such
+        // as 0xff. The legacy DHCP client accepted these becuause it does not check the length at
+        // all but only checks that the interface MAC address matches the first bytes of the address
+        // in the packets. We're a bit stricter: if the length is obviously invalid (i.e., bigger
+        // than the size of the field), we fudge it to 6 (Ethernet). http://b/23725795
+        // TODO: evaluate whether to make this test more liberal.
+        if (addrLen > HWADDR_LEN) {
+            addrLen = ETHER_BROADCAST.length;
+        }
+
+        clientMac = new byte[addrLen];
+        packet.get(clientMac);
+
+        // skip over address padding (16 octets allocated)
+        packet.position(packet.position() + (16 - addrLen)
+                        + 64    // skip server host name (64 chars)
+                        + 128); // skip boot file name (128 chars)
+
+        // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211
+        if (packet.remaining() < 4) {
+            throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message");
+        }
+
+        int dhcpMagicCookie = packet.getInt();
+        if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
+            throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE,
+                    "Bad magic cookie 0x%08x, should be 0x%08x",
+                    dhcpMagicCookie, DHCP_MAGIC_COOKIE);
+        }
+
+        // parse options
+        boolean notFinishedOptions = true;
+
+        while ((packet.position() < packet.limit()) && notFinishedOptions) {
+            final byte optionType = packet.get(); // cannot underflow because position < limit
+            try {
+                if (optionType == DHCP_OPTION_END) {
+                    notFinishedOptions = false;
+                } else if (optionType == DHCP_OPTION_PAD) {
+                    // The pad option doesn't have a length field. Nothing to do.
+                } else {
+                    int optionLen = packet.get() & 0xFF;
+                    int expectedLen = 0;
+
+                    switch(optionType) {
+                        case DHCP_SUBNET_MASK:
+                            netMask = readIpAddress(packet);
+                            expectedLen = 4;
+                            break;
+                        case DHCP_ROUTER:
+                            for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
+                                gateways.add(readIpAddress(packet));
+                            }
+                            break;
+                        case DHCP_DNS_SERVER:
+                            for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
+                                dnsServers.add(readIpAddress(packet));
+                            }
+                            break;
+                        case DHCP_HOST_NAME:
+                            expectedLen = optionLen;
+                            hostName = readAsciiString(packet, optionLen, false);
+                            break;
+                        case DHCP_MTU:
+                            expectedLen = 2;
+                            mtu = packet.getShort();
+                            break;
+                        case DHCP_DOMAIN_NAME:
+                            expectedLen = optionLen;
+                            domainName = readAsciiString(packet, optionLen, false);
+                            break;
+                        case DHCP_BROADCAST_ADDRESS:
+                            bcAddr = readIpAddress(packet);
+                            expectedLen = 4;
+                            break;
+                        case DHCP_REQUESTED_IP:
+                            requestedIp = readIpAddress(packet);
+                            expectedLen = 4;
+                            break;
+                        case DHCP_LEASE_TIME:
+                            leaseTime = Integer.valueOf(packet.getInt());
+                            expectedLen = 4;
+                            break;
+                        case DHCP_MESSAGE_TYPE:
+                            dhcpType = packet.get();
+                            expectedLen = 1;
+                            break;
+                        case DHCP_SERVER_IDENTIFIER:
+                            serverIdentifier = readIpAddress(packet);
+                            expectedLen = 4;
+                            break;
+                        case DHCP_PARAMETER_LIST:
+                            expectedParams = new byte[optionLen];
+                            packet.get(expectedParams);
+                            expectedLen = optionLen;
+                            break;
+                        case DHCP_MESSAGE:
+                            expectedLen = optionLen;
+                            message = readAsciiString(packet, optionLen, false);
+                            break;
+                        case DHCP_MAX_MESSAGE_SIZE:
+                            expectedLen = 2;
+                            maxMessageSize = Short.valueOf(packet.getShort());
+                            break;
+                        case DHCP_RENEWAL_TIME:
+                            expectedLen = 4;
+                            T1 = Integer.valueOf(packet.getInt());
+                            break;
+                        case DHCP_REBINDING_TIME:
+                            expectedLen = 4;
+                            T2 = Integer.valueOf(packet.getInt());
+                            break;
+                        case DHCP_VENDOR_CLASS_ID:
+                            expectedLen = optionLen;
+                            // Embedded nulls are safe as this does not get passed to netd.
+                            vendorId = readAsciiString(packet, optionLen, true);
+                            break;
+                        case DHCP_CLIENT_IDENTIFIER: { // Client identifier
+                            byte[] id = new byte[optionLen];
+                            packet.get(id);
+                            expectedLen = optionLen;
+                        } break;
+                        case DHCP_VENDOR_INFO:
+                            expectedLen = optionLen;
+                            // Embedded nulls are safe as this does not get passed to netd.
+                            vendorInfo = readAsciiString(packet, optionLen, true);
+                            break;
+                        default:
+                            // ignore any other parameters
+                            for (int i = 0; i < optionLen; i++) {
+                                expectedLen++;
+                                byte throwaway = packet.get();
+                            }
+                    }
+
+                    if (expectedLen != optionLen) {
+                        final int errorCode = DhcpErrorEvent.errorCodeWithOption(
+                                DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
+                        throw new ParseException(errorCode,
+                                "Invalid length %d for option %d, expected %d",
+                                optionLen, optionType, expectedLen);
+                    }
+                }
+            } catch (BufferUnderflowException e) {
+                final int errorCode = DhcpErrorEvent.errorCodeWithOption(
+                        DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
+                throw new ParseException(errorCode, "BufferUnderflowException");
+            }
+        }
+
+        DhcpPacket newPacket;
+
+        switch(dhcpType) {
+            case (byte) 0xFF:
+                throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE,
+                        "No DHCP message type option");
+            case DHCP_MESSAGE_TYPE_DISCOVER:
+                newPacket = new DhcpDiscoverPacket(transactionId, secs, relayIp, clientMac,
+                        broadcast, ipSrc);
+                break;
+            case DHCP_MESSAGE_TYPE_OFFER:
+                newPacket = new DhcpOfferPacket(
+                    transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac);
+                break;
+            case DHCP_MESSAGE_TYPE_REQUEST:
+                newPacket = new DhcpRequestPacket(
+                    transactionId, secs, clientIp, relayIp, clientMac, broadcast);
+                break;
+            case DHCP_MESSAGE_TYPE_DECLINE:
+                newPacket = new DhcpDeclinePacket(
+                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
+                    clientMac);
+                break;
+            case DHCP_MESSAGE_TYPE_ACK:
+                newPacket = new DhcpAckPacket(
+                    transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac);
+                break;
+            case DHCP_MESSAGE_TYPE_NAK:
+                newPacket = new DhcpNakPacket(
+                        transactionId, secs, relayIp, clientMac, broadcast);
+                break;
+            case DHCP_MESSAGE_TYPE_RELEASE:
+                if (serverIdentifier == null) {
+                    throw new ParseException(DhcpErrorEvent.MISC_ERROR,
+                            "DHCPRELEASE without server identifier");
+                }
+                newPacket = new DhcpReleasePacket(
+                        transactionId, serverIdentifier, clientIp, relayIp, clientMac);
+                break;
+            case DHCP_MESSAGE_TYPE_INFORM:
+                newPacket = new DhcpInformPacket(
+                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
+                    clientMac);
+                break;
+            default:
+                throw new ParseException(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE,
+                        "Unimplemented DHCP type %d", dhcpType);
+        }
+
+        newPacket.mBroadcastAddress = bcAddr;
+        newPacket.mClientId = clientId;
+        newPacket.mDnsServers = dnsServers;
+        newPacket.mDomainName = domainName;
+        newPacket.mGateways = gateways;
+        newPacket.mHostName = hostName;
+        newPacket.mLeaseTime = leaseTime;
+        newPacket.mMessage = message;
+        newPacket.mMtu = mtu;
+        newPacket.mRequestedIp = requestedIp;
+        newPacket.mRequestedParams = expectedParams;
+        newPacket.mServerIdentifier = serverIdentifier;
+        newPacket.mSubnetMask = netMask;
+        newPacket.mMaxMessageSize = maxMessageSize;
+        newPacket.mT1 = T1;
+        newPacket.mT2 = T2;
+        newPacket.mVendorId = vendorId;
+        newPacket.mVendorInfo = vendorInfo;
+        return newPacket;
+    }
+
+    /**
+     * Parse a packet from an array of bytes, stopping at the given length.
+     */
+    public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
+            throws ParseException {
+        ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
+        try {
+            return decodeFullPacket(buffer, pktType);
+        } catch (ParseException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage());
+        }
+    }
+
+    /**
+     *  Construct a DhcpResults object from a DHCP reply packet.
+     */
+    public DhcpResults toDhcpResults() {
+        Inet4Address ipAddress = mYourIp;
+        if (ipAddress.equals(Inet4Address.ANY)) {
+            ipAddress = mClientIp;
+            if (ipAddress.equals(Inet4Address.ANY)) {
+                return null;
+            }
+        }
+
+        int prefixLength;
+        if (mSubnetMask != null) {
+            try {
+                prefixLength = NetworkUtils.netmaskToPrefixLength(mSubnetMask);
+            } catch (IllegalArgumentException e) {
+                // Non-contiguous netmask.
+                return null;
+            }
+        } else {
+            prefixLength = NetworkUtils.getImplicitNetmask(ipAddress);
+        }
+
+        DhcpResults results = new DhcpResults();
+        try {
+            results.ipAddress = new LinkAddress(ipAddress, prefixLength);
+        } catch (IllegalArgumentException e) {
+            return null;
+        }
+
+        if (mGateways.size() > 0) {
+            results.gateway = mGateways.get(0);
+        }
+
+        results.dnsServers.addAll(mDnsServers);
+        results.domains = mDomainName;
+        results.serverAddress = mServerIdentifier;
+        results.vendorInfo = mVendorInfo;
+        results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
+        results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
+
+        return results;
+    }
+
+    /**
+     * Returns the parsed lease time, in milliseconds, or 0 for infinite.
+     */
+    public long getLeaseTimeMillis() {
+        // dhcpcd treats the lack of a lease time option as an infinite lease.
+        if (mLeaseTime == null || mLeaseTime == INFINITE_LEASE) {
+            return 0;
+        } else if (0 <= mLeaseTime && mLeaseTime < MINIMUM_LEASE) {
+            return MINIMUM_LEASE * 1000;
+        } else {
+            return (mLeaseTime & 0xffffffffL) * 1000;
+        }
+    }
+
+    /**
+     * Builds a DHCP-DISCOVER packet from the required specified
+     * parameters.
+     */
+    public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
+        short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams) {
+        DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, INADDR_ANY /* relayIp */,
+                clientMac, broadcast, INADDR_ANY /* srcIp */);
+        pkt.mRequestedParams = expectedParams;
+        return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
+    }
+
+    /**
+     * Builds a DHCP-OFFER packet from the required specified
+     * parameters.
+     */
+    public static ByteBuffer buildOfferPacket(int encap, int transactionId,
+        boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp,
+        Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask,
+        Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
+        Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
+        short mtu) {
+        DhcpPacket pkt = new DhcpOfferPacket(
+                transactionId, (short) 0, broadcast, serverIpAddr, relayIp,
+                INADDR_ANY /* clientIp */, yourIp, mac);
+        pkt.mGateways = gateways;
+        pkt.mDnsServers = dnsServers;
+        pkt.mLeaseTime = timeout;
+        pkt.mDomainName = domainName;
+        pkt.mHostName = hostname;
+        pkt.mServerIdentifier = dhcpServerIdentifier;
+        pkt.mSubnetMask = netMask;
+        pkt.mBroadcastAddress = bcAddr;
+        pkt.mMtu = mtu;
+        if (metered) {
+            pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
+        }
+        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
+    }
+
+    /**
+     * Builds a DHCP-ACK packet from the required specified parameters.
+     */
+    public static ByteBuffer buildAckPacket(int encap, int transactionId,
+        boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp,
+        Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask,
+        Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
+        Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
+        short mtu) {
+        DhcpPacket pkt = new DhcpAckPacket(
+                transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp,
+                mac);
+        pkt.mGateways = gateways;
+        pkt.mDnsServers = dnsServers;
+        pkt.mLeaseTime = timeout;
+        pkt.mDomainName = domainName;
+        pkt.mHostName = hostname;
+        pkt.mSubnetMask = netMask;
+        pkt.mServerIdentifier = dhcpServerIdentifier;
+        pkt.mBroadcastAddress = bcAddr;
+        pkt.mMtu = mtu;
+        if (metered) {
+            pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
+        }
+        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
+    }
+
+    /**
+     * Builds a DHCP-NAK packet from the required specified parameters.
+     */
+    public static ByteBuffer buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr,
+            Inet4Address relayIp, byte[] mac, boolean broadcast, String message) {
+        DhcpPacket pkt = new DhcpNakPacket(
+                transactionId, (short) 0, relayIp, mac, broadcast);
+        pkt.mMessage = message;
+        pkt.mServerIdentifier = serverIpAddr;
+        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
+    }
+
+    /**
+     * Builds a DHCP-REQUEST packet from the required specified parameters.
+     */
+    public static ByteBuffer buildRequestPacket(int encap,
+        int transactionId, short secs, Inet4Address clientIp, boolean broadcast,
+        byte[] clientMac, Inet4Address requestedIpAddress,
+        Inet4Address serverIdentifier, byte[] requestedParams, String hostName) {
+        DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp,
+                INADDR_ANY /* relayIp */, clientMac, broadcast);
+        pkt.mRequestedIp = requestedIpAddress;
+        pkt.mServerIdentifier = serverIdentifier;
+        pkt.mHostName = hostName;
+        pkt.mRequestedParams = requestedParams;
+        ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
+        return result;
+    }
+}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
new file mode 100644
index 0000000..dce8b61
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.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.net.dhcp;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.util.FdEventsReader;
+import android.os.Handler;
+import android.system.Os;
+
+import java.io.FileDescriptor;
+import java.net.Inet4Address;
+import java.net.InetSocketAddress;
+
+/**
+ * A {@link FdEventsReader} to receive and parse {@link DhcpPacket}.
+ * @hide
+ */
+abstract class DhcpPacketListener extends FdEventsReader<DhcpPacketListener.Payload> {
+    static final class Payload {
+        protected final byte[] mBytes = new byte[DhcpPacket.MAX_LENGTH];
+        protected Inet4Address mSrcAddr;
+        protected int mSrcPort;
+    }
+
+    DhcpPacketListener(@NonNull Handler handler) {
+        super(handler, new Payload());
+    }
+
+    @Override
+    protected int recvBufSize(@NonNull Payload buffer) {
+        return buffer.mBytes.length;
+    }
+
+    @Override
+    protected final void handlePacket(@NonNull Payload recvbuf, int length) {
+        if (recvbuf.mSrcAddr == null) {
+            return;
+        }
+
+        try {
+            final DhcpPacket packet = DhcpPacket.decodeFullPacket(recvbuf.mBytes, length,
+                    DhcpPacket.ENCAP_BOOTP);
+            onReceive(packet, recvbuf.mSrcAddr, recvbuf.mSrcPort);
+        } catch (DhcpPacket.ParseException e) {
+            logParseError(recvbuf.mBytes, length, e);
+        }
+    }
+
+    @Override
+    protected int readPacket(@NonNull FileDescriptor fd, @NonNull Payload packetBuffer)
+            throws Exception {
+        final InetSocketAddress addr = new InetSocketAddress();
+        final int read = Os.recvfrom(
+                fd, packetBuffer.mBytes, 0, packetBuffer.mBytes.length, 0 /* flags */, addr);
+
+        // Buffers with null srcAddr will be dropped in handlePacket()
+        packetBuffer.mSrcAddr = inet4AddrOrNull(addr);
+        packetBuffer.mSrcPort = addr.getPort();
+        return read;
+    }
+
+    @Nullable
+    private static Inet4Address inet4AddrOrNull(@NonNull InetSocketAddress addr) {
+        return addr.getAddress() instanceof Inet4Address
+                ? (Inet4Address) addr.getAddress()
+                : null;
+    }
+
+    protected abstract void onReceive(@NonNull DhcpPacket packet, @NonNull Inet4Address srcAddr,
+            int srcPort);
+    protected abstract void logParseError(@NonNull byte[] packet, int length,
+            @NonNull DhcpPacket.ParseException e);
+}
diff --git a/services/net/java/android/net/dhcp/DhcpReleasePacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpReleasePacket.java
similarity index 100%
rename from services/net/java/android/net/dhcp/DhcpReleasePacket.java
rename to packages/NetworkStack/src/android/net/dhcp/DhcpReleasePacket.java
diff --git a/services/net/java/android/net/dhcp/DhcpRequestPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpRequestPacket.java
similarity index 100%
rename from services/net/java/android/net/dhcp/DhcpRequestPacket.java
rename to packages/NetworkStack/src/android/net/dhcp/DhcpRequestPacket.java
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
new file mode 100644
index 0000000..7b112df
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
@@ -0,0 +1,647 @@
+/*
+ * 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.dhcp;
+
+import static android.net.NetworkUtils.getBroadcastAddress;
+import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
+import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER;
+import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
+import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
+import static android.net.dhcp.DhcpPacket.DHCP_SERVER;
+import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
+import static android.net.dhcp.IDhcpServer.STATUS_INVALID_ARGUMENT;
+import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_BROADCAST;
+import static android.system.OsConstants.SO_REUSEADDR;
+
+import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE;
+import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;
+
+import static java.lang.Integer.toUnsignedLong;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.INetworkStackStatusCallback;
+import android.net.MacAddress;
+import android.net.NetworkUtils;
+import android.net.TrafficStats;
+import android.net.util.SharedLog;
+import android.net.util.SocketUtils;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.text.TextUtils;
+import android.util.Pair;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.HexDump;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+/**
+ * A DHCPv4 server.
+ *
+ * <p>This server listens for and responds to packets on a single interface. It considers itself
+ * authoritative for all leases on the subnet, which means that DHCP requests for unknown leases of
+ * unknown hosts receive a reply instead of being ignored.
+ *
+ * <p>The server is single-threaded (including send/receive operations): all internal operations are
+ * done on the provided {@link Looper}. Public methods are thread-safe and will schedule operations
+ * on the looper asynchronously.
+ * @hide
+ */
+public class DhcpServer extends IDhcpServer.Stub {
+    private static final String REPO_TAG = "Repository";
+
+    // Lease time to transmit to client instead of a negative time in case a lease expired before
+    // the server could send it (if the server process is suspended for example).
+    private static final int EXPIRED_FALLBACK_LEASE_TIME_SECS = 120;
+
+    private static final int CMD_START_DHCP_SERVER = 1;
+    private static final int CMD_STOP_DHCP_SERVER = 2;
+    private static final int CMD_UPDATE_PARAMS = 3;
+
+    @NonNull
+    private final HandlerThread mHandlerThread;
+    @NonNull
+    private final String mIfName;
+    @NonNull
+    private final DhcpLeaseRepository mLeaseRepo;
+    @NonNull
+    private final SharedLog mLog;
+    @NonNull
+    private final Dependencies mDeps;
+    @NonNull
+    private final Clock mClock;
+
+    @Nullable
+    private volatile ServerHandler mHandler;
+
+    // Accessed only on the handler thread
+    @Nullable
+    private DhcpPacketListener mPacketListener;
+    @Nullable
+    private FileDescriptor mSocket;
+    @NonNull
+    private DhcpServingParams mServingParams;
+
+    /**
+     * Clock to be used by DhcpServer to track time for lease expiration.
+     *
+     * <p>The clock should track time as may be measured by clients obtaining a lease. It does not
+     * need to be monotonous across restarts of the server as long as leases are cleared when the
+     * server is stopped.
+     */
+    public static class Clock {
+        /**
+         * @see SystemClock#elapsedRealtime()
+         */
+        public long elapsedRealtime() {
+            return SystemClock.elapsedRealtime();
+        }
+    }
+
+    /**
+     * Dependencies for the DhcpServer. Useful to be mocked in tests.
+     */
+    public interface Dependencies {
+        /**
+         * Send a packet to the specified datagram socket.
+         *
+         * @param fd File descriptor of the socket.
+         * @param buffer Data to be sent.
+         * @param dst Destination address of the packet.
+         */
+        void sendPacket(@NonNull FileDescriptor fd, @NonNull ByteBuffer buffer,
+                @NonNull InetAddress dst) throws ErrnoException, IOException;
+
+        /**
+         * Create a DhcpLeaseRepository for the server.
+         * @param servingParams Parameters used to serve DHCP requests.
+         * @param log Log to be used by the repository.
+         * @param clock Clock that the repository must use to track time.
+         */
+        DhcpLeaseRepository makeLeaseRepository(@NonNull DhcpServingParams servingParams,
+                @NonNull SharedLog log, @NonNull Clock clock);
+
+        /**
+         * Create a packet listener that will send packets to be processed.
+         */
+        DhcpPacketListener makePacketListener();
+
+        /**
+         * Create a clock that the server will use to track time.
+         */
+        Clock makeClock();
+
+        /**
+         * Add an entry to the ARP cache table.
+         * @param fd Datagram socket file descriptor that must use the new entry.
+         */
+        void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr,
+                @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException;
+
+        /**
+         * Verify that the caller is allowed to call public methods on DhcpServer.
+         * @throws SecurityException The caller is not allowed to call public methods on DhcpServer.
+         */
+        void checkCaller() throws SecurityException;
+    }
+
+    private class DependenciesImpl implements Dependencies {
+        @Override
+        public void sendPacket(@NonNull FileDescriptor fd, @NonNull ByteBuffer buffer,
+                @NonNull InetAddress dst) throws ErrnoException, IOException {
+            Os.sendto(fd, buffer, 0, dst, DhcpPacket.DHCP_CLIENT);
+        }
+
+        @Override
+        public DhcpLeaseRepository makeLeaseRepository(@NonNull DhcpServingParams servingParams,
+                @NonNull SharedLog log, @NonNull Clock clock) {
+            return new DhcpLeaseRepository(
+                    DhcpServingParams.makeIpPrefix(servingParams.serverAddr),
+                    servingParams.excludedAddrs,
+                    servingParams.dhcpLeaseTimeSecs * 1000, log.forSubComponent(REPO_TAG), clock);
+        }
+
+        @Override
+        public DhcpPacketListener makePacketListener() {
+            return new PacketListener();
+        }
+
+        @Override
+        public Clock makeClock() {
+            return new Clock();
+        }
+
+        @Override
+        public void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr,
+                @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException {
+            NetworkUtils.addArpEntry(ipv4Addr, ethAddr, ifname, fd);
+        }
+
+        @Override
+        public void checkCaller() {
+            checkNetworkStackCallingPermission();
+        }
+    }
+
+    private static class MalformedPacketException extends Exception {
+        MalformedPacketException(String message, Throwable t) {
+            super(message, t);
+        }
+    }
+
+    public DhcpServer(@NonNull String ifName,
+            @NonNull DhcpServingParams params, @NonNull SharedLog log) {
+        this(new HandlerThread(DhcpServer.class.getSimpleName() + "." + ifName),
+                ifName, params, log, null);
+    }
+
+    @VisibleForTesting
+    DhcpServer(@NonNull HandlerThread handlerThread, @NonNull String ifName,
+            @NonNull DhcpServingParams params, @NonNull SharedLog log,
+            @Nullable Dependencies deps) {
+        if (deps == null) {
+            deps = new DependenciesImpl();
+        }
+        mHandlerThread = handlerThread;
+        mIfName = ifName;
+        mServingParams = params;
+        mLog = log;
+        mDeps = deps;
+        mClock = deps.makeClock();
+        mLeaseRepo = deps.makeLeaseRepository(mServingParams, mLog, mClock);
+    }
+
+    /**
+     * Start listening for and responding to packets.
+     *
+     * <p>It is not legal to call this method more than once; in particular the server cannot be
+     * restarted after being stopped.
+     */
+    @Override
+    public void start(@Nullable INetworkStackStatusCallback cb) {
+        mDeps.checkCaller();
+        mHandlerThread.start();
+        mHandler = new ServerHandler(mHandlerThread.getLooper());
+        sendMessage(CMD_START_DHCP_SERVER, cb);
+    }
+
+    /**
+     * Update serving parameters. All subsequently received requests will be handled with the new
+     * parameters, and current leases that are incompatible with the new parameters are dropped.
+     */
+    @Override
+    public void updateParams(@Nullable DhcpServingParamsParcel params,
+            @Nullable INetworkStackStatusCallback cb) throws RemoteException {
+        mDeps.checkCaller();
+        final DhcpServingParams parsedParams;
+        try {
+            // throws InvalidParameterException with null params
+            parsedParams = DhcpServingParams.fromParcelableObject(params);
+        } catch (DhcpServingParams.InvalidParameterException e) {
+            mLog.e("Invalid parameters sent to DhcpServer", e);
+            if (cb != null) {
+                cb.onStatusAvailable(STATUS_INVALID_ARGUMENT);
+            }
+            return;
+        }
+        sendMessage(CMD_UPDATE_PARAMS, new Pair<>(parsedParams, cb));
+    }
+
+    /**
+     * Stop listening for packets.
+     *
+     * <p>As the server is stopped asynchronously, some packets may still be processed shortly after
+     * calling this method.
+     */
+    @Override
+    public void stop(@Nullable INetworkStackStatusCallback cb) {
+        mDeps.checkCaller();
+        sendMessage(CMD_STOP_DHCP_SERVER, cb);
+    }
+
+    private void sendMessage(int what, @Nullable Object obj) {
+        if (mHandler == null) {
+            mLog.e("Attempting to send a command to stopped DhcpServer: " + what);
+            return;
+        }
+        mHandler.sendMessage(mHandler.obtainMessage(what, obj));
+    }
+
+    private class ServerHandler extends Handler {
+        ServerHandler(@NonNull Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(@NonNull Message msg) {
+            final INetworkStackStatusCallback cb;
+            switch (msg.what) {
+                case CMD_UPDATE_PARAMS:
+                    final Pair<DhcpServingParams, INetworkStackStatusCallback> pair =
+                            (Pair<DhcpServingParams, INetworkStackStatusCallback>) msg.obj;
+                    final DhcpServingParams params = pair.first;
+                    mServingParams = params;
+                    mLeaseRepo.updateParams(
+                            DhcpServingParams.makeIpPrefix(mServingParams.serverAddr),
+                            params.excludedAddrs,
+                            params.dhcpLeaseTimeSecs);
+
+                    cb = pair.second;
+                    break;
+                case CMD_START_DHCP_SERVER:
+                    mPacketListener = mDeps.makePacketListener();
+                    mPacketListener.start();
+                    cb = (INetworkStackStatusCallback) msg.obj;
+                    break;
+                case CMD_STOP_DHCP_SERVER:
+                    if (mPacketListener != null) {
+                        mPacketListener.stop();
+                        mPacketListener = null;
+                    }
+                    mHandlerThread.quitSafely();
+                    cb = (INetworkStackStatusCallback) msg.obj;
+                    break;
+                default:
+                    return;
+            }
+            if (cb != null) {
+                try {
+                    cb.onStatusAvailable(STATUS_SUCCESS);
+                } catch (RemoteException e) {
+                    mLog.e("Could not send status back to caller", e);
+                }
+            }
+        }
+    }
+
+    @VisibleForTesting
+    void processPacket(@NonNull DhcpPacket packet, int srcPort) {
+        final String packetType = packet.getClass().getSimpleName();
+        if (srcPort != DHCP_CLIENT) {
+            mLog.logf("Ignored packet of type %s sent from client port %d", packetType, srcPort);
+            return;
+        }
+
+        mLog.log("Received packet of type " + packetType);
+        final Inet4Address sid = packet.mServerIdentifier;
+        if (sid != null && !sid.equals(mServingParams.serverAddr.getAddress())) {
+            mLog.log("Packet ignored due to wrong server identifier: " + sid);
+            return;
+        }
+
+        try {
+            if (packet instanceof DhcpDiscoverPacket) {
+                processDiscover((DhcpDiscoverPacket) packet);
+            } else if (packet instanceof DhcpRequestPacket) {
+                processRequest((DhcpRequestPacket) packet);
+            } else if (packet instanceof DhcpReleasePacket) {
+                processRelease((DhcpReleasePacket) packet);
+            } else {
+                mLog.e("Unknown packet type: " + packet.getClass().getSimpleName());
+            }
+        } catch (MalformedPacketException e) {
+            // Not an internal error: only logging exception message, not stacktrace
+            mLog.e("Ignored malformed packet: " + e.getMessage());
+        }
+    }
+
+    private void logIgnoredPacketInvalidSubnet(DhcpLeaseRepository.InvalidSubnetException e) {
+        // Not an internal error: only logging exception message, not stacktrace
+        mLog.e("Ignored packet from invalid subnet: " + e.getMessage());
+    }
+
+    private void processDiscover(@NonNull DhcpDiscoverPacket packet)
+            throws MalformedPacketException {
+        final DhcpLease lease;
+        final MacAddress clientMac = getMacAddr(packet);
+        try {
+            lease = mLeaseRepo.getOffer(packet.getExplicitClientIdOrNull(), clientMac,
+                    packet.mRelayIp, packet.mRequestedIp, packet.mHostName);
+        } catch (DhcpLeaseRepository.OutOfAddressesException e) {
+            transmitNak(packet, "Out of addresses to offer");
+            return;
+        } catch (DhcpLeaseRepository.InvalidSubnetException e) {
+            logIgnoredPacketInvalidSubnet(e);
+            return;
+        }
+
+        transmitOffer(packet, lease, clientMac);
+    }
+
+    private void processRequest(@NonNull DhcpRequestPacket packet) throws MalformedPacketException {
+        // If set, packet SID matches with this server's ID as checked in processPacket().
+        final boolean sidSet = packet.mServerIdentifier != null;
+        final DhcpLease lease;
+        final MacAddress clientMac = getMacAddr(packet);
+        try {
+            lease = mLeaseRepo.requestLease(packet.getExplicitClientIdOrNull(), clientMac,
+                    packet.mClientIp, packet.mRelayIp, packet.mRequestedIp, sidSet,
+                    packet.mHostName);
+        } catch (DhcpLeaseRepository.InvalidAddressException e) {
+            transmitNak(packet, "Invalid requested address");
+            return;
+        } catch (DhcpLeaseRepository.InvalidSubnetException e) {
+            logIgnoredPacketInvalidSubnet(e);
+            return;
+        }
+
+        transmitAck(packet, lease, clientMac);
+    }
+
+    private void processRelease(@NonNull DhcpReleasePacket packet)
+            throws MalformedPacketException {
+        final byte[] clientId = packet.getExplicitClientIdOrNull();
+        final MacAddress macAddr = getMacAddr(packet);
+        // Don't care about success (there is no ACK/NAK); logging is already done in the repository
+        mLeaseRepo.releaseLease(clientId, macAddr, packet.mClientIp);
+    }
+
+    private Inet4Address getAckOrOfferDst(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
+            boolean broadcastFlag) {
+        // Unless relayed or broadcast, send to client IP if already configured on the client, or to
+        // the lease address if the client has no configured address
+        if (!isEmpty(request.mRelayIp)) {
+            return request.mRelayIp;
+        } else if (broadcastFlag) {
+            return (Inet4Address) Inet4Address.ALL;
+        } else if (!isEmpty(request.mClientIp)) {
+            return request.mClientIp;
+        } else {
+            return lease.getNetAddr();
+        }
+    }
+
+    /**
+     * Determine whether the broadcast flag should be set in the BOOTP packet flags. This does not
+     * apply to NAK responses, which should always have it set.
+     */
+    private static boolean getBroadcastFlag(@NonNull DhcpPacket request, @NonNull DhcpLease lease) {
+        // No broadcast flag if the client already has a configured IP to unicast to. RFC2131 #4.1
+        // has some contradictions regarding broadcast behavior if a client already has an IP
+        // configured and sends a request with both ciaddr (renew/rebind) and the broadcast flag
+        // set. Sending a unicast response to ciaddr matches previous behavior and is more
+        // efficient.
+        // If the client has no configured IP, broadcast if requested by the client or if the lease
+        // address cannot be used to send a unicast reply either.
+        return isEmpty(request.mClientIp) && (request.mBroadcast || isEmpty(lease.getNetAddr()));
+    }
+
+    /**
+     * Get the hostname from a lease if non-empty and requested in the incoming request.
+     * @param request The incoming request.
+     * @return The hostname, or null if not requested or empty.
+     */
+    @Nullable
+    private static String getHostnameIfRequested(@NonNull DhcpPacket request,
+            @NonNull DhcpLease lease) {
+        return request.hasRequestedParam(DHCP_HOST_NAME) && !TextUtils.isEmpty(lease.getHostname())
+                ? lease.getHostname()
+                : null;
+    }
+
+    private boolean transmitOffer(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
+            @NonNull MacAddress clientMac) {
+        final boolean broadcastFlag = getBroadcastFlag(request, lease);
+        final int timeout = getLeaseTimeout(lease);
+        final Inet4Address prefixMask =
+                getPrefixMaskAsInet4Address(mServingParams.serverAddr.getPrefixLength());
+        final Inet4Address broadcastAddr = getBroadcastAddress(
+                mServingParams.getServerInet4Addr(), mServingParams.serverAddr.getPrefixLength());
+        final String hostname = getHostnameIfRequested(request, lease);
+        final ByteBuffer offerPacket = DhcpPacket.buildOfferPacket(
+                ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(),
+                request.mRelayIp, lease.getNetAddr(), request.mClientMac, timeout, prefixMask,
+                broadcastAddr, new ArrayList<>(mServingParams.defaultRouters),
+                new ArrayList<>(mServingParams.dnsServers),
+                mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
+                mServingParams.metered, (short) mServingParams.linkMtu);
+
+        return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag);
+    }
+
+    private boolean transmitAck(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
+            @NonNull MacAddress clientMac) {
+        // TODO: replace DhcpPacket's build methods with real builders and use common code with
+        // transmitOffer above
+        final boolean broadcastFlag = getBroadcastFlag(request, lease);
+        final int timeout = getLeaseTimeout(lease);
+        final String hostname = getHostnameIfRequested(request, lease);
+        final ByteBuffer ackPacket = DhcpPacket.buildAckPacket(ENCAP_BOOTP, request.mTransId,
+                broadcastFlag, mServingParams.getServerInet4Addr(), request.mRelayIp,
+                lease.getNetAddr(), request.mClientIp, request.mClientMac, timeout,
+                mServingParams.getPrefixMaskAsAddress(), mServingParams.getBroadcastAddress(),
+                new ArrayList<>(mServingParams.defaultRouters),
+                new ArrayList<>(mServingParams.dnsServers),
+                mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
+                mServingParams.metered, (short) mServingParams.linkMtu);
+
+        return transmitOfferOrAckPacket(ackPacket, request, lease, clientMac, broadcastFlag);
+    }
+
+    private boolean transmitNak(DhcpPacket request, String message) {
+        mLog.w("Transmitting NAK: " + message);
+        // Always set broadcast flag for NAK: client may not have a correct IP
+        final ByteBuffer nakPacket = DhcpPacket.buildNakPacket(
+                ENCAP_BOOTP, request.mTransId, mServingParams.getServerInet4Addr(),
+                request.mRelayIp, request.mClientMac, true /* broadcast */, message);
+
+        final Inet4Address dst = isEmpty(request.mRelayIp)
+                ? (Inet4Address) Inet4Address.ALL
+                : request.mRelayIp;
+        return transmitPacket(nakPacket, DhcpNakPacket.class.getSimpleName(), dst);
+    }
+
+    private boolean transmitOfferOrAckPacket(@NonNull ByteBuffer buf, @NonNull DhcpPacket request,
+            @NonNull DhcpLease lease, @NonNull MacAddress clientMac, boolean broadcastFlag) {
+        mLog.logf("Transmitting %s with lease %s", request.getClass().getSimpleName(), lease);
+        // Client may not yet respond to ARP for the lease address, which may be the destination
+        // address. Add an entry to the ARP cache to save future ARP probes and make sure the
+        // packet reaches its destination.
+        if (!addArpEntry(clientMac, lease.getNetAddr())) {
+            // Logging for error already done
+            return false;
+        }
+        final Inet4Address dst = getAckOrOfferDst(request, lease, broadcastFlag);
+        return transmitPacket(buf, request.getClass().getSimpleName(), dst);
+    }
+
+    private boolean transmitPacket(@NonNull ByteBuffer buf, @NonNull String packetTypeTag,
+            @NonNull Inet4Address dst) {
+        try {
+            mDeps.sendPacket(mSocket, buf, dst);
+        } catch (ErrnoException | IOException e) {
+            mLog.e("Can't send packet " + packetTypeTag, e);
+            return false;
+        }
+        return true;
+    }
+
+    private boolean addArpEntry(@NonNull MacAddress macAddr, @NonNull Inet4Address inetAddr) {
+        try {
+            mDeps.addArpEntry(inetAddr, macAddr, mIfName, mSocket);
+            return true;
+        } catch (IOException e) {
+            mLog.e("Error adding client to ARP table", e);
+            return false;
+        }
+    }
+
+    /**
+     * Get the remaining lease time in seconds, starting from {@link Clock#elapsedRealtime()}.
+     *
+     * <p>This is an unsigned 32-bit integer, so it cannot be read as a standard (signed) Java int.
+     * The return value is only intended to be used to populate the lease time field in a DHCP
+     * response, considering that lease time is an unsigned 32-bit integer field in DHCP packets.
+     *
+     * <p>Lease expiration times are tracked internally with millisecond precision: this method
+     * returns a rounded down value.
+     */
+    private int getLeaseTimeout(@NonNull DhcpLease lease) {
+        final long remainingTimeSecs = (lease.getExpTime() - mClock.elapsedRealtime()) / 1000;
+        if (remainingTimeSecs < 0) {
+            mLog.e("Processing expired lease " + lease);
+            return EXPIRED_FALLBACK_LEASE_TIME_SECS;
+        }
+
+        if (remainingTimeSecs >= toUnsignedLong(INFINITE_LEASE)) {
+            return INFINITE_LEASE;
+        }
+
+        return (int) remainingTimeSecs;
+    }
+
+    /**
+     * Get the client MAC address from a packet.
+     *
+     * @throws MalformedPacketException The address in the packet uses an unsupported format.
+     */
+    @NonNull
+    private MacAddress getMacAddr(@NonNull DhcpPacket packet) throws MalformedPacketException {
+        try {
+            return MacAddress.fromBytes(packet.getClientMac());
+        } catch (IllegalArgumentException e) {
+            final String message = "Invalid MAC address in packet: "
+                    + HexDump.dumpHexString(packet.getClientMac());
+            throw new MalformedPacketException(message, e);
+        }
+    }
+
+    private static boolean isEmpty(@Nullable Inet4Address address) {
+        return address == null || Inet4Address.ANY.equals(address);
+    }
+
+    private class PacketListener extends DhcpPacketListener {
+        PacketListener() {
+            super(mHandler);
+        }
+
+        @Override
+        protected void onReceive(@NonNull DhcpPacket packet, @NonNull Inet4Address srcAddr,
+                int srcPort) {
+            processPacket(packet, srcPort);
+        }
+
+        @Override
+        protected void logError(@NonNull String msg, Exception e) {
+            mLog.e("Error receiving packet: " + msg, e);
+        }
+
+        @Override
+        protected void logParseError(@NonNull byte[] packet, int length,
+                @NonNull DhcpPacket.ParseException e) {
+            mLog.e("Error parsing packet", e);
+        }
+
+        @Override
+        protected FileDescriptor createFd() {
+            // TODO: have and use an API to set a socket tag without going through the thread tag
+            final int oldTag = TrafficStats.getAndSetThreadStatsTag(TAG_SYSTEM_DHCP_SERVER);
+            try {
+                mSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+                SocketUtils.bindSocketToInterface(mSocket, mIfName);
+                Os.setsockoptInt(mSocket, SOL_SOCKET, SO_REUSEADDR, 1);
+                Os.setsockoptInt(mSocket, SOL_SOCKET, SO_BROADCAST, 1);
+                Os.bind(mSocket, Inet4Address.ANY, DHCP_SERVER);
+
+                return mSocket;
+            } catch (IOException | ErrnoException e) {
+                mLog.e("Error creating UDP socket", e);
+                DhcpServer.this.stop(null);
+                return null;
+            } finally {
+                TrafficStats.setThreadStatsTag(oldTag);
+            }
+        }
+    }
+}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java
new file mode 100644
index 0000000..868f3be
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java
@@ -0,0 +1,370 @@
+/*
+ * 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.dhcp;
+
+import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
+import static android.net.NetworkUtils.intToInet4AddressHTH;
+
+import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE;
+import static com.android.server.util.NetworkStackConstants.IPV4_MAX_MTU;
+import static com.android.server.util.NetworkStackConstants.IPV4_MIN_MTU;
+
+import static java.lang.Integer.toUnsignedLong;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.NetworkUtils;
+import android.util.ArraySet;
+
+import java.net.Inet4Address;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Parameters used by the DhcpServer to serve requests.
+ *
+ * <p>Instances are immutable. Use {@link DhcpServingParams.Builder} to instantiate.
+ * @hide
+ */
+public class DhcpServingParams {
+    public static final int MTU_UNSET = 0;
+    public static final int MIN_PREFIX_LENGTH = 16;
+    public static final int MAX_PREFIX_LENGTH = 30;
+
+    /** Server inet address and prefix to serve */
+    @NonNull
+    public final LinkAddress serverAddr;
+
+    /**
+     * Default routers to be advertised to DHCP clients. May be empty.
+     * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
+     */
+    @NonNull
+    public final Set<Inet4Address> defaultRouters;
+
+    /**
+     * DNS servers to be advertised to DHCP clients. May be empty.
+     * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
+     */
+    @NonNull
+    public final Set<Inet4Address> dnsServers;
+
+    /**
+     * Excluded addresses that the DHCP server is not allowed to assign to clients.
+     * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
+     */
+    @NonNull
+    public final Set<Inet4Address> excludedAddrs;
+
+    // DHCP uses uint32. Use long for clearer code, and check range when building.
+    public final long dhcpLeaseTimeSecs;
+    public final int linkMtu;
+
+    /**
+     * Indicates whether the DHCP server should send the ANDROID_METERED vendor-specific option.
+     */
+    public final boolean metered;
+
+    /**
+     * Checked exception thrown when some parameters used to build {@link DhcpServingParams} are
+     * missing or invalid.
+     */
+    public static class InvalidParameterException extends Exception {
+        public InvalidParameterException(String message) {
+            super(message);
+        }
+    }
+
+    private DhcpServingParams(@NonNull LinkAddress serverAddr,
+            @NonNull Set<Inet4Address> defaultRouters,
+            @NonNull Set<Inet4Address> dnsServers, @NonNull Set<Inet4Address> excludedAddrs,
+            long dhcpLeaseTimeSecs, int linkMtu, boolean metered) {
+        this.serverAddr = serverAddr;
+        this.defaultRouters = defaultRouters;
+        this.dnsServers = dnsServers;
+        this.excludedAddrs = excludedAddrs;
+        this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
+        this.linkMtu = linkMtu;
+        this.metered = metered;
+    }
+
+    /**
+     * Create parameters from a stable AIDL-compatible parcel.
+     * @throws InvalidParameterException The parameters parcelable is null or invalid.
+     */
+    public static DhcpServingParams fromParcelableObject(@Nullable DhcpServingParamsParcel parcel)
+            throws InvalidParameterException {
+        if (parcel == null) {
+            throw new InvalidParameterException("Null serving parameters");
+        }
+        final LinkAddress serverAddr = new LinkAddress(
+                intToInet4AddressHTH(parcel.serverAddr),
+                parcel.serverAddrPrefixLength);
+        return new Builder()
+                .setServerAddr(serverAddr)
+                .setDefaultRouters(toInet4AddressSet(parcel.defaultRouters))
+                .setDnsServers(toInet4AddressSet(parcel.dnsServers))
+                .setExcludedAddrs(toInet4AddressSet(parcel.excludedAddrs))
+                .setDhcpLeaseTimeSecs(parcel.dhcpLeaseTimeSecs)
+                .setLinkMtu(parcel.linkMtu)
+                .setMetered(parcel.metered)
+                .build();
+    }
+
+    private static Set<Inet4Address> toInet4AddressSet(@Nullable int[] addrs) {
+        if (addrs == null) {
+            return new HashSet<>(0);
+        }
+
+        final HashSet<Inet4Address> res = new HashSet<>();
+        for (int addr : addrs) {
+            res.add(intToInet4AddressHTH(addr));
+        }
+        return res;
+    }
+
+    @NonNull
+    public Inet4Address getServerInet4Addr() {
+        return (Inet4Address) serverAddr.getAddress();
+    }
+
+    /**
+     * Get the served prefix mask as an IPv4 address.
+     *
+     * <p>For example, if the served prefix is 192.168.42.0/24, this will return 255.255.255.0.
+     */
+    @NonNull
+    public Inet4Address getPrefixMaskAsAddress() {
+        return getPrefixMaskAsInet4Address(serverAddr.getPrefixLength());
+    }
+
+    /**
+     * Get the server broadcast address.
+     *
+     * <p>For example, if the server {@link LinkAddress} is 192.168.42.1/24, this will return
+     * 192.168.42.255.
+     */
+    @NonNull
+    public Inet4Address getBroadcastAddress() {
+        return NetworkUtils.getBroadcastAddress(getServerInet4Addr(), serverAddr.getPrefixLength());
+    }
+
+    /**
+     * Utility class to create new instances of {@link DhcpServingParams} while checking validity
+     * of the parameters.
+     */
+    public static class Builder {
+        private LinkAddress mServerAddr;
+        private Set<Inet4Address> mDefaultRouters;
+        private Set<Inet4Address> mDnsServers;
+        private Set<Inet4Address> mExcludedAddrs;
+        private long mDhcpLeaseTimeSecs;
+        private int mLinkMtu = MTU_UNSET;
+        private boolean mMetered;
+
+        /**
+         * Set the server address and served prefix for the DHCP server.
+         *
+         * <p>This parameter is required.
+         */
+        public Builder setServerAddr(@NonNull LinkAddress serverAddr) {
+            this.mServerAddr = serverAddr;
+            return this;
+        }
+
+        /**
+         * Set the default routers to be advertised to DHCP clients.
+         *
+         * <p>Each router must be inside the served prefix. This may be an empty set, but it must
+         * always be set explicitly before building the {@link DhcpServingParams}.
+         */
+        public Builder setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) {
+            this.mDefaultRouters = defaultRouters;
+            return this;
+        }
+
+        /**
+         * Set the default routers to be advertised to DHCP clients.
+         *
+         * <p>Each router must be inside the served prefix. This may be an empty list of routers,
+         * but it must always be set explicitly before building the {@link DhcpServingParams}.
+         */
+        public Builder setDefaultRouters(@NonNull Inet4Address... defaultRouters) {
+            return setDefaultRouters(new ArraySet<>(Arrays.asList(defaultRouters)));
+        }
+
+        /**
+         * Convenience method to build the parameters with no default router.
+         *
+         * <p>Equivalent to calling {@link #setDefaultRouters(Inet4Address...)} with no address.
+         */
+        public Builder withNoDefaultRouter() {
+            return setDefaultRouters();
+        }
+
+        /**
+         * Set the DNS servers to be advertised to DHCP clients.
+         *
+         * <p>This may be an empty set, but it must always be set explicitly before building the
+         * {@link DhcpServingParams}.
+         */
+        public Builder setDnsServers(@NonNull Set<Inet4Address> dnsServers) {
+            this.mDnsServers = dnsServers;
+            return this;
+        }
+
+        /**
+         * Set the DNS servers to be advertised to DHCP clients.
+         *
+         * <p>This may be an empty list of servers, but it must always be set explicitly before
+         * building the {@link DhcpServingParams}.
+         */
+        public Builder setDnsServers(@NonNull Inet4Address... dnsServers) {
+            return setDnsServers(new ArraySet<>(Arrays.asList(dnsServers)));
+        }
+
+        /**
+         * Convenience method to build the parameters with no DNS server.
+         *
+         * <p>Equivalent to calling {@link #setDnsServers(Inet4Address...)} with no address.
+         */
+        public Builder withNoDnsServer() {
+            return setDnsServers();
+        }
+
+        /**
+         * Set excluded addresses that the DHCP server is not allowed to assign to clients.
+         *
+         * <p>This parameter is optional. DNS servers and default routers are always excluded
+         * and do not need to be set here.
+         */
+        public Builder setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) {
+            this.mExcludedAddrs = excludedAddrs;
+            return this;
+        }
+
+        /**
+         * Set excluded addresses that the DHCP server is not allowed to assign to clients.
+         *
+         * <p>This parameter is optional. DNS servers and default routers are always excluded
+         * and do not need to be set here.
+         */
+        public Builder setExcludedAddrs(@NonNull Inet4Address... excludedAddrs) {
+            return setExcludedAddrs(new ArraySet<>(Arrays.asList(excludedAddrs)));
+        }
+
+        /**
+         * Set the lease time for leases assigned by the DHCP server.
+         *
+         * <p>This parameter is required.
+         */
+        public Builder setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) {
+            this.mDhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
+            return this;
+        }
+
+        /**
+         * Set the link MTU to be advertised to DHCP clients.
+         *
+         * <p>If set to {@link #MTU_UNSET}, no MTU will be advertised to clients. This parameter
+         * is optional and defaults to {@link #MTU_UNSET}.
+         */
+        public Builder setLinkMtu(int linkMtu) {
+            this.mLinkMtu = linkMtu;
+            return this;
+        }
+
+        /**
+         * Set whether the DHCP server should send the ANDROID_METERED vendor-specific option.
+         *
+         * <p>If not set, the default value is false.
+         */
+        public Builder setMetered(boolean metered) {
+            this.mMetered = metered;
+            return this;
+        }
+
+        /**
+         * Create a new {@link DhcpServingParams} instance based on parameters set in the builder.
+         *
+         * <p>This method has no side-effects. If it does not throw, a valid
+         * {@link DhcpServingParams} is returned.
+         * @return The constructed parameters.
+         * @throws InvalidParameterException At least one parameter is missing or invalid.
+         */
+        @NonNull
+        public DhcpServingParams build() throws InvalidParameterException {
+            if (mServerAddr == null) {
+                throw new InvalidParameterException("Missing serverAddr");
+            }
+            if (mDefaultRouters == null) {
+                throw new InvalidParameterException("Missing defaultRouters");
+            }
+            if (mDnsServers == null) {
+                // Empty set is OK, but enforce explicitly setting it
+                throw new InvalidParameterException("Missing dnsServers");
+            }
+            if (mDhcpLeaseTimeSecs <= 0 || mDhcpLeaseTimeSecs > toUnsignedLong(INFINITE_LEASE)) {
+                throw new InvalidParameterException("Invalid lease time: " + mDhcpLeaseTimeSecs);
+            }
+            if (mLinkMtu != MTU_UNSET && (mLinkMtu < IPV4_MIN_MTU || mLinkMtu > IPV4_MAX_MTU)) {
+                throw new InvalidParameterException("Invalid link MTU: " + mLinkMtu);
+            }
+            if (!mServerAddr.isIPv4()) {
+                throw new InvalidParameterException("serverAddr must be IPv4");
+            }
+            if (mServerAddr.getPrefixLength() < MIN_PREFIX_LENGTH
+                    || mServerAddr.getPrefixLength() > MAX_PREFIX_LENGTH) {
+                throw new InvalidParameterException("Prefix length is not in supported range");
+            }
+
+            final IpPrefix prefix = makeIpPrefix(mServerAddr);
+            for (Inet4Address addr : mDefaultRouters) {
+                if (!prefix.contains(addr)) {
+                    throw new InvalidParameterException(String.format(
+                            "Default router %s is not in server prefix %s", addr, mServerAddr));
+                }
+            }
+
+            final Set<Inet4Address> excl = new HashSet<>();
+            if (mExcludedAddrs != null) {
+                excl.addAll(mExcludedAddrs);
+            }
+            excl.add((Inet4Address) mServerAddr.getAddress());
+            excl.addAll(mDefaultRouters);
+            excl.addAll(mDnsServers);
+
+            return new DhcpServingParams(mServerAddr,
+                    Collections.unmodifiableSet(new HashSet<>(mDefaultRouters)),
+                    Collections.unmodifiableSet(new HashSet<>(mDnsServers)),
+                    Collections.unmodifiableSet(excl),
+                    mDhcpLeaseTimeSecs, mLinkMtu, mMetered);
+        }
+    }
+
+    /**
+     * Utility method to create an IpPrefix with the address and prefix length of a LinkAddress.
+     */
+    @NonNull
+    static IpPrefix makeIpPrefix(@NonNull LinkAddress addr) {
+        return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
+    }
+}
diff --git a/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java b/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java
new file mode 100644
index 0000000..385dd52
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static android.net.util.SocketUtils.makePacketSocketAddress;
+import static android.system.OsConstants.AF_PACKET;
+import static android.system.OsConstants.ARPHRD_ETHER;
+import static android.system.OsConstants.ETH_P_ALL;
+import static android.system.OsConstants.SOCK_RAW;
+
+import android.net.NetworkUtils;
+import android.net.util.ConnectivityPacketSummary;
+import android.net.util.InterfaceParams;
+import android.net.util.PacketReader;
+import android.os.Handler;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.text.TextUtils;
+import android.util.LocalLog;
+import android.util.Log;
+
+import libcore.util.HexEncoding;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+
+/**
+ * Critical connectivity packet tracking daemon.
+ *
+ * Tracks ARP, DHCPv4, and IPv6 RS/RA/NS/NA packets.
+ *
+ * This class's constructor, start() and stop() methods must only be called
+ * from the same thread on which the passed in |log| is accessed.
+ *
+ * Log lines include a hexdump of the packet, which can be decoded via:
+ *
+ *     echo -n H3XSTR1NG | sed -e 's/\([0-9A-F][0-9A-F]\)/\1 /g' -e 's/^/000000 /'
+ *                       | text2pcap - -
+ *                       | tcpdump -n -vv -e -r -
+ *
+ * @hide
+ */
+public class ConnectivityPacketTracker {
+    private static final String TAG = ConnectivityPacketTracker.class.getSimpleName();
+    private static final boolean DBG = false;
+    private static final String MARK_START = "--- START ---";
+    private static final String MARK_STOP = "--- STOP ---";
+    private static final String MARK_NAMED_START = "--- START (%s) ---";
+    private static final String MARK_NAMED_STOP = "--- STOP (%s) ---";
+
+    private final String mTag;
+    private final LocalLog mLog;
+    private final PacketReader mPacketListener;
+    private boolean mRunning;
+    private String mDisplayName;
+
+    public ConnectivityPacketTracker(Handler h, InterfaceParams ifParams, LocalLog log) {
+        if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams");
+
+        mTag = TAG + "." + ifParams.name;
+        mLog = log;
+        mPacketListener = new PacketListener(h, ifParams);
+    }
+
+    public void start(String displayName) {
+        mRunning = true;
+        mDisplayName = displayName;
+        mPacketListener.start();
+    }
+
+    public void stop() {
+        mPacketListener.stop();
+        mRunning = false;
+        mDisplayName = null;
+    }
+
+    private final class PacketListener extends PacketReader {
+        private final InterfaceParams mInterface;
+
+        PacketListener(Handler h, InterfaceParams ifParams) {
+            super(h, ifParams.defaultMtu);
+            mInterface = ifParams;
+        }
+
+        @Override
+        protected FileDescriptor createFd() {
+            FileDescriptor s = null;
+            try {
+                s = Os.socket(AF_PACKET, SOCK_RAW, 0);
+                NetworkUtils.attachControlPacketFilter(s, ARPHRD_ETHER);
+                Os.bind(s, makePacketSocketAddress((short) ETH_P_ALL, mInterface.index));
+            } catch (ErrnoException | IOException e) {
+                logError("Failed to create packet tracking socket: ", e);
+                closeFd(s);
+                return null;
+            }
+            return s;
+        }
+
+        @Override
+        protected void handlePacket(byte[] recvbuf, int length) {
+            final String summary = ConnectivityPacketSummary.summarize(
+                    mInterface.macAddr, recvbuf, length);
+            if (summary == null) return;
+
+            if (DBG) Log.d(mTag, summary);
+            addLogEntry(summary +
+                        "\n[" + new String(HexEncoding.encode(recvbuf, 0, length)) + "]");
+        }
+
+        @Override
+        protected void onStart() {
+            final String msg = TextUtils.isEmpty(mDisplayName)
+                    ? MARK_START
+                    : String.format(MARK_NAMED_START, mDisplayName);
+            mLog.log(msg);
+        }
+
+        @Override
+        protected void onStop() {
+            String msg = TextUtils.isEmpty(mDisplayName)
+                    ? MARK_STOP
+                    : String.format(MARK_NAMED_STOP, mDisplayName);
+            if (!mRunning) msg += " (packet listener stopped unexpectedly)";
+            mLog.log(msg);
+        }
+
+        @Override
+        protected void logError(String msg, Exception e) {
+            Log.e(mTag, msg, e);
+            addLogEntry(msg + e);
+        }
+
+        private void addLogEntry(String entry) {
+            mLog.log(entry);
+        }
+    }
+}
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
new file mode 100644
index 0000000..ad7f85d
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -0,0 +1,1691 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable;
+import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
+import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable;
+
+import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.DhcpResults;
+import android.net.INetd;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.ProvisioningConfigurationParcelable;
+import android.net.ProxyInfo;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfo;
+import android.net.apf.ApfCapabilities;
+import android.net.apf.ApfFilter;
+import android.net.dhcp.DhcpClient;
+import android.net.ip.IIpClientCallbacks;
+import android.net.metrics.IpConnectivityLog;
+import android.net.metrics.IpManagerEvent;
+import android.net.shared.InitialConfiguration;
+import android.net.shared.NetdService;
+import android.net.shared.ProvisioningConfiguration;
+import android.net.util.InterfaceParams;
+import android.net.util.SharedLog;
+import android.os.ConditionVariable;
+import android.os.INetworkManagementService;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.LocalLog;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IState;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.MessageUtils;
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.internal.util.WakeupMessage;
+import com.android.server.net.NetlinkTracker;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+
+/**
+ * IpClient
+ *
+ * This class provides the interface to IP-layer provisioning and maintenance
+ * functionality that can be used by transport layers like Wi-Fi, Ethernet,
+ * et cetera.
+ *
+ * [ Lifetime ]
+ * IpClient is designed to be instantiated as soon as the interface name is
+ * known and can be as long-lived as the class containing it (i.e. declaring
+ * it "private final" is okay).
+ *
+ * @hide
+ */
+public class IpClient extends StateMachine {
+    private static final boolean DBG = false;
+
+    // For message logging.
+    private static final Class[] sMessageClasses = { IpClient.class, DhcpClient.class };
+    private static final SparseArray<String> sWhatToString =
+            MessageUtils.findMessageNames(sMessageClasses);
+    // Two static concurrent hashmaps of interface name to logging classes.
+    // One holds StateMachine logs and the other connectivity packet logs.
+    private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>();
+    private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>();
+
+    /**
+     * Dump all state machine and connectivity packet logs to the specified writer.
+     * @param skippedIfaces Interfaces for which logs should not be dumped.
+     */
+    public static void dumpAllLogs(PrintWriter writer, Set<String> skippedIfaces) {
+        for (String ifname : sSmLogs.keySet()) {
+            if (skippedIfaces.contains(ifname)) continue;
+
+            writer.println(String.format("--- BEGIN %s ---", ifname));
+
+            final SharedLog smLog = sSmLogs.get(ifname);
+            if (smLog != null) {
+                writer.println("State machine log:");
+                smLog.dump(null, writer, null);
+            }
+
+            writer.println("");
+
+            final LocalLog pktLog = sPktLogs.get(ifname);
+            if (pktLog != null) {
+                writer.println("Connectivity packet log:");
+                pktLog.readOnlyLocalLog().dump(null, writer, null);
+            }
+
+            writer.println(String.format("--- END %s ---", ifname));
+        }
+    }
+
+    // Use a wrapper class to log in order to ensure complete and detailed
+    // logging. This method is lighter weight than annotations/reflection
+    // and has the following benefits:
+    //
+    //     - No invoked method can be forgotten.
+    //       Any new method added to IpClient.Callback must be overridden
+    //       here or it will never be called.
+    //
+    //     - No invoking call site can be forgotten.
+    //       Centralized logging in this way means call sites don't need to
+    //       remember to log, and therefore no call site can be forgotten.
+    //
+    //     - No variation in log format among call sites.
+    //       Encourages logging of any available arguments, and all call sites
+    //       are necessarily logged identically.
+    //
+    // NOTE: Log first because passed objects may or may not be thread-safe and
+    // once passed on to the callback they may be modified by another thread.
+    //
+    // TODO: Find an lighter weight approach.
+    public static class IpClientCallbacksWrapper {
+        private static final String PREFIX = "INVOKE ";
+        private final IIpClientCallbacks mCallback;
+        private final SharedLog mLog;
+
+        @VisibleForTesting
+        protected IpClientCallbacksWrapper(IIpClientCallbacks callback, SharedLog log) {
+            mCallback = callback;
+            mLog = log;
+        }
+
+        private void log(String msg) {
+            mLog.log(PREFIX + msg);
+        }
+
+        private void log(String msg, Throwable e) {
+            mLog.e(PREFIX + msg, e);
+        }
+
+        public void onPreDhcpAction() {
+            log("onPreDhcpAction()");
+            try {
+                mCallback.onPreDhcpAction();
+            } catch (RemoteException e) {
+                log("Failed to call onPreDhcpAction", e);
+            }
+        }
+
+        public void onPostDhcpAction() {
+            log("onPostDhcpAction()");
+            try {
+                mCallback.onPostDhcpAction();
+            } catch (RemoteException e) {
+                log("Failed to call onPostDhcpAction", e);
+            }
+        }
+
+        public void onNewDhcpResults(DhcpResults dhcpResults) {
+            log("onNewDhcpResults({" + dhcpResults + "})");
+            try {
+                mCallback.onNewDhcpResults(toStableParcelable(dhcpResults));
+            } catch (RemoteException e) {
+                log("Failed to call onNewDhcpResults", e);
+            }
+        }
+
+        public void onProvisioningSuccess(LinkProperties newLp) {
+            log("onProvisioningSuccess({" + newLp + "})");
+            try {
+                mCallback.onProvisioningSuccess(toStableParcelable(newLp));
+            } catch (RemoteException e) {
+                log("Failed to call onProvisioningSuccess", e);
+            }
+        }
+
+        public void onProvisioningFailure(LinkProperties newLp) {
+            log("onProvisioningFailure({" + newLp + "})");
+            try {
+                mCallback.onProvisioningFailure(toStableParcelable(newLp));
+            } catch (RemoteException e) {
+                log("Failed to call onProvisioningFailure", e);
+            }
+        }
+
+        public void onLinkPropertiesChange(LinkProperties newLp) {
+            log("onLinkPropertiesChange({" + newLp + "})");
+            try {
+                mCallback.onLinkPropertiesChange(toStableParcelable(newLp));
+            } catch (RemoteException e) {
+                log("Failed to call onLinkPropertiesChange", e);
+            }
+        }
+
+        public void onReachabilityLost(String logMsg) {
+            log("onReachabilityLost(" + logMsg + ")");
+            try {
+                mCallback.onReachabilityLost(logMsg);
+            } catch (RemoteException e) {
+                log("Failed to call onReachabilityLost", e);
+            }
+        }
+
+        public void onQuit() {
+            log("onQuit()");
+            try {
+                mCallback.onQuit();
+            } catch (RemoteException e) {
+                log("Failed to call onQuit", e);
+            }
+        }
+
+        public void installPacketFilter(byte[] filter) {
+            log("installPacketFilter(byte[" + filter.length + "])");
+            try {
+                mCallback.installPacketFilter(filter);
+            } catch (RemoteException e) {
+                log("Failed to call installPacketFilter", e);
+            }
+        }
+
+        public void startReadPacketFilter() {
+            log("startReadPacketFilter()");
+            try {
+                mCallback.startReadPacketFilter();
+            } catch (RemoteException e) {
+                log("Failed to call startReadPacketFilter", e);
+            }
+        }
+
+        public void setFallbackMulticastFilter(boolean enabled) {
+            log("setFallbackMulticastFilter(" + enabled + ")");
+            try {
+                mCallback.setFallbackMulticastFilter(enabled);
+            } catch (RemoteException e) {
+                log("Failed to call setFallbackMulticastFilter", e);
+            }
+        }
+
+        public void setNeighborDiscoveryOffload(boolean enable) {
+            log("setNeighborDiscoveryOffload(" + enable + ")");
+            try {
+                mCallback.setNeighborDiscoveryOffload(enable);
+            } catch (RemoteException e) {
+                log("Failed to call setNeighborDiscoveryOffload", e);
+            }
+        }
+    }
+
+    public static final String DUMP_ARG_CONFIRM = "confirm";
+
+    private static final int CMD_TERMINATE_AFTER_STOP             = 1;
+    private static final int CMD_STOP                             = 2;
+    private static final int CMD_START                            = 3;
+    private static final int CMD_CONFIRM                          = 4;
+    private static final int EVENT_PRE_DHCP_ACTION_COMPLETE       = 5;
+    // Triggered by NetlinkTracker to communicate netlink events.
+    private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 6;
+    private static final int CMD_UPDATE_TCP_BUFFER_SIZES          = 7;
+    private static final int CMD_UPDATE_HTTP_PROXY                = 8;
+    private static final int CMD_SET_MULTICAST_FILTER             = 9;
+    private static final int EVENT_PROVISIONING_TIMEOUT           = 10;
+    private static final int EVENT_DHCPACTION_TIMEOUT             = 11;
+    private static final int EVENT_READ_PACKET_FILTER_COMPLETE    = 12;
+
+    // Internal commands to use instead of trying to call transitionTo() inside
+    // a given State's enter() method. Calling transitionTo() from enter/exit
+    // encounters a Log.wtf() that can cause trouble on eng builds.
+    private static final int CMD_JUMP_STARTED_TO_RUNNING          = 100;
+    private static final int CMD_JUMP_RUNNING_TO_STOPPING         = 101;
+    private static final int CMD_JUMP_STOPPING_TO_STOPPED         = 102;
+
+    // IpClient shares a handler with DhcpClient: commands must not overlap
+    public static final int DHCPCLIENT_CMD_BASE = 1000;
+
+    private static final int MAX_LOG_RECORDS = 500;
+    private static final int MAX_PACKET_RECORDS = 100;
+
+    private static final boolean NO_CALLBACKS = false;
+    private static final boolean SEND_CALLBACKS = true;
+
+    // This must match the interface prefix in clatd.c.
+    // TODO: Revert this hack once IpClient and Nat464Xlat work in concert.
+    private static final String CLAT_PREFIX = "v4-";
+
+    private static final int IMMEDIATE_FAILURE_DURATION = 0;
+
+    private static final int PROV_CHANGE_STILL_NOT_PROVISIONED = 1;
+    private static final int PROV_CHANGE_LOST_PROVISIONING = 2;
+    private static final int PROV_CHANGE_GAINED_PROVISIONING = 3;
+    private static final int PROV_CHANGE_STILL_PROVISIONED = 4;
+
+    private final State mStoppedState = new StoppedState();
+    private final State mStoppingState = new StoppingState();
+    private final State mStartedState = new StartedState();
+    private final State mRunningState = new RunningState();
+
+    private final String mTag;
+    private final Context mContext;
+    private final String mInterfaceName;
+    private final String mClatInterfaceName;
+    @VisibleForTesting
+    protected final IpClientCallbacksWrapper mCallback;
+    private final Dependencies mDependencies;
+    private final CountDownLatch mShutdownLatch;
+    private final ConnectivityManager mCm;
+    private final INetworkManagementService mNwService;
+    private final NetlinkTracker mNetlinkTracker;
+    private final WakeupMessage mProvisioningTimeoutAlarm;
+    private final WakeupMessage mDhcpActionTimeoutAlarm;
+    private final SharedLog mLog;
+    private final LocalLog mConnectivityPacketLog;
+    private final MessageHandlingLogger mMsgStateLogger;
+    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
+    private final InterfaceController mInterfaceCtrl;
+
+    private InterfaceParams mInterfaceParams;
+
+    /**
+     * Non-final member variables accessed only from within our StateMachine.
+     */
+    private LinkProperties mLinkProperties;
+    private android.net.shared.ProvisioningConfiguration mConfiguration;
+    private IpReachabilityMonitor mIpReachabilityMonitor;
+    private DhcpClient mDhcpClient;
+    private DhcpResults mDhcpResults;
+    private String mTcpBufferSizes;
+    private ProxyInfo mHttpProxy;
+    private ApfFilter mApfFilter;
+    private boolean mMulticastFiltering;
+    private long mStartTimeMillis;
+
+    /**
+     * Reading the snapshot is an asynchronous operation initiated by invoking
+     * Callback.startReadPacketFilter() and completed when the WiFi Service responds with an
+     * EVENT_READ_PACKET_FILTER_COMPLETE message. The mApfDataSnapshotComplete condition variable
+     * signals when a new snapshot is ready.
+     */
+    private final ConditionVariable mApfDataSnapshotComplete = new ConditionVariable();
+
+    public static class Dependencies {
+        public INetworkManagementService getNMS() {
+            return INetworkManagementService.Stub.asInterface(
+                    ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+        }
+
+        public INetd getNetd() {
+            return NetdService.getInstance();
+        }
+
+        /**
+         * Get interface parameters for the specified interface.
+         */
+        public InterfaceParams getInterfaceParams(String ifname) {
+            return InterfaceParams.getByName(ifname);
+        }
+    }
+
+    public IpClient(Context context, String ifName, IIpClientCallbacks callback) {
+        this(context, ifName, callback, new Dependencies());
+    }
+
+    /**
+     * An expanded constructor, useful for dependency injection.
+     * TODO: migrate all test users to mock IpClient directly and remove this ctor.
+     */
+    public IpClient(Context context, String ifName, IIpClientCallbacks callback,
+            INetworkManagementService nwService) {
+        this(context, ifName, callback, new Dependencies() {
+            @Override
+            public INetworkManagementService getNMS() {
+                return nwService;
+            }
+        });
+    }
+
+    @VisibleForTesting
+    IpClient(Context context, String ifName, IIpClientCallbacks callback, Dependencies deps) {
+        super(IpClient.class.getSimpleName() + "." + ifName);
+        Preconditions.checkNotNull(ifName);
+        Preconditions.checkNotNull(callback);
+
+        mTag = getName();
+
+        mContext = context;
+        mInterfaceName = ifName;
+        mClatInterfaceName = CLAT_PREFIX + ifName;
+        mDependencies = deps;
+        mShutdownLatch = new CountDownLatch(1);
+        mCm = mContext.getSystemService(ConnectivityManager.class);
+        mNwService = deps.getNMS();
+
+        sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
+        mLog = sSmLogs.get(mInterfaceName);
+        sPktLogs.putIfAbsent(mInterfaceName, new LocalLog(MAX_PACKET_RECORDS));
+        mConnectivityPacketLog = sPktLogs.get(mInterfaceName);
+        mMsgStateLogger = new MessageHandlingLogger();
+        mCallback = new IpClientCallbacksWrapper(callback, mLog);
+
+        // TODO: Consider creating, constructing, and passing in some kind of
+        // InterfaceController.Dependencies class.
+        mInterfaceCtrl = new InterfaceController(mInterfaceName, deps.getNetd(), mLog);
+
+        mNetlinkTracker = new NetlinkTracker(
+                mInterfaceName,
+                new NetlinkTracker.Callback() {
+                    @Override
+                    public void update() {
+                        sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED);
+                    }
+                }) {
+            @Override
+            public void interfaceAdded(String iface) {
+                super.interfaceAdded(iface);
+                if (mClatInterfaceName.equals(iface)) {
+                    mCallback.setNeighborDiscoveryOffload(false);
+                } else if (!mInterfaceName.equals(iface)) {
+                    return;
+                }
+
+                final String msg = "interfaceAdded(" + iface + ")";
+                logMsg(msg);
+            }
+
+            @Override
+            public void interfaceRemoved(String iface) {
+                super.interfaceRemoved(iface);
+                // TODO: Also observe mInterfaceName going down and take some
+                // kind of appropriate action.
+                if (mClatInterfaceName.equals(iface)) {
+                    // TODO: consider sending a message to the IpClient main
+                    // StateMachine thread, in case "NDO enabled" state becomes
+                    // tied to more things that 464xlat operation.
+                    mCallback.setNeighborDiscoveryOffload(true);
+                } else if (!mInterfaceName.equals(iface)) {
+                    return;
+                }
+
+                final String msg = "interfaceRemoved(" + iface + ")";
+                logMsg(msg);
+            }
+
+            private void logMsg(String msg) {
+                Log.d(mTag, msg);
+                getHandler().post(() -> mLog.log("OBSERVED " + msg));
+            }
+        };
+
+        mLinkProperties = new LinkProperties();
+        mLinkProperties.setInterfaceName(mInterfaceName);
+
+        mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
+                mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT);
+        mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
+                mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT);
+
+        // Anything the StateMachine may access must have been instantiated
+        // before this point.
+        configureAndStartStateMachine();
+
+        // Anything that may send messages to the StateMachine must only be
+        // configured to do so after the StateMachine has started (above).
+        startStateMachineUpdaters();
+    }
+
+    /**
+     * Make a IIpClient connector to communicate with this IpClient.
+     */
+    public IIpClient makeConnector() {
+        return new IpClientConnector();
+    }
+
+    class IpClientConnector extends IIpClient.Stub {
+        @Override
+        public void completedPreDhcpAction() {
+            checkNetworkStackCallingPermission();
+            IpClient.this.completedPreDhcpAction();
+        }
+        @Override
+        public void confirmConfiguration() {
+            checkNetworkStackCallingPermission();
+            IpClient.this.confirmConfiguration();
+        }
+        @Override
+        public void readPacketFilterComplete(byte[] data) {
+            checkNetworkStackCallingPermission();
+            IpClient.this.readPacketFilterComplete(data);
+        }
+        @Override
+        public void shutdown() {
+            checkNetworkStackCallingPermission();
+            IpClient.this.shutdown();
+        }
+        @Override
+        public void startProvisioning(ProvisioningConfigurationParcelable req) {
+            checkNetworkStackCallingPermission();
+            IpClient.this.startProvisioning(ProvisioningConfiguration.fromStableParcelable(req));
+        }
+        @Override
+        public void stop() {
+            checkNetworkStackCallingPermission();
+            IpClient.this.stop();
+        }
+        @Override
+        public void setTcpBufferSizes(String tcpBufferSizes) {
+            checkNetworkStackCallingPermission();
+            IpClient.this.setTcpBufferSizes(tcpBufferSizes);
+        }
+        @Override
+        public void setHttpProxy(ProxyInfoParcelable proxyInfo) {
+            checkNetworkStackCallingPermission();
+            IpClient.this.setHttpProxy(fromStableParcelable(proxyInfo));
+        }
+        @Override
+        public void setMulticastFilter(boolean enabled) {
+            checkNetworkStackCallingPermission();
+            IpClient.this.setMulticastFilter(enabled);
+        }
+    }
+
+    public String getInterfaceName() {
+        return mInterfaceName;
+    }
+
+    private void configureAndStartStateMachine() {
+        // CHECKSTYLE:OFF IndentationCheck
+        addState(mStoppedState);
+        addState(mStartedState);
+            addState(mRunningState, mStartedState);
+        addState(mStoppingState);
+        // CHECKSTYLE:ON IndentationCheck
+
+        setInitialState(mStoppedState);
+
+        super.start();
+    }
+
+    private void startStateMachineUpdaters() {
+        try {
+            mNwService.registerObserver(mNetlinkTracker);
+        } catch (RemoteException e) {
+            logError("Couldn't register NetlinkTracker: %s", e);
+        }
+    }
+
+    private void stopStateMachineUpdaters() {
+        try {
+            mNwService.unregisterObserver(mNetlinkTracker);
+        } catch (RemoteException e) {
+            logError("Couldn't unregister NetlinkTracker: %s", e);
+        }
+    }
+
+    @Override
+    protected void onQuitting() {
+        mCallback.onQuit();
+        mShutdownLatch.countDown();
+    }
+
+    /**
+     * Shut down this IpClient instance altogether.
+     */
+    public void shutdown() {
+        stop();
+        sendMessage(CMD_TERMINATE_AFTER_STOP);
+    }
+
+    /**
+     * Start provisioning with the provided parameters.
+     */
+    public void startProvisioning(ProvisioningConfiguration req) {
+        if (!req.isValid()) {
+            doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
+            return;
+        }
+
+        mInterfaceParams = mDependencies.getInterfaceParams(mInterfaceName);
+        if (mInterfaceParams == null) {
+            logError("Failed to find InterfaceParams for " + mInterfaceName);
+            doImmediateProvisioningFailure(IpManagerEvent.ERROR_INTERFACE_NOT_FOUND);
+            return;
+        }
+
+        mCallback.setNeighborDiscoveryOffload(true);
+        sendMessage(CMD_START, new android.net.shared.ProvisioningConfiguration(req));
+    }
+
+    /**
+     * Stop this IpClient.
+     *
+     * <p>This does not shut down the StateMachine itself, which is handled by {@link #shutdown()}.
+     */
+    public void stop() {
+        sendMessage(CMD_STOP);
+    }
+
+    /**
+     * Confirm the provisioning configuration.
+     */
+    public void confirmConfiguration() {
+        sendMessage(CMD_CONFIRM);
+    }
+
+    /**
+     * For clients using {@link ProvisioningConfiguration.Builder#withPreDhcpAction()}, must be
+     * called after {@link IIpClientCallbacks#onPreDhcpAction} to indicate that DHCP is clear to
+     * proceed.
+     */
+    public void completedPreDhcpAction() {
+        sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
+    }
+
+    /**
+     * Indicate that packet filter read is complete.
+     */
+    public void readPacketFilterComplete(byte[] data) {
+        sendMessage(EVENT_READ_PACKET_FILTER_COMPLETE, data);
+    }
+
+    /**
+     * Set the TCP buffer sizes to use.
+     *
+     * This may be called, repeatedly, at any time before or after a call to
+     * #startProvisioning(). The setting is cleared upon calling #stop().
+     */
+    public void setTcpBufferSizes(String tcpBufferSizes) {
+        sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes);
+    }
+
+    /**
+     * Set the HTTP Proxy configuration to use.
+     *
+     * This may be called, repeatedly, at any time before or after a call to
+     * #startProvisioning(). The setting is cleared upon calling #stop().
+     */
+    public void setHttpProxy(ProxyInfo proxyInfo) {
+        sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
+    }
+
+    /**
+     * Enable or disable the multicast filter.  Attempts to use APF to accomplish the filtering,
+     * if not, Callback.setFallbackMulticastFilter() is called.
+     */
+    public void setMulticastFilter(boolean enabled) {
+        sendMessage(CMD_SET_MULTICAST_FILTER, enabled);
+    }
+
+    /**
+     * Dump logs of this IpClient.
+     */
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        if (args != null && args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) {
+            // Execute confirmConfiguration() and take no further action.
+            confirmConfiguration();
+            return;
+        }
+
+        // Thread-unsafe access to mApfFilter but just used for debugging.
+        final ApfFilter apfFilter = mApfFilter;
+        final android.net.shared.ProvisioningConfiguration provisioningConfig = mConfiguration;
+        final ApfCapabilities apfCapabilities = (provisioningConfig != null)
+                ? provisioningConfig.mApfCapabilities : null;
+
+        IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+        pw.println(mTag + " APF dump:");
+        pw.increaseIndent();
+        if (apfFilter != null) {
+            if (apfCapabilities.hasDataAccess()) {
+                // Request a new snapshot, then wait for it.
+                mApfDataSnapshotComplete.close();
+                mCallback.startReadPacketFilter();
+                if (!mApfDataSnapshotComplete.block(1000)) {
+                    pw.print("TIMEOUT: DUMPING STALE APF SNAPSHOT");
+                }
+            }
+            apfFilter.dump(pw);
+
+        } else {
+            pw.print("No active ApfFilter; ");
+            if (provisioningConfig == null) {
+                pw.println("IpClient not yet started.");
+            } else if (apfCapabilities == null || apfCapabilities.apfVersionSupported == 0) {
+                pw.println("Hardware does not support APF.");
+            } else {
+                pw.println("ApfFilter not yet started, APF capabilities: " + apfCapabilities);
+            }
+        }
+        pw.decreaseIndent();
+        pw.println();
+        pw.println(mTag + " current ProvisioningConfiguration:");
+        pw.increaseIndent();
+        pw.println(Objects.toString(provisioningConfig, "N/A"));
+        pw.decreaseIndent();
+
+        final IpReachabilityMonitor iprm = mIpReachabilityMonitor;
+        if (iprm != null) {
+            pw.println();
+            pw.println(mTag + " current IpReachabilityMonitor state:");
+            pw.increaseIndent();
+            iprm.dump(pw);
+            pw.decreaseIndent();
+        }
+
+        pw.println();
+        pw.println(mTag + " StateMachine dump:");
+        pw.increaseIndent();
+        mLog.dump(fd, pw, args);
+        pw.decreaseIndent();
+
+        pw.println();
+        pw.println(mTag + " connectivity packet log:");
+        pw.println();
+        pw.println("Debug with python and scapy via:");
+        pw.println("shell$ python");
+        pw.println(">>> from scapy import all as scapy");
+        pw.println(">>> scapy.Ether(\"<paste_hex_string>\".decode(\"hex\")).show2()");
+        pw.println();
+
+        pw.increaseIndent();
+        mConnectivityPacketLog.readOnlyLocalLog().dump(fd, pw, args);
+        pw.decreaseIndent();
+    }
+
+
+    /**
+     * Internals.
+     */
+
+    @Override
+    protected String getWhatToString(int what) {
+        return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what));
+    }
+
+    @Override
+    protected String getLogRecString(Message msg) {
+        final String logLine = String.format(
+                "%s/%d %d %d %s [%s]",
+                mInterfaceName, (mInterfaceParams == null) ? -1 : mInterfaceParams.index,
+                msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
+
+        final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
+        mLog.log(richerLogLine);
+        if (DBG) {
+            Log.d(mTag, richerLogLine);
+        }
+
+        mMsgStateLogger.reset();
+        return logLine;
+    }
+
+    @Override
+    protected boolean recordLogRec(Message msg) {
+        // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy,
+        // and we already log any LinkProperties change that results in an
+        // invocation of IpClient.Callback#onLinkPropertiesChange().
+        final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
+        if (!shouldLog) {
+            mMsgStateLogger.reset();
+        }
+        return shouldLog;
+    }
+
+    private void logError(String fmt, Object... args) {
+        final String msg = "ERROR " + String.format(fmt, args);
+        Log.e(mTag, msg);
+        mLog.log(msg);
+    }
+
+    // This needs to be called with care to ensure that our LinkProperties
+    // are in sync with the actual LinkProperties of the interface. For example,
+    // we should only call this if we know for sure that there are no IP addresses
+    // assigned to the interface, etc.
+    private void resetLinkProperties() {
+        mNetlinkTracker.clearLinkProperties();
+        mConfiguration = null;
+        mDhcpResults = null;
+        mTcpBufferSizes = "";
+        mHttpProxy = null;
+
+        mLinkProperties = new LinkProperties();
+        mLinkProperties.setInterfaceName(mInterfaceName);
+    }
+
+    private void recordMetric(final int type) {
+        // We may record error metrics prior to starting.
+        // Map this to IMMEDIATE_FAILURE_DURATION.
+        final long duration = (mStartTimeMillis > 0)
+                ? (SystemClock.elapsedRealtime() - mStartTimeMillis)
+                : IMMEDIATE_FAILURE_DURATION;
+        mMetricsLog.log(mInterfaceName, new IpManagerEvent(type, duration));
+    }
+
+    // For now: use WifiStateMachine's historical notion of provisioned.
+    @VisibleForTesting
+    static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) {
+        // For historical reasons, we should connect even if all we have is
+        // an IPv4 address and nothing else.
+        if (lp.hasIPv4Address() || lp.isProvisioned()) {
+            return true;
+        }
+        if (config == null) {
+            return false;
+        }
+
+        // When an InitialConfiguration is specified, ignore any difference with previous
+        // properties and instead check if properties observed match the desired properties.
+        return config.isProvisionedBy(lp.getLinkAddresses(), lp.getRoutes());
+    }
+
+    // TODO: Investigate folding all this into the existing static function
+    // LinkProperties.compareProvisioning() or some other single function that
+    // takes two LinkProperties objects and returns a ProvisioningChange
+    // object that is a correct and complete assessment of what changed, taking
+    // account of the asymmetries described in the comments in this function.
+    // Then switch to using it everywhere (IpReachabilityMonitor, etc.).
+    private int compareProvisioning(LinkProperties oldLp, LinkProperties newLp) {
+        int delta;
+        InitialConfiguration config = mConfiguration != null ? mConfiguration.mInitialConfig : null;
+        final boolean wasProvisioned = isProvisioned(oldLp, config);
+        final boolean isProvisioned = isProvisioned(newLp, config);
+
+        if (!wasProvisioned && isProvisioned) {
+            delta = PROV_CHANGE_GAINED_PROVISIONING;
+        } else if (wasProvisioned && isProvisioned) {
+            delta = PROV_CHANGE_STILL_PROVISIONED;
+        } else if (!wasProvisioned && !isProvisioned) {
+            delta = PROV_CHANGE_STILL_NOT_PROVISIONED;
+        } else {
+            // (wasProvisioned && !isProvisioned)
+            //
+            // Note that this is true even if we lose a configuration element
+            // (e.g., a default gateway) that would not be required to advance
+            // into provisioned state. This is intended: if we have a default
+            // router and we lose it, that's a sure sign of a problem, but if
+            // we connect to a network with no IPv4 DNS servers, we consider
+            // that to be a network without DNS servers and connect anyway.
+            //
+            // See the comment below.
+            delta = PROV_CHANGE_LOST_PROVISIONING;
+        }
+
+        final boolean lostIPv6 = oldLp.isIPv6Provisioned() && !newLp.isIPv6Provisioned();
+        final boolean lostIPv4Address = oldLp.hasIPv4Address() && !newLp.hasIPv4Address();
+        final boolean lostIPv6Router = oldLp.hasIPv6DefaultRoute() && !newLp.hasIPv6DefaultRoute();
+
+        // If bad wifi avoidance is disabled, then ignore IPv6 loss of
+        // provisioning. Otherwise, when a hotspot that loses Internet
+        // access sends out a 0-lifetime RA to its clients, the clients
+        // will disconnect and then reconnect, avoiding the bad hotspot,
+        // instead of getting stuck on the bad hotspot. http://b/31827713 .
+        //
+        // This is incorrect because if the hotspot then regains Internet
+        // access with a different prefix, TCP connections on the
+        // deprecated addresses will remain stuck.
+        //
+        // Note that we can still be disconnected by IpReachabilityMonitor
+        // if the IPv6 default gateway (but not the IPv6 DNS servers; see
+        // accompanying code in IpReachabilityMonitor) is unreachable.
+        final boolean ignoreIPv6ProvisioningLoss =
+                mConfiguration != null && mConfiguration.mUsingMultinetworkPolicyTracker
+                && mCm.getAvoidBadWifi();
+
+        // Additionally:
+        //
+        // Partial configurations (e.g., only an IPv4 address with no DNS
+        // servers and no default route) are accepted as long as DHCPv4
+        // succeeds. On such a network, isProvisioned() will always return
+        // false, because the configuration is not complete, but we want to
+        // connect anyway. It might be a disconnected network such as a
+        // Chromecast or a wireless printer, for example.
+        //
+        // Because on such a network isProvisioned() will always return false,
+        // delta will never be LOST_PROVISIONING. So check for loss of
+        // provisioning here too.
+        if (lostIPv4Address || (lostIPv6 && !ignoreIPv6ProvisioningLoss)) {
+            delta = PROV_CHANGE_LOST_PROVISIONING;
+        }
+
+        // Additionally:
+        //
+        // If the previous link properties had a global IPv6 address and an
+        // IPv6 default route then also consider the loss of that default route
+        // to be a loss of provisioning. See b/27962810.
+        if (oldLp.hasGlobalIPv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) {
+            delta = PROV_CHANGE_LOST_PROVISIONING;
+        }
+
+        return delta;
+    }
+
+    private void dispatchCallback(int delta, LinkProperties newLp) {
+        switch (delta) {
+            case PROV_CHANGE_GAINED_PROVISIONING:
+                if (DBG) {
+                    Log.d(mTag, "onProvisioningSuccess()");
+                }
+                recordMetric(IpManagerEvent.PROVISIONING_OK);
+                mCallback.onProvisioningSuccess(newLp);
+                break;
+
+            case PROV_CHANGE_LOST_PROVISIONING:
+                if (DBG) {
+                    Log.d(mTag, "onProvisioningFailure()");
+                }
+                recordMetric(IpManagerEvent.PROVISIONING_FAIL);
+                mCallback.onProvisioningFailure(newLp);
+                break;
+
+            default:
+                if (DBG) {
+                    Log.d(mTag, "onLinkPropertiesChange()");
+                }
+                mCallback.onLinkPropertiesChange(newLp);
+                break;
+        }
+    }
+
+    // Updates all IpClient-related state concerned with LinkProperties.
+    // Returns a ProvisioningChange for possibly notifying other interested
+    // parties that are not fronted by IpClient.
+    private int setLinkProperties(LinkProperties newLp) {
+        if (mApfFilter != null) {
+            mApfFilter.setLinkProperties(newLp);
+        }
+        if (mIpReachabilityMonitor != null) {
+            mIpReachabilityMonitor.updateLinkProperties(newLp);
+        }
+
+        int delta = compareProvisioning(mLinkProperties, newLp);
+        mLinkProperties = new LinkProperties(newLp);
+
+        if (delta == PROV_CHANGE_GAINED_PROVISIONING) {
+            // TODO: Add a proper ProvisionedState and cancel the alarm in
+            // its enter() method.
+            mProvisioningTimeoutAlarm.cancel();
+        }
+
+        return delta;
+    }
+
+    private LinkProperties assembleLinkProperties() {
+        // [1] Create a new LinkProperties object to populate.
+        LinkProperties newLp = new LinkProperties();
+        newLp.setInterfaceName(mInterfaceName);
+
+        // [2] Pull in data from netlink:
+        //         - IPv4 addresses
+        //         - IPv6 addresses
+        //         - IPv6 routes
+        //         - IPv6 DNS servers
+        //
+        // N.B.: this is fundamentally race-prone and should be fixed by
+        // changing NetlinkTracker from a hybrid edge/level model to an
+        // edge-only model, or by giving IpClient its own netlink socket(s)
+        // so as to track all required information directly.
+        LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
+        newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
+        for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
+            newLp.addRoute(route);
+        }
+        addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());
+
+        // [3] Add in data from DHCPv4, if available.
+        //
+        // mDhcpResults is never shared with any other owner so we don't have
+        // to worry about concurrent modification.
+        if (mDhcpResults != null) {
+            for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
+                newLp.addRoute(route);
+            }
+            addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
+            newLp.setDomains(mDhcpResults.domains);
+
+            if (mDhcpResults.mtu != 0) {
+                newLp.setMtu(mDhcpResults.mtu);
+            }
+        }
+
+        // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
+        if (!TextUtils.isEmpty(mTcpBufferSizes)) {
+            newLp.setTcpBufferSizes(mTcpBufferSizes);
+        }
+        if (mHttpProxy != null) {
+            newLp.setHttpProxy(mHttpProxy);
+        }
+
+        // [5] Add data from InitialConfiguration
+        if (mConfiguration != null && mConfiguration.mInitialConfig != null) {
+            InitialConfiguration config = mConfiguration.mInitialConfig;
+            // Add InitialConfiguration routes and dns server addresses once all addresses
+            // specified in the InitialConfiguration have been observed with Netlink.
+            if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) {
+                for (IpPrefix prefix : config.directlyConnectedRoutes) {
+                    newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName));
+                }
+            }
+            addAllReachableDnsServers(newLp, config.dnsServers);
+        }
+        final LinkProperties oldLp = mLinkProperties;
+        if (DBG) {
+            Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s",
+                    netlinkLinkProperties, newLp, oldLp));
+        }
+
+        // TODO: also learn via netlink routes specified by an InitialConfiguration and specified
+        // from a static IP v4 config instead of manually patching them in in steps [3] and [5].
+        return newLp;
+    }
+
+    private static void addAllReachableDnsServers(
+            LinkProperties lp, Iterable<InetAddress> dnses) {
+        // TODO: Investigate deleting this reachability check.  We should be
+        // able to pass everything down to netd and let netd do evaluation
+        // and RFC6724-style sorting.
+        for (InetAddress dns : dnses) {
+            if (!dns.isAnyLocalAddress() && lp.isReachable(dns)) {
+                lp.addDnsServer(dns);
+            }
+        }
+    }
+
+    // Returns false if we have lost provisioning, true otherwise.
+    private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
+        final LinkProperties newLp = assembleLinkProperties();
+        if (Objects.equals(newLp, mLinkProperties)) {
+            return true;
+        }
+        final int delta = setLinkProperties(newLp);
+        if (sendCallbacks) {
+            dispatchCallback(delta, newLp);
+        }
+        return (delta != PROV_CHANGE_LOST_PROVISIONING);
+    }
+
+    private void handleIPv4Success(DhcpResults dhcpResults) {
+        mDhcpResults = new DhcpResults(dhcpResults);
+        final LinkProperties newLp = assembleLinkProperties();
+        final int delta = setLinkProperties(newLp);
+
+        if (DBG) {
+            Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
+        }
+        mCallback.onNewDhcpResults(dhcpResults);
+        dispatchCallback(delta, newLp);
+    }
+
+    private void handleIPv4Failure() {
+        // TODO: Investigate deleting this clearIPv4Address() call.
+        //
+        // DhcpClient will send us CMD_CLEAR_LINKADDRESS in all circumstances
+        // that could trigger a call to this function. If we missed handling
+        // that message in StartedState for some reason we would still clear
+        // any addresses upon entry to StoppedState.
+        mInterfaceCtrl.clearIPv4Address();
+        mDhcpResults = null;
+        if (DBG) {
+            Log.d(mTag, "onNewDhcpResults(null)");
+        }
+        mCallback.onNewDhcpResults(null);
+
+        handleProvisioningFailure();
+    }
+
+    private void handleProvisioningFailure() {
+        final LinkProperties newLp = assembleLinkProperties();
+        int delta = setLinkProperties(newLp);
+        // If we've gotten here and we're still not provisioned treat that as
+        // a total loss of provisioning.
+        //
+        // Either (a) static IP configuration failed or (b) DHCPv4 failed AND
+        // there was no usable IPv6 obtained before a non-zero provisioning
+        // timeout expired.
+        //
+        // Regardless: GAME OVER.
+        if (delta == PROV_CHANGE_STILL_NOT_PROVISIONED) {
+            delta = PROV_CHANGE_LOST_PROVISIONING;
+        }
+
+        dispatchCallback(delta, newLp);
+        if (delta == PROV_CHANGE_LOST_PROVISIONING) {
+            transitionTo(mStoppingState);
+        }
+    }
+
+    private void doImmediateProvisioningFailure(int failureType) {
+        logError("onProvisioningFailure(): %s", failureType);
+        recordMetric(failureType);
+        mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties));
+    }
+
+    private boolean startIPv4() {
+        // If we have a StaticIpConfiguration attempt to apply it and
+        // handle the result accordingly.
+        if (mConfiguration.mStaticIpConfig != null) {
+            if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) {
+                handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
+            } else {
+                return false;
+            }
+        } else {
+            // Start DHCPv4.
+            mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams);
+            mDhcpClient.registerForPreDhcpNotification();
+            mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
+        }
+
+        return true;
+    }
+
+    private boolean startIPv6() {
+        return mInterfaceCtrl.setIPv6PrivacyExtensions(true)
+                && mInterfaceCtrl.setIPv6AddrGenModeIfSupported(mConfiguration.mIPv6AddrGenMode)
+                && mInterfaceCtrl.enableIPv6();
+    }
+
+    private boolean applyInitialConfig(InitialConfiguration config) {
+        // TODO: also support specifying a static IPv4 configuration in InitialConfiguration.
+        for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIPv6)) {
+            if (!mInterfaceCtrl.addAddress(addr)) return false;
+        }
+
+        return true;
+    }
+
+    private boolean startIpReachabilityMonitor() {
+        try {
+            // TODO: Fetch these parameters from settings, and install a
+            // settings observer to watch for update and re-program these
+            // parameters (Q: is this level of dynamic updatability really
+            // necessary or does reading from settings at startup suffice?).
+            final int numSolicits = 5;
+            final int interSolicitIntervalMs = 750;
+            setNeighborParameters(mDependencies.getNetd(), mInterfaceName,
+                    numSolicits, interSolicitIntervalMs);
+        } catch (Exception e) {
+            mLog.e("Failed to adjust neighbor parameters", e);
+            // Carry on using the system defaults (currently: 3, 1000);
+        }
+
+        try {
+            mIpReachabilityMonitor = new IpReachabilityMonitor(
+                    mContext,
+                    mInterfaceParams,
+                    getHandler(),
+                    mLog,
+                    new IpReachabilityMonitor.Callback() {
+                        @Override
+                        public void notifyLost(InetAddress ip, String logMsg) {
+                            mCallback.onReachabilityLost(logMsg);
+                        }
+                    },
+                    mConfiguration.mUsingMultinetworkPolicyTracker);
+        } catch (IllegalArgumentException iae) {
+            // Failed to start IpReachabilityMonitor. Log it and call
+            // onProvisioningFailure() immediately.
+            //
+            // See http://b/31038971.
+            logError("IpReachabilityMonitor failure: %s", iae);
+            mIpReachabilityMonitor = null;
+        }
+
+        return (mIpReachabilityMonitor != null);
+    }
+
+    private void stopAllIP() {
+        // We don't need to worry about routes, just addresses, because:
+        //     - disableIpv6() will clear autoconf IPv6 routes as well, and
+        //     - we don't get IPv4 routes from netlink
+        // so we neither react to nor need to wait for changes in either.
+
+        mInterfaceCtrl.disableIPv6();
+        mInterfaceCtrl.clearAllAddresses();
+    }
+
+    class StoppedState extends State {
+        @Override
+        public void enter() {
+            stopAllIP();
+
+            resetLinkProperties();
+            if (mStartTimeMillis > 0) {
+                // Completed a life-cycle; send a final empty LinkProperties
+                // (cleared in resetLinkProperties() above) and record an event.
+                mCallback.onLinkPropertiesChange(new LinkProperties(mLinkProperties));
+                recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
+                mStartTimeMillis = 0;
+            }
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_TERMINATE_AFTER_STOP:
+                    stopStateMachineUpdaters();
+                    quit();
+                    break;
+
+                case CMD_STOP:
+                    break;
+
+                case CMD_START:
+                    mConfiguration = (android.net.shared.ProvisioningConfiguration) msg.obj;
+                    transitionTo(mStartedState);
+                    break;
+
+                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    break;
+
+                case CMD_UPDATE_TCP_BUFFER_SIZES:
+                    mTcpBufferSizes = (String) msg.obj;
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    break;
+
+                case CMD_UPDATE_HTTP_PROXY:
+                    mHttpProxy = (ProxyInfo) msg.obj;
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    break;
+
+                case CMD_SET_MULTICAST_FILTER:
+                    mMulticastFiltering = (boolean) msg.obj;
+                    break;
+
+                case DhcpClient.CMD_ON_QUIT:
+                    // Everything is already stopped.
+                    logError("Unexpected CMD_ON_QUIT (already stopped).");
+                    break;
+
+                default:
+                    return NOT_HANDLED;
+            }
+
+            mMsgStateLogger.handled(this, getCurrentState());
+            return HANDLED;
+        }
+    }
+
+    class StoppingState extends State {
+        @Override
+        public void enter() {
+            if (mDhcpClient == null) {
+                // There's no DHCPv4 for which to wait; proceed to stopped.
+                deferMessage(obtainMessage(CMD_JUMP_STOPPING_TO_STOPPED));
+            }
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_JUMP_STOPPING_TO_STOPPED:
+                    transitionTo(mStoppedState);
+                    break;
+
+                case CMD_STOP:
+                    break;
+
+                case DhcpClient.CMD_CLEAR_LINKADDRESS:
+                    mInterfaceCtrl.clearIPv4Address();
+                    break;
+
+                case DhcpClient.CMD_ON_QUIT:
+                    mDhcpClient = null;
+                    transitionTo(mStoppedState);
+                    break;
+
+                default:
+                    deferMessage(msg);
+            }
+
+            mMsgStateLogger.handled(this, getCurrentState());
+            return HANDLED;
+        }
+    }
+
+    class StartedState extends State {
+        @Override
+        public void enter() {
+            mStartTimeMillis = SystemClock.elapsedRealtime();
+
+            if (mConfiguration.mProvisioningTimeoutMs > 0) {
+                final long alarmTime = SystemClock.elapsedRealtime()
+                        + mConfiguration.mProvisioningTimeoutMs;
+                mProvisioningTimeoutAlarm.schedule(alarmTime);
+            }
+
+            if (readyToProceed()) {
+                deferMessage(obtainMessage(CMD_JUMP_STARTED_TO_RUNNING));
+            } else {
+                // Clear all IPv4 and IPv6 before proceeding to RunningState.
+                // Clean up any leftover state from an abnormal exit from
+                // tethering or during an IpClient restart.
+                stopAllIP();
+            }
+        }
+
+        @Override
+        public void exit() {
+            mProvisioningTimeoutAlarm.cancel();
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_JUMP_STARTED_TO_RUNNING:
+                    transitionTo(mRunningState);
+                    break;
+
+                case CMD_STOP:
+                    transitionTo(mStoppingState);
+                    break;
+
+                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    if (readyToProceed()) {
+                        transitionTo(mRunningState);
+                    }
+                    break;
+
+                case EVENT_PROVISIONING_TIMEOUT:
+                    handleProvisioningFailure();
+                    break;
+
+                default:
+                    // It's safe to process messages out of order because the
+                    // only message that can both
+                    //     a) be received at this time and
+                    //     b) affect provisioning state
+                    // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
+                    deferMessage(msg);
+            }
+
+            mMsgStateLogger.handled(this, getCurrentState());
+            return HANDLED;
+        }
+
+        private boolean readyToProceed() {
+            return (!mLinkProperties.hasIPv4Address() && !mLinkProperties.hasGlobalIPv6Address());
+        }
+    }
+
+    class RunningState extends State {
+        private ConnectivityPacketTracker mPacketTracker;
+        private boolean mDhcpActionInFlight;
+
+        @Override
+        public void enter() {
+            ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();
+            apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
+            apfConfig.multicastFilter = mMulticastFiltering;
+            // Get the Configuration for ApfFilter from Context
+            apfConfig.ieee802_3Filter =
+                    mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
+            apfConfig.ethTypeBlackList =
+                    mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
+            mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback);
+            // TODO: investigate the effects of any multicast filtering racing/interfering with the
+            // rest of this IP configuration startup.
+            if (mApfFilter == null) {
+                mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+            }
+
+            mPacketTracker = createPacketTracker();
+            if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
+
+            if (mConfiguration.mEnableIPv6 && !startIPv6()) {
+                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
+                enqueueJumpToStoppingState();
+                return;
+            }
+
+            if (mConfiguration.mEnableIPv4 && !startIPv4()) {
+                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
+                enqueueJumpToStoppingState();
+                return;
+            }
+
+            final InitialConfiguration config = mConfiguration.mInitialConfig;
+            if ((config != null) && !applyInitialConfig(config)) {
+                // TODO introduce a new IpManagerEvent constant to distinguish this error case.
+                doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
+                enqueueJumpToStoppingState();
+                return;
+            }
+
+            if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
+                doImmediateProvisioningFailure(
+                        IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
+                enqueueJumpToStoppingState();
+                return;
+            }
+        }
+
+        @Override
+        public void exit() {
+            stopDhcpAction();
+
+            if (mIpReachabilityMonitor != null) {
+                mIpReachabilityMonitor.stop();
+                mIpReachabilityMonitor = null;
+            }
+
+            if (mDhcpClient != null) {
+                mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
+                mDhcpClient.doQuit();
+            }
+
+            if (mPacketTracker != null) {
+                mPacketTracker.stop();
+                mPacketTracker = null;
+            }
+
+            if (mApfFilter != null) {
+                mApfFilter.shutdown();
+                mApfFilter = null;
+            }
+
+            resetLinkProperties();
+        }
+
+        private void enqueueJumpToStoppingState() {
+            deferMessage(obtainMessage(CMD_JUMP_RUNNING_TO_STOPPING));
+        }
+
+        private ConnectivityPacketTracker createPacketTracker() {
+            try {
+                return new ConnectivityPacketTracker(
+                        getHandler(), mInterfaceParams, mConnectivityPacketLog);
+            } catch (IllegalArgumentException e) {
+                return null;
+            }
+        }
+
+        private void ensureDhcpAction() {
+            if (!mDhcpActionInFlight) {
+                mCallback.onPreDhcpAction();
+                mDhcpActionInFlight = true;
+                final long alarmTime = SystemClock.elapsedRealtime()
+                        + mConfiguration.mRequestedPreDhcpActionMs;
+                mDhcpActionTimeoutAlarm.schedule(alarmTime);
+            }
+        }
+
+        private void stopDhcpAction() {
+            mDhcpActionTimeoutAlarm.cancel();
+            if (mDhcpActionInFlight) {
+                mCallback.onPostDhcpAction();
+                mDhcpActionInFlight = false;
+            }
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_JUMP_RUNNING_TO_STOPPING:
+                case CMD_STOP:
+                    transitionTo(mStoppingState);
+                    break;
+
+                case CMD_START:
+                    logError("ALERT: START received in StartedState. Please fix caller.");
+                    break;
+
+                case CMD_CONFIRM:
+                    // TODO: Possibly introduce a second type of confirmation
+                    // that both probes (a) on-link neighbors and (b) does
+                    // a DHCPv4 RENEW.  We used to do this on Wi-Fi framework
+                    // roams.
+                    if (mIpReachabilityMonitor != null) {
+                        mIpReachabilityMonitor.probeAll();
+                    }
+                    break;
+
+                case EVENT_PRE_DHCP_ACTION_COMPLETE:
+                    // It's possible to reach here if, for example, someone
+                    // calls completedPreDhcpAction() after provisioning with
+                    // a static IP configuration.
+                    if (mDhcpClient != null) {
+                        mDhcpClient.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
+                    }
+                    break;
+
+                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+                    if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) {
+                        transitionTo(mStoppingState);
+                    }
+                    break;
+
+                case CMD_UPDATE_TCP_BUFFER_SIZES:
+                    mTcpBufferSizes = (String) msg.obj;
+                    // This cannot possibly change provisioning state.
+                    handleLinkPropertiesUpdate(SEND_CALLBACKS);
+                    break;
+
+                case CMD_UPDATE_HTTP_PROXY:
+                    mHttpProxy = (ProxyInfo) msg.obj;
+                    // This cannot possibly change provisioning state.
+                    handleLinkPropertiesUpdate(SEND_CALLBACKS);
+                    break;
+
+                case CMD_SET_MULTICAST_FILTER: {
+                    mMulticastFiltering = (boolean) msg.obj;
+                    if (mApfFilter != null) {
+                        mApfFilter.setMulticastFilter(mMulticastFiltering);
+                    } else {
+                        mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+                    }
+                    break;
+                }
+
+                case EVENT_READ_PACKET_FILTER_COMPLETE: {
+                    if (mApfFilter != null) {
+                        mApfFilter.setDataSnapshot((byte[]) msg.obj);
+                    }
+                    mApfDataSnapshotComplete.open();
+                    break;
+                }
+
+                case EVENT_DHCPACTION_TIMEOUT:
+                    stopDhcpAction();
+                    break;
+
+                case DhcpClient.CMD_PRE_DHCP_ACTION:
+                    if (mConfiguration.mRequestedPreDhcpActionMs > 0) {
+                        ensureDhcpAction();
+                    } else {
+                        sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
+                    }
+                    break;
+
+                case DhcpClient.CMD_CLEAR_LINKADDRESS:
+                    mInterfaceCtrl.clearIPv4Address();
+                    break;
+
+                case DhcpClient.CMD_CONFIGURE_LINKADDRESS: {
+                    final LinkAddress ipAddress = (LinkAddress) msg.obj;
+                    if (mInterfaceCtrl.setIPv4Address(ipAddress)) {
+                        mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED);
+                    } else {
+                        logError("Failed to set IPv4 address.");
+                        dispatchCallback(PROV_CHANGE_LOST_PROVISIONING,
+                                new LinkProperties(mLinkProperties));
+                        transitionTo(mStoppingState);
+                    }
+                    break;
+                }
+
+                // This message is only received when:
+                //
+                //     a) initial address acquisition succeeds,
+                //     b) renew succeeds or is NAK'd,
+                //     c) rebind succeeds or is NAK'd, or
+                //     c) the lease expires,
+                //
+                // but never when initial address acquisition fails. The latter
+                // condition is now governed by the provisioning timeout.
+                case DhcpClient.CMD_POST_DHCP_ACTION:
+                    stopDhcpAction();
+
+                    switch (msg.arg1) {
+                        case DhcpClient.DHCP_SUCCESS:
+                            handleIPv4Success((DhcpResults) msg.obj);
+                            break;
+                        case DhcpClient.DHCP_FAILURE:
+                            handleIPv4Failure();
+                            break;
+                        default:
+                            logError("Unknown CMD_POST_DHCP_ACTION status: %s", msg.arg1);
+                    }
+                    break;
+
+                case DhcpClient.CMD_ON_QUIT:
+                    // DHCPv4 quit early for some reason.
+                    logError("Unexpected CMD_ON_QUIT.");
+                    mDhcpClient = null;
+                    break;
+
+                default:
+                    return NOT_HANDLED;
+            }
+
+            mMsgStateLogger.handled(this, getCurrentState());
+            return HANDLED;
+        }
+    }
+
+    private static class MessageHandlingLogger {
+        public String processedInState;
+        public String receivedInState;
+
+        public void reset() {
+            processedInState = null;
+            receivedInState = null;
+        }
+
+        public void handled(State processedIn, IState receivedIn) {
+            processedInState = processedIn.getClass().getSimpleName();
+            receivedInState = receivedIn.getName();
+        }
+
+        public String toString() {
+            return String.format("rcvd_in=%s, proc_in=%s",
+                                 receivedInState, processedInState);
+        }
+    }
+
+    private static void setNeighborParameters(
+            INetd netd, String ifName, int numSolicits, int interSolicitIntervalMs)
+            throws RemoteException, IllegalArgumentException {
+        Preconditions.checkNotNull(netd);
+        Preconditions.checkArgument(!TextUtils.isEmpty(ifName));
+        Preconditions.checkArgument(numSolicits > 0);
+        Preconditions.checkArgument(interSolicitIntervalMs > 0);
+
+        for (int family : new Integer[]{INetd.IPV4, INetd.IPV6}) {
+            netd.setProcSysNet(family, INetd.NEIGH, ifName, "retrans_time_ms",
+                    Integer.toString(interSolicitIntervalMs));
+            netd.setProcSysNet(family, INetd.NEIGH, ifName, "ucast_solicit",
+                    Integer.toString(numSolicits));
+        }
+    }
+
+    // TODO: extract out into CollectionUtils.
+    static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
+        for (T t : coll) {
+            if (fn.test(t)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
+        return !any(coll, not(fn));
+    }
+
+    static <T> Predicate<T> not(Predicate<T> fn) {
+        return (t) -> !fn.test(t);
+    }
+
+    static <T> String join(String delimiter, Collection<T> coll) {
+        return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter));
+    }
+
+    static <T> T find(Iterable<T> coll, Predicate<T> fn) {
+        for (T t: coll) {
+            if (fn.test(t)) {
+                return t;
+            }
+        }
+        return null;
+    }
+
+    static <T> List<T> findAll(Collection<T> coll, Predicate<T> fn) {
+        return coll.stream().filter(fn).collect(Collectors.toList());
+    }
+}
diff --git a/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java b/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java
new file mode 100644
index 0000000..eb993a4
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH;
+import static android.net.netlink.NetlinkConstants.hexify;
+import static android.net.netlink.NetlinkConstants.stringForNlMsgType;
+import static android.net.util.SocketUtils.makeNetlinkSocketAddress;
+
+import android.net.MacAddress;
+import android.net.netlink.NetlinkErrorMessage;
+import android.net.netlink.NetlinkMessage;
+import android.net.netlink.NetlinkSocket;
+import android.net.netlink.RtNetlinkNeighborMessage;
+import android.net.netlink.StructNdMsg;
+import android.net.util.PacketReader;
+import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+
+import com.android.internal.util.BitUtils;
+
+import libcore.io.IoUtils;
+
+import java.io.FileDescriptor;
+import java.net.InetAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.StringJoiner;
+
+
+/**
+ * IpNeighborMonitor.
+ *
+ * Monitors the kernel rtnetlink neighbor notifications and presents to callers
+ * NeighborEvents describing each event. Callers can provide a consumer instance
+ * to both filter (e.g. by interface index and IP address) and handle the
+ * generated NeighborEvents.
+ *
+ * @hide
+ */
+public class IpNeighborMonitor extends PacketReader {
+    private static final String TAG = IpNeighborMonitor.class.getSimpleName();
+    private static final boolean DBG = false;
+    private static final boolean VDBG = false;
+
+    /**
+     * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
+     * for the given IP address on the specified interface index.
+     *
+     * @return 0 if the request was successfully passed to the kernel; otherwise return
+     *         a non-zero error code.
+     */
+    public static int startKernelNeighborProbe(int ifIndex, InetAddress ip) {
+        final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex;
+        if (DBG) { Log.d(TAG, msgSnippet); }
+
+        final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
+                1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
+
+        try {
+            NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_ROUTE, msg);
+        } catch (ErrnoException e) {
+            Log.e(TAG, "Error " + msgSnippet + ": " + e);
+            return -e.errno;
+        }
+
+        return 0;
+    }
+
+    public static class NeighborEvent {
+        final long elapsedMs;
+        final short msgType;
+        final int ifindex;
+        final InetAddress ip;
+        final short nudState;
+        final MacAddress macAddr;
+
+        public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip,
+                short nudState, MacAddress macAddr) {
+            this.elapsedMs = elapsedMs;
+            this.msgType = msgType;
+            this.ifindex = ifindex;
+            this.ip = ip;
+            this.nudState = nudState;
+            this.macAddr = macAddr;
+        }
+
+        boolean isConnected() {
+            return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState);
+        }
+
+        boolean isValid() {
+            return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState);
+        }
+
+        @Override
+        public String toString() {
+            final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}");
+            return j.add("@" + elapsedMs)
+                    .add(stringForNlMsgType(msgType))
+                    .add("if=" + ifindex)
+                    .add(ip.getHostAddress())
+                    .add(StructNdMsg.stringForNudState(nudState))
+                    .add("[" + macAddr + "]")
+                    .toString();
+        }
+    }
+
+    public interface NeighborEventConsumer {
+        // Every neighbor event received on the netlink socket is passed in
+        // here. Subclasses should filter for events of interest.
+        public void accept(NeighborEvent event);
+    }
+
+    private final SharedLog mLog;
+    private final NeighborEventConsumer mConsumer;
+
+    public IpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb) {
+        super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE);
+        mLog = log.forSubComponent(TAG);
+        mConsumer = (cb != null) ? cb : (event) -> { /* discard */ };
+    }
+
+    @Override
+    protected FileDescriptor createFd() {
+        FileDescriptor fd = null;
+
+        try {
+            fd = NetlinkSocket.forProto(OsConstants.NETLINK_ROUTE);
+            Os.bind(fd, makeNetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH));
+            NetlinkSocket.connectToKernel(fd);
+
+            if (VDBG) {
+                final SocketAddress nlAddr = Os.getsockname(fd);
+                Log.d(TAG, "bound to sockaddr_nl{" + nlAddr.toString() + "}");
+            }
+        } catch (ErrnoException|SocketException e) {
+            logError("Failed to create rtnetlink socket", e);
+            IoUtils.closeQuietly(fd);
+            return null;
+        }
+
+        return fd;
+    }
+
+    @Override
+    protected void handlePacket(byte[] recvbuf, int length) {
+        final long whenMs = SystemClock.elapsedRealtime();
+
+        final ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf, 0, length);
+        byteBuffer.order(ByteOrder.nativeOrder());
+
+        parseNetlinkMessageBuffer(byteBuffer, whenMs);
+    }
+
+    private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) {
+        while (byteBuffer.remaining() > 0) {
+            final int position = byteBuffer.position();
+            final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
+            if (nlMsg == null || nlMsg.getHeader() == null) {
+                byteBuffer.position(position);
+                mLog.e("unparsable netlink msg: " + hexify(byteBuffer));
+                break;
+            }
+
+            final int srcPortId = nlMsg.getHeader().nlmsg_pid;
+            if (srcPortId !=  0) {
+                mLog.e("non-kernel source portId: " + BitUtils.uint32(srcPortId));
+                break;
+            }
+
+            if (nlMsg instanceof NetlinkErrorMessage) {
+                mLog.e("netlink error: " + nlMsg);
+                continue;
+            } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) {
+                mLog.i("non-rtnetlink neighbor msg: " + nlMsg);
+                continue;
+            }
+
+            evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);
+        }
+    }
+
+    private void evaluateRtNetlinkNeighborMessage(
+            RtNetlinkNeighborMessage neighMsg, long whenMs) {
+        final short msgType = neighMsg.getHeader().nlmsg_type;
+        final StructNdMsg ndMsg = neighMsg.getNdHeader();
+        if (ndMsg == null) {
+            mLog.e("RtNetlinkNeighborMessage without ND message header!");
+            return;
+        }
+
+        final int ifindex = ndMsg.ndm_ifindex;
+        final InetAddress destination = neighMsg.getDestination();
+        final short nudState =
+                (msgType == RTM_DELNEIGH)
+                ? StructNdMsg.NUD_NONE
+                : ndMsg.ndm_state;
+
+        final NeighborEvent event = new NeighborEvent(
+                whenMs, msgType, ifindex, destination, nudState,
+                getMacAddress(neighMsg.getLinkLayerAddress()));
+
+        if (VDBG) {
+            Log.d(TAG, neighMsg.toString());
+        }
+        if (DBG) {
+            Log.d(TAG, event.toString());
+        }
+
+        mConsumer.accept(event);
+    }
+
+    private static MacAddress getMacAddress(byte[] linkLayerAddress) {
+        if (linkLayerAddress != null) {
+            try {
+                return MacAddress.fromBytes(linkLayerAddress);
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Failed to parse link-layer address: " + hexify(linkLayerAddress));
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java b/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
new file mode 100644
index 0000000..761db68
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static android.net.metrics.IpReachabilityEvent.NUD_FAILED;
+import static android.net.metrics.IpReachabilityEvent.NUD_FAILED_ORGANIC;
+import static android.net.metrics.IpReachabilityEvent.PROVISIONING_LOST;
+import static android.net.metrics.IpReachabilityEvent.PROVISIONING_LOST_ORGANIC;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.RouteInfo;
+import android.net.ip.IpNeighborMonitor.NeighborEvent;
+import android.net.metrics.IpConnectivityLog;
+import android.net.metrics.IpReachabilityEvent;
+import android.net.netlink.StructNdMsg;
+import android.net.util.InterfaceParams;
+import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.DumpUtils.Dump;
+
+import java.io.PrintWriter;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * IpReachabilityMonitor.
+ *
+ * Monitors on-link IP reachability and notifies callers whenever any on-link
+ * addresses of interest appear to have become unresponsive.
+ *
+ * This code does not concern itself with "why" a neighbour might have become
+ * unreachable. Instead, it primarily reacts to the kernel's notion of IP
+ * reachability for each of the neighbours we know to be critically important
+ * to normal network connectivity. As such, it is often "just the messenger":
+ * the neighbours about which it warns are already deemed by the kernel to have
+ * become unreachable.
+ *
+ *
+ * How it works:
+ *
+ *   1. The "on-link neighbours of interest" found in a given LinkProperties
+ *      instance are added to a "watch list" via #updateLinkProperties().
+ *      This usually means all default gateways and any on-link DNS servers.
+ *
+ *   2. We listen continuously for netlink neighbour messages (RTM_NEWNEIGH,
+ *      RTM_DELNEIGH), watching only for neighbours in the watch list.
+ *
+ *        - A neighbour going into NUD_REACHABLE, NUD_STALE, NUD_DELAY, and
+ *          even NUD_PROBE is perfectly normal; we merely record the new state.
+ *
+ *        - A neighbour's entry may be deleted (RTM_DELNEIGH), for example due
+ *          to garbage collection.  This is not necessarily of immediate
+ *          concern; we record the neighbour as moving to NUD_NONE.
+ *
+ *        - A neighbour transitioning to NUD_FAILED (for any reason) is
+ *          critically important and is handled as described below in #4.
+ *
+ *   3. All on-link neighbours in the watch list can be forcibly "probed" by
+ *      calling #probeAll(). This should be called whenever it is important to
+ *      verify that critical neighbours on the link are still reachable, e.g.
+ *      when roaming between BSSIDs.
+ *
+ *        - The kernel will send unicast ARP requests for IPv4 neighbours and
+ *          unicast NS packets for IPv6 neighbours.  The expected replies will
+ *          likely be unicast.
+ *
+ *        - The forced probing is done holding a wakelock. The kernel may,
+ *          however, initiate probing of a neighbor on its own, i.e. whenever
+ *          a neighbour has expired from NUD_DELAY.
+ *
+ *        - The kernel sends:
+ *
+ *              /proc/sys/net/ipv{4,6}/neigh/<ifname>/ucast_solicit
+ *
+ *          number of probes (usually 3) every:
+ *
+ *              /proc/sys/net/ipv{4,6}/neigh/<ifname>/retrans_time_ms
+ *
+ *          number of milliseconds (usually 1000ms). This normally results in
+ *          3 unicast packets, 1 per second.
+ *
+ *        - If no response is received to any of the probe packets, the kernel
+ *          marks the neighbour as being in state NUD_FAILED, and the listening
+ *          process in #2 will learn of it.
+ *
+ *   4. We call the supplied Callback#notifyLost() function if the loss of a
+ *      neighbour in NUD_FAILED would cause IPv4 or IPv6 configuration to
+ *      become incomplete (a loss of provisioning).
+ *
+ *        - For example, losing all our IPv4 on-link DNS servers (or losing
+ *          our only IPv6 default gateway) constitutes a loss of IPv4 (IPv6)
+ *          provisioning; Callback#notifyLost() would be called.
+ *
+ *        - Since it can be non-trivial to reacquire certain IP provisioning
+ *          state it may be best for the link to disconnect completely and
+ *          reconnect afresh.
+ *
+ * Accessing an instance of this class from multiple threads is NOT safe.
+ *
+ * @hide
+ */
+public class IpReachabilityMonitor {
+    private static final String TAG = "IpReachabilityMonitor";
+    private static final boolean DBG = false;
+    private static final boolean VDBG = false;
+
+    public interface Callback {
+        // This callback function must execute as quickly as possible as it is
+        // run on the same thread that listens to kernel neighbor updates.
+        //
+        // TODO: refactor to something like notifyProvisioningLost(String msg).
+        public void notifyLost(InetAddress ip, String logMsg);
+    }
+
+    /**
+     * Encapsulates IpReachabilityMonitor depencencies on systems that hinder unit testing.
+     * TODO: consider also wrapping MultinetworkPolicyTracker in this interface.
+     */
+    interface Dependencies {
+        void acquireWakeLock(long durationMs);
+
+        static Dependencies makeDefault(Context context, String iface) {
+            final String lockName = TAG + "." + iface;
+            final PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+            final WakeLock lock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, lockName);
+
+            return new Dependencies() {
+                public void acquireWakeLock(long durationMs) {
+                    lock.acquire(durationMs);
+                }
+            };
+        }
+    }
+
+    private final InterfaceParams mInterfaceParams;
+    private final IpNeighborMonitor mIpNeighborMonitor;
+    private final SharedLog mLog;
+    private final Callback mCallback;
+    private final Dependencies mDependencies;
+    private final boolean mUsingMultinetworkPolicyTracker;
+    private final ConnectivityManager mCm;
+    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
+    private LinkProperties mLinkProperties = new LinkProperties();
+    private Map<InetAddress, NeighborEvent> mNeighborWatchList = new HashMap<>();
+    // Time in milliseconds of the last forced probe request.
+    private volatile long mLastProbeTimeMs;
+
+    public IpReachabilityMonitor(
+            Context context, InterfaceParams ifParams, Handler h, SharedLog log, Callback callback,
+            boolean usingMultinetworkPolicyTracker) {
+        this(context, ifParams, h, log, callback, usingMultinetworkPolicyTracker,
+                Dependencies.makeDefault(context, ifParams.name));
+    }
+
+    @VisibleForTesting
+    IpReachabilityMonitor(Context context, InterfaceParams ifParams, Handler h, SharedLog log,
+            Callback callback, boolean usingMultinetworkPolicyTracker, Dependencies dependencies) {
+        if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams");
+
+        mInterfaceParams = ifParams;
+        mLog = log.forSubComponent(TAG);
+        mCallback = callback;
+        mUsingMultinetworkPolicyTracker = usingMultinetworkPolicyTracker;
+        mCm = context.getSystemService(ConnectivityManager.class);
+        mDependencies = dependencies;
+
+        mIpNeighborMonitor = new IpNeighborMonitor(h, mLog,
+                (NeighborEvent event) -> {
+                    if (mInterfaceParams.index != event.ifindex) return;
+                    if (!mNeighborWatchList.containsKey(event.ip)) return;
+
+                    final NeighborEvent prev = mNeighborWatchList.put(event.ip, event);
+
+                    // TODO: Consider what to do with other states that are not within
+                    // NeighborEvent#isValid() (i.e. NUD_NONE, NUD_INCOMPLETE).
+                    if (event.nudState == StructNdMsg.NUD_FAILED) {
+                        mLog.w("ALERT neighbor went from: " + prev + " to: " + event);
+                        handleNeighborLost(event);
+                    }
+                });
+        mIpNeighborMonitor.start();
+    }
+
+    public void stop() {
+        mIpNeighborMonitor.stop();
+        clearLinkProperties();
+    }
+
+    public void dump(PrintWriter pw) {
+        DumpUtils.dumpAsync(
+                mIpNeighborMonitor.getHandler(),
+                new Dump() {
+                    @Override
+                    public void dump(PrintWriter pw, String prefix) {
+                        pw.println(describeWatchList("\n"));
+                    }
+                },
+                pw, "", 1000);
+    }
+
+    private String describeWatchList() { return describeWatchList(" "); }
+
+    private String describeWatchList(String sep) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("iface{" + mInterfaceParams + "}," + sep);
+        sb.append("ntable=[" + sep);
+        String delimiter = "";
+        for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) {
+            sb.append(delimiter).append(entry.getKey().getHostAddress() + "/" + entry.getValue());
+            delimiter = "," + sep;
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    private static boolean isOnLink(List<RouteInfo> routes, InetAddress ip) {
+        for (RouteInfo route : routes) {
+            if (!route.hasGateway() && route.matches(ip)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void updateLinkProperties(LinkProperties lp) {
+        if (!mInterfaceParams.name.equals(lp.getInterfaceName())) {
+            // TODO: figure out whether / how to cope with interface changes.
+            Log.wtf(TAG, "requested LinkProperties interface '" + lp.getInterfaceName() +
+                    "' does not match: " + mInterfaceParams.name);
+            return;
+        }
+
+        mLinkProperties = new LinkProperties(lp);
+        Map<InetAddress, NeighborEvent> newNeighborWatchList = new HashMap<>();
+
+        final List<RouteInfo> routes = mLinkProperties.getRoutes();
+        for (RouteInfo route : routes) {
+            if (route.hasGateway()) {
+                InetAddress gw = route.getGateway();
+                if (isOnLink(routes, gw)) {
+                    newNeighborWatchList.put(gw, mNeighborWatchList.getOrDefault(gw, null));
+                }
+            }
+        }
+
+        for (InetAddress dns : lp.getDnsServers()) {
+            if (isOnLink(routes, dns)) {
+                newNeighborWatchList.put(dns, mNeighborWatchList.getOrDefault(dns, null));
+            }
+        }
+
+        mNeighborWatchList = newNeighborWatchList;
+        if (DBG) { Log.d(TAG, "watch: " + describeWatchList()); }
+    }
+
+    public void clearLinkProperties() {
+        mLinkProperties.clear();
+        mNeighborWatchList.clear();
+        if (DBG) { Log.d(TAG, "clear: " + describeWatchList()); }
+    }
+
+    private void handleNeighborLost(NeighborEvent event) {
+        final LinkProperties whatIfLp = new LinkProperties(mLinkProperties);
+
+        InetAddress ip = null;
+        for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) {
+            // TODO: Consider using NeighborEvent#isValid() here; it's more
+            // strict but may interact badly if other entries are somehow in
+            // NUD_INCOMPLETE (say, during network attach).
+            if (entry.getValue().nudState != StructNdMsg.NUD_FAILED) continue;
+
+            ip = entry.getKey();
+            for (RouteInfo route : mLinkProperties.getRoutes()) {
+                if (ip.equals(route.getGateway())) {
+                    whatIfLp.removeRoute(route);
+                }
+            }
+
+            if (avoidingBadLinks() || !(ip instanceof Inet6Address)) {
+                // We should do this unconditionally, but alas we cannot: b/31827713.
+                whatIfLp.removeDnsServer(ip);
+            }
+        }
+
+        final boolean lostProvisioning =
+                (mLinkProperties.isIPv4Provisioned() && !whatIfLp.isIPv4Provisioned())
+                || (mLinkProperties.isIPv6Provisioned() && !whatIfLp.isIPv6Provisioned());
+
+        if (lostProvisioning) {
+            final String logMsg = "FAILURE: LOST_PROVISIONING, " + event;
+            Log.w(TAG, logMsg);
+            if (mCallback != null) {
+                // TODO: remove |ip| when the callback signature no longer has
+                // an InetAddress argument.
+                mCallback.notifyLost(ip, logMsg);
+            }
+        }
+        logNudFailed(lostProvisioning);
+    }
+
+    private boolean avoidingBadLinks() {
+        return !mUsingMultinetworkPolicyTracker || mCm.getAvoidBadWifi();
+    }
+
+    public void probeAll() {
+        final List<InetAddress> ipProbeList = new ArrayList<>(mNeighborWatchList.keySet());
+
+        if (!ipProbeList.isEmpty()) {
+            // Keep the CPU awake long enough to allow all ARP/ND
+            // probes a reasonable chance at success. See b/23197666.
+            //
+            // The wakelock we use is (by default) refcounted, and this version
+            // of acquire(timeout) queues a release message to keep acquisitions
+            // and releases balanced.
+            mDependencies.acquireWakeLock(getProbeWakeLockDuration());
+        }
+
+        for (InetAddress ip : ipProbeList) {
+            final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceParams.index, ip);
+            mLog.log(String.format("put neighbor %s into NUD_PROBE state (rval=%d)",
+                     ip.getHostAddress(), rval));
+            logEvent(IpReachabilityEvent.PROBE, rval);
+        }
+        mLastProbeTimeMs = SystemClock.elapsedRealtime();
+    }
+
+    private static long getProbeWakeLockDuration() {
+        // Ideally, this would be computed by examining the values of:
+        //
+        //     /proc/sys/net/ipv[46]/neigh/<ifname>/ucast_solicit
+        //
+        // and:
+        //
+        //     /proc/sys/net/ipv[46]/neigh/<ifname>/retrans_time_ms
+        //
+        // For now, just make some assumptions.
+        final long numUnicastProbes = 3;
+        final long retransTimeMs = 1000;
+        final long gracePeriodMs = 500;
+        return (numUnicastProbes * retransTimeMs) + gracePeriodMs;
+    }
+
+    private void logEvent(int probeType, int errorCode) {
+        int eventType = probeType | (errorCode & 0xff);
+        mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
+    }
+
+    private void logNudFailed(boolean lostProvisioning) {
+        long duration = SystemClock.elapsedRealtime() - mLastProbeTimeMs;
+        boolean isFromProbe = (duration < getProbeWakeLockDuration());
+        int eventType = nudFailureEventType(isFromProbe, lostProvisioning);
+        mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
+    }
+
+    /**
+     * Returns the NUD failure event type code corresponding to the given conditions.
+     */
+    private static int nudFailureEventType(boolean isFromProbe, boolean isProvisioningLost) {
+        if (isFromProbe) {
+            return isProvisioningLost ? PROVISIONING_LOST : NUD_FAILED;
+        } else {
+            return isProvisioningLost ? PROVISIONING_LOST_ORGANIC : NUD_FAILED_ORGANIC;
+        }
+    }
+}
diff --git a/packages/NetworkStack/src/android/net/util/ConnectivityPacketSummary.java b/packages/NetworkStack/src/android/net/util/ConnectivityPacketSummary.java
new file mode 100644
index 0000000..08c3f60
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/util/ConnectivityPacketSummary.java
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.IPPROTO_UDP;
+
+import static com.android.server.util.NetworkStackConstants.ARP_HWTYPE_ETHER;
+import static com.android.server.util.NetworkStackConstants.ARP_PAYLOAD_LEN;
+import static com.android.server.util.NetworkStackConstants.ARP_REPLY;
+import static com.android.server.util.NetworkStackConstants.ARP_REQUEST;
+import static com.android.server.util.NetworkStackConstants.DHCP4_CLIENT_PORT;
+import static com.android.server.util.NetworkStackConstants.ETHER_ADDR_LEN;
+import static com.android.server.util.NetworkStackConstants.ETHER_DST_ADDR_OFFSET;
+import static com.android.server.util.NetworkStackConstants.ETHER_HEADER_LEN;
+import static com.android.server.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET;
+import static com.android.server.util.NetworkStackConstants.ETHER_TYPE_ARP;
+import static com.android.server.util.NetworkStackConstants.ETHER_TYPE_IPV4;
+import static com.android.server.util.NetworkStackConstants.ETHER_TYPE_IPV6;
+import static com.android.server.util.NetworkStackConstants.ETHER_TYPE_OFFSET;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_HEADER_MIN_LEN;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ND_OPTION_MIN_LENGTH;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ND_OPTION_MTU;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_LEN;
+import static com.android.server.util.NetworkStackConstants.IPV4_DST_ADDR_OFFSET;
+import static com.android.server.util.NetworkStackConstants.IPV4_FLAGS_OFFSET;
+import static com.android.server.util.NetworkStackConstants.IPV4_FRAGMENT_MASK;
+import static com.android.server.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN;
+import static com.android.server.util.NetworkStackConstants.IPV4_IHL_MASK;
+import static com.android.server.util.NetworkStackConstants.IPV4_PROTOCOL_OFFSET;
+import static com.android.server.util.NetworkStackConstants.IPV4_SRC_ADDR_OFFSET;
+import static com.android.server.util.NetworkStackConstants.IPV6_ADDR_LEN;
+import static com.android.server.util.NetworkStackConstants.IPV6_HEADER_LEN;
+import static com.android.server.util.NetworkStackConstants.IPV6_PROTOCOL_OFFSET;
+import static com.android.server.util.NetworkStackConstants.IPV6_SRC_ADDR_OFFSET;
+import static com.android.server.util.NetworkStackConstants.UDP_HEADER_LEN;
+
+import android.net.MacAddress;
+import android.net.dhcp.DhcpPacket;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.StringJoiner;
+
+
+/**
+ * Critical connectivity packet summarizing class.
+ *
+ * Outputs short descriptions of ARP, DHCPv4, and IPv6 RS/RA/NS/NA packets.
+ *
+ * @hide
+ */
+public class ConnectivityPacketSummary {
+    private static final String TAG = ConnectivityPacketSummary.class.getSimpleName();
+
+    private final byte[] mHwAddr;
+    private final byte[] mBytes;
+    private final int mLength;
+    private final ByteBuffer mPacket;
+    private final String mSummary;
+
+    public static String summarize(MacAddress hwaddr, byte[] buffer) {
+        return summarize(hwaddr, buffer, buffer.length);
+    }
+
+    // Methods called herein perform some but by no means all error checking.
+    // They may throw runtime exceptions on malformed packets.
+    public static String summarize(MacAddress macAddr, byte[] buffer, int length) {
+        if ((macAddr == null) || (buffer == null)) return null;
+        length = Math.min(length, buffer.length);
+        return (new ConnectivityPacketSummary(macAddr, buffer, length)).toString();
+    }
+
+    private ConnectivityPacketSummary(MacAddress macAddr, byte[] buffer, int length) {
+        mHwAddr = macAddr.toByteArray();
+        mBytes = buffer;
+        mLength = Math.min(length, mBytes.length);
+        mPacket = ByteBuffer.wrap(mBytes, 0, mLength);
+        mPacket.order(ByteOrder.BIG_ENDIAN);
+
+        final StringJoiner sj = new StringJoiner(" ");
+        // TODO: support other link-layers, or even no link-layer header.
+        parseEther(sj);
+        mSummary = sj.toString();
+    }
+
+    public String toString() {
+        return mSummary;
+    }
+
+    private void parseEther(StringJoiner sj) {
+        if (mPacket.remaining() < ETHER_HEADER_LEN) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        mPacket.position(ETHER_SRC_ADDR_OFFSET);
+        final ByteBuffer srcMac = (ByteBuffer) mPacket.slice().limit(ETHER_ADDR_LEN);
+        sj.add(ByteBuffer.wrap(mHwAddr).equals(srcMac) ? "TX" : "RX");
+        sj.add(getMacAddressString(srcMac));
+
+        mPacket.position(ETHER_DST_ADDR_OFFSET);
+        final ByteBuffer dstMac = (ByteBuffer) mPacket.slice().limit(ETHER_ADDR_LEN);
+        sj.add(">").add(getMacAddressString(dstMac));
+
+        mPacket.position(ETHER_TYPE_OFFSET);
+        final int etherType = asUint(mPacket.getShort());
+        switch (etherType) {
+            case ETHER_TYPE_ARP:
+                sj.add("arp");
+                parseARP(sj);
+                break;
+            case ETHER_TYPE_IPV4:
+                sj.add("ipv4");
+                parseIPv4(sj);
+                break;
+            case ETHER_TYPE_IPV6:
+                sj.add("ipv6");
+                parseIPv6(sj);
+                break;
+            default:
+                // Unknown ether type.
+                sj.add("ethtype").add(asString(etherType));
+                break;
+        }
+    }
+
+    private void parseARP(StringJoiner sj) {
+        if (mPacket.remaining() < ARP_PAYLOAD_LEN) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        if (asUint(mPacket.getShort()) != ARP_HWTYPE_ETHER ||
+            asUint(mPacket.getShort()) != ETHER_TYPE_IPV4 ||
+            asUint(mPacket.get()) != ETHER_ADDR_LEN ||
+            asUint(mPacket.get()) != IPV4_ADDR_LEN) {
+            sj.add("unexpected header");
+            return;
+        }
+
+        final int opCode = asUint(mPacket.getShort());
+
+        final String senderHwAddr = getMacAddressString(mPacket);
+        final String senderIPv4 = getIPv4AddressString(mPacket);
+        getMacAddressString(mPacket);  // target hardware address, unused
+        final String targetIPv4 = getIPv4AddressString(mPacket);
+
+        if (opCode == ARP_REQUEST) {
+            sj.add("who-has").add(targetIPv4);
+        } else if (opCode == ARP_REPLY) {
+            sj.add("reply").add(senderIPv4).add(senderHwAddr);
+        } else {
+            sj.add("unknown opcode").add(asString(opCode));
+        }
+    }
+
+    private void parseIPv4(StringJoiner sj) {
+        if (!mPacket.hasRemaining()) {
+            sj.add("runt");
+            return;
+        }
+
+        final int startOfIpLayer = mPacket.position();
+        final int ipv4HeaderLength = (mPacket.get(startOfIpLayer) & IPV4_IHL_MASK) * 4;
+        if (mPacket.remaining() < ipv4HeaderLength ||
+            mPacket.remaining() < IPV4_HEADER_MIN_LEN) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+        final int startOfTransportLayer = startOfIpLayer + ipv4HeaderLength;
+
+        mPacket.position(startOfIpLayer + IPV4_FLAGS_OFFSET);
+        final int flagsAndFragment = asUint(mPacket.getShort());
+        final boolean isFragment = (flagsAndFragment & IPV4_FRAGMENT_MASK) != 0;
+
+        mPacket.position(startOfIpLayer + IPV4_PROTOCOL_OFFSET);
+        final int protocol = asUint(mPacket.get());
+
+        mPacket.position(startOfIpLayer + IPV4_SRC_ADDR_OFFSET);
+        final String srcAddr = getIPv4AddressString(mPacket);
+
+        mPacket.position(startOfIpLayer + IPV4_DST_ADDR_OFFSET);
+        final String dstAddr = getIPv4AddressString(mPacket);
+
+        sj.add(srcAddr).add(">").add(dstAddr);
+
+        mPacket.position(startOfTransportLayer);
+        if (protocol == IPPROTO_UDP) {
+            sj.add("udp");
+            if (isFragment) sj.add("fragment");
+            else parseUDP(sj);
+        } else {
+            sj.add("proto").add(asString(protocol));
+            if (isFragment) sj.add("fragment");
+        }
+    }
+
+    private void parseIPv6(StringJoiner sj) {
+        if (mPacket.remaining() < IPV6_HEADER_LEN) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        final int startOfIpLayer = mPacket.position();
+
+        mPacket.position(startOfIpLayer + IPV6_PROTOCOL_OFFSET);
+        final int protocol = asUint(mPacket.get());
+
+        mPacket.position(startOfIpLayer + IPV6_SRC_ADDR_OFFSET);
+        final String srcAddr = getIPv6AddressString(mPacket);
+        final String dstAddr = getIPv6AddressString(mPacket);
+
+        sj.add(srcAddr).add(">").add(dstAddr);
+
+        mPacket.position(startOfIpLayer + IPV6_HEADER_LEN);
+        if (protocol == IPPROTO_ICMPV6) {
+            sj.add("icmp6");
+            parseICMPv6(sj);
+        } else {
+            sj.add("proto").add(asString(protocol));
+        }
+    }
+
+    private void parseICMPv6(StringJoiner sj) {
+        if (mPacket.remaining() < ICMPV6_HEADER_MIN_LEN) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        final int icmp6Type = asUint(mPacket.get());
+        final int icmp6Code = asUint(mPacket.get());
+        mPacket.getShort();  // checksum, unused
+
+        switch (icmp6Type) {
+            case ICMPV6_ROUTER_SOLICITATION:
+                sj.add("rs");
+                parseICMPv6RouterSolicitation(sj);
+                break;
+            case ICMPV6_ROUTER_ADVERTISEMENT:
+                sj.add("ra");
+                parseICMPv6RouterAdvertisement(sj);
+                break;
+            case ICMPV6_NEIGHBOR_SOLICITATION:
+                sj.add("ns");
+                parseICMPv6NeighborMessage(sj);
+                break;
+            case ICMPV6_NEIGHBOR_ADVERTISEMENT:
+                sj.add("na");
+                parseICMPv6NeighborMessage(sj);
+                break;
+            default:
+                sj.add("type").add(asString(icmp6Type));
+                sj.add("code").add(asString(icmp6Code));
+                break;
+        }
+    }
+
+    private void parseICMPv6RouterSolicitation(StringJoiner sj) {
+        final int RESERVED = 4;
+        if (mPacket.remaining() < RESERVED) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        mPacket.position(mPacket.position() + RESERVED);
+        parseICMPv6NeighborDiscoveryOptions(sj);
+    }
+
+    private void parseICMPv6RouterAdvertisement(StringJoiner sj) {
+        final int FLAGS_AND_TIMERS = 3 * 4;
+        if (mPacket.remaining() < FLAGS_AND_TIMERS) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        mPacket.position(mPacket.position() + FLAGS_AND_TIMERS);
+        parseICMPv6NeighborDiscoveryOptions(sj);
+    }
+
+    private void parseICMPv6NeighborMessage(StringJoiner sj) {
+        final int RESERVED = 4;
+        final int minReq = RESERVED + IPV6_ADDR_LEN;
+        if (mPacket.remaining() < minReq) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        mPacket.position(mPacket.position() + RESERVED);
+        sj.add(getIPv6AddressString(mPacket));
+        parseICMPv6NeighborDiscoveryOptions(sj);
+    }
+
+    private void parseICMPv6NeighborDiscoveryOptions(StringJoiner sj) {
+        // All ND options are TLV, where T is one byte and L is one byte equal
+        // to the length of T + L + V in units of 8 octets.
+        while (mPacket.remaining() >= ICMPV6_ND_OPTION_MIN_LENGTH) {
+            final int ndType = asUint(mPacket.get());
+            final int ndLength = asUint(mPacket.get());
+            final int ndBytes = ndLength * ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR - 2;
+            if (ndBytes < 0 || ndBytes > mPacket.remaining()) {
+                sj.add("<malformed>");
+                break;
+            }
+            final int position = mPacket.position();
+
+            switch (ndType) {
+                    case ICMPV6_ND_OPTION_SLLA:
+                        sj.add("slla");
+                        sj.add(getMacAddressString(mPacket));
+                        break;
+                    case ICMPV6_ND_OPTION_TLLA:
+                        sj.add("tlla");
+                        sj.add(getMacAddressString(mPacket));
+                        break;
+                    case ICMPV6_ND_OPTION_MTU:
+                        sj.add("mtu");
+                        final short reserved = mPacket.getShort();
+                        sj.add(asString(mPacket.getInt()));
+                        break;
+                    default:
+                        // Skip.
+                        break;
+            }
+
+            mPacket.position(position + ndBytes);
+        }
+    }
+
+    private void parseUDP(StringJoiner sj) {
+        if (mPacket.remaining() < UDP_HEADER_LEN) {
+            sj.add("runt:").add(asString(mPacket.remaining()));
+            return;
+        }
+
+        final int previous = mPacket.position();
+        final int srcPort = asUint(mPacket.getShort());
+        final int dstPort = asUint(mPacket.getShort());
+        sj.add(asString(srcPort)).add(">").add(asString(dstPort));
+
+        mPacket.position(previous + UDP_HEADER_LEN);
+        if (srcPort == DHCP4_CLIENT_PORT || dstPort == DHCP4_CLIENT_PORT) {
+            sj.add("dhcp4");
+            parseDHCPv4(sj);
+        }
+    }
+
+    private void parseDHCPv4(StringJoiner sj) {
+        final DhcpPacket dhcpPacket;
+        try {
+            dhcpPacket = DhcpPacket.decodeFullPacket(mBytes, mLength, DhcpPacket.ENCAP_L2);
+            sj.add(dhcpPacket.toString());
+        } catch (DhcpPacket.ParseException e) {
+            sj.add("parse error: " + e);
+        }
+    }
+
+    private static String getIPv4AddressString(ByteBuffer ipv4) {
+        return getIpAddressString(ipv4, IPV4_ADDR_LEN);
+    }
+
+    private static String getIPv6AddressString(ByteBuffer ipv6) {
+        return getIpAddressString(ipv6, IPV6_ADDR_LEN);
+    }
+
+    private static String getIpAddressString(ByteBuffer ip, int byteLength) {
+        if (ip == null || ip.remaining() < byteLength) return "invalid";
+
+        byte[] bytes = new byte[byteLength];
+        ip.get(bytes, 0, byteLength);
+        try {
+            InetAddress addr = InetAddress.getByAddress(bytes);
+            return addr.getHostAddress();
+        } catch (UnknownHostException uhe) {
+            return "unknown";
+        }
+    }
+
+    private static String getMacAddressString(ByteBuffer mac) {
+        if (mac == null || mac.remaining() < ETHER_ADDR_LEN) return "invalid";
+
+        byte[] bytes = new byte[ETHER_ADDR_LEN];
+        mac.get(bytes, 0, bytes.length);
+        Object[] printableBytes = new Object[bytes.length];
+        int i = 0;
+        for (byte b : bytes) printableBytes[i++] = new Byte(b);
+
+        final String MAC48_FORMAT = "%02x:%02x:%02x:%02x:%02x:%02x";
+        return String.format(MAC48_FORMAT, printableBytes);
+    }
+
+    /**
+     * Convenience method to convert an int to a String.
+     */
+    public static String asString(int i) {
+        return Integer.toString(i);
+    }
+
+    /**
+     * Convenience method to read a byte as an unsigned int.
+     */
+    public static int asUint(byte b) {
+        return (b & 0xff);
+    }
+
+    /**
+     * Convenience method to read a short as an unsigned int.
+     */
+    public static int asUint(short s) {
+        return (s & 0xffff);
+    }
+}
diff --git a/services/net/java/android/net/util/FdEventsReader.java b/packages/NetworkStack/src/android/net/util/FdEventsReader.java
similarity index 100%
rename from services/net/java/android/net/util/FdEventsReader.java
rename to packages/NetworkStack/src/android/net/util/FdEventsReader.java
diff --git a/services/net/java/android/net/util/PacketReader.java b/packages/NetworkStack/src/android/net/util/PacketReader.java
similarity index 100%
rename from services/net/java/android/net/util/PacketReader.java
rename to packages/NetworkStack/src/android/net/util/PacketReader.java
diff --git a/packages/NetworkStack/src/android/net/util/SharedLog.java b/packages/NetworkStack/src/android/net/util/SharedLog.java
new file mode 100644
index 0000000..4fabf10
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/util/SharedLog.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.LocalLog;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.StringJoiner;
+
+
+/**
+ * Class to centralize logging functionality for tethering.
+ *
+ * All access to class methods other than dump() must be on the same thread.
+ *
+ * @hide
+ */
+public class SharedLog {
+    private static final int DEFAULT_MAX_RECORDS = 500;
+    private static final String COMPONENT_DELIMITER = ".";
+
+    private enum Category {
+        NONE,
+        ERROR,
+        MARK,
+        WARN,
+    };
+
+    private final LocalLog mLocalLog;
+    // The tag to use for output to the system log. This is not output to the
+    // LocalLog because that would be redundant.
+    private final String mTag;
+    // The component (or subcomponent) of a system that is sharing this log.
+    // This can grow in depth if components call forSubComponent() to obtain
+    // their SharedLog instance. The tag is not included in the component for
+    // brevity.
+    private final String mComponent;
+
+    public SharedLog(String tag) {
+        this(DEFAULT_MAX_RECORDS, tag);
+    }
+
+    public SharedLog(int maxRecords, String tag) {
+        this(new LocalLog(maxRecords), tag, tag);
+    }
+
+    private SharedLog(LocalLog localLog, String tag, String component) {
+        mLocalLog = localLog;
+        mTag = tag;
+        mComponent = component;
+    }
+
+    public String getTag() {
+        return mTag;
+    }
+
+    /**
+     * Create a SharedLog based on this log with an additional component prefix on each logged line.
+     */
+    public SharedLog forSubComponent(String component) {
+        if (!isRootLogInstance()) {
+            component = mComponent + COMPONENT_DELIMITER + component;
+        }
+        return new SharedLog(mLocalLog, mTag, component);
+    }
+
+    /**
+     * Dump the contents of this log.
+     *
+     * <p>This method may be called on any thread.
+     */
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        mLocalLog.readOnlyLocalLog().dump(fd, writer, args);
+    }
+
+    //////
+    // Methods that both log an entry and emit it to the system log.
+    //////
+
+    /**
+     * Log an error due to an exception. This does not include the exception stacktrace.
+     *
+     * <p>The log entry will be also added to the system log.
+     * @see #e(String, Throwable)
+     */
+    public void e(Exception e) {
+        Log.e(mTag, record(Category.ERROR, e.toString()));
+    }
+
+    /**
+     * Log an error message.
+     *
+     * <p>The log entry will be also added to the system log.
+     */
+    public void e(String msg) {
+        Log.e(mTag, record(Category.ERROR, msg));
+    }
+
+    /**
+     * 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). The log entry will be also added to the system log.
+     */
+    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);
+    }
+
+    /**
+     * Log an informational message.
+     *
+     * <p>The log entry will be also added to the system log.
+     */
+    public void i(String msg) {
+        Log.i(mTag, record(Category.NONE, msg));
+    }
+
+    /**
+     * Log a warning message.
+     *
+     * <p>The log entry will be also added to the system log.
+     */
+    public void w(String msg) {
+        Log.w(mTag, record(Category.WARN, msg));
+    }
+
+    //////
+    // Methods that only log an entry (and do NOT emit to the system log).
+    //////
+
+    /**
+     * Log a general message to be only included in the in-memory log.
+     *
+     * <p>The log entry will *not* be added to the system log.
+     */
+    public void log(String msg) {
+        record(Category.NONE, msg);
+    }
+
+    /**
+     * Log a general, formatted message to be only included in the in-memory log.
+     *
+     * <p>The log entry will *not* be added to the system log.
+     * @see String#format(String, Object...)
+     */
+    public void logf(String fmt, Object... args) {
+        log(String.format(fmt, args));
+    }
+
+    /**
+     * Log a message with MARK level.
+     *
+     * <p>The log entry will *not* be added to the system log.
+     */
+    public void mark(String msg) {
+        record(Category.MARK, msg);
+    }
+
+    private String record(Category category, String msg) {
+        final String entry = logLine(category, msg);
+        mLocalLog.log(entry);
+        return entry;
+    }
+
+    private String logLine(Category category, String msg) {
+        final StringJoiner sj = new StringJoiner(" ");
+        if (!isRootLogInstance()) sj.add("[" + mComponent + "]");
+        if (category != Category.NONE) sj.add(category.toString());
+        return sj.add(msg).toString();
+    }
+
+    // Check whether this SharedLog instance is nominally the top level in
+    // a potential hierarchy of shared logs (the root of a tree),
+    // or is a subcomponent within the hierarchy.
+    private boolean isRootLogInstance() {
+        return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag);
+    }
+}
diff --git a/packages/NetworkStack/src/android/net/util/Stopwatch.java b/packages/NetworkStack/src/android/net/util/Stopwatch.java
new file mode 100644
index 0000000..c316699
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/util/Stopwatch.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import android.os.SystemClock;
+
+
+/**
+ * @hide
+ */
+public class Stopwatch {
+    private long mStartTimeMs;
+    private long mStopTimeMs;
+
+    public boolean isStarted() {
+        return (mStartTimeMs > 0);
+    }
+
+    public boolean isStopped() {
+        return (mStopTimeMs > 0);
+    }
+
+    public boolean isRunning() {
+        return (isStarted() && !isStopped());
+    }
+
+    /**
+     * Start the Stopwatch.
+     */
+    public Stopwatch start() {
+        if (!isStarted()) {
+            mStartTimeMs = SystemClock.elapsedRealtime();
+        }
+        return this;
+    }
+
+    /**
+     * Stop the Stopwatch.
+     * @return the total time recorded, in milliseconds, or 0 if not started.
+     */
+    public long stop() {
+        if (isRunning()) {
+            mStopTimeMs = SystemClock.elapsedRealtime();
+        }
+        // Return either the delta after having stopped, or 0.
+        return (mStopTimeMs - mStartTimeMs);
+    }
+
+    /**
+     * Return the total time recorded to date, in milliseconds.
+     * If the Stopwatch is not running, returns the same value as stop(),
+     * i.e. either the total time recorded before stopping or 0.
+     */
+    public long lap() {
+        if (isRunning()) {
+            return (SystemClock.elapsedRealtime() - mStartTimeMs);
+        } else {
+            return stop();
+        }
+    }
+
+    /**
+     * Reset the Stopwatch. It will be stopped when this method returns.
+     */
+    public void reset() {
+        mStartTimeMs = 0;
+        mStopTimeMs = 0;
+    }
+}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index 5afaf58..4080ddf 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -16,18 +16,47 @@
 
 package com.android.server;
 
-import static android.os.Binder.getCallingUid;
+import static android.net.dhcp.IDhcpServer.STATUS_INVALID_ARGUMENT;
+import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
+import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR;
+
+import static com.android.server.util.PermissionUtil.checkDumpPermission;
+import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Service;
+import android.content.Context;
 import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.INetworkMonitor;
+import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkStackConnector;
+import android.net.Network;
+import android.net.NetworkRequest;
+import android.net.PrivateDnsConfigParcel;
+import android.net.dhcp.DhcpServer;
+import android.net.dhcp.DhcpServingParams;
+import android.net.dhcp.DhcpServingParamsParcel;
+import android.net.dhcp.IDhcpServerCallbacks;
+import android.net.ip.IIpClientCallbacks;
+import android.net.ip.IpClient;
+import android.net.shared.PrivateDnsConfig;
+import android.net.util.SharedLog;
 import android.os.IBinder;
-import android.os.Process;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.connectivity.NetworkMonitor;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
 
 /**
  * Android service used to start the network stack when bound to via an intent.
@@ -43,32 +72,210 @@
      * <p>On platforms where the network stack runs in the system server process, this method may
      * be called directly instead of obtaining the connector by binding to the service.
      */
-    public static IBinder makeConnector() {
-        return new NetworkStackConnector();
+    public static IBinder makeConnector(Context context) {
+        return new NetworkStackConnector(context);
     }
 
     @NonNull
     @Override
     public IBinder onBind(Intent intent) {
-        return makeConnector();
+        return makeConnector(this);
     }
 
     private static class NetworkStackConnector extends INetworkStackConnector.Stub {
-        // TODO: makeDhcpServer(), etc. will go here.
+        private static final int NUM_VALIDATION_LOG_LINES = 20;
+        private final Context mContext;
+        private final ConnectivityManager mCm;
+        @GuardedBy("mIpClients")
+        private final ArrayList<WeakReference<IpClient>> mIpClients = new ArrayList<>();
+
+        private static final int MAX_VALIDATION_LOGS = 10;
+        @GuardedBy("mValidationLogs")
+        private final ArrayDeque<SharedLog> mValidationLogs = new ArrayDeque<>(MAX_VALIDATION_LOGS);
+
+        private SharedLog addValidationLogs(Network network, String name) {
+            final SharedLog log = new SharedLog(NUM_VALIDATION_LOG_LINES, network + " - " + name);
+            synchronized (mValidationLogs) {
+                while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) {
+                    mValidationLogs.removeLast();
+                }
+                mValidationLogs.addFirst(log);
+            }
+            return log;
+        }
+
+        NetworkStackConnector(Context context) {
+            mContext = context;
+            mCm = context.getSystemService(ConnectivityManager.class);
+        }
+
+        @NonNull
+        private final SharedLog mLog = new SharedLog(TAG);
+
+        @Override
+        public void makeDhcpServer(@NonNull String ifName, @NonNull DhcpServingParamsParcel params,
+                @NonNull IDhcpServerCallbacks cb) throws RemoteException {
+            checkNetworkStackCallingPermission();
+            final DhcpServer server;
+            try {
+                server = new DhcpServer(
+                        ifName,
+                        DhcpServingParams.fromParcelableObject(params),
+                        mLog.forSubComponent(ifName + ".DHCP"));
+            } catch (DhcpServingParams.InvalidParameterException e) {
+                mLog.e("Invalid DhcpServingParams", e);
+                cb.onDhcpServerCreated(STATUS_INVALID_ARGUMENT, null);
+                return;
+            } catch (Exception e) {
+                mLog.e("Unknown error starting DhcpServer", e);
+                cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null);
+                return;
+            }
+            cb.onDhcpServerCreated(STATUS_SUCCESS, server);
+        }
+
+        @Override
+        public void makeNetworkMonitor(int netId, String name, INetworkMonitorCallbacks cb)
+                throws RemoteException {
+            final Network network = new Network(netId, false /* privateDnsBypass */);
+            final NetworkRequest defaultRequest = mCm.getDefaultRequest();
+            final SharedLog log = addValidationLogs(network, name);
+            final NetworkMonitor nm = new NetworkMonitor(
+                    mContext, cb, network, defaultRequest, log);
+            cb.onNetworkMonitorCreated(new NetworkMonitorImpl(nm));
+        }
+
+        @Override
+        public void makeIpClient(String ifName, IIpClientCallbacks cb) throws RemoteException {
+            final IpClient ipClient = new IpClient(mContext, ifName, cb);
+
+            synchronized (mIpClients) {
+                final Iterator<WeakReference<IpClient>> it = mIpClients.iterator();
+                while (it.hasNext()) {
+                    final IpClient ipc = it.next().get();
+                    if (ipc == null) {
+                        it.remove();
+                    }
+                }
+                mIpClients.add(new WeakReference<>(ipClient));
+            }
+
+            cb.onIpClientCreated(ipClient.makeConnector());
+        }
 
         @Override
         protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
                 @Nullable String[] args) {
-            checkCaller();
-            fout.println("NetworkStack logs:");
-            // TODO: dump logs here
+            checkDumpPermission();
+            final IndentingPrintWriter pw = new IndentingPrintWriter(fout, "  ");
+            pw.println("NetworkStack logs:");
+            mLog.dump(fd, pw, args);
+
+            // Dump full IpClient logs for non-GCed clients
+            pw.println();
+            pw.println("Recently active IpClient logs:");
+            final ArrayList<IpClient> ipClients = new ArrayList<>();
+            final HashSet<String> dumpedIpClientIfaces = new HashSet<>();
+            synchronized (mIpClients) {
+                for (WeakReference<IpClient> ipcRef : mIpClients) {
+                    final IpClient ipc = ipcRef.get();
+                    if (ipc != null) {
+                        ipClients.add(ipc);
+                    }
+                }
+            }
+
+            for (IpClient ipc : ipClients) {
+                pw.println(ipc.getName());
+                pw.increaseIndent();
+                ipc.dump(fd, pw, args);
+                pw.decreaseIndent();
+                dumpedIpClientIfaces.add(ipc.getInterfaceName());
+            }
+
+            // State machine and connectivity metrics logs are kept for GCed IpClients
+            pw.println();
+            pw.println("Other IpClient logs:");
+            IpClient.dumpAllLogs(fout, dumpedIpClientIfaces);
+
+            pw.println();
+            pw.println("Validation logs (most recent first):");
+            synchronized (mValidationLogs) {
+                for (SharedLog p : mValidationLogs) {
+                    pw.println(p.getTag());
+                    pw.increaseIndent();
+                    p.dump(fd, pw, args);
+                    pw.decreaseIndent();
+                }
+            }
         }
     }
 
-    private static void checkCaller() {
-        // TODO: check that the calling PID is the system server.
-        if (getCallingUid() != Process.SYSTEM_UID && getCallingUid() != Process.ROOT_UID) {
-            throw new SecurityException("Invalid caller: " + getCallingUid());
+    private static class NetworkMonitorImpl extends INetworkMonitor.Stub {
+        private final NetworkMonitor mNm;
+
+        NetworkMonitorImpl(NetworkMonitor nm) {
+            mNm = nm;
+        }
+
+        @Override
+        public void start() {
+            checkNetworkStackCallingPermission();
+            mNm.start();
+        }
+
+        @Override
+        public void launchCaptivePortalApp() {
+            checkNetworkStackCallingPermission();
+            mNm.launchCaptivePortalApp();
+        }
+
+        @Override
+        public void forceReevaluation(int uid) {
+            checkNetworkStackCallingPermission();
+            mNm.forceReevaluation(uid);
+        }
+
+        @Override
+        public void notifyPrivateDnsChanged(PrivateDnsConfigParcel config) {
+            checkNetworkStackCallingPermission();
+            mNm.notifyPrivateDnsSettingsChanged(PrivateDnsConfig.fromParcel(config));
+        }
+
+        @Override
+        public void notifyDnsResponse(int returnCode) {
+            checkNetworkStackCallingPermission();
+            mNm.notifyDnsResponse(returnCode);
+        }
+
+        @Override
+        public void notifySystemReady() {
+            checkNetworkStackCallingPermission();
+            mNm.notifySystemReady();
+        }
+
+        @Override
+        public void notifyNetworkConnected() {
+            checkNetworkStackCallingPermission();
+            mNm.notifyNetworkConnected();
+        }
+
+        @Override
+        public void notifyNetworkDisconnected() {
+            checkNetworkStackCallingPermission();
+            mNm.notifyNetworkDisconnected();
+        }
+
+        @Override
+        public void notifyLinkPropertiesChanged() {
+            checkNetworkStackCallingPermission();
+            mNm.notifyLinkPropertiesChanged();
+        }
+
+        @Override
+        public void notifyNetworkCapabilitiesChanged() {
+            checkNetworkStackCallingPermission();
+            mNm.notifyNetworkCapabilitiesChanged();
         }
     }
 }
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
new file mode 100644
index 0000000..6b31b82
--- /dev/null
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -0,0 +1,1760 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
+import static android.net.CaptivePortal.APP_RETURN_UNWANTED;
+import static android.net.CaptivePortal.APP_RETURN_WANTED_AS_IS;
+import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC;
+import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.metrics.ValidationProbeEvent.DNS_FAILURE;
+import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS;
+import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK;
+import static android.net.metrics.ValidationProbeEvent.PROBE_PRIVDNS;
+
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.CaptivePortal;
+import android.net.ConnectivityManager;
+import android.net.ICaptivePortal;
+import android.net.INetworkMonitor;
+import android.net.INetworkMonitorCallbacks;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.ProxyInfo;
+import android.net.TrafficStats;
+import android.net.Uri;
+import android.net.captiveportal.CaptivePortalProbeResult;
+import android.net.captiveportal.CaptivePortalProbeSpec;
+import android.net.metrics.IpConnectivityLog;
+import android.net.metrics.NetworkEvent;
+import android.net.metrics.ValidationProbeEvent;
+import android.net.shared.NetworkMonitorUtils;
+import android.net.shared.PrivateDnsConfig;
+import android.net.util.SharedLog;
+import android.net.util.Stopwatch;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.telephony.CellIdentityCdma;
+import android.telephony.CellIdentityGsm;
+import android.telephony.CellIdentityLte;
+import android.telephony.CellIdentityWcdma;
+import android.telephony.CellInfo;
+import android.telephony.CellInfoCdma;
+import android.telephony.CellInfoGsm;
+import android.telephony.CellInfoLte;
+import android.telephony.CellInfoWcdma;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.RingBufferIndices;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Random;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@hide}
+ */
+public class NetworkMonitor extends StateMachine {
+    private static final String TAG = NetworkMonitor.class.getSimpleName();
+    private static final boolean DBG  = true;
+    private static final boolean VDBG = false;
+    private static final boolean VDBG_STALL = Log.isLoggable(TAG, Log.DEBUG);
+    // Default configuration values for captive portal detection probes.
+    // TODO: append a random length parameter to the default HTTPS url.
+    // TODO: randomize browser version ids in the default User-Agent String.
+    private static final String DEFAULT_HTTPS_URL = "https://www.google.com/generate_204";
+    private static final String DEFAULT_FALLBACK_URL  = "http://www.google.com/gen_204";
+    private static final String DEFAULT_OTHER_FALLBACK_URLS =
+            "http://play.googleapis.com/generate_204";
+    private static final String DEFAULT_USER_AGENT    = "Mozilla/5.0 (X11; Linux x86_64) "
+                                                      + "AppleWebKit/537.36 (KHTML, like Gecko) "
+                                                      + "Chrome/60.0.3112.32 Safari/537.36";
+
+    private static final int SOCKET_TIMEOUT_MS = 10000;
+    private static final int PROBE_TIMEOUT_MS  = 3000;
+
+    // Default configuration values for data stall detection.
+    private static final int DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = 5;
+    private static final int DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS = 60 * 1000;
+    private static final int DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS = 30 * 60 * 1000;
+
+    private static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
+    private static final int DEFAULT_DATA_STALL_EVALUATION_TYPES =
+            (1 << DATA_STALL_EVALUATION_TYPE_DNS);
+
+    enum EvaluationResult {
+        VALIDATED(true),
+        CAPTIVE_PORTAL(false);
+        final boolean mIsValidated;
+        EvaluationResult(boolean isValidated) {
+            this.mIsValidated = isValidated;
+        }
+    }
+
+    enum ValidationStage {
+        FIRST_VALIDATION(true),
+        REVALIDATION(false);
+        final boolean mIsFirstValidation;
+        ValidationStage(boolean isFirstValidation) {
+            this.mIsFirstValidation = isFirstValidation;
+        }
+    }
+
+    /**
+     * ConnectivityService has sent a notification to indicate that network has connected.
+     * Initiates Network Validation.
+     */
+    private static final int CMD_NETWORK_CONNECTED = 1;
+
+    /**
+     * Message to self indicating it's time to evaluate a network's connectivity.
+     * arg1 = Token to ignore old messages.
+     */
+    private static final int CMD_REEVALUATE = 6;
+
+    /**
+     * ConnectivityService has sent a notification to indicate that network has disconnected.
+     */
+    private static final int CMD_NETWORK_DISCONNECTED = 7;
+
+    /**
+     * Force evaluation even if it has succeeded in the past.
+     * arg1 = UID responsible for requesting this reeval.  Will be billed for data.
+     */
+    private static final int CMD_FORCE_REEVALUATION = 8;
+
+    /**
+     * Message to self indicating captive portal app finished.
+     * arg1 = one of: APP_RETURN_DISMISSED,
+     *                APP_RETURN_UNWANTED,
+     *                APP_RETURN_WANTED_AS_IS
+     * obj = mCaptivePortalLoggedInResponseToken as String
+     */
+    private static final int CMD_CAPTIVE_PORTAL_APP_FINISHED = 9;
+
+    /**
+     * Message indicating sign-in app should be launched.
+     * Sent by mLaunchCaptivePortalAppBroadcastReceiver when the
+     * user touches the sign in notification, or sent by
+     * ConnectivityService when the user touches the "sign into
+     * network" button in the wifi access point detail page.
+     */
+    private static final int CMD_LAUNCH_CAPTIVE_PORTAL_APP = 11;
+
+    /**
+     * Retest network to see if captive portal is still in place.
+     * arg1 = UID responsible for requesting this reeval.  Will be billed for data.
+     *        0 indicates self-initiated, so nobody to blame.
+     */
+    private static final int CMD_CAPTIVE_PORTAL_RECHECK = 12;
+
+    /**
+     * ConnectivityService notifies NetworkMonitor of settings changes to
+     * Private DNS. If a DNS resolution is required, e.g. for DNS-over-TLS in
+     * strict mode, then an event is sent back to ConnectivityService with the
+     * result of the resolution attempt.
+     *
+     * A separate message is used to trigger (re)evaluation of the Private DNS
+     * configuration, so that the message can be handled as needed in different
+     * states, including being ignored until after an ongoing captive portal
+     * validation phase is completed.
+     */
+    private static final int CMD_PRIVATE_DNS_SETTINGS_CHANGED = 13;
+    private static final int CMD_EVALUATE_PRIVATE_DNS = 15;
+
+    /**
+     * Message to self indicating captive portal detection is completed.
+     * obj = CaptivePortalProbeResult for detection result;
+     */
+    public static final int CMD_PROBE_COMPLETE = 16;
+
+    /**
+     * ConnectivityService notifies NetworkMonitor of DNS query responses event.
+     * arg1 = returncode in OnDnsEvent which indicates the response code for the DNS query.
+     */
+    public static final int EVENT_DNS_NOTIFICATION = 17;
+
+    // Start mReevaluateDelayMs at this value and double.
+    private static final int INITIAL_REEVALUATE_DELAY_MS = 1000;
+    private static final int MAX_REEVALUATE_DELAY_MS = 10 * 60 * 1000;
+    // Before network has been evaluated this many times, ignore repeated reevaluate requests.
+    private static final int IGNORE_REEVALUATE_ATTEMPTS = 5;
+    private int mReevaluateToken = 0;
+    private static final int NO_UID = 0;
+    private static final int INVALID_UID = -1;
+    private int mUidResponsibleForReeval = INVALID_UID;
+    // Stop blaming UID that requested re-evaluation after this many attempts.
+    private static final int BLAME_FOR_EVALUATION_ATTEMPTS = 5;
+    // Delay between reevaluations once a captive portal has been found.
+    private static final int CAPTIVE_PORTAL_REEVALUATE_DELAY_MS = 10 * 60 * 1000;
+
+    private String mPrivateDnsProviderHostname = "";
+
+    private final Context mContext;
+    private final INetworkMonitorCallbacks mCallback;
+    private final Network mNetwork;
+    private final Network mNonPrivateDnsBypassNetwork;
+    private final TelephonyManager mTelephonyManager;
+    private final WifiManager mWifiManager;
+    private final ConnectivityManager mCm;
+    private final IpConnectivityLog mMetricsLog;
+    private final Dependencies mDependencies;
+
+    // Configuration values for captive portal detection probes.
+    private final String mCaptivePortalUserAgent;
+    private final URL mCaptivePortalHttpsUrl;
+    private final URL mCaptivePortalHttpUrl;
+    private final URL[] mCaptivePortalFallbackUrls;
+    @Nullable
+    private final CaptivePortalProbeSpec[] mCaptivePortalFallbackSpecs;
+
+    private NetworkCapabilities mNetworkCapabilities;
+    private LinkProperties mLinkProperties;
+
+    @VisibleForTesting
+    protected boolean mIsCaptivePortalCheckEnabled;
+
+    private boolean mUseHttps;
+    // The total number of captive portal detection attempts for this NetworkMonitor instance.
+    private int mValidations = 0;
+
+    // Set if the user explicitly selected "Do not use this network" in captive portal sign-in app.
+    private boolean mUserDoesNotWant = false;
+    // Avoids surfacing "Sign in to network" notification.
+    private boolean mDontDisplaySigninNotification = false;
+
+    private volatile boolean mSystemReady = false;
+
+    private final State mDefaultState = new DefaultState();
+    private final State mValidatedState = new ValidatedState();
+    private final State mMaybeNotifyState = new MaybeNotifyState();
+    private final State mEvaluatingState = new EvaluatingState();
+    private final State mCaptivePortalState = new CaptivePortalState();
+    private final State mEvaluatingPrivateDnsState = new EvaluatingPrivateDnsState();
+    private final State mProbingState = new ProbingState();
+    private final State mWaitingForNextProbeState = new WaitingForNextProbeState();
+
+    private CustomIntentReceiver mLaunchCaptivePortalAppBroadcastReceiver = null;
+
+    private final SharedLog mValidationLogs;
+
+    private final Stopwatch mEvaluationTimer = new Stopwatch();
+
+    // This variable is set before transitioning to the mCaptivePortalState.
+    private CaptivePortalProbeResult mLastPortalProbeResult = CaptivePortalProbeResult.FAILED;
+
+    // Random generator to select fallback URL index
+    private final Random mRandom;
+    private int mNextFallbackUrlIndex = 0;
+
+
+    private int mReevaluateDelayMs = INITIAL_REEVALUATE_DELAY_MS;
+    private int mEvaluateAttempts = 0;
+    private volatile int mProbeToken = 0;
+    private final int mConsecutiveDnsTimeoutThreshold;
+    private final int mDataStallMinEvaluateTime;
+    private final int mDataStallValidDnsTimeThreshold;
+    private final int mDataStallEvaluationType;
+    private final DnsStallDetector mDnsStallDetector;
+    private long mLastProbeTime;
+
+    public NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
+            NetworkRequest defaultRequest, SharedLog validationLog) {
+        this(context, cb, network, defaultRequest, new IpConnectivityLog(), validationLog,
+                Dependencies.DEFAULT);
+    }
+
+    @VisibleForTesting
+    protected NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
+            NetworkRequest defaultRequest, IpConnectivityLog logger, SharedLog validationLogs,
+            Dependencies deps) {
+        // Add suffix indicating which NetworkMonitor we're talking about.
+        super(TAG + "/" + network.toString());
+
+        // Logs with a tag of the form given just above, e.g.
+        //     <timestamp>   862  2402 D NetworkMonitor/NetworkAgentInfo [WIFI () - 100]: ...
+        setDbg(VDBG);
+
+        mContext = context;
+        mMetricsLog = logger;
+        mValidationLogs = validationLogs;
+        mCallback = cb;
+        mDependencies = deps;
+        mNonPrivateDnsBypassNetwork = network;
+        mNetwork = deps.getPrivateDnsBypassNetwork(network);
+        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+        // CHECKSTYLE:OFF IndentationCheck
+        addState(mDefaultState);
+        addState(mMaybeNotifyState, mDefaultState);
+            addState(mEvaluatingState, mMaybeNotifyState);
+                addState(mProbingState, mEvaluatingState);
+                addState(mWaitingForNextProbeState, mEvaluatingState);
+            addState(mCaptivePortalState, mMaybeNotifyState);
+        addState(mEvaluatingPrivateDnsState, mDefaultState);
+        addState(mValidatedState, mDefaultState);
+        setInitialState(mDefaultState);
+        // CHECKSTYLE:ON IndentationCheck
+
+        mIsCaptivePortalCheckEnabled = getIsCaptivePortalCheckEnabled();
+        mUseHttps = getUseHttpsValidation();
+        mCaptivePortalUserAgent = getCaptivePortalUserAgent();
+        mCaptivePortalHttpsUrl = makeURL(getCaptivePortalServerHttpsUrl());
+        mCaptivePortalHttpUrl = makeURL(deps.getCaptivePortalServerHttpUrl(context));
+        mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls();
+        mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs();
+        mRandom = deps.getRandom();
+        // TODO: Evaluate to move data stall configuration to a specific class.
+        mConsecutiveDnsTimeoutThreshold = getConsecutiveDnsTimeoutThreshold();
+        mDnsStallDetector = new DnsStallDetector(mConsecutiveDnsTimeoutThreshold);
+        mDataStallMinEvaluateTime = getDataStallMinEvaluateTime();
+        mDataStallValidDnsTimeThreshold = getDataStallValidDnsTimeThreshold();
+        mDataStallEvaluationType = getDataStallEvalutionType();
+
+        // mLinkProperties and mNetworkCapbilities must never be null or we will NPE.
+        // Provide empty objects in case we are started and the network disconnects before
+        // we can ever fetch them.
+        // TODO: Delete ASAP.
+        mLinkProperties = new LinkProperties();
+        mNetworkCapabilities = new NetworkCapabilities();
+        mNetworkCapabilities.clearAll();
+    }
+
+    /**
+     * Request the NetworkMonitor to reevaluate the network.
+     */
+    public void forceReevaluation(int responsibleUid) {
+        sendMessage(CMD_FORCE_REEVALUATION, responsibleUid, 0);
+    }
+
+    /**
+     * Send a notification to NetworkMonitor indicating that there was a DNS query response event.
+     * @param returnCode the DNS return code of the response.
+     */
+    public void notifyDnsResponse(int returnCode) {
+        sendMessage(EVENT_DNS_NOTIFICATION, returnCode);
+    }
+
+    /**
+     * Send a notification to NetworkMonitor indicating that private DNS settings have changed.
+     * @param newCfg The new private DNS configuration.
+     */
+    public void notifyPrivateDnsSettingsChanged(PrivateDnsConfig newCfg) {
+        // Cancel any outstanding resolutions.
+        removeMessages(CMD_PRIVATE_DNS_SETTINGS_CHANGED);
+        // Send the update to the proper thread.
+        sendMessage(CMD_PRIVATE_DNS_SETTINGS_CHANGED, newCfg);
+    }
+
+    /**
+     * Send a notification to NetworkMonitor indicating that the system is ready.
+     */
+    public void notifySystemReady() {
+        // No need to run on the handler thread: mSystemReady is volatile and read only once on the
+        // isCaptivePortal() thread.
+        mSystemReady = true;
+    }
+
+    /**
+     * Send a notification to NetworkMonitor indicating that the network is now connected.
+     */
+    public void notifyNetworkConnected() {
+        sendMessage(CMD_NETWORK_CONNECTED);
+    }
+
+    /**
+     * Send a notification to NetworkMonitor indicating that the network is now disconnected.
+     */
+    public void notifyNetworkDisconnected() {
+        sendMessage(CMD_NETWORK_DISCONNECTED);
+    }
+
+    /**
+     * Send a notification to NetworkMonitor indicating that link properties have changed.
+     */
+    public void notifyLinkPropertiesChanged() {
+        getHandler().post(() -> {
+            updateLinkProperties();
+        });
+    }
+
+    private void updateLinkProperties() {
+        final LinkProperties lp = mCm.getLinkProperties(mNetwork);
+        // If null, we should soon get a message that the network was disconnected, and will stop.
+        if (lp != null) {
+            // TODO: send LinkProperties parceled in notifyLinkPropertiesChanged() and start().
+            mLinkProperties = lp;
+        }
+    }
+
+    /**
+     * Send a notification to NetworkMonitor indicating that network capabilities have changed.
+     */
+    public void notifyNetworkCapabilitiesChanged() {
+        getHandler().post(() -> {
+            updateNetworkCapabilities();
+        });
+    }
+
+    private void updateNetworkCapabilities() {
+        final NetworkCapabilities nc = mCm.getNetworkCapabilities(mNetwork);
+        // If null, we should soon get a message that the network was disconnected, and will stop.
+        if (nc != null) {
+            // TODO: send NetworkCapabilities parceled in notifyNetworkCapsChanged() and start().
+            mNetworkCapabilities = nc;
+        }
+    }
+
+    /**
+     * Request the captive portal application to be launched.
+     */
+    public void launchCaptivePortalApp() {
+        sendMessage(CMD_LAUNCH_CAPTIVE_PORTAL_APP);
+    }
+
+    @Override
+    protected void log(String s) {
+        if (DBG) Log.d(TAG + "/" + mNetwork.toString(), s);
+    }
+
+    private void validationLog(int probeType, Object url, String msg) {
+        String probeName = ValidationProbeEvent.getProbeName(probeType);
+        validationLog(String.format("%s %s %s", probeName, url, msg));
+    }
+
+    private void validationLog(String s) {
+        if (DBG) log(s);
+        mValidationLogs.log(s);
+    }
+
+    private ValidationStage validationStage() {
+        return 0 == mValidations ? ValidationStage.FIRST_VALIDATION : ValidationStage.REVALIDATION;
+    }
+
+    private boolean isValidationRequired() {
+        return NetworkMonitorUtils.isValidationRequired(mNetworkCapabilities);
+    }
+
+
+    private void notifyNetworkTested(int result, @Nullable String redirectUrl) {
+        try {
+            mCallback.notifyNetworkTested(result, redirectUrl);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error sending network test result", e);
+        }
+    }
+
+    private void showProvisioningNotification(String action) {
+        try {
+            mCallback.showProvisioningNotification(action);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error showing provisioning notification", e);
+        }
+    }
+
+    private void hideProvisioningNotification() {
+        try {
+            mCallback.hideProvisioningNotification();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error hiding provisioning notification", e);
+        }
+    }
+
+    // DefaultState is the parent of all States.  It exists only to handle CMD_* messages but
+    // does not entail any real state (hence no enter() or exit() routines).
+    private class DefaultState extends State {
+        @Override
+        public void enter() {
+            // TODO: have those passed parceled in start() and remove this
+            updateLinkProperties();
+            updateNetworkCapabilities();
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            switch (message.what) {
+                case CMD_NETWORK_CONNECTED:
+                    logNetworkEvent(NetworkEvent.NETWORK_CONNECTED);
+                    transitionTo(mEvaluatingState);
+                    return HANDLED;
+                case CMD_NETWORK_DISCONNECTED:
+                    logNetworkEvent(NetworkEvent.NETWORK_DISCONNECTED);
+                    if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
+                        mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
+                        mLaunchCaptivePortalAppBroadcastReceiver = null;
+                    }
+                    quit();
+                    return HANDLED;
+                case CMD_FORCE_REEVALUATION:
+                case CMD_CAPTIVE_PORTAL_RECHECK:
+                    final int dnsCount = mDnsStallDetector.getConsecutiveTimeoutCount();
+                    validationLog("Forcing reevaluation for UID " + message.arg1
+                            + ". Dns signal count: " + dnsCount);
+                    mUidResponsibleForReeval = message.arg1;
+                    transitionTo(mEvaluatingState);
+                    return HANDLED;
+                case CMD_CAPTIVE_PORTAL_APP_FINISHED:
+                    log("CaptivePortal App responded with " + message.arg1);
+
+                    // If the user has seen and acted on a captive portal notification, and the
+                    // captive portal app is now closed, disable HTTPS probes. This avoids the
+                    // following pathological situation:
+                    //
+                    // 1. HTTP probe returns a captive portal, HTTPS probe fails or times out.
+                    // 2. User opens the app and logs into the captive portal.
+                    // 3. HTTP starts working, but HTTPS still doesn't work for some other reason -
+                    //    perhaps due to the network blocking HTTPS?
+                    //
+                    // In this case, we'll fail to validate the network even after the app is
+                    // dismissed. There is now no way to use this network, because the app is now
+                    // gone, so the user cannot select "Use this network as is".
+                    mUseHttps = false;
+
+                    switch (message.arg1) {
+                        case APP_RETURN_DISMISSED:
+                            sendMessage(CMD_FORCE_REEVALUATION, NO_UID, 0);
+                            break;
+                        case APP_RETURN_WANTED_AS_IS:
+                            mDontDisplaySigninNotification = true;
+                            // TODO: Distinguish this from a network that actually validates.
+                            // Displaying the "x" on the system UI icon may still be a good idea.
+                            transitionTo(mEvaluatingPrivateDnsState);
+                            break;
+                        case APP_RETURN_UNWANTED:
+                            mDontDisplaySigninNotification = true;
+                            mUserDoesNotWant = true;
+                            notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, null);
+                            // TODO: Should teardown network.
+                            mUidResponsibleForReeval = 0;
+                            transitionTo(mEvaluatingState);
+                            break;
+                    }
+                    return HANDLED;
+                case CMD_PRIVATE_DNS_SETTINGS_CHANGED: {
+                    final PrivateDnsConfig cfg = (PrivateDnsConfig) message.obj;
+                    if (!isValidationRequired() || cfg == null || !cfg.inStrictMode()) {
+                        // No DNS resolution required.
+                        //
+                        // We don't force any validation in opportunistic mode
+                        // here. Opportunistic mode nameservers are validated
+                        // separately within netd.
+                        //
+                        // Reset Private DNS settings state.
+                        mPrivateDnsProviderHostname = "";
+                        break;
+                    }
+
+                    mPrivateDnsProviderHostname = cfg.hostname;
+
+                    // DNS resolutions via Private DNS strict mode block for a
+                    // few seconds (~4.2) checking for any IP addresses to
+                    // arrive and validate. Initiating a (re)evaluation now
+                    // should not significantly alter the validation outcome.
+                    //
+                    // No matter what: enqueue a validation request; one of
+                    // three things can happen with this request:
+                    //     [1] ignored (EvaluatingState or CaptivePortalState)
+                    //     [2] transition to EvaluatingPrivateDnsState
+                    //         (DefaultState and ValidatedState)
+                    //     [3] handled (EvaluatingPrivateDnsState)
+                    //
+                    // The Private DNS configuration to be evaluated will:
+                    //     [1] be skipped (not in strict mode), or
+                    //     [2] validate (huzzah), or
+                    //     [3] encounter some problem (invalid hostname,
+                    //         no resolved IP addresses, IPs unreachable,
+                    //         port 853 unreachable, port 853 is not running a
+                    //         DNS-over-TLS server, et cetera).
+                    sendMessage(CMD_EVALUATE_PRIVATE_DNS);
+                    break;
+                }
+                case EVENT_DNS_NOTIFICATION:
+                    mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1);
+                    break;
+                default:
+                    break;
+            }
+            return HANDLED;
+        }
+    }
+
+    // Being in the ValidatedState State indicates a Network is:
+    // - Successfully validated, or
+    // - Wanted "as is" by the user, or
+    // - Does not satisfy the default NetworkRequest and so validation has been skipped.
+    private class ValidatedState extends State {
+        @Override
+        public void enter() {
+            maybeLogEvaluationResult(
+                    networkEventType(validationStage(), EvaluationResult.VALIDATED));
+            notifyNetworkTested(INetworkMonitor.NETWORK_TEST_RESULT_VALID, null);
+            mValidations++;
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            switch (message.what) {
+                case CMD_NETWORK_CONNECTED:
+                    transitionTo(mValidatedState);
+                    break;
+                case CMD_EVALUATE_PRIVATE_DNS:
+                    transitionTo(mEvaluatingPrivateDnsState);
+                    break;
+                case EVENT_DNS_NOTIFICATION:
+                    mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1);
+                    if (isDataStall()) {
+                        validationLog("Suspecting data stall, reevaluate");
+                        transitionTo(mEvaluatingState);
+                    }
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
+        }
+    }
+
+    // Being in the MaybeNotifyState State indicates the user may have been notified that sign-in
+    // is required.  This State takes care to clear the notification upon exit from the State.
+    private class MaybeNotifyState extends State {
+        @Override
+        public boolean processMessage(Message message) {
+            switch (message.what) {
+                case CMD_LAUNCH_CAPTIVE_PORTAL_APP:
+                    final Intent intent = new Intent(
+                            ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
+                    // OneAddressPerFamilyNetwork is not parcelable across processes.
+                    intent.putExtra(ConnectivityManager.EXTRA_NETWORK, new Network(mNetwork));
+                    intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL,
+                            new CaptivePortal(new ICaptivePortal.Stub() {
+                                @Override
+                                public void appResponse(int response) {
+                                    if (response == APP_RETURN_WANTED_AS_IS) {
+                                        mContext.enforceCallingPermission(
+                                                android.Manifest.permission.CONNECTIVITY_INTERNAL,
+                                                "CaptivePortal");
+                                    }
+                                    sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response);
+                                }
+                            }));
+                    final CaptivePortalProbeResult probeRes = mLastPortalProbeResult;
+                    intent.putExtra(EXTRA_CAPTIVE_PORTAL_URL, probeRes.detectUrl);
+                    if (probeRes.probeSpec != null) {
+                        final String encodedSpec = probeRes.probeSpec.getEncodedSpec();
+                        intent.putExtra(EXTRA_CAPTIVE_PORTAL_PROBE_SPEC, encodedSpec);
+                    }
+                    intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT,
+                            mCaptivePortalUserAgent);
+                    intent.setFlags(
+                            Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
+                    mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+                    return HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+
+        @Override
+        public void exit() {
+            hideProvisioningNotification();
+        }
+    }
+
+    // Being in the EvaluatingState State indicates the Network is being evaluated for internet
+    // connectivity, or that the user has indicated that this network is unwanted.
+    private class EvaluatingState extends State {
+        @Override
+        public void enter() {
+            // If we have already started to track time spent in EvaluatingState
+            // don't reset the timer due simply to, say, commands or events that
+            // cause us to exit and re-enter EvaluatingState.
+            if (!mEvaluationTimer.isStarted()) {
+                mEvaluationTimer.start();
+            }
+            sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
+            if (mUidResponsibleForReeval != INVALID_UID) {
+                TrafficStats.setThreadStatsUid(mUidResponsibleForReeval);
+                mUidResponsibleForReeval = INVALID_UID;
+            }
+            mReevaluateDelayMs = INITIAL_REEVALUATE_DELAY_MS;
+            mEvaluateAttempts = 0;
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            switch (message.what) {
+                case CMD_REEVALUATE:
+                    if (message.arg1 != mReevaluateToken || mUserDoesNotWant) {
+                        return HANDLED;
+                    }
+                    // Don't bother validating networks that don't satisfy the default request.
+                    // This includes:
+                    //  - VPNs which can be considered explicitly desired by the user and the
+                    //    user's desire trumps whether the network validates.
+                    //  - Networks that don't provide Internet access.  It's unclear how to
+                    //    validate such networks.
+                    //  - Untrusted networks.  It's unsafe to prompt the user to sign-in to
+                    //    such networks and the user didn't express interest in connecting to
+                    //    such networks (an app did) so the user may be unhappily surprised when
+                    //    asked to sign-in to a network they didn't want to connect to in the
+                    //    first place.  Validation could be done to adjust the network scores
+                    //    however these networks are app-requested and may not be intended for
+                    //    general usage, in which case general validation may not be an accurate
+                    //    measure of the network's quality.  Only the app knows how to evaluate
+                    //    the network so don't bother validating here.  Furthermore sending HTTP
+                    //    packets over the network may be undesirable, for example an extremely
+                    //    expensive metered network, or unwanted leaking of the User Agent string.
+                    if (!isValidationRequired()) {
+                        validationLog("Network would not satisfy default request, not validating");
+                        transitionTo(mValidatedState);
+                        return HANDLED;
+                    }
+                    mEvaluateAttempts++;
+
+                    transitionTo(mProbingState);
+                    return HANDLED;
+                case CMD_FORCE_REEVALUATION:
+                    // Before IGNORE_REEVALUATE_ATTEMPTS attempts are made,
+                    // ignore any re-evaluation requests. After, restart the
+                    // evaluation process via EvaluatingState#enter.
+                    return (mEvaluateAttempts < IGNORE_REEVALUATE_ATTEMPTS) ? HANDLED : NOT_HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+
+        @Override
+        public void exit() {
+            TrafficStats.clearThreadStatsUid();
+        }
+    }
+
+    // BroadcastReceiver that waits for a particular Intent and then posts a message.
+    private class CustomIntentReceiver extends BroadcastReceiver {
+        private final int mToken;
+        private final int mWhat;
+        private final String mAction;
+        CustomIntentReceiver(String action, int token, int what) {
+            mToken = token;
+            mWhat = what;
+            mAction = action + "_" + mNetwork.getNetworkHandle() + "_" + token;
+            mContext.registerReceiver(this, new IntentFilter(mAction));
+        }
+        public PendingIntent getPendingIntent() {
+            final Intent intent = new Intent(mAction);
+            intent.setPackage(mContext.getPackageName());
+            return PendingIntent.getBroadcast(mContext, 0, intent, 0);
+        }
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(mAction)) sendMessage(obtainMessage(mWhat, mToken));
+        }
+    }
+
+    // Being in the CaptivePortalState State indicates a captive portal was detected and the user
+    // has been shown a notification to sign-in.
+    private class CaptivePortalState extends State {
+        private static final String ACTION_LAUNCH_CAPTIVE_PORTAL_APP =
+                "android.net.netmon.launchCaptivePortalApp";
+
+        @Override
+        public void enter() {
+            maybeLogEvaluationResult(
+                    networkEventType(validationStage(), EvaluationResult.CAPTIVE_PORTAL));
+            // Don't annoy user with sign-in notifications.
+            if (mDontDisplaySigninNotification) return;
+            // Create a CustomIntentReceiver that sends us a
+            // CMD_LAUNCH_CAPTIVE_PORTAL_APP message when the user
+            // touches the notification.
+            if (mLaunchCaptivePortalAppBroadcastReceiver == null) {
+                // Wait for result.
+                mLaunchCaptivePortalAppBroadcastReceiver = new CustomIntentReceiver(
+                        ACTION_LAUNCH_CAPTIVE_PORTAL_APP, new Random().nextInt(),
+                        CMD_LAUNCH_CAPTIVE_PORTAL_APP);
+            }
+            // Display the sign in notification.
+            showProvisioningNotification(mLaunchCaptivePortalAppBroadcastReceiver.mAction);
+            // Retest for captive portal occasionally.
+            sendMessageDelayed(CMD_CAPTIVE_PORTAL_RECHECK, 0 /* no UID */,
+                    CAPTIVE_PORTAL_REEVALUATE_DELAY_MS);
+            mValidations++;
+        }
+
+        @Override
+        public void exit() {
+            removeMessages(CMD_CAPTIVE_PORTAL_RECHECK);
+        }
+    }
+
+    private class EvaluatingPrivateDnsState extends State {
+        private int mPrivateDnsReevalDelayMs;
+        private PrivateDnsConfig mPrivateDnsConfig;
+
+        @Override
+        public void enter() {
+            mPrivateDnsReevalDelayMs = INITIAL_REEVALUATE_DELAY_MS;
+            mPrivateDnsConfig = null;
+            sendMessage(CMD_EVALUATE_PRIVATE_DNS);
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_EVALUATE_PRIVATE_DNS:
+                    if (inStrictMode()) {
+                        if (!isStrictModeHostnameResolved()) {
+                            resolveStrictModeHostname();
+
+                            if (isStrictModeHostnameResolved()) {
+                                notifyPrivateDnsConfigResolved();
+                            } else {
+                                handlePrivateDnsEvaluationFailure();
+                                break;
+                            }
+                        }
+
+                        // Look up a one-time hostname, to bypass caching.
+                        //
+                        // Note that this will race with ConnectivityService
+                        // code programming the DNS-over-TLS server IP addresses
+                        // into netd (if invoked, above). If netd doesn't know
+                        // the IP addresses yet, or if the connections to the IP
+                        // addresses haven't yet been validated, netd will block
+                        // for up to a few seconds before failing the lookup.
+                        if (!sendPrivateDnsProbe()) {
+                            handlePrivateDnsEvaluationFailure();
+                            break;
+                        }
+                    }
+
+                    // All good!
+                    transitionTo(mValidatedState);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
+        }
+
+        private boolean inStrictMode() {
+            return !TextUtils.isEmpty(mPrivateDnsProviderHostname);
+        }
+
+        private boolean isStrictModeHostnameResolved() {
+            return (mPrivateDnsConfig != null)
+                    && mPrivateDnsConfig.hostname.equals(mPrivateDnsProviderHostname)
+                    && (mPrivateDnsConfig.ips.length > 0);
+        }
+
+        private void resolveStrictModeHostname() {
+            try {
+                // Do a blocking DNS resolution using the network-assigned nameservers.
+                final InetAddress[] ips = mNetwork.getAllByName(mPrivateDnsProviderHostname);
+                mPrivateDnsConfig = new PrivateDnsConfig(mPrivateDnsProviderHostname, ips);
+                validationLog("Strict mode hostname resolved: " + mPrivateDnsConfig);
+            } catch (UnknownHostException uhe) {
+                mPrivateDnsConfig = null;
+                validationLog("Strict mode hostname resolution failed: " + uhe.getMessage());
+            }
+        }
+
+        private void notifyPrivateDnsConfigResolved() {
+            try {
+                mCallback.notifyPrivateDnsConfigResolved(mPrivateDnsConfig.toParcel());
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error sending private DNS config resolved notification", e);
+            }
+        }
+
+        private void handlePrivateDnsEvaluationFailure() {
+            notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, null);
+
+            // Queue up a re-evaluation with backoff.
+            //
+            // TODO: Consider abandoning this state after a few attempts and
+            // transitioning back to EvaluatingState, to perhaps give ourselves
+            // the opportunity to (re)detect a captive portal or something.
+            sendMessageDelayed(CMD_EVALUATE_PRIVATE_DNS, mPrivateDnsReevalDelayMs);
+            mPrivateDnsReevalDelayMs *= 2;
+            if (mPrivateDnsReevalDelayMs > MAX_REEVALUATE_DELAY_MS) {
+                mPrivateDnsReevalDelayMs = MAX_REEVALUATE_DELAY_MS;
+            }
+        }
+
+        private boolean sendPrivateDnsProbe() {
+            // q.v. system/netd/server/dns/DnsTlsTransport.cpp
+            final String oneTimeHostnameSuffix = "-dnsotls-ds.metric.gstatic.com";
+            final String host = UUID.randomUUID().toString().substring(0, 8)
+                    + oneTimeHostnameSuffix;
+            final Stopwatch watch = new Stopwatch().start();
+            try {
+                final InetAddress[] ips = mNonPrivateDnsBypassNetwork.getAllByName(host);
+                final long time = watch.stop();
+                final String strIps = Arrays.toString(ips);
+                final boolean success = (ips != null && ips.length > 0);
+                validationLog(PROBE_PRIVDNS, host, String.format("%dms: %s", time, strIps));
+                logValidationProbe(time, PROBE_PRIVDNS, success ? DNS_SUCCESS : DNS_FAILURE);
+                return success;
+            } catch (UnknownHostException uhe) {
+                final long time = watch.stop();
+                validationLog(PROBE_PRIVDNS, host,
+                        String.format("%dms - Error: %s", time, uhe.getMessage()));
+                logValidationProbe(time, PROBE_PRIVDNS, DNS_FAILURE);
+            }
+            return false;
+        }
+    }
+
+    private class ProbingState extends State {
+        private Thread mThread;
+
+        @Override
+        public void enter() {
+            if (mEvaluateAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) {
+                //Don't continue to blame UID forever.
+                TrafficStats.clearThreadStatsUid();
+            }
+
+            final int token = ++mProbeToken;
+            mThread = new Thread(() -> sendMessage(obtainMessage(CMD_PROBE_COMPLETE, token, 0,
+                    isCaptivePortal())));
+            mThread.start();
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            switch (message.what) {
+                case CMD_PROBE_COMPLETE:
+                    // Ensure that CMD_PROBE_COMPLETE from stale threads are ignored.
+                    if (message.arg1 != mProbeToken) {
+                        return HANDLED;
+                    }
+
+                    final CaptivePortalProbeResult probeResult =
+                            (CaptivePortalProbeResult) message.obj;
+                    mLastProbeTime = SystemClock.elapsedRealtime();
+                    if (probeResult.isSuccessful()) {
+                        // Transit EvaluatingPrivateDnsState to get to Validated
+                        // state (even if no Private DNS validation required).
+                        transitionTo(mEvaluatingPrivateDnsState);
+                    } else if (probeResult.isPortal()) {
+                        notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, probeResult.redirectUrl);
+                        mLastPortalProbeResult = probeResult;
+                        transitionTo(mCaptivePortalState);
+                    } else {
+                        logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED);
+                        notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, probeResult.redirectUrl);
+                        transitionTo(mWaitingForNextProbeState);
+                    }
+                    return HANDLED;
+                case EVENT_DNS_NOTIFICATION:
+                    // Leave the event to DefaultState to record correct dns timestamp.
+                    return NOT_HANDLED;
+                default:
+                    // Wait for probe result and defer events to next state by default.
+                    deferMessage(message);
+                    return HANDLED;
+            }
+        }
+
+        @Override
+        public void exit() {
+            if (mThread.isAlive()) {
+                mThread.interrupt();
+            }
+            mThread = null;
+        }
+    }
+
+    // Being in the WaitingForNextProbeState indicates that evaluating probes failed and state is
+    // transited from ProbingState. This ensures that the state machine is only in ProbingState
+    // while a probe is in progress, not while waiting to perform the next probe. That allows
+    // ProbingState to defer most messages until the probe is complete, which keeps the code simple
+    // and matches the pre-Q behaviour where probes were a blocking operation performed on the state
+    // machine thread.
+    private class WaitingForNextProbeState extends State {
+        @Override
+        public void enter() {
+            scheduleNextProbe();
+        }
+
+        private void scheduleNextProbe() {
+            final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
+            sendMessageDelayed(msg, mReevaluateDelayMs);
+            mReevaluateDelayMs *= 2;
+            if (mReevaluateDelayMs > MAX_REEVALUATE_DELAY_MS) {
+                mReevaluateDelayMs = MAX_REEVALUATE_DELAY_MS;
+            }
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            return NOT_HANDLED;
+        }
+    }
+
+    // Limits the list of IP addresses returned by getAllByName or tried by openConnection to at
+    // most one per address family. This ensures we only wait up to 20 seconds for TCP connections
+    // to complete, regardless of how many IP addresses a host has.
+    private static class OneAddressPerFamilyNetwork extends Network {
+        OneAddressPerFamilyNetwork(Network network) {
+            // Always bypass Private DNS.
+            super(network.getPrivateDnsBypassingCopy());
+        }
+
+        @Override
+        public InetAddress[] getAllByName(String host) throws UnknownHostException {
+            final List<InetAddress> addrs = Arrays.asList(super.getAllByName(host));
+
+            // Ensure the address family of the first address is tried first.
+            LinkedHashMap<Class, InetAddress> addressByFamily = new LinkedHashMap<>();
+            addressByFamily.put(addrs.get(0).getClass(), addrs.get(0));
+            Collections.shuffle(addrs);
+
+            for (InetAddress addr : addrs) {
+                addressByFamily.put(addr.getClass(), addr);
+            }
+
+            return addressByFamily.values().toArray(new InetAddress[addressByFamily.size()]);
+        }
+    }
+
+    private boolean getIsCaptivePortalCheckEnabled() {
+        String symbol = Settings.Global.CAPTIVE_PORTAL_MODE;
+        int defaultValue = Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT;
+        int mode = mDependencies.getSetting(mContext, symbol, defaultValue);
+        return mode != Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE;
+    }
+
+    private boolean getUseHttpsValidation() {
+        return mDependencies.getSetting(mContext, Settings.Global.CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
+    }
+
+    private String getCaptivePortalServerHttpsUrl() {
+        return mDependencies.getSetting(mContext,
+                Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL);
+    }
+
+    private int getConsecutiveDnsTimeoutThreshold() {
+        return mDependencies.getSetting(mContext,
+                Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
+                DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD);
+    }
+
+    private int getDataStallMinEvaluateTime() {
+        return mDependencies.getSetting(mContext,
+                Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL,
+                DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS);
+    }
+
+    private int getDataStallValidDnsTimeThreshold() {
+        return mDependencies.getSetting(mContext,
+                Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD,
+                DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS);
+    }
+
+    private int getDataStallEvalutionType() {
+        return mDependencies.getSetting(mContext, Settings.Global.DATA_STALL_EVALUATION_TYPE,
+                DEFAULT_DATA_STALL_EVALUATION_TYPES);
+    }
+
+    private URL[] makeCaptivePortalFallbackUrls() {
+        try {
+            String separator = ",";
+            String firstUrl = mDependencies.getSetting(mContext,
+                    Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
+            String joinedUrls = firstUrl + separator + mDependencies.getSetting(mContext,
+                    Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
+                    DEFAULT_OTHER_FALLBACK_URLS);
+            List<URL> urls = new ArrayList<>();
+            for (String s : joinedUrls.split(separator)) {
+                URL u = makeURL(s);
+                if (u == null) {
+                    continue;
+                }
+                urls.add(u);
+            }
+            if (urls.isEmpty()) {
+                Log.e(TAG, String.format("could not create any url from %s", joinedUrls));
+            }
+            return urls.toArray(new URL[urls.size()]);
+        } catch (Exception e) {
+            // Don't let a misconfiguration bootloop the system.
+            Log.e(TAG, "Error parsing configured fallback URLs", e);
+            return new URL[0];
+        }
+    }
+
+    private CaptivePortalProbeSpec[] makeCaptivePortalFallbackProbeSpecs() {
+        try {
+            final String settingsValue = mDependencies.getSetting(
+                    mContext, Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
+            // Probe specs only used if configured in settings
+            if (TextUtils.isEmpty(settingsValue)) {
+                return null;
+            }
+
+            return CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue);
+        } catch (Exception e) {
+            // Don't let a misconfiguration bootloop the system.
+            Log.e(TAG, "Error parsing configured fallback probe specs", e);
+            return null;
+        }
+    }
+
+    private String getCaptivePortalUserAgent() {
+        return mDependencies.getSetting(mContext,
+                Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
+    }
+
+    private URL nextFallbackUrl() {
+        if (mCaptivePortalFallbackUrls.length == 0) {
+            return null;
+        }
+        int idx = Math.abs(mNextFallbackUrlIndex) % mCaptivePortalFallbackUrls.length;
+        mNextFallbackUrlIndex += mRandom.nextInt(); // randomly change url without memory.
+        return mCaptivePortalFallbackUrls[idx];
+    }
+
+    private CaptivePortalProbeSpec nextFallbackSpec() {
+        if (ArrayUtils.isEmpty(mCaptivePortalFallbackSpecs)) {
+            return null;
+        }
+        // Randomly change spec without memory. Also randomize the first attempt.
+        final int idx = Math.abs(mRandom.nextInt()) % mCaptivePortalFallbackSpecs.length;
+        return mCaptivePortalFallbackSpecs[idx];
+    }
+
+    @VisibleForTesting
+    protected CaptivePortalProbeResult isCaptivePortal() {
+        if (!mIsCaptivePortalCheckEnabled) {
+            validationLog("Validation disabled.");
+            return CaptivePortalProbeResult.SUCCESS;
+        }
+
+        URL pacUrl = null;
+        URL httpsUrl = mCaptivePortalHttpsUrl;
+        URL httpUrl = mCaptivePortalHttpUrl;
+
+        // On networks with a PAC instead of fetching a URL that should result in a 204
+        // response, we instead simply fetch the PAC script.  This is done for a few reasons:
+        // 1. At present our PAC code does not yet handle multiple PACs on multiple networks
+        //    until something like https://android-review.googlesource.com/#/c/115180/ lands.
+        //    Network.openConnection() will ignore network-specific PACs and instead fetch
+        //    using NO_PROXY.  If a PAC is in place, the only fetch we know will succeed with
+        //    NO_PROXY is the fetch of the PAC itself.
+        // 2. To proxy the generate_204 fetch through a PAC would require a number of things
+        //    happen before the fetch can commence, namely:
+        //        a) the PAC script be fetched
+        //        b) a PAC script resolver service be fired up and resolve the captive portal
+        //           server.
+        //    Network validation could be delayed until these prerequisities are satisifed or
+        //    could simply be left to race them.  Neither is an optimal solution.
+        // 3. PAC scripts are sometimes used to block or restrict Internet access and may in
+        //    fact block fetching of the generate_204 URL which would lead to false negative
+        //    results for network validation.
+        final ProxyInfo proxyInfo = mLinkProperties.getHttpProxy();
+        if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) {
+            pacUrl = makeURL(proxyInfo.getPacFileUrl().toString());
+            if (pacUrl == null) {
+                return CaptivePortalProbeResult.FAILED;
+            }
+        }
+
+        if ((pacUrl == null) && (httpUrl == null || httpsUrl == null)) {
+            return CaptivePortalProbeResult.FAILED;
+        }
+
+        long startTime = SystemClock.elapsedRealtime();
+
+        final CaptivePortalProbeResult result;
+        if (pacUrl != null) {
+            result = sendDnsAndHttpProbes(null, pacUrl, ValidationProbeEvent.PROBE_PAC);
+        } else if (mUseHttps) {
+            result = sendParallelHttpProbes(proxyInfo, httpsUrl, httpUrl);
+        } else {
+            result = sendDnsAndHttpProbes(proxyInfo, httpUrl, ValidationProbeEvent.PROBE_HTTP);
+        }
+
+        long endTime = SystemClock.elapsedRealtime();
+
+        sendNetworkConditionsBroadcast(true /* response received */,
+                result.isPortal() /* isCaptivePortal */,
+                startTime, endTime);
+
+        log("isCaptivePortal: isSuccessful()=" + result.isSuccessful()
+                + " isPortal()=" + result.isPortal()
+                + " RedirectUrl=" + result.redirectUrl
+                + " Time=" + (endTime - startTime) + "ms");
+
+        return result;
+    }
+
+    /**
+     * Do a DNS resolution and URL fetch on a known web server to see if we get the data we expect.
+     * @return a CaptivePortalProbeResult inferred from the HTTP response.
+     */
+    private CaptivePortalProbeResult sendDnsAndHttpProbes(ProxyInfo proxy, URL url, int probeType) {
+        // Pre-resolve the captive portal server host so we can log it.
+        // Only do this if HttpURLConnection is about to, to avoid any potentially
+        // unnecessary resolution.
+        final String host = (proxy != null) ? proxy.getHost() : url.getHost();
+        sendDnsProbe(host);
+        return sendHttpProbe(url, probeType, null);
+    }
+
+    /** Do a DNS resolution of the given server. */
+    private void sendDnsProbe(String host) {
+        if (TextUtils.isEmpty(host)) {
+            return;
+        }
+
+        final String name = ValidationProbeEvent.getProbeName(ValidationProbeEvent.PROBE_DNS);
+        final Stopwatch watch = new Stopwatch().start();
+        int result;
+        String connectInfo;
+        try {
+            InetAddress[] addresses = mNetwork.getAllByName(host);
+            StringBuffer buffer = new StringBuffer();
+            for (InetAddress address : addresses) {
+                buffer.append(',').append(address.getHostAddress());
+            }
+            result = ValidationProbeEvent.DNS_SUCCESS;
+            connectInfo = "OK " + buffer.substring(1);
+        } catch (UnknownHostException e) {
+            result = ValidationProbeEvent.DNS_FAILURE;
+            connectInfo = "FAIL";
+        }
+        final long latency = watch.stop();
+        validationLog(ValidationProbeEvent.PROBE_DNS, host,
+                String.format("%dms %s", latency, connectInfo));
+        logValidationProbe(latency, ValidationProbeEvent.PROBE_DNS, result);
+    }
+
+    /**
+     * Do a URL fetch on a known web server to see if we get the data we expect.
+     * @return a CaptivePortalProbeResult inferred from the HTTP response.
+     */
+    @VisibleForTesting
+    protected CaptivePortalProbeResult sendHttpProbe(URL url, int probeType,
+            @Nullable CaptivePortalProbeSpec probeSpec) {
+        HttpURLConnection urlConnection = null;
+        int httpResponseCode = CaptivePortalProbeResult.FAILED_CODE;
+        String redirectUrl = null;
+        final Stopwatch probeTimer = new Stopwatch().start();
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
+        try {
+            urlConnection = (HttpURLConnection) mNetwork.openConnection(url);
+            urlConnection.setInstanceFollowRedirects(probeType == ValidationProbeEvent.PROBE_PAC);
+            urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
+            urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
+            urlConnection.setUseCaches(false);
+            if (mCaptivePortalUserAgent != null) {
+                urlConnection.setRequestProperty("User-Agent", mCaptivePortalUserAgent);
+            }
+            // cannot read request header after connection
+            String requestHeader = urlConnection.getRequestProperties().toString();
+
+            // Time how long it takes to get a response to our request
+            long requestTimestamp = SystemClock.elapsedRealtime();
+
+            httpResponseCode = urlConnection.getResponseCode();
+            redirectUrl = urlConnection.getHeaderField("location");
+
+            // Time how long it takes to get a response to our request
+            long responseTimestamp = SystemClock.elapsedRealtime();
+
+            validationLog(probeType, url, "time=" + (responseTimestamp - requestTimestamp) + "ms"
+                    + " ret=" + httpResponseCode
+                    + " request=" + requestHeader
+                    + " headers=" + urlConnection.getHeaderFields());
+            // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive
+            // portal.  The only example of this seen so far was a captive portal.  For
+            // the time being go with prior behavior of assuming it's not a captive
+            // portal.  If it is considered a captive portal, a different sign-in URL
+            // is needed (i.e. can't browse a 204).  This could be the result of an HTTP
+            // proxy server.
+            if (httpResponseCode == 200) {
+                if (probeType == ValidationProbeEvent.PROBE_PAC) {
+                    validationLog(
+                            probeType, url, "PAC fetch 200 response interpreted as 204 response.");
+                    httpResponseCode = CaptivePortalProbeResult.SUCCESS_CODE;
+                } else if (urlConnection.getContentLengthLong() == 0) {
+                    // Consider 200 response with "Content-length=0" to not be a captive portal.
+                    // There's no point in considering this a captive portal as the user cannot
+                    // sign-in to an empty page. Probably the result of a broken transparent proxy.
+                    // See http://b/9972012.
+                    validationLog(probeType, url,
+                            "200 response with Content-length=0 interpreted as 204 response.");
+                    httpResponseCode = CaptivePortalProbeResult.SUCCESS_CODE;
+                } else if (urlConnection.getContentLengthLong() == -1) {
+                    // When no Content-length (default value == -1), attempt to read a byte from the
+                    // response. Do not use available() as it is unreliable. See http://b/33498325.
+                    if (urlConnection.getInputStream().read() == -1) {
+                        validationLog(
+                                probeType, url, "Empty 200 response interpreted as 204 response.");
+                        httpResponseCode = CaptivePortalProbeResult.SUCCESS_CODE;
+                    }
+                }
+            }
+        } catch (IOException e) {
+            validationLog(probeType, url, "Probe failed with exception " + e);
+            if (httpResponseCode == CaptivePortalProbeResult.FAILED_CODE) {
+                // TODO: Ping gateway and DNS server and log results.
+            }
+        } finally {
+            if (urlConnection != null) {
+                urlConnection.disconnect();
+            }
+            TrafficStats.setThreadStatsTag(oldTag);
+        }
+        logValidationProbe(probeTimer.stop(), probeType, httpResponseCode);
+
+        if (probeSpec == null) {
+            return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, url.toString());
+        } else {
+            return probeSpec.getResult(httpResponseCode, redirectUrl);
+        }
+    }
+
+    private CaptivePortalProbeResult sendParallelHttpProbes(
+            ProxyInfo proxy, URL httpsUrl, URL httpUrl) {
+        // Number of probes to wait for. If a probe completes with a conclusive answer
+        // it shortcuts the latch immediately by forcing the count to 0.
+        final CountDownLatch latch = new CountDownLatch(2);
+
+        final class ProbeThread extends Thread {
+            private final boolean mIsHttps;
+            private volatile CaptivePortalProbeResult mResult = CaptivePortalProbeResult.FAILED;
+
+            ProbeThread(boolean isHttps) {
+                mIsHttps = isHttps;
+            }
+
+            public CaptivePortalProbeResult result() {
+                return mResult;
+            }
+
+            @Override
+            public void run() {
+                if (mIsHttps) {
+                    mResult =
+                            sendDnsAndHttpProbes(proxy, httpsUrl, ValidationProbeEvent.PROBE_HTTPS);
+                } else {
+                    mResult = sendDnsAndHttpProbes(proxy, httpUrl, ValidationProbeEvent.PROBE_HTTP);
+                }
+                if ((mIsHttps && mResult.isSuccessful()) || (!mIsHttps && mResult.isPortal())) {
+                    // Stop waiting immediately if https succeeds or if http finds a portal.
+                    while (latch.getCount() > 0) {
+                        latch.countDown();
+                    }
+                }
+                // Signal this probe has completed.
+                latch.countDown();
+            }
+        }
+
+        final ProbeThread httpsProbe = new ProbeThread(true);
+        final ProbeThread httpProbe = new ProbeThread(false);
+
+        try {
+            httpsProbe.start();
+            httpProbe.start();
+            latch.await(PROBE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            validationLog("Error: probes wait interrupted!");
+            return CaptivePortalProbeResult.FAILED;
+        }
+
+        final CaptivePortalProbeResult httpsResult = httpsProbe.result();
+        final CaptivePortalProbeResult httpResult = httpProbe.result();
+
+        // Look for a conclusive probe result first.
+        if (httpResult.isPortal()) {
+            return httpResult;
+        }
+        // httpsResult.isPortal() is not expected, but check it nonetheless.
+        if (httpsResult.isPortal() || httpsResult.isSuccessful()) {
+            return httpsResult;
+        }
+        // If a fallback method exists, use it to retry portal detection.
+        // If we have new-style probe specs, use those. Otherwise, use the fallback URLs.
+        final CaptivePortalProbeSpec probeSpec = nextFallbackSpec();
+        final URL fallbackUrl = (probeSpec != null) ? probeSpec.getUrl() : nextFallbackUrl();
+        if (fallbackUrl != null) {
+            CaptivePortalProbeResult result = sendHttpProbe(fallbackUrl, PROBE_FALLBACK, probeSpec);
+            if (result.isPortal()) {
+                return result;
+            }
+        }
+        // Otherwise wait until http and https probes completes and use their results.
+        try {
+            httpProbe.join();
+            if (httpProbe.result().isPortal()) {
+                return httpProbe.result();
+            }
+            httpsProbe.join();
+            return httpsProbe.result();
+        } catch (InterruptedException e) {
+            validationLog("Error: http or https probe wait interrupted!");
+            return CaptivePortalProbeResult.FAILED;
+        }
+    }
+
+    private URL makeURL(String url) {
+        if (url != null) {
+            try {
+                return new URL(url);
+            } catch (MalformedURLException e) {
+                validationLog("Bad URL: " + url);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @param responseReceived - whether or not we received a valid HTTP response to our request.
+     * If false, isCaptivePortal and responseTimestampMs are ignored
+     * TODO: This should be moved to the transports.  The latency could be passed to the transports
+     * along with the captive portal result.  Currently the TYPE_MOBILE broadcasts appear unused so
+     * perhaps this could just be added to the WiFi transport only.
+     */
+    private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal,
+            long requestTimestampMs, long responseTimestampMs) {
+        if (!mWifiManager.isScanAlwaysAvailable()) {
+            return;
+        }
+
+        if (!mSystemReady) {
+            return;
+        }
+
+        Intent latencyBroadcast =
+                new Intent(NetworkMonitorUtils.ACTION_NETWORK_CONDITIONS_MEASURED);
+        if (mNetworkCapabilities.hasTransport(TRANSPORT_WIFI)) {
+            WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
+            if (currentWifiInfo != null) {
+                // NOTE: getSSID()'s behavior changed in API 17; before that, SSIDs were not
+                // surrounded by double quotation marks (thus violating the Javadoc), but this
+                // was changed to match the Javadoc in API 17. Since clients may have started
+                // sanitizing the output of this method since API 17 was released, we should
+                // not change it here as it would become impossible to tell whether the SSID is
+                // simply being surrounded by quotes due to the API, or whether those quotes
+                // are actually part of the SSID.
+                latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_SSID,
+                        currentWifiInfo.getSSID());
+                latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_BSSID,
+                        currentWifiInfo.getBSSID());
+            } else {
+                if (VDBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
+                return;
+            }
+            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CONNECTIVITY_TYPE, TYPE_WIFI);
+        } else if (mNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_NETWORK_TYPE,
+                    mTelephonyManager.getNetworkType());
+            List<CellInfo> info = mTelephonyManager.getAllCellInfo();
+            if (info == null) return;
+            int numRegisteredCellInfo = 0;
+            for (CellInfo cellInfo : info) {
+                if (cellInfo.isRegistered()) {
+                    numRegisteredCellInfo++;
+                    if (numRegisteredCellInfo > 1) {
+                        if (VDBG) {
+                            logw("more than one registered CellInfo."
+                                    + " Can't tell which is active.  Bailing.");
+                        }
+                        return;
+                    }
+                    if (cellInfo instanceof CellInfoCdma) {
+                        CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
+                        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CELL_ID, cellId);
+                    } else if (cellInfo instanceof CellInfoGsm) {
+                        CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
+                        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CELL_ID, cellId);
+                    } else if (cellInfo instanceof CellInfoLte) {
+                        CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity();
+                        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CELL_ID, cellId);
+                    } else if (cellInfo instanceof CellInfoWcdma) {
+                        CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
+                        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CELL_ID, cellId);
+                    } else {
+                        if (VDBG) logw("Registered cellinfo is unrecognized");
+                        return;
+                    }
+                }
+            }
+            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CONNECTIVITY_TYPE, TYPE_MOBILE);
+        } else {
+            return;
+        }
+        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_RESPONSE_RECEIVED,
+                responseReceived);
+        latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_REQUEST_TIMESTAMP_MS,
+                requestTimestampMs);
+
+        if (responseReceived) {
+            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_IS_CAPTIVE_PORTAL,
+                    isCaptivePortal);
+            latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_RESPONSE_TIMESTAMP_MS,
+                    responseTimestampMs);
+        }
+        mContext.sendBroadcastAsUser(latencyBroadcast, UserHandle.CURRENT,
+                NetworkMonitorUtils.PERMISSION_ACCESS_NETWORK_CONDITIONS);
+    }
+
+    private void logNetworkEvent(int evtype) {
+        int[] transports = mNetworkCapabilities.getTransportTypes();
+        mMetricsLog.log(mNetwork, transports, new NetworkEvent(evtype));
+    }
+
+    private int networkEventType(ValidationStage s, EvaluationResult r) {
+        if (s.mIsFirstValidation) {
+            if (r.mIsValidated) {
+                return NetworkEvent.NETWORK_FIRST_VALIDATION_SUCCESS;
+            } else {
+                return NetworkEvent.NETWORK_FIRST_VALIDATION_PORTAL_FOUND;
+            }
+        } else {
+            if (r.mIsValidated) {
+                return NetworkEvent.NETWORK_REVALIDATION_SUCCESS;
+            } else {
+                return NetworkEvent.NETWORK_REVALIDATION_PORTAL_FOUND;
+            }
+        }
+    }
+
+    private void maybeLogEvaluationResult(int evtype) {
+        if (mEvaluationTimer.isRunning()) {
+            int[] transports = mNetworkCapabilities.getTransportTypes();
+            mMetricsLog.log(mNetwork, transports,
+                    new NetworkEvent(evtype, mEvaluationTimer.stop()));
+            mEvaluationTimer.reset();
+        }
+    }
+
+    private void logValidationProbe(long durationMs, int probeType, int probeResult) {
+        int[] transports = mNetworkCapabilities.getTransportTypes();
+        boolean isFirstValidation = validationStage().mIsFirstValidation;
+        ValidationProbeEvent ev = new ValidationProbeEvent.Builder()
+                .setProbeType(probeType, isFirstValidation)
+                .setReturnCode(probeResult)
+                .setDurationMs(durationMs)
+                .build();
+        mMetricsLog.log(mNetwork, transports, ev);
+    }
+
+    @VisibleForTesting
+    static class Dependencies {
+        public Network getPrivateDnsBypassNetwork(Network network) {
+            return new OneAddressPerFamilyNetwork(network);
+        }
+
+        public Random getRandom() {
+            return new Random();
+        }
+
+        /**
+         * Get the captive portal server HTTP URL that is configured on the device.
+         */
+        public String getCaptivePortalServerHttpUrl(Context context) {
+            return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(context);
+        }
+
+        /**
+         * Get the value of a global integer setting.
+         * @param symbol Name of the setting
+         * @param defaultValue Value to return if the setting is not defined.
+         */
+        public int getSetting(Context context, String symbol, int defaultValue) {
+            return Settings.Global.getInt(context.getContentResolver(), symbol, defaultValue);
+        }
+
+        /**
+         * Get the value of a global String setting.
+         * @param symbol Name of the setting
+         * @param defaultValue Value to return if the setting is not defined.
+         */
+        public String getSetting(Context context, String symbol, String defaultValue) {
+            final String value = Settings.Global.getString(context.getContentResolver(), symbol);
+            return value != null ? value : defaultValue;
+        }
+
+        public static final Dependencies DEFAULT = new Dependencies();
+    }
+
+    /**
+     * Methods in this class perform no locking because all accesses are performed on the state
+     * machine's thread. Need to consider the thread safety if it ever could be accessed outside the
+     * state machine.
+     */
+    @VisibleForTesting
+    protected class DnsStallDetector {
+        private static final int DEFAULT_DNS_LOG_SIZE = 50;
+        private int mConsecutiveTimeoutCount = 0;
+        private int mSize;
+        final DnsResult[] mDnsEvents;
+        final RingBufferIndices mResultIndices;
+
+        DnsStallDetector(int size) {
+            mSize = Math.max(DEFAULT_DNS_LOG_SIZE, size);
+            mDnsEvents = new DnsResult[mSize];
+            mResultIndices = new RingBufferIndices(mSize);
+        }
+
+        @VisibleForTesting
+        protected void accumulateConsecutiveDnsTimeoutCount(int code) {
+            final DnsResult result = new DnsResult(code);
+            mDnsEvents[mResultIndices.add()] = result;
+            if (result.isTimeout()) {
+                mConsecutiveTimeoutCount++;
+            } else {
+                // Keep the event in mDnsEvents without clearing it so that there are logs to do the
+                // simulation and analysis.
+                mConsecutiveTimeoutCount = 0;
+            }
+        }
+
+        private boolean isDataStallSuspected(int timeoutCountThreshold, int validTime) {
+            if (timeoutCountThreshold <= 0) {
+                Log.wtf(TAG, "Timeout count threshold should be larger than 0.");
+                return false;
+            }
+
+            // Check if the consecutive timeout count reach the threshold or not.
+            if (mConsecutiveTimeoutCount < timeoutCountThreshold) {
+                return false;
+            }
+
+            // Check if the target dns event index is valid or not.
+            final int firstConsecutiveTimeoutIndex =
+                    mResultIndices.indexOf(mResultIndices.size() - timeoutCountThreshold);
+
+            // If the dns timeout events happened long time ago, the events are meaningless for
+            // data stall evaluation. Thus, check if the first consecutive timeout dns event
+            // considered in the evaluation happened in defined threshold time.
+            final long now = SystemClock.elapsedRealtime();
+            final long firstTimeoutTime = now - mDnsEvents[firstConsecutiveTimeoutIndex].mTimeStamp;
+            return (firstTimeoutTime < validTime);
+        }
+
+        int getConsecutiveTimeoutCount() {
+            return mConsecutiveTimeoutCount;
+        }
+    }
+
+    private static class DnsResult {
+        // TODO: Need to move the DNS return code definition to a specific class once unify DNS
+        // response code is done.
+        private static final int RETURN_CODE_DNS_TIMEOUT = 255;
+
+        private final long mTimeStamp;
+        private final int mReturnCode;
+
+        DnsResult(int code) {
+            mTimeStamp = SystemClock.elapsedRealtime();
+            mReturnCode = code;
+        }
+
+        private boolean isTimeout() {
+            return mReturnCode == RETURN_CODE_DNS_TIMEOUT;
+        }
+    }
+
+
+    @VisibleForTesting
+    protected DnsStallDetector getDnsStallDetector() {
+        return mDnsStallDetector;
+    }
+
+    private boolean dataStallEvaluateTypeEnabled(int type) {
+        return (mDataStallEvaluationType & (1 << type)) != 0;
+    }
+
+    @VisibleForTesting
+    protected long getLastProbeTime() {
+        return mLastProbeTime;
+    }
+
+    @VisibleForTesting
+    protected boolean isDataStall() {
+        boolean result = false;
+        // Reevaluation will generate traffic. Thus, set a minimal reevaluation timer to limit the
+        // possible traffic cost in metered network.
+        if (!mNetworkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)
+                && (SystemClock.elapsedRealtime() - getLastProbeTime()
+                < mDataStallMinEvaluateTime)) {
+            return false;
+        }
+
+        // Check dns signal. Suspect it may be a data stall if both :
+        // 1. The number of consecutive DNS query timeouts > mConsecutiveDnsTimeoutThreshold.
+        // 2. Those consecutive DNS queries happened in the last mValidDataStallDnsTimeThreshold ms.
+        if (dataStallEvaluateTypeEnabled(DATA_STALL_EVALUATION_TYPE_DNS)) {
+            if (mDnsStallDetector.isDataStallSuspected(mConsecutiveDnsTimeoutThreshold,
+                    mDataStallValidDnsTimeThreshold)) {
+                result = true;
+                logNetworkEvent(NetworkEvent.NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND);
+            }
+        }
+
+        if (VDBG_STALL) {
+            log("isDataStall: result=" + result + ", consecutive dns timeout count="
+                    + mDnsStallDetector.getConsecutiveTimeoutCount());
+        }
+
+        return result;
+    }
+}
diff --git a/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java b/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java
new file mode 100644
index 0000000..eedaf30
--- /dev/null
+++ b/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.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 com.android.server.util;
+
+/**
+ * Network constants used by the network stack.
+ */
+public final class NetworkStackConstants {
+
+    /**
+     * IPv4 constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc791
+     */
+    public static final int IPV4_ADDR_BITS = 32;
+    public static final int IPV4_MIN_MTU = 68;
+    public static final int IPV4_MAX_MTU = 65_535;
+
+    /**
+     * Ethernet constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc894
+     *     - https://tools.ietf.org/html/rfc2464
+     *     - https://tools.ietf.org/html/rfc7042
+     *     - http://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml
+     *     - http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml
+     */
+    public static final int ETHER_DST_ADDR_OFFSET = 0;
+    public static final int ETHER_SRC_ADDR_OFFSET = 6;
+    public static final int ETHER_ADDR_LEN = 6;
+    public static final int ETHER_TYPE_OFFSET = 12;
+    public static final int ETHER_TYPE_LENGTH = 2;
+    public static final int ETHER_TYPE_ARP  = 0x0806;
+    public static final int ETHER_TYPE_IPV4 = 0x0800;
+    public static final int ETHER_TYPE_IPV6 = 0x86dd;
+    public static final int ETHER_HEADER_LEN = 14;
+
+    /**
+     * ARP constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc826
+     *     - http://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml
+     */
+    public static final int ARP_PAYLOAD_LEN = 28;  // For Ethernet+IPv4.
+    public static final int ARP_REQUEST = 1;
+    public static final int ARP_REPLY   = 2;
+    public static final int ARP_HWTYPE_RESERVED_LO = 0;
+    public static final int ARP_HWTYPE_ETHER       = 1;
+    public static final int ARP_HWTYPE_RESERVED_HI = 0xffff;
+
+    /**
+     * IPv4 constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc791
+     */
+    public static final int IPV4_HEADER_MIN_LEN = 20;
+    public static final int IPV4_IHL_MASK = 0xf;
+    public static final int IPV4_FLAGS_OFFSET = 6;
+    public static final int IPV4_FRAGMENT_MASK = 0x1fff;
+    public static final int IPV4_PROTOCOL_OFFSET = 9;
+    public static final int IPV4_SRC_ADDR_OFFSET = 12;
+    public static final int IPV4_DST_ADDR_OFFSET = 16;
+    public static final int IPV4_ADDR_LEN = 4;
+
+    /**
+     * IPv6 constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc2460
+     */
+    public static final int IPV6_ADDR_LEN = 16;
+    public static final int IPV6_HEADER_LEN = 40;
+    public static final int IPV6_PROTOCOL_OFFSET = 6;
+    public static final int IPV6_SRC_ADDR_OFFSET = 8;
+    public static final int IPV6_DST_ADDR_OFFSET = 24;
+
+    /**
+     * ICMPv6 constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc4443
+     *     - https://tools.ietf.org/html/rfc4861
+     */
+    public static final int ICMPV6_HEADER_MIN_LEN = 4;
+    public static final int ICMPV6_ECHO_REPLY_TYPE = 129;
+    public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
+    public static final int ICMPV6_ROUTER_SOLICITATION    = 133;
+    public static final int ICMPV6_ROUTER_ADVERTISEMENT   = 134;
+    public static final int ICMPV6_NEIGHBOR_SOLICITATION  = 135;
+    public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136;
+    public static final int ICMPV6_ND_OPTION_MIN_LENGTH = 8;
+    public static final int ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR = 8;
+    public static final int ICMPV6_ND_OPTION_SLLA = 1;
+    public static final int ICMPV6_ND_OPTION_TLLA = 2;
+    public static final int ICMPV6_ND_OPTION_MTU  = 5;
+
+    /**
+     * UDP constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc768
+     */
+    public static final int UDP_HEADER_LEN = 8;
+
+
+    /**
+     * DHCP constants.
+     *
+     * See also:
+     *     - https://tools.ietf.org/html/rfc2131
+     */
+    public static final int INFINITE_LEASE = 0xffffffff;
+    public static final int DHCP4_CLIENT_PORT = 68;
+
+    private NetworkStackConstants() {
+        throw new UnsupportedOperationException("This class is not to be instantiated");
+    }
+}
diff --git a/packages/NetworkStack/src/com/android/server/util/PermissionUtil.java b/packages/NetworkStack/src/com/android/server/util/PermissionUtil.java
new file mode 100644
index 0000000..82bf038
--- /dev/null
+++ b/packages/NetworkStack/src/com/android/server/util/PermissionUtil.java
@@ -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.
+ */
+
+package com.android.server.util;
+
+import static android.os.Binder.getCallingUid;
+
+import android.os.Process;
+
+/**
+ * Utility class to check calling permissions on the network stack.
+ */
+public final class PermissionUtil {
+
+    /**
+     * Check that the caller is allowed to communicate with the network stack.
+     * @throws SecurityException The caller is not allowed to communicate with the network stack.
+     */
+    public static void checkNetworkStackCallingPermission() {
+        // TODO: check that the calling PID is the system server.
+        final int caller = getCallingUid();
+        if (caller != Process.SYSTEM_UID && caller != Process.BLUETOOTH_UID) {
+            throw new SecurityException("Invalid caller: " + caller);
+        }
+    }
+
+    /**
+     * Check that the caller is allowed to dump the network stack, e.g. dumpsys.
+     * @throws SecurityException The caller is not allowed to dump the network stack.
+     */
+    public static void checkDumpPermission() {
+        final int caller = getCallingUid();
+        if (caller != Process.SYSTEM_UID && caller != Process.ROOT_UID
+                && caller != Process.SHELL_UID) {
+            throw new SecurityException("No dump permissions for caller: " + caller);
+        }
+    }
+
+    private PermissionUtil() {
+        throw new UnsupportedOperationException("This class is not to be instantiated");
+    }
+}
diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp
new file mode 100644
index 0000000..45fa2dc
--- /dev/null
+++ b/packages/NetworkStack/tests/Android.bp
@@ -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.
+//
+
+android_test {
+    name: "NetworkStackTests",
+    certificate: "platform",
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+    static_libs: [
+        "android-support-test",
+        "frameworks-base-testutils",
+        "mockito-target-extended-minus-junit4",
+        "NetworkStackLib",
+        "testables",
+    ],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+        "android.test.mock",
+    ],
+    jni_libs: [
+        // For mockito extended
+        "libdexmakerjvmtiagent",
+        "libstaticjvmtiagent",
+        // For ApfTest
+        "libartbase",
+        "libbacktrace",
+        "libbase",
+        "libbinder",
+        "libbinderthreadstate",
+        "libc++",
+        "libcrypto",
+        "libcutils",
+        "libdexfile",
+        "libhidl-gen-utils",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "liblzma",
+        "libnativehelper",
+        "libnetworkstacktestsjni",
+        "libpackagelistparser",
+        "libpcre2",
+        "libprocessgroup",
+        "libselinux",
+        "libui",
+        "libutils",
+        "libvintf",
+        "libvndksupport",
+        "libtinyxml2",
+        "libunwindstack",
+        "libutilscallstack",
+        "libziparchive",
+        "libz",
+        "netd_aidl_interface-cpp",
+    ],
+}
+
+cc_library_shared {
+    name: "libnetworkstacktestsjni",
+    srcs: [
+        "jni/**/*.cpp"
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    include_dirs: [
+        "hardware/google/apf",
+    ],
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libcutils",
+        "libnativehelper",
+        "netd_aidl_interface-cpp",
+    ],
+    static_libs: [
+        "libapf",
+        "libpcap",
+    ],
+
+}
diff --git a/packages/NetworkStack/tests/AndroidManifest.xml b/packages/NetworkStack/tests/AndroidManifest.xml
new file mode 100644
index 0000000..9cb2c21
--- /dev/null
+++ b/packages/NetworkStack/tests/AndroidManifest.xml
@@ -0,0 +1,54 @@
+<?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.server.networkstack.tests">
+
+    <uses-permission android:name="android.permission.READ_LOGS" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+    <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+    <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
+    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+    <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
+    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
+    <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 android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.server.networkstack.tests"
+        android:label="Networking service tests">
+    </instrumentation>
+</manifest>
\ No newline at end of file
diff --git a/packages/NetworkStack/tests/AndroidTest.xml b/packages/NetworkStack/tests/AndroidTest.xml
new file mode 100644
index 0000000..6b08b57
--- /dev/null
+++ b/packages/NetworkStack/tests/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<configuration description="Runs Tests for NetworkStack">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="NetworkStackTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="framework-base-presubmit" />
+    <option name="test-tag" value="NetworkStackTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.server.networkstack.tests" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/net/jni/apf_jni.cpp b/packages/NetworkStack/tests/jni/apf_jni.cpp
similarity index 100%
rename from tests/net/jni/apf_jni.cpp
rename to packages/NetworkStack/tests/jni/apf_jni.cpp
diff --git a/tests/net/res/raw/apf.pcap b/packages/NetworkStack/tests/res/raw/apf.pcap
similarity index 100%
rename from tests/net/res/raw/apf.pcap
rename to packages/NetworkStack/tests/res/raw/apf.pcap
Binary files differ
diff --git a/tests/net/res/raw/apfPcap.pcap b/packages/NetworkStack/tests/res/raw/apfPcap.pcap
similarity index 100%
rename from tests/net/res/raw/apfPcap.pcap
rename to packages/NetworkStack/tests/res/raw/apfPcap.pcap
Binary files differ
diff --git a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
new file mode 100644
index 0000000..f76e412
--- /dev/null
+++ b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
@@ -0,0 +1,1802 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.apf;
+
+import static android.system.OsConstants.AF_UNIX;
+import static android.system.OsConstants.ARPHRD_ETHER;
+import static android.system.OsConstants.ETH_P_ARP;
+import static android.system.OsConstants.ETH_P_IP;
+import static android.system.OsConstants.ETH_P_IPV6;
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.SOCK_STREAM;
+
+import static com.android.internal.util.BitUtils.bytesToBEInt;
+import static com.android.server.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.apf.ApfFilter.ApfConfiguration;
+import android.net.apf.ApfGenerator.IllegalInstructionException;
+import android.net.apf.ApfGenerator.Register;
+import android.net.ip.IIpClientCallbacks;
+import android.net.ip.IpClient;
+import android.net.ip.IpClient.IpClientCallbacksWrapper;
+import android.net.ip.IpClientCallbacks;
+import android.net.metrics.IpConnectivityLog;
+import android.net.metrics.RaEvent;
+import android.net.util.InterfaceParams;
+import android.net.util.SharedLog;
+import android.os.ConditionVariable;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.text.format.DateUtils;
+import android.util.Log;
+
+import com.android.internal.util.HexDump;
+import com.android.server.networkstack.tests.R;
+import com.android.server.util.NetworkStackConstants;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Tests for APF program generator and interpreter.
+ *
+ * Build, install and run with:
+ *  runtest frameworks-net -c android.net.apf.ApfTest
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ApfTest {
+    private static final int TIMEOUT_MS = 500;
+    private static final int MIN_APF_VERSION = 2;
+
+    @Mock IpConnectivityLog mLog;
+    @Mock Context mContext;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        // Load up native shared library containing APF interpreter exposed via JNI.
+        System.loadLibrary("networkstacktestsjni");
+    }
+
+    private static final String TAG = "ApfTest";
+    // Expected return codes from APF interpreter.
+    private static final int PASS = 1;
+    private static final int DROP = 0;
+    // Interpreter will just accept packets without link layer headers, so pad fake packet to at
+    // least the minimum packet size.
+    private static final int MIN_PKT_SIZE = 15;
+
+    private static final ApfCapabilities MOCK_APF_CAPABILITIES =
+      new ApfCapabilities(2, 1700, ARPHRD_ETHER);
+
+    private static final boolean DROP_MULTICAST = true;
+    private static final boolean ALLOW_MULTICAST = false;
+
+    private static final boolean DROP_802_3_FRAMES = true;
+    private static final boolean ALLOW_802_3_FRAMES = false;
+
+    // Constants for opcode encoding
+    private static final byte LI_OP   = (byte)(13 << 3);
+    private static final byte LDDW_OP = (byte)(22 << 3);
+    private static final byte STDW_OP = (byte)(23 << 3);
+    private static final byte SIZE0   = (byte)(0 << 1);
+    private static final byte SIZE8   = (byte)(1 << 1);
+    private static final byte SIZE16  = (byte)(2 << 1);
+    private static final byte SIZE32  = (byte)(3 << 1);
+    private static final byte R1 = 1;
+
+    private static ApfConfiguration getDefaultConfig() {
+        ApfFilter.ApfConfiguration config = new ApfConfiguration();
+        config.apfCapabilities = MOCK_APF_CAPABILITIES;
+        config.multicastFilter = ALLOW_MULTICAST;
+        config.ieee802_3Filter = ALLOW_802_3_FRAMES;
+        config.ethTypeBlackList = new int[0];
+        return config;
+    }
+
+    private static String label(int code) {
+        switch (code) {
+            case PASS: return "PASS";
+            case DROP: return "DROP";
+            default:   return "UNKNOWN";
+        }
+    }
+
+    private static void assertReturnCodesEqual(int expected, int got) {
+        assertEquals(label(expected), label(got));
+    }
+
+    private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
+        assertReturnCodesEqual(expected, apfSimulate(program, packet, null, filterAge));
+    }
+
+    private void assertVerdict(int expected, byte[] program, byte[] packet) {
+        assertReturnCodesEqual(expected, apfSimulate(program, packet, null, 0));
+    }
+
+    private void assertPass(byte[] program, byte[] packet, int filterAge) {
+        assertVerdict(PASS, program, packet, filterAge);
+    }
+
+    private void assertPass(byte[] program, byte[] packet) {
+        assertVerdict(PASS, program, packet);
+    }
+
+    private void assertDrop(byte[] program, byte[] packet, int filterAge) {
+        assertVerdict(DROP, program, packet, filterAge);
+    }
+
+    private void assertDrop(byte[] program, byte[] packet) {
+        assertVerdict(DROP, program, packet);
+    }
+
+    private void assertProgramEquals(byte[] expected, byte[] program) throws AssertionError {
+        // assertArrayEquals() would only print one byte, making debugging difficult.
+        if (!java.util.Arrays.equals(expected, program)) {
+            throw new AssertionError(
+                    "\nexpected: " + HexDump.toHexString(expected) +
+                    "\nactual:   " + HexDump.toHexString(program));
+        }
+    }
+
+    private void assertDataMemoryContents(
+            int expected, byte[] program, byte[] packet, byte[] data, byte[] expected_data)
+            throws IllegalInstructionException, Exception {
+        assertReturnCodesEqual(expected, apfSimulate(program, packet, data, 0 /* filterAge */));
+
+        // assertArrayEquals() would only print one byte, making debugging difficult.
+        if (!java.util.Arrays.equals(expected_data, data)) {
+            throw new Exception(
+                    "\nprogram:     " + HexDump.toHexString(program) +
+                    "\ndata memory: " + HexDump.toHexString(data) +
+                    "\nexpected:    " + HexDump.toHexString(expected_data));
+        }
+    }
+
+    private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
+            throws IllegalInstructionException {
+        assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, null,
+              filterAge));
+    }
+
+    private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
+            throws IllegalInstructionException {
+        assertVerdict(PASS, gen, packet, filterAge);
+    }
+
+    private void assertDrop(ApfGenerator gen, byte[] packet, int filterAge)
+            throws IllegalInstructionException {
+        assertVerdict(DROP, gen, packet, filterAge);
+    }
+
+    private void assertPass(ApfGenerator gen)
+            throws IllegalInstructionException {
+        assertVerdict(PASS, gen, new byte[MIN_PKT_SIZE], 0);
+    }
+
+    private void assertDrop(ApfGenerator gen)
+            throws IllegalInstructionException {
+        assertVerdict(DROP, gen, new byte[MIN_PKT_SIZE], 0);
+    }
+
+    /**
+     * Test each instruction by generating a program containing the instruction,
+     * generating bytecode for that program and running it through the
+     * interpreter to verify it functions correctly.
+     */
+    @Test
+    public void testApfInstructions() throws IllegalInstructionException {
+        // Empty program should pass because having the program counter reach the
+        // location immediately after the program indicates the packet should be
+        // passed to the AP.
+        ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
+        assertPass(gen);
+
+        // Test jumping to pass label.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addJump(gen.PASS_LABEL);
+        byte[] program = gen.generate();
+        assertEquals(1, program.length);
+        assertEquals((14 << 3) | (0 << 1) | 0, program[0]);
+        assertPass(program, new byte[MIN_PKT_SIZE], 0);
+
+        // Test jumping to drop label.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addJump(gen.DROP_LABEL);
+        program = gen.generate();
+        assertEquals(2, program.length);
+        assertEquals((14 << 3) | (1 << 1) | 0, program[0]);
+        assertEquals(1, program[1]);
+        assertDrop(program, new byte[15], 15);
+
+        // Test jumping if equal to 0.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if not equal to 0.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if registers equal.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addJumpIfR0EqualsR1(gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if registers not equal.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test load immediate.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test add.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addAdd(1234567890);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test subtract.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addAdd(-1234567890);
+        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test or.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addOr(1234567890);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test and.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addAnd(123456789);
+        gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test left shift.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addLeftShift(1);
+        gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test right shift.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addRightShift(1);
+        gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test multiply.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 123456789);
+        gen.addMul(2);
+        gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test divide.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addDiv(2);
+        gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test divide by zero.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addDiv(0);
+        gen.addJump(gen.DROP_LABEL);
+        assertPass(gen);
+
+        // Test add.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, 1234567890);
+        gen.addAddR1();
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test subtract.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, -1234567890);
+        gen.addAddR1();
+        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test or.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, 1234567890);
+        gen.addOrR1();
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test and.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addLoadImmediate(Register.R1, 123456789);
+        gen.addAndR1();
+        gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test left shift.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addLoadImmediate(Register.R1, 1);
+        gen.addLeftShiftR1();
+        gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test right shift.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addLoadImmediate(Register.R1, -1);
+        gen.addLeftShiftR1();
+        gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test multiply.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 123456789);
+        gen.addLoadImmediate(Register.R1, 2);
+        gen.addMulR1();
+        gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test divide.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addLoadImmediate(Register.R1, 2);
+        gen.addDivR1();
+        gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test divide by zero.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addDivR1();
+        gen.addJump(gen.DROP_LABEL);
+        assertPass(gen);
+
+        // Test byte load.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoad8(Register.R0, 1);
+        gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test out of bounds load.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoad8(Register.R0, 16);
+        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
+        assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test half-word load.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoad16(Register.R0, 1);
+        gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test word load.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoad32(Register.R0, 1);
+        gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test byte indexed load.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, 1);
+        gen.addLoad8Indexed(Register.R0, 0);
+        gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test out of bounds indexed load.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, 8);
+        gen.addLoad8Indexed(Register.R0, 8);
+        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
+        assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test half-word indexed load.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, 1);
+        gen.addLoad16Indexed(Register.R0, 0);
+        gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test word indexed load.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, 1);
+        gen.addLoad32Indexed(Register.R0, 0);
+        gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test jumping if greater than.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if less than.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addJumpIfR0LessThan(0, gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addJumpIfR0LessThan(1, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if any bits set.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
+        assertDrop(gen);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 3);
+        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if register greater than.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 2);
+        gen.addLoadImmediate(Register.R1, 1);
+        gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if register less than.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, 1);
+        gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if any bits set in register.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, 3);
+        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, 3);
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
+        assertDrop(gen);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, 3);
+        gen.addLoadImmediate(Register.R0, 3);
+        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test load from memory.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadFromMemory(Register.R0, 0);
+        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test store to memory.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, 1234567890);
+        gen.addStoreToMemory(Register.R1, 12);
+        gen.addLoadFromMemory(Register.R0, 12);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test filter age pre-filled memory.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890);
+
+        // Test packet size pre-filled memory.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
+        gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test IPv4 header size pre-filled memory.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
+        gen.addJumpIfR0Equals(20, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0);
+
+        // Test not.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addNot(Register.R0);
+        gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test negate.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addNeg(Register.R0);
+        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test move.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, 1234567890);
+        gen.addMove(Register.R0);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addMove(Register.R1);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test swap.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R1, 1234567890);
+        gen.addSwap();
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addSwap();
+        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jump if bytes not equal.
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
+        program = gen.generate();
+        assertEquals(6, program.length);
+        assertEquals((13 << 3) | (1 << 1) | 0, program[0]);
+        assertEquals(1, program[1]);
+        assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]);
+        assertEquals(1, program[3]);
+        assertEquals(1, program[4]);
+        assertEquals(123, program[5]);
+        assertDrop(program, new byte[MIN_PKT_SIZE], 0);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
+        byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
+        assertPass(gen, packet123, 0);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
+        assertDrop(gen, packet123, 0);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
+        byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
+        assertDrop(gen, packet12345, 0);
+        gen = new ApfGenerator(MIN_APF_VERSION);
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL);
+        assertPass(gen, packet12345, 0);
+    }
+
+    @Test(expected = ApfGenerator.IllegalInstructionException.class)
+    public void testApfGeneratorWantsV2OrGreater() throws Exception {
+        // The minimum supported APF version is 2.
+        new ApfGenerator(1);
+    }
+
+    @Test
+    public void testApfDataOpcodesWantApfV3() throws IllegalInstructionException, Exception {
+        ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
+        try {
+            gen.addStoreData(Register.R0, 0);
+            fail();
+        } catch (IllegalInstructionException expected) {
+            /* pass */
+        }
+        try {
+            gen.addLoadData(Register.R0, 0);
+            fail();
+        } catch (IllegalInstructionException expected) {
+            /* pass */
+        }
+    }
+
+    /**
+     * Test that the generator emits immediates using the shortest possible encoding.
+     */
+    @Test
+    public void testImmediateEncoding() throws IllegalInstructionException {
+        ApfGenerator gen;
+
+        // 0-byte immediate: li R0, 0
+        gen = new ApfGenerator(4);
+        gen.addLoadImmediate(Register.R0, 0);
+        assertProgramEquals(new byte[]{LI_OP | SIZE0}, gen.generate());
+
+        // 1-byte immediate: li R0, 42
+        gen = new ApfGenerator(4);
+        gen.addLoadImmediate(Register.R0, 42);
+        assertProgramEquals(new byte[]{LI_OP | SIZE8, 42}, gen.generate());
+
+        // 2-byte immediate: li R1, 0x1234
+        gen = new ApfGenerator(4);
+        gen.addLoadImmediate(Register.R1, 0x1234);
+        assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, 0x12, 0x34}, gen.generate());
+
+        // 4-byte immediate: li R0, 0x12345678
+        gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, 0x12345678);
+        assertProgramEquals(
+                new byte[]{LI_OP | SIZE32, 0x12, 0x34, 0x56, 0x78},
+                gen.generate());
+    }
+
+    /**
+     * Test that the generator emits negative immediates using the shortest possible encoding.
+     */
+    @Test
+    public void testNegativeImmediateEncoding() throws IllegalInstructionException {
+        ApfGenerator gen;
+
+        // 1-byte negative immediate: li R0, -42
+        gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, -42);
+        assertProgramEquals(new byte[]{LI_OP | SIZE8, -42}, gen.generate());
+
+        // 2-byte negative immediate: li R1, -0x1122
+        gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R1, -0x1122);
+        assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
+                gen.generate());
+
+        // 4-byte negative immediate: li R0, -0x11223344
+        gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, -0x11223344);
+        assertProgramEquals(
+                new byte[]{LI_OP | SIZE32, (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC},
+                gen.generate());
+    }
+
+    /**
+     * Test that the generator correctly emits positive and negative immediates for LDDW/STDW.
+     */
+    @Test
+    public void testLoadStoreDataEncoding() throws IllegalInstructionException {
+        ApfGenerator gen;
+
+        // Load data with no offset: lddw R0, [0 + r1]
+        gen = new ApfGenerator(3);
+        gen.addLoadData(Register.R0, 0);
+        assertProgramEquals(new byte[]{LDDW_OP | SIZE0}, gen.generate());
+
+        // Store data with 8bit negative offset: lddw r0, [-42 + r1]
+        gen = new ApfGenerator(3);
+        gen.addStoreData(Register.R0, -42);
+        assertProgramEquals(new byte[]{STDW_OP | SIZE8, -42}, gen.generate());
+
+        // Store data to R1 with 16bit negative offset: stdw r1, [-0x1122 + r0]
+        gen = new ApfGenerator(3);
+        gen.addStoreData(Register.R1, -0x1122);
+        assertProgramEquals(new byte[]{STDW_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
+                gen.generate());
+
+        // Load data to R1 with 32bit negative offset: lddw r1, [0xDEADBEEF + r0]
+        gen = new ApfGenerator(3);
+        gen.addLoadData(Register.R1, 0xDEADBEEF);
+        assertProgramEquals(
+                new byte[]{LDDW_OP | SIZE32 | R1, (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF},
+                gen.generate());
+    }
+
+    /**
+     * Test that the interpreter correctly executes STDW with a negative 8bit offset
+     */
+    @Test
+    public void testApfDataWrite() throws IllegalInstructionException, Exception {
+        byte[] packet = new byte[MIN_PKT_SIZE];
+        byte[] data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+        byte[] expected_data = data.clone();
+
+        // No memory access instructions: should leave the data segment untouched.
+        ApfGenerator gen = new ApfGenerator(3);
+        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
+
+        // Expect value 0x87654321 to be stored starting from address -11 from the end of the
+        // data buffer, in big-endian order.
+        gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, 0x87654321);
+        gen.addLoadImmediate(Register.R1, -5);
+        gen.addStoreData(Register.R0, -6);  // -5 + -6 = -11 (offset +5 with data_len=16)
+        expected_data[5] = (byte)0x87;
+        expected_data[6] = (byte)0x65;
+        expected_data[7] = (byte)0x43;
+        expected_data[8] = (byte)0x21;
+        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
+    }
+
+    /**
+     * Test that the interpreter correctly executes LDDW with a negative 16bit offset
+     */
+    @Test
+    public void testApfDataRead() throws IllegalInstructionException, Exception {
+        // Program that DROPs if address 10 (-6) contains 0x87654321.
+        ApfGenerator gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R1, 1000);
+        gen.addLoadData(Register.R0, -1006);  // 1000 + -1006 = -6 (offset +10 with data_len=16)
+        gen.addJumpIfR0Equals(0x87654321, gen.DROP_LABEL);
+        byte[] program = gen.generate();
+        byte[] packet = new byte[MIN_PKT_SIZE];
+
+        // Content is incorrect (last byte does not match) -> PASS
+        byte[] data = new byte[16];
+        data[10] = (byte)0x87;
+        data[11] = (byte)0x65;
+        data[12] = (byte)0x43;
+        data[13] = (byte)0x00;  // != 0x21
+        byte[] expected_data = data.clone();
+        assertDataMemoryContents(PASS, program, packet, data, expected_data);
+
+        // Fix the last byte -> conditional jump taken -> DROP
+        data[13] = (byte)0x21;
+        expected_data = data;
+        assertDataMemoryContents(DROP, program, packet, data, expected_data);
+    }
+
+    /**
+     * Test that the interpreter correctly executes LDDW followed by a STDW.
+     * To cover a few more edge cases, LDDW has a 0bit offset, while STDW has a positive 8bit
+     * offset.
+     */
+    @Test
+    public void testApfDataReadModifyWrite() throws IllegalInstructionException, Exception {
+        ApfGenerator gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R1, -22);
+        gen.addLoadData(Register.R0, 0);  // Load from address 32 -22 + 0 = 10
+        gen.addAdd(0x78453412);  // 87654321 + 78453412 = FFAA7733
+        gen.addStoreData(Register.R0, 4);  // Write back to address 32 -22 + 4 = 14
+
+        byte[] packet = new byte[MIN_PKT_SIZE];
+        byte[] data = new byte[32];
+        data[10] = (byte)0x87;
+        data[11] = (byte)0x65;
+        data[12] = (byte)0x43;
+        data[13] = (byte)0x21;
+        byte[] expected_data = data.clone();
+        expected_data[14] = (byte)0xFF;
+        expected_data[15] = (byte)0xAA;
+        expected_data[16] = (byte)0x77;
+        expected_data[17] = (byte)0x33;
+        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
+    }
+
+    @Test
+    public void testApfDataBoundChecking() throws IllegalInstructionException, Exception {
+        byte[] packet = new byte[MIN_PKT_SIZE];
+        byte[] data = new byte[32];
+        byte[] expected_data = data;
+
+        // Program that DROPs unconditionally. This is our the baseline.
+        ApfGenerator gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, 3);
+        gen.addLoadData(Register.R1, 7);
+        gen.addJump(gen.DROP_LABEL);
+        assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
+
+        // Same program as before, but this time we're trying to load past the end of the data.
+        gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, 20);
+        gen.addLoadData(Register.R1, 15);  // 20 + 15 > 32
+        gen.addJump(gen.DROP_LABEL);  // Not reached.
+        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
+
+        // Subtracting an immediate should work...
+        gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, 20);
+        gen.addLoadData(Register.R1, -4);
+        gen.addJump(gen.DROP_LABEL);
+        assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
+
+        // ...and underflowing simply wraps around to the end of the buffer...
+        gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, 20);
+        gen.addLoadData(Register.R1, -30);
+        gen.addJump(gen.DROP_LABEL);
+        assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
+
+        // ...but doesn't allow accesses before the start of the buffer
+        gen = new ApfGenerator(3);
+        gen.addLoadImmediate(Register.R0, 20);
+        gen.addLoadData(Register.R1, -1000);
+        gen.addJump(gen.DROP_LABEL);  // Not reached.
+        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
+    }
+
+    /**
+     * Generate some BPF programs, translate them to APF, then run APF and BPF programs
+     * over packet traces and verify both programs filter out the same packets.
+     */
+    @Test
+    public void testApfAgainstBpf() throws Exception {
+        String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53",
+                "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24",
+                "arp or icmp6 or portrange 53-54", "portrange 53-54 or portrange 100-50000",
+                "tcp[tcpflags] & (tcp-ack|tcp-fin) != 0 and (ip[2:2] > 57 or icmp)" };
+        String pcap_filename = stageFile(R.raw.apf);
+        for (String tcpdump_filter : tcpdump_filters) {
+            byte[] apf_program = Bpf2Apf.convert(compileToBpf(tcpdump_filter));
+            assertTrue("Failed to match for filter: " + tcpdump_filter,
+                    compareBpfApf(tcpdump_filter, pcap_filename, apf_program));
+        }
+    }
+
+    /**
+     * Generate APF program, run pcap file though APF filter, then check all the packets in the file
+     * should be dropped.
+     */
+    @Test
+    public void testApfFilterPcapFile() throws Exception {
+        final byte[] MOCK_PCAP_IPV4_ADDR = {(byte) 172, 16, 7, (byte) 151};
+        String pcapFilename = stageFile(R.raw.apfPcap);
+        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
+        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_PCAP_IPV4_ADDR), 16);
+        LinkProperties lp = new LinkProperties();
+        lp.addLinkAddress(link);
+
+        ApfConfiguration config = getDefaultConfig();
+        ApfCapabilities MOCK_APF_PCAP_CAPABILITIES = new ApfCapabilities(4, 1700, ARPHRD_ETHER);
+        config.apfCapabilities = MOCK_APF_PCAP_CAPABILITIES;
+        config.multicastFilter = DROP_MULTICAST;
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
+        apfFilter.setLinkProperties(lp);
+        byte[] program = ipClientCallback.getApfProgram();
+        byte[] data = new byte[ApfFilter.Counter.totalSize()];
+        final boolean result;
+
+        result = dropsAllPackets(program, data, pcapFilename);
+        Log.i(TAG, "testApfFilterPcapFile(): Data counters: " + HexDump.toHexString(data, false));
+
+        assertTrue("Failed to drop all packets by filter. \nAPF counters:" +
+            HexDump.toHexString(data, false), result);
+    }
+
+    private class MockIpClientCallback extends IpClientCallbacksWrapper {
+        private final ConditionVariable mGotApfProgram = new ConditionVariable();
+        private byte[] mLastApfProgram;
+
+        MockIpClientCallback() {
+            super(mock(IIpClientCallbacks.class), mock(SharedLog.class));
+        }
+
+        @Override
+        public void installPacketFilter(byte[] filter) {
+            mLastApfProgram = filter;
+            mGotApfProgram.open();
+        }
+
+        public void resetApfProgramWait() {
+            mGotApfProgram.close();
+        }
+
+        public byte[] getApfProgram() {
+            assertTrue(mGotApfProgram.block(TIMEOUT_MS));
+            return mLastApfProgram;
+        }
+
+        public void assertNoProgramUpdate() {
+            assertFalse(mGotApfProgram.block(TIMEOUT_MS));
+        }
+    }
+
+    private static class TestApfFilter extends ApfFilter {
+        public static final byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
+
+        private FileDescriptor mWriteSocket;
+        private final long mFixedTimeMs = SystemClock.elapsedRealtime();
+
+        public TestApfFilter(Context context, ApfConfiguration config,
+                IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log) throws Exception {
+            super(context, config, InterfaceParams.getByName("lo"), ipClientCallback, log);
+        }
+
+        // Pretend an RA packet has been received and show it to ApfFilter.
+        public void pretendPacketReceived(byte[] packet) throws IOException, ErrnoException {
+            // ApfFilter's ReceiveThread will be waiting to read this.
+            Os.write(mWriteSocket, packet, 0, packet.length);
+        }
+
+        @Override
+        protected long currentTimeSeconds() {
+            return mFixedTimeMs / DateUtils.SECOND_IN_MILLIS;
+        }
+
+        @Override
+        void maybeStartFilter() {
+            mHardwareAddress = MOCK_MAC_ADDR;
+            installNewProgramLocked();
+
+            // Create two sockets, "readSocket" and "mWriteSocket" and connect them together.
+            FileDescriptor readSocket = new FileDescriptor();
+            mWriteSocket = new FileDescriptor();
+            try {
+                Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket);
+            } catch (ErrnoException e) {
+                fail();
+                return;
+            }
+            // Now pass readSocket to ReceiveThread as if it was setup to read raw RAs.
+            // This allows us to pretend RA packets have been recieved via pretendPacketReceived().
+            mReceiveThread = new ReceiveThread(readSocket);
+            mReceiveThread.start();
+        }
+
+        @Override
+        public void shutdown() {
+            super.shutdown();
+            IoUtils.closeQuietly(mWriteSocket);
+        }
+    }
+
+    private static final int ETH_HEADER_LEN = 14;
+    private static final int ETH_DEST_ADDR_OFFSET = 0;
+    private static final int ETH_ETHERTYPE_OFFSET = 12;
+    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
+            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
+
+    private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
+    private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
+    private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
+    private static final byte[] IPV4_BROADCAST_ADDRESS =
+            {(byte) 255, (byte) 255, (byte) 255, (byte) 255};
+
+    private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
+    private static final int IPV6_HEADER_LEN = 40;
+    private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
+    // The IPv6 all nodes address ff02::1
+    private static final byte[] IPV6_ALL_NODES_ADDRESS =
+            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
+    private static final byte[] IPV6_ALL_ROUTERS_ADDRESS =
+            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
+
+    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
+    private static final int ICMP6_ROUTER_SOLICITATION = 133;
+    private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
+    private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
+    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
+
+    private static final int ICMP6_RA_HEADER_LEN = 16;
+    private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
+            ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
+    private static final int ICMP6_RA_CHECKSUM_OFFSET =
+            ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
+    private static final int ICMP6_RA_OPTION_OFFSET =
+            ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
+
+    private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
+    private static final int ICMP6_PREFIX_OPTION_LEN = 32;
+    private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
+    private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
+
+    // From RFC6106: Recursive DNS Server option
+    private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
+    // From RFC6106: DNS Search List option
+    private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
+
+    // From RFC4191: Route Information option
+    private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
+    // Above three options all have the same format:
+    private static final int ICMP6_4_BYTE_OPTION_LEN = 8;
+    private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
+    private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
+
+    private static final int UDP_HEADER_LEN = 8;
+    private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22;
+
+    private static final int DHCP_CLIENT_PORT = 68;
+    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
+
+    private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
+    private static final byte[] ARP_IPV4_REQUEST_HEADER = {
+            0, 1, // Hardware type: Ethernet (1)
+            8, 0, // Protocol type: IP (0x0800)
+            6,    // Hardware size: 6
+            4,    // Protocol size: 4
+            0, 1  // Opcode: request (1)
+    };
+    private static final byte[] ARP_IPV4_REPLY_HEADER = {
+            0, 1, // Hardware type: Ethernet (1)
+            8, 0, // Protocol type: IP (0x0800)
+            6,    // Hardware size: 6
+            4,    // Protocol size: 4
+            0, 2  // Opcode: reply (2)
+    };
+    private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
+    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
+
+    private static final byte[] MOCK_IPV4_ADDR           = {10, 0, 0, 1};
+    private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19
+    private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1};
+    private static final byte[] ANOTHER_IPV4_ADDR        = {10, 0, 0, 2};
+    private static final byte[] IPV4_SOURCE_ADDR         = {10, 0, 0, 3};
+    private static final byte[] ANOTHER_IPV4_SOURCE_ADDR = {(byte) 192, 0, 2, 1};
+    private static final byte[] BUG_PROBE_SOURCE_ADDR1   = {0, 0, 1, 2};
+    private static final byte[] BUG_PROBE_SOURCE_ADDR2   = {3, 4, 0, 0};
+    private static final byte[] IPV4_ANY_HOST_ADDR       = {0, 0, 0, 0};
+
+    // Helper to initialize a default apfFilter.
+    private ApfFilter setupApfFilter(
+            IpClientCallbacksWrapper ipClientCallback, ApfConfiguration config) throws Exception {
+        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
+        LinkProperties lp = new LinkProperties();
+        lp.addLinkAddress(link);
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
+        apfFilter.setLinkProperties(lp);
+        return apfFilter;
+    }
+
+    @Test
+    public void testApfFilterIPv4() throws Exception {
+        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
+        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
+        LinkProperties lp = new LinkProperties();
+        lp.addLinkAddress(link);
+
+        ApfConfiguration config = getDefaultConfig();
+        config.multicastFilter = DROP_MULTICAST;
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
+        apfFilter.setLinkProperties(lp);
+
+        byte[] program = ipClientCallback.getApfProgram();
+
+        // Verify empty packet of 100 zero bytes is passed
+        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+        assertPass(program, packet.array());
+
+        // Verify unicast IPv4 packet is passed
+        put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR);
+        assertPass(program, packet.array());
+
+        // Verify L2 unicast to IPv4 broadcast addresses is dropped (b/30231088)
+        put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
+        assertDrop(program, packet.array());
+        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
+        assertDrop(program, packet.array());
+
+        // Verify multicast/broadcast IPv4, not DHCP to us, is dropped
+        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
+        assertDrop(program, packet.array());
+        packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
+        assertDrop(program, packet.array());
+        packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
+        assertDrop(program, packet.array());
+        packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
+        assertDrop(program, packet.array());
+        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_MULTICAST_IPV4_ADDR);
+        assertDrop(program, packet.array());
+        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
+        assertDrop(program, packet.array());
+        put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
+        assertDrop(program, packet.array());
+
+        // Verify broadcast IPv4 DHCP to us is passed
+        put(packet, DHCP_CLIENT_MAC_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
+        assertPass(program, packet.array());
+
+        // Verify unicast IPv4 DHCP to us is passed
+        put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
+        assertPass(program, packet.array());
+
+        apfFilter.shutdown();
+    }
+
+    @Test
+    public void testApfFilterIPv6() throws Exception {
+        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
+        ApfConfiguration config = getDefaultConfig();
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
+        byte[] program = ipClientCallback.getApfProgram();
+
+        // Verify empty IPv6 packet is passed
+        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+        assertPass(program, packet.array());
+
+        // Verify empty ICMPv6 packet is passed
+        packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
+        assertPass(program, packet.array());
+
+        // Verify empty ICMPv6 NA packet is passed
+        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
+        assertPass(program, packet.array());
+
+        // Verify ICMPv6 NA to ff02::1 is dropped
+        put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
+        assertDrop(program, packet.array());
+
+        // Verify ICMPv6 RS to any is dropped
+        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION);
+        assertDrop(program, packet.array());
+        put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS);
+        assertDrop(program, packet.array());
+
+        apfFilter.shutdown();
+    }
+
+    @Test
+    public void testApfFilterMulticast() throws Exception {
+        final byte[] unicastIpv4Addr   = {(byte)192,0,2,63};
+        final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
+        final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
+        final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
+
+        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
+        LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
+        LinkProperties lp = new LinkProperties();
+        lp.addLinkAddress(link);
+
+        ApfConfiguration config = getDefaultConfig();
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
+        apfFilter.setLinkProperties(lp);
+
+        byte[] program = ipClientCallback.getApfProgram();
+
+        // Construct IPv4 and IPv6 multicast packets.
+        ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
+        mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
+
+        ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
+        mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
+        put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
+
+        // Construct IPv4 broadcast packet.
+        ByteBuffer bcastv4packet1 = ByteBuffer.wrap(new byte[100]);
+        bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS);
+        bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
+
+        ByteBuffer bcastv4packet2 = ByteBuffer.wrap(new byte[100]);
+        bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS);
+        bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
+
+        // Construct IPv4 broadcast with L2 unicast address packet (b/30231088).
+        ByteBuffer bcastv4unicastl2packet = ByteBuffer.wrap(new byte[100]);
+        bcastv4unicastl2packet.put(TestApfFilter.MOCK_MAC_ADDR);
+        bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr);
+
+        // Verify initially disabled multicast filter is off
+        assertPass(program, mcastv4packet.array());
+        assertPass(program, mcastv6packet.array());
+        assertPass(program, bcastv4packet1.array());
+        assertPass(program, bcastv4packet2.array());
+        assertPass(program, bcastv4unicastl2packet.array());
+
+        // Turn on multicast filter and verify it works
+        ipClientCallback.resetApfProgramWait();
+        apfFilter.setMulticastFilter(true);
+        program = ipClientCallback.getApfProgram();
+        assertDrop(program, mcastv4packet.array());
+        assertDrop(program, mcastv6packet.array());
+        assertDrop(program, bcastv4packet1.array());
+        assertDrop(program, bcastv4packet2.array());
+        assertDrop(program, bcastv4unicastl2packet.array());
+
+        // Turn off multicast filter and verify it's off
+        ipClientCallback.resetApfProgramWait();
+        apfFilter.setMulticastFilter(false);
+        program = ipClientCallback.getApfProgram();
+        assertPass(program, mcastv4packet.array());
+        assertPass(program, mcastv6packet.array());
+        assertPass(program, bcastv4packet1.array());
+        assertPass(program, bcastv4packet2.array());
+        assertPass(program, bcastv4unicastl2packet.array());
+
+        // Verify it can be initialized to on
+        ipClientCallback.resetApfProgramWait();
+        apfFilter.shutdown();
+        config.multicastFilter = DROP_MULTICAST;
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
+        apfFilter.setLinkProperties(lp);
+        program = ipClientCallback.getApfProgram();
+        assertDrop(program, mcastv4packet.array());
+        assertDrop(program, mcastv6packet.array());
+        assertDrop(program, bcastv4packet1.array());
+        assertDrop(program, bcastv4unicastl2packet.array());
+
+        // Verify that ICMPv6 multicast is not dropped.
+        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
+        assertPass(program, mcastv6packet.array());
+
+        apfFilter.shutdown();
+    }
+
+    @Test
+    public void testApfFilterMulticastPingWhileDozing() throws Exception {
+        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
+        ApfFilter apfFilter = setupApfFilter(ipClientCallback, getDefaultConfig());
+
+        // Construct a multicast ICMPv6 ECHO request.
+        final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
+        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+        packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
+        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ECHO_REQUEST_TYPE);
+        put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
+
+        // Normally, we let multicast pings alone...
+        assertPass(ipClientCallback.getApfProgram(), packet.array());
+
+        // ...and even while dozing...
+        apfFilter.setDozeMode(true);
+        assertPass(ipClientCallback.getApfProgram(), packet.array());
+
+        // ...but when the multicast filter is also enabled, drop the multicast pings to save power.
+        apfFilter.setMulticastFilter(true);
+        assertDrop(ipClientCallback.getApfProgram(), packet.array());
+
+        // However, we should still let through all other ICMPv6 types.
+        ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone());
+        raPacket.put(ICMP6_TYPE_OFFSET, (byte) NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT);
+        assertPass(ipClientCallback.getApfProgram(), raPacket.array());
+
+        // Now wake up from doze mode to ensure that we no longer drop the packets.
+        // (The multicast filter is still enabled at this point).
+        apfFilter.setDozeMode(false);
+        assertPass(ipClientCallback.getApfProgram(), packet.array());
+
+        apfFilter.shutdown();
+    }
+
+    @Test
+    public void testApfFilter802_3() throws Exception {
+        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
+        ApfConfiguration config = getDefaultConfig();
+        ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
+        byte[] program = ipClientCallback.getApfProgram();
+
+        // Verify empty packet of 100 zero bytes is passed
+        // Note that eth-type = 0 makes it an IEEE802.3 frame
+        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+        assertPass(program, packet.array());
+
+        // Verify empty packet with IPv4 is passed
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        assertPass(program, packet.array());
+
+        // Verify empty IPv6 packet is passed
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+        assertPass(program, packet.array());
+
+        // Now turn on the filter
+        ipClientCallback.resetApfProgramWait();
+        apfFilter.shutdown();
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        apfFilter = setupApfFilter(ipClientCallback, config);
+        program = ipClientCallback.getApfProgram();
+
+        // Verify that IEEE802.3 frame is dropped
+        // In this case ethtype is used for payload length
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)(100 - 14));
+        assertDrop(program, packet.array());
+
+        // Verify that IPv4 (as example of Ethernet II) frame will pass
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        assertPass(program, packet.array());
+
+        // Verify that IPv6 (as example of Ethernet II) frame will pass
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+        assertPass(program, packet.array());
+
+        apfFilter.shutdown();
+    }
+
+    @Test
+    public void testApfFilterEthTypeBL() throws Exception {
+        final int[] emptyBlackList = {};
+        final int[] ipv4BlackList = {ETH_P_IP};
+        final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
+
+        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
+        ApfConfiguration config = getDefaultConfig();
+        ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
+        byte[] program = ipClientCallback.getApfProgram();
+
+        // Verify empty packet of 100 zero bytes is passed
+        // Note that eth-type = 0 makes it an IEEE802.3 frame
+        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+        assertPass(program, packet.array());
+
+        // Verify empty packet with IPv4 is passed
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        assertPass(program, packet.array());
+
+        // Verify empty IPv6 packet is passed
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+        assertPass(program, packet.array());
+
+        // Now add IPv4 to the black list
+        ipClientCallback.resetApfProgramWait();
+        apfFilter.shutdown();
+        config.ethTypeBlackList = ipv4BlackList;
+        apfFilter = setupApfFilter(ipClientCallback, config);
+        program = ipClientCallback.getApfProgram();
+
+        // Verify that IPv4 frame will be dropped
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        assertDrop(program, packet.array());
+
+        // Verify that IPv6 frame will pass
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+        assertPass(program, packet.array());
+
+        // Now let us have both IPv4 and IPv6 in the black list
+        ipClientCallback.resetApfProgramWait();
+        apfFilter.shutdown();
+        config.ethTypeBlackList = ipv4Ipv6BlackList;
+        apfFilter = setupApfFilter(ipClientCallback, config);
+        program = ipClientCallback.getApfProgram();
+
+        // Verify that IPv4 frame will be dropped
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
+        assertDrop(program, packet.array());
+
+        // Verify that IPv6 frame will be dropped
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+        assertDrop(program, packet.array());
+
+        apfFilter.shutdown();
+    }
+
+    private byte[] getProgram(MockIpClientCallback cb, ApfFilter filter, LinkProperties lp) {
+        cb.resetApfProgramWait();
+        filter.setLinkProperties(lp);
+        return cb.getApfProgram();
+    }
+
+    private void verifyArpFilter(byte[] program, int filterResult) {
+        // Verify ARP request packet
+        assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR));
+        assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR));
+        assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR));
+
+        // Verify ARP reply packets from different source ip
+        assertDrop(program, arpReply(IPV4_ANY_HOST_ADDR, IPV4_ANY_HOST_ADDR));
+        assertPass(program, arpReply(ANOTHER_IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
+        assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR1, IPV4_ANY_HOST_ADDR));
+        assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR2, IPV4_ANY_HOST_ADDR));
+
+        // Verify unicast ARP reply packet is always accepted.
+        assertPass(program, arpReply(IPV4_SOURCE_ADDR, MOCK_IPV4_ADDR));
+        assertPass(program, arpReply(IPV4_SOURCE_ADDR, ANOTHER_IPV4_ADDR));
+        assertPass(program, arpReply(IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
+
+        // Verify GARP reply packets are always filtered
+        assertDrop(program, garpReply());
+    }
+
+    @Test
+    public void testApfFilterArp() throws Exception {
+        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
+        ApfConfiguration config = getDefaultConfig();
+        config.multicastFilter = DROP_MULTICAST;
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
+
+        // Verify initially ARP request filter is off, and GARP filter is on.
+        verifyArpFilter(ipClientCallback.getApfProgram(), PASS);
+
+        // Inform ApfFilter of our address and verify ARP filtering is on
+        LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24);
+        LinkProperties lp = new LinkProperties();
+        assertTrue(lp.addLinkAddress(linkAddress));
+        verifyArpFilter(getProgram(ipClientCallback, apfFilter, lp), DROP);
+
+        // Inform ApfFilter of loss of IP and verify ARP filtering is off
+        verifyArpFilter(getProgram(ipClientCallback, apfFilter, new LinkProperties()), PASS);
+
+        apfFilter.shutdown();
+    }
+
+    private static byte[] arpReply(byte[] sip, byte[] tip) {
+        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
+        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
+        put(packet, ARP_SOURCE_IP_ADDRESS_OFFSET, sip);
+        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
+        return packet.array();
+    }
+
+    private static byte[] arpRequestBroadcast(byte[] tip) {
+        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
+        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
+        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REQUEST_HEADER);
+        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
+        return packet.array();
+    }
+
+    private static byte[] garpReply() {
+        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
+        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
+        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
+        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR);
+        return packet.array();
+    }
+
+    // Verify that the last program pushed to the IpClient.Callback properly filters the
+    // given packet for the given lifetime.
+    private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) {
+        final int FRACTION_OF_LIFETIME = 6;
+        final int ageLimit = lifetime / FRACTION_OF_LIFETIME;
+
+        // Verify new program should drop RA for 1/6th its lifetime and pass afterwards.
+        assertDrop(program, packet.array());
+        assertDrop(program, packet.array(), ageLimit);
+        assertPass(program, packet.array(), ageLimit + 1);
+        assertPass(program, packet.array(), lifetime);
+        // Verify RA checksum is ignored
+        final short originalChecksum = packet.getShort(ICMP6_RA_CHECKSUM_OFFSET);
+        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
+        assertDrop(program, packet.array());
+        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
+        assertDrop(program, packet.array());
+        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, originalChecksum);
+
+        // Verify other changes to RA make it not match filter
+        final byte originalFirstByte = packet.get(0);
+        packet.put(0, (byte)-1);
+        assertPass(program, packet.array());
+        packet.put(0, (byte)0);
+        assertDrop(program, packet.array());
+        packet.put(0, originalFirstByte);
+    }
+
+    // Test that when ApfFilter is shown the given packet, it generates a program to filter it
+    // for the given lifetime.
+    private void verifyRaLifetime(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
+            ByteBuffer packet, int lifetime) throws IOException, ErrnoException {
+        // Verify new program generated if ApfFilter witnesses RA
+        ipClientCallback.resetApfProgramWait();
+        apfFilter.pretendPacketReceived(packet.array());
+        byte[] program = ipClientCallback.getApfProgram();
+        verifyRaLifetime(program, packet, lifetime);
+    }
+
+    private void verifyRaEvent(RaEvent expected) {
+        ArgumentCaptor<IpConnectivityLog.Event> captor =
+                ArgumentCaptor.forClass(IpConnectivityLog.Event.class);
+        verify(mLog, atLeastOnce()).log(captor.capture());
+        RaEvent got = lastRaEvent(captor.getAllValues());
+        if (!raEventEquals(expected, got)) {
+            assertEquals(expected, got);  // fail for printing an assertion error message.
+        }
+    }
+
+    private RaEvent lastRaEvent(List<IpConnectivityLog.Event> events) {
+        RaEvent got = null;
+        for (Parcelable ev : events) {
+            if (ev instanceof RaEvent) {
+                got = (RaEvent) ev;
+            }
+        }
+        return got;
+    }
+
+    private boolean raEventEquals(RaEvent ev1, RaEvent ev2) {
+        return (ev1 != null) && (ev2 != null)
+                && (ev1.routerLifetime == ev2.routerLifetime)
+                && (ev1.prefixValidLifetime == ev2.prefixValidLifetime)
+                && (ev1.prefixPreferredLifetime == ev2.prefixPreferredLifetime)
+                && (ev1.routeInfoLifetime == ev2.routeInfoLifetime)
+                && (ev1.rdnssLifetime == ev2.rdnssLifetime)
+                && (ev1.dnsslLifetime == ev2.dnsslLifetime);
+    }
+
+    private void assertInvalidRa(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
+            ByteBuffer packet) throws IOException, ErrnoException {
+        ipClientCallback.resetApfProgramWait();
+        apfFilter.pretendPacketReceived(packet.array());
+        ipClientCallback.assertNoProgramUpdate();
+    }
+
+    @Test
+    public void testApfFilterRa() throws Exception {
+        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
+        ApfConfiguration config = getDefaultConfig();
+        config.multicastFilter = DROP_MULTICAST;
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
+        byte[] program = ipClientCallback.getApfProgram();
+
+        final int ROUTER_LIFETIME = 1000;
+        final int PREFIX_VALID_LIFETIME = 200;
+        final int PREFIX_PREFERRED_LIFETIME = 100;
+        final int RDNSS_LIFETIME  = 300;
+        final int ROUTE_LIFETIME  = 400;
+        // Note that lifetime of 2000 will be ignored in favor of shorter route lifetime of 1000.
+        final int DNSSL_LIFETIME  = 2000;
+        final int VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET = ETH_HEADER_LEN;
+        // IPv6, traffic class = 0, flow label = 0x12345
+        final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345;
+
+        // Verify RA is passed the first time
+        ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
+        basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+        basePacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
+                VERSION_TRAFFIC_CLASS_FLOW_LABEL);
+        basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
+        basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
+        basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)ROUTER_LIFETIME);
+        basePacket.position(IPV6_DEST_ADDR_OFFSET);
+        basePacket.put(IPV6_ALL_NODES_ADDRESS);
+        assertPass(program, basePacket.array());
+
+        verifyRaLifetime(apfFilter, ipClientCallback, basePacket, ROUTER_LIFETIME);
+        verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1));
+
+        ByteBuffer newFlowLabelPacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
+        basePacket.clear();
+        newFlowLabelPacket.put(basePacket);
+        // Check that changes are ignored in every byte of the flow label.
+        newFlowLabelPacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
+                VERSION_TRAFFIC_CLASS_FLOW_LABEL + 0x11111);
+
+        // Ensure zero-length options cause the packet to be silently skipped.
+        // Do this before we test other packets. http://b/29586253
+        ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap(
+                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
+        basePacket.clear();
+        zeroLengthOptionPacket.put(basePacket);
+        zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
+        zeroLengthOptionPacket.put((byte)0);
+        assertInvalidRa(apfFilter, ipClientCallback, zeroLengthOptionPacket);
+
+        // Generate several RAs with different options and lifetimes, and verify when
+        // ApfFilter is shown these packets, it generates programs to filter them for the
+        // appropriate lifetime.
+        ByteBuffer prefixOptionPacket = ByteBuffer.wrap(
+                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_LEN]);
+        basePacket.clear();
+        prefixOptionPacket.put(basePacket);
+        prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
+        prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8));
+        prefixOptionPacket.putInt(
+                ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
+                PREFIX_PREFERRED_LIFETIME);
+        prefixOptionPacket.putInt(
+                ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
+                PREFIX_VALID_LIFETIME);
+        verifyRaLifetime(
+                apfFilter, ipClientCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
+        verifyRaEvent(new RaEvent(
+                ROUTER_LIFETIME, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, -1, -1, -1));
+
+        ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(
+                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
+        basePacket.clear();
+        rdnssOptionPacket.put(basePacket);
+        rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE);
+        rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
+        rdnssOptionPacket.putInt(
+                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, RDNSS_LIFETIME);
+        verifyRaLifetime(apfFilter, ipClientCallback, rdnssOptionPacket, RDNSS_LIFETIME);
+        verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1));
+
+        ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
+                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
+        basePacket.clear();
+        routeInfoOptionPacket.put(basePacket);
+        routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE);
+        routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
+        routeInfoOptionPacket.putInt(
+                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, ROUTE_LIFETIME);
+        verifyRaLifetime(apfFilter, ipClientCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
+        verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1));
+
+        ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
+                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
+        basePacket.clear();
+        dnsslOptionPacket.put(basePacket);
+        dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE);
+        dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
+        dnsslOptionPacket.putInt(
+                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, DNSSL_LIFETIME);
+        verifyRaLifetime(apfFilter, ipClientCallback, dnsslOptionPacket, ROUTER_LIFETIME);
+        verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, DNSSL_LIFETIME));
+
+        // Verify that current program filters all five RAs:
+        program = ipClientCallback.getApfProgram();
+        verifyRaLifetime(program, basePacket, ROUTER_LIFETIME);
+        verifyRaLifetime(program, newFlowLabelPacket, ROUTER_LIFETIME);
+        verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
+        verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME);
+        verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME);
+        verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME);
+
+        apfFilter.shutdown();
+    }
+
+    /**
+     * Stage a file for testing, i.e. make it native accessible. Given a resource ID,
+     * copy that resource into the app's data directory and return the path to it.
+     */
+    private String stageFile(int rawId) throws Exception {
+        File file = new File(InstrumentationRegistry.getContext().getFilesDir(), "staged_file");
+        new File(file.getParent()).mkdirs();
+        InputStream in = null;
+        OutputStream out = null;
+        try {
+            in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
+            out = new FileOutputStream(file);
+            Streams.copy(in, out);
+        } finally {
+            if (in != null) in.close();
+            if (out != null) out.close();
+        }
+        return file.getAbsolutePath();
+    }
+
+    private static void put(ByteBuffer buffer, int position, byte[] bytes) {
+        final int original = buffer.position();
+        buffer.position(position);
+        buffer.put(bytes);
+        buffer.position(original);
+    }
+
+    @Test
+    public void testRaParsing() throws Exception {
+        final int maxRandomPacketSize = 512;
+        final Random r = new Random();
+        MockIpClientCallback cb = new MockIpClientCallback();
+        ApfConfiguration config = getDefaultConfig();
+        config.multicastFilter = DROP_MULTICAST;
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
+        for (int i = 0; i < 1000; i++) {
+            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
+            r.nextBytes(packet);
+            try {
+                apfFilter.new Ra(packet, packet.length);
+            } catch (ApfFilter.InvalidRaException e) {
+            } catch (Exception e) {
+                throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
+            }
+        }
+    }
+
+    @Test
+    public void testRaProcessing() throws Exception {
+        final int maxRandomPacketSize = 512;
+        final Random r = new Random();
+        MockIpClientCallback cb = new MockIpClientCallback();
+        ApfConfiguration config = getDefaultConfig();
+        config.multicastFilter = DROP_MULTICAST;
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
+        for (int i = 0; i < 1000; i++) {
+            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
+            r.nextBytes(packet);
+            try {
+                apfFilter.processRa(packet, packet.length);
+            } catch (Exception e) {
+                throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
+            }
+        }
+    }
+
+    /**
+     * Call the APF interpreter to run {@code program} on {@code packet} with persistent memory
+     * segment {@data} pretending the filter was installed {@code filter_age} seconds ago.
+     */
+    private native static int apfSimulate(byte[] program, byte[] packet, byte[] data,
+        int filter_age);
+
+    /**
+     * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF
+     * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d".
+     */
+    private native static String compileToBpf(String filter);
+
+    /**
+     * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump
+     * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and
+     * at the same time using APF program {@code apf_program}.  Return {@code true} if
+     * both APF and BPF programs filter out exactly the same packets.
+     */
+    private native static boolean compareBpfApf(String filter, String pcap_filename,
+            byte[] apf_program);
+
+
+    /**
+     * Open packet capture file {@code pcapFilename} and run it through APF filter. Then
+     * checks whether all the packets are dropped and populates data[] {@code data} with
+     * the APF counters.
+     */
+    private native static boolean dropsAllPackets(byte[] program, byte[] data, String pcapFilename);
+
+    @Test
+    public void testBroadcastAddress() throws Exception {
+        assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
+        assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32));
+        assertEqualsIp("0.0.3.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 22));
+        assertEqualsIp("0.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 8));
+
+        assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 0));
+        assertEqualsIp("10.0.0.1", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 32));
+        assertEqualsIp("10.0.0.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 24));
+        assertEqualsIp("10.0.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 16));
+    }
+
+    public void assertEqualsIp(String expected, int got) throws Exception {
+        int want = bytesToBEInt(InetAddress.getByName(expected).getAddress());
+        assertEquals(want, got);
+    }
+}
diff --git a/tests/net/java/android/net/apf/Bpf2Apf.java b/packages/NetworkStack/tests/src/android/net/apf/Bpf2Apf.java
similarity index 100%
rename from tests/net/java/android/net/apf/Bpf2Apf.java
rename to packages/NetworkStack/tests/src/android/net/apf/Bpf2Apf.java
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
new file mode 100644
index 0000000..51d50d9
--- /dev/null
+++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
@@ -0,0 +1,539 @@
+/*
+ * 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.dhcp;
+
+import static android.net.InetAddresses.parseNumericAddress;
+import static android.net.dhcp.DhcpLease.HOSTNAME_NONE;
+import static android.net.dhcp.DhcpLeaseRepository.CLIENTID_UNSPEC;
+import static android.net.dhcp.DhcpLeaseRepository.INETADDR_UNSPEC;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.when;
+
+import static java.lang.String.format;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.IpPrefix;
+import android.net.MacAddress;
+import android.net.dhcp.DhcpServer.Clock;
+import android.net.util.SharedLog;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.net.Inet4Address;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DhcpLeaseRepositoryTest {
+    private static final Inet4Address INET4_ANY = (Inet4Address) Inet4Address.ANY;
+    private static final Inet4Address TEST_DEF_ROUTER = parseAddr4("192.168.42.247");
+    private static final Inet4Address TEST_SERVER_ADDR = parseAddr4("192.168.42.241");
+    private static final Inet4Address TEST_RESERVED_ADDR = parseAddr4("192.168.42.243");
+    private static final MacAddress TEST_MAC_1 = MacAddress.fromBytes(
+            new byte[] { 5, 4, 3, 2, 1, 0 });
+    private static final MacAddress TEST_MAC_2 = MacAddress.fromBytes(
+            new byte[] { 0, 1, 2, 3, 4, 5 });
+    private static final MacAddress TEST_MAC_3 = MacAddress.fromBytes(
+            new byte[] { 0, 1, 2, 3, 4, 6 });
+    private static final Inet4Address TEST_INETADDR_1 = parseAddr4("192.168.42.248");
+    private static final Inet4Address TEST_INETADDR_2 = parseAddr4("192.168.42.249");
+    private static final String TEST_HOSTNAME_1 = "hostname1";
+    private static final String TEST_HOSTNAME_2 = "hostname2";
+    private static final IpPrefix TEST_IP_PREFIX = new IpPrefix(TEST_SERVER_ADDR, 22);
+    private static final long TEST_TIME = 100L;
+    private static final int TEST_LEASE_TIME_MS = 3_600_000;
+    private static final Set<Inet4Address> TEST_EXCL_SET =
+            Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
+                TEST_SERVER_ADDR, TEST_DEF_ROUTER, TEST_RESERVED_ADDR)));
+
+    @NonNull
+    private SharedLog mLog;
+    @NonNull @Mock
+    private Clock mClock;
+    @NonNull
+    private DhcpLeaseRepository mRepo;
+
+    private static Inet4Address parseAddr4(String inet4Addr) {
+        return (Inet4Address) parseNumericAddress(inet4Addr);
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mLog = new SharedLog("DhcpLeaseRepositoryTest");
+        when(mClock.elapsedRealtime()).thenReturn(TEST_TIME);
+        mRepo = new DhcpLeaseRepository(
+                TEST_IP_PREFIX, TEST_EXCL_SET, TEST_LEASE_TIME_MS, mLog, mClock);
+    }
+
+    /**
+     * Request a number of addresses through offer/request. Useful to test address exhaustion.
+     * @param nAddr Number of addresses to request.
+     */
+    private void requestAddresses(byte nAddr) throws Exception {
+        final HashSet<Inet4Address> addrs = new HashSet<>();
+        byte[] hwAddrBytes = new byte[] { 8, 4, 3, 2, 1, 0 };
+        for (byte i = 0; i < nAddr; i++) {
+            hwAddrBytes[5] = i;
+            MacAddress newMac = MacAddress.fromBytes(hwAddrBytes);
+            final String hostname = "host_" + i;
+            final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, newMac,
+                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, hostname);
+
+            assertNotNull(lease);
+            assertEquals(newMac, lease.getHwAddr());
+            assertEquals(hostname, lease.getHostname());
+            assertTrue(format("Duplicate address allocated: %s in %s", lease.getNetAddr(), addrs),
+                    addrs.add(lease.getNetAddr()));
+
+            requestLeaseSelecting(newMac, lease.getNetAddr(), hostname);
+        }
+    }
+
+    @Test
+    public void testAddressExhaustion() throws Exception {
+        // Use a /28 to quickly run out of addresses
+        mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), TEST_EXCL_SET, TEST_LEASE_TIME_MS);
+
+        // /28 should have 16 addresses, 14 w/o the first/last, 11 w/o excluded addresses
+        requestAddresses((byte) 11);
+
+        try {
+            mRepo.getOffer(null, TEST_MAC_2,
+                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+            fail("Should be out of addresses");
+        } catch (DhcpLeaseRepository.OutOfAddressesException e) {
+            // Expected
+        }
+    }
+
+    @Test
+    public void testUpdateParams_LeaseCleanup() throws Exception {
+        // Inside /28:
+        final Inet4Address reqAddrIn28 = parseAddr4("192.168.42.242");
+        final Inet4Address declinedAddrIn28 = parseAddr4("192.168.42.245");
+
+        // Inside /28, but not available there (first address of the range)
+        final Inet4Address declinedFirstAddrIn28 = parseAddr4("192.168.42.240");
+
+        final DhcpLease reqAddrIn28Lease = requestLeaseSelecting(TEST_MAC_1, reqAddrIn28);
+        mRepo.markLeaseDeclined(declinedAddrIn28);
+        mRepo.markLeaseDeclined(declinedFirstAddrIn28);
+
+        // Inside /22, but outside /28:
+        final Inet4Address reqAddrIn22 = parseAddr4("192.168.42.3");
+        final Inet4Address declinedAddrIn22 = parseAddr4("192.168.42.4");
+
+        final DhcpLease reqAddrIn22Lease = requestLeaseSelecting(TEST_MAC_3, reqAddrIn22);
+        mRepo.markLeaseDeclined(declinedAddrIn22);
+
+        // Address that will be reserved in the updateParams call below
+        final Inet4Address reservedAddr = parseAddr4("192.168.42.244");
+        final DhcpLease reservedAddrLease = requestLeaseSelecting(TEST_MAC_2, reservedAddr);
+
+        // Update from /22 to /28 and add another reserved address
+        Set<Inet4Address> newReserved = new HashSet<>(TEST_EXCL_SET);
+        newReserved.add(reservedAddr);
+        mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), newReserved, TEST_LEASE_TIME_MS);
+
+        assertHasLease(reqAddrIn28Lease);
+        assertDeclined(declinedAddrIn28);
+
+        assertNotDeclined(declinedFirstAddrIn28);
+
+        assertNoLease(reqAddrIn22Lease);
+        assertNotDeclined(declinedAddrIn22);
+
+        assertNoLease(reservedAddrLease);
+    }
+
+    @Test
+    public void testGetOffer_StableAddress() throws Exception {
+        for (final MacAddress macAddr : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) {
+            final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr,
+                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+
+            // Same lease is offered twice
+            final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr,
+                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+            assertEquals(lease, newLease);
+        }
+    }
+
+    @Test
+    public void testUpdateParams_UsesNewPrefix() throws Exception {
+        final IpPrefix newPrefix = new IpPrefix(parseAddr4("192.168.123.0"), 24);
+        mRepo.updateParams(newPrefix, TEST_EXCL_SET, TEST_LEASE_TIME_MS);
+
+        DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
+                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+        assertTrue(newPrefix.contains(lease.getNetAddr()));
+    }
+
+    @Test
+    public void testGetOffer_ExistingLease() throws Exception {
+        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1, TEST_HOSTNAME_1);
+
+        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
+                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+        assertEquals(TEST_INETADDR_1, offer.getNetAddr());
+        assertEquals(TEST_HOSTNAME_1, offer.getHostname());
+    }
+
+    @Test
+    public void testGetOffer_ClientIdHasExistingLease() throws Exception {
+        final byte[] clientId = new byte[] { 1, 2 };
+        mRepo.requestLease(clientId, TEST_MAC_1, INET4_ANY /* clientAddr */,
+                INET4_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false, TEST_HOSTNAME_1);
+
+        // Different MAC, but same clientId
+        DhcpLease offer = mRepo.getOffer(clientId, TEST_MAC_2,
+                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+        assertEquals(TEST_INETADDR_1, offer.getNetAddr());
+        assertEquals(TEST_HOSTNAME_1, offer.getHostname());
+    }
+
+    @Test
+    public void testGetOffer_DifferentClientId() throws Exception {
+        final byte[] clientId1 = new byte[] { 1, 2 };
+        final byte[] clientId2 = new byte[] { 3, 4 };
+        mRepo.requestLease(clientId1, TEST_MAC_1, INET4_ANY /* clientAddr */,
+                INET4_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false, TEST_HOSTNAME_1);
+
+        // Same MAC, different client ID
+        DhcpLease offer = mRepo.getOffer(clientId2, TEST_MAC_1,
+                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+        // Obtains a different address
+        assertNotEquals(TEST_INETADDR_1, offer.getNetAddr());
+        assertEquals(HOSTNAME_NONE, offer.getHostname());
+        assertEquals(TEST_MAC_1, offer.getHwAddr());
+    }
+
+    @Test
+    public void testGetOffer_RequestedAddress() throws Exception {
+        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
+                TEST_INETADDR_1 /* reqAddr */, TEST_HOSTNAME_1);
+        assertEquals(TEST_INETADDR_1, offer.getNetAddr());
+        assertEquals(TEST_HOSTNAME_1, offer.getHostname());
+    }
+
+    @Test
+    public void testGetOffer_RequestedAddressInUse() throws Exception {
+        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
+        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2, INET4_ANY /* relayAddr */,
+                TEST_INETADDR_1 /* reqAddr */, HOSTNAME_NONE);
+        assertNotEquals(TEST_INETADDR_1, offer.getNetAddr());
+    }
+
+    @Test
+    public void testGetOffer_RequestedAddressReserved() throws Exception {
+        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
+                TEST_RESERVED_ADDR /* reqAddr */, HOSTNAME_NONE);
+        assertNotEquals(TEST_RESERVED_ADDR, offer.getNetAddr());
+    }
+
+    @Test
+    public void testGetOffer_RequestedAddressInvalid() throws Exception {
+        final Inet4Address invalidAddr = parseAddr4("192.168.42.0");
+        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
+                invalidAddr /* reqAddr */, HOSTNAME_NONE);
+        assertNotEquals(invalidAddr, offer.getNetAddr());
+    }
+
+    @Test
+    public void testGetOffer_RequestedAddressOutsideSubnet() throws Exception {
+        final Inet4Address invalidAddr = parseAddr4("192.168.254.2");
+        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
+                invalidAddr /* reqAddr */, HOSTNAME_NONE);
+        assertNotEquals(invalidAddr, offer.getNetAddr());
+    }
+
+    @Test(expected = DhcpLeaseRepository.InvalidSubnetException.class)
+    public void testGetOffer_RelayInInvalidSubnet() throws Exception {
+        mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, parseAddr4("192.168.254.2") /* relayAddr */,
+                INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+    }
+
+    @Test
+    public void testRequestLease_SelectingTwice() throws Exception {
+        final DhcpLease lease1 = requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1,
+                TEST_HOSTNAME_1);
+
+        // Second request from same client for a different address
+        final DhcpLease lease2 = requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_2,
+                TEST_HOSTNAME_2);
+
+        assertEquals(TEST_INETADDR_1, lease1.getNetAddr());
+        assertEquals(TEST_HOSTNAME_1, lease1.getHostname());
+
+        assertEquals(TEST_INETADDR_2, lease2.getNetAddr());
+        assertEquals(TEST_HOSTNAME_2, lease2.getHostname());
+
+        // First address freed when client requested a different one: another client can request it
+        final DhcpLease lease3 = requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1, HOSTNAME_NONE);
+        assertEquals(TEST_INETADDR_1, lease3.getNetAddr());
+    }
+
+    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
+    public void testRequestLease_SelectingInvalid() throws Exception {
+        requestLeaseSelecting(TEST_MAC_1, parseAddr4("192.168.254.5"));
+    }
+
+    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
+    public void testRequestLease_SelectingInUse() throws Exception {
+        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
+        requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1);
+    }
+
+    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
+    public void testRequestLease_SelectingReserved() throws Exception {
+        requestLeaseSelecting(TEST_MAC_1, TEST_RESERVED_ADDR);
+    }
+
+    @Test(expected = DhcpLeaseRepository.InvalidSubnetException.class)
+    public void testRequestLease_SelectingRelayInInvalidSubnet() throws  Exception {
+        mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* clientAddr */,
+                parseAddr4("192.168.128.1") /* relayAddr */, TEST_INETADDR_1 /* reqAddr */,
+                true /* sidSet */, HOSTNAME_NONE);
+    }
+
+    @Test
+    public void testRequestLease_InitReboot() throws Exception {
+        // Request address once
+        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
+
+        final long newTime = TEST_TIME + 100;
+        when(mClock.elapsedRealtime()).thenReturn(newTime);
+
+        // init-reboot (sidSet == false): verify configuration
+        final DhcpLease lease = requestLeaseInitReboot(TEST_MAC_1, TEST_INETADDR_1);
+        assertEquals(TEST_INETADDR_1, lease.getNetAddr());
+        assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime());
+    }
+
+    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
+    public void testRequestLease_InitRebootWrongAddr() throws Exception {
+        // Request address once
+        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
+        // init-reboot with different requested address
+        requestLeaseInitReboot(TEST_MAC_1, TEST_INETADDR_2);
+    }
+
+    @Test
+    public void testRequestLease_InitRebootUnknownAddr() throws Exception {
+        // init-reboot with unknown requested address
+        final DhcpLease lease = requestLeaseInitReboot(TEST_MAC_1, TEST_INETADDR_2);
+        // RFC2131 says we should not reply to accommodate other servers, but since we are
+        // authoritative we allow creating the lease to avoid issues with lost lease DB (same as
+        // dnsmasq behavior)
+        assertEquals(TEST_INETADDR_2, lease.getNetAddr());
+    }
+
+    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
+    public void testRequestLease_InitRebootWrongSubnet() throws Exception {
+        requestLeaseInitReboot(TEST_MAC_1, parseAddr4("192.168.254.2"));
+    }
+
+    @Test
+    public void testRequestLease_Renewing() throws Exception {
+        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
+
+        final long newTime = TEST_TIME + 100;
+        when(mClock.elapsedRealtime()).thenReturn(newTime);
+
+        final DhcpLease lease = requestLeaseRenewing(TEST_MAC_1, TEST_INETADDR_1);
+
+        assertEquals(TEST_INETADDR_1, lease.getNetAddr());
+        assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime());
+    }
+
+    @Test
+    public void testRequestLease_RenewingUnknownAddr() throws Exception {
+        final long newTime = TEST_TIME + 100;
+        when(mClock.elapsedRealtime()).thenReturn(newTime);
+        final DhcpLease lease = requestLeaseRenewing(TEST_MAC_1, TEST_INETADDR_1);
+        // Allows renewing an unknown address if available
+        assertEquals(TEST_INETADDR_1, lease.getNetAddr());
+        assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime());
+    }
+
+    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
+    public void testRequestLease_RenewingAddrInUse() throws Exception {
+        requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1);
+        requestLeaseRenewing(TEST_MAC_1, TEST_INETADDR_1);
+    }
+
+    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
+    public void testRequestLease_RenewingInvalidAddr() throws Exception {
+        requestLeaseRenewing(TEST_MAC_1, parseAddr4("192.168.254.2"));
+    }
+
+    @Test
+    public void testReleaseLease() throws Exception {
+        final DhcpLease lease1 = requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
+
+        assertHasLease(lease1);
+        assertTrue(mRepo.releaseLease(CLIENTID_UNSPEC, TEST_MAC_1, TEST_INETADDR_1));
+        assertNoLease(lease1);
+
+        final DhcpLease lease2 = requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1);
+        assertEquals(TEST_INETADDR_1, lease2.getNetAddr());
+    }
+
+    @Test
+    public void testReleaseLease_UnknownLease() {
+        assertFalse(mRepo.releaseLease(CLIENTID_UNSPEC, TEST_MAC_1, TEST_INETADDR_1));
+    }
+
+    @Test
+    public void testReleaseLease_StableOffer() throws Exception {
+        for (MacAddress mac : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) {
+            final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, mac,
+                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+
+            requestLeaseSelecting(mac, lease.getNetAddr());
+            mRepo.releaseLease(CLIENTID_UNSPEC, mac, lease.getNetAddr());
+
+            // Same lease is offered after it was released
+            final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, mac,
+                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+            assertEquals(lease.getNetAddr(), newLease.getNetAddr());
+        }
+    }
+
+    @Test
+    public void testMarkLeaseDeclined() throws Exception {
+        final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
+                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+
+        mRepo.markLeaseDeclined(lease.getNetAddr());
+
+        // Same lease is not offered again
+        final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
+                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+        assertNotEquals(lease.getNetAddr(), newLease.getNetAddr());
+    }
+
+    @Test
+    public void testMarkLeaseDeclined_UsedIfOutOfAddresses() throws Exception {
+        // Use a /28 to quickly run out of addresses
+        mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), TEST_EXCL_SET, TEST_LEASE_TIME_MS);
+
+        mRepo.markLeaseDeclined(TEST_INETADDR_1);
+        mRepo.markLeaseDeclined(TEST_INETADDR_2);
+
+        // /28 should have 16 addresses, 14 w/o the first/last, 11 w/o excluded addresses
+        requestAddresses((byte) 9);
+
+        // Last 2 addresses: addresses marked declined should be used
+        final DhcpLease firstLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
+                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_1);
+        requestLeaseSelecting(TEST_MAC_1, firstLease.getNetAddr());
+
+        final DhcpLease secondLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2,
+                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_2);
+        requestLeaseSelecting(TEST_MAC_2, secondLease.getNetAddr());
+
+        // Now out of addresses
+        try {
+            mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_3, INET4_ANY /* relayAddr */,
+                    INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+            fail("Repository should be out of addresses and throw");
+        } catch (DhcpLeaseRepository.OutOfAddressesException e) { /* expected */ }
+
+        assertEquals(TEST_INETADDR_1, firstLease.getNetAddr());
+        assertEquals(TEST_HOSTNAME_1, firstLease.getHostname());
+        assertEquals(TEST_INETADDR_2, secondLease.getNetAddr());
+        assertEquals(TEST_HOSTNAME_2, secondLease.getHostname());
+    }
+
+    private DhcpLease requestLease(@NonNull MacAddress macAddr, @NonNull Inet4Address clientAddr,
+            @Nullable Inet4Address reqAddr, @Nullable String hostname, boolean sidSet)
+            throws DhcpLeaseRepository.DhcpLeaseException {
+        return mRepo.requestLease(CLIENTID_UNSPEC, macAddr, clientAddr, INET4_ANY /* relayAddr */,
+                reqAddr, sidSet, hostname);
+    }
+
+    /**
+     * Request a lease simulating a client in the SELECTING state.
+     */
+    private DhcpLease requestLeaseSelecting(@NonNull MacAddress macAddr,
+            @NonNull Inet4Address reqAddr, @Nullable String hostname)
+            throws DhcpLeaseRepository.DhcpLeaseException {
+        return requestLease(macAddr, INET4_ANY /* clientAddr */, reqAddr, hostname,
+                true /* sidSet */);
+    }
+
+    /**
+     * Request a lease simulating a client in the SELECTING state.
+     */
+    private DhcpLease requestLeaseSelecting(@NonNull MacAddress macAddr,
+            @NonNull Inet4Address reqAddr) throws DhcpLeaseRepository.DhcpLeaseException {
+        return requestLeaseSelecting(macAddr, reqAddr, HOSTNAME_NONE);
+    }
+
+    /**
+     * Request a lease simulating a client in the INIT-REBOOT state.
+     */
+    private DhcpLease requestLeaseInitReboot(@NonNull MacAddress macAddr,
+            @NonNull Inet4Address reqAddr) throws DhcpLeaseRepository.DhcpLeaseException {
+        return requestLease(macAddr, INET4_ANY /* clientAddr */, reqAddr, HOSTNAME_NONE,
+                false /* sidSet */);
+    }
+
+    /**
+     * Request a lease simulating a client in the RENEWING state.
+     */
+    private DhcpLease requestLeaseRenewing(@NonNull MacAddress macAddr,
+            @NonNull Inet4Address clientAddr) throws DhcpLeaseRepository.DhcpLeaseException {
+        // Renewing: clientAddr filled in, no reqAddr
+        return requestLease(macAddr, clientAddr, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE,
+                true /* sidSet */);
+    }
+
+    private void assertNoLease(DhcpLease lease) {
+        assertFalse("Leases contain " + lease, mRepo.getCommittedLeases().contains(lease));
+    }
+
+    private void assertHasLease(DhcpLease lease) {
+        assertTrue("Leases do not contain " + lease, mRepo.getCommittedLeases().contains(lease));
+    }
+
+    private void assertNotDeclined(Inet4Address addr) {
+        assertFalse("Address is declined: " + addr, mRepo.getDeclinedAddresses().contains(addr));
+    }
+
+    private void assertDeclined(Inet4Address addr) {
+        assertTrue("Address is not declined: " + addr, mRepo.getDeclinedAddresses().contains(addr));
+    }
+}
diff --git a/tests/net/java/android/net/dhcp/DhcpPacketTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java
similarity index 100%
rename from tests/net/java/android/net/dhcp/DhcpPacketTest.java
rename to packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServerTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServerTest.java
new file mode 100644
index 0000000..d4c1e2e
--- /dev/null
+++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServerTest.java
@@ -0,0 +1,327 @@
+/*
+ * 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.dhcp;
+
+import static android.net.InetAddresses.parseNumericAddress;
+import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
+import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
+import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
+import static android.net.dhcp.DhcpPacket.INADDR_ANY;
+import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST;
+import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
+
+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.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doNothing;
+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 static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.INetworkStackStatusCallback;
+import android.net.LinkAddress;
+import android.net.MacAddress;
+import android.net.dhcp.DhcpLeaseRepository.InvalidAddressException;
+import android.net.dhcp.DhcpLeaseRepository.OutOfAddressesException;
+import android.net.dhcp.DhcpServer.Clock;
+import android.net.dhcp.DhcpServer.Dependencies;
+import android.net.util.SharedLog;
+import android.os.HandlerThread;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.net.Inet4Address;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+@RunWithLooper
+public class DhcpServerTest {
+    private static final String TEST_IFACE = "testiface";
+
+    private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2");
+    private static final LinkAddress TEST_SERVER_LINKADDR = new LinkAddress(TEST_SERVER_ADDR, 20);
+    private static final Set<Inet4Address> TEST_DEFAULT_ROUTERS = new HashSet<>(
+            Arrays.asList(parseAddr("192.168.0.123"), parseAddr("192.168.0.124")));
+    private static final Set<Inet4Address> TEST_DNS_SERVERS = new HashSet<>(
+            Arrays.asList(parseAddr("192.168.0.126"), parseAddr("192.168.0.127")));
+    private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>(
+            Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201")));
+    private static final long TEST_LEASE_TIME_SECS = 3600L;
+    private static final int TEST_MTU = 1500;
+    private static final String TEST_HOSTNAME = "testhostname";
+
+    private static final int TEST_TRANSACTION_ID = 123;
+    private static final byte[] TEST_CLIENT_MAC_BYTES = new byte [] { 1, 2, 3, 4, 5, 6 };
+    private static final MacAddress TEST_CLIENT_MAC = MacAddress.fromBytes(TEST_CLIENT_MAC_BYTES);
+    private static final Inet4Address TEST_CLIENT_ADDR = parseAddr("192.168.0.42");
+
+    private static final long TEST_CLOCK_TIME = 1234L;
+    private static final int TEST_LEASE_EXPTIME_SECS = 3600;
+    private static final DhcpLease TEST_LEASE = new DhcpLease(null, TEST_CLIENT_MAC,
+            TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME,
+            null /* hostname */);
+    private static final DhcpLease TEST_LEASE_WITH_HOSTNAME = new DhcpLease(null, TEST_CLIENT_MAC,
+            TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, TEST_HOSTNAME);
+
+    @NonNull @Mock
+    private Dependencies mDeps;
+    @NonNull @Mock
+    private DhcpLeaseRepository mRepository;
+    @NonNull @Mock
+    private Clock mClock;
+    @NonNull @Mock
+    private DhcpPacketListener mPacketListener;
+
+    @NonNull @Captor
+    private ArgumentCaptor<ByteBuffer> mSentPacketCaptor;
+    @NonNull @Captor
+    private ArgumentCaptor<Inet4Address> mResponseDstAddrCaptor;
+
+    @NonNull
+    private HandlerThread mHandlerThread;
+    @NonNull
+    private TestableLooper mLooper;
+    @NonNull
+    private DhcpServer mServer;
+
+    @Nullable
+    private String mPrevShareClassloaderProp;
+
+    private final INetworkStackStatusCallback mAssertSuccessCallback =
+            new INetworkStackStatusCallback.Stub() {
+        @Override
+        public void onStatusAvailable(int statusCode) {
+            assertEquals(STATUS_SUCCESS, statusCode);
+        }
+    };
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        when(mDeps.makeLeaseRepository(any(), any(), any())).thenReturn(mRepository);
+        when(mDeps.makeClock()).thenReturn(mClock);
+        when(mDeps.makePacketListener()).thenReturn(mPacketListener);
+        doNothing().when(mDeps)
+                .sendPacket(any(), mSentPacketCaptor.capture(), mResponseDstAddrCaptor.capture());
+        when(mClock.elapsedRealtime()).thenReturn(TEST_CLOCK_TIME);
+
+        final DhcpServingParams servingParams = new DhcpServingParams.Builder()
+                .setDefaultRouters(TEST_DEFAULT_ROUTERS)
+                .setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS)
+                .setDnsServers(TEST_DNS_SERVERS)
+                .setServerAddr(TEST_SERVER_LINKADDR)
+                .setLinkMtu(TEST_MTU)
+                .setExcludedAddrs(TEST_EXCLUDED_ADDRS)
+                .build();
+
+        mLooper = TestableLooper.get(this);
+        mHandlerThread = spy(new HandlerThread("TestDhcpServer"));
+        when(mHandlerThread.getLooper()).thenReturn(mLooper.getLooper());
+        mServer = new DhcpServer(mHandlerThread, TEST_IFACE, servingParams,
+                new SharedLog(DhcpServerTest.class.getSimpleName()), mDeps);
+
+        mServer.start(mAssertSuccessCallback);
+        mLooper.processAllMessages();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mServer.stop(mAssertSuccessCallback);
+        mLooper.processMessages(1);
+        verify(mPacketListener, times(1)).stop();
+        verify(mHandlerThread, times(1)).quitSafely();
+    }
+
+    @Test
+    public void testStart() throws Exception {
+        verify(mPacketListener, times(1)).start();
+    }
+
+    @Test
+    public void testDiscover() throws Exception {
+        // TODO: refactor packet construction to eliminate unnecessary/confusing/duplicate fields
+        when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
+                eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */))
+                .thenReturn(TEST_LEASE);
+
+        final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID,
+                (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES,
+                false /* broadcast */, INADDR_ANY /* srcIp */);
+        mServer.processPacket(discover, DHCP_CLIENT);
+
+        assertResponseSentTo(TEST_CLIENT_ADDR);
+        final DhcpOfferPacket packet = assertOffer(getPacket());
+        assertMatchesTestLease(packet);
+    }
+
+    @Test
+    public void testDiscover_OutOfAddresses() throws Exception {
+        when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
+                eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */))
+                .thenThrow(new OutOfAddressesException("Test exception"));
+
+        final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID,
+                (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES,
+                false /* broadcast */, INADDR_ANY /* srcIp */);
+        mServer.processPacket(discover, DHCP_CLIENT);
+
+        assertResponseSentTo(INADDR_BROADCAST);
+        final DhcpNakPacket packet = assertNak(getPacket());
+        assertMatchesClient(packet);
+    }
+
+    private DhcpRequestPacket makeRequestSelectingPacket() {
+        final DhcpRequestPacket request = new DhcpRequestPacket(TEST_TRANSACTION_ID,
+                (short) 0 /* secs */, INADDR_ANY /* clientIp */, INADDR_ANY /* relayIp */,
+                TEST_CLIENT_MAC_BYTES, false /* broadcast */);
+        request.mServerIdentifier = TEST_SERVER_ADDR;
+        request.mRequestedIp = TEST_CLIENT_ADDR;
+        return request;
+    }
+
+    @Test
+    public void testRequest_Selecting_Ack() throws Exception {
+        when(mRepository.requestLease(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
+                eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */,
+                eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, eq(TEST_HOSTNAME)))
+                .thenReturn(TEST_LEASE_WITH_HOSTNAME);
+
+        final DhcpRequestPacket request = makeRequestSelectingPacket();
+        request.mHostName = TEST_HOSTNAME;
+        request.mRequestedParams = new byte[] { DHCP_HOST_NAME };
+        mServer.processPacket(request, DHCP_CLIENT);
+
+        assertResponseSentTo(TEST_CLIENT_ADDR);
+        final DhcpAckPacket packet = assertAck(getPacket());
+        assertMatchesTestLease(packet, TEST_HOSTNAME);
+    }
+
+    @Test
+    public void testRequest_Selecting_Nak() throws Exception {
+        when(mRepository.requestLease(isNull(), eq(TEST_CLIENT_MAC),
+                eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */,
+                eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, isNull() /* hostname */))
+                .thenThrow(new InvalidAddressException("Test error"));
+
+        final DhcpRequestPacket request = makeRequestSelectingPacket();
+        mServer.processPacket(request, DHCP_CLIENT);
+
+        assertResponseSentTo(INADDR_BROADCAST);
+        final DhcpNakPacket packet = assertNak(getPacket());
+        assertMatchesClient(packet);
+    }
+
+    @Test
+    public void testRequest_Selecting_WrongClientPort() throws Exception {
+        final DhcpRequestPacket request = makeRequestSelectingPacket();
+        mServer.processPacket(request, 50000);
+
+        verify(mRepository, never())
+                .requestLease(any(), any(), any(), any(), any(), anyBoolean(), any());
+        verify(mDeps, never()).sendPacket(any(), any(), any());
+    }
+
+    @Test
+    public void testRelease() throws Exception {
+        final DhcpReleasePacket release = new DhcpReleasePacket(TEST_TRANSACTION_ID,
+                TEST_SERVER_ADDR, TEST_CLIENT_ADDR,
+                INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES);
+        mServer.processPacket(release, DHCP_CLIENT);
+
+        verify(mRepository, times(1))
+                .releaseLease(isNull(), eq(TEST_CLIENT_MAC), eq(TEST_CLIENT_ADDR));
+    }
+
+    /* TODO: add more tests once packet construction is refactored, including:
+     *  - usage of giaddr
+     *  - usage of broadcast bit
+     *  - other request states (init-reboot/renewing/rebinding)
+     */
+
+    private void assertMatchesTestLease(@NonNull DhcpPacket packet, @Nullable String hostname) {
+        assertMatchesClient(packet);
+        assertFalse(packet.hasExplicitClientId());
+        assertEquals(TEST_SERVER_ADDR, packet.mServerIdentifier);
+        assertEquals(TEST_CLIENT_ADDR, packet.mYourIp);
+        assertNotNull(packet.mLeaseTime);
+        assertEquals(TEST_LEASE_EXPTIME_SECS, (int) packet.mLeaseTime);
+        assertEquals(hostname, packet.mHostName);
+    }
+
+    private void assertMatchesTestLease(@NonNull DhcpPacket packet) {
+        assertMatchesTestLease(packet, null);
+    }
+
+    private void assertMatchesClient(@NonNull DhcpPacket packet) {
+        assertEquals(TEST_TRANSACTION_ID, packet.mTransId);
+        assertEquals(TEST_CLIENT_MAC, MacAddress.fromBytes(packet.mClientMac));
+    }
+
+    private void assertResponseSentTo(@NonNull Inet4Address addr) {
+        assertEquals(addr, mResponseDstAddrCaptor.getValue());
+    }
+
+    private static DhcpNakPacket assertNak(@Nullable DhcpPacket packet) {
+        assertTrue(packet instanceof DhcpNakPacket);
+        return (DhcpNakPacket) packet;
+    }
+
+    private static DhcpAckPacket assertAck(@Nullable DhcpPacket packet) {
+        assertTrue(packet instanceof DhcpAckPacket);
+        return (DhcpAckPacket) packet;
+    }
+
+    private static DhcpOfferPacket assertOffer(@Nullable DhcpPacket packet) {
+        assertTrue(packet instanceof DhcpOfferPacket);
+        return (DhcpOfferPacket) packet;
+    }
+
+    private DhcpPacket getPacket() throws Exception {
+        verify(mDeps, times(1)).sendPacket(any(), any(), any());
+        return DhcpPacket.decodeFullPacket(mSentPacketCaptor.getValue(), ENCAP_BOOTP);
+    }
+
+    private static Inet4Address parseAddr(@Nullable String inet4Addr) {
+        return (Inet4Address) parseNumericAddress(inet4Addr);
+    }
+}
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java
new file mode 100644
index 0000000..3ca0564
--- /dev/null
+++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java
@@ -0,0 +1,220 @@
+/*
+ * 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.dhcp;
+
+import static android.net.InetAddresses.parseNumericAddress;
+import static android.net.NetworkUtils.inet4AddressToIntHTH;
+import static android.net.dhcp.DhcpServingParams.MTU_UNSET;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.LinkAddress;
+import android.net.NetworkUtils;
+import android.net.dhcp.DhcpServingParams.InvalidParameterException;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Modifier;
+import java.net.Inet4Address;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DhcpServingParamsTest {
+    @NonNull
+    private DhcpServingParams.Builder mBuilder;
+
+    private static final Set<Inet4Address> TEST_DEFAULT_ROUTERS = new HashSet<>(
+            Arrays.asList(parseAddr("192.168.0.123"), parseAddr("192.168.0.124")));
+    private static final long TEST_LEASE_TIME_SECS = 3600L;
+    private static final Set<Inet4Address> TEST_DNS_SERVERS = new HashSet<>(
+            Arrays.asList(parseAddr("192.168.0.126"), parseAddr("192.168.0.127")));
+    private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2");
+    private static final LinkAddress TEST_LINKADDR = new LinkAddress(TEST_SERVER_ADDR, 20);
+    private static final int TEST_MTU = 1500;
+    private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>(
+            Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201")));
+    private static final boolean TEST_METERED = true;
+
+    @Before
+    public void setUp() {
+        mBuilder = new DhcpServingParams.Builder()
+                .setDefaultRouters(TEST_DEFAULT_ROUTERS)
+                .setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS)
+                .setDnsServers(TEST_DNS_SERVERS)
+                .setServerAddr(TEST_LINKADDR)
+                .setLinkMtu(TEST_MTU)
+                .setExcludedAddrs(TEST_EXCLUDED_ADDRS)
+                .setMetered(TEST_METERED);
+    }
+
+    @Test
+    public void testBuild_Immutable() throws InvalidParameterException {
+        final Set<Inet4Address> routers = new HashSet<>(TEST_DEFAULT_ROUTERS);
+        final Set<Inet4Address> dnsServers = new HashSet<>(TEST_DNS_SERVERS);
+        final Set<Inet4Address> excludedAddrs = new HashSet<>(TEST_EXCLUDED_ADDRS);
+
+        final DhcpServingParams params = mBuilder
+                .setDefaultRouters(routers)
+                .setDnsServers(dnsServers)
+                .setExcludedAddrs(excludedAddrs)
+                .build();
+
+        // Modifications to source objects should not affect builder or final parameters
+        final Inet4Address addedAddr = parseAddr("192.168.0.223");
+        routers.add(addedAddr);
+        dnsServers.add(addedAddr);
+        excludedAddrs.add(addedAddr);
+
+        assertEquals(TEST_DEFAULT_ROUTERS, params.defaultRouters);
+        assertEquals(TEST_LEASE_TIME_SECS, params.dhcpLeaseTimeSecs);
+        assertEquals(TEST_DNS_SERVERS, params.dnsServers);
+        assertEquals(TEST_LINKADDR, params.serverAddr);
+        assertEquals(TEST_MTU, params.linkMtu);
+        assertEquals(TEST_METERED, params.metered);
+
+        assertContains(params.excludedAddrs, TEST_EXCLUDED_ADDRS);
+        assertContains(params.excludedAddrs, TEST_DEFAULT_ROUTERS);
+        assertContains(params.excludedAddrs, TEST_DNS_SERVERS);
+        assertContains(params.excludedAddrs, TEST_SERVER_ADDR);
+
+        assertFalse("excludedAddrs should not contain " + addedAddr,
+                params.excludedAddrs.contains(addedAddr));
+    }
+
+    @Test(expected = InvalidParameterException.class)
+    public void testBuild_NegativeLeaseTime() throws InvalidParameterException {
+        mBuilder.setDhcpLeaseTimeSecs(-1).build();
+    }
+
+    @Test(expected = InvalidParameterException.class)
+    public void testBuild_LeaseTimeTooLarge() throws InvalidParameterException {
+        // Set lease time larger than max value for uint32
+        mBuilder.setDhcpLeaseTimeSecs(1L << 32).build();
+    }
+
+    @Test
+    public void testBuild_InfiniteLeaseTime() throws InvalidParameterException {
+        final long infiniteLeaseTime = 0xffffffffL;
+        final DhcpServingParams params = mBuilder
+                .setDhcpLeaseTimeSecs(infiniteLeaseTime).build();
+        assertEquals(infiniteLeaseTime, params.dhcpLeaseTimeSecs);
+        assertTrue(params.dhcpLeaseTimeSecs > 0L);
+    }
+
+    @Test
+    public void testBuild_UnsetMtu() throws InvalidParameterException {
+        final DhcpServingParams params = mBuilder.setLinkMtu(MTU_UNSET).build();
+        assertEquals(MTU_UNSET, params.linkMtu);
+    }
+
+    @Test(expected = InvalidParameterException.class)
+    public void testBuild_MtuTooSmall() throws InvalidParameterException {
+        mBuilder.setLinkMtu(20).build();
+    }
+
+    @Test(expected = InvalidParameterException.class)
+    public void testBuild_MtuTooLarge() throws InvalidParameterException {
+        mBuilder.setLinkMtu(65_536).build();
+    }
+
+    @Test(expected = InvalidParameterException.class)
+    public void testBuild_IPv6Addr() throws InvalidParameterException {
+        mBuilder.setServerAddr(new LinkAddress(parseNumericAddress("fe80::1111"), 120)).build();
+    }
+
+    @Test(expected = InvalidParameterException.class)
+    public void testBuild_PrefixTooLarge() throws InvalidParameterException {
+        mBuilder.setServerAddr(new LinkAddress(TEST_SERVER_ADDR, 15)).build();
+    }
+
+    @Test(expected = InvalidParameterException.class)
+    public void testBuild_PrefixTooSmall() throws InvalidParameterException {
+        mBuilder.setDefaultRouters(parseAddr("192.168.0.254"))
+                .setServerAddr(new LinkAddress(TEST_SERVER_ADDR, 31))
+                .build();
+    }
+
+    @Test(expected = InvalidParameterException.class)
+    public void testBuild_RouterNotInPrefix() throws InvalidParameterException {
+        mBuilder.setDefaultRouters(parseAddr("192.168.254.254")).build();
+    }
+
+    @Test
+    public void testFromParcelableObject() throws InvalidParameterException {
+        final DhcpServingParams params = mBuilder.build();
+        final DhcpServingParamsParcel parcel = new DhcpServingParamsParcel();
+        parcel.defaultRouters = toIntArray(TEST_DEFAULT_ROUTERS);
+        parcel.dhcpLeaseTimeSecs = TEST_LEASE_TIME_SECS;
+        parcel.dnsServers = toIntArray(TEST_DNS_SERVERS);
+        parcel.serverAddr = inet4AddressToIntHTH(TEST_SERVER_ADDR);
+        parcel.serverAddrPrefixLength = TEST_LINKADDR.getPrefixLength();
+        parcel.linkMtu = TEST_MTU;
+        parcel.excludedAddrs = toIntArray(TEST_EXCLUDED_ADDRS);
+        parcel.metered = TEST_METERED;
+        final DhcpServingParams parceled = DhcpServingParams.fromParcelableObject(parcel);
+
+        assertEquals(params.defaultRouters, parceled.defaultRouters);
+        assertEquals(params.dhcpLeaseTimeSecs, parceled.dhcpLeaseTimeSecs);
+        assertEquals(params.dnsServers, parceled.dnsServers);
+        assertEquals(params.serverAddr, parceled.serverAddr);
+        assertEquals(params.linkMtu, parceled.linkMtu);
+        assertEquals(params.excludedAddrs, parceled.excludedAddrs);
+        assertEquals(params.metered, parceled.metered);
+
+        // Ensure that we do not miss any field if added in the future
+        final long numFields = Arrays.stream(DhcpServingParams.class.getDeclaredFields())
+                .filter(f -> !Modifier.isStatic(f.getModifiers()))
+                .count();
+        assertEquals(7, numFields);
+    }
+
+    @Test(expected = InvalidParameterException.class)
+    public void testFromParcelableObject_NullArgument() throws InvalidParameterException {
+        DhcpServingParams.fromParcelableObject(null);
+    }
+
+    private static int[] toIntArray(Collection<Inet4Address> addrs) {
+        return addrs.stream().mapToInt(NetworkUtils::inet4AddressToIntHTH).toArray();
+    }
+
+    private static <T> void assertContains(@NonNull Set<T> set, @NonNull Set<T> subset) {
+        for (final T elem : subset) {
+            assertContains(set, elem);
+        }
+    }
+
+    private static <T> void assertContains(@NonNull Set<T> set, @Nullable T elem) {
+        assertTrue("Set does not contain " + elem, set.contains(elem));
+    }
+
+    @NonNull
+    private static Inet4Address parseAddr(@NonNull String inet4Addr) {
+        return (Inet4Address) parseNumericAddress(inet4Addr);
+    }
+}
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
new file mode 100644
index 0000000..f21809f
--- /dev/null
+++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.INetd;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.MacAddress;
+import android.net.RouteInfo;
+import android.net.shared.InitialConfiguration;
+import android.net.shared.ProvisioningConfiguration;
+import android.net.util.InterfaceParams;
+import android.os.INetworkManagementService;
+import android.provider.Settings;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.mock.MockContentResolver;
+
+import com.android.internal.R;
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.net.BaseNetworkObserver;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Tests for IpClient.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpClientTest {
+    private static final int DEFAULT_AVOIDBADWIFI_CONFIG_VALUE = 1;
+
+    private static final String VALID = "VALID";
+    private static final String INVALID = "INVALID";
+    private static final String TEST_IFNAME = "test_wlan0";
+    private static final int TEST_IFINDEX = 1001;
+    // See RFC 7042#section-2.1.2 for EUI-48 documentation values.
+    private static final MacAddress TEST_MAC = MacAddress.fromString("00:00:5E:00:53:01");
+    private static final int TEST_TIMEOUT_MS = 400;
+
+    @Mock private Context mContext;
+    @Mock private ConnectivityManager mCm;
+    @Mock private INetworkManagementService mNMService;
+    @Mock private INetd mNetd;
+    @Mock private Resources mResources;
+    @Mock private IIpClientCallbacks mCb;
+    @Mock private AlarmManager mAlarm;
+    @Mock private IpClient.Dependencies mDependecies;
+    private MockContentResolver mContentResolver;
+
+    private BaseNetworkObserver mObserver;
+    private InterfaceParams mIfParams;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
+        when(mContext.getSystemServiceName(ConnectivityManager.class))
+                .thenReturn(Context.CONNECTIVITY_SERVICE);
+        when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mCm);
+        when(mContext.getResources()).thenReturn(mResources);
+        when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
+                .thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
+
+        mContentResolver = new MockContentResolver();
+        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
+
+        mIfParams = null;
+
+        when(mDependecies.getNMS()).thenReturn(mNMService);
+        when(mDependecies.getNetd()).thenReturn(mNetd);
+    }
+
+    private void setTestInterfaceParams(String ifname) {
+        mIfParams = (ifname != null)
+                ? new InterfaceParams(ifname, TEST_IFINDEX, TEST_MAC)
+                : null;
+        when(mDependecies.getInterfaceParams(anyString())).thenReturn(mIfParams);
+    }
+
+    private IpClient makeIpClient(String ifname) throws Exception {
+        setTestInterfaceParams(ifname);
+        final IpClient ipc = new IpClient(mContext, ifname, mCb, mDependecies);
+        verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false);
+        verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname);
+        ArgumentCaptor<BaseNetworkObserver> arg =
+                ArgumentCaptor.forClass(BaseNetworkObserver.class);
+        verify(mNMService, times(1)).registerObserver(arg.capture());
+        mObserver = arg.getValue();
+        reset(mNMService);
+        reset(mNetd);
+        // Verify IpClient doesn't call onLinkPropertiesChange() when it starts.
+        verify(mCb, never()).onLinkPropertiesChange(any());
+        reset(mCb);
+        return ipc;
+    }
+
+    private static LinkProperties makeEmptyLinkProperties(String iface) {
+        final LinkProperties empty = new LinkProperties();
+        empty.setInterfaceName(iface);
+        return empty;
+    }
+
+    @Test
+    public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
+        setTestInterfaceParams(null);
+        try {
+            final IpClient ipc = new IpClient(mContext, null, mCb, mDependecies);
+            ipc.shutdown();
+            fail();
+        } catch (NullPointerException npe) {
+            // Phew; null interface names not allowed.
+        }
+    }
+
+    @Test
+    public void testNullCallbackMostDefinitelyThrows() throws Exception {
+        final String ifname = "lo";
+        setTestInterfaceParams(ifname);
+        try {
+            final IpClient ipc = new IpClient(mContext, ifname, null, mDependecies);
+            ipc.shutdown();
+            fail();
+        } catch (NullPointerException npe) {
+            // Phew; null callbacks not allowed.
+        }
+    }
+
+    @Test
+    public void testInvalidInterfaceDoesNotThrow() throws Exception {
+        setTestInterfaceParams(TEST_IFNAME);
+        final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mDependecies);
+        ipc.shutdown();
+    }
+
+    @Test
+    public void testInterfaceNotFoundFailsImmediately() throws Exception {
+        setTestInterfaceParams(null);
+        final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mDependecies);
+        ipc.startProvisioning(new ProvisioningConfiguration());
+        verify(mCb, times(1)).onProvisioningFailure(any());
+        ipc.shutdown();
+    }
+
+    @Test
+    public void testDefaultProvisioningConfiguration() throws Exception {
+        final String iface = TEST_IFNAME;
+        final IpClient ipc = makeIpClient(iface);
+
+        ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
+                .withoutIPv4()
+                // TODO: mock IpReachabilityMonitor's dependencies (NetworkInterface, PowerManager)
+                // and enable it in this test
+                .withoutIpReachabilityMonitor()
+                .build();
+
+        ipc.startProvisioning(config);
+        verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
+        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
+        verify(mCb, never()).onProvisioningFailure(any());
+
+        ipc.shutdown();
+        verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
+        verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface);
+        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
+                .onLinkPropertiesChange(argThat(
+                        lp -> fromStableParcelable(lp).equals(makeEmptyLinkProperties(iface))));
+    }
+
+    @Test
+    public void testProvisioningWithInitialConfiguration() throws Exception {
+        final String iface = TEST_IFNAME;
+        final IpClient ipc = makeIpClient(iface);
+
+        String[] addresses = {
+            "fe80::a4be:f92:e1f7:22d1/64",
+            "fe80::f04a:8f6:6a32:d756/64",
+            "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"
+        };
+        String[] prefixes = { "fe80::/64", "fd2c:4e57:8e3c::/64" };
+
+        ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
+                .withoutIPv4()
+                .withoutIpReachabilityMonitor()
+                .withInitialConfiguration(conf(links(addresses), prefixes(prefixes), ips()))
+                .build();
+
+        ipc.startProvisioning(config);
+        verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
+        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
+        verify(mCb, never()).onProvisioningFailure(any());
+
+        for (String addr : addresses) {
+            String[] parts = addr.split("/");
+            verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1))
+                    .interfaceAddAddress(iface, parts[0], Integer.parseInt(parts[1]));
+        }
+
+        final int lastAddr = addresses.length - 1;
+
+        // Add N - 1 addresses
+        for (int i = 0; i < lastAddr; i++) {
+            mObserver.addressUpdated(iface, new LinkAddress(addresses[i]));
+            verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(any());
+            reset(mCb);
+        }
+
+        // Add Nth address
+        mObserver.addressUpdated(iface, new LinkAddress(addresses[lastAddr]));
+        LinkProperties want = linkproperties(links(addresses), routes(prefixes));
+        want.setInterfaceName(iface);
+        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(argThat(
+                lp -> fromStableParcelable(lp).equals(want)));
+
+        ipc.shutdown();
+        verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
+        verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface);
+        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
+                .onLinkPropertiesChange(argThat(
+                        lp -> fromStableParcelable(lp).equals(makeEmptyLinkProperties(iface))));
+    }
+
+    @Test
+    public void testIsProvisioned() throws Exception {
+        InitialConfiguration empty = conf(links(), prefixes());
+        IsProvisionedTestCase[] testcases = {
+            // nothing
+            notProvisionedCase(links(), routes(), dns(), null),
+            notProvisionedCase(links(), routes(), dns(), empty),
+
+            // IPv4
+            provisionedCase(links("192.0.2.12/24"), routes(), dns(), empty),
+
+            // IPv6
+            notProvisionedCase(
+                    links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
+                    routes(), dns(), empty),
+            notProvisionedCase(
+                    links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
+                    routes("fe80::/64", "fd2c:4e57:8e3c::/64"), dns("fd00:1234:5678::1000"), empty),
+            provisionedCase(
+                    links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
+                    routes("::/0"),
+                    dns("2001:db8:dead:beef:f00::02"), empty),
+
+            // Initial configuration
+            provisionedCase(
+                    links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
+                    routes("fe80::/64", "fd2c:4e57:8e3c::/64"),
+                    dns(),
+                    conf(links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
+                        prefixes( "fe80::/64", "fd2c:4e57:8e3c::/64"), ips()))
+        };
+
+        for (IsProvisionedTestCase testcase : testcases) {
+            if (IpClient.isProvisioned(testcase.lp, testcase.config) != testcase.isProvisioned) {
+                fail(testcase.errorMessage());
+            }
+        }
+    }
+
+    static class IsProvisionedTestCase {
+        boolean isProvisioned;
+        LinkProperties lp;
+        InitialConfiguration config;
+
+        String errorMessage() {
+            return String.format("expected %s with config %s to be %s, but was %s",
+                     lp, config, provisioned(isProvisioned), provisioned(!isProvisioned));
+        }
+
+        static String provisioned(boolean isProvisioned) {
+            return isProvisioned ? "provisioned" : "not provisioned";
+        }
+    }
+
+    static IsProvisionedTestCase provisionedCase(Set<LinkAddress> lpAddrs, Set<RouteInfo> lpRoutes,
+            Set<InetAddress> lpDns, InitialConfiguration config) {
+        return provisioningTest(true, lpAddrs, lpRoutes, lpDns, config);
+    }
+
+    static IsProvisionedTestCase notProvisionedCase(Set<LinkAddress> lpAddrs,
+            Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
+        return provisioningTest(false, lpAddrs, lpRoutes, lpDns, config);
+    }
+
+    static IsProvisionedTestCase provisioningTest(boolean isProvisioned, Set<LinkAddress> lpAddrs,
+            Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
+        IsProvisionedTestCase testcase = new IsProvisionedTestCase();
+        testcase.isProvisioned = isProvisioned;
+        testcase.lp = new LinkProperties();
+        testcase.lp.setLinkAddresses(lpAddrs);
+        for (RouteInfo route : lpRoutes) {
+            testcase.lp.addRoute(route);
+        }
+        for (InetAddress dns : lpDns) {
+            testcase.lp.addDnsServer(dns);
+        }
+        testcase.config = config;
+        return testcase;
+    }
+
+    @Test
+    public void testInitialConfigurations() throws Exception {
+        InitialConfigurationTestCase[] testcases = {
+            validConf("valid IPv4 configuration",
+                    links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("192.0.2.2")),
+            validConf("another valid IPv4 configuration",
+                    links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns()),
+            validConf("valid IPv6 configurations",
+                    links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
+                    prefixes("2001:db8:dead:beef::/64", "fe80::/64"),
+                    dns("2001:db8:dead:beef:f00::02")),
+            validConf("valid IPv6 configurations",
+                    links("fe80::1/64"), prefixes("fe80::/64"), dns()),
+            validConf("valid IPv6/v4 configuration",
+                    links("2001:db8:dead:beef:f00::a0/48", "192.0.2.12/24"),
+                    prefixes("2001:db8:dead:beef::/64", "192.0.2.0/24"),
+                    dns("192.0.2.2", "2001:db8:dead:beef:f00::02")),
+            validConf("valid IPv6 configuration without any GUA.",
+                    links("fd00:1234:5678::1/48"),
+                    prefixes("fd00:1234:5678::/48"),
+                    dns("fd00:1234:5678::1000")),
+
+            invalidConf("empty configuration", links(), prefixes(), dns()),
+            invalidConf("v4 addr and dns not in any prefix",
+                    links("192.0.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
+            invalidConf("v4 addr not in any prefix",
+                    links("198.51.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
+            invalidConf("v4 dns addr not in any prefix",
+                    links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("198.51.100.2")),
+            invalidConf("v6 addr not in any prefix",
+                    links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
+                    prefixes("2001:db8:dead:beef::/64"),
+                    dns("2001:db8:dead:beef:f00::02")),
+            invalidConf("v6 dns addr not in any prefix",
+                    links("fe80::1/64"), prefixes("fe80::/64"), dns("2001:db8:dead:beef:f00::02")),
+            invalidConf("default ipv6 route and no GUA",
+                    links("fd01:1111:2222:3333::a0/128"), prefixes("::/0"), dns()),
+            invalidConf("invalid v6 prefix length",
+                    links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/32"),
+                    dns()),
+            invalidConf("another invalid v6 prefix length",
+                    links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/72"),
+                    dns())
+        };
+
+        for (InitialConfigurationTestCase testcase : testcases) {
+            if (testcase.config.isValid() != testcase.isValid) {
+                fail(testcase.errorMessage());
+            }
+        }
+    }
+
+    static class InitialConfigurationTestCase {
+        String descr;
+        boolean isValid;
+        InitialConfiguration config;
+        public String errorMessage() {
+            return String.format("%s: expected configuration %s to be %s, but was %s",
+                    descr, config, validString(isValid), validString(!isValid));
+        }
+        static String validString(boolean isValid) {
+            return isValid ? VALID : INVALID;
+        }
+    }
+
+    static InitialConfigurationTestCase validConf(String descr, Set<LinkAddress> links,
+            Set<IpPrefix> prefixes, Set<InetAddress> dns) {
+        return confTestCase(descr, true, conf(links, prefixes, dns));
+    }
+
+    static InitialConfigurationTestCase invalidConf(String descr, Set<LinkAddress> links,
+            Set<IpPrefix> prefixes, Set<InetAddress> dns) {
+        return confTestCase(descr, false, conf(links, prefixes, dns));
+    }
+
+    static InitialConfigurationTestCase confTestCase(
+            String descr, boolean isValid, InitialConfiguration config) {
+        InitialConfigurationTestCase testcase = new InitialConfigurationTestCase();
+        testcase.descr = descr;
+        testcase.isValid = isValid;
+        testcase.config = config;
+        return testcase;
+    }
+
+    static LinkProperties linkproperties(Set<LinkAddress> addresses, Set<RouteInfo> routes) {
+        LinkProperties lp = new LinkProperties();
+        lp.setLinkAddresses(addresses);
+        for (RouteInfo route : routes) {
+            lp.addRoute(route);
+        }
+        return lp;
+    }
+
+    static InitialConfiguration conf(Set<LinkAddress> links, Set<IpPrefix> prefixes) {
+        return conf(links, prefixes, new HashSet<>());
+    }
+
+    static InitialConfiguration conf(
+            Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns) {
+        InitialConfiguration conf = new InitialConfiguration();
+        conf.ipAddresses.addAll(links);
+        conf.directlyConnectedRoutes.addAll(prefixes);
+        conf.dnsServers.addAll(dns);
+        return conf;
+    }
+
+    static Set<RouteInfo> routes(String... routes) {
+        return mapIntoSet(routes, (r) -> new RouteInfo(new IpPrefix(r)));
+    }
+
+    static Set<IpPrefix> prefixes(String... prefixes) {
+        return mapIntoSet(prefixes, IpPrefix::new);
+    }
+
+    static Set<LinkAddress> links(String... addresses) {
+        return mapIntoSet(addresses, LinkAddress::new);
+    }
+
+    static Set<InetAddress> ips(String... addresses) {
+        return mapIntoSet(addresses, InetAddress::getByName);
+    }
+
+    static Set<InetAddress> dns(String... addresses) {
+        return ips(addresses);
+    }
+
+    static <A, B> Set<B> mapIntoSet(A[] in, Fn<A, B> fn) {
+        Set<B> out = new HashSet<>(in.length);
+        for (A item : in) {
+            try {
+                out.add(fn.call(item));
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return out;
+    }
+
+    interface Fn<A,B> {
+        B call(A a) throws Exception;
+    }
+
+    @Test
+    public void testAll() {
+        List<String> list1 = Arrays.asList();
+        List<String> list2 = Arrays.asList("foo");
+        List<String> list3 = Arrays.asList("bar", "baz");
+        List<String> list4 = Arrays.asList("foo", "bar", "baz");
+
+        assertTrue(InitialConfiguration.all(list1, (x) -> false));
+        assertFalse(InitialConfiguration.all(list2, (x) -> false));
+        assertTrue(InitialConfiguration.all(list3, (x) -> true));
+        assertTrue(InitialConfiguration.all(list2, (x) -> x.charAt(0) == 'f'));
+        assertFalse(InitialConfiguration.all(list4, (x) -> x.charAt(0) == 'f'));
+    }
+
+    @Test
+    public void testAny() {
+        List<String> list1 = Arrays.asList();
+        List<String> list2 = Arrays.asList("foo");
+        List<String> list3 = Arrays.asList("bar", "baz");
+        List<String> list4 = Arrays.asList("foo", "bar", "baz");
+
+        assertFalse(InitialConfiguration.any(list1, (x) -> true));
+        assertTrue(InitialConfiguration.any(list2, (x) -> true));
+        assertTrue(InitialConfiguration.any(list2, (x) -> x.charAt(0) == 'f'));
+        assertFalse(InitialConfiguration.any(list3, (x) -> x.charAt(0) == 'f'));
+        assertTrue(InitialConfiguration.any(list4, (x) -> x.charAt(0) == 'f'));
+    }
+
+    @Test
+    public void testFindAll() {
+        List<String> list1 = Arrays.asList();
+        List<String> list2 = Arrays.asList("foo");
+        List<String> list3 = Arrays.asList("foo", "bar", "baz");
+
+        assertEquals(list1, IpClient.findAll(list1, (x) -> true));
+        assertEquals(list1, IpClient.findAll(list3, (x) -> false));
+        assertEquals(list3, IpClient.findAll(list3, (x) -> true));
+        assertEquals(list2, IpClient.findAll(list3, (x) -> x.charAt(0) == 'f'));
+    }
+}
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpReachabilityMonitorTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpReachabilityMonitorTest.java
new file mode 100644
index 0000000..e3b5ddf
--- /dev/null
+++ b/packages/NetworkStack/tests/src/android/net/ip/IpReachabilityMonitorTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.util.InterfaceParams;
+import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+
+/**
+ * Tests for IpReachabilityMonitor.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpReachabilityMonitorTest {
+
+    @Mock IpReachabilityMonitor.Callback mCallback;
+    @Mock IpReachabilityMonitor.Dependencies mDependencies;
+    @Mock SharedLog mLog;
+    @Mock Context mContext;
+    Handler mHandler;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mLog.forSubComponent(anyString())).thenReturn(mLog);
+        mHandler = new Handler(Looper.getMainLooper());
+    }
+
+    IpReachabilityMonitor makeMonitor() {
+        final InterfaceParams ifParams = new InterfaceParams("fake0", 1, null);
+        return new IpReachabilityMonitor(
+                mContext, ifParams, mHandler, mLog, mCallback, false, mDependencies);
+    }
+
+    @Test
+    public void testNothing() {
+        IpReachabilityMonitor monitor = makeMonitor();
+    }
+}
diff --git a/packages/NetworkStack/tests/src/android/net/util/ConnectivityPacketSummaryTest.java b/packages/NetworkStack/tests/src/android/net/util/ConnectivityPacketSummaryTest.java
new file mode 100644
index 0000000..dfaf52a
--- /dev/null
+++ b/packages/NetworkStack/tests/src/android/net/util/ConnectivityPacketSummaryTest.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.net.MacAddress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import libcore.util.HexEncoding;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for ConnectivityPacketSummary.
+ *
+ * @hide
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ConnectivityPacketSummaryTest {
+    private static final MacAddress MYHWADDR = MacAddress.fromString("80:7a:bf:6f:48:f3");
+
+    private String getSummary(String hexBytes) {
+        hexBytes = hexBytes.replaceAll("\\s+", "");
+        final byte[] bytes = HexEncoding.decode(hexBytes.toCharArray(), false);
+        return ConnectivityPacketSummary.summarize(MYHWADDR, bytes);
+    }
+
+    @Test
+    public void testParseICMPv6DADProbe() {
+        final String packet =
+                // Ethernet
+                "3333FF6F48F3 807ABF6F48F3 86DD" +
+                // IPv6
+                "600000000018 3A FF" +
+                "00000000000000000000000000000000" +
+                "FF0200000000000000000001FF6F48F3" +
+                // ICMPv6
+                "87 00 A8E7" +
+                "00000000" +
+                "FE80000000000000827ABFFFFE6F48F3";
+
+        final String expected =
+                "TX 80:7a:bf:6f:48:f3 > 33:33:ff:6f:48:f3 ipv6" +
+                " :: > ff02::1:ff6f:48f3 icmp6" +
+                " ns fe80::827a:bfff:fe6f:48f3";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    @Test
+    public void testParseICMPv6RS() {
+        final String packet =
+                // Ethernet
+                "333300000002 807ABF6F48F3 86DD" +
+                // IPv6
+                "600000000010 3A FF" +
+                "FE80000000000000827ABFFFFE6F48F3" +
+                "FF020000000000000000000000000002" +
+                // ICMPv6 RS
+                "85 00 6973" +
+                "00000000" +
+                "01 01 807ABF6F48F3";
+
+        final String expected =
+                "TX 80:7a:bf:6f:48:f3 > 33:33:00:00:00:02 ipv6" +
+                " fe80::827a:bfff:fe6f:48f3 > ff02::2 icmp6" +
+                " rs slla 80:7a:bf:6f:48:f3";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    @Test
+    public void testParseICMPv6RA() {
+        final String packet =
+                // Ethernet
+                "807ABF6F48F3 100E7E263FC1 86DD" +
+                // IPv6
+                "600000000068 3A FF" +
+                "FE80000000000000FA000004FD000001" +
+                "FE80000000000000827ABFFFFE6F48F3" +
+                // ICMPv6 RA
+                "86 00 8141" +
+                "40 00 0E10" +
+                "00000000" +
+                "00000000" +
+                "01 01 00005E000265" +
+                "05 01 0000000005DC" +
+                "19 05 000000000E10" +
+                "      20014860486000000000000000008844" +
+                "      20014860486000000000000000008888" +
+                "03 04 40 C0" +
+                "      00278D00" +
+                "      00093A80" +
+                "      00000000" +
+                "      2401FA000004FD000000000000000000";
+
+        final String expected =
+                "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
+                " fe80::fa00:4:fd00:1 > fe80::827a:bfff:fe6f:48f3 icmp6" +
+                " ra slla 00:00:5e:00:02:65 mtu 1500";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    @Test
+    public void testParseICMPv6NS() {
+        final String packet =
+                // Ethernet
+                  "807ABF6F48F3 100E7E263FC1 86DD" +
+                  // IPv6
+                  "6C0000000020 3A FF" +
+                  "FE80000000000000FA000004FD000001" +
+                  "FF0200000000000000000001FF01C146" +
+                  // ICMPv6 NS
+                  "87 00 8AD4" +
+                  "00000000" +
+                  "2401FA000004FD0015EA6A5C7B01C146" +
+                  "01 01 00005E000265";
+
+        final String expected =
+                "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
+                " fe80::fa00:4:fd00:1 > ff02::1:ff01:c146 icmp6" +
+                " ns 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 slla 00:00:5e:00:02:65";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    @Test
+    public void testInvalidICMPv6NDLength() {
+        final String packet =
+                // Ethernet
+                "807ABF6F48F3 100E7E263FC1 86DD" +
+                // IPv6
+                "600000000068 3A FF" +
+                "FE80000000000000FA000004FD000001" +
+                "FE80000000000000827ABFFFFE6F48F3" +
+                // ICMPv6 RA
+                "86 00 8141" +
+                "40 00 0E10" +
+                "00000000" +
+                "00000000" +
+                "01 01 00005E000265" +
+                "00 00 0102030405D6";
+
+        final String expected =
+                "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
+                " fe80::fa00:4:fd00:1 > fe80::827a:bfff:fe6f:48f3 icmp6" +
+                " ra slla 00:00:5e:00:02:65 <malformed>";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    @Test
+    public void testParseICMPv6NA() {
+        final String packet =
+                // Ethernet
+                "00005E000265 807ABF6F48F3 86DD" +
+                "600000000020 3A FF" +
+                "2401FA000004FD0015EA6A5C7B01C146" +
+                "FE80000000000000FA000004FD000001" +
+                "88 00 E8126" +
+                "0000000" +
+                "2401FA000004FD0015EA6A5C7B01C146" +
+                "02 01 807ABF6F48F3";
+
+        final String expected =
+                "TX 80:7a:bf:6f:48:f3 > 00:00:5e:00:02:65 ipv6" +
+                " 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 > fe80::fa00:4:fd00:1 icmp6" +
+                " na 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 tlla 80:7a:bf:6f:48:f3";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    @Test
+    public void testParseARPRequest() {
+        final String packet =
+                // Ethernet
+                  "FFFFFFFFFFFF 807ABF6F48F3 0806" +
+                  // ARP
+                  "0001 0800 06 04" +
+                  // Request
+                  "0001" +
+                  "807ABF6F48F3 64706ADB" +
+                  "000000000000 64706FFD";
+
+        final String expected =
+                "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff arp" +
+                " who-has 100.112.111.253";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    @Test
+    public void testParseARPReply() {
+        final String packet =
+                // Ethernet
+                  "807ABF6F48F3 288A1CA8DFC1 0806" +
+                  // ARP
+                  "0001 0800 06 04" +
+                  // Reply
+                  "0002" +
+                  "288A1CA8DFC1 64706FFD"+
+                  "807ABF6F48F3 64706ADB" +
+                  // Ethernet padding to packet min size.
+                  "0000000000000000000000000000";
+
+        final String expected =
+                "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 arp" +
+                " reply 100.112.111.253 28:8a:1c:a8:df:c1";
+
+        assertEquals(expected, getSummary(packet));
+    }
+
+    @Test
+    public void testParseDHCPv4Discover() {
+        final String packet =
+                // Ethernet
+                "FFFFFFFFFFFF 807ABF6F48F3 0800" +
+                // IPv4
+                "451001580000400040113986" +
+                "00000000" +
+                "FFFFFFFF" +
+                // UDP
+                "0044 0043" +
+                "0144 5559" +
+                // DHCPv4
+                "01 01 06 00" +
+                "79F7ACA4" +
+                "0000 0000" +
+                "00000000" +
+                "00000000" +
+                "00000000" +
+                "00000000" +
+                "807ABF6F48F300000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "63 82 53 63" +
+                "35 01 01" +
+                "3D 07 01807ABF6F48F3" +
+                "39 02 05DC" +
+                "3C 12 616E64726F69642D646863702D372E312E32" +
+                "0C 18 616E64726F69642D36623030366333313333393835343139" +
+                "37 0A 01 03 06 0F 1A 1C 33 3A 3B 2B" +
+                "FF" +
+                "00";
+
+        final String expectedPrefix =
+                "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff ipv4" +
+                " 0.0.0.0 > 255.255.255.255 udp" +
+                " 68 > 67 dhcp4" +
+                " 80:7a:bf:6f:48:f3 DISCOVER";
+
+        assertTrue(getSummary(packet).startsWith(expectedPrefix));
+    }
+
+    @Test
+    public void testParseDHCPv4Offer() {
+        final String packet =
+                // Ethernet
+                "807ABF6F48F3 288A1CA8DFC1 0800" +
+                // IPv4
+                "4500013D4D2C0000401188CB" +
+                "64706FFD" +
+                "64706ADB" +
+                // UDP
+                "0043 0044" +
+                "0129 371D" +
+                // DHCPv4
+                "02 01 06 01" +
+                "79F7ACA4" +
+                "0000 0000" +
+                "00000000" +
+                "64706ADB" +
+                "00000000" +
+                "00000000" +
+                "807ABF6F48F300000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "63 82 53 63" +
+                "35 01 02" +
+                "36 04 AC188A0B" +
+                "33 04 00000708" +
+                "01 04 FFFFF000" +
+                "03 04 64706FFE" +
+                "06 08 08080808" +
+                "      08080404" +
+                "FF0001076165313A363636FF";
+
+        final String expectedPrefix =
+                "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 ipv4" +
+                " 100.112.111.253 > 100.112.106.219 udp" +
+                " 67 > 68 dhcp4" +
+                " 80:7a:bf:6f:48:f3 OFFER";
+
+        assertTrue(getSummary(packet).startsWith(expectedPrefix));
+    }
+
+    @Test
+    public void testParseDHCPv4Request() {
+        final String packet =
+                // Ethernet
+                "FFFFFFFFFFFF 807ABF6F48F3 0800" +
+                // IPv4
+                "45100164000040004011397A" +
+                "00000000" +
+                "FFFFFFFF" +
+                // UDP
+                "0044 0043" +
+                "0150 E5C7" +
+                // DHCPv4
+                "01 01 06 00" +
+                "79F7ACA4" +
+                "0001 0000" +
+                "00000000" +
+                "00000000" +
+                "00000000" +
+                "00000000" +
+                "807ABF6F48F300000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "63 82 53 63" +
+                "35 01 03" +
+                "3D 07 01807ABF6F48F3" +
+                "32 04 64706ADB" +
+                "36 04 AC188A0B" +
+                "39 02 05DC" +
+                "3C 12 616E64726F69642D646863702D372E312E32" +
+                "0C 18 616E64726F69642D36623030366333313333393835343139" +
+                "37 0A 01 03 06 0F 1A 1C 33 3A 3B 2B" +
+                "FF" +
+                "00";
+
+        final String expectedPrefix =
+                "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff ipv4" +
+                " 0.0.0.0 > 255.255.255.255 udp" +
+                " 68 > 67 dhcp4" +
+                " 80:7a:bf:6f:48:f3 REQUEST";
+
+        assertTrue(getSummary(packet).startsWith(expectedPrefix));
+    }
+
+    @Test
+    public void testParseDHCPv4Ack() {
+        final String packet =
+                // Ethernet
+                "807ABF6F48F3 288A1CA8DFC1 0800" +
+                // IPv4
+                "4500013D4D3B0000401188BC" +
+                "64706FFD" +
+                "64706ADB" +
+                // UDP
+                "0043 0044" +
+                "0129 341C" +
+                // DHCPv4
+                "02 01 06 01" +
+                "79F7ACA4" +
+                "0001 0000" +
+                "00000000" +
+                "64706ADB" +
+                "00000000" +
+                "00000000" +
+                "807ABF6F48F300000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "0000000000000000000000000000000000000000000000000000000000000000" +
+                "63 82 53 63" +
+                "35 01 05" +
+                "36 04 AC188A0B" +
+                "33 04 00000708" +
+                "01 04 FFFFF000" +
+                "03 04 64706FFE" +
+                "06 08 08080808" +
+                "      08080404" +
+                "FF0001076165313A363636FF";
+
+        final String expectedPrefix =
+                "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 ipv4" +
+                " 100.112.111.253 > 100.112.106.219 udp" +
+                " 67 > 68 dhcp4" +
+                " 80:7a:bf:6f:48:f3 ACK";
+
+        assertTrue(getSummary(packet).startsWith(expectedPrefix));
+    }
+}
diff --git a/tests/net/java/android/net/util/PacketReaderTest.java b/packages/NetworkStack/tests/src/android/net/util/PacketReaderTest.java
similarity index 100%
rename from tests/net/java/android/net/util/PacketReaderTest.java
rename to packages/NetworkStack/tests/src/android/net/util/PacketReaderTest.java
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
new file mode 100644
index 0000000..d31fa77
--- /dev/null
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
+import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL;
+import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID;
+import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.CaptivePortal;
+import android.net.ConnectivityManager;
+import android.net.INetworkMonitorCallbacks;
+import android.net.InetAddresses;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkRequest;
+import android.net.captiveportal.CaptivePortalProbeResult;
+import android.net.metrics.IpConnectivityLog;
+import android.net.util.SharedLog;
+import android.net.wifi.WifiManager;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.URL;
+import java.util.Random;
+
+import javax.net.ssl.SSLHandshakeException;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetworkMonitorTest {
+    private static final String LOCATION_HEADER = "location";
+
+    private @Mock Context mContext;
+    private @Mock IpConnectivityLog mLogger;
+    private @Mock SharedLog mValidationLogger;
+    private @Mock NetworkInfo mNetworkInfo;
+    private @Mock ConnectivityManager mCm;
+    private @Mock TelephonyManager mTelephony;
+    private @Mock WifiManager mWifi;
+    private @Mock HttpURLConnection mHttpConnection;
+    private @Mock HttpURLConnection mHttpsConnection;
+    private @Mock HttpURLConnection mFallbackConnection;
+    private @Mock HttpURLConnection mOtherFallbackConnection;
+    private @Mock Random mRandom;
+    private @Mock NetworkMonitor.Dependencies mDependencies;
+    private @Mock INetworkMonitorCallbacks mCallbacks;
+    private @Spy Network mNetwork = new Network(TEST_NETID);
+    private NetworkRequest mRequest;
+
+    private static final int TEST_NETID = 4242;
+
+    private static final String TEST_HTTP_URL = "http://www.google.com/gen_204";
+    private static final String TEST_HTTPS_URL = "https://www.google.com/gen_204";
+    private static final String TEST_FALLBACK_URL = "http://fallback.google.com/gen_204";
+    private static final String TEST_OTHER_FALLBACK_URL = "http://otherfallback.google.com/gen_204";
+
+    private static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
+    private static final int RETURN_CODE_DNS_SUCCESS = 0;
+    private static final int RETURN_CODE_DNS_TIMEOUT = 255;
+
+    private static final int HANDLER_TIMEOUT_MS = 1000;
+
+    private static final LinkProperties TEST_LINKPROPERTIES = new LinkProperties();
+
+    private static final NetworkCapabilities METERED_CAPABILITIES = new NetworkCapabilities()
+            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+            .addCapability(NET_CAPABILITY_INTERNET);
+
+    private static final NetworkCapabilities NOT_METERED_CAPABILITIES = new NetworkCapabilities()
+            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+            .addCapability(NET_CAPABILITY_INTERNET)
+            .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+
+    private static final NetworkCapabilities NO_INTERNET_CAPABILITIES = new NetworkCapabilities()
+            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+
+    @Before
+    public void setUp() throws IOException {
+        MockitoAnnotations.initMocks(this);
+        when(mDependencies.getPrivateDnsBypassNetwork(any())).thenReturn(mNetwork);
+        when(mDependencies.getRandom()).thenReturn(mRandom);
+        when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt()))
+                .thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
+        when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_USE_HTTPS),
+                anyInt())).thenReturn(1);
+        when(mDependencies.getCaptivePortalServerHttpUrl(any())).thenReturn(TEST_HTTP_URL);
+        when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL),
+                anyString())).thenReturn(TEST_HTTPS_URL);
+        doReturn(mNetwork).when(mNetwork).getPrivateDnsBypassingCopy();
+
+        when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mCm);
+        when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephony);
+        when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifi);
+
+        when(mNetworkInfo.getType()).thenReturn(ConnectivityManager.TYPE_WIFI);
+        setFallbackUrl(TEST_FALLBACK_URL);
+        setOtherFallbackUrls(TEST_OTHER_FALLBACK_URL);
+        setFallbackSpecs(null); // Test with no fallback spec by default
+        when(mRandom.nextInt()).thenReturn(0);
+
+        doAnswer((invocation) -> {
+            URL url = invocation.getArgument(0);
+            switch(url.toString()) {
+                case TEST_HTTP_URL:
+                    return mHttpConnection;
+                case TEST_HTTPS_URL:
+                    return mHttpsConnection;
+                case TEST_FALLBACK_URL:
+                    return mFallbackConnection;
+                case TEST_OTHER_FALLBACK_URL:
+                    return mOtherFallbackConnection;
+                default:
+                    fail("URL not mocked: " + url.toString());
+                    return null;
+            }
+        }).when(mNetwork).openConnection(any());
+        when(mHttpConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
+        when(mHttpsConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
+        doReturn(new InetAddress[] {
+                InetAddresses.parseNumericAddress("192.168.0.0")
+        }).when(mNetwork).getAllByName(any());
+
+        mRequest = new NetworkRequest.Builder()
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .addCapability(NET_CAPABILITY_NOT_RESTRICTED)
+                .build();
+        // Default values. Individual tests can override these.
+        when(mCm.getLinkProperties(any())).thenReturn(TEST_LINKPROPERTIES);
+        when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
+
+        setMinDataStallEvaluateInterval(500);
+        setDataStallEvaluationType(1 << DATA_STALL_EVALUATION_TYPE_DNS);
+        setValidDataStallDnsTimeThreshold(500);
+        setConsecutiveDnsTimeoutThreshold(5);
+    }
+
+    private class WrappedNetworkMonitor extends NetworkMonitor {
+        private long mProbeTime = 0;
+
+        WrappedNetworkMonitor(Context context, Network network, NetworkRequest defaultRequest,
+                IpConnectivityLog logger, Dependencies deps) {
+                super(context, mCallbacks, network, defaultRequest, logger,
+                        new SharedLog("test_nm"), deps);
+        }
+
+        @Override
+        protected long getLastProbeTime() {
+            return mProbeTime;
+        }
+
+        protected void setLastProbeTime(long time) {
+            mProbeTime = time;
+        }
+    }
+
+    private WrappedNetworkMonitor makeMeteredWrappedNetworkMonitor() {
+        final WrappedNetworkMonitor nm = new WrappedNetworkMonitor(
+                mContext, mNetwork, mRequest, mLogger, mDependencies);
+        when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
+        nm.start();
+        waitForIdle(nm.getHandler());
+        return nm;
+    }
+
+    private WrappedNetworkMonitor makeNotMeteredWrappedNetworkMonitor() {
+        final WrappedNetworkMonitor nm = new WrappedNetworkMonitor(
+                mContext, mNetwork, mRequest, mLogger, mDependencies);
+        when(mCm.getNetworkCapabilities(any())).thenReturn(NOT_METERED_CAPABILITIES);
+        nm.start();
+        waitForIdle(nm.getHandler());
+        return nm;
+    }
+
+    private NetworkMonitor makeMonitor() {
+        final NetworkMonitor nm = new NetworkMonitor(
+                mContext, mCallbacks, mNetwork, mRequest, mLogger, mValidationLogger,
+                mDependencies);
+        nm.start();
+        waitForIdle(nm.getHandler());
+        return nm;
+    }
+
+    private void waitForIdle(Handler handler) {
+        final ConditionVariable cv = new ConditionVariable(false);
+        handler.post(cv::open);
+        if (!cv.block(HANDLER_TIMEOUT_MS)) {
+            fail("Timed out waiting for handler");
+        }
+    }
+
+    @Test
+    public void testIsCaptivePortal_HttpProbeIsPortal() throws IOException {
+        setSslException(mHttpsConnection);
+        setPortal302(mHttpConnection);
+
+        assertPortal(makeMonitor().isCaptivePortal());
+    }
+
+    @Test
+    public void testIsCaptivePortal_HttpsProbeIsNotPortal() throws IOException {
+        setStatus(mHttpsConnection, 204);
+        setStatus(mHttpConnection, 500);
+
+        assertNotPortal(makeMonitor().isCaptivePortal());
+    }
+
+    @Test
+    public void testIsCaptivePortal_HttpsProbeFailedHttpSuccessNotUsed() throws IOException {
+        setSslException(mHttpsConnection);
+        // Even if HTTP returns a 204, do not use the result unless HTTPS succeeded
+        setStatus(mHttpConnection, 204);
+        setStatus(mFallbackConnection, 500);
+
+        assertFailed(makeMonitor().isCaptivePortal());
+    }
+
+    @Test
+    public void testIsCaptivePortal_FallbackProbeIsPortal() throws IOException {
+        setSslException(mHttpsConnection);
+        setStatus(mHttpConnection, 500);
+        setPortal302(mFallbackConnection);
+
+        assertPortal(makeMonitor().isCaptivePortal());
+    }
+
+    @Test
+    public void testIsCaptivePortal_FallbackProbeIsNotPortal() throws IOException {
+        setSslException(mHttpsConnection);
+        setStatus(mHttpConnection, 500);
+        setStatus(mFallbackConnection, 204);
+
+        // Fallback probe did not see portal, HTTPS failed -> inconclusive
+        assertFailed(makeMonitor().isCaptivePortal());
+    }
+
+    @Test
+    public void testIsCaptivePortal_OtherFallbackProbeIsPortal() throws IOException {
+        // Set all fallback probes but one to invalid URLs to verify they are being skipped
+        setFallbackUrl(TEST_FALLBACK_URL);
+        setOtherFallbackUrls(TEST_FALLBACK_URL + "," + TEST_OTHER_FALLBACK_URL);
+
+        setSslException(mHttpsConnection);
+        setStatus(mHttpConnection, 500);
+        setStatus(mFallbackConnection, 500);
+        setPortal302(mOtherFallbackConnection);
+
+        // TEST_OTHER_FALLBACK_URL is third
+        when(mRandom.nextInt()).thenReturn(2);
+
+        final NetworkMonitor monitor = makeMonitor();
+
+        // First check always uses the first fallback URL: inconclusive
+        assertFailed(monitor.isCaptivePortal());
+        verify(mFallbackConnection, times(1)).getResponseCode();
+        verify(mOtherFallbackConnection, never()).getResponseCode();
+
+        // Second check uses the URL chosen by Random
+        assertPortal(monitor.isCaptivePortal());
+        verify(mOtherFallbackConnection, times(1)).getResponseCode();
+    }
+
+    @Test
+    public void testIsCaptivePortal_AllProbesFailed() throws IOException {
+        setSslException(mHttpsConnection);
+        setStatus(mHttpConnection, 500);
+        setStatus(mFallbackConnection, 404);
+
+        assertFailed(makeMonitor().isCaptivePortal());
+        verify(mFallbackConnection, times(1)).getResponseCode();
+        verify(mOtherFallbackConnection, never()).getResponseCode();
+    }
+
+    @Test
+    public void testIsCaptivePortal_InvalidUrlSkipped() throws IOException {
+        setFallbackUrl("invalid");
+        setOtherFallbackUrls("otherinvalid," + TEST_OTHER_FALLBACK_URL + ",yetanotherinvalid");
+
+        setSslException(mHttpsConnection);
+        setStatus(mHttpConnection, 500);
+        setPortal302(mOtherFallbackConnection);
+
+        assertPortal(makeMonitor().isCaptivePortal());
+        verify(mOtherFallbackConnection, times(1)).getResponseCode();
+        verify(mFallbackConnection, never()).getResponseCode();
+    }
+
+    private void setupFallbackSpec() throws IOException {
+        setFallbackSpecs("http://example.com@@/@@204@@/@@"
+                + "@@,@@"
+                + TEST_OTHER_FALLBACK_URL + "@@/@@30[12]@@/@@https://(www\\.)?google.com/?.*");
+
+        setSslException(mHttpsConnection);
+        setStatus(mHttpConnection, 500);
+
+        // Use the 2nd fallback spec
+        when(mRandom.nextInt()).thenReturn(1);
+    }
+
+    @Test
+    public void testIsCaptivePortal_FallbackSpecIsNotPortal() throws IOException {
+        setupFallbackSpec();
+        set302(mOtherFallbackConnection, "https://www.google.com/test?q=3");
+
+        // HTTPS failed, fallback spec did not see a portal -> inconclusive
+        assertFailed(makeMonitor().isCaptivePortal());
+        verify(mOtherFallbackConnection, times(1)).getResponseCode();
+        verify(mFallbackConnection, never()).getResponseCode();
+    }
+
+    @Test
+    public void testIsCaptivePortal_FallbackSpecIsPortal() throws IOException {
+        setupFallbackSpec();
+        set302(mOtherFallbackConnection, "http://login.portal.example.com");
+
+        assertPortal(makeMonitor().isCaptivePortal());
+    }
+
+    @Test
+    public void testIsCaptivePortal_IgnorePortals() throws IOException {
+        setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE);
+        setSslException(mHttpsConnection);
+        setPortal302(mHttpConnection);
+
+        assertNotPortal(makeMonitor().isCaptivePortal());
+    }
+
+    @Test
+    public void testIsDataStall_EvaluationDisabled() {
+        setDataStallEvaluationType(0);
+        WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
+        assertFalse(wrappedMonitor.isDataStall());
+    }
+
+    @Test
+    public void testIsDataStall_EvaluationDnsOnNotMeteredNetwork() {
+        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
+        makeDnsTimeoutEvent(wrappedMonitor, 5);
+        assertTrue(wrappedMonitor.isDataStall());
+    }
+
+    @Test
+    public void testIsDataStall_EvaluationDnsOnMeteredNetwork() {
+        WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
+        assertFalse(wrappedMonitor.isDataStall());
+
+        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
+        makeDnsTimeoutEvent(wrappedMonitor, 5);
+        assertTrue(wrappedMonitor.isDataStall());
+    }
+
+    @Test
+    public void testIsDataStall_EvaluationDnsWithDnsTimeoutCount() {
+        WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
+        makeDnsTimeoutEvent(wrappedMonitor, 3);
+        assertFalse(wrappedMonitor.isDataStall());
+        // Reset consecutive timeout counts.
+        makeDnsSuccessEvent(wrappedMonitor, 1);
+        makeDnsTimeoutEvent(wrappedMonitor, 2);
+        assertFalse(wrappedMonitor.isDataStall());
+
+        makeDnsTimeoutEvent(wrappedMonitor, 3);
+        assertTrue(wrappedMonitor.isDataStall());
+
+        // Set the value to larger than the default dns log size.
+        setConsecutiveDnsTimeoutThreshold(51);
+        wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
+        makeDnsTimeoutEvent(wrappedMonitor, 50);
+        assertFalse(wrappedMonitor.isDataStall());
+
+        makeDnsTimeoutEvent(wrappedMonitor, 1);
+        assertTrue(wrappedMonitor.isDataStall());
+    }
+
+    @Test
+    public void testIsDataStall_EvaluationDnsWithDnsTimeThreshold() {
+        // Test dns events happened in valid dns time threshold.
+        WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
+        makeDnsTimeoutEvent(wrappedMonitor, 5);
+        assertFalse(wrappedMonitor.isDataStall());
+        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
+        assertTrue(wrappedMonitor.isDataStall());
+
+        // Test dns events happened before valid dns time threshold.
+        setValidDataStallDnsTimeThreshold(0);
+        wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
+        makeDnsTimeoutEvent(wrappedMonitor, 5);
+        assertFalse(wrappedMonitor.isDataStall());
+        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
+        assertFalse(wrappedMonitor.isDataStall());
+    }
+
+    @Test
+    public void testBrokenNetworkNotValidated() throws Exception {
+        setSslException(mHttpsConnection);
+        setStatus(mHttpConnection, 500);
+        setStatus(mFallbackConnection, 404);
+        when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
+
+        final NetworkMonitor nm = makeMonitor();
+        nm.notifyNetworkConnected();
+
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
+                .notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, null);
+    }
+
+    @Test
+    public void testNoInternetCapabilityValidated() throws Exception {
+        when(mCm.getNetworkCapabilities(any())).thenReturn(NO_INTERNET_CAPABILITIES);
+
+        final NetworkMonitor nm = makeMonitor();
+        nm.notifyNetworkConnected();
+
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
+                .notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
+        verify(mNetwork, never()).openConnection(any());
+    }
+
+    @Test
+    public void testLaunchCaptivePortalApp() throws Exception {
+        setSslException(mHttpsConnection);
+        setPortal302(mHttpConnection);
+
+        final NetworkMonitor nm = makeMonitor();
+        nm.notifyNetworkConnected();
+
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
+                .showProvisioningNotification(any());
+
+        // Check that startCaptivePortalApp sends the expected intent.
+        nm.launchCaptivePortalApp();
+
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mContext, timeout(HANDLER_TIMEOUT_MS).times(1))
+                .startActivityAsUser(intentCaptor.capture(), eq(UserHandle.CURRENT));
+        final Intent intent = intentCaptor.getValue();
+        assertEquals(ACTION_CAPTIVE_PORTAL_SIGN_IN, intent.getAction());
+        final Network network = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
+        assertEquals(TEST_NETID, network.netId);
+
+        // Have the app report that the captive portal is dismissed, and check that we revalidate.
+        setStatus(mHttpsConnection, 204);
+        setStatus(mHttpConnection, 204);
+        final CaptivePortal captivePortal = intent.getParcelableExtra(EXTRA_CAPTIVE_PORTAL);
+        captivePortal.reportCaptivePortalDismissed();
+        verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
+                .notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
+    }
+
+    private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
+        for (int i = 0; i < count; i++) {
+            wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
+                    RETURN_CODE_DNS_TIMEOUT);
+        }
+    }
+
+    private void makeDnsSuccessEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
+        for (int i = 0; i < count; i++) {
+            wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
+                    RETURN_CODE_DNS_SUCCESS);
+        }
+    }
+
+    private void setDataStallEvaluationType(int type) {
+        when(mDependencies.getSetting(any(),
+            eq(Settings.Global.DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type);
+    }
+
+    private void setMinDataStallEvaluateInterval(int time) {
+        when(mDependencies.getSetting(any(),
+            eq(Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time);
+    }
+
+    private void setValidDataStallDnsTimeThreshold(int time) {
+        when(mDependencies.getSetting(any(),
+            eq(Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time);
+    }
+
+    private void setConsecutiveDnsTimeoutThreshold(int num) {
+        when(mDependencies.getSetting(any(),
+            eq(Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt()))
+            .thenReturn(num);
+    }
+
+    private void setFallbackUrl(String url) {
+        when(mDependencies.getSetting(any(),
+                eq(Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL), any())).thenReturn(url);
+    }
+
+    private void setOtherFallbackUrls(String urls) {
+        when(mDependencies.getSetting(any(),
+                eq(Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS), any())).thenReturn(urls);
+    }
+
+    private void setFallbackSpecs(String specs) {
+        when(mDependencies.getSetting(any(),
+                eq(Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS), any())).thenReturn(specs);
+    }
+
+    private void setCaptivePortalMode(int mode) {
+        when(mDependencies.getSetting(any(),
+                eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt())).thenReturn(mode);
+    }
+
+    private void assertPortal(CaptivePortalProbeResult result) {
+        assertTrue(result.isPortal());
+        assertFalse(result.isFailed());
+        assertFalse(result.isSuccessful());
+    }
+
+    private void assertNotPortal(CaptivePortalProbeResult result) {
+        assertFalse(result.isPortal());
+        assertFalse(result.isFailed());
+        assertTrue(result.isSuccessful());
+    }
+
+    private void assertFailed(CaptivePortalProbeResult result) {
+        assertFalse(result.isPortal());
+        assertTrue(result.isFailed());
+        assertFalse(result.isSuccessful());
+    }
+
+    private void setSslException(HttpURLConnection connection) throws IOException {
+        doThrow(new SSLHandshakeException("Invalid cert")).when(connection).getResponseCode();
+    }
+
+    private void set302(HttpURLConnection connection, String location) throws IOException {
+        setStatus(connection, 302);
+        doReturn(location).when(connection).getHeaderField(LOCATION_HEADER);
+    }
+
+    private void setPortal302(HttpURLConnection connection) throws IOException {
+        set302(connection, "http://login.example.com");
+    }
+
+    private void setStatus(HttpURLConnection connection, int status) throws IOException {
+        doReturn(status).when(connection).getResponseCode();
+    }
+}
+
diff --git a/packages/NetworkStack/tests/src/com/android/server/util/SharedLogTest.java b/packages/NetworkStack/tests/src/com/android/server/util/SharedLogTest.java
new file mode 100644
index 0000000..07ad3123
--- /dev/null
+++ b/packages/NetworkStack/tests/src/com/android/server/util/SharedLogTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.net.util.SharedLog;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SharedLogTest {
+    private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}";
+    private static final String TIMESTAMP = "HH:MM:SS";
+
+    @Test
+    public void testBasicOperation() {
+        final SharedLog logTop = new SharedLog("top");
+        logTop.mark("first post!");
+
+        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");
+        logTop.log("still logging");
+        logLevel3.log("3 >> 2");
+        logLevel2a.mark("ok: last post");
+
+        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",
+            " - [twoA] MARK ok: last post",
+        };
+        // Verify the logs are all there and in the correct order.
+        verifyLogLines(expected, logTop);
+
+        // In fact, because they all share the same underlying LocalLog,
+        // every subcomponent SharedLog's dump() is identical.
+        verifyLogLines(expected, logLevel2a);
+        verifyLogLines(expected, logLevel2b);
+        verifyLogLines(expected, logLevel3);
+    }
+
+    private static void verifyLogLines(String[] expected, SharedLog log) {
+        final ByteArrayOutputStream ostream = new ByteArrayOutputStream();
+        final PrintWriter pw = new PrintWriter(ostream, true);
+        log.dump(null, pw, null);
+
+        final String dumpOutput = ostream.toString();
+        assertTrue(dumpOutput != null);
+        assertTrue(!"".equals(dumpOutput));
+
+        final String[] lines = dumpOutput.split("\n");
+        assertEquals(expected.length, lines.length);
+
+        for (int i = 0; i < expected.length; i++) {
+            String got = lines[i];
+            String want = expected[i];
+            assertTrue(String.format("'%s' did not contain '%s'", got, want), got.endsWith(want));
+            assertTrue(String.format("'%s' did not contain a %s timestamp", got, TIMESTAMP),
+                    got.replaceFirst(TIMESTAMP_PATTERN, TIMESTAMP).contains(TIMESTAMP));
+        }
+    }
+}
diff --git a/packages/PackageInstaller/res/values-da/strings.xml b/packages/PackageInstaller/res/values-da/strings.xml
index 933ff3f..9b57186 100644
--- a/packages/PackageInstaller/res/values-da/strings.xml
+++ b/packages/PackageInstaller/res/values-da/strings.xml
@@ -90,7 +90,7 @@
     <string name="anonymous_source_continue" msgid="4375745439457209366">"Fortsæt"</string>
     <string name="external_sources_settings" msgid="4046964413071713807">"Indstillinger"</string>
     <string name="wear_app_channel" msgid="1960809674709107850">"Installerer/afinstallerer Wear-apps"</string>
-    <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"Underretning om appinstallation"</string>
+    <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"Notifikation om appinstallation"</string>
     <string name="notification_installation_success_message" msgid="6450467996056038442">"Appen er installeret"</string>
     <string name="notification_installation_success_status" msgid="3172502643504323321">"\"<xliff:g id="APPNAME">%1$s</xliff:g>\" er installeret"</string>
 </resources>
diff --git a/packages/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml
index 2182631..4deab35 100644
--- a/packages/PackageInstaller/res/values-mr/strings.xml
+++ b/packages/PackageInstaller/res/values-mr/strings.xml
@@ -59,7 +59,7 @@
     <string name="uninstall_update_text" msgid="863648314632448705">"फॅक्टरी आवृत्तीसह हे अ‍ॅप बदलायचे का? सर्व डेटा काढला जाईल."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"फॅक्टरी आवृत्तीसह हे अ‍ॅप बदलायचे? सर्व डेटा काढला जाईल. हे कार्य प्रोफाइल असलेल्यांसह या डिव्हाइसच्या सर्व वापरकर्त्यांना प्रभावित करते."</string>
     <string name="uninstall_remove_contributed_files" msgid="2048594420923203453">"<xliff:g id="SIZE">%1$s</xliff:g> आकाराच्या संबंधित मीडिया फायलीदेखील काढा."</string>
-    <string name="uninstall_keep_data" msgid="7002379587465487550">"अॅप डेटा पैकी <xliff:g id="SIZE">%1$s</xliff:g> ठेवा."</string>
+    <string name="uninstall_keep_data" msgid="7002379587465487550">"ॲप डेटा पैकी <xliff:g id="SIZE">%1$s</xliff:g> ठेवा."</string>
     <string name="uninstalling_notification_channel" msgid="840153394325714653">"अनइंस्टॉल रन होत आहेत"</string>
     <string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"अनइंस्टॉल करता आले नाही"</string>
     <string name="uninstalling" msgid="8709566347688966845">"अनइंस्टॉल करत आहे…"</string>
diff --git a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml
index 1a4d7b7..b063e13 100644
--- a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml
+++ b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml
@@ -33,33 +33,49 @@
         android:textAppearance="@style/BarChart.Text.HeaderTitle"/>
 
     <LinearLayout
+        android:id="@+id/bar_views_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:gravity="center|bottom">
+        android:gravity="center"
+        android:orientation="vertical">
 
-        <com.android.settingslib.widget.BarView
-            android:id="@+id/bar_view1"
-            style="@style/BarViewStyle"
-            settings:barColor="#FA7B17"/>
-        <com.android.settingslib.widget.BarView
-            android:id="@+id/bar_view2"
-            style="@style/BarViewStyle"
-            settings:barColor="#F439A0"/>
-        <com.android.settingslib.widget.BarView
-            android:id="@+id/bar_view3"
-            style="@style/BarViewStyle"
-            settings:barColor="#A142F4"/>
-        <com.android.settingslib.widget.BarView
-            android:id="@+id/bar_view4"
-            style="@style/BarViewStyle"
-            settings:barColor="#24C1E0"/>
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center|bottom">
+
+            <com.android.settingslib.widget.BarView
+                android:id="@+id/bar_view1"
+                style="@style/BarViewStyle"
+                settings:barColor="#FA7B17"/>
+            <com.android.settingslib.widget.BarView
+                android:id="@+id/bar_view2"
+                style="@style/BarViewStyle"
+                settings:barColor="#F439A0"/>
+            <com.android.settingslib.widget.BarView
+                android:id="@+id/bar_view3"
+                style="@style/BarViewStyle"
+                settings:barColor="#A142F4"/>
+            <com.android.settingslib.widget.BarView
+                android:id="@+id/bar_view4"
+                style="@style/BarViewStyle"
+                settings:barColor="#24C1E0"/>
+        </LinearLayout>
+
+        <Button
+            android:id="@+id/bar_chart_details"
+            style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+            android:layout_width="wrap_content"
+            android:layout_height="48dp"
+            android:gravity="center"/>
     </LinearLayout>
 
-    <Button
-        android:id="@+id/bar_chart_details"
-        style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
-        android:layout_width="wrap_content"
-        android:layout_height="48dp"
-        android:gravity="center"/>
+    <TextView
+        android:id="@+id/empty_view"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/settings_bar_view_max_height"
+        android:gravity="center"
+        android:visibility="gone"
+        android:textAppearance="@style/BarChart.Text.Summary"/>
 
 </LinearLayout>
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartInfo.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartInfo.java
new file mode 100644
index 0000000..eeaf273
--- /dev/null
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartInfo.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * BarChartInfo is responsible for storing information about {@link BarChartPreference}.
+ */
+public class BarChartInfo {
+    @StringRes
+    private final int mTitle;
+    @StringRes
+    private final int mDetails;
+    @StringRes
+    private final int mEmptyText;
+    private final View.OnClickListener mDetailsOnClickListener;
+
+    private BarViewInfo[] mBarViewInfos;
+
+    /**
+     * Gets the resource id for the title shown in {@link BarChartPreference}.
+     *
+     * @return the string resource id for title.
+     */
+    public int getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * Gets the resource id for the details shown in {@link BarChartPreference}.
+     *
+     * @return the string resource id for details.
+     */
+    public int getDetails() {
+        return mDetails;
+    }
+
+    /**
+     * Gets the resource id for the empty text shown in {@link BarChartPreference} when there is no
+     * any bar view in {@link BarChartPreference}.
+     *
+     * @return the string resource id for empty text.
+     */
+    public int getEmptyText() {
+        return mEmptyText;
+    }
+
+    /**
+     * Gets the click listener for the details view.
+     *
+     * @return click listener for details view.
+     */
+    public View.OnClickListener getDetailsOnClickListener() {
+        return mDetailsOnClickListener;
+    }
+
+    /**
+     * Gets an array which contains up to four {@link BarViewInfo}
+     *
+     * @return an array holding the current all {@link BarViewInfo} state of the bar chart.
+     */
+    public BarViewInfo[] getBarViewInfos() {
+        return mBarViewInfos;
+    }
+
+    void setBarViewInfos(BarViewInfo[] barViewInfos) {
+        mBarViewInfos = barViewInfos;
+    }
+
+    private BarChartInfo(Builder builder) {
+        mTitle = builder.mTitle;
+        mDetails = builder.mDetails;
+        mEmptyText = builder.mEmptyText;
+        mDetailsOnClickListener = builder.mDetailsOnClickListener;
+
+        if (builder.mBarViewInfos != null) {
+            mBarViewInfos = builder.mBarViewInfos.stream().toArray(BarViewInfo[]::new);
+        }
+    }
+
+    /**
+     * Builder class for {@link BarChartInfo}
+     */
+    public static class Builder {
+        @StringRes
+        private int mTitle;
+        @StringRes
+        private int mDetails;
+        @StringRes
+        private int mEmptyText;
+        private View.OnClickListener mDetailsOnClickListener;
+        private List<BarViewInfo> mBarViewInfos;
+
+        /**
+         * Creates an instance of a {@link BarChartInfo} based on the current builder settings.
+         *
+         * @return The {@link BarChartInfo}.
+         */
+        public BarChartInfo build() {
+            if (mTitle == 0) {
+                throw new IllegalStateException("You must call Builder#setTitle() once.");
+            }
+            return new BarChartInfo(this);
+        }
+
+        /**
+         * Sets the string resource id for the title.
+         */
+        public Builder setTitle(@StringRes int title) {
+            mTitle = title;
+            return this;
+        }
+
+        /**
+         * Sets the string resource id for the details.
+         */
+        public Builder setDetails(@StringRes int details) {
+            mDetails = details;
+            return this;
+        }
+
+        /**
+         * Sets the string resource id for the empty text.
+         */
+        public Builder setEmptyText(@StringRes int emptyText) {
+            mEmptyText = emptyText;
+            return this;
+        }
+
+        /**
+         * Sets the click listener for details view.
+         */
+        public Builder setDetailsOnClickListener(
+                @Nullable View.OnClickListener clickListener) {
+            mDetailsOnClickListener = clickListener;
+            return this;
+        }
+
+        /**
+         * Adds a {@link BarViewInfo} for {@link BarChartPreference}.
+         * Maximum of 4 {@link BarViewInfo} can be added.
+         */
+        public Builder addBarViewInfo(@NonNull BarViewInfo barViewInfo) {
+            if (mBarViewInfos == null) {
+                mBarViewInfos = new ArrayList<>();
+            }
+            if (mBarViewInfos.size() >= BarChartPreference.MAXIMUM_BAR_VIEWS) {
+                throw new IllegalStateException("We only support up to four bar views");
+            }
+            mBarViewInfos.add(barViewInfo);
+            return this;
+        }
+    }
+}
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
index 0a4b24c..d332bac 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,7 +24,6 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceViewHolder;
 
@@ -41,31 +40,45 @@
  *        android:key="bar_chart"/&gt;
  * </pre>
  *
- * <p>This code sample demonstrates how to initialize the contents of the BarChartPreference defined
- * in the previous XML layout:
- *
- * <pre>
- * BarViewInfo[] viewsInfo = new BarViewInfo [] {
- *     new BarViewInfo(icon, 18, res of summary),
- *     new BarViewInfo(icon, 25, res of summary),
- *     new BarViewInfo(icon, 10, res of summary),
- *     new BarViewInfo(icon, 3, res of summary),
- *  };
- * </pre>
+ * <p>This code sample demonstrates how to initialize the contents of the BarChartPreference
+ * defined in the previous XML layout:
  *
  * <pre>
  * BarChartPreference preference = ((BarChartPreference) findPreference("bar_chart"));
  *
- * preference.setBarChartTitleRes(R.string.title_res);
- * preference.setBarChartDetailsRes(R.string.details_res);
- * preference.setBarChartDetailsClickListener(v -> doSomething());
- * preference.setAllBarViewsData(viewsInfo);
+ * BarChartInfo info = new BarChartInfo.Builder()
+ *     .setTitle(R.string.permission_bar_chart_title)
+ *     .setDetails(R.string.permission_bar_chart_details)
+ *     .setEmptyText(R.string.permission_bar_chart_empty_text)
+ *     .addBarViewInfo(new barViewInfo(...))
+ *     .addBarViewInfo(new barViewInfo(...))
+ *     .addBarViewInfo(new barViewInfo(...))
+ *     .addBarViewInfo(new barViewInfo(...))
+ *     .setDetailsOnClickListener(v -> doSomething())
+ *     .build();
+ *
+ * preference.initializeBarChart(info);
+ * </pre>
+ *
+ *
+ * <p>You also can update new information for bar views by
+ * {@link BarChartPreference#setBarViewInfos(BarViewInfo[])}
+ *
+ * <pre>
+ * BarViewInfo[] barViewsInfo = new BarViewInfo [] {
+ *     new BarViewInfo(...),
+ *     new BarViewInfo(...),
+ *     new BarViewInfo(...),
+ *     new BarViewInfo(...),
+ * };
+ *
+ * preference.setBarViewInfos(barViewsInfo);
  * </pre>
  */
 public class BarChartPreference extends Preference {
 
+    public static final int MAXIMUM_BAR_VIEWS = 4;
     private static final String TAG = "BarChartPreference";
-    private static final int MAXIMUM_BAR_VIEWS = 4;
     private static final int[] BAR_VIEWS = {
             R.id.bar_view1,
             R.id.bar_view2,
@@ -74,12 +87,7 @@
     };
 
     private int mMaxBarHeight;
-    @StringRes
-    private int mTitleId;
-    @StringRes
-    private int mDetailsId;
-    private BarViewInfo[] mBarViewsInfo;
-    private View.OnClickListener mDetailsOnClickListener;
+    private BarChartInfo mBarChartInfo;
 
     public BarChartPreference(Context context) {
         super(context);
@@ -103,40 +111,26 @@
     }
 
     /**
-     * Set the text resource for bar chart title.
-     */
-    public void setBarChartTitle(@StringRes int resId) {
-        mTitleId = resId;
-        notifyChanged();
-    }
-
-    /**
-     * Set the text resource for bar chart details.
-     */
-    public void setBarChartDetails(@StringRes int resId) {
-        mDetailsId = resId;
-        notifyChanged();
-    }
-
-    /**
-     * Register a callback to be invoked when bar chart details view is clicked.
-     */
-    public void setBarChartDetailsClickListener(@Nullable View.OnClickListener clickListener) {
-        mDetailsOnClickListener = clickListener;
-        notifyChanged();
-    }
-
-    /**
-     * Set all bar view information which you'd like to show in preference.
+     * According to the information in {@link BarChartInfo} to initialize bar chart.
      *
-     * @param barViewsInfo the barViewsInfo contain at least one {@link BarViewInfo}.
+     * @param barChartInfo The barChartInfo contains title, details, empty text, click listener
+     *                     attached on details view and four bar views.
      */
-    public void setAllBarViewsInfo(@NonNull BarViewInfo[] barViewsInfo) {
-        mBarViewsInfo = barViewsInfo;
-        // Do a sort in descending order, the first element would have max {@link
-        // BarViewInfo#mBarNumber}
-        Arrays.sort(mBarViewsInfo);
-        calculateAllBarViewHeights();
+    public void initializeBarChart(@NonNull BarChartInfo barChartInfo) {
+        mBarChartInfo = barChartInfo;
+        notifyChanged();
+    }
+
+    /**
+     * Sets all bar view information which you'd like to show in preference.
+     *
+     * @param barViewInfos the barViewInfos contain at least one {@link BarViewInfo}.
+     */
+    public void setBarViewInfos(@Nullable BarViewInfo[] barViewInfos) {
+        if (barViewInfos != null && barViewInfos.length > MAXIMUM_BAR_VIEWS) {
+            throw new IllegalStateException("We only support up to four bar views");
+        }
+        mBarChartInfo.setBarViewInfos(barViewInfos);
         notifyChanged();
     }
 
@@ -146,7 +140,17 @@
         holder.setDividerAllowedAbove(true);
         holder.setDividerAllowedBelow(true);
 
+        // We must show title of bar chart.
         bindChartTitleView(holder);
+
+        final BarViewInfo[] barViewInfos = mBarChartInfo.getBarViewInfos();
+        // If there is no any bar view, we just show an empty text.
+        if (barViewInfos == null || barViewInfos.length == 0) {
+            setEmptyViewVisible(holder, true /* visible */);
+            return;
+        }
+        setEmptyViewVisible(holder, false /* visible */);
+
         bindChartDetailsView(holder);
         updateBarChart(holder);
     }
@@ -160,43 +164,68 @@
 
     private void bindChartTitleView(PreferenceViewHolder holder) {
         final TextView titleView = (TextView) holder.findViewById(R.id.bar_chart_title);
-        titleView.setText(mTitleId);
+        titleView.setText(mBarChartInfo.getTitle());
     }
 
     private void bindChartDetailsView(PreferenceViewHolder holder) {
         final Button detailsView = (Button) holder.findViewById(R.id.bar_chart_details);
-        if (mDetailsId == 0) {
+        final int details = mBarChartInfo.getDetails();
+        if (details == 0) {
             detailsView.setVisibility(View.GONE);
         } else {
             detailsView.setVisibility(View.VISIBLE);
-            detailsView.setText(mDetailsId);
-            detailsView.setOnClickListener(mDetailsOnClickListener);
+            detailsView.setText(details);
+            detailsView.setOnClickListener(mBarChartInfo.getDetailsOnClickListener());
         }
     }
 
     private void updateBarChart(PreferenceViewHolder holder) {
+        normalizeBarViewHeights();
+
+        final BarViewInfo[] barViewInfos = mBarChartInfo.getBarViewInfos();
+
         for (int index = 0; index < MAXIMUM_BAR_VIEWS; index++) {
             final BarView barView = (BarView) holder.findViewById(BAR_VIEWS[index]);
 
-            // If there is no bar views data can be shown.
-            if (mBarViewsInfo == null || index >= mBarViewsInfo.length) {
+            // If there is no bar view info can be shown.
+            if (barViewInfos == null || index >= barViewInfos.length) {
                 barView.setVisibility(View.GONE);
                 continue;
             }
             barView.setVisibility(View.VISIBLE);
-            barView.updateView(mBarViewsInfo[index]);
+            barView.updateView(barViewInfos[index]);
         }
     }
 
-    private void calculateAllBarViewHeights() {
+    private void normalizeBarViewHeights() {
+        final BarViewInfo[] barViewInfos = mBarChartInfo.getBarViewInfos();
+        // If there is no any bar view info, we don't need to calculate the height of all bar views.
+        if (barViewInfos == null || barViewInfos.length == 0) {
+            return;
+        }
+        // Do a sort in descending order, the first element would have max {@link
+        // BarViewInfo#mHeight}
+        Arrays.sort(barViewInfos);
         // Since we sorted this array in advance, the first element must have the max {@link
         // BarViewInfo#mHeight}.
-        final int maxBarHeight = mBarViewsInfo[0].getHeight();
+        final int maxBarHeight = barViewInfos[0].getHeight();
         // If the max number of bar view is zero, then we don't calculate the unit for bar height.
         final int unit = maxBarHeight == 0 ? 0 : mMaxBarHeight / maxBarHeight;
 
-        for (BarViewInfo barView : mBarViewsInfo) {
+        for (BarViewInfo barView : barViewInfos) {
             barView.setNormalizedHeight(barView.getHeight() * unit);
         }
     }
+
+    private void setEmptyViewVisible(PreferenceViewHolder holder, boolean visible) {
+        final View barViewsContainer = holder.findViewById(R.id.bar_views_container);
+        final TextView emptyView = (TextView) holder.findViewById(R.id.empty_view);
+        final int emptyTextRes = mBarChartInfo.getEmptyText();
+
+        if (emptyTextRes != 0) {
+            emptyView.setText(emptyTextRes);
+        }
+        emptyView.setVisibility(visible ? View.VISIBLE : View.GONE);
+        barViewsContainer.setVisibility(visible ? View.GONE : View.VISIBLE);
+    }
 }
diff --git a/packages/SettingsLib/EntityHeaderWidgets/res/layout/app_entities_header.xml b/packages/SettingsLib/EntityHeaderWidgets/res/layout/app_entities_header.xml
index 9f30eda..716fc8d 100644
--- a/packages/SettingsLib/EntityHeaderWidgets/res/layout/app_entities_header.xml
+++ b/packages/SettingsLib/EntityHeaderWidgets/res/layout/app_entities_header.xml
@@ -33,7 +33,7 @@
         android:textAppearance="@style/AppEntitiesHeader.Text.HeaderTitle"/>
 
     <LinearLayout
-        android:id="@+id/all_apps_view"
+        android:id="@+id/app_views_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:paddingTop="16dp"
@@ -61,4 +61,12 @@
         android:layout_height="48dp"
         android:gravity="center"/>
 
+    <TextView
+        android:id="@+id/empty_view"
+        android:layout_width="match_parent"
+        android:layout_height="106dp"
+        android:gravity="center"
+        android:visibility="gone"
+        android:textAppearance="@style/AppEntitiesHeader.Text.Summary"/>
+
 </LinearLayout>
diff --git a/packages/SettingsLib/EntityHeaderWidgets/res/layout/app_view.xml b/packages/SettingsLib/EntityHeaderWidgets/res/layout/app_view.xml
index fcafa31..9604512 100644
--- a/packages/SettingsLib/EntityHeaderWidgets/res/layout/app_view.xml
+++ b/packages/SettingsLib/EntityHeaderWidgets/res/layout/app_view.xml
@@ -22,6 +22,8 @@
     android:layout_weight="1"
     android:layout_marginEnd="16dp"
     android:gravity="center"
+    android:clickable="true"
+    android:background="?android:attr/selectableItemBackground"
     android:orientation="vertical">
 
     <ImageView
diff --git a/packages/SettingsLib/EntityHeaderWidgets/src/com/android/settingslib/widget/AppEntitiesHeaderController.java b/packages/SettingsLib/EntityHeaderWidgets/src/com/android/settingslib/widget/AppEntitiesHeaderController.java
index 8ccf89f..330049f 100644
--- a/packages/SettingsLib/EntityHeaderWidgets/src/com/android/settingslib/widget/AppEntitiesHeaderController.java
+++ b/packages/SettingsLib/EntityHeaderWidgets/src/com/android/settingslib/widget/AppEntitiesHeaderController.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
@@ -32,23 +31,9 @@
 import androidx.annotation.VisibleForTesting;
 
 /**
- * This is used to initialize view which was inflated
+ * This class is used to initialize view which was inflated
  * from {@link R.xml.app_entities_header.xml}.
  *
- * <p>The view looks like below.
- *
- * <pre>
- * --------------------------------------------------------------
- * |                     Header title                           |
- * --------------------------------------------------------------
- * |    App1 icon       |   App2 icon        |   App3 icon      |
- * |    App1 title      |   App2 title       |   App3 title     |
- * |    App1 summary    |   App2 summary     |   App3 summary   |
- * |-------------------------------------------------------------
- * |                     Header details                         |
- * --------------------------------------------------------------
- * </pre>
- *
  * <p>How to use AppEntitiesHeaderController?
  *
  * <p>1. Add a {@link LayoutPreference} in layout XML file.
@@ -66,13 +51,20 @@
  * View headerView = ((LayoutPreference) screen.findPreference("app_entities_header"))
  *         .findViewById(R.id.app_entities_header);
  *
+ * final AppEntityInfo appEntityInfo = new AppEntityInfo.Builder()
+ *         .setIcon(icon)
+ *         .setTitle(title)
+ *         .setSummary(summary)
+ *         .setOnClickListener(view -> doSomething())
+ *         .build();
+ *
  * AppEntitiesHeaderController.newInstance(context, headerView)
  *         .setHeaderTitleRes(R.string.xxxxx)
  *         .setHeaderDetailsRes(R.string.xxxxx)
  *         .setHeaderDetailsClickListener(onClickListener)
- *         .setAppEntity(0, icon, "app title", "app summary")
- *         .setAppEntity(1, icon, "app title", "app summary")
- *         .setAppEntity(2, icon, "app title", "app summary")
+ *         .setAppEntity(0, appEntityInfo)
+ *         .setAppEntity(1, appEntityInfo)
+ *         .setAppEntity(2, appEntityInfo)
  *         .apply();
  * </pre>
  */
@@ -81,13 +73,15 @@
     private static final String TAG = "AppEntitiesHeaderCtl";
 
     @VisibleForTesting
-    static final int MAXIMUM_APPS = 3;
+    public static final int MAXIMUM_APPS = 3;
 
     private final Context mContext;
     private final TextView mHeaderTitleView;
+    private final TextView mHeaderEmptyView;
     private final Button mHeaderDetailsView;
 
-    private final AppEntity[] mAppEntities;
+    private final AppEntityInfo[] mAppEntityInfos;
+    private final View mAppViewsContainer;
     private final View[] mAppEntityViews;
     private final ImageView[] mAppIconViews;
     private final TextView[] mAppTitleViews;
@@ -95,12 +89,13 @@
 
     private int mHeaderTitleRes;
     private int mHeaderDetailsRes;
+    private int mHeaderEmptyRes;
     private View.OnClickListener mDetailsOnClickListener;
 
     /**
      * Creates a new instance of the controller.
      *
-     * @param context the Context the view is running in
+     * @param context               the Context the view is running in
      * @param appEntitiesHeaderView view was inflated from <code>app_entities_header</code>
      */
     public static AppEntitiesHeaderController newInstance(@NonNull Context context,
@@ -112,8 +107,10 @@
         mContext = context;
         mHeaderTitleView = appEntitiesHeaderView.findViewById(R.id.header_title);
         mHeaderDetailsView = appEntitiesHeaderView.findViewById(R.id.header_details);
+        mHeaderEmptyView = appEntitiesHeaderView.findViewById(R.id.empty_view);
+        mAppViewsContainer = appEntitiesHeaderView.findViewById(R.id.app_views_container);
 
-        mAppEntities = new AppEntity[MAXIMUM_APPS];
+        mAppEntityInfos = new AppEntityInfo[MAXIMUM_APPS];
         mAppIconViews = new ImageView[MAXIMUM_APPS];
         mAppTitleViews = new TextView[MAXIMUM_APPS];
         mAppSummaryViews = new TextView[MAXIMUM_APPS];
@@ -160,18 +157,23 @@
     }
 
     /**
+     * Sets the string resource id for the empty text.
+     */
+    public AppEntitiesHeaderController setHeaderEmptyRes(@StringRes int emptyRes) {
+        mHeaderEmptyRes = emptyRes;
+        return this;
+    }
+
+    /**
      * Set an app entity at a specified position view.
      *
-     * @param index the index at which the specified view is to be inserted
-     * @param icon the icon of app entity
-     * @param titleRes the title of app entity
-     * @param summaryRes the summary of app entity
+     * @param index         the index at which the specified view is to be inserted
+     * @param appEntityInfo the information of an app entity
      * @return this {@code AppEntitiesHeaderController} object
      */
-    public AppEntitiesHeaderController setAppEntity(int index, @NonNull Drawable icon,
-            @Nullable CharSequence titleRes, @Nullable CharSequence summaryRes) {
-        final AppEntity appEntity = new AppEntity(icon, titleRes, summaryRes);
-        mAppEntities[index] = appEntity;
+    public AppEntitiesHeaderController setAppEntity(int index,
+            @NonNull AppEntityInfo appEntityInfo) {
+        mAppEntityInfos[index] = appEntityInfo;
         return this;
     }
 
@@ -182,7 +184,7 @@
      * @return this {@code AppEntitiesHeaderController} object
      */
     public AppEntitiesHeaderController removeAppEntity(int index) {
-        mAppEntities[index] = null;
+        mAppEntityInfos[index] = null;
         return this;
     }
 
@@ -203,6 +205,12 @@
      */
     public void apply() {
         bindHeaderTitleView();
+
+        if (isAppEntityInfosEmpty()) {
+            setEmptyViewVisible(true);
+            return;
+        }
+        setEmptyViewVisible(false);
         bindHeaderDetailsView();
 
         // Rebind all apps view
@@ -237,31 +245,41 @@
     }
 
     private void bindAppEntityView(int index) {
-        final AppEntity appEntity = mAppEntities[index];
-        mAppEntityViews[index].setVisibility(appEntity != null ? View.VISIBLE : View.GONE);
+        final AppEntityInfo appEntityInfo = mAppEntityInfos[index];
+        mAppEntityViews[index].setVisibility(appEntityInfo != null ? View.VISIBLE : View.GONE);
 
-        if (appEntity != null) {
-            mAppIconViews[index].setImageDrawable(appEntity.icon);
+        if (appEntityInfo != null) {
+            mAppEntityViews[index].setOnClickListener(appEntityInfo.getClickListener());
 
+            mAppIconViews[index].setImageDrawable(appEntityInfo.getIcon());
+
+            final CharSequence title = appEntityInfo.getTitle();
             mAppTitleViews[index].setVisibility(
-                    TextUtils.isEmpty(appEntity.title) ? View.INVISIBLE : View.VISIBLE);
-            mAppTitleViews[index].setText(appEntity.title);
+                    TextUtils.isEmpty(title) ? View.INVISIBLE : View.VISIBLE);
+            mAppTitleViews[index].setText(title);
 
+            final CharSequence summary = appEntityInfo.getSummary();
             mAppSummaryViews[index].setVisibility(
-                    TextUtils.isEmpty(appEntity.summary) ? View.INVISIBLE : View.VISIBLE);
-            mAppSummaryViews[index].setText(appEntity.summary);
+                    TextUtils.isEmpty(summary) ? View.INVISIBLE : View.VISIBLE);
+            mAppSummaryViews[index].setText(summary);
         }
     }
 
-    private static class AppEntity {
-        public final Drawable icon;
-        public final CharSequence title;
-        public final CharSequence summary;
-
-        AppEntity(Drawable appIcon, CharSequence appTitle, CharSequence appSummary) {
-            icon = appIcon;
-            title = appTitle;
-            summary = appSummary;
+    private void setEmptyViewVisible(boolean visible) {
+        if (mHeaderEmptyRes != 0) {
+            mHeaderEmptyView.setText(mHeaderEmptyRes);
         }
+        mHeaderEmptyView.setVisibility(visible ? View.VISIBLE : View.GONE);
+        mHeaderDetailsView.setVisibility(visible ? View.GONE : View.VISIBLE);
+        mAppViewsContainer.setVisibility(visible ? View.GONE : View.VISIBLE);
+    }
+
+    private boolean isAppEntityInfosEmpty() {
+        for (AppEntityInfo info : mAppEntityInfos) {
+            if (info != null) {
+                return false;
+            }
+        }
+        return true;
     }
 }
diff --git a/packages/SettingsLib/EntityHeaderWidgets/src/com/android/settingslib/widget/AppEntityInfo.java b/packages/SettingsLib/EntityHeaderWidgets/src/com/android/settingslib/widget/AppEntityInfo.java
new file mode 100644
index 0000000..1e55f2e
--- /dev/null
+++ b/packages/SettingsLib/EntityHeaderWidgets/src/com/android/settingslib/widget/AppEntityInfo.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * AppEntityInfo is responsible for storing app information shown in {@link R.xml.app_view.xml}.
+ */
+public class AppEntityInfo {
+
+    private final Drawable mIcon;
+    private final CharSequence mTitle;
+    private final CharSequence mSummary;
+    private final View.OnClickListener mClickListener;
+
+    /**
+     * Gets the drawable for the icon of app entity.
+     *
+     * @return the drawable for the icon of app entity.
+     */
+    public Drawable getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * Gets the text for the title of app enitity.
+     *
+     * @return the text for the title of app enitity.
+     */
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * Gets the text for the summary of app enitity.
+     *
+     * @return the text for the summary of app enitity.
+     */
+    public CharSequence getSummary() {
+        return mSummary;
+    }
+
+    /**
+     * Gets the click listener for the app entity view.
+     *
+     * @return click listener for the app entity view.
+     */
+    public View.OnClickListener getClickListener() {
+        return mClickListener;
+    }
+
+    private AppEntityInfo(Builder builder) {
+        mIcon = builder.mIcon;
+        mTitle = builder.mTitle;
+        mSummary = builder.mSummary;
+        mClickListener = builder.mClickListener;
+    }
+
+    /**
+     * Builder class for {@link AppEntityInfo}
+     */
+    public static class Builder {
+
+        private Drawable mIcon;
+        private CharSequence mTitle;
+        private CharSequence mSummary;
+        private View.OnClickListener mClickListener;
+
+        /**
+         * Creates an instance of a {@link AppEntityInfo} based on the current builder settings.
+         *
+         * @return The {@link AppEntityInfo}.
+         */
+        public AppEntityInfo build() {
+            return new AppEntityInfo(this);
+        }
+
+        /**
+         * Sets the drawable for the icon.
+         */
+        public Builder setIcon(@NonNull Drawable icon) {
+            mIcon = icon;
+            return this;
+        }
+
+        /**
+         * Sets the text for the title.
+         */
+        public Builder setTitle(@Nullable CharSequence title) {
+            mTitle = title;
+            return this;
+        }
+
+        /**
+         * Sets the text for the summary.
+         */
+        public Builder setSummary(@Nullable CharSequence summary) {
+            mSummary = summary;
+            return this;
+        }
+
+        /**
+         * Sets the click listener for app entity view.
+         */
+        public Builder setOnClickListener(@Nullable View.OnClickListener clickListener) {
+            mClickListener = clickListener;
+            return this;
+        }
+    }
+}
diff --git a/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml b/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml
index 3787005..237d62e 100644
--- a/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-fa/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="search_menu" msgid="1604061903696928905">"تنظیمات جستجو"</string>
+    <string name="search_menu" msgid="1604061903696928905">"جستجوی تنظیمات"</string>
 </resources>
diff --git a/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml b/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml
index cbebbb3..d6dc211 100644
--- a/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml
+++ b/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml
@@ -18,12 +18,11 @@
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android"
             android:paddingMode="stack">
     <item>
-        <shape
-            android:tint="?android:attr/colorForeground">
+        <shape>
             <corners
                 android:radius="20dp"/>
             <solid
-                android:color="@android:color/transparent"/>
+                android:color="?android:attr/colorPrimary"/>
             <stroke
                 android:color="#1f000000"
                 android:width="1dp"/>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 1dd7838..080fcc2 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Outomaties deur %1$s gekoppel"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Outomaties deur netwerkgraderingverskaffer gekoppel"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Gekoppel via %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Beskikbaar via %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Gekoppel, geen internet nie"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Geen internet nie"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Aanmelding word vereis"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Toegangspunt is tydelik vol"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Gekoppel via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Beskikbaar via %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Baie stadig"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Stadig"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nuwe rugsteunwagwoord ingestel"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nuwe wagwoord en bevestiging stem nie ooreen nie"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Rugsteunwagwoord kon nie ingestel word nie"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Laai tans …"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Lewendig (verstek)"</item>
     <item msgid="8446070607501413455">"Natuurlik"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vra elke keer"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Totdat jy dit afskakel"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Sopas"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Aansluitingprogram om opgedateerde grafikadrywer in ontwikkeling te gebruik"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Foonluidspreker"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 2ce5f44..53d1c4d 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"በ%1$s በኩል በራስ-ሰር ተገናኝቷል"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"በአውታረ መረብ ደረጃ ሰጪ አቅራቢ በኩል በራስ-ሰር ተገናኝቷል"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"በ%1$s በኩል መገናኘት"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"በ%1$s በኩል የሚገኝ"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ተገናኝቷል፣ ምንም በይነመረብ የለም"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ምንም በይነመረብ የለም"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ወደ መለያ መግባት ያስፈልጋል"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"የመዳረሻ ነጥብ ለጊዜው ሞልቷል"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"በ%1$s በኩል ተገናኝቷል"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"በ%1$s በኩል የሚገኝ"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"በጣም ቀርፋፋ"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"አዘግይ"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"እሺ"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"አዲስ የምትኬ ይለፍ ቃል ተዋቅሯል"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"አዲሱ የይለፍ ቃል እና ማረጋገጫው አይዛመዱም"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"የምትኬ ይለፍ ቃል ማዋቀር አልተሳካም"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"በመጫን ላይ…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"ነዛሪ (ነባሪ)"</item>
     <item msgid="8446070607501413455">"ተፈጥሯዊ"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ሁልጊዜ ጠይቅ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"እስኪያጠፉት ድረስ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ልክ አሁን"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"በግንባታ ላይ የተዘመነ የግራፊክስ ነጂን ለመጠቀም መተግበሪያን መርጠው ያስገቡ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"የስልክ ድምጽ ማጉያ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 23f3a12..81755a7 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"‏تم الاتصال تلقائيًا عبر %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"تم الاتصال تلقائيًا عبر مقدم خدمة تقييم الشبكة"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏تم الاتصال عبر %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"‏متوفرة عبر %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"متصلة ولكن بلا إنترنت"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"لا يتوفر اتصال إنترنت."</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"يلزم تسجيل الدخول"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"نقطة الدخول ممتلئة مؤقتًا"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"‏تم الاتصال عبر %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"‏متوفرة عبر %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"بطيئة جدًا"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"بطيئة"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"موافق"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"تم تعيين كلمة مرور احتياطية جديدة"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"كلمة المرور الجديدة وتأكيدها لا يتطابقان"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"تعذّر تعيين كلمة مرور احتياطية"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"جارٍ التحميل…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"نابض بالحياة (تلقائي)"</item>
     <item msgid="8446070607501413455">"طبيعي"</item>
@@ -453,6 +528,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"الطلب في كل مرة"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"إلى أن توقف الوضع يدويًا"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"للتو"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"فعِّل التطبيق لاستخدام برنامج تشغيل الرسومات المُحدَّث في تطوير البرامج."</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"مكبر صوت الهاتف"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-as/arrays.xml b/packages/SettingsLib/res/values-as/arrays.xml
index 39c0b00..c0a2179 100644
--- a/packages/SettingsLib/res/values-as/arrays.xml
+++ b/packages/SettingsLib/res/values-as/arrays.xml
@@ -40,7 +40,7 @@
     <item msgid="355508996603873860">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ সৈতে সংযোগ কৰি থকা হৈছে…"</item>
     <item msgid="554971459996405634">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ জৰিয়তে সত্যাপন কৰি থকা হৈছে…"</item>
     <item msgid="7928343808033020343">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ আইপি ঠিকনা পৰা সংগ্ৰহ কৰি থকা হৈছে…"</item>
-    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ সৈতে সংযোগ কৰা হ\'ল"</item>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ সৈতে সংযোগ কৰা হ’ল"</item>
     <item msgid="1330262655415760617">"স্থগিত"</item>
     <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>ৰ পৰা সংযোগ বিচ্ছিন্ন কৰি থকা হৈছে…"</item>
     <item msgid="197508606402264311">"সংযোগ বিচ্ছিন্ন"</item>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 86d1459..6cb0c3e 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -32,19 +32,93 @@
     <string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"\'<xliff:g id="AP_NAME">%1$s</xliff:g>\'ৰ সৈতে সংযোগ কৰিব পৰা নাই"</string>
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"পাছৱৰ্ড পৰীক্ষা কৰি আকৌ চেষ্টা কৰক"</string>
     <string name="wifi_not_in_range" msgid="1136191511238508967">"পৰিসৰৰ ভিতৰত নাই"</string>
-    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"স্বয়ংক্ৰিয়ভাৱে সংযোগ নহ\'ব"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"স্বয়ংক্ৰিয়ভাৱে সংযোগ নহ’ব"</string>
     <string name="wifi_no_internet" msgid="4663834955626848401">"ইণ্টাৰনেট সংযোগ নাই"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>এ ছেভ কৰিছে"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s মাধ্যমেদি স্বয়ংক্ৰিয়ভাৱে সংযোগ কৰা হৈছে"</string>
-    <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"নেটৱৰ্ক ৰেটিং প্ৰদানকাৰীৰ জৰিয়তে স্বয়ং সংয়োগ কৰা হ\'ল"</string>
+    <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"নেটৱৰ্ক ৰেটিং প্ৰদানকাৰীৰ জৰিয়তে স্বয়ং সংয়োগ কৰা হ’ল"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-ৰ মাধ্যমেদি সংযোগ কৰা হৈছে"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$sৰ মাধ্যমেৰে উপলব্ধ"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"সংযোজিত, ইণ্টাৰনেট নাই"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ইণ্টাৰনেট সংযোগ নাই"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ছাইন ইন কৰা দৰকাৰী"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"একচেছ পইণ্ট কিছু সময়ৰ বাবে পূৰ্ণ হৈ আছে"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$sৰ যোগেৰে সংযোজিত"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$sৰ মাধ্যমেৰে উপলব্ধ"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"অতি লেহেম"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"লেহেমীয়া"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ঠিক"</string>
@@ -55,16 +129,16 @@
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"সংযোগ বিচ্ছিন্ন কৰা হ’ল"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"সংযোগ বিচ্ছিন্ন কৰি থকা হৈছে…"</string>
     <string name="bluetooth_connecting" msgid="8555009514614320497">"সংযোগ কৰি থকা হৈছে…"</string>
-    <string name="bluetooth_connected" msgid="5427152882755735944">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> সংযোগ কৰা হ\'ল"</string>
+    <string name="bluetooth_connected" msgid="5427152882755735944">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> সংযোগ কৰা হ’ল"</string>
     <string name="bluetooth_pairing" msgid="1426882272690346242">"যোৰা লগোৱা হৈছে…"</string>
-    <string name="bluetooth_connected_no_headset" msgid="616068069034994802">"সংযোগ কৰা হ\'ল (ফ\'ন নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_a2dp" msgid="3736431800395923868">"সংযোগ কৰা হ\'ল (মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_map" msgid="3200033913678466453">"সংযোগ কৰা হ\'ল (বাৰ্তাত প্ৰৱেশাধিকাৰ নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2047403011284187056">"সংযোগ কৰা হ\'ল (কোনো ফ\'ন বা মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_battery_level" msgid="5162924691231307748">"সংযোগ কৰা হ\'ল, বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_headset_battery_level" msgid="1610296229139400266">"সংযোগ কৰা হ\'ল (ফ\'ন নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_a2dp_battery_level" msgid="3908466636369853652">"সংযোগ কৰা হ\'ল (মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1163440823807659316">"সংযোগ কৰা হ\'ল (কোনো ফ\'ন বা মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_headset" msgid="616068069034994802">"সংযোগ কৰা হ’ল (ফ\'ন নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="3736431800395923868">"সংযোগ কৰা হ’ল (মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_map" msgid="3200033913678466453">"সংযোগ কৰা হ’ল (বাৰ্তাত প্ৰৱেশাধিকাৰ নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2047403011284187056">"সংযোগ কৰা হ’ল (কোনো ফ\'ন বা মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_battery_level" msgid="5162924691231307748">"সংযোগ কৰা হ’ল, বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_headset_battery_level" msgid="1610296229139400266">"সংযোগ কৰা হ’ল (ফ\'ন নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_a2dp_battery_level" msgid="3908466636369853652">"সংযোগ কৰা হ’ল (মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="1163440823807659316">"সংযোগ কৰা হ’ল (কোনো ফ\'ন বা মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
     <string name="bluetooth_active_battery_level" msgid="3149689299296462009">"সক্ৰিয়, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰি"</string>
     <string name="bluetooth_battery_level" msgid="1447164613319663655">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰি"</string>
     <string name="bluetooth_active_no_battery_level" msgid="8380223546730241956">"সক্ৰিয়"</string>
@@ -81,9 +155,9 @@
     <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"এইচ্ছডি অডি\'অ: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
     <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"এইচ্ছডি অডিঅ’"</string>
     <string name="bluetooth_profile_hearing_aid" msgid="7999237886427812595">"শ্ৰৱণ যন্ত্ৰ"</string>
-    <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"শ্ৰৱণ যন্ত্ৰৰ লগত সংযোগ কৰা হ\'ল"</string>
+    <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"শ্ৰৱণ যন্ত্ৰৰ লগত সংযোগ কৰা হ’ল"</string>
     <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"মিডিয়া অডিঅ’লৈ সংযোগ হৈছে"</string>
-    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ফোন অডিঅ\'ৰ লগত সংযোগ কৰা হ\'ল"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ফ’ন অডিঅ\'ৰ লগত সংযোগ কৰা হ’ল"</string>
     <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ফাইল ট্ৰান্সফাৰ ছাৰ্ভাৰৰ সৈতে সংযোজিত হৈ আছে"</string>
     <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"মেপৰ সৈতে সংযোগ কৰক"</string>
     <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAPৰ সৈতে সংযোজিত হৈ আছে"</string>
@@ -206,10 +280,10 @@
     <string name="mock_location_app_not_set" msgid="809543285495344223">"কোনো নকল অৱস্থান এপ্ নিৰ্ধাৰণ কৰা হোৱা নাই"</string>
     <string name="mock_location_app_set" msgid="8966420655295102685">"নকল অৱস্থানৰ এপ্: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="debug_networking_category" msgid="7044075693643009662">"নেটৱৰ্কিং"</string>
-    <string name="wifi_display_certification" msgid="8611569543791307533">"বেতাঁৰ ডিছপ্লে প্ৰমাণীকৰণ"</string>
+    <string name="wifi_display_certification" msgid="8611569543791307533">"বেতাঁৰ ডিছপ্লে’ প্ৰমাণীকৰণ"</string>
     <string name="wifi_verbose_logging" msgid="4203729756047242344">"ৱাই-ফাই ভাৰ্ব\'ছ লগিং সক্ষম কৰক"</string>
     <string name="wifi_connected_mac_randomization" msgid="3168165236877957767">"সংযুক্ত MAC যাদৃচ্ছিকৰণ"</string>
-    <string name="mobile_data_always_on" msgid="8774857027458200434">"ম\'বাইল ডেটা সদা-সক্ৰিয়"</string>
+    <string name="mobile_data_always_on" msgid="8774857027458200434">"ম’বাইল ডেটা সদা-সক্ৰিয়"</string>
     <string name="tethering_hardware_offload" msgid="7470077827090325814">"টেডাৰিং হাৰ্ডৱেৰ ত্বৰণ"</string>
     <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"নামবিহীন ব্লুটুথ ডিভাইচসমূহ দেখুৱাওক"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"পূৰ্ণ মাত্ৰাৰ ভলিউম অক্ষম কৰক"</string>
@@ -233,7 +307,7 @@
     <string name="private_dns_mode_provider" msgid="8354935160639360804">"ব্যক্তিগত ডিএনএছ প্ৰদানকাৰীৰ হোষ্টনাম"</string>
     <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"ডিএনএছ সেৱা যোগানকাৰীৰ হ\'ষ্টনাম দিয়ক"</string>
     <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"সংযোগ কৰিব পৰা নগ\'ল"</string>
-    <string name="wifi_display_certification_summary" msgid="1155182309166746973">"বেতাঁৰ ডিছপ্লে প্ৰমাণপত্ৰৰ বাবে বিকল্পসমূহ দেখুৱাওক"</string>
+    <string name="wifi_display_certification_summary" msgid="1155182309166746973">"বেতাঁৰ ডিছপ্লে’ প্ৰমাণপত্ৰৰ বাবে বিকল্পসমূহ দেখুৱাওক"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ৱাই-ফাই লগিঙৰ মাত্ৰা বঢ়াওক, Wi‑Fi পিকাৰত প্ৰতি SSID RSSI দেখুৱাওক"</string>
     <string name="wifi_connected_mac_randomization_summary" msgid="1743059848752201485">"ৱাই-ফাই নেটৱৰ্কৰ লগত সংযোগ কৰি থকাৰ সময়ত MAC ঠিকনা যাদৃচ্ছিক কৰক"</string>
     <string name="wifi_metered_label" msgid="4514924227256839725">"নিৰিখ-নিৰ্দিষ্ট"</string>
@@ -249,7 +323,7 @@
     <string name="allow_mock_location" msgid="2787962564578664888">"নকল অৱস্থানৰ অনুমতি দিয়ক"</string>
     <string name="allow_mock_location_summary" msgid="317615105156345626">"নকল অৱস্থানৰ অনুমতি দিয়ক"</string>
     <string name="debug_view_attributes" msgid="6485448367803310384">"দৃশ্যৰ গুণাগুণ নিৰীক্ষণ সক্ষম কৰক"</string>
-    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"ৱাই-ফাই থকা সময়তো সদায় ম\'বাইল ডেটা সক্ৰিয় ৰাখক (খৰতকীয়াকৈ নেটৱৰ্ক সলনি কৰিবৰ বাবে)।"</string>
+    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"ৱাই-ফাই থকা সময়তো সদায় ম’বাইল ডেটা সক্ৰিয় ৰাখক (খৰতকীয়াকৈ নেটৱৰ্ক সলনি কৰিবৰ বাবে)।"</string>
     <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"যদিহে উপলব্ধ হয় তেন্তে টেডাৰিং হাৰ্ডৱেৰ ত্বৰণ ব্যৱহাৰ কৰক"</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"ইউএছবি ডিবাগিঙৰ অনুমতি দিয়েনে?"</string>
     <string name="adb_warning_message" msgid="7316799925425402244">"ইউএছবি ডিবাগ কৰা কাৰ্য কেৱল বিকাশৰ উদ্দেশ্যৰেহে কৰা হৈছে৷ আপোনাৰ কম্পিউটাৰ আৰু আপোনাৰ ডিভাইচৰ মাজত ডেটা প্ৰতিলিপি কৰিবলৈ এইটো ব্যৱহাৰ কৰক, কোনো জাননী নিদিয়াকৈয়ে আপোনাৰ ডিভাইচত এপ্‌সমূহ ইনষ্টল কৰক আৰু লগ ডেটা পঢ়ক৷"</string>
@@ -285,7 +359,7 @@
     <string name="show_touches_summary" msgid="6101183132903926324">"টিপিলে দৃশ্যায়িত ফীডবেক দিয়ক"</string>
     <string name="show_screen_updates" msgid="5470814345876056420">"পৃষ্ঠভাগৰ আপডেইট দেখুৱাওক"</string>
     <string name="show_screen_updates_summary" msgid="2569622766672785529">"আপডেইট হওতে গোটেই ৱিণ্ড পৃষ্ঠসমূহ ফ্লাশ্ব কৰক"</string>
-    <string name="show_hw_screen_updates" msgid="4117270979975470789">"আপডেট চাওক দেখুৱাওক"</string>
+    <string name="show_hw_screen_updates" msgid="4117270979975470789">"আপডে’ট চাওক দেখুৱাওক"</string>
     <string name="show_hw_screen_updates_summary" msgid="6506943466625875655">"অঁকাৰ সময়ত ৱিণ্ড\'ৰ ভিতৰত ফ্লাশ্ব দৰ্শন"</string>
     <string name="show_hw_layers_updates" msgid="5645728765605699821">"হাৰ্ডৱেৰৰ তৰপৰ আপডেইট দেখুৱাওক"</string>
     <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"হাৰ্ডৱেৰ লেয়াৰ আপডেইট হওতে সিঁহতক সেউজীয়া ৰঙেৰে ফ্লাশ্ব কৰক"</string>
@@ -327,9 +401,10 @@
     <string name="local_backup_password_title" msgid="3860471654439418822">"ডেস্কটপ বেকআপ পাছৱৰ্ড"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ডেস্কটপৰ পূৰ্ণ বেকআপ এতিয়ালৈকে সংৰক্ষিত অৱস্থাত নাই"</string>
     <string name="local_backup_password_summary_change" msgid="5376206246809190364">"ডেস্কটপ সম্পূৰ্ণ বেকআপৰ বাবে পাছৱৰ্ডটো সলনি কৰিবলৈ বা আঁতৰাবলৈ টিপক"</string>
-    <string name="local_backup_password_toast_success" msgid="582016086228434290">"নতুন বেকআপ পাছৱৰ্ড ছেট কৰা হ\'ল"</string>
+    <string name="local_backup_password_toast_success" msgid="582016086228434290">"নতুন বেকআপ পাছৱৰ্ড ছেট কৰা হ’ল"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"নতুন পাছৱৰ্ডটোৰ লগত নিশ্চিত কৰা পাছৱৰ্ডটো মিলা নাই"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"বেকআপ পাছৱৰ্ড নিৰ্ধাৰণ কৰিব পৰা নহ\'ল"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ল’ড হৈ আছে…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"জীৱন্ত (ডিফ\'ল্ট)"</item>
     <item msgid="8446070607501413455">"প্ৰাকৃতিক"</item>
@@ -422,15 +497,15 @@
     <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"ছিষ্টেমৰ ভাষা ব্যৱহাৰ কৰক"</string>
     <string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>ৰ ছেটিংবিলাক খুলিব পৰা নগ\'ল"</string>
     <string name="ime_security_warning" msgid="4135828934735934248">"এই ইনপুট পদ্ধতিটোৱে আপুনি টাইপ কৰা আপোনাৰ ব্যক্তিগত ডেটা যেনে পাছৱৰ্ডসমূহ আৰু ক্ৰেডিট কাৰ্ডৰ নম্বৰসমূহকে ধৰি সকলো পাঠ সংগ্ৰহ কৰিবলৈ সক্ষম হ\'ব পাৰে। <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> এপটোৰ লগত ই সংলগ্ন। এই ইনপুট পদ্ধতিটো ব্যৱহাৰ কৰেনে?"</string>
-    <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"টোকা: ৰিবুট কৰাৰ পিছত আপুনি ফ\'নটো আনলক নকৰালৈকে এই এপটো ষ্টাৰ্ট নহ\'ব"</string>
+    <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"টোকা: ৰিবুট কৰাৰ পিছত আপুনি ফ\'নটো আনলক নকৰালৈকে এই এপটো ষ্টাৰ্ট নহ’ব"</string>
     <string name="ims_reg_title" msgid="7609782759207241443">"আইএমএছ পঞ্জীয়ন স্থিতি"</string>
     <string name="ims_reg_status_registered" msgid="933003316932739188">"পঞ্জীকৃত"</string>
     <string name="ims_reg_status_not_registered" msgid="6529783773485229486">"পঞ্জীকৃত নহয়"</string>
     <string name="status_unavailable" msgid="7862009036663793314">"উপলব্ধ নহয়"</string>
     <string name="wifi_status_mac_randomized" msgid="5589328382467438245">"MAC ক্ৰমানুসৰি ছেট কৰা হোৱা নাই"</string>
     <plurals name="wifi_tether_connected_summary" formatted="false" msgid="3871603864314407780">
-      <item quantity="one">%1$dটা ডিভাইচ সংযোগ হ\'ল</item>
-      <item quantity="other">%1$dটা ডিভাইচ সংযোগ হ\'ল</item>
+      <item quantity="one">%1$dটা ডিভাইচ সংযোগ হ’ল</item>
+      <item quantity="other">%1$dটা ডিভাইচ সংযোগ হ’ল</item>
     </plurals>
     <string name="accessibility_manual_zen_more_time" msgid="1636187409258564291">"অধিক সময়।"</string>
     <string name="accessibility_manual_zen_less_time" msgid="6590887204171164991">"কম সময়।"</string>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"প্ৰতিবাৰতে সোধক"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"আপুনি অফ নকৰা পর্যন্ত"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"এই মাত্ৰ"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"বিকাশকাৰ্য চলি থকা আপডে\'টেড গ্ৰাফিক ড্ৰাইভাৰ ব্যৱহাৰ কৰিবলৈ এপ্ অপ্ট ইন কৰক"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ফ’নৰ স্পীকাৰ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 17d0ca6..d30834f2 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s üzərindən avtomatik qoşuldu"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Avtomatik olaraq şəbəkə reytinq provayderi ilə qoşuludur"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s vasitəsilə qoşuludur"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s vasitəsilə əlçatandır"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Qoşuludur, internet yoxdur"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"İnternet yoxdur"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Giriş tələb olunur"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Giriş nöqtəsi müvəqqəti olaraq doludur"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ilə qoşuludur"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s vasitəsilə əlçatandır"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Çox Yavaş"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Yavaş"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Yeni rezerv parolu ayarlandı"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Yeni parol və parolun təkrarı uyğun gəlmir"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Yedəkləmə parolu xətası"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Yüklənir…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Canlı (defolt)"</item>
     <item msgid="8446070607501413455">"Təbii"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Hər dəfə soruşun"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Deaktiv edənə qədər"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"İndicə"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Qrafik drayverdən istifadə etmək üçün tətbiq seçin"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon spikeri"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 56052d2..427daab 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatski povezano preko %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatski povezano preko dobavljača ocene mreže"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Veza je uspostavljena preko pristupne tačke %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Dostupna je preko pristupne tačke %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Veza je uspostavljena, nema interneta"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nema interneta"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Treba da se prijavite"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Pristupna tačka je privremeno zauzeta"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Povezano preko %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Dostupno preko %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Veoma spora"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Spora"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Potvrdi"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Postavljena je nova lozinka rezervne kopije"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova lozinka i njena potvrda se ne podudaraju"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Postavljanje lozinke rezervne kopije nije uspelo"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Učitava se…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Živopisan (podrazumevano)"</item>
     <item msgid="8446070607501413455">"Prirodan"</item>
@@ -450,6 +525,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Uvek pitaj"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Upravo"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Omogući aplikaciju za korišćenje upravljačkog programa grafičke katice u razvoju"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvučnik telefona"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index f2c2046..a156caf 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Аўтаматычна падключана праз %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Аўтаматычна падключана праз пастаўшчыка паслугі ацэнкі сеткі"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Падлучана праз %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Даступна праз %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Падключана, без доступу да інтэрнэту"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Не падключана да інтэрнэту"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Трэба выканаць уваход"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Пункт доступу часова заняты"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Падлучана праз %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Даступна праз %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Вельмі павольная"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Павольная"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ОК"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Усталяваны новы пароль для рэзервовага капіявання"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Новы пароль і яго пацвярджэнне не супадаюць"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Збой пры ўсталёўцы паролю для рэзервовага капіявання"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Ідзе загрузка…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Сочны (па змаўчанні)"</item>
     <item msgid="8446070607501413455">"Натуральны"</item>
@@ -451,6 +526,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Заўсёды пытацца"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Пакуль не выключыце"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Зараз"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Выбраная праграма, якая выкарыстоўвае абноўлены драйвер графічнай сістэмы (падчас распрацоўкі)"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Дынамік тэлефона"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 5b8d6b8..8333646 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Автоматично е установена връзка чрез %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Автоматично е установена връзка чрез доставчик на услуги за оценяване на мрежите"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Установена е връзка през „%1$s“"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Мрежата е достъпна през „%1$s“"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Установена е връзка – няма достъп до интернет"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Няма връзка с интернет"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Изисква се вход в профила"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Точката за достъп временно е пълна"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Установена е връзка през %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Мрежата е достъпна през %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Много бавна"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Бавна"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ОK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Зададена е нова парола за резервно копие"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Новата парола и въведената за потвърждаване не съвпадат"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Задаването на парола за резервно копие не бе успешно"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Зарежда се…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Ярък (по подразбиране)"</item>
     <item msgid="8446070607501413455">"Естествен"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Да се пита винаги"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"До изключване"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Току-що"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Включване на приложението за използване на актуализирания графичен драйвер в разработка"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Високоговорител на телефона"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 7efad99..c7b3afea 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"স্বয়ংক্রিয়ভাবে %1$s এর মাধ্যমে কানেক্ট হয়েছে"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"নেটওয়ার্কের রেটিং প্রদানকারীর মাধ্যমে অটোমেটিক কানেক্ট"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s মাধ্যমে কানেক্ট হয়েছে"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s এর মাধ্যমে উপলব্ধ"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"কানেক্ট, ইন্টারনেট নেই"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ইন্টারনেট কানেকশন নেই"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"সাইন-ইন করা দরকার"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"এই মুহূর্তে অ্যাক্সেস পয়েন্টের কোনও কানেকশন ফাঁকা নেই"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s এর মাধ্যমে কানেক্ট হয়েছে"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s এর মাধ্যমে পাওয়া যাচ্ছে"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"খুব ধীরে"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"ধীরে"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ঠিক আছে"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"নতুন ব্যাকআপ পাসওয়ার্ড সেট করুন"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"নতুন পাসওয়ার্ড এবং নিশ্চিতকরণ মিলছে না"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ব্যাকআপ পাসওয়ার্ড সেট করা ব্যর্থ"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"লোড হচ্ছে…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"ভাইব্রেন্ট (ডিফল্ট)"</item>
     <item msgid="8446070607501413455">"প্রাকৃতিক"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"প্রতিবার জিজ্ঞেস করা হবে"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"যতক্ষণ না আপনি বন্ধ করছেন"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"এখনই"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ডেভলপমেন্টে আপডেট হওয়া গ্রাফিক্স ড্রাইভার ব্যবহার করতে অ্যাপ বেছে নিন"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ফেনের স্পিকার"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 92435f7..715a8a5 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -27,7 +27,7 @@
     <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Greška u konfiguraciji IP-a"</string>
     <string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"Niste povezani zbog slabog kvaliteta mreže"</string>
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Greška pri povezivanju na WiFi"</string>
-    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem pri provjeri vjerodostojnosti."</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem pri autentifikaciji."</string>
     <string name="wifi_cant_connect" msgid="5410016875644565884">"Nije se moguće povezati"</string>
     <string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"Nije se moguće povezati na aplikaciju \'<xliff:g id="AP_NAME">%1$s</xliff:g>\'"</string>
     <string name="wifi_check_password_try_again" msgid="516958988102584767">"Provjerite lozinku i pokušajte ponovo"</string>
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatski povezano koristeći %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatski povezano putem ocjenjivača mreže"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Povezani preko %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Dostupan preko %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Povezano, nema interneta"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nema internetske veze"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Potrebna je prijava"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Pristupna tačka je privremeno puna"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Povezano koristeći %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Dostupna koristeći %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Veoma sporo"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Sporo"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"UREDU"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova lozinka za sigurnosnu kopiju je postavljena"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova lozinka i potvrda se ne podudaraju"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nije uspjelo postavljanje lozinke za sigurnosnu kopiju"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Učitavanje…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Živopisno (zadano)"</item>
     <item msgid="8446070607501413455">"Prirodan"</item>
@@ -450,6 +525,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pitaj svaki put"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Upravo"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Prijavi aplikaciju za korištenje ažuriranog grafičkog drajvera u razvoju"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvučnik telefona"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 3182f16..56f55dd 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Connectada automàticament a través de: %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Connectada automàticament a través d\'un proveïdor de valoració de xarxes"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connectada mitjançant %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible mitjançant %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connectada, sense Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Sense connexió a Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Cal iniciar la sessió"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"El punt d\'accés està temporalment ple"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Connectat mitjançant %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Disponible mitjançant %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Molt lenta"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lenta"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Correcta"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"S\'ha definit una contrasenya de seguretat nova"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"La contrasenya nova i la confirmació no coincideixen"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Error en definir la contrasenya de seguretat"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Carregant…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (predeterminat)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pregunta sempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Fins que no ho desactivis"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Ara mateix"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Aplicació activada per utilitzar el controlador de gràfics actualitzat en desenvolupament"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altaveu del telèfon"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 3785433..edbb358 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automaticky připojeno přes poskytovatele %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automaticky připojeno přes poskytovatele hodnocení sítí"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Připojeno prostřednictvím %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Dostupné prostřednictvím %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Připojeno, není k dispozici internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nejste připojeni k internetu"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Je vyžadováno přihlášení"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Přístupový bod je dočasně zaplněn"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Připojeno prostřednictvím %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Dostupné prostřednictvím %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Velmi pomalá"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Pomalá"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nové heslo pro zálohy je nastaveno"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nové heslo se neshoduje s potvrzením hesla."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nastavení hesla pro zálohy selhalo"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Načítání…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Jasné (výchozí)"</item>
     <item msgid="8446070607501413455">"Přirozené"</item>
@@ -451,6 +526,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pokaždé se zeptat"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dokud tuto funkci nevypnete"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Právě teď"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Přihlaste aplikaci k použití vyvíjeného aktualizovaného grafického ovladače"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Reproduktor telefonu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index eeeccee..1d34579 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatisk tilsluttet via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatisk forbundet via udbyder af netværksvurdering"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Tilsluttet via %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Tilgængelig via %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Tilsluttet – intet internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Intet internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Login er påkrævet"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Adgangspunktet er midlertidigt fuldt"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Tilsluttet via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Tilgængelig via %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Meget langsom"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Langsom"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -73,8 +147,8 @@
     <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Filoverførsel"</string>
     <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Inputenhed"</string>
     <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internetadgang"</string>
-    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Deling af kontaktpersoner"</string>
-    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Brug til deling af kontaktpersoner"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Deling af kontakter"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Brug til deling af kontakter"</string>
     <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Deling af internetforbindelse"</string>
     <string name="bluetooth_profile_map" msgid="1019763341565580450">"Sms-beskeder"</string>
     <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-adgang"</string>
@@ -102,7 +176,7 @@
     <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Par"</string>
     <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ACCEPTÉR PARRING"</string>
     <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Annuller"</string>
-    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Parring giver adgang til dine kontaktpersoner og din opkaldshistorik, når enhederne er forbundet."</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Parring giver adgang til dine kontakter og din opkaldshistorik, når enhederne er forbundet."</string>
     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Der kunne ikke parres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Der kunne ikke parres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g> på grund af en forkert pinkode eller adgangsnøgle."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Der kan ikke kommunikeres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
@@ -252,7 +326,7 @@
     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Hold altid mobildata aktiveret, selv når Wi-Fi er aktiveret (for at skifte hurtigt mellem netværk)."</string>
     <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Brug hardwareacceleration ved netdeling, hvis det er muligt"</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"Vil du tillade USB-fejlretning?"</string>
-    <string name="adb_warning_message" msgid="7316799925425402244">"USB-fejlretning er kun beregnet til udvikling og kan bruges til at kopiere data mellem din computer og enheden, installere apps på enheden uden underretning og læse logdata."</string>
+    <string name="adb_warning_message" msgid="7316799925425402244">"USB-fejlretning er kun beregnet til udvikling og kan bruges til at kopiere data mellem din computer og enheden, installere apps på enheden uden notifikation og læse logdata."</string>
     <string name="adb_keys_warning_message" msgid="5659849457135841625">"Vil du ophæve adgangen til USB-fejlfinding for alle computere, du tidligere har godkendt?"</string>
     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Vil du tillade udviklingsindstillinger?"</string>
     <string name="dev_settings_warning_message" msgid="2298337781139097964">"Disse indstillinger er kun beregnet til brug i forbindelse med udvikling. De kan forårsage, at din enhed og dens apps går ned eller ikke fungerer korrekt."</string>
@@ -316,8 +390,8 @@
     <string name="app_process_limit_title" msgid="4280600650253107163">"Grænse for baggrundsprocesser"</string>
     <string name="show_all_anrs" msgid="4924885492787069007">"Vis ANR-fejl i baggrunden"</string>
     <string name="show_all_anrs_summary" msgid="6636514318275139826">"Vis dialogboksen \"Appen svarer ikke\" for baggrundsapps"</string>
-    <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Vis advarsler om underretningskanal"</string>
-    <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Viser en advarsel, når en app sender en underretning uden en gyldig kanal"</string>
+    <string name="show_notification_channel_warnings" msgid="1399948193466922683">"Vis advarsler om notifikationskanal"</string>
+    <string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"Viser en advarsel, når en app sender en notifikation uden en gyldig kanal"</string>
     <string name="force_allow_on_external" msgid="3215759785081916381">"Gennemtving tilladelse til eksternt lager"</string>
     <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Gør det muligt at overføre enhver app til et eksternt lager uafhængigt af manifestværdier"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til at kunne tilpasses"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Ny adgangskode til sikkerhedskopi er angivet"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Ny adgangskode og bekræftelse matcher ikke"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Fejl ved angivelse af adgangskode til sikkerhedskopi"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Indlæser…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Klare (standard)"</item>
     <item msgid="8446070607501413455">"Naturlige"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Spørg hver gang"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Indtil du deaktiverer"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Lige nu"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Tilvælg en app, der skal bruge den opdaterede grafikdriver under udvikling"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefonens højttaler"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 95f7416..1abc359 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatisch über %1$s verbunden"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatisch über Anbieter von Netzwerkbewertungen verbunden"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Über %1$s verbunden"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Verfügbar über %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Verbunden, kein Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Kein Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Anmeldung erforderlich"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Zugangspunkt vorübergehend voll belegt"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Über %1$s verbunden"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Verfügbar über %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Sehr langsam"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Langsam"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Neues Sicherungspasswort festgelegt"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Das neue Passwort und die Bestätigung stimmen nicht überein."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Fehler beim Festlegen des Sicherungspassworts"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Wird geladen…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Brillant (Standardeinstellung)"</item>
     <item msgid="8446070607501413455">"Natürlich"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Jedes Mal fragen"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Bis zur Deaktivierung"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Gerade eben"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"App aktivieren, um den aktualisierten Grafiktreiber in der Entwicklung zu verwenden"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon-Lautsprecher"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 310b6cf..eb57558 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Συνδέθηκε αυτόματα μέσω %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Συνδέθηκε αυτόματα μέσω παρόχου αξιολόγησης δικτύου"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Συνδέθηκε μέσω %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Διαθέσιμο μέσω %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Συνδέθηκε, χωρίς σύνδεση στο διαδίκτυο"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Δεν υπάρχει σύνδεση στο διαδίκτυο"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Απαιτείται σύνδεση"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Το σημείο πρόσβασης είναι προσωρινά πλήρες"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Συνδέθηκε μέσω %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Διαθέσιμο μέσω %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Πολύ αργή"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Αργή"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ΟΚ"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Ορίστηκε νέος εφεδρικός κωδικός πρόσβασης"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Ο νέος κωδικός πρόσβασης και η επιβεβαίωση δεν ταιριάζουν"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Αποτυχία κατά τον ορισμό εφεδρικού κωδικού πρόσβασης"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Φόρτωση…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Ζωντανό (προεπιλογή)"</item>
     <item msgid="8446070607501413455">"Φυσικό"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Να ερωτώμαι κάθε φορά"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Μέχρι την απενεργοποίηση"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Μόλις τώρα"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Επιλέξτε μια εφαρμογή για τη χρήση του ενημερωμένου προγράμματος οδήγησης γραφικών σε ανάπτυξη"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Ηχείο τηλεφώνου"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 5b11d63..1f74d9b1 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatically connected via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatically connected via network rating provider"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connected, no Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"No Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Sign-in required"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Access point temporarily full"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Connected via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Available via %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Very slow"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Slow"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"New backup password set"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"New password and confirmation don\'t match"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Failure setting backup password"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Loading…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (default)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 5b11d63..1f74d9b1 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatically connected via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatically connected via network rating provider"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connected, no Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"No Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Sign-in required"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Access point temporarily full"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Connected via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Available via %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Very slow"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Slow"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"New backup password set"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"New password and confirmation don\'t match"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Failure setting backup password"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Loading…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (default)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 5b11d63..1f74d9b1 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatically connected via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatically connected via network rating provider"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connected, no Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"No Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Sign-in required"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Access point temporarily full"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Connected via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Available via %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Very slow"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Slow"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"New backup password set"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"New password and confirmation don\'t match"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Failure setting backup password"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Loading…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (default)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 5b11d63..1f74d9b1 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatically connected via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatically connected via network rating provider"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connected, no Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"No Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Sign-in required"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Access point temporarily full"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Connected via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Available via %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Very slow"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Slow"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"New backup password set"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"New password and confirmation don\'t match"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Failure setting backup password"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Loading…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (default)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ask every time"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Opt in app to use updated graphics driver in development"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Phone speaker"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index d7ed49a..082a331 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -38,13 +38,50 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‏‎‏‎Automatically connected via %1$s‎‏‎‎‏‎"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎Automatically connected via network rating provider‎‏‎‎‏‎"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‎Connected via %1$s‎‏‎‎‏‎"</string>
+    <string name="ssid_by_passpoint_provider" msgid="7898171424140673315">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‎‎‎‎‏‎‏‏‏‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="SSID">%1$s</xliff:g>‎‏‎‎‏‏‏‎ by ‎‏‎‎‏‏‎<xliff:g id="PASSPOINTPROVIDER">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎Available via %1$s‎‏‎‎‏‎"</string>
+    <string name="tap_to_set_up" msgid="2468970825530423314">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‎‏‎‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎Tap to set up‎‏‎‎‏‎"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎Connected, no internet‎‏‎‎‏‎"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‎‏‎‏‎‎‏‎No internet‎‏‎‎‏‎"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎Sign in required‎‏‎‎‏‎"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‏‏‎‏‎Access point temporarily full‎‏‎‎‏‎"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎Connected via %1$s‎‏‎‎‏‎"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‏‏‎‏‎‎‎‏‏‎‏‏‎‏‎‏‎‎‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‎Available via %1$s‎‏‎‎‏‎"</string>
+    <string name="osu_failure_ap_connection" msgid="598977488344424542">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‏‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‎‏‏‏‏‎‎Connection failed‎‏‎‎‏‎"</string>
+    <string name="osu_failure_server_url_invalid" msgid="2237477219243136714">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‎‏‎‏‎‎Invalid OSU server URL‎‏‎‎‏‎"</string>
+    <string name="osu_failure_server_connection" msgid="8192988165059982174">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎OSU server connection failed‎‏‎‎‏‎"</string>
+    <string name="osu_failure_server_validation" msgid="4631649978129606823">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‏‏‎OSU server validation failed‎‏‎‎‏‎"</string>
+    <string name="osu_failure_service_provider_verification" msgid="4854091521439785597">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎Invalid OSU server certificate‎‏‎‎‏‎"</string>
+    <string name="osu_failure_provisioning_aborted" msgid="424627208135320329">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‎Provisioning aborted‎‏‎‎‏‎"</string>
+    <string name="osu_failure_provisioning_not_available" msgid="3021783729256985432">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎Provisioning not available‎‏‎‎‏‎"</string>
+    <string name="osu_failure_invalid_server_url" msgid="8548886196179435758">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‎‎‎‎‎‎‎‎‏‏‏‎‏‏‏‎‎Invalid OSU server URL‎‏‎‎‏‎"</string>
+    <string name="osu_failure_unexpected_command_type" msgid="8245921319866603904">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‏‏‎‎‎‏‏‏‏‎‎‎‎‎‎‏‏‎‎‏‏‎‎‎‎‎‎‎‎Unexpected command type‎‏‎‎‏‎"</string>
+    <string name="osu_failure_unexpected_soap_message_type" msgid="2255897608510053065">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‎‏‎Unexpected SOAP message type‎‏‎‎‏‎"</string>
+    <string name="osu_failure_soap_message_exchange" msgid="4357358438685987192">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‎‎‎SOAP message exchange failed‎‏‎‎‏‎"</string>
+    <string name="osu_failure_start_redirect_listener" msgid="4292769407279548482">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‎‎‎‏‎‎Redirect listener failed to start‎‏‎‎‏‎"</string>
+    <string name="osu_failure_timed_out_redirect_listener" msgid="3168657820278807508">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‎Timed out waiting for redirect‎‏‎‎‏‎"</string>
+    <string name="osu_failure_no_osu_activity_found" msgid="4593038891437878675">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‎‎‏‎‏‏‎‏‎‏‏‏‎‏‏‎‏‎‏‎‏‏‎‏‏‎‏‏‎‎‏‎‎‏‏‎No OSU activity found‎‏‎‎‏‎"</string>
+    <string name="osu_failure_unexpected_soap_message_status" msgid="6568467710235256675">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‎‏‎‎‏‏‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‎‏‏‎‎‎‏‏‎Unexpected SOAP message status‎‏‎‎‏‎"</string>
+    <string name="osu_failure_no_pps_mo" msgid="850567403039076835">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎Failed to find PPS-MO‎‏‎‎‏‎"</string>
+    <string name="osu_failure_no_aaa_server_trust_root_node" msgid="8961455873459838456">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‏‎‎‎‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‏‏‎‏‏‏‏‏‏‎‎‎‎Failed to find trust root node for AAA server‎‏‎‎‏‎"</string>
+    <string name="osu_failure_no_remediation_server_trust_root_node" msgid="5041179688081545244">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎Failed to find trust root node for remediation server‎‏‎‎‏‎"</string>
+    <string name="osu_failure_no_policy_server_trust_root_node" msgid="6617290380940513539">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎Failed to find trust root node for policy server‎‏‎‎‏‎"</string>
+    <string name="osu_failure_retrieve_trust_root_certificates" msgid="1499136256195528265">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‏‎‎‏‎Failed to retrieve trust root certificates‎‏‎‎‏‎"</string>
+    <string name="osu_failure_no_aaa_trust_root_certificate" msgid="1904322497042226984">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‎Failed to find trust root certificate for AAA server‎‏‎‎‏‎"</string>
+    <string name="osu_failure_add_passpoint_configuration" msgid="2173557755811446047">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‎Failed to add PassPoint configuration‎‏‎‎‏‎"</string>
+    <string name="osu_failure_osu_provider_not_found" msgid="6616172862116673082">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎‎‎‏‏‏‎‏‎‎Failed to find an OSU provider‎‏‎‎‏‎"</string>
+    <string name="osu_status_ap_connecting" msgid="5296821043003441437">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‎‎‎‏‎‎‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‎‏‏‎‎‎‎‎‏‎‎‎‏‏‏‎‏‎Connecting‎‏‎‎‏‎"</string>
+    <string name="osu_status_ap_connected" msgid="3777289375683170728">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‏‏‎‏‎‏‎‎‎‎Connected‎‏‎‎‏‎"</string>
+    <string name="osu_status_server_connecting" msgid="8499785407540355867">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‏‏‎Connecting to OSU server‎‏‎‎‏‎"</string>
+    <string name="osu_status_server_validated" msgid="3158727184762596355">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‏‎‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‎‎‏‏‎OSU server validated‎‏‎‎‏‎"</string>
+    <string name="osu_status_server_connected" msgid="8382024481520158168">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‎‎‎‎Connected to OSU server‎‏‎‎‏‎"</string>
+    <string name="osu_status_init_soap_exchange" msgid="8628063888912101981">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‎‎‏‎‏‏‏‎‏‎Initial SOAP exchange‎‏‎‎‏‎"</string>
+    <string name="osu_status_waiting_for_redirect_response" msgid="2343016207837053197">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‎‎‎‎‏‏‎‏‎‎‏‏‏‏‎‎‎‎‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‎‎‏‎‎‎‎‏‏‎‏‎Waiting for redirect response‎‏‎‎‏‎"</string>
+    <string name="osu_status_redirect_response_received" msgid="5323368411922609405">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‎‎‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‏‏‎‏‎Received redirect response‎‏‎‎‏‎"</string>
+    <string name="osu_status_second_soap_exchange" msgid="7115332266758483909">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‏‎Second SOAP exchange‎‏‎‎‏‎"</string>
+    <string name="osu_status_third_soap_exchange" msgid="8460901783597440766">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‏‎‏‎‏‏‎‎‎‎‎‏‎‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‎‏‏‏‏‏‏‏‎‎Third SOAP exchange‎‏‎‎‏‎"</string>
+    <string name="osu_status_retrieving_trust_root_certs" msgid="1563445892926269689">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎Retrieving trust root certificates‎‏‎‎‏‎"</string>
+    <string name="osu_provisioning_complete" msgid="5120178802493970149">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎Provisioning complete‎‏‎‎‏‎"</string>
     <string name="speed_label_very_slow" msgid="1867055264243608530">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‎Very Slow‎‏‎‎‏‎"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‎‎‎‎‏‎‏‎‎‎‏‎‎‎‏‎‏‎‏‏‏‎‏‏‎Slow‎‏‎‎‏‎"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎OK‎‏‎‎‏‎"</string>
@@ -330,6 +367,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎New backup password set‎‏‎‎‏‎"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‎‏‎‏‏‎‎‎‎‎‎‎New password and confirmation don’t match‎‏‎‎‏‎"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‏‎‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎Failure setting backup password‎‏‎‎‏‎"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‎‎Loading…‎‏‎‎‏‎"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎Vibrant (default)‎‏‎‎‏‎"</item>
     <item msgid="8446070607501413455">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎Natural‎‏‎‎‏‎"</item>
@@ -449,6 +487,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‎‏‎Ask every time‎‏‎‎‏‎"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎Until you turn off‎‏‎‎‏‎"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎Just now‎‏‎‎‏‎"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‏‏‎‎‏‏‏‏‎Opt in app to use updated graphcis driver in developement‎‏‎‎‏‎"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎Phone speaker‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index ecec63c..795ad9c 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Conexión automática mediante %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Conectado automáticamente mediante proveedor de calificación de red"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conexión a través de %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible a través de %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conectado pero sin conexión a Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Sin Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Acceso obligatorio"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"El punto de acceso está completo temporalmente"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Conexión a través de %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Disponible a través de %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Muy lenta"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lenta"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Aceptar"</string>
@@ -144,7 +218,7 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Salida de texto a voz"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Velocidad de voz"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidad en la que se habla el texto"</string>
-    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Sonido"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tono"</string>
     <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afecta el tono de la voz sintetizada"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Usar el idioma del sistema"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nueva contraseña de copia de seguridad definida"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"La nueva contraseña y la de confirmación no coinciden."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Error al definir contraseña de copia de seguridad"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Cargando…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrante (predeterminado)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Preguntar siempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Hasta que lo desactives"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Recién"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Habilitar app para que use el controlador de gráficos actualizado en el desarrollo"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altavoz del teléfono"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index b8fdf30..669871f 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Conectada automáticamente a través de %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Conectado automáticamente a través de un proveedor de valoración de redes"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible a través de %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conexión sin Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Sin Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Debes iniciar sesión"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Punto de acceso temporalmente lleno"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Conectado a través de %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Disponible a través de %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Muy lenta"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lenta"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Aceptable"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nueva contraseña de seguridad establecida"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"La nueva contraseña y la de confirmación no coinciden"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Error al establecer la contraseña de seguridad"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Cargando…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrante (predeterminado)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Preguntar siempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Hasta que se desactive"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Justo ahora"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Habilitar aplicación para usar controlador de gráficos actualizado en desarrollo"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altavoz del teléfono"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 1246626..0c9d28e 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Ühendus loodi automaatselt teenusega %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Ühendus loodi automaatselt võrgukvaliteedi hinnangute pakkuja kaudu"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Ühendatud üksuse %1$s kaudu"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Saadaval üksuse %1$s kaudu"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Ühendatud, Interneti-ühendus puudub"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Interneti-ühendus puudub"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Nõutav on sisselogimine"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Pääsupunkt on ajutiselt täis"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Ühendatud operaatori %1$s kaudu"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Saadaval operaatori %1$s kaudu"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Väga aeglane"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Aeglane"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Hea"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Uus varuparool on määratud"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Uus parool ja kinnitus ei ühti"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Varuparooli määramine ebaõnnestus"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Laadimine …"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Ere (vaikeseade)"</item>
     <item msgid="8446070607501413455">"Loomulikud"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Küsi iga kord"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Kuni välja lülitate"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Äsja"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Lubage rakendus, et kasutada arenduses olevat värskendatud graafikadraiverit"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefoni kõlar"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 68b4840..2687d1d 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s bidez automatikoki konektatuta"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatikoki konektatuta sareen balorazioen hornitzailearen bidez"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s bidez konektatuta"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s bidez erabilgarri"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Konektatuta; ezin da atzitu Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Ez dago Interneteko konexiorik"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Saioa hasi behar da"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Sarbide-puntua beteta dago aldi baterako"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s bidez konektatuta"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s bidez erabilgarri"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Oso motela"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Motela"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Ados"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Babeskopiaren pasahitz berria ezarri da"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Pasahitz berria eta berrespena ez datoz bat"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Ezin izan da babeskopiaren pasahitza ezarri"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Kargatzen…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Bizia (balio lehenetsia)"</item>
     <item msgid="8446070607501413455">"Naturala"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Galdetu beti"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Desaktibatu arte"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Oraintxe"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Hautatu zein aplikaziorekin erabili nahi duzun garatze-prozesuan dagoen grafikoen kontrolatzaile eguneratua"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefonoaren bozgorailua"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 7882b056..ec6200f 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"‏اتصال خودکار ازطریق %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"اتصال خودکار ازطریق ارائه‌دهنده رتبه‌بندی شبکه"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏متصل از طریق %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"‏در دسترس از طریق %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"متصل، بدون اینترنت"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"عدم دسترسی به اینترنت"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ورود به سیستم لازم است"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ظرفیت نقطه دسترسی موقتاً تکمیل شده است"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"‏متصل ازطریق %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"‏در دسترس ازطریق %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"بسیار آهسته"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"آهسته"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"تأیید"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"گذرواژه جدید نسخهٔ پشتیبان تنظیم شد"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"گذرواژه جدید و تأیید آن با یکدیگر مطابقت ندارند"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"گذرواژه پشتیبان‌گیری تنظیم نشد"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"بارگیری…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"پرطروات (پیش‌فرض)"</item>
     <item msgid="8446070607501413455">"طبیعی"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"هربار پرسیده شود"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"تا زمانی‌که آن را خاموش کنید"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"هم‌اکنون"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"برنامه انتخاب‌شده برای استفاده از درایور گرافیک به‌روزرسانی‌شده در برنامه‌نویس"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"بلندگوی تلفن"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 1904c4d..174caef 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automaattinen yhteys muodostettu palvelun %1$s kautta"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Yhdistetty automaattisesti verkon arviointipalvelun kautta"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Yhdistetty seuraavan kautta: %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Käytettävissä seuraavan kautta: %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Yhdistetty, ei internetyhteyttä"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Ei internetyhteyttä"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Sisäänkirjautuminen vaaditaan"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Yhteyspiste tilapäisesti täynnä"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Yhdistetty, verkko: %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Käytettävissä, verkko: %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Hyvin hidas"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Hidas"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Uusi varasalasana asetettiin"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Uusi salasana ja vahvistus eivät täsmää"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Varasalasanan asetus epäonnistui"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Ladataan…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Voimakas (oletus)"</item>
     <item msgid="8446070607501413455">"Luonnollinen"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Kysy aina"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Kunnes poistat sen käytöstä"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Äsken"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Lisää sovellus käyttämään päivitettyä grafiikkaohjainta kehitysvaiheessa"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Puhelimen kaiutin"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 45b2872..f189d77 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatiquement connecté par %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Connecté automatiquement par le fournisseur d\'avis sur le réseau"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté par %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Accessible par %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connecté, aucun accès à Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Aucune connexion Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Connexion requise"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Le point d\'accès est temporairement plein"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Connecté par %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Accessible par %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Très lente"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lente"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Le nouveau mot de passe de secours a bien été défini."</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Le nouveau mot de passe et sa confirmation ne correspondent pas."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Échec de la définition du mot de passe de secours."</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Chargement en cours…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrantes (par défaut)"</item>
     <item msgid="8446070607501413455">"Naturelles"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Toujours demander"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Jusqu\'à la désactivation"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"À l\'instant"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Sélectionnez l\'application pour utiliser le pilote graphique mis à jour en mode de conception"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Haut-parleur du téléphone"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 13361d7..97cc5aa 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Connecté automatiquement via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Connecté automatiquement via un fournisseur d\'évaluation de l\'état du réseau"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté via %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible via %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connecté, aucun accès à Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Aucun accès à Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Connexion requise"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Point d\'accès temporairement plein"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Connecté via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Disponible via %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Très lente"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lente"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Correct"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Le nouveau mot de passe de secours a bien été défini."</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Le nouveau mot de passe et sa confirmation ne correspondent pas."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Échec de la définition du mot de passe de secours."</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Chargement…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Couleurs éclatantes (par défaut)"</item>
     <item msgid="8446070607501413455">"Couleurs naturelles"</item>
@@ -371,10 +446,10 @@
     <string name="power_remaining_duration_only_enhanced" msgid="4189311599812296592">"Temps restant en fonction de votre utilisation : environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_discharging_duration_enhanced" msgid="1992003260664804080">"Temps restant en fonction de votre utilisation (<xliff:g id="LEVEL">%2$s</xliff:g>) : environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
     <string name="power_remaining_duration_only_short" msgid="3463575350656389957">"Temps restant : <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
-    <string name="power_discharge_by_enhanced" msgid="2095821536747992464">"Temps restant estimé en fonction de votre utilisation : <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
-    <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Temps restant estimé en fonction de votre utilisation : <xliff:g id="TIME">%1$s</xliff:g>"</string>
-    <string name="power_discharge_by" msgid="6453537733650125582">"Temps restant estimé : <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
-    <string name="power_discharge_by_only" msgid="107616694963545745">"Temps restant estimé : <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="power_discharge_by_enhanced" msgid="2095821536747992464">"Devrait durer jusqu\'à environ <xliff:g id="TIME">%1$s</xliff:g> en fonction de votre utilisation (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+    <string name="power_discharge_by_only_enhanced" msgid="2175151772952365149">"Devrait durer jusqu\'à environ <xliff:g id="TIME">%1$s</xliff:g> en fonction de votre utilisation"</string>
+    <string name="power_discharge_by" msgid="6453537733650125582">"Devrait durer jusqu\'à environ <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+    <string name="power_discharge_by_only" msgid="107616694963545745">"Devrait durer jusqu\'à environ <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_discharge_by_only_short" msgid="1372817269546888804">"Jusqu\'à <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"Il reste moins de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
     <string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Il reste moins de <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Toujours demander"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Jusqu\'à la désactivation"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"À l\'instant"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Sélectionner une application pour le développement de laquelle utiliser le pilote graphique mis à jour"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Haut-parleur du téléphone"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index e8cf009..fb63a9d 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Conectouse automaticamente a través de %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Conectada automaticamente a través dun provedor de valoración de rede"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Dispoñible a través de %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conexión sen Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Non hai conexión a Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"É obrigatorio iniciar sesión"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"O punto de acceso está temporalmente cheo"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Conectado a través de %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Dispoñible a través de %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Moi lenta"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lenta"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Aceptar"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Novo contrasinal da copia de seguranza definido"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"O contrasinal novo e a confirmación non coinciden"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Erro ao definir un contrasinal da copia de seguranza"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Cargando…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Brillante (predeterminado)"</item>
     <item msgid="8446070607501413455">"Naturais"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Preguntar sempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Ata a desactivación"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Agora mesmo"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Subscribirse á aplicación para utilizar o controlador de gráficos actualizado en desenvolvemento"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altofalante do teléfono"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 918920d..54fa7d1 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s દ્વારા સ્વત: કનેક્ટ થયેલ"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"નેટવર્ક રેટિંગ પ્રદાતા દ્વારા આપમેળે કનેક્ટ થયું"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s દ્વારા કનેક્ટ થયેલ"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s દ્વારા ઉપલબ્ધ"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"કનેક્ટ કર્યું, કોઈ ઇન્ટરનેટ નથી"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ઇન્ટરનેટ ઍક્સેસ નથી"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"સાઇન ઇન આવશ્યક"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ઍક્સેસ પૉઇન્ટ અસ્થાયીરૂપે ભરાયેલ છે"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s દ્વારા કનેક્ટ થયેલ"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s દ્વારા ઉપલબ્ધ"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"ખૂબ જ ધીમી"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"ધીમી"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ઓકે"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"નવો બેકઅપ પાસવર્ડ સેટ કર્યો છે"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"નવો પાસવર્ડ અને પુષ્ટિકરણ મેળ ખાતા નથી"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"નિષ્ફળતા સેટિંગ બેકઅપ પાસવર્ડ"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"લોડ થઈ રહ્યું છે…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"વાઇબ્રન્ટ (ડિફોલ્ટ)"</item>
     <item msgid="8446070607501413455">"કુદરતી"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"દર વખતે પૂછો"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"તમે બંધ ન કરો ત્યાં સુધી"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"હમણાં જ"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"અપડેટ કરેલ ગ્રાફિક્સ ડ્રાઇવરનો ઉપયોગ કરવા માટે અ‍ૅપ પસંદ કરો"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ફોન સ્પીકર"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 890d036..0aba3f6 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s के ज़रिए ऑटोमैटिक रूप से कनेक्ट है"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"नेटवर्क रेटिंग प्रदाता के ज़रिए अपने आप कनेक्ट है"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s के द्वारा उपलब्ध"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s के द्वारा उपलब्ध"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"कनेक्ट हो गया है, लेकिन इंटरनेट नहीं है"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"इंटरनेट कनेक्शन नहीं है"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"साइन इन करना ज़रूरी है"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"एक्सेस प्वाइंट फ़िलहाल भरा हुआ है"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s के ज़रिए कनेक्ट"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s के ज़रिए उपलब्ध"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"अत्‍यधिक धीमी"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"धीमी"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ठीक है"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"नया बैकअप पासवर्ड सेट किया गया"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"नया पासवर्ड तथा पुष्टि मेल नही खाते"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"सुरक्षित पासवर्ड सेट करने में विफल रहा"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"लोड हो रहा है…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"चमकीला (डिफ़ॉल्ट)"</item>
     <item msgid="8446070607501413455">"स्वाभाविक"</item>
@@ -416,7 +491,7 @@
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"कस्टम (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"मेन्यू"</string>
     <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोड में फ़ैक्टरी रीसेट के लिए पासवर्ड डालें"</string>
-    <string name="retail_demo_reset_next" msgid="8356731459226304963">"आगे"</string>
+    <string name="retail_demo_reset_next" msgid="8356731459226304963">"आगे बढ़ें"</string>
     <string name="retail_demo_reset_title" msgid="696589204029930100">"पासवर्ड आवश्यक"</string>
     <string name="active_input_method_subtypes" msgid="3596398805424733238">"टाइप करने की सक्रीय पद्धतियां"</string>
     <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"सिस्टम की भाषाओं का उपयोग करें"</string>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"हर बार पूछें"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"जब तक आप इसे बंद नहीं करते"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"अभी-अभी"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"डेवलपमेंट में अपडेट किए गए ग्राफ़िक्स ड्राइवर का इस्तेमाल करने के लिए ऐप्लिकेशन में ऑप्ट इन करें"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"फ़ोन स्पीकर"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 1464b91..5a48ffd 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatski povezan putem %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatski povezan putem ocjenjivača mreže"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Povezano putem %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Dostupno putem %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Povezano, bez interneta"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nema interneta"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Obavezna prijava"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Pristupna je točka privremeno puna"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Povezano putem mreže %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Dostupno putem mreže %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Vrlo sporo"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Sporo"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"U redu"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova zaporka za sigurnosnu kopiju postavljena"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova zaporka i potvrda ne odgovaraju"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nije uspjelo postavljanje zaporke za sigurnosnu kopiju"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Učitavanje…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Živopisno (zadano)"</item>
     <item msgid="8446070607501413455">"Prirodno"</item>
@@ -450,6 +525,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pitaj svaki put"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Upravo sad"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Uključi aplikaciju za upotrebu ažuriranog upravljačkog programa u razvoju"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvučnik telefona"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index c9fdd45..1fa7f6a 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatikusan csatlakozott a következőn keresztül: %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatikusan csatlakozott a hálózatértékelés szolgáltatóján keresztül"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Csatlakozva a következőn keresztül: %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Elérhető a következőn keresztül: %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Csatlakozva, nincs internet-hozzáférés"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nincs internetkapcsolat"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Bejelentkezést igényel"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"A hozzáférési pont átmenetileg megtelt"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Csatlakozva a következőn keresztül: %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Elérhető a következőn keresztül: %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Nagyon lassú"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lassú"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Rendben"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Új mentési jelszó beállítva"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Az új jelszó és a megerősítése nem egyezik."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Hiba a mentési jelszó beállítása során"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Betöltés…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Élénk (alapértelmezett)"</item>
     <item msgid="8446070607501413455">"Természetes"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Mindig kérdezzen rá"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Kikapcsolásig"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Az imént"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"A frissített, fejlesztés alatt álló grafikus drivert használja a választott alkalmazás"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon hangszórója"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 3b13ed1..02a24fe 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Ավտոմատ կերպով կապակցվել է %1$s-ի միջոցով"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Ավտոմատ կերպով միացել է ցանցի վարկանիշի ծառայության մատակարարի միջոցով"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Կապակցված է %1$s-ի միջոցով"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Հասանելի է %1$s-ի միջոցով"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Միացված է, սակայն ինտերնետ կապ չկա"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Ինտերնետ կապ չկա"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Անհրաժեշտ է մուտք գործել"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Հասանելիության կետը ժամանակավորապես լիքն է"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Միացված է %1$s-ի միջոցով"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Հասանելի է %1$s-ի միջոցով"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Շատ դանդաղ"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Դանդաղ"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Հաստատել"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Պահուստավորման նոր գաղտնաբառը սահմանված է"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Նոր գաղտնաբառը և հաստատումը չեն համընկնում"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Ձախողում գաղտնաբառի պահուստավորման կարգավորման ընթացքում"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Բեռնում…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Պայծառ (կանխադրված)"</item>
     <item msgid="8446070607501413455">"Բնական"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Հարցնել ամեն անգամ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Մինչև չանջատեք"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Հենց նոր"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ընտրված հավելվածը, որը պետք է օգտագործի թարմացված գրաֆիկական սարքավարը մշակման ժամանակ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Հեռախոսի բարձրախոս"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 4d1b2df..6b901ff 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Tersambung otomatis melalui %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Otomatis tersambung melalui penyedia rating jaringan"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Terhubung melalui %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Tersedia melalui %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Tersambung, tidak ada internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Tidak ada internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Perlu login"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Titik akses penuh untuk sementara"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Tersambung melalui %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Tersedia melalui %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Sangat Lambat"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lambat"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Oke"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Sandi cadangan baru telah disetel"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Sandi baru dan konfirmasinya tidak cocok."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Gagal menyetel sandi cadangan"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Memuat…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Terang (default)"</item>
     <item msgid="8446070607501413455">"Alami"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Selalu tanya"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Sampai Anda menonaktifkannya"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Baru saja"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ikut sertakan aplikasi untuk menggunakan driver grafis yang diupdate dalam pengembangan"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Speaker ponsel"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 600ffa4..ae31d6b 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Sjálfkrafa tengt um %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Sjálfkrafa tengt um netgæðaveitu"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Tengt í gegnum %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Í boði í gegnum %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Tengt, enginn netaðgangur"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Engin nettenging"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Innskráningar krafist"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Aðgangsstaður tímabundið fullur"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Tengt í gegnum %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Í boði í gegnum %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Mjög hægt"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Hægt"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Í lagi"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nýtt aðgangsorð fyrir afritun valið"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nýja aðgangsorðið og staðfestingaraðgangsorðið eru ekki eins"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Villa við að velja aðgangsorð fyrir afritun"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Hleður…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Líflegir (sjálfgefið)"</item>
     <item msgid="8446070607501413455">"Náttúrulegir"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Spyrja í hvert skipti"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Þar til þú slekkur"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Rétt í þessu"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Velja að nota uppfærðan myndefnisrekil í þróun í forriti"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Símahátalari"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 068aa91..44acbcb 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Collegato automaticamente tramite %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Collegato automaticamente tramite fornitore di servizi di valutazione rete"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Collegato tramite %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponibile tramite %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connesso, senza Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nessuna connessione a Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Accesso richiesto"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Punto di accesso momentaneamente al completo"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Connesso tramite %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Disponibile tramite %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Molto lenta"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lenta"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nuova password di backup impostata"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Le password inserite non corrispondono"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Impossibile impostare la password di backup"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Caricamento…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vivaci (opzione predefinita)"</item>
     <item msgid="8446070607501413455">"Naturali"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Chiedi ogni volta"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Fino alla disattivazione"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Adesso"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Attiva l\'app per utilizzare il driver grafico aggiornato nella versione di sviluppo"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altoparlante telefono"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index fa38f77..5ae1321 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"‏מחובר אוטומטית דרך %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"מחובר אוטומטית דרך ספק של דירוג רשת"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏מחובר דרך %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"‏זמינה דרך %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"מחובר. אין אינטרנט"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"אין אינטרנט"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"נדרשת כניסה"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"נקודת הגישה מלאה באופן זמני"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"‏מחובר לרשת של %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"‏זמינה דרך %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"איטית מאוד"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"איטית"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"אישור"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"הוגדרה סיסמת גיבוי חדשה"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"הסיסמה החדשה והאישור אינם תואמים"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"הגדרת סיסמת גיבוי נכשלה"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"טוען…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"דינמי (ברירת מחדל)"</item>
     <item msgid="8446070607501413455">"טבעי"</item>
@@ -451,6 +526,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"שאל בכל פעם"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"עד הכיבוי"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"הרגע"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"האפליקציה שנבחרה לשימוש במנהל ההתקן המעודכן לגרפיקה שבפיתוח"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"רמקול של טלפון"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 9927654..25308cf 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s 経由で自動的に接続しています"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ネットワーク評価プロバイダ経由で自動的に接続しています"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s経由で接続"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s経由で使用可能"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"接続済み、インターネット接続なし"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"インターネット未接続"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ログインが必要"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"アクセス ポイントが一時的にいっぱいです"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s 経由で接続済み"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s 経由で使用可能"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"とても遅い"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"遅い"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"新しいバックアップパスワードが設定されました"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"新しいパスワードと確認用のパスワードが一致しません。"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"バックアップパスワードの設定に失敗しました"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"読み込んでいます…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"鮮やか(既定)"</item>
     <item msgid="8446070607501413455">"自然"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"毎回確認"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"OFF にするまで"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"たった今"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"更新したグラフィックス ドライバを開発に使用するオプトイン アプリ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"スマートフォンのスピーカー"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 7ba0153..b38dcc6 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"ავტომატურად დაკავშირდა %1$s-ის მეშვეობით"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ავტომატურად დაკავშირდა ქსელის ხარისხის შეფასების პროვაიდერის მეშვეობით"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-ით დაკავშირებული"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"ხელმისაწვდომია %1$s-ით"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"დაკავშირებულია, ინტერნეტის გარეშე"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ინტერნეტ-კავშირი არ არის"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"აუცილებელია სისტემაში შესვლა"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"წვდომის წერტილი დროებით გადატვირთულია"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s-ით დაკავშირებული"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"ხელმისაწვდომია %1$s-ით"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"ძალიან ნელი"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"ნელი"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"კარგი"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"ახალი სარეზერვო პაროლის დაყენება"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ახალი და დადასტურებული პაროლები არ შეესატყვისება ერთმანეთს"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"სარეზერვო პაროლის დაყენება ვერ მოხერხდა"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"მიმდინარეობს ჩატვირთვა…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"მკვეთრი (ნაგულისხმევი)"</item>
     <item msgid="8446070607501413455">"ბუნებრივი"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ყოველთვის მკითხეთ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"გამორთვამდე"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ახლახან"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"გააქტიურების აპი, რომელიც გამოიყენებს შემუშავების პროცესში მყოფ, განახლებულ გრაფიკულ დრაივერს"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ტელეფონის დინამიკი"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index d5b4441..54087a0 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s арқылы автоматты қосылды"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Желі рейтингі провайдері арқылы автоматты түрде қосылған"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s арқылы қосылған"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s арқылы қолжетімді"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Қосылған, интернет жоқ"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Интернетпен байланыс жоқ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Есептік жазбаға кіру керек"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Кіру нүктесі уақытша бос емес"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s арқылы қосылды"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s арқылы қолжетімді"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Өте баяу"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Баяу"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Жарайды"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Жаңа сақтық кілтсөзі тағайындалды"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Жаңа кілтсөз және растау сәйкес емес"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Сақтық кілтсөзі тағайындалмады"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Жүктелуде…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Жарқын (әдепкі)"</item>
     <item msgid="8446070607501413455">"Табиғи"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Әрдайым сұрау"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Өшірілгенге дейін"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Дәл қазір"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Әзірлеу барысында қолданба жаңартылған графика драйверін пайдаланады"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Телефон динамигі"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index d1d1c76..3fc609f 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"បានភ្ជាប់ដោយស្វ័យប្រវត្តិតាមរយៈ %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"បានភ្ជាប់​ដោយស្វ័យប្រវត្តិ​តាម​រយៈក្រុមហ៊ុនផ្តល់​ការ​វាយ​តម្លៃលើ​បណ្តាញ"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"បានភ្ជាប់តាមរយៈ %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"មានតាមរយៈ %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"បាន​ភ្ជាប់ ប៉ុន្តែ​គ្មាន​អ៊ីនធឺណិត​ទេ"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"គ្មាន​អ៊ីនធឺណិតទេ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"តម្រូវ​ឱ្យ​ចូល​គណនី"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ចំណុចចូលប្រើពេញជាបណ្តោះអាសន្ន"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"បានភ្ជាប់តាមរយៈ %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"មានតាមរយៈ %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"យឺតណាស់"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"យឺត"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"យល់ព្រម"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"កំណត់​ពាក្យ​សម្ងាត់​បម្រុង​ទុក​ថ្មី"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ពាក្យ​សម្ងាត់​ថ្មី និង​ការ​បញ្ជាក់​​មិន​ដូច​គ្នា"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"បរាជ័យ​ក្នុង​ការ​កំណត់​ពាក្យ​សម្ងាត់​បម្រុងទុក"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"កំពុងផ្ទុក…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"រស់រវើក (លំនាំដើម)"</item>
     <item msgid="8446070607501413455">"ធម្មជាតិ"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"សួរគ្រប់ពេល"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"រហូតទាល់តែ​អ្នកបិទ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"អម្បាញ់មិញ"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ភ្ជាប់កម្មវិធី​ ដើម្បី​ប្រើដ្រាយវើ​ក្រាហ្វិក​ដែលបាន​ដំឡើងជំនាន់​សម្រាប់​ការ​អភិវឌ្ឍ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ឧបករណ៍​បំពង​សំឡេង​ទូរសព្ទ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 46759f5..bc1150d 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s ಮೂಲಕ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ನೆಟ್‌ವರ್ಕ್ ರೇಟಿಂಗ್ ಒದಗಿಸುವವರ ಮೂಲಕ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ಮೂಲಕ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ಮೂಲಕ ಲಭ್ಯವಿದೆ"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ, ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ಸೈನ್ ಇನ್ ಮಾಡುವ ಅಗತ್ಯವಿದೆ"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ಪ್ರವೇಶ ಕೇಂದ್ರ ತಾತ್ಕಾಲಿಕವಾಗಿ ಭರ್ತಿಯಾಗಿದೆ"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ಮೂಲಕ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s ಮೂಲಕ ಲಭ್ಯವಿದೆ"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"ತುಂಬಾ ನಿಧಾನವಾಗಿದೆ"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"ನಿಧಾನ"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ಸರಿ"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"ಹೊಸ ಬ್ಯಾಕಪ್ ಪಾಸ್‌ವರ್ಡ್‌ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ಹೊಸ ಪಾಸ್‌ವರ್ಡ್‌ ಮತ್ತು ದೃಢೀಕರಣ ಹೊಂದಾಣಿಕೆಯಾಗುತ್ತಿಲ್ಲ"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ಬ್ಯಾಕಪ್‌ ಪಾಸ್‌ವರ್ಡ್‌ ಹೊಂದಿಕೆ ವಿಫಲಗೊಂಡಿದೆ"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ಲೋಡ್ ಆಗುತ್ತಿದೆ…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"ಸ್ಪಂದನಾತ್ಮಕ (ಡೀಫಾಲ್ಟ್)"</item>
     <item msgid="8446070607501413455">"ಪ್ರಾಕೃತಿಕ"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ಪ್ರತಿ ಬಾರಿ ಕೇಳಿ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"ನೀವು ಆಫ್ ಮಾಡುವವರೆಗೆ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ಇದೀಗ"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ಅಭಿವೃದ್ಧಿಯಲ್ಲಿ ಅಪ್‌ಡೇಟ್ ಮಾಡಲಾದ ಗ್ರಾಫಿಕ್‌ಗಳ ಡ್ರೈವರ್ ಬಳಸಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ಫೋನ್ ಸ್ಪೀಕರ್"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 067175b..035c24b 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s을(를) 통해 자동으로 연결됨"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"네트워크 평가 제공업체를 통해 자동으로 연결됨"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s을(를) 통해 연결됨"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s을(를) 통해 사용 가능"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"연결됨, 인터넷 사용 불가"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"인터넷 연결 없음"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"로그인 필요"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"액세스 포인트가 일시적으로 가득 참"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s을(를) 통해 연결됨"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s을(를) 통해 사용 가능"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"매우 느림"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"느림"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"보통"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"새 백업 비밀번호가 설정되었습니다."</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"새 비밀번호와 확인한 비밀번호가 일치하지 않습니다."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"백업 비밀번호를 설정하지 못했습니다."</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"로드 중…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"생동감(기본값)"</item>
     <item msgid="8446070607501413455">"내츄럴"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"항상 확인"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"사용 중지할 때까지"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"조금 전"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"개발 중인 업데이트된 그래픽 드라이버를 사용할 앱을 선택하세요."</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"휴대전화 스피커"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 8e994da..8a68c78 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s аркылуу автоматтык түрдө туташты"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Тармактар рейтингинин автору аркылуу автоматтык түрдө туташты"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s аркылуу жеткиликтүү"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s аркылуу жеткиликтүү"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Туташып турат, Интернет жок"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Интернет жок"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Аккаунтка кирүү талап кылынат"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Байланыш түйүнүнө өтө көп түзмөк туташып турат"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s аркылуу туташты"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s аркылуу иштейт"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Өтө жай"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Жай"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Жарайт"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Жаңы бэкапка сырсөз коюулду"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Жаңы сырсөз жана анын ырастоосу дал келген жок"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Жаңы бэкапка сырсөз коюлган жок"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Жүктөлүүдө…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Толкундуу (демейки)"</item>
     <item msgid="8446070607501413455">"Табигый"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Ар дайым суралсын"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Бул функция өчүрүлгөнгө чейин"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Азыр эле"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Иштеп чыгууда жаңыртылган графикалык драйверлерди пайдалануу үчүн колдонмону кошуңуз"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Телефондун динамиги"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 7bf46c0..009f44f 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"ເຊື່ອມຕໍ່ຜ່ານທາງ %1$s ໂດຍອັດຕະໂນມັດ"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ເຊື່ອມຕໍ່ກັບອັດຕະໂນມັດແລ້ວຜ່ານຜູ້ໃຫ້ບໍລິການຄະແນນເຄືອຂ່າຍ"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"​ເຊື່ອມຕໍ່​ຜ່ານ %1$s ​ແລ້ວ"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"ມີ​ໃຫ້​ຜ່ານ %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ເຊື່ອມຕໍ່ແລ້ວ, ບໍ່ມີອິນເຕີເນັດ"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ບໍ່ມີອິນເຕີເນັດ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ຈຳເປັນຕ້ອງເຂົ້າສູ່ລະບົບ"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ຈຸດການເຂົ້າເຖິງເຕັມຊົ່ວຄາວ"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"ເຊື່ອມຕໍ່ຜ່ານ %1$s ແລ້ວ"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"ໃຊ້ໄດ້ຜ່ານ %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"ຊ້າຫຼາຍ"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"ຊ້າ"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ຕົກລົງ"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"ຕັ້ງລະຫັດສຳຮອງໃໝ່ແລ້ວ"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ລະຫັດຜ່ານໃໝ່ ແລະລະຫັດຢືນຢັນບໍ່ກົງກັນ"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ການຕັ້ງລະຫັດສຳຮອງຂໍ້ມູນລົ້ມເຫລວ"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ກຳລັງໂຫລດ…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"ຕົວ​ສັ່ນ (ມາດ​ຕະ​ຖານ)"</item>
     <item msgid="8446070607501413455">"ທຳ​ມະ​ຊາດ"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ຖາມທຸກເທື່ອ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"ຈົນກວ່າທ່ານຈະປິດ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ຕອນນີ້"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ເຂົ້າຮ່ວມແອັບເພື່ອໃຊ້ໄດຣເວີກຣາຟິກທີ່ອັບເດດແລ້ວໃນການພັດທະນາ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ລຳໂພງໂທລະສັບ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 9da3d52..f08a78b 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatiškai prisijungta naudojant „%1$s“"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatiškai prisijungta naudojant tinklo įvertinimo paslaugos teikėjo paslaugomis"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Prisijungta naudojant „%1$s“"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Pasiekiama naudojant „%1$s“"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Prisijungta, nėra interneto"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nėra interneto ryšio"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Reikia prisijungti"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Prieigos taškas laikinai visiškai užimtas"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Prisijungta naudojant „%1$s“"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Pasiekiama naudojant „%1$s“"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Labai lėtas"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lėtas"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Gerai"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nustatytas naujas atsarginės kopijos slaptažodis"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Naujas slaptažodis ir patvirtinimas neatitinka"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nustatant atsarginės kopijos slaptažodį įvyko klaida"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Įkeliama…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Ryškus (numatytasis)"</item>
     <item msgid="8446070607501413455">"Natūralus"</item>
@@ -451,6 +526,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Klausti kaskart"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Kol išjungsite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Ką tik"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Pasirinkti programą, kuri bus naudojama su atnaujinta kuriama grafikos tvarkykle"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefono garsiakalbis"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 2233468..c768d11 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automātiski savienots, izmantojot %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automātiski izveidots savienojums, izmantojot tīkla vērtējuma sniedzēju"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Savienots, izmantojot %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Pieejams, izmantojot %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Savienojums izveidots, nav piekļuves internetam"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nav piekļuves internetam"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Nepieciešama pierakstīšanās"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Piekļuves punkts īslaicīgi ir pilns"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Savienojums izveidots, izmantojot %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Pieejams, izmantojot %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Ļoti lēns"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lēns"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Labi"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Jaunā dublējuma parole ir iestatīta."</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Jaunā parole un apstiprinājums neatbilst."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Iestatot dublējuma paroli, radās kļūme."</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Notiek ielāde…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Spilgts (noklusējums)"</item>
     <item msgid="8446070607501413455">"Dabisks"</item>
@@ -450,6 +525,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vaicāt katru reizi"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Līdz brīdim, kad izslēgsiet"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Tikko"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Izvēlēties izmantot atjaunināto grafikas dzini šīs lietotnes izstrādē"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Tālruņa skaļrunis"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 534d154..85430a6 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Автоматски поврзано преку %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Автоматски поврзано преку оператор за оценување мрежа"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Поврзано преку %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Достапно преку %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Поврзана, нема интернет"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Нема интернет"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Потребно е најавување"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Пристапната точка привремено е преоптоварена"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Поврзано преку %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Достапно преку %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Многу бавна"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Бавна"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Во ред"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Подесена нова лозинка на резервна копија"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Новата лозинка и потврдата не се исти"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Неуспешно подесување лозинка на резервна копија"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Се вчитува…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Динамично (стандардно)"</item>
     <item msgid="8446070607501413455">"Природно"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Секогаш прашувај"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Додека не го исклучите"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Неодамнешни"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Прифатете ја апликацијата за да се користи ажурираниот драјвер за графика во програмирање"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Телефонски звучник"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 7a335cd..c3438dc 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s വഴി സ്വയമേവ ബന്ധിപ്പിച്ചു"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"നെറ്റ്‌വർക്ക് റേറ്റിംഗ് ദാതാവുമായി സ്വയം കണക്‌റ്റുചെയ്‌തു"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s വഴി ബന്ധിപ്പിച്ചു"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s വഴി ലഭ്യം"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"കണക്റ്റ് ചെയ്‌തു, ഇന്റർനെറ്റ് ഇല്ല"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ഇന്റർനെറ്റ് ഇല്ല"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"സൈൻ ഇൻ ചെയ്യേണ്ടത് ആവശ്യമാണ്"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ആക്‌സസ് പോയിന്റ് താൽക്കാലികമായി നിറഞ്ഞിരിക്കുന്നു"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s വഴി ബന്ധിപ്പിച്ചു"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s വഴി ലഭ്യം"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"വളരെ കുറഞ്ഞ വേഗത്തിൽ"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"കുറഞ്ഞ വേഗത്തിൽ"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ശരി"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"പുതിയ ബാക്കപ്പ് പാസ്‌വേഡ് സജ്ജമാക്കി"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"പുതിയ പാസ്‌വേഡും സ്ഥിരീകരണവും പൊരുത്തപ്പെടുന്നില്ല"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ബാക്കപ്പ് പാസ്‌വേഡ് സജ്ജമാക്കുന്നതിൽ പരാജയപ്പെട്ടു"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ലോഡ് ചെയ്യുന്നു…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"വൈബ്രന്റ് (സ്ഥിരമായത്)"</item>
     <item msgid="8446070607501413455">"സ്വാഭാവികം"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"എപ്പോഴും ചോദിക്കുക"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"നിങ്ങൾ ഓഫാക്കുന്നത് വരെ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ഇപ്പോൾ"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"വികസനത്തിൽ, അപ്ഡേറ്റ് ചെയ്‌ത ഗ്രാഫിക്‌സ് ഡ്രൈവർ ഉപയോഗിക്കാൻ ഓപ്റ്റ് ഇൻ ചെയ്യുക"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ഫോൺ സ്‌പീക്കർ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 4816643..7c8aa8b 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s-р автоматаар холбогдсон"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Сүлжээний үнэлгээ үзүүлэгчээр автоматаар холбогдох"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-р холбогдсон"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s-р боломжтой"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Холбогдсон хэдий ч интернет алга"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Интернэт алга"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Нэвтрэх шаардлагатай"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Хандах цэг түр хугацаанд дүүрсэн байна"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s-р холбогдсон"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s-р боломжтой"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Маш удаан"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Удаан"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ЗА"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Нөөцлөлтийн шинэ нууц үг тохирууллаа"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Шинэ нууц үг болон баталгаажуулалт таарахгүй байна"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Нөөшлөлтийн нууц үгийг тохируулахад алдаа гарлаа"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Ачаалж байна…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Хурц (үндсэн)"</item>
     <item msgid="8446070607501413455">"Байгалийн"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Тухай бүрт асуух"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Таныг унтраах хүртэл"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Дөнгөж сая"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Хөгжүүлэлтэд буй шинэчилсэн график драйверийг ашиглахын тулд аппад нэгдэх"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Утасны чанга яригч"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 5b09b29..3ab2a4b 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s द्वारे स्वयंचलितपणे कनेक्ट केले"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"नेटवर्क रेटिंग प्रदात्याद्वारे स्वयंचलितपणे कनेक्ट केले"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s द्वारे कनेक्‍ट केले"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s द्वारे उपलब्‍ध"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"कनेक्‍ट केले, इंटरनेट नाही"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"इंटरनेट नाही"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"साइन इन करणे आवश्यक आहे"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"अॅक्सेस पॉइंट तात्पुरते भरलेले"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ने कनेक्‍ट केले"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s ने उपलब्‍ध"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"खूप हळू"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"हळू"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ठीक आहे"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"नवीन बॅक अप पासवर्ड सेट झाला"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"नवीन पासवर्ड आणि पुष्टीकरण जुळत नाही"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"बॅक अप पासवर्ड सेट करणे अयशस्वी"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"लोड करत आहे…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"सशक्त (डीफॉल्ट)"</item>
     <item msgid="8446070607501413455">"नैसर्गिक"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"प्रत्येक वेळी विचारा"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"तुम्ही बंद करेपर्यंत"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"आत्ताच"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"अपडेट केलेले ग्राफिक ड्राइव्हर डेव्हलमेंटमध्ये वापरण्यासाठी अ‍ॅप निवडा"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"फोनचा स्पीकर"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 3593882..5459b80 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Disambungkan secara automatik melalui %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Disambungkan secara automatik melalui pembekal penilaian rangkaian"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Disambungkan melalui %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Tersedia melalui %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Disambungkan, tiada Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Tiada Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Log masuk diperlukan"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Titik akses penuh buat sementara waktu"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Disambungkan melalui %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Tersedia melalui %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Sangat Perlahan"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Perlahan"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Kata laluan sandaran baharu telah ditetapkan"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Kata laluan baharu dan pengesahan tidak sepadan"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Gagal menetapkan kata laluan sandaran"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Memuatkan…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Terang (lalai)"</item>
     <item msgid="8446070607501413455">"Semula Jadi"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Tanya setiap kali"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Sehingga anda matikan"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Sebentar tadi"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Sertakan apl untuk menggunakan pemacu grafik yang dikemas kini dalam pembangunan"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Pembesar suara telefon"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 7ac3742..254de2a 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s မှတစ်ဆင့် အလိုအလျောက် ချိတ်ဆက်ထားပါသည်"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ကွန်ရက်အဆင့်သတ်မှတ်ပေးသူ မှတစ်ဆင့် အလိုအလျောက် ချိတ်ဆက်ထားပါသည်"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s မှတစ်ဆင့်ရနိုင်သည်"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ချိတ်ဆက်ထားသည်၊ အင်တာနက်မရှိ"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"အင်တာနက် မရှိပါ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"လက်မှတ်ထိုးဝင်ရန် လိုအပ်သည်"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ကွန်ရက်ချိတ်ဆက်မှု ယာယီပြည့်နေသည်"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s မှတစ်ဆင့် ရနိုင်သည်"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"အလွန်နှေး"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"နှေး"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"အရန်သိမ်းဆည်းခြင်းအတွက် စကားဝှက်အသစ်ကို သတ်မှတ်ပြီးပြီ။"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"စကားဝှက်အသစ်နှင့် အတည်ပြုချက် ကွဲလွဲနေသည်။"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"အရန်သိမ်းဆည်းခြင်းအတွက် စကားဝှက်သတ်မှတ်ချက် မအောင်မြင်ပါ။"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ဖွင့်နေသည်…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"တက်ကြွခြင်း (မူလ)"</item>
     <item msgid="8446070607501413455">"သဘာဝ"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"အမြဲမေးပါ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"သင်ပိတ်လိုက်သည် အထိ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ယခုလေးတင်"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ဆော့ဖ်ဝဲရေးဆွဲမှုအတွင်း အပ်ဒိတ်လုပ်ထားသော ဂရပ်ဖစ်ဒရိုင်ဗာကို အသုံးပြုရန် အက်ပ်ကို ရွေးချယ်ပါ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ဖုန်းစပီကာ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index e810ba2..5d5568f 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatisk tilkoblet via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatisk tilkoblet via leverandør av nettverksvurdering"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Tilkoblet via %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Tilgjengelig via %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Tilkoblet – ingen Internett-tilgang"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Ingen internettilkobling"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Pålogging kreves"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Tilgangspunktet er midlertidig fullt"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Tilkoblet via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Tilgjengelig via %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Veldig treg"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Treg"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Ok"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nytt passord for sikkerhetskopiering er angitt."</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Gjentakelsen av passordet er ikke identisk med det første du skrev inn"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Kunne ikke angi nytt passord for sikkerhetskopiering"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Laster inn …"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Krystallklar (standard)"</item>
     <item msgid="8446070607501413455">"Naturlig"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Spør hver gang"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Til du slår av"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Nå nettopp"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Velg app for å bruke en oppdatert grafikkdriver som er under utvikling"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefonhøyttaler"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 0b4510fd..f63e9d7 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s मार्फत् स्वतः जडान गरिएको"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"नेटवर्कको दर्जा प्रदायक मार्फत स्वत: जडान गरिएको"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s मार्फत जडित"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s मार्फत उपलब्ध"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"जडान गरियो तर इन्टरनेट छैन"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"इन्टरनेटमाथिको पहुँच छैन"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"साइन इन गर्न आवश्यक छ"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"पहुँचसम्बन्धी स्थान अस्थायी रूपमा भरिएको छ"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s मार्फत जडान गरियो"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s मार्फत उपलब्ध"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"धेरै ढिलो"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"बिस्तारै"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ठिक छ"</string>
@@ -231,7 +305,7 @@
     <string name="private_dns_mode_off" msgid="8236575187318721684">"निष्क्रिय छ"</string>
     <string name="private_dns_mode_opportunistic" msgid="8314986739896927399">"स्वचालित"</string>
     <string name="private_dns_mode_provider" msgid="8354935160639360804">"निजी DNS प्रदायकको होस्टनाम"</string>
-    <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS प्रदायकको होस्टनाम प्रविष्ट गर्नुहोस्"</string>
+    <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS प्रदायकको होस्टनाम प्रविष्टि गर्नुहोस्"</string>
     <string name="private_dns_mode_provider_failure" msgid="231837290365031223">"जडान गर्न सकिएन"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ताररहित प्रदर्शन प्रमाणीकरणका लागि विकल्पहरू देखाउनुहोस्"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi लग स्तर बढाउनुहोस्, Wi-Fi चयनकर्तामा प्रति SSID RSSI देखाइन्छ"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"नयाँ जगेडा पासवर्ड सेट गर्नुहोस्"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"नयाँ पासवर्ड र पुष्टिकरण मेल खाँदैनन्"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"विफलता सेटिङ ब्याकअप पासवर्ड"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"लोड गर्दै…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"जोसिलो (पूर्व निर्धारित)"</item>
     <item msgid="8446070607501413455">"प्राकृतिक"</item>
@@ -415,7 +490,7 @@
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"सबैभन्दा ठूलो"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"आफू अनुकूल (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"मेनु"</string>
-    <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमा फ्याक्ट्री रिसेट गर्न पासवर्ड प्रविष्ट गर्नुहोस्"</string>
+    <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमा फ्याक्ट्री रिसेट गर्न पासवर्ड प्रविष्टि गर्नुहोस्"</string>
     <string name="retail_demo_reset_next" msgid="8356731459226304963">"अर्को"</string>
     <string name="retail_demo_reset_title" msgid="696589204029930100">"पासवर्ड आवश्यक छ"</string>
     <string name="active_input_method_subtypes" msgid="3596398805424733238">"आगत विधिहरू सक्रिय गर्नुहोस्"</string>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"प्रत्येक पटक सोध्नुहोस्"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"तपाईंले निष्क्रिय नपार्दासम्म"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"अहिले भर्खरै"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"विकासको क्रममा अद्यावधिक गरिएको ग्राफिक ड्राइभर प्रयोग गर्न अप्ट इन गर्नुहोस्"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"फोनको स्पिकर"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index f227e1c..798dc7c 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatisch verbonden via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatisch verbonden via provider van netwerkbeoordelingen"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Verbonden via %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Beschikbaar via %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Verbonden, geen internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Geen internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Inloggen vereist"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Toegangspunt tijdelijk vol"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Verbonden via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Beschikbaar via %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Zeer langzaam"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Langzaam"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Redelijk"</string>
@@ -144,7 +218,7 @@
     <string name="tts_settings_title" msgid="1237820681016639683">"Spraakuitvoer"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Spreeksnelheid"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Snelheid waarmee de tekst wordt gesproken"</string>
-    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Hoogte"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Toonhoogte"</string>
     <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Is van invloed op de toon van de synthetisch gegenereerde spraak"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Taal"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Systeemtaal gebruiken"</string>
@@ -236,7 +310,7 @@
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Opties weergeven voor certificering van draadloze weergave"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string>
     <string name="wifi_connected_mac_randomization_summary" msgid="1743059848752201485">"Een willekeurig MAC-adres bij het maken van verbinding met wifi-netwerken"</string>
-    <string name="wifi_metered_label" msgid="4514924227256839725">"Betaald"</string>
+    <string name="wifi_metered_label" msgid="4514924227256839725">"Met datalimiet"</string>
     <string name="wifi_unmetered_label" msgid="6124098729457992931">"Gratis"</string>
     <string name="select_logd_size_title" msgid="7433137108348553508">"Logger-buffergrootten"</string>
     <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Kies Logger-grootten per logbuffer"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nieuw back-upwachtwoord ingesteld"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nieuw wachtwoord en bevestiging komen niet overeen."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Instellen van back-upwachtwoord is mislukt"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Laden…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Levendig (standaard)"</item>
     <item msgid="8446070607501413455">"Natuurlijk"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Altijd vragen"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Totdat je uitschakelt"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Zojuist"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Meld een app aan om het geüpdatete grafische stuurprogramma in ontwikkeling te gebruiken"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefoonluidspreker"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index bf8493a..9491af3 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s ମାଧ୍ୟମରେ ଅଟୋମେଟିକାଲୀ ସଂଯୁକ୍ତ"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ନେଟୱର୍କ ମୂଲ୍ୟାୟନ ପ୍ରଦାତାଙ୍କ ମାଧ୍ୟମରେ ଅଟୋମେଟିକାଲ୍ୟ ସଂଯୁକ୍ତ"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ମାଧ୍ୟମରେ ସଂଯୁକ୍ତ"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ମାଧ୍ୟମରେ ଉପଲବ୍ଧ"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ସଂଯୁକ୍ତ, ଇଣ୍ଟର୍‌ନେଟ୍‌ ନାହିଁ"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"କୌଣସି ଇଣ୍ଟରନେଟ୍‌ ନାହିଁ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ସାଇନ୍-ଇନ୍ ଆବଶ୍ୟକ"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ଆକ୍ସେସ୍ ପଏଣ୍ଟ ସାମୟିକ ଭାବେ ପୂର୍ଣ୍ଣ"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ମାଧ୍ୟମରେ ସଂଯୁକ୍ତ"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s ମାଧ୍ୟମରେ ଉପଲବ୍ଧ"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"ବହୁତ ମନ୍ଥର"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"କମ୍‌ ବେଗ"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ଠିକ୍‌ ଅଛି"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"ନୂଆ ବ୍ୟାକ୍‌ଅପ୍‌ ପାସ୍‌ୱର୍ଡ ସେଟ୍‌ କରିଦିଆଗଲା"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ନୂଆ ପାସ୍‌ୱର୍ଡ ଓ ସୁନିଶ୍ଚିତତା ମେଳ ହେଉନାହିଁ"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ବ୍ୟାକ୍‌ଅପ୍‌ ପାସ୍‌ୱର୍ଡ ସେଟିଙ୍ଗ ବିଫଳ ହୋଇଛି"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ଲୋଡ୍ ହେଉଛି…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"ଜୀବନ୍ତ (ପୂର୍ବ-ନିର୍ଦ୍ଧାରିତ)"</item>
     <item msgid="8446070607501413455">"ପ୍ରାକୃତିକ"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ପ୍ରତ୍ୟେକ ଥର ପଚାରନ୍ତୁ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"ଆପଣ ବନ୍ଦ ନକରିବା ପର୍ଯ୍ୟନ୍ତ DND ଅନ୍‌ ରହିବ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ଏହିକ୍ଷଣି"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ଡେଭଲପ୍‍‍‍‍‍‍‍‍ମେଣ୍ଟରେ ଅପ୍‍‍‍‍‍‍‍ଡେଟ୍‍ ଗ୍ରାଫିକ୍ସ ଡ୍ରାଇଭର୍‍ ବ୍ୟବହାର କରିବାକୁ ଆପ୍ଟ ଇ‍ନ୍‍ ଅପ୍ଲିକେସନ୍‍"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ଫୋନ୍‍ ସ୍ପିକର୍‍"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index f948a7e..eadc554 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s ਰਾਹੀਂ ਆਪਣੇ-ਆਪ ਕਨੈਕਟ ਹੋਇਆ"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ਨੈੱਟਵਰਕ ਰੇਟਿੰਗ ਪ੍ਰਦਾਨਕ ਰਾਹੀਂ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਕਨੈਕਟ ਹੋਇਆ"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ਰਾਹੀਂ ਉਪਲਬਧ"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ਕਨੈਕਟ ਕੀਤਾ, ਕੋਈ ਇੰਟਰਨੈੱਟ ਨਹੀਂ"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ਇੰਟਰਨੈੱਟ ਨਹੀਂ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ਸਾਈਨ-ਇਨ ਲੋੜੀਂਦਾ ਹੈ"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ਐਕਸੈੱਸ ਪੁਆਇੰਟ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਸੰਪੂਰਨ ਰੁਝੇਂਵੇਂ ਵਿੱਚ ਹੈ"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s ਰਾਹੀਂ ਉਪਲਬਧ"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"ਬਹੁਤ ਹੌਲੀ"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"ਹੌਲੀ"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ਠੀਕ ਹੈ"</string>
@@ -142,7 +216,7 @@
     <string name="launch_defaults_none" msgid="4241129108140034876">"ਕੋਈ ਡਿਫੌਲਟਸ ਸੈਟ ਨਹੀਂ ਕੀਤੇ"</string>
     <string name="tts_settings" msgid="8186971894801348327">"ਲਿਖਤ ਤੋਂ ਬੋਲੀ ਸੈਟਿੰਗਾਂ"</string>
     <string name="tts_settings_title" msgid="1237820681016639683">"ਲਿਖਤ-ਤੋਂ-ਬੋਲੀ ਆਊਟਪੁੱਟ"</string>
-    <string name="tts_default_rate_title" msgid="6030550998379310088">"ਸਪੀਚ ਰੇਟ"</string>
+    <string name="tts_default_rate_title" msgid="6030550998379310088">"ਬੋਲਣ ਦੀ ਗਤੀ"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"ਸਪੀਡ ਜਿਸਤੇ ਟੈਕਸਟ ਬੋਲਿਆ ਜਾਂਦਾ ਹੈ"</string>
     <string name="tts_default_pitch_title" msgid="6135942113172488671">"ਪਿਚ"</string>
     <string name="tts_default_pitch_summary" msgid="1944885882882650009">"ਬਣਾਵਟੀ ਬੋਲੀ ਦੇ ਲਹਿਜੇ \'ਤੇ ਅਸਰ ਪਾਉਂਦੀ ਹੈ"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"ਨਵਾਂ ਬੈਕਅੱਪ ਪਾਸਵਰਡ ਸੈੱਟ ਕੀਤਾ ਗਿਆ"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"ਨਵਾਂ ਪਾਸਵਰਡ ਅਤੇ ਪੁਸ਼ਟੀ ਮੇਲ ਨਹੀਂ ਖਾਂਦੀ"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ਬੈਕਅੱਪ ਪਾਸਵਰਡ ਸੈੱਟ ਕਰਨ ਵਿੱਚ ਅਸਫਲਤਾ"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"ਚਮਕੀਲਾ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)"</item>
     <item msgid="8446070607501413455">"ਕੁਦਰਤੀ"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ਹਰ ਵਾਰ ਪੁੱਛੋ"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਬੰਦ ਨਹੀਂ ਕਰਦੇ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ਹੁਣੇ ਹੀ"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ਅੱਪਡੇਟ ਕੀਤੇ ਵਿਕਾਸ-ਅਧੀਨ ਗ੍ਰਾਫਿਕਸ ਡਰਾਈਵਰ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਐਪ ਦੀ ਚੋਣ ਕਰੋ"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ਫ਼ੋਨ ਦਾ ਸਪੀਕਰ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index c75a894..f94308a 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatycznie połączono przez: %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatycznie połączono przez dostawcę ocen jakości sieci"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Połączono przez %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Dostępne przez %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Połączono, brak internetu"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Brak internetu"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Musisz się zalogować"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Punkt dostępu jest tymczasowo zajęty"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Połączono przez: %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Dostępna przez: %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Bardzo wolna"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Wolna"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nowe hasło kopii zapasowej zostało ustawione"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nowe hasła nie pasują do siebie"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nie udało się ustawić hasła kopii zapasowej"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Ładuję…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Żywe (domyślnie)"</item>
     <item msgid="8446070607501413455">"Naturalne"</item>
@@ -451,6 +526,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Zawsze pytaj"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dopóki nie wyłączysz"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Przed chwilą"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Wybierz aplikację, która ma używać opracowywanego sterownika grafiki"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Głośnik telefonu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index c273f59..f1b043b 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Conectado automaticamente via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Conectado automaticamente via provedor de avaliação de rede"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponível via %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conectada, sem Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Sem Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"É necessário fazer login"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Ponto de acesso temporariamente cheio"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Conectado via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Disponível via %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Muito lenta"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lenta"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Ok"</string>
@@ -142,9 +216,9 @@
     <string name="launch_defaults_none" msgid="4241129108140034876">"Nenhum padrão definido"</string>
     <string name="tts_settings" msgid="8186971894801348327">"Configurações da conversão de texto em voz"</string>
     <string name="tts_settings_title" msgid="1237820681016639683">"Conversão de texto em voz"</string>
-    <string name="tts_default_rate_title" msgid="6030550998379310088">"Taxa de fala"</string>
+    <string name="tts_default_rate_title" msgid="6030550998379310088">"Velocidade da fala"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidade em que o texto é falado"</string>
-    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tom da fala"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tom de voz"</string>
     <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afeta o tom da voz sintetizada"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Usar idioma do sistema"</string>
@@ -166,8 +240,8 @@
     <string name="tts_engine_settings_button" msgid="1030512042040722285">"Iniciar configurações do mecanismo"</string>
     <string name="tts_engine_preference_section_title" msgid="448294500990971413">"Mecanismo preferencial"</string>
     <string name="tts_general_section_title" msgid="4402572014604490502">"Gerais"</string>
-    <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Redefinir o tom da fala"</string>
-    <string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"Redefinir o tom no qual o texto é falado para o padrão."</string>
+    <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Redefinir o tom de voz"</string>
+    <string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"Redefinir o tom de voz para o padrão."</string>
   <string-array name="tts_rate_entries">
     <item msgid="6695494874362656215">"Muito devagar"</item>
     <item msgid="4795095314303559268">"Devagar"</item>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova senha de backup definida"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"A nova senha e a confirmação não coincidem."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Falha ao definir a senha de backup"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Carregando…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrante (padrão)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Perguntar sempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Até você desativar"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Agora"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ative o app para usar o driver gráfico atualizado no desenvolvimento"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Alto-falante do smartphone"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 26e4729..b0694d1 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Ligado automaticamente através de %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Ligado automaticamente através do fornecedor de classificação de rede"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Ligado através de %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponível através de %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Ligado, sem Internet."</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Sem Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"É necessário iniciar sessão"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Ponto de acesso temporariamente cheio"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Ligado através de %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Disponível através de %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Muito lenta"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lenta"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova palavra-passe da cópia de segurança definida"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"A nova palavra-passe e a confirmação não coincidem"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Falha na definição da palavra-passe da cópia de segurança"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"A carregar…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrante (predefinição)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Perguntar sempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Até ser desativado"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Agora mesmo"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Optar pela aplicação para utilizar a placa gráfica atualizada em desenvolvimento"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altifalante do telemóvel"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index c273f59..f1b043b 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Conectado automaticamente via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Conectado automaticamente via provedor de avaliação de rede"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponível via %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conectada, sem Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Sem Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"É necessário fazer login"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Ponto de acesso temporariamente cheio"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Conectado via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Disponível via %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Muito lenta"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lenta"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Ok"</string>
@@ -142,9 +216,9 @@
     <string name="launch_defaults_none" msgid="4241129108140034876">"Nenhum padrão definido"</string>
     <string name="tts_settings" msgid="8186971894801348327">"Configurações da conversão de texto em voz"</string>
     <string name="tts_settings_title" msgid="1237820681016639683">"Conversão de texto em voz"</string>
-    <string name="tts_default_rate_title" msgid="6030550998379310088">"Taxa de fala"</string>
+    <string name="tts_default_rate_title" msgid="6030550998379310088">"Velocidade da fala"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Velocidade em que o texto é falado"</string>
-    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tom da fala"</string>
+    <string name="tts_default_pitch_title" msgid="6135942113172488671">"Tom de voz"</string>
     <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afeta o tom da voz sintetizada"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"Usar idioma do sistema"</string>
@@ -166,8 +240,8 @@
     <string name="tts_engine_settings_button" msgid="1030512042040722285">"Iniciar configurações do mecanismo"</string>
     <string name="tts_engine_preference_section_title" msgid="448294500990971413">"Mecanismo preferencial"</string>
     <string name="tts_general_section_title" msgid="4402572014604490502">"Gerais"</string>
-    <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Redefinir o tom da fala"</string>
-    <string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"Redefinir o tom no qual o texto é falado para o padrão."</string>
+    <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Redefinir o tom de voz"</string>
+    <string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"Redefinir o tom de voz para o padrão."</string>
   <string-array name="tts_rate_entries">
     <item msgid="6695494874362656215">"Muito devagar"</item>
     <item msgid="4795095314303559268">"Devagar"</item>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova senha de backup definida"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"A nova senha e a confirmação não coincidem."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Falha ao definir a senha de backup"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Carregando…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrante (padrão)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Perguntar sempre"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Até você desativar"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Agora"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ative o app para usar o driver gráfico atualizado no desenvolvimento"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Alto-falante do smartphone"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 94f4842..032fceb 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Conectată automat prin %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Conectată automat prin furnizor de evaluări ale rețelei"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectată prin %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponibilă prin %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conectată, fără internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Fără conexiune la internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Trebuie să vă conectați"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Punctul de acces este temporar plin"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Conectată prin %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Disponibilă prin %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Foarte lentă"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Lentă"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Bine"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"A fost setată o parolă de rezervă nouă"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Parola nouă și confirmarea acesteia nu se potrivesc."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Setarea parolei de rezervă a eșuat"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Se încarcă…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (prestabilit)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -450,6 +525,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Întreabă de fiecare dată"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Până când dezactivați"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Chiar acum"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Aplicația pentru înscriere pentru a folosi driverul actualizat al plăcii grafice este în dezvoltare"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Difuzorul telefonului"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 1c331d8..a280285 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Автоматически подключено к %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Автоматически подключено через автора рейтинга сетей"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Подключено к %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Доступно через %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Подключено, без доступа к Интернету"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Нет подключения к Интернету"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Требуется выполнить вход."</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"К точке доступа подключено слишком много устройств"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Подключено к %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Доступно через %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Очень медленная"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Медленная"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ОК"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Новый пароль для резервной копии установлен"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Пароли не совпадают"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Не удалось установить пароль для резервной копии"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Загрузка…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Насыщенный (по умолчанию)"</item>
     <item msgid="8446070607501413455">"Естественный"</item>
@@ -451,6 +526,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Всегда спрашивать"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Пока вы не отключите"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Только что"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Приложение будет использовать обновленный драйвер графической системы (на стадии разработки)"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Встроенный динамик"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 608ff7f..c143c76 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s හරහා ස්වයංක්‍රියව සම්බන්ධ විය"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"ජාල ශ්‍රේණිගත සපයන්නා හරහා ස්වයංක්‍රියව සම්බන්ධ විය"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s හරහා සම්බන්ධ විය"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s හරහා ලබා ගැනීමට හැකිය"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"සම්බන්ධයි, අන්තර්ජාලය නැත"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"අන්තර්ජාලය නැත"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"පිරීම අවශ්‍යයි"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"ප්‍රවේශ ලක්ෂ්‍ය තාවකාලිකව පිරී ඇත"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s හරහා සම්බන්ධ විය"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s හරහා ලබා ගැනීමට හැකිය"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"ඉතා මන්දගාමී"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"මන්දගාමී"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"හරි"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"නව උපස්ථ මුරපදය සකසන ලදි"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"නව මුරපදය සහ සත්‍යාපනය නොගැළපුනි"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"උපස්ථ මුරපදය පිහිටුවීම අසාර්ථකය"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"පූරණය වේ…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"දීප්තිමත් (පෙරනිමිය)"</item>
     <item msgid="8446070607501413455">"ස්වභාවික"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"සෑම විටම ඉල්ලන්න"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"ඔබ ක්‍රියාවිරහිත කරන තුරු"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"මේ දැන්"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"වැඩිදියුණු වෙමින් ඇති යාවත්කාලීන කළ චිත්‍රක ධාවකය භාවිත කිරීමට යෙදුමට ඇතුළු වන්න"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"දුරකථන ස්පීකරය"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 2f76ef9..b41d5d3 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automaticky pripojené prostredníctvom %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automaticky pripojené prostredníctvom poskytovateľa hodnotenia siete"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Pripojené prostredníctvom %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"K dispozícii prostredníctvom %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Pripojené, žiadny internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Žiadny internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Vyžaduje sa prihlásenie"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Prístupový bod je dočasne plný"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Pripojené prostredníctvom operátora %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"K dispozícii prostredníctvom operátora %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Veľmi nízka"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Nízka"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nové heslo pre zálohy je nastavené"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nové heslo a potvrdenie sa nezhodujú"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nastavenie hesla pre zálohy zlyhalo"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Načítava sa…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Sýty (predvolený)"</item>
     <item msgid="8446070607501413455">"Prirodzený"</item>
@@ -451,6 +526,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vždy sa opýtať"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dokiaľ túto funkciu nevypnete"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Teraz"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Prihlásiť aplikáciu, ktorá má používať aktualizovaný ovládač grafickej karty vo vývoji"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Reproduktor telefónu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 64124cb..298acb9 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Samodejno vzpostavljena povezava prek: %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Samodejno vzpostavljena povezava prek ponudnika ocenjevanja omrežij"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Vzpostavljena povezava prek: %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Na voljo prek: %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Vzpostavljena povezava, brez interneta"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Brez internetne povezave"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Zahtevana je prijava"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Dostopna točka je trenutno zasedena"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Vzpostavljena povezava prek: %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Na voljo prek: %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Zelo počasna"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Počasna"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"V redu"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Novo geslo je nastavljeno"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Novo geslo in potrditev se ne ujemata."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nastavitev gesla ni uspela"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Nalaganje …"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Živo (privzeto)"</item>
     <item msgid="8446070607501413455">"Naravno"</item>
@@ -451,6 +526,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vedno vprašaj"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dokler ne izklopite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Pravkar"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Omogočena aplikacija za uporabo posodobljenega grafičnega gonilnika pri razvoju"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Zvočnik telefona"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 25d575e..569b4d9 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Lidhur automatikisht përmes %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Lidhur automatikisht nëpërmjet ofruesit të vlerësimit të rrjetit"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"E lidhur përmes %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"E mundshme përmes %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"U lidh, por nuk ka internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nuk ka internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Kërkohet identifikimi"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Pika e qasjes është përkohësisht plot"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"E lidhur përmes %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"E disponueshme përmes %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Shumë e ulët"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"E ngadaltë"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Në rregull"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Fjalëkalimi i ri u vendos"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Fjalëkalimi i ri dhe konfirmimi nuk përputhen"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Vendosja e fjalëkalimit dështoi"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Po ngarkohet…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Të gjalla (parazgjedhja)"</item>
     <item msgid="8446070607501413455">"Natyrale"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Pyet çdo herë"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Deri sa ta çaktivizosh"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Pikërisht tani"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Prano aplikacionin për të përdorur drejtuesin e përditësuar të grafikës që është në zhvillim"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Altoparlanti i telefonit"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index b58b47c..bf5e311 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Аутоматски повезано преко %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Аутоматски повезано преко добављача оцене мреже"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Веза је успостављена преко приступне тачке %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Доступна је преко приступне тачке %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Веза је успостављена, нема интернета"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Нема интернета"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Треба да се пријавите"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Приступна тачка је привремено заузета"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Повезано преко %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Доступно преко %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Веома спора"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Спора"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Потврди"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Постављена је нова лозинка резервне копије"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Нова лозинка и њена потврда се не подударају"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Постављање лозинке резервне копије није успело"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Учитава се…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Живописан (подразумевано)"</item>
     <item msgid="8446070607501413455">"Природан"</item>
@@ -450,6 +525,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Увек питај"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Док не искључите"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Управо"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Омогући апликацију за коришћење управљачког програма графичке катице у развоју"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Звучник телефона"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 7198b84..6e004df 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automatiskt ansluten via %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automatiskt ansluten via leverantör av nätverksbetyg"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Anslutet via %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Tillgängligt via %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Ansluten, inget internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Inget internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Inloggning krävs"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Åtkomstpunkten har inga platser över för tillfället"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Anslutet via %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Tillgängligt via %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Mycket långsam"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Långsam"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Okej"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Ett nytt lösenord har angetts"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Det nya lösenordet och bekräftelsen stämmer inte överens"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Det gick inte att ange lösenordet"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Läser in …"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Starka (standard)"</item>
     <item msgid="8446070607501413455">"Naturliga"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Fråga varje gång"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Tills du inaktiverar funktionen"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Nyss"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Välj om appen ska använda den uppdaterade grafikdrivrutinen under utveckling"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Mobilens högtalare"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 657b54f..bf03476 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Imeunganishwa kiotomatiki kupitia %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Imeunganishwa kiotomatiki kupitia mtoa huduma wa ukadiriaji wa mtandao"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Imeunganishwa kupitia %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Inapatikana kupitia %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Imeunganishwa, hakuna intaneti"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Hakuna intaneti"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Unahitaji kuingia katika akaunti"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Lango la mtandao lina shughuli nyingi kwa sasa"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Imeunganishwa kupitia %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Inapatikana kupitia %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Polepole Sana"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Polepole"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Sawa"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nenosiri jipya la hifadhi rudufu limewekwa"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nenosiri jipya na uthibitisho havioani"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Imeshindwa kuweka nenosiri la hifadhi rudufu"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Inapakia…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Maridadi (chaguomsingi)"</item>
     <item msgid="8446070607501413455">"Asili"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Uliza kila wakati"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Hadi utakapoizima"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Sasa hivi"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Chagua programu itakayotumia kiendeshaji cha michoro kilichosasishwa katika hatua ya kusanidi"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Spika ya simu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 59b42d8..58e5967 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s மூலம் தானாக இணைக்கப்பட்டது"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"நெட்வொர்க் மதிப்பீடு வழங்குநரால் தானாக இணைக்கப்பட்டது"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s வழியாக இணைக்கப்பட்டது"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s வழியாகக் கிடைக்கிறது"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"இணைக்கப்பட்டுள்ளது, ஆனால் இண்டர்நெட் இல்லை"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"இணைய இணைப்பு இல்லை"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"உள்நுழைய வேண்டும்"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"தற்காலிகமாக அணுகல் புள்ளி நிரம்பியுள்ளது"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s வழியாக இணைக்கப்பட்டது"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s வழியாகக் கிடைக்கிறது"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"மிகவும் வேகம் குறைவானது"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"வேகம் குறைவு"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"சரி"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"புதிய காப்புப் பிரதியின் கடவுச்சொல் அமைக்கப்பட்டது"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"புதிய கடவுச்சொல்லும், உறுதிப்படுத்தலுக்கான கடவுச்சொல்லும் பொருந்தவில்லை"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"காப்புப் பிரதி கடவுச்சொல்லை அமைப்பதில் தோல்வி"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"ஏற்றுகிறது…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"வைபிரன்ட் (இயல்பு)"</item>
     <item msgid="8446070607501413455">"இயற்கை வண்ணம்"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ஒவ்வொரு முறையும் கேள்"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"ஆஃப் செய்யும் வரை"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"சற்றுமுன்"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"உருவாக்கத்திலுள்ள புதுப்பிக்கப்பட்ட கிராஃபிக்ஸ் டிரைவரைப் பயன்படுத்த ஆப்ஸைத் தேர்ந்தெடுக்கவும்"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"மொபைல் ஸ்பீக்கர்"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml
index ddb40ce..5d79065 100644
--- a/packages/SettingsLib/res/values-te/arrays.xml
+++ b/packages/SettingsLib/res/values-te/arrays.xml
@@ -173,7 +173,7 @@
     <item msgid="2850427388488887328">"కెర్నెల్ మాత్రమే"</item>
   </string-array>
   <string-array name="select_logpersist_summaries">
-    <item msgid="2216470072500521830">"ఆఫ్ చేయి"</item>
+    <item msgid="2216470072500521830">"ఆఫ్"</item>
     <item msgid="172978079776521897">"అన్ని లాగ్ బఫర్‌లు"</item>
     <item msgid="3873873912383879240">"అన్నీ కానీ రేడియో లాగ్ బఫర్‌లు"</item>
     <item msgid="8489661142527693381">"కెర్నెల్ లాగ్ బఫర్ మాత్రమే"</item>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index af233da..9d1b23e 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s ద్వారా స్వయంచాలకంగా కనెక్ట్ చేయబడింది"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"నెట్‌వర్క్ రేటింగ్ ప్రదాత ద్వారా స్వయంచాలకంగా కనెక్ట్ చేయబడింది"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ద్వారా కనెక్ట్ చేయబడింది"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ద్వారా అందుబాటులో ఉంది"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"కనెక్ట్ చేయబడింది, ఇంటర్నెట్ లేదు"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ఇంటర్నెట్ లేదు"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"సైన్ ఇన్ చేయాలి"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"యాక్సెస్ పాయింట్ తాత్కాలికంగా నిండుకుంది"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s ద్వారా కనెక్ట్ చేయబడింది"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s ద్వారా అందుబాటులో ఉంది"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"చాలా నెమ్మది"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"నెమ్మది"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"సరే"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"కొత్త బ్యాకప్ పాస్‌వర్డ్‌ను సెట్ చేసారు"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"కొత్త పాస్‌వర్డ్ మరియు నిర్ధారణ సరిపోలడం లేదు"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"బ్యాకప్ పాస్‌వర్డ్‌ను సెట్ చేయడంలో వైఫల్యం"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"లోడ్ చేస్తోంది…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"సచేతనం (డిఫాల్ట్)"</item>
     <item msgid="8446070607501413455">"సహజం"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ప్రతిసారి అడుగు"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"మీరు ఆఫ్‌ చేసే వరకు"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ఇప్పుడే"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"అభివృద్దిలో అప్‌డేట్‌ చేసిన గ్రాఫిక్ డ్రైవర్‌ను ఉపయోగించడానికి యాప్‌ని ప్రారంభించండి"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ఫోన్ స్పీకర్"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 636c3f2..ddd9aae 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"เชื่อมต่ออัตโนมัติผ่าน %1$s แล้ว"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"เชื่อมต่ออัตโนมัติผ่านผู้ให้บริการการจัดอันดับเครือข่าย"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"เชื่อมต่อผ่าน %1$s แล้ว"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"พร้อมใช้งานผ่านทาง %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"เชื่อมต่อแล้ว ไม่พบอินเทอร์เน็ต"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ไม่มีอินเทอร์เน็ต"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ต้องลงชื่อเข้าใช้"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"จุดเข้าใช้งานเต็มชั่วคราว"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"เชื่อมต่อผ่าน %1$s แล้ว"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"พร้อมใช้งานผ่านทาง %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"ช้ามาก"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"ช้า"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ตกลง"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"ตั้งรหัสผ่านสำหรับการสำรองข้อมูลใหม่แล้ว"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"รหัสผ่านใหม่และการพิมพ์ยืนยันไม่ตรงกัน"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"ไม่สามารถตั้งรหัสผ่านสำหรับการสำรองข้อมูล"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"กำลังโหลด…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"สด (ค่าเริ่มต้น)"</item>
     <item msgid="8446070607501413455">"ธรรมชาติ"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ถามทุกครั้ง"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"จนกว่าคุณจะปิด"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"เมื่อสักครู่"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"เลือกใช้แอปเพื่อใช้ไดรเวอร์กราฟิกที่อัปเดตในการพัฒนา"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"ลำโพงโทรศัพท์"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 1bcc36a..6445480 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Awtomatikong nakakonekta sa pamamagitan ng %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Awtomatikong nakakonekta sa pamamagitan ng provider ng rating ng network"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Nakakonekta sa pamamagitan ng %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available sa pamamagitan ng %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Nakakonekta, walang internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Walang internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Kinakailangang mag-sign in"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Pansamantalang puno ang access point"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Nakakonekta sa pamamagitan ng %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Available sa pamamagitan ng %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Napakabagal"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Mabagal"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Naitakda ang bagong backup na password"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Hindi tugma ang password at kumpirmasyon"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nabigo sa pagtatakda ng backup na password"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Naglo-load…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Vibrant (default)"</item>
     <item msgid="8446070607501413455">"Natural"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Magtanong palagi"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Hanggang sa i-off mo"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Ngayon lang"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"App sa pag-opt in para magamit ang na-update na graphics driver na ginagawa"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Speaker ng telepono"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index ff669f6..c3a3ff2 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s üzerinden otomatik olarak bağlı"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Ağ derecelendirme sağlayıcı aracılığıyla otomatik olarak bağlandı"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s üzerinden bağlı"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s üzerinden kullanılabilir"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Bağlı, internet yok"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"İnternet yok"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Oturum açılması gerekiyor"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Erişim noktası geçici olarak dolu"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s üzerinden bağlı"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s üzerinden kullanılabilir"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Çok Yavaş"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Yavaş"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Tamam"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Yeni yedekleme şifresi ayarlandı"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Yeni şifre ve onayı eşleşmiyor."</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Yedekleme şifresi ayarlanamadı"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Yükleniyor…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Canlı (varsayılan)"</item>
     <item msgid="8446070607501413455">"Doğal"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Her zaman sor"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Siz kapatana kadar"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Az önce"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Güncellenmiş grafik sürücüsünü geliştirme ortamında kullanmak için uygulamayı kaydedin"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon hoparlörü"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 2ded8c1..a28dc18 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Автоматично під’єднано через %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Автоматично під’єднано через постачальника оцінки якості мережі"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Під’єднано через %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Доступ через %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Під’єднано, але немає доступу до Інтернету"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Немає Інтернету"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Потрібно ввійти в обліковий запис"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Точка доступу тимчасово переповнена"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Під’єднано через мережу %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Доступ через мережу %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Дуже повільна"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Повільна"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ОК"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Новий пароль резервної копії встановлено"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Паролі не збігаються"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Не вдалося зберегти пароль"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Завантаження…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Насичений (за умовчанням)"</item>
     <item msgid="8446070607501413455">"Природний"</item>
@@ -451,6 +526,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Запитувати щоразу"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Доки ви не вимкнете"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Щойно"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Вибраний додаток, який використовуватиме оновлений графічний драйвер під час розробки"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Динамік телефона"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 7dc4690..397f4b2 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"‏‎%1$s کے ذریعے از خود منسلک کردہ"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"نیٹ ورک درجہ بندی کے فراہم کنندہ کے ذریعے از خود منسلک"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"‏منسلک بذریعہ ‎%1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"‏دستیاب بذریعہ ‎%1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"منسلک، انٹرنیٹ نہیں ہے"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"انٹرنیٹ نہیں ہے"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"سائن ان درکار ہے"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"رسائی پوائنٹ عارضی طور پر فُل ہے"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"‏منسلک بذریعہ ‎%1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"‏دستیاب بذریعہ ‎%1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"بہت سست"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"سست"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"ٹھیک ہے"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"بیک اپ کا نیا پاس ورڈ سیٹ کر دیا گیا"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"نیا پاس ورڈ اور تصدیق مماثل نہیں ہے"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"بیک اپ پاس ورڈ ترتیب دینے میں ناکامی"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"لوڈ ہو رہی ہے…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"پرجوش (ڈیفالٹ)"</item>
     <item msgid="8446070607501413455">"قدرتی"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"ہر بار پوچھیں"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"یہاں تک کہ آپ آف کر دیں"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ابھی ابھی"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"ڈیولپمنٹ میں اپ ڈیٹ کردہ گرافکس ڈرائیور کو استعمال کرنے کے لیے ایپ آپٹ ان کریں"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"فون اسپیکر"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 5f92c9a..5f214ce 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s orqali avtomatik ulandi"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Tarmoqlar reytingi muallifi orqali avtomatik ulandi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s orqali ulangan"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s orqali ishlaydi"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Ulangan, lekin internet aloqasi yo‘q"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Internet yo‘q"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Hisob bilan kirish zarur"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Internet kirish nuqtasi vaqtinchalik to‘lgan"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"%1$s orqali ulangan"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"%1$s orqali ishlaydi"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Juda sekin"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Sekin"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"OK"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Yangi zaxira paroli o‘rnatildi"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Parollar bir-biriga mos kelmadi"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Zaxira parolini o‘rnatib bo‘lmadi"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Yuklanmoqda…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Yorqin (birlamchi)"</item>
     <item msgid="8446070607501413455">"Tabiiy"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Har safar so‘ralsin"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Bekor qilinmaguncha"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Hozir"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Ilova yangilangan grafik drayverdan (hali ishlov jarayonida) foydalanadi"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Telefon karnayi"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index eb10fb1..e019953 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Tự động được kết nối qua %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Tự động được kết nối qua nhà cung cấp dịch vụ xếp hạng mạng"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Được kết nối qua %1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Có sẵn qua %1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Đã kết nối, không có Internet"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Không có Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Yêu cầu đăng nhập"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Điểm truy cập tạm thời đã đạt đến giới hạn số lượng thiết bị truy cập."</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Được kết nối qua %1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Có sẵn qua %1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Rất chậm"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Chậm"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"Khá tốt"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Đã đặt mật khẩu sao lưu mới"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Mật khẩu mới và xác nhận không khớp"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Đặt mật khẩu sao lưu không thành công"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Đang tải…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Sống động (mặc định)"</item>
     <item msgid="8446070607501413455">"Tự nhiên"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Luôn hỏi"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Cho đến khi bạn tắt"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Vừa xong"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Chọn ứng dụng để sử dụng trình điều khiển đồ họa được cập nhật trong giai đoạn phát triển"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Loa điện thoại"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 7b14138..fd0d36e 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"已通过%1$s自动连接"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"已自动连接(通过网络评分服务提供方)"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"已通过%1$s连接"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"可通过%1$s连接"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"已连接,但无法访问互联网"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"无法访问互联网"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"必须登录"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"接入点暂时满载"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"已通过%1$s连接"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"可通过%1$s连接"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"很慢"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"慢"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"良好"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"已设置了新的备份密码"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"新密码和确认密码不一致"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"设置备份密码失败"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"正在加载…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"鲜亮(默认)"</item>
     <item msgid="8446070607501413455">"自然"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"每次都询问"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"直到您将其关闭"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"刚刚"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"为应用启用更新后的显卡驱动,以在开发过程中使用"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"手机扬声器"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 48b6959..024299b 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"已透過 %1$s 自動連線"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"已透過網絡評分供應商自動連線"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"可透過 %1$s 連線"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"已連線,但沒有互聯網"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"沒有互聯網連線"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"必須登入"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"存取點暫時已滿"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"已透過 %1$s 連線"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"可透過 %1$s 連線"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"非常慢"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"慢"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"良好"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"已設定新備份密碼"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"新密碼與確認密碼不符"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"無法設定備份密碼"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"正在載入…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"生動 (預設)"</item>
     <item msgid="8446070607501413455">"自然"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"每次都詢問"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"直至您關閉為止"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"剛剛"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"請選取應用程式,以在開發階段使用更新的顯示卡驅動程式"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"手機喇叭"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 684569b..146ffac 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"已透過 %1$s 自動連線"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"已透過網路評分供應商自動連線"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"可透過 %1$s 使用"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"已連線,沒有網際網路"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"沒有網際網路連線"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"必須登入"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"存取點暫時滿載"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"已透過 %1$s 連線"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"可透過 %1$s 使用"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"非常慢"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"慢"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"確定"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"已設定新備份密碼"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"新密碼與確認密碼不符。"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"無法設定備份密碼"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"載入中…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"鮮活 (預設)"</item>
     <item msgid="8446070607501413455">"自然"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"每次都詢問"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"直到你關閉為止"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"剛剛"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"選取要在開發階段使用最新版繪圖驅動程式的應用程式"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"手機喇叭"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index d107a5a..fc7b9b4 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -38,13 +38,87 @@
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Ixhumeke ngokuzenzakalela nge-%1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Kuxhunywe ngokuzenzakalelayo ngomhlinzeki wesilinganiso wenethiwekhi"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Kuxhumeke nge-%1$s"</string>
+    <!-- no translation found for ssid_by_passpoint_provider (7898171424140673315) -->
+    <skip />
     <string name="available_via_passpoint" msgid="1617440946846329613">"Iyatholakala nge-%1$s"</string>
+    <!-- no translation found for tap_to_set_up (2468970825530423314) -->
+    <skip />
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Kuxhunyiwe, ayikho i-inthanethi"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Ayikho i-inthanethi"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Ukungena ngemvume kuyadingeka"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Iphoyinti lokufinyelela ligcwele okwesikhashana"</string>
     <string name="connected_via_carrier" msgid="7583780074526041912">"Kuxhumeke nge-%1$s"</string>
     <string name="available_via_carrier" msgid="1469036129740799053">"Iyatholakala nge-%1$s"</string>
+    <!-- no translation found for osu_failure_ap_connection (598977488344424542) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_url_invalid (2237477219243136714) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_connection (8192988165059982174) -->
+    <skip />
+    <!-- no translation found for osu_failure_server_validation (4631649978129606823) -->
+    <skip />
+    <!-- no translation found for osu_failure_service_provider_verification (4854091521439785597) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_aborted (424627208135320329) -->
+    <skip />
+    <!-- no translation found for osu_failure_provisioning_not_available (3021783729256985432) -->
+    <skip />
+    <!-- no translation found for osu_failure_invalid_server_url (8548886196179435758) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_command_type (8245921319866603904) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_type (2255897608510053065) -->
+    <skip />
+    <!-- no translation found for osu_failure_soap_message_exchange (4357358438685987192) -->
+    <skip />
+    <!-- no translation found for osu_failure_start_redirect_listener (4292769407279548482) -->
+    <skip />
+    <!-- no translation found for osu_failure_timed_out_redirect_listener (3168657820278807508) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_osu_activity_found (4593038891437878675) -->
+    <skip />
+    <!-- no translation found for osu_failure_unexpected_soap_message_status (6568467710235256675) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_pps_mo (850567403039076835) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_server_trust_root_node (8961455873459838456) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_remediation_server_trust_root_node (5041179688081545244) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_policy_server_trust_root_node (6617290380940513539) -->
+    <skip />
+    <!-- no translation found for osu_failure_retrieve_trust_root_certificates (1499136256195528265) -->
+    <skip />
+    <!-- no translation found for osu_failure_no_aaa_trust_root_certificate (1904322497042226984) -->
+    <skip />
+    <!-- no translation found for osu_failure_add_passpoint_configuration (2173557755811446047) -->
+    <skip />
+    <!-- no translation found for osu_failure_osu_provider_not_found (6616172862116673082) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connecting (5296821043003441437) -->
+    <skip />
+    <!-- no translation found for osu_status_ap_connected (3777289375683170728) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connecting (8499785407540355867) -->
+    <skip />
+    <!-- no translation found for osu_status_server_validated (3158727184762596355) -->
+    <skip />
+    <!-- no translation found for osu_status_server_connected (8382024481520158168) -->
+    <skip />
+    <!-- no translation found for osu_status_init_soap_exchange (8628063888912101981) -->
+    <skip />
+    <!-- no translation found for osu_status_waiting_for_redirect_response (2343016207837053197) -->
+    <skip />
+    <!-- no translation found for osu_status_redirect_response_received (5323368411922609405) -->
+    <skip />
+    <!-- no translation found for osu_status_second_soap_exchange (7115332266758483909) -->
+    <skip />
+    <!-- no translation found for osu_status_third_soap_exchange (8460901783597440766) -->
+    <skip />
+    <!-- no translation found for osu_status_retrieving_trust_root_certs (1563445892926269689) -->
+    <skip />
+    <!-- no translation found for osu_provisioning_complete (5120178802493970149) -->
+    <skip />
     <string name="speed_label_very_slow" msgid="1867055264243608530">"Phansi kakhulu"</string>
     <string name="speed_label_slow" msgid="813109590815810235">"Phansi"</string>
     <string name="speed_label_okay" msgid="2331665440671174858">"KULUNGILE"</string>
@@ -330,6 +404,7 @@
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"Iphasiwedi entsha eyisipele isethiwe"</string>
     <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Iphasiwedi entsha nokuqinisekisa akufani"</string>
     <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Ukungaphumeleli kokusetha iphasiwedi eyisipele"</string>
+    <string name="loading_injected_setting_summary" msgid="4095178591461231376">"Iyalayisha…"</string>
   <string-array name="color_mode_names">
     <item msgid="2425514299220523812">"Dlidlizela (okuzenzakalelayo)"</item>
     <item msgid="8446070607501413455">"Kwemvelo"</item>
@@ -449,6 +524,5 @@
     <string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Buza njalo"</string>
     <string name="zen_mode_forever" msgid="2704305038191592967">"Uze uvale isikrini"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Khona manje"</string>
-    <string name="updated_gfx_driver_dev_opt_in_app_summary" msgid="5309913444094165199">"Uhlelo lokusebenza lokukhetha ukungena olungasebenzisa idrayivu yamagrafikhi ekuthuthukiseni"</string>
     <string name="media_transfer_phone_device_name" msgid="1003823744105758574">"Isipikha sefoni"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 09fa284..ed3c11c 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -102,6 +102,20 @@
 
 
     <!-- Bluetooth settings -->
+    <!-- Titles for Bluetooth HCI Snoop Logging -->
+    <string-array name="bt_hci_snoop_log_entries">
+        <item>Disabled</item>
+        <item>Enabled Filtered</item>
+        <item>Enabled</item>
+    </string-array>
+
+    <!-- Values for Bluetooth HCI Snoop Logging -->
+    <string-array name="bt_hci_snoop_log_values" translatable="false">
+        <item>disabled</item>
+        <item>filtered</item>
+        <item>full</item>
+    </string-array>
+
     <!-- Titles for Bluetooth AVRCP Versions -->
     <string-array name="bluetooth_avrcp_versions">
         <item>AVRCP 1.4 (Default)</item>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 842779d..c8f8d73 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -99,8 +99,12 @@
     <string name="connected_via_network_scorer_default">Automatically connected via network rating provider</string>
     <!-- Status message of Wi-Fi when it is connected by Passpoint configuration. [CHAR LIMIT=NONE] -->
     <string name="connected_via_passpoint">Connected via %1$s</string>
+    <!-- Status message of Wi-Fi when it is connected by Passpoint configuration. [CHAR LIMIT=NONE] -->
+    <string name="ssid_by_passpoint_provider"><xliff:g id="ssid" example="Cafe Wifi">%1$s</xliff:g> by <xliff:g id="passpointProvider" example="Passpoint Provider">%2$s</xliff:g></string>
     <!-- Status message of Wi-Fi when network has matching passpoint credentials. [CHAR LIMIT=NONE] -->
     <string name="available_via_passpoint">Available via %1$s</string>
+    <!-- Status message of OSU Provider network when not connected. [CHAR LIMIT=NONE] -->
+    <string name="tap_to_set_up">Tap to set up</string>
     <!-- Package name for Settings app-->
     <string name="settings_package" translatable="false">com.android.settings</string>
     <!-- Package name for Certinstaller app-->
@@ -123,6 +127,79 @@
     <!-- Status message of Wi-Fi when an available network is a carrier network. [CHAR LIMIT=NONE] -->
     <string name="available_via_carrier">Available via %1$s</string>
 
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_AP_CONNECTION. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_ap_connection">Connection failed</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_SERVER_URL_INVALID. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_server_url_invalid">Invalid OSU server URL</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_SERVER_CONNECTION. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_server_connection">OSU server connection failed</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_SERVER_VALIDATION. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_server_validation">OSU server validation failed</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_service_provider_verification">Invalid OSU server certificate</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_PROVISIONING_ABORTED. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_provisioning_aborted">Provisioning aborted</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_PROVISIONING_NOT_AVAILABLE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_provisioning_not_available">Provisioning not available</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_INVALID_SERVER_URL. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_invalid_server_url">Invalid OSU server URL</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_UNEXPECTED_COMMAND_TYPE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_unexpected_command_type">Unexpected command type</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_unexpected_soap_message_type">Unexpected SOAP message type</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_SOAP_MESSAGE_EXCHANGE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_soap_message_exchange">SOAP message exchange failed</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_START_REDIRECT_LISTENER. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_start_redirect_listener">Redirect listener failed to start</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_timed_out_redirect_listener">Timed out waiting for redirect</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_OSU_ACTIVITY_FOUND. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_no_osu_activity_found">No OSU activity found</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_unexpected_soap_message_status">Unexpected SOAP message status</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_PPS_MO. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_no_pps_mo">Failed to find PPS-MO</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_no_aaa_server_trust_root_node">Failed to find trust root node for AAA server</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_no_remediation_server_trust_root_node">Failed to find trust root node for remediation server</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_no_policy_server_trust_root_node">Failed to find trust root node for policy server</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_retrieve_trust_root_certificates">Failed to retrieve trust root certificates</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_no_aaa_trust_root_certificate">Failed to find trust root certificate for AAA server</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_add_passpoint_configuration">Failed to add PassPoint configuration</string>
+    <!-- Status message of OSU Provider on receiving OSU_FAILURE_OSU_PROVIDER_NOT_FOUND. [CHAR LIMIT=NONE] -->
+    <string name="osu_failure_osu_provider_not_found">Failed to find an OSU provider</string>
+
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_AP_CONNECTING. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_ap_connecting">Connecting</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_AP_CONNECTED. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_ap_connected">Connected</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_SERVER_CONNECTING. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_server_connecting">Connecting to OSU server</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_SERVER_VALIDATED. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_server_validated">OSU server validated</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_SERVER_CONNECTED. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_server_connected">Connected to OSU server</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_INIT_SOAP_EXCHANGE. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_init_soap_exchange">Initial SOAP exchange</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_WAITING_FOR_REDIRECT_RESPONSE. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_waiting_for_redirect_response">Waiting for redirect response</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_REDIRECT_RESPONSE_RECEIVED. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_redirect_response_received">Received redirect response</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_SECOND_SOAP_EXCHANGE. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_second_soap_exchange">Second SOAP exchange</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_THIRD_SOAP_EXCHANGE. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_third_soap_exchange">Third SOAP exchange</string>
+    <!-- Status message of OSU Provider on receiving OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS. [CHAR LIMIT=NONE] -->
+    <string name="osu_status_retrieving_trust_root_certs">Retrieving trust root certificates</string>
+
+    <!-- Status message of OSU Provider on completing provisioning. [CHAR LIMIT=NONE] -->
+    <string name="osu_provisioning_complete">Provisioning complete</string>
+
     <!-- Speed label for very slow network speed -->
     <string name="speed_label_very_slow">Very Slow</string>
     <!-- Speed label for slow network speed -->
@@ -514,8 +591,8 @@
     <string name="keep_screen_on_summary">Screen will never sleep while charging</string>
     <!-- Setting Checkbox title whether to enable Bluetooth HCI snoop log -->
     <string name="bt_hci_snoop_log">Enable Bluetooth HCI snoop log</string>
-    <!-- setting Checkbox summary whether to capture all Bluetooth HCI packets in a file -->
-    <string name="bt_hci_snoop_log_summary">Capture all Bluetooth HCI packets in a file (Toggle Bluetooth after changing this setting)</string>
+    <!-- setting Checkbox summary whether to capture all Bluetooth HCI packets in a file [CHAR_LIMIT=100] -->
+    <string name="bt_hci_snoop_log_summary">Capture Bluetooth packets. (Toggle Bluetooth after changing this setting)</string>
     <!-- setting Checkbox title whether to enable OEM unlock [CHAR_LIMIT=35] -->
     <string name="oem_unlock_enable">OEM unlocking</string>
     <!-- setting Checkbox summary whether to enable OEM unlock [CHAR_LIMIT=50] -->
@@ -1137,9 +1214,6 @@
     <!-- The notice header of Third-party licenses. not translatable -->
     <string name="notice_header" translatable="false"></string>
 
-    <!-- UI debug setting: opt in to use updated graphics driver? [CHAR LIMIT=100] -->
-    <string name="updated_gfx_driver_dev_opt_in_app_summary">Opt in app to use updated graphcis driver in developement</string>
-
     <!-- Name of the phone device [CHAR LIMIT=NONE] -->
     <string name="media_transfer_phone_device_name">Phone speaker</string>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 6abe76a..c751c39 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -1,5 +1,7 @@
 package com.android.settingslib;
 
+import static android.telephony.ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
+
 import android.annotation.ColorInt;
 import android.content.Context;
 import android.content.Intent;
@@ -36,8 +38,8 @@
     private static final String CURRENT_MODE_KEY = "CURRENT_MODE";
     private static final String NEW_MODE_KEY = "NEW_MODE";
     @VisibleForTesting
-    static final String STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY =
-            "ro.storage_manager.show_opt_in";
+    static final String STORAGE_MANAGER_ENABLED_PROPERTY =
+            "ro.storage_manager.enabled";
 
     private static Signature[] sSystemSignature;
     private static String sPermissionControllerPackageName;
@@ -371,8 +373,7 @@
     public static boolean isStorageManagerEnabled(Context context) {
         boolean isDefaultOn;
         try {
-            // Turn off by default if the opt-in was shown.
-            isDefaultOn = !SystemProperties.getBoolean(STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY, true);
+            isDefaultOn = SystemProperties.getBoolean(STORAGE_MANAGER_ENABLED_PROPERTY, false);
         } catch (Resources.NotFoundException e) {
             isDefaultOn = false;
         }
@@ -429,12 +430,14 @@
         // and do not support voice service, and on these SIM cards, we
         // want to show signal bars for data service as well as the "no
         // service" or "emergency calls only" text that indicates that voice
-        // is not available.
+        // is not available. Note that we ignore the IWLAN service state
+        // because that state indicates the use of VoWIFI and not cell service
         int state = serviceState.getState();
         int dataState = serviceState.getDataRegState();
         if (state == ServiceState.STATE_OUT_OF_SERVICE
                 || state == ServiceState.STATE_EMERGENCY_ONLY) {
-            if (dataState == ServiceState.STATE_IN_SERVICE) {
+            if (dataState == ServiceState.STATE_IN_SERVICE
+                    && serviceState.getDataNetworkType() != RIL_RADIO_TECHNOLOGY_IWLAN) {
                 return ServiceState.STATE_IN_SERVICE;
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java b/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java
index 2387b01..5e5c22a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java
@@ -16,8 +16,8 @@
 package com.android.settingslib.applications;
 
 import android.content.Context;
+import android.permission.PermissionControllerManager;
 import android.permission.RuntimePermissionPresentationInfo;
-import android.permission.RuntimePermissionPresenter;
 
 import java.text.Collator;
 import java.util.ArrayList;
@@ -28,9 +28,9 @@
 
     public static void getPermissionSummary(Context context, String pkg,
             final PermissionsResultCallback callback) {
-        final RuntimePermissionPresenter presenter =
-                RuntimePermissionPresenter.getInstance(context);
-        presenter.getAppPermissions(pkg, permissions -> {
+        final PermissionControllerManager permController =
+                context.getSystemService(PermissionControllerManager.class);
+        permController.getAppPermissions(pkg, permissions -> {
             final int permissionCount = permissions.size();
 
             int grantedStandardCount = 0;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 58feef5..c059156 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -35,7 +35,6 @@
 
 public class A2dpProfile implements LocalBluetoothProfile {
     private static final String TAG = "A2dpProfile";
-    private static boolean V = false;
 
     private Context mContext;
 
@@ -60,7 +59,6 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            if (V) Log.d(TAG,"Bluetooth service connected");
             mService = (BluetoothA2dp) proxy;
             // We just bound to the service, so refresh the UI for any connected A2DP devices.
             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -76,10 +74,10 @@
                 device.refresh();
             }
             mIsProfileReady=true;
+            mProfileManager.callServiceConnectedListeners();
         }
 
         public void onServiceDisconnected(int profile) {
-            if (V) Log.d(TAG,"Bluetooth service disconnected");
             mIsProfileReady=false;
         }
     }
@@ -302,7 +300,7 @@
     }
 
     protected void finalize() {
-        if (V) Log.d(TAG, "finalize()");
+        Log.d(TAG, "finalize()");
         if (mService != null) {
             try {
                 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index 988062d..873dd1a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -55,7 +55,6 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            Log.d(TAG, "Bluetooth service connected");
             mService = (BluetoothA2dpSink) proxy;
             // We just bound to the service, so refresh the UI for any connected A2DP devices.
             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -74,7 +73,6 @@
         }
 
         public void onServiceDisconnected(int profile) {
-            Log.d(TAG, "Bluetooth service disconnected");
             mIsProfileReady=false;
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 62507f5..6b6df9b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -58,7 +58,6 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            Log.d(TAG,"Bluetooth service connected");
             mService = (BluetoothHeadset) proxy;
             // We just bound to the service, so refresh the UI for any connected HFP devices.
             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -80,7 +79,6 @@
         }
 
         public void onServiceDisconnected(int profile) {
-            Log.d(TAG,"Bluetooth service disconnected");
             mProfileManager.callServiceDisconnectedListeners();
             mIsProfileReady=false;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index adb5ab3..77dfbe9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -51,7 +51,6 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            if (V) Log.d(TAG,"Bluetooth service connected");
             mService = (BluetoothHearingAid) proxy;
             // We just bound to the service, so refresh the UI for any connected HearingAid devices.
             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -72,12 +71,11 @@
 
             // Check current list of CachedDevices to see if any are Hearing Aid devices.
             mDeviceManager.updateHearingAidsDevices();
-
             mIsProfileReady=true;
+            mProfileManager.callServiceConnectedListeners();
         }
 
         public void onServiceDisconnected(int profile) {
-            if (V) Log.d(TAG,"Bluetooth service disconnected");
             mIsProfileReady=false;
         }
     }
@@ -234,7 +232,7 @@
     }
 
     protected void finalize() {
-        if (V) Log.d(TAG, "finalize()");
+        Log.d(TAG, "finalize()");
         if (mService != null) {
             try {
                 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HEARING_AID,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index 4879144..c6bb2b3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -59,7 +59,6 @@
 
         @Override
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            Log.d(TAG, "Bluetooth service connected");
             mService = (BluetoothHeadsetClient) proxy;
             // We just bound to the service, so refresh the UI for any connected HFP devices.
             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -80,7 +79,6 @@
 
         @Override
         public void onServiceDisconnected(int profile) {
-            Log.d(TAG, "Bluetooth service disconnected");
             mIsProfileReady=false;
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
index 61e5b6b..4dc050c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
@@ -58,7 +58,6 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            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();
@@ -78,7 +77,6 @@
         }
 
         public void onServiceDisconnected(int profile) {
-            Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
             mIsProfileReady = false;
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index 75d16db..ca840d9a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -33,7 +33,6 @@
  */
 public class HidProfile implements LocalBluetoothProfile {
     private static final String TAG = "HidProfile";
-    private static boolean V = true;
 
     private BluetoothHidHost mService;
     private boolean mIsProfileReady;
@@ -51,7 +50,6 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            if (V) Log.d(TAG,"Bluetooth service connected");
             mService = (BluetoothHidHost) proxy;
             // We just bound to the service, so refresh the UI for any connected HID devices.
             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -70,7 +68,6 @@
         }
 
         public void onServiceDisconnected(int profile) {
-            if (V) Log.d(TAG,"Bluetooth service disconnected");
             mIsProfileReady=false;
         }
     }
@@ -186,7 +183,7 @@
     }
 
     protected void finalize() {
-        if (V) Log.d(TAG, "finalize()");
+        Log.d(TAG, "finalize()");
         if (mService != null) {
             try {
                 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HID_HOST,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index 1e22f44..6acdcac 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -59,7 +59,6 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            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();
@@ -81,7 +80,6 @@
         }
 
         public void onServiceDisconnected(int profile) {
-            Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
             mProfileManager.callServiceDisconnectedListeners();
             mIsProfileReady=false;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index 7582024..28975d4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -58,7 +58,6 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            Log.d(TAG, "Bluetooth service connected");
             mService = (BluetoothMap) proxy;
             // We just bound to the service, so refresh the UI for any connected MAP devices.
             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -80,7 +79,6 @@
         }
 
         public void onServiceDisconnected(int profile) {
-            Log.d(TAG, "Bluetooth service disconnected");
             mProfileManager.callServiceDisconnectedListeners();
             mIsProfileReady=false;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index 7b81162..2d0a090 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -34,7 +34,6 @@
  */
 public class PanProfile implements LocalBluetoothProfile {
     private static final String TAG = "PanProfile";
-    private static boolean V = true;
 
     private BluetoothPan mService;
     private boolean mIsProfileReady;
@@ -53,13 +52,11 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            if (V) Log.d(TAG,"Bluetooth service connected");
             mService = (BluetoothPan) proxy;
             mIsProfileReady=true;
         }
 
         public void onServiceDisconnected(int profile) {
-            if (V) Log.d(TAG,"Bluetooth service disconnected");
             mIsProfileReady=false;
         }
     }
@@ -173,7 +170,7 @@
     }
 
     protected void finalize() {
-        if (V) Log.d(TAG, "finalize()");
+        Log.d(TAG, "finalize()");
         if (mService != null) {
             try {
                 BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.PAN, mService);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index 1f15601..4672393 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -55,7 +55,6 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            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();
@@ -74,7 +73,6 @@
         }
 
         public void onServiceDisconnected(int profile) {
-            Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
             mIsProfileReady = false;
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index adef0841..1b3c453 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -33,7 +33,6 @@
  */
 public class PbapServerProfile implements LocalBluetoothProfile {
     private static final String TAG = "PbapServerProfile";
-    private static boolean V = true;
 
     private BluetoothPbap mService;
     private boolean mIsProfileReady;
@@ -56,13 +55,11 @@
             implements BluetoothPbap.ServiceListener {
 
         public void onServiceConnected(BluetoothPbap proxy) {
-            if (V) Log.d(TAG,"Bluetooth service connected");
             mService = (BluetoothPbap) proxy;
             mIsProfileReady=true;
         }
 
         public void onServiceDisconnected() {
-            if (V) Log.d(TAG,"Bluetooth service disconnected");
             mIsProfileReady=false;
         }
     }
@@ -142,7 +139,7 @@
     }
 
     protected void finalize() {
-        if (V) Log.d(TAG, "finalize()");
+        Log.d(TAG, "finalize()");
         if (mService != null) {
             try {
                 mService.close();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index b4acc48..ea2ebde 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -57,7 +57,6 @@
             implements BluetoothProfile.ServiceListener {
 
         public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            Log.d(TAG, "Bluetooth service connected, profile:" + profile);
             mService = (BluetoothSap) proxy;
             // We just bound to the service, so refresh the UI for any connected SAP devices.
             List<BluetoothDevice> deviceList = mService.getConnectedDevices();
@@ -79,7 +78,6 @@
         }
 
         public void onServiceDisconnected(int profile) {
-            Log.d(TAG, "Bluetooth service disconnected, profile:" + profile);
             mProfileManager.callServiceDisconnectedListeners();
             mIsProfileReady=false;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
index aed02a2..8090169 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
@@ -41,10 +41,6 @@
     private int mSourceMetricsCategory = MetricsProto.MetricsEvent.VIEW_UNKNOWN;
     private long mVisibleTimestamp;
 
-    private VisibilityLoggerMixin() {
-        mMetricsCategory = METRICS_CATEGORY_UNKNOWN;
-    }
-
     public VisibilityLoggerMixin(int metricsCategory, MetricsFeatureProvider metricsFeature) {
         mMetricsCategory = metricsCategory;
         mMetricsFeature = metricsFeature;
@@ -81,12 +77,4 @@
                 MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
                 MetricsProto.MetricsEvent.VIEW_UNKNOWN);
     }
-
-    /** Returns elapsed time since onResume() */
-    public long elapsedTimeSinceVisible() {
-        if (mVisibleTimestamp == 0) {
-            return 0;
-        }
-        return SystemClock.elapsedRealtime() - mVisibleTimestamp;
-    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index 12b8efb..4ab9a9a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -55,6 +55,12 @@
             "com.android.settings.category.ia.privacy";
     public static final String CATEGORY_ENTERPRISE_PRIVACY =
             "com.android.settings.category.ia.enterprise_privacy";
+    public static final String CATEGORY_ABOUT_LEGAL =
+            "com.android.settings.category.ia.about_legal";
+    public static final String CATEGORY_MY_DEVICE_INFO =
+            "com.android.settings.category.ia.my_device_info";
+    public static final String CATEGORY_BATTERY_SAVER_SETTINGS =
+            "com.android.settings.category.ia.battery_saver_settings";
 
     public static final Map<String, String> KEY_COMPAT_MAP;
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index 959f9b2..a5c6f0c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -54,17 +54,17 @@
     }
 
     @Override
-    public void connect() {
+    public boolean connect() {
         //TODO(b/117129183): add callback to notify LocalMediaManager connection state.
-        mIsConnected = mCachedDevice.setActive();
-        super.connect();
-        Log.d(TAG, "connect() device : " + getName() + ", is selected : " + mIsConnected);
+        final boolean isConnected = mCachedDevice.setActive();
+        setConnectedRecord();
+        Log.d(TAG, "connect() device : " + getName() + ", is selected : " + isConnected);
+        return isConnected;
     }
 
     @Override
     public void disconnect() {
         //TODO(b/117129183): disconnected last select device
-        mIsConnected = false;
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
index ab1cca0..fa2dd88 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
@@ -18,6 +18,7 @@
 import android.app.Notification;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.util.Log;
 
@@ -35,36 +36,48 @@
 /**
  * BluetoothMediaManager provide interface to get Bluetooth device list.
  */
-public class BluetoothMediaManager extends MediaManager implements BluetoothCallback {
+public class BluetoothMediaManager extends MediaManager implements BluetoothCallback,
+        LocalBluetoothProfileManager.ServiceListener {
 
     private static final String TAG = "BluetoothMediaManager";
 
-    private final DeviceAttributeChangeCallback mCachedDeviceCallback =
-            new DeviceAttributeChangeCallback();
-
     private LocalBluetoothManager mLocalBluetoothManager;
     private LocalBluetoothProfileManager mProfileManager;
+    private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager;
 
     private MediaDevice mLastAddedDevice;
     private MediaDevice mLastRemovedDevice;
 
+    private boolean mIsA2dpProfileReady = false;
+    private boolean mIsHearingAidProfileReady = false;
+
     BluetoothMediaManager(Context context, LocalBluetoothManager localBluetoothManager,
             Notification notification) {
         super(context, notification);
 
         mLocalBluetoothManager = localBluetoothManager;
         mProfileManager = mLocalBluetoothManager.getProfileManager();
+        mCachedBluetoothDeviceManager = mLocalBluetoothManager.getCachedDeviceManager();
     }
 
     @Override
     public void startScan() {
-        mMediaDevices.clear();
         mLocalBluetoothManager.getEventManager().registerCallback(this);
         buildBluetoothDeviceList();
         dispatchDeviceListAdded();
+
+        // The profile may not ready when calling startScan().
+        // Device status are all disconnected since profiles are not ready to connected.
+        // In this case, we observe onServiceConnected() in LocalBluetoothProfileManager.
+        // When A2dpProfile or HearingAidProfile is connected will call buildBluetoothDeviceList()
+        // again to find the connected devices.
+        if (!mIsA2dpProfileReady || !mIsHearingAidProfileReady) {
+            mProfileManager.addServiceListener(this);
+        }
     }
 
     private void buildBluetoothDeviceList() {
+        mMediaDevices.clear();
         addConnectedA2dpDevices();
         addConnectedHearingAidDevices();
     }
@@ -77,12 +90,10 @@
         }
 
         final List<BluetoothDevice> devices = a2dpProfile.getConnectedDevices();
-        final CachedBluetoothDeviceManager cachedBluetoothDeviceManager =
-                mLocalBluetoothManager.getCachedDeviceManager();
 
         for (BluetoothDevice device : devices) {
             final CachedBluetoothDevice cachedDevice =
-                    cachedBluetoothDeviceManager.findDevice(device);
+                    mCachedBluetoothDeviceManager.findDevice(device);
 
             if (cachedDevice == null) {
                 Log.w(TAG, "Can't found CachedBluetoothDevice : " + device.getName());
@@ -96,6 +107,8 @@
                 addMediaDevice(cachedDevice);
             }
         }
+
+        mIsA2dpProfileReady = a2dpProfile.isProfileReady();
     }
 
     private void addConnectedHearingAidDevices() {
@@ -107,12 +120,10 @@
 
         final List<Long> devicesHiSyncIds = new ArrayList<>();
         final List<BluetoothDevice> devices = hapProfile.getConnectedDevices();
-        final CachedBluetoothDeviceManager cachedBluetoothDeviceManager =
-                mLocalBluetoothManager.getCachedDeviceManager();
 
         for (BluetoothDevice device : devices) {
             final CachedBluetoothDevice cachedDevice =
-                    cachedBluetoothDeviceManager.findDevice(device);
+                    mCachedBluetoothDeviceManager.findDevice(device);
 
             if (cachedDevice == null) {
                 Log.w(TAG, "Can't found CachedBluetoothDevice : " + device.getName());
@@ -130,13 +141,14 @@
                 addMediaDevice(cachedDevice);
             }
         }
+
+        mIsHearingAidProfileReady = hapProfile.isProfileReady();
     }
 
     private void addMediaDevice(CachedBluetoothDevice cachedDevice) {
         MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice));
         if (mediaDevice == null) {
             mediaDevice = new BluetoothMediaDevice(mContext, cachedDevice);
-            cachedDevice.registerCallback(mCachedDeviceCallback);
             mLastAddedDevice = mediaDevice;
             mMediaDevices.add(mediaDevice);
         }
@@ -145,16 +157,6 @@
     @Override
     public void stopScan() {
         mLocalBluetoothManager.getEventManager().unregisterCallback(this);
-        unregisterCachedDeviceCallback();
-    }
-
-    private void unregisterCachedDeviceCallback() {
-        for (MediaDevice device : mMediaDevices) {
-            if (device instanceof BluetoothMediaDevice) {
-                ((BluetoothMediaDevice) device).getCachedDevice()
-                        .unregisterCallback(mCachedDeviceCallback);
-            }
-        }
     }
 
     @Override
@@ -166,8 +168,6 @@
             final List<MediaDevice> removeDevicesList = new ArrayList<>();
             for (MediaDevice device : mMediaDevices) {
                 if (device instanceof BluetoothMediaDevice) {
-                    ((BluetoothMediaDevice) device).getCachedDevice()
-                            .unregisterCallback(mCachedDeviceCallback);
                     removeDevicesList.add(device);
                 }
             }
@@ -212,7 +212,6 @@
     private void removeMediaDevice(CachedBluetoothDevice cachedDevice) {
         final MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice));
         if (mediaDevice != null) {
-            cachedDevice.unregisterCallback(mCachedDeviceCallback);
             mLastRemovedDevice = mediaDevice;
             mMediaDevices.remove(mediaDevice);
         }
@@ -252,10 +251,34 @@
             dispatchDeviceRemoved(cachedDevice);
         }
     }
-    class DeviceAttributeChangeCallback implements CachedBluetoothDevice.Callback {
-        @Override
-        public void onDeviceAttributesChanged() {
-            dispatchDeviceAttributesChanged();
+
+    @Override
+    public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
+        Log.d(TAG, "onActiveDeviceChanged : device : "
+                + activeDevice + ", profile : " + bluetoothProfile);
+        if (BluetoothProfile.HEARING_AID == bluetoothProfile
+                || BluetoothProfile.A2DP == bluetoothProfile) {
+            final String id = activeDevice == null
+                    ? PhoneMediaDevice.ID : MediaDeviceUtils.getId(activeDevice);
+            dispatchConnectedDeviceChanged(id);
         }
     }
+
+    @Override
+    public void onServiceConnected() {
+        if (!mIsA2dpProfileReady || !mIsHearingAidProfileReady) {
+            buildBluetoothDeviceList();
+            dispatchDeviceListAdded();
+        }
+
+        //Remove the listener once a2dpProfile and hearingAidProfile are ready.
+        if (mIsA2dpProfileReady && mIsHearingAidProfileReady) {
+            mProfileManager.removeServiceListener(this);
+        }
+    }
+
+    @Override
+    public void onServiceDisconnected() {
+
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index 21a81e0..04f70cc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -16,6 +16,7 @@
 package com.android.settingslib.media;
 
 import android.content.Context;
+import android.widget.Toast;
 
 import androidx.mediarouter.media.MediaRouter;
 
@@ -43,7 +44,7 @@
 
     @Override
     public int getIcon() {
-        //TODO(b/117129183): This is not final icon for cast device, just for demo.
+        //TODO(b/121083246): This is not final icon for cast device, just for demo.
         return R.drawable.ic_settings_print;
     }
 
@@ -53,15 +54,15 @@
     }
 
     @Override
-    public void connect() {
-        //TODO(b/117129183): use MediaController2 to transfer media
-        mIsConnected = true;
-        super.connect();
+    public boolean connect() {
+        //TODO(b/121083246): use SystemApi to transfer media
+        setConnectedRecord();
+        Toast.makeText(mContext, "This is cast device !", Toast.LENGTH_SHORT).show();
+        return false;
     }
 
     @Override
     public void disconnect() {
-        //TODO(b/117129183): disconnected last select device
-        mIsConnected = false;
+        //TODO(b/121083246): disconnected last select device
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 6907238..bc8e2c3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -22,6 +22,8 @@
 import androidx.mediarouter.media.MediaRouteSelector;
 import androidx.mediarouter.media.MediaRouter;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 /**
  * InfoMediaManager provide interface to get InfoMediaDevice list.
  */
@@ -29,9 +31,13 @@
 
     private static final String TAG = "InfoMediaManager";
 
-    private final MediaRouterCallback mMediaRouterCallback = new MediaRouterCallback();
+    @VisibleForTesting
+    final MediaRouterCallback mMediaRouterCallback = new MediaRouterCallback();
+    @VisibleForTesting
+    MediaRouteSelector mSelector;
+    @VisibleForTesting
+    MediaRouter mMediaRouter;
 
-    private MediaRouter mMediaRouter;
     private String mPackageName;
 
     InfoMediaManager(Context context, String packageName, Notification notification) {
@@ -39,24 +45,20 @@
 
         mMediaRouter = MediaRouter.getInstance(context);
         mPackageName = packageName;
+        mSelector = new MediaRouteSelector.Builder()
+                .addControlCategory(getControlCategoryByPackageName(mPackageName))
+                .build();
     }
 
     @Override
     public void startScan() {
         mMediaDevices.clear();
-        startScanCastDevice();
-    }
-
-    private void startScanCastDevice() {
-        final MediaRouteSelector selector = new MediaRouteSelector.Builder()
-                .addControlCategory(getControlCategoryByPackageName(mPackageName))
-                .build();
-
-        mMediaRouter.addCallback(selector, mMediaRouterCallback,
+        mMediaRouter.addCallback(mSelector, mMediaRouterCallback,
                 MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
     }
 
-    private String getControlCategoryByPackageName(String packageName) {
+    @VisibleForTesting
+    String getControlCategoryByPackageName(String packageName) {
         //TODO(b/117129183): Use package name to get ControlCategory.
         //Since api not ready, return fixed ControlCategory for prototype.
         return "com.google.android.gms.cast.CATEGORY_CAST/4F8B3483";
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index c9479d4..44d945a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -16,12 +16,15 @@
 package com.android.settingslib.media;
 
 import android.app.Notification;
+import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.util.Log;
 
 import androidx.annotation.IntDef;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 
 import java.lang.annotation.Retention;
@@ -50,16 +53,20 @@
     }
 
     private final Collection<DeviceCallback> mCallbacks = new ArrayList<>();
-    private final MediaDeviceCallback mMediaDeviceCallback = new MediaDeviceCallback();
+    @VisibleForTesting
+    final MediaDeviceCallback mMediaDeviceCallback = new MediaDeviceCallback();
 
     private Context mContext;
-    private List<MediaDevice> mMediaDevices = new ArrayList<>();
     private BluetoothMediaManager mBluetoothMediaManager;
     private InfoMediaManager mInfoMediaManager;
-
     private LocalBluetoothManager mLocalBluetoothManager;
-    private MediaDevice mLastConnectedDevice;
-    private MediaDevice mPhoneDevice;
+
+    @VisibleForTesting
+    List<MediaDevice> mMediaDevices = new ArrayList<>();
+    @VisibleForTesting
+    MediaDevice mPhoneDevice;
+    @VisibleForTesting
+    MediaDevice mCurrentConnectedDevice;
 
     /**
      * Register to start receiving callbacks for MediaDevice events.
@@ -93,28 +100,40 @@
         mInfoMediaManager = new InfoMediaManager(context, packageName, notification);
     }
 
+    @VisibleForTesting
+    LocalMediaManager(Context context, LocalBluetoothManager localBluetoothManager,
+            BluetoothMediaManager bluetoothMediaManager, InfoMediaManager infoMediaManager) {
+        mContext = context;
+        mLocalBluetoothManager = localBluetoothManager;
+        mBluetoothMediaManager = bluetoothMediaManager;
+        mInfoMediaManager = infoMediaManager;
+    }
+
     /**
      * Connect the MediaDevice to transfer media
      * @param connectDevice the MediaDevice
      */
     public void connectDevice(MediaDevice connectDevice) {
-        if (connectDevice == mLastConnectedDevice) {
+        final MediaDevice device = getMediaDeviceById(mMediaDevices, connectDevice.getId());
+        if (device == mCurrentConnectedDevice) {
+            Log.d(TAG, "connectDevice() this device all ready connected! : " + device.getName());
             return;
         }
 
-        if (mLastConnectedDevice != null) {
-            mLastConnectedDevice.disconnect();
+        //TODO(b/121083246): Update it once remote media API is ready.
+        if (mCurrentConnectedDevice != null && !(connectDevice instanceof InfoMediaDevice)) {
+            mCurrentConnectedDevice.disconnect();
         }
 
-        connectDevice.connect();
-        if (connectDevice.isConnected()) {
-            mLastConnectedDevice = connectDevice;
+        final boolean isConnected = device.connect();
+        if (isConnected) {
+            mCurrentConnectedDevice = device;
         }
 
-        final int state = connectDevice.isConnected()
+        final int state = isConnected
                 ? MediaDeviceState.STATE_CONNECTED
                 : MediaDeviceState.STATE_DISCONNECTED;
-        dispatchSelectedDeviceStateChanged(connectDevice, state);
+        dispatchSelectedDeviceStateChanged(device, state);
     }
 
     void dispatchSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state) {
@@ -189,6 +208,31 @@
         return null;
     }
 
+    /**
+     * Find the current connected MediaDevice.
+     *
+     * @return MediaDevice
+     */
+    public MediaDevice getCurrentConnectedDevice() {
+        return mCurrentConnectedDevice;
+    }
+
+    private MediaDevice updateCurrentConnectedDevice() {
+        for (MediaDevice device : mMediaDevices) {
+            if (device instanceof  BluetoothMediaDevice) {
+                if (isConnected(((BluetoothMediaDevice) device).getCachedDevice())) {
+                    return device;
+                }
+            }
+        }
+        return mMediaDevices.contains(mPhoneDevice) ? mPhoneDevice : null;
+    }
+
+    private boolean isConnected(CachedBluetoothDevice device) {
+        return device.isActiveDevice(BluetoothProfile.A2DP)
+                || device.isActiveDevice(BluetoothProfile.HEARING_AID);
+    }
+
     class MediaDeviceCallback implements MediaManager.MediaDeviceCallback {
         @Override
         public void onDeviceAdded(MediaDevice device) {
@@ -201,8 +245,13 @@
 
         @Override
         public void onDeviceListAdded(List<MediaDevice> devices) {
-            mMediaDevices.addAll(devices);
+            for (MediaDevice device : devices) {
+                if (getMediaDeviceById(mMediaDevices, device.getId()) == null) {
+                    mMediaDevices.add(device);
+                }
+            }
             addPhoneDeviceIfNecessary();
+            mCurrentConnectedDevice = updateCurrentConnectedDevice();
             dispatchDeviceListUpdate();
         }
 
@@ -226,6 +275,20 @@
         public void onDeviceAttributesChanged() {
             dispatchDeviceListUpdate();
         }
+
+        @Override
+        public void onConnectedDeviceChanged(String id) {
+            final MediaDevice connectDevice = getMediaDeviceById(mMediaDevices, id);
+
+            if (connectDevice == mCurrentConnectedDevice) {
+                Log.d(TAG, "onConnectedDeviceChanged() this device all ready connected! : "
+                        + connectDevice.getName());
+                return;
+            }
+            mCurrentConnectedDevice = connectDevice;
+
+            dispatchDeviceListUpdate();
+        }
     }
 
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 33b621c..f35c30e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -41,7 +41,6 @@
 
     private int mConnectedRecord;
 
-    protected boolean mIsConnected = false;
     protected Context mContext;
     protected int mType;
 
@@ -57,15 +56,6 @@
     }
 
     /**
-     * Check the MediaDevice is be connected to transfer.
-     *
-     * @return true if the MediaDevice is be connected to transfer, false otherwise.
-     */
-    public boolean isConnected() {
-        return mIsConnected;
-    }
-
-    /**
      * Get name from MediaDevice.
      *
      * @return name of MediaDevice.
@@ -87,8 +77,12 @@
 
     /**
      * Transfer MediaDevice for media
+     *
+     * @return result of transfer media
      */
-    public void connect() {
+    public abstract boolean connect();
+
+    void setConnectedRecord() {
         mConnectedRecord++;
         ConnectionRecordManager.getInstance().setConnectionRecord(mContext, getId(),
                 mConnectedRecord);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
index 72b6b09..2c3a96c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
@@ -96,7 +96,7 @@
     protected void dispatchDeviceListAdded() {
         synchronized (mCallbacks) {
             for (MediaDeviceCallback callback : mCallbacks) {
-                callback.onDeviceListAdded(mMediaDevices);
+                callback.onDeviceListAdded(new ArrayList<>(mMediaDevices));
             }
         }
     }
@@ -109,10 +109,10 @@
         }
     }
 
-    protected void dispatchDeviceAttributesChanged() {
+    protected void dispatchConnectedDeviceChanged(String id) {
         synchronized (mCallbacks) {
             for (MediaDeviceCallback callback : mCallbacks) {
-                callback.onDeviceAttributesChanged();
+                callback.onConnectedDeviceChanged(id);
             }
         }
     }
@@ -153,5 +153,12 @@
          * Callback for notifying MediaDevice attributes is changed.
          */
         void onDeviceAttributesChanged();
+
+        /**
+         * Callback for notifying connected MediaDevice is changed.
+         *
+         * @param id the id of MediaDevice
+         */
+        void onConnectedDeviceChanged(String id);
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
new file mode 100644
index 0000000..e600cb8
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.media;
+
+/**
+ * Class to access MediaOutput constants.
+ */
+public class MediaOutputSliceConstants {
+
+    /**
+     * Key for the Media output setting.
+     */
+    public static final String KEY_MEDIA_OUTPUT = "media_output";
+
+    /**
+     * Activity Action: Show a settings dialog containing {@link MediaDevice} to transfer media.
+     */
+    public static final String ACTION_MEDIA_OUTPUT =
+            "com.android.settings.panel.action.MEDIA_OUTPUT";
+
+    /**
+     * An string extra specifying a media package name.
+     */
+    public static final String EXTRA_PACKAGE_NAME =
+            "com.android.settings.panel.extra.PACKAGE_NAME";
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index e0f3c2f..c808214 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -62,20 +62,22 @@
     }
 
     @Override
-    public void connect() {
+    public boolean connect() {
         final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
         final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
 
+        boolean isConnected = false;
+
         if (hapProfile != null && a2dpProfile != null) {
-            mIsConnected = hapProfile.setActiveDevice(null) && a2dpProfile.setActiveDevice(null);
-            super.connect();
+            isConnected = hapProfile.setActiveDevice(null) && a2dpProfile.setActiveDevice(null);
+            setConnectedRecord();
         }
-        Log.d(TAG, "connect() device : " + getName() + ", is selected : " + mIsConnected);
+        Log.d(TAG, "connect() device : " + getName() + ", is selected : " + isConnected);
+        return isConnected;
     }
 
     @Override
     public void disconnect() {
         //TODO(b/117129183): disconnected last select device
-        mIsConnected = false;
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
index 180b77e..8cb252e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -66,6 +66,7 @@
     private INetworkStatsSession mSession;
     private Callback mCallback;
     private NetworkNameProvider mNetworkController;
+    private int mSubscriptionId;
 
     public DataUsageController(Context context) {
         mContext = context;
@@ -75,6 +76,7 @@
                 ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
         mPolicyManager = NetworkPolicyManager.from(mContext);
         mNetworkStatsManager = context.getSystemService(NetworkStatsManager.class);
+        mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     }
 
     public void setNetworkController(NetworkNameProvider networkController) {
@@ -82,6 +84,15 @@
     }
 
     /**
+     * By default this class will just get data usage information for the default data subscription,
+     * but this method can be called to require it to use an explicit subscription id which may be
+     * different from the default one (this is useful for the case of multi-SIM devices).
+     */
+    public void setSubscriptionId(int subscriptionId) {
+        mSubscriptionId = subscriptionId;
+    }
+
+    /**
      * Returns the default warning level in bytes.
      */
     public long getDefaultWarningLevel() {
@@ -99,7 +110,7 @@
     }
 
     public DataUsageInfo getDataUsageInfo() {
-        final String subscriberId = getActiveSubscriberId(mContext);
+        final String subscriberId = getActiveSubscriberId();
         if (subscriberId == null) {
             return warn("no subscriber id");
         }
@@ -164,7 +175,8 @@
     private long getUsageLevel(NetworkTemplate template, long start, long end) {
         try {
             final Bucket bucket = mNetworkStatsManager.querySummaryForDevice(
-                getNetworkType(template), getActiveSubscriberId(mContext), start, end);
+                    getNetworkType(template), getActiveSubscriberId(),
+                    start, end);
             if (bucket != null) {
                 return bucket.getRxBytes() + bucket.getTxBytes();
             }
@@ -237,10 +249,13 @@
         }
     }
 
-    private static String getActiveSubscriberId(Context context) {
-        final TelephonyManager tele = TelephonyManager.from(context);
-        final String actualSubscriberId = tele.getSubscriberId(
-                SubscriptionManager.getDefaultDataSubscriptionId());
+    private String getActiveSubscriberId() {
+        final TelephonyManager tele = TelephonyManager.from(mContext);
+        int subscriptionId = mSubscriptionId;
+        if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            subscriptionId = SubscriptionManager.getDefaultDataSubscriptionId();
+        }
+        final String actualSubscriberId = tele.getSubscriberId(subscriptionId);
         return actualSubscriberId;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 4f81daf..9b12a31 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -41,7 +41,9 @@
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkScoreCache;
+import android.net.wifi.hotspot2.OsuProvider;
 import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.net.wifi.hotspot2.ProvisioningCallback;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.RemoteException;
@@ -182,6 +184,10 @@
 
     public static final int UNREACHABLE_RSSI = Integer.MIN_VALUE;
 
+    public static final String KEY_PREFIX_AP = "AP:";
+    public static final String KEY_PREFIX_FQDN = "FQDN:";
+    public static final String KEY_PREFIX_OSU = "OSU:";
+
     private final Context mContext;
 
     private String ssid;
@@ -204,9 +210,6 @@
     @Speed private int mSpeed = Speed.NONE;
     private boolean mIsScoredNetworkMetered = false;
 
-    // used to co-relate internal vs returned accesspoint.
-    int mId;
-
     /**
      * Information associated with the {@link PasspointConfiguration}.  Only maintaining
      * the relevant info to preserve spaces.
@@ -215,6 +218,13 @@
     private String mProviderFriendlyName;
 
     private boolean mIsCarrierAp = false;
+
+    private OsuProvider mOsuProvider;
+
+    private String mOsuStatus;
+    private String mOsuFailure;
+    private boolean mOsuProvisioningComplete = false;
+
     /**
      * The EAP type {@link WifiEnterpriseConfig.Eap} associated with this AP if it is a carrier AP.
      */
@@ -280,14 +290,18 @@
         // Calculate required fields
         updateKey();
         updateRssi();
-
-        mId = sLastId.incrementAndGet();
     }
 
+    /**
+     * Creates an AccessPoint with only a WifiConfiguration. This is used for the saved networks
+     * page.
+     *
+     * Passpoint Credential AccessPoints should be created with this.
+     * Make sure to call setScanResults after constructing with this.
+     */
     public AccessPoint(Context context, WifiConfiguration config) {
         mContext = context;
         loadConfig(config);
-        mId = sLastId.incrementAndGet();
     }
 
     /**
@@ -298,7 +312,17 @@
         mContext = context;
         mFqdn = config.getHomeSp().getFqdn();
         mProviderFriendlyName = config.getHomeSp().getFriendlyName();
-        mId = sLastId.incrementAndGet();
+    }
+
+    /**
+     * Initialize an AccessPoint object for a Passpoint OSU Provider.
+     * Make sure to call setScanResults after constructing with this.
+     */
+    public AccessPoint(Context context, OsuProvider provider) {
+        mContext = context;
+        mOsuProvider = provider;
+        ssid = provider.getFriendlyName();
+        updateKey();
     }
 
     AccessPoint(Context context, Collection<ScanResult> results) {
@@ -324,33 +348,27 @@
         mIsCarrierAp = firstResult.isCarrierAp;
         mCarrierApEapType = firstResult.carrierApEapType;
         mCarrierName = firstResult.carrierName;
-
-        mId = sLastId.incrementAndGet();
     }
 
     @VisibleForTesting void loadConfig(WifiConfiguration config) {
         ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
         bssid = config.BSSID;
         security = getSecurity(config);
-        updateKey();
         networkId = config.networkId;
         mConfig = config;
+        updateKey();
     }
 
     /** Updates {@link #mKey} and should only called upon object creation/initialization. */
     private void updateKey() {
         // TODO(sghuman): Consolidate Key logic on ScanResultMatchInfo
-
-        StringBuilder builder = new StringBuilder();
-
-        if (TextUtils.isEmpty(getSsidStr())) {
-            builder.append(getBssid());
-        } else {
-            builder.append(getSsidStr());
+        if (isPasspoint()) {
+            mKey = getKey(mConfig);
+        } else if (isOsuProvider()) {
+            mKey = getKey(mOsuProvider);
+        } else { // Non-Passpoint AP
+            mKey = getKey(getSsidStr(), getBssid(), getSecurity());
         }
-
-        builder.append(',').append(getSecurity());
-        mKey = builder.toString();
     }
 
     /**
@@ -394,8 +412,8 @@
             return difference;
         }
 
-        // Sort by ssid.
-        difference = getSsidStr().compareToIgnoreCase(other.getSsidStr());
+        // Sort by title.
+        difference = getTitle().compareToIgnoreCase(other.getTitle());
         if (difference != 0) {
             return difference;
         }
@@ -591,28 +609,46 @@
     }
 
     public static String getKey(ScanResult result) {
-        StringBuilder builder = new StringBuilder();
-
-        if (TextUtils.isEmpty(result.SSID)) {
-            builder.append(result.BSSID);
-        } else {
-            builder.append(result.SSID);
-        }
-
-        builder.append(',').append(getSecurity(result));
-        return builder.toString();
+        return getKey(result.SSID, result.BSSID, getSecurity(result));
     }
 
+    /**
+     * Returns the AccessPoint key for a WifiConfiguration.
+     * This will return a special Passpoint key if the config is for Passpoint.
+     */
     public static String getKey(WifiConfiguration config) {
-        StringBuilder builder = new StringBuilder();
-
-        if (TextUtils.isEmpty(config.SSID)) {
-            builder.append(config.BSSID);
+        if (config.isPasspoint()) {
+            return new StringBuilder()
+                    .append(KEY_PREFIX_FQDN)
+                    .append(config.FQDN).toString();
         } else {
-            builder.append(removeDoubleQuotes(config.SSID));
+            return getKey(removeDoubleQuotes(config.SSID), config.BSSID, getSecurity(config));
         }
+    }
 
-        builder.append(',').append(getSecurity(config));
+    /**
+     * Returns the AccessPoint key corresponding to the OsuProvider.
+     */
+    public static String getKey(OsuProvider provider) {
+        return new StringBuilder()
+                .append(KEY_PREFIX_OSU)
+                .append(provider.getFriendlyName())
+                .append(',')
+                .append(provider.getServerUri()).toString();
+    }
+
+    /**
+     * Returns the AccessPoint key for a normal non-Passpoint network by ssid/bssid and security.
+     */
+    private static String getKey(String ssid, String bssid, int security) {
+        StringBuilder builder = new StringBuilder();
+        builder.append(KEY_PREFIX_AP);
+        if (TextUtils.isEmpty(ssid)) {
+            builder.append(bssid);
+        } else {
+            builder.append(ssid);
+        }
+        builder.append(',').append(security);
         return builder.toString();
     }
 
@@ -621,9 +657,10 @@
     }
 
     public boolean matches(WifiConfiguration config) {
-        if (config.isPasspoint() && mConfig != null && mConfig.isPasspoint()) {
-            return ssid.equals(removeDoubleQuotes(config.SSID)) && config.FQDN.equals(mConfig.FQDN);
+        if (config.isPasspoint()) {
+            return (isPasspoint() && config.FQDN.equals(mConfig.FQDN));
         } else {
+            // Normal non-Passpoint network
             return ssid.equals(removeDoubleQuotes(config.SSID))
                     && security == getSecurity(config)
                     && (mConfig == null || mConfig.shared == config.shared);
@@ -828,86 +865,111 @@
         return "";
     }
 
+    /**
+     * Returns the display title for the AccessPoint, such as for an AccessPointPreference's title.
+     */
+    public String getTitle() {
+        if (isPasspoint()) {
+            return mConfig.providerFriendlyName;
+        } else if (isOsuProvider()) {
+            return mOsuProvider.getFriendlyName();
+        } else {
+            return getSsidStr();
+        }
+    }
+
     public String getSummary() {
-        return getSettingsSummary(mConfig);
+        return getSettingsSummary();
     }
 
     public String getSettingsSummary() {
-        return getSettingsSummary(mConfig);
-    }
-
-    private String getSettingsSummary(WifiConfiguration config) {
         // Update to new summary
         StringBuilder summary = new StringBuilder();
 
-        if (isActive() && config != null && config.isPasspoint()) {
-            // This is the active connection on passpoint
-            summary.append(getSummary(mContext, getDetailedState(),
-                    false, config.providerFriendlyName));
-        } else if (isActive() && config != null && getDetailedState() == DetailedState.CONNECTED
-                && mIsCarrierAp) {
-            summary.append(String.format(mContext.getString(R.string.connected_via_carrier), mCarrierName));
-        } else if (isActive()) {
-            // This is the active connection on non-passpoint network
-            summary.append(getSummary(mContext, getDetailedState(),
-                    mInfo != null && mInfo.isEphemeral()));
-        } else if (config != null && config.isPasspoint()
-                && config.getNetworkSelectionStatus().isNetworkEnabled()) {
-            String format = mContext.getString(R.string.available_via_passpoint);
-            summary.append(String.format(format, config.providerFriendlyName));
-        } else if (config != null && config.hasNoInternetAccess()) {
-            int messageID = config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()
-                    ? R.string.wifi_no_internet_no_reconnect
-                    : R.string.wifi_no_internet;
-            summary.append(mContext.getString(messageID));
-        } else if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) {
-            WifiConfiguration.NetworkSelectionStatus networkStatus =
-                    config.getNetworkSelectionStatus();
-            switch (networkStatus.getNetworkSelectionDisableReason()) {
-                case WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE:
-                    summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
-                    break;
-                case WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD:
-                    summary.append(mContext.getString(R.string.wifi_check_password_try_again));
-                    break;
-                case WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE:
-                case WifiConfiguration.NetworkSelectionStatus.DISABLED_DNS_FAILURE:
-                    summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
-                    break;
-                case WifiConfiguration.NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION:
-                    summary.append(mContext.getString(R.string.wifi_disabled_generic));
-                    break;
+        if (isOsuProvider()) {
+            if (mOsuProvisioningComplete) {
+                summary.append(mContext.getString(R.string.osu_provisioning_complete));
+            } else if (mOsuFailure != null) {
+                summary.append(mOsuFailure);
+            } else if (mOsuStatus != null) {
+                summary.append(mOsuStatus);
+            } else {
+                summary.append(mContext.getString(R.string.tap_to_set_up));
             }
-        } else if (config != null && config.getNetworkSelectionStatus().isNotRecommended()) {
-            summary.append(mContext.getString(R.string.wifi_disabled_by_recommendation_provider));
-        } else if (mIsCarrierAp) {
-            summary.append(String.format(mContext.getString(R.string.available_via_carrier), mCarrierName));
-        } else if (!isReachable()) { // Wifi out of range
-            summary.append(mContext.getString(R.string.wifi_not_in_range));
-        } else { // In range, not disabled.
-            if (config != null) { // Is saved network
-                // Last attempt to connect to this failed. Show reason why
-                switch (config.recentFailure.getAssociationStatus()) {
-                    case WifiConfiguration.RecentFailure.STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
-                        summary.append(mContext.getString(
-                                R.string.wifi_ap_unable_to_handle_new_sta));
+        } else if (isActive()) {
+            if (isPasspoint()) {
+                // This is the active connection on passpoint
+                summary.append(getSummary(mContext, ssid, getDetailedState(),
+                        false, mConfig.providerFriendlyName));
+            } else if (mConfig != null && getDetailedState() == DetailedState.CONNECTED
+                    && mIsCarrierAp) {
+                // This is the active connection on a carrier AP
+                summary.append(String.format(mContext.getString(R.string.connected_via_carrier),
+                        mCarrierName));
+            } else {
+                // This is the active connection on non-passpoint network
+                summary.append(getSummary(mContext, getDetailedState(),
+                        mInfo != null && mInfo.isEphemeral()));
+            }
+        } else { // not active
+            if (mConfig != null && mConfig.hasNoInternetAccess()) {
+                int messageID = mConfig.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()
+                        ? R.string.wifi_no_internet_no_reconnect
+                        : R.string.wifi_no_internet;
+                summary.append(mContext.getString(messageID));
+            } else if (mConfig != null && !mConfig.getNetworkSelectionStatus().isNetworkEnabled()) {
+                WifiConfiguration.NetworkSelectionStatus networkStatus =
+                        mConfig.getNetworkSelectionStatus();
+                switch (networkStatus.getNetworkSelectionDisableReason()) {
+                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE:
+                        summary.append(mContext.getString(R.string.wifi_disabled_password_failure));
                         break;
-                    default:
-                        // "Saved"
-                        summary.append(mContext.getString(R.string.wifi_remembered));
+                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD:
+                        summary.append(mContext.getString(R.string.wifi_check_password_try_again));
                         break;
+                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE:
+                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_DNS_FAILURE:
+                        summary.append(mContext.getString(R.string.wifi_disabled_network_failure));
+                        break;
+                    case WifiConfiguration.NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION:
+                        summary.append(mContext.getString(R.string.wifi_disabled_generic));
+                        break;
+                }
+            } else if (mConfig != null && mConfig.getNetworkSelectionStatus().isNotRecommended()) {
+                summary.append(mContext.getString(
+                        R.string.wifi_disabled_by_recommendation_provider));
+            } else if (mIsCarrierAp) {
+                summary.append(String.format(mContext.getString(
+                        R.string.available_via_carrier), mCarrierName));
+            } else if (!isReachable()) { // Wifi out of range
+                summary.append(mContext.getString(R.string.wifi_not_in_range));
+            } else { // In range, not disabled.
+                if (mConfig != null) { // Is saved network
+                    // Last attempt to connect to this failed. Show reason why
+                    switch (mConfig.recentFailure.getAssociationStatus()) {
+                        case WifiConfiguration.RecentFailure.STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
+                            summary.append(mContext.getString(
+                                    R.string.wifi_ap_unable_to_handle_new_sta));
+                            break;
+                        default:
+                            // "Saved"
+                            summary.append(mContext.getString(R.string.wifi_remembered));
+                            break;
+                    }
                 }
             }
         }
 
+
+
         if (isVerboseLoggingEnabled()) {
-            summary.append(WifiUtils.buildLoggingSummary(this, config));
+            summary.append(WifiUtils.buildLoggingSummary(this, mConfig));
         }
 
-        if (config != null && (WifiUtils.isMeteredOverridden(config) || config.meteredHint)) {
+        if (mConfig != null && (WifiUtils.isMeteredOverridden(mConfig) || mConfig.meteredHint)) {
             return mContext.getResources().getString(
                     R.string.preference_summary_default_combination,
-                    WifiUtils.getMeteredLabel(mContext, config),
+                    WifiUtils.getMeteredLabel(mContext, mConfig),
                     summary.toString());
         }
 
@@ -960,11 +1022,33 @@
     }
 
     /**
+     * Return true if this AccessPoint represents an OSU Provider.
+     */
+    public boolean isOsuProvider() {
+        return mOsuProvider != null;
+    }
+
+    /**
+     * Starts the OSU Provisioning flow.
+     */
+    public void startOsuProvisioning() {
+        mContext.getSystemService(WifiManager.class).startSubscriptionProvisioning(
+                mOsuProvider,
+                new AccessPointProvisioningCallback(),
+                ThreadUtils.getUiThreadHandler()
+        );
+    }
+
+    /**
      * Return whether the given {@link WifiInfo} is for this access point.
      * If the current AP does not have a network Id then the config is used to
      * match based on SSID and security.
      */
     private boolean isInfoForThisAccessPoint(WifiConfiguration config, WifiInfo info) {
+        if (info.isOsuAp()) {
+            return (mOsuStatus != null);
+        }
+
         if (isPasspoint() == false && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
             return networkId == info.getNetworkId();
         } else if (config != null) {
@@ -1048,18 +1132,21 @@
      */
     void setScanResults(Collection<ScanResult> scanResults) {
 
-        // Validate scan results are for current AP only
-        String key = getKey();
-        for (ScanResult result : scanResults) {
-            String scanResultKey = AccessPoint.getKey(result);
-            if (!mKey.equals(scanResultKey)) {
-                throw new IllegalArgumentException(
-                        String.format("ScanResult %s\nkey of %s did not match current AP key %s",
-                                      result, scanResultKey, key));
+        // Validate scan results are for current AP only by matching SSID/BSSID
+        // Passpoint networks are not bound to a specific SSID/BSSID, so skip this for passpoint.
+        if (!isPasspoint() && !isOsuProvider()) {
+            String key = getKey();
+            for (ScanResult result : scanResults) {
+                String scanResultKey = AccessPoint.getKey(result);
+                if (!mKey.equals(scanResultKey)) {
+                    throw new IllegalArgumentException(
+                            String.format(
+                                    "ScanResult %s\nkey of %s did not match current AP key %s",
+                                    result, scanResultKey, key));
+                }
             }
         }
 
-
         int oldLevel = getLevel();
         mScanResults.clear();
         mScanResults.addAll(scanResults);
@@ -1100,7 +1187,17 @@
         }
     }
 
-    /** Attempt to update the AccessPoint and return true if an update occurred. */
+    /**
+     * Attempt to update the AccessPoint with the current connection info.
+     * This is used to set an AccessPoint to the active one if the connection info matches, or
+     * conversely to set an AccessPoint to inactive if the connection info does not match. The RSSI
+     * is also updated upon a match. Listeners will be notified if an update occurred.
+     *
+     * This is called in {@link WifiTracker#updateAccessPoints} as well as in callbacks for handling
+     * NETWORK_STATE_CHANGED_ACTION, RSSI_CHANGED_ACTION, and onCapabilitiesChanged in WifiTracker.
+     *
+     * Returns true if an update occurred.
+     */
     public boolean update(
             @Nullable WifiConfiguration config, WifiInfo info, NetworkInfo networkInfo) {
 
@@ -1149,6 +1246,9 @@
 
     void update(@Nullable WifiConfiguration config) {
         mConfig = config;
+        if (mConfig != null) {
+            ssid = removeDoubleQuotes(mConfig.SSID);
+        }
         networkId = config != null ? config.networkId : WifiConfiguration.INVALID_NETWORK_ID;
         ThreadUtils.postOnMainThread(() -> {
             if (mAccessPointListener != null) {
@@ -1224,11 +1324,11 @@
 
     public static String getSummary(Context context, String ssid, DetailedState state,
             boolean isEphemeral, String passpointProvider) {
-        if (state == DetailedState.CONNECTED && ssid == null) {
-            if (TextUtils.isEmpty(passpointProvider) == false) {
+        if (state == DetailedState.CONNECTED) {
+            if (!TextUtils.isEmpty(passpointProvider)) {
                 // Special case for connected + passpoint networks.
-                String format = context.getString(R.string.connected_via_passpoint);
-                return String.format(format, passpointProvider);
+                String format = context.getString(R.string.ssid_by_passpoint_provider);
+                return String.format(format, ssid, passpointProvider);
             } else if (isEphemeral) {
                 // Special case for connected + ephemeral networks.
                 final NetworkScoreManager networkScoreManager = context.getSystemService(
@@ -1421,4 +1521,166 @@
     private static boolean isVerboseLoggingEnabled() {
         return WifiTracker.sVerboseLogging || Log.isLoggable(TAG, Log.VERBOSE);
     }
+
+    /**
+     * Callbacks relaying changes to the OSU provisioning status started in startOsuProvisioning().
+     *
+     * All methods are invoked on the Main Thread
+     */
+    private class AccessPointProvisioningCallback extends ProvisioningCallback {
+        // TODO: Remove logs and implement summary changing logic for these provisioning callbacks.
+        @Override
+        @MainThread public void onProvisioningFailure(int status) {
+            switch (status) {
+                case OSU_FAILURE_AP_CONNECTION:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_ap_connection);
+                    break;
+                case OSU_FAILURE_SERVER_URL_INVALID:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_server_url_invalid);
+                    break;
+                case OSU_FAILURE_SERVER_CONNECTION:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_server_connection);
+                    break;
+                case OSU_FAILURE_SERVER_VALIDATION:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_server_validation);
+                    break;
+                case OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_service_provider_verification);
+                    break;
+                case OSU_FAILURE_PROVISIONING_ABORTED:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_provisioning_aborted);
+                    break;
+                case OSU_FAILURE_PROVISIONING_NOT_AVAILABLE:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_provisioning_not_available);
+                    break;
+                case OSU_FAILURE_INVALID_URL_FORMAT_FOR_OSU:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_invalid_server_url);
+                    break;
+                case OSU_FAILURE_UNEXPECTED_COMMAND_TYPE:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_unexpected_command_type);
+                    break;
+                case OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_unexpected_soap_message_type);
+                    break;
+                case OSU_FAILURE_SOAP_MESSAGE_EXCHANGE:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_soap_message_exchange);
+                    break;
+                case OSU_FAILURE_START_REDIRECT_LISTENER:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_start_redirect_listener);
+                    break;
+                case OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_timed_out_redirect_listener);
+                    break;
+                case OSU_FAILURE_NO_OSU_ACTIVITY_FOUND:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_no_osu_activity_found);
+                    break;
+                case OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_unexpected_soap_message_status);
+                    break;
+                case OSU_FAILURE_NO_PPS_MO:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_no_pps_mo);
+                    break;
+                case OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_no_aaa_server_trust_root_node);
+                    break;
+                case OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_no_remediation_server_trust_root_node);
+                    break;
+                case OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_no_policy_server_trust_root_node);
+                    break;
+                case OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_retrieve_trust_root_certificates);
+                    break;
+                case OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_no_aaa_trust_root_certificate);
+                    break;
+                case OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION:
+                    mOsuFailure = mContext.getString(
+                            R.string.osu_failure_add_passpoint_configuration);
+                    break;
+                case OSU_FAILURE_OSU_PROVIDER_NOT_FOUND:
+                    mOsuFailure = mContext.getString(R.string.osu_failure_osu_provider_not_found);
+                    break;
+            }
+            mOsuStatus = null;
+            mOsuProvisioningComplete = false;
+            ThreadUtils.postOnMainThread(() -> {
+                if (mAccessPointListener != null) {
+                    mAccessPointListener.onAccessPointChanged(AccessPoint.this);
+                }
+            });
+        }
+
+        @Override
+        @MainThread public void onProvisioningStatus(int status) {
+            switch (status) {
+                case OSU_STATUS_AP_CONNECTING:
+                    mOsuStatus = mContext.getString(R.string.osu_status_ap_connecting);
+                    break;
+                case OSU_STATUS_AP_CONNECTED:
+                    mOsuStatus = mContext.getString(R.string.osu_status_ap_connected);
+                    break;
+                case OSU_STATUS_SERVER_CONNECTING:
+                    mOsuStatus = mContext.getString(R.string.osu_status_server_connecting);
+                    break;
+                case OSU_STATUS_SERVER_VALIDATED:
+                    mOsuStatus = mContext.getString(R.string.osu_status_server_validated);
+                    break;
+                case OSU_STATUS_SERVER_CONNECTED:
+                    mOsuStatus = mContext.getString(R.string.osu_status_server_connected);
+                    break;
+                case OSU_STATUS_INIT_SOAP_EXCHANGE:
+                    mOsuStatus = mContext.getString(R.string.osu_status_init_soap_exchange);
+                    break;
+                case OSU_STATUS_WAITING_FOR_REDIRECT_RESPONSE:
+                    mOsuStatus = mContext.getString(
+                            R.string.osu_status_waiting_for_redirect_response);
+                    break;
+                case OSU_STATUS_REDIRECT_RESPONSE_RECEIVED:
+                    mOsuStatus = mContext.getString(R.string.osu_status_redirect_response_received);
+                    break;
+                case OSU_STATUS_SECOND_SOAP_EXCHANGE:
+                    mOsuStatus = mContext.getString(R.string.osu_status_second_soap_exchange);
+                    break;
+                case OSU_STATUS_THIRD_SOAP_EXCHANGE:
+                    mOsuStatus = mContext.getString(R.string.osu_status_third_soap_exchange);
+                    break;
+                case OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS:
+                    mOsuStatus = mContext.getString(
+                            R.string.osu_status_retrieving_trust_root_certs);
+                    break;
+            }
+            mOsuFailure = null;
+            mOsuProvisioningComplete = false;
+            ThreadUtils.postOnMainThread(() -> {
+                if (mAccessPointListener != null) {
+                    mAccessPointListener.onAccessPointChanged(AccessPoint.this);
+                }
+            });
+        }
+
+        @Override
+        @MainThread public void onProvisioningComplete() {
+            mOsuProvisioningComplete = true;
+            mOsuFailure = null;
+            mOsuStatus = null;
+            ThreadUtils.postOnMainThread(() -> {
+                if (mAccessPointListener != null) {
+                    mAccessPointListener.onAccessPointChanged(AccessPoint.this);
+                }
+            });
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index db364a3..1fa7083 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -266,7 +266,7 @@
         if (savedNetworks) {
             preference.setTitle(ap.getConfigName());
         } else {
-            preference.setTitle(ap.getSsidStr());
+            preference.setTitle(ap.getTitle());
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index e47ca32..b9a5f23 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -35,6 +35,7 @@
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkScoreCache;
 import android.net.wifi.WifiNetworkScoreCache.CacheListener;
+import android.net.wifi.hotspot2.OsuProvider;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
@@ -45,6 +46,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Pair;
 import android.widget.Toast;
 
 import androidx.annotation.GuardedBy;
@@ -66,6 +68,7 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -573,9 +576,72 @@
                 accessPoints.add(accessPoint);
             }
 
+            List<ScanResult> cachedScanResults = new ArrayList<>(mScanResultCache.values());
+
+            // Add a unique Passpoint R1 AccessPoint for each Passpoint profile's FQDN.
+            List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans =
+                    mWifiManager.getAllMatchingWifiConfigs(cachedScanResults);
+            Set<String> seenFQDNs = new ArraySet<>();
+            for (Pair<WifiConfiguration,
+                    Map<Integer, List<ScanResult>>> pairing : passpointConfigsAndScans) {
+                WifiConfiguration config = pairing.first;
+
+                List<ScanResult> scanResults = new ArrayList<>();
+
+                List<ScanResult> homeScans =
+                        pairing.second.get(WifiManager.PASSPOINT_HOME_NETWORK);
+                List<ScanResult> roamingScans =
+                        pairing.second.get(WifiManager.PASSPOINT_ROAMING_NETWORK);
+
+                if (homeScans == null) {
+                    homeScans = new ArrayList<>();
+                }
+                if (roamingScans == null) {
+                    roamingScans = new ArrayList<>();
+                }
+
+                // TODO(b/118705403): Differentiate home network vs roaming network for summary info
+                if (!homeScans.isEmpty()) {
+                    scanResults.addAll(homeScans);
+                } else {
+                    scanResults.addAll(roamingScans);
+                }
+
+                if (seenFQDNs.add(config.FQDN)) {
+                    int bestRssi = Integer.MIN_VALUE;
+                    for (ScanResult result : scanResults) {
+                        if (result.level >= bestRssi) {
+                            bestRssi = result.level;
+                            config.SSID = AccessPoint.convertToQuotedString(result.SSID);
+                        }
+                    }
+
+                    AccessPoint accessPoint =
+                            getCachedOrCreatePasspoint(scanResults, cachedAccessPoints, config);
+                    accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
+                    accessPoints.add(accessPoint);
+                }
+            }
+
+            // Add Passpoint OSU Provider AccessPoints
+            Map<OsuProvider, List<ScanResult>> providersAndScans =
+                    mWifiManager.getMatchingOsuProviders(cachedScanResults);
+            Set<OsuProvider> alreadyProvisioned = mWifiManager
+                    .getMatchingPasspointConfigsForOsuProviders(
+                            providersAndScans.keySet()).keySet();
+            for (OsuProvider provider : providersAndScans.keySet()) {
+                if (!alreadyProvisioned.contains(provider)) {
+                    AccessPoint accessPointOsu =
+                            getCachedOrCreateOsu(providersAndScans.get(provider),
+                                    cachedAccessPoints, provider);
+                    accessPointOsu.update(connectionConfig, mLastInfo, mLastNetworkInfo);
+                    accessPoints.add(accessPointOsu);
+                }
+            }
+
+
             // If there were no scan results, create an AP for the currently connected network (if
             // it exists).
-            // TODO(b/b/73076869): Add support for passpoint (ephemeral) networks
             if (accessPoints.isEmpty() && connectionConfig != null) {
                 AccessPoint activeAp = new AccessPoint(mContext, connectionConfig);
                 activeAp.update(connectionConfig, mLastInfo, mLastNetworkInfo);
@@ -623,16 +689,49 @@
     AccessPoint getCachedOrCreate(
             List<ScanResult> scanResults,
             List<AccessPoint> cache) {
-        final int N = cache.size();
-        for (int i = 0; i < N; i++) {
-            if (cache.get(i).getKey().equals(AccessPoint.getKey(scanResults.get(0)))) {
-                AccessPoint ret = cache.remove(i);
-                ret.setScanResults(scanResults);
-                return ret;
+        AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(scanResults.get(0)));
+        if (accessPoint == null) {
+            accessPoint = new AccessPoint(mContext, scanResults);
+        } else {
+            accessPoint.setScanResults(scanResults);
+        }
+        return accessPoint;
+    }
+
+    private AccessPoint getCachedOrCreatePasspoint(
+            List<ScanResult> scanResults,
+            List<AccessPoint> cache,
+            WifiConfiguration config) {
+        AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(config));
+        if (accessPoint == null) {
+            accessPoint = new AccessPoint(mContext, config);
+        }
+        accessPoint.setScanResults(scanResults);
+        return accessPoint;
+    }
+
+    private AccessPoint getCachedOrCreateOsu(
+            List<ScanResult> scanResults,
+            List<AccessPoint> cache,
+            OsuProvider provider) {
+        AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(provider));
+        if (accessPoint == null) {
+            accessPoint = new AccessPoint(mContext, provider);
+        }
+        accessPoint.setScanResults(scanResults);
+        return accessPoint;
+    }
+
+    private AccessPoint getCachedByKey(List<AccessPoint> cache, String key) {
+        ListIterator<AccessPoint> lit = cache.listIterator();
+        while (lit.hasNext()) {
+            AccessPoint currentAccessPoint = lit.next();
+            if (currentAccessPoint.getKey().equals(key)) {
+                lit.remove();
+                return currentAccessPoint;
             }
         }
-        final AccessPoint accessPoint = new AccessPoint(mContext, scanResults);
-        return accessPoint;
+        return null;
     }
 
     private void updateNetworkInfo(NetworkInfo networkInfo) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 594d767..92ebe44 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -17,7 +17,7 @@
 
 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
 
-import static com.android.settingslib.Utils.STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY;
+import static com.android.settingslib.Utils.STORAGE_MANAGER_ENABLED_PROPERTY;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -159,7 +159,7 @@
 
     @Test
     public void testIsStorageManagerEnabled_UsesSystemProperties() {
-        SystemProperties.set(STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY, "false");
+        SystemProperties.set(STORAGE_MANAGER_ENABLED_PROPERTY, "true");
         assertThat(Utils.isStorageManagerEnabled(mContext)).isTrue();
     }
 
@@ -247,6 +247,15 @@
     }
 
     @Test
+    public void isInService_voiceOutOfServiceDataInServiceOnIwLan_returnFalse() {
+        when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
+        when(mServiceState.getDataNetworkType())
+                .thenReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN);
+        when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+        assertThat(Utils.isInService(mServiceState)).isFalse();
+    }
+
+    @Test
     public void isInService_voiceOutOfServiceDataOutOfService_returnFalse() {
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
         when(mServiceState.getDataRegState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
new file mode 100644
index 0000000..e5d1b18
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.media;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class BluetoothMediaDeviceTest {
+
+    @Mock
+    private CachedBluetoothDevice mDevice;
+
+    private Context mContext;
+    private BluetoothMediaDevice mBluetoothMediaDevice;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+
+        when(mDevice.isActiveDevice(BluetoothProfile.A2DP)).thenReturn(true);
+        when(mDevice.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(true);
+
+        mBluetoothMediaDevice = new BluetoothMediaDevice(mContext, mDevice);
+    }
+
+    @Test
+    public void connect_setActiveSuccess_isConnectedReturnTrue() {
+        when(mDevice.setActive()).thenReturn(true);
+
+        assertThat(mBluetoothMediaDevice.connect()).isTrue();
+    }
+
+    @Test
+    public void connect_setActiveFail_isConnectedReturnFalse() {
+        when(mDevice.setActive()).thenReturn(false);
+
+        assertThat(mBluetoothMediaDevice.connect()).isFalse();
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
new file mode 100644
index 0000000..a20e22b
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
@@ -0,0 +1,416 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.media;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.bluetooth.A2dpProfile;
+import com.android.settingslib.bluetooth.BluetoothEventManager;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+public class BluetoothMediaManagerTest {
+
+    private static final String TEST_ADDRESS = "11:22:33:44:55:66";
+
+    @Mock
+    private LocalBluetoothManager mLocalBluetoothManager;
+    @Mock
+    private LocalBluetoothProfileManager mProfileManager;
+    @Mock
+    private A2dpProfile mA2dpProfile;
+    @Mock
+    private HearingAidProfile mHapProfile;
+    @Mock
+    private CachedBluetoothDeviceManager mCachedDeviceManager;
+    @Mock
+    private BluetoothEventManager mEventManager;
+    @Mock
+    private MediaManager.MediaDeviceCallback mCallback;
+
+    private BluetoothMediaManager mMediaManager;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+
+        when(mLocalBluetoothManager.getProfileManager()).thenReturn(mProfileManager);
+        when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
+        when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
+        when(mProfileManager.getHearingAidProfile()).thenReturn(mHapProfile);
+        when(mLocalBluetoothManager.getEventManager()).thenReturn(mEventManager);
+
+        mMediaManager = new BluetoothMediaManager(mContext, mLocalBluetoothManager, null);
+    }
+
+    @Test
+    public void startScan_haveA2dpProfileConnectedBluetoothDevice_shouldAddDevice() {
+        final List<BluetoothDevice> devices = new ArrayList<>();
+        final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+        final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
+        devices.add(bluetoothDevice);
+
+        when(mA2dpProfile.getConnectedDevices()).thenReturn(devices);
+        when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
+        when(cachedDevice.isConnected()).thenReturn(true);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        mMediaManager.startScan();
+        assertThat(mMediaManager.mMediaDevices).hasSize(devices.size());
+    }
+
+    @Test
+    public void startScan_haveA2dpProfileDisconnectedBluetoothDevice_shouldNotAddDevice() {
+        final List<BluetoothDevice> devices = new ArrayList<>();
+        final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+        final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
+        devices.add(bluetoothDevice);
+
+        when(mA2dpProfile.getConnectedDevices()).thenReturn(devices);
+        when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
+        when(cachedDevice.isConnected()).thenReturn(false);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        mMediaManager.startScan();
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+    }
+
+    @Test
+    public void startScan_noA2dpProfileBluetoothDevice_shouldNotAddDevice() {
+        final List<BluetoothDevice> devices = new ArrayList<>();
+
+        when(mA2dpProfile.getConnectedDevices()).thenReturn(devices);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        mMediaManager.startScan();
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+    }
+
+    @Test
+    public void startScan_haveHapProfileConnectedBluetoothDevice_shouldAddDevice() {
+        final List<BluetoothDevice> devices = new ArrayList<>();
+        final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+        final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
+        devices.add(bluetoothDevice);
+
+        when(mHapProfile.getConnectedDevices()).thenReturn(devices);
+        when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
+        when(cachedDevice.isConnected()).thenReturn(true);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        mMediaManager.startScan();
+        assertThat(mMediaManager.mMediaDevices).hasSize(devices.size());
+    }
+
+    @Test
+    public void startScan_noHapProfileBluetoothDevice_shouldNotAddDevice() {
+        final List<BluetoothDevice> devices = new ArrayList<>();
+
+        when(mHapProfile.getConnectedDevices()).thenReturn(devices);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        mMediaManager.startScan();
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+    }
+
+    @Test
+    public void starScan_a2dpAndHapProfileNotReady_shouldRegisterCallback() {
+        final Collection<CachedBluetoothDevice> mDevices = new ArrayList<>();
+        final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+        mDevices.add(cachedDevice);
+
+        when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mDevices);
+        when(mA2dpProfile.isProfileReady()).thenReturn(false);
+        when(mHapProfile.isProfileReady()).thenReturn(false);
+
+        mMediaManager.startScan();
+
+        verify(mProfileManager).addServiceListener(mMediaManager);
+    }
+
+    @Test
+    public void starScan_a2dpAndHapProfileReady_shouldNotRegisterCallback() {
+        final Collection<CachedBluetoothDevice> mDevices = new ArrayList<>();
+        final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+        mDevices.add(cachedDevice);
+
+        when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mDevices);
+        when(mA2dpProfile.isProfileReady()).thenReturn(true);
+        when(mHapProfile.isProfileReady()).thenReturn(true);
+
+        mMediaManager.startScan();
+
+        verify(mProfileManager, never()).addServiceListener(mMediaManager);
+    }
+
+    @Test
+    public void onServiceConnected_a2dpAndHapProfileNotReady_doNothing() {
+        final Collection<CachedBluetoothDevice> mDevices = new ArrayList<>();
+        final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+        mDevices.add(cachedDevice);
+
+        when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mDevices);
+        when(mA2dpProfile.isProfileReady()).thenReturn(false);
+        when(mHapProfile.isProfileReady()).thenReturn(false);
+
+        mMediaManager.startScan();
+        mMediaManager.onServiceConnected();
+
+        verify(mProfileManager, never()).removeServiceListener(mMediaManager);
+    }
+
+    @Test
+    public void onDeviceAttributesChanged_a2dpAndHapProfileReady_shouldUnregisterCallback() {
+        final Collection<CachedBluetoothDevice> mDevices = new ArrayList<>();
+        final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+        mDevices.add(cachedDevice);
+
+        when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mDevices);
+        when(mA2dpProfile.isProfileReady()).thenReturn(true);
+        when(mHapProfile.isProfileReady()).thenReturn(true);
+
+        mMediaManager.startScan();
+        mMediaManager.onServiceConnected();
+
+        verify(mProfileManager).removeServiceListener(mMediaManager);
+    }
+
+    @Test
+    public void onBluetoothStateChanged_bluetoothStateIsOn_callOnDeviceListAdded() {
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onBluetoothStateChanged(BluetoothAdapter.STATE_ON);
+
+        verify(mCallback).onDeviceListAdded(any());
+    }
+
+    @Test
+    public void onBluetoothStateChanged_bluetoothStateIsOff_callOnDeviceListRemoved() {
+        final BluetoothMediaDevice device1 = mock(BluetoothMediaDevice.class);
+        final BluetoothMediaDevice device2 = mock(BluetoothMediaDevice.class);
+        mMediaManager.mMediaDevices.add(device1);
+        mMediaManager.mMediaDevices.add(device2);
+
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onBluetoothStateChanged(BluetoothAdapter.STATE_OFF);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        verify(mCallback).onDeviceListRemoved(any());
+    }
+
+    @Test
+    public void onDeviceAdded_cachedDeviceIsConnected_callOnDeviceAdded() {
+        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+
+        when(device.isConnectedHearingAidDevice()).thenReturn(true);
+        when(device.isConnectedA2dpDevice()).thenReturn(true);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onDeviceAdded(device);
+
+        assertThat(mMediaManager.mMediaDevices).hasSize(1);
+        verify(mCallback).onDeviceAdded(any());
+
+    }
+
+    @Test
+    public void onDeviceAdded_cachedDeviceIsDisconnected_doNothing() {
+        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+
+        when(device.isConnectedHearingAidDevice()).thenReturn(false);
+        when(device.isConnectedA2dpDevice()).thenReturn(false);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onDeviceAdded(device);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        verify(mCallback, never()).onDeviceAdded(any());
+
+    }
+
+    @Test
+    public void onDeviceDeleted_cachedDeviceIsConnected_doNothing() {
+        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+        final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
+        mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
+
+        when(device.isConnectedHearingAidDevice()).thenReturn(true);
+        when(device.isConnectedA2dpDevice()).thenReturn(true);
+        when(device.getAddress()).thenReturn(TEST_ADDRESS);
+        when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
+
+        assertThat(mMediaManager.mMediaDevices).hasSize(1);
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onDeviceDeleted(device);
+
+        assertThat(mMediaManager.mMediaDevices).hasSize(1);
+        verify(mCallback, never()).onDeviceRemoved(any());
+    }
+
+    @Test
+    public void onDeviceDeleted_cachedDeviceIsDisconnected_callOnDeviceRemoved() {
+        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+        final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
+        mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
+
+        when(device.isConnectedHearingAidDevice()).thenReturn(false);
+        when(device.isConnectedA2dpDevice()).thenReturn(false);
+        when(device.getAddress()).thenReturn(TEST_ADDRESS);
+        when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
+
+        assertThat(mMediaManager.mMediaDevices).hasSize(1);
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onDeviceDeleted(device);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        verify(mCallback).onDeviceRemoved(any());
+    }
+
+    @Test
+    public void onProfileConnectionStateChanged_cachedDeviceIsConnect_callOnDeviceAdded() {
+        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+
+        when(device.isConnectedHearingAidDevice()).thenReturn(true);
+        when(device.isConnectedA2dpDevice()).thenReturn(true);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onProfileConnectionStateChanged(device, 0, 0);
+
+        assertThat(mMediaManager.mMediaDevices).hasSize(1);
+        verify(mCallback).onDeviceAdded(any());
+    }
+
+    @Test
+    public void onProfileConnectionStateChanged_cachedDeviceIsDisconnect_callOnDeviceRemoved() {
+        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+        final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
+        mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
+
+        when(device.isConnectedHearingAidDevice()).thenReturn(false);
+        when(device.isConnectedA2dpDevice()).thenReturn(false);
+        when(device.getAddress()).thenReturn(TEST_ADDRESS);
+        when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
+
+        assertThat(mMediaManager.mMediaDevices).hasSize(1);
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onProfileConnectionStateChanged(device, 0, 0);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        verify(mCallback).onDeviceRemoved(any());
+    }
+
+    @Test
+    public void onAclConnectionStateChanged_cachedDeviceIsConnect_callOnDeviceAdded() {
+        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+
+        when(device.isConnectedHearingAidDevice()).thenReturn(true);
+        when(device.isConnectedA2dpDevice()).thenReturn(true);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onAclConnectionStateChanged(device, 0);
+
+        assertThat(mMediaManager.mMediaDevices).hasSize(1);
+        verify(mCallback).onDeviceAdded(any());
+    }
+
+    @Test
+    public void onAclConnectionStateChanged_cachedDeviceIsDisconnect_callOnDeviceRemoved() {
+        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+        final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
+        mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
+
+        when(device.isConnectedHearingAidDevice()).thenReturn(false);
+        when(device.isConnectedA2dpDevice()).thenReturn(false);
+        when(device.getAddress()).thenReturn(TEST_ADDRESS);
+        when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
+
+        assertThat(mMediaManager.mMediaDevices).hasSize(1);
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onAclConnectionStateChanged(device, 0);
+
+        assertThat(mMediaManager.mMediaDevices).isEmpty();
+        verify(mCallback).onDeviceRemoved(any());
+    }
+
+    @Test
+    public void onActiveDeviceChanged_isHapProfile_callOnActiveDeviceChanged() {
+        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+
+        when(device.getAddress()).thenReturn(TEST_ADDRESS);
+
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onActiveDeviceChanged(device, BluetoothProfile.HEARING_AID);
+
+        verify(mCallback).onConnectedDeviceChanged(any());
+    }
+
+    @Test
+    public void onActiveDeviceChanged_isA2dpProfile_callOnActiveDeviceChanged() {
+        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+
+        when(device.getAddress()).thenReturn(TEST_ADDRESS);
+
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onActiveDeviceChanged(device, BluetoothProfile.A2DP);
+
+        verify(mCallback).onConnectedDeviceChanged(any());
+    }
+
+    @Test
+    public void onActiveDeviceChanged_isNotA2dpAndHapProfile_doNothing() {
+        final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+
+        when(device.getAddress()).thenReturn(TEST_ADDRESS);
+
+        mMediaManager.registerCallback(mCallback);
+        mMediaManager.onActiveDeviceChanged(device, BluetoothProfile.HEALTH);
+
+        verify(mCallback, never()).onConnectedDeviceChanged(any());
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
new file mode 100644
index 0000000..b11cf69
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.media;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import androidx.mediarouter.media.MediaRouteSelector;
+import androidx.mediarouter.media.MediaRouter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class InfoMediaManagerTest {
+
+    private static final String TEST_PACKAGE_NAME = "com.test.packagename";
+    private static final String TEST_ID = "test_id";
+
+    @Mock
+    private MediaRouter mMediaRouter;
+    @Mock
+    private MediaRouteSelector mSelector;
+
+    private InfoMediaManager mInfoMediaManager;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+
+        mInfoMediaManager = new InfoMediaManager(mContext, TEST_PACKAGE_NAME, null);
+        mInfoMediaManager.mMediaRouter = mMediaRouter;
+        mInfoMediaManager.mSelector = mSelector;
+    }
+
+    @Test
+    public void stopScan_shouldRemoveCallback() {
+        mInfoMediaManager.stopScan();
+
+        verify(mMediaRouter).removeCallback(mInfoMediaManager.mMediaRouterCallback);
+    }
+
+    @Test
+    public void startScan_shouldAddCallback() {
+        mInfoMediaManager.startScan();
+
+        verify(mMediaRouter).addCallback(mSelector, mInfoMediaManager.mMediaRouterCallback,
+                MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
+    }
+
+    @Test
+    public void onRouteAdded_mediaDeviceNotExistInList_addMediaDevice() {
+        final MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class);
+        when(info.getId()).thenReturn(TEST_ID);
+
+        final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
+        assertThat(mediaDevice).isNull();
+
+        mInfoMediaManager.mMediaRouterCallback.onRouteAdded(mMediaRouter, info);
+
+        final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
+        assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
+    }
+
+    @Test
+    public void onRouteAdded_mediaDeviceExistInList_doNothing() {
+        final MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class);
+        when(info.getId()).thenReturn(TEST_ID);
+        final InfoMediaDevice infoDevice = new InfoMediaDevice(mContext, info);
+        mInfoMediaManager.mMediaDevices.add(infoDevice);
+
+        final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
+        final int size = mInfoMediaManager.mMediaDevices.size();
+        assertThat(mediaDevice).isNotNull();
+
+        mInfoMediaManager.mMediaRouterCallback.onRouteAdded(mMediaRouter, info);
+
+        assertThat(mInfoMediaManager.mMediaDevices).hasSize(size);
+    }
+
+    @Test
+    public void onRouteRemoved_mediaDeviceExistInList_removeMediaDevice() {
+        final MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class);
+        when(info.getId()).thenReturn(TEST_ID);
+        final InfoMediaDevice infoDevice = new InfoMediaDevice(mContext, info);
+        mInfoMediaManager.mMediaDevices.add(infoDevice);
+
+        final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
+        assertThat(mediaDevice).isNotNull();
+        assertThat(mInfoMediaManager.mMediaDevices).hasSize(1);
+
+        mInfoMediaManager.mMediaRouterCallback.onRouteRemoved(mMediaRouter, info);
+
+        assertThat(mInfoMediaManager.mMediaDevices).isEmpty();
+    }
+
+    @Test
+    public void onRouteRemoved_mediaDeviceNotExistInList_doNothing() {
+        final MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class);
+        when(info.getId()).thenReturn(TEST_ID);
+
+        final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
+        final int size = mInfoMediaManager.mMediaDevices.size();
+        assertThat(mediaDevice).isNull();
+
+        mInfoMediaManager.mMediaRouterCallback.onRouteRemoved(mMediaRouter, info);
+
+        assertThat(mInfoMediaManager.mMediaDevices).hasSize(size);
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
new file mode 100644
index 0000000..3556814
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.media;
+
+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.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import com.android.settingslib.bluetooth.A2dpProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+public class LocalMediaManagerTest {
+
+    private static final String TEST_DEVICE_ID_1 = "device_id_1";
+    private static final String TEST_DEVICE_ID_2 = "device_id_2";
+    private static final String TEST_DEVICE_ID_3 = "device_id_3";
+    private static final String TEST_CURRENT_DEVICE_ID = "currentDevice_id";
+
+    @Mock
+    private BluetoothMediaManager mBluetoothMediaManager;
+    @Mock
+    private InfoMediaManager mInfoMediaManager;
+    @Mock
+    private LocalBluetoothManager mLocalBluetoothManager;
+    @Mock
+    private LocalMediaManager.DeviceCallback mCallback;
+    @Mock
+    private HearingAidProfile mHapProfile;
+    @Mock
+    private A2dpProfile mA2dpProfile;
+    @Mock
+    private LocalBluetoothProfileManager mLocalProfileManager;
+
+    private Context mContext;
+    private LocalMediaManager mLocalMediaManager;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+
+        when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalProfileManager);
+        when(mLocalProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
+        when(mLocalProfileManager.getHearingAidProfile()).thenReturn(mHapProfile);
+
+        mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager,
+                mBluetoothMediaManager, mInfoMediaManager);
+    }
+
+    @Test
+    public void startScan_mediaDevicesListShouldBeClear() {
+        final MediaDevice device = mock(MediaDevice.class);
+        mLocalMediaManager.mMediaDevices.add(device);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(1);
+        mLocalMediaManager.startScan();
+        assertThat(mLocalMediaManager.mMediaDevices).isEmpty();
+    }
+
+    @Test
+    public void connectDevice_deviceNotEqualCurrentConnectedDevice_connectDevice() {
+        final MediaDevice currentDevice = mock(MediaDevice.class);
+        final MediaDevice device = mock(MediaDevice.class);
+        mLocalMediaManager.mMediaDevices.add(currentDevice);
+        mLocalMediaManager.mMediaDevices.add(device);
+        mLocalMediaManager.mCurrentConnectedDevice = currentDevice;
+
+        when(device.getId()).thenReturn(TEST_DEVICE_ID_1);
+        when(currentDevice.getId()).thenReturn(TEST_CURRENT_DEVICE_ID);
+
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.connectDevice(device);
+
+        verify(currentDevice).disconnect();
+        verify(device).connect();
+        verify(mCallback).onSelectedDeviceStateChanged(any(),
+                eq(LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED));
+    }
+
+    @Test
+    public void getMediaDeviceById_idExist_shouldReturnMediaDevice() {
+        final MediaDevice device1 = mock(MediaDevice.class);
+        final MediaDevice device2 = mock(MediaDevice.class);
+        mLocalMediaManager.mMediaDevices.add(device1);
+        mLocalMediaManager.mMediaDevices.add(device2);
+
+        when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
+        when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
+
+        final MediaDevice device = mLocalMediaManager
+                .getMediaDeviceById(mLocalMediaManager.mMediaDevices, TEST_DEVICE_ID_2);
+
+        assertThat(device.getId()).isEqualTo(TEST_DEVICE_ID_2);
+    }
+
+    @Test
+    public void getMediaDeviceById_idNotExist_shouldReturnNull() {
+        final MediaDevice device1 = mock(MediaDevice.class);
+        final MediaDevice device2 = mock(MediaDevice.class);
+        mLocalMediaManager.mMediaDevices.add(device1);
+        mLocalMediaManager.mMediaDevices.add(device2);
+
+        when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
+        when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
+
+        final MediaDevice device = mLocalMediaManager
+                .getMediaDeviceById(mLocalMediaManager.mMediaDevices, TEST_CURRENT_DEVICE_ID);
+
+        assertThat(device).isNull();
+    }
+
+    @Test
+    public void onDeviceAdded_mediaDeviceAndPhoneDeviceNotExistInList_addBothDevice() {
+        final MediaDevice device = mock(MediaDevice.class);
+
+        assertThat(mLocalMediaManager.mMediaDevices).isEmpty();
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onDeviceAdded(device);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
+        verify(mCallback).onDeviceListUpdate(any());
+    }
+
+    @Test
+    public void onDeviceAdded_mediaDeviceNotExistAndPhoneDeviceExistInList_addMediaDevice() {
+        final MediaDevice device1 = mock(MediaDevice.class);
+        final MediaDevice device2 = mock(MediaDevice.class);
+        mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class);
+        mLocalMediaManager.mMediaDevices.add(device1);
+        mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onDeviceAdded(device2);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(3);
+        verify(mCallback).onDeviceListUpdate(any());
+    }
+
+    @Test
+    public void onDeviceAdded_mediaDeviceAndPhoneDeviceExistInList_doNothing() {
+        final MediaDevice device1 = mock(MediaDevice.class);
+        mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class);
+        mLocalMediaManager.mMediaDevices.add(device1);
+        mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onDeviceAdded(device1);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
+        verify(mCallback, never()).onDeviceListUpdate(any());
+    }
+
+    @Test
+    public void onDeviceListAdded_phoneDeviceNotExistInList_addPhoneDeviceAndDevicesList() {
+        final List<MediaDevice> devices = new ArrayList<>();
+        final MediaDevice device1 = mock(MediaDevice.class);
+        final MediaDevice device2 = mock(MediaDevice.class);
+        devices.add(device1);
+        devices.add(device2);
+
+        when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
+        when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
+
+        assertThat(mLocalMediaManager.mMediaDevices).isEmpty();
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onDeviceListAdded(devices);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(3);
+        verify(mCallback).onDeviceListUpdate(any());
+    }
+
+    @Test
+    public void onDeviceListAdded_phoneDeviceExistInList_addDeviceList() {
+        final List<MediaDevice> devices = new ArrayList<>();
+        final MediaDevice device1 = mock(MediaDevice.class);
+        final MediaDevice device2 = mock(MediaDevice.class);
+        final MediaDevice device3 = mock(MediaDevice.class);
+        mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class);
+        devices.add(device1);
+        devices.add(device2);
+        mLocalMediaManager.mMediaDevices.add(device3);
+        mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+
+        when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
+        when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
+        when(device3.getId()).thenReturn(TEST_DEVICE_ID_3);
+        when(mLocalMediaManager.mPhoneDevice.getId()).thenReturn("test_phone_id");
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onDeviceListAdded(devices);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(4);
+        verify(mCallback).onDeviceListUpdate(any());
+    }
+
+    @Test
+    public void onDeviceRemoved_phoneDeviceIsLastDeviceAfterRemoveMediaDevice_removeBothDevice() {
+        final MediaDevice device1 = mock(MediaDevice.class);
+        mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class);
+        mLocalMediaManager.mMediaDevices.add(device1);
+        mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onDeviceRemoved(device1);
+
+        assertThat(mLocalMediaManager.mMediaDevices).isEmpty();
+        verify(mCallback).onDeviceListUpdate(any());
+    }
+
+    @Test
+    public void onDeviceRemoved_phoneDeviceNotLastDeviceAfterRemoveMediaDevice_removeMediaDevice() {
+        final MediaDevice device1 = mock(MediaDevice.class);
+        final MediaDevice device2 = mock(MediaDevice.class);
+        mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class);
+        mLocalMediaManager.mMediaDevices.add(device1);
+        mLocalMediaManager.mMediaDevices.add(device2);
+        mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(3);
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onDeviceRemoved(device2);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
+        verify(mCallback).onDeviceListUpdate(any());
+    }
+
+    @Test
+    public void onDeviceRemoved_removeMediaDeviceNotInList_doNothing() {
+        final MediaDevice device1 = mock(MediaDevice.class);
+        final MediaDevice device2 = mock(MediaDevice.class);
+        mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class);
+        mLocalMediaManager.mMediaDevices.add(device2);
+        mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onDeviceRemoved(device1);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
+        verify(mCallback, never()).onDeviceListUpdate(any());
+    }
+
+    @Test
+    public void onDeviceListRemoved_phoneDeviceIsLastDeviceAfterRemoveDeviceList_removeAll() {
+        final List<MediaDevice> devices = new ArrayList<>();
+        final MediaDevice device1 = mock(MediaDevice.class);
+        final MediaDevice device2 = mock(MediaDevice.class);
+        mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class);
+        devices.add(device1);
+        devices.add(device2);
+        mLocalMediaManager.mMediaDevices.add(device1);
+        mLocalMediaManager.mMediaDevices.add(device2);
+        mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(3);
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onDeviceListRemoved(devices);
+
+        assertThat(mLocalMediaManager.mMediaDevices).isEmpty();
+        verify(mCallback).onDeviceListUpdate(any());
+    }
+
+    @Test
+    public void onDeviceListRemoved_phoneDeviceNotLastDeviceAfterRemoveDeviceList_removeList() {
+        final List<MediaDevice> devices = new ArrayList<>();
+        final MediaDevice device1 = mock(MediaDevice.class);
+        final MediaDevice device2 = mock(MediaDevice.class);
+        final MediaDevice device3 = mock(MediaDevice.class);
+        mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class);
+        devices.add(device1);
+        devices.add(device3);
+        mLocalMediaManager.mMediaDevices.add(device1);
+        mLocalMediaManager.mMediaDevices.add(device2);
+        mLocalMediaManager.mMediaDevices.add(device3);
+        mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(4);
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onDeviceListRemoved(devices);
+
+        assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
+        verify(mCallback).onDeviceListUpdate(any());
+    }
+
+    @Test
+    public void onDeviceAttributesChanged_shouldDispatchDeviceListUpdate() {
+        mLocalMediaManager.registerCallback(mCallback);
+
+        mLocalMediaManager.mMediaDeviceCallback.onDeviceAttributesChanged();
+
+        verify(mCallback).onDeviceListUpdate(any());
+    }
+
+    @Test
+    public void onConnectedDeviceChanged_connectedAndCurrentDeviceAreDifferent_notifyThemChanged() {
+        final MediaDevice device1 = mock(MediaDevice.class);
+        final MediaDevice device2 = mock(MediaDevice.class);
+
+        mLocalMediaManager.mMediaDevices.add(device1);
+        mLocalMediaManager.mMediaDevices.add(device2);
+        mLocalMediaManager.mCurrentConnectedDevice = device1;
+
+        when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
+        when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
+
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_2);
+
+        assertThat(mLocalMediaManager.getCurrentConnectedDevice()).isEqualTo(device2);
+        verify(mCallback).onDeviceListUpdate(any());
+    }
+
+    @Test
+    public void onConnectedDeviceChanged_connectedAndCurrentDeviceAreSame_doNothing() {
+        final MediaDevice device1 = mock(MediaDevice.class);
+        final MediaDevice device2 = mock(MediaDevice.class);
+
+        mLocalMediaManager.mMediaDevices.add(device1);
+        mLocalMediaManager.mMediaDevices.add(device2);
+        mLocalMediaManager.mCurrentConnectedDevice = device1;
+
+        when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
+        when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
+
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_1);
+
+        verify(mCallback, never()).onDeviceListUpdate(any());
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
index 9bbdd01..fc514f0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
@@ -25,8 +25,11 @@
 
 import androidx.mediarouter.media.MediaRouter;
 
+import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -78,6 +81,14 @@
     private MediaRouter.RouteInfo mRouteInfo2;
     @Mock
     private MediaRouter.RouteInfo mRouteInfo3;
+    @Mock
+    private LocalBluetoothProfileManager mProfileManager;
+    @Mock
+    private HearingAidProfile mHapProfile;
+    @Mock
+    private A2dpProfile mA2dpProfile;
+    @Mock
+    private BluetoothDevice mDevice;
 
     private BluetoothMediaDevice mBluetoothMediaDevice1;
     private BluetoothMediaDevice mBluetoothMediaDevice2;
@@ -109,6 +120,10 @@
         when(mRouteInfo1.getName()).thenReturn(DEVICE_NAME_1);
         when(mRouteInfo2.getName()).thenReturn(DEVICE_NAME_2);
         when(mRouteInfo3.getName()).thenReturn(DEVICE_NAME_3);
+        when(mLocalBluetoothManager.getProfileManager()).thenReturn(mProfileManager);
+        when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
+        when(mProfileManager.getHearingAidProfile()).thenReturn(mHapProfile);
+        when(mA2dpProfile.getActiveDevice()).thenReturn(mDevice);
 
         mBluetoothMediaDevice1 = new BluetoothMediaDevice(mContext, mCachedDevice1);
         mBluetoothMediaDevice2 = new BluetoothMediaDevice(mContext, mCachedDevice2);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceUtilsTest.java
new file mode 100644
index 0000000..6e29e13
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceUtilsTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.media;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import androidx.mediarouter.media.MediaRouter;
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class MediaDeviceUtilsTest {
+
+    private static final String TEST_ADDRESS = "11:22:33:44:55:66";
+    private static final String TEST_ROUTE_ID = "test_route_id";
+
+    @Mock
+    private CachedBluetoothDevice mDevice;
+    @Mock
+    private MediaRouter.RouteInfo mRouteInfo;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void getId_returnBluetoothDeviceAddress() {
+        when(mDevice.getAddress()).thenReturn(TEST_ADDRESS);
+
+        final String id = MediaDeviceUtils.getId(mDevice);
+
+        assertThat(id).isEqualTo(TEST_ADDRESS);
+    }
+
+    @Test
+    public void getId_returnRouteInfoId() {
+        when(mRouteInfo.getId()).thenReturn(TEST_ROUTE_ID);
+
+        final String id = MediaDeviceUtils.getId(mRouteInfo);
+
+        assertThat(id).isEqualTo(TEST_ROUTE_ID);
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
new file mode 100644
index 0000000..98eccb5
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.media;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class MediaManagerTest {
+
+    private static final String TEST_ID = "test_id";
+
+    @Mock
+    private MediaManager.MediaDeviceCallback mCallback;
+    @Mock
+    private MediaDevice mDevice;
+
+    private MediaManager mMediaManager;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+
+        when(mDevice.getId()).thenReturn(TEST_ID);
+
+        mMediaManager = new MediaManager(mContext, null) {
+            @Override
+            public void startScan() {
+
+            }
+
+            @Override
+            public void stopScan() {
+
+            }
+        };
+    }
+
+    @Test
+    public void dispatchDeviceAdded_registerCallback_shouldDispatchCallback() {
+        mMediaManager.registerCallback(mCallback);
+
+        mMediaManager.dispatchDeviceAdded(mDevice);
+
+        verify(mCallback).onDeviceAdded(mDevice);
+    }
+
+    @Test
+    public void dispatchDeviceRemoved_registerCallback_shouldDispatchCallback() {
+        mMediaManager.registerCallback(mCallback);
+
+        mMediaManager.dispatchDeviceRemoved(mDevice);
+
+        verify(mCallback).onDeviceRemoved(mDevice);
+    }
+
+    @Test
+    public void dispatchDeviceListAdded_registerCallback_shouldDispatchCallback() {
+        mMediaManager.registerCallback(mCallback);
+
+        mMediaManager.dispatchDeviceListAdded();
+
+        verify(mCallback).onDeviceListAdded(any());
+    }
+
+    @Test
+    public void dispatchDeviceListRemoved_registerCallback_shouldDispatchCallback() {
+        mMediaManager.registerCallback(mCallback);
+
+        mMediaManager.dispatchDeviceListRemoved(mMediaManager.mMediaDevices);
+
+        verify(mCallback).onDeviceListRemoved(mMediaManager.mMediaDevices);
+    }
+
+    @Test
+    public void dispatchActiveDeviceChanged_registerCallback_shouldDispatchCallback() {
+        mMediaManager.registerCallback(mCallback);
+
+        mMediaManager.dispatchConnectedDeviceChanged(TEST_ID);
+
+        verify(mCallback).onConnectedDeviceChanged(TEST_ID);
+    }
+
+    @Test
+    public void findMediaDevice_idExist_shouldReturnMediaDevice() {
+        mMediaManager.mMediaDevices.add(mDevice);
+
+        final MediaDevice device = mMediaManager.findMediaDevice(TEST_ID);
+
+        assertThat(device.getId()).isEqualTo(mDevice.getId());
+    }
+
+    @Test
+    public void findMediaDevice_idNotExist_shouldReturnNull() {
+        mMediaManager.mMediaDevices.add(mDevice);
+
+        final MediaDevice device = mMediaManager.findMediaDevice("123");
+
+        assertThat(device).isNull();
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
new file mode 100644
index 0000000..5ba33f5
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.media;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+
+import com.android.settingslib.bluetooth.A2dpProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class PhoneMediaDeviceTest {
+
+    @Mock
+    private LocalBluetoothProfileManager mLocalProfileManager;
+    @Mock
+    private LocalBluetoothManager mLocalBluetoothManager;
+    @Mock
+    private HearingAidProfile mHapProfile;
+    @Mock
+    private A2dpProfile mA2dpProfile;
+    @Mock
+    private BluetoothDevice mDevice;
+
+    private Context mContext;
+    private PhoneMediaDevice mPhoneMediaDevice;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+
+        when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalProfileManager);
+        when(mLocalProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
+        when(mLocalProfileManager.getHearingAidProfile()).thenReturn(mHapProfile);
+        when(mA2dpProfile.getActiveDevice()).thenReturn(mDevice);
+
+        mPhoneMediaDevice = new PhoneMediaDevice(mContext, mLocalBluetoothManager);
+    }
+
+    @Test
+    public void connect_phoneDeviceSetActiveSuccess_isConnectedReturnTrue() {
+        when(mA2dpProfile.setActiveDevice(null)).thenReturn(true);
+        when(mHapProfile.setActiveDevice(null)).thenReturn(true);
+
+        assertThat(mPhoneMediaDevice.connect()).isTrue();
+    }
+
+    @Test
+    public void connect_a2dpProfileSetActiveFail_isConnectedReturnFalse() {
+        when(mA2dpProfile.setActiveDevice(null)).thenReturn(false);
+        when(mHapProfile.setActiveDevice(null)).thenReturn(true);
+
+        assertThat(mPhoneMediaDevice.connect()).isFalse();
+    }
+
+    @Test
+    public void connect_hearingAidProfileSetActiveFail_isConnectedReturnFalse() {
+        when(mA2dpProfile.setActiveDevice(null)).thenReturn(true);
+        when(mHapProfile.setActiveDevice(null)).thenReturn(false);
+
+        assertThat(mPhoneMediaDevice.connect()).isFalse();
+    }
+
+    @Test
+    public void connect_hearingAidAndA2dpProfileSetActiveFail_isConnectedReturnFalse() {
+        when(mA2dpProfile.setActiveDevice(null)).thenReturn(false);
+        when(mHapProfile.setActiveDevice(null)).thenReturn(false);
+
+        assertThat(mPhoneMediaDevice.connect()).isFalse();
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java
index acf99a2..220463b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java
@@ -45,6 +45,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowSubscriptionManager;
 
 @RunWith(RobolectricTestRunner.class)
 public class DataUsageControllerTest {
@@ -73,7 +74,9 @@
                 new NetworkStatsHistory(DateUtils.DAY_IN_MILLIS /* bucketDuration */));
         doReturn(mNetworkStatsHistory)
                 .when(mSession).getHistoryForNetwork(any(NetworkTemplate.class), anyInt());
-        doReturn(SUB_ID).when(mTelephonyManager).getSubscriberId(anyInt());
+        final int defaultSubscriptionId = 1234;
+        ShadowSubscriptionManager.setDefaultDataSubscriptionId(defaultSubscriptionId);
+        doReturn(SUB_ID).when(mTelephonyManager).getSubscriberId(eq(defaultSubscriptionId));
     }
 
     @Test
@@ -107,4 +110,39 @@
         assertThat(mController.getHistoricalUsageLevel(NetworkTemplate.buildTemplateWifiWildcard()))
                 .isEqualTo(receivedBytes + transmittedBytes);
     }
+
+    @Test
+    public void getDataUsageInfo_hasUsageData_shouldReturnCorrectUsageForExplicitSubId()
+            throws Exception {
+        // First setup a stats bucket for the default subscription / subscriber ID.
+        final long defaultSubRx = 1234567L;
+        final long defaultSubTx = 123456L;
+        final NetworkStats.Bucket defaultSubscriberBucket = mock(NetworkStats.Bucket.class);
+        when(defaultSubscriberBucket.getRxBytes()).thenReturn(defaultSubRx);
+        when(defaultSubscriberBucket.getTxBytes()).thenReturn(defaultSubTx);
+        when(mNetworkStatsManager.querySummaryForDevice(eq(ConnectivityManager.TYPE_MOBILE),
+                eq(SUB_ID), eq(0L)/* startTime */, anyLong() /* endTime */)).thenReturn(
+                defaultSubscriberBucket);
+
+        // Now setup a stats bucket for a different, non-default subscription / subscriber ID.
+        final long nonDefaultSubRx = 7654321L;
+        final long nonDefaultSubTx = 654321L;
+        final NetworkStats.Bucket nonDefaultSubscriberBucket = mock(NetworkStats.Bucket.class);
+        when(nonDefaultSubscriberBucket.getRxBytes()).thenReturn(nonDefaultSubRx);
+        when(nonDefaultSubscriberBucket.getTxBytes()).thenReturn(nonDefaultSubTx);
+        final int explictSubscriptionId = 55;
+        final String subscriberId2 = "Test Subscriber 2";
+        when(mNetworkStatsManager.querySummaryForDevice(eq(ConnectivityManager.TYPE_MOBILE),
+                eq(subscriberId2), eq(0L)/* startTime */, anyLong() /* endTime */)).thenReturn(
+                nonDefaultSubscriberBucket);
+        doReturn(subscriberId2).when(mTelephonyManager).getSubscriberId(explictSubscriptionId);
+
+        // Now verify that when we're asking for stats on the non-default subscription, we get
+        // the data back for that subscription and *not* the default one.
+        mController.setSubscriptionId(explictSubscriptionId);
+
+        assertThat(mController.getHistoricalUsageLevel(
+                NetworkTemplate.buildTemplateMobileAll(subscriberId2))).isEqualTo(
+                nonDefaultSubRx + nonDefaultSubTx);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java
index c3bc8da..4c68c14 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java
@@ -19,7 +19,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
-import android.graphics.drawable.Drawable;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageView;
@@ -43,18 +42,25 @@
     public final ExpectedException thrown = ExpectedException.none();
 
     private Context mContext;
-    private Drawable mIcon;
     private View mAppEntitiesHeaderView;
     private AppEntitiesHeaderController mController;
+    private AppEntityInfo mAppEntityInfo;
 
     @Before
     public void setUp() {
         mContext = RuntimeEnvironment.application;
         mAppEntitiesHeaderView = LayoutInflater.from(mContext).inflate(
                 R.layout.app_entities_header, null /* root */);
-        mIcon = mContext.getDrawable(R.drawable.ic_menu);
         mController = AppEntitiesHeaderController.newInstance(mContext,
                 mAppEntitiesHeaderView);
+        mAppEntityInfo = new AppEntityInfo.Builder()
+                .setIcon(mContext.getDrawable(R.drawable.ic_menu))
+                .setTitle(TITLE)
+                .setSummary(SUMMARY)
+                .setOnClickListener(v -> {
+                })
+                .build();
+        mController.setAppEntity(0, mAppEntityInfo);
     }
 
     @Test
@@ -91,26 +97,26 @@
     public void setAppEntity_indexLessThanZero_shouldThrowArrayIndexOutOfBoundsException() {
         thrown.expect(ArrayIndexOutOfBoundsException.class);
 
-        mController.setAppEntity(-1, mIcon, TITLE, SUMMARY);
+        mController.setAppEntity(-1, mAppEntityInfo);
     }
 
     @Test
     public void asetAppEntity_indexGreaterThanMaximum_shouldThrowArrayIndexOutOfBoundsException() {
         thrown.expect(ArrayIndexOutOfBoundsException.class);
 
-        mController.setAppEntity(AppEntitiesHeaderController.MAXIMUM_APPS + 1, mIcon, TITLE,
-                SUMMARY);
+        mController.setAppEntity(AppEntitiesHeaderController.MAXIMUM_APPS + 1, mAppEntityInfo);
     }
 
     @Test
     public void setAppEntity_addAppToIndex0_shouldShowAppView1() {
-        mController.setAppEntity(0, mIcon, TITLE, SUMMARY).apply();
+        mController.setAppEntity(0, mAppEntityInfo).apply();
         final View app1View = mAppEntitiesHeaderView.findViewById(R.id.app1_view);
         final ImageView appIconView = app1View.findViewById(R.id.app_icon);
         final TextView appTitle = app1View.findViewById(R.id.app_title);
         final TextView appSummary = app1View.findViewById(R.id.app_summary);
 
         assertThat(app1View.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(app1View.hasOnClickListeners()).isTrue();
         assertThat(appIconView.getDrawable()).isNotNull();
         assertThat(appTitle.getText()).isEqualTo(TITLE);
         assertThat(appSummary.getText()).isEqualTo(SUMMARY);
@@ -118,13 +124,14 @@
 
     @Test
     public void setAppEntity_addAppToIndex1_shouldShowAppView2() {
-        mController.setAppEntity(1, mIcon, TITLE, SUMMARY).apply();
+        mController.setAppEntity(1, mAppEntityInfo).apply();
         final View app2View = mAppEntitiesHeaderView.findViewById(R.id.app2_view);
         final ImageView appIconView = app2View.findViewById(R.id.app_icon);
         final TextView appTitle = app2View.findViewById(R.id.app_title);
         final TextView appSummary = app2View.findViewById(R.id.app_summary);
 
         assertThat(app2View.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(app2View.hasOnClickListeners()).isTrue();
         assertThat(appIconView.getDrawable()).isNotNull();
         assertThat(appTitle.getText()).isEqualTo(TITLE);
         assertThat(appSummary.getText()).isEqualTo(SUMMARY);
@@ -132,13 +139,14 @@
 
     @Test
     public void setAppEntity_addAppToIndex2_shouldShowAppView3() {
-        mController.setAppEntity(2, mIcon, TITLE, SUMMARY).apply();
+        mController.setAppEntity(2, mAppEntityInfo).apply();
         final View app3View = mAppEntitiesHeaderView.findViewById(R.id.app3_view);
         final ImageView appIconView = app3View.findViewById(R.id.app_icon);
         final TextView appTitle = app3View.findViewById(R.id.app_title);
         final TextView appSummary = app3View.findViewById(R.id.app_summary);
 
         assertThat(app3View.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(app3View.hasOnClickListeners()).isTrue();
         assertThat(appIconView.getDrawable()).isNotNull();
         assertThat(appTitle.getText()).isEqualTo(TITLE);
         assertThat(appSummary.getText()).isEqualTo(SUMMARY);
@@ -146,8 +154,8 @@
 
     @Test
     public void removeAppEntity_removeIndex0_shouldNotShowAppView1() {
-        mController.setAppEntity(0, mIcon, TITLE, SUMMARY)
-                .setAppEntity(1, mIcon, TITLE, SUMMARY).apply();
+        mController.setAppEntity(0, mAppEntityInfo)
+                .setAppEntity(1, mAppEntityInfo).apply();
         final View app1View = mAppEntitiesHeaderView.findViewById(R.id.app1_view);
         final View app2View = mAppEntitiesHeaderView.findViewById(R.id.app2_view);
 
@@ -162,9 +170,11 @@
 
     @Test
     public void clearAllAppEntities_shouldNotShowAllAppViews() {
-        mController.setAppEntity(0, mIcon, TITLE, SUMMARY)
-                .setAppEntity(1, mIcon, TITLE, SUMMARY)
-                .setAppEntity(2, mIcon, TITLE, SUMMARY).apply();
+        mController.setAppEntity(0, mAppEntityInfo)
+                .setAppEntity(1, mAppEntityInfo)
+                .setAppEntity(2, mAppEntityInfo).apply();
+        final View appViewsContainer = mAppEntitiesHeaderView.findViewById(
+                R.id.app_views_container);
         final View app1View = mAppEntitiesHeaderView.findViewById(R.id.app1_view);
         final View app2View = mAppEntitiesHeaderView.findViewById(R.id.app2_view);
         final View app3View = mAppEntitiesHeaderView.findViewById(R.id.app3_view);
@@ -174,8 +184,28 @@
         assertThat(app3View.getVisibility()).isEqualTo(View.VISIBLE);
 
         mController.clearAllAppEntities().apply();
-        assertThat(app1View.getVisibility()).isEqualTo(View.GONE);
-        assertThat(app2View.getVisibility()).isEqualTo(View.GONE);
-        assertThat(app3View.getVisibility()).isEqualTo(View.GONE);
+
+        assertThat(appViewsContainer.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void apply_noAppEntitySet_shouldOnlyShowTitleAndEmptyView() {
+        mController.setHeaderTitleRes(R.string.expand_button_title)
+                .setAppEntity(0, mAppEntityInfo)
+                .setAppEntity(1, mAppEntityInfo)
+                .setAppEntity(2, mAppEntityInfo).apply();
+        final View titleView = mAppEntitiesHeaderView.findViewById(R.id.header_title);
+        final View detailsView = mAppEntitiesHeaderView.findViewById(R.id.header_details);
+        final View emptyView = mAppEntitiesHeaderView.findViewById(R.id.empty_view);
+        final View appViewsContainer = mAppEntitiesHeaderView.findViewById(
+                R.id.app_views_container);
+
+        mController.clearAllAppEntities().apply();
+
+        assertThat(titleView.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(emptyView.getVisibility()).isEqualTo(View.VISIBLE);
+
+        assertThat(detailsView.getVisibility()).isEqualTo(View.GONE);
+        assertThat(appViewsContainer.getVisibility()).isEqualTo(View.GONE);
     }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartInfoTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartInfoTest.java
new file mode 100644
index 0000000..29d57b7
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartInfoTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.view.View;
+
+import androidx.annotation.StringRes;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class BarChartInfoTest {
+
+    @Rule
+    public final ExpectedException thrown = ExpectedException.none();
+    @StringRes
+    private final int mTitle = 0x11111111;
+    @StringRes
+    private final int mDetails = 0x22222222;
+    @StringRes
+    private final int mEmptyText = 0x33333333;
+    private final View.OnClickListener mClickListener = v -> {
+    };
+
+    @Test
+    public void builder_shouldSetFieldsInTheInfo() {
+        final BarChartInfo barChartInfo = new BarChartInfo.Builder()
+                .setTitle(mTitle)
+                .setDetails(mDetails)
+                .setEmptyText(mEmptyText)
+                .setDetailsOnClickListener(mClickListener)
+                .build();
+        assertThat(barChartInfo.getTitle()).isEqualTo(mTitle);
+        assertThat(barChartInfo.getDetails()).isEqualTo(mDetails);
+        assertThat(barChartInfo.getEmptyText()).isEqualTo(mEmptyText);
+        assertThat(barChartInfo.getDetailsOnClickListener()).isEqualTo(mClickListener);
+    }
+
+    @Test
+    public void builder_noTitle_shouldThrowIllegalStateException() {
+        thrown.expect(IllegalStateException.class);
+
+        new BarChartInfo.Builder()
+                .setDetails(mDetails)
+                .setEmptyText(mEmptyText)
+                .setDetailsOnClickListener(mClickListener)
+                .build();
+    }
+
+    @Test
+    public void addBarViewInfo_oneBarViewInfo_shouldSetOneBarViewInfo() {
+        final BarViewInfo barViewInfo = new BarViewInfo(
+                null /* icon */,
+                50,
+                mTitle);
+
+        final BarChartInfo mBarChartInfo = new BarChartInfo.Builder()
+                .setTitle(mTitle)
+                .setDetails(mDetails)
+                .setEmptyText(mEmptyText)
+                .setDetailsOnClickListener(mClickListener)
+                .addBarViewInfo(barViewInfo)
+                .build();
+
+        assertThat(mBarChartInfo.getBarViewInfos().length).isEqualTo(1);
+        assertThat(mBarChartInfo.getBarViewInfos()[0]).isEqualTo(barViewInfo);
+    }
+
+    @Test
+    public void addBarViewInfo_maxNumberOfInfoAllowed_shouldSetMaxBarViewInfos() {
+        final BarViewInfo barViewInfo = new BarViewInfo(
+                null /* icon */,
+                50,
+                mTitle);
+        final BarChartInfo mBarChartInfo = new BarChartInfo.Builder()
+                .setTitle(mTitle)
+                .setDetails(mDetails)
+                .setEmptyText(mEmptyText)
+                .setDetailsOnClickListener(mClickListener)
+                .addBarViewInfo(barViewInfo)
+                .addBarViewInfo(barViewInfo)
+                .addBarViewInfo(barViewInfo)
+                .addBarViewInfo(barViewInfo)
+                .build();
+
+        assertThat(mBarChartInfo.getBarViewInfos().length).isEqualTo(4);
+    }
+
+    @Test
+    public void addBarViewInfo_moreInfosThanMaxAllowed_shouldThrowIllegalStateException() {
+        thrown.expect(IllegalStateException.class);
+
+        final BarViewInfo barViewInfo = new BarViewInfo(
+                null /* icon */,
+                50,
+                mTitle);
+        new BarChartInfo.Builder()
+                .setTitle(mTitle)
+                .setDetails(mDetails)
+                .setEmptyText(mEmptyText)
+                .setDetailsOnClickListener(mClickListener)
+                .addBarViewInfo(barViewInfo)
+                .addBarViewInfo(barViewInfo)
+                .addBarViewInfo(barViewInfo)
+                .addBarViewInfo(barViewInfo)
+                .addBarViewInfo(barViewInfo)
+                .build();
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
index 96e8995..cf6137d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,7 +26,9 @@
 import androidx.preference.PreferenceViewHolder;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
@@ -34,6 +36,9 @@
 @RunWith(RobolectricTestRunner.class)
 public class BarChartPreferenceTest {
 
+    @Rule
+    public final ExpectedException thrown = ExpectedException.none();
+
     private Context mContext;
     private View mBarChartView;
     private Drawable mIcon;
@@ -44,6 +49,7 @@
     private TextView mDetailsView;
     private PreferenceViewHolder mHolder;
     private BarChartPreference mPreference;
+    private BarChartInfo mBarChartInfo;
 
     @Before
     public void setUp() {
@@ -51,21 +57,31 @@
         mBarChartView = View.inflate(mContext, R.layout.settings_bar_chart, null /* parent */);
         mHolder = PreferenceViewHolder.createInstanceForTests(mBarChartView);
         mPreference = new BarChartPreference(mContext, null /* attrs */);
-        mPreference.setBarChartTitle(R.string.debug_app);
 
         mIcon = mContext.getDrawable(R.drawable.ic_menu);
-        mBarView1 = (BarView) mBarChartView.findViewById(R.id.bar_view1);
-        mBarView2 = (BarView) mBarChartView.findViewById(R.id.bar_view2);
-        mBarView3 = (BarView) mBarChartView.findViewById(R.id.bar_view3);
-        mBarView4 = (BarView) mBarChartView.findViewById(R.id.bar_view4);
-        mDetailsView = (TextView) mBarChartView.findViewById(R.id.bar_chart_details);
+        mBarView1 = mBarChartView.findViewById(R.id.bar_view1);
+        mBarView2 = mBarChartView.findViewById(R.id.bar_view2);
+        mBarView3 = mBarChartView.findViewById(R.id.bar_view3);
+        mBarView4 = mBarChartView.findViewById(R.id.bar_view4);
+        mDetailsView = mBarChartView.findViewById(R.id.bar_chart_details);
+
+        mBarChartInfo = new BarChartInfo.Builder()
+                .setTitle(R.string.debug_app)
+                .setDetails(R.string.debug_app)
+                .setEmptyText(R.string.debug_app)
+                .setDetailsOnClickListener(v -> {
+                })
+                .build();
     }
 
     @Test
-    public void setBarChartTitleRes_setTitleRes_showInBarChartTitle() {
-        final TextView titleView = (TextView) mBarChartView.findViewById(R.id.bar_chart_title);
+    public void initializeBarChart_titleSet_shouldSetTitleInChartView() {
+        final TextView titleView = mBarChartView.findViewById(R.id.bar_chart_title);
+        final BarChartInfo barChartInfo = new BarChartInfo.Builder()
+                .setTitle(R.string.debug_app)
+                .build();
 
-        mPreference.setBarChartTitle(R.string.debug_app);
+        mPreference.initializeBarChart(barChartInfo);
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(titleView.getVisibility()).isEqualTo(View.VISIBLE);
@@ -73,21 +89,33 @@
     }
 
     @Test
-    public void onBindViewHolder_notSetDetailsRes_barChartDetailsViewIsGone() {
-        // We don't call BarChartPreference#setBarChartDetails
+    public void initializeBarChart_noBarViewSet_shouldShowTitleAndEmptyView() {
+        final BarChartInfo barChartInfo = new BarChartInfo.Builder()
+                .setTitle(R.string.debug_app)
+                .setEmptyText(R.string.debug_app)
+                .build();
+
+        mPreference.initializeBarChart(barChartInfo);
+        // We don't add any bar view yet.
         mPreference.onBindViewHolder(mHolder);
 
-        assertThat(mDetailsView.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mBarChartView.findViewById(R.id.bar_chart_title).getVisibility())
+                .isEqualTo(View.VISIBLE);
+        assertThat(mBarChartView.findViewById(R.id.empty_view).getVisibility())
+                .isEqualTo(View.VISIBLE);
+        assertThat(mBarChartView.findViewById(R.id.bar_views_container).getVisibility())
+                .isEqualTo(View.GONE);
     }
 
     @Test
-    public void onBindViewHolder_notSetDetailsRes_barChartDetailsViewIsGoneThenReappears() {
-        // We don't call BarChartPreference#setBarChartDetails yet.
-        mPreference.onBindViewHolder(mHolder);
+    public void initializeBarChart_detailsSet_shouldShowBarChartDetailsView() {
+        final BarChartInfo barChartInfo = new BarChartInfo.Builder()
+                .setTitle(R.string.debug_app)
+                .setDetails(R.string.debug_app)
+                .addBarViewInfo(new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app))
+                .build();
 
-        assertThat(mDetailsView.getVisibility()).isEqualTo(View.GONE);
-
-        mPreference.setBarChartDetails(R.string.debug_app);
+        mPreference.initializeBarChart(barChartInfo);
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mDetailsView.getVisibility()).isEqualTo(View.VISIBLE);
@@ -95,19 +123,30 @@
     }
 
     @Test
-    public void setBarChartDetailsRes_setDetailsRes_showInBarChartDetails() {
-        mPreference.setBarChartDetails(R.string.debug_app);
+    public void initializeBarChart_detailsNotSet_shouldHideBarChartDetailsView() {
+        // We don't call BarChartInfo.Builder#setDetails yet.
+        final BarChartInfo barChartInfo = new BarChartInfo.Builder()
+                .setTitle(R.string.debug_app)
+                .addBarViewInfo(new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app))
+                .build();
+
+        mPreference.initializeBarChart(barChartInfo);
         mPreference.onBindViewHolder(mHolder);
 
-        assertThat(mDetailsView.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mDetailsView.getText()).isEqualTo(mContext.getText(R.string.debug_app));
+        assertThat(mDetailsView.getVisibility()).isEqualTo(View.GONE);
     }
 
     @Test
-    public void setBarChartDetailsClickListener_setClickListener_detailsViewAttachClickListener() {
-        mPreference.setBarChartDetails(R.string.debug_app);
-        mPreference.setBarChartDetailsClickListener(v -> {
-        });
+    public void initializeBarChart_clickListenerSet_shouldSetClickListenerOnDetailsView() {
+        final BarChartInfo barChartInfo = new BarChartInfo.Builder()
+                .setTitle(R.string.debug_app)
+                .setDetails(R.string.debug_app)
+                .setDetailsOnClickListener(v -> {
+                })
+                .addBarViewInfo(new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app))
+                .build();
+
+        mPreference.initializeBarChart(barChartInfo);
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mDetailsView.getVisibility()).isEqualTo(View.VISIBLE);
@@ -115,12 +154,13 @@
     }
 
     @Test
-    public void setAllBarViewsInfo_setOneBarViewInfo_showOneBarView() {
+    public void setBarViewInfos_oneBarViewInfoSet_shouldShowOneBarView() {
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
                 new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app)
         };
 
-        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.initializeBarChart(mBarChartInfo);
+        mPreference.setBarViewInfos(barViewsInfo);
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
@@ -132,13 +172,14 @@
     }
 
     @Test
-    public void setAllBarViewsInfo_setTwoBarViewsInfo_showTwoBarViews() {
+    public void setBarViewInfos_twoBarViewInfosSet_shouldShowTwoBarViews() {
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
                 new BarViewInfo(mIcon, 20 /* barNumber */, R.string.debug_app),
                 new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app)
         };
 
-        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.initializeBarChart(mBarChartInfo);
+        mPreference.setBarViewInfos(barViewsInfo);
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
@@ -151,14 +192,15 @@
     }
 
     @Test
-    public void setAllBarViewsInfo_setThreeBarViewsInfo_showThreeBarViews() {
+    public void setBarViewInfos_threeBarViewInfosSet_shouldShowThreeBarViews() {
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
                 new BarViewInfo(mIcon, 20 /* barNumber */, R.string.debug_app),
                 new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
                 new BarViewInfo(mIcon, 5 /* barNumber */, R.string.debug_app)
         };
 
-        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.initializeBarChart(mBarChartInfo);
+        mPreference.setBarViewInfos(barViewsInfo);
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
@@ -172,7 +214,7 @@
     }
 
     @Test
-    public void setAllBarViewsInfo_setFourBarViewsInfo_showFourBarViews() {
+    public void setBarViewInfos_fourBarViewInfosSet_shouldShowFourBarViews() {
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
                 new BarViewInfo(mIcon, 20 /* barNumber */, R.string.debug_app),
                 new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
@@ -180,7 +222,8 @@
                 new BarViewInfo(mIcon, 2 /* barNumber */, R.string.debug_app),
         };
 
-        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.initializeBarChart(mBarChartInfo);
+        mPreference.setBarViewInfos(barViewsInfo);
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
@@ -194,7 +237,22 @@
     }
 
     @Test
-    public void setAllBarViewsInfo_setFourBarViewsInfo_barViewWasSortedInDescending() {
+    public void setBarViewInfos_moreInfosThanMaxAllowed_shouldThrowIllegalStateException() {
+        thrown.expect(IllegalStateException.class);
+
+        final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
+                new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app),
+                new BarViewInfo(mIcon, 50 /* barNumber */, R.string.debug_app),
+                new BarViewInfo(mIcon, 5 /* barNumber */, R.string.debug_app),
+                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
+                new BarViewInfo(mIcon, 70 /* barNumber */, R.string.debug_app),
+        };
+
+        mPreference.setBarViewInfos(barViewsInfo);
+    }
+
+    @Test
+    public void setBarViewInfos_barViewInfosSet_shouldBeSortedInDescending() {
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
                 new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app),
                 new BarViewInfo(mIcon, 50 /* barNumber */, R.string.debug_app),
@@ -202,7 +260,8 @@
                 new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
         };
 
-        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.initializeBarChart(mBarChartInfo);
+        mPreference.setBarViewInfos(barViewsInfo);
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
@@ -216,12 +275,13 @@
     }
 
     @Test
-    public void setAllBarViewsInfo_setValidSummaryRes_barViewShouldShowSummary() {
+    public void setBarViewInfos_validBarViewSummarySet_barViewShouldShowSummary() {
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
                 new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
         };
 
-        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.initializeBarChart(mBarChartInfo);
+        mPreference.setBarViewInfos(barViewsInfo);
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
@@ -229,13 +289,14 @@
     }
 
     @Test
-    public void setAllBarViewsInfo_setClickListenerForBarView_barViewAttachClickListener() {
+    public void setBarViewInfos_clickListenerForBarViewSet_barViewShouldHaveClickListener() {
         final BarViewInfo viewInfo = new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app);
         viewInfo.setClickListener(v -> {
         });
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{viewInfo};
 
-        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.initializeBarChart(mBarChartInfo);
+        mPreference.setBarViewInfos(barViewsInfo);
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index de86789..dbeee1c 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -40,11 +40,8 @@
     <bool name="def_wifi_display_on">false</bool>
     <bool name="def_install_non_market_apps">false</bool>
     <bool name="def_package_verifier_enable">true</bool>
-    <!-- Comma-separated list of location providers.
-         Network location is off by default because it requires
-         user opt-in via Setup Wizard or Settings.
-    -->
-    <string name="def_location_providers_allowed" translatable="false">gps</string>
+    <!-- Comma-separated list of location providers -->
+    <string name="def_location_providers_allowed" translatable="false">gps,network</string>
     <bool name="assisted_gps_enabled">true</bool>
     <bool name="def_netstats_enabled">true</bool>
     <bool name="def_usb_mass_storage_enabled">true</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index e853399..ef90dc9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -28,8 +28,8 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteStatement;
-import android.media.AudioSystem;
 import android.media.AudioManager;
+import android.media.AudioSystem;
 import android.net.ConnectivityManager;
 import android.os.Build;
 import android.os.Environment;
@@ -1104,9 +1104,7 @@
         }
 
         if (upgradeVersion == 77) {
-            // Introduce "vibrate when ringing" setting
-            loadVibrateWhenRingingSetting(db);
-
+            // "vibrate when ringing" setting moved to SettingsProvider version 168
             upgradeVersion = 78;
         }
 
@@ -2223,8 +2221,6 @@
         } finally {
             if (stmt != null) stmt.close();
         }
-
-        loadVibrateWhenRingingSetting(db);
     }
 
     private void loadVibrateSetting(SQLiteDatabase db, boolean deleteOld) {
@@ -2250,24 +2246,6 @@
         }
     }
 
-    private void loadVibrateWhenRingingSetting(SQLiteDatabase db) {
-        // The default should be off. VIBRATE_SETTING_ONLY_SILENT should also be ignored here.
-        // Phone app should separately check whether AudioManager#getRingerMode() returns
-        // RINGER_MODE_VIBRATE, with which the device should vibrate anyway.
-        int vibrateSetting = getIntValueFromSystem(db, Settings.System.VIBRATE_ON,
-                AudioManager.VIBRATE_SETTING_OFF);
-        boolean vibrateWhenRinging = ((vibrateSetting & 3) == AudioManager.VIBRATE_SETTING_ON);
-
-        SQLiteStatement stmt = null;
-        try {
-            stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
-                    + " VALUES(?,?);");
-            loadSetting(stmt, Settings.System.VIBRATE_WHEN_RINGING, vibrateWhenRinging ? 1 : 0);
-        } finally {
-            if (stmt != null) stmt.close();
-        }
-    }
-
     private void loadSettings(SQLiteDatabase db) {
         loadSystemSettings(db);
         loadSecureSettings(db);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index f2b2719..d0ffe7a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -242,7 +242,7 @@
                 Bundle args = new Bundle();
                 args.putInt(Settings.CALL_METHOD_USER_KEY,
                         ActivityManager.getService().getCurrentUser().id);
-                Bundle b = provider.call(resolveCallingPackage(),
+                Bundle b = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
                         Settings.CALL_METHOD_DELETE_CONFIG, compositeKey, args);
                 success = (b != null && b.getInt(SettingsProvider.RESULT_ROWS_DELETED) == 1);
             } catch (RemoteException e) {
@@ -261,7 +261,7 @@
                 if (namespace != null) {
                     args.putString(Settings.CALL_METHOD_PREFIX_KEY, namespace);
                 }
-                Bundle b = provider.call(resolveCallingPackage(),
+                Bundle b = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
                         Settings.CALL_METHOD_LIST_CONFIG, null, args);
                 if (b != null) {
                     Map<String, String> flagsToValues =
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index e3d3d81..64d68bf 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.provider.Settings.Global;
 import android.providers.settings.GlobalSettingsProto;
 import android.providers.settings.SecureSettingsProto;
 import android.providers.settings.SettingProto;
@@ -397,7 +396,7 @@
         p.end(certPinToken);
 
         dumpSetting(s, p,
-                Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
+                Settings.Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
                 GlobalSettingsProto.CHAINED_BATTERY_ATTRIBUTION_ENABLED);
         dumpSetting(s, p,
                 Settings.Global.COMPATIBILITY_MODE,
@@ -705,8 +704,20 @@
                 Settings.Global.GPU_DEBUG_LAYERS_GLES,
                 GlobalSettingsProto.Gpu.DEBUG_LAYERS_GLES);
         dumpSetting(s, p,
-                Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP,
-                GlobalSettingsProto.Gpu.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP);
+                Settings.Global.GUP_DEV_ALL_APPS,
+                GlobalSettingsProto.Gpu.GUP_DEV_ALL_APPS);
+        dumpSetting(s, p,
+                Settings.Global.GUP_DEV_OPT_IN_APPS,
+                GlobalSettingsProto.Gpu.GUP_DEV_OPT_IN_APPS);
+        dumpSetting(s, p,
+                Settings.Global.GUP_DEV_OPT_OUT_APPS,
+                GlobalSettingsProto.Gpu.GUP_DEV_OPT_OUT_APPS);
+        dumpSetting(s, p,
+                Settings.Global.GUP_BLACKLIST,
+                GlobalSettingsProto.Gpu.GUP_BLACKLIST);
+        dumpSetting(s, p,
+                Settings.Global.GAME_DRIVER_WHITELIST,
+                GlobalSettingsProto.Gpu.GAME_DRIVER_WHITELIST);
         p.end(gpuToken);
 
         final long hdmiToken = p.start(GlobalSettingsProto.HDMI);
@@ -728,7 +739,7 @@
                 Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
                 GlobalSettingsProto.HEADS_UP_NOTIFICATIONS_ENABLED);
         dumpSetting(s, p,
-                Global.HIDDEN_API_BLACKLIST_EXEMPTIONS,
+                Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS,
                 GlobalSettingsProto.HIDDEN_API_BLACKLIST_EXEMPTIONS);
 
         final long inetCondToken = p.start(GlobalSettingsProto.INET_CONDITION);
@@ -823,6 +834,15 @@
         dumpSetting(s, p,
                 Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
                 GlobalSettingsProto.LowPowerMode.AUTOMATIC_POWER_SAVER_MODE);
+        dumpSetting(s, p,
+                Settings.Global.LOW_POWER_MODE_STICKY,
+                GlobalSettingsProto.LowPowerMode.STICKY_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
+                GlobalSettingsProto.LowPowerMode.STICKY_AUTO_DISABLE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL,
+                GlobalSettingsProto.LowPowerMode.STICKY_AUTO_DISABLE_LEVEL);
         p.end(lpmToken);
 
         dumpSetting(s, p,
@@ -873,7 +893,7 @@
         p.end(multiSimToken);
 
         dumpSetting(s, p,
-                Global.NATIVE_FLAGS_HEALTH_CHECK_ENABLED,
+                Settings.Global.NATIVE_FLAGS_HEALTH_CHECK_ENABLED,
                 GlobalSettingsProto.NATIVE_FLAGS_HEALTH_CHECK_ENABLED);
 
         final long netstatsToken = p.start(GlobalSettingsProto.NETSTATS);
@@ -1100,9 +1120,6 @@
         dumpSetting(s, p,
                 Settings.Global.POWER_MANAGER_CONSTANTS,
                 GlobalSettingsProto.POWER_MANAGER_CONSTANTS);
-        dumpSetting(s, p,
-                Settings.Global.PRIV_APP_OOB_ENABLED,
-                GlobalSettingsProto.PRIV_APP_OOB_ENABLED);
 
         final long prepaidSetupToken = p.start(GlobalSettingsProto.PREPAID_SETUP);
         dumpSetting(s, p,
@@ -1253,10 +1270,10 @@
 
         final long soundTriggerToken = p.start(GlobalSettingsProto.SOUND_TRIGGER);
         dumpSetting(s, p,
-                Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
+                Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
                 GlobalSettingsProto.SoundTrigger.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY);
         dumpSetting(s, p,
-                Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT,
+                Settings.Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT,
                 GlobalSettingsProto.SoundTrigger.DETECTION_SERVICE_OP_TIMEOUT_MS);
         p.end(soundTriggerToken);
 
@@ -1551,6 +1568,10 @@
                 Settings.Global.ZRAM_ENABLED,
                 GlobalSettingsProto.ZRAM_ENABLED);
 
+        dumpSetting(s, p,
+                Settings.Global.APP_OPS_CONSTANTS,
+                GlobalSettingsProto.APP_OPS_CONSTANTS);
+
         p.end(token);
         // Please insert new settings using the same order as in GlobalSettingsProto.
 
@@ -1869,6 +1890,9 @@
         dumpSetting(s, p,
                 Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
                 SecureSettingsProto.Doze.PULSE_ON_DOUBLE_TAP);
+        dumpSetting(s, p,
+                Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
+                SecureSettingsProto.Doze.PULSE_ON_TAP);
         p.end(dozeToken);
 
         dumpSetting(s, p,
@@ -2353,6 +2377,18 @@
                 SecureSettingsProto.Zen.SETTINGS_SUGGESTION_VIEWED);
         p.end(zenToken);
 
+        dumpSetting(s, p,
+                Settings.Secure.SKIP_GESTURE,
+                SecureSettingsProto.SKIP_GESTURE_ENABLED);
+
+        dumpSetting(s, p,
+                Settings.Secure.SILENCE_GESTURE,
+                SecureSettingsProto.SILENCE_GESTURE_ENABLED);
+
+        dumpSetting(s, p,
+                Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
+                SecureSettingsProto.THEME_CUSTOMIZATION_OVERLAY_PACKAGES);
+
         // Please insert new settings using the same order as in SecureSettingsProto.
         p.end(token);
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index ce529a0..4453121 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -84,6 +84,8 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 
+import com.google.android.collect.Sets;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
@@ -957,12 +959,12 @@
         UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class);
         userManager.addUserRestrictionsListener((int userId, Bundle newRestrictions,
                 Bundle prevRestrictions) -> {
+            Set<String> changedRestrictions = getRestrictionDiff(prevRestrictions, newRestrictions);
             // We are changing the settings affected by restrictions to their current
             // value with a forced update to ensure that all cross profile dependencies
             // are taken into account. Also make sure the settings update to.. the same
             // value passes the security checks, so clear binder calling id.
-            if (newRestrictions.getBoolean(UserManager.DISALLOW_SHARE_LOCATION)
-                    != prevRestrictions.getBoolean(UserManager.DISALLOW_SHARE_LOCATION)) {
+            if (changedRestrictions.contains(UserManager.DISALLOW_SHARE_LOCATION)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
@@ -976,11 +978,8 @@
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            if (newRestrictions.getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)
-                    != prevRestrictions.getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES) ||
-                    newRestrictions.getBoolean(
-                            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY)
-                    != prevRestrictions.getBoolean(
+            if (changedRestrictions.contains(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)
+                    || changedRestrictions.contains(
                             UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
@@ -994,8 +993,7 @@
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            if (newRestrictions.getBoolean(UserManager.DISALLOW_DEBUGGING_FEATURES)
-                    != prevRestrictions.getBoolean(UserManager.DISALLOW_DEBUGGING_FEATURES)) {
+            if (changedRestrictions.contains(UserManager.DISALLOW_DEBUGGING_FEATURES)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
@@ -1008,8 +1006,7 @@
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            if (newRestrictions.getBoolean(UserManager.ENSURE_VERIFY_APPS)
-                    != prevRestrictions.getBoolean(UserManager.ENSURE_VERIFY_APPS)) {
+            if (changedRestrictions.contains(UserManager.ENSURE_VERIFY_APPS)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
@@ -1028,8 +1025,7 @@
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            if (newRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)
-                    != prevRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
+            if (changedRestrictions.contains(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
@@ -1046,13 +1042,27 @@
         });
     }
 
+    private static Set<String> getRestrictionDiff(Bundle prevRestrictions, Bundle newRestrictions) {
+        Set<String> restrictionNames = Sets.newArraySet();
+        restrictionNames.addAll(prevRestrictions.keySet());
+        restrictionNames.addAll(newRestrictions.keySet());
+        Set<String> diff = Sets.newArraySet();
+        for (String restrictionName : restrictionNames) {
+            if (prevRestrictions.getBoolean(restrictionName) != newRestrictions.getBoolean(
+                    restrictionName)) {
+                diff.add(restrictionName);
+            }
+        }
+        return diff;
+    }
+
     private Setting getConfigSetting(String name) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "getConfigSetting(" + name + ")");
         }
 
         // TODO(b/117663715): Ensure the caller can access the setting.
-        // enforceSettingReadable(name, SETTINGS_TYPE_CONFIG, UserHandle.getCallingUserId());
+        // enforceReadPermission(READ_DEVICE_CONFIG);
 
         // Get the value.
         synchronized (mLock) {
@@ -1088,8 +1098,9 @@
 
     private boolean mutateConfigSetting(String name, String value, String prefix,
             boolean makeDefault, int operation, int mode) {
-        // TODO(b/117663715): check the new permission when it's added.
-        // enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
+
+        // TODO(b/117663715): Ensure the caller can access the setting.
+        // enforceReadPermission(WRITE_DEVICE_CONFIG);
 
         // Perform the mutation.
         synchronized (mLock) {
@@ -1097,7 +1108,7 @@
                 case MUTATION_OPERATION_INSERT: {
                     return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_CONFIG,
                             UserHandle.USER_SYSTEM, name, value, null, makeDefault, true,
-                            getCallingPackage(), false, null);
+                            resolveCallingPackage(), false, null);
                 }
 
                 case MUTATION_OPERATION_DELETE: {
@@ -1107,7 +1118,7 @@
 
                 case MUTATION_OPERATION_RESET: {
                     mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_CONFIG,
-                            UserHandle.USER_SYSTEM, getCallingPackage(), mode, null, prefix);
+                            UserHandle.USER_SYSTEM, resolveCallingPackage(), mode, null, prefix);
                 } return true;
             }
         }
@@ -2247,6 +2258,22 @@
         return !(TextUtils.isEmpty(key) || SettingsState.isBinary(key));
     }
 
+    private String resolveCallingPackage() {
+        switch (Binder.getCallingUid()) {
+            case Process.ROOT_UID: {
+                return "root";
+            }
+
+            case Process.SHELL_UID: {
+                return "com.android.shell";
+            }
+
+            default: {
+                return getCallingPackage();
+            }
+        }
+    }
+
     private static final class Arguments {
         private static final Pattern WHERE_PATTERN_WITH_PARAM_NO_BRACKETS =
                 Pattern.compile("[\\s]*name[\\s]*=[\\s]*\\?[\\s]*");
@@ -3205,7 +3232,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 172;
+            private static final int SETTINGS_VERSION = 173;
 
             private final int mUserId;
 
@@ -4125,10 +4152,12 @@
                             Secure.CHARGING_SOUNDS_ENABLED);
 
                     if (!globalChargingSoundEnabled.isNull()) {
-                        secureSettings.insertSettingLocked(
-                                Secure.CHARGING_SOUNDS_ENABLED,
-                                globalChargingSoundEnabled.getValue(), null, false,
-                                SettingsState.SYSTEM_PACKAGE_NAME);
+                        if (secureChargingSoundsEnabled.isNull()) {
+                            secureSettings.insertSettingLocked(
+                                    Secure.CHARGING_SOUNDS_ENABLED,
+                                    globalChargingSoundEnabled.getValue(), null, false,
+                                    SettingsState.SYSTEM_PACKAGE_NAME);
+                        }
 
                         // set global charging_sounds_enabled setting to null since it's deprecated
                         globalSettings.insertSettingLocked(
@@ -4188,6 +4217,41 @@
                     currentVersion = 172;
                 }
 
+                if (currentVersion == 172) {
+                    // Version 172: Set the default value for Secure Settings: LOCATION_MODE
+
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+
+                    final Setting locationMode = secureSettings.getSettingLocked(
+                            Secure.LOCATION_MODE);
+
+                    if (locationMode.isNull()) {
+                        final Setting locationProvidersAllowed = secureSettings.getSettingLocked(
+                                Secure.LOCATION_PROVIDERS_ALLOWED);
+
+                        String defLocationMode = Integer.toString(
+                                !TextUtils.isEmpty(locationProvidersAllowed.getValue())
+                                        ? Secure.LOCATION_MODE_HIGH_ACCURACY
+                                        : Secure.LOCATION_MODE_OFF);
+                        secureSettings.insertSettingLocked(
+                                Secure.LOCATION_MODE, defLocationMode,
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+
+                        // also reset LOCATION_PROVIDERS_ALLOWED back to the default value - this
+                        // setting is now only for debug/test purposes, and will likely be removed
+                        // in a later release. LocationManagerService is responsible for adjusting
+                        // these settings to the proper state.
+
+                        String defLocationProvidersAllowed = getContext().getResources().getString(
+                                R.string.def_location_providers_allowed);
+                        secureSettings.insertSettingLocked(
+                                Secure.LOCATION_PROVIDERS_ALLOWED, defLocationProvidersAllowed,
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+
+                    currentVersion = 173;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/test/AndroidManifest.xml b/packages/SettingsProvider/test/AndroidManifest.xml
index 87a4f60..ebdf9b1 100644
--- a/packages/SettingsProvider/test/AndroidManifest.xml
+++ b/packages/SettingsProvider/test/AndroidManifest.xml
@@ -20,6 +20,8 @@
     <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
 
     <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/>
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
     <uses-permission android:name="android.permission.MANAGE_USERS"/>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 8cfc2a6..c3c3f25 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -57,6 +57,8 @@
     <uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
     <uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY" />
     <!-- Development tool permissions granted to the shell. -->
@@ -82,6 +84,7 @@
     <uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
     <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
     <uses-permission android:name="android.permission.DELETE_PACKAGES" />
+    <uses-permission android:name="android.permission.MANAGE_ROLLBACKS" />
     <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
@@ -128,11 +131,14 @@
     <uses-permission android:name="android.permission.VIBRATE" />
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
     <uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
+    <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
     <uses-permission android:name="android.permission.ACTIVITY_EMBEDDING" />
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
     <uses-permission android:name="android.permission.MANAGE_AUTO_FILL" />
     <uses-permission android:name="android.permission.MANAGE_CONTENT_CAPTURE" />
+    <uses-permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS" />
+    <uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS" />
     <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.SET_TIME" />
@@ -160,6 +166,10 @@
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
     <uses-permission android:name="android.permission.SUSPEND_APPS" />
     <uses-permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND" />
+    <!-- Permission needed to wipe the device for Test Harness Mode -->
+    <uses-permission android:name="android.permission.ENABLE_TEST_HARNESS_MODE" />
+
+    <uses-permission android:name="android.permission.MANAGE_APPOPS" />
 
     <application android:label="@string/app_label"
                  android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 2530abc..a9ff21f 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -56,6 +56,7 @@
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.annotation.MainThread;
+import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.app.AlertDialog;
 import android.app.Notification;
@@ -799,6 +800,18 @@
             Log.wtf(TAG, "Missing " + EXTRA_BUGREPORT + " on intent " + intent);
             return;
         }
+        final int max = intent.getIntExtra(EXTRA_MAX, -1);
+        final File screenshotFile = getFileExtra(intent, EXTRA_SCREENSHOT);
+        final String shareTitle = intent.getStringExtra(EXTRA_TITLE);
+        final String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION);
+        onBugreportFinished(id, bugreportFile, screenshotFile, shareTitle, shareDescription, max);
+    }
+
+    /**
+     * Wraps up bugreport generation and triggers a notification to share the bugreport.
+     */
+    private void onBugreportFinished(int id, File bugreportFile, @Nullable File screenshotFile,
+        String shareTitle, String shareDescription, int max) {
         mInfoDialog.onBugreportFinished();
         BugreportInfo info = getInfo(id);
         if (info == null) {
@@ -809,22 +822,17 @@
         }
         info.renameScreenshots(mScreenshotsDir);
         info.bugreportFile = bugreportFile;
+        if (screenshotFile != null) {
+            info.addScreenshot(screenshotFile);
+        }
 
-        final int max = intent.getIntExtra(EXTRA_MAX, -1);
         if (max != -1) {
             MetricsLogger.histogram(this, "dumpstate_duration", max);
             info.max = max;
         }
 
-        final File screenshot = getFileExtra(intent, EXTRA_SCREENSHOT);
-        if (screenshot != null) {
-            info.addScreenshot(screenshot);
-        }
-
-        final String shareTitle = intent.getStringExtra(EXTRA_TITLE);
         if (!TextUtils.isEmpty(shareTitle)) {
             info.title = shareTitle;
-            final String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION);
             if (!TextUtils.isEmpty(shareDescription)) {
                 info.shareDescription= shareDescription;
             }
@@ -1944,6 +1952,21 @@
         }
 
         @Override
+        public void onProgress(int progress) throws RemoteException {
+            updateProgressInfo(progress, 100 /* progress is already a percentage; so max = 100 */);
+        }
+
+        @Override
+        public void onError(int errorCode) throws RemoteException {
+            // TODO(b/111441001): implement
+        }
+
+        @Override
+        public void onFinished() throws RemoteException {
+            // TODO(b/111441001): implement
+        }
+
+        @Override
         public void onProgressUpdated(int progress) throws RemoteException {
             /*
              * Checks whether the progress changed in a way that should be displayed to the user:
@@ -1964,21 +1987,7 @@
             }
 
             if (newPercentage > oldPercentage) {
-                if (DEBUG) {
-                    if (progress != info.progress) {
-                        Log.v(TAG, "Updating progress for PID " + info.pid + "(id: " + info.id
-                                + ") from " + info.progress + " to " + progress);
-                    }
-                    if (max != info.max) {
-                        Log.v(TAG, "Updating max progress for PID " + info.pid + "(id: " + info.id
-                                + ") from " + info.max + " to " + max);
-                    }
-                }
-                info.progress = progress;
-                info.max = max;
-                info.lastUpdate = System.currentTimeMillis();
-
-                updateProgress(info);
+                updateProgressInfo(progress, max);
             }
         }
 
@@ -2000,5 +2009,23 @@
         public void dump(String prefix, PrintWriter pw) {
             pw.print(prefix); pw.print("token: "); pw.println(token);
         }
+
+        private void updateProgressInfo(int progress, int max) {
+            if (DEBUG) {
+                if (progress != info.progress) {
+                    Log.v(TAG, "Updating progress for PID " + info.pid + "(id: " + info.id
+                            + ") from " + info.progress + " to " + progress);
+                }
+                if (max != info.max) {
+                    Log.v(TAG, "Updating max progress for PID " + info.pid + "(id: " + info.id
+                            + ") from " + info.max + " to " + max);
+                }
+            }
+            info.progress = progress;
+            info.max = max;
+            info.lastUpdate = System.currentTimeMillis();
+
+            updateProgress(info);
+        }
     }
 }
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 1c1a140..3453e79 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -87,6 +87,7 @@
     <uses-permission android:name="android.permission.STOP_APP_SWITCHES" />
     <uses-permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" />
     <uses-permission android:name="android.permission.START_ANY_ACTIVITY" />
+    <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" />
@@ -385,6 +386,15 @@
             android:excludeFromRecents="true">
         </activity>
 
+        <!-- started from UsbPortManager -->
+        <activity android:name=".usb.UsbContaminantActivity"
+            android:exported="true"
+            android:permission="android.permission.MANAGE_USB"
+            android:theme="@style/Theme.SystemUI.Dialog.Alert"
+            android:finishOnCloseSystemDialogs="true"
+            android:excludeFromRecents="true">
+        </activity>
+
         <!-- started from AdbDebuggingManager -->
         <activity android:name=".usb.UsbDebuggingActivity"
             android:permission="android.permission.MANAGE_DEBUGGING"
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
index 4891e50..5317a6d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java
@@ -32,10 +32,11 @@
     void startPendingIntentDismissingKeyguard(PendingIntent intent);
 
     /**
-     * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent, Runnable)}, but
-     * allow you to specify the callback that is executed after the intent is sent.
+     * Similar to {@link #startPendingIntentDismissingKeyguard(PendingIntent, Runnable)}, but allows
+     * you to specify the callback that is executed on the UI thread after the intent is sent.
      */
-    void startPendingIntentDismissingKeyguard(PendingIntent intent, Runnable intentSentCallback);
+    void startPendingIntentDismissingKeyguard(PendingIntent intent,
+            Runnable intentSentUiThreadCallback);
     void startActivity(Intent intent, boolean dismissShade);
     void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade);
     void startActivity(Intent intent, boolean dismissShade, Callback callback);
diff --git a/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml b/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml
new file mode 100644
index 0000000..d3c3a51
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="200dp"
+    android:width="200dp"
+    android:viewportHeight="100"
+    android:viewportWidth="100">
+    <path
+        android:fillColor="#000000"
+        android:pathData="M50.082,14.199m-13.985,0a13.985,13.985 0,1 1,27.97 0a13.985,13.985 0,1 1,-27.97 0"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml b/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml
new file mode 100644
index 0000000..a4417fb
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="200dp"
+    android:width="200dp"
+    android:viewportHeight="100"
+    android:viewportWidth="100" >
+    <path
+        android:fillColor="#000000"
+        android:pathData="M50.082,0.025L50.082,0.025A13.985,15.63 0,0 1,64.067 15.656L64.067,49.029A13.985,15.63 0,0 1,50.082 64.659L50.082,64.659A13.985,15.63 0,0 1,36.097 49.029L36.097,15.656A13.985,15.63 0,0 1,50.082 0.025z"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
new file mode 100644
index 0000000..6f7f398
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<com.android.keyguard.clock.ClockLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+  >
+  <include
+      android:id="@+id/digital_clock"
+      layout="@layout/text_clock"
+  />
+  <com.android.keyguard.clock.ImageClock
+      android:id="@+id/analog_clock"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+  >
+    <ImageView
+        android:id="@+id/minute_hand"
+        android:layout_width="300dp"
+        android:layout_height="300dp"
+        android:src="@drawable/bubble_minute_hand"
+        android:tint="@color/bubbleMinuteHandColor"
+    />
+    <ImageView
+        android:id="@+id/hour_hand"
+        android:layout_width="300dp"
+        android:layout_height="300dp"
+        android:src="@drawable/bubble_hour_hand"
+        android:tint="@color/bubbleHourHandColor"
+    />
+  </com.android.keyguard.clock.ImageClock>
+</com.android.keyguard.clock.ClockLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/digital_clock.xml b/packages/SystemUI/res-keyguard/layout/digital_clock.xml
new file mode 100644
index 0000000..e88e2c9
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/digital_clock.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_horizontal"
+    android:layout_alignParentTop="true">
+  <include
+      android:id="@+id/lock_screen_clock"
+      layout="@layout/text_clock"
+  />
+</FrameLayout>
+
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index d52866f..463367b 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -30,17 +30,9 @@
          android:layout_height="wrap_content"
          android:layout_gravity="center_horizontal"
          android:layout_alignParentTop="true">
-        <TextClock
+        <include
              android:id="@+id/default_clock_view"
-             android:layout_width="wrap_content"
-             android:layout_height="wrap_content"
-             android:layout_gravity="center_horizontal"
-             android:letterSpacing="0.03"
-             android:textColor="?attr/wallpaperTextColor"
-             android:singleLine="true"
-             style="@style/widget_big"
-             android:format12Hour="@string/keyguard_widget_12_hours_format"
-             android:format24Hour="@string/keyguard_widget_24_hours_format" />
+             layout="@layout/text_clock" />
     </FrameLayout>
     <include layout="@layout/keyguard_status_area"
         android:id="@+id/keyguard_status_area"
diff --git a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
new file mode 100644
index 0000000..64b676f5
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<com.android.keyguard.clock.ClockLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+  >
+  <include
+      android:id="@+id/digital_clock"
+      layout="@layout/text_clock"
+  />
+  <com.android.keyguard.clock.StretchAnalogClock
+      android:id="@+id/analog_clock"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+  />
+</com.android.keyguard.clock.ClockLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/text_clock.xml b/packages/SystemUI/res-keyguard/layout/text_clock.xml
new file mode 100644
index 0000000..b61ad9c
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/text_clock.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<TextClock
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_horizontal"
+    android:letterSpacing="0.03"
+    android:textColor="?attr/wallpaperTextColor"
+    android:singleLine="true"
+    style="@style/widget_big"
+    android:format12Hour="@string/keyguard_widget_12_hours_format"
+    android:format24Hour="@string/keyguard_widget_24_hours_format"
+    android:elegantTextHeight="false"
+/>
diff --git a/packages/SystemUI/res-keyguard/layout/type_clock.xml b/packages/SystemUI/res-keyguard/layout/type_clock.xml
new file mode 100644
index 0000000..21c64e9
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/type_clock.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<com.android.keyguard.clock.ClockLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+  >
+  <com.android.keyguard.clock.TypographicClock
+      android:id="@+id/type_clock"
+      android:orientation="vertical"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+    >
+    <TextView
+        android:id="@+id/header"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="50dp"
+        style="@style/widget_big"
+        android:textColor="@color/typeClockAccentColor"
+        android:text="@string/type_clock_header"
+        android:textSize="40dp"
+    />
+    <TextView
+        android:id="@+id/hour"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="50dp"
+        style="@style/widget_big"
+        android:textSize="40dp"
+    />
+    <TextView
+        android:id="@+id/minute"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="50dp"
+        style="@style/widget_big"
+        android:textSize="40dp"
+    />
+  </com.android.keyguard.clock.TypographicClock>
+</com.android.keyguard.clock.ClockLayout>
diff --git a/packages/SystemUI/res-keyguard/values/colors.xml b/packages/SystemUI/res-keyguard/values/colors.xml
new file mode 100644
index 0000000..74ee7ff
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/values/colors.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<resources>
+  <!-- Default color for hour hand of Bubble clock. -->
+  <color name="bubbleHourHandColor">#C97343</color>
+  <!-- Default color for minute hand of Bubble clock. -->
+  <color name="bubbleMinuteHandColor">#F5C983</color>
+  <!-- Accent color for Typographic clock. -->
+  <color name="typeClockAccentColor">#F5C983</color>
+</resources>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 9245c30..e2ba23e 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -47,8 +47,6 @@
     <dimen name="bottom_text_spacing_digital">0dp</dimen>
     <!-- Slice subtitle -->
     <dimen name="widget_label_font_size">16dp</dimen>
-    <!-- Slice offset when pulsing -->
-    <dimen name="widget_pulsing_bottom_padding">48dp</dimen>
     <!-- Clock without header -->
     <dimen name="widget_big_font_size">64dp</dimen>
     <!-- Clock with header -->
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 1d5aa6d..7432f9c 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -402,4 +402,87 @@
 number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item>
     </plurals>
 
+    <!-- Header for typographic clock face. [CHAR LIMIT=8] -->
+    <string name="type_clock_header">It\u2019s</string>
+
+    <!-- Hour displayed in words on the typographic clock face. [CHAR LIMIT=8] -->
+    <string-array name="type_clock_hours">
+        <item>Twelve</item>
+        <item>One</item>
+        <item>Two</item>
+        <item>Three</item>
+        <item>Four</item>
+        <item>Five</item>
+        <item>Six</item>
+        <item>Seven</item>
+        <item>Eight</item>
+        <item>Nine</item>
+        <item>Ten</item>
+        <item>Eleven</item>
+    </string-array>
+
+    <!-- Minutes displayed in words on the typographic clock face. [CHAR LIMIT=16] -->
+    <string-array name="type_clock_minutes">
+        <item>O\u2019Clock</item>
+        <item>O\u2019One</item>
+        <item>O\u2019Two</item>
+        <item>O\u2019Three</item>
+        <item>O\u2019Four</item>
+        <item>O\u2019Five</item>
+        <item>O\u2019Six</item>
+        <item>O\u2019Seven</item>
+        <item>O\u2019Eight</item>
+        <item>O\u2019Nine</item>
+        <item>Ten</item>
+        <item>Eleven</item>
+        <item>Twelve</item>
+        <item>Thirteen</item>
+        <item>Fourteen</item>
+        <item>Fifteen</item>
+        <item>Sixteen</item>
+        <item>Seventeen</item>
+        <item>Eighteen</item>
+        <item>Nineteen</item>
+        <item>Twenty</item>
+        <item>Twenty\nOne</item>
+        <item>Twenty\nTwo</item>
+        <item>Twenty\nThree</item>
+        <item>Twenty\nFour</item>
+        <item>Twenty\nFive</item>
+        <item>Twenty\nSix</item>
+        <item>Twenty\nSeven</item>
+        <item>Twenty\nEight</item>
+        <item>Twenty\nNine</item>
+        <item>Thirty</item>
+        <item>Thirty\nOne</item>
+        <item>Thirty\nTwo</item>
+        <item>Thirty\nThree</item>
+        <item>Thirty\nFour</item>
+        <item>Thirty\nFive</item>
+        <item>Thirty\nSix</item>
+        <item>Thirty\nSeven</item>
+        <item>Thirty\nEight</item>
+        <item>Thirty\nNine</item>
+        <item>Forty</item>
+        <item>Forty\nOne</item>
+        <item>Forty\nTwo</item>
+        <item>Forty\nThree</item>
+        <item>Forty\nFour</item>
+        <item>Forty\nFive</item>
+        <item>Forty\nSix</item>
+        <item>Forty\nSeven</item>
+        <item>Forty\nEight</item>
+        <item>Forty\nNine</item>
+        <item>Fifty</item>
+        <item>Fifty\nOne</item>
+        <item>Fifty\nTwo</item>
+        <item>Fifty\nThree</item>
+        <item>Fifty\nFour</item>
+        <item>Fifty\nFive</item>
+        <item>Fifty\nSix</item>
+        <item>Fifty\nSeven</item>
+        <item>Fifty\nEight</item>
+        <item>Fifty\nNine</item>
+    </string-array>
+
 </resources>
diff --git a/packages/SystemUI/res/drawable/biometric_dialog_bg.xml b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
index d041556..0c6d57d 100644
--- a/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
+++ b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
@@ -18,7 +18,7 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
     <solid android:color="?android:attr/colorBackgroundFloating" />
-    <corners android:radius="1dp"
+    <corners
         android:topLeftRadius="@dimen/biometric_dialog_corner_size"
         android:topRightRadius="@dimen/biometric_dialog_corner_size"
         android:bottomLeftRadius="@dimen/biometric_dialog_corner_size"
diff --git a/packages/SystemUI/res/drawable/bubble_expanded_header_bg.xml b/packages/SystemUI/res/drawable/bubble_expanded_header_bg.xml
new file mode 100644
index 0000000..26bf981
--- /dev/null
+++ b/packages/SystemUI/res/drawable/bubble_expanded_header_bg.xml
@@ -0,0 +1,32 @@
+<?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
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="?android:attr/colorBackgroundFloating"/>
+            <corners
+                    android:topLeftRadius="@dimen/corner_size"
+                    android:topRightRadius="@dimen/corner_size"/>
+        </shape>
+    </item>
+    <item android:gravity="bottom">
+        <shape>
+            <size android:height="1dp"/>
+            <solid android:color="?android:attr/textColorSecondary" />
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/face_dialog_error_to_face.xml b/packages/SystemUI/res/drawable/face_dialog_error_to_face.xml
new file mode 100644
index 0000000..75311f4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/face_dialog_error_to_face.xml
@@ -0,0 +1,517 @@
+<?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
+  -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt">
+    <aapt:attr name="android:drawable">
+        <vector
+            android:width="60dp"
+            android:height="60dp"
+            android:viewportWidth="60"
+            android:viewportHeight="60">
+            <group android:name="_R_G">
+                <group
+                    android:name="_R_G_L_0_G_N_1_T_0"
+                    android:translateX="30"
+                    android:translateY="30">
+                    <group
+                        android:name="_R_G_L_0_G"
+                        android:translateX="-30"
+                        android:translateY="-30">
+                        <path
+                            android:name="_R_G_L_0_G_D_0_P_0"
+                            android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+                            android:strokeWidth="2.5"
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorError"
+                            android:trimPathStart="0"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0" />
+                        <path
+                            android:name="_R_G_L_0_G_D_1_P_0"
+                            android:pathData=" M34.78 38.76 C33.83,38.75 31.54,38.75 30.01,38.75 C26.97,38.75 26.14,38.75 24.3,38.76 "
+                            android:strokeWidth="2.5"
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorError"
+                            android:trimPathStart="0.34"
+                            android:trimPathEnd="0.5700000000000001"
+                            android:trimPathOffset="0" />
+                        <group
+                            android:name="_R_G_L_0_G_D_2_P_0_G_0_T_0"
+                            android:scaleX="0.3"
+                            android:scaleY="0.3"
+                            android:translateX="37.788"
+                            android:translateY="19.53">
+                            <path
+                                android:name="_R_G_L_0_G_D_2_P_0"
+                                android:fillAlpha="0"
+                                android:fillColor="@color/biometric_face_icon_gray"
+                                android:fillType="nonZero"
+                                android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.1,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0"
+                            android:scaleX="0.3"
+                            android:scaleY="0.3"
+                            android:translateX="22.005"
+                            android:translateY="19.51">
+                            <path
+                                android:name="_R_G_L_0_G_D_3_P_0"
+                                android:fillAlpha="0"
+                                android:fillColor="@color/biometric_face_icon_gray"
+                                android:fillType="nonZero"
+                                android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.2,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0"
+                            android:translateX="30.3"
+                            android:translateY="29.215">
+                            <path
+                                android:name="_R_G_L_0_G_D_4_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="?android:attr/colorError"
+                                android:fillType="nonZero"
+                                android:pathData=" M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-11.71 -1.5,-11.71 C-1.5,-11.71 0.9,-11.71 0.9,-11.71 C0.9,-11.71 0.9,3.25 0.9,3.25c " />
+                        </group>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+    <target android:name="_R_G_L_0_G_D_0_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="strokeColor"
+                    android:startOffset="0"
+                    android:valueFrom="?android:attr/colorError"
+                    android:valueTo="?android:attr/colorError"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="17"
+                    android:propertyName="strokeColor"
+                    android:startOffset="83"
+                    android:valueFrom="?android:attr/colorError"
+                    android:valueTo="@color/biometric_face_icon_gray"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="strokeColor"
+                    android:startOffset="0"
+                    android:valueFrom="?android:attr/colorError"
+                    android:valueTo="?android:attr/colorError"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="17"
+                    android:propertyName="strokeColor"
+                    android:startOffset="83"
+                    android:valueFrom="?android:attr/colorError"
+                    android:valueTo="@color/biometric_face_icon_gray"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="217"
+                    android:propertyName="strokeWidth"
+                    android:startOffset="0"
+                    android:valueFrom="2.5"
+                    android:valueTo="2"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="217"
+                    android:propertyName="pathData"
+                    android:startOffset="0"
+                    android:valueFrom="M34.78 38.76 C33.83,38.75 31.54,38.75 30.01,38.75 C26.97,38.75 26.14,38.75 24.3,38.76 "
+                    android:valueTo="M33.75 42.75 C32.75,43.76 31.37,44.39 29.83,44.39 C26.8,44.39 24.34,41.93 24.34,38.9 "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="217"
+                    android:propertyName="trimPathStart"
+                    android:startOffset="0"
+                    android:valueFrom="0.34"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="217"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="0"
+                    android:valueFrom="0.5700000000000001"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_2_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="17"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="83"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_2_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:pathData="M 37.788,19.53C 38.3400184636116,20.241653709411622 37.235981536388394,18.81834629058838 37.788,19.53"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:pathData="M 37.788,19.53C 38.3400184636116,20.241653709411622 40.5479815363884,23.08834629058838 41.1,23.8"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="50">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_2_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="0.3"
+                    android:valueTo="0.3"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="0.3"
+                    android:valueTo="0.3"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="scaleX"
+                    android:startOffset="50"
+                    android:valueFrom="0.3"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="scaleY"
+                    android:startOffset="50"
+                    android:valueFrom="0.3"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="17"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="83"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:pathData="M 22.005,19.51C 21.43742198228836,20.224974105358122 22.57257801771164,18.79502589464188 22.005,19.51"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:pathData="M 22.005,19.51C 21.43742198228836,20.224974105358122 19.16757801771164,23.08502589464188 18.6,23.8"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="50">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="0.3"
+                    android:valueTo="0.3"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="0.3"
+                    android:valueTo="0.3"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="scaleX"
+                    android:startOffset="50"
+                    android:valueFrom="0.3"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="117"
+                    android:propertyName="scaleY"
+                    android:startOffset="50"
+                    android:valueFrom="0.3"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_4_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="fillColor"
+                    android:startOffset="0"
+                    android:valueFrom="?android:attr/colorError"
+                    android:valueTo="?android:attr/colorError"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="17"
+                    android:propertyName="fillColor"
+                    android:startOffset="83"
+                    android:valueFrom="?android:attr/colorError"
+                    android:valueTo="@color/biometric_face_icon_gray"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="150"
+                    android:pathData="M 30.3,29.215C 30.3,29.58759101867676 30.3,31.077408981323238 30.3,31.45"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_4_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="pathData"
+                    android:startOffset="0"
+                    android:valueFrom="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-11.71 -1.5,-11.71 C-1.5,-11.71 0.9,-11.71 0.9,-11.71 C0.9,-11.71 0.9,3.25 0.9,3.25c "
+                    android:valueTo="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-3.25 -1.5,-3.25 C-1.5,-3.25 0.9,-3.25 0.9,-3.25 C0.9,-3.25 0.9,3.25 0.9,3.25c "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.321,0 0.67,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="133"
+                    android:propertyName="pathData"
+                    android:startOffset="83"
+                    android:valueFrom="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-3.25 -1.5,-3.25 C-1.5,-3.25 0.9,-3.25 0.9,-3.25 C0.9,-3.25 0.9,3.25 0.9,3.25c "
+                    android:valueTo="M2.6 3.25 C2.6,3.25 -2.6,3.25 -2.6,3.25 C-2.6,3.25 -2.6,1.25 -2.6,1.25 C-2.6,1.25 0.6,1.25 0.6,1.25 C0.6,1.25 0.6,-3.25 0.6,-3.25 C0.6,-3.25 2.6,-3.25 2.6,-3.25 C2.6,-3.25 2.6,3.25 2.6,3.25c "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.568,0 0.456,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/face_dialog_face_blue_to_checkmark.xml b/packages/SystemUI/res/drawable/face_dialog_face_blue_to_checkmark.xml
new file mode 100644
index 0000000..e4ace67
--- /dev/null
+++ b/packages/SystemUI/res/drawable/face_dialog_face_blue_to_checkmark.xml
@@ -0,0 +1,637 @@
+<?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
+  -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt">
+    <aapt:attr name="android:drawable">
+        <vector
+            android:width="60dp"
+            android:height="60dp"
+            android:viewportWidth="60"
+            android:viewportHeight="60">
+            <group android:name="_R_G">
+                <group
+                    android:name="_R_G_L_0_G_N_2_T_0"
+                    android:translateX="30"
+                    android:translateY="30">
+                    <group
+                        android:name="_R_G_L_0_G"
+                        android:translateX="-30"
+                        android:translateY="-30">
+                        <group
+                            android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+                            android:scaleX="0.08"
+                            android:scaleY="0.08"
+                            android:translateX="30.1"
+                            android:translateY="30.083">
+                            <path
+                                android:name="_R_G_L_0_G_D_0_P_0"
+                                android:fillAlpha="0"
+                                android:fillColor="?android:attr/colorAccent"
+                                android:fillType="nonZero"
+                                android:pathData=" M-116 -16.5 C-116,-16.5 -31.25,68.5 -31.25,68.5 C-31.25,68.5 108.75,-71.5 108.75,-71.5 "
+                                android:trimPathStart="0"
+                                android:trimPathEnd="0"
+                                android:trimPathOffset="0" />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
+                            android:scaleX="0.08"
+                            android:scaleY="0.08"
+                            android:translateX="30.1"
+                            android:translateY="30.083">
+                            <path
+                                android:name="_R_G_L_0_G_D_1_P_0"
+                                android:pathData=" M-116 -16.5 C-116,-16.5 -31.25,68.5 -31.25,68.5 C-31.25,68.5 108.75,-71.5 108.75,-71.5 "
+                                android:strokeWidth="20"
+                                android:strokeAlpha="1"
+                                android:strokeColor="?android:attr/colorAccent"
+                                android:trimPathStart="0"
+                                android:trimPathEnd="0"
+                                android:trimPathOffset="0" />
+                        </group>
+                        <path
+                            android:name="_R_G_L_0_G_D_2_P_0"
+                            android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+                            android:strokeWidth="2.5"
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorAccent"
+                            android:trimPathStart="0"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0" />
+                        <group
+                            android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0"
+                            android:pivotX="1.05"
+                            android:pivotY="-9.891"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="29.044"
+                            android:translateY="41.647">
+                            <path
+                                android:name="_R_G_L_0_G_D_3_P_0"
+                                android:pathData=" M4.71 1.1 C3.71,2.12 2.32,2.75 0.79,2.75 C-2.25,2.75 -4.7,0.29 -4.7,-2.75 "
+                                android:strokeWidth="2"
+                                android:strokeAlpha="1"
+                                android:strokeColor="?android:attr/colorAccent"
+                                android:trimPathStart="0"
+                                android:trimPathEnd="1"
+                                android:trimPathOffset="0" />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="41.1"
+                            android:translateY="23.8">
+                            <path
+                                android:name="_R_G_L_0_G_D_4_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="?android:attr/colorAccent"
+                                android:fillType="nonZero"
+                                android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.1,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_5_P_0_G_0_T_0"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="18.6"
+                            android:translateY="23.8">
+                            <path
+                                android:name="_R_G_L_0_G_D_5_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="?android:attr/colorAccent"
+                                android:fillType="nonZero"
+                                android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.2,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_6_P_0_G_0_T_0"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="30.727"
+                            android:translateY="31.703">
+                            <path
+                                android:name="_R_G_L_0_G_D_6_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="?android:attr/colorAccent"
+                                android:fillType="nonZero"
+                                android:pathData=" M2.6 3.25 C2.6,3.25 -2.6,3.25 -2.6,3.25 C-2.6,3.25 -2.6,1.25 -2.6,1.25 C-2.6,1.25 0.6,1.25 0.6,1.25 C0.6,1.25 0.6,-3.25 0.6,-3.25 C0.6,-3.25 2.6,-3.25 2.6,-3.25 C2.6,-3.25 2.6,3.25 2.6,3.25c " />
+                        </group>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+    <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.08"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.08"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="scaleX"
+                    android:startOffset="33"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.12789"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="scaleY"
+                    android:startOffset="33"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.12789"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleX"
+                    android:startOffset="200"
+                    android:valueFrom="0.12789"
+                    android:valueTo="0.12241"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleY"
+                    android:startOffset="200"
+                    android:valueFrom="0.12789"
+                    android:valueTo="0.12241"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleX"
+                    android:startOffset="300"
+                    android:valueFrom="0.12241"
+                    android:valueTo="0.125"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleY"
+                    android:startOffset="300"
+                    android:valueFrom="0.12241"
+                    android:valueTo="0.125"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_0_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="33"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.08"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.08"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="scaleX"
+                    android:startOffset="33"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.12789"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="scaleY"
+                    android:startOffset="33"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.12789"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleX"
+                    android:startOffset="200"
+                    android:valueFrom="0.12789"
+                    android:valueTo="0.12241"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleY"
+                    android:startOffset="200"
+                    android:valueFrom="0.12789"
+                    android:valueTo="0.12241"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleX"
+                    android:startOffset="300"
+                    android:valueFrom="0.12241"
+                    android:valueTo="0.125"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleY"
+                    android:startOffset="300"
+                    android:valueFrom="0.12241"
+                    android:valueTo="0.125"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="33"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_2_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="strokeColor"
+                    android:startOffset="0"
+                    android:valueFrom="?android:attr/colorAccent"
+                    android:valueTo="?android:attr/colorAccent"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="17"
+                    android:propertyName="strokeColor"
+                    android:startOffset="67"
+                    android:valueFrom="?android:attr/colorAccent"
+                    android:valueTo="?android:attr/colorAccent"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="strokeAlpha"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0.65"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0.65"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="trimPathStart"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0.5"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0.5"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_4_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_5_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_5_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_6_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_6_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.287,0.12 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.287,0.12 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="383"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/face_dialog_face_gray_to_checkmark.xml b/packages/SystemUI/res/drawable/face_dialog_face_gray_to_checkmark.xml
new file mode 100644
index 0000000..b09f69b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/face_dialog_face_gray_to_checkmark.xml
@@ -0,0 +1,637 @@
+<?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
+  -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt">
+    <aapt:attr name="android:drawable">
+        <vector
+            android:width="60dp"
+            android:height="60dp"
+            android:viewportWidth="60"
+            android:viewportHeight="60">
+            <group android:name="_R_G">
+                <group
+                    android:name="_R_G_L_0_G_N_2_T_0"
+                    android:translateX="30"
+                    android:translateY="30">
+                    <group
+                        android:name="_R_G_L_0_G"
+                        android:translateX="-30"
+                        android:translateY="-30">
+                        <group
+                            android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+                            android:scaleX="0.08"
+                            android:scaleY="0.08"
+                            android:translateX="30.1"
+                            android:translateY="30.083">
+                            <path
+                                android:name="_R_G_L_0_G_D_0_P_0"
+                                android:fillAlpha="0"
+                                android:fillColor="@color/biometric_face_icon_gray"
+                                android:fillType="nonZero"
+                                android:pathData=" M-116 -16.5 C-116,-16.5 -31.25,68.5 -31.25,68.5 C-31.25,68.5 108.75,-71.5 108.75,-71.5 "
+                                android:trimPathStart="0"
+                                android:trimPathEnd="0"
+                                android:trimPathOffset="0" />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
+                            android:scaleX="0.08"
+                            android:scaleY="0.08"
+                            android:translateX="30.1"
+                            android:translateY="30.083">
+                            <path
+                                android:name="_R_G_L_0_G_D_1_P_0"
+                                android:pathData=" M-116 -16.5 C-116,-16.5 -31.25,68.5 -31.25,68.5 C-31.25,68.5 108.75,-71.5 108.75,-71.5 "
+                                android:strokeWidth="20"
+                                android:strokeAlpha="1"
+                                android:strokeColor="?android:attr/colorAccent"
+                                android:trimPathStart="0"
+                                android:trimPathEnd="0"
+                                android:trimPathOffset="0" />
+                        </group>
+                        <path
+                            android:name="_R_G_L_0_G_D_2_P_0"
+                            android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+                            android:strokeWidth="2.5"
+                            android:strokeAlpha="1"
+                            android:strokeColor="@color/biometric_face_icon_gray"
+                            android:trimPathStart="0"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0" />
+                        <group
+                            android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0"
+                            android:pivotX="1.05"
+                            android:pivotY="-9.891"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="29.044"
+                            android:translateY="41.647">
+                            <path
+                                android:name="_R_G_L_0_G_D_3_P_0"
+                                android:pathData=" M4.71 1.1 C3.71,2.12 2.32,2.75 0.79,2.75 C-2.25,2.75 -4.7,0.29 -4.7,-2.75 "
+                                android:strokeWidth="2"
+                                android:strokeAlpha="1"
+                                android:strokeColor="@color/biometric_face_icon_gray"
+                                android:trimPathStart="0"
+                                android:trimPathEnd="1"
+                                android:trimPathOffset="0" />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="41.1"
+                            android:translateY="23.8">
+                            <path
+                                android:name="_R_G_L_0_G_D_4_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="@color/biometric_face_icon_gray"
+                                android:fillType="nonZero"
+                                android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.1,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_5_P_0_G_0_T_0"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="18.6"
+                            android:translateY="23.8">
+                            <path
+                                android:name="_R_G_L_0_G_D_5_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="@color/biometric_face_icon_gray"
+                                android:fillType="nonZero"
+                                android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.2,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_6_P_0_G_0_T_0"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="30.727"
+                            android:translateY="31.703">
+                            <path
+                                android:name="_R_G_L_0_G_D_6_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="@color/biometric_face_icon_gray"
+                                android:fillType="nonZero"
+                                android:pathData=" M2.6 3.25 C2.6,3.25 -2.6,3.25 -2.6,3.25 C-2.6,3.25 -2.6,1.25 -2.6,1.25 C-2.6,1.25 0.6,1.25 0.6,1.25 C0.6,1.25 0.6,-3.25 0.6,-3.25 C0.6,-3.25 2.6,-3.25 2.6,-3.25 C2.6,-3.25 2.6,3.25 2.6,3.25c " />
+                        </group>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+    <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.08"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.08"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="scaleX"
+                    android:startOffset="33"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.12789"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="scaleY"
+                    android:startOffset="33"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.12789"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleX"
+                    android:startOffset="200"
+                    android:valueFrom="0.12789"
+                    android:valueTo="0.12241"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleY"
+                    android:startOffset="200"
+                    android:valueFrom="0.12789"
+                    android:valueTo="0.12241"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleX"
+                    android:startOffset="300"
+                    android:valueFrom="0.12241"
+                    android:valueTo="0.125"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleY"
+                    android:startOffset="300"
+                    android:valueFrom="0.12241"
+                    android:valueTo="0.125"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_0_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="33"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.08"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.08"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="scaleX"
+                    android:startOffset="33"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.12789"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="scaleY"
+                    android:startOffset="33"
+                    android:valueFrom="0.08"
+                    android:valueTo="0.12789"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.333,0 0.537,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleX"
+                    android:startOffset="200"
+                    android:valueFrom="0.12789"
+                    android:valueTo="0.12241"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleY"
+                    android:startOffset="200"
+                    android:valueFrom="0.12789"
+                    android:valueTo="0.12241"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.441,0 0.533,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleX"
+                    android:startOffset="300"
+                    android:valueFrom="0.12241"
+                    android:valueTo="0.125"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleY"
+                    android:startOffset="300"
+                    android:valueFrom="0.12241"
+                    android:valueTo="0.125"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.424,0 0.486,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="233"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="33"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.292,0 0.155,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_2_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="strokeColor"
+                    android:startOffset="0"
+                    android:valueFrom="@color/biometric_face_icon_gray"
+                    android:valueTo="@color/biometric_face_icon_gray"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="17"
+                    android:propertyName="strokeColor"
+                    android:startOffset="67"
+                    android:valueFrom="@color/biometric_face_icon_gray"
+                    android:valueTo="?android:attr/colorAccent"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="strokeAlpha"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0.65"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0.65"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="trimPathStart"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0.5"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0.5"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_4_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_5_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_5_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_6_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_6_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.287,0.12 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.287,0.12 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="383"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/face_dialog_face_gray_to_face_blue.xml b/packages/SystemUI/res/drawable/face_dialog_face_gray_to_face_blue.xml
new file mode 100644
index 0000000..9259dc7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/face_dialog_face_gray_to_face_blue.xml
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt">
+    <aapt:attr name="android:drawable">
+        <vector
+            android:width="60dp"
+            android:height="60dp"
+            android:viewportHeight="60"
+            android:viewportWidth="60">
+            <group android:name="_R_G">
+                <group
+                    android:name="_R_G_L_0_G_N_1_T_0"
+                    android:translateX="30"
+                    android:translateY="30">
+                    <group
+                        android:name="_R_G_L_0_G"
+                        android:translateX="-30"
+                        android:translateY="-30">
+                        <path
+                            android:name="_R_G_L_0_G_D_0_P_0"
+                            android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+                            android:strokeAlpha="1"
+                            android:strokeColor="@color/biometric_face_icon_gray"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="2.5"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="0" />
+                        <path
+                            android:name="_R_G_L_0_G_D_1_P_0"
+                            android:pathData=" M33.75 42.75 C32.75,43.76 31.37,44.39 29.83,44.39 C26.8,44.39 24.34,41.93 24.34,38.9 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="@color/biometric_face_icon_gray"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="2"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="0" />
+                        <path
+                            android:name="_R_G_L_0_G_D_2_P_0"
+                            android:fillAlpha="1"
+                            android:fillColor="@color/biometric_face_icon_gray"
+                            android:fillType="nonZero"
+                            android:pathData=" M39 23.8 C39,25 39.9,25.9 41.1,25.9 C42.2,25.9 43.2,25 43.2,23.8 C43.2,22.6 42.3,21.7 41.1,21.7 C39.9,21.7 39,22.6 39,23.8c " />
+                        <path
+                            android:name="_R_G_L_0_G_D_3_P_0"
+                            android:fillAlpha="1"
+                            android:fillColor="@color/biometric_face_icon_gray"
+                            android:fillType="nonZero"
+                            android:pathData=" M16.5 23.8 C16.5,25 17.4,25.9 18.6,25.9 C19.8,25.9 20.7,25 20.7,23.8 C20.7,22.6 19.8,21.7 18.6,21.7 C17.4,21.7 16.5,22.6 16.5,23.8c " />
+                        <path
+                            android:name="_R_G_L_0_G_D_4_P_0"
+                            android:fillAlpha="1"
+                            android:fillColor="@color/biometric_face_icon_gray"
+                            android:fillType="nonZero"
+                            android:pathData=" M32.9 34.7 C32.9,34.7 27.7,34.7 27.7,34.7 C27.7,34.7 27.7,32.7 27.7,32.7 C27.7,32.7 30.9,32.7 30.9,32.7 C30.9,32.7 30.9,28.2 30.9,28.2 C30.9,28.2 32.9,28.2 32.9,28.2 C32.9,28.2 32.9,34.7 32.9,34.7c " />
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+    <target android:name="_R_G_L_0_G_D_0_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="strokeColor"
+                    android:startOffset="0"
+                    android:valueFrom="@color/biometric_face_icon_gray"
+                    android:valueTo="?android:attr/colorAccent"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="strokeColor"
+                    android:startOffset="0"
+                    android:valueFrom="@color/biometric_face_icon_gray"
+                    android:valueTo="?android:attr/colorAccent"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_2_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="fillColor"
+                    android:startOffset="0"
+                    android:valueFrom="@color/biometric_face_icon_gray"
+                    android:valueTo="?android:attr/colorAccent"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="fillColor"
+                    android:startOffset="0"
+                    android:valueFrom="@color/biometric_face_icon_gray"
+                    android:valueTo="?android:attr/colorAccent"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_4_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="33"
+                    android:propertyName="fillColor"
+                    android:startOffset="0"
+                    android:valueFrom="@color/biometric_face_icon_gray"
+                    android:valueTo="?android:attr/colorAccent"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/face_dialog_face_to_error.xml b/packages/SystemUI/res/drawable/face_dialog_face_to_error.xml
new file mode 100644
index 0000000..a96d21a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/face_dialog_face_to_error.xml
@@ -0,0 +1,473 @@
+<?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
+  -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt">
+    <aapt:attr name="android:drawable">
+        <vector
+            android:width="60dp"
+            android:height="60dp"
+            android:viewportWidth="60"
+            android:viewportHeight="60">
+            <group android:name="_R_G">
+                <group
+                    android:name="_R_G_L_0_G_N_1_T_0"
+                    android:translateX="30"
+                    android:translateY="30">
+                    <group
+                        android:name="_R_G_L_0_G"
+                        android:translateX="-30"
+                        android:translateY="-30">
+                        <path
+                            android:name="_R_G_L_0_G_D_0_P_0"
+                            android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+                            android:strokeWidth="2.5"
+                            android:strokeAlpha="1"
+                            android:strokeColor="@color/biometric_face_icon_gray"
+                            android:trimPathStart="0"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0" />
+                        <path
+                            android:name="_R_G_L_0_G_D_1_P_0"
+                            android:pathData=" M33.75 42.75 C32.75,43.76 31.37,44.39 29.83,44.39 C26.8,44.39 24.34,41.93 24.34,38.9 "
+                            android:strokeWidth="2"
+                            android:strokeAlpha="1"
+                            android:strokeColor="@color/biometric_face_icon_gray"
+                            android:trimPathStart="0"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0" />
+                        <group
+                            android:name="_R_G_L_0_G_D_2_P_0_G_0_T_0"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="41.1"
+                            android:translateY="23.8">
+                            <path
+                                android:name="_R_G_L_0_G_D_2_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="@color/biometric_face_icon_gray"
+                                android:fillType="nonZero"
+                                android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.1,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="18.6"
+                            android:translateY="23.8">
+                            <path
+                                android:name="_R_G_L_0_G_D_3_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="@color/biometric_face_icon_gray"
+                                android:fillType="nonZero"
+                                android:pathData=" M-2.1 0 C-2.1,1.2 -1.2,2.1 0,2.1 C1.2,2.1 2.1,1.2 2.1,0 C2.1,-1.2 1.2,-2.1 0,-2.1 C-1.2,-2.1 -2.1,-1.2 -2.1,0c " />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0"
+                            android:translateX="30.3"
+                            android:translateY="31.45">
+                            <path
+                                android:name="_R_G_L_0_G_D_4_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="@color/biometric_face_icon_gray"
+                                android:fillType="nonZero"
+                                android:pathData=" M2.6 3.25 C2.6,3.25 -2.6,3.25 -2.6,3.25 C-2.6,3.25 -2.6,1.25 -2.6,1.25 C-2.6,1.25 0.6,1.25 0.6,1.25 C0.6,1.25 0.6,-3.25 0.6,-3.25 C0.6,-3.25 2.6,-3.25 2.6,-3.25 C2.6,-3.25 2.6,3.25 2.6,3.25c " />
+                        </group>
+                    </group>
+                </group>
+            </group>
+            <group android:name="time_group" />
+        </vector>
+    </aapt:attr>
+    <target android:name="_R_G_L_0_G_D_0_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="strokeColor"
+                    android:startOffset="0"
+                    android:valueFrom="@color/biometric_face_icon_gray"
+                    android:valueTo="@color/biometric_face_icon_gray"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="17"
+                    android:propertyName="strokeColor"
+                    android:startOffset="50"
+                    android:valueFrom="@color/biometric_face_icon_gray"
+                    android:valueTo="?android:attr/colorError"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="strokeColor"
+                    android:startOffset="0"
+                    android:valueFrom="@color/biometric_face_icon_gray"
+                    android:valueTo="@color/biometric_face_icon_gray"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="17"
+                    android:propertyName="strokeColor"
+                    android:startOffset="50"
+                    android:valueFrom="@color/biometric_face_icon_gray"
+                    android:valueTo="?android:attr/colorError"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="217"
+                    android:propertyName="strokeWidth"
+                    android:startOffset="0"
+                    android:valueFrom="2"
+                    android:valueTo="2.5"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="217"
+                    android:propertyName="pathData"
+                    android:startOffset="0"
+                    android:valueFrom="M33.75 42.75 C32.75,43.76 31.37,44.39 29.83,44.39 C26.8,44.39 24.34,41.93 24.34,38.9 "
+                    android:valueTo="M34.78 38.76 C33.83,38.75 31.54,38.75 30.01,38.75 C26.97,38.75 26.14,38.75 24.3,38.76 "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="217"
+                    android:propertyName="trimPathStart"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0.34"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="217"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0.5700000000000001"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_2_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="17"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="50"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_2_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="67"
+                    android:pathData="M 41.1,23.8C 40.547981774806985,23.08834635019302 38.34001822519301,20.24165364980698 37.788,19.53"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_2_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0.3"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.999,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0.3"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.999,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="17"
+                    android:propertyName="fillAlpha"
+                    android:startOffset="50"
+                    android:valueFrom="1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="67"
+                    android:pathData="M 18.6,23.8C 19.16757813692093,23.08502601385117 21.43742186307907,20.224973986148832 22.005,19.51"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_3_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0.3"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.999,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="0.3"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.999,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_4_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="50"
+                    android:propertyName="fillColor"
+                    android:startOffset="0"
+                    android:valueFrom="@color/biometric_face_icon_gray"
+                    android:valueTo="@color/biometric_face_icon_gray"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="17"
+                    android:propertyName="fillColor"
+                    android:startOffset="50"
+                    android:valueFrom="@color/biometric_face_icon_gray"
+                    android:valueTo="?android:attr/colorError"
+                    android:valueType="colorType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_4_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="67"
+                    android:pathData="M 30.3,31.45C 30.3,31.07740886211395 30.3,31.82259113788605 30.3,31.45"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="0">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="150"
+                    android:pathData="M 30.3,31.45C 30.3,31.07740886211395 30.3,29.58759113788605 30.3,29.215"
+                    android:propertyName="translateXY"
+                    android:propertyXName="translateX"
+                    android:propertyYName="translateY"
+                    android:startOffset="67">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_4_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="pathData"
+                    android:startOffset="0"
+                    android:valueFrom="M2.6 3.25 C2.6,3.25 -2.6,3.25 -2.6,3.25 C-2.6,3.25 -2.6,1.25 -2.6,1.25 C-2.6,1.25 0.6,1.25 0.6,1.25 C0.6,1.25 0.6,-3.25 0.6,-3.25 C0.6,-3.25 2.6,-3.25 2.6,-3.25 C2.6,-3.25 2.6,3.25 2.6,3.25c "
+                    android:valueTo="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-3.25 -1.5,-3.25 C-1.5,-3.25 0.9,-3.25 0.9,-3.25 C0.9,-3.25 0.9,3.25 0.9,3.25c "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="150"
+                    android:propertyName="pathData"
+                    android:startOffset="67"
+                    android:valueFrom="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-3.25 -1.5,-3.25 C-1.5,-3.25 0.9,-3.25 0.9,-3.25 C0.9,-3.25 0.9,3.25 0.9,3.25c "
+                    android:valueTo="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-13.15 -1.5,-13.15 C-1.5,-13.15 0.9,-13.15 0.9,-13.15 C0.9,-13.15 0.9,3.25 0.9,3.25c "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="pathData"
+                    android:startOffset="217"
+                    android:valueFrom="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-13.15 -1.5,-13.15 C-1.5,-13.15 0.9,-13.15 0.9,-13.15 C0.9,-13.15 0.9,3.25 0.9,3.25c "
+                    android:valueTo="M0.9 3.25 C0.9,3.25 -1.5,3.25 -1.5,3.25 C-1.5,3.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,1.25 -1.5,1.25 C-1.5,1.25 -1.5,-11.71 -1.5,-11.71 C-1.5,-11.71 0.9,-11.71 0.9,-11.71 C0.9,-11.71 0.9,3.25 0.9,3.25c "
+                    android:valueType="pathType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="time_group">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="333"
+                    android:propertyName="translateX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType" />
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
\ 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
deleted file mode 100644
index 6d28b5a..0000000
--- a/packages/SystemUI/res/drawable/face_dialog_icon.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<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 af25e44..8f411f4 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
@@ -18,336 +18,268 @@
     xmlns:aapt="http://schemas.android.com/aapt">
     <aapt:attr name="android:drawable">
         <vector
-            android:width="24dp"
-            android:height="24dp"
-            android:viewportHeight="24"
-            android:viewportWidth="24">
+            android:width="60dp"
+            android:height="60dp"
+            android:viewportHeight="60"
+            android:viewportWidth="60">
             <group android:name="_R_G">
                 <group
-                    android:name="_R_G_L_2_G"
-                    android:pivotX="-33"
-                    android:pivotY="-34"
-                    android:rotation="180"
-                    android:scaleX="0.738"
-                    android:scaleY="0.738"
-                    android:translateX="45"
-                    android:translateY="46.4">
-                    <path
-                        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="?android:attr/colorAccent"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="0"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="0" />
-                    <path
-                        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="?android:attr/colorAccent"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="0"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="0" />
-                    <path
-                        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="?android:attr/colorAccent"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="1"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="1" />
-                    <path
-                        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="?android:attr/colorAccent"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="1"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="1" />
-                    <path
-                        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="?android:attr/colorAccent"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="0"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="0" />
-                </group>
-                <group
-                    android:name="_R_G_L_1_G"
-                    android:rotation="10"
-                    android:translateX="12"
-                    android:translateY="12">
-                    <path
-                        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="?android:attr/colorError"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="2"
-                        android:trimPathEnd="1"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="0" />
-                </group>
-                <group
-                    android:name="_R_G_L_0_G"
-                    android:translateX="12"
-                    android:translateY="12">
+                    android:name="_R_G_L_1_G_N_4_T_0"
+                    android:translateX="30"
+                    android:translateY="30">
                     <group
-                        android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
-                        android:pivotY="-0.012"
-                        android:rotation="0"
-                        android:scaleX="1"
-                        android:scaleY="1">
+                        android:name="_R_G_L_1_G"
+                        android:pivotX="114"
+                        android:pivotY="114"
+                        android:scaleX="0.42200000000000004"
+                        android:scaleY="0.42200000000000004"
+                        android:translateX="-114"
+                        android:translateY="-114">
                         <path
-                            android:name="_R_G_L_0_G_D_0_P_0"
-                            android:fillAlpha="1"
-                            android:fillColor="?android:attr/colorError"
-                            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 " />
+                            android:name="_R_G_L_1_G_D_0_P_0"
+                            android:pathData=" M79.63 67.24 C79.63,67.24 111.5,47.42 147.83,67.24 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorAccent"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="5.5"
+                            android:trimPathEnd="0"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="0" />
+                        <path
+                            android:name="_R_G_L_1_G_D_1_P_0"
+                            android:pathData=" M64.27 98.07 C64.27,98.07 80.13,73.02 113.98,73.02 C147.83,73.02 163.56,97.26 163.56,97.26 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorAccent"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="5.5"
+                            android:trimPathEnd="0"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="0" />
+                        <path
+                            android:name="_R_G_L_1_G_D_2_P_0"
+                            android:pathData=" M72.53 151.07 C72.53,151.07 62.46,122.89 76.16,105.55 C89.86,88.21 106.72,86.73 113.98,86.73 C121.08,86.73 153.51,90.62 158.7,125.87 C159.14,128.82 158.8,132.88 157.18,136.09 C154.88,140.63 150.62,143.63 145.85,143.97 C133.78,144.85 129.76,137.92 129.26,128.49 C128.88,121.19 122.49,115.35 113.15,115.35 C102.91,115.35 95.97,126.69 99.77,139.74 C103.57,152.78 111.33,163.85 130.32,169.13 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorAccent"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="5.5"
+                            android:trimPathEnd="0"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="0" />
+                        <path
+                            android:name="_R_G_L_1_G_D_3_P_0"
+                            android:pathData=" M100.6 167.84 C100.6,167.84 82.76,152.1 83.75,130.31 C84.75,108.53 102.58,100.7 113.73,100.7 C124.87,100.7 144.19,108.56 144.19,130.01 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorAccent"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="5.5"
+                            android:trimPathEnd="0"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="0" />
+                        <path
+                            android:name="_R_G_L_1_G_D_4_P_0"
+                            android:pathData=" M113.73 129.17 C113.73,129.17 113.15,161.33 149.15,156.58 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorAccent"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="5.5"
+                            android:trimPathEnd="0"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="0" />
                     </group>
+                </group>
+                <group
+                    android:name="_R_G_L_0_G_N_4_T_0"
+                    android:translateX="30"
+                    android:translateY="30">
                     <group
-                        android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0"
-                        android:pivotY="-0.012"
-                        android:rotation="0"
-                        android:scaleX="1"
-                        android:scaleY="1">
+                        android:name="_R_G_L_0_G"
+                        android:translateX="-30.05"
+                        android:translateY="-30">
+                        <group
+                            android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="30"
+                            android:translateY="38.75">
+                            <path
+                                android:name="_R_G_L_0_G_D_0_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="?android:attr/colorError"
+                                android:fillType="nonZero"
+                                android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c " />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
+                            android:pivotX="0.002"
+                            android:pivotY="7.488"
+                            android:scaleX="1"
+                            android:scaleY="1"
+                            android:translateX="30"
+                            android:translateY="25">
+                            <path
+                                android:name="_R_G_L_0_G_D_1_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="?android:attr/colorError"
+                                android:fillType="nonZero"
+                                android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c " />
+                        </group>
                         <path
-                            android:name="_R_G_L_0_G_D_0_P_1"
-                            android:fillAlpha="1"
-                            android:fillColor="?android:attr/colorError"
-                            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 " />
+                            android:name="_R_G_L_0_G_D_2_P_0"
+                            android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorError"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="2.5"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="0" />
                     </group>
                 </group>
             </group>
             <group android:name="time_group" />
         </vector>
     </aapt:attr>
-    <target android:name="_R_G_L_2_G_D_0_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="350"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="350"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="350"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_1_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="267"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="433"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="267"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_2_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="250"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="250"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="250"
-                    android:valueFrom="1"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_3_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="350"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="117"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="350"
-                    android:valueFrom="1"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_4_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="417"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="117"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="417"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="200"
-                    android:propertyName="rotation"
-                    android:startOffset="0"
-                    android:valueFrom="180"
-                    android:valueTo="180"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="500"
-                    android:propertyName="rotation"
-                    android:startOffset="200"
-                    android:valueFrom="180"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
     <target android:name="_R_G_L_1_G_D_0_P_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
                 <objectAnimator
-                    android:duration="383"
+                    android:duration="83"
                     android:propertyName="trimPathEnd"
                     android:startOffset="0"
-                    android:valueFrom="1"
+                    android:valueFrom="0"
                     android:valueTo="0"
                     android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
                         <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
                     </aapt:attr>
                 </objectAnimator>
+                <objectAnimator
+                    android:duration="250"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="83"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
             </set>
         </aapt:attr>
     </target>
-    <target android:name="_R_G_L_1_G">
+    <target android:name="_R_G_L_1_G_D_1_P_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
                 <objectAnimator
-                    android:duration="33"
-                    android:propertyName="rotation"
+                    android:duration="83"
+                    android:propertyName="trimPathEnd"
                     android:startOffset="0"
-                    android:valueFrom="10"
-                    android:valueTo="10"
+                    android:valueFrom="0"
+                    android:valueTo="0"
                     android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
                     </aapt:attr>
                 </objectAnimator>
                 <objectAnimator
-                    android:duration="367"
-                    android:propertyName="rotation"
-                    android:startOffset="33"
-                    android:valueFrom="10"
-                    android:valueTo="-180"
+                    android:duration="250"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="83"
+                    android:valueFrom="0"
+                    android:valueTo="1"
                     android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_D_2_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="250"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="83"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_D_3_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="250"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="83"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_D_4_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="83"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="250"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="83"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
                     </aapt:attr>
                 </objectAnimator>
             </set>
@@ -357,153 +289,125 @@
         <aapt:attr name="android:animation">
             <set android:ordering="together">
                 <objectAnimator
-                    android:duration="17"
-                    android:propertyName="rotation"
+                    android:duration="67"
+                    android:propertyName="scaleX"
                     android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
+                    android:valueFrom="1"
+                    android:valueTo="1.1"
                     android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0" />
                     </aapt:attr>
                 </objectAnimator>
                 <objectAnimator
-                    android:duration="417"
-                    android:propertyName="rotation"
-                    android:startOffset="17"
-                    android:valueFrom="0"
-                    android:valueTo="-180"
+                    android:duration="67"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="1"
+                    android:valueTo="1.1"
                     android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.2,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleX"
+                    android:startOffset="67"
+                    android:valueFrom="1.1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleY"
+                    android:startOffset="67"
+                    android:valueFrom="1.1"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0" />
                     </aapt:attr>
                 </objectAnimator>
             </set>
         </aapt:attr>
     </target>
-    <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+    <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
                 <objectAnimator
-                    android:duration="117"
+                    android:duration="67"
                     android:propertyName="scaleX"
                     android:startOffset="0"
                     android:valueFrom="1"
                     android:valueTo="1"
                     android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.659,1 1.0,1.0" />
                     </aapt:attr>
                 </objectAnimator>
                 <objectAnimator
-                    android:duration="117"
+                    android:duration="67"
                     android:propertyName="scaleY"
                     android:startOffset="0"
                     android:valueFrom="1"
+                    android:valueTo="1.1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleX"
+                    android:startOffset="67"
+                    android:valueFrom="1"
                     android:valueTo="1"
                     android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0" />
                     </aapt:attr>
                 </objectAnimator>
                 <objectAnimator
-                    android:duration="317"
-                    android:propertyName="scaleX"
-                    android:startOffset="117"
-                    android:valueFrom="1"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="317"
+                    android:duration="100"
                     android:propertyName="scaleY"
-                    android:startOffset="117"
-                    android:valueFrom="1"
+                    android:startOffset="67"
+                    android:valueFrom="1.1"
                     android:valueTo="0"
                     android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.096 1.0,1.0" />
                     </aapt:attr>
                 </objectAnimator>
             </set>
         </aapt:attr>
     </target>
-    <target android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0">
+    <target android:name="_R_G_L_0_G_D_2_P_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
                 <objectAnimator
-                    android:duration="17"
-                    android:propertyName="rotation"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="417"
-                    android:propertyName="rotation"
-                    android:startOffset="17"
-                    android:valueFrom="0"
-                    android:valueTo="-180"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="117"
-                    android:propertyName="scaleX"
+                    android:duration="67"
+                    android:propertyName="trimPathEnd"
                     android:startOffset="0"
                     android:valueFrom="1"
                     android:valueTo="1"
                     android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
                     </aapt:attr>
                 </objectAnimator>
                 <objectAnimator
-                    android:duration="117"
-                    android:propertyName="scaleY"
-                    android:startOffset="0"
-                    android:valueFrom="1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="317"
-                    android:propertyName="scaleX"
-                    android:startOffset="117"
+                    android:duration="133"
+                    android:propertyName="trimPathEnd"
+                    android:startOffset="67"
                     android:valueFrom="1"
                     android:valueTo="0"
                     android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="317"
-                    android:propertyName="scaleY"
-                    android:startOffset="117"
-                    android:valueFrom="1"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c1,0 0.6,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
                     </aapt:attr>
                 </objectAnimator>
             </set>
@@ -513,7 +417,7 @@
         <aapt:attr name="android:animation">
             <set android:ordering="together">
                 <objectAnimator
-                    android:duration="717"
+                    android:duration="350"
                     android:propertyName="translateX"
                     android:startOffset="0"
                     android:valueFrom="0"
@@ -522,4 +426,4 @@
             </set>
         </aapt:attr>
     </target>
-</animated-vector>
+</animated-vector>
\ No newline at end of file
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 1a7a846..89b8228 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
@@ -18,614 +18,133 @@
     xmlns:aapt="http://schemas.android.com/aapt">
     <aapt:attr name="android:drawable">
         <vector
-            android:width="24dp"
-            android:height="24dp"
-            android:viewportHeight="24"
-            android:viewportWidth="24">
+            android:width="60dp"
+            android:height="60dp"
+            android:viewportHeight="60"
+            android:viewportWidth="60">
             <group android:name="_R_G">
                 <group
-                    android:name="_R_G_L_3_G"
-                    android:pivotX="-33"
-                    android:pivotY="-34"
-                    android:rotation="0"
-                    android:scaleX="0.738"
-                    android:scaleY="0.738"
-                    android:translateX="45"
-                    android:translateY="46.4">
-                    <path
-                        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="?android:attr/colorAccent"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="1"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="0" />
-                    <path
-                        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="?android:attr/colorAccent"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="1"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="0" />
-                    <path
-                        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="?android:attr/colorAccent"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="1"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="0" />
-                    <path
-                        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="?android:attr/colorAccent"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="1"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="0" />
-                    <path
-                        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="?android:attr/colorAccent"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="1"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="0" />
-                </group>
-                <group
-                    android:name="_R_G_L_2_G"
-                    android:pivotX="-33"
-                    android:pivotY="-34"
-                    android:rotation="0"
-                    android:scaleX="0.738"
-                    android:scaleY="0.738"
-                    android:translateX="45"
-                    android:translateY="46.4">
-                    <path
-                        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="?android:attr/colorError"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="0"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="0" />
-                    <path
-                        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="?android:attr/colorError"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="0"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="0" />
-                    <path
-                        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="?android:attr/colorError"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="0"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="0" />
-                    <path
-                        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="?android:attr/colorError"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="1"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="1" />
-                    <path
-                        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="?android:attr/colorError"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="1.45"
-                        android:trimPathEnd="0"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="0" />
-                </group>
-                <group
-                    android:name="_R_G_L_1_G"
-                    android:rotation="190"
-                    android:translateX="12"
-                    android:translateY="12">
-                    <path
-                        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="?android:attr/colorError"
-                        android:strokeLineCap="round"
-                        android:strokeLineJoin="round"
-                        android:strokeWidth="2"
-                        android:trimPathEnd="1"
-                        android:trimPathOffset="0"
-                        android:trimPathStart="1" />
-                </group>
-                <group
-                    android:name="_R_G_L_0_G"
-                    android:translateX="12"
-                    android:translateY="12">
+                    android:name="_R_G_L_1_G_N_4_T_0"
+                    android:translateX="30"
+                    android:translateY="30">
                     <group
-                        android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
-                        android:pivotY="-0.012"
-                        android:rotation="184"
-                        android:scaleX="0"
-                        android:scaleY="0">
+                        android:name="_R_G_L_1_G"
+                        android:pivotX="114"
+                        android:pivotY="114"
+                        android:scaleX="0.42244"
+                        android:scaleY="0.42244"
+                        android:translateX="-114"
+                        android:translateY="-114">
                         <path
-                            android:name="_R_G_L_0_G_D_0_P_0"
-                            android:fillAlpha="1"
-                            android:fillColor="?android:attr/colorError"
-                            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 " />
+                            android:name="_R_G_L_1_G_D_0_P_0"
+                            android:pathData=" M79.63 67.24 C79.63,67.24 111.5,47.42 147.83,67.24 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorAccent"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="5.5"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="0" />
+                        <path
+                            android:name="_R_G_L_1_G_D_1_P_0"
+                            android:pathData=" M64.27 98.07 C64.27,98.07 80.13,73.02 113.98,73.02 C147.83,73.02 163.56,97.26 163.56,97.26 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorAccent"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="5.5"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="0" />
+                        <path
+                            android:name="_R_G_L_1_G_D_2_P_0"
+                            android:pathData=" M72.53 151.07 C72.53,151.07 62.46,122.89 76.16,105.55 C89.86,88.21 106.72,86.73 113.98,86.73 C121.08,86.73 153.51,90.62 158.7,125.87 C159.14,128.82 158.8,132.88 157.18,136.09 C154.88,140.63 150.62,143.63 145.85,143.97 C133.78,144.85 129.76,137.92 129.26,128.49 C128.88,121.19 122.49,115.35 113.15,115.35 C102.91,115.35 95.97,126.69 99.77,139.74 C103.57,152.78 111.33,163.85 130.32,169.13 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorAccent"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="5.5"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="0" />
+                        <path
+                            android:name="_R_G_L_1_G_D_3_P_0"
+                            android:pathData=" M100.6 167.84 C100.6,167.84 82.76,152.1 83.75,130.31 C84.75,108.53 102.58,100.7 113.73,100.7 C124.87,100.7 144.19,108.56 144.19,130.01 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorAccent"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="5.5"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="0" />
+                        <path
+                            android:name="_R_G_L_1_G_D_4_P_0"
+                            android:pathData=" M113.73 129.17 C113.73,129.17 113.15,161.33 149.15,156.58 "
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorAccent"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="5.5"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="0" />
                     </group>
+                </group>
+                <group
+                    android:name="_R_G_L_0_G_N_4_T_0"
+                    android:translateX="30"
+                    android:translateY="30">
                     <group
-                        android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0"
-                        android:pivotY="-0.012"
-                        android:rotation="184"
-                        android:scaleX="0"
-                        android:scaleY="0">
+                        android:name="_R_G_L_0_G"
+                        android:translateX="-30.05"
+                        android:translateY="-30">
+                        <group
+                            android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
+                            android:scaleX="0"
+                            android:scaleY="0"
+                            android:translateX="30"
+                            android:translateY="38.75">
+                            <path
+                                android:name="_R_G_L_0_G_D_0_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="?android:attr/colorError"
+                                android:fillType="nonZero"
+                                android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c " />
+                        </group>
+                        <group
+                            android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
+                            android:pivotX="0.002"
+                            android:pivotY="7.488"
+                            android:scaleX="1"
+                            android:scaleY="0"
+                            android:translateX="30"
+                            android:translateY="25">
+                            <path
+                                android:name="_R_G_L_0_G_D_1_P_0"
+                                android:fillAlpha="1"
+                                android:fillColor="?android:attr/colorError"
+                                android:fillType="nonZero"
+                                android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c " />
+                        </group>
                         <path
-                            android:name="_R_G_L_0_G_D_0_P_1"
-                            android:fillAlpha="1"
-                            android:fillColor="?android:attr/colorError"
-                            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 " />
+                            android:name="_R_G_L_0_G_D_2_P_0"
+                            android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
+                            android:strokeAlpha="1"
+                            android:strokeColor="?android:attr/colorError"
+                            android:strokeLineCap="round"
+                            android:strokeLineJoin="round"
+                            android:strokeWidth="2.5"
+                            android:trimPathEnd="1"
+                            android:trimPathOffset="0"
+                            android:trimPathStart="1" />
                     </group>
                 </group>
             </group>
             <group android:name="time_group" />
         </vector>
     </aapt:attr>
-    <target android:name="_R_G_L_3_G_D_0_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="150"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_3_G_D_1_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="33"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="150"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="33"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_3_G_D_2_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="17"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="217"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="17"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_3_G_D_3_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="17"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="133"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="17"
-                    android:valueFrom="1"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_3_G_D_4_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="17"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="67"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="17"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_3_G">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="100"
-                    android:propertyName="rotation"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="567"
-                    android:propertyName="rotation"
-                    android:startOffset="100"
-                    android:valueFrom="0"
-                    android:valueTo="-305"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_0_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="150"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.5,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="167"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="150"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.5,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_0_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="167"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_1_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="133"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.5,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="200"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="133"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.5,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_1_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="17"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="217"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="17"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_2_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="133"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="200"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="133"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_2_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="250"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_3_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="167"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="1"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_3_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="117"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="1"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="117"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="117"
-                    android:valueFrom="1"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_4_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="100"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.5,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="100"
-                    android:propertyName="trimPathStart"
-                    android:startOffset="100"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.5,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G_D_4_P_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="133"
-                    android:propertyName="trimPathEnd"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_2_G">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="100"
-                    android:propertyName="rotation"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="567"
-                    android:propertyName="rotation"
-                    android:startOffset="100"
-                    android:valueFrom="0"
-                    android:valueTo="-305"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
     <target android:name="_R_G_L_1_G_D_0_P_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
@@ -633,6 +152,163 @@
                     android:duration="167"
                     android:propertyName="trimPathStart"
                     android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_D_1_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="trimPathStart"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_D_2_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="trimPathStart"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_D_3_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="trimPathStart"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_1_G_D_4_P_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="trimPathStart"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleX"
+                    android:startOffset="167"
+                    android:valueFrom="0"
+                    android:valueTo="1.1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleY"
+                    android:startOffset="167"
+                    android:valueFrom="0"
+                    android:valueTo="1.1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleX"
+                    android:startOffset="267"
+                    android:valueFrom="1.1"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleY"
+                    android:startOffset="267"
+                    android:valueFrom="1.1"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+            </set>
+        </aapt:attr>
+    </target>
+    <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator
+                    android:duration="167"
+                    android:propertyName="scaleX"
+                    android:startOffset="0"
                     android:valueFrom="1"
                     android:valueTo="1"
                     android:valueType="floatType">
@@ -641,11 +317,55 @@
                     </aapt:attr>
                 </objectAnimator>
                 <objectAnimator
-                    android:duration="533"
-                    android:propertyName="trimPathStart"
+                    android:duration="167"
+                    android:propertyName="scaleY"
+                    android:startOffset="0"
+                    android:valueFrom="0"
+                    android:valueTo="0"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleX"
                     android:startOffset="167"
                     android:valueFrom="1"
-                    android:valueTo="0"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="100"
+                    android:propertyName="scaleY"
+                    android:startOffset="167"
+                    android:valueFrom="0"
+                    android:valueTo="1.1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleX"
+                    android:startOffset="267"
+                    android:valueFrom="1"
+                    android:valueTo="1"
+                    android:valueType="floatType">
+                    <aapt:attr name="android:interpolator">
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.341,0 0.2,1 1.0,1.0" />
+                    </aapt:attr>
+                </objectAnimator>
+                <objectAnimator
+                    android:duration="67"
+                    android:propertyName="scaleY"
+                    android:startOffset="267"
+                    android:valueFrom="1.1"
+                    android:valueTo="1"
                     android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
                         <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
@@ -654,185 +374,18 @@
             </set>
         </aapt:attr>
     </target>
-    <target android:name="_R_G_L_1_G">
+    <target android:name="_R_G_L_0_G_D_2_P_0">
         <aapt:attr name="android:animation">
             <set android:ordering="together">
                 <objectAnimator
-                    android:duration="150"
-                    android:propertyName="rotation"
+                    android:duration="267"
+                    android:propertyName="trimPathStart"
                     android:startOffset="0"
-                    android:valueFrom="190"
-                    android:valueTo="190"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="550"
-                    android:propertyName="rotation"
-                    android:startOffset="150"
-                    android:valueFrom="190"
-                    android:valueTo="-6"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="283"
-                    android:propertyName="rotation"
-                    android:startOffset="0"
-                    android:valueFrom="184"
-                    android:valueTo="184"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="317"
-                    android:propertyName="rotation"
-                    android:startOffset="283"
-                    android:valueFrom="184"
+                    android:valueFrom="1"
                     android:valueTo="0"
                     android:valueType="floatType">
                     <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="283"
-                    android:propertyName="scaleX"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="283"
-                    android:propertyName="scaleY"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="317"
-                    android:propertyName="scaleX"
-                    android:startOffset="283"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="317"
-                    android:propertyName="scaleY"
-                    android:startOffset="283"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="283"
-                    android:propertyName="rotation"
-                    android:startOffset="0"
-                    android:valueFrom="184"
-                    android:valueTo="184"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="317"
-                    android:propertyName="rotation"
-                    android:startOffset="283"
-                    android:valueFrom="184"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-            </set>
-        </aapt:attr>
-    </target>
-    <target android:name="_R_G_L_0_G_D_0_P_1_G_0_T_0">
-        <aapt:attr name="android:animation">
-            <set android:ordering="together">
-                <objectAnimator
-                    android:duration="283"
-                    android:propertyName="scaleX"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="283"
-                    android:propertyName="scaleY"
-                    android:startOffset="0"
-                    android:valueFrom="0"
-                    android:valueTo="0"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="317"
-                    android:propertyName="scaleX"
-                    android:startOffset="283"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
-                    </aapt:attr>
-                </objectAnimator>
-                <objectAnimator
-                    android:duration="317"
-                    android:propertyName="scaleY"
-                    android:startOffset="283"
-                    android:valueFrom="0"
-                    android:valueTo="1"
-                    android:valueType="floatType">
-                    <aapt:attr name="android:interpolator">
-                        <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.6,1 1.0,1.0" />
+                        <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
                     </aapt:attr>
                 </objectAnimator>
             </set>
@@ -842,7 +395,7 @@
         <aapt:attr name="android:animation">
             <set android:ordering="together">
                 <objectAnimator
-                    android:duration="717"
+                    android:duration="350"
                     android:propertyName="translateX"
                     android:startOffset="0"
                     android:valueFrom="0"
@@ -851,4 +404,4 @@
             </set>
         </aapt:attr>
     </target>
-</animated-vector>
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/battery_percentage_view.xml b/packages/SystemUI/res/layout/battery_percentage_view.xml
index e52aa14..b9b1bb1 100644
--- a/packages/SystemUI/res/layout/battery_percentage_view.xml
+++ b/packages/SystemUI/res/layout/battery_percentage_view.xml
@@ -22,7 +22,7 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:singleLine="true"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+        android:textAppearance="@style/TextAppearance.StatusBar.Clock"
         android:textColor="?android:attr/textColorPrimary"
         android:gravity="center_vertical|start"
         android:paddingStart="@dimen/battery_level_padding_start"
diff --git a/packages/SystemUI/res/layout/bubble_expanded_view.xml b/packages/SystemUI/res/layout/bubble_expanded_view.xml
index b2307e7..1aeb52c 100644
--- a/packages/SystemUI/res/layout/bubble_expanded_view.xml
+++ b/packages/SystemUI/res/layout/bubble_expanded_view.xml
@@ -20,11 +20,23 @@
     android:layout_width="match_parent"
     android:id="@+id/bubble_expanded_view">
 
-    <!-- TODO: header -->
-
     <View
         android:id="@+id/pointer_view"
         android:layout_width="@dimen/bubble_pointer_width"
         android:layout_height="@dimen/bubble_pointer_height"
     />
+
+    <TextView
+        android:id="@+id/bubble_content_header"
+        android:background="@drawable/bubble_expanded_header_bg"
+        android:textAppearance="@*android:style/TextAppearance.Material.Title"
+        android:textSize="18sp"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/bubble_expanded_header_height"
+        android:gravity="start|center_vertical"
+        android:singleLine="true"
+        android:paddingLeft="@dimen/bubble_expanded_header_horizontal_padding"
+        android:paddingRight="@dimen/bubble_expanded_header_horizontal_padding"
+    />
+
 </com.android.systemui.bubbles.BubbleExpandedViewContainer>
diff --git a/packages/SystemUI/res/layout/bubble_view.xml b/packages/SystemUI/res/layout/bubble_view.xml
new file mode 100644
index 0000000..204408cd
--- /dev/null
+++ b/packages/SystemUI/res/layout/bubble_view.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<com.android.systemui.bubbles.BubbleView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="wrap_content"
+    android:layout_width="wrap_content"
+    android:id="@+id/bubble_view">
+
+    <com.android.systemui.bubbles.BadgedImageView
+        android:id="@+id/bubble_image"
+        android:layout_width="@dimen/bubble_size"
+        android:layout_height="@dimen/bubble_size"
+        android:padding="@dimen/bubble_view_padding"
+        android:clipToPadding="false"/>
+
+    <TextView
+        android:id="@+id/message_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:minWidth="@dimen/bubble_message_min_width"
+        android:maxWidth="@dimen/bubble_message_max_width"
+        android:padding="@dimen/bubble_message_padding"/>
+
+</com.android.systemui.bubbles.BubbleView>
diff --git a/packages/SystemUI/res/layout/dock_info_overlay.xml b/packages/SystemUI/res/layout/dock_info_overlay.xml
new file mode 100644
index 0000000..430143c
--- /dev/null
+++ b/packages/SystemUI/res/layout/dock_info_overlay.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- empty stub -->
+<merge />
diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml
index 7f4e0d2..f932303 100644
--- a/packages/SystemUI/res/layout/global_actions_wrapped.xml
+++ b/packages/SystemUI/res/layout/global_actions_wrapped.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <com.android.systemui.HardwareUiLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@id/global_actions_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_gravity="top|right"
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml b/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
index ecfbfb4..c8e0845 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
@@ -25,12 +25,18 @@
     android:focusable="true"
     android:layout_gravity="center_vertical">
 
-    <ImageView
-        android:id="@+id/app_icon"
+    <FrameLayout
         android:layout_height="@dimen/ongoing_appops_dialog_app_icon_size"
         android:layout_width="@dimen/ongoing_appops_dialog_app_icon_size"
-        android:layout_gravity="start|center_vertical"
-    />
+        android:layout_gravity="start|center_vertical">
+
+        <ImageView
+            android:id="@+id/app_icon"
+            android:layout_height="@dimen/ongoing_appops_dialog_app_icon_size"
+            android:layout_width="@dimen/ongoing_appops_dialog_app_icon_size"
+            android:layout_gravity="center"
+            />
+    </FrameLayout>
 
     <TextView
         android:id="@+id/app_name"
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 2000104..74002ac 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -51,11 +51,4 @@
         android:layout_width="wrap_content"
         android:paddingEnd="2dp" />
 
-    <TextView
-        android:id="@+id/batteryRemainingText"
-        android:textAppearance="@style/TextAppearance.QS.TileLabel"
-        android:layout_height="match_parent"
-        android:layout_width="wrap_content"
-        android:gravity="center_vertical" />
-
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml b/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml
index 307b538..5bcc1b3 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml
@@ -39,7 +39,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="@string/monitoring_title_device_owned"
-                style="@android:style/TextAppearance.Material.Title"
+                style="@style/TextAppearance.DeviceManagementDialog.Title"
                 android:textColor="?android:attr/textColorPrimary"
                 android:paddingBottom="@dimen/qs_footer_dialog_subtitle_padding"
             />
@@ -64,7 +64,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="@string/monitoring_subtitle_ca_certificate"
-                style="@android:style/TextAppearance.Material.Title"
+                style="@style/TextAppearance.DeviceManagementDialog.Title"
                 android:textColor="?android:attr/textColorPrimary"
                 android:paddingBottom="@dimen/qs_footer_dialog_subtitle_padding"
             />
@@ -89,7 +89,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="@string/monitoring_subtitle_network_logging"
-                style="@android:style/TextAppearance.Material.Title"
+                style="@style/TextAppearance.DeviceManagementDialog.Title"
                 android:textColor="?android:attr/textColorPrimary"
                 android:paddingBottom="@dimen/qs_footer_dialog_subtitle_padding"
             />
@@ -114,7 +114,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:text="@string/monitoring_subtitle_vpn"
-                style="@android:style/TextAppearance.Material.Title"
+                style="@style/TextAppearance.DeviceManagementDialog.Title"
                 android:textColor="?android:attr/textColorPrimary"
                 android:paddingBottom="@dimen/qs_footer_dialog_subtitle_padding"
             />
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 4e0cbe0..ed18dc7 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -24,14 +24,13 @@
     android:layout_gravity="@integer/notification_panel_layout_gravity"
     android:background="@android:color/transparent"
     android:baselineAligned="false"
-    android:clickable="true"
+    android:clickable="false"
     android:clipChildren="false"
     android:clipToPadding="false"
     android:paddingTop="0dp"
     android:paddingEnd="0dp"
     android:paddingStart="0dp"
-    android:elevation="4dp"
-    android:importantForAccessibility="no" >
+    android:elevation="4dp" >
 
     <include layout="@layout/quick_status_bar_header_system_icons" />
 
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
index 22b8d2f..cd9f780 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
@@ -24,6 +24,7 @@
     android:clipToPadding="false"
     android:gravity="center"
     android:orientation="horizontal"
+    android:clickable="true"
     android:paddingStart="@dimen/status_bar_padding_start"
     android:paddingEnd="@dimen/status_bar_padding_end" >
 
@@ -63,11 +64,5 @@
 
     <include layout="@layout/ongoing_privacy_chip" />
 
-    <com.android.systemui.BatteryMeterView
-        android:id="@+id/battery"
-        android:layout_height="match_parent"
-        android:layout_width="wrap_content"
-        android:gravity="center_vertical|end"
-        android:layout_gravity="center_vertical|end" />
     </LinearLayout>
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
deleted file mode 100644
index cfa372b..0000000
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ /dev/null
@@ -1,129 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
--->
-<!-- extends LinearLayout -->
-<com.android.systemui.statusbar.SignalClusterView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/signal_cluster"
-    android:layout_height="match_parent"
-    android:layout_width="wrap_content"
-    android:gravity="center_vertical"
-    android:orientation="horizontal"
-    android:paddingEnd="@dimen/signal_cluster_battery_padding"
-    >
-    <ImageView
-        android:id="@+id/vpn"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:paddingEnd="6dp"
-        android:src="@drawable/stat_sys_vpn_ic"
-        android:tint="@color/background_protect_secondary"
-        android:contentDescription="@string/accessibility_vpn_on"
-        />
-    <FrameLayout
-        android:id="@+id/ethernet_combo"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        >
-        <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="?attr/lightIconTheme"
-            android:id="@+id/ethernet"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            />
-        <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="?attr/darkIconTheme"
-            android:id="@+id/ethernet_dark"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:alpha="0.0"
-            />
-    </FrameLayout>
-    <FrameLayout
-        android:layout_height="17dp"
-        android:layout_width="wrap_content">
-        <ImageView
-            android:id="@+id/wifi_in"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:src="@drawable/ic_activity_down"
-            android:visibility="gone"
-            android:paddingEnd="2dp"
-            />
-        <ImageView
-            android:id="@+id/wifi_out"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:src="@drawable/ic_activity_up"
-            android:paddingEnd="2dp"
-            android:visibility="gone"
-            />
-    </FrameLayout>
-    <FrameLayout
-        android:id="@+id/wifi_combo"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        >
-        <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="?attr/lightIconTheme"
-            android:id="@+id/wifi_signal"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            />
-        <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="?attr/darkIconTheme"
-            android:id="@+id/wifi_signal_dark"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:alpha="0.0"
-            />
-        <ImageView
-            android:id="@+id/wifi_inout"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            />
-    </FrameLayout>
-    <View
-        android:id="@+id/wifi_signal_spacer"
-        android:layout_width="@dimen/status_bar_wifi_signal_spacer_width"
-        android:layout_height="4dp"
-        android:visibility="gone"
-        />
-    <ViewStub
-        android:id="@+id/connected_device_signals_stub"
-        android:layout="@layout/connected_device_signal"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content" />
-    <LinearLayout
-        android:id="@+id/mobile_signal_group"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        >
-    </LinearLayout>
-    <View
-        android:id="@+id/wifi_airplane_spacer"
-        android:layout_width="@dimen/status_bar_airplane_spacer_width"
-        android:layout_height="4dp"
-        android:visibility="gone"
-        />
-    <ImageView
-        android:id="@+id/airplane"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        />
-</com.android.systemui.statusbar.SignalClusterView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 75c0ec3..7d403b2 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -43,6 +43,8 @@
         android:clipToPadding="false"
         android:clipChildren="false">
 
+        <include layout="@layout/dock_info_overlay" />
+
         <FrameLayout
             android:id="@+id/qs_frame"
             android:layout="@layout/qs_panel"
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 34c208a..02062bb 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -43,6 +43,14 @@
                    android:visibility="invisible" />
     </com.android.systemui.statusbar.BackDropView>
 
+    <com.android.systemui.wallpaper.AodMaskView
+        android:id="@+id/aod_mask"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:importantForAccessibility="no"
+        android:visibility="invisible"
+        sysui:ignoreRightInset="true" />
+
     <com.android.systemui.statusbar.ScrimView
         android:id="@+id/scrim_behind"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index eed44dd..de2a950 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors is af"</string>
     <string name="device_services" msgid="1191212554435440592">"Toesteldienste"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Titelloos"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 7c09112..4154643 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"ዳሳሾች ጠፍተዋል"</string>
     <string name="device_services" msgid="1191212554435440592">"የመሣሪያ አገልግሎቶች"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"ርዕስ የለም"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 16abb68..579964d 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -914,6 +914,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"إيقاف أجهزة الاستشعار"</string>
     <string name="device_services" msgid="1191212554435440592">"خدمات الأجهزة"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"بلا عنوان"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 25f7b5b..8113504 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="other"><xliff:g id="NUM_APPS_1">%d</xliff:g>টা অন্য এপ্</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"ছেন্সৰ অফ হৈ আছে"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"ডিভাইচ সেৱা"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"কোনো শিৰোনাম নাই"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 4cc91d2..6a27dbb 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -176,7 +176,7 @@
     <string name="accessibility_no_sim" msgid="8274017118472455155">"Няма SIM-карты."</string>
     <string name="accessibility_cell_data" msgid="5326139158682385073">"Мабільная перадача даных"</string>
     <string name="accessibility_cell_data_on" msgid="5927098403452994422">"Мабільная перадача даных уключана"</string>
-    <string name="cell_data_off_content_description" msgid="4356113230238585072">"Мабільны інтэрнэт выключаны"</string>
+    <string name="cell_data_off_content_description" msgid="4356113230238585072">"Мабільная перадача даных выключана"</string>
     <string name="cell_data_off" msgid="1051264981229902873">"Выключаны"</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Сувязь па Bluetooth."</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"Рэжым палёту."</string>
@@ -865,7 +865,7 @@
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Замяніць"</string>
     <string name="running_foreground_services_title" msgid="381024150898615683">"Праграмы, якія працуюць у фонавым рэжыме"</string>
     <string name="running_foreground_services_msg" msgid="6326247670075574355">"Дакраніцеся, каб даведацца пра выкарыстанне трафіка і акумулятара"</string>
-    <string name="mobile_data_disable_title" msgid="1068272097382942231">"Адключыць мабільны інтэрнэт?"</string>
+    <string name="mobile_data_disable_title" msgid="1068272097382942231">"Выключыць мабільную перадачу даных?"</string>
     <string name="mobile_data_disable_message" msgid="4756541658791493506">"У вас не будзе доступу да даных ці інтэрнэту праз аператара <xliff:g id="CARRIER">%s</xliff:g>. Інтэрнэт будзе даступны толькі праз Wi-Fi."</string>
     <string name="mobile_data_disable_message_default_carrier" msgid="6078110473451946831">"ваш аператар"</string>
     <string name="touch_filtered_warning" msgid="8671693809204767551">"Праграма хавае запыт на дазвол, таму ваш адказ немагчыма спраўдзіць у Наладах."</string>
@@ -904,6 +904,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Датчыкі выкл."</string>
     <string name="device_services" msgid="1191212554435440592">"Сэрвісы прылады"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Без назвы"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index ede7af9..e9effcf 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Сензорите са изключени"</string>
     <string name="device_services" msgid="1191212554435440592">"Услуги за устройството"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Няма заглавие"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 76a344f..0724e37 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"সেন্সর বন্ধ"</string>
     <string name="device_services" msgid="1191212554435440592">"ডিভাইস সংক্রান্ত পরিষেবা"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"কোনও শীর্ষক নেই"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 69550b0..4e8e833 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors desactivats"</string>
     <string name="device_services" msgid="1191212554435440592">"Serveis per a dispositius"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sense títol"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index cf116e3..30bf1de 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -902,6 +902,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzory jsou vypnuty"</string>
     <string name="device_services" msgid="1191212554435440592">"Služby zařízení"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Bez názvu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ce9a821..ad4afcf 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -21,9 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"System-UI"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ryd"</string>
-    <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen underretninger"</string>
+    <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen notifikationer"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"I gang"</string>
-    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Underretninger"</string>
+    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifikationer"</string>
     <string name="battery_low_title" msgid="9187898087363540349">"Enheden løber muligvis snart tør for batteri"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> tilbage"</string>
     <string name="battery_low_percent_format_hybrid" msgid="6838677459286775617">"Der er <xliff:g id="PERCENTAGE">%1$s</xliff:g> tilbage eller ca. <xliff:g id="TIME">%2$s</xliff:g>, alt efter hvordan du bruger enheden"</string>
@@ -41,7 +41,7 @@
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatisk skærmrotation"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"LYDLØS"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
-    <string name="status_bar_settings_notifications" msgid="397146176280905137">"Underretninger"</string>
+    <string name="status_bar_settings_notifications" msgid="397146176280905137">"Notifikationer"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Netdeling via Bluetooth anvendt"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfigurer inputmetoder"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysisk tastatur"</string>
@@ -71,7 +71,7 @@
     <string name="screenshot_failed_to_save_text" msgid="3041612585107107310">"Screenshottet kan ikke gemmes, fordi der er begrænset lagerplads"</string>
     <string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Appen eller din organisation tillader ikke, at du tager screenshots"</string>
     <string name="screenrecord_name" msgid="4196719243134204796">"Skærmoptagelse"</string>
-    <string name="screenrecord_channel_description" msgid="4630777331970993858">"Konstant underretning om skærmoptagelse"</string>
+    <string name="screenrecord_channel_description" msgid="4630777331970993858">"Konstant notifikation om skærmoptagelse"</string>
     <string name="screenrecord_start_label" msgid="5177739269492196055">"Start optagelse"</string>
     <string name="screenrecord_mic_label" msgid="4522870600914810019">"Optag voiceover"</string>
     <string name="screenrecord_taps_label" msgid="1776467076607964790">"Vis tryk"</string>
@@ -187,9 +187,9 @@
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Batteri <xliff:g id="NUMBER">%d</xliff:g> procent."</string>
     <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Batteriet oplades. <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> %%."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Systemindstillinger."</string>
-    <string name="accessibility_notifications_button" msgid="4498000369779421892">"Underretninger."</string>
-    <string name="accessibility_overflow_action" msgid="5681882033274783311">"Se alle underretninger"</string>
-    <string name="accessibility_remove_notification" msgid="3603099514902182350">"Ryd underretning."</string>
+    <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notifikationer."</string>
+    <string name="accessibility_overflow_action" msgid="5681882033274783311">"Se alle notifikationer"</string>
+    <string name="accessibility_remove_notification" msgid="3603099514902182350">"Ryd notifikation."</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS aktiveret."</string>
     <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS samler data."</string>
     <string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter aktiveret."</string>
@@ -199,8 +199,8 @@
     <skip />
     <!-- no translation found for accessibility_work_mode (702887484664647430) -->
     <skip />
-    <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Underretningen er annulleret."</string>
-    <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Underretningspanel."</string>
+    <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notifikationen er annulleret."</string>
+    <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Notifikationspanel."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Hurtige indstillinger."</string>
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Låseskærm."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Indstillinger"</string>
@@ -265,14 +265,14 @@
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Søger efter GPS"</string>
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Placeringen er angivet ved hjælp af GPS"</string>
     <string name="accessibility_location_active" msgid="2427290146138169014">"Aktive placeringsanmodninger"</string>
-    <string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle underretninger."</string>
+    <string name="accessibility_clear_all" msgid="5235938559247164925">"Ryd alle notifikationer."</string>
     <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"<xliff:g id="NUMBER">%s</xliff:g> mere"</string>
     <string name="notification_group_overflow_indicator_ambient" msgid="879560382990377886">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, +<xliff:g id="OVERFLOW">%2$s</xliff:g>"</string>
     <plurals name="notification_group_overflow_description" formatted="false" msgid="4579313201268495404">
-      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> underretning mere i gruppen.</item>
-      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> underretninger mere i gruppen.</item>
+      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> notifikation mere i gruppen.</item>
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> notifikationer mere i gruppen.</item>
     </plurals>
-    <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Underretningsindstillinger"</string>
+    <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Notifikationsindstillinger"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Indstillinger for <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skærmen roterer automatisk."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skærmen er nu låst i liggende retning."</string>
@@ -347,7 +347,7 @@
       <item quantity="one">%d enhed</item>
       <item quantity="other">%d enheder</item>
     </plurals>
-    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Underretninger"</string>
+    <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notifikationer"</string>
     <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Lommelygte"</string>
     <string name="quick_settings_cellular_detail_title" msgid="3661194685666477347">"Mobildata"</string>
     <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Dataforbrug"</string>
@@ -382,7 +382,7 @@
     <string name="zen_silence_introduction_voice" msgid="3948778066295728085">"Dette blokerer ALLE lyde og vibrationer, bl.a. fra alarmer, musik, videoer og spil. Du vil stadig kunne foretage telefonopkald."</string>
     <string name="zen_silence_introduction" msgid="3137882381093271568">"Dette blokerer ALLE lyde og vibrationer, bl.a. fra alarmer, musik, videoer og spil."</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
-    <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre presserende underretninger nedenfor"</string>
+    <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre presserende notifikationer nedenfor"</string>
     <string name="notification_tap_again" msgid="7590196980943943842">"Tryk igen for at åbne"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Stryg opad for at låse op"</string>
     <string name="do_disclosure_generic" msgid="5615898451805157556">"Denne enhed administreres af din organisation"</string>
@@ -439,9 +439,9 @@
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Vis ikke igen"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Ryd alt"</string>
     <string name="manage_notifications_text" msgid="2386728145475108753">"Administrer"</string>
-    <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Underretninger er sat på pause af Forstyr ikke"</string>
+    <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Notifikationer er sat på pause af Forstyr ikke"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Start nu"</string>
-    <string name="empty_shade_text" msgid="708135716272867002">"Ingen underretninger"</string>
+    <string name="empty_shade_text" msgid="708135716272867002">"Ingen notifikationer"</string>
     <string name="profile_owned_footer" msgid="8021888108553696069">"Profilen kan overvåges"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"Netværket kan være overvåget"</string>
     <string name="branded_vpn_footer" msgid="2168111859226496230">"Netværket kan være overvåget"</string>
@@ -501,7 +501,7 @@
     <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"Låst op for <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_trust_managed" msgid="8319646760022357585">"<xliff:g id="TRUST_AGENT">%1$s</xliff:g> kører"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheden vil forblive låst, indtil du manuelt låser den op"</string>
-    <string name="hidden_notifications_title" msgid="7139628534207443290">"Modtag underretninger hurtigere"</string>
+    <string name="hidden_notifications_title" msgid="7139628534207443290">"Modtag notifikationer hurtigere"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Se dem, før du låser op"</string>
     <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Nej tak"</string>
     <string name="hidden_notifications_setup" msgid="41079514801976810">"Konfigurer"</string>
@@ -530,7 +530,7 @@
     <string name="stream_ring" msgid="8213049469184048338">"Ring"</string>
     <string name="stream_music" msgid="9086982948697544342">"Medie"</string>
     <string name="stream_alarm" msgid="5209444229227197703">"Alarm"</string>
-    <string name="stream_notification" msgid="2563720670905665031">"Underretning"</string>
+    <string name="stream_notification" msgid="2563720670905665031">"Notifikation"</string>
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Tonesignalfrekvens (DTMF)"</string>
     <string name="stream_accessibility" msgid="301136219144385106">"Hjælpefunktioner"</string>
@@ -549,7 +549,7 @@
     <string name="volume_ringer_hint_unmute" msgid="6602880133293060368">"slå lyden til"</string>
     <string name="volume_ringer_hint_vibrate" msgid="4036802135666515202">"vibrer"</string>
     <string name="volume_dialog_title" msgid="7272969888820035876">"%s lydstyrkeknapper"</string>
-    <string name="volume_dialog_ringer_guidance_ring" msgid="3360373718388509040">"Der afspilles lyd ved opkald og underretninger (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
+    <string name="volume_dialog_ringer_guidance_ring" msgid="3360373718388509040">"Der afspilles lyd ved opkald og notifikationer (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
     <string name="output_title" msgid="5355078100792942802">"Medieafspilning"</string>
     <string name="output_calls_title" msgid="8717692905017206161">"Udgang til telefonopkald"</string>
     <string name="output_none_found" msgid="5544982839808921091">"Der blev ikke fundet nogen enheder"</string>
@@ -595,25 +595,25 @@
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå Bluetooth til?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Bluetooth skal være slået til, før du kan knytte dit tastatur til din tablet."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå til"</string>
-    <string name="show_silently" msgid="6841966539811264192">"Vis underretninger lydløst"</string>
-    <string name="block" msgid="2734508760962682611">"Bloker alle underretninger"</string>
+    <string name="show_silently" msgid="6841966539811264192">"Vis notifikationer lydløst"</string>
+    <string name="block" msgid="2734508760962682611">"Bloker alle notifikationer"</string>
     <string name="do_not_silence" msgid="6878060322594892441">"Skal ikke sættes på lydløs"</string>
     <string name="do_not_silence_block" msgid="4070647971382232311">"Skal ikke sættes på lydløs eller blokeres"</string>
-    <string name="tuner_full_importance_settings" msgid="3207312268609236827">"Kontrolelementer til underretning om strøm"</string>
+    <string name="tuner_full_importance_settings" msgid="3207312268609236827">"Kontrolelementer til notifikation om strøm"</string>
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Til"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Fra"</string>
-    <string name="power_notification_controls_description" msgid="4372459941671353358">"Med kontrolelementer til underretninger om strøm kan du konfigurere et vigtighedsniveau fra 0 til 5 for en apps underretninger. \n\n"<b>"Niveau 5"</b>\n"- Vis øverst på listen over underretninger \n- Tillad afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 4"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 3"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n\n"<b>"Niveau 2"</b>\n"- Ingen afbrydelse af fuld skærm \n Se aldrig smugkig \n- Ingen lyd og vibration \n\n"<b>"Niveau 1"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n- Ingen lyd eller vibration \n- Skjul fra låseskærm og statusbjælke \n- Vis nederst på listen over underretninger \n\n"<b>"Niveau 0"</b>\n"- Bloker alle underretninger fra appen."</string>
-    <string name="notification_header_default_channel" msgid="7506845022070889909">"Underretninger"</string>
-    <string name="notification_channel_disabled" msgid="344536703863700565">"Du får ikke længere vist disse underretninger"</string>
-    <string name="notification_channel_minimized" msgid="1664411570378910931">"Disse underretninger minimeres"</string>
-    <string name="notification_channel_silenced" msgid="2877199534497961942">"Disse underretninger vises lydløst"</string>
-    <string name="notification_channel_unsilenced" msgid="4790904571552394137">"Disse underretninger underretter dig"</string>
-    <string name="inline_blocking_helper" msgid="3055064577771478591">"Du afviser som regel disse underretninger. \nVil du blive ved med at se dem?"</string>
-    <string name="inline_keep_showing" msgid="8945102997083836858">"Vil du fortsætte med at se disse underretninger?"</string>
-    <string name="inline_stop_button" msgid="4172980096860941033">"Stop underretninger"</string>
+    <string name="power_notification_controls_description" msgid="4372459941671353358">"Med kontrolelementer til notifikationer om strøm kan du konfigurere et vigtighedsniveau fra 0 til 5 for en apps notifikationer. \n\n"<b>"Niveau 5"</b>\n"- Vis øverst på listen over notifikationer \n- Tillad afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 4"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 3"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n\n"<b>"Niveau 2"</b>\n"- Ingen afbrydelse af fuld skærm \n Se aldrig smugkig \n- Ingen lyd og vibration \n\n"<b>"Niveau 1"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n- Ingen lyd eller vibration \n- Skjul fra låseskærm og statusbjælke \n- Vis nederst på listen over notifikationer \n\n"<b>"Niveau 0"</b>\n"- Bloker alle notifikationer fra appen."</string>
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notifikationer"</string>
+    <string name="notification_channel_disabled" msgid="344536703863700565">"Du får ikke længere vist disse notifikationer"</string>
+    <string name="notification_channel_minimized" msgid="1664411570378910931">"Disse notifikationer minimeres"</string>
+    <string name="notification_channel_silenced" msgid="2877199534497961942">"Disse notifikationer vises lydløst"</string>
+    <string name="notification_channel_unsilenced" msgid="4790904571552394137">"Disse notifikationer underretter dig"</string>
+    <string name="inline_blocking_helper" msgid="3055064577771478591">"Du afviser som regel disse notifikationer. \nVil du blive ved med at se dem?"</string>
+    <string name="inline_keep_showing" msgid="8945102997083836858">"Vil du fortsætte med at se disse notifikationer?"</string>
+    <string name="inline_stop_button" msgid="4172980096860941033">"Stop notifikationer"</string>
     <!-- no translation found for inline_block_button (8735843688021655065) -->
     <skip />
-    <string name="inline_keep_button" msgid="6665940297019018232">"Fortsæt med at vise underretninger"</string>
+    <string name="inline_keep_button" msgid="6665940297019018232">"Fortsæt med at vise notifikationer"</string>
     <string name="inline_minimize_button" msgid="966233327974702195">"Minimer"</string>
     <string name="inline_silent_button_silent" msgid="4411510650503783646">"Vis lydløst"</string>
     <!-- no translation found for inline_silent_button_stay_silent (6308371431217601009) -->
@@ -622,8 +622,8 @@
     <skip />
     <!-- no translation found for inline_silent_button_keep_alerting (327696842264359693) -->
     <skip />
-    <string name="inline_keep_showing_app" msgid="1723113469580031041">"Vil du fortsætte med at se underretninger fra denne app?"</string>
-    <string name="notification_unblockable_desc" msgid="1037434112919403708">"Disse underretninger kan ikke deaktiveres"</string>
+    <string name="inline_keep_showing_app" msgid="1723113469580031041">"Vil du fortsætte med at se notifikationer fra denne app?"</string>
+    <string name="notification_unblockable_desc" msgid="1037434112919403708">"Disse notifikationer kan ikke deaktiveres"</string>
     <string name="notification_delegate_header" msgid="9167022191405284627">"via <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="appops_camera" msgid="8100147441602585776">"Denne app anvender kameraet."</string>
     <string name="appops_microphone" msgid="741508267659494555">"Denne app anvender mikrofonen."</string>
@@ -634,15 +634,15 @@
     <string name="appops_camera_mic_overlay" msgid="6718768197048030993">"Denne app vises over andre apps på din skærm og anvender mikrofonen og kameraet."</string>
     <string name="notification_appops_settings" msgid="1028328314935908050">"Indstillinger"</string>
     <string name="notification_appops_ok" msgid="1156966426011011434">"OK"</string>
-    <string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Styring af underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g> blev åbnet"</string>
-    <string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Styring af underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g> blev lukket"</string>
-    <string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Tillad underretninger fra denne kanal"</string>
+    <string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Styring af notifikationer for <xliff:g id="APP_NAME">%1$s</xliff:g> blev åbnet"</string>
+    <string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Styring af notifikationer for <xliff:g id="APP_NAME">%1$s</xliff:g> blev lukket"</string>
+    <string name="notification_channel_switch_accessibility" msgid="3420796005601900717">"Tillad notifikationer fra denne kanal"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
     <string name="notification_app_settings" msgid="420348114670768449">"Tilpas"</string>
     <string name="notification_done" msgid="5279426047273930175">"Udfør"</string>
     <string name="inline_undo" msgid="558916737624706010">"Fortryd"</string>
     <string name="notification_menu_accessibility" msgid="2046162834248888553">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
-    <string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrolelementer til underretninger"</string>
+    <string name="notification_menu_gear_description" msgid="2204480013726775108">"kontrolelementer til notifikationer"</string>
     <string name="notification_menu_snooze_description" msgid="3653669438131034525">"Indstillinger for udsættelse"</string>
     <string name="notification_menu_snooze_action" msgid="1112254519029621372">"Udsæt"</string>
     <string name="snooze_undo" msgid="6074877317002985129">"FORTRYD"</string>
@@ -689,7 +689,7 @@
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"Start"</string>
     <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"Seneste"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"Tilbage"</string>
-    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Underretninger"</string>
+    <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"Notifikationer"</string>
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"Tastaturgenveje"</string>
     <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"Skift tastaturlayout"</string>
     <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"Applikationer"</string>
@@ -759,7 +759,7 @@
     <item msgid="2139628951880142927">"Vis procent ved opladning (standard)"</item>
     <item msgid="3327323682209964956">"Vis ikke dette ikon"</item>
   </string-array>
-    <string name="tuner_low_priority" msgid="1325884786608312358">"Vis ikoner for underretninger med lav prioritet"</string>
+    <string name="tuner_low_priority" msgid="1325884786608312358">"Vis ikoner for notifikationer med lav prioritet"</string>
     <string name="other" msgid="4060683095962566764">"Andet"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Adskiller til opdelt skærm"</string>
     <string name="accessibility_action_divider_left_full" msgid="2801570521881574972">"Vis venstre del i fuld skærm"</string>
@@ -779,7 +779,7 @@
     <string name="accessibility_qs_edit_tile_add" msgid="3520406665865985109">"Føj <xliff:g id="TILE_NAME">%1$s</xliff:g> til position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
     <string name="accessibility_qs_edit_tile_move" msgid="3108103090006972938">"Flyt <xliff:g id="TILE_NAME">%1$s</xliff:g> til position <xliff:g id="POSITION">%2$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Redigeringsværktøj for Hurtige indstillinger."</string>
-    <string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"<xliff:g id="ID_1">%1$s</xliff:g>-underretning: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"<xliff:g id="ID_1">%1$s</xliff:g>-notifikation: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="dock_forced_resizable" msgid="5914261505436217520">"Appen fungerer muligvis ikke i opdelt skærm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Appen understøtter ikke opdelt skærm."</string>
     <string name="forced_resizable_secondary_display" msgid="4230857851756391925">"Appen fungerer muligvis ikke på sekundære skærme."</string>
@@ -828,7 +828,7 @@
     <string name="tuner_right" msgid="6222734772467850156">"Højre"</string>
     <string name="tuner_menu" msgid="191640047241552081">"Menu"</string>
     <string name="tuner_app" msgid="3507057938640108777">"Appen <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="notification_channel_alerts" msgid="4496839309318519037">"Underretninger"</string>
+    <string name="notification_channel_alerts" msgid="4496839309318519037">"Notifikationer"</string>
     <string name="notification_channel_battery" msgid="5786118169182888462">"Batteri"</string>
     <string name="notification_channel_screenshot" msgid="6314080179230000938">"Screenshots"</string>
     <string name="notification_channel_general" msgid="4525309436693914482">"Generelle meddelelser"</string>
@@ -852,7 +852,7 @@
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Behold"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Erstat"</string>
     <string name="running_foreground_services_title" msgid="381024150898615683">"Apps, der kører i baggrunden"</string>
-    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tryk for at se oplysninger om batteri- og dataforbrug"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tryk for at se info om batteri- og dataforbrug"</string>
     <string name="mobile_data_disable_title" msgid="1068272097382942231">"Vil du deaktivere mobildata?"</string>
     <string name="mobile_data_disable_message" msgid="4756541658791493506">"Du vil ikke have data- eller internetadgang via <xliff:g id="CARRIER">%s</xliff:g>. Der vil kunne være adgang til internettet via Wi-Fi."</string>
     <string name="mobile_data_disable_message_default_carrier" msgid="6078110473451946831">"dit mobilselskab"</string>
@@ -876,7 +876,7 @@
     <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8640691753867990511">"Apps anvender enhedens <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <!-- no translation found for ongoing_privacy_chip_content_multiple_apps_single_op (4871926099254314088) -->
     <string name="ongoing_privacy_dialog_cancel" msgid="5479124524931216790">"Luk"</string>
-    <string name="ongoing_privacy_dialog_open_settings" msgid="2074844974365194279">"Se oplysninger"</string>
+    <string name="ongoing_privacy_dialog_open_settings" msgid="2074844974365194279">"Se info"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App, der anvender din/dit <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps, der anvender din/dit <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Deaktiver sensorer"</string>
     <string name="device_services" msgid="1191212554435440592">"Enhedstjenester"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Ingen titel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 447f8b9..0be730a 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -894,6 +894,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensoren aus"</string>
     <string name="device_services" msgid="1191212554435440592">"Gerätedienste"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Kein Titel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 5e2fb03..703bc40 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
     <string name="device_services" msgid="1191212554435440592">"Device Services"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3891569..31fd04a 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
     <string name="device_services" msgid="1191212554435440592">"Device Services"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 5e2fb03..703bc40 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
     <string name="device_services" msgid="1191212554435440592">"Device Services"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 5e2fb03..703bc40 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
     <string name="device_services" msgid="1191212554435440592">"Device Services"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 9ef6a83..761acf6 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> app más</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Se desactivaron los sensores"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"Servicios del dispositivo"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sin título"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index f4e107d..0b3ba5d 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desactivados"</string>
     <string name="device_services" msgid="1191212554435440592">"Servicios del dispositivo"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sin título"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index d8568df..e318291 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Andurid on välja lülitatud"</string>
     <string name="device_services" msgid="1191212554435440592">"Seadme teenused"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Pealkiri puudub"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index cfdf7a5..5b9f0cf 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sentsoreak desaktibatuta daude"</string>
     <string name="device_services" msgid="1191212554435440592">"Gailuetarako zerbitzuak"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Ez du izenik"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index cd92d45..931def7 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Anturit pois päältä"</string>
     <string name="device_services" msgid="1191212554435440592">"Laitepalvelut"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Ei nimeä"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 695a6a5..d1412aa 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Capteurs désactivés"</string>
     <string name="device_services" msgid="1191212554435440592">"Services de l\'appareil"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sans titre"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index a1a0352..8ba575b 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Capteurs désactivés"</string>
     <string name="device_services" msgid="1191212554435440592">"Services pour l\'appareil"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sans titre"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 7f111e8..2784567 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Desactivar sensores"</string>
     <string name="device_services" msgid="1191212554435440592">"Servizos do dispositivo"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sen título"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 8525094..f17a7f6 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="other"><xliff:g id="NUM_APPS_1">%d</xliff:g> અન્ય ઍપ</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"સેન્સર બંધ છે"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"ડિવાઇસ સેવાઓ"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"કોઈ શીર્ષક નથી"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index ae12412..49d923a 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Érzékelők kikapcsolva"</string>
     <string name="device_services" msgid="1191212554435440592">"Eszközszolgáltatások"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Nincs cím"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index ffcc762..dc592c5 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Տվիչներն անջատած են"</string>
     <string name="device_services" msgid="1191212554435440592">"Սարքի ծառայություններ"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Անանուն"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index eb99a6c..1b43e65 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensor nonaktif"</string>
     <string name="device_services" msgid="1191212554435440592">"Layanan Perangkat"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Tanpa judul"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 0040c3c..36b557d 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Slökkt á skynjurum"</string>
     <string name="device_services" msgid="1191212554435440592">"Tækjaþjónusta"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Enginn titill"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 83956e8..21c259a 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensori disattivati"</string>
     <string name="device_services" msgid="1191212554435440592">"Servizi del dispositivo"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Senza titolo"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index f7d52ed..ff88a0d 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"センサー OFF"</string>
     <string name="device_services" msgid="1191212554435440592">"デバイス サービス"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"タイトルなし"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index a1788fc..41ef3e2 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Датчиктер өшірулі"</string>
     <string name="device_services" msgid="1191212554435440592">"Құрылғы қызметтері"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Атауы жоқ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 0cbd06c..5520cb0 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"បិទឧបករណ៍​ចាប់សញ្ញា"</string>
     <string name="device_services" msgid="1191212554435440592">"សេវាកម្មឧបករណ៍"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"គ្មាន​ចំណងជើង"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 9f46742..f829c12 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="other"><xliff:g id="NUM_APPS_1">%d</xliff:g> ಇತರ ಆ್ಯಪ್‌ಗಳು</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"ಸೆನ್ಸರ್‌ಗಳು ಆಫ್"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"ಸಾಧನ ಸೇವೆಗಳು"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"ಯಾವುದೇ ಶೀರ್ಷಿಕೆಯಿಲ್ಲ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 581ffa9..f5168fb 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"센서 사용 안함"</string>
     <string name="device_services" msgid="1191212554435440592">"기기 서비스"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"제목 없음"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index ba5a0ac..9558c3a 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Сенсорлорду өчүрүү"</string>
     <string name="device_services" msgid="1191212554435440592">"Түзмөк кызматтары"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Аталышы жок"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 46cd3f0..5786fb0 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -901,8 +901,6 @@
       <item quantity="other">Dar <xliff:g id="NUM_APPS_1">%d</xliff:g> programų</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Jutikliai išjungti"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"Įrenginio paslaugos"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Nėra pavadinimo"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index a1203d5..cebd91c 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -896,6 +896,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensori izslēgti"</string>
     <string name="device_services" msgid="1191212554435440592">"Ierīces pakalpojumi"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Nav nosaukuma"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index a3fd2d5..df1bdbb 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Сензорите се исклучени"</string>
     <string name="device_services" msgid="1191212554435440592">"Услуги за уредот"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Без наслов"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index f3075b8..5800e0e 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"സെൻസറുകൾ ഓഫാണ്"</string>
     <string name="device_services" msgid="1191212554435440592">"ഉപകരണ സേവനങ്ങള്‍"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"പേരില്ല"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 7236893..e96865e 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Мэдрэгчийг унтраах"</string>
     <string name="device_services" msgid="1191212554435440592">"Төхөөрөмжийн үйлчилгээ"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Гарчиггүй"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 59e481c..6022a9c 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="other">इतर <xliff:g id="NUM_APPS_1">%d</xliff:g> अ‍ॅप्स</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"सेन्सर बंद आहेत"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"डिव्हाइस सेवा"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"शीर्षक नाही"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index e77771d..1a9eb1c 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Penderia dimatikan"</string>
     <string name="device_services" msgid="1191212554435440592">"Perkhidmatan Peranti"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Tiada tajuk"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index e5561e8..dbfa01e 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"အာရုံခံကိရိယာများ ပိတ်ထားသည်"</string>
     <string name="device_services" msgid="1191212554435440592">"စက်ပစ္စည်းဝန်ဆောင်မှုများ"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"ခေါင်းစဉ် မရှိပါ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index a1a12bd..e790684 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorer er av"</string>
     <string name="device_services" msgid="1191212554435440592">"Enhetstjenester"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Ingen tittel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 096db56..9b4441f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> अन्य अनुप्रयोग</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"सेन्सरहरू निष्क्रिय छन्"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"यन्त्रका सेवाहरू"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"शीर्षक छैन"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3607ff8..e570789 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensoren uit"</string>
     <string name="device_services" msgid="1191212554435440592">"Apparaatservices"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Geen titel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 5cb98ee..dd260b1 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g>ଟି ଅନ୍ୟ ଆପ୍‍</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"ସେନ୍ସର୍‍ଗୁଡ଼ିକ ବନ୍ଦ ଅଛି"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"ଡିଭାଇସ୍‍ ସେବାଗୁଡିକ"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"କୌଣସି ଶୀର୍ଷକ ନାହିଁ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 3702e2b..e36fea2 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="other"><xliff:g id="NUM_APPS_1">%d</xliff:g> ਹੋਰ ਐਪਾਂ</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"ਸੈਂਸਰ ਬੰਦ ਕਰੋ"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"ਕੋਈ ਸਿਰਲੇਖ ਨਹੀਂ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 4ece82c..ed2902f 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -901,8 +901,6 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> inna aplikacja</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Wyłącz czujniki"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"Usługi urządzenia"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Bez tytułu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 375f5e8..c1858fc 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> outra aplicação</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desativados"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"Serviços do dispositivo"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Sem título"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 24254f6..c393bde 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -896,6 +896,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori dezactivați"</string>
     <string name="device_services" msgid="1191212554435440592">"Servicii pentru dispozitiv"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Fără titlu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a5d4059..e643c8f 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -902,6 +902,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Датчики отключены"</string>
     <string name="device_services" msgid="1191212554435440592">"Сервисы устройства"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Без названия"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index d9ba8de..bcc444f 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -901,8 +901,6 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%d</xliff:g> ďalšia aplikácia</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzory sú vypnuté"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"Služby zariadenia"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Bez názvu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 5048227..706e700 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -902,6 +902,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Izklop za tipala"</string>
     <string name="device_services" msgid="1191212554435440592">"Storitve naprave"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Brez naslova"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 22ffa81..3c8c3ab 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -800,7 +800,7 @@
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimera"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Stäng"</string>
     <string name="pip_phone_settings" msgid="8080777499521528521">"Inställningar"</string>
-    <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Tryck och dra nedåt för att avvisa"</string>
+    <string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Tryck och dra nedåt för att ta bort"</string>
     <string name="pip_menu_title" msgid="4707292089961887657">"Meny"</string>
     <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> visas i bild-i-bild"</string>
     <string name="pip_notification_message" msgid="5619512781514343311">"Om du inte vill att den här funktionen används i <xliff:g id="NAME">%s</xliff:g> öppnar du inställningarna genom att trycka. Sedan inaktiverar du funktionen."</string>
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorer har inaktiverats"</string>
     <string name="device_services" msgid="1191212554435440592">"Enhetstjänster"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Ingen titel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index a35c78c..f75cc4d 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="one">வேறு <xliff:g id="NUM_APPS_0">%d</xliff:g> ஆப்ஸ்</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"சென்சார்களை ஆஃப் செய்தல்"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"சாதன சேவைகள்"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"தலைப்பு இல்லை"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index e7eafbe..894263e 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -889,8 +889,6 @@
       <item quantity="one">మరో <xliff:g id="NUM_APPS_0">%d</xliff:g> యాప్</item>
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"సెన్సార్‌లు ఆఫ్"</string>
-    <!-- no translation found for device_services (1191212554435440592) -->
-    <skip />
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="device_services" msgid="1191212554435440592">"పరికర సేవలు"</string>
+    <string name="music_controls_no_title" msgid="5236895307087002011">"శీర్షిక లేదు"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 05df7bd..ae581ac 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"เซ็นเซอร์ปิดอยู่"</string>
     <string name="device_services" msgid="1191212554435440592">"บริการของอุปกรณ์"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"ไม่มีชื่อ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 3bd6ea6..ab20ff0 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Naka-off ang mga sensor"</string>
     <string name="device_services" msgid="1191212554435440592">"Mga Serbisyo ng Device"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Walang pamagat"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4962b16..32201fb 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensörler kapalı"</string>
     <string name="device_services" msgid="1191212554435440592">"Cihaz Hizmetleri"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Başlıksız"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 3a59029..ee9da5e 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"سینسرز آف ہیں"</string>
     <string name="device_services" msgid="1191212554435440592">"آلہ کی سروس"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"کوئی عنوان نہیں ہے"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 3388bcb..488bfae 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorlar nofaol"</string>
     <string name="device_services" msgid="1191212554435440592">"Qurilma xizmatlari"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Nomsiz"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 3ebb8dd..125eb72 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Tắt cảm biến"</string>
     <string name="device_services" msgid="1191212554435440592">"Dịch vụ cho thiết bị"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"Không có tiêu đề"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index d480a8a..d6fd3d89 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"已关闭传感器"</string>
     <string name="device_services" msgid="1191212554435440592">"设备服务"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"无标题"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 7ff70d9..dbe24bb 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -890,6 +890,5 @@
     </plurals>
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"已關閉感應器"</string>
     <string name="device_services" msgid="1191212554435440592">"裝置服務"</string>
-    <!-- no translation found for music_controls_no_title (5236895307087002011) -->
-    <skip />
+    <string name="music_controls_no_title" msgid="5236895307087002011">"無標題"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index b3567f8..d5f29ba 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -130,6 +130,7 @@
 
     <!-- Biometric dialog colors -->
     <color name="biometric_dialog_dim_color">#80000000</color> <!-- 50% black -->
+    <color name="biometric_face_icon_gray">#ffbdc1c6</color>
 
     <!-- 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 889db66..f2be2e7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -106,7 +106,7 @@
 
     <!-- The default tiles to display in QuickSettings -->
     <string name="quick_settings_tiles_default" translatable="false">
-        wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast
+        wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast,sensorprivacy
     </string>
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
@@ -449,6 +449,20 @@
          better (narrower) line-break for a double-line smart reply button. -->
     <integer name="config_smart_replies_in_notifications_max_squeeze_remeasure_attempts">3</integer>
 
+    <!-- Smart replies in notifications: Whether by default tapping on a choice should let the user
+         edit the input before it is sent to the app. Developers can override this via
+         RemoteInput.Builder.setEditChoicesBeforeSending. -->
+    <bool name="config_smart_replies_in_notifications_edit_choices_before_sending">false</bool>
+
+    <!-- Smart replies in notifications: Whether smart suggestions in notifications are enabled in
+         heads-up notifications.  -->
+    <bool name="config_smart_replies_in_notifications_show_in_heads_up">true</bool>
+
+    <!-- Smart replies in notifications: Minimum number of system generated smart replies that
+         should be shown in a notification. If we cannot show at least this many replies we instead
+         show none. -->
+    <integer name="config_smart_replies_in_notifications_min_num_system_generated_replies">0</integer>
+
     <!-- Screenshot editing default activity.  Must handle ACTION_EDIT image/png intents.
          Blank sends the user to the Chooser first.
          This name is in the ComponentName flattened format (package/class)  -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6037dfc..ab0bbe1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -66,9 +66,7 @@
     <item name="status_bar_icon_scale_factor" format="float" type="dimen">1.0</item>
 
     <dimen name="group_overflow_number_size">@*android:dimen/notification_text_size</dimen>
-    <dimen name="group_overflow_number_size_dark">16sp</dimen>
     <dimen name="group_overflow_number_padding">@*android:dimen/notification_content_margin_end</dimen>
-    <dimen name="group_overflow_number_extra_padding_dark">@*android:dimen/notification_extra_margin_ambient</dimen>
 
     <!-- max height of a notification such that the content can still fade out when closing -->
     <dimen name="max_notification_fadeout_height">100dp</dimen>
@@ -94,9 +92,6 @@
     <!-- Height of a large notification in the status bar -->
     <dimen name="notification_max_height">294dp</dimen>
 
-    <!-- Height of an ambient notification on ambient display -->
-    <dimen name="notification_ambient_height">400dp</dimen>
-
     <!-- Height of a heads up notification in the status bar for legacy custom views -->
     <dimen name="notification_max_heads_up_height_legacy">128dp</dimen>
 
@@ -861,9 +856,6 @@
     <dimen name="bottom_padding">48dp</dimen>
     <dimen name="edge_margin">8dp</dimen>
 
-    <dimen name="rounded_corner_radius">@*android:dimen/rounded_corner_radius</dimen>
-    <dimen name="rounded_corner_radius_top">@*android:dimen/rounded_corner_radius_top</dimen>
-    <dimen name="rounded_corner_radius_bottom">@*android:dimen/rounded_corner_radius_bottom</dimen>
     <dimen name="rounded_corner_content_padding">0dp</dimen>
     <dimen name="nav_content_padding">0dp</dimen>
     <dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
@@ -955,6 +947,8 @@
     <dimen name="ongoing_appops_dialog_icon_margin">8dp</dimen>
     <!-- Height and width of Application icons in Ongoing App Ops dialog -->
     <dimen name="ongoing_appops_dialog_app_icon_size">32dp</dimen>
+    <!-- Height and width of Plus sign in Ongoing App Ops dialog -->
+    <dimen name="ongoing_appops_dialog_app_plus_size">24dp</dimen>
     <!-- Height of line in Ongoing App Ops dialog-->
     <dimen name="ongoing_appops_dialog_line_height">48dp</dimen>
     <!-- Side margin of title in Ongoing App Ops dialog -->
@@ -984,14 +978,16 @@
 
     <!-- How much a bubble is elevated -->
     <dimen name="bubble_elevation">8dp</dimen>
+    <!-- Padding around a collapsed bubble -->
+    <dimen name="bubble_view_padding">0dp</dimen>
     <!-- Padding between bubbles when displayed in expanded state -->
     <dimen name="bubble_padding">8dp</dimen>
-    <!-- Padding around the view displayed when the bubble is expanded -->
-    <dimen name="bubble_expanded_view_padding">8dp</dimen>
     <!-- Size of the collapsed bubble -->
     <dimen name="bubble_size">56dp</dimen>
-    <!-- Size of an icon displayed within the bubble -->
-    <dimen name="bubble_icon_size">24dp</dimen>
+    <!-- How much to inset the icon in the circle -->
+    <dimen name="bubble_icon_inset">16dp</dimen>
+    <!-- Padding around the view displayed when the bubble is expanded -->
+    <dimen name="bubble_expanded_view_padding">8dp</dimen>
     <!-- Default height of the expanded view shown when the bubble is expanded -->
     <dimen name="bubble_expanded_default_height">400dp</dimen>
     <!-- Height of the triangle that points to the expanded bubble -->
@@ -1000,4 +996,14 @@
     <dimen name="bubble_pointer_width">6dp</dimen>
     <!-- Extra padding around the dismiss target for bubbles -->
     <dimen name="bubble_dismiss_slop">16dp</dimen>
+    <!-- Height of the header within the expanded view. -->
+    <dimen name="bubble_expanded_header_height">48dp</dimen>
+    <!-- Left and right padding applied to the header. -->
+    <dimen name="bubble_expanded_header_horizontal_padding">24dp</dimen>
+    <!-- Max width of the message bubble-->
+    <dimen name="bubble_message_max_width">144dp</dimen>
+    <!-- Min width of the message bubble -->
+    <dimen name="bubble_message_min_width">32dp</dimen>
+    <!-- Interior padding of the message bubble -->
+    <dimen name="bubble_message_padding">4dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index dac20b5..bd34bea 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -102,12 +102,20 @@
     <item type="id" name="action_snooze_assistant_suggestion_1"/>
     <item type="id" name="action_snooze"/>
 
-    <!-- For StatusBarIconContainer to tag its icon views -->
+    <!-- For StatusIconContainer to tag its icon views -->
     <item type="id" name="status_bar_view_state_tag" />
 
     <item type="id" name="display_cutout" />
 
     <!-- Optional cancel button on Keyguard -->
     <item type="id" name="cancel_button"/>
+
+    <!-- AodMaskView transition tag -->
+    <item type="id" name="aod_mask_transition_progress_tag" />
+    <item type="id" name="aod_mask_transition_progress_end_tag" />
+    <item type="id" name="aod_mask_transition_progress_start_tag" />
+
+    <!-- Global Actions Menu -->
+    <item type="id" name="global_actions_view" />
 </resources>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f384d8f..190bd7a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -150,12 +150,21 @@
     <!-- Option to always allow USB debugging from the attached computer -->
     <string name="usb_debugging_always">Always allow from this computer</string>
 
+    <!-- Button label for confirming acceptance of enabling USB debugging [CHAR LIMIT=15] -->
+    <string name="usb_debugging_allow">Allow</string>
+
     <!-- Title of notification shown when trying to enable USB debugging but a secondary user is the current foreground user. -->
     <string name="usb_debugging_secondary_user_title">USB debugging not allowed</string>
 
     <!-- Message of notification shown when trying to enable USB debugging but a secondary user is the current foreground user. -->
     <string name="usb_debugging_secondary_user_message">The user currently signed in to this device can\'t turn on USB debugging. To use this feature, switch to the primary user.</string>
 
+    <!-- Title of USB contaminant presence dialog [CHAR LIMIT=NONE] -->
+    <string name="usb_contaminant_title">USB port disabled</string>
+
+    <!-- Message of USB contaminant presence dialog [CHAR LIMIT=NONE] -->
+    <string name="usb_contaminant_message">To protect your device from liquid or debris, the USB port is disabled and won\u2019t detect any accessories.\n\nYou\u2019ll be notified when it\u2019s safe to use the USB port again.</string>
+
     <!-- Checkbox label for application compatibility mode ON (zooming app to look like it's running
          on a phone).  [CHAR LIMIT=25] -->
     <string name="compat_mode_on">Zoom to fill screen</string>
@@ -2276,7 +2285,7 @@
          app for debugging. Will not be seen by users. [CHAR LIMIT=20] -->
     <string name="heap_dump_tile_name">Dump SysUI Heap</string>
 
-    <!-- Text on chip for multiple apps using a single app op [CHAR LIMIT=10] -->
+    <!-- Text on chip for multiple apps using a single app op [CHAR LIMIT=12] -->
     <plurals name="ongoing_privacy_chip_multiple_apps">
         <item quantity="one"><xliff:g id="num_apps" example="1">%d</xliff:g> app</item>
         <item quantity="few"><xliff:g id="num_apps" example="3">%d</xliff:g> apps</item>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 8a5a69b..fa675b7 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -64,48 +64,16 @@
         <item name="hybridNotificationTextStyle">@style/hybrid_notification_text</item>
     </style>
 
-    <style name="HybridNotification.Ambient">
-        <item name="hybridNotificationStyle">@style/hybrid_notification_ambient</item>
-        <item name="hybridNotificationTitleStyle">@style/hybrid_notification_title_ambient</item>
-        <item name="hybridNotificationTextStyle">@style/hybrid_notification_text_ambient</item>
-    </style>
-
-    <style name="hybrid_notification_ambient">
-        <item name="android:paddingStart">@*android:dimen/notification_extra_margin_ambient</item>
-        <item name="android:paddingEnd">@*android:dimen/notification_extra_margin_ambient</item>
-        <item name="android:orientation">vertical</item>
-    </style>
-
     <style name="hybrid_notification">
         <item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
         <item name="android:paddingEnd">12dp</item>
     </style>
 
-    <style name="hybrid_notification_title_ambient">
-        <item name="android:layout_marginTop">@*android:dimen/notification_header_margin_top_ambient</item>
-        <item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
-        <item name="android:paddingEnd">@*android:dimen/notification_content_margin_end</item>
-        <item name="android:textAppearance">@*android:style/Notification.Header.Ambient</item>
-        <item name="android:layout_gravity">top|center_horizontal</item>
-        <item name="android:textSize">@*android:dimen/notification_ambient_title_text_size</item>
-        <item name="android:textColor">#ffffffff</item>
-    </style>
-
     <style name="hybrid_notification_title">
         <item name="android:paddingEnd">4dp</item>
         <item name="android:textAppearance">@*android:style/TextAppearance.Material.Notification.Title</item>
     </style>
 
-    <style name="hybrid_notification_text_ambient">
-        <item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
-        <item name="android:paddingEnd">@*android:dimen/notification_content_margin_end</item>
-        <item name="android:textSize">@*android:dimen/notification_ambient_text_size</item>
-        <item name="android:textColor">#eeffffff</item>
-        <item name="android:gravity">top|center_horizontal</item>
-        <item name="android:ellipsize">end</item>
-        <item name="android:maxLines">3</item>
-    </style>
-
     <style name="hybrid_notification_text"
            parent="@*android:style/Widget.Material.Notification.Text">
         <item name="android:paddingEnd">4dp</item>
@@ -125,7 +93,7 @@
 
     <style name="TextAppearance.StatusBar.Clock" parent="@*android:style/TextAppearance.StatusBar.Icon">
         <item name="android:textSize">@dimen/status_bar_clock_size</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
         <item name="android:textColor">@color/status_bar_clock_color</item>
     </style>
 
@@ -265,6 +233,10 @@
         <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
     </style>
 
+    <style name="TextAppearance.DeviceManagementDialog.Title" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
+        <item name="android:gravity">center</item>
+    </style>
+
     <style name="BaseBrightnessDialogContainer" parent="@style/Theme.SystemUI">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
index 523720d5..1a684a0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
@@ -323,7 +323,7 @@
                     return null;
                 }
                 // Create our own ClassLoader so we can use our own code as the parent.
-                ClassLoader classLoader = mManager.getClassLoader(info.sourceDir, info.packageName);
+                ClassLoader classLoader = mManager.getClassLoader(info);
                 Context pluginContext = new PluginContextWrapper(
                         mContext.createApplicationContext(info, 0), classLoader);
                 Class<?> pluginClass = Class.forName(cls, true, classLoader);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index da143f9..7139708 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -14,6 +14,7 @@
 
 package com.android.systemui.shared.plugins;
 
+import android.app.LoadedApk;
 import android.app.Notification;
 import android.app.Notification.Action;
 import android.app.NotificationManager;
@@ -44,15 +45,17 @@
 import com.android.systemui.plugins.Plugin;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
-import com.android.systemui.shared.plugins.PluginInstanceManager.PluginContextWrapper;
 import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
 
 import dalvik.system.PathClassLoader;
 
+import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 /**
  * @see Plugin
@@ -117,6 +120,7 @@
         return mPluginEnabler;
     }
 
+    // TODO(mankoff): This appears to be only called from tests. Remove?
     public <T extends Plugin> T getOneShotPlugin(Class<T> cls) {
         ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
         if (info == null) {
@@ -282,17 +286,25 @@
         }
     }
 
-    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);
+    /** Returns class loader specific for the given plugin. */
+    public ClassLoader getClassLoader(ApplicationInfo appInfo) {
+        if (!isDebuggable && !mWhitelistedPlugins.contains(appInfo.packageName)) {
+            Log.w(TAG, "Cannot get class loader for non-whitelisted plugin. Src:"
+                    + appInfo.sourceDir + ", pkg: " + appInfo.packageName);
             return null;
         }
-        if (mClassLoaders.containsKey(pkg)) {
-            return mClassLoaders.get(pkg);
+        if (mClassLoaders.containsKey(appInfo.packageName)) {
+            return mClassLoaders.get(appInfo.packageName);
         }
-        ClassLoader classLoader = new PathClassLoader(sourceDir, getParentClassLoader());
-        mClassLoaders.put(pkg, classLoader);
+
+        List<String> zipPaths = new ArrayList<>();
+        List<String> libPaths = new ArrayList<>();
+        LoadedApk.makePaths(null, true, appInfo, zipPaths, libPaths);
+        ClassLoader classLoader = new PathClassLoader(
+                TextUtils.join(File.pathSeparator, zipPaths),
+                TextUtils.join(File.pathSeparator, libPaths),
+                getParentClassLoader());
+        mClassLoaders.put(appInfo.packageName, classLoader);
         return classLoader;
     }
 
@@ -309,11 +321,6 @@
         return mParentClassLoader;
     }
 
-    public Context getContext(ApplicationInfo info, String pkg) throws NameNotFoundException {
-        ClassLoader classLoader = getClassLoader(info.sourceDir, pkg);
-        return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader);
-    }
-
     public <T> boolean dependsOn(Plugin p, Class<T> cls) {
         for (int i = 0; i < mPluginMap.size(); i++) {
             if (mPluginMap.valueAt(i).dependsOn(p, cls)) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index f3bdbae..078947c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -76,4 +76,10 @@
      */
     float getWindowCornerRadius() = 10;
 
+    /**
+     * If device supports live rounded corners on windows.
+     * This might be turned off for performance reasons
+     */
+    boolean supportsRoundedCornersOnWindows() = 11;
+
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextCompat.java
new file mode 100644
index 0000000..51fcb0a
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextCompat.java
@@ -0,0 +1,34 @@
+/*
+ * 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.shared.system;
+
+import android.content.Context;
+
+/**
+ * Wraps a context to expose some methods for launcher to call.
+ */
+public class ContextCompat {
+    private final Context mWrapped;
+
+    public ContextCompat(Context context) {
+        mWrapped = context;
+    }
+
+    public int getUserId() {
+        return mWrapped.getUserId();
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index c0a1d89..e6acfbe 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -16,14 +16,10 @@
 
 package com.android.systemui.shared.system;
 
+import android.graphics.HardwareRenderer;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.view.Surface;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-import android.view.SyncRtSurfaceTransactionApplier;
-import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
-import android.view.ThreadedRenderer;
 import android.view.View;
 import android.view.ViewRootImpl;
 
@@ -31,20 +27,21 @@
 
 /**
  * Helper class to apply surface transactions in sync with RenderThread.
+ *
+ * NOTE: This is a modification of {@link android.view.SyncRtSurfaceTransactionApplier}, we can't 
+ *       currently reference that class from the shared lib as it is hidden.
  */
 public class SyncRtSurfaceTransactionApplierCompat {
 
-    private final SyncRtSurfaceTransactionApplier mApplier;
+    private final Surface mTargetSurface;
+    private final ViewRootImpl mTargetViewRootImpl;
 
     /**
      * @param targetView The view in the surface that acts as synchronization anchor.
      */
     public SyncRtSurfaceTransactionApplierCompat(View targetView) {
-        mApplier = new SyncRtSurfaceTransactionApplier(targetView);
-    }
-
-    private SyncRtSurfaceTransactionApplierCompat(SyncRtSurfaceTransactionApplier applier) {
-        mApplier = applier;
+        mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
+        mTargetSurface = mTargetViewRootImpl != null ? mTargetViewRootImpl.mSurface : null;
     }
 
     /**
@@ -53,38 +50,74 @@
      * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
      *               this method to avoid synchronization issues.
      */
-    public void scheduleApply(final SurfaceParams... params) {
-        mApplier.scheduleApply(convert(params));
-    }
-
-    private SyncRtSurfaceTransactionApplier.SurfaceParams[] convert(SurfaceParams[] params) {
-        SyncRtSurfaceTransactionApplier.SurfaceParams[] result =
-                new SyncRtSurfaceTransactionApplier.SurfaceParams[params.length];
-        for (int i = 0; i < params.length; i++) {
-            result[i] = params[i].mParams;
+    public void scheduleApply(final SyncRtSurfaceTransactionApplierCompat.SurfaceParams... params) {
+        if (mTargetViewRootImpl == null) {
+            return;
         }
-        return result;
+        mTargetViewRootImpl.registerRtFrameCallback(new HardwareRenderer.FrameDrawingCallback() {
+            @Override
+            public void onFrameDraw(long frame) {
+                if (mTargetSurface == null || !mTargetSurface.isValid()) {
+                    return;
+                }
+                TransactionCompat t = new TransactionCompat();
+                for (int i = params.length - 1; i >= 0; i--) {
+                    SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams =
+                            params[i];
+                    SurfaceControlCompat surface = surfaceParams.surface;
+                    t.deferTransactionUntil(surface, mTargetSurface, frame);
+                    applyParams(t, surfaceParams);
+                }
+                t.setEarlyWakeup();
+                t.apply();
+            }
+        });
+
+        // Make sure a frame gets scheduled.
+        mTargetViewRootImpl.getView().invalidate();
     }
 
-    public static void applyParams(TransactionCompat t, SurfaceParams params) {
-        SyncRtSurfaceTransactionApplier.applyParams(t.mTransaction, params.mParams, t.mTmpValues);
+    public static void applyParams(TransactionCompat t,
+            SyncRtSurfaceTransactionApplierCompat.SurfaceParams params) {
+        t.setMatrix(params.surface, params.matrix);
+        t.setWindowCrop(params.surface, params.windowCrop);
+        t.setAlpha(params.surface, params.alpha);
+        t.setLayer(params.surface, params.layer);
+        t.setCornerRadius(params.surface, params.cornerRadius);
+        t.show(params.surface);
     }
 
+    /**
+     * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is
+     * attached if necessary.
+     */
     public static void create(final View targetView,
             final Consumer<SyncRtSurfaceTransactionApplierCompat> callback) {
-        SyncRtSurfaceTransactionApplier.create(targetView,
-                new Consumer<SyncRtSurfaceTransactionApplier>() {
-                    @Override
-                    public void accept(SyncRtSurfaceTransactionApplier applier) {
-                        callback.accept(new SyncRtSurfaceTransactionApplierCompat(applier));
-                    }
-                });
+        if (targetView == null) {
+            // No target view, no applier
+            callback.accept(null);
+        } else if (targetView.getViewRootImpl() != null) {
+            // Already attached, we're good to go
+            callback.accept(new SyncRtSurfaceTransactionApplierCompat(targetView));
+        } else {
+            // Haven't been attached before we can get the view root
+            targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+                @Override
+                public void onViewAttachedToWindow(View v) {
+                    targetView.removeOnAttachStateChangeListener(this);
+                    callback.accept(new SyncRtSurfaceTransactionApplierCompat(targetView));
+                }
+
+                @Override
+                public void onViewDetachedFromWindow(View v) {
+                    // Do nothing
+                }
+            });
+        }
     }
 
     public static class SurfaceParams {
 
-        private final SyncRtSurfaceTransactionApplier.SurfaceParams mParams;
-
         /**
          * Constructs surface parameters to be applied when the current view state gets pushed to
          * RenderThread.
@@ -96,8 +129,19 @@
          */
         public SurfaceParams(SurfaceControlCompat surface, float alpha, Matrix matrix,
                 Rect windowCrop, int layer, float cornerRadius) {
-            mParams = new SyncRtSurfaceTransactionApplier.SurfaceParams(surface.mSurfaceControl,
-                    alpha, matrix, windowCrop, layer, cornerRadius);
+            this.surface = surface;
+            this.alpha = alpha;
+            this.matrix = new Matrix(matrix);
+            this.windowCrop = new Rect(windowCrop);
+            this.layer = layer;
+            this.cornerRadius = cornerRadius;
         }
+
+        public final SurfaceControlCompat surface;
+        public final float alpha;
+        final float cornerRadius;
+        public final Matrix matrix;
+        public final Rect windowCrop;
+        public final int layer;
     }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
index 2aba3fa..af32f48 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
@@ -82,6 +82,11 @@
         return this;
     }
 
+    public TransactionCompat setCornerRadius(SurfaceControlCompat surfaceControl, float radius) {
+        mTransaction.setCornerRadius(surfaceControl.mSurfaceControl, radius);
+        return this;
+    }
+
     public TransactionCompat deferTransactionUntil(SurfaceControlCompat surfaceControl,
             IBinder handle, long frameNumber) {
         mTransaction.deferTransactionUntil(surfaceControl.mSurfaceControl, handle, frameNumber);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 41e9eba..a055950 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -46,6 +46,7 @@
     protected View mEcaView;
     protected boolean mEnableHaptics;
     private boolean mDismissing;
+    protected boolean mResumed;
     private CountDownTimer mCountdownTimer = null;
 
     // To avoid accidental lockout due to events while the device in in the pocket, ignore
@@ -263,6 +264,8 @@
 
     @Override
     public void onPause() {
+        mResumed = false;
+
         if (mCountdownTimer != null) {
             mCountdownTimer.cancel();
             mCountdownTimer = null;
@@ -276,6 +279,7 @@
 
     @Override
     public void onResume(int reason) {
+        mResumed = true;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 570d351..7218acf 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -12,18 +12,19 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.keyguard.clock.ClockManager;
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.ClockPlugin;
-import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
 
-import java.util.Objects;
 import java.util.TimeZone;
 
 /**
  * Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
  */
 public class KeyguardClockSwitch extends RelativeLayout {
+
     /**
      * Optional/alternative clock injected via plugin.
      */
@@ -45,43 +46,31 @@
      * or not to show it below the alternate clock.
      */
     private View mKeyguardStatusArea;
+    /**
+     * Maintain state so that a newly connected plugin can be initialized.
+     */
+    private float mDarkAmount;
 
-    private final PluginListener<ClockPlugin> mClockPluginListener =
-            new PluginListener<ClockPlugin>() {
+    private final StatusBarStateController.StateListener mStateListener =
+            new StatusBarStateController.StateListener() {
                 @Override
-                public void onPluginConnected(ClockPlugin plugin, Context pluginContext) {
-                    disconnectPlugin();
-                    View smallClockView = plugin.getView();
-                    if (smallClockView != null) {
-                        // For now, assume that the most recently connected plugin is the
-                        // selected clock face. In the future, the user should be able to
-                        // pick a clock face from the available plugins.
-                        mSmallClockFrame.addView(smallClockView, -1,
-                                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-                                        ViewGroup.LayoutParams.WRAP_CONTENT));
-                        initPluginParams();
-                        mClockView.setVisibility(View.GONE);
+                public void onStateChanged(int newState) {
+                    if (mBigClockContainer == null) {
+                        return;
                     }
-                    View bigClockView = plugin.getBigClockView();
-                    if (bigClockView != null && mBigClockContainer != null) {
-                        mBigClockContainer.addView(bigClockView);
-                        mBigClockContainer.setVisibility(View.VISIBLE);
-                    }
-                    if (!plugin.shouldShowStatusArea()) {
-                        mKeyguardStatusArea.setVisibility(View.GONE);
-                    }
-                    mClockPlugin = plugin;
-                }
-
-                @Override
-                public void onPluginDisconnected(ClockPlugin plugin) {
-                    if (Objects.equals(plugin, mClockPlugin)) {
-                        disconnectPlugin();
-                        mClockView.setVisibility(View.VISIBLE);
-                        mKeyguardStatusArea.setVisibility(View.VISIBLE);
+                    if (newState == StatusBarState.SHADE) {
+                        if (mBigClockContainer.getVisibility() == View.VISIBLE) {
+                            mBigClockContainer.setVisibility(View.INVISIBLE);
+                        }
+                    } else {
+                        if (mBigClockContainer.getVisibility() == View.INVISIBLE) {
+                            mBigClockContainer.setVisibility(View.VISIBLE);
+                        }
                     }
                 }
-            };
+    };
+
+    private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
 
     public KeyguardClockSwitch(Context context) {
         this(context, null);
@@ -91,6 +80,13 @@
         super(context, attrs);
     }
 
+    /**
+     * Returns if this view is presenting a custom clock, or the default implementation.
+     */
+    public boolean hasCustomClock() {
+        return mClockPlugin != null;
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -102,14 +98,57 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        Dependency.get(PluginManager.class).addPluginListener(mClockPluginListener,
-                ClockPlugin.class);
+        Dependency.get(ClockManager.class).addOnClockChangedListener(mClockChangedListener);
+        Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        Dependency.get(PluginManager.class).removePluginListener(mClockPluginListener);
+        Dependency.get(ClockManager.class).removeOnClockChangedListener(mClockChangedListener);
+        Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
+    }
+
+    private void setClockPlugin(ClockPlugin plugin) {
+        // Disconnect from existing plugin.
+        if (mClockPlugin != null) {
+            View smallClockView = mClockPlugin.getView();
+            if (smallClockView != null && smallClockView.getParent() == mSmallClockFrame) {
+                mSmallClockFrame.removeView(smallClockView);
+            }
+            if (mBigClockContainer != null) {
+                mBigClockContainer.removeAllViews();
+                mBigClockContainer.setVisibility(View.GONE);
+            }
+            mClockPlugin = null;
+        }
+        if (plugin == null) {
+            mClockView.setVisibility(View.VISIBLE);
+            mKeyguardStatusArea.setVisibility(View.VISIBLE);
+            return;
+        }
+        // Attach small and big clock views to hierarchy.
+        View smallClockView = plugin.getView();
+        if (smallClockView != null) {
+            mSmallClockFrame.addView(smallClockView, -1,
+                    new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.WRAP_CONTENT));
+            mClockView.setVisibility(View.GONE);
+        }
+        View bigClockView = plugin.getBigClockView();
+        if (bigClockView != null && mBigClockContainer != null) {
+            mBigClockContainer.addView(bigClockView);
+            mBigClockContainer.setVisibility(View.VISIBLE);
+        }
+        // Hide default clock.
+        if (!plugin.shouldShowStatusArea()) {
+            mKeyguardStatusArea.setVisibility(View.GONE);
+        }
+        // Initialize plugin parameters.
+        mClockPlugin = plugin;
+        mClockPlugin.setStyle(getPaint().getStyle());
+        mClockPlugin.setTextColor(getCurrentTextColor());
+        mClockPlugin.setDarkAmount(mDarkAmount);
     }
 
     /**
@@ -150,10 +189,6 @@
         mClockView.setShowCurrentUserTime(showCurrentUserTime);
     }
 
-    public void setElegantTextHeight(boolean elegant) {
-        mClockView.setElegantTextHeight(elegant);
-    }
-
     public void setTextSize(int unit, float size) {
         mClockView.setTextSize(unit, size);
     }
@@ -171,6 +206,7 @@
      * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
      */
     public void setDarkAmount(float darkAmount) {
+        mDarkAmount = darkAmount;
         if (mClockPlugin != null) {
             mClockPlugin.setDarkAmount(darkAmount);
         }
@@ -210,32 +246,13 @@
         }
     }
 
-    /**
-     * When plugin changes, set all kept parameters into newer plugin.
-     */
-    private void initPluginParams() {
-        if (mClockPlugin != null) {
-            mClockPlugin.setStyle(getPaint().getStyle());
-            mClockPlugin.setTextColor(getCurrentTextColor());
-        }
-    }
-
-    private void disconnectPlugin() {
-        if (mClockPlugin != null) {
-            View smallClockView = mClockPlugin.getView();
-            if (smallClockView != null) {
-                mSmallClockFrame.removeView(smallClockView);
-            }
-            if (mBigClockContainer != null) {
-                mBigClockContainer.removeAllViews();
-                mBigClockContainer.setVisibility(View.GONE);
-            }
-            mClockPlugin = null;
-        }
+    @VisibleForTesting (otherwise = VisibleForTesting.NONE)
+    ClockManager.ClockChangedListener getClockChangedListener() {
+        return mClockChangedListener;
     }
 
     @VisibleForTesting (otherwise = VisibleForTesting.NONE)
-    PluginListener getClockPluginListener() {
-        return mClockPluginListener;
+    StatusBarStateController.StateListener getStateListener() {
+        return mStateListener;
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 41afa9a..64c5b17 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.graphics.Rect;
+import android.os.UserHandle;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.TextUtils;
@@ -79,8 +80,14 @@
 
     @Override
     protected void resetState() {
+        mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser()));
         mSecurityMessageDisplay.setMessage("");
         final boolean wasDisabled = mPasswordEntry.isEnabled();
+        // Don't set enabled password entry & showSoftInput when PasswordEntry is invisible or in
+        // pausing stage.
+        if (!mResumed || !mPasswordEntry.isVisibleToUser()) {
+            return;
+        }
         setPasswordEntryEnabled(true);
         setPasswordEntryInputEnabled(true);
         if (wasDisabled) {
@@ -169,6 +176,7 @@
                 Context.INPUT_METHOD_SERVICE);
 
         mPasswordEntry = findViewById(getPasswordTextViewId());
+        mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser()));
         mPasswordEntryDisabler = new TextViewInputDisabler(mPasswordEntry);
         mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
         mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 669e6ff..bac7844 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -90,7 +90,7 @@
      */
     private Runnable mContentChangeListener;
     private Slice mSlice;
-    private boolean mPulsing;
+    private boolean mHasHeader;
 
     public KeyguardSliceView(Context context) {
         this(context, null, 0);
@@ -150,10 +150,18 @@
         Dependency.get(ConfigurationController.class).removeCallback(this);
     }
 
+    /**
+     * Returns whether the current visible slice has a title/header.
+     */
+    public boolean hasHeader() {
+        return mHasHeader;
+    }
+
     private void showSlice() {
         Trace.beginSection("KeyguardSliceView#showSlice");
-        if (mPulsing || mSlice == null) {
+        if (mSlice == null) {
             mRow.setVisibility(GONE);
+            mHasHeader = false;
             if (mContentChangeListener != null) {
                 mContentChangeListener.run();
             }
@@ -162,7 +170,7 @@
 
         ListContent lc = new ListContent(getContext(), mSlice);
         SliceContent headerContent = lc.getHeader();
-        boolean hasHeader = headerContent != null
+        mHasHeader = headerContent != null
                 && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM);
         List<SliceContent> subItems = new ArrayList<>();
         for (int i = 0; i < lc.getRowItems().size(); i++) {
@@ -177,7 +185,7 @@
         mClickActions.clear();
         final int subItemsCount = subItems.size();
         final int blendedColor = getTextColor();
-        final int startIndex = hasHeader ? 1 : 0; // First item is header; skip it
+        final int startIndex = mHasHeader ? 1 : 0; // First item is header; skip it
         mRow.setVisibility(subItemsCount > 0 ? VISIBLE : GONE);
         for (int i = startIndex; i < subItemsCount; i++) {
             RowContent rc = (RowContent) subItems.get(i);
@@ -189,7 +197,7 @@
                 button = new KeyguardSliceButton(mContext);
                 button.setTextColor(blendedColor);
                 button.setTag(itemTag);
-                final int viewIndex = i - (hasHeader ? 1 : 0);
+                final int viewIndex = i - (mHasHeader ? 1 : 0);
                 mRow.addView(button, viewIndex);
             }
 
@@ -234,18 +242,6 @@
         Trace.endSection();
     }
 
-    public void setPulsing(boolean pulsing, boolean animate) {
-        mPulsing = pulsing;
-        LayoutTransition transition = getLayoutTransition();
-        if (!animate) {
-            setLayoutTransition(null);
-        }
-        showSlice();
-        if (!animate) {
-            setLayoutTransition(transition);
-        }
-    }
-
     public void setDarkAmount(float darkAmount) {
         mDarkAmount = darkAmount;
         mRow.setDarkAmount(darkAmount);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index c6f1726..bb549ad 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -72,7 +72,6 @@
 
     private ArraySet<View> mVisibleInDoze;
     private boolean mPulsing;
-    private boolean mWasPulsing;
     private float mDarkAmount = 0;
     private int mTextColor;
     private int mLastLayoutHeight;
@@ -141,6 +140,13 @@
         onDensityOrFontScaleChanged();
     }
 
+    /**
+     * If we're presenting a custom clock of just the default one.
+     */
+    public boolean hasCustomClock() {
+        return mClockView.hasCustomClock();
+    }
+
     private void setEnableMarquee(boolean enabled) {
         if (DEBUG) Log.v(TAG, "Schedule setEnableMarquee: " + (enabled ? "Enable" : "Disable"));
         if (enabled) {
@@ -195,10 +201,6 @@
         updateOwnerInfo();
         updateLogoutView();
         updateDark();
-
-        // Disable elegant text height because our fancy colon makes the ymin value huge for no
-        // reason.
-        mClockView.setElegantTextHeight(false);
     }
 
     /**
@@ -207,7 +209,7 @@
     private void onSliceContentChanged() {
         LinearLayout.LayoutParams layoutParams =
                 (LinearLayout.LayoutParams) mClockView.getLayoutParams();
-        layoutParams.bottomMargin = mPulsing ? mSmallClockPadding : 0;
+        layoutParams.bottomMargin = mKeyguardSlice.hasHeader() ? mSmallClockPadding : 0;
         mClockView.setLayoutParams(layoutParams);
     }
 
@@ -217,16 +219,16 @@
     @Override
     public void onLayoutChange(View view, int left, int top, int right, int bottom,
             int oldLeft, int oldTop, int oldRight, int oldBottom) {
-        int heightOffset = mPulsing || mWasPulsing ? 0 : getHeight() - mLastLayoutHeight;
+        boolean smallClock = mKeyguardSlice.hasHeader();
+        int heightOffset = smallClock ? 0 : getHeight() - mLastLayoutHeight;
         long duration = KeyguardSliceView.DEFAULT_ANIM_DURATION;
-        long delay = mPulsing || mWasPulsing ? 0 : duration / 4;
-        mWasPulsing = false;
+        long delay = smallClock ? 0 : duration / 4;
 
         boolean shouldAnimate = mKeyguardSlice.getLayoutTransition() != null
                 && mKeyguardSlice.getLayoutTransition().isRunning();
         if (view == mClockView) {
-            float clockScale = mPulsing ? mSmallClockScale : 1;
-            Paint.Style style = mPulsing ? Paint.Style.FILL_AND_STROKE : Paint.Style.FILL;
+            float clockScale = smallClock ? mSmallClockScale : 1;
+            Paint.Style style = smallClock ? Paint.Style.FILL_AND_STROKE : Paint.Style.FILL;
             mClockView.animate().cancel();
             if (shouldAnimate) {
                 mClockView.setY(oldTop + heightOffset);
@@ -431,15 +433,11 @@
         }
     }
 
-    public void setPulsing(boolean pulsing, boolean animate) {
+    public void setPulsing(boolean pulsing) {
         if (mPulsing == pulsing) {
             return;
         }
-        if (mPulsing) {
-            mWasPulsing = true;
-        }
         mPulsing = pulsing;
-        mKeyguardSlice.setPulsing(pulsing, animate);
         updateDozeVisibleViews();
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
new file mode 100644
index 0000000..db6127f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.graphics.Paint.Style;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextClock;
+
+import com.android.keyguard.R;
+import com.android.systemui.plugins.ClockPlugin;
+
+import java.util.TimeZone;
+
+/**
+ * Controller for Bubble clock that can appear on lock screen and AOD.
+ */
+public class BubbleClockController implements ClockPlugin {
+
+    /**
+     * Custom clock shown on AOD screen and behind stack scroller on lock.
+     */
+    private View mView;
+    private TextClock mDigitalClock;
+    private ImageClock mAnalogClock;
+
+    /**
+     * Small clock shown on lock screen above stack scroller.
+     */
+    private View mLockClockContainer;
+    private TextClock mLockClock;
+
+    /**
+     * Controller for transition to dark state.
+     */
+    private CrossFadeDarkController mDarkController;
+
+    private BubbleClockController() { }
+
+    /**
+     * Create a BubbleClockController instance.
+     *
+     * @param layoutInflater Inflater used to inflate custom clock views.
+     */
+    public static BubbleClockController build(LayoutInflater layoutInflater) {
+        BubbleClockController controller = new BubbleClockController();
+        controller.createViews(layoutInflater);
+        return controller;
+    }
+
+    private void createViews(LayoutInflater layoutInflater) {
+        mView = layoutInflater.inflate(R.layout.bubble_clock, null);
+        mDigitalClock = (TextClock) mView.findViewById(R.id.digital_clock);
+        mAnalogClock = (ImageClock) mView.findViewById(R.id.analog_clock);
+
+        mLockClockContainer = layoutInflater.inflate(R.layout.digital_clock, null);
+        mLockClock = (TextClock) mLockClockContainer.findViewById(R.id.lock_screen_clock);
+        mLockClock.setVisibility(View.GONE);
+
+        mDarkController = new CrossFadeDarkController(mDigitalClock, mLockClock);
+    }
+
+    @Override
+    public View getView() {
+        return mLockClockContainer;
+    }
+
+    @Override
+    public View getBigClockView() {
+        return mView;
+    }
+
+    @Override
+    public void setStyle(Style style) {}
+
+    @Override
+    public void setTextColor(int color) {
+        mLockClock.setTextColor(color);
+        mDigitalClock.setTextColor(color);
+    }
+
+    @Override
+    public void dozeTimeTick() {
+        mAnalogClock.onTimeChanged();
+    }
+
+    @Override
+    public void setDarkAmount(float darkAmount) {
+        mDarkController.setDarkAmount(darkAmount);
+    }
+
+    @Override
+    public void onTimeZoneChanged(TimeZone timeZone) {
+        mAnalogClock.onTimeZoneChanged(timeZone);
+    }
+
+    @Override
+    public boolean shouldShowStatusArea() {
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
new file mode 100644
index 0000000..3591dc8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.keyguard.R;
+
+/**
+ * Positions clock faces (analog, digital, typographic) and handles pixel shifting
+ * to prevent screen burn-in.
+ */
+public class ClockLayout extends FrameLayout {
+
+    /**
+     * Clock face views.
+     */
+    private View mDigitalClock;
+    private View mAnalogClock;
+    private View mTypeClock;
+
+    /**
+     * Pixel shifting amplitidues used to prevent screen burn-in.
+     */
+    private int mBurnInPreventionOffsetX;
+    private int mBurnInPreventionOffsetY;
+
+    public ClockLayout(Context context) {
+        this(context, null);
+    }
+
+    public ClockLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ClockLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mDigitalClock = findViewById(R.id.digital_clock);
+        mAnalogClock = findViewById(R.id.analog_clock);
+        mTypeClock = findViewById(R.id.type_clock);
+
+        // Get pixel shifting X, Y amplitudes from resources.
+        Resources resources = getResources();
+        mBurnInPreventionOffsetX = resources.getDimensionPixelSize(
+            R.dimen.burn_in_prevention_offset_x);
+        mBurnInPreventionOffsetY = resources.getDimensionPixelSize(
+            R.dimen.burn_in_prevention_offset_y);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        final float offsetX = getBurnInOffset(mBurnInPreventionOffsetX, true);
+        final float offsetY = getBurnInOffset(mBurnInPreventionOffsetY, false);
+
+        // Put digital clock in two left corner of the screen.
+        if (mDigitalClock != null) {
+            mDigitalClock.setX(0.1f * getWidth() + offsetX);
+            mDigitalClock.setY(0.1f * getHeight() + offsetY);
+        }
+
+        // Put the analog clock in the middle of the screen.
+        if (mAnalogClock != null) {
+            mAnalogClock.setX(Math.max(0f, 0.5f * (getWidth() - mAnalogClock.getWidth()))
+                    + offsetX);
+            mAnalogClock.setY(Math.max(0f, 0.5f * (getHeight() - mAnalogClock.getHeight()))
+                    + offsetY);
+        }
+
+        // Put the typographic clock part way down the screen.
+        if (mTypeClock != null) {
+            mTypeClock.setX(offsetX);
+            mTypeClock.setY(0.2f * getHeight() + offsetY);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
new file mode 100644
index 0000000..3217ca6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.view.LayoutInflater;
+
+import com.android.systemui.plugins.ClockPlugin;
+import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.ExtensionController.Extension;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Manages custom clock faces.
+ */
+@Singleton
+public final class ClockManager {
+
+    private final LayoutInflater mLayoutInflater;
+    private final ContentResolver mContentResolver;
+
+    /**
+     * Observe settings changes to know when to switch the clock face.
+     */
+    private final ContentObserver mContentObserver =
+            new ContentObserver(new Handler(Looper.getMainLooper())) {
+                @Override
+                public void onChange(boolean selfChange) {
+                    super.onChange(selfChange);
+                    if (mClockExtension != null) {
+                        mClockExtension.reload();
+                    }
+                }
+            };
+
+    private final ExtensionController mExtensionController;
+    /**
+     * Used to select between plugin or default implementations of ClockPlugin interface.
+     */
+    private Extension<ClockPlugin> mClockExtension;
+    /**
+     * Consumer that accepts the a new ClockPlugin implementation when the Extension reloads.
+     */
+    private final Consumer<ClockPlugin> mClockPluginConsumer = this::setClockPlugin;
+
+    private final List<ClockChangedListener> mListeners = new ArrayList<>();
+
+    @Inject
+    public ClockManager(Context context, ExtensionController extensionController) {
+        mExtensionController = extensionController;
+        mLayoutInflater = LayoutInflater.from(context);
+        mContentResolver = context.getContentResolver();
+    }
+
+    /**
+     * Add listener to be notified when clock implementation should change.
+     */
+    public void addOnClockChangedListener(ClockChangedListener listener) {
+        if (mListeners.isEmpty()) {
+            register();
+        }
+        mListeners.add(listener);
+        if (mClockExtension != null) {
+            mClockExtension.reload();
+        }
+    }
+
+    /**
+     * Remove listener added with {@link addOnClockChangedListener}.
+     */
+    public void removeOnClockChangedListener(ClockChangedListener listener) {
+        mListeners.remove(listener);
+        if (mListeners.isEmpty()) {
+            unregister();
+        }
+    }
+
+    private void setClockPlugin(ClockPlugin plugin) {
+        for (int i = 0; i < mListeners.size(); i++) {
+            // It probably doesn't make sense to supply the same plugin instances to multiple
+            // listeners. This should be fine for now since there is only a single listener.
+            mListeners.get(i).onClockChanged(plugin);
+        }
+    }
+
+    private void register() {
+        mContentResolver.registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
+                false, mContentObserver);
+        mClockExtension = mExtensionController.newExtension(ClockPlugin.class)
+            .withPlugin(ClockPlugin.class)
+            .withCallback(mClockPluginConsumer)
+            // Using withDefault even though this isn't the default as a workaround.
+            // ExtensionBuilder doesn't provide the ability to supply a ClockPlugin
+            // instance based off of the value of a setting. Since multiple "default"
+            // can be provided, using a supplier that changes the settings value.
+            // A null return will cause Extension#reload to look at the next "default"
+            // supplier.
+            .withDefault(
+                    new SettingsGattedSupplier(
+                        mContentResolver,
+                        Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
+                        BubbleClockController.class.getName(),
+                            () -> BubbleClockController.build(mLayoutInflater)))
+            .withDefault(
+                    new SettingsGattedSupplier(
+                        mContentResolver,
+                        Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
+                        StretchAnalogClockController.class.getName(),
+                            () -> StretchAnalogClockController.build(mLayoutInflater)))
+            .withDefault(
+                    new SettingsGattedSupplier(
+                        mContentResolver,
+                        Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
+                        TypeClockController.class.getName(),
+                            () -> TypeClockController.build(mLayoutInflater)))
+            .build();
+    }
+
+    private void unregister() {
+        mContentResolver.unregisterContentObserver(mContentObserver);
+        mClockExtension.destroy();
+    }
+
+    /**
+     * Listener for events that should cause the custom clock face to change.
+     */
+    public interface ClockChangedListener {
+        /**
+         * Called when custom clock should change.
+         *
+         * @param clock Custom clock face to use. A null value indicates the default clock face.
+         */
+        void onClockChanged(ClockPlugin clock);
+    }
+
+    /**
+     * Supplier that only gets an instance when a settings value matches expected value.
+     */
+    private static class SettingsGattedSupplier implements Supplier<ClockPlugin> {
+
+        private final ContentResolver mContentResolver;
+        private final String mKey;
+        private final String mValue;
+        private final Supplier<ClockPlugin> mSupplier;
+
+        /**
+         * Constructs a supplier that changes secure setting key against value.
+         *
+         * @param contentResolver Used to look up settings value.
+         * @param key Settings key.
+         * @param value If the setting matches this values that get supplies a ClockPlugin
+         *        instance.
+         * @param supplier Supplier of ClockPlugin instance, only used if the setting
+         *        matches value.
+         */
+        SettingsGattedSupplier(ContentResolver contentResolver, String key, String value,
+                Supplier<ClockPlugin> supplier) {
+            mContentResolver = contentResolver;
+            mKey = key;
+            mValue = value;
+            mSupplier = supplier;
+        }
+
+        /**
+         * Returns null if the settings value doesn't match the expected value.
+         *
+         * A null return causes Extension#reload to skip this supplier and move to the next.
+         */
+        @Override
+        public ClockPlugin get() {
+            final String currentValue = Settings.Secure.getString(mContentResolver, mKey);
+            return Objects.equals(currentValue, mValue) ? mSupplier.get() : null;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java b/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java
new file mode 100644
index 0000000..3c3f475
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.view.View;
+
+/**
+ * Controls transition to dark state by cross fading between views.
+ */
+final class CrossFadeDarkController {
+
+    private final View mFadeInView;
+    private final View mFadeOutView;
+
+    /**
+     * Creates a new controller that fades between views.
+     *
+     * @param fadeInView View to fade in when transitioning to AOD.
+     * @param fadeOutView View to fade out when transitioning to AOD.
+     */
+    CrossFadeDarkController(View fadeInView, View fadeOutView) {
+        mFadeInView = fadeInView;
+        mFadeOutView = fadeOutView;
+    }
+
+    /**
+     * Sets the amount the system has transitioned to the dark state.
+     *
+     * @param darkAmount Amount of transition to dark state: 1f for AOD and 0f for lock screen.
+     */
+    void setDarkAmount(float darkAmount) {
+        mFadeInView.setAlpha(Math.max(0f, 2f * darkAmount - 1f));
+        if (darkAmount == 0f) {
+            mFadeInView.setVisibility(View.GONE);
+        } else {
+            if (mFadeInView.getVisibility() == View.GONE) {
+                mFadeInView.setVisibility(View.VISIBLE);
+            }
+        }
+        mFadeOutView.setAlpha(Math.max(0f, 1f - 2f * darkAmount));
+        if (darkAmount == 1f) {
+            mFadeOutView.setVisibility(View.GONE);
+        } else {
+            if (mFadeOutView.getVisibility() == View.GONE) {
+                mFadeOutView.setVisibility(View.VISIBLE);
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
new file mode 100644
index 0000000..2c709e0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.content.Context;
+import android.text.format.DateFormat;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.keyguard.R;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * Clock composed of two images that rotate with the time.
+ *
+ * The images are the clock hands. ImageClock expects two child ImageViews
+ * with ids hour_hand and minute_hand.
+ */
+public class ImageClock extends FrameLayout {
+
+    private ImageView mHourHand;
+    private ImageView mMinuteHand;
+    private Calendar mTime;
+    private String mDescFormat;
+    private TimeZone mTimeZone;
+
+    public ImageClock(Context context) {
+        this(context, null);
+    }
+
+    public ImageClock(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ImageClock(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mTime = Calendar.getInstance();
+        mDescFormat = ((SimpleDateFormat) DateFormat.getTimeFormat(context)).toLocalizedPattern();
+    }
+
+    /**
+     * Call when the time changes to update the rotation of the clock hands.
+     */
+    public void onTimeChanged() {
+        mTime.setTimeInMillis(System.currentTimeMillis());
+        final float hourAngle = mTime.get(Calendar.HOUR) * 30f;
+        mHourHand.setRotation(hourAngle);
+        final float minuteAngle = mTime.get(Calendar.MINUTE) * 6f;
+        mMinuteHand.setRotation(minuteAngle);
+        setContentDescription(DateFormat.format(mDescFormat, mTime));
+        invalidate();
+    }
+
+    /**
+     * Call when the time zone has changed to update clock hands.
+     *
+     * @param timeZone The updated time zone that will be used.
+     */
+    public void onTimeZoneChanged(TimeZone timeZone) {
+        mTimeZone = timeZone;
+        mTime.setTimeZone(timeZone);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mHourHand = findViewById(R.id.hour_hand);
+        mMinuteHand = findViewById(R.id.minute_hand);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
+        onTimeChanged();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
new file mode 100644
index 0000000..87347545
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * Analog clock where the minute hand extends off of the screen.
+ */
+public class StretchAnalogClock extends View {
+
+    private static final int DEFAULT_COLOR = Color.parseColor("#F5C983");
+    private static final float HOUR_STROKE_WIDTH = 60f;
+    private static final float MINUTE_STROKE_WIDTH = 20f;
+    private static final float CENTER_GAP_AND_CIRCLE_RADIUS = 80f;
+
+    private final Paint mHourPaint = new Paint();
+    private final Paint mMinutePaint = new Paint();
+    private Calendar mTime;
+    private TimeZone mTimeZone;
+
+    public StretchAnalogClock(Context context) {
+        this(context, null);
+    }
+
+    public StretchAnalogClock(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public StretchAnalogClock(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public StretchAnalogClock(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    /**
+     * Call when the time changes to update the clock hands.
+     */
+    public void onTimeChanged() {
+        mTime.setTimeInMillis(System.currentTimeMillis());
+        invalidate();
+    }
+
+    /**
+     * Call when the time zone has changed to update clock hands.
+     *
+     * @param timeZone The updated time zone that will be used.
+     */
+    public void onTimeZoneChanged(TimeZone timeZone) {
+        mTime.setTimeZone(timeZone);
+    }
+
+    /**
+     * Set the color of the minute hand.
+     */
+    public void setMinuteHandColor(int color) {
+        mMinutePaint.setColor(color);
+        invalidate();
+    }
+
+    private void init() {
+        mHourPaint.setColor(DEFAULT_COLOR);
+        mHourPaint.setStrokeWidth(HOUR_STROKE_WIDTH);
+        mHourPaint.setAntiAlias(true);
+        mHourPaint.setStrokeCap(Paint.Cap.ROUND);
+
+        mMinutePaint.setColor(Color.WHITE);
+        mMinutePaint.setStrokeWidth(MINUTE_STROKE_WIDTH);
+        mMinutePaint.setAntiAlias(true);
+        mMinutePaint.setStrokeCap(Paint.Cap.ROUND);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        final float centerX = getWidth() / 2f;
+        final float centerY = getHeight() / 2f;
+
+        final float minutesRotation = mTime.get(Calendar.MINUTE) * 6f;
+        final float hoursRotation = (mTime.get(Calendar.HOUR) * 30);
+
+        // Compute length of clock hands. Hour hand is 60% the length from center to edge
+        // and minute hand is twice the length to make sure it extends past screen edge.
+        double sMinuteHandLengthFactor = Math.sin(2d * Math.PI * minutesRotation / 360d);
+        float sMinuteHandLength = (float) (2d * (centerY + (centerX - centerY)
+                * sMinuteHandLengthFactor * sMinuteHandLengthFactor));
+        double sHourHandLengthFactor = Math.sin(2d * Math.PI * hoursRotation / 360d);
+        float sHourHandLength = (float) (0.6d * (centerY + (centerX - centerY)
+                * sHourHandLengthFactor * sHourHandLengthFactor));
+
+        canvas.save();
+
+        canvas.rotate(minutesRotation, centerX, centerY);
+        canvas.drawLine(
+                centerX,
+                centerY + CENTER_GAP_AND_CIRCLE_RADIUS,
+                centerX,
+                centerY - sMinuteHandLength,
+                mMinutePaint);
+
+        canvas.rotate(hoursRotation - minutesRotation, centerX, centerY);
+        canvas.drawLine(
+                centerX,
+                centerY + CENTER_GAP_AND_CIRCLE_RADIUS,
+                centerX,
+                centerY - sHourHandLength,
+                mHourPaint);
+
+        canvas.restore();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
+        onTimeChanged();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
new file mode 100644
index 0000000..0a39158
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.graphics.Paint.Style;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextClock;
+
+import com.android.keyguard.R;
+import com.android.systemui.plugins.ClockPlugin;
+
+import java.util.TimeZone;
+
+/**
+ * Controller for Stretch clock that can appear on lock screen and AOD.
+ */
+public class StretchAnalogClockController implements ClockPlugin {
+
+    /**
+     * Custom clock shown on AOD screen and behind stack scroller on lock.
+     */
+    private View mBigClockView;
+    private TextClock mDigitalClock;
+    private StretchAnalogClock mAnalogClock;
+
+    /**
+     * Small clock shown on lock screen above stack scroller.
+     */
+    private View mView;
+    private TextClock mLockClock;
+
+    /**
+     * Controller for transition to dark state.
+     */
+    private CrossFadeDarkController mDarkController;
+
+    private StretchAnalogClockController() { }
+
+    /**
+     * Create a BubbleClockController instance.
+     *
+     * @param layoutInflater Inflater used to inflate custom clock views.
+     */
+    public static StretchAnalogClockController build(LayoutInflater layoutInflater) {
+        StretchAnalogClockController controller = new StretchAnalogClockController();
+        controller.createViews(layoutInflater);
+        return controller;
+    }
+
+    private void createViews(LayoutInflater layoutInflater) {
+        mBigClockView = layoutInflater.inflate(R.layout.stretchanalog_clock, null);
+        mAnalogClock = mBigClockView.findViewById(R.id.analog_clock);
+        mDigitalClock = mBigClockView.findViewById(R.id.digital_clock);
+
+        mView = layoutInflater.inflate(R.layout.digital_clock, null);
+        mLockClock = mView.findViewById(R.id.lock_screen_clock);
+        mLockClock.setVisibility(View.GONE);
+
+        mDarkController = new CrossFadeDarkController(mDigitalClock, mLockClock);
+    }
+
+    @Override
+    public View getView() {
+        return mView;
+    }
+
+    @Override
+    public View getBigClockView() {
+        return mBigClockView;
+    }
+
+    @Override
+    public void setStyle(Style style) {}
+
+    @Override
+    public void setTextColor(int color) {
+        mLockClock.setTextColor(color);
+        mDigitalClock.setTextColor(color);
+        mAnalogClock.setMinuteHandColor(color);
+    }
+
+    @Override
+    public void dozeTimeTick() {
+        mAnalogClock.onTimeChanged();
+    }
+
+    @Override
+    public void setDarkAmount(float darkAmount) {
+        mDarkController.setDarkAmount(darkAmount);
+    }
+
+    @Override
+    public void onTimeZoneChanged(TimeZone timeZone) {
+        mAnalogClock.onTimeZoneChanged(timeZone);
+    }
+
+    @Override
+    public boolean shouldShowStatusArea() {
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
new file mode 100644
index 0000000..17d929d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.graphics.Paint.Style;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.keyguard.R;
+import com.android.systemui.plugins.ClockPlugin;
+
+import java.util.TimeZone;
+
+/**
+ * Plugin for a custom Typographic clock face that displays the time in words.
+ */
+public class TypeClockController implements ClockPlugin {
+
+    /**
+     * Custom clock shown on AOD screen and behind stack scroller on lock.
+     */
+    private View mView;
+    private TypographicClock mTypeClock;
+
+    /**
+     * Small clock shown on lock screen above stack scroller.
+     */
+    private View mLockClockContainer;
+
+    /**
+     * Controller for transition into dark state.
+     */
+    private CrossFadeDarkController mDarkController;
+
+    private TypeClockController() {}
+
+    /**
+     * Create a TypeClockController instance.
+     *
+     * @param inflater Inflater used to inflate custom clock views.
+     */
+    public static TypeClockController build(LayoutInflater inflater) {
+        TypeClockController controller = new TypeClockController();
+        controller.createViews(inflater);
+        return controller;
+    }
+
+    private void createViews(LayoutInflater inflater) {
+        mView = inflater.inflate(R.layout.type_clock, null);
+        mTypeClock = mView.findViewById(R.id.type_clock);
+
+        // For now, this view is used to hide the default digital clock.
+        // Need better transition to lock screen.
+        mLockClockContainer = inflater.inflate(R.layout.digital_clock, null);
+        mLockClockContainer.setVisibility(View.GONE);
+    }
+
+    @Override
+    public View getView() {
+        return mLockClockContainer;
+    }
+
+    @Override
+    public View getBigClockView() {
+        return mView;
+    }
+
+    @Override
+    public void setStyle(Style style) {}
+
+    @Override
+    public void setTextColor(int color) {
+        mTypeClock.setTextColor(color);
+    }
+
+    @Override
+    public void dozeTimeTick() {
+        mTypeClock.onTimeChanged();
+    }
+
+    @Override
+    public void setDarkAmount(float darkAmount) {}
+
+    @Override
+    public void onTimeZoneChanged(TimeZone timeZone) {
+        mTypeClock.onTimeZoneChanged(timeZone);
+    }
+
+    @Override
+    public boolean shouldShowStatusArea() {
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
new file mode 100644
index 0000000..5f9da3e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.text.format.DateFormat;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.keyguard.R;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * Clock that presents the time in words.
+ */
+public class TypographicClock extends LinearLayout {
+
+    private final String[] mHours;
+    private final String[] mMinutes;
+    private TextView mHeaderText;
+    private TextView mHourText;
+    private TextView mMinuteText;
+    private Calendar mTime;
+    private String mDescFormat;
+    private TimeZone mTimeZone;
+
+    public TypographicClock(Context context) {
+        this(context, null);
+    }
+
+    public TypographicClock(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TypographicClock(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mTime = Calendar.getInstance();
+        mDescFormat = ((SimpleDateFormat) DateFormat.getTimeFormat(context)).toLocalizedPattern();
+        Resources res = context.getResources();
+        mHours = res.getStringArray(R.array.type_clock_hours);
+        mMinutes = res.getStringArray(R.array.type_clock_minutes);
+    }
+
+    /**
+     * Call when the time changes to update the text of the time.
+     */
+    public void onTimeChanged() {
+        mTime.setTimeInMillis(System.currentTimeMillis());
+        setContentDescription(DateFormat.format(mDescFormat, mTime));
+        final int hour = mTime.get(Calendar.HOUR);
+        mHourText.setText(mHours[hour % 12]);
+        final int minute = mTime.get(Calendar.MINUTE);
+        mMinuteText.setText(mMinutes[minute % 60]);
+        invalidate();
+    }
+
+    /**
+     * Call when the time zone has changed to update clock time.
+     *
+     * @param timeZone The updated time zone that will be used.
+     */
+    public void onTimeZoneChanged(TimeZone timeZone) {
+        mTimeZone = timeZone;
+        mTime.setTimeZone(timeZone);
+    }
+
+    /**
+     * Set the color of the text used to display the time.
+     *
+     * This is necessary when the wallpaper shown behind the clock on the
+     * lock screen changes.
+     */
+    public void setTextColor(int color) {
+        mHourText.setTextColor(color);
+        mMinuteText.setTextColor(color);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mHeaderText = findViewById(R.id.header);
+        mHourText = findViewById(R.id.hour);
+        mMinuteText = findViewById(R.id.minute);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
+        onTimeChanged();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 6864ea1..2006794 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -40,7 +40,6 @@
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
-import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -56,7 +55,6 @@
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.IconLogger;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 import com.android.systemui.util.Utils.DisableStateTracker;
@@ -71,11 +69,12 @@
 
 
     @Retention(SOURCE)
-    @IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF})
+    @IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF, MODE_ESTIMATE})
     public @interface BatteryPercentMode {}
     public static final int MODE_DEFAULT = 0;
     public static final int MODE_ON = 1;
     public static final int MODE_OFF = 2;
+    public static final int MODE_ESTIMATE = 3;
 
     private final BatteryMeterDrawableBase mDrawable;
     private final String mSlotBattery;
@@ -93,6 +92,7 @@
     // Some places may need to show the battery conditionally, and not obey the tuner
     private boolean mIgnoreTunerUpdates;
     private boolean mIsSubscribedForTunerUpdates;
+    private boolean mCharging;
 
     private int mDarkModeBackgroundColor;
     private int mDarkModeFillColor;
@@ -276,9 +276,6 @@
     public void onTuningChanged(String key, String newValue) {
         if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
             ArraySet<String> icons = StatusBarIconController.getIconBlacklist(newValue);
-            boolean hidden = icons.contains(mSlotBattery);
-            Dependency.get(IconLogger.class).onIconVisibility(mSlotBattery, !hidden);
-            setVisibility(hidden ? View.GONE : View.VISIBLE);
         }
     }
 
@@ -308,6 +305,7 @@
     public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
         mDrawable.setBatteryLevel(level);
         mDrawable.setCharging(pluggedIn);
+        mCharging = pluggedIn;
         mLevel = level;
         updatePercentText();
         setContentDescription(
@@ -337,9 +335,19 @@
     }
 
     private void updatePercentText() {
+        if (mBatteryController == null) {
+            return;
+        }
+
         if (mBatteryPercentView != null) {
-            mBatteryPercentView.setText(
-                    NumberFormat.getPercentInstance().format(mLevel / 100f));
+            if (mShowPercentMode == MODE_ESTIMATE && !mCharging) {
+                mBatteryController.getEstimatedTimeRemainingString((String estimate) -> {
+                    mBatteryPercentView.setText(estimate);
+                });
+            } else {
+                mBatteryPercentView.setText(
+                        NumberFormat.getPercentInstance().format(mLevel / 100f));
+            }
         }
     }
 
@@ -350,7 +358,7 @@
                 SHOW_BATTERY_PERCENT, 0, mUser);
 
         if ((mShowPercentAvailable && systemSetting && mShowPercentMode != MODE_OFF)
-                || mShowPercentMode == MODE_ON) {
+                || mShowPercentMode == MODE_ON || mShowPercentMode == MODE_ESTIMATE) {
             if (!showing) {
                 mBatteryPercentView = loadPercentView();
                 if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 6e50429..d99f234 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -29,6 +29,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.Preconditions;
+import com.android.keyguard.clock.ClockManager;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.systemui.appops.AppOpsController;
 import com.android.systemui.assist.AssistManager;
@@ -56,15 +57,16 @@
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.phone.AutoHideController;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
@@ -85,7 +87,6 @@
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.IconLogger;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.LocationController;
 import com.android.systemui.statusbar.policy.NetworkController;
@@ -156,6 +157,12 @@
     public static final String LEAK_REPORT_EMAIL_NAME = "leak_report_email";
 
     /**
+     * Whether this platform supports long-pressing notifications to show notification channel
+     * settings.
+     */
+    public static final String ALLOW_NOTIFICATION_LONG_PRESS_NAME = "allow_notif_longpress";
+
+    /**
      * Key for getting a background Looper for background work.
      */
     public static final DependencyKey<Looper> BG_LOOPER = new DependencyKey<>(BG_LOOPER_NAME);
@@ -210,7 +217,6 @@
     @Inject Lazy<LeakDetector> mLeakDetector;
     @Inject Lazy<LeakReporter> mLeakReporter;
     @Inject Lazy<GarbageMonitor> mGarbageMonitor;
-    @Inject Lazy<IconLogger> mIconLogger;
     @Inject Lazy<TunerService> mTunerService;
     @Inject Lazy<StatusBarWindowController> mStatusBarWindowController;
     @Inject Lazy<DarkIconDispatcher> mDarkIconDispatcher;
@@ -270,12 +276,15 @@
     @Inject
     Lazy<NotificationAlertingManager> mNotificationAlertingManager;
     @Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager;
+    @Inject Lazy<AutoHideController> mAutoHideController;
+    @Inject Lazy<ForegroundServiceNotificationListener> mForegroundServiceNotificationListener;
     @Inject @Named(BG_LOOPER_NAME) Lazy<Looper> mBgLooper;
     @Inject @Named(BG_HANDLER_NAME) Lazy<Handler> mBgHandler;
     @Inject @Named(MAIN_HANDLER_NAME) Lazy<Handler> mMainHandler;
     @Inject @Named(TIME_TICK_HANDLER_NAME) Lazy<Handler> mTimeTickHandler;
     @Nullable
     @Inject @Named(LEAK_REPORT_EMAIL_NAME) Lazy<String> mLeakReportEmail;
+    @Inject Lazy<ClockManager> mClockManager;
 
     @Inject
     public Dependency() {
@@ -383,8 +392,6 @@
 
         mProviders.put(PowerUI.WarningsUI.class, mWarningsUI::get);
 
-        mProviders.put(IconLogger.class, mIconLogger::get);
-
         mProviders.put(LightBarController.class, mLightBarController::get);
 
         mProviders.put(IWindowManager.class, mIWindowManager::get);
@@ -442,6 +449,15 @@
         mProviders.put(BubbleController.class, mBubbleController::get);
         mProviders.put(NotificationEntryManager.class, mNotificationEntryManager::get);
         mProviders.put(NotificationAlertingManager.class, mNotificationAlertingManager::get);
+        mProviders.put(ForegroundServiceNotificationListener.class,
+                mForegroundServiceNotificationListener::get);
+        mProviders.put(ClockManager.class, mClockManager::get);
+
+        // TODO(b/118592525): to support multi-display , we start to add something which is
+        //                    per-display, while others may be global. I think it's time to add
+        //                    a new class maybe named DisplayDependency to solve per-display
+        //                    Dependency problem.
+        mProviders.put(AutoHideController.class, mAutoHideController::get);
 
         sDependency = this;
     }
@@ -511,6 +527,9 @@
     public static void initDependencies(Context context) {
         if (sDependency != null) return;
         Dependency d = new Dependency();
+        SystemUIFactory.getInstance().getRootComponent()
+                .createDependency()
+                .createSystemUI(d);
         d.mContext = context;
         d.mComponents = new HashMap<>();
         d.start();
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
index 1ee1dcf..ce9c637 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
@@ -46,8 +46,6 @@
 import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.statusbar.policy.HotspotControllerImpl;
-import com.android.systemui.statusbar.policy.IconLogger;
-import com.android.systemui.statusbar.policy.IconLoggerImpl;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 import com.android.systemui.statusbar.policy.LocationController;
@@ -133,11 +131,6 @@
     /**
      */
     @Binds
-    public abstract IconLogger provideIconLogger(IconLoggerImpl loggerImpl);
-
-    /**
-     */
-    @Binds
     public abstract CastController provideCastController(CastControllerImpl controllerImpl);
 
     /**
@@ -219,12 +212,6 @@
     /**
      */
     @Binds
-    public abstract ForegroundServiceController provideForegroundService(
-            ForegroundServiceControllerImpl controllerImpl);
-
-    /**
-     */
-    @Binds
     public abstract PowerUI.WarningsUI provideWarningsUi(PowerNotificationWarnings controllerImpl);
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
index 5c9b999..88e32cb 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
@@ -42,9 +42,8 @@
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.shared.plugins.PluginManagerImpl;
 import com.android.systemui.statusbar.NavigationBarController;
+import com.android.systemui.statusbar.phone.AutoHideController;
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
-import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.NetworkController;
@@ -140,12 +139,6 @@
 
     @Singleton
     @Provides
-    public ShadeController provideShadeController(Context context) {
-        return SysUiServiceProvider.getComponent(context, StatusBar.class);
-    }
-
-    @Singleton
-    @Provides
     public SensorPrivacyManager provideSensorPrivacyManager(Context context) {
         return context.getSystemService(SensorPrivacyManager.class);
     }
@@ -181,4 +174,11 @@
     public ConfigurationController provideConfigurationController(Context context) {
         return new ConfigurationControllerImpl(context);
     }
+
+    @Singleton
+    @Provides
+    public AutoHideController provideAutoHideController(Context context,
+            @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
+        return new AutoHideController(context, mainHandler);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
index ae6ee2a..df0d787 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -15,65 +15,158 @@
 package com.android.systemui;
 
 import android.annotation.Nullable;
+import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.util.ArraySet;
+import android.util.SparseArray;
 
-public interface ForegroundServiceController {
-    /**
-     * @param sbn notification that was just posted
-     * @param importance
-     */
-    void addNotification(StatusBarNotification sbn, int importance);
+import com.android.internal.messages.nano.SystemMessageProto;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Tracks state of foreground services and notifications related to foreground services per user.
+ */
+@Singleton
+public class ForegroundServiceController {
+
+    private final SparseArray<ForegroundServicesUserState> mUserServices = new SparseArray<>();
+    private final Object mMutex = new Object();
+
+    @Inject
+    public ForegroundServiceController() {
+    }
 
     /**
-     * @param sbn notification that was just changed in some way
-     * @param newImportance
-     */
-    void updateNotification(StatusBarNotification sbn, int newImportance);
-
-    /**
-     * @param sbn notification that was just canceled
-     */
-    boolean removeNotification(StatusBarNotification sbn);
-
-    /**
-     * @param userId
      * @return true if this user has services missing notifications and therefore needs a
      * disclosure notification.
      */
-    boolean isDungeonNeededForUser(int userId);
-
-    /**
-     * @param sbn
-     * @return true if sbn is the system-provided "dungeon" (list of running foreground services).
-     */
-    boolean isDungeonNotification(StatusBarNotification sbn);
-
-    /**
-     * @return true if sbn is one of the window manager "drawing over other apps" notifications
-     */
-    boolean isSystemAlertNotification(StatusBarNotification sbn);
-
-    /**
-     * Returns the key of the foreground service from this package using the standard template,
-     * if one exists.
-     */
-    @Nullable String getStandardLayoutKey(int userId, String pkg);
+    public boolean isDisclosureNeededForUser(int userId) {
+        synchronized (mMutex) {
+            final ForegroundServicesUserState services = mUserServices.get(userId);
+            if (services == null) return false;
+            return services.isDisclosureNeeded();
+        }
+    }
 
     /**
      * @return true if this user/pkg has a missing or custom layout notification and therefore needs
      * a disclosure notification for system alert windows.
      */
-    boolean isSystemAlertWarningNeeded(int userId, String pkg);
+    public boolean isSystemAlertWarningNeeded(int userId, String pkg) {
+        synchronized (mMutex) {
+            final ForegroundServicesUserState services = mUserServices.get(userId);
+            if (services == null) return false;
+            return services.getStandardLayoutKey(pkg) == null;
+        }
+    }
+
+    /**
+     * Returns the key of the foreground service from this package using the standard template,
+     * if one exists.
+     */
+    @Nullable
+    public String getStandardLayoutKey(int userId, String pkg) {
+        synchronized (mMutex) {
+            final ForegroundServicesUserState services = mUserServices.get(userId);
+            if (services == null) return null;
+            return services.getStandardLayoutKey(pkg);
+        }
+    }
+
+    /**
+     * Gets active app ops for this user and package
+     */
+    @Nullable
+    public ArraySet<Integer> getAppOps(int userId, String pkg) {
+        synchronized (mMutex) {
+            final ForegroundServicesUserState services = mUserServices.get(userId);
+            if (services == null) {
+                return null;
+            }
+            return services.getFeatures(pkg);
+        }
+    }
 
     /**
      * Records active app ops. App Ops are stored in FSC in addition to NotificationData in
      * case they change before we have a notification to tag.
      */
-    void onAppOpChanged(int code, int uid, String packageName, boolean active);
+    public void onAppOpChanged(int code, int uid, String packageName, boolean active) {
+        int userId = UserHandle.getUserId(uid);
+        synchronized (mMutex) {
+            ForegroundServicesUserState userServices = mUserServices.get(userId);
+            if (userServices == null) {
+                userServices = new ForegroundServicesUserState();
+                mUserServices.put(userId, userServices);
+            }
+            if (active) {
+                userServices.addOp(packageName, code);
+            } else {
+                userServices.removeOp(packageName, code);
+            }
+        }
+    }
 
     /**
-     * Gets active app ops for this user and package
+     * Looks up the {@link ForegroundServicesUserState} for the given {@code userId}, then performs
+     * the given {@link UserStateUpdateCallback} on it.  If no state exists for the user ID, creates
+     * a new one if {@code createIfNotFound} is true, then performs the update on the new state.
+     * If {@code createIfNotFound} is false, no update is performed.
+     *
+     * @return false if no user state was found and none was created; true otherwise.
      */
-    @Nullable ArraySet<Integer> getAppOps(int userId, String packageName);
+    boolean updateUserState(int userId,
+            UserStateUpdateCallback updateCallback,
+            boolean createIfNotFound) {
+        synchronized (mMutex) {
+            ForegroundServicesUserState userState = mUserServices.get(userId);
+            if (userState == null) {
+                if (createIfNotFound) {
+                    userState = new ForegroundServicesUserState();
+                    mUserServices.put(userId, userState);
+                } else {
+                    return false;
+                }
+            }
+            return updateCallback.updateUserState(userState);
+        }
+    }
+
+    /**
+     * @return true if {@code sbn} is the system-provided disclosure notification containing the
+     * list of running foreground services.
+     */
+    public boolean isDisclosureNotification(StatusBarNotification sbn) {
+        return sbn.getId() == SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES
+                && sbn.getTag() == null
+                && sbn.getPackageName().equals("android");
+    }
+
+    /**
+     * @return true if sbn is one of the window manager "drawing over other apps" notifications
+     */
+    public boolean isSystemAlertNotification(StatusBarNotification sbn) {
+        return sbn.getPackageName().equals("android")
+                && sbn.getTag() != null
+                && sbn.getTag().contains("AlertWindowNotification");
+    }
+
+    /**
+     * Callback provided to {@link #updateUserState(int, UserStateUpdateCallback, boolean)}
+     * to perform the update.
+     */
+    interface UserStateUpdateCallback {
+        /**
+         * Perform update operations on the provided {@code userState}.
+         *
+         * @return true if the update succeeded.
+         */
+        boolean updateUserState(ForegroundServicesUserState userState);
+
+        /** Called if the state was not found and was not created. */
+        default void userStateNotFound(int userId) {
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java
deleted file mode 100644
index ae446dd..0000000
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.messages.nano.SystemMessageProto;
-
-import java.util.Arrays;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Foreground service controller, a/k/a Dianne's Dungeon.
- */
-@Singleton
-public class ForegroundServiceControllerImpl
-        implements ForegroundServiceController {
-
-    // shelf life of foreground services before they go bad
-    public static final long FG_SERVICE_GRACE_MILLIS = 5000;
-
-    private static final String TAG = "FgServiceController";
-    private static final boolean DBG = false;
-
-    private final Context mContext;
-    private final SparseArray<UserServices> mUserServices = new SparseArray<>();
-    private final Object mMutex = new Object();
-
-    @Inject
-    public ForegroundServiceControllerImpl(Context context) {
-        mContext = context;
-    }
-
-    @Override
-    public boolean isDungeonNeededForUser(int userId) {
-        synchronized (mMutex) {
-            final UserServices services = mUserServices.get(userId);
-            if (services == null) return false;
-            return services.isDungeonNeeded();
-        }
-    }
-
-    @Override
-    public boolean isSystemAlertWarningNeeded(int userId, String pkg) {
-        synchronized (mMutex) {
-            final UserServices services = mUserServices.get(userId);
-            if (services == null) return false;
-            return services.getStandardLayoutKey(pkg) == null;
-        }
-    }
-
-    @Override
-    public String getStandardLayoutKey(int userId, String pkg) {
-        synchronized (mMutex) {
-            final UserServices services = mUserServices.get(userId);
-            if (services == null) return null;
-            return services.getStandardLayoutKey(pkg);
-        }
-    }
-
-    @Override
-    public ArraySet<Integer> getAppOps(int userId, String pkg) {
-        synchronized (mMutex) {
-            final UserServices services = mUserServices.get(userId);
-            if (services == null) {
-                return null;
-            }
-            return services.getFeatures(pkg);
-        }
-    }
-
-    @Override
-    public void onAppOpChanged(int code, int uid, String packageName, boolean active) {
-        int userId = UserHandle.getUserId(uid);
-        synchronized (mMutex) {
-            UserServices userServices = mUserServices.get(userId);
-            if (userServices == null) {
-                userServices = new UserServices();
-                mUserServices.put(userId, userServices);
-            }
-            if (active) {
-                userServices.addOp(packageName, code);
-            } else {
-                userServices.removeOp(packageName, code);
-            }
-        }
-    }
-
-    @Override
-    public void addNotification(StatusBarNotification sbn, int importance) {
-        updateNotification(sbn, importance);
-    }
-
-    @Override
-    public boolean removeNotification(StatusBarNotification sbn) {
-        synchronized (mMutex) {
-            final UserServices userServices = mUserServices.get(sbn.getUserId());
-            if (userServices == null) {
-                if (DBG) {
-                    Log.w(TAG, String.format(
-                            "user %d with no known notifications got removeNotification for %s",
-                            sbn.getUserId(), sbn));
-                }
-                return false;
-            }
-            if (isDungeonNotification(sbn)) {
-                // if you remove the dungeon entirely, we take that to mean there are
-                // no running services
-                userServices.setRunningServices(null, 0);
-                return true;
-            } else {
-                // this is safe to call on any notification, not just FLAG_FOREGROUND_SERVICE
-                return userServices.removeNotification(sbn.getPackageName(), sbn.getKey());
-            }
-        }
-    }
-
-    @Override
-    public void updateNotification(StatusBarNotification sbn, int newImportance) {
-        synchronized (mMutex) {
-            UserServices userServices = mUserServices.get(sbn.getUserId());
-            if (userServices == null) {
-                userServices = new UserServices();
-                mUserServices.put(sbn.getUserId(), userServices);
-            }
-
-            if (isDungeonNotification(sbn)) {
-                final Bundle extras = sbn.getNotification().extras;
-                if (extras != null) {
-                    final String[] svcs = extras.getStringArray(Notification.EXTRA_FOREGROUND_APPS);
-                    userServices.setRunningServices(svcs, sbn.getNotification().when);
-                }
-            } else {
-                userServices.removeNotification(sbn.getPackageName(), sbn.getKey());
-                if (0 != (sbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE)) {
-                    if (newImportance > NotificationManager.IMPORTANCE_MIN) {
-                        userServices.addImportantNotification(sbn.getPackageName(), sbn.getKey());
-                    }
-                    final Notification.Builder builder = Notification.Builder.recoverBuilder(
-                            mContext, sbn.getNotification());
-                    if (builder.usesStandardHeader()) {
-                        userServices.addStandardLayoutNotification(
-                                sbn.getPackageName(), sbn.getKey());
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public boolean isDungeonNotification(StatusBarNotification sbn) {
-        return sbn.getId() == SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES
-                && sbn.getTag() == null
-                && sbn.getPackageName().equals("android");
-    }
-
-    @Override
-    public boolean isSystemAlertNotification(StatusBarNotification sbn) {
-        return sbn.getPackageName().equals("android")
-                && sbn.getTag() != null
-                && sbn.getTag().contains("AlertWindowNotification");
-    }
-
-    /**
-     * Struct to track relevant packages and notifications for a userid's foreground services.
-     */
-    private static class UserServices {
-        private String[] mRunning = null;
-        private long mServiceStartTime = 0;
-        // package -> sufficiently important posted notification keys
-        private ArrayMap<String, ArraySet<String>> mImportantNotifications = new ArrayMap<>(1);
-        // package -> standard layout posted notification keys
-        private ArrayMap<String, ArraySet<String>> mStandardLayoutNotifications = new ArrayMap<>(1);
-
-        // package -> app ops
-        private ArrayMap<String, ArraySet<Integer>> mAppOps = new ArrayMap<>(1);
-
-        public void setRunningServices(String[] pkgs, long serviceStartTime) {
-            mRunning = pkgs != null ? Arrays.copyOf(pkgs, pkgs.length) : null;
-            mServiceStartTime = serviceStartTime;
-        }
-
-        public void addOp(String pkg, int op) {
-            if (mAppOps.get(pkg) == null) {
-                mAppOps.put(pkg, new ArraySet<>(3));
-            }
-            mAppOps.get(pkg).add(op);
-        }
-
-        public boolean removeOp(String pkg, int op) {
-            final boolean found;
-            final ArraySet<Integer> keys = mAppOps.get(pkg);
-            if (keys == null) {
-                found = false;
-            } else {
-                found = keys.remove(op);
-                if (keys.size() == 0) {
-                    mAppOps.remove(pkg);
-                }
-            }
-            return found;
-        }
-
-        public void addImportantNotification(String pkg, String key) {
-            addNotification(mImportantNotifications, pkg, key);
-        }
-
-        public boolean removeImportantNotification(String pkg, String key) {
-            return removeNotification(mImportantNotifications, pkg, key);
-        }
-
-        public void addStandardLayoutNotification(String pkg, String key) {
-            addNotification(mStandardLayoutNotifications, pkg, key);
-        }
-
-        public boolean removeStandardLayoutNotification(String pkg, String key) {
-            return removeNotification(mStandardLayoutNotifications, pkg, key);
-        }
-
-        public boolean removeNotification(String pkg, String key) {
-            boolean removed = false;
-            removed |= removeImportantNotification(pkg, key);
-            removed |= removeStandardLayoutNotification(pkg, key);
-            return removed;
-        }
-
-        public void addNotification(ArrayMap<String, ArraySet<String>> map, String pkg,
-                String key) {
-            if (map.get(pkg) == null) {
-                map.put(pkg, new ArraySet<>());
-            }
-            map.get(pkg).add(key);
-        }
-
-        public boolean removeNotification(ArrayMap<String, ArraySet<String>> map,
-                String pkg, String key) {
-            final boolean found;
-            final ArraySet<String> keys = map.get(pkg);
-            if (keys == null) {
-                found = false;
-            } else {
-                found = keys.remove(key);
-                if (keys.size() == 0) {
-                    map.remove(pkg);
-                }
-            }
-            return found;
-        }
-
-        public boolean isDungeonNeeded() {
-            if (mRunning != null
-                && System.currentTimeMillis() - mServiceStartTime >= FG_SERVICE_GRACE_MILLIS) {
-
-                for (String pkg : mRunning) {
-                    final ArraySet<String> set = mImportantNotifications.get(pkg);
-                    if (set == null || set.size() == 0) {
-                        return true;
-                    }
-                }
-            }
-            return false;
-        }
-
-        public ArraySet<Integer> getFeatures(String pkg) {
-            return mAppOps.get(pkg);
-        }
-
-        public String getStandardLayoutKey(String pkg) {
-            final ArraySet<String> set = mStandardLayoutNotifications.get(pkg);
-            if (set == null || set.size() == 0) {
-                return null;
-            }
-            return set.valueAt(0);
-        }
-
-        @Override
-        public String toString() {
-            return "UserServices{" +
-                    "mRunning=" + Arrays.toString(mRunning) +
-                    ", mServiceStartTime=" + mServiceStartTime +
-                    ", mImportantNotifications=" + mImportantNotifications +
-                    ", mStandardLayoutNotifications=" + mStandardLayoutNotifications +
-                    '}';
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
new file mode 100644
index 0000000..96b62ac
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -0,0 +1,147 @@
+/*
+ * 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;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** Updates foreground service notification state in response to notification data events. */
+@Singleton
+public class ForegroundServiceNotificationListener {
+
+    private static final String TAG = "FgServiceController";
+    private static final boolean DBG = false;
+
+    private final Context mContext;
+    private final ForegroundServiceController mForegroundServiceController;
+
+    @Inject
+    public ForegroundServiceNotificationListener(Context context,
+            ForegroundServiceController foregroundServiceController,
+            NotificationEntryManager notificationEntryManager) {
+        mContext = context;
+        mForegroundServiceController = foregroundServiceController;
+        notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
+            @Override
+            public void onPendingEntryAdded(NotificationEntry entry) {
+                addNotification(entry.notification, entry.importance);
+            }
+
+            @Override
+            public void onPostEntryUpdated(NotificationEntry entry) {
+                updateNotification(entry.notification, entry.importance);
+            }
+
+            @Override
+            public void onEntryRemoved(
+                    NotificationEntry entry,
+                    NotificationVisibility visibility,
+                    boolean removedByUser) {
+                removeNotification(entry.notification);
+            }
+        });
+    }
+
+    /**
+     * @param sbn notification that was just posted
+     */
+    private void addNotification(StatusBarNotification sbn, int importance) {
+        updateNotification(sbn, importance);
+    }
+
+    /**
+     * @param sbn notification that was just removed
+     */
+    private void removeNotification(StatusBarNotification sbn) {
+        mForegroundServiceController.updateUserState(
+                sbn.getUserId(),
+                new ForegroundServiceController.UserStateUpdateCallback() {
+                    @Override
+                    public boolean updateUserState(ForegroundServicesUserState userState) {
+                        if (mForegroundServiceController.isDisclosureNotification(sbn)) {
+                            // if you remove the dungeon entirely, we take that to mean there are
+                            // no running services
+                            userState.setRunningServices(null, 0);
+                            return true;
+                        } else {
+                            // this is safe to call on any notification, not just
+                            // FLAG_FOREGROUND_SERVICE
+                            return userState.removeNotification(sbn.getPackageName(), sbn.getKey());
+                        }
+                    }
+
+                    @Override
+                    public void userStateNotFound(int userId) {
+                        if (DBG) {
+                            Log.w(TAG, String.format(
+                                    "user %d with no known notifications got removeNotification "
+                                            + "for %s",
+                                    sbn.getUserId(), sbn));
+                        }
+                    }
+                },
+                false /* don't create */);
+    }
+
+    /**
+     * @param sbn notification that was just changed in some way
+     */
+    private void updateNotification(StatusBarNotification sbn, int newImportance) {
+        mForegroundServiceController.updateUserState(
+                sbn.getUserId(),
+                userState -> {
+                    if (mForegroundServiceController.isDisclosureNotification(sbn)) {
+                        final Bundle extras = sbn.getNotification().extras;
+                        if (extras != null) {
+                            final String[] svcs = extras.getStringArray(
+                                    Notification.EXTRA_FOREGROUND_APPS);
+                            userState.setRunningServices(svcs, sbn.getNotification().when);
+                        }
+                    } else {
+                        userState.removeNotification(sbn.getPackageName(), sbn.getKey());
+                        if (0 != (sbn.getNotification().flags
+                                & Notification.FLAG_FOREGROUND_SERVICE)) {
+                            if (newImportance > NotificationManager.IMPORTANCE_MIN) {
+                                userState.addImportantNotification(sbn.getPackageName(),
+                                        sbn.getKey());
+                            }
+                            final Notification.Builder builder =
+                                    Notification.Builder.recoverBuilder(
+                                            mContext, sbn.getNotification());
+                            if (builder.usesStandardHeader()) {
+                                userState.addStandardLayoutNotification(
+                                        sbn.getPackageName(), sbn.getKey());
+                            }
+                        }
+                    }
+                    return true;
+                },
+                true /* create if not found */);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.java b/packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.java
new file mode 100644
index 0000000..a8ae654
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.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;
+
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import java.util.Arrays;
+
+/**
+ * Struct to track relevant packages and notifications for a userid's foreground services.
+ */
+class ForegroundServicesUserState {
+    // shelf life of foreground services before they go bad
+    private static final long FG_SERVICE_GRACE_MILLIS = 5000;
+
+    private String[] mRunning = null;
+    private long mServiceStartTime = 0;
+    // package -> sufficiently important posted notification keys
+    private ArrayMap<String, ArraySet<String>> mImportantNotifications = new ArrayMap<>(1);
+    // package -> standard layout posted notification keys
+    private ArrayMap<String, ArraySet<String>> mStandardLayoutNotifications = new ArrayMap<>(1);
+
+    // package -> app ops
+    private ArrayMap<String, ArraySet<Integer>> mAppOps = new ArrayMap<>(1);
+
+    public void setRunningServices(String[] pkgs, long serviceStartTime) {
+        mRunning = pkgs != null ? Arrays.copyOf(pkgs, pkgs.length) : null;
+        mServiceStartTime = serviceStartTime;
+    }
+
+    public void addOp(String pkg, int op) {
+        if (mAppOps.get(pkg) == null) {
+            mAppOps.put(pkg, new ArraySet<>(3));
+        }
+        mAppOps.get(pkg).add(op);
+    }
+
+    public boolean removeOp(String pkg, int op) {
+        final boolean found;
+        final ArraySet<Integer> keys = mAppOps.get(pkg);
+        if (keys == null) {
+            found = false;
+        } else {
+            found = keys.remove(op);
+            if (keys.size() == 0) {
+                mAppOps.remove(pkg);
+            }
+        }
+        return found;
+    }
+
+    public void addImportantNotification(String pkg, String key) {
+        addNotification(mImportantNotifications, pkg, key);
+    }
+
+    public boolean removeImportantNotification(String pkg, String key) {
+        return removeNotification(mImportantNotifications, pkg, key);
+    }
+
+    public void addStandardLayoutNotification(String pkg, String key) {
+        addNotification(mStandardLayoutNotifications, pkg, key);
+    }
+
+    public boolean removeStandardLayoutNotification(String pkg, String key) {
+        return removeNotification(mStandardLayoutNotifications, pkg, key);
+    }
+
+    public boolean removeNotification(String pkg, String key) {
+        boolean removed = false;
+        removed |= removeImportantNotification(pkg, key);
+        removed |= removeStandardLayoutNotification(pkg, key);
+        return removed;
+    }
+
+    public void addNotification(ArrayMap<String, ArraySet<String>> map, String pkg,
+            String key) {
+        if (map.get(pkg) == null) {
+            map.put(pkg, new ArraySet<>());
+        }
+        map.get(pkg).add(key);
+    }
+
+    public boolean removeNotification(ArrayMap<String, ArraySet<String>> map,
+            String pkg, String key) {
+        final boolean found;
+        final ArraySet<String> keys = map.get(pkg);
+        if (keys == null) {
+            found = false;
+        } else {
+            found = keys.remove(key);
+            if (keys.size() == 0) {
+                map.remove(pkg);
+            }
+        }
+        return found;
+    }
+
+    public boolean isDisclosureNeeded() {
+        if (mRunning != null
+                && System.currentTimeMillis() - mServiceStartTime
+                >= FG_SERVICE_GRACE_MILLIS) {
+
+            for (String pkg : mRunning) {
+                final ArraySet<String> set = mImportantNotifications.get(pkg);
+                if (set == null || set.size() == 0) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public ArraySet<Integer> getFeatures(String pkg) {
+        return mAppOps.get(pkg);
+    }
+
+    public String getStandardLayoutKey(String pkg) {
+        final ArraySet<String> set = mStandardLayoutNotifications.get(pkg);
+        if (set == null || set.size() == 0) {
+            return null;
+        }
+        return set.valueAt(0);
+    }
+
+    @Override
+    public String toString() {
+        return "UserServices{"
+                + "mRunning=" + Arrays.toString(mRunning)
+                + ", mServiceStartTime=" + mServiceStartTime
+                + ", mImportantNotifications=" + mImportantNotifications
+                + ", mStandardLayoutNotifications=" + mStandardLayoutNotifications
+                + '}';
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index 16e869e..e28aa9d 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -37,23 +37,25 @@
 import com.android.systemui.tuner.TunerService.Tunable;
 import com.android.systemui.util.leak.RotationUtils;
 
-public class HardwareUiLayout extends LinearLayout implements Tunable {
+/**
+ * Layout for placing two containers at a specific physical position on the device, relative to the
+ * device's hardware, regardless of screen rotation.
+ */
+public class HardwareUiLayout extends MultiListLayout implements Tunable {
 
     private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
     private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
     private final int[] mTmp2 = new int[2];
-    private View mList;
-    private View mSeparatedView;
+    private ViewGroup mList;
+    private ViewGroup mSeparatedView;
     private int mOldHeight;
     private boolean mAnimating;
     private AnimatorSet mAnimation;
     private View mDivision;
-    private boolean mHasOutsideTouch;
     private HardwareBgDrawable mListBackground;
     private HardwareBgDrawable mSeparatedViewBackground;
     private Animator mAnimator;
     private boolean mCollapse;
-    private boolean mHasSeparatedButton;
     private int mEndPoint;
     private boolean mEdgeBleed;
     private boolean mRoundedDivider;
@@ -67,6 +69,35 @@
     }
 
     @Override
+    protected ViewGroup getSeparatedView() {
+        return findViewById(com.android.systemui.R.id.separated_button);
+    }
+
+    @Override
+    protected ViewGroup getListView() {
+        return findViewById(android.R.id.list);
+    }
+
+    @Override
+    public void removeAllItems() {
+        if (mList != null) {
+            mList.removeAllViews();
+        }
+        if (mSeparatedView != null) {
+            mSeparatedView.removeAllViews();
+        }
+    }
+
+    @Override
+    public ViewGroup getParentView(boolean separated, int index) {
+        if (separated) {
+            return getSeparatedView();
+        } else {
+            return getListView();
+        }
+    }
+
+    @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         updateSettings();
@@ -137,9 +168,9 @@
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         if (mList == null) {
             if (getChildCount() != 0) {
-                mList = getChildAt(0);
+                mList = getListView();
                 mList.setBackground(mListBackground);
-                mSeparatedView = getChildAt(1);
+                mSeparatedView = getSeparatedView();
                 mSeparatedView.setBackground(mSeparatedViewBackground);
                 updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
                 mOldHeight = mList.getMeasuredHeight();
@@ -187,7 +218,7 @@
         } else {
             rotateLeft();
         }
-        if (mHasSeparatedButton) {
+        if (mHasSeparatedView) {
             if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
                 // Separated view has top margin, so seascape separated view need special rotation,
                 // not a full left or right rotation.
@@ -408,8 +439,8 @@
         if (mList == null) return;
         // If got separated button, setRotatedBackground to false,
         // all items won't get white background.
-        mListBackground.setRotatedBackground(mHasSeparatedButton);
-        mSeparatedViewBackground.setRotatedBackground(mHasSeparatedButton);
+        mListBackground.setRotatedBackground(mHasSeparatedView);
+        mSeparatedViewBackground.setRotatedBackground(mHasSeparatedView);
         if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
             int index = mRotatedBackground ? 0 : 1;
             mDivision.getLocationOnScreen(mTmp2);
@@ -460,21 +491,21 @@
             case RotationUtils.ROTATION_LANDSCAPE:
                 defaultTopPadding = getPaddingLeft();
                 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
-                separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0;
+                separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0;
                 screenHeight = getMeasuredWidth();
                 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
                 break;
             case RotationUtils.ROTATION_SEASCAPE:
                 defaultTopPadding = getPaddingRight();
                 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
-                separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0;
+                separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0;
                 screenHeight = getMeasuredWidth();
                 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
                 break;
             default: // Portrait
                 defaultTopPadding = getPaddingTop();
                 viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
-                separatedViewTopMargin = mHasSeparatedButton ? params.topMargin : 0;
+                separatedViewTopMargin = mHasSeparatedView ? params.topMargin : 0;
                 screenHeight = getMeasuredHeight();
                 targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
                 break;
@@ -491,30 +522,10 @@
         return super.getOutlineProvider();
     }
 
-    public void setOutsideTouchListener(OnClickListener onClickListener) {
-        mHasOutsideTouch = true;
-        requestLayout();
-        setOnClickListener(onClickListener);
-        setClickable(true);
-        setFocusable(true);
-    }
-
     public void setCollapse() {
         mCollapse = true;
     }
 
-    public void setHasSeparatedButton(boolean hasSeparatedButton) {
-        mHasSeparatedButton = hasSeparatedButton;
-    }
-
-    public static HardwareUiLayout get(View v) {
-        if (v instanceof HardwareUiLayout) return (HardwareUiLayout) v;
-        if (v.getParent() instanceof View) {
-            return get((View) v.getParent());
-        }
-        return null;
-    }
-
     private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
         if (mHasOutsideTouch || (mList == null)) {
             inoutInfo.setTouchableInsets(
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 1d2d7fa..2aecc24 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -16,14 +16,18 @@
 
 package com.android.systemui;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import android.app.WallpaperManager;
 import android.content.ComponentCallbacks2;
+import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region.Op;
+import android.hardware.display.DisplayManager;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Trace;
@@ -33,7 +37,6 @@
 import android.view.DisplayInfo;
 import android.view.Surface;
 import android.view.SurfaceHolder;
-import android.view.WindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -94,7 +97,7 @@
         float mYOffset = 0f;
         float mScale = 1f;
 
-        private Display mDefaultDisplay;
+        private Display mDisplay;
         private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
 
         boolean mVisible = true;
@@ -138,10 +141,20 @@
             super.onCreate(surfaceHolder);
 
             //noinspection ConstantConditions
-            mDefaultDisplay = getSystemService(WindowManager.class).getDefaultDisplay();
+            final Context displayContext = getDisplayContext();
+            final int displayId = displayContext == null ? DEFAULT_DISPLAY :
+                    displayContext.getDisplayId();
+            DisplayManager dm = getSystemService(DisplayManager.class);
+            if (dm != null) {
+                mDisplay = dm.getDisplay(displayId);
+                if (mDisplay == null) {
+                    Log.e(TAG, "Cannot find display! Fallback to default.");
+                    mDisplay = dm.getDisplay(DEFAULT_DISPLAY);
+                }
+            }
             setOffsetNotificationsEnabled(false);
 
-            updateSurfaceSize(surfaceHolder, getDefaultDisplayInfo(), false /* forDraw */);
+            updateSurfaceSize(surfaceHolder, getDisplayInfo(), false /* forDraw */);
         }
 
         @Override
@@ -165,9 +178,26 @@
                 hasWallpaper = false;
             }
 
-            // Set surface size equal to bitmap size, prevent memory waste
-            int surfaceWidth = Math.max(MIN_BACKGROUND_WIDTH, mBackgroundWidth);
-            int surfaceHeight = Math.max(MIN_BACKGROUND_HEIGHT, mBackgroundHeight);
+            // Expected surface size.
+            int surfaceWidth = Math.max(displayInfo.logicalWidth, mBackgroundWidth);
+            int surfaceHeight = Math.max(displayInfo.logicalHeight, mBackgroundHeight);
+
+            // Calculate the minimum drawing area of the surface, which saves memory and does not
+            // distort the image.
+            final float scale = Math.min(
+                    (float) mBackgroundHeight / (float) surfaceHeight,
+                    (float) mBackgroundWidth / (float) surfaceWidth);
+            surfaceHeight = (int) (scale * surfaceHeight);
+            surfaceWidth = (int) (scale * surfaceWidth);
+
+            // Set surface size to at least MIN size.
+            if (surfaceWidth < MIN_BACKGROUND_WIDTH || surfaceHeight < MIN_BACKGROUND_HEIGHT) {
+                final float scaleUp = Math.max(
+                        (float) MIN_BACKGROUND_WIDTH / (float) surfaceWidth,
+                        (float) MIN_BACKGROUND_HEIGHT / (float) surfaceHeight);
+                surfaceWidth = (int) ((float) surfaceWidth * scaleUp);
+                surfaceHeight = (int) ((float) surfaceHeight * scaleUp);
+            }
 
             // Used a fixed size surface, because we are special.  We can do
             // this because we know the current design of window animations doesn't
@@ -267,8 +297,8 @@
         }
 
         @VisibleForTesting
-        DisplayInfo getDefaultDisplayInfo() {
-            mDefaultDisplay.getDisplayInfo(mTmpDisplayInfo);
+        DisplayInfo getDisplayInfo() {
+            mDisplay.getDisplayInfo(mTmpDisplayInfo);
             return mTmpDisplayInfo;
         }
 
@@ -278,7 +308,7 @@
             }
             try {
                 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawWallpaper");
-                DisplayInfo displayInfo = getDefaultDisplayInfo();
+                DisplayInfo displayInfo = getDisplayInfo();
                 int newRotation = displayInfo.rotation;
 
                 // Sometimes a wallpaper is not large enough to cover the screen in one dimension.
@@ -445,7 +475,7 @@
             if (DEBUG) {
                 Log.d(TAG, "Wallpaper loaded: " + mBackground);
             }
-            updateSurfaceSize(getSurfaceHolder(), getDefaultDisplayInfo(),
+            updateSurfaceSize(getSurfaceHolder(), getDisplayInfo(),
                     false /* forDraw */);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
new file mode 100644
index 0000000..0c7a9a9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+/**
+ * Layout class representing the Global Actions menu which appears when the power button is held.
+ */
+public abstract class MultiListLayout extends LinearLayout {
+    boolean mHasOutsideTouch;
+    boolean mHasSeparatedView;
+
+    int mExpectedSeparatedItemCount;
+    int mExpectedListItemCount;
+
+    public MultiListLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    protected abstract ViewGroup getSeparatedView();
+
+    protected abstract ViewGroup getListView();
+
+    /**
+     * Removes all child items from the separated and list views, if they exist.
+     */
+    public abstract void removeAllItems();
+
+    /**
+     * Get the parent view which will be used to contain the item at the specified index.
+     * @param separated Whether or not this index refers to a position in the separated or list
+     *                  container.
+     * @param index The index of the item within the container.
+     * @return The parent ViewGroup which will be used to contain the specified item
+     * after it has been added to the layout.
+     */
+    public abstract ViewGroup getParentView(boolean separated, int index);
+
+    /**
+     * Sets the divided view, which may have a differently-colored background.
+     */
+    public abstract void setDivisionView(View v);
+
+    /**
+     * Set the view accessibility delegate for the list view container.
+     */
+    public void setListViewAccessibilityDelegate(View.AccessibilityDelegate delegate) {
+        getListView().setAccessibilityDelegate(delegate);
+    }
+
+    protected void setSeparatedViewVisibility(boolean visible) {
+        getSeparatedView().setVisibility(visible ? View.VISIBLE : View.GONE);
+    }
+
+    /**
+     * Sets the number of items expected to be rendered in the separated container. This allows the
+     * layout to correctly determine which parent containers will be used for items before they have
+     * beenadded to the layout.
+     * @param count The number of items expected.
+     */
+    public void setExpectedSeparatedItemCount(int count) {
+        mExpectedSeparatedItemCount = count;
+    }
+
+    /**
+     * Sets the number of items expected to be rendered in the list container. This allows the
+     * layout to correctly determine which parent containers will be used for items before they have
+     * beenadded to the layout.
+     * @param count The number of items expected.
+     */
+    public void setExpectedListItemCount(int count) {
+        mExpectedListItemCount = count;
+    }
+
+    /**
+     * Sets whether the separated view should be shown, and handles updating visibility on
+     * that view.
+     */
+    public void setHasSeparatedView(boolean hasSeparatedView) {
+        mHasSeparatedView = hasSeparatedView;
+        setSeparatedViewVisibility(hasSeparatedView);
+    }
+
+    /**
+     * Sets this layout to respond to an outside touch listener.
+     */
+    public void setOutsideTouchListener(OnClickListener onClickListener) {
+        mHasOutsideTouch = true;
+        requestLayout();
+        setOnClickListener(onClickListener);
+        setClickable(true);
+        setFocusable(true);
+    }
+
+    /**
+     * Retrieve the MultiListLayout associated with the given view.
+     */
+    public static MultiListLayout get(View v) {
+        if (v instanceof MultiListLayout) return (MultiListLayout) v;
+        if (v.getParent() instanceof View) {
+            return get((View) v.getParent());
+        }
+        return null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 1dd231c..ab077d6 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -329,11 +329,11 @@
 
     private void updateRoundedCornerRadii() {
         final int newRoundedDefault = mContext.getResources().getDimensionPixelSize(
-                R.dimen.rounded_corner_radius);
+                com.android.internal.R.dimen.rounded_corner_radius);
         final int newRoundedDefaultTop = mContext.getResources().getDimensionPixelSize(
-                R.dimen.rounded_corner_radius_top);
+                com.android.internal.R.dimen.rounded_corner_radius_top);
         final int newRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize(
-                R.dimen.rounded_corner_radius_bottom);
+                com.android.internal.R.dimen.rounded_corner_radius_bottom);
 
         final boolean roundedCornersChanged = mRoundedDefault != newRoundedDefault
                 || mRoundedDefaultBottom != newRoundedDefaultBottom
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 3666400..9efa656 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -604,8 +604,14 @@
                         if (absDelta >= size) {
                             delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
                         } else {
-                            delta = maxScrollDistance * (float) Math.sin(
-                                    (delta / size) * (Math.PI / 2));
+                            int startPosition = mCallback.getConstrainSwipeStartPosition();
+                            if (absDelta > startPosition) {
+                                int signedStartPosition =
+                                        (int) (startPosition * Math.signum(delta));
+                                delta = signedStartPosition
+                                        + maxScrollDistance * (float) Math.sin(
+                                        ((delta - signedStartPosition) / size) * (Math.PI / 2));
+                            }
                         }
                     }
 
@@ -742,6 +748,14 @@
         float getFalsingThresholdFactor();
 
         /**
+         * @return The position, in pixels, at which a constrained swipe should start being
+         * constrained.
+         */
+        default int getConstrainSwipeStartPosition() {
+            return 0;
+        }
+
+        /**
          * @return If true, the given view is draggable.
          */
         default boolean canChildBeDragged(@NonNull View animView) { return true; }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index e3bfdc9..f66a57b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui;
 
+import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;
 
 import android.annotation.Nullable;
@@ -39,9 +40,10 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
 import com.android.systemui.statusbar.ScrimView;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
@@ -50,6 +52,7 @@
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.ScrimState;
+import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -134,8 +137,8 @@
     }
 
     public NotificationIconAreaController createNotificationIconAreaController(Context context,
-            StatusBar statusBar) {
-        return new NotificationIconAreaController(context, statusBar);
+            StatusBar statusBar, StatusBarStateController statusBarStateController) {
+        return new NotificationIconAreaController(context, statusBar, statusBarStateController);
     }
 
     public KeyguardIndicationController createKeyguardIndicationController(Context context,
@@ -200,6 +203,19 @@
         return new NotificationInterruptionStateProvider(context);
     }
 
+    @Singleton
+    @Provides
+    @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME)
+    public boolean provideAllowNotificationLongPress() {
+        return true;
+    }
+
+    @Singleton
+    @Provides
+    public ShadeController provideShadeController(Context context) {
+        return SysUiServiceProvider.getComponent(context, StatusBar.class);
+    }
+
     @Module
     protected static class ContextHolder {
         private Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
index 9f363f6..7e5b426 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpItem.java
@@ -25,12 +25,20 @@
     private int mUid;
     private String mPackageName;
     private long mTimeStarted;
+    private String mState;
 
     public AppOpItem(int code, int uid, String packageName, long timeStarted) {
         this.mCode = code;
         this.mUid = uid;
         this.mPackageName = packageName;
         this.mTimeStarted = timeStarted;
+        mState = new StringBuilder()
+                .append("AppOpItem(")
+                .append("Op code=").append(code).append(", ")
+                .append("UID=").append(uid).append(", ")
+                .append("Package name=").append(packageName)
+                .append(")")
+                .toString();
     }
 
     public int getCode() {
@@ -48,4 +56,9 @@
     public long getTimeStarted() {
         return mTimeStarted;
     }
+
+    @Override
+    public String toString() {
+        return mState;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index e3bcb37..c013df3 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -29,7 +29,10 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dumpable;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -47,7 +50,7 @@
 @Singleton
 public class AppOpsControllerImpl implements AppOpsController,
         AppOpsManager.OnOpActiveChangedListener,
-        AppOpsManager.OnOpNotedListener {
+        AppOpsManager.OnOpNotedListener, Dumpable {
 
     private static final long NOTED_OP_TIME_DELAY_MS = 5000;
     private static final String TAG = "AppOpsControllerImpl";
@@ -271,6 +274,22 @@
         }
     }
 
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("AppOpsController state:");
+        pw.println("  Active Items:");
+        for (int i = 0; i < mActiveItems.size(); i++) {
+            final AppOpItem item = mActiveItems.get(i);
+            pw.print("    "); pw.println(item.toString());
+        }
+        pw.println("  Noted Items:");
+        for (int i = 0; i < mNotedItems.size(); i++) {
+            final AppOpItem item = mNotedItems.get(i);
+            pw.print("    "); pw.println(item.toString());
+        }
+
+    }
+
     protected final class H extends Handler {
         H(Looper looper) {
             super(looper);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 53cdee5..4d70890 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -47,6 +47,10 @@
 public class AssistManager implements ConfigurationChangedReceiver {
 
     private static final String TAG = "AssistManager";
+
+    // Note that VERBOSE logging may leak PII (e.g. transcription contents).
+    private static final boolean VERBOSE = false;
+
     private static final String ASSIST_ICON_METADATA_NAME =
             "com.android.systemui.action_assist_icon";
 
@@ -103,16 +107,41 @@
     protected void registerVoiceInteractionSessionListener() {
         mAssistUtils.registerVoiceInteractionSessionListener(
                 new IVoiceInteractionSessionListener.Stub() {
-            @Override
-            public void onVoiceSessionShown() throws RemoteException {
-                Log.v(TAG, "Voice open");
-            }
+                    @Override
+                    public void onVoiceSessionShown() throws RemoteException {
+                        if (VERBOSE) {
+                            Log.v(TAG, "Voice open");
+                        }
+                    }
 
-            @Override
-            public void onVoiceSessionHidden() throws RemoteException {
-                Log.v(TAG, "Voice closed");
-            }
-        });
+                    @Override
+                    public void onVoiceSessionHidden() throws RemoteException {
+                        if (VERBOSE) {
+                            Log.v(TAG, "Voice closed");
+                        }
+                    }
+
+                    @Override
+                    public void onTranscriptionUpdate(String transcription) {
+                        if (VERBOSE) {
+                            Log.v(TAG, "Transcription Updated: \"" + transcription + "\"");
+                        }
+                    }
+
+                    @Override
+                    public void onTranscriptionComplete(boolean immediate) {
+                        if (VERBOSE) {
+                            Log.v(TAG, "Transcription complete (immediate=" + immediate + ")");
+                        }
+                    }
+
+                    @Override
+                    public void onVoiceStateChange(int state) {
+                        if (VERBOSE) {
+                            Log.v(TAG, "Voice state is now " + state);
+                        }
+                    }
+                });
     }
 
     public void onConfigurationChanged(Configuration newConfiguration) {
@@ -291,8 +320,10 @@
                     }
                 }
             } catch (PackageManager.NameNotFoundException e) {
-                Log.v(TAG, "Assistant component "
-                        + component.flattenToShortString() + " not found");
+                if (VERBOSE) {
+                    Log.v(TAG, "Assistant component "
+                            + component.flattenToShortString() + " not found");
+                }
             } catch (Resources.NotFoundException nfe) {
                 Log.w(TAG, "Failed to swap drawable from "
                         + component.flattenToShortString(), nfe);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
index ba89fe6..016b8fe 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
@@ -33,9 +33,6 @@
 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.
  * BiometricDialogView).
@@ -52,10 +49,8 @@
     private static final int MSG_BUTTON_NEGATIVE = 6;
     private static final int MSG_USER_CANCELED = 7;
     private static final int MSG_BUTTON_POSITIVE = 8;
-    private static final int MSG_BIOMETRIC_SHOW_TRY_AGAIN = 9;
-    private static final int MSG_TRY_AGAIN_PRESSED = 10;
+    private static final int MSG_TRY_AGAIN_PRESSED = 9;
 
-    private Map<Integer, BiometricDialogView> mDialogs; // BiometricAuthenticator type, view
     private SomeArgs mCurrentDialogArgs;
     private BiometricDialogView mCurrentDialog;
     private WindowManager mWindowManager;
@@ -63,21 +58,22 @@
     private boolean mDialogShowing;
     private Callback mCallback = new Callback();
 
-    private boolean mTryAgainShowing; // No good place to save state before config change :/
-    private boolean mConfirmShowing; // No good place to save state before config change :/
-
     private Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch(msg.what) {
                 case MSG_SHOW_DIALOG:
-                    handleShowDialog((SomeArgs) msg.obj, false /* skipAnimation */);
+                    handleShowDialog((SomeArgs) msg.obj, false /* skipAnimation */,
+                            null /* savedState */);
                     break;
                 case MSG_BIOMETRIC_AUTHENTICATED:
-                    handleBiometricAuthenticated();
+                    handleBiometricAuthenticated((boolean) msg.obj);
                     break;
                 case MSG_BIOMETRIC_HELP:
-                    handleBiometricHelp((String) msg.obj);
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    handleBiometricHelp((String) args.arg1 /* message */,
+                            (boolean) args.arg2 /* requireTryAgain */);
+                    args.recycle();
                     break;
                 case MSG_BIOMETRIC_ERROR:
                     handleBiometricError((String) msg.obj);
@@ -94,9 +90,6 @@
                 case MSG_BUTTON_POSITIVE:
                     handleButtonPositive();
                     break;
-                case MSG_BIOMETRIC_SHOW_TRY_AGAIN:
-                    handleShowTryAgain();
-                    break;
                 case MSG_TRY_AGAIN_PRESSED:
                     handleTryAgainPressed();
                     break;
@@ -137,30 +130,22 @@
 
     @Override
     public void start() {
-        createDialogs();
-
-        if (!mDialogs.isEmpty()) {
+        final PackageManager pm = mContext.getPackageManager();
+        if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
+                || pm.hasSystemFeature(PackageManager.FEATURE_FACE)
+                || pm.hasSystemFeature(PackageManager.FEATURE_IRIS)) {
             getComponent(CommandQueue.class).addCallback(this);
             mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         }
     }
 
-    private void createDialogs() {
-        final PackageManager pm = mContext.getPackageManager();
-        mDialogs = new HashMap<>();
-        if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
-            mDialogs.put(BiometricAuthenticator.TYPE_FACE, new FaceDialogView(mContext, mCallback));
-        }
-        if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
-            mDialogs.put(BiometricAuthenticator.TYPE_FINGERPRINT,
-                    new FingerprintDialogView(mContext, mCallback));
-        }
-    }
-
     @Override
     public void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
             int type, boolean requireConfirmation, int userId) {
-        if (DEBUG) Log.d(TAG, "showBiometricDialog, type: " + type);
+        if (DEBUG) {
+            Log.d(TAG, "showBiometricDialog, type: " + type
+                    + ", requireConfirmation: " + requireConfirmation);
+        }
         // Remove these messages as they are part of the previous client
         mHandler.removeMessages(MSG_BIOMETRIC_ERROR);
         mHandler.removeMessages(MSG_BIOMETRIC_HELP);
@@ -176,15 +161,18 @@
     }
 
     @Override
-    public void onBiometricAuthenticated() {
-        if (DEBUG) Log.d(TAG, "onBiometricAuthenticated");
-        mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED).sendToTarget();
+    public void onBiometricAuthenticated(boolean authenticated) {
+        if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: " + authenticated);
+        mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, authenticated).sendToTarget();
     }
 
     @Override
     public void onBiometricHelp(String message) {
         if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message);
-        mHandler.obtainMessage(MSG_BIOMETRIC_HELP, message).sendToTarget();
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = message;
+        args.arg2 = false; // requireTryAgain
+        mHandler.obtainMessage(MSG_BIOMETRIC_HELP, args).sendToTarget();
     }
 
     @Override
@@ -199,16 +187,21 @@
         mHandler.obtainMessage(MSG_HIDE_DIALOG, false /* userCanceled */).sendToTarget();
     }
 
-    @Override
-    public void showBiometricTryAgain() {
-        if (DEBUG) Log.d(TAG, "showBiometricTryAgain");
-        mHandler.obtainMessage(MSG_BIOMETRIC_SHOW_TRY_AGAIN).sendToTarget();
-    }
-
-    private void handleShowDialog(SomeArgs args, boolean skipAnimation) {
+    private void handleShowDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
         mCurrentDialogArgs = args;
         final int type = args.argi1;
-        mCurrentDialog = mDialogs.get(type);
+
+        if (type == BiometricAuthenticator.TYPE_FINGERPRINT) {
+            mCurrentDialog = new FingerprintDialogView(mContext, mCallback);
+        } else if (type == BiometricAuthenticator.TYPE_FACE) {
+            mCurrentDialog = new FaceDialogView(mContext, mCallback);
+        } else {
+            Log.e(TAG, "Unsupported type: " + type);
+        }
+
+        if (savedState != null) {
+            mCurrentDialog.restoreState(savedState);
+        }
 
         if (DEBUG) Log.d(TAG, "handleShowDialog, isAnimatingAway: "
                 + mCurrentDialog.isAnimatingAway() + " type: " + type);
@@ -224,29 +217,36 @@
         mCurrentDialog.setRequireConfirmation((boolean) args.arg3);
         mCurrentDialog.setUserId(args.argi2);
         mCurrentDialog.setSkipIntro(skipAnimation);
-        mCurrentDialog.setPendingTryAgain(mTryAgainShowing);
-        mCurrentDialog.setPendingConfirm(mConfirmShowing);
         mWindowManager.addView(mCurrentDialog, mCurrentDialog.getLayoutParams());
         mDialogShowing = true;
     }
 
-    private void handleBiometricAuthenticated() {
-        if (DEBUG) Log.d(TAG, "handleBiometricAuthenticated");
+    private void handleBiometricAuthenticated(boolean authenticated) {
+        if (DEBUG) Log.d(TAG, "handleBiometricAuthenticated: " + authenticated);
 
-        mCurrentDialog.announceForAccessibility(
-                mContext.getResources()
-                        .getText(mCurrentDialog.getAuthenticatedAccessibilityResourceId()));
-        if (mCurrentDialog.requiresConfirmation()) {
-            mConfirmShowing = true;
-            mCurrentDialog.showConfirmationButton(true /* show */);
+        if (authenticated) {
+            mCurrentDialog.announceForAccessibility(
+                    mContext.getResources()
+                            .getText(mCurrentDialog.getAuthenticatedAccessibilityResourceId()));
+            if (mCurrentDialog.requiresConfirmation()) {
+                mCurrentDialog.showConfirmationButton(true /* show */);
+            } else {
+                mCurrentDialog.updateState(BiometricDialogView.STATE_AUTHENTICATED);
+                mHandler.postDelayed(() -> {
+                    handleHideDialog(false /* userCanceled */);
+                }, mCurrentDialog.getDelayAfterAuthenticatedDurationMs());
+            }
         } else {
-            handleHideDialog(false /* userCanceled */);
+            handleBiometricHelp(mContext.getResources()
+                    .getString(com.android.internal.R.string.biometric_not_recognized),
+                    true /* requireTryAgain */);
+            mCurrentDialog.showTryAgainButton(true /* show */);
         }
     }
 
-    private void handleBiometricHelp(String message) {
+    private void handleBiometricHelp(String message, boolean requireTryAgain) {
         if (DEBUG) Log.d(TAG, "handleBiometricHelp: " + message);
-        mCurrentDialog.showHelpMessage(message);
+        mCurrentDialog.showHelpMessage(message, requireTryAgain);
     }
 
     private void handleBiometricError(String error) {
@@ -255,7 +255,6 @@
             if (DEBUG) Log.d(TAG, "Dialog already dismissed");
             return;
         }
-        mTryAgainShowing = false;
         mCurrentDialog.showErrorMessage(error);
     }
 
@@ -276,8 +275,6 @@
         }
         mReceiver = null;
         mDialogShowing = false;
-        mConfirmShowing = false;
-        mTryAgainShowing = false;
         mCurrentDialog.startDismiss();
     }
 
@@ -291,7 +288,6 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Remote exception when handling negative button", e);
         }
-        mTryAgainShowing = false;
         handleHideDialog(false /* userCanceled */);
     }
 
@@ -305,25 +301,16 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Remote exception when handling positive button", e);
         }
-        mConfirmShowing = false;
         handleHideDialog(false /* userCanceled */);
     }
 
     private void handleUserCanceled() {
-        mTryAgainShowing = false;
-        mConfirmShowing = false;
         handleHideDialog(true /* userCanceled */);
     }
 
-    private void handleShowTryAgain() {
-        mCurrentDialog.showTryAgainButton(true /* show */);
-        mTryAgainShowing = true;
-    }
-
     private void handleTryAgainPressed() {
         try {
             mCurrentDialog.clearTemporaryMessage();
-            mTryAgainShowing = false;
             mReceiver.onTryAgainPressed();
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException when handling try again", e);
@@ -334,13 +321,20 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         final boolean wasShowing = mDialogShowing;
+
+        // Save the state of the current dialog (buttons showing, etc)
+        final Bundle savedState = new Bundle();
+        if (mCurrentDialog != null) {
+            mCurrentDialog.onSaveState(savedState);
+        }
+
         if (mDialogShowing) {
             mCurrentDialog.forceRemove();
             mDialogShowing = false;
         }
-        createDialogs();
+
         if (wasShowing) {
-            handleShowDialog(mCurrentDialogArgs, true /* skipAnimation */);
+            handleShowDialog(mCurrentDialogArgs, true /* skipAnimation */, savedState);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index e085f23..c927677 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -21,6 +21,7 @@
 import android.content.res.TypedArray;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
+import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.hardware.biometrics.BiometricPrompt;
 import android.os.Binder;
@@ -55,15 +56,19 @@
 
     private static final String TAG = "BiometricDialogView";
 
+    private static final String KEY_TRY_AGAIN_VISIBILITY = "key_try_again_visibility";
+    private static final String KEY_CONFIRM_VISIBILITY = "key_confirm_visibility";
+
     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_IDLE = 0;
     protected static final int STATE_AUTHENTICATING = 1;
     protected static final int STATE_ERROR = 2;
-    protected static final int STATE_AUTHENTICATED = 3;
+    protected static final int STATE_PENDING_CONFIRMATION = 3;
+    protected static final int STATE_AUTHENTICATED = 4;
 
     private final IBinder mWindowToken = new Binder();
     private final Interpolator mLinearOutSlowIn;
@@ -72,14 +77,24 @@
     private final DevicePolicyManager mDevicePolicyManager;
     private final float mAnimationTranslationOffset;
     private final int mErrorColor;
-    private final int mTextColor;
     private final float mDialogWidth;
     private final DialogViewCallback mCallback;
 
-    private ViewGroup mLayout;
-    private final TextView mErrorText;
+    protected final ViewGroup mLayout;
+    protected final LinearLayout mDialog;
+    protected final TextView mTitleText;
+    protected final TextView mSubtitleText;
+    protected final TextView mDescriptionText;
+    protected final ImageView mBiometricIcon;
+    protected final TextView mErrorText;
+    protected final Button mPositiveButton;
+    protected final Button mNegativeButton;
+    protected final Button mTryAgainButton;
+
+    protected final int mTextColor;
+
     private Bundle mBundle;
-    private final LinearLayout mDialog;
+
     private int mLastState;
     private boolean mAnimatingAway;
     private boolean mWasForceRemoved;
@@ -87,13 +102,14 @@
     protected boolean mRequireConfirmation;
     private int mUserId; // used to determine if we should show work background
 
-    private boolean mPendingShowTryAgain;
-    private boolean mPendingShowConfirm;
-
-    protected abstract void updateIcon(int lastState, int newState);
     protected abstract int getHintStringResourceId();
     protected abstract int getAuthenticatedAccessibilityResourceId();
     protected abstract int getIconDescriptionResourceId();
+    protected abstract Drawable getAnimationForTransition(int oldState, int newState);
+    protected abstract boolean shouldAnimateForTransition(int oldState, int newState);
+    protected abstract int getDelayAfterAuthenticatedDurationMs();
+    protected abstract boolean shouldGrayAreaDismissDialog();
+    protected abstract void handleClearMessage(boolean requireTryAgain);
 
     private final Runnable mShowAnimationRunnable = new Runnable() {
         @Override
@@ -118,7 +134,7 @@
         public void handleMessage(Message msg) {
             switch(msg.what) {
                 case MSG_CLEAR_MESSAGE:
-                    handleClearMessage();
+                    handleClearMessage((boolean) msg.obj /* requireTryAgain */);
                     break;
                 default:
                     Log.e(TAG, "Unhandled message: " + msg.what);
@@ -152,10 +168,6 @@
         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
@@ -178,27 +190,38 @@
         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);
-        final Button tryAgain = mLayout.findViewById(R.id.button_try_again);
 
-        icon.setContentDescription(getResources().getString(getIconDescriptionResourceId()));
+        mDialog = mLayout.findViewById(R.id.dialog);
+        mTitleText = mLayout.findViewById(R.id.title);
+        mSubtitleText = mLayout.findViewById(R.id.subtitle);
+        mDescriptionText = mLayout.findViewById(R.id.description);
+        mBiometricIcon = mLayout.findViewById(R.id.biometric_icon);
+        mErrorText = mLayout.findViewById(R.id.error);
+        mNegativeButton = mLayout.findViewById(R.id.button2);
+        mPositiveButton = mLayout.findViewById(R.id.button1);
+        mTryAgainButton = mLayout.findViewById(R.id.button_try_again);
+
+        mBiometricIcon.setContentDescription(
+                getResources().getString(getIconDescriptionResourceId()));
 
         setDismissesDialog(space);
         setDismissesDialog(leftSpace);
         setDismissesDialog(rightSpace);
 
-        negative.setOnClickListener((View v) -> {
+        mNegativeButton.setOnClickListener((View v) -> {
             mCallback.onNegativePressed();
         });
 
-        positive.setOnClickListener((View v) -> {
-            mCallback.onPositivePressed();
+        mPositiveButton.setOnClickListener((View v) -> {
+            updateState(STATE_AUTHENTICATED);
+            mHandler.postDelayed(() -> {
+                mCallback.onPositivePressed();
+            }, getDelayAfterAuthenticatedDurationMs());
         });
 
-        tryAgain.setOnClickListener((View v) -> {
+        mTryAgainButton.setOnClickListener((View v) -> {
             showTryAgainButton(false /* show */);
+            handleClearMessage(false /* requireTryAgain */);
             mCallback.onTryAgainPressed();
         });
 
@@ -206,16 +229,17 @@
         mLayout.requestFocus();
     }
 
+    public void onSaveState(Bundle bundle) {
+        bundle.putInt(KEY_TRY_AGAIN_VISIBILITY, mTryAgainButton.getVisibility());
+        bundle.putInt(KEY_CONFIRM_VISIBILITY, mPositiveButton.getVisibility());
+    }
+
     @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
 
         mErrorText.setText(getHintStringResourceId());
 
-        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 ImageView backgroundView = mLayout.findViewById(R.id.background);
 
         if (mUserManager.isManagedProfile(mUserId)) {
@@ -229,39 +253,40 @@
             backgroundView.setBackgroundColor(R.color.biometric_dialog_dim_color);
         }
 
+        mNegativeButton.setVisibility(View.VISIBLE);
+        mErrorText.setVisibility(View.VISIBLE);
+
         if (RotationUtils.getRotation(mContext) != RotationUtils.ROTATION_NONE) {
             mDialog.getLayoutParams().width = (int) mDialogWidth;
         }
 
-        mLastState = STATE_NONE;
+        mLastState = STATE_IDLE;
         updateState(STATE_AUTHENTICATING);
 
         CharSequence titleText = mBundle.getCharSequence(BiometricPrompt.KEY_TITLE);
 
-        title.setText(titleText);
-        title.setSelected(true);
+        mTitleText.setVisibility(View.VISIBLE);
+        mTitleText.setText(titleText);
+        mTitleText.setSelected(true);
 
         final CharSequence subtitleText = mBundle.getCharSequence(BiometricPrompt.KEY_SUBTITLE);
         if (TextUtils.isEmpty(subtitleText)) {
-            subtitle.setVisibility(View.GONE);
+            mSubtitleText.setVisibility(View.GONE);
         } else {
-            subtitle.setVisibility(View.VISIBLE);
-            subtitle.setText(subtitleText);
+            mSubtitleText.setVisibility(View.VISIBLE);
+            mSubtitleText.setText(subtitleText);
         }
 
         final CharSequence descriptionText =
                 mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION);
         if (TextUtils.isEmpty(descriptionText)) {
-            description.setVisibility(View.GONE);
+            mDescriptionText.setVisibility(View.GONE);
         } else {
-            description.setVisibility(View.VISIBLE);
-            description.setText(descriptionText);
+            mDescriptionText.setVisibility(View.VISIBLE);
+            mDescriptionText.setText(descriptionText);
         }
 
-        negative.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
-
-        showTryAgainButton(mPendingShowTryAgain);
-        showConfirmationButton(mPendingShowConfirm);
+        mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
 
         if (mWasForceRemoved || mSkipIntro) {
             // Show the dialog immediately
@@ -280,10 +305,31 @@
         mSkipIntro = false;
     }
 
+    protected void updateIcon(int lastState, int newState) {
+        final Drawable icon = getAnimationForTransition(lastState, newState);
+        if (icon == null) {
+            Log.e(TAG, "Animation not found");
+            return;
+        }
+
+        final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
+                ? (AnimatedVectorDrawable) icon
+                : null;
+
+        mBiometricIcon.setImageDrawable(icon);
+
+        if (animation != null && shouldAnimateForTransition(lastState, newState)) {
+            animation.forceAnimationOnUI();
+            animation.start();
+        }
+    }
+
     private void setDismissesDialog(View v) {
         v.setClickable(true);
         v.setOnTouchListener((View view, MotionEvent event) -> {
-            mCallback.onUserCanceled();
+            if (mLastState != STATE_AUTHENTICATED && shouldGrayAreaDismissDialog()) {
+                mCallback.onUserCanceled();
+            }
             return true;
         });
     }
@@ -298,10 +344,9 @@
                 mWindowManager.removeView(BiometricDialogView.this);
                 mAnimatingAway = false;
                 // Set the icons / text back to normal state
-                handleClearMessage();
+                handleClearMessage(false /* requireTryAgain */);
                 showTryAgainButton(false /* show */);
-                mPendingShowTryAgain = false;
-                mPendingShowConfirm = false;
+                updateState(STATE_IDLE);
             }
         };
 
@@ -362,11 +407,11 @@
     }
 
     public void showConfirmationButton(boolean show) {
-        final Button positive = mLayout.findViewById(R.id.button1);
         if (show) {
-            positive.setVisibility(View.VISIBLE);
+            updateState(STATE_PENDING_CONFIRMATION);
+            mPositiveButton.setVisibility(View.VISIBLE);
         } else {
-            positive.setVisibility(View.GONE);
+            mPositiveButton.setVisibility(View.GONE);
         }
     }
 
@@ -378,61 +423,51 @@
         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) {
+    private void showTemporaryMessage(String message, boolean requireTryAgain) {
         mHandler.removeMessages(MSG_CLEAR_MESSAGE);
         updateState(STATE_ERROR);
         mErrorText.setText(message);
         mErrorText.setTextColor(mErrorColor);
         mErrorText.setContentDescription(message);
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_MESSAGE),
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_MESSAGE, requireTryAgain),
                 BiometricPrompt.HIDE_DIALOG_DELAY);
     }
 
     public void clearTemporaryMessage() {
         mHandler.removeMessages(MSG_CLEAR_MESSAGE);
-        mHandler.obtainMessage(MSG_CLEAR_MESSAGE).sendToTarget();
+        mHandler.obtainMessage(MSG_CLEAR_MESSAGE, false /* requireTryAgain */).sendToTarget();
     }
 
-    public void showHelpMessage(String message) {
-        showTemporaryMessage(message);
+    public void showHelpMessage(String message, boolean requireTryAgain) {
+        showTemporaryMessage(message, requireTryAgain);
     }
 
     public void showErrorMessage(String error) {
-        showTemporaryMessage(error);
+        showTemporaryMessage(error, false /* requireTryAgain */);
         showTryAgainButton(false /* show */);
         mCallback.onErrorShown();
     }
 
-    private void updateState(int newState) {
+    public void updateState(int newState) {
+        if (newState == STATE_PENDING_CONFIRMATION) {
+            mErrorText.setVisibility(View.INVISIBLE);
+        } else if (newState == STATE_AUTHENTICATED) {
+            mPositiveButton.setVisibility(View.GONE);
+            mNegativeButton.setVisibility(View.GONE);
+            mErrorText.setVisibility(View.INVISIBLE);
+        }
+
         updateIcon(mLastState, newState);
         mLastState = newState;
     }
 
     public void showTryAgainButton(boolean show) {
-        final Button tryAgain = mLayout.findViewById(R.id.button_try_again);
-        if (show) {
-            tryAgain.setVisibility(View.VISIBLE);
-        } else {
-            tryAgain.setVisibility(View.GONE);
-        }
     }
 
-    // Set the state before the window is attached, so we know if the dialog should be started
-    // with or without the button. This is because there's no good onPause signal
-    public void setPendingTryAgain(boolean show) {
-        mPendingShowTryAgain = show;
-    }
-
-    public void setPendingConfirm(boolean show) {
-        mPendingShowConfirm = show;
+    public void restoreState(Bundle bundle) {
+        mTryAgainButton.setVisibility(bundle.getInt(KEY_TRY_AGAIN_VISIBILITY));
+        mPositiveButton.setVisibility(bundle.getInt(KEY_CONFIRM_VISIBILITY));
     }
 
     public WindowManager.LayoutParams getLayoutParams() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
index feef3a6d..9fba44b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
@@ -16,23 +16,285 @@
 
 package com.android.systemui.biometrics;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.graphics.Outline;
 import android.graphics.drawable.Drawable;
-import android.widget.ImageView;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.ViewOutlineProvider;
 
 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,
+ * Application Icon, Title, Subtitle, Description, Biometric Icon, Error/Help message area,
  * and positive/negative buttons.
  */
 public class FaceDialogView extends BiometricDialogView {
+
+    private static final String TAG = "FaceDialogView";
+    private static final String KEY_DIALOG_SIZE = "key_dialog_size";
+
+    private static final int HIDE_DIALOG_DELAY = 500; // ms
+    private static final int IMPLICIT_Y_PADDING = 16; // dp
+    private static final int GROW_DURATION = 150; // ms
+    private static final int TEXT_ANIMATE_DISTANCE = 32; // dp
+
+    private static final int SIZE_UNKNOWN = 0;
+    private static final int SIZE_SMALL = 1;
+    private static final int SIZE_GROWING = 2;
+    private static final int SIZE_BIG = 3;
+
+    private int mSize;
+    private float mIconOriginalY;
+    private DialogOutlineProvider mOutlineProvider = new DialogOutlineProvider();
+
+    private final class DialogOutlineProvider extends ViewOutlineProvider {
+
+        float mY;
+
+        @Override
+        public void getOutline(View view, Outline outline) {
+            outline.setRoundRect(
+                    0 /* left */,
+                    (int) mY, /* top */
+                    mDialog.getWidth() /* right */,
+                    mDialog.getBottom(), /* bottom */
+                    getResources().getDimension(R.dimen.biometric_dialog_corner_size));
+        }
+
+        int calculateSmall() {
+            final float padding = dpToPixels(IMPLICIT_Y_PADDING);
+            return mDialog.getHeight() - mBiometricIcon.getHeight() - 2 * (int) padding;
+        }
+
+        void setOutlineY(float y) {
+            mY = y;
+        }
+    }
+
     public FaceDialogView(Context context,
             DialogViewCallback callback) {
         super(context, callback);
     }
 
+    private void updateSize(int newSize) {
+        final float padding = dpToPixels(IMPLICIT_Y_PADDING);
+        final float iconSmallPositionY = mDialog.getHeight() - mBiometricIcon.getHeight() - padding;
+
+        if (newSize == SIZE_SMALL) {
+            // These fields are required and/or always hold a spot on the UI, so should be set to
+            // INVISIBLE so they keep their position
+            mTitleText.setVisibility(View.INVISIBLE);
+            mErrorText.setVisibility(View.INVISIBLE);
+            mNegativeButton.setVisibility(View.INVISIBLE);
+
+            // These fields are optional, so set them to gone or invisible depending on their
+            // usage. If they're empty, they're already set to GONE in BiometricDialogView.
+            if (!TextUtils.isEmpty(mSubtitleText.getText())) {
+                mSubtitleText.setVisibility(View.INVISIBLE);
+            }
+            if (!TextUtils.isEmpty(mDescriptionText.getText())) {
+                mDescriptionText.setVisibility(View.INVISIBLE);
+            }
+
+            // Move the biometric icon to the small spot
+            mBiometricIcon.setY(iconSmallPositionY);
+
+            // Clip the dialog to the small size
+            mDialog.setOutlineProvider(mOutlineProvider);
+            mOutlineProvider.setOutlineY(mOutlineProvider.calculateSmall());
+
+            mDialog.setClipToOutline(true);
+            mDialog.invalidateOutline();
+
+            mSize = newSize;
+        } else if (mSize == SIZE_SMALL && newSize == SIZE_BIG) {
+            mSize = SIZE_GROWING;
+
+            // Animate the outline
+            final ValueAnimator outlineAnimator =
+                    ValueAnimator.ofFloat(mOutlineProvider.calculateSmall(), 0);
+            outlineAnimator.addUpdateListener((animation) -> {
+                final float y = (float) animation.getAnimatedValue();
+                mOutlineProvider.setOutlineY(y);
+                mDialog.invalidateOutline();
+            });
+
+            // Animate the icon back to original big position
+            final ValueAnimator iconAnimator =
+                    ValueAnimator.ofFloat(iconSmallPositionY, mIconOriginalY);
+            iconAnimator.addUpdateListener((animation) -> {
+                final float y = (float) animation.getAnimatedValue();
+                mBiometricIcon.setY(y);
+            });
+
+            // Animate the error text so it slides up with the icon
+            final ValueAnimator textSlideAnimator =
+                    ValueAnimator.ofFloat(dpToPixels(TEXT_ANIMATE_DISTANCE), 0);
+            textSlideAnimator.addUpdateListener((animation) -> {
+                final float y = (float) animation.getAnimatedValue();
+                mErrorText.setTranslationY(y);
+            });
+
+            // Opacity animator for things that should fade in (title, subtitle, details, negative
+            // button)
+            final ValueAnimator opacityAnimator = ValueAnimator.ofFloat(0, 1);
+            opacityAnimator.addUpdateListener((animation) -> {
+                final float opacity = (float) animation.getAnimatedValue();
+
+                // These fields are required and/or always hold a spot on the UI
+                mTitleText.setAlpha(opacity);
+                mErrorText.setAlpha(opacity);
+                mNegativeButton.setAlpha(opacity);
+                mTryAgainButton.setAlpha(opacity);
+
+                // These fields are optional, so only animate them if they're supposed to be showing
+                if (!TextUtils.isEmpty(mSubtitleText.getText())) {
+                    mSubtitleText.setAlpha(opacity);
+                }
+                if (!TextUtils.isEmpty(mDescriptionText.getText())) {
+                    mDescriptionText.setAlpha(opacity);
+                }
+            });
+
+            // Choreograph together
+            final AnimatorSet as = new AnimatorSet();
+            as.setDuration(GROW_DURATION);
+            as.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    super.onAnimationStart(animation);
+                    // Set the visibility of opacity-animating views back to VISIBLE
+                    mTitleText.setVisibility(View.VISIBLE);
+                    mErrorText.setVisibility(View.VISIBLE);
+                    mNegativeButton.setVisibility(View.VISIBLE);
+                    mTryAgainButton.setVisibility(View.VISIBLE);
+
+                    if (!TextUtils.isEmpty(mSubtitleText.getText())) {
+                        mSubtitleText.setVisibility(View.VISIBLE);
+                    }
+                    if (!TextUtils.isEmpty(mDescriptionText.getText())) {
+                        mDescriptionText.setVisibility(View.VISIBLE);
+                    }
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    super.onAnimationEnd(animation);
+                    mSize = SIZE_BIG;
+                }
+            });
+            as.play(outlineAnimator).with(iconAnimator).with(opacityAnimator)
+                    .with(textSlideAnimator);
+            as.start();
+        } else if (mSize == SIZE_BIG) {
+            mDialog.setClipToOutline(false);
+            mDialog.invalidateOutline();
+
+            mBiometricIcon.setY(mIconOriginalY);
+
+            mSize = newSize;
+        }
+    }
+
+    @Override
+    public void onSaveState(Bundle bundle) {
+        super.onSaveState(bundle);
+        bundle.putInt(KEY_DIALOG_SIZE, mSize);
+    }
+
+
+    @Override
+    protected void handleClearMessage(boolean requireTryAgain) {
+        // Clears the temporary message and shows the help message. If requireTryAgain is true,
+        // we will start the authenticating state again.
+        if (!requireTryAgain) {
+            updateState(STATE_AUTHENTICATING);
+            mErrorText.setText(getHintStringResourceId());
+            mErrorText.setTextColor(mTextColor);
+            mErrorText.setVisibility(View.VISIBLE);
+        } else {
+            updateState(STATE_IDLE);
+            mErrorText.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    @Override
+    public void restoreState(Bundle bundle) {
+        super.restoreState(bundle);
+        // Keep in mind that this happens before onAttachedToWindow()
+        mSize = bundle.getInt(KEY_DIALOG_SIZE);
+    }
+
+    /**
+     * Do small/big layout here instead of onAttachedToWindow, since:
+     * 1) We need the big layout to be measured, etc for small -> big animation
+     * 2) We need the dialog measurements to know where to move the biometric icon to
+     *
+     * BiometricDialogView already sets the views to their default big state, so here we only
+     * need to hide the ones that are unnecessary.
+     */
+    @Override
+    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        if (mIconOriginalY == 0) {
+            mIconOriginalY = mBiometricIcon.getY();
+        }
+
+        // UNKNOWN means size hasn't been set yet. First time we create the dialog.
+        // onLayout can happen when visibility of views change (during animation, etc).
+        if (mSize != SIZE_UNKNOWN) {
+            // Probably not the cleanest way to do this, but since dialog is big by default,
+            // and small dialogs can persist across orientation changes, we need to set it to
+            // small size here again.
+            if (mSize == SIZE_SMALL) {
+                updateSize(SIZE_SMALL);
+            }
+            return;
+        }
+
+        // If we don't require confirmation, show the small dialog first (until errors occur).
+        if (!requiresConfirmation()) {
+            updateSize(SIZE_SMALL);
+        } else {
+            updateSize(SIZE_BIG);
+        }
+    }
+
+    @Override
+    public void showErrorMessage(String error) {
+        super.showErrorMessage(error);
+
+        // All error messages will cause the dialog to go from small -> big. Error messages
+        // are messages such as lockout, auth failed, etc.
+        if (mSize == SIZE_SMALL) {
+            updateSize(SIZE_BIG);
+        }
+    }
+
+    @Override
+    public void showTryAgainButton(boolean show) {
+        if (show && mSize == SIZE_SMALL) {
+            // Do not call super, we will nicely animate the alpha together with the rest
+            // of the elements in here.
+            updateSize(SIZE_BIG);
+        } else {
+            if (show) {
+                mTryAgainButton.setVisibility(View.VISIBLE);
+            } else {
+                mTryAgainButton.setVisibility(View.GONE);
+            }
+        }
+    }
+
     @Override
     protected int getHintStringResourceId() {
         return R.string.face_dialog_looking_for_face;
@@ -53,10 +315,68 @@
     }
 
     @Override
-    protected void updateIcon(int lastState, int newState) {
-        Drawable icon = mContext.getDrawable(R.drawable.face_dialog_icon);
+    protected boolean shouldAnimateForTransition(int oldState, int newState) {
+        if (oldState == STATE_ERROR && newState == STATE_IDLE) {
+            return true;
+        } else if (oldState == STATE_IDLE && newState == STATE_AUTHENTICATING) {
+            return false;
+        } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
+            return true;
+        } else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATING) {
+            return true;
+        } else if (oldState == STATE_AUTHENTICATING && newState == STATE_PENDING_CONFIRMATION) {
+            return true;
+        } else if (oldState == STATE_PENDING_CONFIRMATION && newState == STATE_AUTHENTICATED) {
+            return true;
+        } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) {
+            return true;
+        }
+        return false;
+    }
 
-        final ImageView faceIcon = getLayout().findViewById(R.id.biometric_icon);
-        faceIcon.setImageDrawable(icon);
+    @Override
+    protected int getDelayAfterAuthenticatedDurationMs() {
+        return HIDE_DIALOG_DELAY;
+    }
+
+    @Override
+    protected boolean shouldGrayAreaDismissDialog() {
+        if (mSize == SIZE_SMALL) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    protected Drawable getAnimationForTransition(int oldState, int newState) {
+        int iconRes;
+        if (oldState == STATE_ERROR && newState == STATE_IDLE) {
+            iconRes = R.drawable.face_dialog_error_to_face;
+        } else if (oldState == STATE_IDLE && newState == STATE_AUTHENTICATING) {
+            iconRes = R.drawable.face_dialog_face_to_error;
+        } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
+            iconRes = R.drawable.face_dialog_face_to_error;
+        } else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATING) {
+            iconRes = R.drawable.face_dialog_error_to_face;
+        } else if (oldState == STATE_AUTHENTICATING && newState == STATE_PENDING_CONFIRMATION) {
+            iconRes = R.drawable.face_dialog_face_gray_to_face_blue;
+        } else if (oldState == STATE_PENDING_CONFIRMATION && newState == STATE_AUTHENTICATED) {
+            iconRes = R.drawable.face_dialog_face_blue_to_checkmark;
+        } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) {
+            iconRes = R.drawable.face_dialog_face_gray_to_checkmark;
+        } else {
+            return null;
+        }
+        return mContext.getDrawable(iconRes);
+    }
+
+    private float dpToPixels(float dp) {
+        return dp * ((float) mContext.getResources().getDisplayMetrics().densityDpi
+                / DisplayMetrics.DENSITY_DEFAULT);
+    }
+
+    private float pixelsToDp(float pixels) {
+        return pixels / ((float) mContext.getResources().getDisplayMetrics().densityDpi
+                / DisplayMetrics.DENSITY_DEFAULT);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
index 38a69a9..c9b30ba 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
@@ -17,20 +17,28 @@
 package com.android.systemui.biometrics;
 
 import android.content.Context;
-import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
-import android.util.Log;
-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,
+ * Application Icon, Title, Subtitle, Description, Biometric Icon, Error/Help message area,
  * and positive/negative buttons.
  */
 public class FingerprintDialogView extends BiometricDialogView {
-    private static final String TAG = "FingerprintDialogView";
+
+    public FingerprintDialogView(Context context,
+            DialogViewCallback callback) {
+        super(context, callback);
+    }
+
+    @Override
+    protected void handleClearMessage(boolean requireTryAgain) {
+        updateState(STATE_AUTHENTICATING);
+        mErrorText.setText(getHintStringResourceId());
+        mErrorText.setTextColor(mTextColor);
+    }
 
     @Override
     protected int getHintStringResourceId() {
@@ -48,34 +56,8 @@
     }
 
     @Override
-    protected void updateIcon(int lastState, int newState) {
-        Drawable icon = getAnimationForTransition(lastState, newState);
-
-        if (icon == null) {
-            Log.e(TAG, "Animation not found");
-            return;
-        }
-
-        final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
-                ? (AnimatedVectorDrawable) icon
-                : null;
-
-        final ImageView fingerprintIcon = getLayout().findViewById(R.id.biometric_icon);
-        fingerprintIcon.setImageDrawable(icon);
-
-        if (animation != null && shouldAnimateForTransition(lastState, newState)) {
-            animation.forceAnimationOnUI();
-            animation.start();
-        }
-    }
-
-    public FingerprintDialogView(Context context,
-            DialogViewCallback callback) {
-        super(context, callback);
-    }
-
-    private boolean shouldAnimateForTransition(int oldState, int newState) {
-        if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
+    protected boolean shouldAnimateForTransition(int oldState, int newState) {
+        if (oldState == STATE_IDLE && newState == STATE_AUTHENTICATING) {
             return false;
         } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
             return true;
@@ -88,9 +70,21 @@
         return false;
     }
 
-    private Drawable getAnimationForTransition(int oldState, int newState) {
+    @Override
+    protected int getDelayAfterAuthenticatedDurationMs() {
+        return 0;
+    }
+
+    @Override
+    protected boolean shouldGrayAreaDismissDialog() {
+        // Fingerprint dialog always dismisses when region outside the dialog is tapped
+        return true;
+    }
+
+    @Override
+    protected Drawable getAnimationForTransition(int oldState, int newState) {
         int iconRes;
-        if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
+        if (oldState == STATE_IDLE && newState == STATE_AUTHENTICATING) {
             iconRes = R.drawable.fingerprint_dialog_fp_to_error;
         } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
             iconRes = R.drawable.fingerprint_dialog_fp_to_error;
@@ -98,7 +92,7 @@
             iconRes = R.drawable.fingerprint_dialog_error_to_fp;
         } 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;
+            iconRes = R.drawable.fingerprint_dialog_fp_to_error;
         } else {
             return null;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BadgeRenderer.java b/packages/SystemUI/src/com/android/systemui/bubbles/BadgeRenderer.java
new file mode 100644
index 0000000..845b084
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BadgeRenderer.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 com.android.systemui.bubbles;
+
+import static android.graphics.Paint.ANTI_ALIAS_FLAG;
+import static android.graphics.Paint.FILTER_BITMAP_FLAG;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.Log;
+
+// XXX: Mostly opied from launcher code / can we share?
+/**
+ * Contains parameters necessary to draw a badge for an icon (e.g. the size of the badge).
+ */
+public class BadgeRenderer {
+
+    private static final String TAG = "BadgeRenderer";
+
+    // The badge sizes are defined as percentages of the app icon size.
+    private static final float SIZE_PERCENTAGE = 0.38f;
+
+    // Extra scale down of the dot
+    private static final float DOT_SCALE = 0.6f;
+
+    private final float mDotCenterOffset;
+    private final float mCircleRadius;
+    private final Paint mCirclePaint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG);
+
+    public BadgeRenderer(int iconSizePx) {
+        mDotCenterOffset = SIZE_PERCENTAGE * iconSizePx;
+        int size = (int) (DOT_SCALE * mDotCenterOffset);
+        mCircleRadius = size / 2f;
+    }
+
+    /**
+     * Draw a circle in the top right corner of the given bounds.
+     *
+     * @param color The color (based on the icon) to use for the badge.
+     * @param iconBounds The bounds of the icon being badged.
+     * @param badgeScale The progress of the animation, from 0 to 1.
+     * @param spaceForOffset How much space to offset the badge up and to the left or right.
+     * @param onLeft Whether the badge should be draw on left or right side.
+     */
+    public void draw(Canvas canvas, int color, Rect iconBounds, float badgeScale,
+            Point spaceForOffset, boolean onLeft) {
+        if (iconBounds == null) {
+            Log.e(TAG, "Invalid null argument(s) passed in call to draw.");
+            return;
+        }
+        canvas.save();
+        // We draw the badge relative to its center.
+        int x = onLeft ? iconBounds.left : iconBounds.right;
+        float offset = onLeft ? (mDotCenterOffset / 2) : -(mDotCenterOffset / 2);
+        float badgeCenterX = x + offset;
+        float badgeCenterY = iconBounds.top + mDotCenterOffset / 2;
+
+        canvas.translate(badgeCenterX + spaceForOffset.x, badgeCenterY - spaceForOffset.y);
+
+        canvas.scale(badgeScale, badgeScale);
+        mCirclePaint.setColor(color);
+        canvas.drawCircle(0, 0, mCircleRadius, mCirclePaint);
+        canvas.restore();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
new file mode 100644
index 0000000..92d3cc1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.bubbles;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+/**
+ * View that circle crops its contents and supports displaying a coloured dot on a top corner.
+ */
+public class BadgedImageView extends ImageView {
+
+    private BadgeRenderer mDotRenderer;
+    private int mIconSize;
+    private Rect mTempBounds = new Rect();
+    private Point mTempPoint = new Point();
+    private Path mClipPath = new Path();
+
+    private float mDotScale = 0f;
+    private int mUpdateDotColor;
+    private boolean mShowUpdateDot;
+    private boolean mOnLeft;
+
+    public BadgedImageView(Context context) {
+        this(context, null);
+    }
+
+    public BadgedImageView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        setScaleType(ScaleType.CENTER_CROP);
+        mIconSize = getResources().getDimensionPixelSize(R.dimen.bubble_size);
+        mDotRenderer = new BadgeRenderer(mIconSize);
+    }
+
+    // TODO: Clipping oval path isn't great: rerender image into a separate, rounded bitmap and
+    // then draw would be better
+    @Override
+    public void onDraw(Canvas canvas) {
+        canvas.save();
+        // Circle crop
+        mClipPath.addOval(getPaddingStart(), getPaddingTop(),
+                getWidth() - getPaddingEnd(), getHeight() - getPaddingBottom(), Path.Direction.CW);
+        canvas.clipPath(mClipPath);
+        super.onDraw(canvas);
+
+        // After we've circle cropped what we're showing, restore so we don't clip the badge
+        canvas.restore();
+
+        // Draw the badge
+        if (mShowUpdateDot) {
+            getDrawingRect(mTempBounds);
+            mTempPoint.set((getWidth() - mIconSize) / 2, getPaddingTop());
+            mDotRenderer.draw(canvas, mUpdateDotColor, mTempBounds, mDotScale, mTempPoint,
+                    mOnLeft);
+        }
+    }
+
+    /**
+     * Set whether the dot should appear on left or right side of the view.
+     */
+    public void setDotPosition(boolean onLeft) {
+        mOnLeft = onLeft;
+        invalidate();
+    }
+
+    /**
+     * Set whether the dot should show or not.
+     */
+    public void setShowDot(boolean showBadge) {
+        mShowUpdateDot = showBadge;
+        invalidate();
+    }
+
+    /**
+     * @return whether the dot is being displayed.
+     */
+    public boolean isShowingDot() {
+        return mShowUpdateDot;
+    }
+
+    /**
+     * The colour to use for the dot.
+     */
+    public void setDotColor(int color) {
+        mUpdateDotColor = color;
+        invalidate();
+    }
+
+    /**
+     * How big the dot should be, fraction from 0 to 1.
+     */
+    public void setDotScale(float fraction) {
+        mDotScale = fraction;
+        invalidate();
+    }
+
+    public float getDotScale() {
+        return mDotScale;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 881aa18..a457dee 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -21,25 +21,42 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
 import static com.android.systemui.bubbles.BubbleMovementHelper.EDGE_OVERLAP;
+import static com.android.systemui.statusbar.StatusBarState.SHADE;
+import static com.android.systemui.statusbar.notification.NotificationAlertingManager.alertAgain;
 
+import android.annotation.Nullable;
+import android.app.INotificationManager;
 import android.app.Notification;
+import android.app.PendingIntent;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.view.LayoutInflater;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.NotificationInflater;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -57,47 +74,38 @@
     private static final String TAG = "BubbleController";
 
     // Enables some subset of notifs to automatically become bubbles
-    public static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false;
-    // When a bubble is dismissed, recreate it as a notification
-    public static final boolean DEBUG_DEMOTE_TO_NOTIF = false;
+    private static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false;
 
     // Secure settings
     private static final String ENABLE_AUTO_BUBBLE_MESSAGES = "experiment_autobubble_messaging";
     private static final String ENABLE_AUTO_BUBBLE_ONGOING = "experiment_autobubble_ongoing";
     private static final String ENABLE_AUTO_BUBBLE_ALL = "experiment_autobubble_all";
+    private static final String ENABLE_BUBBLE_ACTIVITY_VIEW = "experiment_bubble_activity_view";
+    private static final String ENABLE_BUBBLE_CONTENT_INTENT = "experiment_bubble_content_intent";
 
-    private Context mContext;
-    private BubbleDismissListener mDismissListener;
+    private final Context mContext;
+    private final NotificationEntryManager mNotificationEntryManager;
     private BubbleStateChangeListener mStateChangeListener;
     private BubbleExpandListener mExpandListener;
+    private LayoutInflater mInflater;
 
-    private Map<String, BubbleView> mBubbles = new HashMap<>();
+    private final Map<String, BubbleView> mBubbles = new HashMap<>();
     private BubbleStackView mStackView;
-    private Point mDisplaySize;
+    private final Point mDisplaySize;
 
     // Bubbles get added to the status bar view
-    @VisibleForTesting
-    protected StatusBarWindowController mStatusBarWindowController;
+    private final StatusBarWindowController mStatusBarWindowController;
+    private StatusBarStateListener mStatusBarStateListener;
+
+    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
+            Dependency.get(NotificationInterruptionStateProvider.class);
+
+    private INotificationManager mNotificationManagerService;
 
     // Used for determining view rect for touch interaction
     private Rect mTempRect = new Rect();
 
     /**
-     * Listener to find out about bubble / bubble stack dismissal events.
-     */
-    public interface BubbleDismissListener {
-        /**
-         * Called when the entire stack of bubbles is dismissed by the user.
-         */
-        void onStackDismissed();
-
-        /**
-         * Called when a specific bubble is dismissed by the user.
-         */
-        void onBubbleDismissed(String key);
-    }
-
-    /**
      * Listener to be notified when some states of the bubbles change.
      */
     public interface BubbleStateChangeListener {
@@ -113,11 +121,30 @@
     public interface BubbleExpandListener {
         /**
          * Called when the expansion state of the bubble stack changes.
-         *
          * @param isExpanding whether it's expanding or collapsing
-         * @param amount fraction of how expanded or collapsed it is, 1 being fully, 0 at the start
+         * @param key the notification key associated with bubble being expanded
          */
-        void onBubbleExpandChanged(boolean isExpanding, float amount);
+        void onBubbleExpandChanged(boolean isExpanding, String key);
+    }
+
+    /**
+     * Listens for the current state of the status bar and updates the visibility state
+     * of bubbles as needed.
+     */
+    private class StatusBarStateListener implements StatusBarStateController.StateListener {
+        private int mState;
+        /**
+         * Returns the current status bar state.
+         */
+        public int getCurrentState() {
+            return mState;
+        }
+
+        @Override
+        public void onStateChanged(int newState) {
+            mState = newState;
+            updateVisibility();
+        }
     }
 
     @Inject
@@ -126,14 +153,21 @@
         WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         mDisplaySize = new Point();
         wm.getDefaultDisplay().getSize(mDisplaySize);
-        mStatusBarWindowController = statusBarWindowController;
-    }
+        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
-    /**
-     * Set a listener to be notified of bubble dismissal events.
-     */
-    public void setDismissListener(BubbleDismissListener listener) {
-        mDismissListener = listener;
+        mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
+        mNotificationEntryManager.addNotificationEntryListener(mEntryListener);
+
+        try {
+            mNotificationManagerService = INotificationManager.Stub.asInterface(
+                    ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE));
+        } catch (ServiceManager.ServiceNotFoundException e) {
+            e.printStackTrace();
+        }
+
+        mStatusBarWindowController = statusBarWindowController;
+        mStatusBarStateListener = new StatusBarStateListener();
+        Dependency.get(StatusBarStateController.class).addCallback(mStatusBarStateListener);
     }
 
     /**
@@ -158,7 +192,12 @@
      * screen (e.g. if on AOD).
      */
     public boolean hasBubbles() {
-        return mBubbles.size() > 0;
+        for (BubbleView bv : mBubbles.values()) {
+            if (!bv.getEntry().isBubbleDismissed()) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -173,43 +212,43 @@
      */
     public void collapseStack() {
         if (mStackView != null) {
-            mStackView.animateExpansion(false);
+            mStackView.collapseStack();
         }
     }
 
     /**
      * Tell the stack of bubbles to be dismissed, this will remove all of the bubbles in the stack.
      */
-    public void dismissStack() {
+    void dismissStack() {
         if (mStackView == null) {
             return;
         }
-        Point startPoint = getStartPoint(mStackView.getStackWidth(), mDisplaySize);
+        Set<String> keys = mBubbles.keySet();
+        for (String key: keys) {
+            mBubbles.get(key).getEntry().setBubbleDismissed(true);
+        }
+        mStackView.stackDismissed();
+
         // Reset the position of the stack (TODO - or should we save / respect last user position?)
+        Point startPoint = getStartPoint(mStackView.getStackWidth(), mDisplaySize);
         mStackView.setPosition(startPoint.x, startPoint.y);
-        for (String key: mBubbles.keySet()) {
-            removeBubble(key);
-        }
-        if (mDismissListener != null) {
-            mDismissListener.onStackDismissed();
-        }
-        updateBubblesShowing();
+
+        updateVisibility();
+        mNotificationEntryManager.updateNotifications();
     }
 
     /**
-     * Adds a bubble associated with the provided notification entry or updates it if it exists.
+     * Adds or updates a bubble associated with the provided notification entry.
+     *
+     * @param notif the notification associated with this bubble.
+     * @param updatePosition whether this update should promote the bubble to the top of the stack.
      */
-    public void addBubble(NotificationData.Entry notif) {
+    public void updateBubble(NotificationEntry notif, boolean updatePosition) {
         if (mBubbles.containsKey(notif.key)) {
             // It's an update
             BubbleView bubble = mBubbles.get(notif.key);
-            mStackView.updateBubble(bubble, notif);
+            mStackView.updateBubble(bubble, notif, updatePosition);
         } else {
-            // It's new
-            BubbleView bubble = new BubbleView(mContext);
-            bubble.setNotif(notif);
-            mBubbles.put(bubble.getKey(), bubble);
-
             boolean setPosition = mStackView != null && mStackView.getVisibility() != VISIBLE;
             if (mStackView == null) {
                 setPosition = true;
@@ -224,75 +263,135 @@
                     mStackView.setExpandListener(mExpandListener);
                 }
             }
+            // It's new
+            BubbleView bubble = (BubbleView) mInflater.inflate(
+                    R.layout.bubble_view, mStackView, false /* attachToRoot */);
+            bubble.setNotif(notif);
+            PendingIntent bubbleIntent = getValidBubbleIntent(notif);
+            if (shouldUseActivityView(mContext) || bubbleIntent != null) {
+                bubble.setBubbleIntent(getValidBubbleIntent(notif));
+            }
+            mBubbles.put(bubble.getKey(), bubble);
             mStackView.addBubble(bubble);
             if (setPosition) {
                 // Need to add the bubble to the stack before we can know the width
                 Point startPoint = getStartPoint(mStackView.getStackWidth(), mDisplaySize);
                 mStackView.setPosition(startPoint.x, startPoint.y);
-                mStackView.setVisibility(VISIBLE);
             }
-            updateBubblesShowing();
         }
+        updateVisibility();
+    }
+
+    @Nullable
+    private PendingIntent getValidBubbleIntent(NotificationEntry notif) {
+        Notification notification = notif.notification.getNotification();
+        if (canLaunchInActivityView(notification.getBubbleMetadata() != null
+                ? notification.getBubbleMetadata().getIntent() : null)) {
+            return notification.getBubbleMetadata().getIntent();
+        } else if (shouldUseContentIntent(mContext)
+                && canLaunchInActivityView(notification.contentIntent)) {
+            Log.d(TAG, "[addBubble " + notif.key
+                    + "]: No appOverlayIntent, using contentIntent.");
+            return notification.contentIntent;
+        }
+        Log.d(TAG, "[addBubble " + notif.key + "]: No supported intent for ActivityView.");
+        return null;
     }
 
     /**
      * Removes the bubble associated with the {@param uri}.
      */
-    public void removeBubble(String key) {
-        BubbleView bv = mBubbles.get(key);
+    void removeBubble(String key) {
+        BubbleView bv = mBubbles.remove(key);
         if (mStackView != null && bv != null) {
             mStackView.removeBubble(bv);
-            bv.getEntry().setBubbleDismissed(true);
+            bv.destroyActivityView(mStackView);
         }
-        if (mDismissListener != null) {
-            mDismissListener.onBubbleDismissed(key);
+
+        NotificationEntry entry = bv != null ? bv.getEntry() : null;
+        if (entry != null) {
+            entry.setBubbleDismissed(true);
+            mNotificationEntryManager.updateNotifications();
         }
-        updateBubblesShowing();
+        updateVisibility();
     }
 
-    private void updateBubblesShowing() {
-        boolean hasBubblesShowing = false;
-        for (BubbleView bv : mBubbles.values()) {
-            if (!bv.getEntry().isBubbleDismissed()) {
-                hasBubblesShowing = true;
-                break;
+    @SuppressWarnings("FieldCanBeLocal")
+    private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
+        @Override
+        public void onPendingEntryAdded(NotificationEntry entry) {
+            if (shouldAutoBubble(mContext, entry) || shouldBubble(entry)) {
+                // TODO: handle group summaries
+                // It's a new notif, it shows in the shade and as a bubble
+                entry.setIsBubble(true);
+                entry.setShowInShadeWhenBubble(true);
             }
         }
-        boolean hadBubbles = mStatusBarWindowController.getBubblesShowing();
-        mStatusBarWindowController.setBubblesShowing(hasBubblesShowing);
-        if (mStackView != null && !hasBubblesShowing) {
-            mStackView.setVisibility(INVISIBLE);
+
+        @Override
+        public void onEntryInflated(NotificationEntry entry,
+                @NotificationInflater.InflationFlag int inflatedFlags) {
+            if (entry.isBubble() && mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) {
+                updateBubble(entry, true /* updatePosition */);
+            }
         }
+
+        @Override
+        public void onPreEntryUpdated(NotificationEntry entry) {
+            if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
+                    && alertAgain(entry, entry.notification.getNotification())) {
+                entry.setShowInShadeWhenBubble(true);
+                entry.setBubbleDismissed(false); // updates come back as bubbles even if dismissed
+                if (mBubbles.containsKey(entry.key)) {
+                    mBubbles.get(entry.key).updateDotVisibility();
+                }
+                updateBubble(entry, true /* updatePosition */);
+            }
+        }
+
+        @Override
+        public void onEntryRemoved(NotificationEntry entry,
+                @Nullable NotificationVisibility visibility,
+                boolean removedByUser) {
+            entry.setShowInShadeWhenBubble(false);
+            if (mBubbles.containsKey(entry.key)) {
+                mBubbles.get(entry.key).updateDotVisibility();
+            }
+            if (!removedByUser) {
+                // This was a cancel so we should remove the bubble
+                removeBubble(entry.key);
+            }
+        }
+    };
+
+    /**
+     * Lets any listeners know if bubble state has changed.
+     */
+    private void updateBubblesShowing() {
+        if (mStackView == null) {
+            return;
+        }
+
+        boolean hadBubbles = mStatusBarWindowController.getBubblesShowing();
+        boolean hasBubblesShowing = hasBubbles() && mStackView.getVisibility() == VISIBLE;
+        mStatusBarWindowController.setBubblesShowing(hasBubblesShowing);
         if (mStateChangeListener != null && hadBubbles != hasBubblesShowing) {
             mStateChangeListener.onHasBubblesChanged(hasBubblesShowing);
         }
     }
 
     /**
-     * Sets the visibility of the bubbles, doesn't un-bubble them, just changes visibility.
+     * Updates the visibility of the bubbles based on current state.
+     * Does not un-bubble, just hides or un-hides. Will notify any
+     * {@link BubbleStateChangeListener}s if visibility changes.
      */
-    public void updateVisibility(boolean visible) {
-        if (mStackView == null) {
-            return;
-        }
-        ArrayList<BubbleView> viewsToRemove = new ArrayList<>();
-        for (BubbleView bv : mBubbles.values()) {
-            NotificationData.Entry entry = bv.getEntry();
-            if (entry != null) {
-                if (entry.isRowRemoved() || entry.isBubbleDismissed() || entry.isRowDismissed()) {
-                    viewsToRemove.add(bv);
-                }
-            }
-        }
-        for (BubbleView view : viewsToRemove) {
-            mBubbles.remove(view.getKey());
-            mStackView.removeBubble(view);
-        }
-        if (mStackView != null) {
-            mStackView.setVisibility(visible ? VISIBLE : INVISIBLE);
-            if (!visible) {
-                collapseStack();
-            }
+    public void updateVisibility() {
+        if (mStatusBarStateListener.getCurrentState() == SHADE && hasBubbles()) {
+            // Bubbles only appear in unlocked shade
+            mStackView.setVisibility(hasBubbles() ? VISIBLE : INVISIBLE);
+        } else if (mStackView != null) {
+            mStackView.setVisibility(INVISIBLE);
+            collapseStack();
         }
         updateBubblesShowing();
     }
@@ -308,8 +407,19 @@
         return mTempRect;
     }
 
+    private boolean canLaunchInActivityView(PendingIntent intent) {
+        if (intent == null) {
+            return false;
+        }
+        ActivityInfo info =
+                intent.getIntent().resolveActivityInfo(mContext.getPackageManager(), 0);
+        return info != null
+                && ActivityInfo.isResizeableMode(info.resizeMode)
+                && (info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) != 0;
+    }
+
     @VisibleForTesting
-    public BubbleStackView getStackView() {
+    BubbleStackView getStackView() {
         return mStackView;
     }
 
@@ -317,7 +427,7 @@
     /**
      * Gets an appropriate starting point to position the bubble stack.
      */
-    public static Point getStartPoint(int size, Point displaySize) {
+    private static Point getStartPoint(int size, Point displaySize) {
         final int x = displaySize.x - size + EDGE_OVERLAP;
         final int y = displaySize.y / 4;
         return new Point(x, y);
@@ -326,24 +436,48 @@
     /**
      * Gets an appropriate position for the bubble when the stack is expanded.
      */
-    public static Point getExpandPoint(BubbleStackView view, int size, Point displaySize) {
+    static Point getExpandPoint(BubbleStackView view, int size, Point displaySize) {
         // Same place for now..
         return new Point(EDGE_OVERLAP, size);
     }
 
     /**
-     * Whether the notification should bubble or not.
+     * Whether the notification has been developer configured to bubble and is allowed by the user.
      */
-    public static boolean shouldAutoBubble(Context context, NotificationData.Entry entry) {
+    private boolean shouldBubble(NotificationEntry entry) {
+        StatusBarNotification n = entry.notification;
+        boolean canAppOverlay = false;
+        try {
+            canAppOverlay = mNotificationManagerService.areBubblesAllowedForPackage(
+                    n.getPackageName(), n.getUid());
+        } catch (RemoteException e) {
+            Log.w(TAG, "Error calling NoMan to determine if app can overlay", e);
+        }
+
+        boolean canChannelOverlay = mNotificationEntryManager.getNotificationData().getChannel(
+                entry.key).canBubble();
+        boolean hasOverlayIntent = n.getNotification().getBubbleMetadata() != null
+                && n.getNotification().getBubbleMetadata().getIntent() != null;
+        return hasOverlayIntent && canChannelOverlay && canAppOverlay;
+    }
+
+    /**
+     * Whether the notification should bubble or not. Gated by debug flag.
+     * <p>
+     * If a notification has been set to bubble via proper bubble APIs or if it is an important
+     * message-like notification.
+     * </p>
+     */
+    private boolean shouldAutoBubble(Context context, NotificationEntry entry) {
         if (entry.isBubbleDismissed()) {
             return false;
         }
+        StatusBarNotification n = entry.notification;
 
         boolean autoBubbleMessages = shouldAutoBubbleMessages(context) || DEBUG_ENABLE_AUTO_BUBBLE;
         boolean autoBubbleOngoing = shouldAutoBubbleOngoing(context) || DEBUG_ENABLE_AUTO_BUBBLE;
         boolean autoBubbleAll = shouldAutoBubbleAll(context) || DEBUG_ENABLE_AUTO_BUBBLE;
 
-        StatusBarNotification n = entry.notification;
         boolean hasRemoteInput = false;
         if (n.getNotification().actions != null) {
             for (Notification.Action action : n.getNotification().actions) {
@@ -380,4 +514,14 @@
         return Settings.Secure.getInt(context.getContentResolver(),
                 ENABLE_AUTO_BUBBLE_ALL, 0) != 0;
     }
+
+    private static boolean shouldUseActivityView(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                ENABLE_BUBBLE_ACTIVITY_VIEW, 0) != 0;
+    }
+
+    private static boolean shouldUseContentIntent(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                ENABLE_BUBBLE_CONTENT_INTENT, 0) != 0;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java
index e28d96b..71ae1f8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java
@@ -21,9 +21,11 @@
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.drawable.ShapeDrawable;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import com.android.systemui.R;
 import com.android.systemui.recents.TriangleShape;
@@ -35,6 +37,8 @@
 
     // The triangle pointing to the expanded view
     private View mPointerView;
+    // The view displayed between the pointer and the expanded view
+    private TextView mHeaderView;
     // The view that is being displayed for the expanded state
     private View mExpandedView;
 
@@ -68,6 +72,7 @@
                 TriangleShape.create(width, height, true /* pointUp */));
         triangleDrawable.setTint(Color.WHITE); // TODO: dark mode
         mPointerView.setBackground(triangleDrawable);
+        mHeaderView = findViewById(R.id.bubble_content_header);
     }
 
     /**
@@ -80,9 +85,20 @@
     }
 
     /**
+     * Set the text displayed within the header.
+     */
+    public void setHeaderText(CharSequence text) {
+        mHeaderView.setText(text);
+        mHeaderView.setVisibility(TextUtils.isEmpty(text) ? GONE : VISIBLE);
+    }
+
+    /**
      * Set the view to display for the expanded state. Passing null will clear the view.
      */
     public void setExpandedView(View view) {
+        if (mExpandedView == view) {
+            return;
+        }
         if (mExpandedView != null) {
             removeView(mExpandedView);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index dfd18b2..dcd121b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -21,10 +21,13 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
+import android.app.ActivityView;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.RectF;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -35,12 +38,14 @@
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.OvershootInterpolator;
 import android.widget.FrameLayout;
+import android.widget.LinearLayout;
 
 import androidx.annotation.Nullable;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.ViewClippingUtil;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -50,6 +55,7 @@
  */
 public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.FloatingView {
 
+    private static final String TAG = "BubbleStackView";
     private Point mDisplaySize;
 
     private FrameLayout mBubbleContainer;
@@ -59,9 +65,10 @@
     private int mBubblePadding;
 
     private boolean mIsExpanded;
+    private int mExpandedBubbleHeight;
+    private BubbleTouchHandler mTouchHandler;
     private BubbleView mExpandedBubble;
     private Point mCollapsedPosition;
-    private BubbleTouchHandler mTouchHandler;
     private BubbleController.BubbleExpandListener mExpandListener;
 
     private boolean mViewUpdatedRequested = false;
@@ -106,6 +113,7 @@
         mBubbleSize = res.getDimensionPixelSize(R.dimen.bubble_size);
         mBubblePadding = res.getDimensionPixelSize(R.dimen.bubble_padding);
 
+        mExpandedBubbleHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
         mDisplaySize = new Point();
         WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         wm.getDefaultDisplay().getSize(mDisplaySize);
@@ -205,13 +213,37 @@
      */
     public void setExpandedBubble(BubbleView bubbleToExpand) {
         mExpandedBubble = bubbleToExpand;
+        boolean prevExpanded = mIsExpanded;
         mIsExpanded = true;
-        updateExpandedBubble();
-        requestUpdate();
+        if (!prevExpanded) {
+            // If we weren't previously expanded we should animate open.
+            animateExpansion(true /* expand */);
+        } else {
+            // If we were expanded just update the views
+            updateExpandedBubble();
+            requestUpdate();
+        }
+        mExpandedBubble.getEntry().setShowInShadeWhenBubble(false);
+        notifyExpansionChanged(mExpandedBubble, true /* expanded */);
     }
 
     /**
-     * Adds a bubble to the stack.
+     * Sets the entry that should be expanded and expands if needed.
+     */
+    @VisibleForTesting
+    public void setExpandedBubble(NotificationEntry entry) {
+        for (int i = 0; i < mBubbleContainer.getChildCount(); i++) {
+            BubbleView bv = (BubbleView) mBubbleContainer.getChildAt(i);
+            if (entry.equals(bv.getEntry())) {
+                setExpandedBubble(bv);
+            }
+        }
+    }
+
+    /**
+     * Adds a bubble to the top of the stack.
+     *
+     * @param bubbleView the view to add to the stack.
      */
     public void addBubble(BubbleView bubbleView) {
         mBubbleContainer.addView(bubbleView, 0,
@@ -228,17 +260,26 @@
         mBubbleContainer.removeView(bubbleView);
         boolean wasExpanded = mIsExpanded;
         int bubbleCount = mBubbleContainer.getChildCount();
-        if (bubbleView.equals(mExpandedBubble) && bubbleCount > 0) {
+        if (mIsExpanded && bubbleView.equals(mExpandedBubble) && bubbleCount > 0) {
             // If we have other bubbles and are expanded go to the next one or previous
             // if the bubble removed was last
             int nextIndex = bubbleCount > removedIndex ? removedIndex : bubbleCount - 1;
-            mExpandedBubble = (BubbleView) mBubbleContainer.getChildAt(nextIndex);
+            BubbleView expandedBubble = (BubbleView) mBubbleContainer.getChildAt(nextIndex);
+            setExpandedBubble(expandedBubble);
         }
         mIsExpanded = wasExpanded && mBubbleContainer.getChildCount() > 0;
-        requestUpdate();
-        if (wasExpanded && !mIsExpanded && mExpandListener != null) {
-            mExpandListener.onBubbleExpandChanged(mIsExpanded, 1 /* amount */);
+        if (wasExpanded != mIsExpanded) {
+            notifyExpansionChanged(mExpandedBubble, mIsExpanded);
         }
+        requestUpdate();
+    }
+
+    /**
+     * Dismiss the stack of bubbles.
+     */
+    public void stackDismissed() {
+        collapseStack();
+        mBubbleContainer.removeAllViews();
     }
 
     /**
@@ -246,11 +287,19 @@
      *
      * @param bubbleView the view to update in the stack.
      * @param entry the entry to update it with.
+     * @param updatePosition whether this bubble should be moved to top of the stack.
      */
-    public void updateBubble(BubbleView bubbleView, NotificationData.Entry entry) {
-        // TODO - move to top of bubble stack, make it show its update if it makes sense
+    public void updateBubble(BubbleView bubbleView, NotificationEntry entry,
+            boolean updatePosition) {
         bubbleView.update(entry);
-        if (bubbleView.equals(mExpandedBubble)) {
+        if (updatePosition && !mIsExpanded) {
+            // If alerting it gets promoted to top of the stack
+            mBubbleContainer.removeView(bubbleView);
+            mBubbleContainer.addView(bubbleView, 0);
+            requestUpdate();
+        }
+        if (mIsExpanded && bubbleView.equals(mExpandedBubble)) {
+            entry.setShowInShadeWhenBubble(false);
             requestUpdate();
         }
     }
@@ -281,17 +330,36 @@
     }
 
     /**
+     * Collapses the stack of bubbles.
+     */
+    public void collapseStack() {
+        if (mIsExpanded) {
+            // TODO: Save opened bubble & move it to top of stack
+            animateExpansion(false /* shouldExpand */);
+            notifyExpansionChanged(mExpandedBubble, mIsExpanded);
+        }
+    }
+
+    /**
+     * Expands the stack fo bubbles.
+     */
+    public void expandStack() {
+        if (!mIsExpanded) {
+            mExpandedBubble = getTopBubble();
+            mExpandedBubble.getEntry().setShowInShadeWhenBubble(false);
+            animateExpansion(true /* shouldExpand */);
+            notifyExpansionChanged(mExpandedBubble, true /* expanded */);
+        }
+    }
+
+    /**
      * Tell the stack to animate to collapsed or expanded state.
      */
-    public void animateExpansion(boolean shouldExpand) {
+    private void animateExpansion(boolean shouldExpand) {
         if (mIsExpanded != shouldExpand) {
             mIsExpanded = shouldExpand;
-            mExpandedBubble = shouldExpand ? getTopBubble() : null;
             updateExpandedBubble();
 
-            if (mExpandListener != null) {
-                mExpandListener.onBubbleExpandChanged(mIsExpanded, 1 /* amount */);
-            }
             if (shouldExpand) {
                 // Save current position so that we might return there
                 savePosition();
@@ -341,6 +409,13 @@
         mCollapsedPosition = getPosition();
     }
 
+    private void notifyExpansionChanged(BubbleView bubbleView, boolean expanded) {
+        if (mExpandListener != null) {
+            NotificationEntry entry = bubbleView != null ? bubbleView.getEntry() : null;
+            mExpandListener.onBubbleExpandChanged(expanded, entry != null ? entry.key : null);
+        }
+    }
+
     private BubbleView getTopBubble() {
         return getBubbleAt(0);
     }
@@ -389,32 +464,79 @@
     }
 
     private void updateExpandedBubble() {
-        if (mExpandedBubble != null) {
+        if (mExpandedBubble == null) {
+            return;
+        }
+
+        if (mExpandedBubble.hasAppOverlayIntent()) {
+            // Bubble with activity view expanded state
+            ActivityView expandedView = mExpandedBubble.getActivityView();
+            // XXX: gets added to linear layout
+            expandedView.setLayoutParams(new LinearLayout.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT, mExpandedBubbleHeight));
+
+            final PendingIntent intent = mExpandedBubble.getAppOverlayIntent();
+            mExpandedViewContainer.setHeaderText(intent.getIntent().getComponent().toShortString());
+            mExpandedViewContainer.setExpandedView(expandedView);
+            expandedView.setCallback(new ActivityView.StateCallback() {
+                @Override
+                public void onActivityViewReady(ActivityView view) {
+                    Log.d(TAG, "onActivityViewReady("
+                            + mExpandedBubble.getEntry().key + "): " + view);
+                    view.startActivity(intent);
+                }
+
+                @Override
+                public void onActivityViewDestroyed(ActivityView view) {
+                    NotificationEntry entry = mExpandedBubble != null
+                            ? mExpandedBubble.getEntry() : null;
+                    Log.d(TAG, "onActivityViewDestroyed(key="
+                            + ((entry != null) ? entry.key : "(none)") + "): " + view);
+                }
+            });
+        } else {
+            // Bubble with notification view expanded state
             ExpandableNotificationRow row = mExpandedBubble.getRowView();
-            if (!row.equals(mExpandedViewContainer.getChildAt(0))) {
-                // Different expanded view than what we have
+            if (row.getParent() != null) {
+                // Row might still be in the shade when we expand
+                ((ViewGroup) row.getParent()).removeView(row);
+            }
+            if (mIsExpanded) {
+                mExpandedViewContainer.setExpandedView(row);
+            } else {
                 mExpandedViewContainer.setExpandedView(null);
             }
-            int pointerPosition = mExpandedBubble.getPosition().x
-                    + (mExpandedBubble.getWidth() / 2);
-            mExpandedViewContainer.setPointerPosition(pointerPosition);
-            mExpandedViewContainer.setExpandedView(row);
+            // Bubble with notification as expanded state doesn't need a header / title
+            mExpandedViewContainer.setHeaderText(null);
+
         }
+        int pointerPosition = mExpandedBubble.getPosition().x
+                + (mExpandedBubble.getWidth() / 2);
+        mExpandedViewContainer.setPointerPosition(pointerPosition);
     }
 
     private void applyCurrentState() {
+        Log.d(TAG, "applyCurrentState: mIsExpanded=" + mIsExpanded);
+
         mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
         if (!mIsExpanded) {
             mExpandedViewContainer.setExpandedView(null);
         } else {
             mExpandedViewContainer.setTranslationY(mBubbleContainer.getHeight());
-            ExpandableNotificationRow row = mExpandedBubble.getRowView();
-            applyRowState(row);
+            View expandedView = mExpandedViewContainer.getExpandedView();
+            if (expandedView instanceof ActivityView) {
+                if (expandedView.isAttachedToWindow()) {
+                    ((ActivityView) expandedView).onLocationChanged();
+                }
+            } else {
+                applyRowState(mExpandedBubble.getRowView());
+            }
         }
         int bubbsCount = mBubbleContainer.getChildCount();
         for (int i = 0; i < bubbsCount; i++) {
             BubbleView bv = (BubbleView) mBubbleContainer.getChildAt(i);
-            bv.setZ(bubbsCount - 1);
+            bv.updateDotVisibility();
+            bv.setZ(bubbsCount - i);
 
             int transX = mIsExpanded ? (bv.getWidth() + mBubblePadding) * i : mBubblePadding * i;
             ViewState viewState = new ViewState();
@@ -468,6 +590,7 @@
     private void applyRowState(ExpandableNotificationRow view) {
         view.reset();
         view.setHeadsUp(false);
+        view.resetTranslation();
         view.setOnKeyguard(false);
         view.setOnAmbient(false);
         view.setClipBottomAmount(0);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index 88030ee..97784b0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -33,7 +33,7 @@
  * Handles interpreting touches on a {@link BubbleStackView}. This includes expanding, collapsing,
  * dismissing, and flings.
  */
-public class BubbleTouchHandler implements View.OnTouchListener {
+class BubbleTouchHandler implements View.OnTouchListener {
 
     private BubbleController mController = Dependency.get(BubbleController.class);
     private PipDismissViewController mDismissViewController;
@@ -110,7 +110,7 @@
                 : stack.getTargetView(event);
         boolean isFloating = targetView instanceof FloatingView;
         if (!isFloating || targetView == null || action == MotionEvent.ACTION_OUTSIDE) {
-            stack.animateExpansion(false /* shouldExpand */);
+            stack.collapseStack();
             cleanUpDismissTarget();
             resetTouches();
             return false;
@@ -196,9 +196,13 @@
                         mMovementHelper.getTranslateAnim(floatingView, toGoTo, 100, 0).start();
                     }
                 } else if (floatingView.equals(stack.getExpandedBubble())) {
-                    stack.animateExpansion(false /* shouldExpand */);
+                    stack.collapseStack();
                 } else if (isBubbleStack) {
-                    stack.animateExpansion(!stack.isExpanded() /* shouldExpand */);
+                    if (stack.isExpanded()) {
+                        stack.collapseStack();
+                    } else {
+                        stack.expandStack();
+                    }
                 } else {
                     stack.setExpandedBubble((BubbleView) floatingView);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
index 6c47aac..e8432b9 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 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.
@@ -16,36 +16,50 @@
 
 package com.android.systemui.bubbles;
 
+import android.annotation.Nullable;
+import android.app.ActivityView;
 import android.app.Notification;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.Point;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.OvalShape;
+import android.graphics.drawable.InsetDrawable;
+import android.graphics.drawable.LayerDrawable;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
-import android.widget.ImageView;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 
-import com.android.internal.util.ContrastColorUtil;
+import com.android.internal.graphics.ColorUtils;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
 /**
- * A floating object on the screen that has a collapsed and expanded state.
+ * A floating object on the screen that can post message updates.
  */
-public class BubbleView extends LinearLayout implements BubbleTouchHandler.FloatingView {
+public class BubbleView extends FrameLayout implements BubbleTouchHandler.FloatingView {
     private static final String TAG = "BubbleView";
 
+    // Same value as Launcher3 badge code
+    private static final float WHITE_SCRIM_ALPHA = 0.54f;
     private Context mContext;
-    private View mIconView;
 
-    private NotificationData.Entry mEntry;
-    private int mBubbleSize;
-    private int mIconSize;
+    private BadgedImageView mBadgedImageView;
+    private TextView mMessageView;
+    private int mPadding;
+    private int mIconInset;
+
+    private NotificationEntry mEntry;
+    private PendingIntent mAppOverlayIntent;
+    private ActivityView mActivityView;
 
     public BubbleView(Context context) {
         this(context, null);
@@ -61,72 +75,201 @@
 
     public BubbleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        setOrientation(LinearLayout.VERTICAL);
         mContext = context;
-        mBubbleSize = getResources().getDimensionPixelSize(R.dimen.bubble_size);
-        mIconSize = getResources().getDimensionPixelSize(R.dimen.bubble_icon_size);
+        // XXX: can this padding just be on the view and we look it up?
+        mPadding = getResources().getDimensionPixelSize(R.dimen.bubble_view_padding);
+        mIconInset = getResources().getDimensionPixelSize(R.dimen.bubble_icon_inset);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mBadgedImageView = (BadgedImageView) findViewById(R.id.bubble_image);
+        mMessageView = (TextView) findViewById(R.id.message_view);
+        mMessageView.setVisibility(GONE);
+        mMessageView.setPivotX(0);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        updateViews();
+    }
+
+    @Override
+    protected void onMeasure(int widthSpec, int heightSpec) {
+        measureChild(mBadgedImageView, widthSpec, heightSpec);
+        measureChild(mMessageView, widthSpec, heightSpec);
+        boolean messageGone = mMessageView.getVisibility() == GONE;
+        int imageHeight = mBadgedImageView.getMeasuredHeight();
+        int imageWidth = mBadgedImageView.getMeasuredWidth();
+        int messageHeight = messageGone ? 0 : mMessageView.getMeasuredHeight();
+        int messageWidth = messageGone ? 0 : mMessageView.getMeasuredWidth();
+        setMeasuredDimension(
+                getPaddingStart() + imageWidth + mPadding + messageWidth + getPaddingEnd(),
+                getPaddingTop() + Math.max(imageHeight, messageHeight) + getPaddingBottom());
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        left = getPaddingStart();
+        top = getPaddingTop();
+        int imageWidth = mBadgedImageView.getMeasuredWidth();
+        int imageHeight = mBadgedImageView.getMeasuredHeight();
+        int messageWidth = mMessageView.getMeasuredWidth();
+        int messageHeight = mMessageView.getMeasuredHeight();
+        mBadgedImageView.layout(left, top, left + imageWidth, top + imageHeight);
+        mMessageView.layout(left + imageWidth + mPadding, top,
+                left + imageWidth + mPadding + messageWidth, top + messageHeight);
     }
 
     /**
      * Populates this view with a notification.
+     * <p>
+     * This should only be called when a new notification is being set on the view, updates to the
+     * current notification should use {@link #update(NotificationEntry)}.
      *
      * @param entry the notification to display as a bubble.
      */
-    public void setNotif(NotificationData.Entry entry) {
-        removeAllViews();
-        // TODO: migrate to inflater
-        mIconView = new ImageView(mContext);
-        addView(mIconView);
-
-        LinearLayout.LayoutParams iconLp = (LinearLayout.LayoutParams) mIconView.getLayoutParams();
-        iconLp.width = mBubbleSize;
-        iconLp.height = mBubbleSize;
-        mIconView.setLayoutParams(iconLp);
-
-        update(entry);
-    }
-
-    /**
-     * Updates the UI based on the entry.
-     */
-    public void update(NotificationData.Entry entry) {
+    public void setNotif(NotificationEntry entry) {
         mEntry = entry;
-        Notification n = entry.notification.getNotification();
-        Icon ic = n.getLargeIcon() != null ? n.getLargeIcon() : n.getSmallIcon();
-
-        if (n.getLargeIcon() == null) {
-            createCircledIcon(n.color, ic, ((ImageView) mIconView));
-        } else {
-            ((ImageView) mIconView).setImageIcon(ic);
-        }
+        updateViews();
     }
 
     /**
-     * @return the key identifying this bubble / notification entry associated with this
-     * bubble, if it exists.
+     * The {@link NotificationEntry} associated with this view, if one exists.
      */
-    public String getKey() {
-        return mEntry == null ? null : mEntry.key;
-    }
-
-    /**
-     * @return the notification entry associated with this bubble.
-     */
-    public NotificationData.Entry getEntry() {
+    @Nullable
+    public NotificationEntry getEntry() {
         return mEntry;
     }
 
     /**
-     * @return the view to display when the bubble is expanded.
+     * The key for the {@link NotificationEntry} associated with this view, if one exists.
      */
+    @Nullable
+    public String getKey() {
+        return (mEntry != null) ? mEntry.key : null;
+    }
+
+    /**
+     * Updates the UI based on the entry, updates badge and animates messages as needed.
+     */
+    public void update(NotificationEntry entry) {
+        mEntry = entry;
+        updateViews();
+    }
+
+
+    /**
+     * @return the {@link ExpandableNotificationRow} view to display notification content when the
+     * bubble is expanded.
+     */
+    @Nullable
     public ExpandableNotificationRow getRowView() {
-        return mEntry.getRow();
+        return (mEntry != null) ? mEntry.getRow() : null;
+    }
+
+    /**
+     * Marks this bubble as "read", i.e. no badge should show.
+     */
+    public void updateDotVisibility() {
+        boolean showDot = getEntry().showInShadeWhenBubble();
+        animateDot(showDot);
+    }
+
+    /**
+     * Animates the badge to show or hide.
+     */
+    private void animateDot(boolean showDot) {
+        if (mBadgedImageView.isShowingDot() != showDot) {
+            mBadgedImageView.setShowDot(showDot);
+            mBadgedImageView.clearAnimation();
+            mBadgedImageView.animate().setDuration(200)
+                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                    .setUpdateListener((valueAnimator) -> {
+                        float fraction = valueAnimator.getAnimatedFraction();
+                        fraction = showDot ? fraction : 1 - fraction;
+                        mBadgedImageView.setDotScale(fraction);
+                    }).withEndAction(() -> {
+                        if (!showDot) {
+                            mBadgedImageView.setShowDot(false);
+                        }
+                    }).start();
+        }
+    }
+
+    private void updateViews() {
+        if (mEntry == null) {
+            return;
+        }
+        Notification n = mEntry.notification.getNotification();
+        boolean isLarge = n.getLargeIcon() != null;
+        Icon ic = isLarge ? n.getLargeIcon() : n.getSmallIcon();
+        Drawable iconDrawable = ic.loadDrawable(mContext);
+        if (!isLarge) {
+            // Center icon on coloured background
+            iconDrawable.setTint(Color.WHITE); // TODO: dark mode
+            Drawable bg = new ColorDrawable(n.color);
+            InsetDrawable d = new InsetDrawable(iconDrawable, mIconInset);
+            Drawable[] layers = {bg, d};
+            mBadgedImageView.setImageDrawable(new LayerDrawable(layers));
+        } else {
+            mBadgedImageView.setImageDrawable(iconDrawable);
+        }
+        int badgeColor = determineDominateColor(iconDrawable, n.color);
+        mBadgedImageView.setDotColor(badgeColor);
+        animateDot(mEntry.showInShadeWhenBubble() /* showDot */);
+    }
+
+    private int determineDominateColor(Drawable d, int defaultTint) {
+        // XXX: should we pull from the drawable, app icon, notif tint?
+        return ColorUtils.blendARGB(defaultTint, Color.WHITE, WHITE_SCRIM_ALPHA);
+    }
+
+    /**
+     * @return a view used to display app overlay content when expanded.
+     */
+    public ActivityView getActivityView() {
+        if (mActivityView == null) {
+            mActivityView = new ActivityView(mContext);
+            Log.d(TAG, "[getActivityView] created: " + mActivityView);
+        }
+        return mActivityView;
+    }
+
+    /**
+     * Removes and releases an ActivityView if one was previously created for this bubble.
+     */
+    public void destroyActivityView(ViewGroup tmpParent) {
+        if (mActivityView == null) {
+            return;
+        }
+        // HACK: Only release if initialized. There's no way to know if the ActivityView has
+        // been initialized. Calling release() if it hasn't been initialized will crash.
+
+        if (!mActivityView.isAttachedToWindow()) {
+            // HACK: release() will crash if the view is not attached.
+
+            mActivityView.setVisibility(View.GONE);
+            tmpParent.addView(mActivityView, new LinearLayout.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.MATCH_PARENT));
+        }
+        try {
+            mActivityView.release();
+        } catch (IllegalStateException ex) {
+            Log.e(TAG, "ActivityView either already released, or not yet initialized.", ex);
+        }
+
+        ((ViewGroup) mActivityView.getParent()).removeView(mActivityView);
+        mActivityView = null;
     }
 
     @Override
     public void setPosition(int x, int y) {
-        setTranslationX(x);
-        setTranslationY(y);
+        setPositionX(x);
+        setPositionY(y);
     }
 
     @Override
@@ -144,22 +287,19 @@
         return new Point((int) getTranslationX(), (int) getTranslationY());
     }
 
-    // Seems sub optimal
-    private void createCircledIcon(int tint, Icon icon, ImageView v) {
-        // TODO: dark mode
-        icon.setTint(Color.WHITE);
-        icon.scaleDownIfNecessary(mIconSize, mIconSize);
-        v.setImageDrawable(icon.loadDrawable(mContext));
-        v.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) v.getLayoutParams();
-        int color = ContrastColorUtil.ensureContrast(tint, Color.WHITE,
-                false /* isBgDarker */, 3);
-        Drawable d = new ShapeDrawable(new OvalShape());
-        d.setTint(color);
-        v.setBackgroundDrawable(d);
+    /**
+     * @return whether an ActivityView should be used to display the content of this Bubble
+     */
+    public boolean hasAppOverlayIntent() {
+        return mAppOverlayIntent != null;
+    }
 
-        lp.width = mBubbleSize;
-        lp.height = mBubbleSize;
-        v.setLayoutParams(lp);
+    public PendingIntent getAppOverlayIntent() {
+        return mAppOverlayIntent;
+
+    }
+
+    public void setBubbleIntent(PendingIntent intent) {
+        mAppOverlayIntent = intent;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 1718cff..4ff27b1 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -48,7 +48,7 @@
  *
  * It does not collect touch events when the bouncer shows up.
  */
-public class FalsingManager implements SensorEventListener {
+public class FalsingManager implements SensorEventListener, StateListener {
     private static final String ENFORCE_BOUNCER = "falsing_manager_enforce_bouncer";
 
     private static final int[] CLASSIFIER_SENSORS = new int[] {
@@ -84,8 +84,6 @@
     private boolean mShowingAod;
     private Runnable mPendingWtf;
 
-    private final StateListener mStateListener = this::setStatusBarState;
-
     protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
         @Override
         public void onChange(boolean selfChange) {
@@ -108,7 +106,7 @@
                 UserHandle.USER_ALL);
 
         updateConfiguration();
-        Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
+        Dependency.get(StatusBarStateController.class).addCallback(this);
     }
 
     public static FalsingManager getInstance(Context context) {
@@ -282,14 +280,15 @@
         updateSessionActive();
     }
 
-    private void setStatusBarState(int state) {
+    @Override
+    public void onStateChanged(int newState) {
         if (FalsingLog.ENABLED) {
             FalsingLog.i("setStatusBarState", new StringBuilder()
                     .append("from=").append(StatusBarState.toShortString(mState))
-                    .append(" to=").append(StatusBarState.toShortString(state))
+                    .append(" to=").append(StatusBarState.toShortString(newState))
                     .toString());
         }
-        mState = state;
+        mState = newState;
         updateSessionActive();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
index fa5a114..d332f59 100644
--- a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
+++ b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
@@ -48,6 +48,11 @@
      */
     void removeListener(DockEventListener callback);
 
+    /**
+    * Returns true if the device is in docking state.
+    */
+    boolean isDocked();
+
     /** Callback for receiving dock events */
     interface DockEventListener {
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index 9fc2234..5353ee6 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -22,7 +22,6 @@
 import android.util.Log;
 
 import com.android.internal.hardware.AmbientDisplayConfiguration;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.doze.DozeMachine.State;
 
@@ -46,12 +45,12 @@
     private int mDockState = DockManager.STATE_NONE;
 
     public DozeDockHandler(Context context, DozeMachine machine, DozeHost dozeHost,
-            AmbientDisplayConfiguration config, Handler handler) {
+            AmbientDisplayConfiguration config, Handler handler, DockManager dockManager) {
         mMachine = machine;
         mDozeHost = dozeHost;
         mConfig = config;
         mHandler = handler;
-        mDockManager = SysUiServiceProvider.getComponent(context, DockManager.class);
+        mDockManager = dockManager;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 58ae555..e338a34 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -27,8 +27,10 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.AsyncSensorManager;
 import com.android.systemui.util.wakelock.DelayedWakeLock;
@@ -44,6 +46,7 @@
         Context context = dozeService;
         SensorManager sensorManager = Dependency.get(AsyncSensorManager.class);
         AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
+        DockManager dockManager = SysUiServiceProvider.getComponent(context, DockManager.class);
 
         DozeHost host = getHost(dozeService);
         AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(context);
@@ -63,13 +66,13 @@
                 new DozePauser(handler, machine, alarmManager, params.getPolicy()),
                 new DozeFalsingManagerAdapter(FalsingManager.getInstance(context)),
                 createDozeTriggers(context, sensorManager, host, alarmManager, config, params,
-                        handler, wakeLock, machine),
+                        handler, wakeLock, machine, dockManager),
                 createDozeUi(context, host, wakeLock, machine, handler, alarmManager, params),
                 new DozeScreenState(wrappedService, handler, params, wakeLock),
                 createDozeScreenBrightness(context, wrappedService, sensorManager, host, params,
                         handler),
                 new DozeWallpaperState(context),
-                new DozeDockHandler(context, machine, host, config, handler)
+                new DozeDockHandler(context, machine, host, config, handler, dockManager)
         });
 
         return machine;
@@ -86,10 +89,11 @@
 
     private DozeTriggers createDozeTriggers(Context context, SensorManager sensorManager,
             DozeHost host, AlarmManager alarmManager, AmbientDisplayConfiguration config,
-            DozeParameters params, Handler handler, WakeLock wakeLock, DozeMachine machine) {
+            DozeParameters params, Handler handler, WakeLock wakeLock, DozeMachine machine,
+            DockManager dockManager) {
         boolean allowPulseTriggers = true;
         return new DozeTriggers(context, machine, host, alarmManager, config, params,
-                sensorManager, handler, wakeLock, allowPulseTriggers);
+                sensorManager, handler, wakeLock, allowPulseTriggers, dockManager);
     }
 
     private DozeMachine.Part createDozeUi(Context context, DozeHost host, WakeLock wakeLock,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 4cb1fee..bd7a421 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -38,7 +38,13 @@
     void setAnimateWakeup(boolean animateWakeup);
     void setAnimateScreenOff(boolean animateScreenOff);
 
-    void onDoubleTap(float x, float y);
+    /**
+     * Reports that a tap event happend on the Sensors Low Power Island.
+     *
+     * @param x Touch X, or -1 if sensor doesn't support touch location.
+     * @param y Touch Y, or -1 if sensor doesn't support touch location.
+     */
+    void onSlpiTap(float x, float y);
 
     default void setAodDimmingScrim(float scrimOpacity) {}
     void setDozeScreenBrightness(int value);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 50003e3..a784773 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -35,7 +35,7 @@
     private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
     static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
 
-    private static final int REASONS = 9;
+    private static final int REASONS = 10;
 
     public static final int PULSE_REASON_NONE = -1;
     public static final int PULSE_REASON_INTENT = 0;
@@ -47,6 +47,7 @@
     public static final int PULSE_REASON_DOCKING = 6;
     public static final int REASON_SENSOR_WAKE_UP = 7;
     public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8;
+    public static final int PULSE_REASON_SENSOR_TAP = 9;
 
     private static boolean sRegisterKeyguardCallback = true;
 
@@ -207,6 +208,7 @@
             case PULSE_REASON_DOCKING: return "docking";
             case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen";
             case REASON_SENSOR_WAKE_UP: return "wakeup";
+            case PULSE_REASON_SENSOR_TAP: return "tap";
             default: throw new IllegalArgumentException("bad reason: " + pulseReason);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 04362c1..562edd6 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -85,6 +85,7 @@
         mProxCallback = proxCallback;
         mResolver = mContext.getContentResolver();
 
+        boolean alwaysOn = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT);
         mSensors = new TriggerSensor[] {
                 new TriggerSensor(
                         mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
@@ -106,6 +107,13 @@
                         dozeParameters.doubleTapReportsTouchCoordinates(),
                         true /* touchscreen */),
                 new TriggerSensor(
+                        findSensorWithType(config.tapSensorType()),
+                        Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
+                        true /* configured */,
+                        DozeLog.PULSE_REASON_SENSOR_TAP,
+                        false /* reports touch coordinates */,
+                        true /* touchscreen */),
+                new TriggerSensor(
                         findSensorWithType(config.longPressSensorType()),
                         Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
                         false /* settingDef */,
@@ -116,7 +124,7 @@
                 new PluginSensor(
                         new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY),
                         Settings.Secure.DOZE_WAKE_SCREEN_GESTURE,
-                        mConfig.wakeScreenGestureAvailable(),
+                        mConfig.wakeScreenGestureAvailable() && alwaysOn,
                         DozeLog.REASON_SENSOR_WAKE_UP,
                         false /* reports touch coordinates */,
                         false /* touchscreen */),
@@ -206,6 +214,15 @@
         mPickupSensor.setDisabled(disable);
     }
 
+    /** Ignore the setting value of only the sensors that require the touchscreen. */
+    public void ignoreTouchScreenSensorsSettingInterferingWithDocking(boolean ignore) {
+        for (TriggerSensor sensor : mSensors) {
+            if (sensor.mRequiresTouchscreen) {
+                sensor.ignoreSetting(ignore);
+            }
+        }
+    }
+
     /** Dump current state */
     public void dump(PrintWriter pw) {
         for (TriggerSensor s : mSensors) {
@@ -315,6 +332,7 @@
         protected boolean mRequested;
         protected boolean mRegistered;
         protected boolean mDisabled;
+        protected boolean mIgnoresSetting;
 
         public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason,
                 boolean reportsTouchCoordinates, boolean requiresTouchscreen) {
@@ -325,6 +343,13 @@
         public TriggerSensor(Sensor sensor, String setting, boolean settingDef,
                 boolean configured, int pulseReason, boolean reportsTouchCoordinates,
                 boolean requiresTouchscreen) {
+            this(sensor, setting, settingDef, configured, pulseReason, reportsTouchCoordinates,
+                    requiresTouchscreen, false /* ignoresSetting */);
+        }
+
+        private TriggerSensor(Sensor sensor, String setting, boolean settingDef,
+                boolean configured, int pulseReason, boolean reportsTouchCoordinates,
+                boolean requiresTouchscreen, boolean ignoresSetting) {
             mSensor = sensor;
             mSetting = setting;
             mSettingDefault = settingDef;
@@ -332,6 +357,7 @@
             mPulseReason = pulseReason;
             mReportsTouchCoordinates = reportsTouchCoordinates;
             mRequiresTouchscreen = requiresTouchscreen;
+            mIgnoresSetting = ignoresSetting;
         }
 
         public void setListening(boolean listen) {
@@ -346,9 +372,16 @@
             updateListener();
         }
 
+        public void ignoreSetting(boolean ignored) {
+            if (mIgnoresSetting == ignored) return;
+            mIgnoresSetting = ignored;
+            updateListener();
+        }
+
         public void updateListener() {
             if (!mConfigured || mSensor == null) return;
-            if (mRequested && !mDisabled && enabledBySetting() && !mRegistered) {
+            if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
+                    && !mRegistered) {
                 mRegistered = mSensorManager.requestTriggerSensor(this, mSensor);
                 if (DEBUG) Log.d(TAG, "requestTriggerSensor " + mRegistered);
             } else if (mRegistered) {
@@ -374,6 +407,7 @@
                     .append(", mRequested=").append(mRequested)
                     .append(", mDisabled=").append(mDisabled)
                     .append(", mConfigured=").append(mConfigured)
+                    .append(", mIgnoresSetting=").append(mIgnoresSetting)
                     .append(", mSensor=").append(mSensor).append("}").toString();
         }
 
@@ -456,7 +490,8 @@
         public void updateListener() {
             if (!mConfigured) return;
             AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager;
-            if (mRequested && !mDisabled && enabledBySetting() && !mRegistered) {
+            if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
+                    && !mRegistered) {
                 asyncSensorManager.registerPluginListener(mPluginSensor, mTriggerEventListener);
                 mRegistered = true;
                 if (DEBUG) Log.d(TAG, "registerPluginListener");
@@ -473,6 +508,7 @@
                     .append(", mRequested=").append(mRequested)
                     .append(", mDisabled=").append(mDisabled)
                     .append(", mConfigured=").append(mConfigured)
+                    .append(", mIgnoresSetting=").append(mIgnoresSetting)
                     .append(", mSensor=").append(mPluginSensor).append("}").toString();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 6a9b689..dc505b5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -33,8 +33,10 @@
 import android.text.format.Formatter;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.hardware.AmbientDisplayConfiguration;
 import com.android.internal.util.Preconditions;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.Assert;
 import com.android.systemui.util.wakelock.WakeLock;
@@ -71,6 +73,8 @@
     private final boolean mAllowPulseTriggers;
     private final UiModeManager mUiModeManager;
     private final TriggerReceiver mBroadcastReceiver = new TriggerReceiver();
+    private final DockEventListener mDockEventListener = new DockEventListener();
+    private final DockManager mDockManager;
 
     private long mNotificationPulseTime;
     private boolean mPulsePending;
@@ -79,7 +83,7 @@
     public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost,
             AlarmManager alarmManager, AmbientDisplayConfiguration config,
             DozeParameters dozeParameters, SensorManager sensorManager, Handler handler,
-            WakeLock wakeLock, boolean allowPulseTriggers) {
+            WakeLock wakeLock, boolean allowPulseTriggers, DockManager dockManager) {
         mContext = context;
         mMachine = machine;
         mDozeHost = dozeHost;
@@ -93,6 +97,7 @@
                 config, wakeLock, this::onSensor, this::onProximityFar,
                 dozeParameters.getPolicy());
         mUiModeManager = mContext.getSystemService(UiModeManager.class);
+        mDockManager = dockManager;
     }
 
     private void onNotification() {
@@ -129,9 +134,11 @@
         }
     }
 
-    private void onSensor(int pulseReason, boolean sensorPerformedProxCheck,
+    @VisibleForTesting
+    void onSensor(int pulseReason, boolean sensorPerformedProxCheck,
             float screenX, float screenY, float[] rawValues) {
         boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
+        boolean isTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_TAP;
         boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
         boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS;
         boolean isWakeDisplay = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP;
@@ -148,15 +155,17 @@
                     // In pocket, drop event.
                     return;
                 }
-                if (isDoubleTap) {
-                    mDozeHost.onDoubleTap(screenX, screenY);
+                if (isDoubleTap || isTap) {
+                    if (screenX != -1 && screenY != -1) {
+                        mDozeHost.onSlpiTap(screenX, screenY);
+                    }
                     mMachine.wakeUp();
                 } else if (isPickup) {
                     mMachine.wakeUp();
                 } else {
                     mDozeHost.extendPulse();
                 }
-            }, sensorPerformedProxCheck, pulseReason);
+            }, sensorPerformedProxCheck || mDockManager.isDocked(), pulseReason);
         }
 
         if (isPickup) {
@@ -220,6 +229,7 @@
             case INITIALIZED:
                 mBroadcastReceiver.register(mContext);
                 mDozeHost.addCallback(mHostCallback);
+                mDockManager.addListener(mDockEventListener);
                 checkTriggersAtInit();
                 break;
             case DOZE:
@@ -245,6 +255,7 @@
             case FINISH:
                 mBroadcastReceiver.unregister(mContext);
                 mDozeHost.removeCallback(mHostCallback);
+                mDockManager.removeListener(mDockEventListener);
                 mDozeSensors.setListening(false);
                 mDozeSensors.setProxListening(false);
                 break;
@@ -420,6 +431,24 @@
         }
     }
 
+    private class DockEventListener implements DockManager.DockEventListener {
+        @Override
+        public void onEvent(int event) {
+            if (DEBUG) Log.d(TAG, "dock event = " + event);
+            switch (event) {
+                case DockManager.STATE_DOCKED:
+                case DockManager.STATE_DOCKED_HIDE:
+                    mDozeSensors.ignoreTouchScreenSensorsSettingInterferingWithDocking(true);
+                    break;
+                case DockManager.STATE_NONE:
+                    mDozeSensors.ignoreTouchScreenSensorsSettingInterferingWithDocking(false);
+                    break;
+                default:
+                    // no-op
+            }
+        }
+    }
+
     private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
         @Override
         public void onNotificationAlerted() {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 67aa82d..7656564 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -124,6 +124,7 @@
                 unscheduleTimeTick();
                 break;
             case DOZE_REQUEST_PULSE:
+                scheduleTimeTick();
                 pulseWhileDozing(mMachine.getPulseReason());
                 break;
             case INITIALIZED:
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 268245b..7b18fad 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -67,10 +67,8 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.AdapterView.OnItemLongClickListener;
 import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.internal.R;
@@ -86,8 +84,8 @@
 import com.android.internal.util.ScreenshotHelper;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.Dependency;
-import com.android.systemui.HardwareUiLayout;
 import com.android.systemui.Interpolators;
+import com.android.systemui.MultiListLayout;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
 import com.android.systemui.statusbar.phone.ScrimController;
@@ -490,6 +488,11 @@
         public boolean showBeforeProvisioning() {
             return true;
         }
+
+        @Override
+        public boolean shouldBeSeparated() {
+            return true;
+        }
     }
 
     private final class RestartAction extends SinglePressAction implements LongPressAction {
@@ -926,6 +929,34 @@
             return getItem(position).isEnabled();
         }
 
+        public ArrayList<Action> getSeparatedActions(boolean shouldUseSeparatedView) {
+            ArrayList<Action> separatedActions = new ArrayList<Action>();
+            if (!shouldUseSeparatedView) {
+                return separatedActions;
+            }
+            for (int i = 0; i < mItems.size(); i++) {
+                final Action action = mItems.get(i);
+                if (action.shouldBeSeparated()) {
+                    separatedActions.add(action);
+                }
+            }
+            return separatedActions;
+        }
+
+        public ArrayList<Action> getListActions(boolean shouldUseSeparatedView) {
+            if (!shouldUseSeparatedView) {
+                return new ArrayList<Action>(mItems);
+            }
+            ArrayList<Action> listActions = new ArrayList<Action>();
+            for (int i = 0; i < mItems.size(); i++) {
+                final Action action = mItems.get(i);
+                if (!action.shouldBeSeparated()) {
+                    listActions.add(action);
+                }
+            }
+            return listActions;
+        }
+
         @Override
         public boolean areAllItemsEnabled() {
             return false;
@@ -965,7 +996,7 @@
             View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
             // Everything but screenshot, the last item, gets white background.
             if (position == getCount() - 1) {
-                HardwareUiLayout.get(parent).setDivisionView(view);
+                MultiListLayout.get(parent).setDivisionView(view);
             }
             return view;
         }
@@ -1004,6 +1035,10 @@
         boolean showBeforeProvisioning();
 
         boolean isEnabled();
+
+        default boolean shouldBeSeparated() {
+            return false;
+        }
     }
 
     /**
@@ -1423,9 +1458,7 @@
 
         private final Context mContext;
         private final MyAdapter mAdapter;
-        private final LinearLayout mListView;
-        private final FrameLayout mSeparatedView;
-        private final HardwareUiLayout mHardwareLayout;
+        private final MultiListLayout mGlobalActionsLayout;
         private final OnClickListener mClickListener;
         private final OnItemLongClickListener mLongClickListener;
         private final GradientDrawable mGradientDrawable;
@@ -1466,16 +1499,11 @@
             window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
 
             setContentView(com.android.systemui.R.layout.global_actions_wrapped);
-            mListView = findViewById(android.R.id.list);
-            mSeparatedView = findViewById(com.android.systemui.R.id.separated_button);
-            if (!mShouldDisplaySeparatedButton) {
-                mSeparatedView.setVisibility(View.GONE);
-            }
-            mHardwareLayout = HardwareUiLayout.get(mListView);
-            mHardwareLayout.setOutsideTouchListener(view -> dismiss());
-            mHardwareLayout.setHasSeparatedButton(mShouldDisplaySeparatedButton);
-            setTitle(R.string.global_actions);
-            mListView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+            mGlobalActionsLayout = (MultiListLayout)
+                    findViewById(com.android.systemui.R.id.global_actions_view);
+            mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
+            mGlobalActionsLayout.setHasSeparatedView(mShouldDisplaySeparatedButton);
+            mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
                 @Override
                 public boolean dispatchPopulateAccessibilityEvent(
                         View host, AccessibilityEvent event) {
@@ -1484,20 +1512,33 @@
                     return true;
                 }
             });
+            setTitle(R.string.global_actions);
         }
 
         private void updateList() {
-            mListView.removeAllViews();
-            mSeparatedView.removeAllViews();
+            mGlobalActionsLayout.removeAllItems();
+            ArrayList<Action> separatedActions =
+                    mAdapter.getSeparatedActions(mShouldDisplaySeparatedButton);
+            ArrayList<Action> listActions = mAdapter.getListActions(mShouldDisplaySeparatedButton);
+            mGlobalActionsLayout.setExpectedListItemCount(listActions.size());
+            mGlobalActionsLayout.setExpectedSeparatedItemCount(separatedActions.size());
+
             for (int i = 0; i < mAdapter.getCount(); i++) {
-                ViewGroup parentView = mShouldDisplaySeparatedButton && i == mAdapter.getCount() - 1
-                        ? mSeparatedView : mListView;
-                View v = mAdapter.getView(i, null, parentView);
+                Action action = mAdapter.getItem(i);
+                int separatedIndex = separatedActions.indexOf(action);
+                ViewGroup parent;
+                if (separatedIndex != -1) {
+                    parent = mGlobalActionsLayout.getParentView(true, separatedIndex);
+                } else {
+                    int listIndex = listActions.indexOf(action);
+                    parent = mGlobalActionsLayout.getParentView(false, listIndex);
+                }
+                View v = mAdapter.getView(i, null, parent);
                 final int pos = i;
                 v.setOnClickListener(view -> mClickListener.onClick(this, pos));
                 v.setOnLongClickListener(view ->
                         mLongClickListener.onItemLongClick(null, v, pos, 0));
-                parentView.addView(v);
+                parent.addView(v);
             }
         }
 
@@ -1543,9 +1584,9 @@
             super.show();
             mShowing = true;
             mGradientDrawable.setAlpha(0);
-            mHardwareLayout.setTranslationX(getAnimTranslation());
-            mHardwareLayout.setAlpha(0);
-            mHardwareLayout.animate()
+            mGlobalActionsLayout.setTranslationX(getAnimTranslation());
+            mGlobalActionsLayout.setAlpha(0);
+            mGlobalActionsLayout.animate()
                     .alpha(1)
                     .translationX(0)
                     .setDuration(300)
@@ -1564,9 +1605,9 @@
                 return;
             }
             mShowing = false;
-            mHardwareLayout.setTranslationX(0);
-            mHardwareLayout.setAlpha(1);
-            mHardwareLayout.animate()
+            mGlobalActionsLayout.setTranslationX(0);
+            mGlobalActionsLayout.setAlpha(1);
+            mGlobalActionsLayout.animate()
                     .alpha(0)
                     .translationX(getAnimTranslation())
                     .setDuration(300)
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index dc11b4c..19a7cea 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -132,9 +132,9 @@
     }
 
     @Override
-    public void disable(int state1, int state2, boolean animate) {
+    public void disable(int displayId, int state1, int state2, boolean animate) {
         final boolean disabled = (state2 & DISABLE2_GLOBAL_ACTIONS) != 0;
-        if (disabled == mDisabled) return;
+        if (displayId != mContext.getDisplayId() || disabled == mDisabled) return;
         mDisabled = disabled;
         if (disabled && mGlobalActions != null) {
             mGlobalActions.dismissDialog();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 6a0e8ad..c4c8bc7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -50,9 +50,9 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -68,7 +68,7 @@
  */
 public class KeyguardSliceProvider extends SliceProvider implements
         NextAlarmController.NextAlarmChangeCallback, ZenModeController.Callback,
-        NotificationMediaManager.MediaListener {
+        NotificationMediaManager.MediaListener, StatusBarStateController.StateListener {
 
     private static final StyleSpan BOLD_STYLE = new StyleSpan(Typeface.BOLD);
     public static final String KEYGUARD_SLICE_URI = "content://com.android.systemui.keyguard/main";
@@ -109,7 +109,9 @@
     private AlarmManager.AlarmClockInfo mNextAlarmInfo;
     private PendingIntent mPendingIntent;
     protected NotificationMediaManager mMediaManager;
+    private StatusBarStateController mStatusBarStateController;
     protected MediaMetadata mMediaMetaData;
+    protected boolean mDozing;
 
     /**
      * Receiver responsible for time ticking and updating the date format.
@@ -167,9 +169,20 @@
         mMediaUri = Uri.parse(KEYGUARD_MEDIA_URI);
     }
 
-    public void initDependencies() {
-        mMediaManager = Dependency.get(NotificationMediaManager.class);
+    /**
+     * Initialize dependencies that don't exist during {@link android.content.ContentProvider}
+     * instantiation.
+     *
+     * @param mediaManager {@link NotificationMediaManager} singleton.
+     * @param statusBarStateController {@link StatusBarStateController} singleton.
+     */
+    public void initDependencies(
+            NotificationMediaManager mediaManager,
+            StatusBarStateController statusBarStateController) {
+        mMediaManager = mediaManager;
         mMediaManager.addCallback(this);
+        mStatusBarStateController = statusBarStateController;
+        mStatusBarStateController.addCallback(this);
     }
 
     @AnyThread
@@ -179,7 +192,7 @@
         Slice slice;
         synchronized (this) {
             ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
-            if (mMediaMetaData != null) {
+            if (needsMediaLocked()) {
                 addMediaLocked(builder);
             } else {
                 builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText));
@@ -193,6 +206,10 @@
         return slice;
     }
 
+    protected boolean needsMediaLocked() {
+        return mMediaMetaData != null && mDozing;
+    }
+
     protected void addMediaLocked(ListBuilder listBuilder) {
         if (mMediaMetaData != null) {
             SpannableStringBuilder builder = new SpannableStringBuilder();
@@ -209,7 +226,7 @@
             }
 
             RowBuilder mediaBuilder = new RowBuilder(mMediaUri).setTitle(builder);
-            Icon notificationIcon = mMediaManager.getMediaIcon();
+            Icon notificationIcon = mMediaManager == null ? null : mMediaManager.getMediaIcon();
             if (notificationIcon != null) {
                 IconCompat icon = IconCompat.createFromIcon(notificationIcon);
                 mediaBuilder.addEndItem(icon, ListBuilder.ICON_IMAGE);
@@ -389,13 +406,35 @@
 
     @Override
     public void onMetadataChanged(MediaMetadata metadata) {
+        final boolean notify;
         synchronized (this) {
+            boolean neededMedia = needsMediaLocked();
             mMediaMetaData = metadata;
+            notify = neededMedia != needsMediaLocked();
         }
-        notifyChange();
+        if (notify) {
+            notifyChange();
+        }
     }
 
     protected void notifyChange() {
         mContentResolver.notifyChange(mSliceUri, null /* observer */);
     }
+
+    @Override
+    public void onDozingChanged(boolean isDozing) {
+        final boolean notify;
+        synchronized (this) {
+            boolean neededMedia = needsMediaLocked();
+            mDozing = isDozing;
+            notify = neededMedia != needsMediaLocked();
+        }
+        if (notify) {
+            notifyChange();
+        }
+    }
+
+    @Override
+    public void onStateChanged(int newState) {
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 323cf1f..f14495b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1843,6 +1843,13 @@
      */
     private void handleHide() {
         Trace.beginSection("KeyguardViewMediator#handleHide");
+
+        // It's possible that the device was unlocked in a dream state. It's time to wake up.
+        if (mAodShowing) {
+            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+            pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:BOUNCER_DOZING");
+        }
+
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleHide");
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
index 1e0d4d0..b09d6e1 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
@@ -36,8 +36,7 @@
     private Handler mHandler;
     private IActivityManager mActivityManager;
     private AppOpsManager mAppOpsManager;
-
-    private PipMotionHelper mMotionHelper;
+    private Callback mCallback;
 
     private AppOpsManager.OnOpChangedListener mAppOpsChangedListener = new OnOpChangedListener() {
         @Override
@@ -52,7 +51,7 @@
                     if (appInfo.packageName.equals(topPipActivityInfo.first.getPackageName()) &&
                             mAppOpsManager.checkOpNoThrow(OP_PICTURE_IN_PICTURE, appInfo.uid,
                                     packageName) != MODE_ALLOWED) {
-                        mHandler.post(() -> mMotionHelper.dismissPip());
+                        mHandler.post(() -> mCallback.dismissPip());
                     }
                 }
             } catch (NameNotFoundException e) {
@@ -63,12 +62,12 @@
     };
 
     public PipAppOpsListener(Context context, IActivityManager activityManager,
-            PipMotionHelper motionHelper) {
+            Callback callback) {
         mContext = context;
         mHandler = new Handler(mContext.getMainLooper());
         mActivityManager = activityManager;
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-        mMotionHelper = motionHelper;
+        mCallback = callback;
     }
 
     public void onActivityPinned(String packageName) {
@@ -89,4 +88,10 @@
     private void unregisterAppOpsListener() {
         mAppOpsManager.stopWatchingMode(mAppOpsChangedListener);
     }
-}
\ No newline at end of file
+
+    /** Callback for PipAppOpsListener to request changes to the PIP window. */
+    public interface Callback {
+        /** Dismisses the PIP window. */
+        void dismissPip();
+    }
+}
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 3858356..82aa473 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -55,7 +55,7 @@
 /**
  * A helper to animate and manipulate the PiP.
  */
-public class PipMotionHelper implements Handler.Callback {
+public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Callback {
 
     private static final String TAG = "PipMotionHelper";
     private static final boolean DEBUG = false;
@@ -172,7 +172,8 @@
     /**
      * Dismisses the pinned stack.
      */
-    void dismissPip() {
+    @Override
+    public void dismissPip() {
         if (DEBUG) {
             Log.d(TAG, "dismissPip: callers=\n" + Debug.getCallers(5, "    "));
         }
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
index 3991c19..26c6d50 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
@@ -20,6 +20,7 @@
 import android.content.DialogInterface
 import android.content.Intent
 import android.content.res.ColorStateList
+import android.util.IconDrawableFactory
 import android.view.Gravity
 import android.view.LayoutInflater
 import android.view.View
@@ -29,6 +30,7 @@
 import com.android.systemui.Dependency
 import com.android.systemui.R
 import com.android.systemui.plugins.ActivityStarter
+import java.util.concurrent.TimeUnit
 
 class OngoingPrivacyDialog constructor(
     val context: Context,
@@ -37,21 +39,35 @@
 
     private val iconSize = context.resources.getDimensionPixelSize(
             R.dimen.ongoing_appops_dialog_icon_size)
+    private val plusSize = context.resources.getDimensionPixelSize(
+            R.dimen.ongoing_appops_dialog_app_plus_size)
     private val iconColor = context.resources.getColor(
             com.android.internal.R.color.text_color_primary, context.theme)
+    private val plusColor: Int
     private val iconMargin = context.resources.getDimensionPixelSize(
             R.dimen.ongoing_appops_dialog_icon_margin)
     private val MAX_ITEMS = context.resources.getInteger(R.integer.ongoing_appops_dialog_max_apps)
+    private val iconFactory = IconDrawableFactory.newInstance(context, true)
+
+    init {
+        val a = context.theme.obtainStyledAttributes(
+                intArrayOf(com.android.internal.R.attr.colorAccent))
+        plusColor = a.getColor(0, 0)
+        a.recycle()
+    }
 
     fun createDialog(): Dialog {
         val builder = AlertDialog.Builder(context).apply {
             setNegativeButton(R.string.ongoing_privacy_dialog_cancel, null)
             setPositiveButton(R.string.ongoing_privacy_dialog_open_settings,
                     object : DialogInterface.OnClickListener {
-                        val intent = Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE)
+                        val intent = Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE).putExtra(
+                                Intent.EXTRA_DURATION_MILLIS, TimeUnit.MINUTES.toMillis(1))
 
+                        @Suppress("DEPRECATION")
                         override fun onClick(dialog: DialogInterface?, which: Int) {
-                            Dependency.get(ActivityStarter::class.java).startActivity(intent, false)
+                            Dependency.get(ActivityStarter::class.java)
+                                    .postStartActivityDismissingKeyguard(intent, 0)
                         }
                     })
         }
@@ -85,9 +101,15 @@
                     numItems - MAX_ITEMS
             )
             val overflowPlus = overflow.findViewById(R.id.app_icon) as ImageView
+            val lp = overflowPlus.layoutParams.apply {
+                height = plusSize
+                width = plusSize
+            }
+            overflowPlus.layoutParams = lp
             overflowPlus.apply {
-                imageTintList = ColorStateList.valueOf(iconColor)
-                setImageDrawable(context.getDrawable(R.drawable.plus))
+                val plus = context.getDrawable(R.drawable.plus)
+                imageTintList = ColorStateList.valueOf(plusColor)
+                setImageDrawable(plus)
             }
         }
 
@@ -112,17 +134,18 @@
         }
 
         app.icon.let {
-            appIcon.setImageDrawable(it)
+            appIcon.setImageDrawable(iconFactory.getShadowedIcon(it))
         }
 
         appName.text = app.applicationName
         if (showIcons) {
-            dialogBuilder.generateIconsForApp(types).forEach {
+            dialogBuilder.generateIconsForApp(types).forEachIndexed { index, it ->
                 it.setBounds(0, 0, iconSize, iconSize)
                 val image = ImageView(context).apply {
                     imageTintList = ColorStateList.valueOf(iconColor)
                     setImageDrawable(it)
                 }
+                image.contentDescription = types[index].getName(context)
                 icons.addView(image, lp)
             }
             icons.visibility = View.VISIBLE
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index d5b807d..b218e80 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -46,10 +46,13 @@
     }
     private var privacyList = emptyList<PrivacyItem>()
 
+    @Suppress("DEPRECATION")
     private val appOpsController = Dependency.get(AppOpsController::class.java)
     private val userManager = context.getSystemService(UserManager::class.java)
     private var currentUserIds = emptyList<Int>()
+    @Suppress("DEPRECATION")
     private val bgHandler = Handler(Dependency.get(Dependency.BG_LOOPER))
+    @Suppress("DEPRECATION")
     private val uiHandler = Dependency.get(Dependency.MAIN_HANDLER)
     private var listening = false
     val systemApp = PrivacyApplication(context.getString(R.string.device_services), context)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
index dfd3f73..2365e67 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
@@ -35,6 +35,8 @@
 import java.util.Collection;
 import java.util.Collections;
 
+import javax.inject.Inject;
+
 public class AutoAddTracker {
 
     private static final String[][] CONVERT_PREFS = {
@@ -48,6 +50,7 @@
     private final ArraySet<String> mAutoAdded;
     private final Context mContext;
 
+    @Inject
     public AutoAddTracker(Context context) {
         mContext = context;
         mAutoAdded = new ArraySet<>(getAdded());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 34d30fe..087a826 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -215,7 +215,10 @@
     }
 
     @Override
-    public void disable(int state1, int state2, boolean animate) {
+    public void disable(int displayId, int state1, int state2, boolean animate) {
+        if (displayId != getContext().getDisplayId()) {
+            return;
+        }
         state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
 
         final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 3a6b785..dfc3e66 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -56,6 +56,7 @@
 
 import javax.inject.Inject;
 import javax.inject.Named;
+import javax.inject.Provider;
 import javax.inject.Singleton;
 
 /** Platform implementation of the quick settings tile host **/
@@ -74,7 +75,7 @@
     private final PluginManager mPluginManager;
 
     private final List<Callback> mCallbacks = new ArrayList<>();
-    private final AutoTileManager mAutoTiles;
+    private AutoTileManager mAutoTiles;
     private final StatusBarIconController mIconController;
     private final ArrayList<QSFactory> mQsFactories = new ArrayList<>();
     private int mCurrentUser;
@@ -87,7 +88,8 @@
             @Named(Dependency.MAIN_HANDLER_NAME) Handler mainHandler,
             @Named(Dependency.BG_LOOPER_NAME) Looper bgLooper,
             PluginManager pluginManager,
-            TunerService tunerService) {
+            TunerService tunerService,
+            Provider<AutoTileManager> autoTiles) {
         mIconController = iconController;
         mContext = context;
         mTunerService = tunerService;
@@ -104,9 +106,9 @@
             // QSTileHost -> XXXTile -> QSTileHost. Posting ensures creation
             // finishes before creating any tiles.
             tunerService.addTunable(this, TILES_SETTING);
+            // AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
+            mAutoTiles = autoTiles.get();
         });
-        // AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
-        mAutoTiles = new AutoTileManager(context, this);
     }
 
     public StatusBarIconController getIconController() {
@@ -264,7 +266,7 @@
 
     @Override
     public void unmarkTileAsAutoAdded(String spec) {
-        mAutoTiles.unmarkTileAsAutoAdded(spec);
+        if (mAutoTiles != null) mAutoTiles.unmarkTileAsAutoAdded(spec);
     }
 
     public void addTile(String spec) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 7224599..75ab5df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -141,14 +141,11 @@
     private View mStatusSeparator;
     private ImageView mRingerModeIcon;
     private TextView mRingerModeTextView;
-    private BatteryMeterView mBatteryMeterView;
     private Clock mClockView;
     private DateView mDateView;
     private OngoingPrivacyChip mPrivacyChip;
     private Space mSpace;
     private BatteryMeterView mBatteryRemainingIcon;
-    private TextView mBatteryRemainingText;
-    private boolean mShowBatteryPercentAndEstimate;
 
     private PrivacyItemController mPrivacyItemController;
     /** Counts how many times the long press tooltip has been shown to the user. */
@@ -229,13 +226,6 @@
         // Set the correct tint for the status icons so they contrast
         mIconManager.setTint(fillColor);
 
-        mShowBatteryPercentAndEstimate = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_battery_percentage_setting_available);
-
-        mBatteryMeterView = findViewById(R.id.battery);
-        mBatteryMeterView.setPercentShowMode(mShowBatteryPercentAndEstimate
-                ? BatteryMeterView.MODE_ON : BatteryMeterView.MODE_OFF);
-        mBatteryMeterView.setOnClickListener(this);
         mClockView = findViewById(R.id.clock);
         mClockView.setOnClickListener(this);
         mDateView = findViewById(R.id.date);
@@ -245,13 +235,8 @@
 
         // Tint for the battery icons are handled in setupHost()
         mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
-        mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_OFF);
         // Don't need to worry about tuner settings for this icon
         mBatteryRemainingIcon.setIgnoreTunerUpdates(true);
-
-        mBatteryRemainingText = findViewById(R.id.batteryRemainingText);
-        mBatteryRemainingText.setTextColor(fillColor);
-
         updateShowPercent();
     }
 
@@ -268,10 +253,8 @@
     }
 
     private void setChipVisibility(boolean chipVisible) {
-        mBatteryMeterView.setVisibility(View.VISIBLE);
         if (chipVisible) {
             mPrivacyChip.setVisibility(View.VISIBLE);
-            if (mHasTopCutout) mBatteryMeterView.setVisibility(View.GONE);
         } else {
             mPrivacyChip.setVisibility(View.GONE);
         }
@@ -339,7 +322,6 @@
         // Update color schemes in landscape to use wallpaperTextColor
         boolean shouldUseWallpaperTextColor =
                 newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
-        mBatteryMeterView.useWallpaperTextColor(shouldUseWallpaperTextColor);
         mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor);
     }
 
@@ -415,17 +397,11 @@
                 .build();
     }
 
-    private void updateBatteryRemainingText() {
-        if (!mShowBatteryPercentAndEstimate) {
-            return;
-        }
-        mBatteryRemainingText.setText(mBatteryController.getEstimatedTimeRemainingString());
-    }
-
     public void setExpanded(boolean expanded) {
         if (mExpanded == expanded) return;
         mExpanded = expanded;
         mHeaderQsPanel.setExpanded(expanded);
+        updateEverything();
     }
 
     /**
@@ -518,7 +494,6 @@
             }
         }
         mSpace.setLayoutParams(lp);
-        // Decide whether to show BatteryMeterView
         setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
         return super.onApplyWindowInsets(insets);
     }
@@ -545,7 +520,6 @@
             mAlarmController.addCallback(this);
             mContext.registerReceiver(mRingerReceiver,
                     new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
-            updateBatteryRemainingText();
         } else {
             mZenController.removeCallback(this);
             mAlarmController.removeCallback(this);
@@ -558,9 +532,6 @@
         if (v == mClockView) {
             mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
                     AlarmClock.ACTION_SHOW_ALARMS),0);
-        } else if (v == mBatteryMeterView) {
-            mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
-                    Intent.ACTION_POWER_USAGE_SUMMARY),0);
         } else if (v == mPrivacyChip) {
             Handler mUiHandler = new Handler(Looper.getMainLooper());
             mUiHandler.post(() -> {
@@ -697,6 +668,10 @@
                 .start();
     }
 
+    public void updateEverything() {
+        post(() -> setClickable(!mExpanded));
+    }
+
     public void setQSPanel(final QSPanel qsPanel) {
         mQsPanel = qsPanel;
         setupHost(qsPanel.getHost());
@@ -708,9 +683,6 @@
         mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
         mHeaderQsPanel.setHost(host, null /* No customization in header */);
 
-        // Use SystemUI context to get battery meter colors, and let it use the default tint (white)
-        mBatteryMeterView.setColorsFromContext(mHost.getContext());
-        mBatteryMeterView.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
 
         Rect tintArea = new Rect(0, 0, 0, 0);
         int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
@@ -758,22 +730,8 @@
                 .getIntForUser(getContext().getContentResolver(),
                         SHOW_BATTERY_PERCENT, 0, ActivityManager.getCurrentUser());
 
-        mShowBatteryPercentAndEstimate = systemSetting;
-
-        updateBatteryViews();
-    }
-
-    private void updateBatteryViews() {
-        if (mShowBatteryPercentAndEstimate) {
-            mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_ON);
-            mBatteryRemainingIcon.setVisibility(View.VISIBLE);
-            mBatteryRemainingText.setVisibility(View.VISIBLE);
-            updateBatteryRemainingText();
-        } else {
-            mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_OFF);
-            mBatteryRemainingIcon.setVisibility(View.GONE);
-            mBatteryRemainingText.setVisibility(View.GONE);
-        }
+        mBatteryRemainingIcon.setPercentShowMode(systemSetting
+                ? BatteryMeterView.MODE_ESTIMATE : BatteryMeterView.MODE_ON);
     }
 
     private final class PercentSettingObserver extends ContentObserver {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 1155a41..e1becdb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -188,7 +188,7 @@
             state.secondaryLabel = r.getString(R.string.status_bar_airplane);
         } else if (mobileDataEnabled) {
             state.state = Tile.STATE_ACTIVE;
-            state.secondaryLabel = getMobileDataDescription(cb);
+            state.secondaryLabel = getMobileDataSubscriptionName(cb);
         } else {
             state.state = Tile.STATE_INACTIVE;
             state.secondaryLabel = r.getString(R.string.cell_data_off);
@@ -207,16 +207,16 @@
         state.contentDescription = state.label + ", " + contentDescriptionSuffix;
     }
 
-    private CharSequence getMobileDataDescription(CallbackInfo cb) {
-        if (cb.roaming && !TextUtils.isEmpty(cb.dataContentDescription)) {
+    private CharSequence getMobileDataSubscriptionName(CallbackInfo cb) {
+        if (cb.roaming && !TextUtils.isEmpty(cb.dataSubscriptionName)) {
             String roaming = mContext.getString(R.string.data_connection_roaming);
-            String dataDescription = cb.dataContentDescription;
+            String dataDescription = cb.dataSubscriptionName.toString();
             return mContext.getString(R.string.mobile_data_text_format, roaming, dataDescription);
         }
         if (cb.roaming) {
             return mContext.getString(R.string.data_connection_roaming);
         }
-        return cb.dataContentDescription;
+        return cb.dataSubscriptionName;
     }
 
     @Override
@@ -231,7 +231,7 @@
 
     private static final class CallbackInfo {
         boolean airplaneModeEnabled;
-        String dataContentDescription;
+        CharSequence dataSubscriptionName;
         boolean activityIn;
         boolean activityOut;
         boolean noSim;
@@ -249,7 +249,7 @@
                 // Not data sim, don't display.
                 return;
             }
-            mInfo.dataContentDescription = typeContentDescription;
+            mInfo.dataSubscriptionName = mController.getMobileDataNetworkName();
             mInfo.activityIn = activityIn;
             mInfo.activityOut = activityOut;
             mInfo.roaming = roaming;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
index 5230cea..7ee37d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
@@ -84,7 +84,7 @@
 
     @Override
     public Intent getLongClickIntent() {
-        return null;
+        return new Intent();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 81757d0..c474faf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -101,6 +101,7 @@
     private float mBackButtonAlpha;
     private MotionEvent mStatusBarGestureDownEvent;
     private float mWindowCornerRadius;
+    private boolean mSupportsRoundedCornersOnWindows;
 
     private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
 
@@ -244,6 +245,18 @@
             }
         }
 
+        public boolean supportsRoundedCornersOnWindows() {
+            if (!verifyCaller("supportsRoundedCornersOnWindows")) {
+                return false;
+            }
+            long token = Binder.clearCallingIdentity();
+            try {
+                return mSupportsRoundedCornersOnWindows;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
         private boolean verifyCaller(String reason) {
             final int callerId = Binder.getCallingUserHandle().getIdentifier();
             if (callerId != mCurrentBoundedUserId) {
@@ -353,6 +366,8 @@
         mInteractionFlags = Prefs.getInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS,
                 getDefaultInteractionFlags());
         mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources());
+        mSupportsRoundedCornersOnWindows = ScreenDecorationsUtils
+                .supportsRoundedCornersOnWindows(mContext.getResources());
 
         // Listen for the package update changes.
         if (mDeviceProvisionedController.getCurrentUser() == UserHandle.USER_SYSTEM) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index f13b565..0fc4fe7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -54,8 +54,10 @@
     }
 
     @Override
-    public void appTransitionFinished() {
-        mImpl.onAppTransitionFinished();
+    public void appTransitionFinished(int displayId) {
+        if (mContext.getDisplayId() == displayId) {
+            mImpl.onAppTransitionFinished();
+        }
     }
 
     public void growRecents() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index bc38169..a776d0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar;
 
-import static com.android.systemui.statusbar.notification.NotificationData.Entry;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Handler;
@@ -29,6 +27,7 @@
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
 
 import java.util.stream.Stream;
@@ -48,7 +47,7 @@
      * NotificationManagerService side, but we keep it to prevent the UI from looking weird and
      * will remove when possible. See {@link NotificationLifetimeExtender}
      */
-    protected final ArraySet<Entry> mExtendedLifetimeAlertEntries = new ArraySet<>();
+    protected final ArraySet<NotificationEntry> mExtendedLifetimeAlertEntries = new ArraySet<>();
 
     protected NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback;
     protected int mMinimumDisplayTime;
@@ -61,7 +60,7 @@
      * Adds the notification to be managed.
      * @param entry entry to show
      */
-    public void showNotification(@NonNull Entry entry) {
+    public void showNotification(@NonNull NotificationEntry entry) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "showNotification");
         }
@@ -139,7 +138,7 @@
      * @return the entry
      */
     @Nullable
-    public Entry getEntry(@NonNull String key) {
+    public NotificationEntry getEntry(@NonNull String key) {
         AlertEntry entry = mAlertEntries.get(key);
         return entry != null ? entry.mEntry : null;
     }
@@ -149,7 +148,7 @@
      * @return all entries
      */
     @NonNull
-    public Stream<Entry> getAllEntries() {
+    public Stream<NotificationEntry> getAllEntries() {
         return mAlertEntries.values().stream().map(headsUpEntry -> headsUpEntry.mEntry);
     }
 
@@ -180,7 +179,7 @@
      * Add a new entry and begin managing it.
      * @param entry the entry to add
      */
-    protected final void addAlertEntry(@NonNull Entry entry) {
+    protected final void addAlertEntry(@NonNull NotificationEntry entry) {
         AlertEntry alertEntry = createAlertEntry();
         alertEntry.setEntry(entry);
         mAlertEntries.put(entry.key, alertEntry);
@@ -203,7 +202,7 @@
         if (alertEntry == null) {
             return;
         }
-        Entry entry = alertEntry.mEntry;
+        NotificationEntry entry = alertEntry.mEntry;
         mAlertEntries.remove(key);
         onAlertEntryRemoved(alertEntry);
         entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
@@ -250,12 +249,12 @@
     }
 
     @Override
-    public boolean shouldExtendLifetime(Entry entry) {
+    public boolean shouldExtendLifetime(NotificationEntry entry) {
         return !canRemoveImmediately(entry.key);
     }
 
     @Override
-    public void setShouldManageLifetime(Entry entry, boolean shouldExtend) {
+    public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) {
         if (shouldExtend) {
             mExtendedLifetimeAlertEntries.add(entry);
         } else {
@@ -265,17 +264,17 @@
     ///////////////////////////////////////////////////////////////////////////////////////////////
 
     protected class AlertEntry implements Comparable<AlertEntry> {
-        @Nullable public Entry mEntry;
+        @Nullable public NotificationEntry mEntry;
         public long mPostTime;
         public long mEarliestRemovaltime;
 
         @Nullable protected Runnable mRemoveAlertRunnable;
 
-        public void setEntry(@NonNull final Entry entry) {
+        public void setEntry(@NonNull final NotificationEntry entry) {
             setEntry(entry, () -> removeAlertEntry(entry.key));
         }
 
-        public void setEntry(@NonNull final Entry entry,
+        public void setEntry(@NonNull final NotificationEntry entry,
                 @Nullable Runnable removeAlertRunnable) {
             mEntry = entry;
             mRemoveAlertRunnable = removeAlertRunnable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
index 9bfd4ee..a3beb96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
@@ -25,7 +25,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
 
 import javax.inject.Inject;
@@ -83,7 +83,7 @@
 
     @Override
     protected void onAlertEntryAdded(AlertEntry alertEntry) {
-        NotificationData.Entry entry = alertEntry.mEntry;
+        NotificationEntry entry = alertEntry.mEntry;
         entry.setAmbientPulsing(true);
         for (OnAmbientChangedListener listener : mListeners) {
             listener.onAmbientStateChanged(entry, true);
@@ -92,7 +92,7 @@
 
     @Override
     protected void onAlertEntryRemoved(AlertEntry alertEntry) {
-        NotificationData.Entry entry = alertEntry.mEntry;
+        NotificationEntry entry = alertEntry.mEntry;
         entry.setAmbientPulsing(false);
         for (OnAmbientChangedListener listener : mListeners) {
             listener.onAmbientStateChanged(entry, false);
@@ -131,7 +131,7 @@
          * @param entry the entry that changed
          * @param isPulsing true if the entry is now pulsing, false otherwise
          */
-        void onAmbientStateChanged(NotificationData.Entry entry, boolean isPulsing);
+        void onAmbientStateChanged(NotificationEntry entry, boolean isPulsing);
     }
 
     private final class AmbientEntry extends AlertEntry {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 95019ee..904478e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -16,18 +16,30 @@
 
 package com.android.systemui.statusbar;
 
+import static android.app.StatusBarManager.DISABLE2_NONE;
+import static android.app.StatusBarManager.DISABLE_NONE;
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS;
 
 import android.app.StatusBarManager;
+import android.app.StatusBarManager.Disable2Flags;
+import android.app.StatusBarManager.DisableFlags;
+import android.app.StatusBarManager.WindowType;
+import android.app.StatusBarManager.WindowVisibleState;
 import android.content.ComponentName;
+import android.content.Context;
 import android.graphics.Rect;
 import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.hardware.display.DisplayManager;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.util.Pair;
+import android.util.SparseArray;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -47,7 +59,8 @@
  * coalescing these calls so they don't stack up.  For the calls
  * are coalesced, note that they are all idempotent.
  */
-public class CommandQueue extends IStatusBar.Stub implements CallbackController<Callbacks> {
+public class CommandQueue extends IStatusBar.Stub implements CallbackController<Callbacks>,
+        DisplayManager.DisplayListener {
     private static final int INDEX_MASK = 0xffff;
     private static final int MSG_SHIFT  = 16;
     private static final int MSG_MASK   = 0xffff << MSG_SHIFT;
@@ -98,7 +111,6 @@
     private static final int MSG_SHOW_CHARGING_ANIMATION       = 44 << MSG_SHIFT;
     private static final int MSG_SHOW_PINNING_TOAST_ENTER_EXIT = 45 << MSG_SHIFT;
     private static final int MSG_SHOW_PINNING_TOAST_ESCAPE     = 46 << MSG_SHIFT;
-    private static final int MSG_BIOMETRIC_TRY_AGAIN           = 47 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -112,8 +124,8 @@
     private final Object mLock = new Object();
     private ArrayList<Callbacks> mCallbacks = new ArrayList<>();
     private Handler mHandler = new H(Looper.getMainLooper());
-    private int mDisable1;
-    private int mDisable2;
+    /** A map of display id - disable flag pair */
+    private SparseArray<Pair<Integer, Integer>> mDisplayDisabled = new SparseArray<>();
 
     /**
      * These methods are called back on the main thread.
@@ -121,17 +133,63 @@
     public interface Callbacks {
         default void setIcon(String slot, StatusBarIcon icon) { }
         default void removeIcon(String slot) { }
-        default void disable(int state1, int state2, boolean animate) { }
+
+        /**
+         * Called to notify that disable flags are updated.
+         * @see IStatusBar#disable(int, int, int).
+         *
+         * @param displayId The id of the display to notify.
+         * @param state1 The combination of following DISABLE_* flags:
+         * @param state2 The combination of following DISABLE2_* flags:
+         * @param animate {@code true} to show animations.
+         */
+        default void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2,
+                boolean animate) { }
         default void animateExpandNotificationsPanel() { }
         default void animateCollapsePanels(int flags, boolean force) { }
         default void togglePanel() { }
         default void animateExpandSettingsPanel(String obj) { }
-        default void setSystemUiVisibility(int vis, int fullscreenStackVis,
+
+        /**
+         * Called to notify visibility flag changes.
+         * @see IStatusBar#setSystemUiVisibility(int, int, int, int, int, Rect, Rect).
+         *
+         * @param displayId The id of the display to notify.
+         * @param vis The visibility flags except SYSTEM_UI_FLAG_LIGHT_STATUS_BAR which will
+         *            be reported separately in fullscreenStackVis and dockedStackVis.
+         * @param fullscreenStackVis The flags which only apply in the region of the fullscreen
+         *                           stack, which is currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
+         * @param dockedStackVis The flags that only apply in the region of the docked stack, which
+         *                       is currently only SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
+         * @param mask Which flags to change.
+         * @param fullscreenStackBounds The current bounds of the fullscreen stack, in screen
+         *                              coordinates.
+         * @param dockedStackBounds The current bounds of the docked stack, in screen coordinates.
+         */
+        default void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
                 int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
         }
-        default void topAppWindowChanged(boolean visible) { }
-        default void setImeWindowStatus(IBinder token, int vis, int backDisposition,
-                boolean showImeSwitcher) { }
+
+        /**
+         * Called to notify top app window changes.
+         * @see IStatusBar#topAppWindowChanged(int, boolean)
+         *
+         * @param displayId The id of the display to notify.
+         * @param visible {@code true} to show menu button.
+         */
+        default void topAppWindowChanged(int displayId, boolean visible) { }
+
+        /**
+         * Called to notify IME window status changes.
+         *
+         * @param displayId The id of the display to notify.
+         * @param token IME token.
+         * @param vis IME visibility.
+         * @param backDisposition Disposition mode of back button. It should be one of below flags:
+         * @param showImeSwitcher {@code true} to show IME switch button.
+         */
+        default void setImeWindowStatus(int displayId, IBinder token,  int vis,
+                @BackDispositionMode int backDisposition, boolean showImeSwitcher) { }
         default void showRecentApps(boolean triggeredFromAltTab) { }
         default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
         default void toggleRecentApps() { }
@@ -140,12 +198,56 @@
         default void dismissKeyboardShortcutsMenu() { }
         default void toggleKeyboardShortcutsMenu(int deviceId) { }
         default void cancelPreloadRecentApps() { }
-        default void setWindowState(int window, int state) { }
+
+        /**
+         * Called to notify window state changes.
+         * @see IStatusBar#setWindowState(int, int, int)
+         *
+         * @param displayId The id of the display to notify.
+         * @param window Window type. It should be one of {@link StatusBarManager#WINDOW_STATUS_BAR}
+         *               or {@link StatusBarManager#WINDOW_NAVIGATION_BAR}
+         * @param state Window visible state.
+         */
+        default void setWindowState(int displayId, @WindowType int window,
+                @WindowVisibleState int state) { }
         default void showScreenPinningRequest(int taskId) { }
-        default void appTransitionPending(boolean forced) { }
-        default void appTransitionCancelled() { }
-        default void appTransitionStarting(long startTime, long duration, boolean forced) { }
-        default void appTransitionFinished() { }
+
+        /**
+         * Called to notify System UI that an application transition is pending.
+         * @see IStatusBar#appTransitionPending(int).
+         *
+         * @param displayId The id of the display to notify.
+         * @param forced {@code true} to force transition pending.
+         */
+        default void appTransitionPending(int displayId, boolean forced) { }
+
+        /**
+         * Called to notify System UI that an application transition is canceled.
+         * @see IStatusBar#appTransitionCancelled(int).
+         *
+         * @param displayId The id of the display to notify.
+         */
+        default void appTransitionCancelled(int displayId) { }
+
+        /**
+         * Called to notify System UI that an application transition is starting.
+         * @see IStatusBar#appTransitionStarting(int, long, long).
+         *
+         * @param displayId The id of the display to notify.
+         * @param startTime Transition start time.
+         * @param duration Transition duration.
+         * @param forced {@code true} to force transition pending.
+         */
+        default void appTransitionStarting(
+                int displayId, long startTime, long duration, boolean forced) { }
+
+        /**
+         * Called to notify System UI that an application transition is finished.
+         * @see IStatusBar#appTransitionFinished(int)
+         *
+         * @param displayId The id of the display to notify.
+         */
+        default void appTransitionFinished(int displayId) { }
         default void showAssistDisclosure() { }
         default void startAssist(Bundle args) { }
         default void onCameraLaunchGestureDetected(int source) { }
@@ -168,26 +270,50 @@
 
         default void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver,
                 int type, boolean requireConfirmation, int userId) { }
-        default void onBiometricAuthenticated() { }
+        default void onBiometricAuthenticated(boolean authenticated) { }
         default void onBiometricHelp(String message) { }
         default void onBiometricError(String error) { }
         default void hideBiometricDialog() { }
-        default void showBiometricTryAgain() { }
     }
 
     @VisibleForTesting
-    public CommandQueue() {
+    public CommandQueue(Context context) {
+        context.getSystemService(DisplayManager.class).registerDisplayListener(this, mHandler);
+        // We always have default display.
+        setDisabled(DEFAULT_DISPLAY, DISABLE_NONE, DISABLE2_NONE);
     }
 
+    @Override
+    public void onDisplayAdded(int displayId) { }
+
+    @Override
+    public void onDisplayRemoved(int displayId) {
+        synchronized (mLock) {
+            mDisplayDisabled.remove(displayId);
+        }
+    }
+
+    @Override
+    public void onDisplayChanged(int displayId) { }
+
+    // TODO(b/118592525): add multi-display support if needed.
     public boolean panelsEnabled() {
-        return (mDisable1 & StatusBarManager.DISABLE_EXPAND) == 0
-                && (mDisable2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
+        final int disabled1 = getDisabled1(DEFAULT_DISPLAY);
+        final int disabled2 = getDisabled2(DEFAULT_DISPLAY);
+        return (disabled1 & StatusBarManager.DISABLE_EXPAND) == 0
+                && (disabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
                 && !ONLY_CORE_APPS;
     }
 
     public void addCallback(Callbacks callbacks) {
         mCallbacks.add(callbacks);
-        callbacks.disable(mDisable1, mDisable2, false /* animate */);
+        // TODO(b/117478341): find a better way to pass disable flags by display.
+        for (int i = 0; i < mDisplayDisabled.size(); i++) {
+            int displayId = mDisplayDisabled.keyAt(i);
+            int disabled1 = getDisabled1(displayId);
+            int disabled2 = getDisabled2(displayId);
+            callbacks.disable(displayId, disabled1, disabled2, false /* animate */);
+        }
     }
 
     public void removeCallback(Callbacks callbacks) {
@@ -209,12 +335,21 @@
         }
     }
 
-    public void disable(int state1, int state2, boolean animate) {
+    /**
+     * Called to notify that disable flags are updated.
+     * @see Callbacks#disable(int, int, int, boolean).
+     */
+    public void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2,
+            boolean animate) {
         synchronized (mLock) {
-            mDisable1 = state1;
-            mDisable2 = state2;
+            setDisabled(displayId, state1, state2);
             mHandler.removeMessages(MSG_DISABLE);
-            Message msg = mHandler.obtainMessage(MSG_DISABLE, state1, state2, animate);
+            final SomeArgs args = SomeArgs.obtain();
+            args.argi1 = displayId;
+            args.argi2 = state1;
+            args.argi3 = state2;
+            args.argi4 = animate ? 1 : 0;
+            Message msg = mHandler.obtainMessage(MSG_DISABLE, args);
             if (Looper.myLooper() == mHandler.getLooper()) {
                 // If its the right looper execute immediately so hides can be handled quickly.
                 mHandler.handleMessage(msg);
@@ -225,14 +360,42 @@
         }
     }
 
-    // TODO(b/117478341): Add multi-display support.
     @Override
-    public void disable(int displayId, int state1, int state2) {
-        disable(state1, state2, true);
+    public void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2) {
+        disable(displayId, state1, state2, true);
     }
 
-    public void recomputeDisableFlags(boolean animate) {
-        disable(mDisable1, mDisable2, animate);
+    /**
+     * Apply current disable flags by {@link CommandQueue#disable(int, int, int, boolean)}.
+     *
+     * @param displayId The id of the display to notify.
+     * @param animate {@code true} to show animations.
+     */
+    public void recomputeDisableFlags(int displayId, boolean animate) {
+        int disabled1 = getDisabled1(displayId);
+        int disabled2 = getDisabled2(displayId);
+        disable(displayId, disabled1, disabled2, animate);
+    }
+
+    private void setDisabled(int displayId, int disabled1, int disabled2) {
+        mDisplayDisabled.put(displayId, new Pair<>(disabled1, disabled2));
+    }
+
+    private int getDisabled1(int displayId) {
+        return getDisabled(displayId).first;
+    }
+
+    private int getDisabled2(int displayId) {
+        return getDisabled(displayId).second;
+    }
+
+    private Pair<Integer, Integer> getDisabled(int displayId) {
+        Pair<Integer, Integer> disablePair = mDisplayDisabled.get(displayId);
+        if (disablePair == null) {
+            disablePair = new Pair<>(DISABLE_NONE, DISABLE2_NONE);
+            mDisplayDisabled.put(displayId, disablePair);
+        }
+        return disablePair;
     }
 
     public void animateExpandNotificationsPanel() {
@@ -270,7 +433,6 @@
         }
     }
 
-    // TODO(b/117478341): Add multi-display support.
     @Override
     public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
             int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
@@ -278,34 +440,38 @@
             // Don't coalesce these, since it might have one time flags set such as
             // STATUS_BAR_UNHIDE which might get lost.
             SomeArgs args = SomeArgs.obtain();
-            args.argi1 = vis;
-            args.argi2 = fullscreenStackVis;
-            args.argi3 = dockedStackVis;
-            args.argi4 = mask;
+            args.argi1 = displayId;
+            args.argi2 = vis;
+            args.argi3 = fullscreenStackVis;
+            args.argi4 = dockedStackVis;
+            args.argi5 = mask;
             args.arg1 = fullscreenStackBounds;
             args.arg2 = dockedStackBounds;
             mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, args).sendToTarget();
         }
     }
 
-    // TODO(b/117478341): Add multi-display support.
     @Override
     public void topAppWindowChanged(int displayId, boolean menuVisible) {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_TOP_APP_WINDOW_CHANGED);
-            mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED, menuVisible ? 1 : 0, 0,
-                    null).sendToTarget();
+            mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED,
+                    displayId, menuVisible ? 1 : 0, null).sendToTarget();
         }
     }
 
-    // TODO(b/117478341): Add multi-display support.
     @Override
     public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher) {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
-            Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token);
-            m.getData().putBoolean(SHOW_IME_SWITCHER_KEY, showImeSwitcher);
+            SomeArgs args = SomeArgs.obtain();
+            args.argi1 = displayId;
+            args.argi2 = vis;
+            args.argi3 = backDisposition;
+            args.argi4 = showImeSwitcher ? 1 : 0;
+            args.arg1 = token;
+            Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, args);
             m.sendToTarget();
         }
     }
@@ -381,12 +547,11 @@
         }
     }
 
-    // TODO(b/117478341): Add multi-display support.
     @Override
     public void setWindowState(int displayId, int window, int state) {
         synchronized (mLock) {
             // don't coalesce these
-            mHandler.obtainMessage(MSG_SET_WINDOW_STATE, window, state, null).sendToTarget();
+            mHandler.obtainMessage(MSG_SET_WINDOW_STATE, displayId, window, state).sendToTarget();
         }
     }
 
@@ -397,44 +562,54 @@
         }
     }
 
-    // TODO(b/117478341): Add multi-display support.
     @Override
     public void appTransitionPending(int displayId) {
-        appTransitionPending(false /* forced */);
+        appTransitionPending(displayId, false /* forced */);
     }
 
-    public void appTransitionPending(boolean forced) {
+    /**
+     * Called to notify System UI that an application transition is pending.
+     * @see Callbacks#appTransitionPending(int, boolean)
+     */
+    public void appTransitionPending(int displayId, boolean forced) {
         synchronized (mLock) {
-            mHandler.obtainMessage(MSG_APP_TRANSITION_PENDING, forced ? 1 : 0, 0).sendToTarget();
+            mHandler.obtainMessage(MSG_APP_TRANSITION_PENDING, displayId, forced ? 1 : 0)
+                    .sendToTarget();
         }
     }
 
-    // TODO(b/117478341): Add multi-display support.
     @Override
     public void appTransitionCancelled(int displayId) {
         synchronized (mLock) {
-            mHandler.sendEmptyMessage(MSG_APP_TRANSITION_CANCELLED);
+            mHandler.obtainMessage(MSG_APP_TRANSITION_CANCELLED, displayId).sendToTarget();
         }
     }
 
-    // TODO(b/117478341): Add multi-display support.
     @Override
     public void appTransitionStarting(int displayId, long startTime, long duration) {
-        appTransitionStarting(startTime, duration, false /* forced */);
+        appTransitionStarting(displayId, startTime, duration, false /* forced */);
     }
 
-    public void appTransitionStarting(long startTime, long duration, boolean forced) {
+    /**
+     * Called to notify System UI that an application transition is starting.
+     * @see Callbacks#appTransitionStarting(int, long, long, boolean).
+     */
+    public void appTransitionStarting(int displayId, long startTime, long duration,
+            boolean forced) {
         synchronized (mLock) {
-            mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, forced ? 1 : 0, 0,
-                    Pair.create(startTime, duration)).sendToTarget();
+            final SomeArgs args = SomeArgs.obtain();
+            args.argi1 = displayId;
+            args.argi2 = forced ? 1 : 0;
+            args.arg1 = startTime;
+            args.arg2 = duration;
+            mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, args).sendToTarget();
         }
     }
 
-    // TODO(b/117478341): Add multi-display support.
     @Override
     public void appTransitionFinished(int displayId) {
         synchronized (mLock) {
-            mHandler.sendEmptyMessage(MSG_APP_TRANSITION_FINISHED);
+            mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId).sendToTarget();
         }
     }
 
@@ -559,9 +734,9 @@
     }
 
     @Override
-    public void onBiometricAuthenticated() {
+    public void onBiometricAuthenticated(boolean authenticated) {
         synchronized (mLock) {
-            mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED).sendToTarget();
+            mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, authenticated).sendToTarget();
         }
     }
 
@@ -586,13 +761,6 @@
         }
     }
 
-    @Override
-    public void showBiometricTryAgain() {
-        synchronized (mLock) {
-            mHandler.obtainMessage(MSG_BIOMETRIC_TRY_AGAIN).sendToTarget();
-        }
-    }
-
     private final class H extends Handler {
         private H(Looper l) {
             super(l);
@@ -619,8 +787,10 @@
                     break;
                 }
                 case MSG_DISABLE:
+                    SomeArgs args = (SomeArgs) msg.obj;
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).disable(msg.arg1, msg.arg2, (Boolean) msg.obj);
+                        mCallbacks.get(i).disable(args.argi1, args.argi2, args.argi3,
+                                args.argi4 != 0 /* animate */);
                     }
                     break;
                 case MSG_EXPAND_NOTIFICATIONS:
@@ -644,22 +814,23 @@
                     }
                     break;
                 case MSG_SET_SYSTEMUI_VISIBILITY:
-                    SomeArgs args = (SomeArgs) msg.obj;
+                    args = (SomeArgs) msg.obj;
                     for (int i = 0; i < mCallbacks.size(); i++) {
                         mCallbacks.get(i).setSystemUiVisibility(args.argi1, args.argi2, args.argi3,
-                                args.argi4, (Rect) args.arg1, (Rect) args.arg2);
+                                args.argi4, args.argi5, (Rect) args.arg1, (Rect) args.arg2);
                     }
                     args.recycle();
                     break;
                 case MSG_TOP_APP_WINDOW_CHANGED:
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).topAppWindowChanged(msg.arg1 != 0);
+                        mCallbacks.get(i).topAppWindowChanged(msg.arg1, msg.arg2 != 0);
                     }
                     break;
                 case MSG_SHOW_IME_BUTTON:
+                    args = (SomeArgs) msg.obj;
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2,
-                                msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false));
+                        mCallbacks.get(i).setImeWindowStatus(args.argi1, (IBinder) args.arg1,
+                                args.argi2, args.argi3, args.argi4 != 0 /* showImeSwitcher */);
                     }
                     break;
                 case MSG_SHOW_RECENT_APPS:
@@ -699,7 +870,7 @@
                     break;
                 case MSG_SET_WINDOW_STATE:
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).setWindowState(msg.arg1, msg.arg2);
+                        mCallbacks.get(i).setWindowState(msg.arg1, msg.arg2, (int) msg.obj);
                     }
                     break;
                 case MSG_SHOW_SCREEN_PIN_REQUEST:
@@ -709,24 +880,24 @@
                     break;
                 case MSG_APP_TRANSITION_PENDING:
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).appTransitionPending(msg.arg1 != 0);
+                        mCallbacks.get(i).appTransitionPending(msg.arg1, msg.arg2 != 0);
                     }
                     break;
                 case MSG_APP_TRANSITION_CANCELLED:
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).appTransitionCancelled();
+                        mCallbacks.get(i).appTransitionCancelled(msg.arg1);
                     }
                     break;
                 case MSG_APP_TRANSITION_STARTING:
+                    args = (SomeArgs) msg.obj;
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
-                        mCallbacks.get(i).appTransitionStarting(data.first, data.second,
-                                msg.arg1 != 0);
+                        mCallbacks.get(i).appTransitionStarting(args.argi1, (long) args.arg1,
+                                (long) args.arg2, args.argi2 != 0 /* forced */);
                     }
                     break;
                 case MSG_APP_TRANSITION_FINISHED:
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).appTransitionFinished();
+                        mCallbacks.get(i).appTransitionFinished(msg.arg1);
                     }
                     break;
                 case MSG_ASSIST_DISCLOSURE:
@@ -811,7 +982,7 @@
                     break;
                 case MSG_BIOMETRIC_AUTHENTICATED:
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).onBiometricAuthenticated();
+                        mCallbacks.get(i).onBiometricAuthenticated((boolean) msg.obj);
                     }
                     break;
                 case MSG_BIOMETRIC_HELP:
@@ -844,11 +1015,6 @@
                         mCallbacks.get(i).showPinningEscapeToast();
                     }
                     break;
-                case MSG_BIOMETRIC_TRY_AGAIN:
-                    for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).showBiometricTryAgain();
-                    }
-                    break;
             }
         }
     }
@@ -858,7 +1024,7 @@
     public static class CommandQueueStart extends SystemUI {
         @Override
         public void start() {
-            putComponent(CommandQueue.class, new CommandQueue());
+            putComponent(CommandQueue.class, new CommandQueue(mContext));
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
index 758fb7a..22d1d5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
@@ -18,12 +18,14 @@
 
 import android.animation.Animator;
 import android.content.Context;
+import android.util.Log;
 import android.view.ViewPropertyAnimator;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.phone.StatusBar;
 
 /**
  * Utility class to calculate general fling animation when the finger is released.
@@ -196,9 +198,16 @@
         if (startGradient != mCachedStartGradient
                 || velocityFactor != mCachedVelocityFactor) {
             float speedup = mSpeedUpFactor * (1.0f - velocityFactor);
-            mInterpolator = new PathInterpolator(speedup,
-                    speedup * startGradient,
-                    mLinearOutSlowInX2, mY2);
+            float x1 = speedup;
+            float y1 = speedup * startGradient;
+            float x2 = mLinearOutSlowInX2;
+            float y2 = mY2;
+            try {
+                mInterpolator = new PathInterpolator(x1, y1, x2, y2);
+            } catch (IllegalArgumentException e) {
+                throw new IllegalArgumentException("Illegal path with "
+                        + "x1=" + x1 + " y1=" + y1 + " x2=" + x2 + " y2=" + y2, e);
+            }
             mCachedStartGradient = startGradient;
             mCachedVelocityFactor = velocityFactor;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index e217777..3f1ff33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -32,7 +32,7 @@
 import com.android.keyguard.AlphaOptimizedLinearLayout;
 import com.android.systemui.R;
 import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import java.util.List;
 
@@ -50,7 +50,7 @@
     private int mEndMargin;
     private View mIconPlaceholder;
     private TextView mTextView;
-    private NotificationData.Entry mShowingEntry;
+    private NotificationEntry mShowingEntry;
     private Rect mLayoutedIconRect = new Rect();
     private int[] mTmpPosition = new int[2];
     private boolean mFirstLayout = true;
@@ -162,7 +162,7 @@
         mTextView = findViewById(R.id.text);
     }
 
-    public void setEntry(NotificationData.Entry entry) {
+    public void setEntry(NotificationEntry entry) {
         if (entry != null) {
             mShowingEntry = entry;
             CharSequence text = entry.headsUpStatusBarText;
@@ -261,7 +261,7 @@
         return super.fitSystemWindows(insets);
     }
 
-    public NotificationData.Entry getShowingEntry() {
+    public NotificationEntry getShowingEntry() {
         return mShowingEntry;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 43eaff4..9740d1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -34,6 +34,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.phone.AutoHideController;
 import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.NavigationBarFragment;
@@ -132,12 +133,21 @@
             // Unfortunately, we still need it because status bar needs LightBarController
             // before notifications creation. We cannot directly use getLightBarController()
             // from NavigationBarFragment directly.
-            LightBarController controller = isOnDefaultDisplay
+            LightBarController lightBarController = isOnDefaultDisplay
                     ? Dependency.get(LightBarController.class)
                     : new LightBarController(context,
                             Dependency.get(DarkIconDispatcher.class),
                             Dependency.get(BatteryController.class));
-            navBar.setLightBarController(controller);
+            navBar.setLightBarController(lightBarController);
+
+            // TODO(b/118592525): to support multi-display, we start to add something which is
+            //                    per-display, while others may be global. I think it's time to add
+            //                    a new class maybe named DisplayDependency to solve per-display
+            //                    Dependency problem.
+            AutoHideController autoHideController = isOnDefaultDisplay
+                    ? Dependency.get(AutoHideController.class)
+                    : new AutoHideController(context, mHandler);
+            navBar.setAutoHideController(autoHideController);
             navBar.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
             mNavigationBars.append(displayId, navBar);
         });
@@ -197,15 +207,6 @@
         }
     }
 
-    /** @see NavigationBarFragment#isSemiTransparent() */
-    public boolean isSemiTransparent(int displayId) {
-        NavigationBarFragment navBar = mNavigationBars.get(displayId);
-        if (navBar != null) {
-            return navBar.isSemiTransparent();
-        }
-        return false;
-    }
-
     /** @see NavigationBarFragment#disableAnimationsDuringHide(long) */
     public void disableAnimationsDuringHide(int displayId, long delay) {
         NavigationBarFragment navBar = mNavigationBars.get(displayId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
index ecd9814..0f295ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLifetimeExtender.java
@@ -2,7 +2,7 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 /**
  * Interface for anything that may need to keep notifications managed even after
@@ -24,7 +24,7 @@
      * @param entry the entry containing the notification to check
      * @return true if the notification lifetime should be extended
      */
-    boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry);
+    boolean shouldExtendLifetime(@NonNull NotificationEntry entry);
 
     /**
      * Sets whether or not the lifetime should be managed by the extender.  In practice, if
@@ -37,7 +37,7 @@
      * @param entry the entry that needs an extended lifetime
      * @param shouldManage true if the extender should manage the entry now, false otherwise
      */
-    void setShouldManageLifetime(@NonNull NotificationData.Entry entry, boolean shouldManage);
+    void setShouldManageLifetime(@NonNull NotificationEntry entry, boolean shouldManage);
 
     /**
      * The callback for when the notification is now safe to remove (i.e. its lifetime has ended).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index bc662e3..f46ded4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -18,7 +18,7 @@
 import android.service.notification.StatusBarNotification;
 import android.util.SparseArray;
 
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 public interface NotificationLockscreenUserManager {
     String PERMISSION_SELF = "com.android.systemui.permission.SELF";
@@ -55,7 +55,7 @@
 
     void updatePublicMode();
 
-    boolean needsRedaction(Entry entry);
+    boolean needsRedaction(NotificationEntry entry);
 
     boolean userAllowsPrivateNotificationsInPublic(int currentUserId);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index bba4369..d2ce31d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -46,9 +46,10 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.recents.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.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
@@ -130,8 +131,11 @@
                     final int count =
                             getEntryManager().getNotificationData().getActiveNotifications().size();
                     final int rank = getEntryManager().getNotificationData().getRank(notificationKey);
+                    NotificationVisibility.NotificationLocation location =
+                            NotificationLogger.getNotificationLocation(
+                                    getEntryManager().getNotificationData().get(notificationKey));
                     final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
-                            rank, count, true);
+                            rank, count, true, location);
                     try {
                         mBarService.onNotificationClick(notificationKey, nv);
                     } catch (RemoteException e) {
@@ -407,7 +411,7 @@
     }
 
     /** @return true if the entry needs redaction when on the lockscreen. */
-    public boolean needsRedaction(NotificationData.Entry ent) {
+    public boolean needsRedaction(NotificationEntry ent) {
         int userId = ent.notification.getUserId();
 
         boolean currentUserWantsRedaction = !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 1bf101c..7412702 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -37,7 +37,6 @@
 import android.os.Handler;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.service.notification.StatusBarNotification;
 import android.util.Log;
 import android.view.View;
 import android.widget.ImageView;
@@ -47,9 +46,9 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.Interpolators;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.LockscreenWallpaper;
 import com.android.systemui.statusbar.phone.ScrimController;
@@ -157,15 +156,10 @@
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
             public void onEntryRemoved(
-                    @Nullable Entry entry,
-                    String key,
-                    StatusBarNotification old,
+                    NotificationEntry entry,
                     NotificationVisibility visibility,
-                    boolean lifetimeExtended,
                     boolean removedByUser) {
-                if (!lifetimeExtended) {
-                    onNotificationRemoved(key);
-                }
+                onNotificationRemoved(entry.key);
             }
         });
     }
@@ -194,7 +188,7 @@
             return null;
         }
         synchronized (mEntryManager.getNotificationData()) {
-            Entry entry = mEntryManager.getNotificationData().get(mMediaNotificationKey);
+            NotificationEntry entry = mEntryManager.getNotificationData().get(mMediaNotificationKey);
             if (entry == null || entry.expandedIcon == null) {
                 return null;
             }
@@ -216,15 +210,15 @@
         boolean metaDataChanged = false;
 
         synchronized (mEntryManager.getNotificationData()) {
-            ArrayList<Entry> activeNotifications =
+            ArrayList<NotificationEntry> activeNotifications =
                     mEntryManager.getNotificationData().getActiveNotifications();
             final int N = activeNotifications.size();
 
             // Promote the media notification with a controller in 'playing' state, if any.
-            Entry mediaNotification = null;
+            NotificationEntry mediaNotification = null;
             MediaController controller = null;
             for (int i = 0; i < N; i++) {
-                final Entry entry = activeNotifications.get(i);
+                final NotificationEntry entry = activeNotifications.get(i);
 
                 if (entry.isMediaNotification()) {
                     final MediaSession.Token token =
@@ -264,7 +258,7 @@
                             final String pkg = aController.getPackageName();
 
                             for (int i = 0; i < N; i++) {
-                                final Entry entry = activeNotifications.get(i);
+                                final NotificationEntry entry = activeNotifications.get(i);
                                 if (entry.notification.getPackageName().equals(pkg)) {
                                     if (DEBUG_MEDIA) {
                                         Log.v(TAG, "DEBUG_MEDIA: found controller matching "
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 886d99e..31d1621 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -51,9 +51,10 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dumpable;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -103,7 +104,7 @@
      * Notifications that are already removed but are kept around because the remote input is
      * actively being used (i.e. user is typing in it).  See {@link RemoteInputActiveExtender}.
      */
-    protected final ArraySet<NotificationData.Entry> mEntriesKeptForRemoteInputActive =
+    protected final ArraySet<NotificationEntry> mEntriesKeptForRemoteInputActive =
             new ArraySet<>();
 
     // Dependencies:
@@ -181,7 +182,11 @@
             final int rank = mEntryManager.getNotificationData().getRank(key);
             final Notification.Action action =
                     statusBarNotification.getNotification().actions[actionIndex];
-            final NotificationVisibility nv = NotificationVisibility.obtain(key, rank, count, true);
+            NotificationVisibility.NotificationLocation location =
+                    NotificationLogger.getNotificationLocation(
+                            mEntryManager.getNotificationData().get(key));
+            final NotificationVisibility nv =
+                    NotificationVisibility.obtain(key, rank, count, true, location);
             try {
                 mBarService.onNotificationActionClick(key, buttonIndex, action, nv, false);
             } catch (RemoteException e) {
@@ -253,14 +258,11 @@
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
             public void onEntryRemoved(
-                    @Nullable NotificationData.Entry entry,
-                    String key,
-                    StatusBarNotification old,
+                    @Nullable NotificationEntry entry,
                     NotificationVisibility visibility,
-                    boolean lifetimeExtended,
                     boolean removedByUser) {
                 if (removedByUser && entry != null) {
-                    onPerformRemoveNotification(entry, key);
+                    onPerformRemoveNotification(entry, entry.key);
                 }
             }
         });
@@ -272,7 +274,7 @@
         mRemoteInputController = new RemoteInputController(delegate);
         mRemoteInputController.addCallback(new RemoteInputController.Callback() {
             @Override
-            public void onRemoteInputSent(NotificationData.Entry entry) {
+            public void onRemoteInputSent(NotificationEntry entry) {
                 if (FORCE_REMOTE_INPUT_HISTORY
                         && isNotificationKeptForRemoteInputHistory(entry.key)) {
                     mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.key);
@@ -416,7 +418,7 @@
     }
 
     @VisibleForTesting
-    void onPerformRemoveNotification(NotificationData.Entry entry, final String key) {
+    void onPerformRemoveNotification(NotificationEntry entry, final String key) {
         if (mKeysKeptForRemoteInputHistory.contains(key)) {
             mKeysKeptForRemoteInputHistory.remove(key);
         }
@@ -427,7 +429,7 @@
 
     public void onPanelCollapsed() {
         for (int i = 0; i < mEntriesKeptForRemoteInputActive.size(); i++) {
-            NotificationData.Entry entry = mEntriesKeptForRemoteInputActive.valueAt(i);
+            NotificationEntry entry = mEntriesKeptForRemoteInputActive.valueAt(i);
             mRemoteInputController.removeRemoteInput(entry, null);
             if (mNotificationLifetimeFinishedCallback != null) {
                 mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.key);
@@ -440,7 +442,7 @@
         return mKeysKeptForRemoteInputHistory.contains(key);
     }
 
-    public boolean shouldKeepForRemoteInputHistory(NotificationData.Entry entry) {
+    public boolean shouldKeepForRemoteInputHistory(NotificationEntry entry) {
         if (entry.isDismissed()) {
             return false;
         }
@@ -450,7 +452,7 @@
         return (mRemoteInputController.isSpinning(entry.key) || entry.hasJustSentRemoteInput());
     }
 
-    public boolean shouldKeepForSmartReplyHistory(NotificationData.Entry entry) {
+    public boolean shouldKeepForSmartReplyHistory(NotificationEntry entry) {
         if (entry.isDismissed()) {
             return false;
         }
@@ -470,13 +472,13 @@
 
     @VisibleForTesting
     StatusBarNotification rebuildNotificationForCanceledSmartReplies(
-            NotificationData.Entry entry) {
+            NotificationEntry entry) {
         return rebuildNotificationWithRemoteInput(entry, null /* remoteInputTest */,
                 false /* showSpinner */);
     }
 
     @VisibleForTesting
-    StatusBarNotification rebuildNotificationWithRemoteInput(NotificationData.Entry entry,
+    StatusBarNotification rebuildNotificationWithRemoteInput(NotificationEntry entry,
             CharSequence remoteInputText, boolean showSpinner) {
         StatusBarNotification sbn = entry.notification;
 
@@ -533,7 +535,7 @@
     }
 
     @VisibleForTesting
-    public Set<NotificationData.Entry> getEntriesKeptForRemoteInputActive() {
+    public Set<NotificationEntry> getEntriesKeptForRemoteInputActive() {
         return mEntriesKeptForRemoteInputActive;
     }
 
@@ -556,12 +558,12 @@
      */
     protected class RemoteInputHistoryExtender extends RemoteInputExtender {
         @Override
-        public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) {
+        public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
             return shouldKeepForRemoteInputHistory(entry);
         }
 
         @Override
-        public void setShouldManageLifetime(NotificationData.Entry entry,
+        public void setShouldManageLifetime(NotificationEntry entry,
                 boolean shouldExtend) {
             if (shouldExtend) {
                 CharSequence remoteInputText = entry.remoteInputText;
@@ -602,12 +604,12 @@
      */
     protected class SmartReplyHistoryExtender extends RemoteInputExtender {
         @Override
-        public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) {
+        public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
             return shouldKeepForSmartReplyHistory(entry);
         }
 
         @Override
-        public void setShouldManageLifetime(NotificationData.Entry entry,
+        public void setShouldManageLifetime(NotificationEntry entry,
                 boolean shouldExtend) {
             if (shouldExtend) {
                 StatusBarNotification newSbn = rebuildNotificationForCanceledSmartReplies(entry);
@@ -640,7 +642,7 @@
      */
     protected class RemoteInputActiveExtender extends RemoteInputExtender {
         @Override
-        public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) {
+        public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
             if (entry.isDismissed()) {
                 return false;
             }
@@ -648,7 +650,7 @@
         }
 
         @Override
-        public void setShouldManageLifetime(NotificationData.Entry entry,
+        public void setShouldManageLifetime(NotificationEntry entry,
                 boolean shouldExtend) {
             if (shouldExtend) {
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 91b34fc..546b2e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -55,7 +55,7 @@
  * overflow icons that don't fit into the regular list anymore.
  */
 public class NotificationShelf extends ActivatableNotificationView implements
-        View.OnLayoutChangeListener {
+        View.OnLayoutChangeListener, StateListener {
 
     private static final boolean USE_ANIMATIONS_WHEN_OPENING =
             SystemProperties.getBoolean("debug.icon_opening_animations", true);
@@ -65,12 +65,12 @@
     private static final String TAG = "NotificationShelf";
     private static final long SHELF_IN_TRANSLATION_DURATION = 200;
 
-    private boolean mDark;
     private NotificationIconContainer mShelfIcons;
     private int[] mTmp = new int[2];
     private boolean mHideBackground;
     private int mIconAppearTopPadding;
     private int mShelfAppearTranslation;
+    private float mDarkShelfPadding;
     private int mStatusBarHeight;
     private int mStatusBarPaddingStart;
     private AmbientState mAmbientState;
@@ -95,8 +95,6 @@
     private int mCutoutHeight;
     private int mGapHeight;
 
-    private final StateListener mStateListener = this::setStatusBarState;
-
     public NotificationShelf(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -121,13 +119,13 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         Dependency.get(StatusBarStateController.class)
-                .addCallback(mStateListener, StatusBarStateController.RANK_SHELF);
+                .addCallback(this, StatusBarStateController.RANK_SHELF);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
+        Dependency.get(StatusBarStateController.class).removeCallback(this);
     }
 
     public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout) {
@@ -142,6 +140,7 @@
         mStatusBarPaddingStart = res.getDimensionPixelOffset(R.dimen.status_bar_padding_start);
         mPaddingBetweenElements = res.getDimensionPixelSize(R.dimen.notification_divider_height);
         mShelfAppearTranslation = res.getDimensionPixelSize(R.dimen.shelf_appear_translation);
+        mDarkShelfPadding = res.getDimensionPixelSize(R.dimen.widget_bottom_separator_padding);
 
         ViewGroup.LayoutParams layoutParams = getLayoutParams();
         layoutParams.height = res.getDimensionPixelOffset(R.dimen.notification_shelf_height);
@@ -167,11 +166,29 @@
 
     @Override
     public void setDark(boolean dark, boolean fade, long delay) {
-        super.setDark(dark, fade, delay);
         if (mDark == dark) return;
-        mDark = dark;
+        super.setDark(dark, fade, delay);
         mShelfIcons.setDark(dark, fade, delay);
         updateInteractiveness();
+        updateOutline();
+    }
+
+    /**
+     * Alpha animation with translation played when this view is visible on AOD.
+     */
+    public void fadeInTranslating() {
+        mShelfIcons.setTranslationY(-mShelfAppearTranslation);
+        mShelfIcons.setAlpha(0);
+        mShelfIcons.animate()
+                .setInterpolator(Interpolators.DECELERATE_QUINT)
+                .translationY(0)
+                .setDuration(SHELF_IN_TRANSLATION_DURATION)
+                .start();
+        mShelfIcons.animate()
+                .alpha(1)
+                .setInterpolator(Interpolators.LINEAR)
+                .setDuration(SHELF_IN_TRANSLATION_DURATION)
+                .start();
     }
 
     @Override
@@ -202,10 +219,9 @@
 
             float awakenTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - viewState.height,
                     getFullyClosedTranslation());
-            float darkTranslation = mAmbientState.getDarkTopPadding();
             float yRatio = mAmbientState.hasPulsingNotifications() ?
                     0 : mAmbientState.getDarkAmount();
-            viewState.yTranslation = MathUtils.lerp(awakenTranslation, darkTranslation, yRatio);
+            viewState.yTranslation = awakenTranslation + mDarkShelfPadding * yRatio;
             viewState.zTranslation = ambientState.getBaseZHeight();
             // For the small display size, it's not enough to make the icon not covered by
             // the top cutout so the denominator add the height of cutout.
@@ -225,7 +241,7 @@
             }
             viewState.hasItemsInStableShelf = lastViewState.inShelf;
             viewState.hidden = !mAmbientState.isShadeExpanded()
-                    || mAmbientState.isQsCustomizerShowing() || mAmbientState.isFullyDark();
+                    || mAmbientState.isQsCustomizerShowing();
             viewState.maxShelfEnd = maxShelfEnd;
         } else {
             viewState.hidden = true;
@@ -420,7 +436,7 @@
         float maxTop = row.getTranslationY();
         StatusBarIconView icon = row.getEntry().expandedIcon;
         float shelfIconPosition = getTranslationY() + icon.getTop() + icon.getTranslationY();
-        if (shelfIconPosition < maxTop) {
+        if (shelfIconPosition < maxTop && !mAmbientState.isDark()) {
             int top = (int) (maxTop - shelfIconPosition);
             Rect clipRect = new Rect(0, top, icon.getWidth(), Math.max(top, icon.getHeight()));
             icon.setClipBounds(clipRect);
@@ -431,7 +447,7 @@
 
     private void updateContinuousClipping(final ExpandableNotificationRow row) {
         StatusBarIconView icon = row.getEntry().expandedIcon;
-        boolean needsContinuousClipping = ViewState.isAnimatingY(icon);
+        boolean needsContinuousClipping = ViewState.isAnimatingY(icon) && !mAmbientState.isDark();
         boolean isContinuousClipping = icon.getTag(TAG_CONTINUOUS_CLIPPING) != null;
         if (needsContinuousClipping && !isContinuousClipping) {
             final ViewTreeObserver observer = icon.getViewTreeObserver();
@@ -522,6 +538,7 @@
                     - getIntrinsicHeight());
         }
         float viewEnd = viewStart + fullHeight;
+        // TODO: fix this check for anchor scrolling.
         if (expandingAnimated && mAmbientState.getScrollY() == 0
                 && !mAmbientState.isOnKeyguard() && !iconState.isLastExpandIcon) {
             // We are expanding animated. Because we switch to a linear interpolation in this case,
@@ -622,7 +639,9 @@
             iconState.translateContent = false;
         }
         float transitionAmount;
-        if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount
+        if (mAmbientState.isDarkAtAll() && !row.isInShelf()) {
+            transitionAmount = mAmbientState.isFullyDark() ? 1 : 0;
+        } else if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount
                 || iconState.useLinearTransitionAmount) {
             transitionAmount = iconTransitionAmount;
         } else {
@@ -745,18 +764,14 @@
         }
     }
 
-    public boolean hidesBackground() {
-        return mHideBackground;
-    }
-
     @Override
     protected boolean needsOutline() {
-        return !mHideBackground && super.needsOutline();
+        return !mHideBackground && !mDark && super.needsOutline();
     }
 
     @Override
     protected boolean shouldHideBackground() {
-        return super.shouldHideBackground() || mHideBackground;
+        return super.shouldHideBackground() || mHideBackground || mDark;
     }
 
     @Override
@@ -860,8 +875,9 @@
         mCollapsedIcons.addOnLayoutChangeListener(this);
     }
 
-    private void setStatusBarState(int statusBarState) {
-        mStatusBarState = statusBarState;
+    @Override
+    public void onStateChanged(int newState) {
+        mStatusBarState = newState;
         updateInteractiveness();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java
index f23ae3f..f0d804d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java
@@ -24,7 +24,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -52,7 +52,7 @@
     }
 
     public static NotificationUiAdjustment extractFromNotificationEntry(
-            NotificationData.Entry entry) {
+            NotificationEntry entry) {
         return new NotificationUiAdjustment(
                 entry.key, entry.systemGeneratedSmartActions, entry.smartReplies);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 017a9c3..f2ff85b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar;
 
-import static com.android.systemui.statusbar.StatusBarState.SHADE;
-
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.Trace;
@@ -26,10 +24,9 @@
 import android.view.ViewGroup;
 
 import com.android.systemui.R;
-import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -66,7 +63,6 @@
     protected final VisualStabilityManager mVisualStabilityManager;
     private final StatusBarStateController mStatusBarStateController;
     private final NotificationEntryManager mEntryManager;
-    private final BubbleController mBubbleController;
 
     // Lazy
     private final Lazy<ShadeController> mShadeController;
@@ -80,41 +76,6 @@
 
     private NotificationPresenter mPresenter;
     private NotificationListContainer mListContainer;
-    private StatusBarStateListener mStatusBarStateListener;
-
-    /**
-     * Listens for the current state of the status bar and updates the visibility state
-     * of bubbles as needed.
-     */
-    public class StatusBarStateListener implements StatusBarStateController.StateListener {
-        private int mState;
-        private BubbleController mController;
-
-        public StatusBarStateListener(BubbleController controller) {
-            mController = controller;
-        }
-
-        /**
-         * Returns the current status bar state.
-         */
-        public int getCurrentState() {
-            return mState;
-        }
-
-        @Override
-        public void onStateChanged(int newState) {
-            mState = newState;
-            // Order here matters because we need to remove the expandable notification row
-            // from it's current parent (NSSL or bubble) before it can be added to the new parent
-            if (mState == SHADE) {
-                updateNotificationViews();
-                mController.updateVisibility(true);
-            } else {
-                mController.updateVisibility(false);
-                updateNotificationViews();
-            }
-        }
-    }
 
     @Inject
     public NotificationViewHierarchyManager(Context context,
@@ -123,20 +84,16 @@
             VisualStabilityManager visualStabilityManager,
             StatusBarStateController statusBarStateController,
             NotificationEntryManager notificationEntryManager,
-            BubbleController bubbleController,
             Lazy<ShadeController> shadeController) {
         mLockscreenUserManager = notificationLockscreenUserManager;
         mGroupManager = groupManager;
         mVisualStabilityManager = visualStabilityManager;
         mStatusBarStateController = statusBarStateController;
         mEntryManager = notificationEntryManager;
-        mBubbleController = bubbleController;
         mShadeController = shadeController;
         Resources res = context.getResources();
         mAlwaysExpandNonGroupedNotification =
                 res.getBoolean(R.bool.config_alwaysExpandNonGroupedNotifications);
-        mStatusBarStateListener = new StatusBarStateListener(mBubbleController);
-        mStatusBarStateController.addCallback(mStatusBarStateListener);
     }
 
     public void setUpWithPresenter(NotificationPresenter presenter,
@@ -150,25 +107,17 @@
      */
     //TODO: Rewrite this to focus on Entries, or some other data object instead of views
     public void updateNotificationViews() {
-        ArrayList<NotificationData.Entry> activeNotifications = mEntryManager.getNotificationData()
+        ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
                 .getActiveNotifications();
         ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
-        ArrayList<NotificationData.Entry> toBubble = new ArrayList<>();
         final int N = activeNotifications.size();
         for (int i = 0; i < N; i++) {
-            NotificationData.Entry ent = activeNotifications.get(i);
+            NotificationEntry ent = activeNotifications.get(i);
             if (ent.isRowDismissed() || ent.isRowRemoved()) {
                 // we don't want to update removed notifications because they could
                 // temporarily become children if they were isolated before.
                 continue;
             }
-            ent.getRow().setStatusBarState(mStatusBarStateListener.getCurrentState());
-            boolean showAsBubble = ent.isBubble() && !ent.isBubbleDismissed()
-                    && mStatusBarStateListener.getCurrentState() == SHADE;
-            if (showAsBubble) {
-                toBubble.add(ent);
-                continue;
-            }
 
             int userId = ent.notification.getUserId();
 
@@ -187,7 +136,7 @@
             ent.getRow().setSensitive(sensitive, deviceSensitive);
             ent.getRow().setNeedsRedaction(needsRedaction);
             if (mGroupManager.isChildInGroupWithSummary(ent.notification)) {
-                NotificationData.Entry summary = mGroupManager.getGroupSummary(ent.notification);
+                NotificationEntry summary = mGroupManager.getGroupSummary(ent.notification);
                 List<ExpandableNotificationRow> orderedChildren =
                         mTmpChildOrderMap.get(summary.getRow());
                 if (orderedChildren == null) {
@@ -269,12 +218,6 @@
 
         }
 
-        for (int i = 0; i < toBubble.size(); i++) {
-            // TODO: might make sense to leave them in the shade and just reposition them
-            NotificationData.Entry ent = toBubble.get(i);
-            mBubbleController.addBubble(ent);
-        }
-
         mVisualStabilityManager.onReorderingFinished();
         // clear the map again for the next usage
         mTmpChildOrderMap.clear();
@@ -385,7 +328,7 @@
         }
         while(!stack.isEmpty()) {
             ExpandableNotificationRow row = stack.pop();
-            NotificationData.Entry entry = row.getEntry();
+            NotificationEntry entry = row.getEntry();
             boolean isChildNotification =
                     mGroupManager.isChildInGroupWithSummary(entry.notification);
 
@@ -408,7 +351,7 @@
             if (!showOnKeyguard) {
                 // min priority notifications should show if their summary is showing
                 if (mGroupManager.isChildInGroupWithSummary(entry.notification)) {
-                    NotificationData.Entry summary = mGroupManager.getLogicalGroupSummary(
+                    NotificationEntry summary = mGroupManager.getLogicalGroupSummary(
                             entry.notification);
                     if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(
                             summary.notification))         {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index e8abcc2..998cf52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -24,7 +24,7 @@
 import android.util.Pair;
 
 import com.android.internal.util.Preconditions;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.RemoteInputView;
 
 import java.lang.ref.WeakReference;
@@ -38,7 +38,7 @@
     private static final boolean ENABLE_REMOTE_INPUT =
             SystemProperties.getBoolean("debug.enable_remote_input", true);
 
-    private final ArrayList<Pair<WeakReference<NotificationData.Entry>, Object>> mOpen
+    private final ArrayList<Pair<WeakReference<NotificationEntry>, Object>> mOpen
             = new ArrayList<>();
     private final ArrayMap<String, Object> mSpinning = new ArrayMap<>();
     private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
@@ -101,7 +101,7 @@
      * @param entry the entry for which a remote input is now active.
      * @param token a token identifying the view that is managing the remote input
      */
-    public void addRemoteInput(NotificationData.Entry entry, Object token) {
+    public void addRemoteInput(NotificationEntry entry, Object token) {
         Preconditions.checkNotNull(entry);
         Preconditions.checkNotNull(token);
 
@@ -122,7 +122,7 @@
      *              the entry is only removed if the token matches the last added token for this
      *              entry. If null, the entry is removed regardless.
      */
-    public void removeRemoteInput(NotificationData.Entry entry, Object token) {
+    public void removeRemoteInput(NotificationEntry entry, Object token) {
         Preconditions.checkNotNull(entry);
 
         pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */, token);
@@ -173,7 +173,7 @@
         return mSpinning.get(key) == token;
     }
 
-    private void apply(NotificationData.Entry entry) {
+    private void apply(NotificationEntry entry) {
         mDelegate.setRemoteInputActive(entry, isRemoteInputActive(entry));
         boolean remoteInputActive = isRemoteInputActive();
         int N = mCallbacks.size();
@@ -185,7 +185,7 @@
     /**
      * @return true if {@param entry} has an active RemoteInput
      */
-    public boolean isRemoteInputActive(NotificationData.Entry entry) {
+    public boolean isRemoteInputActive(NotificationEntry entry) {
         return pruneWeakThenRemoveAndContains(entry /* contains */, null /* remove */,
                 null /* removeToken */);
     }
@@ -208,10 +208,10 @@
      * @return true if {@param contains} is in the set of active remote inputs
      */
     private boolean pruneWeakThenRemoveAndContains(
-            NotificationData.Entry contains, NotificationData.Entry remove, Object removeToken) {
+            NotificationEntry contains, NotificationEntry remove, Object removeToken) {
         boolean found = false;
         for (int i = mOpen.size() - 1; i >= 0; i--) {
-            NotificationData.Entry item = mOpen.get(i).first.get();
+            NotificationEntry item = mOpen.get(i).first.get();
             Object itemToken = mOpen.get(i).second;
             boolean removeTokenMatches = (removeToken == null || itemToken == removeToken);
 
@@ -235,7 +235,7 @@
         mCallbacks.add(callback);
     }
 
-    public void remoteInputSent(NotificationData.Entry entry) {
+    public void remoteInputSent(NotificationEntry entry) {
         int N = mCallbacks.size();
         for (int i = 0; i < N; i++) {
             mCallbacks.get(i).onRemoteInputSent(entry);
@@ -248,16 +248,16 @@
         }
 
         // Make a copy because closing the remote inputs will modify mOpen.
-        ArrayList<NotificationData.Entry> list = new ArrayList<>(mOpen.size());
+        ArrayList<NotificationEntry> list = new ArrayList<>(mOpen.size());
         for (int i = mOpen.size() - 1; i >= 0; i--) {
-            NotificationData.Entry entry = mOpen.get(i).first.get();
+            NotificationEntry entry = mOpen.get(i).first.get();
             if (entry != null && entry.rowExists()) {
                 list.add(entry);
             }
         }
 
         for (int i = list.size() - 1; i >= 0; i--) {
-            NotificationData.Entry entry = list.get(i);
+            NotificationEntry entry = list.get(i);
             if (entry.rowExists()) {
                 entry.closeRemoteInput();
             }
@@ -268,31 +268,31 @@
         mDelegate.requestDisallowLongPressAndDismiss();
     }
 
-    public void lockScrollTo(NotificationData.Entry entry) {
+    public void lockScrollTo(NotificationEntry entry) {
         mDelegate.lockScrollTo(entry);
     }
 
     public interface Callback {
         default void onRemoteInputActive(boolean active) {}
 
-        default void onRemoteInputSent(NotificationData.Entry entry) {}
+        default void onRemoteInputSent(NotificationEntry entry) {}
     }
 
     public interface Delegate {
         /**
          * Activate remote input if necessary.
          */
-        void setRemoteInputActive(NotificationData.Entry entry, boolean remoteInputActive);
+        void setRemoteInputActive(NotificationEntry entry, boolean remoteInputActive);
 
-       /**
-        * Request that the view does not dismiss nor perform long press for the current touch.
-        */
-       void requestDisallowLongPressAndDismiss();
+        /**
+         * Request that the view does not dismiss nor perform long press for the current touch.
+         */
+        void requestDisallowLongPressAndDismiss();
 
-      /**
-       * Request that the view is made visible by scrolling to it, and keep the scroll locked until
-       * the user scrolls, or {@param v} loses focus or is detached.
-       */
-       void lockScrollTo(NotificationData.Entry entry);
+        /**
+         * Request that the view is made visible by scrolling to it, and keep the scroll locked until
+         * the user scrolls, or {@param entry} loses focus or is detached.
+         */
+        void lockScrollTo(NotificationEntry entry);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
deleted file mode 100644
index 6d2c001..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ /dev/null
@@ -1,692 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar;
-
-import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
-import static android.app.StatusBarManager.DISABLE_NONE;
-
-import android.annotation.DrawableRes;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.telephony.SubscriptionInfo;
-import android.util.ArraySet;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-
-import com.android.settingslib.graph.SignalDrawable;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.policy.IconLogger;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NetworkController.IconState;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl;
-import com.android.systemui.statusbar.policy.SecurityController;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.systemui.util.Utils.DisableStateTracker;
-
-import java.util.ArrayList;
-import java.util.List;
-
-// Intimately tied to the design of res/layout/signal_cluster_view.xml
-public class SignalClusterView extends LinearLayout implements NetworkControllerImpl.SignalCallback,
-        SecurityController.SecurityControllerCallback, Tunable, DarkReceiver {
-
-    static final String TAG = "SignalClusterView";
-    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    private static final String SLOT_AIRPLANE = "airplane";
-    private static final String SLOT_MOBILE = "mobile";
-    private static final String SLOT_WIFI = "wifi";
-    private static final String SLOT_ETHERNET = "ethernet";
-    private static final String SLOT_VPN = "vpn";
-
-    private final NetworkController mNetworkController;
-    private final SecurityController mSecurityController;
-
-    private boolean mVpnVisible = false;
-    private int mVpnIconId = 0;
-    private int mLastVpnIconId = -1;
-    private boolean mEthernetVisible = false;
-    private int mEthernetIconId = 0;
-    private int mLastEthernetIconId = -1;
-    private boolean mWifiVisible = false;
-    private int mWifiStrengthId = 0;
-    private int mLastWifiStrengthId = -1;
-    private boolean mWifiIn;
-    private boolean mWifiOut;
-    private boolean mIsAirplaneMode = false;
-    private int mAirplaneIconId = 0;
-    private int mLastAirplaneIconId = -1;
-    private String mAirplaneContentDescription;
-    private String mWifiDescription;
-    private String mEthernetDescription;
-    private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>();
-    private int mIconTint = Color.WHITE;
-    private float mDarkIntensity;
-    private final Rect mTintArea = new Rect();
-
-    ViewGroup mEthernetGroup, mWifiGroup;
-    ImageView mVpn, mEthernet, mWifi, mAirplane, mEthernetDark, mWifiDark;
-    ImageView mWifiActivityIn;
-    ImageView mWifiActivityOut;
-    View mWifiAirplaneSpacer;
-    View mWifiSignalSpacer;
-    LinearLayout mMobileSignalGroup;
-
-    private final int mMobileSignalGroupEndPadding;
-    private final int mMobileDataIconStartPadding;
-    private final int mSecondaryTelephonyPadding;
-    private final int mEndPadding;
-    private final int mEndPaddingNothingVisible;
-    private final float mIconScaleFactor;
-
-    private boolean mBlockAirplane;
-    private boolean mBlockMobile;
-    private boolean mBlockWifi;
-    private boolean mBlockEthernet;
-    private boolean mActivityEnabled;
-    private boolean mForceBlockWifi;
-
-    private final IconLogger mIconLogger = Dependency.get(IconLogger.class);
-
-    public SignalClusterView(Context context) {
-        this(context, null);
-    }
-
-    public SignalClusterView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SignalClusterView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        Resources res = getResources();
-        mMobileSignalGroupEndPadding =
-                res.getDimensionPixelSize(R.dimen.mobile_signal_group_end_padding);
-        mMobileDataIconStartPadding =
-                res.getDimensionPixelSize(R.dimen.mobile_data_icon_start_padding);
-        mSecondaryTelephonyPadding = res.getDimensionPixelSize(R.dimen.secondary_telephony_padding);
-        mEndPadding = res.getDimensionPixelSize(R.dimen.signal_cluster_battery_padding);
-        mEndPaddingNothingVisible = res.getDimensionPixelSize(
-                R.dimen.no_signal_cluster_battery_padding);
-
-        TypedValue typedValue = new TypedValue();
-        res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
-        mIconScaleFactor = typedValue.getFloat();
-        mNetworkController = Dependency.get(NetworkController.class);
-        mSecurityController = Dependency.get(SecurityController.class);
-        addOnAttachStateChangeListener(
-                new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS));
-        updateActivityEnabled();
-    }
-
-    public void setForceBlockWifi() {
-        mForceBlockWifi = true;
-        mBlockWifi = true;
-        if (isAttachedToWindow()) {
-            // Re-register to get new callbacks.
-            mNetworkController.removeCallback(this);
-            mNetworkController.addCallback(this);
-        }
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) {
-            return;
-        }
-        ArraySet<String> blockList = StatusBarIconController.getIconBlacklist(newValue);
-        boolean blockAirplane = blockList.contains(SLOT_AIRPLANE);
-        boolean blockMobile = blockList.contains(SLOT_MOBILE);
-        boolean blockWifi = blockList.contains(SLOT_WIFI);
-        boolean blockEthernet = blockList.contains(SLOT_ETHERNET);
-
-        if (blockAirplane != mBlockAirplane || blockMobile != mBlockMobile
-                || blockEthernet != mBlockEthernet || blockWifi != mBlockWifi) {
-            mBlockAirplane = blockAirplane;
-            mBlockMobile = blockMobile;
-            mBlockEthernet = blockEthernet;
-            mBlockWifi = blockWifi || mForceBlockWifi;
-            // Re-register to get new callbacks.
-            mNetworkController.removeCallback(this);
-            mNetworkController.addCallback(this);
-        }
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        mVpn            = findViewById(R.id.vpn);
-        mEthernetGroup  = findViewById(R.id.ethernet_combo);
-        mEthernet       = findViewById(R.id.ethernet);
-        mEthernetDark   = findViewById(R.id.ethernet_dark);
-        mWifiGroup      = findViewById(R.id.wifi_combo);
-        mWifi           = findViewById(R.id.wifi_signal);
-        mWifiDark       = findViewById(R.id.wifi_signal_dark);
-        mWifiActivityIn = findViewById(R.id.wifi_in);
-        mWifiActivityOut= findViewById(R.id.wifi_out);
-        mAirplane       = findViewById(R.id.airplane);
-        mWifiAirplaneSpacer =         findViewById(R.id.wifi_airplane_spacer);
-        mWifiSignalSpacer =           findViewById(R.id.wifi_signal_spacer);
-        mMobileSignalGroup =          findViewById(R.id.mobile_signal_group);
-
-        maybeScaleVpnAndNoSimsIcons();
-    }
-
-    /**
-     * Extracts the icon off of the VPN and no sims views and maybe scale them by
-     * {@link #mIconScaleFactor}. Note that the other icons are not scaled here because they are
-     * dynamic. As such, they need to be scaled each time the icon changes in {@link #apply()}.
-     */
-    private void maybeScaleVpnAndNoSimsIcons() {
-        if (mIconScaleFactor == 1.f) {
-            return;
-        }
-
-        mVpn.setImageDrawable(new ScalingDrawableWrapper(mVpn.getDrawable(), mIconScaleFactor));
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mVpnVisible = mSecurityController.isVpnEnabled();
-        mVpnIconId = currentVpnIconId(mSecurityController.isVpnBranded());
-
-        for (PhoneState state : mPhoneStates) {
-            if (state.mMobileGroup.getParent() == null) {
-                mMobileSignalGroup.addView(state.mMobileGroup);
-            }
-        }
-
-        int endPadding = mMobileSignalGroup.getChildCount() > 0 ? mMobileSignalGroupEndPadding : 0;
-        mMobileSignalGroup.setPaddingRelative(0, 0, endPadding, 0);
-
-        Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
-
-        apply();
-        applyIconTint();
-        mNetworkController.addCallback(this);
-        mSecurityController.addCallback(this);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        mMobileSignalGroup.removeAllViews();
-        Dependency.get(TunerService.class).removeTunable(this);
-        mSecurityController.removeCallback(this);
-        mNetworkController.removeCallback(this);
-
-        super.onDetachedFromWindow();
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
-
-        // Re-run all checks against the tint area for all icons
-        applyIconTint();
-    }
-
-    // From SecurityController.
-    @Override
-    public void onStateChanged() {
-        post(new Runnable() {
-            @Override
-            public void run() {
-                mVpnVisible = mSecurityController.isVpnEnabled();
-                mVpnIconId = currentVpnIconId(mSecurityController.isVpnBranded());
-                apply();
-            }
-        });
-    }
-
-    private void updateActivityEnabled() {
-        mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
-    }
-
-    @Override
-    public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
-            boolean activityIn, boolean activityOut, String description, boolean isTransient,
-            String secondaryLabel) {
-        mWifiVisible = statusIcon.visible && !mBlockWifi;
-        mWifiStrengthId = statusIcon.icon;
-        mWifiDescription = statusIcon.contentDescription;
-        mWifiIn = activityIn && mActivityEnabled && mWifiVisible;
-        mWifiOut = activityOut && mActivityEnabled && mWifiVisible;
-
-        apply();
-    }
-
-    @Override
-    public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
-            int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
-            String description, boolean isWide, int subId, boolean roaming) {
-        PhoneState state = getState(subId);
-        if (state == null) {
-            return;
-        }
-        state.mMobileVisible = statusIcon.visible && !mBlockMobile;
-        state.mMobileStrengthId = statusIcon.icon;
-        state.mMobileTypeId = statusType;
-        state.mMobileDescription = statusIcon.contentDescription;
-        state.mMobileTypeDescription = typeContentDescription;
-        state.mRoaming = roaming;
-        state.mActivityIn = activityIn && mActivityEnabled;
-        state.mActivityOut = activityOut && mActivityEnabled;
-
-        apply();
-    }
-
-    @Override
-    public void setEthernetIndicators(IconState state) {
-        mEthernetVisible = state.visible && !mBlockEthernet;
-        mEthernetIconId = state.icon;
-        mEthernetDescription = state.contentDescription;
-
-        apply();
-    }
-
-    @Override
-    public void setNoSims(boolean show, boolean simDetected) {
-        // Noop. Status bar no longer shows no sim icon.
-    }
-
-    @Override
-    public void setSubs(List<SubscriptionInfo> subs) {
-        if (hasCorrectSubs(subs)) {
-            return;
-        }
-        mPhoneStates.clear();
-        if (mMobileSignalGroup != null) {
-            mMobileSignalGroup.removeAllViews();
-        }
-        final int n = subs.size();
-        for (int i = 0; i < n; i++) {
-            inflatePhoneState(subs.get(i).getSubscriptionId());
-        }
-        if (isAttachedToWindow()) {
-            applyIconTint();
-        }
-    }
-
-    private boolean hasCorrectSubs(List<SubscriptionInfo> subs) {
-        final int N = subs.size();
-        if (N != mPhoneStates.size()) {
-            return false;
-        }
-        for (int i = 0; i < N; i++) {
-            if (mPhoneStates.get(i).mSubId != subs.get(i).getSubscriptionId()) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private PhoneState getState(int subId) {
-        for (PhoneState state : mPhoneStates) {
-            if (state.mSubId == subId) {
-                return state;
-            }
-        }
-        Log.e(TAG, "Unexpected subscription " + subId);
-        return null;
-    }
-
-    private PhoneState inflatePhoneState(int subId) {
-        PhoneState state = new PhoneState(subId, mContext);
-        if (mMobileSignalGroup != null) {
-            mMobileSignalGroup.addView(state.mMobileGroup);
-        }
-        mPhoneStates.add(state);
-        return state;
-    }
-
-    @Override
-    public void setIsAirplaneMode(IconState icon) {
-        mIsAirplaneMode = icon.visible && !mBlockAirplane;
-        mAirplaneIconId = icon.icon;
-        mAirplaneContentDescription = icon.contentDescription;
-
-        apply();
-    }
-
-    @Override
-    public void setMobileDataEnabled(boolean enabled) {
-        // Don't care.
-    }
-
-    @Override
-    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
-        // Standard group layout onPopulateAccessibilityEvent() implementations
-        // ignore content description, so populate manually
-        if (mEthernetVisible && mEthernetGroup != null &&
-                mEthernetGroup.getContentDescription() != null)
-            event.getText().add(mEthernetGroup.getContentDescription());
-        if (mWifiVisible && mWifiGroup != null && mWifiGroup.getContentDescription() != null)
-            event.getText().add(mWifiGroup.getContentDescription());
-        for (PhoneState state : mPhoneStates) {
-            state.populateAccessibilityEvent(event);
-        }
-        return super.dispatchPopulateAccessibilityEventInternal(event);
-    }
-
-    @Override
-    public void onRtlPropertiesChanged(int layoutDirection) {
-        super.onRtlPropertiesChanged(layoutDirection);
-
-        if (mEthernet != null) {
-            mEthernet.setImageDrawable(null);
-            mEthernetDark.setImageDrawable(null);
-            mLastEthernetIconId = -1;
-        }
-
-        if (mWifi != null) {
-            mWifi.setImageDrawable(null);
-            mWifiDark.setImageDrawable(null);
-            mLastWifiStrengthId = -1;
-        }
-
-        for (PhoneState state : mPhoneStates) {
-            if (state.mMobileType != null) {
-                state.mMobileType.setImageDrawable(null);
-                state.mLastMobileTypeId = -1;
-            }
-        }
-
-        if (mAirplane != null) {
-            mAirplane.setImageDrawable(null);
-            mLastAirplaneIconId = -1;
-        }
-
-        apply();
-    }
-
-    @Override
-    public boolean hasOverlappingRendering() {
-        return false;
-    }
-
-    // Run after each indicator change.
-    private void apply() {
-        if (mWifiGroup == null) return;
-
-        if (mVpnVisible) {
-            if (mLastVpnIconId != mVpnIconId) {
-                setIconForView(mVpn, mVpnIconId);
-                mLastVpnIconId = mVpnIconId;
-            }
-            mIconLogger.onIconShown(SLOT_VPN);
-            mVpn.setVisibility(View.VISIBLE);
-        } else {
-            mIconLogger.onIconHidden(SLOT_VPN);
-            mVpn.setVisibility(View.GONE);
-        }
-        if (DEBUG) Log.d(TAG, String.format("vpn: %s", mVpnVisible ? "VISIBLE" : "GONE"));
-
-        if (mEthernetVisible) {
-            if (mLastEthernetIconId != mEthernetIconId) {
-                setIconForView(mEthernet, mEthernetIconId);
-                setIconForView(mEthernetDark, mEthernetIconId);
-                mLastEthernetIconId = mEthernetIconId;
-            }
-            mEthernetGroup.setContentDescription(mEthernetDescription);
-            mIconLogger.onIconShown(SLOT_ETHERNET);
-            mEthernetGroup.setVisibility(View.VISIBLE);
-        } else {
-            mIconLogger.onIconHidden(SLOT_ETHERNET);
-            mEthernetGroup.setVisibility(View.GONE);
-        }
-
-        if (DEBUG) Log.d(TAG,
-                String.format("ethernet: %s",
-                    (mEthernetVisible ? "VISIBLE" : "GONE")));
-
-        if (mWifiVisible) {
-            if (mWifiStrengthId != mLastWifiStrengthId) {
-                setIconForView(mWifi, mWifiStrengthId);
-                setIconForView(mWifiDark, mWifiStrengthId);
-                mLastWifiStrengthId = mWifiStrengthId;
-            }
-            mIconLogger.onIconShown(SLOT_WIFI);
-            mWifiGroup.setContentDescription(mWifiDescription);
-            mWifiGroup.setVisibility(View.VISIBLE);
-        } else {
-            mIconLogger.onIconHidden(SLOT_WIFI);
-            mWifiGroup.setVisibility(View.GONE);
-        }
-
-        if (DEBUG) Log.d(TAG,
-                String.format("wifi: %s sig=%d",
-                    (mWifiVisible ? "VISIBLE" : "GONE"),
-                    mWifiStrengthId));
-
-        mWifiActivityIn.setVisibility(mWifiIn ? View.VISIBLE : View.GONE);
-        mWifiActivityOut.setVisibility(mWifiOut ? View.VISIBLE : View.GONE);
-
-        boolean anyMobileVisible = false;
-        int firstMobileTypeId = 0;
-        for (PhoneState state : mPhoneStates) {
-            if (state.apply(anyMobileVisible)) {
-                if (!anyMobileVisible) {
-                    firstMobileTypeId = state.mMobileTypeId;
-                    anyMobileVisible = true;
-                }
-            }
-        }
-        if (anyMobileVisible) {
-            mIconLogger.onIconShown(SLOT_MOBILE);
-        } else {
-            mIconLogger.onIconHidden(SLOT_MOBILE);
-        }
-
-        if (mIsAirplaneMode) {
-            if (mLastAirplaneIconId != mAirplaneIconId) {
-                setIconForView(mAirplane, mAirplaneIconId);
-                mLastAirplaneIconId = mAirplaneIconId;
-            }
-            mAirplane.setContentDescription(mAirplaneContentDescription);
-            mIconLogger.onIconShown(SLOT_AIRPLANE);
-            mAirplane.setVisibility(View.VISIBLE);
-        } else {
-            mIconLogger.onIconHidden(SLOT_AIRPLANE);
-            mAirplane.setVisibility(View.GONE);
-        }
-
-        if (mIsAirplaneMode && mWifiVisible) {
-            mWifiAirplaneSpacer.setVisibility(View.VISIBLE);
-        } else {
-            mWifiAirplaneSpacer.setVisibility(View.GONE);
-        }
-
-        if ((anyMobileVisible && firstMobileTypeId != 0) && mWifiVisible) {
-            mWifiSignalSpacer.setVisibility(View.VISIBLE);
-        } else {
-            mWifiSignalSpacer.setVisibility(View.GONE);
-        }
-
-        boolean anythingVisible = mWifiVisible || mIsAirplaneMode
-                || anyMobileVisible || mVpnVisible || mEthernetVisible;
-        setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0);
-    }
-
-    /**
-     * Sets the given drawable id on the view. This method will also scale the icon by
-     * {@link #mIconScaleFactor} if appropriate.
-     */
-    private void setIconForView(ImageView imageView, @DrawableRes int iconId) {
-        // Using the imageView's context to retrieve the Drawable so that theme is preserved.
-        Drawable icon = imageView.getContext().getDrawable(iconId);
-
-        if (mIconScaleFactor == 1.f) {
-            imageView.setImageDrawable(icon);
-        } else {
-            imageView.setImageDrawable(new ScalingDrawableWrapper(icon, mIconScaleFactor));
-        }
-    }
-
-
-    @Override
-    public void onDarkChanged(Rect tintArea, float darkIntensity, int tint) {
-        boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity
-                || !mTintArea.equals(tintArea);
-        mIconTint = tint;
-        mDarkIntensity = darkIntensity;
-        mTintArea.set(tintArea);
-        if (changed && isAttachedToWindow()) {
-            applyIconTint();
-        }
-    }
-
-    private void applyIconTint() {
-        setTint(mVpn, DarkIconDispatcher.getTint(mTintArea, mVpn, mIconTint));
-        setTint(mAirplane, DarkIconDispatcher.getTint(mTintArea, mAirplane, mIconTint));
-        applyDarkIntensity(
-                DarkIconDispatcher.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
-                mWifi, mWifiDark);
-        setTint(mWifiActivityIn,
-                DarkIconDispatcher.getTint(mTintArea, mWifiActivityIn, mIconTint));
-        setTint(mWifiActivityOut,
-                DarkIconDispatcher.getTint(mTintArea, mWifiActivityOut, mIconTint));
-        applyDarkIntensity(
-                DarkIconDispatcher.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
-                mEthernet, mEthernetDark);
-        for (int i = 0; i < mPhoneStates.size(); i++) {
-            mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity, mTintArea);
-        }
-    }
-
-    private void applyDarkIntensity(float darkIntensity, View lightIcon, View darkIcon) {
-        lightIcon.setAlpha(1 - darkIntensity);
-        darkIcon.setAlpha(darkIntensity);
-    }
-
-    private void setTint(ImageView v, int tint) {
-        v.setImageTintList(ColorStateList.valueOf(tint));
-    }
-
-    private int currentVpnIconId(boolean isBranded) {
-        return isBranded ? R.drawable.stat_sys_branded_vpn : R.drawable.stat_sys_vpn_ic;
-    }
-
-    private class PhoneState {
-        private final int mSubId;
-        private boolean mMobileVisible = false;
-        private int mMobileStrengthId = 0, mMobileTypeId = 0;
-        private int mLastMobileStrengthId = -1;
-        private int mLastMobileTypeId = -1;
-        private String mMobileDescription, mMobileTypeDescription;
-
-        private ViewGroup mMobileGroup;
-        private ImageView mMobile, mMobileType, mMobileRoaming;
-        private View mMobileRoamingSpace;
-        public boolean mRoaming;
-        private ImageView mMobileActivityIn;
-        private ImageView mMobileActivityOut;
-        public boolean mActivityIn;
-        public boolean mActivityOut;
-        private SignalDrawable mMobileSignalDrawable;
-
-        public PhoneState(int subId, Context context) {
-            ViewGroup root = (ViewGroup) LayoutInflater.from(context)
-                    .inflate(R.layout.mobile_signal_group, null);
-            setViews(root);
-            mSubId = subId;
-        }
-
-        public void setViews(ViewGroup root) {
-            mMobileGroup    = root;
-            mMobile         = root.findViewById(R.id.mobile_signal);
-            mMobileType     = root.findViewById(R.id.mobile_type);
-            mMobileRoaming  = root.findViewById(R.id.mobile_roaming);
-            mMobileRoamingSpace  = root.findViewById(R.id.mobile_roaming_space);
-            mMobileActivityIn = root.findViewById(R.id.mobile_in);
-            mMobileActivityOut = root.findViewById(R.id.mobile_out);
-            mMobileSignalDrawable = new SignalDrawable(mMobile.getContext());
-            mMobile.setImageDrawable(mMobileSignalDrawable);
-        }
-
-        public boolean apply(boolean isSecondaryIcon) {
-            if (mMobileVisible && !mIsAirplaneMode) {
-                if (mLastMobileStrengthId != mMobileStrengthId) {
-                    mMobile.getDrawable().setLevel(mMobileStrengthId);
-                    mLastMobileStrengthId = mMobileStrengthId;
-                }
-
-                if (mLastMobileTypeId != mMobileTypeId) {
-                    mMobileType.setImageResource(mMobileTypeId);
-                    mLastMobileTypeId = mMobileTypeId;
-                }
-
-                mMobileGroup.setContentDescription(mMobileTypeDescription
-                        + " " + mMobileDescription);
-                mMobileGroup.setVisibility(View.VISIBLE);
-            } else {
-                mMobileGroup.setVisibility(View.GONE);
-            }
-
-            // When this isn't next to wifi, give it some extra padding between the signals.
-            mMobileGroup.setPaddingRelative(isSecondaryIcon ? mSecondaryTelephonyPadding : 0,
-                    0, 0, 0);
-            mMobile.setPaddingRelative(mMobileDataIconStartPadding, 0, 0, 0);
-
-            if (DEBUG) Log.d(TAG, String.format("mobile: %s sig=%d typ=%d",
-                        (mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId));
-
-            mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE);
-            mMobileRoaming.setVisibility(mRoaming ? View.VISIBLE : View.GONE);
-            mMobileRoamingSpace.setVisibility(mRoaming ? View.VISIBLE : View.GONE);
-            mMobileActivityIn.setVisibility(mActivityIn ? View.VISIBLE : View.GONE);
-            mMobileActivityOut.setVisibility(mActivityOut ? View.VISIBLE : View.GONE);
-
-            return mMobileVisible;
-        }
-
-        public void populateAccessibilityEvent(AccessibilityEvent event) {
-            if (mMobileVisible && mMobileGroup != null
-                    && mMobileGroup.getContentDescription() != null) {
-                event.getText().add(mMobileGroup.getContentDescription());
-            }
-        }
-
-        public void setIconTint(int tint, float darkIntensity, Rect tintArea) {
-            mMobileSignalDrawable.setDarkIntensity(darkIntensity);
-            setTint(mMobileType, DarkIconDispatcher.getTint(tintArea, mMobileType, tint));
-            setTint(mMobileRoaming, DarkIconDispatcher.getTint(tintArea, mMobileRoaming,
-                    tint));
-            setTint(mMobileActivityIn,
-                    DarkIconDispatcher.getTint(tintArea, mMobileActivityIn, tint));
-            setTint(mMobileActivityOut,
-                    DarkIconDispatcher.getTint(tintArea, mMobileActivityOut, tint));
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
index 9e91133..a2abcd2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
@@ -21,8 +21,9 @@
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 
 import java.util.Set;
 
@@ -54,7 +55,7 @@
     /**
      * Notifies StatusBarService a smart reply is sent.
      */
-    public void smartReplySent(NotificationData.Entry entry, int replyIndex, CharSequence reply,
+    public void smartReplySent(NotificationEntry entry, int replyIndex, CharSequence reply,
             boolean generatedByAssistant) {
         mCallback.onSmartReplySent(entry, reply);
         mSendingKeys.add(entry.key);
@@ -70,12 +71,14 @@
      * Notifies StatusBarService a smart action is clicked.
      */
     public void smartActionClicked(
-            NotificationData.Entry entry, int actionIndex, Notification.Action action,
+            NotificationEntry entry, int actionIndex, Notification.Action action,
             boolean generatedByAssistant) {
         final int count = mEntryManager.getNotificationData().getActiveNotifications().size();
         final int rank = mEntryManager.getNotificationData().getRank(entry.key);
-        final NotificationVisibility nv =
-                NotificationVisibility.obtain(entry.key, rank, count, true);
+        NotificationVisibility.NotificationLocation location =
+                NotificationLogger.getNotificationLocation(entry);
+        final NotificationVisibility nv = NotificationVisibility.obtain(
+                entry.key, rank, count, true, location);
         try {
             mBarService.onNotificationActionClick(
                     entry.key, actionIndex, action, nv, generatedByAssistant);
@@ -95,7 +98,7 @@
     /**
      * Smart Replies and Actions have been added to the UI.
      */
-    public void smartSuggestionsAdded(final NotificationData.Entry entry, int replyCount,
+    public void smartSuggestionsAdded(final NotificationEntry entry, int replyCount,
             int actionCount, boolean generatedByAssistant) {
         try {
             mBarService.onNotificationSmartSuggestionsAdded(
@@ -105,7 +108,7 @@
         }
     }
 
-    public void stopSending(final NotificationData.Entry entry) {
+    public void stopSending(final NotificationEntry entry) {
         if (entry != null) {
             mSendingKeys.remove(entry.notification.getKey());
         }
@@ -121,6 +124,6 @@
          * @param entry the entry for the notification
          * @param reply the reply that was sent
          */
-        void onSmartReplySent(NotificationData.Entry entry, CharSequence reply);
+        void onSmartReplySent(NotificationEntry entry, CharSequence reply);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconContainer.java
deleted file mode 100644
index 0652227..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconContainer.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar;
-
-import com.android.internal.statusbar.StatusBarIcon;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Holds an array of {@link com.android.internal.statusbar.StatusBarIcon}s and draws them
- * in a linear layout
- */
-public class StatusBarIconContainer {
-    private final List<StatusBarIcon> mIcons = new ArrayList<>();
-
-    public StatusBarIconContainer(List<StatusBarIcon> icons) {
-        mIcons.addAll(icons);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 3c13354..19ed13e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -206,6 +206,10 @@
         mIconScale = SYSTEM_ICON_SCALE;
     }
 
+    public float getIconScaleFullyDark() {
+        return (float) mStatusBarIconDrawingSizeDark / mStatusBarIconDrawingSize;
+    }
+
     public float getIconScale() {
         return mIconScale;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
index 087b655..54bce1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
@@ -331,7 +331,8 @@
          *
          * @param newState the new {@link StatusBarState}
          */
-        public void onStateChanged(int newState);
+        default void onStateChanged(int newState) {
+        }
 
         /**
          * Callback to be notified when Dozing changes. Dozing is stored separately from state.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
index 7b42dd9..5605f3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
@@ -20,7 +20,6 @@
 import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
 import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
 
-import android.annotation.Nullable;
 import android.app.Notification;
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
@@ -30,6 +29,7 @@
 import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationInflater;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -72,24 +72,21 @@
 
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
-            public void onEntryInflated(NotificationData.Entry entry, int inflatedFlags) {
+            public void onEntryInflated(NotificationEntry entry, int inflatedFlags) {
                 showAlertingView(entry, inflatedFlags);
             }
 
             @Override
-            public void onEntryUpdated(NotificationData.Entry entry) {
+            public void onPostEntryUpdated(NotificationEntry entry) {
                 updateAlertState(entry);
             }
 
             @Override
             public void onEntryRemoved(
-                    @Nullable NotificationData.Entry entry,
-                    String key,
-                    StatusBarNotification old,
+                    NotificationEntry entry,
                     NotificationVisibility visibility,
-                    boolean lifetimeExtended,
                     boolean removedByUser) {
-                stopAlerting(key);
+                stopAlerting(entry.key);
             }
         });
     }
@@ -105,7 +102,7 @@
      * @param entry         entry to add
      * @param inflatedFlags flags representing content views that were inflated
      */
-    private void showAlertingView(NotificationData.Entry entry,
+    private void showAlertingView(NotificationEntry entry,
             @NotificationInflater.InflationFlag int inflatedFlags) {
         if ((inflatedFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
             // Possible for shouldHeadsUp to change between the inflation starting and ending.
@@ -127,7 +124,7 @@
         }
     }
 
-    private void updateAlertState(NotificationData.Entry entry) {
+    private void updateAlertState(NotificationEntry entry) {
         boolean alertAgain = alertAgain(entry, entry.notification.getNotification());
         AlertingNotificationManager alertManager;
         boolean shouldAlert;
@@ -153,8 +150,15 @@
         }
     }
 
-    private static boolean alertAgain(
-            NotificationData.Entry oldEntry, Notification newNotification) {
+    /**
+     * Checks whether an update for a notification warrants an alert for the user.
+     *
+     * @param oldEntry the entry for this notification.
+     * @param newNotification the new notification for this entry.
+     * @return whether this notification should alert the user.
+     */
+    public static boolean alertAgain(
+            NotificationEntry oldEntry, Notification newNotification) {
         return oldEntry == null || !oldEntry.hasInterrupted()
                 || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
deleted file mode 100644
index a51896e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ /dev/null
@@ -1,1072 +0,0 @@
-/*
- * Copyright (C) 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
- */
-
-package com.android.systemui.statusbar.notification;
-
-import static android.app.Notification.CATEGORY_ALARM;
-import static android.app.Notification.CATEGORY_CALL;
-import static android.app.Notification.CATEGORY_EVENT;
-import static android.app.Notification.CATEGORY_MESSAGE;
-import static android.app.Notification.CATEGORY_REMINDER;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
-
-import android.annotation.NonNull;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.Person;
-import android.content.Context;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.SnoozeCriterion;
-import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.view.View;
-import android.widget.ImageView;
-
-import androidx.annotation.Nullable;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.ContrastColorUtil;
-import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.InflationTask;
-import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationGuts;
-import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * The list of currently displaying notifications.
- */
-public class NotificationData {
-
-    private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class);
-
-    /**
-     * These dependencies are late init-ed
-     */
-    private KeyguardEnvironment mEnvironment;
-    private NotificationMediaManager mMediaManager;
-
-    private HeadsUpManager mHeadsUpManager;
-
-    public static final class Entry {
-        private static final long LAUNCH_COOLDOWN = 2000;
-        private static final long REMOTE_INPUT_COOLDOWN = 500;
-        private static final long INITIALIZATION_DELAY = 400;
-        private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN;
-        private static final int COLOR_INVALID = 1;
-        public final String key;
-        public StatusBarNotification notification;
-        public NotificationChannel channel;
-        public long lastAudiblyAlertedMs;
-        public boolean noisy;
-        public boolean ambient;
-        public int importance;
-        public StatusBarIconView icon;
-        public StatusBarIconView expandedIcon;
-        private boolean interruption;
-        public boolean autoRedacted; // whether the redacted notification was generated by us
-        public int targetSdk;
-        private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
-        public CharSequence remoteInputText;
-        public List<SnoozeCriterion> snoozeCriteria;
-        public int userSentiment = Ranking.USER_SENTIMENT_NEUTRAL;
-        /** Smart Actions provided by the NotificationAssistantService. */
-        @NonNull
-        public List<Notification.Action> systemGeneratedSmartActions = Collections.emptyList();
-        public CharSequence[] smartReplies = new CharSequence[0];
-        @VisibleForTesting
-        public int suppressedVisualEffects;
-        public boolean suspended;
-
-        private Entry parent; // our parent (if we're in a group)
-        private ArrayList<Entry> children = new ArrayList<Entry>();
-        private ExpandableNotificationRow row; // the outer expanded view
-
-        private int mCachedContrastColor = COLOR_INVALID;
-        private int mCachedContrastColorIsFor = COLOR_INVALID;
-        private InflationTask mRunningTask = null;
-        private Throwable mDebugThrowable;
-        public CharSequence remoteInputTextWhenReset;
-        public long lastRemoteInputSent = NOT_LAUNCHED_YET;
-        public ArraySet<Integer> mActiveAppOps = new ArraySet<>(3);
-        public CharSequence headsUpStatusBarText;
-        public CharSequence headsUpStatusBarTextPublic;
-
-        private long initializationTime = -1;
-
-        /**
-         * Whether or not this row represents a system notification. Note that if this is
-         * {@code null}, that means we were either unable to retrieve the info or have yet to
-         * retrieve the info.
-         */
-        public Boolean mIsSystemNotification;
-
-        /**
-         * Has the user sent a reply through this Notification.
-         */
-        private boolean hasSentReply;
-
-        /**
-         * Whether this notification should be displayed as a bubble.
-         */
-        private boolean mIsBubble;
-
-        /**
-         * Whether the user has dismissed this notification when it was in bubble form.
-         */
-        private boolean mUserDismissedBubble;
-
-        public Entry(StatusBarNotification n) {
-            this(n, null);
-        }
-
-        public Entry(StatusBarNotification n, @Nullable Ranking ranking) {
-            this.key = n.getKey();
-            this.notification = n;
-            if (ranking != null) {
-                populateFromRanking(ranking);
-            }
-        }
-
-        public void populateFromRanking(@NonNull Ranking ranking) {
-            channel = ranking.getChannel();
-            lastAudiblyAlertedMs = ranking.getLastAudiblyAlertedMillis();
-            importance = ranking.getImportance();
-            ambient = ranking.isAmbient();
-            snoozeCriteria = ranking.getSnoozeCriteria();
-            userSentiment = ranking.getUserSentiment();
-            systemGeneratedSmartActions = ranking.getSmartActions() == null
-                    ? Collections.emptyList() : ranking.getSmartActions();
-            smartReplies = ranking.getSmartReplies() == null
-                    ? new CharSequence[0]
-                    : ranking.getSmartReplies().toArray(new CharSequence[0]);
-            suppressedVisualEffects = ranking.getSuppressedVisualEffects();
-            suspended = ranking.isSuspended();
-        }
-
-        public void setInterruption() {
-            interruption = true;
-        }
-
-        public boolean hasInterrupted() {
-            return interruption;
-        }
-
-        public void setIsBubble(boolean bubbleable) {
-            mIsBubble = bubbleable;
-        }
-
-        public boolean isBubble() {
-            return mIsBubble;
-        }
-
-        public void setBubbleDismissed(boolean userDismissed) {
-            mUserDismissedBubble = userDismissed;
-        }
-
-        public boolean isBubbleDismissed() {
-            return mUserDismissedBubble;
-        }
-
-        /**
-         * Resets the notification entry to be re-used.
-         */
-        public void reset() {
-            if (row != null) {
-                row.reset();
-            }
-        }
-
-        public ExpandableNotificationRow getRow() {
-            return row;
-        }
-
-        //TODO: This will go away when we have a way to bind an entry to a row
-        public void setRow(ExpandableNotificationRow row) {
-            this.row = row;
-        }
-
-        @Nullable
-        public List<Entry> getChildren() {
-            if (children.size() <= 0) {
-                return null;
-            }
-
-            return children;
-        }
-
-        public void notifyFullScreenIntentLaunched() {
-            setInterruption();
-            lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
-        }
-
-        public boolean hasJustLaunchedFullScreenIntent() {
-            return SystemClock.elapsedRealtime() < lastFullScreenIntentLaunchTime + LAUNCH_COOLDOWN;
-        }
-
-        public boolean hasJustSentRemoteInput() {
-            return SystemClock.elapsedRealtime() < lastRemoteInputSent + REMOTE_INPUT_COOLDOWN;
-        }
-
-        public boolean hasFinishedInitialization() {
-            return initializationTime == -1 ||
-                    SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY;
-        }
-
-        /**
-         * Create the icons for a notification
-         * @param context the context to create the icons with
-         * @param sbn the notification
-         * @throws InflationException
-         */
-        public void createIcons(Context context, StatusBarNotification sbn)
-                throws InflationException {
-            Notification n = sbn.getNotification();
-            final Icon smallIcon = n.getSmallIcon();
-            if (smallIcon == null) {
-                throw new InflationException("No small icon in notification from "
-                        + sbn.getPackageName());
-            }
-
-            // Construct the icon.
-            icon = new StatusBarIconView(context,
-                    sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
-            icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-
-            // Construct the expanded icon.
-            expandedIcon = new StatusBarIconView(context,
-                    sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
-            expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-            final StatusBarIcon ic = new StatusBarIcon(
-                    sbn.getUser(),
-                    sbn.getPackageName(),
-                    smallIcon,
-                    n.iconLevel,
-                    n.number,
-                    StatusBarIconView.contentDescForNotification(context, n));
-            if (!icon.set(ic) || !expandedIcon.set(ic)) {
-                icon = null;
-                expandedIcon = null;
-                throw new InflationException("Couldn't create icon: " + ic);
-            }
-            expandedIcon.setVisibility(View.INVISIBLE);
-            expandedIcon.setOnVisibilityChangedListener(
-                    newVisibility -> {
-                        if (row != null) {
-                            row.setIconsVisible(newVisibility != View.VISIBLE);
-                        }
-                    });
-        }
-
-        public void setIconTag(int key, Object tag) {
-            if (icon != null) {
-                icon.setTag(key, tag);
-                expandedIcon.setTag(key, tag);
-            }
-        }
-
-        /**
-         * Update the notification icons.
-         *
-         * @param context the context to create the icons with.
-         * @param sbn the notification to read the icon from.
-         * @throws InflationException
-         */
-        public void updateIcons(Context context, StatusBarNotification sbn)
-                throws InflationException {
-            if (icon != null) {
-                // Update the icon
-                Notification n = sbn.getNotification();
-                final StatusBarIcon ic = new StatusBarIcon(
-                        notification.getUser(),
-                        notification.getPackageName(),
-                        n.getSmallIcon(),
-                        n.iconLevel,
-                        n.number,
-                        StatusBarIconView.contentDescForNotification(context, n));
-                icon.setNotification(sbn);
-                expandedIcon.setNotification(sbn);
-                if (!icon.set(ic) || !expandedIcon.set(ic)) {
-                    throw new InflationException("Couldn't update icon: " + ic);
-                }
-            }
-        }
-
-        public int getContrastedColor(Context context, boolean isLowPriority,
-                int backgroundColor) {
-            int rawColor = isLowPriority ? Notification.COLOR_DEFAULT :
-                    notification.getNotification().color;
-            if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
-                return mCachedContrastColor;
-            }
-            final int contrasted = ContrastColorUtil.resolveContrastColor(context, rawColor,
-                    backgroundColor);
-            mCachedContrastColorIsFor = rawColor;
-            mCachedContrastColor = contrasted;
-            return mCachedContrastColor;
-        }
-
-        /**
-         * Abort all existing inflation tasks
-         */
-        public void abortTask() {
-            if (mRunningTask != null) {
-                mRunningTask.abort();
-                mRunningTask = null;
-            }
-        }
-
-        public void setInflationTask(InflationTask abortableTask) {
-            // abort any existing inflation
-            InflationTask existing = mRunningTask;
-            abortTask();
-            mRunningTask = abortableTask;
-            if (existing != null && mRunningTask != null) {
-                mRunningTask.supersedeTask(existing);
-            }
-        }
-
-        public void onInflationTaskFinished() {
-            mRunningTask = null;
-        }
-
-        @VisibleForTesting
-        public InflationTask getRunningTask() {
-            return mRunningTask;
-        }
-
-        /**
-         * Set a throwable that is used for debugging
-         *
-         * @param debugThrowable the throwable to save
-         */
-        public void setDebugThrowable(Throwable debugThrowable) {
-            mDebugThrowable = debugThrowable;
-        }
-
-        public Throwable getDebugThrowable() {
-            return mDebugThrowable;
-        }
-
-        public void onRemoteInputInserted() {
-            lastRemoteInputSent = NOT_LAUNCHED_YET;
-            remoteInputTextWhenReset = null;
-        }
-
-        public void setHasSentReply() {
-            hasSentReply = true;
-        }
-
-        public boolean isLastMessageFromReply() {
-            if (!hasSentReply) {
-                return false;
-            }
-            Bundle extras = notification.getNotification().extras;
-            CharSequence[] replyTexts = extras.getCharSequenceArray(
-                    Notification.EXTRA_REMOTE_INPUT_HISTORY);
-            if (!ArrayUtils.isEmpty(replyTexts)) {
-                return true;
-            }
-            Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
-            if (messages != null && messages.length > 0) {
-                Parcelable message = messages[messages.length - 1];
-                if (message instanceof Bundle) {
-                    Notification.MessagingStyle.Message lastMessage =
-                            Notification.MessagingStyle.Message.getMessageFromBundle(
-                                    (Bundle) message);
-                    if (lastMessage != null) {
-                        Person senderPerson = lastMessage.getSenderPerson();
-                        if (senderPerson == null) {
-                            return true;
-                        }
-                        Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON);
-                        return Objects.equals(user, senderPerson);
-                    }
-                }
-            }
-            return false;
-        }
-
-        public void setInitializationTime(long time) {
-            if (initializationTime == -1) {
-                initializationTime = time;
-            }
-        }
-
-        public void sendAccessibilityEvent(int eventType) {
-            if (row != null) {
-                row.sendAccessibilityEvent(eventType);
-            }
-        }
-
-        /**
-         * Used by NotificationMediaManager to determine... things
-         * @return {@code true} if we are a media notification
-         */
-        public boolean isMediaNotification() {
-            if (row == null) return false;
-
-            return row.isMediaRow();
-        }
-
-        /**
-         * We are a top level child if our parent is the list of notifications duh
-         * @return {@code true} if we're a top level notification
-         */
-        public boolean isTopLevelChild() {
-            return row != null && row.isTopLevelChild();
-        }
-
-        public void resetUserExpansion() {
-            if (row != null) row.resetUserExpansion();
-        }
-
-        public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) {
-            if (row != null) row.freeContentViewWhenSafe(inflationFlag);
-        }
-
-        public void setAmbientPulsing(boolean pulsing) {
-            if (row != null) row.setAmbientPulsing(pulsing);
-        }
-
-        public boolean rowExists() {
-            return row != null;
-        }
-
-        public boolean isRowDismissed() {
-            return row != null && row.isDismissed();
-        }
-
-        public boolean isRowRemoved() {
-            return row != null && row.isRemoved();
-        }
-
-        /**
-         * @return {@code true} if the row is null or removed
-         */
-        public boolean isRemoved() {
-            //TODO: recycling invalidates this
-            return row == null || row.isRemoved();
-        }
-
-        /**
-         * @return {@code true} if the row is null or dismissed
-         */
-        public boolean isDismissed() {
-            //TODO: recycling
-            return row == null || row.isDismissed();
-        }
-
-        public boolean isRowPinned() {
-            return row != null && row.isPinned();
-        }
-
-        public void setRowPinned(boolean pinned) {
-            if (row != null) row.setPinned(pinned);
-        }
-
-        public boolean isRowAnimatingAway() {
-            return row != null && row.isHeadsUpAnimatingAway();
-        }
-
-        public boolean isRowHeadsUp() {
-            return row != null && row.isHeadsUp();
-        }
-
-        public void setHeadsUp(boolean shouldHeadsUp) {
-            if (row != null) row.setHeadsUp(shouldHeadsUp);
-        }
-
-        public boolean mustStayOnScreen() {
-            return row != null && row.mustStayOnScreen();
-        }
-
-        public void setHeadsUpIsVisible() {
-            if (row != null) row.setHeadsUpIsVisible();
-        }
-
-        //TODO: i'm imagining a world where this isn't just the row, but I could be rwong
-        public ExpandableNotificationRow getHeadsUpAnimationView() {
-            return row;
-        }
-
-        public void setUserLocked(boolean userLocked) {
-            if (row != null) row.setUserLocked(userLocked);
-        }
-
-        public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
-            if (row != null) row.setUserExpanded(userExpanded, allowChildExpansion);
-        }
-
-        public void setGroupExpansionChanging(boolean changing) {
-            if (row != null) row.setGroupExpansionChanging(changing);
-        }
-
-        public void notifyHeightChanged(boolean needsAnimation) {
-            if (row != null) row.notifyHeightChanged(needsAnimation);
-        }
-
-        public void closeRemoteInput() {
-            if (row != null) row.closeRemoteInput();
-        }
-
-        public boolean areChildrenExpanded() {
-            return row != null && row.areChildrenExpanded();
-        }
-
-        public boolean keepInParent() {
-            return row != null && row.keepInParent();
-        }
-
-        //TODO: probably less confusing to say "is group fully visible"
-        public boolean isGroupNotFullyVisible() {
-            return row == null || row.isGroupNotFullyVisible();
-        }
-
-        public NotificationGuts getGuts() {
-            if (row != null) return row.getGuts();
-            return null;
-        }
-
-        public boolean hasLowPriorityStateUpdated() {
-            return row != null && row.hasLowPriorityStateUpdated();
-        }
-
-        public void removeRow() {
-            if (row != null) row.setRemoved();
-        }
-
-        public boolean isSummaryWithChildren() {
-            return row != null && row.isSummaryWithChildren();
-        }
-
-        public void setKeepInParent(boolean keep) {
-            if (row != null) row.setKeepInParent(keep);
-        }
-
-        public void onDensityOrFontScaleChanged() {
-            if (row != null) row.onDensityOrFontScaleChanged();
-        }
-
-        public boolean areGutsExposed() {
-            return row != null && row.getGuts() != null && row.getGuts().isExposed();
-        }
-
-        public boolean isChildInGroup() {
-            return parent == null;
-        }
-
-        public void setLowPriorityStateUpdated(boolean updated) {
-            if (row != null) row.setLowPriorityStateUpdated(updated);
-        }
-
-        /**
-         * @return Can the underlying notification be cleared? This can be different from whether the
-         *         notification can be dismissed in case notifications are sensitive on the lockscreen.
-         * @see #canViewBeDismissed()
-         */
-        public boolean isClearable() {
-            if (notification == null || !notification.isClearable()) {
-                return false;
-            }
-            if (children.size() > 0) {
-                for (int i = 0; i < children.size(); i++) {
-                    Entry child =  children.get(i);
-                    if (!child.isClearable()) {
-                        return false;
-                    }
-                }
-            }
-            return true;
-        }
-
-        public boolean canViewBeDismissed() {
-            if (row == null) return true;
-            return row.canViewBeDismissed();
-        }
-
-        boolean isExemptFromDndVisualSuppression() {
-            if (isNotificationBlockedByPolicy(notification.getNotification())) {
-                return false;
-            }
-
-            if ((notification.getNotification().flags
-                    & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
-                return true;
-            }
-            if (notification.getNotification().isMediaNotification()) {
-                return true;
-            }
-            if (mIsSystemNotification != null && mIsSystemNotification) {
-                return true;
-            }
-            return false;
-        }
-
-        private boolean shouldSuppressVisualEffect(int effect) {
-            if (isExemptFromDndVisualSuppression()) {
-                return false;
-            }
-            return (suppressedVisualEffects & effect) != 0;
-        }
-
-        /**
-         * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_FULL_SCREEN_INTENT}
-         * is set for this entry.
-         */
-        public boolean shouldSuppressFullScreenIntent() {
-            return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
-        }
-
-        /**
-         * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_PEEK}
-         * is set for this entry.
-         */
-        public boolean shouldSuppressPeek() {
-            return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_PEEK);
-        }
-
-        /**
-         * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_STATUS_BAR}
-         * is set for this entry.
-         */
-        public boolean shouldSuppressStatusBar() {
-            return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_STATUS_BAR);
-        }
-
-        /**
-         * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_AMBIENT}
-         * is set for this entry.
-         */
-        public boolean shouldSuppressAmbient() {
-            return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_AMBIENT);
-        }
-
-        /**
-         * Returns whether {@link NotificationManager.Policy#SUPPRESSED_EFFECT_NOTIFICATION_LIST}
-         * is set for this entry.
-         */
-        public boolean shouldSuppressNotificationList() {
-            return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_NOTIFICATION_LIST);
-        }
-    }
-
-    private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
-    private final ArrayList<Entry> mSortedAndFiltered = new ArrayList<>();
-    private final ArrayList<Entry> mFilteredForUser = new ArrayList<>();
-
-    private final NotificationGroupManager mGroupManager
-            = Dependency.get(NotificationGroupManager.class);
-
-    private RankingMap mRankingMap;
-    private final Ranking mTmpRanking = new Ranking();
-
-    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
-        mHeadsUpManager = headsUpManager;
-    }
-
-    private final Comparator<Entry> mRankingComparator = new Comparator<Entry>() {
-        private final Ranking mRankingA = new Ranking();
-        private final Ranking mRankingB = new Ranking();
-
-        @Override
-        public int compare(Entry a, Entry b) {
-            final StatusBarNotification na = a.notification;
-            final StatusBarNotification nb = b.notification;
-            int aImportance = NotificationManager.IMPORTANCE_DEFAULT;
-            int bImportance = NotificationManager.IMPORTANCE_DEFAULT;
-            int aRank = 0;
-            int bRank = 0;
-
-            if (mRankingMap != null) {
-                // RankingMap as received from NoMan
-                getRanking(a.key, mRankingA);
-                getRanking(b.key, mRankingB);
-                aImportance = mRankingA.getImportance();
-                bImportance = mRankingB.getImportance();
-                aRank = mRankingA.getRank();
-                bRank = mRankingB.getRank();
-            }
-
-            String mediaNotification = getMediaManager().getMediaNotificationKey();
-
-            // IMPORTANCE_MIN media streams are allowed to drift to the bottom
-            final boolean aMedia = a.key.equals(mediaNotification)
-                    && aImportance > NotificationManager.IMPORTANCE_MIN;
-            final boolean bMedia = b.key.equals(mediaNotification)
-                    && bImportance > NotificationManager.IMPORTANCE_MIN;
-
-            boolean aSystemMax = aImportance >= NotificationManager.IMPORTANCE_HIGH &&
-                    isSystemNotification(na);
-            boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH &&
-                    isSystemNotification(nb);
-
-            boolean isHeadsUp = a.row.isHeadsUp();
-            if (isHeadsUp != b.row.isHeadsUp()) {
-                return isHeadsUp ? -1 : 1;
-            } 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;
-            } else if (aSystemMax != bSystemMax) {
-                // Upsort PRIORITY_MAX system notifications
-                return aSystemMax ? -1 : 1;
-            } else if (aRank != bRank) {
-                return aRank - bRank;
-            } else {
-                return Long.compare(nb.getNotification().when, na.getNotification().when);
-            }
-        }
-    };
-
-    private KeyguardEnvironment getEnvironment() {
-        if (mEnvironment == null) {
-            mEnvironment = Dependency.get(KeyguardEnvironment.class);
-        }
-        return mEnvironment;
-    }
-
-    private NotificationMediaManager getMediaManager() {
-        if (mMediaManager == null) {
-            mMediaManager = Dependency.get(NotificationMediaManager.class);
-        }
-        return mMediaManager;
-    }
-
-    /**
-     * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment}
-     *
-     * <p>
-     * This call doesn't update the list of active notifications. Call {@link #filterAndSort()}
-     * when the environment changes.
-     * <p>
-     * Don't hold on to or modify the returned list.
-     */
-    public ArrayList<Entry> getActiveNotifications() {
-        return mSortedAndFiltered;
-    }
-
-    public ArrayList<Entry> getNotificationsForCurrentUser() {
-        mFilteredForUser.clear();
-
-        synchronized (mEntries) {
-            final int N = mEntries.size();
-            for (int i = 0; i < N; i++) {
-                Entry entry = mEntries.valueAt(i);
-                final StatusBarNotification sbn = entry.notification;
-                if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
-                    continue;
-                }
-                mFilteredForUser.add(entry);
-            }
-        }
-        return mFilteredForUser;
-    }
-
-    public Entry get(String key) {
-        return mEntries.get(key);
-    }
-
-    public void add(Entry entry) {
-        synchronized (mEntries) {
-            mEntries.put(entry.notification.getKey(), entry);
-        }
-        mGroupManager.onEntryAdded(entry);
-
-        updateRankingAndSort(mRankingMap);
-    }
-
-    public Entry remove(String key, RankingMap ranking) {
-        Entry removed;
-        synchronized (mEntries) {
-            removed = mEntries.remove(key);
-        }
-        if (removed == null) return null;
-        mGroupManager.onEntryRemoved(removed);
-        updateRankingAndSort(ranking);
-        return removed;
-    }
-
-    /** Updates the given notification entry with the provided ranking. */
-    public void update(Entry entry, RankingMap ranking, StatusBarNotification notification) {
-        updateRanking(ranking);
-        final StatusBarNotification oldNotification = entry.notification;
-        entry.notification = notification;
-        mGroupManager.onEntryUpdated(entry, oldNotification);
-    }
-
-    public void updateRanking(RankingMap ranking) {
-        updateRankingAndSort(ranking);
-    }
-
-    public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) {
-        synchronized (mEntries) {
-            final int N = mEntries.size();
-            for (int i = 0; i < N; i++) {
-                Entry entry = mEntries.valueAt(i);
-                if (uid == entry.notification.getUid()
-                        && pkg.equals(entry.notification.getPackageName())
-                        && key.equals(entry.key)) {
-                    if (showIcon) {
-                        entry.mActiveAppOps.add(appOp);
-                    } else {
-                        entry.mActiveAppOps.remove(appOp);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Returns true if this notification should be displayed in the high-priority notifications
-     * section (and on the lockscreen and status bar).
-     */
-    public boolean isHighPriority(StatusBarNotification statusBarNotification) {
-        if (mRankingMap != null) {
-            getRanking(statusBarNotification.getKey(), mTmpRanking);
-            if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
-                    || statusBarNotification.getNotification().isForegroundService()
-                    || statusBarNotification.getNotification().hasMediaSession()) {
-                return true;
-            }
-            if (mGroupManager.isSummaryOfGroup(statusBarNotification)) {
-                for (Entry child : mGroupManager.getLogicalChildren(statusBarNotification)) {
-                    if (isHighPriority(child.notification)) {
-                        return true;
-                    }
-                }
-            }
-        }
-        return false;
-    }
-
-    public boolean isAmbient(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.isAmbient();
-        }
-        return false;
-    }
-
-    public int getVisibilityOverride(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.getVisibilityOverride();
-        }
-        return Ranking.VISIBILITY_NO_OVERRIDE;
-    }
-
-    /**
-     * Categories that are explicitly called out on DND settings screens are always blocked, if
-     * DND has flagged them, even if they are foreground or system notifications that might
-     * otherwise visually bypass DND.
-     */
-    private static boolean isNotificationBlockedByPolicy(Notification n) {
-        if (isCategory(CATEGORY_CALL, n)
-                || isCategory(CATEGORY_MESSAGE, n)
-                || isCategory(CATEGORY_ALARM, n)
-                || isCategory(CATEGORY_EVENT, n)
-                || isCategory(CATEGORY_REMINDER, n)) {
-            return true;
-        }
-        return false;
-    }
-
-    private static boolean isCategory(String category, Notification n) {
-        return Objects.equals(n.category, category);
-    }
-
-    public int getImportance(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.getImportance();
-        }
-        return NotificationManager.IMPORTANCE_UNSPECIFIED;
-    }
-
-    public String getOverrideGroupKey(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.getOverrideGroupKey();
-        }
-        return null;
-    }
-
-    public List<SnoozeCriterion> getSnoozeCriteria(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.getSnoozeCriteria();
-        }
-        return null;
-    }
-
-    public NotificationChannel getChannel(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.getChannel();
-        }
-        return null;
-    }
-
-    public int getRank(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.getRank();
-        }
-        return 0;
-    }
-
-    public boolean shouldHide(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.isSuspended();
-        }
-        return false;
-    }
-
-    private void updateRankingAndSort(RankingMap ranking) {
-        if (ranking != null) {
-            mRankingMap = ranking;
-            synchronized (mEntries) {
-                final int N = mEntries.size();
-                for (int i = 0; i < N; i++) {
-                    Entry entry = mEntries.valueAt(i);
-                    if (!getRanking(entry.key, mTmpRanking)) {
-                        continue;
-                    }
-                    final StatusBarNotification oldSbn = entry.notification.cloneLight();
-                    final String overrideGroupKey = getOverrideGroupKey(entry.key);
-                    if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) {
-                        entry.notification.setOverrideGroupKey(overrideGroupKey);
-                        mGroupManager.onEntryUpdated(entry, oldSbn);
-                    }
-                    entry.populateFromRanking(mTmpRanking);
-                }
-            }
-        }
-        filterAndSort();
-    }
-
-    /**
-     * Get the ranking from the current ranking map.
-     *
-     * @param key the key to look up
-     * @param outRanking the ranking to populate
-     *
-     * @return {@code true} if the ranking was properly obtained.
-     */
-    @VisibleForTesting
-    protected boolean getRanking(String key, Ranking outRanking) {
-        return mRankingMap.getRanking(key, outRanking);
-    }
-
-    // TODO: This should not be public. Instead the Environment should notify this class when
-    // anything changed, and this class should call back the UI so it updates itself.
-    public void filterAndSort() {
-        mSortedAndFiltered.clear();
-
-        synchronized (mEntries) {
-            final int N = mEntries.size();
-            for (int i = 0; i < N; i++) {
-                Entry entry = mEntries.valueAt(i);
-
-                if (mNotificationFilter.shouldFilterOut(entry)) {
-                    continue;
-                }
-
-                mSortedAndFiltered.add(entry);
-            }
-        }
-
-        Collections.sort(mSortedAndFiltered, mRankingComparator);
-    }
-
-    public void dump(PrintWriter pw, String indent) {
-        int N = mSortedAndFiltered.size();
-        pw.print(indent);
-        pw.println("active notifications: " + N);
-        int active;
-        for (active = 0; active < N; active++) {
-            NotificationData.Entry e = mSortedAndFiltered.get(active);
-            dumpEntry(pw, indent, active, e);
-        }
-        synchronized (mEntries) {
-            int M = mEntries.size();
-            pw.print(indent);
-            pw.println("inactive notifications: " + (M - active));
-            int inactiveCount = 0;
-            for (int i = 0; i < M; i++) {
-                Entry entry = mEntries.valueAt(i);
-                if (!mSortedAndFiltered.contains(entry)) {
-                    dumpEntry(pw, indent, inactiveCount, entry);
-                    inactiveCount++;
-                }
-            }
-        }
-    }
-
-    private void dumpEntry(PrintWriter pw, String indent, int i, Entry e) {
-        getRanking(e.key, mTmpRanking);
-        pw.print(indent);
-        pw.println("  [" + i + "] key=" + e.key + " icon=" + e.icon);
-        StatusBarNotification n = e.notification;
-        pw.print(indent);
-        pw.println("      pkg=" + n.getPackageName() + " id=" + n.getId() + " importance=" +
-                mTmpRanking.getImportance());
-        pw.print(indent);
-        pw.println("      notification=" + n.getNotification());
-    }
-
-    private static boolean isSystemNotification(StatusBarNotification sbn) {
-        String sbnPackage = sbn.getPackageName();
-        return "android".equals(sbnPackage) || "com.android.systemui".equals(sbnPackage);
-    }
-
-    /**
-     * Provides access to keyguard state and user settings dependent data.
-     */
-    public interface KeyguardEnvironment {
-        boolean isDeviceProvisioned();
-        boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index 1d06ce0..839b06c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -19,6 +19,7 @@
 import android.service.notification.StatusBarNotification;
 
 import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationInflater;
 
 /**
@@ -29,25 +30,38 @@
      * Called when a new notification is posted. At this point, the notification is "pending": its
      * views haven't been inflated yet and most of the system pretends like it doesn't exist yet.
      */
-    default void onPendingEntryAdded(NotificationData.Entry entry) {
+    default void onPendingEntryAdded(NotificationEntry entry) {
+    }
+
+    // TODO: Combine this with onPreEntryUpdated into "onBeforeEntryFiltered" or similar
+    /**
+     * Called when a new entry is created but before it has been filtered or displayed to the user.
+     */
+    default void onBeforeNotificationAdded(NotificationEntry entry) {
     }
 
     /**
      * Called when a new entry is created.
      */
-    default void onNotificationAdded(NotificationData.Entry entry) {
+    default void onNotificationAdded(NotificationEntry entry) {
     }
 
     /**
-     * Called when a notification was updated.
+     * Called when a notification is updated, before any filtering of notifications have occurred.
      */
-    default void onEntryUpdated(NotificationData.Entry entry) {
+    default void onPreEntryUpdated(NotificationEntry entry) {
+    }
+
+    /**
+     * Called when a notification was updated, after any filtering of notifications have occurred.
+     */
+    default void onPostEntryUpdated(NotificationEntry entry) {
     }
 
     /**
      * Called when a notification's views are inflated for the first time.
      */
-    default void onEntryInflated(NotificationData.Entry entry,
+    default void onEntryInflated(NotificationEntry entry,
             @NotificationInflater.InflationFlag int inflatedFlags) {
     }
 
@@ -57,7 +71,7 @@
      *
      * @param entry notification data entry that was reinflated.
      */
-    default void onEntryReinflated(NotificationData.Entry entry) {
+    default void onEntryReinflated(NotificationEntry entry) {
     }
 
     /**
@@ -71,20 +85,14 @@
      * because the developer retracted it).
      * @param entry notification data entry that was removed.  Null if no entry existed for the
      *              removed key at the time of removal.
-     * @param key key of notification that was removed
-     * @param old StatusBarNotification of the notification before it was removed
      * @param visibility logging data related to the visibility of the notification at the time of
      *                   removal, if it was removed by a user action.  Null if it was not removed by
      *                   a user action.
-     * @param lifetimeExtended true if something is artificially extending how long the notification
      * @param removedByUser true if the notification was removed by a user action
      */
     default void onEntryRemoved(
-            @Nullable NotificationData.Entry entry,
-            String key,
-            StatusBarNotification old,
+            NotificationEntry entry,
             @Nullable NotificationVisibility visibility,
-            boolean lifetimeExtended,
             boolean removedByUser) {
     }
 }
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 e0fa723..ef5e936 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -15,18 +15,12 @@
  */
 package com.android.systemui.statusbar.notification;
 
-import static com.android.systemui.bubbles.BubbleController.DEBUG_DEMOTE_TO_NOTIF;
-
 import android.annotation.Nullable;
 import android.app.Notification;
 import android.content.Context;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -34,19 +28,18 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.ForegroundServiceController;
-import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationUiAdjustment;
 import com.android.systemui.statusbar.NotificationUpdateHandler;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationInflater;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.leak.LeakDetector;
 
@@ -55,7 +48,6 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
-import java.util.concurrent.TimeUnit;
 
 /**
  * NotificationEntryManager is responsible for the adding, removing, and updating of notifications.
@@ -66,55 +58,31 @@
         Dumpable,
         NotificationInflater.InflationCallback,
         NotificationUpdateHandler,
-        VisualStabilityManager.Callback,
-        BubbleController.BubbleDismissListener {
+        VisualStabilityManager.Callback {
     private static final String TAG = "NotificationEntryMgr";
-    protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    public static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
+    private final Context mContext;
+    @VisibleForTesting
+    protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>();
 
-    protected final Context mContext;
-    protected final HashMap<String, NotificationData.Entry> mPendingNotifications = new HashMap<>();
-
-    private final NotificationGutsManager mGutsManager =
-            Dependency.get(NotificationGutsManager.class);
-    private final DeviceProvisionedController mDeviceProvisionedController =
-            Dependency.get(DeviceProvisionedController.class);
     private final ForegroundServiceController mForegroundServiceController =
             Dependency.get(ForegroundServiceController.class);
-    private final BubbleController mBubbleController = Dependency.get(BubbleController.class);
 
     // Lazily retrieved dependencies
     private NotificationRemoteInputManager mRemoteInputManager;
     private NotificationRowBinder mNotificationRowBinder;
 
-    private final Handler mDeferredNotificationViewUpdateHandler;
-    private Runnable mUpdateNotificationViewsCallback;
-
     private NotificationPresenter mPresenter;
-    protected PowerManager mPowerManager;
     private NotificationListenerService.RankingMap mLatestRankingMap;
-    protected HeadsUpManager mHeadsUpManager;
+    @VisibleForTesting
     protected NotificationData mNotificationData;
-    protected NotificationListContainer mListContainer;
+
     @VisibleForTesting
     final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders
             = new ArrayList<>();
     private final List<NotificationEntryListener> mNotificationEntryListeners = new ArrayList<>();
 
-    private final DeviceProvisionedController.DeviceProvisionedListener
-            mDeviceProvisionedListener =
-            new DeviceProvisionedController.DeviceProvisionedListener() {
-                @Override
-                public void onDeviceProvisionedChanged() {
-                    updateNotifications();
-                }
-            };
-
-    public void destroy() {
-        mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
-    }
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("NotificationEntryManager state:");
@@ -122,7 +90,7 @@
         if (mPendingNotifications.size() == 0) {
             pw.println("null");
         } else {
-            for (NotificationData.Entry entry : mPendingNotifications.values()) {
+            for (NotificationEntry entry : mPendingNotifications.values()) {
                 pw.println(entry.notification);
             }
         }
@@ -130,10 +98,7 @@
 
     public NotificationEntryManager(Context context) {
         mContext = context;
-        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-        mBubbleController.setDismissListener(this /* bubbleEventListener */);
         mNotificationData = new NotificationData();
-        mDeferredNotificationViewUpdateHandler = new Handler();
     }
 
     /** Adds a {@link NotificationEntryListener}. */
@@ -158,16 +123,17 @@
         return mNotificationRowBinder;
     }
 
+    // TODO: Remove this once we can always use a mocked row binder in our tests
+    @VisibleForTesting
+    void setRowBinder(NotificationRowBinder notificationRowBinder) {
+        mNotificationRowBinder = notificationRowBinder;
+    }
+
     public void setUpWithPresenter(NotificationPresenter presenter,
             NotificationListContainer listContainer,
             HeadsUpManager headsUpManager) {
         mPresenter = presenter;
-        mUpdateNotificationViewsCallback = mPresenter::updateNotificationViews;
-        mHeadsUpManager = headsUpManager;
-        mNotificationData.setHeadsUpManager(mHeadsUpManager);
-        mListContainer = listContainer;
-
-        mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
+        mNotificationData.setHeadsUpManager(headsUpManager);
     }
 
     /** Adds multiple {@link NotificationLifetimeExtender}s. */
@@ -187,18 +153,6 @@
         return mNotificationData;
     }
 
-    protected Context getContext() {
-        return mContext;
-    }
-
-    protected NotificationPresenter getPresenter() {
-        return mPresenter;
-    }
-
-    public ExpandableNotificationRow.LongPressListener getNotificationLongClicker() {
-        return getRowBinder().getNotificationLongClicker();
-    }
-
     @Override
     public void onReorderingAllowed() {
         updateNotifications();
@@ -207,36 +161,21 @@
     public void performRemoveNotification(StatusBarNotification n) {
         final int rank = mNotificationData.getRank(n.getKey());
         final int count = mNotificationData.getActiveNotifications().size();
+        NotificationVisibility.NotificationLocation location =
+                NotificationLogger.getNotificationLocation(getNotificationData().get(n.getKey()));
         final NotificationVisibility nv = NotificationVisibility.obtain(n.getKey(), rank, count,
-                true);
+                true, location);
         removeNotificationInternal(
                 n.getKey(), null, nv, false /* forceRemove */, true /* removedByUser */);
     }
 
-    @Override
-    public void onStackDismissed() {
-        updateNotifications();
-    }
-
-    @Override
-    public void onBubbleDismissed(String key) {
-        NotificationData.Entry entry = mNotificationData.get(key);
-        if (entry != null) {
-            entry.setBubbleDismissed(true);
-            if (!DEBUG_DEMOTE_TO_NOTIF) {
-                performRemoveNotification(entry.notification);
-            }
-        }
-        updateNotifications();
-    }
-
     private void abortExistingInflation(String key) {
         if (mPendingNotifications.containsKey(key)) {
-            NotificationData.Entry entry = mPendingNotifications.get(key);
+            NotificationEntry entry = mPendingNotifications.get(key);
             entry.abortTask();
             mPendingNotifications.remove(key);
         }
-        NotificationData.Entry addedEntry = mNotificationData.get(key);
+        NotificationEntry addedEntry = mNotificationData.get(key);
         if (addedEntry != null) {
             addedEntry.abortTask();
         }
@@ -257,32 +196,8 @@
         }
     }
 
-    private void addEntry(NotificationData.Entry shadeEntry) {
-        if (shadeEntry == null) {
-            return;
-        }
-        // Add the expanded view and icon.
-        mNotificationData.add(shadeEntry);
-        tagForeground(shadeEntry.notification);
-        updateNotifications();
-        for (NotificationEntryListener listener : mNotificationEntryListeners) {
-            listener.onNotificationAdded(shadeEntry);
-        }
-
-        maybeScheduleUpdateNotificationViews(shadeEntry);
-    }
-
-    private void maybeScheduleUpdateNotificationViews(NotificationData.Entry entry) {
-        long audibleAlertTimeout = RECENTLY_ALERTED_THRESHOLD_MS
-                - (System.currentTimeMillis() - entry.lastAudiblyAlertedMs);
-        if (audibleAlertTimeout > 0) {
-            mDeferredNotificationViewUpdateHandler.postDelayed(
-                    mUpdateNotificationViewsCallback, audibleAlertTimeout);
-        }
-    }
-
     @Override
-    public void onAsyncInflationFinished(NotificationData.Entry entry,
+    public void onAsyncInflationFinished(NotificationEntry entry,
             @InflationFlag int inflatedFlags) {
         mPendingNotifications.remove(entry.key);
         // If there was an async task started after the removal, we don't want to add it back to
@@ -293,7 +208,14 @@
                 for (NotificationEntryListener listener : mNotificationEntryListeners) {
                     listener.onEntryInflated(entry, inflatedFlags);
                 }
-                addEntry(entry);
+                mNotificationData.add(entry);
+                for (NotificationEntryListener listener : mNotificationEntryListeners) {
+                    listener.onBeforeNotificationAdded(entry);
+                }
+                updateNotifications();
+                for (NotificationEntryListener listener : mNotificationEntryListeners) {
+                    listener.onNotificationAdded(entry);
+                }
             } else {
                 for (NotificationEntryListener listener : mNotificationEntryListeners) {
                     listener.onEntryReinflated(entry);
@@ -315,11 +237,10 @@
             @Nullable NotificationVisibility visibility,
             boolean forceRemove,
             boolean removedByUser) {
-        final NotificationData.Entry entry = mNotificationData.get(key);
+        final NotificationEntry entry = mNotificationData.get(key);
 
         abortExistingInflation(key);
 
-        StatusBarNotification old = null;
         boolean lifetimeExtended = false;
 
         if (entry != null) {
@@ -344,35 +265,22 @@
                     extender.setShouldManageLifetime(entry, false /* shouldManage */);
                 }
 
-                mForegroundServiceController.removeNotification(entry.notification);
-
                 if (entry.rowExists()) {
                     entry.removeRow();
-                    mListContainer.cleanUpViewStateForEntry(entry);
                 }
 
                 // Let's remove the children if this was a summary
                 handleGroupSummaryRemoved(key);
 
-                old = removeNotificationViews(key, ranking);
+                mNotificationData.remove(key, ranking);
+                updateNotifications();
+                Dependency.get(LeakDetector.class).trackGarbage(entry);
+
+                for (NotificationEntryListener listener : mNotificationEntryListeners) {
+                    listener.onEntryRemoved(entry, visibility, removedByUser);
+                }
             }
         }
-
-        for (NotificationEntryListener listener : mNotificationEntryListeners) {
-            listener.onEntryRemoved(entry, key, old, visibility, lifetimeExtended, removedByUser);
-        }
-    }
-
-    private StatusBarNotification removeNotificationViews(String key,
-            NotificationListenerService.RankingMap ranking) {
-        NotificationData.Entry entry = mNotificationData.remove(key, ranking);
-        if (entry == null) {
-            Log.w(TAG, "removeNotification for unknown key: " + key);
-            return null;
-        }
-        updateNotifications();
-        Dependency.get(LeakDetector.class).trackGarbage(entry);
-        return entry.notification;
     }
 
     /**
@@ -386,19 +294,19 @@
      *
      */
     private void handleGroupSummaryRemoved(String key) {
-        NotificationData.Entry entry = mNotificationData.get(key);
+        NotificationEntry entry = mNotificationData.get(key);
         if (entry != null && entry.rowExists() && entry.isSummaryWithChildren()) {
             if (entry.notification.getOverrideGroupKey() != null && !entry.isRowDismissed()) {
                 // We don't want to remove children for autobundled notifications as they are not
                 // always cancelled. We only remove them if they were dismissed by the user.
                 return;
             }
-            List<NotificationData.Entry> childEntries = entry.getChildren();
+            List<NotificationEntry> childEntries = entry.getChildren();
             if (childEntries == null) {
                 return;
             }
             for (int i = 0; i < childEntries.size(); i++) {
-                NotificationData.Entry childEntry = childEntries.get(i);
+                NotificationEntry childEntry = childEntries.get(i);
                 boolean isForeground = (entry.notification.getNotification().flags
                         & Notification.FLAG_FOREGROUND_SERVICE) != 0;
                 boolean keepForReply =
@@ -417,39 +325,6 @@
         }
     }
 
-    public void updateNotificationsOnDensityOrFontScaleChanged() {
-        ArrayList<NotificationData.Entry> userNotifications =
-                mNotificationData.getNotificationsForCurrentUser();
-        for (int i = 0; i < userNotifications.size(); i++) {
-            NotificationData.Entry entry = userNotifications.get(i);
-            entry.onDensityOrFontScaleChanged();
-            boolean exposedGuts = entry.areGutsExposed();
-            if (exposedGuts) {
-                mGutsManager.onDensityOrFontScaleChanged(entry);
-            }
-        }
-    }
-
-    private NotificationData.Entry createNotificationEntry(
-            StatusBarNotification sbn, NotificationListenerService.Ranking ranking)
-            throws InflationException {
-        if (DEBUG) {
-            Log.d(TAG, "createNotificationEntry(notification=" + sbn + " " + ranking);
-        }
-
-        NotificationData.Entry entry = new NotificationData.Entry(sbn, ranking);
-        if (BubbleController.shouldAutoBubble(getContext(), entry)) {
-            entry.setIsBubble(true);
-        }
-
-        Dependency.get(LeakDetector.class).trackInstance(entry);
-        entry.createIcons(mContext, sbn);
-        // Construct the expanded view.
-        getRowBinder().inflateViews(entry, () -> performRemoveNotification(sbn),
-                mNotificationData.get(entry.key) != null);
-        return entry;
-    }
-
     private void addNotificationInternal(StatusBarNotification notification,
             NotificationListenerService.RankingMap rankingMap) throws InflationException {
         String key = notification.getKey();
@@ -460,11 +335,15 @@
         mNotificationData.updateRanking(rankingMap);
         NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking();
         rankingMap.getRanking(key, ranking);
-        NotificationData.Entry entry = createNotificationEntry(notification, ranking);
-        abortExistingInflation(key);
 
-        mForegroundServiceController.addNotification(notification,
-                mNotificationData.getImportance(key));
+        NotificationEntry entry = new NotificationEntry(notification, ranking);
+
+        Dependency.get(LeakDetector.class).trackInstance(entry);
+        // Construct the expanded view.
+        getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification),
+                mNotificationData.get(entry.key) != null);
+
+        abortExistingInflation(key);
 
         mPendingNotifications.put(key, entry);
         for (NotificationEntryListener listener : mNotificationEntryListeners) {
@@ -472,19 +351,6 @@
         }
     }
 
-    @VisibleForTesting
-    void tagForeground(StatusBarNotification notification) {
-        ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps(
-                notification.getUserId(), notification.getPackageName());
-        if (activeOps != null) {
-            int N = activeOps.size();
-            for (int i = 0; i < N; i++) {
-                updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(),
-                        notification.getPackageName(), true);
-            }
-        }
-    }
-
     @Override
     public void addNotification(StatusBarNotification notification,
             NotificationListenerService.RankingMap ranking) {
@@ -495,22 +361,13 @@
         }
     }
 
-    public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) {
-        String foregroundKey = mForegroundServiceController.getStandardLayoutKey(
-                UserHandle.getUserId(uid), pkg);
-        if (foregroundKey != null) {
-            mNotificationData.updateAppOp(appOp, uid, pkg, foregroundKey, showIcon);
-            updateNotifications();
-        }
-    }
-
     private void updateNotificationInternal(StatusBarNotification notification,
             NotificationListenerService.RankingMap ranking) throws InflationException {
         if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
 
         final String key = notification.getKey();
         abortExistingInflation(key);
-        NotificationData.Entry entry = mNotificationData.get(key);
+        NotificationEntry entry = mNotificationData.get(key);
         if (entry == null) {
             return;
         }
@@ -523,21 +380,15 @@
 
         mNotificationData.update(entry, ranking, notification);
 
-        entry.updateIcons(mContext, notification);
         getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification),
                 mNotificationData.get(entry.key) != null);
 
-        mForegroundServiceController.updateNotification(notification,
-                mNotificationData.getImportance(key));
+        for (NotificationEntryListener listener : mNotificationEntryListeners) {
+            listener.onPreEntryUpdated(entry);
+        }
 
         updateNotifications();
 
-        if (!notification.isClearable()) {
-            // The user may have performed a dismiss action on the notification, since it's
-            // not clearable we should snap it back.
-            mListContainer.snapViewIfNeeded(entry);
-        }
-
         if (DEBUG) {
             // Is this for you?
             boolean isForCurrentUser = Dependency.get(KeyguardEnvironment.class)
@@ -546,10 +397,8 @@
         }
 
         for (NotificationEntryListener listener : mNotificationEntryListeners) {
-            listener.onEntryUpdated(entry);
+            listener.onPostEntryUpdated(entry);
         }
-
-        maybeScheduleUpdateNotificationViews(entry);
     }
 
     @Override
@@ -564,19 +413,20 @@
 
     public void updateNotifications() {
         mNotificationData.filterAndSort();
-
-        mPresenter.updateNotificationViews();
+        if (mPresenter != null) {
+            mPresenter.updateNotificationViews();
+        }
     }
 
     public void updateNotificationRanking(NotificationListenerService.RankingMap rankingMap) {
-        List<NotificationData.Entry> entries = new ArrayList<>();
+        List<NotificationEntry> entries = new ArrayList<>();
         entries.addAll(mNotificationData.getActiveNotifications());
         entries.addAll(mPendingNotifications.values());
 
         // Has a copy of the current UI adjustments.
         ArrayMap<String, NotificationUiAdjustment> oldAdjustments = new ArrayMap<>();
         ArrayMap<String, Integer> oldImportances = new ArrayMap<>();
-        for (NotificationData.Entry entry : entries) {
+        for (NotificationEntry entry : entries) {
             NotificationUiAdjustment adjustment =
                     NotificationUiAdjustment.extractFromNotificationEntry(entry);
             oldAdjustments.put(entry.key, adjustment);
@@ -588,7 +438,7 @@
         updateRankingOfPendingNotifications(rankingMap);
 
         // By comparing the old and new UI adjustments, reinflate the view accordingly.
-        for (NotificationData.Entry entry : entries) {
+        for (NotificationEntry entry : entries) {
             getRowBinder().onNotificationRankingUpdated(
                     entry,
                     oldImportances.get(entry.key),
@@ -606,7 +456,7 @@
             return;
         }
         NotificationListenerService.Ranking tmpRanking = new NotificationListenerService.Ranking();
-        for (NotificationData.Entry pendingNotification : mPendingNotifications.values()) {
+        for (NotificationEntry pendingNotification : mPendingNotifications.values()) {
             rankingMap.getRanking(pendingNotification.key, tmpRanking);
             pendingNotification.populateFromRanking(tmpRanking);
         }
@@ -617,7 +467,7 @@
      * notifications whose views have not yet been inflated. In general, the system pretends like
      * these don't exist, although there are a couple exceptions.
      */
-    public Iterable<NotificationData.Entry> getPendingNotificationsIterator() {
+    public Iterable<NotificationEntry> getPendingNotificationsIterator() {
         return mPendingNotifications.values();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index 5e99c38..154d7b35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -28,6 +28,8 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -82,7 +84,7 @@
     /**
      * @return true if the provided notification should NOT be shown right now.
      */
-    public boolean shouldFilterOut(NotificationData.Entry entry) {
+    public boolean shouldFilterOut(NotificationEntry entry) {
         final StatusBarNotification sbn = entry.notification;
         if (!(getEnvironment().isDeviceProvisioned()
                 || showNotificationEvenIfUnprovisioned(sbn))) {
@@ -117,8 +119,8 @@
             return true;
         }
 
-        if (getFsc().isDungeonNotification(sbn)
-                && !getFsc().isDungeonNeededForUser(sbn.getUserId())) {
+        if (getFsc().isDisclosureNotification(sbn)
+                && !getFsc().isDisclosureNeededForUser(sbn.getUserId())) {
             // this is a foreground-service disclosure for a user that does not need to show one
             return true;
         }
@@ -132,6 +134,10 @@
             }
         }
 
+        if (entry.isBubble() && !entry.showInShadeWhenBubble()) {
+            return true;
+        }
+
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 8bd0e9a..c50f10b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -37,6 +37,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
@@ -134,12 +135,35 @@
     }
 
     /**
+     * Whether the notification should appear as a bubble with a fly-out on top of the screen.
+     *
+     * @param entry the entry to check
+     * @return true if the entry should bubble up, false otherwise
+     */
+    public boolean shouldBubbleUp(NotificationEntry entry) {
+        StatusBarNotification sbn = entry.notification;
+        if (!entry.isBubble()) {
+            if (DEBUG) {
+                Log.d(TAG, "No bubble up: notification " + sbn.getKey()
+                        + " is bubble? " + entry.isBubble());
+            }
+            return false;
+        }
+
+        if (!canHeadsUpCommon(entry)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
      * 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
      */
-    public boolean shouldHeadsUp(NotificationData.Entry entry) {
+    public boolean shouldHeadsUp(NotificationEntry entry) {
         StatusBarNotification sbn = entry.notification;
 
         if (getShadeController().isDozing()) {
@@ -149,10 +173,12 @@
             return false;
         }
 
-        // TODO: need to changes this, e.g. should still heads up in expanded shade, might want
-        // message bubble from the bubble to go through heads up path
         boolean inShade = mStatusBarStateController.getState() == SHADE;
-        if (entry.isBubble() && !entry.isBubbleDismissed() && inShade) {
+        if (entry.isBubble() && inShade) {
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: in unlocked shade where notification is shown as a "
+                        + "bubble: " + sbn.getKey());
+            }
             return false;
         }
 
@@ -163,9 +189,13 @@
             return false;
         }
 
-        if (!mUseHeadsUp || mPresenter.isDeviceInVrMode()) {
+        if (!canHeadsUpCommon(entry)) {
+            return false;
+        }
+
+        if (entry.importance < NotificationManager.IMPORTANCE_HIGH) {
             if (DEBUG) {
-                Log.d(TAG, "No heads up: no huns or vr mode");
+                Log.d(TAG, "No heads up: unimportant notification: " + sbn.getKey());
             }
             return false;
         }
@@ -185,34 +215,6 @@
             return false;
         }
 
-        if (entry.shouldSuppressPeek()) {
-            if (DEBUG) {
-                Log.d(TAG, "No heads up: suppressed by DND: " + sbn.getKey());
-            }
-            return false;
-        }
-
-        if (isSnoozedPackage(sbn)) {
-            if (DEBUG) {
-                Log.d(TAG, "No heads up: snoozed package: " + sbn.getKey());
-            }
-            return false;
-        }
-
-        if (entry.hasJustLaunchedFullScreenIntent()) {
-            if (DEBUG) {
-                Log.d(TAG, "No heads up: recent fullscreen: " + sbn.getKey());
-            }
-            return false;
-        }
-
-        if (entry.importance < NotificationManager.IMPORTANCE_HIGH) {
-            if (DEBUG) {
-                Log.d(TAG, "No heads up: unimportant notification: " + sbn.getKey());
-            }
-            return false;
-        }
-
         if (!mHeadsUpSuppressor.canHeadsUp(entry, sbn)) {
             return false;
         }
@@ -227,7 +229,7 @@
      * @param entry the entry to check
      * @return true if the entry should ambient pulse, false otherwise
      */
-    public boolean shouldPulse(NotificationData.Entry entry) {
+    public boolean shouldPulse(NotificationEntry entry) {
         StatusBarNotification sbn = entry.notification;
 
         if (!getShadeController().isDozing()) {
@@ -273,14 +275,14 @@
 
     /**
      * Common checks between heads up alerting and ambient pulse alerting.  See
-     * {@link #shouldHeadsUp(NotificationData.Entry)} and
-     * {@link #shouldPulse(NotificationData.Entry)}.  Notifications that fail any of these checks
+     * {@link #shouldHeadsUp(NotificationEntry)} and
+     * {@link #shouldPulse(NotificationEntry)}.  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) {
+    protected boolean canAlertCommon(NotificationEntry entry) {
         StatusBarNotification sbn = entry.notification;
 
         if (mNotificationFilter.shouldFilterOut(entry)) {
@@ -301,6 +303,49 @@
         return true;
     }
 
+    /**
+     * Common checks between heads up alerting and bubble fly out alerting. See
+     * {@link #shouldHeadsUp(NotificationEntry)} and
+     * {@link #shouldBubbleUp(NotificationEntry)}. Notifications that fail any of these
+     * checks should not interrupt the user on screen.
+     *
+     * @param entry the entry to check
+     * @return true if these checks pass, false if the notification should not interrupt on screen
+     */
+    public boolean canHeadsUpCommon(NotificationEntry entry) {
+        StatusBarNotification sbn = entry.notification;
+
+        if (!mUseHeadsUp || mPresenter.isDeviceInVrMode()) {
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: no huns or vr mode");
+            }
+            return false;
+        }
+
+        if (entry.shouldSuppressPeek()) {
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: suppressed by DND: " + sbn.getKey());
+            }
+            return false;
+        }
+
+        if (isSnoozedPackage(sbn)) {
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: snoozed package: " + sbn.getKey());
+            }
+            return false;
+        }
+
+        if (entry.hasJustLaunchedFullScreenIntent()) {
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: recent fullscreen: " + sbn.getKey());
+            }
+            return false;
+        }
+
+        return true;
+    }
+
     private boolean isSnoozedPackage(StatusBarNotification sbn) {
         return mHeadsUpManager.isSnoozed(sbn.getPackageName());
     }
@@ -325,7 +370,7 @@
          * @param sbn   notification that might be heads upped
          * @return false if the notification can not be heads upped
          */
-        boolean canHeadsUp(NotificationData.Entry entry, StatusBarNotification sbn);
+        boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn);
 
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
new file mode 100644
index 0000000..88f4ca2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+
+/**
+ * Root controller for the list of notifications in the shade.
+ *
+ * TODO: Much of the code in NotificationPresenter should eventually move in here. It will proxy
+ * domain-specific behavior (ARC, etc) to subcontrollers.
+ */
+public class NotificationListController {
+    private final NotificationEntryManager mEntryManager;
+    private final NotificationListContainer mListContainer;
+    private final ForegroundServiceController mForegroundServiceController;
+    private final DeviceProvisionedController mDeviceProvisionedController;
+
+    public NotificationListController(
+            NotificationEntryManager entryManager,
+            NotificationListContainer listContainer,
+            ForegroundServiceController foregroundServiceController,
+            DeviceProvisionedController deviceProvisionedController) {
+        mEntryManager = checkNotNull(entryManager);
+        mListContainer = checkNotNull(listContainer);
+        mForegroundServiceController = checkNotNull(foregroundServiceController);
+        mDeviceProvisionedController = checkNotNull(deviceProvisionedController);
+    }
+
+    /**
+     * Causes the controller to register listeners on its dependencies. This method must be called
+     * before the controller is ready to perform its duties.
+     */
+    public void bind() {
+        mEntryManager.addNotificationEntryListener(mEntryListener);
+        mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
+    }
+
+    /** Should be called when the list controller is being destroyed. */
+    public void destroy() {
+        mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
+    }
+
+    @SuppressWarnings("FieldCanBeLocal")
+    private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
+        @Override
+        public void onEntryRemoved(
+                NotificationEntry entry,
+                NotificationVisibility visibility,
+                boolean removedByUser) {
+            mListContainer.cleanUpViewStateForEntry(entry);
+        }
+
+        @Override
+        public void onBeforeNotificationAdded(NotificationEntry entry) {
+            tagForeground(entry.notification);
+        }
+    };
+
+    private final DeviceProvisionedListener mDeviceProvisionedListener =
+            new DeviceProvisionedListener() {
+                @Override
+                public void onDeviceProvisionedChanged() {
+                    mEntryManager.updateNotifications();
+                }
+            };
+
+    // TODO: This method is horrifically inefficient
+    private void tagForeground(StatusBarNotification notification) {
+        ArraySet<Integer> activeOps =
+                mForegroundServiceController.getAppOps(
+                        notification.getUserId(), notification.getPackageName());
+        if (activeOps != null) {
+            int len = activeOps.size();
+            for (int i = 0; i < len; i++) {
+                updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(),
+                        notification.getPackageName(), true);
+            }
+        }
+    }
+
+    /** When an app op changes, propagate that change to notifications. */
+    public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) {
+        String foregroundKey =
+                mForegroundServiceController.getStandardLayoutKey(UserHandle.getUserId(uid), pkg);
+        if (foregroundKey != null) {
+            mEntryManager
+                    .getNotificationData().updateAppOp(appOp, uid, pkg, foregroundKey, showIcon);
+            mEntryManager.updateNotifications();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
index b241b8a..0b8596f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification;
 
 import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
 import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
 import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
@@ -26,13 +27,10 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.os.Build;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
 import android.view.ViewGroup;
 
-import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.NotificationMessagingUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -41,6 +39,8 @@
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationUiAdjustment;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationInflater;
@@ -51,6 +51,7 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Singleton;
 
 /** Handles inflating and updating views for notifications. */
@@ -68,10 +69,10 @@
             Dependency.get(NotificationInterruptionStateProvider.class);
 
     private final Context mContext;
-    private final IStatusBarService mBarService;
     private final NotificationMessagingUtil mMessagingUtil;
     private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
             this::logNotificationExpansion;
+    private final boolean mAllowLongPress;
 
     private NotificationRemoteInputManager mRemoteInputManager;
     private NotificationPresenter mPresenter;
@@ -81,13 +82,14 @@
     private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
     private BindRowCallback mBindRowCallback;
     private NotificationClicker mNotificationClicker;
+    private final NotificationLogger mNotificationLogger = Dependency.get(NotificationLogger.class);
 
     @Inject
-    public NotificationRowBinder(Context context) {
+    public NotificationRowBinder(Context context,
+            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress) {
         mContext = context;
         mMessagingUtil = new NotificationMessagingUtil(context);
-        mBarService = IStatusBarService.Stub.asInterface(
-                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        mAllowLongPress = allowLongPress;
     }
 
     private NotificationRemoteInputManager getRemoteInputManager() {
@@ -120,17 +122,22 @@
     /**
      * Inflates the views for the given entry (possibly asynchronously).
      */
-    public void inflateViews(NotificationData.Entry entry, Runnable onDismissRunnable,
-            boolean isUpdate) {
+    public void inflateViews(
+            NotificationEntry entry,
+            Runnable onDismissRunnable,
+            boolean isUpdate)
+            throws InflationException {
         ViewGroup parent = mListContainer.getViewParentForNotification(entry);
         PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext,
                 entry.notification.getUser().getIdentifier());
 
         final StatusBarNotification sbn = entry.notification;
         if (entry.rowExists()) {
+            entry.updateIcons(mContext, sbn);
             entry.reset();
             updateNotification(entry, pmUser, sbn, entry.getRow(), isUpdate);
         } else {
+            entry.createIcons(mContext, sbn);
             new RowInflaterTask().inflate(mContext, parent, entry,
                     row -> {
                         bindRow(entry, pmUser, sbn, row, onDismissRunnable);
@@ -139,7 +146,7 @@
         }
     }
 
-    private void bindRow(NotificationData.Entry entry, PackageManager pmUser,
+    private void bindRow(NotificationEntry entry, PackageManager pmUser,
             StatusBarNotification sbn, ExpandableNotificationRow row,
             Runnable onDismissRunnable) {
         row.setExpansionLogger(mExpansionLogger, entry.notification.getKey());
@@ -147,7 +154,9 @@
         row.setHeadsUpManager(mHeadsUpManager);
         row.setOnExpandClickListener(mPresenter);
         row.setInflationCallback(mInflationCallback);
-        row.setLongPressListener(getNotificationLongClicker());
+        if (mAllowLongPress) {
+            row.setLongPressListener(mGutsManager::openGuts);
+        }
         mListContainer.bindRow(row);
         getRemoteInputManager().bindRow(row);
 
@@ -185,7 +194,7 @@
      * reinflating them.
      */
     public void onNotificationRankingUpdated(
-            NotificationData.Entry entry,
+            NotificationEntry entry,
             @Nullable Integer oldImportance,
             NotificationUiAdjustment oldAdjustment,
             NotificationUiAdjustment newAdjustment,
@@ -212,7 +221,7 @@
 
     //TODO: This method associates a row with an entry, but eventually needs to not do that
     private void updateNotification(
-            NotificationData.Entry entry,
+            NotificationEntry entry,
             PackageManager pmUser,
             StatusBarNotification sbn,
             ExpandableNotificationRow row,
@@ -260,18 +269,8 @@
         row.inflateViews();
     }
 
-    ExpandableNotificationRow.LongPressListener getNotificationLongClicker() {
-        return mGutsManager::openGuts;
-    }
-
     private void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
-        mUiOffloadThread.submit(() -> {
-            try {
-                mBarService.onNotificationExpansionChanged(key, userAction, expanded);
-            } catch (RemoteException e) {
-                // Ignore.
-            }
-        });
+         mNotificationLogger.onExpansionChanged(key, userAction, expanded);
     }
 
     /** Callback for when a row is bound to an entry. */
@@ -284,7 +283,7 @@
          * @param sbn    notification
          * @param row    row for the notification
          */
-        void onBindRow(NotificationData.Entry entry, PackageManager pmUser,
+        void onBindRow(NotificationEntry entry, PackageManager pmUser,
                 StatusBarNotification sbn, ExpandableNotificationRow row);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
index a194eef..f09c57d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.notification;
 
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
 /**
  * An object that can determine the visibility of a Notification.
  */
@@ -27,5 +29,5 @@
      * @param entry
      * @return true if row is in a visible location
      */
-    boolean isInVisibleLocation(NotificationData.Entry entry);
+    boolean isInVisibleLocation(NotificationEntry entry);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index 8e6a93d..c886685 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -21,6 +21,7 @@
 import androidx.collection.ArraySet;
 
 import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 
@@ -52,7 +53,7 @@
     public VisualStabilityManager(NotificationEntryManager notificationEntryManager) {
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
-            public void onEntryReinflated(NotificationData.Entry entry) {
+            public void onEntryReinflated(NotificationEntry entry) {
                 if (entry.hasLowPriorityStateUpdated()) {
                     onLowPriorityUpdated(entry);
                     if (mPresenter != null) {
@@ -163,7 +164,7 @@
     }
 
     @Override
-    public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
         if (isHeadsUp) {
             // Heads up notifications should in general be allowed to reorder if they are out of
             // view and stay at the current location if they aren't.
@@ -171,7 +172,7 @@
         }
     }
 
-    private void onLowPriorityUpdated(NotificationData.Entry entry) {
+    private void onLowPriorityUpdated(NotificationEntry entry) {
         mLowPriorityReorderingViews.add(entry.getRow());
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
new file mode 100644
index 0000000..8c29fb5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
+import android.service.notification.SnoozeCriterion;
+import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
+import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The list of currently displaying notifications.
+ */
+public class NotificationData {
+
+    private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class);
+
+    /**
+     * These dependencies are late init-ed
+     */
+    private KeyguardEnvironment mEnvironment;
+    private NotificationMediaManager mMediaManager;
+
+    private HeadsUpManager mHeadsUpManager;
+
+    private final ArrayMap<String, NotificationEntry> mEntries = new ArrayMap<>();
+    private final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
+    private final ArrayList<NotificationEntry> mFilteredForUser = new ArrayList<>();
+
+    private final NotificationGroupManager mGroupManager =
+            Dependency.get(NotificationGroupManager.class);
+
+    private RankingMap mRankingMap;
+    private final Ranking mTmpRanking = new Ranking();
+
+    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
+        mHeadsUpManager = headsUpManager;
+    }
+
+    private final Comparator<NotificationEntry> mRankingComparator =
+            new Comparator<NotificationEntry>() {
+        private final Ranking mRankingA = new Ranking();
+        private final Ranking mRankingB = new Ranking();
+
+        @Override
+        public int compare(NotificationEntry a, NotificationEntry b) {
+            final StatusBarNotification na = a.notification;
+            final StatusBarNotification nb = b.notification;
+            int aImportance = NotificationManager.IMPORTANCE_DEFAULT;
+            int bImportance = NotificationManager.IMPORTANCE_DEFAULT;
+            int aRank = 0;
+            int bRank = 0;
+
+            if (mRankingMap != null) {
+                // RankingMap as received from NoMan
+                getRanking(a.key, mRankingA);
+                getRanking(b.key, mRankingB);
+                aImportance = mRankingA.getImportance();
+                bImportance = mRankingB.getImportance();
+                aRank = mRankingA.getRank();
+                bRank = mRankingB.getRank();
+            }
+
+            String mediaNotification = getMediaManager().getMediaNotificationKey();
+
+            // IMPORTANCE_MIN media streams are allowed to drift to the bottom
+            final boolean aMedia = a.key.equals(mediaNotification)
+                    && aImportance > NotificationManager.IMPORTANCE_MIN;
+            final boolean bMedia = b.key.equals(mediaNotification)
+                    && bImportance > NotificationManager.IMPORTANCE_MIN;
+
+            boolean aSystemMax = aImportance >= NotificationManager.IMPORTANCE_HIGH
+                    && isSystemNotification(na);
+            boolean bSystemMax = bImportance >= NotificationManager.IMPORTANCE_HIGH
+                    && isSystemNotification(nb);
+
+            boolean isHeadsUp = a.getRow().isHeadsUp();
+            if (isHeadsUp != b.getRow().isHeadsUp()) {
+                return isHeadsUp ? -1 : 1;
+            } else if (isHeadsUp) {
+                // Provide consistent ranking with headsUpManager
+                return mHeadsUpManager.compare(a, b);
+            } else if (a.getRow().isAmbientPulsing() != b.getRow().isAmbientPulsing()) {
+                return a.getRow().isAmbientPulsing() ? -1 : 1;
+            } else if (aMedia != bMedia) {
+                // Upsort current media notification.
+                return aMedia ? -1 : 1;
+            } else if (aSystemMax != bSystemMax) {
+                // Upsort PRIORITY_MAX system notifications
+                return aSystemMax ? -1 : 1;
+            } else if (aRank != bRank) {
+                return aRank - bRank;
+            } else {
+                return Long.compare(nb.getNotification().when, na.getNotification().when);
+            }
+        }
+    };
+
+    private KeyguardEnvironment getEnvironment() {
+        if (mEnvironment == null) {
+            mEnvironment = Dependency.get(KeyguardEnvironment.class);
+        }
+        return mEnvironment;
+    }
+
+    private NotificationMediaManager getMediaManager() {
+        if (mMediaManager == null) {
+            mMediaManager = Dependency.get(NotificationMediaManager.class);
+        }
+        return mMediaManager;
+    }
+
+    /**
+     * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment}
+     *
+     * <p>
+     * This call doesn't update the list of active notifications. Call {@link #filterAndSort()}
+     * when the environment changes.
+     * <p>
+     * Don't hold on to or modify the returned list.
+     */
+    public ArrayList<NotificationEntry> getActiveNotifications() {
+        return mSortedAndFiltered;
+    }
+
+    public ArrayList<NotificationEntry> getNotificationsForCurrentUser() {
+        mFilteredForUser.clear();
+
+        synchronized (mEntries) {
+            final int len = mEntries.size();
+            for (int i = 0; i < len; i++) {
+                NotificationEntry entry = mEntries.valueAt(i);
+                final StatusBarNotification sbn = entry.notification;
+                if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
+                    continue;
+                }
+                mFilteredForUser.add(entry);
+            }
+        }
+        return mFilteredForUser;
+    }
+
+    public NotificationEntry get(String key) {
+        return mEntries.get(key);
+    }
+
+    public void add(NotificationEntry entry) {
+        synchronized (mEntries) {
+            mEntries.put(entry.notification.getKey(), entry);
+        }
+        mGroupManager.onEntryAdded(entry);
+
+        updateRankingAndSort(mRankingMap);
+    }
+
+    public NotificationEntry remove(String key, RankingMap ranking) {
+        NotificationEntry removed;
+        synchronized (mEntries) {
+            removed = mEntries.remove(key);
+        }
+        if (removed == null) return null;
+        mGroupManager.onEntryRemoved(removed);
+        updateRankingAndSort(ranking);
+        return removed;
+    }
+
+    /** Updates the given notification entry with the provided ranking. */
+    public void update(
+            NotificationEntry entry,
+            RankingMap ranking,
+            StatusBarNotification notification) {
+        updateRanking(ranking);
+        final StatusBarNotification oldNotification = entry.notification;
+        entry.notification = notification;
+        mGroupManager.onEntryUpdated(entry, oldNotification);
+    }
+
+    public void updateRanking(RankingMap ranking) {
+        updateRankingAndSort(ranking);
+    }
+
+    public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) {
+        synchronized (mEntries) {
+            final int len = mEntries.size();
+            for (int i = 0; i < len; i++) {
+                NotificationEntry entry = mEntries.valueAt(i);
+                if (uid == entry.notification.getUid()
+                        && pkg.equals(entry.notification.getPackageName())
+                        && key.equals(entry.key)) {
+                    if (showIcon) {
+                        entry.mActiveAppOps.add(appOp);
+                    } else {
+                        entry.mActiveAppOps.remove(appOp);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns true if this notification should be displayed in the high-priority notifications
+     * section (and on the lockscreen and status bar).
+     */
+    public boolean isHighPriority(StatusBarNotification statusBarNotification) {
+        if (mRankingMap != null) {
+            getRanking(statusBarNotification.getKey(), mTmpRanking);
+            if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
+                    || statusBarNotification.getNotification().isForegroundService()
+                    || statusBarNotification.getNotification().hasMediaSession()) {
+                return true;
+            }
+            if (mGroupManager.isSummaryOfGroup(statusBarNotification)) {
+                final ArrayList<NotificationEntry> logicalChildren =
+                        mGroupManager.getLogicalChildren(statusBarNotification);
+                for (NotificationEntry child : logicalChildren) {
+                    if (isHighPriority(child.notification)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean isAmbient(String key) {
+        if (mRankingMap != null) {
+            getRanking(key, mTmpRanking);
+            return mTmpRanking.isAmbient();
+        }
+        return false;
+    }
+
+    public int getVisibilityOverride(String key) {
+        if (mRankingMap != null) {
+            getRanking(key, mTmpRanking);
+            return mTmpRanking.getVisibilityOverride();
+        }
+        return Ranking.VISIBILITY_NO_OVERRIDE;
+    }
+
+    public int getImportance(String key) {
+        if (mRankingMap != null) {
+            getRanking(key, mTmpRanking);
+            return mTmpRanking.getImportance();
+        }
+        return NotificationManager.IMPORTANCE_UNSPECIFIED;
+    }
+
+    public String getOverrideGroupKey(String key) {
+        if (mRankingMap != null) {
+            getRanking(key, mTmpRanking);
+            return mTmpRanking.getOverrideGroupKey();
+        }
+        return null;
+    }
+
+    public List<SnoozeCriterion> getSnoozeCriteria(String key) {
+        if (mRankingMap != null) {
+            getRanking(key, mTmpRanking);
+            return mTmpRanking.getSnoozeCriteria();
+        }
+        return null;
+    }
+
+    public NotificationChannel getChannel(String key) {
+        if (mRankingMap != null) {
+            getRanking(key, mTmpRanking);
+            return mTmpRanking.getChannel();
+        }
+        return null;
+    }
+
+    public int getRank(String key) {
+        if (mRankingMap != null) {
+            getRanking(key, mTmpRanking);
+            return mTmpRanking.getRank();
+        }
+        return 0;
+    }
+
+    public boolean shouldHide(String key) {
+        if (mRankingMap != null) {
+            getRanking(key, mTmpRanking);
+            return mTmpRanking.isSuspended();
+        }
+        return false;
+    }
+
+    private void updateRankingAndSort(RankingMap ranking) {
+        if (ranking != null) {
+            mRankingMap = ranking;
+            synchronized (mEntries) {
+                final int len = mEntries.size();
+                for (int i = 0; i < len; i++) {
+                    NotificationEntry entry = mEntries.valueAt(i);
+                    if (!getRanking(entry.key, mTmpRanking)) {
+                        continue;
+                    }
+                    final StatusBarNotification oldSbn = entry.notification.cloneLight();
+                    final String overrideGroupKey = getOverrideGroupKey(entry.key);
+                    if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) {
+                        entry.notification.setOverrideGroupKey(overrideGroupKey);
+                        mGroupManager.onEntryUpdated(entry, oldSbn);
+                    }
+                    entry.populateFromRanking(mTmpRanking);
+                }
+            }
+        }
+        filterAndSort();
+    }
+
+    /**
+     * Get the ranking from the current ranking map.
+     *
+     * @param key the key to look up
+     * @param outRanking the ranking to populate
+     *
+     * @return {@code true} if the ranking was properly obtained.
+     */
+    @VisibleForTesting
+    protected boolean getRanking(String key, Ranking outRanking) {
+        return mRankingMap.getRanking(key, outRanking);
+    }
+
+    // TODO: This should not be public. Instead the Environment should notify this class when
+    // anything changed, and this class should call back the UI so it updates itself.
+    public void filterAndSort() {
+        mSortedAndFiltered.clear();
+
+        synchronized (mEntries) {
+            final int len = mEntries.size();
+            for (int i = 0; i < len; i++) {
+                NotificationEntry entry = mEntries.valueAt(i);
+
+                if (mNotificationFilter.shouldFilterOut(entry)) {
+                    continue;
+                }
+
+                mSortedAndFiltered.add(entry);
+            }
+        }
+
+        Collections.sort(mSortedAndFiltered, mRankingComparator);
+    }
+
+    public void dump(PrintWriter pw, String indent) {
+        int filteredLen = mSortedAndFiltered.size();
+        pw.print(indent);
+        pw.println("active notifications: " + filteredLen);
+        int active;
+        for (active = 0; active < filteredLen; active++) {
+            NotificationEntry e = mSortedAndFiltered.get(active);
+            dumpEntry(pw, indent, active, e);
+        }
+        synchronized (mEntries) {
+            int totalLen = mEntries.size();
+            pw.print(indent);
+            pw.println("inactive notifications: " + (totalLen - active));
+            int inactiveCount = 0;
+            for (int i = 0; i < totalLen; i++) {
+                NotificationEntry entry = mEntries.valueAt(i);
+                if (!mSortedAndFiltered.contains(entry)) {
+                    dumpEntry(pw, indent, inactiveCount, entry);
+                    inactiveCount++;
+                }
+            }
+        }
+    }
+
+    private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) {
+        getRanking(e.key, mTmpRanking);
+        pw.print(indent);
+        pw.println("  [" + i + "] key=" + e.key + " icon=" + e.icon);
+        StatusBarNotification n = e.notification;
+        pw.print(indent);
+        pw.println("      pkg=" + n.getPackageName() + " id=" + n.getId() + " importance="
+                + mTmpRanking.getImportance());
+        pw.print(indent);
+        pw.println("      notification=" + n.getNotification());
+    }
+
+    private static boolean isSystemNotification(StatusBarNotification sbn) {
+        String sbnPackage = sbn.getPackageName();
+        return "android".equals(sbnPackage) || "com.android.systemui".equals(sbnPackage);
+    }
+
+    /**
+     * Provides access to keyguard state and user settings dependent data.
+     */
+    public interface KeyguardEnvironment {
+        boolean isDeviceProvisioned();
+        boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
new file mode 100644
index 0000000..ee551ee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -0,0 +1,726 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import static android.app.Notification.CATEGORY_ALARM;
+import static android.app.Notification.CATEGORY_CALL;
+import static android.app.Notification.CATEGORY_EVENT;
+import static android.app.Notification.CATEGORY_MESSAGE;
+import static android.app.Notification.CATEGORY_REMINDER;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager.Policy;
+import android.app.Person;
+import android.content.Context;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.SnoozeCriterion;
+import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.ContrastColorUtil;
+import com.android.systemui.statusbar.InflationTask;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationGuts;
+import com.android.systemui.statusbar.notification.row.NotificationInflater;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents a notification that the system UI knows about
+ *
+ * Whenever the NotificationManager tells us about the existence of a new notification, we wrap it
+ * in a NotificationEntry. Thus, every notification has an associated NotificationEntry, even if
+ * that notification is never displayed to the user (for example, if it's filtered out for some
+ * reason).
+ *
+ * Entries store information about the current state of the notification. Essentially:
+ * anything that needs to persist or be modifiable even when the notification's views don't
+ * exist. Any other state should be stored on the views/view controllers themselves.
+ *
+ * At the moment, there are many things here that shouldn't be and vice-versa. Hopefully we can
+ * clean this up in the future.
+ */
+public final class NotificationEntry {
+    private static final long LAUNCH_COOLDOWN = 2000;
+    private static final long REMOTE_INPUT_COOLDOWN = 500;
+    private static final long INITIALIZATION_DELAY = 400;
+    private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN;
+    private static final int COLOR_INVALID = 1;
+    public final String key;
+    public StatusBarNotification notification;
+    public NotificationChannel channel;
+    public long lastAudiblyAlertedMs;
+    public boolean noisy;
+    public boolean ambient;
+    public int importance;
+    public StatusBarIconView icon;
+    public StatusBarIconView expandedIcon;
+    private boolean interruption;
+    public boolean autoRedacted; // whether the redacted notification was generated by us
+    public int targetSdk;
+    private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
+    public CharSequence remoteInputText;
+    public List<SnoozeCriterion> snoozeCriteria;
+    public int userSentiment = NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
+    /** Smart Actions provided by the NotificationAssistantService. */
+    @NonNull
+    public List<Notification.Action> systemGeneratedSmartActions = Collections.emptyList();
+    public CharSequence[] smartReplies = new CharSequence[0];
+    @VisibleForTesting
+    public int suppressedVisualEffects;
+    public boolean suspended;
+
+    private NotificationEntry parent; // our parent (if we're in a group)
+    private ArrayList<NotificationEntry> children = new ArrayList<NotificationEntry>();
+    private ExpandableNotificationRow row; // the outer expanded view
+
+    private int mCachedContrastColor = COLOR_INVALID;
+    private int mCachedContrastColorIsFor = COLOR_INVALID;
+    private InflationTask mRunningTask = null;
+    private Throwable mDebugThrowable;
+    public CharSequence remoteInputTextWhenReset;
+    public long lastRemoteInputSent = NOT_LAUNCHED_YET;
+    public ArraySet<Integer> mActiveAppOps = new ArraySet<>(3);
+    public CharSequence headsUpStatusBarText;
+    public CharSequence headsUpStatusBarTextPublic;
+
+    private long initializationTime = -1;
+
+    /**
+     * Whether or not this row represents a system notification. Note that if this is
+     * {@code null}, that means we were either unable to retrieve the info or have yet to
+     * retrieve the info.
+     */
+    public Boolean mIsSystemNotification;
+
+    /**
+     * Has the user sent a reply through this Notification.
+     */
+    private boolean hasSentReply;
+
+    /**
+     * Whether this notification should be displayed as a bubble.
+     */
+    private boolean mIsBubble;
+
+    /**
+     * Whether this notification should be shown in the shade when it is also displayed as a bubble.
+     *
+     * <p>When a notification is a bubble we don't show it in the shade once the bubble has been
+     * expanded</p>
+     */
+    private boolean mShowInShadeWhenBubble;
+
+    /**
+     * Whether the user has dismissed this notification when it was in bubble form.
+     */
+    private boolean mUserDismissedBubble;
+
+    public NotificationEntry(StatusBarNotification n) {
+        this(n, null);
+    }
+
+    public NotificationEntry(
+            StatusBarNotification n,
+            @Nullable NotificationListenerService.Ranking ranking) {
+        this.key = n.getKey();
+        this.notification = n;
+        if (ranking != null) {
+            populateFromRanking(ranking);
+        }
+    }
+
+    public void populateFromRanking(@NonNull NotificationListenerService.Ranking ranking) {
+        channel = ranking.getChannel();
+        lastAudiblyAlertedMs = ranking.getLastAudiblyAlertedMillis();
+        importance = ranking.getImportance();
+        ambient = ranking.isAmbient();
+        snoozeCriteria = ranking.getSnoozeCriteria();
+        userSentiment = ranking.getUserSentiment();
+        systemGeneratedSmartActions = ranking.getSmartActions() == null
+                ? Collections.emptyList() : ranking.getSmartActions();
+        smartReplies = ranking.getSmartReplies() == null
+                ? new CharSequence[0]
+                : ranking.getSmartReplies().toArray(new CharSequence[0]);
+        suppressedVisualEffects = ranking.getSuppressedVisualEffects();
+        suspended = ranking.isSuspended();
+    }
+
+    public void setInterruption() {
+        interruption = true;
+    }
+
+    public boolean hasInterrupted() {
+        return interruption;
+    }
+
+    public void setIsBubble(boolean bubbleable) {
+        mIsBubble = bubbleable;
+    }
+
+    public boolean isBubble() {
+        return mIsBubble;
+    }
+
+    public void setBubbleDismissed(boolean userDismissed) {
+        mUserDismissedBubble = userDismissed;
+    }
+
+    public boolean isBubbleDismissed() {
+        return mUserDismissedBubble;
+    }
+
+    /**
+     * Sets whether this notification should be shown in the shade when it is also displayed as a
+     * bubble.
+     */
+    public void setShowInShadeWhenBubble(boolean showInShade) {
+        mShowInShadeWhenBubble = showInShade;
+    }
+
+    /**
+     * Whether this notification should be shown in the shade when it is also displayed as a
+     * bubble.
+     */
+    public boolean showInShadeWhenBubble() {
+        // We always show it in the shade if non-clearable
+        return !isClearable() || mShowInShadeWhenBubble;
+    }
+
+    /**
+     * Resets the notification entry to be re-used.
+     */
+    public void reset() {
+        if (row != null) {
+            row.reset();
+        }
+    }
+
+    public ExpandableNotificationRow getRow() {
+        return row;
+    }
+
+    //TODO: This will go away when we have a way to bind an entry to a row
+    public void setRow(ExpandableNotificationRow row) {
+        this.row = row;
+    }
+
+    @Nullable
+    public List<NotificationEntry> getChildren() {
+        if (children.size() <= 0) {
+            return null;
+        }
+
+        return children;
+    }
+
+    public void notifyFullScreenIntentLaunched() {
+        setInterruption();
+        lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
+    }
+
+    public boolean hasJustLaunchedFullScreenIntent() {
+        return SystemClock.elapsedRealtime() < lastFullScreenIntentLaunchTime + LAUNCH_COOLDOWN;
+    }
+
+    public boolean hasJustSentRemoteInput() {
+        return SystemClock.elapsedRealtime() < lastRemoteInputSent + REMOTE_INPUT_COOLDOWN;
+    }
+
+    public boolean hasFinishedInitialization() {
+        return initializationTime == -1
+                || SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY;
+    }
+
+    /**
+     * Create the icons for a notification
+     * @param context the context to create the icons with
+     * @param sbn the notification
+     * @throws InflationException Exception if required icons are not valid or specified
+     */
+    public void createIcons(Context context, StatusBarNotification sbn)
+            throws InflationException {
+        Notification n = sbn.getNotification();
+        final Icon smallIcon = n.getSmallIcon();
+        if (smallIcon == null) {
+            throw new InflationException("No small icon in notification from "
+                    + sbn.getPackageName());
+        }
+
+        // Construct the icon.
+        icon = new StatusBarIconView(context,
+                sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
+        icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+
+        // Construct the expanded icon.
+        expandedIcon = new StatusBarIconView(context,
+                sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), sbn);
+        expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+        final StatusBarIcon ic = new StatusBarIcon(
+                sbn.getUser(),
+                sbn.getPackageName(),
+                smallIcon,
+                n.iconLevel,
+                n.number,
+                StatusBarIconView.contentDescForNotification(context, n));
+        if (!icon.set(ic) || !expandedIcon.set(ic)) {
+            icon = null;
+            expandedIcon = null;
+            throw new InflationException("Couldn't create icon: " + ic);
+        }
+        expandedIcon.setVisibility(View.INVISIBLE);
+        expandedIcon.setOnVisibilityChangedListener(
+                newVisibility -> {
+                    if (row != null) {
+                        row.setIconsVisible(newVisibility != View.VISIBLE);
+                    }
+                });
+    }
+
+    public void setIconTag(int key, Object tag) {
+        if (icon != null) {
+            icon.setTag(key, tag);
+            expandedIcon.setTag(key, tag);
+        }
+    }
+
+    /**
+     * Update the notification icons.
+     *
+     * @param context the context to create the icons with.
+     * @param sbn the notification to read the icon from.
+     * @throws InflationException Exception if required icons are not valid or specified
+     */
+    public void updateIcons(Context context, StatusBarNotification sbn)
+            throws InflationException {
+        if (icon != null) {
+            // Update the icon
+            Notification n = sbn.getNotification();
+            final StatusBarIcon ic = new StatusBarIcon(
+                    notification.getUser(),
+                    notification.getPackageName(),
+                    n.getSmallIcon(),
+                    n.iconLevel,
+                    n.number,
+                    StatusBarIconView.contentDescForNotification(context, n));
+            icon.setNotification(sbn);
+            expandedIcon.setNotification(sbn);
+            if (!icon.set(ic) || !expandedIcon.set(ic)) {
+                throw new InflationException("Couldn't update icon: " + ic);
+            }
+        }
+    }
+
+    public int getContrastedColor(Context context, boolean isLowPriority,
+            int backgroundColor) {
+        int rawColor = isLowPriority ? Notification.COLOR_DEFAULT :
+                notification.getNotification().color;
+        if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
+            return mCachedContrastColor;
+        }
+        final int contrasted = ContrastColorUtil.resolveContrastColor(context, rawColor,
+                backgroundColor);
+        mCachedContrastColorIsFor = rawColor;
+        mCachedContrastColor = contrasted;
+        return mCachedContrastColor;
+    }
+
+    /**
+     * Abort all existing inflation tasks
+     */
+    public void abortTask() {
+        if (mRunningTask != null) {
+            mRunningTask.abort();
+            mRunningTask = null;
+        }
+    }
+
+    public void setInflationTask(InflationTask abortableTask) {
+        // abort any existing inflation
+        InflationTask existing = mRunningTask;
+        abortTask();
+        mRunningTask = abortableTask;
+        if (existing != null && mRunningTask != null) {
+            mRunningTask.supersedeTask(existing);
+        }
+    }
+
+    public void onInflationTaskFinished() {
+        mRunningTask = null;
+    }
+
+    @VisibleForTesting
+    public InflationTask getRunningTask() {
+        return mRunningTask;
+    }
+
+    /**
+     * Set a throwable that is used for debugging
+     *
+     * @param debugThrowable the throwable to save
+     */
+    public void setDebugThrowable(Throwable debugThrowable) {
+        mDebugThrowable = debugThrowable;
+    }
+
+    public Throwable getDebugThrowable() {
+        return mDebugThrowable;
+    }
+
+    public void onRemoteInputInserted() {
+        lastRemoteInputSent = NOT_LAUNCHED_YET;
+        remoteInputTextWhenReset = null;
+    }
+
+    public void setHasSentReply() {
+        hasSentReply = true;
+    }
+
+    public boolean isLastMessageFromReply() {
+        if (!hasSentReply) {
+            return false;
+        }
+        Bundle extras = notification.getNotification().extras;
+        CharSequence[] replyTexts = extras.getCharSequenceArray(
+                Notification.EXTRA_REMOTE_INPUT_HISTORY);
+        if (!ArrayUtils.isEmpty(replyTexts)) {
+            return true;
+        }
+        Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
+        if (messages != null && messages.length > 0) {
+            Parcelable message = messages[messages.length - 1];
+            if (message instanceof Bundle) {
+                Notification.MessagingStyle.Message lastMessage =
+                        Notification.MessagingStyle.Message.getMessageFromBundle(
+                                (Bundle) message);
+                if (lastMessage != null) {
+                    Person senderPerson = lastMessage.getSenderPerson();
+                    if (senderPerson == null) {
+                        return true;
+                    }
+                    Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON);
+                    return Objects.equals(user, senderPerson);
+                }
+            }
+        }
+        return false;
+    }
+
+    public void setInitializationTime(long time) {
+        if (initializationTime == -1) {
+            initializationTime = time;
+        }
+    }
+
+    public void sendAccessibilityEvent(int eventType) {
+        if (row != null) {
+            row.sendAccessibilityEvent(eventType);
+        }
+    }
+
+    /**
+     * Used by NotificationMediaManager to determine... things
+     * @return {@code true} if we are a media notification
+     */
+    public boolean isMediaNotification() {
+        if (row == null) return false;
+
+        return row.isMediaRow();
+    }
+
+    /**
+     * We are a top level child if our parent is the list of notifications duh
+     * @return {@code true} if we're a top level notification
+     */
+    public boolean isTopLevelChild() {
+        return row != null && row.isTopLevelChild();
+    }
+
+    public void resetUserExpansion() {
+        if (row != null) row.resetUserExpansion();
+    }
+
+    public void freeContentViewWhenSafe(@NotificationInflater.InflationFlag int inflationFlag) {
+        if (row != null) row.freeContentViewWhenSafe(inflationFlag);
+    }
+
+    public void setAmbientPulsing(boolean pulsing) {
+        if (row != null) row.setAmbientPulsing(pulsing);
+    }
+
+    public boolean rowExists() {
+        return row != null;
+    }
+
+    public boolean isRowDismissed() {
+        return row != null && row.isDismissed();
+    }
+
+    public boolean isRowRemoved() {
+        return row != null && row.isRemoved();
+    }
+
+    /**
+     * @return {@code true} if the row is null or removed
+     */
+    public boolean isRemoved() {
+        //TODO: recycling invalidates this
+        return row == null || row.isRemoved();
+    }
+
+    /**
+     * @return {@code true} if the row is null or dismissed
+     */
+    public boolean isDismissed() {
+        //TODO: recycling
+        return row == null || row.isDismissed();
+    }
+
+    public boolean isRowPinned() {
+        return row != null && row.isPinned();
+    }
+
+    public void setRowPinned(boolean pinned) {
+        if (row != null) row.setPinned(pinned);
+    }
+
+    public boolean isRowAnimatingAway() {
+        return row != null && row.isHeadsUpAnimatingAway();
+    }
+
+    public boolean isRowHeadsUp() {
+        return row != null && row.isHeadsUp();
+    }
+
+    public void setHeadsUp(boolean shouldHeadsUp) {
+        if (row != null) row.setHeadsUp(shouldHeadsUp);
+    }
+
+    public boolean mustStayOnScreen() {
+        return row != null && row.mustStayOnScreen();
+    }
+
+    public void setHeadsUpIsVisible() {
+        if (row != null) row.setHeadsUpIsVisible();
+    }
+
+    //TODO: i'm imagining a world where this isn't just the row, but I could be rwong
+    public ExpandableNotificationRow getHeadsUpAnimationView() {
+        return row;
+    }
+
+    public void setUserLocked(boolean userLocked) {
+        if (row != null) row.setUserLocked(userLocked);
+    }
+
+    public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
+        if (row != null) row.setUserExpanded(userExpanded, allowChildExpansion);
+    }
+
+    public void setGroupExpansionChanging(boolean changing) {
+        if (row != null) row.setGroupExpansionChanging(changing);
+    }
+
+    public void notifyHeightChanged(boolean needsAnimation) {
+        if (row != null) row.notifyHeightChanged(needsAnimation);
+    }
+
+    public void closeRemoteInput() {
+        if (row != null) row.closeRemoteInput();
+    }
+
+    public boolean areChildrenExpanded() {
+        return row != null && row.areChildrenExpanded();
+    }
+
+    public boolean keepInParent() {
+        return row != null && row.keepInParent();
+    }
+
+    //TODO: probably less confusing to say "is group fully visible"
+    public boolean isGroupNotFullyVisible() {
+        return row == null || row.isGroupNotFullyVisible();
+    }
+
+    public NotificationGuts getGuts() {
+        if (row != null) return row.getGuts();
+        return null;
+    }
+
+    public boolean hasLowPriorityStateUpdated() {
+        return row != null && row.hasLowPriorityStateUpdated();
+    }
+
+    public void removeRow() {
+        if (row != null) row.setRemoved();
+    }
+
+    public boolean isSummaryWithChildren() {
+        return row != null && row.isSummaryWithChildren();
+    }
+
+    public void setKeepInParent(boolean keep) {
+        if (row != null) row.setKeepInParent(keep);
+    }
+
+    public void onDensityOrFontScaleChanged() {
+        if (row != null) row.onDensityOrFontScaleChanged();
+    }
+
+    public boolean areGutsExposed() {
+        return row != null && row.getGuts() != null && row.getGuts().isExposed();
+    }
+
+    public boolean isChildInGroup() {
+        return parent == null;
+    }
+
+    public void setLowPriorityStateUpdated(boolean updated) {
+        if (row != null) row.setLowPriorityStateUpdated(updated);
+    }
+
+    /**
+     * @return Can the underlying notification be cleared? This can be different from whether the
+     *         notification can be dismissed in case notifications are sensitive on the lockscreen.
+     * @see #canViewBeDismissed()
+     */
+    public boolean isClearable() {
+        if (notification == null || !notification.isClearable()) {
+            return false;
+        }
+        if (children.size() > 0) {
+            for (int i = 0; i < children.size(); i++) {
+                NotificationEntry child =  children.get(i);
+                if (!child.isClearable()) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public boolean canViewBeDismissed() {
+        if (row == null) return true;
+        return row.canViewBeDismissed();
+    }
+
+    @VisibleForTesting
+    boolean isExemptFromDndVisualSuppression() {
+        if (isNotificationBlockedByPolicy(notification.getNotification())) {
+            return false;
+        }
+
+        if ((notification.getNotification().flags
+                & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+            return true;
+        }
+        if (notification.getNotification().isMediaNotification()) {
+            return true;
+        }
+        if (mIsSystemNotification != null && mIsSystemNotification) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean shouldSuppressVisualEffect(int effect) {
+        if (isExemptFromDndVisualSuppression()) {
+            return false;
+        }
+        return (suppressedVisualEffects & effect) != 0;
+    }
+
+    /**
+     * Returns whether {@link Policy#SUPPRESSED_EFFECT_FULL_SCREEN_INTENT}
+     * is set for this entry.
+     */
+    public boolean shouldSuppressFullScreenIntent() {
+        return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
+    }
+
+    /**
+     * Returns whether {@link Policy#SUPPRESSED_EFFECT_PEEK}
+     * is set for this entry.
+     */
+    public boolean shouldSuppressPeek() {
+        return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_PEEK);
+    }
+
+    /**
+     * Returns whether {@link Policy#SUPPRESSED_EFFECT_STATUS_BAR}
+     * is set for this entry.
+     */
+    public boolean shouldSuppressStatusBar() {
+        return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_STATUS_BAR);
+    }
+
+    /**
+     * Returns whether {@link Policy#SUPPRESSED_EFFECT_AMBIENT}
+     * is set for this entry.
+     */
+    public boolean shouldSuppressAmbient() {
+        return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_AMBIENT);
+    }
+
+    /**
+     * Returns whether {@link Policy#SUPPRESSED_EFFECT_NOTIFICATION_LIST}
+     * is set for this entry.
+     */
+    public boolean shouldSuppressNotificationList() {
+        return shouldSuppressVisualEffect(SUPPRESSED_EFFECT_NOTIFICATION_LIST);
+    }
+
+    /**
+     * Categories that are explicitly called out on DND settings screens are always blocked, if
+     * DND has flagged them, even if they are foreground or system notifications that might
+     * otherwise visually bypass DND.
+     */
+    private static boolean isNotificationBlockedByPolicy(Notification n) {
+        return isCategory(CATEGORY_CALL, n)
+                || isCategory(CATEGORY_MESSAGE, n)
+                || isCategory(CATEGORY_ALARM, n)
+                || isCategory(CATEGORY_EVENT, n)
+                || isCategory(CATEGORY_REMINDER, n);
+    }
+
+    private static boolean isCategory(String category, Notification n) {
+        return Objects.equals(n.category, category);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 32acb8d..7b94c74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -15,7 +15,6 @@
  */
 package com.android.systemui.statusbar.notification.logging;
 
-import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -24,9 +23,12 @@
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationStats;
 import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
 
+import androidx.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
@@ -34,15 +36,18 @@
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Map;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -67,6 +72,7 @@
     private final UiOffloadThread mUiOffloadThread;
     private final NotificationEntryManager mEntryManager;
     private HeadsUpManager mHeadsUpManager;
+    private final ExpansionStateLogger mExpansionStateLogger;
 
     protected Handler mHandler = new Handler();
     protected IStatusBarService mBarService;
@@ -116,14 +122,15 @@
             //    notifications.
             // 3. Report newly visible and no-longer visible notifications.
             // 4. Keep currently visible notifications for next report.
-            ArrayList<NotificationData.Entry> activeNotifications = mEntryManager
+            ArrayList<NotificationEntry> activeNotifications = mEntryManager
                     .getNotificationData().getActiveNotifications();
             int N = activeNotifications.size();
             for (int i = 0; i < N; i++) {
-                NotificationData.Entry entry = activeNotifications.get(i);
+                NotificationEntry entry = activeNotifications.get(i);
                 String key = entry.notification.getKey();
                 boolean isVisible = mListContainer.isInVisibleLocation(entry);
-                NotificationVisibility visObj = NotificationVisibility.obtain(key, i, N, isVisible);
+                NotificationVisibility visObj = NotificationVisibility.obtain(key, i, N, isVisible,
+                        getNotificationLocation(entry));
                 boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj);
                 if (isVisible) {
                     // Build new set of visible notifications.
@@ -145,6 +152,9 @@
             recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
             mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications);
 
+            mExpansionStateLogger.onVisibilityChanged(
+                    mTmpCurrentlyVisibleNotifications, mTmpCurrentlyVisibleNotifications);
+
             recycleAllVisibilityObjects(mTmpNoLongerVisibleNotifications);
             mTmpCurrentlyVisibleNotifications.clear();
             mTmpNewlyVisibleNotifications.clear();
@@ -152,31 +162,65 @@
         }
     };
 
+    /**
+     * Returns the location of the notification referenced by the given {@link NotificationEntry}.
+     */
+    public static NotificationVisibility.NotificationLocation getNotificationLocation(
+            NotificationEntry entry) {
+        ExpandableNotificationRow row = entry.getRow();
+        ExpandableViewState childViewState = row.getViewState();
+
+        if (childViewState == null) {
+            return NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN;
+        }
+        return convertNotificationLocation(childViewState.location);
+    }
+
+    private static NotificationVisibility.NotificationLocation convertNotificationLocation(
+            int location) {
+        switch (location) {
+            case ExpandableViewState.LOCATION_FIRST_HUN:
+                return NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP;
+            case ExpandableViewState.LOCATION_HIDDEN_TOP:
+                return NotificationVisibility.NotificationLocation.LOCATION_HIDDEN_TOP;
+            case ExpandableViewState.LOCATION_MAIN_AREA:
+                return NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA;
+            case ExpandableViewState.LOCATION_BOTTOM_STACK_PEEKING:
+                return NotificationVisibility.NotificationLocation.LOCATION_BOTTOM_STACK_PEEKING;
+            case ExpandableViewState.LOCATION_BOTTOM_STACK_HIDDEN:
+                return NotificationVisibility.NotificationLocation.LOCATION_BOTTOM_STACK_HIDDEN;
+            case ExpandableViewState.LOCATION_GONE:
+                return NotificationVisibility.NotificationLocation.LOCATION_GONE;
+            default:
+                return NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN;
+        }
+    }
+
     @Inject
     public NotificationLogger(NotificationListener notificationListener,
             UiOffloadThread uiOffloadThread,
             NotificationEntryManager entryManager,
-            StatusBarStateController statusBarStateController) {
+            StatusBarStateController statusBarStateController,
+            ExpansionStateLogger expansionStateLogger) {
         mNotificationListener = notificationListener;
         mUiOffloadThread = uiOffloadThread;
         mEntryManager = entryManager;
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        mExpansionStateLogger = expansionStateLogger;
         // Not expected to be destroyed, don't need to unsubscribe
         statusBarStateController.addCallback(this);
 
         entryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
             public void onEntryRemoved(
-                    @Nullable NotificationData.Entry entry,
-                    String key,
-                    StatusBarNotification old,
+                    NotificationEntry entry,
                     NotificationVisibility visibility,
-                    boolean lifetimeExtended,
                     boolean removedByUser) {
-                if (removedByUser && visibility != null && entry.notification != null) {
-                    logNotificationClear(key, entry.notification, visibility);
+                if (removedByUser && visibility != null) {
+                    logNotificationClear(entry.key, entry.notification, visibility);
                 }
+                mExpansionStateLogger.onEntryRemoved(entry.key);
             }
 
             @Override
@@ -323,8 +367,8 @@
         }
     }
 
-    private NotificationVisibility[] cloneVisibilitiesAsArr(Collection<NotificationVisibility> c) {
-
+    private static NotificationVisibility[] cloneVisibilitiesAsArr(
+            Collection<NotificationVisibility> c) {
         final NotificationVisibility[] array = new NotificationVisibility[c.size()];
         int i = 0;
         for(NotificationVisibility nv: c) {
@@ -352,9 +396,142 @@
     }
 
     /**
+     * Called when the notification is expanded / collapsed.
+     */
+    public void onExpansionChanged(String key, boolean isUserAction, boolean isExpanded) {
+        NotificationVisibility.NotificationLocation location =
+                getNotificationLocation(mEntryManager.getNotificationData().get(key));
+        mExpansionStateLogger.onExpansionChanged(key, isUserAction, isExpanded, location);
+    }
+
+    /**
      * A listener that is notified when some child locations might have changed.
      */
     public interface OnChildLocationsChangedListener {
         void onChildLocationsChanged();
     }
+
+    /**
+     * Logs the expansion state change when the notification is visible.
+     */
+    public static class ExpansionStateLogger {
+        /** Notification key -> state, should be accessed in UI offload thread only. */
+        private final Map<String, State> mExpansionStates = new ArrayMap<>();
+
+        /**
+         * Notification key -> last logged expansion state, should be accessed in UI thread only.
+         */
+        private final Map<String, Boolean> mLoggedExpansionState = new ArrayMap<>();
+        private final UiOffloadThread mUiOffloadThread;
+        @VisibleForTesting
+        IStatusBarService mBarService;
+
+        @Inject
+        public ExpansionStateLogger(UiOffloadThread uiOffloadThread) {
+            mUiOffloadThread = uiOffloadThread;
+            mBarService =
+                    IStatusBarService.Stub.asInterface(
+                            ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        }
+
+        @VisibleForTesting
+        void onExpansionChanged(String key, boolean isUserAction, boolean isExpanded,
+                NotificationVisibility.NotificationLocation location) {
+            State state = getState(key);
+            state.mIsUserAction = isUserAction;
+            state.mIsExpanded = isExpanded;
+            state.mLocation = location;
+            maybeNotifyOnNotificationExpansionChanged(key, state);
+        }
+
+        @VisibleForTesting
+        void onVisibilityChanged(
+                Collection<NotificationVisibility> newlyVisible,
+                Collection<NotificationVisibility> noLongerVisible) {
+            final NotificationVisibility[] newlyVisibleAr =
+                    cloneVisibilitiesAsArr(newlyVisible);
+            final NotificationVisibility[] noLongerVisibleAr =
+                    cloneVisibilitiesAsArr(noLongerVisible);
+
+            for (NotificationVisibility nv : newlyVisibleAr) {
+                State state = getState(nv.key);
+                state.mIsVisible = true;
+                state.mLocation = nv.location;
+                maybeNotifyOnNotificationExpansionChanged(nv.key, state);
+            }
+            for (NotificationVisibility nv : noLongerVisibleAr) {
+                State state = getState(nv.key);
+                state.mIsVisible = false;
+            }
+        }
+
+        @VisibleForTesting
+        void onEntryRemoved(String key) {
+            mExpansionStates.remove(key);
+            mLoggedExpansionState.remove(key);
+        }
+
+        private State getState(String key) {
+            State state = mExpansionStates.get(key);
+            if (state == null) {
+                state = new State();
+                mExpansionStates.put(key, state);
+            }
+            return state;
+        }
+
+        private void maybeNotifyOnNotificationExpansionChanged(final String key, State state) {
+            if (!state.isFullySet()) {
+                return;
+            }
+            if (!state.mIsVisible) {
+                return;
+            }
+            Boolean loggedExpansionState = mLoggedExpansionState.get(key);
+            // Consider notification is initially collapsed, so only expanded is logged in the
+            // first time.
+            if (loggedExpansionState == null && !state.mIsExpanded) {
+                return;
+            }
+            if (loggedExpansionState != null
+                    && state.mIsExpanded == loggedExpansionState) {
+                return;
+            }
+            mLoggedExpansionState.put(key, state.mIsExpanded);
+            final State stateToBeLogged = new State(state);
+            mUiOffloadThread.submit(() -> {
+                try {
+                    mBarService.onNotificationExpansionChanged(key, stateToBeLogged.mIsUserAction,
+                            stateToBeLogged.mIsExpanded, stateToBeLogged.mLocation.ordinal());
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to call onNotificationExpansionChanged: ", e);
+                }
+            });
+        }
+
+        private static class State {
+            @Nullable
+            Boolean mIsUserAction;
+            @Nullable
+            Boolean mIsExpanded;
+            @Nullable
+            Boolean mIsVisible;
+            @Nullable
+            NotificationVisibility.NotificationLocation mLocation;
+
+            private State() {}
+
+            private State(State state) {
+                this.mIsUserAction = state.mIsUserAction;
+                this.mIsExpanded = state.mIsExpanded;
+                this.mIsVisible = state.mIsVisible;
+                this.mLocation = state.mLocation;
+            }
+
+            private boolean isFullySet() {
+                return mIsUserAction != null && mIsExpanded != null && mIsVisible != null
+                        && mLocation != null;
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 8b0a682..c34d567 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -105,7 +105,7 @@
     private final DoubleTapHelper mDoubleTapHelper;
 
     private boolean mDimmed;
-    private boolean mDark;
+    protected boolean mDark;
 
     protected int mBgTint = NO_COLOR;
     private float mBgAlpha = 1f;
@@ -140,7 +140,6 @@
     private FalsingManager mFalsingManager;
 
     private float mNormalBackgroundVisibilityAmount;
-    private ValueAnimator mFadeInFromDarkAnimator;
     private float mDimmedBackgroundFadeInAmount = -1;
     private ValueAnimator.AnimatorUpdateListener mBackgroundVisibilityUpdater
             = new ValueAnimator.AnimatorUpdateListener() {
@@ -150,22 +149,6 @@
             mDimmedBackgroundFadeInAmount = mBackgroundDimmed.getAlpha();
         }
     };
-    private AnimatorListenerAdapter mFadeInEndListener = new AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            super.onAnimationEnd(animation);
-            mFadeInFromDarkAnimator = null;
-            mDimmedBackgroundFadeInAmount = -1;
-            updateBackground();
-        }
-    };
-    private ValueAnimator.AnimatorUpdateListener mUpdateOutlineListener
-            = new ValueAnimator.AnimatorUpdateListener() {
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            updateOutlineAlpha();
-        }
-    };
     private FakeShadowView mFakeShadow;
     private int mCurrentBackgroundTint;
     private int mTargetTint;
@@ -465,22 +448,11 @@
         mDark = dark;
         updateBackground();
         updateBackgroundTint(false);
-        if (!dark && fade && !shouldHideBackground()) {
-            fadeInFromDark(delay);
-        }
-        updateOutlineAlpha();
     }
 
     private void updateOutlineAlpha() {
-        if (mDark) {
-            setOutlineAlpha(0f);
-            return;
-        }
         float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED;
         alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount);
-        if (mFadeInFromDarkAnimator != null) {
-            alpha *= mFadeInFromDarkAnimator.getAnimatedFraction();
-        }
         setOutlineAlpha(alpha);
     }
 
@@ -638,36 +610,6 @@
     }
 
     /**
-     * Fades in the background when exiting dark mode.
-     */
-    private void fadeInFromDark(long delay) {
-        final View background = mDimmed ? mBackgroundDimmed : mBackgroundNormal;
-        background.setAlpha(0f);
-        mBackgroundVisibilityUpdater.onAnimationUpdate(null);
-        background.animate()
-                .alpha(1f)
-                .setDuration(DARK_ANIMATION_LENGTH)
-                .setStartDelay(delay)
-                .setInterpolator(Interpolators.ALPHA_IN)
-                .setListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationCancel(Animator animation) {
-                        // Jump state if we are cancelled
-                        background.setAlpha(1f);
-                    }
-                })
-                .setUpdateListener(mBackgroundVisibilityUpdater)
-                .start();
-        mFadeInFromDarkAnimator = TimeAnimator.ofFloat(0.0f, 1.0f);
-        mFadeInFromDarkAnimator.setDuration(DARK_ANIMATION_LENGTH);
-        mFadeInFromDarkAnimator.setStartDelay(delay);
-        mFadeInFromDarkAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-        mFadeInFromDarkAnimator.addListener(mFadeInEndListener);
-        mFadeInFromDarkAnimator.addUpdateListener(mUpdateOutlineListener);
-        mFadeInFromDarkAnimator.start();
-    }
-
-    /**
      * Fades the background when the dimmed state changes.
      */
     private void fadeDimmedBackground() {
@@ -708,9 +650,7 @@
             public void onAnimationEnd(Animator animation) {
                 updateBackground();
                 mBackgroundAnimator = null;
-                if (mFadeInFromDarkAnimator == null) {
-                    mDimmedBackgroundFadeInAmount = -1;
-                }
+                mDimmedBackgroundFadeInAmount = -1;
             }
         });
         mBackgroundAnimator.addUpdateListener(mBackgroundVisibilityUpdater);
@@ -736,7 +676,7 @@
             mBackgroundNormal.setVisibility(mActivated ? VISIBLE : INVISIBLE);
         } else if (mDimmed) {
             // When groups are animating to the expanded state from the lockscreen, show the
-            // normal background instead of the dimmed background
+            // normal background instead of the dimmed background.
             final boolean dontShowDimmed = isGroupExpansionChanging() && isChildInGroup();
             mBackgroundDimmed.setVisibility(dontShowDimmed ? View.INVISIBLE : View.VISIBLE);
             mBackgroundNormal.setVisibility((mActivated || dontShowDimmed)
@@ -760,7 +700,7 @@
     }
 
     protected boolean shouldHideBackground() {
-        return mDark;
+        return false;
     }
 
     private void cancelFadeAnimations() {
@@ -1023,14 +963,11 @@
 
     /**
      * @param withTint should a possible tint be factored in?
-     * @param withOverRide should the value be interpolated with {@link #mOverrideTint}
+     * @param withOverride should the value be interpolated with {@link #mOverrideTint}
      * @return the calculated background color
      */
-    private int calculateBgColor(boolean withTint, boolean withOverRide) {
-        if (withTint && mDark) {
-            return getContext().getColor(R.color.notification_material_background_dark_color);
-        }
-        if (withOverRide && mOverrideTint != NO_COLOR) {
+    private int calculateBgColor(boolean withTint, boolean withOverride) {
+        if (withOverride && mOverrideTint != NO_COLOR) {
             int defaultTint = calculateBgColor(withTint, false);
             return NotificationUtils.interpolateColors(defaultTint, mOverrideTint, mOverrideAmount);
         }
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 a58c7cd..296c061 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
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.notification.row;
 
-import static com.android.systemui.statusbar.StatusBarState.SHADE;
 import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED;
@@ -86,10 +85,9 @@
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.logging.NotificationCounters;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
@@ -106,6 +104,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 import java.util.function.BooleanSupplier;
 import java.util.function.Consumer;
 
@@ -122,6 +121,7 @@
     private static final int MENU_VIEW_INDEX = 0;
     private static final String TAG = "ExpandableNotifRow";
     public static final float DEFAULT_HEADER_VISIBLE_AMOUNT = 1.0f;
+    private static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
     private boolean mUpdateBackgroundOnUpdate;
 
     /**
@@ -132,7 +132,6 @@
     }
 
     private LayoutListener mLayoutListener;
-    private boolean mDark;
     private boolean mLowPriorityStateUpdated;
     private final NotificationInflater mNotificationInflater;
     private int mIconTransformContentShift;
@@ -146,7 +145,6 @@
     private int mNotificationMinHeight;
     private int mNotificationMinHeightLarge;
     private int mNotificationMaxHeight;
-    private int mNotificationAmbientHeight;
     private int mIncreasedPaddingBetweenElements;
     private int mNotificationLaunchHeight;
     private boolean mMustStayOnScreen;
@@ -199,7 +197,7 @@
     private ExpansionLogger mLogger;
     private String mLoggingKey;
     private NotificationGuts mGuts;
-    private NotificationData.Entry mEntry;
+    private NotificationEntry mEntry;
     private StatusBarNotification mStatusBarNotification;
     private String mAppName;
 
@@ -451,7 +449,7 @@
      *
      * @param entry the entry this row is tied to
      */
-    public void setEntry(@NonNull NotificationData.Entry entry) {
+    public void setEntry(@NonNull NotificationEntry entry) {
         mEntry = entry;
         mStatusBarNotification = entry.notification;
         cacheIsSystemNotification();
@@ -677,15 +675,14 @@
         if (headsUpWrapper != null) {
             headsUpHeight = Math.max(headsUpHeight, headsUpWrapper.getMinLayoutHeight());
         }
-        layout.setHeights(minHeight, headsUpHeight, mNotificationMaxHeight,
-                mNotificationAmbientHeight);
+        layout.setHeights(minHeight, headsUpHeight, mNotificationMaxHeight, headsUpHeight);
     }
 
     public StatusBarNotification getStatusBarNotification() {
         return mStatusBarNotification;
     }
 
-    public NotificationData.Entry getEntry() {
+    public NotificationEntry getEntry() {
         return mEntry;
     }
 
@@ -1422,7 +1419,7 @@
 
     public void performDismiss(boolean fromAccessibility) {
         if (isOnlyChildInGroup()) {
-            NotificationData.Entry groupSummary =
+            NotificationEntry groupSummary =
                     mGroupManager.getLogicalGroupSummary(getStatusBarNotification());
             if (groupSummary.isClearable()) {
                 // If this is the only child in the group, dismiss the group, but don't try to show
@@ -1647,8 +1644,6 @@
                 R.dimen.notification_min_height_increased);
         mNotificationMaxHeight = NotificationUtils.getFontScaledHeight(mContext,
                 R.dimen.notification_max_height);
-        mNotificationAmbientHeight = NotificationUtils.getFontScaledHeight(mContext,
-                R.dimen.notification_ambient_height);
         mMaxHeadsUpHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
                 R.dimen.notification_max_heads_up_height_legacy);
         mMaxHeadsUpHeightBeforeP = NotificationUtils.getFontScaledHeight(mContext,
@@ -1693,17 +1688,31 @@
     /** Sets the last time the notification being displayed audibly alerted the user. */
     public void setLastAudiblyAlertedMs(long lastAudiblyAlertedMs) {
         if (NotificationUtils.useNewInterruptionModel(mContext)) {
-            boolean recentlyAudiblyAlerted = System.currentTimeMillis() - lastAudiblyAlertedMs
-                    < NotificationEntryManager.RECENTLY_ALERTED_THRESHOLD_MS;
-            if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
-                mChildrenContainer.getHeaderView().setRecentlyAudiblyAlerted(
-                        recentlyAudiblyAlerted);
+            long timeSinceAlertedAudibly = System.currentTimeMillis() - lastAudiblyAlertedMs;
+            boolean alertedRecently =
+                    timeSinceAlertedAudibly < RECENTLY_ALERTED_THRESHOLD_MS;
+
+            applyAudiblyAlertedRecently(alertedRecently);
+
+            removeCallbacks(mExpireRecentlyAlertedFlag);
+            if (alertedRecently) {
+                long timeUntilNoLongerRecent =
+                        RECENTLY_ALERTED_THRESHOLD_MS - timeSinceAlertedAudibly;
+                postDelayed(mExpireRecentlyAlertedFlag, timeUntilNoLongerRecent);
             }
-            mPrivateLayout.setRecentlyAudiblyAlerted(recentlyAudiblyAlerted);
-            mPublicLayout.setRecentlyAudiblyAlerted(recentlyAudiblyAlerted);
         }
     }
 
+    private final Runnable mExpireRecentlyAlertedFlag = () -> applyAudiblyAlertedRecently(false);
+
+    private void applyAudiblyAlertedRecently(boolean audiblyAlertedRecently) {
+        if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
+            mChildrenContainer.getHeaderView().setRecentlyAudiblyAlerted(audiblyAlertedRecently);
+        }
+        mPrivateLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
+        mPublicLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
+    }
+
     public View.OnClickListener getAppOpsOnClickListener() {
         return mOnAppOpsClickListener;
     }
@@ -1994,8 +2003,10 @@
 
     @Override
     public void setDark(boolean dark, boolean fade, long delay) {
+        if (mDark == dark) {
+            return;
+        }
         super.setDark(dark, fade, delay);
-        mDark = dark;
         if (!mIsAmbientPulsing) {
             // Only fade the showing view of the pulsing notification.
             fade = false;
@@ -2004,9 +2015,6 @@
         if (showing != null) {
             showing.setDark(dark, fade, delay);
         }
-        if (mIsSummaryWithChildren) {
-            mChildrenContainer.setDark(dark, fade, delay);
-        }
         updateShelfIconColor();
     }
 
@@ -2307,7 +2315,7 @@
     }
 
     private boolean isShownAsBubble() {
-        return mEntry.isBubble() && (mStatusBarState == SHADE || mStatusBarState == -1);
+        return mEntry.isBubble() && !mEntry.showInShadeWhenBubble() && !mEntry.isBubbleDismissed();
     }
 
     /**
@@ -2538,7 +2546,7 @@
     /**
      * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
      *         otherwise some state might not be updated. To request about the general clearability
-     *         see {@link NotificationData.Entry#isClearable()}.
+     *         see {@link NotificationEntry#isClearable()}.
      */
     public boolean canViewBeDismissed() {
         return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
@@ -2969,7 +2977,7 @@
     }
 
     public interface OnExpandClickListener {
-        void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
+        void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
index 33badaf..90ff4a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
@@ -39,14 +39,10 @@
     private final NotificationDozeHelper mDozer;
     private final ViewGroup mParent;
 
-    private float mOverflowNumberSizeDark;
-    private int mOverflowNumberPaddingDark;
     private float mOverflowNumberSize;
     private int mOverflowNumberPadding;
 
     private int mOverflowNumberColor;
-    private int mOverflowNumberColorDark;
-    private float mDarkAmount = 0f;
 
     public HybridGroupManager(Context ctx, ViewGroup parent) {
         mContext = ctx;
@@ -59,12 +55,8 @@
         Resources res = mContext.getResources();
         mOverflowNumberSize = res.getDimensionPixelSize(
                 R.dimen.group_overflow_number_size);
-        mOverflowNumberSizeDark = res.getDimensionPixelSize(
-                R.dimen.group_overflow_number_size_dark);
         mOverflowNumberPadding = res.getDimensionPixelSize(
                 R.dimen.group_overflow_number_padding);
-        mOverflowNumberPaddingDark = mOverflowNumberPadding + res.getDimensionPixelSize(
-                R.dimen.group_overflow_number_extra_padding_dark);
     }
 
     private HybridNotificationView inflateHybridViewWithStyle(int style) {
@@ -86,13 +78,11 @@
     }
 
     private void updateOverFlowNumberColor(TextView numberView) {
-        numberView.setTextColor(NotificationUtils.interpolateColors(
-                mOverflowNumberColor, mOverflowNumberColorDark, mDarkAmount));
+        numberView.setTextColor(mOverflowNumberColor);
     }
 
-    public void setOverflowNumberColor(TextView numberView, int colorRegular, int colorDark) {
+    public void setOverflowNumberColor(TextView numberView, int colorRegular) {
         mOverflowNumberColor = colorRegular;
-        mOverflowNumberColorDark = colorDark;
         if (numberView != null) {
             updateOverFlowNumberColor(numberView);
         }
@@ -107,7 +97,7 @@
     public HybridNotificationView bindAmbientFromNotification(HybridNotificationView reusableView,
             Notification notification) {
         return bindFromNotificationWithStyle(reusableView, notification,
-                R.style.HybridNotification_Ambient);
+                R.style.HybridNotification);
     }
 
     private HybridNotificationView bindFromNotificationWithStyle(
@@ -150,6 +140,11 @@
                 R.plurals.notification_group_overflow_description, number), number);
 
         reusableView.setContentDescription(contentDescription);
+        reusableView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mOverflowNumberSize);
+        reusableView.setPaddingRelative(reusableView.getPaddingStart(),
+                reusableView.getPaddingTop(), mOverflowNumberPadding,
+                reusableView.getPaddingBottom());
+        updateOverFlowNumberColor(reusableView);
         return reusableView;
     }
 
@@ -163,16 +158,4 @@
         }
         return titleView;
     }
-
-    public void setOverflowNumberDark(TextView view, boolean dark, boolean fade, long delay) {
-        mDozer.setIntensityDark((f)->{
-            mDarkAmount = f;
-            updateOverFlowNumberColor(view);
-        }, dark, fade, delay, view);
-        view.setTextSize(TypedValue.COMPLEX_UNIT_PX,
-                dark ? mOverflowNumberSizeDark : mOverflowNumberSize);
-        int paddingEnd = dark ? mOverflowNumberPaddingDark : mOverflowNumberPadding;
-        view.setPaddingRelative(view.getPaddingStart(), view.getPaddingTop(), paddingEnd,
-                view.getPaddingBottom());
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
index 607d96d..6df72fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
@@ -20,11 +20,13 @@
         .USER_SENTIMENT_NEGATIVE;
 
 import android.content.Context;
+import android.metrics.LogMaker;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -58,6 +60,8 @@
      */
     private boolean mIsShadeExpanded;
 
+    private MetricsLogger mMetricsLogger = new MetricsLogger();
+
     @Inject
     public NotificationBlockingHelperManager(Context context) {
         mContext = context;
@@ -100,6 +104,11 @@
             mBlockingHelperRow = row;
             mBlockingHelperRow.setBlockingHelperShowing(true);
 
+            // Log triggering of blocking helper by the system. This log line
+            // should be emitted before the "display" log line.
+            mMetricsLogger.write(
+                    getLogMaker().setSubtype(MetricsEvent.BLOCKING_HELPER_TRIGGERED_BY_SYSTEM));
+
             // We don't care about the touch origin (x, y) since we're opening guts without any
             // explicit user interaction.
             manager.openGuts(mBlockingHelperRow, 0, 0, menuRow.getLongpressMenuItem(mContext));
@@ -153,6 +162,13 @@
                 || mNonBlockablePkgs.contains(makeChannelKey(packageName, channelName));
     }
 
+    private LogMaker getLogMaker() {
+        return mBlockingHelperRow.getStatusBarNotification()
+            .getLogMaker()
+            .setCategory(MetricsEvent.NOTIFICATION_ITEM)
+            .setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER);
+    }
+
     // Format must stay in sync with frameworks/base/core/res/res/values/config.xml
     // config_nonBlockableNotificationPackages
     private String makeChannelKey(String pkg, String channel) {
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 02a310c..c161da3 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
@@ -46,8 +46,8 @@
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.TransformableView;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -1231,7 +1231,7 @@
         updateAllSingleLineViews();
     }
 
-    public void onNotificationUpdated(NotificationData.Entry entry) {
+    public void onNotificationUpdated(NotificationEntry entry) {
         mStatusBarNotification = entry.notification;
         mOnContentViewInactiveListeners.clear();
         mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
@@ -1292,7 +1292,7 @@
         }
     }
 
-    private void applyRemoteInputAndSmartReply(final NotificationData.Entry entry) {
+    private void applyRemoteInputAndSmartReply(final NotificationEntry entry) {
         if (mRemoteInputController == null) {
             return;
         }
@@ -1313,7 +1313,7 @@
     @VisibleForTesting
     static SmartRepliesAndActions chooseSmartRepliesAndActions(
             SmartReplyConstants smartReplyConstants,
-            final NotificationData.Entry entry) {
+            final NotificationEntry entry) {
         boolean enableAppGeneratedSmartReplies = (smartReplyConstants.isEnabled()
                 && (!smartReplyConstants.requiresTargetingP()
                 || entry.targetSdk >= Build.VERSION_CODES.P));
@@ -1370,7 +1370,7 @@
                 smartReplies, smartActions, freeformRemoteInputActionPair != null);
     }
 
-    private void applyRemoteInput(NotificationData.Entry entry, boolean hasFreeformRemoteInput) {
+    private void applyRemoteInput(NotificationEntry entry, boolean hasFreeformRemoteInput) {
         View bigContentView = mExpandedChild;
         if (bigContentView != null) {
             mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasFreeformRemoteInput,
@@ -1402,7 +1402,7 @@
         mCachedHeadsUpRemoteInput = null;
     }
 
-    private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry,
+    private RemoteInputView applyRemoteInput(View view, NotificationEntry entry,
             boolean hasRemoteInput, PendingIntent existingPendingIntent,
             RemoteInputView cachedView, NotificationViewWrapper wrapper) {
         View actionContainerCandidate = view.findViewById(
@@ -1470,7 +1470,7 @@
     }
 
     private void applySmartReplyView(SmartRepliesAndActions smartRepliesAndActions,
-            NotificationData.Entry entry) {
+            NotificationEntry entry) {
         if (mExpandedChild != null) {
             mExpandedSmartReplyView =
                     applySmartReplyView(mExpandedChild, smartRepliesAndActions, entry);
@@ -1489,14 +1489,14 @@
                 }
             }
         }
-        if (mHeadsUpChild != null) {
+        if (mHeadsUpChild != null && mSmartReplyConstants.getShowInHeadsUp()) {
             mHeadsUpSmartReplyView =
                     applySmartReplyView(mHeadsUpChild, smartRepliesAndActions, entry);
         }
     }
 
     private SmartReplyView applySmartReplyView(View view,
-            SmartRepliesAndActions smartRepliesAndActions, NotificationData.Entry entry) {
+            SmartRepliesAndActions smartRepliesAndActions, NotificationEntry entry) {
         View smartReplyContainerCandidate = view.findViewById(
                 com.android.internal.R.id.smart_reply_container);
         if (!(smartReplyContainerCandidate instanceof LinearLayout)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index ac4e583..5e9f207 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -48,7 +49,7 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -116,7 +117,7 @@
         mNotificationActivityStarter = notificationActivityStarter;
     }
 
-    public void onDensityOrFontScaleChanged(NotificationData.Entry entry) {
+    public void onDensityOrFontScaleChanged(NotificationEntry entry) {
         setExposedGuts(entry.getGuts());
         bindGuts(entry.getRow());
     }
@@ -159,7 +160,8 @@
         return bindGuts(row, mGutsMenuItem);
     }
 
-    private boolean bindGuts(final ExpandableNotificationRow row,
+    @VisibleForTesting
+    protected boolean bindGuts(final ExpandableNotificationRow row,
             NotificationMenuRowPlugin.MenuItem item) {
         StatusBarNotification sbn = row.getStatusBarNotification();
 
@@ -389,7 +391,11 @@
             return false;
         }
 
-        mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_NOTE_CONTROLS);
+        LogMaker logMaker = (row.getStatusBarNotification() == null)
+                ? new LogMaker(MetricsProto.MetricsEvent.ACTION_NOTE_CONTROLS)
+                : row.getStatusBarNotification().getLogMaker();
+        mMetricsLogger.write(logMaker.setCategory(MetricsProto.MetricsEvent.ACTION_NOTE_CONTROLS)
+                    .setType(MetricsProto.MetricsEvent.TYPE_ACTION));
 
         // ensure that it's laid but not visible until actually laid out
         guts.setVisibility(View.INVISIBLE);
@@ -429,7 +435,7 @@
     }
 
     @Override
-    public boolean shouldExtendLifetime(NotificationData.Entry entry) {
+    public boolean shouldExtendLifetime(NotificationEntry entry) {
         return entry != null
                 &&(mNotificationGutsExposed != null
                     && entry.getGuts() != null
@@ -438,7 +444,7 @@
     }
 
     @Override
-    public void setShouldManageLifetime(NotificationData.Entry entry, boolean shouldExtend) {
+    public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) {
         if (shouldExtend) {
             mKeyToRemoveOnGutsClosed = entry.key;
             if (Log.isLoggable(TAG, Log.DEBUG)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
index 9908049..42ebfce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
@@ -37,7 +37,7 @@
 import com.android.systemui.statusbar.InflationTask;
 import com.android.systemui.statusbar.notification.InflationException;
 import com.android.systemui.statusbar.notification.MediaNotificationProcessor;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.util.Assert;
@@ -614,7 +614,7 @@
             @Nullable InflationCallback endListener, ExpandableNotificationRow row,
             boolean redactAmbient) {
         Assert.isMainThread();
-        NotificationData.Entry entry = row.getEntry();
+        NotificationEntry entry = row.getEntry();
         NotificationContentView privateLayout = row.getPrivateLayout();
         NotificationContentView publicLayout = row.getPublicLayout();
         if (runningInflations.isEmpty()) {
@@ -724,7 +724,7 @@
          * @param entry the entry with the content views set
          * @param inflatedFlags the flags associated with the content views that were inflated
          */
-        void onAsyncInflationFinished(NotificationData.Entry entry,
+        void onAsyncInflationFinished(NotificationEntry entry,
                 @InflationFlag int inflatedFlags);
 
         /**
@@ -782,7 +782,7 @@
             mRedactAmbient = redactAmbient;
             mRemoteViewClickHandler = remoteViewClickHandler;
             mCallback = callback;
-            NotificationData.Entry entry = row.getEntry();
+            NotificationEntry entry = row.getEntry();
             entry.setInflationTask(this);
         }
 
@@ -857,7 +857,7 @@
         }
 
         @Override
-        public void onAsyncInflationFinished(NotificationData.Entry entry,
+        public void onAsyncInflationFinished(NotificationEntry entry,
                 @InflationFlag int inflatedFlags) {
             mRow.getEntry().onInflationTaskFinished();
             mRow.onNotificationUpdated();
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 b1eab80..5253e38 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
@@ -123,11 +123,15 @@
     private OnClickListener mOnKeepShowing = v -> {
         mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
         closeControls(v);
+        mMetricsLogger.write(getLogMaker().setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
+                .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT));
     };
 
     private OnClickListener mOnToggleSilent = v -> {
         Runnable saveImportance = () -> {
             swapContent(ACTION_TOGGLE_SILENT, true /* animate */);
+            mMetricsLogger.write(getLogMaker().setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
+                    .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME));
         };
         if (mCheckSaveListener != null) {
             mCheckSaveListener.checkSave(saveImportance, mSbn);
@@ -139,6 +143,8 @@
     private OnClickListener mOnStopOrMinimizeNotifications = v -> {
         Runnable saveImportance = () -> {
             swapContent(ACTION_BLOCK, true /* animate */);
+            mMetricsLogger.write(getLogMaker().setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
+                    .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED));
         };
         if (mCheckSaveListener != null) {
             mCheckSaveListener.checkSave(saveImportance, mSbn);
@@ -153,6 +159,8 @@
         logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
         mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS));
         swapContent(ACTION_UNDO, true /* animate */);
+        mMetricsLogger.write(getLogMaker().setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
+                .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_UNDO));
     };
 
     public NotificationInfo(Context context, AttributeSet attrs) {
@@ -251,6 +259,9 @@
         bindHeader();
         bindPrompt();
         bindButtons();
+
+        mMetricsLogger.write(getLogMaker().setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
+                .setSubtype(MetricsEvent.BLOCKING_HELPER_DISPLAY));
     }
 
     private void bindHeader() throws RemoteException {
@@ -588,6 +599,8 @@
         confirmation.setAlpha(1f);
         header.setVisibility(VISIBLE);
         header.setAlpha(1f);
+        mMetricsLogger.write(getLogMaker().setType(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
+                .setSubtype(MetricsEvent.BLOCKING_HELPER_DISMISS));
     }
 
     @Override
@@ -733,4 +746,8 @@
             }
         }
     }
+
+    private LogMaker getLogMaker() {
+        return mSbn.getLogMaker().setCategory(MetricsEvent.NOTIFICATION_ITEM);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
index 1741a0b..0160c547 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
@@ -25,7 +25,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.InflationTask;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 /**
  * An inflater task that asynchronously inflates a ExpandableNotificationRow
@@ -36,14 +36,14 @@
     private static final boolean TRACE_ORIGIN = true;
 
     private RowInflationFinishedListener mListener;
-    private NotificationData.Entry mEntry;
+    private NotificationEntry mEntry;
     private boolean mCancelled;
     private Throwable mInflateOrigin;
 
     /**
      * Inflates a new notificationView. This should not be called twice on this object
      */
-    public void inflate(Context context, ViewGroup parent, NotificationData.Entry entry,
+    public void inflate(Context context, ViewGroup parent, NotificationEntry entry,
             RowInflationFinishedListener listener) {
         if (TRACE_ORIGIN) {
             mInflateOrigin = new Throwable("inflate requested here");
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 670908f..c246af5 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
@@ -25,7 +25,7 @@
 import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -42,6 +42,8 @@
 
     private ArrayList<ExpandableView> mDraggedViews = new ArrayList<>();
     private int mScrollY;
+    private int mAnchorViewIndex;
+    private int mAnchorViewY;
     private boolean mDimmed;
     private ActivatableNotificationView mActivatedChild;
     private float mOverScrollTopAmount;
@@ -75,7 +77,6 @@
     private int mIntrinsicPadding;
     private int mExpandAnimationTopChange;
     private ExpandableNotificationRow mExpandingNotification;
-    private int mDarkTopPadding;
     private float mDarkAmount;
     private boolean mAppearing;
 
@@ -131,6 +132,27 @@
         this.mScrollY = scrollY;
     }
 
+    /**
+     * Index of the child view whose Y position on screen is returned by {@link #getAnchorViewY()}.
+     * Other views are laid out outwards from this view in both directions.
+     */
+    public int getAnchorViewIndex() {
+        return mAnchorViewIndex;
+    }
+
+    public void setAnchorViewIndex(int anchorViewIndex) {
+        mAnchorViewIndex = anchorViewIndex;
+    }
+
+    /** Current Y position of the view at {@link #getAnchorViewIndex()}. */
+    public int getAnchorViewY() {
+        return mAnchorViewY;
+    }
+
+    public void setAnchorViewY(int anchorViewY) {
+        mAnchorViewY = anchorViewY;
+    }
+
     /** Call when dragging begins. */
     public void onBeginDrag(ExpandableView view) {
         mDraggedViews.add(view);
@@ -351,14 +373,15 @@
     }
 
     public boolean hasPulsingNotifications() {
-        return mPulsing;
+        return mPulsing && mAmbientPulseManager != null
+                && mAmbientPulseManager.hasNotifications();
     }
 
     public void setPulsing(boolean hasPulsing) {
         mPulsing = hasPulsing;
     }
 
-    public boolean isPulsing(NotificationData.Entry entry) {
+    public boolean isPulsing(NotificationEntry entry) {
         if (!mPulsing || mAmbientPulseManager == null) {
             return false;
         }
@@ -458,14 +481,6 @@
         return mDarkAmount != 0;
     }
 
-    public void setDarkTopPadding(int darkTopPadding) {
-        mDarkTopPadding = darkTopPadding;
-    }
-
-    public int getDarkTopPadding() {
-        return mDarkTopPadding;
-    }
-
     public void setAppearing(boolean appearing) {
         mAppearing = appearing;
     }
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 5118036..8ffada4 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
@@ -316,7 +316,7 @@
         StatusBarNotification notification = mContainingNotification.getStatusBarNotification();
         final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
                 notification.getNotification());
-        RemoteViews header = builder.makeNotificationHeader(false /* ambient */);
+        RemoteViews header = builder.makeNotificationHeader();
         if (mNotificationHeader == null) {
             mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
             final View expandButton = mNotificationHeader.findViewById(
@@ -344,7 +344,7 @@
             builder = Notification.Builder.recoverBuilder(getContext(),
                     notification.getNotification());
         }
-        header = builder.makeNotificationHeader(true /* ambient */);
+        header = builder.makeNotificationHeader();
         if (mNotificationHeaderAmbient == null) {
             mNotificationHeaderAmbient = (ViewGroup) header.apply(getContext(), this);
             mNotificationHeaderWrapperAmbient = NotificationViewWrapper.wrap(getContext(),
@@ -1171,12 +1171,6 @@
         return mIsLowPriority && !mContainingNotification.isExpanded();
     }
 
-    public void setDark(boolean dark, boolean fade, long delay) {
-        if (mOverflowNumber != null) {
-            mHybridGroupManager.setOverflowNumberDark(mOverflowNumber, dark, fade, delay);
-        }
-    }
-
     public void reInflateViews(OnClickListener listener, StatusBarNotification notification) {
         if (mNotificationHeader != null) {
             removeView(mNotificationHeader);
@@ -1227,8 +1221,7 @@
 
     public void onNotificationUpdated() {
         mHybridGroupManager.setOverflowNumberColor(mOverflowNumber,
-                mContainingNotification.getNotificationColor(),
-                mContainingNotification.getNotificationColorAmbient());
+                mContainingNotification.getNotificationColor());
     }
 
     public int getPositionInLinearLayout(View childInGroup) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index f0a2653..f771be0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -16,15 +16,14 @@
 
 package com.android.systemui.statusbar.notification.stack;
 
-import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator
-        .ExpandAnimationParameters;
+import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
 
 import android.view.View;
 import android.view.ViewGroup;
 
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -113,19 +112,12 @@
     void setMaxDisplayedNotifications(int maxNotifications);
 
     /**
-     * Handle snapping a non-dismissable row back if the user tried to dismiss it.
-     *
-     * @param entry the entry whose row needs to snap back
-     */
-    void snapViewIfNeeded(NotificationData.Entry entry);
-
-    /**
      * Get the view parent for a notification entry. For example, NotificationStackScrollLayout.
      *
      * @param entry entry to get the view parent for
      * @return the view parent for entry
      */
-    ViewGroup getViewParentForNotification(NotificationData.Entry entry);
+    ViewGroup getViewParentForNotification(NotificationEntry entry);
 
     /**
      * Resets the currently exposed menu view.
@@ -148,7 +140,7 @@
      *
      * @param entry the entry whose view's view state needs to be cleaned up (say that 5 times fast)
      */
-    void cleanUpViewStateForEntry(NotificationData.Entry entry);
+    void cleanUpViewStateForEntry(NotificationEntry entry);
 
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
index 4f0831f1..c5ab9f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
@@ -18,7 +18,8 @@
 
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.NUM_SECTIONS;
 
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.AmbientPulseManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -26,35 +27,43 @@
 
 import java.util.HashSet;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 /**
  * A class that manages the roundness for notification views
  */
-class NotificationRoundnessManager implements OnHeadsUpChangedListener {
+@Singleton
+class NotificationRoundnessManager implements OnHeadsUpChangedListener,
+        AmbientPulseManager.OnAmbientChangedListener {
 
+    private final ActivatableNotificationView[] mFirstInSectionViews;
+    private final ActivatableNotificationView[] mLastInSectionViews;
+    private final ActivatableNotificationView[] mTmpFirstInSectionViews;
+    private final ActivatableNotificationView[] mTmpLastInSectionViews;
     private boolean mExpanded;
-    private ActivatableNotificationView[] mFirstInSectionViews;
-    private ActivatableNotificationView[] mLastInSectionViews;
-    private ActivatableNotificationView[] mTmpFirstInSectionViews;
-    private ActivatableNotificationView[] mTmpLastInSectionViews;
     private HashSet<ExpandableView> mAnimatedChildren;
     private Runnable mRoundingChangedCallback;
     private ExpandableNotificationRow mTrackedHeadsUp;
+    private ActivatableNotificationView mTrackedAmbient;
     private float mAppearFraction;
 
-    NotificationRoundnessManager() {
+    @Inject
+    NotificationRoundnessManager(AmbientPulseManager ambientPulseManager) {
         mFirstInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
         mLastInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
         mTmpFirstInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
         mTmpLastInSectionViews = new ActivatableNotificationView[NUM_SECTIONS];
+        ambientPulseManager.addListener(this);
     }
 
     @Override
-    public void onHeadsUpPinned(NotificationData.Entry headsUp) {
+    public void onHeadsUpPinned(NotificationEntry headsUp) {
         updateView(headsUp.getRow(), false /* animate */);
     }
 
     @Override
-    public void onHeadsUpUnPinned(NotificationData.Entry headsUp) {
+    public void onHeadsUpUnPinned(NotificationEntry headsUp) {
         updateView(headsUp.getRow(), true /* animate */);
     }
 
@@ -63,6 +72,17 @@
         updateView(row, false /* animate */);
     }
 
+    @Override
+    public void onAmbientStateChanged(NotificationEntry entry, boolean isPulsing) {
+        ActivatableNotificationView row = entry.getRow();
+        if (isPulsing) {
+            mTrackedAmbient = row;
+        } else if (mTrackedAmbient == row) {
+            mTrackedAmbient = null;
+        }
+        updateView(row, false /* animate */);
+    }
+
     private void updateView(ActivatableNotificationView view, boolean animate) {
         boolean changed = updateViewWithoutCallback(view, animate);
         if (changed) {
@@ -125,6 +145,9 @@
             // rounded.
             return 1.0f;
         }
+        if (view == mTrackedAmbient) {
+            return 1.0f;
+        }
         return 0.0f;
     }
 
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 f982ecf..2129b81 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
@@ -16,9 +16,12 @@
 
 package com.android.systemui.statusbar.notification.stack;
 
+import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
 import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
+import static com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.ANCHOR_SCROLLING;
 import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE;
 import static com.android.systemui.statusbar.phone.NotificationIconAreaController.LOW_PRIORITY;
+import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -94,12 +97,13 @@
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.FakeShadowView;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 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.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -110,6 +114,7 @@
 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.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
@@ -136,6 +141,9 @@
 import java.util.List;
 import java.util.function.BiConsumer;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+
 /**
  * A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
  */
@@ -165,13 +173,22 @@
     private final Paint mBackgroundPaint = new Paint();
     private final boolean mShouldDrawNotificationBackground;
     private boolean mLowPriorityBeforeSpeedBump;
+    private final boolean mAllowLongPress;
 
     private float mExpandedHeight;
     private int mOwnScrollY;
+    private View mScrollAnchorView;
+    private int mScrollAnchorViewY;
     private int mMaxLayoutHeight;
 
     private VelocityTracker mVelocityTracker;
     private OverScroller mScroller;
+    /** Last Y position reported by {@link #mScroller}, used to calculate scroll delta. */
+    private int mLastScrollerY;
+    /**
+     * True if the max position was set to a known position on the last call to {@link #mScroller}.
+     */
+    private boolean mIsScrollerBoundSet;
     private Runnable mFinishScrollingCallback;
     private int mTouchSlop;
     private int mMinimumVelocity;
@@ -193,12 +210,7 @@
     private int mPaddingBetweenElements;
     private int mIncreasedPaddingBetweenElements;
     private int mMaxTopPadding;
-    private int mRegularTopPadding;
-    private int mDarkTopPadding;
-    // Current padding, will be either mRegularTopPadding or mDarkTopPadding
     private int mTopPadding;
-    // Distance between AOD separator and shelf
-    private int mDarkShelfPadding;
     private int mBottomMargin;
     private int mBottomInset = 0;
     private float mQsExpansionFraction;
@@ -310,7 +322,7 @@
     private HashSet<Pair<ExpandableNotificationRow, Boolean>> mHeadsUpChangeAnimations
             = new HashSet<>();
     private HeadsUpManagerPhone mHeadsUpManager;
-    private NotificationRoundnessManager mRoundnessManager = new NotificationRoundnessManager();
+    private final NotificationRoundnessManager mRoundnessManager;
     private boolean mTrackingHeadsUp;
     private ScrimController mScrimController;
     private boolean mForceNoOverlappingRendering;
@@ -414,7 +426,12 @@
     private int mStatusBarState;
     private int mCachedBackgroundColor;
     private boolean mHeadsUpGoingAwayAnimationsAllowed = true;
-    private Runnable mAnimateScroll = this::animateScroll;
+    private Runnable mReflingAndAnimateScroll = () -> {
+        if (ANCHOR_SCROLLING) {
+            maybeReflingScroller();
+        }
+        animateScroll();
+    };
     private int mCornerRadius;
     private int mSidePaddings;
     private final Rect mBackgroundAnimationRect = new Rect();
@@ -423,7 +440,7 @@
     private int mHeadsUpInset;
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
     private NotificationIconAreaController mIconAreaController;
-    private float mVerticalPanelTranslation;
+    private float mHorizontalPanelTranslation;
     private final NotificationLockscreenUserManager mLockscreenUserManager =
             Dependency.get(NotificationLockscreenUserManager.class);
     protected final NotificationGutsManager mGutsManager =
@@ -433,7 +450,8 @@
             Dependency.get(NotificationEntryManager.class);
     private final IStatusBarService mBarService = IStatusBarService.Stub.asInterface(
             ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+    @VisibleForTesting
+    protected final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
     private final NotificationRemoteInputManager mRemoteInputManager =
             Dependency.get(NotificationRemoteInputManager.class);
     private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
@@ -451,33 +469,28 @@
 
     private final NotificationGutsManager
             mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);
+    /**
+     * If the {@link NotificationShelf} should be visible when dark.
+     */
+    private boolean mShowDarkShelf;
 
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public NotificationStackScrollLayout(Context context) {
-        this(context, null);
-    }
-
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public NotificationStackScrollLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public NotificationStackScrollLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public NotificationStackScrollLayout(Context context, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
+    @Inject
+    public NotificationStackScrollLayout(
+            @Named(VIEW_CONTEXT) Context context,
+            AttributeSet attrs,
+            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
+            NotificationRoundnessManager notificationRoundnessManager) {
+        super(context, attrs, 0, 0);
         Resources res = getResources();
 
+        mAllowLongPress = allowLongPress;
+
         for (int i = 0; i < NUM_SECTIONS; i++) {
             mSections[i] = new NotificationSection(this);
         }
 
         mAmbientState = new AmbientState(context);
+        mRoundnessManager = notificationRoundnessManager;
         mBgColor = context.getColor(R.color.notification_shade_background_color);
         int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
         int maxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
@@ -494,7 +507,6 @@
                 res.getBoolean(R.bool.config_drawNotificationBackground);
         mFadeNotificationsOnDismiss =
                 res.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
-        mDarkShelfPadding = res.getDimensionPixelSize(R.dimen.widget_bottom_separator_padding);
         mRoundnessManager.setAnimatedChildren(mChildrenToAddAnimated);
         mRoundnessManager.setOnRoundingChangedCallback(this::invalidate);
         addOnExpandedHeightListener(mRoundnessManager::setExpanded);
@@ -513,6 +525,7 @@
             mDebugPaint.setColor(0xffff0000);
             mDebugPaint.setStrokeWidth(2);
             mDebugPaint.setStyle(Paint.Style.STROKE);
+            mDebugPaint.setTextSize(25f);
         }
         mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll);
 
@@ -522,6 +535,17 @@
                 mLowPriorityBeforeSpeedBump = "1".equals(newValue);
             }
         }, LOW_PRIORITY);
+
+        mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
+            @Override
+            public void onPostEntryUpdated(NotificationEntry entry) {
+                if (!entry.notification.isClearable()) {
+                    // The user may have performed a dismiss action on the notification, since it's
+                    // not clearable we should snap it back.
+                    snapViewIfNeeded(entry);
+                }
+            }
+        });
     }
 
     @Override
@@ -532,7 +556,9 @@
         inflateEmptyShadeView();
         inflateFooterView();
         mVisualStabilityManager.setVisibilityLocationProvider(this::isInVisibleLocation);
-        setLongPressListener(mEntryManager.getNotificationLongClicker());
+        if (mAllowLongPress) {
+            setLongPressListener(mGutsManager::openGuts);
+        }
     }
 
     @Override
@@ -593,14 +619,14 @@
   @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
   public RemoteInputController.Delegate createDelegate() {
         return new RemoteInputController.Delegate() {
-            public void setRemoteInputActive(NotificationData.Entry entry,
+            public void setRemoteInputActive(NotificationEntry entry,
                     boolean remoteInputActive) {
                 mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
                 entry.notifyHeightChanged(true /* needsAnimation */);
                 updateFooter();
             }
 
-            public void lockScrollTo(NotificationData.Entry entry) {
+            public void lockScrollTo(NotificationEntry entry) {
                 NotificationStackScrollLayout.this.lockScrollTo(entry.getRow());
             }
 
@@ -663,6 +689,30 @@
         }
     }
 
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+
+        if (DEBUG && ANCHOR_SCROLLING) {
+            if (mScrollAnchorView instanceof ExpandableNotificationRow) {
+                canvas.drawRect(0,
+                        mScrollAnchorView.getTranslationY(),
+                        getWidth(),
+                        mScrollAnchorView.getTranslationY()
+                                + ((ExpandableNotificationRow) mScrollAnchorView).getActualHeight(),
+                        mDebugPaint);
+                canvas.drawText(Integer.toString(mScrollAnchorViewY), getWidth() - 200,
+                        mScrollAnchorView.getTranslationY() + 30, mDebugPaint);
+                int y = (int) mShelf.getTranslationY();
+                canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+            }
+            canvas.drawText(Integer.toString(getMaxNegativeScrollAmount()), getWidth() - 100,
+                    getIntrinsicPadding() + 30, mDebugPaint);
+            canvas.drawText(Integer.toString(getMaxPositiveScrollAmount()), getWidth() - 100,
+                    getHeight() - 30, mDebugPaint);
+        }
+    }
+
     @ShadeViewRefactor(RefactorComponent.DECORATOR)
     private void drawBackground(Canvas canvas) {
         int lockScreenLeft = mSidePaddings;
@@ -670,7 +720,7 @@
         int lockScreenTop = mSections[0].getCurrentBounds().top;
         int lockScreenBottom = mSections[NUM_SECTIONS - 1].getCurrentBounds().bottom;
         int darkLeft = getWidth() / 2;
-        int darkTop = mRegularTopPadding;
+        int darkTop = mTopPadding;
 
         float yProgress = 1 - mInterpolatedDarkAmount;
         float xProgress = mDarkXInterpolator.getInterpolation(
@@ -913,7 +963,7 @@
 
     @Override
     @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
-    public boolean isInVisibleLocation(NotificationData.Entry entry) {
+    public boolean isInVisibleLocation(NotificationEntry entry) {
         ExpandableNotificationRow row = entry.getRow();
         ExpandableViewState childViewState = row.getViewState();
 
@@ -938,8 +988,6 @@
 
     @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
     private void updateAlgorithmHeightAndPadding() {
-        mTopPadding = (int) MathUtils.lerp(mRegularTopPadding, mDarkTopPadding,
-                mInterpolatedDarkAmount);
         mAmbientState.setLayoutHeight(getLayoutHeight());
         updateAlgorithmLayoutMinHeight();
         mAmbientState.setTopPadding(mTopPadding);
@@ -961,7 +1009,12 @@
         mAmbientState.setCurrentScrollVelocity(mScroller.isFinished()
                 ? 0
                 : mScroller.getCurrVelocity());
-        mAmbientState.setScrollY(mOwnScrollY);
+        if (ANCHOR_SCROLLING) {
+            mAmbientState.setAnchorViewIndex(indexOfChild(mScrollAnchorView));
+            mAmbientState.setAnchorViewY(mScrollAnchorViewY);
+        } else {
+            mAmbientState.setScrollY(mOwnScrollY);
+        }
         mStackScrollAlgorithm.resetViewStates(mAmbientState);
         if (!isCurrentlyAnimating() && !mNeedsAnimation) {
             applyCurrentState();
@@ -995,7 +1048,7 @@
             float end = start + child.getActualHeight();
             boolean clip = clipStart > start && clipStart < end
                     || clipEnd >= start && clipEnd <= end;
-            clip &= !(first && mOwnScrollY == 0);
+            clip &= !(first && isScrolledToTop());
             child.setDistanceToTopRoundness(clip ? Math.max(start - clipStart, 0)
                     : ExpandableView.NO_ROUNDNESS);
             first = false;
@@ -1007,19 +1060,21 @@
         if (mChildrenToAddAnimated.isEmpty()) {
             return;
         }
-        for (int i = 0; i < getChildCount(); i++) {
-            ExpandableView child = (ExpandableView) getChildAt(i);
-            if (mChildrenToAddAnimated.contains(child)) {
-                int startingPosition = getPositionInLinearLayout(child);
-                float increasedPaddingAmount = child.getIncreasedPaddingAmount();
-                int padding = increasedPaddingAmount == 1.0f ? mIncreasedPaddingBetweenElements
-                        : increasedPaddingAmount == -1.0f ? 0 : mPaddingBetweenElements;
-                int childHeight = getIntrinsicHeight(child) + padding;
-                if (startingPosition < mOwnScrollY) {
-                    // This child starts off screen, so let's keep it offscreen to keep the
-                    // others visible
+        if (!ANCHOR_SCROLLING) {
+            for (int i = 0; i < getChildCount(); i++) {
+                ExpandableView child = (ExpandableView) getChildAt(i);
+                if (mChildrenToAddAnimated.contains(child)) {
+                    int startingPosition = getPositionInLinearLayout(child);
+                    float increasedPaddingAmount = child.getIncreasedPaddingAmount();
+                    int padding = increasedPaddingAmount == 1.0f ? mIncreasedPaddingBetweenElements
+                            : increasedPaddingAmount == -1.0f ? 0 : mPaddingBetweenElements;
+                    int childHeight = getIntrinsicHeight(child) + padding;
+                    if (startingPosition < mOwnScrollY) {
+                        // This child starts off screen, so let's keep it offscreen to keep the
+                        // others visible
 
-                    setOwnScrollY(mOwnScrollY + childHeight);
+                        setOwnScrollY(mOwnScrollY + childHeight);
+                    }
                 }
             }
         }
@@ -1038,12 +1093,16 @@
             int targetScroll = targetScrollForView(expandableView, positionInLinearLayout);
             int outOfViewScroll = positionInLinearLayout + expandableView.getIntrinsicHeight();
 
-            targetScroll = Math.max(0, Math.min(targetScroll, getScrollRange()));
+            if (ANCHOR_SCROLLING) {
+                // TODO
+            } else {
+                targetScroll = Math.max(0, Math.min(targetScroll, getScrollRange()));
 
-            // Only apply the scroll if we're scrolling the view upwards, or the view is so far up
-            // that it is not visible anymore.
-            if (mOwnScrollY < targetScroll || outOfViewScroll < mOwnScrollY) {
-                setOwnScrollY(targetScroll);
+                // Only apply the scroll if we're scrolling the view upwards, or the view is so
+                // far up that it is not visible anymore.
+                if (mOwnScrollY < targetScroll || outOfViewScroll < mOwnScrollY) {
+                    setOwnScrollY(targetScroll);
+                }
             }
         }
     }
@@ -1064,9 +1123,13 @@
 
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     private void clampScrollPosition() {
-        int scrollRange = getScrollRange();
-        if (scrollRange < mOwnScrollY) {
-            setOwnScrollY(scrollRange);
+        if (ANCHOR_SCROLLING) {
+            // TODO
+        } else {
+            int scrollRange = getScrollRange();
+            if (scrollRange < mOwnScrollY) {
+                setOwnScrollY(scrollRange);
+            }
         }
     }
 
@@ -1077,10 +1140,8 @@
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     private void setTopPadding(int topPadding, boolean animate) {
-        if (mRegularTopPadding != topPadding) {
-            mRegularTopPadding = topPadding;
-            mDarkTopPadding = topPadding + mDarkShelfPadding;
-            mAmbientState.setDarkTopPadding(mDarkTopPadding);
+        if (mTopPadding != topPadding) {
+            mTopPadding = topPadding;
             updateAlgorithmHeightAndPadding();
             updateContentHeight();
             if (animate && mAnimationsEnabled && mIsExpanded) {
@@ -1187,7 +1248,7 @@
             mIsClipped = clipped;
         }
 
-        if (mPulsing) {
+        if (mPulsing || mAmbientState.isFullyDark() && mShowDarkShelf) {
             setClipBounds(null);
         } else if (mAmbientState.isDarkAtAll()) {
             setClipBounds(mBackgroundAnimationRect);
@@ -1227,13 +1288,13 @@
      */
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     private int getTopHeadsUpPinnedHeight() {
-        NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry();
+        NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
         if (topEntry == null) {
             return 0;
         }
         ExpandableNotificationRow row = topEntry.getRow();
         if (row.isChildInGroup()) {
-            final NotificationData.Entry groupSummary
+            final NotificationEntry groupSummary
                     = mGroupManager.getGroupSummary(row.getStatusBarNotification());
             if (groupSummary != null) {
                 row = groupSummary.getRow();
@@ -1408,7 +1469,7 @@
                     && touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) {
                 if (slidingChild instanceof ExpandableNotificationRow) {
                     ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild;
-                    NotificationData.Entry entry = row.getEntry();
+                    NotificationEntry entry = row.getEntry();
                     if (!mIsExpanded && row.isHeadsUp() && row.isPinned()
                             && mHeadsUpManager.getTopEntry().getRow() != row
                             && mGroupManager.getGroupSummary(
@@ -1446,17 +1507,21 @@
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public boolean scrollTo(View v) {
         ExpandableView expandableView = (ExpandableView) v;
-        int positionInLinearLayout = getPositionInLinearLayout(v);
-        int targetScroll = targetScrollForView(expandableView, positionInLinearLayout);
-        int outOfViewScroll = positionInLinearLayout + expandableView.getIntrinsicHeight();
+        if (ANCHOR_SCROLLING) {
+            // TODO
+        } else {
+            int positionInLinearLayout = getPositionInLinearLayout(v);
+            int targetScroll = targetScrollForView(expandableView, positionInLinearLayout);
+            int outOfViewScroll = positionInLinearLayout + expandableView.getIntrinsicHeight();
 
-        // Only apply the scroll if we're scrolling the view upwards, or the view is so far up
-        // that it is not visible anymore.
-        if (mOwnScrollY < targetScroll || outOfViewScroll < mOwnScrollY) {
-            mScroller.startScroll(mScrollX, mOwnScrollY, 0, targetScroll - mOwnScrollY);
-            mDontReportNextOverScroll = true;
-            animateScroll();
-            return true;
+            // Only apply the scroll if we're scrolling the view upwards, or the view is so far up
+            // that it is not visible anymore.
+            if (mOwnScrollY < targetScroll || outOfViewScroll < mOwnScrollY) {
+                mScroller.startScroll(mScrollX, mOwnScrollY, 0, targetScroll - mOwnScrollY);
+                mDontReportNextOverScroll = true;
+                animateScroll();
+                return true;
+            }
         }
         return false;
     }
@@ -1477,16 +1542,20 @@
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         mBottomInset = insets.getSystemWindowInsetBottom();
 
-        int range = getScrollRange();
-        if (mOwnScrollY > range) {
-            // HACK: We're repeatedly getting staggered insets here while the IME is
-            // animating away. To work around that we'll wait until things have settled.
-            removeCallbacks(mReclamp);
-            postDelayed(mReclamp, 50);
-        } else if (mForcedScroll != null) {
-            // The scroll was requested before we got the actual inset - in case we need
-            // to scroll up some more do so now.
-            scrollTo(mForcedScroll);
+        if (ANCHOR_SCROLLING) {
+            // TODO
+        } else {
+            int range = getScrollRange();
+            if (mOwnScrollY > range) {
+                // HACK: We're repeatedly getting staggered insets here while the IME is
+                // animating away. To work around that we'll wait until things have settled.
+                removeCallbacks(mReclamp);
+                postDelayed(mReclamp, 50);
+            } else if (mForcedScroll != null) {
+                // The scroll was requested before we got the actual inset - in case we need
+                // to scroll up some more do so now.
+                scrollTo(mForcedScroll);
+            }
         }
         return insets;
     }
@@ -1495,8 +1564,12 @@
     private Runnable mReclamp = new Runnable() {
         @Override
         public void run() {
-            int range = getScrollRange();
-            mScroller.startScroll(mScrollX, mOwnScrollY, 0, range - mOwnScrollY);
+            if (ANCHOR_SCROLLING) {
+                // TODO
+            } else {
+                int range = getScrollRange();
+                mScroller.startScroll(mScrollX, mOwnScrollY, 0, range - mOwnScrollY);
+            }
             mDontReportNextOverScroll = true;
             mDontClampNextScroll = true;
             animateScroll();
@@ -1541,9 +1614,8 @@
                 true /* isDismissAll */);
     }
 
-    @Override
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-    public void snapViewIfNeeded(NotificationData.Entry entry) {
+    private void snapViewIfNeeded(NotificationEntry entry) {
         ExpandableNotificationRow child = entry.getRow();
         boolean animate = mIsExpanded || isPinnedHeadsUp(child);
         // If the child is showing the notification menu snap to that
@@ -1553,7 +1625,7 @@
 
     @Override
     @ShadeViewRefactor(RefactorComponent.ADAPTER)
-    public ViewGroup getViewParentForNotification(NotificationData.Entry entry) {
+    public ViewGroup getViewParentForNotification(NotificationEntry entry) {
         return this;
     }
 
@@ -1575,20 +1647,39 @@
         }
         // Top overScroll might not grab all scrolling motion,
         // we have to scroll as well.
-        float scrollAmount = newTopAmount < 0 ? -newTopAmount : 0.0f;
-        float newScrollY = mOwnScrollY + scrollAmount;
-        if (newScrollY > range) {
-            if (!mExpandedInThisMotion) {
-                float currentBottomPixels = getCurrentOverScrolledPixels(false);
-                // We overScroll on the top
-                setOverScrolledPixels(currentBottomPixels + newScrollY - range,
-                        false /* onTop */,
-                        false /* animate */);
+        if (ANCHOR_SCROLLING) {
+            float scrollAmount = newTopAmount < 0 ? -newTopAmount : 0.0f;
+            // TODO: once we're recycling this will need to check the adapter position of the child
+            ExpandableView lastRow = getLastRowNotGone();
+            if (lastRow != null && !lastRow.isInShelf()) {
+                float distanceToMax = Math.max(0, getMaxPositiveScrollAmount());
+                if (scrollAmount > distanceToMax) {
+                    float currentBottomPixels = getCurrentOverScrolledPixels(false);
+                    // We overScroll on the bottom
+                    setOverScrolledPixels(currentBottomPixels + (scrollAmount - distanceToMax),
+                            false /* onTop */,
+                            false /* animate */);
+                    mScrollAnchorViewY -= distanceToMax;
+                    scrollAmount = 0f;
+                }
             }
-            setOwnScrollY(range);
-            scrollAmount = 0.0f;
+            return scrollAmount;
+        } else {
+            float scrollAmount = newTopAmount < 0 ? -newTopAmount : 0.0f;
+            float newScrollY = mOwnScrollY + scrollAmount;
+            if (newScrollY > range) {
+                if (!mExpandedInThisMotion) {
+                    float currentBottomPixels = getCurrentOverScrolledPixels(false);
+                    // We overScroll on the bottom
+                    setOverScrolledPixels(currentBottomPixels + newScrollY - range,
+                            false /* onTop */,
+                            false /* animate */);
+                }
+                setOwnScrollY(range);
+                scrollAmount = 0.0f;
+            }
+            return scrollAmount;
         }
-        return scrollAmount;
     }
 
     /**
@@ -1609,18 +1700,37 @@
         }
         // Bottom overScroll might not grab all scrolling motion,
         // we have to scroll as well.
-        float scrollAmount = newBottomAmount < 0 ? newBottomAmount : 0.0f;
-        float newScrollY = mOwnScrollY + scrollAmount;
-        if (newScrollY < 0) {
-            float currentTopPixels = getCurrentOverScrolledPixels(true);
-            // We overScroll on the top
-            setOverScrolledPixels(currentTopPixels - newScrollY,
-                    true /* onTop */,
-                    false /* animate */);
-            setOwnScrollY(0);
-            scrollAmount = 0.0f;
+        if (ANCHOR_SCROLLING) {
+            float scrollAmount = newBottomAmount < 0 ? newBottomAmount : 0.0f;
+            // TODO: once we're recycling this will need to check the adapter position of the child
+            ExpandableView firstChild = getFirstChildNotGone();
+            float top = firstChild.getTranslationY();
+            float distanceToTop = mScrollAnchorView.getTranslationY() - top - mScrollAnchorViewY;
+            if (distanceToTop < -scrollAmount) {
+                float currentTopPixels = getCurrentOverScrolledPixels(true);
+                // We overScroll on the top
+                setOverScrolledPixels(currentTopPixels + (-scrollAmount - distanceToTop),
+                        true /* onTop */,
+                        false /* animate */);
+                mScrollAnchorView = firstChild;
+                mScrollAnchorViewY = 0;
+                scrollAmount = 0f;
+            }
+            return scrollAmount;
+        } else {
+            float scrollAmount = newBottomAmount < 0 ? newBottomAmount : 0.0f;
+            float newScrollY = mOwnScrollY + scrollAmount;
+            if (newScrollY < 0) {
+                float currentTopPixels = getCurrentOverScrolledPixels(true);
+                // We overScroll on the top
+                setOverScrolledPixels(currentTopPixels - newScrollY,
+                        true /* onTop */,
+                        false /* animate */);
+                setOwnScrollY(0);
+                scrollAmount = 0.0f;
+            }
+            return scrollAmount;
         }
-        return scrollAmount;
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -1655,26 +1765,43 @@
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     private void animateScroll() {
         if (mScroller.computeScrollOffset()) {
-            int oldY = mOwnScrollY;
-            int y = mScroller.getCurrY();
-
-            if (oldY != y) {
-                int range = getScrollRange();
-                if (y < 0 && oldY >= 0 || y > range && oldY <= range) {
-                    float currVelocity = mScroller.getCurrVelocity();
-                    if (currVelocity >= mMinimumVelocity) {
-                        mMaxOverScroll = Math.abs(currVelocity) / 1000 * mOverflingDistance;
+            if (ANCHOR_SCROLLING) {
+                int oldY = mLastScrollerY;
+                int y = mScroller.getCurrY();
+                int deltaY = y - oldY;
+                if (deltaY != 0) {
+                    int maxNegativeScrollAmount = getMaxNegativeScrollAmount();
+                    int maxPositiveScrollAmount = getMaxPositiveScrollAmount();
+                    if ((maxNegativeScrollAmount < 0 && deltaY < maxNegativeScrollAmount)
+                            || (maxPositiveScrollAmount > 0 && deltaY > maxPositiveScrollAmount)) {
+                        // This frame takes us into overscroll, so set the max overscroll based on
+                        // the current velocity
+                        setMaxOverScrollFromCurrentVelocity();
                     }
+                    customOverScrollBy(deltaY, oldY, 0, (int) mMaxOverScroll);
+                    mLastScrollerY = y;
                 }
+            } else {
+                int oldY = mOwnScrollY;
+                int y = mScroller.getCurrY();
 
-                if (mDontClampNextScroll) {
-                    range = Math.max(range, oldY);
+                if (oldY != y) {
+                    int range = getScrollRange();
+                    if (y < 0 && oldY >= 0 || y > range && oldY <= range) {
+                        // This frame takes us into overscroll, so set the max overscroll based on
+                        // the current velocity
+                        setMaxOverScrollFromCurrentVelocity();
+                    }
+
+                    if (mDontClampNextScroll) {
+                        range = Math.max(range, oldY);
+                    }
+                    customOverScrollBy(y - oldY, oldY, range,
+                            (int) (mMaxOverScroll));
                 }
-                customOverScrollBy(y - oldY, oldY, range,
-                        (int) (mMaxOverScroll));
             }
 
-            postOnAnimation(mAnimateScroll);
+            postOnAnimation(mReflingAndAnimateScroll);
         } else {
             mDontClampNextScroll = false;
             if (mFinishScrollingCallback != null) {
@@ -1683,26 +1810,67 @@
         }
     }
 
-    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-    private boolean customOverScrollBy(int deltaY, int scrollY, int scrollRangeY,
-            int maxOverScrollY) {
-
-        int newScrollY = scrollY + deltaY;
-        final int top = -maxOverScrollY;
-        final int bottom = maxOverScrollY + scrollRangeY;
-
-        boolean clampedY = false;
-        if (newScrollY > bottom) {
-            newScrollY = bottom;
-            clampedY = true;
-        } else if (newScrollY < top) {
-            newScrollY = top;
-            clampedY = true;
+    private void setMaxOverScrollFromCurrentVelocity() {
+        float currVelocity = mScroller.getCurrVelocity();
+        if (currVelocity >= mMinimumVelocity) {
+            mMaxOverScroll = Math.abs(currVelocity) / 1000 * mOverflingDistance;
         }
+    }
 
-        onCustomOverScrolled(newScrollY, clampedY);
+    /**
+     * Scrolls by the given delta, overscrolling if needed.  If called during a fling and the delta
+     * would cause us to exceed the provided maximum overscroll, springs back instead.
+     *
+     * This method performs the determination of whether we're exceeding the overscroll and clamps
+     * the scroll amount if so.  The actual scrolling/overscrolling happens in
+     * {@link #onCustomOverScrolled(int, boolean)} (absolute scrolling) or
+     * {@link #onCustomOverScrolledBy(int, boolean)} (anchor scrolling).
+     *
+     * @param deltaY         The (signed) number of pixels to scroll.
+     * @param scrollY        The current scroll position (absolute scrolling only).
+     * @param scrollRangeY   The maximum allowable scroll position (absolute scrolling only).
+     * @param maxOverScrollY The current (unsigned) limit on number of pixels to overscroll by.
+     */
+    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+    private void customOverScrollBy(int deltaY, int scrollY, int scrollRangeY, int maxOverScrollY) {
+        if (ANCHOR_SCROLLING) {
+            boolean clampedY = false;
+            if (deltaY < 0) {
+                int maxScrollAmount = getMaxNegativeScrollAmount();
+                if (maxScrollAmount > Integer.MIN_VALUE) {
+                    maxScrollAmount -= maxOverScrollY;
+                    if (deltaY < maxScrollAmount) {
+                        deltaY = maxScrollAmount;
+                        clampedY = true;
+                    }
+                }
+            } else {
+                int maxScrollAmount = getMaxPositiveScrollAmount();
+                if (maxScrollAmount < Integer.MAX_VALUE) {
+                    maxScrollAmount += maxOverScrollY;
+                    if (deltaY > maxScrollAmount) {
+                        deltaY = maxScrollAmount;
+                        clampedY = true;
+                    }
+                }
+            }
+            onCustomOverScrolledBy(deltaY, clampedY);
+        } else {
+            int newScrollY = scrollY + deltaY;
+            final int top = -maxOverScrollY;
+            final int bottom = maxOverScrollY + scrollRangeY;
 
-        return clampedY;
+            boolean clampedY = false;
+            if (newScrollY > bottom) {
+                newScrollY = bottom;
+                clampedY = true;
+            } else if (newScrollY < top) {
+                newScrollY = top;
+                clampedY = true;
+            }
+
+            onCustomOverScrolled(newScrollY, clampedY);
+        }
     }
 
     /**
@@ -1820,8 +1988,46 @@
         }
     }
 
+    /**
+     * Scrolls by the given delta, overscrolling if needed.  If called during a fling and the delta
+     * would cause us to exceed the provided maximum overscroll, springs back instead.
+     *
+     * @param deltaY   The (signed) number of pixels to scroll.
+     * @param clampedY Whether this value was clamped by the calling method, meaning we've reached
+     *                 the overscroll limit.
+     */
+    private void onCustomOverScrolledBy(int deltaY, boolean clampedY) {
+        assert ANCHOR_SCROLLING;
+        mScrollAnchorViewY -= deltaY;
+        // Treat animating scrolls differently; see #computeScroll() for why.
+        if (!mScroller.isFinished()) {
+            if (clampedY) {
+                springBack();
+            } else {
+                float overScrollTop = getCurrentOverScrollAmount(true /* top */);
+                if (isScrolledToTop() && mScrollAnchorViewY > 0) {
+                    notifyOverscrollTopListener(mScrollAnchorViewY,
+                            isRubberbanded(true /* onTop */));
+                } else {
+                    notifyOverscrollTopListener(overScrollTop, isRubberbanded(true /* onTop */));
+                }
+            }
+        }
+        updateScrollAnchor();
+        updateOnScrollChange();
+    }
+
+    /**
+     * Scrolls to the given position, overscrolling if needed.  If called during a fling and the
+     * position exceeds the provided maximum overscroll, springs back instead.
+     *
+     * @param scrollY The target scroll position.
+     * @param clampedY Whether this value was clamped by the calling method, meaning we've reached
+     *                 the overscroll limit.
+     */
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     private void onCustomOverScrolled(int scrollY, boolean clampedY) {
+        assert !ANCHOR_SCROLLING;
         // Treat animating scrolls differently; see #computeScroll() for why.
         if (!mScroller.isFinished()) {
             setOwnScrollY(scrollY);
@@ -1840,27 +2046,51 @@
         }
     }
 
+    /**
+     * Springs back from an overscroll by stopping the {@link #mScroller} and animating the
+     * overscroll amount back to zero.
+     */
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     private void springBack() {
-        int scrollRange = getScrollRange();
-        boolean overScrolledTop = mOwnScrollY <= 0;
-        boolean overScrolledBottom = mOwnScrollY >= scrollRange;
-        if (overScrolledTop || overScrolledBottom) {
-            boolean onTop;
-            float newAmount;
-            if (overScrolledTop) {
-                onTop = true;
-                newAmount = -mOwnScrollY;
-                setOwnScrollY(0);
-                mDontReportNextOverScroll = true;
-            } else {
-                onTop = false;
-                newAmount = mOwnScrollY - scrollRange;
-                setOwnScrollY(scrollRange);
+        if (ANCHOR_SCROLLING) {
+            boolean overScrolledTop = isScrolledToTop() && mScrollAnchorViewY > 0;
+            int maxPositiveScrollAmount = getMaxPositiveScrollAmount();
+            boolean overscrolledBottom = maxPositiveScrollAmount < 0;
+            if (overScrolledTop || overscrolledBottom) {
+                float newAmount;
+                if (overScrolledTop) {
+                    newAmount = mScrollAnchorViewY;
+                    mScrollAnchorViewY = 0;
+                    mDontReportNextOverScroll = true;
+                } else {
+                    newAmount = -maxPositiveScrollAmount;
+                    mScrollAnchorViewY -= maxPositiveScrollAmount;
+                }
+                setOverScrollAmount(newAmount, overScrolledTop, false);
+                setOverScrollAmount(0.0f, overScrolledTop, true);
+                mScroller.forceFinished(true);
             }
-            setOverScrollAmount(newAmount, onTop, false);
-            setOverScrollAmount(0.0f, onTop, true);
-            mScroller.forceFinished(true);
+        } else {
+            int scrollRange = getScrollRange();
+            boolean overScrolledTop = mOwnScrollY <= 0;
+            boolean overScrolledBottom = mOwnScrollY >= scrollRange;
+            if (overScrolledTop || overScrolledBottom) {
+                boolean onTop;
+                float newAmount;
+                if (overScrolledTop) {
+                    onTop = true;
+                    newAmount = -mOwnScrollY;
+                    setOwnScrollY(0);
+                    mDontReportNextOverScroll = true;
+                } else {
+                    onTop = false;
+                    newAmount = mOwnScrollY - scrollRange;
+                    setOwnScrollY(scrollRange);
+                }
+                setOverScrollAmount(newAmount, onTop, false);
+                setOverScrollAmount(0.0f, onTop, true);
+                mScroller.forceFinished(true);
+            }
         }
     }
 
@@ -1965,6 +2195,17 @@
         return null;
     }
 
+    private ExpandableNotificationRow getLastRowNotGone() {
+        int childCount = getChildCount();
+        for (int i = childCount - 1; i >= 0; i--) {
+            View child = getChildAt(i);
+            if (child instanceof ExpandableNotificationRow && child.getVisibility() != View.GONE) {
+                return (ExpandableNotificationRow) child;
+            }
+        }
+        return null;
+    }
+
     /**
      * @return the number of children which have visibility unequal to GONE
      */
@@ -2046,17 +2287,14 @@
         }
         mIntrinsicContentHeight = height;
 
-        // We don't want to use the toppadding since that might be interpolated and we want
-        // to take the final value of the animation.
-        int topPadding = mAmbientState.isFullyDark() ? mDarkTopPadding : mRegularTopPadding;
-        mContentHeight = height + topPadding + mBottomMargin;
+        mContentHeight = height + mTopPadding + mBottomMargin;
         updateScrollability();
         clampScrollPosition();
         mAmbientState.setLayoutMaxHeight(mContentHeight);
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    private boolean isPulsing(NotificationData.Entry entry) {
+    private boolean isPulsing(NotificationEntry entry) {
         return mAmbientState.isPulsing(entry);
     }
 
@@ -2078,8 +2316,8 @@
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     private void updateForwardAndBackwardScrollability() {
-        boolean forwardScrollable = mScrollable && mOwnScrollY < getScrollRange();
-        boolean backwardsScrollable = mScrollable && mOwnScrollY > 0;
+        boolean forwardScrollable = mScrollable && !isScrolledToBottom();
+        boolean backwardsScrollable = mScrollable && !isScrolledToTop();
         boolean changed = forwardScrollable != mForwardScrollable
                 || backwardsScrollable != mBackwardScrollable;
         mForwardScrollable = forwardScrollable;
@@ -2213,13 +2451,16 @@
         int top = 0;
         if (section != null) {
             ActivatableNotificationView firstView = section.getFirstVisibleChild();
-            // Round Y up to avoid seeing the background during animation
-            int finalTranslationY = (int) Math.ceil(ViewState.getFinalTranslationY(firstView));
-            if (alreadyAnimating || section.isTargetTop(finalTranslationY)) {
-                // we're ending up at the same location as we are now, let's just skip the animation
-                top = finalTranslationY;
-            } else {
-                top = (int) Math.ceil(firstView.getTranslationY());
+            if (firstView != null) {
+                // Round Y up to avoid seeing the background during animation
+                int finalTranslationY = (int) Math.ceil(ViewState.getFinalTranslationY(firstView));
+                if (alreadyAnimating || section.isTargetTop(finalTranslationY)) {
+                    // we're ending up at the same location as we are now, let's just skip the
+                    // animation
+                    top = finalTranslationY;
+                } else {
+                    top = (int) Math.ceil(firstView.getTranslationY());
+                }
             }
         }
         return top;
@@ -2397,18 +2638,24 @@
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     protected void fling(int velocityY) {
         if (getChildCount() > 0) {
-            int scrollRange = getScrollRange();
-
             float topAmount = getCurrentOverScrollAmount(true);
             float bottomAmount = getCurrentOverScrollAmount(false);
             if (velocityY < 0 && topAmount > 0) {
-                setOwnScrollY(mOwnScrollY - (int) topAmount);
+                if (ANCHOR_SCROLLING) {
+                    mScrollAnchorViewY += topAmount;
+                } else {
+                    setOwnScrollY(mOwnScrollY - (int) topAmount);
+                }
                 mDontReportNextOverScroll = true;
                 setOverScrollAmount(0, true, false);
                 mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor(true /* onTop */)
                         * mOverflingDistance + topAmount;
             } else if (velocityY > 0 && bottomAmount > 0) {
-                setOwnScrollY((int) (mOwnScrollY + bottomAmount));
+                if (ANCHOR_SCROLLING) {
+                    mScrollAnchorViewY -= bottomAmount;
+                } else {
+                    setOwnScrollY((int) (mOwnScrollY + bottomAmount));
+                }
                 setOverScrollAmount(0, false, false);
                 mMaxOverScroll = Math.abs(velocityY) / 1000f
                         * getRubberBandFactor(false /* onTop */) * mOverflingDistance
@@ -2417,18 +2664,138 @@
                 // it will be set once we reach the boundary
                 mMaxOverScroll = 0.0f;
             }
-            int minScrollY = Math.max(0, scrollRange);
-            if (mExpandedInThisMotion) {
-                minScrollY = Math.min(minScrollY, mMaxScrollAfterExpand);
+            if (ANCHOR_SCROLLING) {
+                flingScroller(velocityY);
+            } else {
+                int scrollRange = getScrollRange();
+                int minScrollY = Math.max(0, scrollRange);
+                if (mExpandedInThisMotion) {
+                    minScrollY = Math.min(minScrollY, mMaxScrollAfterExpand);
+                }
+                mScroller.fling(mScrollX, mOwnScrollY, 1, velocityY, 0, 0, 0, minScrollY, 0,
+                        mExpandedInThisMotion && mOwnScrollY >= 0 ? 0 : Integer.MAX_VALUE / 2);
             }
-            mScroller.fling(mScrollX, mOwnScrollY, 1, velocityY, 0, 0, 0, minScrollY, 0,
-                    mExpandedInThisMotion && mOwnScrollY >= 0 ? 0 : Integer.MAX_VALUE / 2);
 
             animateScroll();
         }
     }
 
     /**
+     * Flings the overscroller with the given velocity (anchor-based scrolling).
+     *
+     * Because anchor-based scrolling can't track the current scroll position, the overscroller is
+     * always started at startY = 0, and we interpret the positions it computes as relative to the
+     * start of the scroll.
+     */
+    private void flingScroller(int velocityY) {
+        assert ANCHOR_SCROLLING;
+        mIsScrollerBoundSet = false;
+        maybeFlingScroller(velocityY, true /* always fling */);
+    }
+
+    private void maybeFlingScroller(int velocityY, boolean alwaysFling) {
+        assert ANCHOR_SCROLLING;
+        // Attempt to determine the maximum amount to scroll before we reach the end.
+        // If the first view is not materialized (for an upwards scroll) or the last view is either
+        // not materialized or is pinned to the shade (for a downwards scroll), we don't know this
+        // amount, so we do an unbounded fling and rely on {@link #maybeReflingScroller()} to update
+        // the scroller once we approach the start/end of the list.
+        int minY = Integer.MIN_VALUE;
+        int maxY = Integer.MAX_VALUE;
+        if (velocityY < 0) {
+            minY = getMaxNegativeScrollAmount();
+            if (minY > Integer.MIN_VALUE) {
+                mIsScrollerBoundSet = true;
+            }
+        } else {
+            maxY = getMaxPositiveScrollAmount();
+            if (maxY < Integer.MAX_VALUE) {
+                mIsScrollerBoundSet = true;
+            }
+        }
+        if (mIsScrollerBoundSet || alwaysFling) {
+            mLastScrollerY = 0;
+            // x velocity is set to 1 to avoid overscroller bug
+            mScroller.fling(0, 0, 1, velocityY, 0, 0, minY, maxY, 0,
+                    mExpandedInThisMotion && !isScrolledToTop() ? 0 : Integer.MAX_VALUE / 2);
+        }
+    }
+
+    /**
+     * Returns the maximum number of pixels we can scroll in the positive direction (downwards)
+     * before reaching the bottom of the list (discounting overscroll).
+     *
+     * If the return value is negative then we have overscrolled; this is a transient state which
+     * should immediately be handled by adjusting the anchor position and adding the extra space to
+     * the bottom overscroll amount.
+     *
+     * If we don't know how many pixels we have left to scroll (because the last row has not been
+     * materialized, or it's in the shelf so it doesn't have its "natural" position), we return
+     * {@link Integer#MAX_VALUE}.
+     */
+    private int getMaxPositiveScrollAmount() {
+        assert ANCHOR_SCROLLING;
+        // TODO: once we're recycling we need to check the adapter position of the last child.
+        ExpandableNotificationRow lastRow = getLastRowNotGone();
+        if (mScrollAnchorView != null && lastRow != null && !lastRow.isInShelf()) {
+            // distance from bottom of last child to bottom of notifications area is:
+            // distance from bottom of last child
+            return (int) (lastRow.getTranslationY() + lastRow.getActualHeight()
+                    // to top of anchor view
+                    - mScrollAnchorView.getTranslationY()
+                    // plus distance from anchor view to top of notifications area
+                    + mScrollAnchorViewY
+                    // minus height of notifications area.
+                    - (mMaxLayoutHeight - getIntrinsicPadding() - mFooterView.getActualHeight()));
+        } else {
+            return Integer.MAX_VALUE;
+        }
+    }
+
+    /**
+     * Returns the maximum number of pixels (as a negative number) we can scroll in the negative
+     * direction (upwards) before reaching the top of the list (discounting overscroll).
+     *
+     * If the return value is positive then we have overscrolled; this is a transient state which
+     * should immediately be handled by adjusting the anchor position and adding the extra space to
+     * the top overscroll amount.
+     *
+     * If we don't know how many pixels we have left to scroll (because the first row has not been
+     * materialized), we return {@link Integer#MIN_VALUE}.
+     */
+    private int getMaxNegativeScrollAmount() {
+        assert ANCHOR_SCROLLING;
+        // TODO: once we're recycling we need to check the adapter position of the first child.
+        ExpandableView firstChild = getFirstChildNotGone();
+        if (mScrollAnchorView != null && firstChild != null) {
+            // distance from top of first child to top of notifications area is:
+            // distance from top of anchor view
+            return (int) -(mScrollAnchorView.getTranslationY()
+                    // to top of first child
+                    - firstChild.getTranslationY()
+                    // minus distance from top of anchor view to top of notifications area.
+                    - mScrollAnchorViewY);
+        } else {
+            return Integer.MIN_VALUE;
+        }
+    }
+
+    /**
+     * During a fling, if we were unable to set the bounds of the fling due to the top/bottom view
+     * not being materialized or being pinned to the shelf, we need to check on every frame if we're
+     * able to set the bounds.  If we are, we fling the scroller again with the newly computed
+     * bounds.
+     */
+    private void maybeReflingScroller() {
+        if (!mIsScrollerBoundSet) {
+            // Because mScroller is a flywheel scroller, we fling with the minimum possible
+            // velocity to establish direction, so as not to perceptibly affect the velocity.
+            maybeFlingScroller((int) Math.signum(mScroller.getCurrVelocity()),
+                    false /* alwaysFling */);
+        }
+    }
+
+    /**
      * @return Whether a fling performed on the top overscroll edge lead to the expanded
      * overScroll view (i.e QS).
      */
@@ -2479,25 +2846,10 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
-    public int getFirstChildIntrinsicHeight() {
-        final ExpandableView firstChild = getFirstChildNotGone();
-        int firstChildMinHeight = firstChild != null
-                ? firstChild.getIntrinsicHeight()
-                : mEmptyShadeView != null
-                        ? mEmptyShadeView.getIntrinsicHeight()
-                        : mCollapsedSize;
-        if (mOwnScrollY > 0) {
-            firstChildMinHeight = Math.max(firstChildMinHeight - mOwnScrollY, mCollapsedSize);
-        }
-        return firstChildMinHeight;
-    }
-
-    @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     public float getTopPaddingOverflow() {
         return mTopPaddingOverflow;
     }
 
-
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     public int getPeekHeight() {
         final ExpandableView firstChild = getFirstChildNotGone();
@@ -2561,7 +2913,7 @@
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     @Override
-    public void cleanUpViewStateForEntry(NotificationData.Entry entry) {
+    public void cleanUpViewStateForEntry(NotificationEntry entry) {
         View child = entry.getRow();
         if (child == mSwipeHelper.getTranslatingParentView()) {
             mSwipeHelper.clearTranslatingParentView();
@@ -2689,7 +3041,7 @@
     private boolean isChildInInvisibleGroup(View child) {
         if (child instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            NotificationData.Entry groupSummary =
+            NotificationEntry groupSummary =
                     mGroupManager.getGroupSummary(row.getStatusBarNotification());
             if (groupSummary != null && groupSummary.getRow() != row) {
                 return row.getVisibility() == View.INVISIBLE;
@@ -2705,30 +3057,51 @@
      */
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     private void updateScrollStateForRemovedChild(ExpandableView removedChild) {
-        int startingPosition = getPositionInLinearLayout(removedChild);
-        float increasedPaddingAmount = removedChild.getIncreasedPaddingAmount();
-        int padding;
-        if (increasedPaddingAmount >= 0) {
-            padding = (int) NotificationUtils.interpolate(
-                    mPaddingBetweenElements,
-                    mIncreasedPaddingBetweenElements,
-                    increasedPaddingAmount);
+        if (ANCHOR_SCROLLING) {
+            if (removedChild == mScrollAnchorView) {
+                ExpandableView firstChild = getFirstChildNotGone();
+                if (firstChild != null) {
+                    mScrollAnchorView = firstChild;
+                } else {
+                    mScrollAnchorView = mShelf;
+                }
+                // Adjust anchor view Y by the distance between the old and new anchors
+                // so that there's no visible change.
+                mScrollAnchorViewY +=
+                        mScrollAnchorView.getTranslationY() - removedChild.getTranslationY();
+            }
+            updateScrollAnchor();
+            // TODO: once we're recycling this will need to check the adapter position of the child
+            if (mScrollAnchorView == getFirstChildNotGone() && mScrollAnchorViewY > 0) {
+                mScrollAnchorViewY = 0;
+            }
+            updateOnScrollChange();
         } else {
-            padding = (int) NotificationUtils.interpolate(
-                    0,
-                    mPaddingBetweenElements,
-                    1.0f + increasedPaddingAmount);
-        }
-        int childHeight = getIntrinsicHeight(removedChild) + padding;
-        int endPosition = startingPosition + childHeight;
-        if (endPosition <= mOwnScrollY) {
-            // This child is fully scrolled of the top, so we have to deduct its height from the
-            // scrollPosition
-            setOwnScrollY(mOwnScrollY - childHeight);
-        } else if (startingPosition < mOwnScrollY) {
-            // This child is currently being scrolled into, set the scroll position to the start of
-            // this child
-            setOwnScrollY(startingPosition);
+            int startingPosition = getPositionInLinearLayout(removedChild);
+            float increasedPaddingAmount = removedChild.getIncreasedPaddingAmount();
+            int padding;
+            if (increasedPaddingAmount >= 0) {
+                padding = (int) NotificationUtils.interpolate(
+                        mPaddingBetweenElements,
+                        mIncreasedPaddingBetweenElements,
+                        increasedPaddingAmount);
+            } else {
+                padding = (int) NotificationUtils.interpolate(
+                        0,
+                        mPaddingBetweenElements,
+                        1.0f + increasedPaddingAmount);
+            }
+            int childHeight = getIntrinsicHeight(removedChild) + padding;
+            int endPosition = startingPosition + childHeight;
+            if (endPosition <= mOwnScrollY) {
+                // This child is fully scrolled of the top, so we have to deduct its height from the
+                // scrollPosition
+                setOwnScrollY(mOwnScrollY - childHeight);
+            } else if (startingPosition < mOwnScrollY) {
+                // This child is currently being scrolled into, set the scroll position to the
+                // start of this child
+                setOwnScrollY(startingPosition);
+            }
         }
     }
 
@@ -2882,6 +3255,14 @@
         generateAddAnimation(child, false /* fromMoreCard */);
         updateAnimationState(child);
         updateChronometerForChild(child);
+        if (ANCHOR_SCROLLING) {
+            // TODO: once we're recycling this will need to check the adapter position of the child
+            if (child == getFirstChildNotGone() && (isScrolledToTop() || !mIsExpanded)) {
+                // New child was added at the top while we're scrolled to the top;
+                // make it the new anchor view so that we stay at the top.
+                mScrollAnchorView = child;
+            }
+        }
     }
 
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
@@ -3375,17 +3756,24 @@
                         final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
                         if (vscroll != 0) {
                             final int delta = (int) (vscroll * getVerticalScrollFactor());
-                            final int range = getScrollRange();
-                            int oldScrollY = mOwnScrollY;
-                            int newScrollY = oldScrollY - delta;
-                            if (newScrollY < 0) {
-                                newScrollY = 0;
-                            } else if (newScrollY > range) {
-                                newScrollY = range;
-                            }
-                            if (newScrollY != oldScrollY) {
-                                setOwnScrollY(newScrollY);
-                                return true;
+                            if (ANCHOR_SCROLLING) {
+                                mScrollAnchorViewY -= delta;
+                                updateScrollAnchor();
+                                clampScrollPosition();
+                                updateOnScrollChange();
+                            } else {
+                                final int range = getScrollRange();
+                                int oldScrollY = mOwnScrollY;
+                                int newScrollY = oldScrollY - delta;
+                                if (newScrollY < 0) {
+                                    newScrollY = 0;
+                                } else if (newScrollY > range) {
+                                    newScrollY = range;
+                                }
+                                if (newScrollY != oldScrollY) {
+                                    setOwnScrollY(newScrollY);
+                                    return true;
+                                }
                             }
                         }
                     }
@@ -3453,12 +3841,16 @@
                 if (mIsBeingDragged) {
                     // Scroll to follow the motion event
                     mLastMotionY = y;
-                    int range = getScrollRange();
-                    if (mExpandedInThisMotion) {
-                        range = Math.min(range, mMaxScrollAfterExpand);
-                    }
-
                     float scrollAmount;
+                    int range;
+                    if (ANCHOR_SCROLLING) {
+                        range = 0;  // unused in the methods it's being passed to
+                    } else {
+                        range = getScrollRange();
+                        if (mExpandedInThisMotion) {
+                            range = Math.min(range, mMaxScrollAfterExpand);
+                        }
+                    }
                     if (deltaY < 0) {
                         scrollAmount = overScrollDown(deltaY);
                     } else {
@@ -3495,9 +3887,13 @@
                                     onOverScrollFling(false, initialVelocity);
                                 }
                             } else {
-                                if (mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0,
-                                        getScrollRange())) {
-                                    animateScroll();
+                                if (ANCHOR_SCROLLING) {
+                                    // TODO
+                                } else {
+                                    if (mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0,
+                                            getScrollRange())) {
+                                        animateScroll();
+                                    }
                                 }
                             }
                         }
@@ -3509,8 +3905,13 @@
                 break;
             case MotionEvent.ACTION_CANCEL:
                 if (mIsBeingDragged && getChildCount() > 0) {
-                    if (mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0, getScrollRange())) {
-                        animateScroll();
+                    if (ANCHOR_SCROLLING) {
+                        // TODO
+                    } else {
+                        if (mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0,
+                                getScrollRange())) {
+                            animateScroll();
+                        }
                     }
                     mActivePointerId = INVALID_POINTER;
                     endDrag();
@@ -3579,12 +3980,6 @@
         }
     }
 
-    @ShadeViewRefactor(RefactorComponent.INPUT)
-    private void transformTouchEvent(MotionEvent ev, View sourceView, View targetView) {
-        ev.offsetLocation(sourceView.getX(), sourceView.getY());
-        ev.offsetLocation(-targetView.getX(), -targetView.getY());
-    }
-
     @Override
     @ShadeViewRefactor(RefactorComponent.INPUT)
     public boolean onInterceptTouchEvent(MotionEvent ev) {
@@ -3757,8 +4152,12 @@
                 setIsBeingDragged(false);
                 mActivePointerId = INVALID_POINTER;
                 recycleVelocityTracker();
-                if (mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0, getScrollRange())) {
-                    animateScroll();
+                if (ANCHOR_SCROLLING) {
+                    // TODO
+                } else {
+                    if (mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0, getScrollRange())) {
+                        animateScroll();
+                    }
                 }
                 break;
             case MotionEvent.ACTION_POINTER_UP:
@@ -3833,14 +4232,20 @@
             case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
                 // fall through
             case android.R.id.accessibilityActionScrollUp:
-                final int viewportHeight = getHeight() - mPaddingBottom - mTopPadding - mPaddingTop
-                        - mShelf.getIntrinsicHeight();
-                final int targetScrollY = Math.max(0,
-                        Math.min(mOwnScrollY + direction * viewportHeight, getScrollRange()));
-                if (targetScrollY != mOwnScrollY) {
-                    mScroller.startScroll(mScrollX, mOwnScrollY, 0, targetScrollY - mOwnScrollY);
-                    animateScroll();
-                    return true;
+                if (ANCHOR_SCROLLING) {
+                    // TODO
+                } else {
+                    final int viewportHeight =
+                            getHeight() - mPaddingBottom - mTopPadding - mPaddingTop
+                                    - mShelf.getIntrinsicHeight();
+                    final int targetScrollY = Math.max(0,
+                            Math.min(mOwnScrollY + direction * viewportHeight, getScrollRange()));
+                    if (targetScrollY != mOwnScrollY) {
+                        mScroller.startScroll(mScrollX, mOwnScrollY, 0,
+                                targetScrollY - mOwnScrollY);
+                        animateScroll();
+                        return true;
+                    }
                 }
                 break;
         }
@@ -3899,13 +4304,23 @@
     @Override
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     public boolean isScrolledToTop() {
-        return mOwnScrollY == 0;
+        if (ANCHOR_SCROLLING) {
+            updateScrollAnchor();
+            // TODO: once we're recycling this will need to check the adapter position of the child
+            return mScrollAnchorView == getFirstChildNotGone() && mScrollAnchorViewY >= 0;
+        } else {
+            return mOwnScrollY == 0;
+        }
     }
 
     @Override
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     public boolean isScrolledToBottom() {
-        return mOwnScrollY >= getScrollRange();
+        if (ANCHOR_SCROLLING) {
+            return getMaxPositiveScrollAmount() <= 0;
+        } else {
+            return mOwnScrollY >= getScrollRange();
+        }
     }
 
     @Override
@@ -3947,7 +4362,7 @@
         resetCheckSnoozeLeavebehind();
         mAmbientState.setExpansionChanging(false);
         if (!mIsExpanded) {
-            setOwnScrollY(0);
+            resetScrollPosition();
             mStatusBar.resetUserExpandedStates();
             clearTemporaryViews();
             clearUserLockedViews();
@@ -4006,7 +4421,14 @@
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     public void resetScrollPosition() {
         mScroller.abortAnimation();
-        setOwnScrollY(0);
+        if (ANCHOR_SCROLLING) {
+            // TODO: once we're recycling this will need to modify the adapter position instead
+            mScrollAnchorView = getFirstChildNotGone();
+            mScrollAnchorViewY = 0;
+            updateOnScrollChange();
+        } else {
+            setOwnScrollY(0);
+        }
     }
 
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
@@ -4075,6 +4497,7 @@
     private void updateScrollPositionOnExpandInBottom(ExpandableView view) {
         if (view instanceof ExpandableNotificationRow && !onKeyguard()) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+            // TODO: once we're recycling this will need to check the adapter position of the child
             if (row.isUserLocked() && row != getFirstChildNotGone()) {
                 if (row.isSummaryWithChildren()) {
                     return;
@@ -4092,7 +4515,13 @@
                     layoutEnd -= mShelf.getIntrinsicHeight() + mPaddingBetweenElements;
                 }
                 if (endPosition > layoutEnd) {
-                    setOwnScrollY((int) (mOwnScrollY + endPosition - layoutEnd));
+                    if (ANCHOR_SCROLLING) {
+                        mScrollAnchorViewY -= (endPosition - layoutEnd);
+                        updateScrollAnchor();
+                        updateOnScrollChange();
+                    } else {
+                        setOwnScrollY((int) (mOwnScrollY + endPosition - layoutEnd));
+                    }
                     mDisallowScrollingInThisMotion = true;
                 }
             }
@@ -4353,6 +4782,9 @@
         if (mAmbientState.isDark() == dark) {
             return;
         }
+        if (!dark) {
+            mShowDarkShelf = false;
+        }
         mAmbientState.setDark(dark);
         if (animate && mAnimationsEnabled) {
             mDarkNeedsAnimation = true;
@@ -4369,12 +4801,12 @@
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     private void updatePanelTranslation() {
-        setTranslationX(mVerticalPanelTranslation + mAntiBurnInOffsetX * mInterpolatedDarkAmount);
+        setTranslationX(mHorizontalPanelTranslation + mAntiBurnInOffsetX * mInterpolatedDarkAmount);
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void setVerticalPanelTranslation(float verticalPanelTranslation) {
-        mVerticalPanelTranslation = verticalPanelTranslation;
+    public void setHorizontalPanelTranslation(float verticalPanelTranslation) {
+        mHorizontalPanelTranslation = verticalPanelTranslation;
         updatePanelTranslation();
     }
 
@@ -4414,9 +4846,9 @@
         boolean nowDarkAtAll = mAmbientState.isDarkAtAll();
         if (nowFullyDark != wasFullyDark) {
             updateContentHeight();
-        }
-        if (mIconAreaController != null) {
-            mIconAreaController.setDarkAmount(interpolatedDarkAmount);
+            if (nowFullyDark && mShowDarkShelf) {
+                updateDarkShelfVisibility();
+            }
         }
         if (!wasDarkAtAll && nowDarkAtAll) {
             resetExposedMenuView(true /* animate */, true /* animate */);
@@ -4427,6 +4859,22 @@
         requestChildrenUpdate();
     }
 
+    /**
+     * If the shelf should be visible when the device is in ambient mode (dozing.)
+     */
+    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+    public void setShowDarkShelf(boolean showDarkShelf) {
+        mShowDarkShelf = showDarkShelf;
+    }
+
+    private void updateDarkShelfVisibility() {
+        DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
+        if (dozeParameters.shouldControlScreenOff()) {
+            mShelf.fadeInTranslating();
+        }
+        updateClipping();
+    }
+
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     public void notifyDarkAnimationStart(boolean dark) {
         // We only swap the scaling factor if we're fully dark or fully awake to avoid
@@ -4638,9 +5086,13 @@
         super.onInitializeAccessibilityEventInternal(event);
         event.setScrollable(mScrollable);
         event.setScrollX(mScrollX);
-        event.setScrollY(mOwnScrollY);
         event.setMaxScrollX(mScrollX);
-        event.setMaxScrollY(getScrollRange());
+        if (ANCHOR_SCROLLING) {
+            // TODO
+        } else {
+            event.setScrollY(mOwnScrollY);
+            event.setMaxScrollY(getScrollRange());
+        }
     }
 
     @Override
@@ -4708,7 +5160,7 @@
         mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
     }
 
-    public void generateHeadsUpAnimation(NotificationData.Entry entry, boolean isHeadsUp) {
+    public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) {
         ExpandableNotificationRow row = entry.getHeadsUpAnimationView();
         generateHeadsUpAnimation(row, isHeadsUp);
     }
@@ -4825,13 +5277,63 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
-    public void setOwnScrollY(int ownScrollY) {
+    private void setOwnScrollY(int ownScrollY) {
+        assert !ANCHOR_SCROLLING;
         if (ownScrollY != mOwnScrollY) {
             // We still want to call the normal scrolled changed for accessibility reasons
             onScrollChanged(mScrollX, ownScrollY, mScrollX, mOwnScrollY);
             mOwnScrollY = ownScrollY;
-            updateForwardAndBackwardScrollability();
-            requestChildrenUpdate();
+            updateOnScrollChange();
+        }
+    }
+
+    private void updateOnScrollChange() {
+        updateForwardAndBackwardScrollability();
+        requestChildrenUpdate();
+    }
+
+    private void updateScrollAnchor() {
+        int anchorIndex = indexOfChild(mScrollAnchorView);
+        // If the anchor view has been scrolled off the top, move to the next view.
+        while (mScrollAnchorViewY < 0) {
+            View nextAnchor = null;
+            for (int i = anchorIndex + 1; i < getChildCount(); i++) {
+                View child = getChildAt(i);
+                if (child.getVisibility() != View.GONE
+                        && child instanceof ExpandableNotificationRow) {
+                    anchorIndex = i;
+                    nextAnchor = child;
+                    break;
+                }
+            }
+            if (nextAnchor == null) {
+                break;
+            }
+            mScrollAnchorViewY +=
+                    (int) (nextAnchor.getTranslationY() - mScrollAnchorView.getTranslationY());
+            mScrollAnchorView = nextAnchor;
+        }
+        // If the view above the anchor view is fully visible, make it the anchor view.
+        while (anchorIndex > 0 && mScrollAnchorViewY > 0) {
+            View prevAnchor = null;
+            for (int i = anchorIndex - 1; i >= 0; i--) {
+                View child = getChildAt(i);
+                if (child.getVisibility() != View.GONE
+                        && child instanceof ExpandableNotificationRow) {
+                    anchorIndex = i;
+                    prevAnchor = child;
+                    break;
+                }
+            }
+            if (prevAnchor == null) {
+                break;
+            }
+            float distanceToPreviousAnchor =
+                    mScrollAnchorView.getTranslationY() - prevAnchor.getTranslationY();
+            if (distanceToPreviousAnchor < mScrollAnchorViewY) {
+                mScrollAnchorViewY -= (int) distanceToPreviousAnchor;
+                mScrollAnchorView = prevAnchor;
+            }
         }
     }
 
@@ -4847,6 +5349,9 @@
         mAmbientState.setShelf(shelf);
         mStateAnimator.setShelf(shelf);
         shelf.bind(mAmbientState, this);
+        if (ANCHOR_SCROLLING) {
+            mScrollAnchorView = mShelf;
+        }
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5186,9 +5691,6 @@
         // another "changeViewPosition" call is ever added.
         changeViewPosition(mShelf,
                 getChildCount() - offsetFromEnd);
-
-        // Scrim opacity varies based on notification count
-        mScrimController.setNotificationCount(getNotGoneChildCount());
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5606,8 +6108,9 @@
       }
     };
 
+    @VisibleForTesting
     @ShadeViewRefactor(RefactorComponent.INPUT)
-    private final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() {
+    protected final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() {
         @Override
         public void onMenuClicked(View view, int x, int y, MenuItem item) {
             if (mLongPressListener == null) {
@@ -5615,8 +6118,10 @@
             }
             if (view instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-                MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR,
-                        row.getStatusBarNotification().getPackageName());
+                mMetricsLogger.write(row.getStatusBarNotification().getLogMaker()
+                        .setCategory(MetricsEvent.ACTION_TOUCH_GEAR)
+                        .setType(MetricsEvent.TYPE_ACTION)
+                        );
             }
             mLongPressListener.onLongPress(view, x, y, item);
         }
@@ -5639,8 +6144,9 @@
         public void onMenuShown(View row) {
             if (row instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow notificationRow = (ExpandableNotificationRow) row;
-                MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR,
-                        notificationRow.getStatusBarNotification().getPackageName());
+                mMetricsLogger.write(notificationRow.getStatusBarNotification().getLogMaker()
+                        .setCategory(MetricsEvent.ACTION_REVEAL_GEAR)
+                        .setType(MetricsEvent.TYPE_ACTION));
                 mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true);
             }
             mSwipeHelper.onMenuShown(row);
@@ -5792,6 +6298,15 @@
         }
 
         @Override
+        public int getConstrainSwipeStartPosition() {
+            NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
+            if (menuRow != null) {
+                return Math.abs(menuRow.getMenuSnapTarget());
+            }
+            return 0;
+        }
+
+                @Override
         public boolean canChildBeDismissed(View v) {
             return NotificationStackScrollLayout.this.canChildBeDismissed(v);
         }
@@ -5987,7 +6502,11 @@
         public void expansionStateChanged(boolean isExpanding) {
             mExpandingNotification = isExpanding;
             if (!mExpandedInThisMotion) {
-                mMaxScrollAfterExpand = mOwnScrollY;
+                if (ANCHOR_SCROLLING) {
+                    // TODO
+                } else {
+                    mMaxScrollAfterExpand = mOwnScrollY;
+                }
                 mExpandedInThisMotion = true;
             }
         }
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
index f1d9549..975aee5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -189,10 +189,13 @@
         boolean isFastNonDismissGesture =
                 gestureFastEnough && !gestureTowardsMenu && !isDismissGesture;
         boolean isMenuRevealingGestureAwayFromMenu = slowSwipedFarEnough || isFastNonDismissGesture;
-        if (isNonDismissGestureTowardsMenu
-                || (!isFalseGesture(ev) && isMenuRevealingGestureAwayFromMenu)) {
+        int menuSnapTarget = menuRow.getMenuSnapTarget();
+        boolean isNonFalseMenuRevealingGesture =
+                !isFalseGesture(ev) && isMenuRevealingGestureAwayFromMenu;
+        if ((isNonDismissGestureTowardsMenu || isNonFalseMenuRevealingGesture)
+                && menuSnapTarget != 0) {
             // Menu has not been snapped to previously and this is menu revealing gesture
-            snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
+            snapOpen(animView, menuSnapTarget, velocity);
             menuRow.onSnapOpen();
         } else if (isDismissGesture(ev) && !gestureTowardsMenu) {
             dismiss(animView, velocity);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 25fb7f9..2a88080 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -41,6 +41,8 @@
  */
 public class StackScrollAlgorithm {
 
+    static final boolean ANCHOR_SCROLLING = false;
+
     private static final String LOG_TAG = "StackScrollAlgorithm";
     private final ViewGroup mHostView;
 
@@ -236,6 +238,10 @@
         scrollY = Math.max(0, scrollY);
         state.scrollY = (int) (scrollY + bottomOverScroll);
 
+        if (ANCHOR_SCROLLING) {
+            state.anchorViewY = (int) (ambientState.getAnchorViewY() - bottomOverScroll);
+        }
+
         //now init the visible children and update paddings
         int childCount = hostView.getChildCount();
         state.visibleChildren.clear();
@@ -252,6 +258,11 @@
         // iterating over it again, it's filled with the actual resolved value.
 
         for (int i = 0; i < childCount; i++) {
+            if (ANCHOR_SCROLLING) {
+                if (i == ambientState.getAnchorViewIndex()) {
+                    state.anchorViewIndex = state.visibleChildren.size();
+                }
+            }
             ExpandableView v = (ExpandableView) hostView.getChildAt(i);
             if (v.getVisibility() != View.GONE) {
                 if (v == ambientState.getShelf()) {
@@ -350,28 +361,74 @@
     private void updatePositionsForState(StackScrollAlgorithmState algorithmState,
             AmbientState ambientState) {
 
-        // The y coordinate of the current child.
-        float currentYPosition = -algorithmState.scrollY;
-        int childCount = algorithmState.visibleChildren.size();
-        for (int i = 0; i < childCount; i++) {
-            currentYPosition = updateChild(i, algorithmState, ambientState, currentYPosition);
+        if (ANCHOR_SCROLLING) {
+            float currentYPosition = algorithmState.anchorViewY;
+            int childCount = algorithmState.visibleChildren.size();
+            for (int i = algorithmState.anchorViewIndex; i < childCount; i++) {
+                if (i > algorithmState.anchorViewIndex && ambientState.beginsNewSection(i)) {
+                    currentYPosition += mGapHeight;
+                }
+                currentYPosition = updateChild(i, algorithmState, ambientState, currentYPosition,
+                        false /* reverse */);
+            }
+            currentYPosition = algorithmState.anchorViewY;
+            for (int i = algorithmState.anchorViewIndex - 1; i >= 0; i--) {
+                if (ambientState.beginsNewSection(i + 1)) {
+                    currentYPosition -= mGapHeight;
+                }
+                currentYPosition = updateChild(i, algorithmState, ambientState, currentYPosition,
+                        true /* reverse */);
+            }
+        } else {
+            // The y coordinate of the current child.
+            float currentYPosition = -algorithmState.scrollY;
+            int childCount = algorithmState.visibleChildren.size();
+            for (int i = 0; i < childCount; i++) {
+                if (ambientState.beginsNewSection(i)) {
+                    currentYPosition += mGapHeight;
+                }
+                currentYPosition = updateChild(i, algorithmState, ambientState, currentYPosition,
+                        false /* reverse */);
+            }
         }
     }
 
+    /**
+     * Populates the {@link ExpandableViewState} for a single child.
+     *
+     * @param i                The index of the child in
+     * {@link StackScrollAlgorithmState#visibleChildren}.
+     * @param algorithmState   The overall output state of the algorithm.
+     * @param ambientState     The input state provided to the algorithm.
+     * @param currentYPosition The Y position of the current pass of the algorithm.  For a forward
+     *                         pass, this should be the top of the child; for a reverse pass, the
+     *                         bottom of the child.
+     * @param reverse          Whether we're laying out children in the reverse direction (Y
+     *                         positions
+     *                         decreasing) instead of the forward direction (Y positions
+     *                         increasing).
+     * @return The Y position after laying out the child.  This will be the {@code currentYPosition}
+     * for the next call to this method, after adjusting for any gaps between children.
+     */
     protected float updateChild(
             int i,
             StackScrollAlgorithmState algorithmState,
             AmbientState ambientState,
-            float currentYPosition) {
+            float currentYPosition,
+            boolean reverse) {
         ExpandableView child = algorithmState.visibleChildren.get(i);
         ExpandableViewState childViewState = child.getViewState();
         childViewState.location = ExpandableViewState.LOCATION_UNKNOWN;
         int paddingAfterChild = getPaddingAfterChild(algorithmState, child);
         int childHeight = getMaxAllowedChildHeight(child);
-        if (ambientState.beginsNewSection(i)) {
-            currentYPosition += mGapHeight;
+        if (reverse) {
+            childViewState.yTranslation = currentYPosition - (childHeight + paddingAfterChild);
+            if (currentYPosition <= 0) {
+                childViewState.location = ExpandableViewState.LOCATION_HIDDEN_TOP;
+            }
+        } else {
+            childViewState.yTranslation = currentYPosition;
         }
-        childViewState.yTranslation = currentYPosition;
         boolean isFooterView = child instanceof FooterView;
         boolean isEmptyShadeView = child instanceof EmptyShadeView;
 
@@ -396,9 +453,13 @@
             clampPositionToShelf(child, childViewState, ambientState);
         }
 
-        currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
-        if (currentYPosition <= 0) {
-            childViewState.location = ExpandableViewState.LOCATION_HIDDEN_TOP;
+        if (reverse) {
+            currentYPosition = childViewState.yTranslation;
+        } else {
+            currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
+            if (currentYPosition <= 0) {
+                childViewState.location = ExpandableViewState.LOCATION_HIDDEN_TOP;
+            }
         }
         if (childViewState.location == ExpandableViewState.LOCATION_UNKNOWN) {
             Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
@@ -464,6 +525,7 @@
                 // To check if the row need to do translation according to scroll Y
                 // heads up show full of row's content and any scroll y indicate that the
                 // translationY need to move up the HUN.
+                // TODO: fix this check for anchor scrolling.
                 if (!mIsExpanded && isTopEntry && ambientState.getScrollY() > 0) {
                     childState.yTranslation -= ambientState.getScrollY();
                 }
@@ -607,10 +669,18 @@
     public class StackScrollAlgorithmState {
 
         /**
-         * The scroll position of the algorithm
+         * The scroll position of the algorithm (absolute scrolling).
          */
         public int scrollY;
 
+        /** The index of the anchor view (anchor scrolling). */
+        public int anchorViewIndex;
+
+        /**
+         * The Y position, relative to the top of the screen, of the anchor view (anchor scrolling).
+         */
+        public int anchorViewY;
+
         /**
          * The children from the host view which are not gone.
          */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 19fce48..b4c205a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -426,6 +426,9 @@
                     mTmpState.yTranslation += mPulsingAppearingTranslation;
                     mTmpState.alpha = 0;
                     mTmpState.applyToView(changingView);
+
+                    mTmpState.copyFrom(mShelf.getViewState());
+                    mTmpState.applyToView(mShelf);
                 }
             } else if (event.animationType == NotificationStackScrollLayout
                     .AnimationEvent.ANIMATION_TYPE_PULSE_DISAPPEAR) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
new file mode 100644
index 0000000..b9425d4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -0,0 +1,216 @@
+/*
+ * 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 com.android.systemui.Dependency.MAIN_HANDLER_NAME;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IWindowManager;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/** A controller to control all auto-hide things. */
+public class AutoHideController implements CommandQueue.Callbacks {
+    private static final String TAG = "AutoHideController";
+
+    private final IWindowManager mWindowManagerService;
+
+    private final Handler mHandler;
+    private final NotificationRemoteInputManager mRemoteInputManager;
+    private final CommandQueue mCommandQueue;
+    private StatusBar mStatusBar;
+    private NavigationBarFragment mNavigationBar;
+
+    private int mDisplayId;
+    private int mSystemUiVisibility;
+    // last value sent to window manager
+    private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
+
+    private boolean mAutoHideSuspended;
+
+    private static final long AUTOHIDE_TIMEOUT_MS = 2250;
+
+    private final Runnable mAutoHide = () -> {
+        int requested = mSystemUiVisibility & ~getTransientMask();
+        if (mSystemUiVisibility != requested) {
+            notifySystemUiVisibilityChanged(requested);
+        }
+    };
+
+    @Inject
+    public AutoHideController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) {
+        mCommandQueue = SysUiServiceProvider.getComponent(context, CommandQueue.class);
+        mCommandQueue.addCallback(this);
+        mHandler = handler;
+        mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
+        mWindowManagerService = Dependency.get(IWindowManager.class);
+
+        mDisplayId = context.getDisplayId();
+    }
+
+    void setStatusBar(StatusBar statusBar) {
+        mStatusBar = statusBar;
+    }
+
+    void setNavigationBar(NavigationBarFragment navigationBar) {
+        mNavigationBar = navigationBar;
+    }
+
+    @Override
+    public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
+            int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+        if (displayId != mDisplayId) {
+            return;
+        }
+        int oldVal = mSystemUiVisibility;
+        int newVal = (oldVal & ~mask) | (vis & mask);
+        int diff = newVal ^ oldVal;
+
+        if (diff != 0) {
+            mSystemUiVisibility = newVal;
+
+            // ready to unhide
+            if (hasStatusBar() && (vis & View.STATUS_BAR_UNHIDE) != 0) {
+                mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
+            }
+
+            if (hasNavigationBar() && (vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
+                mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
+            }
+
+            // Re-send setSystemUiVisibility to update un-hide status.
+            if (mSystemUiVisibility != newVal) {
+                mCommandQueue.setSystemUiVisibility(mDisplayId, mSystemUiVisibility,
+                        fullscreenStackVis, dockedStackVis, mask, fullscreenStackBounds,
+                        dockedStackBounds);
+            }
+
+            notifySystemUiVisibilityChanged(mSystemUiVisibility);
+        }
+    }
+
+    private void notifySystemUiVisibilityChanged(int vis) {
+        try {
+            if (mLastDispatchedSystemUiVisibility != vis) {
+                mWindowManagerService.statusBarVisibilityChanged(mDisplayId, vis);
+                mLastDispatchedSystemUiVisibility = vis;
+            }
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Cannot get WindowManager");
+        }
+    }
+
+    void resumeSuspendedAutoHide() {
+        if (mAutoHideSuspended) {
+            scheduleAutoHide();
+            Runnable checkBarModesRunnable = getCheckBarModesRunnable();
+            if (checkBarModesRunnable != null) {
+                mHandler.postDelayed(checkBarModesRunnable, 500); // longer than home -> launcher
+            }
+        }
+    }
+
+    void suspendAutoHide() {
+        mHandler.removeCallbacks(mAutoHide);
+        Runnable checkBarModesRunnable = getCheckBarModesRunnable();
+        if (checkBarModesRunnable != null) {
+            mHandler.removeCallbacks(checkBarModesRunnable);
+        }
+        mAutoHideSuspended = (mSystemUiVisibility & getTransientMask()) != 0;
+    }
+
+    void touchAutoHide() {
+        // update transient bar auto hide
+        if ((hasStatusBar() && mStatusBar.getStatusBarMode() == MODE_SEMI_TRANSPARENT)
+                || hasNavigationBar() && mNavigationBar.isSemiTransparent()) {
+            scheduleAutoHide();
+        } else {
+            cancelAutoHide();
+        }
+    }
+
+    private Runnable getCheckBarModesRunnable() {
+        if (hasStatusBar()) {
+            return () -> mStatusBar.checkBarModes();
+        } else if (hasNavigationBar()) {
+            return () -> mNavigationBar.checkNavBarModes();
+        } else {
+            return null;
+        }
+    }
+
+    private void cancelAutoHide() {
+        mAutoHideSuspended = false;
+        mHandler.removeCallbacks(mAutoHide);
+    }
+
+    private void scheduleAutoHide() {
+        cancelAutoHide();
+        mHandler.postDelayed(mAutoHide, AUTOHIDE_TIMEOUT_MS);
+    }
+
+    void checkUserAutoHide(MotionEvent event) {
+        boolean shouldAutoHide =
+                (mSystemUiVisibility & getTransientMask()) != 0  // a transient bar is revealed.
+                && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar.
+                && event.getX() == 0 && event.getY() == 0;
+        if (hasStatusBar()) {
+            // a touch outside both bars
+            shouldAutoHide &= !mRemoteInputManager.getController().isRemoteInputActive();
+        }
+        if (shouldAutoHide) {
+            userAutoHide();
+        }
+    }
+
+    private void userAutoHide() {
+        cancelAutoHide();
+        mHandler.postDelayed(mAutoHide, 350); // longer than app gesture -> flag clear
+    }
+
+    private int getTransientMask() {
+        int mask = 0;
+        if (hasStatusBar()) {
+            mask |= View.STATUS_BAR_TRANSIENT;
+        }
+        if (hasNavigationBar()) {
+            mask |= View.NAVIGATION_BAR_TRANSIENT;
+        }
+        return mask;
+    }
+
+    private boolean hasNavigationBar() {
+        return mNavigationBar != null;
+    }
+
+    private boolean hasStatusBar() {
+        return mStatusBar != null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 1d7e899..fac4dbb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -30,6 +30,9 @@
 import com.android.systemui.statusbar.policy.HotspotController;
 import com.android.systemui.statusbar.policy.HotspotController.Callback;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+
 /**
  * Manages which tiles should be automatically added to QS.
  */
@@ -44,24 +47,31 @@
     private final QSTileHost mHost;
     private final Handler mHandler;
     private final AutoAddTracker mAutoTracker;
+    private final HotspotController mHotspotController;
+    private final DataSaverController mDataSaverController;
+    private final ManagedProfileController mManagedProfileController;
+    private final ColorDisplayController mColorDisplayController;
 
-    public AutoTileManager(Context context, QSTileHost host) {
-        this(context, new AutoAddTracker(context), host,
-            new Handler(Dependency.get(Dependency.BG_LOOPER)));
-    }
-
-    @VisibleForTesting
-    AutoTileManager(Context context, AutoAddTracker autoAddTracker, QSTileHost host,
-            Handler handler) {
+    @Inject
+    public AutoTileManager(Context context, AutoAddTracker autoAddTracker, QSTileHost host,
+            @Named(Dependency.BG_HANDLER_NAME) Handler handler,
+            HotspotController hotspotController,
+            DataSaverController dataSaverController,
+            ManagedProfileController managedProfileController,
+            ColorDisplayController colorDisplayController) {
         mAutoTracker = autoAddTracker;
         mContext = context;
         mHost = host;
         mHandler = handler;
+        mHotspotController = hotspotController;
+        mDataSaverController = dataSaverController;
+        mManagedProfileController = managedProfileController;
+        mColorDisplayController = colorDisplayController;
         if (!mAutoTracker.isAdded(HOTSPOT)) {
-            Dependency.get(HotspotController.class).addCallback(mHotspotCallback);
+            hotspotController.addCallback(mHotspotCallback);
         }
         if (!mAutoTracker.isAdded(SAVER)) {
-            Dependency.get(DataSaverController.class).addCallback(mDataSaverListener);
+            dataSaverController.addCallback(mDataSaverListener);
         }
         if (!mAutoTracker.isAdded(INVERSION)) {
             mColorsSetting = new SecureSetting(mContext, mHandler,
@@ -79,11 +89,11 @@
             mColorsSetting.setListening(true);
         }
         if (!mAutoTracker.isAdded(WORK)) {
-            Dependency.get(ManagedProfileController.class).addCallback(mProfileCallback);
+            managedProfileController.addCallback(mProfileCallback);
         }
         if (!mAutoTracker.isAdded(NIGHT)
                 && ColorDisplayManager.isNightDisplayAvailable(mContext)) {
-            Dependency.get(ColorDisplayController.class).setListener(mColorDisplayCallback);
+            colorDisplayController.setListener(mColorDisplayCallback);
         }
     }
 
@@ -92,11 +102,11 @@
             mColorsSetting.setListening(false);
         }
         mAutoTracker.destroy();
-        Dependency.get(HotspotController.class).removeCallback(mHotspotCallback);
-        Dependency.get(DataSaverController.class).removeCallback(mDataSaverListener);
-        Dependency.get(ManagedProfileController.class).removeCallback(mProfileCallback);
+        mHotspotController.removeCallback(mHotspotCallback);
+        mDataSaverController.removeCallback(mDataSaverListener);
+        mManagedProfileController.removeCallback(mProfileCallback);
         if (ColorDisplayManager.isNightDisplayAvailable(mContext)) {
-            Dependency.get(ColorDisplayController.class).setListener(null);
+            mColorDisplayController.setListener(null);
         }
     }
 
@@ -109,7 +119,7 @@
                 @Override
                 public void onManagedProfileChanged() {
                     if (mAutoTracker.isAdded(WORK)) return;
-                    if (Dependency.get(ManagedProfileController.class).hasActiveProfile()) {
+                    if (mManagedProfileController.hasActiveProfile()) {
                         mHost.addTile(WORK);
                         mAutoTracker.setTileAdded(WORK);
                     }
@@ -129,8 +139,7 @@
             if (isDataSaving) {
                 mHost.addTile(SAVER);
                 mAutoTracker.setTileAdded(SAVER);
-                mHandler.post(() -> Dependency.get(DataSaverController.class).removeCallback(
-                        mDataSaverListener));
+                mHandler.post(() -> mDataSaverController.removeCallback(mDataSaverListener));
             }
         }
     };
@@ -142,8 +151,7 @@
             if (enabled) {
                 mHost.addTile(HOTSPOT);
                 mAutoTracker.setTileAdded(HOTSPOT);
-                mHandler.post(() -> Dependency.get(HotspotController.class)
-                        .removeCallback(mHotspotCallback));
+                mHandler.post(() -> mHotspotController.removeCallback(mHotspotCallback));
             }
         }
     };
@@ -170,8 +178,7 @@
             if (mAutoTracker.isAdded(NIGHT)) return;
             mHost.addTile(NIGHT);
             mAutoTracker.setTileAdded(NIGHT);
-            mHandler.post(() -> Dependency.get(ColorDisplayController.class)
-                    .setListener(null));
+            mHandler.post(() -> mColorDisplayController.setListener(null));
         }
     };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 24570ae..35763dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -70,7 +70,7 @@
     private SignalCallback mSignalCallback = new SignalCallback() {
         @Override
         public void setIsAirplaneMode(NetworkController.IconState icon) {
-            mCommandQueue.recomputeDisableFlags(true /* animate */);
+            mCommandQueue.recomputeDisableFlags(getContext().getDisplayId(), true /* animate */);
         }
     };
 
@@ -155,7 +155,10 @@
     }
 
     @Override
-    public void disable(int state1, int state2, boolean animate) {
+    public void disable(int displayId, int state1, int state2, boolean animate) {
+        if (displayId != getContext().getDisplayId()) {
+            return;
+        }
         state1 = adjustDisableFlags(state1);
         final int old1 = mDisabled1;
         final int diff1 = state1 ^ old1;
@@ -212,7 +215,10 @@
             }
         }
 
-        if (mStatusBarStateController.isDozing()) {
+        // The shelf will be hidden when dozing with a custom clock, we must show notification
+        // icons in this occasion.
+        if (mStatusBarStateController.isDozing()
+                && mStatusBarComponent.getPanel().hasCustomClock()) {
             state |= DISABLE_CLOCK | DISABLE_SYSTEM_INFO;
             state &= ~DISABLE_NOTIFICATION_ICONS;
         }
@@ -362,6 +368,6 @@
 
     @Override
     public void onDozingChanged(boolean isDozing) {
-        disable(mDisabled1, mDisabled1, false /* animate */);
+        disable(getContext().getDisplayId(), mDisabled1, mDisabled1, false /* animate */);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 6f2b63d..1049773 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -158,8 +158,7 @@
      * @return duration in millis.
      */
     public long getWallpaperAodDuration() {
-        if (mAmbientDisplayConfiguration.wakeLockScreenGestureEnabled(UserHandle.USER_CURRENT)
-                || shouldControlScreenOff()) {
+        if (shouldControlScreenOff()) {
             return DozeScreenState.ENTER_DOZE_HIDE_WALLPAPER_DELAY;
         }
         return mAlwaysOnPolicy.wallpaperVisibilityDuration;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index d1e488a..876b902 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -28,7 +28,7 @@
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -143,7 +143,7 @@
     }
 
     @Override
-    public void onHeadsUpPinned(NotificationData.Entry entry) {
+    public void onHeadsUpPinned(NotificationEntry entry) {
         updateTopEntry();
         updateHeader(entry);
     }
@@ -206,11 +206,11 @@
     }
 
     private void updateTopEntry() {
-        NotificationData.Entry newEntry = null;
+        NotificationEntry newEntry = null;
         if (!mIsExpanded && mHeadsUpManager.hasPinnedHeadsUp()) {
             newEntry = mHeadsUpManager.getTopEntry();
         }
-        NotificationData.Entry previousEntry = mHeadsUpStatusBarView.getShowingEntry();
+        NotificationEntry previousEntry = mHeadsUpStatusBarView.getShowingEntry();
         mHeadsUpStatusBarView.setEntry(newEntry);
         if (newEntry != previousEntry) {
             boolean animateIsolation = false;
@@ -298,7 +298,7 @@
     }
 
     @Override
-    public void onHeadsUpUnPinned(NotificationData.Entry entry) {
+    public void onHeadsUpUnPinned(NotificationEntry entry) {
         updateTopEntry();
         updateHeader(entry);
     }
@@ -338,7 +338,7 @@
         });
     }
 
-    public void updateHeader(NotificationData.Entry entry) {
+    public void updateHeader(NotificationEntry entry) {
         ExpandableNotificationRow row = entry.getRow();
         float headerVisibleAmount = 1.0f;
         if (row.isPinned() || row.isHeadsUpAnimatingAway() || row == mTrackedChild) {
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 f4cfd41..7f75223 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -41,8 +41,8 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -58,7 +58,7 @@
  */
 public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
         ViewTreeObserver.OnComputeInternalInsetsListener, VisualStabilityManager.Callback,
-        OnHeadsUpChangedListener, ConfigurationController.ConfigurationListener {
+        OnHeadsUpChangedListener, ConfigurationController.ConfigurationListener, StateListener {
     private static final String TAG = "HeadsUpManagerPhone";
 
     private final View mStatusBarWindowView;
@@ -72,8 +72,8 @@
     private int mDisplayCutoutTouchableRegionSize;
     private boolean mTrackingHeadsUp;
     private HashSet<String> mSwipedOutKeys = new HashSet<>();
-    private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>();
-    private ArraySet<NotificationData.Entry> mEntriesToRemoveWhenReorderingAllowed
+    private HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>();
+    private ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
             = new ArraySet<>();
     private boolean mIsExpanded;
     private int[] mTmpTwoArray = new int[2];
@@ -83,7 +83,6 @@
     private boolean mIsObserving;
     private int mStatusBarState;
 
-    private final StateListener mStateListener = this::setStatusBarState;
     private AnimationStateHandler mAnimationStateHandler;
     private BubbleController mBubbleController = Dependency.get(BubbleController.class);
 
@@ -129,7 +128,7 @@
                 updateTouchableRegionListener();
             }
         });
-        Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
+        Dependency.get(StatusBarStateController.class).addCallback(this);
         mBubbleController.setBubbleStateChangeListener((hasBubbles) -> {
             if (!hasBubbles) {
                 mBubbleGoingAway = true;
@@ -143,7 +142,7 @@
     }
 
     public void destroy() {
-        Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
+        Dependency.get(StatusBarStateController.class).removeCallback(this);
     }
 
     private void initResources() {
@@ -187,7 +186,7 @@
             releaseAllImmediately();
             mReleaseOnExpandFinish = false;
         } else {
-            for (NotificationData.Entry entry : mEntriesToRemoveAfterExpand) {
+            for (NotificationEntry entry : mEntriesToRemoveAfterExpand) {
                 if (isAlerting(entry.key)) {
                     // Maybe the heads-up was removed already
                     removeAlertEntry(entry.key);
@@ -225,11 +224,9 @@
         }
     }
 
-    /**
-     * Set the current state of the statusbar.
-     */
-    private void setStatusBarState(int statusBarState) {
-        mStatusBarState = statusBarState;
+    @Override
+    public void onStateChanged(int newState) {
+        mStatusBarState = newState;
     }
 
     /**
@@ -252,7 +249,7 @@
      * @param remoteInputActive True to notify active, False to notify inactive.
      */
     public void setRemoteInputActive(
-            @NonNull NotificationData.Entry entry, boolean remoteInputActive) {
+            @NonNull NotificationEntry entry, boolean remoteInputActive) {
         HeadsUpEntryPhone headsUpEntry = getHeadsUpEntryPhone(entry.key);
         if (headsUpEntry != null && headsUpEntry.remoteInputActive != remoteInputActive) {
             headsUpEntry.remoteInputActive = remoteInputActive;
@@ -268,7 +265,7 @@
      * Sets whether an entry's menu row is exposed and therefore it should stick in the heads up
      * area if it's pinned until it's hidden again.
      */
-    public void setMenuShown(@NonNull NotificationData.Entry entry, boolean menuShown) {
+    public void setMenuShown(@NonNull NotificationEntry entry, boolean menuShown) {
         HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.key);
         if (headsUpEntry instanceof HeadsUpEntryPhone && entry.isRowPinned()) {
             ((HeadsUpEntryPhone) headsUpEntry).setMenuShownPinned(menuShown);
@@ -315,9 +312,9 @@
             return;
         }
         if (hasPinnedHeadsUp()) {
-            NotificationData.Entry topEntry = getTopEntry();
+            NotificationEntry topEntry = getTopEntry();
             if (topEntry.isChildInGroup()) {
-                final NotificationData.Entry groupSummary
+                final NotificationEntry groupSummary
                         = mGroupManager.getGroupSummary(topEntry.notification);
                 if (groupSummary != null) {
                     topEntry = groupSummary;
@@ -374,7 +371,7 @@
     @Override
     public void onReorderingAllowed() {
         mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
-        for (NotificationData.Entry entry : mEntriesToRemoveWhenReorderingAllowed) {
+        for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
             if (isAlerting(entry.key)) {
                 // Maybe the heads-up was removed already
                 removeAlertEntry(entry.key);
@@ -399,7 +396,7 @@
     }
 
     @Override
-    protected boolean shouldHeadsUpBecomePinned(NotificationData.Entry entry) {
+    protected boolean shouldHeadsUpBecomePinned(NotificationEntry entry) {
           return mStatusBarState != StatusBarState.KEYGUARD && !mIsExpanded
                   || super.shouldHeadsUpBecomePinned(entry);
     }
@@ -488,7 +485,7 @@
             return super.isSticky() || mMenuShownPinned;
         }
 
-        public void setEntry(@NonNull final NotificationData.Entry entry) {
+        public void setEntry(@NonNull final NotificationEntry entry) {
            Runnable removeHeadsUpRunnable = () -> {
                 if (!mVisualStabilityManager.isReorderingAllowed()) {
                     mEntriesToRemoveWhenReorderingAllowed.add(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index 9c1c71a..dd200da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -21,7 +21,7 @@
 import android.view.ViewConfiguration;
 
 import com.android.systemui.Gefingerpoken;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 
@@ -83,7 +83,7 @@
                 } else if (child == null && !mCallback.isExpanded()) {
                     // We might touch above the visible heads up child, but then we still would
                     // like to capture it.
-                    NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry();
+                    NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
                     if (topEntry != null && topEntry.isRowPinned()) {
                         mPickedChild = topEntry.getRow();
                         mTouchingHeadsUpView = true;
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 a81b7e5..c68fdd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -91,11 +91,6 @@
     private int mBurnInPreventionOffsetY;
 
     /**
-     * Clock vertical padding when pulsing.
-     */
-    private int mPulsingPadding;
-
-    /**
      * Doze/AOD transition amount.
      */
     private float mDarkAmount;
@@ -105,10 +100,6 @@
      */
     private boolean mCurrentlySecure;
 
-    /**
-     * Dozing and receiving a notification (AOD notification.)
-     */
-    private boolean mPulsing;
     private float mEmptyDragAmount;
 
     /**
@@ -123,13 +114,11 @@
                 R.dimen.burn_in_prevention_offset_x);
         mBurnInPreventionOffsetY = res.getDimensionPixelSize(
                 R.dimen.burn_in_prevention_offset_y);
-        mPulsingPadding = res.getDimensionPixelSize(
-                R.dimen.widget_pulsing_bottom_padding);
     }
 
     public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
             float panelExpansion, int parentHeight, int keyguardStatusHeight, float dark,
-            boolean secure, boolean pulsing, float emptyDragAmount) {
+            boolean secure, float emptyDragAmount) {
         mMinTopMargin = minTopMargin + mContainerTopPadding;
         mMaxShadeBottom = maxShadeBottom;
         mNotificationStackHeight = notificationStackHeight;
@@ -138,7 +127,6 @@
         mKeyguardStatusHeight = keyguardStatusHeight;
         mDarkAmount = dark;
         mCurrentlySecure = secure;
-        mPulsing = pulsing;
         mEmptyDragAmount = emptyDragAmount;
     }
 
@@ -146,7 +134,7 @@
         final int y = getClockY();
         result.clockY = y;
         result.clockAlpha = getClockAlpha(y);
-        result.stackScrollerPadding = y + (mPulsing ? mPulsingPadding : mKeyguardStatusHeight);
+        result.stackScrollerPadding = y + mKeyguardStatusHeight;
         result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
     }
 
@@ -185,9 +173,6 @@
     private int getClockY() {
         // Dark: Align the bottom edge of the clock at about half of the screen:
         float clockYDark = getMaxClockY() + burnInPreventionOffsetY();
-        if (mPulsing) {
-            clockYDark -= mPulsingPadding;
-        }
         clockYDark = MathUtils.max(0, clockYDark);
 
         float clockYRegular = getExpandedClockPosition();
@@ -230,11 +215,6 @@
                 - mBurnInPreventionOffsetX;
     }
 
-    @VisibleForTesting
-    void setPulsingPadding(int padding) {
-        mPulsingPadding = padding;
-    }
-
     public static class Result {
 
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
index 927228e..925a19d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
@@ -22,7 +22,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
 public class KeyguardEnvironmentImpl implements KeyguardEnvironment {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index dd07ec4..1944c3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -25,8 +25,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.SystemClock;
-import android.util.MathUtils;
 import android.provider.Settings;
+import android.util.MathUtils;
 import android.util.TimeUtils;
 
 import com.android.systemui.Dependency;
@@ -66,6 +66,7 @@
     private float mDarkIntensity;
     private float mNextDarkIntensity;
     private float mDozeAmount;
+    private int mDisplayId;
     private final Runnable mTransitionDeferringDoneRunnable = new Runnable() {
         @Override
         public void run() {
@@ -85,6 +86,7 @@
         mStatusBarStateController.addCallback(this);
         mDozeAmount = mStatusBarStateController.getDozeAmount();
         mContext = context;
+        mDisplayId = mContext.getDisplayId();
     }
 
     public void destroy(Context context) {
@@ -104,15 +106,18 @@
     }
 
     @Override
-    public void appTransitionPending(boolean forced) {
-        if (mKeyguardMonitor.isKeyguardGoingAway() && !forced) {
+    public void appTransitionPending(int displayId, boolean forced) {
+        if (mDisplayId != displayId || mKeyguardMonitor.isKeyguardGoingAway() && !forced) {
             return;
         }
         mTransitionPending = true;
     }
 
     @Override
-    public void appTransitionCancelled() {
+    public void appTransitionCancelled(int displayId) {
+        if (mDisplayId != displayId) {
+            return;
+        }
         if (mTransitionPending && mTintChangePending) {
             mTintChangePending = false;
             animateIconTint(mPendingDarkIntensity, 0 /* delay */, getTintAnimationDuration());
@@ -121,8 +126,9 @@
     }
 
     @Override
-    public void appTransitionStarting(long startTime, long duration, boolean forced) {
-        if (mKeyguardMonitor.isKeyguardGoingAway() && !forced) {
+    public void appTransitionStarting(int displayId, long startTime, long duration,
+            boolean forced) {
+        if (mDisplayId != displayId || mKeyguardMonitor.isKeyguardGoingAway() && !forced) {
             return;
         }
         if (mTransitionPending && mTintChangePending) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java
new file mode 100644
index 0000000..323e776
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.NonNull;
+import android.os.Bundle;
+import android.view.MotionEvent;
+
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.recents.OverviewProxyService;
+
+/**
+ * Assistant is triggered with this action
+ */
+public class NavigationAssistantAction extends NavigationGestureAction {
+    private static final String TAG = "NavigationAssistantActions";
+
+    private final AssistManager mAssistManager;
+
+    public NavigationAssistantAction(@NonNull NavigationBarView navigationBarView,
+            @NonNull OverviewProxyService service, AssistManager assistManager) {
+        super(navigationBarView, service);
+        mAssistManager = assistManager;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return true;
+    }
+
+    @Override
+    public boolean disableProxyEvents() {
+        return true;
+    }
+
+    @Override
+    public void onGestureStart(MotionEvent event) {
+        mAssistManager.startAssist(new Bundle());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
index 9c8b1b1..7a42b03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
@@ -67,7 +67,7 @@
 
     @Override
     public boolean isEnabled() {
-        return !getGlobalBoolean(NavigationPrototypeController.NAVBAR_EXPERIMENTS_DISABLED);
+        return true;
     }
 
     @Override
@@ -95,6 +95,11 @@
         }
     }
 
+    @Override
+    public boolean disableProxyEvents() {
+        return true;
+    }
+
     private void performBack() {
         sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
         sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
@@ -102,8 +107,7 @@
     }
 
     private boolean shouldExecuteBackOnUp() {
-        return !getGlobalBoolean(NavigationPrototypeController.NAVBAR_EXPERIMENTS_DISABLED)
-                && getGlobalBoolean(BACK_AFTER_END_PROP);
+        return getGlobalBoolean(BACK_AFTER_END_PROP);
     }
 
     private void sendEvent(int action, int code) {
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 270565b..ee047e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -18,6 +18,8 @@
 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
+import static android.app.StatusBarManager.WindowType;
+import static android.app.StatusBarManager.WindowVisibleState;
 import static android.app.StatusBarManager.windowStateToString;
 
 import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
@@ -60,7 +62,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Display;
-import android.view.IWindowManager;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -69,7 +70,6 @@
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
-import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
@@ -121,7 +121,7 @@
 
     /** Allow some time inbetween the long press for back and recents. */
     private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
-    private static final long AUTOHIDE_TIMEOUT_MS = 2250;
+    private static final long AUTODIM_TIMEOUT_MS = 2250;
 
     private final AccessibilityManagerWrapper mAccessibilityManagerWrapper;
     protected final AssistManager mAssistManager;
@@ -130,14 +130,13 @@
 
     protected NavigationBarView mNavigationBarView = null;
 
-    private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
+    private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
 
     private int mNavigationIconHints = 0;
     private @TransitionMode int mNavigationBarMode;
     private AccessibilityManager mAccessibilityManager;
     private MagnificationContentObserver mMagnificationObserver;
     private ContentResolver mContentResolver;
-    private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
 
     private int mDisabledFlags1;
     private int mDisabledFlags2;
@@ -153,6 +152,7 @@
 
     private int mSystemUiVisibility;
     private LightBarController mLightBarController;
+    private AutoHideController mAutoHideController;
 
     private OverviewProxyService mOverviewProxyService;
 
@@ -162,9 +162,6 @@
 
     private Handler mHandler = Dependency.get(Dependency.MAIN_HANDLER);
 
-    // last value sent to window manager
-    private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
-
     private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
         @Override
         public void onConnectionChanged(boolean isConnected) {
@@ -205,19 +202,12 @@
         if (visible) {
             // If the button will actually become visible and the navbar is about to hide,
             // tell the statusbar to keep it around for longer
-            touchAutoHide();
+            mAutoHideController.touchAutoHide();
         }
     };
 
     private final Runnable mAutoDim = () -> getBarTransitions().setAutoDim(true);
 
-    private final Runnable mAutoHide = () -> {
-        int requested = mSystemUiVisibility & ~View.NAVIGATION_BAR_TRANSIENT;
-        if (mSystemUiVisibility != requested) {
-            notifySystemUiVisibilityChanged(requested);
-        }
-    };
-
     @Inject
     public NavigationBarFragment(AccessibilityManagerWrapper accessibilityManagerWrapper,
             DeviceProvisionedController deviceProvisionedController, MetricsLogger metricsLogger,
@@ -253,6 +243,9 @@
             mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0);
         }
         mAccessibilityManagerWrapper.addCallback(mAccessibilityListener);
+
+        // Respect the latest disabled-flags.
+        mCommandQueue.recomputeDisableFlags(mDisplayId, false);
     }
 
     @Override
@@ -279,7 +272,7 @@
             mIsOnDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
         }
 
-        mNavigationBarView.setComponents(mStatusBar.getPanel());
+        mNavigationBarView.setComponents(mStatusBar.getPanel(), mAssistManager);
         mNavigationBarView.setDisabledFlags(mDisabledFlags1);
         mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
         mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
@@ -376,8 +369,11 @@
     // ----- CommandQueue Callbacks -----
 
     @Override
-    public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+    public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
             boolean showImeSwitcher) {
+        if (displayId != mDisplayId) {
+            return;
+        }
         boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
         int hints = mNavigationIconHints;
         switch (backDisposition) {
@@ -410,15 +406,17 @@
     }
 
     @Override
-    public void topAppWindowChanged(boolean showMenu) {
-        if (mNavigationBarView != null) {
+    public void topAppWindowChanged(int displayId, boolean showMenu) {
+        if (displayId == mDisplayId && mNavigationBarView != null) {
             mNavigationBarView.setMenuVisibility(showMenu);
         }
     }
 
     @Override
-    public void setWindowState(int window, int state) {
-        if (mNavigationBarView != null
+    public void setWindowState(
+            int displayId, @WindowType int window, @WindowVisibleState int state) {
+        if (displayId == mDisplayId
+                && mNavigationBarView != null
                 && window == StatusBarManager.WINDOW_NAVIGATION_BAR
                 && mNavigationBarWindowState != state) {
             mNavigationBarWindowState = state;
@@ -463,15 +461,18 @@
             mNavigationBarMode = barMode;
         }
         checkNavBarModes();
-        touchAutoHide();
+        mAutoHideController.touchAutoHide();
 
         mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
-                    true /* nbModeChanged */, mNavigationBarMode);
+                true /* nbModeChanged */, mNavigationBarMode);
     }
 
     @Override
-    public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
-            int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+    public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
+            int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+        if (displayId != mDisplayId) {
+            return;
+        }
         final int oldVal = mSystemUiVisibility;
         final int newVal = (oldVal & ~mask) | (vis & mask);
         final int diff = newVal ^ oldVal;
@@ -492,16 +493,7 @@
                     mNavigationBarMode = nbMode;
                     checkNavBarModes();
                 }
-                touchAutoHide();
-            }
-            if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
-                mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
-            }
-
-
-            // On the default display, just make StatusBar do this job.
-            if (!mIsOnDefaultDisplay) {
-                notifySystemUiVisibilityChanged(mSystemUiVisibility);
+                mAutoHideController.touchAutoHide();
             }
         }
         mLightBarController.onNavigationVisibilityChanged(
@@ -536,7 +528,10 @@
     }
 
     @Override
-    public void disable(int state1, int state2, boolean animate) {
+    public void disable(int displayId, int state1, int state2, boolean animate) {
+        if (displayId != mDisplayId) {
+            return;
+        }
         // Navigation bar flags are in both state1 and state2.
         final int masked = state1 & (StatusBarManager.DISABLE_HOME
                 | StatusBarManager.DISABLE_RECENT
@@ -664,7 +659,7 @@
     }
 
     private boolean onNavigationTouch(View v, MotionEvent event) {
-        checkUserAutoHide(event);
+        mAutoHideController.checkUserAutoHide(event);
         return false;
     }
 
@@ -807,7 +802,9 @@
     }
 
     private void onAccessibilityClick(View v) {
-        mAccessibilityManager.notifyAccessibilityButtonClicked();
+        final Display display = v.getDisplay();
+        mAccessibilityManager.notifyAccessibilityButtonClicked(
+                display != null ? display.getDisplayId() : Display.DEFAULT_DISPLAY);
     }
 
     private boolean onAccessibilityLongClick(View v) {
@@ -854,77 +851,15 @@
         mNavigationBarView.setAccessibilityButtonState(showAccessibilityButton, targetSelection);
     }
 
-    private void touchAutoHide() {
-        // There is status bar on default display. Thus the hide animations should apply on both
-        // status/navigation bar.
-        if (mIsOnDefaultDisplay) {
-            mStatusBar.touchAutoHide();
-        } else {
-            touchAutoHideInternal();
-        }
-    }
-
-    private void touchAutoHideInternal() {
-        // update transient bar autoHide.
-        if (isSemiTransparent()) {
-            scheduleAutoHide();
-        } else {
-            cancelAutoHide();
-        }
-    }
-
-    private void checkUserAutoHide(MotionEvent event) {
-        // There is status bar on default display. Thus the hide animations should apply on both
-        // status/navigation bar.
-        if (mIsOnDefaultDisplay) {
-            mStatusBar.checkUserAutoHide(event);
-        } else {
-            checkUserAutoHideInternal(event);
-        }
-    }
-
-    private void checkUserAutoHideInternal(MotionEvent event) {
-        if ((mSystemUiVisibility & View.NAVIGATION_BAR_TRANSIENT) != 0
-                // a transient bar is revealed
-                && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar.
-                && event.getX() == 0 && event.getY() == 0) { // a touch outside both bars.
-            userAutoHide();
-        }
-    }
-
-    private void userAutoHide() {
-        cancelAutoHide();
-        mHandler.postDelayed(mAutoHide, 350); // longer than app gesture -> flag clear.
-    }
-
-    private void cancelAutoHide() {
-        mHandler.removeCallbacks(mAutoHide);
-    }
-
-    private void scheduleAutoHide() {
-        cancelAutoHide();
-        mHandler.postDelayed(mAutoHide, AUTOHIDE_TIMEOUT_MS);
-    }
-
-    private void notifySystemUiVisibilityChanged(int vis) {
-        try {
-            if (mLastDispatchedSystemUiVisibility != vis) {
-                mWindowManagerService.statusBarVisibilityChanged(mDisplayId, vis);
-                mLastDispatchedSystemUiVisibility = vis;
-            }
-        } catch (RemoteException ex) {
-        }
-    }
-
     // ----- Methods that DisplayNavigationBarController talks to -----
 
-    /** Applys auto dimming animation on navigation bar when touched. */
+    /** Applies auto dimming animation on navigation bar when touched. */
     public void touchAutoDim() {
         getBarTransitions().setAutoDim(false);
         mHandler.removeCallbacks(mAutoDim);
         int state = Dependency.get(StatusBarStateController.class).getState();
         if (state != StatusBarState.KEYGUARD && state != StatusBarState.SHADE_LOCKED) {
-            mHandler.postDelayed(mAutoDim, AUTOHIDE_TIMEOUT_MS);
+            mHandler.postDelayed(mAutoDim, AUTODIM_TIMEOUT_MS);
         }
     }
 
@@ -933,6 +868,12 @@
         mLightBarController.setNavigationBar(mNavigationBarView.getLightTransitionsController());
     }
 
+    /** Sets {@link AutoHideController} to the navigation bar. */
+    public void setAutoHideController(AutoHideController autoHideController) {
+        mAutoHideController = autoHideController;
+        mAutoHideController.setNavigationBar(this);
+    }
+
     public boolean isSemiTransparent() {
         return mNavigationBarMode == MODE_SEMI_TRANSPARENT;
     }
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 2fc7b78..8bf1c58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -69,6 +69,7 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.assist.AssistManager;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.statusbar.phone.NavGesture;
 import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
@@ -156,6 +157,7 @@
     private QuickStepAction mQuickStepAction;
     private NavigationBackAction mBackAction;
     private QuickSwitchAction mQuickSwitchAction;
+    private NavigationAssistantAction mAssistantAction;
 
     /**
      * Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -366,8 +368,12 @@
         return mBarTransitions.getLightTransitionsController();
     }
 
-    public void setComponents(NotificationPanelView panel) {
+    public void setComponents(NotificationPanelView panel, AssistManager assistManager) {
         mPanelView = panel;
+        if (mAssistantAction == null) {
+            mAssistantAction = new NavigationAssistantAction(this, mOverviewProxyService,
+                    assistManager);
+        }
         if (mGestureHelper instanceof QuickStepController) {
             ((QuickStepController) mGestureHelper).setComponents(this);
             updateNavigationGestures();
@@ -398,6 +404,10 @@
                 return mBackAction;
             case NavigationPrototypeController.ACTION_QUICKSWITCH:
                 return mQuickSwitchAction;
+            case NavigationPrototypeController.ACTION_ASSISTANT:
+                return mAssistantAction;
+            case NavigationPrototypeController.ACTION_NOTHING:
+                return null;
             default:
                 return defaultAction;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
index 8c57fc3..a5d9382 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
@@ -24,6 +24,7 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.provider.Settings;
 import android.view.MotionEvent;
 
 import com.android.systemui.recents.OverviewProxyService;
@@ -32,6 +33,9 @@
  * A gesture action that would be triggered and reassigned by {@link QuickStepController}
  */
 public abstract class NavigationGestureAction {
+    private static final String ENABLE_TASK_STABILIZER_FLAG = "ENABLE_TASK_STABILIZER";
+
+    static private boolean sLastTaskStabilizationFlag;
 
     protected final NavigationBarView mNavigationBarView;
     protected final OverviewProxyService mProxySender;
@@ -45,6 +49,9 @@
             @NonNull OverviewProxyService service) {
         mNavigationBarView = navigationBarView;
         mProxySender = service;
+        sLastTaskStabilizationFlag = Settings.Global.getInt(
+                mNavigationBarView.getContext().getContentResolver(),
+                ENABLE_TASK_STABILIZER_FLAG, 0) != 0;
     }
 
     /**
@@ -74,6 +81,15 @@
      */
     public void startGesture(MotionEvent event) {
         mIsActive = true;
+
+        // Tell launcher that this action requires a stable task list or not
+        boolean flag = requiresStableTaskList();
+        if (flag != sLastTaskStabilizationFlag) {
+            Settings.Global.putInt(mNavigationBarView.getContext().getContentResolver(),
+                    ENABLE_TASK_STABILIZER_FLAG, flag ? 1 : 0);
+            sLastTaskStabilizationFlag = flag;
+        }
+
         onGestureStart(event);
     }
 
@@ -146,6 +162,13 @@
      */
     public abstract boolean isEnabled();
 
+    /**
+     * @return action requires a stable task list from launcher
+     */
+    protected boolean requiresStableTaskList() {
+        return false;
+    }
+
     protected void onDarkIntensityChange(float intensity) {
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index fb6254b..a09e585 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -22,7 +22,6 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -36,18 +35,20 @@
     private static final String HIDE_BACK_BUTTON_SETTING = "quickstepcontroller_hideback";
     private static final String HIDE_HOME_BUTTON_SETTING = "quickstepcontroller_hidehome";
 
-    static final String NAVBAR_EXPERIMENTS_DISABLED = "navbarexperiments_disabled";
     private final String GESTURE_MATCH_SETTING = "quickstepcontroller_gesture_match_map";
     public static final String NAV_COLOR_ADAPT_ENABLE_SETTING = "navbar_color_adapt_enable";
 
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ACTION_DEFAULT, ACTION_QUICKSTEP, ACTION_QUICKSCRUB, ACTION_BACK})
+    @IntDef({ACTION_DEFAULT, ACTION_QUICKSTEP, ACTION_QUICKSCRUB, ACTION_BACK,
+            ACTION_QUICKSWITCH, ACTION_NOTHING, ACTION_ASSISTANT})
     @interface GestureAction {}
     static final int ACTION_DEFAULT = 0;
     static final int ACTION_QUICKSTEP = 1;
     static final int ACTION_QUICKSCRUB = 2;
     static final int ACTION_BACK = 3;
     static final int ACTION_QUICKSWITCH = 4;
+    static final int ACTION_NOTHING = 5;
+    static final int ACTION_ASSISTANT = 6;
 
     private OnPrototypeChangedListener mListener;
 
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 2a11c26..d022808 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java
@@ -97,10 +97,11 @@
         }
         return mClickableChildren
                 .stream()
-                .filter(v -> v.isAttachedToWindow())
+                .filter(View::isAttachedToWindow)
                 .map(v -> new Pair<>(distance(v, event), v))
                 .min(Comparator.comparingInt(f -> f.first))
-                .get().second;
+                .map(data -> data.second)
+                .orElse(null);
     }
 
     private int distance(View v, MotionEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index 3839ed5..d364356 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -31,9 +31,9 @@
 import com.android.systemui.statusbar.InflationTask;
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.AsyncInflationTask;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
 import com.android.systemui.statusbar.phone.NotificationGroupManager.NotificationGroup;
@@ -108,7 +108,7 @@
      * @param entry notification to check
      * @return true if the entry was transferred to and should inflate + alert
      */
-    public boolean isAlertTransferPending(@NonNull Entry entry) {
+    public boolean isAlertTransferPending(@NonNull NotificationEntry entry) {
         PendingAlertInfo alertInfo = mPendingAlerts.get(entry.key);
         return alertInfo != null && alertInfo.isStillValid();
     }
@@ -172,16 +172,16 @@
     };
 
     @Override
-    public void onAmbientStateChanged(Entry entry, boolean isAmbient) {
+    public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
         onAlertStateChanged(entry, isAmbient, mAmbientPulseManager);
     }
 
     @Override
-    public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
+    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
         onAlertStateChanged(entry, isHeadsUp, mHeadsUpManager);
     }
 
-    private void onAlertStateChanged(Entry entry, boolean isAlerting,
+    private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting,
             AlertingNotificationManager alertManager) {
         if (isAlerting && mGroupManager.isSummaryOfSuppressedGroup(entry.notification)) {
             handleSuppressedSummaryAlerted(entry, alertManager);
@@ -193,7 +193,7 @@
         // Called when a new notification has been posted but is not inflated yet. We use this to
         // see as early as we can if we need to abort a transfer.
         @Override
-        public void onPendingEntryAdded(Entry entry) {
+        public void onPendingEntryAdded(NotificationEntry entry) {
             String groupKey = mGroupManager.getGroupKey(entry.notification);
             GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey);
             if (groupAlertEntry != null) {
@@ -204,7 +204,7 @@
         // Called when the entry's reinflation has finished. If there is an alert pending, we
         // then show the alert.
         @Override
-        public void onEntryReinflated(Entry entry) {
+        public void onEntryReinflated(NotificationEntry entry) {
             PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.key);
             if (alertInfo != null) {
                 if (alertInfo.isStillValid()) {
@@ -219,16 +219,13 @@
 
         @Override
         public void onEntryRemoved(
-                @Nullable Entry entry,
-                String key,
-                StatusBarNotification old,
+                @Nullable NotificationEntry entry,
                 NotificationVisibility visibility,
-                boolean lifetimeExtended,
                 boolean removedByUser) {
             // Removes any alerts pending on this entry. Note that this will not stop any inflation
             // tasks started by a transfer, so this should only be used as clean-up for when
             // inflation is stopped and the pending alert no longer needs to happen.
-            mPendingAlerts.remove(key);
+            mPendingAlerts.remove(entry.key);
         }
     };
 
@@ -244,8 +241,8 @@
             return 0;
         }
         int number = 0;
-        Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator();
-        for (Entry entry : values) {
+        Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator();
+        for (NotificationEntry entry : values) {
             if (isPendingNotificationInGroup(entry, group) && onlySummaryAlerts(entry)) {
                 number++;
             }
@@ -263,8 +260,8 @@
         if (mEntryManager == null) {
             return false;
         }
-        Iterable<Entry> values = mEntryManager.getPendingNotificationsIterator();
-        for (Entry entry : values) {
+        Iterable<NotificationEntry> values = mEntryManager.getPendingNotificationsIterator();
+        for (NotificationEntry entry : values) {
             if (isPendingNotificationInGroup(entry, group)) {
                 return true;
             }
@@ -279,7 +276,7 @@
      * @param group group to check
      * @return true if the notification will add to the group, false o/w
      */
-    private boolean isPendingNotificationInGroup(@NonNull Entry entry,
+    private boolean isPendingNotificationInGroup(@NonNull NotificationEntry entry,
             @NonNull NotificationGroup group) {
         String groupKey = mGroupManager.getGroupKey(group.summary.notification);
         return mGroupManager.isGroupChild(entry.notification)
@@ -296,7 +293,7 @@
      * @param summary the summary that is suppressed and alerting
      * @param alertManager the alert manager that manages the alerting summary
      */
-    private void handleSuppressedSummaryAlerted(@NonNull Entry summary,
+    private void handleSuppressedSummaryAlerted(@NonNull NotificationEntry summary,
             @NonNull AlertingNotificationManager alertManager) {
         StatusBarNotification sbn = summary.notification;
         GroupAlertEntry groupAlertEntry =
@@ -312,7 +309,7 @@
             return;
         }
 
-        Entry child = mGroupManager.getLogicalChildren(summary.notification).iterator().next();
+        NotificationEntry child = mGroupManager.getLogicalChildren(summary.notification).iterator().next();
         if (child != null) {
             if (child.getRow().keepInParent()
                     || child.isRowRemoved()
@@ -336,7 +333,7 @@
      * @param toEntry entry to transfer to
      * @param alertManager alert manager for the alert type
      */
-    private void transferAlertState(@NonNull Entry fromEntry, @NonNull Entry toEntry,
+    private void transferAlertState(@NonNull NotificationEntry fromEntry, @NonNull NotificationEntry toEntry,
             @NonNull AlertingNotificationManager alertManager) {
         alertManager.removeNotification(fromEntry.key, true /* releaseImmediately */);
         alertNotificationWhenPossible(toEntry, alertManager);
@@ -356,13 +353,13 @@
     private void checkShouldTransferBack(@NonNull GroupAlertEntry groupAlertEntry) {
         if (SystemClock.elapsedRealtime() - groupAlertEntry.mLastAlertTransferTime
                 < ALERT_TRANSFER_TIMEOUT) {
-            Entry summary = groupAlertEntry.mGroup.summary;
+            NotificationEntry summary = groupAlertEntry.mGroup.summary;
             AlertingNotificationManager alertManager = getActiveAlertManager();
 
             if (!onlySummaryAlerts(summary)) {
                 return;
             }
-            ArrayList<Entry> children = mGroupManager.getLogicalChildren(summary.notification);
+            ArrayList<NotificationEntry> children = mGroupManager.getLogicalChildren(summary.notification);
             int numChildren = children.size();
             int numPendingChildren = getPendingChildrenNotAlerting(groupAlertEntry.mGroup);
             numChildren += numPendingChildren;
@@ -371,7 +368,7 @@
             }
             boolean releasedChild = false;
             for (int i = 0; i < children.size(); i++) {
-                Entry entry = children.get(i);
+                NotificationEntry entry = children.get(i);
                 if (onlySummaryAlerts(entry) && alertManager.isAlerting(entry.key)) {
                     releasedChild = true;
                     alertManager.removeNotification(entry.key, true /* releaseImmediately */);
@@ -402,7 +399,7 @@
      * @param entry entry to show
      * @param alertManager alert manager for the alert type
      */
-    private void alertNotificationWhenPossible(@NonNull Entry entry,
+    private void alertNotificationWhenPossible(@NonNull NotificationEntry entry,
             @NonNull AlertingNotificationManager alertManager) {
         @InflationFlag int contentFlag = alertManager.getContentFlag();
         if (!entry.getRow().isInflationFlagSet(contentFlag)) {
@@ -422,7 +419,7 @@
         return mIsDozing ? mAmbientPulseManager : mHeadsUpManager;
     }
 
-    private boolean onlySummaryAlerts(Entry entry) {
+    private boolean onlySummaryAlerts(NotificationEntry entry) {
         return entry.notification.getNotification().getGroupAlertBehavior()
                 == Notification.GROUP_ALERT_SUMMARY;
     }
@@ -442,7 +439,7 @@
          * the transfer is still valid if the notification is updated.
          */
         final StatusBarNotification mOriginalNotification;
-        final Entry mEntry;
+        final NotificationEntry mEntry;
 
         /**
          * The notification is still pending inflation but we've decided that we no longer need
@@ -453,7 +450,7 @@
          */
         boolean mAbortOnInflation;
 
-        PendingAlertInfo(Entry entry, AlertingNotificationManager alertManager) {
+        PendingAlertInfo(NotificationEntry entry, AlertingNotificationManager alertManager) {
             mOriginalNotification = entry.notification;
             mEntry = entry;
             mAlertManager = alertManager;
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 3c1c076..bb9e418 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -27,7 +27,7 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -97,7 +97,7 @@
         }
     }
 
-    public void onEntryRemoved(NotificationData.Entry removed) {
+    public void onEntryRemoved(NotificationEntry removed) {
         onEntryRemovedInternal(removed, removed.notification);
         mIsolatedEntries.remove(removed.key);
     }
@@ -109,7 +109,7 @@
      * @param sbn the notification the entry has, which doesn't need to be the same as it's internal
      *            notification
      */
-    private void onEntryRemovedInternal(NotificationData.Entry removed,
+    private void onEntryRemovedInternal(NotificationEntry removed,
             final StatusBarNotification sbn) {
         String groupKey = getGroupKey(sbn);
         final NotificationGroup group = mGroupMap.get(groupKey);
@@ -136,7 +136,7 @@
         }
     }
 
-    public void onEntryAdded(final NotificationData.Entry added) {
+    public void onEntryAdded(final NotificationEntry added) {
         if (added.isRowRemoved()) {
             added.setDebugThrowable(new Throwable());
         }
@@ -152,7 +152,7 @@
             }
         }
         if (isGroupChild) {
-            NotificationData.Entry existing = group.children.get(added.key);
+            NotificationEntry existing = group.children.get(added.key);
             if (existing != null && existing != added) {
                 Throwable existingThrowable = existing.getDebugThrowable();
                 Log.wtf(TAG, "Inconsistent entries found with the same key " + added.key
@@ -169,9 +169,9 @@
             group.expanded = added.areChildrenExpanded();
             updateSuppression(group);
             if (!group.children.isEmpty()) {
-                ArrayList<NotificationData.Entry> childrenCopy
+                ArrayList<NotificationEntry> childrenCopy
                         = new ArrayList<>(group.children.values());
-                for (NotificationData.Entry child : childrenCopy) {
+                for (NotificationEntry child : childrenCopy) {
                     onEntryBecomingChild(child);
                 }
                 for (OnGroupChangeListener listener : mListeners) {
@@ -181,7 +181,7 @@
         }
     }
 
-    private void onEntryBecomingChild(NotificationData.Entry entry) {
+    private void onEntryBecomingChild(NotificationEntry entry) {
         if (shouldIsolate(entry)) {
             isolateNotification(entry);
         }
@@ -221,7 +221,7 @@
         return count;
     }
 
-    private NotificationData.Entry getIsolatedChild(String groupKey) {
+    private NotificationEntry getIsolatedChild(String groupKey) {
         for (StatusBarNotification sbn : mIsolatedEntries.values()) {
             if (sbn.getGroupKey().equals(groupKey) && isIsolated(sbn)) {
                 return mGroupMap.get(sbn.getKey()).summary;
@@ -230,7 +230,7 @@
         return null;
     }
 
-    public void onEntryUpdated(NotificationData.Entry entry,
+    public void onEntryUpdated(NotificationEntry entry,
             StatusBarNotification oldNotification) {
         String oldKey = oldNotification.getGroupKey();
         String newKey = entry.notification.getGroupKey();
@@ -267,7 +267,7 @@
         if (!isOnlyChild(sbn)) {
             return false;
         }
-        NotificationData.Entry logicalGroupSummary = getLogicalGroupSummary(sbn);
+        NotificationEntry logicalGroupSummary = getLogicalGroupSummary(sbn);
         return logicalGroupSummary != null
                 && !logicalGroupSummary.notification.equals(sbn);
     }
@@ -343,7 +343,7 @@
      * Get the summary of a specified status bar notification. For isolated notification this return
      * itself.
      */
-    public NotificationData.Entry getGroupSummary(StatusBarNotification sbn) {
+    public NotificationEntry getGroupSummary(StatusBarNotification sbn) {
         return getGroupSummary(getGroupKey(sbn));
     }
 
@@ -352,12 +352,12 @@
      * but the logical summary, i.e when a child is isolated, it still returns the summary as if
      * it wasn't isolated.
      */
-    public NotificationData.Entry getLogicalGroupSummary(StatusBarNotification sbn) {
+    public NotificationEntry getLogicalGroupSummary(StatusBarNotification sbn) {
         return getGroupSummary(sbn.getGroupKey());
     }
 
     @Nullable
-    private NotificationData.Entry getGroupSummary(String groupKey) {
+    private NotificationEntry getGroupSummary(String groupKey) {
         NotificationGroup group = mGroupMap.get(groupKey);
         //TODO: see if this can become an Entry
         return group == null ? null
@@ -371,13 +371,13 @@
      * @param summary summary of a group
      * @return list of the children
      */
-    public ArrayList<NotificationData.Entry> getLogicalChildren(StatusBarNotification summary) {
+    public ArrayList<NotificationEntry> getLogicalChildren(StatusBarNotification summary) {
         NotificationGroup group = mGroupMap.get(summary.getGroupKey());
         if (group == null) {
             return null;
         }
-        ArrayList<NotificationData.Entry> children = new ArrayList<>(group.children.values());
-        NotificationData.Entry isolatedChild = getIsolatedChild(summary.getGroupKey());
+        ArrayList<NotificationEntry> children = new ArrayList<>(group.children.values());
+        NotificationEntry isolatedChild = getIsolatedChild(summary.getGroupKey());
         if (isolatedChild != null) {
             children.add(isolatedChild);
         }
@@ -443,24 +443,24 @@
     }
 
     @Override
-    public void onHeadsUpPinned(NotificationData.Entry entry) {
+    public void onHeadsUpPinned(NotificationEntry entry) {
     }
 
     @Override
-    public void onHeadsUpUnPinned(NotificationData.Entry entry) {
+    public void onHeadsUpUnPinned(NotificationEntry entry) {
     }
 
     @Override
-    public void onAmbientStateChanged(NotificationData.Entry entry, boolean isAmbient) {
+    public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
         onAlertStateChanged(entry, isAmbient);
     }
 
     @Override
-    public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
         onAlertStateChanged(entry, isHeadsUp);
     }
 
-    private void onAlertStateChanged(NotificationData.Entry entry, boolean isAlerting) {
+    private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting) {
         if (isAlerting) {
             if (shouldIsolate(entry)) {
                 isolateNotification(entry);
@@ -479,7 +479,7 @@
      * @return true if the entry should be isolated
      */
 
-    private boolean shouldIsolate(NotificationData.Entry entry) {
+    private boolean shouldIsolate(NotificationEntry entry) {
         StatusBarNotification sbn = entry.notification;
         NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
         if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {
@@ -499,7 +499,7 @@
      *
      * @param entry the notification to isolate
      */
-    private void isolateNotification(NotificationData.Entry entry) {
+    private void isolateNotification(NotificationEntry entry) {
         StatusBarNotification sbn = entry.notification;
 
         // We will be isolated now, so lets update the groups
@@ -523,7 +523,7 @@
      *
      * @param entry the notification to un-isolate
      */
-    private void stopIsolatingNotification(NotificationData.Entry entry) {
+    private void stopIsolatingNotification(NotificationEntry entry) {
         StatusBarNotification sbn = entry.notification;
         if (mIsolatedEntries.containsKey(sbn.getKey())) {
             // not isolated anymore, we need to update the groups
@@ -564,8 +564,8 @@
     }
 
     public static class NotificationGroup {
-        public final HashMap<String, NotificationData.Entry> children = new HashMap<>();
-        public NotificationData.Entry summary;
+        public final HashMap<String, NotificationEntry> children = new HashMap<>();
+        public NotificationEntry summary;
         public boolean expanded;
         /**
          * Is this notification group suppressed, i.e its summary is hidden
@@ -580,7 +580,7 @@
                             ? Log.getStackTraceString(summary.getDebugThrowable())
                             : "");
             result += "\n    children size: " + children.size();
-            for (NotificationData.Entry child : children.values()) {
+            for (NotificationEntry child : children.values()) {
                 result += "\n      " + child.notification
                 + (child.getDebugThrowable() != null
                         ? Log.getStackTraceString(child.getDebugThrowable())
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 056c8a7..077fcda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -23,9 +23,10 @@
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.tuner.TunerService;
 
@@ -36,13 +37,15 @@
  * A controller for the space in the status bar to the left of the system icons. This area is
  * normally reserved for notifications.
  */
-public class NotificationIconAreaController implements DarkReceiver {
+public class NotificationIconAreaController implements DarkReceiver,
+        StatusBarStateController.StateListener {
 
     public static final String LOW_PRIORITY = "low_priority";
 
     private final ContrastColorUtil mContrastColorUtil;
     private final NotificationEntryManager mEntryManager;
     private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
+    private final StatusBarStateController mStatusBarStateController;
     private final TunerService.Tunable mTunable = new TunerService.Tunable() {
         @Override
         public void onTuningChanged(String key, String newValue) {
@@ -86,11 +89,14 @@
     private final ViewClippingUtil.ClippingParameters mClippingParameters =
             view -> view instanceof StatusBarWindowView;
 
-    public NotificationIconAreaController(Context context, StatusBar statusBar) {
+    public NotificationIconAreaController(Context context, StatusBar statusBar,
+            StatusBarStateController statusBarStateController) {
         mStatusBar = statusBar;
         mContrastColorUtil = ContrastColorUtil.getInstance(context);
         mContext = context;
         mEntryManager = Dependency.get(NotificationEntryManager.class);
+        mStatusBarStateController = statusBarStateController;
+        mStatusBarStateController.addCallback(this);
 
         Dependency.get(TunerService.class).addTunable(mTunable, LOW_PRIORITY);
 
@@ -182,7 +188,7 @@
         return mStatusBar.getStatusBarHeight();
     }
 
-    protected boolean shouldShowNotificationIcon(NotificationData.Entry entry,
+    protected boolean shouldShowNotificationIcon(NotificationEntry entry,
             boolean showAmbient, boolean showLowPriority, boolean hideDismissed,
             boolean hideRepliedMessages) {
         if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
@@ -247,7 +253,7 @@
      * @param hideDismissed should dismissed icons be hidden
      * @param hideRepliedMessages should messages that have been replied to be hidden
      */
-    private void updateIconsForLayout(Function<NotificationData.Entry, StatusBarIconView> function,
+    private void updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function,
             NotificationIconContainer hostLayout, boolean showAmbient, boolean showLowPriority,
             boolean hideDismissed, boolean hideRepliedMessages) {
         ArrayList<StatusBarIconView> toShow = new ArrayList<>(
@@ -257,7 +263,7 @@
         for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) {
             View view = mNotificationScrollLayout.getChildAt(i);
             if (view instanceof ExpandableNotificationRow) {
-                NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry();
+                NotificationEntry ent = ((ExpandableNotificationRow) view).getEntry();
                 if (shouldShowNotificationIcon(ent, showAmbient, showLowPriority, hideDismissed,
                         hideRepliedMessages)) {
                     toShow.add(function.apply(ent));
@@ -373,24 +379,6 @@
         v.setDecorColor(mIconTint);
     }
 
-    /**
-     * Dark amount, from 0 to 1, representing being awake or in AOD.
-     */
-    public void setDarkAmount(float darkAmount) {
-        mDarkAmount = darkAmount;
-        if (darkAmount == 0 || darkAmount == 1) {
-            ViewClippingUtil.setClippingDeactivated(mNotificationIcons, darkAmount != 0,
-                    mClippingParameters);
-        }
-        dozeTimeTick();
-
-        boolean fullyDark = darkAmount == 1f;
-        if (mFullyDark != fullyDark) {
-            mFullyDark = fullyDark;
-            updateShelfIcons();
-        }
-    }
-
     public void setDark(boolean dark) {
         mNotificationIcons.setDark(dark, false, 0);
         mShelfIcons.setDark(dark, false, 0);
@@ -408,10 +396,45 @@
      * Moves icons whenever the device wakes up in AOD, to avoid burn in.
      */
     public void dozeTimeTick() {
+        if (mNotificationIcons.getVisibility() != View.VISIBLE) {
+            return;
+        }
+
+        if (mDarkAmount == 0 && !mStatusBarStateController.isDozing()) {
+            mNotificationIcons.setTranslationX(0);
+            mNotificationIcons.setTranslationY(0);
+            return;
+        }
+
         int yOffset = (mKeyguardStatusBarHeight - getHeight()) / 2;
         int translationX = getBurnInOffset(mBurnInOffset, true /* xAxis */);
         int translationY = getBurnInOffset(mBurnInOffset, false /* xAxis */) + yOffset;
-        mNotificationIcons.setTranslationX(translationX * mDarkAmount);
-        mNotificationIcons.setTranslationY(translationY * mDarkAmount);
+        mNotificationIcons.setTranslationX(translationX);
+        mNotificationIcons.setTranslationY(translationY);
+    }
+
+    @Override
+    public void onDozingChanged(boolean isDozing) {
+        dozeTimeTick();
+    }
+
+    @Override
+    public void onDozeAmountChanged(float linear, float eased) {
+        boolean wasOrIsAwake = mDarkAmount == 0 || linear == 0;
+        boolean wasOrIsDozing = mDarkAmount == 1 || linear == 1;
+        mDarkAmount = linear;
+        if (wasOrIsAwake) {
+            ViewClippingUtil.setClippingDeactivated(mNotificationIcons, mDarkAmount != 0,
+                    mClippingParameters);
+        }
+        if (wasOrIsAwake || wasOrIsDozing) {
+            dozeTimeTick();
+        }
+
+        boolean fullyDark = mDarkAmount == 1f;
+        if (mFullyDark != fullyDark) {
+            mFullyDark = fullyDark;
+            updateShelfIcons();
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 964b2210..009afca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -128,6 +128,7 @@
         }
     }.setDuration(CONTENT_FADE_DURATION);
 
+    private static final int MAX_VISIBLE_ICONS_WHEN_DARK = 5;
     public static final int MAX_STATIC_ICONS = 4;
     private static final int MAX_DOTS = 1;
 
@@ -371,7 +372,8 @@
         float translationX = getActualPaddingStart();
         int firstOverflowIndex = -1;
         int childCount = getChildCount();
-        int maxVisibleIcons = mIsStaticLayout ? MAX_STATIC_ICONS : childCount;
+        int maxVisibleIcons = mDark ? MAX_VISIBLE_ICONS_WHEN_DARK :
+                mIsStaticLayout ? MAX_STATIC_ICONS : childCount;
         float layoutEnd = getLayoutEnd();
         float overflowStart = getMaxOverflowStart();
         mVisualOverflowStart = 0;
@@ -387,6 +389,9 @@
             boolean forceOverflow = mSpeedBumpIndex != -1 && i >= mSpeedBumpIndex
                     && iconState.iconAppearAmount > 0.0f || i >= maxVisibleIcons;
             boolean noOverflowAfter = i == childCount - 1;
+            float drawingScale = mDark && view instanceof StatusBarIconView
+                    ? ((StatusBarIconView) view).getIconScaleFullyDark()
+                    : 1f;
             if (mOpenedAmount != 0.0f) {
                 noOverflowAfter = noOverflowAfter && !hasAmbient && !forceOverflow;
             }
@@ -402,7 +407,7 @@
                     mVisualOverflowStart = Math.min(translationX, mVisualOverflowStart);
                 }
             }
-            translationX += iconState.iconAppearAmount * view.getWidth();
+            translationX += iconState.iconAppearAmount * view.getWidth() * drawingScale;
         }
         mNumDots = 0;
         if (firstOverflowIndex != -1) {
@@ -432,6 +437,32 @@
             mFirstVisibleIconState = mIconStates.get(getChildAt(0));
         }
 
+        boolean center = mDark;
+        if (center && translationX < getLayoutEnd()) {
+            float initialTranslation =
+                    mFirstVisibleIconState == null ? 0 : mFirstVisibleIconState.xTranslation;
+
+            float contentWidth = 0;
+            if (mLastVisibleIconState != null) {
+                contentWidth = mLastVisibleIconState.xTranslation + mIconSize;
+                contentWidth = Math.min(getWidth(), contentWidth) - initialTranslation;
+            }
+            float availableSpace = getLayoutEnd() - getActualPaddingStart();
+            float delta = (availableSpace - contentWidth) / 2;
+
+            if (firstOverflowIndex != -1) {
+                // If we have an overflow, only count those half for centering because the dots
+                // don't have a lot of visual weight.
+                float deltaIgnoringOverflow = (getLayoutEnd() - mVisualOverflowStart) / 2;
+                delta = (deltaIgnoringOverflow + delta) / 2;
+            }
+            for (int i = 0; i < childCount; i++) {
+                View view = getChildAt(i);
+                IconState iconState = mIconStates.get(view);
+                iconState.xTranslation += delta;
+            }
+        }
+
         if (isLayoutRtl()) {
             for (int i = 0; i < childCount; i++) {
                 View view = getChildAt(i);
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 1b18c6c..0d5ebb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -50,6 +50,7 @@
 import android.view.accessibility.AccessibilityManager;
 import android.widget.FrameLayout;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.KeyguardClockSwitch;
@@ -76,9 +77,9 @@
 import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -140,9 +141,11 @@
     private KeyguardAffordanceHelper mAffordanceHelper;
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
     private KeyguardStatusBarView mKeyguardStatusBar;
+    private ViewGroup mBigClockContainer;
     private QS mQs;
     private FrameLayout mQsFrame;
-    private KeyguardStatusView mKeyguardStatusView;
+    @VisibleForTesting
+    protected KeyguardStatusView mKeyguardStatusView;
     private View mQsNavbarScrim;
     protected NotificationsQuickSettingsContainer mNotificationContainerParent;
     protected NotificationStackScrollLayout mNotificationStackScroller;
@@ -312,6 +315,7 @@
             Dependency.get(NotificationLockscreenUserManager.class);
     private final ShadeController mShadeController =
             Dependency.get(ShadeController.class);
+    private int mDisplayId;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -323,6 +327,14 @@
         mAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
         setPanelAlpha(255, false /* animate */);
         mCommandQueue = getComponent(context, CommandQueue.class);
+        mDisplayId = context.getDisplayId();
+    }
+
+    /**
+     * Returns if there's a custom clock being presented.
+     */
+    public boolean hasCustomClock() {
+        return mKeyguardStatusView.hasCustomClock();
     }
 
     private void setStatusBar(StatusBar bar) {
@@ -337,8 +349,8 @@
         mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
 
         KeyguardClockSwitch keyguardClockSwitch = findViewById(R.id.keyguard_clock_container);
-        ViewGroup bigClockContainer = findViewById(R.id.big_clock_container);
-        keyguardClockSwitch.setBigClockContainer(bigClockContainer);
+        mBigClockContainer = findViewById(R.id.big_clock_container);
+        keyguardClockSwitch.setBigClockContainer(mBigClockContainer);
 
         mNotificationContainerParent = findViewById(R.id.notification_container_parent);
         mNotificationStackScroller = findViewById(R.id.notification_stack_scroller);
@@ -567,18 +579,23 @@
                     mKeyguardStatusView.getHeight(),
                     mInterpolatedDarkAmount,
                     mStatusBar.isKeyguardCurrentlySecure(),
-                    mPulsing,
                     mEmptyDragAmount);
             mClockPositionAlgorithm.run(mClockPositionResult);
             PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.X,
                     mClockPositionResult.clockX, CLOCK_ANIMATION_PROPERTIES, animateClock);
             PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.Y,
                     mClockPositionResult.clockY, CLOCK_ANIMATION_PROPERTIES, animateClock);
+            // Move big clock up while pulling up the bouncer
+            PropertyAnimator.setProperty(mBigClockContainer, AnimatableProperty.Y,
+                    MathUtils.lerp(-mBigClockContainer.getHeight(), 0,
+                          Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(getExpandedFraction())),
+                    CLOCK_ANIMATION_PROPERTIES, animateClock);
             updateClock();
             stackScrollerPadding = mClockPositionResult.stackScrollerPadding;
         }
         mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
-        mNotificationStackScroller.setAntiBurnInOffsetX(mClockPositionResult.clockX);
+        int burnInXOffset = mPulsing ? 0 : mClockPositionResult.clockX;
+        mNotificationStackScroller.setAntiBurnInOffsetX(burnInXOffset);
 
         mStackScrollerMeasuringPass++;
         requestScrollerTopPaddingUpdate(animate);
@@ -954,7 +971,7 @@
             handled = true;
         }
         handled |= super.onTouchEvent(event);
-        return mDozing ? handled : true;
+        return !mDozing || mPulsing || handled;
     }
 
     private boolean handleQsTouch(MotionEvent event) {
@@ -1231,7 +1248,7 @@
             updateDozingVisibilities(false /* animate */);
         }
 
-        resetVerticalPanelPosition();
+        resetHorizontalPanelPosition();
         updateQsState();
     }
 
@@ -2041,7 +2058,7 @@
         super.onConfigurationChanged(newConfig);
         mAffordanceHelper.onConfigurationChanged();
         if (newConfig.orientation != mLastOrientation) {
-            resetVerticalPanelPosition();
+            resetHorizontalPanelPosition();
         }
         mLastOrientation = newConfig.orientation;
     }
@@ -2487,12 +2504,12 @@
     }
 
     @Override
-    public void onHeadsUpPinned(NotificationData.Entry entry) {
+    public void onHeadsUpPinned(NotificationEntry entry) {
         mNotificationStackScroller.generateHeadsUpAnimation(entry.getHeadsUpAnimationView(), true);
     }
 
     @Override
-    public void onHeadsUpUnPinned(NotificationData.Entry entry) {
+    public void onHeadsUpUnPinned(NotificationEntry entry) {
 
         // When we're unpinning the notification via active edge they remain heads-upped,
         // we need to make sure that an animation happens in this case, otherwise the notification
@@ -2505,7 +2522,7 @@
     }
 
     @Override
-    public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
+    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
         mNotificationStackScroller.generateHeadsUpAnimation(entry, isHeadsUp);
     }
 
@@ -2527,7 +2544,7 @@
     @Override
     protected void onClosingFinished() {
         super.onClosingFinished();
-        resetVerticalPanelPosition();
+        resetHorizontalPanelPosition();
         setClosingWithAlphaFadeout(false);
     }
 
@@ -2544,7 +2561,7 @@
      */
     protected void updateVerticalPanelPosition(float x) {
         if (mNotificationStackScroller.getWidth() * 1.75f > getWidth()) {
-            resetVerticalPanelPosition();
+            resetHorizontalPanelPosition();
             return;
         }
         float leftMost = mPositionMinSideMargin + mNotificationStackScroller.getWidth() / 2;
@@ -2554,16 +2571,17 @@
             x = getWidth() / 2;
         }
         x = Math.min(rightMost, Math.max(leftMost, x));
-        setVerticalPanelTranslation(x -
-                (mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2));
+        float center =
+                mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2;
+        setHorizontalPanelTranslation(x - center);
     }
 
-    private void resetVerticalPanelPosition() {
-        setVerticalPanelTranslation(0f);
+    private void resetHorizontalPanelPosition() {
+        setHorizontalPanelTranslation(0f);
     }
 
-    protected void setVerticalPanelTranslation(float translation) {
-        mNotificationStackScroller.setVerticalPanelTranslation(translation);
+    protected void setHorizontalPanelTranslation(float translation) {
+        mNotificationStackScroller.setHorizontalPanelTranslation(translation);
         mQsFrame.setTranslationX(translation);
         int size = mVerticalTranslationListener.size();
         for (int i = 0; i < size; i++) {
@@ -2596,7 +2614,7 @@
         }
         if (showIconsWhenExpanded != mShowIconsWhenExpanded) {
             mShowIconsWhenExpanded = showIconsWhenExpanded;
-            mCommandQueue.recomputeDisableFlags(false);
+            mCommandQueue.recomputeDisableFlags(mDisplayId, false);
         }
     }
 
@@ -2771,6 +2789,9 @@
         if (dozing == mDozing) return;
         mDozing = dozing;
         mNotificationStackScroller.setDark(mDozing, animate, wakeUpTouchLocation);
+        if (mDozing) {
+            mNotificationStackScroller.setShowDarkShelf(!hasCustomClock());
+        }
 
         if (mBarState == StatusBarState.KEYGUARD
                 || mBarState == StatusBarState.SHADE_LOCKED) {
@@ -2803,8 +2824,13 @@
         if (animatePulse) {
             mAnimateNextPositionUpdate = true;
         }
+        // Do not animate the clock when waking up from a pulse.
+        // The height callback will take care of pushing the clock to the right position.
+        if (!mPulsing && !mDozing) {
+            mAnimateNextPositionUpdate = false;
+        }
         mNotificationStackScroller.setPulsing(pulsing, animatePulse);
-        mKeyguardStatusView.setPulsing(pulsing, animatePulse);
+        mKeyguardStatusView.setPulsing(pulsing);
         mKeyguardBottomArea.setPulsing(pulsing, animatePulse);
     }
 
@@ -2856,7 +2882,7 @@
             if (hideIcons != mHideIconsDuringNotificationLaunch) {
                 mHideIconsDuringNotificationLaunch = hideIcons;
                 if (!hideIcons) {
-                    mCommandQueue.recomputeDisableFlags(true /* animate */);
+                    mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 021b430..f17145d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -142,8 +142,8 @@
     private boolean mIgnoreXTouchSlop;
     private boolean mExpandLatencyTracking;
     protected final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
-    protected final StatusBarStateController
-            mStatusBarStateController = Dependency.get(StatusBarStateController.class);
+    protected final StatusBarStateController mStatusBarStateController =
+            Dependency.get(StatusBarStateController.class);
 
     protected void onExpandingFinished() {
         mBar.onExpandingFinished();
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 d6f2fd7..43c35f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -736,9 +736,12 @@
             };
 
     @Override
-    public void appTransitionStarting(long startTime, long duration, boolean forced) {
-        updateManagedProfile();
-        updateForegroundInstantApps();
+    public void appTransitionStarting(int displayId, long startTime, long duration,
+            boolean forced) {
+        if (mContext.getDisplayId() == displayId) {
+            updateManagedProfile();
+            updateForegroundInstantApps();
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepAction.java
index b18b79e..1999f9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepAction.java
@@ -47,6 +47,10 @@
         return mNavigationBarView.isQuickStepSwipeUpEnabled();
     }
 
+    protected boolean requiresStableTaskList() {
+        return true;
+    }
+
     @Override
     public void onGestureStart(MotionEvent event) {
         try {
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 0cec637..9e91ab7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -34,13 +34,20 @@
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Rect;
+import android.hardware.input.InputManager;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.provider.Settings;
 import android.util.Log;
+import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewPropertyAnimator;
 
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -64,7 +71,10 @@
 
     /** Experiment to swipe home button left to execute a back key press */
     private static final String HIDE_BACK_BUTTON_PROP = "quickstepcontroller_hideback";
+    private static final String ENABLE_CLICK_THROUGH_NAV_PROP = "quickstepcontroller_clickthrough";
     private static final long BACK_BUTTON_FADE_IN_ALPHA = 150;
+    private static final long CLICK_THROUGH_TAP_DELAY = 70;
+    private static final long CLICK_THROUGH_TAP_RESET_DELAY = 100;
 
     /** When the home-swipe-back gesture is disallowed, make it harder to pull */
     private static final float HORIZONTAL_GESTURE_DAMPING = 0.3f;
@@ -100,6 +110,9 @@
     private float mMinDragLimit;
     private float mDragDampeningFactor;
     private float mEdgeSwipeThreshold;
+    private boolean mClickThroughPressed;
+    private float mClickThroughPressX;
+    private float mClickThroughPressY;
 
     private NavigationGestureAction mCurrentAction;
     private NavigationGestureAction[] mGestureActions = new NavigationGestureAction[MAX_GESTURES];
@@ -117,6 +130,19 @@
         mOverviewEventSender = Dependency.get(OverviewProxyService.class);
     }
 
+    private final Runnable mClickThroughSendTap = new Runnable() {
+        @Override
+        public void run() {
+            sendTap(mClickThroughPressX, mClickThroughPressY);
+            mNavigationBarView.postDelayed(mClickThroughResetTap, CLICK_THROUGH_TAP_RESET_DELAY);
+        }
+    };
+
+    private final Runnable mClickThroughResetTap = () -> {
+        setWindowTouchable(true);
+        mClickThroughPressed = false;
+    };
+
     public void setComponents(NavigationBarView navigationBarView) {
         mNavigationBarView = navigationBarView;
 
@@ -320,6 +346,25 @@
             case MotionEvent.ACTION_UP:
                 if (mCurrentAction != null) {
                     mCurrentAction.endGesture();
+                } else if (action == MotionEvent.ACTION_UP
+                        && getBoolGlobalSetting(mContext, ENABLE_CLICK_THROUGH_NAV_PROP)
+                        && !mClickThroughPressed) {
+                    // Enable click through functionality where no gesture has been detected and not
+                    // passed the drag slop so inject a touch event at the same location
+                    // after making the navigation bar window untouchable. After a some time, the
+                    // navigation bar will be able to take input events again
+                    float diffX = Math.abs(event.getX() - mTouchDownX);
+                    float diffY = Math.abs(event.getY() - mTouchDownY);
+
+                    if ((diffX <= NavigationBarCompat.getQuickStepDragSlopPx()
+                            && diffY <= NavigationBarCompat.getQuickStepDragSlopPx())) {
+                        setWindowTouchable(false);
+                        mClickThroughPressX = event.getRawX();
+                        mClickThroughPressY = event.getRawY();
+                        mClickThroughPressed = true;
+                        mNavigationBarView.postDelayed(mClickThroughSendTap,
+                                CLICK_THROUGH_TAP_DELAY);
+                    }
                 }
 
                 // Return the hit target back to its original position
@@ -350,6 +395,19 @@
         return mCurrentAction != null || deadZoneConsumed;
     }
 
+    private void setWindowTouchable(boolean flag) {
+        final WindowManager.LayoutParams lp = (WindowManager.LayoutParams)
+                ((ViewGroup) mNavigationBarView.getParent()).getLayoutParams();
+        if (flag) {
+            lp.flags &= ~LayoutParams.FLAG_NOT_TOUCHABLE;
+        } else {
+            lp.flags |= LayoutParams.FLAG_NOT_TOUCHABLE;
+        }
+        final WindowManager wm = (WindowManager) mNavigationBarView.getContext()
+                .getSystemService(Context.WINDOW_SERVICE);
+        wm.updateViewLayout((View) mNavigationBarView.getParent(), lp);
+    }
+
     private boolean isEdgeSwipeAlongNavBar(int touchDown, boolean dragPositiveDirection) {
         // Detect edge swipe from side of 0 -> threshold
         if (dragPositiveDirection) {
@@ -562,6 +620,38 @@
         return false;
     }
 
+    private void sendTap(float x, float y) {
+        long now = SystemClock.uptimeMillis();
+        injectMotionEvent(InputDevice.SOURCE_TOUCHSCREEN, MotionEvent.ACTION_DOWN, now, x, y, 1.0f);
+        injectMotionEvent(InputDevice.SOURCE_TOUCHSCREEN, MotionEvent.ACTION_UP, now, x, y, 0.0f);
+    }
+
+    private int getInputDeviceId(int inputSource) {
+        int[] devIds = InputDevice.getDeviceIds();
+        for (int devId : devIds) {
+            InputDevice inputDev = InputDevice.getDevice(devId);
+            if (inputDev.supportsSource(inputSource)) {
+                return devId;
+            }
+        }
+        return 0;
+    }
+
+    private void injectMotionEvent(int inputSource, int action, long when, float x, float y,
+            float pressure) {
+        final float defaultSize = 1.0f;
+        final int defaultMetaState = 0;
+        final float defaultPrecisionX = 1.0f;
+        final float defaultPrecisionY = 1.0f;
+        final int defaultEdgeFlags = 0;
+        MotionEvent event = MotionEvent.obtain(when, when, action, x, y, pressure, defaultSize,
+                defaultMetaState, defaultPrecisionX, defaultPrecisionY,
+                getInputDeviceId(inputSource), defaultEdgeFlags);
+        event.setSource(inputSource);
+        InputManager.getInstance().injectInputEvent(event,
+                InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+    }
+
     private boolean proxyMotionEvents(MotionEvent event) {
         final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
         event.transform(mTransformGlobalMatrix);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index e25c829..bf143c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -88,16 +88,12 @@
     /**
      * Default alpha value for most scrims.
      */
-    public static final float GRADIENT_SCRIM_ALPHA = 0.45f;
+    public static final float GRADIENT_SCRIM_ALPHA = 0.2f;
     /**
      * A scrim varies its opacity based on a busyness factor, for example
      * how many notifications are currently visible.
      */
     public static final float GRADIENT_SCRIM_ALPHA_BUSY = 0.7f;
-    /**
-     * Scrim opacity when a wallpaper doesn't support ambient mode.
-     */
-    public static final float PULSING_WALLPAPER_SCRIM_ALPHA = 0.6f;
 
     /**
      * The most common scrim, the one under the keyguard.
@@ -154,7 +150,6 @@
     private Callback mCallback;
     private boolean mWallpaperSupportsAmbientMode;
     private boolean mScreenOn;
-    private float mNotificationDensity;
 
     // Scrim blanking callbacks
     private Runnable mPendingFrameCallback;
@@ -245,7 +240,7 @@
         mCurrentInFrontTint = state.getFrontTint();
         mCurrentBehindTint = state.getBehindTint();
         mCurrentInFrontAlpha = state.getFrontAlpha();
-        mCurrentBehindAlpha = state.getBehindAlpha(mNotificationDensity);
+        mCurrentBehindAlpha = state.getBehindAlpha();
         applyExpansionToAlpha();
 
         // Scrim might acquire focus when user is navigating with a D-pad or a keyboard.
@@ -275,9 +270,11 @@
             holdWakeLock();
         }
 
-        // AOD wallpapers should fade away after a while
-        if (mWallpaperSupportsAmbientMode && mDozeParameters.getAlwaysOn()
-                && mState == ScrimState.AOD) {
+        // AOD wallpapers should fade away after a while.
+        // Docking pulses may take a long time, wallpapers should also fade away after a while.
+        if (mWallpaperSupportsAmbientMode && (
+                mDozeParameters.getAlwaysOn() && mState == ScrimState.AOD
+                        || mState == ScrimState.PULSING && mCallback != null)) {
             if (!mWallpaperVisibilityTimedOut) {
                 mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
                         AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
@@ -329,7 +326,7 @@
 
     @VisibleForTesting
     protected void onHideWallpaperTimeout() {
-        if (mState != ScrimState.AOD) {
+        if (mState != ScrimState.AOD && mState != ScrimState.PULSING) {
             return;
         }
 
@@ -364,7 +361,7 @@
             mExpansionFraction = fraction;
 
             final boolean keyguardOrUnlocked = mState == ScrimState.UNLOCKED
-                    || mState == ScrimState.KEYGUARD;
+                    || mState == ScrimState.KEYGUARD || mState == ScrimState.PULSING;
             if (!keyguardOrUnlocked || !mExpansionAffectsAlpha) {
                 return;
             }
@@ -409,11 +406,11 @@
             behindFraction = (float) Math.pow(behindFraction, 0.8f);
             mCurrentBehindAlpha = behindFraction * GRADIENT_SCRIM_ALPHA_BUSY;
             mCurrentInFrontAlpha = 0;
-        } else if (mState == ScrimState.KEYGUARD) {
+        } else if (mState == ScrimState.KEYGUARD || mState == ScrimState.PULSING) {
             // Either darken of make the scrim transparent when you
             // pull down the shade
             float interpolatedFract = getInterpolatedFraction();
-            float alphaBehind = mState.getBehindAlpha(mNotificationDensity);
+            float alphaBehind = mState.getBehindAlpha();
             if (mDarkenWhileDragging) {
                 mCurrentBehindAlpha = MathUtils.lerp(GRADIENT_SCRIM_ALPHA_BUSY, alphaBehind,
                         interpolatedFract);
@@ -427,24 +424,6 @@
     }
 
     /**
-     * Keyguard and shade scrim opacity varies according to how many notifications are visible.
-     * @param notificationCount Number of visible notifications.
-     */
-    public void setNotificationCount(int notificationCount) {
-        final float maxNotificationDensity = 3;
-        float notificationDensity = Math.min(notificationCount / maxNotificationDensity, 1f);
-        if (mNotificationDensity == notificationDensity) {
-            return;
-        }
-        mNotificationDensity = notificationDensity;
-
-        if (mState == ScrimState.KEYGUARD) {
-            applyExpansionToAlpha();
-            scheduleUpdate();
-        }
-    }
-
-    /**
      * Sets the given drawable as the background of the scrim that shows up behind the
      * notifications.
      */
@@ -504,7 +483,8 @@
 
         // We want to override the back scrim opacity for the AOD state
         // when it's time to fade the wallpaper away.
-        boolean aodWallpaperTimeout = mState == ScrimState.AOD && mWallpaperVisibilityTimedOut;
+        boolean aodWallpaperTimeout = (mState == ScrimState.AOD || mState == ScrimState.PULSING)
+                && mWallpaperVisibilityTimedOut;
         // We also want to hide FLAG_SHOW_WHEN_LOCKED activities under the scrim.
         boolean occludedKeyguard = (mState == ScrimState.PULSING || mState == ScrimState.AOD)
                 && mKeyguardOccluded;
@@ -562,8 +542,8 @@
         if (alpha == 0f) {
             scrim.setClickable(false);
         } else {
-            // Eat touch events (unless dozing or pulsing).
-            scrim.setClickable(mState != ScrimState.AOD && mState != ScrimState.PULSING);
+            // Eat touch events (unless dozing).
+            scrim.setClickable(mState != ScrimState.AOD);
         }
         updateScrim(scrim, alpha);
     }
@@ -608,9 +588,11 @@
         anim.setStartDelay(mAnimationDelay);
         anim.setDuration(mAnimationDuration);
         anim.addListener(new AnimatorListenerAdapter() {
+            private Callback lastCallback = mCallback;
+
             @Override
             public void onAnimationEnd(Animator animation) {
-                onFinished();
+                onFinished(lastCallback);
 
                 scrim.setTag(TAG_KEY_ANIM, null);
                 dispatchScrimsVisible();
@@ -668,14 +650,23 @@
     }
 
     private void onFinished() {
+        onFinished(mCallback);
+    }
+
+    private void onFinished(Callback callback) {
         if (mWakeLockHeld) {
             mWakeLock.release();
             mWakeLockHeld = false;
         }
-        if (mCallback != null) {
-            mCallback.onFinished();
-            mCallback = null;
+
+        if (callback != null) {
+            callback.onFinished();
+
+            if (callback == mCallback) {
+                mCallback = null;
+            }
         }
+
         // When unlocking with fingerprint, we'll fade the scrims from black to transparent.
         // At the end of the animation we need to remove the tint.
         if (mState == ScrimState.UNLOCKED) {
@@ -894,7 +885,7 @@
         // Backdrop event may arrive after state was already applied,
         // in this case, back-scrim needs to be re-evaluated
         if (mState == ScrimState.AOD || mState == ScrimState.PULSING) {
-            float newBehindAlpha = mState.getBehindAlpha(mNotificationDensity);
+            float newBehindAlpha = mState.getBehindAlpha();
             if (mCurrentBehindAlpha != newBehindAlpha) {
                 mCurrentBehindAlpha = newBehindAlpha;
                 updateScrims();
@@ -908,6 +899,10 @@
         }
     }
 
+    public void setPulseReason(int pulseReason) {
+        ScrimState.PULSING.setPulseReason(pulseReason);
+    }
+
     public interface Callback {
         default void onStart() {
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index fb3c4aa..11a2d32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -18,8 +18,8 @@
 
 import android.graphics.Color;
 import android.os.Trace;
-import android.util.MathUtils;
 
+import com.android.systemui.doze.DozeLog;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
@@ -57,13 +57,6 @@
             mCurrentBehindAlpha = mScrimBehindAlphaKeyguard;
             mCurrentInFrontAlpha = 0;
         }
-
-        @Override
-        public float getBehindAlpha(float busynessFactor) {
-            return MathUtils.map(0 /* start */, 1 /* stop */,
-                    mScrimBehindAlphaKeyguard, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY,
-                    busynessFactor);
-        }
     },
 
     /**
@@ -117,7 +110,7 @@
         }
 
         @Override
-        public float getBehindAlpha(float busyness) {
+        public float getBehindAlpha() {
             return mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f : 1f;
         }
 
@@ -133,17 +126,17 @@
     PULSING(5) {
         @Override
         public void prepare(ScrimState previousState) {
-            mCurrentInFrontAlpha = 0;
-            mCurrentInFrontTint = Color.BLACK;
-            mCurrentBehindTint = Color.BLACK;
+            mCurrentInFrontAlpha = 0f;
+            if (mPulseReason == DozeLog.PULSE_REASON_NOTIFICATION
+                    || mPulseReason == DozeLog.PULSE_REASON_DOCKING) {
+                mCurrentBehindAlpha = previousState.getBehindAlpha();
+                mCurrentBehindTint = Color.BLACK;
+            } else {
+                mCurrentBehindAlpha = mScrimBehindAlphaKeyguard;
+                mCurrentBehindTint = Color.TRANSPARENT;
+            }
             mBlankScreen = mDisplayRequiresBlanking;
         }
-
-        @Override
-        public float getBehindAlpha(float busyness) {
-            return mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f
-                    : ScrimController.PULSING_WALLPAPER_SCRIM_ALPHA;
-        }
     },
 
     /**
@@ -204,6 +197,7 @@
     int mIndex;
     boolean mHasBackdrop;
     boolean mLaunchingAffordanceWithPreview;
+    int mPulseReason;
 
     ScrimState(int index) {
         mIndex = index;
@@ -219,6 +213,14 @@
     public void prepare(ScrimState previousState) {
     }
 
+    /**
+     * Check if lockscreen wallpaper or music album art exists.
+     * @return true if lockscreen wallpaper or music album art exists.
+     */
+    public boolean hasBackdrop() {
+        return mHasBackdrop;
+    }
+
     public int getIndex() {
         return mIndex;
     }
@@ -227,7 +229,7 @@
         return mCurrentInFrontAlpha;
     }
 
-    public float getBehindAlpha(float busyness) {
+    public float getBehindAlpha() {
         return mCurrentBehindAlpha;
     }
 
@@ -268,6 +270,10 @@
         mAodFrontScrimAlpha = aodFrontScrimAlpha;
     }
 
+    public void setPulseReason(int pulseReason) {
+        mPulseReason = pulseReason;
+    }
+
     public void setScrimBehindAlphaKeyguard(float scrimBehindAlphaKeyguard) {
         mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
     }
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 9f0eec4..1470d0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -20,9 +20,10 @@
 import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
+import static android.app.StatusBarManager.WindowType;
+import static android.app.StatusBarManager.WindowVisibleState;
 import static android.app.StatusBarManager.windowStateToString;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
-import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
@@ -69,6 +70,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.database.ContentObserver;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
@@ -79,6 +81,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.RemoteException;
@@ -96,6 +99,7 @@
 import android.service.notification.StatusBarNotification;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
+import android.util.FeatureFlagUtils;
 import android.util.Log;
 import android.util.Slog;
 import android.view.Display;
@@ -190,12 +194,12 @@
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationClicker;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.NotificationListController;
 import com.android.systemui.statusbar.notification.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -289,10 +293,6 @@
 
     protected static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
 
-    private static final int STATUS_OR_NAV_TRANSIENT =
-            View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
-    private static final long AUTOHIDE_TIMEOUT_MS = 2250;
-
     /**
      * The delay to reset the hint text when the hint animation is finished running.
      */
@@ -341,6 +341,8 @@
     protected BiometricUnlockController mBiometricUnlockController;
     private LightBarController mLightBarController;
     protected LockscreenWallpaper mLockscreenWallpaper;
+    @VisibleForTesting
+    protected AutoHideController mAutoHideController;
 
     private int mNaturalBarHeight = -1;
 
@@ -386,6 +388,7 @@
     private NotificationGutsManager mGutsManager;
     protected NotificationLogger mNotificationLogger;
     protected NotificationEntryManager mEntryManager;
+    private NotificationListController mNotificationListController;
     private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
     private NotificationRowBinder mNotificationRowBinder;
     protected NotificationViewHierarchyManager mViewHierarchyManager;
@@ -405,9 +408,6 @@
     private final Rect mLastFullscreenStackBounds = new Rect();
     private final Rect mLastDockedStackBounds = new Rect();
 
-    // last value sent to window manager
-    private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
-
     private final DisplayMetrics mDisplayMetrics = Dependency.get(DisplayMetrics.class);
 
     // XXX: gesture research
@@ -447,7 +447,6 @@
     protected final H mHandler = createHandler();
 
     private int mInteractingWindows;
-    private boolean mAutoHideSuspended;
     private @TransitionMode int mStatusBarMode;
 
     private ViewMediatorCallback mKeyguardViewMediatorCallback;
@@ -455,13 +454,6 @@
     protected DozeScrimController mDozeScrimController;
     private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
 
-    private final Runnable mAutoHide = () -> {
-        int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
-        if (mSystemUiVisibility != requested) {
-            notifySystemUiVisibilityChanged(requested);
-        }
-    };
-
     protected boolean mDozing;
     private boolean mDozingRequested;
 
@@ -471,13 +463,6 @@
     private NotificationMediaManager mMediaManager;
     protected NotificationLockscreenUserManager mLockscreenUserManager;
     protected NotificationRemoteInputManager mRemoteInputManager;
-    protected BubbleController mBubbleController;
-    private final BubbleController.BubbleExpandListener mBubbleExpandListener =
-            (isExpanding, amount) -> {
-                if (amount == 1) {
-                    updateScrimController();
-                }
-            };
 
     private final BroadcastReceiver mWallpaperChangedReceiver = new BroadcastReceiver() {
         @Override
@@ -490,8 +475,13 @@
             WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
             final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean(
                     com.android.internal.R.bool.config_dozeSupportsAodWallpaper);
+            final boolean aodImageWallpaperEnabled = FeatureFlagUtils.isEnabled(mContext,
+                    FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED);
+            updateAodMaskVisibility(deviceSupportsAodWallpaper && aodImageWallpaperEnabled);
+            // If WallpaperInfo is null, it must be ImageWallpaper.
             final boolean supportsAmbientMode = deviceSupportsAodWallpaper
-                    && info != null && info.supportsAmbientMode();
+                    && (info == null && aodImageWallpaperEnabled
+                        || info != null && info.supportsAmbientMode());
 
             mStatusBarWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
             mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
@@ -500,7 +490,7 @@
 
     private Runnable mLaunchTransitionEndRunnable;
     protected boolean mLaunchTransitionFadingAway;
-    private NotificationData.Entry mDraggedDownEntry;
+    private NotificationEntry mDraggedDownEntry;
     private boolean mLaunchCameraOnScreenTurningOn;
     private boolean mLaunchCameraOnFinishedGoingToSleep;
     private int mLastCameraLaunchSource;
@@ -584,6 +574,7 @@
                     mEntryManager.updateNotifications();
                 }
             };
+    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
 
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
     private boolean mVibrateOnOpening;
@@ -592,12 +583,19 @@
     protected NotificationPresenter mPresenter;
     private NotificationActivityStarter mNotificationActivityStarter;
     private boolean mPulsing;
+    private ContentObserver mFeatureFlagObserver;
+    protected BubbleController mBubbleController;
+    private final BubbleController.BubbleExpandListener mBubbleExpandListener =
+            (isExpanding, key) -> {
+                mEntryManager.updateNotifications();
+                updateScrimController();
+            };
 
     @Override
     public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
         mForegroundServiceController.onAppOpChanged(code, uid, packageName, active);
         Dependency.get(Dependency.MAIN_HANDLER).post(() -> {
-            mEntryManager.updateNotificationsForAppOp(code, uid, packageName, active);
+            mNotificationListController.updateNotificationsForAppOp(code, uid, packageName, active);
         });
     }
 
@@ -643,7 +641,7 @@
         mBubbleController.setExpandListener(mBubbleExpandListener);
         KeyguardSliceProvider sliceProvider = KeyguardSliceProvider.getAttachedInstance();
         if (sliceProvider != null) {
-            sliceProvider.initDependencies();
+            sliceProvider.initDependencies(mMediaManager, mStatusBarStateController);
         } else {
             Log.w(TAG, "Cannot init KeyguardSliceProvider dependencies");
         }
@@ -656,6 +654,7 @@
                 ServiceManager.checkService(DreamService.DREAM_SERVICE));
 
         mDisplay = mWindowManager.getDefaultDisplay();
+        mDisplayId = mDisplay.getDisplayId();
         updateDisplaySize();
 
         Resources res = mContext.getResources();
@@ -707,15 +706,18 @@
         mContext.registerReceiverAsUser(mWallpaperChangedReceiver, UserHandle.ALL,
                 wallpaperChangedFilter, null /* broadcastPermission */, null /* scheduler */);
         mWallpaperChangedReceiver.onReceive(mContext, null);
+        mFeatureFlagObserver = new FeatureFlagObserver(
+                FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED /* feature */,
+                () -> mWallpaperChangedReceiver.onReceive(mContext, null) /* callback */);
 
         // Set up the initial notification state. This needs to happen before CommandQueue.disable()
         setUpPresenter();
 
-        setSystemUiVisibility(switches[1], switches[7], switches[8], 0xffffffff,
+        setSystemUiVisibility(mDisplayId, switches[1], switches[7], switches[8], 0xffffffff,
                 fullscreenStackBounds, dockedStackBounds);
-        topAppWindowChanged(switches[2] != 0);
+        topAppWindowChanged(mDisplayId, switches[2] != 0);
         // StatusBarManagerService has a back up of IME token and it's restored here.
-        setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);
+        setImeWindowStatus(mDisplayId, binders.get(0), switches[3], switches[4], switches[5] != 0);
 
         // Set up the initial icon state
         int N = iconSlots.size();
@@ -799,7 +801,7 @@
         mNotificationLogger.setUpWithContainer(notifListContainer);
 
         mNotificationIconAreaController = SystemUIFactory.getInstance()
-                .createNotificationIconAreaController(context, this);
+                .createNotificationIconAreaController(context, this, mStatusBarStateController);
         inflateShelf();
         mNotificationIconAreaController.setupShelf(mNotificationShelf);
 
@@ -902,6 +904,9 @@
             }
         });
 
+        mAutoHideController = Dependency.get(AutoHideController.class);
+        mAutoHideController.setStatusBar(this);
+
         mLightBarController = Dependency.get(LightBarController.class);
 
         ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind);
@@ -1041,6 +1046,13 @@
                 mScrimController, mActivityLaunchAnimator, mStatusBarKeyguardViewManager,
                 mNotificationAlertingManager);
 
+        mNotificationListController =
+                new NotificationListController(
+                        mEntryManager,
+                        (NotificationListContainer) mStackScroller,
+                        mForegroundServiceController,
+                        mDeviceProvisionedController);
+
         mAppOpsController.addCallback(APP_OPS, this);
         mNotificationListener.setUpWithPresenter(mPresenter);
         mNotificationShelf.setOnActivatedListener(mPresenter);
@@ -1053,6 +1065,7 @@
                 this, Dependency.get(BubbleController.class), mNotificationActivityStarter));
 
         mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager);
+        mNotificationListController.bind();
     }
 
     /**
@@ -1061,7 +1074,7 @@
      * @param state2 disable2 flags
      */
     protected void setUpDisableFlags(int state1, int state2) {
-        mCommandQueue.disable(state1, state2, false /* animate */);
+        mCommandQueue.disable(mDisplayId, state1, state2, false /* animate */);
     }
 
     @Override
@@ -1100,7 +1113,7 @@
      */
     protected View.OnTouchListener getStatusBarWindowTouchListener() {
         return (v, event) -> {
-            checkUserAutoHide(event);
+            mAutoHideController.checkUserAutoHide(event);
             mRemoteInputManager.checkRemoteInputOutside(event);
             if (event.getAction() == MotionEvent.ACTION_DOWN) {
                 if (mExpandedVisible) {
@@ -1235,8 +1248,7 @@
         }
         int dockSide = WindowManagerProxy.getInstance().getDockSide();
         if (dockSide == WindowManager.DOCKED_INVALID) {
-            final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(
-                    mDisplay.getDisplayId());
+            final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(mDisplayId);
             if (navbarPos == NAV_BAR_POS_INVALID) {
                 return false;
             }
@@ -1345,7 +1357,10 @@
      * State is one or more of the DISABLE constants from StatusBarManager.
      */
     @Override
-    public void disable(int state1, int state2, boolean animate) {
+    public void disable(int displayId, int state1, int state2, boolean animate) {
+        if (displayId != mDisplayId) {
+            return;
+        }
         state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
 
         animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
@@ -1514,21 +1529,21 @@
     }
 
     @Override
-    public void onHeadsUpPinned(NotificationData.Entry entry) {
+    public void onHeadsUpPinned(NotificationEntry entry) {
         dismissVolumeDialog();
     }
 
     @Override
-    public void onHeadsUpUnPinned(NotificationData.Entry entry) {
+    public void onHeadsUpUnPinned(NotificationEntry entry) {
     }
 
     @Override
-    public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) {
+    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
         mEntryManager.updateNotificationRanking(null /* rankingMap */);
     }
 
     @Override
-    public void onAmbientStateChanged(Entry entry, boolean isAmbient) {
+    public void onAmbientStateChanged(NotificationEntry entry, boolean isAmbient) {
         mEntryManager.updateNotificationRanking(null);
         if (isAmbient) {
             mDozeServiceHost.fireNotificationPulse();
@@ -1623,10 +1638,10 @@
                 mWereIconsJustHidden = true;
                 mHandler.postDelayed(() -> {
                     mWereIconsJustHidden = false;
-                    mCommandQueue.recomputeDisableFlags(true);
+                    mCommandQueue.recomputeDisableFlags(mDisplayId, true);
                 }, 500);
             } else {
-                mCommandQueue.recomputeDisableFlags(animate);
+                mCommandQueue.recomputeDisableFlags(mDisplayId, animate);
             }
         }
         if (shouldHideIconsForBouncer) {
@@ -1792,7 +1807,7 @@
         mStatusBarWindowController.setPanelVisible(true);
 
         visibilityChanged(true);
-        mCommandQueue.recomputeDisableFlags(!force /* animate */);
+        mCommandQueue.recomputeDisableFlags(mDisplayId, !force /* animate */);
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
     }
 
@@ -1965,7 +1980,7 @@
             Log.d(TAG, "Not showing bouncer due to activity showing over lockscreen");
         }
         mCommandQueue.recomputeDisableFlags(
-                mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
+                mDisplayId, mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
 
         // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
         // the bouncer appear animation.
@@ -2022,7 +2037,11 @@
     }
 
     @Override // CommandQueue
-    public void setWindowState(int window, int state) {
+    public void setWindowState(
+            int displayId, @WindowType int window, @WindowVisibleState int state) {
+        if (displayId != mDisplayId) {
+            return;
+        }
         boolean showing = state == WINDOW_STATE_SHOWING;
         if (mStatusBarWindow != null
                 && window == StatusBarManager.WINDOW_STATUS_BAR
@@ -2041,14 +2060,17 @@
     }
 
     @Override // CommandQueue
-    public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
-            int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+    public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
+            int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+        if (displayId != mDisplayId) {
+            return;
+        }
         final int oldVal = mSystemUiVisibility;
         final int newVal = (oldVal&~mask) | (vis&mask);
         final int diff = newVal ^ oldVal;
         if (DEBUG) Log.d(TAG, String.format(
-                "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
-                Integer.toHexString(vis), Integer.toHexString(mask),
+                "setSystemUiVisibility displayId=%d vis=%s mask=%s oldVal=%s newVal=%s diff=%s",
+                displayId, Integer.toHexString(vis), Integer.toHexString(mask),
                 Integer.toHexString(oldVal), Integer.toHexString(newVal),
                 Integer.toHexString(diff)));
         boolean sbModeChanged = false;
@@ -2062,7 +2084,6 @@
 
             // ready to unhide
             if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
-                mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
                 mNoAnimationOnNextBarModeChange = true;
             }
 
@@ -2073,17 +2094,9 @@
             if (sbModeChanged && sbMode != mStatusBarMode) {
                 mStatusBarMode = sbMode;
                 checkBarModes();
-                touchAutoHide();
+                mAutoHideController.touchAutoHide();
             }
-
-            if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
-                mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
-            }
-
-            // send updated sysui visibility to window manager
-            notifySystemUiVisibilityChanged(mSystemUiVisibility);
         }
-
         mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
                 mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
     }
@@ -2111,16 +2124,6 @@
         }
     }
 
-    void touchAutoHide() {
-        // update transient bar auto hide
-        if (mStatusBarMode == MODE_SEMI_TRANSPARENT
-                || mNavigationBarController.isSemiTransparent(DEFAULT_DISPLAY)) {
-            scheduleAutoHide();
-        } else {
-            cancelAutoHide();
-        }
-    }
-
     protected @TransitionMode int computeStatusBarMode(int oldVal, int newVal) {
         return computeBarMode(oldVal, newVal);
     }
@@ -2159,7 +2162,7 @@
         if (mDemoMode) return;
         if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState,
                 getStatusBarTransitions());
-        mNavigationBarController.checkNavBarModes(DEFAULT_DISPLAY);
+        mNavigationBarController.checkNavBarModes(mDisplayId);
         mNoAnimationOnNextBarModeChange = false;
     }
 
@@ -2168,7 +2171,8 @@
         mNotificationPanel.setQsScrimEnabled(scrimEnabled);
     }
 
-    void checkBarMode(@TransitionMode int mode, int windowState, BarTransitions transitions) {
+    void checkBarMode(@TransitionMode int mode, @WindowVisibleState int windowState,
+            BarTransitions transitions) {
         final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive
                 && windowState != WINDOW_STATE_HIDDEN;
         transitions.transitionTo(mode, anim);
@@ -2178,7 +2182,7 @@
         if (mStatusBarView != null) {
             mStatusBarView.getBarTransitions().finishAnimations();
         }
-        mNavigationBarController.finishBarAnimations(DEFAULT_DISPLAY);
+        mNavigationBarController.finishBarAnimations(mDisplayId);
     }
 
     private final Runnable mCheckBarModes = this::checkBarModes;
@@ -2189,13 +2193,13 @@
                 ? (mInteractingWindows | barWindow)
                 : (mInteractingWindows & ~barWindow);
         if (mInteractingWindows != 0) {
-            suspendAutoHide();
+            mAutoHideController.suspendAutoHide();
         } else {
-            resumeSuspendedAutoHide();
+            mAutoHideController.resumeSuspendedAutoHide();
         }
         // manually dismiss the volume panel when interacting with the nav bar
         if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
-            mNavigationBarController.touchAutoDim(DEFAULT_DISPLAY);
+            mNavigationBarController.touchAutoDim(mDisplayId);
             dismissVolumeDialog();
         }
         checkBarModes();
@@ -2207,44 +2211,6 @@
         }
     }
 
-    private void resumeSuspendedAutoHide() {
-        if (mAutoHideSuspended) {
-            scheduleAutoHide();
-            mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher
-        }
-    }
-
-    private void suspendAutoHide() {
-        mHandler.removeCallbacks(mAutoHide);
-        mHandler.removeCallbacks(mCheckBarModes);
-        mAutoHideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
-    }
-
-    private void cancelAutoHide() {
-        mAutoHideSuspended = false;
-        mHandler.removeCallbacks(mAutoHide);
-    }
-
-    private void scheduleAutoHide() {
-        cancelAutoHide();
-        mHandler.postDelayed(mAutoHide, AUTOHIDE_TIMEOUT_MS);
-    }
-
-    void checkUserAutoHide(MotionEvent event) {
-        if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0  // a transient bar is revealed
-                && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
-                && event.getX() == 0 && event.getY() == 0  // a touch outside both bars
-                && !mRemoteInputManager.getController()
-                        .isRemoteInputActive()) { // not due to typing in IME
-            userAutoHide();
-        }
-    }
-
-    private void userAutoHide() {
-        cancelAutoHide();
-        mHandler.postDelayed(mAutoHide, 350); // longer than app gesture -> flag clear
-    }
-
     private boolean areLightsOn() {
         return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
     }
@@ -2252,29 +2218,21 @@
     public void setLightsOn(boolean on) {
         Log.v(TAG, "setLightsOn(" + on + ")");
         if (on) {
-            setSystemUiVisibility(0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
+            setSystemUiVisibility(mDisplayId, 0, 0, 0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
                     mLastFullscreenStackBounds, mLastDockedStackBounds);
         } else {
-            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
+            setSystemUiVisibility(mDisplayId, View.SYSTEM_UI_FLAG_LOW_PROFILE, 0, 0,
                     View.SYSTEM_UI_FLAG_LOW_PROFILE, mLastFullscreenStackBounds,
                     mLastDockedStackBounds);
         }
     }
 
-    private void notifySystemUiVisibilityChanged(int vis) {
-        try {
-            if (mLastDispatchedSystemUiVisibility != vis) {
-                mWindowManagerService.statusBarVisibilityChanged(DEFAULT_DISPLAY, vis);
-                mLastDispatchedSystemUiVisibility = vis;
-            }
-        } catch (RemoteException ex) {
-        }
-    }
-
     @Override
-    public void topAppWindowChanged(boolean showMenu) {
+    public void topAppWindowChanged(int displayId, boolean showMenu) {
+        if (mDisplayId != displayId) return;
         if (SPEW) {
-            Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
+            Log.d(TAG, "display#" + displayId + ": "
+                    + (showMenu ? "showing" : "hiding") + " the MENU button");
         }
 
         // See above re: lights-out policy for legacy apps.
@@ -2612,11 +2570,11 @@
     };
 
     public void resetUserExpandedStates() {
-        ArrayList<Entry> activeNotifications = mEntryManager.getNotificationData()
+        ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
                 .getActiveNotifications();
         final int notificationCount = activeNotifications.size();
         for (int i = 0; i < notificationCount; i++) {
-            NotificationData.Entry entry = activeNotifications.get(i);
+            NotificationEntry entry = activeNotifications.get(i);
             entry.resetUserExpansion();
         }
     }
@@ -2883,7 +2841,7 @@
         } catch (RemoteException e) {
             // Ignore.
         }
-        mEntryManager.destroy();
+        mNotificationListController.destroy();
         // End old BaseStatusBar.destroy().
         if (mStatusBarWindow != null) {
             mWindowManager.removeViewImmediate(mStatusBarWindow);
@@ -2963,7 +2921,7 @@
                 if (mStatusBarView != null) {
                     mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
                 }
-                mNavigationBarController.transitionTo(DEFAULT_DISPLAY, barMode, animate);
+                mNavigationBarController.transitionTo(mDisplayId, barMode, animate);
             }
         }
         if (modeChange || command.equals(COMMAND_OPERATOR)) {
@@ -3101,7 +3059,7 @@
                     .setDuration(FADE_KEYGUARD_DURATION)
                     .withLayer()
                     .withEndAction(this::onLaunchTransitionFadingEnded);
-            mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(),
+            mCommandQueue.appTransitionStarting(mDisplayId, SystemClock.uptimeMillis(),
                     LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
         };
         if (mNotificationPanel.isLaunchTransitionRunning()) {
@@ -3191,7 +3149,7 @@
 
             // Disable layout transitions in navbar for this transition because the load is just
             // too heavy for the CPU and GPU on any device.
-            mNavigationBarController.disableAnimationsDuringHide(DEFAULT_DISPLAY, delay);
+            mNavigationBarController.disableAnimationsDuringHide(mDisplayId, delay);
         } else if (!mNotificationPanel.isCollapsing()) {
             instantCollapseNotificationPanel();
         }
@@ -3224,7 +3182,7 @@
         // Treat Keyguard exit animation as an app transition to achieve nice transition for status
         // bar.
         mKeyguardMonitor.notifyKeyguardGoingAway(true);
-        mCommandQueue.appTransitionPending(true);
+        mCommandQueue.appTransitionPending(mDisplayId, true /* forced */);
     }
 
     /**
@@ -3235,11 +3193,11 @@
      * @param fadeoutDuration the duration of the exit animation, in milliseconds
      */
     public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
-        mCommandQueue.appTransitionStarting(startTime + fadeoutDuration
+        mCommandQueue.appTransitionStarting(mDisplayId, startTime + fadeoutDuration
                         - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
                 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
-        mCommandQueue.recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
-        mCommandQueue.appTransitionStarting(
+        mCommandQueue.recomputeDisableFlags(mDisplayId, fadeoutDuration > 0 /* animate */);
+        mCommandQueue.appTransitionStarting(mDisplayId,
                     startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
                     LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true);
         mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration);
@@ -3365,7 +3323,7 @@
         // Make our window larger and the panel expanded.
         makeExpandedVisible(true);
         mNotificationPanel.expand(false /* animate */);
-        mCommandQueue.recomputeDisableFlags(false /* animate */);
+        mCommandQueue.recomputeDisableFlags(mDisplayId, false /* animate */);
     }
 
     @Override
@@ -3421,7 +3379,7 @@
         updateReportRejectedTouchVisibility();
         updateDozing();
         updateTheme();
-        mNavigationBarController.touchAutoDim(DEFAULT_DISPLAY);
+        mNavigationBarController.touchAutoDim(mDisplayId);
         Trace.beginSection("StatusBar#updateKeyguardState");
         if (mState == StatusBarState.KEYGUARD) {
             mKeyguardIndicationController.setVisible(true);
@@ -3567,7 +3525,7 @@
 
         int userId = mLockscreenUserManager.getCurrentUserId();
         ExpandableNotificationRow row = null;
-        NotificationData.Entry entry = null;
+        NotificationEntry entry = null;
         if (expandView instanceof ExpandableNotificationRow) {
             entry = ((ExpandableNotificationRow) expandView).getEntry();
             entry.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
@@ -3606,7 +3564,7 @@
         mBouncerShowing = bouncerShowing;
         if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
         updateHideIconsForBouncer(true /* animate */);
-        mCommandQueue.recomputeDisableFlags(true /* animate */);
+        mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
         updateScrimController();
     }
 
@@ -3635,10 +3593,7 @@
             mVisualStabilityManager.setScreenOn(false);
             updateVisibleToUser();
 
-            // We need to disable touch events because these might
-            // collapse the panel after we expanded it, and thus we would end up with a blank
-            // Keyguard.
-            mNotificationPanel.setTouchAndAnimationDisabled(true);
+            updateNotificationPanelTouchState();
             mStatusBarWindow.cancelCurrentTouch();
             if (mLaunchCameraOnFinishedGoingToSleep) {
                 mLaunchCameraOnFinishedGoingToSleep = false;
@@ -3661,13 +3616,22 @@
             mDeviceInteractive = true;
             mAmbientPulseManager.releaseAllImmediately();
             mVisualStabilityManager.setScreenOn(true);
-            mNotificationPanel.setTouchAndAnimationDisabled(false);
+            updateNotificationPanelTouchState();
             updateVisibleToUser();
             updateIsKeyguard();
             mDozeServiceHost.stopDozing();
         }
     };
 
+    /**
+     * We need to disable touch events because these might
+     * collapse the panel after we expanded it, and thus we would end up with a blank
+     * Keyguard.
+     */
+    private void updateNotificationPanelTouchState() {
+        mNotificationPanel.setTouchAndAnimationDisabled(!mDeviceInteractive && !mPulsing);
+    }
+
     final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
         @Override
         public void onScreenTurningOn() {
@@ -3731,13 +3695,17 @@
     }
 
     @Override
-    public void appTransitionCancelled() {
-        getComponent(Divider.class).onAppTransitionFinished();
+    public void appTransitionCancelled(int displayId) {
+        if (displayId == mDisplayId) {
+            getComponent(Divider.class).onAppTransitionFinished();
+        }
     }
 
     @Override
-    public void appTransitionFinished() {
-        getComponent(Divider.class).onAppTransitionFinished();
+    public void appTransitionFinished(int displayId) {
+        if (displayId == mDisplayId) {
+            getComponent(Divider.class).onAppTransitionFinished();
+        }
     }
 
     @Override
@@ -3915,6 +3883,7 @@
 
         @Override
         public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
+            mScrimController.setPulseReason(reason);
             if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) {
                 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
                 startAssist(new Bundle());
@@ -3929,17 +3898,15 @@
                 @Override
                 public void onPulseStarted() {
                     callback.onPulseStarted();
-                    if (mAmbientPulseManager.hasNotifications()) {
-                        // Only pulse the stack scroller if there's actually something to show.
-                        // Otherwise just show the always-on screen.
-                        setPulsing(true);
-                    }
+                    updateNotificationPanelTouchState();
+                    setPulsing(true);
                 }
 
                 @Override
                 public void onPulseFinished() {
                     mPulsing = false;
                     callback.onPulseFinished();
+                    updateNotificationPanelTouchState();
                     setPulsing(false);
                 }
 
@@ -4043,7 +4010,7 @@
         }
 
         @Override
-        public void onDoubleTap(float screenX, float screenY) {
+        public void onSlpiTap(float screenX, float screenY) {
             if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
                 && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
                 mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2);
@@ -4133,6 +4100,7 @@
     private IDreamManager mDreamManager;
 
     protected Display mDisplay;
+    private int mDisplayId;
 
     protected Recents mRecents;
 
@@ -4260,7 +4228,7 @@
             // Immediately update the icon hidden state, since that should only apply if we're
             // staying fullscreen.
             mWereIconsJustHidden = false;
-            mCommandQueue.recomputeDisableFlags(true);
+            mCommandQueue.recomputeDisableFlags(mDisplayId, true);
         }
         updateHideIconsForBouncer(true /* animate */);
     }
@@ -4319,7 +4287,7 @@
 
     @Override
     public void startPendingIntentDismissingKeyguard(
-            final PendingIntent intent, @Nullable final Runnable intentSentCallback) {
+            final PendingIntent intent, @Nullable final Runnable intentSentUiThreadCallback) {
         final boolean afterKeyguardGone = intent.isActivity()
                 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
                 mLockscreenUserManager.getCurrentUserId());
@@ -4338,12 +4306,16 @@
             if (intent.isActivity()) {
                 mAssistManager.hideAssist();
             }
-            if (intentSentCallback != null) {
-                intentSentCallback.run();
+            if (intentSentUiThreadCallback != null) {
+                postOnUiThread(intentSentUiThreadCallback);
             }
         }, afterKeyguardGone);
     }
 
+    private void postOnUiThread(Runnable runnable) {
+        mMainThreadHandler.post(runnable);
+    }
+
     public static Bundle getActivityOptions(@Nullable RemoteAnimationAdapter animationAdapter) {
         ActivityOptions options;
         if (animationAdapter != null) {
@@ -4460,4 +4432,37 @@
     public interface StatusBarInjector {
         void createStatusBar(StatusBar statusbar);
     }
+
+    public @TransitionMode int getStatusBarMode() {
+        return mStatusBarMode;
+    }
+
+    private void updateAodMaskVisibility(boolean supportsAodWallpaper) {
+        View mask = mStatusBarWindow.findViewById(R.id.aod_mask);
+        if (mask != null) {
+            mask.setVisibility(supportsAodWallpaper ? View.VISIBLE : View.INVISIBLE);
+        }
+    }
+
+    private final class FeatureFlagObserver extends ContentObserver {
+        private final Runnable mCallback;
+
+        FeatureFlagObserver(String feature, Runnable callback) {
+            this(null, feature, callback);
+        }
+
+        private FeatureFlagObserver(Handler handler, String feature, Runnable callback) {
+            super(handler);
+            mCallback = callback;
+            mContext.getContentResolver().registerContentObserver(
+                    Settings.Global.getUriFor(feature), false, this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            if (mCallback != null) {
+                mStatusBarWindow.post(mCallback);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index db7589d..f846036 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -36,7 +36,6 @@
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.statusbar.policy.IconLogger;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -61,7 +60,6 @@
 
     private final ArrayList<IconManager> mIconGroups = new ArrayList<>();
     private final ArraySet<String> mIconBlacklist = new ArraySet<>();
-    private final IconLogger mIconLogger = Dependency.get(IconLogger.class);
 
     // Points to light or dark context depending on the... context?
     private Context mContext;
@@ -147,7 +145,6 @@
         int viewIndex = getViewIndex(index, holder.getTag());
         boolean blocked = mIconBlacklist.contains(slot);
 
-        mIconLogger.onIconVisibility(getSlotName(index), holder.isVisible());
         mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, blocked, holder));
     }
 
@@ -281,8 +278,6 @@
             return;
         }
 
-        mIconLogger.onIconHidden(slotName);
-
         int slotIndex = getSlotIndex(slotName);
         List<StatusBarIconHolder> iconsToRemove = slot.getHolderListInViewOrder();
         for (StatusBarIconHolder holder : iconsToRemove) {
@@ -297,7 +292,6 @@
         if (getIcon(index, tag) == null) {
             return;
         }
-        mIconLogger.onIconHidden(getSlotName(index));
         super.removeIcon(index, tag);
         int viewIndex = getViewIndex(index, 0);
         mIconGroups.forEach(l -> l.onRemoveIcon(viewIndex));
@@ -305,7 +299,6 @@
 
     private void handleSet(int index, StatusBarIconHolder holder) {
         int viewIndex = getViewIndex(index, holder.getTag());
-        mIconLogger.onIconVisibility(getSlotName(index), holder.isVisible());
         mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
     }
 
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 0f8970f..bb23608 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -187,7 +187,7 @@
             mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
         } else if (bouncerNeedsScrimming()) {
             mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
-        } else if (mShowing && !mDozing) {
+        } else if (mShowing) {
             if (!isWakeAndUnlocking() && !mStatusBar.isInLaunchTransition()) {
                 mBouncer.setExpansion(expansion);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 8d1b911..86326be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -60,10 +60,11 @@
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.HeadsUpUtil;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -131,7 +132,7 @@
 
         mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
-            public void onPendingEntryAdded(NotificationData.Entry entry) {
+            public void onPendingEntryAdded(NotificationEntry entry) {
                 handleFullScreenIntent(entry);
             }
         });
@@ -267,7 +268,7 @@
             }
         }
         Intent fillInIntent = null;
-        NotificationData.Entry entry = row.getEntry();
+        NotificationEntry entry = row.getEntry();
         CharSequence remoteInputText = null;
         if (!TextUtils.isEmpty(entry.remoteInputText)) {
             remoteInputText = entry.remoteInputText;
@@ -304,8 +305,11 @@
         final int count =
                 mEntryManager.getNotificationData().getActiveNotifications().size();
         final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
+        NotificationVisibility.NotificationLocation location =
+                NotificationLogger.getNotificationLocation(
+                        mEntryManager.getNotificationData().get(notificationKey));
         final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
-                rank, count, true);
+                rank, count, true, location);
         try {
             mBarService.onNotificationClick(notificationKey, nv);
         } catch (RemoteException ex) {
@@ -345,7 +349,7 @@
         }, null, false /* afterKeyguardGone */);
     }
 
-    private void handleFullScreenIntent(NotificationData.Entry entry) {
+    private void handleFullScreenIntent(NotificationEntry entry) {
         boolean isHeadsUped = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
         if (!isHeadsUped && entry.notification.getNotification().fullScreenIntent != null) {
             if (shouldSuppressFullScreenIntent(entry)) {
@@ -413,7 +417,7 @@
                 || !mActivityLaunchAnimator.isAnimationPending();
     }
 
-    private boolean shouldSuppressFullScreenIntent(NotificationData.Entry entry) {
+    private boolean shouldSuppressFullScreenIntent(NotificationEntry entry) {
         if (mPresenter.isDeviceInVrMode()) {
             return true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 7b7bcb4..df7f53b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -43,6 +43,7 @@
 import com.android.internal.widget.MessagingMessage;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dependency;
+import com.android.systemui.ForegroundServiceNotificationListener;
 import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
@@ -59,12 +60,12 @@
 import com.android.systemui.statusbar.notification.AboveShelfObserver;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -103,6 +104,8 @@
             Dependency.get(NotificationMediaManager.class);
     private final VisualStabilityManager mVisualStabilityManager =
             Dependency.get(VisualStabilityManager.class);
+    private final NotificationGutsManager mGutsManager =
+            Dependency.get(NotificationGutsManager.class);
     protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
 
     private final NotificationPanelView mNotificationPanel;
@@ -182,41 +185,35 @@
         Dependency.get(InitController.class).addPostInitTask(() -> {
             NotificationEntryListener notificationEntryListener = new NotificationEntryListener() {
                 @Override
-                public void onNotificationAdded(Entry entry) {
+                public void onNotificationAdded(NotificationEntry entry) {
                     // Recalculate the position of the sliding windows and the titles.
                     mShadeController.updateAreThereNotifications();
                 }
 
                 @Override
-                public void onEntryUpdated(Entry entry) {
+                public void onPostEntryUpdated(NotificationEntry entry) {
                     mShadeController.updateAreThereNotifications();
                 }
 
                 @Override
                 public void onEntryRemoved(
-                        @Nullable Entry entry,
-                        String key,
-                        StatusBarNotification old,
+                        @Nullable NotificationEntry entry,
                         NotificationVisibility visibility,
-                        boolean lifetimeExtended,
                         boolean removedByUser) {
-                    if (!lifetimeExtended) {
-                        StatusBarNotificationPresenter.this.onNotificationRemoved(key, old);
-                    }
+                    StatusBarNotificationPresenter.this.onNotificationRemoved(
+                            entry.key, entry.notification);
                     if (removedByUser) {
                         maybeEndAmbientPulse();
                     }
                 }
             };
 
-            NotificationGutsManager gutsManager = Dependency.get(NotificationGutsManager.class);
-
             mViewHierarchyManager.setUpWithPresenter(this, notifListContainer);
             mEntryManager.setUpWithPresenter(this, notifListContainer, mHeadsUpManager);
             mEntryManager.addNotificationEntryListener(notificationEntryListener);
             mEntryManager.addNotificationLifetimeExtender(mHeadsUpManager);
             mEntryManager.addNotificationLifetimeExtender(mAmbientPulseManager);
-            mEntryManager.addNotificationLifetimeExtender(gutsManager);
+            mEntryManager.addNotificationLifetimeExtender(mGutsManager);
             mEntryManager.addNotificationLifetimeExtenders(
                     remoteInputManager.getLifetimeExtenders());
             mNotificationRowBinder.setUpWithPresenter(this, notifListContainer, mHeadsUpManager,
@@ -226,8 +223,12 @@
             mLockscreenUserManager.setUpWithPresenter(this);
             mMediaManager.setUpWithPresenter(this);
             mVisualStabilityManager.setUpWithPresenter(this);
-            gutsManager.setUpWithPresenter(this,
+            mGutsManager.setUpWithPresenter(this,
                     notifListContainer, mCheckSaveListener, mOnSettingsClickListener);
+            // ForegroundServiceControllerListener adds its listener in its constructor
+            // but we need to request it here in order for it to be instantiated.
+            // TODO: figure out how to do this correctly once Dependency.get() is gone.
+            Dependency.get(ForegroundServiceNotificationListener.class);
 
             onUserSwitched(mLockscreenUserManager.getCurrentUserId());
         });
@@ -241,7 +242,7 @@
         MessagingMessage.dropCache();
         MessagingGroup.dropCache();
         if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
-            mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
+            updateNotificationsOnDensityOrFontScaleChanged();
         } else {
             mReinflateNotificationsOnUserSwitched = true;
         }
@@ -257,10 +258,10 @@
     }
 
     private void updateNotificationOnUiModeChanged() {
-        ArrayList<Entry> userNotifications
+        ArrayList<NotificationEntry> userNotifications
                 = mEntryManager.getNotificationData().getNotificationsForCurrentUser();
         for (int i = 0; i < userNotifications.size(); i++) {
-            Entry entry = userNotifications.get(i);
+            NotificationEntry entry = userNotifications.get(i);
             ExpandableNotificationRow row = entry.getRow();
             if (row != null) {
                 row.onUiModeChanged();
@@ -268,6 +269,19 @@
         }
     }
 
+    private void updateNotificationsOnDensityOrFontScaleChanged() {
+        ArrayList<NotificationEntry> userNotifications =
+                mEntryManager.getNotificationData().getNotificationsForCurrentUser();
+        for (int i = 0; i < userNotifications.size(); i++) {
+            NotificationEntry entry = userNotifications.get(i);
+            entry.onDensityOrFontScaleChanged();
+            boolean exposedGuts = entry.areGutsExposed();
+            if (exposedGuts) {
+                mGutsManager.onDensityOrFontScaleChanged(entry);
+            }
+        }
+    }
+
     @Override
     public boolean isCollapsing() {
         return mNotificationPanel.isCollapsing()
@@ -322,7 +336,7 @@
         return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
     }
 
-    public boolean canHeadsUp(Entry entry, StatusBarNotification sbn) {
+    public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) {
         if (mShadeController.isDozing()) {
             return false;
         }
@@ -366,7 +380,7 @@
         if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
         mCommandQueue.animateCollapsePanels();
         if (mReinflateNotificationsOnUserSwitched) {
-            mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
+            updateNotificationsOnDensityOrFontScaleChanged();
             mReinflateNotificationsOnUserSwitched = false;
         }
         if (mDispatchUiModeChangeOnUserSwitched) {
@@ -380,7 +394,7 @@
     }
 
     @Override
-    public void onBindRow(Entry entry, PackageManager pmUser,
+    public void onBindRow(NotificationEntry entry, PackageManager pmUser,
             StatusBarNotification sbn, ExpandableNotificationRow row) {
         row.setAboveShelfChangedListener(mAboveShelfObserver);
         row.setSecureStateProvider(mUnlockMethodCache::canSkipBouncer);
@@ -438,7 +452,7 @@
     }
 
     @Override
-    public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
+    public void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded) {
         mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
         if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD && nowExpanded) {
             mShadeController.goToLockedShade(clickedEntry.getRow());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 116ecc8..8d58410 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -53,7 +53,8 @@
 /**
  */
 @Singleton
-public class StatusBarRemoteInputCallback implements Callback, Callbacks {
+public class StatusBarRemoteInputCallback implements Callback, Callbacks,
+        StatusBarStateController.StateListener {
 
     private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
     private final StatusBarStateController mStatusBarStateController
@@ -63,7 +64,6 @@
     private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
     private final Context mContext;
     private View mPendingWorkRemoteInputView;
-    private final StatusBarStateController.StateListener mStateListener = this::setStatusBarState;
     private View mPendingRemoteInputView;
     private final ShadeController mShadeController = Dependency.get(ShadeController.class);
     private KeyguardManager mKeyguardManager;
@@ -78,13 +78,14 @@
         mContext = context;
         mContext.registerReceiverAsUser(mChallengeReceiver, UserHandle.ALL,
                 new IntentFilter(ACTION_DEVICE_LOCKED_CHANGED), null, null);
-        mStatusBarStateController.addCallback(mStateListener);
+        mStatusBarStateController.addCallback(this);
         mKeyguardManager = context.getSystemService(KeyguardManager.class);
         mCommandQueue = getComponent(context, CommandQueue.class);
         mCommandQueue.addCallback(this);
     }
 
-    private void setStatusBarState(int state) {
+    @Override
+    public void onStateChanged(int state) {
         if (state == StatusBarState.SHADE && mStatusBarStateController.leaveOpenOnKeyguardHide()) {
             if (!mStatusBarStateController.isKeyguardRequested()) {
                 if (mPendingRemoteInputView != null
@@ -238,8 +239,10 @@
     }
 
     @Override
-    public void disable(int state1, int state2, boolean animate) {
-        mDisabled2 = state2;
+    public void disable(int displayId, int state1, int state2, boolean animate) {
+        if (displayId == mContext.getDisplayId()) {
+            mDisabled2 = state2;
+        }
     }
 
     protected class ChallengeReceiver extends BroadcastReceiver {
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 88f9048..ffaa236 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -69,13 +69,13 @@
     private final WindowManager mWindowManager;
     private final IActivityManager mActivityManager;
     private final DozeParameters mDozeParameters;
+    private final WindowManager.LayoutParams mLpChanged;
+    private final boolean mKeyguardScreenRotation;
     private ViewGroup mStatusBarView;
     private WindowManager.LayoutParams mLp;
-    private WindowManager.LayoutParams mLpChanged;
     private boolean mHasTopUi;
     private boolean mHasTopUiChanged;
     private int mBarHeight;
-    private final boolean mKeyguardScreenRotation;
     private float mScreenBrightnessDoze;
     private final State mCurrentState = new State();
     private OtherwisedCollapsedListener mListener;
@@ -97,6 +97,7 @@
         mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
         mDozeParameters = dozeParameters;
         mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze();
+        mLpChanged = new WindowManager.LayoutParams();
         Dependency.get(StatusBarStateController.class).addCallback(
                 mStateListener, StatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER);
         Dependency.get(ConfigurationController.class).addCallback(this);
@@ -138,7 +139,6 @@
         mStatusBarView = statusBarView;
         mBarHeight = barHeight;
         mWindowManager.addView(mStatusBarView, mLp);
-        mLpChanged = new WindowManager.LayoutParams();
         mLpChanged.copyFrom(mLp);
         onThemeChanged();
     }
@@ -228,7 +228,9 @@
     private void applyHeight(State state) {
         boolean expanded = isExpanded(state);
         if (state.forcePluginOpen) {
-            mListener.setWouldOtherwiseCollapse(expanded);
+            if (mListener != null) {
+                mListener.setWouldOtherwiseCollapse(expanded);
+            }
             expanded = true;
         }
         if (expanded) {
@@ -247,7 +249,7 @@
 
     private void applyFitsSystemWindows(State state) {
         boolean fitsSystemWindows = !state.isKeyguardShowingAndNotOccluded();
-        if (mStatusBarView.getFitsSystemWindows() != fitsSystemWindows) {
+        if (mStatusBarView != null && mStatusBarView.getFitsSystemWindows() != fitsSystemWindows) {
             mStatusBarView.setFitsSystemWindows(fitsSystemWindows);
             mStatusBarView.requestApplyInsets();
         }
@@ -289,7 +291,7 @@
         applyBrightness(state);
         applyHasTopUi(state);
         applyNotTouchable(state);
-        if (mLp.copyFrom(mLpChanged) != 0) {
+        if (mLp != null && mLp.copyFrom(mLpChanged) != 0) {
             mWindowManager.updateViewLayout(mStatusBarView, mLp);
         }
         if (mHasTopUi != mHasTopUiChanged) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 53e461d..8b25c34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -339,7 +339,7 @@
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         NotificationStackScrollLayout stackScrollLayout = getStackScrollLayout();
-        if (mService.isDozing() && !stackScrollLayout.hasPulsingNotifications()) {
+        if (mService.isDozing() && !mService.isPulsing()) {
             // Capture all touch events in always-on.
             return true;
         }
@@ -347,8 +347,7 @@
         if (mNotificationPanel.isFullyExpanded()
                 && stackScrollLayout.getVisibility() == View.VISIBLE
                 && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
-                && !mService.isBouncerShowing()
-                && !mService.isDozing()) {
+                && !mService.isBouncerShowing()) {
             intercept = mDragDownHelper.onInterceptTouchEvent(ev);
         }
         if (!intercept) {
@@ -369,7 +368,7 @@
         boolean handled = false;
         if (mService.isDozing()) {
             mDoubleTapHelper.onTouchEvent(ev);
-            handled = true;
+            handled = !mService.isPulsing();
         }
         if ((mStatusBarStateController.getState() == StatusBarState.KEYGUARD && !handled)
                 || mDragDownHelper.isDraggingDown()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index f65f826..5e94152 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -48,18 +48,36 @@
     }
 
     /**
-     * A listener that will be notified whenever a change in battery level or power save mode
-     * has occurred.
+     * A listener that will be notified whenever a change in battery level or power save mode has
+     * occurred.
      */
     interface BatteryStateChangeCallback {
-        default void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {}
-        default void onPowerSaveChanged(boolean isPowerSave) {}
+
+        default void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+        }
+
+        default void onPowerSaveChanged(boolean isPowerSave) {
+        }
     }
 
     /**
-     * If available, get the estimated battery time remaining as a string
+     * If available, get the estimated battery time remaining as a string.
+     *
+     * @param completion A lambda that will be called with the result of fetching the estimate. The
+     * first time this method is called may need to be dispatched to a background thread. The
+     * completion is called on the main thread
      */
-    default String getEstimatedTimeRemainingString() {
-        return null;
+    default void getEstimatedTimeRemainingString(EstimateFetchCompletion completion) {}
+
+    /**
+     * Callback called when the estimated time remaining text is fetched.
+     */
+    public interface EstimateFetchCompletion {
+
+        /**
+         * The callback
+         * @param estimate the estimate
+         */
+        void onBatteryRemainingEstimateRetrieved(String estimate);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 6190c8f..af3c96f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -27,9 +27,12 @@
 import android.os.PowerSaveState;
 import android.util.Log;
 
+import androidx.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.fuelgauge.BatterySaverUtils;
 import com.android.settingslib.utils.PowerUtil;
+import com.android.systemui.Dependency;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.Estimate;
 
@@ -56,6 +59,7 @@
 
     private final EnhancedEstimates mEstimates;
     private final ArrayList<BatteryController.BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
+    private final ArrayList<EstimateFetchCompletion> mFetchCallbacks = new ArrayList<>();
     private final PowerManager mPowerManager;
     private final Handler mHandler;
     private final Context mContext;
@@ -70,6 +74,7 @@
     private boolean mHasReceivedBattery = false;
     private Estimate mEstimate;
     private long mLastEstimateTimestamp = -1;
+    private boolean mFetchingEstimate = false;
 
     @Inject
     public BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates) {
@@ -197,20 +202,61 @@
     }
 
     @Override
-    public String getEstimatedTimeRemainingString() {
-        if (mEstimate == null
-                || System.currentTimeMillis() > mLastEstimateTimestamp + UPDATE_GRANULARITY_MSEC) {
-            updateEstimate();
+    public void getEstimatedTimeRemainingString(EstimateFetchCompletion completion) {
+        if (mEstimate != null
+                && mLastEstimateTimestamp > System.currentTimeMillis() - UPDATE_GRANULARITY_MSEC) {
+            String percentage = generateTimeRemainingString();
+            completion.onBatteryRemainingEstimateRetrieved(percentage);
+            return;
         }
-        // Estimates may not exist yet even if we've checked
+
+        // Need to fetch or refresh the estimate, but it may involve binder calls so offload the
+        // work
+        synchronized (mFetchCallbacks) {
+            mFetchCallbacks.add(completion);
+        }
+        updateEstimateInBackground();
+    }
+
+    @Nullable
+    private String generateTimeRemainingString() {
         if (mEstimate == null) {
             return null;
         }
-        final String percentage = NumberFormat.getPercentInstance().format((double) mLevel / 100.0);
+
+        String percentage = NumberFormat.getPercentInstance().format((double) mLevel / 100.0);
         return PowerUtil.getBatteryRemainingShortStringFormatted(
                 mContext, mEstimate.estimateMillis);
     }
 
+    private void updateEstimateInBackground() {
+        if (mFetchingEstimate) {
+            // Already dispatched a fetch. It will notify all listeners when finished
+            return;
+        }
+
+        mFetchingEstimate = true;
+        Dependency.get(Dependency.BG_HANDLER).post(() -> {
+            mEstimate = mEstimates.getEstimate();
+            mLastEstimateTimestamp = System.currentTimeMillis();
+            mFetchingEstimate = false;
+
+            Dependency.get(Dependency.MAIN_HANDLER).post(this::notifyEstimateFetchCallbacks);
+        });
+    }
+
+    private void notifyEstimateFetchCallbacks() {
+        String estimate = generateTimeRemainingString();
+
+        synchronized (mFetchCallbacks) {
+            for (EstimateFetchCompletion completion : mFetchCallbacks) {
+                completion.onBatteryRemainingEstimateRetrieved(estimate);
+            }
+
+            mFetchCallbacks.clear();
+        }
+    }
+
     private void updateEstimate() {
         mEstimate = mEstimates.getEstimate();
         mLastEstimateTimestamp = System.currentTimeMillis();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 5eb3e89..4299af7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -274,7 +274,6 @@
 
     private void updateClockVisibility() {
         boolean visible = shouldBeVisible();
-        Dependency.get(IconLogger.class).onIconVisibility("clock", visible);
         int visibility = visible ? View.VISIBLE : View.GONE;
         super.setVisibility(visibility);
     }
@@ -299,7 +298,10 @@
     }
 
     @Override
-    public void disable(int state1, int state2, boolean animate) {
+    public void disable(int displayId, int state1, int state2, boolean animate) {
+        if (displayId != getDisplay().getDisplayId()) {
+            return;
+        }
         boolean clockVisibleByPolicy = (state1 & StatusBarManager.DISABLE_CLOCK) == 0;
         if (clockVisibleByPolicy != mClockVisibleByPolicy) {
             setClockVisibilityByPolicy(clockVisibleByPolicy);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index a02c9d5..fd3f680 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -30,7 +30,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.AlertingNotificationManager;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
 
 import java.io.FileDescriptor;
@@ -108,11 +108,11 @@
         }
     }
 
-    protected boolean shouldHeadsUpBecomePinned(@NonNull NotificationData.Entry entry) {
+    protected boolean shouldHeadsUpBecomePinned(@NonNull NotificationEntry entry) {
         return hasFullScreenIntent(entry);
     }
 
-    protected boolean hasFullScreenIntent(@NonNull NotificationData.Entry entry) {
+    protected boolean hasFullScreenIntent(@NonNull NotificationEntry entry) {
         return entry.notification.getNotification().fullScreenIntent != null;
     }
 
@@ -121,7 +121,7 @@
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "setEntryPinned: " + isPinned);
         }
-        NotificationData.Entry entry = headsUpEntry.mEntry;
+        NotificationEntry entry = headsUpEntry.mEntry;
         if (entry.isRowPinned() != isPinned) {
             entry.setRowPinned(isPinned);
             updatePinnedMode();
@@ -141,7 +141,7 @@
 
     @Override
     protected void onAlertEntryAdded(AlertEntry alertEntry) {
-        NotificationData.Entry entry = alertEntry.mEntry;
+        NotificationEntry entry = alertEntry.mEntry;
         entry.setHeadsUp(true);
         setEntryPinned((HeadsUpEntry) alertEntry, shouldHeadsUpBecomePinned(entry));
         for (OnHeadsUpChangedListener listener : mListeners) {
@@ -151,7 +151,7 @@
 
     @Override
     protected void onAlertEntryRemoved(AlertEntry alertEntry) {
-        NotificationData.Entry entry = alertEntry.mEntry;
+        NotificationEntry entry = alertEntry.mEntry;
         entry.setHeadsUp(false);
         setEntryPinned((HeadsUpEntry) alertEntry, false /* isPinned */);
         for (OnHeadsUpChangedListener listener : mListeners) {
@@ -222,7 +222,7 @@
      * Returns the top Heads Up Notification, which appears to show at first.
      */
     @Nullable
-    public NotificationData.Entry getTopEntry() {
+    public NotificationEntry getTopEntry() {
         HeadsUpEntry topEntry = getTopHeadsUpEntry();
         return (topEntry != null) ? topEntry.mEntry : null;
     }
@@ -323,7 +323,7 @@
      * @return -1 if the first argument should be ranked higher than the second, 1 if the second
      * one should be ranked higher and 0 if they are equal.
      */
-    public int compare(@NonNull NotificationData.Entry a, @NonNull NotificationData.Entry b) {
+    public int compare(@NonNull NotificationEntry a, @NonNull NotificationEntry b) {
         AlertEntry aEntry = getHeadsUpEntry(a.key);
         AlertEntry bEntry = getHeadsUpEntry(b.key);
         if (aEntry == null || bEntry == null) {
@@ -336,7 +336,7 @@
      * Set an entry to be expanded and therefore stick in the heads up area if it's pinned
      * until it's collapsed again.
      */
-    public void setExpanded(@NonNull NotificationData.Entry entry, boolean expanded) {
+    public void setExpanded(@NonNull NotificationEntry entry, boolean expanded) {
         HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.key);
         if (headsUpEntry != null && entry.isRowPinned()) {
             headsUpEntry.setExpanded(expanded);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLogger.java
deleted file mode 100644
index 710e1df..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLogger.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.statusbar.policy;
-
-public interface IconLogger {
-
-    void onIconShown(String tag);
-    void onIconHidden(String tag);
-
-    default void onIconVisibility(String tag, boolean visible) {
-        if (visible) {
-            onIconShown(tag);
-        } else {
-            onIconHidden(tag);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLoggerImpl.java
deleted file mode 100644
index ba6369e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IconLoggerImpl.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.statusbar.policy;
-
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NUM_STATUS_ICONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_ICONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.STATUS_BAR_ICONS_CHANGED;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
-import static com.android.systemui.Dependency.BG_LOOPER_NAME;
-
-import android.content.Context;
-import android.metrics.LogMaker;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.ArraySet;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.internal.logging.MetricsLogger;
-
-import java.util.Arrays;
-import java.util.List;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-public class IconLoggerImpl implements IconLogger {
-
-    // Minimum ms between log statements.
-    // NonFinalForTesting
-    @VisibleForTesting
-    protected static long MIN_LOG_INTERVAL = 1000;
-
-    private final Context mContext;
-    private final Handler mHandler;
-    private final MetricsLogger mLogger;
-    private final ArraySet<String> mIcons = new ArraySet<>();
-    private final List<String> mIconIndex;
-    private long mLastLog = System.currentTimeMillis();
-
-    @Inject
-    public IconLoggerImpl(Context context, @Named(BG_LOOPER_NAME) Looper bgLooper,
-            MetricsLogger logger) {
-        mContext = context;
-        mHandler = new Handler(bgLooper);
-        mLogger = logger;
-        String[] icons = mContext.getResources().getStringArray(
-                com.android.internal.R.array.config_statusBarIcons);
-        mIconIndex = Arrays.asList(icons);
-        doLog();
-    }
-
-    @Override
-    public void onIconShown(String tag) {
-        synchronized (mIcons) {
-            if (mIcons.contains(tag)) return;
-            mIcons.add(tag);
-        }
-        if (!mHandler.hasCallbacks(mLog)) {
-            mHandler.postDelayed(mLog, MIN_LOG_INTERVAL);
-        }
-    }
-
-    @Override
-    public void onIconHidden(String tag) {
-        synchronized (mIcons) {
-            if (!mIcons.contains(tag)) return;
-            mIcons.remove(tag);
-        }
-        if (!mHandler.hasCallbacks(mLog)) {
-            mHandler.postDelayed(mLog, MIN_LOG_INTERVAL);
-        }
-    }
-
-    private void doLog() {
-        long time = System.currentTimeMillis();
-        long timeSinceLastLog = time - mLastLog;
-        mLastLog = time;
-
-        ArraySet<String> icons;
-        synchronized (mIcons) {
-            icons = new ArraySet<>(mIcons);
-        }
-        mLogger.write(new LogMaker(STATUS_BAR_ICONS_CHANGED)
-                .setType(TYPE_ACTION)
-                .setLatency(timeSinceLastLog)
-                .addTaggedData(FIELD_NUM_STATUS_ICONS, icons.size())
-                .addTaggedData(FIELD_STATUS_ICONS, getBitField(icons)));
-    }
-
-    private int getBitField(ArraySet<String> icons) {
-        int iconsVisible = 0;
-        for (String icon : icons) {
-            int index = mIconIndex.indexOf(icon);
-            if (index >= 0) {
-                iconsVisible |= (1 << index);
-            }
-        }
-        return iconsVisible;
-    }
-
-    private final Runnable mLog = this::doLog;
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 2c756ce..d404982 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -33,6 +33,7 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.TypedValue;
 import android.view.HapticFeedbackConstants;
 import android.view.InputDevice;
@@ -304,6 +305,10 @@
                 .setSubtype(mCode)
                 .addTaggedData(MetricsEvent.FIELD_NAV_ACTION, action)
                 .addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
+        // TODO(b/122195391): Added logs to make sure sysui is sending back button events
+        if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
+            Log.i(TAG, "Back button event: " + KeyEvent.actionToString(action));
+        }
         final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
         final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
                 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 9422101..f79ad71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -541,7 +541,8 @@
 
     @VisibleForTesting
     void doUpdateMobileControllers() {
-        List<SubscriptionInfo> subscriptions = mSubscriptionManager.getActiveSubscriptionInfoList();
+        List<SubscriptionInfo> subscriptions = mSubscriptionManager
+                .getActiveSubscriptionInfoList(true);
         if (subscriptions == null) {
             subscriptions = Collections.emptyList();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
index 7ad547a..438226a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
@@ -16,8 +16,7 @@
 
 package com.android.systemui.statusbar.policy;
 
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 /**
  * A listener to heads up changes
@@ -33,12 +32,12 @@
     /**
      * A notification was just pinned to the top.
      */
-    default void onHeadsUpPinned(NotificationData.Entry entry) {}
+    default void onHeadsUpPinned(NotificationEntry entry) {}
 
     /**
      * A notification was just unpinned from the top.
      */
-    default void onHeadsUpUnPinned(NotificationData.Entry entry) {}
+    default void onHeadsUpUnPinned(NotificationEntry entry) {}
 
     /**
      * A notification just became a heads up or turned back to its normal state.
@@ -46,5 +45,5 @@
      * @param entry     the entry of the changed notification
      * @param isHeadsUp whether the notification is now a headsUp notification
      */
-    default void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {}
+    default void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
index 630bd18..2b60274 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
@@ -82,6 +82,6 @@
      * to modify the disable flags according to the status of mRemoteInputActive and misLandscape.
      */
     private void recomputeDisableFlags() {
-        mCommandQueue.recomputeDisableFlags(true);
+        mCommandQueue.recomputeDisableFlags(mContext.getDisplayId(), true);
     }
 }
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 866015e..7881df9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -18,6 +18,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.app.ActivityManager;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.RemoteInput;
@@ -28,6 +29,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.text.Editable;
 import android.text.SpannedString;
 import android.text.TextWatcher;
@@ -56,7 +58,7 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.RemoteInputController;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
@@ -83,7 +85,7 @@
     private RemoteInputController mController;
     private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
 
-    private NotificationData.Entry mEntry;
+    private NotificationEntry mEntry;
 
     private boolean mRemoved;
 
@@ -180,12 +182,13 @@
     }
 
     public static RemoteInputView inflate(Context context, ViewGroup root,
-            NotificationData.Entry entry,
+            NotificationEntry entry,
             RemoteInputController controller) {
         RemoteInputView v = (RemoteInputView)
                 LayoutInflater.from(context).inflate(R.layout.remote_input, root, false);
         v.mController = controller;
         v.mEntry = entry;
+        v.mEditText.setTextOperationUser(computeTextOperationUser(entry.notification.getUser()));
         v.setTag(VIEW_TAG);
 
         return v;
@@ -283,6 +286,11 @@
         focus();
     }
 
+    private static UserHandle computeTextOperationUser(UserHandle notificationUser) {
+        return UserHandle.ALL.equals(notificationUser)
+                ? UserHandle.of(ActivityManager.getCurrentUser()) : notificationUser;
+    }
+
     public void focus() {
         MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_OPEN,
                 mEntry.notification.getPackageName());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
index 6193159..db04620 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
@@ -18,6 +18,7 @@
 
 import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
 
+import android.app.RemoteInput;
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.ContentObserver;
@@ -42,14 +43,24 @@
     private static final String KEY_REQUIRES_TARGETING_P = "requires_targeting_p";
     private static final String KEY_MAX_SQUEEZE_REMEASURE_ATTEMPTS =
             "max_squeeze_remeasure_attempts";
+    private static final String KEY_EDIT_CHOICES_BEFORE_SENDING =
+            "edit_choices_before_sending";
+    private static final String KEY_SHOW_IN_HEADS_UP = "show_in_heads_up";
+    private static final String KEY_MIN_NUM_REPLIES = "min_num_system_generated_replies";
 
     private final boolean mDefaultEnabled;
     private final boolean mDefaultRequiresP;
     private final int mDefaultMaxSqueezeRemeasureAttempts;
+    private final boolean mDefaultEditChoicesBeforeSending;
+    private final boolean mDefaultShowInHeadsUp;
+    private final int mDefaultMinNumSystemGeneratedReplies;
 
     private boolean mEnabled;
     private boolean mRequiresTargetingP;
     private int mMaxSqueezeRemeasureAttempts;
+    private boolean mEditChoicesBeforeSending;
+    private boolean mShowInHeadsUp;
+    private int mMinNumSystemGeneratedReplies;
 
     private final Context mContext;
     private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -66,6 +77,12 @@
                 R.bool.config_smart_replies_in_notifications_requires_targeting_p);
         mDefaultMaxSqueezeRemeasureAttempts = resources.getInteger(
                 R.integer.config_smart_replies_in_notifications_max_squeeze_remeasure_attempts);
+        mDefaultEditChoicesBeforeSending = resources.getBoolean(
+                R.bool.config_smart_replies_in_notifications_edit_choices_before_sending);
+        mDefaultShowInHeadsUp = resources.getBoolean(
+                R.bool.config_smart_replies_in_notifications_show_in_heads_up);
+        mDefaultMinNumSystemGeneratedReplies = resources.getInteger(
+                R.integer.config_smart_replies_in_notifications_min_num_system_generated_replies);
 
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS),
@@ -90,6 +107,11 @@
             mRequiresTargetingP = mParser.getBoolean(KEY_REQUIRES_TARGETING_P, mDefaultRequiresP);
             mMaxSqueezeRemeasureAttempts = mParser.getInt(
                     KEY_MAX_SQUEEZE_REMEASURE_ATTEMPTS, mDefaultMaxSqueezeRemeasureAttempts);
+            mEditChoicesBeforeSending = mParser.getBoolean(
+                    KEY_EDIT_CHOICES_BEFORE_SENDING, mDefaultEditChoicesBeforeSending);
+            mShowInHeadsUp = mParser.getBoolean(KEY_SHOW_IN_HEADS_UP, mDefaultShowInHeadsUp);
+            mMinNumSystemGeneratedReplies =
+                    mParser.getInt(KEY_MIN_NUM_REPLIES, mDefaultMinNumSystemGeneratedReplies);
         }
     }
 
@@ -113,4 +135,39 @@
     public int getMaxSqueezeRemeasureAttempts() {
         return mMaxSqueezeRemeasureAttempts;
     }
+
+    /**
+     * Returns whether by tapping on a choice should let the user edit the input before it
+     * is sent to the app.
+     *
+     * @param remoteInputEditChoicesBeforeSending The value from
+     *         {@link RemoteInput#getEditChoicesBeforeSending()}
+     */
+    public boolean getEffectiveEditChoicesBeforeSending(
+            @RemoteInput.EditChoicesBeforeSending int remoteInputEditChoicesBeforeSending) {
+        switch (remoteInputEditChoicesBeforeSending) {
+            case RemoteInput.EDIT_CHOICES_BEFORE_SENDING_DISABLED:
+                return false;
+            case RemoteInput.EDIT_CHOICES_BEFORE_SENDING_ENABLED:
+                return true;
+            case RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO:
+            default:
+                return mEditChoicesBeforeSending;
+        }
+    }
+
+    /**
+     * Returns whether smart suggestions should be enabled in heads-up notifications.
+     */
+    public boolean getShowInHeadsUp() {
+        return mShowInHeadsUp;
+    }
+
+    /**
+     * Returns the minimum number of system generated replies to show in a notification.
+     * If we cannot show at least this many system generated replies we should show none.
+     */
+    public int getMinNumSystemGeneratedReplies() {
+        return mMinNumSystemGeneratedReplies;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 4fa8321..c4f027f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -16,8 +16,6 @@
 import android.graphics.drawable.InsetDrawable;
 import android.graphics.drawable.RippleDrawable;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
 import android.text.Layout;
 import android.text.TextPaint;
 import android.text.method.TransformationMethod;
@@ -38,8 +36,8 @@
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.SmartReplyController;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 
 import java.text.BreakIterator;
@@ -65,7 +63,6 @@
     private final SmartReplyConstants mConstants;
     private final KeyguardDismissUtil mKeyguardDismissUtil;
     private final NotificationRemoteInputManager mRemoteInputManager;
-    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
 
     /**
      * The upper bound for the height of this view in pixels. Notifications are automatically
@@ -91,6 +88,12 @@
 
     private View mSmartReplyContainer;
 
+    /**
+     * Whether the smart replies in this view were generated by the notification assistant. If not
+     * they're provided by the app.
+     */
+    private boolean mSmartRepliesGeneratedByAssistant = false;
+
     @ColorInt
     private int mCurrentBackgroundColor;
     @ColorInt
@@ -197,7 +200,7 @@
      */
     public void addRepliesFromRemoteInput(
             SmartReplies smartReplies,
-            SmartReplyController smartReplyController, NotificationData.Entry entry) {
+            SmartReplyController smartReplyController, NotificationEntry entry) {
         if (smartReplies.remoteInput != null && smartReplies.pendingIntent != null) {
             if (smartReplies.choices != null) {
                 for (int i = 0; i < smartReplies.choices.length; ++i) {
@@ -205,6 +208,7 @@
                             getContext(), this, i, smartReplies, smartReplyController, entry);
                     addView(replyButton);
                 }
+                this.mSmartRepliesGeneratedByAssistant = smartReplies.fromAssistant;
             }
         }
         reallocateCandidateButtonQueueForSqueezing();
@@ -215,7 +219,7 @@
      * notification are shown.
      */
     public void addSmartActions(SmartActions smartActions,
-            SmartReplyController smartReplyController, NotificationData.Entry entry,
+            SmartReplyController smartReplyController, NotificationEntry entry,
             HeadsUpManager headsUpManager) {
         int numSmartActions = smartActions.actions.size();
         for (int n = 0; n < numSmartActions; n++) {
@@ -238,16 +242,15 @@
     @VisibleForTesting
     Button inflateReplyButton(Context context, ViewGroup root, int replyIndex,
             SmartReplies smartReplies, SmartReplyController smartReplyController,
-            NotificationData.Entry entry) {
+            NotificationEntry entry) {
         Button b = (Button) LayoutInflater.from(context).inflate(
                 R.layout.smart_reply_button, root, false);
         CharSequence choice = smartReplies.choices[replyIndex];
         b.setText(choice);
 
         OnDismissAction action = () -> {
-            // TODO(b/111437455): Also for EDIT_CHOICES_BEFORE_SENDING_AUTO, depending on flags.
-            if (smartReplies.remoteInput.getEditChoicesBeforeSending()
-                    == RemoteInput.EDIT_CHOICES_BEFORE_SENDING_ENABLED) {
+            if (mConstants.getEffectiveEditChoicesBeforeSending(
+                    smartReplies.remoteInput.getEditChoicesBeforeSending())) {
                 entry.remoteInputText = choice;
                 mRemoteInputManager.activateRemoteInput(b,
                         new RemoteInput[] { smartReplies.remoteInput }, smartReplies.remoteInput,
@@ -292,7 +295,7 @@
     @VisibleForTesting
     Button inflateActionButton(Context context, ViewGroup root, int actionIndex,
             SmartActions smartActions, SmartReplyController smartReplyController,
-            NotificationData.Entry entry, HeadsUpManager headsUpManager) {
+            NotificationEntry entry, HeadsUpManager headsUpManager) {
         Notification.Action action = smartActions.actions.get(actionIndex);
         Button button = (Button) LayoutInflater.from(context).inflate(
                 R.layout.smart_action_button, root, false);
@@ -311,22 +314,15 @@
                         () -> {
                             smartReplyController.smartActionClicked(
                                     entry, actionIndex, action, smartActions.fromAssistant);
-                            postOnUiThread(() ->
-                                    headsUpManager.removeNotification(entry.key, true));
+                            headsUpManager.removeNotification(entry.key, true);
                         }));
 
-        // TODO(b/119010281): handle accessibility
-
         // Mark this as an Action button
         final LayoutParams lp = (LayoutParams) button.getLayoutParams();
         lp.buttonType = SmartButtonType.ACTION;
         return button;
     }
 
-    private void postOnUiThread(Runnable runnable) {
-        mMainThreadHandler.post(runnable);
-    }
-
     @Override
     public LayoutParams generateLayoutParams(AttributeSet attrs) {
         return new LayoutParams(mContext, attrs);
@@ -355,10 +351,11 @@
             mCandidateButtonQueueForSqueezing.clear();
         }
 
-        int measuredWidth = mPaddingLeft + mPaddingRight;
-        int maxChildHeight = 0;
+        SmartSuggestionMeasures accumulatedMeasures = new SmartSuggestionMeasures(
+                mPaddingLeft + mPaddingRight,
+                0 /* maxChildHeight */,
+                mSingleLineButtonPaddingHorizontal);
         int displayedChildCount = 0;
-        int buttonPaddingHorizontal = mSingleLineButtonPaddingHorizontal;
 
         // Set up a list of suggestions where actions come before replies. Note that the Buttons
         // themselves have already been added to the view hierarchy in an order such that Smart
@@ -371,11 +368,15 @@
         smartSuggestions.addAll(smartReplies);
         List<View> coveredSuggestions = new ArrayList<>();
 
+        // SmartSuggestionMeasures for all action buttons, this will be filled in when the first
+        // reply button is added.
+        SmartSuggestionMeasures actionsMeasures = null;
+
         for (View child : smartSuggestions) {
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
 
-            child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(),
-                    buttonPaddingHorizontal, child.getPaddingBottom());
+            child.setPadding(accumulatedMeasures.mButtonPaddingHorizontal, child.getPaddingTop(),
+                    accumulatedMeasures.mButtonPaddingHorizontal, child.getPaddingBottom());
             child.measure(MEASURE_SPEC_ANY_LENGTH, heightMeasureSpec);
 
             coveredSuggestions.add(child);
@@ -391,54 +392,61 @@
             }
 
             // Remember the current measurements in case the current button doesn't fit in.
-            final int originalMaxChildHeight = maxChildHeight;
-            final int originalMeasuredWidth = measuredWidth;
-            final int originalButtonPaddingHorizontal = buttonPaddingHorizontal;
+            SmartSuggestionMeasures originalMeasures = accumulatedMeasures.clone();
+            if (actionsMeasures == null && lp.buttonType == SmartButtonType.REPLY) {
+                // We've added all actions (we go through actions first), now add their
+                // measurements.
+                actionsMeasures = accumulatedMeasures.clone();
+            }
 
             final int spacing = displayedChildCount == 0 ? 0 : mSpacing;
             final int childWidth = child.getMeasuredWidth();
             final int childHeight = child.getMeasuredHeight();
-            measuredWidth += spacing + childWidth;
-            maxChildHeight = Math.max(maxChildHeight, childHeight);
+            accumulatedMeasures.mMeasuredWidth += spacing + childWidth;
+            accumulatedMeasures.mMaxChildHeight =
+                    Math.max(accumulatedMeasures.mMaxChildHeight, childHeight);
 
             // Do we need to increase the number of lines in smart reply buttons to two?
             final boolean increaseToTwoLines =
-                    buttonPaddingHorizontal == mSingleLineButtonPaddingHorizontal
-                            && (lineCount == 2 || measuredWidth > targetWidth);
+                    (accumulatedMeasures.mButtonPaddingHorizontal
+                            == mSingleLineButtonPaddingHorizontal)
+                    && (lineCount == 2 || accumulatedMeasures.mMeasuredWidth > targetWidth);
             if (increaseToTwoLines) {
-                measuredWidth += (displayedChildCount + 1) * mSingleToDoubleLineButtonWidthIncrease;
-                buttonPaddingHorizontal = mDoubleLineButtonPaddingHorizontal;
+                accumulatedMeasures.mMeasuredWidth +=
+                        (displayedChildCount + 1) * mSingleToDoubleLineButtonWidthIncrease;
+                accumulatedMeasures.mButtonPaddingHorizontal =
+                        mDoubleLineButtonPaddingHorizontal;
             }
 
             // If the last button doesn't fit into the remaining width, try squeezing preceding
             // smart reply buttons.
-            if (measuredWidth > targetWidth) {
+            if (accumulatedMeasures.mMeasuredWidth > targetWidth) {
                 // Keep squeezing preceding and current smart reply buttons until they all fit.
-                while (measuredWidth > targetWidth
+                while (accumulatedMeasures.mMeasuredWidth > targetWidth
                         && !mCandidateButtonQueueForSqueezing.isEmpty()) {
                     final Button candidate = mCandidateButtonQueueForSqueezing.poll();
                     final int squeezeReduction = squeezeButton(candidate, heightMeasureSpec);
                     if (squeezeReduction != SQUEEZE_FAILED) {
-                        maxChildHeight = Math.max(maxChildHeight, candidate.getMeasuredHeight());
-                        measuredWidth -= squeezeReduction;
+                        accumulatedMeasures.mMaxChildHeight =
+                                Math.max(accumulatedMeasures.mMaxChildHeight,
+                                        candidate.getMeasuredHeight());
+                        accumulatedMeasures.mMeasuredWidth -= squeezeReduction;
                     }
                 }
 
                 // If the current button still doesn't fit after squeezing all buttons, undo the
                 // last squeezing round.
-                if (measuredWidth > targetWidth) {
-                    measuredWidth = originalMeasuredWidth;
-                    maxChildHeight = originalMaxChildHeight;
-                    buttonPaddingHorizontal = originalButtonPaddingHorizontal;
+                if (accumulatedMeasures.mMeasuredWidth > targetWidth) {
+                    accumulatedMeasures = originalMeasures;
 
                     // Mark all buttons from the last squeezing round as "failed to squeeze", so
                     // that they're re-measured without squeezing later.
                     markButtonsWithPendingSqueezeStatusAs(
                             LayoutParams.SQUEEZE_STATUS_FAILED, coveredSuggestions);
 
-                    // The current button doesn't fit, so there's no point in measuring further
-                    // buttons.
-                    break;
+                    // The current button doesn't fit, keep on adding lower-priority buttons in case
+                    // any of those fit.
+                    continue;
                 }
 
                 // The current button fits, so mark all squeezed buttons as "successfully squeezed"
@@ -451,16 +459,75 @@
             displayedChildCount++;
         }
 
+        if (mSmartRepliesGeneratedByAssistant) {
+            if (!gotEnoughSmartReplies(smartReplies)) {
+                // We don't have enough smart replies - hide all of them.
+                for (View smartReplyButton : smartReplies) {
+                    final LayoutParams lp = (LayoutParams) smartReplyButton.getLayoutParams();
+                    lp.show = false;
+                }
+                // Reset our measures back to when we had only added actions (before adding
+                // replies).
+                accumulatedMeasures = actionsMeasures;
+            }
+        }
+
         // We're done squeezing buttons, so we can clear the priority queue.
         mCandidateButtonQueueForSqueezing.clear();
 
         // Finally, we need to re-measure some buttons.
-        remeasureButtonsIfNecessary(buttonPaddingHorizontal, maxChildHeight);
+        remeasureButtonsIfNecessary(accumulatedMeasures.mButtonPaddingHorizontal,
+                                    accumulatedMeasures.mMaxChildHeight);
 
         setMeasuredDimension(
-                resolveSize(Math.max(getSuggestedMinimumWidth(), measuredWidth), widthMeasureSpec),
-                resolveSize(Math.max(getSuggestedMinimumHeight(),
-                        mPaddingTop + maxChildHeight + mPaddingBottom), heightMeasureSpec));
+                resolveSize(Math.max(getSuggestedMinimumWidth(),
+                                     accumulatedMeasures.mMeasuredWidth),
+                            widthMeasureSpec),
+                resolveSize(Math.max(getSuggestedMinimumHeight(), mPaddingTop
+                        + accumulatedMeasures.mMaxChildHeight + mPaddingBottom),
+                            heightMeasureSpec));
+    }
+
+    /**
+     * Fields we keep track of inside onMeasure() to correctly measure the SmartReplyView depending
+     * on which suggestions are added.
+     */
+    private static class SmartSuggestionMeasures {
+        int mMeasuredWidth = -1;
+        int mMaxChildHeight = -1;
+        int mButtonPaddingHorizontal = -1;
+
+        SmartSuggestionMeasures(int measuredWidth, int maxChildHeight,
+                int buttonPaddingHorizontal) {
+            this.mMeasuredWidth = measuredWidth;
+            this.mMaxChildHeight = maxChildHeight;
+            this.mButtonPaddingHorizontal = buttonPaddingHorizontal;
+        }
+
+        public SmartSuggestionMeasures clone() {
+            return new SmartSuggestionMeasures(
+                    mMeasuredWidth, mMaxChildHeight, mButtonPaddingHorizontal);
+        }
+    }
+
+    /**
+     * Returns whether our notification contains at least N smart replies (or 0) where N is
+     * determined by {@link SmartReplyConstants}.
+     */
+    private boolean gotEnoughSmartReplies(List<View> smartReplies) {
+        int numShownReplies = 0;
+        for (View smartReplyButton : smartReplies) {
+            final LayoutParams lp = (LayoutParams) smartReplyButton.getLayoutParams();
+            if (lp.show) {
+                numShownReplies++;
+            }
+        }
+        if (numShownReplies == 0
+                || numShownReplies >= mConstants.getMinNumSystemGeneratedReplies()) {
+            // We have enough replies, yay!
+            return true;
+        }
+        return false;
     }
 
     private List<View> filterActionsOrReplies(SmartButtonType buttonType) {
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java
new file mode 100644
index 0000000..fa4b3fe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.usb;
+
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.hardware.usb.ParcelableUsbPort;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbPort;
+import android.os.Bundle;
+import android.view.Window;
+import android.view.WindowManager;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+import com.android.systemui.R;
+
+/**
+ * Activity that alerts the user when contaminant is detected on USB port.
+ */
+public class UsbContaminantActivity extends AlertActivity
+                                  implements DialogInterface.OnClickListener {
+    private static final String TAG = "UsbContaminantActivity";
+
+    private UsbDisconnectedReceiver mDisconnectedReceiver;
+    private UsbPort mUsbPort;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        Window window = getWindow();
+        window.addSystemFlags(WindowManager.LayoutParams
+                .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+        window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+
+        super.onCreate(icicle);
+
+        Intent intent = getIntent();
+        ParcelableUsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT);
+        mUsbPort = port.getUsbPort(getSystemService(UsbManager.class));
+
+        final AlertController.AlertParams ap = mAlertParams;
+        ap.mTitle = getString(R.string.usb_contaminant_title);
+        ap.mMessage = getString(R.string.usb_contaminant_message);
+        ap.mPositiveButtonText = getString(android.R.string.ok);
+        ap.mPositiveButtonListener = this;
+
+        setupAlert();
+    }
+
+    @Override
+    public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
+        super.onWindowAttributesChanged(params);
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        finish();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index ed2ad79..12006fa 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -75,7 +75,7 @@
         final AlertController.AlertParams ap = mAlertParams;
         ap.mTitle = getString(R.string.usb_debugging_title);
         ap.mMessage = getString(R.string.usb_debugging_message, fingerprints);
-        ap.mPositiveButtonText = getString(android.R.string.ok);
+        ap.mPositiveButtonText = getString(R.string.usb_debugging_allow);
         ap.mNegativeButtonText = getString(android.R.string.cancel);
         ap.mPositiveButtonListener = this;
         ap.mNegativeButtonListener = this;
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index 59aa522..faebf60 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -26,6 +26,7 @@
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.qs.QSFooterImpl;
 import com.android.systemui.qs.QuickStatusBarHeader;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -112,6 +113,11 @@
          * Creates the QSFooterImpl.
          */
         QSFooterImpl createQsFooter();
+
+        /**
+         * Creates the NotificationStackScrollLayout.
+         */
+        NotificationStackScrollLayout createNotificationStackScrollLayout();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index 490cdd5c..6b4f7ed 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -69,10 +69,13 @@
 
         /**
          * Sets visibility of this {@link View} given the states passed from
-         * {@link com.android.systemui.statusbar.CommandQueue.Callbacks#disable(int, int)}.
+         * {@link com.android.systemui.statusbar.CommandQueue.Callbacks#disable(int, int, int)}.
          */
         @Override
-        public void disable(int state1, int state2, boolean animate) {
+        public void disable(int displayId, int state1, int state2, boolean animate) {
+            if (displayId != mView.getDisplay().getDisplayId()) {
+                return;
+            }
             final boolean disabled = ((state1 & mMask1) != 0) || ((state2 & mMask2) != 0);
             if (disabled == mDisabled) return;
             mDisabled = disabled;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/MediaSessions.java b/packages/SystemUI/src/com/android/systemui/volume/MediaSessions.java
index 712ea27..8b00eee 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/MediaSessions.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/MediaSessions.java
@@ -25,9 +25,9 @@
 import android.content.pm.ResolveInfo;
 import android.media.IRemoteVolumeController;
 import android.media.MediaMetadata;
-import android.media.session.ISessionController;
 import android.media.session.MediaController;
 import android.media.session.MediaController.PlaybackInfo;
+import android.media.session.MediaSession;
 import android.media.session.MediaSession.QueueItem;
 import android.media.session.MediaSession.Token;
 import android.media.session.MediaSessionManager;
@@ -113,17 +113,17 @@
         r.controller.setVolumeTo(level, 0);
     }
 
-    private void onRemoteVolumeChangedH(ISessionController session, int flags) {
-        final MediaController controller = new MediaController(mContext, session);
+    private void onRemoteVolumeChangedH(MediaSession.Token sessionToken, int flags) {
+        final MediaController controller = new MediaController(mContext, sessionToken);
         if (D.BUG) Log.d(TAG, "remoteVolumeChangedH " + controller.getPackageName() + " "
                 + Util.audioManagerFlagsToString(flags));
         final Token token = controller.getSessionToken();
         mCallbacks.onRemoteVolumeChanged(token, flags);
     }
 
-    private void onUpdateRemoteControllerH(ISessionController session) {
-        final MediaController controller = session != null ? new MediaController(mContext, session)
-                : null;
+    private void onUpdateRemoteControllerH(MediaSession.Token sessionToken) {
+        final MediaController controller =
+                sessionToken != null ? new MediaController(mContext, sessionToken) : null;
         final String pkg = controller != null ? controller.getPackageName() : null;
         if (D.BUG) Log.d(TAG, "updateRemoteControllerH " + pkg);
         // this may be our only indication that a remote session is changed, refresh
@@ -332,15 +332,16 @@
 
     private final IRemoteVolumeController mRvc = new IRemoteVolumeController.Stub() {
         @Override
-        public void remoteVolumeChanged(ISessionController session, int flags)
+        public void remoteVolumeChanged(MediaSession.Token sessionToken, int flags)
                 throws RemoteException {
-            mHandler.obtainMessage(H.REMOTE_VOLUME_CHANGED, flags, 0, session).sendToTarget();
+            mHandler.obtainMessage(H.REMOTE_VOLUME_CHANGED, flags, 0,
+                    sessionToken).sendToTarget();
         }
 
         @Override
-        public void updateRemoteController(final ISessionController session)
+        public void updateRemoteController(final MediaSession.Token sessionToken)
                 throws RemoteException {
-            mHandler.obtainMessage(H.UPDATE_REMOTE_CONTROLLER, session).sendToTarget();
+            mHandler.obtainMessage(H.UPDATE_REMOTE_CONTROLLER, sessionToken).sendToTarget();
         }
     };
 
@@ -360,10 +361,10 @@
                     onActiveSessionsUpdatedH(mMgr.getActiveSessions(null));
                     break;
                 case REMOTE_VOLUME_CHANGED:
-                    onRemoteVolumeChangedH((ISessionController) msg.obj, msg.arg1);
+                    onRemoteVolumeChangedH((MediaSession.Token) msg.obj, msg.arg1);
                     break;
                 case UPDATE_REMOTE_CONTROLLER:
-                    onUpdateRemoteControllerH((ISessionController) msg.obj);
+                    onUpdateRemoteControllerH((MediaSession.Token) msg.obj);
                     break;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java b/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java
new file mode 100644
index 0000000..52cabe2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java
@@ -0,0 +1,222 @@
+/*
+ * 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.wallpaper;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.RectF;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
+import android.util.AttributeSet;
+import android.util.FeatureFlagUtils;
+import android.util.Log;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.widget.ImageView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.stack.AnimationProperties;
+import com.android.systemui.statusbar.phone.ScrimState;
+
+/**
+ * A view that draws mask upon either image wallpaper or music album art in AOD.
+ */
+public class AodMaskView extends ImageView implements StatusBarStateController.StateListener,
+        ImageWallpaperTransformer.TransformationListener {
+    private static final String TAG = AodMaskView.class.getSimpleName();
+    private static final int TRANSITION_DURATION = 1000;
+
+    private static final AnimatableProperty TRANSITION_PROGRESS = AnimatableProperty.from(
+            "transition_progress",
+            AodMaskView::setTransitionAmount,
+            AodMaskView::getTransitionAmount,
+            R.id.aod_mask_transition_progress_tag,
+            R.id.aod_mask_transition_progress_start_tag,
+            R.id.aod_mask_transition_progress_end_tag
+    );
+
+    private final AnimationProperties mTransitionProperties = new AnimationProperties();
+    private final ImageWallpaperTransformer mTransformer;
+    private final RectF mBounds = new RectF();
+    private boolean mChangingStates;
+    private boolean mNeedMask;
+    private float mTransitionAmount;
+    private final WallpaperManager mWallpaperManager;
+    private final DisplayManager mDisplayManager;
+    private DisplayListener mDisplayListener = new DisplayListener() {
+        @Override
+        public void onDisplayAdded(int displayId) {
+        }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {
+        }
+
+        @Override
+        public void onDisplayChanged(int displayId) {
+            // We just support DEFAULT_DISPLAY currently.
+            if (displayId == Display.DEFAULT_DISPLAY) {
+                mTransformer.updateDisplayInfo(getDisplayInfo(displayId));
+            }
+        }
+    };
+
+    public AodMaskView(Context context) {
+        this(context, null);
+    }
+
+    public AodMaskView(Context context, AttributeSet attrs) {
+        this(context, attrs, null);
+    }
+
+    @VisibleForTesting
+    public AodMaskView(Context context, AttributeSet attrs, ImageWallpaperTransformer transformer) {
+        super(context, attrs);
+        setClickable(false);
+
+        StatusBarStateController controller = Dependency.get(StatusBarStateController.class);
+        if (controller != null) {
+            controller.addCallback(this);
+        } else {
+            Log.d(TAG, "Can not get StatusBarStateController!");
+        }
+
+        mDisplayManager = (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
+        mDisplayManager.registerDisplayListener(mDisplayListener, null);
+        mWallpaperManager =
+                (WallpaperManager) getContext().getSystemService(Context.WALLPAPER_SERVICE);
+
+        if (transformer == null) {
+            mTransformer = new ImageWallpaperTransformer(this);
+            mTransformer.addFilter(new ScrimFilter());
+            mTransformer.addFilter(new VignetteFilter());
+            mTransformer.updateOffsets();
+            mTransformer.updateDisplayInfo(getDisplayInfo(Display.DEFAULT_DISPLAY));
+
+            mTransitionProperties.setDuration(TRANSITION_DURATION);
+            mTransitionProperties.setAnimationFinishListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mTransformer.setIsTransiting(false);
+                }
+
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    mTransformer.setIsTransiting(true);
+                }
+            });
+        } else {
+            // This part should only be hit by test cases.
+            mTransformer = transformer;
+        }
+    }
+
+    private DisplayInfo getDisplayInfo(int displayId) {
+        DisplayInfo displayInfo = new DisplayInfo();
+        mDisplayManager.getDisplay(displayId).getDisplayInfo(displayInfo);
+        return displayInfo;
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        mBounds.set(0, 0, w, h);
+        mTransformer.updateOffsets();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        if (mNeedMask) {
+            mTransformer.drawTransformedImage(canvas, null /* target */, null /* src */, mBounds);
+        }
+    }
+
+    private boolean checkIfNeedMask() {
+        // We need mask for ImageWallpaper / LockScreen Wallpaper (Music album art).
+        return mWallpaperManager.getWallpaperInfo() == null || ScrimState.AOD.hasBackdrop();
+    }
+
+    @Override
+    public void onStatePreChange(int oldState, int newState) {
+        mChangingStates = oldState != newState;
+        mNeedMask = checkIfNeedMask();
+    }
+
+    @Override
+    public void onStatePostChange() {
+        mChangingStates = false;
+    }
+
+    @Override
+    public void onStateChanged(int newState) {
+    }
+
+    @Override
+    public void onDozingChanged(boolean isDozing) {
+        if (!mNeedMask) {
+            return;
+        }
+
+        boolean enabled = checkFeatureIsEnabled();
+        mTransformer.updateAmbientModeState(enabled && isDozing);
+
+        if (enabled && !mChangingStates) {
+            setAnimatorProperty(isDozing);
+        } else {
+            invalidate();
+        }
+    }
+
+    private boolean checkFeatureIsEnabled() {
+        return FeatureFlagUtils.isEnabled(
+                getContext(), FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED);
+    }
+
+    @VisibleForTesting
+    void setAnimatorProperty(boolean isDozing) {
+        PropertyAnimator.setProperty(
+                this,
+                TRANSITION_PROGRESS,
+                isDozing ? 1f : 0f /* newEndValue */,
+                mTransitionProperties,
+                true /* animated */);
+    }
+
+    @Override
+    public void onTransformationUpdated() {
+        invalidate();
+    }
+
+    private void setTransitionAmount(float amount) {
+        mTransitionAmount = amount;
+        mTransformer.updateTransitionAmount(amount);
+    }
+
+    private float getTransitionAmount() {
+        return mTransitionAmount;
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperFilter.java b/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperFilter.java
new file mode 100644
index 0000000..d457dac
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperFilter.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.systemui.wallpaper;
+
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+/**
+ * Abstract filter used by static image wallpaper.
+ */
+abstract class ImageWallpaperFilter {
+    protected static final boolean DEBUG = false;
+
+    private ImageWallpaperTransformer mTransformer;
+
+    /**
+     * Apply this filter to the bitmap before drawing on canvas.
+     * @param c      The canvas that will draw to.
+     * @param bitmap The bitmap to apply this filter.
+     * @param src    The subset of the bitmap to be drawn.
+     * @param dest   The rectangle that the bitmap will be scaled/translated to fit into.
+     */
+    public abstract void apply(@NonNull Canvas c, @Nullable Bitmap bitmap,
+            @Nullable Rect src, @NonNull RectF dest);
+
+    /**
+     * Notifies the occurrence of built-in transition of the animation.
+     * @param animator The animator which was animated.
+     */
+    public abstract void onAnimatorUpdate(ValueAnimator animator);
+
+    /**
+     * Notifies the occurrence of another transition of the animation.
+     * @param amount The transition amount.
+     */
+    public abstract void onTransitionAmountUpdate(float amount);
+
+    /**
+     * To set the associated transformer.
+     * @param transformer The transformer that is associated with this filter.
+     */
+    public void setTransformer(ImageWallpaperTransformer transformer) {
+        if (transformer != null) {
+            mTransformer = transformer;
+        }
+    }
+
+    protected ImageWallpaperTransformer getTransformer() {
+        return mTransformer;
+    }
+
+    /**
+     * Notifies the changing of the offset value of the ImageWallpaper.
+     * @param force True to force re-evaluate offsets.
+     * @param xOffset X offset of the ImageWallpaper in percentage.
+     * @param yOffset Y offset of the ImageWallpaper in percentage.
+     */
+    public void onOffsetsUpdate(boolean force, float xOffset, float yOffset) {
+        // No-op
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperTransformer.java b/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperTransformer.java
new file mode 100644
index 0000000..25b0b0a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/ImageWallpaperTransformer.java
@@ -0,0 +1,173 @@
+/*
+ * 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.wallpaper;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.view.DisplayInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class is used to manage the filters that will be applied.
+ */
+public class ImageWallpaperTransformer {
+    private static final String TAG = ImageWallpaperTransformer.class.getSimpleName();
+
+    private DisplayInfo mDisplayInfo;
+    private final List<ImageWallpaperFilter> mFilters;
+    private final TransformationListener mListener;
+    private boolean mIsInAmbientMode;
+    private boolean mIsTransiting;
+
+    /**
+     * Constructor.
+     * @param listener A listener to inform you the transformation has updated.
+     */
+    public ImageWallpaperTransformer(TransformationListener listener) {
+        mFilters = new ArrayList<>();
+        mListener = listener;
+    }
+
+    /**
+     * Claim that we want to use the specified filter.
+     * @param filter The filter will be used.
+     */
+    public void addFilter(ImageWallpaperFilter filter) {
+        if (filter != null) {
+            filter.setTransformer(this);
+            mFilters.add(filter);
+        }
+    }
+
+    /**
+     * Check if any transition is running.
+     * @return True if the transition is running, false otherwise.
+     */
+    boolean isTransiting() {
+        return mIsTransiting;
+    }
+
+    /**
+     * Indicate if any transition is running. <br/>
+     * @param isTransiting True if the transition is running.
+     */
+    void setIsTransiting(boolean isTransiting) {
+        mIsTransiting = isTransiting;
+    }
+
+    /**
+     * Check if the device is in ambient mode.
+     * @return True if the device is in ambient mode, false otherwise.
+     */
+    public boolean isInAmbientMode() {
+        return mIsInAmbientMode;
+    }
+
+    /**
+     * Update current state of ambient mode.
+     * @param isInAmbientMode Current ambient mode state.
+     */
+    public void updateAmbientModeState(boolean isInAmbientMode) {
+        mIsInAmbientMode = isInAmbientMode;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        int idx = 0;
+        for (ImageWallpaperFilter filter : mFilters) {
+            sb.append(idx++).append(": ").append(filter.getClass().getSimpleName()).append("\n");
+        }
+        if (sb.length() == 0) {
+            sb.append("No filters applied");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Set a new display info.
+     * @param displayInfo New display info.
+     */
+    public void updateDisplayInfo(DisplayInfo displayInfo) {
+        mDisplayInfo = displayInfo;
+    }
+
+    /**
+     * To get current display info.
+     * @return Current display info.
+     */
+    public DisplayInfo getDisplayInfo() {
+        return mDisplayInfo;
+    }
+
+    /**
+     * Update the offsets with default value.
+     */
+    public void updateOffsets() {
+        this.updateOffsets(true, 0f, .5f);
+    }
+
+    /**
+     * To notify the filters that the offset of the ImageWallpaper changes.
+     * @param force True to force re-evaluate offsets.
+     * @param offsetX X offset of the ImageWallpaper in percentage.
+     * @param offsetY Y offset of the ImageWallpaper in percentage.
+     */
+    public void updateOffsets(boolean force, float offsetX, float offsetY) {
+        mFilters.forEach(filter -> filter.onOffsetsUpdate(force, offsetX, offsetY));
+    }
+
+    /**
+     * Apply all specified filters to the bitmap then draw to the canvas.
+     * @param c      The canvas that will draw to.
+     * @param target The bitmap to apply filters.
+     * @param src    The subset of the bitmap to be drawn
+     * @param dest   The rectangle that the bitmap will be scaled/translated to fit into.
+     */
+    void drawTransformedImage(@NonNull Canvas c, @Nullable Bitmap target,
+            @Nullable Rect src, @NonNull RectF dest) {
+        mFilters.forEach(filter -> filter.apply(c, target, src, dest));
+    }
+
+    /**
+     * Update the transition amount. <br/>
+     * Must invoke this to update transition amount if not running built-in transition.
+     * @param amount The transition amount.
+     */
+    void updateTransitionAmount(float amount) {
+        mFilters.forEach(filter -> filter.onTransitionAmountUpdate(amount));
+        if (mListener != null) {
+            mListener.onTransformationUpdated();
+        }
+    }
+
+    /**
+     * An interface that informs the transformation status.
+     */
+    public interface TransformationListener {
+        /**
+         * Notifies the update of the transformation.
+         */
+        void onTransformationUpdated();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/ScrimFilter.java b/packages/SystemUI/src/com/android/systemui/wallpaper/ScrimFilter.java
new file mode 100644
index 0000000..637e48e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/ScrimFilter.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.systemui.wallpaper;
+
+import android.animation.ValueAnimator;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+/**
+ * A filter that implements 70% black scrim effect.
+ */
+public class ScrimFilter extends ImageWallpaperFilter {
+    private static final int MAX_ALPHA = (int) (255 * .7f);
+    private static final int MIN_ALPHA = 0;
+
+    private final Paint mPaint;
+
+    public ScrimFilter() {
+        mPaint = new Paint();
+        mPaint.setColor(Color.BLACK);
+        mPaint.setAlpha(MAX_ALPHA);
+    }
+
+    @Override
+    public void apply(Canvas c, Bitmap bitmap, Rect src, RectF dest) {
+        ImageWallpaperTransformer transformer = getTransformer();
+
+        // If it is not in the transition, we need to set the property according to aod state.
+        if (!transformer.isTransiting()) {
+            mPaint.setAlpha(transformer.isInAmbientMode() ? MAX_ALPHA : MIN_ALPHA);
+        }
+
+        c.drawRect(dest, mPaint);
+    }
+
+    @Override
+    public void onAnimatorUpdate(ValueAnimator animator) {
+        ImageWallpaperTransformer transformer = getTransformer();
+        float fraction = animator.getAnimatedFraction();
+        float factor = transformer.isInAmbientMode() ? fraction : 1f - fraction;
+        mPaint.setAlpha((int) (factor * MAX_ALPHA));
+    }
+
+    @Override
+    public void onTransitionAmountUpdate(float amount) {
+        mPaint.setAlpha((int) (amount * MAX_ALPHA));
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/VignetteFilter.java b/packages/SystemUI/src/com/android/systemui/wallpaper/VignetteFilter.java
new file mode 100644
index 0000000..ad0b98b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/VignetteFilter.java
@@ -0,0 +1,124 @@
+/*
+ * 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.wallpaper;
+
+import android.animation.ValueAnimator;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PointF;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.util.Log;
+import android.view.DisplayInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A filter that implements vignette effect.
+ */
+public class VignetteFilter extends ImageWallpaperFilter {
+    private static final String TAG = VignetteFilter.class.getSimpleName();
+    private static final int MAX_ALPHA = 255;
+    private static final int MIN_ALPHA = 0;
+
+    private final Paint mPaint;
+    private final Matrix mMatrix;
+    private final Shader mShader;
+
+    private float mXOffset;
+    private float mYOffset;
+    private float mCenterX;
+    private float mCenterY;
+    private float mStretchX;
+    private float mStretchY;
+    private boolean mCalculateOffsetNeeded;
+
+    public VignetteFilter() {
+        mPaint = new Paint();
+        mMatrix = new Matrix();
+        mShader = new RadialGradient(0, 0, 1,
+                Color.TRANSPARENT, Color.BLACK, Shader.TileMode.CLAMP);
+    }
+
+    @Override
+    public void apply(Canvas c, Bitmap bitmap, Rect src, RectF dest) {
+        DisplayInfo info = getTransformer().getDisplayInfo();
+
+        if (mCalculateOffsetNeeded) {
+            int lw = info.logicalWidth;
+            int lh = info.logicalHeight;
+            mCenterX = lw / 2 + (dest.width() - lw) * mXOffset;
+            mCenterY = lh / 2 + (dest.height() - lh) * mYOffset;
+            mStretchX = info.logicalWidth / 2;
+            mStretchY = info.logicalHeight / 2;
+            mCalculateOffsetNeeded = false;
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "apply: lw=" + info.logicalWidth + ", lh=" + info.logicalHeight
+                    + ", center=(" + mCenterX + "," + mCenterY + ")"
+                    + ", stretch=(" + mStretchX + "," + mStretchY + ")");
+        }
+
+        mMatrix.reset();
+        mMatrix.postTranslate(mCenterX, mCenterY);
+        mMatrix.postScale(mStretchX, mStretchY, mCenterX, mCenterY);
+        mShader.setLocalMatrix(mMatrix);
+        mPaint.setShader(mShader);
+
+        ImageWallpaperTransformer transformer = getTransformer();
+
+        // If it is not in the transition, we need to set the property according to aod state.
+        if (!transformer.isTransiting()) {
+            mPaint.setAlpha(transformer.isInAmbientMode() ? MAX_ALPHA : MIN_ALPHA);
+        }
+
+        c.drawRect(dest, mPaint);
+    }
+
+    @Override
+    public void onAnimatorUpdate(ValueAnimator animator) {
+        ImageWallpaperTransformer transformer = getTransformer();
+        float fraction = animator.getAnimatedFraction();
+        float factor = transformer.isInAmbientMode() ? fraction : 1f - fraction;
+        mPaint.setAlpha((int) (factor * MAX_ALPHA));
+    }
+
+    @Override
+    public void onTransitionAmountUpdate(float amount) {
+        mPaint.setAlpha((int) (amount * MAX_ALPHA));
+    }
+
+    @Override
+    public void onOffsetsUpdate(boolean force, float xOffset, float yOffset) {
+        if (force || mXOffset != xOffset || mYOffset != yOffset) {
+            mXOffset = xOffset;
+            mYOffset = yOffset;
+            mCalculateOffsetNeeded = true;
+        }
+    }
+
+    @VisibleForTesting
+    public PointF getCenterPoint() {
+        return new PointF(mCenterX, mCenterY);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 4150602..d80b444 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -21,7 +21,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -35,18 +34,20 @@
 import android.testing.TestableLooper.RunWithLooper;
 import android.text.TextPaint;
 import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.TextClock;
 
+import com.android.keyguard.clock.ClockManager;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.ClockPlugin;
-import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -58,8 +59,8 @@
 // the keyguard_clcok_switch layout is inflated.
 @RunWithLooper(setAsMainLooper = true)
 public class KeyguardClockSwitchTest extends SysuiTestCase {
-    private PluginManager mPluginManager;
     private FrameLayout mClockContainer;
+    private StatusBarStateController.StateListener mStateListener;
 
     @Mock
     TextClock mClockView;
@@ -68,29 +69,13 @@
 
     @Before
     public void setUp() {
-        mPluginManager = mDependency.injectMockDependency(PluginManager.class);
         LayoutInflater layoutInflater = LayoutInflater.from(getContext());
         mKeyguardClockSwitch =
                 (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
         mClockContainer = mKeyguardClockSwitch.findViewById(R.id.clock_view);
         MockitoAnnotations.initMocks(this);
         when(mClockView.getPaint()).thenReturn(mock(TextPaint.class));
-    }
-
-    @Test
-    public void onAttachToWindow_addPluginListener() {
-        mKeyguardClockSwitch.onAttachedToWindow();
-
-        ArgumentCaptor<PluginListener> listener = ArgumentCaptor.forClass(PluginListener.class);
-        verify(mPluginManager).addPluginListener(listener.capture(), eq(ClockPlugin.class));
-    }
-
-    @Test
-    public void onDetachToWindow_removePluginListener() {
-        mKeyguardClockSwitch.onDetachedFromWindow();
-
-        ArgumentCaptor<PluginListener> listener = ArgumentCaptor.forClass(PluginListener.class);
-        verify(mPluginManager).removePluginListener(listener.capture());
+        mStateListener = mKeyguardClockSwitch.getStateListener();
     }
 
     @Test
@@ -98,9 +83,8 @@
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getView()).thenReturn(pluginView);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
 
-        listener.onPluginConnected(plugin, null);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
 
         verify(mClockView).setVisibility(GONE);
         assertThat(plugin.getView().getParent()).isEqualTo(mClockContainer);
@@ -116,9 +100,8 @@
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getBigClockView()).thenReturn(pluginView);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
         // WHEN the plugin is connected
-        listener.onPluginConnected(plugin, null);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
         // THEN the big clock container is visible and it is the parent of the
         // big clock view.
         assertThat(bigClockContainer.getVisibility()).isEqualTo(VISIBLE);
@@ -128,8 +111,7 @@
     @Test
     public void onPluginConnected_nullView() {
         ClockPlugin plugin = mock(ClockPlugin.class);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin, null);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
         verify(mClockView, never()).setVisibility(GONE);
     }
 
@@ -138,27 +120,36 @@
         // GIVEN a plugin has already connected
         ClockPlugin plugin1 = mock(ClockPlugin.class);
         when(plugin1.getView()).thenReturn(new TextClock(getContext()));
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin1, null);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin1);
         // WHEN a second plugin is connected
         ClockPlugin plugin2 = mock(ClockPlugin.class);
         when(plugin2.getView()).thenReturn(new TextClock(getContext()));
-        listener.onPluginConnected(plugin2, null);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin2);
         // THEN only the view from the second plugin should be a child of KeyguardClockSwitch.
         assertThat(plugin2.getView().getParent()).isEqualTo(mClockContainer);
         assertThat(plugin1.getView().getParent()).isNull();
     }
 
     @Test
+    public void onPluginConnected_darkAmountInitialized() {
+        // GIVEN that the dark amount has already been set
+        mKeyguardClockSwitch.setDarkAmount(0.5f);
+        // WHEN a plugin is connected
+        ClockPlugin plugin = mock(ClockPlugin.class);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+        // THEN dark amount should be initalized on the plugin.
+        verify(plugin).setDarkAmount(0.5f);
+    }
+
+    @Test
     public void onPluginDisconnected_showDefaultClock() {
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getView()).thenReturn(pluginView);
         mClockView.setVisibility(GONE);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
 
-        listener.onPluginConnected(plugin, null);
-        listener.onPluginDisconnected(plugin);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
 
         verify(mClockView).setVisibility(VISIBLE);
         assertThat(plugin.getView().getParent()).isNull();
@@ -174,10 +165,9 @@
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getBigClockView()).thenReturn(pluginView);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin, null);
-        // WHEN the plugin is disconnected
-        listener.onPluginDisconnected(plugin);
+        // WHEN the plugin is connected and then disconnected
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
         // THEN the big lock container is GONE and the big clock view doesn't have
         // a parent.
         assertThat(bigClockContainer.getVisibility()).isEqualTo(GONE);
@@ -187,41 +177,23 @@
     @Test
     public void onPluginDisconnected_nullView() {
         ClockPlugin plugin = mock(ClockPlugin.class);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin, null);
-        listener.onPluginDisconnected(plugin);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
         verify(mClockView, never()).setVisibility(GONE);
     }
 
     @Test
-    public void onPluginDisconnected_firstOfTwoDisconnected() {
-        // GIVEN two plugins are connected
-        ClockPlugin plugin1 = mock(ClockPlugin.class);
-        when(plugin1.getView()).thenReturn(new TextClock(getContext()));
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin1, null);
-        ClockPlugin plugin2 = mock(ClockPlugin.class);
-        when(plugin2.getView()).thenReturn(new TextClock(getContext()));
-        listener.onPluginConnected(plugin2, null);
-        // WHEN the first plugin is disconnected
-        listener.onPluginDisconnected(plugin1);
-        // THEN the view from the second plugin is still a child of KeyguardClockSwitch.
-        assertThat(plugin2.getView().getParent()).isEqualTo(mClockContainer);
-        assertThat(plugin1.getView().getParent()).isNull();
-    }
-
-    @Test
     public void onPluginDisconnected_secondOfTwoDisconnected() {
         // GIVEN two plugins are connected
         ClockPlugin plugin1 = mock(ClockPlugin.class);
         when(plugin1.getView()).thenReturn(new TextClock(getContext()));
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin1, null);
+        ClockManager.ClockChangedListener listener = mKeyguardClockSwitch.getClockChangedListener();
+        listener.onClockChanged(plugin1);
         ClockPlugin plugin2 = mock(ClockPlugin.class);
         when(plugin2.getView()).thenReturn(new TextClock(getContext()));
-        listener.onPluginConnected(plugin2, null);
+        listener.onClockChanged(plugin2);
         // WHEN the second plugin is disconnected
-        listener.onPluginDisconnected(plugin2);
+        listener.onClockChanged(null);
         // THEN the default clock should be shown.
         verify(mClockView).setVisibility(VISIBLE);
         assertThat(plugin1.getView().getParent()).isNull();
@@ -240,8 +212,7 @@
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getView()).thenReturn(pluginView);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin, null);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
 
         mKeyguardClockSwitch.setTextColor(Color.WHITE);
 
@@ -265,11 +236,34 @@
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getView()).thenReturn(pluginView);
         Style style = mock(Style.class);
-        PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
-        listener.onPluginConnected(plugin, null);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
 
         mKeyguardClockSwitch.setStyle(style);
 
         verify(plugin).setStyle(style);
     }
+
+    @Test
+    public void onStateChanged_InvisibleInShade() {
+        // GIVEN that the big clock container is visible
+        ViewGroup container = mock(ViewGroup.class);
+        when(container.getVisibility()).thenReturn(View.VISIBLE);
+        mKeyguardClockSwitch.setBigClockContainer(container);
+        // WHEN transitioned to SHADE state
+        mStateListener.onStateChanged(StatusBarState.SHADE);
+        // THEN the container is invisible.
+        verify(container).setVisibility(View.INVISIBLE);
+    }
+
+    @Test
+    public void onStateChanged_VisibleInKeyguard() {
+        // GIVEN that the big clock container is invisible
+        ViewGroup container = mock(ViewGroup.class);
+        when(container.getVisibility()).thenReturn(View.INVISIBLE);
+        mKeyguardClockSwitch.setBigClockContainer(container);
+        // WHEN transitioned to KEYGUARD state
+        mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+        // THEN the container is visible.
+        verify(container).setVisibility(View.VISIBLE);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
new file mode 100644
index 0000000..9e946fa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public final class BubbleClockControllerTest extends SysuiTestCase {
+
+    private BubbleClockController mClockController;
+
+    @Before
+    public void setUp() {
+        LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+        mClockController = BubbleClockController.build(layoutInflater);
+    }
+
+    @Test
+    public void setDarkAmount_fadeIn() {
+        ViewGroup smallClockFrame = (ViewGroup) mClockController.getView();
+        View smallClock = smallClockFrame.getChildAt(0);
+        // WHEN dark amount is set to AOD
+        mClockController.setDarkAmount(1f);
+        // THEN small clock should not be shown.
+        assertThat(smallClock.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void setTextColor_setDigitalClock() {
+        ViewGroup smallClock = (ViewGroup) mClockController.getView();
+        // WHEN text color is set
+        mClockController.setTextColor(42);
+        // THEN child of small clock should have text color set.
+        TextView digitalClock = (TextView) smallClock.getChildAt(0);
+        assertThat(digitalClock.getCurrentTextColor()).isEqualTo(42);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java
new file mode 100644
index 0000000..fd7657f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public final class CrossFadeDarkControllerTest extends SysuiTestCase {
+
+    private View mViewFadeIn;
+    private View mViewFadeOut;
+    private CrossFadeDarkController mDarkController;
+
+    @Before
+    public void setUp() {
+        mViewFadeIn = new TextView(getContext());
+        mViewFadeIn.setVisibility(View.VISIBLE);
+        mViewFadeIn.setAlpha(1f);
+        mViewFadeOut = new TextView(getContext());
+        mViewFadeOut.setVisibility(View.VISIBLE);
+        mViewFadeOut.setAlpha(1f);
+
+        mDarkController = new CrossFadeDarkController(mViewFadeIn, mViewFadeOut);
+    }
+
+    @Test
+    public void setDarkAmount_fadeIn() {
+        // WHEN dark amount corresponds to AOD
+        mDarkController.setDarkAmount(1f);
+        // THEN fade in view should be faded in and fade out view faded out.
+        assertThat(mViewFadeIn.getAlpha()).isEqualTo(1f);
+        assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mViewFadeOut.getAlpha()).isEqualTo(0f);
+        assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void setDarkAmount_fadeOut() {
+        // WHEN dark amount corresponds to lock screen
+        mDarkController.setDarkAmount(0f);
+        // THEN fade out view should bed faded out and fade in view faded in.
+        assertThat(mViewFadeIn.getAlpha()).isEqualTo(0f);
+        assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mViewFadeOut.getAlpha()).isEqualTo(1f);
+        assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void setDarkAmount_partialFadeIn() {
+        // WHEN dark amount corresponds to a partial transition
+        mDarkController.setDarkAmount(0.9f);
+        // THEN views should have intermediate alpha value.
+        assertThat(mViewFadeIn.getAlpha()).isGreaterThan(0f);
+        assertThat(mViewFadeIn.getAlpha()).isLessThan(1f);
+        assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void setDarkAmount_partialFadeOut() {
+        // WHEN dark amount corresponds to a partial transition
+        mDarkController.setDarkAmount(0.1f);
+        // THEN views should have intermediate alpha value.
+        assertThat(mViewFadeOut.getAlpha()).isGreaterThan(0f);
+        assertThat(mViewFadeOut.getAlpha()).isLessThan(1f);
+        assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java
new file mode 100644
index 0000000..8de8f3d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard.clock;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public final class StretchAnalogClockControllerTest extends SysuiTestCase {
+
+    private StretchAnalogClockController mClockController;
+
+    @Before
+    public void setUp() {
+        LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+        mClockController = StretchAnalogClockController.build(layoutInflater);
+    }
+
+    @Test
+    public void setDarkAmount_fadeIn() {
+        ViewGroup smallClockFrame = (ViewGroup) mClockController.getView();
+        View smallClock = smallClockFrame.getChildAt(0);
+        // WHEN dark amount is set to AOD
+        mClockController.setDarkAmount(1f);
+        // THEN small clock should not be shown.
+        assertThat(smallClock.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void setTextColor_setDigitalClock() {
+        ViewGroup smallClock = (ViewGroup) mClockController.getView();
+        // WHEN text color is set
+        mClockController.setTextColor(42);
+        // THEN child of small clock should have text color set.
+        TextView digitalClock = (TextView) smallClock.getChildAt(0);
+        assertThat(digitalClock.getCurrentTextColor()).isEqualTo(42);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
index 3426e11..61bfa75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
@@ -69,4 +69,10 @@
         mDependency.onConfigurationChanged(null);
         verify(d).onConfigurationChanged(eq(null));
     }
+
+    @Test
+    public void testInitDependency() {
+        Dependency.clearDependencies();
+        Dependency.initDependencies(mContext);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index f278a17..31e8071 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.annotation.UserIdInt;
@@ -35,197 +36,95 @@
 import android.widget.RemoteViews;
 
 import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ForegroundServiceControllerTest extends SysuiTestCase {
-    public static @UserIdInt int USERID_ONE = 10; // UserManagerService.MIN_USER_ID;
-    public static @UserIdInt int USERID_TWO = USERID_ONE + 1;
+    @UserIdInt private static final int USERID_ONE = 10; // UserManagerService.MIN_USER_ID;
+    @UserIdInt private static final int USERID_TWO = USERID_ONE + 1;
 
-    private ForegroundServiceController fsc;
+    private ForegroundServiceController mFsc;
+    private ForegroundServiceNotificationListener mListener;
+    private NotificationEntryListener mEntryListener;
 
     @Before
     public void setUp() throws Exception {
-        fsc = new ForegroundServiceControllerImpl(mContext);
-    }
-
-    @Test
-    public void testNotificationCRUD_dungeon() {
-        StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, "com.example.app1");
-        StatusBarNotification sbn_user2_app2_fg = makeMockFgSBN(USERID_TWO, "com.example.app2");
-        StatusBarNotification sbn_user1_app3_fg = makeMockFgSBN(USERID_ONE, "com.example.app3");
-        StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
-                5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
-        StatusBarNotification sbn_user2_app1 = makeMockSBN(USERID_TWO, "com.example.app1",
-                5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
-
-        assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
-        assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
-        assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
-        assertFalse(fsc.removeNotification(sbn_user1_app1));
-        assertFalse(fsc.removeNotification(sbn_user2_app1));
-
-        fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
-        fsc.addNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_DEFAULT);
-        fsc.addNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_DEFAULT);
-        fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
-        fsc.addNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_DEFAULT);
-
-        // these are never added to the tracker
-        assertFalse(fsc.removeNotification(sbn_user1_app1));
-        assertFalse(fsc.removeNotification(sbn_user2_app1));
-
-        fsc.updateNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
-        fsc.updateNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_DEFAULT);
-        // should still not be there
-        assertFalse(fsc.removeNotification(sbn_user1_app1));
-        assertFalse(fsc.removeNotification(sbn_user2_app1));
-
-        fsc.updateNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_DEFAULT);
-        fsc.updateNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_DEFAULT);
-        fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
-
-        assertTrue(fsc.removeNotification(sbn_user1_app3_fg));
-        assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
-
-        assertTrue(fsc.removeNotification(sbn_user2_app2_fg));
-        assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
-
-        assertTrue(fsc.removeNotification(sbn_user1_app1_fg));
-        assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
-
-        assertFalse(fsc.removeNotification(sbn_user1_app1));
-        assertFalse(fsc.removeNotification(sbn_user2_app1));
-    }
-
-    @Test
-    public void testNotificationCRUD_stdLayout() {
-        StatusBarNotification sbn_user1_app1_fg =
-                makeMockFgSBN(USERID_ONE, "com.example.app1", 0, true);
-        StatusBarNotification sbn_user2_app2_fg =
-                makeMockFgSBN(USERID_TWO, "com.example.app2", 1, true);
-        StatusBarNotification sbn_user1_app3_fg =
-                makeMockFgSBN(USERID_ONE, "com.example.app3", 2, true);
-        StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
-                5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
-        StatusBarNotification sbn_user2_app1 = makeMockSBN(USERID_TWO, "com.example.app1",
-                5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
-
-        assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
-        assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
-        assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
-        assertFalse(fsc.removeNotification(sbn_user1_app1));
-        assertFalse(fsc.removeNotification(sbn_user2_app1));
-
-        fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
-        fsc.addNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_MIN);
-        fsc.addNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_MIN);
-        fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
-        fsc.addNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_MIN);
-
-        // these are never added to the tracker
-        assertFalse(fsc.removeNotification(sbn_user1_app1));
-        assertFalse(fsc.removeNotification(sbn_user2_app1));
-
-        fsc.updateNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
-        fsc.updateNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_MIN);
-        // should still not be there
-        assertFalse(fsc.removeNotification(sbn_user1_app1));
-        assertFalse(fsc.removeNotification(sbn_user2_app1));
-
-        fsc.updateNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_MIN);
-        fsc.updateNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_MIN);
-        fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
-
-        assertTrue(fsc.removeNotification(sbn_user1_app3_fg));
-        assertFalse(fsc.removeNotification(sbn_user1_app3_fg));
-
-        assertTrue(fsc.removeNotification(sbn_user2_app2_fg));
-        assertFalse(fsc.removeNotification(sbn_user2_app2_fg));
-
-        assertTrue(fsc.removeNotification(sbn_user1_app1_fg));
-        assertFalse(fsc.removeNotification(sbn_user1_app1_fg));
-
-        assertFalse(fsc.removeNotification(sbn_user1_app1));
-        assertFalse(fsc.removeNotification(sbn_user2_app1));
+        mFsc = new ForegroundServiceController();
+        NotificationEntryManager notificationEntryManager = mock(NotificationEntryManager.class);
+        mListener = new ForegroundServiceNotificationListener(
+                mContext, mFsc, notificationEntryManager);
+        ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
+                ArgumentCaptor.forClass(NotificationEntryListener.class);
+        verify(notificationEntryManager).addNotificationEntryListener(
+                entryListenerCaptor.capture());
+        mEntryListener = entryListenerCaptor.getValue();
     }
 
     @Test
     public void testAppOpsCRUD() {
         // no crash on remove that doesn't exist
-        fsc.onAppOpChanged(9, 1000, "pkg1", false);
-        assertNull(fsc.getAppOps(0, "pkg1"));
+        mFsc.onAppOpChanged(9, 1000, "pkg1", false);
+        assertNull(mFsc.getAppOps(0, "pkg1"));
 
         // multiuser & multipackage
-        fsc.onAppOpChanged(8, 50, "pkg1", true);
-        fsc.onAppOpChanged(1, 60, "pkg3", true);
-        fsc.onAppOpChanged(7, 500000, "pkg2", true);
+        mFsc.onAppOpChanged(8, 50, "pkg1", true);
+        mFsc.onAppOpChanged(1, 60, "pkg3", true);
+        mFsc.onAppOpChanged(7, 500000, "pkg2", true);
 
-        assertEquals(1, fsc.getAppOps(0, "pkg1").size());
-        assertTrue(fsc.getAppOps(0, "pkg1").contains(8));
+        assertEquals(1, mFsc.getAppOps(0, "pkg1").size());
+        assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
 
-        assertEquals(1, fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
-        assertTrue(fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
+        assertEquals(1, mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
+        assertTrue(mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
 
-        assertEquals(1, fsc.getAppOps(0, "pkg3").size());
-        assertTrue(fsc.getAppOps(0, "pkg3").contains(1));
+        assertEquals(1, mFsc.getAppOps(0, "pkg3").size());
+        assertTrue(mFsc.getAppOps(0, "pkg3").contains(1));
 
         // multiple ops for the same package
-        fsc.onAppOpChanged(9, 50, "pkg1", true);
-        fsc.onAppOpChanged(5, 50, "pkg1", true);
+        mFsc.onAppOpChanged(9, 50, "pkg1", true);
+        mFsc.onAppOpChanged(5, 50, "pkg1", true);
 
-        assertEquals(3, fsc.getAppOps(0, "pkg1").size());
-        assertTrue(fsc.getAppOps(0, "pkg1").contains(8));
-        assertTrue(fsc.getAppOps(0, "pkg1").contains(9));
-        assertTrue(fsc.getAppOps(0, "pkg1").contains(5));
+        assertEquals(3, mFsc.getAppOps(0, "pkg1").size());
+        assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
+        assertTrue(mFsc.getAppOps(0, "pkg1").contains(9));
+        assertTrue(mFsc.getAppOps(0, "pkg1").contains(5));
 
-        assertEquals(1, fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
-        assertTrue(fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
+        assertEquals(1, mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size());
+        assertTrue(mFsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7));
 
         // remove one of the multiples
-        fsc.onAppOpChanged(9, 50, "pkg1", false);
-        assertEquals(2, fsc.getAppOps(0, "pkg1").size());
-        assertTrue(fsc.getAppOps(0, "pkg1").contains(8));
-        assertTrue(fsc.getAppOps(0, "pkg1").contains(5));
+        mFsc.onAppOpChanged(9, 50, "pkg1", false);
+        assertEquals(2, mFsc.getAppOps(0, "pkg1").size());
+        assertTrue(mFsc.getAppOps(0, "pkg1").contains(8));
+        assertTrue(mFsc.getAppOps(0, "pkg1").contains(5));
 
         // remove last op
-        fsc.onAppOpChanged(1, 60, "pkg3", false);
-        assertNull(fsc.getAppOps(0, "pkg3"));
+        mFsc.onAppOpChanged(1, 60, "pkg3", false);
+        assertNull(mFsc.getAppOps(0, "pkg3"));
     }
 
     @Test
-    public void testDungeonPredicate() {
+    public void testDisclosurePredicate() {
         StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
                 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
-        StatusBarNotification sbn_user1_dungeon = makeMockSBN(USERID_ONE, "android",
+        StatusBarNotification sbn_user1_disclosure = makeMockSBN(USERID_ONE, "android",
                 SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
                 null, Notification.FLAG_NO_CLEAR);
 
-        assertTrue(fsc.isDungeonNotification(sbn_user1_dungeon));
-        assertFalse(fsc.isDungeonNotification(sbn_user1_app1));
+        assertTrue(mFsc.isDisclosureNotification(sbn_user1_disclosure));
+        assertFalse(mFsc.isDisclosureNotification(sbn_user1_app1));
     }
 
     @Test
-    public void testDungeonCRUD() {
-        StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1",
-                5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
-        StatusBarNotification sbn_user1_dungeon = makeMockSBN(USERID_ONE, "android",
-                SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
-                null, Notification.FLAG_NO_CLEAR);
-
-        fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
-        fsc.addNotification(sbn_user1_dungeon, NotificationManager.IMPORTANCE_DEFAULT);
-
-        fsc.removeNotification(sbn_user1_dungeon);
-        assertFalse(fsc.removeNotification(sbn_user1_app1));
-    }
-
-    @Test
-    public void testNeedsDungeonAfterRemovingUnrelatedNotification() {
+    public void testNeedsDisclosureAfterRemovingUnrelatedNotification() {
         final String PKG1 = "com.example.app100";
 
         StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
@@ -233,21 +132,21 @@
         StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1);
 
         // first add a normal notification
-        fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+        entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
         // nothing required yet
-        assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
         // now the app starts a fg service
-        fsc.addNotification(makeMockDungeon(USERID_ONE, new String[]{ PKG1 }),
+        entryAdded(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
                 NotificationManager.IMPORTANCE_DEFAULT);
-        assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
         // add the fg notification
-        fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
-        assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // app1 has got it covered
+        entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has got it covered
         // remove the boring notification
-        fsc.removeNotification(sbn_user1_app1);
-        assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // app1 has STILL got it covered
-        assertTrue(fsc.removeNotification(sbn_user1_app1_fg));
-        assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
+        entryRemoved(sbn_user1_app1);
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has STILL got it covered
+        entryRemoved(sbn_user1_app1_fg);
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
     }
 
     @Test
@@ -257,115 +156,117 @@
 
         StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
                 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
-        fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+        entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
 
         // no services are "running"
-        fsc.addNotification(makeMockDungeon(USERID_ONE, null),
+        entryAdded(makeMockDisclosure(USERID_ONE, null),
                 NotificationManager.IMPORTANCE_DEFAULT);
 
-        assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
 
-        fsc.updateNotification(makeMockDungeon(USERID_ONE, new String[]{PKG1}),
+        entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
                 NotificationManager.IMPORTANCE_DEFAULT);
-        assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
 
         // switch to different package
-        fsc.updateNotification(makeMockDungeon(USERID_ONE, new String[]{PKG2}),
+        entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG2}),
                 NotificationManager.IMPORTANCE_DEFAULT);
-        assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
 
-        fsc.updateNotification(makeMockDungeon(USERID_TWO, new String[]{PKG1}),
+        entryUpdated(makeMockDisclosure(USERID_TWO, new String[]{PKG1}),
                 NotificationManager.IMPORTANCE_DEFAULT);
-        assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
-        assertTrue(fsc.isDungeonNeededForUser(USERID_TWO)); // finally user2 needs one too
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO)); // finally user2 needs one too
 
-        fsc.updateNotification(makeMockDungeon(USERID_ONE, new String[]{PKG2, PKG1}),
+        entryUpdated(makeMockDisclosure(USERID_ONE, new String[]{PKG2, PKG1}),
                 NotificationManager.IMPORTANCE_DEFAULT);
-        assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
-        assertTrue(fsc.isDungeonNeededForUser(USERID_TWO));
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO));
 
-        fsc.removeNotification(makeMockDungeon(USERID_ONE, null /*unused*/));
-        assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
-        assertTrue(fsc.isDungeonNeededForUser(USERID_TWO));
+        entryRemoved(makeMockDisclosure(USERID_ONE, null /*unused*/));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_TWO));
 
-        fsc.removeNotification(makeMockDungeon(USERID_TWO, null /*unused*/));
-        assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+        entryRemoved(makeMockDisclosure(USERID_TWO, null /*unused*/));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
     }
 
     @Test
-    public void testDungeonBasic() {
+    public void testDisclosureBasic() {
         final String PKG1 = "com.example.app0";
 
         StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, PKG1,
                 5000, "monkeys", Notification.FLAG_AUTO_CANCEL);
         StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1);
 
-        fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT); // not fg
-        fsc.addNotification(makeMockDungeon(USERID_ONE, new String[]{ PKG1 }),
+        entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT); // not fg
+        entryAdded(makeMockDisclosure(USERID_ONE, new String[]{PKG1}),
                 NotificationManager.IMPORTANCE_DEFAULT);
-        assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
-        fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
-        assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // app1 has got it covered
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
+        entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE)); // app1 has got it covered
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
 
         // let's take out the other notification and see what happens.
 
-        fsc.removeNotification(sbn_user1_app1);
-        assertFalse(fsc.isDungeonNeededForUser(USERID_ONE)); // still covered by sbn_user1_app1_fg
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+        entryRemoved(sbn_user1_app1);
+        assertFalse(
+                mFsc.isDisclosureNeededForUser(USERID_ONE)); // still covered by sbn_user1_app1_fg
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
 
         // let's attempt to downgrade the notification from FLAG_FOREGROUND and see what we get
         StatusBarNotification sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1);
         sbn_user1_app1_fg_sneaky.getNotification().flags = 0;
-        fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_DEFAULT);
-        assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+        entryUpdated(sbn_user1_app1_fg_sneaky,
+                NotificationManager.IMPORTANCE_DEFAULT);
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
 
         // ok, ok, we'll put it back
         sbn_user1_app1_fg_sneaky.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
-        fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
-        assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+        entryUpdated(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_DEFAULT);
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
 
-        assertTrue(fsc.removeNotification(sbn_user1_app1_fg_sneaky));
-        assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); // should be required!
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+        entryRemoved(sbn_user1_app1_fg_sneaky);
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE)); // should be required!
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
 
         // now let's test an upgrade
-        fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
-        assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+        entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_DEFAULT);
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
         sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
-        fsc.updateNotification(sbn_user1_app1,
+        entryUpdated(sbn_user1_app1,
                 NotificationManager.IMPORTANCE_DEFAULT); // this is now a fg notification
 
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
-        assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
 
         // remove it, make sure we're out of compliance again
-        assertTrue(fsc.removeNotification(sbn_user1_app1)); // was fg, should return true
-        assertFalse(fsc.removeNotification(sbn_user1_app1));
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
-        assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
+        entryRemoved(sbn_user1_app1); // was fg, should return true
+        entryRemoved(sbn_user1_app1);
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
 
         // importance upgrade
-        fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
-        assertTrue(fsc.isDungeonNeededForUser(USERID_ONE));
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+        entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+        assertTrue(mFsc.isDisclosureNeededForUser(USERID_ONE));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
         sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
-        fsc.updateNotification(sbn_user1_app1_fg,
+        entryUpdated(sbn_user1_app1_fg,
                 NotificationManager.IMPORTANCE_DEFAULT); // this is now a fg notification
 
         // finally, let's turn off the service
-        fsc.addNotification(makeMockDungeon(USERID_ONE, null),
+        entryAdded(makeMockDisclosure(USERID_ONE, null),
                 NotificationManager.IMPORTANCE_DEFAULT);
 
-        assertFalse(fsc.isDungeonNeededForUser(USERID_ONE));
-        assertFalse(fsc.isDungeonNeededForUser(USERID_TWO));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_ONE));
+        assertFalse(mFsc.isDisclosureNeededForUser(USERID_TWO));
     }
 
     @Test
@@ -375,8 +276,8 @@
         StatusBarNotification sbn_user1_overlay = makeMockSBN(USERID_ONE, "android",
                 0, "AlertWindowNotification", Notification.FLAG_NO_CLEAR);
 
-        assertTrue(fsc.isSystemAlertNotification(sbn_user1_overlay));
-        assertFalse(fsc.isSystemAlertNotification(sbn_user1_app1));
+        assertTrue(mFsc.isSystemAlertNotification(sbn_user1_overlay));
+        assertFalse(mFsc.isSystemAlertNotification(sbn_user1_app1));
     }
 
     @Test
@@ -386,54 +287,54 @@
         StatusBarNotification sbn_user1_app1 = makeMockFgSBN(USERID_ONE, PKG1, 0, true);
         sbn_user1_app1.getNotification().flags = 0;
         StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1, 1, true);
-        fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN); // not fg
-        assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
-        fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
-        assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // app1 has got it covered
-        assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "otherpkg"));
+        entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN); // not fg
+        assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+        entryAdded(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+        assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // app1 has got it covered
+        assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "otherpkg"));
         // let's take out the non-fg notification and see what happens.
-        fsc.removeNotification(sbn_user1_app1);
+        entryRemoved(sbn_user1_app1);
         // still covered by sbn_user1_app1_fg
-        assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
-        assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anyPkg"));
+        assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+        assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "anyPkg"));
 
         // let's attempt to downgrade the notification from FLAG_FOREGROUND and see what we get
         StatusBarNotification sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1, 1, true);
         sbn_user1_app1_fg_sneaky.getNotification().flags = 0;
-        fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
-        assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
-        assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
+        entryUpdated(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
+        assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+        assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
         // ok, ok, we'll put it back
         sbn_user1_app1_fg_sneaky.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
-        fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
-        assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
-        assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "whatever"));
+        entryUpdated(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN);
+        assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+        assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "whatever"));
 
-        assertTrue(fsc.removeNotification(sbn_user1_app1_fg_sneaky));
-        assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
-        assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "a"));
+        entryRemoved(sbn_user1_app1_fg_sneaky);
+        assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+        assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "a"));
 
         // let's try a custom layout
         sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1, 1, false);
-        fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
-        assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
-        assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
+        entryUpdated(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN);
+        assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required!
+        assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "anything"));
         // now let's test an upgrade (non fg to fg)
-        fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
-        assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
-        assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "b"));
+        entryAdded(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN);
+        assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+        assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, "b"));
         sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
-        fsc.updateNotification(sbn_user1_app1,
+        entryUpdated(sbn_user1_app1,
                 NotificationManager.IMPORTANCE_MIN); // this is now a fg notification
 
-        assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
-        assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+        assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
+        assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
 
         // remove it, make sure we're out of compliance again
-        assertTrue(fsc.removeNotification(sbn_user1_app1)); // was fg, should return true
-        assertFalse(fsc.removeNotification(sbn_user1_app1));
-        assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
-        assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
+        entryRemoved(sbn_user1_app1); // was fg, should return true
+        entryRemoved(sbn_user1_app1);
+        assertFalse(mFsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1));
+        assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
     }
 
     private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag,
@@ -475,7 +376,7 @@
         return makeMockSBN(userid, pkg, 1000, "foo", Notification.FLAG_FOREGROUND_SERVICE);
     }
 
-    private StatusBarNotification makeMockDungeon(int userid, String[] pkgs) {
+    private StatusBarNotification makeMockDisclosure(int userid, String[] pkgs) {
         final Notification n = mock(Notification.class);
         n.flags = Notification.FLAG_ONGOING_EVENT;
         final Bundle extras = new Bundle();
@@ -488,4 +389,21 @@
         sbn.getNotification().extras = extras;
         return sbn;
     }
+
+    private void entryRemoved(StatusBarNotification notification) {
+        mEntryListener.onEntryRemoved(new NotificationEntry(notification),
+                null, false);
+    }
+
+    private void entryAdded(StatusBarNotification notification, int importance) {
+        NotificationEntry entry = new NotificationEntry(notification);
+        entry.importance = importance;
+        mEntryListener.onPendingEntryAdded(entry);
+    }
+
+    private void entryUpdated(StatusBarNotification notification, int importance) {
+        NotificationEntry entry = new NotificationEntry(notification);
+        entry.importance = importance;
+        mEntryListener.onPostEntryUpdated(entry);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
index 521d5d1..fc57909 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java
@@ -16,17 +16,12 @@
 
 package com.android.systemui;
 
-
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.graphics.Bitmap;
@@ -58,20 +53,22 @@
     @Mock private SurfaceHolder mSurfaceHolder;
     @Mock private DisplayInfo mDisplayInfo;
 
-    CountDownLatch mEventCountdown;
+    private CountDownLatch mEventCountdown;
+    private CountDownLatch mAmbientEventCountdown;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
         mEventCountdown = new CountDownLatch(1);
+        mAmbientEventCountdown = new CountDownLatch(2);
 
         mImageWallpaper = new ImageWallpaper() {
             @Override
             public Engine onCreateEngine() {
                 return new DrawableEngine() {
                     @Override
-                    DisplayInfo getDefaultDisplayInfo() {
+                    DisplayInfo getDisplayInfo() {
                         return mDisplayInfo;
                     }
 
@@ -86,6 +83,11 @@
                         assertTrue("mFixedSizeAllowed should be true", allowed);
                         mEventCountdown.countDown();
                     }
+
+                    @Override
+                    public void onAmbientModeChanged(boolean inAmbientMode, long duration) {
+                        mAmbientEventCountdown.countDown();
+                    }
                 };
             }
         };
@@ -132,4 +134,23 @@
         verify(mSurfaceHolder, times(1)).setFixedSize(ImageWallpaper.DrawableEngine.MIN_BACKGROUND_WIDTH, ImageWallpaper.DrawableEngine.MIN_BACKGROUND_HEIGHT);
     }
 
+    @Test
+    public void testDeliversAmbientModeChanged() {
+        ImageWallpaper.DrawableEngine wallpaperEngine =
+                (ImageWallpaper.DrawableEngine) mImageWallpaper.onCreateEngine();
+
+        assertEquals("setFixedSizeAllowed should have been called.",
+                0, mEventCountdown.getCount());
+
+        wallpaperEngine.setCreated(true);
+        wallpaperEngine.doAmbientModeChanged(false, 1000);
+        assertFalse("ambient mode should be false", wallpaperEngine.isInAmbientMode());
+        assertEquals("onAmbientModeChanged should have been called.",
+                1, mAmbientEventCountdown.getCount());
+
+        wallpaperEngine.doAmbientModeChanged(true, 1000);
+        assertTrue("ambient mode should be true", wallpaperEngine.isInAmbientMode());
+        assertEquals("onAmbientModeChanged should have been called.",
+                0, mAmbientEventCountdown.getCount());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 122b094..e91a7e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -134,9 +134,12 @@
     public void testNoRounding_NoCutout() {
         mContext.getOrCreateTestableResources().addOverride(
                 com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 0);
-        mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius_top, 0);
-        mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius_bottom, 0);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius, 0);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius_top, 0);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 0);
 
@@ -153,7 +156,8 @@
     public void testRounding() {
         mContext.getOrCreateTestableResources().addOverride(
                 com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 20);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius, 20);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 20);
 
@@ -173,7 +177,8 @@
     public void testCutout() {
         mContext.getOrCreateTestableResources().addOverride(
                 com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
-        mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 0);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius, 0);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 0);
 
@@ -186,7 +191,8 @@
     public void testDelayedCutout() {
         mContext.getOrCreateTestableResources().addOverride(
                 com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 0);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius, 0);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 0);
 
@@ -234,12 +240,14 @@
     public void testUpdateRoundedCorners() {
         mContext.getOrCreateTestableResources().addOverride(
                 com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
-        mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 20);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius, 20);
 
         mScreenDecorations.start();
         assertEquals(mScreenDecorations.mRoundedDefault, 20);
 
-        mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 5);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.dimen.rounded_corner_radius, 5);
         mScreenDecorations.onConfigurationChanged(null);
         assertEquals(mScreenDecorations.mRoundedDefault, 5);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 8f2b2d0..60a20cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -16,8 +16,12 @@
 
 package com.android.systemui.bubbles;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.app.IActivityManager;
 import android.content.Context;
@@ -29,6 +33,9 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
@@ -36,6 +43,8 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -45,6 +54,8 @@
 public class BubbleControllerTest extends SysuiTestCase {
 
     @Mock
+    private NotificationEntryManager mNotificationEntryManager;
+    @Mock
     private WindowManager mWindowManager;
     @Mock
     private IActivityManager mActivityManager;
@@ -52,17 +63,24 @@
     private DozeParameters mDozeParameters;
     @Mock
     private FrameLayout mStatusBarView;
+    @Captor
+    private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
 
     private TestableBubbleController mBubbleController;
     private StatusBarWindowController mStatusBarWindowController;
+    private NotificationEntryListener mEntryListener;
 
     private NotificationTestHelper mNotificationTestHelper;
     private ExpandableNotificationRow mRow;
     private ExpandableNotificationRow mRow2;
 
+    @Mock
+    private NotificationData mNotificationData;
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
 
         // Bubbles get added to status bar window view
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
@@ -74,72 +92,97 @@
         mRow = mNotificationTestHelper.createBubble();
         mRow2 = mNotificationTestHelper.createBubble();
 
-        mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController);
-    }
+        // Return non-null notification data from the NEM
+        when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData);
+        when(mNotificationData.getChannel(mRow.getEntry().key)).thenReturn(mRow.getEntry().channel);
 
-    @Test
-    public void testIsBubble() {
-        assertTrue(mRow.getEntry().isBubble());
+        mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController);
+
+        // Get a reference to the BubbleController's entry listener
+        verify(mNotificationEntryManager, atLeastOnce())
+                .addNotificationEntryListener(mEntryListenerCaptor.capture());
+        mEntryListener = mEntryListenerCaptor.getValue();
     }
 
     @Test
     public void testAddBubble() {
-        mBubbleController.addBubble(mRow.getEntry());
+        mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
         assertTrue(mBubbleController.hasBubbles());
     }
 
     @Test
     public void testHasBubbles() {
         assertFalse(mBubbleController.hasBubbles());
-        mBubbleController.addBubble(mRow.getEntry());
+        mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
         assertTrue(mBubbleController.hasBubbles());
     }
 
     @Test
     public void testRemoveBubble() {
-        mBubbleController.addBubble(mRow.getEntry());
+        mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
         assertTrue(mBubbleController.hasBubbles());
 
         mBubbleController.removeBubble(mRow.getEntry().key);
         assertFalse(mStatusBarWindowController.getBubblesShowing());
+        assertTrue(mRow.getEntry().isBubbleDismissed());
+        verify(mNotificationEntryManager).updateNotifications();
     }
 
     @Test
     public void testDismissStack() {
-        mBubbleController.addBubble(mRow.getEntry());
-        mBubbleController.addBubble(mRow2.getEntry());
+        mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
+        mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */);
         assertTrue(mBubbleController.hasBubbles());
 
         mBubbleController.dismissStack();
         assertFalse(mStatusBarWindowController.getBubblesShowing());
+        verify(mNotificationEntryManager).updateNotifications();
     }
 
     @Test
     public void testIsStackExpanded() {
         assertFalse(mBubbleController.isStackExpanded());
-        mBubbleController.addBubble(mRow.getEntry());
+        mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
 
         BubbleStackView stackView = mBubbleController.getStackView();
-        stackView.animateExpansion(true /* expanded */);
+        stackView.expandStack();
         assertTrue(mBubbleController.isStackExpanded());
 
-        stackView.animateExpansion(false /* expanded */);
+        stackView.collapseStack();
         assertFalse(mBubbleController.isStackExpanded());
     }
 
     @Test
     public void testCollapseStack() {
-        mBubbleController.addBubble(mRow.getEntry());
-        mBubbleController.addBubble(mRow2.getEntry());
+        mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */);
+        mBubbleController.updateBubble(mRow2.getEntry(), true /* updatePosition */);
 
         BubbleStackView stackView = mBubbleController.getStackView();
-        stackView.animateExpansion(true /* expanded */);
+        stackView.expandStack();
         assertTrue(mBubbleController.isStackExpanded());
 
+        stackView.setExpandedBubble(mRow.getEntry());
+        assertEquals(stackView.getExpandedBubble().getEntry(), mRow.getEntry());
+
+        stackView.setExpandedBubble(mRow2.getEntry());
+        assertEquals(stackView.getExpandedBubble().getEntry(), mRow2.getEntry());
+
         mBubbleController.collapseStack();
         assertFalse(mBubbleController.isStackExpanded());
     }
 
+    @Test
+    public void testMarkNewNotificationAsBubble() {
+        mEntryListener.onPendingEntryAdded(mRow.getEntry());
+        assertTrue(mRow.getEntry().isBubble());
+    }
+
+    @Test
+    public void testMarkNewNotificationAsShowInShade() {
+        mEntryListener.onPendingEntryAdded(mRow.getEntry());
+        assertTrue(mRow.getEntry().showInShadeWhenBubble());
+    }
+
     static class TestableBubbleController extends BubbleController {
 
         TestableBubbleController(Context context,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java b/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
index b368876..839b5e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
@@ -32,6 +32,11 @@
         this.mCallback = null;
     }
 
+    @Override
+    public boolean isDocked() {
+        return false;
+    }
+
     public void setDockEvent(int event) {
         mCallback.onEvent(event);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index f45500a..e4558df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -36,6 +36,8 @@
         when(params.getPickupVibrationThreshold()).thenReturn(0);
         when(params.getProxCheckBeforePulse()).thenReturn(true);
         when(params.getPickupSubtypePerformsProxCheck(anyInt())).thenReturn(true);
+        when(params.getPolicy()).thenReturn(mock(AlwaysOnDisplayPolicy.class));
+        when(params.doubleTapReportsTouchCoordinates()).thenReturn(false);
 
         doneHolder[0] = true;
         return params;
@@ -48,9 +50,14 @@
         when(config.doubleTapGestureEnabled(anyInt())).thenReturn(false);
         when(config.pickupGestureEnabled(anyInt())).thenReturn(false);
         when(config.pulseOnNotificationEnabled(anyInt())).thenReturn(true);
+        when(config.alwaysOnEnabled(anyInt())).thenReturn(false);
 
         when(config.doubleTapSensorType()).thenReturn(null);
+        when(config.tapSensorType()).thenReturn(null);
+        when(config.longPressSensorType()).thenReturn(null);
+
         when(config.dozePickupSensorAvailable()).thenReturn(false);
+        when(config.wakeScreenGestureAvailable()).thenReturn(false);
 
         doneHolder[0] = true;
         return config;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
index 926ff69..0fc0953 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
@@ -75,7 +75,7 @@
         mContext.putComponent(DockManager.class, mDockManagerFake);
 
         mDockHandler = new DozeDockHandler(mContext, mMachine, mHost, mConfig,
-                Handler.createAsync(Looper.myLooper()));
+                Handler.createAsync(Looper.myLooper()), mDockManagerFake);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
index ce28b50..dc42872 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
@@ -104,7 +104,7 @@
     }
 
     @Override
-    public void onDoubleTap(float x, float y) {
+    public void onSlpiTap(float x, float y) {
         doubleTapX = y;
         doubleTapY = y;
     }
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 31fc625..7b358b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -18,8 +18,10 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
 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.when;
 
@@ -34,6 +36,8 @@
 
 import com.android.internal.hardware.AmbientDisplayConfiguration;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dock.DockManager;
+import com.android.systemui.dock.DockManagerFake;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.wakelock.WakeLock;
 import com.android.systemui.util.wakelock.WakeLockFake;
@@ -59,6 +63,7 @@
     private WakeLock mWakeLock;
     private Instrumentation mInstrumentation;
     private AlarmManager mAlarmManager;
+    private DockManagerFake mDockManagerFake;
 
     @BeforeClass
     public static void setupSuite() {
@@ -76,9 +81,12 @@
         mParameters = DozeConfigurationUtil.createMockParameters();
         mSensors = new FakeSensorManager(mContext);
         mWakeLock = new WakeLockFake();
+        mDockManagerFake = spy(new DockManagerFake());
+        mContext.putComponent(DockManager.class, mDockManagerFake);
 
         mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, mConfig, mParameters,
-                mSensors, Handler.createAsync(Looper.myLooper()), mWakeLock, true);
+                mSensors, Handler.createAsync(Looper.myLooper()), mWakeLock, true,
+                mDockManagerFake);
     }
 
     @Test
@@ -102,4 +110,38 @@
         verify(mMachine).requestPulse(anyInt());
     }
 
+    @Test
+    public void testDockEventListener_registerAndUnregister() {
+        mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+
+        verify(mDockManagerFake).addListener(any());
+
+        mTriggers.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.FINISH);
+
+        verify(mDockManagerFake).removeListener(any());
+    }
+
+    @Test
+    public void testOnSensor_whenUndockedWithNearAndDoubleTapScreen_shouldNotWakeUp() {
+        mSensors.getMockProximitySensor().sendProximityResult(false /* far */);
+
+        mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP,
+                false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
+                null /* rawValues */);
+
+        verify(mMachine, never()).wakeUp();
+    }
+
+    @Test
+    public void testOnSensor_whenDockedWithNearAndDoubleTapScreen_shouldWakeUp() {
+        doReturn(true).when(mDockManagerFake).isDocked();
+        mSensors.getMockProximitySensor().sendProximityResult(false /* far */);
+
+        mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP,
+                false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
+                null /* rawValues */);
+
+        verify(mMachine).wakeUp();
+    }
+
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index a8ff0b2..cfc19ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
@@ -44,6 +45,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.StatusBarStateController;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -67,6 +69,8 @@
     private AlarmManager mAlarmManager;
     @Mock
     private NotificationMediaManager mNotificationMediaManager;
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
     private TestableKeyguardSliceProvider mProvider;
     private boolean mIsZenMode;
 
@@ -76,7 +80,7 @@
         mIsZenMode = false;
         mProvider = new TestableKeyguardSliceProvider();
         mProvider.attachInfo(getContext(), null);
-        mProvider.initDependencies();
+        mProvider.initDependencies(mNotificationMediaManager, mStatusBarStateController);
         SliceProvider.setSpecs(new HashSet<>(Arrays.asList(SliceSpecs.LIST)));
     }
 
@@ -98,6 +102,7 @@
     @Test
     public void onBindSlice_readsMedia() {
         MediaMetadata metadata = mock(MediaMetadata.class);
+        mProvider.onDozingChanged(true);
         mProvider.onMetadataChanged(metadata);
         mProvider.onBindSlice(mProvider.getUri());
         verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_TITLE));
@@ -162,7 +167,31 @@
     @Test
     public void onMetadataChanged_updatesSlice() {
         mProvider.onMetadataChanged(mock(MediaMetadata.class));
+        mProvider.onDozingChanged(true);
         verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
+
+        // Hides after waking up
+        reset(mContentResolver);
+        mProvider.onDozingChanged(false);
+        verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
+
+        // And won't update slice if device is awake
+        reset(mContentResolver);
+        mProvider.onMetadataChanged(mock(MediaMetadata.class));
+        verify(mContentResolver, never()).notifyChange(eq(mProvider.getUri()), eq(null));
+    }
+
+    @Test
+    public void onDozingChanged_updatesSliceIfMedia() {
+        // Show media when dozing
+        mProvider.onMetadataChanged(mock(MediaMetadata.class));
+        mProvider.onDozingChanged(true);
+        verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
+
+        // Do not notify again if nothing changed
+        reset(mContentResolver);
+        mProvider.onDozingChanged(true);
+        verify(mContentResolver, never()).notifyChange(eq(mProvider.getUri()), eq(null));
     }
 
     private class TestableKeyguardSliceProvider extends KeyguardSliceProvider {
@@ -201,11 +230,6 @@
         protected String getFormattedDateLocked() {
             return super.getFormattedDateLocked() + mCounter++;
         }
-
-        @Override
-        public void initDependencies() {
-            mMediaManager = mNotificationMediaManager;
-        }
     }
 
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 2cb326e..823485f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -39,6 +39,7 @@
 import com.android.systemui.SysuiBaseFragmentTest;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
 import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.Clock;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -92,7 +93,8 @@
         processAllMessages();
         QSTileHost host = new QSTileHost(mContext, mock(StatusBarIconController.class),
                 mock(QSFactoryImpl.class), new Handler(), Looper.myLooper(),
-                mock(PluginManager.class), mock(TunerService.class));
+                mock(PluginManager.class), mock(TunerService.class),
+                () -> mock(AutoTileManager.class));
         qs.setHost(host);
 
         qs.setListening(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 63f4bbc..03278b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -33,6 +33,7 @@
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
 import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.tuner.TunerService;
@@ -65,7 +66,8 @@
                 new Handler(),
                 Looper.myLooper(),
                 mock(PluginManager.class),
-                mock(TunerService.class));
+                mock(TunerService.class),
+                () -> mock(AutoTileManager.class));
         mTileService = new TestTileServices(host, Looper.getMainLooper());
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
index 4583770..3415c72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
@@ -91,7 +91,7 @@
         mMockPm = mock(PackageManager.class);
         mMockListener = mock(PluginListener.class);
         mMockManager = mock(PluginManagerImpl.class);
-        when(mMockManager.getClassLoader(any(), any())).thenReturn(getClass().getClassLoader());
+        when(mMockManager.getClassLoader(any())).thenReturn(getClass().getClassLoader());
         mMockEnabler = mock(PluginEnabler.class);
         when(mMockManager.getPluginEnabler()).thenReturn(mMockEnabler);
         mMockVersionInfo = mock(VersionInfo.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
index 76e68f1..536c043 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
@@ -25,6 +25,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -135,9 +136,13 @@
         });
         resetExceptionHandler();
 
+        String sourceDir = "myPlugin";
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.sourceDir = sourceDir;
+        applicationInfo.packageName = WHITELISTED_PACKAGE;
         mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
-        assertNull(mPluginManager.getOneShotPlugin("myPlugin", TestPlugin.class));
-        assertNull(mPluginManager.getClassLoader("myPlugin", WHITELISTED_PACKAGE));
+        assertNull(mPluginManager.getOneShotPlugin(sourceDir, TestPlugin.class));
+        assertNull(mPluginManager.getClassLoader(applicationInfo));
     }
 
     @Test
@@ -152,9 +157,16 @@
         });
         resetExceptionHandler();
 
+        String sourceDir = "myPlugin";
+        ApplicationInfo whiteListedApplicationInfo = new ApplicationInfo();
+        whiteListedApplicationInfo.sourceDir = sourceDir;
+        whiteListedApplicationInfo.packageName = WHITELISTED_PACKAGE;
+        ApplicationInfo invalidApplicationInfo = new ApplicationInfo();
+        invalidApplicationInfo.sourceDir = sourceDir;
+        invalidApplicationInfo.packageName = "com.android.invalidpackage";
         mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
-        assertNotNull(mPluginManager.getClassLoader("myPlugin", WHITELISTED_PACKAGE));
-        assertNull(mPluginManager.getClassLoader("myPlugin", "com.android.invalidpackage"));
+        assertNotNull(mPluginManager.getClassLoader(whiteListedApplicationInfo));
+        assertNull(mPluginManager.getClassLoader(invalidApplicationInfo));
     }
 
     @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 9d0556f..f8957b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -36,7 +36,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
 
@@ -67,7 +67,7 @@
 
     private AlertingNotificationManager mAlertingNotificationManager;
 
-    protected NotificationData.Entry mEntry;
+    protected NotificationEntry mEntry;
     protected Handler mTestHandler;
     private StatusBarNotification mSbn;
     protected boolean mTimedOut = false;
@@ -119,7 +119,7 @@
     public void setUp() {
         mTestHandler = Handler.createAsync(Looper.myLooper());
         mSbn = createNewNotification(0 /* id */);
-        mEntry = new NotificationData.Entry(mSbn);
+        mEntry = new NotificationEntry(mSbn);
         mEntry.setRow(mRow);
 
         mAlertingNotificationManager = createAlertingNotificationManager();
@@ -170,7 +170,7 @@
     public void testReleaseAllImmediately() {
         for (int i = 0; i < TEST_NUM_NOTIFICATIONS; i++) {
             StatusBarNotification sbn = createNewNotification(i);
-            NotificationData.Entry entry = new NotificationData.Entry(sbn);
+            NotificationEntry entry = new NotificationEntry(sbn);
             entry.setRow(mRow);
             mAlertingNotificationManager.showNotification(entry);
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index a04e57b..51d94f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -16,6 +16,7 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -42,10 +43,10 @@
 
     @Before
     public void setup() {
-        mCommandQueue = new CommandQueue();
+        mCommandQueue = new CommandQueue(mContext);
         mCallbacks = mock(Callbacks.class);
         mCommandQueue.addCallback(mCallbacks);
-        verify(mCallbacks).disable(eq(0), eq(0), eq(false));
+        verify(mCallbacks).disable(anyInt(), eq(0), eq(0), eq(false));
     }
 
     @After
@@ -73,7 +74,7 @@
         int state2 = 42;
         mCommandQueue.disable(DEFAULT_DISPLAY, state1, state2);
         waitForIdleSync();
-        verify(mCallbacks).disable(eq(state1), eq(state2), eq(true));
+        verify(mCallbacks).disable(eq(DEFAULT_DISPLAY), eq(state1), eq(state2), eq(true));
     }
 
     @Test
@@ -104,7 +105,8 @@
         Rect r = new Rect();
         mCommandQueue.setSystemUiVisibility(DEFAULT_DISPLAY, 1, 2, 3, 4, null, r);
         waitForIdleSync();
-        verify(mCallbacks).setSystemUiVisibility(eq(1), eq(2), eq(3), eq(4), eq(null), eq(r));
+        verify(mCallbacks).setSystemUiVisibility(eq(DEFAULT_DISPLAY), eq(1), eq(2), eq(3), eq(4),
+                eq(null), eq(r));
     }
 
     // TODO(b/117478341): add test case for multi-display
@@ -112,7 +114,7 @@
     public void testTopAppWindowChanged() {
         mCommandQueue.topAppWindowChanged(DEFAULT_DISPLAY, true);
         waitForIdleSync();
-        verify(mCallbacks).topAppWindowChanged(eq(true));
+        verify(mCallbacks).topAppWindowChanged(eq(DEFAULT_DISPLAY), eq(true));
     }
 
     // TODO(b/117478341): add test case for multi-display
@@ -120,7 +122,8 @@
     public void testShowImeButton() {
         mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true);
         waitForIdleSync();
-        verify(mCallbacks).setImeWindowStatus(eq(null), eq(1), eq(2), eq(true));
+        verify(mCallbacks).setImeWindowStatus(
+                eq(DEFAULT_DISPLAY), eq(null), eq(1), eq(2), eq(true));
     }
 
     @Test
@@ -177,7 +180,7 @@
     public void testSetWindowState() {
         mCommandQueue.setWindowState(DEFAULT_DISPLAY, 1, 2);
         waitForIdleSync();
-        verify(mCallbacks).setWindowState(eq(1), eq(2));
+        verify(mCallbacks).setWindowState(eq(DEFAULT_DISPLAY), eq(1), eq(2));
     }
 
     @Test
@@ -192,7 +195,7 @@
     public void testAppTransitionPending() {
         mCommandQueue.appTransitionPending(DEFAULT_DISPLAY);
         waitForIdleSync();
-        verify(mCallbacks).appTransitionPending(eq(false));
+        verify(mCallbacks).appTransitionPending(eq(DEFAULT_DISPLAY), eq(false));
     }
 
     // TODO(b/117478341): add test case for multi-display
@@ -200,7 +203,7 @@
     public void testAppTransitionCancelled() {
         mCommandQueue.appTransitionCancelled(DEFAULT_DISPLAY);
         waitForIdleSync();
-        verify(mCallbacks).appTransitionCancelled();
+        verify(mCallbacks).appTransitionCancelled(eq(DEFAULT_DISPLAY));
     }
 
     // TODO(b/117478341): add test case for multi-display
@@ -208,7 +211,8 @@
     public void testAppTransitionStarting() {
         mCommandQueue.appTransitionStarting(DEFAULT_DISPLAY, 1, 2);
         waitForIdleSync();
-        verify(mCallbacks).appTransitionStarting(eq(1L), eq(2L), eq(false));
+        verify(mCallbacks).appTransitionStarting(
+                eq(DEFAULT_DISPLAY), eq(1L), eq(2L), eq(false));
     }
 
     // TODO(b/117478341): add test case for multi-display
@@ -216,7 +220,7 @@
     public void testAppTransitionFinished() {
         mCommandQueue.appTransitionFinished(DEFAULT_DISPLAY);
         waitForIdleSync();
-        verify(mCallbacks).appTransitionFinished();
+        verify(mCallbacks).appTransitionFinished(eq(DEFAULT_DISPLAY));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index 65c04fe..c880172 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -31,8 +31,9 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -85,7 +86,7 @@
 
     @Test
     public void testNotificationUpdateCallsUpdateNotification() {
-        when(mNotificationData.get(mSbn.getKey())).thenReturn(new NotificationData.Entry(mSbn));
+        when(mNotificationData.get(mSbn.getKey())).thenReturn(new NotificationEntry(mSbn));
         mListener.onNotificationPosted(mSbn, mRanking);
         TestableLooper.get(this).processAllMessages();
         verify(mEntryManager).updateNotification(mSbn, mRanking);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index f168a49..d7ca5b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar;
 
-import static android.content.Intent.ACTION_DEVICE_LOCKED_CHANGED;
 import static android.content.Intent.ACTION_USER_SWITCHED;
 
 import static junit.framework.Assert.assertFalse;
@@ -42,8 +41,8 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 150dcb9..c159516 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -24,8 +24,8 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputActiveExtender;
 import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputHistoryExtender;
 import com.android.systemui.statusbar.NotificationRemoteInputManager.SmartReplyHistoryExtender;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.ShadeController;
 
@@ -60,7 +60,7 @@
 
     private TestableNotificationRemoteInputManager mRemoteInputManager;
     private StatusBarNotification mSbn;
-    private NotificationData.Entry mEntry;
+    private NotificationEntry mEntry;
     private RemoteInputHistoryExtender mRemoteInputHistoryExtender;
     private SmartReplyHistoryExtender mSmartReplyHistoryExtender;
     private RemoteInputActiveExtender mRemoteInputActiveExtender;
@@ -75,7 +75,7 @@
                 Handler.createAsync(Looper.myLooper()));
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
                 0, new Notification(), UserHandle.CURRENT, null, 0);
-        mEntry = new NotificationData.Entry(mSbn);
+        mEntry = new NotificationEntry(mSbn);
         mEntry.setRow(mRow);
 
         mRemoteInputManager.setUpWithPresenterForTest(mCallback,
@@ -170,7 +170,7 @@
         // Setup a notification entry with 1 remote input.
         StatusBarNotification newSbn =
                 mRemoteInputManager.rebuildNotificationWithRemoteInput(mEntry, "A Reply", false);
-        NotificationData.Entry entry = new NotificationData.Entry(newSbn);
+        NotificationEntry entry = new NotificationEntry(newSbn);
 
         // Try rebuilding to add another reply.
         newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInput(entry, "Reply 2", true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index fb5e875..0b24c21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -17,13 +17,17 @@
 package com.android.systemui.statusbar;
 
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.Instrumentation;
 import android.app.Notification;
 import android.app.NotificationChannel;
+import android.app.PendingIntent;
 import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.support.test.InstrumentationRegistry;
@@ -32,7 +36,7 @@
 import android.widget.RemoteViews;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.row.NotificationInflaterTest;
@@ -50,6 +54,8 @@
     public static final String PKG = "com.android.systemui";
     /** System UI id for testing purposes. */
     public static final int UID = 1000;
+    /** Current {@link UserHandle} of the system. */
+    public static final UserHandle USER_HANDLE = UserHandle.of(ActivityManager.getCurrentUser());
 
     private static final String GROUP_KEY = "gruKey";
 
@@ -74,7 +80,7 @@
      * @throws Exception
      */
     public ExpandableNotificationRow createRow() throws Exception {
-        return createRow(PKG, UID);
+        return createRow(PKG, UID, USER_HANDLE);
     }
 
     /**
@@ -85,9 +91,9 @@
      * @return a row with a notification using the package and user id
      * @throws Exception
      */
-    public ExpandableNotificationRow createRow(String pkg, int uid) throws Exception {
-        return createRow(pkg, uid, false /* isGroupSummary */, null /* groupKey */,
-                false /* isBubble */);
+    public ExpandableNotificationRow createRow(String pkg, int uid, UserHandle userHandle)
+            throws Exception {
+        return createRow(pkg, uid, userHandle, false /* isGroupSummary */, null /* groupKey */);
     }
 
     /**
@@ -98,8 +104,7 @@
      * @throws Exception
      */
     public ExpandableNotificationRow createRow(Notification notification) throws Exception {
-        return generateRow(notification, PKG, UID, 0 /* extraInflationFlags */,
-                false /* isBubble */);
+        return generateRow(notification, PKG, UID, USER_HANDLE, 0 /* extraInflationFlags */);
     }
 
     /**
@@ -112,8 +117,7 @@
      */
     public ExpandableNotificationRow createRow(@InflationFlag int extraInflationFlags)
             throws Exception {
-        return generateRow(createNotification(), PKG, UID, extraInflationFlags,
-                false /* isBubble */);
+        return generateRow(createNotification(), PKG, UID, USER_HANDLE, extraInflationFlags);
     }
 
     /**
@@ -134,20 +138,21 @@
         return createGroup(2);
     }
 
-    /**
-     * Retursn an {@link ExpandableNotificationRow} that should be a bubble.
-     */
-    public ExpandableNotificationRow createBubble() throws Exception {
-        return createRow(PKG, UID, false /* isGroupSummary */, null /* groupKey */,
-                true /* isBubble */);
-    }
-
     private ExpandableNotificationRow createGroupSummary(String groupkey) throws Exception {
-        return createRow(PKG, UID, true /* isGroupSummary */, groupkey, false);
+        return createRow(PKG, UID, USER_HANDLE, true /* isGroupSummary */, groupkey);
     }
 
     private ExpandableNotificationRow createGroupChild(String groupkey) throws Exception {
-        return createRow(PKG, UID, false /* isGroupSummary */, groupkey, false);
+        return createRow(PKG, UID, USER_HANDLE, false /* isGroupSummary */, groupkey);
+    }
+
+    /**
+     * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
+     */
+    public ExpandableNotificationRow createBubble() throws Exception {
+        Notification n = createNotification(false /* isGroupSummary */,
+                null /* groupKey */, true /* isBubble */);
+        return generateRow(n, PKG, UID, USER_HANDLE, 0 /* extraInflationFlags */, IMPORTANCE_HIGH);
     }
 
     /**
@@ -157,7 +162,6 @@
      * @param uid uid used for creating a {@link StatusBarNotification}
      * @param isGroupSummary whether the notification row is a group summary
      * @param groupKey the group key for the notification group used across notifications
-     * @param isBubble
      * @return a row with that's either a standalone notification or a group notification if the
      *         groupKey is non-null
      * @throws Exception
@@ -165,11 +169,12 @@
     private ExpandableNotificationRow createRow(
             String pkg,
             int uid,
+            UserHandle userHandle,
             boolean isGroupSummary,
-            @Nullable String groupKey, boolean isBubble)
+            @Nullable String groupKey)
             throws Exception {
         Notification notif = createNotification(isGroupSummary, groupKey);
-        return generateRow(notif, pkg, uid, 0 /* inflationFlags */, isBubble);
+        return generateRow(notif, pkg, uid, userHandle, 0 /* inflationFlags */);
     }
 
     /**
@@ -188,8 +193,20 @@
      * @param groupKey the group key for the notification group used across notifications
      * @return a notification that is in the group specified or standalone if unspecified
      */
+    private Notification createNotification(boolean isGroupSummary, @Nullable String groupKey) {
+        return createNotification(isGroupSummary, groupKey, false /* isBubble */);
+    }
+
+    /**
+     * Creates a notification with the given parameters.
+     *
+     * @param isGroupSummary whether the notification is a group summary
+     * @param groupKey the group key for the notification group used across notifications
+     * @param isBubble whether this notification should bubble
+     * @return a notification that is in the group specified or standalone if unspecified
+     */
     private Notification createNotification(boolean isGroupSummary,
-            @Nullable String groupKey) {
+            @Nullable String groupKey, boolean isBubble) {
         Notification publicVersion = new Notification.Builder(mContext).setSmallIcon(
                 R.drawable.ic_person)
                 .setCustomContentView(new RemoteViews(mContext.getPackageName(),
@@ -207,6 +224,9 @@
         if (!TextUtils.isEmpty(groupKey)) {
             notificationBuilder.setGroup(groupKey);
         }
+        if (isBubble) {
+            notificationBuilder.setBubbleMetadata(makeBubbleMetadata());
+        }
         return notificationBuilder.build();
     }
 
@@ -214,7 +234,20 @@
             Notification notification,
             String pkg,
             int uid,
-            @InflationFlag int extraInflationFlags, boolean isBubble)
+            UserHandle userHandle,
+            @InflationFlag int extraInflationFlags)
+            throws Exception {
+        return generateRow(notification, pkg, uid, userHandle, extraInflationFlags,
+                IMPORTANCE_DEFAULT);
+    }
+
+    private ExpandableNotificationRow generateRow(
+            Notification notification,
+            String pkg,
+            int uid,
+            UserHandle userHandle,
+            @InflationFlag int extraInflationFlags,
+            int importance)
             throws Exception {
         LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
                 mContext.LAYOUT_INFLATER_SERVICE);
@@ -226,7 +259,6 @@
         row.setGroupManager(mGroupManager);
         row.setHeadsUpManager(mHeadsUpManager);
         row.setAboveShelfChangedListener(aboveShelf -> {});
-        UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
         StatusBarNotification sbn = new StatusBarNotification(
                 pkg,
                 pkg,
@@ -235,16 +267,15 @@
                 uid,
                 2000 /* initialPid */,
                 notification,
-                mUser,
+                userHandle,
                 null /* overrideGroupKey */,
                 System.currentTimeMillis());
-        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        NotificationEntry entry = new NotificationEntry(sbn);
         entry.setRow(row);
         entry.createIcons(mContext, sbn);
         entry.channel = new NotificationChannel(
-                notification.getChannelId(), notification.getChannelId(), IMPORTANCE_DEFAULT);
+                notification.getChannelId(), notification.getChannelId(), importance);
         entry.channel.setBlockableSystem(true);
-        entry.setIsBubble(isBubble);
         row.setEntry(entry);
         row.getNotificationInflater().addInflationFlags(extraInflationFlags);
         NotificationInflaterTest.runThenWaitForInflation(
@@ -257,4 +288,14 @@
         mGroupManager.onEntryAdded(entry);
         return row;
     }
+
+    private Notification.BubbleMetadata makeBubbleMetadata() {
+        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        return new Notification.BubbleMetadata.Builder()
+                .setIntent(bubbleIntent)
+                .setTitle("bubble title")
+                .setIcon(Icon.createWithResource(mContext, 1))
+                .setDesiredHeight(314)
+                .build();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 8cf4b05..56e1fc6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -36,12 +36,11 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.InitController;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -77,7 +76,7 @@
     @Mock private ShadeController mShadeController;
 
     private NotificationViewHierarchyManager mViewHierarchyManager;
-    private NotificationTestHelper mHelper = new NotificationTestHelper(mContext);
+    private NotificationTestHelper mHelper;
 
     @Before
     public void setUp() {
@@ -90,19 +89,21 @@
         mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
         mDependency.injectTestDependency(ShadeController.class, mShadeController);
 
+        mHelper = new NotificationTestHelper(mContext);
+
         when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
 
         mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,
                 mLockscreenUserManager, mGroupManager, mVisualStabilityManager,
-                mock(StatusBarStateController.class), mEntryManager, mock(BubbleController.class),
+                mock(StatusBarStateController.class), mEntryManager,
                 () -> mShadeController);
         Dependency.get(InitController.class).executePostInitTasks();
         mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
     }
 
-    private NotificationData.Entry createEntry() throws Exception {
+    private NotificationEntry createEntry() throws Exception {
         ExpandableNotificationRow row = mHelper.createRow();
-        NotificationData.Entry entry = new NotificationData.Entry(row.getStatusBarNotification());
+        NotificationEntry entry = new NotificationEntry(row.getStatusBarNotification());
         entry.setRow(row);
         return entry;
     }
@@ -111,9 +112,9 @@
     public void testNotificationsBecomingBundled() throws Exception {
         // Tests 3 top level notifications becoming a single bundled notification with |entry0| as
         // the summary.
-        NotificationData.Entry entry0 = createEntry();
-        NotificationData.Entry entry1 = createEntry();
-        NotificationData.Entry entry2 = createEntry();
+        NotificationEntry entry0 = createEntry();
+        NotificationEntry entry1 = createEntry();
+        NotificationEntry entry2 = createEntry();
 
         // Set up the prior state to look like three top level notifications.
         mListContainer.addContainerView(entry0.getRow());
@@ -140,9 +141,9 @@
     @Test
     public void testNotificationsBecomingUnbundled() throws Exception {
         // Tests a bundled notification becoming three top level notifications.
-        NotificationData.Entry entry0 = createEntry();
-        NotificationData.Entry entry1 = createEntry();
-        NotificationData.Entry entry2 = createEntry();
+        NotificationEntry entry0 = createEntry();
+        NotificationEntry entry1 = createEntry();
+        NotificationEntry entry2 = createEntry();
         entry0.getRow().addChildNotification(entry1.getRow());
         entry0.getRow().addChildNotification(entry2.getRow());
 
@@ -171,8 +172,8 @@
     @Test
     public void testNotificationsBecomingSuppressed() throws Exception {
         // Tests two top level notifications becoming a suppressed summary and a child.
-        NotificationData.Entry entry0 = createEntry();
-        NotificationData.Entry entry1 = createEntry();
+        NotificationEntry entry0 = createEntry();
+        NotificationEntry entry1 = createEntry();
         entry0.getRow().addChildNotification(entry1.getRow());
 
         // Set up the prior state to look like a top level notification.
@@ -197,7 +198,7 @@
 
     @Test
     public void testUpdateNotificationViews_appOps() throws Exception {
-        NotificationData.Entry entry0 = createEntry();
+        NotificationEntry entry0 = createEntry();
         entry0.setRow(spy(entry0.getRow()));
         when(mNotificationData.getActiveNotifications()).thenReturn(
                 Lists.newArrayList(entry0));
@@ -262,10 +263,7 @@
         public void setMaxDisplayedNotifications(int maxNotifications) {}
 
         @Override
-        public void snapViewIfNeeded(Entry entry) {}
-
-        @Override
-        public ViewGroup getViewParentForNotification(NotificationData.Entry entry) {
+        public ViewGroup getViewParentForNotification(NotificationEntry entry) {
             return null;
         }
 
@@ -281,10 +279,10 @@
         }
 
         @Override
-        public void cleanUpViewStateForEntry(Entry entry) { }
+        public void cleanUpViewStateForEntry(NotificationEntry entry) { }
 
         @Override
-        public boolean isInVisibleLocation(Entry entry) {
+        public boolean isInVisibleLocation(NotificationEntry entry) {
             return true;
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index e7a1f05..6cca434 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -36,8 +36,8 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.ShadeController;
 
 import org.junit.Before;
@@ -58,7 +58,7 @@
     private static final int TEST_ACTION_COUNT = 3;
 
     private Notification mNotification;
-    private NotificationData.Entry mEntry;
+    private NotificationEntry mEntry;
     private SmartReplyController mSmartReplyController;
     private NotificationRemoteInputManager mRemoteInputManager;
 
@@ -92,7 +92,7 @@
 
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
                 0, mNotification, new UserHandle(ActivityManager.getCurrentUser()), null, 0);
-        mEntry = new NotificationData.Entry(mSbn);
+        mEntry = new NotificationEntry(mSbn);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
deleted file mode 100644
index 871ff89..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification;
-
-import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER;
-import static android.app.AppOpsManager.OP_CAMERA;
-import static android.app.Notification.CATEGORY_ALARM;
-import static android.app.Notification.CATEGORY_CALL;
-import static android.app.Notification.CATEGORY_EVENT;
-import static android.app.Notification.CATEGORY_MESSAGE;
-import static android.app.Notification.CATEGORY_REMINDER;
-
-import static junit.framework.Assert.assertEquals;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.Manifest;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.PendingIntent;
-import android.app.Person;
-import android.content.Intent;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Icon;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.SnoozeCriterion;
-import android.service.notification.StatusBarNotification;
-import android.support.test.filters.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-import android.util.ArraySet;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.ForegroundServiceController;
-import com.android.systemui.InitController;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.ShadeController;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public class NotificationDataTest extends SysuiTestCase {
-
-    private static final int UID_NORMAL = 123;
-    private static final int UID_ALLOW_DURING_SETUP = 456;
-    private static final String TEST_HIDDEN_NOTIFICATION_KEY = "testHiddenNotificationKey";
-    private static final String TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY = "exempt";
-    private static final NotificationChannel NOTIFICATION_CHANNEL =
-            new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
-
-    private final StatusBarNotification mMockStatusBarNotification =
-            mock(StatusBarNotification.class);
-    @Mock
-    ForegroundServiceController mFsc;
-    @Mock
-    NotificationData.KeyguardEnvironment mEnvironment;
-
-    private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
-    private NotificationData mNotificationData;
-    private ExpandableNotificationRow mRow;
-
-    @Before
-    public void setUp() throws Exception {
-        com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
-        MockitoAnnotations.initMocks(this);
-        when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
-        when(mMockStatusBarNotification.cloneLight()).thenReturn(mMockStatusBarNotification);
-
-        when(mMockPackageManager.checkUidPermission(
-                eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
-                eq(UID_NORMAL)))
-                .thenReturn(PackageManager.PERMISSION_DENIED);
-        when(mMockPackageManager.checkUidPermission(
-                eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
-                eq(UID_ALLOW_DURING_SETUP)))
-                .thenReturn(PackageManager.PERMISSION_GRANTED);
-
-        mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
-        mDependency.injectTestDependency(NotificationGroupManager.class,
-                new NotificationGroupManager());
-        mDependency.injectMockDependency(ShadeController.class);
-        mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
-        when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
-        when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
-        mNotificationData = new TestableNotificationData();
-        mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class));
-        mRow = new NotificationTestHelper(getContext()).createRow();
-        Dependency.get(InitController.class).executePostInitTasks();
-    }
-
-    @Test
-    public void testChannelSetWhenAdded() {
-        mNotificationData.add(mRow.getEntry());
-        assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().channel);
-    }
-
-    @Test
-    public void testAllRelevantNotisTaggedWithAppOps() throws Exception {
-        mNotificationData.add(mRow.getEntry());
-        ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
-        mNotificationData.add(row2.getEntry());
-        ExpandableNotificationRow diffPkg =
-                new NotificationTestHelper(getContext()).createRow("pkg", 4000);
-        mNotificationData.add(diffPkg.getEntry());
-
-        ArraySet<Integer> expectedOps = new ArraySet<>();
-        expectedOps.add(OP_CAMERA);
-        expectedOps.add(OP_ACCEPT_HANDOVER);
-
-        for (int op : expectedOps) {
-            mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
-                    NotificationTestHelper.PKG, mRow.getEntry().key, true);
-            mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
-                    NotificationTestHelper.PKG, row2.getEntry().key, true);
-        }
-        for (int op : expectedOps) {
-            assertTrue(mRow.getEntry().key + " doesn't have op " + op,
-                    mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(op));
-            assertTrue(row2.getEntry().key + " doesn't have op " + op,
-                    mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(op));
-            assertFalse(diffPkg.getEntry().key + " has op " + op,
-                    mNotificationData.get(diffPkg.getEntry().key).mActiveAppOps.contains(op));
-        }
-    }
-
-    @Test
-    public void testAppOpsRemoval() throws Exception {
-        mNotificationData.add(mRow.getEntry());
-        ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
-        mNotificationData.add(row2.getEntry());
-
-        ArraySet<Integer> expectedOps = new ArraySet<>();
-        expectedOps.add(OP_CAMERA);
-        expectedOps.add(OP_ACCEPT_HANDOVER);
-
-        for (int op : expectedOps) {
-            mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
-                    NotificationTestHelper.PKG, row2.getEntry().key, true);
-        }
-
-        expectedOps.remove(OP_ACCEPT_HANDOVER);
-        mNotificationData.updateAppOp(OP_ACCEPT_HANDOVER, NotificationTestHelper.UID,
-                NotificationTestHelper.PKG, row2.getEntry().key, false);
-
-        assertTrue(mRow.getEntry().key + " doesn't have op " + OP_CAMERA,
-                mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
-        assertTrue(row2.getEntry().key + " doesn't have op " + OP_CAMERA,
-                mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
-        assertFalse(mRow.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
-                mNotificationData.get(mRow.getEntry().key)
-                        .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
-        assertFalse(row2.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
-                mNotificationData.get(row2.getEntry().key)
-                        .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
-    }
-
-    @Test
-    public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications()
-            throws Exception {
-        mNotificationData.add(mRow.getEntry());
-        ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
-        mNotificationData.add(row2.getEntry());
-
-        when(mEnvironment.isNotificationForCurrentProfiles(
-                mRow.getEntry().notification)).thenReturn(false);
-        when(mEnvironment.isNotificationForCurrentProfiles(
-                row2.getEntry().notification)).thenReturn(true);
-        ArrayList<NotificationData.Entry> result =
-                mNotificationData.getNotificationsForCurrentUser();
-
-        assertEquals(result.size(), 1);
-        junit.framework.Assert.assertEquals(result.get(0), row2.getEntry());
-    }
-
-    @Test
-    public void testIsExemptFromDndVisualSuppression_foreground() {
-        initStatusBarNotification(false);
-        when(mMockStatusBarNotification.getKey()).thenReturn(
-                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
-        Notification n = mMockStatusBarNotification.getNotification();
-        n.flags = Notification.FLAG_FOREGROUND_SERVICE;
-        NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
-        mNotificationData.add(entry);
-
-        assertTrue(entry.isExemptFromDndVisualSuppression());
-        assertFalse(entry.shouldSuppressAmbient());
-    }
-
-    @Test
-    public void testIsExemptFromDndVisualSuppression_media() {
-        initStatusBarNotification(false);
-        when(mMockStatusBarNotification.getKey()).thenReturn(
-                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
-        Notification n = mMockStatusBarNotification.getNotification();
-        Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n);
-        nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
-        n = nb.build();
-        when(mMockStatusBarNotification.getNotification()).thenReturn(n);
-        NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
-        mNotificationData.add(entry);
-
-        assertTrue(entry.isExemptFromDndVisualSuppression());
-        assertFalse(entry.shouldSuppressAmbient());
-    }
-
-    @Test
-    public void testIsExemptFromDndVisualSuppression_system() {
-        initStatusBarNotification(false);
-        when(mMockStatusBarNotification.getKey()).thenReturn(
-                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
-        NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
-        entry.mIsSystemNotification = true;
-        mNotificationData.add(entry);
-
-        assertTrue(entry.isExemptFromDndVisualSuppression());
-        assertFalse(entry.shouldSuppressAmbient());
-    }
-
-    @Test
-    public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
-        initStatusBarNotification(false);
-        when(mMockStatusBarNotification.getKey()).thenReturn(
-                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
-        NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
-        entry.mIsSystemNotification = true;
-        mNotificationData.add(entry);
-
-        when(mMockStatusBarNotification.getNotification()).thenReturn(
-                new Notification.Builder(mContext, "").setCategory(CATEGORY_CALL).build());
-
-        assertFalse(entry.isExemptFromDndVisualSuppression());
-        assertTrue(entry.shouldSuppressAmbient());
-
-        when(mMockStatusBarNotification.getNotification()).thenReturn(
-                new Notification.Builder(mContext, "").setCategory(CATEGORY_REMINDER).build());
-
-        assertFalse(entry.isExemptFromDndVisualSuppression());
-
-        when(mMockStatusBarNotification.getNotification()).thenReturn(
-                new Notification.Builder(mContext, "").setCategory(CATEGORY_ALARM).build());
-
-        assertFalse(entry.isExemptFromDndVisualSuppression());
-
-        when(mMockStatusBarNotification.getNotification()).thenReturn(
-                new Notification.Builder(mContext, "").setCategory(CATEGORY_EVENT).build());
-
-        assertFalse(entry.isExemptFromDndVisualSuppression());
-
-        when(mMockStatusBarNotification.getNotification()).thenReturn(
-                new Notification.Builder(mContext, "").setCategory(CATEGORY_MESSAGE).build());
-
-        assertFalse(entry.isExemptFromDndVisualSuppression());
-    }
-
-    @Test
-    public void testCreateNotificationDataEntry_RankingUpdate() {
-        Ranking ranking = mock(Ranking.class);
-        initStatusBarNotification(false);
-
-        List<Notification.Action> appGeneratedSmartActions =
-                Collections.singletonList(createContextualAction("appGeneratedAction"));
-        mMockStatusBarNotification.getNotification().actions =
-                appGeneratedSmartActions.toArray(new Notification.Action[0]);
-
-        List<Notification.Action> systemGeneratedSmartActions =
-                Collections.singletonList(createAction("systemGeneratedAction"));
-        when(ranking.getSmartActions()).thenReturn(systemGeneratedSmartActions);
-
-        when(ranking.getChannel()).thenReturn(NOTIFICATION_CHANNEL);
-
-        when(ranking.getUserSentiment()).thenReturn(Ranking.USER_SENTIMENT_NEGATIVE);
-
-        SnoozeCriterion snoozeCriterion = new SnoozeCriterion("id", "explanation", "confirmation");
-        ArrayList<SnoozeCriterion> snoozeCriterions = new ArrayList<>();
-        snoozeCriterions.add(snoozeCriterion);
-        when(ranking.getSnoozeCriteria()).thenReturn(snoozeCriterions);
-
-        NotificationData.Entry entry =
-                new NotificationData.Entry(mMockStatusBarNotification, ranking);
-
-        assertEquals(systemGeneratedSmartActions, entry.systemGeneratedSmartActions);
-        assertEquals(NOTIFICATION_CHANNEL, entry.channel);
-        assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, entry.userSentiment);
-        assertEquals(snoozeCriterions, entry.snoozeCriteria);
-    }
-
-    @Test
-    public void notificationDataEntry_testIsLastMessageFromReply() {
-        Person.Builder person = new Person.Builder()
-                .setName("name")
-                .setKey("abc")
-                .setUri("uri")
-                .setBot(true);
-
-        // EXTRA_MESSAGING_PERSON is the same Person as the sender in last message in EXTRA_MESSAGES
-        Bundle bundle = new Bundle();
-        bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person.build());
-        Bundle[] messagesBundle = new Bundle[]{ new Notification.MessagingStyle.Message(
-                "text", 0, person.build()).toBundle() };
-        bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle);
-
-        Notification notification = new Notification.Builder(mContext, "test")
-                .addExtras(bundle)
-                .build();
-        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
-                notification, mContext.getUser(), "", 0);
-
-        NotificationData.Entry entry = new NotificationData.Entry(sbn);
-        entry.setHasSentReply();
-
-        assertTrue(entry.isLastMessageFromReply());
-    }
-
-    private void initStatusBarNotification(boolean allowDuringSetup) {
-        Bundle bundle = new Bundle();
-        bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
-        Notification notification = new Notification.Builder(mContext, "test")
-                .addExtras(bundle)
-                .build();
-        when(mMockStatusBarNotification.getNotification()).thenReturn(notification);
-    }
-
-    private class TestableNotificationData extends NotificationData {
-        public TestableNotificationData() {
-            super();
-        }
-
-        @Override
-        protected boolean getRanking(String key, Ranking outRanking) {
-            super.getRanking(key, outRanking);
-            if (key.equals(TEST_HIDDEN_NOTIFICATION_KEY)) {
-                outRanking.populate(key, outRanking.getRank(),
-                        outRanking.matchesInterruptionFilter(),
-                        outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
-                        outRanking.getImportance(), outRanking.getImportanceExplanation(),
-                        outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
-                        outRanking.canShowBadge(), outRanking.getUserSentiment(), true,
-                        -1, false, null, null);
-            } else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) {
-                outRanking.populate(key, outRanking.getRank(),
-                        outRanking.matchesInterruptionFilter(),
-                        outRanking.getVisibilityOverride(), 255,
-                        outRanking.getImportance(), outRanking.getImportanceExplanation(),
-                        outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
-                        outRanking.canShowBadge(), outRanking.getUserSentiment(), true, -1,
-                        false, null, null);
-            } else {
-                outRanking.populate(key, outRanking.getRank(),
-                        outRanking.matchesInterruptionFilter(),
-                        outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
-                        outRanking.getImportance(), outRanking.getImportanceExplanation(),
-                        outRanking.getOverrideGroupKey(), NOTIFICATION_CHANNEL, null, null,
-                        outRanking.canShowBadge(), outRanking.getUserSentiment(), false, -1,
-                        false, null, null);
-            }
-            return true;
-        }
-    }
-
-    private Notification.Action createContextualAction(String title) {
-        return new Notification.Action.Builder(
-                Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
-                title,
-                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0))
-                        .setSemanticAction(
-                                Notification.Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION)
-                        .build();
-    }
-
-    private Notification.Action createAction(String title) {
-        return new Notification.Action.Builder(
-                Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
-                title,
-                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build();
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index a2d408e..9ce6ae1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -22,18 +22,15 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
-import android.app.AppOpsManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -48,7 +45,6 @@
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
-import android.util.ArraySet;
 import android.widget.FrameLayout;
 
 import com.android.internal.logging.MetricsLogger;
@@ -65,7 +61,9 @@
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationInflater;
@@ -76,12 +74,11 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
-import junit.framework.Assert;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -121,8 +118,9 @@
     @Mock private MetricsLogger mMetricsLogger;
     @Mock private SmartReplyController mSmartReplyController;
     @Mock private RowInflaterTask mAsyncInflationTask;
+    @Mock private NotificationRowBinder mMockedRowBinder;
 
-    private NotificationData.Entry mEntry;
+    private NotificationEntry mEntry;
     private StatusBarNotification mSbn;
     private TestableNotificationEntryManager mEntryManager;
     private CountDownLatch mCountDownLatch;
@@ -135,8 +133,12 @@
             mCountDownLatch = new CountDownLatch(1);
         }
 
+        public void setNotificationData(NotificationData data) {
+            mNotificationData = data;
+        }
+
         @Override
-        public void onAsyncInflationFinished(NotificationData.Entry entry,
+        public void onAsyncInflationFinished(NotificationEntry entry,
                 @NotificationInflater.InflationFlag int inflatedFlags) {
             super.onAsyncInflationFinished(entry, inflatedFlags);
 
@@ -221,7 +223,7 @@
                 .setContentText("Text");
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
                 0, n.build(), new UserHandle(ActivityManager.getCurrentUser()), null, 0);
-        mEntry = new NotificationData.Entry(mSbn);
+        mEntry = new NotificationEntry(mSbn);
         mEntry.expandedIcon = mock(StatusBarIconView.class);
 
         mEntryManager = new TestableNotificationEntryManager(mContext);
@@ -256,13 +258,12 @@
 
         // Check that no inflation error occurred.
         verify(mEntryListener, never()).onInflationError(any(), any());
-        verify(mForegroundServiceController).addNotification(eq(mSbn), anyInt());
 
         // Row inflation:
-        ArgumentCaptor<NotificationData.Entry> entryCaptor = ArgumentCaptor.forClass(
-                NotificationData.Entry.class);
+        ArgumentCaptor<NotificationEntry> entryCaptor = ArgumentCaptor.forClass(
+                NotificationEntry.class);
         verify(mBindCallback).onBindRow(entryCaptor.capture(), any(), eq(mSbn), any());
-        NotificationData.Entry entry = entryCaptor.getValue();
+        NotificationEntry entry = entryCaptor.getValue();
         verify(mRemoteInputManager).bindRow(entry.getRow());
 
         // Row content inflation:
@@ -291,15 +292,43 @@
 
         verify(mEntryListener, never()).onInflationError(any(), any());
 
+        verify(mEntryListener).onPreEntryUpdated(mEntry);
         verify(mPresenter).updateNotificationViews();
-        verify(mForegroundServiceController).updateNotification(eq(mSbn), anyInt());
-        verify(mEntryListener).onEntryUpdated(mEntry);
+        verify(mEntryListener).onPostEntryUpdated(mEntry);
+
         assertNotNull(mEntry.getRow());
         assertEquals(mEntry.userSentiment,
                 NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE);
     }
 
     @Test
+    public void testUpdateNotification_prePostEntryOrder() throws Exception {
+        com.android.systemui.util.Assert.isNotMainThread();
+        TestableLooper.get(this).processAllMessages();
+
+        NotificationData notifData = mock(NotificationData.class);
+        when(notifData.get(mEntry.key)).thenReturn(mEntry);
+
+        mEntryManager.setNotificationData(notifData);
+
+        mEntryManager.updateNotification(mSbn, mRankingMap);
+        TestableLooper.get(this).processMessages(1);
+        // Wait for content update.
+        assertTrue(mEntryManager.getCountDownLatch().await(10, TimeUnit.SECONDS));
+
+        verify(mEntryListener, never()).onInflationError(any(), any());
+
+        // Ensure that update callbacks happen in correct order
+        InOrder order = inOrder(mEntryListener, notifData, mPresenter, mEntryListener);
+        order.verify(mEntryListener).onPreEntryUpdated(mEntry);
+        order.verify(notifData).filterAndSort();
+        order.verify(mPresenter).updateNotificationViews();
+        order.verify(mEntryListener).onPostEntryUpdated(mEntry);
+
+        assertNotNull(mEntry.getRow());
+    }
+
+    @Test
     public void testRemoveNotification() throws Exception {
         com.android.systemui.util.Assert.isNotMainThread();
 
@@ -310,11 +339,9 @@
 
         verify(mEntryListener, never()).onInflationError(any(), any());
 
-        verify(mForegroundServiceController).removeNotification(mSbn);
-        verify(mListContainer).cleanUpViewStateForEntry(mEntry);
         verify(mPresenter).updateNotificationViews();
-        verify(mEntryListener).onEntryRemoved(mEntry, mSbn.getKey(), mSbn,
-                null, false /* lifetimeExtended */, false /* removedByUser */);
+        verify(mEntryListener).onEntryRemoved(
+                mEntry, null, false /* removedByUser */);
         verify(mRow).setRemoved();
 
         assertNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
@@ -338,92 +365,31 @@
 
         assertNotNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
         verify(extender).setShouldManageLifetime(mEntry, true /* shouldManage */);
-        verify(mEntryListener).onEntryRemoved(mEntry, mSbn.getKey(), null,
-                null, true /* lifetimeExtended */, false /* removedByUser */);
+        verify(mEntryListener, never()).onEntryRemoved(
+                mEntry, null, false /* removedByUser */);
     }
 
     @Test
-    public void testUpdateAppOps_foregroundNoti() {
+    public void testRemoveNotification_onEntryRemoveNotFiredIfEntryDoesntExist() {
         com.android.systemui.util.Assert.isNotMainThread();
 
-        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
-                .thenReturn(mEntry.key);
-        mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
+        mEntryManager.removeNotification("not_a_real_key", mRankingMap);
 
-        mEntryManager.updateNotificationsForAppOp(
-                AppOpsManager.OP_CAMERA, mEntry.notification.getUid(),
-                mEntry.notification.getPackageName(), true);
-
-        verify(mPresenter, times(1)).updateNotificationViews();
-        assertTrue(mEntryManager.getNotificationData().get(mEntry.key).mActiveAppOps.contains(
-                AppOpsManager.OP_CAMERA));
+        verify(mEntryListener, never()).onEntryRemoved(
+                mEntry, null, false /* removedByUser */);
     }
 
     @Test
-    public void testUpdateAppOps_otherNoti() {
+    public void testRemoveNotification_whilePending() throws InterruptedException {
         com.android.systemui.util.Assert.isNotMainThread();
 
-        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
-                .thenReturn(null);
-        mEntryManager.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
+        mEntryManager.setRowBinder(mMockedRowBinder);
 
-        verify(mPresenter, never()).updateNotificationViews();
-    }
+        mEntryManager.addNotification(mSbn, mRankingMap);
+        mEntryManager.removeNotification(mSbn.getKey(), mRankingMap);
 
-    @Test
-    public void testAddNotificationExistingAppOps() {
-        mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
-        ArraySet<Integer> expected = new ArraySet<>();
-        expected.add(3);
-        expected.add(235);
-        expected.add(1);
-
-        when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(expected);
-        when(mForegroundServiceController.getStandardLayoutKey(
-                mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(mEntry.key);
-
-        mEntryManager.tagForeground(mEntry.notification);
-
-        Assert.assertEquals(expected.size(), mEntry.mActiveAppOps.size());
-        for (int op : expected) {
-            assertTrue("Entry missing op " + op, mEntry.mActiveAppOps.contains(op));
-        }
-    }
-
-    @Test
-    public void testAdd_noExistingAppOps() {
-        mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
-        when(mForegroundServiceController.getStandardLayoutKey(
-                mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(mEntry.key);
-        when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(null);
-
-        mEntryManager.tagForeground(mEntry.notification);
-        Assert.assertEquals(0, mEntry.mActiveAppOps.size());
-    }
-
-    @Test
-    public void testAdd_existingAppOpsNotForegroundNoti() {
-        mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
-        ArraySet<Integer> ops = new ArraySet<>();
-        ops.add(3);
-        ops.add(235);
-        ops.add(1);
-        when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn(ops);
-        when(mForegroundServiceController.getStandardLayoutKey(
-                mEntry.notification.getUserId(),
-                mEntry.notification.getPackageName())).thenReturn("something else");
-
-        mEntryManager.tagForeground(mEntry.notification);
-        Assert.assertEquals(0, mEntry.mActiveAppOps.size());
+        verify(mEntryListener, never()).onEntryRemoved(
+                mEntry, null, false /* removedByUser */);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index da8bc01d..387475f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -40,6 +40,8 @@
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ShadeController;
@@ -191,12 +193,12 @@
 
         // test should filter out hidden notifications:
         // hidden
-        NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
+        NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
         entry.suspended = true;
         assertTrue(mNotificationFilter.shouldFilterOut(entry));
 
         // not hidden
-        entry = new NotificationData.Entry(mMockStatusBarNotification);
+        entry = new NotificationEntry(mMockStatusBarNotification);
         entry.suspended = false;
         assertFalse(mNotificationFilter.shouldFilterOut(entry));
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
new file mode 100644
index 0000000..4b5037b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+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 android.util.ArraySet;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationListControllerTest extends SysuiTestCase {
+    private NotificationListController mController;
+
+    @Mock private NotificationEntryManager mEntryManager;
+    @Mock private NotificationListContainer mListContainer;
+    @Mock private ForegroundServiceController mForegroundServiceController;
+    @Mock private DeviceProvisionedController mDeviceProvisionedController;
+
+    @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
+    @Captor private ArgumentCaptor<DeviceProvisionedListener> mProvisionedCaptor;
+
+    private NotificationEntryListener mEntryListener;
+    private DeviceProvisionedListener mProvisionedListener;
+
+    // TODO: Remove this once EntryManager no longer needs to be mocked
+    private NotificationData mNotificationData = new NotificationData();
+
+    private int mNextNotifId = 0;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
+
+        mController = new NotificationListController(
+                mEntryManager,
+                mListContainer,
+                mForegroundServiceController,
+                mDeviceProvisionedController);
+        mController.bind();
+
+        // Capture callbacks passed to mocks
+        verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
+        mEntryListener = mEntryListenerCaptor.getValue();
+        verify(mDeviceProvisionedController).addCallback(mProvisionedCaptor.capture());
+        mProvisionedListener = mProvisionedCaptor.getValue();
+    }
+
+    @Test
+    public void testCleanUpViewStateOnEntryRemoved() {
+        final NotificationEntry entry = buildEntry();
+        mEntryListener.onEntryRemoved(
+                entry,
+                NotificationVisibility.obtain(entry.key, 0, 0, true),
+                false);
+        verify(mListContainer).cleanUpViewStateForEntry(entry);
+    }
+
+    @Test
+    public void testCallUpdateNotificationsOnDeviceProvisionedChange() {
+        mProvisionedListener.onDeviceProvisionedChanged();
+        verify(mEntryManager).updateNotifications();
+    }
+
+    @Test
+    public void testAppOps_appOpAddedToForegroundNotif() {
+        // GIVEN a notification associated with a foreground service
+        final NotificationEntry entry = buildEntry();
+        mNotificationData.add(entry);
+        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
+                .thenReturn(entry.key);
+
+        // WHEN we are notified of a new app op
+        mController.updateNotificationsForAppOp(
+                AppOpsManager.OP_CAMERA,
+                entry.notification.getUid(),
+                entry.notification.getPackageName(),
+                true);
+
+        // THEN the app op is added to the entry
+        assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
+        // THEN updateNotifications() is called
+        verify(mEntryManager, times(1)).updateNotifications();
+    }
+
+    @Test
+    public void testAppOps_appOpAddedToUnrelatedNotif() {
+        // GIVEN No current foreground notifs
+        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
+                .thenReturn(null);
+
+        // WHEN An unrelated notification gets a new app op
+        mController.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
+
+        // THEN We never call updateNotifications()
+        verify(mEntryManager, never()).updateNotifications();
+    }
+
+    @Test
+    public void testAppOps_addNotificationWithExistingAppOps() {
+        // GIVEN a notification with three associated app ops that is associated with a foreground
+        // service
+        final NotificationEntry entry = buildEntry();
+        mNotificationData.add(entry);
+        ArraySet<Integer> expected = new ArraySet<>();
+        expected.add(3);
+        expected.add(235);
+        expected.add(1);
+        when(mForegroundServiceController.getStandardLayoutKey(
+                entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(entry.key);
+        when(mForegroundServiceController.getAppOps(entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(expected);
+
+        // WHEN the notification is added
+        mEntryListener.onBeforeNotificationAdded(entry);
+
+        // THEN the entry is tagged with all three app ops
+        assertEquals(expected.size(), entry.mActiveAppOps.size());
+        for (int op : expected) {
+            assertTrue("Entry missing op " + op, entry.mActiveAppOps.contains(op));
+        }
+    }
+
+    @Test
+    public void testAdd_addNotificationWithNoExistingAppOps() {
+        // GIVEN a notification with NO associated app ops
+        final NotificationEntry entry = buildEntry();
+
+        mNotificationData.add(entry);
+        when(mForegroundServiceController.getStandardLayoutKey(
+                entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(entry.key);
+        when(mForegroundServiceController.getAppOps(entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(null);
+
+        // WHEN the notification is added
+        mEntryListener.onBeforeNotificationAdded(entry);
+
+        // THEN the entry doesn't have any app ops associated with it
+        assertEquals(0, entry.mActiveAppOps.size());
+    }
+
+    @Test
+    public void testAdd_addNonForegroundNotificationWithExistingAppOps() {
+        // GIVEN a notification with app ops that isn't associated with a foreground service
+        final NotificationEntry entry = buildEntry();
+        mNotificationData.add(entry);
+        ArraySet<Integer> ops = new ArraySet<>();
+        ops.add(3);
+        ops.add(235);
+        ops.add(1);
+        when(mForegroundServiceController.getAppOps(entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn(ops);
+        when(mForegroundServiceController.getStandardLayoutKey(
+                entry.notification.getUserId(),
+                entry.notification.getPackageName())).thenReturn("something else");
+
+        // WHEN the notification is added
+        mEntryListener.onBeforeNotificationAdded(entry);
+
+        // THEN the entry doesn't have any app ops associated with it
+        assertEquals(0, entry.mActiveAppOps.size());
+    }
+
+    private NotificationEntry buildEntry() {
+        mNextNotifId++;
+
+        Notification.Builder n = new Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+
+        StatusBarNotification notification =
+                new StatusBarNotification(
+                        TEST_PACKAGE_NAME,
+                        TEST_PACKAGE_NAME,
+                        mNextNotifId,
+                        null,
+                        TEST_UID,
+                        0,
+                        n.build(),
+                        new UserHandle(ActivityManager.getCurrentUser()),
+                        null,
+                        0);
+        return new NotificationEntry(notification);
+    }
+
+    private static final String TEST_PACKAGE_NAME = "test";
+    private static final int TEST_UID = 0;
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
index 6fbd8c7..813fc9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
@@ -29,6 +29,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
 import org.junit.Before;
@@ -44,13 +45,13 @@
     private VisualStabilityManager.Callback mCallback = mock(VisualStabilityManager.Callback.class);
     private VisibilityLocationProvider mLocationProvider = mock(VisibilityLocationProvider.class);
     private ExpandableNotificationRow mRow = mock(ExpandableNotificationRow.class);
-    private NotificationData.Entry mEntry;
+    private NotificationEntry mEntry;
 
     @Before
     public void setUp() {
         mVisualStabilityManager.setUpWithPresenter(mock(NotificationPresenter.class));
         mVisualStabilityManager.setVisibilityLocationProvider(mLocationProvider);
-        mEntry = new NotificationData.Entry(mock(StatusBarNotification.class));
+        mEntry = new NotificationEntry(mock(StatusBarNotification.class));
         mEntry.setRow(mRow);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
new file mode 100644
index 0000000..b507692
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER;
+import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.Notification.CATEGORY_ALARM;
+import static android.app.Notification.CATEGORY_CALL;
+import static android.app.Notification.CATEGORY_EVENT;
+import static android.app.Notification.CATEGORY_MESSAGE;
+import static android.app.Notification.CATEGORY_REMINDER;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.PendingIntent;
+import android.app.Person;
+import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Icon;
+import android.media.session.MediaSession;
+import android.os.Bundle;
+import android.os.Process;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.SnoozeCriterion;
+import android.service.notification.StatusBarNotification;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.util.ArraySet;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.InitController;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ShadeController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class NotificationDataTest extends SysuiTestCase {
+
+    private static final int UID_NORMAL = 123;
+    private static final int UID_ALLOW_DURING_SETUP = 456;
+    private static final String TEST_HIDDEN_NOTIFICATION_KEY = "testHiddenNotificationKey";
+    private static final String TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY = "exempt";
+    private static final NotificationChannel NOTIFICATION_CHANNEL =
+            new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
+
+    private final StatusBarNotification mMockStatusBarNotification =
+            mock(StatusBarNotification.class);
+    @Mock
+    ForegroundServiceController mFsc;
+    @Mock
+    NotificationData.KeyguardEnvironment mEnvironment;
+
+    private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
+    private NotificationData mNotificationData;
+    private ExpandableNotificationRow mRow;
+
+    @Before
+    public void setUp() throws Exception {
+        com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
+        MockitoAnnotations.initMocks(this);
+        when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
+        when(mMockStatusBarNotification.cloneLight()).thenReturn(mMockStatusBarNotification);
+
+        when(mMockPackageManager.checkUidPermission(
+                eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
+                eq(UID_NORMAL)))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+        when(mMockPackageManager.checkUidPermission(
+                eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
+                eq(UID_ALLOW_DURING_SETUP)))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+        mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
+        mDependency.injectTestDependency(NotificationGroupManager.class,
+                new NotificationGroupManager());
+        mDependency.injectMockDependency(ShadeController.class);
+        mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
+        when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
+        when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
+        mNotificationData = new TestableNotificationData();
+        mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class));
+        mRow = new NotificationTestHelper(getContext()).createRow();
+        Dependency.get(InitController.class).executePostInitTasks();
+    }
+
+    @Test
+    public void testChannelSetWhenAdded() {
+        mNotificationData.add(mRow.getEntry());
+        assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().channel);
+    }
+
+    @Test
+    public void testAllRelevantNotisTaggedWithAppOps() throws Exception {
+        mNotificationData.add(mRow.getEntry());
+        ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
+        mNotificationData.add(row2.getEntry());
+        ExpandableNotificationRow diffPkg =
+                new NotificationTestHelper(getContext()).createRow("pkg", 4000,
+                        Process.myUserHandle());
+        mNotificationData.add(diffPkg.getEntry());
+
+        ArraySet<Integer> expectedOps = new ArraySet<>();
+        expectedOps.add(OP_CAMERA);
+        expectedOps.add(OP_ACCEPT_HANDOVER);
+
+        for (int op : expectedOps) {
+            mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
+                    NotificationTestHelper.PKG, mRow.getEntry().key, true);
+            mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
+                    NotificationTestHelper.PKG, row2.getEntry().key, true);
+        }
+        for (int op : expectedOps) {
+            assertTrue(mRow.getEntry().key + " doesn't have op " + op,
+                    mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(op));
+            assertTrue(row2.getEntry().key + " doesn't have op " + op,
+                    mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(op));
+            assertFalse(diffPkg.getEntry().key + " has op " + op,
+                    mNotificationData.get(diffPkg.getEntry().key).mActiveAppOps.contains(op));
+        }
+    }
+
+    @Test
+    public void testAppOpsRemoval() throws Exception {
+        mNotificationData.add(mRow.getEntry());
+        ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
+        mNotificationData.add(row2.getEntry());
+
+        ArraySet<Integer> expectedOps = new ArraySet<>();
+        expectedOps.add(OP_CAMERA);
+        expectedOps.add(OP_ACCEPT_HANDOVER);
+
+        for (int op : expectedOps) {
+            mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
+                    NotificationTestHelper.PKG, row2.getEntry().key, true);
+        }
+
+        expectedOps.remove(OP_ACCEPT_HANDOVER);
+        mNotificationData.updateAppOp(OP_ACCEPT_HANDOVER, NotificationTestHelper.UID,
+                NotificationTestHelper.PKG, row2.getEntry().key, false);
+
+        assertTrue(mRow.getEntry().key + " doesn't have op " + OP_CAMERA,
+                mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
+        assertTrue(row2.getEntry().key + " doesn't have op " + OP_CAMERA,
+                mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
+        assertFalse(mRow.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
+                mNotificationData.get(mRow.getEntry().key)
+                        .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
+        assertFalse(row2.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
+                mNotificationData.get(row2.getEntry().key)
+                        .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
+    }
+
+    @Test
+    public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications()
+            throws Exception {
+        mNotificationData.add(mRow.getEntry());
+        ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
+        mNotificationData.add(row2.getEntry());
+
+        when(mEnvironment.isNotificationForCurrentProfiles(
+                mRow.getEntry().notification)).thenReturn(false);
+        when(mEnvironment.isNotificationForCurrentProfiles(
+                row2.getEntry().notification)).thenReturn(true);
+        ArrayList<NotificationEntry> result =
+                mNotificationData.getNotificationsForCurrentUser();
+
+        assertEquals(result.size(), 1);
+        junit.framework.Assert.assertEquals(result.get(0), row2.getEntry());
+    }
+
+    @Test
+    public void testIsExemptFromDndVisualSuppression_foreground() {
+        initStatusBarNotification(false);
+        when(mMockStatusBarNotification.getKey()).thenReturn(
+                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
+        Notification n = mMockStatusBarNotification.getNotification();
+        n.flags = Notification.FLAG_FOREGROUND_SERVICE;
+        NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        mNotificationData.add(entry);
+
+        assertTrue(entry.isExemptFromDndVisualSuppression());
+        assertFalse(entry.shouldSuppressAmbient());
+    }
+
+    @Test
+    public void testIsExemptFromDndVisualSuppression_media() {
+        initStatusBarNotification(false);
+        when(mMockStatusBarNotification.getKey()).thenReturn(
+                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
+        Notification n = mMockStatusBarNotification.getNotification();
+        Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n);
+        nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
+        n = nb.build();
+        when(mMockStatusBarNotification.getNotification()).thenReturn(n);
+        NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        mNotificationData.add(entry);
+
+        assertTrue(entry.isExemptFromDndVisualSuppression());
+        assertFalse(entry.shouldSuppressAmbient());
+    }
+
+    @Test
+    public void testIsExemptFromDndVisualSuppression_system() {
+        initStatusBarNotification(false);
+        when(mMockStatusBarNotification.getKey()).thenReturn(
+                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
+        NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.mIsSystemNotification = true;
+        mNotificationData.add(entry);
+
+        assertTrue(entry.isExemptFromDndVisualSuppression());
+        assertFalse(entry.shouldSuppressAmbient());
+    }
+
+    @Test
+    public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
+        initStatusBarNotification(false);
+        when(mMockStatusBarNotification.getKey()).thenReturn(
+                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
+        NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
+        entry.mIsSystemNotification = true;
+        mNotificationData.add(entry);
+
+        when(mMockStatusBarNotification.getNotification()).thenReturn(
+                new Notification.Builder(mContext, "").setCategory(CATEGORY_CALL).build());
+
+        assertFalse(entry.isExemptFromDndVisualSuppression());
+        assertTrue(entry.shouldSuppressAmbient());
+
+        when(mMockStatusBarNotification.getNotification()).thenReturn(
+                new Notification.Builder(mContext, "").setCategory(CATEGORY_REMINDER).build());
+
+        assertFalse(entry.isExemptFromDndVisualSuppression());
+
+        when(mMockStatusBarNotification.getNotification()).thenReturn(
+                new Notification.Builder(mContext, "").setCategory(CATEGORY_ALARM).build());
+
+        assertFalse(entry.isExemptFromDndVisualSuppression());
+
+        when(mMockStatusBarNotification.getNotification()).thenReturn(
+                new Notification.Builder(mContext, "").setCategory(CATEGORY_EVENT).build());
+
+        assertFalse(entry.isExemptFromDndVisualSuppression());
+
+        when(mMockStatusBarNotification.getNotification()).thenReturn(
+                new Notification.Builder(mContext, "").setCategory(CATEGORY_MESSAGE).build());
+
+        assertFalse(entry.isExemptFromDndVisualSuppression());
+    }
+
+    @Test
+    public void testCreateNotificationDataEntry_RankingUpdate() {
+        Ranking ranking = mock(Ranking.class);
+        initStatusBarNotification(false);
+
+        List<Notification.Action> appGeneratedSmartActions =
+                Collections.singletonList(createContextualAction("appGeneratedAction"));
+        mMockStatusBarNotification.getNotification().actions =
+                appGeneratedSmartActions.toArray(new Notification.Action[0]);
+
+        List<Notification.Action> systemGeneratedSmartActions =
+                Collections.singletonList(createAction("systemGeneratedAction"));
+        when(ranking.getSmartActions()).thenReturn(systemGeneratedSmartActions);
+
+        when(ranking.getChannel()).thenReturn(NOTIFICATION_CHANNEL);
+
+        when(ranking.getUserSentiment()).thenReturn(Ranking.USER_SENTIMENT_NEGATIVE);
+
+        SnoozeCriterion snoozeCriterion = new SnoozeCriterion("id", "explanation", "confirmation");
+        ArrayList<SnoozeCriterion> snoozeCriterions = new ArrayList<>();
+        snoozeCriterions.add(snoozeCriterion);
+        when(ranking.getSnoozeCriteria()).thenReturn(snoozeCriterions);
+
+        NotificationEntry entry =
+                new NotificationEntry(mMockStatusBarNotification, ranking);
+
+        assertEquals(systemGeneratedSmartActions, entry.systemGeneratedSmartActions);
+        assertEquals(NOTIFICATION_CHANNEL, entry.channel);
+        assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, entry.userSentiment);
+        assertEquals(snoozeCriterions, entry.snoozeCriteria);
+    }
+
+    @Test
+    public void notificationDataEntry_testIsLastMessageFromReply() {
+        Person.Builder person = new Person.Builder()
+                .setName("name")
+                .setKey("abc")
+                .setUri("uri")
+                .setBot(true);
+
+        // EXTRA_MESSAGING_PERSON is the same Person as the sender in last message in EXTRA_MESSAGES
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person.build());
+        Bundle[] messagesBundle = new Bundle[]{ new Notification.MessagingStyle.Message(
+                "text", 0, person.build()).toBundle() };
+        bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle);
+
+        Notification notification = new Notification.Builder(mContext, "test")
+                .addExtras(bundle)
+                .build();
+        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+                notification, mContext.getUser(), "", 0);
+
+        NotificationEntry entry = new NotificationEntry(sbn);
+        entry.setHasSentReply();
+
+        assertTrue(entry.isLastMessageFromReply());
+    }
+
+    private void initStatusBarNotification(boolean allowDuringSetup) {
+        Bundle bundle = new Bundle();
+        bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
+        Notification notification = new Notification.Builder(mContext, "test")
+                .addExtras(bundle)
+                .build();
+        when(mMockStatusBarNotification.getNotification()).thenReturn(notification);
+    }
+
+    private class TestableNotificationData extends NotificationData {
+        public TestableNotificationData() {
+            super();
+        }
+
+        @Override
+        protected boolean getRanking(String key, Ranking outRanking) {
+            super.getRanking(key, outRanking);
+            if (key.equals(TEST_HIDDEN_NOTIFICATION_KEY)) {
+                outRanking.populate(key, outRanking.getRank(),
+                        outRanking.matchesInterruptionFilter(),
+                        outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
+                        outRanking.getImportance(), outRanking.getImportanceExplanation(),
+                        outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
+                        outRanking.canShowBadge(), outRanking.getUserSentiment(), true,
+                        -1, false, null, null);
+            } else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) {
+                outRanking.populate(key, outRanking.getRank(),
+                        outRanking.matchesInterruptionFilter(),
+                        outRanking.getVisibilityOverride(), 255,
+                        outRanking.getImportance(), outRanking.getImportanceExplanation(),
+                        outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
+                        outRanking.canShowBadge(), outRanking.getUserSentiment(), true, -1,
+                        false, null, null);
+            } else {
+                outRanking.populate(key, outRanking.getRank(),
+                        outRanking.matchesInterruptionFilter(),
+                        outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
+                        outRanking.getImportance(), outRanking.getImportanceExplanation(),
+                        outRanking.getOverrideGroupKey(), NOTIFICATION_CHANNEL, null, null,
+                        outRanking.canShowBadge(), outRanking.getUserSentiment(), false, -1,
+                        false, null, null);
+            }
+            return true;
+        }
+    }
+
+    private Notification.Action createContextualAction(String title) {
+        return new Notification.Action.Builder(
+                Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
+                title,
+                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0))
+                        .setContextual(true)
+                        .build();
+    }
+
+    private Notification.Action createAction(String title) {
+        return new Notification.Action.Builder(
+                Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
+                title,
+                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
new file mode 100644
index 0000000..5ff9d14
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
@@ -0,0 +1,167 @@
+/**
+ * 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.logging;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.os.RemoteException;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.UiOffloadThread;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Collections;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class ExpansionStateLoggerTest extends SysuiTestCase {
+    private static final String NOTIFICATION_KEY = "notin_key";
+
+    private NotificationLogger.ExpansionStateLogger mLogger;
+    @Mock
+    private IStatusBarService mBarService;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mLogger = new NotificationLogger.ExpansionStateLogger(
+                Dependency.get(UiOffloadThread.class));
+        mLogger.mBarService = mBarService;
+    }
+
+    @Test
+    public void testVisible() throws RemoteException {
+        mLogger.onVisibilityChanged(
+                Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
+                Collections.emptyList());
+        waitForUiOffloadThread();
+
+        verify(mBarService, Mockito.never()).onNotificationExpansionChanged(
+                eq(NOTIFICATION_KEY), anyBoolean(), anyBoolean(), anyInt());
+    }
+
+    @Test
+    public void testExpanded() throws RemoteException {
+        mLogger.onExpansionChanged(NOTIFICATION_KEY, false, true,
+                NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN);
+        waitForUiOffloadThread();
+
+        verify(mBarService, Mockito.never()).onNotificationExpansionChanged(
+                eq(NOTIFICATION_KEY), anyBoolean(), anyBoolean(), anyInt());
+    }
+
+    @Test
+    public void testVisibleAndNotExpanded() throws RemoteException {
+        mLogger.onExpansionChanged(NOTIFICATION_KEY, true, false,
+                NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN);
+        mLogger.onVisibilityChanged(
+                Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
+                Collections.emptyList());
+        waitForUiOffloadThread();
+
+        verify(mBarService, Mockito.never()).onNotificationExpansionChanged(
+                eq(NOTIFICATION_KEY), anyBoolean(), anyBoolean(), anyInt());
+    }
+
+    @Test
+    public void testVisibleAndExpanded() throws RemoteException {
+        mLogger.onExpansionChanged(NOTIFICATION_KEY, true, true,
+                NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN);
+        mLogger.onVisibilityChanged(
+                Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
+                Collections.emptyList());
+        waitForUiOffloadThread();
+
+        verify(mBarService).onNotificationExpansionChanged(
+                NOTIFICATION_KEY, true, true,
+                NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN.toMetricsEventEnum());
+    }
+
+    @Test
+    public void testExpandedAndVisible_expandedBeforeVisible() throws RemoteException {
+        mLogger.onExpansionChanged(NOTIFICATION_KEY, false, true,
+                NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN);
+        mLogger.onVisibilityChanged(
+                Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true,
+                    NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA)),
+                Collections.emptyList());
+        waitForUiOffloadThread();
+
+        verify(mBarService).onNotificationExpansionChanged(
+                NOTIFICATION_KEY, false, true,
+                // The last location seen should be logged (the one passed to onVisibilityChanged).
+                NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.toMetricsEventEnum()
+        );
+    }
+
+    @Test
+    public void testExpandedAndVisible_visibleBeforeExpanded() throws RemoteException {
+        mLogger.onVisibilityChanged(
+                Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
+                Collections.emptyList());
+        mLogger.onExpansionChanged(NOTIFICATION_KEY, false, true,
+                NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP);
+        waitForUiOffloadThread();
+
+        verify(mBarService).onNotificationExpansionChanged(
+                NOTIFICATION_KEY, false, true,
+                // The last location seen should be logged (the one passed to onExpansionChanged).
+                NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP.toMetricsEventEnum());
+    }
+
+    @Test
+    public void testExpandedAndVisible_logOnceOnly() throws RemoteException {
+        mLogger.onVisibilityChanged(
+                Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
+                Collections.emptyList());
+        mLogger.onExpansionChanged(NOTIFICATION_KEY, false, true,
+                NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN);
+        mLogger.onExpansionChanged(NOTIFICATION_KEY, false, true,
+                NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN);
+        waitForUiOffloadThread();
+
+        verify(mBarService).onNotificationExpansionChanged(
+                NOTIFICATION_KEY, false, true,
+                NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN.toMetricsEventEnum());
+    }
+
+    private NotificationVisibility createNotificationVisibility(String key, boolean visibility) {
+        return createNotificationVisibility(key, visibility,
+                NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN);
+    }
+
+    private NotificationVisibility createNotificationVisibility(String key, boolean visibility,
+            NotificationVisibility.NotificationLocation location) {
+        return NotificationVisibility.obtain(key, 0, 0, visibility, location);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 7b96518..db2706b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -41,8 +41,10 @@
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 
@@ -51,6 +53,8 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
@@ -68,13 +72,16 @@
     @Mock private IStatusBarService mBarService;
     @Mock private NotificationData mNotificationData;
     @Mock private ExpandableNotificationRow mRow;
+    @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
 
     // Dependency mocks:
     @Mock private NotificationEntryManager mEntryManager;
     @Mock private NotificationListener mListener;
+    @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
 
-    private NotificationData.Entry mEntry;
+    private NotificationEntry mEntry;
     private TestableNotificationLogger mLogger;
+    private NotificationEntryListener mNotificationEntryListener;
     private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
 
     @Before
@@ -88,12 +95,15 @@
         StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME,
                 0, null, TEST_UID,
                 0, new Notification(), UserHandle.CURRENT, null, 0);
-        mEntry = new NotificationData.Entry(sbn);
+        mEntry = new NotificationEntry(sbn);
         mEntry.setRow(mRow);
 
         mLogger = new TestableNotificationLogger(mListener, Dependency.get(UiOffloadThread.class),
-                mEntryManager, mock(StatusBarStateController.class), mBarService);
+                mEntryManager, mock(StatusBarStateController.class), mBarService,
+                mExpansionStateLogger);
         mLogger.setUpWithContainer(mListContainer);
+        verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
+        mNotificationEntryListener = mEntryListenerCaptor.getValue();
     }
 
     @Test
@@ -158,8 +168,10 @@
                 UiOffloadThread uiOffloadThread,
                 NotificationEntryManager entryManager,
                 StatusBarStateController statusBarStateController,
-                IStatusBarService barService) {
-            super(notificationListener, uiOffloadThread, entryManager, statusBarStateController);
+                IStatusBarService barService,
+                ExpansionStateLogger expansionStateLogger) {
+            super(notificationListener, uiOffloadThread, entryManager, statusBarStateController,
+                    expansionStateLogger);
             mBarService = barService;
             // Make this on the current thread so we can wait for it during tests.
             mHandler = Handler.createAsync(Looper.myLooper());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index f0fa788..d94bf84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -47,7 +47,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.SmartReplyConstants;
 
 import org.junit.Before;
@@ -73,7 +73,7 @@
     StatusBarNotification mStatusBarNotification;
     @Mock
     Notification mNotification;
-    NotificationData.Entry mEntry;
+    NotificationEntry mEntry;
     @Mock
     RemoteInput mRemoteInput;
     @Mock
@@ -107,7 +107,7 @@
         // Smart replies and actions
         when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(true);
         when(mStatusBarNotification.getNotification()).thenReturn(mNotification);
-        mEntry = new NotificationData.Entry(mStatusBarNotification);
+        mEntry = new NotificationEntry(mStatusBarNotification);
         when(mSmartReplyConstants.isEnabled()).thenReturn(true);
         mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
     }
@@ -159,28 +159,37 @@
         verify(mockHeadsUp, times(1)).showAppOpsIcons(any());
     }
 
-    private void setupAppGeneratedReplies(CharSequence[] smartReplyTitles) {
-        Notification.Action freeFormAction =
-                new Notification.Action.Builder(null, "Freeform Test Action", null).build();
-        setupAppGeneratedReplies(smartReplyTitles, freeFormAction);
+    private void setupAppGeneratedReplies(CharSequence[] smartReplies) {
+        setupAppGeneratedReplies(smartReplies, true /* allowSystemGeneratedReplies */);
     }
 
     private void setupAppGeneratedReplies(
-            CharSequence[] smartReplyTitles,
-            Notification.Action freeFormRemoteInputAction) {
+            CharSequence[] smartReplies, boolean allowSystemGeneratedReplies) {
         PendingIntent pendingIntent =
                 PendingIntent.getBroadcast(mContext, 0, new Intent(TEST_ACTION), 0);
         Notification.Action action =
                 new Notification.Action.Builder(null, "Test Action", pendingIntent).build();
-        when(mRemoteInput.getChoices()).thenReturn(smartReplyTitles);
+        when(mRemoteInput.getChoices()).thenReturn(smartReplies);
         Pair<RemoteInput, Notification.Action> remoteInputActionPair =
                 Pair.create(mRemoteInput, action);
         when(mNotification.findRemoteInputActionPair(false)).thenReturn(remoteInputActionPair);
 
+        Notification.Action freeFormRemoteInputAction =
+                createActionBuilder("Freeform Test Action")
+                .setAllowGeneratedReplies(allowSystemGeneratedReplies)
+                .build();
         Pair<RemoteInput, Notification.Action> freeFormRemoteInputActionPair =
                 Pair.create(mFreeFormRemoteInput, freeFormRemoteInputAction);
         when(mNotification.findRemoteInputActionPair(true)).thenReturn(
                 freeFormRemoteInputActionPair);
+
+        when(mSmartReplyConstants.requiresTargetingP()).thenReturn(false);
+    }
+
+    private void setupAppGeneratedSuggestions(
+            CharSequence[] smartReplies, List<Notification.Action> smartActions) {
+        setupAppGeneratedReplies(smartReplies);
+        when(mNotification.getContextualActions()).thenReturn(smartActions);
     }
 
     @Test
@@ -198,7 +207,6 @@
     public void chooseSmartRepliesAndActions_appGeneratedSmartReplies() {
         CharSequence[] smartReplies = new String[] {"Reply1", "Reply2"};
         setupAppGeneratedReplies(smartReplies);
-        when(mSmartReplyConstants.requiresTargetingP()).thenReturn(false);
 
         NotificationContentView.SmartRepliesAndActions repliesAndActions =
                 NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
@@ -211,12 +219,9 @@
     @Test
     public void chooseSmartRepliesAndActions_appGeneratedSmartRepliesAndActions() {
         CharSequence[] smartReplies = new String[] {"Reply1", "Reply2"};
-        setupAppGeneratedReplies(smartReplies);
-        when(mSmartReplyConstants.requiresTargetingP()).thenReturn(false);
-
         List<Notification.Action> smartActions =
                 createActions(new String[] {"Test Action 1", "Test Action 2"});
-        when(mNotification.getContextualActions()).thenReturn(smartActions);
+        setupAppGeneratedSuggestions(smartReplies, smartActions);
 
         NotificationContentView.SmartRepliesAndActions repliesAndActions =
                 NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
@@ -229,15 +234,11 @@
 
     @Test
     public void chooseSmartRepliesAndActions_sysGeneratedSmartReplies() {
-        Notification.Action freeFormAction = createActionBuilder("Freeform Action")
-                .setAllowGeneratedReplies(true)
-                .build();
         // Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
         // replies.
-        setupAppGeneratedReplies(null, freeFormAction);
+        setupAppGeneratedReplies(null /* smartReplies */);
 
-        mEntry.smartReplies =
-                new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
+        mEntry.smartReplies = new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
         NotificationContentView.SmartRepliesAndActions repliesAndActions =
                 NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
 
@@ -248,12 +249,9 @@
 
     @Test
     public void chooseSmartRepliesAndActions_noSysGeneratedSmartRepliesIfNotAllowed() {
-        Notification.Action freeFormAction = createActionBuilder("Freeform Action")
-                .setAllowGeneratedReplies(false)
-                .build();
         // Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
         // replies.
-        setupAppGeneratedReplies(null, freeFormAction);
+        setupAppGeneratedReplies(null /* smartReplies */, false /* allowSystemGeneratedReplies */);
 
         mEntry.smartReplies =
                 new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
@@ -268,7 +266,7 @@
     public void chooseSmartRepliesAndActions_sysGeneratedSmartActions() {
         // Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
         // actions.
-        setupAppGeneratedReplies(null);
+        setupAppGeneratedReplies(null /* smartReplies */);
 
         mEntry.systemGeneratedSmartActions =
                 createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
@@ -283,18 +281,12 @@
 
     @Test
     public void chooseSmartRepliesAndActions_appGenPreferredOverSysGen() {
-        Notification.Action freeFormAction = createActionBuilder("Freeform Action")
-                .setAllowGeneratedReplies(true)
-                .build();
         CharSequence[] appGenSmartReplies = new String[] {"Reply1", "Reply2"};
         // Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
         // replies.
-        setupAppGeneratedReplies(appGenSmartReplies, freeFormAction);
-        when(mSmartReplyConstants.requiresTargetingP()).thenReturn(false);
-
         List<Notification.Action> appGenSmartActions =
                 createActions(new String[] {"Test Action 1", "Test Action 2"});
-        when(mNotification.getContextualActions()).thenReturn(appGenSmartActions);
+        setupAppGeneratedSuggestions(appGenSmartReplies, appGenSmartActions);
 
         mEntry.smartReplies = new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
         mEntry.systemGeneratedSmartActions =
@@ -313,12 +305,12 @@
     public void chooseSmartRepliesAndActions_disallowSysGenSmartActions() {
         // Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
         // actions.
-        setupAppGeneratedReplies(null);
-
+        setupAppGeneratedReplies(null /* smartReplies */, false /* allowSystemGeneratedReplies */);
         when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(false);
-
+        mEntry.smartReplies = new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
         mEntry.systemGeneratedSmartActions =
                 createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
+
         NotificationContentView.SmartRepliesAndActions repliesAndActions =
                 NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index ad43bea..40d2da9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -45,6 +45,7 @@
 import android.app.NotificationChannel;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.metrics.LogMaker;
 import android.os.Binder;
 import android.os.Handler;
 import android.provider.Settings;
@@ -55,12 +56,14 @@
 import android.util.ArraySet;
 import android.view.View;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -92,6 +95,7 @@
     private NotificationGutsManager mGutsManager;
 
     @Rule public MockitoRule mockito = MockitoJUnit.rule();
+    @Mock private MetricsLogger mMetricsLogger;
     @Mock private NotificationPresenter mPresenter;
     @Mock private NotificationActivityStarter mNotificationActivityStarter;
     @Mock private NotificationStackScrollLayout mStackScroller;
@@ -105,6 +109,7 @@
         Assert.sMainLooper = TestableLooper.get(this).getLooper();
         mDependency.injectTestDependency(DeviceProvisionedController.class,
                 mDeviceProvisionedController);
+        mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
         mHandler = Handler.createAsync(mTestableLooper.getLooper());
 
         mHelper = new NotificationTestHelper(mContext);
@@ -141,7 +146,7 @@
         when(row.getWindowToken()).thenReturn(new Binder());
         when(row.getGuts()).thenReturn(guts);
 
-        mGutsManager.openGuts(row, 0, 0, menuItem);
+        assertTrue(mGutsManager.openGuts(row, 0, 0, menuItem));
         assertEquals(View.INVISIBLE, guts.getVisibility());
         mTestableLooper.processAllMessages();
         verify(guts).openControls(
@@ -183,13 +188,13 @@
         when(row.getGuts()).thenReturn(guts);
         doNothing().when(row).inflateGuts();
 
-        NotificationData.Entry realEntry = realRow.getEntry();
-        NotificationData.Entry entry = spy(realEntry);
+        NotificationEntry realEntry = realRow.getEntry();
+        NotificationEntry entry = spy(realEntry);
 
         when(entry.getRow()).thenReturn(row);
         when(entry.getGuts()).thenReturn(guts);
 
-        mGutsManager.openGuts(row, 0, 0, menuItem);
+        assertTrue(mGutsManager.openGuts(row, 0, 0, menuItem));
         mTestableLooper.processAllMessages();
         verify(guts).openControls(
                 eq(true),
@@ -215,6 +220,34 @@
     }
 
     @Test
+    public void testOpenGutsLogging() {
+        NotificationGutsManager gutsManager = spy(mGutsManager);
+        doReturn(true).when(gutsManager).bindGuts(any(), any());
+
+        NotificationGuts guts = spy(new NotificationGuts(mContext));
+        doReturn(true).when(guts).post(any());
+
+        ExpandableNotificationRow realRow = createTestNotificationRow();
+        NotificationMenuRowPlugin.MenuItem menuItem = createTestMenuItem(realRow);
+
+        ExpandableNotificationRow row = spy(realRow);
+        when(row.getWindowToken()).thenReturn(new Binder());
+        when(row.getGuts()).thenReturn(guts);
+        StatusBarNotification notification = spy(realRow.getStatusBarNotification());
+        when(row.getStatusBarNotification()).thenReturn(notification);
+
+        assertTrue(gutsManager.openGuts(row, 0, 0, menuItem));
+
+        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+        verify(notification).getLogMaker();
+        verify(mMetricsLogger).write(logMakerCaptor.capture());
+        assertEquals(MetricsProto.MetricsEvent.ACTION_NOTE_CONTROLS,
+                logMakerCaptor.getValue().getCategory());
+        assertEquals(MetricsProto.MetricsEvent.TYPE_ACTION,
+                logMakerCaptor.getValue().getType());
+    }
+
+    @Test
     public void testAppOpsSettingsIntent_camera() {
         ArraySet<Integer> ops = new ArraySet<>();
         ops.add(OP_CAMERA);
@@ -443,7 +476,7 @@
         NotificationGuts guts = new NotificationGuts(mContext);
         ExpandableNotificationRow row = spy(createTestNotificationRow());
         doReturn(guts).when(row).getGuts();
-        NotificationData.Entry entry = row.getEntry();
+        NotificationEntry entry = row.getEntry();
         entry.setRow(row);
         mGutsManager.setExposedGuts(guts);
 
@@ -452,7 +485,7 @@
 
     @Test
     public void testSetShouldManageLifetime_setShouldManage() {
-        NotificationData.Entry entry = createTestNotificationRow().getEntry();
+        NotificationEntry entry = createTestNotificationRow().getEntry();
         mGutsManager.setShouldManageLifetime(entry, true /* shouldManage */);
 
         assertTrue(entry.key.equals(mGutsManager.mKeyToRemoveOnGutsClosed));
@@ -460,7 +493,7 @@
 
     @Test
     public void testSetShouldManageLifetime_setShouldNotManage() {
-        NotificationData.Entry entry = createTestNotificationRow().getEntry();
+        NotificationEntry entry = createTestNotificationRow().getEntry();
         mGutsManager.mKeyToRemoveOnGutsClosed = entry.key;
         mGutsManager.setShouldManageLifetime(entry, false /* shouldManage */);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
index d6b706d..648df3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInflaterTest.java
@@ -48,7 +48,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.InflationTask;
 import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -88,7 +88,7 @@
             }
 
             @Override
-            public void onAsyncInflationFinished(NotificationData.Entry entry,
+            public void onAsyncInflationFinished(NotificationEntry entry,
                     @NotificationInflater.InflationFlag int inflatedFlags) {
             }
         });
@@ -174,7 +174,7 @@
                     }
 
                     @Override
-                    public void onAsyncInflationFinished(NotificationData.Entry entry,
+                    public void onAsyncInflationFinished(NotificationEntry entry,
                             @NotificationInflater.InflationFlag int inflatedFlags) {
                         countDownLatch.countDown();
                     }
@@ -256,7 +256,7 @@
             }
 
             @Override
-            public void onAsyncInflationFinished(NotificationData.Entry entry,
+            public void onAsyncInflationFinished(NotificationEntry entry,
                     @NotificationInflater.InflationFlag int inflatedFlags) {
                 if (expectingException) {
                     exceptionHolder.setException(new RuntimeException(
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 ecb0cf8..f6791dd5 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
@@ -45,7 +45,6 @@
 import static org.mockito.Mockito.spy;
 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.app.INotificationManager;
@@ -73,6 +72,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
@@ -498,12 +498,15 @@
     }
 
     @Test
-    public void testLogBlockingHelperCounter_doesntLogForNormalGutsView() throws Exception {
+    public void testLogBlockingHelperCounter_logGutsViewDisplayed() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
                 IMPORTANCE_DEFAULT);
         mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
-        verifyZeroInteractions(mMetricsLogger);
+        verify(mMetricsLogger).write(argThat(logMaker ->
+                logMaker.getType() == MetricsEvent.NOTIFICATION_BLOCKING_HELPER
+                        && logMaker.getSubtype() == MetricsEvent.BLOCKING_HELPER_DISPLAY
+        ));
     }
 
     @Test
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 e4d0196..04d7509 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
@@ -35,7 +35,7 @@
 import android.view.ViewGroup;
 
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 
 import org.junit.Before;
@@ -54,7 +54,7 @@
     public void setup() {
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
         mRow = mock(ExpandableNotificationRow.class);
-        NotificationData.Entry entry = new NotificationData.Entry(
+        NotificationEntry entry = new NotificationEntry(
                 mock(StatusBarNotification.class));
         entry.channel = mock(NotificationChannel.class);
         when(mRow.getEntry()).thenReturn(entry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
index 8ae7d52..ff30a4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
@@ -29,7 +29,10 @@
 import android.testing.TestableLooper.RunWithLooper;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 
@@ -37,6 +40,8 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.util.HashSet;
 
@@ -45,14 +50,18 @@
 @RunWithLooper
 public class NotificationRoundnessManagerTest extends SysuiTestCase {
 
-    private NotificationRoundnessManager mRoundnessManager = new NotificationRoundnessManager();
+    private NotificationRoundnessManager mRoundnessManager;
     private HashSet<ExpandableView> mAnimatedChildren = new HashSet<>();
     private Runnable mRoundnessCallback = mock(Runnable.class);
     private ExpandableNotificationRow mFirst;
     private ExpandableNotificationRow mSecond;
+    @Mock
+    private AmbientPulseManager mAmbientPulseManager;
 
     @Before
     public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mRoundnessManager = new NotificationRoundnessManager(mAmbientPulseManager);
         com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
         NotificationTestHelper testHelper = new NotificationTestHelper(getContext());
         mFirst = testHelper.createRow();
@@ -127,6 +136,27 @@
     }
 
     @Test
+    public void testRoundnessPulsing() throws Exception {
+        // Let's create a notification that's neither the first or last item of the stack,
+        // this way we'll ensure that it won't have any rounded corners by default.
+        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
+                createSection(mFirst, mSecond),
+                createSection(null, null)
+        });
+        ExpandableNotificationRow row = new NotificationTestHelper(getContext()).createRow();
+        NotificationEntry entry = mock(NotificationEntry.class);
+        when(entry.getRow()).thenReturn(row);
+
+        mRoundnessManager.onAmbientStateChanged(entry, true);
+        Assert.assertEquals(1f, row.getCurrentBottomRoundness(), 0.0f);
+        Assert.assertEquals(1f, row.getCurrentTopRoundness(), 0.0f);
+
+        mRoundnessManager.onAmbientStateChanged(entry, false);
+        Assert.assertEquals(0f, row.getCurrentBottomRoundness(), 0.0f);
+        Assert.assertEquals(0f, row.getCurrentTopRoundness(), 0.0f);
+    }
+
+    @Test
     public void testRoundnessSetOnSecondSectionLast() {
         mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
                 createSection(mFirst, mFirst),
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 b8c7ee0..736f384 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
@@ -24,6 +24,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.atLeastOnce;
@@ -35,22 +36,21 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.os.Handler;
-import android.os.IPowerManager;
-import android.os.Looper;
-import android.os.PowerManager;
+import android.metrics.LogMaker;
 import android.provider.Settings;
-import android.service.dreams.IDreamManager;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.systemui.Dependency;
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -58,9 +58,9 @@
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.FooterView;
 import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -78,6 +78,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
@@ -91,7 +92,8 @@
 @RunWith(AndroidJUnit4.class)
 public class NotificationStackScrollLayoutTest extends SysuiTestCase {
 
-    private NotificationStackScrollLayout mStackScroller;
+    private NotificationStackScrollLayout mStackScroller;  // Normally test this
+    private NotificationStackScrollLayout mStackScrollerInternal;  // See explanation below
 
     @Rule public MockitoRule mockito = MockitoJUnit.rule();
     @Mock private StatusBar mBar;
@@ -104,11 +106,12 @@
     @Mock private NotificationData mNotificationData;
     @Mock private NotificationRemoteInputManager mRemoteInputManager;
     @Mock private RemoteInputController mRemoteInputController;
-    @Mock private IDreamManager mDreamManager;
-    private PowerManager mPowerManager;
+    @Mock private MetricsLogger mMetricsLogger;
+    @Mock private NotificationRoundnessManager mNotificationRoundnessManager;
     private TestableNotificationEntryManager mEntryManager;
     private int mOriginalInterruptionModelSetting;
 
+
     @Before
     @UiThreadTest
     public void setUp() throws Exception {
@@ -117,17 +120,13 @@
                 NotificationBlockingHelperManager.class,
                 mBlockingHelperManager);
         mDependency.injectTestDependency(StatusBarStateController.class, mBarState);
+        mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
         mDependency.injectTestDependency(NotificationRemoteInputManager.class,
                 mRemoteInputManager);
         mDependency.injectMockDependency(ShadeController.class);
         when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
 
-        IPowerManager powerManagerService = mock(IPowerManager.class);
-        mPowerManager = new PowerManager(mContext, powerManagerService,
-                Handler.createAsync(Looper.myLooper()));
-
-        mEntryManager = new TestableNotificationEntryManager(mPowerManager,
-                mContext);
+        mEntryManager = new TestableNotificationEntryManager(mContext);
         mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
         Dependency.get(InitController.class).executePostInitTasks();
         mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager,
@@ -135,7 +134,15 @@
 
 
         NotificationShelf notificationShelf = mock(NotificationShelf.class);
-        mStackScroller = spy(new NotificationStackScrollLayout(getContext()));
+
+        // The actual class under test.  You may need to work with this class directly when
+        // testing anonymous class members of mStackScroller, like mMenuEventListener,
+        // which refer to members of NotificationStackScrollLayout. The spy
+        // holds a copy of the CUT's instances of these classes, so they still refer to the CUT's
+        // member variables, not the spy's member variables.
+        mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null,
+                true /* allowLongPress */, mNotificationRoundnessManager);
+        mStackScroller = spy(mStackScrollerInternal);
         mStackScroller.setShelf(notificationShelf);
         mStackScroller.setStatusBar(mBar);
         mStackScroller.setScrimController(mock(ScrimController.class));
@@ -153,6 +160,7 @@
         doNothing().when(mGroupManager).collapseAllGroups();
         doNothing().when(mExpandHelper).cancelImmediately();
         doNothing().when(notificationShelf).setAnimationsEnabled(anyBoolean());
+        doNothing().when(notificationShelf).fadeInTranslating();
 
         mOriginalInterruptionModelSetting = Settings.Secure.getInt(mContext.getContentResolver(),
                 NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
@@ -276,8 +284,8 @@
     @Test
     public void testUpdateFooter_remoteInput() {
         setBarStateForTest(StatusBarState.SHADE);
-        ArrayList<Entry> entries = new ArrayList<>();
-        entries.add(mock(Entry.class));
+        ArrayList<NotificationEntry> entries = new ArrayList<>();
+        entries.add(mock(NotificationEntry.class));
         when(mNotificationData.getActiveNotifications()).thenReturn(entries);
 
         ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
@@ -293,8 +301,8 @@
     @Test
     public void testUpdateFooter_oneClearableNotification() {
         setBarStateForTest(StatusBarState.SHADE);
-        ArrayList<Entry> entries = new ArrayList<>();
-        entries.add(mock(Entry.class));
+        ArrayList<NotificationEntry> entries = new ArrayList<>();
+        entries.add(mock(NotificationEntry.class));
         when(mNotificationData.getActiveNotifications()).thenReturn(entries);
 
         ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
@@ -309,8 +317,8 @@
     @Test
     public void testUpdateFooter_oneNonClearableNotification() {
         setBarStateForTest(StatusBarState.SHADE);
-        ArrayList<Entry> entries = new ArrayList<>();
-        entries.add(mock(Entry.class));
+        ArrayList<NotificationEntry> entries = new ArrayList<>();
+        entries.add(mock(NotificationEntry.class));
         when(mEntryManager.getNotificationData().getActiveNotifications()).thenReturn(entries);
         assertTrue(mEntryManager.getNotificationData().getActiveNotifications().size() != 0);
 
@@ -325,7 +333,7 @@
 
         // add notification
         ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
-        NotificationData.Entry entry = mock(NotificationData.Entry.class);
+        NotificationEntry entry = mock(NotificationEntry.class);
         when(row.getEntry()).thenReturn(entry);
         when(entry.isClearable()).thenReturn(true);
         mStackScroller.addContainerView(row);
@@ -432,6 +440,63 @@
         assertNull(swipeActionHelper.getExposedMenuView());
     }
 
+    class LogMatcher implements ArgumentMatcher<LogMaker> {
+        private int mCategory, mType;
+
+        LogMatcher(int category, int type) {
+            mCategory = category;
+            mType = type;
+        }
+        public boolean matches(LogMaker l) {
+            return (l.getCategory() == mCategory)
+                    && (l.getType() == mType);
+        }
+
+        public String toString() {
+            return String.format("LogMaker(%d, %d)", mCategory, mType);
+        }
+    }
+
+    private LogMaker logMatcher(int category, int type) {
+        return argThat(new LogMatcher(category, type));
+    }
+
+    @Test
+    @UiThreadTest
+    public void testOnMenuClickedLogging() {
+        // Set up the object under test to have a valid mLongPressListener.  We're testing an
+        // anonymous-class member, mMenuEventListener, so we need to modify the state of the
+        // class itself, not the Mockito spy copied from it.  See notes in setup.
+        mStackScrollerInternal.setLongPressListener(
+                mock(ExpandableNotificationRow.LongPressListener.class));
+
+        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
+        when(row.getStatusBarNotification().getLogMaker()).thenReturn(new LogMaker(
+                MetricsProto.MetricsEvent.VIEW_UNKNOWN));
+
+        mStackScroller.mMenuEventListener.onMenuClicked(row, 0, 0, mock(
+                NotificationMenuRowPlugin.MenuItem.class));
+        verify(row.getStatusBarNotification()).getLogMaker();  // This writes most of the log data
+        verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR,
+                MetricsProto.MetricsEvent.TYPE_ACTION));
+    }
+
+    @Test
+    @UiThreadTest
+    public void testOnMenuShownLogging() {
+        // Set up the object under test to have a valid mHeadsUpManager. See notes in setup.
+        mStackScrollerInternal.setHeadsUpManager(mHeadsUpManager);
+
+        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
+        when(row.getStatusBarNotification().getLogMaker()).thenReturn(new LogMaker(
+                MetricsProto.MetricsEvent.VIEW_UNKNOWN));
+
+        mStackScroller.mMenuEventListener.onMenuShown(row);
+        verify(row.getStatusBarNotification()).getLogMaker();  // This writes most of the log data
+        verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR,
+                MetricsProto.MetricsEvent.TYPE_ACTION));
+    }
+
     private void setBarStateForTest(int state) {
         // Can't inject this through the listener or we end up on the actual implementation
         // rather than the mock because the spy just coppied the anonymous inner /shruggie.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 1481aef..c0f7f0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
@@ -30,6 +31,8 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.HotspotController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -51,7 +54,11 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mAutoTileManager = new AutoTileManager(mContext, mAutoAddTracker, mQsTileHost,
-                Handler.createAsync(TestableLooper.get(this).getLooper()));
+                Handler.createAsync(TestableLooper.get(this).getLooper()),
+                mock(HotspotController.class),
+                mock(DataSaverController.class),
+                mock(ManagedProfileController.class),
+                mock(ColorDisplayController.class));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index d99e46d..a72be7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.atLeast;
@@ -55,13 +57,15 @@
     @Before
     public void setup() {
         mSysuiContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
-        mSysuiContext.putComponent(StatusBar.class, mock(StatusBar.class));
+        StatusBar statusBar = mock(StatusBar.class);
+        mSysuiContext.putComponent(StatusBar.class, statusBar);
         mSysuiContext.putComponent(TunerService.class, mock(TunerService.class));
         mStatusBarStateController = mDependency
                 .injectMockDependency(StatusBarStateController.class);
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
         mMockNotificiationAreaController = mock(NotificationIconAreaController.class);
         mNotificationAreaInner = mock(View.class);
+        when(statusBar.getPanel()).thenReturn(mock(NotificationPanelView.class));
         when(mNotificationAreaInner.animate()).thenReturn(mock(ViewPropertyAnimator.class));
         when(mMockNotificiationAreaController.getNotificationInnerAreaView()).thenReturn(
                 mNotificationAreaInner);
@@ -74,7 +78,7 @@
 
         CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
         fragment.initNotificationIconArea(mMockNotificiationAreaController);
-        fragment.disable(0, 0, false);
+        fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
 
         assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
                 .getVisibility());
@@ -89,12 +93,12 @@
 
         CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
         fragment.initNotificationIconArea(mMockNotificiationAreaController);
-        fragment.disable(StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
+        fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
 
         assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
                 .getVisibility());
 
-        fragment.disable(0, 0, false);
+        fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
 
         assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
                 .getVisibility());
@@ -107,11 +111,11 @@
 
         CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
         fragment.initNotificationIconArea(mMockNotificiationAreaController);
-        fragment.disable(StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
+        fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
 
         Mockito.verify(mNotificationAreaInner).setVisibility(eq(View.INVISIBLE));
 
-        fragment.disable(0, 0, false);
+        fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
 
         Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
     }
@@ -123,11 +127,11 @@
 
         CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
         fragment.initNotificationIconArea(mMockNotificiationAreaController);
-        fragment.disable(StatusBarManager.DISABLE_CLOCK, 0, false);
+        fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false);
 
         assertEquals(View.GONE, mFragment.getView().findViewById(R.id.clock).getVisibility());
 
-        fragment.disable(0, 0, false);
+        fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
 
         assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.clock).getVisibility());
     }
@@ -139,7 +143,7 @@
 
         CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
         fragment.initNotificationIconArea(mMockNotificiationAreaController);
-        fragment.disable(StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
+        fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
 
         Mockito.verify(mNotificationAreaInner).setVisibility(eq(View.INVISIBLE));
 
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 44deb10..9ceb325 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
@@ -16,15 +16,20 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.view.View;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.when;
+
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.view.View;
 
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.AlertingNotificationManagerTest;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -34,11 +39,6 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.assertFalse;
-
-import static org.mockito.Mockito.when;
-
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -96,7 +96,7 @@
 
     @Test
     public void testCanRemoveImmediately_notTopEntry() {
-        NotificationData.Entry laterEntry = new NotificationData.Entry(createNewNotification(1));
+        NotificationEntry laterEntry = new NotificationEntry(createNewNotification(1));
         laterEntry.setRow(mRow);
         mHeadsUpManager.showNotification(mEntry);
         mHeadsUpManager.showNotification(laterEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 27ed9c5..cd52e87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -47,7 +47,6 @@
     private float mPanelExpansion;
     private int mKeyguardStatusHeight;
     private float mDark;
-    private boolean mPulsing;
 
     @Before
     public void setUp() {
@@ -208,20 +207,6 @@
     }
 
     @Test
-    public void notifPositionWhilePulsingOnAOD() {
-        // GIVEN on AOD and pulsing
-        givenAOD();
-        mNotificationStackHeight = EMPTY_HEIGHT;
-        mKeyguardStatusHeight = EMPTY_HEIGHT;
-        mPulsing = true;
-        mClockPositionAlgorithm.setPulsingPadding(200);
-        // WHEN the clock position algorithm is run
-        positionClock();
-        // THEN the notif padding doesn't adjust for pulsing.
-        assertThat(mClockPosition.stackScrollerPadding).isEqualTo(1000);
-    }
-
-    @Test
     public void notifPositionMiddleOfScreenOnLockScreen() {
         // GIVEN on lock screen and both stack scroll and clock have 0 height
         givenLockScreen();
@@ -307,20 +292,6 @@
         assertThat(mClockPosition.stackScrollerPadding).isEqualTo(0);
     }
 
-    @Test
-    public void notifPositionWhilePulsingOnLockScreen() {
-        // GIVEN on lock screen and pulsing
-        givenLockScreen();
-        mNotificationStackHeight = EMPTY_HEIGHT;
-        mKeyguardStatusHeight = EMPTY_HEIGHT;
-        mPulsing = true;
-        mClockPositionAlgorithm.setPulsingPadding(200);
-        // WHEN the clock position algorithm is run
-        positionClock();
-        // THEN the notif padding adjusts for pulsing.
-        assertThat(mClockPosition.stackScrollerPadding).isEqualTo(1200);
-    }
-
     private void givenAOD() {
         mPanelExpansion = 1.f;
         mDark = 1.f;
@@ -334,7 +305,7 @@
     private void positionClock() {
         mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight,
                 mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, mDark, SECURE_LOCKED,
-                mPulsing, ZERO_DRAG);
+                ZERO_DRAG);
         mClockPositionAlgorithm.run(mClockPosition);
     }
 }
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 667a508..4dee438 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
@@ -17,7 +17,6 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -171,6 +170,19 @@
         ev.recycle();
     }
 
+    @Test
+    public void testViewNotAttachedNoCrash() {
+        View view = mockViewAt(0, 20, 10, 10);
+        when(view.isAttachedToWindow()).thenReturn(false);
+        mNearestTouchFrame.addView(view);
+        mNearestTouchFrame.onMeasure(0, 0);
+
+        MotionEvent ev = MotionEvent.obtain(0, 0, 0, 5 /* x */, 18 /* y */, 0);
+        mNearestTouchFrame.onTouchEvent(ev);
+        verify(view, never()).onTouchEvent(eq(ev));
+        ev.recycle();
+    }
+
     private View mockViewAt(int x, int y, int width, int height) {
         View v = spy(new View(mContext));
         doAnswer(invocation -> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index 56af400..cefd4ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -32,10 +32,9 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.AmbientPulseManager;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import org.junit.Before;
@@ -64,7 +63,7 @@
     @Captor
     private ArgumentCaptor<NotificationEntryListener> mListenerCaptor;
     private NotificationEntryListener mNotificationEntryListener;
-    private final HashMap<String, Entry> mPendingEntries = new HashMap<>();
+    private final HashMap<String, NotificationEntry> mPendingEntries = new HashMap<>();
     private final NotificationGroupTestHelper mGroupTestHelper =
             new NotificationGroupTestHelper(mContext);
 
@@ -94,9 +93,9 @@
 
     @Test
     public void testSuppressedSummaryHeadsUpTransfersToChild() {
-        Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
         mHeadsUpManager.showNotification(summaryEntry);
-        Entry childEntry = mGroupTestHelper.createChildNotification();
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
 
         // Summary will be suppressed because there is only one child.
         mGroupManager.onEntryAdded(summaryEntry);
@@ -109,11 +108,11 @@
 
     @Test
     public void testSuppressedSummaryHeadsUpTransfersToChildButBackAgain() {
-        NotificationData.Entry summaryEntry =
+        NotificationEntry summaryEntry =
                 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationData.Entry childEntry =
+        NotificationEntry childEntry =
                 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationData.Entry childEntry2 =
+        NotificationEntry childEntry2 =
                 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
         mHeadsUpManager.showNotification(summaryEntry);
         // Trigger a transfer of alert state from summary to child.
@@ -133,11 +132,11 @@
 
     @Test
     public void testSuppressedSummaryHeadsUpDoesntTransferBackOnDozingChanged() {
-        NotificationData.Entry summaryEntry =
+        NotificationEntry summaryEntry =
                 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationData.Entry childEntry =
+        NotificationEntry childEntry =
                 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationData.Entry childEntry2 =
+        NotificationEntry childEntry2 =
                 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
         mHeadsUpManager.showNotification(summaryEntry);
         // Trigger a transfer of alert state from summary to child.
@@ -158,9 +157,9 @@
 
     @Test
     public void testSuppressedSummaryHeadsUpTransferDoesNotAlertChildIfUninflated() {
-        Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
         mHeadsUpManager.showNotification(summaryEntry);
-        Entry childEntry = mGroupTestHelper.createChildNotification();
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
         when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
             .thenReturn(false);
 
@@ -176,9 +175,9 @@
 
     @Test
     public void testSuppressedSummaryHeadsUpTransferAlertsChildOnInflation() {
-        Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
         mHeadsUpManager.showNotification(summaryEntry);
-        Entry childEntry = mGroupTestHelper.createChildNotification();
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
         when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
             .thenReturn(false);
 
@@ -196,13 +195,13 @@
 
     @Test
     public void testSuppressedSummaryHeadsUpTransferBackAbortsChildInflation() {
-        NotificationData.Entry summaryEntry =
+        NotificationEntry summaryEntry =
                 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationData.Entry childEntry =
+        NotificationEntry childEntry =
                 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
         when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
             .thenReturn(false);
-        NotificationData.Entry childEntry2 =
+        NotificationEntry childEntry2 =
                 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
         mHeadsUpManager.showNotification(summaryEntry);
         // Trigger a transfer of alert state from summary to child.
@@ -226,9 +225,9 @@
 
     @Test
     public void testCleanUpPendingAlertInfo() {
-        NotificationData.Entry summaryEntry =
+        NotificationEntry summaryEntry =
                 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationData.Entry childEntry =
+        NotificationEntry childEntry =
                 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
         when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
             .thenReturn(false);
@@ -237,17 +236,16 @@
         mGroupManager.onEntryAdded(summaryEntry);
         mGroupManager.onEntryAdded(childEntry);
 
-        mNotificationEntryListener.onEntryRemoved(childEntry, childEntry.key, null, null,
-                false, false);
+        mNotificationEntryListener.onEntryRemoved(childEntry, null, false);
 
         assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
     }
 
     @Test
     public void testUpdateGroupChangeDoesNotTransfer() {
-        NotificationData.Entry summaryEntry =
+        NotificationEntry summaryEntry =
                 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationData.Entry childEntry =
+        NotificationEntry childEntry =
                 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
         when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
             .thenReturn(false);
@@ -268,9 +266,9 @@
 
     @Test
     public void testUpdateChildToSummaryDoesNotTransfer() {
-        NotificationData.Entry summaryEntry =
+        NotificationEntry summaryEntry =
                 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
-        NotificationData.Entry childEntry =
+        NotificationEntry childEntry =
                 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
         when(childEntry.getRow().isInflationFlagSet(mHeadsUpManager.getContentFlag()))
             .thenReturn(false);
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
index b0bd1fb..ecb3e4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerTest.java
@@ -29,7 +29,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.AmbientPulseManager;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import org.junit.Before;
@@ -69,8 +69,8 @@
 
     @Test
     public void testIsOnlyChildInGroup() {
-        NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
 
         mGroupManager.onEntryAdded(summaryEntry);
         mGroupManager.onEntryAdded(childEntry);
@@ -80,8 +80,8 @@
 
     @Test
     public void testIsChildInGroupWithSummary() {
-        NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
 
         mGroupManager.onEntryAdded(summaryEntry);
         mGroupManager.onEntryAdded(childEntry);
@@ -92,8 +92,8 @@
 
     @Test
     public void testIsSummaryOfGroupWithChildren() {
-        NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
 
         mGroupManager.onEntryAdded(summaryEntry);
         mGroupManager.onEntryAdded(childEntry);
@@ -105,8 +105,8 @@
 
     @Test
     public void testRemoveChildFromGroupWithSummary() {
-        NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
         mGroupManager.onEntryAdded(summaryEntry);
         mGroupManager.onEntryAdded(childEntry);
         mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
@@ -118,8 +118,8 @@
 
     @Test
     public void testRemoveSummaryFromGroupWithSummary() {
-        NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
         mGroupManager.onEntryAdded(summaryEntry);
         mGroupManager.onEntryAdded(childEntry);
         mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
@@ -132,8 +132,8 @@
 
     @Test
     public void testHeadsUpEntryIsIsolated() {
-        NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
         mGroupManager.onEntryAdded(summaryEntry);
         mGroupManager.onEntryAdded(childEntry);
         mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
@@ -149,8 +149,8 @@
 
     @Test
     public void testAmbientPulseEntryIsIsolated() {
-        NotificationData.Entry childEntry = mGroupTestHelper.createChildNotification();
-        NotificationData.Entry summaryEntry = mGroupTestHelper.createSummaryNotification();
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
         mGroupManager.onEntryAdded(summaryEntry);
         mGroupManager.onEntryAdded(childEntry);
         mGroupManager.onEntryAdded(mGroupTestHelper.createChildNotification());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
index 7ad68eb..e6b9778 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
@@ -27,7 +27,7 @@
 import android.service.notification.StatusBarNotification;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
 /**
@@ -44,23 +44,23 @@
         mContext = context;
     }
 
-    public NotificationData.Entry createSummaryNotification() {
+    public NotificationEntry createSummaryNotification() {
         return createSummaryNotification(Notification.GROUP_ALERT_ALL);
     }
 
-    public NotificationData.Entry createSummaryNotification(int groupAlertBehavior) {
+    public NotificationEntry createSummaryNotification(int groupAlertBehavior) {
         return createEntry(true, groupAlertBehavior);
     }
 
-    public NotificationData.Entry createChildNotification() {
+    public NotificationEntry createChildNotification() {
         return createChildNotification(Notification.GROUP_ALERT_ALL);
     }
 
-    public NotificationData.Entry createChildNotification(int groupAlertBehavior) {
+    public NotificationEntry createChildNotification(int groupAlertBehavior) {
         return createEntry(false, groupAlertBehavior);
     }
 
-    public NotificationData.Entry createEntry(boolean isSummary, int groupAlertBehavior) {
+    public NotificationEntry createEntry(boolean isSummary, int groupAlertBehavior) {
         Notification notif = new Notification.Builder(mContext, TEST_CHANNEL_ID)
                 .setContentTitle("Title")
                 .setSmallIcon(R.drawable.ic_person)
@@ -79,7 +79,7 @@
                 new UserHandle(ActivityManager.getCurrentUser()),
                 null /* overrideGroupKey */,
                 0 /* postTime */);
-        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        NotificationEntry entry = new NotificationEntry(sbn);
         ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
         entry.setRow(row);
         when(row.getEntry()).thenReturn(entry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
new file mode 100644
index 0000000..b7b95ef
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.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 com.android.systemui.statusbar.phone;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.keyguard.KeyguardStatusView;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationPanelViewTest extends SysuiTestCase {
+
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private NotificationStackScrollLayout mNotificationStackScrollLayout;
+    @Mock
+    private KeyguardStatusView mKeyguardStatusView;
+    private NotificationPanelView mNotificationPanelView;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mDependency.injectTestDependency(StatusBarStateController.class,
+                mStatusBarStateController);
+        mDependency.injectMockDependency(ShadeController.class);
+        mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
+        mDependency.injectMockDependency(ConfigurationController.class);
+        mDependency.injectMockDependency(ZenModeController.class);
+        mNotificationPanelView = new TestableNotificationPanelView();
+    }
+
+    @Test
+    public void testSetDozing_notifiesNsslAndStateController() {
+        mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
+        InOrder inOrder = inOrder(mNotificationStackScrollLayout, mStatusBarStateController);
+        inOrder.verify(mNotificationStackScrollLayout).setDark(eq(true), eq(true), eq(null));
+        inOrder.verify(mNotificationStackScrollLayout).setShowDarkShelf(eq(true));
+        inOrder.verify(mStatusBarStateController).setDozeAmount(eq(1f), eq(true));
+    }
+
+    @Test
+    public void testSetDozing_showsDarkShelfWithDefaultClock() {
+        when(mKeyguardStatusView.hasCustomClock()).thenReturn(false);
+        mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
+        verify(mNotificationStackScrollLayout).setShowDarkShelf(eq(true));
+    }
+
+    @Test
+    public void testSetDozing_hidesDarkShelfWhenCustomClock() {
+        when(mKeyguardStatusView.hasCustomClock()).thenReturn(true);
+        mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
+        verify(mNotificationStackScrollLayout).setShowDarkShelf(eq(false));
+    }
+
+    private class TestableNotificationPanelView extends NotificationPanelView {
+        TestableNotificationPanelView() {
+            super(NotificationPanelViewTest.this.mContext, null);
+            mNotificationStackScroller = mNotificationStackScrollLayout;
+            mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
index 2805908..382dde9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
@@ -97,6 +97,7 @@
         doReturn(HIT_TARGET_NONE).when(mNavigationBarView).getDownHitTarget();
         doReturn(backButton).when(mNavigationBarView).getBackButton();
         doReturn(mResources).when(mNavigationBarView).getResources();
+        doReturn(mContext).when(mNavigationBarView).getContext();
 
         mController = new QuickStepController(mContext);
         mController.setComponents(mNavigationBarView);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 146c5d6..c20d37f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -45,6 +45,7 @@
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
 import com.android.internal.util.function.TriConsumer;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.doze.DozeLog;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.util.wakelock.WakeLock;
 import com.android.systemui.utils.os.FakeHandler;
@@ -54,7 +55,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.function.Consumer;
 
@@ -94,6 +95,7 @@
                 },
                 visible -> mScrimVisibility = visible, mDozeParamenters, mAlarmManager);
         mScrimController.setHasBackdrop(false);
+        mScrimController.setWallpaperSupportsAmbientMode(false);
     }
 
     @Test
@@ -132,7 +134,8 @@
         // Back scrim should be transparent
         assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT);
 
-        // Move on to PULSING and check if the back scrim is still transparent
+        // Pulsing notification should conserve AOD wallpaper.
+        mScrimController.setPulseReason(DozeLog.PULSE_REASON_NOTIFICATION);
         mScrimController.transitionTo(ScrimState.PULSING);
         mScrimController.finishAnimationsImmediately();
         assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT);
@@ -217,13 +220,14 @@
         mScrimController.finishAnimationsImmediately();
         assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
 
+        mScrimController.setPulseReason(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN);
         mScrimController.transitionTo(ScrimState.PULSING);
         mScrimController.finishAnimationsImmediately();
         // Front scrim should be transparent
         // Back scrim should be semi-transparent so the user can see the wallpaper
         // Pulse callback should have been invoked
         assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
-        assertScrimTint(mScrimBehind, true /* tinted */);
+        assertScrimTint(mScrimBehind, false /* tinted */);
     }
 
     @Test
@@ -474,6 +478,21 @@
     }
 
     @Test
+    public void testHoldsPulsingWallpaperAnimationLock() {
+        // Pre-conditions
+        mScrimController.setPulseReason(DozeLog.PULSE_REASON_NOTIFICATION);
+        mScrimController.transitionTo(ScrimState.PULSING);
+        mScrimController.finishAnimationsImmediately();
+        reset(mWakeLock);
+
+        mScrimController.onHideWallpaperTimeout();
+        verify(mWakeLock).acquire();
+        verify(mWakeLock, never()).release();
+        mScrimController.finishAnimationsImmediately();
+        verify(mWakeLock).release();
+    }
+
+    @Test
     public void testWillHideAodWallpaper() {
         mScrimController.setWallpaperSupportsAmbientMode(true);
         mScrimController.transitionTo(ScrimState.AOD);
@@ -483,6 +502,30 @@
     }
 
     @Test
+    public void testWillHidePulsingWallpaper_whenNotification() {
+        mScrimController.setWallpaperSupportsAmbientMode(false);
+        mScrimController.transitionTo(ScrimState.AOD);
+        mScrimController.finishAnimationsImmediately();
+        mScrimController.setPulseReason(DozeLog.PULSE_REASON_NOTIFICATION);
+        mScrimController.transitionTo(ScrimState.PULSING);
+        mScrimController.finishAnimationsImmediately();
+        assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
+        assertScrimTint(mScrimBehind, true);
+    }
+
+    @Test
+    public void testWillHidePulsingWallpaper_whenDocking() {
+        mScrimController.setWallpaperSupportsAmbientMode(false);
+        mScrimController.transitionTo(ScrimState.AOD);
+        mScrimController.finishAnimationsImmediately();
+        mScrimController.setPulseReason(DozeLog.PULSE_REASON_DOCKING);
+        mScrimController.transitionTo(ScrimState.PULSING);
+        mScrimController.finishAnimationsImmediately();
+        assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
+        assertScrimTint(mScrimBehind, true);
+    }
+
+    @Test
     public void testConservesExpansionOpacityAfterTransition() {
         mScrimController.transitionTo(ScrimState.UNLOCKED);
         mScrimController.setPanelExpansion(0.5f);
@@ -511,34 +554,6 @@
         Assert.assertTrue(mScrimController.wasAnimationJustCancelled());
     }
 
-    /**
-     * Number of visible notifications affects scrim opacity.
-     */
-    @Test
-    public void testNotificationDensity() {
-        mScrimController.transitionTo(ScrimState.KEYGUARD);
-        mScrimController.finishAnimationsImmediately();
-
-        mScrimController.setNotificationCount(0);
-        mScrimController.finishAnimationsImmediately();
-        Assert.assertEquals("lower density when no notifications",
-                ScrimController.GRADIENT_SCRIM_ALPHA,  mScrimBehind.getViewAlpha(), 0.01f);
-
-        mScrimController.setNotificationCount(3);
-        mScrimController.finishAnimationsImmediately();
-        Assert.assertEquals("stronger density when notifications are visible",
-                ScrimController.GRADIENT_SCRIM_ALPHA_BUSY,  mScrimBehind.getViewAlpha(), 0.01f);
-    }
-
-    /**
-     * Moving from/to states conserves old notification density.
-     */
-    @Test
-    public void testConservesNotificationDensity() {
-        testConservesNotificationDensity(0 /* count */, ScrimController.GRADIENT_SCRIM_ALPHA);
-        testConservesNotificationDensity(3 /* count */, ScrimController.GRADIENT_SCRIM_ALPHA_BUSY);
-    }
-
     @Test
     public void testScrimFocus() {
         mScrimController.transitionTo(ScrimState.AOD);
@@ -578,7 +593,7 @@
     @Test
     public void testEatsTouchEvent() {
         HashSet<ScrimState> eatsTouches =
-                new HashSet<>(Arrays.asList(ScrimState.AOD, ScrimState.PULSING));
+                new HashSet<>(Collections.singletonList(ScrimState.AOD));
         for (ScrimState state : ScrimState.values()) {
             if (state == ScrimState.UNINITIALIZED) {
                 continue;
@@ -613,24 +628,6 @@
                 mScrimBehind.getDefaultFocusHighlightEnabled());
     }
 
-    /**
-     * Conserves old notification density after leaving state and coming back.
-     *
-     * @param count How many notification.
-     * @param expectedAlpha Expected alpha.
-     */
-    private void testConservesNotificationDensity(int count, float expectedAlpha) {
-        mScrimController.setNotificationCount(count);
-        mScrimController.transitionTo(ScrimState.UNLOCKED);
-        mScrimController.finishAnimationsImmediately();
-
-        mScrimController.transitionTo(ScrimState.KEYGUARD);
-        mScrimController.finishAnimationsImmediately();
-
-        Assert.assertEquals("Doesn't respect notification busyness after transition",
-                expectedAlpha,  mScrimBehind.getViewAlpha(), 0.01f);
-    }
-
     private void assertScrimTint(ScrimView scrimView, boolean tinted) {
         final boolean viewIsTinted = scrimView.getTint() != Color.TRANSPARENT;
         final String name = scrimView == mScrimInFront ? "front" : "back";
@@ -738,5 +735,4 @@
             callback.run();
         }
     }
-
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 4fabe7f..12cb9957 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import static org.junit.Assert.assertFalse;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -38,7 +40,7 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 
@@ -61,7 +63,7 @@
     public void setup() {
         mMetricsLogger = new FakeMetricsLogger();
         mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
-        mCommandQueue = new CommandQueue();
+        mCommandQueue = new CommandQueue(mContext);
         mContext.putComponent(CommandQueue.class, mCommandQueue);
         mDependency.injectTestDependency(ShadeController.class, mShadeController);
 
@@ -80,8 +82,9 @@
         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);
-        mCommandQueue.disable(StatusBarManager.DISABLE_EXPAND, 0, false /* animate */);
+        NotificationEntry entry = new NotificationEntry(sbn);
+        mCommandQueue.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_EXPAND, 0,
+                false /* animate */);
         TestableLooper.get(this).processAllMessages();
 
         assertFalse("The panel shouldn't allow heads up while disabled",
@@ -93,8 +96,9 @@
         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);
-        mCommandQueue.disable(0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false /* animate */);
+        NotificationEntry entry = new NotificationEntry(sbn);
+        mCommandQueue.disable(DEFAULT_DISPLAY, 0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE,
+                false /* animate */);
         TestableLooper.get(this).processAllMessages();
 
         assertFalse("The panel shouldn't allow heads up while notitifcation shade disabled",
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 18ead90..17611ff 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
@@ -18,6 +18,7 @@
 
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.view.Display.DEFAULT_DISPLAY;
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
@@ -94,13 +95,13 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationData;
-import com.android.systemui.statusbar.notification.NotificationData.Entry;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -134,7 +135,7 @@
     @Mock private IDreamManager mDreamManager;
     @Mock private ScrimController mScrimController;
     @Mock private DozeScrimController mDozeScrimController;
-    @Mock private ArrayList<Entry> mNotificationList;
+    @Mock private ArrayList<NotificationEntry> mNotificationList;
     @Mock private BiometricUnlockController mBiometricUnlockController;
     @Mock private NotificationData mNotificationData;
     @Mock
@@ -158,6 +159,8 @@
     private NotificationFilter mNotificationFilter;
     @Mock
     private NotificationAlertingManager mNotificationAlertingManager;
+    @Mock
+    private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
 
     private TestableStatusBar mStatusBar;
     private FakeMetricsLogger mMetricsLogger;
@@ -204,9 +207,10 @@
 
         mMetricsLogger = new FakeMetricsLogger();
         mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
-        mEntryManager = new TestableNotificationEntryManager(mPowerManager, mContext);
+        mEntryManager = new TestableNotificationEntryManager(mContext);
         mNotificationLogger = new NotificationLogger(mNotificationListener,
-                Dependency.get(UiOffloadThread.class), mEntryManager, mStatusBarStateController);
+                Dependency.get(UiOffloadThread.class), mEntryManager, mStatusBarStateController,
+                mExpansionStateLogger);
         mDependency.injectTestDependency(NotificationLogger.class, mNotificationLogger);
         DozeLog.traceDozing(mContext, false /* dozing */);
 
@@ -247,7 +251,8 @@
                 mock(StatusBarWindowController.class), mock(NotificationIconAreaController.class),
                 mDozeScrimController, mock(NotificationShelf.class),
                 mLockscreenUserManager, mCommandQueue, mNotificationPresenter,
-                mock(BubbleController.class), mock(NavigationBarController.class));
+                mock(BubbleController.class), mock(NavigationBarController.class),
+                mock(AutoHideController.class));
         mStatusBar.mContext = mContext;
         mStatusBar.mComponents = mContext.getComponents();
         SystemUIFactory.getInstance().getRootComponent()
@@ -407,7 +412,7 @@
                 .build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
                 UserHandle.of(0), null, 0);
-        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        NotificationEntry entry = new NotificationEntry(sbn);
         entry.importance = IMPORTANCE_HIGH;
 
         assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
@@ -428,7 +433,7 @@
                 .build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
                 UserHandle.of(0), null, 0);
-        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        NotificationEntry entry = new NotificationEntry(sbn);
         entry.importance = IMPORTANCE_HIGH;
 
         assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
@@ -445,7 +450,7 @@
         Notification n = new Notification.Builder(getContext(), "a").build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
                 UserHandle.of(0), null, 0);
-        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        NotificationEntry entry = new NotificationEntry(sbn);
         entry.suppressedVisualEffects = SUPPRESSED_EFFECT_PEEK;
         entry.importance = IMPORTANCE_HIGH;
 
@@ -463,7 +468,7 @@
         Notification n = new Notification.Builder(getContext(), "a").build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "a", 0, 0, n,
                 UserHandle.of(0), null, 0);
-        NotificationData.Entry entry = new NotificationData.Entry(sbn);
+        NotificationEntry entry = new NotificationEntry(sbn);
         entry.importance = IMPORTANCE_HIGH;
 
         assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
@@ -546,7 +551,7 @@
         when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
 
         when(mCommandQueue.panelsEnabled()).thenReturn(false);
-        mStatusBar.disable(StatusBarManager.DISABLE_NONE,
+        mStatusBar.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
                 StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false);
         verify(mNotificationPanelView).setQsExpansionEnabled(false);
         mStatusBar.animateExpandNotificationsPanel();
@@ -555,7 +560,8 @@
         verify(mNotificationPanelView, never()).expand(anyBoolean());
 
         when(mCommandQueue.panelsEnabled()).thenReturn(true);
-        mStatusBar.disable(StatusBarManager.DISABLE_NONE, StatusBarManager.DISABLE2_NONE, false);
+        mStatusBar.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
+                StatusBarManager.DISABLE2_NONE, false);
         verify(mNotificationPanelView).setQsExpansionEnabled(true);
         mStatusBar.animateExpandNotificationsPanel();
         verify(mNotificationPanelView).expandWithoutQs();
@@ -698,7 +704,8 @@
                 CommandQueue commandQueue,
                 NotificationPresenter notificationPresenter,
                 BubbleController bubbleController,
-                NavigationBarController navBarController) {
+                NavigationBarController navBarController,
+                AutoHideController autoHideController) {
             mStatusBarKeyguardViewManager = man;
             mUnlockMethodCache = unlock;
             mKeyguardIndicationController = key;
@@ -730,6 +737,7 @@
             mGestureWakeLock = mock(PowerManager.WakeLock.class);
             mBubbleController = bubbleController;
             mNavigationBarController = navBarController;
+            mAutoHideController = autoHideController;
         }
 
         private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {
@@ -756,9 +764,8 @@
 
     public static class TestableNotificationEntryManager extends NotificationEntryManager {
 
-        public TestableNotificationEntryManager(PowerManager powerManager, Context context) {
+        public TestableNotificationEntryManager(Context context) {
             super(context);
-            mPowerManager = powerManager;
         }
 
         public void setUpForTest(NotificationPresenter presenter,
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 98d0c6b..9996a9e 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
@@ -95,4 +95,11 @@
     public void testAdd_updatesVisibilityFlags() {
         verify(mStatusBarView).setSystemUiVisibility(anyInt());
     }
+
+    @Test
+    public void testSetForcePluginOpen_beforeStatusBarInitialization() {
+        mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
+                mActivityManager, mDozeParameters);
+        mStatusBarWindowController.setForcePluginOpen(true);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java
deleted file mode 100644
index 5c34730..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.statusbar.policy;
-
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NUM_STATUS_ICONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_ICONS;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
-        .RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS;
-
-import static org.junit.Assert.*;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import static java.lang.Thread.sleep;
-
-import android.metrics.LogMaker;
-import android.support.test.filters.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.MessageHandler;
-import android.testing.TestableLooper.RunWithLooper;
-import android.util.Log;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-@SmallTest
-public class IconLoggerImplTest extends SysuiTestCase {
-
-    private MetricsLogger mMetricsLogger;
-    private IconLoggerImpl mIconLogger;
-    private TestableLooper mTestableLooper;
-    private MessageHandler mMessageHandler;
-
-    @Before
-    public void setup() {
-        IconLoggerImpl.MIN_LOG_INTERVAL = 5; // Low interval for testing
-        mMetricsLogger = mock(MetricsLogger.class);
-        mTestableLooper = TestableLooper.get(this);
-        mMessageHandler = mock(MessageHandler.class);
-        mTestableLooper.setMessageHandler(mMessageHandler);
-        String[] iconArray = new String[] {
-                "test_icon_1",
-                "test_icon_2",
-        };
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.array.config_statusBarIcons, iconArray);
-        mIconLogger = new IconLoggerImpl(mContext, mTestableLooper.getLooper(), mMetricsLogger);
-        when(mMessageHandler.onMessageHandled(any())).thenReturn(true);
-        clearInvocations(mMetricsLogger);
-    }
-
-    @Test
-    public void testIconShown() throws InterruptedException {
-        // Should only get one message, for the same icon shown twice.
-        mIconLogger.onIconShown("test_icon_2");
-        mIconLogger.onIconShown("test_icon_2");
-
-        // There should be some delay before execute.
-        mTestableLooper.processAllMessages();
-        verify(mMessageHandler, never()).onMessageHandled(any());
-
-        sleep(10);
-        mTestableLooper.processAllMessages();
-        verify(mMessageHandler, times(1)).onMessageHandled(any());
-    }
-
-    @Test
-    public void testIconHidden() throws InterruptedException {
-        // Add the icon so that it can be removed.
-        mIconLogger.onIconShown("test_icon_2");
-        sleep(10);
-        mTestableLooper.processAllMessages();
-        clearInvocations(mMessageHandler);
-
-        // Should only get one message, for the same icon shown twice.
-        mIconLogger.onIconHidden("test_icon_2");
-        mIconLogger.onIconHidden("test_icon_2");
-
-        // There should be some delay before execute.
-        mTestableLooper.processAllMessages();
-        verify(mMessageHandler, never()).onMessageHandled(any());
-
-        sleep(10);
-        mTestableLooper.processAllMessages();
-        verify(mMessageHandler, times(1)).onMessageHandled(any());
-    }
-
-    @Test
-    public void testLog() throws InterruptedException {
-        mIconLogger.onIconShown("test_icon_2");
-        sleep(10);
-        mTestableLooper.processAllMessages();
-
-        verify(mMetricsLogger).write(argThat(maker -> {
-            if (IconLoggerImpl.MIN_LOG_INTERVAL >
-                    (long) maker.getTaggedData(RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS)) {
-                Log.e("IconLoggerImplTest", "Invalid latency "
-                        + maker.getTaggedData(RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS));
-                return false;
-            }
-            if (1 != (int) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)) {
-                Log.e("IconLoggerImplTest", "Invalid icon count "
-                        + maker.getTaggedData(FIELD_NUM_STATUS_ICONS));
-                return false;
-            }
-            return true;
-        }));
-    }
-
-    @Test
-    public void testBitField() throws InterruptedException {
-        mIconLogger.onIconShown("test_icon_2");
-        sleep(10);
-        mTestableLooper.processAllMessages();
-
-        verify(mMetricsLogger).write(argThat(maker -> {
-            if ((1 << 1) != (int) maker.getTaggedData(FIELD_STATUS_ICONS)) {
-                Log.e("IconLoggerImplTest", "Invalid bitfield " + Integer.toHexString(
-                        (Integer) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)));
-                return false;
-            }
-            return true;
-        }));
-
-        mIconLogger.onIconShown("test_icon_1");
-        sleep(10);
-        mTestableLooper.processAllMessages();
-
-        verify(mMetricsLogger).write(argThat(maker -> {
-            if ((1 << 1 | 1 << 0) != (int) maker.getTaggedData(FIELD_STATUS_ICONS)) {
-                Log.e("IconLoggerImplTest", "Invalid bitfield " + Integer.toHexString(
-                        (Integer) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)));
-                return false;
-            }
-            return true;
-        }));
-
-        mIconLogger.onIconHidden("test_icon_2");
-        sleep(10);
-        mTestableLooper.processAllMessages();
-
-        verify(mMetricsLogger).write(argThat(maker -> {
-            if ((1 << 0) != (int) maker.getTaggedData(FIELD_STATUS_ICONS)) {
-                Log.e("IconLoggerImplTest", "Invalid bitfield " + Integer.toHexString(
-                        (Integer) maker.getTaggedData(FIELD_STATUS_ICONS)));
-                return false;
-            }
-            return true;
-        }));
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index fdbf090..c1f8885 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -182,6 +182,7 @@
             subs.add(subscription);
         }
         when(mMockSm.getActiveSubscriptionInfoList()).thenReturn(subs);
+        when(mMockSm.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(subs);
         mNetworkController.doUpdateMobileControllers();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
index e3a41be..8b8e3f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
@@ -14,11 +14,11 @@
 
 package com.android.systemui.statusbar.policy;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import static junit.framework.TestCase.assertTrue;
+
 import static org.junit.Assert.assertFalse;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -59,7 +59,7 @@
         mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.TRUE);
         mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.FALSE);
         assertFalse(mRemoteInputQuickSettingsDisabler.mRemoteInputActive);
-        verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+        verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyInt(), anyBoolean());
     }
 
     @Test
@@ -67,7 +67,7 @@
         mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.FALSE);
         mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.TRUE);
         assertTrue(mRemoteInputQuickSettingsDisabler.mRemoteInputActive);
-        verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+        verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyInt(), anyBoolean());
     }
 
     @Test
@@ -78,7 +78,7 @@
         c.orientation = Configuration.ORIENTATION_LANDSCAPE;
         mRemoteInputQuickSettingsDisabler.onConfigChanged(c);
         assertTrue(mRemoteInputQuickSettingsDisabler.misLandscape);
-        verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+        verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyInt(), anyBoolean());
     }
 
     @Test
@@ -89,7 +89,7 @@
         c.orientation = Configuration.ORIENTATION_PORTRAIT;
         mRemoteInputQuickSettingsDisabler.onConfigChanged(c);
         assertFalse(mRemoteInputQuickSettingsDisabler.misLandscape);
-        verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+        verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyInt(), anyBoolean());
     }
 
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index b3ac6be..ed98c62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -15,17 +15,23 @@
 package com.android.systemui.statusbar.policy;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
 
+import android.app.ActivityManager;
 import android.app.PendingIntent;
 import android.app.RemoteInput;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ShortcutManager;
 import android.os.Handler;
+import android.os.Process;
+import android.os.UserHandle;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
 import android.widget.EditText;
 import android.widget.ImageButton;
 
@@ -53,6 +59,10 @@
     private static final String TEST_REPLY = "hello";
     private static final String TEST_ACTION = "com.android.REMOTE_INPUT_VIEW_ACTION";
 
+    private static final String DUMMY_MESSAGE_APP_PKG =
+            "com.android.sysuitest.dummynotificationsender";
+    private static final int DUMMY_MESSAGE_APP_ID = Process.LAST_APPLICATION_UID - 1;
+
     @Mock private RemoteInputController mController;
     @Mock private ShortcutManager mShortcutManager;
     @Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
@@ -73,9 +83,6 @@
 
         // Avoid SecurityException RemoteInputView#sendRemoteInput().
         mContext.addMockSystemService(ShortcutManager.class, mShortcutManager);
-
-        ExpandableNotificationRow row = new NotificationTestHelper(mContext).createRow();
-        mView = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
     }
 
     @After
@@ -83,19 +90,27 @@
         mContext.unregisterReceiver(mReceiver);
     }
 
-    @Test
-    public void testSendRemoteInput_intentContainsResultsAndSource() throws InterruptedException {
+    private void setTestPendingIntent(RemoteInputView view) {
         PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
                 new Intent(TEST_ACTION), 0);
         RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).build();
 
-        mView.setPendingIntent(pendingIntent);
-        mView.setRemoteInput(new RemoteInput[]{input}, input);
-        mView.focus();
+        view.setPendingIntent(pendingIntent);
+        view.setRemoteInput(new RemoteInput[]{input}, input);
+    }
 
-        EditText editText = mView.findViewById(R.id.remote_input_text);
+    @Test
+    public void testSendRemoteInput_intentContainsResultsAndSource() throws Exception {
+        ExpandableNotificationRow row = new NotificationTestHelper(mContext).createRow();
+        RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
+
+        setTestPendingIntent(view);
+
+        view.focus();
+
+        EditText editText = view.findViewById(R.id.remote_input_text);
         editText.setText(TEST_REPLY);
-        ImageButton sendButton = mView.findViewById(R.id.remote_input_send);
+        ImageButton sendButton = view.findViewById(R.id.remote_input_send);
         sendButton.performClick();
 
         Intent resultIntent = mReceiver.waitForIntent();
@@ -105,10 +120,55 @@
                 RemoteInput.getResultsSource(resultIntent));
     }
 
+    private UserHandle getTargetInputMethodUser(UserHandle fromUser, UserHandle toUser)
+            throws Exception {
+        ExpandableNotificationRow row = new NotificationTestHelper(mContext).createRow(
+                DUMMY_MESSAGE_APP_PKG,
+                UserHandle.getUid(fromUser.getIdentifier(), DUMMY_MESSAGE_APP_ID),
+                toUser);
+        RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
+
+        setTestPendingIntent(view);
+
+        view.focus();
+
+        EditText editText = view.findViewById(R.id.remote_input_text);
+        EditorInfo editorInfo = new EditorInfo();
+        editorInfo.packageName = DUMMY_MESSAGE_APP_PKG;
+        editorInfo.fieldId = editText.getId();
+        InputConnection ic = editText.onCreateInputConnection(editorInfo);
+        assertNotNull(ic);
+        return editorInfo.targetInputMethodUser;
+    }
+
     @Test
-    public void testNoCrashWithoutVisibilityListener() {
-        mView.setOnVisibilityChangedListener(null);
-        mView.setVisibility(View.INVISIBLE);
-        mView.setVisibility(View.VISIBLE);
+    public void testEditorInfoTargetInputMethodUserForCallingUser() throws Exception {
+        UserHandle callingUser = Process.myUserHandle();
+        assertEquals(callingUser, getTargetInputMethodUser(callingUser, callingUser));
+    }
+
+    @Test
+    public void testEditorInfoTargetInputMethodUserForDifferentUser() throws Exception {
+        UserHandle differentUser = UserHandle.of(UserHandle.getCallingUserId() + 1);
+        assertEquals(differentUser, getTargetInputMethodUser(differentUser, differentUser));
+    }
+
+    @Test
+    public void testEditorInfoTargetInputMethodUserForAllUser() throws Exception {
+        // For the special pseudo user UserHandle.ALL, EditorInfo#targetInputMethodUser must be
+        // resolved as the current user.
+        UserHandle callingUser = Process.myUserHandle();
+        assertEquals(UserHandle.of(ActivityManager.getCurrentUser()),
+                getTargetInputMethodUser(callingUser, UserHandle.ALL));
+    }
+
+    @Test
+    public void testNoCrashWithoutVisibilityListener() throws Exception {
+        ExpandableNotificationRow row = new NotificationTestHelper(mContext).createRow();
+        RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
+
+        view.setOnVisibilityChangedListener(null);
+        view.setVisibility(View.INVISIBLE);
+        view.setVisibility(View.VISIBLE);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
index 2266b47..03b7c95 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
@@ -20,6 +20,7 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import android.app.RemoteInput;
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.Settings;
@@ -51,6 +52,12 @@
         resources.addOverride(R.bool.config_smart_replies_in_notifications_enabled, true);
         resources.addOverride(
                 R.integer.config_smart_replies_in_notifications_max_squeeze_remeasure_attempts, 7);
+        resources.addOverride(
+                R.bool.config_smart_replies_in_notifications_edit_choices_before_sending, false);
+        resources.addOverride(R.bool.config_smart_replies_in_notifications_show_in_heads_up, true);
+        resources.addOverride(
+                R.integer.config_smart_replies_in_notifications_min_num_system_generated_replies,
+                2);
         mConstants = new SmartReplyConstants(Handler.createAsync(Looper.myLooper()), mContext);
     }
 
@@ -104,11 +111,89 @@
         assertEquals(5, mConstants.getMaxSqueezeRemeasureAttempts());
     }
 
+    @Test
+    public void testGetEffectiveEditChoicesBeforeSendingWithNoConfig() {
+        overrideSetting("enabled=true");
+        triggerConstantsOnChange();
+        assertFalse(
+                mConstants.getEffectiveEditChoicesBeforeSending(
+                        RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO));
+        assertTrue(
+                mConstants.getEffectiveEditChoicesBeforeSending(
+                        RemoteInput.EDIT_CHOICES_BEFORE_SENDING_ENABLED));
+        assertFalse(
+                mConstants.getEffectiveEditChoicesBeforeSending(
+                        RemoteInput.EDIT_CHOICES_BEFORE_SENDING_DISABLED));
+    }
+
+    @Test
+    public void testGetEffectiveEditChoicesBeforeSendingWithEnabledConfig() {
+        overrideSetting("enabled=true,edit_choices_before_sending=true");
+        triggerConstantsOnChange();
+        assertTrue(
+                mConstants.getEffectiveEditChoicesBeforeSending(
+                        RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO));
+        assertTrue(
+                mConstants.getEffectiveEditChoicesBeforeSending(
+                        RemoteInput.EDIT_CHOICES_BEFORE_SENDING_ENABLED));
+        assertFalse(
+                mConstants.getEffectiveEditChoicesBeforeSending(
+                        RemoteInput.EDIT_CHOICES_BEFORE_SENDING_DISABLED));
+    }
+
+    @Test
+    public void testGetEffectiveEditChoicesBeforeSendingWithDisabledConfig() {
+        overrideSetting("enabled=true,edit_choices_before_sending=false");
+        triggerConstantsOnChange();
+        assertFalse(
+                mConstants.getEffectiveEditChoicesBeforeSending(
+                        RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO));
+        assertTrue(
+                mConstants.getEffectiveEditChoicesBeforeSending(
+                        RemoteInput.EDIT_CHOICES_BEFORE_SENDING_ENABLED));
+        assertFalse(
+                mConstants.getEffectiveEditChoicesBeforeSending(
+                        RemoteInput.EDIT_CHOICES_BEFORE_SENDING_DISABLED));
+    }
+
+    @Test
+    public void testShowInHeadsUpWithNoConfig() {
+        assertTrue(mConstants.isEnabled());
+        assertTrue(mConstants.getShowInHeadsUp());
+    }
+
+    @Test
+    public void testShowInHeadsUpEnabled() {
+        overrideSetting("enabled=true,show_in_heads_up=true");
+        triggerConstantsOnChange();
+        assertTrue(mConstants.getShowInHeadsUp());
+    }
+
+    @Test
+    public void testShowInHeadsUpDisabled() {
+        overrideSetting("enabled=true,show_in_heads_up=false");
+        triggerConstantsOnChange();
+        assertFalse(mConstants.getShowInHeadsUp());
+    }
+
     private void overrideSetting(String flags) {
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS, flags);
     }
 
+    @Test
+    public void testGetMinNumSystemGeneratedRepliesWithNoConfig() {
+        assertTrue(mConstants.isEnabled());
+        assertEquals(2, mConstants.getMinNumSystemGeneratedReplies());
+    }
+
+    @Test
+    public void testGetMinNumSystemGeneratedRepliesWithValidConfig() {
+        overrideSetting("enabled=true,min_num_system_generated_replies=5");
+        triggerConstantsOnChange();
+        assertEquals(5, mConstants.getMinNumSystemGeneratedReplies());
+    }
+
     private void triggerConstantsOnChange() {
         // Since Settings.Global is mocked in TestableContext, we need to manually trigger the
         // content observer.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index c5bac92..d1c4d01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -50,7 +50,7 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.statusbar.SmartReplyController;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 import com.android.systemui.statusbar.phone.ShadeController;
 
@@ -94,8 +94,9 @@
     private int mSpacing;
 
     @Mock private SmartReplyController mLogger;
-    private NotificationData.Entry mEntry;
+    private NotificationEntry mEntry;
     private Notification mNotification;
+    @Mock private SmartReplyConstants mConstants;
 
     @Mock ActivityStarter mActivityStarter;
     @Mock HeadsUpManager mHeadsUpManager;
@@ -108,10 +109,14 @@
         mDependency.get(KeyguardDismissUtil.class).setDismissHandler(action -> action.onDismiss());
         mDependency.injectMockDependency(ShadeController.class);
         mDependency.injectTestDependency(ActivityStarter.class, mActivityStarter);
+        mDependency.injectTestDependency(SmartReplyConstants.class, mConstants);
 
         mContainer = new View(mContext, null);
         mView = SmartReplyView.inflate(mContext, null);
 
+        // Any number of replies are fine.
+        when(mConstants.getMinNumSystemGeneratedReplies()).thenReturn(0);
+        when(mConstants.getMaxSqueezeRemeasureAttempts()).thenReturn(3);
 
         final Resources res = mContext.getResources();
         mSingleLinePaddingHorizontal = res.getDimensionPixelSize(
@@ -127,7 +132,7 @@
         StatusBarNotification sbn = mock(StatusBarNotification.class);
         when(sbn.getNotification()).thenReturn(mNotification);
         when(sbn.getKey()).thenReturn(TEST_NOTIFICATION_KEY);
-        mEntry = new NotificationData.Entry(sbn);
+        mEntry = new NotificationEntry(sbn);
 
         mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
     }
@@ -403,7 +408,7 @@
     }
 
     private void setSmartReplies(CharSequence[] choices) {
-        setSmartReplies(choices, false);
+        setSmartReplies(choices, false /* fromAssistant */);
     }
 
     private void setSmartReplies(CharSequence[] choices, boolean fromAssistant) {
@@ -440,9 +445,14 @@
     }
 
     private void setSmartRepliesAndActions(CharSequence[] choices, String[] actionTitles) {
-        setSmartReplies(choices);
+        setSmartRepliesAndActions(choices, actionTitles, false /* fromAssistant */);
+    }
+
+    private void setSmartRepliesAndActions(
+            CharSequence[] choices, String[] actionTitles, boolean fromAssistant) {
+        setSmartReplies(choices, fromAssistant);
         mView.addSmartActions(
-                new SmartReplyView.SmartActions(createActions(actionTitles), false),
+                new SmartReplyView.SmartActions(createActions(actionTitles), fromAssistant),
                 mLogger,
                 mEntry,
                 mHeadsUpManager);
@@ -855,4 +865,166 @@
         assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(2));
         assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(3));
     }
+
+    /**
+     * Test to ensure that we try to add all possible actions - if we find one action that's too
+     * long we just skip that one rather than quitting altogether.
+     */
+    @Test
+    public void testMeasure_skipTooLongActions() {
+        String[] choices = new String[] {};
+        String[] actions = new String[] {
+                "a1", "a2", "this action is soooooooo long it's ridiculous", "a4"};
+
+        // All actions should be displayed as DOUBLE-line smart action buttons.
+        ViewGroup expectedView = buildExpectedView(new String[] {}, 1 /* lineCount */,
+                createActions(new String[] {"a1", "a2", "a4"}));
+        expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+        setSmartRepliesAndActions(choices, actions);
+        mView.measure(
+                MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
+                MeasureSpec.UNSPECIFIED);
+
+        assertEqualMeasures(expectedView, mView);
+        assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+        assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
+        assertReplyButtonHidden(mView.getChildAt(2));
+        assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(3));
+    }
+
+    /**
+     * Test to ensure that we try to add all possible replies - if we find one reply that's too
+     * long we just skip that one rather than quitting altogether.
+     */
+    @Test
+    public void testMeasure_skipTooLongReplies() {
+        String[] choices = new String[] {
+                "r1", "r2", "this reply is soooooooo long it's ridiculous", "r4"};
+        String[] actions = new String[] {};
+
+        // All replies should be displayed as single-line smart reply buttons.
+        ViewGroup expectedView = buildExpectedView(new String[] {"r1", "r2", "r4"},
+                1 /* lineCount */, Collections.emptyList());
+        expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+        setSmartRepliesAndActions(choices, actions);
+        mView.measure(
+                MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
+                MeasureSpec.UNSPECIFIED);
+
+        assertEqualMeasures(expectedView, mView);
+        assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+        assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
+        assertReplyButtonHidden(mView.getChildAt(2));
+        assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(3));
+    }
+
+    /**
+     * Test to ensure that we try to add all possible replies and actions - if we find a reply or
+     * action that's too long we just skip that one rather than quitting altogether.
+     */
+    @Test
+    public void testMeasure_skipTooLongRepliesAndActions() {
+        String[] choices = new String[] {
+                "r1", "r2", "this reply is soooooooo long it's ridiculous", "r4"};
+        String[] actions = new String[] {
+                "a1", "ThisActionIsSooooooooLongItsRidiculousIPromise"};
+
+        // All replies should be displayed as single-line smart reply buttons.
+        ViewGroup expectedView = buildExpectedView(new String[] {"r1", "r2", "r4"},
+                1 /* lineCount */, createActions(new String[] {"a1"}));
+        expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+        setSmartRepliesAndActions(choices, actions);
+        mView.measure(
+                MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
+                MeasureSpec.UNSPECIFIED);
+
+        assertEqualMeasures(expectedView, mView);
+        assertReplyButtonShownWithEqualMeasures(
+                expectedView.getChildAt(0), mView.getChildAt(0)); // r1
+        assertReplyButtonShownWithEqualMeasures(
+                expectedView.getChildAt(1), mView.getChildAt(1)); // r2
+        assertReplyButtonHidden(mView.getChildAt(2)); // long reply
+        assertReplyButtonShownWithEqualMeasures(
+                expectedView.getChildAt(2), mView.getChildAt(3)); // r4
+        assertReplyButtonShownWithEqualMeasures(
+                expectedView.getChildAt(3), mView.getChildAt(4)); // a1
+        assertReplyButtonHidden(mView.getChildAt(5)); // long action
+    }
+
+    @Test
+    public void testMeasure_minNumSystemGeneratedSmartReplies_notEnoughReplies() {
+        when(mConstants.getMinNumSystemGeneratedReplies()).thenReturn(3);
+
+        // Add 2 replies when the minimum is 3 -> we should end up with 0 replies.
+        String[] choices = new String[] {"reply1", "reply2"};
+        String[] actions = new String[] {"action1"};
+
+        ViewGroup expectedView = buildExpectedView(new String[] {}, 1,
+                createActions(new String[] {"action1"}));
+        expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+        setSmartRepliesAndActions(choices, actions, true /* fromAssistant */);
+        mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+        assertEqualMeasures(expectedView, mView);
+        // smart replies
+        assertReplyButtonHidden(mView.getChildAt(0));
+        assertReplyButtonHidden(mView.getChildAt(1));
+        // smart actions
+        assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(2));
+    }
+
+    @Test
+    public void testMeasure_minNumSystemGeneratedSmartReplies_enoughReplies() {
+        when(mConstants.getMinNumSystemGeneratedReplies()).thenReturn(2);
+
+        // Add 2 replies when the minimum is 3 -> we should end up with 0 replies.
+        String[] choices = new String[] {"reply1", "reply2"};
+        String[] actions = new String[] {"action1"};
+
+        ViewGroup expectedView = buildExpectedView(new String[] {"reply1", "reply2"}, 1,
+                createActions(new String[] {"action1"}));
+        expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+        setSmartRepliesAndActions(choices, actions, true /* fromAssistant */);
+        mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+        assertEqualMeasures(expectedView, mView);
+        // smart replies
+        assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+        assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
+        // smart actions
+        assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2));
+    }
+
+    /**
+     * Ensure actions that are squeezed when shown together with smart replies are unsqueezed if the
+     * replies are never added (because of the SmartReplyConstants.getMinNumSystemGeneratedReplies()
+     * flag).
+     */
+    @Test
+    public void testMeasure_minNumSystemGeneratedSmartReplies_unSqueezeActions() {
+        when(mConstants.getMinNumSystemGeneratedReplies()).thenReturn(2);
+
+        // Add 2 replies when the minimum is 3 -> we should end up with 0 replies.
+        String[] choices = new String[] {"This is a very long two-line reply."};
+        String[] actions = new String[] {"Short action"};
+
+        // The action should be displayed on one line only - since it fits!
+        ViewGroup expectedView = buildExpectedView(new String[] {}, 1 /* lineCount */,
+                createActions(new String[] {"Short action"}));
+        expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+        setSmartRepliesAndActions(choices, actions, true /* fromAssistant */);
+        mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+        assertEqualMeasures(expectedView, mView);
+        // smart replies
+        assertReplyButtonHidden(mView.getChildAt(0));
+        // smart actions
+        assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(1));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpaper/AodMaskViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpaper/AodMaskViewTest.java
new file mode 100644
index 0000000..c44a366
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpaper/AodMaskViewTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.wallpaper;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.RectF;
+import android.hardware.display.DisplayManager;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.FeatureFlagUtils;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AodMaskViewTest extends SysuiTestCase {
+    private AodMaskView mMaskView;
+    private DisplayInfo mDisplayInfo;
+    private ImageWallpaperTransformer mTransformer;
+
+    @Before
+    public void setUp() throws Exception {
+        DisplayManager displayManager =
+                spy((DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE));
+        doNothing().when(displayManager).registerDisplayListener(any(), any());
+        mContext.addMockSystemService(DisplayManager.class, displayManager);
+
+        WallpaperManager wallpaperManager =
+                spy((WallpaperManager) mContext.getSystemService(Context.WALLPAPER_SERVICE));
+        doReturn(null).when(wallpaperManager).getWallpaperInfo();
+        mContext.addMockSystemService(WallpaperManager.class, wallpaperManager);
+
+        mTransformer = spy(new ImageWallpaperTransformer(null /* listener */));
+        mMaskView = spy(new AodMaskView(getContext(), null /* attrs */, mTransformer));
+        mDisplayInfo = new DisplayInfo();
+
+        ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE))
+                .getDefaultDisplay().getDisplayInfo(mDisplayInfo);
+
+        FeatureFlagUtils.setEnabled(
+                mContext, FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED, true);
+    }
+
+    @After
+    public void tearDown() {
+        FeatureFlagUtils.setEnabled(
+                mContext, FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED, false);
+    }
+
+    @Test
+    public void testCreateMaskView_TransformerIsNotNull() {
+        assertNotNull("mTransformer should not be null", mTransformer);
+    }
+
+    @Test
+    public void testAodMaskView_ShouldNotClickable() {
+        assertFalse("MaskView should not be clickable", mMaskView.isClickable());
+    }
+
+    @Test
+    public void testAodMaskView_OnSizeChange_ShouldUpdateTransformerOffsets() {
+        mMaskView.onSizeChanged(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight, 0, 0);
+        verify(mTransformer, times(1)).updateOffsets();
+    }
+
+    @Test
+    public void testAodMaskView_OnDraw_ShouldDrawTransformedImage() {
+        Canvas c = new Canvas();
+        RectF bounds = new RectF(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
+        mMaskView.onSizeChanged(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight, 0, 0);
+        mMaskView.onStatePreChange(0, 1);
+        mMaskView.onDraw(c);
+        verify(mTransformer, times(1)).drawTransformedImage(c, null, null, bounds);
+    }
+
+    @Test
+    public void testAodMaskView_IsDozing_ShouldUpdateAmbientModeState() {
+        doNothing().when(mMaskView).setAnimatorProperty(anyBoolean());
+        mMaskView.onStatePreChange(0, 1);
+        mMaskView.onDozingChanged(true);
+        verify(mTransformer, times(1)).updateAmbientModeState(true);
+    }
+
+    @Test
+    public void testAodMaskView_IsDozing_ShouldDoTransitionOrDrawFinalFrame() {
+        doNothing().when(mMaskView).setAnimatorProperty(anyBoolean());
+        mMaskView.onStatePreChange(0, 1);
+        mMaskView.onDozingChanged(true);
+        mMaskView.onStatePostChange();
+        mMaskView.onDozingChanged(false);
+        verify(mMaskView, times(1)).invalidate();
+        verify(mMaskView, times(1)).setAnimatorProperty(false);
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpaper/ImageWallpaperTransformerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpaper/ImageWallpaperTransformerTest.java
new file mode 100644
index 0000000..55b0aae
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpaper/ImageWallpaperTransformerTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wallpaper;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ImageWallpaperTransformerTest extends SysuiTestCase {
+    private DisplayInfo mDisplayInfo;
+    private Bitmap mBitmap;
+    private Canvas mCanvas;
+    private RectF mDestination;
+
+    @Before
+    public void setUp() throws Exception {
+        mDisplayInfo = new DisplayInfo();
+        ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
+                .getDefaultDisplay().getDisplayInfo(mDisplayInfo);
+        int dimension = Math.max(mDisplayInfo.logicalHeight, mDisplayInfo.logicalWidth);
+        mBitmap = Bitmap.createBitmap(dimension, dimension, Bitmap.Config.ARGB_8888);
+        mCanvas = new Canvas(mBitmap);
+        mCanvas.drawColor(Color.RED);
+        mDestination = new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
+    }
+
+    @Test
+    public void testVignetteFilter() {
+        VignetteFilter vignette = new VignetteFilter();
+
+        ImageWallpaperTransformer transformer = getTransformer(vignette);
+        transformer.drawTransformedImage(mCanvas, mBitmap, null, mDestination);
+
+        PointF center = vignette.getCenterPoint();
+        int p1 = mBitmap.getPixel((int) center.x, (int) center.y);
+        int p2 = mBitmap.getPixel(0, 0);
+        int p3 = mBitmap.getPixel(mBitmap.getWidth() - 1, mBitmap.getHeight() - 1);
+
+        assertThat(p1).isEqualTo(Color.RED);
+        assertThat(p2 | p3).isEqualTo(Color.BLACK);
+    }
+
+    @Test
+    public void testScrimFilter() {
+        getTransformer(new ScrimFilter())
+                .drawTransformedImage(mCanvas, mBitmap, null, mDestination);
+
+        int pixel = mBitmap.getPixel(0, 0);
+
+        // 0xff4d0000 is the result of 70% alpha pre-multiplied which is 0.7*(0,0,0)+0.3*(255,0,0).
+        assertThat(pixel).isEqualTo(0xff4d0000);
+    }
+
+    private ImageWallpaperTransformer getTransformer(ImageWallpaperFilter filter) {
+        ImageWallpaperTransformer transformer = new ImageWallpaperTransformer(null);
+        transformer.addFilter(filter);
+        transformer.updateDisplayInfo(mDisplayInfo);
+        transformer.updateOffsets();
+        transformer.updateAmbientModeState(true);
+        return transformer;
+    }
+}
diff --git a/packages/VpnDialogs/res/values-as/strings.xml b/packages/VpnDialogs/res/values-as/strings.xml
index 25f16e3..45d8458 100644
--- a/packages/VpnDialogs/res/values-as/strings.xml
+++ b/packages/VpnDialogs/res/values-as/strings.xml
@@ -21,7 +21,7 @@
     <string name="legacy_title" msgid="192936250066580964">"ভিপিএন সংযোগ হৈ আছে"</string>
     <string name="session" msgid="6470628549473641030">"ছেশ্বন:"</string>
     <string name="duration" msgid="3584782459928719435">"সময়সীমা:"</string>
-    <string name="data_transmitted" msgid="7988167672982199061">"পঠিওৱা হ\'ল:"</string>
+    <string name="data_transmitted" msgid="7988167672982199061">"পঠিওৱা হ’ল:"</string>
     <string name="data_received" msgid="4062776929376067820">"পোৱা গ\'ল:"</string>
     <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_1">%2$s</xliff:g> পেকেট / <xliff:g id="NUMBER_0">%1$s</xliff:g> বাইট"</string>
     <string name="always_on_disconnected_title" msgid="1906740176262776166">"সদা-সক্ৰিয় ভিপিএনৰ লগত সংযোগ কৰিবপৰা নাই"</string>
diff --git a/packages/VpnDialogs/res/values-ne/strings.xml b/packages/VpnDialogs/res/values-ne/strings.xml
index 5019a06..b716c35 100644
--- a/packages/VpnDialogs/res/values-ne/strings.xml
+++ b/packages/VpnDialogs/res/values-ne/strings.xml
@@ -25,7 +25,7 @@
     <string name="data_received" msgid="4062776929376067820">"प्राप्त भयो:"</string>
     <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> बाइटहरू / <xliff:g id="NUMBER_1">%2$s</xliff:g> प्याकेटहरू"</string>
     <string name="always_on_disconnected_title" msgid="1906740176262776166">"सधैँ-सक्रिय रहने VPN सेवामा जडान गर्न सकिँदैन"</string>
-    <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> लाई सधैँ जडान भइरहनेगरि सेटअप गरिएको छ तर यसलाई अहिले नै जडान गर्न मिल्दैन। तपाईंको फोन <xliff:g id="VPN_APP_1">%1$s</xliff:g> मा पुन: जडान नहुँदासम्म यसले कुनै सार्वजनिक नेटवर्क प्रयोग गर्नेछ।"</string>
+    <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> लाई सधैँ जडान भइरहनेगरि सेटअप गरिएको छ तर यसलाई अहिले नै जडान गर्न मिल्दैन। तपाईंको फोन <xliff:g id="VPN_APP_1">%1$s</xliff:g> मा पुन: जडान नहुँदासम्म यसले कुनै सार्वजनिक नेटवर्क प्रयोग गर्ने छ।"</string>
     <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> लाई सधैँ पनि जडान भइरहनेगरि सेटअप गरिएको छ तर यसलाई अहिले नै जडान गर्न मिल्दैन। VPN पुन: जडान नहुँदासम्म तपाईंसँग कुनै पनि इन्टरनेट रहनेछैन।"</string>
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
     <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN सम्बन्धी सेटिङहरू परिवर्तन गर्नुहोस्"</string>
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
index 848f2bd..2fa1dde 100644
--- a/packages/WallpaperCropper/Android.mk
+++ b/packages/WallpaperCropper/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_PACKAGE_NAME := WallpaperCropper
 LOCAL_PRIVATE_PLATFORM_APIS := true
 LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
 LOCAL_PRIVILEGED_MODULE := true
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
diff --git a/packages/WallpaperCropper/CleanSpec.mk b/packages/WallpaperCropper/CleanSpec.mk
new file mode 100644
index 0000000..e6d8d5a
--- /dev/null
+++ b/packages/WallpaperCropper/CleanSpec.mk
@@ -0,0 +1,50 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/WallpaperCropper)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/packages/overlays/AccentColorBlackOverlay/res/values/strings.xml b/packages/overlays/AccentColorBlackOverlay/res/values/strings.xml
index baf09b1..da10361 100644
--- a/packages/overlays/AccentColorBlackOverlay/res/values/strings.xml
+++ b/packages/overlays/AccentColorBlackOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Black accent color name application label. [CHAR LIMIT=50] -->
-    <string name="accent_color_black_overlay" translatable="false">Black Accent Color</string>
+    <string name="accent_color_black_overlay" translatable="false">Black</string>
 </resources>
 
diff --git a/packages/overlays/AccentColorGreenOverlay/res/values/strings.xml b/packages/overlays/AccentColorGreenOverlay/res/values/strings.xml
index 4de344c..623a1da 100644
--- a/packages/overlays/AccentColorGreenOverlay/res/values/strings.xml
+++ b/packages/overlays/AccentColorGreenOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Green accent color name application label. [CHAR LIMIT=50] -->
-    <string name="accent_color_green_overlay" translatable="false">Green Accent Color</string>
+    <string name="accent_color_green_overlay" translatable="false">Green</string>
 </resources>
 
diff --git a/packages/overlays/AccentColorPurpleOverlay/res/values/strings.xml b/packages/overlays/AccentColorPurpleOverlay/res/values/strings.xml
index d1eb95a..d1c7168 100644
--- a/packages/overlays/AccentColorPurpleOverlay/res/values/strings.xml
+++ b/packages/overlays/AccentColorPurpleOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Purple accent color name application label. [CHAR LIMIT=50] -->
-    <string name="accent_color_purple_overlay" translatable="false">Purple Accent Color</string>
+    <string name="accent_color_purple_overlay" translatable="false">Purple</string>
 </resources>
 
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-af/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-af/strings.xml
new file mode 100644
index 0000000..9ac5fd6
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-af/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Eksperiment met verstek navigasiebalk (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-am/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-am/strings.xml
new file mode 100644
index 0000000..c15f374
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-am/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"ነባሪ የዳሰሳ አሞሌ ሙከራ (48 ዲፒ)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ar/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ar/strings.xml
new file mode 100644
index 0000000..26abf03
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ar/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"‏تجربة شريط التنقل التلقائي (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-as/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-as/strings.xml
new file mode 100644
index 0000000..cfd21b1
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-as/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"ডিফ’ল্ট নেভিগে’শ্বন বাৰ সম্পৰীক্ষা (৪৮ডিপি)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-az/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-az/strings.xml
new file mode 100644
index 0000000..a7e9110
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-az/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Defolt Naviqasiya Paneli Təcrübəsi (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-b+sr+Latn/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..1222625
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-b+sr+Latn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Eksperiment sa tankom trakom za navigaciju (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-be/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-be/strings.xml
new file mode 100644
index 0000000..da91427
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-be/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Эксперымент са стандартнай панэллю навігацыі (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-bg/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-bg/strings.xml
new file mode 100644
index 0000000..7295457
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-bg/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Експеримент със стандартна лента за навигация (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-bn/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-bn/strings.xml
new file mode 100644
index 0000000..1515805
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-bn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"ডিফল্ট নেভিগেশন বার সম্পর্কিত পরীক্ষা (৪৮ ডিপি)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-bs/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-bs/strings.xml
new file mode 100644
index 0000000..dea0884
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-bs/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Eksperiment sa zadanom trakom za navigaciju (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ca/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ca/strings.xml
new file mode 100644
index 0000000..d422c86
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ca/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Experiment amb barra de navegació predeterminada (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-cs/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-cs/strings.xml
new file mode 100644
index 0000000..61d4131
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-cs/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Výchozí navigační panel – experiment (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-da/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-da/strings.xml
new file mode 100644
index 0000000..78c5ff3
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-da/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Test med standardnavigationslinje (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-de/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-de/strings.xml
new file mode 100644
index 0000000..a0779b5
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-de/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Test mit Standard-Navigationsleiste (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-el/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-el/strings.xml
new file mode 100644
index 0000000..b34cf5afb
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-el/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Πείραμα προεπιλεγμένης γραμμής πλοήγησης (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-en-rAU/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..aa3bf66
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-en-rAU/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Default Navigation Bar Experiment (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-en-rCA/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..aa3bf66
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-en-rCA/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Default Navigation Bar Experiment (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-en-rGB/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..aa3bf66
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-en-rGB/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Default Navigation Bar Experiment (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-en-rIN/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..aa3bf66
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-en-rIN/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Default Navigation Bar Experiment (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-es-rUS/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..81297d0
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-es-rUS/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Experimento de la barra navegación predeterminada (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-es/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-es/strings.xml
new file mode 100644
index 0000000..81297d0
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-es/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Experimento de la barra navegación predeterminada (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-et/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-et/strings.xml
new file mode 100644
index 0000000..8a442be
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-et/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Vaikenavigeerimisriba katse (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-eu/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-eu/strings.xml
new file mode 100644
index 0000000..fdf4c4e
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-eu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Nabigazio-barra lehenetsiaren esperimentua (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-fa/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-fa/strings.xml
new file mode 100644
index 0000000..d521f79
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-fa/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"‏آزمایش نوار پیمایش پیش‌فرض (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-fi/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-fi/strings.xml
new file mode 100644
index 0000000..2e538a3
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-fi/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Oletusnavigointipalkin kokeilu (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-fr-rCA/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..171a37e
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-fr-rCA/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Expérience de barre de navigation par défaut (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-fr/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-fr/strings.xml
new file mode 100644
index 0000000..bcbf94d
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-fr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Test relatif à la barre de navigation par défaut (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-gl/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-gl/strings.xml
new file mode 100644
index 0000000..b9a0165
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-gl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Experimento da barra de navegación predeterminada (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-gu/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-gu/strings.xml
new file mode 100644
index 0000000..f4cdb38
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-gu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"ડિફૉલ્ટ નૅવિગેશન બારનો પ્રયોગ (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-hi/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-hi/strings.xml
new file mode 100644
index 0000000..ee8a739
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-hi/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"डिफ़ॉल्ट नेविगेशन बार प्रयोग (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-hr/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-hr/strings.xml
new file mode 100644
index 0000000..63a5b044
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-hr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Eksperiment s tankom navigacijskom trakom (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-hu/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-hu/strings.xml
new file mode 100644
index 0000000..110347c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-hu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Kísérleti alapértelmezett navigációs sáv (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-hy/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-hy/strings.xml
new file mode 100644
index 0000000..9ef0d82
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-hy/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Նավարկման կանխադրված գոտու փորձարկում (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-in/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-in/strings.xml
new file mode 100644
index 0000000..c48e0a7
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-in/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Eksperimen Menu Navigasi Default (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-is/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-is/strings.xml
new file mode 100644
index 0000000..1950f5d
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-is/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Tilraun með sjálfgefna yfirlitsstiku (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-it/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-it/strings.xml
new file mode 100644
index 0000000..45985d9
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-it/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Esperimento Barra di navigazione predefinita (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-iw/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-iw/strings.xml
new file mode 100644
index 0000000..1d99dfe
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-iw/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"‏ניסוי של סרגל ניווט דק (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ja/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ja/strings.xml
new file mode 100644
index 0000000..80e6954
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ja/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"デフォルト ナビゲーション バー テスト(48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ka/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ka/strings.xml
new file mode 100644
index 0000000..f623c11
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ka/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"ნავიგაციის ნაგულისხმევი ზოლის ექსპერიმენტი (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-kk/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-kk/strings.xml
new file mode 100644
index 0000000..f42d9ac
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-kk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Әдепкі навигация жолағы (эксперимент) (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-km/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-km/strings.xml
new file mode 100644
index 0000000..a1316b7
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-km/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"ការពិសោធ​នៃ​របារ​រុករក​លំនាំដើម (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-kn/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-kn/strings.xml
new file mode 100644
index 0000000..15f3f4a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-kn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"ಡೀಫಾಲ್ಟ್ ನ್ಯಾವಿಗೇಶನ್‌ ಬಾರ್‌ ಪ್ರಯೋಗ (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ko/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ko/strings.xml
new file mode 100644
index 0000000..08a93df
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ko/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"기본 탐색 메뉴 실험(48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ky/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ky/strings.xml
new file mode 100644
index 0000000..e352c7f3
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ky/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Демейки чабыттоо тилкесин сыноо (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-lo/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-lo/strings.xml
new file mode 100644
index 0000000..6dfeacf
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-lo/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"ການທົດສອບແຖບນໍາທາງແບບບາງ (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-lt/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-lt/strings.xml
new file mode 100644
index 0000000..0752655
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-lt/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Numatytosios naršymo juostos eksperimentas (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-lv/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-lv/strings.xml
new file mode 100644
index 0000000..c72c9eb
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-lv/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Noklusējuma navigācijas joslas eksperiments (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-mk/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-mk/strings.xml
new file mode 100644
index 0000000..de21e96
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-mk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Експеримент со стандардна лента за навигација (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ml/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ml/strings.xml
new file mode 100644
index 0000000..8870ae7
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ml/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"സ്ലിം നാവിഗേഷൻ ബാർ പരീക്ഷണം (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-mn/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-mn/strings.xml
new file mode 100644
index 0000000..29377d1
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-mn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Өгөгдмөл навигацийн самбарын туршилт (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-mr/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-mr/strings.xml
new file mode 100644
index 0000000..3057fe7
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-mr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"डीफॉल्ट नॅव्हिगेशन बार प्रयोग (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ms/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ms/strings.xml
new file mode 100644
index 0000000..047a6ce
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ms/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Pengalaman Bar Navigasi Lalai (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-my/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-my/strings.xml
new file mode 100644
index 0000000..37b559a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-my/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"မူရင်း လမ်းညွှန်ဘား စမ်းသပ်မှု (၄၈dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-nb/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-nb/strings.xml
new file mode 100644
index 0000000..e6cc2af
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-nb/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Eksperiment med standard navigasjonsrad (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ne/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ne/strings.xml
new file mode 100644
index 0000000..5df6f56
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ne/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"पूर्वनिर्धारित नेभिगेसन पट्टीको परीक्षण (४८dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-nl/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-nl/strings.xml
new file mode 100644
index 0000000..f97a352
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-nl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Experiment voor standaard navigatiebalk (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-or/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-or/strings.xml
new file mode 100644
index 0000000..e602159
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-or/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"ଡିଫଲ୍ଟ ନାଭିଗେସନ୍ ବାର୍‍ର ପ୍ରୟୋଗ (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pa/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pa/strings.xml
new file mode 100644
index 0000000..0c26291
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pa/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਦਿਸ਼ਾ-ਨਿਰਦੇਸ਼ ਪੱਟੀ ਪ੍ਰਯੋਗ (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pl/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pl/strings.xml
new file mode 100644
index 0000000..395e678
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Eksperyment z domyślnym paskiem nawigacyjnym (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pt-rBR/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..06f1966
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pt-rBR/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Experimento de barra de navegação padrão (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pt-rPT/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..e2bb116
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pt-rPT/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Experiência de barra de navegação predefinida (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pt/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pt/strings.xml
new file mode 100644
index 0000000..06f1966
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-pt/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Experimento de barra de navegação padrão (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ro/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ro/strings.xml
new file mode 100644
index 0000000..2547137
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ro/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Experiment cu bară de navigare prestabilită (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ru/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ru/strings.xml
new file mode 100644
index 0000000..b5e26b3
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ru/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Экспериментальная панель навигации по умолчанию (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-si/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-si/strings.xml
new file mode 100644
index 0000000..7ef2c3e
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-si/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"පෙරනිමි සංචලන තීරු පරීක්‍ෂණය (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sk/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sk/strings.xml
new file mode 100644
index 0000000..9946848
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Experiment s predvoleným navigačným panelom (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sl/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sl/strings.xml
new file mode 100644
index 0000000..34b33ae
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Preizkus s privzeto vrstico za krmarjenje (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sq/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sq/strings.xml
new file mode 100644
index 0000000..428e43d
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sq/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Eksperimenti i shiritit të parazgjedhur të navigimit (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sr/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sr/strings.xml
new file mode 100644
index 0000000..a1f914c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Експеримент са танком траком за навигацију (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sv/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sv/strings.xml
new file mode 100644
index 0000000..96f4f56
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sv/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Standardnavigeringsfält för experiment (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sw/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sw/strings.xml
new file mode 100644
index 0000000..3ca80c2
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-sw/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Jaribio Chaguomsingi la Sehemu ya Viungo Muhimu (dp 48)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ta/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ta/strings.xml
new file mode 100644
index 0000000..2ff46e8
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ta/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"இயல்புநிலை வழிசெலுத்துதல் பட்டி சோதனை (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-te/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-te/strings.xml
new file mode 100644
index 0000000..99a32ed
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-te/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"డిఫాల్ట్ నావిగేషన్ పట్టీ ప్రయోగం (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-th/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-th/strings.xml
new file mode 100644
index 0000000..acfb209
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-th/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"การทดสอบแถบนำทางเริ่มต้น (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-tl/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-tl/strings.xml
new file mode 100644
index 0000000..6284190
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-tl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Eksperimentong Default na Navigation Bar (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-tr/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-tr/strings.xml
new file mode 100644
index 0000000..518e801
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-tr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Varsayılan Gezinme Çubuğu Denemesi (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-uk/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-uk/strings.xml
new file mode 100644
index 0000000..bff10a6
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-uk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Експеримент зі стандартною панеллю навігації (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ur/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ur/strings.xml
new file mode 100644
index 0000000..ff19804
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-ur/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"‏ڈیفالٹ نیویگیشن بار کا تجربہ (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-uz/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-uz/strings.xml
new file mode 100644
index 0000000..d208c7b
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-uz/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Standart navigatsiya paneli tajribasi (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-vi/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-vi/strings.xml
new file mode 100644
index 0000000..067de92
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-vi/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Thử nghiệm thanh điều hướng mặc định (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-zh-rCN/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..75a1207
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-zh-rCN/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"默认导航栏实验 (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-zh-rHK/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..32ff1b2
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-zh-rHK/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"預設導覽列實驗 (48 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-zh-rTW/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..f8fe18c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-zh-rTW/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"預設導覽列實驗 (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-zu/strings.xml b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-zu/strings.xml
new file mode 100644
index 0000000..0e56660
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarDefaultOverlay/res/values-zu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="3475628315769912732">"Ukuhlolwa kwebha yokuzulazula ezenzakalelayo (48dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-af/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-af/strings.xml
new file mode 100644
index 0000000..7e52c2a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-af/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Eksperiment met dun navigasiebalk (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-am/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-am/strings.xml
new file mode 100644
index 0000000..533bf95
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-am/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"የቀጭን ዳሰሳ አሞሌ ሙከራ (24 ዲፒ)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ar/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ar/strings.xml
new file mode 100644
index 0000000..b338de5
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ar/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"‏تجربة شريط التنقل الصغير الحجم (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-as/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-as/strings.xml
new file mode 100644
index 0000000..1c15d70
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-as/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"লাহী নেভিগে’শ্বন বাৰ সম্পৰীক্ষা (২৪ডিপি)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-az/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-az/strings.xml
new file mode 100644
index 0000000..1696946
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-az/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Ensiz Naviqasiya Paneli Təcrübəsi (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-b+sr+Latn/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..fafec1d
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-b+sr+Latn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Eksperiment sa tankom trakom za navigaciju (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-be/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-be/strings.xml
new file mode 100644
index 0000000..ba572a5
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-be/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Эксперымент з тонкай панэллю навігацыі (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-bg/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-bg/strings.xml
new file mode 100644
index 0000000..752eb1d
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-bg/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Експеримент с тънка лента за навигация (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-bn/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-bn/strings.xml
new file mode 100644
index 0000000..b486c9f
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-bn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"স্লিম নেভিগেশন বার সম্পর্কিত পরীক্ষা (২৪ ডিপি)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-bs/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-bs/strings.xml
new file mode 100644
index 0000000..25fb785
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-bs/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Eksperiment s tankom trakom za navigaciju (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ca/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ca/strings.xml
new file mode 100644
index 0000000..d859f0a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ca/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Experiment amb barra de navegació fina (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-cs/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-cs/strings.xml
new file mode 100644
index 0000000..d81c6e3
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-cs/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Úzký navigační panel – experiment (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-da/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-da/strings.xml
new file mode 100644
index 0000000..2f10bfe
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-da/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Test med smal navigationslinje (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-de/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-de/strings.xml
new file mode 100644
index 0000000..2c0937b
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-de/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Test mit schmaler Navigationsleiste (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-el/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-el/strings.xml
new file mode 100644
index 0000000..ef522b3
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-el/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Πείραμα λεπτής γραμμής πλοήγησης (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-en-rAU/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..d9958ec
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-en-rAU/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Slim Navigation Bar Experiment (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-en-rCA/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..d9958ec
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-en-rCA/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Slim Navigation Bar Experiment (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-en-rGB/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..d9958ec
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-en-rGB/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Slim Navigation Bar Experiment (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-en-rIN/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..d9958ec
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-en-rIN/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Slim Navigation Bar Experiment (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-es-rUS/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..7c47655
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-es-rUS/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Experimento de la barra navegación delgada (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-es/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-es/strings.xml
new file mode 100644
index 0000000..7c47655
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-es/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Experimento de la barra navegación delgada (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-et/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-et/strings.xml
new file mode 100644
index 0000000..bf23377
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-et/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Kitsa navigeerimisriba katse (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-eu/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-eu/strings.xml
new file mode 100644
index 0000000..cc4276ed
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-eu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Nabigazio-barra finaren esperimentua (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-fa/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-fa/strings.xml
new file mode 100644
index 0000000..3c584d4
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-fa/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"‏آزمایش نوار پیمایش باریک (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-fi/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-fi/strings.xml
new file mode 100644
index 0000000..33236aa
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-fi/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Ohuen navigointipalkin kokeilu (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-fr-rCA/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..523a593
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-fr-rCA/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Expérience de barre de navigation mince (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-fr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-fr/strings.xml
new file mode 100644
index 0000000..f5a75c7
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-fr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Test relatif à la barre de navigation fine (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-gl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-gl/strings.xml
new file mode 100644
index 0000000..8a4b2ab
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-gl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Experimento de barra de navegación estreita (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-gu/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-gu/strings.xml
new file mode 100644
index 0000000..aa3466d
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-gu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"સ્લિમ નૅવિગેશન બારનો પ્રયોગ (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-hi/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-hi/strings.xml
new file mode 100644
index 0000000..f3a5b02
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-hi/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"स्लिम नेविगेशन बार प्रयोग (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-hr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-hr/strings.xml
new file mode 100644
index 0000000..6532bf8
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-hr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Eksperiment s tankom navigacijskom trakom (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-hu/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-hu/strings.xml
new file mode 100644
index 0000000..2a8adf9
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-hu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Kísérleti keskeny navigációs sáv (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-hy/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-hy/strings.xml
new file mode 100644
index 0000000..a48dfc5
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-hy/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Նավարկման նեղ գոտու փորձարկում (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-in/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-in/strings.xml
new file mode 100644
index 0000000..961b639
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-in/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Eksperimen Menu Navigasi Ramping (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-is/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-is/strings.xml
new file mode 100644
index 0000000..659f126
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-is/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Tilraun með þunna yfirlitsstiku (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-it/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-it/strings.xml
new file mode 100644
index 0000000..57df77d
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-it/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Esperimento Barra di navigazione sottile (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-iw/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-iw/strings.xml
new file mode 100644
index 0000000..5fbc0a2
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-iw/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"‏ניסוי של סרגל ניווט דק (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ja/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ja/strings.xml
new file mode 100644
index 0000000..ab2d149
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ja/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"スリム ナビゲーション バー テスト(24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ka/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ka/strings.xml
new file mode 100644
index 0000000..2605327
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ka/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"ნავიგაციის მჭიდრო ზოლის ექსპერიმენტი (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-kk/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-kk/strings.xml
new file mode 100644
index 0000000..99c6085
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-kk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Жіңішке навигация жолағы (эксперимент) (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-km/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-km/strings.xml
new file mode 100644
index 0000000..f63a7bc
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-km/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"ការពិសោធ​នៃ​របាររុករក​ស្ដើង (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-kn/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-kn/strings.xml
new file mode 100644
index 0000000..74a72df
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-kn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"ಸ್ಲಿಮ್ ನ್ಯಾವಿಗೇಶನ್‌ ಬಾರ್‌ ಪ್ರಯೋಗ (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ko/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ko/strings.xml
new file mode 100644
index 0000000..0b8acb5
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ko/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"슬림한 탐색 메뉴 실험(24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ky/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ky/strings.xml
new file mode 100644
index 0000000..5629ecd
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ky/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Чакан чабыттоо тилкесин сыноо (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-lo/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-lo/strings.xml
new file mode 100644
index 0000000..71846dc
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-lo/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"ການທົດສອບແຖບນໍາທາງແບບບາງ (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-lt/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-lt/strings.xml
new file mode 100644
index 0000000..e340412
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-lt/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Plonos naršymo juostos eksperimentas (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-lv/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-lv/strings.xml
new file mode 100644
index 0000000..eb963eb
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-lv/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Plānas navigācijas joslas eksperiments (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-mk/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-mk/strings.xml
new file mode 100644
index 0000000..9e57314
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-mk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Експеримент со тенка лента за навигација (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ml/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ml/strings.xml
new file mode 100644
index 0000000..41862af
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ml/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"സ്ലിം നാവിഗേഷൻ ബാർ പരീക്ഷണം (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-mn/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-mn/strings.xml
new file mode 100644
index 0000000..e83a219
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-mn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Нимгэн навигацийн самбарын туршилт (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-mr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-mr/strings.xml
new file mode 100644
index 0000000..e9ac6ee
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-mr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"स्लिम नॅव्हिगेशन बार प्रयोग (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ms/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ms/strings.xml
new file mode 100644
index 0000000..134293c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ms/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Pengalaman Bar Navigasi Nipis (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-my/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-my/strings.xml
new file mode 100644
index 0000000..a525c08
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-my/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"လမ်းညွှန်ဘားအသေး စမ်းသပ်မှု (၂၄dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-nb/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-nb/strings.xml
new file mode 100644
index 0000000..e431c90
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-nb/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Eksperiment med tynn navigasjonsrad (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ne/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ne/strings.xml
new file mode 100644
index 0000000..ff71d9a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ne/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"पातलो नेभिगेसन पट्टीको परीक्षण (२४dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-nl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-nl/strings.xml
new file mode 100644
index 0000000..b3a09cc
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-nl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Experiment voor smalle navigatiebalk (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-or/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-or/strings.xml
new file mode 100644
index 0000000..98ee79b
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-or/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"ସ୍ଲିମ୍ ନାଭିଗେସନ୍ ବାର୍‍ର ପ୍ରୟୋଗ (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pa/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pa/strings.xml
new file mode 100644
index 0000000..06e4fd5
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pa/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"ਸਲਿਮ ਦਿਸ਼ਾ-ਨਿਰਦੇਸ਼ ਪੱਟੀ ਪ੍ਰਯੋਗ (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pl/strings.xml
new file mode 100644
index 0000000..e466973
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Eksperyment z wąskim paskiem nawigacyjnym (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pt-rBR/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..df3c38a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pt-rBR/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Experimento de barra de navegação fina (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pt-rPT/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..dc72eab
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pt-rPT/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Experiência de barra de navegação fina (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pt/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pt/strings.xml
new file mode 100644
index 0000000..df3c38a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-pt/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Experimento de barra de navegação fina (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ro/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ro/strings.xml
new file mode 100644
index 0000000..dc9200c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ro/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Experiment cu bară de navigare subțire (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ru/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ru/strings.xml
new file mode 100644
index 0000000..99d5ce4
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ru/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Экспериментальная узкая панель навигации (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-si/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-si/strings.xml
new file mode 100644
index 0000000..501010f
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-si/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"සිහින් සංචලන තීරු පරීක්‍ෂණය (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sk/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sk/strings.xml
new file mode 100644
index 0000000..eaddff1
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Experiment s úzkym navigačným panelom (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sl/strings.xml
new file mode 100644
index 0000000..69d777e
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Preizkus z vitko vrstico za krmarjenje (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sq/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sq/strings.xml
new file mode 100644
index 0000000..9109a0e
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sq/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Eksperimenti i shiritit të hollë të navigimit (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sr/strings.xml
new file mode 100644
index 0000000..eb68b0b
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Експеримент са танком траком за навигацију (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sv/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sv/strings.xml
new file mode 100644
index 0000000..ed9ffa2
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sv/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Experimentellt tunt navigeringsfält (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sw/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sw/strings.xml
new file mode 100644
index 0000000..bf120d6
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-sw/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Jaribio la Sehemu ya Viungo Muhimu Inayoweza Kupunguzwa (dp 24)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ta/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ta/strings.xml
new file mode 100644
index 0000000..29590cf
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ta/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"மெலிதான வழிசெலுத்துதல் பட்டி சோதனை (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-te/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-te/strings.xml
new file mode 100644
index 0000000..fa95dec
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-te/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"సన్నని నావిగేషన్ పట్టీ ప్రయోగం (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-th/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-th/strings.xml
new file mode 100644
index 0000000..e46eda2
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-th/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"การทดสอบแถบนำทางแบบบาง (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-tl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-tl/strings.xml
new file mode 100644
index 0000000..3457f4b
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-tl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Eksperimentong Slim na Navigation Bar (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-tr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-tr/strings.xml
new file mode 100644
index 0000000..bab4695
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-tr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"İnce Gezinme Çubuğu Denemesi (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-uk/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-uk/strings.xml
new file mode 100644
index 0000000..8f790be
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-uk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Експеримент із тонкою панеллю навігації (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ur/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ur/strings.xml
new file mode 100644
index 0000000..a34cf80
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-ur/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"‏پتلے نیویگیشن بار کا تجربہ (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-uz/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-uz/strings.xml
new file mode 100644
index 0000000..a20309a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-uz/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Ingichka navigatsiya paneli tajribasi (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-vi/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-vi/strings.xml
new file mode 100644
index 0000000..530feeb
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-vi/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Thử nghiệm thanh điều hướng mỏng (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-zh-rCN/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..6472d4f
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-zh-rCN/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"精简导航栏实验 (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-zh-rHK/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..181e41c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-zh-rHK/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"精簡導覽列實驗 (24 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-zh-rTW/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..a6d53f4
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-zh-rTW/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"細長導覽列實驗 (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-zu/strings.xml b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-zu/strings.xml
new file mode 100644
index 0000000..338d906
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim24Overlay/res/values-zu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="9207872199884142345">"Ukuhlolwa kwebha yokuzulazula encane (24dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-af/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-af/strings.xml
new file mode 100644
index 0000000..e3d7313
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-af/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Eksperiment met dun navigasiebalk (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-am/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-am/strings.xml
new file mode 100644
index 0000000..f3128dd
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-am/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"የቀጭን ዳሰሳ አሞሌ ሙከራ (32 ዲፒ)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ar/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ar/strings.xml
new file mode 100644
index 0000000..670d09e
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ar/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"‏تجربة شريط التنقل الصغير الحجم (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-as/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-as/strings.xml
new file mode 100644
index 0000000..42d135a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-as/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"লাহী নেভিগে’শ্বন বাৰ সম্পৰীক্ষা (৩২ডিপি)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-az/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-az/strings.xml
new file mode 100644
index 0000000..ef07c44
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-az/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Ensiz Naviqasiya Paneli Təcrübəsi (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-b+sr+Latn/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..024e5d5
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-b+sr+Latn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Eksperiment sa tankom trakom za navigaciju (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-be/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-be/strings.xml
new file mode 100644
index 0000000..71ffb20
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-be/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Эксперымент з тонкай панэллю навігацыі (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-bg/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-bg/strings.xml
new file mode 100644
index 0000000..fc159b2
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-bg/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Експеримент с тънка лента за навигация (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-bn/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-bn/strings.xml
new file mode 100644
index 0000000..cba2ffb
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-bn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"স্লিম নেভিগেশন বার সম্পর্কিত পরীক্ষা (৩২ ডিপি)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-bs/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-bs/strings.xml
new file mode 100644
index 0000000..378c39b
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-bs/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Eksperiment s tankom trakom za navigaciju (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ca/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ca/strings.xml
new file mode 100644
index 0000000..6b5c71b
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ca/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Experiment amb barra de navegació fina (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-cs/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-cs/strings.xml
new file mode 100644
index 0000000..c779583
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-cs/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Úzký navigační panel – experiment (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-da/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-da/strings.xml
new file mode 100644
index 0000000..2f83f76
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-da/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Test med smal navigationslinje (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-de/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-de/strings.xml
new file mode 100644
index 0000000..2446b8a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-de/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Test mit schmaler Navigationsleiste (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-el/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-el/strings.xml
new file mode 100644
index 0000000..97c52cf4
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-el/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Πείραμα λεπτής γραμμής πλοήγησης (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-en-rAU/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..90e7fae
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-en-rAU/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Slim Navigation Bar Experiment (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-en-rCA/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..90e7fae
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-en-rCA/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Slim Navigation Bar Experiment (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-en-rGB/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..90e7fae
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-en-rGB/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Slim Navigation Bar Experiment (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-en-rIN/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..90e7fae
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-en-rIN/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Slim Navigation Bar Experiment (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-es-rUS/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..02bb563
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-es-rUS/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Experimento de la barra navegación delgada (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-es/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-es/strings.xml
new file mode 100644
index 0000000..02bb563
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-es/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Experimento de la barra navegación delgada (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-et/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-et/strings.xml
new file mode 100644
index 0000000..d979cc3
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-et/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Kitsa navigeerimisriba katse (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-eu/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-eu/strings.xml
new file mode 100644
index 0000000..a9b869c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-eu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Nabigazio-barra finaren esperimentua (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-fa/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-fa/strings.xml
new file mode 100644
index 0000000..fb724e0
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-fa/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"‏آزمایش نوار پیمایش باریک (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-fi/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-fi/strings.xml
new file mode 100644
index 0000000..88fa2b9
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-fi/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Ohuen navigointipalkin kokeilu (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-fr-rCA/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..2a73bd3
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-fr-rCA/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Expérience de barre de navigation mince (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-fr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-fr/strings.xml
new file mode 100644
index 0000000..1530d81
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-fr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Test relatif à la barre de navigation fine (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-gl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-gl/strings.xml
new file mode 100644
index 0000000..174f501
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-gl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Experimento da barra de navegación estreita (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-gu/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-gu/strings.xml
new file mode 100644
index 0000000..1e9de62
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-gu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"સ્લિમ નૅવિગેશન બારનો પ્રયોગ (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-hi/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-hi/strings.xml
new file mode 100644
index 0000000..f52b1fd
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-hi/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"स्लिम नेविगेशन बार प्रयोग (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-hr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-hr/strings.xml
new file mode 100644
index 0000000..04aed15
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-hr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Eksperiment s tankom navigacijskom trakom (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-hu/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-hu/strings.xml
new file mode 100644
index 0000000..500b45e
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-hu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Kísérleti keskeny navigációs sáv (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-hy/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-hy/strings.xml
new file mode 100644
index 0000000..a5f684b
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-hy/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Նավարկման նեղ գոտու փորձարկում (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-in/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-in/strings.xml
new file mode 100644
index 0000000..fe78b4c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-in/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Eksperimen Menu Navigasi Ramping (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-is/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-is/strings.xml
new file mode 100644
index 0000000..1d6da50
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-is/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Tilraun með þunna yfirlitsstiku (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-it/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-it/strings.xml
new file mode 100644
index 0000000..dc3530e
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-it/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Esperimento Barra di navigazione sottile (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-iw/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-iw/strings.xml
new file mode 100644
index 0000000..8832941
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-iw/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"‏ניסוי של סרגל ניווט דק (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ja/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ja/strings.xml
new file mode 100644
index 0000000..7bab58a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ja/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"スリム ナビゲーション バー テスト(32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ka/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ka/strings.xml
new file mode 100644
index 0000000..8a7f3bf
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ka/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"ნავიგაციის მჭიდრო ზოლის ექსპერიმენტი (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-kk/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-kk/strings.xml
new file mode 100644
index 0000000..182ac1a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-kk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Жіңішке навигация жолағы (эксперимент) (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-km/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-km/strings.xml
new file mode 100644
index 0000000..0a52f66
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-km/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"ការពិសោធ​នៃ​របាររុករក​ស្ដើង (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-kn/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-kn/strings.xml
new file mode 100644
index 0000000..118303f
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-kn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"ಸ್ಲಿಮ್ ನ್ಯಾವಿಗೇಶನ್‌ ಬಾರ್‌ ಪ್ರಯೋಗ (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ko/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ko/strings.xml
new file mode 100644
index 0000000..11f28ce
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ko/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"슬림한 탐색 메뉴 실험(32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ky/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ky/strings.xml
new file mode 100644
index 0000000..4418c4d
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ky/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Чакан чабыттоо тилкесин сыноо (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-lo/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-lo/strings.xml
new file mode 100644
index 0000000..090ab09
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-lo/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"ການທົດສອບແຖບນໍາທາງແບບບາງ (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-lt/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-lt/strings.xml
new file mode 100644
index 0000000..cb72a0f
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-lt/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Plonos naršymo juostos eksperimentas (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-lv/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-lv/strings.xml
new file mode 100644
index 0000000..164e7d2
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-lv/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Plānas navigācijas joslas eksperiments (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-mk/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-mk/strings.xml
new file mode 100644
index 0000000..e10d685
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-mk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Експеримент со тенка лента за навигација (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ml/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ml/strings.xml
new file mode 100644
index 0000000..878ea10
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ml/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"സ്ലിം നാവിഗേഷൻ ബാർ പരീക്ഷണം (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-mn/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-mn/strings.xml
new file mode 100644
index 0000000..a808c5c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-mn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Нимгэн навигацийн самбарын туршилт (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-mr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-mr/strings.xml
new file mode 100644
index 0000000..8454ba7
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-mr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"स्लिम नॅव्हिगेशन बार प्रयोग (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ms/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ms/strings.xml
new file mode 100644
index 0000000..6494245
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ms/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Pengalaman Bar Navigasi Nipis (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-my/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-my/strings.xml
new file mode 100644
index 0000000..11586c0
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-my/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"လမ်းညွှန်ဘားအသေး စမ်းသပ်မှု (၃၂dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-nb/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-nb/strings.xml
new file mode 100644
index 0000000..625c605
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-nb/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Eksperiment med tynn navigasjonsrad (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ne/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ne/strings.xml
new file mode 100644
index 0000000..b0d019c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ne/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"पातलो नेभिगेसन पट्टीको परीक्षण (३२dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-nl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-nl/strings.xml
new file mode 100644
index 0000000..9d14cef
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-nl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Experiment voor smalle navigatiebalk (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-or/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-or/strings.xml
new file mode 100644
index 0000000..e941c52
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-or/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"ସ୍ଲିମ୍ ନାଭିଗେସନ୍ ବାର୍‍ର ପ୍ରୟୋଗ (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pa/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pa/strings.xml
new file mode 100644
index 0000000..c85e9d6
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pa/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"ਸਲਿਮ ਦਿਸ਼ਾ-ਨਿਰਦੇਸ਼ ਪੱਟੀ ਪ੍ਰਯੋਗ (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pl/strings.xml
new file mode 100644
index 0000000..a254e62
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Eksperyment z wąskim paskiem nawigacyjnym (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pt-rBR/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..8bab19c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pt-rBR/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Experimento de barra de navegação fina (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pt-rPT/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..133d97d
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pt-rPT/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Experiência de barra de navegação fina (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pt/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pt/strings.xml
new file mode 100644
index 0000000..8bab19c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-pt/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Experimento de barra de navegação fina (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ro/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ro/strings.xml
new file mode 100644
index 0000000..f1518718
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ro/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Experiment cu bară de navigare subțire (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ru/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ru/strings.xml
new file mode 100644
index 0000000..3031ae0
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ru/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Экспериментальная узкая панель навигации (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-si/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-si/strings.xml
new file mode 100644
index 0000000..a257a76
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-si/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"සිහින් සංචලන තීරු පරීක්‍ෂණය (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sk/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sk/strings.xml
new file mode 100644
index 0000000..f9fe39b
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Experiment s úzkym navigačným panelom (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sl/strings.xml
new file mode 100644
index 0000000..5849b03
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Preizkus z vitko vrstico za krmarjenje (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sq/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sq/strings.xml
new file mode 100644
index 0000000..719f233
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sq/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Eksperimenti i shiritit të hollë të navigimit (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sr/strings.xml
new file mode 100644
index 0000000..3d67560
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Експеримент са танком траком за навигацију (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sv/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sv/strings.xml
new file mode 100644
index 0000000..daee00a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sv/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Experimentellt tunt navigeringsfält (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sw/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sw/strings.xml
new file mode 100644
index 0000000..cf44256
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-sw/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Jaribio la Sehemu ya Viungo Muhimu Inayoweza Kupunguzwa (dp 32)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ta/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ta/strings.xml
new file mode 100644
index 0000000..e69442a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ta/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"மெலிதான வழிசெலுத்துதல் பட்டி சோதனை (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-te/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-te/strings.xml
new file mode 100644
index 0000000..5a39ccf
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-te/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"సన్నని నావిగేషన్ పట్టీ ప్రయోగం (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-th/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-th/strings.xml
new file mode 100644
index 0000000..e197554
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-th/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"การทดสอบแถบนำทางแบบบาง (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-tl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-tl/strings.xml
new file mode 100644
index 0000000..bbaa96f
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-tl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Eksperimentong Slim na Navigation Bar (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-tr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-tr/strings.xml
new file mode 100644
index 0000000..d315cf4
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-tr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"İnce Gezinme Çubuğu Denemesi (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-uk/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-uk/strings.xml
new file mode 100644
index 0000000..e75f766
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-uk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Експеримент із тонкою панеллю навігації (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ur/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ur/strings.xml
new file mode 100644
index 0000000..743903d
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-ur/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"‏پتلے نیویگیشن بار کا تجربہ (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-uz/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-uz/strings.xml
new file mode 100644
index 0000000..d8519a7
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-uz/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Ingichka navigatsiya paneli tajribasi (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-vi/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-vi/strings.xml
new file mode 100644
index 0000000..bc22ff8
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-vi/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Thử nghiệm thanh điều hướng mỏng (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-zh-rCN/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..b0e6f58
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-zh-rCN/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"精简导航栏实验 (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-zh-rHK/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..5dd0d79
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-zh-rHK/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"精簡導覽列實驗 (32 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-zh-rTW/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..b1f6b06
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-zh-rTW/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"細長導覽列實驗 (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-zu/strings.xml b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-zu/strings.xml
new file mode 100644
index 0000000..9a8bb4f
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim32Overlay/res/values-zu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="2616250866244714325">"Ukuhlolwa kwebha yokuzulazula encane (32dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-af/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-af/strings.xml
new file mode 100644
index 0000000..e815299
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-af/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Eksperiment met dun navigasiebalk (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-am/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-am/strings.xml
new file mode 100644
index 0000000..5644a85
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-am/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"የቀጭን ዳሰሳ አሞሌ ሙከራ (40 ዲፒ)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ar/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ar/strings.xml
new file mode 100644
index 0000000..40a11de
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ar/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"‏تجربة شريط التنقل الصغير الحجم (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-as/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-as/strings.xml
new file mode 100644
index 0000000..1c4003f
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-as/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"লাহী নেভিগে’শ্বন বাৰ সম্পৰীক্ষা (৪০ডিপি)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-az/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-az/strings.xml
new file mode 100644
index 0000000..5897e75
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-az/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Ensiz Naviqasiya Paneli Təcrübəsi (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-b+sr+Latn/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..1f49607
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-b+sr+Latn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Eksperiment sa tankom trakom za navigaciju (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-be/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-be/strings.xml
new file mode 100644
index 0000000..2c46430
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-be/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Эксперымент з тонкай панэллю навігацыі (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-bg/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-bg/strings.xml
new file mode 100644
index 0000000..25a1496
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-bg/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Експеримент с тънка лента за навигация (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-bn/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-bn/strings.xml
new file mode 100644
index 0000000..66ba5b0
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-bn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"স্লিম নেভিগেশন বার সম্পর্কিত পরীক্ষা (৪০ ডিপি)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-bs/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-bs/strings.xml
new file mode 100644
index 0000000..21597ce
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-bs/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Eksperiment s tankom trakom za navigaciju (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ca/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ca/strings.xml
new file mode 100644
index 0000000..34ce751
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ca/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Experiment amb barra de navegació fina (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-cs/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-cs/strings.xml
new file mode 100644
index 0000000..cd87611
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-cs/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Úzký navigační panel – experiment (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-da/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-da/strings.xml
new file mode 100644
index 0000000..fcbd7b5
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-da/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Test med smal navigationslinje (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-de/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-de/strings.xml
new file mode 100644
index 0000000..8ee35b7
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-de/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Test mit schmaler Navigationsleiste (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-el/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-el/strings.xml
new file mode 100644
index 0000000..c016e83
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-el/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Πείραμα λεπτής γραμμής πλοήγησης (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-en-rAU/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..b3621cb
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-en-rAU/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Slim Navigation Bar Experiment (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-en-rCA/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..b3621cb
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-en-rCA/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Slim Navigation Bar Experiment (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-en-rGB/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..b3621cb
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-en-rGB/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Slim Navigation Bar Experiment (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-en-rIN/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..b3621cb
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-en-rIN/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Slim Navigation Bar Experiment (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-es-rUS/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..d1cc0fe
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-es-rUS/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Experimento de la barra navegación delgada (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-es/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-es/strings.xml
new file mode 100644
index 0000000..d1cc0fe
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-es/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Experimento de la barra navegación delgada (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-et/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-et/strings.xml
new file mode 100644
index 0000000..64dc9ae
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-et/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Kitsa navigeerimisriba katse (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-eu/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-eu/strings.xml
new file mode 100644
index 0000000..98a4dd9
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-eu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Nabigazio-barra finaren esperimentua (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-fa/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-fa/strings.xml
new file mode 100644
index 0000000..987ab4a
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-fa/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"‏آزمایش نوار پیمایش باریک (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-fi/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-fi/strings.xml
new file mode 100644
index 0000000..e850c3f
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-fi/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Ohuen navigointipalkin kokeilu (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-fr-rCA/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..c196ef9
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-fr-rCA/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Expérience de barre de navigation mince (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-fr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-fr/strings.xml
new file mode 100644
index 0000000..dd1ec9c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-fr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Test relatif à la barre de navigation fine (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-gl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-gl/strings.xml
new file mode 100644
index 0000000..5c44987
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-gl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Experimento da barra de navegación estreita (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-gu/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-gu/strings.xml
new file mode 100644
index 0000000..ed1f5ce
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-gu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"સ્લિમ નૅવિગેશન બારનો પ્રયોગ (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-hi/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-hi/strings.xml
new file mode 100644
index 0000000..64141ce
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-hi/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"स्लिम नेविगेशन बार प्रयोग (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-hr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-hr/strings.xml
new file mode 100644
index 0000000..41ec2e7
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-hr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Eksperiment s tankom navigacijskom trakom (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-hu/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-hu/strings.xml
new file mode 100644
index 0000000..3fb2907
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-hu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Kísérleti keskeny navigációs sáv (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-hy/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-hy/strings.xml
new file mode 100644
index 0000000..04d6995
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-hy/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Նավարկման նեղ գոտու փորձարկում (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-in/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-in/strings.xml
new file mode 100644
index 0000000..2f01577
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-in/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Eksperimen Menu Navigasi Ramping (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-is/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-is/strings.xml
new file mode 100644
index 0000000..5ccf607
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-is/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Tilraun með þunna yfirlitsstiku (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-it/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-it/strings.xml
new file mode 100644
index 0000000..1522bd3
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-it/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Esperimento Barra di navigazione sottile (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-iw/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-iw/strings.xml
new file mode 100644
index 0000000..cf40958
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-iw/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"‏ניסוי של סרגל ניווט דק (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ja/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ja/strings.xml
new file mode 100644
index 0000000..51797e6
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ja/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"スリム ナビゲーション バー テスト(40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ka/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ka/strings.xml
new file mode 100644
index 0000000..575b453
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ka/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"ნავიგაციის მჭიდრო ზოლის ექსპერიმენტი (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-kk/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-kk/strings.xml
new file mode 100644
index 0000000..4febe3f
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-kk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Жіңішке навигация жолағы (эксперимент) (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-km/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-km/strings.xml
new file mode 100644
index 0000000..58b9e16
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-km/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"ការពិសោធ​នៃ​របាររុករក​ស្ដើង (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-kn/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-kn/strings.xml
new file mode 100644
index 0000000..35a6776
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-kn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"ಸ್ಲಿಮ್ ನ್ಯಾವಿಗೇಶನ್‌ ಬಾರ್‌ ಪ್ರಯೋಗ (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ko/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ko/strings.xml
new file mode 100644
index 0000000..bced462
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ko/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"슬림한 탐색 메뉴 실험(40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ky/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ky/strings.xml
new file mode 100644
index 0000000..8b34990
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ky/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Чакан чабыттоо тилкесин сыноо (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-lo/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-lo/strings.xml
new file mode 100644
index 0000000..b7fe3cf
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-lo/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"ການທົດສອບແຖບນໍາທາງແບບບາງ (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-lt/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-lt/strings.xml
new file mode 100644
index 0000000..808a90c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-lt/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Plonos naršymo juostos eksperimentas (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-lv/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-lv/strings.xml
new file mode 100644
index 0000000..002e8687
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-lv/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Plānas navigācijas joslas eksperiments (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-mk/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-mk/strings.xml
new file mode 100644
index 0000000..148b5ed
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-mk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Експеримент со тенка лента за навигација (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ml/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ml/strings.xml
new file mode 100644
index 0000000..be37488
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ml/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"സ്ലിം നാവിഗേഷൻ ബാർ പരീക്ഷണം (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-mn/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-mn/strings.xml
new file mode 100644
index 0000000..41e2ce1
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-mn/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Нимгэн навигацийн самбарын туршилт (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-mr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-mr/strings.xml
new file mode 100644
index 0000000..d946257
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-mr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"स्लिम नॅव्हिगेशन बार प्रयोग (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ms/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ms/strings.xml
new file mode 100644
index 0000000..a442be3
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ms/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Pengalaman Bar Navigasi Nipis (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-my/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-my/strings.xml
new file mode 100644
index 0000000..f12cf41
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-my/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"လမ်းညွှန်ဘားအသေး စမ်းသပ်မှု (၄၀dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-nb/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-nb/strings.xml
new file mode 100644
index 0000000..d138836
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-nb/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Eksperiment med tynn navigasjonsrad (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ne/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ne/strings.xml
new file mode 100644
index 0000000..9fce6c2
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ne/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"पातलो नेभिगेसन पट्टीको परीक्षण (४०dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-nl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-nl/strings.xml
new file mode 100644
index 0000000..8eae8ce
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-nl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Experiment voor smalle navigatiebalk (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-or/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-or/strings.xml
new file mode 100644
index 0000000..aff8e9c
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-or/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"ସ୍ଲିମ୍ ନାଭିଗେସନ୍‍ ବାର୍‍ର ପ୍ରୟୋଗ (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pa/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pa/strings.xml
new file mode 100644
index 0000000..c23a03f
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pa/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"ਸਲਿਮ ਦਿਸ਼ਾ-ਨਿਰਦੇਸ਼ ਪੱਟੀ ਪ੍ਰਯੋਗ (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pl/strings.xml
new file mode 100644
index 0000000..7cd3e4e
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Eksperyment z wąskim paskiem nawigacyjnym (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pt-rBR/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..dbc47fd
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pt-rBR/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Experimento de barra de navegação fina (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pt-rPT/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..82ef087
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pt-rPT/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Experiência de barra de navegação fina (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pt/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pt/strings.xml
new file mode 100644
index 0000000..dbc47fd
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-pt/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Experimento de barra de navegação fina (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ro/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ro/strings.xml
new file mode 100644
index 0000000..18a96e0
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ro/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Experiment cu bară de navigare subțire (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ru/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ru/strings.xml
new file mode 100644
index 0000000..195ab10
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ru/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Экспериментальная узкая панель навигации (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-si/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-si/strings.xml
new file mode 100644
index 0000000..0bda351
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-si/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"සිහින් සංචලන තීරු පරීක්‍ෂණය (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sk/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sk/strings.xml
new file mode 100644
index 0000000..9aebdfbe
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Experiment s úzkym navigačným panelom (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sl/strings.xml
new file mode 100644
index 0000000..68f6e6d
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Preizkus z vitko vrstico za krmarjenje (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sq/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sq/strings.xml
new file mode 100644
index 0000000..18c1ff0
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sq/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Eksperimenti i shiritit të hollë të navigimit (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sr/strings.xml
new file mode 100644
index 0000000..8067165
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Експеримент са танком траком за навигацију (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sv/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sv/strings.xml
new file mode 100644
index 0000000..d91626e
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sv/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Experimentellt tunt navigeringsfält (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sw/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sw/strings.xml
new file mode 100644
index 0000000..f3ca208
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-sw/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Jaribio la Sehemu ya Viungo Muhimu Inayoweza Kupunguzwa (dp 40)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ta/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ta/strings.xml
new file mode 100644
index 0000000..04bee67
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ta/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"மெலிதான வழிசெலுத்துதல் பட்டி சோதனை (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-te/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-te/strings.xml
new file mode 100644
index 0000000..fc0cd55
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-te/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"సన్నని నావిగేషన్ పట్టీ ప్రయోగం (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-th/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-th/strings.xml
new file mode 100644
index 0000000..33d46e4
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-th/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"การทดสอบแถบนำทางแบบบาง (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-tl/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-tl/strings.xml
new file mode 100644
index 0000000..bf6451f
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-tl/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Eksperimentong Slim na Navigation Bar (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-tr/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-tr/strings.xml
new file mode 100644
index 0000000..7918059
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-tr/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"İnce Gezinme  Çubuğu Denemesi (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-uk/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-uk/strings.xml
new file mode 100644
index 0000000..b45b9b4
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-uk/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Експеримент із тонкою панеллю навігації (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ur/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ur/strings.xml
new file mode 100644
index 0000000..9281ff8
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-ur/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"‏پتلے نیویگیشن بار کا تجربہ (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-uz/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-uz/strings.xml
new file mode 100644
index 0000000..46e7334
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-uz/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Ingichka navigatsiya paneli tajribasi (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-vi/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-vi/strings.xml
new file mode 100644
index 0000000..ea0f155
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-vi/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Thử nghiệm thanh điều hướng mỏng (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-zh-rCN/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..5746854
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-zh-rCN/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"精简导航栏实验 (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-zh-rHK/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..aad885b
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-zh-rHK/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"精簡導覽列實驗 (40 dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-zh-rTW/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..590e4f5
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-zh-rTW/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"細長導覽列實驗 (40dp)"</string>
+</resources>
diff --git a/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-zu/strings.xml b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-zu/strings.xml
new file mode 100644
index 0000000..e077f08
--- /dev/null
+++ b/packages/overlays/ExperimentNavigationBarSlim40Overlay/res/values-zu/strings.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.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="experiment_navigationbar_overlay" msgid="6415947279345789008">"Ukuhlolwa kwebha yokuzulazula encane (40dp)"</string>
+</resources>
diff --git a/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml b/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml
index 165aab2..a6aa64c 100644
--- a/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml
+++ b/packages/overlays/FontArbutusSourceOverlay/res/values/config.xml
@@ -19,7 +19,7 @@
      <!-- Name of a font family to use for body text. -->
     <string name="config_bodyFontFamily" translatable="false">source-sans-pro</string>
     <!-- Name of a font family to use for medium body text. -->
-    <string name="config_bodyFontFamilyMedium" translatable="false">source-sans-pro-medium</string>
+    <string name="config_bodyFontFamilyMedium" translatable="false">source-sans-pro-semi-bold</string>
     <!-- Name of a font family to use for headlines. If empty, falls back to platform default -->
     <string name="config_headlineFontFamily" translatable="false">arbutus-slab</string>
     <!-- Name of the font family used for system surfaces where the font should use medium weight -->
diff --git a/packages/overlays/FontArvoLatoOverlay/res/values/config.xml b/packages/overlays/FontArvoLatoOverlay/res/values/config.xml
index 229c578..4e70d72 100644
--- a/packages/overlays/FontArvoLatoOverlay/res/values/config.xml
+++ b/packages/overlays/FontArvoLatoOverlay/res/values/config.xml
@@ -19,10 +19,10 @@
      <!-- Name of a font family to use for body text. -->
     <string name="config_bodyFontFamily" translatable="false">lato</string>
     <!-- Name of a font family to use for medium body text. -->
-    <string name="config_bodyFontFamilyMedium" translatable="false">lato-medium</string>
+    <string name="config_bodyFontFamilyMedium" translatable="false">lato-bold</string>
     <!-- Name of a font family to use for headlines. If empty, falls back to platform default -->
     <string name="config_headlineFontFamily" translatable="false">arvo</string>
     <!-- Name of the font family used for system surfaces where the font should use medium weight -->
-    <string name="config_headlineFontFamilyMedium" translatable="false">arvo-medium</string>
+    <string name="config_headlineFontFamilyMedium" translatable="false">arvo-bold</string>
 </resources>
 
diff --git a/packages/overlays/IconShapeRoundedRectOverlay/res/values/strings.xml b/packages/overlays/IconShapeRoundedRectOverlay/res/values/strings.xml
index dc5c196..3c4c24d 100644
--- a/packages/overlays/IconShapeRoundedRectOverlay/res/values/strings.xml
+++ b/packages/overlays/IconShapeRoundedRectOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Rounded corner rectangle overlay -->
-    <string name="icon_shape_roundedrect_overlay" translatable="false">RoundedRectangle Icons</string>
+    <string name="icon_shape_roundedrect_overlay" translatable="false">Rounded Rectangle</string>
 
 </resources>
diff --git a/packages/overlays/IconShapeSquareOverlay/res/values/strings.xml b/packages/overlays/IconShapeSquareOverlay/res/values/strings.xml
index 4fd39ff26..5772165 100644
--- a/packages/overlays/IconShapeSquareOverlay/res/values/strings.xml
+++ b/packages/overlays/IconShapeSquareOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Square icon overlay -->
-    <string name="icon_shape_square_overlay" translatable="false">Square Icons</string>
+    <string name="icon_shape_square_overlay" translatable="false">Square</string>
 
 </resources>
diff --git a/packages/overlays/IconShapeSquircleOverlay/res/values/strings.xml b/packages/overlays/IconShapeSquircleOverlay/res/values/strings.xml
index b7c001c..028eccb 100644
--- a/packages/overlays/IconShapeSquircleOverlay/res/values/strings.xml
+++ b/packages/overlays/IconShapeSquircleOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Squircle icon shape overlay -->
-    <string name="icon_shape_squircle_overlay" translatable="false">Square Icons</string>
+    <string name="icon_shape_squircle_overlay" translatable="false">Squircle</string>
 
 </resources>
diff --git a/packages/overlays/IconShapeTeardropOverlay/res/values/strings.xml b/packages/overlays/IconShapeTeardropOverlay/res/values/strings.xml
index d946ee8..db9fa98 100644
--- a/packages/overlays/IconShapeTeardropOverlay/res/values/strings.xml
+++ b/packages/overlays/IconShapeTeardropOverlay/res/values/strings.xml
@@ -18,6 +18,6 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Teardrop icon overlay -->
-    <string name="icon_shape_teardrop_overlay" translatable="false">Teardrop Icons</string>
+    <string name="icon_shape_teardrop_overlay" translatable="false">Teardrop</string>
 
 </resources>
diff --git a/packages/services/PacProcessor/Android.mk b/packages/services/PacProcessor/Android.mk
index 295b3d8b..be9ba43 100644
--- a/packages/services/PacProcessor/Android.mk
+++ b/packages/services/PacProcessor/Android.mk
@@ -26,6 +26,6 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 LOCAL_CERTIFICATE := platform
 
-LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor libpac
+LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor
 
 include $(BUILD_PACKAGE)
diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
index 846ff25..d969c69 100644
--- a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
+++ b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
@@ -16,6 +16,9 @@
 
 #define LOG_TAG "PacProcessor"
 
+#include <stdlib.h>
+#include <string>
+
 #include <utils/Log.h>
 #include <utils/Mutex.h>
 #include "android_runtime/AndroidRuntime.h"
@@ -23,40 +26,24 @@
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 
-#include "proxy_resolver_v8.h"
+#include "proxy_resolver_v8_wrapper.h"
 
 namespace android {
 
-class ProxyErrorLogger : public net::ProxyErrorListener {
-public:
-    ~ProxyErrorLogger() {
-
-    }
-    void AlertMessage(String16 message) {
-        String8 str(message);
-        ALOGD("Alert: %s", str.string());
-    }
-    void ErrorMessage(String16 message) {
-        String8 str(message);
-        ALOGE("Error: %s", str.string());
-    }
-};
-
-net::ProxyResolverV8* proxyResolver = NULL;
-ProxyErrorLogger* logger = NULL;
+ProxyResolverV8Handle* proxyResolver = NULL;
 bool pacSet = false;
 
-String16 jstringToString16(JNIEnv* env, jstring jstr) {
+std::u16string jstringToString16(JNIEnv* env, jstring jstr) {
     const jchar* str = env->GetStringCritical(jstr, 0);
-    String16 str16(reinterpret_cast<const char16_t*>(str),
+    std::u16string str16(reinterpret_cast<const char16_t*>(str),
                    env->GetStringLength(jstr));
     env->ReleaseStringCritical(jstr, str);
     return str16;
 }
 
-jstring string16ToJstring(JNIEnv* env, String16 string) {
-    const char16_t* str = string.string();
-    size_t len = string.size();
+jstring string16ToJstring(JNIEnv* env, std::u16string string) {
+    const char16_t* str = string.data();
+    size_t len = string.length();
 
     return env->NewString(reinterpret_cast<const jchar*>(str), len);
 }
@@ -64,9 +51,7 @@
 static jboolean com_android_pacprocessor_PacNative_createV8ParserNativeLocked(JNIEnv* /* env */,
         jobject) {
     if (proxyResolver == NULL) {
-        logger = new ProxyErrorLogger();
-        proxyResolver = new net::ProxyResolverV8(net::ProxyResolverJSBindings::CreateDefault(),
-                logger);
+        proxyResolver = ProxyResolverV8Handle_new();
         pacSet = false;
         return JNI_FALSE;
     }
@@ -76,9 +61,7 @@
 static jboolean com_android_pacprocessor_PacNative_destroyV8ParserNativeLocked(JNIEnv* /* env */,
         jobject) {
     if (proxyResolver != NULL) {
-        delete logger;
-        delete proxyResolver;
-        logger = NULL;
+        ProxyResolverV8Handle_delete(proxyResolver);
         proxyResolver = NULL;
         return JNI_FALSE;
     }
@@ -87,14 +70,14 @@
 
 static jboolean com_android_pacprocessor_PacNative_setProxyScriptNativeLocked(JNIEnv* env, jobject,
         jstring script) {
-    String16 script16 = jstringToString16(env, script);
+    std::u16string script16 = jstringToString16(env, script);
 
     if (proxyResolver == NULL) {
         ALOGE("V8 Parser not started when setting PAC script");
         return JNI_TRUE;
     }
 
-    if (proxyResolver->SetPacScript(script16) != OK) {
+    if (ProxyResolverV8Handle_SetPacScript(proxyResolver, script16.data()) != OK) {
         ALOGE("Unable to set PAC script");
         return JNI_TRUE;
     }
@@ -105,9 +88,8 @@
 
 static jstring com_android_pacprocessor_PacNative_makeProxyRequestNativeLocked(JNIEnv* env, jobject,
         jstring url, jstring host) {
-    String16 url16 = jstringToString16(env, url);
-    String16 host16 = jstringToString16(env, host);
-    String16 ret;
+    std::u16string url16 = jstringToString16(env, url);
+    std::u16string host16 = jstringToString16(env, host);
 
     if (proxyResolver == NULL) {
         ALOGE("V8 Parser not initialized when running PAC script");
@@ -119,12 +101,14 @@
         return NULL;
     }
 
-    if (proxyResolver->GetProxyForURL(url16, host16, &ret) != OK) {
-        String8 ret8(ret);
-        ALOGE("Error Running PAC: %s", ret8.string());
+    std::unique_ptr<char16_t, decltype(&free)> result = std::unique_ptr<char16_t, decltype(&free)>(
+        ProxyResolverV8Handle_GetProxyForURL(proxyResolver, url16.data(), host16.data()), &free);
+    if (result.get() == NULL) {
+        ALOGE("Error Running PAC");
         return NULL;
     }
 
+    std::u16string ret(result.get());
     jstring jret = string16ToJstring(env, ret);
 
     return jret;
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 3180b47..efa4e79 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -73,6 +73,10 @@
 
     // The view switched to summary mode (most relevant for notifications)
     TYPE_COLLAPSE = 14;
+
+    // The notification was adjusted by the assistant. Enum value is
+    // out of sequence due to b/122737498.
+    TYPE_NOTIFICATION_ASSISTANT_ADJUSTMENT = 1573;
   }
 
   // Types of alerts, as bit field values
@@ -213,6 +217,36 @@
         IOOP_SYNC = 4;
     }
 
+  // Subtypes of notifications blocking helper view
+  // (NOTIFICATION_BLOCKING_HELPER).
+  enum NotificationBlockingHelper {
+    BLOCKING_HELPER_UNKNOWN = 0;
+    BLOCKING_HELPER_DISPLAY = 1;
+    BLOCKING_HELPER_DISMISS = 2;
+    // When the view of the notification blocking helper was triggered by
+    // system.
+    BLOCKING_HELPER_TRIGGERED_BY_SYSTEM = 3;
+    // "block" was clicked.
+    BLOCKING_HELPER_CLICK_BLOCKED = 4;
+    // "stay silent" was clicked.
+    BLOCKING_HELPER_CLICK_STAY_SILENT = 5;
+    // "alert me" was clicked.
+    BLOCKING_HELPER_CLICK_ALERT_ME = 6;
+    // "undo" was clicked (enables the user to undo "stop notification" action).
+    BLOCKING_HELPER_CLICK_UNDO = 7;
+  }
+
+  // The (visual) location of a Notification.
+  enum NotificationLocation {
+    LOCATION_UNKNOWN = 0;
+    LOCATION_FIRST_HEADS_UP = 1; // visible heads-up
+    LOCATION_HIDDEN_TOP = 2; // hidden/scrolled away on the top
+    LOCATION_MAIN_AREA = 3; // visible in the shade
+    LOCATION_BOTTOM_STACK_PEEKING = 4; // in the bottom stack, and peeking
+    LOCATION_BOTTOM_STACK_HIDDEN = 5; // in the bottom stack, and hidden
+    LOCATION_GONE = 6; // the view isn't laid out at all
+  }
+
   // Known visual elements: views or controls.
   enum View {
     // Unknown view
@@ -3684,7 +3718,7 @@
     ACTION_SETTINGS_TILE_CLICK = 830;
 
     // OPEN: Notification unsnoozed. CLOSE: Notification snoozed. UPDATE: snoozed notification
-    // updated
+    // updated. TYPE_DISMISS: snoozing canceled due to data being cleared on package
     // CATEGORY: NOTIFICATION
     // OS: O
     NOTIFICATION_SNOOZED = 831;
@@ -4030,6 +4064,8 @@
     // - 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
+    // Tag FIELD_AUTOFILL_NUMBER_AUGMENTED_REQUESTS: number of requests made to the augmented
+    //     autofill service
     AUTOFILL_REQUEST = 907;
 
     // Tag of a field for a package of an autofill service
@@ -5325,7 +5361,7 @@
     // OS: P
     ACCESSIBILITY_VIBRATION = 1292;
 
-    // OPEN: Settings > Accessibility > Vibration > Ring & notification vibration
+    // OPEN: Settings > Accessibility > Vibration > Notification vibration
     // CATEGORY: SETTINGS
     // OS: P
     ACCESSIBILITY_VIBRATION_NOTIFICATION = 1293;
@@ -6730,8 +6766,103 @@
     // OS: Q
     ZEN_CUSTOM_SETTINGS_DIALOG = 1612;
 
-    // ---- End Q Constants, all Q constants go above this line ----
+    // OPEN: Settings > Developer Options > Game Update Packages
+    // CATEGORY: SETTINGS
+    // OS: Q
+    SETTINGS_GUP_DASHBOARD = 1613;
 
+    // CATEGORY: The category for all actions relating to language detection logging.
+    // OS: Q
+    LANGUAGE_DETECTION = 1614;
+
+    // CATEGORY: The category for all actions relating to conversation actions logging.
+    // OS: Q
+    CONVERSATION_ACTIONS = 1615;
+
+    // ACTION: Actions from a text classifier are shown to user.
+    // CATEGORY: CONVERSATION_ACTIONS
+    // OS: Q
+    ACTION_TEXT_CLASSIFIER_ACTIONS_SHOWN = 1616;
+
+    // ACTION: Event time of a text classifier event in unix timestamp.
+    // CATEGORY: CONVERSATION_ACTIONS, LANGUAGE_DETECTION
+    // OS: Q
+    FIELD_TEXT_CLASSIFIER_EVENT_TIME = 1617;
+
+    // ACTION: Users compose their own replies instead of using suggested ones.
+    // CATEGORY: CONVERSATION_ACTIONS
+    // OS: Q
+    ACTION_TEXT_CLASSIFIER_MANUAL_REPLY = 1618;
+
+    // ACTION: Text classifier generates an action.
+    // CATEGORY: CONVERSATION_ACTIONS
+    // OS: Q
+    ACTION_TEXT_CLASSIFIER_ACTIONS_GENERATED = 1619;
+
+    // OPEN: Settings > Accessibility > Vibration > Ring vibration
+    // CATEGORY: SETTINGS
+    // OS: Q
+    ACCESSIBILITY_VIBRATION_RING = 1620;
+
+    // ACTION: Notification blocking helper view, which helps the user to block
+    // application or channel from showing notifications.
+    // SUBTYPE: NotificationBlockingHelper enum.
+    // CATEGORY: NOTIFICATION
+    // OS: Q
+    NOTIFICATION_BLOCKING_HELPER = 1621;
+
+    // ACTION: Tap & Pay -> Default Application Setting -> Use Forground
+    // OS: Q
+    ACTION_NFC_PAYMENT_FOREGROUND_SETTING = 1622;
+
+    // ACTION: Tap & Pay -> Default Application Setting -> Use Default
+    // OS: Q
+    ACTION_NFC_PAYMENT_ALWAYS_SETTING = 1623;
+
+    // OPEN: Settings > System > Input & Gesture > Skip song gesture
+    // OS: Q
+    SETTINGS_GESTURE_SKIP_SONG = 1624;
+
+    // OPEN: Settings > System > Input & Gesture > Silence gesture
+    // OS: Q
+    SETTINGS_GESTURE_SILENCE = 1625;
+
+    // OPEN: Settings > System > Input & Gesture > Tap screen gesture
+    // OS: Q
+    SETTINGS_GESTURE_TAP_SCREEN = 1626;
+
+    // OPEN: Settings > Network & internet > Click Mobile network to land on a page with a list of
+    // SIM/eSIM subscriptions.
+    // CATEGORY: SETTINGS
+    // OS: Q
+    MOBILE_NETWORK_LIST = 1627;
+
+    // OPEN: Settings > Display > Adaptive sleep
+    // OS: Q
+    SETTINGS_ADAPTIVE_SLEEP = 1628;
+    
+    // Tagged data for SMART_REPLY_VISIBLE and NOTIFICATION_ITEM_ACTION.
+    // The UI location of the notification containing the smart suggestions.
+    // This is a NotificationLocation object (see the NotificationLocation
+    // enum).
+    // OS: Q
+    NOTIFICATION_LOCATION = 1629;
+
+    // The autofill system made request to the system-provided augmented autofill service.
+    // OS: Q
+    // Package: Package of app that is autofilled
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SERVICE: Package of the augmented autofill service that processed the
+    // request
+    // 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.
+    AUTOFILL_AUGMENTED_REQUEST = 1630;
+
+    // Tag of a field for the number of augmented autofill requests in a session
+    // OS: Q
+    FIELD_AUTOFILL_NUMBER_AUGMENTED_REQUESTS = 1631;
+
+    // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 1212676..f128d86 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -216,9 +216,15 @@
     // Package: android
     NOTE_SOFTAP_CONFIG_CHANGED = 50;
 
-    // Notify the user that connected to app suggested network.
+    // Notify the user that an app suggested network is available for connection.
     // Package: android
-    NOTE_CONNECTED_TO_NETWORK_SUGGESTION = 51;
+    NOTE_NETWORK_SUGGESTION_AVAILABLE = 51;
+
+    // Inform the user that the contaminant is detected on the USB port
+    NOTE_USB_CONTAMINANT_DETECTED = 52;
+
+    // Inform that user that the USB port is free of contaminants.
+    NOTE_USB_CONTAMINANT_NOT_DETECTED = 53;
 
     // ADD_NEW_IDS_ABOVE_THIS_LINE
     // Legacy IDs with arbitrary values appear below
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index e9ce737..6656919 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -485,6 +485,12 @@
 
   // Multiple lists of timestamped link layer stats with labels to represent whether wifi is usable
   repeated WifiUsabilityStats wifi_usability_stats_list = 126;
+
+  // Counts the occurrences of each Wifi usability score provided by external app
+  repeated WifiUsabilityScoreCount wifi_usability_score_count = 127;
+
+  // List of PNO scan stats, one element for each mobility state
+  repeated DeviceMobilityStatePnoScanStats mobility_state_pno_stats_list = 128;
 }
 
 // Information that gets logged for every WiFi connection.
@@ -670,6 +676,15 @@
   optional int32 count = 2;
 }
 
+// Counts the number of instances of a specific Wifi Usability Score
+message WifiUsabilityScoreCount {
+  // Wifi Usability Score
+  optional int32 score = 1;
+
+  // Number of Wifi score reports with this score
+  optional int32 count = 2;
+}
+
 // Number of occurrences of a specific link speed (Mbps)
 // and sum of rssi (dBm) and rssi^2 (dBm^2)
 message LinkSpeedCount {
@@ -826,6 +841,10 @@
 
     // Wifi is turned off
     TYPE_WIFI_DISABLED = 19;
+
+    // The NetworkAgent Wifi usability score has changed in a way that may
+    // impact connectivity
+    TYPE_WIFI_USABILITY_SCORE_BREACH = 20;
   }
 
   enum FrameworkDisconnectReason {
@@ -940,6 +959,9 @@
 
   // NetworkAgent score of connected wifi
   optional int32 last_score = 14 [default = -1];
+
+  // NetworkAgent Wifi usability score of connected wifi
+  optional int32 last_wifi_usability_score = 15 [default = -1];
 }
 
 // Wi-Fi Aware metrics
@@ -1653,6 +1675,10 @@
 
   // Firmware alert code. Only valid when the event was triggered by a firmware alert, otherwise -1.
   optional int32 firmware_alert_code = 10 [default = -1];
+
+  // NetworkAgent wifi usability score of connected wifi.
+  // Defaults to -1 if the score was never set.
+  optional int32 last_wifi_usability_score = 11 [default = -1];
 }
 
 message PasspointProfileTypeCount {
@@ -1765,6 +1791,26 @@
   // The total time spent on hotspot2.0 scans and GAS exchange in ms counted from the last radio
   // chip reset
   optional int64 total_hotspot_2_scan_time_ms = 16;
+
+  // Internal framework Wifi score
+  optional int32 wifi_score = 17;
+
+  // Wifi usability score provided by external system app
+  optional int32 wifi_usability_score = 18;
+
+  // Sequence number from external system app to framework
+  optional int32 seq_num_to_framework = 19;
+
+  // The total time CCA is on busy status on the current frequency in ms
+  // counted from the last radio chip reset
+  optional int64 total_cca_busy_freq_time_ms = 20;
+
+  // The total radio on time of the current frequency from the last radio
+  // chip reset
+  optional int64 total_radio_on_freq_time_ms = 21;
+
+  // The total number of beacons received from the last radio chip reset
+  optional int64 total_beacon_rx = 22;
 }
 
 message WifiUsabilityStats {
@@ -1784,4 +1830,33 @@
 
   // The list of timestamped wifi usability stats
   repeated WifiUsabilityStatsEntry stats = 2;
-}
\ No newline at end of file
+}
+
+message DeviceMobilityStatePnoScanStats {
+  // see WifiManager.DEVICE_MOBILITY_STATE_* constants
+  enum DeviceMobilityState {
+    // Unknown mobility
+    UNKNOWN = 0;
+
+    // High movement
+    HIGH_MVMT = 1;
+
+    // Low movement
+    LOW_MVMT = 2;
+
+    // Stationary
+    STATIONARY = 3;
+  }
+
+  // The device mobility state
+  optional DeviceMobilityState device_mobility_state = 1;
+
+  // The number of times that this state was entered
+  optional int32 num_times_entered_state = 2;
+
+  // The total duration elapsed while in this mobility state, in ms
+  optional int64 total_duration_ms = 3;
+
+  // the total duration elapsed while in this mobility state with PNO scans running, in ms
+  optional int64 pno_duration_ms = 4;
+}
diff --git a/services/Android.bp b/services/Android.bp
index 58a0997..31385ed 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -17,17 +17,21 @@
     static_libs: [
         "services.core",
         "services.accessibility",
+        "services.appprediction",
         "services.appwidget",
         "services.autofill",
         "services.backup",
         "services.companion",
         "services.contentcapture",
+        "services.contentsuggestions",
         "services.coverage",
         "services.devicepolicy",
+        "services.ipmemorystore",
         "services.midi",
         "services.net",
         "services.print",
         "services.restrictions",
+        "services.startop",
         "services.usage",
         "services.usb",
         "services.voiceinteraction",
diff --git a/services/accessibility/TEST_MAPPING b/services/accessibility/TEST_MAPPING
index 320924c..d90c3bd 100644
--- a/services/accessibility/TEST_MAPPING
+++ b/services/accessibility/TEST_MAPPING
@@ -7,7 +7,7 @@
           "include-annotation": "android.platform.test.annotations.Presubmit"
         },
         {
-          "exclude-annotation": "android.support.test.filters.FlakyTest"
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
     },
@@ -18,7 +18,7 @@
           "include-annotation": "android.platform.test.annotations.Presubmit"
         },
         {
-          "exclude-annotation": "android.support.test.filters.FlakyTest"
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
     },
@@ -29,7 +29,7 @@
           "include-annotation": "android.platform.test.annotations.Presubmit"
         },
         {
-          "exclude-annotation": "android.support.test.filters.FlakyTest"
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
     },
@@ -40,7 +40,7 @@
           "include-filter": "com.android.server.accessibility"
         },
         {
-          "exclude-annotation": "android.support.test.filters.FlakyTest"
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
     },
@@ -51,7 +51,7 @@
           "include-filter": "com.android.internal.accessibility"
         },
         {
-          "exclude-annotation": "android.support.test.filters.FlakyTest"
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
     },
@@ -62,7 +62,7 @@
           "include-filter": "android.view.accessibility"
         },
         {
-          "exclude-annotation": "android.support.test.filters.FlakyTest"
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
     }
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 6eba914..2c075dc 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -53,6 +53,7 @@
 import android.view.accessibility.IAccessibilityInteractionConnection;
 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.DumpUtils;
 import com.android.server.accessibility.AccessibilityManagerService.RemoteAccessibilityConnection;
@@ -751,7 +752,7 @@
     }
 
     @Override
-    public float getMagnificationScale() {
+    public float getMagnificationScale(int displayId) {
         synchronized (mLock) {
             if (!isCalledForCurrentUserLocked()) {
                 return 1.0f;
@@ -759,14 +760,14 @@
         }
         final long identity = Binder.clearCallingIdentity();
         try {
-            return mSystemSupport.getMagnificationController().getScale();
+            return mSystemSupport.getMagnificationController().getScale(displayId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
     @Override
-    public Region getMagnificationRegion() {
+    public Region getMagnificationRegion(int displayId) {
         synchronized (mLock) {
             final Region region = Region.obtain();
             if (!isCalledForCurrentUserLocked()) {
@@ -775,22 +776,22 @@
             MagnificationController magnificationController =
                     mSystemSupport.getMagnificationController();
             boolean registeredJustForThisCall =
-                    registerMagnificationIfNeeded(magnificationController);
+                    registerMagnificationIfNeeded(displayId, magnificationController);
             final long identity = Binder.clearCallingIdentity();
             try {
-                magnificationController.getMagnificationRegion(region);
+                magnificationController.getMagnificationRegion(displayId, region);
                 return region;
             } finally {
                 Binder.restoreCallingIdentity(identity);
                 if (registeredJustForThisCall) {
-                    magnificationController.unregister();
+                    magnificationController.unregister(displayId);
                 }
             }
         }
     }
 
     @Override
-    public float getMagnificationCenterX() {
+    public float getMagnificationCenterX(int displayId) {
         synchronized (mLock) {
             if (!isCalledForCurrentUserLocked()) {
                 return 0.0f;
@@ -798,21 +799,21 @@
             MagnificationController magnificationController =
                     mSystemSupport.getMagnificationController();
             boolean registeredJustForThisCall =
-                    registerMagnificationIfNeeded(magnificationController);
+                    registerMagnificationIfNeeded(displayId, magnificationController);
             final long identity = Binder.clearCallingIdentity();
             try {
-                return magnificationController.getCenterX();
+                return magnificationController.getCenterX(displayId);
             } finally {
                 Binder.restoreCallingIdentity(identity);
                 if (registeredJustForThisCall) {
-                    magnificationController.unregister();
+                    magnificationController.unregister(displayId);
                 }
             }
         }
     }
 
     @Override
-    public float getMagnificationCenterY() {
+    public float getMagnificationCenterY(int displayId) {
         synchronized (mLock) {
             if (!isCalledForCurrentUserLocked()) {
                 return 0.0f;
@@ -820,31 +821,31 @@
             MagnificationController magnificationController =
                     mSystemSupport.getMagnificationController();
             boolean registeredJustForThisCall =
-                    registerMagnificationIfNeeded(magnificationController);
+                    registerMagnificationIfNeeded(displayId, magnificationController);
             final long identity = Binder.clearCallingIdentity();
             try {
-                return magnificationController.getCenterY();
+                return magnificationController.getCenterY(displayId);
             } finally {
                 Binder.restoreCallingIdentity(identity);
                 if (registeredJustForThisCall) {
-                    magnificationController.unregister();
+                    magnificationController.unregister(displayId);
                 }
             }
         }
     }
 
-    private boolean registerMagnificationIfNeeded(
+    private boolean registerMagnificationIfNeeded(int displayId,
             MagnificationController magnificationController) {
-        if (!magnificationController.isRegisteredLocked()
+        if (!magnificationController.isRegistered(displayId)
                 && mSecurityPolicy.canControlMagnification(this)) {
-            magnificationController.register();
+            magnificationController.register(displayId);
             return true;
         }
         return false;
     }
 
     @Override
-    public boolean resetMagnification(boolean animate) {
+    public boolean resetMagnification(int displayId, boolean animate) {
         synchronized (mLock) {
             if (!isCalledForCurrentUserLocked()) {
                 return false;
@@ -857,16 +858,16 @@
         try {
             MagnificationController magnificationController =
                     mSystemSupport.getMagnificationController();
-            return (magnificationController.reset(animate)
-                    || !magnificationController.isMagnifying());
+            return (magnificationController.reset(displayId, animate)
+                    || !magnificationController.isMagnifying(displayId));
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
     @Override
-    public boolean setMagnificationScaleAndCenter(float scale, float centerX, float centerY,
-            boolean animate) {
+    public boolean setMagnificationScaleAndCenter(int displayId, float scale, float centerX,
+            float centerY, boolean animate) {
         synchronized (mLock) {
             if (!isCalledForCurrentUserLocked()) {
                 return false;
@@ -878,11 +879,11 @@
             try {
                 MagnificationController magnificationController =
                         mSystemSupport.getMagnificationController();
-                if (!magnificationController.isRegisteredLocked()) {
-                    magnificationController.register();
+                if (!magnificationController.isRegistered(displayId)) {
+                    magnificationController.register(displayId);
                 }
                 return magnificationController
-                        .setScaleAndCenter(scale, centerX, centerY, animate, mId);
+                        .setScaleAndCenter(displayId, scale, centerX, centerY, animate, mId);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -890,12 +891,12 @@
     }
 
     @Override
-    public void setMagnificationCallbackEnabled(boolean enabled) {
-        mInvocationHandler.setMagnificationCallbackEnabled(enabled);
+    public void setMagnificationCallbackEnabled(int displayId, boolean enabled) {
+        mInvocationHandler.setMagnificationCallbackEnabled(displayId, enabled);
     }
 
-    public boolean isMagnificationCallbackEnabled() {
-        return mInvocationHandler.mIsMagnificationCallbackEnabled;
+    public boolean isMagnificationCallbackEnabled(int displayId) {
+        return mInvocationHandler.isMagnificationCallbackEnabled(displayId);
     }
 
     @Override
@@ -1106,10 +1107,10 @@
                 InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE);
     }
 
-    public void notifyMagnificationChangedLocked(@NonNull Region region,
+    public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region,
             float scale, float centerX, float centerY) {
         mInvocationHandler
-                .notifyMagnificationChangedLocked(region, scale, centerX, centerY);
+                .notifyMagnificationChangedLocked(displayId, region, scale, centerX, centerY);
     }
 
     public void notifySoftKeyboardShowModeChangedLocked(int showState) {
@@ -1128,12 +1129,12 @@
      * Called by the invocation handler to notify the service that the
      * state of magnification has changed.
      */
-    private void notifyMagnificationChangedInternal(@NonNull Region region,
+    private void notifyMagnificationChangedInternal(int displayId, @NonNull Region region,
             float scale, float centerX, float centerY) {
         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
         if (listener != null) {
             try {
-                listener.onMagnificationChanged(region, scale, centerX, centerY);
+                listener.onMagnificationChanged(displayId, region, scale, centerX, centerY);
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error sending magnification changes to " + mService, re);
             }
@@ -1251,7 +1252,9 @@
         private static final int MSG_ON_ACCESSIBILITY_BUTTON_CLICKED = 7;
         private static final int MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 8;
 
-        private boolean mIsMagnificationCallbackEnabled = false;
+        /** List of magnification callback states, mapping from displayId -> Boolean */
+        @GuardedBy("mlock")
+        private final SparseArray<Boolean> mMagnificationCallbackState = new SparseArray<>(0);
         private boolean mIsSoftKeyboardCallbackEnabled = false;
 
         public InvocationHandler(Looper looper) {
@@ -1277,7 +1280,8 @@
                     final float scale = (float) args.arg2;
                     final float centerX = (float) args.arg3;
                     final float centerY = (float) args.arg4;
-                    notifyMagnificationChangedInternal(region, scale, centerX, centerY);
+                    final int displayId = args.argi1;
+                    notifyMagnificationChangedInternal(displayId, region, scale, centerX, centerY);
                     args.recycle();
                 } break;
 
@@ -1301,11 +1305,12 @@
             }
         }
 
-        public void notifyMagnificationChangedLocked(@NonNull Region region, float scale,
-                float centerX, float centerY) {
-            if (!mIsMagnificationCallbackEnabled) {
-                // Callback is disabled, don't bother packing args.
-                return;
+        public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region,
+                float scale, float centerX, float centerY) {
+            synchronized (mLock) {
+                if (mMagnificationCallbackState.get(displayId) == null) {
+                    return;
+                }
             }
 
             final SomeArgs args = SomeArgs.obtain();
@@ -1313,13 +1318,26 @@
             args.arg2 = scale;
             args.arg3 = centerX;
             args.arg4 = centerY;
+            args.argi1 = displayId;
 
             final Message msg = obtainMessage(MSG_ON_MAGNIFICATION_CHANGED, args);
             msg.sendToTarget();
         }
 
-        public void setMagnificationCallbackEnabled(boolean enabled) {
-            mIsMagnificationCallbackEnabled = enabled;
+        public void setMagnificationCallbackEnabled(int displayId, boolean enabled) {
+            synchronized (mLock) {
+                if (enabled) {
+                    mMagnificationCallbackState.put(displayId, true);
+                } else {
+                    mMagnificationCallbackState.remove(displayId);
+                }
+            }
+        }
+
+        public boolean isMagnificationCallbackEnabled(int displayId) {
+            synchronized (mLock) {
+                return mMagnificationCallbackState.get(displayId) != null;
+            }
         }
 
         public void notifySoftKeyboardShowModeChangedLocked(int showState) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index cf08681..bcff4e0 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -17,13 +17,11 @@
 package com.android.server.accessibility;
 
 import android.content.Context;
-import android.os.Handler;
 import android.os.PowerManager;
-import android.util.DebugUtils;
-import android.util.ExceptionUtils;
-import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.view.Display;
 import android.view.InputDevice;
 import android.view.InputEvent;
 import android.view.InputFilter;
@@ -31,10 +29,11 @@
 import android.view.MotionEvent;
 import android.view.accessibility.AccessibilityEvent;
 
-import com.android.internal.util.BitUtils;
 import com.android.server.LocalServices;
 import com.android.server.policy.WindowManagerPolicy;
 
+import java.util.ArrayList;
+
 /**
  * This class is an input filter for implementing accessibility features such
  * as display magnification and explore by touch.
@@ -108,23 +107,24 @@
 
     private final AccessibilityManagerService mAms;
 
-    private boolean mInstalled;
+    private final SparseArray<EventStreamTransformation> mEventHandler;
 
-    private int mUserId;
+    private final SparseArray<TouchExplorer> mTouchExplorer = new SparseArray<>(0);
 
-    private int mEnabledFeatures;
+    private final SparseArray<MagnificationGestureHandler> mMagnificationGestureHandler =
+            new SparseArray<>(0);
 
-    private TouchExplorer mTouchExplorer;
-
-    private MagnificationGestureHandler mMagnificationGestureHandler;
-
-    private MotionEventInjector mMotionEventInjector;
+    private final SparseArray<MotionEventInjector> mMotionEventInjector = new SparseArray<>(0);
 
     private AutoclickController mAutoclickController;
 
     private KeyboardInterceptor mKeyboardInterceptor;
 
-    private EventStreamTransformation mEventHandler;
+    private boolean mInstalled;
+
+    private int mUserId;
+
+    private int mEnabledFeatures;
 
     private EventStreamState mMouseStreamState;
 
@@ -133,10 +133,16 @@
     private EventStreamState mKeyboardStreamState;
 
     AccessibilityInputFilter(Context context, AccessibilityManagerService service) {
+        this(context, service, new SparseArray<>(0));
+    }
+
+    AccessibilityInputFilter(Context context, AccessibilityManagerService service,
+            SparseArray<EventStreamTransformation> eventHandler) {
         super(context.getMainLooper());
         mContext = context;
         mAms = service;
         mPm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        mEventHandler = eventHandler;
     }
 
     @Override
@@ -160,6 +166,13 @@
         super.onUninstalled();
     }
 
+    void onDisplayChanged() {
+        if (mInstalled) {
+            disableFeatures();
+            enableFeatures();
+        }
+    }
+
     @Override
     public void onInputEvent(InputEvent event, int policyFlags) {
         if (DEBUG) {
@@ -167,8 +180,8 @@
                     + Integer.toHexString(policyFlags));
         }
 
-        if (mEventHandler == null) {
-            if (DEBUG) Slog.d(TAG, "mEventHandler == null for event " + event);
+        if (mEventHandler.size() == 0) {
+            if (DEBUG) Slog.d(TAG, "No mEventHandler for event " + event);
             super.onInputEvent(event, policyFlags);
             return;
         }
@@ -182,16 +195,16 @@
         int eventSource = event.getSource();
         if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) {
             state.reset();
-            mEventHandler.clearEvents(eventSource);
+            clearEventsForAllEventHandlers(eventSource);
             super.onInputEvent(event, policyFlags);
             return;
         }
 
-        if (state.updateDeviceId(event.getDeviceId())) {
-            mEventHandler.clearEvents(eventSource);
+        if (state.updateInputSource(event.getSource())) {
+            clearEventsForAllEventHandlers(eventSource);
         }
 
-        if (!state.deviceIdValid()) {
+        if (!state.inputSourceValid()) {
             super.onInputEvent(event, policyFlags);
             return;
         }
@@ -240,6 +253,15 @@
         return null;
     }
 
+    private void clearEventsForAllEventHandlers(int eventSource) {
+        for (int i = 0; i < mEventHandler.size(); i++) {
+            final EventStreamTransformation eventHandler = mEventHandler.valueAt(i);
+            if (eventHandler != null) {
+                eventHandler.clearEvents(eventSource);
+            }
+        }
+    }
+
     private void processMotionEvent(EventStreamState state, MotionEvent event, int policyFlags) {
         if (!state.shouldProcessScroll() && event.getActionMasked() == MotionEvent.ACTION_SCROLL) {
             super.onInputEvent(event, policyFlags);
@@ -258,7 +280,10 @@
             super.onInputEvent(event, policyFlags);
             return;
         }
-        mEventHandler.onKeyEvent(event, policyFlags);
+        // Since the display id of KeyEvent always would be -1 and there is only one
+        // KeyboardInterceptor for all display, pass KeyEvent to the mEventHandler of
+        // DEFAULT_DISPLAY to handle.
+        mEventHandler.get(Display.DEFAULT_DISPLAY).onKeyEvent(event, policyFlags);
     }
 
     private void handleMotionEvent(MotionEvent event, int policyFlags) {
@@ -267,10 +292,16 @@
         }
         mPm.userActivity(event.getEventTime(), false);
         MotionEvent transformedEvent = MotionEvent.obtain(event);
-        mEventHandler.onMotionEvent(transformedEvent, event, policyFlags);
+        final int displayId = event.getDisplayId();
+        mEventHandler.get(isDisplayIdValid(displayId) ? displayId : Display.DEFAULT_DISPLAY)
+                .onMotionEvent(transformedEvent, event, policyFlags);
         transformedEvent.recycle();
     }
 
+    private boolean isDisplayIdValid(int displayId) {
+        return mEventHandler.get(displayId) != null;
+    }
+
     @Override
     public void onMotionEvent(MotionEvent transformedEvent, MotionEvent rawEvent,
             int policyFlags) {
@@ -323,14 +354,20 @@
     }
 
     void notifyAccessibilityEvent(AccessibilityEvent event) {
-        if (mEventHandler != null) {
-            mEventHandler.onAccessibilityEvent(event);
+        for (int i = 0; i < mEventHandler.size(); i++) {
+            final EventStreamTransformation eventHandler = mEventHandler.valueAt(i);
+            if (eventHandler != null) {
+                eventHandler.onAccessibilityEvent(event);
+            }
         }
     }
 
-    void notifyAccessibilityButtonClicked() {
-        if (mMagnificationGestureHandler != null) {
-            mMagnificationGestureHandler.notifyShortcutTriggered();
+    void notifyAccessibilityButtonClicked(int displayId) {
+        if (mMagnificationGestureHandler.size() != 0) {
+            final MagnificationGestureHandler handler = mMagnificationGestureHandler.get(displayId);
+            if (handler != null) {
+                handler.notifyShortcutTriggered();
+            }
         }
     }
 
@@ -339,81 +376,124 @@
 
         resetStreamState();
 
+        final ArrayList<Display> displaysList = mAms.getValidDisplayList();
+
         if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) {
             mAutoclickController = new AutoclickController(mContext, mUserId);
-            addFirstEventHandler(mAutoclickController);
+            addFirstEventHandlerForAllDisplays(displaysList, mAutoclickController);
         }
 
-        if ((mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
-            mTouchExplorer = new TouchExplorer(mContext, mAms);
-            addFirstEventHandler(mTouchExplorer);
-        }
+        for (int i = displaysList.size() - 1; i >= 0; i--) {
+            final int displayId = displaysList.get(i).getDisplayId();
 
-        if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0
-                || ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0)
-                || ((mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0)) {
-            final boolean detectControlGestures = (mEnabledFeatures
-                    & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0;
-            final boolean triggerable = (mEnabledFeatures
-                    & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0;
-            mMagnificationGestureHandler = new MagnificationGestureHandler(
-                    mContext, mAms.getMagnificationController(),
-                    detectControlGestures, triggerable);
-            addFirstEventHandler(mMagnificationGestureHandler);
-        }
+            if ((mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
+                TouchExplorer explorer = new TouchExplorer(mContext, mAms);
+                addFirstEventHandler(displayId, explorer);
+                mTouchExplorer.put(displayId, explorer);
+            }
 
-        if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
-            mMotionEventInjector = new MotionEventInjector(mContext.getMainLooper());
-            addFirstEventHandler(mMotionEventInjector);
-            mAms.setMotionEventInjector(mMotionEventInjector);
+            if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0
+                    || ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0)
+                    || ((mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0)) {
+                final boolean detectControlGestures = (mEnabledFeatures
+                        & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0;
+                final boolean triggerable = (mEnabledFeatures
+                        & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0;
+                MagnificationGestureHandler magnificationGestureHandler =
+                        new MagnificationGestureHandler(mContext,
+                                mAms.getMagnificationController(),
+                                detectControlGestures, triggerable);
+                addFirstEventHandler(displayId, magnificationGestureHandler);
+                mMagnificationGestureHandler.put(displayId, magnificationGestureHandler);
+            }
+
+            if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
+                MotionEventInjector injector = new MotionEventInjector(
+                        mContext.getMainLooper());
+                addFirstEventHandler(displayId, injector);
+                // TODO: Need to set MotionEventInjector per display.
+                mAms.setMotionEventInjector(injector);
+                mMotionEventInjector.put(displayId, injector);
+            }
         }
 
         if ((mEnabledFeatures & FLAG_FEATURE_FILTER_KEY_EVENTS) != 0) {
             mKeyboardInterceptor = new KeyboardInterceptor(mAms,
                     LocalServices.getService(WindowManagerPolicy.class));
-            addFirstEventHandler(mKeyboardInterceptor);
+            // Since the display id of KeyEvent always would be -1 and it would be dispatched to
+            // the display with input focus directly, we only need one KeyboardInterceptor for
+            // default display.
+            addFirstEventHandler(Display.DEFAULT_DISPLAY, mKeyboardInterceptor);
         }
     }
 
     /**
-     * Adds an event handler to the event handler chain. The handler is added at the beginning of
-     * the chain.
+     * Adds an event handler to the event handler chain for giving display. The handler is added at
+     * the beginning of the chain.
      *
+     * @param displayId The logical display id.
      * @param handler The handler to be added to the event handlers list.
      */
-    private void addFirstEventHandler(EventStreamTransformation handler) {
-        if (mEventHandler != null) {
-            handler.setNext(mEventHandler);
+    private void addFirstEventHandler(int displayId, EventStreamTransformation handler) {
+        EventStreamTransformation eventHandler = mEventHandler.get(displayId);
+        if (eventHandler != null) {
+            handler.setNext(eventHandler);
         } else {
             handler.setNext(this);
         }
-        mEventHandler = handler;
+        eventHandler = handler;
+        mEventHandler.put(displayId, eventHandler);
+    }
+
+    /**
+     * Adds an event handler to the event handler chain for all displays. The handler is added at
+     * the beginning of the chain.
+     *
+     * @param displayList The list of displays
+     * @param handler The handler to be added to the event handlers list.
+     */
+    private void addFirstEventHandlerForAllDisplays(ArrayList<Display> displayList,
+            EventStreamTransformation handler) {
+        for (int i = 0; i < displayList.size(); i++) {
+            final int displayId = displayList.get(i).getDisplayId();
+            addFirstEventHandler(displayId, handler);
+        }
     }
 
     private void disableFeatures() {
-        if (mMotionEventInjector != null) {
+        for (int i = mMotionEventInjector.size() - 1; i >= 0; i--) {
+            final MotionEventInjector injector = mMotionEventInjector.valueAt(i);
+            // TODO: Need to set MotionEventInjector per display.
             mAms.setMotionEventInjector(null);
-            mMotionEventInjector.onDestroy();
-            mMotionEventInjector = null;
+            if (injector != null) {
+                injector.onDestroy();
+            }
         }
+        mMotionEventInjector.clear();
         if (mAutoclickController != null) {
             mAutoclickController.onDestroy();
             mAutoclickController = null;
         }
-        if (mTouchExplorer != null) {
-            mTouchExplorer.onDestroy();
-            mTouchExplorer = null;
+        for (int i = mTouchExplorer.size() - 1; i >= 0; i--) {
+            final TouchExplorer explorer = mTouchExplorer.valueAt(i);
+            if (explorer != null) {
+                explorer.onDestroy();
+            }
         }
-        if (mMagnificationGestureHandler != null) {
-            mMagnificationGestureHandler.onDestroy();
-            mMagnificationGestureHandler = null;
+        mTouchExplorer.clear();
+        for (int i = mMagnificationGestureHandler.size() - 1; i >= 0; i--) {
+            final MagnificationGestureHandler handler = mMagnificationGestureHandler.valueAt(i);
+            if (handler != null) {
+                handler.onDestroy();
+            }
         }
+        mMagnificationGestureHandler.clear();
         if (mKeyboardInterceptor != null) {
             mKeyboardInterceptor.onDestroy();
             mKeyboardInterceptor = null;
         }
 
-        mEventHandler = null;
+        mEventHandler.clear();
         resetStreamState();
     }
 
@@ -441,41 +521,41 @@
      * whose events should not be handled by a11y event stream transformations.
      */
     private static class EventStreamState {
-        private int mDeviceId;
+        private int mSource;
 
         EventStreamState() {
-            mDeviceId = -1;
+            mSource = -1;
         }
 
         /**
-         * Updates the ID of the device associated with the state. If the ID changes, resets
-         * internal state.
+         * Updates the input source of the device associated with the state. If the source changes,
+         * resets internal state.
          *
-         * @param deviceId Updated input device ID.
-         * @return Whether the device ID has changed.
+         * @param source Updated input source.
+         * @return Whether the input source has changed.
          */
-        public boolean updateDeviceId(int deviceId) {
-            if (mDeviceId == deviceId) {
+        public boolean updateInputSource(int source) {
+            if (mSource == source) {
                 return false;
             }
-            // Reset clears internal state, so make sure it's called before |mDeviceId| is updated.
+            // Reset clears internal state, so make sure it's called before |mSource| is updated.
             reset();
-            mDeviceId = deviceId;
+            mSource = source;
             return true;
         }
 
         /**
-         * @return Whether device ID is valid.
+         * @return Whether input source is valid.
          */
-        public boolean deviceIdValid() {
-            return mDeviceId >= 0;
+        public boolean inputSourceValid() {
+            return mSource >= 0;
         }
 
         /**
          * Resets the event stream state.
          */
         public void reset() {
-            mDeviceId = -1;
+            mSource = -1;
         }
 
         /**
@@ -592,20 +672,19 @@
 
         /*
          * Key events from different devices may be interleaved. For example, the volume up and
-         * down keys can come from different device IDs.
+         * down keys can come from different input sources.
          */
         @Override
-        public boolean updateDeviceId(int deviceId) {
+        public boolean updateInputSource(int deviceId) {
             return false;
         }
 
-        // We manage all device ids simultaneously; there is no concept of validity.
+        // We manage all input source simultaneously; there is no concept of validity.
         @Override
-        public boolean deviceIdValid() {
+        public boolean inputSourceValid() {
             return true;
         }
 
-
         @Override
         final public boolean shouldProcessKeyEvent(KeyEvent event) {
             // For each keyboard device, wait for a down event from a device to start processing
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 36ca52a..305c53e 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -16,6 +16,11 @@
 
 package com.android.server.accessibility;
 
+import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO;
+import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE;
+import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN;
+import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
+import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD;
 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_MASK;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
 import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED;
@@ -23,13 +28,9 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
+
 import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
-import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO;
-import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN;
-import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD;
-import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE;
-import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN;
 
 import android.Manifest;
 import android.accessibilityservice.AccessibilityService;
@@ -37,6 +38,7 @@
 import android.accessibilityservice.IAccessibilityServiceClient;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityOptions;
 import android.app.AlertDialog;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -121,6 +123,8 @@
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
+import libcore.util.EmptyArray;
+
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.FileDescriptor;
@@ -139,8 +143,6 @@
 import java.util.function.Consumer;
 import java.util.function.IntSupplier;
 
-import libcore.util.EmptyArray;
-
 /**
  * This class is instantiated by the system as a system level service and can be
  * accessed only by the system. The task of this service is to be a centralized
@@ -211,6 +213,8 @@
 
     private final SecurityPolicy mSecurityPolicy;
 
+    private final AccessibilityDisplayListener mA11yDisplayListener;
+
     private final AppOpsManager mAppOpsManager;
 
     private final MainHandler mMainHandler;
@@ -303,6 +307,7 @@
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         mMainHandler = new MainHandler(mContext.getMainLooper());
         mGlobalActionPerformer = new GlobalActionPerformer(mContext, mWindowManagerService);
+        mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
 
         registerBroadcastReceivers();
         new AccessibilityContentObserver(mMainHandler).register(
@@ -908,16 +913,18 @@
     /**
      * Invoked remotely over AIDL by SysUi when the accessibility button within the system's
      * navigation area has been clicked.
+     *
+     * @param displayId The logical display id.
      */
     @Override
-    public void notifyAccessibilityButtonClicked() {
+    public void notifyAccessibilityButtonClicked(int displayId) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Caller does not hold permission "
                     + android.Manifest.permission.STATUS_BAR_SERVICE);
         }
         synchronized (mLock) {
-            notifyAccessibilityButtonClickedLocked();
+            notifyAccessibilityButtonClickedLocked(displayId);
         }
     }
 
@@ -967,17 +974,18 @@
      * Called by the MagnificationController when the state of display
      * magnification changes.
      *
+     * @param displayId The logical display id.
      * @param region the new magnified region, may be empty if
      *               magnification is not enabled (e.g. scale is 1)
      * @param scale the new scale
      * @param centerX the new screen-relative center X coordinate
      * @param centerY the new screen-relative center Y coordinate
      */
-    public void notifyMagnificationChanged(@NonNull Region region,
+    public void notifyMagnificationChanged(int displayId, @NonNull Region region,
             float scale, float centerX, float centerY) {
         synchronized (mLock) {
             notifyClearAccessibilityCacheLocked();
-            notifyMagnificationChangedLocked(region, scale, centerX, centerY);
+            notifyMagnificationChangedLocked(displayId, region, scale, centerX, centerY);
         }
     }
 
@@ -1202,12 +1210,12 @@
         }
     }
 
-    private void notifyMagnificationChangedLocked(@NonNull Region region,
+    private void notifyMagnificationChangedLocked(int displayId, @NonNull Region region,
             float scale, float centerX, float centerY) {
         final UserState state = getCurrentUserStateLocked();
         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
             final AccessibilityServiceConnection service = state.mBoundServices.get(i);
-            service.notifyMagnificationChangedLocked(region, scale, centerX, centerY);
+            service.notifyMagnificationChangedLocked(displayId, region, scale, centerX, centerY);
         }
     }
 
@@ -1219,7 +1227,7 @@
         }
     }
 
-    private void notifyAccessibilityButtonClickedLocked() {
+    private void notifyAccessibilityButtonClickedLocked(int displayId) {
         final UserState state = getCurrentUserStateLocked();
 
         int potentialTargets = state.mIsNavBarMagnificationEnabled ? 1 : 0;
@@ -1236,12 +1244,15 @@
         if (potentialTargets == 1) {
             if (state.mIsNavBarMagnificationEnabled) {
                 mMainHandler.sendMessage(obtainMessage(
-                        AccessibilityManagerService::sendAccessibilityButtonToInputFilter, this));
+                        AccessibilityManagerService::sendAccessibilityButtonToInputFilter, this,
+                        displayId));
                 return;
             } else {
                 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
                     final AccessibilityServiceConnection service = state.mBoundServices.get(i);
                     if (service.mRequestAccessibilityButton) {
+                        // TODO(b/120762691): Need to notify each accessibility service if
+                        // accessibility button is clicked per display.
                         service.notifyAccessibilityButtonClickedLocked();
                         return;
                     }
@@ -1251,17 +1262,21 @@
             if (state.mServiceAssignedToAccessibilityButton == null
                     && !state.mIsNavBarMagnificationAssignedToAccessibilityButton) {
                 mMainHandler.sendMessage(obtainMessage(
-                        AccessibilityManagerService::showAccessibilityButtonTargetSelection, this));
+                        AccessibilityManagerService::showAccessibilityButtonTargetSelection, this,
+                        displayId));
             } else if (state.mIsNavBarMagnificationEnabled
                     && state.mIsNavBarMagnificationAssignedToAccessibilityButton) {
                 mMainHandler.sendMessage(obtainMessage(
-                        AccessibilityManagerService::sendAccessibilityButtonToInputFilter, this));
+                        AccessibilityManagerService::sendAccessibilityButtonToInputFilter, this,
+                        displayId));
                 return;
             } else {
                 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
                     final AccessibilityServiceConnection service = state.mBoundServices.get(i);
                     if (service.mRequestAccessibilityButton && (service.mComponentName.equals(
                             state.mServiceAssignedToAccessibilityButton))) {
+                        // TODO(b/120762691): Need to notify each accessibility service if
+                        // accessibility button is clicked per display.
                         service.notifyAccessibilityButtonClickedLocked();
                         return;
                     }
@@ -1269,22 +1284,24 @@
             }
             // The user may have turned off the assigned service or feature
             mMainHandler.sendMessage(obtainMessage(
-                    AccessibilityManagerService::showAccessibilityButtonTargetSelection, this));
+                    AccessibilityManagerService::showAccessibilityButtonTargetSelection, this,
+                    displayId));
         }
     }
 
-    private void sendAccessibilityButtonToInputFilter() {
+    private void sendAccessibilityButtonToInputFilter(int displayId) {
         synchronized (mLock) {
             if (mHasInputFilter && mInputFilter != null) {
-                mInputFilter.notifyAccessibilityButtonClicked();
+                mInputFilter.notifyAccessibilityButtonClicked(displayId);
             }
         }
     }
 
-    private void showAccessibilityButtonTargetSelection() {
+    private void showAccessibilityButtonTargetSelection(int displayId) {
         Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        mContext.startActivityAsUser(intent, UserHandle.of(mCurrentUserId));
+        final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
+        mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId));
     }
 
     private void notifyAccessibilityButtonVisibilityChangedLocked(boolean available) {
@@ -1827,8 +1844,6 @@
         updateFilterKeyEventsLocked(userState);
         updateTouchExplorationLocked(userState);
         updatePerformGesturesLocked(userState);
-        updateDisplayDaltonizerLocked(userState);
-        updateDisplayInversionLocked(userState);
         updateMagnificationLocked(userState);
         scheduleUpdateFingerprintGestureHandling(userState);
         scheduleUpdateInputFilter(userState);
@@ -2187,28 +2202,39 @@
         return false;
     }
 
-    private void updateDisplayDaltonizerLocked(UserState userState) {
-        DisplayAdjustmentUtils.applyDaltonizerSetting(mContext, userState.mUserId);
-    }
-
-    private void updateDisplayInversionLocked(UserState userState) {
-        DisplayAdjustmentUtils.applyInversionSetting(mContext, userState.mUserId);
-    }
-
     private void updateMagnificationLocked(UserState userState) {
         if (userState.mUserId != mCurrentUserId) {
             return;
         }
 
-        if (!mUiAutomationManager.suppressingAccessibilityServicesLocked()
-                && (userState.mIsDisplayMagnificationEnabled
-                        || userState.mIsNavBarMagnificationEnabled
-                        || userHasListeningMagnificationServicesLocked(userState))) {
-            // Initialize the magnification controller if necessary
-            getMagnificationController();
-            mMagnificationController.register();
-        } else if (mMagnificationController != null) {
-            mMagnificationController.unregister();
+        if (mUiAutomationManager.suppressingAccessibilityServicesLocked()
+                && mMagnificationController != null) {
+            mMagnificationController.unregisterAll();
+            return;
+        }
+
+        // Get all valid displays and register them if global magnification is enabled.
+        // We would skip overlay display because it uses overlay window to simulate secondary
+        // displays in one display. It's not a real display and there's no input events for it.
+        final ArrayList<Display> displays = getValidDisplayList();
+        if (userState.mIsDisplayMagnificationEnabled
+                || userState.mIsNavBarMagnificationEnabled) {
+            for (int i = 0; i < displays.size(); i++) {
+                final Display display = displays.get(i);
+                getMagnificationController().register(display.getDisplayId());
+            }
+            return;
+        }
+
+        // Register if display has listening magnification services.
+        for (int i = 0; i < displays.size(); i++) {
+            final Display display = displays.get(i);
+            final int displayId = display.getDisplayId();
+            if (userHasListeningMagnificationServicesLocked(userState, displayId)) {
+                getMagnificationController().register(displayId);
+            } else if (mMagnificationController != null) {
+                mMagnificationController.unregister(displayId);
+            }
         }
     }
 
@@ -2231,12 +2257,13 @@
      * Returns whether the specified user has any services that are capable of
      * controlling magnification and are actively listening for magnification updates.
      */
-    private boolean userHasListeningMagnificationServicesLocked(UserState userState) {
+    private boolean userHasListeningMagnificationServicesLocked(UserState userState,
+            int displayId) {
         final List<AccessibilityServiceConnection> services = userState.mBoundServices;
         for (int i = 0, count = services.size(); i < count; i++) {
             final AccessibilityServiceConnection service = services.get(i);
             if (mSecurityPolicy.canControlMagnification(service)
-                    && service.isMagnificationCallbackEnabled()) {
+                    && service.isMagnificationCallbackEnabled(displayId)) {
                 return true;
             }
         }
@@ -3762,6 +3789,92 @@
         }
     }
 
+    /**
+     * Gets all currently valid logical displays.
+     *
+     * @return An array list containing all valid logical displays.
+     */
+    public ArrayList<Display> getValidDisplayList() {
+        return mA11yDisplayListener.getValidDisplayList();
+    }
+
+    /**
+     * A Utility class to handle display state.
+     */
+    public class AccessibilityDisplayListener implements DisplayManager.DisplayListener {
+        private final DisplayManager mDisplayManager;
+        private final ArrayList<Display> mDisplaysList = new ArrayList<>();
+
+        AccessibilityDisplayListener(Context context, MainHandler handler) {
+            mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+            mDisplayManager.registerDisplayListener(this, handler);
+            initializeDisplayList();
+        }
+
+        ArrayList<Display> getValidDisplayList() {
+            synchronized (mLock) {
+                return mDisplaysList;
+            }
+        }
+
+        private void initializeDisplayList() {
+            final Display[] displays = mDisplayManager.getDisplays();
+            synchronized (mLock) {
+                mDisplaysList.clear();
+                for (int i = 0; i < displays.length; i++) {
+                    // Exclude overlay virtual displays. The display list is for A11yInputFilter
+                    // to create event handler per display. The events should be handled by the
+                    // display which is overlaid by it.
+                    final Display display = displays[i];
+                    if (display.getType() == Display.TYPE_OVERLAY) {
+                        continue;
+                    }
+                    mDisplaysList.add(display);
+                }
+            }
+        }
+
+        @Override
+        public void onDisplayAdded(int displayId) {
+            final Display display = mDisplayManager.getDisplay(displayId);
+            if (display == null || display.getType() == Display.TYPE_OVERLAY) {
+                return;
+            }
+
+            synchronized (mLock) {
+                mDisplaysList.add(display);
+                if (mInputFilter != null) {
+                    mInputFilter.onDisplayChanged();
+                }
+                UserState userState = getCurrentUserStateLocked();
+                updateMagnificationLocked(userState);
+            }
+        }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {
+            synchronized (mLock) {
+                for (int i = 0; i < mDisplaysList.size(); i++) {
+                    if (mDisplaysList.get(i).getDisplayId() == displayId) {
+                        mDisplaysList.remove(i);
+                        break;
+                    }
+                }
+                if (mInputFilter != null) {
+                    mInputFilter.onDisplayChanged();
+                }
+            }
+            if (mMagnificationController != null) {
+                mMagnificationController.onDisplayRemoved(displayId);
+            }
+        }
+
+        @Override
+        public void onDisplayChanged(int displayId) {
+            /* do nothing */
+        }
+    }
+
     /** Represents an {@link AccessibilityManager} */
     class Client {
         final IAccessibilityManagerClient mCallback;
@@ -4104,15 +4217,6 @@
         private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
                 .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
 
-        private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(
-                Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
-
-        private final Uri mDisplayDaltonizerEnabledUri = Settings.Secure.getUriFor(
-                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
-
-        private final Uri mDisplayDaltonizerUri = Settings.Secure.getUriFor(
-                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER);
-
         private final Uri mHighTextContrastUri = Settings.Secure.getUriFor(
                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED);
 
@@ -4153,12 +4257,6 @@
                     mTouchExplorationGrantedAccessibilityServicesUri,
                     false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(
-                    mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL);
-            contentResolver.registerContentObserver(
-                    mDisplayDaltonizerEnabledUri, false, this, UserHandle.USER_ALL);
-            contentResolver.registerContentObserver(
-                    mDisplayDaltonizerUri, false, this, UserHandle.USER_ALL);
-            contentResolver.registerContentObserver(
                     mHighTextContrastUri, false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(
                     mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL);
@@ -4202,11 +4300,6 @@
                     if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) {
                         onUserStateChangedLocked(userState);
                     }
-                } else if (mDisplayDaltonizerEnabledUri.equals(uri)
-                        || mDisplayDaltonizerUri.equals(uri)) {
-                    updateDisplayDaltonizerLocked(userState);
-                } else if (mDisplayInversionEnabledUri.equals(uri)) {
-                    updateDisplayInversionLocked(userState);
                 } else if (mHighTextContrastUri.equals(uri)) {
                     if (readHighTextContrastEnabledSettingLocked(userState)) {
                         onUserStateChangedLocked(userState);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 86132a8..a19a847 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -109,7 +109,7 @@
         UserState userState = mUserStateWeakReference.get();
         if (userState == null) return;
         userState.removeServiceLocked(this);
-        mSystemSupport.getMagnificationController().resetIfNeeded(mId);
+        mSystemSupport.getMagnificationController().resetAllIfNeeded(mId);
         resetLocked();
     }
 
@@ -256,7 +256,7 @@
                 userState.serviceDisconnectedLocked(this);
             }
             resetLocked();
-            mSystemSupport.getMagnificationController().resetIfNeeded(mId);
+            mSystemSupport.getMagnificationController().resetAllIfNeeded(mId);
             mSystemSupport.onClientChangeLocked(false);
         }
     }
diff --git a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
deleted file mode 100644
index c81a876..0000000
--- a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.accessibility;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.os.Binder;
-import android.provider.Settings.Secure;
-import android.view.accessibility.AccessibilityManager;
-
-import com.android.server.LocalServices;
-import com.android.server.display.DisplayTransformManager;
-
-/**
- * Utility methods for performing accessibility display adjustments.
- */
-class DisplayAdjustmentUtils {
-
-    /** Default inversion mode for display color correction. */
-    private static final int DEFAULT_DISPLAY_DALTONIZER =
-            AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY;
-
-    /** Matrix and offset used for converting color to gray-scale. */
-    private static final float[] MATRIX_GRAYSCALE = new float[] {
-        .2126f, .2126f, .2126f, 0,
-        .7152f, .7152f, .7152f, 0,
-        .0722f, .0722f, .0722f, 0,
-             0,      0,      0, 1
-    };
-
-    /**
-     * Matrix and offset used for luminance inversion. Represents a transform
-     * from RGB to YIQ color space, rotation around the Y axis by 180 degrees,
-     * transform back to RGB color space, and subtraction from 1. The last row
-     * represents a non-multiplied addition, see surfaceflinger's ProgramCache
-     * for full implementation details.
-     */
-    private static final float[] MATRIX_INVERT_COLOR = new float[] {
-        0.402f, -0.598f, -0.599f, 0,
-       -1.174f, -0.174f, -1.175f, 0,
-       -0.228f, -0.228f,  0.772f, 0,
-             1,       1,       1, 1
-    };
-
-    public static void applyDaltonizerSetting(Context context, int userId) {
-        final ContentResolver cr = context.getContentResolver();
-        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
-
-        int daltonizerMode = AccessibilityManager.DALTONIZER_DISABLED;
-        long identity = Binder.clearCallingIdentity();
-        try {
-            if (Secure.getIntForUser(cr,
-                    Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0) {
-                daltonizerMode = Secure.getIntForUser(cr,
-                        Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER, userId);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-
-        float[] grayscaleMatrix = null;
-        if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
-            // Monochromacy isn't supported by the native Daltonizer.
-            grayscaleMatrix = MATRIX_GRAYSCALE;
-            daltonizerMode = AccessibilityManager.DALTONIZER_DISABLED;
-        }
-        dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, grayscaleMatrix);
-        dtm.setDaltonizerMode(daltonizerMode);
-    }
-
-    /**
-     * Applies the specified user's display color adjustments.
-     */
-    public static void applyInversionSetting(Context context, int userId) {
-        final ContentResolver cr = context.getContentResolver();
-        final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
-
-        long identity = Binder.clearCallingIdentity();
-        try {
-            final boolean invertColors = Secure.getIntForUser(cr,
-                    Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) != 0;
-            dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR,
-                    invertColors ? MATRIX_INVERT_COLOR : null);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-}
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index 17bf570..e784056 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -19,7 +19,6 @@
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -41,7 +40,6 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.SomeArgs;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.LocalServices;
 import com.android.server.wm.WindowManagerInternal;
@@ -63,7 +61,7 @@
     private static final String LOG_TAG = "MagnificationController";
 
     public static final float MIN_SCALE = 1.0f;
-    public static final float MAX_SCALE = 5.0f;
+    public static final float MAX_SCALE = 8.0f;
 
     private static final boolean DEBUG_SET_MAGNIFICATION_SPEC = false;
 
@@ -71,9 +69,7 @@
 
     private final Object mLock;
 
-    private final AccessibilityManagerService mAms;
-
-    private final SettingsBridge mSettingsBridge;
+    private final ControllerContext mControllerCtx;
 
     private final ScreenStateObserver mScreenStateObserver;
 
@@ -81,11 +77,9 @@
 
     private final long mMainThreadId;
 
-    private Handler mHandler;
-
-    private final WindowManagerInternal mWindowManager;
-
-    private final DisplayMagnification mDisplay;
+    /** List of display Magnification, mapping from displayId -> DisplayMagnification. */
+    @GuardedBy("mLock")
+    private final SparseArray<DisplayMagnification> mDisplays = new SparseArray<>(0);
 
     /**
      * This class implements {@link WindowManagerInternal.MagnificationCallbacks} and holds
@@ -110,46 +104,82 @@
         // Flag indicating that we are registered with window manager.
         private boolean mRegistered;
         private boolean mUnregisterPending;
+        private boolean mDeleteAfterUnregister;
 
         private final int mDisplayId;
 
         private static final int INVALID_ID = -1;
         private int mIdOfLastServiceToMagnify = INVALID_ID;
 
-
-        DisplayMagnification(int displayId, SpecAnimationBridge specAnimation) {
+        DisplayMagnification(int displayId) {
             mDisplayId = displayId;
-            mSpecAnimationBridge = specAnimation;
+            mSpecAnimationBridge = new SpecAnimationBridge(mControllerCtx, mLock, mDisplayId);
         }
 
-        void register() {
-            synchronized (mLock) {
-                if (!mRegistered) {
-                    mWindowManager.setMagnificationCallbacks(this);
-                    mSpecAnimationBridge.setEnabled(true);
-                    // Obtain initial state.
-                    mWindowManager.getMagnificationRegion(mMagnificationRegion);
-                    mMagnificationRegion.getBounds(mMagnificationBounds);
-                    mRegistered = true;
-                }
+        /**
+         * Registers magnification callback and get current magnification region from
+         * window manager.
+         *
+         * @return true if callback registers successful.
+         */
+        @GuardedBy("mLock")
+        boolean register() {
+            mRegistered = mControllerCtx.getWindowManager().setMagnificationCallbacks(
+                    mDisplayId, this);
+            if (!mRegistered) {
+                Slog.w(LOG_TAG, "set magnification callbacks fail, displayId:" + mDisplayId);
+                return false;
             }
+            mSpecAnimationBridge.setEnabled(true);
+            // Obtain initial state.
+            mControllerCtx.getWindowManager().getMagnificationRegion(
+                    mDisplayId, mMagnificationRegion);
+            mMagnificationRegion.getBounds(mMagnificationBounds);
+            return true;
         }
 
-        void unregister() {
-            synchronized (mLock) {
-                if (!isMagnifying()) {
-                    unregisterInternalLocked();
-                } else {
-                    mUnregisterPending = true;
-                    reset(true);
-                }
+        /**
+         * Unregisters magnification callback from window manager. Callbacks to
+         * {@link MagnificationController#unregisterCallbackLocked(int, boolean)} after
+         * unregistered.
+         *
+         * @param delete true if this instance should be removed from the SparseArray in
+         *               MagnificationController after unregistered, for example, display removed.
+         */
+        @GuardedBy("mLock")
+        void unregister(boolean delete) {
+            if (mRegistered) {
+                mSpecAnimationBridge.setEnabled(false);
+                mControllerCtx.getWindowManager().setMagnificationCallbacks(
+                        mDisplayId, null);
+                mMagnificationRegion.setEmpty();
+                mRegistered = false;
+                unregisterCallbackLocked(mDisplayId, delete);
             }
+            mUnregisterPending = false;
         }
 
-        boolean isRegisteredLocked() {
+        /**
+         * Reset magnification status with animation enabled. {@link #unregister(boolean)} will be
+         * called after animation finished.
+         *
+         * @param delete true if this instance should be removed from the SparseArray in
+         *               MagnificationController after unregistered, for example, display removed.
+         */
+        @GuardedBy("mLock")
+        void unregisterPending(boolean delete) {
+            mDeleteAfterUnregister = delete;
+            mUnregisterPending = true;
+            reset(true);
+        }
+
+        boolean isRegistered() {
             return mRegistered;
         }
 
+        boolean isMagnifying() {
+            return mCurrentMagnificationSpec.scale > 1.0f;
+        }
 
         float getScale() {
             return mCurrentMagnificationSpec.scale;
@@ -159,18 +189,20 @@
             return mCurrentMagnificationSpec.offsetX;
         }
 
-        float getCenterX() {
-            synchronized (mLock) {
-                return (mMagnificationBounds.width() / 2.0f
-                        + mMagnificationBounds.left - getOffsetX()) / getScale();
-            }
+        float getOffsetY() {
+            return mCurrentMagnificationSpec.offsetY;
         }
 
+        @GuardedBy("mLock")
+        float getCenterX() {
+            return (mMagnificationBounds.width() / 2.0f
+                    + mMagnificationBounds.left - getOffsetX()) / getScale();
+        }
+
+        @GuardedBy("mLock")
         float getCenterY() {
-            synchronized (mLock) {
-                return (mMagnificationBounds.height() / 2.0f
-                        + mMagnificationBounds.top - getOffsetY()) / getScale();
-            }
+            return (mMagnificationBounds.height() / 2.0f
+                    + mMagnificationBounds.top - getOffsetY()) / getScale();
         }
 
         /**
@@ -206,64 +238,35 @@
             return mSpecAnimationBridge.mSentMagnificationSpec.offsetY;
         }
 
-        boolean resetIfNeeded(boolean animate) {
-            synchronized (mLock) {
-                if (isMagnifying()) {
-                    reset(animate);
-                    return true;
-                }
-                return false;
-            }
-        }
-
-        float getOffsetY() {
-            return mCurrentMagnificationSpec.offsetY;
-        }
-
-        boolean isMagnifying() {
-            return mCurrentMagnificationSpec.scale > 1.0f;
-        }
-
-        void unregisterInternalLocked() {
-            if (mRegistered) {
-                mSpecAnimationBridge.setEnabled(false);
-                mWindowManager.setMagnificationCallbacks(null);
-                mMagnificationRegion.setEmpty();
-
-                mRegistered = false;
-            }
-            mUnregisterPending = false;
-        }
-
-
         @Override
         public void onMagnificationRegionChanged(Region magnificationRegion) {
             final Message m = PooledLambda.obtainMessage(
-                    DisplayMagnification.this::updateMagnificationRegion,
+                    DisplayMagnification::updateMagnificationRegion, this,
                     Region.obtain(magnificationRegion));
-            mHandler.sendMessage(m);
+            mControllerCtx.getHandler().sendMessage(m);
         }
 
         @Override
         public void onRectangleOnScreenRequested(int left, int top, int right, int bottom) {
             final Message m = PooledLambda.obtainMessage(
-                    DisplayMagnification.this::requestRectangleOnScreen, left, top, right, bottom);
-            mHandler.sendMessage(m);
+                    DisplayMagnification::requestRectangleOnScreen, this,
+                    left, top, right, bottom);
+            mControllerCtx.getHandler().sendMessage(m);
         }
 
         @Override
         public void onRotationChanged(int rotation) {
             // Treat as context change and reset
-            final Message m = PooledLambda.obtainMessage(DisplayMagnification.this::resetIfNeeded,
-                    true);
-            mHandler.sendMessage(m);
+            final Message m = PooledLambda.obtainMessage(MagnificationController::resetIfNeeded,
+                    MagnificationController.this, mDisplayId, true);
+            mControllerCtx.getHandler().sendMessage(m);
         }
 
         @Override
         public void onUserContextChanged() {
-            final Message m = PooledLambda.obtainMessage(DisplayMagnification.this::resetIfNeeded,
-                    true);
-            mHandler.sendMessage(m);
+            final Message m = PooledLambda.obtainMessage(MagnificationController::resetIfNeeded,
+                    MagnificationController.this, mDisplayId, true);
+            mControllerCtx.getHandler().sendMessage(m);
         }
 
         /**
@@ -301,8 +304,9 @@
                 mSpecAnimationBridge.updateSentSpecMainThread(spec, animate);
             } else {
                 final Message m = PooledLambda.obtainMessage(
-                        this.mSpecAnimationBridge::updateSentSpecMainThread, spec, animate);
-                mHandler.sendMessage(m);
+                        SpecAnimationBridge::updateSentSpecMainThread,
+                        mSpecAnimationBridge, spec, animate);
+                mControllerCtx.getHandler().sendMessage(m);
             }
         }
 
@@ -316,30 +320,26 @@
         }
 
         void onMagnificationChangedLocked() {
-            mAms.notifyMagnificationChanged(mMagnificationRegion,
+            mControllerCtx.getAms().notifyMagnificationChanged(mDisplayId, mMagnificationRegion,
                     getScale(), getCenterX(), getCenterY());
             if (mUnregisterPending && !isMagnifying()) {
-                unregisterInternalLocked();
+                unregister(mDeleteAfterUnregister);
             }
         }
 
+        @GuardedBy("mLock")
         boolean magnificationRegionContains(float x, float y) {
-            synchronized (mLock) {
-                return mMagnificationRegion.contains((int) x, (int) y);
-
-            }
+            return mMagnificationRegion.contains((int) x, (int) y);
         }
 
+        @GuardedBy("mLock")
         void getMagnificationBounds(@NonNull Rect outBounds) {
-            synchronized (mLock) {
-                outBounds.set(mMagnificationBounds);
-            }
+            outBounds.set(mMagnificationBounds);
         }
 
+        @GuardedBy("mLock")
         void getMagnificationRegion(@NonNull Region outRegion) {
-            synchronized (mLock) {
-                outRegion.set(mMagnificationRegion);
-            }
+            outRegion.set(mMagnificationRegion);
         }
 
         void requestRectangleOnScreen(int left, int top, int right, int bottom) {
@@ -395,94 +395,76 @@
             outFrame.scale(1.0f / scale);
         }
 
-        /**
-         * Resets magnification if last magnifying service is disabled.
-         *
-         * @param connectionId the connection ID be disabled.
-         * @return {@code true} on success, {@code false} on failure
-         */
-        boolean resetIfNeeded(int connectionId) {
-            if (mIdOfLastServiceToMagnify == connectionId) {
-                return resetIfNeeded(true /*animate*/);
-            }
-            return false;
-        }
-
+        @GuardedBy("mLock")
         void setForceShowMagnifiableBounds(boolean show) {
             if (mRegistered) {
-                mWindowManager.setForceShowMagnifiableBounds(show);
+                mControllerCtx.getWindowManager().setForceShowMagnifiableBounds(
+                        mDisplayId, show);
             }
         }
 
+        @GuardedBy("mLock")
         boolean reset(boolean animate) {
-            synchronized (mLock) {
-                if (!mRegistered) {
-                    return false;
-                }
-                final MagnificationSpec spec = mCurrentMagnificationSpec;
-                final boolean changed = !spec.isNop();
-                if (changed) {
-                    spec.clear();
-                    onMagnificationChangedLocked();
-                }
-                mIdOfLastServiceToMagnify = INVALID_ID;
-                sendSpecToAnimation(spec, animate);
-                return changed;
+            if (!mRegistered) {
+                return false;
             }
+            final MagnificationSpec spec = mCurrentMagnificationSpec;
+            final boolean changed = !spec.isNop();
+            if (changed) {
+                spec.clear();
+                onMagnificationChangedLocked();
+            }
+            mIdOfLastServiceToMagnify = INVALID_ID;
+            sendSpecToAnimation(spec, animate);
+            return changed;
         }
 
-
+        @GuardedBy("mLock")
         boolean setScale(float scale, float pivotX, float pivotY,
                 boolean animate, int id) {
-
-            synchronized (mLock) {
-                if (!mRegistered) {
-                    return false;
-                }
-                // Constrain scale immediately for use in the pivot calculations.
-                scale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
-
-                final Rect viewport = mTempRect;
-                mMagnificationRegion.getBounds(viewport);
-                final MagnificationSpec spec = mCurrentMagnificationSpec;
-                final float oldScale = spec.scale;
-                final float oldCenterX
-                        = (viewport.width() / 2.0f - spec.offsetX + viewport.left) / oldScale;
-                final float oldCenterY
-                        = (viewport.height() / 2.0f - spec.offsetY + viewport.top) / oldScale;
-                final float normPivotX = (pivotX - spec.offsetX) / oldScale;
-                final float normPivotY = (pivotY - spec.offsetY) / oldScale;
-                final float offsetX = (oldCenterX - normPivotX) * (oldScale / scale);
-                final float offsetY = (oldCenterY - normPivotY) * (oldScale / scale);
-                final float centerX = normPivotX + offsetX;
-                final float centerY = normPivotY + offsetY;
-                mIdOfLastServiceToMagnify = id;
-
-                return setScaleAndCenter(scale, centerX, centerY, animate, id);
+            if (!mRegistered) {
+                return false;
             }
+            // Constrain scale immediately for use in the pivot calculations.
+            scale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
+
+            final Rect viewport = mTempRect;
+            mMagnificationRegion.getBounds(viewport);
+            final MagnificationSpec spec = mCurrentMagnificationSpec;
+            final float oldScale = spec.scale;
+            final float oldCenterX =
+                    (viewport.width() / 2.0f - spec.offsetX + viewport.left) / oldScale;
+            final float oldCenterY =
+                    (viewport.height() / 2.0f - spec.offsetY + viewport.top) / oldScale;
+            final float normPivotX = (pivotX - spec.offsetX) / oldScale;
+            final float normPivotY = (pivotY - spec.offsetY) / oldScale;
+            final float offsetX = (oldCenterX - normPivotX) * (oldScale / scale);
+            final float offsetY = (oldCenterY - normPivotY) * (oldScale / scale);
+            final float centerX = normPivotX + offsetX;
+            final float centerY = normPivotY + offsetY;
+            mIdOfLastServiceToMagnify = id;
+            return setScaleAndCenter(scale, centerX, centerY, animate, id);
         }
 
+        @GuardedBy("mLock")
         boolean setScaleAndCenter(float scale, float centerX, float centerY,
                 boolean animate, int id) {
-
-            synchronized (mLock) {
-                if (!mRegistered) {
-                    return false;
-                }
-                if (DEBUG) {
-                    Slog.i(LOG_TAG,
-                            "setScaleAndCenterLocked(scale = " + scale + ", centerX = " + centerX
-                                    + ", centerY = " + centerY + ", animate = " + animate
-                                    + ", id = " + id
-                                    + ")");
-                }
-                final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
-                sendSpecToAnimation(mCurrentMagnificationSpec, animate);
-                if (isMagnifying() && (id != INVALID_ID)) {
-                    mIdOfLastServiceToMagnify = id;
-                }
-                return changed;
+            if (!mRegistered) {
+                return false;
             }
+            if (DEBUG) {
+                Slog.i(LOG_TAG,
+                        "setScaleAndCenterLocked(scale = " + scale + ", centerX = " + centerX
+                                + ", centerY = " + centerY + ", animate = " + animate
+                                + ", id = " + id
+                                + ")");
+            }
+            final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
+            sendSpecToAnimation(mCurrentMagnificationSpec, animate);
+            if (isMagnifying() && (id != INVALID_ID)) {
+                mIdOfLastServiceToMagnify = id;
+            }
+            return changed;
         }
 
         /**
@@ -530,22 +512,21 @@
             return changed;
         }
 
+        @GuardedBy("mLock")
         void offsetMagnifiedRegion(float offsetX, float offsetY, int id) {
-            synchronized (mLock) {
-                if (!mRegistered) {
-                    return;
-                }
-
-                final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX;
-                final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY;
-                if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) {
-                    onMagnificationChangedLocked();
-                }
-                if (id != INVALID_ID) {
-                    mIdOfLastServiceToMagnify = id;
-                }
-                sendSpecToAnimation(mCurrentMagnificationSpec, false);
+            if (!mRegistered) {
+                return;
             }
+
+            final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX;
+            final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY;
+            if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) {
+                onMagnificationChangedLocked();
+            }
+            if (id != INVALID_ID) {
+                mIdOfLastServiceToMagnify = id;
+            }
+            sendSpecToAnimation(mCurrentMagnificationSpec, false);
         }
 
         boolean updateCurrentSpecWithOffsetsLocked(float nonNormOffsetX, float nonNormOffsetY) {
@@ -596,44 +577,38 @@
 
         @Override
         public String toString() {
-            return "DisplayMagnification{" +
-                    "mCurrentMagnificationSpec=" + mCurrentMagnificationSpec +
-                    ", mMagnificationRegion=" + mMagnificationRegion +
-                    ", mMagnificationBounds=" + mMagnificationBounds +
-                    ", mDisplayId=" + mDisplayId +
-                    ", mUserId=" + mUserId +
-                    ", mIdOfLastServiceToMagnify=" + mIdOfLastServiceToMagnify +
-                    ", mRegistered=" + mRegistered +
-                    ", mUnregisterPending=" + mUnregisterPending +
-                    '}';
+            return "DisplayMagnification["
+                    + "mCurrentMagnificationSpec=" + mCurrentMagnificationSpec
+                    + ", mMagnificationRegion=" + mMagnificationRegion
+                    + ", mMagnificationBounds=" + mMagnificationBounds
+                    + ", mDisplayId=" + mDisplayId
+                    + ", mIdOfLastServiceToMagnify=" + mIdOfLastServiceToMagnify
+                    + ", mRegistered=" + mRegistered
+                    + ", mUnregisterPending=" + mUnregisterPending
+                    + ']';
         }
-
     }
 
-    public MagnificationController(Context context, AccessibilityManagerService ams, Object lock) {
-        this(context, ams, lock, null, LocalServices.getService(WindowManagerInternal.class),
-                new ValueAnimator(), new SettingsBridge(context.getContentResolver()));
-        mHandler = new Handler(context.getMainLooper());
+    /**
+     * MagnificationController Constructor
+     */
+    public MagnificationController(@NonNull Context context,
+            @NonNull AccessibilityManagerService ams, @NonNull Object lock) {
+        this(new ControllerContext(context, ams,
+                LocalServices.getService(WindowManagerInternal.class),
+                new Handler(context.getMainLooper()),
+                context.getResources().getInteger(R.integer.config_longAnimTime)), lock);
     }
 
-    public MagnificationController(
-            Context context,
-            AccessibilityManagerService ams,
-            Object lock,
-            Handler handler,
-            WindowManagerInternal windowManagerInternal,
-            ValueAnimator valueAnimator,
-            SettingsBridge settingsBridge) {
-        mHandler = handler;
-        mWindowManager = windowManagerInternal;
-        mMainThreadId = context.getMainLooper().getThread().getId();
-        mAms = ams;
-        mScreenStateObserver = new ScreenStateObserver(context, this);
+    /**
+     * Constructor for tests
+     */
+    @VisibleForTesting
+    public MagnificationController(@NonNull ControllerContext ctx, @NonNull Object lock) {
+        mControllerCtx = ctx;
         mLock = lock;
-        mSettingsBridge = settingsBridge;
-        //TODO (multidisplay): Magnification is supported only for the default display.
-        mDisplay =  new DisplayMagnification(Display.DEFAULT_DISPLAY,
-                new SpecAnimationBridge(context, mLock, mWindowManager, valueAnimator));
+        mMainThreadId = mControllerCtx.getContext().getMainLooper().getThread().getId();
+        mScreenStateObserver = new ScreenStateObserver(mControllerCtx.getContext(), this);
     }
 
     /**
@@ -642,54 +617,114 @@
      *
      * This tracking imposes a cost on the system, so we avoid tracking this data unless it's
      * required.
+     *
+     * @param displayId The logical display id.
      */
-    public void register() {
+    public void register(int displayId) {
         synchronized (mLock) {
-            mScreenStateObserver.register();
+            DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                display = new DisplayMagnification(displayId);
+            }
+            if (display.isRegistered()) {
+                return;
+            }
+            if (display.register()) {
+                mDisplays.put(displayId, display);
+                mScreenStateObserver.registerIfNecessary();
+            }
         }
-        mDisplay.register();
     }
 
     /**
      * Stop requiring tracking the magnification region. We may remain registered while we
      * reset magnification.
-     */
-    public void unregister() {
-        synchronized (mLock) {
-            mScreenStateObserver.unregister();
-        }
-        mDisplay.unregister();
-    }
-    
-    /**
-     * Check if we are registered. Note that we may be planning to unregister at any moment.
      *
-     * @return {@code true} if the controller is registered. {@code false} otherwise.
+     * @param displayId The logical display id.
      */
-    public boolean isRegisteredLocked() {
-        return mDisplay.isRegisteredLocked();
+    public void unregister(int displayId) {
+        synchronized (mLock) {
+            unregisterLocked(displayId, false);
+        }
     }
 
     /**
+     * Stop tracking all displays' magnification region.
+     */
+    public void unregisterAll() {
+        synchronized (mLock) {
+            // display will be removed from array after unregister, we need to clone it to
+            // prevent error.
+            final SparseArray<DisplayMagnification> displays = mDisplays.clone();
+            for (int i = 0; i < displays.size(); i++) {
+                unregisterLocked(displays.keyAt(i), false);
+            }
+        }
+    }
+
+    /**
+     * Remove the display magnification with given id.
+     *
+     * @param displayId The logical display id.
+     */
+    public void onDisplayRemoved(int displayId) {
+        synchronized (mLock) {
+            unregisterLocked(displayId, true);
+        }
+    }
+
+    /**
+     * Check if we are registered on specified display. Note that we may be planning to unregister
+     * at any moment.
+     *
+     * @return {@code true} if the controller is registered on specified display.
+     * {@code false} otherwise.
+     *
+     * @param displayId The logical display id.
+     */
+    public boolean isRegistered(int displayId) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return false;
+            }
+            return display.isRegistered();
+        }
+    }
+
+    /**
+     * @param displayId The logical display id.
      * @return {@code true} if magnification is active, e.g. the scale
      *         is > 1, {@code false} otherwise
      */
-    public boolean isMagnifying() {
-        return mDisplay.isMagnifying();
+    public boolean isMagnifying(int displayId) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return false;
+            }
+            return display.isMagnifying();
+        }
     }
 
     /**
      * Returns whether the magnification region contains the specified
      * screen-relative coordinates.
      *
+     * @param displayId The logical display id.
      * @param x the screen-relative X coordinate to check
      * @param y the screen-relative Y coordinate to check
      * @return {@code true} if the coordinate is contained within the
      *         magnified region, or {@code false} otherwise
      */
-    public boolean magnificationRegionContains(float x, float y) {
-        return mDisplay.magnificationRegionContains(x, y);
-
+    public boolean magnificationRegionContains(int displayId, float x, float y) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return false;
+            }
+            return display.magnificationRegionContains(x, y);
+        }
     }
 
     /**
@@ -697,11 +732,18 @@
      * magnification region. If magnification is not enabled, the returned
      * bounds will be empty.
      *
+     * @param displayId The logical display id.
      * @param outBounds rect to populate with the bounds of the magnified
      *                  region
      */
-    public void getMagnificationBounds(@NonNull Rect outBounds) {
-        mDisplay.getMagnificationBounds(outBounds);
+    public void getMagnificationBounds(int displayId, @NonNull Rect outBounds) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return;
+            }
+            display.getMagnificationBounds(outBounds);
+        }
     }
 
     /**
@@ -709,76 +751,122 @@
      * region. If magnification is not enabled, then the returned region
      * will be empty.
      *
+     * @param displayId The logical display id.
      * @param outRegion the region to populate
      */
-    public void getMagnificationRegion(@NonNull Region outRegion) {
-        mDisplay.getMagnificationRegion(outRegion);
+    public void getMagnificationRegion(int displayId, @NonNull Region outRegion) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return;
+            }
+            display.getMagnificationRegion(outRegion);
+        }
     }
 
     /**
      * Returns the magnification scale. If an animation is in progress,
      * this reflects the end state of the animation.
      *
+     * @param displayId The logical display id.
      * @return the scale
      */
-    public float getScale() {
-        return mDisplay.getScale();
+    public float getScale(int displayId) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return 1.0f;
+            }
+            return display.getScale();
+        }
     }
 
     /**
      * Returns the X offset of the magnification viewport. If an animation
      * is in progress, this reflects the end state of the animation.
      *
+     * @param displayId The logical display id.
      * @return the X offset
      */
-    public float getOffsetX() {
-        return mDisplay.getOffsetX();
+    public float getOffsetX(int displayId) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return 0.0f;
+            }
+            return display.getOffsetX();
+        }
     }
 
-
     /**
      * Returns the screen-relative X coordinate of the center of the
      * magnification viewport.
      *
+     * @param displayId The logical display id.
      * @return the X coordinate
      */
-    public float getCenterX() {
-        return mDisplay.getCenterX();
+    public float getCenterX(int displayId) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return 0.0f;
+            }
+            return display.getCenterX();
+        }
     }
 
     /**
      * Returns the Y offset of the magnification viewport. If an animation
      * is in progress, this reflects the end state of the animation.
      *
+     * @param displayId The logical display id.
      * @return the Y offset
      */
-    public float getOffsetY() {
-        return mDisplay.getOffsetY();
+    public float getOffsetY(int displayId) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return 0.0f;
+            }
+            return display.getOffsetY();
+        }
     }
 
     /**
      * Returns the screen-relative Y coordinate of the center of the
      * magnification viewport.
      *
+     * @param displayId The logical display id.
      * @return the Y coordinate
      */
-    public float getCenterY() {
-        return mDisplay.getCenterY();
+    public float getCenterY(int displayId) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return 0.0f;
+            }
+            return display.getCenterY();
+        }
     }
 
     /**
      * Resets the magnification scale and center, optionally animating the
      * transition.
      *
+     * @param displayId The logical display id.
      * @param animate {@code true} to animate the transition, {@code false}
      *                to transition immediately
      * @return {@code true} if the magnification spec changed, {@code false} if
      *         the spec did not change
      */
-    public boolean reset(boolean animate) {
-
-        return mDisplay.reset(animate);
-
+    public boolean reset(int displayId, boolean animate) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return false;
+            }
+            return display.reset(animate);
+        }
     }
 
     /**
@@ -786,6 +874,7 @@
      * optionally animating the transition. If animation is disabled, the
      * transition is immediate.
      *
+     * @param displayId The logical display id.
      * @param scale the target scale, must be >= 1
      * @param pivotX the screen-relative X coordinate around which to scale
      * @param pivotY the screen-relative Y coordinate around which to scale
@@ -795,15 +884,22 @@
      * @return {@code true} if the magnification spec changed, {@code false} if
      *         the spec did not change
      */
-    public boolean setScale(float scale, float pivotX, float pivotY, boolean animate, int id) {
-            return mDisplay.
-                    setScale(scale, pivotX, pivotY, animate, id);
+    public boolean setScale(int displayId, float scale, float pivotX, float pivotY,
+            boolean animate, int id) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return false;
+            }
+            return display.setScale(scale, pivotX, pivotY, animate, id);
+        }
     }
 
     /**
      * Sets the center of the magnified region, optionally animating the
      * transition. If animation is disabled, the transition is immediate.
      *
+     * @param displayId The logical display id.
      * @param centerX the screen-relative X coordinate around which to
      *                center
      * @param centerY the screen-relative Y coordinate around which to
@@ -814,9 +910,14 @@
      * @return {@code true} if the magnification spec changed, {@code false} if
      * the spec did not change
      */
-    public boolean setCenter(float centerX, float centerY, boolean animate, int id) {
-            return mDisplay.
-                    setScaleAndCenter(Float.NaN, centerX, centerY, animate, id);
+    public boolean setCenter(int displayId, float centerX, float centerY, boolean animate, int id) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return false;
+            }
+            return display.setScaleAndCenter(Float.NaN, centerX, centerY, animate, id);
+        }
     }
 
     /**
@@ -824,6 +925,7 @@
      * animating the transition. If animation is disabled, the transition
      * is immediate.
      *
+     * @param displayId The logical display id.
      * @param scale the target scale, or {@link Float#NaN} to leave unchanged
      * @param centerX the screen-relative X coordinate around which to
      *                center and scale, or {@link Float#NaN} to leave unchanged
@@ -835,53 +937,66 @@
      * @return {@code true} if the magnification spec changed, {@code false} if
      *         the spec did not change
      */
-    public boolean setScaleAndCenter(
-            float scale, float centerX, float centerY, boolean animate, int id) {
-        return mDisplay.
-                setScaleAndCenter(scale, centerX, centerY, animate, id);
+    public boolean setScaleAndCenter(int displayId, float scale, float centerX, float centerY,
+            boolean animate, int id) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return false;
+            }
+            return display.setScaleAndCenter(scale, centerX, centerY, animate, id);
+        }
     }
 
     /**
      * Offsets the magnified region. Note that the offsetX and offsetY values actually move in the
      * opposite direction as the offsets passed in here.
      *
+     * @param displayId The logical display id.
      * @param offsetX the amount in pixels to offset the region in the X direction, in current
      *                screen pixels.
      * @param offsetY the amount in pixels to offset the region in the Y direction, in current
      *                screen pixels.
      * @param id      the ID of the service requesting the change
      */
-    public void offsetMagnifiedRegion(float offsetX, float offsetY, int id) {
-        mDisplay.offsetMagnifiedRegion(offsetX, offsetY,
-                id);
+    public void offsetMagnifiedRegion(int displayId, float offsetX, float offsetY, int id) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return;
+            }
+            display.offsetMagnifiedRegion(offsetX, offsetY, id);
+        }
     }
 
     /**
      * Get the ID of the last service that changed the magnification spec.
      *
+     * @param displayId The logical display id.
      * @return The id
      */
-    public int getIdOfLastServiceToMagnify() {
-        return mDisplay.getIdOfLastServiceToMagnify();
+    public int getIdOfLastServiceToMagnify(int displayId) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return -1;
+            }
+            return display.getIdOfLastServiceToMagnify();
+        }
     }
 
     /**
-     * Persists the current magnification scale to the current user's settings.
+     * Persists the default display magnification scale to the current user's settings.
      */
     public void persistScale() {
-        persistScale(Display.DEFAULT_DISPLAY);
-    }
-    /**
-     * Persists the current magnification scale to the current user's settings.
-     */
-    public void persistScale(int displayId) {
-        final float scale = mDisplay.getScale();
+        // TODO: b/123047354, Need support multi-display?
+        final float scale = getScale(Display.DEFAULT_DISPLAY);
         final int userId = mUserId;
 
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
-                mSettingsBridge.putMagnificationScale(scale, displayId, userId);
+                mControllerCtx.putMagnificationScale(scale, userId);
                 return null;
             }
         }.execute();
@@ -895,7 +1010,7 @@
      *         scale if none is available
      */
     public float getPersistedScale() {
-        return mSettingsBridge.getMagnificationScale(Display.DEFAULT_DISPLAY, mUserId);
+        return mControllerCtx.getMagnificationScale(mUserId);
     }
 
     /**
@@ -904,50 +1019,136 @@
      * @param userId the currently active user ID
      */
     public void setUserId(int userId) {
-        if (mUserId != userId) {
-            mUserId = userId;
+        if (mUserId == userId) {
+            return;
+        }
+        mUserId = userId;
+        resetAllIfNeeded(false);
+    }
 
-            synchronized (mLock) {
-                if (isMagnifying()) {
-                    reset(false);
-                }
+    /**
+     * Resets all displays' magnification if last magnifying service is disabled.
+     *
+     * @param connectionId
+     */
+    public void resetAllIfNeeded(int connectionId) {
+        synchronized (mLock) {
+            for (int i = 0; i < mDisplays.size(); i++) {
+                resetIfNeeded(mDisplays.keyAt(i), connectionId);
             }
         }
     }
 
-   /**
+    /**
      * Resets magnification if magnification and auto-update are both enabled.
      *
+     * @param displayId The logical display id.
      * @param animate whether the animate the transition
-     * @return whether was {@link #isMagnifying magnifying}
+     * @return whether was {@link #isMagnifying(int) magnifying}
      */
-    public boolean resetIfNeeded(boolean animate) {
-        return mDisplay.resetIfNeeded(animate);
+    boolean resetIfNeeded(int displayId, boolean animate) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null || !display.isMagnifying()) {
+                return false;
+            }
+            display.reset(animate);
+            return true;
+        }
     }
 
     /**
      * Resets magnification if last magnifying service is disabled.
      *
+     * @param displayId The logical display id.
      * @param connectionId the connection ID be disabled.
      * @return {@code true} on success, {@code false} on failure
      */
-    public boolean resetIfNeeded(int connectionId) {
-        return mDisplay.resetIfNeeded(connectionId);
+    boolean resetIfNeeded(int displayId, int connectionId) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null || !display.isMagnifying()
+                    || connectionId != display.getIdOfLastServiceToMagnify()) {
+                return false;
+            }
+            display.reset(true);
+            return true;
+        }
     }
 
-    void setForceShowMagnifiableBounds(boolean show) {
-        mDisplay.setForceShowMagnifiableBounds(show);
+    void setForceShowMagnifiableBounds(int displayId, boolean show) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return;
+            }
+            display.setForceShowMagnifiableBounds(show);
+        }
     }
 
     private void onScreenTurnedOff() {
         final Message m = PooledLambda.obtainMessage(
-                mDisplay::resetIfNeeded, false);
-        mHandler.sendMessage(m);
+                MagnificationController::resetAllIfNeeded, this, false);
+        mControllerCtx.getHandler().sendMessage(m);
+    }
+
+    private void resetAllIfNeeded(boolean animate) {
+        synchronized (mLock) {
+            for (int i = 0; i < mDisplays.size(); i++) {
+                resetIfNeeded(mDisplays.keyAt(i), animate);
+            }
+        }
+    }
+
+    private void unregisterLocked(int displayId, boolean delete) {
+        final DisplayMagnification display = mDisplays.get(displayId);
+        if (display == null) {
+            return;
+        }
+        if (!display.isRegistered()) {
+            if (delete) {
+                mDisplays.remove(displayId);
+            }
+            return;
+        }
+        if (!display.isMagnifying()) {
+            display.unregister(delete);
+        } else {
+            display.unregisterPending(delete);
+        }
+    }
+
+    /**
+     * Callbacks from DisplayMagnification after display magnification unregistered. It will remove
+     * DisplayMagnification instance if delete is true, and unregister screen state if
+     * there is no registered display magnification.
+     */
+    private void unregisterCallbackLocked(int displayId, boolean delete) {
+        if (delete) {
+            mDisplays.remove(displayId);
+        }
+        // unregister screen state if necessary
+        boolean hasRegister = false;
+        for (int i = 0; i < mDisplays.size(); i++) {
+            final DisplayMagnification display = mDisplays.valueAt(i);
+            hasRegister = display.isRegistered();
+            if (hasRegister) {
+                break;
+            }
+        }
+        if (!hasRegister) {
+            mScreenStateObserver.unregister();
+        }
     }
 
     @Override
     public String toString() {
-        return mDisplay.toString();
+        StringBuilder builder = new StringBuilder();
+        builder.append("MagnificationController[");
+        builder.append("mUserId=").append(mUserId);
+        builder.append(", mDisplays=").append(mDisplays);
+        builder.append("]");
+        return builder.toString();
     }
 
     /**
@@ -955,7 +1156,7 @@
      * updates to the window manager.
      */
     private static class SpecAnimationBridge implements ValueAnimator.AnimatorUpdateListener {
-        private final WindowManagerInternal mWindowManager;
+        private final ControllerContext mControllerCtx;
 
         /**
          * The magnification spec that was sent to the window manager. This should
@@ -976,16 +1177,17 @@
 
         private final Object mLock;
 
+        private final int mDisplayId;
+
         @GuardedBy("mLock")
         private boolean mEnabled = false;
 
-        private SpecAnimationBridge(Context context, Object lock, WindowManagerInternal wm,
-                ValueAnimator animator) {
+        private SpecAnimationBridge(ControllerContext ctx, Object lock, int displayId) {
+            mControllerCtx = ctx;
             mLock = lock;
-            mWindowManager = wm;
-            final long animationDuration = context.getResources().getInteger(
-                    R.integer.config_longAnimTime);
-            mValueAnimator = animator;
+            mDisplayId = displayId;
+            final long animationDuration = mControllerCtx.getAnimationDuration();
+            mValueAnimator = mControllerCtx.newValueAnimator();
             mValueAnimator.setDuration(animationDuration);
             mValueAnimator.setInterpolator(new DecelerateInterpolator(2.5f));
             mValueAnimator.setFloatValues(0.0f, 1.0f);
@@ -1002,7 +1204,8 @@
                     mEnabled = enabled;
                     if (!mEnabled) {
                         mSentMagnificationSpec.clear();
-                        mWindowManager.setMagnificationSpec(mSentMagnificationSpec);
+                        mControllerCtx.getWindowManager().setMagnificationSpec(
+                                mDisplayId, mSentMagnificationSpec);
                     }
                 }
             }
@@ -1034,7 +1237,8 @@
                 }
 
                 mSentMagnificationSpec.setTo(spec);
-                mWindowManager.setMagnificationSpec(spec);
+                mControllerCtx.getWindowManager().setMagnificationSpec(
+                        mDisplayId, mSentMagnificationSpec);
             }
         }
 
@@ -1057,9 +1261,7 @@
                     mTmpMagnificationSpec.offsetY = mStartMagnificationSpec.offsetY +
                             (mEndMagnificationSpec.offsetY - mStartMagnificationSpec.offsetY)
                                     * fract;
-                    synchronized (mLock) {
-                        setMagnificationSpecLocked(mTmpMagnificationSpec);
-                    }
+                    setMagnificationSpecLocked(mTmpMagnificationSpec);
                 }
             }
         }
@@ -1075,7 +1277,7 @@
             mController = controller;
         }
 
-        public void register() {
+        public void registerIfNecessary() {
             if (!mRegistered) {
                 mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_SCREEN_OFF));
                 mRegistered = true;
@@ -1095,26 +1297,97 @@
         }
     }
 
-    // Extra class to get settings so tests can mock it
-    public static class SettingsBridge {
-        private final ContentResolver mContentResolver;
+    /**
+     * This class holds resources used between the classes in MagnificationController, and
+     * functions for tests to mock it.
+     */
+    @VisibleForTesting
+    public static class ControllerContext {
+        private final Context mContext;
+        private final AccessibilityManagerService mAms;
+        private final WindowManagerInternal mWindowManager;
+        private final Handler mHandler;
+        private final Long mAnimationDuration;
 
-        public SettingsBridge(ContentResolver contentResolver) {
-            mContentResolver = contentResolver;
+        /**
+         * Constructor for ControllerContext.
+         */
+        public ControllerContext(@NonNull Context context,
+                @NonNull AccessibilityManagerService ams,
+                @NonNull WindowManagerInternal windowManager,
+                @NonNull Handler handler,
+                long animationDuration) {
+            mContext = context;
+            mAms = ams;
+            mWindowManager = windowManager;
+            mHandler = handler;
+            mAnimationDuration = animationDuration;
         }
 
-        public void putMagnificationScale(float value, int displayId, int userId) {
-            Settings.Secure.putFloatForUser(mContentResolver,
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE + (
-                            Display.DEFAULT_DISPLAY == displayId ? "" : displayId),
-                    value, userId);
+        /**
+         * @return A context.
+         */
+        @NonNull
+        public Context getContext() {
+            return mContext;
         }
 
-        public float getMagnificationScale(int displayId, int userId) {
-            return Settings.Secure.getFloatForUser(mContentResolver,
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE
-                            + (Display.DEFAULT_DISPLAY == displayId ? "" : displayId),
+        /**
+         * @return AccessibilityManagerService
+         */
+        @NonNull
+        public AccessibilityManagerService getAms() {
+            return mAms;
+        }
+
+        /**
+         * @return WindowManagerInternal
+         */
+        @NonNull
+        public WindowManagerInternal getWindowManager() {
+            return mWindowManager;
+        }
+
+        /**
+         * @return Handler for main looper
+         */
+        @NonNull
+        public Handler getHandler() {
+            return mHandler;
+        }
+
+        /**
+         * Create a new ValueAnimator.
+         *
+         * @return ValueAnimator
+         */
+        @NonNull
+        public ValueAnimator newValueAnimator() {
+            return new ValueAnimator();
+        }
+
+        /**
+         * Write Settings of magnification scale.
+         */
+        public void putMagnificationScale(float value, int userId) {
+            Settings.Secure.putFloatForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, value, userId);
+        }
+
+        /**
+         * Get Settings of magnification scale.
+         */
+        public float getMagnificationScale(int userId) {
+            return Settings.Secure.getFloatForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
                     DEFAULT_MAGNIFICATION_SCALE, userId);
         }
+
+        /**
+         * @return Configuration of animation duration.
+         */
+        public long getAnimationDuration() {
+            return mAnimationDuration;
+        }
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 12e7376..49db488 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -43,6 +43,7 @@
 import android.util.MathUtils;
 import android.util.Slog;
 import android.util.TypedValue;
+import android.view.Display;
 import android.view.GestureDetector;
 import android.view.GestureDetector.SimpleOnGestureListener;
 import android.view.MotionEvent;
@@ -115,8 +116,11 @@
     private static final boolean DEBUG_PANNING_SCALING = false || DEBUG_ALL;
     private static final boolean DEBUG_EVENT_STREAM = false || DEBUG_ALL;
 
+    // The MIN_SCALE is different from MagnificationController.MIN_SCALE due
+    // to AccessibilityService.MagnificationController#setScale() has
+    // different scale range
     private static final float MIN_SCALE = 2.0f;
-    private static final float MAX_SCALE = 5.0f;
+    private static final float MAX_SCALE = MagnificationController.MAX_SCALE;
 
     @VisibleForTesting final MagnificationController mMagnificationController;
 
@@ -248,14 +252,16 @@
             mScreenStateReceiver.unregister();
         }
         // Check if need to reset when MagnificationGestureHandler is the last magnifying service.
-        mMagnificationController.resetIfNeeded(
+        mMagnificationController.resetAllIfNeeded(
                 AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
         clearAndTransitionToStateDetecting();
     }
 
     void notifyShortcutTriggered() {
         if (mDetectShortcutTrigger) {
-            boolean wasMagnifying = mMagnificationController.resetIfNeeded(/* animate */ true);
+            // TODO: multi-display support for magnification gesture handler
+            boolean wasMagnifying = mMagnificationController.resetIfNeeded(Display.DEFAULT_DISPLAY,
+                    /* animate */ true);
             if (wasMagnifying) {
                 clearAndTransitionToStateDetecting();
             } else {
@@ -416,8 +422,9 @@
                 Slog.i(LOG_TAG, "Panned content by scrollX: " + distanceX
                         + " scrollY: " + distanceY);
             }
-            mMagnificationController.offsetMagnifiedRegion(distanceX, distanceY,
-                    AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+            // TODO: multi-display support for magnification gesture handler
+            mMagnificationController.offsetMagnifiedRegion(Display.DEFAULT_DISPLAY, distanceX,
+                    distanceY, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
             return /* event consumed: */ true;
         }
 
@@ -433,7 +440,8 @@
                 return mScaling;
             }
 
-            final float initialScale = mMagnificationController.getScale();
+            // TODO: multi-display support for magnification gesture handler
+            final float initialScale = mMagnificationController.getScale(Display.DEFAULT_DISPLAY);
             final float targetScale = initialScale * detector.getScaleFactor();
 
             // Don't allow a gesture to move the user further outside the
@@ -455,7 +463,8 @@
             final float pivotX = detector.getFocusX();
             final float pivotY = detector.getFocusY();
             if (DEBUG_PANNING_SCALING) Slog.i(LOG_TAG, "Scaled content to: " + scale + "x");
-            mMagnificationController.setScale(scale, pivotX, pivotY, false,
+            // TODO: multi-display support for magnification gesture handler
+            mMagnificationController.setScale(Display.DEFAULT_DISPLAY, scale, pivotX, pivotY, false,
                     AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
             return /* handled: */ true;
         }
@@ -515,8 +524,10 @@
                     }
                     final float eventX = event.getX();
                     final float eventY = event.getY();
-                    if (mMagnificationController.magnificationRegionContains(eventX, eventY)) {
-                        mMagnificationController.setCenter(eventX, eventY,
+                    // TODO: multi-display support for magnification gesture handler
+                    if (mMagnificationController.magnificationRegionContains(
+                            Display.DEFAULT_DISPLAY, eventX, eventY)) {
+                        mMagnificationController.setCenter(Display.DEFAULT_DISPLAY, eventX, eventY,
                                 /* animate */ mLastMoveOutsideMagnifiedRegion,
                                 AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
                         mLastMoveOutsideMagnifiedRegion = false;
@@ -654,8 +665,9 @@
 
                     mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
 
+                    // TODO: multi-display support for magnification gesture handler
                     if (!mMagnificationController.magnificationRegionContains(
-                            event.getX(), event.getY())) {
+                            Display.DEFAULT_DISPLAY, event.getX(), event.getY())) {
 
                         transitionToDelegatingStateAndClear();
 
@@ -664,11 +676,16 @@
                         // 3tap and hold
                         afterLongTapTimeoutTransitionToDraggingState(event);
 
+                    } else if (isTapOutOfDistanceSlop()) {
+
+                        transitionToDelegatingStateAndClear();
+
                     } else if (mDetectTripleTap
                             // If magnified, delay an ACTION_DOWN for mMultiTapMaxDelay
                             // to ensure reachability of
                             // STATE_PANNING_SCALING(triggerable with ACTION_POINTER_DOWN)
-                            || mMagnificationController.isMagnifying()) {
+                            // TODO: multi-display support for magnification gesture handler
+                            || mMagnificationController.isMagnifying(Display.DEFAULT_DISPLAY)) {
 
                         afterMultiTapTimeoutTransitionToDelegatingState();
 
@@ -680,7 +697,8 @@
                 }
                 break;
                 case ACTION_POINTER_DOWN: {
-                    if (mMagnificationController.isMagnifying()) {
+                    // TODO: multi-display support for magnification gesture handler
+                    if (mMagnificationController.isMagnifying(Display.DEFAULT_DISPLAY)) {
                         transitionTo(mPanningScalingState);
                         clear();
                     } else {
@@ -709,8 +727,9 @@
 
                     mHandler.removeMessages(MESSAGE_ON_TRIPLE_TAP_AND_HOLD);
 
+                    // TODO: multi-display support for magnification gesture handler
                     if (!mMagnificationController.magnificationRegionContains(
-                            event.getX(), event.getY())) {
+                            Display.DEFAULT_DISPLAY, event.getX(), event.getY())) {
 
                         transitionToDelegatingStateAndClear();
 
@@ -861,7 +880,8 @@
             clear();
 
             // Toggle zoom
-            if (mMagnificationController.isMagnifying()) {
+            // TODO: multi-display support for magnification gesture handler
+            if (mMagnificationController.isMagnifying(Display.DEFAULT_DISPLAY)) {
                 zoomOff();
             } else {
                 zoomOn(up.getX(), up.getY());
@@ -873,8 +893,9 @@
             if (DEBUG_DETECTING) Slog.i(LOG_TAG, "onTripleTapAndHold()");
             clear();
 
+            // TODO: multi-display support for magnification gesture handler
             mViewportDraggingState.mZoomedInBeforeDrag =
-                    mMagnificationController.isMagnifying();
+                    mMagnificationController.isMagnifying(Display.DEFAULT_DISPLAY);
 
             zoomOn(down.getX(), down.getY());
 
@@ -901,7 +922,33 @@
             if (DEBUG_DETECTING) Slog.i(LOG_TAG, "setShortcutTriggered(" + state + ")");
 
             mShortcutTriggered = state;
-            mMagnificationController.setForceShowMagnifiableBounds(state);
+            // TODO: multi-display support for magnification gesture handler
+            mMagnificationController.setForceShowMagnifiableBounds(Display.DEFAULT_DISPLAY, state);
+        }
+
+        /**
+         * Detects if last action down is out of distance slop between with previous
+         * one, when triple tap is enabled.
+         *
+         * @return true if tap is out of distance slop
+         */
+        boolean isTapOutOfDistanceSlop() {
+            if (!mDetectTripleTap) return false;
+            if (mPreLastDown == null || mLastDown == null) {
+                return false;
+            }
+            final boolean outOfDistanceSlop =
+                    GestureUtils.distance(mPreLastDown, mLastDown) > mMultiTapMaxDistance;
+            if (tapCount() > 0) {
+                return outOfDistanceSlop;
+            }
+            // There's no tap in the queue here. We still need to check if this is the case that
+            // user tap screen quickly and out of distance slop.
+            if (outOfDistanceSlop
+                    && !GestureUtils.isTimedOut(mPreLastDown, mLastDown, mMultiTapMaxDelay)) {
+                return true;
+            }
+            return false;
         }
     }
 
@@ -911,7 +958,8 @@
         final float scale = MathUtils.constrain(
                 mMagnificationController.getPersistedScale(),
                 MIN_SCALE, MAX_SCALE);
-        mMagnificationController.setScaleAndCenter(
+        // TODO: multi-display support for magnification gesture handler
+        mMagnificationController.setScaleAndCenter(Display.DEFAULT_DISPLAY,
                 scale, centerX, centerY,
                 /* animate */ true,
                 AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
@@ -919,8 +967,8 @@
 
     private void zoomOff() {
         if (DEBUG_DETECTING) Slog.i(LOG_TAG, "zoomOff()");
-
-        mMagnificationController.reset(/* animate */ true);
+        // TODO: multi-display support for magnification gesture handler
+        mMagnificationController.reset(Display.DEFAULT_DISPLAY, /* animate */ true);
     }
 
     private static MotionEvent recycleAndNullify(@Nullable MotionEvent event) {
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index cf9f233..8ffadde 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -462,7 +462,7 @@
             return false;
         }
 
-        endGestureDetection();
+        endGestureDetection(true);
 
         mAms.onGesture(gestureId);
 
@@ -472,7 +472,7 @@
     @Override
     public boolean onGestureCancelled(MotionEvent event, int policyFlags) {
         if (mCurrentState == STATE_GESTURE_DETECTING) {
-            endGestureDetection();
+            endGestureDetection(event.getActionMasked() == MotionEvent.ACTION_UP);
             return true;
         } else if (mCurrentState == STATE_TOUCH_EXPLORING) {
             // If the finger is still moving, pass the event on.
@@ -804,13 +804,19 @@
         }
     }
 
-    private void endGestureDetection() {
+    private void endGestureDetection(boolean interactionEnd) {
         mAms.onTouchInteractionEnd();
 
         // Announce the end of the gesture recognition.
         sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
-        // Announce the end of a the touch interaction.
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+        if (interactionEnd) {
+            // Announce the end of a the touch interaction.
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+        } else {
+            // If gesture detection is end, but user doesn't release the finger, announce the
+            // transition to exploration state.
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
+        }
 
         mExitGestureDetectionModeDelayed.cancel();
         mCurrentState = STATE_TOUCH_EXPLORING;
@@ -889,7 +895,6 @@
         MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
         if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
             final int pointerIdBits = event.getPointerIdBits();
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
             sendMotionEvent(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, policyFlags);
         }
     }
@@ -1148,8 +1153,8 @@
             sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
             // Clearing puts is in touch exploration state with a finger already
             // down, so announce the transition to exploration state.
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
             clear();
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
         }
     }
 
diff --git a/services/appprediction/Android.bp b/services/appprediction/Android.bp
new file mode 100644
index 0000000..a7be587
--- /dev/null
+++ b/services/appprediction/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+    name: "services.appprediction",
+    srcs: ["java/**/*.java"],
+    libs: ["services.core"],
+}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
new file mode 100644
index 0000000..833eaa0
--- /dev/null
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
@@ -0,0 +1,156 @@
+/*
+ * 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.appprediction;
+
+import static android.Manifest.permission.MANAGE_APP_PREDICTIONS;
+import static android.content.Context.APP_PREDICTION_SERVICE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.IPredictionCallback;
+import android.app.prediction.IPredictionManager;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.UserHandle;
+
+import com.android.server.infra.AbstractMasterSystemService;
+import com.android.server.infra.FrameworkResourcesServiceNameResolver;
+
+import java.io.FileDescriptor;
+import java.util.function.Consumer;
+
+/**
+ * A service used to predict app and shortcut usage.
+ *
+ * <p>The data collected by this service can be analyzed and combined with other sources to provide
+ * predictions in different areas of the system such as Launcher and Share sheet.
+ */
+public class AppPredictionManagerService extends
+        AbstractMasterSystemService<AppPredictionManagerService, AppPredictionPerUserService> {
+
+    private static final String TAG = AppPredictionManagerService.class.getSimpleName();
+
+    private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
+
+    public AppPredictionManagerService(Context context) {
+        super(context, new FrameworkResourcesServiceNameResolver(context,
+                com.android.internal.R.string.config_defaultAppPredictionService), null);
+    }
+
+    @Override
+    protected AppPredictionPerUserService newServiceLocked(int resolvedUserId, boolean disabled) {
+        return new AppPredictionPerUserService(this, mLock, resolvedUserId);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(APP_PREDICTION_SERVICE, new PredictionManagerServiceStub());
+    }
+
+    @Override
+    protected void enforceCallingPermissionForManagement() {
+        getContext().enforceCallingPermission(MANAGE_APP_PREDICTIONS, TAG);
+    }
+
+    @Override
+    protected int getMaximumTemporaryServiceDurationMs() {
+        return MAX_TEMP_SERVICE_DURATION_MS;
+    }
+
+    private class PredictionManagerServiceStub extends IPredictionManager.Stub {
+
+        @Override
+        public void createPredictionSession(@NonNull AppPredictionContext context,
+                @NonNull AppPredictionSessionId sessionId) {
+            runForUserLocked((service) ->
+                    service.onCreatePredictionSessionLocked(context, sessionId));
+        }
+
+        @Override
+        public void notifyAppTargetEvent(@NonNull AppPredictionSessionId sessionId,
+                @NonNull AppTargetEvent event) {
+            runForUserLocked((service) -> service.notifyAppTargetEventLocked(sessionId, event));
+        }
+
+        @Override
+        public void notifyLocationShown(@NonNull AppPredictionSessionId sessionId,
+                @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
+            runForUserLocked((service) ->
+                    service.notifyLocationShownLocked(sessionId, launchLocation, targetIds));
+        }
+
+        @Override
+        public void sortAppTargets(@NonNull AppPredictionSessionId sessionId,
+                @NonNull ParceledListSlice targets,
+                IPredictionCallback callback) {
+            runForUserLocked((service) ->
+                    service.sortAppTargetsLocked(sessionId, targets, callback));
+        }
+
+        @Override
+        public void registerPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+                @NonNull IPredictionCallback callback) {
+            runForUserLocked((service) ->
+                    service.registerPredictionUpdatesLocked(sessionId, callback));
+        }
+
+        public void unregisterPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+                @NonNull IPredictionCallback callback) {
+            runForUserLocked((service) ->
+                    service.unregisterPredictionUpdatesLocked(sessionId, callback));
+        }
+
+        @Override
+        public void requestPredictionUpdate(@NonNull AppPredictionSessionId sessionId) {
+            runForUserLocked((service) -> service.requestPredictionUpdateLocked(sessionId));
+        }
+
+        @Override
+        public void onDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {
+            runForUserLocked((service) -> service.onDestroyPredictionSessionLocked(sessionId));
+        }
+
+        public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+                @Nullable FileDescriptor err,
+                @NonNull String[] args, @Nullable ShellCallback callback,
+                @NonNull ResultReceiver resultReceiver) throws RemoteException {
+            new AppPredictionManagerServiceShellCommand(AppPredictionManagerService.this)
+                    .exec(this, in, out, err, args, callback, resultReceiver);
+        }
+
+        private void runForUserLocked(@NonNull Consumer<AppPredictionPerUserService> c) {
+            final int userId = UserHandle.getCallingUserId();
+            // TODO(b/111701043): Determine what permission model we want for this
+            long origId = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    final AppPredictionPerUserService service = getServiceForUserLocked(userId);
+                    c.accept(service);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerServiceShellCommand.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerServiceShellCommand.java
new file mode 100644
index 0000000..ed7cc67
--- /dev/null
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerServiceShellCommand.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.appprediction;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/**
+ * The shell command implementation for the AppPredictionManagerService.
+ */
+public class AppPredictionManagerServiceShellCommand extends ShellCommand {
+
+    private static final String TAG =
+            AppPredictionManagerServiceShellCommand.class.getSimpleName();
+
+    private final AppPredictionManagerService mService;
+
+    public AppPredictionManagerServiceShellCommand(@NonNull AppPredictionManagerService service) {
+        mService = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        final PrintWriter pw = getOutPrintWriter();
+        switch (cmd) {
+            case "set": {
+                final String what = getNextArgRequired();
+                switch (what) {
+                    case "temporary-service": {
+                        final int userId = Integer.parseInt(getNextArgRequired());
+                        String serviceName = getNextArg();
+                        if (serviceName == null) {
+                            mService.resetTemporaryService(userId);
+                            return 0;
+                        }
+                        final int duration = Integer.parseInt(getNextArgRequired());
+                        mService.setTemporaryService(userId, serviceName, duration);
+                        pw.println("AppPredictionService temporarily set to " + serviceName
+                                + " for " + duration + "ms");
+                        break;
+                    }
+                }
+            }
+            break;
+            default:
+                return handleDefaultCommands(cmd);
+        }
+        return 0;
+    }
+
+    @Override
+    public void onHelp() {
+        try (PrintWriter pw = getOutPrintWriter()) {
+            pw.println("AppPredictionManagerService commands:");
+            pw.println("  help");
+            pw.println("    Prints this help text.");
+            pw.println("");
+            pw.println("  set temporary-service USER_ID [COMPONENT_NAME DURATION]");
+            pw.println("    Temporarily (for DURATION ms) changes the service implemtation.");
+            pw.println("    To reset, call with just the USER_ID argument.");
+            pw.println("");
+        }
+    }
+}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
new file mode 100644
index 0000000..24d592c
--- /dev/null
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -0,0 +1,218 @@
+/*
+ * 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.appprediction;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppGlobals;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.IPredictionCallback;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteException;
+import android.service.appprediction.AppPredictionService;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.infra.AbstractPerUserSystemService;
+
+/**
+ * Per-user instance of {@link AppPredictionManagerService}.
+ */
+public class AppPredictionPerUserService extends
+        AbstractPerUserSystemService<AppPredictionPerUserService, AppPredictionManagerService>
+             implements RemoteAppPredictionService.RemoteAppPredictionServiceCallbacks {
+
+    private static final String TAG = AppPredictionPerUserService.class.getSimpleName();
+
+    @Nullable
+    @GuardedBy("mLock")
+    private RemoteAppPredictionService mRemoteService;
+
+    protected AppPredictionPerUserService(AppPredictionManagerService master,
+            Object lock, int userId) {
+        super(master, lock, userId);
+    }
+
+    @Override // from PerUserSystemService
+    protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
+            throws NameNotFoundException {
+
+        ServiceInfo si;
+        try {
+            si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+                    PackageManager.GET_META_DATA, mUserId);
+        } catch (RemoteException e) {
+            throw new NameNotFoundException("Could not get service for " + serviceComponent);
+        }
+        // TODO(b/111701043): must check that either the service is from a system component,
+        // or it matches a service set by shell cmd (so it can be used on CTS tests and when
+        // OEMs are implementing the real service and also verify the proper permissions
+        return si;
+    }
+
+    @GuardedBy("mLock")
+    @Override // from PerUserSystemService
+    protected boolean updateLocked(boolean disabled) {
+        final boolean enabledChanged = super.updateLocked(disabled);
+        if (enabledChanged) {
+            if (!isEnabledLocked()) {
+                // Clear the remote service for the next call
+                mRemoteService = null;
+            }
+        }
+        return enabledChanged;
+    }
+
+    /**
+     * Notifies the service of a new prediction session.
+     */
+    @GuardedBy("mLock")
+    public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context,
+            @NonNull AppPredictionSessionId sessionId) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.onCreatePredictionSession(context, sessionId);
+        }
+    }
+
+    /**
+     * Records an app target event to the service.
+     */
+    @GuardedBy("mLock")
+    public void notifyAppTargetEventLocked(@NonNull AppPredictionSessionId sessionId,
+            @NonNull AppTargetEvent event) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.notifyAppTargetEvent(sessionId, event);
+        }
+    }
+
+    /**
+     * Records when a launch location is shown.
+     */
+    @GuardedBy("mLock")
+    public void notifyLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
+            @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.notifyLocationShown(sessionId, launchLocation, targetIds);
+        }
+    }
+
+    /**
+     * Requests the service to sort a list of apps or shortcuts.
+     */
+    @GuardedBy("mLock")
+    public void sortAppTargetsLocked(@NonNull AppPredictionSessionId sessionId,
+            @NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.sortAppTargets(sessionId, targets, callback);
+        }
+    }
+
+    /**
+     * Registers a callback for continuous updates of predicted apps or shortcuts.
+     */
+    @GuardedBy("mLock")
+    public void registerPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
+            @NonNull IPredictionCallback callback) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.registerPredictionUpdates(sessionId, callback);
+        }
+    }
+
+    /**
+     * Unregisters a callback for continuous updates of predicted apps or shortcuts.
+     */
+    @GuardedBy("mLock")
+    public void unregisterPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
+            @NonNull IPredictionCallback callback) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.unregisterPredictionUpdates(sessionId, callback);
+        }
+    }
+
+    /**
+     * Requests a new set of predicted apps or shortcuts.
+     */
+    @GuardedBy("mLock")
+    public void requestPredictionUpdateLocked(@NonNull AppPredictionSessionId sessionId) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.requestPredictionUpdate(sessionId);
+        }
+    }
+
+    /**
+     * Notifies the service of the end of an existing prediction session.
+     */
+    @GuardedBy("mLock")
+    public void onDestroyPredictionSessionLocked(@NonNull AppPredictionSessionId sessionId) {
+        final RemoteAppPredictionService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.onDestroyPredictionSession(sessionId);
+        }
+    }
+
+    @Override
+    public void onFailureOrTimeout(boolean timedOut) {
+        if (isDebug()) {
+            Slog.d(TAG, "onFailureOrTimeout(): timed out=" + timedOut);
+        }
+
+        // Do nothing, we are just proxying to the prediction service
+    }
+
+    @Override
+    public void onServiceDied(RemoteAppPredictionService service) {
+        if (isDebug()) {
+            Slog.d(TAG, "onServiceDied():");
+        }
+
+        // Do nothing, we are just proxying to the prediction service
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    private RemoteAppPredictionService getRemoteServiceLocked() {
+        if (mRemoteService == null) {
+            final String serviceName = getComponentNameLocked();
+            if (serviceName == null) {
+                if (mMaster.verbose) {
+                    Slog.v(TAG, "getRemoteServiceLocked(): not set");
+                }
+                return null;
+            }
+            ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+
+            mRemoteService = new RemoteAppPredictionService(getContext(),
+                    AppPredictionService.SERVICE_INTERFACE, serviceComponent, mUserId, this,
+                    mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
+        }
+
+        return mRemoteService;
+    }
+}
diff --git a/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
new file mode 100644
index 0000000..45ea86f
--- /dev/null
+++ b/services/appprediction/java/com/android/server/appprediction/RemoteAppPredictionService.java
@@ -0,0 +1,142 @@
+/*
+ * 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.appprediction;
+
+import android.annotation.NonNull;
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionSessionId;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.IPredictionCallback;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.IBinder;
+import android.service.appprediction.IPredictionService;
+import android.text.format.DateUtils;
+
+import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
+
+
+/**
+ * Proxy to the {@link android.service.appprediction.AppPredictionService} implemention in another
+ * process.
+ */
+public class RemoteAppPredictionService extends
+        AbstractMultiplePendingRequestsRemoteService<RemoteAppPredictionService,
+                IPredictionService> {
+
+    private static final String TAG = "RemoteAppPredictionService";
+
+    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
+
+    public RemoteAppPredictionService(Context context, String serviceInterface,
+            ComponentName componentName, int userId,
+            RemoteAppPredictionServiceCallbacks callback, boolean bindInstantServiceAllowed,
+            boolean verbose) {
+        super(context, serviceInterface, componentName, userId, callback, bindInstantServiceAllowed,
+                verbose, /* initialCapacity= */ 1);
+    }
+
+    @Override
+    protected IPredictionService getServiceInterface(IBinder service) {
+        return IPredictionService.Stub.asInterface(service);
+    }
+
+    @Override
+    protected long getTimeoutIdleBindMillis() {
+        return PERMANENT_BOUND_TIMEOUT_MS;
+    }
+
+    @Override
+    protected long getRemoteRequestMillis() {
+        return TIMEOUT_REMOTE_REQUEST_MILLIS;
+    }
+
+    /**
+     * Notifies the service of a new prediction session.
+     */
+    public void onCreatePredictionSession(@NonNull AppPredictionContext context,
+            @NonNull AppPredictionSessionId sessionId) {
+        scheduleAsyncRequest((s) -> s.onCreatePredictionSession(context, sessionId));
+    }
+
+    /**
+     * Records an app target event to the service.
+     */
+    public void notifyAppTargetEvent(@NonNull AppPredictionSessionId sessionId,
+            @NonNull AppTargetEvent event) {
+        scheduleAsyncRequest((s) -> s.notifyAppTargetEvent(sessionId, event));
+    }
+
+    /**
+     * Records when a launch location is shown.
+     */
+    public void notifyLocationShown(@NonNull AppPredictionSessionId sessionId,
+            @NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
+        scheduleAsyncRequest((s) -> s.notifyLocationShown(sessionId, launchLocation, targetIds));
+    }
+
+    /**
+     * Requests the service to sort a list of apps or shortcuts.
+     */
+    public void sortAppTargets(@NonNull AppPredictionSessionId sessionId,
+            @NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
+        scheduleAsyncRequest((s) -> s.sortAppTargets(sessionId, targets, callback));
+    }
+
+
+    /**
+     * Registers a callback for continuous updates of predicted apps or shortcuts.
+     */
+    public void registerPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+            @NonNull IPredictionCallback callback) {
+        scheduleAsyncRequest((s) -> s.registerPredictionUpdates(sessionId, callback));
+    }
+
+    /**
+     * Unregisters a callback for continuous updates of predicted apps or shortcuts.
+     */
+    public void unregisterPredictionUpdates(@NonNull AppPredictionSessionId sessionId,
+            @NonNull IPredictionCallback callback) {
+        scheduleAsyncRequest((s) -> s.unregisterPredictionUpdates(sessionId, callback));
+    }
+
+    /**
+     * Requests a new set of predicted apps or shortcuts.
+     */
+    public void requestPredictionUpdate(@NonNull AppPredictionSessionId sessionId) {
+        scheduleAsyncRequest((s) -> s.requestPredictionUpdate(sessionId));
+    }
+
+    /**
+     * Notifies the service of the end of an existing prediction session.
+     */
+    public void onDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {
+        scheduleAsyncRequest((s) -> s.onDestroyPredictionSession(sessionId));
+    }
+
+    /**
+     * Failure callback
+     */
+    public interface RemoteAppPredictionServiceCallbacks
+            extends VultureCallback<RemoteAppPredictionService> {
+
+        /**
+         * Notifies a the failure or timeout of a remote call.
+         */
+        void onFailureOrTimeout(boolean timedOut);
+    }
+}
diff --git a/services/art-profile b/services/art-profile
index af9d7a9..7e4884b 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -6970,6 +6970,7 @@
 PLcom/android/server/am/ActivityManagerService$LocalService;->getMemoryStateForProcesses()Ljava/util/List;
 PLcom/android/server/am/ActivityManagerService$LocalService;->getTopVisibleActivities()Ljava/util/List;
 PLcom/android/server/am/ActivityManagerService$LocalService;->getUidProcessState(I)I
+PLcom/android/server/am/ActivityManagerService$LocalService;->isAppForeground(I)Z
 PLcom/android/server/am/ActivityManagerService$LocalService;->isCallerRecents(I)Z
 PLcom/android/server/am/ActivityManagerService$LocalService;->isRuntimeRestarted()Z
 PLcom/android/server/am/ActivityManagerService$LocalService;->isSystemReady()Z
@@ -7125,7 +7126,6 @@
 PLcom/android/server/am/ActivityManagerService;->installEncryptionUnawareProviders(I)V
 PLcom/android/server/am/ActivityManagerService;->installSystemProviders()V
 PLcom/android/server/am/ActivityManagerService;->isAllowedWhileBooting(Landroid/content/pm/ApplicationInfo;)Z
-PLcom/android/server/am/ActivityManagerService;->isAppForeground(I)Z
 PLcom/android/server/am/ActivityManagerService;->isAssistDataAllowedOnCurrentActivity()Z
 PLcom/android/server/am/ActivityManagerService;->isGetTasksAllowed(Ljava/lang/String;II)Z
 PLcom/android/server/am/ActivityManagerService;->isInLockTaskMode()Z
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 1a6bee9..2e45fa7 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -18,13 +18,13 @@
 
 import static android.Manifest.permission.MANAGE_AUTO_FILL;
 import static android.content.Context.AUTOFILL_MANAGER_SERVICE;
-import static android.util.DebugUtils.flagsToString;
+import static android.view.autofill.AutofillManager.MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS;
+import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
 
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sFullScreenMode;
 import static com.android.server.autofill.Helper.sVerbose;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -60,6 +60,7 @@
 import android.util.SparseArray;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillManager.SmartSuggestionMode;
 import android.view.autofill.AutofillManagerInternal;
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAutoFillManager;
@@ -70,6 +71,7 @@
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.SyncResultReceiver;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.autofill.ui.AutoFillUI;
@@ -78,8 +80,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -100,28 +100,6 @@
 
     private static final Object sLock = AutofillManagerService.class;
 
-    private static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
-
-    /**
-     * IME supports Smart Suggestions.
-     */
-    // NOTE: must be public because of flagsToString()
-    public static final int FLAG_SMART_SUGGESTION_IME = 0x1;
-
-    /**
-     * System supports Smarts Suggestions (as a popup-window similar to standard Autofill).
-     */
-    // NOTE: must be public because of flagsToString()
-    public static final int FLAG_SMART_SUGGESTION_SYSTEM = 0x2;
-
-    /** @hide */
-    @IntDef(flag = true, prefix = { "FLAG_SMART_SUGGESTION_" }, value = {
-            FLAG_SMART_SUGGESTION_IME,
-            FLAG_SMART_SUGGESTION_SYSTEM
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    @interface SmartSuggestionMode {}
-
     static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
 
     private static final char COMPAT_PACKAGE_DELIMITER = ':';
@@ -252,9 +230,8 @@
     @Override // from AbstractMasterSystemService
     protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
             boolean disabled) {
-        return new AutofillManagerServiceImpl(this, mLock, mRequestsHistory,
-                mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi, mAutofillCompatState,
-                disabled);
+        return new AutofillManagerServiceImpl(this, mLock, mUiLatencyHistory,
+                mWtfHistory, resolvedUserId, mUi, mAutofillCompatState, disabled);
     }
 
     @Override // AbstractMasterSystemService
@@ -291,6 +268,13 @@
         return mSupportedSmartSuggestionModes;
     }
 
+    /**
+     * Logs a request so it's dumped later...
+     */
+    void logRequestLocked(@NonNull String historyItem) {
+        mRequestsHistory.log(historyItem);
+    }
+
     // Called by AutofillManagerServiceImpl, doesn't need to check permission
     boolean isInstantServiceAllowed() {
         return mAllowInstantService;
@@ -478,7 +462,7 @@
                 Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS, 0);
         if (sDebug) {
             Slog.d(TAG, "setSmartSuggestionEmulationFromSettings(): "
-                    + smartSuggestionFlagsToString(flags));
+                    + getSmartSuggestionModeToString(flags));
         }
 
         synchronized (mLock) {
@@ -606,15 +590,15 @@
     }
 
     private void send(@NonNull IResultReceiver receiver, @Nullable String value) {
-        send(receiver, AutofillManager.SyncResultReceiver.bundleFor(value));
+        send(receiver, SyncResultReceiver.bundleFor(value));
     }
 
     private void send(@NonNull IResultReceiver receiver, @Nullable String[] value) {
-        send(receiver, AutofillManager.SyncResultReceiver.bundleFor(value));
+        send(receiver, SyncResultReceiver.bundleFor(value));
     }
 
     private void send(@NonNull IResultReceiver receiver, @Nullable Parcelable value) {
-        send(receiver, AutofillManager.SyncResultReceiver.bundleFor(value));
+        send(receiver, SyncResultReceiver.bundleFor(value));
     }
 
     private void send(@NonNull IResultReceiver receiver, boolean value) {
@@ -692,15 +676,16 @@
         }
     }
 
-    static String smartSuggestionFlagsToString(int flags) {
-        return flagsToString(AutofillManagerService.class, "FLAG_SMART_SUGGESTION_", flags);
-    }
-
     private final class LocalService extends AutofillManagerInternal {
         @Override
         public void onBackKeyPressed() {
             if (sDebug) Slog.d(TAG, "onBackKeyPressed()");
             mUi.hideAll(null);
+            synchronized (mLock) {
+                final AutofillManagerServiceImpl service =
+                        getServiceForUserLocked(UserHandle.getCallingUserId());
+                service.onBackKeyPressed();
+            }
         }
 
         @Override
@@ -1240,7 +1225,7 @@
                     pw.println(getWhitelistedCompatModePackagesFromSettings());
                     if (mSupportedSmartSuggestionModes != 0) {
                         pw.print("Smart Suggestion modes: ");
-                        pw.println(smartSuggestionFlagsToString(mSupportedSmartSuggestionModes));
+                        pw.println(getSmartSuggestionModeToString(mSupportedSmartSuggestionModes));
                     }
                     if (showHistory) {
                         pw.println(); pw.println("Requests history:"); pw.println();
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 4b7efe1..8886ee2 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -63,6 +63,7 @@
 import android.util.TimeUtils;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillManager.SmartSuggestionMode;
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAutoFillManagerClient;
 
@@ -72,7 +73,6 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.LocalServices;
 import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
-import com.android.server.autofill.AutofillManagerService.SmartSuggestionMode;
 import com.android.server.autofill.RemoteAugmentedAutofillService.RemoteAugmentedAutofillServiceCallbacks;
 import com.android.server.autofill.ui.AutoFillUI;
 import com.android.server.infra.AbstractPerUserSystemService;
@@ -108,7 +108,6 @@
 
     private static final Random sRandom = new Random();
 
-    private final LocalLog mRequestsHistory;
     private final LocalLog mUiLatencyHistory;
     private final LocalLog mWtfHistory;
     private final FieldClassificationStrategy mFieldClassificationStrategy;
@@ -166,12 +165,12 @@
     @Nullable
     private RemoteAugmentedAutofillService mRemoteAugmentedAutofillService;
 
-    AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog requestsHistory,
+    AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
             LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
-            AutofillCompatState autofillCompatState, boolean disabled) {
+            AutofillCompatState autofillCompatState,
+            boolean disabled) {
         super(master, lock, userId);
 
-        mRequestsHistory = requestsHistory;
         mUiLatencyHistory = uiLatencyHistory;
         mWtfHistory = wtfHistory;
         mUi = ui;
@@ -187,6 +186,15 @@
     }
 
     @GuardedBy("mLock")
+    void onBackKeyPressed() {
+        final RemoteAugmentedAutofillService remoteService =
+                getRemoteAugmentedAutofillServiceLocked();
+        if (remoteService != null) {
+            remoteService.onDestroyAutofillWindowsRequest();
+        }
+    }
+
+    @GuardedBy("mLock")
     @Override // from PerUserSystemService
     protected boolean updateLocked(boolean disabled) {
         destroySessionsLocked();
@@ -301,7 +309,7 @@
                 + " s=" + mInfo.getServiceInfo().packageName
                 + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds
                 + " hc=" + hasCallback + " f=" + flags;
-        mRequestsHistory.log(historyItem);
+        mMaster.logRequestLocked(historyItem);
 
         newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags);
 
@@ -847,7 +855,6 @@
 
     @GuardedBy("mLock")
     @SmartSuggestionMode int getSupportedSmartSuggestionModesLocked() {
-        // TODO(b/111330312): once we support IME, we need to set it per-user (OR'ed with master)
         return mMaster.getSupportedSmartSuggestionModesLocked();
     }
 
@@ -870,8 +877,11 @@
         }
         pw.print(prefix); pw.print("Default component: "); pw.println(getContext()
                 .getString(R.string.config_defaultAutofillService));
-        pw.print(prefix); pw.print("mAugmentedAutofillNamer: ");
-        mAugmentedAutofillResolver.dumpShort(pw); pw.println();
+
+        pw.print(prefix); pw.println("mAugmentedAutofillNamer: ");
+        pw.print(prefix2); mAugmentedAutofillResolver.dumpShort(pw); pw.println();
+        pw.print(prefix2); mAugmentedAutofillResolver.dumpShort(pw, mUserId); pw.println();
+
         if (mRemoteAugmentedAutofillService != null) {
             pw.print(prefix); pw.println("RemoteAugmentedAutofillService: ");
             mRemoteAugmentedAutofillService.dump(prefix2, pw);
@@ -1038,7 +1048,7 @@
                     componentName, mUserId, new RemoteAugmentedAutofillServiceCallbacks() {
                         @Override
                         public void onServiceDied(@NonNull RemoteAugmentedAutofillService service) {
-                            // TODO(b/111330312): properly implement
+                            // TODO(b/123100811): properly implement
                             Slog.w(TAG, "remote augmented autofill service died");
                         }
                     }, mMaster.isInstantServiceAllowed(), mMaster.verbose);
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 239a386..9b863a9 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -109,11 +109,11 @@
     /**
      * Called by {@link Session} when it's time to destroy all augmented autofill requests.
      */
-    public void onDestroyAutofillWindowsRequest(int sessionId) {
-        scheduleAsyncRequest((s) -> s.onDestroyFillWindowRequest(sessionId));
+    public void onDestroyAutofillWindowsRequest() {
+        scheduleAsyncRequest((s) -> s.onDestroyAllFillWindowsRequest());
     }
 
-    // TODO(b/111330312): inline into PendingAutofillRequest if it doesn't have any other subclass
+    // TODO(b/123100811): inline into PendingAutofillRequest if it doesn't have any other subclass
     private abstract static class MyPendingRequest
             extends PendingRequest<RemoteAugmentedAutofillService, IAugmentedAutofillService> {
         protected final int mSessionId;
@@ -168,7 +168,7 @@
                 }
             };
 
-            // TODO(b/111330312): set cancellation signal, timeout (from both mClient and service),
+            // TODO(b/122728762): set cancellation signal, timeout (from both mClient and service),
             // cache IAugmentedAutofillManagerClient reference, etc...
             try {
                 mClient.getAugmentedAutofillClient(receiver);
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 34fe5d9..e8a52b4 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -139,9 +139,6 @@
         if (mPendingRequest == pendingRequest) {
             mPendingRequest = null;
         }
-        if (mPendingRequest == null) {
-            scheduleUnbind();
-        }
         return true;
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 0348f2b..194332a 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -23,11 +23,10 @@
 import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED;
 import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED;
 import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
+import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
+import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
-import static com.android.server.autofill.AutofillManagerService.FLAG_SMART_SUGGESTION_IME;
-import static com.android.server.autofill.AutofillManagerService.FLAG_SMART_SUGGESTION_SYSTEM;
-import static com.android.server.autofill.AutofillManagerService.smartSuggestionFlagsToString;
 import static com.android.server.autofill.Helper.getNumericValue;
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sVerbose;
@@ -88,6 +87,7 @@
 import android.view.KeyEvent;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillManager.SmartSuggestionMode;
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAutoFillManagerClient;
 import android.view.autofill.IAutofillWindowPresenter;
@@ -97,7 +97,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.ArrayUtils;
-import com.android.server.autofill.AutofillManagerService.SmartSuggestionMode;
 import com.android.server.autofill.ui.AutoFillUI;
 import com.android.server.autofill.ui.PendingUi;
 
@@ -250,7 +249,7 @@
     /**
      * Destroys the augmented Autofill UI.
      */
-    // TODO(b/111330312): this runnable is called when the Autofill session is destroyed, the
+    // TODO(b/123099468): this runnable is called when the Autofill session is destroyed, the
     // main reason being the cases where user tap HOME.
     // Right now it's completely destroying the UI, but we need to decide whether / how to
     // properly recover it later (for example, if the user switches back to the activity,
@@ -261,6 +260,12 @@
     private Runnable mAugmentedAutofillDestroyer;
 
     /**
+     * List of {@link MetricsEvent#AUTOFILL_AUGMENTED_REQUEST} metrics.
+     */
+    @GuardedBy("mLock")
+    private ArrayList<LogMaker> mAugmentedRequestsLogs;
+
+    /**
      * Receiver of assist data from the app's {@link Activity}.
      */
     private final IAssistDataReceiver mAssistReceiver = new IAssistDataReceiver.Stub() {
@@ -2541,8 +2546,8 @@
         }
         mService.resetLastResponse();
 
-        // The default autofill service cannot fullfill the request, let's check if the intelligence
-        // service can.
+        // The default autofill service cannot fullfill the request, let's check if the augmented
+        // autofill service can.
         mAugmentedAutofillDestroyer = triggerAugmentedAutofillLocked();
         if (mAugmentedAutofillDestroyer == null) {
             if (sVerbose) {
@@ -2553,7 +2558,7 @@
             notifyUnavailableToClient(AutofillManager.STATE_FINISHED);
             removeSelf();
         } else {
-            // TODO(b/111330312, b/119638958): must set internal state so when user focus other
+            // TODO(b/123099468, b/119638958): must set internal state so when user focus other
             // fields it does not generate a new call to the standard autofill service (right now
             // it does). Must also add CTS tests to exercise this scenario.
             if (sVerbose) {
@@ -2568,7 +2573,7 @@
      *
      * @return callback to destroy the autofill UI, or {@code null} if not supported.
      */
-    // TODO(b/111330312): might need to call it in other places, like when the service returns a
+    // TODO(b/123099468): might need to call it in other places, like when the service returns a
     // non-null response but without datasets (for example, just SaveInfo)
     @GuardedBy("mLock")
     private Runnable triggerAugmentedAutofillLocked() {
@@ -2581,18 +2586,19 @@
 
         final RemoteAugmentedAutofillService remoteService = mService
                 .getRemoteAugmentedAutofillServiceLocked();
-        if (remoteService == null) return null;
+        if (remoteService == null) {
+            if (sVerbose) Slog.v(TAG, "triggerAugmentedAutofillLocked(): no service for user");
+            return null;
+        }
 
         // Define which mode will be used
         final int mode;
-        if ((supportedModes & FLAG_SMART_SUGGESTION_IME) != 0) {
-            // TODO(b/111330312): support it :-)
-            Slog.w(TAG, "Smart Suggestions on IME not supported yet");
-            return null;
-        } else if ((supportedModes & FLAG_SMART_SUGGESTION_SYSTEM) != 0) {
+        if ((supportedModes & FLAG_SMART_SUGGESTION_SYSTEM) != 0) {
             mode = FLAG_SMART_SUGGESTION_SYSTEM;
+        } else if ((supportedModes & AutofillManager.FLAG_SMART_SUGGESTION_LEGACY) != 0) {
+            mode = AutofillManager.FLAG_SMART_SUGGESTION_LEGACY;
         } else {
-            Slog.w(TAG, "Unsupported Smart Suggestion Mode: " + supportedModes);
+            Slog.w(TAG, "Unsupported Smart Suggestion mode: " + supportedModes);
             return null;
         }
 
@@ -2602,21 +2608,37 @@
         }
 
         if (sVerbose) {
-            Slog.v(TAG, "calling IntelligenseService on view " + mCurrentViewId
-                    + " using suggestion mode " + smartSuggestionFlagsToString(mode)
+            Slog.v(TAG, "calling Augmented Autofill Service ("
+                    + remoteService.getComponentName().toShortString() + ") on view "
+                    + mCurrentViewId + " using suggestion mode "
+                    + getSmartSuggestionModeToString(mode)
                     + " when server returned null for session " + this.id);
         }
 
+        final String historyItem =
+                "aug:id=" + id + " u=" + uid + " m=" + mode
+                + " a=" + ComponentName.flattenToShortString(mComponentName)
+                + " f=" + mCurrentViewId
+                + " s=" + remoteService.getComponentName();
+        mService.getMaster().logRequestLocked(historyItem);
+
         final AutofillValue currentValue = mViewStates.get(mCurrentViewId).getCurrentValue();
 
         // TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize
-        // furgher AFM -> AFMS calls.
-        // TODO(b/119638958): add CTS tests
+        // further AFM -> AFMS calls.
+
+        if (mAugmentedRequestsLogs == null) {
+            mAugmentedRequestsLogs = new ArrayList<>();
+        }
+        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_AUGMENTED_REQUEST,
+                remoteService.getComponentName().getPackageName());
+        mAugmentedRequestsLogs.add(log);
+
         remoteService.onRequestAutofillLocked(id, mClient, taskId, mComponentName, mCurrentViewId,
                 currentValue);
 
         if (mAugmentedAutofillDestroyer == null) {
-            mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest(id);
+            mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest();
         }
         return mAugmentedAutofillDestroyer;
     }
@@ -2902,6 +2924,11 @@
         if (mAugmentedAutofillDestroyer != null) {
             pw.print(prefix); pw.println("has mAugmentedAutofillDestroyer");
         }
+        if (mAugmentedRequestsLogs != null) {
+            pw.print(prefix); pw.print("number augmented requests: ");
+            pw.println(mAugmentedRequestsLogs.size());
+        }
+
         mRemoteFillService.dump(prefix, pw);
     }
 
@@ -3043,8 +3070,26 @@
                 mMetricsLogger.write(log);
             }
         }
-        mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_FINISHED)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_REQUESTS, totalRequests));
+
+        final int totalAugmentedRequests = mAugmentedRequestsLogs == null ? 0
+                : mAugmentedRequestsLogs.size();
+        if (totalAugmentedRequests > 0) {
+            if (sVerbose) {
+                Slog.v(TAG, "destroyLocked(): logging " + totalRequests + " augmented requests");
+            }
+            for (int i = 0; i < totalAugmentedRequests; i++) {
+                final LogMaker log = mAugmentedRequestsLogs.get(i);
+                mMetricsLogger.write(log);
+            }
+        }
+
+        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_SESSION_FINISHED)
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_REQUESTS, totalRequests);
+        if (totalAugmentedRequests > 0) {
+            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_AUGMENTED_REQUESTS,
+                    totalAugmentedRequests);
+        }
+        mMetricsLogger.write(log);
 
         return mRemoteFillService;
     }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 8b07db7..14322ec 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -39,7 +39,6 @@
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.util.Slog;
@@ -125,9 +124,14 @@
      */
     @VisibleForTesting
     protected void startServiceForUser(int userId) {
+        if (mServiceUsers.get(userId) != null) {
+            Slog.i(TAG, "userId " + userId + " already started, so not starting again");
+            return;
+        }
+
         UserBackupManagerService userBackupManagerService =
                 UserBackupManagerService.createAndInitializeService(
-                        userId, mContext, mTrampoline, mBackupThread, mTransportWhitelist);
+                        userId, mContext, mTrampoline, mTransportWhitelist);
         startServiceForUser(userId, userBackupManagerService);
     }
 
@@ -139,23 +143,29 @@
         mServiceUsers.put(userId, userBackupManagerService);
 
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
-        try {
-            // TODO(b/121198604): Make enable file per-user and clean up indirection.
-            mTrampoline.setBackupEnabledForUser(
-                    userId, UserBackupManagerFilePersistedSettings.readBackupEnableState(userId));
-        } catch (RemoteException e) {
-            // Can't happen, it's a local object.
-        }
+        userBackupManagerService.initializeBackupEnableState();
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
 
     /** Stops the backup service for user {@code userId} when the user is stopped. */
     @VisibleForTesting
     protected void stopServiceForUser(int userId) {
-        mServiceUsers.remove(userId);
+        UserBackupManagerService userBackupManagerService = mServiceUsers.removeReturnOld(userId);
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.tearDownService();
+
+            KeyValueBackupJob.cancel(userId, mContext);
+            FullBackupJob.cancel(userId, mContext);
+        }
     }
 
-    SparseArray<UserBackupManagerService> getServiceUsers() {
+    /**
+     *  Returns a lst of users currently unlocked that have a
+     *  {@link UserBackupManagerService} registered.
+     */
+    @VisibleForTesting
+    public SparseArray<UserBackupManagerService> getServiceUsers() {
         return mServiceUsers;
     }
 
@@ -580,9 +590,9 @@
      * @return Whether ongoing work will continue. The return value here will be passed along as the
      *     return value to the callback {@link JobService#onStartJob(JobParameters)}.
      */
-    public boolean beginFullBackup(FullBackupJob scheduledJob) {
+    public boolean beginFullBackup(@UserIdInt int userId, FullBackupJob scheduledJob) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(UserHandle.USER_SYSTEM, "beginFullBackup()");
+                getServiceForUserIfCallerHasPermission(userId, "beginFullBackup()");
 
         return userBackupManagerService != null
                 && userBackupManagerService.beginFullBackup(scheduledJob);
@@ -592,9 +602,9 @@
      * Used by the {@link JobScheduler} to end the current full backup task when conditions are no
      * longer met for running the full backup job.
      */
-    public void endFullBackup() {
+    public void endFullBackup(@UserIdInt int userId) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUserIfCallerHasPermission(UserHandle.USER_SYSTEM, "endFullBackup()");
+                getServiceForUserIfCallerHasPermission(userId, "endFullBackup()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.endFullBackup();
diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java
index 82638b4..33d21cb0 100644
--- a/services/backup/java/com/android/server/backup/FullBackupJob.java
+++ b/services/backup/java/com/android/server/backup/FullBackupJob.java
@@ -22,21 +22,30 @@
 import android.app.job.JobService;
 import android.content.ComponentName;
 import android.content.Context;
+import android.os.Bundle;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 public class FullBackupJob extends JobService {
-    private static final String TAG = "FullBackupJob";
-    private static final boolean DEBUG = true;
+    private static final String USER_ID_EXTRA_KEY = "userId";
+
+    @VisibleForTesting
+    static final int MIN_JOB_ID = 52418896;
+    @VisibleForTesting
+    static final int MAX_JOB_ID = 52419896;
 
     private static ComponentName sIdleService =
             new ComponentName("android", FullBackupJob.class.getName());
 
-    private static final int JOB_ID = 0x5038;
+    @GuardedBy("mParamsForUser")
+    private final SparseArray<JobParameters> mParamsForUser = new SparseArray<>();
 
-    JobParameters mParams;
-
-    public static void schedule(Context ctx, long minDelay, BackupManagerConstants constants) {
+    public static void schedule(int userId, Context ctx, long minDelay,
+            BackupManagerConstants constants) {
         JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-        JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sIdleService);
+        JobInfo.Builder builder = new JobInfo.Builder(getJobIdForUserId(userId), sIdleService);
         synchronized (constants) {
             builder.setRequiresDeviceIdle(true)
                     .setRequiredNetworkType(constants.getFullBackupRequiredNetworkType())
@@ -45,14 +54,28 @@
         if (minDelay > 0) {
             builder.setMinimumLatency(minDelay);
         }
+
+        Bundle extraInfo = new Bundle();
+        extraInfo.putInt(USER_ID_EXTRA_KEY, userId);
+        builder.setTransientExtras(extraInfo);
+
         js.schedule(builder.build());
     }
 
+    public static void cancel(int userId, Context ctx) {
+        JobScheduler js = (JobScheduler) ctx.getSystemService(
+                Context.JOB_SCHEDULER_SERVICE);
+        js.cancel(getJobIdForUserId(userId));
+    }
+
     // callback from the Backup Manager Service: it's finished its work for this pass
-    public void finishBackupPass() {
-        if (mParams != null) {
-            jobFinished(mParams, false);
-            mParams = null;
+    public void finishBackupPass(int userId) {
+        synchronized (mParamsForUser) {
+            JobParameters jobParameters = mParamsForUser.get(userId);
+            if (jobParameters != null) {
+                jobFinished(jobParameters, false);
+                mParamsForUser.remove(userId);
+            }
         }
     }
 
@@ -60,19 +83,33 @@
 
     @Override
     public boolean onStartJob(JobParameters params) {
-        mParams = params;
+        int userId = params.getTransientExtras().getInt(USER_ID_EXTRA_KEY);
+
+        synchronized (mParamsForUser) {
+            mParamsForUser.put(userId, params);
+        }
+
         Trampoline service = BackupManagerService.getInstance();
-        return service.beginFullBackup(this);
+        return service.beginFullBackup(userId, this);
     }
 
     @Override
     public boolean onStopJob(JobParameters params) {
-        if (mParams != null) {
-            mParams = null;
-            Trampoline service = BackupManagerService.getInstance();
-            service.endFullBackup();
+        int userId = params.getTransientExtras().getInt(USER_ID_EXTRA_KEY);
+
+        synchronized (mParamsForUser) {
+            if (mParamsForUser.removeReturnOld(userId) == null) {
+                return false;
+            }
         }
+
+        Trampoline service = BackupManagerService.getInstance();
+        service.endFullBackup(userId);
+
         return false;
     }
 
+    private static int getJobIdForUserId(int userId) {
+        return JobIdManager.getJobIdForUserId(MIN_JOB_ID, MAX_JOB_ID, userId);
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/JobIdManager.java b/services/backup/java/com/android/server/backup/JobIdManager.java
new file mode 100644
index 0000000..2e834dbf
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/JobIdManager.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup;
+
+/**
+ * Allocates job IDs for {@link FullBackupJob} and {@link KeyValueBackupJob}
+ */
+public class JobIdManager {
+    public static int getJobIdForUserId(int minJobId, int maxJobId, int userId) {
+        if (minJobId + userId > maxJobId) {
+            throw new RuntimeException("No job IDs available in the given range");
+        }
+
+        return minJobId + userId;
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java
index bed520e..3184bd8 100644
--- a/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/KeyValueAdbRestoreEngine.java
@@ -13,8 +13,6 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
-import com.android.server.backup.restore.PerformAdbRestoreTask;
-
 import libcore.io.IoUtils;
 
 import java.io.File;
@@ -42,11 +40,10 @@
     private final UserBackupManagerService mBackupManagerService;
     private final File mDataDir;
 
-    FileMetadata mInfo;
-    PerformAdbRestoreTask mRestoreTask;
-    ParcelFileDescriptor mInFD;
-    IBackupAgent mAgent;
-    int mToken;
+    private final FileMetadata mInfo;
+    private final ParcelFileDescriptor mInFD;
+    private final IBackupAgent mAgent;
+    private final int mToken;
 
     public KeyValueAdbRestoreEngine(UserBackupManagerService backupManagerService,
             File dataDir, FileMetadata info, ParcelFileDescriptor inFD, IBackupAgent agent,
diff --git a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
index f2e7435..d43859e 100644
--- a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
+++ b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
@@ -25,8 +25,14 @@
 import android.app.job.JobService;
 import android.content.ComponentName;
 import android.content.Context;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.util.Slog;
+import android.util.SparseBooleanArray;
+import android.util.SparseLongArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.Random;
 
@@ -38,7 +44,8 @@
     private static final String TAG = "KeyValueBackupJob";
     private static ComponentName sKeyValueJobService =
             new ComponentName("android", KeyValueBackupJob.class.getName());
-    private static final int JOB_ID = 0x5039;
+
+    private static final String USER_ID_EXTRA_KEY = "userId";
 
     // Once someone asks for a backup, this is how long we hold off until we find
     // an on-charging opportunity.  If we hit this max latency we will run the operation
@@ -46,16 +53,22 @@
     // BackupManager.backupNow().
     private static final long MAX_DEFERRAL = AlarmManager.INTERVAL_DAY;
 
-    private static boolean sScheduled = false;
-    private static long sNextScheduled = 0;
+    @GuardedBy("KeyValueBackupJob.class")
+    private static final SparseBooleanArray sScheduledForUserId = new SparseBooleanArray();
+    @GuardedBy("KeyValueBackupJob.class")
+    private static final SparseLongArray sNextScheduledForUserId = new SparseLongArray();
 
-    public static void schedule(Context ctx, BackupManagerConstants constants) {
-        schedule(ctx, 0, constants);
+    private static final int MIN_JOB_ID = 52417896;
+    private static final int MAX_JOB_ID = 52418896;
+
+    public static void schedule(int userId, Context ctx, BackupManagerConstants constants) {
+        schedule(userId, ctx, 0, constants);
     }
 
-    public static void schedule(Context ctx, long delay, BackupManagerConstants constants) {
+    public static void schedule(int userId, Context ctx, long delay,
+            BackupManagerConstants constants) {
         synchronized (KeyValueBackupJob.class) {
-            if (sScheduled) {
+            if (sScheduledForUserId.get(userId)) {
                 return;
             }
 
@@ -76,51 +89,61 @@
             if (DEBUG_SCHEDULING) {
                 Slog.v(TAG, "Scheduling k/v pass in " + (delay / 1000 / 60) + " minutes");
             }
-            JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sKeyValueJobService)
+
+            JobInfo.Builder builder = new JobInfo.Builder(getJobIdForUserId(userId),
+                    sKeyValueJobService)
                     .setMinimumLatency(delay)
                     .setRequiredNetworkType(networkType)
                     .setRequiresCharging(needsCharging)
                     .setOverrideDeadline(MAX_DEFERRAL);
+
+            Bundle extraInfo = new Bundle();
+            extraInfo.putInt(USER_ID_EXTRA_KEY, userId);
+            builder.setTransientExtras(extraInfo);
+
             JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE);
             js.schedule(builder.build());
 
-            sNextScheduled = System.currentTimeMillis() + delay;
-            sScheduled = true;
+            sScheduledForUserId.put(userId, true);
+            sNextScheduledForUserId.put(userId, System.currentTimeMillis() + delay);
         }
     }
 
-    public static void cancel(Context ctx) {
+    public static void cancel(int userId, Context ctx) {
         synchronized (KeyValueBackupJob.class) {
-            JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-            js.cancel(JOB_ID);
-            sNextScheduled = 0;
-            sScheduled = false;
+            JobScheduler js = (JobScheduler) ctx.getSystemService(
+                    Context.JOB_SCHEDULER_SERVICE);
+            js.cancel(getJobIdForUserId(userId));
+
+            clearScheduledForUserId(userId);
         }
     }
 
-    public static long nextScheduled() {
+    public static long nextScheduled(int userId) {
         synchronized (KeyValueBackupJob.class) {
-            return sNextScheduled;
+            return sNextScheduledForUserId.get(userId);
         }
     }
 
-    public static boolean isScheduled() {
+    @VisibleForTesting
+    public static boolean isScheduled(int userId) {
         synchronized (KeyValueBackupJob.class) {
-            return sScheduled;
+            return sScheduledForUserId.get(userId);
         }
     }
 
     @Override
     public boolean onStartJob(JobParameters params) {
+        int userId = params.getTransientExtras().getInt(USER_ID_EXTRA_KEY);
+
         synchronized (KeyValueBackupJob.class) {
-            sNextScheduled = 0;
-            sScheduled = false;
+            clearScheduledForUserId(userId);
         }
 
         // Time to run a key/value backup!
         Trampoline service = BackupManagerService.getInstance();
         try {
-            service.backupNow();
+            service.backupNowForUser(userId);
         } catch (RemoteException e) {}
 
         // This was just a trigger; ongoing wakelock management is done by the
@@ -134,4 +157,13 @@
         return false;
     }
 
+    @GuardedBy("KeyValueBackupJob.class")
+    private static void clearScheduledForUserId(int userId) {
+        sScheduledForUserId.delete(userId);
+        sNextScheduledForUserId.delete(userId);
+    }
+
+    private static int getJobIdForUserId(int userId) {
+        return JobIdManager.getJobIdForUserId(MIN_JOB_ID, MAX_JOB_ID, userId);
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index e4ce62d..2241569 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -23,9 +23,9 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.Signature;
 import android.content.pm.SigningInfo;
 import android.os.Build;
@@ -49,9 +49,8 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
-
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * We back up the signatures of each package so that during a system restore,
@@ -95,6 +94,7 @@
     // is coming from pre-Android P device.
     private static final int UNDEFINED_ANCESTRAL_RECORD_VERSION = -1;
 
+    private int mUserId;
     private List<PackageInfo> mAllPackages;
     private PackageManager mPackageManager;
     // version & signature info of each app in a restore set
@@ -129,17 +129,18 @@
 
     // We're constructed with the set of applications that are participating
     // in backup.  This set changes as apps are installed & removed.
-    public PackageManagerBackupAgent(PackageManager packageMgr, List<PackageInfo> packages) {
-        init(packageMgr, packages);
+    public PackageManagerBackupAgent(
+            PackageManager packageMgr, List<PackageInfo> packages, int userId) {
+        init(packageMgr, packages, userId);
     }
 
-    public PackageManagerBackupAgent(PackageManager packageMgr) {
-        init(packageMgr, null);
+    public PackageManagerBackupAgent(PackageManager packageMgr, int userId) {
+        init(packageMgr, null, userId);
 
         evaluateStorablePackages();
     }
 
-    private void init(PackageManager packageMgr, List<PackageInfo> packages) {
+    private void init(PackageManager packageMgr, List<PackageInfo> packages, int userId) {
         mPackageManager = packageMgr;
         mAllPackages = packages;
         mRestoredSignatures = null;
@@ -147,21 +148,23 @@
 
         mStoredSdkVersion = Build.VERSION.SDK_INT;
         mStoredIncrementalVersion = Build.VERSION.INCREMENTAL;
+        mUserId = userId;
     }
 
     // We will need to refresh our understanding of what is eligible for
     // backup periodically; this entry point serves that purpose.
     public void evaluateStorablePackages() {
-        mAllPackages = getStorableApplications(mPackageManager);
+        mAllPackages = getStorableApplications(mPackageManager, mUserId);
     }
 
-    public static List<PackageInfo> getStorableApplications(PackageManager pm) {
-        List<PackageInfo> pkgs;
-        pkgs = pm.getInstalledPackages(PackageManager.GET_SIGNING_CERTIFICATES);
+    /** Gets all packages installed on user {@code userId} eligible for backup. */
+    public static List<PackageInfo> getStorableApplications(PackageManager pm, int userId) {
+        List<PackageInfo> pkgs =
+                pm.getInstalledPackagesAsUser(PackageManager.GET_SIGNING_CERTIFICATES, userId);
         int N = pkgs.size();
         for (int a = N-1; a >= 0; a--) {
             PackageInfo pkg = pkgs.get(a);
-            if (!AppBackupUtils.appIsEligibleForBackup(pkg.applicationInfo, pm)) {
+            if (!AppBackupUtils.appIsEligibleForBackup(pkg.applicationInfo, userId)) {
                 pkgs.remove(a);
             }
         }
@@ -237,8 +240,8 @@
         ComponentName home = getPreferredHomeComponent();
         if (home != null) {
             try {
-                homeInfo = mPackageManager.getPackageInfo(home.getPackageName(),
-                        PackageManager.GET_SIGNING_CERTIFICATES);
+                homeInfo = mPackageManager.getPackageInfoAsUser(home.getPackageName(),
+                        PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
                 homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName());
                 homeVersion = homeInfo.getLongVersionCode();
                 SigningInfo signingInfo = homeInfo.signingInfo;
@@ -315,8 +318,8 @@
                 } else {
                     PackageInfo info = null;
                     try {
-                        info = mPackageManager.getPackageInfo(packName,
-                                PackageManager.GET_SIGNING_CERTIFICATES);
+                        info = mPackageManager.getPackageInfoAsUser(packName,
+                                PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
                     } catch (NameNotFoundException e) {
                         // Weird; we just found it, and now are told it doesn't exist.
                         // Treat it as having been removed from the device.
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 79d4a2c..4f58d79 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -32,7 +32,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Binder;
-import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -45,7 +44,6 @@
 import android.provider.Settings;
 import android.util.Slog;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.DumpUtils;
 
 import java.io.File;
@@ -65,8 +63,8 @@
  * following two ways:
  *
  * <ul>
- *   <li>Temporary - create the file {@link #BACKUP_SUPPRESS_FILENAME}, or
- *   <li>Permanent - set the system property {@link #BACKUP_DISABLE_PROPERTY} to true.
+ * <li>Temporary - create the file {@link #BACKUP_SUPPRESS_FILENAME}, or
+ * <li>Permanent - set the system property {@link #BACKUP_DISABLE_PROPERTY} to true.
  * </ul>
  *
  * Temporary disabling is controlled by {@link #setBackupServiceActive(int, boolean)} through
@@ -91,10 +89,9 @@
 
     private final Context mContext;
 
-    @GuardedBy("mStateLock")
-    private final File mSuppressFile;
-
     private final boolean mGlobalDisable;
+    // Lock to write backup suppress files.
+    // TODD(b/121198006): remove this object and synchronized all methods on "this".
     private final Object mStateLock = new Object();
 
     private volatile BackupManagerService mService;
@@ -104,9 +101,6 @@
     public Trampoline(Context context) {
         mContext = context;
         mGlobalDisable = isBackupDisabled();
-        mSuppressFile = getSuppressFile();
-        mSuppressFile.getParentFile().mkdirs();
-
         mHandlerThread = new HandlerThread(BACKUP_THREAD, Process.THREAD_PRIORITY_BACKGROUND);
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
@@ -132,11 +126,42 @@
         return Binder.getCallingUid();
     }
 
-    protected File getSuppressFile() {
-        return new File(new File(Environment.getDataDirectory(), "backup"),
+    protected File getSuppressFileForUser(int userId) {
+        return new File(UserBackupManagerFiles.getBaseStateDir(userId),
                 BACKUP_SUPPRESS_FILENAME);
     }
 
+    protected void createBackupSuppressFileForUser(int userId) throws IOException {
+        synchronized (mStateLock) {
+            getSuppressFileForUser(userId).getParentFile().mkdirs();
+            getSuppressFileForUser(userId).createNewFile();
+        }
+    }
+
+    private void deleteBackupSuppressFileForUser(int userId) {
+        if (!getSuppressFileForUser(userId).delete()) {
+            Slog.w(TAG, "Failed deleting backup suppressed file for user: " + userId);
+        }
+    }
+
+    // A user is ready for a backup if it's unlocked and is not suppressed by a device
+    // admin (device owner or profile owner).
+    private boolean isUserReadyForBackup(int userId) {
+        return mService != null && mService.getServiceUsers().get(userId) != null
+                && !isBackupSuppressedForUser(userId);
+    }
+
+    private boolean isBackupSuppressedForUser(int userId) {
+        // If backup is disabled for system user, it's disabled for all other users on device.
+        if (getSuppressFileForUser(UserHandle.USER_SYSTEM).exists()) {
+            return true;
+        }
+        if (userId != UserHandle.USER_SYSTEM) {
+            return getSuppressFileForUser(userId).exists();
+        }
+        return false;
+    }
+
     protected Context getContext() {
         return mContext;
     }
@@ -162,12 +187,9 @@
                         Slog.i(TAG, "Backup service not supported");
                         return;
                     }
-
                     synchronized (mStateLock) {
-                        if (!mSuppressFile.exists()) {
+                        if (mService == null) {
                             mService = createBackupManagerService();
-                        } else {
-                            Slog.i(TAG, "Backup service inactive");
                         }
                     }
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -190,10 +212,11 @@
     }
 
     private void startServiceForUser(int userId) {
-        BackupManagerService service = mService;
-        if (service != null) {
+        // We know that the user is unlocked here because it is called from setBackupServiceActive
+        // and unlockUser which have these guarantees. So we can check if the file exists.
+        if (mService != null && !isBackupSuppressedForUser(userId)) {
             Slog.i(TAG, "Starting service for user: " + userId);
-            service.startServiceForUser(userId);
+            mService.startServiceForUser(userId);
         }
     }
 
@@ -209,10 +232,9 @@
 
         postToHandler(
                 () -> {
-                    BackupManagerService service = mService;
-                    if (service != null) {
+                    if (mService != null) {
                         Slog.i(TAG, "Stopping service for user: " + userId);
-                        service.stopServiceForUser(userId);
+                        mService.stopServiceForUser(userId);
                     }
                 });
     }
@@ -221,6 +243,8 @@
      * Only privileged callers should be changing the backup state. This method only acts on {@link
      * UserHandle#USER_SYSTEM} and is a no-op if passed non-system users. Deactivating backup in the
      * system user also deactivates backup in all users.
+     *
+     * This call will only work if the calling {@code userID} is unlocked.
      */
     public void setBackupServiceActive(int userId, boolean makeActive) {
         int caller = binderGetCallingUid();
@@ -246,16 +270,21 @@
         synchronized (mStateLock) {
             Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active");
             if (makeActive) {
-                mService = createBackupManagerService();
-                mSuppressFile.delete();
+                if (mService == null) {
+                    mService = createBackupManagerService();
+                }
+                deleteBackupSuppressFileForUser(userId);
                 startServiceForUser(userId);
             } else {
-                mService = null;
                 try {
-                    mSuppressFile.createNewFile();
+                    //TODO(b/121198006): what if this throws an exception?
+                    createBackupSuppressFileForUser(userId);
                 } catch (IOException e) {
                     Slog.e(TAG, "Unable to persist backup service inactivity");
                 }
+                //TODO(b/121198006): loop through active users that have work profile and
+                // stop them as well.
+                stopUser(userId);
             }
         }
     }
@@ -271,20 +300,15 @@
      */
     @Override
     public boolean isBackupServiceActive(int userId) {
-        // TODO: http://b/22388012
-        if (userId == UserHandle.USER_SYSTEM) {
-            synchronized (mStateLock) {
-                return mService != null;
-            }
+        synchronized (mStateLock) {
+            return isUserReadyForBackup(userId);
         }
-        return false;
     }
 
     @Override
     public void dataChangedForUser(int userId, String packageName) throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.dataChanged(userId, packageName);
+        if (isUserReadyForBackup(userId)) {
+            mService.dataChanged(userId, packageName);
         }
     }
 
@@ -296,18 +320,16 @@
     @Override
     public void initializeTransportsForUser(
             int userId, String[] transportNames, IBackupObserver observer) throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.initializeTransports(userId, transportNames, observer);
+        if (isUserReadyForBackup(userId)) {
+            mService.initializeTransports(userId, transportNames, observer);
         }
     }
 
     @Override
     public void clearBackupDataForUser(int userId, String transportName, String packageName)
             throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.clearBackupData(userId, transportName, packageName);
+        if (isUserReadyForBackup(userId)) {
+            mService.clearBackupData(userId, transportName, packageName);
         }
     }
 
@@ -320,9 +342,8 @@
     @Override
     public void agentConnectedForUser(int userId, String packageName, IBinder agent)
             throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.agentConnected(userId, packageName, agent);
+        if (isUserReadyForBackup(userId)) {
+            mService.agentConnected(userId, packageName, agent);
         }
     }
 
@@ -333,9 +354,8 @@
 
     @Override
     public void agentDisconnectedForUser(int userId, String packageName) throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.agentDisconnected(userId, packageName);
+        if (isUserReadyForBackup(userId)) {
+            mService.agentDisconnected(userId, packageName);
         }
     }
 
@@ -347,9 +367,8 @@
     @Override
     public void restoreAtInstallForUser(int userId, String packageName, int token)
             throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.restoreAtInstall(userId, packageName, token);
+        if (isUserReadyForBackup(userId)) {
+            mService.restoreAtInstall(userId, packageName, token);
         }
     }
 
@@ -361,9 +380,8 @@
     @Override
     public void setBackupEnabledForUser(@UserIdInt int userId, boolean isEnabled)
             throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.setBackupEnabled(userId, isEnabled);
+        if (isUserReadyForBackup(userId)) {
+            mService.setBackupEnabled(userId, isEnabled);
         }
     }
 
@@ -374,9 +392,8 @@
 
     @Override
     public void setAutoRestoreForUser(int userId, boolean doAutoRestore) throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.setAutoRestore(userId, doAutoRestore);
+        if (isUserReadyForBackup(userId)) {
+            mService.setAutoRestore(userId, doAutoRestore);
         }
     }
 
@@ -387,8 +404,7 @@
 
     @Override
     public boolean isBackupEnabledForUser(@UserIdInt int userId) throws RemoteException {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.isBackupEnabled(userId) : false;
+        return isUserReadyForBackup(userId) && mService.isBackupEnabled(userId);
     }
 
     @Override
@@ -398,21 +414,20 @@
 
     @Override
     public boolean setBackupPassword(String currentPw, String newPw) throws RemoteException {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.setBackupPassword(currentPw, newPw) : false;
+        int userId = binderGetCallingUserId();
+        return (isUserReadyForBackup(userId)) && mService.setBackupPassword(currentPw, newPw);
     }
 
     @Override
     public boolean hasBackupPassword() throws RemoteException {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.hasBackupPassword() : false;
+        int userId = binderGetCallingUserId();
+        return (isUserReadyForBackup(userId)) && mService.hasBackupPassword();
     }
 
     @Override
     public void backupNowForUser(@UserIdInt int userId) throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.backupNow(userId);
+        if (isUserReadyForBackup(userId)) {
+            mService.backupNow(userId);
         }
     }
 
@@ -425,9 +440,8 @@
             boolean includeApks, boolean includeObbs, boolean includeShared, boolean doWidgets,
             boolean allApps, boolean allIncludesSystem, boolean doCompress, boolean doKeyValue,
             String[] packageNames) throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.adbBackup(userId, fd, includeApks, includeObbs, includeShared, doWidgets,
+        if (isUserReadyForBackup(userId)) {
+            mService.adbBackup(userId, fd, includeApks, includeObbs, includeShared, doWidgets,
                     allApps, allIncludesSystem, doCompress, doKeyValue, packageNames);
         }
     }
@@ -435,17 +449,15 @@
     @Override
     public void fullTransportBackupForUser(int userId, String[] packageNames)
             throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.fullTransportBackup(userId, packageNames);
+        if (isUserReadyForBackup(userId)) {
+            mService.fullTransportBackup(userId, packageNames);
         }
     }
 
     @Override
     public void adbRestore(@UserIdInt int userId, ParcelFileDescriptor fd) throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.adbRestore(userId, fd);
+        if (isUserReadyForBackup(userId)) {
+            mService.adbRestore(userId, fd);
         }
     }
 
@@ -458,9 +470,8 @@
             String encryptionPassword,
             IFullBackupRestoreObserver observer)
             throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.acknowledgeAdbBackupOrRestore(userId, token, allow,
+        if (isUserReadyForBackup(userId)) {
+            mService.acknowledgeAdbBackupOrRestore(userId, token, allow,
                     curPassword, encryptionPassword, observer);
         }
     }
@@ -468,8 +479,7 @@
     @Override
     public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword,
             String encryptionPassword, IFullBackupRestoreObserver observer)
-                    throws RemoteException {
-        BackupManagerService svc = mService;
+            throws RemoteException {
         acknowledgeFullBackupOrRestoreForUser(
                 binderGetCallingUserId(), token, allow, curPassword, encryptionPassword, observer);
     }
@@ -477,8 +487,7 @@
 
     @Override
     public String getCurrentTransportForUser(int userId) throws RemoteException {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.getCurrentTransport(userId) : null;
+        return (isUserReadyForBackup(userId)) ? mService.getCurrentTransport(userId) : null;
     }
 
     @Override
@@ -493,14 +502,13 @@
     @Override
     @Nullable
     public ComponentName getCurrentTransportComponentForUser(int userId) {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.getCurrentTransportComponent(userId) : null;
+        return (isUserReadyForBackup(userId)) ? mService.getCurrentTransportComponent(userId)
+                : null;
     }
 
     @Override
     public String[] listAllTransportsForUser(int userId) throws RemoteException {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.listAllTransports(userId) : null;
+        return (isUserReadyForBackup(userId)) ? mService.listAllTransports(userId) : null;
     }
 
     @Override
@@ -510,14 +518,14 @@
 
     @Override
     public ComponentName[] listAllTransportComponentsForUser(int userId) throws RemoteException {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.listAllTransportComponents(userId) : null;
+        return (isUserReadyForBackup(userId)) ? mService.listAllTransportComponents(userId)
+                : null;
     }
 
     @Override
     public String[] getTransportWhitelist() {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.getTransportWhitelist() : null;
+        int userId = binderGetCallingUserId();
+        return (isUserReadyForBackup(userId)) ? mService.getTransportWhitelist() : null;
     }
 
     @Override
@@ -529,9 +537,9 @@
             String currentDestinationString,
             @Nullable Intent dataManagementIntent,
             String dataManagementLabel) {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.updateTransportAttributes(
+
+        if (isUserReadyForBackup(userId)) {
+            mService.updateTransportAttributes(
                     userId,
                     transportComponent,
                     name,
@@ -545,8 +553,8 @@
     @Override
     public String selectBackupTransportForUser(int userId, String transport)
             throws RemoteException {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.selectBackupTransport(userId, transport) : null;
+        return (isUserReadyForBackup(userId)) ? mService.selectBackupTransport(userId, transport)
+                : null;
     }
 
     @Override
@@ -557,9 +565,8 @@
     @Override
     public void selectBackupTransportAsyncForUser(int userId, ComponentName transport,
             ISelectBackupTransportCallback listener) throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.selectBackupTransportAsync(userId, transport, listener);
+        if (isUserReadyForBackup(userId)) {
+            mService.selectBackupTransportAsync(userId, transport, listener);
         } else {
             if (listener != null) {
                 try {
@@ -574,8 +581,8 @@
     @Override
     public Intent getConfigurationIntentForUser(int userId, String transport)
             throws RemoteException {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.getConfigurationIntent(userId, transport) : null;
+        return isUserReadyForBackup(userId) ? mService.getConfigurationIntent(userId, transport)
+                : null;
     }
 
     @Override
@@ -586,8 +593,8 @@
 
     @Override
     public String getDestinationStringForUser(int userId, String transport) throws RemoteException {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.getDestinationString(userId, transport) : null;
+        return isUserReadyForBackup(userId) ? mService.getDestinationString(userId, transport)
+                : null;
     }
 
     @Override
@@ -598,8 +605,8 @@
     @Override
     public Intent getDataManagementIntentForUser(int userId, String transport)
             throws RemoteException {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.getDataManagementIntent(userId, transport) : null;
+        return isUserReadyForBackup(userId) ? mService.getDataManagementIntent(userId, transport)
+                : null;
     }
 
     @Override
@@ -611,8 +618,8 @@
     @Override
     public String getDataManagementLabelForUser(int userId, String transport)
             throws RemoteException {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.getDataManagementLabel(userId, transport) : null;
+        return isUserReadyForBackup(userId) ? mService.getDataManagementLabel(userId, transport)
+                : null;
     }
 
     @Override
@@ -624,44 +631,47 @@
     @Override
     public IRestoreSession beginRestoreSessionForUser(
             int userId, String packageName, String transportID) throws RemoteException {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.beginRestoreSession(userId, packageName, transportID) : null;
+        return isUserReadyForBackup(userId) ? mService.beginRestoreSession(userId, packageName,
+                transportID) : null;
     }
 
     @Override
-    public void opComplete(int token, long result) throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.opComplete(binderGetCallingUserId(), token, result);
+    public void opCompleteForUser(int userId, int token, long result) throws RemoteException {
+        if (isUserReadyForBackup(userId)) {
+            mService.opComplete(userId, token, result);
         }
     }
 
     @Override
+    public void opComplete(int token, long result) throws RemoteException {
+        opCompleteForUser(binderGetCallingUserId(), token, result);
+    }
+
+    @Override
     public long getAvailableRestoreTokenForUser(int userId, String packageName) {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.getAvailableRestoreToken(userId, packageName) : 0;
+        return isUserReadyForBackup(userId) ? mService.getAvailableRestoreToken(userId,
+                packageName) : 0;
     }
 
     @Override
     public boolean isAppEligibleForBackupForUser(int userId, String packageName) {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.isAppEligibleForBackup(userId, packageName) : false;
+        return isUserReadyForBackup(userId) && mService.isAppEligibleForBackup(userId,
+                packageName);
     }
 
     @Override
     public String[] filterAppsEligibleForBackupForUser(int userId, String[] packages) {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.filterAppsEligibleForBackup(userId, packages) : null;
+        return isUserReadyForBackup(userId) ? mService.filterAppsEligibleForBackup(userId,
+                packages) : null;
     }
 
     @Override
     public int requestBackupForUser(@UserIdInt int userId, String[] packages, IBackupObserver
             observer, IBackupManagerMonitor monitor, int flags) throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc == null) {
+        if (!isUserReadyForBackup(userId)) {
             return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
         }
-        return svc.requestBackup(userId, packages, observer, monitor, flags);
+        return mService.requestBackup(userId, packages, observer, monitor, flags);
     }
 
     @Override
@@ -673,9 +683,8 @@
 
     @Override
     public void cancelBackupsForUser(@UserIdInt int userId) throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.cancelBackups(userId);
+        if (isUserReadyForBackup(userId)) {
+            mService.cancelBackups(userId);
         }
     }
 
@@ -687,10 +696,9 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
-
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.dump(fd, pw, args);
+        int userId = binderGetCallingUserId();
+        if (isUserReadyForBackup(userId)) {
+            mService.dump(fd, pw, args);
         } else {
             pw.println("Inactive");
         }
@@ -698,15 +706,13 @@
 
     // Full backup/restore entry points - non-Binder; called directly
     // by the full-backup scheduled job
-    /* package */ boolean beginFullBackup(FullBackupJob scheduledJob) {
-        BackupManagerService svc = mService;
-        return (svc != null) ? svc.beginFullBackup(scheduledJob) : false;
+    /* package */ boolean beginFullBackup(@UserIdInt int userId, FullBackupJob scheduledJob) {
+        return (isUserReadyForBackup(userId)) && mService.beginFullBackup(userId, scheduledJob);
     }
 
-    /* package */ void endFullBackup() {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.endFullBackup();
+    /* package */ void endFullBackup(@UserIdInt int userId) {
+        if (isUserReadyForBackup(userId)) {
+            mService.endFullBackup(userId);
         }
     }
 }
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index ddce6bb..a7bada0 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -17,6 +17,7 @@
 package com.android.server.backup;
 
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.app.backup.BackupManager;
 import android.app.backup.BackupTransport;
@@ -29,7 +30,6 @@
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -61,7 +61,7 @@
     public static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
 
     private final Intent mTransportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
-    private final Context mContext;
+    private final @UserIdInt int mUserId;
     private final PackageManager mPackageManager;
     private final Set<ComponentName> mTransportWhitelist;
     private final TransportClientManager mTransportClientManager;
@@ -86,22 +86,24 @@
     @Nullable
     private volatile String mCurrentTransportName;
 
-    TransportManager(Context context, Set<ComponentName> whitelist, String selectedTransport) {
-        mContext = context;
+    TransportManager(@UserIdInt int userId, Context context, Set<ComponentName> whitelist,
+            String selectedTransport) {
+        mUserId = userId;
         mPackageManager = context.getPackageManager();
         mTransportWhitelist = Preconditions.checkNotNull(whitelist);
         mCurrentTransportName = selectedTransport;
         mTransportStats = new TransportStats();
-        mTransportClientManager = new TransportClientManager(context, mTransportStats);
+        mTransportClientManager = new TransportClientManager(mUserId, context, mTransportStats);
     }
 
     @VisibleForTesting
     TransportManager(
+            @UserIdInt int userId,
             Context context,
             Set<ComponentName> whitelist,
             String selectedTransport,
             TransportClientManager transportClientManager) {
-        mContext = context;
+        mUserId = userId;
         mPackageManager = context.getPackageManager();
         mTransportWhitelist = Preconditions.checkNotNull(whitelist);
         mCurrentTransportName = selectedTransport;
@@ -560,7 +562,7 @@
     private void registerTransportsFromPackage(
             String packageName, Predicate<ComponentName> transportComponentFilter) {
         try {
-            mPackageManager.getPackageInfo(packageName, 0);
+            mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId);
         } catch (PackageManager.NameNotFoundException e) {
             Slog.e(TAG, "Trying to register transports from package not found " + packageName);
             return;
@@ -575,7 +577,7 @@
     private void registerTransportsForIntent(
             Intent intent, Predicate<ComponentName> transportComponentFilter) {
         List<ResolveInfo> hosts =
-                mPackageManager.queryIntentServicesAsUser(intent, 0, UserHandle.USER_SYSTEM);
+                mPackageManager.queryIntentServicesAsUser(intent, 0, mUserId);
         if (hosts == null) {
             return;
         }
@@ -597,7 +599,8 @@
             return false;
         }
         try {
-            PackageInfo packInfo = mPackageManager.getPackageInfo(transport.getPackageName(), 0);
+            PackageInfo packInfo =
+                    mPackageManager.getPackageInfoAsUser(transport.getPackageName(), 0, mUserId);
             if ((packInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
                     == 0) {
                 Slog.w(TAG, "Transport package " + transport.getPackageName() + " not privileged");
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java b/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java
index a0feaf9..aabd41a 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerFiles.java
@@ -17,29 +17,35 @@
 package com.android.server.backup;
 
 import android.os.Environment;
+import android.os.UserHandle;
 
 import java.io.File;
 
 /** Directories used for user specific backup/restore persistent state and book-keeping. */
-public final class UserBackupManagerFiles {
+final class UserBackupManagerFiles {
     // Name of the directories the service stores bookkeeping data under.
     private static final String BACKUP_PERSISTENT_DIR = "backup";
     private static final String BACKUP_STAGING_DIR = "backup_stage";
 
+    private static File getBaseDir(int userId) {
+        return Environment.getDataSystemCeDirectory(userId);
+    }
+
     static File getBaseStateDir(int userId) {
-        // TODO (b/120424138) this should be per user
+        if (userId != UserHandle.USER_SYSTEM) {
+            return new File(getBaseDir(userId), BACKUP_PERSISTENT_DIR);
+        }
+        // TODO (b/120424138) remove if clause above and use same logic for system user.
+        // simultaneously, copy below dir to new system user dir
         return new File(Environment.getDataDirectory(), BACKUP_PERSISTENT_DIR);
     }
 
     static File getDataDir(int userId) {
-        // TODO (b/120424138) this should be per user
-        // This dir on /cache is managed directly in init.rc
+        if (userId != UserHandle.USER_SYSTEM) {
+            return new File(getBaseDir(userId), BACKUP_STAGING_DIR);
+        }
+        // TODO (b/120424138) remove if clause above and use same logic for system user. Since this
+        // is a staging dir, we dont need to copy below dir to new system user dir
         return new File(Environment.getDownloadCacheDirectory(), BACKUP_STAGING_DIR);
     }
-
-    /** Directory used by full backup engine to store state. */
-    public static File getFullBackupEngineFilesDir(int userId) {
-        // TODO (b/120424138) this should be per user
-        return new File("/data/system");
-    }
 }
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 6425508..115e924 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -39,6 +39,7 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
@@ -103,6 +104,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.AppWidgetBackupBridge;
 import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
 import com.android.server.backup.fullbackup.FullBackupEntry;
 import com.android.server.backup.fullbackup.PerformFullTransportBackupTask;
 import com.android.server.backup.internal.BackupHandler;
@@ -110,9 +112,9 @@
 import com.android.server.backup.internal.OnTaskFinishedListener;
 import com.android.server.backup.internal.Operation;
 import com.android.server.backup.internal.PerformInitializeTask;
-import com.android.server.backup.internal.ProvisionedObserver;
 import com.android.server.backup.internal.RunBackupReceiver;
 import com.android.server.backup.internal.RunInitializeReceiver;
+import com.android.server.backup.internal.SetupObserver;
 import com.android.server.backup.keyvalue.BackupRequest;
 import com.android.server.backup.params.AdbBackupParams;
 import com.android.server.backup.params.AdbParams;
@@ -208,8 +210,8 @@
 
     public static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN";
     public static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
-    public static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED";
-    public static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName";
+    private static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED";
+    private static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName";
 
     // Bookkeeping of in-flight operations. The operation token is the index of the entry in the
     // pending operations list.
@@ -245,26 +247,28 @@
     private final @UserIdInt int mUserId;
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
     private final TransportManager mTransportManager;
+    private final HandlerThread mUserBackupThread;
 
-    private Context mContext;
-    private PackageManager mPackageManager;
-    private IPackageManager mPackageManagerBinder;
-    private IActivityManager mActivityManager;
+    private final Context mContext;
+    private final PackageManager mPackageManager;
+    private final IPackageManager mPackageManagerBinder;
+    private final IActivityManager mActivityManager;
+    private final ActivityManagerInternal mActivityManagerInternal;
     private PowerManager mPowerManager;
-    private AlarmManager mAlarmManager;
-    private IStorageManager mStorageManager;
-    private BackupManagerConstants mConstants;
-    private PowerManager.WakeLock mWakelock;
-    private BackupHandler mBackupHandler;
+    private final AlarmManager mAlarmManager;
+    private final IStorageManager mStorageManager;
+    private final BackupManagerConstants mConstants;
+    private final PowerManager.WakeLock mWakelock;
+    private final BackupHandler mBackupHandler;
 
-    private IBackupManager mBackupManagerBinder;
+    private final IBackupManager mBackupManagerBinder;
 
     private boolean mEnabled;   // access to this is synchronized on 'this'
-    private boolean mProvisioned;
+    private boolean mSetupComplete;
     private boolean mAutoRestore;
 
-    private PendingIntent mRunBackupIntent;
-    private PendingIntent mRunInitIntent;
+    private final PendingIntent mRunBackupIntent;
+    private final PendingIntent mRunInitIntent;
 
     private final ArraySet<String> mPendingInits = new ArraySet<>();  // transport names
 
@@ -272,7 +276,7 @@
     private final SparseArray<HashSet<String>> mBackupParticipants = new SparseArray<>();
 
     // Backups that we haven't started yet.  Keys are package names.
-    private HashMap<String, BackupRequest> mPendingBackups = new HashMap<>();
+    private final HashMap<String, BackupRequest> mPendingBackups = new HashMap<>();
 
     // locking around the pending-backup management
     private final Object mQueueLock = new Object();
@@ -314,9 +318,6 @@
 
     private ActiveRestoreSession mActiveRestoreSession;
 
-    // Watch the device provisioning operation during setup
-    private ContentObserver mProvisionedObserver;
-
     /**
      * mCurrentOperations contains the list of currently active operations.
      *
@@ -342,7 +343,7 @@
     private final SparseArray<Operation> mCurrentOperations = new SparseArray<>();
     private final Object mCurrentOpLock = new Object();
     private final Random mTokenGenerator = new Random();
-    final AtomicInteger mNextToken = new AtomicInteger();
+    private final AtomicInteger mNextToken = new AtomicInteger();
 
     // Where we keep our journal files and other bookkeeping.
     private final File mBaseStateDir;
@@ -350,7 +351,7 @@
     private final File mJournalDir;
     @Nullable
     private DataChangedJournal mJournal;
-    private File mFullBackupScheduleFile;
+    private final File mFullBackupScheduleFile;
 
     // Keep a log of all the apps we've ever backed up.
     private ProcessedPackagesJournal mProcessedPackagesJournal;
@@ -371,11 +372,10 @@
             @UserIdInt int userId,
             Context context,
             Trampoline trampoline,
-            HandlerThread backupThread,
             Set<ComponentName> transportWhitelist) {
         String currentTransport =
-                Settings.Secure.getString(
-                        context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT);
+                Settings.Secure.getStringForUser(
+                        context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT, userId);
         if (TextUtils.isEmpty(currentTransport)) {
             currentTransport = null;
         }
@@ -384,13 +384,26 @@
             Slog.v(TAG, "Starting with transport " + currentTransport);
         }
         TransportManager transportManager =
-                new TransportManager(context, transportWhitelist, currentTransport);
+                new TransportManager(userId, context, transportWhitelist, currentTransport);
 
         File baseStateDir = UserBackupManagerFiles.getBaseStateDir(userId);
         File dataDir = UserBackupManagerFiles.getDataDir(userId);
 
+        HandlerThread userBackupThread =
+                new HandlerThread("backup-" + userId, Process.THREAD_PRIORITY_BACKGROUND);
+        userBackupThread.start();
+        if (DEBUG) {
+            Slog.d(TAG, "Started thread " + userBackupThread.getName() + " for user " + userId);
+        }
+
         return createAndInitializeService(
-                userId, context, trampoline, backupThread, baseStateDir, dataDir, transportManager);
+                userId,
+                context,
+                trampoline,
+                userBackupThread,
+                baseStateDir,
+                dataDir,
+                transportManager);
     }
 
     /**
@@ -399,7 +412,7 @@
      * @param userId The user which this service is for.
      * @param context The system server context.
      * @param trampoline A reference to the proxy to {@link BackupManagerService}.
-     * @param backupThread The thread running backup/restore operations for the user.
+     * @param userBackupThread The thread running backup/restore operations for the user.
      * @param baseStateDir The directory we store the user's persistent bookkeeping data.
      * @param dataDir The directory we store the user's temporary staging data.
      * @param transportManager The {@link TransportManager} responsible for handling the user's
@@ -410,19 +423,38 @@
             @UserIdInt int userId,
             Context context,
             Trampoline trampoline,
-            HandlerThread backupThread,
+            HandlerThread userBackupThread,
             File baseStateDir,
             File dataDir,
             TransportManager transportManager) {
         return new UserBackupManagerService(
-                userId, context, trampoline, backupThread, baseStateDir, dataDir, transportManager);
+                userId,
+                context,
+                trampoline,
+                userBackupThread,
+                baseStateDir,
+                dataDir,
+                transportManager);
+    }
+
+    /**
+     * Returns the value of {@link Settings.Secure#USER_SETUP_COMPLETE} for the specified user
+     * {@code userId} as a {@code boolean}.
+     */
+    public static boolean getSetupCompleteSettingForUser(Context context, int userId) {
+        return Settings.Secure.getIntForUser(
+                context.getContentResolver(),
+                Settings.Secure.USER_SETUP_COMPLETE,
+                0,
+                userId)
+                != 0;
     }
 
     private UserBackupManagerService(
             @UserIdInt int userId,
             Context context,
             Trampoline parent,
-            HandlerThread backupThread,
+            HandlerThread userBackupThread,
             File baseStateDir,
             File dataDir,
             TransportManager transportManager) {
@@ -431,6 +463,7 @@
         mPackageManager = context.getPackageManager();
         mPackageManagerBinder = AppGlobals.getPackageManager();
         mActivityManager = ActivityManager.getService();
+        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
 
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -443,52 +476,78 @@
                 BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver());
         mAgentTimeoutParameters.start();
 
-        // spin up the backup/restore handler thread
-        checkNotNull(backupThread, "backupThread cannot be null");
-        mBackupHandler = new BackupHandler(this, backupThread.getLooper());
+        checkNotNull(userBackupThread, "userBackupThread cannot be null");
+        mUserBackupThread = userBackupThread;
+        mBackupHandler = new BackupHandler(this, userBackupThread.getLooper());
 
         // Set up our bookkeeping
         final ContentResolver resolver = context.getContentResolver();
-        mProvisioned = Settings.Global.getInt(resolver,
-                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
-        mAutoRestore = Settings.Secure.getInt(resolver,
-                Settings.Secure.BACKUP_AUTO_RESTORE, 1) != 0;
+        mSetupComplete = getSetupCompleteSettingForUser(context, userId);
+        mAutoRestore = Settings.Secure.getIntForUser(resolver,
+                Settings.Secure.BACKUP_AUTO_RESTORE, 1, userId) != 0;
 
-        mProvisionedObserver = new ProvisionedObserver(this, mBackupHandler);
+        ContentObserver setupObserver = new SetupObserver(this, mBackupHandler);
         resolver.registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
-                false, mProvisionedObserver);
+                Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE),
+                /* notifyForDescendents */ false,
+                setupObserver,
+                mUserId);
 
         mBaseStateDir = checkNotNull(baseStateDir, "baseStateDir cannot be null");
-        mBaseStateDir.mkdirs();
-        if (!SELinux.restorecon(mBaseStateDir)) {
-            Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
+        // TODO (b/120424138): Remove once the system user is migrated to use the per-user CE
+        // directory. Per-user CE directories are managed by vold.
+        if (userId == UserHandle.USER_SYSTEM) {
+            mBaseStateDir.mkdirs();
+            if (!SELinux.restorecon(mBaseStateDir)) {
+                Slog.w(TAG, "SELinux restorecon failed on " + mBaseStateDir);
+            }
         }
 
+        // TODO (b/120424138): The system user currently uses the cache which is managed by init.rc
+        // Initialization and restorecon is managed by vold for per-user CE directories.
         mDataDir = checkNotNull(dataDir, "dataDir cannot be null");
-
         mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng);
 
-        // Alarm receivers for scheduled backups & initialization operations
-        BroadcastReceiver mRunBackupReceiver = new RunBackupReceiver(this);
+        // Receivers for scheduled backups and transport initialization operations.
+        BroadcastReceiver runBackupReceiver = new RunBackupReceiver(this);
         IntentFilter filter = new IntentFilter();
         filter.addAction(RUN_BACKUP_ACTION);
-        context.registerReceiver(mRunBackupReceiver, filter,
-                android.Manifest.permission.BACKUP, null);
+        context.registerReceiverAsUser(
+                runBackupReceiver,
+                UserHandle.of(userId),
+                filter,
+                android.Manifest.permission.BACKUP,
+                /* scheduler */ null);
 
-        BroadcastReceiver mRunInitReceiver = new RunInitializeReceiver(this);
+        BroadcastReceiver runInitReceiver = new RunInitializeReceiver(this);
         filter = new IntentFilter();
         filter.addAction(RUN_INITIALIZE_ACTION);
-        context.registerReceiver(mRunInitReceiver, filter,
-                android.Manifest.permission.BACKUP, null);
+        context.registerReceiverAsUser(
+                runInitReceiver,
+                UserHandle.of(userId),
+                filter,
+                android.Manifest.permission.BACKUP,
+                /* scheduler */ null);
 
         Intent backupIntent = new Intent(RUN_BACKUP_ACTION);
         backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        mRunBackupIntent = PendingIntent.getBroadcast(context, 0, backupIntent, 0);
+        mRunBackupIntent =
+                PendingIntent.getBroadcastAsUser(
+                        context,
+                        /* requestCode */ 0,
+                        backupIntent,
+                        /* flags */ 0,
+                        UserHandle.of(userId));
 
         Intent initIntent = new Intent(RUN_INITIALIZE_ACTION);
         initIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        mRunInitIntent = PendingIntent.getBroadcast(context, 0, initIntent, 0);
+        mRunInitIntent =
+                PendingIntent.getBroadcastAsUser(
+                        context,
+                        /* requestCode */ 0,
+                        initIntent,
+                        /* flags */ 0,
+                        UserHandle.of(userId));
 
         // Set up the backup-request journaling
         mJournalDir = new File(mBaseStateDir, "pending");
@@ -523,7 +582,21 @@
         mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
 
         // Power management
-        mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
+        mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*-" + userId);
+    }
+
+    void initializeBackupEnableState() {
+        boolean isEnabled = UserBackupManagerFilePersistedSettings.readBackupEnableState(mUserId);
+        setBackupEnabled(isEnabled);
+    }
+
+    /** Cleans up state when the user of this service is stopped. */
+    void tearDownService() {
+        mUserBackupThread.quit();
+    }
+
+    public @UserIdInt int getUserId() {
+        return mUserId;
     }
 
     public BackupManagerConstants getConstants() {
@@ -538,51 +611,27 @@
         return mContext;
     }
 
-    public void setContext(Context context) {
-        mContext = context;
-    }
-
     public PackageManager getPackageManager() {
         return mPackageManager;
     }
 
-    public void setPackageManager(PackageManager packageManager) {
-        mPackageManager = packageManager;
-    }
-
     public IPackageManager getPackageManagerBinder() {
         return mPackageManagerBinder;
     }
 
-    public void setPackageManagerBinder(IPackageManager packageManagerBinder) {
-        mPackageManagerBinder = packageManagerBinder;
-    }
-
     public IActivityManager getActivityManager() {
         return mActivityManager;
     }
 
-    public void setActivityManager(IActivityManager activityManager) {
-        mActivityManager = activityManager;
-    }
-
     public AlarmManager getAlarmManager() {
         return mAlarmManager;
     }
 
-    public void setAlarmManager(AlarmManager alarmManager) {
-        mAlarmManager = alarmManager;
-    }
-
     @VisibleForTesting
     void setPowerManager(PowerManager powerManager) {
         mPowerManager = powerManager;
     }
 
-    public void setBackupManagerBinder(IBackupManager backupManagerBinder) {
-        mBackupManagerBinder = backupManagerBinder;
-    }
-
     public TransportManager getTransportManager() {
         return mTransportManager;
     }
@@ -595,12 +644,12 @@
         mEnabled = enabled;
     }
 
-    public boolean isProvisioned() {
-        return mProvisioned;
+    public boolean isSetupComplete() {
+        return mSetupComplete;
     }
 
-    public void setProvisioned(boolean provisioned) {
-        mProvisioned = provisioned;
+    public void setSetupComplete(boolean setupComplete) {
+        mSetupComplete = setupComplete;
     }
 
     public PowerManager.WakeLock getWakelock() {
@@ -617,35 +666,18 @@
         mWakelock.setWorkSource(workSource);
     }
 
-    public void setWakelock(PowerManager.WakeLock wakelock) {
-        mWakelock = wakelock;
-    }
-
     public Handler getBackupHandler() {
         return mBackupHandler;
     }
 
-    public void setBackupHandler(BackupHandler backupHandler) {
-        mBackupHandler = backupHandler;
-    }
-
     public PendingIntent getRunInitIntent() {
         return mRunInitIntent;
     }
 
-    public void setRunInitIntent(PendingIntent runInitIntent) {
-        mRunInitIntent = runInitIntent;
-    }
-
     public HashMap<String, BackupRequest> getPendingBackups() {
         return mPendingBackups;
     }
 
-    public void setPendingBackups(
-            HashMap<String, BackupRequest> pendingBackups) {
-        mPendingBackups = pendingBackups;
-    }
-
     public Object getQueueLock() {
         return mQueueLock;
     }
@@ -658,10 +690,6 @@
         mBackupRunning = backupRunning;
     }
 
-    public long getLastBackupPass() {
-        return mLastBackupPass;
-    }
-
     public void setLastBackupPass(long lastBackupPass) {
         mLastBackupPass = lastBackupPass;
     }
@@ -670,10 +698,6 @@
         return mClearDataLock;
     }
 
-    public boolean isClearingData() {
-        return mClearingData;
-    }
-
     public void setClearingData(boolean clearingData) {
         mClearingData = clearingData;
     }
@@ -694,11 +718,6 @@
         return mActiveRestoreSession;
     }
 
-    public void setActiveRestoreSession(
-            ActiveRestoreSession activeRestoreSession) {
-        mActiveRestoreSession = activeRestoreSession;
-    }
-
     public SparseArray<Operation> getCurrentOperations() {
         return mCurrentOperations;
     }
@@ -732,18 +751,10 @@
         return mRng;
     }
 
-    public Set<String> getAncestralPackages() {
-        return mAncestralPackages;
-    }
-
     public void setAncestralPackages(Set<String> ancestralPackages) {
         mAncestralPackages = ancestralPackages;
     }
 
-    public long getAncestralToken() {
-        return mAncestralToken;
-    }
-
     public void setAncestralToken(long ancestralToken) {
         mAncestralToken = ancestralToken;
     }
@@ -791,9 +802,9 @@
      * non-lifecycle agent instance, so we manually set up the context topology for it.
      */
     public BackupAgent makeMetadataAgent() {
-        PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(mPackageManager);
+        PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(mPackageManager, mUserId);
         pmAgent.attach(mContext);
-        pmAgent.onCreate();
+        pmAgent.onCreate(UserHandle.of(mUserId));
         return pmAgent;
     }
 
@@ -802,9 +813,9 @@
      */
     public PackageManagerBackupAgent makeMetadataAgent(List<PackageInfo> packages) {
         PackageManagerBackupAgent pmAgent =
-                new PackageManagerBackupAgent(mPackageManager, packages);
+                new PackageManagerBackupAgent(mPackageManager, packages, mUserId);
         pmAgent.attach(mContext);
-        pmAgent.onCreate();
+        pmAgent.onCreate(UserHandle.of(mUserId));
         return pmAgent;
     }
 
@@ -844,26 +855,36 @@
             mFullBackupQueue = readFullBackupSchedule();
         }
 
-        // Register for broadcasts about package install, etc., so we can
-        // update the provider list.
+        // Register for broadcasts about package changes.
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addDataScheme("package");
-        mContext.registerReceiver(mBroadcastReceiver, filter);
+        mContext.registerReceiverAsUser(
+                mBroadcastReceiver,
+                UserHandle.of(mUserId),
+                filter,
+                /* broadcastPermission */ null,
+                /* scheduler */ null);
+
         // Register for events related to sdcard installation.
         IntentFilter sdFilter = new IntentFilter();
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-        mContext.registerReceiver(mBroadcastReceiver, sdFilter);
+        mContext.registerReceiverAsUser(
+                mBroadcastReceiver,
+                UserHandle.of(mUserId),
+                sdFilter,
+                /* broadcastPermission */ null,
+                /* scheduler */ null);
     }
 
     private ArrayList<FullBackupEntry> readFullBackupSchedule() {
         boolean changed = false;
         ArrayList<FullBackupEntry> schedule = null;
         List<PackageInfo> apps =
-                PackageManagerBackupAgent.getStorableApplications(mPackageManager);
+                PackageManagerBackupAgent.getStorableApplications(mPackageManager, mUserId);
 
         if (mFullBackupScheduleFile.exists()) {
             try (FileInputStream fstream = new FileInputStream(mFullBackupScheduleFile);
@@ -889,10 +910,10 @@
                     long lastBackup = in.readLong();
                     foundApps.add(pkgName); // all apps that we've addressed already
                     try {
-                        PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0);
+                        PackageInfo pkg = mPackageManager.getPackageInfoAsUser(pkgName, 0, mUserId);
                         if (AppBackupUtils.appGetsFullBackup(pkg)
-                                && AppBackupUtils.appIsEligibleForBackup(
-                                pkg.applicationInfo, mPackageManager)) {
+                                && AppBackupUtils.appIsEligibleForBackup(pkg.applicationInfo,
+                                mUserId)) {
                             schedule.add(new FullBackupEntry(pkgName, lastBackup));
                         } else {
                             if (DEBUG) {
@@ -912,8 +933,8 @@
                 // scan to make sure that we're tracking all full-backup candidates properly
                 for (PackageInfo app : apps) {
                     if (AppBackupUtils.appGetsFullBackup(app)
-                            && AppBackupUtils.appIsEligibleForBackup(
-                            app.applicationInfo, mPackageManager)) {
+                            && AppBackupUtils.appIsEligibleForBackup(app.applicationInfo,
+                            mUserId)) {
                         if (!foundApps.contains(app.packageName)) {
                             if (MORE_DEBUG) {
                                 Slog.i(TAG, "New full backup app " + app.packageName + " found");
@@ -939,7 +960,7 @@
             schedule = new ArrayList<>(apps.size());
             for (PackageInfo info : apps) {
                 if (AppBackupUtils.appGetsFullBackup(info) && AppBackupUtils.appIsEligibleForBackup(
-                        info.applicationInfo, mPackageManager)) {
+                        info.applicationInfo, mUserId)) {
                     schedule.add(new FullBackupEntry(info.packageName, 0));
                 }
             }
@@ -1121,17 +1142,23 @@
         }
     }
 
-    // ----- Track installation/removal of packages -----
+    /**
+     * A {@link BroadcastReceiver} tracking changes to packages and sd cards in order to update our
+     * internal bookkeeping.
+     */
     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
-            if (MORE_DEBUG) Slog.d(TAG, "Received broadcast " + intent);
+            if (MORE_DEBUG) {
+                Slog.d(TAG, "Received broadcast " + intent);
+            }
 
             String action = intent.getAction();
             boolean replacing = false;
             boolean added = false;
             boolean changed = false;
             Bundle extras = intent.getExtras();
-            String[] pkgList = null;
+            String[] packageList = null;
+
             if (Intent.ACTION_PACKAGE_ADDED.equals(action)
                     || Intent.ACTION_PACKAGE_REMOVED.equals(action)
                     || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
@@ -1139,69 +1166,70 @@
                 if (uri == null) {
                     return;
                 }
-                final String pkgName = uri.getSchemeSpecificPart();
-                if (pkgName != null) {
-                    pkgList = new String[]{pkgName};
-                }
-                changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
 
-                // At package-changed we only care about looking at new transport states
+                String packageName = uri.getSchemeSpecificPart();
+                if (packageName != null) {
+                    packageList = new String[]{packageName};
+                }
+
+                changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
                 if (changed) {
-                    final String[] components =
+                    // Look at new transport states for package changed events.
+                    String[] components =
                             intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
 
                     if (MORE_DEBUG) {
-                        Slog.i(TAG, "Package " + pkgName + " changed; rechecking");
+                        Slog.i(TAG, "Package " + packageName + " changed");
                         for (int i = 0; i < components.length; i++) {
                             Slog.i(TAG, "   * " + components[i]);
                         }
                     }
 
                     mBackupHandler.post(
-                            () -> mTransportManager.onPackageChanged(pkgName, components));
-                    return; // nothing more to do in the PACKAGE_CHANGED case
+                            () -> mTransportManager.onPackageChanged(packageName, components));
+                    return;
                 }
 
                 added = Intent.ACTION_PACKAGE_ADDED.equals(action);
                 replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
                 added = true;
-                pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                packageList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
                 added = false;
-                pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                packageList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             }
 
-            if (pkgList == null || pkgList.length == 0) {
+            if (packageList == null || packageList.length == 0) {
                 return;
             }
 
-            final int uid = extras.getInt(Intent.EXTRA_UID);
+            int uid = extras.getInt(Intent.EXTRA_UID);
             if (added) {
                 synchronized (mBackupParticipants) {
                     if (replacing) {
-                        // This is the package-replaced case; we just remove the entry
-                        // under the old uid and fall through to re-add.  If an app
-                        // just added key/value backup participation, this picks it up
-                        // as a known participant.
-                        removePackageParticipantsLocked(pkgList, uid);
+                        // Remove the entry under the old uid and fall through to re-add. If an app
+                        // just opted into key/value backup, add it as a known participant.
+                        removePackageParticipantsLocked(packageList, uid);
                     }
-                    addPackageParticipantsLocked(pkgList);
+                    addPackageParticipantsLocked(packageList);
                 }
-                // If they're full-backup candidates, add them there instead
-                final long now = System.currentTimeMillis();
-                for (final String packageName : pkgList) {
+
+                long now = System.currentTimeMillis();
+                for (String packageName : packageList) {
                     try {
-                        PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
+                        PackageInfo app =
+                                mPackageManager.getPackageInfoAsUser(
+                                        packageName, /* flags */ 0, mUserId);
                         if (AppBackupUtils.appGetsFullBackup(app)
-                                && AppBackupUtils.appIsEligibleForBackup(
-                                app.applicationInfo, mPackageManager)) {
+                                && AppBackupUtils.appIsEligibleForBackup(app.applicationInfo,
+                                mUserId)) {
                             enqueueFullBackup(packageName, now);
                             scheduleNextFullBackupJob(0);
                         } else {
-                            // The app might have just transitioned out of full-data into
-                            // doing key/value backups, or might have just disabled backups
-                            // entirely.  Make sure it is no longer in the full-data queue.
+                            // The app might have just transitioned out of full-data into doing
+                            // key/value backups, or might have just disabled backups entirely. Make
+                            // sure it is no longer in the full-data queue.
                             synchronized (mQueueLock) {
                                 dequeueFullBackupLocked(packageName);
                             }
@@ -1210,32 +1238,28 @@
 
                         mBackupHandler.post(
                                 () -> mTransportManager.onPackageAdded(packageName));
-
                     } catch (NameNotFoundException e) {
-                        // doesn't really exist; ignore it
                         if (DEBUG) {
                             Slog.w(TAG, "Can't resolve new app " + packageName);
                         }
                     }
                 }
 
-                // Whenever a package is added or updated we need to update
-                // the package metadata bookkeeping.
+                // Whenever a package is added or updated we need to update the package metadata
+                // bookkeeping.
                 dataChangedImpl(PACKAGE_MANAGER_SENTINEL);
             } else {
-                if (replacing) {
-                    // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
-                } else {
-                    // Outright removal.  In the full-data case, the app will be dropped
-                    // from the queue when its (now obsolete) name comes up again for
-                    // backup.
+                if (!replacing) {
+                    // Outright removal. In the full-data case, the app will be dropped from the
+                    // queue when its (now obsolete) name comes up again for backup.
                     synchronized (mBackupParticipants) {
-                        removePackageParticipantsLocked(pkgList, uid);
+                        removePackageParticipantsLocked(packageList, uid);
                     }
                 }
-                for (final String pkgName : pkgList) {
+
+                for (String packageName : packageList) {
                     mBackupHandler.post(
-                            () -> mTransportManager.onPackageRemoved(pkgName));
+                            () -> mTransportManager.onPackageRemoved(packageName));
                 }
             }
         }
@@ -1326,7 +1350,7 @@
     private List<PackageInfo> allAgentPackages() {
         // !!! TODO: cache this and regenerate only when necessary
         int flags = PackageManager.GET_SIGNING_CERTIFICATES;
-        List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
+        List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(flags, mUserId);
         int numPackages = packages.size();
         for (int a = numPackages - 1; a >= 0; a--) {
             PackageInfo pkg = packages.get(a);
@@ -1340,8 +1364,8 @@
                     // we will need the shared library path, so look that up and store it here.
                     // This is used implicitly when we pass the PackageInfo object off to
                     // the Activity Manager to launch the app for backup/restore purposes.
-                    app = mPackageManager.getApplicationInfo(pkg.packageName,
-                            PackageManager.GET_SHARED_LIBRARY_FILES);
+                    app = mPackageManager.getApplicationInfoAsUser(pkg.packageName,
+                            PackageManager.GET_SHARED_LIBRARY_FILES, mUserId);
                     pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
                     pkg.applicationInfo.sharedLibraryInfos = app.sharedLibraryInfos;
                 }
@@ -1366,7 +1390,7 @@
             notification.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES
                     | Intent.FLAG_RECEIVER_FOREGROUND);
             notification.putExtra(BACKUP_FINISHED_PACKAGE_EXTRA, packageName);
-            mContext.sendBroadcastAsUser(notification, UserHandle.OWNER);
+            mContext.sendBroadcastAsUser(notification, UserHandle.of(mUserId));
         }
 
         mProcessedPackagesJournal.addPackage(packageName);
@@ -1409,8 +1433,7 @@
             mConnecting = true;
             mConnectedAgent = null;
             try {
-                if (mActivityManager.bindBackupAgent(app.packageName, mode,
-                        UserHandle.USER_OWNER)) {
+                if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId)) {
                     Slog.d(TAG, "awaiting agent for " + app);
 
                     // success; wait for the agent to arrive
@@ -1441,11 +1464,7 @@
             }
         }
         if (agent == null) {
-            try {
-                mActivityManager.clearPendingBackup();
-            } catch (RemoteException e) {
-                // can't happen - ActivityManager is local
-            }
+            mActivityManagerInternal.clearPendingBackup(mUserId);
         }
         return agent;
     }
@@ -1469,7 +1488,7 @@
     public void clearApplicationDataSynchronous(String packageName, boolean keepSystemState) {
         // Don't wipe packages marked allowClearUserData=false
         try {
-            PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
+            PackageInfo info = mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId);
             if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
                 if (MORE_DEBUG) {
                     Slog.i(TAG, "allowClearUserData=false so not wiping "
@@ -1488,7 +1507,7 @@
             mClearingData = true;
             try {
                 mActivityManager.clearApplicationUserData(
-                        packageName, keepSystemState, observer, 0);
+                        packageName, keepSystemState, observer, mUserId);
             } catch (RemoteException e) {
                 // can't happen because the activity manager is in this process
             }
@@ -1553,11 +1572,16 @@
             throw new IllegalArgumentException("No packages are provided for backup");
         }
 
-        if (!mEnabled || !mProvisioned) {
-            Slog.i(TAG, "Backup requested but e=" + mEnabled + " p=" + mProvisioned);
+        if (!mEnabled || !mSetupComplete) {
+            Slog.i(
+                    TAG,
+                    "Backup requested but enabled="
+                            + mEnabled
+                            + " setupComplete="
+                            + mSetupComplete);
             BackupObserverUtils.sendBackupFinished(observer,
                     BackupManager.ERROR_BACKUP_NOT_ALLOWED);
-            final int logTag = mProvisioned
+            final int logTag = mSetupComplete
                     ? BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED
                     : BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED;
             monitor = BackupManagerMonitorUtils.monitorEvent(monitor, logTag, null,
@@ -1592,10 +1616,9 @@
                 continue;
             }
             try {
-                PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
-                        PackageManager.GET_SIGNING_CERTIFICATES);
-                if (!AppBackupUtils.appIsEligibleForBackup(packageInfo.applicationInfo,
-                        mPackageManager)) {
+                PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageName,
+                        PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
+                if (!AppBackupUtils.appIsEligibleForBackup(packageInfo.applicationInfo, mUserId)) {
                     BackupObserverUtils.sendBackupOnPackageResult(observer, packageName,
                             BackupManager.ERROR_BACKUP_NOT_ALLOWED);
                     continue;
@@ -1650,8 +1673,8 @@
             }
             // We don't want the backup jobs to kick in any time soon.
             // Reschedules them to run in the distant future.
-            KeyValueBackupJob.schedule(mContext, BUSY_BACKOFF_MIN_MILLIS, mConstants);
-            FullBackupJob.schedule(mContext, 2 * BUSY_BACKOFF_MIN_MILLIS, mConstants);
+            KeyValueBackupJob.schedule(mUserId, mContext, BUSY_BACKOFF_MIN_MILLIS, mConstants);
+            FullBackupJob.schedule(mUserId, mContext, 2 * BUSY_BACKOFF_MIN_MILLIS, mConstants);
         } finally {
             Binder.restoreCallingIdentity(oldToken);
         }
@@ -1886,7 +1909,7 @@
                 Runnable r = new Runnable() {
                     @Override
                     public void run() {
-                        FullBackupJob.schedule(mContext, latency, mConstants);
+                        FullBackupJob.schedule(mUserId, mContext, latency, mConstants);
                     }
                 };
                 mBackupHandler.postDelayed(r, 2500);
@@ -1992,13 +2015,13 @@
         FullBackupEntry entry = null;
         long latency = fullBackupInterval;
 
-        if (!mEnabled || !mProvisioned) {
+        if (!mEnabled || !mSetupComplete) {
             // Backups are globally disabled, so don't proceed.  We also don't reschedule
             // the job driving automatic backups; that job will be scheduled again when
             // the user enables backup.
             if (MORE_DEBUG) {
-                Slog.i(TAG, "beginFullBackup but e=" + mEnabled
-                        + " p=" + mProvisioned + "; ignoring");
+                Slog.i(TAG, "beginFullBackup but enabled=" + mEnabled
+                        + " setupComplete=" + mSetupComplete + "; ignoring");
             }
             return false;
         }
@@ -2009,7 +2032,7 @@
                 mPowerManager.getPowerSaveState(ServiceType.FULL_BACKUP);
         if (result.batterySaverEnabled) {
             if (DEBUG) Slog.i(TAG, "Deferring scheduled full backups in battery saver mode");
-            FullBackupJob.schedule(mContext, keyValueBackupInterval, mConstants);
+            FullBackupJob.schedule(mUserId, mContext, keyValueBackupInterval, mConstants);
             return false;
         }
 
@@ -2071,7 +2094,8 @@
                     }
 
                     try {
-                        PackageInfo appInfo = mPackageManager.getPackageInfo(entry.packageName, 0);
+                        PackageInfo appInfo = mPackageManager.getPackageInfoAsUser(
+                                entry.packageName, 0, mUserId);
                         if (!AppBackupUtils.appGetsFullBackup(appInfo)) {
                             // The head app isn't supposed to get full-data backups [any more];
                             // so we cull it and force a loop around to consider the new head
@@ -2087,7 +2111,8 @@
 
                         final int privFlags = appInfo.applicationInfo.privateFlags;
                         headBusy = (privFlags & PRIVATE_FLAG_BACKUP_IN_FOREGROUND) == 0
-                                && mActivityManager.isAppForeground(appInfo.applicationInfo.uid);
+                                && mActivityManagerInternal.isAppForeground(
+                                        appInfo.applicationInfo.uid);
 
                         if (headBusy) {
                             final long nextEligible = System.currentTimeMillis()
@@ -2110,8 +2135,6 @@
                         // queue entirely and move on, but if there's nothing else in the queue
                         // we should bail entirely.  headBusy cannot have been set to true yet.
                         runBackup = (mFullBackupQueue.size() > 1);
-                    } catch (RemoteException e) {
-                        // Cannot happen; the Activity Manager is in the same process
                     }
                 }
             } while (headBusy);
@@ -2124,7 +2147,7 @@
                 mBackupHandler.post(new Runnable() {
                     @Override
                     public void run() {
-                        FullBackupJob.schedule(mContext, deferTime, mConstants);
+                        FullBackupJob.schedule(mUserId, mContext, deferTime, mConstants);
                     }
                 });
                 return false;
@@ -2183,11 +2206,10 @@
     /** Used by both incremental and full restore to restore widget data. */
     public void restoreWidgetData(String packageName, byte[] widgetData) {
         // Apply the restored widget state and generate the ID update for the app
-        // TODO: http://b/22388012
         if (MORE_DEBUG) {
             Slog.i(TAG, "Incorporating restored widget data");
         }
-        AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, UserHandle.USER_SYSTEM);
+        AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, mUserId);
     }
 
     // *****************************
@@ -2228,7 +2250,7 @@
         }
 
         // ...and schedule a backup pass if necessary
-        KeyValueBackupJob.schedule(mContext, mConstants);
+        KeyValueBackupJob.schedule(mUserId, mContext, mConstants);
     }
 
     // Note: packageName is currently unused, but may be in the future
@@ -2266,20 +2288,6 @@
 
     /** Sent from an app's backup agent to let the service know that there's new data to backup. */
     public void dataChanged(final String packageName) {
-        final int callingUserHandle = UserHandle.getCallingUserId();
-        if (callingUserHandle != UserHandle.USER_SYSTEM) {
-            // TODO: http://b/22388012
-            // App is running under a non-owner user profile.  For now, we do not back
-            // up data from secondary user profiles.
-            // TODO: backups for all user profiles although don't add backup for profiles
-            // without adding admin control in DevicePolicyManager.
-            if (MORE_DEBUG) {
-                Slog.v(TAG, "dataChanged(" + packageName + ") ignored because it's user "
-                        + callingUserHandle);
-            }
-            return;
-        }
-
         final HashSet<String> targets = dataChangedTargets(packageName);
         if (targets == null) {
             Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
@@ -2316,8 +2324,8 @@
         if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
         PackageInfo info;
         try {
-            info = mPackageManager.getPackageInfo(packageName,
-                    PackageManager.GET_SIGNING_CERTIFICATES);
+            info = mPackageManager.getPackageInfoAsUser(packageName,
+                    PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
         } catch (NameNotFoundException e) {
             Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
             return;
@@ -2378,7 +2386,8 @@
                     mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP);
             if (result.batterySaverEnabled) {
                 if (DEBUG) Slog.v(TAG, "Not running backup while in battery save mode");
-                KeyValueBackupJob.schedule(mContext, mConstants);   // try again in several hours
+                // Try again in several hours.
+                KeyValueBackupJob.schedule(mUserId, mContext, mConstants);
             } else {
                 if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass");
                 synchronized (mQueueLock) {
@@ -2391,7 +2400,7 @@
                     }
 
                     // ...and cancel any pending scheduled job, because we've just superseded it
-                    KeyValueBackupJob.cancel(mContext);
+                    KeyValueBackupJob.cancel(mUserId, mContext);
                 }
             }
         } finally {
@@ -2399,12 +2408,6 @@
         }
     }
 
-    /** Returns {@code true} if the system user has gone through SUW. */
-    public boolean deviceIsProvisioned() {
-        final ContentResolver resolver = mContext.getContentResolver();
-        return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0);
-    }
-
     /**
      * Used by 'adb backup' to run a backup pass for packages supplied via the command line, writing
      * the resulting data stream to the supplied {@code fd}. This method is synchronous and does not
@@ -2437,8 +2440,7 @@
 
         long oldId = Binder.clearCallingIdentity();
         try {
-            // Doesn't make sense to do a full backup prior to setup
-            if (!deviceIsProvisioned()) {
+            if (!mSetupComplete) {
                 Slog.i(TAG, "Backup not supported before setup");
                 return;
             }
@@ -2564,9 +2566,7 @@
         long oldId = Binder.clearCallingIdentity();
 
         try {
-            // Check whether the device has been provisioned -- we don't handle
-            // full restores prior to completing the setup process.
-            if (!deviceIsProvisioned()) {
+            if (!mSetupComplete) {
                 Slog.i(TAG, "Full restore not permitted before setup");
                 return;
             }
@@ -2721,20 +2721,20 @@
             }
 
             synchronized (mQueueLock) {
-                if (enable && !wasEnabled && mProvisioned) {
+                if (enable && !wasEnabled && mSetupComplete) {
                     // if we've just been enabled, start scheduling backup passes
-                    KeyValueBackupJob.schedule(mContext, mConstants);
+                    KeyValueBackupJob.schedule(mUserId, mContext, mConstants);
                     scheduleNextFullBackupJob(0);
                 } else if (!enable) {
                     // No longer enabled, so stop running backups
                     if (MORE_DEBUG) Slog.i(TAG, "Opting out of backup");
 
-                    KeyValueBackupJob.cancel(mContext);
+                    KeyValueBackupJob.cancel(mUserId, mContext);
 
                     // This also constitutes an opt-out, so we wipe any data for
                     // this device from the backend.  We start that process with
                     // an alarm in order to guarantee wakelock states.
-                    if (wasEnabled && mProvisioned) {
+                    if (wasEnabled && mSetupComplete) {
                         // NOTE: we currently flush every registered transport, not just
                         // the currently-active one.
                         List<String> transportNames = new ArrayList<>();
@@ -2782,8 +2782,8 @@
         final long oldId = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                Settings.Secure.putInt(mContext.getContentResolver(),
-                        Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
+                Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0, mUserId);
                 mAutoRestore = doAutoRestore;
             }
         } finally {
@@ -2904,7 +2904,7 @@
         try {
             int transportUid =
                     mContext.getPackageManager()
-                            .getPackageUid(transportComponent.getPackageName(), 0);
+                            .getPackageUidAsUser(transportComponent.getPackageName(), 0, mUserId);
             if (callingUid != transportUid) {
                 throw new SecurityException("Only the transport can change its description");
             }
@@ -2996,8 +2996,8 @@
 
     private void updateStateForTransport(String newTransportName) {
         // Publish the name change
-        Settings.Secure.putString(mContext.getContentResolver(),
-                Settings.Secure.BACKUP_TRANSPORT, newTransportName);
+        Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                Settings.Secure.BACKUP_TRANSPORT, newTransportName, mUserId);
 
         // And update our current-dataset bookkeeping
         String callerLogString = "BMS.updateStateForTransport()";
@@ -3112,8 +3112,7 @@
         synchronized (mAgentConnectLock) {
             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
                 Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder);
-                IBackupAgent agent = IBackupAgent.Stub.asInterface(agentBinder);
-                mConnectedAgent = agent;
+                mConnectedAgent = IBackupAgent.Stub.asInterface(agentBinder);
                 mConnecting = false;
             } else {
                 Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
@@ -3244,7 +3243,7 @@
             if (packageName != null) {
                 PackageInfo app = null;
                 try {
-                    app = mPackageManager.getPackageInfo(packageName, 0);
+                    app = mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId);
                 } catch (NameNotFoundException nnf) {
                     Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
                     throw new IllegalArgumentException("Package " + packageName + " not found");
@@ -3348,7 +3347,7 @@
                     mTransportManager.getCurrentTransportClient(callerLogString);
             boolean eligible =
                     AppBackupUtils.appIsRunningAndEligibleForBackupWithTransport(
-                            transportClient, packageName, mPackageManager);
+                            transportClient, packageName, mPackageManager, mUserId);
             if (transportClient != null) {
                 mTransportManager.disposeOfTransportClient(transportClient, callerLogString);
             }
@@ -3372,7 +3371,7 @@
             for (String packageName : packages) {
                 if (AppBackupUtils
                         .appIsRunningAndEligibleForBackupWithTransport(
-                                transportClient, packageName, mPackageManager)) {
+                                transportClient, packageName, mPackageManager, mUserId)) {
                     eligibleApps.add(packageName);
                 }
             }
@@ -3431,14 +3430,14 @@
     private void dumpInternal(PrintWriter pw) {
         synchronized (mQueueLock) {
             pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
-                    + " / " + (!mProvisioned ? "not " : "") + "provisioned / "
+                    + " / " + (!mSetupComplete ? "not " : "") + "setup complete / "
                     + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init");
             pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled"));
             if (mBackupRunning) pw.println("Backup currently running");
             pw.println(isBackupOperationInProgress() ? "Backup in progress" : "No backups running");
             pw.println("Last backup pass started: " + mLastBackupPass
                     + " (now = " + System.currentTimeMillis() + ')');
-            pw.println("  next scheduled: " + KeyValueBackupJob.nextScheduled());
+            pw.println("  next scheduled: " + KeyValueBackupJob.nextScheduled(mUserId));
 
             pw.println("Transport whitelist:");
             for (ComponentName transport : mTransportManager.getTransportWhitelist()) {
diff --git a/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java b/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java
index bace1aa..d13f711 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/AppMetadataBackupWriter.java
@@ -7,6 +7,7 @@
 import static com.android.server.backup.UserBackupManagerService.BACKUP_WIDGET_METADATA_TOKEN;
 
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.backup.FullBackup;
 import android.app.backup.FullBackupDataOutput;
 import android.content.pm.PackageInfo;
@@ -15,7 +16,6 @@
 import android.content.pm.SigningInfo;
 import android.os.Build;
 import android.os.Environment;
-import android.os.UserHandle;
 import android.util.Log;
 import android.util.StringBuilderPrinter;
 
@@ -254,12 +254,11 @@
      * for 'adb backup'.
      */
     // TODO(b/113807190): Investigate and potentially remove.
-    public void backupObb(PackageInfo packageInfo) {
+    public void backupObb(@UserIdInt int userId, PackageInfo packageInfo) {
         // TODO: migrate this to SharedStorageBackup, since AID_SYSTEM doesn't have access to
         // external storage.
-        // TODO: http://b/22388012
         Environment.UserEnvironment userEnv =
-                new Environment.UserEnvironment(UserHandle.USER_SYSTEM);
+                new Environment.UserEnvironment(userId);
         File obbDir = userEnv.buildExternalStorageAppObbDirs(packageInfo.packageName)[0];
         if (obbDir != null) {
             if (MORE_DEBUG) {
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
index 45ca2af..7ea1892 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
@@ -34,14 +34,12 @@
 import android.content.pm.PackageManager;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.util.Slog;
 
 import com.android.internal.util.Preconditions;
 import com.android.server.AppWidgetBackupBridge;
 import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
-import com.android.server.backup.UserBackupManagerFiles;
 import com.android.server.backup.UserBackupManagerService;
 import com.android.server.backup.remote.RemoteCall;
 import com.android.server.backup.utils.FullBackupUtils;
@@ -56,12 +54,12 @@
  */
 public class FullBackupEngine {
     private UserBackupManagerService backupManagerService;
-    OutputStream mOutput;
-    FullBackupPreflight mPreflightHook;
-    BackupRestoreTask mTimeoutMonitor;
-    IBackupAgent mAgent;
-    boolean mIncludeApks;
-    PackageInfo mPkg;
+    private OutputStream mOutput;
+    private FullBackupPreflight mPreflightHook;
+    private BackupRestoreTask mTimeoutMonitor;
+    private IBackupAgent mAgent;
+    private boolean mIncludeApks;
+    private PackageInfo mPkg;
     private final long mQuota;
     private final int mOpToken;
     private final int mTransportFlags;
@@ -78,21 +76,21 @@
         private final File mFilesDir;
 
         FullBackupRunner(
+                UserBackupManagerService userBackupManagerService,
                 PackageInfo packageInfo,
                 IBackupAgent agent,
                 ParcelFileDescriptor pipe,
                 int token,
                 boolean includeApks)
                 throws IOException {
-            // TODO: http://b/22388012
-            mUserId = UserHandle.USER_SYSTEM;
+            mUserId = userBackupManagerService.getUserId();
             mPackageManager = backupManagerService.getPackageManager();
             mPackage = packageInfo;
             mAgent = agent;
             mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
             mToken = token;
             mIncludeApks = includeApks;
-            mFilesDir = UserBackupManagerFiles.getFullBackupEngineFilesDir(mUserId);
+            mFilesDir = userBackupManagerService.getDataDir();
         }
 
         @Override
@@ -132,7 +130,7 @@
                 // TODO(b/113807190): Look into removing, only used for 'adb backup'.
                 if (writeApk) {
                     appMetadataBackupWriter.backupApk(mPackage);
-                    appMetadataBackupWriter.backupObb(mPackage);
+                    appMetadataBackupWriter.backupObb(mUserId, mPackage);
                 }
 
                 if (DEBUG) {
@@ -155,9 +153,12 @@
                         backupManagerService.getBackupManagerBinder(),
                         mTransportFlags);
             } catch (IOException e) {
-                Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
+                Slog.e(TAG, "Error running full backup for " + mPackage.packageName, e);
             } catch (RemoteException e) {
-                Slog.e(TAG, "Remote agent vanished during full backup of " + mPackage.packageName);
+                Slog.e(
+                        TAG,
+                        "Remote agent vanished during full backup of " + mPackage.packageName,
+                        e);
             } finally {
                 try {
                     mPipe.close();
@@ -233,7 +234,13 @@
                 pipes = ParcelFileDescriptor.createPipe();
 
                 FullBackupRunner runner =
-                        new FullBackupRunner(mPkg, mAgent, pipes[1], mOpToken, mIncludeApks);
+                        new FullBackupRunner(
+                                backupManagerService,
+                                mPkg,
+                                mAgent,
+                                pipes[1],
+                                mOpToken,
+                                mIncludeApks);
                 pipes[1].close(); // the runner has dup'd it
                 pipes[1] = null;
                 Thread t = new Thread(runner, "app-data-runner");
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index 43a80c4..0a7159b 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -66,24 +66,22 @@
  */
 public class PerformAdbBackupTask extends FullBackupTask implements BackupRestoreTask {
 
-    private UserBackupManagerService backupManagerService;
-    FullBackupEngine mBackupEngine;
-    final AtomicBoolean mLatch;
+    private final UserBackupManagerService mUserBackupManagerService;
+    private final AtomicBoolean mLatch;
 
-    ParcelFileDescriptor mOutputFile;
-    DeflaterOutputStream mDeflater;
-    boolean mIncludeApks;
-    boolean mIncludeObbs;
-    boolean mIncludeShared;
-    boolean mDoWidgets;
-    boolean mAllApps;
-    boolean mIncludeSystem;
-    boolean mCompress;
-    boolean mKeyValue;
-    ArrayList<String> mPackages;
-    PackageInfo mCurrentTarget;
-    String mCurrentPassword;
-    String mEncryptPassword;
+    private final ParcelFileDescriptor mOutputFile;
+    private final boolean mIncludeApks;
+    private final boolean mIncludeObbs;
+    private final boolean mIncludeShared;
+    private final boolean mDoWidgets;
+    private final boolean mAllApps;
+    private final boolean mIncludeSystem;
+    private final boolean mCompress;
+    private final boolean mKeyValue;
+    private final ArrayList<String> mPackages;
+    private PackageInfo mCurrentTarget;
+    private final String mCurrentPassword;
+    private final String mEncryptPassword;
     private final int mCurrentOpToken;
 
     public PerformAdbBackupTask(UserBackupManagerService backupManagerService,
@@ -92,7 +90,7 @@
             String curPassword, String encryptPassword, boolean doAllApps, boolean doSystem,
             boolean doCompress, boolean doKeyValue, String[] packages, AtomicBoolean latch) {
         super(observer);
-        this.backupManagerService = backupManagerService;
+        mUserBackupManagerService = backupManagerService;
         mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
         mLatch = latch;
 
@@ -104,7 +102,7 @@
         mAllApps = doAllApps;
         mIncludeSystem = doSystem;
         mPackages = (packages == null)
-                ? new ArrayList<String>()
+                ? new ArrayList<>()
                 : new ArrayList<>(Arrays.asList(packages));
         mCurrentPassword = curPassword;
         // when backing up, if there is a current backup password, we require that
@@ -123,11 +121,11 @@
         mKeyValue = doKeyValue;
     }
 
-    void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) {
+    private void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) {
         for (String pkgName : pkgNames) {
             if (!set.containsKey(pkgName)) {
                 try {
-                    PackageInfo info = backupManagerService.getPackageManager().getPackageInfo(
+                    PackageInfo info = mUserBackupManagerService.getPackageManager().getPackageInfo(
                             pkgName,
                             PackageManager.GET_SIGNING_CERTIFICATES);
                     set.put(pkgName, info);
@@ -141,7 +139,7 @@
     private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
             OutputStream ofstream) throws Exception {
         // User key will be used to encrypt the master key.
-        byte[] newUserSalt = backupManagerService
+        byte[] newUserSalt = mUserBackupManagerService
                 .randomBytes(PasswordUtils.PBKDF2_SALT_SIZE);
         SecretKey userKey = PasswordUtils
                 .buildPasswordKey(PBKDF_CURRENT, mEncryptPassword,
@@ -150,8 +148,8 @@
 
         // the master key is random for each backup
         byte[] masterPw = new byte[256 / 8];
-        backupManagerService.getRng().nextBytes(masterPw);
-        byte[] checksumSalt = backupManagerService
+        mUserBackupManagerService.getRng().nextBytes(masterPw);
+        byte[] checksumSalt = mUserBackupManagerService
                 .randomBytes(PasswordUtils.PBKDF2_SALT_SIZE);
 
         // primary encryption of the datastream with the random key
@@ -232,11 +230,11 @@
 
         TreeMap<String, PackageInfo> packagesToBackup = new TreeMap<>();
         FullBackupObbConnection obbConnection = new FullBackupObbConnection(
-                backupManagerService);
+                mUserBackupManagerService);
         obbConnection.establish();  // we'll want this later
 
         sendStartBackup();
-        PackageManager pm = backupManagerService.getPackageManager();
+        PackageManager pm = mUserBackupManagerService.getPackageManager();
 
         // doAllApps supersedes the package set if any
         if (mAllApps) {
@@ -245,7 +243,7 @@
             for (int i = 0; i < allPackages.size(); i++) {
                 PackageInfo pkg = allPackages.get(i);
                 // Exclude system apps if we've been asked to do so
-                if (mIncludeSystem == true
+                if (mIncludeSystem
                         || ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) {
                     packagesToBackup.put(pkg.packageName, pkg);
                 }
@@ -288,7 +286,8 @@
         Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator();
         while (iter.hasNext()) {
             PackageInfo pkg = iter.next().getValue();
-            if (!AppBackupUtils.appIsEligibleForBackup(pkg.applicationInfo, pm)
+            if (!AppBackupUtils.appIsEligibleForBackup(pkg.applicationInfo,
+                    mUserBackupManagerService.getUserId())
                     || AppBackupUtils.appIsStopped(pkg.applicationInfo)) {
                 iter.remove();
                 if (DEBUG) {
@@ -316,7 +315,7 @@
             boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
 
             // Only allow encrypted backups of encrypted devices
-            if (backupManagerService.deviceIsEncrypted() && !encrypting) {
+            if (mUserBackupManagerService.deviceIsEncrypted() && !encrypting) {
                 Slog.e(TAG, "Unencrypted backup of encrypted device; aborting");
                 return;
             }
@@ -325,7 +324,7 @@
 
             // Verify that the given password matches the currently-active
             // backup password, if any
-            if (!backupManagerService.backupPasswordMatches(mCurrentPassword)) {
+            if (!mUserBackupManagerService.backupPasswordMatches(mCurrentPassword)) {
                 if (DEBUG) {
                     Slog.w(TAG, "Backup password mismatch; aborting");
                 }
@@ -390,7 +389,7 @@
             // Shared storage if requested
             if (mIncludeShared) {
                 try {
-                    pkg = backupManagerService.getPackageManager().getPackageInfo(
+                    pkg = mUserBackupManagerService.getPackageManager().getPackageInfo(
                             SHARED_BACKUP_AGENT_PACKAGE, 0);
                     backupQueue.add(pkg);
                 } catch (NameNotFoundException e) {
@@ -410,9 +409,17 @@
                         pkg.packageName.equals(
                                 SHARED_BACKUP_AGENT_PACKAGE);
 
-                mBackupEngine = new FullBackupEngine(backupManagerService, out,
-                        null, pkg, mIncludeApks, this, Long.MAX_VALUE,
-                        mCurrentOpToken, /*transportFlags=*/ 0);
+                FullBackupEngine mBackupEngine =
+                        new FullBackupEngine(
+                                mUserBackupManagerService,
+                                out,
+                                null,
+                                pkg,
+                                mIncludeApks,
+                                this,
+                                Long.MAX_VALUE,
+                                mCurrentOpToken,
+                                /*transportFlags=*/ 0);
                 sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
 
                 // Don't need to check preflight result as there is no preflight hook.
@@ -437,10 +444,10 @@
                     }
                     KeyValueAdbBackupEngine kvBackupEngine =
                             new KeyValueAdbBackupEngine(out, keyValuePackage,
-                                    backupManagerService,
-                                    backupManagerService.getPackageManager(),
-                                    backupManagerService.getBaseStateDir(),
-                                    backupManagerService.getDataDir());
+                                    mUserBackupManagerService,
+                                    mUserBackupManagerService.getPackageManager(),
+                                    mUserBackupManagerService.getBaseStateDir(),
+                                    mUserBackupManagerService.getDataDir());
                     sendOnBackupPackage(keyValuePackage.packageName);
                     kvBackupEngine.backupOnePackage();
                 }
@@ -471,7 +478,7 @@
             if (DEBUG) {
                 Slog.d(TAG, "Full backup pass complete.");
             }
-            backupManagerService.getWakelock().release();
+            mUserBackupManagerService.getWakelock().release();
         }
     }
 
@@ -493,8 +500,8 @@
             Slog.w(TAG, "adb backup cancel of " + target);
         }
         if (target != null) {
-            backupManagerService.tearDownAgentAndKill(mCurrentTarget.applicationInfo);
+            mUserBackupManagerService.tearDownAgentAndKill(mCurrentTarget.applicationInfo);
         }
-        backupManagerService.removeOperation(mCurrentOpToken);
+        mUserBackupManagerService.removeOperation(mCurrentOpToken);
     }
 }
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index 5b449c5..86e679f 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -143,6 +143,7 @@
     private final int mBackupRunnerOpToken;
     private final OnTaskFinishedListener mListener;
     private final TransportClient mTransportClient;
+    private final int mUserId;
 
     // This is true when a backup operation for some package is in progress.
     private volatile boolean mIsDoingBackup;
@@ -173,6 +174,7 @@
         mAgentTimeoutParameters = Preconditions.checkNotNull(
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
+        mUserId = backupManagerService.getUserId();
 
         if (backupManagerService.isBackupOperationInProgress()) {
             if (DEBUG) {
@@ -187,9 +189,10 @@
         for (String pkg : whichPackages) {
             try {
                 PackageManager pm = backupManagerService.getPackageManager();
-                PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNING_CERTIFICATES);
+                PackageInfo info = pm.getPackageInfoAsUser(pkg,
+                        PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
                 mCurrentPackage = info;
-                if (!AppBackupUtils.appIsEligibleForBackup(info.applicationInfo, pm)) {
+                if (!AppBackupUtils.appIsEligibleForBackup(info.applicationInfo, mUserId)) {
                     // Cull any packages that have indicated that backups are not permitted,
                     // that run as system-domain uids but do not define their own backup agents,
                     // as well as any explicit mention of the 'special' shared-storage agent
@@ -317,16 +320,16 @@
         int backupRunStatus = BackupManager.SUCCESS;
 
         try {
-            if (!backupManagerService.isEnabled() || !backupManagerService.isProvisioned()) {
+            if (!backupManagerService.isEnabled() || !backupManagerService.isSetupComplete()) {
                 // Backups are globally disabled, so don't proceed.
                 if (DEBUG) {
                     Slog.i(TAG, "full backup requested but enabled=" + backupManagerService
                             .isEnabled()
-                            + " provisioned=" + backupManagerService.isProvisioned()
+                            + " setupComplete=" + backupManagerService.isSetupComplete()
                             + "; ignoring");
                 }
                 int monitoringEvent;
-                if (backupManagerService.isProvisioned()) {
+                if (backupManagerService.isSetupComplete()) {
                     monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED;
                 } else {
                     monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED;
@@ -633,7 +636,7 @@
             unregisterTask();
 
             if (mJob != null) {
-                mJob.finishBackupPass();
+                mJob.finishBackupPass(mUserId);
             }
 
             synchronized (backupManagerService.getQueueLock()) {
diff --git a/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java b/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java
deleted file mode 100644
index 7e2ac79..0000000
--- a/services/backup/java/com/android/server/backup/internal/ProvisionedObserver.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.backup.internal;
-
-import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
-import static com.android.server.backup.BackupManagerService.TAG;
-
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.util.Slog;
-
-import com.android.server.backup.KeyValueBackupJob;
-import com.android.server.backup.UserBackupManagerService;
-
-public class ProvisionedObserver extends ContentObserver {
-
-    private UserBackupManagerService backupManagerService;
-
-    public ProvisionedObserver(
-            UserBackupManagerService backupManagerService, Handler handler) {
-        super(handler);
-        this.backupManagerService = backupManagerService;
-    }
-
-    public void onChange(boolean selfChange) {
-        final boolean wasProvisioned = backupManagerService.isProvisioned();
-        final boolean isProvisioned = backupManagerService.deviceIsProvisioned();
-        // latch: never unprovision
-        backupManagerService.setProvisioned(wasProvisioned || isProvisioned);
-        if (MORE_DEBUG) {
-            Slog.d(TAG, "Provisioning change: was=" + wasProvisioned
-                    + " is=" + isProvisioned + " now=" + backupManagerService.isProvisioned());
-        }
-
-        synchronized (backupManagerService.getQueueLock()) {
-            if (backupManagerService.isProvisioned() && !wasProvisioned
-                    && backupManagerService.isEnabled()) {
-                // we're now good to go, so start the backup alarms
-                if (MORE_DEBUG) {
-                    Slog.d(TAG, "Now provisioned, so starting backups");
-                }
-                KeyValueBackupJob.schedule(backupManagerService.getContext(),
-                        backupManagerService.getConstants());
-                backupManagerService.scheduleNextFullBackupJob(0);
-            }
-        }
-    }
-}
diff --git a/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java b/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java
index 2a5d913..d37b106 100644
--- a/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java
+++ b/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java
@@ -26,61 +26,84 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Handler;
 import android.os.Message;
 import android.util.Slog;
 
 import com.android.server.backup.UserBackupManagerService;
 
+/**
+ * A {@link BroadcastReceiver} for the action {@link UserBackupManagerService#RUN_BACKUP_ACTION}
+ * that runs an immediate backup operation if eligible.
+ */
 public class RunBackupReceiver extends BroadcastReceiver {
+    private final UserBackupManagerService mUserBackupManagerService;
 
-    private UserBackupManagerService backupManagerService;
-
-    public RunBackupReceiver(UserBackupManagerService backupManagerService) {
-        this.backupManagerService = backupManagerService;
+    public RunBackupReceiver(UserBackupManagerService userBackupManagerService) {
+        mUserBackupManagerService = userBackupManagerService;
     }
 
+    /**
+     * Run a backup pass if we're eligible. We're eligible if the following conditions are met:
+     *
+     * <ul>
+     *   <li>No transports are pending initialization (otherwise we kick off an initialization
+     *       operation instead).
+     *   <li>Backup is enabled for the user.
+     *   <li>The user has completed setup.
+     *   <li>No backup operation is currently running for the user.
+     * </ul>
+     */
     public void onReceive(Context context, Intent intent) {
-        if (RUN_BACKUP_ACTION.equals(intent.getAction())) {
-            synchronized (backupManagerService.getQueueLock()) {
-                if (backupManagerService.getPendingInits().size() > 0) {
-                    // If there are pending init operations, we process those
-                    // and then settle into the usual periodic backup schedule.
-                    if (MORE_DEBUG) {
-                        Slog.v(TAG, "Init pending at scheduled backup");
-                    }
-                    try {
-                        backupManagerService.getAlarmManager().cancel(
-                                backupManagerService.getRunInitIntent());
-                        backupManagerService.getRunInitIntent().send();
-                    } catch (PendingIntent.CanceledException ce) {
-                        Slog.e(TAG, "Run init intent cancelled");
-                        // can't really do more than bail here
-                    }
-                } else {
-                    // Don't run backups now if we're disabled or not yet
-                    // fully set up.
-                    if (backupManagerService.isEnabled() && backupManagerService.isProvisioned()) {
-                        if (!backupManagerService.isBackupRunning()) {
-                            if (DEBUG) {
-                                Slog.v(TAG, "Running a backup pass");
-                            }
+        if (!RUN_BACKUP_ACTION.equals(intent.getAction())) {
+            return;
+        }
 
-                            // Acquire the wakelock and pass it to the backup thread.  it will
-                            // be released once backup concludes.
-                            backupManagerService.setBackupRunning(true);
-                            backupManagerService.getWakelock().acquire();
-
-                            Message msg = backupManagerService.getBackupHandler().obtainMessage(
-                                    MSG_RUN_BACKUP);
-                            backupManagerService.getBackupHandler().sendMessage(msg);
-                        } else {
-                            Slog.i(TAG, "Backup time but one already running");
-                        }
-                    } else {
-                        Slog.w(TAG, "Backup pass but e=" + backupManagerService.isEnabled() + " p="
-                                + backupManagerService.isProvisioned());
-                    }
+        synchronized (mUserBackupManagerService.getQueueLock()) {
+            if (mUserBackupManagerService.getPendingInits().size() > 0) {
+                // If there are pending init operations, we process those and then settle into the
+                // usual periodic backup schedule.
+                if (MORE_DEBUG) {
+                    Slog.v(TAG, "Init pending at scheduled backup");
                 }
+                try {
+                    PendingIntent runInitIntent = mUserBackupManagerService.getRunInitIntent();
+                    mUserBackupManagerService.getAlarmManager().cancel(runInitIntent);
+                    runInitIntent.send();
+                } catch (PendingIntent.CanceledException ce) {
+                    Slog.w(TAG, "Run init intent cancelled");
+                }
+            } else {
+                // Don't run backups if we're disabled or not yet set up.
+                if (!mUserBackupManagerService.isEnabled()
+                        || !mUserBackupManagerService.isSetupComplete()) {
+                    Slog.w(
+                            TAG,
+                            "Backup pass but enabled="
+                                    + mUserBackupManagerService.isEnabled()
+                                    + " setupComplete="
+                                    + mUserBackupManagerService.isSetupComplete());
+                    return;
+                }
+
+                // Don't run backups if one is already running.
+                if (mUserBackupManagerService.isBackupRunning()) {
+                    Slog.i(TAG, "Backup time but one already running");
+                    return;
+                }
+
+                if (DEBUG) {
+                    Slog.v(TAG, "Running a backup pass");
+                }
+
+                // Acquire the wakelock and pass it to the backup thread. It will be released once
+                // backup concludes.
+                mUserBackupManagerService.setBackupRunning(true);
+                mUserBackupManagerService.getWakelock().acquire();
+
+                Handler backupHandler = mUserBackupManagerService.getBackupHandler();
+                Message message = backupHandler.obtainMessage(MSG_RUN_BACKUP);
+                backupHandler.sendMessage(message);
             }
         }
     }
diff --git a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
index 38870cb..97711e3 100644
--- a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
+++ b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
@@ -24,41 +24,50 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.PowerManager;
-import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.server.backup.UserBackupManagerService;
 
-public class RunInitializeReceiver extends BroadcastReceiver {
-    private final UserBackupManagerService mBackupManagerService;
+import java.util.Set;
 
-    public RunInitializeReceiver(UserBackupManagerService backupManagerService) {
-        mBackupManagerService = backupManagerService;
+/**
+ * A {@link BroadcastReceiver} for the action {@link UserBackupManagerService#RUN_INITIALIZE_ACTION}
+ * that runs an initialization operation on all pending transports.
+ */
+public class RunInitializeReceiver extends BroadcastReceiver {
+    private final UserBackupManagerService mUserBackupManagerService;
+
+    public RunInitializeReceiver(UserBackupManagerService userBackupManagerService) {
+        mUserBackupManagerService = userBackupManagerService;
     }
 
     public void onReceive(Context context, Intent intent) {
-        if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
-            synchronized (mBackupManagerService.getQueueLock()) {
-                final ArraySet<String> pendingInits = mBackupManagerService.getPendingInits();
-                if (DEBUG) {
-                    Slog.v(TAG, "Running a device init; " + pendingInits.size() + " pending");
-                }
+        if (!RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
+            return;
+        }
 
-                if (pendingInits.size() > 0) {
-                    final String[] transports =
-                            pendingInits.toArray(new String[pendingInits.size()]);
+        synchronized (mUserBackupManagerService.getQueueLock()) {
+            Set<String> pendingInits = mUserBackupManagerService.getPendingInits();
+            if (DEBUG) {
+                Slog.v(TAG, "Running a device init; " + pendingInits.size() + " pending");
+            }
 
-                    mBackupManagerService.clearPendingInits();
+            if (pendingInits.size() > 0) {
+                String[] transports = pendingInits.toArray(new String[pendingInits.size()]);
 
-                    PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
-                    wakelock.acquire();
-                    OnTaskFinishedListener listener = caller -> wakelock.release();
+                mUserBackupManagerService.clearPendingInits();
 
-                    Runnable task =
-                            new PerformInitializeTask(
-                                    mBackupManagerService, transports, null, listener);
-                    mBackupManagerService.getBackupHandler().post(task);
-                }
+                PowerManager.WakeLock wakelock = mUserBackupManagerService.getWakelock();
+                wakelock.acquire();
+                OnTaskFinishedListener listener = caller -> wakelock.release();
+
+                Runnable task =
+                        new PerformInitializeTask(
+                                mUserBackupManagerService,
+                                transports,
+                                /* observer */ null,
+                                listener);
+                mUserBackupManagerService.getBackupHandler().post(task);
             }
         }
     }
diff --git a/services/backup/java/com/android/server/backup/internal/SetupObserver.java b/services/backup/java/com/android/server/backup/internal/SetupObserver.java
new file mode 100644
index 0000000..c5e912e
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/internal/SetupObserver.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.internal;
+
+import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
+import static com.android.server.backup.BackupManagerService.TAG;
+import static com.android.server.backup.UserBackupManagerService.getSetupCompleteSettingForUser;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.server.backup.KeyValueBackupJob;
+import com.android.server.backup.UserBackupManagerService;
+
+/**
+ * A {@link ContentObserver} for changes to the setting {@link Settings.Secure#USER_SETUP_COMPLETE}
+ * for a particular user.
+ */
+public class SetupObserver extends ContentObserver {
+    private final UserBackupManagerService mUserBackupManagerService;
+    private final Context mContext;
+    private final int mUserId;
+
+    public SetupObserver(UserBackupManagerService userBackupManagerService, Handler handler) {
+        super(handler);
+        mUserBackupManagerService = userBackupManagerService;
+        mContext = userBackupManagerService.getContext();
+        mUserId = userBackupManagerService.getUserId();
+    }
+
+    /**
+     * Callback that executes when the setting {@link Settings.Secure#USER_SETUP_COMPLETE} changes
+     * for the user {@link #mUserId}. If the user is newly setup and backup is enabled, then we
+     * schedule a key value and full backup job for the user. If the user was previously setup and
+     * now the setting has changed to {@code false}, we don't reset the state as having gone through
+     * setup is a non-reversible action.
+     */
+    public void onChange(boolean selfChange) {
+        boolean previousSetupComplete = mUserBackupManagerService.isSetupComplete();
+        boolean newSetupComplete = getSetupCompleteSettingForUser(mContext, mUserId);
+
+        boolean resolvedSetupComplete = previousSetupComplete || newSetupComplete;
+        mUserBackupManagerService.setSetupComplete(resolvedSetupComplete);
+        if (MORE_DEBUG) {
+            Slog.d(
+                    TAG,
+                    "Setup complete change: was="
+                            + previousSetupComplete
+                            + " new="
+                            + newSetupComplete
+                            + " resolved="
+                            + resolvedSetupComplete);
+        }
+
+        synchronized (mUserBackupManagerService.getQueueLock()) {
+            // Start backup if the user is newly setup and backup is enabled.
+            if (resolvedSetupComplete
+                    && !previousSetupComplete
+                    && mUserBackupManagerService.isEnabled()) {
+                if (MORE_DEBUG) {
+                    Slog.d(TAG, "Setup complete so starting backups");
+                }
+                KeyValueBackupJob.schedule(mUserBackupManagerService.getUserId(), mContext,
+                        mUserBackupManagerService.getConstants());
+                mUserBackupManagerService.scheduleNextFullBackupJob(0);
+            }
+        }
+    }
+}
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 f39d795..294eb01 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -241,6 +241,7 @@
     private final boolean mUserInitiated;
     private final boolean mNonIncremental;
     private final int mCurrentOpToken;
+    private final int mUserId;
     private final File mStateDirectory;
     private final File mDataDirectory;
     private final File mBlankStateFile;
@@ -320,6 +321,7 @@
         mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
         mQueueLock = mBackupManagerService.getQueueLock();
         mBlankStateFile = new File(mStateDirectory, BLANK_STATE_FILE_NAME);
+        mUserId = backupManagerService.getUserId();
     }
 
     private void registerTask() {
@@ -480,14 +482,14 @@
         final PackageInfo packageInfo;
         try {
             packageInfo =
-                    mPackageManager.getPackageInfo(
-                            packageName, PackageManager.GET_SIGNING_CERTIFICATES);
+                    mPackageManager.getPackageInfoAsUser(
+                            packageName, PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
         } catch (PackageManager.NameNotFoundException e) {
             mReporter.onAgentUnknown(packageName);
             throw AgentException.permanent(e);
         }
         ApplicationInfo applicationInfo = packageInfo.applicationInfo;
-        if (!AppBackupUtils.appIsEligibleForBackup(applicationInfo, mPackageManager)) {
+        if (!AppBackupUtils.appIsEligibleForBackup(applicationInfo, mUserId)) {
             mReporter.onPackageNotEligibleForBackup(packageName);
             throw AgentException.permanent();
         }
@@ -685,8 +687,12 @@
                     ParcelFileDescriptor.open(
                             mNewStateFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
 
-            if (!SELinux.restorecon(mBackupDataFile)) {
-                mReporter.onRestoreconFailed(mBackupDataFile);
+            // TODO (b/120424138): Remove once the system user is migrated to use the per-user CE
+            // directory. Per-user CE directories are managed by vold.
+            if (mUserId == UserHandle.USER_SYSTEM) {
+                if (!SELinux.restorecon(mBackupDataFile)) {
+                    mReporter.onRestoreconFailed(mBackupDataFile);
+                }
             }
 
             IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.extractAgentData()");
@@ -770,8 +776,7 @@
 
     private void writeWidgetPayloadIfAppropriate(FileDescriptor fd, String pkgName)
             throws IOException {
-        // TODO: http://b/22388012
-        byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName, UserHandle.USER_SYSTEM);
+        byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName, mUserId);
         File widgetFile = new File(mStateDirectory, pkgName + "_widget");
         boolean priorStateExists = widgetFile.exists();
         if (!priorStateExists && widgetState == null) {
@@ -1003,7 +1008,7 @@
             // Use the scheduler's default.
             delay = 0;
         }
-        KeyValueBackupJob.schedule(
+        KeyValueBackupJob.schedule(mBackupManagerService.getUserId(),
                 mBackupManagerService.getContext(), delay, mBackupManagerService.getConstants());
 
         for (String packageName : mOriginalQueue) {
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index e273b32..0fa0f89 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -54,6 +54,7 @@
     private final TransportManager mTransportManager;
     private final String mTransportName;
     private final UserBackupManagerService mBackupManagerService;
+    private final int mUserId;
     @Nullable private final String mPackageName;
     public RestoreSet[] mRestoreSets = null;
     boolean mEnded = false;
@@ -67,6 +68,7 @@
         mPackageName = packageName;
         mTransportManager = backupManagerService.getTransportManager();
         mTransportName = transportName;
+        mUserId = backupManagerService.getUserId();
     }
 
     public void markTimedOut() {
@@ -304,7 +306,8 @@
 
         final PackageInfo app;
         try {
-            app = mBackupManagerService.getPackageManager().getPackageInfo(packageName, 0);
+            app = mBackupManagerService.getPackageManager().getPackageInfoAsUser(
+                    packageName, 0, mUserId);
         } catch (NameNotFoundException nnf) {
             Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
             return -1;
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index 0d26ea5..c5389fa 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -68,6 +68,8 @@
 public class FullRestoreEngine extends RestoreEngine {
 
     private final UserBackupManagerService mBackupManagerService;
+    private final int mUserId;
+
     // Task in charge of monitoring timeouts
     private final BackupRestoreTask mMonitorTask;
 
@@ -146,6 +148,7 @@
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
         mIsAdbRestore = isAdbRestore;
+        mUserId = backupManagerService.getUserId();
     }
 
     public IBackupAgent getAgent() {
@@ -227,7 +230,7 @@
                             PackageManagerInternal.class);
                     RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy(
                             mBackupManagerService.getPackageManager(), allowApks, info, signatures,
-                            pmi);
+                            pmi, mUserId);
                     mManifestSignatures.put(info.packageName, signatures);
                     mPackagePolicies.put(pkg, restorePolicy);
                     mPackageInstallers.put(pkg, info.installerPackageName);
@@ -272,7 +275,7 @@
                                         instream, mBackupManagerService.getContext(),
                                         mDeleteObserver, mManifestSignatures,
                                         mPackagePolicies, info, installerPackageName,
-                                        bytesReadListener);
+                                        bytesReadListener, mUserId);
                                 // good to go; promote to ACCEPT
                                 mPackagePolicies.put(pkg, isSuccessfullyInstalled
                                         ? RestorePolicy.ACCEPT
@@ -330,8 +333,8 @@
 
                         try {
                             mTargetApp =
-                                    mBackupManagerService.getPackageManager().getApplicationInfo(
-                                            pkg, 0);
+                                    mBackupManagerService.getPackageManager()
+                                            .getApplicationInfoAsUser(pkg, 0, mUserId);
 
                             // If we haven't sent any data to this app yet, we probably
                             // need to clear it first. Check that.
@@ -678,12 +681,13 @@
      * Returns whether the package is in the list of the packages for which clear app data should
      * be called despite the fact that they have backup agent.
      *
-     * <p>The list is read from {@link Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE}.
+     * <p>The list is read from {@link Settings.Secure#PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE}.
      */
     private boolean shouldForceClearAppDataOnFullRestore(String packageName) {
-        String packageListString = Settings.Secure.getString(
+        String packageListString = Settings.Secure.getStringForUser(
                 mBackupManagerService.getContext().getContentResolver(),
-                Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE);
+                Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE,
+                mUserId);
         if (TextUtils.isEmpty(packageListString)) {
             return false;
         }
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index f7efad6..7763d7b 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -48,7 +48,6 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.UserHandle;
 import android.util.EventLog;
 import android.util.Slog;
 
@@ -81,6 +80,7 @@
 public class PerformUnifiedRestoreTask implements BackupRestoreTask {
 
     private UserBackupManagerService backupManagerService;
+    private final int mUserId;
     private final TransportManager mTransportManager;
     // Transport client we're working with to do the restore
     private final TransportClient mTransportClient;
@@ -175,6 +175,7 @@
             @Nullable String[] filterSet,
             OnTaskFinishedListener listener) {
         this.backupManagerService = backupManagerService;
+        mUserId = backupManagerService.getUserId();
         mTransportManager = backupManagerService.getTransportManager();
         mEphemeralOpToken = backupManagerService.generateRandomIntegerToken();
         mState = UnifiedRestoreState.INITIAL;
@@ -204,7 +205,7 @@
                 // We want everything and a pony
                 List<PackageInfo> apps =
                         PackageManagerBackupAgent.getStorableApplications(
-                                backupManagerService.getPackageManager());
+                                backupManagerService.getPackageManager(), mUserId);
                 filterSet = packagesToNames(apps);
                 if (DEBUG) {
                     Slog.i(TAG, "Full restore; asking about " + filterSet.length + " apps");
@@ -221,7 +222,7 @@
             for (int i = 0; i < filterSet.length; i++) {
                 try {
                     PackageManager pm = backupManagerService.getPackageManager();
-                    PackageInfo info = pm.getPackageInfo(filterSet[i], 0);
+                    PackageInfo info = pm.getPackageInfoAsUser(filterSet[i], 0, mUserId);
                     if ("android".equals(info.packageName)) {
                         hasSystem = true;
                         continue;
@@ -231,7 +232,7 @@
                         continue;
                     }
 
-                    if (AppBackupUtils.appIsEligibleForBackup(info.applicationInfo, pm)) {
+                    if (AppBackupUtils.appIsEligibleForBackup(info.applicationInfo, mUserId)) {
                         mAcceptSet.add(info);
                     }
                 } catch (NameNotFoundException e) {
@@ -240,16 +241,16 @@
             }
             if (hasSystem) {
                 try {
-                    mAcceptSet.add(0,
-                            backupManagerService.getPackageManager().getPackageInfo("android", 0));
+                    mAcceptSet.add(0, backupManagerService.getPackageManager().getPackageInfoAsUser(
+                                    "android", 0, mUserId));
                 } catch (NameNotFoundException e) {
                     // won't happen; we know a priori that it's valid
                 }
             }
             if (hasSettings) {
                 try {
-                    mAcceptSet.add(backupManagerService.getPackageManager().getPackageInfo(
-                            SETTINGS_PACKAGE, 0));
+                    mAcceptSet.add(backupManagerService.getPackageManager().getPackageInfoAsUser(
+                            SETTINGS_PACKAGE, 0, mUserId));
                 } catch (NameNotFoundException e) {
                     // this one is always valid too
                 }
@@ -359,8 +360,7 @@
 
         // If we're starting a full-system restore, set up to begin widget ID remapping
         if (mIsSystemRestore) {
-            // TODO: http://b/22388012
-            AppWidgetBackupBridge.restoreStarting(UserHandle.USER_SYSTEM);
+            AppWidgetBackupBridge.restoreStarting(mUserId);
         }
 
         try {
@@ -508,8 +508,8 @@
             }
 
             try {
-                mCurrentPackage = backupManagerService.getPackageManager().getPackageInfo(
-                        pkgName, PackageManager.GET_SIGNING_CERTIFICATES);
+                mCurrentPackage = backupManagerService.getPackageManager().getPackageInfoAsUser(
+                        pkgName, PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
             } catch (NameNotFoundException e) {
                 // Whoops, we thought we could restore this package but it
                 // turns out not to be present.  Skip it.
@@ -1078,8 +1078,7 @@
         }
 
         // Kick off any work that may be needed regarding app widget restores
-        // TODO: http://b/22388012
-        AppWidgetBackupBridge.restoreFinished(UserHandle.USER_SYSTEM);
+        AppWidgetBackupBridge.restoreFinished(mUserId);
 
         // If this was a full-system restore, record the ancestral
         // dataset information
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClient.java b/services/backup/java/com/android/server/backup/transport/TransportClient.java
index e4dcb25..7c5a57c 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClient.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClient.java
@@ -20,6 +20,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.content.ComponentName;
 import android.content.Context;
@@ -34,7 +35,6 @@
 import android.text.format.DateFormat;
 import android.util.ArrayMap;
 import android.util.EventLog;
-import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -79,6 +79,7 @@
     @VisibleForTesting static final String TAG = "TransportClient";
     private static final int LOG_BUFFER_SIZE = 5;
 
+    private final @UserIdInt int mUserId;
     private final Context mContext;
     private final TransportStats mTransportStats;
     private final Intent mBindIntent;
@@ -106,6 +107,7 @@
     private volatile IBackupTransport mTransport;
 
     TransportClient(
+            @UserIdInt int userId,
             Context context,
             TransportStats transportStats,
             Intent bindIntent,
@@ -113,6 +115,7 @@
             String identifier,
             String caller) {
         this(
+                userId,
                 context,
                 transportStats,
                 bindIntent,
@@ -124,6 +127,7 @@
 
     @VisibleForTesting
     TransportClient(
+            @UserIdInt int userId,
             Context context,
             TransportStats transportStats,
             Intent bindIntent,
@@ -131,6 +135,7 @@
             String identifier,
             String caller,
             Handler listenerHandler) {
+        mUserId = userId;
         mContext = context;
         mTransportStats = transportStats;
         mTransportComponent = transportComponent;
@@ -213,7 +218,7 @@
                                     mBindIntent,
                                     mConnection,
                                     Context.BIND_AUTO_CREATE,
-                                    UserHandle.SYSTEM);
+                                    UserHandle.of(mUserId));
                     if (hasBound) {
                         // We don't need to set a time-out because we are guaranteed to get a call
                         // back in ServiceConnection, either an onServiceConnected() or
diff --git a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
index f4e3928..a4e9b10 100644
--- a/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
+++ b/services/backup/java/com/android/server/backup/transport/TransportClientManager.java
@@ -19,12 +19,15 @@
 import static com.android.server.backup.TransportManager.SERVICE_ACTION_TRANSPORT_HOST;
 import static com.android.server.backup.transport.TransportUtils.formatMessage;
 
+import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+
 import com.android.server.backup.TransportManager;
 import com.android.server.backup.transport.TransportUtils.Priority;
+
 import java.io.PrintWriter;
 import java.util.Map;
 import java.util.WeakHashMap;
@@ -36,13 +39,16 @@
 public class TransportClientManager {
     private static final String TAG = "TransportClientManager";
 
+    private final @UserIdInt int mUserId;
     private final Context mContext;
     private final TransportStats mTransportStats;
     private final Object mTransportClientsLock = new Object();
     private int mTransportClientsCreated = 0;
     private Map<TransportClient, String> mTransportClientsCallerMap = new WeakHashMap<>();
 
-    public TransportClientManager(Context context, TransportStats transportStats) {
+    public TransportClientManager(@UserIdInt int userId, Context context,
+            TransportStats transportStats) {
+        mUserId = userId;
         mContext = context;
         mTransportStats = transportStats;
     }
@@ -89,6 +95,7 @@
         synchronized (mTransportClientsLock) {
             TransportClient transportClient =
                     new TransportClient(
+                            mUserId,
                             mContext,
                             mTransportStats,
                             bindIntent,
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 e465c7e..2db8928 100644
--- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
@@ -18,19 +18,25 @@
 
 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
 import static com.android.server.backup.BackupManagerService.TAG;
+import static com.android.server.backup.UserBackupManagerService.PACKAGE_MANAGER_SENTINEL;
 import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
 
 import android.annotation.Nullable;
+import android.app.AppGlobals;
 import android.app.backup.BackupTransport;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
 import android.content.pm.SigningInfo;
 import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.backup.IBackupTransport;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.backup.transport.TransportClient;
@@ -39,7 +45,6 @@
  * Utility methods wrapping operations on ApplicationInfo and PackageInfo.
  */
 public class AppBackupUtils {
-
     private static final boolean DEBUG = false;
 
     /**
@@ -54,15 +59,30 @@
      *     <li>it is the special shared-storage backup package used for 'adb backup'
      * </ol>
      */
-    public static boolean appIsEligibleForBackup(ApplicationInfo app, PackageManager pm) {
+    public static boolean appIsEligibleForBackup(ApplicationInfo app, int userId) {
+        return appIsEligibleForBackup(app, AppGlobals.getPackageManager(), userId);
+    }
+
+    @VisibleForTesting
+    static boolean appIsEligibleForBackup(ApplicationInfo app,
+        IPackageManager packageManager, int userId) {
         // 1. their manifest states android:allowBackup="false"
         if ((app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
             return false;
         }
 
-        // 2. they run as a system-level uid but do not supply their own backup agent
-        if ((app.uid < Process.FIRST_APPLICATION_UID) && (app.backupAgentName == null)) {
-            return false;
+        // 2. they run as a system-level uid
+        if ((app.uid < Process.FIRST_APPLICATION_UID)) {
+            // and the backup is happening for non-system user
+            if (userId != UserHandle.USER_SYSTEM && !app.packageName.equals(
+                    PACKAGE_MANAGER_SENTINEL)) {
+                return false;
+            }
+
+            // or do not supply their own backup agent
+            if (app.backupAgentName == null) {
+                return false;
+            }
         }
 
         // 3. it is the special shared-storage backup package used for 'adb backup'
@@ -75,9 +95,7 @@
             return false;
         }
 
-        // Everything else checks out; the only remaining roadblock would be if the
-        // package were disabled
-        return !appIsDisabled(app, pm);
+        return !appIsDisabled(app, packageManager, userId);
     }
 
     /**
@@ -91,14 +109,17 @@
      * </ol>
      */
     public static boolean appIsRunningAndEligibleForBackupWithTransport(
-            @Nullable TransportClient transportClient, String packageName, PackageManager pm) {
+            @Nullable TransportClient transportClient,
+            String packageName,
+            PackageManager pm,
+            int userId) {
         try {
-            PackageInfo packageInfo = pm.getPackageInfo(packageName,
-                    PackageManager.GET_SIGNING_CERTIFICATES);
+            PackageInfo packageInfo = pm.getPackageInfoAsUser(packageName,
+                    PackageManager.GET_SIGNING_CERTIFICATES, userId);
             ApplicationInfo applicationInfo = packageInfo.applicationInfo;
-            if (!appIsEligibleForBackup(applicationInfo, pm)
+            if (!appIsEligibleForBackup(applicationInfo, userId)
                     || appIsStopped(applicationInfo)
-                    || appIsDisabled(applicationInfo, pm)) {
+                    || appIsDisabled(applicationInfo, userId)) {
                 return false;
             }
             if (transportClient != null) {
@@ -120,8 +141,22 @@
     }
 
     /** Avoid backups of 'disabled' apps. */
-    public static boolean appIsDisabled(ApplicationInfo app, PackageManager pm) {
-        switch (pm.getApplicationEnabledSetting(app.packageName)) {
+    static boolean appIsDisabled(ApplicationInfo app, int userId) {
+        return appIsDisabled(app, AppGlobals.getPackageManager(), userId);
+    }
+
+    @VisibleForTesting
+    static boolean appIsDisabled(ApplicationInfo app,
+        IPackageManager packageManager, int userId) {
+        int enabledSetting;
+        try {
+            enabledSetting = packageManager.getApplicationEnabledSetting(app.packageName, userId);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to get application enabled setting: " + e);
+            return false;
+        }
+
+        switch (enabledSetting) {
             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
diff --git a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
index df7e6d4..cce5b3b 100644
--- a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
@@ -72,7 +72,9 @@
             HashMap<String, Signature[]> manifestSignatures,
             HashMap<String, RestorePolicy> packagePolicies,
             FileMetadata info,
-            String installerPackageName, BytesReadListener bytesReadListener) {
+            String installerPackageName,
+            BytesReadListener bytesReadListener,
+            int userId) {
         boolean okay = true;
 
         if (DEBUG) {
@@ -144,8 +146,8 @@
                     uninstall = true;
                 } else {
                     try {
-                        PackageInfo pkg = packageManager.getPackageInfo(info.packageName,
-                                PackageManager.GET_SIGNING_CERTIFICATES);
+                        PackageInfo pkg = packageManager.getPackageInfoAsUser(info.packageName,
+                                PackageManager.GET_SIGNING_CERTIFICATES, userId);
                         if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP)
                                 == 0) {
                             Slog.w(TAG, "Restore stream contains apk of package "
diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
index 0f4b681..f4b235a 100644
--- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
+++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
@@ -383,11 +383,12 @@
      * @param allowApks - allow restore set to include apks.
      * @param info - file metadata.
      * @param signatures - array of signatures parsed from backup file.
+     * @param userId - ID of the user for which restore is performed.
      * @return a restore policy constant.
      */
     public RestorePolicy chooseRestorePolicy(PackageManager packageManager,
             boolean allowApks, FileMetadata info, Signature[] signatures,
-            PackageManagerInternal pmi) {
+            PackageManagerInternal pmi, int userId) {
         if (signatures == null) {
             return RestorePolicy.IGNORE;
         }
@@ -396,8 +397,8 @@
 
         // Okay, got the manifest info we need...
         try {
-            PackageInfo pkgInfo = packageManager.getPackageInfo(
-                    info.packageName, PackageManager.GET_SIGNING_CERTIFICATES);
+            PackageInfo pkgInfo = packageManager.getPackageInfoAsUser(
+                    info.packageName, PackageManager.GET_SIGNING_CERTIFICATES, userId);
             // Fall through to IGNORE if the app explicitly disallows backup
             final int flags = pkgInfo.applicationInfo.flags;
             if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 4b24ef9..844096d 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -32,13 +32,16 @@
 import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.LocalLog;
 import android.util.Slog;
 import android.view.contentcapture.IContentCaptureManager;
+import android.view.contentcapture.UserDataRemovalRequest;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.SyncResultReceiver;
 import com.android.server.LocalServices;
 import com.android.server.infra.AbstractMasterSystemService;
 import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -50,8 +53,9 @@
 /**
  * A service used to observe the contents of the screen.
  *
- * <p>The data collected by this service can be analyzed and combined with other sources to provide
- * contextual data in other areas of the system such as Autofill.
+ * <p>The data collected by this service can be analyzed on-device and combined
+ * with other sources to provide contextual data in other areas of the system
+ * such as Autofill.
  */
 public final class ContentCaptureManagerService extends
         AbstractMasterSystemService<ContentCaptureManagerService, ContentCapturePerUserService> {
@@ -67,6 +71,8 @@
 
     private final LocalService mLocalService = new LocalService();
 
+    private final LocalLog mRequestsHistory = new LocalLog(20);
+
     public ContentCaptureManagerService(@NonNull Context context) {
         super(context, new FrameworkResourcesServiceNameResolver(context,
                 com.android.internal.R.string.config_defaultContentCaptureService),
@@ -152,6 +158,13 @@
         }
     }
 
+    /**
+     * Logs a request so it's dumped later...
+     */
+    void logRequestLocked(@NonNull String historyItem) {
+        mRequestsHistory.log(historyItem);
+    }
+
     private ActivityManagerInternal getAmInternal() {
         synchronized (mLock) {
             if (mAm == null) {
@@ -196,12 +209,57 @@
         }
 
         @Override
+        public void getReceiverServiceComponentName(@UserIdInt int userId,
+                IResultReceiver receiver) {
+            ComponentName connectedServiceComponentName;
+            synchronized (mLock) {
+                final ContentCapturePerUserService service = getServiceForUserLocked(userId);
+                connectedServiceComponentName = service.getServiceComponentName();
+            }
+            try {
+                receiver.send(0, SyncResultReceiver.bundleFor(connectedServiceComponentName));
+            } catch (RemoteException e) {
+                // Ignore exception as we need to be resilient against app behavior.
+                Slog.w(TAG, "Unable to send service component name: " + e);
+            }
+        }
+
+        @Override
+        public void removeUserData(@UserIdInt int userId, @NonNull UserDataRemovalRequest request) {
+            Preconditions.checkNotNull(request);
+            synchronized (mLock) {
+                final ContentCapturePerUserService service = getServiceForUserLocked(userId);
+                service.removeUserDataLocked(request);
+            }
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
 
+            boolean showHistory = true;
+            if (args != null) {
+                for (String arg : args) {
+                    switch(arg) {
+                        case "--no-history":
+                            showHistory = false;
+                            break;
+                        case "--help":
+                            pw.println("Usage: dumpsys content_capture [--no-history]");
+                            return;
+                        default:
+                            Slog.w(TAG, "Ignoring invalid dump arg: " + arg);
+                    }
+                }
+            }
+
             synchronized (mLock) {
                 dumpLocked("", pw);
             }
+            if (showHistory) {
+                pw.println(); pw.println("Requests history:"); pw.println();
+                mRequestsHistory.reverseDump(fd, pw, args);
+            }
         }
 
         @Override
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index c467935..bc0e19a 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -17,6 +17,9 @@
 package com.android.server.contentcapture;
 
 import static android.service.contentcapture.ContentCaptureService.setClientState;
+import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
+import static android.view.contentcapture.ContentCaptureSession.STATE_DUPLICATED_ID;
+import static android.view.contentcapture.ContentCaptureSession.STATE_NO_SERVICE;
 
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
@@ -25,6 +28,7 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
@@ -32,22 +36,28 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ServiceInfo;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.service.contentcapture.ContentCaptureService;
+import android.service.contentcapture.IContentCaptureServiceCallback;
 import android.service.contentcapture.SnapshotData;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.util.Slog;
-import android.view.contentcapture.ContentCaptureSession;
+import android.view.contentcapture.UserDataRemovalRequest;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.IResultReceiver;
+import com.android.server.LocalServices;
 import com.android.server.contentcapture.RemoteContentCaptureService.ContentCaptureServiceCallbacks;
 import com.android.server.infra.AbstractPerUserSystemService;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Per-user instance of {@link ContentCaptureManagerService}.
@@ -72,12 +82,14 @@
     @GuardedBy("mLock")
     private RemoteContentCaptureService mRemoteService;
 
+    private final ContentCaptureServiceRemoteCallback mRemoteServiceCallback =
+            new ContentCaptureServiceRemoteCallback();
+
     // TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's
 
     ContentCapturePerUserService(@NonNull ContentCaptureManagerService master,
             @NonNull Object lock, boolean disabled, @UserIdInt int userId) {
         super(master, lock, userId);
-
         updateRemoteServiceLocked(disabled);
     }
 
@@ -95,15 +107,15 @@
         final ComponentName serviceComponentName = updateServiceInfoLocked();
 
         if (serviceComponentName == null) {
-            Slog.w(TAG, "updateRemoteService(): no service componennt name");
+            if (mMaster.debug) Slog.d(TAG, "updateRemoteService(): no service component name");
             return;
         }
 
         if (!disabled) {
-            mRemoteService = new RemoteContentCaptureService(
-                  mMaster.getContext(),
-                  ContentCaptureService.SERVICE_INTERFACE, serviceComponentName, mUserId, this,
-                  mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
+            mRemoteService = new RemoteContentCaptureService(mMaster.getContext(),
+                    ContentCaptureService.SERVICE_INTERFACE, serviceComponentName,
+                    mRemoteServiceCallback, mUserId, this, mMaster.isBindInstantServiceAllowed(),
+                    mMaster.verbose);
         }
     }
 
@@ -162,11 +174,24 @@
             @NonNull ComponentName componentName, int taskId, int displayId,
             @NonNull String sessionId, int uid, int flags,
             @NonNull IResultReceiver clientReceiver) {
-        if (!isEnabledLocked()) {
-            setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED, /* binder=*/ null);
+
+        final ComponentName serviceComponentName = getServiceComponentName();
+        final boolean enabled = isEnabledLocked();
+        final String historyItem =
+                "id=" + sessionId + " uid=" + uid
+                + " a=" + ComponentName.flattenToShortString(componentName)
+                + " t=" + taskId + " d=" + displayId
+                + " s=" + ComponentName.flattenToShortString(serviceComponentName)
+                + " u=" + mUserId + " f=" + flags + (enabled ? "" : " (disabled)");
+        mMaster.logRequestLocked(historyItem);
+
+        if (!enabled) {
+            // TODO: it would be better to split in differet reasons, like
+            // STATE_DISABLED_NO_SERVICE and STATE_DISABLED_BY_DEVICE_POLICY
+            setClientState(clientReceiver, STATE_DISABLED | STATE_NO_SERVICE,
+                    /* binder= */ null);
             return;
         }
-        final ComponentName serviceComponentName = getServiceComponentName();
         if (serviceComponentName == null) {
             // TODO(b/111276913): this happens when the system service is starting, we should
             // probably handle it in a more elegant way (like waiting for boot_complete or
@@ -181,7 +206,7 @@
         if (existingSession != null) {
             Slog.w(TAG, "startSession(id=" + existingSession + ", token=" + activityToken
                     + ": ignoring because it already exists for " + existingSession.mActivityToken);
-            setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED_DUPLICATED_ID,
+            setClientState(clientReceiver, STATE_DISABLED | STATE_DUPLICATED_ID,
                     /* binder=*/ null);
             return;
         }
@@ -194,9 +219,8 @@
             // TODO(b/119613670): log metrics
             Slog.w(TAG, "startSession(id=" + existingSession + ", token=" + activityToken
                     + ": ignoring because service is not set");
-            // TODO(b/111276913): use a new disabled state?
-            setClientState(clientReceiver, ContentCaptureSession.STATE_DISABLED,
-                    /* binder=*/ null);
+            setClientState(clientReceiver, STATE_DISABLED | STATE_NO_SERVICE,
+                    /* binder= */ null);
             return;
         }
 
@@ -230,6 +254,39 @@
     }
 
     @GuardedBy("mLock")
+    public void removeUserDataLocked(@NonNull UserDataRemovalRequest request) {
+        if (!isEnabledLocked()) {
+            return;
+        }
+        assertCallerLocked(request.getPackageName());
+        mRemoteService.onUserDataRemovalRequest(request);
+    }
+
+    /**
+     * Asserts the component is owned by the caller.
+     */
+    @GuardedBy("mLock")
+    private void assertCallerLocked(@NonNull String packageName) {
+        final PackageManager pm = getContext().getPackageManager();
+        final int callingUid = Binder.getCallingUid();
+        final int packageUid;
+        try {
+            packageUid = pm.getPackageUidAsUser(packageName, UserHandle.getCallingUserId());
+        } catch (NameNotFoundException e) {
+            throw new SecurityException("Could not verify UID for " + packageName);
+        }
+        if (callingUid != packageUid && !LocalServices.getService(ActivityManagerInternal.class)
+                .hasRunningActivity(callingUid, packageName)) {
+            final String[] packages = pm.getPackagesForUid(callingUid);
+            final String callingPackage = packages != null ? packages[0] : "uid-" + callingUid;
+            Slog.w(TAG, "App (package=" + callingPackage + ", UID=" + callingUid
+                    + ") passed package (" + packageName + ") owned by UID " + packageUid);
+
+            throw new SecurityException("Invalid package: " + packageName);
+        }
+    }
+
+    @GuardedBy("mLock")
     public boolean sendActivityAssistDataLocked(@NonNull IBinder activityToken,
             @NonNull Bundle data) {
         final String id = getSessionId(activityToken);
@@ -285,7 +342,7 @@
         final int numSessions = mSessions.size();
         for (int i = 0; i < numSessions; i++) {
             final ContentCaptureServerSession session = mSessions.valueAt(i);
-            session.destroyLocked(true);
+            session.destroyLocked(/* notifyRemoteService= */ true);
         }
         mSessions.clear();
     }
@@ -335,4 +392,50 @@
         }
         return null;
     }
+
+    private final class ContentCaptureServiceRemoteCallback extends
+            IContentCaptureServiceCallback.Stub {
+
+        @Override
+        public void setContentCaptureWhitelist(List<String> packages,
+                List<ComponentName> activities) {
+            if (mMaster.verbose) {
+                Log.v(TAG, "setContentCaptureWhitelist(packages=" + packages + ", activities="
+                        + activities + ")");
+            }
+            // TODO(b/122595322): implement
+            // TODO(b/119613670): log metrics
+        }
+
+        @Override
+        public void setActivityContentCaptureEnabled(ComponentName activity, boolean enabled) {
+            if (mMaster.verbose) {
+                Log.v(TAG, "setActivityContentCaptureEnabled(activity=" + activity + ", enabled="
+                        + enabled + ")");
+            }
+            // TODO(b/122595322): implement
+            // TODO(b/119613670): log metrics
+        }
+
+        @Override
+        public void setPackageContentCaptureEnabled(String packageName, boolean enabled) {
+            if (mMaster.verbose) {
+                Log.v(TAG,
+                        "setPackageContentCaptureEnabled(packageName=" + packageName + ", enabled="
+                                + enabled + ")");
+            }
+            // TODO(b/122595322): implement
+            // TODO(b/119613670): log metrics
+        }
+
+        @Override
+        public void getContentCaptureDisabledActivities(IResultReceiver receiver) {
+            // TODO(b/122595322): implement
+        }
+
+        @Override
+        public void getContentCaptureDisabledPackages(IResultReceiver receiver) {
+            // TODO(b/122595322): implement
+        }
+    }
 }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index ebe0083..3c52e17 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -83,6 +83,8 @@
      */
     @GuardedBy("mLock")
     public void sendActivitySnapshotLocked(@NonNull SnapshotData snapshotData) {
+        mService.getMaster().logRequestLocked("snapshot: id=" + mId);
+
         mRemoteService.onActivitySnapshotRequest(mId, snapshotData);
     }
 
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index 8241628..54eea5d 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -21,10 +21,12 @@
 import android.content.Context;
 import android.os.IBinder;
 import android.service.contentcapture.IContentCaptureService;
+import android.service.contentcapture.IContentCaptureServiceCallback;
 import android.service.contentcapture.SnapshotData;
 import android.text.format.DateUtils;
 import android.util.Slog;
 import android.view.contentcapture.ContentCaptureContext;
+import android.view.contentcapture.UserDataRemovalRequest;
 
 import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
 import com.android.internal.os.IResultReceiver;
@@ -35,12 +37,15 @@
 
     private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
 
+    private final IBinder mServerCallback;
+
     RemoteContentCaptureService(Context context, String serviceInterface,
-            ComponentName componentName, int userId,
+            ComponentName serviceComponentName, IContentCaptureServiceCallback callback, int userId,
             ContentCaptureServiceCallbacks callbacks, boolean bindInstantServiceAllowed,
             boolean verbose) {
-        super(context, serviceInterface, componentName, userId, callbacks,
+        super(context, serviceInterface, serviceComponentName, userId, callbacks,
                 bindInstantServiceAllowed, verbose, /* initialCapacity= */ 2);
+        mServerCallback = callback.asBinder();
 
         // Bind right away, which will trigger a onConnected() on service's
         scheduleBind();
@@ -69,7 +74,11 @@
             scheduleUnbind();
         }
         try {
-            mService.onConnectedStateChanged(state);
+            if (state) {
+                mService.onConnected(mServerCallback);
+            } else {
+                mService.onDisconnected();
+            }
         } catch (Exception e) {
             Slog.w(mTag, "Exception calling onConnectedStateChanged(" + state + "): " + e);
         }
@@ -100,6 +109,13 @@
         scheduleAsyncRequest((s) -> s.onActivitySnapshot(sessionId, snapshotData));
     }
 
+    /**
+     * Called by {@link ContentCaptureServerSession} to request removal of user data.
+     */
+    public void onUserDataRemovalRequest(@NonNull UserDataRemovalRequest request) {
+        scheduleAsyncRequest((s) -> s.onUserDataRemovalRequest(request));
+    }
+
     public interface ContentCaptureServiceCallbacks
             extends VultureCallback<RemoteContentCaptureService> {
         // NOTE: so far we don't need to notify the callback implementation
diff --git a/services/contentsuggestions/Android.bp b/services/contentsuggestions/Android.bp
new file mode 100644
index 0000000..fc09d2e
--- /dev/null
+++ b/services/contentsuggestions/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+    name: "services.contentsuggestions",
+    srcs: ["java/**/*.java"],
+    libs: ["services.core"],
+}
\ No newline at end of file
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
new file mode 100644
index 0000000..58dbea4
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
@@ -0,0 +1,205 @@
+/*
+ * 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.contentsuggestions;
+
+import static android.Manifest.permission.MANAGE_CONTENT_SUGGESTIONS;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.IContentSuggestionsManager;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.infra.AbstractMasterSystemService;
+import com.android.server.infra.FrameworkResourcesServiceNameResolver;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import java.io.FileDescriptor;
+
+/**
+ * The system service for providing recents / overview with content suggestion selections and
+ * classifications.
+ *
+ * <p>Calls are received here from
+ * {@link android.app.contentsuggestions.ContentSuggestionsManager} then delegated to
+ * a per user version of the service. From there they are routed to the remote actual implementation
+ * that provides the suggestion selections and classifications.
+ */
+public class ContentSuggestionsManagerService extends
+        AbstractMasterSystemService<
+                        ContentSuggestionsManagerService, ContentSuggestionsPerUserService> {
+
+    private static final String TAG = ContentSuggestionsManagerService.class.getSimpleName();
+    private static final boolean VERBOSE = false; // TODO: make dynamic
+
+    private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
+
+    private ActivityTaskManagerInternal mActivityTaskManagerInternal;
+
+    public ContentSuggestionsManagerService(Context context) {
+        super(context, new FrameworkResourcesServiceNameResolver(context,
+                com.android.internal.R.string.config_defaultContentSuggestionsService), null);
+        mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+    }
+
+    @Override
+    protected ContentSuggestionsPerUserService newServiceLocked(int resolvedUserId,
+            boolean disabled) {
+        return new ContentSuggestionsPerUserService(this, mLock, resolvedUserId);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(
+                Context.CONTENT_SUGGESTIONS_SERVICE, new ContentSuggestionsManagerStub());
+    }
+
+    @Override
+    protected void enforceCallingPermissionForManagement() {
+        getContext().enforceCallingPermission(MANAGE_CONTENT_SUGGESTIONS, TAG);
+    }
+
+    @Override
+    protected int getMaximumTemporaryServiceDurationMs() {
+        return MAX_TEMP_SERVICE_DURATION_MS;
+    }
+
+    private boolean isCallerRecents(int userId) {
+        if (mServiceNameResolver.isTemporary(userId)) {
+            // If a temporary service is set then skip the recents check
+            return true;
+        }
+        return mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid());
+    }
+
+    private void enforceCallerIsRecents(int userId, String func) {
+        if (isCallerRecents(userId)) {
+            return;
+        }
+
+        String msg = "Permission Denial: " + func + " from pid="
+                + Binder.getCallingPid()
+                + ", uid=" + Binder.getCallingUid()
+                + " expected caller is recents";
+        Slog.w(TAG, msg);
+        throw new SecurityException(msg);
+    }
+
+    private class ContentSuggestionsManagerStub extends IContentSuggestionsManager.Stub {
+        @Override
+        public void provideContextImage(int taskId, @NonNull Bundle imageContextRequestExtras) {
+            if (imageContextRequestExtras == null) {
+                throw new IllegalArgumentException("Expected non-null imageContextRequestExtras");
+            }
+
+            final int userId = UserHandle.getCallingUserId();
+            enforceCallerIsRecents(userId, "provideContextImage");
+
+            synchronized (mLock) {
+                final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.provideContextImageLocked(taskId, imageContextRequestExtras);
+                } else {
+                    if (VERBOSE) {
+                        Slog.v(TAG, "provideContextImageLocked: no service for " + userId);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void suggestContentSelections(
+                @NonNull SelectionsRequest selectionsRequest,
+                @NonNull ISelectionsCallback selectionsCallback) {
+            final int userId = UserHandle.getCallingUserId();
+            enforceCallerIsRecents(userId, "suggestContentSelections");
+
+            synchronized (mLock) {
+                final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.suggestContentSelectionsLocked(selectionsRequest, selectionsCallback);
+                } else {
+                    if (VERBOSE) {
+                        Slog.v(TAG, "suggestContentSelectionsLocked: no service for " + userId);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void classifyContentSelections(
+                @NonNull ClassificationsRequest classificationsRequest,
+                @NonNull IClassificationsCallback callback) {
+            final int userId = UserHandle.getCallingUserId();
+            enforceCallerIsRecents(userId, "classifyContentSelections");
+
+            synchronized (mLock) {
+                final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.classifyContentSelectionsLocked(classificationsRequest, callback);
+                } else {
+                    if (VERBOSE) {
+                        Slog.v(TAG, "classifyContentSelectionsLocked: no service for " + userId);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void notifyInteraction(@NonNull String requestId, @NonNull Bundle bundle) {
+            final int userId = UserHandle.getCallingUserId();
+            enforceCallerIsRecents(userId, "notifyInteraction");
+
+            synchronized (mLock) {
+                final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.notifyInteractionLocked(requestId, bundle);
+                } else {
+                    if (VERBOSE) {
+                        Slog.v(TAG, "reportInteractionLocked: no service for " + userId);
+                    }
+                }
+            }
+        }
+
+        public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+                @Nullable FileDescriptor err,
+                @NonNull String[] args, @Nullable ShellCallback callback,
+                @NonNull ResultReceiver resultReceiver) throws RemoteException {
+            // Ensure that the caller is the shell process
+            final int callingUid = Binder.getCallingUid();
+            if (callingUid != android.os.Process.SHELL_UID
+                    && callingUid != android.os.Process.ROOT_UID) {
+                Slog.e(TAG, "Expected shell caller");
+                return;
+            }
+            new ContentSuggestionsManagerServiceShellCommand(ContentSuggestionsManagerService.this)
+                    .exec(this, in, out, err, args, callback, resultReceiver);
+        }
+    }
+}
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerServiceShellCommand.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerServiceShellCommand.java
new file mode 100644
index 0000000..e34f1ea
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerServiceShellCommand.java
@@ -0,0 +1,84 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/**
+ * The shell command implementation for the ContentSuggestionsManagerService.
+ */
+public class ContentSuggestionsManagerServiceShellCommand extends ShellCommand {
+
+    private static final String TAG =
+            ContentSuggestionsManagerServiceShellCommand.class.getSimpleName();
+
+    private final ContentSuggestionsManagerService mService;
+
+    public ContentSuggestionsManagerServiceShellCommand(
+            @NonNull ContentSuggestionsManagerService service) {
+        mService = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        final PrintWriter pw = getOutPrintWriter();
+        switch (cmd) {
+            case "set": {
+                final String what = getNextArgRequired();
+                switch (what) {
+                    case "temporary-service": {
+                        final int userId = Integer.parseInt(getNextArgRequired());
+                        String serviceName = getNextArg();
+                        if (serviceName == null) {
+                            mService.resetTemporaryService(userId);
+                            return 0;
+                        }
+                        final int duration = Integer.parseInt(getNextArgRequired());
+                        mService.setTemporaryService(userId, serviceName, duration);
+                        pw.println("ContentSuggestionsService temporarily set to " + serviceName
+                                + " for " + duration + "ms");
+                        break;
+                    }
+                }
+            }
+            break;
+            default:
+                return handleDefaultCommands(cmd);
+        }
+        return 0;
+    }
+
+    @Override
+    public void onHelp() {
+        try (PrintWriter pw = getOutPrintWriter()) {
+            pw.println("ContentSuggestionsManagerService commands:");
+            pw.println("  help");
+            pw.println("    Prints this help text.");
+            pw.println("");
+            pw.println("  set temporary-service USER_ID [COMPONENT_NAME DURATION]");
+            pw.println("    Temporarily (for DURATION ms) changes the service implemtation.");
+            pw.println("    To reset, call with just the USER_ID argument.");
+            pw.println("");
+        }
+    }
+}
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
new file mode 100644
index 0000000..385bc6c
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
@@ -0,0 +1,162 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.AppGlobals;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.infra.AbstractPerUserSystemService;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+/**
+ * Per user delegate of {@link ContentSuggestionsManagerService}.
+ *
+ * <p>Main job is to forward calls to the remote implementation that can provide suggestion
+ * selections and classifications.
+ */
+public final class ContentSuggestionsPerUserService extends
+        AbstractPerUserSystemService<
+                        ContentSuggestionsPerUserService, ContentSuggestionsManagerService> {
+    private static final String TAG = ContentSuggestionsPerUserService.class.getSimpleName();
+
+    @Nullable
+    @GuardedBy("mLock")
+    private RemoteContentSuggestionsService mRemoteService;
+
+    @NonNull
+    private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
+
+    ContentSuggestionsPerUserService(
+            ContentSuggestionsManagerService master, Object lock, int userId) {
+        super(master, lock, userId);
+        mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+    }
+
+    @GuardedBy("mLock")
+    @Override // from PerUserSystemService
+    protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
+            throws PackageManager.NameNotFoundException {
+        ServiceInfo si;
+        try {
+            si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+                    PackageManager.GET_META_DATA, mUserId);
+        } catch (RemoteException e) {
+            throw new PackageManager.NameNotFoundException(
+                    "Could not get service for " + serviceComponent);
+        }
+        return si;
+    }
+
+    @GuardedBy("mLock")
+    @Override // from PerUserSystemService
+    protected boolean updateLocked(boolean disabled) {
+        final boolean enabledChanged = super.updateLocked(disabled);
+        if (enabledChanged) {
+            if (!isEnabledLocked()) {
+                // Clear the remote service for the next call
+                mRemoteService = null;
+            }
+        }
+        return enabledChanged;
+    }
+
+    @GuardedBy("mLock")
+    void provideContextImageLocked(int taskId, @NonNull Bundle imageContextRequestExtras) {
+        RemoteContentSuggestionsService service = getRemoteServiceLocked();
+        if (service != null) {
+            ActivityManager.TaskSnapshot snapshot =
+                    mActivityTaskManagerInternal.getTaskSnapshot(taskId, false);
+            GraphicBuffer snapshotBuffer = null;
+            if (snapshot != null) {
+                snapshotBuffer = snapshot.getSnapshot();
+            }
+
+            service.provideContextImage(taskId, snapshotBuffer, imageContextRequestExtras);
+        }
+    }
+
+    @GuardedBy("mLock")
+    void suggestContentSelectionsLocked(
+            @NonNull SelectionsRequest selectionsRequest,
+            @NonNull ISelectionsCallback selectionsCallback) {
+        RemoteContentSuggestionsService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.suggestContentSelections(selectionsRequest, selectionsCallback);
+        }
+    }
+
+    @GuardedBy("mLock")
+    void classifyContentSelectionsLocked(
+            @NonNull ClassificationsRequest classificationsRequest,
+            @NonNull IClassificationsCallback callback) {
+        RemoteContentSuggestionsService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.classifyContentSelections(classificationsRequest, callback);
+        }
+    }
+
+    @GuardedBy("mLock")
+    void notifyInteractionLocked(@NonNull String requestId, @NonNull Bundle bundle) {
+        RemoteContentSuggestionsService service = getRemoteServiceLocked();
+        if (service != null) {
+            service.notifyInteraction(requestId, bundle);
+        }
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    private RemoteContentSuggestionsService getRemoteServiceLocked() {
+        if (mRemoteService == null) {
+            final String serviceName = getComponentNameLocked();
+            if (serviceName == null) {
+                if (mMaster.verbose) {
+                    Slog.v(TAG, "getRemoteServiceLocked(): not set");
+                }
+                return null;
+            }
+            ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+
+            mRemoteService = new RemoteContentSuggestionsService(getContext(),
+                    serviceComponent, mUserId,
+                    new RemoteContentSuggestionsService.Callbacks() {
+                        @Override
+                        public void onServiceDied(
+                                @NonNull RemoteContentSuggestionsService service) {
+                            // TODO(b/120865921): properly implement
+                            Slog.w(TAG, "remote content suggestions service died");
+                        }
+                    }, mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
+        }
+
+        return mRemoteService;
+    }
+}
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/RemoteContentSuggestionsService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/RemoteContentSuggestionsService.java
new file mode 100644
index 0000000..bf48d76
--- /dev/null
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/RemoteContentSuggestionsService.java
@@ -0,0 +1,97 @@
+/*
+ * 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.contentsuggestions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.IClassificationsCallback;
+import android.app.contentsuggestions.ISelectionsCallback;
+import android.app.contentsuggestions.SelectionsRequest;
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.service.contentsuggestions.ContentSuggestionsService;
+import android.service.contentsuggestions.IContentSuggestionsService;
+import android.text.format.DateUtils;
+
+import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
+
+/**
+ * Delegates calls from {@link ContentSuggestionsPerUserService} to the remote actual implementation
+ * of the suggestion selection and classification service.
+ */
+public class RemoteContentSuggestionsService extends
+        AbstractMultiplePendingRequestsRemoteService<RemoteContentSuggestionsService,
+                                IContentSuggestionsService> {
+
+    private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
+
+    RemoteContentSuggestionsService(Context context, ComponentName serviceName,
+            int userId, Callbacks callbacks,
+            boolean bindInstantServiceAllowed, boolean verbose) {
+        super(context, ContentSuggestionsService.SERVICE_INTERFACE, serviceName, userId, callbacks,
+                bindInstantServiceAllowed, verbose, /* initialCapacity= */ 1);
+    }
+
+    @Override
+    protected IContentSuggestionsService getServiceInterface(IBinder service) {
+        return IContentSuggestionsService.Stub.asInterface(service);
+    }
+
+    @Override
+    protected long getTimeoutIdleBindMillis() {
+        return PERMANENT_BOUND_TIMEOUT_MS;
+    }
+
+    @Override
+    protected long getRemoteRequestMillis() {
+        return TIMEOUT_REMOTE_REQUEST_MILLIS;
+    }
+
+    void provideContextImage(int taskId, @Nullable GraphicBuffer contextImage,
+            @NonNull Bundle imageContextRequestExtras) {
+        scheduleAsyncRequest((s) -> s.provideContextImage(taskId, contextImage,
+                imageContextRequestExtras));
+    }
+
+    void suggestContentSelections(
+            @NonNull SelectionsRequest selectionsRequest,
+            @NonNull ISelectionsCallback selectionsCallback) {
+        scheduleAsyncRequest(
+                (s) -> s.suggestContentSelections(selectionsRequest, selectionsCallback));
+    }
+
+    void classifyContentSelections(
+            @NonNull ClassificationsRequest classificationsRequest,
+            @NonNull IClassificationsCallback callback) {
+        scheduleAsyncRequest((s) -> s.classifyContentSelections(classificationsRequest, callback));
+    }
+
+    void notifyInteraction(@NonNull String requestId, @NonNull Bundle bundle) {
+        scheduleAsyncRequest((s) -> s.notifyInteraction(requestId, bundle));
+    }
+
+    interface Callbacks
+            extends VultureCallback<RemoteContentSuggestionsService> {
+        // NOTE: so far we don't need to notify the callback implementation
+        // (ContentSuggestionsManager) of the request results (success, timeouts, etc..), so this
+        // callback interface is empty.
+    }
+}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 0fa996e..e3dcb7d 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -64,6 +64,7 @@
 import android.os.ShellCommand;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.ThreadLocalWorkSource;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.WorkSource;
@@ -76,6 +77,7 @@
 import android.util.ArraySet;
 import android.util.KeyValueListParser;
 import android.util.Log;
+import android.util.LongArrayQueue;
 import android.util.NtpTrustedTime;
 import android.util.Pair;
 import android.util.Slog;
@@ -90,6 +92,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.LocalLog;
 import com.android.internal.util.StatLogger;
 import com.android.server.AppStateTracker.Listener;
@@ -144,6 +147,7 @@
     static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
 
     static final int TICK_HISTORY_DEPTH = 10;
+    static final long MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
 
     // Indices into the APP_STANDBY_MIN_DELAYS and KEYS_APP_STANDBY_DELAY arrays
     static final int ACTIVE_INDEX = 0;
@@ -194,6 +198,7 @@
     ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>();
     ArrayList<InFlight> mInFlight = new ArrayList<>();
     AlarmHandler mHandler;
+    AppWakeupHistory mAppWakeupHistory;
     ClockReceiver mClockReceiver;
     final DeliveryTracker mDeliveryTracker = new DeliveryTracker();
     Intent mTimeTickIntent;
@@ -276,7 +281,91 @@
 
     private AppStateTracker mAppStateTracker;
     private boolean mAppStandbyParole;
-    private ArrayMap<Pair<String, Integer>, Long> mLastAlarmDeliveredForPackage = new ArrayMap<>();
+
+    /**
+     * A rolling window history of previous times when an alarm was sent to a package.
+     */
+    private static class AppWakeupHistory {
+        private ArrayMap<Pair<String, Integer>, LongArrayQueue> mPackageHistory =
+                new ArrayMap<>();
+        private long mWindowSize;
+
+        AppWakeupHistory(long windowSize) {
+            mWindowSize = windowSize;
+        }
+
+        void recordAlarmForPackage(String packageName, int userId, long nowElapsed) {
+            final Pair<String, Integer> packageUser = Pair.create(packageName, userId);
+            LongArrayQueue history = mPackageHistory.get(packageUser);
+            if (history == null) {
+                history = new LongArrayQueue();
+                mPackageHistory.put(packageUser, history);
+            }
+            if (history.size() == 0 || history.peekLast() < nowElapsed) {
+                history.addLast(nowElapsed);
+            }
+            snapToWindow(history);
+        }
+
+        void removeForUser(int userId) {
+            for (int i = mPackageHistory.size() - 1; i >= 0; i--) {
+                final Pair<String, Integer> packageUserKey = mPackageHistory.keyAt(i);
+                if (packageUserKey.second == userId) {
+                    mPackageHistory.removeAt(i);
+                }
+            }
+        }
+
+        void removeForPackage(String packageName, int userId) {
+            final Pair<String, Integer> packageUser = Pair.create(packageName, userId);
+            mPackageHistory.remove(packageUser);
+        }
+
+        private void snapToWindow(LongArrayQueue history) {
+            while (history.peekFirst() + mWindowSize < history.peekLast()) {
+                history.removeFirst();
+            }
+        }
+
+        int getTotalWakeupsInWindow(String packageName, int userId) {
+            final LongArrayQueue history = mPackageHistory.get(Pair.create(packageName, userId));
+            return (history == null) ? 0 : history.size();
+        }
+
+        long getLastWakeupForPackage(String packageName, int userId, int positionFromEnd) {
+            final LongArrayQueue history = mPackageHistory.get(Pair.create(packageName, userId));
+            if (history == null) {
+                return 0;
+            }
+            final int i = history.size() - positionFromEnd;
+            return (i < 0) ? 0 : history.get(i);
+        }
+
+        void dump(PrintWriter pw, String prefix, long nowElapsed) {
+            dump(new IndentingPrintWriter(pw, "  ").setIndent(prefix), nowElapsed);
+        }
+
+        void dump(IndentingPrintWriter pw, long nowElapsed) {
+            pw.println("App Alarm history:");
+            pw.increaseIndent();
+            for (int i = 0; i < mPackageHistory.size(); i++) {
+                final Pair<String, Integer> packageUser = mPackageHistory.keyAt(i);
+                final LongArrayQueue timestamps = mPackageHistory.valueAt(i);
+                pw.print(packageUser.first);
+                pw.print(", u");
+                pw.print(packageUser.second);
+                pw.print(": ");
+                // limit dumping to a max of 100 values
+                final int lastIdx = Math.max(0, timestamps.size() - 100);
+                for (int j = timestamps.size() - 1; j >= lastIdx; j--) {
+                    TimeUtils.formatDuration(timestamps.get(j), nowElapsed, pw);
+                    pw.print(", ");
+                }
+                pw.println();
+            }
+            pw.decreaseIndent();
+        }
+    }
 
     /**
      * All times are in milliseconds. These constants are kept synchronized with the system
@@ -301,6 +390,17 @@
                 = "allow_while_idle_whitelist_duration";
         @VisibleForTesting
         static final String KEY_LISTENER_TIMEOUT = "listener_timeout";
+        @VisibleForTesting
+        static final String KEY_APP_STANDBY_QUOTAS_ENABLED = "app_standby_quotas_enabled";
+        private static final String KEY_APP_STANDBY_WINDOW = "app_standby_window";
+        @VisibleForTesting
+        final String[] KEYS_APP_STANDBY_QUOTAS = {
+                "standby_active_quota",
+                "standby_working_quota",
+                "standby_frequent_quota",
+                "standby_rare_quota",
+                "standby_never_quota",
+        };
 
         // Keys for specifying throttling delay based on app standby bucketing
         private final String[] KEYS_APP_STANDBY_DELAY = {
@@ -318,6 +418,18 @@
         private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000;
         private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
         private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;
+        private static final boolean DEFAULT_APP_STANDBY_QUOTAS_ENABLED = true;
+        private static final long DEFAULT_APP_STANDBY_WINDOW = 60 * 60 * 1000;  // 1 hr
+        /**
+         * Max number of times an app can receive alarms in {@link #APP_STANDBY_WINDOW}
+         */
+        private final int[] DEFAULT_APP_STANDBY_QUOTAS = {
+                720,    // Active
+                10,     // Working
+                2,      // Frequent
+                1,      // Rare
+                0       // Never
+        };
         private final long[] DEFAULT_APP_STANDBY_DELAYS = {
                 0,                       // Active
                 6 * 60_000,              // Working
@@ -347,8 +459,11 @@
 
         // Direct alarm listener callback timeout
         public long LISTENER_TIMEOUT = DEFAULT_LISTENER_TIMEOUT;
+        public boolean APP_STANDBY_QUOTAS_ENABLED = DEFAULT_APP_STANDBY_QUOTAS_ENABLED;
 
+        public long APP_STANDBY_WINDOW = DEFAULT_APP_STANDBY_WINDOW;
         public long[] APP_STANDBY_MIN_DELAYS = new long[DEFAULT_APP_STANDBY_DELAYS.length];
+        public int[] APP_STANDBY_QUOTAS = new int[DEFAULT_APP_STANDBY_QUOTAS.length];
 
         private ContentResolver mResolver;
         private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -408,48 +523,90 @@
                         DEFAULT_APP_STANDBY_DELAYS[ACTIVE_INDEX]);
                 for (int i = WORKING_INDEX; i < KEYS_APP_STANDBY_DELAY.length; i++) {
                     APP_STANDBY_MIN_DELAYS[i] = mParser.getDurationMillis(KEYS_APP_STANDBY_DELAY[i],
-                            Math.max(APP_STANDBY_MIN_DELAYS[i-1], DEFAULT_APP_STANDBY_DELAYS[i]));
+                            Math.max(APP_STANDBY_MIN_DELAYS[i - 1], DEFAULT_APP_STANDBY_DELAYS[i]));
+                }
+
+                APP_STANDBY_QUOTAS_ENABLED = mParser.getBoolean(KEY_APP_STANDBY_QUOTAS_ENABLED,
+                        DEFAULT_APP_STANDBY_QUOTAS_ENABLED);
+
+                APP_STANDBY_WINDOW = mParser.getLong(KEY_APP_STANDBY_WINDOW,
+                        DEFAULT_APP_STANDBY_WINDOW);
+                if (APP_STANDBY_WINDOW > DEFAULT_APP_STANDBY_WINDOW) {
+                    Slog.w(TAG, "Cannot exceed the app_standby_window size of "
+                            + DEFAULT_APP_STANDBY_WINDOW);
+                    APP_STANDBY_WINDOW = DEFAULT_APP_STANDBY_WINDOW;
+                } else if (APP_STANDBY_WINDOW < DEFAULT_APP_STANDBY_WINDOW) {
+                    // Not recommended outside of testing.
+                    Slog.w(TAG, "Using a non-default app_standby_window of " + APP_STANDBY_WINDOW);
+                }
+
+                APP_STANDBY_QUOTAS[ACTIVE_INDEX] = mParser.getInt(
+                        KEYS_APP_STANDBY_QUOTAS[ACTIVE_INDEX],
+                        DEFAULT_APP_STANDBY_QUOTAS[ACTIVE_INDEX]);
+                for (int i = WORKING_INDEX; i < KEYS_APP_STANDBY_QUOTAS.length; i++) {
+                    APP_STANDBY_QUOTAS[i] = mParser.getInt(KEYS_APP_STANDBY_QUOTAS[i],
+                            Math.min(APP_STANDBY_QUOTAS[i - 1], DEFAULT_APP_STANDBY_QUOTAS[i]));
                 }
                 updateAllowWhileIdleWhitelistDurationLocked();
             }
         }
 
-        void dump(PrintWriter pw) {
-            pw.println("  Settings:");
+        void dump(PrintWriter pw, String prefix) {
+            dump(new IndentingPrintWriter(pw, "  ").setIndent(prefix));
+        }
 
-            pw.print("    "); pw.print(KEY_MIN_FUTURITY); pw.print("=");
+        void dump(IndentingPrintWriter pw) {
+            pw.println("Settings:");
+
+            pw.increaseIndent();
+
+            pw.print(KEY_MIN_FUTURITY); pw.print("=");
             TimeUtils.formatDuration(MIN_FUTURITY, pw);
             pw.println();
 
-            pw.print("    "); pw.print(KEY_MIN_INTERVAL); pw.print("=");
+            pw.print(KEY_MIN_INTERVAL); pw.print("=");
             TimeUtils.formatDuration(MIN_INTERVAL, pw);
             pw.println();
 
-            pw.print("    "); pw.print(KEY_MAX_INTERVAL); pw.print("=");
+            pw.print(KEY_MAX_INTERVAL); pw.print("=");
             TimeUtils.formatDuration(MAX_INTERVAL, pw);
             pw.println();
 
-            pw.print("    "); pw.print(KEY_LISTENER_TIMEOUT); pw.print("=");
+            pw.print(KEY_LISTENER_TIMEOUT); pw.print("=");
             TimeUtils.formatDuration(LISTENER_TIMEOUT, pw);
             pw.println();
 
-            pw.print("    "); pw.print(KEY_ALLOW_WHILE_IDLE_SHORT_TIME); pw.print("=");
+            pw.print(KEY_ALLOW_WHILE_IDLE_SHORT_TIME); pw.print("=");
             TimeUtils.formatDuration(ALLOW_WHILE_IDLE_SHORT_TIME, pw);
             pw.println();
 
-            pw.print("    "); pw.print(KEY_ALLOW_WHILE_IDLE_LONG_TIME); pw.print("=");
+            pw.print(KEY_ALLOW_WHILE_IDLE_LONG_TIME); pw.print("=");
             TimeUtils.formatDuration(ALLOW_WHILE_IDLE_LONG_TIME, pw);
             pw.println();
 
-            pw.print("    "); pw.print(KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION); pw.print("=");
+            pw.print(KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION); pw.print("=");
             TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION, pw);
             pw.println();
 
             for (int i = 0; i < KEYS_APP_STANDBY_DELAY.length; i++) {
-                pw.print("    "); pw.print(KEYS_APP_STANDBY_DELAY[i]); pw.print("=");
+                pw.print(KEYS_APP_STANDBY_DELAY[i]); pw.print("=");
                 TimeUtils.formatDuration(APP_STANDBY_MIN_DELAYS[i], pw);
                 pw.println();
             }
+
+            pw.print(KEY_APP_STANDBY_QUOTAS_ENABLED); pw.print("=");
+            pw.println(APP_STANDBY_QUOTAS_ENABLED);
+
+            pw.print(KEY_APP_STANDBY_WINDOW); pw.print("=");
+            TimeUtils.formatDuration(APP_STANDBY_WINDOW, pw);
+            pw.println();
+
+            for (int i = 0; i < KEYS_APP_STANDBY_QUOTAS.length; i++) {
+                pw.print(KEYS_APP_STANDBY_QUOTAS[i]); pw.print("=");
+                pw.println(APP_STANDBY_QUOTAS[i]);
+            }
+
+            pw.decreaseIndent();
         }
 
         void dumpProto(ProtoOutputStream proto, long fieldId) {
@@ -924,7 +1081,7 @@
                 if (targetPackages != null && !targetPackages.contains(packageUser)) {
                     continue;
                 }
-                if (adjustDeliveryTimeBasedOnStandbyBucketLocked(alarm)) {
+                if (adjustDeliveryTimeBasedOnBucketLocked(alarm)) {
                     batch.remove(alarm);
                     rescheduledAlarms.add(alarm);
                 }
@@ -1131,23 +1288,23 @@
         final IBinder mListener;
         final WorkSource mWorkSource;
         final int mUid;
+        final int mCreatorUid;
         final String mTag;
         final BroadcastStats mBroadcastStats;
         final FilterStats mFilterStats;
         final int mAlarmType;
 
-        InFlight(AlarmManagerService service, PendingIntent pendingIntent, IAlarmListener listener,
-                WorkSource workSource, int uid, String alarmPkg, int alarmType, String tag,
-                long nowELAPSED) {
-            mPendingIntent = pendingIntent;
+        InFlight(AlarmManagerService service, Alarm alarm, long nowELAPSED) {
+            mPendingIntent = alarm.operation;
             mWhenElapsed = nowELAPSED;
-            mListener = listener != null ? listener.asBinder() : null;
-            mWorkSource = workSource;
-            mUid = uid;
-            mTag = tag;
-            mBroadcastStats = (pendingIntent != null)
-                    ? service.getStatsLocked(pendingIntent)
-                    : service.getStatsLocked(uid, alarmPkg);
+            mListener = alarm.listener != null ? alarm.listener.asBinder() : null;
+            mWorkSource = alarm.workSource;
+            mUid = alarm.uid;
+            mCreatorUid = alarm.creatorUid;
+            mTag = alarm.statsTag;
+            mBroadcastStats = (alarm.operation != null)
+                    ? service.getStatsLocked(alarm.operation)
+                    : service.getStatsLocked(alarm.uid, alarm.packageName);
             FilterStats fs = mBroadcastStats.filterStats.get(mTag);
             if (fs == null) {
                 fs = new FilterStats(mBroadcastStats, mTag);
@@ -1155,7 +1312,7 @@
             }
             fs.lastTime = nowELAPSED;
             mFilterStats = fs;
-            mAlarmType = alarmType;
+            mAlarmType = alarm.type;
         }
 
         @Override
@@ -1165,6 +1322,7 @@
                     + ", when=" + mWhenElapsed
                     + ", workSource=" + mWorkSource
                     + ", uid=" + mUid
+                    + ", creatorUid=" + mCreatorUid
                     + ", tag=" + mTag
                     + ", broadcastStats=" + mBroadcastStats
                     + ", filterStats=" + mFilterStats
@@ -1298,6 +1456,7 @@
         synchronized (mLock) {
             mHandler = new AlarmHandler();
             mConstants = new Constants(mHandler);
+            mAppWakeupHistory = new AppWakeupHistory(Constants.DEFAULT_APP_STANDBY_WINDOW);
 
             mNextWakeup = mNextNonWakeup = 0;
 
@@ -1581,6 +1740,27 @@
     }
 
     /**
+     * Returns the maximum alarms that an app in the specified bucket can receive in a rolling time
+     * window given by {@link Constants#APP_STANDBY_WINDOW}
+     */
+    @VisibleForTesting
+    int getQuotaForBucketLocked(int bucket) {
+        final int index;
+        if (bucket <= UsageStatsManager.STANDBY_BUCKET_ACTIVE) {
+            index = ACTIVE_INDEX;
+        } else if (bucket <= UsageStatsManager.STANDBY_BUCKET_WORKING_SET) {
+            index = WORKING_INDEX;
+        } else if (bucket <= UsageStatsManager.STANDBY_BUCKET_FREQUENT) {
+            index = FREQUENT_INDEX;
+        } else if (bucket < UsageStatsManager.STANDBY_BUCKET_NEVER) {
+            index = RARE_INDEX;
+        } else {
+            index = NEVER_INDEX;
+        }
+        return mConstants.APP_STANDBY_QUOTAS[index];
+    }
+
+    /**
      * Return the minimum time that should elapse before an app in the specified bucket
      * can receive alarms again
      */
@@ -1606,7 +1786,7 @@
      * @param alarm The alarm to adjust
      * @return true if the alarm delivery time was updated.
      */
-    private boolean adjustDeliveryTimeBasedOnStandbyBucketLocked(Alarm alarm) {
+    private boolean adjustDeliveryTimeBasedOnBucketLocked(Alarm alarm) {
         if (isExemptFromAppStandby(alarm)) {
             return false;
         }
@@ -1627,18 +1807,49 @@
         final int standbyBucket = mUsageStatsManagerInternal.getAppStandbyBucket(
                 sourcePackage, sourceUserId, mInjector.getElapsedRealtime());
 
-        final Pair<String, Integer> packageUser = Pair.create(sourcePackage, sourceUserId);
-        final long lastElapsed = mLastAlarmDeliveredForPackage.getOrDefault(packageUser, 0L);
-        if (lastElapsed > 0) {
-            final long minElapsed = lastElapsed + getMinDelayForBucketLocked(standbyBucket);
-            if (alarm.expectedWhenElapsed < minElapsed) {
-                alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
-            } else {
-                // app is now eligible to run alarms at the originally requested window.
+        if (mConstants.APP_STANDBY_QUOTAS_ENABLED) {
+            // Quota deferring implementation:
+            final int wakeupsInWindow = mAppWakeupHistory.getTotalWakeupsInWindow(sourcePackage,
+                    sourceUserId);
+            final int quotaForBucket = getQuotaForBucketLocked(standbyBucket);
+            boolean deferred = false;
+            if (wakeupsInWindow >= quotaForBucket) {
+                final long minElapsed;
+                if (quotaForBucket <= 0) {
+                    // Just keep deferring for a day till the quota changes
+                    minElapsed = mInjector.getElapsedRealtime() + MILLIS_IN_DAY;
+                } else {
+                    // Suppose the quota for window was q, and the qth last delivery time for this
+                    // package was t(q) then the next delivery must be after t(q) + <window_size>
+                    final long t = mAppWakeupHistory.getLastWakeupForPackage(sourcePackage,
+                            sourceUserId, quotaForBucket);
+                    minElapsed = t + 1 + mConstants.APP_STANDBY_WINDOW;
+                }
+                if (alarm.expectedWhenElapsed < minElapsed) {
+                    alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
+                    deferred = true;
+                }
+            }
+            if (!deferred) {
                 // Restore original requirements in case they were changed earlier.
                 alarm.whenElapsed = alarm.expectedWhenElapsed;
                 alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
             }
+        } else {
+            // Minimum delay deferring implementation:
+            final long lastElapsed = mAppWakeupHistory.getLastWakeupForPackage(sourcePackage,
+                    sourceUserId, 1);
+            if (lastElapsed > 0) {
+                final long minElapsed = lastElapsed + getMinDelayForBucketLocked(standbyBucket);
+                if (alarm.expectedWhenElapsed < minElapsed) {
+                    alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
+                } else {
+                    // app is now eligible to run alarms at the originally requested window.
+                    // Restore original requirements in case they were changed earlier.
+                    alarm.whenElapsed = alarm.expectedWhenElapsed;
+                    alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
+                }
+            }
         }
         return (oldWhenElapsed != alarm.whenElapsed || oldMaxWhenElapsed != alarm.maxWhenElapsed);
     }
@@ -1694,7 +1905,7 @@
                 mAllowWhileIdleDispatches.add(ent);
             }
         }
-        adjustDeliveryTimeBasedOnStandbyBucketLocked(a);
+        adjustDeliveryTimeBasedOnBucketLocked(a);
         insertAndBatchAlarmLocked(a);
 
         if (a.alarmClock != null) {
@@ -1913,7 +2124,7 @@
     void dumpImpl(PrintWriter pw) {
         synchronized (mLock) {
             pw.println("Current Alarm Manager state:");
-            mConstants.dump(pw);
+            mConstants.dump(pw, "  ");
             pw.println();
 
             if (mAppStateTracker != null) {
@@ -2063,14 +2274,7 @@
                 pw.println("    none");
             }
 
-            pw.println("  mLastAlarmDeliveredForPackage:");
-            for (int i = 0; i < mLastAlarmDeliveredForPackage.size(); i++) {
-                Pair<String, Integer> packageUser = mLastAlarmDeliveredForPackage.keyAt(i);
-                pw.print("    Package " + packageUser.first + ", User " + packageUser.second + ":");
-                TimeUtils.formatDuration(mLastAlarmDeliveredForPackage.valueAt(i), nowELAPSED, pw);
-                pw.println();
-            }
-            pw.println();
+            mAppWakeupHistory.dump(pw, "  ", nowELAPSED);
 
             if (mPendingIdleUntil != null || mPendingWhileIdleAlarms.size() > 0) {
                 pw.println();
@@ -3811,12 +4015,10 @@
 
     /**
      * Attribute blame for a WakeLock.
-     * @param pi PendingIntent to attribute blame to if ws is null.
      * @param ws WorkSource to attribute blame.
-     * @param knownUid attribution uid; < 0 if we need to derive it from the PendingIntent sender
+     * @param knownUid attribution uid; < 0 values are ignored.
      */
-    void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, String tag,
-            int knownUid, boolean first) {
+    void setWakelockWorkSource(WorkSource ws, int knownUid, String tag, boolean first) {
         try {
             mWakeLock.setHistoryTag(first ? tag : null);
 
@@ -3825,11 +4027,8 @@
                 return;
             }
 
-            final int uid = (knownUid >= 0)
-                    ? knownUid
-                    : ActivityManager.getService().getUidForIntentSender(pi.getTarget());
-            if (uid >= 0) {
-                mWakeLock.setWorkSource(new WorkSource(uid));
+            if (knownUid >= 0) {
+                mWakeLock.setWorkSource(new WorkSource(knownUid));
                 return;
             }
         } catch (Exception e) {
@@ -3839,6 +4038,14 @@
         mWakeLock.setWorkSource(null);
     }
 
+    private static int getAlarmAttributionUid(Alarm alarm) {
+        if (alarm.workSource != null && !alarm.workSource.isEmpty()) {
+            return alarm.workSource.getAttributionUid();
+        }
+
+        return alarm.creatorUid;
+    }
+
     @VisibleForTesting
     class AlarmHandler extends Handler {
         public static final int ALARM_EVENT = 1;
@@ -3857,6 +4064,7 @@
             obtainMessage(REMOVE_FOR_STOPPED, uid, 0).sendToTarget();
         }
 
+        @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case ALARM_EVENT: {
@@ -4025,64 +4233,57 @@
         public void onReceive(Context context, Intent intent) {
             final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
             synchronized (mLock) {
-                String action = intent.getAction();
                 String pkgList[] = null;
-                if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
-                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
-                    for (String packageName : pkgList) {
-                        if (lookForPackageLocked(packageName)) {
-                            setResultCode(Activity.RESULT_OK);
-                            return;
-                        }
-                    }
-                    return;
-                } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
-                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-                } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
-                    int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-                    if (userHandle >= 0) {
-                        removeUserLocked(userHandle);
-                        for (int i = mLastAlarmDeliveredForPackage.size() - 1; i >= 0; i--) {
-                            final Pair<String, Integer> packageUser =
-                                    mLastAlarmDeliveredForPackage.keyAt(i);
-                            if (packageUser.second == userHandle) {
-                                mLastAlarmDeliveredForPackage.removeAt(i);
+                switch (intent.getAction()) {
+                    case Intent.ACTION_QUERY_PACKAGE_RESTART:
+                        pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
+                        for (String packageName : pkgList) {
+                            if (lookForPackageLocked(packageName)) {
+                                setResultCode(Activity.RESULT_OK);
+                                return;
                             }
                         }
-                    }
-                } else if (Intent.ACTION_UID_REMOVED.equals(action)) {
-                    if (uid >= 0) {
-                        mLastAllowWhileIdleDispatch.delete(uid);
-                        mUseAllowWhileIdleShortTime.delete(uid);
-                    }
-                } else {
-                    if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
-                            && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
-                        // This package is being updated; don't kill its alarms.
                         return;
-                    }
-                    Uri data = intent.getData();
-                    if (data != null) {
-                        String pkg = data.getSchemeSpecificPart();
-                        if (pkg != null) {
-                            pkgList = new String[]{pkg};
+                    case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
+                        pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                        break;
+                    case Intent.ACTION_USER_STOPPED:
+                        final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+                        if (userHandle >= 0) {
+                            removeUserLocked(userHandle);
+                            mAppWakeupHistory.removeForUser(userHandle);
                         }
-                    }
+                        return;
+                    case Intent.ACTION_UID_REMOVED:
+                        if (uid >= 0) {
+                            mLastAllowWhileIdleDispatch.delete(uid);
+                            mUseAllowWhileIdleShortTime.delete(uid);
+                        }
+                        return;
+                    case Intent.ACTION_PACKAGE_REMOVED:
+                        if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                            // This package is being updated; don't kill its alarms.
+                            return;
+                        }
+                        // Intentional fall-through.
+                    case Intent.ACTION_PACKAGE_RESTARTED:
+                        final Uri data = intent.getData();
+                        if (data != null) {
+                            final String pkg = data.getSchemeSpecificPart();
+                            if (pkg != null) {
+                                pkgList = new String[]{pkg};
+                            }
+                        }
+                        break;
                 }
                 if (pkgList != null && (pkgList.length > 0)) {
-                    for (int i = mLastAlarmDeliveredForPackage.size() - 1; i >= 0; i--) {
-                        Pair<String, Integer> packageUser = mLastAlarmDeliveredForPackage.keyAt(i);
-                        if (ArrayUtils.contains(pkgList, packageUser.first)
-                                && packageUser.second == UserHandle.getUserId(uid)) {
-                            mLastAlarmDeliveredForPackage.removeAt(i);
-                        }
-                    }
                     for (String pkg : pkgList) {
                         if (uid >= 0) {
-                            // package-removed case
+                            // package-removed and package-restarted case
+                            mAppWakeupHistory.removeForPackage(pkg, UserHandle.getUserId(uid));
                             removeLocked(uid);
                         } else {
-                            // external-applications-unavailable etc case
+                            // external-applications-unavailable case
                             removeLocked(pkg);
                         }
                         mPriorities.remove(pkg);
@@ -4126,7 +4327,8 @@
     /**
      * Tracking of app assignments to standby buckets
      */
-    final class AppStandbyTracker extends UsageStatsManagerInternal.AppIdleStateChangeListener {
+    private final class AppStandbyTracker extends
+            UsageStatsManagerInternal.AppIdleStateChangeListener {
         @Override
         public void onAppIdleStateChanged(final String packageName, final @UserIdInt int userId,
                 boolean idle, int bucket, int reason) {
@@ -4285,8 +4487,8 @@
                 // the next of our alarms is now in flight.  reattribute the wakelock.
                 if (mInFlight.size() > 0) {
                     InFlight inFlight = mInFlight.get(0);
-                    setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource,
-                            inFlight.mAlarmType, inFlight.mTag, -1, false);
+                    setWakelockWorkSource(inFlight.mWorkSource, inFlight.mCreatorUid, inFlight.mTag,
+                            false);
                 } else {
                     // should never happen
                     mLog.w("Alarm wakelock still held but sent queue empty");
@@ -4369,64 +4571,70 @@
          */
         @GuardedBy("mLock")
         public void deliverLocked(Alarm alarm, long nowELAPSED, boolean allowWhileIdle) {
-            if (alarm.operation != null) {
-                // PendingIntent alarm
-                mSendCount++;
+            final long workSourceToken = ThreadLocalWorkSource.setUid(
+                    getAlarmAttributionUid(alarm));
+            try {
+                if (alarm.operation != null) {
+                    // PendingIntent alarm
+                    mSendCount++;
 
-                try {
-                    alarm.operation.send(getContext(), 0,
-                            mBackgroundIntent.putExtra(
-                                    Intent.EXTRA_ALARM_COUNT, alarm.count),
-                                    mDeliveryTracker, mHandler, null,
-                                    allowWhileIdle ? mIdleOptions : null);
-                } catch (PendingIntent.CanceledException e) {
-                    if (alarm.repeatInterval > 0) {
-                        // This IntentSender is no longer valid, but this
-                        // is a repeating alarm, so toss it
-                        removeImpl(alarm.operation, null);
+                    try {
+                        alarm.operation.send(getContext(), 0,
+                                mBackgroundIntent.putExtra(
+                                        Intent.EXTRA_ALARM_COUNT, alarm.count),
+                                mDeliveryTracker, mHandler, null,
+                                allowWhileIdle ? mIdleOptions : null);
+                    } catch (PendingIntent.CanceledException e) {
+                        if (alarm.repeatInterval > 0) {
+                            // This IntentSender is no longer valid, but this
+                            // is a repeating alarm, so toss it
+                            removeImpl(alarm.operation, null);
+                        }
+                        // No actual delivery was possible, so the delivery tracker's
+                        // 'finished' callback won't be invoked.  We also don't need
+                        // to do any wakelock or stats tracking, so we have nothing
+                        // left to do here but go on to the next thing.
+                        mSendFinishCount++;
+                        return;
                     }
-                    // No actual delivery was possible, so the delivery tracker's
-                    // 'finished' callback won't be invoked.  We also don't need
-                    // to do any wakelock or stats tracking, so we have nothing
-                    // left to do here but go on to the next thing.
-                    mSendFinishCount++;
-                    return;
-                }
-            } else {
-                // Direct listener callback alarm
-                mListenerCount++;
+                } else {
+                    // Direct listener callback alarm
+                    mListenerCount++;
 
-                if (RECORD_ALARMS_IN_HISTORY) {
-                    if (alarm.listener == mTimeTickTrigger) {
-                        mTickHistory[mNextTickHistory++] = nowELAPSED;
-                        if (mNextTickHistory >= TICK_HISTORY_DEPTH) {
-                            mNextTickHistory = 0;
+                    if (RECORD_ALARMS_IN_HISTORY) {
+                        if (alarm.listener == mTimeTickTrigger) {
+                            mTickHistory[mNextTickHistory++] = nowELAPSED;
+                            if (mNextTickHistory >= TICK_HISTORY_DEPTH) {
+                                mNextTickHistory = 0;
+                            }
                         }
                     }
-                }
 
-                try {
-                    if (DEBUG_LISTENER_CALLBACK) {
-                        Slog.v(TAG, "Alarm to uid=" + alarm.uid
-                                + " listener=" + alarm.listener.asBinder());
+                    try {
+                        if (DEBUG_LISTENER_CALLBACK) {
+                            Slog.v(TAG, "Alarm to uid=" + alarm.uid
+                                    + " listener=" + alarm.listener.asBinder());
+                        }
+                        alarm.listener.doAlarm(this);
+                        mHandler.sendMessageDelayed(
+                                mHandler.obtainMessage(AlarmHandler.LISTENER_TIMEOUT,
+                                        alarm.listener.asBinder()),
+                                mConstants.LISTENER_TIMEOUT);
+                    } catch (Exception e) {
+                        if (DEBUG_LISTENER_CALLBACK) {
+                            Slog.i(TAG, "Alarm undeliverable to listener "
+                                    + alarm.listener.asBinder(), e);
+                        }
+                        // As in the PendingIntent.CanceledException case, delivery of the
+                        // alarm was not possible, so we have no wakelock or timeout or
+                        // stats management to do.  It threw before we posted the delayed
+                        // timeout message, so we're done here.
+                        mListenerFinishCount++;
+                        return;
                     }
-                    alarm.listener.doAlarm(this);
-                    mHandler.sendMessageDelayed(
-                            mHandler.obtainMessage(AlarmHandler.LISTENER_TIMEOUT,
-                                    alarm.listener.asBinder()),
-                            mConstants.LISTENER_TIMEOUT);
-                } catch (Exception e) {
-                    if (DEBUG_LISTENER_CALLBACK) {
-                        Slog.i(TAG, "Alarm undeliverable to listener "
-                                + alarm.listener.asBinder(), e);
-                    }
-                    // As in the PendingIntent.CanceledException case, delivery of the
-                    // alarm was not possible, so we have no wakelock or timeout or
-                    // stats management to do.  It threw before we posted the delayed
-                    // timeout message, so we're done here.
-                    mListenerFinishCount++;
-                    return;
                 }
+            } finally {
+                ThreadLocalWorkSource.restore(workSourceToken);
             }
 
             // The alarm is now in flight; now arrange wakelock and stats tracking
@@ -4434,15 +4642,11 @@
                 Slog.d(TAG, "mBroadcastRefCount -> " + (mBroadcastRefCount + 1));
             }
             if (mBroadcastRefCount == 0) {
-                setWakelockWorkSource(alarm.operation, alarm.workSource,
-                        alarm.type, alarm.statsTag, (alarm.operation == null) ? alarm.uid : -1,
-                        true);
+                setWakelockWorkSource(alarm.workSource, alarm.creatorUid, alarm.statsTag, true);
                 mWakeLock.acquire();
                 mHandler.obtainMessage(AlarmHandler.REPORT_ALARMS_ACTIVE, 1).sendToTarget();
             }
-            final InFlight inflight = new InFlight(AlarmManagerService.this,
-                    alarm.operation, alarm.listener, alarm.workSource, alarm.uid,
-                    alarm.packageName, alarm.type, alarm.statsTag, nowELAPSED);
+            final InFlight inflight = new InFlight(AlarmManagerService.this, alarm, nowELAPSED);
             mInFlight.add(inflight);
             mBroadcastRefCount++;
             if (allowWhileIdle) {
@@ -4467,7 +4671,8 @@
             if (!isExemptFromAppStandby(alarm)) {
                 final Pair<String, Integer> packageUser = Pair.create(alarm.sourcePackage,
                         UserHandle.getUserId(alarm.creatorUid));
-                mLastAlarmDeliveredForPackage.put(packageUser, nowELAPSED);
+                mAppWakeupHistory.recordAlarmForPackage(alarm.sourcePackage,
+                        UserHandle.getUserId(alarm.creatorUid), nowELAPSED);
             }
 
             final BroadcastStats bs = inflight.mBroadcastStats;
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
deleted file mode 100644
index 3cdf09e..0000000
--- a/services/core/java/com/android/server/AppOpsService.java
+++ /dev/null
@@ -1,4281 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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;
-
-import static android.app.AppOpsManager.OP_PLAY_AUDIO;
-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 static android.app.AppOpsManager.modeToName;
-import static android.app.AppOpsManager.opToName;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.ActivityThread;
-import android.app.AppGlobals;
-import android.app.AppOpsManager;
-import android.app.AppOpsManager.HistoricalOpEntry;
-import android.app.AppOpsManager.HistoricalPackageOps;
-import android.app.AppOpsManagerInternal;
-import android.app.AppOpsManagerInternal.CheckOpsDelegate;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.UserInfo;
-import android.database.ContentObserver;
-import android.media.AudioAttributes;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ServiceManager;
-import android.os.ShellCallback;
-import android.os.ShellCommand;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.os.storage.StorageManager;
-import android.os.storage.StorageManagerInternal;
-import android.provider.Settings;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.AtomicFile;
-import android.util.KeyValueListParser;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
-import android.util.TimeUtils;
-import android.util.Xml;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IAppOpsActiveCallback;
-import com.android.internal.app.IAppOpsCallback;
-import com.android.internal.app.IAppOpsNotedCallback;
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.os.Zygote;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.Preconditions;
-import com.android.internal.util.XmlUtils;
-import com.android.internal.util.function.pooled.PooledLambda;
-
-import libcore.util.EmptyArray;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-public class AppOpsService extends IAppOpsService.Stub {
-    static final String TAG = "AppOps";
-    static final boolean DEBUG = false;
-
-    private static final int NO_VERSION = -1;
-    /** Increment by one every time and add the corresponding upgrade logic in
-     *  {@link #upgradeLocked(int)} below. The first version was 1 */
-    private static final int CURRENT_VERSION = 1;
-
-    // Write at most every 30 minutes.
-    static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
-
-    // Constant meaning that any UID should be matched when dispatching callbacks
-    private static final int UID_ANY = -2;
-
-    // Map from process states to the uid states we track.
-    private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
-        UID_STATE_PERSISTENT,           // ActivityManager.PROCESS_STATE_PERSISTENT
-        UID_STATE_PERSISTENT,           // ActivityManager.PROCESS_STATE_PERSISTENT_UI
-        UID_STATE_TOP,                  // ActivityManager.PROCESS_STATE_TOP
-        UID_STATE_FOREGROUND_SERVICE,   // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
-        UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
-        UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
-        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
-        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
-        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_BACKUP
-        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_SERVICE
-        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_RECEIVER
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_TOP_SLEEPING
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_HOME
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_RECENT
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_EMPTY
-        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_NONEXISTENT
-    };
-
-    static final String[] UID_STATE_NAMES = new String[] {
-            "pers ",    // UID_STATE_PERSISTENT
-            "top  ",    // UID_STATE_TOP
-            "fgsvc",    // UID_STATE_FOREGROUND_SERVICE
-            "fg   ",    // UID_STATE_FOREGROUND
-            "bg   ",    // UID_STATE_BACKGROUND
-            "cch  ",    // UID_STATE_CACHED
-    };
-
-    static final String[] UID_STATE_TIME_ATTRS = new String[] {
-            "tp",       // UID_STATE_PERSISTENT
-            "tt",       // UID_STATE_TOP
-            "tfs",      // UID_STATE_FOREGROUND_SERVICE
-            "tf",       // UID_STATE_FOREGROUND
-            "tb",       // UID_STATE_BACKGROUND
-            "tc",       // UID_STATE_CACHED
-    };
-
-    static final String[] UID_STATE_REJECT_ATTRS = new String[] {
-            "rp",       // UID_STATE_PERSISTENT
-            "rt",       // UID_STATE_TOP
-            "rfs",      // UID_STATE_FOREGROUND_SERVICE
-            "rf",       // UID_STATE_FOREGROUND
-            "rb",       // UID_STATE_BACKGROUND
-            "rc",       // UID_STATE_CACHED
-    };
-
-    Context mContext;
-    final AtomicFile mFile;
-    final Handler mHandler;
-
-    private final AppOpsManagerInternalImpl mAppOpsManagerInternal
-            = new AppOpsManagerInternalImpl();
-
-    boolean mWriteScheduled;
-    boolean mFastWriteScheduled;
-    final Runnable mWriteRunner = new Runnable() {
-        public void run() {
-            synchronized (AppOpsService.this) {
-                mWriteScheduled = false;
-                mFastWriteScheduled = false;
-                AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
-                    @Override protected Void doInBackground(Void... params) {
-                        writeState();
-                        return null;
-                    }
-                };
-                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
-            }
-        }
-    };
-
-    @VisibleForTesting
-    final SparseArray<UidState> mUidStates = new SparseArray<>();
-
-    long mLastRealtime;
-
-    /*
-     * These are app op restrictions imposed per user from various parties.
-     */
-    private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
-
-    SparseIntArray mProfileOwners;
-
-    @GuardedBy("this")
-    private CheckOpsDelegate mCheckOpsDelegate;
-
-    /**
-     * All times are in milliseconds. These constants are kept synchronized with the system
-     * global Settings. Any access to this class or its fields should be done while
-     * holding the AppOpsService lock.
-     */
-    private final class Constants extends ContentObserver {
-        // Key names stored in the settings value.
-        private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
-        private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
-                = "fg_service_state_settle_time";
-        private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
-
-        /**
-         * How long we want for a drop in uid state from top to settle before applying it.
-         * @see Settings.Global#APP_OPS_CONSTANTS
-         * @see #KEY_TOP_STATE_SETTLE_TIME
-         */
-        public long TOP_STATE_SETTLE_TIME;
-
-        /**
-         * How long we want for a drop in uid state from foreground to settle before applying it.
-         * @see Settings.Global#APP_OPS_CONSTANTS
-         * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
-         */
-        public long FG_SERVICE_STATE_SETTLE_TIME;
-
-        /**
-         * How long we want for a drop in uid state from background to settle before applying it.
-         * @see Settings.Global#APP_OPS_CONSTANTS
-         * @see #KEY_BG_STATE_SETTLE_TIME
-         */
-        public long BG_STATE_SETTLE_TIME;
-
-        private final KeyValueListParser mParser = new KeyValueListParser(',');
-        private ContentResolver mResolver;
-
-        public Constants(Handler handler) {
-            super(handler);
-            updateConstants();
-        }
-
-        public void startMonitoring(ContentResolver resolver) {
-            mResolver = resolver;
-            mResolver.registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
-                    false, this);
-            updateConstants();
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            updateConstants();
-        }
-
-        private void updateConstants() {
-            String value = mResolver != null ? Settings.Global.getString(mResolver,
-                    Settings.Global.APP_OPS_CONSTANTS) : "";
-
-            synchronized (AppOpsService.this) {
-                try {
-                    mParser.setString(value);
-                } catch (IllegalArgumentException e) {
-                    // Failed to parse the settings string, log this and move on
-                    // with defaults.
-                    Slog.e(TAG, "Bad app ops settings", e);
-                }
-                TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
-                        KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
-                FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
-                        KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
-                BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
-                        KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
-            }
-        }
-
-        void dump(PrintWriter pw) {
-            pw.println("  Settings:");
-
-            pw.print("    "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
-            TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
-            pw.println();
-            pw.print("    "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
-            TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
-            pw.println();
-            pw.print("    "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
-            TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
-            pw.println();
-        }
-    }
-
-    private final Constants mConstants;
-
-    @VisibleForTesting
-    static final class UidState {
-        public final int uid;
-
-        public int state = UID_STATE_CACHED;
-        public int pendingState = UID_STATE_CACHED;
-        public long pendingStateCommitTime;
-
-        public int startNesting;
-        public ArrayMap<String, Ops> pkgOps;
-        public SparseIntArray opModes;
-
-        // true indicates there is an interested observer, false there isn't but it has such an op
-        public SparseBooleanArray foregroundOps;
-        public boolean hasForegroundWatchers;
-
-        public UidState(int uid) {
-            this.uid = uid;
-        }
-
-        public void clear() {
-            pkgOps = null;
-            opModes = null;
-        }
-
-        public boolean isDefault() {
-            return (pkgOps == null || pkgOps.isEmpty())
-                    && (opModes == null || opModes.size() <= 0);
-        }
-
-        int evalMode(int mode) {
-            if (mode == AppOpsManager.MODE_FOREGROUND) {
-                return state <= UID_STATE_LAST_NON_RESTRICTED
-                        ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
-            }
-            return mode;
-        }
-
-        private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
-                SparseBooleanArray which) {
-            boolean curValue = which.get(op, false);
-            ArraySet<ModeCallback> callbacks = watchers.get(op);
-            if (callbacks != null) {
-                for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
-                    if ((callbacks.valueAt(cbi).mFlags
-                            & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
-                        hasForegroundWatchers = true;
-                        curValue = true;
-                    }
-                }
-            }
-            which.put(op, curValue);
-        }
-
-        public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
-            SparseBooleanArray which = null;
-            hasForegroundWatchers = false;
-            if (opModes != null) {
-                for (int i = opModes.size() - 1; i >= 0; i--) {
-                    if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
-                        if (which == null) {
-                            which = new SparseBooleanArray();
-                        }
-                        evalForegroundWatchers(opModes.keyAt(i), watchers, which);
-                    }
-                }
-            }
-            if (pkgOps != null) {
-                for (int i = pkgOps.size() - 1; i >= 0; i--) {
-                    Ops ops = pkgOps.valueAt(i);
-                    for (int j = ops.size() - 1; j >= 0; j--) {
-                        if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
-                            if (which == null) {
-                                which = new SparseBooleanArray();
-                            }
-                            evalForegroundWatchers(ops.keyAt(j), watchers, which);
-                        }
-                    }
-                }
-            }
-            foregroundOps = which;
-        }
-    }
-
-    final static class Ops extends SparseArray<Op> {
-        final String packageName;
-        final UidState uidState;
-        final boolean isPrivileged;
-
-        Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
-            packageName = _packageName;
-            uidState = _uidState;
-            isPrivileged = _isPrivileged;
-        }
-    }
-
-    final static class Op {
-        final UidState uidState;
-        final int uid;
-        final String packageName;
-        final int op;
-        int proxyUid = -1;
-        String proxyPackageName;
-        int mode;
-        int duration;
-        long time[] = new long[_NUM_UID_STATE];
-        long rejectTime[] = new long[_NUM_UID_STATE];
-        int startNesting;
-        long startRealtime;
-
-        Op(UidState _uidState, String _packageName, int _op) {
-            uidState = _uidState;
-            uid = _uidState.uid;
-            packageName = _packageName;
-            op = _op;
-            mode = AppOpsManager.opToDefaultMode(op);
-        }
-
-        boolean hasAnyTime() {
-            for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
-                if (time[i] != 0) {
-                    return true;
-                }
-                if (rejectTime[i] != 0) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        int getMode() {
-            return uidState.evalMode(mode);
-        }
-    }
-
-    final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
-    final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
-    final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
-    final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
-    final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
-    final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
-
-    final class ModeCallback implements DeathRecipient {
-        final IAppOpsCallback mCallback;
-        final int mWatchingUid;
-        final int mFlags;
-        final int mCallingUid;
-        final int mCallingPid;
-
-        ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
-                int callingPid) {
-            mCallback = callback;
-            mWatchingUid = watchingUid;
-            mFlags = flags;
-            mCallingUid = callingUid;
-            mCallingPid = callingPid;
-            try {
-                mCallback.asBinder().linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                /*ignored*/
-            }
-        }
-
-        public boolean isWatchingUid(int uid) {
-            return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder(128);
-            sb.append("ModeCallback{");
-            sb.append(Integer.toHexString(System.identityHashCode(this)));
-            sb.append(" watchinguid=");
-            UserHandle.formatUid(sb, mWatchingUid);
-            sb.append(" flags=0x");
-            sb.append(Integer.toHexString(mFlags));
-            sb.append(" from uid=");
-            UserHandle.formatUid(sb, mCallingUid);
-            sb.append(" pid=");
-            sb.append(mCallingPid);
-            sb.append('}');
-            return sb.toString();
-        }
-
-        void unlinkToDeath() {
-            mCallback.asBinder().unlinkToDeath(this, 0);
-        }
-
-        @Override
-        public void binderDied() {
-            stopWatchingMode(mCallback);
-        }
-    }
-
-    final class ActiveCallback implements DeathRecipient {
-        final IAppOpsActiveCallback mCallback;
-        final int mWatchingUid;
-        final int mCallingUid;
-        final int mCallingPid;
-
-        ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
-                int callingPid) {
-            mCallback = callback;
-            mWatchingUid = watchingUid;
-            mCallingUid = callingUid;
-            mCallingPid = callingPid;
-            try {
-                mCallback.asBinder().linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                /*ignored*/
-            }
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder(128);
-            sb.append("ActiveCallback{");
-            sb.append(Integer.toHexString(System.identityHashCode(this)));
-            sb.append(" watchinguid=");
-            UserHandle.formatUid(sb, mWatchingUid);
-            sb.append(" from uid=");
-            UserHandle.formatUid(sb, mCallingUid);
-            sb.append(" pid=");
-            sb.append(mCallingPid);
-            sb.append('}');
-            return sb.toString();
-        }
-
-        void destroy() {
-            mCallback.asBinder().unlinkToDeath(this, 0);
-        }
-
-        @Override
-        public void binderDied() {
-            stopWatchingActive(mCallback);
-        }
-    }
-
-    final class NotedCallback implements DeathRecipient {
-        final IAppOpsNotedCallback mCallback;
-        final int mWatchingUid;
-        final int mCallingUid;
-        final int mCallingPid;
-
-        NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid,
-                int callingPid) {
-            mCallback = callback;
-            mWatchingUid = watchingUid;
-            mCallingUid = callingUid;
-            mCallingPid = callingPid;
-            try {
-                mCallback.asBinder().linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                /*ignored*/
-            }
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder(128);
-            sb.append("NotedCallback{");
-            sb.append(Integer.toHexString(System.identityHashCode(this)));
-            sb.append(" watchinguid=");
-            UserHandle.formatUid(sb, mWatchingUid);
-            sb.append(" from uid=");
-            UserHandle.formatUid(sb, mCallingUid);
-            sb.append(" pid=");
-            sb.append(mCallingPid);
-            sb.append('}');
-            return sb.toString();
-        }
-
-        void destroy() {
-            mCallback.asBinder().unlinkToDeath(this, 0);
-        }
-
-        @Override
-        public void binderDied() {
-            stopWatchingNoted(mCallback);
-        }
-    }
-
-    final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
-
-    final class ClientState extends Binder implements DeathRecipient {
-        final ArrayList<Op> mStartedOps = new ArrayList<>();
-        final IBinder mAppToken;
-        final int mPid;
-
-        ClientState(IBinder appToken) {
-            mAppToken = appToken;
-            mPid = Binder.getCallingPid();
-            // Watch only for remote processes dying
-            if (!(appToken instanceof Binder)) {
-                try {
-                    mAppToken.linkToDeath(this, 0);
-                } catch (RemoteException e) {
-                    /* do nothing */
-                }
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "ClientState{" +
-                    "mAppToken=" + mAppToken +
-                    ", " + "pid=" + mPid +
-                    '}';
-        }
-
-        @Override
-        public void binderDied() {
-            synchronized (AppOpsService.this) {
-                for (int i=mStartedOps.size()-1; i>=0; i--) {
-                    finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
-                }
-                mClients.remove(mAppToken);
-            }
-        }
-    }
-
-    public AppOpsService(File storagePath, Handler handler) {
-        LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
-        mFile = new AtomicFile(storagePath, "appops");
-        mHandler = handler;
-        mConstants = new Constants(mHandler);
-        readState();
-    }
-
-    public void publish(Context context) {
-        mContext = context;
-        ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
-        LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
-    }
-
-    public void systemReady() {
-        mConstants.startMonitoring(mContext.getContentResolver());
-
-        synchronized (this) {
-            boolean changed = false;
-            for (int i = mUidStates.size() - 1; i >= 0; i--) {
-                UidState uidState = mUidStates.valueAt(i);
-
-                String[] packageNames = getPackagesForUid(uidState.uid);
-                if (ArrayUtils.isEmpty(packageNames)) {
-                    uidState.clear();
-                    mUidStates.removeAt(i);
-                    changed = true;
-                    continue;
-                }
-
-                ArrayMap<String, Ops> pkgs = uidState.pkgOps;
-                if (pkgs == null) {
-                    continue;
-                }
-
-                Iterator<Ops> it = pkgs.values().iterator();
-                while (it.hasNext()) {
-                    Ops ops = it.next();
-                    int curUid = -1;
-                    try {
-                        curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
-                                PackageManager.MATCH_UNINSTALLED_PACKAGES,
-                                UserHandle.getUserId(ops.uidState.uid));
-                    } catch (RemoteException ignored) {
-                    }
-                    if (curUid != ops.uidState.uid) {
-                        Slog.i(TAG, "Pruning old package " + ops.packageName
-                                + "/" + ops.uidState + ": new uid=" + curUid);
-                        it.remove();
-                        changed = true;
-                    }
-                }
-
-                if (uidState.isDefault()) {
-                    mUidStates.removeAt(i);
-                }
-            }
-            if (changed) {
-                scheduleFastWriteLocked();
-            }
-        }
-
-        final IntentFilter packageSuspendFilter = new IntentFilter();
-        packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
-        packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
-                final String[] changedPkgs = intent.getStringArrayExtra(
-                        Intent.EXTRA_CHANGED_PACKAGE_LIST);
-                final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(OP_PLAY_AUDIO);
-                for (int i = 0; i < changedUids.length; i++) {
-                    final int changedUid = changedUids[i];
-                    final String changedPkg = changedPkgs[i];
-                    // We trust packagemanager to insert matching uid and packageNames in the extras
-                    mHandler.sendMessage(PooledLambda.obtainMessage(AppOpsService::notifyOpChanged,
-                            AppOpsService.this, callbacks, OP_PLAY_AUDIO, changedUid, changedPkg));
-                }
-            }
-        }, packageSuspendFilter);
-
-        PackageManagerInternal packageManagerInternal = LocalServices.getService(
-                PackageManagerInternal.class);
-        packageManagerInternal.setExternalSourcesPolicy(
-                new PackageManagerInternal.ExternalSourcesPolicy() {
-                    @Override
-                    public int getPackageTrustedToInstallApps(String packageName, int uid) {
-                        int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
-                                uid, packageName);
-                        switch (appOpMode) {
-                            case AppOpsManager.MODE_ALLOWED:
-                                return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
-                            case AppOpsManager.MODE_ERRORED:
-                                return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
-                            default:
-                                return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
-                        }
-                    }
-                });
-
-        if (!StorageManager.hasIsolatedStorage()) {
-            StorageManagerInternal storageManagerInternal = LocalServices.getService(
-                    StorageManagerInternal.class);
-            storageManagerInternal.addExternalStoragePolicy(
-                    new StorageManagerInternal.ExternalStorageMountPolicy() {
-                        @Override
-                        public int getMountMode(int uid, String packageName) {
-                            if (Process.isIsolated(uid)) {
-                                return Zygote.MOUNT_EXTERNAL_NONE;
-                            }
-                            if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
-                                    packageName) != AppOpsManager.MODE_ALLOWED) {
-                                return Zygote.MOUNT_EXTERNAL_NONE;
-                            }
-                            if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
-                                    packageName) != AppOpsManager.MODE_ALLOWED) {
-                                return Zygote.MOUNT_EXTERNAL_READ;
-                            }
-                            return Zygote.MOUNT_EXTERNAL_WRITE;
-                        }
-
-                        @Override
-                        public boolean hasExternalStorage(int uid, String packageName) {
-                            final int mountMode = getMountMode(uid, packageName);
-                            return mountMode == Zygote.MOUNT_EXTERNAL_READ
-                                    || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
-                        }
-                    });
-        }
-    }
-
-    public void packageRemoved(int uid, String packageName) {
-        synchronized (this) {
-            UidState uidState = mUidStates.get(uid);
-            if (uidState == null) {
-                return;
-            }
-
-            Ops ops = null;
-
-            // Remove any package state if such.
-            if (uidState.pkgOps != null) {
-                ops = uidState.pkgOps.remove(packageName);
-            }
-
-            // If we just nuked the last package state check if the UID is valid.
-            if (ops != null && uidState.pkgOps.isEmpty()
-                    && getPackagesForUid(uid).length <= 0) {
-                mUidStates.remove(uid);
-            }
-
-            // Finish ops other packages started on behalf of the package.
-            final int clientCount = mClients.size();
-            for (int i = 0; i < clientCount; i++) {
-                final ClientState client = mClients.valueAt(i);
-                if (client.mStartedOps == null) {
-                    continue;
-                }
-                final int opCount = client.mStartedOps.size();
-                for (int j = opCount - 1; j >= 0; j--) {
-                    final Op op = client.mStartedOps.get(j);
-                    if (uid == op.uid && packageName.equals(op.packageName)) {
-                        finishOperationLocked(op, /*finishNested*/ true);
-                        client.mStartedOps.remove(j);
-                        if (op.startNesting <= 0) {
-                            scheduleOpActiveChangedIfNeededLocked(op.op,
-                                    uid, packageName, false);
-                        }
-                    }
-                }
-            }
-
-            if (ops != null) {
-                scheduleFastWriteLocked();
-
-                final int opCount = ops.size();
-                for (int i = 0; i < opCount; i++) {
-                    final Op op = ops.valueAt(i);
-                    if (op.duration == -1) {
-                        scheduleOpActiveChangedIfNeededLocked(
-                                op.op, op.uid, op.packageName, false);
-                    }
-                }
-            }
-        }
-    }
-
-    public void uidRemoved(int uid) {
-        synchronized (this) {
-            if (mUidStates.indexOfKey(uid) >= 0) {
-                mUidStates.remove(uid);
-                scheduleFastWriteLocked();
-            }
-        }
-    }
-
-    public void updateUidProcState(int uid, int procState) {
-        synchronized (this) {
-            final UidState uidState = getUidStateLocked(uid, true);
-            final int newState = PROCESS_STATE_TO_UID_STATE[procState];
-            if (uidState != null && uidState.pendingState != newState) {
-                final int oldPendingState = uidState.pendingState;
-                uidState.pendingState = newState;
-                if (newState < uidState.state || newState <= UID_STATE_LAST_NON_RESTRICTED) {
-                    // We are moving to a more important state, or the new state is in the
-                    // foreground, then always do it immediately.
-                    commitUidPendingStateLocked(uidState);
-                } else if (uidState.pendingStateCommitTime == 0) {
-                    // We are moving to a less important state for the first time,
-                    // delay the application for a bit.
-                    final long settleTime;
-                    if (uidState.state <= UID_STATE_TOP) {
-                        settleTime = mConstants.TOP_STATE_SETTLE_TIME;
-                    } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
-                        settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
-                    } else {
-                        settleTime = mConstants.BG_STATE_SETTLE_TIME;
-                    }
-                    uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime;
-                }
-                if (uidState.startNesting != 0) {
-                    // There is some actively running operation...  need to find it
-                    // and appropriately update its state.
-                    final long now = System.currentTimeMillis();
-                    for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
-                        final Ops ops = uidState.pkgOps.valueAt(i);
-                        for (int j = ops.size() - 1; j >= 0; j--) {
-                            final Op op = ops.valueAt(j);
-                            if (op.startNesting > 0) {
-                                op.time[oldPendingState] = now;
-                                op.time[newState] = now;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    public void shutdown() {
-        Slog.w(TAG, "Writing app ops before shutdown...");
-        boolean doWrite = false;
-        synchronized (this) {
-            if (mWriteScheduled) {
-                mWriteScheduled = false;
-                doWrite = true;
-            }
-        }
-        if (doWrite) {
-            writeState();
-        }
-    }
-
-    private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
-        ArrayList<AppOpsManager.OpEntry> resOps = null;
-        final long elapsedNow = SystemClock.elapsedRealtime();
-        if (ops == null) {
-            resOps = new ArrayList<>();
-            for (int j=0; j<pkgOps.size(); j++) {
-                Op curOp = pkgOps.valueAt(j);
-                final boolean running = curOp.duration == -1;
-                long duration = running
-                        ? (elapsedNow - curOp.startRealtime)
-                        : curOp.duration;
-                resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
-                        curOp.rejectTime, (int) duration, running, curOp.proxyUid,
-                        curOp.proxyPackageName));
-            }
-        } else {
-            for (int j=0; j<ops.length; j++) {
-                Op curOp = pkgOps.get(ops[j]);
-                if (curOp != null) {
-                    if (resOps == null) {
-                        resOps = new ArrayList<>();
-                    }
-                    final boolean running = curOp.duration == -1;
-                    final long duration = running
-                            ? (elapsedNow - curOp.startRealtime)
-                            : curOp.duration;
-                    resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
-                            curOp.rejectTime, (int) duration, running, curOp.proxyUid,
-                            curOp.proxyPackageName));
-                }
-            }
-        }
-        return resOps;
-    }
-
-    private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
-        if (uidOps == null) {
-            return null;
-        }
-        ArrayList<AppOpsManager.OpEntry> resOps = null;
-        if (ops == null) {
-            resOps = new ArrayList<>();
-            for (int j=0; j<uidOps.size(); j++) {
-                resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
-                        0, 0, 0, -1, null));
-            }
-        } else {
-            for (int j=0; j<ops.length; j++) {
-                int index = uidOps.indexOfKey(ops[j]);
-                if (index >= 0) {
-                    if (resOps == null) {
-                        resOps = new ArrayList<>();
-                    }
-                    resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
-                            0, 0, 0, -1, null));
-                }
-            }
-        }
-        return resOps;
-    }
-
-    @Override
-    public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
-        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
-                Binder.getCallingPid(), Binder.getCallingUid(), null);
-        ArrayList<AppOpsManager.PackageOps> res = null;
-        synchronized (this) {
-            final int uidStateCount = mUidStates.size();
-            for (int i = 0; i < uidStateCount; i++) {
-                UidState uidState = mUidStates.valueAt(i);
-                if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
-                    continue;
-                }
-                ArrayMap<String, Ops> packages = uidState.pkgOps;
-                final int packageCount = packages.size();
-                for (int j = 0; j < packageCount; j++) {
-                    Ops pkgOps = packages.valueAt(j);
-                    ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
-                    if (resOps != null) {
-                        if (res == null) {
-                            res = new ArrayList<AppOpsManager.PackageOps>();
-                        }
-                        AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
-                                pkgOps.packageName, pkgOps.uidState.uid, resOps);
-                        res.add(resPackage);
-                    }
-                }
-            }
-        }
-        return res;
-    }
-
-    @Override
-    public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
-            int[] ops) {
-        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
-                Binder.getCallingPid(), Binder.getCallingUid(), null);
-        String resolvedPackageName = resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return Collections.emptyList();
-        }
-        synchronized (this) {
-            Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
-                    false /* uidMismatchExpected */);
-            if (pkgOps == null) {
-                return null;
-            }
-            ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
-            if (resOps == null) {
-                return null;
-            }
-            ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
-            AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
-                    pkgOps.packageName, pkgOps.uidState.uid, resOps);
-            res.add(resPackage);
-            return res;
-        }
-    }
-
-    @Override
-    public @Nullable ParceledListSlice getAllHistoricalPackagesOps(@Nullable String[] opNames,
-            long beginTimeMillis, long endTimeMillis) {
-        Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
-                "beginTimeMillis must be non negative and lesser than endTimeMillis");
-
-        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
-                Binder.getCallingPid(), Binder.getCallingUid(), "getAllHistoricalPackagesOps");
-
-        ArrayList<HistoricalPackageOps> historicalPackageOpsList = null;
-
-        final int uidStateCount = mUidStates.size();
-        for (int i = 0; i < uidStateCount; i++) {
-            final UidState uidState = mUidStates.valueAt(i);
-            if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
-                continue;
-            }
-            final ArrayMap<String, Ops> packages = uidState.pkgOps;
-            final int packageCount = packages.size();
-            for (int j = 0; j < packageCount; j++) {
-                final Ops pkgOps = packages.valueAt(j);
-                final AppOpsManager.HistoricalPackageOps historicalPackageOps =
-                        createHistoricalPackageOps(uidState.uid, pkgOps, opNames,
-                                beginTimeMillis, endTimeMillis);
-                if (historicalPackageOps != null) {
-                    if (historicalPackageOpsList == null) {
-                        historicalPackageOpsList = new ArrayList<>();
-                    }
-                    historicalPackageOpsList.add(historicalPackageOps);
-                }
-            }
-        }
-
-        if (historicalPackageOpsList == null) {
-            return null;
-        }
-
-        return new ParceledListSlice<>(historicalPackageOpsList);
-    }
-
-    private static @Nullable HistoricalPackageOps createHistoricalPackageOps(int uid,
-            @Nullable Ops pkgOps, @Nullable String[] opNames, long beginTimeMillis,
-            long endTimeMillis) {
-        // TODO: Implement historical data collection
-        if (pkgOps == null) {
-            return null;
-        }
-
-        final HistoricalPackageOps historicalPackageOps = new HistoricalPackageOps(uid,
-                pkgOps.packageName);
-
-        if (opNames == null) {
-            opNames = AppOpsManager.getOpStrs();
-        }
-        for (String opName : opNames) {
-            addHistoricOpEntry(AppOpsManager.strOpToOp(opName), pkgOps, historicalPackageOps);
-        }
-
-        return historicalPackageOps;
-    }
-
-    @Override
-    public @Nullable HistoricalPackageOps getHistoricalPackagesOps(int uid,
-            @NonNull String packageName, @Nullable String[] opNames,
-            long beginTimeMillis, long endTimeMillis) {
-        Preconditions.checkNotNull(packageName,
-                "packageName cannot be null");
-        Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
-                "beginTimeMillis must be non negative and lesser than endTimeMillis");
-
-        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
-                Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalPackagesOps");
-
-        final String resolvedPackageName = resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return null;
-        }
-
-        // TODO: Implement historical data collection
-        final Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
-                false /* uidMismatchExpected */);
-        return createHistoricalPackageOps(uid, pkgOps, opNames, beginTimeMillis, endTimeMillis);
-    }
-
-    private static void addHistoricOpEntry(int opCode, @NonNull Ops ops,
-            @NonNull HistoricalPackageOps outHistoricalPackageOps) {
-        final Op op = ops.get(opCode);
-        if (op == null) {
-            return;
-        }
-
-        final HistoricalOpEntry historicalOpEntry = new HistoricalOpEntry(opCode);
-
-        // TODO: Keep per UID state duration
-        for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
-            final int acceptCount;
-            final int rejectCount;
-            if (op.rejectTime[uidState] == 0) {
-                acceptCount = 1;
-                rejectCount = 0;
-            } else {
-                acceptCount = 0;
-                rejectCount = 1;
-            }
-            historicalOpEntry.addEntry(uidState, acceptCount, rejectCount, 0);
-        }
-
-        outHistoricalPackageOps.addEntry(historicalOpEntry);
-    }
-
-    @Override
-    public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
-        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
-                Binder.getCallingPid(), Binder.getCallingUid(), null);
-        synchronized (this) {
-            UidState uidState = getUidStateLocked(uid, false);
-            if (uidState == null) {
-                return null;
-            }
-            ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
-            if (resOps == null) {
-                return null;
-            }
-            ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
-            AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
-                    null, uidState.uid, resOps);
-            res.add(resPackage);
-            return res;
-        }
-    }
-
-    private void pruneOp(Op op, int uid, String packageName) {
-        if (!op.hasAnyTime()) {
-            Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
-                    false /* uidMismatchExpected */);
-            if (ops != null) {
-                ops.remove(op.op);
-                if (ops.size() <= 0) {
-                    UidState uidState = ops.uidState;
-                    ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
-                    if (pkgOps != null) {
-                        pkgOps.remove(ops.packageName);
-                        if (pkgOps.isEmpty()) {
-                            uidState.pkgOps = null;
-                        }
-                        if (uidState.isDefault()) {
-                            mUidStates.remove(uid);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
-        if (callingPid == Process.myPid()) {
-            return;
-        }
-        final int callingUser = UserHandle.getUserId(callingUid);
-        synchronized (this) {
-            if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
-                if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
-                    // Profile owners are allowed to change modes but only for apps
-                    // within their user.
-                    return;
-                }
-            }
-        }
-        mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
-                Binder.getCallingPid(), Binder.getCallingUid(), null);
-    }
-
-    @Override
-    public void setUidMode(int code, int uid, int mode) {
-        if (DEBUG) {
-            Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode)
-                    + " by uid " + Binder.getCallingUid());
-        }
-
-        enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
-        verifyIncomingOp(code);
-        code = AppOpsManager.opToSwitch(code);
-
-        synchronized (this) {
-            final int defaultMode = AppOpsManager.opToDefaultMode(code);
-
-            UidState uidState = getUidStateLocked(uid, false);
-            if (uidState == null) {
-                if (mode == defaultMode) {
-                    return;
-                }
-                uidState = new UidState(uid);
-                uidState.opModes = new SparseIntArray();
-                uidState.opModes.put(code, mode);
-                mUidStates.put(uid, uidState);
-                scheduleWriteLocked();
-            } else if (uidState.opModes == null) {
-                if (mode != defaultMode) {
-                    uidState.opModes = new SparseIntArray();
-                    uidState.opModes.put(code, mode);
-                    scheduleWriteLocked();
-                }
-            } else {
-                if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
-                    return;
-                }
-                if (mode == defaultMode) {
-                    uidState.opModes.delete(code);
-                    if (uidState.opModes.size() <= 0) {
-                        uidState.opModes = null;
-                    }
-                } else {
-                    uidState.opModes.put(code, mode);
-                }
-                scheduleWriteLocked();
-            }
-        }
-
-        String[] uidPackageNames = getPackagesForUid(uid);
-        ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
-
-        synchronized (this) {
-            ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
-            if (callbacks != null) {
-                final int callbackCount = callbacks.size();
-                for (int i = 0; i < callbackCount; i++) {
-                    ModeCallback callback = callbacks.valueAt(i);
-                    ArraySet<String> changedPackages = new ArraySet<>();
-                    Collections.addAll(changedPackages, uidPackageNames);
-                    if (callbackSpecs == null) {
-                        callbackSpecs = new ArrayMap<>();
-                    }
-                    callbackSpecs.put(callback, changedPackages);
-                }
-            }
-
-            for (String uidPackageName : uidPackageNames) {
-                callbacks = mPackageModeWatchers.get(uidPackageName);
-                if (callbacks != null) {
-                    if (callbackSpecs == null) {
-                        callbackSpecs = new ArrayMap<>();
-                    }
-                    final int callbackCount = callbacks.size();
-                    for (int i = 0; i < callbackCount; i++) {
-                        ModeCallback callback = callbacks.valueAt(i);
-                        ArraySet<String> changedPackages = callbackSpecs.get(callback);
-                        if (changedPackages == null) {
-                            changedPackages = new ArraySet<>();
-                            callbackSpecs.put(callback, changedPackages);
-                        }
-                        changedPackages.add(uidPackageName);
-                    }
-                }
-            }
-        }
-
-        if (callbackSpecs == null) {
-            return;
-        }
-
-        for (int i = 0; i < callbackSpecs.size(); i++) {
-            final ModeCallback callback = callbackSpecs.keyAt(i);
-            final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
-            if (reportedPackageNames == null) {
-                mHandler.sendMessage(PooledLambda.obtainMessage(
-                        AppOpsService::notifyOpChanged,
-                        this, callback, code, uid, (String) null));
-
-            } else {
-                final int reportedPackageCount = reportedPackageNames.size();
-                for (int j = 0; j < reportedPackageCount; j++) {
-                    final String reportedPackageName = reportedPackageNames.valueAt(j);
-                    mHandler.sendMessage(PooledLambda.obtainMessage(
-                            AppOpsService::notifyOpChanged,
-                            this, callback, code, uid, reportedPackageName));
-                }
-            }
-        }
-    }
-
-    @Override
-    public void setMode(int code, int uid, String packageName, int mode) {
-        setMode(code, uid, packageName, mode, true, false);
-    }
-
-    /**
-     * Sets the mode for a certain op and uid.
-     *
-     * @param code The op code to set
-     * @param uid The UID for which to set
-     * @param packageName The package for which to set
-     * @param mode The new mode to set
-     * @param verifyUid Iff {@code true}, check that the package name belongs to the uid
-     * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid ==
-     *                     false})
-     */
-    private void setMode(int code, int uid, @NonNull String packageName, int mode,
-            boolean verifyUid, boolean isPrivileged) {
-        enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
-        verifyIncomingOp(code);
-        ArraySet<ModeCallback> repCbs = null;
-        code = AppOpsManager.opToSwitch(code);
-        synchronized (this) {
-            UidState uidState = getUidStateLocked(uid, false);
-            Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged);
-            if (op != null) {
-                if (op.mode != mode) {
-                    op.mode = mode;
-                    if (uidState != null) {
-                        uidState.evalForegroundOps(mOpModeWatchers);
-                    }
-                    ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
-                    if (cbs != null) {
-                        if (repCbs == null) {
-                            repCbs = new ArraySet<>();
-                        }
-                        repCbs.addAll(cbs);
-                    }
-                    cbs = mPackageModeWatchers.get(packageName);
-                    if (cbs != null) {
-                        if (repCbs == null) {
-                            repCbs = new ArraySet<>();
-                        }
-                        repCbs.addAll(cbs);
-                    }
-                    if (mode == AppOpsManager.opToDefaultMode(op.op)) {
-                        // If going into the default mode, prune this op
-                        // if there is nothing else interesting in it.
-                        pruneOp(op, uid, packageName);
-                    }
-                    scheduleFastWriteLocked();
-                }
-            }
-        }
-        if (repCbs != null) {
-            mHandler.sendMessage(PooledLambda.obtainMessage(
-                    AppOpsService::notifyOpChanged,
-                    this, repCbs, code, uid, packageName));
-        }
-    }
-
-    private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
-            int uid, String packageName) {
-        for (int i = 0; i < callbacks.size(); i++) {
-            final ModeCallback callback = callbacks.valueAt(i);
-            notifyOpChanged(callback, code, uid, packageName);
-        }
-    }
-
-    private void notifyOpChanged(ModeCallback callback, int code,
-            int uid, String packageName) {
-        if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
-            return;
-        }
-        // There are components watching for mode changes such as window manager
-        // and location manager which are in our process. The callbacks in these
-        // components may require permissions our remote caller does not have.
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            callback.mCallback.opChanged(code, uid, packageName);
-        } catch (RemoteException e) {
-            /* ignore */
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
-            HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
-            int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
-        if (cbs == null) {
-            return callbacks;
-        }
-        if (callbacks == null) {
-            callbacks = new HashMap<>();
-        }
-        boolean duplicate = false;
-        final int N = cbs.size();
-        for (int i=0; i<N; i++) {
-            ModeCallback cb = cbs.valueAt(i);
-            ArrayList<ChangeRec> reports = callbacks.get(cb);
-            if (reports == null) {
-                reports = new ArrayList<>();
-                callbacks.put(cb, reports);
-            } else {
-                final int reportCount = reports.size();
-                for (int j = 0; j < reportCount; j++) {
-                    ChangeRec report = reports.get(j);
-                    if (report.op == op && report.pkg.equals(packageName)) {
-                        duplicate = true;
-                        break;
-                    }
-                }
-            }
-            if (!duplicate) {
-                reports.add(new ChangeRec(op, uid, packageName));
-            }
-        }
-        return callbacks;
-    }
-
-    static final class ChangeRec {
-        final int op;
-        final int uid;
-        final String pkg;
-
-        ChangeRec(int _op, int _uid, String _pkg) {
-            op = _op;
-            uid = _uid;
-            pkg = _pkg;
-        }
-    }
-
-    @Override
-    public void resetAllModes(int reqUserId, String reqPackageName) {
-        final int callingPid = Binder.getCallingPid();
-        final int callingUid = Binder.getCallingUid();
-        reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
-                true, true, "resetAllModes", null);
-
-        int reqUid = -1;
-        if (reqPackageName != null) {
-            try {
-                reqUid = AppGlobals.getPackageManager().getPackageUid(
-                        reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
-            } catch (RemoteException e) {
-                /* ignore - local call */
-            }
-        }
-
-        enforceManageAppOpsModes(callingPid, callingUid, reqUid);
-
-        HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
-        synchronized (this) {
-            boolean changed = false;
-            for (int i = mUidStates.size() - 1; i >= 0; i--) {
-                UidState uidState = mUidStates.valueAt(i);
-
-                SparseIntArray opModes = uidState.opModes;
-                if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
-                    final int uidOpCount = opModes.size();
-                    for (int j = uidOpCount - 1; j >= 0; j--) {
-                        final int code = opModes.keyAt(j);
-                        if (AppOpsManager.opAllowsReset(code)) {
-                            opModes.removeAt(j);
-                            if (opModes.size() <= 0) {
-                                uidState.opModes = null;
-                            }
-                            for (String packageName : getPackagesForUid(uidState.uid)) {
-                                callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
-                                        mOpModeWatchers.get(code));
-                                callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
-                                        mPackageModeWatchers.get(packageName));
-                            }
-                        }
-                    }
-                }
-
-                if (uidState.pkgOps == null) {
-                    continue;
-                }
-
-                if (reqUserId != UserHandle.USER_ALL
-                        && reqUserId != UserHandle.getUserId(uidState.uid)) {
-                    // Skip any ops for a different user
-                    continue;
-                }
-
-                Map<String, Ops> packages = uidState.pkgOps;
-                Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
-                boolean uidChanged = false;
-                while (it.hasNext()) {
-                    Map.Entry<String, Ops> ent = it.next();
-                    String packageName = ent.getKey();
-                    if (reqPackageName != null && !reqPackageName.equals(packageName)) {
-                        // Skip any ops for a different package
-                        continue;
-                    }
-                    Ops pkgOps = ent.getValue();
-                    for (int j=pkgOps.size()-1; j>=0; j--) {
-                        Op curOp = pkgOps.valueAt(j);
-                        if (AppOpsManager.opAllowsReset(curOp.op)
-                                && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
-                            curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
-                            changed = true;
-                            uidChanged = true;
-                            callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
-                                    mOpModeWatchers.get(curOp.op));
-                            callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
-                                    mPackageModeWatchers.get(packageName));
-                            if (!curOp.hasAnyTime()) {
-                                pkgOps.removeAt(j);
-                            }
-                        }
-                    }
-                    if (pkgOps.size() == 0) {
-                        it.remove();
-                    }
-                }
-                if (uidState.isDefault()) {
-                    mUidStates.remove(uidState.uid);
-                }
-                if (uidChanged) {
-                    uidState.evalForegroundOps(mOpModeWatchers);
-                }
-            }
-
-            if (changed) {
-                scheduleFastWriteLocked();
-            }
-        }
-        if (callbacks != null) {
-            for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
-                ModeCallback cb = ent.getKey();
-                ArrayList<ChangeRec> reports = ent.getValue();
-                for (int i=0; i<reports.size(); i++) {
-                    ChangeRec rep = reports.get(i);
-                    mHandler.sendMessage(PooledLambda.obtainMessage(
-                            AppOpsService::notifyOpChanged,
-                            this, cb, rep.op, rep.uid, rep.pkg));
-                }
-            }
-        }
-    }
-
-    private void evalAllForegroundOpsLocked() {
-        for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
-            final UidState uidState = mUidStates.valueAt(uidi);
-            if (uidState.foregroundOps != null) {
-                uidState.evalForegroundOps(mOpModeWatchers);
-            }
-        }
-    }
-
-    @Override
-    public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
-        startWatchingModeWithFlags(op, packageName, 0, callback);
-    }
-
-    @Override
-    public void startWatchingModeWithFlags(int op, String packageName, int flags,
-            IAppOpsCallback callback) {
-        int watchedUid = -1;
-        final int callingUid = Binder.getCallingUid();
-        final int callingPid = Binder.getCallingPid();
-        // TODO: should have a privileged permission to protect this.
-        // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
-        // the USAGE_STATS permission since this can provide information about when an
-        // app is in the foreground?
-        Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
-                AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
-        if (callback == null) {
-            return;
-        }
-        synchronized (this) {
-            op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
-            ModeCallback cb = mModeWatchers.get(callback.asBinder());
-            if (cb == null) {
-                cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
-                mModeWatchers.put(callback.asBinder(), cb);
-            }
-            if (op != AppOpsManager.OP_NONE) {
-                ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
-                if (cbs == null) {
-                    cbs = new ArraySet<>();
-                    mOpModeWatchers.put(op, cbs);
-                }
-                cbs.add(cb);
-            }
-            if (packageName != null) {
-                ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
-                if (cbs == null) {
-                    cbs = new ArraySet<>();
-                    mPackageModeWatchers.put(packageName, cbs);
-                }
-                cbs.add(cb);
-            }
-            evalAllForegroundOpsLocked();
-        }
-    }
-
-    @Override
-    public void stopWatchingMode(IAppOpsCallback callback) {
-        if (callback == null) {
-            return;
-        }
-        synchronized (this) {
-            ModeCallback cb = mModeWatchers.remove(callback.asBinder());
-            if (cb != null) {
-                cb.unlinkToDeath();
-                for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
-                    ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
-                    cbs.remove(cb);
-                    if (cbs.size() <= 0) {
-                        mOpModeWatchers.removeAt(i);
-                    }
-                }
-                for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
-                    ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
-                    cbs.remove(cb);
-                    if (cbs.size() <= 0) {
-                        mPackageModeWatchers.removeAt(i);
-                    }
-                }
-            }
-            evalAllForegroundOpsLocked();
-        }
-    }
-
-    @Override
-    public IBinder getToken(IBinder clientToken) {
-        synchronized (this) {
-            ClientState cs = mClients.get(clientToken);
-            if (cs == null) {
-                cs = new ClientState(clientToken);
-                mClients.put(clientToken, cs);
-            }
-            return cs;
-        }
-    }
-
-    public CheckOpsDelegate getAppOpsServiceDelegate() {
-        synchronized (this) {
-            return mCheckOpsDelegate;
-        }
-    }
-
-    public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
-        synchronized (this) {
-            mCheckOpsDelegate = delegate;
-        }
-    }
-
-    @Override
-    public int checkOperationRaw(int code, int uid, String packageName) {
-        return checkOperationInternal(code, uid, packageName, true /*raw*/);
-    }
-
-    @Override
-    public int checkOperation(int code, int uid, String packageName) {
-        return checkOperationInternal(code, uid, packageName, false /*raw*/);
-    }
-
-    private int checkOperationInternal(int code, int uid, String packageName, boolean raw) {
-        final CheckOpsDelegate delegate;
-        synchronized (this) {
-            delegate = mCheckOpsDelegate;
-        }
-        if (delegate == null) {
-            return checkOperationImpl(code, uid, packageName, raw);
-        }
-        return delegate.checkOperation(code, uid, packageName, raw,
-                    AppOpsService.this::checkOperationImpl);
-    }
-
-    private int checkOperationImpl(int code, int uid, String packageName,
-                boolean raw) {
-        verifyIncomingUid(uid);
-        verifyIncomingOp(code);
-        String resolvedPackageName = resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return AppOpsManager.MODE_IGNORED;
-        }
-        return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
-    }
-
-    private int checkOperationUnchecked(int code, int uid, String packageName,
-                boolean raw) {
-        synchronized (this) {
-            if (isOpRestrictedLocked(uid, code, packageName)) {
-                return AppOpsManager.MODE_IGNORED;
-            }
-            code = AppOpsManager.opToSwitch(code);
-            UidState uidState = getUidStateLocked(uid, false);
-            if (uidState != null && uidState.opModes != null
-                    && uidState.opModes.indexOfKey(code) >= 0) {
-                final int rawMode = uidState.opModes.get(code);
-                return raw ? rawMode : uidState.evalMode(rawMode);
-            }
-            Op op = getOpLocked(code, uid, packageName, false, true, false);
-            if (op == null) {
-                return AppOpsManager.opToDefaultMode(code);
-            }
-            return op.mode;
-        }
-    }
-
-    @Override
-    public int checkAudioOperation(int code, int usage, int uid, String packageName) {
-        final CheckOpsDelegate delegate;
-        synchronized (this) {
-            delegate = mCheckOpsDelegate;
-        }
-        if (delegate == null) {
-            return checkAudioOperationImpl(code, usage, uid, packageName);
-        }
-        return delegate.checkAudioOperation(code, usage, uid, packageName,
-                AppOpsService.this::checkAudioOperationImpl);
-    }
-
-    private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
-        boolean suspended;
-        try {
-            suspended = isPackageSuspendedForUser(packageName, uid);
-        } catch (IllegalArgumentException ex) {
-            // Package not found.
-            suspended = false;
-        }
-
-        if (suspended) {
-            Slog.i(TAG, "Audio disabled for suspended package=" + packageName
-                    + " for uid=" + uid);
-            return AppOpsManager.MODE_IGNORED;
-        }
-
-        synchronized (this) {
-            final int mode = checkRestrictionLocked(code, usage, uid, packageName);
-            if (mode != AppOpsManager.MODE_ALLOWED) {
-                return mode;
-            }
-        }
-        return checkOperation(code, uid, packageName);
-    }
-
-    private boolean isPackageSuspendedForUser(String pkg, int uid) {
-        try {
-            return AppGlobals.getPackageManager().isPackageSuspendedForUser(
-                    pkg, UserHandle.getUserId(uid));
-        } catch (RemoteException re) {
-            throw new SecurityException("Could not talk to package manager service");
-        }
-    }
-
-    private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
-        final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
-        if (usageRestrictions != null) {
-            final Restriction r = usageRestrictions.get(usage);
-            if (r != null && !r.exceptionPackages.contains(packageName)) {
-                return r.mode;
-            }
-        }
-        return AppOpsManager.MODE_ALLOWED;
-    }
-
-    @Override
-    public void setAudioRestriction(int code, int usage, int uid, int mode,
-            String[] exceptionPackages) {
-        enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
-        verifyIncomingUid(uid);
-        verifyIncomingOp(code);
-        synchronized (this) {
-            SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
-            if (usageRestrictions == null) {
-                usageRestrictions = new SparseArray<Restriction>();
-                mAudioRestrictions.put(code, usageRestrictions);
-            }
-            usageRestrictions.remove(usage);
-            if (mode != AppOpsManager.MODE_ALLOWED) {
-                final Restriction r = new Restriction();
-                r.mode = mode;
-                if (exceptionPackages != null) {
-                    final int N = exceptionPackages.length;
-                    r.exceptionPackages = new ArraySet<String>(N);
-                    for (int i = 0; i < N; i++) {
-                        final String pkg = exceptionPackages[i];
-                        if (pkg != null) {
-                            r.exceptionPackages.add(pkg.trim());
-                        }
-                    }
-                }
-                usageRestrictions.put(usage, r);
-            }
-        }
-
-        mHandler.sendMessage(PooledLambda.obtainMessage(
-                AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
-    }
-
-    @Override
-    public int checkPackage(int uid, String packageName) {
-        Preconditions.checkNotNull(packageName);
-        synchronized (this) {
-            Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
-                    true /* uidMismatchExpected */);
-            if (ops != null) {
-                return AppOpsManager.MODE_ALLOWED;
-            } else {
-                return AppOpsManager.MODE_ERRORED;
-            }
-        }
-    }
-
-    @Override
-    public int noteProxyOperation(int code, int proxyUid,
-            String proxyPackageName, int proxiedUid, String proxiedPackageName) {
-        verifyIncomingUid(proxyUid);
-        verifyIncomingOp(code);
-        String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
-        if (resolveProxyPackageName == null) {
-            return AppOpsManager.MODE_IGNORED;
-        }
-        final int proxyMode = noteOperationUnchecked(code, proxyUid,
-                resolveProxyPackageName, -1, null);
-        if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
-            return proxyMode;
-        }
-        String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
-        if (resolveProxiedPackageName == null) {
-            return AppOpsManager.MODE_IGNORED;
-        }
-        return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
-                proxyMode, resolveProxyPackageName);
-    }
-
-    @Override
-    public int noteOperation(int code, int uid, String packageName) {
-        final CheckOpsDelegate delegate;
-        synchronized (this) {
-            delegate = mCheckOpsDelegate;
-        }
-        if (delegate == null) {
-            return noteOperationImpl(code, uid, packageName);
-        }
-        return delegate.noteOperation(code, uid, packageName,
-                AppOpsService.this::noteOperationImpl);
-    }
-
-    private int noteOperationImpl(int code, int uid, String packageName) {
-        verifyIncomingUid(uid);
-        verifyIncomingOp(code);
-        String resolvedPackageName = resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return AppOpsManager.MODE_IGNORED;
-        }
-        return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
-    }
-
-    private int noteOperationUnchecked(int code, int uid, String packageName,
-            int proxyUid, String proxyPackageName) {
-        synchronized (this) {
-            final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
-                    false /* uidMismatchExpected */);
-            if (ops == null) {
-                scheduleOpNotedIfNeededLocked(code, uid, packageName,
-                        AppOpsManager.MODE_IGNORED);
-                if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
-                        + " package " + packageName);
-                return AppOpsManager.MODE_ERRORED;
-            }
-            final Op op = getOpLocked(ops, code, true);
-            if (isOpRestrictedLocked(uid, code, packageName)) {
-                scheduleOpNotedIfNeededLocked(code, uid, packageName,
-                        AppOpsManager.MODE_IGNORED);
-                return AppOpsManager.MODE_IGNORED;
-            }
-            final UidState uidState = ops.uidState;
-            if (op.duration == -1) {
-                Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
-                        + " code " + code + " time=" + op.time[uidState.state]
-                        + " duration=" + op.duration);
-            }
-            op.duration = 0;
-            final int switchCode = AppOpsManager.opToSwitch(code);
-            // If there is a non-default per UID policy (we set UID op mode only if
-            // non-default) it takes over, otherwise use the per package policy.
-            if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
-                final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
-                if (uidMode != AppOpsManager.MODE_ALLOWED) {
-                    if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
-                            + switchCode + " (" + code + ") uid " + uid + " package "
-                            + packageName);
-                    op.rejectTime[uidState.state] = System.currentTimeMillis();
-                    scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
-                    return uidMode;
-                }
-            } else {
-                final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
-                final int mode = switchOp.getMode();
-                if (mode != AppOpsManager.MODE_ALLOWED) {
-                    if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
-                            + switchCode + " (" + code + ") uid " + uid + " package "
-                            + packageName);
-                    op.rejectTime[uidState.state] = System.currentTimeMillis();
-                    scheduleOpNotedIfNeededLocked(op.op, uid, packageName, mode);
-                    return mode;
-                }
-            }
-            if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
-                    + " package " + packageName);
-            op.time[uidState.state] = System.currentTimeMillis();
-            op.rejectTime[uidState.state] = 0;
-            op.proxyUid = proxyUid;
-            op.proxyPackageName = proxyPackageName;
-            scheduleOpNotedIfNeededLocked(code, uid, packageName,
-                    AppOpsManager.MODE_ALLOWED);
-            return AppOpsManager.MODE_ALLOWED;
-        }
-    }
-
-    @Override
-    public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
-        int watchedUid = -1;
-        final int callingUid = Binder.getCallingUid();
-        final int callingPid = Binder.getCallingPid();
-        if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
-                != PackageManager.PERMISSION_GRANTED) {
-            watchedUid = callingUid;
-        }
-        if (ops != null) {
-            Preconditions.checkArrayElementsInRange(ops, 0,
-                    AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
-        }
-        if (callback == null) {
-            return;
-        }
-        synchronized (this) {
-            SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
-            if (callbacks == null) {
-                callbacks = new SparseArray<>();
-                mActiveWatchers.put(callback.asBinder(), callbacks);
-            }
-            final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
-                    callingUid, callingPid);
-            for (int op : ops) {
-                callbacks.put(op, activeCallback);
-            }
-        }
-    }
-
-    @Override
-    public void stopWatchingActive(IAppOpsActiveCallback callback) {
-        if (callback == null) {
-            return;
-        }
-        synchronized (this) {
-            final SparseArray<ActiveCallback> activeCallbacks =
-                    mActiveWatchers.remove(callback.asBinder());
-            if (activeCallbacks == null) {
-                return;
-            }
-            final int callbackCount = activeCallbacks.size();
-            for (int i = 0; i < callbackCount; i++) {
-                activeCallbacks.valueAt(i).destroy();
-            }
-        }
-    }
-
-    @Override
-    public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
-        int watchedUid = Process.INVALID_UID;
-        final int callingUid = Binder.getCallingUid();
-        final int callingPid = Binder.getCallingPid();
-        if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
-                != PackageManager.PERMISSION_GRANTED) {
-            watchedUid = callingUid;
-        }
-        Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
-        Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
-                "Invalid op code in: " + Arrays.toString(ops));
-        Preconditions.checkNotNull(callback, "Callback cannot be null");
-        synchronized (this) {
-            SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
-            if (callbacks == null) {
-                callbacks = new SparseArray<>();
-                mNotedWatchers.put(callback.asBinder(), callbacks);
-            }
-            final NotedCallback notedCallback = new NotedCallback(callback, watchedUid,
-                    callingUid, callingPid);
-            for (int op : ops) {
-                callbacks.put(op, notedCallback);
-            }
-        }
-    }
-
-    @Override
-    public void stopWatchingNoted(IAppOpsNotedCallback callback) {
-        Preconditions.checkNotNull(callback, "Callback cannot be null");
-        synchronized (this) {
-            final SparseArray<NotedCallback> notedCallbacks =
-                    mNotedWatchers.remove(callback.asBinder());
-            if (notedCallbacks == null) {
-                return;
-            }
-            final int callbackCount = notedCallbacks.size();
-            for (int i = 0; i < callbackCount; i++) {
-                notedCallbacks.valueAt(i).destroy();
-            }
-        }
-    }
-
-    @Override
-    public int startOperation(IBinder token, int code, int uid, String packageName,
-            boolean startIfModeDefault) {
-        verifyIncomingUid(uid);
-        verifyIncomingOp(code);
-        String resolvedPackageName = resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return  AppOpsManager.MODE_IGNORED;
-        }
-        ClientState client = (ClientState)token;
-        synchronized (this) {
-            final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
-                    false /* uidMismatchExpected */);
-            if (ops == null) {
-                if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
-                        + " package " + resolvedPackageName);
-                return AppOpsManager.MODE_ERRORED;
-            }
-            final Op op = getOpLocked(ops, code, true);
-            if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
-                return AppOpsManager.MODE_IGNORED;
-            }
-            final int switchCode = AppOpsManager.opToSwitch(code);
-            final UidState uidState = ops.uidState;
-            // If there is a non-default per UID policy (we set UID op mode only if
-            // non-default) it takes over, otherwise use the per package policy.
-            if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
-                final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
-                if (uidMode != AppOpsManager.MODE_ALLOWED
-                        && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
-                    if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
-                            + switchCode + " (" + code + ") uid " + uid + " package "
-                            + resolvedPackageName);
-                    op.rejectTime[uidState.state] = System.currentTimeMillis();
-                    return uidMode;
-                }
-            } else {
-                final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
-                final int mode = switchOp.getMode();
-                if (mode != AppOpsManager.MODE_ALLOWED
-                        && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
-                    if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
-                            + switchCode + " (" + code + ") uid " + uid + " package "
-                            + resolvedPackageName);
-                    op.rejectTime[uidState.state] = System.currentTimeMillis();
-                    return mode;
-                }
-            }
-            if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
-                    + " package " + resolvedPackageName);
-            if (op.startNesting == 0) {
-                op.startRealtime = SystemClock.elapsedRealtime();
-                op.time[uidState.state] = System.currentTimeMillis();
-                op.rejectTime[uidState.state] = 0;
-                op.duration = -1;
-                scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
-            }
-            op.startNesting++;
-            uidState.startNesting++;
-            if (client.mStartedOps != null) {
-                client.mStartedOps.add(op);
-            }
-        }
-
-        return AppOpsManager.MODE_ALLOWED;
-    }
-
-    @Override
-    public void finishOperation(IBinder token, int code, int uid, String packageName) {
-        verifyIncomingUid(uid);
-        verifyIncomingOp(code);
-        String resolvedPackageName = resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return;
-        }
-        if (!(token instanceof ClientState)) {
-            return;
-        }
-        ClientState client = (ClientState) token;
-        synchronized (this) {
-            Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false);
-            if (op == null) {
-                return;
-            }
-            if (!client.mStartedOps.remove(op)) {
-                // We finish ops when packages get removed to guarantee no dangling
-                // started ops. However, some part of the system may asynchronously
-                // finish ops for an already gone package. Hence, finishing an op
-                // for a non existing package is fine and we don't log as a wtf.
-                final long identity = Binder.clearCallingIdentity();
-                try {
-                    if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
-                            resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
-                        Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
-                                + " for non-existing package=" + resolvedPackageName
-                                + " in uid=" + uid);
-                        return;
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-                Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
-                        + op.packageName + " op=" + AppOpsManager.opToName(op.op));
-                return;
-            }
-            finishOperationLocked(op, /*finishNested*/ false);
-            if (op.startNesting <= 0) {
-                scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
-            }
-        }
-    }
-
-    private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
-            boolean active) {
-        ArraySet<ActiveCallback> dispatchedCallbacks = null;
-        final int callbackListCount = mActiveWatchers.size();
-        for (int i = 0; i < callbackListCount; i++) {
-            final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
-            ActiveCallback callback = callbacks.get(code);
-            if (callback != null) {
-                if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
-                    continue;
-                }
-                if (dispatchedCallbacks == null) {
-                    dispatchedCallbacks = new ArraySet<>();
-                }
-                dispatchedCallbacks.add(callback);
-            }
-        }
-        if (dispatchedCallbacks == null) {
-            return;
-        }
-        mHandler.sendMessage(PooledLambda.obtainMessage(
-                AppOpsService::notifyOpActiveChanged,
-                this, dispatchedCallbacks, code, uid, packageName, active));
-    }
-
-    private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
-            int code, int uid, String packageName, boolean active) {
-        // There are components watching for mode changes such as window manager
-        // and location manager which are in our process. The callbacks in these
-        // components may require permissions our remote caller does not have.
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            final int callbackCount = callbacks.size();
-            for (int i = 0; i < callbackCount; i++) {
-                final ActiveCallback callback = callbacks.valueAt(i);
-                try {
-                    callback.mCallback.opActiveChanged(code, uid, packageName, active);
-                } catch (RemoteException e) {
-                    /* do nothing */
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
-            int result) {
-        ArraySet<NotedCallback> dispatchedCallbacks = null;
-        final int callbackListCount = mNotedWatchers.size();
-        for (int i = 0; i < callbackListCount; i++) {
-            final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i);
-            final NotedCallback callback = callbacks.get(code);
-            if (callback != null) {
-                if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
-                    continue;
-                }
-                if (dispatchedCallbacks == null) {
-                    dispatchedCallbacks = new ArraySet<>();
-                }
-                dispatchedCallbacks.add(callback);
-            }
-        }
-        if (dispatchedCallbacks == null) {
-            return;
-        }
-        mHandler.sendMessage(PooledLambda.obtainMessage(
-                AppOpsService::notifyOpChecked,
-                this, dispatchedCallbacks, code, uid, packageName, result));
-    }
-
-    private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
-            int code, int uid, String packageName, int result) {
-        // There are components watching for checks in our process. The callbacks in
-        // these components may require permissions our remote caller does not have.
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            final int callbackCount = callbacks.size();
-            for (int i = 0; i < callbackCount; i++) {
-                final NotedCallback callback = callbacks.valueAt(i);
-                try {
-                    callback.mCallback.opNoted(code, uid, packageName, result);
-                } catch (RemoteException e) {
-                    /* do nothing */
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public int permissionToOpCode(String permission) {
-        if (permission == null) {
-            return AppOpsManager.OP_NONE;
-        }
-        return AppOpsManager.permissionToOpCode(permission);
-    }
-
-    void finishOperationLocked(Op op, boolean finishNested) {
-        if (op.startNesting <= 1 || finishNested) {
-            if (op.startNesting == 1 || finishNested) {
-                op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
-                op.time[op.uidState.state] = System.currentTimeMillis();
-            } else {
-                Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
-                        + op.packageName + " code " + op.op + " time=" + op.time
-                        + " duration=" + op.duration + " nesting=" + op.startNesting);
-            }
-            if (op.startNesting >= 1) {
-                op.uidState.startNesting -= op.startNesting;
-            }
-            op.startNesting = 0;
-        } else {
-            op.startNesting--;
-            op.uidState.startNesting--;
-        }
-    }
-
-    private void verifyIncomingUid(int uid) {
-        if (uid == Binder.getCallingUid()) {
-            return;
-        }
-        if (Binder.getCallingPid() == Process.myPid()) {
-            return;
-        }
-        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
-                Binder.getCallingPid(), Binder.getCallingUid(), null);
-    }
-
-    private void verifyIncomingOp(int op) {
-        if (op >= 0 && op < AppOpsManager._NUM_OP) {
-            return;
-        }
-        throw new IllegalArgumentException("Bad operation #" + op);
-    }
-
-    private UidState getUidStateLocked(int uid, boolean edit) {
-        UidState uidState = mUidStates.get(uid);
-        if (uidState == null) {
-            if (!edit) {
-                return null;
-            }
-            uidState = new UidState(uid);
-            mUidStates.put(uid, uidState);
-        } else {
-            if (uidState.pendingStateCommitTime != 0) {
-                if (uidState.pendingStateCommitTime < mLastRealtime) {
-                    commitUidPendingStateLocked(uidState);
-                } else {
-                    mLastRealtime = SystemClock.elapsedRealtime();
-                    if (uidState.pendingStateCommitTime < mLastRealtime) {
-                        commitUidPendingStateLocked(uidState);
-                    }
-                }
-            }
-        }
-        return uidState;
-    }
-
-    private void commitUidPendingStateLocked(UidState uidState) {
-        final boolean lastForeground = uidState.state <= UID_STATE_LAST_NON_RESTRICTED;
-        final boolean nowForeground = uidState.pendingState <= UID_STATE_LAST_NON_RESTRICTED;
-        uidState.state = uidState.pendingState;
-        uidState.pendingStateCommitTime = 0;
-        if (uidState.hasForegroundWatchers && lastForeground != nowForeground) {
-            for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
-                if (!uidState.foregroundOps.valueAt(fgi)) {
-                    continue;
-                }
-                final int code = uidState.foregroundOps.keyAt(fgi);
-
-                final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
-                if (callbacks != null) {
-                    for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
-                        final ModeCallback callback = callbacks.valueAt(cbi);
-                        if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
-                                || !callback.isWatchingUid(uidState.uid)) {
-                            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--) {
-                                final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
-                                if (doAllPackages || (op != null
-                                        && op.mode == AppOpsManager.MODE_FOREGROUND)) {
-                                    mHandler.sendMessage(PooledLambda.obtainMessage(
-                                            AppOpsService::notifyOpChanged,
-                                            this, callback, code, uidState.uid,
-                                            uidState.pkgOps.keyAt(pkgi)));
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
-            boolean uidMismatchExpected) {
-        UidState uidState = getUidStateLocked(uid, edit);
-        if (uidState == null) {
-            return null;
-        }
-
-        if (uidState.pkgOps == null) {
-            if (!edit) {
-                return null;
-            }
-            uidState.pkgOps = new ArrayMap<>();
-        }
-
-        Ops ops = uidState.pkgOps.get(packageName);
-        if (ops == null) {
-            if (!edit) {
-                return null;
-            }
-            boolean isPrivileged = false;
-            // This is the first time we have seen this package name under this uid,
-            // so let's make sure it is valid.
-            if (uid != 0) {
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    int pkgUid = -1;
-                    try {
-                        ApplicationInfo appInfo = ActivityThread.getPackageManager()
-                                .getApplicationInfo(packageName,
-                                        PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                                        UserHandle.getUserId(uid));
-                        if (appInfo != null) {
-                            pkgUid = appInfo.uid;
-                            isPrivileged = (appInfo.privateFlags
-                                    & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
-                        } else {
-                            pkgUid = resolveUid(packageName);
-                            if (pkgUid >= 0) {
-                                isPrivileged = false;
-                            }
-                        }
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Could not contact PackageManager", e);
-                    }
-                    if (pkgUid != uid) {
-                        // Oops!  The package name is not valid for the uid they are calling
-                        // under.  Abort.
-                        if (!uidMismatchExpected) {
-                            RuntimeException ex = new RuntimeException("here");
-                            ex.fillInStackTrace();
-                            Slog.w(TAG, "Bad call: specified package " + packageName
-                                    + " under uid " + uid + " but it is really " + pkgUid, ex);
-                        }
-                        return null;
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-            }
-            ops = new Ops(packageName, uidState, isPrivileged);
-            uidState.pkgOps.put(packageName, ops);
-        }
-        return ops;
-    }
-
-    /**
-     * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>.
-     *
-     * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
-     *
-     * @param uid The uid the of the package
-     * @param packageName The package name for which to get the state for
-     * @param edit Iff {@code true} create the {@link Ops} object if not yet created
-     * @param isPrivileged Whether the package is privileged or not
-     *
-     * @return The {@link Ops state} of all ops for the package
-     */
-    private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
-            boolean edit, boolean isPrivileged) {
-        UidState uidState = getUidStateLocked(uid, edit);
-        if (uidState == null) {
-            return null;
-        }
-
-        if (uidState.pkgOps == null) {
-            if (!edit) {
-                return null;
-            }
-            uidState.pkgOps = new ArrayMap<>();
-        }
-
-        Ops ops = uidState.pkgOps.get(packageName);
-        if (ops == null) {
-            if (!edit) {
-                return null;
-            }
-            ops = new Ops(packageName, uidState, isPrivileged);
-            uidState.pkgOps.put(packageName, ops);
-        }
-        return ops;
-    }
-
-    private void scheduleWriteLocked() {
-        if (!mWriteScheduled) {
-            mWriteScheduled = true;
-            mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
-        }
-    }
-
-    private void scheduleFastWriteLocked() {
-        if (!mFastWriteScheduled) {
-            mWriteScheduled = true;
-            mFastWriteScheduled = true;
-            mHandler.removeCallbacks(mWriteRunner);
-            mHandler.postDelayed(mWriteRunner, 10*1000);
-        }
-    }
-
-    /**
-     * Get the state of an op for a uid.
-     *
-     * @param code The code of the op
-     * @param uid The uid the of the package
-     * @param packageName The package name for which to get the state for
-     * @param edit Iff {@code true} create the {@link Op} object if not yet created
-     * @param verifyUid Iff {@code true} check that the package belongs to the uid
-     * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid
-     *                     == false})
-     *
-     * @return The {@link Op state} of the op
-     */
-    private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit,
-            boolean verifyUid, boolean isPrivileged) {
-        Ops ops;
-
-        if (verifyUid) {
-            ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */);
-        }  else {
-            ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
-        }
-
-        if (ops == null) {
-            return null;
-        }
-        return getOpLocked(ops, code, edit);
-    }
-
-    private Op getOpLocked(Ops ops, int code, boolean edit) {
-        Op op = ops.get(code);
-        if (op == null) {
-            if (!edit) {
-                return null;
-            }
-            op = new Op(ops.uidState, ops.packageName, code);
-            ops.put(code, op);
-        }
-        if (edit) {
-            scheduleWriteLocked();
-        }
-        return op;
-    }
-
-    private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
-        int userHandle = UserHandle.getUserId(uid);
-        final int restrictionSetCount = mOpUserRestrictions.size();
-
-        for (int i = 0; i < restrictionSetCount; i++) {
-            // For each client, check that the given op is not restricted, or that the given
-            // package is exempt from the restriction.
-            ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
-            if (restrictionState.hasRestriction(code, packageName, userHandle)) {
-                if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
-                    // If we are the system, bypass user restrictions for certain codes
-                    synchronized (this) {
-                        Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
-                                false /* uidMismatchExpected */);
-                        if ((ops != null) && ops.isPrivileged) {
-                            return false;
-                        }
-                    }
-                }
-                return true;
-            }
-        }
-        return false;
-    }
-
-    void readState() {
-        int oldVersion = NO_VERSION;
-        synchronized (mFile) {
-            synchronized (this) {
-                FileInputStream stream;
-                try {
-                    stream = mFile.openRead();
-                } catch (FileNotFoundException e) {
-                    Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
-                    return;
-                }
-                boolean success = false;
-                mUidStates.clear();
-                try {
-                    XmlPullParser parser = Xml.newPullParser();
-                    parser.setInput(stream, StandardCharsets.UTF_8.name());
-                    int type;
-                    while ((type = parser.next()) != XmlPullParser.START_TAG
-                            && type != XmlPullParser.END_DOCUMENT) {
-                        ;
-                    }
-
-                    if (type != XmlPullParser.START_TAG) {
-                        throw new IllegalStateException("no start tag found");
-                    }
-
-                    final String versionString = parser.getAttributeValue(null, "v");
-                    if (versionString != null) {
-                        oldVersion = Integer.parseInt(versionString);
-                    }
-
-                    int outerDepth = parser.getDepth();
-                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                            && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-                        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                            continue;
-                        }
-
-                        String tagName = parser.getName();
-                        if (tagName.equals("pkg")) {
-                            readPackage(parser);
-                        } else if (tagName.equals("uid")) {
-                            readUidOps(parser);
-                        } else {
-                            Slog.w(TAG, "Unknown element under <app-ops>: "
-                                    + parser.getName());
-                            XmlUtils.skipCurrentTag(parser);
-                        }
-                    }
-                    success = true;
-                } catch (IllegalStateException e) {
-                    Slog.w(TAG, "Failed parsing " + e);
-                } catch (NullPointerException e) {
-                    Slog.w(TAG, "Failed parsing " + e);
-                } catch (NumberFormatException e) {
-                    Slog.w(TAG, "Failed parsing " + e);
-                } catch (XmlPullParserException e) {
-                    Slog.w(TAG, "Failed parsing " + e);
-                } catch (IOException e) {
-                    Slog.w(TAG, "Failed parsing " + e);
-                } catch (IndexOutOfBoundsException e) {
-                    Slog.w(TAG, "Failed parsing " + e);
-                } finally {
-                    if (!success) {
-                        mUidStates.clear();
-                    }
-                    try {
-                        stream.close();
-                    } catch (IOException e) {
-                    }
-                }
-            }
-        }
-        synchronized (this) {
-            upgradeLocked(oldVersion);
-        }
-    }
-
-    private void upgradeRunAnyInBackgroundLocked() {
-        for (int i = 0; i < mUidStates.size(); i++) {
-            final UidState uidState = mUidStates.valueAt(i);
-            if (uidState == null) {
-                continue;
-            }
-            if (uidState.opModes != null) {
-                final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
-                if (idx >= 0) {
-                    uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
-                            uidState.opModes.valueAt(idx));
-                }
-            }
-            if (uidState.pkgOps == null) {
-                continue;
-            }
-            boolean changed = false;
-            for (int j = 0; j < uidState.pkgOps.size(); j++) {
-                Ops ops = uidState.pkgOps.valueAt(j);
-                if (ops != null) {
-                    final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
-                    if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
-                        final Op copy = new Op(op.uidState, op.packageName,
-                                AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
-                        copy.mode = op.mode;
-                        ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
-                        changed = true;
-                    }
-                }
-            }
-            if (changed) {
-                uidState.evalForegroundOps(mOpModeWatchers);
-            }
-        }
-    }
-
-    private void upgradeLocked(int oldVersion) {
-        if (oldVersion >= CURRENT_VERSION) {
-            return;
-        }
-        Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
-        switch (oldVersion) {
-            case NO_VERSION:
-                upgradeRunAnyInBackgroundLocked();
-                // fall through
-            case 1:
-                // for future upgrades
-        }
-        scheduleFastWriteLocked();
-    }
-
-    void readUidOps(XmlPullParser parser) throws NumberFormatException,
-            XmlPullParserException, IOException {
-        final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if (tagName.equals("op")) {
-                final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
-                final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
-                UidState uidState = getUidStateLocked(uid, true);
-                if (uidState.opModes == null) {
-                    uidState.opModes = new SparseIntArray();
-                }
-                uidState.opModes.put(code, mode);
-            } else {
-                Slog.w(TAG, "Unknown element under <uid-ops>: "
-                        + parser.getName());
-                XmlUtils.skipCurrentTag(parser);
-            }
-        }
-    }
-
-    void readPackage(XmlPullParser parser) throws NumberFormatException,
-            XmlPullParserException, IOException {
-        String pkgName = parser.getAttributeValue(null, "n");
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if (tagName.equals("uid")) {
-                readUid(parser, pkgName);
-            } else {
-                Slog.w(TAG, "Unknown element under <pkg>: "
-                        + parser.getName());
-                XmlUtils.skipCurrentTag(parser);
-            }
-        }
-    }
-
-    void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
-            XmlPullParserException, IOException {
-        int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
-        String isPrivilegedString = parser.getAttributeValue(null, "p");
-        boolean isPrivileged = false;
-        if (isPrivilegedString == null) {
-            try {
-                IPackageManager packageManager = ActivityThread.getPackageManager();
-                if (packageManager != null) {
-                    ApplicationInfo appInfo = ActivityThread.getPackageManager()
-                            .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
-                    if (appInfo != null) {
-                        isPrivileged = (appInfo.privateFlags
-                                & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
-                    }
-                } else {
-                    // Could not load data, don't add to cache so it will be loaded later.
-                    return;
-                }
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Could not contact PackageManager", e);
-            }
-        } else {
-            isPrivileged = Boolean.parseBoolean(isPrivilegedString);
-        }
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if (tagName.equals("op")) {
-                UidState uidState = getUidStateLocked(uid, true);
-                if (uidState.pkgOps == null) {
-                    uidState.pkgOps = new ArrayMap<>();
-                }
-
-                Op op = new Op(uidState, pkgName,
-                        Integer.parseInt(parser.getAttributeValue(null, "n")));
-
-                for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
-                    final String name = parser.getAttributeName(i);
-                    final String value = parser.getAttributeValue(i);
-                    switch (name) {
-                        case "m":
-                            op.mode = Integer.parseInt(value);
-                            break;
-                        case "d":
-                            op.duration = Integer.parseInt(value);
-                            break;
-                        case "pu":
-                            op.proxyUid = Integer.parseInt(value);
-                            break;
-                        case "pp":
-                            op.proxyPackageName = value;
-                            break;
-                        case "tp":
-                            op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
-                            break;
-                        case "tt":
-                            op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
-                            break;
-                        case "tfs":
-                            op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
-                                    = Long.parseLong(value);
-                            break;
-                        case "tf":
-                            op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
-                            break;
-                        case "tb":
-                            op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
-                            break;
-                        case "tc":
-                            op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
-                            break;
-                        case "rp":
-                            op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT]
-                                    = Long.parseLong(value);
-                            break;
-                        case "rt":
-                            op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
-                            break;
-                        case "rfs":
-                            op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
-                                    = Long.parseLong(value);
-                            break;
-                        case "rf":
-                            op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND]
-                                    = Long.parseLong(value);
-                            break;
-                        case "rb":
-                            op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND]
-                                    = Long.parseLong(value);
-                            break;
-                        case "rc":
-                            op.rejectTime[AppOpsManager.UID_STATE_CACHED]
-                                    = Long.parseLong(value);
-                            break;
-                        case "t":
-                            // Backwards compat.
-                            op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
-                            break;
-                        case "r":
-                            // Backwards compat.
-                            op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
-                            break;
-                        default:
-                            Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
-                            break;
-                    }
-                }
-
-                Ops ops = uidState.pkgOps.get(pkgName);
-                if (ops == null) {
-                    ops = new Ops(pkgName, uidState, isPrivileged);
-                    uidState.pkgOps.put(pkgName, ops);
-                }
-                ops.put(op.op, op);
-            } else {
-                Slog.w(TAG, "Unknown element under <pkg>: "
-                        + parser.getName());
-                XmlUtils.skipCurrentTag(parser);
-            }
-        }
-        UidState uidState = getUidStateLocked(uid, false);
-        if (uidState != null) {
-            uidState.evalForegroundOps(mOpModeWatchers);
-        }
-    }
-
-    void writeState() {
-        synchronized (mFile) {
-            FileOutputStream stream;
-            try {
-                stream = mFile.startWrite();
-            } catch (IOException e) {
-                Slog.w(TAG, "Failed to write state: " + e);
-                return;
-            }
-
-            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
-
-            try {
-                XmlSerializer out = new FastXmlSerializer();
-                out.setOutput(stream, StandardCharsets.UTF_8.name());
-                out.startDocument(null, true);
-                out.startTag(null, "app-ops");
-                out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
-
-                final int uidStateCount = mUidStates.size();
-                for (int i = 0; i < uidStateCount; i++) {
-                    UidState uidState = mUidStates.valueAt(i);
-                    if (uidState.opModes != null && uidState.opModes.size() > 0) {
-                        out.startTag(null, "uid");
-                        out.attribute(null, "n", Integer.toString(uidState.uid));
-                        SparseIntArray uidOpModes = uidState.opModes;
-                        final int opCount = uidOpModes.size();
-                        for (int j = 0; j < opCount; j++) {
-                            final int op = uidOpModes.keyAt(j);
-                            final int mode = uidOpModes.valueAt(j);
-                            out.startTag(null, "op");
-                            out.attribute(null, "n", Integer.toString(op));
-                            out.attribute(null, "m", Integer.toString(mode));
-                            out.endTag(null, "op");
-                        }
-                        out.endTag(null, "uid");
-                    }
-                }
-
-                if (allOps != null) {
-                    String lastPkg = null;
-                    for (int i=0; i<allOps.size(); i++) {
-                        AppOpsManager.PackageOps pkg = allOps.get(i);
-                        if (!pkg.getPackageName().equals(lastPkg)) {
-                            if (lastPkg != null) {
-                                out.endTag(null, "pkg");
-                            }
-                            lastPkg = pkg.getPackageName();
-                            out.startTag(null, "pkg");
-                            out.attribute(null, "n", lastPkg);
-                        }
-                        out.startTag(null, "uid");
-                        out.attribute(null, "n", Integer.toString(pkg.getUid()));
-                        synchronized (this) {
-                            Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
-                                    false /* edit */, false /* uidMismatchExpected */);
-                            // Should always be present as the list of PackageOps is generated
-                            // from Ops.
-                            if (ops != null) {
-                                out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
-                            } else {
-                                out.attribute(null, "p", Boolean.toString(false));
-                            }
-                        }
-                        List<AppOpsManager.OpEntry> ops = pkg.getOps();
-                        for (int j=0; j<ops.size(); j++) {
-                            AppOpsManager.OpEntry op = ops.get(j);
-                            out.startTag(null, "op");
-                            out.attribute(null, "n", Integer.toString(op.getOp()));
-                            if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
-                                out.attribute(null, "m", Integer.toString(op.getMode()));
-                            }
-                            for (int k = 0; k < _NUM_UID_STATE; k++) {
-                                final long time = op.getLastTimeFor(k);
-                                if (time != 0) {
-                                    out.attribute(null, UID_STATE_TIME_ATTRS[k],
-                                            Long.toString(time));
-                                }
-                                final long rejectTime = op.getLastRejectTimeFor(k);
-                                if (rejectTime != 0) {
-                                    out.attribute(null, UID_STATE_REJECT_ATTRS[k],
-                                            Long.toString(rejectTime));
-                                }
-                            }
-                            int dur = op.getDuration();
-                            if (dur != 0) {
-                                out.attribute(null, "d", Integer.toString(dur));
-                            }
-                            int proxyUid = op.getProxyUid();
-                            if (proxyUid != -1) {
-                                out.attribute(null, "pu", Integer.toString(proxyUid));
-                            }
-                            String proxyPackageName = op.getProxyPackageName();
-                            if (proxyPackageName != null) {
-                                out.attribute(null, "pp", proxyPackageName);
-                            }
-                            out.endTag(null, "op");
-                        }
-                        out.endTag(null, "uid");
-                    }
-                    if (lastPkg != null) {
-                        out.endTag(null, "pkg");
-                    }
-                }
-
-                out.endTag(null, "app-ops");
-                out.endDocument();
-                mFile.finishWrite(stream);
-            } catch (IOException e) {
-                Slog.w(TAG, "Failed to write state, restoring backup.", e);
-                mFile.failWrite(stream);
-            }
-        }
-    }
-
-    static class Shell extends ShellCommand {
-        final IAppOpsService mInterface;
-        final AppOpsService mInternal;
-
-        int userId = UserHandle.USER_SYSTEM;
-        String packageName;
-        String opStr;
-        String modeStr;
-        int op;
-        int mode;
-        int packageUid;
-        int nonpackageUid;
-        final static Binder sBinder = new Binder();
-        IBinder mToken;
-
-        Shell(IAppOpsService iface, AppOpsService internal) {
-            mInterface = iface;
-            mInternal = internal;
-            try {
-                mToken = mInterface.getToken(sBinder);
-            } catch (RemoteException e) {
-            }
-        }
-
-        @Override
-        public int onCommand(String cmd) {
-            return onShellCommand(this, cmd);
-        }
-
-        @Override
-        public void onHelp() {
-            PrintWriter pw = getOutPrintWriter();
-            dumpCommandHelp(pw);
-        }
-
-        static private int strOpToOp(String op, PrintWriter err) {
-            try {
-                return AppOpsManager.strOpToOp(op);
-            } catch (IllegalArgumentException e) {
-            }
-            try {
-                return Integer.parseInt(op);
-            } catch (NumberFormatException e) {
-            }
-            try {
-                return AppOpsManager.strDebugOpToOp(op);
-            } catch (IllegalArgumentException e) {
-                err.println("Error: " + e.getMessage());
-                return -1;
-            }
-        }
-
-        static int strModeToMode(String modeStr, PrintWriter err) {
-            for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
-                if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
-                    return i;
-                }
-            }
-            try {
-                return Integer.parseInt(modeStr);
-            } catch (NumberFormatException e) {
-            }
-            err.println("Error: Mode " + modeStr + " is not valid");
-            return -1;
-        }
-
-        int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
-            userId = UserHandle.USER_CURRENT;
-            opStr = null;
-            modeStr = null;
-            for (String argument; (argument = getNextArg()) != null;) {
-                if ("--user".equals(argument)) {
-                    userId = UserHandle.parseUserArg(getNextArgRequired());
-                } else {
-                    if (opStr == null) {
-                        opStr = argument;
-                    } else if (modeStr == null) {
-                        modeStr = argument;
-                        break;
-                    }
-                }
-            }
-            if (opStr == null) {
-                err.println("Error: Operation not specified.");
-                return -1;
-            }
-            op = strOpToOp(opStr, err);
-            if (op < 0) {
-                return -1;
-            }
-            if (modeStr != null) {
-                if ((mode=strModeToMode(modeStr, err)) < 0) {
-                    return -1;
-                }
-            } else {
-                mode = defMode;
-            }
-            return 0;
-        }
-
-        int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
-            userId = UserHandle.USER_CURRENT;
-            packageName = null;
-            opStr = null;
-            for (String argument; (argument = getNextArg()) != null;) {
-                if ("--user".equals(argument)) {
-                    userId = UserHandle.parseUserArg(getNextArgRequired());
-                } else {
-                    if (packageName == null) {
-                        packageName = argument;
-                    } else if (opStr == null) {
-                        opStr = argument;
-                        break;
-                    }
-                }
-            }
-            if (packageName == null) {
-                err.println("Error: Package name not specified.");
-                return -1;
-            } else if (opStr == null && reqOp) {
-                err.println("Error: Operation not specified.");
-                return -1;
-            }
-            if (opStr != null) {
-                op = strOpToOp(opStr, err);
-                if (op < 0) {
-                    return -1;
-                }
-            } else {
-                op = AppOpsManager.OP_NONE;
-            }
-            if (userId == UserHandle.USER_CURRENT) {
-                userId = ActivityManager.getCurrentUser();
-            }
-            nonpackageUid = -1;
-            try {
-                nonpackageUid = Integer.parseInt(packageName);
-            } catch (NumberFormatException e) {
-            }
-            if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
-                    && packageName.indexOf('.') < 0) {
-                int i = 1;
-                while (i < packageName.length() && packageName.charAt(i) >= '0'
-                        && packageName.charAt(i) <= '9') {
-                    i++;
-                }
-                if (i > 1 && i < packageName.length()) {
-                    String userStr = packageName.substring(1, i);
-                    try {
-                        int user = Integer.parseInt(userStr);
-                        char type = packageName.charAt(i);
-                        i++;
-                        int startTypeVal = i;
-                        while (i < packageName.length() && packageName.charAt(i) >= '0'
-                                && packageName.charAt(i) <= '9') {
-                            i++;
-                        }
-                        if (i > startTypeVal) {
-                            String typeValStr = packageName.substring(startTypeVal, i);
-                            try {
-                                int typeVal = Integer.parseInt(typeValStr);
-                                if (type == 'a') {
-                                    nonpackageUid = UserHandle.getUid(user,
-                                            typeVal + Process.FIRST_APPLICATION_UID);
-                                } else if (type == 's') {
-                                    nonpackageUid = UserHandle.getUid(user, typeVal);
-                                }
-                            } catch (NumberFormatException e) {
-                            }
-                        }
-                    } catch (NumberFormatException e) {
-                    }
-                }
-            }
-            if (nonpackageUid != -1) {
-                packageName = null;
-            } else {
-                packageUid = resolveUid(packageName);
-                if (packageUid < 0) {
-                    packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
-                            PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
-                }
-                if (packageUid < 0) {
-                    err.println("Error: No UID for " + packageName + " in user " + userId);
-                    return -1;
-                }
-            }
-            return 0;
-        }
-    }
-
-    @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
-            FileDescriptor err, String[] args, ShellCallback callback,
-            ResultReceiver resultReceiver) {
-        (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
-    }
-
-    static void dumpCommandHelp(PrintWriter pw) {
-        pw.println("AppOps service (appops) commands:");
-        pw.println("  help");
-        pw.println("    Print this help text.");
-        pw.println("  start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
-        pw.println("    Starts a given operation for a particular application.");
-        pw.println("  stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
-        pw.println("    Stops a given operation for a particular application.");
-        pw.println("  set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
-        pw.println("    Set the mode for a particular application and operation.");
-        pw.println("  get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
-        pw.println("    Return the mode for a particular application and optional operation.");
-        pw.println("  query-op [--user <USER_ID>] <OP> [<MODE>]");
-        pw.println("    Print all packages that currently have the given op in the given mode.");
-        pw.println("  reset [--user <USER_ID>] [<PACKAGE>]");
-        pw.println("    Reset the given application or all applications to default modes.");
-        pw.println("  write-settings");
-        pw.println("    Immediately write pending changes to storage.");
-        pw.println("  read-settings");
-        pw.println("    Read the last written settings, replacing current state in RAM.");
-        pw.println("  options:");
-        pw.println("    <PACKAGE> an Android package name.");
-        pw.println("    <OP>      an AppOps operation.");
-        pw.println("    <MODE>    one of allow, ignore, deny, or default");
-        pw.println("    <USER_ID> the user id under which the package is installed. If --user is not");
-        pw.println("              specified, the current user is assumed.");
-    }
-
-    static int onShellCommand(Shell shell, String cmd) {
-        if (cmd == null) {
-            return shell.handleDefaultCommands(cmd);
-        }
-        PrintWriter pw = shell.getOutPrintWriter();
-        PrintWriter err = shell.getErrPrintWriter();
-        try {
-            switch (cmd) {
-                case "set": {
-                    int res = shell.parseUserPackageOp(true, err);
-                    if (res < 0) {
-                        return res;
-                    }
-                    String modeStr = shell.getNextArg();
-                    if (modeStr == null) {
-                        err.println("Error: Mode not specified.");
-                        return -1;
-                    }
-
-                    final int mode = shell.strModeToMode(modeStr, err);
-                    if (mode < 0) {
-                        return -1;
-                    }
-
-                    if (shell.packageName != null) {
-                        shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
-                                mode);
-                    } else {
-                        shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
-                    }
-                    return 0;
-                }
-                case "get": {
-                    int res = shell.parseUserPackageOp(false, err);
-                    if (res < 0) {
-                        return res;
-                    }
-
-                    List<AppOpsManager.PackageOps> ops = new ArrayList<>();
-                    if (shell.packageName != null) {
-                        // Uid mode overrides package mode, so make sure it's also reported
-                        List<AppOpsManager.PackageOps> r = shell.mInterface.getUidOps(
-                                shell.packageUid,
-                                shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
-                        if (r != null) {
-                            ops.addAll(r);
-                        }
-                        r = shell.mInterface.getOpsForPackage(
-                                shell.packageUid, shell.packageName,
-                                shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
-                        if (r != null) {
-                            ops.addAll(r);
-                        }
-                    } else {
-                        ops = shell.mInterface.getUidOps(
-                                shell.nonpackageUid,
-                                shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
-                    }
-                    if (ops == null || ops.size() <= 0) {
-                        pw.println("No operations.");
-                        if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
-                            pw.println("Default mode: " + AppOpsManager.modeToName(
-                                    AppOpsManager.opToDefaultMode(shell.op)));
-                        }
-                        return 0;
-                    }
-                    final long now = System.currentTimeMillis();
-                    for (int i=0; i<ops.size(); i++) {
-                        AppOpsManager.PackageOps packageOps = ops.get(i);
-                        if (packageOps.getPackageName() == null) {
-                            pw.print("Uid mode: ");
-                        }
-                        List<AppOpsManager.OpEntry> entries = packageOps.getOps();
-                        for (int j=0; j<entries.size(); j++) {
-                            AppOpsManager.OpEntry ent = entries.get(j);
-                            pw.print(AppOpsManager.opToName(ent.getOp()));
-                            pw.print(": ");
-                            pw.print(AppOpsManager.modeToName(ent.getMode()));
-                            if (ent.getTime() != 0) {
-                                pw.print("; time=");
-                                TimeUtils.formatDuration(now - ent.getTime(), pw);
-                                pw.print(" ago");
-                            }
-                            if (ent.getRejectTime() != 0) {
-                                pw.print("; rejectTime=");
-                                TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
-                                pw.print(" ago");
-                            }
-                            if (ent.getDuration() == -1) {
-                                pw.print(" (running)");
-                            } else if (ent.getDuration() != 0) {
-                                pw.print("; duration=");
-                                TimeUtils.formatDuration(ent.getDuration(), pw);
-                            }
-                            pw.println();
-                        }
-                    }
-                    return 0;
-                }
-                case "query-op": {
-                    int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
-                    if (res < 0) {
-                        return res;
-                    }
-                    List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
-                            new int[] {shell.op});
-                    if (ops == null || ops.size() <= 0) {
-                        pw.println("No operations.");
-                        return 0;
-                    }
-                    for (int i=0; i<ops.size(); i++) {
-                        final AppOpsManager.PackageOps pkg = ops.get(i);
-                        boolean hasMatch = false;
-                        final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
-                        for (int j=0; j<entries.size(); j++) {
-                            AppOpsManager.OpEntry ent = entries.get(j);
-                            if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
-                                hasMatch = true;
-                                break;
-                            }
-                        }
-                        if (hasMatch) {
-                            pw.println(pkg.getPackageName());
-                        }
-                    }
-                    return 0;
-                }
-                case "reset": {
-                    String packageName = null;
-                    int userId = UserHandle.USER_CURRENT;
-                    for (String argument; (argument = shell.getNextArg()) != null;) {
-                        if ("--user".equals(argument)) {
-                            String userStr = shell.getNextArgRequired();
-                            userId = UserHandle.parseUserArg(userStr);
-                        } else {
-                            if (packageName == null) {
-                                packageName = argument;
-                            } else {
-                                err.println("Error: Unsupported argument: " + argument);
-                                return -1;
-                            }
-                        }
-                    }
-
-                    if (userId == UserHandle.USER_CURRENT) {
-                        userId = ActivityManager.getCurrentUser();
-                    }
-
-                    shell.mInterface.resetAllModes(userId, packageName);
-                    pw.print("Reset all modes for: ");
-                    if (userId == UserHandle.USER_ALL) {
-                        pw.print("all users");
-                    } else {
-                        pw.print("user "); pw.print(userId);
-                    }
-                    pw.print(", ");
-                    if (packageName == null) {
-                        pw.println("all packages");
-                    } else {
-                        pw.print("package "); pw.println(packageName);
-                    }
-                    return 0;
-                }
-                case "write-settings": {
-                    shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
-                            Binder.getCallingUid(), -1);
-                    long token = Binder.clearCallingIdentity();
-                    try {
-                        synchronized (shell.mInternal) {
-                            shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
-                        }
-                        shell.mInternal.writeState();
-                        pw.println("Current settings written.");
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                    }
-                    return 0;
-                }
-                case "read-settings": {
-                    shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
-                            Binder.getCallingUid(), -1);
-                    long token = Binder.clearCallingIdentity();
-                    try {
-                        shell.mInternal.readState();
-                        pw.println("Last settings read.");
-                    } finally {
-                        Binder.restoreCallingIdentity(token);
-                    }
-                    return 0;
-                }
-                case "start": {
-                    int res = shell.parseUserPackageOp(true, err);
-                    if (res < 0) {
-                        return res;
-                    }
-
-                    if (shell.packageName != null) {
-                        shell.mInterface.startOperation(shell.mToken,
-                                shell.op, shell.packageUid, shell.packageName, true);
-                    } else {
-                        return -1;
-                    }
-                    return 0;
-                }
-                case "stop": {
-                    int res = shell.parseUserPackageOp(true, err);
-                    if (res < 0) {
-                        return res;
-                    }
-
-                    if (shell.packageName != null) {
-                        shell.mInterface.finishOperation(shell.mToken,
-                                shell.op, shell.packageUid, shell.packageName);
-                    } else {
-                        return -1;
-                    }
-                    return 0;
-                }
-                default:
-                    return shell.handleDefaultCommands(cmd);
-            }
-        } catch (RemoteException e) {
-            pw.println("Remote exception: " + e);
-        }
-        return -1;
-    }
-
-    private void dumpHelp(PrintWriter pw) {
-        pw.println("AppOps service (appops) dump options:");
-        pw.println("  -h");
-        pw.println("    Print this help text.");
-        pw.println("  --op [OP]");
-        pw.println("    Limit output to data associated with the given app op code.");
-        pw.println("  --mode [MODE]");
-        pw.println("    Limit output to data associated with the given app op mode.");
-        pw.println("  --package [PACKAGE]");
-        pw.println("    Limit output to data associated with the given package name.");
-    }
-
-    private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
-            long now, SimpleDateFormat sdf, Date date) {
-        boolean hasTime = false;
-        for (int i = 0; i < _NUM_UID_STATE; i++) {
-            if (times[i] != 0) {
-                hasTime = true;
-                break;
-            }
-        }
-        if (!hasTime) {
-            return;
-        }
-        boolean first = true;
-        for (int i = 0; i < _NUM_UID_STATE; i++) {
-            if (times[i] != 0) {
-                pw.print(first ? firstPrefix : prefix);
-                first = false;
-                pw.print(UID_STATE_NAMES[i]);
-                pw.print(" = ");
-                date.setTime(times[i]);
-                pw.print(sdf.format(date));
-                pw.print(" (");
-                TimeUtils.formatDuration(times[i]-now, pw);
-                pw.println(")");
-            }
-        }
-    }
-
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
-
-        int dumpOp = -1;
-        String dumpPackage = null;
-        int dumpUid = -1;
-        int dumpMode = -1;
-
-        if (args != null) {
-            for (int i=0; i<args.length; i++) {
-                String arg = args[i];
-                if ("-h".equals(arg)) {
-                    dumpHelp(pw);
-                    return;
-                } else if ("-a".equals(arg)) {
-                    // dump all data
-                } else if ("--op".equals(arg)) {
-                    i++;
-                    if (i >= args.length) {
-                        pw.println("No argument for --op option");
-                        return;
-                    }
-                    dumpOp = Shell.strOpToOp(args[i], pw);
-                    if (dumpOp < 0) {
-                        return;
-                    }
-                } else if ("--package".equals(arg)) {
-                    i++;
-                    if (i >= args.length) {
-                        pw.println("No argument for --package option");
-                        return;
-                    }
-                    dumpPackage = args[i];
-                    try {
-                        dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
-                                PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
-                                0);
-                    } catch (RemoteException e) {
-                    }
-                    if (dumpUid < 0) {
-                        pw.println("Unknown package: " + dumpPackage);
-                        return;
-                    }
-                    dumpUid = UserHandle.getAppId(dumpUid);
-                } else if ("--mode".equals(arg)) {
-                    i++;
-                    if (i >= args.length) {
-                        pw.println("No argument for --mode option");
-                        return;
-                    }
-                    dumpMode = Shell.strModeToMode(args[i], pw);
-                    if (dumpMode < 0) {
-                        return;
-                    }
-                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
-                    pw.println("Unknown option: " + arg);
-                    return;
-                } else {
-                    pw.println("Unknown command: " + arg);
-                    return;
-                }
-            }
-        }
-
-        synchronized (this) {
-            pw.println("Current AppOps Service state:");
-            mConstants.dump(pw);
-            pw.println();
-            final long now = System.currentTimeMillis();
-            final long nowElapsed = SystemClock.elapsedRealtime();
-            final long nowUptime = SystemClock.uptimeMillis();
-            final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
-            final Date date = new Date();
-            boolean needSep = false;
-            if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null) {
-                pw.println("  Profile owners:");
-                for (int poi = 0; poi < mProfileOwners.size(); poi++) {
-                    pw.print("    User #");
-                    pw.print(mProfileOwners.keyAt(poi));
-                    pw.print(": ");
-                    UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
-                    pw.println();
-                }
-                pw.println();
-            }
-            if (mOpModeWatchers.size() > 0) {
-                boolean printedHeader = false;
-                for (int i=0; i<mOpModeWatchers.size(); i++) {
-                    if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
-                        continue;
-                    }
-                    boolean printedOpHeader = false;
-                    ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
-                    for (int j=0; j<callbacks.size(); j++) {
-                        final ModeCallback cb = callbacks.valueAt(j);
-                        if (dumpPackage != null && cb.mWatchingUid >= 0
-                                && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
-                            continue;
-                        }
-                        needSep = true;
-                        if (!printedHeader) {
-                            pw.println("  Op mode watchers:");
-                            printedHeader = true;
-                        }
-                        if (!printedOpHeader) {
-                            pw.print("    Op ");
-                            pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
-                            pw.println(":");
-                            printedOpHeader = true;
-                        }
-                        pw.print("      #"); pw.print(j); pw.print(": ");
-                        pw.println(cb);
-                    }
-                }
-            }
-            if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
-                boolean printedHeader = false;
-                for (int i=0; i<mPackageModeWatchers.size(); i++) {
-                    if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
-                        continue;
-                    }
-                    needSep = true;
-                    if (!printedHeader) {
-                        pw.println("  Package mode watchers:");
-                        printedHeader = true;
-                    }
-                    pw.print("    Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
-                    pw.println(":");
-                    ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
-                    for (int j=0; j<callbacks.size(); j++) {
-                        pw.print("      #"); pw.print(j); pw.print(": ");
-                        pw.println(callbacks.valueAt(j));
-                    }
-                }
-            }
-            if (mModeWatchers.size() > 0 && dumpOp < 0) {
-                boolean printedHeader = false;
-                for (int i=0; i<mModeWatchers.size(); i++) {
-                    final ModeCallback cb = mModeWatchers.valueAt(i);
-                    if (dumpPackage != null && cb.mWatchingUid >= 0
-                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
-                        continue;
-                    }
-                    needSep = true;
-                    if (!printedHeader) {
-                        pw.println("  All op mode watchers:");
-                        printedHeader = true;
-                    }
-                    pw.print("    ");
-                    pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
-                    pw.print(": "); pw.println(cb);
-                }
-            }
-            if (mActiveWatchers.size() > 0 && dumpMode < 0) {
-                needSep = true;
-                boolean printedHeader = false;
-                for (int i = 0; i < mActiveWatchers.size(); i++) {
-                    final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
-                    if (activeWatchers.size() <= 0) {
-                        continue;
-                    }
-                    final ActiveCallback cb = activeWatchers.valueAt(0);
-                    if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
-                        continue;
-                    }
-                    if (dumpPackage != null && cb.mWatchingUid >= 0
-                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
-                        continue;
-                    }
-                    if (!printedHeader) {
-                        pw.println("  All op active watchers:");
-                        printedHeader = true;
-                    }
-                    pw.print("    ");
-                    pw.print(Integer.toHexString(System.identityHashCode(
-                            mActiveWatchers.keyAt(i))));
-                    pw.println(" ->");
-                    pw.print("        [");
-                    final int opCount = activeWatchers.size();
-                    for (i = 0; i < opCount; i++) {
-                        if (i > 0) {
-                            pw.print(' ');
-                        }
-                        pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
-                        if (i < opCount - 1) {
-                            pw.print(',');
-                        }
-                    }
-                    pw.println("]");
-                    pw.print("        ");
-                    pw.println(cb);
-                }
-            }
-            if (mNotedWatchers.size() > 0 && dumpMode < 0) {
-                needSep = true;
-                boolean printedHeader = false;
-                for (int i = 0; i < mNotedWatchers.size(); i++) {
-                    final SparseArray<NotedCallback> notedWatchers = mNotedWatchers.valueAt(i);
-                    if (notedWatchers.size() <= 0) {
-                        continue;
-                    }
-                    final NotedCallback cb = notedWatchers.valueAt(0);
-                    if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
-                        continue;
-                    }
-                    if (dumpPackage != null && cb.mWatchingUid >= 0
-                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
-                        continue;
-                    }
-                    if (!printedHeader) {
-                        pw.println("  All op noted watchers:");
-                        printedHeader = true;
-                    }
-                    pw.print("    ");
-                    pw.print(Integer.toHexString(System.identityHashCode(
-                            mNotedWatchers.keyAt(i))));
-                    pw.println(" ->");
-                    pw.print("        [");
-                    final int opCount = notedWatchers.size();
-                    for (i = 0; i < opCount; i++) {
-                        if (i > 0) {
-                            pw.print(' ');
-                        }
-                        pw.print(AppOpsManager.opToName(notedWatchers.keyAt(i)));
-                        if (i < opCount - 1) {
-                            pw.print(',');
-                        }
-                    }
-                    pw.println("]");
-                    pw.print("        ");
-                    pw.println(cb);
-                }
-            }
-            if (mClients.size() > 0 && dumpMode < 0) {
-                needSep = true;
-                boolean printedHeader = false;
-                for (int i=0; i<mClients.size(); i++) {
-                    boolean printedClient = false;
-                    ClientState cs = mClients.valueAt(i);
-                    if (cs.mStartedOps.size() > 0) {
-                        boolean printedStarted = false;
-                        for (int j=0; j<cs.mStartedOps.size(); j++) {
-                            Op op = cs.mStartedOps.get(j);
-                            if (dumpOp >= 0 && op.op != dumpOp) {
-                                continue;
-                            }
-                            if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
-                                continue;
-                            }
-                            if (!printedHeader) {
-                                pw.println("  Clients:");
-                                printedHeader = true;
-                            }
-                            if (!printedClient) {
-                                pw.print("    "); pw.print(mClients.keyAt(i)); pw.println(":");
-                                pw.print("      "); pw.println(cs);
-                                printedClient = true;
-                            }
-                            if (!printedStarted) {
-                                pw.println("      Started ops:");
-                                printedStarted = true;
-                            }
-                            pw.print("        "); pw.print("uid="); pw.print(op.uid);
-                            pw.print(" pkg="); pw.print(op.packageName);
-                            pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
-                        }
-                    }
-                }
-            }
-            if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
-                    && dumpMode < 0) {
-                boolean printedHeader = false;
-                for (int o=0; o<mAudioRestrictions.size(); o++) {
-                    final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
-                    final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
-                    for (int i=0; i<restrictions.size(); i++) {
-                        if (!printedHeader){
-                            pw.println("  Audio Restrictions:");
-                            printedHeader = true;
-                            needSep = true;
-                        }
-                        final int usage = restrictions.keyAt(i);
-                        pw.print("    "); pw.print(op);
-                        pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
-                        Restriction r = restrictions.valueAt(i);
-                        pw.print(": mode="); pw.println(AppOpsManager.modeToName(r.mode));
-                        if (!r.exceptionPackages.isEmpty()) {
-                            pw.println("      Exceptions:");
-                            for (int j=0; j<r.exceptionPackages.size(); j++) {
-                                pw.print("        "); pw.println(r.exceptionPackages.valueAt(j));
-                            }
-                        }
-                    }
-                }
-            }
-            if (needSep) {
-                pw.println();
-            }
-            for (int i=0; i<mUidStates.size(); i++) {
-                UidState uidState = mUidStates.valueAt(i);
-                final SparseIntArray opModes = uidState.opModes;
-                final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
-
-                if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
-                    boolean hasOp = dumpOp < 0 || (uidState.opModes != null
-                            && uidState.opModes.indexOfKey(dumpOp) >= 0);
-                    boolean hasPackage = dumpPackage == null;
-                    boolean hasMode = dumpMode < 0;
-                    if (!hasMode && opModes != null) {
-                        for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
-                            if (opModes.valueAt(opi) == dumpMode) {
-                                hasMode = true;
-                            }
-                        }
-                    }
-                    if (pkgOps != null) {
-                        for (int pkgi = 0;
-                                (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
-                                pkgi++) {
-                            Ops ops = pkgOps.valueAt(pkgi);
-                            if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
-                                hasOp = true;
-                            }
-                            if (!hasMode) {
-                                for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
-                                    if (ops.valueAt(opi).mode == dumpMode) {
-                                        hasMode = true;
-                                    }
-                                }
-                            }
-                            if (!hasPackage && dumpPackage.equals(ops.packageName)) {
-                                hasPackage = true;
-                            }
-                        }
-                    }
-                    if (uidState.foregroundOps != null && !hasOp) {
-                        if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
-                            hasOp = true;
-                        }
-                    }
-                    if (!hasOp || !hasPackage || !hasMode) {
-                        continue;
-                    }
-                }
-
-                pw.print("  Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
-                pw.print("    state=");
-                pw.println(UID_STATE_NAMES[uidState.state]);
-                if (uidState.state != uidState.pendingState) {
-                    pw.print("    pendingState=");
-                    pw.println(UID_STATE_NAMES[uidState.pendingState]);
-                }
-                if (uidState.pendingStateCommitTime != 0) {
-                    pw.print("    pendingStateCommitTime=");
-                    TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
-                    pw.println();
-                }
-                if (uidState.startNesting != 0) {
-                    pw.print("    startNesting=");
-                    pw.println(uidState.startNesting);
-                }
-                if (uidState.foregroundOps != null && (dumpMode < 0
-                        || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
-                    pw.println("    foregroundOps:");
-                    for (int j = 0; j < uidState.foregroundOps.size(); j++) {
-                        if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
-                            continue;
-                        }
-                        pw.print("      ");
-                        pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
-                        pw.print(": ");
-                        pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
-                    }
-                    pw.print("    hasForegroundWatchers=");
-                    pw.println(uidState.hasForegroundWatchers);
-                }
-                needSep = true;
-
-                if (opModes != null) {
-                    final int opModeCount = opModes.size();
-                    for (int j = 0; j < opModeCount; j++) {
-                        final int code = opModes.keyAt(j);
-                        final int mode = opModes.valueAt(j);
-                        if (dumpOp >= 0 && dumpOp != code) {
-                            continue;
-                        }
-                        if (dumpMode >= 0 && dumpMode != mode) {
-                            continue;
-                        }
-                        pw.print("      "); pw.print(AppOpsManager.opToName(code));
-                        pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
-                    }
-                }
-
-                if (pkgOps == null) {
-                    continue;
-                }
-
-                for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
-                    final Ops ops = pkgOps.valueAt(pkgi);
-                    if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
-                        continue;
-                    }
-                    boolean printedPackage = false;
-                    for (int j=0; j<ops.size(); j++) {
-                        final Op op = ops.valueAt(j);
-                        if (dumpOp >= 0 && dumpOp != op.op) {
-                            continue;
-                        }
-                        if (dumpMode >= 0 && dumpMode != op.mode) {
-                            continue;
-                        }
-                        if (!printedPackage) {
-                            pw.print("    Package "); pw.print(ops.packageName); pw.println(":");
-                            printedPackage = true;
-                        }
-                        pw.print("      "); pw.print(AppOpsManager.opToName(op.op));
-                        pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
-                        final int switchOp = AppOpsManager.opToSwitch(op.op);
-                        if (switchOp != op.op) {
-                            pw.print(" / switch ");
-                            pw.print(AppOpsManager.opToName(switchOp));
-                            final Op switchObj = ops.get(switchOp);
-                            int mode = switchObj != null
-                                    ? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
-                            pw.print("="); pw.print(AppOpsManager.modeToName(mode));
-                        }
-                        pw.println("): ");
-                        dumpTimesLocked(pw,
-                                "          Access: ",
-                                "                  ", op.time, now, sdf, date);
-                        dumpTimesLocked(pw,
-                                "          Reject: ",
-                                "                  ", op.rejectTime, now, sdf, date);
-                        if (op.duration == -1) {
-                            pw.print("          Running start at: ");
-                            TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
-                            pw.println();
-                        } else if (op.duration != 0) {
-                            pw.print("          duration=");
-                            TimeUtils.formatDuration(op.duration, pw);
-                            pw.println();
-                        }
-                        if (op.startNesting != 0) {
-                            pw.print("          startNesting=");
-                            pw.println(op.startNesting);
-                        }
-                    }
-                }
-            }
-            if (needSep) {
-                pw.println();
-            }
-
-            final int userRestrictionCount = mOpUserRestrictions.size();
-            for (int i = 0; i < userRestrictionCount; i++) {
-                IBinder token = mOpUserRestrictions.keyAt(i);
-                ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
-                pw.println("  User restrictions for token " + token + ":");
-
-                final int restrictionCount = restrictionState.perUserRestrictions != null
-                        ? restrictionState.perUserRestrictions.size() : 0;
-                if (restrictionCount > 0) {
-                    pw.println("      Restricted ops:");
-                    for (int j = 0; j < restrictionCount; j++) {
-                        int userId = restrictionState.perUserRestrictions.keyAt(j);
-                        boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
-                        if (restrictedOps == null) {
-                            continue;
-                        }
-                        StringBuilder restrictedOpsValue = new StringBuilder();
-                        restrictedOpsValue.append("[");
-                        final int restrictedOpCount = restrictedOps.length;
-                        for (int k = 0; k < restrictedOpCount; k++) {
-                            if (restrictedOps[k]) {
-                                if (restrictedOpsValue.length() > 1) {
-                                    restrictedOpsValue.append(", ");
-                                }
-                                restrictedOpsValue.append(AppOpsManager.opToName(k));
-                            }
-                        }
-                        restrictedOpsValue.append("]");
-                        pw.print("        "); pw.print("user: "); pw.print(userId);
-                                pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
-                    }
-                }
-
-                final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
-                        ? restrictionState.perUserExcludedPackages.size() : 0;
-                if (excludedPackageCount > 0) {
-                    pw.println("      Excluded packages:");
-                    for (int j = 0; j < excludedPackageCount; j++) {
-                        int userId = restrictionState.perUserExcludedPackages.keyAt(j);
-                        String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
-                        pw.print("        "); pw.print("user: "); pw.print(userId);
-                                pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
-                    }
-                }
-            }
-        }
-    }
-
-    private static final class Restriction {
-        private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
-        int mode;
-        ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
-    }
-
-    @Override
-    public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
-        checkSystemUid("setUserRestrictions");
-        Preconditions.checkNotNull(restrictions);
-        Preconditions.checkNotNull(token);
-        for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
-            String restriction = AppOpsManager.opToRestriction(i);
-            if (restriction != null) {
-                setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
-                        userHandle, null);
-            }
-        }
-    }
-
-    @Override
-    public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
-            String[] exceptionPackages) {
-        if (Binder.getCallingPid() != Process.myPid()) {
-            mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
-                    Binder.getCallingPid(), Binder.getCallingUid(), null);
-        }
-        if (userHandle != UserHandle.getCallingUserId()) {
-            if (mContext.checkCallingOrSelfPermission(Manifest.permission
-                    .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
-                && mContext.checkCallingOrSelfPermission(Manifest.permission
-                    .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
-                throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
-                        + " INTERACT_ACROSS_USERS to interact cross user ");
-            }
-        }
-        verifyIncomingOp(code);
-        Preconditions.checkNotNull(token);
-        setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
-    }
-
-    private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
-            int userHandle, String[] exceptionPackages) {
-        synchronized (AppOpsService.this) {
-            ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
-
-            if (restrictionState == null) {
-                try {
-                    restrictionState = new ClientRestrictionState(token);
-                } catch (RemoteException e) {
-                    return;
-                }
-                mOpUserRestrictions.put(token, restrictionState);
-            }
-
-            if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
-                mHandler.sendMessage(PooledLambda.obtainMessage(
-                        AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
-            }
-
-            if (restrictionState.isDefault()) {
-                mOpUserRestrictions.remove(token);
-                restrictionState.destroy();
-            }
-        }
-    }
-
-    private void notifyWatchersOfChange(int code, int uid) {
-        final ArraySet<ModeCallback> clonedCallbacks;
-        synchronized (this) {
-            ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
-            if (callbacks == null) {
-                return;
-            }
-            clonedCallbacks = new ArraySet<>(callbacks);
-        }
-
-        notifyOpChanged(clonedCallbacks,  code, uid, null);
-    }
-
-    @Override
-    public void removeUser(int userHandle) throws RemoteException {
-        checkSystemUid("removeUser");
-        synchronized (AppOpsService.this) {
-            final int tokenCount = mOpUserRestrictions.size();
-            for (int i = tokenCount - 1; i >= 0; i--) {
-                ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
-                opRestrictions.removeUser(userHandle);
-            }
-            removeUidsForUserLocked(userHandle);
-        }
-    }
-
-    @Override
-    public boolean isOperationActive(int code, int uid, String packageName) {
-        if (Binder.getCallingUid() != uid) {
-            if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
-                    != PackageManager.PERMISSION_GRANTED) {
-                return false;
-            }
-        }
-        verifyIncomingOp(code);
-        final String resolvedPackageName = resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return false;
-        }
-        synchronized (AppOpsService.this) {
-            for (int i = mClients.size() - 1; i >= 0; i--) {
-                final ClientState client = mClients.valueAt(i);
-                for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
-                    final Op op = client.mStartedOps.get(j);
-                    if (op.op == code && op.uid == uid) return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private void removeUidsForUserLocked(int userHandle) {
-        for (int i = mUidStates.size() - 1; i >= 0; --i) {
-            final int uid = mUidStates.keyAt(i);
-            if (UserHandle.getUserId(uid) == userHandle) {
-                mUidStates.removeAt(i);
-            }
-        }
-    }
-
-    private void checkSystemUid(String function) {
-        int uid = Binder.getCallingUid();
-        if (uid != Process.SYSTEM_UID) {
-            throw new SecurityException(function + " must by called by the system");
-        }
-    }
-
-    private static String resolvePackageName(int uid, String packageName)  {
-        if (uid == Process.ROOT_UID) {
-            return "root";
-        } else if (uid == Process.SHELL_UID) {
-            return "com.android.shell";
-        } else if (uid == Process.MEDIA_UID) {
-            return "media";
-        } else if (uid == Process.AUDIOSERVER_UID) {
-            return "audioserver";
-        } else if (uid == Process.CAMERASERVER_UID) {
-            return "cameraserver";
-        } else if (uid == Process.SYSTEM_UID && packageName == null) {
-            return "android";
-        }
-        return packageName;
-    }
-
-    private static int resolveUid(String packageName)  {
-        if (packageName == null) {
-            return -1;
-        }
-        switch (packageName) {
-            case "root":
-                return Process.ROOT_UID;
-            case "shell":
-                return Process.SHELL_UID;
-            case "media":
-                return Process.MEDIA_UID;
-            case "audioserver":
-                return Process.AUDIOSERVER_UID;
-            case "cameraserver":
-                return Process.CAMERASERVER_UID;
-        }
-        return -1;
-    }
-
-    private static String[] getPackagesForUid(int uid) {
-        String[] packageNames = null;
-
-        // Very early during boot the package manager is not yet or not yet fully started. At this
-        // time there are no packages yet.
-        if (AppGlobals.getPackageManager() != null) {
-            try {
-                packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
-            } catch (RemoteException e) {
-                /* ignore - local call */
-            }
-        }
-        if (packageNames == null) {
-            return EmptyArray.STRING;
-        }
-        return packageNames;
-    }
-
-    private final class ClientRestrictionState implements DeathRecipient {
-        private final IBinder token;
-        SparseArray<boolean[]> perUserRestrictions;
-        SparseArray<String[]> perUserExcludedPackages;
-
-        public ClientRestrictionState(IBinder token)
-                throws RemoteException {
-            token.linkToDeath(this, 0);
-            this.token = token;
-        }
-
-        public boolean setRestriction(int code, boolean restricted,
-                String[] excludedPackages, int userId) {
-            boolean changed = false;
-
-            if (perUserRestrictions == null && restricted) {
-                perUserRestrictions = new SparseArray<>();
-            }
-
-            int[] users;
-            if (userId == UserHandle.USER_ALL) {
-                List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
-
-                users = new int[liveUsers.size()];
-                for (int i = 0; i < liveUsers.size(); i++) {
-                    users[i] = liveUsers.get(i).id;
-                }
-            } else {
-                users = new int[]{userId};
-            }
-
-            if (perUserRestrictions != null) {
-                int numUsers = users.length;
-
-                for (int i = 0; i < numUsers; i++) {
-                    int thisUserId = users[i];
-
-                    boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
-                    if (userRestrictions == null && restricted) {
-                        userRestrictions = new boolean[AppOpsManager._NUM_OP];
-                        perUserRestrictions.put(thisUserId, userRestrictions);
-                    }
-                    if (userRestrictions != null && userRestrictions[code] != restricted) {
-                        userRestrictions[code] = restricted;
-                        if (!restricted && isDefault(userRestrictions)) {
-                            perUserRestrictions.remove(thisUserId);
-                            userRestrictions = null;
-                        }
-                        changed = true;
-                    }
-
-                    if (userRestrictions != null) {
-                        final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
-                        if (perUserExcludedPackages == null && !noExcludedPackages) {
-                            perUserExcludedPackages = new SparseArray<>();
-                        }
-                        if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
-                                perUserExcludedPackages.get(thisUserId))) {
-                            if (noExcludedPackages) {
-                                perUserExcludedPackages.remove(thisUserId);
-                                if (perUserExcludedPackages.size() <= 0) {
-                                    perUserExcludedPackages = null;
-                                }
-                            } else {
-                                perUserExcludedPackages.put(thisUserId, excludedPackages);
-                            }
-                            changed = true;
-                        }
-                    }
-                }
-            }
-
-            return changed;
-        }
-
-        public boolean hasRestriction(int restriction, String packageName, int userId) {
-            if (perUserRestrictions == null) {
-                return false;
-            }
-            boolean[] restrictions = perUserRestrictions.get(userId);
-            if (restrictions == null) {
-                return false;
-            }
-            if (!restrictions[restriction]) {
-                return false;
-            }
-            if (perUserExcludedPackages == null) {
-                return true;
-            }
-            String[] perUserExclusions = perUserExcludedPackages.get(userId);
-            if (perUserExclusions == null) {
-                return true;
-            }
-            return !ArrayUtils.contains(perUserExclusions, packageName);
-        }
-
-        public void removeUser(int userId) {
-            if (perUserExcludedPackages != null) {
-                perUserExcludedPackages.remove(userId);
-                if (perUserExcludedPackages.size() <= 0) {
-                    perUserExcludedPackages = null;
-                }
-            }
-            if (perUserRestrictions != null) {
-                perUserRestrictions.remove(userId);
-                if (perUserRestrictions.size() <= 0) {
-                    perUserRestrictions = null;
-                }
-            }
-        }
-
-        public boolean isDefault() {
-            return perUserRestrictions == null || perUserRestrictions.size() <= 0;
-        }
-
-        @Override
-        public void binderDied() {
-            synchronized (AppOpsService.this) {
-                mOpUserRestrictions.remove(token);
-                if (perUserRestrictions == null) {
-                    return;
-                }
-                final int userCount = perUserRestrictions.size();
-                for (int i = 0; i < userCount; i++) {
-                    final boolean[] restrictions = perUserRestrictions.valueAt(i);
-                    final int restrictionCount = restrictions.length;
-                    for (int j = 0; j < restrictionCount; j++) {
-                        if (restrictions[j]) {
-                            final int changedCode = j;
-                            mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
-                        }
-                    }
-                }
-                destroy();
-            }
-        }
-
-        public void destroy() {
-            token.unlinkToDeath(this, 0);
-        }
-
-        private boolean isDefault(boolean[] array) {
-            if (ArrayUtils.isEmpty(array)) {
-                return true;
-            }
-            for (boolean value : array) {
-                if (value) {
-                    return false;
-                }
-            }
-            return true;
-        }
-    }
-
-    private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
-        @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
-            synchronized (AppOpsService.this) {
-                mProfileOwners = owners;
-            }
-        }
-
-        @Override
-        public void setUidMode(int code, int uid, int mode) {
-            AppOpsService.this.setUidMode(code, uid, mode);
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 7bbc543..c4bc52c 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -208,6 +208,8 @@
     private int mErrorRecoveryRetryCounter;
     private final int mSystemUiUid;
 
+    private boolean mIsHearingAidProfileSupported;
+
     // Save a ProfileServiceConnections object for each of the bound
     // bluetooth profile services
     private final Map<Integer, ProfileServiceConnections> mProfileServices = new HashMap<>();
@@ -279,7 +281,7 @@
 
                 Slog.d(TAG,
                         "Airplane Mode change - current state:  " + BluetoothAdapter.nameForState(
-                                st));
+                                st) + ", isAirplaneModeOn()=" + isAirplaneModeOn());
 
                 if (isAirplaneModeOn()) {
                     // Clear registered LE apps to force shut-off
@@ -391,13 +393,19 @@
         mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
         mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
 
+        mIsHearingAidProfileSupported = context.getResources()
+                .getBoolean(com.android.internal.R.bool.config_hearing_aid_profile_supported);
+
         // TODO: We need a more generic way to initialize the persist keys of FeatureFlagUtils
-        boolean isHearingAidEnabled;
         String value = SystemProperties.get(FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.HEARING_AID_SETTINGS);
         if (!TextUtils.isEmpty(value)) {
-            isHearingAidEnabled = Boolean.parseBoolean(value);
+            boolean isHearingAidEnabled = Boolean.parseBoolean(value);
             Log.v(TAG, "set feature flag HEARING_AID_SETTINGS to " + isHearingAidEnabled);
             FeatureFlagUtils.setEnabled(context, FeatureFlagUtils.HEARING_AID_SETTINGS, isHearingAidEnabled);
+            if (isHearingAidEnabled && !mIsHearingAidProfileSupported) {
+                // Overwrite to enable support by FeatureFlag
+                mIsHearingAidProfileSupported = true;
+            }
         }
 
         IntentFilter filter = new IntentFilter();
@@ -679,6 +687,11 @@
         return false;
     }
 
+    @Override
+    public boolean isHearingAidProfileSupported() {
+        return mIsHearingAidProfileSupported;
+    }
+
     // Monitor change of BLE scan only mode settings.
     private void registerForBleScanModeChange() {
         ContentObserver contentObserver = new ContentObserver(null) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 66ceae4..fda7279 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -25,6 +25,7 @@
 import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.ConnectivityManager.isNetworkTypeValid;
+import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
@@ -37,6 +38,8 @@
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkPolicyManager.RULE_NONE;
 import static android.net.NetworkPolicyManager.uidRulesToString;
+import static android.net.NetworkStack.NETWORKSTACK_PACKAGE_NAME;
+import static android.net.shared.NetworkMonitorUtils.isValidationRequired;
 import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.IPPROTO_TCP;
 import static android.system.OsConstants.IPPROTO_UDP;
@@ -62,12 +65,15 @@
 import android.net.INetd;
 import android.net.INetdEventCallback;
 import android.net.INetworkManagementEventObserver;
+import android.net.INetworkMonitor;
+import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkPolicyListener;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
 import android.net.LinkProperties;
 import android.net.LinkProperties.CompareResult;
 import android.net.MatchAllNetworkSpecifier;
+import android.net.NattSocketKeepalive;
 import android.net.Network;
 import android.net.NetworkAgent;
 import android.net.NetworkCapabilities;
@@ -79,9 +85,11 @@
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
+import android.net.NetworkStack;
 import android.net.NetworkState;
 import android.net.NetworkUtils;
 import android.net.NetworkWatchlistManager;
+import android.net.PrivateDnsConfigParcel;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
 import android.net.UidRange;
@@ -90,12 +98,13 @@
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.NetworkEvent;
 import android.net.netlink.InetDiagMessage;
+import android.net.shared.NetworkMonitorUtils;
+import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
-import android.net.util.NetdService;
+import android.net.shared.NetdService;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -123,8 +132,8 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.LocalLog;
-import android.util.LocalLog.ReadOnlyLocalLog;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -149,7 +158,6 @@
 import com.android.server.am.BatteryStatsService;
 import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.connectivity.DnsManager;
-import com.android.server.connectivity.DnsManager.PrivateDnsConfig;
 import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
 import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.KeepaliveTracker;
@@ -158,7 +166,6 @@
 import com.android.server.connectivity.MultipathPolicyTracker;
 import com.android.server.connectivity.NetworkAgentInfo;
 import com.android.server.connectivity.NetworkDiagnostics;
-import com.android.server.connectivity.NetworkMonitor;
 import com.android.server.connectivity.NetworkNotificationManager;
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 import com.android.server.connectivity.PermissionMonitor;
@@ -186,7 +193,6 @@
 import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -442,6 +448,43 @@
      */
     private static final int EVENT_DATA_SAVER_CHANGED = 40;
 
+     /**
+      * Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has
+      * been tested.
+      * obj = String representing URL that Internet probe was redirect to, if it was redirected.
+      * arg1 = One of the NETWORK_TESTED_RESULT_* constants.
+      * arg2 = NetID.
+      */
+    public static final int EVENT_NETWORK_TESTED = 41;
+
+    /**
+     * Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the private DNS
+     * config was resolved.
+     * obj = PrivateDnsConfig
+     * arg2 = netid
+     */
+    public static final int EVENT_PRIVATE_DNS_CONFIG_RESOLVED = 42;
+
+    /**
+     * Request ConnectivityService display provisioning notification.
+     * arg1    = Whether to make the notification visible.
+     * arg2    = NetID.
+     * obj     = Intent to be launched when notification selected by user, null if !arg1.
+     */
+    public static final int EVENT_PROVISIONING_NOTIFICATION = 43;
+
+    /**
+     * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
+     * should be shown.
+     */
+    public static final int PROVISIONING_NOTIFICATION_SHOW = 1;
+
+    /**
+     * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
+     * should be hidden.
+     */
+    public static final int PROVISIONING_NOTIFICATION_HIDE = 0;
+
     private static String eventName(int what) {
         return sMagicDecoderRing.get(what, Integer.toString(what));
     }
@@ -506,30 +549,6 @@
     private long mMaxWakelockDurationMs = 0;
     private long mLastWakeLockAcquireTimestamp = 0;
 
-    // Array of <Network,ReadOnlyLocalLogs> tracking network validation and results
-    private static final int MAX_VALIDATION_LOGS = 10;
-    private static class ValidationLog {
-        final Network mNetwork;
-        final String mName;
-        final ReadOnlyLocalLog mLog;
-
-        ValidationLog(Network network, String name, ReadOnlyLocalLog log) {
-            mNetwork = network;
-            mName = name;
-            mLog = log;
-        }
-    }
-    private final ArrayDeque<ValidationLog> mValidationLogs = new ArrayDeque<>(MAX_VALIDATION_LOGS);
-
-    private void addValidationLogs(ReadOnlyLocalLog log, Network network, String name) {
-        synchronized (mValidationLogs) {
-            while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) {
-                mValidationLogs.removeLast();
-            }
-            mValidationLogs.addFirst(new ValidationLog(network, name, log));
-        }
-    }
-
     private final IpConnectivityLog mMetricsLog;
 
     @GuardedBy("mBandwidthRequests")
@@ -1476,6 +1495,9 @@
             newNc.setUids(null);
             newNc.setSSID(null);
         }
+        if (newNc.getNetworkSpecifier() != null) {
+            newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
+        }
         return newNc;
     }
 
@@ -1684,7 +1706,11 @@
             // caller type. Need to re-factor NetdEventListenerService to allow multiple
             // NetworkMonitor registrants.
             if (nai != null && nai.satisfies(mDefaultRequest)) {
-                nai.networkMonitor.sendMessage(NetworkMonitor.EVENT_DNS_NOTIFICATION, returnCode);
+                try {
+                    nai.networkMonitor().notifyDnsResponse(returnCode);
+                } catch (RemoteException e) {
+                    e.rethrowFromSystemServer();
+                }
             }
         }
     };
@@ -2266,17 +2292,6 @@
 
         if (ArrayUtils.contains(args, SHORT_ARG) == false) {
             pw.println();
-            synchronized (mValidationLogs) {
-                pw.println("mValidationLogs (most recent first):");
-                for (ValidationLog p : mValidationLogs) {
-                    pw.println(p.mNetwork + " - " + p.mName);
-                    pw.increaseIndent();
-                    p.mLog.dump(fd, pw, args);
-                    pw.decreaseIndent();
-                }
-            }
-
-            pw.println();
             pw.println("mNetworkRequestInfoLogs (most recent first):");
             pw.increaseIndent();
             mNetworkRequestInfoLogs.reverseDump(fd, pw, args);
@@ -2455,11 +2470,11 @@
             switch (msg.what) {
                 default:
                     return false;
-                case NetworkMonitor.EVENT_NETWORK_TESTED: {
+                case EVENT_NETWORK_TESTED: {
                     final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
                     if (nai == null) break;
 
-                    final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
+                    final boolean valid = (msg.arg1 == NETWORK_TEST_RESULT_VALID);
                     final boolean wasValidated = nai.lastValidated;
                     final boolean wasDefault = isDefaultNetwork(nai);
 
@@ -2497,7 +2512,7 @@
                     }
                     break;
                 }
-                case NetworkMonitor.EVENT_PROVISIONING_NOTIFICATION: {
+                case EVENT_PROVISIONING_NOTIFICATION: {
                     final int netId = msg.arg2;
                     final boolean visible = toBool(msg.arg1);
                     final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
@@ -2530,7 +2545,7 @@
                     }
                     break;
                 }
-                case NetworkMonitor.EVENT_PRIVATE_DNS_CONFIG_RESOLVED: {
+                case EVENT_PRIVATE_DNS_CONFIG_RESOLVED: {
                     final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
                     if (nai == null) break;
 
@@ -2572,9 +2587,61 @@
         }
     }
 
+    private class NetworkMonitorCallbacks extends INetworkMonitorCallbacks.Stub {
+        private final NetworkAgentInfo mNai;
+
+        private NetworkMonitorCallbacks(NetworkAgentInfo nai) {
+            mNai = nai;
+        }
+
+        @Override
+        public void onNetworkMonitorCreated(INetworkMonitor networkMonitor) {
+            mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT,
+                    new Pair<>(mNai, networkMonitor)));
+        }
+
+        @Override
+        public void notifyNetworkTested(int testResult, @Nullable String redirectUrl) {
+            mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(EVENT_NETWORK_TESTED,
+                    testResult, mNai.network.netId, redirectUrl));
+        }
+
+        @Override
+        public void notifyPrivateDnsConfigResolved(PrivateDnsConfigParcel config) {
+            mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
+                    EVENT_PRIVATE_DNS_CONFIG_RESOLVED,
+                    0, mNai.network.netId, PrivateDnsConfig.fromParcel(config)));
+        }
+
+        @Override
+        public void showProvisioningNotification(String action) {
+            final Intent intent = new Intent(action);
+            intent.setPackage(NETWORKSTACK_PACKAGE_NAME);
+
+            final PendingIntent pendingIntent;
+            // Only the system server can register notifications with package "android"
+            final long token = Binder.clearCallingIdentity();
+            try {
+                pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
+                    EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_SHOW,
+                    mNai.network.netId,
+                    pendingIntent));
+        }
+
+        @Override
+        public void hideProvisioningNotification() {
+            mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
+                    EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE,
+                    mNai.network.netId));
+        }
+    }
+
     private boolean networkRequiresValidation(NetworkAgentInfo nai) {
-        return NetworkMonitor.isValidationRequired(
-                mDefaultRequest.networkCapabilities, nai.networkCapabilities);
+        return isValidationRequired(nai.networkCapabilities);
     }
 
     private void handleFreshlyValidatedNetwork(NetworkAgentInfo nai) {
@@ -2603,10 +2670,14 @@
         // Internet access and therefore also require validation.
         if (!networkRequiresValidation(nai)) return;
 
-        // Notify the NetworkMonitor thread in case it needs to cancel or
+        // Notify the NetworkAgentInfo/NetworkMonitor in case NetworkMonitor needs to cancel or
         // schedule DNS resolutions. If a DNS resolution is required the
         // result will be sent back to us.
-        nai.networkMonitor.notifyPrivateDnsSettingsChanged(cfg);
+        try {
+            nai.networkMonitor().notifyPrivateDnsChanged(cfg.toParcel());
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
 
         // With Private DNS bypass support, we can proceed to update the
         // Private DNS config immediately, even if we're in strict mode
@@ -2736,7 +2807,11 @@
             // Disable wakeup packet monitoring for each interface.
             wakeupModifyInterface(iface, nai.networkCapabilities, false);
         }
-        nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
+        try {
+            nai.networkMonitor().notifyNetworkDisconnected();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
         mNetworkAgentInfos.remove(nai.messenger);
         nai.maybeStopClat();
         synchronized (mNetworkForNetId) {
@@ -3096,7 +3171,11 @@
             NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
             if (nai == null) return;
             if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) return;
-            nai.networkMonitor.sendMessage(NetworkMonitor.CMD_LAUNCH_CAPTIVE_PORTAL_APP);
+            try {
+                nai.networkMonitor().launchCaptivePortalApp();
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
         });
     }
 
@@ -3104,6 +3183,15 @@
         return mMultinetworkPolicyTracker.getAvoidBadWifi();
     }
 
+    @Override
+    public boolean getAvoidBadWifi() {
+        if (!checkNetworkStackPermission()) {
+            throw new SecurityException("avoidBadWifi requires NETWORK_STACK permission");
+        }
+        return avoidBadWifi();
+    }
+
+
     private void rematchForAvoidBadWifiUpdate() {
         rematchAllNetworksAndRequests(null, 0);
         for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) {
@@ -3217,6 +3305,11 @@
         return mMultinetworkPolicyTracker.getMeteredMultipathPreference();
     }
 
+    @Override
+    public NetworkRequest getDefaultRequest() {
+        return mDefaultRequest;
+    }
+
     private class InternalHandler extends Handler {
         public InternalHandler(Looper looper) {
             super(looper);
@@ -3247,7 +3340,9 @@
                     break;
                 }
                 case EVENT_REGISTER_NETWORK_AGENT: {
-                    handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);
+                    final Pair<NetworkAgentInfo, INetworkMonitor> arg =
+                            (Pair<NetworkAgentInfo, INetworkMonitor>) msg.obj;
+                    handleRegisterNetworkAgent(arg.first, arg.second);
                     break;
                 }
                 case EVENT_REGISTER_NETWORK_REQUEST:
@@ -3305,7 +3400,14 @@
                 }
                 case EVENT_SYSTEM_READY: {
                     for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
-                        nai.networkMonitor.systemReady = true;
+                        // Might have been called already in handleRegisterNetworkAgent since
+                        // mSystemReady is set before sending EVENT_SYSTEM_READY, but calling
+                        // this several times is fine.
+                        try {
+                            nai.networkMonitor().notifySystemReady();
+                        } catch (RemoteException e) {
+                            e.rethrowFromSystemServer();
+                        }
                     }
                     mMultipathPolicyTracker.start();
                     break;
@@ -3577,7 +3679,11 @@
         if (isNetworkWithLinkPropertiesBlocked(lp, uid, false)) {
             return;
         }
-        nai.networkMonitor.forceReevaluation(uid);
+        try {
+            nai.networkMonitor().forceReevaluation(uid);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     @Override
@@ -4785,27 +4891,49 @@
         final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
         final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
                 new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
-                mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
+                mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS);
         // Make sure the network capabilities reflect what the agent info says.
         nai.networkCapabilities = mixInCapabilities(nai, nc);
-        synchronized (this) {
-            nai.networkMonitor.systemReady = mSystemReady;
-        }
         final String extraInfo = networkInfo.getExtraInfo();
         final String name = TextUtils.isEmpty(extraInfo)
                 ? nai.networkCapabilities.getSSID() : extraInfo;
-        addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network, name);
         if (DBG) log("registerNetworkAgent " + nai);
-        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
+        final long token = Binder.clearCallingIdentity();
+        try {
+            mContext.getSystemService(NetworkStack.class)
+                    .makeNetworkMonitor(nai.network, name, new NetworkMonitorCallbacks(nai));
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        // NetworkAgentInfo registration will finish when the NetworkMonitor is created.
+        // If the network disconnects or sends any other event before that, messages are deferred by
+        // NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the
+        // registration.
         return nai.network.netId;
     }
 
-    private void handleRegisterNetworkAgent(NetworkAgentInfo nai) {
+    private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) {
+        nai.onNetworkMonitorCreated(networkMonitor);
         if (VDBG) log("Got NetworkAgent Messenger");
         mNetworkAgentInfos.put(nai.messenger, nai);
         synchronized (mNetworkForNetId) {
             mNetworkForNetId.put(nai.network.netId, nai);
         }
+        synchronized (this) {
+            if (mSystemReady) {
+                try {
+                    networkMonitor.notifySystemReady();
+                } catch (RemoteException e) {
+                    e.rethrowFromSystemServer();
+                }
+            }
+        }
+
+        try {
+            networkMonitor.start();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
         nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger);
         NetworkInfo networkInfo = nai.networkInfo;
         nai.networkInfo = null;
@@ -4855,6 +4983,11 @@
             networkAgent.updateClat(mNMS);
             notifyIfacesChangedForNetworkStats();
             if (networkAgent.everConnected) {
+                try {
+                    networkAgent.networkMonitor().notifyLinkPropertiesChanged();
+                } catch (RemoteException e) {
+                    e.rethrowFromSystemServer();
+                }
                 notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
             }
         }
@@ -5092,6 +5225,11 @@
             // If the requestable capabilities have changed or the score changed, we can't have been
             // called by rematchNetworkAndRequests, so it's safe to start a rematch.
             rematchAllNetworksAndRequests(nai, oldScore);
+            try {
+                nai.networkMonitor().notifyNetworkCapabilitiesChanged();
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
 
@@ -5232,7 +5370,8 @@
         }
         switch (notificationType) {
             case ConnectivityManager.CALLBACK_AVAILABLE: {
-                putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities));
+                putParcelable(bundle, networkCapabilitiesRestrictedForCallerPermissions(
+                        networkAgent.networkCapabilities, nri.mPid, nri.mUid));
                 putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));
                 // For this notification, arg1 contains the blocked status.
                 msg.arg1 = arg1;
@@ -5339,6 +5478,11 @@
         }
 
         if (capabilitiesChanged) {
+            try {
+                nai.networkMonitor().notifyNetworkCapabilitiesChanged();
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
 
@@ -5739,7 +5883,15 @@
             updateLinkProperties(networkAgent, new LinkProperties(networkAgent.linkProperties),
                     null);
 
-            networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
+            // Until parceled LinkProperties are sent directly to NetworkMonitor, the connect
+            // command must be sent after updating LinkProperties to maximize chances of
+            // NetworkMonitor seeing the correct LinkProperties when starting.
+            // TODO: pass LinkProperties to the NetworkMonitor in the notifyNetworkConnected call.
+            try {
+                networkAgent.networkMonitor().notifyNetworkConnected();
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
             scheduleUnvalidatedPrompt(networkAgent);
 
             if (networkAgent.isVPN()) {
@@ -6020,7 +6172,7 @@
     @Override
     public String getCaptivePortalServerUrl() {
         enforceConnectivityInternalPermission();
-        return NetworkMonitor.getCaptivePortalServerHttpUrl(mContext);
+        return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(mContext);
     }
 
     @Override
@@ -6034,6 +6186,17 @@
     }
 
     @Override
+    public void startNattKeepaliveWithFd(Network network, FileDescriptor fd, int resourceId,
+            int intervalSeconds, Messenger messenger, IBinder binder, String srcAddr,
+            String dstAddr) {
+        enforceKeepalivePermission();
+        mKeepaliveTracker.startNattKeepalive(
+                getNetworkAgentInfoForNetwork(network), fd, resourceId,
+                intervalSeconds, messenger, binder,
+                srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT);
+    }
+
+    @Override
     public void stopKeepalive(Network network, int slot) {
         mHandler.sendMessage(mHandler.obtainMessage(
                 NetworkAgent.CMD_STOP_PACKET_KEEPALIVE, slot, PacketKeepalive.SUCCESS, network));
@@ -6113,12 +6276,6 @@
     }
 
     @VisibleForTesting
-    public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
-            NetworkAgentInfo nai, NetworkRequest defaultRequest) {
-        return new NetworkMonitor(context, handler, nai, defaultRequest);
-    }
-
-    @VisibleForTesting
     MultinetworkPolicyTracker createMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
         return new MultinetworkPolicyTracker(c, h, r);
     }
@@ -6209,6 +6366,20 @@
         }
     }
 
+    @GuardedBy("mVpns")
+    private Vpn getVpnIfOwner() {
+        final int uid = Binder.getCallingUid();
+        final int user = UserHandle.getUserId(uid);
+
+        final Vpn vpn = mVpns.get(user);
+        if (vpn == null) {
+            return null;
+        } else {
+            final VpnInfo info = vpn.getVpnInfo();
+            return (info == null || info.ownerUid != uid) ? null : vpn;
+        }
+    }
+
     /**
      * Caller either needs to be an active VPN, or hold the NETWORK_STACK permission
      * for testing.
@@ -6217,14 +6388,10 @@
         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. */
+            Vpn vpn = getVpnIfOwner();
+            if (vpn != null) {
+                return vpn;
             }
         }
         throw new SecurityException("App must either be an active VPN or have the NETWORK_STACK "
@@ -6253,4 +6420,20 @@
 
         return uid;
     }
+
+    @Override
+    public boolean isCallerCurrentAlwaysOnVpnApp() {
+        synchronized (mVpns) {
+            Vpn vpn = getVpnIfOwner();
+            return vpn != null && vpn.getAlwaysOn();
+        }
+    }
+
+    @Override
+    public boolean isCallerCurrentAlwaysOnVpnLockdownApp() {
+        synchronized (mVpns) {
+            Vpn vpn = getVpnIfOwner();
+            return vpn != null && vpn.getLockdown();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 121a830..39030aa 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -341,6 +341,29 @@
     @VisibleForTesting
     static final int STATE_QUICK_DOZE_DELAY = 7;
 
+    private static final int ACTIVE_REASON_UNKNOWN = 0;
+    private static final int ACTIVE_REASON_MOTION = 1;
+    private static final int ACTIVE_REASON_SCREEN = 2;
+    private static final int ACTIVE_REASON_CHARGING = 3;
+    private static final int ACTIVE_REASON_UNLOCKED = 4;
+    private static final int ACTIVE_REASON_FROM_BINDER_CALL = 5;
+    private static final int ACTIVE_REASON_FORCED = 6;
+    private static final int ACTIVE_REASON_ALARM = 7;
+    @VisibleForTesting
+    static final int SET_IDLE_FACTOR_RESULT_UNINIT = -1;
+    @VisibleForTesting
+    static final int SET_IDLE_FACTOR_RESULT_IGNORED = 0;
+    @VisibleForTesting
+    static final int SET_IDLE_FACTOR_RESULT_OK = 1;
+    @VisibleForTesting
+    static final int SET_IDLE_FACTOR_RESULT_NOT_SUPPORT = 2;
+    @VisibleForTesting
+    static final int SET_IDLE_FACTOR_RESULT_INVALID = 3;
+    @VisibleForTesting
+    static final long MIN_STATE_STEP_ALARM_CHANGE = 60 * 1000;
+    @VisibleForTesting
+    static final float MIN_PRE_IDLE_FACTOR_CHANGE = 0.05f;
+
     @VisibleForTesting
     static String stateToString(int state) {
         switch (state) {
@@ -405,6 +428,7 @@
     private long mNextSensingTimeoutAlarmTime;
     private long mCurIdleBudget;
     private long mMaintenanceStartTime;
+    private long mIdleStartTime;
 
     private int mActiveIdleOpCount;
     private PowerManager.WakeLock mActiveIdleWakeLock; // held when there are operations in progress
@@ -415,6 +439,17 @@
     private boolean mAlarmsActive;
     private boolean mReportedMaintenanceActivity;
 
+    /* Factor to apply to INACTIVE_TIMEOUT and IDLE_AFTER_INACTIVE_TIMEOUT in order to enter
+     * STATE_IDLE faster or slower. Don't apply this to SENSING_TIMEOUT or LOCATING_TIMEOUT because:
+     *   - Both of them are shorter
+     *   - Device sensor might take time be to become be stabilized
+     * Also don't apply the factor if the device is in motion because device motion provides a
+     * stronger signal than a prediction algorithm.
+     */
+    private float mPreIdleFactor;
+    private float mLastPreIdleFactor;
+    private int mActiveReason;
+
     public final AtomicFile mConfigFile;
 
     private final RemoteCallbackList<IMaintenanceActivityListener> mMaintenanceActivityListeners =
@@ -760,6 +795,10 @@
          * exit doze. Default = true
          */
         private static final String KEY_WAIT_FOR_UNLOCK = "wait_for_unlock";
+        private static final String KEY_PRE_IDLE_FACTOR_LONG =
+                "pre_idle_factor_long";
+        private static final String KEY_PRE_IDLE_FACTOR_SHORT =
+                "pre_idle_factor_short";
 
         /**
          * This is the time, after becoming inactive, that we go in to the first
@@ -987,6 +1026,16 @@
          */
         public long NOTIFICATION_WHITELIST_DURATION;
 
+        /**
+         * Pre idle time factor use to make idle delay longer
+         */
+        public float PRE_IDLE_FACTOR_LONG;
+
+        /**
+         * Pre idle time factor use to make idle delay shorter
+         */
+        public float PRE_IDLE_FACTOR_SHORT;
+
         public boolean WAIT_FOR_UNLOCK;
 
         private final ContentResolver mResolver;
@@ -1082,6 +1131,8 @@
                 NOTIFICATION_WHITELIST_DURATION = mParser.getDurationMillis(
                         KEY_NOTIFICATION_WHITELIST_DURATION, 30 * 1000L);
                 WAIT_FOR_UNLOCK = mParser.getBoolean(KEY_WAIT_FOR_UNLOCK, false);
+                PRE_IDLE_FACTOR_LONG = mParser.getFloat(KEY_PRE_IDLE_FACTOR_LONG, 1.67f);
+                PRE_IDLE_FACTOR_SHORT = mParser.getFloat(KEY_PRE_IDLE_FACTOR_SHORT, 0.33f);
             }
         }
 
@@ -1196,6 +1247,12 @@
 
             pw.print("    "); pw.print(KEY_WAIT_FOR_UNLOCK); pw.print("=");
             pw.println(WAIT_FOR_UNLOCK);
+
+            pw.print("    "); pw.print(KEY_PRE_IDLE_FACTOR_LONG); pw.print("=");
+            pw.println(PRE_IDLE_FACTOR_LONG);
+
+            pw.print("    "); pw.print(KEY_PRE_IDLE_FACTOR_SHORT); pw.print("=");
+            pw.println(PRE_IDLE_FACTOR_SHORT);
         }
     }
 
@@ -1244,6 +1301,8 @@
     private static final int MSG_FINISH_IDLE_OP = 8;
     private static final int MSG_REPORT_TEMP_APP_WHITELIST_CHANGED = 9;
     private static final int MSG_SEND_CONSTRAINT_MONITORING = 10;
+    private static final int MSG_UPDATE_PRE_IDLE_TIMEOUT_FACTOR = 11;
+    private static final int MSG_RESET_PRE_IDLE_TIMEOUT_FACTOR = 12;
 
     final class MyHandler extends Handler {
         MyHandler(Looper looper) {
@@ -1373,6 +1432,13 @@
                         constraint.stopMonitoring();
                     }
                 } break;
+                case MSG_UPDATE_PRE_IDLE_TIMEOUT_FACTOR: {
+                    updatePreIdleFactor();
+                } break;
+                case MSG_RESET_PRE_IDLE_TIMEOUT_FACTOR: {
+                    updatePreIdleFactor();
+                    maybeDoImmediateMaintenance();
+                } break;
             }
         }
     }
@@ -1526,6 +1592,28 @@
             DeviceIdleController.this.unregisterMaintenanceActivityListener(listener);
         }
 
+        @Override public int setPreIdleTimeoutMode(int mode) {
+            getContext().enforceCallingOrSelfPermission(Manifest.permission.DEVICE_POWER,
+                    null);
+            long ident = Binder.clearCallingIdentity();
+            try {
+                return DeviceIdleController.this.setPreIdleTimeoutMode(mode);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override public void resetPreIdleTimeoutMode() {
+            getContext().enforceCallingOrSelfPermission(Manifest.permission.DEVICE_POWER,
+                    null);
+            long ident = Binder.clearCallingIdentity();
+            try {
+                DeviceIdleController.this.resetPreIdleTimeoutMode();
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
         @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             DeviceIdleController.this.dump(fd, pw, args);
         }
@@ -1768,9 +1856,12 @@
             // Start out assuming we are charging.  If we aren't, we will at least get
             // a battery update the next time the level drops.
             mCharging = true;
+            mActiveReason = ACTIVE_REASON_UNKNOWN;
             mState = STATE_ACTIVE;
             mLightState = LIGHT_STATE_ACTIVE;
             mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
+            mPreIdleFactor = 1.0f;
+            mLastPreIdleFactor = 1.0f;
         }
 
         mBinderService = new BinderService();
@@ -2394,6 +2485,7 @@
 
     public void exitIdleInternal(String reason) {
         synchronized (this) {
+            mActiveReason = ACTIVE_REASON_FROM_BINDER_CALL;
             becomeActiveLocked(reason, Binder.getCallingUid());
         }
     }
@@ -2463,6 +2555,7 @@
         } else if (screenOn) {
             mScreenOn = true;
             if (!mForceIdle && (!mScreenLocked || !mConstants.WAIT_FOR_UNLOCK)) {
+                mActiveReason = ACTIVE_REASON_SCREEN;
                 becomeActiveLocked("screen", Process.myUid());
             }
         }
@@ -2485,6 +2578,7 @@
         } else if (charging) {
             mCharging = charging;
             if (!mForceIdle) {
+                mActiveReason = ACTIVE_REASON_CHARGING;
                 becomeActiveLocked("charging", Process.myUid());
             }
         }
@@ -2516,6 +2610,7 @@
         if (mScreenLocked != showing) {
             mScreenLocked = showing;
             if (mScreenOn && !mForceIdle && !mScreenLocked) {
+                mActiveReason = ACTIVE_REASON_UNLOCKED;
                 becomeActiveLocked("unlocked", Process.myUid());
             }
         }
@@ -2587,7 +2682,11 @@
                     mState = STATE_INACTIVE;
                     if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
                     resetIdleManagementLocked();
-                    scheduleAlarmLocked(mInactiveTimeout, false);
+                    long delay = mInactiveTimeout;
+                    if (shouldUseIdleTimeoutFactorLocked()) {
+                        delay = (long) (mPreIdleFactor * delay);
+                    }
+                    scheduleAlarmLocked(delay, false);
                     EventLogTags.writeDeviceIdle(mState, "no activity");
                 }
             }
@@ -2605,6 +2704,7 @@
         mNextIdlePendingDelay = 0;
         mNextIdleDelay = 0;
         mNextLightIdleDelay = 0;
+        mIdleStartTime = 0;
         cancelAlarmLocked();
         cancelSensingTimeoutAlarmLocked();
         cancelLocatingLocked();
@@ -2621,6 +2721,7 @@
         if (mForceIdle) {
             mForceIdle = false;
             if (mScreenOn || mCharging) {
+                mActiveReason = ACTIVE_REASON_FORCED;
                 becomeActiveLocked("exit-force", Process.myUid());
             }
         }
@@ -2740,6 +2841,7 @@
         if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
             // Whoops, there is an upcoming alarm.  We don't actually want to go idle.
             if (mState != STATE_ACTIVE) {
+                mActiveReason = ACTIVE_REASON_ALARM;
                 becomeActiveLocked("alarm", Process.myUid());
                 becomeInactiveIfAppropriateLocked();
             }
@@ -2763,7 +2865,11 @@
                 // We have now been inactive long enough, it is time to start looking
                 // for motion and sleep some more while doing so.
                 startMonitoringMotionLocked();
-                scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);
+                long delay = mConstants.IDLE_AFTER_INACTIVE_TIMEOUT;
+                if (shouldUseIdleTimeoutFactorLocked()) {
+                    delay = (long) (mPreIdleFactor * delay);
+                }
+                scheduleAlarmLocked(delay, false);
                 moveToStateLocked(STATE_IDLE_PENDING, reason);
                 break;
             case STATE_IDLE_PENDING:
@@ -2834,6 +2940,7 @@
                         " ms.");
                 mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);
                 if (DEBUG) Slog.d(TAG, "Setting mNextIdleDelay = " + mNextIdleDelay);
+                mIdleStartTime = SystemClock.elapsedRealtime();
                 mNextIdleDelay = Math.min(mNextIdleDelay, mConstants.MAX_IDLE_TIMEOUT);
                 if (mNextIdleDelay < mConstants.IDLE_TIMEOUT) {
                     mNextIdleDelay = mConstants.IDLE_TIMEOUT;
@@ -2934,6 +3041,127 @@
         }
     }
 
+    @VisibleForTesting
+    int setPreIdleTimeoutMode(int mode) {
+        return setPreIdleTimeoutFactor(getPreIdleTimeoutByMode(mode));
+    }
+
+    @VisibleForTesting
+    float getPreIdleTimeoutByMode(int mode) {
+        switch (mode) {
+            case PowerManager.PRE_IDLE_TIMEOUT_MODE_LONG: {
+                return mConstants.PRE_IDLE_FACTOR_LONG;
+            }
+            case PowerManager.PRE_IDLE_TIMEOUT_MODE_SHORT: {
+                return mConstants.PRE_IDLE_FACTOR_SHORT;
+            }
+            case PowerManager.PRE_IDLE_TIMEOUT_MODE_NORMAL: {
+                return 1.0f;
+            }
+            default: {
+                Slog.w(TAG, "Invalid time out factor mode: " + mode);
+                return 1.0f;
+            }
+        }
+    }
+
+    @VisibleForTesting
+    float getPreIdleTimeoutFactor() {
+        return mPreIdleFactor;
+    }
+
+    @VisibleForTesting
+    int setPreIdleTimeoutFactor(float ratio) {
+        if (!mDeepEnabled) {
+            if (DEBUG) Slog.d(TAG, "setPreIdleTimeoutFactor: Deep Idle disable");
+            return SET_IDLE_FACTOR_RESULT_NOT_SUPPORT;
+        } else if (ratio <= MIN_PRE_IDLE_FACTOR_CHANGE) {
+            if (DEBUG) Slog.d(TAG, "setPreIdleTimeoutFactor: Invalid input");
+            return SET_IDLE_FACTOR_RESULT_INVALID;
+        } else if (Math.abs(ratio - mPreIdleFactor) < MIN_PRE_IDLE_FACTOR_CHANGE) {
+            if (DEBUG) Slog.d(TAG, "setPreIdleTimeoutFactor: New factor same as previous factor");
+            return SET_IDLE_FACTOR_RESULT_IGNORED;
+        }
+        synchronized (this) {
+            mLastPreIdleFactor = mPreIdleFactor;
+            mPreIdleFactor = ratio;
+        }
+        if (DEBUG) Slog.d(TAG, "setPreIdleTimeoutFactor: " + ratio);
+        postUpdatePreIdleFactor();
+        return SET_IDLE_FACTOR_RESULT_OK;
+    }
+
+    @VisibleForTesting
+    void resetPreIdleTimeoutMode() {
+        synchronized (this) {
+            mLastPreIdleFactor = mPreIdleFactor;
+            mPreIdleFactor = 1.0f;
+        }
+        if (DEBUG) Slog.d(TAG, "resetPreIdleTimeoutMode to 1.0");
+        postResetPreIdleTimeoutFactor();
+    }
+
+    private void postUpdatePreIdleFactor() {
+        mHandler.sendEmptyMessage(MSG_UPDATE_PRE_IDLE_TIMEOUT_FACTOR);
+    }
+
+    private void postResetPreIdleTimeoutFactor() {
+        mHandler.sendEmptyMessage(MSG_RESET_PRE_IDLE_TIMEOUT_FACTOR);
+    }
+
+    @VisibleForTesting
+    void updatePreIdleFactor() {
+        synchronized (this) {
+            if (!shouldUseIdleTimeoutFactorLocked()) {
+                return;
+            }
+            if (mState == STATE_INACTIVE || mState == STATE_IDLE_PENDING) {
+                if (mNextAlarmTime == 0) {
+                    return;
+                }
+                long delay = mNextAlarmTime - SystemClock.elapsedRealtime();
+                if (delay < MIN_STATE_STEP_ALARM_CHANGE) {
+                    return;
+                }
+                long newDelay = (long) (delay / mLastPreIdleFactor * mPreIdleFactor);
+                if (Math.abs(delay - newDelay) < MIN_STATE_STEP_ALARM_CHANGE) {
+                    return;
+                }
+                scheduleAlarmLocked(newDelay, false);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    void maybeDoImmediateMaintenance() {
+        synchronized (this) {
+            if (mState == STATE_IDLE) {
+                long duration = SystemClock.elapsedRealtime() - mIdleStartTime;
+                /* Let's trgger a immediate maintenance,
+                 * if it has been idle for a long time */
+                if (duration > mConstants.IDLE_TIMEOUT) {
+                    scheduleAlarmLocked(0, false);
+                }
+            }
+        }
+    }
+
+    private boolean shouldUseIdleTimeoutFactorLocked() {
+        // exclude ACTIVE_REASON_MOTION, for exclude device in pocket case
+        if (mActiveReason == ACTIVE_REASON_MOTION) {
+            return false;
+        }
+        return true;
+    }
+
+    /** Must only be used in tests. */
+    @VisibleForTesting
+    void setIdleStartTimeForTest(long idleStartTime) {
+        synchronized (this) {
+            mIdleStartTime = idleStartTime;
+        }
+    }
+
     void reportMaintenanceActivityIfNeededLocked() {
         boolean active = mJobsActive;
         if (active == mReportedMaintenanceActivity) {
@@ -2945,6 +3173,11 @@
         mHandler.sendMessage(msg);
     }
 
+    @VisibleForTesting
+    long getNextAlarmTime() {
+        return mNextAlarmTime;
+    }
+
     boolean isOpsInactiveLocked() {
         return mActiveIdleOpCount <= 0 && !mJobsActive && !mAlarmsActive;
     }
@@ -2994,6 +3227,7 @@
                 scheduleReportActiveLocked(type, Process.myUid());
                 addEvent(EVENT_NORMAL, type);
             }
+            mActiveReason = ACTIVE_REASON_MOTION;
             mState = STATE_ACTIVE;
             mInactiveTimeout = timeout;
             mCurIdleBudget = 0;
@@ -3401,6 +3635,11 @@
                 + "and any [-d] is ignored");
         pw.println("  motion");
         pw.println("    Simulate a motion event to bring the device out of deep doze");
+        pw.println("  pre-idle-factor [0|1|2]");
+        pw.println("    Set a new factor to idle time before step to idle"
+                + "(inactive_to and idle_after_inactive_to)");
+        pw.println("  reset-pre-idle-factor");
+        pw.println("    Reset factor to idle time to default");
     }
 
     class Shell extends ShellCommand {
@@ -3571,6 +3810,7 @@
                         }
                     }
                     if (becomeActive) {
+                        mActiveReason = ACTIVE_REASON_FORCED;
                         becomeActiveLocked((arg == null ? "all" : arg) + "-disabled",
                                 Process.myUid());
                     }
@@ -3820,6 +4060,52 @@
                     Binder.restoreCallingIdentity(token);
                 }
             }
+        } else if ("pre-idle-factor".equals(cmd)) {
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
+                    null);
+            synchronized (this) {
+                long token = Binder.clearCallingIdentity();
+                int ret  = SET_IDLE_FACTOR_RESULT_UNINIT;
+                try {
+                    String arg = shell.getNextArg();
+                    boolean valid = false;
+                    int mode = 0;
+                    if (arg != null) {
+                        mode = Integer.parseInt(arg);
+                        ret = setPreIdleTimeoutMode(mode);
+                        if (ret == SET_IDLE_FACTOR_RESULT_OK) {
+                            pw.println("pre-idle-factor: " + mode);
+                            valid = true;
+                        } else if (ret == SET_IDLE_FACTOR_RESULT_NOT_SUPPORT) {
+                            valid = true;
+                            pw.println("Deep idle not supported");
+                        } else if (ret == SET_IDLE_FACTOR_RESULT_IGNORED) {
+                            valid = true;
+                            pw.println("Idle timeout factor not changed");
+                        }
+                    }
+                    if (!valid) {
+                        pw.println("Unknown idle timeout factor: " + arg
+                                + ",(error code: " + ret + ")");
+                    }
+                } catch (NumberFormatException e) {
+                    pw.println("Unknown idle timeout factor"
+                            + ",(error code: " + ret + ")");
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        } else if ("reset-pre-idle-factor".equals(cmd)) {
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
+                    null);
+            synchronized (this) {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    resetPreIdleTimeoutMode();
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
         } else {
             return shell.handleDefaultCommands(cmd);
         }
@@ -4053,6 +4339,9 @@
             if (mAlarmsActive) {
                 pw.print("  mAlarmsActive="); pw.println(mAlarmsActive);
             }
+            if (Math.abs(mPreIdleFactor - 1.0f) > MIN_PRE_IDLE_FACTOR_CHANGE) {
+                pw.print("  mPreIdleFactor="); pw.println(mPreIdleFactor);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index ea80ac1..80fda19 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -16,6 +16,22 @@
 
 package com.android.server;
 
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.FastImmutableArraySet;
+import android.util.Log;
+import android.util.LogPrinter;
+import android.util.MutableInt;
+import android.util.PrintWriterPrinter;
+import android.util.Printer;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.FastPrintWriter;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -25,23 +41,6 @@
 import java.util.List;
 import java.util.Set;
 
-import android.net.Uri;
-import android.util.FastImmutableArraySet;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.MutableInt;
-import android.util.PrintWriterPrinter;
-import android.util.Slog;
-import android.util.LogPrinter;
-import android.util.Printer;
-
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.util.FastPrintWriter;
-
 /**
  * {@hide}
  */
@@ -788,6 +787,7 @@
                         + filter.hasCategory(Intent.CATEGORY_DEFAULT));
                 if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
                     final R oneResult = newResult(filter, match, userId);
+                    if (debug) Slog.v(TAG, "    Created result: " + oneResult);
                     if (oneResult != null) {
                         dest.add(oneResult);
                         if (debug) {
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 126bf65..371276f 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -44,7 +44,7 @@
 import android.net.Network;
 import android.net.NetworkUtils;
 import android.net.TrafficStats;
-import android.net.util.NetdService;
+import android.net.shared.NetdService;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 2346cfc..d2c6354 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -17,9 +17,14 @@
 package com.android.server;
 
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.location.LocationManager.FUSED_PROVIDER;
+import static android.location.LocationManager.GPS_PROVIDER;
+import static android.location.LocationManager.NETWORK_PROVIDER;
+import static android.location.LocationManager.PASSIVE_PROVIDER;
 import static android.location.LocationProvider.AVAILABLE;
 import static android.provider.Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS;
 
+import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.internal.util.Preconditions.checkState;
 
 import android.Manifest;
@@ -29,7 +34,6 @@
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -63,8 +67,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
@@ -81,12 +83,13 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
 import com.android.server.location.AbstractLocationProvider;
 import com.android.server.location.ActivityRecognitionProxy;
 import com.android.server.location.GeocoderProxy;
@@ -116,7 +119,6 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.NoSuchElementException;
-import java.util.Set;
 
 /**
  * The service class that manages LocationProviders and issues location
@@ -137,16 +139,12 @@
 
     private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
             android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
-    private static final String INSTALL_LOCATION_PROVIDER =
-            android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
 
     private static final String NETWORK_LOCATION_SERVICE_ACTION =
             "com.android.location.service.v3.NetworkLocationProvider";
     private static final String FUSED_LOCATION_SERVICE_ACTION =
             "com.android.location.service.FusedLocationProvider";
 
-    private static final int MSG_LOCATION_CHANGED = 1;
-
     private static final long NANOS_PER_MILLI = 1000000L;
 
     // The maximum interval a location request can have and still be considered "high power".
@@ -170,75 +168,64 @@
 
     private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
 
-    private final Context mContext;
-    private final AppOpsManager mAppOps;
-
-    // used internally for synchronization
     private final Object mLock = new Object();
+    private final Context mContext;
+    private final Handler mHandler;
 
-    // --- fields below are final after systemRunning() ---
-    private LocationFudger mLocationFudger;
-    private GeofenceManager mGeofenceManager;
+    private AppOpsManager mAppOps;
     private PackageManager mPackageManager;
     private PowerManager mPowerManager;
     private ActivityManager mActivityManager;
     private UserManager mUserManager;
+
+    private GeofenceManager mGeofenceManager;
+    private LocationFudger mLocationFudger;
     private GeocoderProxy mGeocodeProvider;
     private GnssStatusListenerHelper mGnssStatusProvider;
     private INetInitiatedListener mNetInitiatedListener;
-    private LocationWorkerHandler mLocationHandler;
     private PassiveProvider mPassiveProvider;  // track passive provider for special cases
     private LocationBlacklist mBlacklist;
     private GnssMeasurementsProvider mGnssMeasurementsProvider;
     private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
+    @GuardedBy("mLock")
     private String mLocationControllerExtraPackage;
     private boolean mLocationControllerExtraPackageEnabled;
     private IGpsGeofenceHardware mGpsGeofenceProxy;
 
-    // --- fields below are protected by mLock ---
+    // list of currently active providers
+    @GuardedBy("mLock")
+    private final ArrayList<LocationProvider> mProviders = new ArrayList<>();
 
-    // Mock (test) providers
-    private final HashMap<String, MockProvider> mMockProviders =
-            new HashMap<>();
+    // list of non-mock providers, so that when mock providers replace real providers, they can be
+    // later re-replaced
+    @GuardedBy("mLock")
+    private final ArrayList<LocationProvider> mRealProviders = new ArrayList<>();
 
-    // all receivers
+    @GuardedBy("mLock")
     private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
-
-    // currently installed providers (with mocks replacing real providers)
-    private final ArrayList<LocationProvider> mProviders =
-            new ArrayList<>();
-
-    // real providers, saved here when mocked out
-    private final HashMap<String, LocationProvider> mRealProviders =
-            new HashMap<>();
-
-    // mapping from provider name to provider
-    private final HashMap<String, LocationProvider> mProvidersByName =
-            new HashMap<>();
-
-    // mapping from provider name to all its UpdateRecords
     private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
             new HashMap<>();
 
     private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
 
     // mapping from provider name to last known location
+    @GuardedBy("mLock")
     private final HashMap<String, Location> mLastLocation = new HashMap<>();
 
     // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
     // locations stored here are not fudged for coarse permissions.
+    @GuardedBy("mLock")
     private final HashMap<String, Location> mLastLocationCoarseInterval =
             new HashMap<>();
 
-    // all providers that operate over proxy, for authorizing incoming location and whitelisting
-    // throttling
-    private final ArrayList<LocationProviderProxy> mProxyProviders =
-            new ArrayList<>();
-
     private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
 
+    private final ArraySet<String> mIgnoreSettingsPackageWhitelist = new ArraySet<>();
+
+    @GuardedBy("mLock")
     private final ArrayMap<IBinder, Identity> mGnssMeasurementsListeners = new ArrayMap<>();
 
+    @GuardedBy("mLock")
     private final ArrayMap<IBinder, Identity>
             mGnssNavigationMessageListeners = new ArrayMap<>();
 
@@ -246,22 +233,22 @@
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
     private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
 
-    // Maximum age of last location returned to clients with foreground-only location permissions.
-    private long mLastLocationMaxAgeMs;
-
     private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
 
     private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
 
     private GnssBatchingProvider mGnssBatchingProvider;
+    @GuardedBy("mLock")
     private IBatchedLocationCallback mGnssBatchingCallback;
+    @GuardedBy("mLock")
     private LinkedCallback mGnssBatchingDeathCallback;
+    @GuardedBy("mLock")
     private boolean mGnssBatchingInProgress = false;
 
     public LocationManagerService(Context context) {
         super();
         mContext = context;
-        mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        mHandler = FgThread.getHandler();
 
         // Let the package manager query which are the default location
         // providers as they get certain permissions granted by default.
@@ -270,135 +257,126 @@
         packageManagerInternal.setLocationPackagesProvider(
                 userId -> mContext.getResources().getStringArray(
                         com.android.internal.R.array.config_locationProviderPackageNames));
-
-        if (D) Log.d(TAG, "Constructed");
+        packageManagerInternal.setLocationExtraPackagesProvider(
+                userId -> mContext.getResources().getStringArray(
+                      com.android.internal.R.array.config_locationExtraPackageNames));
 
         // most startup is deferred until systemRunning()
     }
 
     public void systemRunning() {
         synchronized (mLock) {
-            if (D) Log.d(TAG, "systemRunning()");
-
-            // fetch package manager
-            mPackageManager = mContext.getPackageManager();
-
-            // fetch power manager
-            mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-
-            // fetch activity manager
-            mActivityManager
-                    = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
-
-            // prepare worker thread
-            mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
-
-            // prepare mLocationHandler's dependents
-            mLocationFudger = new LocationFudger(mContext, mLocationHandler);
-            mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
-            mBlacklist.init();
-            mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
-
-            // Monitor for app ops mode changes.
-            AppOpsManager.OnOpChangedListener callback
-                    = new AppOpsManager.OnOpChangedInternalListener() {
-                public void onOpChanged(int op, String packageName) {
-                            mLocationHandler.post(() -> {
-                                synchronized (mLock) {
-                                    for (Receiver receiver : mReceivers.values()) {
-                                        receiver.updateMonitoring(true);
-                                    }
-                                    applyAllProviderRequirementsLocked();
-                                }
-                            });
-                }
-            };
-            mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null,
-                    AppOpsManager.WATCH_FOREGROUND_CHANGES, callback);
-
-            PackageManager.OnPermissionsChangedListener permissionListener = uid -> {
-                synchronized (mLock) {
-                    applyAllProviderRequirementsLocked();
-                }
-            };
-            mPackageManager.addOnPermissionsChangeListener(permissionListener);
-
-            // listen for background/foreground changes
-            ActivityManager.OnUidImportanceListener uidImportanceListener =
-                    (uid, importance) -> mLocationHandler.post(
-                            () -> onUidImportanceChanged(uid, importance));
-            mActivityManager.addOnUidImportanceListener(uidImportanceListener,
-                    FOREGROUND_IMPORTANCE_CUTOFF);
-
-            mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-            updateUserProfiles(mCurrentUserId);
-
-            updateBackgroundThrottlingWhitelistLocked();
-            updateLastLocationMaxAgeLocked();
-
-            // prepare providers
-            loadProvidersLocked();
-            updateProvidersSettingsLocked();
-            for (LocationProvider provider : mProviders) {
-                applyRequirementsLocked(provider.getName());
-            }
+            initializeLocked();
         }
+    }
 
-        // listen for settings changes
+    @GuardedBy("mLock")
+    private void initializeLocked() {
+        mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mPackageManager = mContext.getPackageManager();
+        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+
+        mLocationFudger = new LocationFudger(mContext, mHandler);
+        mBlacklist = new LocationBlacklist(mContext, mHandler);
+        mBlacklist.init();
+        mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
+
+        // prepare providers
+        initializeProvidersLocked();
+
+        // add listeners
+        mAppOps.startWatchingMode(
+                AppOpsManager.OP_COARSE_LOCATION,
+                null,
+                AppOpsManager.WATCH_FOREGROUND_CHANGES,
+                new AppOpsManager.OnOpChangedInternalListener() {
+                    public void onOpChanged(int op, String packageName) {
+                        synchronized (mLock) {
+                            onAppOpChangedLocked();
+                        }
+                    }
+                });
+        mPackageManager.addOnPermissionsChangeListener(
+                uid -> {
+                    synchronized (mLock) {
+                        onPermissionsChangedLocked();
+                    }
+                });
+
+        mActivityManager.addOnUidImportanceListener(
+                (uid, importance) -> {
+                    synchronized (mLock) {
+                        onUidImportanceChangedLocked(uid, importance);
+                    }
+                },
+                FOREGROUND_IMPORTANCE_CUTOFF);
         mContext.getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
-                new ContentObserver(mLocationHandler) {
+                Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE), true,
+                new ContentObserver(mHandler) {
                     @Override
                     public void onChange(boolean selfChange) {
                         synchronized (mLock) {
-                            updateProvidersSettingsLocked();
+                            onLocationModeChangedLocked(true);
+                        }
+                    }
+                }, UserHandle.USER_ALL);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
+                new ContentObserver(mHandler) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        synchronized (mLock) {
+                            onProviderAllowedChangedLocked(true);
                         }
                     }
                 }, UserHandle.USER_ALL);
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
                 true,
-                new ContentObserver(mLocationHandler) {
+                new ContentObserver(mHandler) {
                     @Override
                     public void onChange(boolean selfChange) {
                         synchronized (mLock) {
-                            for (LocationProvider provider : mProviders) {
-                                applyRequirementsLocked(provider.getName());
-                            }
+                            onBackgroundThrottleIntervalChangedLocked();
                         }
                     }
                 }, UserHandle.USER_ALL);
         mContext.getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS),
-                true,
-                new ContentObserver(mLocationHandler) {
-                    @Override
-                    public void onChange(boolean selfChange) {
-                        synchronized (mLock) {
-                            updateLastLocationMaxAgeLocked();
-                        }
-                    }
-                }
-        );
-        mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(
                         Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
                 true,
-                new ContentObserver(mLocationHandler) {
+                new ContentObserver(mHandler) {
                     @Override
                     public void onChange(boolean selfChange) {
                         synchronized (mLock) {
-                            updateBackgroundThrottlingWhitelistLocked();
-                            for (LocationProvider provider : mProviders) {
-                                applyRequirementsLocked(provider.getName());
-                            }
+                            onBackgroundThrottleWhitelistChangedLocked();
+                        }
+                    }
+                }, UserHandle.USER_ALL);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(
+                        Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST),
+                true,
+                new ContentObserver(mHandler) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        synchronized (mLock) {
+                            onIgnoreSettingsWhitelistChangedLocked();
                         }
                     }
                 }, UserHandle.USER_ALL);
 
-        mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
+        new PackageMonitor() {
+            @Override
+            public void onPackageDisappeared(String packageName, int reason) {
+                synchronized (mLock) {
+                    LocationManagerService.this.onPackageDisappearedLocked(packageName);
+                }
+            }
+        }.register(mContext, mHandler.getLooper(), true);
 
-        // listen for user change
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
         intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
@@ -407,81 +385,152 @@
         mContext.registerReceiverAsUser(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
-                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
-                } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
-                        || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
-                    updateUserProfiles(mCurrentUserId);
+                synchronized (mLock) {
+                    String action = intent.getAction();
+                    if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                        onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                    } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
+                            || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
+                        onUserProfilesChangedLocked();
+                    }
                 }
             }
-        }, UserHandle.ALL, intentFilter, null, mLocationHandler);
+        }, UserHandle.ALL, intentFilter, null, mHandler);
+
+        // switching the user from null to system here performs the bulk of the initialization work.
+        // the user being changed will cause a reload of all user specific settings, which causes
+        // provider initialization, and propagates changes until a steady state is reached
+        mCurrentUserId = UserHandle.USER_NULL;
+        onUserChangedLocked(UserHandle.USER_SYSTEM);
+
+        // initialize in-memory settings values
+        onBackgroundThrottleWhitelistChangedLocked();
     }
 
-    private void onUidImportanceChanged(int uid, int importance) {
+    @GuardedBy("mLock")
+    private void onAppOpChangedLocked() {
+        for (Receiver receiver : mReceivers.values()) {
+            receiver.updateMonitoring(true);
+        }
+        for (LocationProvider p : mProviders) {
+            applyRequirementsLocked(p);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onPermissionsChangedLocked() {
+        for (LocationProvider p : mProviders) {
+            applyRequirementsLocked(p);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onLocationModeChangedLocked(boolean broadcast) {
+        for (LocationProvider p : mProviders) {
+            p.onLocationModeChangedLocked();
+        }
+
+        if (broadcast) {
+            mContext.sendBroadcastAsUser(
+                    new Intent(LocationManager.MODE_CHANGED_ACTION),
+                    UserHandle.ALL);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onProviderAllowedChangedLocked(boolean broadcast) {
+        for (LocationProvider p : mProviders) {
+            p.onAllowedChangedLocked();
+        }
+
+        if (broadcast) {
+            mContext.sendBroadcastAsUser(
+                    new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
+                    UserHandle.ALL);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onPackageDisappearedLocked(String packageName) {
+        ArrayList<Receiver> deadReceivers = null;
+
+        for (Receiver receiver : mReceivers.values()) {
+            if (receiver.mIdentity.mPackageName.equals(packageName)) {
+                if (deadReceivers == null) {
+                    deadReceivers = new ArrayList<>();
+                }
+                deadReceivers.add(receiver);
+            }
+        }
+
+        // perform removal outside of mReceivers loop
+        if (deadReceivers != null) {
+            for (Receiver receiver : deadReceivers) {
+                removeUpdatesLocked(receiver);
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onUidImportanceChangedLocked(int uid, int importance) {
         boolean foreground = isImportanceForeground(importance);
         HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
-        synchronized (mLock) {
-            for (Entry<String, ArrayList<UpdateRecord>> entry
-                    : mRecordsByProvider.entrySet()) {
-                String provider = entry.getKey();
-                for (UpdateRecord record : entry.getValue()) {
-                    if (record.mReceiver.mIdentity.mUid == uid
-                            && record.mIsForegroundUid != foreground) {
-                        if (D) {
-                            Log.d(TAG, "request from uid " + uid + " is now "
-                                    + (foreground ? "foreground" : "background)"));
-                        }
-                        record.updateForeground(foreground);
-
-                        if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
-                            affectedProviders.add(provider);
-                        }
-                    }
-                }
-            }
-            for (String provider : affectedProviders) {
-                applyRequirementsLocked(provider);
-            }
-
-            for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
-                Identity callerIdentity = entry.getValue();
-                if (callerIdentity.mUid == uid) {
+        for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
+            String provider = entry.getKey();
+            for (UpdateRecord record : entry.getValue()) {
+                if (record.mReceiver.mIdentity.mUid == uid
+                        && record.mIsForegroundUid != foreground) {
                     if (D) {
-                        Log.d(TAG, "gnss measurements listener from uid " + uid
-                                + " is now " + (foreground ? "foreground" : "background)"));
-                    }
-                    if (foreground || isThrottlingExemptLocked(entry.getValue())) {
-                        mGnssMeasurementsProvider.addListener(
-                                IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
-                                callerIdentity.mUid, callerIdentity.mPackageName);
-                    } else {
-                        mGnssMeasurementsProvider.removeListener(
-                                IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
-                    }
-                }
-            }
-
-            for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
-                Identity callerIdentity = entry.getValue();
-                if (callerIdentity.mUid == uid) {
-                    if (D) {
-                        Log.d(TAG, "gnss navigation message listener from uid "
-                                + uid + " is now "
+                        Log.d(TAG, "request from uid " + uid + " is now "
                                 + (foreground ? "foreground" : "background)"));
                     }
-                    if (foreground || isThrottlingExemptLocked(entry.getValue())) {
-                        mGnssNavigationMessageProvider.addListener(
-                                IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
-                                callerIdentity.mUid, callerIdentity.mPackageName);
-                    } else {
-                        mGnssNavigationMessageProvider.removeListener(
-                                IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
+                    record.updateForeground(foreground);
+
+                    if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
+                        affectedProviders.add(provider);
                     }
                 }
             }
+        }
+        for (String provider : affectedProviders) {
+            applyRequirementsLocked(provider);
+        }
 
-            // TODO(b/120449926): The GNSS status listeners should be handled similar to the above.
+        for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
+            Identity callerIdentity = entry.getValue();
+            if (callerIdentity.mUid == uid) {
+                if (D) {
+                    Log.d(TAG, "gnss measurements listener from uid " + uid
+                            + " is now " + (foreground ? "foreground" : "background)"));
+                }
+                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+                    mGnssMeasurementsProvider.addListener(
+                            IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
+                            callerIdentity.mUid, callerIdentity.mPackageName);
+                } else {
+                    mGnssMeasurementsProvider.removeListener(
+                            IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
+                }
+            }
+        }
+
+        for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
+            Identity callerIdentity = entry.getValue();
+            if (callerIdentity.mUid == uid) {
+                if (D) {
+                    Log.d(TAG, "gnss navigation message listener from uid "
+                            + uid + " is now "
+                            + (foreground ? "foreground" : "background)"));
+                }
+                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+                    mGnssNavigationMessageProvider.addListener(
+                            IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
+                            callerIdentity.mUid, callerIdentity.mPackageName);
+                } else {
+                    mGnssNavigationMessageProvider.removeListener(
+                            IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
+                }
+            }
         }
     }
 
@@ -489,30 +538,62 @@
         return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
     }
 
-    /**
-     * Makes a list of userids that are related to the current user. This is
-     * relevant when using managed profiles. Otherwise the list only contains
-     * the current user.
-     *
-     * @param currentUserId the current user, who might have an alter-ego.
-     */
-    private void updateUserProfiles(int currentUserId) {
-        int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
-        synchronized (mLock) {
-            mCurrentUserProfiles = profileIds;
+    @GuardedBy("mLock")
+    private void onBackgroundThrottleIntervalChangedLocked() {
+        for (LocationProvider provider : mProviders) {
+            applyRequirementsLocked(provider);
         }
     }
 
-    /**
-     * Checks if the specified userId matches any of the current foreground
-     * users stored in mCurrentUserProfiles.
-     */
-    private boolean isCurrentProfile(int userId) {
-        synchronized (mLock) {
-            return ArrayUtils.contains(mCurrentUserProfiles, userId);
+    @GuardedBy("mLock")
+    private void onBackgroundThrottleWhitelistChangedLocked() {
+        String setting = Settings.Global.getString(
+                mContext.getContentResolver(),
+                Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
+        if (setting == null) {
+            setting = "";
+        }
+
+        mBackgroundThrottlePackageWhitelist.clear();
+        mBackgroundThrottlePackageWhitelist.addAll(
+                SystemConfig.getInstance().getAllowUnthrottledLocation());
+        mBackgroundThrottlePackageWhitelist.addAll(Arrays.asList(setting.split(",")));
+
+        for (LocationProvider p : mProviders) {
+            applyRequirementsLocked(p);
         }
     }
 
+    @GuardedBy("lock")
+    private void onIgnoreSettingsWhitelistChangedLocked() {
+        String setting = Settings.Global.getString(
+                mContext.getContentResolver(),
+                Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST);
+        if (setting == null) {
+            setting = "";
+        }
+
+        mIgnoreSettingsPackageWhitelist.clear();
+        mIgnoreSettingsPackageWhitelist.addAll(
+                SystemConfig.getInstance().getAllowIgnoreLocationSettings());
+        mIgnoreSettingsPackageWhitelist.addAll(Arrays.asList(setting.split(",")));
+
+        for (LocationProvider p : mProviders) {
+            applyRequirementsLocked(p);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void onUserProfilesChangedLocked() {
+        mCurrentUserProfiles = mUserManager.getProfileIdsWithDisabled(mCurrentUserId);
+    }
+
+    @GuardedBy("mLock")
+    private boolean isCurrentProfileLocked(int userId) {
+        return ArrayUtils.contains(mCurrentUserProfiles, userId);
+    }
+
+    @GuardedBy("mLock")
     private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
         PackageManager pm = mContext.getPackageManager();
         String systemPackageName = mContext.getPackageName();
@@ -583,30 +664,30 @@
                 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
     }
 
-    private void loadProvidersLocked() {
+    @GuardedBy("mLock")
+    private void initializeProvidersLocked() {
         // create a passive location provider, which is always enabled
-        LocationProvider passiveProviderManager = new LocationProvider(
-                LocationManager.PASSIVE_PROVIDER);
-        PassiveProvider passiveProvider = new PassiveProvider(passiveProviderManager);
-
+        LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER);
         addProviderLocked(passiveProviderManager);
-        mPassiveProvider = passiveProvider;
+        mPassiveProvider = new PassiveProvider(passiveProviderManager);
+        passiveProviderManager.attachLocked(mPassiveProvider);
 
         if (GnssLocationProvider.isSupported()) {
             // Create a gps location provider
-            LocationProvider gnssProviderManager = new LocationProvider(
-                    LocationManager.GPS_PROVIDER);
+            LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER, true);
+            mRealProviders.add(gnssProviderManager);
+            addProviderLocked(gnssProviderManager);
+
             GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
                     gnssProviderManager,
-                    mLocationHandler.getLooper());
+                    mHandler.getLooper());
+            gnssProviderManager.attachLocked(gnssProvider);
 
             mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
             mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
             mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
             mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
             mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
-            addProviderLocked(gnssProviderManager);
-            mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProviderManager);
             mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
             mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
             mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
@@ -634,9 +715,7 @@
         ensureFallbackFusedProviderPresentLocked(pkgs);
 
         // bind to network provider
-
-        LocationProvider networkProviderManager = new LocationProvider(
-                LocationManager.NETWORK_PROVIDER);
+        LocationProvider networkProviderManager = new LocationProvider(NETWORK_PROVIDER, true);
         LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
                 mContext,
                 networkProviderManager,
@@ -645,16 +724,15 @@
                 com.android.internal.R.string.config_networkLocationProviderPackageName,
                 com.android.internal.R.array.config_locationProviderPackageNames);
         if (networkProvider != null) {
-            mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProviderManager);
-            mProxyProviders.add(networkProvider);
+            mRealProviders.add(networkProviderManager);
             addProviderLocked(networkProviderManager);
+            networkProviderManager.attachLocked(networkProvider);
         } else {
             Slog.w(TAG, "no network location provider found");
         }
 
         // bind to fused provider
-        LocationProvider fusedProviderManager = new LocationProvider(
-                LocationManager.FUSED_PROVIDER);
+        LocationProvider fusedProviderManager = new LocationProvider(FUSED_PROVIDER);
         LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
                 mContext,
                 fusedProviderManager,
@@ -663,9 +741,9 @@
                 com.android.internal.R.string.config_fusedLocationProviderPackageName,
                 com.android.internal.R.array.config_locationProviderPackageNames);
         if (fusedProvider != null) {
+            mRealProviders.add(fusedProviderManager);
             addProviderLocked(fusedProviderManager);
-            mProxyProviders.add(fusedProvider);
-            mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedProviderManager);
+            fusedProviderManager.attachLocked(fusedProvider);
         } else {
             Slog.e(TAG, "no fused location provider found",
                     new IllegalStateException("Location service needs a fused location provider"));
@@ -715,9 +793,6 @@
         for (String testProviderString : testProviderStrings) {
             String fragments[] = testProviderString.split(",");
             String name = fragments[0].trim();
-            if (mProvidersByName.get(name) != null) {
-                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
-            }
             ProviderProperties properties = new ProviderProperties(
                     Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
                     Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
@@ -728,28 +803,37 @@
                     Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
                     Integer.parseInt(fragments[8]) /* powerRequirement */,
                     Integer.parseInt(fragments[9]) /* accuracy */);
-            addTestProviderLocked(name, properties);
+            LocationProvider testProviderManager = new LocationProvider(name);
+            addProviderLocked(testProviderManager);
+            new MockProvider(testProviderManager, properties);
         }
     }
 
-    /**
-     * Called when the device's active user changes.
-     *
-     * @param userId the new active user's UserId
-     */
-    private void switchUser(int userId) {
+    @GuardedBy("mLock")
+    private void onUserChangedLocked(int userId) {
         if (mCurrentUserId == userId) {
             return;
         }
-        mBlacklist.switchUser(userId);
-        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
-        synchronized (mLock) {
-            mLastLocation.clear();
-            mLastLocationCoarseInterval.clear();
-            updateUserProfiles(userId);
-            updateProvidersSettingsLocked();
-            mCurrentUserId = userId;
+
+        // this call has the side effect of forcing a write to the LOCATION_MODE setting in an OS
+        // upgrade case, and ensures that if anyone checks the LOCATION_MODE setting directly, they
+        // will see it in an appropriate state (at least after that user becomes foreground for the
+        // first time...)
+        isLocationEnabledForUser(userId);
+
+        // let providers know the current user is on the way out before changing the user
+        for (LocationProvider p : mProviders) {
+            p.onUserChangingLocked();
         }
+
+        mCurrentUserId = userId;
+        onUserProfilesChangedLocked();
+
+        mBlacklist.switchUser(userId);
+
+        // if the user changes, per-user settings may also have changed
+        onLocationModeChangedLocked(false);
+        onProviderAllowedChangedLocked(false);
     }
 
     private static final class Identity {
@@ -767,158 +851,380 @@
     private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
 
         private final String mName;
-        private AbstractLocationProvider mProvider;
 
-        // whether the provider is enabled in location settings
-        private boolean mSettingsEnabled;
+        // whether this provider should respect LOCATION_PROVIDERS_ALLOWED (ie gps and network)
+        private final boolean mIsManagedBySettings;
 
-        // whether the provider considers itself enabled
-        private volatile boolean mEnabled;
+        // remember to clear binder identity before invoking any provider operation
+        @GuardedBy("mLock")
+        @Nullable protected AbstractLocationProvider mProvider;
 
-        @Nullable
-        private volatile ProviderProperties mProperties;
+        @GuardedBy("mLock")
+        private boolean mUseable;  // combined state
+        @GuardedBy("mLock")
+        private boolean mAllowed;  // state of LOCATION_PROVIDERS_ALLOWED
+        @GuardedBy("mLock")
+        private boolean mEnabled;  // state of provider
+
+        @GuardedBy("mLock")
+        @Nullable private ProviderProperties mProperties;
 
         private LocationProvider(String name) {
-            mName = name;
-            // TODO: initialize settings enabled?
+            this(name, false);
         }
 
-        @Override
-        public void onAttachProvider(AbstractLocationProvider provider, boolean initiallyEnabled) {
-            checkState(mProvider == null);
+        private LocationProvider(String name, boolean isManagedBySettings) {
+            mName = name;
+            mIsManagedBySettings = isManagedBySettings;
 
-            // the provider is not yet fully constructed at this point, so we may not do anything
-            // except save a reference for later use here. do not call any provider methods.
-            mProvider = provider;
-            mEnabled = initiallyEnabled;
+            mProvider = null;
+            mUseable = false;
+            mAllowed = !mIsManagedBySettings;
+            mEnabled = false;
             mProperties = null;
+
+            if (mIsManagedBySettings) {
+                // since we assume providers are disabled by default
+                Settings.Secure.putStringForUser(
+                        mContext.getContentResolver(),
+                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                        "-" + mName,
+                        mCurrentUserId);
+            }
+        }
+
+        @GuardedBy("mLock")
+        public void attachLocked(AbstractLocationProvider provider) {
+            checkNotNull(provider);
+            checkState(mProvider == null);
+            mProvider = provider;
+
+            onUseableChangedLocked();
         }
 
         public String getName() {
             return mName;
         }
 
-        public boolean isEnabled() {
-            return mSettingsEnabled && mEnabled;
+        @GuardedBy("mLock")
+        @Nullable
+        public String getPackageLocked() {
+            if (mProvider == null) {
+                return null;
+            } else if (mProvider instanceof LocationProviderProxy) {
+                // safe to not clear binder context since this doesn't call into the actual provider
+                return ((LocationProviderProxy) mProvider).getConnectedPackageName();
+            } else {
+                return mContext.getPackageName();
+            }
         }
 
+        public boolean isMock() {
+            return false;
+        }
+
+        @GuardedBy("mLock")
+        public boolean isPassiveLocked() {
+            return mProvider == mPassiveProvider;
+        }
+
+        @GuardedBy("mLock")
         @Nullable
-        public ProviderProperties getProperties() {
+        public ProviderProperties getPropertiesLocked() {
             return mProperties;
         }
 
-        public void setRequest(ProviderRequest request, WorkSource workSource) {
-            mProvider.setRequest(request, workSource);
+        @GuardedBy("mLock")
+        public void setRequestLocked(ProviderRequest request, WorkSource workSource) {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    mProvider.setRequest(request, workSource);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
         }
 
-        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        @GuardedBy("mLock")
+        public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
             pw.println(mName + " provider:");
-            pw.println(" setting=" + mSettingsEnabled);
+            if (isMock()) {
+                pw.println(" mock=true");
+            }
+            pw.println(" attached=" + (mProvider != null));
+            if (mIsManagedBySettings) {
+                pw.println(" allowed=" + mAllowed);
+            }
             pw.println(" enabled=" + mEnabled);
+            pw.println(" useable=" + mUseable);
             pw.println(" properties=" + mProperties);
-            mProvider.dump(fd, pw, args);
+
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    mProvider.dump(fd, pw, args);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
         }
 
-        public long getStatusUpdateTime() {
-            return mProvider.getStatusUpdateTime();
+        @GuardedBy("mLock")
+        public long getStatusUpdateTimeLocked() {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    return mProvider.getStatusUpdateTime();
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            } else {
+                return 0;
+            }
         }
 
-        public int getStatus(Bundle extras) {
-            return mProvider.getStatus(extras);
+        @GuardedBy("mLock")
+        public int getStatusLocked(Bundle extras) {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    return mProvider.getStatus(extras);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            } else {
+                return AVAILABLE;
+            }
         }
 
-        public void sendExtraCommand(String command, Bundle extras) {
-            mProvider.sendExtraCommand(command, extras);
+        @GuardedBy("mLock")
+        public void sendExtraCommandLocked(String command, Bundle extras) {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    mProvider.sendExtraCommand(command, extras);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
         }
 
         // called from any thread
         @Override
         public void onReportLocation(Location location) {
-            runOnHandler(() -> LocationManagerService.this.reportLocation(location,
-                    mProvider == mPassiveProvider));
+            // no security check necessary because this is coming from an internal-only interface
+            // move calls coming from below LMS onto a different thread to avoid deadlock
+            mHandler.post(() -> {
+                synchronized (mLock) {
+                    handleLocationChangedLocked(location, this);
+                }
+            });
         }
 
         // called from any thread
         @Override
         public void onReportLocation(List<Location> locations) {
-            runOnHandler(() -> LocationManagerService.this.reportLocationBatch(locations));
+            // move calls coming from below LMS onto a different thread to avoid deadlock
+            mHandler.post(() -> {
+                synchronized (mLock) {
+                    LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
+                    if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
+                        Slog.w(TAG, "reportLocationBatch() called without user permission");
+                        return;
+                    }
+
+                    if (mGnssBatchingCallback == null) {
+                        Slog.e(TAG, "reportLocationBatch() called without active Callback");
+                        return;
+                    }
+
+                    try {
+                        mGnssBatchingCallback.onLocationBatch(locations);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
+                    }
+                }
+            });
         }
 
         // called from any thread
         @Override
         public void onSetEnabled(boolean enabled) {
-            runOnHandler(() -> {
-                if (enabled == mEnabled) {
-                    return;
-                }
-
-                mEnabled = enabled;
-
-                if (!mSettingsEnabled) {
-                    // this provider was disabled in settings anyways, so a change to it's own
-                    // enabled status won't have any affect.
-                    return;
-                }
-
-                // traditionally clients can listen for changes to the LOCATION_PROVIDERS_ALLOWED
-                // setting to detect when providers are enabled or disabled (even though they aren't
-                // supposed to). to continue to support this we must force a change to this setting.
-                // we use the fused provider because this is forced to be always enabled in settings
-                // anyways, and so won't have any visible effect beyond triggering content observers
-                Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                        "+" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
-                Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                        "-" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
-
+            // move calls coming from below LMS onto a different thread to avoid deadlock
+            mHandler.post(() -> {
                 synchronized (mLock) {
-                    if (!enabled) {
-                        // If any provider has been disabled, clear all last locations for all
-                        // providers. This is to be on the safe side in case a provider has location
-                        // derived from this disabled provider.
-                        mLastLocation.clear();
-                        mLastLocationCoarseInterval.clear();
+                    if (enabled == mEnabled) {
+                        return;
                     }
 
-                    updateProviderListenersLocked(mName);
-                }
+                    mEnabled = enabled;
 
-                mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
-                        UserHandle.ALL);
+                    // update provider allowed settings to reflect enabled status
+                    if (mIsManagedBySettings) {
+                        if (mEnabled && !mAllowed) {
+                            Settings.Secure.putStringForUser(
+                                    mContext.getContentResolver(),
+                                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                                    "+" + mName,
+                                    mCurrentUserId);
+                        } else if (!mEnabled && mAllowed) {
+                            Settings.Secure.putStringForUser(
+                                    mContext.getContentResolver(),
+                                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                                    "-" + mName,
+                                    mCurrentUserId);
+                        }
+                    }
+
+                    onUseableChangedLocked();
+                }
             });
         }
 
         @Override
         public void onSetProperties(ProviderProperties properties) {
-            runOnHandler(() -> mProperties = properties);
+            // because this does not invoke any other methods which might result in calling back
+            // into the location provider, it is safe to run this on the calling thread. it is also
+            // currently necessary to run this on the calling thread to ensure that property changes
+            // are publicly visibly immediately, ie for mock providers which are created.
+            synchronized (mLock) {
+                mProperties = properties;
+            }
         }
 
-        private void setSettingsEnabled(boolean enabled) {
-            synchronized (mLock) {
-                if (mSettingsEnabled == enabled) {
+        @GuardedBy("mLock")
+        public void onLocationModeChangedLocked() {
+            onUseableChangedLocked();
+        }
+
+        private boolean isAllowed() {
+            return isAllowedForUser(mCurrentUserId);
+        }
+
+        private boolean isAllowedForUser(int userId) {
+            String allowedProviders = Settings.Secure.getStringForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                    userId);
+            return TextUtils.delimitedStringContains(allowedProviders, ',', mName);
+        }
+
+        @GuardedBy("mLock")
+        public void onAllowedChangedLocked() {
+            if (mIsManagedBySettings) {
+                boolean allowed = isAllowed();
+                if (allowed == mAllowed) {
                     return;
                 }
+                mAllowed = allowed;
 
-                mSettingsEnabled = enabled;
-                if (!mSettingsEnabled) {
-                    // if any provider has been disabled, clear all last locations for all
-                    // providers. this is to be on the safe side in case a provider has location
-                    // derived from this disabled provider.
-                    mLastLocation.clear();
-                    mLastLocationCoarseInterval.clear();
-                    updateProviderListenersLocked(mName);
-                } else if (mEnabled) {
-                    updateProviderListenersLocked(mName);
+                // make a best effort to keep the setting matching the real enabled state of the
+                // provider so that legacy applications aren't broken.
+                if (mAllowed && !mEnabled) {
+                    Settings.Secure.putStringForUser(
+                            mContext.getContentResolver(),
+                            Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                            "-" + mName,
+                            mCurrentUserId);
+                }
+
+                onUseableChangedLocked();
+            }
+        }
+
+        @GuardedBy("mLock")
+        public boolean isUseableLocked() {
+            return isUseableForUserLocked(mCurrentUserId);
+        }
+
+        @GuardedBy("mLock")
+        public boolean isUseableForUserLocked(int userId) {
+            return userId == mCurrentUserId && mUseable;
+        }
+
+        @GuardedBy("mLock")
+        public void onUseableChangedLocked() {
+            // if any property that contributes to "useability" here changes state, it MUST result
+            // in a direct or indrect call to onUseableChangedLocked. this allows the provider to
+            // guarantee that it will always eventually reach the correct state.
+            boolean useable = mProvider != null
+                    && mProviders.contains(this) && isLocationEnabled() && mAllowed && mEnabled;
+            if (useable == mUseable) {
+                return;
+            }
+            mUseable = useable;
+
+            if (!mUseable) {
+                // If any provider has been disabled, clear all last locations for all
+                // providers. This is to be on the safe side in case a provider has location
+                // derived from this disabled provider.
+                mLastLocation.clear();
+                mLastLocationCoarseInterval.clear();
+            }
+
+            updateProviderUseableLocked(this);
+        }
+
+        @GuardedBy("mLock")
+        public void onUserChangingLocked() {
+            // when the user is about to change, we set this provider to un-useable, and notify all
+            // of the current user clients. when the user is finished changing, useability will be
+            // updated back via onLocationModeChanged() and onAllowedChanged().
+            mUseable = false;
+            updateProviderUseableLocked(this);
+        }
+    }
+
+    private class MockLocationProvider extends LocationProvider {
+
+        private MockLocationProvider(String name) {
+            super(name);
+        }
+
+        @Override
+        public void attachLocked(AbstractLocationProvider provider) {
+            checkState(provider instanceof MockProvider);
+            super.attachLocked(provider);
+        }
+
+        public boolean isMock() {
+            return true;
+        }
+
+        @GuardedBy("mLock")
+        public void setEnabledLocked(boolean enabled) {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    ((MockProvider) mProvider).setEnabled(enabled);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
                 }
             }
         }
 
-        private void runOnHandler(Runnable runnable) {
-            if (Looper.myLooper() == mLocationHandler.getLooper()) {
-                runnable.run();
-            } else {
-                mLocationHandler.post(runnable);
+        @GuardedBy("mLock")
+        public void setLocationLocked(Location location) {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    ((MockProvider) mProvider).setLocation(location);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+
+        @GuardedBy("mLock")
+        public void setStatusLocked(int status, Bundle extras, long updateTime) {
+            if (mProvider != null) {
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    ((MockProvider) mProvider).setStatus(status, extras, updateTime);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
             }
         }
     }
@@ -1022,19 +1328,21 @@
                 // See if receiver has any enabled update records.  Also note if any update records
                 // are high power (has a high power provider with an interval under a threshold).
                 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
-                    if (isAllowedByUserSettingsLockedForUser(updateRecord.mProvider,
-                            mCurrentUserId)) {
-                        requestingLocation = true;
-                        LocationManagerService.LocationProvider locationProvider
-                                = mProvidersByName.get(updateRecord.mProvider);
-                        ProviderProperties properties = locationProvider != null
-                                ? locationProvider.getProperties() : null;
-                        if (properties != null
-                                && properties.mPowerRequirement == Criteria.POWER_HIGH
-                                && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
-                            requestingHighPowerLocation = true;
-                            break;
-                        }
+                    LocationProvider provider = getLocationProviderLocked(updateRecord.mProvider);
+                    if (provider == null) {
+                        continue;
+                    }
+                    if (!provider.isUseableLocked() && !isSettingsExemptLocked(updateRecord)) {
+                        continue;
+                    }
+
+                    requestingLocation = true;
+                    ProviderProperties properties = provider.getPropertiesLocked();
+                    if (properties != null
+                            && properties.mPowerRequirement == Criteria.POWER_HIGH
+                            && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
+                        requestingHighPowerLocation = true;
+                        break;
                     }
                 }
             }
@@ -1122,7 +1430,7 @@
                     synchronized (this) {
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
-                        mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
+                        mPendingIntent.send(mContext, 0, statusChanged, this, mHandler,
                                 getResolutionPermission(mAllowedResolutionLevel),
                                 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
                         // call this after broadcasting so we do not increment
@@ -1158,7 +1466,7 @@
                     synchronized (this) {
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
-                        mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
+                        mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
                                 getResolutionPermission(mAllowedResolutionLevel),
                                 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
                         // call this after broadcasting so we do not increment
@@ -1201,7 +1509,7 @@
                     synchronized (this) {
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
-                        mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
+                        mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
                                 getResolutionPermission(mAllowedResolutionLevel),
                                 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
                         // call this after broadcasting so we do not increment
@@ -1273,16 +1581,16 @@
                 synchronized (receiver) {
                     // so wakelock calls will succeed
                     long identity = Binder.clearCallingIdentity();
-                    receiver.decrementPendingBroadcastsLocked();
-                    Binder.restoreCallingIdentity(identity);
+                    try {
+                        receiver.decrementPendingBroadcastsLocked();
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
                 }
             }
         }
     }
 
-    /**
-     * Returns the year of the GNSS hardware.
-     */
     @Override
     public int getGnssYearOfHardware() {
         if (mGnssSystemInfoProvider != null) {
@@ -1292,10 +1600,6 @@
         }
     }
 
-
-    /**
-     * Returns the model name of the GNSS hardware.
-     */
     @Override
     @Nullable
     public String getGnssHardwareModelName() {
@@ -1306,32 +1610,24 @@
         }
     }
 
-    /**
-     * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
-     * (try to) access GNSS information at this layer.
-     */
     private boolean hasGnssPermissions(String packageName) {
-        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
-        checkResolutionLevelIsSufficientForProviderUse(
-                allowedResolutionLevel,
-                LocationManager.GPS_PROVIDER);
+        synchronized (mLock) {
+            int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+            checkResolutionLevelIsSufficientForProviderUseLocked(
+                    allowedResolutionLevel,
+                    GPS_PROVIDER);
 
-        int pid = Binder.getCallingPid();
-        int uid = Binder.getCallingUid();
-        long identity = Binder.clearCallingIdentity();
-        boolean hasLocationAccess;
-        try {
-            hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+            int pid = Binder.getCallingPid();
+            int uid = Binder.getCallingUid();
+            long identity = Binder.clearCallingIdentity();
+            try {
+                return checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
-
-        return hasLocationAccess;
     }
 
-    /**
-     * Returns the GNSS batching size, if available.
-     */
     @Override
     public int getGnssBatchSize(String packageName) {
         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1344,10 +1640,6 @@
         }
     }
 
-    /**
-     * Adds a callback for GNSS Batching events, if permissions allow, which are transported
-     * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
-     */
     @Override
     public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1357,18 +1649,20 @@
             return false;
         }
 
-        mGnssBatchingCallback = callback;
-        mGnssBatchingDeathCallback = new LinkedCallback(callback);
-        try {
-            callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
-        } catch (RemoteException e) {
-            // if the remote process registering the listener is already dead, just swallow the
-            // exception and return
-            Log.e(TAG, "Remote listener already died.", e);
-            return false;
-        }
+        synchronized (mLock) {
+            mGnssBatchingCallback = callback;
+            mGnssBatchingDeathCallback = new LinkedCallback(callback);
+            try {
+                callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
+            } catch (RemoteException e) {
+                // if the remote process registering the listener is already dead, just swallow the
+                // exception and return
+                Log.e(TAG, "Remote listener already died.", e);
+                return false;
+            }
 
-        return true;
+            return true;
+        }
     }
 
     private class LinkedCallback implements IBinder.DeathRecipient {
@@ -1391,27 +1685,22 @@
         }
     }
 
-    /**
-     * Removes callback for GNSS batching
-     */
     @Override
     public void removeGnssBatchingCallback() {
-        try {
-            mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
-                    0 /* flags */);
-        } catch (NoSuchElementException e) {
-            // if the death callback isn't connected (it should be...), log error, swallow the
-            // exception and return
-            Log.e(TAG, "Couldn't unlink death callback.", e);
+        synchronized (mLock) {
+            try {
+                mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
+                        0 /* flags */);
+            } catch (NoSuchElementException e) {
+                // if the death callback isn't connected (it should be...), log error, swallow the
+                // exception and return
+                Log.e(TAG, "Couldn't unlink death callback.", e);
+            }
+            mGnssBatchingCallback = null;
+            mGnssBatchingDeathCallback = null;
         }
-        mGnssBatchingCallback = null;
-        mGnssBatchingDeathCallback = null;
     }
 
-
-    /**
-     * Starts GNSS batching, if available.
-     */
     @Override
     public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1421,20 +1710,20 @@
             return false;
         }
 
-        if (mGnssBatchingInProgress) {
-            // Current design does not expect multiple starts to be called repeatedly
-            Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
-            // Try to clean up anyway, and continue
-            stopGnssBatch();
-        }
+        synchronized (mLock) {
+            if (mGnssBatchingInProgress) {
+                // Current design does not expect multiple starts to be called repeatedly
+                Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
+                // Try to clean up anyway, and continue
+                stopGnssBatch();
+            }
 
-        mGnssBatchingInProgress = true;
-        return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
+            mGnssBatchingInProgress = true;
+            return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
+        }
     }
 
-    /**
-     * Flushes a GNSS batch in progress
-     */
+
     @Override
     public void flushGnssBatch(String packageName) {
         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -1445,117 +1734,66 @@
             return;
         }
 
-        if (!mGnssBatchingInProgress) {
-            Log.w(TAG, "flushGnssBatch called with no batch in progress");
-        }
+        synchronized (mLock) {
+            if (!mGnssBatchingInProgress) {
+                Log.w(TAG, "flushGnssBatch called with no batch in progress");
+            }
 
-        if (mGnssBatchingProvider != null) {
-            mGnssBatchingProvider.flush();
+            if (mGnssBatchingProvider != null) {
+                mGnssBatchingProvider.flush();
+            }
         }
     }
 
-    /**
-     * Stops GNSS batching
-     */
     @Override
     public boolean stopGnssBatch() {
         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
                 "Location Hardware permission not granted to access hardware batching");
 
-        if (mGnssBatchingProvider != null) {
-            mGnssBatchingInProgress = false;
-            return mGnssBatchingProvider.stop();
-        } else {
-            return false;
-        }
-    }
-
-    @Override
-    public void reportLocationBatch(List<Location> locations) {
-        checkCallerIsProvider();
-
-        // Currently used only for GNSS locations - update permissions check if changed
-        if (isAllowedByUserSettingsLockedForUser(LocationManager.GPS_PROVIDER, mCurrentUserId)) {
-            if (mGnssBatchingCallback == null) {
-                Slog.e(TAG, "reportLocationBatch() called without active Callback");
-                return;
-            }
-            try {
-                mGnssBatchingCallback.onLocationBatch(locations);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
-            }
-        } else {
-            Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
-        }
-    }
-
-    private void addProviderLocked(LocationProvider provider) {
-        mProviders.add(provider);
-        mProvidersByName.put(provider.getName(), provider);
-    }
-
-    private void removeProviderLocked(LocationProvider provider) {
-        mProviders.remove(provider);
-        mProvidersByName.remove(provider.getName());
-    }
-
-    /**
-     * Returns "true" if access to the specified location provider is allowed by the specified
-     * user's settings. Access to all location providers is forbidden to non-location-provider
-     * processes belonging to background users.
-     *
-     * @param provider the name of the location provider
-     * @param userId   the user id to query
-     */
-    private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
-        if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
-            return isLocationEnabledForUser(userId);
-        }
-        if (LocationManager.FUSED_PROVIDER.equals(provider)) {
-            return isLocationEnabledForUser(userId);
-        }
         synchronized (mLock) {
-            if (mMockProviders.containsKey(provider)) {
-                return isLocationEnabledForUser(userId);
+            if (mGnssBatchingProvider != null) {
+                mGnssBatchingInProgress = false;
+                return mGnssBatchingProvider.stop();
+            } else {
+                return false;
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void addProviderLocked(LocationProvider provider) {
+        Preconditions.checkState(getLocationProviderLocked(provider.getName()) == null);
+
+        mProviders.add(provider);
+
+        provider.onAllowedChangedLocked();  // allowed state may change while provider was inactive
+        provider.onUseableChangedLocked();
+    }
+
+    @GuardedBy("mLock")
+    private void removeProviderLocked(LocationProvider provider) {
+        if (mProviders.remove(provider)) {
+            long identity = Binder.clearCallingIdentity();
+            try {
+                provider.onUseableChangedLocked();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    private LocationProvider getLocationProviderLocked(String providerName) {
+        for (LocationProvider provider : mProviders) {
+            if (providerName.equals(provider.getName())) {
+                return provider;
             }
         }
 
-        long identity = Binder.clearCallingIdentity();
-        try {
-            // Use system settings
-            ContentResolver cr = mContext.getContentResolver();
-            String allowedProviders = Settings.Secure.getStringForUser(
-                    cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
-            return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
+        return null;
     }
 
-
-    /**
-     * Returns "true" if access to the specified location provider is allowed by the specified
-     * user's settings. Access to all location providers is forbidden to non-location-provider
-     * processes belonging to background users.
-     *
-     * @param provider the name of the location provider
-     * @param uid      the requestor's UID
-     * @param userId   the user id to query
-     */
-    private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
-        if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
-            return false;
-        }
-        return isAllowedByUserSettingsLockedForUser(provider, userId);
-    }
-
-    /**
-     * Returns the permission string associated with the specified resolution level.
-     *
-     * @param resolutionLevel the resolution level
-     * @return the permission string
-     */
     private String getResolutionPermission(int resolutionLevel) {
         switch (resolutionLevel) {
             case RESOLUTION_LEVEL_FINE:
@@ -1567,13 +1805,6 @@
         }
     }
 
-    /**
-     * Returns the resolution level allowed to the given PID/UID pair.
-     *
-     * @param pid the PID
-     * @param uid the UID
-     * @return resolution level allowed to the pid/uid pair
-     */
     private int getAllowedResolutionLevel(int pid, int uid) {
         if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
                 pid, uid) == PERMISSION_GRANTED) {
@@ -1586,39 +1817,22 @@
         }
     }
 
-    /**
-     * Returns the resolution level allowed to the caller
-     *
-     * @return resolution level allowed to caller
-     */
     private int getCallerAllowedResolutionLevel() {
         return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
     }
 
-    /**
-     * Throw SecurityException if specified resolution level is insufficient to use geofences.
-     *
-     * @param allowedResolutionLevel resolution level allowed to caller
-     */
     private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
         if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
             throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
         }
     }
 
-    /**
-     * Return the minimum resolution level required to use the specified location provider.
-     *
-     * @param provider the name of the location provider
-     * @return minimum resolution level required for provider
-     */
-    private int getMinimumResolutionLevelForProviderUse(String provider) {
-        if (LocationManager.GPS_PROVIDER.equals(provider) ||
-                LocationManager.PASSIVE_PROVIDER.equals(provider)) {
+    @GuardedBy("mLock")
+    private int getMinimumResolutionLevelForProviderUseLocked(String provider) {
+        if (GPS_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) {
             // gps and passive providers require FINE permission
             return RESOLUTION_LEVEL_FINE;
-        } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
-                LocationManager.FUSED_PROVIDER.equals(provider)) {
+        } else if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
             // network and fused providers are ok with COARSE or FINE
             return RESOLUTION_LEVEL_COARSE;
         } else {
@@ -1627,7 +1841,7 @@
                     continue;
                 }
 
-                ProviderProperties properties = lp.getProperties();
+                ProviderProperties properties = lp.getPropertiesLocked();
                 if (properties != null) {
                     if (properties.mRequiresSatellite) {
                         // provider requiring satellites require FINE permission
@@ -1643,16 +1857,10 @@
         return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
     }
 
-    /**
-     * Throw SecurityException if specified resolution level is insufficient to use the named
-     * location provider.
-     *
-     * @param allowedResolutionLevel resolution level allowed to caller
-     * @param providerName           the name of the location provider
-     */
-    private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
+    @GuardedBy("mLock")
+    private void checkResolutionLevelIsSufficientForProviderUseLocked(int allowedResolutionLevel,
             String providerName) {
-        int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
+        int requiredResolutionLevel = getMinimumResolutionLevelForProviderUseLocked(providerName);
         if (allowedResolutionLevel < requiredResolutionLevel) {
             switch (requiredResolutionLevel) {
                 case RESOLUTION_LEVEL_FINE:
@@ -1668,20 +1876,6 @@
         }
     }
 
-    /**
-     * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
-     * for battery).
-     */
-    private void checkDeviceStatsAllowed() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.UPDATE_DEVICE_STATS, null);
-    }
-
-    private void checkUpdateAppOpsAllowed() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
-    }
-
     public static int resolutionLevelToOp(int allowedResolutionLevel) {
         if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
             if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
@@ -1739,19 +1933,17 @@
      */
     @Override
     public List<String> getAllProviders() {
-        ArrayList<String> out;
         synchronized (mLock) {
-            out = new ArrayList<>(mProviders.size());
+            ArrayList<String> providers = new ArrayList<>(mProviders.size());
             for (LocationProvider provider : mProviders) {
                 String name = provider.getName();
-                if (LocationManager.FUSED_PROVIDER.equals(name)) {
+                if (FUSED_PROVIDER.equals(name)) {
                     continue;
                 }
-                out.add(name);
+                providers.add(name);
             }
+            return providers;
         }
-        if (D) Log.d(TAG, "getAllProviders()=" + out);
-        return out;
     }
 
     /**
@@ -1762,37 +1954,28 @@
     @Override
     public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
-        ArrayList<String> out;
-        int uid = Binder.getCallingUid();
-        long identity = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                out = new ArrayList<>(mProviders.size());
-                for (LocationProvider provider : mProviders) {
-                    String name = provider.getName();
-                    if (LocationManager.FUSED_PROVIDER.equals(name)) {
-                        continue;
-                    }
-                    if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
-                        if (enabledOnly
-                                && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
-                            continue;
-                        }
-                        if (criteria != null
-                                && !android.location.LocationProvider.propertiesMeetCriteria(
-                                name, provider.getProperties(), criteria)) {
-                            continue;
-                        }
-                        out.add(name);
-                    }
+        synchronized (mLock) {
+            ArrayList<String> providers = new ArrayList<>(mProviders.size());
+            for (LocationProvider provider : mProviders) {
+                String name = provider.getName();
+                if (FUSED_PROVIDER.equals(name)) {
+                    continue;
                 }
+                if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) {
+                    continue;
+                }
+                if (enabledOnly && !provider.isUseableLocked()) {
+                    continue;
+                }
+                if (criteria != null
+                        && !android.location.LocationProvider.propertiesMeetCriteria(
+                        name, provider.getPropertiesLocked(), criteria)) {
+                    continue;
+                }
+                providers.add(name);
             }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+            return providers;
         }
-
-        if (D) Log.d(TAG, "getProviders()=" + out);
-        return out;
     }
 
     /**
@@ -1804,76 +1987,49 @@
      */
     @Override
     public String getBestProvider(Criteria criteria, boolean enabledOnly) {
-        String result;
-
         List<String> providers = getProviders(criteria, enabledOnly);
-        if (!providers.isEmpty()) {
-            result = pickBest(providers);
-            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
-            return result;
-        }
-        providers = getProviders(null, enabledOnly);
-        if (!providers.isEmpty()) {
-            result = pickBest(providers);
-            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
-            return result;
+        if (providers.isEmpty()) {
+            providers = getProviders(null, enabledOnly);
         }
 
-        if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + null);
+        if (!providers.isEmpty()) {
+            if (providers.contains(GPS_PROVIDER)) {
+                return GPS_PROVIDER;
+            } else if (providers.contains(NETWORK_PROVIDER)) {
+                return NETWORK_PROVIDER;
+            } else {
+                return providers.get(0);
+            }
+        }
+
         return null;
     }
 
-    private String pickBest(List<String> providers) {
-        if (providers.contains(LocationManager.GPS_PROVIDER)) {
-            return LocationManager.GPS_PROVIDER;
-        } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
-            return LocationManager.NETWORK_PROVIDER;
-        } else {
-            return providers.get(0);
-        }
-    }
-
-    @Override
-    public boolean providerMeetsCriteria(String provider, Criteria criteria) {
-        LocationProvider p = mProvidersByName.get(provider);
-        if (p == null) {
-            throw new IllegalArgumentException("provider=" + provider);
-        }
-
-        boolean result = android.location.LocationProvider.propertiesMeetCriteria(
-                p.getName(), p.getProperties(), criteria);
-        if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
-        return result;
-    }
-
-    private void updateProvidersSettingsLocked() {
-        for (LocationProvider p : mProviders) {
-            p.setSettingsEnabled(isAllowedByUserSettingsLockedForUser(p.getName(), mCurrentUserId));
-        }
-
-        mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
-                UserHandle.ALL);
-    }
-
-    private void updateProviderListenersLocked(String provider) {
-        LocationProvider p = mProvidersByName.get(provider);
-        if (p == null) return;
-
-        boolean enabled = p.isEnabled();
+    @GuardedBy("mLock")
+    private void updateProviderUseableLocked(LocationProvider provider) {
+        boolean useable = provider.isUseableLocked();
 
         ArrayList<Receiver> deadReceivers = null;
 
-        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
+        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
         if (records != null) {
             for (UpdateRecord record : records) {
-                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
-                    // Sends a notification message to the receiver
-                    if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
-                        if (deadReceivers == null) {
-                            deadReceivers = new ArrayList<>();
-                        }
-                        deadReceivers.add(record.mReceiver);
+                if (!isCurrentProfileLocked(
+                        UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
+                    continue;
+                }
+
+                // requests that ignore location settings will never provider notifications
+                if (isSettingsExemptLocked(record)) {
+                    continue;
+                }
+
+                // Sends a notification message to the receiver
+                if (!record.mReceiver.callProviderEnabledLocked(provider.getName(), useable)) {
+                    if (deadReceivers == null) {
+                        deadReceivers = new ArrayList<>();
                     }
+                    deadReceivers.add(record.mReceiver);
                 }
             }
         }
@@ -1887,53 +2043,72 @@
         applyRequirementsLocked(provider);
     }
 
-    private void applyRequirementsLocked(String provider) {
-        LocationProvider p = mProvidersByName.get(provider);
-        if (p == null) return;
+    @GuardedBy("mLock")
+    private void applyRequirementsLocked(String providerName) {
+        LocationProvider provider = getLocationProviderLocked(providerName);
+        if (provider != null) {
+            applyRequirementsLocked(provider);
+        }
+    }
 
-        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
+    @GuardedBy("mLock")
+    private void applyRequirementsLocked(LocationProvider provider) {
+        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
         WorkSource worksource = new WorkSource();
         ProviderRequest providerRequest = new ProviderRequest();
 
-        ContentResolver resolver = mContext.getContentResolver();
-        long backgroundThrottleInterval = Settings.Global.getLong(
-                resolver,
-                Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
-                DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
+        long backgroundThrottleInterval;
 
-        if (p.isEnabled() && records != null && !records.isEmpty()) {
+        long identity = Binder.clearCallingIdentity();
+        try {
+            backgroundThrottleInterval = Settings.Global.getLong(
+                    mContext.getContentResolver(),
+                    Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
+                    DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+
+        if (records != null && !records.isEmpty()) {
             // initialize the low power mode to true and set to false if any of the records requires
             providerRequest.lowPowerMode = true;
             for (UpdateRecord record : records) {
-                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
-                    if (checkLocationAccess(
-                            record.mReceiver.mIdentity.mPid,
-                            record.mReceiver.mIdentity.mUid,
-                            record.mReceiver.mIdentity.mPackageName,
-                            record.mReceiver.mAllowedResolutionLevel)) {
-                        LocationRequest locationRequest = record.mRealRequest;
-                        long interval = locationRequest.getInterval();
+                if (!isCurrentProfileLocked(
+                        UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
+                    continue;
+                }
+                if (!checkLocationAccess(
+                        record.mReceiver.mIdentity.mPid,
+                        record.mReceiver.mIdentity.mUid,
+                        record.mReceiver.mIdentity.mPackageName,
+                        record.mReceiver.mAllowedResolutionLevel)) {
+                    continue;
+                }
+                if (!provider.isUseableLocked() && !isSettingsExemptLocked(record)) {
+                    continue;
+                }
 
-                        if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
-                            if (!record.mIsForegroundUid) {
-                                interval = Math.max(interval, backgroundThrottleInterval);
-                            }
-                            if (interval != locationRequest.getInterval()) {
-                                locationRequest = new LocationRequest(locationRequest);
-                                locationRequest.setInterval(interval);
-                            }
-                        }
+                LocationRequest locationRequest = record.mRealRequest;
+                long interval = locationRequest.getInterval();
 
-                        record.mRequest = locationRequest;
-                        providerRequest.locationRequests.add(locationRequest);
-                        if (!locationRequest.isLowPowerMode()) {
-                            providerRequest.lowPowerMode = false;
-                        }
-                        if (interval < providerRequest.interval) {
-                            providerRequest.reportLocation = true;
-                            providerRequest.interval = interval;
-                        }
+                if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
+                    if (!record.mIsForegroundUid) {
+                        interval = Math.max(interval, backgroundThrottleInterval);
                     }
+                    if (interval != locationRequest.getInterval()) {
+                        locationRequest = new LocationRequest(locationRequest);
+                        locationRequest.setInterval(interval);
+                    }
+                }
+
+                record.mRequest = locationRequest;
+                providerRequest.locationRequests.add(locationRequest);
+                if (!locationRequest.isLowPowerMode()) {
+                    providerRequest.lowPowerMode = false;
+                }
+                if (interval < providerRequest.interval) {
+                    providerRequest.reportLocation = true;
+                    providerRequest.interval = interval;
                 }
             }
 
@@ -1945,7 +2120,8 @@
                 // under that threshold.
                 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
                 for (UpdateRecord record : records) {
-                    if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
+                    if (isCurrentProfileLocked(
+                            UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
                         LocationRequest locationRequest = record.mRequest;
 
                         // Don't assign battery blame for update records whose
@@ -1972,7 +2148,7 @@
         }
 
         if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
-        p.setRequest(providerRequest, worksource);
+        provider.setRequestLocked(providerRequest, worksource);
     }
 
     /**
@@ -1995,34 +2171,11 @@
     @Override
     public String[] getBackgroundThrottlingWhitelist() {
         synchronized (mLock) {
-            return mBackgroundThrottlePackageWhitelist.toArray(
-                    new String[0]);
+            return mBackgroundThrottlePackageWhitelist.toArray(new String[0]);
         }
     }
 
-    private void updateBackgroundThrottlingWhitelistLocked() {
-        String setting = Settings.Global.getString(
-                mContext.getContentResolver(),
-                Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
-        if (setting == null) {
-            setting = "";
-        }
-
-        mBackgroundThrottlePackageWhitelist.clear();
-        mBackgroundThrottlePackageWhitelist.addAll(
-                SystemConfig.getInstance().getAllowUnthrottledLocation());
-        mBackgroundThrottlePackageWhitelist.addAll(
-                Arrays.asList(setting.split(",")));
-    }
-
-    private void updateLastLocationMaxAgeLocked() {
-        mLastLocationMaxAgeMs =
-                Settings.Global.getLong(
-                        mContext.getContentResolver(),
-                        Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
-                        DEFAULT_LAST_LOCATION_MAX_AGE_MS);
-    }
-
+    @GuardedBy("mLock")
     private boolean isThrottlingExemptLocked(Identity identity) {
         if (identity.mUid == Process.SYSTEM_UID) {
             return true;
@@ -2032,8 +2185,27 @@
             return true;
         }
 
-        for (LocationProviderProxy provider : mProxyProviders) {
-            if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
+        for (LocationProvider provider : mProviders) {
+            if (identity.mPackageName.equals(provider.getPackageLocked())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @GuardedBy("mLock")
+    private boolean isSettingsExemptLocked(UpdateRecord record) {
+        if (!record.mRealRequest.isLocationSettingsIgnored()) {
+            return false;
+        }
+
+        if (mBackgroundThrottlePackageWhitelist.contains(record.mReceiver.mIdentity.mPackageName)) {
+            return true;
+        }
+
+        for (LocationProvider provider : mProviders) {
+            if (record.mReceiver.mIdentity.mPackageName.equals(provider.getPackageLocked())) {
                 return true;
             }
         }
@@ -2119,6 +2291,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
             String packageName, WorkSource workSource, boolean hideFromAppOps) {
         IBinder binder = listener.asBinder();
@@ -2137,6 +2310,7 @@
         return receiver;
     }
 
+    @GuardedBy("mLock")
     private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
             WorkSource workSource, boolean hideFromAppOps) {
         Receiver receiver = mReceivers.get(intent);
@@ -2182,7 +2356,7 @@
         }
         // make getFastestInterval() the minimum of interval and fastest interval
         if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
-            request.setFastestInterval(request.getInterval());
+            sanitizedRequest.setFastestInterval(request.getInterval());
         }
         return sanitizedRequest;
     }
@@ -2202,67 +2376,69 @@
         throw new SecurityException("invalid package name: " + packageName);
     }
 
-    private void checkPendingIntent(PendingIntent intent) {
-        if (intent == null) {
-            throw new IllegalArgumentException("invalid pending intent: " + null);
-        }
-    }
-
-    private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
-            int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
-        if (intent == null && listener == null) {
-            throw new IllegalArgumentException("need either listener or intent");
-        } else if (intent != null && listener != null) {
-            throw new IllegalArgumentException("cannot register both listener and intent");
-        } else if (intent != null) {
-            checkPendingIntent(intent);
-            return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
-        } else {
-            return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
-        }
-    }
-
     @Override
     public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
             PendingIntent intent, String packageName) {
-        if (request == null) request = DEFAULT_LOCATION_REQUEST;
-        checkPackageName(packageName);
-        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
-        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
-                request.getProvider());
-        WorkSource workSource = request.getWorkSource();
-        if (workSource != null && !workSource.isEmpty()) {
-            checkDeviceStatsAllowed();
-        }
-        boolean hideFromAppOps = request.getHideFromAppOps();
-        if (hideFromAppOps) {
-            checkUpdateAppOpsAllowed();
-        }
-        boolean callerHasLocationHardwarePermission =
-                mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
-                        == PERMISSION_GRANTED;
-        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
-                callerHasLocationHardwarePermission);
-
-        final int pid = Binder.getCallingPid();
-        final int uid = Binder.getCallingUid();
-        // providers may use public location API's, need to clear identity
-        long identity = Binder.clearCallingIdentity();
-        try {
-            // We don't check for MODE_IGNORED here; we will do that when we go to deliver
-            // a location.
-            checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
-
-            synchronized (mLock) {
-                Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
-                        packageName, workSource, hideFromAppOps);
-                requestLocationUpdatesLocked(sanitizedRequest, recevier, uid, packageName);
+        synchronized (mLock) {
+            if (request == null) request = DEFAULT_LOCATION_REQUEST;
+            checkPackageName(packageName);
+            int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+            checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
+                    request.getProvider());
+            WorkSource workSource = request.getWorkSource();
+            if (workSource != null && !workSource.isEmpty()) {
+                mContext.enforceCallingOrSelfPermission(
+                        Manifest.permission.UPDATE_DEVICE_STATS, null);
             }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+            boolean hideFromAppOps = request.getHideFromAppOps();
+            if (hideFromAppOps) {
+                mContext.enforceCallingOrSelfPermission(
+                        Manifest.permission.UPDATE_APP_OPS_STATS, null);
+            }
+            if (request.isLocationSettingsIgnored()) {
+                mContext.enforceCallingOrSelfPermission(
+                        Manifest.permission.WRITE_SECURE_SETTINGS, null);
+            }
+            boolean callerHasLocationHardwarePermission =
+                    mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
+                            == PERMISSION_GRANTED;
+            LocationRequest sanitizedRequest = createSanitizedRequest(request,
+                    allowedResolutionLevel,
+                    callerHasLocationHardwarePermission);
+
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+
+            long identity = Binder.clearCallingIdentity();
+            try {
+
+                // We don't check for MODE_IGNORED here; we will do that when we go to deliver
+                // a location.
+                checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
+
+                if (intent == null && listener == null) {
+                    throw new IllegalArgumentException("need either listener or intent");
+                } else if (intent != null && listener != null) {
+                    throw new IllegalArgumentException(
+                            "cannot register both listener and intent");
+                }
+
+                Receiver receiver;
+                if (intent != null) {
+                    receiver = getReceiverLocked(intent, pid, uid, packageName, workSource,
+                            hideFromAppOps);
+                } else {
+                    receiver = getReceiverLocked(listener, pid, uid, packageName, workSource,
+                            hideFromAppOps);
+                }
+                requestLocationUpdatesLocked(sanitizedRequest, receiver, uid, packageName);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
     }
 
+    @GuardedBy("mLock")
     private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
             int uid, String packageName) {
         // Figure out the provider. Either its explicitly request (legacy use cases), or
@@ -2273,7 +2449,7 @@
             throw new IllegalArgumentException("provider name must not be null");
         }
 
-        LocationProvider provider = mProvidersByName.get(name);
+        LocationProvider provider = getLocationProviderLocked(name);
         if (provider == null) {
             throw new IllegalArgumentException("provider doesn't exist: " + name);
         }
@@ -2292,12 +2468,14 @@
             oldRecord.disposeLocked(false);
         }
 
-        if (provider.isEnabled()) {
-            applyRequirementsLocked(name);
-        } else {
-            // Notify the listener that updates are currently disabled
+        if (!provider.isUseableLocked() && !isSettingsExemptLocked(record)) {
+            // Notify the listener that updates are currently disabled - but only if the request
+            // does not ignore location settings
             receiver.callProviderEnabledLocked(name, false);
         }
+
+        applyRequirementsLocked(name);
+
         // Update the monitoring here just in case multiple location requests were added to the
         // same receiver (this request may be high power and the initial might not have been).
         receiver.updateMonitoring(true);
@@ -2308,14 +2486,23 @@
             String packageName) {
         checkPackageName(packageName);
 
-        final int pid = Binder.getCallingPid();
-        final int uid = Binder.getCallingUid();
+        int pid = Binder.getCallingPid();
+        int uid = Binder.getCallingUid();
+
+        if (intent == null && listener == null) {
+            throw new IllegalArgumentException("need either listener or intent");
+        } else if (intent != null && listener != null) {
+            throw new IllegalArgumentException("cannot register both listener and intent");
+        }
 
         synchronized (mLock) {
-            Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
-                    packageName, null, false);
+            Receiver receiver;
+            if (intent != null) {
+                receiver = getReceiverLocked(intent, pid, uid, packageName, null, false);
+            } else {
+                receiver = getReceiverLocked(listener, pid, uid, packageName, null, false);
+            }
 
-            // providers may use public location API's, need to clear identity
             long identity = Binder.clearCallingIdentity();
             try {
                 removeUpdatesLocked(receiver);
@@ -2325,6 +2512,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void removeUpdatesLocked(Receiver receiver) {
         if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
 
@@ -2356,51 +2544,53 @@
         }
     }
 
-    private void applyAllProviderRequirementsLocked() {
-        for (LocationProvider p : mProviders) {
-            applyRequirementsLocked(p.getName());
-        }
-    }
-
     @Override
-    public Location getLastLocation(LocationRequest request, String packageName) {
-        if (D) Log.d(TAG, "getLastLocation: " + request);
-        if (request == null) request = DEFAULT_LOCATION_REQUEST;
-        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
-        checkPackageName(packageName);
-        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
-                request.getProvider());
-        // no need to sanitize this request, as only the provider name is used
+    public Location getLastLocation(LocationRequest r, String packageName) {
+        if (D) Log.d(TAG, "getLastLocation: " + r);
+        synchronized (mLock) {
+            LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
+            int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+            checkPackageName(packageName);
+            checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
+                    request.getProvider());
+            // no need to sanitize this request, as only the provider name is used
 
-        final int pid = Binder.getCallingPid();
-        final int uid = Binder.getCallingUid();
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            if (mBlacklist.isBlacklisted(packageName)) {
-                if (D) {
-                    Log.d(TAG, "not returning last loc for blacklisted app: " +
-                            packageName);
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                if (mBlacklist.isBlacklisted(packageName)) {
+                    if (D) {
+                        Log.d(TAG, "not returning last loc for blacklisted app: "
+                                + packageName);
+                    }
+                    return null;
                 }
-                return null;
-            }
 
-            if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
-                if (D) {
-                    Log.d(TAG, "not returning last loc for no op app: " +
-                            packageName);
+                if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
+                    if (D) {
+                        Log.d(TAG, "not returning last loc for no op app: "
+                                + packageName);
+                    }
+                    return null;
                 }
-                return null;
-            }
 
-            synchronized (mLock) {
                 // Figure out the provider. Either its explicitly request (deprecated API's),
                 // or use the fused provider
                 String name = request.getProvider();
                 if (name == null) name = LocationManager.FUSED_PROVIDER;
-                LocationProvider provider = mProvidersByName.get(name);
+                LocationProvider provider = getLocationProviderLocked(name);
                 if (provider == null) return null;
 
-                if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
+                // only the current user or location providers may get location this way
+                if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isLocationProviderLocked(
+                        uid)) {
+                    return null;
+                }
+
+                if (!provider.isUseableLocked()) {
+                    return null;
+                }
 
                 Location location;
                 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
@@ -2416,9 +2606,12 @@
 
                 // Don't return stale location to apps with foreground-only location permission.
                 String op = resolutionLevelToOpStr(allowedResolutionLevel);
-                long locationAgeMs = SystemClock.elapsedRealtime() -
-                        location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
-                if ((locationAgeMs > mLastLocationMaxAgeMs)
+                long locationAgeMs = SystemClock.elapsedRealtime()
+                        - location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
+                if ((locationAgeMs > Settings.Global.getLong(
+                        mContext.getContentResolver(),
+                        Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
+                        DEFAULT_LAST_LOCATION_MAX_AGE_MS))
                         && (mAppOps.unsafeCheckOp(op, uid, packageName)
                         == AppOpsManager.MODE_FOREGROUND)) {
                     return null;
@@ -2433,24 +2626,13 @@
                 } else {
                     return new Location(location);
                 }
+                return null;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
             }
-            return null;
-        } finally {
-            Binder.restoreCallingIdentity(identity);
         }
     }
 
-    /**
-     * Provides an interface to inject and set the last location if location is not available
-     * currently.
-     *
-     * This helps in cases where the product (Cars for example) has saved the last known location
-     * before powering off.  This interface lets the client inject the saved location while the GPS
-     * chipset is getting its first fix, there by improving user experience.
-     *
-     * @param location - Location object to inject
-     * @return true if update was successful, false if not
-     */
     @Override
     public boolean injectLocation(Location location) {
         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
@@ -2464,38 +2646,23 @@
             }
             return false;
         }
-        LocationProvider p = null;
-        String provider = location.getProvider();
-        if (provider != null) {
-            p = mProvidersByName.get(provider);
-        }
-        if (p == null) {
-            if (D) {
-                Log.d(TAG, "injectLocation(): unknown provider");
-            }
-            return false;
-        }
+
         synchronized (mLock) {
-            if (!isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId)) {
-                if (D) {
-                    Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId);
-                }
+            LocationProvider provider = getLocationProviderLocked(location.getProvider());
+            if (provider == null || !provider.isUseableLocked()) {
                 return false;
-            } else {
-                // NOTE: If last location is already available, location is not injected.  If
-                // provider's normal source (like a GPS chipset) have already provided an output,
-                // there is no need to inject this location.
-                if (mLastLocation.get(provider) == null) {
-                    updateLastLocationLocked(location, provider);
-                } else {
-                    if (D) {
-                        Log.d(TAG, "injectLocation(): Location exists. Not updating");
-                    }
-                    return false;
-                }
             }
+
+            // NOTE: If last location is already available, location is not injected.  If
+            // provider's normal source (like a GPS chipset) have already provided an output
+            // there is no need to inject this location.
+            if (mLastLocation.get(provider.getName()) != null) {
+                return false;
+            }
+
+            updateLastLocationLocked(location, provider.getName());
+            return true;
         }
-        return true;
     }
 
     @Override
@@ -2504,39 +2671,49 @@
         if (request == null) request = DEFAULT_LOCATION_REQUEST;
         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
         checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
-        checkPendingIntent(intent);
-        checkPackageName(packageName);
-        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
-                request.getProvider());
-        // Require that caller can manage given document
-        boolean callerHasLocationHardwarePermission =
-                mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
-                        == PERMISSION_GRANTED;
-        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
-                callerHasLocationHardwarePermission);
-
-        if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
-
-        // geo-fence manager uses the public location API, need to clear identity
-        int uid = Binder.getCallingUid();
-        // TODO: http://b/23822629
-        if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
-            // temporary measure until geofences work for secondary users
-            Log.w(TAG, "proximity alerts are currently available only to the primary user");
-            return;
+        if (intent == null) {
+            throw new IllegalArgumentException("invalid pending intent: " + null);
         }
-        long identity = Binder.clearCallingIdentity();
-        try {
-            mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
-                    uid, packageName);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+        checkPackageName(packageName);
+        synchronized (mLock) {
+            checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
+                    request.getProvider());
+            // Require that caller can manage given document
+            boolean callerHasLocationHardwarePermission =
+                    mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
+                            == PERMISSION_GRANTED;
+            LocationRequest sanitizedRequest = createSanitizedRequest(request,
+                    allowedResolutionLevel,
+                    callerHasLocationHardwarePermission);
+
+            if (D) {
+                Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
+            }
+
+            // geo-fence manager uses the public location API, need to clear identity
+            int uid = Binder.getCallingUid();
+            // TODO: http://b/23822629
+            if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
+                // temporary measure until geofences work for secondary users
+                Log.w(TAG, "proximity alerts are currently available only to the primary user");
+                return;
+            }
+            long identity = Binder.clearCallingIdentity();
+            try {
+                mGeofenceManager.addFence(sanitizedRequest, geofence, intent,
+                        allowedResolutionLevel,
+                        uid, packageName);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
     }
 
     @Override
     public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
-        checkPendingIntent(intent);
+        if (intent == null) {
+            throw new IllegalArgumentException("invalid pending intent: " + null);
+        }
         checkPackageName(packageName);
 
         if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
@@ -2641,6 +2818,7 @@
         synchronized (mLock) {
             Identity callerIdentity
                     = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+
             // TODO(b/120481270): Register for client death notification and update map.
             mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
             long identity = Binder.clearCallingIdentity();
@@ -2670,25 +2848,26 @@
     }
 
     @Override
-    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
-        if (provider == null) {
+    public boolean sendExtraCommand(String providerName, String command, Bundle extras) {
+        if (providerName == null) {
             // throw NullPointerException to remain compatible with previous implementation
             throw new NullPointerException();
         }
-        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
-                provider);
-
-        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
-        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
-                != PERMISSION_GRANTED)) {
-            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
-        }
-
         synchronized (mLock) {
-            LocationProvider p = mProvidersByName.get(provider);
-            if (p == null) return false;
+            checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
+                    providerName);
 
-            p.sendExtraCommand(command, extras);
+            // and check for ACCESS_LOCATION_EXTRA_COMMANDS
+            if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
+                    != PERMISSION_GRANTED)) {
+                throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
+            }
+
+            LocationProvider provider = getLocationProviderLocked(providerName);
+            if (provider != null) {
+                provider.sendExtraCommandLocked(command, extras);
+            }
+
             return true;
         }
     }
@@ -2707,44 +2886,29 @@
         }
     }
 
-    /**
-     * @return null if the provider does not exist
-     * @throws SecurityException if the provider is not allowed to be
-     *                           accessed by the caller
-     */
     @Override
-    public ProviderProperties getProviderProperties(String provider) {
-        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
-                provider);
-
-        LocationProvider p;
+    public ProviderProperties getProviderProperties(String providerName) {
         synchronized (mLock) {
-            p = mProvidersByName.get(provider);
-        }
+            checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
+                    providerName);
 
-        if (p == null) return null;
-        return p.getProperties();
+            LocationProvider provider = getLocationProviderLocked(providerName);
+            if (provider == null) {
+                return null;
+            }
+            return provider.getPropertiesLocked();
+        }
     }
 
-    /**
-     * @return null if the provider does not exist
-     * @throws SecurityException if the provider is not allowed to be
-     *                           accessed by the caller
-     */
     @Override
     public String getNetworkProviderPackage() {
-        LocationProvider p;
         synchronized (mLock) {
-            p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
+            LocationProvider provider = getLocationProviderLocked(NETWORK_PROVIDER);
+            if (provider == null) {
+                return null;
+            }
+            return provider.getPackageLocked();
         }
-
-        if (p == null) {
-            return null;
-        }
-        if (p.mProvider instanceof LocationProviderProxy) {
-            return ((LocationProviderProxy) p.mProvider).getConnectedPackageName();
-        }
-        return null;
     }
 
     @Override
@@ -2780,241 +2944,74 @@
         }
     }
 
-    /**
-     * Returns the current location enabled/disabled status for a user
-     *
-     * @param userId the id of the user
-     * @return true if location is enabled
-     */
+    private boolean isLocationEnabled() {
+        return isLocationEnabledForUser(mCurrentUserId);
+    }
+
     @Override
     public boolean isLocationEnabledForUser(int userId) {
         // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
-        checkInteractAcrossUsersPermission(userId);
+        if (UserHandle.getCallingUserId() != userId) {
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS,
+                    "Requires INTERACT_ACROSS_USERS permission");
+        }
 
         long identity = Binder.clearCallingIdentity();
         try {
-            synchronized (mLock) {
-                final String allowedProviders = Settings.Secure.getStringForUser(
+            return Settings.Secure.getIntForUser(
                         mContext.getContentResolver(),
-                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                        userId);
-                if (allowedProviders == null) {
-                    return false;
-                }
-                final List<String> providerList = Arrays.asList(allowedProviders.split(","));
-                for (String provider : mRealProviders.keySet()) {
-                    if (provider.equals(LocationManager.PASSIVE_PROVIDER)
-                            || provider.equals(LocationManager.FUSED_PROVIDER)) {
-                        continue;
-                    }
-                    if (providerList.contains(provider)) {
-                        return true;
-                    }
-                }
-                return false;
-            }
+                        Settings.Secure.LOCATION_MODE,
+                        Settings.Secure.LOCATION_MODE_OFF,
+                        userId) != Settings.Secure.LOCATION_MODE_OFF;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
-    /**
-     * Enable or disable location for a user
-     *
-     * @param enabled true to enable location, false to disable location
-     * @param userId  the id of the user
-     */
-    @Override
-    public void setLocationEnabledForUser(boolean enabled, int userId) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.WRITE_SECURE_SETTINGS,
-                "Requires WRITE_SECURE_SETTINGS permission");
-
-        // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
-        checkInteractAcrossUsersPermission(userId);
-
-        long identity = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                final Set<String> allRealProviders = mRealProviders.keySet();
-                // Update all providers on device plus gps and network provider when disabling
-                // location
-                Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
-                allProvidersSet.addAll(allRealProviders);
-                // When disabling location, disable gps and network provider that could have been
-                // enabled by location mode api.
-                if (!enabled) {
-                    allProvidersSet.add(LocationManager.GPS_PROVIDER);
-                    allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
-                }
-                if (allProvidersSet.isEmpty()) {
-                    return;
-                }
-                // to ensure thread safety, we write the provider name with a '+' or '-'
-                // and let the SettingsProvider handle it rather than reading and modifying
-                // the list of enabled providers.
-                final String prefix = enabled ? "+" : "-";
-                StringBuilder locationProvidersAllowed = new StringBuilder();
-                for (String provider : allProvidersSet) {
-                    if (provider.equals(LocationManager.PASSIVE_PROVIDER)
-                            || provider.equals(LocationManager.FUSED_PROVIDER)) {
-                        continue;
-                    }
-                    locationProvidersAllowed.append(prefix);
-                    locationProvidersAllowed.append(provider);
-                    locationProvidersAllowed.append(",");
-                }
-                // Remove the trailing comma
-                locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
-                Settings.Secure.putStringForUser(
-                        mContext.getContentResolver(),
-                        Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                        locationProvidersAllowed.toString(),
-                        userId);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    /**
-     * Returns the current enabled/disabled status of a location provider and user
-     *
-     * @param providerName name of the provider
-     * @param userId       the id of the user
-     * @return true if the provider exists and is enabled
-     */
     @Override
     public boolean isProviderEnabledForUser(String providerName, int userId) {
         // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
-        checkInteractAcrossUsersPermission(userId);
-
-        if (!isLocationEnabledForUser(userId)) {
-            return false;
+        if (UserHandle.getCallingUserId() != userId) {
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS,
+                    "Requires INTERACT_ACROSS_USERS permission");
         }
 
         // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
         // so we discourage its use
-        if (LocationManager.FUSED_PROVIDER.equals(providerName)) return false;
+        if (FUSED_PROVIDER.equals(providerName)) return false;
 
-        long identity = Binder.clearCallingIdentity();
-        try {
-            LocationProvider provider;
-            synchronized (mLock) {
-                provider = mProvidersByName.get(providerName);
-            }
-            return provider != null && provider.isEnabled();
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+        synchronized (mLock) {
+            LocationProvider provider = getLocationProviderLocked(providerName);
+            return provider != null && provider.isUseableForUserLocked(userId);
         }
     }
 
-    /**
-     * Enable or disable a single location provider.
-     *
-     * @param provider name of the provider
-     * @param enabled  true to enable the provider. False to disable the provider
-     * @param userId   the id of the user to set
-     * @return true if the value was set, false on errors
-     */
-    @Override
-    public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
-        return false;
-    }
-
-    /**
-     * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
-     * current user id
-     *
-     * @param userId the user id to get or set value
-     */
-    private void checkInteractAcrossUsersPermission(int userId) {
-        int uid = Binder.getCallingUid();
-        if (UserHandle.getUserId(uid) != userId) {
-            if (ActivityManager.checkComponentPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
-                    != PERMISSION_GRANTED) {
-                throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
-            }
-        }
-    }
-
-    /**
-     * Returns "true" if the UID belongs to a bound location provider.
-     *
-     * @param uid the uid
-     * @return true if uid belongs to a bound location provider
-     */
-    private boolean isUidALocationProvider(int uid) {
+    @GuardedBy("mLock")
+    private boolean isLocationProviderLocked(int uid) {
         if (uid == Process.SYSTEM_UID) {
             return true;
         }
-        if (mGeocodeProvider != null) {
-            if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
-        }
-        for (LocationProviderProxy proxy : mProxyProviders) {
-            if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
-        }
-        return false;
-    }
 
-    private void checkCallerIsProvider() {
-        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
-                == PERMISSION_GRANTED) {
-            return;
-        }
-
-        // Previously we only used the INSTALL_LOCATION_PROVIDER
-        // check. But that is system or signature
-        // protection level which is not flexible enough for
-        // providers installed oustide the system image. So
-        // also allow providers with a UID matching the
-        // currently bound package name
-
-        if (isUidALocationProvider(Binder.getCallingUid())) {
-            return;
-        }
-
-        throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
-                "or UID of a currently bound location provider");
-    }
-
-    /**
-     * Returns true if the given package belongs to the given uid.
-     */
-    private boolean doesUidHavePackage(int uid, String packageName) {
-        if (packageName == null) {
-            return false;
-        }
         String[] packageNames = mPackageManager.getPackagesForUid(uid);
         if (packageNames == null) {
             return false;
         }
-        for (String name : packageNames) {
-            if (packageName.equals(name)) {
+        for (LocationProvider provider : mProviders) {
+            String packageName = provider.getPackageLocked();
+            if (packageName == null) {
+                continue;
+            }
+            if (ArrayUtils.contains(packageNames, packageName)) {
                 return true;
             }
         }
         return false;
     }
 
-    @Override
-    public void reportLocation(Location location, boolean passive) {
-        checkCallerIsProvider();
-
-        if (!location.isComplete()) {
-            Log.w(TAG, "Dropping incomplete location: " + location);
-            return;
-        }
-
-        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
-        Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
-        m.arg1 = (passive ? 1 : 0);
-        mLocationHandler.sendMessageAtFrontOfQueue(m);
-    }
-
-
-    private static boolean shouldBroadcastSafe(
+    @GuardedBy("mLock")
+    private static boolean shouldBroadcastSafeLocked(
             Location loc, Location lastLoc, UpdateRecord record, long now) {
         // Always broadcast the first update
         if (lastLoc == null) {
@@ -3046,26 +3043,39 @@
         return record.mRealRequest.getExpireAt() >= now;
     }
 
-    private void handleLocationChangedLocked(Location location, boolean passive) {
-        if (D) Log.d(TAG, "incoming location: " + location);
-        long now = SystemClock.elapsedRealtime();
-        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
-        // Skip if the provider is unknown.
-        LocationProvider p = mProvidersByName.get(provider);
-        if (p == null) return;
-        updateLastLocationLocked(location, provider);
-        // mLastLocation should have been updated from the updateLastLocationLocked call above.
-        Location lastLocation = mLastLocation.get(provider);
-        if (lastLocation == null) {
-            Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
+    @GuardedBy("mLock")
+    private void handleLocationChangedLocked(Location location, LocationProvider provider) {
+        if (!mProviders.contains(provider)) {
+            return;
+        }
+        if (!location.isComplete()) {
+            Log.w(TAG, "Dropping incomplete location: " + location);
             return;
         }
 
+        // only notify passive provider and update last location for locations that come from
+        // useable providers
+        if (provider.isUseableLocked()) {
+            if (!provider.isPassiveLocked()) {
+                mPassiveProvider.updateLocation(location);
+            }
+        }
+
+        if (D) Log.d(TAG, "incoming location: " + location);
+        long now = SystemClock.elapsedRealtime();
+        if (provider.isUseableLocked()) {
+            updateLastLocationLocked(location, provider.getName());
+        }
+
         // Update last known coarse interval location if enough time has passed.
-        Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
+        Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(
+                provider.getName());
         if (lastLocationCoarseInterval == null) {
             lastLocationCoarseInterval = new Location(location);
-            mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
+
+            if (provider.isUseableLocked()) {
+                mLastLocationCoarseInterval.put(provider.getName(), lastLocationCoarseInterval);
+            }
         }
         long timeDiffNanos = location.getElapsedRealtimeNanos()
                 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
@@ -3079,7 +3089,7 @@
                 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
 
         // Skip if there are no UpdateRecords for this provider.
-        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
+        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
         if (records == null || records.size() == 0) return;
 
         // Fetch coarse location
@@ -3088,13 +3098,6 @@
             coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
         }
 
-        // Fetch latest status update time
-        long newStatusUpdateTime = p.getStatusUpdateTime();
-
-        // Get latest status
-        Bundle extras = new Bundle();
-        int status = p.getStatus(extras);
-
         ArrayList<Receiver> deadReceivers = null;
         ArrayList<UpdateRecord> deadUpdateRecords = null;
 
@@ -3103,9 +3106,13 @@
             Receiver receiver = r.mReceiver;
             boolean receiverDead = false;
 
+            if (!provider.isUseableLocked() && !isSettingsExemptLocked(r)) {
+                continue;
+            }
+
             int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
-            if (!isCurrentProfile(receiverUserId)
-                    && !isUidALocationProvider(receiver.mIdentity.mUid)) {
+            if (!isCurrentProfileLocked(receiverUserId)
+                    && !isLocationProviderLocked(receiver.mIdentity.mUid)) {
                 if (D) {
                     Log.d(TAG, "skipping loc update for background user " + receiverUserId +
                             " (current user: " + mCurrentUserId + ", app: " +
@@ -3138,11 +3145,12 @@
             if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
                 notifyLocation = coarseLocation;  // use coarse location
             } else {
-                notifyLocation = lastLocation;  // use fine location
+                notifyLocation = location;  // use fine location
             }
             if (notifyLocation != null) {
                 Location lastLoc = r.mLastFixBroadcast;
-                if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
+                if ((lastLoc == null)
+                        || shouldBroadcastSafeLocked(notifyLocation, lastLoc, r, now)) {
                     if (lastLoc == null) {
                         lastLoc = new Location(notifyLocation);
                         r.mLastFixBroadcast = lastLoc;
@@ -3150,7 +3158,8 @@
                         lastLoc.set(notifyLocation);
                     }
                     if (!receiver.callLocationChangedLocked(notifyLocation)) {
-                        Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
+                        Slog.w(TAG, "RemoteException calling onLocationChanged on "
+                                + receiver);
                         receiverDead = true;
                     }
                     r.mRealRequest.decrementNumUpdates();
@@ -3161,12 +3170,16 @@
             // guarded behind this setting now. should be removed completely post-Q
             if (Settings.Global.getInt(mContext.getContentResolver(),
                     LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
+                long newStatusUpdateTime = provider.getStatusUpdateTimeLocked();
+                Bundle extras = new Bundle();
+                int status = provider.getStatusLocked(extras);
+
                 long prevStatusUpdateTime = r.mLastStatusBroadcast;
                 if ((newStatusUpdateTime > prevStatusUpdateTime)
                         && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
 
                     r.mLastStatusBroadcast = newStatusUpdateTime;
-                    if (!receiver.callStatusChangedLocked(provider, status, extras)) {
+                    if (!receiver.callStatusChangedLocked(provider.getName(), status, extras)) {
                         receiverDead = true;
                         Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
                     }
@@ -3205,12 +3218,7 @@
         }
     }
 
-    /**
-     * Updates last location with the given location
-     *
-     * @param location new location to update
-     * @param provider Location provider to update for
-     */
+    @GuardedBy("mLock")
     private void updateLastLocationLocked(Location location, String provider) {
         Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
         Location lastNoGPSLocation;
@@ -3229,75 +3237,6 @@
         lastLocation.set(location);
     }
 
-    private class LocationWorkerHandler extends Handler {
-        public LocationWorkerHandler(Looper looper) {
-            super(looper, null, true);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_LOCATION_CHANGED:
-                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
-                    break;
-            }
-        }
-    }
-
-    private boolean isMockProvider(String provider) {
-        synchronized (mLock) {
-            return mMockProviders.containsKey(provider);
-        }
-    }
-
-    private void handleLocationChanged(Location location, boolean passive) {
-        // create a working copy of the incoming Location so that the service can modify it without
-        // disturbing the caller's copy
-        Location myLocation = new Location(location);
-        String provider = myLocation.getProvider();
-
-        // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
-        // bit if location did not come from a mock provider because passive/fused providers can
-        // forward locations from mock providers, and should not grant them legitimacy in doing so.
-        if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
-            myLocation.setIsFromMockProvider(true);
-        }
-
-        synchronized (mLock) {
-            if (!passive) {
-                // notify passive provider of the new location
-                mPassiveProvider.updateLocation(myLocation);
-            }
-            handleLocationChangedLocked(myLocation, passive);
-        }
-    }
-
-    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
-        @Override
-        public void onPackageDisappeared(String packageName, int reason) {
-            // remove all receivers associated with this package name
-            synchronized (mLock) {
-                ArrayList<Receiver> deadReceivers = null;
-
-                for (Receiver receiver : mReceivers.values()) {
-                    if (receiver.mIdentity.mPackageName.equals(packageName)) {
-                        if (deadReceivers == null) {
-                            deadReceivers = new ArrayList<>();
-                        }
-                        deadReceivers.add(receiver);
-                    }
-                }
-
-                // perform removal outside of mReceivers loop
-                if (deadReceivers != null) {
-                    for (Receiver receiver : deadReceivers) {
-                        removeUpdatesLocked(receiver);
-                    }
-                }
-            }
-        }
-    };
-
     // Geocoder
 
     @Override
@@ -3343,63 +3282,60 @@
             return;
         }
 
-        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
+        if (PASSIVE_PROVIDER.equals(name)) {
             throw new IllegalArgumentException("Cannot mock the passive location provider");
         }
 
-        long identity = Binder.clearCallingIdentity();
         synchronized (mLock) {
-            // remove the real provider if we are replacing GPS or network provider
-            if (LocationManager.GPS_PROVIDER.equals(name)
-                    || LocationManager.NETWORK_PROVIDER.equals(name)
-                    || LocationManager.FUSED_PROVIDER.equals(name)) {
-                LocationProvider p = mProvidersByName.get(name);
-                if (p != null) {
-                    removeProviderLocked(p);
+            long identity = Binder.clearCallingIdentity();
+            try {
+                LocationProvider oldProvider = getLocationProviderLocked(name);
+                if (oldProvider != null) {
+                    if (oldProvider.isMock()) {
+                        throw new IllegalArgumentException(
+                                "Provider \"" + name + "\" already exists");
+                    }
+
+                    removeProviderLocked(oldProvider);
                 }
+
+                MockLocationProvider mockProviderManager = new MockLocationProvider(name);
+                addProviderLocked(mockProviderManager);
+                mockProviderManager.attachLocked(new MockProvider(mockProviderManager, properties));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
             }
-            addTestProviderLocked(name, properties);
         }
-        Binder.restoreCallingIdentity(identity);
-    }
-
-    private void addTestProviderLocked(String name, ProviderProperties properties) {
-        if (mProvidersByName.get(name) != null) {
-            throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
-        }
-
-        LocationProvider provider = new LocationProvider(name);
-        MockProvider mockProvider = new MockProvider(provider, properties);
-
-        addProviderLocked(provider);
-        mMockProviders.put(name, mockProvider);
-        mLastLocation.put(name, null);
-        mLastLocationCoarseInterval.put(name, null);
     }
 
     @Override
-    public void removeTestProvider(String provider, String opPackageName) {
+    public void removeTestProvider(String name, String opPackageName) {
         if (!canCallerAccessMockLocation(opPackageName)) {
             return;
         }
 
         synchronized (mLock) {
-            MockProvider mockProvider = mMockProviders.remove(provider);
-            if (mockProvider == null) {
-                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
-            }
-
             long identity = Binder.clearCallingIdentity();
             try {
-                removeProviderLocked(mProvidersByName.get(provider));
+                LocationProvider testProvider = getLocationProviderLocked(name);
+                if (testProvider == null || !testProvider.isMock()) {
+                    throw new IllegalArgumentException("Provider \"" + name + "\" unknown");
+                }
+
+                removeProviderLocked(testProvider);
 
                 // reinstate real provider if available
-                LocationProvider realProvider = mRealProviders.get(provider);
+                LocationProvider realProvider = null;
+                for (LocationProvider provider : mRealProviders) {
+                    if (name.equals(provider.getName())) {
+                        realProvider = provider;
+                        break;
+                    }
+                }
+
                 if (realProvider != null) {
                     addProviderLocked(realProvider);
                 }
-                mLastLocation.put(provider, null);
-                mLastLocationCoarseInterval.put(provider, null);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -3407,78 +3343,60 @@
     }
 
     @Override
-    public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
-        if (!canCallerAccessMockLocation(opPackageName)) {
-            return;
-        }
-
-        synchronized (mLock) {
-            MockProvider mockProvider = mMockProviders.get(provider);
-            if (mockProvider == null) {
-                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
-            }
-
-            // Ensure that the location is marked as being mock. There's some logic to do this in
-            // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
-            Location mock = new Location(loc);
-            mock.setIsFromMockProvider(true);
-
-            if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
-                // The location has an explicit provider that is different from the mock provider
-                // name. The caller may be trying to fool us via bug 33091107.
-                EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
-                        provider + "!=" + loc.getProvider());
-            }
-
-            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
-            long identity = Binder.clearCallingIdentity();
-            try {
-                mockProvider.setLocation(mock);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    @Override
-    public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
-        if (!canCallerAccessMockLocation(opPackageName)) {
-            return;
-        }
-
-        synchronized (mLock) {
-            MockProvider mockProvider = mMockProviders.get(provider);
-            if (mockProvider == null) {
-                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
-            }
-            long identity = Binder.clearCallingIdentity();
-            try {
-                mockProvider.setEnabled(enabled);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    @Override
-    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
+    public void setTestProviderLocation(String providerName, Location location,
             String opPackageName) {
         if (!canCallerAccessMockLocation(opPackageName)) {
             return;
         }
 
         synchronized (mLock) {
-            MockProvider mockProvider = mMockProviders.get(provider);
-            if (mockProvider == null) {
-                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+            LocationProvider testProvider = getLocationProviderLocked(providerName);
+            if (testProvider == null || !testProvider.isMock()) {
+                throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
             }
-            mockProvider.setStatus(status, extras, updateTime);
+
+            String locationProvider = location.getProvider();
+            if (!TextUtils.isEmpty(locationProvider) && !providerName.equals(locationProvider)) {
+                // The location has an explicit provider that is different from the mock
+                // provider name. The caller may be trying to fool us via b/33091107.
+                EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
+                        providerName + "!=" + location.getProvider());
+            }
+
+            ((MockLocationProvider) testProvider).setLocationLocked(location);
         }
     }
 
-    private void log(String log) {
-        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Slog.d(TAG, log);
+    @Override
+    public void setTestProviderEnabled(String providerName, boolean enabled, String opPackageName) {
+        if (!canCallerAccessMockLocation(opPackageName)) {
+            return;
+        }
+
+        synchronized (mLock) {
+            LocationProvider testProvider = getLocationProviderLocked(providerName);
+            if (testProvider == null || !testProvider.isMock()) {
+                throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
+            }
+
+            ((MockLocationProvider) testProvider).setEnabledLocked(enabled);
+        }
+    }
+
+    @Override
+    public void setTestProviderStatus(String providerName, int status, Bundle extras,
+            long updateTime, String opPackageName) {
+        if (!canCallerAccessMockLocation(opPackageName)) {
+            return;
+        }
+
+        synchronized (mLock) {
+            LocationProvider testProvider = getLocationProviderLocked(providerName);
+            if (testProvider == null || !testProvider.isMock()) {
+                throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
+            }
+
+            ((MockLocationProvider) testProvider).setStatusLocked(status, extras, updateTime);
         }
     }
 
@@ -3494,6 +3412,7 @@
                 return;
             }
             pw.println("Current Location Manager state:");
+            pw.println("  Location Mode: " + isLocationEnabled());
             pw.println("  Location Listeners:");
             for (Receiver receiver : mReceivers.values()) {
                 pw.println("    " + receiver);
@@ -3548,12 +3467,6 @@
 
             pw.append("  ");
             mBlacklist.dump(pw);
-            if (mMockProviders.size() > 0) {
-                pw.println("  Mock Providers:");
-                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
-                    i.getValue().dump(fd, pw, args);
-                }
-            }
 
             if (mLocationControllerExtraPackage != null) {
                 pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
@@ -3574,7 +3487,7 @@
                 return;
             }
             for (LocationProvider provider : mProviders) {
-                provider.dump(fd, pw, args);
+                provider.dumpLocked(fd, pw, args);
             }
             if (mGnssBatchingInProgress) {
                 pw.println("  GNSS batching in progress");
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index cee98c1..4a8706e 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -122,6 +122,10 @@
                 "exception_count"));
         pw.println(header);
         for (LooperStats.ExportedEntry entry : entries) {
+            if (entry.messageName.startsWith(LooperStats.DEBUG_ENTRY_PREFIX)) {
+                // Do not dump debug entries.
+                continue;
+            }
             pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
                     packageMap.mapUid(entry.workSourceUid),
                     entry.threadName,
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index b0ca2df..89ff338 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -17,13 +17,11 @@
 package com.android.server;
 
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
-import static android.Manifest.permission.DUMP;
 import static android.Manifest.permission.NETWORK_SETTINGS;
 import static android.Manifest.permission.NETWORK_STACK;
 import static android.Manifest.permission.SHUTDOWN;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
-import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
@@ -40,24 +38,17 @@
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.TrafficStats.UID_TETHERING;
-import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult;
-import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
-import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
-import static com.android.server.NetworkManagementService.NetdResponseCode.IpFwdStatusResult;
-import static com.android.server.NetworkManagementService.NetdResponseCode.TetherDnsFwdTgtListResult;
-import static com.android.server.NetworkManagementService.NetdResponseCode.TetherInterfaceListResult;
-import static com.android.server.NetworkManagementService.NetdResponseCode.TetherStatusResult;
-import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsListResult;
+
 import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.InetAddresses;
 import android.net.INetd;
-import android.net.TetherStatsParcel;
+import android.net.INetdUnsolicitedEventListener;
 import android.net.INetworkManagementEventObserver;
 import android.net.ITetheringStatsProvider;
 import android.net.InterfaceConfiguration;
@@ -69,18 +60,15 @@
 import android.net.NetworkStats;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
+import android.net.TetherStatsParcel;
 import android.net.UidRange;
-import android.net.UidRangeParcel;
-import android.net.util.NetdService;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.shared.NetdService;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.INetworkActivityListener;
 import android.os.INetworkManagementService;
-import android.os.PersistableBundle;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
@@ -91,12 +79,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
-import android.provider.Settings;
 import android.telephony.DataConnectionRealTimeInfo;
-import android.telephony.PhoneStateListener;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -110,13 +93,11 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.HexDump;
 import com.android.internal.util.Preconditions;
-import com.android.server.NativeDaemonConnector.Command;
-import com.android.server.NativeDaemonConnector.SensitiveArg;
+
 import com.google.android.collect.Maps;
 
 import java.io.BufferedReader;
 import java.io.DataInputStream;
-import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -124,15 +105,11 @@
 import java.io.PrintWriter;
 import java.net.InetAddress;
 import java.net.InterfaceAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
 import java.util.concurrent.CountDownLatch;
 
 /**
@@ -230,6 +207,8 @@
 
     private INetd mNetdService;
 
+    private final NetdUnsolicitedEventListener mNetdUnsolicitedEventListener;
+
     private IBatteryStats mBatteryStats;
 
     private final Thread mThread;
@@ -347,6 +326,8 @@
 
         mDaemonHandler = new Handler(FgThread.get().getLooper());
 
+        mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener();
+
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
 
@@ -365,6 +346,7 @@
         mFgHandler = null;
         mThread = null;
         mServices = null;
+        mNetdUnsolicitedEventListener = null;
     }
 
     static NetworkManagementService create(Context context, String socket, SystemServices services)
@@ -471,7 +453,6 @@
         // our sanity-checking state.
         mActiveAlerts.remove(iface);
         mActiveQuotas.remove(iface);
-
         invokeForAllObservers(o -> o.interfaceRemoved(iface));
     }
 
@@ -577,7 +558,7 @@
                 return;
             }
             // No current code examines the interface parameter in a global alert. Just pass null.
-            notifyLimitReached(LIMIT_GLOBAL_ALERT, null);
+            mDaemonHandler.post(() -> notifyLimitReached(LIMIT_GLOBAL_ALERT, null));
         }
     }
 
@@ -608,6 +589,12 @@
 
     private void connectNativeNetdService() {
         mNetdService = mServices.getNetd();
+        try {
+            mNetdService.registerUnsolicitedEventListener(mNetdUnsolicitedEventListener);
+            if (DBG) Slog.d(TAG, "Register unsolicited event listener");
+        } catch (RemoteException | ServiceSpecificException e) {
+            Slog.e(TAG, "Failed to set Netd unsolicited event listener " + e);
+        }
     }
 
     /**
@@ -734,14 +721,96 @@
     /**
      * Notify our observers of a route change.
      */
-    private void notifyRouteChange(String action, RouteInfo route) {
-        if (action.equals("updated")) {
+    private void notifyRouteChange(boolean updated, RouteInfo route) {
+        if (updated) {
             invokeForAllObservers(o -> o.routeUpdated(route));
         } else {
             invokeForAllObservers(o -> o.routeRemoved(route));
         }
     }
 
+    private class NetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub {
+        @Override
+        public void onInterfaceClassActivityChanged(boolean isActive,
+                int label, long timestamp, int uid) throws RemoteException {
+            final long timestampNanos;
+            if (timestamp <= 0) {
+                timestampNanos = SystemClock.elapsedRealtimeNanos();
+            } else {
+                timestampNanos = timestamp;
+            }
+            mDaemonHandler.post(() -> notifyInterfaceClassActivity(label,
+                    isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+                    : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
+                    timestampNanos, uid, false));
+        }
+
+        @Override
+        public void onQuotaLimitReached(String alertName, String ifName)
+                throws RemoteException {
+            mDaemonHandler.post(() -> notifyLimitReached(alertName, ifName));
+        }
+
+        @Override
+        public void onInterfaceDnsServerInfo(String ifName,
+                long lifetime, String[] servers) throws RemoteException {
+            mDaemonHandler.post(() -> notifyInterfaceDnsServerInfo(ifName, lifetime, servers));
+        }
+
+        @Override
+        public void onInterfaceAddressUpdated(String addr,
+                String ifName, int flags, int scope) throws RemoteException {
+            final LinkAddress address = new LinkAddress(addr, flags, scope);
+            mDaemonHandler.post(() -> notifyAddressUpdated(ifName, address));
+        }
+
+        @Override
+        public void onInterfaceAddressRemoved(String addr,
+                String ifName, int flags, int scope) throws RemoteException {
+            final LinkAddress address = new LinkAddress(addr, flags, scope);
+            mDaemonHandler.post(() -> notifyAddressRemoved(ifName, address));
+        }
+
+        @Override
+        public void onInterfaceAdded(String ifName) throws RemoteException {
+            mDaemonHandler.post(() -> notifyInterfaceAdded(ifName));
+        }
+
+        @Override
+        public void onInterfaceRemoved(String ifName) throws RemoteException {
+            mDaemonHandler.post(() -> notifyInterfaceRemoved(ifName));
+        }
+
+        @Override
+        public void onInterfaceChanged(String ifName, boolean up)
+                throws RemoteException {
+            mDaemonHandler.post(() -> notifyInterfaceStatusChanged(ifName, up));
+        }
+
+        @Override
+        public void onInterfaceLinkStateChanged(String ifName, boolean up)
+                throws RemoteException {
+            mDaemonHandler.post(() -> notifyInterfaceLinkStateChanged(ifName, up));
+        }
+
+        @Override
+        public void onRouteChanged(boolean updated,
+                String route, String gateway, String ifName) throws RemoteException {
+            final RouteInfo processRoute = new RouteInfo(new IpPrefix(route),
+                    ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway),
+                    ifName);
+            mDaemonHandler.post(() -> notifyRouteChange(updated, processRoute));
+        }
+
+        @Override
+        public void onStrictCleartextDetected(int uid, String hex) throws RemoteException {
+            // Don't need to post to mDaemonHandler because the only thing
+            // that notifyCleartextNetwork does is post to a handler
+            ActivityManager.getService().notifyCleartextNetwork(uid,
+                    HexDump.hexStringToByteArray(hex));
+        }
+    }
+
     //
     // Netd Callback handling
     //
@@ -929,7 +998,7 @@
                             InetAddress gateway = null;
                             if (via != null) gateway = InetAddress.parseNumericAddress(via);
                             RouteInfo route = new RouteInfo(new IpPrefix(cooked[3]), gateway, dev);
-                            notifyRouteChange(cooked[2], route);
+                            notifyRouteChange(cooked[2].equals("updated"), route);
                             return true;
                         } catch (IllegalArgumentException e) {}
                     }
@@ -1392,13 +1461,9 @@
             if (ConnectivityManager.isNetworkTypeMobile(type)) {
                 mNetworkActive = false;
             }
-            mDaemonHandler.post(new Runnable() {
-                @Override public void run() {
-                    notifyInterfaceClassActivity(type,
-                            DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
-                            SystemClock.elapsedRealtimeNanos(), -1, false);
-                }
-            });
+            mDaemonHandler.post(() -> notifyInterfaceClassActivity(type,
+                    DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
+                    SystemClock.elapsedRealtimeNanos(), -1, false));
         }
     }
 
@@ -1421,13 +1486,9 @@
                 throw new IllegalStateException(e);
             }
             mActiveIdleTimers.remove(iface);
-            mDaemonHandler.post(new Runnable() {
-                @Override public void run() {
-                    notifyInterfaceClassActivity(params.type,
-                            DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
-                            SystemClock.elapsedRealtimeNanos(), -1, false);
-                }
-            });
+            mDaemonHandler.post(() -> notifyInterfaceClassActivity(params.type,
+                    DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
+                    SystemClock.elapsedRealtimeNanos(), -1, false));
         }
     }
 
@@ -2153,28 +2214,6 @@
     }
 
     @Override
-    public void startClatd(String interfaceName) throws IllegalStateException {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
-        try {
-            mNetdService.clatdStart(interfaceName);
-        } catch (RemoteException | ServiceSpecificException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    @Override
-    public void stopClatd(String interfaceName) throws IllegalStateException {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
-        try {
-            mNetdService.clatdStop(interfaceName);
-        } catch (RemoteException | ServiceSpecificException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    @Override
     public void registerNetworkActivityListener(INetworkActivityListener listener) {
         mNetworkActivityListeners.register(listener);
     }
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 06dc918..8adc416 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -16,13 +16,11 @@
 
 package com.android.server;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Environment;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.Looper;
-import android.os.Message;
-import android.os.Process;
 import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -32,6 +30,8 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 
@@ -48,10 +48,10 @@
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
+import java.util.Set;
 
 /**
  * Monitors the health of packages on the system and notifies interested observers when packages
@@ -62,7 +62,7 @@
     // Duration to count package failures before it resets to 0
     private static final int TRIGGER_DURATION_MS = 60000;
     // Number of package failures within the duration above before we notify observers
-    private static final int TRIGGER_FAILURE_COUNT = 5;
+    static final int TRIGGER_FAILURE_COUNT = 5;
     private static final int DB_VERSION = 1;
     private static final String TAG_PACKAGE_WATCHDOG = "package-watchdog";
     private static final String TAG_PACKAGE = "package";
@@ -70,7 +70,6 @@
     private static final String ATTR_VERSION = "version";
     private static final String ATTR_NAME = "name";
     private static final String ATTR_DURATION = "duration";
-    private static final int MESSAGE_SAVE_FILE = 1;
 
     private static PackageWatchdog sPackageWatchdog;
 
@@ -79,20 +78,14 @@
     private final Context mContext;
     // Handler to run package cleanup runnables
     private final Handler mTimerHandler;
-    private final HandlerThread mIoThread = new HandlerThread("package_watchdog_io",
-            Process.THREAD_PRIORITY_BACKGROUND);
     private final Handler mIoHandler;
-    // Maps observer names to package observers that have been registered since the last boot
+    // Contains (observer-name -> observer-handle) that have ever been registered from
+    // previous boots. Observers with all packages expired are periodically pruned.
+    // It is saved to disk on system shutdown and repouplated on startup so it survives reboots.
     @GuardedBy("mLock")
-    final Map<String, PackageHealthObserver> mRegisteredObservers = new ArrayMap<>();
-    // Maps observer names to internal observers (registered or not) loaded from file
-    @GuardedBy("mLock")
-    final Map<String, ObserverInternal> mAllObservers = new ArrayMap<>();
-    // /data/system/ directory
-    private final File mSystemDir = new File(Environment.getDataDirectory(), "system");
-    // File containing the XML data of monitored packages
-    private final AtomicFile mPolicyFile =
-            new AtomicFile(new File(mSystemDir, "package-watchdog.xml"));
+    private final ArrayMap<String, ObserverInternal> mAllObservers = new ArrayMap<>();
+    // File containing the XML data of monitored packages /data/system/package-watchdog.xml
+    private final AtomicFile mPolicyFile;
     // Runnable to prune monitored packages that have expired
     private final Runnable mPackageCleanup;
     // Last SystemClock#uptimeMillis a package clean up was executed.
@@ -102,21 +95,40 @@
     // 0 if mPackageCleanup not running.
     private long mDurationAtLastReschedule;
 
+    // TODO(zezeozue): Remove redundant context param
     private PackageWatchdog(Context context) {
         mContext = context;
+        mPolicyFile = new AtomicFile(new File(new File(Environment.getDataDirectory(), "system"),
+                        "package-watchdog.xml"));
         mTimerHandler = new Handler(Looper.myLooper());
-        mIoThread.start();
-        mIoHandler = new IoHandler(mIoThread.getLooper());
+        mIoHandler = BackgroundThread.getHandler();
         mPackageCleanup = this::rescheduleCleanup;
         loadFromFile();
     }
 
+    /**
+     * Creates a PackageWatchdog for testing that uses the same {@code looper} for all handlers
+     * and creates package-watchdog.xml in an apps data directory.
+     */
+    @VisibleForTesting
+    PackageWatchdog(Context context, Looper looper) {
+        mContext = context;
+        mPolicyFile = new AtomicFile(new File(context.getFilesDir(), "package-watchdog.xml"));
+        mTimerHandler = new Handler(looper);
+        mIoHandler = mTimerHandler;
+        mPackageCleanup = this::rescheduleCleanup;
+        loadFromFile();
+    }
+
+
     /** Creates or gets singleton instance of PackageWatchdog. */
-    public static synchronized PackageWatchdog getInstance(Context context) {
-        if (sPackageWatchdog == null) {
-            sPackageWatchdog = new PackageWatchdog(context);
+    public static PackageWatchdog getInstance(Context context) {
+        synchronized (PackageWatchdog.class) {
+            if (sPackageWatchdog == null) {
+                sPackageWatchdog = new PackageWatchdog(context);
+            }
+            return sPackageWatchdog;
         }
-        return sPackageWatchdog;
     }
 
     /**
@@ -127,7 +139,10 @@
      */
     public void registerHealthObserver(PackageHealthObserver observer) {
         synchronized (mLock) {
-            mRegisteredObservers.put(observer.getName(), observer);
+            ObserverInternal internalObserver = mAllObservers.get(observer.getName());
+            if (internalObserver != null) {
+                internalObserver.mRegisteredObserver = observer;
+            }
             if (mDurationAtLastReschedule == 0) {
                 // Nothing running, schedule
                 rescheduleCleanup();
@@ -140,21 +155,20 @@
      * {@code observer} of any package failures within the monitoring duration.
      *
      * <p>If {@code observer} is already monitoring a package in {@code packageNames},
-     * the monitoring window of that package will be reset to {@code hours}.
+     * the monitoring window of that package will be reset to {@code durationMs}.
      *
      * @throws IllegalArgumentException if {@code packageNames} is empty
-     * or {@code hours} is less than 1
+     * or {@code durationMs} is less than 1
      */
     public void startObservingHealth(PackageHealthObserver observer, List<String> packageNames,
-            int hours) {
-        if (packageNames.isEmpty() || hours < 1) {
+            long durationMs) {
+        if (packageNames.isEmpty() || durationMs < 1) {
             throw new IllegalArgumentException("Observation not started, no packages specified"
-                    + "or invalid hours");
+                    + "or invalid duration");
         }
-        long durationMs = TimeUnit.HOURS.toMillis(hours);
         List<MonitoredPackage> packages = new ArrayList<>();
-        for (String packageName : packageNames) {
-            packages.add(new MonitoredPackage(packageName, durationMs));
+        for (int i = 0; i < packageNames.size(); i++) {
+            packages.add(new MonitoredPackage(packageNames.get(i), durationMs));
         }
         synchronized (mLock) {
             ObserverInternal oldObserver = mAllObservers.get(observer.getName());
@@ -173,7 +187,7 @@
         // Always reschedule because we may need to expire packages
         // earlier than we are already scheduled for
         rescheduleCleanup();
-        sendIoMessage(MESSAGE_SAVE_FILE);
+        saveToFileAsync();
     }
 
     /**
@@ -184,9 +198,30 @@
     public void unregisterHealthObserver(PackageHealthObserver observer) {
         synchronized (mLock) {
             mAllObservers.remove(observer.getName());
-            mRegisteredObservers.remove(observer.getName());
         }
-        sendIoMessage(MESSAGE_SAVE_FILE);
+        saveToFileAsync();
+    }
+
+    /**
+     * Returns packages observed by {@code observer}
+     *
+     * @return an empty set if {@code observer} has some packages observerd from a previous boot
+     * but has not registered itself in the current boot to receive notifications. Returns null
+     * if there are no active packages monitored from any boot.
+     */
+    @Nullable
+    public Set<String> getPackages(PackageHealthObserver observer) {
+        synchronized (mLock) {
+            for (int i = 0; i < mAllObservers.size(); i++) {
+                if (observer.getName().equals(mAllObservers.keyAt(i))) {
+                    if (observer.equals(mAllObservers.valueAt(i).mRegisteredObserver)) {
+                        return mAllObservers.valueAt(i).mPackages.keySet();
+                    }
+                    return Collections.emptySet();
+                }
+            }
+        }
+        return null;
     }
 
     // TODO(zezeozue:) Accept current versionCodes of failing packages?
@@ -194,28 +229,46 @@
      * Called when a process fails either due to a crash or ANR.
      *
      * <p>All registered observers for the packages contained in the process will be notified in
-     * order of priority unitl an observer signifies that it has taken action and other observers
+     * order of priority until an observer signifies that it has taken action and other observers
      * should not notified.
      *
      * <p>This method could be called frequently if there is a severe problem on the device.
      */
     public void onPackageFailure(String[] packages) {
+        ArrayMap<String, List<PackageHealthObserver>> packagesToReport = new ArrayMap<>();
         synchronized (mLock) {
-            if (mRegisteredObservers.isEmpty()) {
+            if (mAllObservers.isEmpty()) {
                 return;
             }
-            for (String packageName : packages) {
-                for (ObserverInternal observer : mAllObservers.values()) {
-                    if (observer.onPackageFailure(packageName)) {
-                        PackageHealthObserver activeObserver =
-                                mRegisteredObservers.get(observer.mName);
-                        if (activeObserver != null
-                                && activeObserver.onHealthCheckFailed(packageName)) {
-                            // Observer has handled, do not notify other observers
-                            break;
-                        }
+
+            for (int pIndex = 0; pIndex < packages.length; pIndex++) {
+                // Observers interested in receiving packageName failures
+                List<PackageHealthObserver> observersToNotify = new ArrayList<>();
+                for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
+                    PackageHealthObserver registeredObserver =
+                            mAllObservers.valueAt(oIndex).mRegisteredObserver;
+                    if (registeredObserver != null) {
+                        observersToNotify.add(registeredObserver);
                     }
                 }
+                // Save interested observers and notify them outside the lock
+                if (!observersToNotify.isEmpty()) {
+                    packagesToReport.put(packages[pIndex], observersToNotify);
+                }
+            }
+        }
+
+        // Notify observers
+        for (int pIndex = 0; pIndex < packagesToReport.size(); pIndex++) {
+            List<PackageHealthObserver> observers = packagesToReport.valueAt(pIndex);
+            String packageName = packages[pIndex];
+            for (int oIndex = 0; oIndex < observers.size(); oIndex++) {
+                PackageHealthObserver observer = observers.get(oIndex);
+                if (mAllObservers.get(observer.getName()).onPackageFailure(packageName)
+                        && observer.onHealthCheckFailed(packageName)) {
+                    // Observer has handled, do not notify others
+                    break;
+                }
             }
         }
     }
@@ -225,7 +278,7 @@
     /** Writes the package information to file during shutdown. */
     public void writeNow() {
         if (!mAllObservers.isEmpty()) {
-            mIoHandler.removeMessages(MESSAGE_SAVE_FILE);
+            mIoHandler.removeCallbacks(this::saveToFile);
             pruneObservers(SystemClock.uptimeMillis() - mUptimeAtLastRescheduleMs);
             saveToFile();
             Slog.i(TAG, "Last write to update package durations");
@@ -235,7 +288,7 @@
     /** Register instances of this interface to receive notifications on package failure. */
     public interface PackageHealthObserver {
         /**
-         * Called when health check fails for the {@code packages}.
+         * Called when health check fails for the {@code packageName}.
          * @return {@code true} if action was taken and other observers should not be notified of
          * this failure, {@code false} otherwise.
          */
@@ -263,10 +316,12 @@
             // O if mPackageCleanup not running
             long elapsedDurationMs = mUptimeAtLastRescheduleMs == 0
                     ? 0 : uptimeMs - mUptimeAtLastRescheduleMs;
-            // O if mPackageCleanup not running
+            // Less than O if mPackageCleanup unexpectedly didn't run yet even though
+            // and we are past the last duration scheduled to run
             long remainingDurationMs = mDurationAtLastReschedule - elapsedDurationMs;
-
-            if (mUptimeAtLastRescheduleMs == 0 || nextDurationToScheduleMs < remainingDurationMs) {
+            if (mUptimeAtLastRescheduleMs == 0
+                    || remainingDurationMs <= 0
+                    || nextDurationToScheduleMs < remainingDurationMs) {
                 // First schedule or an earlier reschedule
                 pruneObservers(elapsedDurationMs);
                 mTimerHandler.removeCallbacks(mPackageCleanup);
@@ -283,14 +338,17 @@
      */
     private long getEarliestPackageExpiryLocked() {
         long shortestDurationMs = Long.MAX_VALUE;
-        for (ObserverInternal observer : mAllObservers.values()) {
-            for (MonitoredPackage p : observer.mPackages.values()) {
-                if (p.mDurationMs < shortestDurationMs) {
-                    shortestDurationMs = p.mDurationMs;
+        for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
+            ArrayMap<String, MonitoredPackage> packages = mAllObservers.valueAt(oIndex).mPackages;
+            for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
+                long duration = packages.valueAt(pIndex).mDurationMs;
+                if (duration < shortestDurationMs) {
+                    shortestDurationMs = duration;
                 }
             }
         }
         Slog.v(TAG, "Earliest package time is " + shortestDurationMs);
+
         return shortestDurationMs;
     }
 
@@ -313,7 +371,7 @@
                 }
             }
         }
-        sendIoMessage(MESSAGE_SAVE_FILE);
+        saveToFileAsync();
     }
 
     /**
@@ -339,59 +397,53 @@
             }
         } catch (FileNotFoundException e) {
             // Nothing to monitor
-        } catch (IOException e) {
-            Log.wtf(TAG, "Unable to read monitored packages", e);
-        } catch (NumberFormatException e) {
-            Log.wtf(TAG, "Unable to parse monitored package windows", e);
-        } catch (XmlPullParserException e) {
-            Log.wtf(TAG, "Unable to parse monitored packages", e);
+        } catch (IOException | NumberFormatException | XmlPullParserException e) {
+            Log.wtf(TAG, "Unable to read monitored packages, deleting file", e);
+            mPolicyFile.delete();
         } finally {
             IoUtils.closeQuietly(infile);
         }
     }
 
     /**
-     * Persists mAllObservers to file and ignores threshold information.
-     *
-     * <p>Note that this is <b>not</b> thread safe and should only be called on the
-     * single threaded IoHandler.
+     * Persists mAllObservers to file. Threshold information is ignored.
      */
     private boolean saveToFile() {
-        FileOutputStream stream;
-        try {
-            stream = mPolicyFile.startWrite();
-        } catch (IOException e) {
-            Slog.w(TAG, "Cannot update monitored packages", e);
-            return false;
-        }
-
-        try {
-            XmlSerializer out = new FastXmlSerializer();
-            out.setOutput(stream, StandardCharsets.UTF_8.name());
-            out.startDocument(null, true);
-            out.startTag(null, TAG_PACKAGE_WATCHDOG);
-            out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
-            for (ObserverInternal observer : mAllObservers.values()) {
-                observer.write(out);
+        synchronized (mLock) {
+            FileOutputStream stream;
+            try {
+                stream = mPolicyFile.startWrite();
+            } catch (IOException e) {
+                Slog.w(TAG, "Cannot update monitored packages", e);
+                return false;
             }
-            out.endTag(null, TAG_PACKAGE_WATCHDOG);
-            out.endDocument();
-            mPolicyFile.finishWrite(stream);
-            return true;
-        } catch (IOException e) {
-            Slog.w(TAG, "Failed to save monitored packages, restoring backup", e);
-            mPolicyFile.failWrite(stream);
-            return false;
-        } finally {
-            IoUtils.closeQuietly(stream);
+
+            try {
+                XmlSerializer out = new FastXmlSerializer();
+                out.setOutput(stream, StandardCharsets.UTF_8.name());
+                out.startDocument(null, true);
+                out.startTag(null, TAG_PACKAGE_WATCHDOG);
+                out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
+                for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
+                    mAllObservers.valueAt(oIndex).write(out);
+                }
+                out.endTag(null, TAG_PACKAGE_WATCHDOG);
+                out.endDocument();
+                mPolicyFile.finishWrite(stream);
+                return true;
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed to save monitored packages, restoring backup", e);
+                mPolicyFile.failWrite(stream);
+                return false;
+            } finally {
+                IoUtils.closeQuietly(stream);
+            }
         }
     }
 
-    private void sendIoMessage(int what) {
-        if (!mIoHandler.hasMessages(what)) {
-            Message m = Message.obtain(mIoHandler, what);
-            mIoHandler.sendMessage(m);
-        }
+    private void saveToFileAsync() {
+        mIoHandler.removeCallbacks(this::saveToFile);
+        mIoHandler.post(this::saveToFile);
     }
 
     /**
@@ -401,6 +453,8 @@
     static class ObserverInternal {
         public final String mName;
         public final ArrayMap<String, MonitoredPackage> mPackages;
+        @Nullable
+        public PackageHealthObserver mRegisteredObserver;
 
         ObserverInternal(String name, List<MonitoredPackage> packages) {
             mName = name;
@@ -435,7 +489,8 @@
 
         public void updatePackages(List<MonitoredPackage> packages) {
             synchronized (mName) {
-                for (MonitoredPackage p : packages) {
+                for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
+                    MonitoredPackage p = packages.get(pIndex);
                     mPackages.put(p.mName, p);
                 }
             }
@@ -554,19 +609,4 @@
             return mFailures >= TRIGGER_FAILURE_COUNT;
         }
     }
-
-    private class IoHandler extends Handler {
-        IoHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MESSAGE_SAVE_FILE:
-                    saveToFile();
-                    break;
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java b/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
index 1e9a007..190fff1 100644
--- a/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
+++ b/services/core/java/com/android/server/PersistentDataBlockManagerInternal.java
@@ -31,6 +31,19 @@
      */
     byte[] getFrpCredentialHandle();
 
+    /** Stores the data used to enable the Test Harness Mode after factory-resetting. */
+    void setTestHarnessModeData(byte[] data);
+
+    /**
+     * Retrieves the data used to place the device into Test Harness Mode.
+     *
+     * @throws IllegalStateException if the underlying storage is corrupt or inaccessible.
+     */
+    byte[] getTestHarnessModeData();
+
+    /** Clear out the Test Harness Mode data. */
+    void clearTestHarnessModeData();
+
     /** Update the OEM unlock enabled bit, bypassing user restriction checks. */
     void forceOemUnlockEnabled(boolean enabled);
 }
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 21093b9..bd5ad96 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -16,6 +16,8 @@
 
 package com.android.server;
 
+import static com.android.internal.util.Preconditions.checkArgument;
+
 import android.Manifest;
 import android.app.ActivityManager;
 import android.content.Context;
@@ -28,12 +30,10 @@
 import android.os.UserManager;
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.service.persistentdata.PersistentDataBlockManager;
-import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
 
 import libcore.io.IoUtils;
 
@@ -65,6 +65,40 @@
  *
  * Clients can read any number of bytes from the currently written block up to its total size by
  * invoking {@link IPersistentDataBlockService#read}
+ *
+ * The persistent data block is currently laid out as follows:
+ * | ---------BEGINNING OF PARTITION-------------|
+ * | Partition digest (32 bytes)                 |
+ * | --------------------------------------------|
+ * | PARTITION_TYPE_MARKER (4 bytes)             |
+ * | --------------------------------------------|
+ * | FRP data block length (4 bytes)             |
+ * | --------------------------------------------|
+ * | FRP data (variable length)                  |
+ * | --------------------------------------------|
+ * | ...                                         |
+ * | --------------------------------------------|
+ * | Test mode data block (10000 bytes)          |
+ * | --------------------------------------------|
+ * |     | Test mode data length (4 bytes)       |
+ * | --------------------------------------------|
+ * |     | Test mode data (variable length)      |
+ * |     | ...                                   |
+ * | --------------------------------------------|
+ * | FRP credential handle block (1000 bytes)    |
+ * | --------------------------------------------|
+ * |     | FRP credential handle length (4 bytes)|
+ * | --------------------------------------------|
+ * |     | FRP credential handle (variable len)  |
+ * |     | ...                                   |
+ * | --------------------------------------------|
+ * | OEM Unlock bit (1 byte)                     |
+ * | ---------END OF PARTITION-------------------|
+ *
+ * TODO: now that the persistent partition contains several blocks, next time someone wants a new
+ * block, we should look at adding more generic block definitions and get rid of the various raw
+ * XXX_RESERVED_SIZE and XXX_DATA_SIZE constants. That will ensure the code is easier to maintain
+ * and less likely to introduce out-of-bounds read/write.
  */
 public class PersistentDataBlockService extends SystemService {
     private static final String TAG = PersistentDataBlockService.class.getSimpleName();
@@ -73,10 +107,16 @@
     private static final int HEADER_SIZE = 8;
     // Magic number to mark block device as adhering to the format consumed by this service
     private static final int PARTITION_TYPE_MARKER = 0x19901873;
-    /** Size of the block reserved for FPR credential, including 4 bytes for the size header. */
+    /** Size of the block reserved for FRP credential, including 4 bytes for the size header. */
     private static final int FRP_CREDENTIAL_RESERVED_SIZE = 1000;
     /** Maximum size of the FRP credential handle that can be stored. */
     private static final int MAX_FRP_CREDENTIAL_HANDLE_SIZE = FRP_CREDENTIAL_RESERVED_SIZE - 4;
+    /**
+     * Size of the block reserved for Test Harness Mode data, including 4 bytes for the size header.
+     */
+    private static final int TEST_MODE_RESERVED_SIZE = 10000;
+    /** Maximum size of the Test Harness Mode data that can be stored. */
+    private static final int MAX_TEST_MODE_DATA_SIZE = TEST_MODE_RESERVED_SIZE - 4;
     // Limit to 100k as blocks larger than this might cause strain on Binder.
     private static final int MAX_DATA_BLOCK_SIZE = 1024 * 100;
 
@@ -221,6 +261,14 @@
         return mBlockDeviceSize;
     }
 
+    private long getFrpCredentialDataOffset() {
+        return getBlockDeviceSize() - 1 - FRP_CREDENTIAL_RESERVED_SIZE;
+    }
+
+    private long getTestHarnessModeDataOffset() {
+        return getFrpCredentialDataOffset() - TEST_MODE_RESERVED_SIZE;
+    }
+
     private boolean enforceChecksumValidity() {
         byte[] storedDigest = new byte[DIGEST_SIZE_BYTES];
 
@@ -383,7 +431,7 @@
 
     private long doGetMaximumDataBlockSize() {
         long actualSize = getBlockDeviceSize() - HEADER_SIZE - DIGEST_SIZE_BYTES
-                - FRP_CREDENTIAL_RESERVED_SIZE - 1;
+                - TEST_MODE_RESERVED_SIZE - FRP_CREDENTIAL_RESERVED_SIZE - 1;
         return actualSize <= MAX_DATA_BLOCK_SIZE ? actualSize : MAX_DATA_BLOCK_SIZE;
     }
 
@@ -391,6 +439,13 @@
     private native int nativeWipe(String path);
 
     private final IBinder mService = new IPersistentDataBlockService.Stub() {
+
+        /**
+         * Write the data to the persistent data block.
+         *
+         * @return a positive integer of the number of bytes that were written if successful,
+         * otherwise a negative integer indicating there was a problem
+         */
         @Override
         public int write(byte[] data) throws RemoteException {
             enforceUid(Binder.getCallingUid());
@@ -597,12 +652,51 @@
 
         @Override
         public void setFrpCredentialHandle(byte[] handle) {
-            Preconditions.checkArgument(handle == null || handle.length > 0,
-                    "handle must be null or non-empty");
-            Preconditions.checkArgument(handle == null
-                            || handle.length <= MAX_FRP_CREDENTIAL_HANDLE_SIZE,
-                    "handle must not be longer than " + MAX_FRP_CREDENTIAL_HANDLE_SIZE);
+            writeInternal(handle, getFrpCredentialDataOffset(), MAX_FRP_CREDENTIAL_HANDLE_SIZE);
+        }
 
+        @Override
+        public byte[] getFrpCredentialHandle() {
+            return readInternal(getFrpCredentialDataOffset(), MAX_FRP_CREDENTIAL_HANDLE_SIZE);
+        }
+
+        @Override
+        public void setTestHarnessModeData(byte[] data) {
+            writeInternal(data, getTestHarnessModeDataOffset(), MAX_TEST_MODE_DATA_SIZE);
+        }
+
+        @Override
+        public byte[] getTestHarnessModeData() {
+            byte[] data = readInternal(getTestHarnessModeDataOffset(), MAX_TEST_MODE_DATA_SIZE);
+            if (data == null) {
+                return new byte[0];
+            }
+            return data;
+        }
+
+        @Override
+        public void clearTestHarnessModeData() {
+            int size = Math.min(MAX_TEST_MODE_DATA_SIZE, getTestHarnessModeData().length) + 4;
+            writeDataBuffer(getTestHarnessModeDataOffset(), ByteBuffer.allocate(size));
+        }
+
+        private void writeInternal(byte[] data, long offset, int dataLength) {
+            checkArgument(data == null || data.length > 0, "data must be null or non-empty");
+            checkArgument(
+                    data == null || data.length <= dataLength,
+                    "data must not be longer than " + dataLength);
+
+            ByteBuffer dataBuffer = ByteBuffer.allocate(dataLength + 4);
+            dataBuffer.putInt(data == null ? 0 : data.length);
+            if (data != null) {
+                dataBuffer.put(data);
+            }
+            dataBuffer.flip();
+
+            writeDataBuffer(offset, dataBuffer);
+        }
+
+        private void writeDataBuffer(long offset, ByteBuffer dataBuffer) {
             FileOutputStream outputStream;
             try {
                 outputStream = new FileOutputStream(new File(mDataBlockFile));
@@ -610,25 +704,15 @@
                 Slog.e(TAG, "partition not available", e);
                 return;
             }
-
-            ByteBuffer data = ByteBuffer.allocate(FRP_CREDENTIAL_RESERVED_SIZE);
-            data.putInt(handle == null ? 0 : handle.length);
-            if (handle != null) {
-                data.put(handle);
-            }
-            data.flip();
-
             synchronized (mLock) {
                 if (!mIsWritable) {
                     IoUtils.closeQuietly(outputStream);
                     return;
                 }
-
                 try {
                     FileChannel channel = outputStream.getChannel();
-
-                    channel.position(getBlockDeviceSize() - 1 - FRP_CREDENTIAL_RESERVED_SIZE);
-                    channel.write(data);
+                    channel.position(offset);
+                    channel.write(dataBuffer);
                     outputStream.flush();
                 } catch (IOException e) {
                     Slog.e(TAG, "unable to access persistent partition", e);
@@ -641,8 +725,7 @@
             }
         }
 
-        @Override
-        public byte[] getFrpCredentialHandle() {
+        private byte[] readInternal(long offset, int maxLength) {
             if (!enforceChecksumValidity()) {
                 throw new IllegalStateException("invalid checksum");
             }
@@ -652,14 +735,14 @@
                 inputStream = new DataInputStream(
                         new FileInputStream(new File(mDataBlockFile)));
             } catch (FileNotFoundException e) {
-                throw new IllegalStateException("frp partition not available");
+                throw new IllegalStateException("persistent partition not available");
             }
 
             try {
                 synchronized (mLock) {
-                    inputStream.skip(getBlockDeviceSize() - 1 - FRP_CREDENTIAL_RESERVED_SIZE);
+                    inputStream.skip(offset);
                     int length = inputStream.readInt();
-                    if (length <= 0 || length > MAX_FRP_CREDENTIAL_HANDLE_SIZE) {
+                    if (length <= 0 || length > maxLength) {
                         return null;
                     }
                     byte[] bytes = new byte[length];
@@ -667,7 +750,7 @@
                     return bytes;
                 }
             } catch (IOException e) {
-                throw new IllegalStateException("frp handle not readable", e);
+                throw new IllegalStateException("persistent partition not readable", e);
             } finally {
                 IoUtils.closeQuietly(inputStream);
             }
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index a9f190c..62da3f8 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -34,9 +34,9 @@
 import android.util.MathUtils;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.StatsLog;
 
 import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.PackageManagerService;
 
 import java.io.File;
 
@@ -179,6 +179,7 @@
     }
 
     private static void executeRescueLevelInternal(Context context, int level) throws Exception {
+        StatsLog.write(StatsLog.RESCUE_PARTY_RESET_REPORTED, level);
         switch (level) {
             case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
                 resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 2a80644..9d810cd 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -780,6 +780,13 @@
             });
         refreshZramSettings();
 
+        // Schedule zram writeback unless zram is disabled by persist.sys.zram_enabled
+        String zramPropValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY);
+        if (!zramPropValue.equals("0")
+                && mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.config_zramWriteback)) {
+            ZramWriteback.scheduleZramWriteback(mContext);
+        }
         // Toggle isolated-enable system property in response to settings
         mContext.getContentResolver().registerContentObserver(
             Settings.Global.getUriFor(Settings.Global.ISOLATED_STORAGE_REMOTE),
@@ -813,6 +820,12 @@
             // changing the property value. There's no race: we're the
             // sole writer.
             SystemProperties.set(ZRAM_ENABLED_PROPERTY, desiredPropertyValue);
+            // Schedule writeback only if zram is being enabled.
+            if (desiredPropertyValue.equals("1")
+                    && mContext.getResources().getBoolean(
+                        com.android.internal.R.bool.config_zramWriteback)) {
+                ZramWriteback.scheduleZramWriteback(mContext);
+            }
         }
     }
 
@@ -1693,8 +1706,8 @@
             int uid, String packageName, int[] ops) {
         long maxTime = 0;
         final List<AppOpsManager.PackageOps> pkgs = manager.getOpsForPackage(uid, packageName, ops);
-        for (AppOpsManager.PackageOps pkg : CollectionUtils.defeatNullable(pkgs)) {
-            for (AppOpsManager.OpEntry op : CollectionUtils.defeatNullable(pkg.getOps())) {
+        for (AppOpsManager.PackageOps pkg : CollectionUtils.emptyIfNull(pkgs)) {
+            for (AppOpsManager.OpEntry op : CollectionUtils.emptyIfNull(pkg.getOps())) {
                 maxTime = Math.max(maxTime, op.getLastAccessTime());
             }
         }
@@ -3275,7 +3288,8 @@
         }
 
         final int mountMode = mAmInternal.getStorageMountMode(pid, uid);
-        if (mountMode == Zygote.MOUNT_EXTERNAL_FULL) {
+        if (mountMode == Zygote.MOUNT_EXTERNAL_FULL
+                || mountMode == Zygote.MOUNT_EXTERNAL_LEGACY) {
             return path;
         }
 
@@ -3650,12 +3664,13 @@
                 return Zygote.MOUNT_EXTERNAL_FULL;
             } else if (mIAppOpsService.checkOperation(OP_LEGACY_STORAGE, uid,
                     packageName) == MODE_ALLOWED) {
-                // TODO: define a specific "legacy" mount mode
-                return Zygote.MOUNT_EXTERNAL_FULL;
+                return Zygote.MOUNT_EXTERNAL_LEGACY;
             } else if (mIPackageManager.checkUidPermission(INSTALL_PACKAGES, uid)
                     == PERMISSION_GRANTED || mIAppOpsService.checkOperation(
                             OP_REQUEST_INSTALL_PACKAGES, uid, packageName) == MODE_ALLOWED) {
                 return Zygote.MOUNT_EXTERNAL_INSTALLER;
+            } else if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
+                return Zygote.MOUNT_EXTERNAL_NONE;
             } else {
                 return Zygote.MOUNT_EXTERNAL_WRITE;
             }
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
new file mode 100644
index 0000000..1870f8d
--- /dev/null
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -0,0 +1,16 @@
+{
+    "presubmit": [
+        {
+            "name": "FrameworksMockingServicesTests",
+            "file_patterns": ["AlarmManagerService\\.java"],
+            "options": [
+                {
+                  "include-annotation": "android.platform.test.annotations.Presubmit"
+                },
+                {
+                  "exclude-annotation": "androidx.test.filters.FlakyTest"
+                }
+            ]
+        }
+    ]
+}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index d07cf78..e543617 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -32,8 +32,11 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.telephony.CallAttributes;
+import android.telephony.CallQuality;
 import android.telephony.CellInfo;
 import android.telephony.CellLocation;
+import android.telephony.DataFailCause;
 import android.telephony.DisconnectCause;
 import android.telephony.LocationAccessPolicy;
 import android.telephony.PhoneCapability;
@@ -47,6 +50,7 @@
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
 import android.telephony.emergency.EmergencyNumber;
 import android.util.LocalLog;
 import android.util.StatsLog;
@@ -171,6 +175,8 @@
 
     private ServiceState[] mServiceState;
 
+    private int[] mNetworkType;
+
     private int[] mVoiceActivationState;
 
     private int[] mDataActivationState;
@@ -200,6 +206,10 @@
 
     private Map<Integer, List<EmergencyNumber>> mEmergencyNumberList;
 
+    private CallQuality mCallQuality;
+
+    private CallAttributes mCallAttributes;
+
     private int[] mSrvccState;
 
     private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -356,6 +366,7 @@
         mDataConnectionNetworkType = new int[numPhones];
         mCallIncomingNumber = new String[numPhones];
         mServiceState = new ServiceState[numPhones];
+        mNetworkType = new int[numPhones];
         mVoiceActivationState = new int[numPhones];
         mDataActivationState = new int[numPhones];
         mUserMobileDataState = new boolean[numPhones];
@@ -375,6 +386,7 @@
             mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
             mCallIncomingNumber[i] =  "";
             mServiceState[i] =  new ServiceState();
+            mNetworkType[i] = mServiceState[i].getVoiceNetworkType();
             mSignalStrength[i] =  new SignalStrength();
             mUserMobileDataState[i] = false;
             mMessageWaiting[i] =  false;
@@ -805,6 +817,13 @@
                             remove(r.binder);
                         }
                     }
+                    if ((events & PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) != 0) {
+                        try {
+                            r.callback.onCallAttributesChanged(mCallAttributes);
+                        } catch (RemoteException ex) {
+                            remove(r.binder);
+                        }
+                    }
                 }
             }
         } else {
@@ -955,6 +974,21 @@
             if (validatePhoneId(phoneId)) {
                 mServiceState[phoneId] = state;
 
+                boolean notifyCallAttributes = true;
+                if (mNetworkType[phoneId] != mServiceState[phoneId].getVoiceNetworkType()) {
+                    mNetworkType[phoneId] = state.getVoiceNetworkType();
+                    mCallAttributes = new CallAttributes(mPreciseCallState, mNetworkType[phoneId],
+                            mCallQuality);
+                } else {
+                    // No change to network type, so no need to notify call attributes
+                    notifyCallAttributes = false;
+                }
+
+                if (mCallQuality == null) {
+                    // No call quality reported yet, so no need to notify call attributes
+                    notifyCallAttributes = false;
+                }
+
                 for (Record r : mRecords) {
                     if (VDBG) {
                         log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId
@@ -973,6 +1007,14 @@
                             mRemoveList.add(r.binder);
                         }
                     }
+                    if (notifyCallAttributes && r.matchPhoneStateListenerEvent(
+                                    PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED)) {
+                        try {
+                            r.callback.onCallAttributesChanged(mCallAttributes);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
+                    }
                 }
             } else {
                 log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId);
@@ -1313,16 +1355,17 @@
         }
     }
 
-    public void notifyDataConnection(int state, boolean isDataAllowed,
-            String reason, String apn, String apnType, LinkProperties linkProperties,
-            NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
+    public void notifyDataConnection(int state, boolean isDataAllowed, String apn, String apnType,
+                                     LinkProperties linkProperties,
+                                     NetworkCapabilities networkCapabilities, int networkType,
+                                     boolean roaming) {
         notifyDataConnectionForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, state,
-            isDataAllowed,reason, apn, apnType, linkProperties,
-            networkCapabilities, networkType, roaming);
+                isDataAllowed, apn, apnType, linkProperties,
+                networkCapabilities, networkType, roaming);
     }
 
-    public void notifyDataConnectionForSubscriber(int subId, int state,
-            boolean isDataAllowed, String reason, String apn, String apnType,
+    public void notifyDataConnectionForSubscriber(int subId, int state, boolean isDataAllowed,
+                                                  String apn, String apnType,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int networkType, boolean roaming) {
         if (!checkNotifyPermission("notifyDataConnection()" )) {
@@ -1331,7 +1374,6 @@
         if (VDBG) {
             log("notifyDataConnectionForSubscriber: subId=" + subId
                 + " state=" + state + " isDataAllowed=" + isDataAllowed
-                + " reason='" + reason
                 + "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType
                 + " mRecords.size()=" + mRecords.size());
         }
@@ -1366,7 +1408,8 @@
                     mDataConnectionNetworkType[phoneId] = networkType;
                 }
                 mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType,
-                        apnType, apn, reason, linkProperties, "");
+                        ApnSetting.getApnTypesBitmaskFromString(apnType), apn,
+                        linkProperties, DataFailCause.NONE);
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
                             PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) {
@@ -1381,30 +1424,30 @@
             }
             handleRemoveListLocked();
         }
-        broadcastDataConnectionStateChanged(state, isDataAllowed, reason, apn,
-                apnType, linkProperties, networkCapabilities, roaming, subId);
-        broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
-                linkProperties, "");
+        broadcastDataConnectionStateChanged(state, isDataAllowed, apn, apnType, linkProperties,
+                networkCapabilities, roaming, subId);
+        broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn,
+                linkProperties, DataFailCause.NONE);
     }
 
-    public void notifyDataConnectionFailed(String reason, String apnType) {
+    public void notifyDataConnectionFailed(String apnType) {
          notifyDataConnectionFailedForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
-                 reason, apnType);
+                 apnType);
     }
 
-    public void notifyDataConnectionFailedForSubscriber(int subId,
-            String reason, String apnType) {
+    public void notifyDataConnectionFailedForSubscriber(int subId, String apnType) {
         if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
             return;
         }
         if (VDBG) {
             log("notifyDataConnectionFailedForSubscriber: subId=" + subId
-                + " reason=" + reason + " apnType=" + apnType);
+                    + " apnType=" + apnType);
         }
         synchronized (mRecords) {
             mPreciseDataConnectionState = new PreciseDataConnectionState(
                     TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                    apnType, "", reason, null, "");
+                    ApnSetting.getApnTypesBitmaskFromString(apnType), "", null,
+                    DataFailCause.NONE);
             for (Record r : mRecords) {
                 if (r.matchPhoneStateListenerEvent(
                         PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) {
@@ -1417,9 +1460,10 @@
             }
             handleRemoveListLocked();
         }
-        broadcastDataConnectionFailed(reason, apnType, subId);
+        broadcastDataConnectionFailed(apnType, subId);
         broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
-                TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", reason, null, "");
+                TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", null,
+                DataFailCause.NONE);
     }
 
     public void notifyCellLocation(Bundle cellLocation) {
@@ -1480,7 +1524,7 @@
     }
 
     public void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
-            int backgroundCallState) {
+            int backgroundCallState, int phoneId) {
         if (!checkNotifyPermission("notifyPreciseCallState()")) {
             return;
         }
@@ -1492,6 +1536,15 @@
                     backgroundCallState,
                     DisconnectCause.NOT_VALID,
                     PreciseDisconnectCause.NOT_VALID);
+            boolean notifyCallAttributes = true;
+            if (mCallQuality == null) {
+                log("notifyPreciseCallState: mCallQuality is null, skipping call attributes");
+                notifyCallAttributes = false;
+            } else {
+                mCallAttributes = new CallAttributes(mPreciseCallState, mNetworkType[phoneId],
+                        mCallQuality);
+            }
+
             for (Record r : mRecords) {
                 if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_PRECISE_CALL_STATE)) {
                     try {
@@ -1500,6 +1553,14 @@
                         mRemoveList.add(r.binder);
                     }
                 }
+                if (notifyCallAttributes && r.matchPhoneStateListenerEvent(
+                        PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED)) {
+                    try {
+                        r.callback.onCallAttributesChanged(mCallAttributes);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
             }
             handleRemoveListLocked();
         }
@@ -1529,15 +1590,15 @@
         }
     }
 
-    public void notifyPreciseDataConnectionFailed(String reason, String apnType,
-            String apn, String failCause) {
+    public void notifyPreciseDataConnectionFailed(String apnType,
+            String apn, @DataFailCause.FailCause int failCause) {
         if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) {
             return;
         }
         synchronized (mRecords) {
             mPreciseDataConnectionState = new PreciseDataConnectionState(
                     TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                    apnType, apn, reason, null, failCause);
+                    ApnSetting.getApnTypesBitmaskFromString(apnType), apn, null, failCause);
             for (Record r : mRecords) {
                 if (r.matchPhoneStateListenerEvent(
                         PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)) {
@@ -1551,7 +1612,7 @@
             handleRemoveListLocked();
         }
         broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
-                TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause);
+                TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, null, failCause);
     }
 
     @Override
@@ -1717,6 +1778,36 @@
         }
     }
 
+    @Override
+    public void notifyCallQualityChanged(CallQuality callQuality, int phoneId) {
+        if (!checkNotifyPermission("notifyCallQualityChanged()")) {
+            return;
+        }
+
+        // merge CallQuality with PreciseCallState and network type
+        mCallQuality = callQuality;
+        mCallAttributes = new CallAttributes(mPreciseCallState,
+                mNetworkType[phoneId],
+                callQuality);
+
+        synchronized (mRecords) {
+            TelephonyManager tm = (TelephonyManager) mContext.getSystemService(
+                    Context.TELEPHONY_SERVICE);
+
+            for (Record r : mRecords) {
+                if (r.matchPhoneStateListenerEvent(
+                        PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED)) {
+                    try {
+                        r.callback.onCallAttributesChanged(mCallAttributes);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -1734,6 +1825,7 @@
                 pw.println("mCallState=" + mCallState[i]);
                 pw.println("mCallIncomingNumber=" + mCallIncomingNumber[i]);
                 pw.println("mServiceState=" + mServiceState[i]);
+                pw.println("mNetworkType=" + mNetworkType[i]);
                 pw.println("mVoiceActivationState= " + mVoiceActivationState[i]);
                 pw.println("mDataActivationState= " + mDataActivationState[i]);
                 pw.println("mUserMobileDataState= " + mUserMobileDataState[i]);
@@ -1759,6 +1851,8 @@
             pw.println("mPreferredDataSubId=" + mPreferredDataSubId);
             pw.println("mRadioPowerState=" + mRadioPowerState);
             pw.println("mEmergencyNumberList=" + mEmergencyNumberList);
+            pw.println("mCallQuality=" + mCallQuality);
+            pw.println("mCallAttributes=" + mCallAttributes);
 
             pw.decreaseIndent();
 
@@ -1881,10 +1975,10 @@
                         android.Manifest.permission.READ_CALL_LOG});
     }
 
-    private void broadcastDataConnectionStateChanged(int state,
-            boolean isDataAllowed,
-            String reason, String apn, String apnType, LinkProperties linkProperties,
-            NetworkCapabilities networkCapabilities, boolean roaming, int subId) {
+    private void broadcastDataConnectionStateChanged(int state, boolean isDataAllowed, String apn,
+                                                     String apnType, LinkProperties linkProperties,
+                                                     NetworkCapabilities networkCapabilities,
+                                                     boolean roaming, int subId) {
         // Note: not reporting to the battery stats service here, because the
         // status bar takes care of that after taking into account all of the
         // required info.
@@ -1894,9 +1988,6 @@
         if (!isDataAllowed) {
             intent.putExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY, true);
         }
-        if (reason != null) {
-            intent.putExtra(PhoneConstants.STATE_CHANGE_REASON_KEY, reason);
-        }
         if (linkProperties != null) {
             intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
             String iface = linkProperties.getInterfaceName();
@@ -1915,17 +2006,15 @@
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
-    private void broadcastDataConnectionFailed(String reason, String apnType,
-            int subId) {
+    private void broadcastDataConnectionFailed(String apnType, int subId) {
         Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
-        intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason);
         intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
     private void broadcastPreciseCallStateChanged(int ringingCallState, int foregroundCallState,
-            int backgroundCallState) {
+                                                  int backgroundCallState) {
         Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED);
         intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState);
         intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState);
@@ -1935,18 +2024,17 @@
     }
 
     private void broadcastPreciseDataConnectionStateChanged(int state, int networkType,
-            String apnType, String apn, String reason, LinkProperties linkProperties,
-            String failCause) {
+            String apnType, String apn, LinkProperties linkProperties,
+            @DataFailCause.FailCause int failCause) {
         Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
         intent.putExtra(PhoneConstants.STATE_KEY, state);
         intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType);
-        if (reason != null) intent.putExtra(PhoneConstants.STATE_CHANGE_REASON_KEY, reason);
         if (apnType != null) intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
         if (apn != null) intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
         if (linkProperties != null) {
-            intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY,linkProperties);
+            intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
         }
-        if (failCause != null) intent.putExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY, failCause);
+        intent.putExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY, failCause);
 
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
                 android.Manifest.permission.READ_PRECISE_PHONE_STATE);
@@ -2022,6 +2110,21 @@
                     android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
         }
 
+        if ((events & PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
+        }
+
+        if ((events & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
+        }
+
+        if ((events & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
+        }
+
         return true;
     }
 
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 9f353a8..ea6d435 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -141,6 +141,7 @@
     private boolean mLowPowerMode;
     private int mHapticFeedbackIntensity;
     private int mNotificationIntensity;
+    private int mRingIntensity;
 
     native static boolean vibratorExists();
     native static void vibratorInit();
@@ -149,6 +150,8 @@
     native static boolean vibratorSupportsAmplitudeControl();
     native static void vibratorSetAmplitude(int amplitude);
     native static long vibratorPerformEffect(long effect, long strength);
+    static native boolean vibratorSupportsExternalControl();
+    static native void vibratorSetExternalControl(boolean enabled);
 
     private final IUidObserver mUidObserver = new IUidObserver.Stub() {
         @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
@@ -426,6 +429,10 @@
                     Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
                     true, mSettingObserver, UserHandle.USER_ALL);
 
+            mContext.getContentResolver().registerContentObserver(
+                    Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
+                    true, mSettingObserver, UserHandle.USER_ALL);
+
             mContext.registerReceiver(new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
@@ -532,12 +539,6 @@
                 return;
             }
             verifyIncomingUid(uid);
-            if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
-                    > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
-                Slog.e(TAG, "Ignoring incoming vibration as process with uid = "
-                        + uid + " is background");
-                return;
-            }
             if (!verifyVibrationEffect(effect)) {
                 return;
             }
@@ -575,6 +576,13 @@
                 }
 
                 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg, reason);
+                if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
+                        > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+                        && vib.isHapticFeedback()) {
+                    Slog.e(TAG, "Ignoring incoming vibration as process with uid = "
+                            + uid + " is background");
+                    return;
+                }
                 linkVibration(vib);
                 long ident = Binder.clearCallingIdentity();
                 try {
@@ -745,7 +753,9 @@
     }
 
     private int getCurrentIntensityLocked(Vibration vib) {
-        if (vib.isNotification() || vib.isRingtone()){
+        if (vib.isRingtone()) {
+            return mRingIntensity;
+        } else if (vib.isNotification()) {
             return mNotificationIntensity;
         } else if (vib.isHapticFeedback()) {
             return mHapticFeedbackIntensity;
@@ -767,7 +777,9 @@
         }
 
         final int defaultIntensity;
-        if (vib.isNotification() || vib.isRingtone()) {
+        if (vib.isRingtone()) {
+            defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
+        } else if (vib.isNotification()) {
             defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
         } else if (vib.isHapticFeedback()) {
             defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
@@ -930,6 +942,9 @@
         mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
                 Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
                 mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
+        mRingIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
+                Settings.System.RING_VIBRATION_INTENSITY,
+                mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
     }
 
     @Override
@@ -1278,6 +1293,7 @@
             pw.println("  mLowPowerMode=" + mLowPowerMode);
             pw.println("  mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
             pw.println("  mNotificationIntensity=" + mNotificationIntensity);
+            pw.println("  mRingIntensity=" + mRingIntensity);
             pw.println("");
             pw.println("  Previous vibrations:");
             for (VibrationInfo info : mPreviousVibrations) {
diff --git a/services/core/java/com/android/server/ZramWriteback.java b/services/core/java/com/android/server/ZramWriteback.java
new file mode 100644
index 0000000..3a4aff2
--- /dev/null
+++ b/services/core/java/com/android/server/ZramWriteback.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.FileUtils;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Schedules jobs for triggering zram writeback.
+ */
+public final class ZramWriteback extends JobService {
+    private static final String TAG = "ZramWriteback";
+    private static final boolean DEBUG = false;
+
+    private static final ComponentName sZramWriteback =
+            new ComponentName("android", ZramWriteback.class.getName());
+
+    private static final int MARK_IDLE_JOB_ID = 811;
+    private static final int WRITEBACK_IDLE_JOB_ID = 812;
+
+    private static final int MAX_ZRAM_DEVICES = 256;
+    private static int sZramDeviceId = 0;
+
+    private static final String IDLE_SYS = "/sys/block/zram%d/idle";
+    private static final String IDLE_SYS_ALL_PAGES = "all";
+
+    private static final String WB_SYS = "/sys/block/zram%d/writeback";
+    private static final String WB_SYS_IDLE_PAGES = "idle";
+
+    private static final String WB_STATS_SYS = "/sys/block/zram%d/bd_stat";
+    private static final int WB_STATS_MAX_FILE_SIZE = 128;
+
+    private static final String BDEV_SYS = "/sys/block/zram%d/backing_dev";
+
+    private static final String MARK_IDLE_DELAY_PROP = "ro.zram.mark_idle_delay_mins";
+    private static final String FIRST_WB_DELAY_PROP = "ro.zram.first_wb_delay_mins";
+    private static final String PERIODIC_WB_DELAY_PROP = "ro.zram.periodic_wb_delay_hours";
+
+    private void markPagesAsIdle() {
+        String idlePath = String.format(IDLE_SYS, sZramDeviceId);
+        try {
+            FileUtils.stringToFile(new File(idlePath), IDLE_SYS_ALL_PAGES);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to write to " + idlePath);
+        }
+    }
+
+    private void flushIdlePages() {
+        if (DEBUG) Slog.d(TAG, "Start writing back idle pages to disk");
+        String wbPath = String.format(WB_SYS, sZramDeviceId);
+        try {
+            FileUtils.stringToFile(new File(wbPath), WB_SYS_IDLE_PAGES);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to write to " + wbPath);
+        }
+        if (DEBUG) Slog.d(TAG, "Finished writeback back idle pages");
+    }
+
+    private int getWrittenPageCount() {
+        String wbStatsPath = String.format(WB_STATS_SYS, sZramDeviceId);
+        try {
+            String wbStats = FileUtils
+                    .readTextFile(new File(wbStatsPath), WB_STATS_MAX_FILE_SIZE, "");
+            return Integer.parseInt(wbStats.trim().split("\\s+")[2], 10);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to read writeback stats from " + wbStatsPath);
+        }
+
+        return -1;
+    }
+
+    private void markAndFlushPages() {
+        int pageCount = getWrittenPageCount();
+
+        flushIdlePages();
+        markPagesAsIdle();
+
+        if (pageCount != -1) {
+            Slog.i(TAG, "Total pages written to disk is " + (getWrittenPageCount() - pageCount));
+        }
+    }
+
+    private static boolean isWritebackEnabled() {
+        try {
+            String backingDev = FileUtils
+                    .readTextFile(new File(String.format(BDEV_SYS, sZramDeviceId)), 128, "");
+            if (!"none".equals(backingDev.trim())) {
+                return true;
+            } else {
+                Slog.w(TAG, "Writeback device is not set");
+            }
+        } catch (IOException e) {
+            Slog.w(TAG, "Writeback is not enabled on zram");
+        }
+        return false;
+    }
+
+    private static void schedNextWriteback(Context context) {
+        int nextWbDelay = SystemProperties.getInt(PERIODIC_WB_DELAY_PROP, 24);
+        JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+
+        js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback)
+                        .setMinimumLatency(TimeUnit.HOURS.toMillis(nextWbDelay))
+                        .setRequiresDeviceIdle(true)
+                        .build());
+    }
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+
+        if (!isWritebackEnabled()) {
+            jobFinished(params, false);
+            return false;
+        }
+
+        if (params.getJobId() == MARK_IDLE_JOB_ID) {
+            markPagesAsIdle();
+            jobFinished(params, false);
+            return false;
+        } else {
+            new Thread("ZramWriteback_WritebackIdlePages") {
+                @Override
+                public void run() {
+                    markAndFlushPages();
+                    schedNextWriteback(ZramWriteback.this);
+                    jobFinished(params, false);
+                }
+            }.start();
+        }
+        return true;
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        // The thread that triggers the writeback is non-interruptible
+        return false;
+    }
+
+    /**
+     * Schedule the zram writeback job to trigger a writeback when idle
+     */
+    public static void scheduleZramWriteback(Context context) {
+        int markIdleDelay = SystemProperties.getInt(MARK_IDLE_DELAY_PROP, 20);
+        int firstWbDelay = SystemProperties.getInt(FIRST_WB_DELAY_PROP, 180);
+
+        JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+
+        // Schedule a one time job to mark pages as idle. These pages will be written
+        // back at later point if they remain untouched.
+        js.schedule(new JobInfo.Builder(MARK_IDLE_JOB_ID, sZramWriteback)
+                        .setMinimumLatency(TimeUnit.MINUTES.toMillis(markIdleDelay))
+                        .build());
+
+        // Schedule a one time job to flush idle pages to disk.
+        // After the initial writeback, subsequent writebacks are done at interval set
+        // by ro.zram.periodic_wb_delay_hours.
+        js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback)
+                        .setMinimumLatency(TimeUnit.MINUTES.toMillis(firstWbDelay))
+                        .setRequiresDeviceIdle(true)
+                        .build());
+    }
+}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index e879efd..c826df0 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -5202,7 +5202,7 @@
                     Process.SYSTEM_UID, null /* packageName */, false);
             fout.println("Accounts: " + accounts.length);
             for (Account account : accounts) {
-                fout.println("  " + account.toSafeString());
+                fout.println("  " + account.toString());
             }
 
             // Add debug information.
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index ccead6c..c7b9a3c 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -18,6 +18,7 @@
 
 import static com.android.internal.util.dump.DumpUtils.writeStringIfNotNull;
 
+import android.annotation.TestApi;
 import android.app.ActivityManager;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
@@ -26,6 +27,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
+import android.debug.AdbProtoEnums;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.os.Environment;
@@ -37,21 +39,36 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.service.adb.AdbDebuggingManagerProto;
+import android.util.AtomicFile;
 import android.util.Base64;
 import android.util.Slog;
+import android.util.StatsLog;
+import android.util.Xml;
 
 import com.android.internal.R;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
 import com.android.internal.util.dump.DualDumpOutputStream;
 import com.android.server.FgThread;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
 
 /**
  * Provides communication to the Android Debug Bridge daemon to allow, deny, or clear public keysi
@@ -63,6 +80,7 @@
 
     private static final String ADBD_SOCKET = "adbd";
     private static final String ADB_DIRECTORY = "misc/adb";
+    // This file contains keys that will always be allowed to connect to the device via adb.
     private static final String ADB_KEYS_FILE = "adb_keys";
     private static final int BUFFER_SIZE = 4096;
 
@@ -71,12 +89,25 @@
     private AdbDebuggingThread mThread;
     private boolean mAdbEnabled = false;
     private String mFingerprints;
+    private String mConnectedKey;
+    private String mConfirmComponent;
 
     public AdbDebuggingManager(Context context) {
         mHandler = new AdbDebuggingHandler(FgThread.get().getLooper());
         mContext = context;
     }
 
+    /**
+     * Constructor that accepts the component to be invoked to confirm if the user wants to allow
+     * an adb connection from the key.
+     */
+    @TestApi
+    protected AdbDebuggingManager(Context context, String confirmComponent) {
+        mHandler = new AdbDebuggingHandler(FgThread.get().getLooper());
+        mContext = context;
+        mConfirmComponent = confirmComponent;
+    }
+
     class AdbDebuggingThread extends Thread {
         private boolean mStopped;
         private LocalSocket mSocket;
@@ -135,7 +166,9 @@
                 byte[] buffer = new byte[BUFFER_SIZE];
                 while (true) {
                     int count = mInputStream.read(buffer);
-                    if (count < 0) {
+                    // if less than 2 bytes are read the if statements below will throw an
+                    // IndexOutOfBoundsException.
+                    if (count < 2) {
                         break;
                     }
 
@@ -146,6 +179,11 @@
                                 AdbDebuggingHandler.MESSAGE_ADB_CONFIRM);
                         msg.obj = key;
                         mHandler.sendMessage(msg);
+                    } else if (buffer[0] == 'D' && buffer[1] == 'C') {
+                        Slog.d(TAG, "Received disconnected message");
+                        Message msg = mHandler.obtainMessage(
+                                AdbDebuggingHandler.MESSAGE_ADB_DISCONNECT);
+                        mHandler.sendMessage(msg);
                     } else {
                         Slog.e(TAG, "Wrong message: "
                                 + (new String(Arrays.copyOfRange(buffer, 0, 2))));
@@ -202,15 +240,41 @@
     }
 
     class AdbDebuggingHandler extends Handler {
-        private static final int MESSAGE_ADB_ENABLED = 1;
-        private static final int MESSAGE_ADB_DISABLED = 2;
-        private static final int MESSAGE_ADB_ALLOW = 3;
-        private static final int MESSAGE_ADB_DENY = 4;
-        private static final int MESSAGE_ADB_CONFIRM = 5;
-        private static final int MESSAGE_ADB_CLEAR = 6;
+        // The time to schedule the job to keep the key store updated with a currently connected
+        // key. This job is required because a deveoper could keep a device connected to their
+        // system beyond the time within which a subsequent connection is allowed. But since the
+        // last connection time is only written when a device is connected and disconnected then
+        // if the device is rebooted while connected to the development system it would appear as
+        // though the adb grant for the system is no longer authorized and the developer would need
+        // to manually allow the connection again.
+        private static final long UPDATE_KEY_STORE_JOB_INTERVAL = 86400000;
+
+        static final int MESSAGE_ADB_ENABLED = 1;
+        static final int MESSAGE_ADB_DISABLED = 2;
+        static final int MESSAGE_ADB_ALLOW = 3;
+        static final int MESSAGE_ADB_DENY = 4;
+        static final int MESSAGE_ADB_CONFIRM = 5;
+        static final int MESSAGE_ADB_CLEAR = 6;
+        static final int MESSAGE_ADB_DISCONNECT = 7;
+        static final int MESSAGE_ADB_PERSIST_KEY_STORE = 8;
+        static final int MESSAGE_ADB_UPDATE_KEY_CONNECTION_TIME = 9;
+
+        private AdbKeyStore mAdbKeyStore;
 
         AdbDebuggingHandler(Looper looper) {
             super(looper);
+            mAdbKeyStore = new AdbKeyStore();
+        }
+
+        /**
+         * Constructor that accepts the AdbDebuggingThread to which responses should be sent
+         * and the AdbKeyStore to be used to store the temporary grants.
+         */
+        @TestApi
+        AdbDebuggingHandler(Looper looper, AdbDebuggingThread thread, AdbKeyStore adbKeyStore) {
+            super(looper);
+            mThread = thread;
+            mAdbKeyStore = adbKeyStore;
         }
 
         public void handleMessage(Message msg) {
@@ -251,12 +315,15 @@
                         break;
                     }
 
-                    if (msg.arg1 == 1) {
-                        writeKey(key);
-                    }
-
+                    boolean alwaysAllow = msg.arg1 == 1;
                     if (mThread != null) {
                         mThread.sendResponse("OK");
+                        if (alwaysAllow) {
+                            mConnectedKey = key;
+                            mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis());
+                            scheduleJobToUpdateAdbKeyStore();
+                        }
+                        logAdbConnectionChanged(key, AdbProtoEnums.USER_ALLOWED, alwaysAllow);
                     }
                     break;
                 }
@@ -264,36 +331,88 @@
                 case MESSAGE_ADB_DENY:
                     if (mThread != null) {
                         mThread.sendResponse("NO");
+                        logAdbConnectionChanged(null, AdbProtoEnums.USER_DENIED, false);
                     }
                     break;
 
                 case MESSAGE_ADB_CONFIRM: {
+                    String key = (String) msg.obj;
                     if ("trigger_restart_min_framework".equals(
                             SystemProperties.get("vold.decrypt"))) {
                         Slog.d(TAG, "Deferring adb confirmation until after vold decrypt");
                         if (mThread != null) {
                             mThread.sendResponse("NO");
+                            logAdbConnectionChanged(key, AdbProtoEnums.DENIED_VOLD_DECRYPT, false);
                         }
                         break;
                     }
-                    String key = (String) msg.obj;
                     String fingerprints = getFingerprints(key);
                     if ("".equals(fingerprints)) {
                         if (mThread != null) {
                             mThread.sendResponse("NO");
+                            logAdbConnectionChanged(key, AdbProtoEnums.DENIED_INVALID_KEY, false);
                         }
                         break;
                     }
-                    mFingerprints = fingerprints;
-                    startConfirmation(key, mFingerprints);
+                    // Check if the key should be allowed without user interaction.
+                    if (mAdbKeyStore.isKeyAuthorized(key)) {
+                        if (mThread != null) {
+                            mThread.sendResponse("OK");
+                            mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis());
+                            logAdbConnectionChanged(key, AdbProtoEnums.AUTOMATICALLY_ALLOWED, true);
+                            mConnectedKey = key;
+                            scheduleJobToUpdateAdbKeyStore();
+                        }
+                    } else {
+                        logAdbConnectionChanged(key, AdbProtoEnums.AWAITING_USER_APPROVAL, false);
+                        mFingerprints = fingerprints;
+                        startConfirmation(key, mFingerprints);
+                    }
                     break;
                 }
 
-                case MESSAGE_ADB_CLEAR:
+                case MESSAGE_ADB_CLEAR: {
                     deleteKeyFile();
+                    mConnectedKey = null;
+                    mAdbKeyStore.deleteKeyStore();
+                    cancelJobToUpdateAdbKeyStore();
                     break;
+                }
+
+                case MESSAGE_ADB_DISCONNECT: {
+                    if (mConnectedKey != null) {
+                        mAdbKeyStore.setLastConnectionTime(mConnectedKey,
+                                System.currentTimeMillis());
+                        cancelJobToUpdateAdbKeyStore();
+                    }
+                    logAdbConnectionChanged(mConnectedKey, AdbProtoEnums.DISCONNECTED,
+                            (mConnectedKey != null));
+                    mConnectedKey = null;
+                    break;
+                }
+
+                case MESSAGE_ADB_PERSIST_KEY_STORE: {
+                    mAdbKeyStore.persistKeyStore();
+                    break;
+                }
+
+                case MESSAGE_ADB_UPDATE_KEY_CONNECTION_TIME: {
+                    if (mConnectedKey != null) {
+                        mAdbKeyStore.setLastConnectionTime(mConnectedKey,
+                                System.currentTimeMillis());
+                        scheduleJobToUpdateAdbKeyStore();
+                    }
+                    break;
+                }
             }
         }
+
+        private void logAdbConnectionChanged(String key, int state, boolean alwaysAllow) {
+            long lastConnectionTime = mAdbKeyStore.getLastConnectionTime(key);
+            long authWindow = mAdbKeyStore.getAllowedConnectionTime();
+            StatsLog.write(StatsLog.ADB_CONNECTION_CHANGED, lastConnectionTime, authWindow, state,
+                    alwaysAllow);
+        }
     }
 
     private String getFingerprints(String key) {
@@ -335,7 +454,8 @@
         UserInfo userInfo = UserManager.get(mContext).getUserInfo(currentUserId);
         String componentString;
         if (userInfo.isAdmin()) {
-            componentString = Resources.getSystem().getString(
+            componentString = mConfirmComponent != null
+                    ? mConfirmComponent : Resources.getSystem().getString(
                     com.android.internal.R.string.config_customAdbPublicKeyConfirmationComponent);
         } else {
             // If the current foreground user is not the admin user we send a different
@@ -397,7 +517,10 @@
         return intent;
     }
 
-    private File getUserKeyFile() {
+    /**
+     * Returns a new File with the specified name in the adb directory.
+     */
+    private File getAdbFile(String fileName) {
         File dataDir = Environment.getDataDirectory();
         File adbDir = new File(dataDir, ADB_DIRECTORY);
 
@@ -406,7 +529,11 @@
             return null;
         }
 
-        return new File(adbDir, ADB_KEYS_FILE);
+        return new File(adbDir, fileName);
+    }
+
+    private File getUserKeyFile() {
+        return getAdbFile(ADB_KEYS_FILE);
     }
 
     private void writeKey(String key) {
@@ -476,6 +603,36 @@
     }
 
     /**
+     * Sends a message to the handler to persist the key store.
+     */
+    private void sendPersistKeyStoreMessage() {
+        Message msg = mHandler.obtainMessage(AdbDebuggingHandler.MESSAGE_ADB_PERSIST_KEY_STORE);
+        mHandler.sendMessage(msg);
+    }
+
+    /**
+     * Schedules a job to update the connection time of the currently connected key. This is
+     * intended for cases such as development devices that are left connected to a user's
+     * system beyond the window within which a connection is allowed without user interaction.
+     * A job should be rescheduled daily so that if the device is rebooted while connected to
+     * the user's system the last time in the key store will show within 24 hours which should
+     * be within the allowed window.
+     */
+    private void scheduleJobToUpdateAdbKeyStore() {
+        Message message = mHandler.obtainMessage(
+                AdbDebuggingHandler.MESSAGE_ADB_UPDATE_KEY_CONNECTION_TIME);
+        mHandler.sendMessageDelayed(message, AdbDebuggingHandler.UPDATE_KEY_STORE_JOB_INTERVAL);
+    }
+
+    /**
+     * Cancels the scheduled job to update the connection time of the currently connected key.
+     * This should be invoked once the adb session is disconnected.
+     */
+    private void cancelJobToUpdateAdbKeyStore() {
+        mHandler.removeMessages(AdbDebuggingHandler.MESSAGE_ADB_UPDATE_KEY_CONNECTION_TIME);
+    }
+
+    /**
      * Dump the USB debugging state.
      */
     public void dump(DualDumpOutputStream dump, String idName, long id) {
@@ -501,4 +658,231 @@
 
         dump.end(token);
     }
+
+    /**
+     * Handles adb keys for which the user has granted the 'always allow' option. This class ensures
+     * these grants are revoked after a period of inactivity as specified in the
+     * ADB_ALLOWED_CONNECTION_TIME setting.
+     */
+    class AdbKeyStore {
+        private Map<String, Long> mKeyMap;
+        private File mKeyFile;
+        private AtomicFile mAtomicKeyFile;
+        // This file contains keys that will be allowed to connect without user interaction as long
+        // as a subsequent connection occurs within the allowed duration.
+        private static final String ADB_TEMP_KEYS_FILE = "adb_temp_keys.xml";
+        private static final String XML_TAG_ADB_KEY = "adbKey";
+        private static final String XML_ATTRIBUTE_KEY = "key";
+        private static final String XML_ATTRIBUTE_LAST_CONNECTION = "lastConnection";
+
+        /**
+         * Value returned by {@code getLastConnectionTime} when there is no previously saved
+         * connection time for the specified key.
+         */
+        public static final long NO_PREVIOUS_CONNECTION = 0;
+
+        /**
+         * Constructor that uses the default location for the persistent adb key store.
+         */
+        AdbKeyStore() {
+            initKeyFile();
+            mKeyMap = getKeyMapFromFile();
+        }
+
+        /**
+         * Constructor that uses the specified file as the location for the persistent adb key
+         * store.
+         */
+        AdbKeyStore(File keyFile) {
+            mKeyFile = keyFile;
+            initKeyFile();
+            mKeyMap = getKeyMapFromFile();
+        }
+
+        /**
+         * Initializes the key file that will be used to persist the adb grants.
+         */
+        private void initKeyFile() {
+            if (mKeyFile == null) {
+                mKeyFile = getAdbFile(ADB_TEMP_KEYS_FILE);
+            }
+            // getAdbFile can return null if the adb file cannot be obtained
+            if (mKeyFile != null) {
+                mAtomicKeyFile = new AtomicFile(mKeyFile);
+            }
+        }
+
+        /**
+         * Returns the key map with the keys and last connection times from the key file.
+         */
+        private Map<String, Long> getKeyMapFromFile() {
+            Map<String, Long> keyMap = new HashMap<String, Long>();
+            // if the AtomicFile could not be instantiated before attempt again; if it still fails
+            // return an empty key map.
+            if (mAtomicKeyFile == null) {
+                initKeyFile();
+                if (mAtomicKeyFile == null) {
+                    Slog.e(TAG, "Unable to obtain the key file, " + mKeyFile + ", for reading");
+                    return keyMap;
+                }
+            }
+            if (!mAtomicKeyFile.exists()) {
+                return keyMap;
+            }
+            try (FileInputStream keyStream = mAtomicKeyFile.openRead()) {
+                XmlPullParser parser = Xml.newPullParser();
+                parser.setInput(keyStream, StandardCharsets.UTF_8.name());
+                XmlUtils.beginDocument(parser, XML_TAG_ADB_KEY);
+                while (parser.next() != XmlPullParser.END_DOCUMENT) {
+                    String tagName = parser.getName();
+                    if (tagName == null) {
+                        break;
+                    } else if (!tagName.equals(XML_TAG_ADB_KEY)) {
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    String key = parser.getAttributeValue(null, XML_ATTRIBUTE_KEY);
+                    long connectionTime;
+                    try {
+                        connectionTime = Long.valueOf(
+                                parser.getAttributeValue(null, XML_ATTRIBUTE_LAST_CONNECTION));
+                    } catch (NumberFormatException e) {
+                        Slog.e(TAG,
+                                "Caught a NumberFormatException parsing the last connection time: "
+                                        + e);
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    keyMap.put(key, connectionTime);
+                }
+            } catch (IOException | XmlPullParserException e) {
+                Slog.e(TAG, "Caught an exception parsing the XML key file: ", e);
+            }
+            return keyMap;
+        }
+
+        /**
+         * Writes the key map to the key file.
+         */
+        public void persistKeyStore() {
+            // if there is nothing in the key map then ensure any keys left in the key store files
+            // are deleted as well.
+            if (mKeyMap.size() == 0) {
+                deleteKeyStore();
+                return;
+            }
+            if (mAtomicKeyFile == null) {
+                initKeyFile();
+                if (mAtomicKeyFile == null) {
+                    Slog.e(TAG, "Unable to obtain the key file, " + mKeyFile + ", for writing");
+                    return;
+                }
+            }
+            FileOutputStream keyStream = null;
+            try {
+                XmlSerializer serializer = new FastXmlSerializer();
+                keyStream = mAtomicKeyFile.startWrite();
+                serializer.setOutput(keyStream, StandardCharsets.UTF_8.name());
+                serializer.startDocument(null, true);
+                long allowedTime = getAllowedConnectionTime();
+                long systemTime = System.currentTimeMillis();
+                Iterator keyMapIterator = mKeyMap.entrySet().iterator();
+                while (keyMapIterator.hasNext()) {
+                    Map.Entry<String, Long> keyEntry = (Map.Entry) keyMapIterator.next();
+                    long connectionTime = keyEntry.getValue();
+                    if (systemTime < (connectionTime + allowedTime)) {
+                        serializer.startTag(null, XML_TAG_ADB_KEY);
+                        serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey());
+                        serializer.attribute(null, XML_ATTRIBUTE_LAST_CONNECTION,
+                                String.valueOf(keyEntry.getValue()));
+                        serializer.endTag(null, XML_TAG_ADB_KEY);
+                    } else {
+                        keyMapIterator.remove();
+                    }
+                }
+                serializer.endDocument();
+                mAtomicKeyFile.finishWrite(keyStream);
+            } catch (IOException e) {
+                Slog.e(TAG, "Caught an exception writing the key map: ", e);
+                mAtomicKeyFile.failWrite(keyStream);
+            }
+        }
+
+        /**
+         * Removes all of the entries in the key map and deletes the key file.
+         */
+        public void deleteKeyStore() {
+            mKeyMap.clear();
+            if (mAtomicKeyFile == null) {
+                return;
+            }
+            mAtomicKeyFile.delete();
+        }
+
+        /**
+         * Returns the time of the last connection from the specified key, or {@code
+         * NO_PREVIOUS_CONNECTION} if the specified key does not have an active adb grant.
+         */
+        public long getLastConnectionTime(String key) {
+            return mKeyMap.getOrDefault(key, NO_PREVIOUS_CONNECTION);
+        }
+
+        /**
+         * Sets the time of the last connection for the specified key to the provided time.
+         */
+        public void setLastConnectionTime(String key, long connectionTime) {
+            // Do not set the connection time to a value that is earlier than what was previously
+            // stored as the last connection time.
+            if (mKeyMap.containsKey(key) && mKeyMap.get(key) >= connectionTime) {
+                return;
+            }
+            mKeyMap.put(key, connectionTime);
+            sendPersistKeyStoreMessage();
+        }
+
+        /**
+         * Returns whether the specified key should be authroized to connect without user
+         * interaction. This requires that the user previously connected this device and selected
+         * the option to 'Always allow', and the time since the last connection is within the
+         * allowed window.
+         */
+        public boolean isKeyAuthorized(String key) {
+            long lastConnectionTime = getLastConnectionTime(key);
+            if (lastConnectionTime == NO_PREVIOUS_CONNECTION) {
+                return false;
+            }
+            long allowedConnectionTime = getAllowedConnectionTime();
+            // if the allowed connection time is 0 then revert to the previous behavior of always
+            // allowing previously granted adb grants.
+            if (allowedConnectionTime == 0 || (System.currentTimeMillis() < (lastConnectionTime
+                    + allowedConnectionTime))) {
+                return true;
+            } else {
+                // since this key is no longer auhorized remove it from the Map
+                removeKey(key);
+                return false;
+            }
+        }
+
+        /**
+         * Returns the connection time within which a connection from an allowed key is
+         * automatically allowed without user interaction.
+         */
+        public long getAllowedConnectionTime() {
+            return Settings.Global.getLong(mContext.getContentResolver(),
+                    Settings.Global.ADB_ALLOWED_CONNECTION_TIME,
+                    Settings.Global.DEFAULT_ADB_ALLOWED_CONNECTION_TIME);
+        }
+
+        /**
+         * Removes the specified key from the key store.
+         */
+        public void removeKey(String key) {
+            if (!mKeyMap.containsKey(key)) {
+                return;
+            }
+            mKeyMap.remove(key);
+            sendPersistKeyStoreMessage();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index e5ab8fc..c316915 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -31,6 +31,7 @@
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.service.adb.AdbServiceDumpProto;
+import android.sysprop.AdbProperties;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -185,7 +186,7 @@
         mContext = context;
         mContentResolver = context.getContentResolver();
 
-        boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false);
+        boolean secureAdbEnabled = AdbProperties.secure().orElse(false);
         boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt"));
         if (secureAdbEnabled && !dataEncrypted) {
             mDebuggingManager = new AdbDebuggingManager(context);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a94fa12..a96676e 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -130,6 +130,9 @@
     // calling startForeground() before we ANR + stop it.
     static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000;
 
+    // For how long after a whitelisted service's start its process can start a background activity
+    private static final int SERVICE_BG_ACTIVITY_START_TIMEOUT_MS = 10*1000;
+
     final ActivityManagerService mAm;
 
     // Maximum number of services that we allow to start in the background
@@ -398,6 +401,14 @@
     ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
             int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
             throws TransactionTooLargeException {
+        return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
+                callingPackage, userId, false);
+    }
+
+    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
+            int callingPid, int callingUid, boolean fgRequired, String callingPackage,
+            final int userId, boolean allowBackgroundActivityStarts)
+            throws TransactionTooLargeException {
         if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
                 + " type=" + resolvedType + " args=" + service.getExtras());
 
@@ -505,7 +516,7 @@
                 }
                 // This app knows it is in the new model where this operation is not
                 // allowed, so tell it what has happened.
-                UidRecord uidRec = mAm.mActiveUids.get(r.appInfo.uid);
+                UidRecord uidRec = mAm.mProcessList.getUidRecordLocked(r.appInfo.uid);
                 return new ComponentName("?", "app is in background uid " + uidRec);
             }
         }
@@ -622,10 +633,28 @@
             }
         }
 
+        if (allowBackgroundActivityStarts) {
+            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
+            if (proc != null) {
+                proc.addAllowBackgroundActivityStartsToken(r);
+                // schedule removal of the whitelisting token after the timeout
+                removeAllowBackgroundActivityStartsServiceToken(proc, r,
+                        SERVICE_BG_ACTIVITY_START_TIMEOUT_MS);
+            }
+        }
         ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
         return cmp;
     }
 
+    private void removeAllowBackgroundActivityStartsServiceToken(ProcessRecord proc,
+            ServiceRecord r, int delayMillis) {
+        mAm.mHandler.postDelayed(() -> {
+            if (proc != null) {
+                proc.removeAllowBackgroundActivityStartsToken(r);
+            }
+        }, delayMillis);
+    }
+
     private boolean requestStartTargetPermissionsReviewIfNeededLocked(ServiceRecord r,
             String callingPackage, int callingUid, Intent service, boolean callerFg,
             final int userId) {
@@ -710,7 +739,7 @@
 
     private void stopServiceLocked(ServiceRecord service) {
         if (service.delayed) {
-            // If service isn't actually running, but is is being held in the
+            // If service isn't actually running, but is being held in the
             // delayed list, then we need to keep it started but note that it
             // should be stopped once no longer delayed.
             if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Delaying stop of pending: " + service);
@@ -752,6 +781,9 @@
             if (r.record != null) {
                 final long origId = Binder.clearCallingIdentity();
                 try {
+                    // immediately remove bg activity whitelisting token if there was one
+                    removeAllowBackgroundActivityStartsServiceToken(callerApp, r.record,
+                            0 /* delayMillis */);
                     stopServiceLocked(r.record);
                 } finally {
                     Binder.restoreCallingIdentity(origId);
@@ -1654,6 +1686,10 @@
                 }
             }
 
+            if ((flags & Context.BIND_RESTRICT_ASSOCIATIONS) != 0) {
+                mAm.requireAllowedAssociationsLocked(s.appInfo.packageName);
+            }
+
             mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
                     callerApp.getCurProcState(), s.appInfo.uid, s.appInfo.longVersionCode,
                     s.instanceName, s.processName);
@@ -2503,6 +2539,9 @@
                     && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
                 hostingType = "webview_service";
             }
+            if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {
+                hostingType = "app_zygote";
+            }
         }
 
         // Not running -- get it started, and enqueue this service record
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 1c04a94..dd2b33a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -70,6 +70,12 @@
     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";
     static final String KEY_USE_COMPACTION = "use_compaction";
+    static final String KEY_COMPACT_ACTION_1 = "compact_action_1";
+    static final String KEY_COMPACT_ACTION_2 = "compact_action_2";
+    static final String KEY_COMPACT_THROTTLE_1 = "compact_throttle_1";
+    static final String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2";
+    static final String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3";
+    static final String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
     private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -101,6 +107,12 @@
     private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
     private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
     private static final boolean DEFAULT_USE_COMPACTION = false;
+    public static final int DEFAULT_COMPACT_ACTION_1 = 1;
+    public static final int DEFAULT_COMPACT_ACTION_2 = 3;
+    public static final long DEFAULT_COMPACT_THROTTLE_1 = 5000;
+    public static final long DEFAULT_COMPACT_THROTTLE_2 = 10000;
+    public static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
+    public static final long DEFAULT_COMPACT_THROTTLE_4 = 10000;
 
     // Maximum number of cached processes we will allow.
     public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -223,6 +235,20 @@
     // Use compaction for background apps.
     public boolean USE_COMPACTION = DEFAULT_USE_COMPACTION;
 
+    // Action for compactAppSome.
+    public int COMPACT_ACTION_1 = DEFAULT_COMPACT_ACTION_1;
+    // Action for compactAppFull;
+    public int COMPACT_ACTION_2 = DEFAULT_COMPACT_ACTION_2;
+
+    // How long we'll skip second compactAppSome after first compactAppSome
+    public long COMPACT_THROTTLE_1 = DEFAULT_COMPACT_THROTTLE_1;
+    // How long we'll skip compactAppSome after compactAppFull
+    public long COMPACT_THROTTLE_2 = DEFAULT_COMPACT_THROTTLE_2;
+    // How long we'll skip compactAppFull after compactAppSome
+    public long COMPACT_THROTTLE_3 = DEFAULT_COMPACT_THROTTLE_3;
+    // How long we'll skip second compactAppFull after first compactAppFull
+    public long COMPACT_THROTTLE_4 = DEFAULT_COMPACT_THROTTLE_4;
+
     // Indicates whether the activity starts logging is enabled.
     // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
     volatile boolean mFlagActivityStartsLoggingEnabled;
@@ -381,6 +407,12 @@
             TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION,
                     DEFAULT_TOP_TO_FGS_GRACE_DURATION);
             USE_COMPACTION = mParser.getBoolean(KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);
+            COMPACT_ACTION_1 = mParser.getInt(KEY_COMPACT_ACTION_1, DEFAULT_COMPACT_ACTION_1);
+            COMPACT_ACTION_2 = mParser.getInt(KEY_COMPACT_ACTION_2, DEFAULT_COMPACT_ACTION_2);
+            COMPACT_THROTTLE_1 = mParser.getLong(KEY_COMPACT_THROTTLE_1, DEFAULT_COMPACT_THROTTLE_1);
+            COMPACT_THROTTLE_2 = mParser.getLong(KEY_COMPACT_THROTTLE_2, DEFAULT_COMPACT_THROTTLE_2);
+            COMPACT_THROTTLE_3 = mParser.getLong(KEY_COMPACT_THROTTLE_3, DEFAULT_COMPACT_THROTTLE_3);
+            COMPACT_THROTTLE_4 = mParser.getLong(KEY_COMPACT_THROTTLE_4, DEFAULT_COMPACT_THROTTLE_4);
 
             updateMaxCachedProcesses();
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 16c236e..b24290f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -24,8 +24,6 @@
 import static android.Manifest.permission.REMOVE_TASKS;
 import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
 import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL;
-import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
-import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
 import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
@@ -34,6 +32,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
 import static android.content.pm.PackageManager.GET_PROVIDERS;
+import static android.content.pm.PackageManager.MATCH_ALL;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -50,6 +49,7 @@
 import static android.os.IServiceManager.DUMP_FLAG_PROTO;
 import static android.os.Process.BLUETOOTH_UID;
 import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.os.Process.NETWORK_STACK_UID;
 import static android.os.Process.NFC_UID;
 import static android.os.Process.PHONE_UID;
 import static android.os.Process.PROC_CHAR;
@@ -58,17 +58,13 @@
 import static android.os.Process.PROC_SPACE_TERM;
 import static android.os.Process.ROOT_UID;
 import static android.os.Process.SCHED_FIFO;
-import static android.os.Process.SCHED_OTHER;
 import static android.os.Process.SCHED_RESET_ON_FORK;
 import static android.os.Process.SE_UID;
 import static android.os.Process.SHELL_UID;
 import static android.os.Process.SIGNAL_USR1;
 import static android.os.Process.SYSTEM_UID;
-import static android.os.Process.THREAD_GROUP_BG_NONINTERACTIVE;
-import static android.os.Process.THREAD_GROUP_DEFAULT;
-import static android.os.Process.THREAD_GROUP_RESTRICTED;
-import static android.os.Process.THREAD_GROUP_TOP_APP;
 import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
+import static android.os.Process.ZYGOTE_PROCESS;
 import static android.os.Process.getTotalMemory;
 import static android.os.Process.isThreadInProcess;
 import static android.os.Process.killProcess;
@@ -78,10 +74,8 @@
 import static android.os.Process.readProcFile;
 import static android.os.Process.removeAllProcessGroups;
 import static android.os.Process.sendSignal;
-import static android.os.Process.setProcessGroup;
 import static android.os.Process.setThreadPriority;
 import static android.os.Process.setThreadScheduler;
-import static android.os.Process.zygoteProcess;
 import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
 import static android.provider.Settings.Global.DEBUG_APP;
 import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS;
@@ -95,11 +89,9 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ_REASON;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
@@ -108,7 +100,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
@@ -235,6 +226,7 @@
 import android.net.Proxy;
 import android.net.ProxyInfo;
 import android.net.Uri;
+import android.os.AppZygote;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.BinderProxy;
@@ -327,7 +319,6 @@
 import com.android.internal.util.function.QuadFunction;
 import com.android.internal.util.function.TriFunction;
 import com.android.server.AlarmManagerInternal;
-import com.android.server.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.DeviceIdleController;
 import com.android.server.DisplayThread;
@@ -346,6 +337,7 @@
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
 import com.android.server.am.MemoryStatUtil.MemoryStat;
+import com.android.server.appop.AppOpsService;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.job.JobSchedulerInternal;
 import com.android.server.pm.Installer;
@@ -402,7 +394,7 @@
     public static final int TOP_APP_PRIORITY_BOOST = -10;
 
     static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
-    private static final String TAG_BACKUP = TAG + POSTFIX_BACKUP;
+    static final String TAG_BACKUP = TAG + POSTFIX_BACKUP;
     private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
     private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
@@ -410,9 +402,9 @@
     static final String TAG_LRU = TAG + POSTFIX_LRU;
     private static final String TAG_MU = TAG + POSTFIX_MU;
     private static final String TAG_NETWORK = TAG + POSTFIX_NETWORK;
-    private static final String TAG_OOM_ADJ = TAG + POSTFIX_OOM_ADJ;
+    static final String TAG_OOM_ADJ = TAG + POSTFIX_OOM_ADJ;
     private static final String TAG_POWER = TAG + POSTFIX_POWER;
-    private static final String TAG_PROCESS_OBSERVERS = TAG + POSTFIX_PROCESS_OBSERVERS;
+    static final String TAG_PROCESS_OBSERVERS = TAG + POSTFIX_PROCESS_OBSERVERS;
     static final String TAG_PROCESSES = TAG + POSTFIX_PROCESSES;
     private static final String TAG_PROVIDER = TAG + POSTFIX_PROVIDER;
     static final String TAG_PSS = TAG + POSTFIX_PSS;
@@ -452,6 +444,9 @@
     // before we decide it must be hung.
     static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
 
+    // How long we wait to kill an application zygote, after the last process using
+    // it has gone away.
+    static final int KILL_APP_ZYGOTE_DELAY_MS = 5 * 1000;
     /**
      * How long we wait for an provider to be published. Should be longer than
      * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT}.
@@ -536,6 +531,8 @@
 
     private static final int NATIVE_DUMP_TIMEOUT_MS = 2000; // 2 seconds;
 
+    final OomAdjuster mOomAdjuster;
+
     /** All system services */
     SystemServiceManager mSystemServiceManager;
 
@@ -550,7 +547,7 @@
     public OomAdjProfiler mOomAdjProfiler = new OomAdjProfiler();
 
     // Whether we should use SCHED_FIFO for UI and RenderThreads.
-    private boolean mUseFifoUiScheduling = false;
+    boolean mUseFifoUiScheduling = false;
 
     BroadcastQueue mFgBroadcastQueue;
     BroadcastQueue mBgBroadcastQueue;
@@ -649,11 +646,6 @@
     final ProcessStatsService mProcessStats;
 
     /**
-     * Service for compacting background apps.
-     */
-    final AppCompactor mAppCompact;
-
-    /**
      * Non-persistent appId whitelist for background restrictions
      */
     int[] mBackgroundAppIdWhitelist = new int[] {
@@ -667,9 +659,47 @@
 
     /**
      * When an app has restrictions on the other apps that can have associations with it,
-     * it appears here with a set of the allowed apps.
+     * it appears here with a set of the allowed apps and also track debuggability of the app.
      */
-    ArrayMap<String, ArraySet<String>> mAllowedAssociations;
+    ArrayMap<String, PackageAssociationInfo> mAllowedAssociations;
+
+    /**
+     * Tracks association information for a particular package along with debuggability.
+     * <p> Associations for a package A are allowed to package B if B is part of the
+     *     allowed associations for A or if A is debuggable.
+     */
+    private final class PackageAssociationInfo {
+        private final String mSourcePackage;
+        private final ArraySet<String> mAllowedPackageAssociations;
+        private boolean mIsDebuggable;
+
+        PackageAssociationInfo(String sourcePackage, ArraySet<String> allowedPackages,
+                boolean isDebuggable) {
+            mSourcePackage = sourcePackage;
+            mAllowedPackageAssociations = allowedPackages;
+            mIsDebuggable = isDebuggable;
+        }
+
+        /**
+         * Returns true if {@code mSourcePackage} is allowed association with
+         * {@code targetPackage}.
+         */
+        boolean isPackageAssociationAllowed(String targetPackage) {
+            return mIsDebuggable || mAllowedPackageAssociations.contains(targetPackage);
+        }
+
+        boolean isDebuggable() {
+            return mIsDebuggable;
+        }
+
+        void setDebuggable(boolean isDebuggable) {
+            mIsDebuggable = isDebuggable;
+        }
+
+        ArraySet<String> getAllowedPackageAssociations() {
+            return mAllowedPackageAssociations;
+        }
+    }
 
     /**
      * All of the processes we currently have running organized by pid.
@@ -816,8 +846,6 @@
      */
     boolean mFullPssPending = false;
 
-    /** Track all uids that have actively running processes. */
-    final ActiveUids mActiveUids;
 
     /**
      * This is for verifying the UID report flow.
@@ -931,8 +959,8 @@
     /**
      * Backup/restore process management
      */
-    String mBackupAppName = null;
-    BackupRecord mBackupTarget = null;
+    @GuardedBy("this")
+    final SparseArray<BackupRecord> mBackupTargets = new SparseArray<>();
 
     final ProviderMap mProviderMap;
 
@@ -1099,32 +1127,7 @@
     /**
      * State of external calls telling us if the device is awake or asleep.
      */
-    private int mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
-
-    /**
-     * Current sequence id for oom_adj computation traversal.
-     */
-    int mAdjSeq = 0;
-
-    /**
-     * Keep track of the non-cached/empty process we last found, to help
-     * determine how to distribute cached/empty processes next time.
-     */
-    int mNumNonCachedProcs = 0;
-
-    /**
-     * Keep track of the number of cached hidden procs, to balance oom adj
-     * distribution between those and empty procs.
-     */
-    int mNumCachedHiddenProcs = 0;
-
-    /**
-     * Keep track of the number of service processes we last found, to
-     * determine on the next iteration which should be B services.
-     */
-    int mNumServiceProcs = 0;
-    int mNewNumAServiceProcs = 0;
-    int mNewNumServiceProcs = 0;
+    int mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
 
     /**
      * Allow the current computed overall memory level of the system to go down?
@@ -1251,10 +1254,6 @@
     String mTrackAllocationApp = null;
     String mNativeDebuggingApp = null;
 
-    final long[] mTmpLong = new long[3];
-
-    private final ArraySet<BroadcastQueue> mTmpBroadcastQueue = new ArraySet();
-
     private final Injector mInjector;
 
     static final class ProcessChangeItem {
@@ -1329,6 +1328,7 @@
         }
     }
 
+    // TODO: Move below 4 members and code to ProcessList
     final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>();
     ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5];
 
@@ -1441,6 +1441,7 @@
     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;
+    static final int KILL_APP_ZYGOTE_MSG = 71;
 
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
 
@@ -1644,6 +1645,12 @@
                             false, userId, reason);
                 }
             } break;
+                case KILL_APP_ZYGOTE_MSG: {
+                    synchronized (ActivityManagerService.this) {
+                        final AppZygote appZygote = (AppZygote) msg.obj;
+                        mProcessList.killAppZygoteIfNeededLocked(appZygote);
+                    }
+                } break;
             case CHECK_EXCESSIVE_POWER_USE_MSG: {
                 synchronized (ActivityManagerService.this) {
                     checkExcessivePowerUsageLocked();
@@ -1932,7 +1939,8 @@
             synchronized (this) {
                 ProcessRecord app = mProcessList.newProcessRecordLocked(info, info.processName,
                         false,
-                        0);
+                        0,
+                        false);
                 app.setPersistent(true);
                 app.pid = MY_PID;
                 app.getWindowProcessController().setPid(MY_PID);
@@ -2154,7 +2162,7 @@
                             ? Collections.emptyList()
                             : Arrays.asList(exemptions.split(","));
                 }
-                if (!zygoteProcess.setApiBlacklistExemptions(mExemptions)) {
+                if (!ZYGOTE_PROCESS.setApiBlacklistExemptions(mExemptions)) {
                   Slog.e(TAG, "Failed to set API blacklist exemptions!");
                   // leave mExemptionsStr as is, so we don't try to send the same list again.
                   mExemptions = Collections.emptyList();
@@ -2167,7 +2175,7 @@
             }
             if (logSampleRate != -1 && logSampleRate != mLogSampleRate) {
                 mLogSampleRate = logSampleRate;
-                zygoteProcess.setHiddenApiAccessLogSampleRate(mLogSampleRate);
+                ZYGOTE_PROCESS.setHiddenApiAccessLogSampleRate(mLogSampleRate);
             }
             mPolicy = getValidEnforcementPolicy(Settings.Global.HIDDEN_API_POLICY);
         }
@@ -2212,12 +2220,15 @@
         mUiContext = null;
         mAppErrors = null;
         mPackageWatchdog = null;
-        mActiveUids = new ActiveUids(this, false /* postChangesToAtm */);
         mAppOpsService = mInjector.getAppOpsService(null /* file */, null /* handler */);
         mBatteryStatsService = null;
         mHandler = hasHandlerThread ? new MainHandler(handlerThread.getLooper()) : null;
         mHandlerThread = handlerThread;
         mConstants = hasHandlerThread ? new ActivityManagerConstants(this, mHandler) : null;
+        final ActiveUids activeUids = new ActiveUids(this, false /* postChangesToAtm */);
+        mProcessList.init(this, activeUids);
+        mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
+
         mIntentFirewall = hasHandlerThread
                 ? new IntentFirewall(new IntentFirewallInterface(), mHandler) : null;
         mProcessCpuThread = null;
@@ -2233,7 +2244,6 @@
                 ? new PendingIntentController(handlerThread.getLooper(), mUserController) : null;
         mProcStartHandlerThread = null;
         mProcStartHandler = null;
-        mAppCompact = null;
         mHiddenApiBlacklist = null;
         mFactoryTest = FACTORY_TEST_OFF;
     }
@@ -2263,8 +2273,9 @@
         mProcStartHandler = new Handler(mProcStartHandlerThread.getLooper());
 
         mConstants = new ActivityManagerConstants(this, mHandler);
-
-        mProcessList.init(this);
+        final ActiveUids activeUids = new ActiveUids(this, true /* postChangesToAtm */);
+        mProcessList.init(this, activeUids);
+        mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
 
         mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
                 "foreground", BROADCAST_FG_TIMEOUT, false);
@@ -2280,7 +2291,6 @@
         mProviderMap = new ProviderMap(this);
         mPackageWatchdog = PackageWatchdog.getInstance(mUiContext);
         mAppErrors = new AppErrors(mUiContext, this, mPackageWatchdog);
-        mActiveUids = new ActiveUids(this, true /* postChangesToAtm */);
 
         final File systemDir = SystemServiceManager.ensureSystemDir();
 
@@ -2317,8 +2327,6 @@
                 DisplayThread.get().getLooper());
         mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
 
-        mAppCompact = new AppCompactor(this);
-
         mProcessCpuThread = new Thread("CpuTracker") {
             @Override
             public void run() {
@@ -2365,7 +2373,8 @@
         try {
             Process.setThreadGroupAndCpuset(BackgroundThread.get().getThreadId(),
                     Process.THREAD_GROUP_SYSTEM);
-            Process.setThreadGroupAndCpuset(mAppCompact.mCompactionThread.getThreadId(),
+            Process.setThreadGroupAndCpuset(
+                    mOomAdjuster.mAppCompact.mCompactionThread.getThreadId(),
                     Process.THREAD_GROUP_SYSTEM);
         } catch (Exception e) {
             Slog.w(TAG, "Setting background thread cpuset failed");
@@ -2417,32 +2426,82 @@
         return mBackgroundLaunchBroadcasts;
     }
 
+    /**
+     * Ensures that the given package name has an explicit set of allowed associations.
+     * If it does not, give it an empty set.
+     */
+    void requireAllowedAssociationsLocked(String packageName) {
+        ensureAllowedAssociations();
+        if (mAllowedAssociations.get(packageName) == null) {
+            mAllowedAssociations.put(packageName, new PackageAssociationInfo(packageName,
+                    new ArraySet<>(), /* isDebuggable = */ false));
+        }
+    }
+
+    /**
+     * Returns true if the package {@code pkg1} running under user handle {@code uid1} is
+     * allowed association with the package {@code pkg2} running under user handle {@code uid2}.
+     * <p> If either of the packages are running as  part of the core system, then the
+     * association is implicitly allowed.
+     */
     boolean validateAssociationAllowedLocked(String pkg1, int uid1, String pkg2, int uid2) {
-        if (mAllowedAssociations == null) {
-            mAllowedAssociations = SystemConfig.getInstance().getAllowedAssociations();
-        }
+        ensureAllowedAssociations();
         // Interactions with the system uid are always allowed, since that is the core system
-        // that everyone needs to be able to interact with.
-        if (UserHandle.getAppId(uid1) == SYSTEM_UID) {
+        // that everyone needs to be able to interact with. Also allow reflexive associations
+        // within the same uid.
+        if (uid1 == uid2 || UserHandle.getAppId(uid1) == SYSTEM_UID
+                || UserHandle.getAppId(uid2) == SYSTEM_UID) {
             return true;
         }
-        if (UserHandle.getAppId(uid2) == SYSTEM_UID) {
-            return true;
+
+        // Check for association on both source and target packages.
+        PackageAssociationInfo pai = mAllowedAssociations.get(pkg1);
+        if (pai != null && !pai.isPackageAssociationAllowed(pkg2)) {
+            return false;
         }
-        // We won't allow this association if either pkg1 or pkg2 has a limit on the
-        // associations that are allowed with it, and the other package is not explicitly
-        // specified as one of those associations.
-        ArraySet<String> pkgs = mAllowedAssociations.get(pkg1);
-        if (pkgs != null) {
-            if (!pkgs.contains(pkg2)) {
-                return false;
+        pai = mAllowedAssociations.get(pkg2);
+        if (pai != null && !pai.isPackageAssociationAllowed(pkg1)) {
+            return false;
+        }
+        // If no explicit associations are provided in the manifest, then assume the app is
+        // allowed associations with any package.
+        return true;
+    }
+
+    /** Sets up allowed associations for system prebuilt packages from system config (if needed). */
+    private void ensureAllowedAssociations() {
+        if (mAllowedAssociations == null) {
+            ArrayMap<String, ArraySet<String>> allowedAssociations =
+                    SystemConfig.getInstance().getAllowedAssociations();
+            mAllowedAssociations = new ArrayMap<>(allowedAssociations.size());
+            PackageManagerInternal pm = getPackageManagerInternalLocked();
+            for (int i = 0; i < allowedAssociations.size(); i++) {
+                final String pkg = allowedAssociations.keyAt(i);
+                final ArraySet<String> asc = allowedAssociations.valueAt(i);
+
+                // Query latest debuggable flag from package-manager.
+                boolean isDebuggable = false;
+                try {
+                    ApplicationInfo ai = AppGlobals.getPackageManager()
+                            .getApplicationInfo(pkg, MATCH_ALL, 0);
+                    if (ai != null) {
+                        isDebuggable = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+                    }
+                } catch (RemoteException e) {
+                    /* ignore */
+                }
+                mAllowedAssociations.put(pkg, new PackageAssociationInfo(pkg, asc, isDebuggable));
             }
         }
-        pkgs = mAllowedAssociations.get(pkg2);
-        if (pkgs != null) {
-            return pkgs.contains(pkg1);
+    }
+
+    /** Updates allowed associations for app info (specifically, based on debuggability).  */
+    private void updateAssociationForApp(ApplicationInfo appInfo) {
+        ensureAllowedAssociations();
+        PackageAssociationInfo pai = mAllowedAssociations.get(appInfo.packageName);
+        if (pai != null) {
+            pai.setDebuggable((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
         }
-        return true;
     }
 
     @Override
@@ -2805,16 +2864,18 @@
      * @param userId
      * @param event
      * @param appToken ActivityRecord's appToken.
+     * @param taskRoot TaskRecord's root
      */
     public void updateActivityUsageStats(ComponentName activity, int userId, int event,
-            IBinder appToken) {
+            IBinder appToken, ComponentName taskRoot) {
         if (DEBUG_SWITCH) {
             Slog.d(TAG_SWITCH, "updateActivityUsageStats: comp="
                     + activity + " hash=" + appToken.hashCode() + " event=" + event);
         }
         synchronized (this) {
             if (mUsageStatsService != null) {
-                mUsageStatsService.reportEvent(activity, userId, event, appToken.hashCode());
+                mUsageStatsService.reportEvent(activity, userId, event, appToken.hashCode(),
+                        taskRoot);
             }
         }
     }
@@ -2852,7 +2913,7 @@
             if (mUsageStatsService != null) {
                 mUsageStatsService.reportEvent(service, userId,
                         started ? UsageEvents.Event.FOREGROUND_SERVICE_START
-                                : UsageEvents.Event.FOREGROUND_SERVICE_STOP, 0);
+                                : UsageEvents.Event.FOREGROUND_SERVICE_STOP, 0, null);
             }
         }
     }
@@ -3744,10 +3805,10 @@
                         intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
                         broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
                                 null, null, permission.ACCESS_INSTANT_APPS, null, false, false,
-                                resolvedUserId);
+                                resolvedUserId, false);
                     } else {
                         broadcastIntentInPackage("android", SYSTEM_UID, intent, null, null, 0,
-                                null, null, null, null, false, false, resolvedUserId);
+                                null, null, null, null, false, false, resolvedUserId, false);
                     }
 
                     if (observer != null) {
@@ -4373,6 +4434,7 @@
         mProcessList.removeProcessLocked(app, false, true, "timeout publishing content providers");
     }
 
+    @GuardedBy("this")
     private final void processStartTimedOutLocked(ProcessRecord app) {
         final int pid = app.pid;
         boolean gone = mPidsSelfLocked.removeIfNoThread(pid);
@@ -4393,7 +4455,8 @@
                 mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
             }
             removeLruProcessLocked(app);
-            if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
+            final BackupRecord backupTarget = mBackupTargets.get(app.userId);
+            if (backupTarget != null && backupTarget.app.pid == pid) {
                 Slog.w(TAG, "Unattached app died before backup, skipping");
                 mHandler.post(new Runnable() {
                 @Override
@@ -4401,7 +4464,7 @@
                         try {
                             IBackupManager bm = IBackupManager.Stub.asInterface(
                                     ServiceManager.getService(Context.BACKUP_SERVICE));
-                            bm.agentDisconnected(app.info.packageName);
+                            bm.agentDisconnectedForUser(app.userId, app.info.packageName);
                         } catch (RemoteException e) {
                             // Can't happen; the backup manager is local
                         }
@@ -4524,6 +4587,7 @@
         if (DEBUG_ALL) Slog.v(
             TAG, "New app record " + app
             + " thread=" + thread.asBinder() + " pid=" + pid);
+        final BackupRecord backupTarget = mBackupTargets.get(app.userId);
         try {
             int testMode = ApplicationThreadConstants.DEBUG_OFF;
             if (mDebugApp != null && mDebugApp.equals(processName)) {
@@ -4545,11 +4609,11 @@
 
             // If the app is being launched for restore or full backup, set it up specially
             boolean isRestrictedBackupMode = false;
-            if (mBackupTarget != null && mBackupAppName.equals(processName)) {
-                isRestrictedBackupMode = mBackupTarget.appInfo.uid >= FIRST_APPLICATION_UID
-                        && ((mBackupTarget.backupMode == BackupRecord.RESTORE)
-                                || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
-                                || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
+            if (backupTarget != null && backupTarget.appInfo.packageName.equals(processName)) {
+                isRestrictedBackupMode = backupTarget.appInfo.uid >= FIRST_APPLICATION_UID
+                        && ((backupTarget.backupMode == BackupRecord.RESTORE)
+                                || (backupTarget.backupMode == BackupRecord.RESTORE_FULL)
+                                || (backupTarget.backupMode == BackupRecord.BACKUP_FULL));
             }
 
             final ActiveInstrumentation instr = app.getActiveInstrumentation();
@@ -4757,15 +4821,15 @@
         }
 
         // Check whether the next backup agent is in this process...
-        if (!badApp && mBackupTarget != null && mBackupTarget.app == app) {
+        if (!badApp && backupTarget != null && backupTarget.app == app) {
             if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
                     "New app is backup target, launching agent for " + app);
-            notifyPackageUse(mBackupTarget.appInfo.packageName,
+            notifyPackageUse(backupTarget.appInfo.packageName,
                              PackageManager.NOTIFY_PACKAGE_USE_BACKUP);
             try {
-                thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
-                        compatibilityInfoForPackage(mBackupTarget.appInfo),
-                        mBackupTarget.backupMode);
+                thread.scheduleCreateBackupAgent(backupTarget.appInfo,
+                        compatibilityInfoForPackage(backupTarget.appInfo),
+                        backupTarget.backupMode);
             } catch (Exception e) {
                 Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);
                 badApp = true;
@@ -4818,7 +4882,7 @@
 
         ArraySet<String> completedIsas = new ArraySet<String>();
         for (String abi : Build.SUPPORTED_ABIS) {
-            zygoteProcess.establishZygoteConnectionForAbi(abi);
+            ZYGOTE_PROCESS.establishZygoteConnectionForAbi(abi);
             final String instructionSet = VMRuntime.getInstructionSet(abi);
             if (!completedIsas.contains(instructionSet)) {
                 try {
@@ -5310,18 +5374,9 @@
         }
     }
 
-    @Override
-    public boolean isAppForeground(int uid) {
-        int callerUid = Binder.getCallingUid();
-        if (UserHandle.isCore(callerUid) || callerUid == uid) {
-            return isAppForegroundInternal(uid);
-        }
-        return false;
-    }
-
-    private boolean isAppForegroundInternal(int uid) {
+    private boolean isAppForeground(int uid) {
         synchronized (this) {
-            UidRecord uidRec = mActiveUids.get(uid);
+            UidRecord uidRec = mProcessList.mActiveUids.get(uid);
             if (uidRec == null || uidRec.idle) {
                 return false;
             }
@@ -5333,15 +5388,10 @@
     // be guarded by permission checking.
     int getUidState(int uid) {
         synchronized (this) {
-            return getUidStateLocked(uid);
+            return mProcessList.getUidProcStateLocked(uid);
         }
     }
 
-    int getUidStateLocked(int uid) {
-        UidRecord uidRec = mActiveUids.get(uid);
-        return uidRec == null ? PROCESS_STATE_NONEXISTENT : uidRec.getCurProcState();
-    }
-
     // =========================================================
     // PROCESS INFO
     // =========================================================
@@ -5633,7 +5683,7 @@
 
     int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
             int callingPid, boolean alwaysRestrict, boolean disabledOnly, boolean forcedStandby) {
-        UidRecord uidRec = mActiveUids.get(uid);
+        UidRecord uidRec = mProcessList.getUidRecordLocked(uid);
         if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg="
                 + packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle="
                 + (uidRec != null ? uidRec.idle : false));
@@ -7396,7 +7446,7 @@
         }
 
         if (app == null) {
-            app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0);
+            app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0, false);
             mProcessList.updateLruProcessLocked(app, false, null);
             updateOomAdjLocked();
         }
@@ -7854,8 +7904,7 @@
         }
 
         synchronized (this) {
-            UidRecord uidRec = mActiveUids.get(uid);
-            return uidRec != null ? uidRec.getCurProcState() : PROCESS_STATE_NONEXISTENT;
+            return mProcessList.getUidProcStateLocked(uid);
         }
     }
 
@@ -7891,7 +7940,7 @@
     }
 
     boolean isUidActiveLocked(int uid) {
-        final UidRecord uidRecord = mActiveUids.get(uid);
+        final UidRecord uidRecord = mProcessList.getUidRecordLocked(uid);
         return uidRecord != null && !uidRecord.setIdle;
     }
 
@@ -8683,7 +8732,7 @@
 
                 if (mForceBackgroundCheck) {
                     // Stop background services for idle UIDs.
-                    doStopUidForIdleUidsLocked();
+                    mProcessList.doStopUidForIdleUidsLocked();
                 }
             }
         }
@@ -9532,7 +9581,8 @@
                     proto.end(broadcastToken);
 
                     long serviceToken = proto.start(ActivityManagerServiceProto.SERVICES);
-                    mServices.writeToProto(proto, ActivityManagerServiceDumpServicesProto.ACTIVE_SERVICES);
+                    mServices.writeToProto(proto,
+                            ActivityManagerServiceDumpServicesProto.ACTIVE_SERVICES);
                     proto.end(serviceToken);
 
                     long processToken = proto.start(ActivityManagerServiceProto.PROCESSES);
@@ -10084,11 +10134,13 @@
             }
         }
 
-        if (mActiveUids.size() > 0) {
-            if (dumpUids(pw, dumpPackage, dumpAppId, mActiveUids, "UID states:", needSep)) {
+        if (mProcessList.mActiveUids.size() > 0) {
+            if (dumpUids(pw, dumpPackage, dumpAppId, mProcessList.mActiveUids,
+                    "UID states:", needSep)) {
                 needSep = true;
             }
         }
+
         if (dumpAll) {
             if (mValidateUids.size() > 0) {
                 if (dumpUids(pw, dumpPackage, dumpAppId, mValidateUids, "UID validation:",
@@ -10351,12 +10403,8 @@
                 pw.print("  mLastPowerCheckUptime=");
                         TimeUtils.formatDuration(mLastPowerCheckUptime, pw);
                         pw.println("");
-                pw.println("  mAdjSeq=" + mAdjSeq + " mLruSeq=" + mProcessList.mLruSeq);
-                pw.println("  mNumNonCachedProcs=" + mNumNonCachedProcs
-                        + " (" + mProcessList.getLruSizeLocked() + " total)"
-                        + " mNumCachedHiddenProcs=" + mNumCachedHiddenProcs
-                        + " mNumServiceProcs=" + mNumServiceProcs
-                        + " mNewNumServiceProcs=" + mNewNumServiceProcs);
+                mOomAdjuster.dumpSequenceNumbersLocked(pw);
+                mOomAdjuster.dumpProcCountsLocked(pw);
                 pw.println("  mAllowLowerMemLevel=" + mAllowLowerMemLevel
                         + " mLastMemoryLevel=" + mLastMemoryLevel
                         + " mLastNumProcesses=" + mLastNumProcesses);
@@ -10408,7 +10456,8 @@
                 if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
                     continue;
                 }
-                r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PROCS, mProcessList.mLruProcesses.indexOf(r)
+                r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PROCS,
+                        mProcessList.mLruProcesses.indexOf(r)
                 );
                 if (r.isPersistent()) {
                     numPers++;
@@ -10432,19 +10481,20 @@
                     && !ai.mTargetInfo.packageName.equals(dumpPackage)) {
                 continue;
             }
-            ai.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ACTIVE_INSTRUMENTATIONS);
+            ai.writeToProto(proto,
+                    ActivityManagerServiceDumpProcessesProto.ACTIVE_INSTRUMENTATIONS);
         }
 
         int whichAppId = getAppId(dumpPackage);
-        for (int i=0; i<mActiveUids.size(); i++) {
-            UidRecord uidRec = mActiveUids.valueAt(i);
+        for (int i = 0; i < mProcessList.mActiveUids.size(); i++) {
+            UidRecord uidRec = mProcessList.mActiveUids.valueAt(i);
             if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
                 continue;
             }
             uidRec.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ACTIVE_UIDS);
         }
 
-        for (int i=0; i<mValidateUids.size(); i++) {
+        for (int i = 0; i < mValidateUids.size(); i++) {
             UidRecord uidRec = mValidateUids.valueAt(i);
             if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
                 continue;
@@ -10519,12 +10569,15 @@
             r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ON_HOLD_PROCS);
         }
 
-        writeProcessesToGcToProto(proto, ActivityManagerServiceDumpProcessesProto.GC_PROCS, dumpPackage);
-        mAppErrors.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.APP_ERRORS, dumpPackage);
+        writeProcessesToGcToProto(proto, ActivityManagerServiceDumpProcessesProto.GC_PROCS,
+                dumpPackage);
+        mAppErrors.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.APP_ERRORS,
+                dumpPackage);
         mAtmInternal.writeProcessesToProto(proto, dumpPackage, mWakefulness, mTestPssMode);
 
         if (dumpPackage == null) {
-            mUserController.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.USER_CONTROLLER);
+            mUserController.writeToProto(proto,
+            ActivityManagerServiceDumpProcessesProto.USER_CONTROLLER);
         }
 
         final int NI = mUidObservers.getRegisteredCallbackCount();
@@ -10636,11 +10689,7 @@
             proto.write(ActivityManagerServiceDumpProcessesProto.CALL_FINISH_BOOTING, mCallFinishBooting);
             proto.write(ActivityManagerServiceDumpProcessesProto.BOOT_ANIMATION_COMPLETE, mBootAnimationComplete);
             proto.write(ActivityManagerServiceDumpProcessesProto.LAST_POWER_CHECK_UPTIME_MS, mLastPowerCheckUptime);
-            proto.write(ActivityManagerServiceDumpProcessesProto.ADJ_SEQ, mAdjSeq);
-            proto.write(ActivityManagerServiceDumpProcessesProto.LRU_SEQ, mProcessList.mLruSeq);
-            proto.write(ActivityManagerServiceDumpProcessesProto.NUM_NON_CACHED_PROCS, mNumNonCachedProcs);
-            proto.write(ActivityManagerServiceDumpProcessesProto.NUM_SERVICE_PROCS, mNumServiceProcs);
-            proto.write(ActivityManagerServiceDumpProcessesProto.NEW_NUM_SERVICE_PROCS, mNewNumServiceProcs);
+            mOomAdjuster.dumpProcessListVariablesLocked(proto);
             proto.write(ActivityManagerServiceDumpProcessesProto.ALLOW_LOWER_MEM_LEVEL, mAllowLowerMemLevel);
             proto.write(ActivityManagerServiceDumpProcessesProto.LAST_MEMORY_LEVEL, mLastMemoryLevel);
             proto.write(ActivityManagerServiceDumpProcessesProto.LAST_NUM_PROCESSES, mLastNumProcesses);
@@ -10648,7 +10697,6 @@
             ProtoUtils.toDuration(proto, ActivityManagerServiceDumpProcessesProto.LAST_IDLE_TIME, mLastIdleTime, now);
             proto.write(ActivityManagerServiceDumpProcessesProto.LOW_RAM_SINCE_LAST_IDLE_MS, getLowRamTimeSinceIdle(now));
         }
-
     }
 
     void writeProcessesToGcToProto(ProtoOutputStream proto, long fieldId, String dumpPackage) {
@@ -10930,14 +10978,14 @@
     void dumpAllowedAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage) {
         boolean needSep = false;
-        boolean printedAnything = false;
 
         pw.println("ACTIVITY MANAGER ALLOWED ASSOCIATION STATE (dumpsys activity allowed-associations)");
         boolean printed = false;
         if (mAllowedAssociations != null) {
             for (int i = 0; i < mAllowedAssociations.size(); i++) {
                 final String pkg = mAllowedAssociations.keyAt(i);
-                final ArraySet<String> asc = mAllowedAssociations.valueAt(i);
+                final ArraySet<String> asc =
+                        mAllowedAssociations.valueAt(i).getAllowedPackageAssociations();
                 boolean printedHeader = false;
                 for (int j = 0; j < asc.size(); j++) {
                     if (dumpPackage == null || pkg.equals(dumpPackage)
@@ -10946,7 +10994,6 @@
                             pw.println("  Allowed associations (by restricted package):");
                             printed = true;
                             needSep = true;
-                            printedAnything = true;
                         }
                         if (!printedHeader) {
                             pw.print("  * ");
@@ -10958,6 +11005,9 @@
                         pw.println(asc.valueAt(j));
                     }
                 }
+                if (mAllowedAssociations.valueAt(i).isDebuggable()) {
+                    pw.println("      (debuggable)");
+                }
             }
         }
         if (!printed) {
@@ -13247,16 +13297,17 @@
         app.receivers.clear();
 
         // If the app is undergoing backup, tell the backup manager about it
-        if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
+        final BackupRecord backupTarget = mBackupTargets.get(app.userId);
+        if (backupTarget != null && app.pid == backupTarget.app.pid) {
             if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App "
-                    + mBackupTarget.appInfo + " died during backup");
+                    + backupTarget.appInfo + " died during backup");
             mHandler.post(new Runnable() {
                 @Override
                 public void run(){
                     try {
                         IBackupManager bm = IBackupManager.Stub.asInterface(
                                 ServiceManager.getService(Context.BACKUP_SERVICE));
-                        bm.agentDisconnected(app.info.packageName);
+                        bm.agentDisconnectedForUser(app.userId, app.info.packageName);
                     } catch (RemoteException e) {
                         // can't happen; backup manager is local
                     }
@@ -13596,7 +13647,11 @@
     // instantiated.  The backup agent will invoke backupAgentCreated() on the
     // activity manager to announce its creation.
     public boolean bindBackupAgent(String packageName, int backupMode, int userId) {
-        if (DEBUG_BACKUP) Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode);
+        if (DEBUG_BACKUP) {
+            Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode="
+                    + backupMode + " userId=" + userId + " callingUid = " + Binder.getCallingUid()
+                    + " uid = " + Process.myUid());
+        }
         enforceCallingPermission("android.permission.CONFIRM_FULL_BACKUP", "bindBackupAgent");
 
         IPackageManager pm = AppGlobals.getPackageManager();
@@ -13648,10 +13703,10 @@
                 proc.inFullBackup = true;
             }
             r.app = proc;
-            oldBackupUid = mBackupTarget != null ? mBackupTarget.appInfo.uid : -1;
+            final BackupRecord backupTarget = mBackupTargets.get(userId);
+            oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1;
             newBackupUid = proc.inFullBackup ? r.appInfo.uid : -1;
-            mBackupTarget = r;
-            mBackupAppName = app.packageName;
+            mBackupTargets.put(userId, r);
 
             // Try not to kill the process during backup
             updateOomAdjLocked(proc, true);
@@ -13686,14 +13741,14 @@
         return true;
     }
 
-    @Override
-    public void clearPendingBackup() {
-        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "clearPendingBackup");
-        enforceCallingPermission("android.permission.BACKUP", "clearPendingBackup");
+    private void clearPendingBackup(int userId) {
+        if (DEBUG_BACKUP) {
+            Slog.v(TAG_BACKUP, "clearPendingBackup: userId = " + userId + " callingUid = "
+                    + Binder.getCallingUid() + " uid = " + Process.myUid());
+        }
 
         synchronized (this) {
-            mBackupTarget = null;
-            mBackupAppName = null;
+            mBackupTargets.delete(userId);
         }
 
         JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
@@ -13701,12 +13756,19 @@
     }
 
     // A backup agent has just come up
+    @Override
     public void backupAgentCreated(String agentPackageName, IBinder agent) {
-        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName
-                + " = " + agent);
+        final int callingUserId = UserHandle.getCallingUserId();
+        if (DEBUG_BACKUP) {
+            Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName + " = " + agent
+                    + " callingUserId = " + callingUserId + " callingUid = "
+                    + Binder.getCallingUid() + " uid = " + Process.myUid());
+        }
 
         synchronized(this) {
-            if (!agentPackageName.equals(mBackupAppName)) {
+            final BackupRecord backupTarget = mBackupTargets.get(callingUserId);
+            String backupAppName = backupTarget == null ? null : backupTarget.appInfo.packageName;
+            if (!agentPackageName.equals(backupAppName)) {
                 Slog.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
                 return;
             }
@@ -13716,7 +13778,7 @@
         try {
             IBackupManager bm = IBackupManager.Stub.asInterface(
                     ServiceManager.getService(Context.BACKUP_SERVICE));
-            bm.agentConnected(agentPackageName, agent);
+            bm.agentConnectedForUser(callingUserId, agentPackageName, agent);
         } catch (RemoteException e) {
             // can't happen; the backup manager service is local
         } catch (Exception e) {
@@ -13729,7 +13791,12 @@
 
     // done with this agent
     public void unbindBackupAgent(ApplicationInfo appInfo) {
-        if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "unbindBackupAgent: " + appInfo);
+        if (DEBUG_BACKUP) {
+            Slog.v(TAG_BACKUP, "unbindBackupAgent: " + appInfo + " appInfo.uid = "
+                    + appInfo.uid + " callingUid = " + Binder.getCallingUid() + " uid = "
+                    + Process.myUid());
+        }
+
         enforceCallingPermission("android.permission.CONFIRM_FULL_BACKUP", "unbindBackupAgent");
         if (appInfo == null) {
             Slog.w(TAG, "unbind backup agent for null app");
@@ -13738,24 +13805,27 @@
 
         int oldBackupUid;
 
+        final int userId = UserHandle.getUserId(appInfo.uid);
         synchronized(this) {
+            final BackupRecord backupTarget = mBackupTargets.get(userId);
+            String backupAppName = backupTarget == null ? null : backupTarget.appInfo.packageName;
             try {
-                if (mBackupAppName == null) {
+                if (backupAppName == null) {
                     Slog.w(TAG, "Unbinding backup agent with no active backup");
                     return;
                 }
 
-                if (!mBackupAppName.equals(appInfo.packageName)) {
+                if (!backupAppName.equals(appInfo.packageName)) {
                     Slog.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
                     return;
                 }
 
                 // Not backing this app up any more; reset its OOM adjustment
-                final ProcessRecord proc = mBackupTarget.app;
+                final ProcessRecord proc = backupTarget.app;
                 updateOomAdjLocked(proc, true);
                 proc.inFullBackup = false;
 
-                oldBackupUid = mBackupTarget != null ? mBackupTarget.appInfo.uid : -1;
+                oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1;
 
                 // If the app crashed during backup, 'thread' will be null here
                 if (proc.thread != null) {
@@ -13768,8 +13838,7 @@
                     }
                 }
             } finally {
-                mBackupTarget = null;
-                mBackupAppName = null;
+                mBackupTargets.delete(userId);
             }
         }
 
@@ -13996,7 +14065,7 @@
                     BroadcastQueue queue = broadcastQueueForIntent(intent);
                     BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                             null, -1, -1, false, null, null, OP_NONE, null, receivers,
-                            null, 0, null, null, false, true, true, -1);
+                            null, 0, null, null, false, true, true, -1, false);
                     queue.enqueueParallelBroadcastLocked(r);
                     queue.scheduleBroadcastsLocked();
                 }
@@ -14235,6 +14304,18 @@
             IIntentReceiver resultTo, int resultCode, String resultData,
             Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
             boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
+        return broadcastIntentLocked(callerApp, callerPackage, intent, resolvedType, resultTo,
+            resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions, ordered,
+            sticky, callingPid, callingUid, userId, false /* allowBackgroundActivityStarts */);
+    }
+
+    @GuardedBy("this")
+    final int broadcastIntentLocked(ProcessRecord callerApp,
+            String callerPackage, Intent intent, String resolvedType,
+            IIntentReceiver resultTo, int resultCode, String resultData,
+            Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
+            boolean ordered, boolean sticky, int callingPid, int callingUid, int userId,
+            boolean allowBackgroundActivityStarts) {
         intent = new Intent(intent);
 
         final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
@@ -14321,6 +14402,7 @@
             case BLUETOOTH_UID:
             case NFC_UID:
             case SE_UID:
+            case NETWORK_STACK_UID:
                 isCallerSystem = true;
                 break;
             default:
@@ -14507,6 +14589,7 @@
                                     + " ssp=" + ssp + " data=" + data);
                             return ActivityManager.BROADCAST_SUCCESS;
                         }
+                        updateAssociationForApp(aInfo);
                         mAtmInternal.onPackageReplaced(aInfo);
                         mServices.updateServiceApplicationInfoLocked(aInfo);
                         sendPackageBroadcastLocked(ApplicationThreadConstants.PACKAGE_REPLACED,
@@ -14601,7 +14684,7 @@
                     Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
                 final int uid = getUidFromIntent(intent);
                 if (uid != -1) {
-                    final UidRecord uidRec = mActiveUids.get(uid);
+                    final UidRecord uidRec = mProcessList.getUidRecordLocked(uid);
                     if (uidRec != null) {
                         uidRec.updateHasInternetPermission();
                     }
@@ -14735,7 +14818,8 @@
             BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                     callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                     requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
-                    resultCode, resultData, resultExtras, ordered, sticky, false, userId);
+                    resultCode, resultData, resultExtras, ordered, sticky, false, userId,
+                    allowBackgroundActivityStarts);
             if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
             final boolean replaced = replacePending
                     && (queue.replaceParallelBroadcastLocked(r) != null);
@@ -14831,7 +14915,8 @@
             BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                     callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                     requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
-                    resultData, resultExtras, ordered, sticky, false, userId);
+                    resultData, resultExtras, ordered, sticky, false, userId,
+                    allowBackgroundActivityStarts);
 
             if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
                     + ": prev had " + queue.mOrderedBroadcasts.size());
@@ -14978,7 +15063,7 @@
             Intent intent, String resolvedType, IIntentReceiver resultTo,
             int resultCode, String resultData, Bundle resultExtras,
             String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
-            int userId) {
+            int userId, boolean allowBackgroundActivityStarts) {
         synchronized(this) {
             intent = verifyBroadcastLocked(intent);
 
@@ -14988,7 +15073,7 @@
             int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
                     resultTo, resultCode, resultData, resultExtras,
                     requiredPermissions, OP_NONE, bOptions, serialized,
-                    sticky, -1, uid, userId);
+                    sticky, -1, uid, userId, allowBackgroundActivityStarts);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
@@ -15377,7 +15462,7 @@
     // Returns whether the app is receiving broadcast.
     // If receiving, fetch all broadcast queues which the app is
     // the current [or imminent] receiver on.
-    private boolean isReceivingBroadcastLocked(ProcessRecord app,
+    boolean isReceivingBroadcastLocked(ProcessRecord app,
             ArraySet<BroadcastQueue> receivingQueues) {
         final int N = app.curReceivers.size();
         if (N > 0) {
@@ -15497,1087 +15582,6 @@
         }
     }
 
-    private final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback =
-            new ComputeOomAdjWindowCallback();
-
-    /** These methods are called inline during computeOomAdjLocked(), on the same thread */
-    private final class ComputeOomAdjWindowCallback
-            implements WindowProcessController.ComputeOomAdjCallback {
-
-        ProcessRecord app;
-        int adj;
-        boolean foregroundActivities;
-        int procState;
-        int schedGroup;
-        int appUid;
-        int logUid;
-        int processStateCurTop;
-
-        void initialize(ProcessRecord app, int adj, boolean foregroundActivities,
-                int procState, int schedGroup, int appUid, int logUid, int processStateCurTop) {
-            this.app = app;
-            this.adj = adj;
-            this.foregroundActivities = foregroundActivities;
-            this.procState = procState;
-            this.schedGroup = schedGroup;
-            this.appUid = appUid;
-            this.logUid = logUid;
-            this.processStateCurTop = processStateCurTop;
-        }
-
-        @Override
-        public void onVisibleActivity() {
-            // App has a visible activity; only upgrade adjustment.
-            if (adj > ProcessList.VISIBLE_APP_ADJ) {
-                adj = ProcessList.VISIBLE_APP_ADJ;
-                app.adjType = "vis-activity";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to vis-activity: " + app);
-                }
-            }
-            if (procState > processStateCurTop) {
-                procState = processStateCurTop;
-                app.adjType = "vis-activity";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                            "Raise procstate to vis-activity (top): " + app);
-                }
-            }
-            if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
-                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-            }
-            app.cached = false;
-            app.empty = false;
-            foregroundActivities = true;
-        }
-
-        @Override
-        public void onPausedActivity() {
-            if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
-                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                app.adjType = "pause-activity";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to pause-activity: "  + app);
-                }
-            }
-            if (procState > processStateCurTop) {
-                procState = processStateCurTop;
-                app.adjType = "pause-activity";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                            "Raise procstate to pause-activity (top): "  + app);
-                }
-            }
-            if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
-                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-            }
-            app.cached = false;
-            app.empty = false;
-            foregroundActivities = true;
-        }
-
-        @Override
-        public void onStoppingActivity(boolean finishing) {
-            if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
-                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                app.adjType = "stop-activity";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                            "Raise adj to stop-activity: "  + app);
-                }
-            }
-
-            // For the process state, we will at this point consider the process to be cached. It
-            // will be cached either as an activity or empty depending on whether the activity is
-            // finishing. We do this so that we can treat the process as cached for purposes of
-            // memory trimming (determining current memory level, trim command to send to process)
-            // since there can be an arbitrary number of stopping processes and they should soon all
-            // go into the cached state.
-            if (!finishing) {
-                if (procState > PROCESS_STATE_LAST_ACTIVITY) {
-                    procState = PROCESS_STATE_LAST_ACTIVITY;
-                    app.adjType = "stop-activity";
-                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                                "Raise procstate to stop-activity: " + app);
-                    }
-                }
-            }
-            app.cached = false;
-            app.empty = false;
-            foregroundActivities = true;
-        }
-
-        @Override
-        public void onOtherActivity() {
-            if (procState > PROCESS_STATE_CACHED_ACTIVITY) {
-                procState = PROCESS_STATE_CACHED_ACTIVITY;
-                app.adjType = "cch-act";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                            "Raise procstate to cached activity: " + app);
-                }
-            }
-        }
-    }
-
-    private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
-            boolean doingAll, long now, boolean cycleReEval) {
-        if (mAdjSeq == app.adjSeq) {
-            if (app.adjSeq == app.completedAdjSeq) {
-                // This adjustment has already been computed successfully.
-                return false;
-            } else {
-                // The process is being computed, so there is a cycle. We cannot
-                // rely on this process's state.
-                app.containsCycle = true;
-
-                return false;
-            }
-        }
-
-        if (app.thread == null) {
-            app.adjSeq = mAdjSeq;
-            app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_BACKGROUND);
-            app.setCurProcState(ActivityManager.PROCESS_STATE_CACHED_EMPTY);
-            app.curAdj = ProcessList.CACHED_APP_MAX_ADJ;
-            app.setCurRawAdj(ProcessList.CACHED_APP_MAX_ADJ);
-            app.completedAdjSeq = app.adjSeq;
-            return false;
-        }
-
-        app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
-        app.adjSource = null;
-        app.adjTarget = null;
-        app.empty = false;
-        app.cached = false;
-
-        final WindowProcessController wpc = app.getWindowProcessController();
-        final int appUid = app.info.uid;
-        final int logUid = mCurOomAdjUid;
-
-        int prevAppAdj = app.curAdj;
-        int prevProcState = app.getCurProcState();
-
-        if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
-            // The max adjustment doesn't allow this app to be anything
-            // below foreground, so it is not worth doing work for it.
-            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making fixed: " + app);
-            }
-            app.adjType = "fixed";
-            app.adjSeq = mAdjSeq;
-            app.setCurRawAdj(app.maxAdj);
-            app.setHasForegroundActivities(false);
-            app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
-            app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT);
-            // System processes can do UI, and when they do we want to have
-            // them trim their memory after the user leaves the UI.  To
-            // facilitate this, here we need to determine whether or not it
-            // is currently showing UI.
-            app.systemNoUi = true;
-            if (app == TOP_APP) {
-                app.systemNoUi = false;
-                app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
-                app.adjType = "pers-top-activity";
-            } else if (app.hasTopUi()) {
-                // sched group/proc state adjustment is below
-                app.systemNoUi = false;
-                app.adjType = "pers-top-ui";
-            } else if (wpc.hasVisibleActivities()) {
-                app.systemNoUi = false;
-            }
-            if (!app.systemNoUi) {
-                if (mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
-                    // screen on, promote UI
-                    app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
-                    app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
-                } else {
-                    // screen off, restrict UI scheduling
-                    app.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
-                    app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
-                }
-            }
-            app.setCurRawProcState(app.getCurProcState());
-            app.curAdj = app.maxAdj;
-            app.completedAdjSeq = app.adjSeq;
-            // if curAdj is less than prevAppAdj, then this process was promoted
-            return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
-        }
-
-        app.systemNoUi = false;
-
-        final int PROCESS_STATE_CUR_TOP = mAtmInternal.getTopProcessState();
-
-        // Determine the importance of the process, starting with most
-        // important to least, and assign an appropriate OOM adjustment.
-        int adj;
-        int schedGroup;
-        int procState;
-        int cachedAdjSeq;
-
-        boolean foregroundActivities = false;
-        mTmpBroadcastQueue.clear();
-        if (PROCESS_STATE_CUR_TOP == ActivityManager.PROCESS_STATE_TOP && app == TOP_APP) {
-            // The last app on the list is the foreground app.
-            adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
-            app.adjType = "top-activity";
-            foregroundActivities = true;
-            procState = PROCESS_STATE_CUR_TOP;
-            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app);
-            }
-        } else if (app.runningRemoteAnimation) {
-            adj = ProcessList.VISIBLE_APP_ADJ;
-            schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
-            app.adjType = "running-remote-anim";
-            procState = PROCESS_STATE_CUR_TOP;
-            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making running remote anim: " + app);
-            }
-        } else if (app.getActiveInstrumentation() != null) {
-            // Don't want to kill running instrumentation.
-            adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-            app.adjType = "instrumentation";
-            procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
-            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making instrumentation: " + app);
-            }
-        } else if (isReceivingBroadcastLocked(app, mTmpBroadcastQueue)) {
-            // An app that is currently receiving a broadcast also
-            // counts as being in the foreground for OOM killer purposes.
-            // It's placed in a sched group based on the nature of the
-            // broadcast as reflected by which queue it's active in.
-            adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = (mTmpBroadcastQueue.contains(mFgBroadcastQueue))
-                    ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
-            app.adjType = "broadcast";
-            procState = ActivityManager.PROCESS_STATE_RECEIVER;
-            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making broadcast: " + app);
-            }
-        } else if (app.executingServices.size() > 0) {
-            // An app that is currently executing a service callback also
-            // counts as being in the foreground.
-            adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = app.execServicesFg ?
-                    ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
-            app.adjType = "exec-service";
-            procState = ActivityManager.PROCESS_STATE_SERVICE;
-            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making exec-service: " + app);
-            }
-            //Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
-        } else if (app == TOP_APP) {
-            adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
-            app.adjType = "top-sleeping";
-            foregroundActivities = true;
-            procState = PROCESS_STATE_CUR_TOP;
-            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top (sleeping): " + app);
-            }
-        } else {
-            // As far as we know the process is empty.  We may change our mind later.
-            schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
-            // At this point we don't actually know the adjustment.  Use the cached adj
-            // value that the caller wants us to.
-            adj = cachedAdj;
-            procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
-            app.cached = true;
-            app.empty = true;
-            app.adjType = "cch-empty";
-            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making empty: " + app);
-            }
-        }
-
-        // Examine all activities if not already foreground.
-        if (!foregroundActivities && wpc.hasActivities()) {
-            mTmpComputeOomAdjWindowCallback.initialize(app, adj, foregroundActivities, procState,
-                    schedGroup, appUid, logUid, PROCESS_STATE_CUR_TOP);
-            final int minLayer = wpc.computeOomAdjFromActivities(
-                    ProcessList.VISIBLE_APP_LAYER_MAX, mTmpComputeOomAdjWindowCallback);
-
-            adj = mTmpComputeOomAdjWindowCallback.adj;
-            foregroundActivities = mTmpComputeOomAdjWindowCallback.foregroundActivities;
-            procState = mTmpComputeOomAdjWindowCallback.procState;
-            schedGroup = mTmpComputeOomAdjWindowCallback.schedGroup;
-
-            if (adj == ProcessList.VISIBLE_APP_ADJ) {
-                adj += minLayer;
-            }
-        }
-
-        if (procState > ActivityManager.PROCESS_STATE_CACHED_RECENT && app.hasRecentTasks()) {
-            procState = ActivityManager.PROCESS_STATE_CACHED_RECENT;
-            app.adjType = "cch-rec";
-            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to cached recent: " + app);
-            }
-        }
-
-        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
-                || procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
-            if (app.hasForegroundServices()) {
-                // The user is aware of this app, so make it visible.
-                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
-                app.cached = false;
-                app.adjType = "fg-service";
-                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to fg service: " + app);
-                }
-            } else if (app.hasOverlayUi()) {
-                // The process is display an overlay UI.
-                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
-                app.cached = false;
-                app.adjType = "has-overlay-ui";
-                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to overlay ui: " + app);
-                }
-            }
-        }
-
-        // 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) {
-                // This is currently used for toasts...  they are not interactive, and
-                // we don't want them to cause the app to become fully foreground (and
-                // thus out of background check), so we yes the best background level we can.
-                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
-                app.cached = false;
-                app.adjType = "force-imp";
-                app.adjSource = app.forcingToImportant;
-                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to force imp: " + app);
-                }
-            }
-        }
-
-        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;
-                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
-                app.cached = false;
-                app.adjType = "heavy";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to heavy: " + app);
-                }
-            }
-            if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
-                procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
-                app.adjType = "heavy";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to heavy: " + app);
-                }
-            }
-        }
-
-        if (wpc.isHomeProcess()) {
-            if (adj > ProcessList.HOME_APP_ADJ) {
-                // This process is hosting what we currently consider to be the
-                // home app, so we don't want to let it go into the background.
-                adj = ProcessList.HOME_APP_ADJ;
-                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
-                app.cached = false;
-                app.adjType = "home";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to home: " + app);
-                }
-            }
-            if (procState > ActivityManager.PROCESS_STATE_HOME) {
-                procState = ActivityManager.PROCESS_STATE_HOME;
-                app.adjType = "home";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to home: " + app);
-                }
-            }
-        }
-
-        if (wpc.isPreviousProcess() && app.hasActivities()) {
-            if (adj > ProcessList.PREVIOUS_APP_ADJ) {
-                // This was the previous process that showed UI to the user.
-                // We want to try to keep it around more aggressively, to give
-                // a good experience around switching between two apps.
-                adj = ProcessList.PREVIOUS_APP_ADJ;
-                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
-                app.cached = false;
-                app.adjType = "previous";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to prev: " + app);
-                }
-            }
-            if (procState > PROCESS_STATE_LAST_ACTIVITY) {
-                procState = PROCESS_STATE_LAST_ACTIVITY;
-                app.adjType = "previous";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to prev: " + app);
-                }
-            }
-        }
-
-        if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj
-                + " reason=" + app.adjType);
-
-        // By default, we use the computed adjustment.  It may be changed if
-        // there are applications dependent on our services or providers, but
-        // this gives us a baseline and makes sure we don't get into an
-        // infinite recursion. If we're re-evaluating due to cycles, use the previously computed
-        // values.
-        app.setCurRawAdj(!cycleReEval ? adj : Math.min(adj, app.getCurRawAdj()));
-        app.setCurRawProcState(!cycleReEval
-                ? procState
-                : Math.min(procState, app.getCurRawProcState()));
-
-        app.hasStartedServices = false;
-        app.adjSeq = mAdjSeq;
-
-        if (mBackupTarget != null && app == mBackupTarget.app) {
-            // If possible we want to avoid killing apps while they're being backed up
-            if (adj > ProcessList.BACKUP_APP_ADJ) {
-                if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
-                adj = ProcessList.BACKUP_APP_ADJ;
-                if (procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
-                    procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
-                }
-                app.adjType = "backup";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to backup: " + app);
-                }
-                app.cached = false;
-            }
-            if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
-                procState = ActivityManager.PROCESS_STATE_BACKUP;
-                app.adjType = "backup";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to backup: " + app);
-                }
-            }
-        }
-
-        boolean mayBeTop = false;
-        String mayBeTopType = null;
-        Object mayBeTopSource = null;
-        Object mayBeTopTarget = null;
-
-        for (int is = app.services.size()-1;
-                is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                        || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
-                        || procState > ActivityManager.PROCESS_STATE_TOP);
-                is--) {
-            ServiceRecord s = app.services.valueAt(is);
-            if (s.startRequested) {
-                app.hasStartedServices = true;
-                if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
-                    procState = ActivityManager.PROCESS_STATE_SERVICE;
-                    app.adjType = "started-services";
-                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                                "Raise procstate to started service: " + app);
-                    }
-                }
-                if (app.hasShownUi && !wpc.isHomeProcess()) {
-                    // If this process has shown some UI, let it immediately
-                    // go to the LRU list because it may be pretty heavy with
-                    // UI stuff.  We'll tag it with a label just to help
-                    // debug and understand what is going on.
-                    if (adj > ProcessList.SERVICE_ADJ) {
-                        app.adjType = "cch-started-ui-services";
-                    }
-                } else {
-                    if (now < (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
-                        // This service has seen some activity within
-                        // recent memory, so we will keep its process ahead
-                        // of the background processes.
-                        if (adj > ProcessList.SERVICE_ADJ) {
-                            adj = ProcessList.SERVICE_ADJ;
-                            app.adjType = "started-services";
-                            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                                reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                                        "Raise adj to started service: " + app);
-                            }
-                            app.cached = false;
-                        }
-                    }
-                    // If we have let the service slide into the background
-                    // state, still have some text describing what it is doing
-                    // even though the service no longer has an impact.
-                    if (adj > ProcessList.SERVICE_ADJ) {
-                        app.adjType = "cch-started-services";
-                    }
-                }
-            }
-
-            for (int conni = s.connections.size()-1;
-                    conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                            || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
-                            || procState > ActivityManager.PROCESS_STATE_TOP);
-                    conni--) {
-                ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
-                for (int i = 0;
-                        i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
-                                || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
-                                || procState > ActivityManager.PROCESS_STATE_TOP);
-                        i++) {
-                    // XXX should compute this based on the max of
-                    // all connected clients.
-                    ConnectionRecord cr = clist.get(i);
-                    if (cr.binding.client == app) {
-                        // Binding to oneself is not interesting.
-                        continue;
-                    }
-
-                    boolean trackedProcState = false;
-                    if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
-                        ProcessRecord client = cr.binding.client;
-                        computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now, cycleReEval);
-
-                        if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
-                            continue;
-                        }
-
-                        int clientAdj = client.getCurRawAdj();
-                        int clientProcState = client.getCurRawProcState();
-
-                        if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
-                            // If the other app is cached for any reason, for purposes here
-                            // we are going to consider it empty.  The specific cached state
-                            // doesn't propagate except under certain conditions.
-                            clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
-                        }
-                        String adjType = null;
-                        if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
-                            // Not doing bind OOM management, so treat
-                            // this guy more like a started service.
-                            if (app.hasShownUi && !wpc.isHomeProcess()) {
-                                // If this process has shown some UI, let it immediately
-                                // go to the LRU list because it may be pretty heavy with
-                                // UI stuff.  We'll tag it with a label just to help
-                                // debug and understand what is going on.
-                                if (adj > clientAdj) {
-                                    adjType = "cch-bound-ui-services";
-                                }
-                                app.cached = false;
-                                clientAdj = adj;
-                                clientProcState = procState;
-                            } else {
-                                if (now >= (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
-                                    // This service has not seen activity within
-                                    // recent memory, so allow it to drop to the
-                                    // LRU list if there is no other reason to keep
-                                    // it around.  We'll also tag it with a label just
-                                    // to help debug and undertand what is going on.
-                                    if (adj > clientAdj) {
-                                        adjType = "cch-bound-services";
-                                    }
-                                    clientAdj = adj;
-                                }
-                            }
-                        }
-                        if (adj > clientAdj) {
-                            // If this process has recently shown UI, and
-                            // the process that is binding to it is less
-                            // important than being visible, then we don't
-                            // care about the binding as much as we care
-                            // about letting this process get into the LRU
-                            // list to be killed and restarted if needed for
-                            // memory.
-                            if (app.hasShownUi && !wpc.isHomeProcess()
-                                    && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
-                                if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
-                                    adjType = "cch-bound-ui-services";
-                                }
-                            } else {
-                                int newAdj;
-                                if ((cr.flags&(Context.BIND_ABOVE_CLIENT
-                                        |Context.BIND_IMPORTANT)) != 0) {
-                                    if (clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
-                                        newAdj = clientAdj;
-                                    } else {
-                                        // make this service persistent
-                                        newAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
-                                        schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-                                        procState = ActivityManager.PROCESS_STATE_PERSISTENT;
-                                        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) {
-                                    newAdj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                                } else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
-                                    newAdj = clientAdj;
-                                } else {
-                                    if (adj > ProcessList.VISIBLE_APP_ADJ) {
-                                        newAdj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
-                                    } else {
-                                        newAdj = adj;
-                                    }
-                                }
-                                if (!client.cached) {
-                                    app.cached = false;
-                                }
-                                if (adj >  newAdj) {
-                                    adj = newAdj;
-                                    app.setCurRawAdj(adj);
-                                    adjType = "service";
-                                }
-                            }
-                        }
-                        if ((cr.flags & (Context.BIND_NOT_FOREGROUND
-                                | Context.BIND_IMPORTANT_BACKGROUND)) == 0) {
-                            // This will treat important bound services identically to
-                            // the top app, which may behave differently than generic
-                            // foreground work.
-                            final int curSchedGroup = client.getCurrentSchedulingGroup();
-                            if (curSchedGroup > schedGroup) {
-                                if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
-                                    schedGroup = curSchedGroup;
-                                } else {
-                                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-                                }
-                            }
-                            if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
-                                if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
-                                    // Special handling of clients who are in the top state.
-                                    // We *may* want to consider this process to be in the
-                                    // top state as well, but only if there is not another
-                                    // reason for it to be running.  Being on the top is a
-                                    // special state, meaning you are specifically running
-                                    // for the current top app.  If the process is already
-                                    // running in the background for some other reason, it
-                                    // is more important to continue considering it to be
-                                    // in the background state.
-                                    mayBeTop = true;
-                                    mayBeTopType = "service";
-                                    mayBeTopSource = cr.binding.client;
-                                    mayBeTopTarget = s.instanceName;
-                                    clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
-                                } else {
-                                    // Special handling for above-top states (persistent
-                                    // processes).  These should not bring the current process
-                                    // into the top state, since they are not on top.  Instead
-                                    // give them the best state after that.
-                                    if ((cr.flags&Context.BIND_FOREGROUND_SERVICE) != 0) {
-                                        clientProcState =
-                                                ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
-                                    } else if (mWakefulness
-                                                    == PowerManagerInternal.WAKEFULNESS_AWAKE &&
-                                            (cr.flags&Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
-                                                    != 0) {
-                                        clientProcState =
-                                                ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
-                                    } else {
-                                        clientProcState =
-                                                ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
-                                    }
-                                }
-                            }
-                        } else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
-                            if (clientProcState <
-                                    ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
-                                clientProcState =
-                                        ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
-                            }
-                        } else {
-                            if (clientProcState <
-                                    ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
-                                clientProcState =
-                                        ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
-                            }
-                        }
-                        if (!trackedProcState) {
-                            cr.trackProcState(clientProcState, mAdjSeq, now);
-                        }
-                        if (procState > clientProcState) {
-                            procState = clientProcState;
-                            app.setCurRawProcState(procState);
-                            if (adjType == null) {
-                                adjType = "service";
-                            }
-                        }
-                        if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
-                                && (cr.flags & Context.BIND_SHOWING_UI) != 0) {
-                            app.setPendingUiClean(true);
-                        }
-                        if (adjType != null) {
-                            app.adjType = adjType;
-                            app.adjTypeCode = ActivityManager.RunningAppProcessInfo
-                                    .REASON_SERVICE_IN_USE;
-                            app.adjSource = cr.binding.client;
-                            app.adjSourceProcState = clientProcState;
-                            app.adjTarget = s.instanceName;
-                            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
-                                        + ": " + app + ", due to " + cr.binding.client
-                                        + " adj=" + adj + " procState="
-                                        + ProcessList.makeProcStateString(procState));
-                            }
-                        }
-                    }
-                    if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
-                        app.treatLikeActivity = true;
-                    }
-                    final ActivityServiceConnectionsHolder a = cr.activity;
-                    if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
-                        if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ
-                                && a.isActivityVisible()) {
-                            adj = ProcessList.FOREGROUND_APP_ADJ;
-                            app.setCurRawAdj(adj);
-                            if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
-                                if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
-                                    schedGroup = ProcessList.SCHED_GROUP_TOP_APP_BOUND;
-                                } else {
-                                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-                                }
-                            }
-                            app.cached = false;
-                            app.adjType = "service";
-                            app.adjTypeCode = ActivityManager.RunningAppProcessInfo
-                                    .REASON_SERVICE_IN_USE;
-                            app.adjSource = a;
-                            app.adjSourceProcState = procState;
-                            app.adjTarget = s.instanceName;
-                            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                                reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                                        "Raise to service w/activity: " + app);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        for (int provi = app.pubProviders.size()-1;
-                provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                        || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
-                        || procState > ActivityManager.PROCESS_STATE_TOP);
-                provi--) {
-            ContentProviderRecord cpr = app.pubProviders.valueAt(provi);
-            for (int i = cpr.connections.size()-1;
-                    i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                            || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
-                            || procState > ActivityManager.PROCESS_STATE_TOP);
-                    i--) {
-                ContentProviderConnection conn = cpr.connections.get(i);
-                ProcessRecord client = conn.client;
-                if (client == app) {
-                    // Being our own client is not interesting.
-                    continue;
-                }
-                computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now, cycleReEval);
-
-                if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
-                    continue;
-                }
-
-                int clientAdj = client.getCurRawAdj();
-                int clientProcState = client.getCurRawProcState();
-
-                if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
-                    // If the other app is cached for any reason, for purposes here
-                    // we are going to consider it empty.
-                    clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
-                }
-                String adjType = null;
-                if (adj > clientAdj) {
-                    if (app.hasShownUi && !wpc.isHomeProcess()
-                            && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
-                        adjType = "cch-ui-provider";
-                    } else {
-                        adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
-                                ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
-                        app.setCurRawAdj(adj);
-                        adjType = "provider";
-                    }
-                    app.cached &= client.cached;
-                }
-                if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
-                    if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
-                        // Special handling of clients who are in the top state.
-                        // We *may* want to consider this process to be in the
-                        // top state as well, but only if there is not another
-                        // reason for it to be running.  Being on the top is a
-                        // special state, meaning you are specifically running
-                        // for the current top app.  If the process is already
-                        // running in the background for some other reason, it
-                        // is more important to continue considering it to be
-                        // in the background state.
-                        mayBeTop = true;
-                        clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
-                        mayBeTopType = adjType = "provider-top";
-                        mayBeTopSource = client;
-                        mayBeTopTarget = cpr.name;
-                    } else {
-                        // Special handling for above-top states (persistent
-                        // processes).  These should not bring the current process
-                        // into the top state, since they are not on top.  Instead
-                        // give them the best state after that.
-                        clientProcState =
-                                ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
-                        if (adjType == null) {
-                            adjType = "provider";
-                        }
-                    }
-                }
-                conn.trackProcState(clientProcState, mAdjSeq, now);
-                if (procState > clientProcState) {
-                    procState = clientProcState;
-                    app.setCurRawProcState(procState);
-                }
-                if (client.getCurrentSchedulingGroup() > schedGroup) {
-                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-                }
-                if (adjType != null) {
-                    app.adjType = adjType;
-                    app.adjTypeCode = ActivityManager.RunningAppProcessInfo
-                            .REASON_PROVIDER_IN_USE;
-                    app.adjSource = client;
-                    app.adjSourceProcState = clientProcState;
-                    app.adjTarget = cpr.name;
-                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                        reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
-                                + ": " + app + ", due to " + client
-                                + " adj=" + adj + " procState="
-                                + ProcessList.makeProcStateString(procState));
-                    }
-                }
-            }
-            // If the provider has external (non-framework) process
-            // dependencies, ensure that its adjustment is at least
-            // FOREGROUND_APP_ADJ.
-            if (cpr.hasExternalProcessHandles()) {
-                if (adj > ProcessList.FOREGROUND_APP_ADJ) {
-                    adj = ProcessList.FOREGROUND_APP_ADJ;
-                    app.setCurRawAdj(adj);
-                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-                    app.cached = false;
-                    app.adjType = "ext-provider";
-                    app.adjTarget = cpr.name;
-                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                                "Raise adj to external provider: " + app);
-                    }
-                }
-                if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
-                    procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
-                    app.setCurRawProcState(procState);
-                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                                "Raise procstate to external provider: " + app);
-                    }
-                }
-            }
-        }
-
-        if (app.lastProviderTime > 0 &&
-                (app.lastProviderTime+mConstants.CONTENT_PROVIDER_RETAIN_TIME) > now) {
-            if (adj > ProcessList.PREVIOUS_APP_ADJ) {
-                adj = ProcessList.PREVIOUS_APP_ADJ;
-                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
-                app.cached = false;
-                app.adjType = "recent-provider";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                            "Raise adj to recent provider: " + app);
-                }
-            }
-            if (procState > PROCESS_STATE_LAST_ACTIVITY) {
-                procState = PROCESS_STATE_LAST_ACTIVITY;
-                app.adjType = "recent-provider";
-                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                            "Raise procstate to recent provider: " + app);
-                }
-            }
-        }
-
-        if (mayBeTop && procState > ActivityManager.PROCESS_STATE_TOP) {
-            // A client of one of our services or providers is in the top state.  We
-            // *may* want to be in the top state, but not if we are already running in
-            // the background for some other reason.  For the decision here, we are going
-            // to pick out a few specific states that we want to remain in when a client
-            // is top (states that tend to be longer-term) and otherwise allow it to go
-            // to the top state.
-            switch (procState) {
-                case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
-                case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
-                    // Something else is keeping it at this level, just leave it.
-                    break;
-                case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
-                case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
-                case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
-                case ActivityManager.PROCESS_STATE_SERVICE:
-                    // These all are longer-term states, so pull them up to the top
-                    // of the background states, but not all the way to the top state.
-                    procState = ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
-                    app.adjType = mayBeTopType;
-                    app.adjSource = mayBeTopSource;
-                    app.adjTarget = mayBeTopTarget;
-                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                        reportOomAdjMessageLocked(TAG_OOM_ADJ, "May be top raise to " + mayBeTopType
-                                + ": " + app + ", due to " + mayBeTopSource
-                                + " adj=" + adj + " procState="
-                                + ProcessList.makeProcStateString(procState));
-                    }
-                    break;
-                default:
-                    // Otherwise, top is a better choice, so take it.
-                    procState = ActivityManager.PROCESS_STATE_TOP;
-                    app.adjType = mayBeTopType;
-                    app.adjSource = mayBeTopSource;
-                    app.adjTarget = mayBeTopTarget;
-                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                        reportOomAdjMessageLocked(TAG_OOM_ADJ, "May be top raise to " + mayBeTopType
-                                + ": " + app + ", due to " + mayBeTopSource
-                                + " adj=" + adj + " procState="
-                                + ProcessList.makeProcStateString(procState));
-                    }
-                    break;
-            }
-        }
-
-        if (procState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
-            if (app.hasClientActivities()) {
-                // This is a cached process, but with client activities.  Mark it so.
-                procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
-                app.adjType = "cch-client-act";
-            } else if (app.treatLikeActivity) {
-                // This is a cached process, but somebody wants us to treat it like it has
-                // an activity, okay!
-                procState = PROCESS_STATE_CACHED_ACTIVITY;
-                app.adjType = "cch-as-act";
-            }
-        }
-
-        if (adj == ProcessList.SERVICE_ADJ) {
-            if (doingAll) {
-                app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);
-                mNewNumServiceProcs++;
-                //Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb);
-                if (!app.serviceb) {
-                    // This service isn't far enough down on the LRU list to
-                    // normally be a B service, but if we are low on RAM and it
-                    // is large we want to force it down since we would prefer to
-                    // keep launcher over it.
-                    if (mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
-                            && app.lastPss >= mProcessList.getCachedRestoreThresholdKb()) {
-                        app.serviceHighRam = true;
-                        app.serviceb = true;
-                        //Slog.i(TAG, "ADJ " + app + " high ram!");
-                    } else {
-                        mNewNumAServiceProcs++;
-                        //Slog.i(TAG, "ADJ " + app + " not high ram!");
-                    }
-                } else {
-                    app.serviceHighRam = false;
-                }
-            }
-            if (app.serviceb) {
-                adj = ProcessList.SERVICE_B_ADJ;
-            }
-        }
-
-        app.setCurRawAdj(adj);
-
-        //Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
-        //      " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
-        if (adj > app.maxAdj) {
-            adj = app.maxAdj;
-            if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
-                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-            }
-        }
-
-        // Put bound foreground services in a special sched group for additional
-        // restrictions on screen off
-        if (procState >= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE &&
-            mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE) {
-            if (schedGroup > ProcessList.SCHED_GROUP_RESTRICTED) {
-                schedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
-            }
-        }
-
-        // Do final modification to adj.  Everything we do between here and applying
-        // the final setAdj must be done in this function, because we will also use
-        // it when computing the final cached adj later.  Note that we don't need to
-        // worry about this for max adj above, since max adj will always be used to
-        // keep it out of the cached vaues.
-        app.curAdj = app.modifyRawOomAdj(adj);
-        app.setCurrentSchedulingGroup(schedGroup);
-        app.setCurProcState(procState);
-        app.setCurRawProcState(procState);
-        app.setHasForegroundActivities(foregroundActivities);
-        app.completedAdjSeq = mAdjSeq;
-
-        // if curAdj or curProcState improved, then this process was promoted
-        return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
-    }
-
-    /**
-     * Checks if for the given app and client, there's a cycle that should skip over the client
-     * for now or use partial values to evaluate the effect of the client binding.
-     * @param app
-     * @param client
-     * @param procState procstate evaluated so far for this app
-     * @param adj oom_adj evaluated so far for this app
-     * @param cycleReEval whether we're currently re-evaluating due to a cycle, and not the first
-     *                    evaluation.
-     * @return whether to skip using the client connection at this time
-     */
-    private boolean shouldSkipDueToCycle(ProcessRecord app, ProcessRecord client,
-            int procState, int adj, boolean cycleReEval) {
-        if (client.containsCycle) {
-            // We've detected a cycle. We should retry computeOomAdjLocked later in
-            // case a later-checked connection from a client  would raise its
-            // priority legitimately.
-            app.containsCycle = true;
-            // If the client has not been completely evaluated, check if it's worth
-            // using the partial values.
-            if (client.completedAdjSeq < mAdjSeq) {
-                if (cycleReEval) {
-                    // If the partial values are no better, skip until the next
-                    // attempt
-                    if (client.getCurRawProcState() >= procState
-                            && client.getCurRawAdj() >= adj) {
-                        return true;
-                    }
-                    // Else use the client's partial procstate and adj to adjust the
-                    // effect of the binding
-                } else {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     private static final class RecordPssRunnable implements Runnable {
         private final ActivityManagerService mService;
         private final ProcessRecord mProc;
@@ -16975,287 +15979,6 @@
         }
     }
 
-    private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
-            long nowElapsed) {
-        boolean success = true;
-
-        if (app.getCurRawAdj() != app.setRawAdj) {
-            app.setRawAdj = app.getCurRawAdj();
-        }
-
-        int changes = 0;
-
-        if (app.curAdj != app.setAdj) {
-            // don't compact during bootup
-            if (mConstants.USE_COMPACTION && mBooted) {
-                // Perform a minor compaction when a perceptible app becomes the prev/home app
-                // Perform a major compaction when any app enters cached
-                // reminder: here, setAdj is previous state, curAdj is upcoming state
-                if (app.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ &&
-                    (app.curAdj == ProcessList.PREVIOUS_APP_ADJ ||
-                     app.curAdj == ProcessList.HOME_APP_ADJ)) {
-                    mAppCompact.compactAppSome(app);
-                } else if (app.setAdj < ProcessList.CACHED_APP_MIN_ADJ &&
-                           app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
-                    mAppCompact.compactAppFull(app);
-                }
-            }
-            ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);
-            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.info.uid) {
-                String msg = "Set " + app.pid + " " + app.processName + " adj "
-                        + app.curAdj + ": " + app.adjType;
-                reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
-            }
-            app.setAdj = app.curAdj;
-            app.verifiedAdj = ProcessList.INVALID_ADJ;
-        }
-
-        final int curSchedGroup = app.getCurrentSchedulingGroup();
-        if (app.setSchedGroup != curSchedGroup) {
-            int oldSchedGroup = app.setSchedGroup;
-            app.setSchedGroup = curSchedGroup;
-            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.uid) {
-                String msg = "Setting sched group of " + app.processName
-                        + " to " + curSchedGroup + ": " + app.adjType;
-                reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
-            }
-            if (app.waitingToKill != null && app.curReceivers.isEmpty()
-                    && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
-                app.kill(app.waitingToKill, true);
-                success = false;
-            } else {
-                int processGroup;
-                switch (curSchedGroup) {
-                    case ProcessList.SCHED_GROUP_BACKGROUND:
-                        processGroup = THREAD_GROUP_BG_NONINTERACTIVE;
-                        break;
-                    case ProcessList.SCHED_GROUP_TOP_APP:
-                    case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
-                        processGroup = THREAD_GROUP_TOP_APP;
-                        break;
-                    case ProcessList.SCHED_GROUP_RESTRICTED:
-                        processGroup = THREAD_GROUP_RESTRICTED;
-                        break;
-                    default:
-                        processGroup = THREAD_GROUP_DEFAULT;
-                        break;
-                }
-                long oldId = Binder.clearCallingIdentity();
-                try {
-                    setProcessGroup(app.pid, processGroup);
-                    if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
-                        // do nothing if we already switched to RT
-                        if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
-                            app.getWindowProcessController().onTopProcChanged();
-                            if (mUseFifoUiScheduling) {
-                                // Switch UI pipeline for app to SCHED_FIFO
-                                app.savedPriority = Process.getThreadPriority(app.pid);
-                                scheduleAsFifoPriority(app.pid, /* suppressLogs */true);
-                                if (app.renderThreadTid != 0) {
-                                    scheduleAsFifoPriority(app.renderThreadTid,
-                                        /* suppressLogs */true);
-                                    if (DEBUG_OOM_ADJ) {
-                                        Slog.d("UI_FIFO", "Set RenderThread (TID " +
-                                            app.renderThreadTid + ") to FIFO");
-                                    }
-                                } else {
-                                    if (DEBUG_OOM_ADJ) {
-                                        Slog.d("UI_FIFO", "Not setting RenderThread TID");
-                                    }
-                                }
-                            } else {
-                                // Boost priority for top app UI and render threads
-                                setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST);
-                                if (app.renderThreadTid != 0) {
-                                    try {
-                                        setThreadPriority(app.renderThreadTid,
-                                                TOP_APP_PRIORITY_BOOST);
-                                    } catch (IllegalArgumentException e) {
-                                        // thread died, ignore
-                                    }
-                                }
-                            }
-                        }
-                    } else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
-                            curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
-                        app.getWindowProcessController().onTopProcChanged();
-                        if (mUseFifoUiScheduling) {
-                            try {
-                                // Reset UI pipeline to SCHED_OTHER
-                                setThreadScheduler(app.pid, SCHED_OTHER, 0);
-                                setThreadPriority(app.pid, app.savedPriority);
-                                if (app.renderThreadTid != 0) {
-                                    setThreadScheduler(app.renderThreadTid,
-                                        SCHED_OTHER, 0);
-                                    setThreadPriority(app.renderThreadTid, -4);
-                                }
-                            } catch (IllegalArgumentException e) {
-                                Slog.w(TAG,
-                                        "Failed to set scheduling policy, thread does not exist:\n"
-                                                + e);
-                            } catch (SecurityException e) {
-                                Slog.w(TAG, "Failed to set scheduling policy, not allowed:\n" + e);
-                            }
-                        } else {
-                            // Reset priority for top app UI and render threads
-                            setThreadPriority(app.pid, 0);
-                            if (app.renderThreadTid != 0) {
-                                setThreadPriority(app.renderThreadTid, 0);
-                            }
-                        }
-                    }
-                } catch (Exception e) {
-                    if (false) {
-                        Slog.w(TAG, "Failed setting process group of " + app.pid
-                                + " to " + app.getCurrentSchedulingGroup());
-                        Slog.w(TAG, "at location", e);
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(oldId);
-                }
-            }
-        }
-        if (app.repForegroundActivities != app.hasForegroundActivities()) {
-            app.repForegroundActivities = app.hasForegroundActivities();
-            changes |= ProcessChangeItem.CHANGE_ACTIVITIES;
-        }
-        if (app.getReportedProcState() != app.getCurProcState()) {
-            app.setReportedProcState(app.getCurProcState());
-            if (app.thread != null) {
-                try {
-                    if (false) {
-                        //RuntimeException h = new RuntimeException("here");
-                        Slog.i(TAG, "Sending new process state " + app.getReportedProcState()
-                                + " to " + app /*, h*/);
-                    }
-                    app.thread.setProcessState(app.getReportedProcState());
-                } catch (RemoteException e) {
-                }
-            }
-        }
-        if (app.setProcState == PROCESS_STATE_NONEXISTENT
-                || ProcessList.procStatesDifferForMem(app.getCurProcState(), app.setProcState)) {
-            if (false && mTestPssMode && app.setProcState >= 0 && app.lastStateTime <= (now-200)) {
-                // Experimental code to more aggressively collect pss while
-                // running test...  the problem is that this tends to collect
-                // the data right when a process is transitioning between process
-                // states, which will tend to give noisy data.
-                long start = SystemClock.uptimeMillis();
-                long startTime = SystemClock.currentThreadTimeMillis();
-                long pss = Debug.getPss(app.pid, mTmpLong, null);
-                long endTime = SystemClock.currentThreadTimeMillis();
-                recordPssSampleLocked(app, app.getCurProcState(), pss, mTmpLong[0], mTmpLong[1],
-                        mTmpLong[2], ProcessStats.ADD_PSS_INTERNAL_SINGLE, endTime-startTime, now);
-                mPendingPssProcesses.remove(app);
-                Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
-                        + " to " + app.getCurProcState() + ": "
-                        + (SystemClock.uptimeMillis()-start) + "ms");
-            }
-            app.lastStateTime = now;
-            app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
-                    app.procStateMemTracker, mTestPssMode, mAtmInternal.isSleeping(), now);
-            if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
-                    + ProcessList.makeProcStateString(app.setProcState) + " to "
-                    + ProcessList.makeProcStateString(app.getCurProcState()) + " next pss in "
-                    + (app.nextPssTime-now) + ": " + app);
-        } else {
-            if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
-                    && now > (app.lastStateTime+ProcessList.minTimeFromStateChange(
-                    mTestPssMode)))) {
-                if (requestPssLocked(app, app.setProcState)) {
-                    app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
-                            app.procStateMemTracker, mTestPssMode, mAtmInternal.isSleeping(), now);
-                }
-            } else if (false && DEBUG_PSS) Slog.d(TAG_PSS,
-                    "Not requesting pss of " + app + ": next=" + (app.nextPssTime-now));
-        }
-        if (app.setProcState != app.getCurProcState()) {
-            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.uid) {
-                String msg = "Proc state change of " + app.processName
-                        + " to " + ProcessList.makeProcStateString(app.getCurProcState())
-                        + " (" + app.getCurProcState() + ")" + ": " + app.adjType;
-                reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
-            }
-            boolean setImportant = app.setProcState < ActivityManager.PROCESS_STATE_SERVICE;
-            boolean curImportant = app.getCurProcState() < ActivityManager.PROCESS_STATE_SERVICE;
-            if (setImportant && !curImportant) {
-                // This app is no longer something we consider important enough to allow to use
-                // arbitrary amounts of battery power. Note its current CPU time to later know to
-                // kill it if it is not behaving well.
-                app.setWhenUnimportant(now);
-                app.lastCpuTime = 0;
-            }
-            // Inform UsageStats of important process state change
-            // Must be called before updating setProcState
-            maybeUpdateUsageStatsLocked(app, nowElapsed);
-
-            maybeUpdateLastTopTime(app, now);
-
-            app.setProcState = app.getCurProcState();
-            if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
-                app.notCachedSinceIdle = false;
-            }
-            if (!doingAll) {
-                setProcessTrackerStateLocked(app, mProcessStats.getMemFactorLocked(), now);
-            } else {
-                app.procStateChanged = true;
-            }
-        } else if (app.reportedInteraction && (nowElapsed - app.getInteractionEventTime())
-                > mConstants.USAGE_STATS_INTERACTION_INTERVAL) {
-            // For apps that sit around for a long time in the interactive state, we need
-            // to report this at least once a day so they don't go idle.
-            maybeUpdateUsageStatsLocked(app, nowElapsed);
-        }
-
-        if (changes != 0) {
-            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                    "Changes in " + app + ": " + changes);
-            int i = mPendingProcessChanges.size()-1;
-            ProcessChangeItem item = null;
-            while (i >= 0) {
-                item = mPendingProcessChanges.get(i);
-                if (item.pid == app.pid) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                            "Re-using existing item: " + item);
-                    break;
-                }
-                i--;
-            }
-            if (i < 0) {
-                // No existing item in pending changes; need a new one.
-                final int NA = mAvailProcessChanges.size();
-                if (NA > 0) {
-                    item = mAvailProcessChanges.remove(NA-1);
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                            "Retrieving available item: " + item);
-                } else {
-                    item = new ProcessChangeItem();
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                            "Allocating new item: " + item);
-                }
-                item.changes = 0;
-                item.pid = app.pid;
-                item.uid = app.info.uid;
-                if (mPendingProcessChanges.size() == 0) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                            "*** Enqueueing dispatch processes changed!");
-                    mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG).sendToTarget();
-                }
-                mPendingProcessChanges.add(item);
-            }
-            item.changes |= changes;
-            item.foregroundActivities = app.repForegroundActivities;
-            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                    "Item " + Integer.toHexString(System.identityHashCode(item))
-                    + " " + app.toShortString() + ": changes=" + item.changes
-                    + " foreground=" + item.foregroundActivities
-                    + " type=" + app.adjType + " source=" + app.adjSource
-                    + " target=" + app.adjTarget);
-        }
-
-        return success;
-    }
-
     private boolean isEphemeralLocked(int uid) {
         String packages[] = mContext.getPackageManager().getPackagesForUid(uid);
         if (packages == null || packages.length != 1) { // Ephemeral apps cannot share uid
@@ -17369,78 +16092,13 @@
         }
     }
 
-    private void maybeUpdateUsageStatsLocked(ProcessRecord app, long nowElapsed) {
-        if (DEBUG_USAGE_STATS) {
-            Slog.d(TAG, "Checking proc [" + Arrays.toString(app.getPackageList())
-                    + "] state changes: old = " + app.setProcState + ", new = "
-                    + app.getCurProcState());
-        }
-        if (mUsageStatsService == null) {
-            return;
-        }
-        boolean isInteraction;
-        // To avoid some abuse patterns, we are going to be careful about what we consider
-        // to be an app interaction.  Being the top activity doesn't count while the display
-        // is sleeping, nor do short foreground services.
-        if (app.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP) {
-            isInteraction = true;
-            app.setFgInteractionTime(0);
-        } else if (app.getCurProcState() <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
-            if (app.getFgInteractionTime() == 0) {
-                app.setFgInteractionTime(nowElapsed);
-                isInteraction = false;
-            } else {
-                isInteraction = nowElapsed > app.getFgInteractionTime()
-                        + mConstants.SERVICE_USAGE_INTERACTION_TIME;
-            }
-        } else {
-            isInteraction =
-                    app.getCurProcState() <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
-            app.setFgInteractionTime(0);
-        }
-        if (isInteraction
-                && (!app.reportedInteraction || (nowElapsed - app.getInteractionEventTime())
-                > mConstants.USAGE_STATS_INTERACTION_INTERVAL)) {
-            app.setInteractionEventTime(nowElapsed);
-            String[] packages = app.getPackageList();
-            if (packages != null) {
-                for (int i = 0; i < packages.length; i++) {
-                    mUsageStatsService.reportEvent(packages[i], app.userId,
-                            UsageEvents.Event.SYSTEM_INTERACTION);
-                }
-            }
-        }
-        app.reportedInteraction = isInteraction;
-        if (!isInteraction) {
-            app.setInteractionEventTime(0);
-        }
-    }
-
-    private void maybeUpdateLastTopTime(ProcessRecord app, long nowUptime) {
-        if (app.setProcState <= ActivityManager.PROCESS_STATE_TOP
-                && app.getCurProcState() > ActivityManager.PROCESS_STATE_TOP) {
-            app.lastTopTime = nowUptime;
-        }
-    }
-
-    private final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
+    final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
         if (proc.thread != null && proc.baseProcessTracker != null) {
             proc.baseProcessTracker.setState(
                     proc.getReportedProcState(), memFactor, now, proc.pkgList.mPkgList);
         }
     }
 
-    private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
-            ProcessRecord TOP_APP, boolean doingAll, long now) {
-        if (app.thread == null) {
-            return false;
-        }
-
-        computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now, false);
-
-        return applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
-    }
-
     @GuardedBy("this")
     final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
             boolean oomAdj) {
@@ -17523,29 +16181,10 @@
      */
     @GuardedBy("this")
     final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) {
-        final ProcessRecord TOP_APP = getTopAppLocked();
-        final boolean wasCached = app.cached;
-
-        mAdjSeq++;
-
-        // This is the desired cached adjusment we want to tell it to use.
-        // If our app is currently cached, we know it, and that is it.  Otherwise,
-        // we don't know it yet, and it needs to now be cached we will then
-        // need to do a complete oom adj.
-        final int cachedAdj = app.getCurRawAdj() >= ProcessList.CACHED_APP_MIN_ADJ
-                ? app.getCurRawAdj() : ProcessList.UNKNOWN_ADJ;
-        boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
-                SystemClock.uptimeMillis());
-        if (oomAdjAll
-                && (wasCached != app.cached || app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ)) {
-            // Changed to/from cached state, so apps after it in the LRU
-            // list may also be changed.
-            updateOomAdjLocked();
-        }
-        return success;
+        return mOomAdjuster.updateOomAdjLocked(app, oomAdjAll);
     }
 
-    private static final class ProcStatsRunnable implements Runnable {
+    static final class ProcStatsRunnable implements Runnable {
         private final ActivityManagerService mService;
         private final ProcessStatsService mProcessStats;
 
@@ -17736,387 +16375,7 @@
 
     @GuardedBy("this")
     final void updateOomAdjLocked() {
-        mOomAdjProfiler.oomAdjStarted();
-        final ProcessRecord TOP_APP = getTopAppLocked();
-        final long now = SystemClock.uptimeMillis();
-        final long nowElapsed = SystemClock.elapsedRealtime();
-        final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
-        final int N = mProcessList.getLruSizeLocked();
-
-        // Reset state in all uid records.
-        for (int i=mActiveUids.size()-1; i>=0; i--) {
-            final UidRecord uidRec = mActiveUids.valueAt(i);
-            if (false && DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
-                    "Starting update of " + uidRec);
-            uidRec.reset();
-        }
-
-        if (mAtmInternal != null) {
-            mAtmInternal.rankTaskLayersIfNeeded();
-        }
-
-        mAdjSeq++;
-        mNewNumServiceProcs = 0;
-        mNewNumAServiceProcs = 0;
-
-        final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;
-        final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES - emptyProcessLimit;
-
-        // Let's determine how many processes we have running vs.
-        // how many slots we have for background processes; we may want
-        // to put multiple processes in a slot of there are enough of
-        // them.
-        final int numSlots = (ProcessList.CACHED_APP_MAX_ADJ
-                - ProcessList.CACHED_APP_MIN_ADJ + 1) / 2
-                / ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
-        int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs;
-        if (numEmptyProcs > cachedProcessLimit) {
-            // If there are more empty processes than our limit on cached
-            // processes, then use the cached process limit for the factor.
-            // This ensures that the really old empty processes get pushed
-            // down to the bottom, so if we are running low on memory we will
-            // have a better chance at keeping around more cached processes
-            // instead of a gazillion empty processes.
-            numEmptyProcs = cachedProcessLimit;
-        }
-        int emptyFactor = (numEmptyProcs + numSlots - 1) / numSlots;
-        if (emptyFactor < 1) emptyFactor = 1;
-        int cachedFactor = (mNumCachedHiddenProcs > 0 ? (mNumCachedHiddenProcs + numSlots - 1) : 1)
-                / numSlots;
-        if (cachedFactor < 1) cachedFactor = 1;
-        int stepCached = -1;
-        int stepEmpty = -1;
-        int numCached = 0;
-        int numCachedExtraGroup = 0;
-        int numEmpty = 0;
-        int numTrimming = 0;
-        int lastCachedGroup = 0;
-        int lastCachedGroupImportance = 0;
-        int lastCachedGroupUid = 0;
-
-        mNumNonCachedProcs = 0;
-        mNumCachedHiddenProcs = 0;
-
-        // First update the OOM adjustment for each of the
-        // application processes based on their current state.
-        int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
-        int nextCachedAdj = curCachedAdj + (ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2);
-        int curCachedImpAdj = 0;
-        int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
-        int nextEmptyAdj = curEmptyAdj + (ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2);
-
-        boolean retryCycles = false;
-
-        // need to reset cycle state before calling computeOomAdjLocked because of service connections
-        for (int i=N-1; i>=0; i--) {
-            ProcessRecord app = mProcessList.mLruProcesses.get(i);
-            app.containsCycle = false;
-            app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY);
-            app.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
-        }
-        for (int i=N-1; i>=0; i--) {
-            ProcessRecord app = mProcessList.mLruProcesses.get(i);
-            if (!app.killedByAm && app.thread != null) {
-                app.procStateChanged = false;
-                computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now, false);
-
-                // if any app encountered a cycle, we need to perform an additional loop later
-                retryCycles |= app.containsCycle;
-
-                // If we haven't yet assigned the final cached adj
-                // to the process, do that now.
-                if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
-                    switch (app.getCurProcState()) {
-                        case PROCESS_STATE_CACHED_ACTIVITY:
-                        case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
-                        case ActivityManager.PROCESS_STATE_CACHED_RECENT:
-                            // Figure out the next cached level, taking into account groups.
-                            boolean inGroup = false;
-                            if (app.connectionGroup != 0) {
-                                if (lastCachedGroupUid == app.uid
-                                        && lastCachedGroup == app.connectionGroup) {
-                                    // This is in the same group as the last process, just tweak
-                                    // adjustment by importance.
-                                    if (app.connectionImportance > lastCachedGroupImportance) {
-                                        lastCachedGroupImportance = app.connectionImportance;
-                                        if (curCachedAdj < nextCachedAdj
-                                                && curCachedAdj < ProcessList.CACHED_APP_MAX_ADJ) {
-                                            curCachedImpAdj++;
-                                        }
-                                    }
-                                    inGroup = true;
-                                } else {
-                                    lastCachedGroupUid = app.uid;
-                                    lastCachedGroup = app.connectionGroup;
-                                    lastCachedGroupImportance = app.connectionImportance;
-                                }
-                            }
-                            if (!inGroup && curCachedAdj != nextCachedAdj) {
-                                stepCached++;
-                                curCachedImpAdj = 0;
-                                if (stepCached >= cachedFactor) {
-                                    stepCached = 0;
-                                    curCachedAdj = nextCachedAdj;
-                                    nextCachedAdj += ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
-                                    if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
-                                        nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
-                                    }
-                                }
-                            }
-                            // This process is a cached process holding activities...
-                            // assign it the next cached value for that type, and then
-                            // step that cached level.
-                            app.setCurRawAdj(curCachedAdj + curCachedImpAdj);
-                            app.curAdj = app.modifyRawOomAdj(curCachedAdj + curCachedImpAdj);
-                            if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning activity LRU #" + i
-                                    + " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj
-                                    + " curCachedImpAdj=" + curCachedImpAdj + ")");
-                            break;
-                        default:
-                            // Figure out the next cached level.
-                            if (curEmptyAdj != nextEmptyAdj) {
-                                stepEmpty++;
-                                if (stepEmpty >= emptyFactor) {
-                                    stepEmpty = 0;
-                                    curEmptyAdj = nextEmptyAdj;
-                                    nextEmptyAdj += ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
-                                    if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
-                                        nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
-                                    }
-                                }
-                            }
-                            // For everything else, assign next empty cached process
-                            // level and bump that up.  Note that this means that
-                            // long-running services that have dropped down to the
-                            // cached level will be treated as empty (since their process
-                            // state is still as a service), which is what we want.
-                            app.setCurRawAdj(curEmptyAdj);
-                            app.curAdj = app.modifyRawOomAdj(curEmptyAdj);
-                            if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning empty LRU #" + i
-                                    + " adj: " + app.curAdj + " (curEmptyAdj=" + curEmptyAdj
-                                    + ")");
-                            break;
-                    }
-                }
-            }
-        }
-
-        // Cycle strategy:
-        // - Retry computing any process that has encountered a cycle.
-        // - Continue retrying until no process was promoted.
-        // - Iterate from least important to most important.
-        int cycleCount = 0;
-        while (retryCycles && cycleCount < 10) {
-            cycleCount++;
-            retryCycles = false;
-
-            for (int i=0; i<N; i++) {
-                ProcessRecord app = mProcessList.mLruProcesses.get(i);
-                if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
-                    app.adjSeq--;
-                    app.completedAdjSeq--;
-                }
-            }
-
-            for (int i=0; i<N; i++) {
-                ProcessRecord app = mProcessList.mLruProcesses.get(i);
-                if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
-                    if (computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now,
-                            true)) {
-                        retryCycles = true;
-                    }
-                }
-            }
-        }
-
-        lastCachedGroup = lastCachedGroupUid = 0;
-
-        for (int i=N-1; i>=0; i--) {
-            ProcessRecord app = mProcessList.mLruProcesses.get(i);
-            if (!app.killedByAm && app.thread != null) {
-                applyOomAdjLocked(app, true, now, nowElapsed);
-
-                // Count the number of process types.
-                switch (app.getCurProcState()) {
-                    case PROCESS_STATE_CACHED_ACTIVITY:
-                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
-                        mNumCachedHiddenProcs++;
-                        numCached++;
-                        if (app.connectionGroup != 0) {
-                            if (lastCachedGroupUid == app.uid
-                                    && lastCachedGroup == app.connectionGroup) {
-                                // If this process is the next in the same group, we don't
-                                // want it to count against our limit of the number of cached
-                                // processes, so bump up the group count to account for it.
-                                numCachedExtraGroup++;
-                            } else {
-                                lastCachedGroupUid = app.uid;
-                                lastCachedGroup = app.connectionGroup;
-                            }
-                        } else {
-                            lastCachedGroupUid = lastCachedGroup = 0;
-                        }
-                        if ((numCached - numCachedExtraGroup) > cachedProcessLimit) {
-                            app.kill("cached #" + numCached, true);
-                        }
-                        break;
-                    case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
-                        if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES
-                                && app.lastActivityTime < oldTime) {
-                            app.kill("empty for "
-                                    + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
-                                    / 1000) + "s", true);
-                        } else {
-                            numEmpty++;
-                            if (numEmpty > emptyProcessLimit) {
-                                app.kill("empty #" + numEmpty, true);
-                            }
-                        }
-                        break;
-                    default:
-                        mNumNonCachedProcs++;
-                        break;
-                }
-
-                if (app.isolated && app.services.size() <= 0 && app.isolatedEntryPoint == null) {
-                    // If this is an isolated process, there are no services
-                    // running in it, and it's not a special process with a
-                    // custom entry point, then the process is no longer
-                    // needed.  We agressively kill these because we can by
-                    // definition not re-use the same process again, and it is
-                    // good to avoid having whatever code was running in them
-                    // left sitting around after no longer needed.
-                    app.kill("isolated not needed", true);
-                } else {
-                    // Keeping this process, update its uid.
-                    final UidRecord uidRec = app.uidRecord;
-                    if (uidRec != null) {
-                        uidRec.ephemeral = app.info.isInstantApp();
-                        if (uidRec.getCurProcState() > app.getCurProcState()) {
-                            uidRec.setCurProcState(app.getCurProcState());
-                        }
-                        if (app.hasForegroundServices()) {
-                            uidRec.foregroundServices = true;
-                        }
-                    }
-                }
-
-                if (app.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME
-                        && !app.killedByAm) {
-                    numTrimming++;
-                }
-            }
-        }
-
-        incrementProcStateSeqAndNotifyAppsLocked();
-
-        mNumServiceProcs = mNewNumServiceProcs;
-
-        boolean allChanged = updateLowMemStateLocked(numCached, numEmpty, numTrimming);
-
-        if (mAlwaysFinishActivities) {
-            // Need to do this on its own message because the stack may not
-            // be in a consistent state at this point.
-            mAtmInternal.scheduleDestroyAllActivities("always-finish");
-        }
-
-        if (allChanged) {
-            requestPssAllProcsLocked(now, false, mProcessStats.isMemFactorLowered());
-        }
-
-        ArrayList<UidRecord> becameIdle = null;
-
-        // Update from any uid changes.
-        if (mLocalPowerManager != null) {
-            mLocalPowerManager.startUidChanges();
-        }
-        for (int i=mActiveUids.size()-1; i>=0; i--) {
-            final UidRecord uidRec = mActiveUids.valueAt(i);
-            int uidChange = UidRecord.CHANGE_PROCSTATE;
-            if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT
-                    && (uidRec.setProcState != uidRec.getCurProcState()
-                           || uidRec.setWhitelist != uidRec.curWhitelist)) {
-                if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "Changes in " + uidRec
-                        + ": proc state from " + uidRec.setProcState + " to "
-                        + uidRec.getCurProcState() + ", whitelist from " + uidRec.setWhitelist
-                        + " to " + uidRec.curWhitelist);
-                if (ActivityManager.isProcStateBackground(uidRec.getCurProcState())
-                        && !uidRec.curWhitelist) {
-                    // UID is now in the background (and not on the temp whitelist).  Was it
-                    // previously in the foreground (or on the temp whitelist)?
-                    if (!ActivityManager.isProcStateBackground(uidRec.setProcState)
-                            || uidRec.setWhitelist) {
-                        uidRec.lastBackgroundTime = nowElapsed;
-                        if (!mHandler.hasMessages(IDLE_UIDS_MSG)) {
-                            // Note: the background settle time is in elapsed realtime, while
-                            // the handler time base is uptime.  All this means is that we may
-                            // stop background uids later than we had intended, but that only
-                            // happens because the device was sleeping so we are okay anyway.
-                            mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
-                                    mConstants.BACKGROUND_SETTLE_TIME);
-                        }
-                    }
-                    if (uidRec.idle && !uidRec.setIdle) {
-                        uidChange = UidRecord.CHANGE_IDLE;
-                        if (becameIdle == null) {
-                            becameIdle = new ArrayList<>();
-                        }
-                        becameIdle.add(uidRec);
-                    }
-                } else {
-                    if (uidRec.idle) {
-                        uidChange = UidRecord.CHANGE_ACTIVE;
-                        EventLogTags.writeAmUidActive(uidRec.uid);
-                        uidRec.idle = false;
-                    }
-                    uidRec.lastBackgroundTime = 0;
-                }
-                final boolean wasCached = uidRec.setProcState
-                        > ActivityManager.PROCESS_STATE_RECEIVER;
-                final boolean isCached = uidRec.getCurProcState()
-                        > ActivityManager.PROCESS_STATE_RECEIVER;
-                if (wasCached != isCached || uidRec.setProcState == PROCESS_STATE_NONEXISTENT) {
-                    uidChange |= isCached ? UidRecord.CHANGE_CACHED : UidRecord.CHANGE_UNCACHED;
-                }
-                uidRec.setProcState = uidRec.getCurProcState();
-                uidRec.setWhitelist = uidRec.curWhitelist;
-                uidRec.setIdle = uidRec.idle;
-                enqueueUidChangeLocked(uidRec, -1, uidChange);
-                noteUidProcessState(uidRec.uid, uidRec.getCurProcState());
-                if (uidRec.foregroundServices) {
-                    mServices.foregroundServiceProcStateChangedLocked(uidRec);
-                }
-            }
-        }
-        if (mLocalPowerManager != null) {
-            mLocalPowerManager.finishUidChanges();
-        }
-
-        if (becameIdle != null) {
-            // If we have any new uids that became idle this time, we need to make sure
-            // they aren't left with running services.
-            for (int i = becameIdle.size() - 1; i >= 0; i--) {
-                mServices.stopInBackgroundLocked(becameIdle.get(i).uid);
-            }
-        }
-
-        if (mProcessStats.shouldWriteNowLocked(now)) {
-            mHandler.post(new ProcStatsRunnable(ActivityManagerService.this, mProcessStats));
-        }
-
-        // Run this after making sure all procstates are updated.
-        mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);
-
-        if (DEBUG_OOM_ADJ) {
-            final long duration = SystemClock.uptimeMillis() - now;
-            if (false) {
-                Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms",
-                        new RuntimeException("here").fillInStackTrace());
-            } else {
-                Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms");
-            }
-        }
-        mOomAdjProfiler.oomAdjEnded();
+        mOomAdjuster.updateOomAdjLocked();
     }
 
     @Override
@@ -18151,9 +16410,9 @@
                     mLocalPowerManager.startUidChanges();
                 }
                 final int appId = UserHandle.getAppId(pkgUid);
-                final int N = mActiveUids.size();
-                for (int i=N-1; i>=0; i--) {
-                    final UidRecord uidRec = mActiveUids.valueAt(i);
+                final int N = mProcessList.mActiveUids.size();
+                for (int i = N - 1; i >= 0; i--) {
+                    final UidRecord uidRec = mProcessList.mActiveUids.valueAt(i);
                     final long bgTime = uidRec.lastBackgroundTime;
                     if (bgTime > 0 && !uidRec.idle) {
                         if (UserHandle.getAppId(uidRec.uid) == appId) {
@@ -18178,49 +16437,17 @@
         }
     }
 
+    /** Make the currently active UIDs idle after a certain grace period. */
     final void idleUids() {
         synchronized (this) {
-            final int N = mActiveUids.size();
-            if (N <= 0) {
-                return;
-            }
-            final long nowElapsed = SystemClock.elapsedRealtime();
-            final long maxBgTime = nowElapsed - mConstants.BACKGROUND_SETTLE_TIME;
-            long nextTime = 0;
-            if (mLocalPowerManager != null) {
-                mLocalPowerManager.startUidChanges();
-            }
-            for (int i=N-1; i>=0; i--) {
-                final UidRecord uidRec = mActiveUids.valueAt(i);
-                final long bgTime = uidRec.lastBackgroundTime;
-                if (bgTime > 0 && !uidRec.idle) {
-                    if (bgTime <= maxBgTime) {
-                        EventLogTags.writeAmUidIdle(uidRec.uid);
-                        uidRec.idle = true;
-                        uidRec.setIdle = true;
-                        doStopUidLocked(uidRec.uid, uidRec);
-                    } else {
-                        if (nextTime == 0 || nextTime > bgTime) {
-                            nextTime = bgTime;
-                        }
-                    }
-                }
-            }
-            if (mLocalPowerManager != null) {
-                mLocalPowerManager.finishUidChanges();
-            }
-            if (nextTime > 0) {
-                mHandler.removeMessages(IDLE_UIDS_MSG);
-                mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
-                        nextTime + mConstants.BACKGROUND_SETTLE_TIME - nowElapsed);
-            }
+            mOomAdjuster.idleUidsLocked();
         }
     }
 
     /**
      * Checks if any uid is coming from background to foreground or vice versa and if so, increments
      * the {@link UidRecord#curProcStateSeq} corresponding to that uid using global seq counter
-     * {@link #mProcStateSeqCounter} and notifies the app if it needs to block.
+     * {@link ProcessList#mProcStateSeqCounter} and notifies the app if it needs to block.
      */
     @VisibleForTesting
     @GuardedBy("this")
@@ -18230,8 +16457,8 @@
         }
         // Used for identifying which uids need to block for network.
         ArrayList<Integer> blockingUids = null;
-        for (int i = mActiveUids.size() - 1; i >= 0; --i) {
-            final UidRecord uidRec = mActiveUids.valueAt(i);
+        for (int i = mProcessList.mActiveUids.size() - 1; i >= 0; --i) {
+            final UidRecord uidRec = mProcessList.mActiveUids.valueAt(i);
             // If the network is not restricted for uid, then nothing to do here.
             if (!mInjector.isNetworkRestrictedForUid(uidRec.uid)) {
                 continue;
@@ -18279,13 +16506,15 @@
                 continue;
             }
             if (!app.killedByAm && app.thread != null) {
-                final UidRecord uidRec = mActiveUids.get(app.uid);
+                final UidRecord uidRec = mProcessList.getUidRecordLocked(app.uid);
                 try {
                     if (DEBUG_NETWORK) {
                         Slog.d(TAG_NETWORK, "Informing app thread that it needs to block: "
                                 + uidRec);
                     }
-                    app.thread.setNetworkBlockSeq(uidRec.curProcStateSeq);
+                    if (uidRec != null) {
+                        app.thread.setNetworkBlockSeq(uidRec.curProcStateSeq);
+                    }
                 } catch (RemoteException ignored) {
                 }
             }
@@ -18326,7 +16555,7 @@
 
     final void runInBackgroundDisabled(int uid) {
         synchronized (this) {
-            UidRecord uidRec = mActiveUids.get(uid);
+            UidRecord uidRec = mProcessList.getUidRecordLocked(uid);
             if (uidRec != null) {
                 // This uid is actually running...  should it be considered background now?
                 if (uidRec.idle) {
@@ -18339,24 +16568,7 @@
         }
     }
 
-    /**
-     * Call {@link #doStopUidLocked} (which will also stop background services) for all idle UIDs.
-     */
-    void doStopUidForIdleUidsLocked() {
-        final int size = mActiveUids.size();
-        for (int i = 0; i < size; i++) {
-            final int uid = mActiveUids.keyAt(i);
-            if (UserHandle.isCore(uid)) {
-                continue;
-            }
-            final UidRecord uidRec = mActiveUids.valueAt(i);
-            if (!uidRec.idle) {
-                continue;
-            }
-            doStopUidLocked(uidRec.uid, uidRec);
-        }
-    }
-
+    @GuardedBy("this")
     final void doStopUidLocked(int uid, final UidRecord uidRec) {
         mServices.stopInBackgroundLocked(uid);
         enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE);
@@ -18440,27 +16652,12 @@
 
     @GuardedBy("this")
     final void setAppIdTempWhitelistStateLocked(int appId, boolean onWhitelist) {
-        boolean changed = false;
-        for (int i=mActiveUids.size()-1; i>=0; i--) {
-            final UidRecord uidRec = mActiveUids.valueAt(i);
-            if (UserHandle.getAppId(uidRec.uid) == appId && uidRec.curWhitelist != onWhitelist) {
-                uidRec.curWhitelist = onWhitelist;
-                changed = true;
-            }
-        }
-        if (changed) {
-            updateOomAdjLocked();
-        }
+        mOomAdjuster.setAppIdTempWhitelistStateLocked(appId, onWhitelist);
     }
 
     @GuardedBy("this")
     final void setUidTempWhitelistStateLocked(int uid, boolean onWhitelist) {
-        boolean changed = false;
-        final UidRecord uidRec = mActiveUids.get(uid);
-        if (uidRec != null && uidRec.curWhitelist != onWhitelist) {
-            uidRec.curWhitelist = onWhitelist;
-            updateOomAdjLocked();
-        }
+        mOomAdjuster.setUidTempWhitelistStateLocked(uid, onWhitelist);
     }
 
     final void trimApplications() {
@@ -19044,6 +17241,19 @@
         }
 
         @Override
+        public void setPendingIntentAllowBgActivityStarts(IIntentSender target,
+                IBinder whitelistToken, int flags) {
+            if (!(target instanceof PendingIntentRecord)) {
+                Slog.w(TAG, "setPendingIntentAllowBgActivityStarts():"
+                        + " not a PendingIntentRecord: " + target);
+                return;
+            }
+            synchronized (ActivityManagerService.this) {
+                ((PendingIntentRecord) target).setAllowBgActivityStarts(whitelistToken, flags);
+            }
+        }
+
+        @Override
         public void setDeviceIdleWhitelist(int[] allAppids, int[] exceptIdleAppids) {
             synchronized (ActivityManagerService.this) {
                 mDeviceIdleWhitelist = allAppids;
@@ -19110,7 +17320,7 @@
             }
             UidRecord record;
             synchronized (ActivityManagerService.this) {
-                record = mActiveUids.get(uid);
+                record = mProcessList.getUidRecordLocked(uid);
                 if (record == null) {
                     if (DEBUG_NETWORK) {
                         Slog.d(TAG_NETWORK, "No active uidRecord for uid: " + uid
@@ -19313,10 +17523,10 @@
 
         @Override
         public void updateActivityUsageStats(ComponentName activity, int userId, int event,
-                IBinder appToken) {
+                IBinder appToken, ComponentName taskRoot) {
             synchronized (ActivityManagerService.this) {
                 ActivityManagerService.this.updateActivityUsageStats(activity, userId, event,
-                        appToken);
+                        appToken, taskRoot);
             }
         }
 
@@ -19430,18 +17640,19 @@
         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) {
+                boolean sticky, int userId, boolean allowBackgroundActivityStarts) {
             synchronized (ActivityManagerService.this) {
                 return ActivityManagerService.this.broadcastIntentInPackage(packageName, uid,
                         intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
-                        requiredPermission, bOptions, serialized, sticky, userId);
+                        requiredPermission, bOptions, serialized, sticky, userId,
+                        allowBackgroundActivityStarts);
             }
         }
 
         @Override
         public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType,
-                boolean fgRequired, String callingPackage, int userId)
-                throws TransactionTooLargeException {
+                boolean fgRequired, String callingPackage, int userId,
+                boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
             synchronized(ActivityManagerService.this) {
                 if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                         "startServiceInPackage: " + service + " type=" + resolvedType);
@@ -19449,7 +17660,8 @@
                 ComponentName res;
                 try {
                     res = mServices.startServiceLocked(null, service,
-                            resolvedType, -1, uid, fgRequired, callingPackage, userId);
+                            resolvedType, -1, uid, fgRequired, callingPackage, userId,
+                            allowBackgroundActivityStarts);
                 } finally {
                     Binder.restoreCallingIdentity(origId);
                 }
@@ -19647,6 +17859,25 @@
                 return pr == null ? Zygote.MOUNT_EXTERNAL_NONE : pr.mountMode;
             }
         }
+
+        @Override
+        public boolean isAppForeground(int uid) {
+            return ActivityManagerService.this.isAppForeground(uid);
+        }
+
+        @Override
+        public void clearPendingBackup(int userId) {
+            ActivityManagerService.this.clearPendingBackup(userId);
+        }
+
+        /**
+         * When power button is very long pressed, call this interface to do some pre-shutdown work
+         * like persisting database etc.
+         */
+        @Override
+        public void prepareForPossibleShutdown() {
+            ActivityManagerService.this.prepareForPossibleShutdown();
+        }
     }
 
     long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
@@ -19722,7 +17953,7 @@
         }
         UidRecord record;
         synchronized (this) {
-            record = mActiveUids.get(callingUid);
+            record = mProcessList.getUidRecordLocked(callingUid);
             if (record == null) {
                 return;
             }
@@ -19903,6 +18134,18 @@
         }
     }
 
+    /**
+     * When power button is very long pressed, call this interface to do some pre-shutdown work
+     * like persisting database etc.
+     */
+    public void prepareForPossibleShutdown() {
+        synchronized (this) {
+            if (mUsageStatsService != null) {
+                mUsageStatsService.prepareForPossibleShutdown();
+            }
+        }
+    }
+
     @VisibleForTesting
     public static class Injector {
         private NetworkManagementInternal mNmi;
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index aee16c3..fd402cc 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -44,7 +44,11 @@
      */
     final ArrayList<ProcessRecord> mPendingCompactionProcesses = new ArrayList<ProcessRecord>();
 
-    /*
+    static final int COMPACT_PROCESS_SOME = 1;
+    static final int COMPACT_PROCESS_FULL = 2;
+    static final int COMPACT_PROCESS_MSG = 1;
+
+    /**
      * This thread must be moved to the system background cpuset.
      * If that doesn't happen, it's probably going to draw a lot of power.
      * However, this has to happen after the first updateOomAdjLocked, because
@@ -53,13 +57,22 @@
      */
     final ServiceThread mCompactionThread;
 
-    static final int COMPACT_PROCESS_SOME = 1;
-    static final int COMPACT_PROCESS_FULL = 2;
-    static final int COMPACT_PROCESS_MSG = 1;
-    final Handler mCompactionHandler;
+    final private Handler mCompactionHandler;
 
-    final ActivityManagerService mAm;
-    final ActivityManagerConstants mConstants;
+    final private ActivityManagerService mAm;
+    final private ActivityManagerConstants mConstants;
+
+    final private String COMPACT_ACTION_FILE = "file";
+    final private String COMPACT_ACTION_ANON = "anon";
+    final private String COMPACT_ACTION_FULL = "all";
+
+    final private String compactActionSome;
+    final private String compactActionFull;
+
+    final private long throttleSomeSome;
+    final private long throttleSomeFull;
+    final private long throttleFullSome;
+    final private long throttleFullFull;
 
     public AppCompactor(ActivityManagerService am) {
         mAm = am;
@@ -69,6 +82,41 @@
                 THREAD_PRIORITY_FOREGROUND, true);
         mCompactionThread.start();
         mCompactionHandler = new MemCompactionHandler(this);
+
+        switch(mConstants.COMPACT_ACTION_1) {
+            case 1:
+                compactActionSome = COMPACT_ACTION_FILE;
+                break;
+            case 2:
+                compactActionSome = COMPACT_ACTION_ANON;
+                break;
+            case 3:
+                compactActionSome = COMPACT_ACTION_FULL;
+                break;
+            default:
+                compactActionSome = COMPACT_ACTION_FILE;
+                break;
+        }
+
+        switch(mConstants.COMPACT_ACTION_2) {
+            case 1:
+                compactActionFull = COMPACT_ACTION_FILE;
+                break;
+            case 2:
+                compactActionFull = COMPACT_ACTION_ANON;
+                break;
+            case 3:
+                compactActionFull = COMPACT_ACTION_FULL;
+                break;
+            default:
+                compactActionFull = COMPACT_ACTION_FULL;
+                break;
+        }
+
+        throttleSomeSome = mConstants.COMPACT_THROTTLE_1;
+        throttleSomeFull = mConstants.COMPACT_THROTTLE_2;
+        throttleFullSome = mConstants.COMPACT_THROTTLE_3;
+        throttleFullFull = mConstants.COMPACT_THROTTLE_4;
     }
 
     // Must be called while holding AMS lock.
@@ -128,18 +176,16 @@
                 }
 
                 // basic throttling
+                // use the ActivityManagerConstants knobs to determine whether current/prevous
+                // compaction combo should be throtted or not
                 if (pendingAction == COMPACT_PROCESS_SOME) {
-                    // if we're compacting some, then compact if >10s after last full
-                    // or >5s after last some
-                    if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < 5000)) ||
-                        (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < 10000))) {
+                    if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < throttleSomeSome)) ||
+                        (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < throttleSomeFull))) {
                         return;
                     }
                 } else {
-                    // if we're compacting full, then compact if >10s after last full
-                    // or >.5s after last some
-                    if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < 500)) ||
-                        (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < 10000))) {
+                    if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < throttleFullSome)) ||
+                        (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < throttleFullFull))) {
                         return;
                     }
                 }
@@ -151,9 +197,9 @@
                     long[] rssBefore = Process.getRss(pid);
                     FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim");
                     if (pendingAction == COMPACT_PROCESS_SOME) {
-                        action = "file";
+                        action = compactActionSome;
                     } else {
-                        action = "all";
+                        action = compactActionFull;
                     }
                     fos.write(action.getBytes());
                     fos.close();
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index c290fbe..353749f 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -45,6 +45,7 @@
 import android.os.UserHandle;
 import android.util.EventLog;
 import android.util.Slog;
+import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
@@ -157,6 +158,9 @@
     static final int BROADCAST_INTENT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG;
     static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1;
 
+    // log latency metrics for ordered broadcasts during BOOT_COMPLETED processing
+    boolean mLogLatencyMetrics = true;
+
     final BroadcastHandler mHandler;
 
     private final class BroadcastHandler extends Handler {
@@ -287,6 +291,9 @@
         r.curApp = app;
         app.curReceivers.add(r);
         app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
+        if (r.allowBackgroundActivityStarts) {
+            app.addAllowBackgroundActivityStartsToken(r);
+        }
         mService.mProcessList.updateLruProcessLocked(app, false, null);
         if (!skipOomAdj) {
             mService.updateOomAdjLocked();
@@ -415,6 +422,9 @@
         if (state == BroadcastRecord.IDLE) {
             Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
         }
+        if (r.allowBackgroundActivityStarts) {
+            r.curApp.removeAllowBackgroundActivityStartsToken(r);
+         }
         // If we're abandoning this broadcast before any receivers were actually spun up,
         // nextReceiver is zero; in which case time-to-process bookkeeping doesn't apply.
         if (r.nextReceiver > 0) {
@@ -935,6 +945,12 @@
                     // adjustments.
                     mService.updateOomAdjLocked();
                 }
+
+                // when we have no more ordered broadcast on this queue, stop logging
+                if (mService.mUserController.mBootCompleted && mLogLatencyMetrics) {
+                    mLogLatencyMetrics = false;
+                }
+
                 return;
             }
             r = mOrderedBroadcasts.get(0);
@@ -1030,6 +1046,13 @@
         if (recIdx == 0) {
             r.dispatchTime = r.receiverTime;
             r.dispatchClockTime = System.currentTimeMillis();
+
+            if (mLogLatencyMetrics) {
+                StatsLog.write(
+                        StatsLog.BROADCAST_DISPATCH_LATENCY_REPORTED,
+                        r.dispatchClockTime - r.enqueueClockTime);
+            }
+
             if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                 Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                     createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 9b7dc44..9e799f6 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -81,6 +81,10 @@
     int manifestSkipCount;  // number of manifest receivers skipped.
     BroadcastQueue queue;   // the outbound queue handling this broadcast
 
+    // if set to true, app's process will be temporarily whitelisted to start activities
+    // from background for the duration of the broadcast dispatch
+    final boolean allowBackgroundActivityStarts;
+
     static final int IDLE = 0;
     static final int APP_RECEIVE = 1;
     static final int CALL_IN_RECEIVE = 2;
@@ -223,7 +227,8 @@
             int _callingPid, int _callingUid, boolean _callerInstantApp, String _resolvedType,
             String[] _requiredPermissions, int _appOp, BroadcastOptions _options, List _receivers,
             IIntentReceiver _resultTo, int _resultCode, String _resultData, Bundle _resultExtras,
-            boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId) {
+            boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId,
+            boolean _allowBackgroundActivityStarts) {
         if (_intent == null) {
             throw new NullPointerException("Can't construct with a null intent");
         }
@@ -252,6 +257,7 @@
         userId = _userId;
         nextReceiver = 0;
         state = IDLE;
+        allowBackgroundActivityStarts = _allowBackgroundActivityStarts;
     }
 
     /**
@@ -295,6 +301,7 @@
         manifestCount = from.manifestCount;
         manifestSkipCount = from.manifestSkipCount;
         queue = from.queue;
+        allowBackgroundActivityStarts = from.allowBackgroundActivityStarts;
     }
 
     public BroadcastRecord maybeStripForHistory() {
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 65cd329..d3953b5 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -67,8 +67,10 @@
         sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS_GLES, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYER_APP, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, int.class);
-        sGlobalSettingToTypeMap.put(Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP,
-                                    String.class);
+        sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_ALL_APPS, int.class);
+        sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_OPT_IN_APPS, String.class);
+        sGlobalSettingToTypeMap.put(Settings.Global.GUP_DEV_OPT_OUT_APPS, String.class);
+        sGlobalSettingToTypeMap.put(Settings.Global.GUP_BLACKLIST, String.class);
         // add other global settings here...
     }
 
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
new file mode 100644
index 0000000..be910d4
--- /dev/null
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -0,0 +1,2107 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+import static android.os.Process.SCHED_OTHER;
+import static android.os.Process.THREAD_GROUP_BG_NONINTERACTIVE;
+import static android.os.Process.THREAD_GROUP_DEFAULT;
+import static android.os.Process.THREAD_GROUP_RESTRICTED;
+import static android.os.Process.THREAD_GROUP_TOP_APP;
+import static android.os.Process.setProcessGroup;
+import static android.os.Process.setThreadPriority;
+import static android.os.Process.setThreadScheduler;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ_REASON;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
+import static com.android.server.am.ActivityManagerService.DISPATCH_OOM_ADJ_OBSERVER_MSG;
+import static com.android.server.am.ActivityManagerService.DISPATCH_PROCESSES_CHANGED_UI_MSG;
+import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG;
+import static com.android.server.am.ActivityManagerService.TAG_BACKUP;
+import static com.android.server.am.ActivityManagerService.TAG_LRU;
+import static com.android.server.am.ActivityManagerService.TAG_OOM_ADJ;
+import static com.android.server.am.ActivityManagerService.TAG_PROCESS_OBSERVERS;
+import static com.android.server.am.ActivityManagerService.TAG_PSS;
+import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS;
+import static com.android.server.am.ActivityManagerService.TOP_APP_PRIORITY_BOOST;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
+
+import android.app.ActivityManager;
+import android.app.usage.UsageEvents;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Debug;
+import android.os.PowerManagerInternal;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.server.LocalServices;
+import com.android.server.wm.ActivityServiceConnectionsHolder;
+import com.android.server.wm.WindowProcessController;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * All of the code required to compute proc states and oom_adj values.
+ */
+public final class OomAdjuster {
+    private static final String TAG = "OomAdjuster";
+
+    /**
+     * For some direct access we need to power manager.
+     */
+    PowerManagerInternal mLocalPowerManager;
+
+    /**
+     * Service for compacting background apps.
+     */
+    AppCompactor mAppCompact;
+
+    ActivityManagerConstants mConstants;
+
+    final long[] mTmpLong = new long[3];
+
+    /**
+     * Current sequence id for oom_adj computation traversal.
+     */
+    int mAdjSeq = 0;
+
+    /**
+     * Keep track of the number of service processes we last found, to
+     * determine on the next iteration which should be B services.
+     */
+    int mNumServiceProcs = 0;
+    int mNewNumAServiceProcs = 0;
+    int mNewNumServiceProcs = 0;
+
+    /**
+     * Keep track of the non-cached/empty process we last found, to help
+     * determine how to distribute cached/empty processes next time.
+     */
+    int mNumNonCachedProcs = 0;
+
+    /**
+     * Keep track of the number of cached hidden procs, to balance oom adj
+     * distribution between those and empty procs.
+     */
+    int mNumCachedHiddenProcs = 0;
+
+    /** Track all uids that have actively running processes. */
+    ActiveUids mActiveUids;
+
+    private final ArraySet<BroadcastQueue> mTmpBroadcastQueue = new ArraySet();
+
+    private final ActivityManagerService mService;
+    private final ProcessList mProcessList;
+
+    OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
+        mService = service;
+        mProcessList = processList;
+        mActiveUids = activeUids;
+
+        mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class);
+        mConstants = mService.mConstants;
+        // mConstants can be null under test, which causes AppCompactor to crash
+        if (mConstants != null) {
+            mAppCompact = new AppCompactor(mService);
+        }
+    }
+
+    /**
+     * Update OomAdj for a specific process.
+     * @param app The process to update
+     * @param oomAdjAll If it's ok to call updateOomAdjLocked() for all running apps
+     *                  if necessary, or skip.
+     * @return whether updateOomAdjLocked(app) was successful.
+     */
+    @GuardedBy("mService")
+    final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) {
+        final ProcessRecord TOP_APP = mService.getTopAppLocked();
+        final boolean wasCached = app.cached;
+
+        mAdjSeq++;
+
+        // This is the desired cached adjusment we want to tell it to use.
+        // If our app is currently cached, we know it, and that is it.  Otherwise,
+        // we don't know it yet, and it needs to now be cached we will then
+        // need to do a complete oom adj.
+        final int cachedAdj = app.getCurRawAdj() >= ProcessList.CACHED_APP_MIN_ADJ
+                ? app.getCurRawAdj() : ProcessList.UNKNOWN_ADJ;
+        boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
+                SystemClock.uptimeMillis());
+        if (oomAdjAll
+                && (wasCached != app.cached || app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ)) {
+            // Changed to/from cached state, so apps after it in the LRU
+            // list may also be changed.
+            updateOomAdjLocked();
+        }
+        return success;
+    }
+
+    @GuardedBy("mService")
+    private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
+            ProcessRecord TOP_APP, boolean doingAll, long now) {
+        if (app.thread == null) {
+            return false;
+        }
+
+        computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now, false);
+
+        return applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
+    }
+
+    @GuardedBy("mService")
+    final void updateOomAdjLocked() {
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "updateOomAdj");
+        mService.mOomAdjProfiler.oomAdjStarted();
+        final ProcessRecord TOP_APP = mService.getTopAppLocked();
+        final long now = SystemClock.uptimeMillis();
+        final long nowElapsed = SystemClock.elapsedRealtime();
+        final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
+        final int N = mProcessList.getLruSizeLocked();
+
+        // Reset state in all uid records.
+        for (int  i = mActiveUids.size() - 1; i >= 0; i--) {
+            final UidRecord uidRec = mActiveUids.valueAt(i);
+            if (false && DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+                    "Starting update of " + uidRec);
+            uidRec.reset();
+        }
+
+        if (mService.mAtmInternal != null) {
+            mService.mAtmInternal.rankTaskLayersIfNeeded();
+        }
+
+        mAdjSeq++;
+        mNewNumServiceProcs = 0;
+        mNewNumAServiceProcs = 0;
+
+        final int emptyProcessLimit = mConstants.CUR_MAX_EMPTY_PROCESSES;
+        final int cachedProcessLimit = mConstants.CUR_MAX_CACHED_PROCESSES
+                - emptyProcessLimit;
+
+        // Let's determine how many processes we have running vs.
+        // how many slots we have for background processes; we may want
+        // to put multiple processes in a slot of there are enough of
+        // them.
+        final int numSlots = (ProcessList.CACHED_APP_MAX_ADJ
+                - ProcessList.CACHED_APP_MIN_ADJ + 1) / 2
+                / ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
+        int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs;
+        if (numEmptyProcs > cachedProcessLimit) {
+            // If there are more empty processes than our limit on cached
+            // processes, then use the cached process limit for the factor.
+            // This ensures that the really old empty processes get pushed
+            // down to the bottom, so if we are running low on memory we will
+            // have a better chance at keeping around more cached processes
+            // instead of a gazillion empty processes.
+            numEmptyProcs = cachedProcessLimit;
+        }
+        int emptyFactor = (numEmptyProcs + numSlots - 1) / numSlots;
+        if (emptyFactor < 1) emptyFactor = 1;
+        int cachedFactor = (mNumCachedHiddenProcs > 0 ? (mNumCachedHiddenProcs + numSlots - 1) : 1)
+                / numSlots;
+        if (cachedFactor < 1) cachedFactor = 1;
+        int stepCached = -1;
+        int stepEmpty = -1;
+        int numCached = 0;
+        int numCachedExtraGroup = 0;
+        int numEmpty = 0;
+        int numTrimming = 0;
+        int lastCachedGroup = 0;
+        int lastCachedGroupImportance = 0;
+        int lastCachedGroupUid = 0;
+
+        mNumNonCachedProcs = 0;
+        mNumCachedHiddenProcs = 0;
+
+        // First update the OOM adjustment for each of the
+        // application processes based on their current state.
+        int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
+        int nextCachedAdj = curCachedAdj + (ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2);
+        int curCachedImpAdj = 0;
+        int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
+        int nextEmptyAdj = curEmptyAdj + (ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2);
+
+        boolean retryCycles = false;
+
+        // need to reset cycle state before calling computeOomAdjLocked because of service conns
+        for (int i = N - 1; i >= 0; i--) {
+            ProcessRecord app = mProcessList.mLruProcesses.get(i);
+            app.containsCycle = false;
+            app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY);
+            app.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
+        }
+        for (int i = N - 1; i >= 0; i--) {
+            ProcessRecord app = mProcessList.mLruProcesses.get(i);
+            if (!app.killedByAm && app.thread != null) {
+                app.procStateChanged = false;
+                computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now, false);
+
+                // if any app encountered a cycle, we need to perform an additional loop later
+                retryCycles |= app.containsCycle;
+
+                // If we haven't yet assigned the final cached adj
+                // to the process, do that now.
+                if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
+                    switch (app.getCurProcState()) {
+                        case PROCESS_STATE_CACHED_ACTIVITY:
+                        case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+                        case ActivityManager.PROCESS_STATE_CACHED_RECENT:
+                            // Figure out the next cached level, taking into account groups.
+                            boolean inGroup = false;
+                            if (app.connectionGroup != 0) {
+                                if (lastCachedGroupUid == app.uid
+                                        && lastCachedGroup == app.connectionGroup) {
+                                    // This is in the same group as the last process, just tweak
+                                    // adjustment by importance.
+                                    if (app.connectionImportance > lastCachedGroupImportance) {
+                                        lastCachedGroupImportance = app.connectionImportance;
+                                        if (curCachedAdj < nextCachedAdj
+                                                && curCachedAdj < ProcessList.CACHED_APP_MAX_ADJ) {
+                                            curCachedImpAdj++;
+                                        }
+                                    }
+                                    inGroup = true;
+                                } else {
+                                    lastCachedGroupUid = app.uid;
+                                    lastCachedGroup = app.connectionGroup;
+                                    lastCachedGroupImportance = app.connectionImportance;
+                                }
+                            }
+                            if (!inGroup && curCachedAdj != nextCachedAdj) {
+                                stepCached++;
+                                curCachedImpAdj = 0;
+                                if (stepCached >= cachedFactor) {
+                                    stepCached = 0;
+                                    curCachedAdj = nextCachedAdj;
+                                    nextCachedAdj += ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
+                                    if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+                                        nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
+                                    }
+                                }
+                            }
+                            // This process is a cached process holding activities...
+                            // assign it the next cached value for that type, and then
+                            // step that cached level.
+                            app.setCurRawAdj(curCachedAdj + curCachedImpAdj);
+                            app.curAdj = app.modifyRawOomAdj(curCachedAdj + curCachedImpAdj);
+                            if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning activity LRU #" + i
+                                    + " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj
+                                    + " curCachedImpAdj=" + curCachedImpAdj + ")");
+                            break;
+                        default:
+                            // Figure out the next cached level.
+                            if (curEmptyAdj != nextEmptyAdj) {
+                                stepEmpty++;
+                                if (stepEmpty >= emptyFactor) {
+                                    stepEmpty = 0;
+                                    curEmptyAdj = nextEmptyAdj;
+                                    nextEmptyAdj += ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
+                                    if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+                                        nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
+                                    }
+                                }
+                            }
+                            // For everything else, assign next empty cached process
+                            // level and bump that up.  Note that this means that
+                            // long-running services that have dropped down to the
+                            // cached level will be treated as empty (since their process
+                            // state is still as a service), which is what we want.
+                            app.setCurRawAdj(curEmptyAdj);
+                            app.curAdj = app.modifyRawOomAdj(curEmptyAdj);
+                            if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning empty LRU #" + i
+                                    + " adj: " + app.curAdj + " (curEmptyAdj=" + curEmptyAdj
+                                    + ")");
+                            break;
+                    }
+                }
+            }
+        }
+
+        // Cycle strategy:
+        // - Retry computing any process that has encountered a cycle.
+        // - Continue retrying until no process was promoted.
+        // - Iterate from least important to most important.
+        int cycleCount = 0;
+        while (retryCycles && cycleCount < 10) {
+            cycleCount++;
+            retryCycles = false;
+
+            for (int i = 0; i < N; i++) {
+                ProcessRecord app = mProcessList.mLruProcesses.get(i);
+                if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
+                    app.adjSeq--;
+                    app.completedAdjSeq--;
+                }
+            }
+
+            for (int i = 0; i < N; i++) {
+                ProcessRecord app = mProcessList.mLruProcesses.get(i);
+                if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
+                    if (computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now,
+                            true)) {
+                        retryCycles = true;
+                    }
+                }
+            }
+        }
+
+        lastCachedGroup = lastCachedGroupUid = 0;
+
+        for (int i = N - 1; i >= 0; i--) {
+            ProcessRecord app = mProcessList.mLruProcesses.get(i);
+            if (!app.killedByAm && app.thread != null) {
+                applyOomAdjLocked(app, true, now, nowElapsed);
+
+                // Count the number of process types.
+                switch (app.getCurProcState()) {
+                    case PROCESS_STATE_CACHED_ACTIVITY:
+                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+                        mNumCachedHiddenProcs++;
+                        numCached++;
+                        if (app.connectionGroup != 0) {
+                            if (lastCachedGroupUid == app.uid
+                                    && lastCachedGroup == app.connectionGroup) {
+                                // If this process is the next in the same group, we don't
+                                // want it to count against our limit of the number of cached
+                                // processes, so bump up the group count to account for it.
+                                numCachedExtraGroup++;
+                            } else {
+                                lastCachedGroupUid = app.uid;
+                                lastCachedGroup = app.connectionGroup;
+                            }
+                        } else {
+                            lastCachedGroupUid = lastCachedGroup = 0;
+                        }
+                        if ((numCached - numCachedExtraGroup) > cachedProcessLimit) {
+                            app.kill("cached #" + numCached, true);
+                        }
+                        break;
+                    case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
+                        if (numEmpty > mConstants.CUR_TRIM_EMPTY_PROCESSES
+                                && app.lastActivityTime < oldTime) {
+                            app.kill("empty for "
+                                    + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
+                                    / 1000) + "s", true);
+                        } else {
+                            numEmpty++;
+                            if (numEmpty > emptyProcessLimit) {
+                                app.kill("empty #" + numEmpty, true);
+                            }
+                        }
+                        break;
+                    default:
+                        mNumNonCachedProcs++;
+                        break;
+                }
+
+                if (app.isolated && app.services.size() <= 0 && app.isolatedEntryPoint == null) {
+                    // If this is an isolated process, there are no services
+                    // running in it, and it's not a special process with a
+                    // custom entry point, then the process is no longer
+                    // needed.  We agressively kill these because we can by
+                    // definition not re-use the same process again, and it is
+                    // good to avoid having whatever code was running in them
+                    // left sitting around after no longer needed.
+                    app.kill("isolated not needed", true);
+                } else {
+                    // Keeping this process, update its uid.
+                    final UidRecord uidRec = app.uidRecord;
+                    if (uidRec != null) {
+                        uidRec.ephemeral = app.info.isInstantApp();
+                        if (uidRec.getCurProcState() > app.getCurProcState()) {
+                            uidRec.setCurProcState(app.getCurProcState());
+                        }
+                        if (app.hasForegroundServices()) {
+                            uidRec.foregroundServices = true;
+                        }
+                    }
+                }
+
+                if (app.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME
+                        && !app.killedByAm) {
+                    numTrimming++;
+                }
+            }
+        }
+
+        mService.incrementProcStateSeqAndNotifyAppsLocked();
+
+        mNumServiceProcs = mNewNumServiceProcs;
+
+        boolean allChanged = mService.updateLowMemStateLocked(numCached, numEmpty, numTrimming);
+
+        if (mService.mAlwaysFinishActivities) {
+            // Need to do this on its own message because the stack may not
+            // be in a consistent state at this point.
+            mService.mAtmInternal.scheduleDestroyAllActivities("always-finish");
+        }
+
+        if (allChanged) {
+            mService.requestPssAllProcsLocked(now, false,
+                    mService.mProcessStats.isMemFactorLowered());
+        }
+
+        ArrayList<UidRecord> becameIdle = null;
+
+        // Update from any uid changes.
+        if (mLocalPowerManager != null) {
+            mLocalPowerManager.startUidChanges();
+        }
+        for (int i = mActiveUids.size() - 1; i >= 0; i--) {
+            final UidRecord uidRec = mActiveUids.valueAt(i);
+            int uidChange = UidRecord.CHANGE_PROCSTATE;
+            if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT
+                    && (uidRec.setProcState != uidRec.getCurProcState()
+                    || uidRec.setWhitelist != uidRec.curWhitelist)) {
+                if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "Changes in " + uidRec
+                        + ": proc state from " + uidRec.setProcState + " to "
+                        + uidRec.getCurProcState() + ", whitelist from " + uidRec.setWhitelist
+                        + " to " + uidRec.curWhitelist);
+                if (ActivityManager.isProcStateBackground(uidRec.getCurProcState())
+                        && !uidRec.curWhitelist) {
+                    // UID is now in the background (and not on the temp whitelist).  Was it
+                    // previously in the foreground (or on the temp whitelist)?
+                    if (!ActivityManager.isProcStateBackground(uidRec.setProcState)
+                            || uidRec.setWhitelist) {
+                        uidRec.lastBackgroundTime = nowElapsed;
+                        if (!mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
+                            // Note: the background settle time is in elapsed realtime, while
+                            // the handler time base is uptime.  All this means is that we may
+                            // stop background uids later than we had intended, but that only
+                            // happens because the device was sleeping so we are okay anyway.
+                            mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
+                                    mConstants.BACKGROUND_SETTLE_TIME);
+                        }
+                    }
+                    if (uidRec.idle && !uidRec.setIdle) {
+                        uidChange = UidRecord.CHANGE_IDLE;
+                        if (becameIdle == null) {
+                            becameIdle = new ArrayList<>();
+                        }
+                        becameIdle.add(uidRec);
+                    }
+                } else {
+                    if (uidRec.idle) {
+                        uidChange = UidRecord.CHANGE_ACTIVE;
+                        EventLogTags.writeAmUidActive(uidRec.uid);
+                        uidRec.idle = false;
+                    }
+                    uidRec.lastBackgroundTime = 0;
+                }
+                final boolean wasCached = uidRec.setProcState
+                        > ActivityManager.PROCESS_STATE_RECEIVER;
+                final boolean isCached = uidRec.getCurProcState()
+                        > ActivityManager.PROCESS_STATE_RECEIVER;
+                if (wasCached != isCached || uidRec.setProcState == PROCESS_STATE_NONEXISTENT) {
+                    uidChange |= isCached ? UidRecord.CHANGE_CACHED : UidRecord.CHANGE_UNCACHED;
+                }
+                uidRec.setProcState = uidRec.getCurProcState();
+                uidRec.setWhitelist = uidRec.curWhitelist;
+                uidRec.setIdle = uidRec.idle;
+                mService.enqueueUidChangeLocked(uidRec, -1, uidChange);
+                mService.noteUidProcessState(uidRec.uid, uidRec.getCurProcState());
+                if (uidRec.foregroundServices) {
+                    mService.mServices.foregroundServiceProcStateChangedLocked(uidRec);
+                }
+            }
+        }
+        if (mLocalPowerManager != null) {
+            mLocalPowerManager.finishUidChanges();
+        }
+
+        if (becameIdle != null) {
+            // If we have any new uids that became idle this time, we need to make sure
+            // they aren't left with running services.
+            for (int i = becameIdle.size() - 1; i >= 0; i--) {
+                mService.mServices.stopInBackgroundLocked(becameIdle.get(i).uid);
+            }
+        }
+
+        if (mService.mProcessStats.shouldWriteNowLocked(now)) {
+            mService.mHandler.post(new ActivityManagerService.ProcStatsRunnable(mService,
+                    mService.mProcessStats));
+        }
+
+        // Run this after making sure all procstates are updated.
+        mService.mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);
+
+        if (DEBUG_OOM_ADJ) {
+            final long duration = SystemClock.uptimeMillis() - now;
+            if (false) {
+                Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms",
+                        new RuntimeException("here").fillInStackTrace());
+            } else {
+                Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms");
+            }
+        }
+        mService.mOomAdjProfiler.oomAdjEnded();
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+    }
+
+    private final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback =
+            new ComputeOomAdjWindowCallback();
+
+    /** These methods are called inline during computeOomAdjLocked(), on the same thread */
+    private final class ComputeOomAdjWindowCallback
+            implements WindowProcessController.ComputeOomAdjCallback {
+
+        ProcessRecord app;
+        int adj;
+        boolean foregroundActivities;
+        int procState;
+        int schedGroup;
+        int appUid;
+        int logUid;
+        int processStateCurTop;
+
+        void initialize(ProcessRecord app, int adj, boolean foregroundActivities,
+                int procState, int schedGroup, int appUid, int logUid, int processStateCurTop) {
+            this.app = app;
+            this.adj = adj;
+            this.foregroundActivities = foregroundActivities;
+            this.procState = procState;
+            this.schedGroup = schedGroup;
+            this.appUid = appUid;
+            this.logUid = logUid;
+            this.processStateCurTop = processStateCurTop;
+        }
+
+        @Override
+        public void onVisibleActivity() {
+            // App has a visible activity; only upgrade adjustment.
+            if (adj > ProcessList.VISIBLE_APP_ADJ) {
+                adj = ProcessList.VISIBLE_APP_ADJ;
+                app.adjType = "vis-activity";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to vis-activity: " + app);
+                }
+            }
+            if (procState > processStateCurTop) {
+                procState = processStateCurTop;
+                app.adjType = "vis-activity";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                            "Raise procstate to vis-activity (top): " + app);
+                }
+            }
+            if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+            }
+            app.cached = false;
+            app.empty = false;
+            foregroundActivities = true;
+        }
+
+        @Override
+        public void onPausedActivity() {
+            if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+                app.adjType = "pause-activity";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to pause-activity: "  + app);
+                }
+            }
+            if (procState > processStateCurTop) {
+                procState = processStateCurTop;
+                app.adjType = "pause-activity";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                            "Raise procstate to pause-activity (top): "  + app);
+                }
+            }
+            if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+            }
+            app.cached = false;
+            app.empty = false;
+            foregroundActivities = true;
+        }
+
+        @Override
+        public void onStoppingActivity(boolean finishing) {
+            if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+                app.adjType = "stop-activity";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                            "Raise adj to stop-activity: "  + app);
+                }
+            }
+
+            // For the process state, we will at this point consider the process to be cached. It
+            // will be cached either as an activity or empty depending on whether the activity is
+            // finishing. We do this so that we can treat the process as cached for purposes of
+            // memory trimming (determining current memory level, trim command to send to process)
+            // since there can be an arbitrary number of stopping processes and they should soon all
+            // go into the cached state.
+            if (!finishing) {
+                if (procState > PROCESS_STATE_LAST_ACTIVITY) {
+                    procState = PROCESS_STATE_LAST_ACTIVITY;
+                    app.adjType = "stop-activity";
+                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                "Raise procstate to stop-activity: " + app);
+                    }
+                }
+            }
+            app.cached = false;
+            app.empty = false;
+            foregroundActivities = true;
+        }
+
+        @Override
+        public void onOtherActivity() {
+            if (procState > PROCESS_STATE_CACHED_ACTIVITY) {
+                procState = PROCESS_STATE_CACHED_ACTIVITY;
+                app.adjType = "cch-act";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                            "Raise procstate to cached activity: " + app);
+                }
+            }
+        }
+    }
+
+    private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
+            ProcessRecord TOP_APP, boolean doingAll, long now, boolean cycleReEval) {
+        if (mAdjSeq == app.adjSeq) {
+            if (app.adjSeq == app.completedAdjSeq) {
+                // This adjustment has already been computed successfully.
+                return false;
+            } else {
+                // The process is being computed, so there is a cycle. We cannot
+                // rely on this process's state.
+                app.containsCycle = true;
+
+                return false;
+            }
+        }
+
+        if (app.thread == null) {
+            app.adjSeq = mAdjSeq;
+            app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_BACKGROUND);
+            app.setCurProcState(ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+            app.curAdj = ProcessList.CACHED_APP_MAX_ADJ;
+            app.setCurRawAdj(ProcessList.CACHED_APP_MAX_ADJ);
+            app.completedAdjSeq = app.adjSeq;
+            return false;
+        }
+
+        app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
+        app.adjSource = null;
+        app.adjTarget = null;
+        app.empty = false;
+        app.cached = false;
+
+        final WindowProcessController wpc = app.getWindowProcessController();
+        final int appUid = app.info.uid;
+        final int logUid = mService.mCurOomAdjUid;
+
+        int prevAppAdj = app.curAdj;
+        int prevProcState = app.getCurProcState();
+
+        if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+            // The max adjustment doesn't allow this app to be anything
+            // below foreground, so it is not worth doing work for it.
+            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                mService.reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making fixed: " + app);
+            }
+            app.adjType = "fixed";
+            app.adjSeq = mAdjSeq;
+            app.setCurRawAdj(app.maxAdj);
+            app.setHasForegroundActivities(false);
+            app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
+            app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT);
+            // System processes can do UI, and when they do we want to have
+            // them trim their memory after the user leaves the UI.  To
+            // facilitate this, here we need to determine whether or not it
+            // is currently showing UI.
+            app.systemNoUi = true;
+            if (app == TOP_APP) {
+                app.systemNoUi = false;
+                app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
+                app.adjType = "pers-top-activity";
+            } else if (app.hasTopUi()) {
+                // sched group/proc state adjustment is below
+                app.systemNoUi = false;
+                app.adjType = "pers-top-ui";
+            } else if (wpc.hasVisibleActivities()) {
+                app.systemNoUi = false;
+            }
+            if (!app.systemNoUi) {
+                if (mService.mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
+                    // screen on, promote UI
+                    app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
+                    app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
+                } else {
+                    // screen off, restrict UI scheduling
+                    app.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
+                    app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
+                }
+            }
+            app.setCurRawProcState(app.getCurProcState());
+            app.curAdj = app.maxAdj;
+            app.completedAdjSeq = app.adjSeq;
+            // if curAdj is less than prevAppAdj, then this process was promoted
+            return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
+        }
+
+        app.systemNoUi = false;
+
+        final int PROCESS_STATE_CUR_TOP = mService.mAtmInternal.getTopProcessState();
+
+        // Determine the importance of the process, starting with most
+        // important to least, and assign an appropriate OOM adjustment.
+        int adj;
+        int schedGroup;
+        int procState;
+        int cachedAdjSeq;
+
+        boolean foregroundActivities = false;
+        mTmpBroadcastQueue.clear();
+        if (PROCESS_STATE_CUR_TOP == ActivityManager.PROCESS_STATE_TOP && app == TOP_APP) {
+            // The last app on the list is the foreground app.
+            adj = ProcessList.FOREGROUND_APP_ADJ;
+            schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+            app.adjType = "top-activity";
+            foregroundActivities = true;
+            procState = PROCESS_STATE_CUR_TOP;
+            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app);
+            }
+        } else if (app.runningRemoteAnimation) {
+            adj = ProcessList.VISIBLE_APP_ADJ;
+            schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+            app.adjType = "running-remote-anim";
+            procState = PROCESS_STATE_CUR_TOP;
+            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making running remote anim: " + app);
+            }
+        } else if (app.getActiveInstrumentation() != null) {
+            // Don't want to kill running instrumentation.
+            adj = ProcessList.FOREGROUND_APP_ADJ;
+            schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+            app.adjType = "instrumentation";
+            procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making instrumentation: " + app);
+            }
+        } else if (mService.isReceivingBroadcastLocked(app, mTmpBroadcastQueue)) {
+            // An app that is currently receiving a broadcast also
+            // counts as being in the foreground for OOM killer purposes.
+            // It's placed in a sched group based on the nature of the
+            // broadcast as reflected by which queue it's active in.
+            adj = ProcessList.FOREGROUND_APP_ADJ;
+            schedGroup = (mTmpBroadcastQueue.contains(mService.mFgBroadcastQueue))
+                    ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
+            app.adjType = "broadcast";
+            procState = ActivityManager.PROCESS_STATE_RECEIVER;
+            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making broadcast: " + app);
+            }
+        } else if (app.executingServices.size() > 0) {
+            // An app that is currently executing a service callback also
+            // counts as being in the foreground.
+            adj = ProcessList.FOREGROUND_APP_ADJ;
+            schedGroup = app.execServicesFg ?
+                    ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
+            app.adjType = "exec-service";
+            procState = ActivityManager.PROCESS_STATE_SERVICE;
+            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making exec-service: " + app);
+            }
+            //Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
+        } else if (app == TOP_APP) {
+            adj = ProcessList.FOREGROUND_APP_ADJ;
+            schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
+            app.adjType = "top-sleeping";
+            foregroundActivities = true;
+            procState = PROCESS_STATE_CUR_TOP;
+            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top (sleeping): " + app);
+            }
+        } else {
+            // As far as we know the process is empty.  We may change our mind later.
+            schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
+            // At this point we don't actually know the adjustment.  Use the cached adj
+            // value that the caller wants us to.
+            adj = cachedAdj;
+            procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+            app.cached = true;
+            app.empty = true;
+            app.adjType = "cch-empty";
+            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making empty: " + app);
+            }
+        }
+
+        // Examine all activities if not already foreground.
+        if (!foregroundActivities && wpc.hasActivities()) {
+            mTmpComputeOomAdjWindowCallback.initialize(app, adj, foregroundActivities, procState,
+                    schedGroup, appUid, logUid, PROCESS_STATE_CUR_TOP);
+            final int minLayer = wpc.computeOomAdjFromActivities(
+                    ProcessList.VISIBLE_APP_LAYER_MAX, mTmpComputeOomAdjWindowCallback);
+
+            adj = mTmpComputeOomAdjWindowCallback.adj;
+            foregroundActivities = mTmpComputeOomAdjWindowCallback.foregroundActivities;
+            procState = mTmpComputeOomAdjWindowCallback.procState;
+            schedGroup = mTmpComputeOomAdjWindowCallback.schedGroup;
+
+            if (adj == ProcessList.VISIBLE_APP_ADJ) {
+                adj += minLayer;
+            }
+        }
+
+        if (procState > ActivityManager.PROCESS_STATE_CACHED_RECENT && app.hasRecentTasks()) {
+            procState = ActivityManager.PROCESS_STATE_CACHED_RECENT;
+            app.adjType = "cch-rec";
+            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to cached recent: " + app);
+            }
+        }
+
+        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
+                || procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+            if (app.hasForegroundServices()) {
+                // The user is aware of this app, so make it visible.
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+                procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+                app.cached = false;
+                app.adjType = "fg-service";
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to fg service: " + app);
+                }
+            } else if (app.hasOverlayUi()) {
+                // The process is display an overlay UI.
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+                procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                app.cached = false;
+                app.adjType = "has-overlay-ui";
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to overlay ui: " + app);
+                }
+            }
+        }
+
+        // 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) {
+                // This is currently used for toasts...  they are not interactive, and
+                // we don't want them to cause the app to become fully foreground (and
+                // thus out of background check), so we yes the best background level we can.
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+                procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+                app.cached = false;
+                app.adjType = "force-imp";
+                app.adjSource = app.forcingToImportant;
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to force imp: " + app);
+                }
+            }
+        }
+
+        if (mService.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;
+                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
+                app.cached = false;
+                app.adjType = "heavy";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to heavy: " + app);
+                }
+            }
+            if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
+                procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+                app.adjType = "heavy";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to heavy: " + app);
+                }
+            }
+        }
+
+        if (wpc.isHomeProcess()) {
+            if (adj > ProcessList.HOME_APP_ADJ) {
+                // This process is hosting what we currently consider to be the
+                // home app, so we don't want to let it go into the background.
+                adj = ProcessList.HOME_APP_ADJ;
+                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
+                app.cached = false;
+                app.adjType = "home";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to home: " + app);
+                }
+            }
+            if (procState > ActivityManager.PROCESS_STATE_HOME) {
+                procState = ActivityManager.PROCESS_STATE_HOME;
+                app.adjType = "home";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to home: " + app);
+                }
+            }
+        }
+
+        if (wpc.isPreviousProcess() && app.hasActivities()) {
+            if (adj > ProcessList.PREVIOUS_APP_ADJ) {
+                // This was the previous process that showed UI to the user.
+                // We want to try to keep it around more aggressively, to give
+                // a good experience around switching between two apps.
+                adj = ProcessList.PREVIOUS_APP_ADJ;
+                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
+                app.cached = false;
+                app.adjType = "previous";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to prev: " + app);
+                }
+            }
+            if (procState > PROCESS_STATE_LAST_ACTIVITY) {
+                procState = PROCESS_STATE_LAST_ACTIVITY;
+                app.adjType = "previous";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to prev: " + app);
+                }
+            }
+        }
+
+        if (false) Slog.i(TAG, "OOM " + app + ": initial adj=" + adj
+                + " reason=" + app.adjType);
+
+        // By default, we use the computed adjustment.  It may be changed if
+        // there are applications dependent on our services or providers, but
+        // this gives us a baseline and makes sure we don't get into an
+        // infinite recursion. If we're re-evaluating due to cycles, use the previously computed
+        // values.
+        app.setCurRawAdj(!cycleReEval ? adj : Math.min(adj, app.getCurRawAdj()));
+        app.setCurRawProcState(!cycleReEval
+                ? procState
+                : Math.min(procState, app.getCurRawProcState()));
+
+        app.hasStartedServices = false;
+        app.adjSeq = mAdjSeq;
+
+        final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);
+        if (backupTarget != null && app == backupTarget.app) {
+            // If possible we want to avoid killing apps while they're being backed up
+            if (adj > ProcessList.BACKUP_APP_ADJ) {
+                if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
+                adj = ProcessList.BACKUP_APP_ADJ;
+                if (procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+                    procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+                }
+                app.adjType = "backup";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to backup: " + app);
+                }
+                app.cached = false;
+            }
+            if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
+                procState = ActivityManager.PROCESS_STATE_BACKUP;
+                app.adjType = "backup";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to backup: " + app);
+                }
+            }
+        }
+
+        boolean mayBeTop = false;
+        String mayBeTopType = null;
+        Object mayBeTopSource = null;
+        Object mayBeTopTarget = null;
+
+        for (int is = app.services.size() - 1;
+                is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+                        || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
+                        || procState > ActivityManager.PROCESS_STATE_TOP);
+                is--) {
+            ServiceRecord s = app.services.valueAt(is);
+            if (s.startRequested) {
+                app.hasStartedServices = true;
+                if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
+                    procState = ActivityManager.PROCESS_STATE_SERVICE;
+                    app.adjType = "started-services";
+                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                "Raise procstate to started service: " + app);
+                    }
+                }
+                if (app.hasShownUi && !wpc.isHomeProcess()) {
+                    // If this process has shown some UI, let it immediately
+                    // go to the LRU list because it may be pretty heavy with
+                    // UI stuff.  We'll tag it with a label just to help
+                    // debug and understand what is going on.
+                    if (adj > ProcessList.SERVICE_ADJ) {
+                        app.adjType = "cch-started-ui-services";
+                    }
+                } else {
+                    if (now < (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
+                        // This service has seen some activity within
+                        // recent memory, so we will keep its process ahead
+                        // of the background processes.
+                        if (adj > ProcessList.SERVICE_ADJ) {
+                            adj = ProcessList.SERVICE_ADJ;
+                            app.adjType = "started-services";
+                            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                                reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                        "Raise adj to started service: " + app);
+                            }
+                            app.cached = false;
+                        }
+                    }
+                    // If we have let the service slide into the background
+                    // state, still have some text describing what it is doing
+                    // even though the service no longer has an impact.
+                    if (adj > ProcessList.SERVICE_ADJ) {
+                        app.adjType = "cch-started-services";
+                    }
+                }
+            }
+
+            for (int conni = s.connections.size() - 1;
+                    conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+                            || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
+                            || procState > ActivityManager.PROCESS_STATE_TOP);
+                    conni--) {
+                ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
+                for (int i = 0;
+                        i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
+                                || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
+                                || procState > ActivityManager.PROCESS_STATE_TOP);
+                        i++) {
+                    // XXX should compute this based on the max of
+                    // all connected clients.
+                    ConnectionRecord cr = clist.get(i);
+                    if (cr.binding.client == app) {
+                        // Binding to oneself is not interesting.
+                        continue;
+                    }
+
+                    boolean trackedProcState = false;
+                    if ((cr.flags& Context.BIND_WAIVE_PRIORITY) == 0) {
+                        ProcessRecord client = cr.binding.client;
+                        computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now, cycleReEval);
+
+                        if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
+                            continue;
+                        }
+
+                        int clientAdj = client.getCurRawAdj();
+                        int clientProcState = client.getCurRawProcState();
+
+                        if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
+                            // If the other app is cached for any reason, for purposes here
+                            // we are going to consider it empty.  The specific cached state
+                            // doesn't propagate except under certain conditions.
+                            clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+                        }
+                        String adjType = null;
+                        if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
+                            // Not doing bind OOM management, so treat
+                            // this guy more like a started service.
+                            if (app.hasShownUi && !wpc.isHomeProcess()) {
+                                // If this process has shown some UI, let it immediately
+                                // go to the LRU list because it may be pretty heavy with
+                                // UI stuff.  We'll tag it with a label just to help
+                                // debug and understand what is going on.
+                                if (adj > clientAdj) {
+                                    adjType = "cch-bound-ui-services";
+                                }
+                                app.cached = false;
+                                clientAdj = adj;
+                                clientProcState = procState;
+                            } else {
+                                if (now >= (s.lastActivity
+                                        + mConstants.MAX_SERVICE_INACTIVITY)) {
+                                    // This service has not seen activity within
+                                    // recent memory, so allow it to drop to the
+                                    // LRU list if there is no other reason to keep
+                                    // it around.  We'll also tag it with a label just
+                                    // to help debug and undertand what is going on.
+                                    if (adj > clientAdj) {
+                                        adjType = "cch-bound-services";
+                                    }
+                                    clientAdj = adj;
+                                }
+                            }
+                        }
+                        if (adj > clientAdj) {
+                            // If this process has recently shown UI, and
+                            // the process that is binding to it is less
+                            // important than being visible, then we don't
+                            // care about the binding as much as we care
+                            // about letting this process get into the LRU
+                            // list to be killed and restarted if needed for
+                            // memory.
+                            if (app.hasShownUi && !wpc.isHomeProcess()
+                                    && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                                if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
+                                    adjType = "cch-bound-ui-services";
+                                }
+                            } else {
+                                int newAdj;
+                                if ((cr.flags&(Context.BIND_ABOVE_CLIENT
+                                        |Context.BIND_IMPORTANT)) != 0) {
+                                    if (clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
+                                        newAdj = clientAdj;
+                                    } else {
+                                        // make this service persistent
+                                        newAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
+                                        schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+                                        procState = ActivityManager.PROCESS_STATE_PERSISTENT;
+                                        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) {
+                                    newAdj = ProcessList.PERCEPTIBLE_APP_ADJ;
+                                } else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
+                                    newAdj = clientAdj;
+                                } else {
+                                    if (adj > ProcessList.VISIBLE_APP_ADJ) {
+                                        newAdj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
+                                    } else {
+                                        newAdj = adj;
+                                    }
+                                }
+                                if (!client.cached) {
+                                    app.cached = false;
+                                }
+                                if (adj >  newAdj) {
+                                    adj = newAdj;
+                                    app.setCurRawAdj(adj);
+                                    adjType = "service";
+                                }
+                            }
+                        }
+                        if ((cr.flags & (Context.BIND_NOT_FOREGROUND
+                                | Context.BIND_IMPORTANT_BACKGROUND)) == 0) {
+                            // This will treat important bound services identically to
+                            // the top app, which may behave differently than generic
+                            // foreground work.
+                            final int curSchedGroup = client.getCurrentSchedulingGroup();
+                            if (curSchedGroup > schedGroup) {
+                                if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
+                                    schedGroup = curSchedGroup;
+                                } else {
+                                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+                                }
+                            }
+                            if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
+                                if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
+                                    // Special handling of clients who are in the top state.
+                                    // We *may* want to consider this process to be in the
+                                    // top state as well, but only if there is not another
+                                    // reason for it to be running.  Being on the top is a
+                                    // special state, meaning you are specifically running
+                                    // for the current top app.  If the process is already
+                                    // running in the background for some other reason, it
+                                    // is more important to continue considering it to be
+                                    // in the background state.
+                                    mayBeTop = true;
+                                    mayBeTopType = "service";
+                                    mayBeTopSource = cr.binding.client;
+                                    mayBeTopTarget = s.instanceName;
+                                    clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+                                } else {
+                                    // Special handling for above-top states (persistent
+                                    // processes).  These should not bring the current process
+                                    // into the top state, since they are not on top.  Instead
+                                    // give them the best state after that.
+                                    if ((cr.flags&Context.BIND_FOREGROUND_SERVICE) != 0) {
+                                        clientProcState =
+                                                ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+                                    } else if (mService.mWakefulness
+                                            == PowerManagerInternal.WAKEFULNESS_AWAKE &&
+                                            (cr.flags&Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
+                                                    != 0) {
+                                        clientProcState =
+                                                ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+                                    } else {
+                                        clientProcState =
+                                                ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                                    }
+                                }
+                            }
+                        } else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
+                            if (clientProcState <
+                                    ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+                                clientProcState =
+                                        ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+                            }
+                        } else {
+                            if (clientProcState <
+                                    ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
+                                clientProcState =
+                                        ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+                            }
+                        }
+                        if (!trackedProcState) {
+                            cr.trackProcState(clientProcState, mAdjSeq, now);
+                        }
+                        if (procState > clientProcState) {
+                            procState = clientProcState;
+                            app.setCurRawProcState(procState);
+                            if (adjType == null) {
+                                adjType = "service";
+                            }
+                        }
+                        if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+                                && (cr.flags & Context.BIND_SHOWING_UI) != 0) {
+                            app.setPendingUiClean(true);
+                        }
+                        if (adjType != null) {
+                            app.adjType = adjType;
+                            app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+                                    .REASON_SERVICE_IN_USE;
+                            app.adjSource = cr.binding.client;
+                            app.adjSourceProcState = clientProcState;
+                            app.adjTarget = s.instanceName;
+                            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
+                                        + ": " + app + ", due to " + cr.binding.client
+                                        + " adj=" + adj + " procState="
+                                        + ProcessList.makeProcStateString(procState));
+                            }
+                        }
+                    }
+                    if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
+                        app.treatLikeActivity = true;
+                    }
+                    final ActivityServiceConnectionsHolder a = cr.activity;
+                    if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
+                        if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ
+                                && a.isActivityVisible()) {
+                            adj = ProcessList.FOREGROUND_APP_ADJ;
+                            app.setCurRawAdj(adj);
+                            if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+                                if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
+                                    schedGroup = ProcessList.SCHED_GROUP_TOP_APP_BOUND;
+                                } else {
+                                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+                                }
+                            }
+                            app.cached = false;
+                            app.adjType = "service";
+                            app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+                                    .REASON_SERVICE_IN_USE;
+                            app.adjSource = a;
+                            app.adjSourceProcState = procState;
+                            app.adjTarget = s.instanceName;
+                            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                                reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                        "Raise to service w/activity: " + app);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        for (int provi = app.pubProviders.size() - 1;
+                provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+                        || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
+                        || procState > ActivityManager.PROCESS_STATE_TOP);
+                provi--) {
+            ContentProviderRecord cpr = app.pubProviders.valueAt(provi);
+            for (int i = cpr.connections.size() - 1;
+                    i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+                            || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
+                            || procState > ActivityManager.PROCESS_STATE_TOP);
+                    i--) {
+                ContentProviderConnection conn = cpr.connections.get(i);
+                ProcessRecord client = conn.client;
+                if (client == app) {
+                    // Being our own client is not interesting.
+                    continue;
+                }
+                computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now, cycleReEval);
+
+                if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) {
+                    continue;
+                }
+
+                int clientAdj = client.getCurRawAdj();
+                int clientProcState = client.getCurRawProcState();
+
+                if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
+                    // If the other app is cached for any reason, for purposes here
+                    // we are going to consider it empty.
+                    clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+                }
+                String adjType = null;
+                if (adj > clientAdj) {
+                    if (app.hasShownUi && !wpc.isHomeProcess()
+                            && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                        adjType = "cch-ui-provider";
+                    } else {
+                        adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
+                                ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
+                        app.setCurRawAdj(adj);
+                        adjType = "provider";
+                    }
+                    app.cached &= client.cached;
+                }
+                if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
+                    if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
+                        // Special handling of clients who are in the top state.
+                        // We *may* want to consider this process to be in the
+                        // top state as well, but only if there is not another
+                        // reason for it to be running.  Being on the top is a
+                        // special state, meaning you are specifically running
+                        // for the current top app.  If the process is already
+                        // running in the background for some other reason, it
+                        // is more important to continue considering it to be
+                        // in the background state.
+                        mayBeTop = true;
+                        clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+                        mayBeTopType = adjType = "provider-top";
+                        mayBeTopSource = client;
+                        mayBeTopTarget = cpr.name;
+                    } else {
+                        // Special handling for above-top states (persistent
+                        // processes).  These should not bring the current process
+                        // into the top state, since they are not on top.  Instead
+                        // give them the best state after that.
+                        clientProcState =
+                                ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+                        if (adjType == null) {
+                            adjType = "provider";
+                        }
+                    }
+                }
+                conn.trackProcState(clientProcState, mAdjSeq, now);
+                if (procState > clientProcState) {
+                    procState = clientProcState;
+                    app.setCurRawProcState(procState);
+                }
+                if (client.getCurrentSchedulingGroup() > schedGroup) {
+                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+                }
+                if (adjType != null) {
+                    app.adjType = adjType;
+                    app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+                            .REASON_PROVIDER_IN_USE;
+                    app.adjSource = client;
+                    app.adjSourceProcState = clientProcState;
+                    app.adjTarget = cpr.name;
+                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                        reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
+                                + ": " + app + ", due to " + client
+                                + " adj=" + adj + " procState="
+                                + ProcessList.makeProcStateString(procState));
+                    }
+                }
+            }
+            // If the provider has external (non-framework) process
+            // dependencies, ensure that its adjustment is at least
+            // FOREGROUND_APP_ADJ.
+            if (cpr.hasExternalProcessHandles()) {
+                if (adj > ProcessList.FOREGROUND_APP_ADJ) {
+                    adj = ProcessList.FOREGROUND_APP_ADJ;
+                    app.setCurRawAdj(adj);
+                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+                    app.cached = false;
+                    app.adjType = "ext-provider";
+                    app.adjTarget = cpr.name;
+                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                "Raise adj to external provider: " + app);
+                    }
+                }
+                if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+                    procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                    app.setCurRawProcState(procState);
+                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                "Raise procstate to external provider: " + app);
+                    }
+                }
+            }
+        }
+
+        if (app.lastProviderTime > 0 &&
+                (app.lastProviderTime + mConstants.CONTENT_PROVIDER_RETAIN_TIME) > now) {
+            if (adj > ProcessList.PREVIOUS_APP_ADJ) {
+                adj = ProcessList.PREVIOUS_APP_ADJ;
+                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
+                app.cached = false;
+                app.adjType = "recent-provider";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                            "Raise adj to recent provider: " + app);
+                }
+            }
+            if (procState > PROCESS_STATE_LAST_ACTIVITY) {
+                procState = PROCESS_STATE_LAST_ACTIVITY;
+                app.adjType = "recent-provider";
+                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                            "Raise procstate to recent provider: " + app);
+                }
+            }
+        }
+
+        if (mayBeTop && procState > ActivityManager.PROCESS_STATE_TOP) {
+            // A client of one of our services or providers is in the top state.  We
+            // *may* want to be in the top state, but not if we are already running in
+            // the background for some other reason.  For the decision here, we are going
+            // to pick out a few specific states that we want to remain in when a client
+            // is top (states that tend to be longer-term) and otherwise allow it to go
+            // to the top state.
+            switch (procState) {
+                case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
+                case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
+                    // Something else is keeping it at this level, just leave it.
+                    break;
+                case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
+                case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
+                case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
+                case ActivityManager.PROCESS_STATE_SERVICE:
+                    // These all are longer-term states, so pull them up to the top
+                    // of the background states, but not all the way to the top state.
+                    procState = ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+                    app.adjType = mayBeTopType;
+                    app.adjSource = mayBeTopSource;
+                    app.adjTarget = mayBeTopTarget;
+                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                        reportOomAdjMessageLocked(TAG_OOM_ADJ, "May be top raise to " + mayBeTopType
+                                + ": " + app + ", due to " + mayBeTopSource
+                                + " adj=" + adj + " procState="
+                                + ProcessList.makeProcStateString(procState));
+                    }
+                    break;
+                default:
+                    // Otherwise, top is a better choice, so take it.
+                    procState = ActivityManager.PROCESS_STATE_TOP;
+                    app.adjType = mayBeTopType;
+                    app.adjSource = mayBeTopSource;
+                    app.adjTarget = mayBeTopTarget;
+                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                        reportOomAdjMessageLocked(TAG_OOM_ADJ, "May be top raise to " + mayBeTopType
+                                + ": " + app + ", due to " + mayBeTopSource
+                                + " adj=" + adj + " procState="
+                                + ProcessList.makeProcStateString(procState));
+                    }
+                    break;
+            }
+        }
+
+        if (procState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
+            if (app.hasClientActivities()) {
+                // This is a cached process, but with client activities.  Mark it so.
+                procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+                app.adjType = "cch-client-act";
+            } else if (app.treatLikeActivity) {
+                // This is a cached process, but somebody wants us to treat it like it has
+                // an activity, okay!
+                procState = PROCESS_STATE_CACHED_ACTIVITY;
+                app.adjType = "cch-as-act";
+            }
+        }
+
+        if (adj == ProcessList.SERVICE_ADJ) {
+            if (doingAll) {
+                app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);
+                mNewNumServiceProcs++;
+                //Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb);
+                if (!app.serviceb) {
+                    // This service isn't far enough down on the LRU list to
+                    // normally be a B service, but if we are low on RAM and it
+                    // is large we want to force it down since we would prefer to
+                    // keep launcher over it.
+                    if (mService.mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
+                            && app.lastPss >= mProcessList.getCachedRestoreThresholdKb()) {
+                        app.serviceHighRam = true;
+                        app.serviceb = true;
+                        //Slog.i(TAG, "ADJ " + app + " high ram!");
+                    } else {
+                        mNewNumAServiceProcs++;
+                        //Slog.i(TAG, "ADJ " + app + " not high ram!");
+                    }
+                } else {
+                    app.serviceHighRam = false;
+                }
+            }
+            if (app.serviceb) {
+                adj = ProcessList.SERVICE_B_ADJ;
+            }
+        }
+
+        app.setCurRawAdj(adj);
+
+        //Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
+        //      " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
+        if (adj > app.maxAdj) {
+            adj = app.maxAdj;
+            if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+            }
+        }
+
+        // Put bound foreground services in a special sched group for additional
+        // restrictions on screen off
+        if (procState >= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE &&
+                mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE) {
+            if (schedGroup > ProcessList.SCHED_GROUP_RESTRICTED) {
+                schedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
+            }
+        }
+
+        // Do final modification to adj.  Everything we do between here and applying
+        // the final setAdj must be done in this function, because we will also use
+        // it when computing the final cached adj later.  Note that we don't need to
+        // worry about this for max adj above, since max adj will always be used to
+        // keep it out of the cached vaues.
+        app.curAdj = app.modifyRawOomAdj(adj);
+        app.setCurrentSchedulingGroup(schedGroup);
+        app.setCurProcState(procState);
+        app.setCurRawProcState(procState);
+        app.setHasForegroundActivities(foregroundActivities);
+        app.completedAdjSeq = mAdjSeq;
+
+        // if curAdj or curProcState improved, then this process was promoted
+        return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
+    }
+
+    /**
+     * Checks if for the given app and client, there's a cycle that should skip over the client
+     * for now or use partial values to evaluate the effect of the client binding.
+     * @param app
+     * @param client
+     * @param procState procstate evaluated so far for this app
+     * @param adj oom_adj evaluated so far for this app
+     * @param cycleReEval whether we're currently re-evaluating due to a cycle, and not the first
+     *                    evaluation.
+     * @return whether to skip using the client connection at this time
+     */
+    private boolean shouldSkipDueToCycle(ProcessRecord app, ProcessRecord client,
+            int procState, int adj, boolean cycleReEval) {
+        if (client.containsCycle) {
+            // We've detected a cycle. We should retry computeOomAdjLocked later in
+            // case a later-checked connection from a client  would raise its
+            // priority legitimately.
+            app.containsCycle = true;
+            // If the client has not been completely evaluated, check if it's worth
+            // using the partial values.
+            if (client.completedAdjSeq < mAdjSeq) {
+                if (cycleReEval) {
+                    // If the partial values are no better, skip until the next
+                    // attempt
+                    if (client.getCurRawProcState() >= procState
+                            && client.getCurRawAdj() >= adj) {
+                        return true;
+                    }
+                    // Else use the client's partial procstate and adj to adjust the
+                    // effect of the binding
+                } else {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /** Inform the oomadj observer of changes to oomadj. Used by tests. */
+    @GuardedBy("mService")
+    void reportOomAdjMessageLocked(String tag, String msg) {
+        Slog.d(tag, msg);
+        if (mService.mCurOomAdjObserver != null) {
+            mService.mUiHandler.obtainMessage(DISPATCH_OOM_ADJ_OBSERVER_MSG, msg).sendToTarget();
+        }
+    }
+
+    /** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
+    @GuardedBy("mService")
+    private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
+            long nowElapsed) {
+        boolean success = true;
+
+        if (app.getCurRawAdj() != app.setRawAdj) {
+            app.setRawAdj = app.getCurRawAdj();
+        }
+
+        int changes = 0;
+
+        if (app.curAdj != app.setAdj) {
+            // don't compact during bootup
+            if (mConstants.USE_COMPACTION && mService.mBooted) {
+                // Perform a minor compaction when a perceptible app becomes the prev/home app
+                // Perform a major compaction when any app enters cached
+                // reminder: here, setAdj is previous state, curAdj is upcoming state
+                if (app.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ &&
+                        (app.curAdj == ProcessList.PREVIOUS_APP_ADJ ||
+                                app.curAdj == ProcessList.HOME_APP_ADJ)) {
+                    mAppCompact.compactAppSome(app);
+                } else if (app.setAdj < ProcessList.CACHED_APP_MIN_ADJ &&
+                        app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+                    mAppCompact.compactAppFull(app);
+                }
+            }
+            ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);
+            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) {
+                String msg = "Set " + app.pid + " " + app.processName + " adj "
+                        + app.curAdj + ": " + app.adjType;
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
+            }
+            app.setAdj = app.curAdj;
+            app.verifiedAdj = ProcessList.INVALID_ADJ;
+        }
+
+        final int curSchedGroup = app.getCurrentSchedulingGroup();
+        if (app.setSchedGroup != curSchedGroup) {
+            int oldSchedGroup = app.setSchedGroup;
+            app.setSchedGroup = curSchedGroup;
+            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.uid) {
+                String msg = "Setting sched group of " + app.processName
+                        + " to " + curSchedGroup + ": " + app.adjType;
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
+            }
+            if (app.waitingToKill != null && app.curReceivers.isEmpty()
+                    && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
+                app.kill(app.waitingToKill, true);
+                success = false;
+            } else {
+                int processGroup;
+                switch (curSchedGroup) {
+                    case ProcessList.SCHED_GROUP_BACKGROUND:
+                        processGroup = THREAD_GROUP_BG_NONINTERACTIVE;
+                        break;
+                    case ProcessList.SCHED_GROUP_TOP_APP:
+                    case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
+                        processGroup = THREAD_GROUP_TOP_APP;
+                        break;
+                    case ProcessList.SCHED_GROUP_RESTRICTED:
+                        processGroup = THREAD_GROUP_RESTRICTED;
+                        break;
+                    default:
+                        processGroup = THREAD_GROUP_DEFAULT;
+                        break;
+                }
+                long oldId = Binder.clearCallingIdentity();
+                try {
+                    setProcessGroup(app.pid, processGroup);
+                    if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
+                        // do nothing if we already switched to RT
+                        if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
+                            app.getWindowProcessController().onTopProcChanged();
+                            if (mService.mUseFifoUiScheduling) {
+                                // Switch UI pipeline for app to SCHED_FIFO
+                                app.savedPriority = Process.getThreadPriority(app.pid);
+                                mService.scheduleAsFifoPriority(app.pid, /* suppressLogs */true);
+                                if (app.renderThreadTid != 0) {
+                                    mService.scheduleAsFifoPriority(app.renderThreadTid,
+                                            /* suppressLogs */true);
+                                    if (DEBUG_OOM_ADJ) {
+                                        Slog.d("UI_FIFO", "Set RenderThread (TID " +
+                                                app.renderThreadTid + ") to FIFO");
+                                    }
+                                } else {
+                                    if (DEBUG_OOM_ADJ) {
+                                        Slog.d("UI_FIFO", "Not setting RenderThread TID");
+                                    }
+                                }
+                            } else {
+                                // Boost priority for top app UI and render threads
+                                setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST);
+                                if (app.renderThreadTid != 0) {
+                                    try {
+                                        setThreadPriority(app.renderThreadTid,
+                                                TOP_APP_PRIORITY_BOOST);
+                                    } catch (IllegalArgumentException e) {
+                                        // thread died, ignore
+                                    }
+                                }
+                            }
+                        }
+                    } else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
+                            curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
+                        app.getWindowProcessController().onTopProcChanged();
+                        if (mService.mUseFifoUiScheduling) {
+                            try {
+                                // Reset UI pipeline to SCHED_OTHER
+                                setThreadScheduler(app.pid, SCHED_OTHER, 0);
+                                setThreadPriority(app.pid, app.savedPriority);
+                                if (app.renderThreadTid != 0) {
+                                    setThreadScheduler(app.renderThreadTid,
+                                            SCHED_OTHER, 0);
+                                    setThreadPriority(app.renderThreadTid, -4);
+                                }
+                            } catch (IllegalArgumentException e) {
+                                Slog.w(TAG,
+                                        "Failed to set scheduling policy, thread does not exist:\n"
+                                                + e);
+                            } catch (SecurityException e) {
+                                Slog.w(TAG, "Failed to set scheduling policy, not allowed:\n" + e);
+                            }
+                        } else {
+                            // Reset priority for top app UI and render threads
+                            setThreadPriority(app.pid, 0);
+                            if (app.renderThreadTid != 0) {
+                                setThreadPriority(app.renderThreadTid, 0);
+                            }
+                        }
+                    }
+                } catch (Exception e) {
+                    if (false) {
+                        Slog.w(TAG, "Failed setting process group of " + app.pid
+                                + " to " + app.getCurrentSchedulingGroup());
+                        Slog.w(TAG, "at location", e);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(oldId);
+                }
+            }
+        }
+        if (app.repForegroundActivities != app.hasForegroundActivities()) {
+            app.repForegroundActivities = app.hasForegroundActivities();
+            changes |= ActivityManagerService.ProcessChangeItem.CHANGE_ACTIVITIES;
+        }
+        if (app.getReportedProcState() != app.getCurProcState()) {
+            app.setReportedProcState(app.getCurProcState());
+            if (app.thread != null) {
+                try {
+                    if (false) {
+                        //RuntimeException h = new RuntimeException("here");
+                        Slog.i(TAG, "Sending new process state " + app.getReportedProcState()
+                                + " to " + app /*, h*/);
+                    }
+                    app.thread.setProcessState(app.getReportedProcState());
+                } catch (RemoteException e) {
+                }
+            }
+        }
+        if (app.setProcState == PROCESS_STATE_NONEXISTENT
+                || ProcessList.procStatesDifferForMem(app.getCurProcState(), app.setProcState)) {
+            if (false && mService.mTestPssMode
+                    && app.setProcState >= 0 && app.lastStateTime <= (now-200)) {
+                // Experimental code to more aggressively collect pss while
+                // running test...  the problem is that this tends to collect
+                // the data right when a process is transitioning between process
+                // states, which will tend to give noisy data.
+                long start = SystemClock.uptimeMillis();
+                long startTime = SystemClock.currentThreadTimeMillis();
+                long pss = Debug.getPss(app.pid, mTmpLong, null);
+                long endTime = SystemClock.currentThreadTimeMillis();
+                mService.recordPssSampleLocked(app, app.getCurProcState(), pss,
+                        mTmpLong[0], mTmpLong[1], mTmpLong[2],
+                        ProcessStats.ADD_PSS_INTERNAL_SINGLE, endTime-startTime, now);
+                mService.mPendingPssProcesses.remove(app);
+                Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
+                        + " to " + app.getCurProcState() + ": "
+                        + (SystemClock.uptimeMillis()-start) + "ms");
+            }
+            app.lastStateTime = now;
+            app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
+                    app.procStateMemTracker, mService.mTestPssMode,
+                    mService.mAtmInternal.isSleeping(), now);
+            if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
+                    + ProcessList.makeProcStateString(app.setProcState) + " to "
+                    + ProcessList.makeProcStateString(app.getCurProcState()) + " next pss in "
+                    + (app.nextPssTime-now) + ": " + app);
+        } else {
+            if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
+                    && now > (app.lastStateTime+ProcessList.minTimeFromStateChange(
+                    mService.mTestPssMode)))) {
+                if (mService.requestPssLocked(app, app.setProcState)) {
+                    app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
+                            app.procStateMemTracker, mService.mTestPssMode,
+                            mService.mAtmInternal.isSleeping(), now);
+                }
+            } else if (false && DEBUG_PSS) {
+                Slog.d(TAG_PSS,
+                        "Not requesting pss of " + app + ": next=" + (app.nextPssTime-now));
+            }
+        }
+        if (app.setProcState != app.getCurProcState()) {
+            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.uid) {
+                String msg = "Proc state change of " + app.processName
+                        + " to " + ProcessList.makeProcStateString(app.getCurProcState())
+                        + " (" + app.getCurProcState() + ")" + ": " + app.adjType;
+                reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
+            }
+            boolean setImportant = app.setProcState < ActivityManager.PROCESS_STATE_SERVICE;
+            boolean curImportant = app.getCurProcState() < ActivityManager.PROCESS_STATE_SERVICE;
+            if (setImportant && !curImportant) {
+                // This app is no longer something we consider important enough to allow to use
+                // arbitrary amounts of battery power. Note its current CPU time to later know to
+                // kill it if it is not behaving well.
+                app.setWhenUnimportant(now);
+                app.lastCpuTime = 0;
+            }
+            // Inform UsageStats of important process state change
+            // Must be called before updating setProcState
+            maybeUpdateUsageStatsLocked(app, nowElapsed);
+
+            maybeUpdateLastTopTime(app, now);
+
+            app.setProcState = app.getCurProcState();
+            if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
+                app.notCachedSinceIdle = false;
+            }
+            if (!doingAll) {
+                mService.setProcessTrackerStateLocked(app,
+                        mService.mProcessStats.getMemFactorLocked(), now);
+            } else {
+                app.procStateChanged = true;
+            }
+        } else if (app.reportedInteraction && (nowElapsed - app.getInteractionEventTime())
+                > mConstants.USAGE_STATS_INTERACTION_INTERVAL) {
+            // For apps that sit around for a long time in the interactive state, we need
+            // to report this at least once a day so they don't go idle.
+            maybeUpdateUsageStatsLocked(app, nowElapsed);
+        }
+
+        if (changes != 0) {
+            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                    "Changes in " + app + ": " + changes);
+            int i = mService.mPendingProcessChanges.size()-1;
+            ActivityManagerService.ProcessChangeItem item = null;
+            while (i >= 0) {
+                item = mService.mPendingProcessChanges.get(i);
+                if (item.pid == app.pid) {
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                            "Re-using existing item: " + item);
+                    break;
+                }
+                i--;
+            }
+            if (i < 0) {
+                // No existing item in pending changes; need a new one.
+                final int NA = mService.mAvailProcessChanges.size();
+                if (NA > 0) {
+                    item = mService.mAvailProcessChanges.remove(NA-1);
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                            "Retrieving available item: " + item);
+                } else {
+                    item = new ActivityManagerService.ProcessChangeItem();
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                            "Allocating new item: " + item);
+                }
+                item.changes = 0;
+                item.pid = app.pid;
+                item.uid = app.info.uid;
+                if (mService.mPendingProcessChanges.size() == 0) {
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                            "*** Enqueueing dispatch processes changed!");
+                    mService.mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
+                            .sendToTarget();
+                }
+                mService.mPendingProcessChanges.add(item);
+            }
+            item.changes |= changes;
+            item.foregroundActivities = app.repForegroundActivities;
+            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                    "Item " + Integer.toHexString(System.identityHashCode(item))
+                            + " " + app.toShortString() + ": changes=" + item.changes
+                            + " foreground=" + item.foregroundActivities
+                            + " type=" + app.adjType + " source=" + app.adjSource
+                            + " target=" + app.adjTarget);
+        }
+
+        return success;
+    }
+
+    @GuardedBy("mService")
+    private void maybeUpdateUsageStatsLocked(ProcessRecord app, long nowElapsed) {
+        if (DEBUG_USAGE_STATS) {
+            Slog.d(TAG, "Checking proc [" + Arrays.toString(app.getPackageList())
+                    + "] state changes: old = " + app.setProcState + ", new = "
+                    + app.getCurProcState());
+        }
+        if (mService.mUsageStatsService == null) {
+            return;
+        }
+        boolean isInteraction;
+        // To avoid some abuse patterns, we are going to be careful about what we consider
+        // to be an app interaction.  Being the top activity doesn't count while the display
+        // is sleeping, nor do short foreground services.
+        if (app.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP) {
+            isInteraction = true;
+            app.setFgInteractionTime(0);
+        } else if (app.getCurProcState() <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+            if (app.getFgInteractionTime() == 0) {
+                app.setFgInteractionTime(nowElapsed);
+                isInteraction = false;
+            } else {
+                isInteraction = nowElapsed > app.getFgInteractionTime()
+                        + mConstants.SERVICE_USAGE_INTERACTION_TIME;
+            }
+        } else {
+            isInteraction =
+                    app.getCurProcState() <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+            app.setFgInteractionTime(0);
+        }
+        if (isInteraction
+                && (!app.reportedInteraction || (nowElapsed - app.getInteractionEventTime())
+                > mConstants.USAGE_STATS_INTERACTION_INTERVAL)) {
+            app.setInteractionEventTime(nowElapsed);
+            String[] packages = app.getPackageList();
+            if (packages != null) {
+                for (int i = 0; i < packages.length; i++) {
+                    mService.mUsageStatsService.reportEvent(packages[i], app.userId,
+                            UsageEvents.Event.SYSTEM_INTERACTION);
+                }
+            }
+        }
+        app.reportedInteraction = isInteraction;
+        if (!isInteraction) {
+            app.setInteractionEventTime(0);
+        }
+    }
+
+    private void maybeUpdateLastTopTime(ProcessRecord app, long nowUptime) {
+        if (app.setProcState <= ActivityManager.PROCESS_STATE_TOP
+                && app.getCurProcState() > ActivityManager.PROCESS_STATE_TOP) {
+            app.lastTopTime = nowUptime;
+        }
+    }
+
+    /**
+     * Look for recently inactive apps and mark them idle after a grace period. If idled, stop
+     * any background services and inform listeners.
+     */
+    @GuardedBy("mService")
+    void idleUidsLocked() {
+        final int N = mActiveUids.size();
+        if (N <= 0) {
+            return;
+        }
+        final long nowElapsed = SystemClock.elapsedRealtime();
+        final long maxBgTime = nowElapsed - mConstants.BACKGROUND_SETTLE_TIME;
+        long nextTime = 0;
+        if (mLocalPowerManager != null) {
+            mLocalPowerManager.startUidChanges();
+        }
+        for (int i = N - 1; i >= 0; i--) {
+            final UidRecord uidRec = mActiveUids.valueAt(i);
+            final long bgTime = uidRec.lastBackgroundTime;
+            if (bgTime > 0 && !uidRec.idle) {
+                if (bgTime <= maxBgTime) {
+                    EventLogTags.writeAmUidIdle(uidRec.uid);
+                    uidRec.idle = true;
+                    uidRec.setIdle = true;
+                    mService.doStopUidLocked(uidRec.uid, uidRec);
+                } else {
+                    if (nextTime == 0 || nextTime > bgTime) {
+                        nextTime = bgTime;
+                    }
+                }
+            }
+        }
+        if (mLocalPowerManager != null) {
+            mLocalPowerManager.finishUidChanges();
+        }
+        if (nextTime > 0) {
+            mService.mHandler.removeMessages(IDLE_UIDS_MSG);
+            mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
+                    nextTime + mConstants.BACKGROUND_SETTLE_TIME - nowElapsed);
+        }
+    }
+
+    @GuardedBy("mService")
+    final void setAppIdTempWhitelistStateLocked(int appId, boolean onWhitelist) {
+        boolean changed = false;
+        for (int i = mActiveUids.size() - 1; i >= 0; i--) {
+            final UidRecord uidRec = mActiveUids.valueAt(i);
+            if (UserHandle.getAppId(uidRec.uid) == appId && uidRec.curWhitelist != onWhitelist) {
+                uidRec.curWhitelist = onWhitelist;
+                changed = true;
+            }
+        }
+        if (changed) {
+            updateOomAdjLocked();
+        }
+    }
+
+    @GuardedBy("mService")
+    final void setUidTempWhitelistStateLocked(int uid, boolean onWhitelist) {
+        boolean changed = false;
+        final UidRecord uidRec = mActiveUids.get(uid);
+        if (uidRec != null && uidRec.curWhitelist != onWhitelist) {
+            uidRec.curWhitelist = onWhitelist;
+            updateOomAdjLocked();
+        }
+    }
+
+    @GuardedBy("mService")
+    void dumpProcessListVariablesLocked(ProtoOutputStream proto) {
+        proto.write(ActivityManagerServiceDumpProcessesProto.ADJ_SEQ, mAdjSeq);
+        proto.write(ActivityManagerServiceDumpProcessesProto.LRU_SEQ, mProcessList.mLruSeq);
+        proto.write(ActivityManagerServiceDumpProcessesProto.NUM_NON_CACHED_PROCS,
+                mNumNonCachedProcs);
+        proto.write(ActivityManagerServiceDumpProcessesProto.NUM_SERVICE_PROCS, mNumServiceProcs);
+        proto.write(ActivityManagerServiceDumpProcessesProto.NEW_NUM_SERVICE_PROCS,
+                mNewNumServiceProcs);
+
+    }
+
+    @GuardedBy("mService")
+    void dumpSequenceNumbersLocked(PrintWriter pw) {
+        pw.println("  mAdjSeq=" + mAdjSeq + " mLruSeq=" + mProcessList.mLruSeq);
+    }
+
+    @GuardedBy("mService")
+    void dumpProcCountsLocked(PrintWriter pw) {
+        pw.println("  mNumNonCachedProcs=" + mNumNonCachedProcs
+                + " (" + mProcessList.getLruSizeLocked() + " total)"
+                + " mNumCachedHiddenProcs=" + mNumCachedHiddenProcs
+                + " mNumServiceProcs=" + mNumServiceProcs
+                + " mNewNumServiceProcs=" + mNewNumServiceProcs);
+    }
+
+}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 447243b..55cca95 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -34,6 +34,7 @@
 import android.os.TransactionTooLargeException;
 import android.os.UserHandle;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.TimeUtils;
 
@@ -48,6 +49,10 @@
 public final class PendingIntentRecord extends IIntentSender.Stub {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;
 
+    public static final int FLAG_ACTIVITY_SENDER = 1 << 0;
+    public static final int FLAG_BROADCAST_SENDER = 1 << 1;
+    public static final int FLAG_SERVICE_SENDER = 1 << 2;
+
     final PendingIntentController controller;
     final Key key;
     final int uid;
@@ -56,6 +61,9 @@
     boolean canceled = false;
     private ArrayMap<IBinder, Long> whitelistDuration;
     private RemoteCallbackList<IResultReceiver> mCancelCallbacks;
+    private ArraySet<IBinder> mAllowBgActivityStartsForActivitySender = new ArraySet<>();
+    private ArraySet<IBinder> mAllowBgActivityStartsForBroadcastSender = new ArraySet<>();
+    private ArraySet<IBinder> mAllowBgActivityStartsForServiceSender = new ArraySet<>();
 
     String stringName;
     String lastTagPrefix;
@@ -214,6 +222,19 @@
         this.stringName = null;
     }
 
+    void setAllowBgActivityStarts(IBinder token, int flags) {
+        if (token == null) return;
+        if ((flags & FLAG_ACTIVITY_SENDER) != 0) {
+            mAllowBgActivityStartsForActivitySender.add(token);
+        }
+        if ((flags & FLAG_BROADCAST_SENDER) != 0) {
+            mAllowBgActivityStartsForBroadcastSender.add(token);
+        }
+        if ((flags & FLAG_SERVICE_SENDER) != 0) {
+            mAllowBgActivityStartsForServiceSender.add(token);
+        }
+    }
+
     public void registerCancelListenerLocked(IResultReceiver receiver) {
         if (mCancelCallbacks == null) {
             mCancelCallbacks = new RemoteCallbackList<>();
@@ -368,16 +389,19 @@
 
                         if (key.allIntents != null && key.allIntents.length > 1) {
                             res = controller.mAtmInternal.startActivitiesInPackage(
-                                    uid, key.packageName, allIntents, allResolvedTypes, resultTo,
-                                    mergedOptions, userId, false /* validateIncomingUser */,
-                                    this /* originatingPendingIntent */);
+                                    uid, callingPid, callingUid, key.packageName, allIntents,
+                                    allResolvedTypes, resultTo, mergedOptions, userId,
+                                    false /* validateIncomingUser */,
+                                    this /* originatingPendingIntent */,
+                                    mAllowBgActivityStartsForActivitySender.contains(whitelistToken));
                         } else {
                             res = controller.mAtmInternal.startActivityInPackage(
                                     uid, callingPid, callingUid, key.packageName, finalIntent,
                                     resolvedType, resultTo, resultWho, requestCode, 0,
                                     mergedOptions, userId, null, "PendingIntentRecord",
                                     false /* validateIncomingUser */,
-                                    this /* originatingPendingIntent */);
+                                    this /* originatingPendingIntent */,
+                                    mAllowBgActivityStartsForActivitySender.contains(whitelistToken));
                         }
                     } catch (RuntimeException e) {
                         Slog.w(TAG, "Unable to send startActivity intent", e);
@@ -394,7 +418,8 @@
                         int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,
                                 uid, finalIntent, resolvedType, finishedReceiver, code, null, null,
                                 requiredPermission, options, (finishedReceiver != null),
-                                false, userId);
+                                false, userId,
+                                mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken));
                         if (sent == ActivityManager.BROADCAST_SUCCESS) {
                             sendFinish = false;
                         }
@@ -407,7 +432,8 @@
                     try {
                         controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
                                 key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
-                                key.packageName, userId);
+                                key.packageName, userId,
+                                mAllowBgActivityStartsForServiceSender.contains(whitelistToken));
                     } catch (RuntimeException e) {
                         Slog.w(TAG, "Unable to send startService intent", e);
                     } catch (TransactionTooLargeException e) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 26a0b59..64ee30a 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -17,10 +17,9 @@
 package com.android.server.am;
 
 import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO;
-import static android.os.Process.FIRST_ISOLATED_UID;
-import static android.os.Process.LAST_ISOLATED_UID;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
 import static android.os.Process.getFreeMemory;
@@ -34,6 +33,8 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
 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.ActivityManagerService.KILL_APP_ZYGOTE_DELAY_MS;
+import static com.android.server.am.ActivityManagerService.KILL_APP_ZYGOTE_MSG;
 import static com.android.server.am.ActivityManagerService.PERSISTENT_MASK;
 import static com.android.server.am.ActivityManagerService.PROC_START_TIMEOUT;
 import static com.android.server.am.ActivityManagerService.PROC_START_TIMEOUT_MSG;
@@ -58,6 +59,7 @@
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.net.Uri;
+import android.os.AppZygote;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -75,10 +77,12 @@
 import android.os.storage.StorageManager;
 import android.os.storage.StorageManagerInternal;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.EventLog;
 import android.util.LongSparseArray;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.StatsLog;
 import android.view.Display;
 
@@ -108,6 +112,7 @@
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.BitSet;
 import java.util.List;
 
 /**
@@ -119,7 +124,7 @@
  * </ul>
  */
 public final class ProcessList {
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM;
+    static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM;
 
     // The minimum time we allow between crashes, for us to consider this
     // application to be bad and stop and its services and reject broadcasts.
@@ -140,6 +145,11 @@
     static final int CACHED_APP_MAX_ADJ = 999;
     static final int CACHED_APP_MIN_ADJ = 900;
 
+    // This is the oom_adj level that we allow to die first. This cannot be equal to
+    // CACHED_APP_MAX_ADJ unless processes are actively being assigned an oom_score_adj of
+    // CACHED_APP_MAX_ADJ.
+    static final int CACHED_APP_LMK_FIRST_ADJ = 950;
+
     // Number of levels we have available for different service connection group importance
     // levels.
     static final int CACHED_APP_IMPORTANCE_LEVELS = 5;
@@ -261,7 +271,7 @@
     // can't give it a different value for every possible kind of process.
     private final int[] mOomAdj = new int[] {
             FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
-            BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ
+            BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_LMK_FIRST_ADJ
     };
     // These are the low-end OOM level limits.  This is appropriate for an
     // HVGA or smaller phone with less than 512MB.  Values are in KB.
@@ -348,16 +358,144 @@
      */
     int mLruSeq = 0;
 
+    ActiveUids mActiveUids;
+
     /**
      * The currently running isolated processes.
      */
     final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<>();
 
     /**
-     * Counter for assigning isolated process uids, to avoid frequently reusing the
-     * same ones.
+     * The currently running application zygotes.
      */
-    int mNextIsolatedProcessUid = 0;
+    final ProcessMap<AppZygote> mAppZygotes = new ProcessMap<AppZygote>();
+
+    /**
+     * The processes that are forked off an application zygote.
+     */
+    final ArrayMap<AppZygote, ArrayList<ProcessRecord>> mAppZygoteProcesses =
+            new ArrayMap<AppZygote, ArrayList<ProcessRecord>>();
+
+    final class IsolatedUidRange {
+        @VisibleForTesting
+        public final int mFirstUid;
+        @VisibleForTesting
+        public final int mLastUid;
+
+        @GuardedBy("ProcessList.this.mService")
+        private final SparseBooleanArray mUidUsed = new SparseBooleanArray();
+
+        @GuardedBy("ProcessList.this.mService")
+        private int mNextUid;
+
+        IsolatedUidRange(int firstUid, int lastUid) {
+            mFirstUid = firstUid;
+            mLastUid = lastUid;
+            mNextUid = firstUid;
+        }
+
+        @GuardedBy("ProcessList.this.mService")
+        int allocateIsolatedUidLocked(int userId) {
+            int uid;
+            int stepsLeft = (mLastUid - mFirstUid + 1);
+            for (int i = 0; i < stepsLeft; ++i) {
+                if (mNextUid < mFirstUid || mNextUid > mLastUid) {
+                    mNextUid = mFirstUid;
+                }
+                uid = UserHandle.getUid(userId, mNextUid);
+                mNextUid++;
+                if (!mUidUsed.get(uid, false)) {
+                    mUidUsed.put(uid, true);
+                    return uid;
+                }
+            }
+            return -1;
+        }
+
+        @GuardedBy("ProcessList.this.mService")
+        void freeIsolatedUidLocked(int uid) {
+            // Strip out userId
+            final int appId = UserHandle.getAppId(uid);
+            mUidUsed.delete(appId);
+        }
+    };
+
+    /**
+     * A class that allocates ranges of isolated UIDs per application, and keeps track of them.
+     */
+    final class IsolatedUidRangeAllocator {
+        private final int mFirstUid;
+        private final int mNumUidRanges;
+        private final int mNumUidsPerRange;
+        /**
+         * We map the uid range [mFirstUid, mFirstUid + mNumUidRanges * mNumUidsPerRange)
+         * back to an underlying bitset of [0, mNumUidRanges) and allocate out of that.
+         */
+        @GuardedBy("ProcessList.this.mService")
+        private final BitSet mAvailableUidRanges;
+        @GuardedBy("ProcessList.this.mService")
+        private final ProcessMap<IsolatedUidRange> mAppRanges = new ProcessMap<IsolatedUidRange>();
+
+        IsolatedUidRangeAllocator(int firstUid, int lastUid, int numUidsPerRange) {
+            mFirstUid = firstUid;
+            mNumUidsPerRange = numUidsPerRange;
+            mNumUidRanges = (lastUid - firstUid + 1) / numUidsPerRange;
+            mAvailableUidRanges = new BitSet(mNumUidRanges);
+            // Mark all as available
+            mAvailableUidRanges.set(0, mNumUidRanges);
+        }
+
+        @GuardedBy("ProcessList.this.mService")
+        IsolatedUidRange getIsolatedUidRangeLocked(ApplicationInfo info) {
+            return mAppRanges.get(info.processName, info.uid);
+        }
+
+        @GuardedBy("ProcessList.this.mService")
+        IsolatedUidRange getOrCreateIsolatedUidRangeLocked(ApplicationInfo info) {
+            IsolatedUidRange range = getIsolatedUidRangeLocked(info);
+            if (range == null) {
+                int uidRangeIndex = mAvailableUidRanges.nextSetBit(0);
+                if (uidRangeIndex < 0) {
+                    // No free range
+                    return null;
+                }
+                mAvailableUidRanges.clear(uidRangeIndex);
+                int actualUid = mFirstUid + uidRangeIndex * mNumUidsPerRange;
+                range = new IsolatedUidRange(actualUid, actualUid + mNumUidsPerRange - 1);
+                mAppRanges.put(info.processName, info.uid, range);
+            }
+            return range;
+        }
+
+        @GuardedBy("ProcessList.this.mService")
+        void freeUidRangeLocked(ApplicationInfo info) {
+            // Find the UID range
+            IsolatedUidRange range = mAppRanges.get(info.processName, info.uid);
+            if (range != null) {
+                // Map back to starting uid
+                final int uidRangeIndex = (range.mFirstUid - mFirstUid) / mNumUidsPerRange;
+                // Mark it as available in the underlying bitset
+                mAvailableUidRanges.set(uidRangeIndex);
+                // And the map
+                mAppRanges.remove(info.processName, info.uid);
+            }
+        }
+    }
+
+    /**
+     * The available isolated UIDs for processes that are not spawned from an application zygote.
+     */
+    @VisibleForTesting
+    IsolatedUidRange mGlobalIsolatedUids = new IsolatedUidRange(Process.FIRST_ISOLATED_UID,
+            Process.LAST_ISOLATED_UID);
+
+    /**
+     * An allocator for isolated UID ranges for apps that use an application zygote.
+     */
+    @VisibleForTesting
+    IsolatedUidRangeAllocator mAppIsolatedUidRangeAllocator =
+            new IsolatedUidRangeAllocator(Process.FIRST_APP_ZYGOTE_ISOLATED_UID,
+                    Process.LAST_APP_ZYGOTE_ISOLATED_UID, Process.NUM_UIDS_PER_APP_ZYGOTE);
 
     /**
      * Processes that are being forcibly torn down.
@@ -419,8 +557,10 @@
         updateOomLevels(0, 0, false);
     }
 
-    void init(ActivityManagerService service) {
+    void init(ActivityManagerService service, ActiveUids activeUids) {
         mService = service;
+        mActiveUids = activeUids;
+
         if (sKillHandler == null) {
             sKillThread = new ServiceThread(TAG + ":kill",
                     THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
@@ -1505,6 +1645,69 @@
         }
     }
 
+    @GuardedBy("mService")
+    public void killAppZygoteIfNeededLocked(AppZygote appZygote) {
+        final ApplicationInfo appInfo = appZygote.getAppInfo();
+        ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote);
+        if (zygoteProcesses.size() == 0) { // Only remove if no longer in use now
+            mAppZygotes.remove(appInfo.processName, appInfo.uid);
+            mAppZygoteProcesses.remove(appZygote);
+            mAppIsolatedUidRangeAllocator.freeUidRangeLocked(appInfo);
+            appZygote.stopZygote();
+        }
+    }
+
+    @GuardedBy("mService")
+    private void removeProcessFromAppZygoteLocked(final ProcessRecord app) {
+        // Free the isolated uid for this process
+        final IsolatedUidRange appUidRange =
+                mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info);
+        if (appUidRange != null) {
+            appUidRange.freeIsolatedUidLocked(app.uid);
+        }
+
+        final AppZygote appZygote = mAppZygotes.get(app.info.processName, app.info.uid);
+        if (appZygote != null) {
+            ArrayList<ProcessRecord> zygoteProcesses = mAppZygoteProcesses.get(appZygote);
+            zygoteProcesses.remove(app);
+            if (zygoteProcesses.size() == 0) {
+                Message msg = mService.mHandler.obtainMessage(KILL_APP_ZYGOTE_MSG);
+                msg.obj = appZygote;
+                mService.mHandler.sendMessageDelayed(msg, KILL_APP_ZYGOTE_DELAY_MS);
+            }
+        }
+    }
+
+    private AppZygote createAppZygoteForProcessIfNeeded(final ProcessRecord app) {
+        synchronized (mService) {
+            AppZygote appZygote = mAppZygotes.get(app.info.processName, app.info.uid);
+            final ArrayList<ProcessRecord> zygoteProcessList;
+            if (appZygote == null) {
+                final IsolatedUidRange uidRange =
+                        mAppIsolatedUidRangeAllocator.getIsolatedUidRangeLocked(app.info);
+                final int userId = UserHandle.getUserId(app.info.uid);
+                // Create the app-zygote and provide it with the UID-range it's allowed
+                // to setresuid/setresgid to.
+                final int firstUid = UserHandle.getUid(userId, uidRange.mFirstUid);
+                final int lastUid = UserHandle.getUid(userId, uidRange.mLastUid);
+                appZygote = new AppZygote(app.info, app.info.uid, firstUid, lastUid);
+                mAppZygotes.put(app.info.processName, app.info.uid, appZygote);
+                zygoteProcessList = new ArrayList<ProcessRecord>();
+                mAppZygoteProcesses.put(appZygote, zygoteProcessList);
+            } else {
+                mService.mHandler.removeMessages(KILL_APP_ZYGOTE_MSG, appZygote);
+                zygoteProcessList = mAppZygoteProcesses.get(appZygote);
+            }
+            // Note that we already add the app to mAppZygoteProcesses here;
+            // this is so that another thread can't come in and kill the zygote
+            // before we've even tried to start the process. If the process launch
+            // goes wrong, we'll clean this up in removeProcessNameLocked()
+            zygoteProcessList.add(app);
+
+            return appZygote;
+        }
+    }
+
     private Process.ProcessStartResult startProcess(String hostingType, String entryPoint,
             ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
             String seInfo, String requiredAbi, String instructionSet, String invokeWith,
@@ -1525,6 +1728,15 @@
                         app.info.dataDir, null, app.info.packageName,
                         packageNames, visibleVolIds,
                         new String[] {PROC_START_SEQ_IDENT + app.startSeq});
+            } else if (hostingType.equals("app_zygote")) {
+                final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
+
+                startResult = appZygote.getProcess().start(entryPoint,
+                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
+                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
+                        app.info.dataDir, null, app.info.packageName,
+                        packageNames, visibleVolIds, /*useBlastulaPool=*/ false,
+                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
             } else {
                 startResult = Process.start(entryPoint,
                         app.processName, uid, uid, gids, runtimeFlags, mountExternal,
@@ -1614,13 +1826,6 @@
                 app.addPackage(info.packageName, info.versionCode, mService.mProcessStats);
                 checkSlow(startTime, "startProcess: done, added package to proc");
                 return app;
-            } else if (app.getActiveInstrumentation() != null) {
-                // We don't want to kill running instrumentation.
-                if (DEBUG_PROCESSES) {
-                    Slog.v(TAG_PROCESSES, "Instrumentation already running: " + app);
-                }
-                checkSlow(startTime, "startProcess: keep instrumentation proc");
-                return app;
             }
 
             // An application record is attached to a previous process,
@@ -1636,8 +1841,9 @@
                 ? hostingName.flattenToShortString() : null;
 
         if (app == null) {
+            final boolean fromAppZygote = "app_zygote".equals(hostingType);
             checkSlow(startTime, "startProcess: creating new process record");
-            app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
+            app = newProcessRecordLocked(info, processName, isolated, isolatedUid, fromAppZygote);
             if (app == null) {
                 Slog.w(TAG, "Failed making new process record for "
                         + processName + "/" + info.uid + " isolated=" + isolated);
@@ -1982,7 +2188,7 @@
         } else if (old != null) {
             Slog.wtf(TAG, "Already have existing proc " + old + " when adding " + proc);
         }
-        UidRecord uidRec = mService.mActiveUids.get(proc.uid);
+        UidRecord uidRec = mActiveUids.get(proc.uid);
         if (uidRec == null) {
             uidRec = new UidRecord(proc.uid, mService.mAtmInternal);
             // This is the first appearance of the uid, report it now!
@@ -1994,7 +2200,7 @@
                 uidRec.setWhitelist = uidRec.curWhitelist = true;
             }
             uidRec.updateHasInternetPermission();
-            mService.mActiveUids.put(proc.uid, uidRec);
+            mActiveUids.put(proc.uid, uidRec);
             EventLogTags.writeAmUidRunning(uidRec.uid);
             mService.noteUidProcessState(uidRec.uid, uidRec.getCurProcState());
         }
@@ -2010,29 +2216,31 @@
     }
 
     @GuardedBy("mService")
+    private IsolatedUidRange getOrCreateIsolatedUidRangeLocked(ApplicationInfo info,
+            boolean fromAppZygote) {
+        if (!fromAppZygote) {
+            // Allocate an isolated UID from the global range
+            return mGlobalIsolatedUids;
+        } else {
+            return mAppIsolatedUidRangeAllocator.getOrCreateIsolatedUidRangeLocked(info);
+        }
+    }
+
+    @GuardedBy("mService")
     final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
-            boolean isolated, int isolatedUid) {
+            boolean isolated, int isolatedUid, boolean fromAppZygote) {
         String proc = customProcess != null ? customProcess : info.processName;
         final int userId = UserHandle.getUserId(info.uid);
         int uid = info.uid;
         if (isolated) {
             if (isolatedUid == 0) {
-                int stepsLeft = LAST_ISOLATED_UID - FIRST_ISOLATED_UID + 1;
-                while (true) {
-                    if (mNextIsolatedProcessUid < FIRST_ISOLATED_UID
-                            || mNextIsolatedProcessUid > LAST_ISOLATED_UID) {
-                        mNextIsolatedProcessUid = FIRST_ISOLATED_UID;
-                    }
-                    uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);
-                    mNextIsolatedProcessUid++;
-                    if (mIsolatedProcesses.indexOfKey(uid) < 0) {
-                        // No process for this uid, use it.
-                        break;
-                    }
-                    stepsLeft--;
-                    if (stepsLeft <= 0) {
-                        return null;
-                    }
+                IsolatedUidRange uidRange = getOrCreateIsolatedUidRangeLocked(info, fromAppZygote);
+                if (uidRange == null) {
+                    return null;
+                }
+                uid = uidRange.allocateIsolatedUidLocked(userId);
+                if (uid == -1) {
+                    return null;
                 }
             } else {
                 // Special case for startIsolatedProcess (internal only), where
@@ -2094,12 +2302,19 @@
                         "No more processes in " + old.uidRecord);
                 mService.enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
                 EventLogTags.writeAmUidStopped(uid);
-                mService.mActiveUids.remove(uid);
+                mActiveUids.remove(uid);
                 mService.noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
             }
             old.uidRecord = null;
         }
         mIsolatedProcesses.remove(uid);
+        mGlobalIsolatedUids.freeIsolatedUidLocked(uid);
+        // Remove the (expected) ProcessRecord from the app zygote
+        final ProcessRecord record = expecting != null ? expecting : old;
+        if (record != null && record.appZygote) {
+            removeProcessFromAppZygoteLocked(record);
+        }
+
         return old;
     }
 
@@ -2847,4 +3062,37 @@
             }
         }
     }
+
+    /** Returns the uid's process state or PROCESS_STATE_NONEXISTENT if not running */
+    @GuardedBy("mService")
+    int getUidProcStateLocked(int uid) {
+        UidRecord uidRec = mActiveUids.get(uid);
+        return uidRec == null ? PROCESS_STATE_NONEXISTENT : uidRec.getCurProcState();
+    }
+
+    /** Returns the UidRecord for the given uid, if it exists. */
+    @GuardedBy("mService")
+    UidRecord getUidRecordLocked(int uid) {
+        return mActiveUids.get(uid);
+    }
+
+    /**
+     * Call {@link ActivityManagerService#doStopUidLocked}
+     * (which will also stop background services) for all idle UIDs.
+     */
+    @GuardedBy("mService")
+    void doStopUidForIdleUidsLocked() {
+        final int size = mActiveUids.size();
+        for (int i = 0; i < size; i++) {
+            final int uid = mActiveUids.keyAt(i);
+            if (UserHandle.isCore(uid)) {
+                continue;
+            }
+            final UidRecord uidRec = mActiveUids.valueAt(i);
+            if (!uidRec.idle) {
+                continue;
+            }
+            mService.doStopUidLocked(uidRec.uid, uidRec);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index c15b7c7..054c830 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -76,6 +76,7 @@
     private final ActivityManagerService mService; // where we came from
     final ApplicationInfo info; // all about the first app in the process
     final boolean isolated;     // true if this is a special isolated process
+    final boolean appZygote;    // true if this is forked from the app zygote
     final int uid;              // uid of process; may be different from 'info' if isolated
     final int userId;           // user of process.
     final String processName;   // name of the process
@@ -249,6 +250,9 @@
     final ArrayMap<String, ContentProviderRecord> pubProviders = new ArrayMap<>();
     // All ContentProviderRecord process is using
     final ArrayList<ContentProviderConnection> conProviders = new ArrayList<>();
+    // A set of tokens that currently contribute to this process being temporarily whitelisted
+    // to start activities even if it's not in the foreground
+    final ArraySet<Binder> mAllowBackgroundActivityStartsTokens = new ArraySet<>();
 
     String isolatedEntryPoint;  // Class to run on start if this is a special isolated process.
     String[] isolatedEntryPointArgs; // Arguments to pass to isolatedEntryPoint's main().
@@ -556,6 +560,8 @@
         mService = _service;
         info = _info;
         isolated = _info.uid != _uid;
+        appZygote = (UserHandle.getAppId(_uid) >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID
+                && UserHandle.getAppId(_uid) <= Process.LAST_APP_ZYGOTE_ISOLATED_UID);
         uid = _uid;
         userId = UserHandle.getUserId(_uid);
         processName = _processName;
@@ -1135,6 +1141,19 @@
         return mUsingWrapper;
     }
 
+    void addAllowBackgroundActivityStartsToken(Binder entity) {
+        if (entity == null) return;
+        mAllowBackgroundActivityStartsTokens.add(entity);
+        mWindowProcessController.setAllowBackgroundActivityStarts(true);
+    }
+
+    void removeAllowBackgroundActivityStartsToken(Binder entity) {
+        if (entity == null) return;
+        mAllowBackgroundActivityStartsTokens.remove(entity);
+        mWindowProcessController.setAllowBackgroundActivityStarts(
+                !mAllowBackgroundActivityStartsTokens.isEmpty());
+    }
+
     void setActiveInstrumentation(ActiveInstrumentation instr) {
         mInstr = instr;
         mWindowProcessController.setInstrumenting(instr != null);
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index d5ede5b..128d98b 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -77,6 +77,8 @@
     // permission in the corresponding .te file your feature belongs to.
     @VisibleForTesting
     static final String[] sDeviceConfigScopes = new String[] {
+        DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
+        DeviceConfig.NAMESPACE_NETD_NATIVE,
     };
 
     private final String[] mGlobalSettings;
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index 48b4145..c84b5c7 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -7,7 +7,7 @@
           "include-annotation": "android.platform.test.annotations.Presubmit"
         },
         {
-          "exclude-annotation": "android.support.test.filters.FlakyTest"
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
     },
@@ -21,7 +21,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/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index bcce052..c981e68 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -240,6 +240,8 @@
 
     private final LockPatternUtils mLockPatternUtils;
 
+    volatile boolean mBootCompleted;
+
     UserController(ActivityManagerService service) {
         this(new Injector(service));
     }
@@ -567,6 +569,7 @@
                             Bundle extras, boolean ordered, boolean sticky, int sendingUser)
                             throws RemoteException {
                         Slog.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u" + userId);
+                        mBootCompleted = true;
                     }
                 }, 0, null, null,
                 new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
new file mode 100644
index 0000000..7ede6dc
--- /dev/null
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -0,0 +1,4391 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.appop;
+
+import static android.app.AppOpsManager.OP_PLAY_AUDIO;
+import static android.app.AppOpsManager.OP_NONE;
+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 static android.app.AppOpsManager.modeToName;
+import static android.app.AppOpsManager.opToName;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityThread;
+import android.app.AppGlobals;
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.HistoricalOps;
+import android.app.AppOpsManagerInternal;
+import android.app.AppOpsManagerInternal.CheckOpsDelegate;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.media.AudioAttributes;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ServiceManager;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageManagerInternal;
+import android.provider.Settings;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+import android.util.TimeUtils;
+import android.util.Xml;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IAppOpsActiveCallback;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsNotedCallback;
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.os.Zygote;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.XmlUtils;
+import com.android.internal.util.function.pooled.PooledLambda;
+
+import com.android.server.LocalServices;
+import com.android.server.LockGuard;
+import libcore.util.EmptyArray;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class AppOpsService extends IAppOpsService.Stub {
+    static final String TAG = "AppOps";
+    static final boolean DEBUG = false;
+
+    private static final int NO_VERSION = -1;
+    /** Increment by one every time and add the corresponding upgrade logic in
+     *  {@link #upgradeLocked(int)} below. The first version was 1 */
+    private static final int CURRENT_VERSION = 1;
+
+    // Write at most every 30 minutes.
+    static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
+
+    // Constant meaning that any UID should be matched when dispatching callbacks
+    private static final int UID_ANY = -2;
+
+    // Map from process states to the uid states we track.
+    private static final int[] PROCESS_STATE_TO_UID_STATE = new int[] {
+        UID_STATE_PERSISTENT,           // ActivityManager.PROCESS_STATE_PERSISTENT
+        UID_STATE_PERSISTENT,           // ActivityManager.PROCESS_STATE_PERSISTENT_UI
+        UID_STATE_TOP,                  // ActivityManager.PROCESS_STATE_TOP
+        UID_STATE_FOREGROUND_SERVICE,   // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
+        UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
+        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_BACKUP
+        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_SERVICE
+        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_RECEIVER
+        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_TOP_SLEEPING
+        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_HOME
+        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
+        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_RECENT
+        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_CACHED_EMPTY
+        UID_STATE_CACHED,               // ActivityManager.PROCESS_STATE_NONEXISTENT
+    };
+
+    static final String[] UID_STATE_NAMES = new String[] {
+            "pers ",    // UID_STATE_PERSISTENT
+            "top  ",    // UID_STATE_TOP
+            "fgsvc",    // UID_STATE_FOREGROUND_SERVICE
+            "fg   ",    // UID_STATE_FOREGROUND
+            "bg   ",    // UID_STATE_BACKGROUND
+            "cch  ",    // UID_STATE_CACHED
+    };
+
+    static final String[] UID_STATE_TIME_ATTRS = new String[] {
+            "tp",       // UID_STATE_PERSISTENT
+            "tt",       // UID_STATE_TOP
+            "tfs",      // UID_STATE_FOREGROUND_SERVICE
+            "tf",       // UID_STATE_FOREGROUND
+            "tb",       // UID_STATE_BACKGROUND
+            "tc",       // UID_STATE_CACHED
+    };
+
+    static final String[] UID_STATE_REJECT_ATTRS = new String[] {
+            "rp",       // UID_STATE_PERSISTENT
+            "rt",       // UID_STATE_TOP
+            "rfs",      // UID_STATE_FOREGROUND_SERVICE
+            "rf",       // UID_STATE_FOREGROUND
+            "rb",       // UID_STATE_BACKGROUND
+            "rc",       // UID_STATE_CACHED
+    };
+
+    Context mContext;
+    final AtomicFile mFile;
+    final Handler mHandler;
+
+    private final AppOpsManagerInternalImpl mAppOpsManagerInternal
+            = new AppOpsManagerInternalImpl();
+
+    boolean mWriteScheduled;
+    boolean mFastWriteScheduled;
+    final Runnable mWriteRunner = new Runnable() {
+        public void run() {
+            synchronized (AppOpsService.this) {
+                mWriteScheduled = false;
+                mFastWriteScheduled = false;
+                AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
+                    @Override protected Void doInBackground(Void... params) {
+                        writeState();
+                        return null;
+                    }
+                };
+                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
+            }
+        }
+    };
+
+    @VisibleForTesting
+    final SparseArray<UidState> mUidStates = new SparseArray<>();
+
+    private final HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
+
+    long mLastRealtime;
+
+    /*
+     * These are app op restrictions imposed per user from various parties.
+     */
+    private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
+
+    SparseIntArray mProfileOwners;
+
+    @GuardedBy("this")
+    private CheckOpsDelegate mCheckOpsDelegate;
+
+    /**
+     * All times are in milliseconds. These constants are kept synchronized with the system
+     * global Settings. Any access to this class or its fields should be done while
+     * holding the AppOpsService lock.
+     */
+    private final class Constants extends ContentObserver {
+        // Key names stored in the settings value.
+        private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
+        private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME
+                = "fg_service_state_settle_time";
+        private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time";
+
+        /**
+         * How long we want for a drop in uid state from top to settle before applying it.
+         * @see Settings.Global#APP_OPS_CONSTANTS
+         * @see #KEY_TOP_STATE_SETTLE_TIME
+         */
+        public long TOP_STATE_SETTLE_TIME;
+
+        /**
+         * How long we want for a drop in uid state from foreground to settle before applying it.
+         * @see Settings.Global#APP_OPS_CONSTANTS
+         * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME
+         */
+        public long FG_SERVICE_STATE_SETTLE_TIME;
+
+        /**
+         * How long we want for a drop in uid state from background to settle before applying it.
+         * @see Settings.Global#APP_OPS_CONSTANTS
+         * @see #KEY_BG_STATE_SETTLE_TIME
+         */
+        public long BG_STATE_SETTLE_TIME;
+
+        private final KeyValueListParser mParser = new KeyValueListParser(',');
+        private ContentResolver mResolver;
+
+        public Constants(Handler handler) {
+            super(handler);
+            updateConstants();
+        }
+
+        public void startMonitoring(ContentResolver resolver) {
+            mResolver = resolver;
+            mResolver.registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
+                    false, this);
+            updateConstants();
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            updateConstants();
+        }
+
+        private void updateConstants() {
+            String value = mResolver != null ? Settings.Global.getString(mResolver,
+                    Settings.Global.APP_OPS_CONSTANTS) : "";
+
+            synchronized (AppOpsService.this) {
+                try {
+                    mParser.setString(value);
+                } catch (IllegalArgumentException e) {
+                    // Failed to parse the settings string, log this and move on
+                    // with defaults.
+                    Slog.e(TAG, "Bad app ops settings", e);
+                }
+                TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
+                        KEY_TOP_STATE_SETTLE_TIME, 30 * 1000L);
+                FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
+                        KEY_FG_SERVICE_STATE_SETTLE_TIME, 10 * 1000L);
+                BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
+                        KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
+            }
+        }
+
+        void dump(PrintWriter pw) {
+            pw.println("  Settings:");
+
+            pw.print("    "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
+            TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
+            pw.println();
+            pw.print("    "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
+            TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
+            pw.println();
+            pw.print("    "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
+            TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
+            pw.println();
+        }
+    }
+
+    private final Constants mConstants;
+
+    @VisibleForTesting
+    static final class UidState {
+        public final int uid;
+
+        public int state = UID_STATE_CACHED;
+        public int pendingState = UID_STATE_CACHED;
+        public long pendingStateCommitTime;
+
+        public int startNesting;
+        public ArrayMap<String, Ops> pkgOps;
+        public SparseIntArray opModes;
+
+        // true indicates there is an interested observer, false there isn't but it has such an op
+        public SparseBooleanArray foregroundOps;
+        public boolean hasForegroundWatchers;
+
+        public UidState(int uid) {
+            this.uid = uid;
+        }
+
+        public void clear() {
+            pkgOps = null;
+            opModes = null;
+        }
+
+        public boolean isDefault() {
+            return (pkgOps == null || pkgOps.isEmpty())
+                    && (opModes == null || opModes.size() <= 0);
+        }
+
+        int evalMode(int mode) {
+            if (mode == AppOpsManager.MODE_FOREGROUND) {
+                return state <= UID_STATE_LAST_NON_RESTRICTED
+                        ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
+            }
+            return mode;
+        }
+
+        private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
+                SparseBooleanArray which) {
+            boolean curValue = which.get(op, false);
+            ArraySet<ModeCallback> callbacks = watchers.get(op);
+            if (callbacks != null) {
+                for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
+                    if ((callbacks.valueAt(cbi).mFlags
+                            & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
+                        hasForegroundWatchers = true;
+                        curValue = true;
+                    }
+                }
+            }
+            which.put(op, curValue);
+        }
+
+        public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
+            SparseBooleanArray which = null;
+            hasForegroundWatchers = false;
+            if (opModes != null) {
+                for (int i = opModes.size() - 1; i >= 0; i--) {
+                    if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
+                        if (which == null) {
+                            which = new SparseBooleanArray();
+                        }
+                        evalForegroundWatchers(opModes.keyAt(i), watchers, which);
+                    }
+                }
+            }
+            if (pkgOps != null) {
+                for (int i = pkgOps.size() - 1; i >= 0; i--) {
+                    Ops ops = pkgOps.valueAt(i);
+                    for (int j = ops.size() - 1; j >= 0; j--) {
+                        if (ops.valueAt(j).mode == AppOpsManager.MODE_FOREGROUND) {
+                            if (which == null) {
+                                which = new SparseBooleanArray();
+                            }
+                            evalForegroundWatchers(ops.keyAt(j), watchers, which);
+                        }
+                    }
+                }
+            }
+            foregroundOps = which;
+        }
+    }
+
+    final static class Ops extends SparseArray<Op> {
+        final String packageName;
+        final UidState uidState;
+        final boolean isPrivileged;
+
+        Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
+            packageName = _packageName;
+            uidState = _uidState;
+            isPrivileged = _isPrivileged;
+        }
+    }
+
+    final static class Op {
+        final UidState uidState;
+        final int uid;
+        final String packageName;
+        final int op;
+        int proxyUid = -1;
+        String proxyPackageName;
+        int mode;
+        int duration;
+        long time[] = new long[_NUM_UID_STATE];
+        long rejectTime[] = new long[_NUM_UID_STATE];
+        int startNesting;
+        long startRealtime;
+
+        Op(UidState _uidState, String _packageName, int _op) {
+            uidState = _uidState;
+            uid = _uidState.uid;
+            packageName = _packageName;
+            op = _op;
+            mode = AppOpsManager.opToDefaultMode(op);
+        }
+
+        boolean hasAnyTime() {
+            for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
+                if (time[i] != 0) {
+                    return true;
+                }
+                if (rejectTime[i] != 0) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        int getMode() {
+            return uidState.evalMode(mode);
+        }
+    }
+
+    final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
+    final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
+    final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
+    final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
+    final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
+    final SparseArray<SparseArray<Restriction>> mAudioRestrictions = new SparseArray<>();
+
+    final class ModeCallback implements DeathRecipient {
+        final IAppOpsCallback mCallback;
+        final int mWatchingUid;
+        final int mFlags;
+        final int mCallingUid;
+        final int mCallingPid;
+
+        ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
+                int callingPid) {
+            mCallback = callback;
+            mWatchingUid = watchingUid;
+            mFlags = flags;
+            mCallingUid = callingUid;
+            mCallingPid = callingPid;
+            try {
+                mCallback.asBinder().linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                /*ignored*/
+            }
+        }
+
+        public boolean isWatchingUid(int uid) {
+            return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("ModeCallback{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(" watchinguid=");
+            UserHandle.formatUid(sb, mWatchingUid);
+            sb.append(" flags=0x");
+            sb.append(Integer.toHexString(mFlags));
+            sb.append(" from uid=");
+            UserHandle.formatUid(sb, mCallingUid);
+            sb.append(" pid=");
+            sb.append(mCallingPid);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        void unlinkToDeath() {
+            mCallback.asBinder().unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            stopWatchingMode(mCallback);
+        }
+    }
+
+    final class ActiveCallback implements DeathRecipient {
+        final IAppOpsActiveCallback mCallback;
+        final int mWatchingUid;
+        final int mCallingUid;
+        final int mCallingPid;
+
+        ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
+                int callingPid) {
+            mCallback = callback;
+            mWatchingUid = watchingUid;
+            mCallingUid = callingUid;
+            mCallingPid = callingPid;
+            try {
+                mCallback.asBinder().linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                /*ignored*/
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("ActiveCallback{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(" watchinguid=");
+            UserHandle.formatUid(sb, mWatchingUid);
+            sb.append(" from uid=");
+            UserHandle.formatUid(sb, mCallingUid);
+            sb.append(" pid=");
+            sb.append(mCallingPid);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        void destroy() {
+            mCallback.asBinder().unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            stopWatchingActive(mCallback);
+        }
+    }
+
+    final class NotedCallback implements DeathRecipient {
+        final IAppOpsNotedCallback mCallback;
+        final int mWatchingUid;
+        final int mCallingUid;
+        final int mCallingPid;
+
+        NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid,
+                int callingPid) {
+            mCallback = callback;
+            mWatchingUid = watchingUid;
+            mCallingUid = callingUid;
+            mCallingPid = callingPid;
+            try {
+                mCallback.asBinder().linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                /*ignored*/
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("NotedCallback{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(" watchinguid=");
+            UserHandle.formatUid(sb, mWatchingUid);
+            sb.append(" from uid=");
+            UserHandle.formatUid(sb, mCallingUid);
+            sb.append(" pid=");
+            sb.append(mCallingPid);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        void destroy() {
+            mCallback.asBinder().unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            stopWatchingNoted(mCallback);
+        }
+    }
+
+    final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
+
+    final class ClientState extends Binder implements DeathRecipient {
+        final ArrayList<Op> mStartedOps = new ArrayList<>();
+        final IBinder mAppToken;
+        final int mPid;
+
+        ClientState(IBinder appToken) {
+            mAppToken = appToken;
+            mPid = Binder.getCallingPid();
+            // Watch only for remote processes dying
+            if (!(appToken instanceof Binder)) {
+                try {
+                    mAppToken.linkToDeath(this, 0);
+                } catch (RemoteException e) {
+                    /* do nothing */
+                }
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "ClientState{" +
+                    "mAppToken=" + mAppToken +
+                    ", " + "pid=" + mPid +
+                    '}';
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (AppOpsService.this) {
+                for (int i=mStartedOps.size()-1; i>=0; i--) {
+                    finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true);
+                }
+                mClients.remove(mAppToken);
+            }
+        }
+    }
+
+    public AppOpsService(File storagePath, Handler handler) {
+        LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
+        mFile = new AtomicFile(storagePath, "appops");
+        mHandler = handler;
+        mConstants = new Constants(mHandler);
+        readState();
+    }
+
+    public void publish(Context context) {
+        mContext = context;
+        ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
+        LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
+    }
+
+    public void systemReady() {
+        mConstants.startMonitoring(mContext.getContentResolver());
+        mHistoricalRegistry.systemReady(mContext.getContentResolver());
+
+        synchronized (this) {
+            boolean changed = false;
+            for (int i = mUidStates.size() - 1; i >= 0; i--) {
+                UidState uidState = mUidStates.valueAt(i);
+
+                String[] packageNames = getPackagesForUid(uidState.uid);
+                if (ArrayUtils.isEmpty(packageNames)) {
+                    uidState.clear();
+                    mUidStates.removeAt(i);
+                    changed = true;
+                    continue;
+                }
+
+                ArrayMap<String, Ops> pkgs = uidState.pkgOps;
+                if (pkgs == null) {
+                    continue;
+                }
+
+                Iterator<Ops> it = pkgs.values().iterator();
+                while (it.hasNext()) {
+                    Ops ops = it.next();
+                    int curUid = -1;
+                    try {
+                        curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
+                                PackageManager.MATCH_UNINSTALLED_PACKAGES,
+                                UserHandle.getUserId(ops.uidState.uid));
+                    } catch (RemoteException ignored) {
+                    }
+                    if (curUid != ops.uidState.uid) {
+                        Slog.i(TAG, "Pruning old package " + ops.packageName
+                                + "/" + ops.uidState + ": new uid=" + curUid);
+                        it.remove();
+                        changed = true;
+                    }
+                }
+
+                if (uidState.isDefault()) {
+                    mUidStates.removeAt(i);
+                }
+            }
+            if (changed) {
+                scheduleFastWriteLocked();
+            }
+        }
+
+        final IntentFilter packageSuspendFilter = new IntentFilter();
+        packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
+        packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+                final String[] changedPkgs = intent.getStringArrayExtra(
+                        Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(OP_PLAY_AUDIO);
+                for (int i = 0; i < changedUids.length; i++) {
+                    final int changedUid = changedUids[i];
+                    final String changedPkg = changedPkgs[i];
+                    // We trust packagemanager to insert matching uid and packageNames in the extras
+                    mHandler.sendMessage(PooledLambda.obtainMessage(AppOpsService::notifyOpChanged,
+                            AppOpsService.this, callbacks, OP_PLAY_AUDIO, changedUid, changedPkg));
+                }
+            }
+        }, packageSuspendFilter);
+
+        PackageManagerInternal packageManagerInternal = LocalServices.getService(
+                PackageManagerInternal.class);
+        packageManagerInternal.setExternalSourcesPolicy(
+                new PackageManagerInternal.ExternalSourcesPolicy() {
+                    @Override
+                    public int getPackageTrustedToInstallApps(String packageName, int uid) {
+                        int appOpMode = checkOperation(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
+                                uid, packageName);
+                        switch (appOpMode) {
+                            case AppOpsManager.MODE_ALLOWED:
+                                return PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
+                            case AppOpsManager.MODE_ERRORED:
+                                return PackageManagerInternal.ExternalSourcesPolicy.USER_BLOCKED;
+                            default:
+                                return PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT;
+                        }
+                    }
+                });
+
+        if (!StorageManager.hasIsolatedStorage()) {
+            StorageManagerInternal storageManagerInternal = LocalServices.getService(
+                    StorageManagerInternal.class);
+            storageManagerInternal.addExternalStoragePolicy(
+                    new StorageManagerInternal.ExternalStorageMountPolicy() {
+                        @Override
+                        public int getMountMode(int uid, String packageName) {
+                            if (Process.isIsolated(uid)) {
+                                return Zygote.MOUNT_EXTERNAL_NONE;
+                            }
+                            if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
+                                    packageName) != AppOpsManager.MODE_ALLOWED) {
+                                return Zygote.MOUNT_EXTERNAL_NONE;
+                            }
+                            if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
+                                    packageName) != AppOpsManager.MODE_ALLOWED) {
+                                return Zygote.MOUNT_EXTERNAL_READ;
+                            }
+                            return Zygote.MOUNT_EXTERNAL_WRITE;
+                        }
+
+                        @Override
+                        public boolean hasExternalStorage(int uid, String packageName) {
+                            final int mountMode = getMountMode(uid, packageName);
+                            return mountMode == Zygote.MOUNT_EXTERNAL_READ
+                                    || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
+                        }
+                    });
+        }
+    }
+
+    public void packageRemoved(int uid, String packageName) {
+        synchronized (this) {
+            UidState uidState = mUidStates.get(uid);
+            if (uidState == null) {
+                return;
+            }
+
+            Ops ops = null;
+
+            // Remove any package state if such.
+            if (uidState.pkgOps != null) {
+                ops = uidState.pkgOps.remove(packageName);
+            }
+
+            // If we just nuked the last package state check if the UID is valid.
+            if (ops != null && uidState.pkgOps.isEmpty()
+                    && getPackagesForUid(uid).length <= 0) {
+                mUidStates.remove(uid);
+            }
+
+            // Finish ops other packages started on behalf of the package.
+            final int clientCount = mClients.size();
+            for (int i = 0; i < clientCount; i++) {
+                final ClientState client = mClients.valueAt(i);
+                if (client.mStartedOps == null) {
+                    continue;
+                }
+                final int opCount = client.mStartedOps.size();
+                for (int j = opCount - 1; j >= 0; j--) {
+                    final Op op = client.mStartedOps.get(j);
+                    if (uid == op.uid && packageName.equals(op.packageName)) {
+                        finishOperationLocked(op, /*finishNested*/ true);
+                        client.mStartedOps.remove(j);
+                        if (op.startNesting <= 0) {
+                            scheduleOpActiveChangedIfNeededLocked(op.op,
+                                    uid, packageName, false);
+                        }
+                    }
+                }
+            }
+
+            if (ops != null) {
+                scheduleFastWriteLocked();
+
+                final int opCount = ops.size();
+                for (int i = 0; i < opCount; i++) {
+                    final Op op = ops.valueAt(i);
+                    if (op.duration == -1) {
+                        scheduleOpActiveChangedIfNeededLocked(
+                                op.op, op.uid, op.packageName, false);
+                    }
+                }
+            }
+        }
+    }
+
+    public void uidRemoved(int uid) {
+        synchronized (this) {
+            if (mUidStates.indexOfKey(uid) >= 0) {
+                mUidStates.remove(uid);
+                scheduleFastWriteLocked();
+            }
+        }
+    }
+
+    public void updateUidProcState(int uid, int procState) {
+        synchronized (this) {
+            final UidState uidState = getUidStateLocked(uid, true);
+            final int newState = PROCESS_STATE_TO_UID_STATE[procState];
+            if (uidState != null && uidState.pendingState != newState) {
+                final int oldPendingState = uidState.pendingState;
+                uidState.pendingState = newState;
+                if (newState < uidState.state || newState <= UID_STATE_LAST_NON_RESTRICTED) {
+                    // We are moving to a more important state, or the new state is in the
+                    // foreground, then always do it immediately.
+                    commitUidPendingStateLocked(uidState);
+                } else if (uidState.pendingStateCommitTime == 0) {
+                    // We are moving to a less important state for the first time,
+                    // delay the application for a bit.
+                    final long settleTime;
+                    if (uidState.state <= UID_STATE_TOP) {
+                        settleTime = mConstants.TOP_STATE_SETTLE_TIME;
+                    } else if (uidState.state <= UID_STATE_FOREGROUND_SERVICE) {
+                        settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
+                    } else {
+                        settleTime = mConstants.BG_STATE_SETTLE_TIME;
+                    }
+                    uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime;
+                }
+                if (uidState.startNesting != 0) {
+                    // There is some actively running operation...  need to find it
+                    // and appropriately update its state.
+                    final long now = System.currentTimeMillis();
+                    for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
+                        final Ops ops = uidState.pkgOps.valueAt(i);
+                        for (int j = ops.size() - 1; j >= 0; j--) {
+                            final Op op = ops.valueAt(j);
+                            if (op.startNesting > 0) {
+                                op.time[oldPendingState] = now;
+                                op.time[newState] = now;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public void shutdown() {
+        Slog.w(TAG, "Writing app ops before shutdown...");
+        boolean doWrite = false;
+        synchronized (this) {
+            if (mWriteScheduled) {
+                mWriteScheduled = false;
+                doWrite = true;
+            }
+        }
+        if (doWrite) {
+            writeState();
+        }
+    }
+
+    private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
+        ArrayList<AppOpsManager.OpEntry> resOps = null;
+        final long elapsedNow = SystemClock.elapsedRealtime();
+        if (ops == null) {
+            resOps = new ArrayList<>();
+            for (int j=0; j<pkgOps.size(); j++) {
+                Op curOp = pkgOps.valueAt(j);
+                final boolean running = curOp.duration == -1;
+                long duration = running
+                        ? (elapsedNow - curOp.startRealtime)
+                        : curOp.duration;
+                resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
+                        curOp.rejectTime, (int) duration, running, curOp.proxyUid,
+                        curOp.proxyPackageName));
+            }
+        } else {
+            for (int j=0; j<ops.length; j++) {
+                Op curOp = pkgOps.get(ops[j]);
+                if (curOp != null) {
+                    if (resOps == null) {
+                        resOps = new ArrayList<>();
+                    }
+                    final boolean running = curOp.duration == -1;
+                    final long duration = running
+                            ? (elapsedNow - curOp.startRealtime)
+                            : curOp.duration;
+                    resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
+                            curOp.rejectTime, (int) duration, running, curOp.proxyUid,
+                            curOp.proxyPackageName));
+                }
+            }
+        }
+        return resOps;
+    }
+
+    private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
+        if (uidOps == null) {
+            return null;
+        }
+        ArrayList<AppOpsManager.OpEntry> resOps = null;
+        if (ops == null) {
+            resOps = new ArrayList<>();
+            for (int j=0; j<uidOps.size(); j++) {
+                resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
+                        0, 0, 0, -1, null));
+            }
+        } else {
+            for (int j=0; j<ops.length; j++) {
+                int index = uidOps.indexOfKey(ops[j]);
+                if (index >= 0) {
+                    if (resOps == null) {
+                        resOps = new ArrayList<>();
+                    }
+                    resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
+                            0, 0, 0, -1, null));
+                }
+            }
+        }
+        return resOps;
+    }
+
+    @Override
+    public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
+        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+                Binder.getCallingPid(), Binder.getCallingUid(), null);
+        ArrayList<AppOpsManager.PackageOps> res = null;
+        synchronized (this) {
+            final int uidStateCount = mUidStates.size();
+            for (int i = 0; i < uidStateCount; i++) {
+                UidState uidState = mUidStates.valueAt(i);
+                if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
+                    continue;
+                }
+                ArrayMap<String, Ops> packages = uidState.pkgOps;
+                final int packageCount = packages.size();
+                for (int j = 0; j < packageCount; j++) {
+                    Ops pkgOps = packages.valueAt(j);
+                    ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
+                    if (resOps != null) {
+                        if (res == null) {
+                            res = new ArrayList<AppOpsManager.PackageOps>();
+                        }
+                        AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
+                                pkgOps.packageName, pkgOps.uidState.uid, resOps);
+                        res.add(resPackage);
+                    }
+                }
+            }
+        }
+        return res;
+    }
+
+    @Override
+    public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
+            int[] ops) {
+        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+                Binder.getCallingPid(), Binder.getCallingUid(), null);
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return Collections.emptyList();
+        }
+        synchronized (this) {
+            Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
+                    false /* uidMismatchExpected */);
+            if (pkgOps == null) {
+                return null;
+            }
+            ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
+            if (resOps == null) {
+                return null;
+            }
+            ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
+            AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
+                    pkgOps.packageName, pkgOps.uidState.uid, resOps);
+            res.add(resPackage);
+            return res;
+        }
+    }
+
+    @Override
+    public void getHistoricalOps(int uid, @NonNull String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @NonNull RemoteCallback callback) {
+        Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
+                "uid must be " + Process.INVALID_UID + " or non negative");
+        Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
+                "beginTimeMillis must be non negative and lesser than endTimeMillis");
+        Preconditions.checkNotNull(callback, "callback cannot be null");
+        checkValidOpsOrNull(opNames);
+
+        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+                Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
+
+        if (mHistoricalRegistry.getMode() == AppOpsManager.HISTORICAL_MODE_DISABLED) {
+            // TODO (bug:122218838): Remove once the feature fully enabled.
+            getHistoricalPackagesOpsCompat(uid, packageName, opNames, beginTimeMillis,
+                    endTimeMillis, callback);
+        } else {
+            // Must not hold the appops lock
+            mHistoricalRegistry.getHistoricalOps(uid, packageName, opNames,
+                    beginTimeMillis, endTimeMillis, callback);
+        }
+    }
+
+    private void getHistoricalPackagesOpsCompat(int uid, @NonNull String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @NonNull RemoteCallback callback) {
+        synchronized (AppOpsService.this) {
+            final HistoricalOps ops = new HistoricalOps(beginTimeMillis, endTimeMillis);
+            if (opNames == null) {
+                opNames = AppOpsManager.getOpStrs();
+            }
+            final int uidStateCount = mUidStates.size();
+            for (int uidIdx = 0; uidIdx < uidStateCount; uidIdx++) {
+                final UidState uidState = mUidStates.valueAt(uidIdx);
+                if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()
+                        || (uid != Process.INVALID_UID && uid != uidState.uid)) {
+                    continue;
+                }
+                final ArrayMap<String, Ops> packages = uidState.pkgOps;
+                final int packageCount = packages.size();
+                for (int pkgIdx = 0; pkgIdx < packageCount; pkgIdx++) {
+                    final Ops pkgOps = packages.valueAt(pkgIdx);
+                    if (packageName != null && !packageName.equals(pkgOps.packageName)) {
+                        continue;
+                    }
+                    final int opCount = opNames.length;
+                    for (int opIdx = 0; opIdx < opCount; opIdx++) {
+                        final String opName = opNames[opIdx];
+                        if (!ArrayUtils.contains(opNames, opName)) {
+                            continue;
+                        }
+                        final int opCode = AppOpsManager.strOpToOp(opName);
+                        final Op op = pkgOps.get(opCode);
+                        if (op == null) {
+                            continue;
+                        }
+                        final int stateCount = AppOpsManager._NUM_UID_STATE;
+                        for (int stateIdx = 0; stateIdx < stateCount; stateIdx++) {
+                            if (op.rejectTime[stateIdx] != 0) {
+                                ops.increaseRejectCount(opCode, uidState.uid,
+                                        pkgOps.packageName, stateIdx, 1);
+                            } else if (op.time[stateIdx] != 0) {
+                                ops.increaseAccessCount(opCode, uidState.uid,
+                                        pkgOps.packageName, stateIdx, 1);
+                            }
+                        }
+                    }
+                }
+            }
+            final Bundle payload = new Bundle();
+            payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, ops);
+            callback.sendResult(payload);
+        }
+    }
+
+    @Override
+    public void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @NonNull RemoteCallback callback) {
+        Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
+                "uid must be " + Process.INVALID_UID + " or non negative");
+        Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
+                "beginTimeMillis must be non negative and lesser than endTimeMillis");
+        Preconditions.checkNotNull(callback, "callback cannot be null");
+        checkValidOpsOrNull(opNames);
+
+        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+                Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
+
+        // Must not hold the appops lock
+        mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, opNames,
+                beginTimeMillis, endTimeMillis, callback);
+    }
+
+    @Override
+    public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
+        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+                Binder.getCallingPid(), Binder.getCallingUid(), null);
+        synchronized (this) {
+            UidState uidState = getUidStateLocked(uid, false);
+            if (uidState == null) {
+                return null;
+            }
+            ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
+            if (resOps == null) {
+                return null;
+            }
+            ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
+            AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
+                    null, uidState.uid, resOps);
+            res.add(resPackage);
+            return res;
+        }
+    }
+
+    private void pruneOp(Op op, int uid, String packageName) {
+        if (!op.hasAnyTime()) {
+            Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
+                    false /* uidMismatchExpected */);
+            if (ops != null) {
+                ops.remove(op.op);
+                if (ops.size() <= 0) {
+                    UidState uidState = ops.uidState;
+                    ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
+                    if (pkgOps != null) {
+                        pkgOps.remove(ops.packageName);
+                        if (pkgOps.isEmpty()) {
+                            uidState.pkgOps = null;
+                        }
+                        if (uidState.isDefault()) {
+                            mUidStates.remove(uid);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
+        if (callingPid == Process.myPid()) {
+            return;
+        }
+        final int callingUser = UserHandle.getUserId(callingUid);
+        synchronized (this) {
+            if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
+                if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
+                    // Profile owners are allowed to change modes but only for apps
+                    // within their user.
+                    return;
+                }
+            }
+        }
+        mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
+                Binder.getCallingPid(), Binder.getCallingUid(), null);
+    }
+
+    @Override
+    public void setUidMode(int code, int uid, int mode) {
+        if (DEBUG) {
+            Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode)
+                    + " by uid " + Binder.getCallingUid());
+        }
+
+        enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
+        verifyIncomingOp(code);
+        code = AppOpsManager.opToSwitch(code);
+
+        synchronized (this) {
+            final int defaultMode = AppOpsManager.opToDefaultMode(code);
+
+            UidState uidState = getUidStateLocked(uid, false);
+            if (uidState == null) {
+                if (mode == defaultMode) {
+                    return;
+                }
+                uidState = new UidState(uid);
+                uidState.opModes = new SparseIntArray();
+                uidState.opModes.put(code, mode);
+                mUidStates.put(uid, uidState);
+                scheduleWriteLocked();
+            } else if (uidState.opModes == null) {
+                if (mode != defaultMode) {
+                    uidState.opModes = new SparseIntArray();
+                    uidState.opModes.put(code, mode);
+                    scheduleWriteLocked();
+                }
+            } else {
+                if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
+                    return;
+                }
+                if (mode == defaultMode) {
+                    uidState.opModes.delete(code);
+                    if (uidState.opModes.size() <= 0) {
+                        uidState.opModes = null;
+                    }
+                } else {
+                    uidState.opModes.put(code, mode);
+                }
+                scheduleWriteLocked();
+            }
+        }
+
+        String[] uidPackageNames = getPackagesForUid(uid);
+        ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
+
+        synchronized (this) {
+            ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
+            if (callbacks != null) {
+                final int callbackCount = callbacks.size();
+                for (int i = 0; i < callbackCount; i++) {
+                    ModeCallback callback = callbacks.valueAt(i);
+                    ArraySet<String> changedPackages = new ArraySet<>();
+                    Collections.addAll(changedPackages, uidPackageNames);
+                    if (callbackSpecs == null) {
+                        callbackSpecs = new ArrayMap<>();
+                    }
+                    callbackSpecs.put(callback, changedPackages);
+                }
+            }
+
+            for (String uidPackageName : uidPackageNames) {
+                callbacks = mPackageModeWatchers.get(uidPackageName);
+                if (callbacks != null) {
+                    if (callbackSpecs == null) {
+                        callbackSpecs = new ArrayMap<>();
+                    }
+                    final int callbackCount = callbacks.size();
+                    for (int i = 0; i < callbackCount; i++) {
+                        ModeCallback callback = callbacks.valueAt(i);
+                        ArraySet<String> changedPackages = callbackSpecs.get(callback);
+                        if (changedPackages == null) {
+                            changedPackages = new ArraySet<>();
+                            callbackSpecs.put(callback, changedPackages);
+                        }
+                        changedPackages.add(uidPackageName);
+                    }
+                }
+            }
+        }
+
+        if (callbackSpecs == null) {
+            return;
+        }
+
+        for (int i = 0; i < callbackSpecs.size(); i++) {
+            final ModeCallback callback = callbackSpecs.keyAt(i);
+            final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
+            if (reportedPackageNames == null) {
+                mHandler.sendMessage(PooledLambda.obtainMessage(
+                        AppOpsService::notifyOpChanged,
+                        this, callback, code, uid, (String) null));
+
+            } else {
+                final int reportedPackageCount = reportedPackageNames.size();
+                for (int j = 0; j < reportedPackageCount; j++) {
+                    final String reportedPackageName = reportedPackageNames.valueAt(j);
+                    mHandler.sendMessage(PooledLambda.obtainMessage(
+                            AppOpsService::notifyOpChanged,
+                            this, callback, code, uid, reportedPackageName));
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setMode(int code, int uid, String packageName, int mode) {
+        setMode(code, uid, packageName, mode, true, false);
+    }
+
+    /**
+     * Sets the mode for a certain op and uid.
+     *
+     * @param code The op code to set
+     * @param uid The UID for which to set
+     * @param packageName The package for which to set
+     * @param mode The new mode to set
+     * @param verifyUid Iff {@code true}, check that the package name belongs to the uid
+     * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid ==
+     *                     false})
+     */
+    private void setMode(int code, int uid, @NonNull String packageName, int mode,
+            boolean verifyUid, boolean isPrivileged) {
+        enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
+        verifyIncomingOp(code);
+        ArraySet<ModeCallback> repCbs = null;
+        code = AppOpsManager.opToSwitch(code);
+        synchronized (this) {
+            UidState uidState = getUidStateLocked(uid, false);
+            Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged);
+            if (op != null) {
+                if (op.mode != mode) {
+                    op.mode = mode;
+                    if (uidState != null) {
+                        uidState.evalForegroundOps(mOpModeWatchers);
+                    }
+                    ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
+                    if (cbs != null) {
+                        if (repCbs == null) {
+                            repCbs = new ArraySet<>();
+                        }
+                        repCbs.addAll(cbs);
+                    }
+                    cbs = mPackageModeWatchers.get(packageName);
+                    if (cbs != null) {
+                        if (repCbs == null) {
+                            repCbs = new ArraySet<>();
+                        }
+                        repCbs.addAll(cbs);
+                    }
+                    if (mode == AppOpsManager.opToDefaultMode(op.op)) {
+                        // If going into the default mode, prune this op
+                        // if there is nothing else interesting in it.
+                        pruneOp(op, uid, packageName);
+                    }
+                    scheduleFastWriteLocked();
+                }
+            }
+        }
+        if (repCbs != null) {
+            mHandler.sendMessage(PooledLambda.obtainMessage(
+                    AppOpsService::notifyOpChanged,
+                    this, repCbs, code, uid, packageName));
+        }
+    }
+
+    private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
+            int uid, String packageName) {
+        for (int i = 0; i < callbacks.size(); i++) {
+            final ModeCallback callback = callbacks.valueAt(i);
+            notifyOpChanged(callback, code, uid, packageName);
+        }
+    }
+
+    private void notifyOpChanged(ModeCallback callback, int code,
+            int uid, String packageName) {
+        if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
+            return;
+        }
+        // There are components watching for mode changes such as window manager
+        // and location manager which are in our process. The callbacks in these
+        // components may require permissions our remote caller does not have.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            callback.mCallback.opChanged(code, uid, packageName);
+        } catch (RemoteException e) {
+            /* ignore */
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
+            HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
+            int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
+        if (cbs == null) {
+            return callbacks;
+        }
+        if (callbacks == null) {
+            callbacks = new HashMap<>();
+        }
+        boolean duplicate = false;
+        final int N = cbs.size();
+        for (int i=0; i<N; i++) {
+            ModeCallback cb = cbs.valueAt(i);
+            ArrayList<ChangeRec> reports = callbacks.get(cb);
+            if (reports == null) {
+                reports = new ArrayList<>();
+                callbacks.put(cb, reports);
+            } else {
+                final int reportCount = reports.size();
+                for (int j = 0; j < reportCount; j++) {
+                    ChangeRec report = reports.get(j);
+                    if (report.op == op && report.pkg.equals(packageName)) {
+                        duplicate = true;
+                        break;
+                    }
+                }
+            }
+            if (!duplicate) {
+                reports.add(new ChangeRec(op, uid, packageName));
+            }
+        }
+        return callbacks;
+    }
+
+    static final class ChangeRec {
+        final int op;
+        final int uid;
+        final String pkg;
+
+        ChangeRec(int _op, int _uid, String _pkg) {
+            op = _op;
+            uid = _uid;
+            pkg = _pkg;
+        }
+    }
+
+    @Override
+    public void resetAllModes(int reqUserId, String reqPackageName) {
+        final int callingPid = Binder.getCallingPid();
+        final int callingUid = Binder.getCallingUid();
+        reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
+                true, true, "resetAllModes", null);
+
+        int reqUid = -1;
+        if (reqPackageName != null) {
+            try {
+                reqUid = AppGlobals.getPackageManager().getPackageUid(
+                        reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
+            } catch (RemoteException e) {
+                /* ignore - local call */
+            }
+        }
+
+        enforceManageAppOpsModes(callingPid, callingUid, reqUid);
+
+        HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
+        synchronized (this) {
+            boolean changed = false;
+            for (int i = mUidStates.size() - 1; i >= 0; i--) {
+                UidState uidState = mUidStates.valueAt(i);
+
+                SparseIntArray opModes = uidState.opModes;
+                if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
+                    final int uidOpCount = opModes.size();
+                    for (int j = uidOpCount - 1; j >= 0; j--) {
+                        final int code = opModes.keyAt(j);
+                        if (AppOpsManager.opAllowsReset(code)) {
+                            opModes.removeAt(j);
+                            if (opModes.size() <= 0) {
+                                uidState.opModes = null;
+                            }
+                            for (String packageName : getPackagesForUid(uidState.uid)) {
+                                callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
+                                        mOpModeWatchers.get(code));
+                                callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
+                                        mPackageModeWatchers.get(packageName));
+                            }
+                        }
+                    }
+                }
+
+                if (uidState.pkgOps == null) {
+                    continue;
+                }
+
+                if (reqUserId != UserHandle.USER_ALL
+                        && reqUserId != UserHandle.getUserId(uidState.uid)) {
+                    // Skip any ops for a different user
+                    continue;
+                }
+
+                Map<String, Ops> packages = uidState.pkgOps;
+                Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
+                boolean uidChanged = false;
+                while (it.hasNext()) {
+                    Map.Entry<String, Ops> ent = it.next();
+                    String packageName = ent.getKey();
+                    if (reqPackageName != null && !reqPackageName.equals(packageName)) {
+                        // Skip any ops for a different package
+                        continue;
+                    }
+                    Ops pkgOps = ent.getValue();
+                    for (int j=pkgOps.size()-1; j>=0; j--) {
+                        Op curOp = pkgOps.valueAt(j);
+                        if (AppOpsManager.opAllowsReset(curOp.op)
+                                && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
+                            curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
+                            changed = true;
+                            uidChanged = true;
+                            callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
+                                    mOpModeWatchers.get(curOp.op));
+                            callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
+                                    mPackageModeWatchers.get(packageName));
+                            if (!curOp.hasAnyTime()) {
+                                pkgOps.removeAt(j);
+                            }
+                        }
+                    }
+                    if (pkgOps.size() == 0) {
+                        it.remove();
+                    }
+                }
+                if (uidState.isDefault()) {
+                    mUidStates.remove(uidState.uid);
+                }
+                if (uidChanged) {
+                    uidState.evalForegroundOps(mOpModeWatchers);
+                }
+            }
+
+            if (changed) {
+                scheduleFastWriteLocked();
+            }
+        }
+        if (callbacks != null) {
+            for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
+                ModeCallback cb = ent.getKey();
+                ArrayList<ChangeRec> reports = ent.getValue();
+                for (int i=0; i<reports.size(); i++) {
+                    ChangeRec rep = reports.get(i);
+                    mHandler.sendMessage(PooledLambda.obtainMessage(
+                            AppOpsService::notifyOpChanged,
+                            this, cb, rep.op, rep.uid, rep.pkg));
+                }
+            }
+        }
+    }
+
+    private void evalAllForegroundOpsLocked() {
+        for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
+            final UidState uidState = mUidStates.valueAt(uidi);
+            if (uidState.foregroundOps != null) {
+                uidState.evalForegroundOps(mOpModeWatchers);
+            }
+        }
+    }
+
+    @Override
+    public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
+        startWatchingModeWithFlags(op, packageName, 0, callback);
+    }
+
+    @Override
+    public void startWatchingModeWithFlags(int op, String packageName, int flags,
+            IAppOpsCallback callback) {
+        int watchedUid = -1;
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
+        // TODO: should have a privileged permission to protect this.
+        // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
+        // the USAGE_STATS permission since this can provide information about when an
+        // app is in the foreground?
+        Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
+                AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
+        if (callback == null) {
+            return;
+        }
+        synchronized (this) {
+            op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
+            ModeCallback cb = mModeWatchers.get(callback.asBinder());
+            if (cb == null) {
+                cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
+                mModeWatchers.put(callback.asBinder(), cb);
+            }
+            if (op != AppOpsManager.OP_NONE) {
+                ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op);
+                if (cbs == null) {
+                    cbs = new ArraySet<>();
+                    mOpModeWatchers.put(op, cbs);
+                }
+                cbs.add(cb);
+            }
+            if (packageName != null) {
+                ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
+                if (cbs == null) {
+                    cbs = new ArraySet<>();
+                    mPackageModeWatchers.put(packageName, cbs);
+                }
+                cbs.add(cb);
+            }
+            evalAllForegroundOpsLocked();
+        }
+    }
+
+    @Override
+    public void stopWatchingMode(IAppOpsCallback callback) {
+        if (callback == null) {
+            return;
+        }
+        synchronized (this) {
+            ModeCallback cb = mModeWatchers.remove(callback.asBinder());
+            if (cb != null) {
+                cb.unlinkToDeath();
+                for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
+                    ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
+                    cbs.remove(cb);
+                    if (cbs.size() <= 0) {
+                        mOpModeWatchers.removeAt(i);
+                    }
+                }
+                for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
+                    ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
+                    cbs.remove(cb);
+                    if (cbs.size() <= 0) {
+                        mPackageModeWatchers.removeAt(i);
+                    }
+                }
+            }
+            evalAllForegroundOpsLocked();
+        }
+    }
+
+    @Override
+    public IBinder getToken(IBinder clientToken) {
+        synchronized (this) {
+            ClientState cs = mClients.get(clientToken);
+            if (cs == null) {
+                cs = new ClientState(clientToken);
+                mClients.put(clientToken, cs);
+            }
+            return cs;
+        }
+    }
+
+    public CheckOpsDelegate getAppOpsServiceDelegate() {
+        synchronized (this) {
+            return mCheckOpsDelegate;
+        }
+    }
+
+    public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
+        synchronized (this) {
+            mCheckOpsDelegate = delegate;
+        }
+    }
+
+    @Override
+    public int checkOperationRaw(int code, int uid, String packageName) {
+        return checkOperationInternal(code, uid, packageName, true /*raw*/);
+    }
+
+    @Override
+    public int checkOperation(int code, int uid, String packageName) {
+        return checkOperationInternal(code, uid, packageName, false /*raw*/);
+    }
+
+    private int checkOperationInternal(int code, int uid, String packageName, boolean raw) {
+        final CheckOpsDelegate delegate;
+        synchronized (this) {
+            delegate = mCheckOpsDelegate;
+        }
+        if (delegate == null) {
+            return checkOperationImpl(code, uid, packageName, raw);
+        }
+        return delegate.checkOperation(code, uid, packageName, raw,
+                    AppOpsService.this::checkOperationImpl);
+    }
+
+    private int checkOperationImpl(int code, int uid, String packageName,
+                boolean raw) {
+        verifyIncomingUid(uid);
+        verifyIncomingOp(code);
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+        return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
+    }
+
+    private int checkOperationUnchecked(int code, int uid, String packageName,
+                boolean raw) {
+        synchronized (this) {
+            if (isOpRestrictedLocked(uid, code, packageName)) {
+                return AppOpsManager.MODE_IGNORED;
+            }
+            code = AppOpsManager.opToSwitch(code);
+            UidState uidState = getUidStateLocked(uid, false);
+            if (uidState != null && uidState.opModes != null
+                    && uidState.opModes.indexOfKey(code) >= 0) {
+                final int rawMode = uidState.opModes.get(code);
+                return raw ? rawMode : uidState.evalMode(rawMode);
+            }
+            Op op = getOpLocked(code, uid, packageName, false, true, false);
+            if (op == null) {
+                return AppOpsManager.opToDefaultMode(code);
+            }
+            return op.mode;
+        }
+    }
+
+    @Override
+    public int checkAudioOperation(int code, int usage, int uid, String packageName) {
+        final CheckOpsDelegate delegate;
+        synchronized (this) {
+            delegate = mCheckOpsDelegate;
+        }
+        if (delegate == null) {
+            return checkAudioOperationImpl(code, usage, uid, packageName);
+        }
+        return delegate.checkAudioOperation(code, usage, uid, packageName,
+                AppOpsService.this::checkAudioOperationImpl);
+    }
+
+    private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) {
+        boolean suspended;
+        try {
+            suspended = isPackageSuspendedForUser(packageName, uid);
+        } catch (IllegalArgumentException ex) {
+            // Package not found.
+            suspended = false;
+        }
+
+        if (suspended) {
+            Slog.i(TAG, "Audio disabled for suspended package=" + packageName
+                    + " for uid=" + uid);
+            return AppOpsManager.MODE_IGNORED;
+        }
+
+        synchronized (this) {
+            final int mode = checkRestrictionLocked(code, usage, uid, packageName);
+            if (mode != AppOpsManager.MODE_ALLOWED) {
+                return mode;
+            }
+        }
+        return checkOperation(code, uid, packageName);
+    }
+
+    private boolean isPackageSuspendedForUser(String pkg, int uid) {
+        try {
+            return AppGlobals.getPackageManager().isPackageSuspendedForUser(
+                    pkg, UserHandle.getUserId(uid));
+        } catch (RemoteException re) {
+            throw new SecurityException("Could not talk to package manager service");
+        }
+    }
+
+    private int checkRestrictionLocked(int code, int usage, int uid, String packageName) {
+        final SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
+        if (usageRestrictions != null) {
+            final Restriction r = usageRestrictions.get(usage);
+            if (r != null && !r.exceptionPackages.contains(packageName)) {
+                return r.mode;
+            }
+        }
+        return AppOpsManager.MODE_ALLOWED;
+    }
+
+    @Override
+    public void setAudioRestriction(int code, int usage, int uid, int mode,
+            String[] exceptionPackages) {
+        enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
+        verifyIncomingUid(uid);
+        verifyIncomingOp(code);
+        synchronized (this) {
+            SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
+            if (usageRestrictions == null) {
+                usageRestrictions = new SparseArray<Restriction>();
+                mAudioRestrictions.put(code, usageRestrictions);
+            }
+            usageRestrictions.remove(usage);
+            if (mode != AppOpsManager.MODE_ALLOWED) {
+                final Restriction r = new Restriction();
+                r.mode = mode;
+                if (exceptionPackages != null) {
+                    final int N = exceptionPackages.length;
+                    r.exceptionPackages = new ArraySet<String>(N);
+                    for (int i = 0; i < N; i++) {
+                        final String pkg = exceptionPackages[i];
+                        if (pkg != null) {
+                            r.exceptionPackages.add(pkg.trim());
+                        }
+                    }
+                }
+                usageRestrictions.put(usage, r);
+            }
+        }
+
+        mHandler.sendMessage(PooledLambda.obtainMessage(
+                AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
+    }
+
+    @Override
+    public int checkPackage(int uid, String packageName) {
+        Preconditions.checkNotNull(packageName);
+        synchronized (this) {
+            Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
+                    true /* uidMismatchExpected */);
+            if (ops != null) {
+                return AppOpsManager.MODE_ALLOWED;
+            } else {
+                return AppOpsManager.MODE_ERRORED;
+            }
+        }
+    }
+
+    @Override
+    public int noteProxyOperation(int code, int proxyUid,
+            String proxyPackageName, int proxiedUid, String proxiedPackageName) {
+        verifyIncomingUid(proxyUid);
+        verifyIncomingOp(code);
+        String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
+        if (resolveProxyPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+        final int proxyMode = noteOperationUnchecked(code, proxyUid,
+                resolveProxyPackageName, -1, null);
+        if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
+            return proxyMode;
+        }
+        String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
+        if (resolveProxiedPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+        return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
+                proxyMode, resolveProxyPackageName);
+    }
+
+    @Override
+    public int noteOperation(int code, int uid, String packageName) {
+        final CheckOpsDelegate delegate;
+        synchronized (this) {
+            delegate = mCheckOpsDelegate;
+        }
+        if (delegate == null) {
+            return noteOperationImpl(code, uid, packageName);
+        }
+        return delegate.noteOperation(code, uid, packageName,
+                AppOpsService.this::noteOperationImpl);
+    }
+
+    private int noteOperationImpl(int code, int uid, String packageName) {
+        verifyIncomingUid(uid);
+        verifyIncomingOp(code);
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+        return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
+    }
+
+    private int noteOperationUnchecked(int code, int uid, String packageName,
+            int proxyUid, String proxyPackageName) {
+        synchronized (this) {
+            final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
+                    false /* uidMismatchExpected */);
+            if (ops == null) {
+                scheduleOpNotedIfNeededLocked(code, uid, packageName,
+                        AppOpsManager.MODE_IGNORED);
+                if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
+                        + " package " + packageName);
+                return AppOpsManager.MODE_ERRORED;
+            }
+            final Op op = getOpLocked(ops, code, true);
+            if (isOpRestrictedLocked(uid, code, packageName)) {
+                scheduleOpNotedIfNeededLocked(code, uid, packageName,
+                        AppOpsManager.MODE_IGNORED);
+                return AppOpsManager.MODE_IGNORED;
+            }
+            final UidState uidState = ops.uidState;
+            if (op.duration == -1) {
+                Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
+                        + " code " + code + " time=" + op.time[uidState.state]
+                        + " duration=" + op.duration);
+            }
+            op.duration = 0;
+            final int switchCode = AppOpsManager.opToSwitch(code);
+            // If there is a non-default per UID policy (we set UID op mode only if
+            // non-default) it takes over, otherwise use the per package policy.
+            if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
+                final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
+                if (uidMode != AppOpsManager.MODE_ALLOWED) {
+                    if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
+                            + switchCode + " (" + code + ") uid " + uid + " package "
+                            + packageName);
+                    op.rejectTime[uidState.state] = System.currentTimeMillis();
+                    scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
+                    mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
+                            uidState.state);
+                    return uidMode;
+                }
+            } else {
+                final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
+                final int mode = switchOp.getMode();
+                if (mode != AppOpsManager.MODE_ALLOWED) {
+                    if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
+                            + switchCode + " (" + code + ") uid " + uid + " package "
+                            + packageName);
+                    op.rejectTime[uidState.state] = System.currentTimeMillis();
+                    scheduleOpNotedIfNeededLocked(op.op, uid, packageName, mode);
+                    mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
+                            uidState.state);
+                    return mode;
+                }
+            }
+            if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
+                    + " package " + packageName);
+            op.time[uidState.state] = System.currentTimeMillis();
+            mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName,
+                    uidState.state);
+            op.rejectTime[uidState.state] = 0;
+            op.proxyUid = proxyUid;
+            op.proxyPackageName = proxyPackageName;
+            scheduleOpNotedIfNeededLocked(code, uid, packageName,
+                    AppOpsManager.MODE_ALLOWED);
+            return AppOpsManager.MODE_ALLOWED;
+        }
+    }
+
+    @Override
+    public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
+        int watchedUid = -1;
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
+                != PackageManager.PERMISSION_GRANTED) {
+            watchedUid = callingUid;
+        }
+        if (ops != null) {
+            Preconditions.checkArrayElementsInRange(ops, 0,
+                    AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
+        }
+        if (callback == null) {
+            return;
+        }
+        synchronized (this) {
+            SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
+            if (callbacks == null) {
+                callbacks = new SparseArray<>();
+                mActiveWatchers.put(callback.asBinder(), callbacks);
+            }
+            final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
+                    callingUid, callingPid);
+            for (int op : ops) {
+                callbacks.put(op, activeCallback);
+            }
+        }
+    }
+
+    @Override
+    public void stopWatchingActive(IAppOpsActiveCallback callback) {
+        if (callback == null) {
+            return;
+        }
+        synchronized (this) {
+            final SparseArray<ActiveCallback> activeCallbacks =
+                    mActiveWatchers.remove(callback.asBinder());
+            if (activeCallbacks == null) {
+                return;
+            }
+            final int callbackCount = activeCallbacks.size();
+            for (int i = 0; i < callbackCount; i++) {
+                activeCallbacks.valueAt(i).destroy();
+            }
+        }
+    }
+
+    @Override
+    public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
+        int watchedUid = Process.INVALID_UID;
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
+                != PackageManager.PERMISSION_GRANTED) {
+            watchedUid = callingUid;
+        }
+        Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
+        Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
+                "Invalid op code in: " + Arrays.toString(ops));
+        Preconditions.checkNotNull(callback, "Callback cannot be null");
+        synchronized (this) {
+            SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
+            if (callbacks == null) {
+                callbacks = new SparseArray<>();
+                mNotedWatchers.put(callback.asBinder(), callbacks);
+            }
+            final NotedCallback notedCallback = new NotedCallback(callback, watchedUid,
+                    callingUid, callingPid);
+            for (int op : ops) {
+                callbacks.put(op, notedCallback);
+            }
+        }
+    }
+
+    @Override
+    public void stopWatchingNoted(IAppOpsNotedCallback callback) {
+        Preconditions.checkNotNull(callback, "Callback cannot be null");
+        synchronized (this) {
+            final SparseArray<NotedCallback> notedCallbacks =
+                    mNotedWatchers.remove(callback.asBinder());
+            if (notedCallbacks == null) {
+                return;
+            }
+            final int callbackCount = notedCallbacks.size();
+            for (int i = 0; i < callbackCount; i++) {
+                notedCallbacks.valueAt(i).destroy();
+            }
+        }
+    }
+
+    @Override
+    public int startOperation(IBinder token, int code, int uid, String packageName,
+            boolean startIfModeDefault) {
+        verifyIncomingUid(uid);
+        verifyIncomingOp(code);
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return  AppOpsManager.MODE_IGNORED;
+        }
+        ClientState client = (ClientState)token;
+        synchronized (this) {
+            final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
+                    false /* uidMismatchExpected */);
+            if (ops == null) {
+                if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
+                        + " package " + resolvedPackageName);
+                return AppOpsManager.MODE_ERRORED;
+            }
+            final Op op = getOpLocked(ops, code, true);
+            if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
+                return AppOpsManager.MODE_IGNORED;
+            }
+            final int switchCode = AppOpsManager.opToSwitch(code);
+            final UidState uidState = ops.uidState;
+            // If there is a non-default per UID policy (we set UID op mode only if
+            // non-default) it takes over, otherwise use the per package policy.
+            if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
+                final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
+                if (uidMode != AppOpsManager.MODE_ALLOWED
+                        && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
+                    if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
+                            + switchCode + " (" + code + ") uid " + uid + " package "
+                            + resolvedPackageName);
+                    op.rejectTime[uidState.state] = System.currentTimeMillis();
+                    mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
+                            uidState.state);
+                    return uidMode;
+                }
+            } else {
+                final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
+                final int mode = switchOp.getMode();
+                if (mode != AppOpsManager.MODE_ALLOWED
+                        && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
+                    if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
+                            + switchCode + " (" + code + ") uid " + uid + " package "
+                            + resolvedPackageName);
+                    op.rejectTime[uidState.state] = System.currentTimeMillis();
+                    mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
+                            uidState.state);
+                    return mode;
+                }
+            }
+            if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
+                    + " package " + resolvedPackageName);
+            if (op.startNesting == 0) {
+                op.startRealtime = SystemClock.elapsedRealtime();
+                op.time[uidState.state] = System.currentTimeMillis();
+                mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName,
+                        uidState.state);
+                op.rejectTime[uidState.state] = 0;
+                op.duration = -1;
+                scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
+            }
+            op.startNesting++;
+            uidState.startNesting++;
+            if (client.mStartedOps != null) {
+                client.mStartedOps.add(op);
+            }
+        }
+
+        return AppOpsManager.MODE_ALLOWED;
+    }
+
+    @Override
+    public void finishOperation(IBinder token, int code, int uid, String packageName) {
+        verifyIncomingUid(uid);
+        verifyIncomingOp(code);
+        String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return;
+        }
+        if (!(token instanceof ClientState)) {
+            return;
+        }
+        ClientState client = (ClientState) token;
+        synchronized (this) {
+            Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false);
+            if (op == null) {
+                return;
+            }
+            if (!client.mStartedOps.remove(op)) {
+                // We finish ops when packages get removed to guarantee no dangling
+                // started ops. However, some part of the system may asynchronously
+                // finish ops for an already gone package. Hence, finishing an op
+                // for a non existing package is fine and we don't log as a wtf.
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    if (LocalServices.getService(PackageManagerInternal.class).getPackageUid(
+                            resolvedPackageName, 0, UserHandle.getUserId(uid)) < 0) {
+                        Slog.i(TAG, "Finishing op=" + AppOpsManager.opToName(code)
+                                + " for non-existing package=" + resolvedPackageName
+                                + " in uid=" + uid);
+                        return;
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+                Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
+                        + op.packageName + " op=" + AppOpsManager.opToName(op.op));
+                return;
+            }
+            finishOperationLocked(op, /*finishNested*/ false);
+            if (op.startNesting <= 0) {
+                scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false);
+            }
+        }
+    }
+
+    private void scheduleOpActiveChangedIfNeededLocked(int code, int uid, String packageName,
+            boolean active) {
+        ArraySet<ActiveCallback> dispatchedCallbacks = null;
+        final int callbackListCount = mActiveWatchers.size();
+        for (int i = 0; i < callbackListCount; i++) {
+            final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
+            ActiveCallback callback = callbacks.get(code);
+            if (callback != null) {
+                if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
+                    continue;
+                }
+                if (dispatchedCallbacks == null) {
+                    dispatchedCallbacks = new ArraySet<>();
+                }
+                dispatchedCallbacks.add(callback);
+            }
+        }
+        if (dispatchedCallbacks == null) {
+            return;
+        }
+        mHandler.sendMessage(PooledLambda.obtainMessage(
+                AppOpsService::notifyOpActiveChanged,
+                this, dispatchedCallbacks, code, uid, packageName, active));
+    }
+
+    private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
+            int code, int uid, String packageName, boolean active) {
+        // There are components watching for mode changes such as window manager
+        // and location manager which are in our process. The callbacks in these
+        // components may require permissions our remote caller does not have.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final int callbackCount = callbacks.size();
+            for (int i = 0; i < callbackCount; i++) {
+                final ActiveCallback callback = callbacks.valueAt(i);
+                try {
+                    callback.mCallback.opActiveChanged(code, uid, packageName, active);
+                } catch (RemoteException e) {
+                    /* do nothing */
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
+            int result) {
+        ArraySet<NotedCallback> dispatchedCallbacks = null;
+        final int callbackListCount = mNotedWatchers.size();
+        for (int i = 0; i < callbackListCount; i++) {
+            final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i);
+            final NotedCallback callback = callbacks.get(code);
+            if (callback != null) {
+                if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
+                    continue;
+                }
+                if (dispatchedCallbacks == null) {
+                    dispatchedCallbacks = new ArraySet<>();
+                }
+                dispatchedCallbacks.add(callback);
+            }
+        }
+        if (dispatchedCallbacks == null) {
+            return;
+        }
+        mHandler.sendMessage(PooledLambda.obtainMessage(
+                AppOpsService::notifyOpChecked,
+                this, dispatchedCallbacks, code, uid, packageName, result));
+    }
+
+    private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
+            int code, int uid, String packageName, int result) {
+        // There are components watching for checks in our process. The callbacks in
+        // these components may require permissions our remote caller does not have.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final int callbackCount = callbacks.size();
+            for (int i = 0; i < callbackCount; i++) {
+                final NotedCallback callback = callbacks.valueAt(i);
+                try {
+                    callback.mCallback.opNoted(code, uid, packageName, result);
+                } catch (RemoteException e) {
+                    /* do nothing */
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public int permissionToOpCode(String permission) {
+        if (permission == null) {
+            return AppOpsManager.OP_NONE;
+        }
+        return AppOpsManager.permissionToOpCode(permission);
+    }
+
+    void finishOperationLocked(Op op, boolean finishNested) {
+        if (op.startNesting <= 1 || finishNested) {
+            if (op.startNesting == 1 || finishNested) {
+                op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
+                mHistoricalRegistry.increaseOpAccessDuration(op.op, op.uid, op.packageName,
+                        op.uidState.state, op.duration);
+                op.time[op.uidState.state] = System.currentTimeMillis();
+            } else {
+                Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
+                        + op.packageName + " code " + op.op + " time=" + op.time
+                        + " duration=" + op.duration + " nesting=" + op.startNesting);
+            }
+            if (op.startNesting >= 1) {
+                op.uidState.startNesting -= op.startNesting;
+            }
+            op.startNesting = 0;
+        } else {
+            op.startNesting--;
+            op.uidState.startNesting--;
+        }
+    }
+
+    private void verifyIncomingUid(int uid) {
+        if (uid == Binder.getCallingUid()) {
+            return;
+        }
+        if (Binder.getCallingPid() == Process.myPid()) {
+            return;
+        }
+        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
+                Binder.getCallingPid(), Binder.getCallingUid(), null);
+    }
+
+    private void verifyIncomingOp(int op) {
+        if (op >= 0 && op < AppOpsManager._NUM_OP) {
+            return;
+        }
+        throw new IllegalArgumentException("Bad operation #" + op);
+    }
+
+    private UidState getUidStateLocked(int uid, boolean edit) {
+        UidState uidState = mUidStates.get(uid);
+        if (uidState == null) {
+            if (!edit) {
+                return null;
+            }
+            uidState = new UidState(uid);
+            mUidStates.put(uid, uidState);
+        } else {
+            if (uidState.pendingStateCommitTime != 0) {
+                if (uidState.pendingStateCommitTime < mLastRealtime) {
+                    commitUidPendingStateLocked(uidState);
+                } else {
+                    mLastRealtime = SystemClock.elapsedRealtime();
+                    if (uidState.pendingStateCommitTime < mLastRealtime) {
+                        commitUidPendingStateLocked(uidState);
+                    }
+                }
+            }
+        }
+        return uidState;
+    }
+
+    private void commitUidPendingStateLocked(UidState uidState) {
+        final boolean lastForeground = uidState.state <= UID_STATE_LAST_NON_RESTRICTED;
+        final boolean nowForeground = uidState.pendingState <= UID_STATE_LAST_NON_RESTRICTED;
+        uidState.state = uidState.pendingState;
+        uidState.pendingStateCommitTime = 0;
+        if (uidState.hasForegroundWatchers && lastForeground != nowForeground) {
+            for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
+                if (!uidState.foregroundOps.valueAt(fgi)) {
+                    continue;
+                }
+                final int code = uidState.foregroundOps.keyAt(fgi);
+
+                final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
+                if (callbacks != null) {
+                    for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
+                        final ModeCallback callback = callbacks.valueAt(cbi);
+                        if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
+                                || !callback.isWatchingUid(uidState.uid)) {
+                            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--) {
+                                final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
+                                if (doAllPackages || (op != null
+                                        && op.mode == AppOpsManager.MODE_FOREGROUND)) {
+                                    mHandler.sendMessage(PooledLambda.obtainMessage(
+                                            AppOpsService::notifyOpChanged,
+                                            this, callback, code, uidState.uid,
+                                            uidState.pkgOps.keyAt(pkgi)));
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
+            boolean uidMismatchExpected) {
+        UidState uidState = getUidStateLocked(uid, edit);
+        if (uidState == null) {
+            return null;
+        }
+
+        if (uidState.pkgOps == null) {
+            if (!edit) {
+                return null;
+            }
+            uidState.pkgOps = new ArrayMap<>();
+        }
+
+        Ops ops = uidState.pkgOps.get(packageName);
+        if (ops == null) {
+            if (!edit) {
+                return null;
+            }
+            boolean isPrivileged = false;
+            // This is the first time we have seen this package name under this uid,
+            // so let's make sure it is valid.
+            if (uid != 0) {
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    int pkgUid = -1;
+                    try {
+                        ApplicationInfo appInfo = ActivityThread.getPackageManager()
+                                .getApplicationInfo(packageName,
+                                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                                        UserHandle.getUserId(uid));
+                        if (appInfo != null) {
+                            pkgUid = appInfo.uid;
+                            isPrivileged = (appInfo.privateFlags
+                                    & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+                        } else {
+                            pkgUid = resolveUid(packageName);
+                            if (pkgUid >= 0) {
+                                isPrivileged = false;
+                            }
+                        }
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "Could not contact PackageManager", e);
+                    }
+                    if (pkgUid != uid) {
+                        // Oops!  The package name is not valid for the uid they are calling
+                        // under.  Abort.
+                        if (!uidMismatchExpected) {
+                            RuntimeException ex = new RuntimeException("here");
+                            ex.fillInStackTrace();
+                            Slog.w(TAG, "Bad call: specified package " + packageName
+                                    + " under uid " + uid + " but it is really " + pkgUid, ex);
+                        }
+                        return null;
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+            ops = new Ops(packageName, uidState, isPrivileged);
+            uidState.pkgOps.put(packageName, ops);
+        }
+        return ops;
+    }
+
+    /**
+     * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>.
+     *
+     * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
+     *
+     * @param uid The uid the of the package
+     * @param packageName The package name for which to get the state for
+     * @param edit Iff {@code true} create the {@link Ops} object if not yet created
+     * @param isPrivileged Whether the package is privileged or not
+     *
+     * @return The {@link Ops state} of all ops for the package
+     */
+    private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
+            boolean edit, boolean isPrivileged) {
+        UidState uidState = getUidStateLocked(uid, edit);
+        if (uidState == null) {
+            return null;
+        }
+
+        if (uidState.pkgOps == null) {
+            if (!edit) {
+                return null;
+            }
+            uidState.pkgOps = new ArrayMap<>();
+        }
+
+        Ops ops = uidState.pkgOps.get(packageName);
+        if (ops == null) {
+            if (!edit) {
+                return null;
+            }
+            ops = new Ops(packageName, uidState, isPrivileged);
+            uidState.pkgOps.put(packageName, ops);
+        }
+        return ops;
+    }
+
+    private void scheduleWriteLocked() {
+        if (!mWriteScheduled) {
+            mWriteScheduled = true;
+            mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
+        }
+    }
+
+    private void scheduleFastWriteLocked() {
+        if (!mFastWriteScheduled) {
+            mWriteScheduled = true;
+            mFastWriteScheduled = true;
+            mHandler.removeCallbacks(mWriteRunner);
+            mHandler.postDelayed(mWriteRunner, 10*1000);
+        }
+    }
+
+    /**
+     * Get the state of an op for a uid.
+     *
+     * @param code The code of the op
+     * @param uid The uid the of the package
+     * @param packageName The package name for which to get the state for
+     * @param edit Iff {@code true} create the {@link Op} object if not yet created
+     * @param verifyUid Iff {@code true} check that the package belongs to the uid
+     * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid
+     *                     == false})
+     *
+     * @return The {@link Op state} of the op
+     */
+    private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit,
+            boolean verifyUid, boolean isPrivileged) {
+        Ops ops;
+
+        if (verifyUid) {
+            ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */);
+        }  else {
+            ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
+        }
+
+        if (ops == null) {
+            return null;
+        }
+        return getOpLocked(ops, code, edit);
+    }
+
+    private Op getOpLocked(Ops ops, int code, boolean edit) {
+        Op op = ops.get(code);
+        if (op == null) {
+            if (!edit) {
+                return null;
+            }
+            op = new Op(ops.uidState, ops.packageName, code);
+            ops.put(code, op);
+        }
+        if (edit) {
+            scheduleWriteLocked();
+        }
+        return op;
+    }
+
+    private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
+        int userHandle = UserHandle.getUserId(uid);
+        final int restrictionSetCount = mOpUserRestrictions.size();
+
+        for (int i = 0; i < restrictionSetCount; i++) {
+            // For each client, check that the given op is not restricted, or that the given
+            // package is exempt from the restriction.
+            ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
+            if (restrictionState.hasRestriction(code, packageName, userHandle)) {
+                if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
+                    // If we are the system, bypass user restrictions for certain codes
+                    synchronized (this) {
+                        Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
+                                false /* uidMismatchExpected */);
+                        if ((ops != null) && ops.isPrivileged) {
+                            return false;
+                        }
+                    }
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void readState() {
+        int oldVersion = NO_VERSION;
+        synchronized (mFile) {
+            synchronized (this) {
+                FileInputStream stream;
+                try {
+                    stream = mFile.openRead();
+                } catch (FileNotFoundException e) {
+                    Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
+                    return;
+                }
+                boolean success = false;
+                mUidStates.clear();
+                try {
+                    XmlPullParser parser = Xml.newPullParser();
+                    parser.setInput(stream, StandardCharsets.UTF_8.name());
+                    int type;
+                    while ((type = parser.next()) != XmlPullParser.START_TAG
+                            && type != XmlPullParser.END_DOCUMENT) {
+                        ;
+                    }
+
+                    if (type != XmlPullParser.START_TAG) {
+                        throw new IllegalStateException("no start tag found");
+                    }
+
+                    final String versionString = parser.getAttributeValue(null, "v");
+                    if (versionString != null) {
+                        oldVersion = Integer.parseInt(versionString);
+                    }
+
+                    int outerDepth = parser.getDepth();
+                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                            && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                            continue;
+                        }
+
+                        String tagName = parser.getName();
+                        if (tagName.equals("pkg")) {
+                            readPackage(parser);
+                        } else if (tagName.equals("uid")) {
+                            readUidOps(parser);
+                        } else {
+                            Slog.w(TAG, "Unknown element under <app-ops>: "
+                                    + parser.getName());
+                            XmlUtils.skipCurrentTag(parser);
+                        }
+                    }
+                    success = true;
+                } catch (IllegalStateException e) {
+                    Slog.w(TAG, "Failed parsing " + e);
+                } catch (NullPointerException e) {
+                    Slog.w(TAG, "Failed parsing " + e);
+                } catch (NumberFormatException e) {
+                    Slog.w(TAG, "Failed parsing " + e);
+                } catch (XmlPullParserException e) {
+                    Slog.w(TAG, "Failed parsing " + e);
+                } catch (IOException e) {
+                    Slog.w(TAG, "Failed parsing " + e);
+                } catch (IndexOutOfBoundsException e) {
+                    Slog.w(TAG, "Failed parsing " + e);
+                } finally {
+                    if (!success) {
+                        mUidStates.clear();
+                    }
+                    try {
+                        stream.close();
+                    } catch (IOException e) {
+                    }
+                }
+            }
+        }
+        synchronized (this) {
+            upgradeLocked(oldVersion);
+        }
+    }
+
+    private void upgradeRunAnyInBackgroundLocked() {
+        for (int i = 0; i < mUidStates.size(); i++) {
+            final UidState uidState = mUidStates.valueAt(i);
+            if (uidState == null) {
+                continue;
+            }
+            if (uidState.opModes != null) {
+                final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
+                if (idx >= 0) {
+                    uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
+                            uidState.opModes.valueAt(idx));
+                }
+            }
+            if (uidState.pkgOps == null) {
+                continue;
+            }
+            boolean changed = false;
+            for (int j = 0; j < uidState.pkgOps.size(); j++) {
+                Ops ops = uidState.pkgOps.valueAt(j);
+                if (ops != null) {
+                    final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
+                    if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
+                        final Op copy = new Op(op.uidState, op.packageName,
+                                AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
+                        copy.mode = op.mode;
+                        ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
+                        changed = true;
+                    }
+                }
+            }
+            if (changed) {
+                uidState.evalForegroundOps(mOpModeWatchers);
+            }
+        }
+    }
+
+    private void upgradeLocked(int oldVersion) {
+        if (oldVersion >= CURRENT_VERSION) {
+            return;
+        }
+        Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
+        switch (oldVersion) {
+            case NO_VERSION:
+                upgradeRunAnyInBackgroundLocked();
+                // fall through
+            case 1:
+                // for future upgrades
+        }
+        scheduleFastWriteLocked();
+    }
+
+    void readUidOps(XmlPullParser parser) throws NumberFormatException,
+            XmlPullParserException, IOException {
+        final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals("op")) {
+                final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
+                final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
+                UidState uidState = getUidStateLocked(uid, true);
+                if (uidState.opModes == null) {
+                    uidState.opModes = new SparseIntArray();
+                }
+                uidState.opModes.put(code, mode);
+            } else {
+                Slog.w(TAG, "Unknown element under <uid-ops>: "
+                        + parser.getName());
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+    }
+
+    void readPackage(XmlPullParser parser) throws NumberFormatException,
+            XmlPullParserException, IOException {
+        String pkgName = parser.getAttributeValue(null, "n");
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals("uid")) {
+                readUid(parser, pkgName);
+            } else {
+                Slog.w(TAG, "Unknown element under <pkg>: "
+                        + parser.getName());
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+    }
+
+    void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
+            XmlPullParserException, IOException {
+        int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
+        String isPrivilegedString = parser.getAttributeValue(null, "p");
+        boolean isPrivileged = false;
+        if (isPrivilegedString == null) {
+            try {
+                IPackageManager packageManager = ActivityThread.getPackageManager();
+                if (packageManager != null) {
+                    ApplicationInfo appInfo = ActivityThread.getPackageManager()
+                            .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
+                    if (appInfo != null) {
+                        isPrivileged = (appInfo.privateFlags
+                                & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+                    }
+                } else {
+                    // Could not load data, don't add to cache so it will be loaded later.
+                    return;
+                }
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Could not contact PackageManager", e);
+            }
+        } else {
+            isPrivileged = Boolean.parseBoolean(isPrivilegedString);
+        }
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals("op")) {
+                UidState uidState = getUidStateLocked(uid, true);
+                if (uidState.pkgOps == null) {
+                    uidState.pkgOps = new ArrayMap<>();
+                }
+
+                Op op = new Op(uidState, pkgName,
+                        Integer.parseInt(parser.getAttributeValue(null, "n")));
+
+                for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
+                    final String name = parser.getAttributeName(i);
+                    final String value = parser.getAttributeValue(i);
+                    switch (name) {
+                        case "m":
+                            op.mode = Integer.parseInt(value);
+                            break;
+                        case "d":
+                            op.duration = Integer.parseInt(value);
+                            break;
+                        case "pu":
+                            op.proxyUid = Integer.parseInt(value);
+                            break;
+                        case "pp":
+                            op.proxyPackageName = value;
+                            break;
+                        case "tp":
+                            op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
+                            break;
+                        case "tt":
+                            op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
+                            break;
+                        case "tfs":
+                            op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
+                                    = Long.parseLong(value);
+                            break;
+                        case "tf":
+                            op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
+                            break;
+                        case "tb":
+                            op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
+                            break;
+                        case "tc":
+                            op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
+                            break;
+                        case "rp":
+                            op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT]
+                                    = Long.parseLong(value);
+                            break;
+                        case "rt":
+                            op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
+                            break;
+                        case "rfs":
+                            op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE]
+                                    = Long.parseLong(value);
+                            break;
+                        case "rf":
+                            op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND]
+                                    = Long.parseLong(value);
+                            break;
+                        case "rb":
+                            op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND]
+                                    = Long.parseLong(value);
+                            break;
+                        case "rc":
+                            op.rejectTime[AppOpsManager.UID_STATE_CACHED]
+                                    = Long.parseLong(value);
+                            break;
+                        case "t":
+                            // Backwards compat.
+                            op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
+                            break;
+                        case "r":
+                            // Backwards compat.
+                            op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
+                            break;
+                        default:
+                            Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
+                            break;
+                    }
+                }
+
+                Ops ops = uidState.pkgOps.get(pkgName);
+                if (ops == null) {
+                    ops = new Ops(pkgName, uidState, isPrivileged);
+                    uidState.pkgOps.put(pkgName, ops);
+                }
+                ops.put(op.op, op);
+            } else {
+                Slog.w(TAG, "Unknown element under <pkg>: "
+                        + parser.getName());
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+        UidState uidState = getUidStateLocked(uid, false);
+        if (uidState != null) {
+            uidState.evalForegroundOps(mOpModeWatchers);
+        }
+    }
+
+    void writeState() {
+        synchronized (mFile) {
+            FileOutputStream stream;
+            try {
+                stream = mFile.startWrite();
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed to write state: " + e);
+                return;
+            }
+
+            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
+
+            try {
+                XmlSerializer out = new FastXmlSerializer();
+                out.setOutput(stream, StandardCharsets.UTF_8.name());
+                out.startDocument(null, true);
+                out.startTag(null, "app-ops");
+                out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
+
+                final int uidStateCount = mUidStates.size();
+                for (int i = 0; i < uidStateCount; i++) {
+                    UidState uidState = mUidStates.valueAt(i);
+                    if (uidState.opModes != null && uidState.opModes.size() > 0) {
+                        out.startTag(null, "uid");
+                        out.attribute(null, "n", Integer.toString(uidState.uid));
+                        SparseIntArray uidOpModes = uidState.opModes;
+                        final int opCount = uidOpModes.size();
+                        for (int j = 0; j < opCount; j++) {
+                            final int op = uidOpModes.keyAt(j);
+                            final int mode = uidOpModes.valueAt(j);
+                            out.startTag(null, "op");
+                            out.attribute(null, "n", Integer.toString(op));
+                            out.attribute(null, "m", Integer.toString(mode));
+                            out.endTag(null, "op");
+                        }
+                        out.endTag(null, "uid");
+                    }
+                }
+
+                if (allOps != null) {
+                    String lastPkg = null;
+                    for (int i=0; i<allOps.size(); i++) {
+                        AppOpsManager.PackageOps pkg = allOps.get(i);
+                        if (!pkg.getPackageName().equals(lastPkg)) {
+                            if (lastPkg != null) {
+                                out.endTag(null, "pkg");
+                            }
+                            lastPkg = pkg.getPackageName();
+                            out.startTag(null, "pkg");
+                            out.attribute(null, "n", lastPkg);
+                        }
+                        out.startTag(null, "uid");
+                        out.attribute(null, "n", Integer.toString(pkg.getUid()));
+                        synchronized (this) {
+                            Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
+                                    false /* edit */, false /* uidMismatchExpected */);
+                            // Should always be present as the list of PackageOps is generated
+                            // from Ops.
+                            if (ops != null) {
+                                out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
+                            } else {
+                                out.attribute(null, "p", Boolean.toString(false));
+                            }
+                        }
+                        List<AppOpsManager.OpEntry> ops = pkg.getOps();
+                        for (int j=0; j<ops.size(); j++) {
+                            AppOpsManager.OpEntry op = ops.get(j);
+                            out.startTag(null, "op");
+                            out.attribute(null, "n", Integer.toString(op.getOp()));
+                            if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
+                                out.attribute(null, "m", Integer.toString(op.getMode()));
+                            }
+                            for (int k = 0; k < _NUM_UID_STATE; k++) {
+                                final long time = op.getLastTimeFor(k);
+                                if (time != 0) {
+                                    out.attribute(null, UID_STATE_TIME_ATTRS[k],
+                                            Long.toString(time));
+                                }
+                                final long rejectTime = op.getLastRejectTimeFor(k);
+                                if (rejectTime != 0) {
+                                    out.attribute(null, UID_STATE_REJECT_ATTRS[k],
+                                            Long.toString(rejectTime));
+                                }
+                            }
+                            int dur = op.getDuration();
+                            if (dur != 0) {
+                                out.attribute(null, "d", Integer.toString(dur));
+                            }
+                            int proxyUid = op.getProxyUid();
+                            if (proxyUid != -1) {
+                                out.attribute(null, "pu", Integer.toString(proxyUid));
+                            }
+                            String proxyPackageName = op.getProxyPackageName();
+                            if (proxyPackageName != null) {
+                                out.attribute(null, "pp", proxyPackageName);
+                            }
+                            out.endTag(null, "op");
+                        }
+                        out.endTag(null, "uid");
+                    }
+                    if (lastPkg != null) {
+                        out.endTag(null, "pkg");
+                    }
+                }
+
+                out.endTag(null, "app-ops");
+                out.endDocument();
+                mFile.finishWrite(stream);
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed to write state, restoring backup.", e);
+                mFile.failWrite(stream);
+            }
+        }
+    }
+
+    static class Shell extends ShellCommand {
+        final IAppOpsService mInterface;
+        final AppOpsService mInternal;
+
+        int userId = UserHandle.USER_SYSTEM;
+        String packageName;
+        String opStr;
+        String modeStr;
+        int op;
+        int mode;
+        int packageUid;
+        int nonpackageUid;
+        final static Binder sBinder = new Binder();
+        IBinder mToken;
+
+        Shell(IAppOpsService iface, AppOpsService internal) {
+            mInterface = iface;
+            mInternal = internal;
+            try {
+                mToken = mInterface.getToken(sBinder);
+            } catch (RemoteException e) {
+            }
+        }
+
+        @Override
+        public int onCommand(String cmd) {
+            return onShellCommand(this, cmd);
+        }
+
+        @Override
+        public void onHelp() {
+            PrintWriter pw = getOutPrintWriter();
+            dumpCommandHelp(pw);
+        }
+
+        static private int strOpToOp(String op, PrintWriter err) {
+            try {
+                return AppOpsManager.strOpToOp(op);
+            } catch (IllegalArgumentException e) {
+            }
+            try {
+                return Integer.parseInt(op);
+            } catch (NumberFormatException e) {
+            }
+            try {
+                return AppOpsManager.strDebugOpToOp(op);
+            } catch (IllegalArgumentException e) {
+                err.println("Error: " + e.getMessage());
+                return -1;
+            }
+        }
+
+        static int strModeToMode(String modeStr, PrintWriter err) {
+            for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
+                if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
+                    return i;
+                }
+            }
+            try {
+                return Integer.parseInt(modeStr);
+            } catch (NumberFormatException e) {
+            }
+            err.println("Error: Mode " + modeStr + " is not valid");
+            return -1;
+        }
+
+        int parseUserOpMode(int defMode, PrintWriter err) throws RemoteException {
+            userId = UserHandle.USER_CURRENT;
+            opStr = null;
+            modeStr = null;
+            for (String argument; (argument = getNextArg()) != null;) {
+                if ("--user".equals(argument)) {
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                } else {
+                    if (opStr == null) {
+                        opStr = argument;
+                    } else if (modeStr == null) {
+                        modeStr = argument;
+                        break;
+                    }
+                }
+            }
+            if (opStr == null) {
+                err.println("Error: Operation not specified.");
+                return -1;
+            }
+            op = strOpToOp(opStr, err);
+            if (op < 0) {
+                return -1;
+            }
+            if (modeStr != null) {
+                if ((mode=strModeToMode(modeStr, err)) < 0) {
+                    return -1;
+                }
+            } else {
+                mode = defMode;
+            }
+            return 0;
+        }
+
+        int parseUserPackageOp(boolean reqOp, PrintWriter err) throws RemoteException {
+            userId = UserHandle.USER_CURRENT;
+            packageName = null;
+            opStr = null;
+            for (String argument; (argument = getNextArg()) != null;) {
+                if ("--user".equals(argument)) {
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                } else {
+                    if (packageName == null) {
+                        packageName = argument;
+                    } else if (opStr == null) {
+                        opStr = argument;
+                        break;
+                    }
+                }
+            }
+            if (packageName == null) {
+                err.println("Error: Package name not specified.");
+                return -1;
+            } else if (opStr == null && reqOp) {
+                err.println("Error: Operation not specified.");
+                return -1;
+            }
+            if (opStr != null) {
+                op = strOpToOp(opStr, err);
+                if (op < 0) {
+                    return -1;
+                }
+            } else {
+                op = AppOpsManager.OP_NONE;
+            }
+            if (userId == UserHandle.USER_CURRENT) {
+                userId = ActivityManager.getCurrentUser();
+            }
+            nonpackageUid = -1;
+            try {
+                nonpackageUid = Integer.parseInt(packageName);
+            } catch (NumberFormatException e) {
+            }
+            if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
+                    && packageName.indexOf('.') < 0) {
+                int i = 1;
+                while (i < packageName.length() && packageName.charAt(i) >= '0'
+                        && packageName.charAt(i) <= '9') {
+                    i++;
+                }
+                if (i > 1 && i < packageName.length()) {
+                    String userStr = packageName.substring(1, i);
+                    try {
+                        int user = Integer.parseInt(userStr);
+                        char type = packageName.charAt(i);
+                        i++;
+                        int startTypeVal = i;
+                        while (i < packageName.length() && packageName.charAt(i) >= '0'
+                                && packageName.charAt(i) <= '9') {
+                            i++;
+                        }
+                        if (i > startTypeVal) {
+                            String typeValStr = packageName.substring(startTypeVal, i);
+                            try {
+                                int typeVal = Integer.parseInt(typeValStr);
+                                if (type == 'a') {
+                                    nonpackageUid = UserHandle.getUid(user,
+                                            typeVal + Process.FIRST_APPLICATION_UID);
+                                } else if (type == 's') {
+                                    nonpackageUid = UserHandle.getUid(user, typeVal);
+                                }
+                            } catch (NumberFormatException e) {
+                            }
+                        }
+                    } catch (NumberFormatException e) {
+                    }
+                }
+            }
+            if (nonpackageUid != -1) {
+                packageName = null;
+            } else {
+                packageUid = resolveUid(packageName);
+                if (packageUid < 0) {
+                    packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
+                            PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+                }
+                if (packageUid < 0) {
+                    err.println("Error: No UID for " + packageName + " in user " + userId);
+                    return -1;
+                }
+            }
+            return 0;
+        }
+    }
+
+    @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
+            FileDescriptor err, String[] args, ShellCallback callback,
+            ResultReceiver resultReceiver) {
+        (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver);
+    }
+
+    static void dumpCommandHelp(PrintWriter pw) {
+        pw.println("AppOps service (appops) commands:");
+        pw.println("  help");
+        pw.println("    Print this help text.");
+        pw.println("  start [--user <USER_ID>] <PACKAGE | UID> <OP> ");
+        pw.println("    Starts a given operation for a particular application.");
+        pw.println("  stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
+        pw.println("    Stops a given operation for a particular application.");
+        pw.println("  set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
+        pw.println("    Set the mode for a particular application and operation.");
+        pw.println("  get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
+        pw.println("    Return the mode for a particular application and optional operation.");
+        pw.println("  query-op [--user <USER_ID>] <OP> [<MODE>]");
+        pw.println("    Print all packages that currently have the given op in the given mode.");
+        pw.println("  reset [--user <USER_ID>] [<PACKAGE>]");
+        pw.println("    Reset the given application or all applications to default modes.");
+        pw.println("  write-settings");
+        pw.println("    Immediately write pending changes to storage.");
+        pw.println("  read-settings");
+        pw.println("    Read the last written settings, replacing current state in RAM.");
+        pw.println("  options:");
+        pw.println("    <PACKAGE> an Android package name.");
+        pw.println("    <OP>      an AppOps operation.");
+        pw.println("    <MODE>    one of allow, ignore, deny, or default");
+        pw.println("    <USER_ID> the user id under which the package is installed. If --user is not");
+        pw.println("              specified, the current user is assumed.");
+    }
+
+    static int onShellCommand(Shell shell, String cmd) {
+        if (cmd == null) {
+            return shell.handleDefaultCommands(cmd);
+        }
+        PrintWriter pw = shell.getOutPrintWriter();
+        PrintWriter err = shell.getErrPrintWriter();
+        try {
+            switch (cmd) {
+                case "set": {
+                    int res = shell.parseUserPackageOp(true, err);
+                    if (res < 0) {
+                        return res;
+                    }
+                    String modeStr = shell.getNextArg();
+                    if (modeStr == null) {
+                        err.println("Error: Mode not specified.");
+                        return -1;
+                    }
+
+                    final int mode = shell.strModeToMode(modeStr, err);
+                    if (mode < 0) {
+                        return -1;
+                    }
+
+                    if (shell.packageName != null) {
+                        shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
+                                mode);
+                    } else {
+                        shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
+                    }
+                    return 0;
+                }
+                case "get": {
+                    int res = shell.parseUserPackageOp(false, err);
+                    if (res < 0) {
+                        return res;
+                    }
+
+                    List<AppOpsManager.PackageOps> ops = new ArrayList<>();
+                    if (shell.packageName != null) {
+                        // Uid mode overrides package mode, so make sure it's also reported
+                        List<AppOpsManager.PackageOps> r = shell.mInterface.getUidOps(
+                                shell.packageUid,
+                                shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
+                        if (r != null) {
+                            ops.addAll(r);
+                        }
+                        r = shell.mInterface.getOpsForPackage(
+                                shell.packageUid, shell.packageName,
+                                shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
+                        if (r != null) {
+                            ops.addAll(r);
+                        }
+                    } else {
+                        ops = shell.mInterface.getUidOps(
+                                shell.nonpackageUid,
+                                shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
+                    }
+                    if (ops == null || ops.size() <= 0) {
+                        pw.println("No operations.");
+                        if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
+                            pw.println("Default mode: " + AppOpsManager.modeToName(
+                                    AppOpsManager.opToDefaultMode(shell.op)));
+                        }
+                        return 0;
+                    }
+                    final long now = System.currentTimeMillis();
+                    for (int i=0; i<ops.size(); i++) {
+                        AppOpsManager.PackageOps packageOps = ops.get(i);
+                        if (packageOps.getPackageName() == null) {
+                            pw.print("Uid mode: ");
+                        }
+                        List<AppOpsManager.OpEntry> entries = packageOps.getOps();
+                        for (int j=0; j<entries.size(); j++) {
+                            AppOpsManager.OpEntry ent = entries.get(j);
+                            pw.print(AppOpsManager.opToName(ent.getOp()));
+                            pw.print(": ");
+                            pw.print(AppOpsManager.modeToName(ent.getMode()));
+                            if (ent.getTime() != 0) {
+                                pw.print("; time=");
+                                TimeUtils.formatDuration(now - ent.getTime(), pw);
+                                pw.print(" ago");
+                            }
+                            if (ent.getRejectTime() != 0) {
+                                pw.print("; rejectTime=");
+                                TimeUtils.formatDuration(now - ent.getRejectTime(), pw);
+                                pw.print(" ago");
+                            }
+                            if (ent.getDuration() == -1) {
+                                pw.print(" (running)");
+                            } else if (ent.getDuration() != 0) {
+                                pw.print("; duration=");
+                                TimeUtils.formatDuration(ent.getDuration(), pw);
+                            }
+                            pw.println();
+                        }
+                    }
+                    return 0;
+                }
+                case "query-op": {
+                    int res = shell.parseUserOpMode(AppOpsManager.MODE_IGNORED, err);
+                    if (res < 0) {
+                        return res;
+                    }
+                    List<AppOpsManager.PackageOps> ops = shell.mInterface.getPackagesForOps(
+                            new int[] {shell.op});
+                    if (ops == null || ops.size() <= 0) {
+                        pw.println("No operations.");
+                        return 0;
+                    }
+                    for (int i=0; i<ops.size(); i++) {
+                        final AppOpsManager.PackageOps pkg = ops.get(i);
+                        boolean hasMatch = false;
+                        final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
+                        for (int j=0; j<entries.size(); j++) {
+                            AppOpsManager.OpEntry ent = entries.get(j);
+                            if (ent.getOp() == shell.op && ent.getMode() == shell.mode) {
+                                hasMatch = true;
+                                break;
+                            }
+                        }
+                        if (hasMatch) {
+                            pw.println(pkg.getPackageName());
+                        }
+                    }
+                    return 0;
+                }
+                case "reset": {
+                    String packageName = null;
+                    int userId = UserHandle.USER_CURRENT;
+                    for (String argument; (argument = shell.getNextArg()) != null;) {
+                        if ("--user".equals(argument)) {
+                            String userStr = shell.getNextArgRequired();
+                            userId = UserHandle.parseUserArg(userStr);
+                        } else {
+                            if (packageName == null) {
+                                packageName = argument;
+                            } else {
+                                err.println("Error: Unsupported argument: " + argument);
+                                return -1;
+                            }
+                        }
+                    }
+
+                    if (userId == UserHandle.USER_CURRENT) {
+                        userId = ActivityManager.getCurrentUser();
+                    }
+
+                    shell.mInterface.resetAllModes(userId, packageName);
+                    pw.print("Reset all modes for: ");
+                    if (userId == UserHandle.USER_ALL) {
+                        pw.print("all users");
+                    } else {
+                        pw.print("user "); pw.print(userId);
+                    }
+                    pw.print(", ");
+                    if (packageName == null) {
+                        pw.println("all packages");
+                    } else {
+                        pw.print("package "); pw.println(packageName);
+                    }
+                    return 0;
+                }
+                case "write-settings": {
+                    shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
+                            Binder.getCallingUid(), -1);
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        synchronized (shell.mInternal) {
+                            shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
+                        }
+                        shell.mInternal.writeState();
+                        pw.println("Current settings written.");
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                    return 0;
+                }
+                case "read-settings": {
+                    shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
+                            Binder.getCallingUid(), -1);
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        shell.mInternal.readState();
+                        pw.println("Last settings read.");
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                    return 0;
+                }
+                case "start": {
+                    int res = shell.parseUserPackageOp(true, err);
+                    if (res < 0) {
+                        return res;
+                    }
+
+                    if (shell.packageName != null) {
+                        shell.mInterface.startOperation(shell.mToken,
+                                shell.op, shell.packageUid, shell.packageName, true);
+                    } else {
+                        return -1;
+                    }
+                    return 0;
+                }
+                case "stop": {
+                    int res = shell.parseUserPackageOp(true, err);
+                    if (res < 0) {
+                        return res;
+                    }
+
+                    if (shell.packageName != null) {
+                        shell.mInterface.finishOperation(shell.mToken,
+                                shell.op, shell.packageUid, shell.packageName);
+                    } else {
+                        return -1;
+                    }
+                    return 0;
+                }
+                default:
+                    return shell.handleDefaultCommands(cmd);
+            }
+        } catch (RemoteException e) {
+            pw.println("Remote exception: " + e);
+        }
+        return -1;
+    }
+
+    private void dumpHelp(PrintWriter pw) {
+        pw.println("AppOps service (appops) dump options:");
+        pw.println("  -h");
+        pw.println("    Print this help text.");
+        pw.println("  --op [OP]");
+        pw.println("    Limit output to data associated with the given app op code.");
+        pw.println("  --mode [MODE]");
+        pw.println("    Limit output to data associated with the given app op mode.");
+        pw.println("  --package [PACKAGE]");
+        pw.println("    Limit output to data associated with the given package name.");
+        pw.println("  --watchers");
+        pw.println("    Only output the watcher sections.");
+    }
+
+    private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
+            long now, SimpleDateFormat sdf, Date date) {
+        boolean hasTime = false;
+        for (int i = 0; i < _NUM_UID_STATE; i++) {
+            if (times[i] != 0) {
+                hasTime = true;
+                break;
+            }
+        }
+        if (!hasTime) {
+            return;
+        }
+        boolean first = true;
+        for (int i = 0; i < _NUM_UID_STATE; i++) {
+            if (times[i] != 0) {
+                pw.print(first ? firstPrefix : prefix);
+                first = false;
+                pw.print(UID_STATE_NAMES[i]);
+                pw.print(" = ");
+                date.setTime(times[i]);
+                pw.print(sdf.format(date));
+                pw.print(" (");
+                TimeUtils.formatDuration(times[i]-now, pw);
+                pw.println(")");
+            }
+        }
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
+
+        int dumpOp = OP_NONE;
+        String dumpPackage = null;
+        int dumpUid = Process.INVALID_UID;
+        int dumpMode = -1;
+        boolean dumpWatchers = false;
+
+        if (args != null) {
+            for (int i=0; i<args.length; i++) {
+                String arg = args[i];
+                if ("-h".equals(arg)) {
+                    dumpHelp(pw);
+                    return;
+                } else if ("-a".equals(arg)) {
+                    // dump all data
+                } else if ("--op".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("No argument for --op option");
+                        return;
+                    }
+                    dumpOp = Shell.strOpToOp(args[i], pw);
+                    if (dumpOp < 0) {
+                        return;
+                    }
+                } else if ("--package".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("No argument for --package option");
+                        return;
+                    }
+                    dumpPackage = args[i];
+                    try {
+                        dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
+                                PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
+                                0);
+                    } catch (RemoteException e) {
+                    }
+                    if (dumpUid < 0) {
+                        pw.println("Unknown package: " + dumpPackage);
+                        return;
+                    }
+                    dumpUid = UserHandle.getAppId(dumpUid);
+                } else if ("--mode".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("No argument for --mode option");
+                        return;
+                    }
+                    dumpMode = Shell.strModeToMode(args[i], pw);
+                    if (dumpMode < 0) {
+                        return;
+                    }
+                } else if ("--watchers".equals(arg)) {
+                    dumpWatchers = true;
+                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
+                    pw.println("Unknown option: " + arg);
+                    return;
+                } else {
+                    pw.println("Unknown command: " + arg);
+                    return;
+                }
+            }
+        }
+
+        synchronized (this) {
+            pw.println("Current AppOps Service state:");
+            mConstants.dump(pw);
+            pw.println();
+            final long now = System.currentTimeMillis();
+            final long nowElapsed = SystemClock.elapsedRealtime();
+            final long nowUptime = SystemClock.uptimeMillis();
+            final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+            final Date date = new Date();
+            boolean needSep = false;
+            if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null
+                    && !dumpWatchers) {
+                pw.println("  Profile owners:");
+                for (int poi = 0; poi < mProfileOwners.size(); poi++) {
+                    pw.print("    User #");
+                    pw.print(mProfileOwners.keyAt(poi));
+                    pw.print(": ");
+                    UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
+                    pw.println();
+                }
+                pw.println();
+            }
+            if (mOpModeWatchers.size() > 0) {
+                boolean printedHeader = false;
+                for (int i=0; i<mOpModeWatchers.size(); i++) {
+                    if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
+                        continue;
+                    }
+                    boolean printedOpHeader = false;
+                    ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
+                    for (int j=0; j<callbacks.size(); j++) {
+                        final ModeCallback cb = callbacks.valueAt(j);
+                        if (dumpPackage != null
+                                && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+                            continue;
+                        }
+                        needSep = true;
+                        if (!printedHeader) {
+                            pw.println("  Op mode watchers:");
+                            printedHeader = true;
+                        }
+                        if (!printedOpHeader) {
+                            pw.print("    Op ");
+                            pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
+                            pw.println(":");
+                            printedOpHeader = true;
+                        }
+                        pw.print("      #"); pw.print(j); pw.print(": ");
+                        pw.println(cb);
+                    }
+                }
+            }
+            if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
+                boolean printedHeader = false;
+                for (int i=0; i<mPackageModeWatchers.size(); i++) {
+                    if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
+                        continue;
+                    }
+                    needSep = true;
+                    if (!printedHeader) {
+                        pw.println("  Package mode watchers:");
+                        printedHeader = true;
+                    }
+                    pw.print("    Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
+                    pw.println(":");
+                    ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
+                    for (int j=0; j<callbacks.size(); j++) {
+                        pw.print("      #"); pw.print(j); pw.print(": ");
+                        pw.println(callbacks.valueAt(j));
+                    }
+                }
+            }
+            if (mModeWatchers.size() > 0 && dumpOp < 0) {
+                boolean printedHeader = false;
+                for (int i=0; i<mModeWatchers.size(); i++) {
+                    final ModeCallback cb = mModeWatchers.valueAt(i);
+                    if (dumpPackage != null
+                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+                        continue;
+                    }
+                    needSep = true;
+                    if (!printedHeader) {
+                        pw.println("  All op mode watchers:");
+                        printedHeader = true;
+                    }
+                    pw.print("    ");
+                    pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
+                    pw.print(": "); pw.println(cb);
+                }
+            }
+            if (mActiveWatchers.size() > 0 && dumpMode < 0) {
+                needSep = true;
+                boolean printedHeader = false;
+                for (int i = 0; i < mActiveWatchers.size(); i++) {
+                    final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
+                    if (activeWatchers.size() <= 0) {
+                        continue;
+                    }
+                    final ActiveCallback cb = activeWatchers.valueAt(0);
+                    if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
+                        continue;
+                    }
+                    if (dumpPackage != null
+                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+                        continue;
+                    }
+                    if (!printedHeader) {
+                        pw.println("  All op active watchers:");
+                        printedHeader = true;
+                    }
+                    pw.print("    ");
+                    pw.print(Integer.toHexString(System.identityHashCode(
+                            mActiveWatchers.keyAt(i))));
+                    pw.println(" ->");
+                    pw.print("        [");
+                    final int opCount = activeWatchers.size();
+                    for (i = 0; i < opCount; i++) {
+                        if (i > 0) {
+                            pw.print(' ');
+                        }
+                        pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
+                        if (i < opCount - 1) {
+                            pw.print(',');
+                        }
+                    }
+                    pw.println("]");
+                    pw.print("        ");
+                    pw.println(cb);
+                }
+            }
+            if (mNotedWatchers.size() > 0 && dumpMode < 0) {
+                needSep = true;
+                boolean printedHeader = false;
+                for (int i = 0; i < mNotedWatchers.size(); i++) {
+                    final SparseArray<NotedCallback> notedWatchers = mNotedWatchers.valueAt(i);
+                    if (notedWatchers.size() <= 0) {
+                        continue;
+                    }
+                    final NotedCallback cb = notedWatchers.valueAt(0);
+                    if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
+                        continue;
+                    }
+                    if (dumpPackage != null
+                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+                        continue;
+                    }
+                    if (!printedHeader) {
+                        pw.println("  All op noted watchers:");
+                        printedHeader = true;
+                    }
+                    pw.print("    ");
+                    pw.print(Integer.toHexString(System.identityHashCode(
+                            mNotedWatchers.keyAt(i))));
+                    pw.println(" ->");
+                    pw.print("        [");
+                    final int opCount = notedWatchers.size();
+                    for (i = 0; i < opCount; i++) {
+                        if (i > 0) {
+                            pw.print(' ');
+                        }
+                        pw.print(AppOpsManager.opToName(notedWatchers.keyAt(i)));
+                        if (i < opCount - 1) {
+                            pw.print(',');
+                        }
+                    }
+                    pw.println("]");
+                    pw.print("        ");
+                    pw.println(cb);
+                }
+            }
+            if (mClients.size() > 0 && dumpMode < 0 && !dumpWatchers) {
+                needSep = true;
+                boolean printedHeader = false;
+                for (int i=0; i<mClients.size(); i++) {
+                    boolean printedClient = false;
+                    ClientState cs = mClients.valueAt(i);
+                    if (cs.mStartedOps.size() > 0) {
+                        boolean printedStarted = false;
+                        for (int j=0; j<cs.mStartedOps.size(); j++) {
+                            Op op = cs.mStartedOps.get(j);
+                            if (dumpOp >= 0 && op.op != dumpOp) {
+                                continue;
+                            }
+                            if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
+                                continue;
+                            }
+                            if (!printedHeader) {
+                                pw.println("  Clients:");
+                                printedHeader = true;
+                            }
+                            if (!printedClient) {
+                                pw.print("    "); pw.print(mClients.keyAt(i)); pw.println(":");
+                                pw.print("      "); pw.println(cs);
+                                printedClient = true;
+                            }
+                            if (!printedStarted) {
+                                pw.println("      Started ops:");
+                                printedStarted = true;
+                            }
+                            pw.print("        "); pw.print("uid="); pw.print(op.uid);
+                            pw.print(" pkg="); pw.print(op.packageName);
+                            pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
+                        }
+                    }
+                }
+            }
+            if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
+                    && dumpMode < 0 && !dumpWatchers) {
+                boolean printedHeader = false;
+                for (int o=0; o<mAudioRestrictions.size(); o++) {
+                    final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
+                    final SparseArray<Restriction> restrictions = mAudioRestrictions.valueAt(o);
+                    for (int i=0; i<restrictions.size(); i++) {
+                        if (!printedHeader){
+                            pw.println("  Audio Restrictions:");
+                            printedHeader = true;
+                            needSep = true;
+                        }
+                        final int usage = restrictions.keyAt(i);
+                        pw.print("    "); pw.print(op);
+                        pw.print(" usage="); pw.print(AudioAttributes.usageToString(usage));
+                        Restriction r = restrictions.valueAt(i);
+                        pw.print(": mode="); pw.println(AppOpsManager.modeToName(r.mode));
+                        if (!r.exceptionPackages.isEmpty()) {
+                            pw.println("      Exceptions:");
+                            for (int j=0; j<r.exceptionPackages.size(); j++) {
+                                pw.print("        "); pw.println(r.exceptionPackages.valueAt(j));
+                            }
+                        }
+                    }
+                }
+            }
+            if (needSep) {
+                pw.println();
+            }
+            for (int i=0; i<mUidStates.size(); i++) {
+                UidState uidState = mUidStates.valueAt(i);
+                final SparseIntArray opModes = uidState.opModes;
+                final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
+
+                if (dumpWatchers) {
+                    continue;
+                }
+                if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
+                    boolean hasOp = dumpOp < 0 || (uidState.opModes != null
+                            && uidState.opModes.indexOfKey(dumpOp) >= 0);
+                    boolean hasPackage = dumpPackage == null;
+                    boolean hasMode = dumpMode < 0;
+                    if (!hasMode && opModes != null) {
+                        for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
+                            if (opModes.valueAt(opi) == dumpMode) {
+                                hasMode = true;
+                            }
+                        }
+                    }
+                    if (pkgOps != null) {
+                        for (int pkgi = 0;
+                                 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
+                                 pkgi++) {
+                            Ops ops = pkgOps.valueAt(pkgi);
+                            if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
+                                hasOp = true;
+                            }
+                            if (!hasMode) {
+                                for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
+                                    if (ops.valueAt(opi).mode == dumpMode) {
+                                        hasMode = true;
+                                    }
+                                }
+                            }
+                            if (!hasPackage && dumpPackage.equals(ops.packageName)) {
+                                hasPackage = true;
+                            }
+                        }
+                    }
+                    if (uidState.foregroundOps != null && !hasOp) {
+                        if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
+                            hasOp = true;
+                        }
+                    }
+                    if (!hasOp || !hasPackage || !hasMode) {
+                        continue;
+                    }
+                }
+
+                pw.print("  Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
+                pw.print("    state=");
+                pw.println(UID_STATE_NAMES[uidState.state]);
+                if (uidState.state != uidState.pendingState) {
+                    pw.print("    pendingState=");
+                    pw.println(UID_STATE_NAMES[uidState.pendingState]);
+                }
+                if (uidState.pendingStateCommitTime != 0) {
+                    pw.print("    pendingStateCommitTime=");
+                    TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
+                    pw.println();
+                }
+                if (uidState.startNesting != 0) {
+                    pw.print("    startNesting=");
+                    pw.println(uidState.startNesting);
+                }
+                if (uidState.foregroundOps != null && (dumpMode < 0
+                        || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
+                    pw.println("    foregroundOps:");
+                    for (int j = 0; j < uidState.foregroundOps.size(); j++) {
+                        if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
+                            continue;
+                        }
+                        pw.print("      ");
+                        pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
+                        pw.print(": ");
+                        pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
+                    }
+                    pw.print("    hasForegroundWatchers=");
+                    pw.println(uidState.hasForegroundWatchers);
+                }
+                needSep = true;
+
+                if (opModes != null) {
+                    final int opModeCount = opModes.size();
+                    for (int j = 0; j < opModeCount; j++) {
+                        final int code = opModes.keyAt(j);
+                        final int mode = opModes.valueAt(j);
+                        if (dumpOp >= 0 && dumpOp != code) {
+                            continue;
+                        }
+                        if (dumpMode >= 0 && dumpMode != mode) {
+                            continue;
+                        }
+                        pw.print("      "); pw.print(AppOpsManager.opToName(code));
+                        pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
+                    }
+                }
+
+                if (pkgOps == null) {
+                    continue;
+                }
+
+                for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
+                    final Ops ops = pkgOps.valueAt(pkgi);
+                    if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
+                        continue;
+                    }
+                    boolean printedPackage = false;
+                    for (int j=0; j<ops.size(); j++) {
+                        final Op op = ops.valueAt(j);
+                        if (dumpOp >= 0 && dumpOp != op.op) {
+                            continue;
+                        }
+                        if (dumpMode >= 0 && dumpMode != op.mode) {
+                            continue;
+                        }
+                        if (!printedPackage) {
+                            pw.print("    Package "); pw.print(ops.packageName); pw.println(":");
+                            printedPackage = true;
+                        }
+                        pw.print("      "); pw.print(AppOpsManager.opToName(op.op));
+                        pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
+                        final int switchOp = AppOpsManager.opToSwitch(op.op);
+                        if (switchOp != op.op) {
+                            pw.print(" / switch ");
+                            pw.print(AppOpsManager.opToName(switchOp));
+                            final Op switchObj = ops.get(switchOp);
+                            int mode = switchObj != null
+                                    ? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
+                            pw.print("="); pw.print(AppOpsManager.modeToName(mode));
+                        }
+                        pw.println("): ");
+                        dumpTimesLocked(pw,
+                                "          Access: ",
+                                "                  ", op.time, now, sdf, date);
+                        dumpTimesLocked(pw,
+                                "          Reject: ",
+                                "                  ", op.rejectTime, now, sdf, date);
+                        if (op.duration == -1) {
+                            pw.print("          Running start at: ");
+                            TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
+                            pw.println();
+                        } else if (op.duration != 0) {
+                            pw.print("          duration=");
+                            TimeUtils.formatDuration(op.duration, pw);
+                            pw.println();
+                        }
+                        if (op.startNesting != 0) {
+                            pw.print("          startNesting=");
+                            pw.println(op.startNesting);
+                        }
+                    }
+                }
+            }
+            if (needSep) {
+                pw.println();
+            }
+
+            final int userRestrictionCount = mOpUserRestrictions.size();
+            for (int i = 0; i < userRestrictionCount; i++) {
+                IBinder token = mOpUserRestrictions.keyAt(i);
+                ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
+                boolean printedTokenHeader = false;
+
+                if (dumpMode >= 0 || dumpWatchers) {
+                    continue;
+                }
+
+                final int restrictionCount = restrictionState.perUserRestrictions != null
+                        ? restrictionState.perUserRestrictions.size() : 0;
+                if (restrictionCount > 0 && dumpPackage == null) {
+                    boolean printedOpsHeader = false;
+                    for (int j = 0; j < restrictionCount; j++) {
+                        int userId = restrictionState.perUserRestrictions.keyAt(j);
+                        boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
+                        if (restrictedOps == null) {
+                            continue;
+                        }
+                        if (dumpOp >= 0 && (dumpOp >= restrictedOps.length
+                                || !restrictedOps[dumpOp])) {
+                            continue;
+                        }
+                        if (!printedTokenHeader) {
+                            pw.println("  User restrictions for token " + token + ":");
+                            printedTokenHeader = true;
+                        }
+                        if (!printedOpsHeader) {
+                            pw.println("      Restricted ops:");
+                            printedOpsHeader = true;
+                        }
+                        StringBuilder restrictedOpsValue = new StringBuilder();
+                        restrictedOpsValue.append("[");
+                        final int restrictedOpCount = restrictedOps.length;
+                        for (int k = 0; k < restrictedOpCount; k++) {
+                            if (restrictedOps[k]) {
+                                if (restrictedOpsValue.length() > 1) {
+                                    restrictedOpsValue.append(", ");
+                                }
+                                restrictedOpsValue.append(AppOpsManager.opToName(k));
+                            }
+                        }
+                        restrictedOpsValue.append("]");
+                        pw.print("        "); pw.print("user: "); pw.print(userId);
+                                pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
+                    }
+                }
+
+                final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
+                        ? restrictionState.perUserExcludedPackages.size() : 0;
+                if (excludedPackageCount > 0 && dumpOp < 0) {
+                    boolean printedPackagesHeader = false;
+                    for (int j = 0; j < excludedPackageCount; j++) {
+                        int userId = restrictionState.perUserExcludedPackages.keyAt(j);
+                        String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
+                        if (packageNames == null) {
+                            continue;
+                        }
+                        boolean hasPackage;
+                        if (dumpPackage != null) {
+                            hasPackage = false;
+                            for (String pkg : packageNames) {
+                                if (dumpPackage.equals(pkg)) {
+                                    hasPackage = true;
+                                    break;
+                                }
+                            }
+                        } else {
+                            hasPackage = true;
+                        }
+                        if (!hasPackage) {
+                            continue;
+                        }
+                        if (!printedTokenHeader) {
+                            pw.println("  User restrictions for token " + token + ":");
+                            printedTokenHeader = true;
+                        }
+                        if (!printedPackagesHeader) {
+                            pw.println("      Excluded packages:");
+                            printedPackagesHeader = true;
+                        }
+                        pw.print("        "); pw.print("user: "); pw.print(userId);
+                                pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
+                    }
+                }
+            }
+        }
+
+        // Must not hold the appops lock
+        mHistoricalRegistry.dump("  ", pw, dumpUid, dumpPackage, dumpOp);
+    }
+
+    private static final class Restriction {
+        private static final ArraySet<String> NO_EXCEPTIONS = new ArraySet<String>();
+        int mode;
+        ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
+    }
+
+    @Override
+    public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
+        checkSystemUid("setUserRestrictions");
+        Preconditions.checkNotNull(restrictions);
+        Preconditions.checkNotNull(token);
+        for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
+            String restriction = AppOpsManager.opToRestriction(i);
+            if (restriction != null) {
+                setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
+                        userHandle, null);
+            }
+        }
+    }
+
+    @Override
+    public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
+            String[] exceptionPackages) {
+        if (Binder.getCallingPid() != Process.myPid()) {
+            mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
+                    Binder.getCallingPid(), Binder.getCallingUid(), null);
+        }
+        if (userHandle != UserHandle.getCallingUserId()) {
+            if (mContext.checkCallingOrSelfPermission(Manifest.permission
+                    .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
+                && mContext.checkCallingOrSelfPermission(Manifest.permission
+                    .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
+                        + " INTERACT_ACROSS_USERS to interact cross user ");
+            }
+        }
+        verifyIncomingOp(code);
+        Preconditions.checkNotNull(token);
+        setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
+    }
+
+    private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
+            int userHandle, String[] exceptionPackages) {
+        synchronized (AppOpsService.this) {
+            ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
+
+            if (restrictionState == null) {
+                try {
+                    restrictionState = new ClientRestrictionState(token);
+                } catch (RemoteException e) {
+                    return;
+                }
+                mOpUserRestrictions.put(token, restrictionState);
+            }
+
+            if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
+                mHandler.sendMessage(PooledLambda.obtainMessage(
+                        AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
+            }
+
+            if (restrictionState.isDefault()) {
+                mOpUserRestrictions.remove(token);
+                restrictionState.destroy();
+            }
+        }
+    }
+
+    private void notifyWatchersOfChange(int code, int uid) {
+        final ArraySet<ModeCallback> clonedCallbacks;
+        synchronized (this) {
+            ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
+            if (callbacks == null) {
+                return;
+            }
+            clonedCallbacks = new ArraySet<>(callbacks);
+        }
+
+        notifyOpChanged(clonedCallbacks,  code, uid, null);
+    }
+
+    @Override
+    public void removeUser(int userHandle) throws RemoteException {
+        checkSystemUid("removeUser");
+        synchronized (AppOpsService.this) {
+            final int tokenCount = mOpUserRestrictions.size();
+            for (int i = tokenCount - 1; i >= 0; i--) {
+                ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
+                opRestrictions.removeUser(userHandle);
+            }
+            removeUidsForUserLocked(userHandle);
+        }
+    }
+
+    @Override
+    public boolean isOperationActive(int code, int uid, String packageName) {
+        if (Binder.getCallingUid() != uid) {
+            if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                return false;
+            }
+        }
+        verifyIncomingOp(code);
+        final String resolvedPackageName = resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return false;
+        }
+        synchronized (AppOpsService.this) {
+            for (int i = mClients.size() - 1; i >= 0; i--) {
+                final ClientState client = mClients.valueAt(i);
+                for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
+                    final Op op = client.mStartedOps.get(j);
+                    if (op.op == code && op.uid == uid) return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void setHistoryParameters(@AppOpsManager.HistoricalMode int mode,
+            long baseSnapshotInterval, int compressionStep) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "setHistoryParameters");
+        // Must not hold the appops lock
+        mHistoricalRegistry.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
+    }
+
+    @Override
+    public void offsetHistory(long offsetMillis) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "offsetHistory");
+        // Must not hold the appops lock
+        mHistoricalRegistry.offsetHistory(offsetMillis);
+    }
+
+    @Override
+    public void addHistoricalOps(HistoricalOps ops) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "addHistoricalOps");
+        // Must not hold the appops lock
+        mHistoricalRegistry.addHistoricalOps(ops);
+    }
+
+    @Override
+    public void resetHistoryParameters() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "resetHistoryParameters");
+        // Must not hold the appops lock
+        mHistoricalRegistry.resetHistoryParameters();
+    }
+
+    @Override
+    public void clearHistory() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "clearHistory");
+        // Must not hold the appops lock
+        mHistoricalRegistry.clearHistory();
+    }
+
+    private void removeUidsForUserLocked(int userHandle) {
+        for (int i = mUidStates.size() - 1; i >= 0; --i) {
+            final int uid = mUidStates.keyAt(i);
+            if (UserHandle.getUserId(uid) == userHandle) {
+                mUidStates.removeAt(i);
+            }
+        }
+    }
+
+    private void checkSystemUid(String function) {
+        int uid = Binder.getCallingUid();
+        if (uid != Process.SYSTEM_UID) {
+            throw new SecurityException(function + " must by called by the system");
+        }
+    }
+
+    private static String resolvePackageName(int uid, String packageName)  {
+        if (uid == Process.ROOT_UID) {
+            return "root";
+        } else if (uid == Process.SHELL_UID) {
+            return "com.android.shell";
+        } else if (uid == Process.MEDIA_UID) {
+            return "media";
+        } else if (uid == Process.AUDIOSERVER_UID) {
+            return "audioserver";
+        } else if (uid == Process.CAMERASERVER_UID) {
+            return "cameraserver";
+        } else if (uid == Process.SYSTEM_UID && packageName == null) {
+            return "android";
+        }
+        return packageName;
+    }
+
+    private static int resolveUid(String packageName)  {
+        if (packageName == null) {
+            return -1;
+        }
+        switch (packageName) {
+            case "root":
+                return Process.ROOT_UID;
+            case "shell":
+                return Process.SHELL_UID;
+            case "media":
+                return Process.MEDIA_UID;
+            case "audioserver":
+                return Process.AUDIOSERVER_UID;
+            case "cameraserver":
+                return Process.CAMERASERVER_UID;
+        }
+        return -1;
+    }
+
+    private static String[] getPackagesForUid(int uid) {
+        String[] packageNames = null;
+
+        // Very early during boot the package manager is not yet or not yet fully started. At this
+        // time there are no packages yet.
+        if (AppGlobals.getPackageManager() != null) {
+            try {
+                packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
+            } catch (RemoteException e) {
+                /* ignore - local call */
+            }
+        }
+        if (packageNames == null) {
+            return EmptyArray.STRING;
+        }
+        return packageNames;
+    }
+
+    private static void checkValidOpsOrNull(String[] opNames) {
+        if (opNames != null) {
+            for (String opName : opNames) {
+                if (AppOpsManager.strOpToOp(opName) == AppOpsManager.OP_NONE) {
+                    throw new IllegalArgumentException("Unknown op: " + opName);
+                }
+            }
+        }
+    }
+
+    private final class ClientRestrictionState implements DeathRecipient {
+        private final IBinder token;
+        SparseArray<boolean[]> perUserRestrictions;
+        SparseArray<String[]> perUserExcludedPackages;
+
+        public ClientRestrictionState(IBinder token)
+                throws RemoteException {
+            token.linkToDeath(this, 0);
+            this.token = token;
+        }
+
+        public boolean setRestriction(int code, boolean restricted,
+                String[] excludedPackages, int userId) {
+            boolean changed = false;
+
+            if (perUserRestrictions == null && restricted) {
+                perUserRestrictions = new SparseArray<>();
+            }
+
+            int[] users;
+            if (userId == UserHandle.USER_ALL) {
+                List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
+
+                users = new int[liveUsers.size()];
+                for (int i = 0; i < liveUsers.size(); i++) {
+                    users[i] = liveUsers.get(i).id;
+                }
+            } else {
+                users = new int[]{userId};
+            }
+
+            if (perUserRestrictions != null) {
+                int numUsers = users.length;
+
+                for (int i = 0; i < numUsers; i++) {
+                    int thisUserId = users[i];
+
+                    boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
+                    if (userRestrictions == null && restricted) {
+                        userRestrictions = new boolean[AppOpsManager._NUM_OP];
+                        perUserRestrictions.put(thisUserId, userRestrictions);
+                    }
+                    if (userRestrictions != null && userRestrictions[code] != restricted) {
+                        userRestrictions[code] = restricted;
+                        if (!restricted && isDefault(userRestrictions)) {
+                            perUserRestrictions.remove(thisUserId);
+                            userRestrictions = null;
+                        }
+                        changed = true;
+                    }
+
+                    if (userRestrictions != null) {
+                        final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
+                        if (perUserExcludedPackages == null && !noExcludedPackages) {
+                            perUserExcludedPackages = new SparseArray<>();
+                        }
+                        if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
+                                perUserExcludedPackages.get(thisUserId))) {
+                            if (noExcludedPackages) {
+                                perUserExcludedPackages.remove(thisUserId);
+                                if (perUserExcludedPackages.size() <= 0) {
+                                    perUserExcludedPackages = null;
+                                }
+                            } else {
+                                perUserExcludedPackages.put(thisUserId, excludedPackages);
+                            }
+                            changed = true;
+                        }
+                    }
+                }
+            }
+
+            return changed;
+        }
+
+        public boolean hasRestriction(int restriction, String packageName, int userId) {
+            if (perUserRestrictions == null) {
+                return false;
+            }
+            boolean[] restrictions = perUserRestrictions.get(userId);
+            if (restrictions == null) {
+                return false;
+            }
+            if (!restrictions[restriction]) {
+                return false;
+            }
+            if (perUserExcludedPackages == null) {
+                return true;
+            }
+            String[] perUserExclusions = perUserExcludedPackages.get(userId);
+            if (perUserExclusions == null) {
+                return true;
+            }
+            return !ArrayUtils.contains(perUserExclusions, packageName);
+        }
+
+        public void removeUser(int userId) {
+            if (perUserExcludedPackages != null) {
+                perUserExcludedPackages.remove(userId);
+                if (perUserExcludedPackages.size() <= 0) {
+                    perUserExcludedPackages = null;
+                }
+            }
+            if (perUserRestrictions != null) {
+                perUserRestrictions.remove(userId);
+                if (perUserRestrictions.size() <= 0) {
+                    perUserRestrictions = null;
+                }
+            }
+        }
+
+        public boolean isDefault() {
+            return perUserRestrictions == null || perUserRestrictions.size() <= 0;
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (AppOpsService.this) {
+                mOpUserRestrictions.remove(token);
+                if (perUserRestrictions == null) {
+                    return;
+                }
+                final int userCount = perUserRestrictions.size();
+                for (int i = 0; i < userCount; i++) {
+                    final boolean[] restrictions = perUserRestrictions.valueAt(i);
+                    final int restrictionCount = restrictions.length;
+                    for (int j = 0; j < restrictionCount; j++) {
+                        if (restrictions[j]) {
+                            final int changedCode = j;
+                            mHandler.post(() -> notifyWatchersOfChange(changedCode, UID_ANY));
+                        }
+                    }
+                }
+                destroy();
+            }
+        }
+
+        public void destroy() {
+            token.unlinkToDeath(this, 0);
+        }
+
+        private boolean isDefault(boolean[] array) {
+            if (ArrayUtils.isEmpty(array)) {
+                return true;
+            }
+            for (boolean value : array) {
+                if (value) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
+        @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
+            synchronized (AppOpsService.this) {
+                mProfileOwners = owners;
+            }
+        }
+
+        @Override
+        public void setUidMode(int code, int uid, int mode) {
+            AppOpsService.this.setUidMode(code, uid, mode);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
new file mode 100644
index 0000000..708de73
--- /dev/null
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -0,0 +1,1606 @@
+/*
+ * 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.appop;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.HistoricalMode;
+import android.app.AppOpsManager.HistoricalOp;
+import android.app.AppOpsManager.HistoricalOps;
+import android.app.AppOpsManager.HistoricalPackageOps;
+import android.app.AppOpsManager.HistoricalUidOps;
+import android.app.AppOpsManager.UidState;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.Environment;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteCallback;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.TimeUtils;
+import android.util.Xml;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.AtomicDirectory;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.FgThread;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This class managers historical app op state. This includes reading, persistence,
+ * accounting, querying.
+ * <p>
+ * The history is kept forever in multiple files. Each file time contains the
+ * relative offset from the current time which time is encoded in the file name.
+ * The files contain historical app op state snapshots which have times that
+ * are relative to the time of the container file.
+ *
+ * The data in the files are stored in a logarithmic fashion where where every
+ * subsequent file would contain data for ten times longer interval with ten
+ * times more time distance between snapshots. Hence, the more time passes
+ * the lesser the fidelity.
+ * <p>
+ * For example, the first file would contain data for 1 days with snapshots
+ * every 0.1 days, the next file would contain data for the period 1 to 10
+ * days with snapshots every 1 days, and so on.
+ * <p>
+ * THREADING AND LOCKING: Reported ops must be processed as quickly as possible.
+ * We keep ops pending to be persisted in memory and write to disk on a background
+ * thread. Hence, methods that report op changes are locking only the in memory
+ * state guarded by the mInMemoryLock which happens to be the app ops service lock
+ * avoiding a lock addition on the critical path. When a query comes we need to
+ * evaluate it based off both in memory and on disk state. This means they need to
+ * be frozen with respect to each other and not change from the querying caller's
+ * perspective. To achieve this we add a dedicated mOnDiskLock to guard the on
+ * disk state. To have fast critical path we need to limit the locking of the
+ * mInMemoryLock, thus for operations that touch in memory and on disk state one
+ * must grab first the mOnDiskLock and then the mInMemoryLock and limit the
+ * in memory lock to extraction of relevant data. Locking order is critical to
+ * avoid deadlocks. The convention is that xxxDLocked suffix means the method
+ * must be called with the mOnDiskLock lock, xxxMLocked suffix means the method
+ * must be called with the mInMemoryLock, xxxDMLocked suffix means the method
+ * must be called with the mOnDiskLock and mInMemoryLock locks acquired in that
+ * exact order.
+ */
+// TODO (bug:122218838): Make sure we handle start of epoch time
+// TODO (bug:122218838): Validate changed time is handled correctly
+final class HistoricalRegistry {
+    private static final boolean DEBUG = false;
+    private static final boolean KEEP_WTF_LOG = Build.IS_DEBUGGABLE;
+
+    private static final String LOG_TAG = HistoricalRegistry.class.getSimpleName();
+
+    private static final String PARAMETER_DELIMITER = ",";
+    private static final String PARAMETER_ASSIGNMENT = "=";
+
+    @GuardedBy("mLock")
+    private @NonNull LinkedList<HistoricalOps> mPendingWrites = new LinkedList<>();
+
+    // Lock for read/write access to on disk state
+    private final Object mOnDiskLock = new Object();
+
+    //Lock for read/write access to in memory state
+    private final @NonNull Object mInMemoryLock;
+
+    private static final int MSG_WRITE_PENDING_HISTORY = 1;
+
+    // See mMode
+    private static final int DEFAULT_MODE = AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE;
+
+    // See mBaseSnapshotInterval
+    private static final long DEFAULT_SNAPSHOT_INTERVAL_MILLIS = TimeUnit.MINUTES.toMillis(15);
+
+    // See mIntervalCompressionMultiplier
+    private static final long DEFAULT_COMPRESSION_STEP = 10;
+
+    private static final String HISTORY_FILE_SUFFIX = ".xml";
+
+    /**
+     * Whether history is enabled.
+     */
+    @GuardedBy("mInMemoryLock")
+    private int mMode = AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE;
+
+    /**
+     * This granularity has been chosen to allow clean delineation for intervals
+     * humans understand, 15 min, 60, min, a day, a week, a month (30 days).
+     */
+    @GuardedBy("mInMemoryLock")
+    private long mBaseSnapshotInterval = DEFAULT_SNAPSHOT_INTERVAL_MILLIS;
+
+    /**
+     * The compression between steps. Each subsequent step is this much longer
+     * in terms of duration and each snapshot is this much more apart from the
+     * previous step.
+     */
+    @GuardedBy("mInMemoryLock")
+    private long mIntervalCompressionMultiplier = DEFAULT_COMPRESSION_STEP;
+
+    // The current ops to which to add statistics.
+    @GuardedBy("mInMemoryLock")
+    private @Nullable HistoricalOps mCurrentHistoricalOps;
+
+    // The time we should write the next snapshot.
+    @GuardedBy("mInMemoryLock")
+    private long mNextPersistDueTimeMillis;
+
+    // How much to offset the history on the next write.
+    @GuardedBy("mInMemoryLock")
+    private long mPendingHistoryOffsetMillis;
+
+    // Object managing persistence (read/write)
+    @GuardedBy("mOnDiskLock")
+    private Persistence mPersistence = new Persistence(mBaseSnapshotInterval,
+            mIntervalCompressionMultiplier);
+
+    HistoricalRegistry(@NonNull Object lock) {
+        mInMemoryLock = lock;
+        if (mMode != AppOpsManager.HISTORICAL_MODE_DISABLED) {
+            synchronized (mOnDiskLock) {
+                synchronized (mInMemoryLock) {
+                    // When starting always adjust history to now.
+                    final long lastPersistTimeMills =
+                            mPersistence.getLastPersistTimeMillisDLocked();
+                    if (lastPersistTimeMills > 0) {
+                        mPendingHistoryOffsetMillis =
+                                System.currentTimeMillis() - lastPersistTimeMills;
+                    }
+                }
+            }
+        }
+    }
+
+    void systemReady(@NonNull ContentResolver resolver) {
+        updateParametersFromSetting(resolver);
+        final Uri uri = Settings.Global.getUriFor(Settings.Global.APPOP_HISTORY_PARAMETERS);
+        resolver.registerContentObserver(uri, false, new ContentObserver(
+                FgThread.getHandler()) {
+            @Override
+            public void onChange(boolean selfChange) {
+                updateParametersFromSetting(resolver);
+            }
+        });
+    }
+
+    private void updateParametersFromSetting(@NonNull ContentResolver resolver) {
+        final String setting = Settings.Global.getString(resolver,
+                Settings.Global.APPOP_HISTORY_PARAMETERS);
+        if (setting == null) {
+            return;
+        }
+        String modeValue = null;
+        String baseSnapshotIntervalValue = null;
+        String intervalMultiplierValue = null;
+        final String[] parameters = setting.split(PARAMETER_DELIMITER);
+        for (String parameter : parameters) {
+            final String[] parts = parameter.split(PARAMETER_ASSIGNMENT);
+            if (parts.length == 2) {
+                final String key = parts[0].trim();
+                switch (key) {
+                    case Settings.Global.APPOP_HISTORY_MODE: {
+                        modeValue = parts[1].trim();
+                    } break;
+                    case Settings.Global.APPOP_HISTORY_BASE_INTERVAL_MILLIS: {
+                        baseSnapshotIntervalValue = parts[1].trim();
+                    } break;
+                    case Settings.Global.APPOP_HISTORY_INTERVAL_MULTIPLIER: {
+                        intervalMultiplierValue = parts[1].trim();
+                    } break;
+                    default: {
+                        Slog.w(LOG_TAG, "Unknown parameter: " + parameter);
+                    }
+                }
+            }
+        }
+        if (modeValue != null && baseSnapshotIntervalValue != null
+                && intervalMultiplierValue != null) {
+            try {
+                final int mode = AppOpsManager.parseHistoricalMode(modeValue);
+                final long baseSnapshotInterval = Long.parseLong(baseSnapshotIntervalValue);
+                final int intervalCompressionMultiplier = Integer.parseInt(intervalMultiplierValue);
+                setHistoryParameters(mode, baseSnapshotInterval,intervalCompressionMultiplier);
+                return;
+            } catch (NumberFormatException ignored) {}
+        }
+        Slog.w(LOG_TAG, "Bad value for" + Settings.Global.APPOP_HISTORY_PARAMETERS
+                + "=" + setting + " resetting!");
+    }
+
+    void dump(String prefix, PrintWriter pw, int filterUid,
+              String filterPackage, int filterOp) {
+        synchronized (mOnDiskLock) {
+            synchronized (mInMemoryLock) {
+                pw.println();
+                pw.print(prefix);
+                pw.print("History:");
+
+                pw.print("  mode=");
+                pw.println(AppOpsManager.historicalModeToString(mMode));
+
+                final StringDumpVisitor visitor = new StringDumpVisitor(prefix + "  ",
+                        pw, filterUid, filterPackage, filterOp);
+                final long nowMillis = System.currentTimeMillis();
+
+                // Dump in memory state first
+                final HistoricalOps currentOps = getUpdatedPendingHistoricalOpsMLocked(
+                        nowMillis);
+                makeRelativeToEpochStart(currentOps, nowMillis);
+                currentOps.accept(visitor);
+
+                final List<HistoricalOps> ops = mPersistence.readHistoryDLocked();
+                if (ops != null) {
+                    // TODO (bug:122218838): Make sure this is properly dumped
+                    final long remainingToFillBatchMillis = mNextPersistDueTimeMillis
+                            - nowMillis - mBaseSnapshotInterval;
+                    final int opCount = ops.size();
+                    for (int i = 0; i < opCount; i++) {
+                        final HistoricalOps op = ops.get(i);
+                        op.offsetBeginAndEndTime(remainingToFillBatchMillis);
+                        makeRelativeToEpochStart(op, nowMillis);
+                        op.accept(visitor);
+                    }
+                } else {
+                    pw.println("  Empty");
+                }
+            }
+        }
+    }
+
+    @HistoricalMode int getMode() {
+        synchronized (mInMemoryLock) {
+            return mMode;
+        }
+    }
+
+    @Nullable void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @NonNull RemoteCallback callback) {
+        final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
+        mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, opNames,
+                beginTimeMillis, endTimeMillis);
+        final Bundle payload = new Bundle();
+        payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
+        callback.sendResult(payload);
+    }
+
+    @Nullable void getHistoricalOps(int uid, @NonNull String packageName,
+            @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
+            @NonNull RemoteCallback callback) {
+        final long currentTimeMillis = System.currentTimeMillis();
+        if (endTimeMillis == Long.MAX_VALUE) {
+            endTimeMillis = currentTimeMillis;
+        }
+
+        // Argument times are based off epoch start while our internal store is
+        // based off now, so take this into account.
+        final long inMemoryAdjBeginTimeMillis = Math.max(currentTimeMillis - endTimeMillis, 0);
+        final long inMemoryAdjEndTimeMillis = Math.max(currentTimeMillis - beginTimeMillis, 0);
+        final HistoricalOps result = new HistoricalOps(inMemoryAdjBeginTimeMillis,
+                inMemoryAdjEndTimeMillis);
+
+        synchronized (mOnDiskLock) {
+            final List<HistoricalOps> pendingWrites;
+            final HistoricalOps currentOps;
+            synchronized (mInMemoryLock) {
+                currentOps = getUpdatedPendingHistoricalOpsMLocked(currentTimeMillis);
+                if (!(inMemoryAdjBeginTimeMillis >= currentOps.getEndTimeMillis()
+                        || inMemoryAdjEndTimeMillis <= currentOps.getBeginTimeMillis())) {
+                    // Some of the current batch falls into the query, so extract that.
+                    final HistoricalOps currentOpsCopy = new HistoricalOps(currentOps);
+                    currentOpsCopy.filter(uid, packageName, opNames, inMemoryAdjBeginTimeMillis,
+                            inMemoryAdjEndTimeMillis);
+                    result.merge(currentOpsCopy);
+                }
+                pendingWrites = new ArrayList<>(mPendingWrites);
+                mPendingWrites.clear();
+            }
+
+            // If the query was only for in-memory state - done.
+            if (inMemoryAdjEndTimeMillis > currentOps.getEndTimeMillis()) {
+                // If there is a write in flight we need to force it now
+                persistPendingHistory(pendingWrites);
+                // Collect persisted state.
+                final long onDiskAndInMemoryOffsetMillis = currentTimeMillis
+                        - mNextPersistDueTimeMillis + mBaseSnapshotInterval;
+                final long onDiskAdjBeginTimeMillis = Math.max(inMemoryAdjBeginTimeMillis
+                        - onDiskAndInMemoryOffsetMillis, 0);
+                final long onDiskAdjEndTimeMillis = Math.max(inMemoryAdjEndTimeMillis
+                        - onDiskAndInMemoryOffsetMillis, 0);
+                mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, opNames,
+                        onDiskAdjBeginTimeMillis, onDiskAdjEndTimeMillis);
+            }
+
+            // Rebase the result time to be since epoch.
+            result.setBeginAndEndTime(beginTimeMillis, endTimeMillis);
+
+            // Send back the result.
+            final Bundle payload = new Bundle();
+            payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
+            callback.sendResult(payload);
+        }
+    }
+
+    void incrementOpAccessedCount(int op, int uid, @NonNull String packageName,
+            @UidState int uidState) {
+        synchronized (mInMemoryLock) {
+            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
+                getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
+                        .increaseAccessCount(op, uid, packageName, uidState, 1);
+
+            }
+        }
+    }
+
+    void incrementOpRejected(int op, int uid, @NonNull String packageName,
+            @UidState int uidState) {
+        synchronized (mInMemoryLock) {
+            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
+                getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
+                        .increaseRejectCount(op, uid, packageName, uidState, 1);
+            }
+        }
+    }
+
+    void increaseOpAccessDuration(int op, int uid, @NonNull String packageName,
+            @UidState int uidState, long increment) {
+        synchronized (mInMemoryLock) {
+            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
+                getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
+                        .increaseAccessDuration(op, uid, packageName, uidState, increment);
+            }
+        }
+    }
+
+    void setHistoryParameters(@HistoricalMode int mode,
+            long baseSnapshotInterval, long intervalCompressionMultiplier) {
+        synchronized (mOnDiskLock) {
+            synchronized (mInMemoryLock) {
+                boolean resampleHistory = false;
+                Slog.i(LOG_TAG, "New history parameters: mode:"
+                        + AppOpsManager.historicalModeToString(mMode) + " baseSnapshotInterval:"
+                        + baseSnapshotInterval + " intervalCompressionMultiplier:"
+                        + intervalCompressionMultiplier);
+                if (mMode != mode) {
+                    mMode = mode;
+                    if (mMode == AppOpsManager.HISTORICAL_MODE_DISABLED) {
+                        clearHistoryOnDiskLocked();
+                    }
+                }
+                if (mBaseSnapshotInterval != baseSnapshotInterval) {
+                    mBaseSnapshotInterval = baseSnapshotInterval;
+                    resampleHistory = true;
+                }
+                if (mIntervalCompressionMultiplier != intervalCompressionMultiplier) {
+                    mIntervalCompressionMultiplier = intervalCompressionMultiplier;
+                    resampleHistory = true;
+                }
+                if (resampleHistory) {
+                    resampleHistoryOnDiskInMemoryDMLocked(0);
+                }
+            }
+        }
+    }
+
+    void offsetHistory(long offsetMillis) {
+        synchronized (mOnDiskLock) {
+            synchronized (mInMemoryLock) {
+                final List<HistoricalOps> history = mPersistence.readHistoryDLocked();
+                clearHistory();
+                if (history != null) {
+                    final int historySize = history.size();
+                    for (int i = 0; i < historySize; i++) {
+                        final HistoricalOps ops = history.get(i);
+                        ops.offsetBeginAndEndTime(offsetMillis);
+                    }
+                    if (offsetMillis < 0) {
+                        pruneFutureOps(history);
+                    }
+                    mPersistence.persistHistoricalOpsDLocked(history);
+                }
+            }
+        }
+    }
+
+    void addHistoricalOps(HistoricalOps ops) {
+        final List<HistoricalOps> pendingWrites;
+        synchronized (mInMemoryLock) {
+            // The history files start from mBaseSnapshotInterval - take this into account.
+            ops.offsetBeginAndEndTime(mBaseSnapshotInterval);
+            mPendingWrites.offerFirst(ops);
+            pendingWrites = new ArrayList<>(mPendingWrites);
+            mPendingWrites.clear();
+        }
+        persistPendingHistory(pendingWrites);
+    }
+
+    private void resampleHistoryOnDiskInMemoryDMLocked(long offsetMillis) {
+        mPersistence = new Persistence(mBaseSnapshotInterval, mIntervalCompressionMultiplier);
+        offsetHistory(offsetMillis);
+    }
+
+    void resetHistoryParameters() {
+        setHistoryParameters(DEFAULT_MODE, DEFAULT_SNAPSHOT_INTERVAL_MILLIS,
+                DEFAULT_COMPRESSION_STEP);
+    }
+
+    void clearHistory() {
+        synchronized (mOnDiskLock) {
+            clearHistoryOnDiskLocked();
+        }
+    }
+
+    private void clearHistoryOnDiskLocked() {
+        BackgroundThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY);
+        synchronized (mInMemoryLock) {
+            mCurrentHistoricalOps = null;
+            mNextPersistDueTimeMillis = System.currentTimeMillis();
+            mPendingWrites.clear();
+        }
+        mPersistence.clearHistoryDLocked();
+    }
+
+    private @NonNull HistoricalOps getUpdatedPendingHistoricalOpsMLocked(long now) {
+        if (mCurrentHistoricalOps != null) {
+            final long remainingTimeMillis = mNextPersistDueTimeMillis - now;
+            if (remainingTimeMillis > mBaseSnapshotInterval) {
+                // If time went backwards we need to push history to the future with the
+                // overflow over our snapshot interval. If time went forward do nothing
+                // as we would naturally push history into the past on the next write.
+                mPendingHistoryOffsetMillis = remainingTimeMillis - mBaseSnapshotInterval;
+            }
+            final long elapsedTimeMillis = mBaseSnapshotInterval - remainingTimeMillis;
+            mCurrentHistoricalOps.setEndTime(elapsedTimeMillis);
+            if (remainingTimeMillis > 0) {
+                if (DEBUG) {
+                    Slog.i(LOG_TAG, "Returning current in-memory state");
+                }
+                return mCurrentHistoricalOps;
+            }
+            if (mCurrentHistoricalOps.isEmpty()) {
+                mCurrentHistoricalOps.setBeginAndEndTime(0, 0);
+                mNextPersistDueTimeMillis = now + mBaseSnapshotInterval;
+                return mCurrentHistoricalOps;
+            }
+            // The current batch is full, so persist taking into account overdue persist time.
+            mCurrentHistoricalOps.offsetBeginAndEndTime(mBaseSnapshotInterval);
+            mCurrentHistoricalOps.setBeginTime(mCurrentHistoricalOps.getEndTimeMillis()
+                    - mBaseSnapshotInterval);
+            final long overdueTimeMillis = Math.abs(remainingTimeMillis);
+            mCurrentHistoricalOps.offsetBeginAndEndTime(overdueTimeMillis);
+            schedulePersistHistoricalOpsMLocked(mCurrentHistoricalOps);
+        }
+        // The current batch is in the future, i.e. not complete yet.
+        mCurrentHistoricalOps = new HistoricalOps(0, 0);
+        mNextPersistDueTimeMillis = now + mBaseSnapshotInterval;
+        if (DEBUG) {
+            Slog.i(LOG_TAG, "Returning new in-memory state");
+        }
+        return mCurrentHistoricalOps;
+    }
+
+    private void persistPendingHistory() {
+        final List<HistoricalOps> pendingWrites;
+        synchronized (mOnDiskLock) {
+            synchronized (mInMemoryLock) {
+                pendingWrites = new ArrayList<>(mPendingWrites);
+                mPendingWrites.clear();
+                if (mPendingHistoryOffsetMillis != 0) {
+                    resampleHistoryOnDiskInMemoryDMLocked(mPendingHistoryOffsetMillis);
+                    mPendingHistoryOffsetMillis = 0;
+                }
+            }
+            persistPendingHistory(pendingWrites);
+        }
+    }
+
+    private void persistPendingHistory(@NonNull List<HistoricalOps> pendingWrites) {
+        synchronized (mOnDiskLock) {
+            BackgroundThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY);
+            if (pendingWrites.isEmpty()) {
+                return;
+            }
+            final int opCount = pendingWrites.size();
+            // Pending writes are offset relative to each other, so take this
+            // into account to persist everything in one shot - single write.
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalOps current = pendingWrites.get(i);
+                if (i > 0) {
+                    final HistoricalOps previous = pendingWrites.get(i - 1);
+                    current.offsetBeginAndEndTime(previous.getBeginTimeMillis());
+                }
+            }
+            mPersistence.persistHistoricalOpsDLocked(pendingWrites);
+        }
+    }
+
+    private void schedulePersistHistoricalOpsMLocked(@NonNull HistoricalOps ops) {
+        final Message message = PooledLambda.obtainMessage(
+                HistoricalRegistry::persistPendingHistory, HistoricalRegistry.this);
+        message.what = MSG_WRITE_PENDING_HISTORY;
+        BackgroundThread.getHandler().sendMessage(message);
+        mPendingWrites.offerFirst(ops);
+    }
+
+    private static void makeRelativeToEpochStart(@NonNull HistoricalOps ops, long nowMillis) {
+        ops.setBeginAndEndTime(nowMillis - ops.getEndTimeMillis(),
+                nowMillis- ops.getBeginTimeMillis());
+    }
+
+    private void pruneFutureOps(@NonNull List<HistoricalOps> ops) {
+        final int opCount = ops.size();
+        for (int i = opCount - 1; i >= 0; i--) {
+            final HistoricalOps op = ops.get(i);
+            if (op.getEndTimeMillis() <= mBaseSnapshotInterval) {
+                ops.remove(i);
+            } else if (op.getBeginTimeMillis() < mBaseSnapshotInterval) {
+                final double filterScale = (double) (op.getEndTimeMillis() - mBaseSnapshotInterval)
+                        / (double) op.getDurationMillis();
+                Persistence.spliceFromBeginning(op, filterScale);
+            }
+        }
+    }
+
+    private static final class Persistence {
+        private static final boolean DEBUG = false;
+
+        private static final String LOG_TAG = Persistence.class.getSimpleName();
+
+        private static final String TAG_HISTORY = "history";
+        private static final String TAG_OPS = "ops";
+        private static final String TAG_UID = "uid";
+        private static final String TAG_PACKAGE = "package";
+        private static final String TAG_OP = "op";
+        private static final String TAG_STATE = "state";
+
+        private static final String ATTR_VERSION = "version";
+        private static final String ATTR_NAME = "name";
+        private static final String ATTR_ACCESS_COUNT = "accessCount";
+        private static final String ATTR_REJECT_COUNT = "rejectCount";
+        private static final String ATTR_ACCESS_DURATION = "accessDuration";
+        private static final String ATTR_BEGIN_TIME = "beginTime";
+        private static final String ATTR_END_TIME = "endTime";
+        private static final String ATTR_OVERFLOW = "overflow";
+
+        private static final int CURRENT_VERSION = 1;
+
+        private final long mBaseSnapshotInterval;
+        private final long mIntervalCompressionMultiplier;
+
+        Persistence(long baseSnapshotInterval, long intervalCompressionMultiplier) {
+            mBaseSnapshotInterval = baseSnapshotInterval;
+            mIntervalCompressionMultiplier = intervalCompressionMultiplier;
+        }
+
+        private final AtomicDirectory mHistoricalAppOpsDir = new AtomicDirectory(
+                new File(new File(Environment.getDataSystemDirectory(), "appops"), "history"));
+
+        private File generateFile(@NonNull File baseDir, int depth) {
+            final long globalBeginMillis = computeGlobalIntervalBeginMillis(depth);
+            return new File(baseDir, Long.toString(globalBeginMillis) + HISTORY_FILE_SUFFIX);
+        }
+
+        void clearHistoryDLocked() {
+            mHistoricalAppOpsDir.delete();
+        }
+
+        void persistHistoricalOpsDLocked(@NonNull List<HistoricalOps> ops) {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "Persisting ops:\n" + opsToDebugString(ops));
+                enforceOpsWellFormed(ops);
+            }
+            try {
+                final File newBaseDir = mHistoricalAppOpsDir.startWrite();
+                final File oldBaseDir = mHistoricalAppOpsDir.getBackupDirectory();
+                final HistoricalFilesInvariant filesInvariant;
+                if (DEBUG) {
+                    filesInvariant = new HistoricalFilesInvariant();
+                    filesInvariant.startTracking(oldBaseDir);
+                }
+                final Set<String> oldFileNames = getHistoricalFileNames(oldBaseDir);
+                handlePersistHistoricalOpsRecursiveDLocked(newBaseDir, oldBaseDir, ops,
+                        oldFileNames,  0);
+                if (DEBUG) {
+                    filesInvariant.stopTracking(newBaseDir);
+                }
+                mHistoricalAppOpsDir.finishWrite();
+            } catch (Throwable t) {
+                wtf("Failed to write historical app ops, restoring backup", t, null);
+                mHistoricalAppOpsDir.failWrite();
+            }
+        }
+
+        @Nullable List<HistoricalOps> readHistoryRawDLocked() {
+            return collectHistoricalOpsBaseDLocked(Process.INVALID_UID /*filterUid*/,
+                    null /*filterPackageName*/, null /*filterOpNames*/,
+                    0 /*filterBeginTimeMills*/, Long.MAX_VALUE /*filterEndTimeMills*/);
+        }
+
+        @Nullable List<HistoricalOps> readHistoryDLocked() {
+            final List<HistoricalOps> result = readHistoryRawDLocked();
+            // Take into account in memory state duration.
+            if (result != null) {
+                final int opCount = result.size();
+                for (int i = 0; i < opCount; i++) {
+                    result.get(i).offsetBeginAndEndTime(mBaseSnapshotInterval);
+                }
+            }
+            return result;
+        }
+
+        long getLastPersistTimeMillisDLocked() {
+            File baseDir = null;
+            try {
+                baseDir = mHistoricalAppOpsDir.startRead();
+                final File[] files = baseDir.listFiles();
+                if (files != null && files.length > 0) {
+                    final Set<File> historyFiles = new ArraySet<>();
+                    Collections.addAll(historyFiles, files);
+                    for (int i = 0;; i++) {
+                        final File file = generateFile(baseDir, i);
+                        if (historyFiles.contains(file)) {
+                            return file.lastModified();
+                        }
+                    }
+                }
+                mHistoricalAppOpsDir.finishRead();
+            } catch (Throwable e) {
+                wtf("Error reading historical app ops. Deleting history.", e, baseDir);
+                mHistoricalAppOpsDir.delete();
+            }
+            return 0;
+        }
+
+        private void collectHistoricalOpsDLocked(@NonNull HistoricalOps currentOps,
+                int filterUid, @NonNull String filterPackageName, @Nullable String[] filterOpNames,
+                long filterBeingMillis, long filterEndMillis) {
+            final List<HistoricalOps> readOps = collectHistoricalOpsBaseDLocked(filterUid,
+                    filterPackageName, filterOpNames, filterBeingMillis, filterEndMillis);
+            if (readOps != null) {
+                final int readCount = readOps.size();
+                for (int i = 0; i < readCount; i++) {
+                    final HistoricalOps readOp = readOps.get(i);
+                    currentOps.merge(readOp);
+                }
+             }
+        }
+
+        private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsBaseDLocked(
+                int filterUid, @NonNull String filterPackageName, @Nullable String[] filterOpNames,
+                long filterBeginTimeMillis, long filterEndTimeMillis) {
+            File baseDir = null;
+            try {
+                baseDir = mHistoricalAppOpsDir.startRead();
+                final HistoricalFilesInvariant filesInvariant;
+                if (DEBUG) {
+                    filesInvariant = new HistoricalFilesInvariant();
+                    filesInvariant.startTracking(baseDir);
+                }
+                final Set<String> historyFiles = getHistoricalFileNames(baseDir);
+                final long[] globalContentOffsetMillis = {0};
+                final LinkedList<HistoricalOps> ops = collectHistoricalOpsRecursiveDLocked(
+                        baseDir, filterUid, filterPackageName, filterOpNames, filterBeginTimeMillis,
+                        filterEndTimeMillis, globalContentOffsetMillis, null /*outOps*/,
+                        0 /*depth*/, historyFiles);
+                if (DEBUG) {
+                    filesInvariant.stopTracking(baseDir);
+                }
+                mHistoricalAppOpsDir.finishRead();
+                return ops;
+            } catch (Throwable t) {
+                wtf("Error reading historical app ops. Deleting history.", t, baseDir);
+                mHistoricalAppOpsDir.delete();
+            }
+            return null;
+        }
+
+        private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsRecursiveDLocked(
+                @NonNull File baseDir, int filterUid, @NonNull String filterPackageName,
+                @Nullable String[] filterOpNames, long filterBeginTimeMillis,
+                long filterEndTimeMillis, @NonNull long[] globalContentOffsetMillis,
+                @Nullable LinkedList<HistoricalOps> outOps, int depth,
+                @NonNull Set<String> historyFiles)
+                throws IOException, XmlPullParserException {
+            final long previousIntervalEndMillis = (long) Math.pow(mIntervalCompressionMultiplier,
+                    depth) * mBaseSnapshotInterval;
+            final long currentIntervalEndMillis = (long) Math.pow(mIntervalCompressionMultiplier,
+                    depth + 1) * mBaseSnapshotInterval;
+
+            filterBeginTimeMillis = Math.max(filterBeginTimeMillis - previousIntervalEndMillis, 0);
+            filterEndTimeMillis = filterEndTimeMillis - previousIntervalEndMillis;
+
+            // Read historical data at this level
+            final List<HistoricalOps> readOps = readHistoricalOpsLocked(baseDir,
+                    previousIntervalEndMillis, currentIntervalEndMillis, filterUid,
+                    filterPackageName, filterOpNames, filterBeginTimeMillis, filterEndTimeMillis,
+                    globalContentOffsetMillis, depth, historyFiles);
+
+            // Empty is a special signal to stop diving
+            if (readOps != null && readOps.isEmpty()) {
+                return outOps;
+            }
+
+            // Collect older historical data from subsequent levels
+            outOps = collectHistoricalOpsRecursiveDLocked(
+                    baseDir, filterUid, filterPackageName, filterOpNames, filterBeginTimeMillis,
+                    filterEndTimeMillis, globalContentOffsetMillis, outOps, depth + 1,
+                    historyFiles);
+
+            // Make older historical data relative to the current historical level
+            if (outOps != null) {
+                final int opCount = outOps.size();
+                for (int i = 0; i < opCount; i++) {
+                    final HistoricalOps collectedOp = outOps.get(i);
+                    collectedOp.offsetBeginAndEndTime(currentIntervalEndMillis);
+                }
+            }
+
+            if (readOps != null) {
+                if (outOps == null) {
+                    outOps = new LinkedList<>();
+                }
+                // Add the read ops to output
+                final int opCount = readOps.size();
+                for (int i = opCount - 1; i >= 0; i--) {
+                    outOps.offerFirst(readOps.get(i));
+                }
+            }
+
+            return outOps;
+        }
+
+        private void handlePersistHistoricalOpsRecursiveDLocked(@NonNull File newBaseDir,
+                @NonNull File oldBaseDir, @Nullable List<HistoricalOps> passedOps,
+                @NonNull Set<String> oldFileNames, int depth)
+                throws IOException, XmlPullParserException {
+            final long previousIntervalEndMillis = (long) Math.pow(mIntervalCompressionMultiplier,
+                    depth) * mBaseSnapshotInterval;
+            final long currentIntervalEndMillis = (long) Math.pow(mIntervalCompressionMultiplier,
+                    depth + 1) * mBaseSnapshotInterval;
+
+            if (passedOps == null || passedOps.isEmpty()) {
+                if (!oldFileNames.isEmpty()) {
+                    // If there is an old file we need to copy it over to the new state.
+                    final File oldFile = generateFile(oldBaseDir, depth);
+                    if (oldFileNames.remove(oldFile.getName())) {
+                        final File newFile = generateFile(newBaseDir, depth);
+                        Files.createLink(newFile.toPath(), oldFile.toPath());
+                    }
+                    handlePersistHistoricalOpsRecursiveDLocked(newBaseDir, oldBaseDir,
+                            passedOps, oldFileNames, depth + 1);
+                }
+                return;
+            }
+
+            if (DEBUG) {
+                enforceOpsWellFormed(passedOps);
+            }
+
+            // Normalize passed ops time to be based off this interval start
+            final int passedOpCount = passedOps.size();
+            for (int i = 0; i < passedOpCount; i++) {
+                final HistoricalOps passedOp = passedOps.get(i);
+                passedOp.offsetBeginAndEndTime(-previousIntervalEndMillis);
+            }
+
+            if (DEBUG) {
+                enforceOpsWellFormed(passedOps);
+            }
+
+            // Read persisted ops for this interval
+            final List<HistoricalOps> existingOps = readHistoricalOpsLocked(oldBaseDir,
+                    previousIntervalEndMillis, currentIntervalEndMillis,
+                    Process.INVALID_UID /*filterUid*/, null /*filterPackageName*/,
+                    null /*filterOpNames*/, Long.MIN_VALUE /*filterBeginTimeMillis*/,
+                    Long.MAX_VALUE /*filterEndTimeMillis*/, null, depth,
+                    null /*historyFiles*/);
+
+            if (DEBUG) {
+                enforceOpsWellFormed(existingOps);
+            }
+
+            // Offset existing ops to account for elapsed time
+            final int existingOpCount = existingOps.size();
+            if (existingOpCount > 0) {
+                // Compute elapsed time
+                final long elapsedTimeMillis = passedOps.get(passedOps.size() - 1)
+                        .getEndTimeMillis();
+                for (int i = 0; i < existingOpCount; i++) {
+                    final HistoricalOps existingOp = existingOps.get(i);
+                    existingOp.offsetBeginAndEndTime(elapsedTimeMillis);
+                }
+            }
+
+            if (DEBUG) {
+                enforceOpsWellFormed(existingOps);
+            }
+
+            final long slotDurationMillis = previousIntervalEndMillis;
+
+            // Consolidate passed ops at the current slot duration ensuring each snapshot is
+            // full. To achieve this we put all passed and existing ops in a list and will
+            // merge them to ensure each represents a snapshot at the current granularity.
+            final List<HistoricalOps> allOps = new LinkedList<>();
+            allOps.addAll(passedOps);
+            allOps.addAll(existingOps);
+
+            if (DEBUG) {
+                enforceOpsWellFormed(allOps);
+            }
+
+            // Compute ops to persist and overflow ops
+            List<HistoricalOps> persistedOps = null;
+            List<HistoricalOps> overflowedOps = null;
+
+            // We move a snapshot into the next level only if the start time is
+            // after the end of the current interval. This avoids rewriting all
+            // files to propagate the information added to the history on every
+            // iteration. Instead, we would rewrite the next level file only if
+            // an entire snapshot from the previous level is being propagated.
+            // The trade off is that we need to store how much the last snapshot
+            // of the current interval overflows past the interval end. We write
+            // the overflow data to avoid parsing all snapshots on query.
+            long intervalOverflowMillis = 0;
+            final int opCount = allOps.size();
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalOps op = allOps.get(i);
+                final HistoricalOps persistedOp;
+                final HistoricalOps overflowedOp;
+                if (op.getEndTimeMillis() <= currentIntervalEndMillis) {
+                    persistedOp = op;
+                    overflowedOp = null;
+                } else if (op.getBeginTimeMillis() < currentIntervalEndMillis) {
+                    persistedOp = op;
+                    intervalOverflowMillis = op.getEndTimeMillis() - currentIntervalEndMillis;
+                    if (intervalOverflowMillis > previousIntervalEndMillis) {
+                        final double splitScale = (double) intervalOverflowMillis
+                                / op.getDurationMillis();
+                        overflowedOp = spliceFromEnd(op, splitScale);
+                        intervalOverflowMillis = op.getEndTimeMillis() - currentIntervalEndMillis;
+                    } else {
+                        overflowedOp = null;
+                    }
+                } else {
+                    persistedOp = null;
+                    overflowedOp = op;
+                }
+                if (persistedOp != null) {
+                    if (persistedOps == null) {
+                        persistedOps = new ArrayList<>();
+                    }
+                    persistedOps.add(persistedOp);
+                }
+                if (overflowedOp != null) {
+                    if (overflowedOps == null) {
+                        overflowedOps = new ArrayList<>();
+                    }
+                    overflowedOps.add(overflowedOp);
+                }
+            }
+
+            if (DEBUG) {
+                enforceOpsWellFormed(persistedOps);
+                enforceOpsWellFormed(overflowedOps);
+            }
+
+            final File newFile = generateFile(newBaseDir, depth);
+            oldFileNames.remove(newFile.getName());
+
+            if (persistedOps != null) {
+                normalizeSnapshotForSlotDuration(persistedOps, slotDurationMillis);
+                writeHistoricalOpsDLocked(persistedOps, intervalOverflowMillis, newFile);
+                if (DEBUG) {
+                    Slog.i(LOG_TAG, "Persisted at depth: " + depth
+                            + " ops:\n" + opsToDebugString(persistedOps));
+                    enforceOpsWellFormed(persistedOps);
+                }
+            }
+
+            handlePersistHistoricalOpsRecursiveDLocked(newBaseDir, oldBaseDir,
+                    overflowedOps, oldFileNames, depth + 1);
+        }
+
+        private @NonNull List<HistoricalOps> readHistoricalOpsLocked(File baseDir,
+                long intervalBeginMillis, long intervalEndMillis, int filterUid,
+                @Nullable String filterPackageName, @Nullable String[] filterOpNames,
+                long filterBeginTimeMillis, long filterEndTimeMillis,
+                @Nullable long[] cumulativeOverflowMillis, int depth,
+                @NonNull Set<String> historyFiles)
+                throws IOException, XmlPullParserException {
+            final File file = generateFile(baseDir, depth);
+            if (historyFiles != null) {
+                historyFiles.remove(file.getName());
+            }
+            if (filterBeginTimeMillis >= filterEndTimeMillis
+                    || filterEndTimeMillis < intervalBeginMillis) {
+                // Don't go deeper
+                return Collections.emptyList();
+            }
+            if (filterBeginTimeMillis >= (intervalEndMillis
+                    + ((intervalEndMillis - intervalBeginMillis) / mIntervalCompressionMultiplier)
+                    + (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0))
+                    || !file.exists()) {
+                if (historyFiles == null || historyFiles.isEmpty()) {
+                    // Don't go deeper
+                    return Collections.emptyList();
+                } else {
+                    // Keep diving
+                    return null;
+                }
+            }
+            return readHistoricalOpsLocked(file, filterUid, filterPackageName, filterOpNames,
+                    filterBeginTimeMillis, filterEndTimeMillis, cumulativeOverflowMillis);
+        }
+
+        private @Nullable List<HistoricalOps> readHistoricalOpsLocked(@NonNull File file,
+                int filterUid, @Nullable String filterPackageName, @Nullable String[] filterOpNames,
+                long filterBeginTimeMillis, long filterEndTimeMillis,
+                @Nullable long[] cumulativeOverflowMillis)
+                throws IOException, XmlPullParserException {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "Reading ops from:" + file);
+            }
+            List<HistoricalOps> allOps = null;
+            try (FileInputStream stream = new FileInputStream(file)) {
+                final XmlPullParser parser = Xml.newPullParser();
+                parser.setInput(stream, StandardCharsets.UTF_8.name());
+                XmlUtils.beginDocument(parser, TAG_HISTORY);
+                final long overflowMillis = XmlUtils.readLongAttribute(parser, ATTR_OVERFLOW, 0);
+                final int depth = parser.getDepth();
+                while (XmlUtils.nextElementWithin(parser, depth)) {
+                    if (TAG_OPS.equals(parser.getName())) {
+                        final HistoricalOps ops = readeHistoricalOpsDLocked(parser,
+                                filterUid, filterPackageName, filterOpNames, filterBeginTimeMillis,
+                                filterEndTimeMillis, cumulativeOverflowMillis);
+                        if (ops == null) {
+                            continue;
+                        }
+                        if (ops.isEmpty()) {
+                            XmlUtils.skipCurrentTag(parser);
+                            continue;
+                        }
+                        if (allOps == null) {
+                            allOps = new ArrayList<>();
+                        }
+                        allOps.add(ops);
+                    }
+                }
+                if (cumulativeOverflowMillis != null) {
+                    cumulativeOverflowMillis[0] += overflowMillis;
+                }
+            } catch (FileNotFoundException e) {
+                Slog.i(LOG_TAG, "No history file: " + file.getName());
+                return Collections.emptyList();
+            }
+            if (DEBUG) {
+                if (allOps != null) {
+                    Slog.i(LOG_TAG, "Read from file: " + file + "ops:\n"
+                            + opsToDebugString(allOps));
+                    enforceOpsWellFormed(allOps);
+                }
+            }
+            return allOps;
+        }
+
+        private @Nullable HistoricalOps readeHistoricalOpsDLocked(
+                @NonNull XmlPullParser parser, int filterUid, @Nullable String filterPackageName,
+                @Nullable String[] filterOpNames, long filterBeginTimeMillis,
+                long filterEndTimeMillis, @Nullable long[] cumulativeOverflowMillis)
+                throws IOException, XmlPullParserException {
+            final long beginTimeMillis = XmlUtils.readLongAttribute(parser, ATTR_BEGIN_TIME, 0)
+                    + (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0);
+            final long endTimeMillis = XmlUtils.readLongAttribute(parser, ATTR_END_TIME, 0)
+                    + (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0);
+            // Keep reading as subsequent records may start matching
+            if (filterEndTimeMillis < beginTimeMillis) {
+                return null;
+            }
+            // Stop reading as subsequent records will not match
+            if (filterBeginTimeMillis > endTimeMillis) {
+                return new HistoricalOps(0, 0);
+            }
+            final long filteredBeginTimeMillis = Math.max(beginTimeMillis, filterBeginTimeMillis);
+            final long filteredEndTimeMillis = Math.min(endTimeMillis, filterEndTimeMillis);
+            final double filterScale = (double) (filteredEndTimeMillis - filteredBeginTimeMillis)
+                    / (double) (endTimeMillis - beginTimeMillis);
+            HistoricalOps ops = null;
+            final int depth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, depth)) {
+                if (TAG_UID.equals(parser.getName())) {
+                    final HistoricalOps returnedOps = readHistoricalUidOpsDLocked(ops, parser,
+                            filterUid, filterPackageName, filterOpNames, filterScale);
+                    if (ops == null) {
+                        ops = returnedOps;
+                    }
+                }
+            }
+            if (ops != null) {
+                ops.setBeginAndEndTime(filteredBeginTimeMillis, filteredEndTimeMillis);
+            }
+            return ops;
+        }
+
+        private @Nullable HistoricalOps readHistoricalUidOpsDLocked(
+                @Nullable HistoricalOps ops, @NonNull XmlPullParser parser, int filterUid,
+                @Nullable String filterPackageName, @Nullable String[] filterOpNames,
+                double filterScale) throws IOException, XmlPullParserException {
+            final int uid = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+            if (filterUid != Process.INVALID_UID && filterUid != uid) {
+                XmlUtils.skipCurrentTag(parser);
+                return null;
+            }
+            final int depth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, depth)) {
+                if (TAG_PACKAGE.equals(parser.getName())) {
+                    final HistoricalOps returnedOps = readHistoricalPackageOpsDLocked(ops,
+                            uid, parser, filterPackageName, filterOpNames, filterScale);
+                    if (ops == null) {
+                        ops = returnedOps;
+                    }
+                }
+            }
+            return ops;
+        }
+
+        private @Nullable HistoricalOps readHistoricalPackageOpsDLocked(
+                @Nullable HistoricalOps ops, int uid, @NonNull XmlPullParser parser,
+                @Nullable String filterPackageName, @Nullable String[] filterOpNames,
+                double filterScale) throws IOException, XmlPullParserException {
+            final String packageName = XmlUtils.readStringAttribute(parser, ATTR_NAME);
+            if (filterPackageName != null && !filterPackageName.equals(packageName)) {
+                XmlUtils.skipCurrentTag(parser);
+                return null;
+            }
+            final int depth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, depth)) {
+                if (TAG_OP.equals(parser.getName())) {
+                    final HistoricalOps returnedOps = readHistoricalOpDLocked(ops, uid,
+                            packageName, parser, filterOpNames, filterScale);
+                    if (ops == null) {
+                        ops = returnedOps;
+                    }
+                }
+            }
+            return ops;
+        }
+
+        private @Nullable HistoricalOps readHistoricalOpDLocked(@Nullable HistoricalOps ops,
+                int uid, String packageName, @NonNull XmlPullParser parser,
+                @Nullable String[] filterOpNames, double filterScale)
+                throws IOException, XmlPullParserException {
+            final int op = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+            if (filterOpNames != null && !ArrayUtils.contains(filterOpNames,
+                    AppOpsManager.opToPublicName(op))) {
+                XmlUtils.skipCurrentTag(parser);
+                return null;
+            }
+            final int depth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, depth)) {
+                if (TAG_STATE.equals(parser.getName())) {
+                    final HistoricalOps returnedOps = readUidStateDLocked(ops, uid,
+                            packageName, op, parser, filterScale);
+                    if (ops == null) {
+                        ops = returnedOps;
+                    }
+                }
+            }
+            return ops;
+        }
+
+        private @Nullable HistoricalOps readUidStateDLocked(@Nullable HistoricalOps ops,
+                int uid, String packageName, int op, @NonNull XmlPullParser parser,
+                double filterScale) throws IOException {
+            final int uidState = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+            long accessCount = XmlUtils.readLongAttribute(parser, ATTR_ACCESS_COUNT, 0);
+            if (accessCount > 0) {
+                if (!Double.isNaN(filterScale)) {
+                    accessCount = (long) HistoricalOps.round(
+                            (double) accessCount * filterScale);
+                }
+                if (ops == null) {
+                    ops = new HistoricalOps(0, 0);
+                }
+                ops.increaseAccessCount(op, uid, packageName, uidState, accessCount);
+            }
+            long rejectCount = XmlUtils.readLongAttribute(parser, ATTR_REJECT_COUNT, 0);
+            if (rejectCount > 0) {
+                if (!Double.isNaN(filterScale)) {
+                    rejectCount = (long) HistoricalOps.round(
+                            (double) rejectCount * filterScale);
+                }
+                if (ops == null) {
+                    ops = new HistoricalOps(0, 0);
+                }
+                ops.increaseRejectCount(op, uid, packageName, uidState, rejectCount);
+            }
+            long accessDuration =  XmlUtils.readLongAttribute(parser, ATTR_ACCESS_DURATION, 0);
+            if (accessDuration > 0) {
+                if (!Double.isNaN(filterScale)) {
+                    accessDuration = (long) HistoricalOps.round(
+                            (double) accessDuration * filterScale);
+                }
+                if (ops == null) {
+                    ops = new HistoricalOps(0, 0);
+                }
+                ops.increaseAccessDuration(op, uid, packageName, uidState, accessDuration);
+            }
+            return ops;
+        }
+
+        private void writeHistoricalOpsDLocked(@Nullable List<HistoricalOps> allOps,
+                long intervalOverflowMillis, @NonNull File file) throws IOException {
+            final FileOutputStream output = mHistoricalAppOpsDir.openWrite(file);
+            try {
+                final XmlSerializer serializer = Xml.newSerializer();
+                serializer.setOutput(output, StandardCharsets.UTF_8.name());
+                serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
+                        true);
+                serializer.startDocument(null, true);
+                serializer.startTag(null, TAG_HISTORY);
+                serializer.attribute(null, ATTR_VERSION, String.valueOf(CURRENT_VERSION));
+                if (intervalOverflowMillis != 0) {
+                    serializer.attribute(null, ATTR_OVERFLOW,
+                            Long.toString(intervalOverflowMillis));
+                }
+                if (allOps != null) {
+                    final int opsCount = allOps.size();
+                    for (int i = 0; i < opsCount; i++) {
+                        final HistoricalOps ops = allOps.get(i);
+                        writeHistoricalOpDLocked(ops, serializer);
+                    }
+                }
+                serializer.endTag(null, TAG_HISTORY);
+                serializer.endDocument();
+                mHistoricalAppOpsDir.closeWrite(output);
+            } catch (IOException e) {
+                mHistoricalAppOpsDir.failWrite(output);
+                throw e;
+            }
+        }
+
+        private void writeHistoricalOpDLocked(@NonNull HistoricalOps ops,
+                @NonNull XmlSerializer serializer) throws IOException {
+            serializer.startTag(null, TAG_OPS);
+            serializer.attribute(null, ATTR_BEGIN_TIME, Long.toString(ops.getBeginTimeMillis()));
+            serializer.attribute(null, ATTR_END_TIME, Long.toString(ops.getEndTimeMillis()));
+            final int uidCount = ops.getUidCount();
+            for (int i = 0; i < uidCount; i++) {
+                final HistoricalUidOps uidOp = ops.getUidOpsAt(i);
+                writeHistoricalUidOpsDLocked(uidOp, serializer);
+            }
+            serializer.endTag(null, TAG_OPS);
+        }
+
+        private void writeHistoricalUidOpsDLocked(@NonNull HistoricalUidOps uidOps,
+                @NonNull XmlSerializer serializer) throws IOException {
+            serializer.startTag(null, TAG_UID);
+            serializer.attribute(null, ATTR_NAME, Integer.toString(uidOps.getUid()));
+            final int packageCount = uidOps.getPackageCount();
+            for (int i = 0; i < packageCount; i++) {
+                final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(i);
+                writeHistoricalPackageOpsDLocked(packageOps, serializer);
+            }
+            serializer.endTag(null, TAG_UID);
+        }
+
+        private void writeHistoricalPackageOpsDLocked(@NonNull HistoricalPackageOps packageOps,
+                @NonNull XmlSerializer serializer) throws IOException {
+            serializer.startTag(null, TAG_PACKAGE);
+            serializer.attribute(null, ATTR_NAME, packageOps.getPackageName());
+            final int opCount = packageOps.getOpCount();
+            for (int i = 0; i < opCount; i++) {
+                final HistoricalOp op = packageOps.getOpAt(i);
+                writeHistoricalOpDLocked(op, serializer);
+            }
+            serializer.endTag(null, TAG_PACKAGE);
+        }
+
+        private void writeHistoricalOpDLocked(@NonNull HistoricalOp op,
+                @NonNull XmlSerializer serializer) throws IOException {
+            serializer.startTag(null, TAG_OP);
+            serializer.attribute(null, ATTR_NAME, Integer.toString(op.getOpCode()));
+            for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
+                writeUidStateOnLocked(op, uidState, serializer);
+            }
+            serializer.endTag(null, TAG_OP);
+        }
+
+        private void writeUidStateOnLocked(@NonNull HistoricalOp op, @UidState int uidState,
+                @NonNull XmlSerializer serializer) throws IOException {
+            final long accessCount = op.getAccessCount(uidState);
+            final long rejectCount = op.getRejectCount(uidState);
+            final long accessDuration = op.getAccessDuration(uidState);
+            if (accessCount == 0 && rejectCount == 0 && accessDuration == 0) {
+                return;
+            }
+            serializer.startTag(null, TAG_STATE);
+            serializer.attribute(null, ATTR_NAME, Integer.toString(uidState));
+            if (accessCount > 0) {
+                serializer.attribute(null, ATTR_ACCESS_COUNT, Long.toString(accessCount));
+            }
+            if (rejectCount > 0) {
+                serializer.attribute(null, ATTR_REJECT_COUNT, Long.toString(rejectCount));
+            }
+            if (accessDuration > 0) {
+                serializer.attribute(null, ATTR_ACCESS_DURATION, Long.toString(accessDuration));
+            }
+            serializer.endTag(null, TAG_STATE);
+        }
+
+        private static void enforceOpsWellFormed(@NonNull List<HistoricalOps> ops) {
+            if (ops == null) {
+                return;
+            }
+            HistoricalOps previous;
+            HistoricalOps current = null;
+            final int opsCount = ops.size();
+            for (int i = 0; i < opsCount; i++) {
+                previous = current;
+                current = ops.get(i);
+                if (current.isEmpty()) {
+                    throw new IllegalStateException("Empty ops:\n"
+                            + opsToDebugString(ops));
+                }
+                if (current.getEndTimeMillis() < current.getBeginTimeMillis()) {
+                    throw new IllegalStateException("Begin after end:\n"
+                            + opsToDebugString(ops));
+                }
+                if (previous != null) {
+                    if (previous.getEndTimeMillis() > current.getBeginTimeMillis()) {
+                        throw new IllegalStateException("Intersecting ops:\n"
+                                + opsToDebugString(ops));
+                    }
+                    if (previous.getBeginTimeMillis() > current.getBeginTimeMillis()) {
+                        throw new IllegalStateException("Non increasing ops:\n"
+                                + opsToDebugString(ops));
+                    }
+                }
+            }
+        }
+
+        private long computeGlobalIntervalBeginMillis(int depth) {
+            long beginTimeMillis = 0;
+            for (int i = 0; i < depth + 1; i++) {
+                beginTimeMillis += Math.pow(mIntervalCompressionMultiplier, i);
+            }
+            return beginTimeMillis * mBaseSnapshotInterval;
+        }
+
+        private static @NonNull HistoricalOps spliceFromEnd(@NonNull HistoricalOps ops,
+                double spliceRatio) {
+            if (DEBUG) {
+                Slog.w(LOG_TAG, "Splicing from end:" + ops + " ratio:" + spliceRatio);
+            }
+            final HistoricalOps splice = ops.spliceFromEnd(spliceRatio);
+            if (DEBUG) {
+                Slog.w(LOG_TAG, "Spliced into:" + ops + " and:" + splice);
+            }
+            return splice;
+        }
+
+
+        private static @NonNull HistoricalOps spliceFromBeginning(@NonNull HistoricalOps ops,
+                double spliceRatio) {
+            if (DEBUG) {
+                Slog.w(LOG_TAG, "Splicing from beginning:" + ops + " ratio:" + spliceRatio);
+            }
+            final HistoricalOps splice = ops.spliceFromBeginning(spliceRatio);
+            if (DEBUG) {
+                Slog.w(LOG_TAG, "Spliced into:" + ops + " and:" + splice);
+            }
+            return splice;
+        }
+
+        private static void normalizeSnapshotForSlotDuration(@NonNull List<HistoricalOps> ops,
+                long slotDurationMillis) {
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "Normalizing for slot duration: " + slotDurationMillis
+                        + " ops:\n" + opsToDebugString(ops));
+                enforceOpsWellFormed(ops);
+            }
+            long slotBeginTimeMillis;
+            final int opCount = ops.size();
+            for (int processedIdx = opCount - 1; processedIdx >= 0; processedIdx--) {
+                final HistoricalOps processedOp = ops.get(processedIdx);
+                slotBeginTimeMillis = Math.max(processedOp.getEndTimeMillis()
+                        - slotDurationMillis, 0);
+                for (int candidateIdx = processedIdx - 1; candidateIdx >= 0; candidateIdx--) {
+                    final HistoricalOps candidateOp = ops.get(candidateIdx);
+                    final long candidateSlotIntersectionMillis = candidateOp.getEndTimeMillis()
+                            - Math.min(slotBeginTimeMillis, processedOp.getBeginTimeMillis());
+                    if (candidateSlotIntersectionMillis <= 0) {
+                        break;
+                    }
+                    final float candidateSplitRatio = candidateSlotIntersectionMillis
+                            / (float) candidateOp.getDurationMillis();
+                    if (Float.compare(candidateSplitRatio, 1.0f) >= 0) {
+                        ops.remove(candidateIdx);
+                        processedIdx--;
+                        processedOp.merge(candidateOp);
+                    } else {
+                        final HistoricalOps endSplice = spliceFromEnd(candidateOp,
+                                candidateSplitRatio);
+                        if (endSplice != null) {
+                            processedOp.merge(endSplice);
+                        }
+                        if (candidateOp.isEmpty()) {
+                            ops.remove(candidateIdx);
+                            processedIdx--;
+                        }
+                    }
+                }
+            }
+            if (DEBUG) {
+                Slog.i(LOG_TAG, "Normalized for slot duration: " + slotDurationMillis
+                        + " ops:\n" + opsToDebugString(ops));
+                enforceOpsWellFormed(ops);
+            }
+        }
+
+        private static @NonNull String opsToDebugString(@NonNull List<HistoricalOps> ops) {
+            StringBuilder builder = new StringBuilder();
+            final int opCount = ops.size();
+            for (int i = 0; i < opCount; i++) {
+                builder.append("  ");
+                builder.append(ops.get(i));
+                if (i < opCount - 1) {
+                    builder.append('\n');
+                }
+            }
+            return builder.toString();
+        }
+
+        private static Set<String> getHistoricalFileNames(@NonNull File historyDir)  {
+            final File[] files = historyDir.listFiles();
+            if (files == null) {
+                return Collections.emptySet();
+            }
+            final ArraySet<String> fileNames = new ArraySet<>(files.length);
+            for (File file : files) {
+                fileNames.add(file.getName());
+
+            }
+            return fileNames;
+        }
+    }
+
+    private static class HistoricalFilesInvariant {
+        private final @NonNull List<File> mBeginFiles = new ArrayList<>();
+
+        public void startTracking(@NonNull File folder) {
+            final File[] files = folder.listFiles();
+            if (files != null) {
+                Collections.addAll(mBeginFiles, files);
+            }
+        }
+
+        public void stopTracking(@NonNull File folder) {
+            final List<File> endFiles = new ArrayList<>();
+            final File[] files = folder.listFiles();
+            if (files != null) {
+                Collections.addAll(endFiles, files);
+            }
+            final long beginOldestFileOffsetMillis = getOldestFileOffsetMillis(mBeginFiles);
+            final long endOldestFileOffsetMillis = getOldestFileOffsetMillis(endFiles);
+            if (endOldestFileOffsetMillis < beginOldestFileOffsetMillis) {
+                final String message = "History loss detected!"
+                        + "\nold files: " + mBeginFiles;
+                wtf(message, null, folder);
+                throw new IllegalStateException(message);
+            }
+        }
+
+        private static long getOldestFileOffsetMillis(@NonNull List<File> files) {
+            if (files.isEmpty()) {
+                return 0;
+            }
+            String longestName = files.get(0).getName();
+            final int fileCount = files.size();
+            for (int i = 1; i < fileCount; i++) {
+                final File file = files.get(i);
+                if (file.getName().length() > longestName.length()) {
+                    longestName = file.getName();
+                }
+            }
+            return Long.parseLong(longestName.replace(HISTORY_FILE_SUFFIX, ""));
+        }
+    }
+
+    private final class StringDumpVisitor implements AppOpsManager.HistoricalOpsVisitor {
+        private final long mNow = System.currentTimeMillis();
+
+        private final SimpleDateFormat mDateFormatter = new SimpleDateFormat(
+                "yyyy-MM-dd HH:mm:ss.SSS");
+        private final Date mDate = new Date();
+
+        private final @NonNull String mOpsPrefix;
+        private final @NonNull String mUidPrefix;
+        private final @NonNull String mPackagePrefix;
+        private final @NonNull String mEntryPrefix;
+        private final @NonNull String mUidStatePrefix;
+        private final @NonNull PrintWriter mWriter;
+        private final int mFilterUid;
+        private final String mFilterPackage;
+        private final int mFilterOp;
+
+        StringDumpVisitor(@NonNull String prefix, @NonNull PrintWriter writer,
+                int filterUid, String filterPackage, int filterOp) {
+            mOpsPrefix = prefix + "  ";
+            mUidPrefix = mOpsPrefix + "  ";
+            mPackagePrefix = mUidPrefix + "  ";
+            mEntryPrefix = mPackagePrefix + "  ";
+            mUidStatePrefix = mEntryPrefix + "  ";
+            mWriter = writer;
+            mFilterUid = filterUid;
+            mFilterPackage = filterPackage;
+            mFilterOp = filterOp;
+        }
+
+        @Override
+        public void visitHistoricalOps(HistoricalOps ops) {
+            mWriter.println();
+            mWriter.print(mOpsPrefix);
+            mWriter.println("snapshot:");
+            mWriter.print(mUidPrefix);
+            mWriter.print("begin = ");
+            mDate.setTime(ops.getBeginTimeMillis());
+            mWriter.print(mDateFormatter.format(mDate));
+            mWriter.print("  (");
+            TimeUtils.formatDuration(ops.getBeginTimeMillis() - mNow, mWriter);
+            mWriter.println(")");
+            mWriter.print(mUidPrefix);
+            mWriter.print("end = ");
+            mDate.setTime(ops.getEndTimeMillis());
+            mWriter.print(mDateFormatter.format(mDate));
+            mWriter.print("  (");
+            TimeUtils.formatDuration(ops.getEndTimeMillis() - mNow, mWriter);
+            mWriter.println(")");
+        }
+
+        @Override
+        public void visitHistoricalUidOps(HistoricalUidOps ops) {
+            if (mFilterUid != Process.INVALID_UID && mFilterUid != ops.getUid()) {
+                return;
+            }
+            mWriter.println();
+            mWriter.print(mUidPrefix);
+            mWriter.print("Uid ");
+            UserHandle.formatUid(mWriter, ops.getUid());
+            mWriter.println(":");
+        }
+
+        @Override
+        public void visitHistoricalPackageOps(HistoricalPackageOps ops) {
+            if (mFilterPackage != null && !mFilterPackage.equals(ops.getPackageName())) {
+                return;
+            }
+            mWriter.print(mPackagePrefix);
+            mWriter.print("Package ");
+            mWriter.print(ops.getPackageName());
+            mWriter.println(":");
+        }
+
+        @Override
+        public void visitHistoricalOp(HistoricalOp ops) {
+            if (mFilterOp != AppOpsManager.OP_NONE && mFilterOp != ops.getOpCode()) {
+                return;
+            }
+            mWriter.print(mEntryPrefix);
+            mWriter.print(AppOpsManager.opToName(ops.getOpCode()));
+            mWriter.println(":");
+            for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
+                boolean printedUidState = false;
+                final long accessCount = ops.getAccessCount(uidState);
+                if (accessCount > 0) {
+                    if (!printedUidState) {
+                        mWriter.print(mUidStatePrefix);
+                        mWriter.print(AppOpsService.UID_STATE_NAMES[uidState]);
+                        mWriter.print(" = ");
+                        printedUidState = true;
+                    }
+                    mWriter.print("access=");
+                    mWriter.print(accessCount);
+                }
+                final long rejectCount = ops.getRejectCount(uidState);
+                if (rejectCount > 0) {
+                    if (!printedUidState) {
+                        mWriter.print(mUidStatePrefix);
+                        mWriter.print(AppOpsService.UID_STATE_NAMES[uidState]);
+                        mWriter.print(" = ");
+                        printedUidState = true;
+                    } else {
+                        mWriter.print(", ");
+                    }
+                    mWriter.print("reject=");
+                    mWriter.print(rejectCount);
+                }
+                final long accessDuration = ops.getAccessDuration(uidState);
+                if (accessDuration > 0) {
+                    if (!printedUidState) {
+                        mWriter.print(mUidStatePrefix);
+                        mWriter.print(AppOpsService.UID_STATE_NAMES[uidState]);
+                        mWriter.print(" = ");
+                        printedUidState = true;
+                    } else {
+                        mWriter.print(", ");
+                    }
+                    mWriter.print("duration=");
+                    TimeUtils.formatDuration(accessDuration, mWriter);
+                }
+                if (printedUidState) {
+                    mWriter.println("");
+                }
+            }
+        }
+    }
+
+    private static void wtf(@Nullable String message, @Nullable Throwable t,
+            @Nullable File storage) {
+        Slog.wtf(LOG_TAG, message, t);
+        if (KEEP_WTF_LOG) {
+            try {
+                final File file = new File(new File(Environment.getDataSystemDirectory(), "appops"),
+                        "wtf" + TimeUtils.formatForLogging(System.currentTimeMillis()));
+                if (file.createNewFile()) {
+                    try (PrintWriter writer = new PrintWriter(file)) {
+                        if (t != null) {
+                            writer.append('\n').append(t.toString());
+                        }
+                        writer.append('\n').append(Debug.getCallers(10));
+                        if (storage != null) {
+                            writer.append("\nfiles: " + Arrays.toString(storage.listFiles()));
+                        } else {
+                            writer.append("\nfiles: none");
+                        }
+                    }
+                }
+            } catch (IOException e) {
+                /* ignore */
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
new file mode 100644
index 0000000..27edbbf
--- /dev/null
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.attention;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.attention.AttentionManagerInternal;
+import android.attention.AttentionManagerInternal.AttentionCallbackInternal;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.service.attention.AttentionService;
+import android.service.attention.AttentionService.AttentionFailureCodes;
+import android.service.attention.IAttentionCallback;
+import android.service.attention.IAttentionService;
+import android.text.TextUtils;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.StatsLog;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+import com.android.server.SystemService;
+
+import java.io.PrintWriter;
+
+/**
+ * An attention service implementation that runs in System Server process.
+ * This service publishes a LocalService and reroutes calls to a {@link AttentionService} that it
+ * manages.
+ */
+public class AttentionManagerService extends SystemService {
+    private static final String LOG_TAG = "AttentionManagerService";
+
+    /** Service will unbind if connection is not used for that amount of time. */
+    private static final long CONNECTION_TTL_MILLIS = 60_000;
+
+    /** If the check attention called within that period - cached value will be returned. */
+    private static final long STALE_AFTER_MILLIS = 5_000;
+
+    private final Context mContext;
+    private final PowerManager mPowerManager;
+    private final Object mLock;
+    @GuardedBy("mLock")
+    private final SparseArray<UserState> mUserStates = new SparseArray<>();
+    private final AttentionHandler mAttentionHandler;
+
+    private ComponentName mComponentName;
+
+    public AttentionManagerService(Context context) {
+        super(context);
+        mContext = Preconditions.checkNotNull(context);
+        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mLock = new Object();
+        mAttentionHandler = new AttentionHandler();
+    }
+
+    @Override
+    public void onStart() {
+        publishLocalService(AttentionManagerInternal.class, new LocalService());
+    }
+
+    @Override
+    public void onSwitchUser(int userId) {
+        cancelAndUnbindLocked(peekUserStateLocked(userId),
+                AttentionService.ATTENTION_FAILURE_UNKNOWN);
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        super.onBootPhase(phase);
+        if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+            mComponentName = resolveAttentionService(mContext);
+            if (mComponentName != null) {
+                // If the service is supported we want to keep receiving the screen off events.
+                mContext.registerReceiver(new ScreenStateReceiver(),
+                        new IntentFilter(Intent.ACTION_SCREEN_OFF));
+            }
+        }
+    }
+
+    /**
+     * Returns {@code true} if attention service is supported on this device.
+     */
+    public boolean isAttentionServiceSupported() {
+        return mComponentName != null;
+    }
+
+    /**
+     * Checks whether user attention is at the screen and calls in the provided callback.
+     *
+     * @return {@code true} if the framework was able to send the provided callback to the service
+     */
+    public boolean checkAttention(int requestCode, long timeout,
+            AttentionCallbackInternal callback) {
+        Preconditions.checkNotNull(callback);
+
+        if (!isAttentionServiceSupported()) {
+            Slog.w(LOG_TAG, "Trying to call checkAttention() on an unsupported device.");
+            return false;
+        }
+
+        // don't allow attention check in screen off state
+        if (!mPowerManager.isInteractive()) {
+            return false;
+        }
+
+        synchronized (mLock) {
+            unbindAfterTimeoutLocked();
+
+            final UserState userState = getOrCreateCurrentUserStateLocked();
+            // lazily start the service, which should be very lightweight to start
+            if (!userState.bindLocked()) {
+                return false;
+            }
+
+            if (userState.mService == null) {
+                // make sure every callback is called back
+                if (userState.mPendingAttentionCheck != null) {
+                    userState.mPendingAttentionCheck.cancel(
+                            AttentionService.ATTENTION_FAILURE_UNKNOWN);
+                }
+                userState.mPendingAttentionCheck = new PendingAttentionCheck(requestCode,
+                        callback, () -> checkAttention(requestCode, timeout, callback));
+            } else {
+                try {
+                    // throttle frequent requests
+                    final AttentionCheckCache attentionCheckCache = userState.mAttentionCheckCache;
+                    if (attentionCheckCache != null && SystemClock.uptimeMillis()
+                            < attentionCheckCache.mLastComputed + STALE_AFTER_MILLIS) {
+                        callback.onSuccess(requestCode, attentionCheckCache.mResult,
+                                attentionCheckCache.mTimestamp);
+                        return true;
+                    }
+
+                    cancelAfterTimeoutLocked(timeout);
+
+                    userState.mCurrentAttentionCheckRequestCode = requestCode;
+                    userState.mService.checkAttention(requestCode, new IAttentionCallback.Stub() {
+                        @Override
+                        public void onSuccess(int requestCode, int result, long timestamp) {
+                            callback.onSuccess(requestCode, result, timestamp);
+                            userState.mAttentionCheckCache = new AttentionCheckCache(
+                                    SystemClock.uptimeMillis(), result,
+                                    timestamp);
+
+                            StatsLog.write(StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
+                                    result);
+                        }
+
+                        @Override
+                        public void onFailure(int requestCode, int error) {
+                            callback.onFailure(requestCode, error);
+                            StatsLog.write(StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
+                                    error);
+                        }
+
+                        @Override
+                        public IBinder asBinder() {
+                            return null;
+                        }
+                    });
+                } catch (RemoteException e) {
+                    Slog.e(LOG_TAG, "Cannot call into the AttentionService");
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    /** Cancels the specified attention check. */
+    public void cancelAttentionCheck(int requestCode) {
+        synchronized (mLock) {
+            final UserState userState = getOrCreateCurrentUserStateLocked();
+            if (userState.mService == null) {
+                if (userState.mPendingAttentionCheck != null
+                        && userState.mPendingAttentionCheck.mRequestCode == requestCode) {
+                    userState.mPendingAttentionCheck = null;
+                }
+                return;
+            }
+            try {
+                userState.mService.cancelAttentionCheck(requestCode);
+            } catch (RemoteException e) {
+                Slog.e(LOG_TAG, "Cannot call into the AttentionService");
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void unbindAfterTimeoutLocked() {
+        mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.CONNECTION_EXPIRED,
+                CONNECTION_TTL_MILLIS);
+    }
+
+    @GuardedBy("mLock")
+    private void cancelAfterTimeoutLocked(long timeout) {
+        mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.ATTENTION_CHECK_TIMEOUT,
+                timeout);
+    }
+
+
+    @GuardedBy("mLock")
+    private UserState getOrCreateCurrentUserStateLocked() {
+        return getOrCreateUserStateLocked(ActivityManager.getCurrentUser());
+    }
+
+    @GuardedBy("mLock")
+    private UserState getOrCreateUserStateLocked(int userId) {
+        UserState result = mUserStates.get(userId);
+        if (result == null) {
+            result = new UserState(userId, mContext, mLock);
+            mUserStates.put(userId, result);
+        }
+        return result;
+    }
+
+    @GuardedBy("mLock")
+    UserState peekCurrentUserStateLocked() {
+        return peekUserStateLocked(ActivityManager.getCurrentUser());
+    }
+
+    @GuardedBy("mLock")
+    UserState peekUserStateLocked(int userId) {
+        return mUserStates.get(userId);
+    }
+
+    /**
+     * Provides attention service component name at runtime, making sure it's provided by the
+     * system.
+     */
+    private static ComponentName resolveAttentionService(Context context) {
+        // TODO(b/111939367): add a flag to turn on/off.
+        final String componentNameString = context.getString(
+                R.string.config_defaultAttentionService);
+
+        if (TextUtils.isEmpty(componentNameString)) {
+            return null;
+        }
+
+        final ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
+        if (componentName == null) {
+            return null;
+        }
+
+        final Intent intent = new Intent(AttentionService.SERVICE_INTERFACE).setPackage(
+                componentName.getPackageName());
+
+        // Make sure that only system apps can declare the AttentionService.
+        final ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent,
+                PackageManager.MATCH_SYSTEM_ONLY);
+        if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+            Slog.wtf(LOG_TAG, String.format("Service %s not found in package %s",
+                    AttentionService.SERVICE_INTERFACE, componentName
+            ));
+            return null;
+        }
+
+        final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+        final String permission = serviceInfo.permission;
+        if (Manifest.permission.BIND_ATTENTION_SERVICE.equals(permission)) {
+            return serviceInfo.getComponentName();
+        }
+        Slog.e(LOG_TAG, String.format(
+                "Service %s should require %s permission. Found %s permission",
+                serviceInfo.getComponentName(),
+                Manifest.permission.BIND_ATTENTION_SERVICE,
+                serviceInfo.permission));
+        return null;
+    }
+
+    private void dumpInternal(PrintWriter pw) {
+        if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
+        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+        ipw.println("Attention Manager Service (dumpsys attention)\n");
+
+        ipw.printPair("context", mContext);
+        pw.println();
+        synchronized (mLock) {
+            int size = mUserStates.size();
+            ipw.print("Number user states: ");
+            pw.println(size);
+            if (size > 0) {
+                ipw.increaseIndent();
+                for (int i = 0; i < size; i++) {
+                    UserState userState = mUserStates.valueAt(i);
+                    ipw.print(i);
+                    ipw.print(":");
+                    userState.dump(ipw);
+                    ipw.println();
+                }
+                ipw.decreaseIndent();
+            }
+        }
+    }
+
+    private final class LocalService extends AttentionManagerInternal {
+        @Override
+        public boolean isAttentionServiceSupported() {
+            return AttentionManagerService.this.isAttentionServiceSupported();
+        }
+
+        @Override
+        public boolean checkAttention(int requestCode, long timeout,
+                AttentionCallbackInternal callback) {
+            return AttentionManagerService.this.checkAttention(requestCode, timeout, callback);
+        }
+
+        @Override
+        public void cancelAttentionCheck(int requestCode) {
+            AttentionManagerService.this.cancelAttentionCheck(requestCode);
+        }
+    }
+
+    private static final class AttentionCheckCache {
+        private final long mLastComputed;
+        private final int mResult;
+        private final long mTimestamp;
+
+        AttentionCheckCache(long lastComputed, @AttentionService.AttentionSuccessCodes int result,
+                long timestamp) {
+            mLastComputed = lastComputed;
+            mResult = result;
+            mTimestamp = timestamp;
+        }
+    }
+
+    private static final class PendingAttentionCheck {
+        private final int mRequestCode;
+        private final AttentionCallbackInternal mCallback;
+        private final Runnable mRunnable;
+
+        PendingAttentionCheck(int requestCode, AttentionCallbackInternal callback,
+                Runnable runnable) {
+            mRequestCode = requestCode;
+            mCallback = callback;
+            mRunnable = runnable;
+        }
+
+        void cancel(@AttentionFailureCodes int failureCode) {
+            mCallback.onFailure(mRequestCode, failureCode);
+        }
+
+        void run() {
+            mRunnable.run();
+        }
+    }
+
+    private static final class UserState {
+        final AttentionServiceConnection mConnection = new AttentionServiceConnection();
+
+        @GuardedBy("mLock")
+        IAttentionService mService;
+        @GuardedBy("mLock")
+        boolean mBinding;
+        @GuardedBy("mLock")
+        int mCurrentAttentionCheckRequestCode;
+        @GuardedBy("mLock")
+        PendingAttentionCheck mPendingAttentionCheck;
+
+        @GuardedBy("mLock")
+        AttentionCheckCache mAttentionCheckCache;
+
+        @UserIdInt
+        final int mUserId;
+        final Context mContext;
+        final Object mLock;
+
+        private UserState(int userId, Context context, Object lock) {
+            mUserId = userId;
+            mContext = Preconditions.checkNotNull(context);
+            mLock = Preconditions.checkNotNull(lock);
+        }
+
+
+        @GuardedBy("mLock")
+        private void handlePendingCallbackLocked() {
+            if (mService != null && mPendingAttentionCheck != null) {
+                mPendingAttentionCheck.run();
+                mPendingAttentionCheck = null;
+            }
+        }
+
+        /** Binds to the system's AttentionService which provides an actual implementation. */
+        @GuardedBy("mLock")
+        private boolean bindLocked() {
+            // No need to bind if service is binding or has already been bound.
+            if (mBinding || mService != null) {
+                return true;
+            }
+
+            final boolean willBind;
+            final long identity = Binder.clearCallingIdentity();
+
+            try {
+                final ComponentName componentName =
+                        resolveAttentionService(mContext);
+                if (componentName == null) {
+                    // Might happen if the storage is encrypted and the user is not unlocked
+                    return false;
+                }
+                final Intent mServiceIntent = new Intent(
+                        AttentionService.SERVICE_INTERFACE).setComponent(
+                        componentName);
+                willBind = mContext.bindServiceAsUser(mServiceIntent, mConnection,
+                        Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
+                mBinding = willBind;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+            return willBind;
+        }
+
+        private void dump(IndentingPrintWriter pw) {
+            pw.printPair("context", mContext);
+            pw.printPair("userId", mUserId);
+            synchronized (mLock) {
+                pw.printPair("binding", mBinding);
+                pw.printPair("isAttentionCheckPending", mPendingAttentionCheck != null);
+            }
+        }
+
+        private final class AttentionServiceConnection implements ServiceConnection {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                init(IAttentionService.Stub.asInterface(service));
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                cleanupService();
+            }
+
+            @Override
+            public void onBindingDied(ComponentName name) {
+                cleanupService();
+            }
+
+            @Override
+            public void onNullBinding(ComponentName name) {
+                cleanupService();
+            }
+
+            void cleanupService() {
+                init(null);
+            }
+
+            private void init(@Nullable IAttentionService service) {
+                synchronized (mLock) {
+                    mService = service;
+                    mBinding = false;
+                    handlePendingCallbackLocked();
+                }
+            }
+        }
+    }
+
+    private class AttentionHandler extends Handler {
+        private static final int CONNECTION_EXPIRED = 1;
+        private static final int ATTENTION_CHECK_TIMEOUT = 2;
+
+        AttentionHandler() {
+            super(Looper.myLooper());
+        }
+
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                // Do not occupy resources when not in use - unbind proactively.
+                case CONNECTION_EXPIRED: {
+                    for (int i = 0; i < mUserStates.size(); i++) {
+                        cancelAndUnbindLocked(mUserStates.valueAt(i),
+                                AttentionService.ATTENTION_FAILURE_UNKNOWN);
+                    }
+
+                }
+                break;
+
+                // Callee is no longer interested in the attention check result - cancel.
+                case ATTENTION_CHECK_TIMEOUT: {
+                    cancelAndUnbindLocked(peekCurrentUserStateLocked(),
+                            AttentionService.ATTENTION_FAILURE_TIMED_OUT);
+                }
+                break;
+
+                default:
+                    break;
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void cancelAndUnbindLocked(UserState userState,
+            @AttentionFailureCodes int failureCode) {
+        synchronized (mLock) {
+            if (userState != null && userState.mService != null) {
+                try {
+                    userState.mService.cancelAttentionCheck(
+                            userState.mCurrentAttentionCheckRequestCode);
+                } catch (RemoteException e) {
+                    Slog.e(LOG_TAG, "Unable to cancel attention check");
+                }
+
+                if (userState.mPendingAttentionCheck != null) {
+                    userState.mPendingAttentionCheck.cancel(failureCode);
+                }
+                mContext.unbindService(userState.mConnection);
+                userState.mConnection.cleanupService();
+                mUserStates.remove(userState.mUserId);
+            }
+        }
+    }
+
+    /**
+     * Unbinds and stops the service when the screen off intent is received.
+     * Attention service only makes sense when screen is ON; disconnect and stop service otherwise.
+     */
+    private final class ScreenStateReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
+                cancelAndUnbindLocked(peekCurrentUserStateLocked(),
+                        AttentionService.ATTENTION_FAILURE_UNKNOWN);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d704a3e..de389bc 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -38,6 +38,8 @@
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothCodecStatus;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHearingAid;
@@ -268,6 +270,7 @@
     private static final int MSG_DISABLE_AUDIO_FOR_UID = 104;
     private static final int MSG_SET_HEARING_AID_CONNECTION_STATE = 105;
     private static final int MSG_BTA2DP_DOCK_TIMEOUT = 106;
+    private static final int MSG_A2DP_ACTIVE_DEVICE_CHANGE = 107;
     // end of messages handled under wakelock
 
     private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -480,16 +483,20 @@
         int mDeviceType;
         String mDeviceName;
         String mDeviceAddress;
+        int mDeviceCodecFormat;
 
-        public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
+        DeviceListSpec(int deviceType, String deviceName, String deviceAddress,
+                int deviceCodecFormat) {
             mDeviceType = deviceType;
             mDeviceName = deviceName;
             mDeviceAddress = deviceAddress;
+            mDeviceCodecFormat = deviceCodecFormat;
         }
 
         public String toString() {
             return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
-                    + " address:" + mDeviceAddress + "]";
+                    + " address:" + mDeviceAddress
+                    + " codec: " + Integer.toHexString(mDeviceCodecFormat) + "]";
         }
     }
 
@@ -501,6 +508,52 @@
 
     private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
 
+    private class BluetoothA2dpDeviceInfo {
+        BluetoothDevice mBtDevice;
+        int mVolume;
+        int mCodec;
+
+        BluetoothA2dpDeviceInfo(BluetoothDevice btDevice) {
+            this(btDevice, -1, AudioSystem.AUDIO_FORMAT_DEFAULT);
+        }
+
+        BluetoothA2dpDeviceInfo(BluetoothDevice btDevice,
+                     int volume, int codec) {
+            mBtDevice = btDevice;
+            mVolume = volume;
+            mCodec = codec;
+        }
+
+        public BluetoothDevice getBtDevice() {
+            return mBtDevice;
+        }
+
+        public int getVolume() {
+            return mVolume;
+        }
+
+        public int getCodec() {
+            return mCodec;
+        }
+    }
+
+    private int mapBluetoothCodecToAudioFormat(int btCodecType) {
+        switch (btCodecType) {
+            case BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC:
+                return AudioSystem.AUDIO_FORMAT_SBC;
+            case BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC:
+                return AudioSystem.AUDIO_FORMAT_AAC;
+            case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX:
+                return AudioSystem.AUDIO_FORMAT_APTX;
+            case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD:
+                return AudioSystem.AUDIO_FORMAT_APTX_HD;
+            case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC:
+                return AudioSystem.AUDIO_FORMAT_LDAC;
+            default:
+                return AudioSystem.AUDIO_FORMAT_DEFAULT;
+        }
+    }
+
     // Forced device usage for communications
     private int mForcedUseForComm;
     private int mForcedUseForCommExt; // External state returned by getters: always consistent
@@ -1020,7 +1073,8 @@
                                                 spec.mDeviceType,
                                                 AudioSystem.DEVICE_STATE_AVAILABLE,
                                                 spec.mDeviceAddress,
-                                                spec.mDeviceName);
+                                                spec.mDeviceName,
+                                                spec.mDeviceCodecFormat);
             }
         }
         // Restore call state
@@ -1169,11 +1223,13 @@
 
     private void checkMuteAffectedStreams() {
         // any stream with a min level > 0 is not muteable by definition
-        // STREAM_VOICE_CALL can be muted by applications that has the the MODIFY_PHONE_STATE permission.
+        // STREAM_VOICE_CALL and STREAM_BLUETOOTH_SCO can be muted by applications
+        // that has the the MODIFY_PHONE_STATE permission.
         for (int i = 0; i < mStreamStates.length; i++) {
             final VolumeStreamState vss = mStreamStates[i];
             if (vss.mIndexMin > 0 &&
-                vss.mStreamType != AudioSystem.STREAM_VOICE_CALL) {
+                (vss.mStreamType != AudioSystem.STREAM_VOICE_CALL &&
+                vss.mStreamType != AudioSystem.STREAM_BLUETOOTH_SCO)) {
                 mMuteAffectedStreams &= ~(1 << vss.mStreamType);
             }
         }
@@ -1614,7 +1670,9 @@
 
         // For notifications/ring, show the ui before making any adjustments
         // Don't suppress mute/unmute requests
-        if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
+        // Don't suppress adjustments for single volume device
+        if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)
+                && !mIsSingleVolume) {
             direction = 0;
             flags &= ~AudioManager.FLAG_PLAY_SOUND;
             flags &= ~AudioManager.FLAG_VIBRATE;
@@ -1655,10 +1713,11 @@
             return;
         }
 
-        // If adjust is mute and the stream is STREAM_VOICE_CALL, make sure
+        // If adjust is mute and the stream is STREAM_VOICE_CALL or STREAM_BLUETOOTH_SCO, make sure
         // that the calling app have the MODIFY_PHONE_STATE permission.
         if (isMuteAdjust &&
-            streamType == AudioSystem.STREAM_VOICE_CALL &&
+            (streamType == AudioSystem.STREAM_VOICE_CALL ||
+                streamType == AudioSystem.STREAM_BLUETOOTH_SCO) &&
             mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.MODIFY_PHONE_STATE)
                     != PackageManager.PERMISSION_GRANTED) {
@@ -1982,12 +2041,14 @@
                     + " CHANGE_ACCESSIBILITY_VOLUME  callingPackage=" + callingPackage);
             return;
         }
-        if ((streamType == AudioManager.STREAM_VOICE_CALL) &&
+        if ((streamType == AudioManager.STREAM_VOICE_CALL ||
+                streamType == AudioManager.STREAM_BLUETOOTH_SCO) &&
                 (index == 0) &&
                 (mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.MODIFY_PHONE_STATE)
                     != PackageManager.PERMISSION_GRANTED)) {
-            Log.w(TAG, "Trying to call setStreamVolume() for STREAM_VOICE_CALL and index 0 without"
+            Log.w(TAG, "Trying to call setStreamVolume() for STREAM_VOICE_CALL or"
+                    + " STREAM_BLUETOOTH_SCO and index 0 without"
                     + " MODIFY_PHONE_STATE  callingPackage=" + callingPackage);
             return;
         }
@@ -3904,8 +3965,8 @@
                             queueMsgUnderWakeLock(mAudioHandler,
                                     MSG_SET_A2DP_SINK_CONNECTION_STATE,
                                     state,
-                                    -1,
-                                    btDevice,
+                                    0 /* arg2 unused */,
+                                    new BluetoothA2dpDeviceInfo(btDevice),
                                     delay);
                         }
                     }
@@ -3922,7 +3983,7 @@
                                 MSG_SET_A2DP_SRC_CONNECTION_STATE,
                                 state,
                                 0 /* arg2 unused */,
-                                btDevice,
+                                new BluetoothA2dpDeviceInfo(btDevice),
                                 0 /* delay */);
                     }
                 }
@@ -4618,6 +4679,7 @@
                 msg == MSG_SET_HEARING_AID_CONNECTION_STATE ||
                 msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
                 msg == MSG_A2DP_DEVICE_CONFIG_CHANGE ||
+                msg == MSG_A2DP_ACTIVE_DEVICE_CHANGE ||
                 msg == MSG_BTA2DP_DOCK_TIMEOUT) {
                 if (mLastDeviceConnectMsgTime >= time) {
                   // add a little delay to make sure messages are ordered as expected
@@ -4687,6 +4749,23 @@
         }
     }
 
+    private int getA2dpCodec(BluetoothDevice device) {
+        synchronized (mA2dpAvrcpLock) {
+            if (mA2dp == null) {
+                return AudioSystem.AUDIO_FORMAT_DEFAULT;
+            }
+            BluetoothCodecStatus btCodecStatus = mA2dp.getCodecStatus(device);
+            if (btCodecStatus == null) {
+                return AudioSystem.AUDIO_FORMAT_DEFAULT;
+            }
+            BluetoothCodecConfig btCodecConfig = btCodecStatus.getCodecConfig();
+            if (btCodecConfig == null) {
+                return AudioSystem.AUDIO_FORMAT_DEFAULT;
+            }
+            return mapBluetoothCodecToAudioFormat(btCodecConfig.getCodecType());
+        }
+    }
+
     /*
      * A class just for packaging up a set of connection parameters.
      */
@@ -4751,14 +4830,16 @@
         return delay;
     }
 
-    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
+    public int setBluetoothA2dpDeviceConnectionState(
+            BluetoothDevice device, int state, int profile)
     {
         return setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
-                device, state, profile, false /* suppressNoisyIntent */, -1 /* a2dpVolume */);
+                device, state, profile, false /* suppressNoisyIntent */,
+                -1 /* a2dpVolume */);
     }
 
     public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device,
-                int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)
+            int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)
     {
         mDeviceLogger.log((new AudioEventLogger.StringEvent(
                 "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent state=" + state
@@ -4771,7 +4852,8 @@
             return 0;
         }
         return setBluetoothA2dpDeviceConnectionStateInt(
-                device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume);
+                device, state, profile, suppressNoisyIntent,
+                AudioSystem.DEVICE_NONE, a2dpVolume);
     }
 
     public int setBluetoothA2dpDeviceConnectionStateInt(
@@ -4791,18 +4873,20 @@
                 delay = 0;
             }
 
+            int a2dpCodec = getA2dpCodec(device);
+
             if (DEBUG_DEVICES) {
                 Log.d(TAG, "setBluetoothA2dpDeviceConnectionStateInt device: " + device
-                      + " state: " + state + " delay(ms): " + delay
-                      + " suppressNoisyIntent: " + suppressNoisyIntent);
+                        + " state: " + state + " delay(ms): " + delay + "codec:" + a2dpCodec
+                        + " suppressNoisyIntent: " + suppressNoisyIntent);
             }
 
             queueMsgUnderWakeLock(mAudioHandler,
                     (profile == BluetoothProfile.A2DP ?
                         MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
                     state,
-                    a2dpVolume,
-                    device,
+                    0, /* arg2 unused */
+                    new BluetoothA2dpDeviceInfo(device, a2dpVolume, a2dpCodec),
                     delay);
         }
         return delay;
@@ -4811,15 +4895,71 @@
     public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)
     {
         synchronized (mConnectedDevices) {
+            int a2dpCodec = getA2dpCodec(device);
             queueMsgUnderWakeLock(mAudioHandler,
                     MSG_A2DP_DEVICE_CONFIG_CHANGE,
                     0 /* arg1 unused */,
-                    0 /* arg1 unused */,
-                    device,
+                    0 /* arg2 unused */,
+                    new BluetoothA2dpDeviceInfo(device, -1, a2dpCodec),
                     0 /* delay */);
         }
     }
 
+    /**
+     * @see AudioManager#handleBluetoothA2dpActiveDeviceChange(BluetoothDevice, int, int,
+     *                                                          boolean, int)
+     */
+    public int handleBluetoothA2dpActiveDeviceChange(
+            BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent,
+            int a2dpVolume) {
+        if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
+            throw new IllegalArgumentException("invalid profile " + profile);
+        }
+
+        synchronized (mConnectedDevices) {
+            if (state == BluetoothA2dp.STATE_CONNECTED) {
+                for (int i = 0; i < mConnectedDevices.size(); i++) {
+                    DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
+                    if (deviceSpec.mDeviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+                        continue;
+                    }
+                    // If A2DP device exists, this is either an active device change or
+                    // device config change
+                    String existingDevicekey = mConnectedDevices.keyAt(i);
+                    String deviceName = device.getName();
+                    String address = device.getAddress();
+                    String newDeviceKey = makeDeviceListKey(
+                            AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
+                    int a2dpCodec = getA2dpCodec(device);
+                    // Device not equal to existing device, active device change
+                    if (!TextUtils.equals(existingDevicekey, newDeviceKey)) {
+                        mConnectedDevices.remove(existingDevicekey);
+                        mConnectedDevices.put(newDeviceKey, new DeviceListSpec(
+                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, deviceName,
+                                address, a2dpCodec));
+                        queueMsgUnderWakeLock(mAudioHandler,
+                                MSG_A2DP_ACTIVE_DEVICE_CHANGE,
+                                0,
+                                0,
+                                new BluetoothA2dpDeviceInfo(
+                                        device, a2dpVolume, a2dpCodec),
+                                0 /* delay */);
+                        return 0;
+                    } else {
+                        // Device config change for existing device
+                        handleBluetoothA2dpDeviceConfigChange(device);
+                        return 0;
+                    }
+                }
+            }
+        }
+
+        // New device connection or a device disconnect
+        return setBluetoothA2dpDeviceConnectionStateInt(
+                    device, state, profile, suppressNoisyIntent,
+                    AudioSystem.DEVICE_NONE, a2dpVolume);
+    }
+
     private static final int DEVICE_MEDIA_UNMUTED_ON_PLUG =
             AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
             AudioSystem.DEVICE_OUT_LINE |
@@ -5697,7 +5837,7 @@
                 case MSG_BTA2DP_DOCK_TIMEOUT:
                     // msg.obj  == address of BTA2DP device
                     synchronized (mConnectedDevices) {
-                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
+                        makeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1);
                     }
                     mAudioEventWakeLock.release();
                     break;
@@ -5722,12 +5862,12 @@
                     break;
 
                 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
-                    onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
+                    onSetA2dpSourceConnectionState((BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
                     mAudioEventWakeLock.release();
                     break;
 
                 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
-                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1, msg.arg2);
+                    onSetA2dpSinkConnectionState((BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
                     mAudioEventWakeLock.release();
                     break;
 
@@ -5737,7 +5877,12 @@
                     break;
 
                 case MSG_A2DP_DEVICE_CONFIG_CHANGE:
-                    onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj);
+                    onBluetoothA2dpDeviceConfigChange((BluetoothA2dpDeviceInfo) msg.obj);
+                    mAudioEventWakeLock.release();
+                    break;
+
+                case MSG_A2DP_ACTIVE_DEVICE_CHANGE:
+                    onBluetoothA2dpActiveDeviceChange((BluetoothA2dpDeviceInfo) msg.obj);
                     mAudioEventWakeLock.release();
                     break;
 
@@ -5911,19 +6056,20 @@
     }
 
     // must be called synchronized on mConnectedDevices
-    private void makeA2dpDeviceAvailable(String address, String name, String eventSource) {
+    private void makeA2dpDeviceAvailable(
+            String address, String name, String eventSource, int a2dpCodec) {
         // enable A2DP before notifying A2DP connection to avoid unnecessary processing in
         // audio policy manager
         VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
         setBluetoothA2dpOnInt(true, eventSource);
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
+                AudioSystem.DEVICE_STATE_AVAILABLE, address, name, a2dpCodec);
         // Reset A2DP suspend state each time a new sink is connected
         AudioSystem.setParameters("A2dpSuspended=false");
         mConnectedDevices.put(
                 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
                 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
-                                   address));
+                                   address, a2dpCodec));
         sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
                 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, null, 0);
         setCurrentAudioRouteNameIfPossible(name);
@@ -5936,7 +6082,7 @@
     }
 
     // must be called synchronized on mConnectedDevices
-    private void makeA2dpDeviceUnavailableNow(String address) {
+    private void makeA2dpDeviceUnavailableNow(String address, int a2dpCodec) {
         if (address == null) {
             return;
         }
@@ -5944,7 +6090,7 @@
             mAvrcpAbsVolSupported = false;
         }
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "", a2dpCodec);
         mConnectedDevices.remove(
                 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
         // Remove A2DP routes as well
@@ -5959,32 +6105,38 @@
         // prevent any activity on the A2DP audio output to avoid unwanted
         // reconnection of the sink.
         AudioSystem.setParameters("A2dpSuspended=true");
+        // Retrieve deviceSpec before removing device
+        String deviceKey = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
+        DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
+        int a2dpCodec = deviceSpec != null ? deviceSpec.mDeviceCodecFormat :
+                                AudioSystem.AUDIO_FORMAT_DEFAULT;
         // the device will be made unavailable later, so consider it disconnected right away
-        mConnectedDevices.remove(
-                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
+        mConnectedDevices.remove(deviceKey);
         // send the delayed message to make the device unavailable later
         queueMsgUnderWakeLock(mAudioHandler,
-            MSG_BTA2DP_DOCK_TIMEOUT,
-            0,
-            0,
-            address,
-            delayMs);
+                MSG_BTA2DP_DOCK_TIMEOUT,
+                a2dpCodec,
+                0,
+                address,
+                delayMs);
     }
 
     // must be called synchronized on mConnectedDevices
     private void makeA2dpSrcAvailable(String address) {
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE, address, "");
+                AudioSystem.DEVICE_STATE_AVAILABLE, address, "",
+                AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.put(
                 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
                 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
-                                   address));
+                                   address, AudioSystem.AUDIO_FORMAT_DEFAULT));
     }
 
     // must be called synchronized on mConnectedDevices
     private void makeA2dpSrcUnavailable(String address) {
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "",
+                AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.remove(
                 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
     }
@@ -6008,11 +6160,12 @@
         setHearingAidVolume(index, AudioSystem.STREAM_MUSIC);
 
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
-                AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
+                AudioSystem.DEVICE_STATE_AVAILABLE, address, name,
+                AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.put(
                 makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
                 new DeviceListSpec(AudioSystem.DEVICE_OUT_HEARING_AID, name,
-                                   address));
+                                   address, AudioSystem.AUDIO_FORMAT_DEFAULT));
         sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
                 AudioSystem.DEVICE_OUT_HEARING_AID, 0, null, 0);
         sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
@@ -6024,7 +6177,8 @@
     // must be called synchronized on mConnectedDevices
     private void makeHearingAidDeviceUnavailable(String address) {
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "",
+                AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.remove(
                 makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
         // Remove Hearing Aid routes as well
@@ -6041,15 +6195,23 @@
         return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
     }
 
-    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state, int a2dpVolume)
+    private void onSetA2dpSinkConnectionState(BluetoothA2dpDeviceInfo btInfo, int state)
     {
-        if (DEBUG_DEVICES) {
-            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice= " + btDevice+" state= " + state
-                + " is dock: "+btDevice.isBluetoothDock());
+        if (btInfo == null) {
+            return;
         }
+
+        BluetoothDevice btDevice = btInfo.getBtDevice();
+        int a2dpVolume = btInfo.getVolume();
+        int a2dpCodec = btInfo.getCodec();
+
         if (btDevice == null) {
             return;
         }
+        if (DEBUG_DEVICES) {
+            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice= " + btDevice + " state= " + state
+                    + " is dock: " + btDevice.isBluetoothDock());
+        }
         String address = btDevice.getAddress();
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             address = "";
@@ -6071,7 +6233,7 @@
                         // the next time isConnected is evaluated, it will be false for the dock
                     }
                 } else {
-                    makeA2dpDeviceUnavailableNow(address);
+                    makeA2dpDeviceUnavailableNow(address, deviceSpec.mDeviceCodecFormat);
                 }
             } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
                 if (btDevice.isBluetoothDock()) {
@@ -6083,7 +6245,8 @@
                     // a dock: cancel the dock timeout, and make the dock unavailable now
                     if (hasScheduledA2dpDockTimeout() && mDockAddress != null) {
                         cancelA2dpDeviceTimeout();
-                        makeA2dpDeviceUnavailableNow(mDockAddress);
+                        makeA2dpDeviceUnavailableNow(mDockAddress,
+                                AudioSystem.AUDIO_FORMAT_DEFAULT);
                     }
                 }
                 if (a2dpVolume != -1) {
@@ -6095,13 +6258,18 @@
                     setDeviceVolume(streamState, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
                 }
                 makeA2dpDeviceAvailable(address, btDevice.getName(),
-                        "onSetA2dpSinkConnectionState");
+                        "onSetA2dpSinkConnectionState", a2dpCodec);
             }
         }
     }
 
-    private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
+    private void onSetA2dpSourceConnectionState(BluetoothA2dpDeviceInfo btInfo, int state)
     {
+        if (btInfo == null) {
+            return;
+        }
+        BluetoothDevice btDevice = btInfo.getBtDevice();
+
         if (DEBUG_VOL) {
             Log.d(TAG, "onSetA2dpSourceConnectionState btDevice=" + btDevice + " state=" + state);
         }
@@ -6176,14 +6344,20 @@
         return false;
     }
 
-    private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
+    private void onBluetoothA2dpDeviceConfigChange(BluetoothA2dpDeviceInfo btInfo)
     {
-        if (DEBUG_DEVICES) {
-            Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
+        if (btInfo == null) {
+            return;
         }
+        BluetoothDevice btDevice = btInfo.getBtDevice();
+        int a2dpCodec = btInfo.getCodec();
+
         if (btDevice == null) {
             return;
         }
+        if (DEBUG_DEVICES) {
+            Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
+        }
         String address = btDevice.getAddress();
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             address = "";
@@ -6200,17 +6374,84 @@
             }
             final String key = makeDeviceListKey(device, address);
             final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
-            if (deviceSpec != null) {
-                // Device is connected
-               int musicDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
-               if (AudioSystem.handleDeviceConfigChange(device, address,
-                        btDevice.getName()) != AudioSystem.AUDIO_STATUS_OK) {
-                   // force A2DP device disconnection in case of error so that AudioService state is
-                   // consistent with audio policy manager state
-                   setBluetoothA2dpDeviceConnectionStateInt(
-                           btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
-                           false /* suppressNoisyIntent */, musicDevice, -1 /* a2dpVolume */);
-               }
+            if (deviceSpec == null) {
+                return;
+            }
+            // Device is connected
+            if (deviceSpec.mDeviceCodecFormat != a2dpCodec) {
+                deviceSpec.mDeviceCodecFormat = a2dpCodec;
+                mConnectedDevices.replace(key, deviceSpec);
+            }
+            if (DEBUG_DEVICES) {
+                Log.d(TAG, "onBluetoothA2dpDeviceConfigChange: codec="
+                        + deviceSpec.mDeviceCodecFormat);
+            }
+            if (AudioSystem.handleDeviceConfigChange(device, address,
+                       btDevice.getName(), deviceSpec.mDeviceCodecFormat)
+                       != AudioSystem.AUDIO_STATUS_OK) {
+                int musicDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
+                // force A2DP device disconnection in case of error so that AudioService state is
+                // consistent with audio policy manager state
+                setBluetoothA2dpDeviceConnectionStateInt(
+                        btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
+                        false /* suppressNoisyIntent */, musicDevice, -1 /* a2dpVolume */);
+            }
+        }
+    }
+
+    /** message handler for MSG_A2DP_ACTIVE_DEVICE_CHANGE */
+    public void onBluetoothA2dpActiveDeviceChange(BluetoothA2dpDeviceInfo btInfo) {
+        if (btInfo == null) {
+            return;
+        }
+        BluetoothDevice btDevice = btInfo.getBtDevice();
+        int a2dpVolume = btInfo.getVolume();
+        int a2dpCodec = btInfo.getCodec();
+
+        if (btDevice == null) {
+            return;
+        }
+        if (DEBUG_DEVICES) {
+            Log.d(TAG, "onBluetoothA2dpActiveDeviceChange btDevice=" + btDevice);
+        }
+        String address = btDevice.getAddress();
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+            address = "";
+        }
+        mDeviceLogger.log(new AudioEventLogger.StringEvent(
+                "onBluetoothA2dpActiveDeviceChange addr=" + address));
+
+        int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
+        synchronized (mConnectedDevices) {
+            if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, btDevice)) {
+                mDeviceLogger.log(new AudioEventLogger.StringEvent(
+                        "A2dp config change ignored"));
+                return;
+            }
+            final String key = makeDeviceListKey(device, address);
+            final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+            if (deviceSpec == null) {
+                return;
+            }
+
+            // Device is connected
+            if (a2dpVolume != -1) {
+                VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+                // Convert index to internal representation in VolumeStreamState
+                a2dpVolume = a2dpVolume * 10;
+                streamState.setIndex(a2dpVolume, device,
+                        "onBluetoothA2dpActiveDeviceChange");
+                setDeviceVolume(streamState, device);
+            }
+
+            if (AudioSystem.handleDeviceConfigChange(device, address,
+                    btDevice.getName(), a2dpCodec) != AudioSystem.AUDIO_STATUS_OK) {
+                int musicDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
+                // force A2DP device disconnection in case of error so that AudioService state is
+                // consistent with audio policy manager state
+                setBluetoothA2dpDeviceConnectionStateInt(
+                        btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
+                        false /* suppressNoisyIntent */, musicDevice, -1 /* a2dpVolume */);
             }
         }
     }
@@ -6243,19 +6484,22 @@
             }
             if (connect && !isConnected) {
                 final int res = AudioSystem.setDeviceConnectionState(device,
-                        AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
+                        AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName,
+                        AudioSystem.AUDIO_FORMAT_DEFAULT);
                 if (res != AudioSystem.AUDIO_STATUS_OK) {
                     Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
                             " due to command error " + res );
                     return false;
                 }
-                mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
+                mConnectedDevices.put(deviceKey, new DeviceListSpec(device,
+                                deviceName, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
                 sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
                         device, 0, null, 0);
                 return true;
             } else if (!connect && isConnected) {
                 AudioSystem.setDeviceConnectionState(device,
-                        AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
+                        AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName,
+                        AudioSystem.AUDIO_FORMAT_DEFAULT);
                 // always remove even if disconnection failed
                 mConnectedDevices.remove(deviceKey);
                 return true;
@@ -7824,8 +8068,10 @@
 
     /** see AudioPolicy.setUidDeviceAffinity() */
     public int setUidDeviceAffinity(IAudioPolicyCallback pcb, int uid,
-            @NonNull int[] deviceTypes,
-            @NonNull String[] deviceAddresses) {
+            @NonNull int[] deviceTypes, @NonNull String[] deviceAddresses) {
+        if (DEBUG_AP) {
+            Log.d(TAG, "setUidDeviceAffinity for " + pcb.asBinder() + " uid:" + uid);
+        }
         synchronized (mAudioPolicies) {
             final AudioPolicyProxy app =
                     checkUpdateForPolicy(pcb, "Cannot change device affinity in audio policy");
@@ -7835,21 +8081,23 @@
             if (!app.hasMixRoutedToDevices(deviceTypes, deviceAddresses)) {
                 return AudioManager.ERROR;
             }
+            return app.setUidDeviceAffinities(uid, deviceTypes, deviceAddresses);
         }
-        return AudioManager.SUCCESS;
     }
 
     /** see AudioPolicy.removeUidDeviceAffinity() */
     public int removeUidDeviceAffinity(IAudioPolicyCallback pcb, int uid) {
+        if (DEBUG_AP) {
+            Log.d(TAG, "removeUidDeviceAffinity for " + pcb.asBinder() + " uid:" + uid);
+        }
         synchronized (mAudioPolicies) {
             final AudioPolicyProxy app =
                     checkUpdateForPolicy(pcb, "Cannot remove device affinity in audio policy");
             if (app == null) {
                 return AudioManager.ERROR;
             }
-
+            return app.removeUidDeviceAffinities(uid);
         }
-        return AudioManager.SUCCESS;
     }
 
     public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
@@ -8160,27 +8408,41 @@
             Binder.restoreCallingIdentity(identity);
         }
 
-        void setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
+        int setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
             final Integer Uid = new Integer(uid);
+            int res;
             if (mUidDeviceAffinities.remove(Uid) != null) {
                 final long identity = Binder.clearCallingIdentity();
-                AudioSystem.removeUidDeviceAffinities(uid);
+                res = AudioSystem.removeUidDeviceAffinities(uid);
                 Binder.restoreCallingIdentity(identity);
+                if (res != AudioSystem.SUCCESS) {
+                    Log.e(TAG, "AudioSystem. removeUidDeviceAffinities(" + uid + ") failed, "
+                            + " cannot call AudioSystem.setUidDeviceAffinities");
+                    return AudioManager.ERROR;
+                }
             }
             final long identity = Binder.clearCallingIdentity();
-            final int res = AudioSystem.setUidDeviceAffinities(uid, types, addresses);
+            res = AudioSystem.setUidDeviceAffinities(uid, types, addresses);
             Binder.restoreCallingIdentity(identity);
             if (res == AudioSystem.SUCCESS) {
                 mUidDeviceAffinities.put(Uid, new AudioDeviceArray(types, addresses));
+                return AudioManager.SUCCESS;
             }
+            Log.e(TAG, "AudioSystem. setUidDeviceAffinities(" + uid + ") failed");
+            return AudioManager.ERROR;
         }
 
-        void removeUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
+        int removeUidDeviceAffinities(int uid) {
             if (mUidDeviceAffinities.remove(new Integer(uid)) != null) {
                 final long identity = Binder.clearCallingIdentity();
-                AudioSystem.removeUidDeviceAffinities(uid);
+                final int res = AudioSystem.removeUidDeviceAffinities(uid);
                 Binder.restoreCallingIdentity(identity);
+                if (res == AudioSystem.SUCCESS) {
+                    return AudioManager.SUCCESS;
+                }
             }
+            Log.e(TAG, "AudioSystem. removeUidDeviceAffinities failed");
+            return AudioManager.ERROR;
         }
     };
 
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index 905f826..9d6628c 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -206,7 +206,7 @@
             switch (event) {
             case AudioManager.RECORD_CONFIG_EVENT_STOP:
                 // return failure if an unknown recording session stopped
-                configChanged = (mRecordConfigs.remove(new Integer(session)) != null);
+                configChanged = (mRecordConfigs.remove(new Integer(portId)) != null);
                 if (configChanged) {
                     sEventLogger.log(new RecordingEvent(event, uid, session, source, null));
                 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index a381477..41fedc5 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -132,10 +132,13 @@
                 Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED);
         private final Uri FACE_UNLOCK_APP_ENABLED =
                 Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_APP_ENABLED);
+        private final Uri FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION =
+                Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION);
 
         private final ContentResolver mContentResolver;
         private boolean mFaceEnabledOnKeyguard;
         private boolean mFaceEnabledForApps;
+        private boolean mFaceAlwaysRequireConfirmation;
 
         /**
          * Creates a content observer.
@@ -158,10 +161,15 @@
                     false /* notifyForDescendents */,
                     this /* observer */,
                     UserHandle.USER_CURRENT);
+            mContentResolver.registerContentObserver(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
+                    false /* notifyForDescendents */,
+                    this /* observer */,
+                    UserHandle.USER_CURRENT);
 
             // Update the value immediately
             onChange(true /* selfChange */, FACE_UNLOCK_KEYGUARD_ENABLED);
             onChange(true /* selfChange */, FACE_UNLOCK_APP_ENABLED);
+            onChange(true /* selfChange */, FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION);
         }
 
         @Override
@@ -185,6 +193,13 @@
                                 Settings.Secure.FACE_UNLOCK_APP_ENABLED,
                                 1 /* default */,
                                 UserHandle.USER_CURRENT) != 0;
+            } else if (FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION.equals(uri)) {
+                mFaceAlwaysRequireConfirmation =
+                        Settings.Secure.getIntForUser(
+                                mContentResolver,
+                                Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
+                                0 /* default */,
+                                UserHandle.USER_CURRENT) != 0;
             }
         }
 
@@ -195,6 +210,10 @@
         boolean getFaceEnabledForApps() {
             return mFaceEnabledForApps;
         }
+
+        boolean getFaceAlwaysRequireConfirmation() {
+            return mFaceAlwaysRequireConfirmation;
+        }
     }
 
     private final class EnabledOnKeyguardCallback implements IBinder.DeathRecipient {
@@ -332,10 +351,7 @@
                     if (!runningTasks.isEmpty()) {
                         final String topPackage = runningTasks.get(0).topActivity.getPackageName();
                         if (mCurrentAuthSession != null
-                                && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)
-                                && mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
-                            // We only care about this state, since <Biometric>Service will
-                            // cancel any client that's still in STATE_AUTH_STARTED
+                                && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)) {
                             mStatusBarService.hideBiometricDialog();
                             mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
                             mCurrentAuthSession.mClientReceiver.onError(
@@ -373,6 +389,13 @@
             public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token)
                     throws RemoteException {
                 try {
+                    // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+                    // after user dismissed/canceled dialog).
+                    if (mCurrentAuthSession == null) {
+                        Slog.e(TAG, "onAuthenticationSucceeded(): Auth session is null");
+                        return;
+                    }
+
                     if (!requireConfirmation) {
                         mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
                         KeyStore.getInstance().addAuthToken(token);
@@ -388,7 +411,7 @@
 
                     // Notify SysUI that the biometric has been authenticated. SysUI already knows
                     // the implicit/explicit state and will react accordingly.
-                    mStatusBarService.onBiometricAuthenticated();
+                    mStatusBarService.onBiometricAuthenticated(true);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Remote exception", e);
                 }
@@ -398,17 +421,27 @@
             public void onAuthenticationFailed(int cookie, boolean requireConfirmation)
                     throws RemoteException {
                 try {
-                    mStatusBarService.onBiometricHelp(getContext().getResources().getString(
-                            com.android.internal.R.string.biometric_not_recognized));
-                    if (requireConfirmation) {
+                    // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+                    // after user dismissed/canceled dialog).
+                    if (mCurrentAuthSession == null) {
+                        Slog.e(TAG, "onAuthenticationFailed(): Auth session is null");
+                        return;
+                    }
+
+                    mStatusBarService.onBiometricAuthenticated(false);
+
+                    // TODO: This logic will need to be updated if BP is multi-modal
+                    if ((mCurrentAuthSession.mModality & TYPE_FACE) != 0) {
+                        // Pause authentication. onBiometricAuthenticated(false) causes the
+                        // dialog to show a "try again" button for passive modalities.
                         mCurrentAuthSession.mState = STATE_AUTH_PAUSED;
-                        mStatusBarService.showBiometricTryAgain();
                         // Cancel authentication. Skip the token/package check since we are
                         // cancelling from system server. The interface is permission protected so
                         // this is fine.
                         cancelInternal(null /* token */, null /* package */,
                                 false /* fromClient */);
                     }
+
                     mCurrentAuthSession.mClientReceiver.onAuthenticationFailed();
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Remote exception", e);
@@ -428,8 +461,9 @@
                     if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) {
                         if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
                             mStatusBarService.onBiometricError(message);
-                            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
                             if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
+                                    mActivityTaskManager.unregisterTaskStackListener(
+                                            mTaskStackListener);
                                     mCurrentAuthSession.mClientReceiver.onError(error, message);
                                     mCurrentAuthSession.mState = STATE_AUTH_IDLE;
                                     mCurrentAuthSession = null;
@@ -438,9 +472,14 @@
                                 // Send errors after the dialog is dismissed.
                                 mHandler.postDelayed(() -> {
                                     try {
-                                        mCurrentAuthSession.mClientReceiver.onError(error, message);
-                                        mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                                        mCurrentAuthSession = null;
+                                        if (mCurrentAuthSession != null) {
+                                            mActivityTaskManager.unregisterTaskStackListener(
+                                                    mTaskStackListener);
+                                            mCurrentAuthSession.mClientReceiver.onError(error,
+                                                    message);
+                                            mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                                            mCurrentAuthSession = null;
+                                        }
                                     } catch (RemoteException e) {
                                         Slog.e(TAG, "Remote exception", e);
                                     }
@@ -486,6 +525,13 @@
 
             @Override
             public void onAcquired(int acquiredInfo, String message) throws RemoteException {
+                // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+                // after user dismissed/canceled dialog).
+                if (mCurrentAuthSession == null) {
+                    Slog.e(TAG, "onAcquired(): Auth session is null");
+                    return;
+                }
+
                 if (acquiredInfo != BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
                     try {
                         mStatusBarService.onBiometricHelp(message);
@@ -497,6 +543,11 @@
 
             @Override
             public void onDialogDismissed(int reason) throws RemoteException {
+                if (mCurrentAuthSession == null) {
+                    Slog.e(TAG, "onDialogDismissed: " + reason + ", auth session null");
+                    return;
+                }
+
                 if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) {
                     // Positive button is used by passive modalities as a "confirm" button,
                     // do not send to client
@@ -558,8 +609,10 @@
             }
 
             if (mPendingAuthSession.mModalitiesWaiting.isEmpty()) {
-                final boolean mContinuing = mCurrentAuthSession != null
-                        && mCurrentAuthSession.mState == STATE_AUTH_PAUSED;
+                final boolean continuing = mCurrentAuthSession != null &&
+                        (mCurrentAuthSession.mState == STATE_AUTH_PAUSED
+                                || mCurrentAuthSession.mState == STATE_AUTH_PAUSED_CANCELED);
+
                 mCurrentAuthSession = mPendingAuthSession;
                 mPendingAuthSession = null;
 
@@ -581,7 +634,7 @@
                         modality |= pair.getKey();
                     }
 
-                    if (!mContinuing) {
+                    if (!continuing) {
                         mStatusBarService.showBiometricDialog(mCurrentAuthSession.mBundle,
                                 mInternalReceiver, modality, requireConfirmation, userId);
                         mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
@@ -685,7 +738,8 @@
 
                 mCurrentModality = modality;
 
-                // Actually start authentication
+                // Start preparing for authentication. Authentication starts when
+                // all modalities requested have invoked onReadyForAuthentication.
                 authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle,
                         callingUid, callingPid, callingUserId, modality);
             });
@@ -704,6 +758,9 @@
                 IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
                 int callingUid, int callingPid, int callingUserId, int modality) {
             try {
+                boolean requireConfirmation = bundle.getBoolean(
+                        BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */);
+
                 // Generate random cookies to pass to the services that should prepare to start
                 // authenticating. Store the cookie here and wait for all services to "ack"
                 // with the cookie. Once all cookies are received, we can show the prompt
@@ -727,7 +784,10 @@
                     Slog.w(TAG, "Iris unsupported");
                 }
                 if ((modality & TYPE_FACE) != 0) {
-                    mFaceService.prepareForAuthentication(true /* requireConfirmation */,
+                    // Check if the user has forced confirmation to be required in Settings.
+                    requireConfirmation = requireConfirmation
+                            || mSettingObserver.getFaceAlwaysRequireConfirmation();
+                    mFaceService.prepareForAuthentication(requireConfirmation,
                             token, sessionId, userId, mInternalReceiver, opPackageName,
                             cookie, callingUid, callingPid, callingUserId);
                 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 32219aa..174ecfa 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -116,6 +116,7 @@
     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 int mHALDeathCount;
 
     protected class PerformanceStats {
         public int accept; // number of accepted biometrics
@@ -596,6 +597,7 @@
     public void serviceDied(long cookie) {
         Slog.e(getTag(), "HAL died");
         mMetricsLogger.count(getMetrics().tagHalDied(), 1);
+        mHALDeathCount++;
         handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
                 0 /*vendorCode */);
     }
@@ -819,8 +821,6 @@
 
     // 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();
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 72f73f6..a2aacdd 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -133,10 +133,11 @@
         }
 
         @Override // Binder call
-        public void authenticate(final IBinder token, final long opId,
+        public void authenticate(final IBinder token, final long opId, int userId,
                 final IFaceServiceReceiver receiver, final int flags,
                 final String opPackageName) {
             checkPermission(USE_BIOMETRIC_INTERNAL);
+            updateActiveGroup(userId, opPackageName);
             final boolean restricted = isRestricted();
             final AuthenticationClientImpl client = new FaceAuthClient(getContext(),
                     mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
@@ -156,7 +157,7 @@
                     mDaemonWrapper, mHalDeviceId, token,
                     new BiometricPromptServiceListenerImpl(wrapperReceiver),
                     mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName, cookie,
-                    true /* requireConfirmation */);
+                    requireConfirmation);
             authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
                     callingUserId);
         }
@@ -674,6 +675,12 @@
     }
 
     @Override
+    public void serviceDied(long cookie) {
+        super.serviceDied(cookie);
+        mDaemon = null;
+    }
+
+    @Override
     protected void updateActiveGroup(int userId, String clientPackage) {
         IBiometricsFace daemon = getFaceDaemon();
 
@@ -863,6 +870,8 @@
             Slog.e(TAG, "dump formatting failure", e);
         }
         pw.println(dump);
+        pw.println("HAL Deaths: " + mHALDeathCount);
+        mHALDeathCount = 0;
     }
 
     private void dumpProto(FileDescriptor fd) {
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 3895ef7..3db6a74 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -159,6 +159,7 @@
         public void authenticate(final IBinder token, final long opId, final int groupId,
                 final IFingerprintServiceReceiver receiver, final int flags,
                 final String opPackageName) {
+            updateActiveGroup(groupId, opPackageName);
             final boolean restricted = isRestricted();
             final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
                     mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
@@ -776,6 +777,12 @@
     }
 
     @Override
+    public void serviceDied(long cookie) {
+        super.serviceDied(cookie);
+        mDaemon = null;
+    }
+
+    @Override
     protected void updateActiveGroup(int userId, String clientPackage) {
         IBiometricsFingerprint daemon = getFingerprintDaemon();
 
@@ -1073,6 +1080,8 @@
             Slog.e(TAG, "dump formatting failure", e);
         }
         pw.println(dump);
+        pw.println("HAL Deaths: " + mHALDeathCount);
+        mHALDeathCount = 0;
     }
 
     private void dumpProto(FileDescriptor fd) {
diff --git a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
index 24865bc..6fa98b8 100644
--- a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
+++ b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
@@ -21,22 +21,6 @@
  * @hide
  */
 public class ConnectivityConstants {
-    // IPC constants
-    public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
-            "android.net.conn.NETWORK_CONDITIONS_MEASURED";
-    public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
-    public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
-    public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
-    public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
-    public static final String EXTRA_CELL_ID = "extra_cellid";
-    public static final String EXTRA_SSID = "extra_ssid";
-    public static final String EXTRA_BSSID = "extra_bssid";
-    /** real time since boot */
-    public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
-    public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
-
-    public static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
-            "android.permission.ACCESS_NETWORK_CONDITIONS";
 
     // Penalty applied to scores of Networks that have not been validated.
     public static final int UNVALIDATED_SCORE_PENALTY = 40;
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index b8f057d..d8bb635 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -18,10 +18,9 @@
 
 import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
-import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
 import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES;
+import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
 import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
 import static android.provider.Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
 import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
@@ -35,6 +34,7 @@
 import android.net.Network;
 import android.net.NetworkUtils;
 import android.net.Uri;
+import android.net.shared.PrivateDnsConfig;
 import android.os.Binder;
 import android.os.INetworkManagementService;
 import android.os.UserHandle;
@@ -43,10 +43,7 @@
 import android.util.Pair;
 import android.util.Slog;
 
-import com.android.server.connectivity.MockableSystemProperties;
-
 import java.net.InetAddress;
-import java.net.UnknownHostException;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -54,10 +51,8 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Objects;
-import java.util.stream.Collectors;
 import java.util.Set;
-import java.util.StringJoiner;
+import java.util.stream.Collectors;
 
 
 /**
@@ -123,43 +118,6 @@
     private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
     private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
 
-    public static class PrivateDnsConfig {
-        public final boolean useTls;
-        public final String hostname;
-        public final InetAddress[] ips;
-
-        public PrivateDnsConfig() {
-            this(false);
-        }
-
-        public PrivateDnsConfig(boolean useTls) {
-            this.useTls = useTls;
-            this.hostname = "";
-            this.ips = new InetAddress[0];
-        }
-
-        public PrivateDnsConfig(String hostname, InetAddress[] ips) {
-            this.useTls = !TextUtils.isEmpty(hostname);
-            this.hostname = useTls ? hostname : "";
-            this.ips = (ips != null) ? ips : new InetAddress[0];
-        }
-
-        public PrivateDnsConfig(PrivateDnsConfig cfg) {
-            useTls = cfg.useTls;
-            hostname = cfg.hostname;
-            ips = cfg.ips;
-        }
-
-        public boolean inStrictMode() {
-            return useTls && !TextUtils.isEmpty(hostname);
-        }
-
-        public String toString() {
-            return PrivateDnsConfig.class.getSimpleName() +
-                    "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}";
-        }
-    }
-
     public static PrivateDnsConfig getPrivateDnsConfig(ContentResolver cr) {
         final String mode = getPrivateDnsMode(cr);
 
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index ac74598..79b56c6 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -20,7 +20,6 @@
 import android.net.ConnectivityMetricsEvent;
 import android.net.IIpConnectivityMetrics;
 import android.net.INetdEventCallback;
-import android.net.ip.IpClient;
 import android.net.metrics.ApfProgramEvent;
 import android.net.metrics.IpConnectivityLog;
 import android.os.Binder;
@@ -270,8 +269,6 @@
         // Dump the rolling buffer of metrics event and pretty print events using a human readable
         // format. Also print network dns/connect statistics and default network event time series.
         static final String CMD_LIST = "list";
-        // Dump all IpClient logs ("ipclient").
-        static final String CMD_IPCLIENT = IpClient.DUMP_ARG;
         // By default any other argument will fall into the default case which is the equivalent
         // of calling both the "list" and "ipclient" commands. This includes most notably bug
         // reports collected by dumpsys.cpp with the "-a" argument.
@@ -295,20 +292,9 @@
                 case CMD_PROTO:
                     cmdListAsProto(pw);
                     return;
-                case CMD_IPCLIENT: {
-                    final String[] ipclientArgs = ((args != null) && (args.length > 1))
-                            ? Arrays.copyOfRange(args, 1, args.length)
-                            : null;
-                    IpClient.dumpAllLogs(pw, ipclientArgs);
-                    return;
-                }
                 case CMD_LIST:
-                    cmdList(pw);
-                    return;
                 default:
                     cmdList(pw);
-                    pw.println("");
-                    IpClient.dumpAllLogs(pw, null);
                     return;
             }
         }
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 0f8fc17..1559ba8 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -16,40 +16,49 @@
 
 package com.android.server.connectivity;
 
-import com.android.internal.util.HexDump;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.connectivity.NetworkAgentInfo;
-import android.net.ConnectivityManager;
+// TODO: Clean up imports and remove references of PacketKeepalive constants.
+
+import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_INTERVAL;
+import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS;
+import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK;
+import static android.net.ConnectivityManager.PacketKeepalive.MIN_INTERVAL;
+import static android.net.ConnectivityManager.PacketKeepalive.NATT_PORT;
+import static android.net.ConnectivityManager.PacketKeepalive.NO_KEEPALIVE;
+import static android.net.ConnectivityManager.PacketKeepalive.SUCCESS;
+import static android.net.NetworkAgent.CMD_START_PACKET_KEEPALIVE;
+import static android.net.NetworkAgent.CMD_STOP_PACKET_KEEPALIVE;
+import static android.net.NetworkAgent.EVENT_PACKET_KEEPALIVE;
+import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.net.ConnectivityManager.PacketKeepalive;
 import android.net.KeepalivePacketData;
-import android.net.LinkAddress;
 import android.net.NetworkAgent;
 import android.net.NetworkUtils;
 import android.net.util.IpUtils;
 import android.os.Binder;
-import android.os.IBinder;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.Process;
 import android.os.RemoteException;
-import android.system.OsConstants;
+import android.system.ErrnoException;
+import android.system.Os;
 import android.util.Log;
 import android.util.Pair;
 
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
+import com.android.internal.util.HexDump;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.FileDescriptor;
 import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
 import java.util.ArrayList;
 import java.util.HashMap;
 
-import static android.net.ConnectivityManager.PacketKeepalive.*;
-import static android.net.NetworkAgent.CMD_START_PACKET_KEEPALIVE;
-import static android.net.NetworkAgent.CMD_STOP_PACKET_KEEPALIVE;
-import static android.net.NetworkAgent.EVENT_PACKET_KEEPALIVE;
-
 /**
  * Manages packet keepalive requests.
  *
@@ -185,13 +194,13 @@
         }
 
         void start(int slot) {
+            mSlot = slot;
             int error = isValid();
             if (error == SUCCESS) {
-                mSlot = slot;
                 Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.name());
                 mNai.asyncChannel.sendMessage(CMD_START_PACKET_KEEPALIVE, slot, mInterval, mPacket);
             } else {
-                notifyMessenger(NO_KEEPALIVE, error);
+                handleStopKeepalive(mNai, mSlot, error);
                 return;
             }
         }
@@ -277,6 +286,7 @@
             return;
         }
         ki.stop(reason);
+        Log.d(TAG, "Stopped keepalive " + slot + " on " + networkName);
         networkKeepalives.remove(slot);
         if (networkKeepalives.isEmpty()) {
             mKeepalives.remove(nai);
@@ -299,7 +309,9 @@
         }
     }
 
-    public void handleEventPacketKeepalive(NetworkAgentInfo nai, Message message) {
+    /** Handle keepalive events from lower layer. */
+    public void handleEventPacketKeepalive(@NonNull NetworkAgentInfo nai,
+            @NonNull Message message) {
         int slot = message.arg1;
         int reason = message.arg2;
 
@@ -329,8 +341,18 @@
         }
     }
 
-    public void startNattKeepalive(NetworkAgentInfo nai, int intervalSeconds, Messenger messenger,
-            IBinder binder, String srcAddrString, int srcPort, String dstAddrString, int dstPort) {
+    /**
+     * Called when requesting that keepalives be started on a IPsec NAT-T socket. See
+     * {@link android.net.SocketKeepalive}.
+     **/
+    public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
+            int intervalSeconds,
+            @NonNull Messenger messenger,
+            @NonNull IBinder binder,
+            @NonNull String srcAddrString,
+            int srcPort,
+            @NonNull String dstAddrString,
+            int dstPort) {
         if (nai == null) {
             notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_NETWORK);
             return;
@@ -359,6 +381,56 @@
                 NetworkAgent.CMD_START_PACKET_KEEPALIVE, ki).sendToTarget();
     }
 
+   /**
+    * Called when requesting that keepalives be started on a IPsec NAT-T socket. This function is
+    * identical to {@link #startNattKeepalive}, but also takes a {@code resourceId}, which is the
+    * resource index bound to the {@link UdpEncapsulationSocket} when creating by
+    * {@link com.android.server.IpSecService} to verify whether the given
+    * {@link UdpEncapsulationSocket} is legitimate.
+    **/
+    public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
+            @Nullable FileDescriptor fd,
+            int resourceId,
+            int intervalSeconds,
+            @NonNull Messenger messenger,
+            @NonNull IBinder binder,
+            @NonNull String srcAddrString,
+            @NonNull String dstAddrString,
+            int dstPort) {
+        // Ensure that the socket is created by IpSecService.
+        if (!isNattKeepaliveSocketValid(fd, resourceId)) {
+            notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_SOCKET);
+        }
+
+        // Get src port to adopt old API.
+        int srcPort = 0;
+        try {
+            final SocketAddress srcSockAddr = Os.getsockname(fd);
+            srcPort = ((InetSocketAddress) srcSockAddr).getPort();
+        } catch (ErrnoException e) {
+            notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_SOCKET);
+        }
+
+        // Forward request to old API.
+        startNattKeepalive(nai, intervalSeconds, messenger, binder, srcAddrString, srcPort,
+                dstAddrString, dstPort);
+    }
+
+    /**
+     * Verify if the IPsec NAT-T file descriptor and resource Id hold for IPsec keepalive is valid.
+     **/
+    public static boolean isNattKeepaliveSocketValid(@Nullable FileDescriptor fd, int resourceId) {
+        // TODO: 1. confirm whether the fd is called from system api or created by IpSecService.
+        //       2. If the fd is created from the system api, check that it's bounded. And
+        //          call dup to keep the fd open.
+        //       3. If the fd is created from IpSecService, check if the resource ID is valid. And
+        //          hold the resource needed in IpSecService.
+        if (null == fd) {
+            return false;
+        }
+        return true;
+    }
+
     public void dump(IndentingPrintWriter pw) {
         pw.println("Packet keepalives:");
         pw.increaseIndent();
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 6596d27..9d9b1cf 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -16,8 +16,9 @@
 
 package com.android.server.connectivity;
 
-import android.net.InterfaceConfiguration;
 import android.net.ConnectivityManager;
+import android.net.INetd;
+import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
@@ -59,6 +60,7 @@
         NetworkInfo.State.SUSPENDED,
     };
 
+    private final INetd mNetd;
     private final INetworkManagementService mNMService;
 
     // The network we're running on, and its type.
@@ -76,7 +78,8 @@
     private String mIface;
     private State mState = State.IDLE;
 
-    public Nat464Xlat(INetworkManagementService nmService, NetworkAgentInfo nai) {
+    public Nat464Xlat(NetworkAgentInfo nai, INetd netd, INetworkManagementService nmService) {
+        mNetd = netd;
         mNMService = nmService;
         mNetwork = nai;
     }
@@ -140,7 +143,7 @@
             return;
         }
         try {
-            mNMService.startClatd(baseIface);
+            mNetd.clatdStart(baseIface);
         } catch(RemoteException|IllegalStateException e) {
             Slog.e(TAG, "Error starting clatd on " + baseIface, e);
         }
@@ -162,7 +165,7 @@
      */
     private void enterStoppingState() {
         try {
-            mNMService.stopClatd(mBaseIface);
+            mNetd.clatdStop(mBaseIface);
         } catch(RemoteException|IllegalStateException e) {
             Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
         }
@@ -204,7 +207,7 @@
             Slog.e(TAG, "startClat: Can't start clat on null interface");
             return;
         }
-        // TODO: should we only do this if mNMService.startClatd() succeeds?
+        // TODO: should we only do this if mNetd.clatdStart() succeeds?
         Slog.i(TAG, "Starting clatd on " + baseIface);
         enterStartingState(baseIface);
     }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 262184b..9ea73fb 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -16,9 +16,9 @@
 
 package com.android.server.connectivity;
 
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-
 import android.content.Context;
+import android.net.INetd;
+import android.net.INetworkMonitor;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
@@ -29,7 +29,6 @@
 import android.os.Handler;
 import android.os.INetworkManagementService;
 import android.os.Messenger;
-import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Log;
 import android.util.SparseArray;
@@ -37,11 +36,8 @@
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.WakeupMessage;
 import com.android.server.ConnectivityService;
-import com.android.server.connectivity.NetworkMonitor;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.Objects;
 import java.util.SortedSet;
 import java.util.TreeSet;
@@ -126,7 +122,6 @@
     public LinkProperties linkProperties;
     // This should only be modified via ConnectivityService.updateCapabilities().
     public NetworkCapabilities networkCapabilities;
-    public final NetworkMonitor networkMonitor;
     public final NetworkMisc networkMisc;
     // Indicates if netd has been told to create this Network. From this point on the appropriate
     // routing rules are setup and routes are added so packets can begin flowing over the Network.
@@ -239,15 +234,21 @@
     // Used by ConnectivityService to keep track of 464xlat.
     public Nat464Xlat clatd;
 
+    // Set after asynchronous creation of the NetworkMonitor.
+    private volatile INetworkMonitor mNetworkMonitor;
+
     private static final String TAG = ConnectivityService.class.getSimpleName();
     private static final boolean VDBG = false;
     private final ConnectivityService mConnService;
+    private final INetd mNetd;
+    private final INetworkManagementService mNMS;
     private final Context mContext;
     private final Handler mHandler;
 
     public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
             LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
-            NetworkMisc misc, NetworkRequest defaultRequest, ConnectivityService connService) {
+            NetworkMisc misc, ConnectivityService connService, INetd netd,
+            INetworkManagementService nms) {
         this.messenger = messenger;
         asyncChannel = ac;
         network = net;
@@ -256,12 +257,20 @@
         networkCapabilities = nc;
         currentScore = score;
         mConnService = connService;
+        mNetd = netd;
+        mNMS = nms;
         mContext = context;
         mHandler = handler;
-        networkMonitor = mConnService.createNetworkMonitor(context, handler, this, defaultRequest);
         networkMisc = misc;
     }
 
+    /**
+     * Inform NetworkAgentInfo that a new NetworkMonitor was created.
+     */
+    public void onNetworkMonitorCreated(INetworkMonitor networkMonitor) {
+        mNetworkMonitor = networkMonitor;
+    }
+
     public ConnectivityService connService() {
         return mConnService;
     }
@@ -278,6 +287,15 @@
         return network;
     }
 
+    /**
+     * Get the INetworkMonitor in this NetworkAgentInfo.
+     *
+     * <p>This will be null before {@link #onNetworkMonitorCreated(INetworkMonitor)} is called.
+     */
+    public INetworkMonitor networkMonitor() {
+        return mNetworkMonitor;
+    }
+
     // Functions for manipulating the requests satisfied by this network.
     //
     // These functions must only called on ConnectivityService's main thread.
@@ -575,18 +593,18 @@
 
     public void updateClat(INetworkManagementService netd) {
         if (Nat464Xlat.requiresClat(this)) {
-            maybeStartClat(netd);
+            maybeStartClat();
         } else {
             maybeStopClat();
         }
     }
 
     /** Ensure clat has started for this network. */
-    public void maybeStartClat(INetworkManagementService netd) {
+    public void maybeStartClat() {
         if (clatd != null && clatd.isStarted()) {
             return;
         }
-        clatd = new Nat464Xlat(netd, this);
+        clatd = new Nat464Xlat(this, mNetd, mNMS);
         clatd.start();
     }
 
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
deleted file mode 100644
index 9684f4c..0000000
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ /dev/null
@@ -1,1672 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
-import static android.net.CaptivePortal.APP_RETURN_UNWANTED;
-import static android.net.CaptivePortal.APP_RETURN_WANTED_AS_IS;
-import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC;
-import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL;
-import static android.net.metrics.ValidationProbeEvent.DNS_FAILURE;
-import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS;
-import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK;
-import static android.net.metrics.ValidationProbeEvent.PROBE_PRIVDNS;
-
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.CaptivePortal;
-import android.net.ConnectivityManager;
-import android.net.ICaptivePortal;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.net.ProxyInfo;
-import android.net.TrafficStats;
-import android.net.Uri;
-import android.net.captiveportal.CaptivePortalProbeResult;
-import android.net.captiveportal.CaptivePortalProbeSpec;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.NetworkEvent;
-import android.net.metrics.ValidationProbeEvent;
-import android.net.util.Stopwatch;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.telephony.CellIdentityCdma;
-import android.telephony.CellIdentityGsm;
-import android.telephony.CellIdentityLte;
-import android.telephony.CellIdentityWcdma;
-import android.telephony.CellInfo;
-import android.telephony.CellInfoCdma;
-import android.telephony.CellInfoGsm;
-import android.telephony.CellInfoLte;
-import android.telephony.CellInfoWcdma;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.LocalLog;
-import android.util.LocalLog.ReadOnlyLocalLog;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.Protocol;
-import com.android.internal.util.RingBufferIndices;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-import com.android.server.connectivity.DnsManager.PrivateDnsConfig;
-
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Random;
-import java.util.UUID;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * {@hide}
- */
-public class NetworkMonitor extends StateMachine {
-    private static final String TAG = NetworkMonitor.class.getSimpleName();
-    private static final boolean DBG  = true;
-    private static final boolean VDBG = false;
-    private static final boolean VDBG_STALL = Log.isLoggable(TAG, Log.DEBUG);
-    // Default configuration values for captive portal detection probes.
-    // TODO: append a random length parameter to the default HTTPS url.
-    // TODO: randomize browser version ids in the default User-Agent String.
-    private static final String DEFAULT_HTTPS_URL     = "https://www.google.com/generate_204";
-    private static final String DEFAULT_HTTP_URL      =
-            "http://connectivitycheck.gstatic.com/generate_204";
-    private static final String DEFAULT_FALLBACK_URL  = "http://www.google.com/gen_204";
-    private static final String DEFAULT_OTHER_FALLBACK_URLS =
-            "http://play.googleapis.com/generate_204";
-    private static final String DEFAULT_USER_AGENT    = "Mozilla/5.0 (X11; Linux x86_64) "
-                                                      + "AppleWebKit/537.36 (KHTML, like Gecko) "
-                                                      + "Chrome/60.0.3112.32 Safari/537.36";
-
-    private static final int SOCKET_TIMEOUT_MS = 10000;
-    private static final int PROBE_TIMEOUT_MS  = 3000;
-
-    // Default configuration values for data stall detection.
-    private static final int DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = 5;
-    private static final int DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS = 60 * 1000;
-    private static final int DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS = 30 * 60 * 1000;
-
-    private static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
-    private static final int DEFAULT_DATA_STALL_EVALUATION_TYPES =
-            (1 << DATA_STALL_EVALUATION_TYPE_DNS);
-
-    static enum EvaluationResult {
-        VALIDATED(true),
-        CAPTIVE_PORTAL(false);
-        final boolean isValidated;
-        EvaluationResult(boolean isValidated) {
-            this.isValidated = isValidated;
-        }
-    }
-
-    static enum ValidationStage {
-        FIRST_VALIDATION(true),
-        REVALIDATION(false);
-        final boolean isFirstValidation;
-        ValidationStage(boolean isFirstValidation) {
-            this.isFirstValidation = isFirstValidation;
-        }
-    }
-
-    // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.
-    // The network should be used as a default internet connection.  It was found to be:
-    // 1. a functioning network providing internet access, or
-    // 2. a captive portal and the user decided to use it as is.
-    public static final int NETWORK_TEST_RESULT_VALID = 0;
-    // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.
-    // The network should not be used as a default internet connection.  It was found to be:
-    // 1. a captive portal and the user is prompted to sign-in, or
-    // 2. a captive portal and the user did not want to use it, or
-    // 3. a broken network (e.g. DNS failed, connect failed, HTTP request failed).
-    public static final int NETWORK_TEST_RESULT_INVALID = 1;
-
-    private static final int BASE = Protocol.BASE_NETWORK_MONITOR;
-
-    /**
-     * Inform NetworkMonitor that their network is connected.
-     * Initiates Network Validation.
-     */
-    public static final int CMD_NETWORK_CONNECTED = BASE + 1;
-
-    /**
-     * Inform ConnectivityService that the network has been tested.
-     * obj = String representing URL that Internet probe was redirect to, if it was redirected.
-     * arg1 = One of the NETWORK_TESTED_RESULT_* constants.
-     * arg2 = NetID.
-     */
-    public static final int EVENT_NETWORK_TESTED = BASE + 2;
-
-    /**
-     * Message to self indicating it's time to evaluate a network's connectivity.
-     * arg1 = Token to ignore old messages.
-     */
-    private static final int CMD_REEVALUATE = BASE + 6;
-
-    /**
-     * Inform NetworkMonitor that the network has disconnected.
-     */
-    public static final int CMD_NETWORK_DISCONNECTED = BASE + 7;
-
-    /**
-     * Force evaluation even if it has succeeded in the past.
-     * arg1 = UID responsible for requesting this reeval.  Will be billed for data.
-     */
-    private static final int CMD_FORCE_REEVALUATION = BASE + 8;
-
-    /**
-     * Message to self indicating captive portal app finished.
-     * arg1 = one of: APP_RETURN_DISMISSED,
-     *                APP_RETURN_UNWANTED,
-     *                APP_RETURN_WANTED_AS_IS
-     * obj = mCaptivePortalLoggedInResponseToken as String
-     */
-    private static final int CMD_CAPTIVE_PORTAL_APP_FINISHED = BASE + 9;
-
-    /**
-     * Request ConnectivityService display provisioning notification.
-     * arg1    = Whether to make the notification visible.
-     * arg2    = NetID.
-     * obj     = Intent to be launched when notification selected by user, null if !arg1.
-     */
-    public static final int EVENT_PROVISIONING_NOTIFICATION = BASE + 10;
-
-    /**
-     * Message indicating sign-in app should be launched.
-     * Sent by mLaunchCaptivePortalAppBroadcastReceiver when the
-     * user touches the sign in notification, or sent by
-     * ConnectivityService when the user touches the "sign into
-     * network" button in the wifi access point detail page.
-     */
-    public static final int CMD_LAUNCH_CAPTIVE_PORTAL_APP = BASE + 11;
-
-    /**
-     * Retest network to see if captive portal is still in place.
-     * arg1 = UID responsible for requesting this reeval.  Will be billed for data.
-     *        0 indicates self-initiated, so nobody to blame.
-     */
-    private static final int CMD_CAPTIVE_PORTAL_RECHECK = BASE + 12;
-
-    /**
-     * ConnectivityService notifies NetworkMonitor of settings changes to
-     * Private DNS. If a DNS resolution is required, e.g. for DNS-over-TLS in
-     * strict mode, then an event is sent back to ConnectivityService with the
-     * result of the resolution attempt.
-     *
-     * A separate message is used to trigger (re)evaluation of the Private DNS
-     * configuration, so that the message can be handled as needed in different
-     * states, including being ignored until after an ongoing captive portal
-     * validation phase is completed.
-     */
-    private static final int CMD_PRIVATE_DNS_SETTINGS_CHANGED = BASE + 13;
-    public static final int EVENT_PRIVATE_DNS_CONFIG_RESOLVED = BASE + 14;
-    private static final int CMD_EVALUATE_PRIVATE_DNS = BASE + 15;
-
-    /**
-     * Message to self indicating captive portal detection is completed.
-     * obj = CaptivePortalProbeResult for detection result;
-     */
-    public static final int CMD_PROBE_COMPLETE = BASE + 16;
-
-    /**
-     * ConnectivityService notifies NetworkMonitor of DNS query responses event.
-     * arg1 = returncode in OnDnsEvent which indicates the response code for the DNS query.
-     */
-    public static final int EVENT_DNS_NOTIFICATION = BASE + 17;
-
-    // Start mReevaluateDelayMs at this value and double.
-    private static final int INITIAL_REEVALUATE_DELAY_MS = 1000;
-    private static final int MAX_REEVALUATE_DELAY_MS = 10*60*1000;
-    // Before network has been evaluated this many times, ignore repeated reevaluate requests.
-    private static final int IGNORE_REEVALUATE_ATTEMPTS = 5;
-    private int mReevaluateToken = 0;
-    private static final int NO_UID = 0;
-    private static final int INVALID_UID = -1;
-    private int mUidResponsibleForReeval = INVALID_UID;
-    // Stop blaming UID that requested re-evaluation after this many attempts.
-    private static final int BLAME_FOR_EVALUATION_ATTEMPTS = 5;
-    // Delay between reevaluations once a captive portal has been found.
-    private static final int CAPTIVE_PORTAL_REEVALUATE_DELAY_MS = 10*60*1000;
-
-    private static final int NUM_VALIDATION_LOG_LINES = 20;
-
-    private String mPrivateDnsProviderHostname = "";
-
-    public static boolean isValidationRequired(
-            NetworkCapabilities dfltNetCap, NetworkCapabilities nc) {
-        // TODO: Consider requiring validation for DUN networks.
-        return dfltNetCap.satisfiedByNetworkCapabilities(nc);
-    }
-
-    private final Context mContext;
-    private final Handler mConnectivityServiceHandler;
-    private final NetworkAgentInfo mNetworkAgentInfo;
-    private final Network mNetwork;
-    private final int mNetId;
-    private final TelephonyManager mTelephonyManager;
-    private final WifiManager mWifiManager;
-    private final NetworkRequest mDefaultRequest;
-    private final IpConnectivityLog mMetricsLog;
-    private final Dependencies mDependencies;
-
-    // Configuration values for captive portal detection probes.
-    private final String mCaptivePortalUserAgent;
-    private final URL mCaptivePortalHttpsUrl;
-    private final URL mCaptivePortalHttpUrl;
-    private final URL[] mCaptivePortalFallbackUrls;
-    @Nullable
-    private final CaptivePortalProbeSpec[] mCaptivePortalFallbackSpecs;
-
-    @VisibleForTesting
-    protected boolean mIsCaptivePortalCheckEnabled;
-
-    private boolean mUseHttps;
-    // The total number of captive portal detection attempts for this NetworkMonitor instance.
-    private int mValidations = 0;
-
-    // Set if the user explicitly selected "Do not use this network" in captive portal sign-in app.
-    private boolean mUserDoesNotWant = false;
-    // Avoids surfacing "Sign in to network" notification.
-    private boolean mDontDisplaySigninNotification = false;
-
-    public boolean systemReady = false;
-
-    private final State mDefaultState = new DefaultState();
-    private final State mValidatedState = new ValidatedState();
-    private final State mMaybeNotifyState = new MaybeNotifyState();
-    private final State mEvaluatingState = new EvaluatingState();
-    private final State mCaptivePortalState = new CaptivePortalState();
-    private final State mEvaluatingPrivateDnsState = new EvaluatingPrivateDnsState();
-    private final State mProbingState = new ProbingState();
-    private final State mWaitingForNextProbeState = new WaitingForNextProbeState();
-
-    private CustomIntentReceiver mLaunchCaptivePortalAppBroadcastReceiver = null;
-
-    private final LocalLog validationLogs = new LocalLog(NUM_VALIDATION_LOG_LINES);
-
-    private final Stopwatch mEvaluationTimer = new Stopwatch();
-
-    // This variable is set before transitioning to the mCaptivePortalState.
-    private CaptivePortalProbeResult mLastPortalProbeResult = CaptivePortalProbeResult.FAILED;
-
-    // Random generator to select fallback URL index
-    private final Random mRandom;
-    private int mNextFallbackUrlIndex = 0;
-
-    private int mReevaluateDelayMs = INITIAL_REEVALUATE_DELAY_MS;
-    private int mEvaluateAttempts = 0;
-    private volatile int mProbeToken = 0;
-    private final int mConsecutiveDnsTimeoutThreshold;
-    private final int mDataStallMinEvaluateTime;
-    private final int mDataStallValidDnsTimeThreshold;
-    private final int mDataStallEvaluationType;
-    private final DnsStallDetector mDnsStallDetector;
-    private long mLastProbeTime;
-
-    public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
-            NetworkRequest defaultRequest) {
-        this(context, handler, networkAgentInfo, defaultRequest, new IpConnectivityLog(),
-                Dependencies.DEFAULT);
-    }
-
-    @VisibleForTesting
-    protected NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
-            NetworkRequest defaultRequest, IpConnectivityLog logger, Dependencies deps) {
-        // Add suffix indicating which NetworkMonitor we're talking about.
-        super(TAG + networkAgentInfo.name());
-
-        // Logs with a tag of the form given just above, e.g.
-        //     <timestamp>   862  2402 D NetworkMonitor/NetworkAgentInfo [WIFI () - 100]: ...
-        setDbg(VDBG);
-
-        mContext = context;
-        mMetricsLog = logger;
-        mConnectivityServiceHandler = handler;
-        mDependencies = deps;
-        mNetworkAgentInfo = networkAgentInfo;
-        mNetwork = deps.getNetwork(networkAgentInfo).getPrivateDnsBypassingCopy();
-        mNetId = mNetwork.netId;
-        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
-        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-        mDefaultRequest = defaultRequest;
-
-        addState(mDefaultState);
-        addState(mMaybeNotifyState, mDefaultState);
-            addState(mEvaluatingState, mMaybeNotifyState);
-                addState(mProbingState, mEvaluatingState);
-                addState(mWaitingForNextProbeState, mEvaluatingState);
-            addState(mCaptivePortalState, mMaybeNotifyState);
-        addState(mEvaluatingPrivateDnsState, mDefaultState);
-        addState(mValidatedState, mDefaultState);
-        setInitialState(mDefaultState);
-
-        mIsCaptivePortalCheckEnabled = getIsCaptivePortalCheckEnabled();
-        mUseHttps = getUseHttpsValidation();
-        mCaptivePortalUserAgent = getCaptivePortalUserAgent();
-        mCaptivePortalHttpsUrl = makeURL(getCaptivePortalServerHttpsUrl());
-        mCaptivePortalHttpUrl = makeURL(getCaptivePortalServerHttpUrl(deps, context));
-        mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls();
-        mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs();
-        mRandom = deps.getRandom();
-        // TODO: Evaluate to move data stall configuration to a specific class.
-        mConsecutiveDnsTimeoutThreshold = getConsecutiveDnsTimeoutThreshold();
-        mDnsStallDetector = new DnsStallDetector(mConsecutiveDnsTimeoutThreshold);
-        mDataStallMinEvaluateTime = getDataStallMinEvaluateTime();
-        mDataStallValidDnsTimeThreshold = getDataStallValidDnsTimeThreshold();
-        mDataStallEvaluationType = getDataStallEvalutionType();
-
-        start();
-    }
-
-    public void forceReevaluation(int responsibleUid) {
-        sendMessage(CMD_FORCE_REEVALUATION, responsibleUid, 0);
-    }
-
-    public void notifyPrivateDnsSettingsChanged(PrivateDnsConfig newCfg) {
-        // Cancel any outstanding resolutions.
-        removeMessages(CMD_PRIVATE_DNS_SETTINGS_CHANGED);
-        // Send the update to the proper thread.
-        sendMessage(CMD_PRIVATE_DNS_SETTINGS_CHANGED, newCfg);
-    }
-
-    @Override
-    protected void log(String s) {
-        if (DBG) Log.d(TAG + "/" + mNetworkAgentInfo.name(), s);
-    }
-
-    private void validationLog(int probeType, Object url, String msg) {
-        String probeName = ValidationProbeEvent.getProbeName(probeType);
-        validationLog(String.format("%s %s %s", probeName, url, msg));
-    }
-
-    private void validationLog(String s) {
-        if (DBG) log(s);
-        validationLogs.log(s);
-    }
-
-    public ReadOnlyLocalLog getValidationLogs() {
-        return validationLogs.readOnlyLocalLog();
-    }
-
-    private ValidationStage validationStage() {
-        return 0 == mValidations ? ValidationStage.FIRST_VALIDATION : ValidationStage.REVALIDATION;
-    }
-
-    private boolean isValidationRequired() {
-        return isValidationRequired(
-                mDefaultRequest.networkCapabilities, mNetworkAgentInfo.networkCapabilities);
-    }
-
-
-    private void notifyNetworkTestResultInvalid(Object obj) {
-        mConnectivityServiceHandler.sendMessage(obtainMessage(
-                EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId, obj));
-    }
-
-    // DefaultState is the parent of all States.  It exists only to handle CMD_* messages but
-    // does not entail any real state (hence no enter() or exit() routines).
-    private class DefaultState extends State {
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_NETWORK_CONNECTED:
-                    logNetworkEvent(NetworkEvent.NETWORK_CONNECTED);
-                    transitionTo(mEvaluatingState);
-                    return HANDLED;
-                case CMD_NETWORK_DISCONNECTED:
-                    logNetworkEvent(NetworkEvent.NETWORK_DISCONNECTED);
-                    if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
-                        mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
-                        mLaunchCaptivePortalAppBroadcastReceiver = null;
-                    }
-                    quit();
-                    return HANDLED;
-                case CMD_FORCE_REEVALUATION:
-                case CMD_CAPTIVE_PORTAL_RECHECK:
-                    log("Forcing reevaluation for UID " + message.arg1);
-                    mUidResponsibleForReeval = message.arg1;
-                    transitionTo(mEvaluatingState);
-                    return HANDLED;
-                case CMD_CAPTIVE_PORTAL_APP_FINISHED:
-                    log("CaptivePortal App responded with " + message.arg1);
-
-                    // If the user has seen and acted on a captive portal notification, and the
-                    // captive portal app is now closed, disable HTTPS probes. This avoids the
-                    // following pathological situation:
-                    //
-                    // 1. HTTP probe returns a captive portal, HTTPS probe fails or times out.
-                    // 2. User opens the app and logs into the captive portal.
-                    // 3. HTTP starts working, but HTTPS still doesn't work for some other reason -
-                    //    perhaps due to the network blocking HTTPS?
-                    //
-                    // In this case, we'll fail to validate the network even after the app is
-                    // dismissed. There is now no way to use this network, because the app is now
-                    // gone, so the user cannot select "Use this network as is".
-                    mUseHttps = false;
-
-                    switch (message.arg1) {
-                        case APP_RETURN_DISMISSED:
-                            sendMessage(CMD_FORCE_REEVALUATION, NO_UID, 0);
-                            break;
-                        case APP_RETURN_WANTED_AS_IS:
-                            mDontDisplaySigninNotification = true;
-                            // TODO: Distinguish this from a network that actually validates.
-                            // Displaying the "x" on the system UI icon may still be a good idea.
-                            transitionTo(mEvaluatingPrivateDnsState);
-                            break;
-                        case APP_RETURN_UNWANTED:
-                            mDontDisplaySigninNotification = true;
-                            mUserDoesNotWant = true;
-                            notifyNetworkTestResultInvalid(null);
-                            // TODO: Should teardown network.
-                            mUidResponsibleForReeval = 0;
-                            transitionTo(mEvaluatingState);
-                            break;
-                    }
-                    return HANDLED;
-                case CMD_PRIVATE_DNS_SETTINGS_CHANGED: {
-                    final PrivateDnsConfig cfg = (PrivateDnsConfig) message.obj;
-                    if (!isValidationRequired() || cfg == null || !cfg.inStrictMode()) {
-                        // No DNS resolution required.
-                        //
-                        // We don't force any validation in opportunistic mode
-                        // here. Opportunistic mode nameservers are validated
-                        // separately within netd.
-                        //
-                        // Reset Private DNS settings state.
-                        mPrivateDnsProviderHostname = "";
-                        break;
-                    }
-
-                    mPrivateDnsProviderHostname = cfg.hostname;
-
-                    // DNS resolutions via Private DNS strict mode block for a
-                    // few seconds (~4.2) checking for any IP addresses to
-                    // arrive and validate. Initiating a (re)evaluation now
-                    // should not significantly alter the validation outcome.
-                    //
-                    // No matter what: enqueue a validation request; one of
-                    // three things can happen with this request:
-                    //     [1] ignored (EvaluatingState or CaptivePortalState)
-                    //     [2] transition to EvaluatingPrivateDnsState
-                    //         (DefaultState and ValidatedState)
-                    //     [3] handled (EvaluatingPrivateDnsState)
-                    //
-                    // The Private DNS configuration to be evaluated will:
-                    //     [1] be skipped (not in strict mode), or
-                    //     [2] validate (huzzah), or
-                    //     [3] encounter some problem (invalid hostname,
-                    //         no resolved IP addresses, IPs unreachable,
-                    //         port 853 unreachable, port 853 is not running a
-                    //         DNS-over-TLS server, et cetera).
-                    sendMessage(CMD_EVALUATE_PRIVATE_DNS);
-                    break;
-                }
-                case EVENT_DNS_NOTIFICATION:
-                    mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1);
-                    break;
-                default:
-                    break;
-            }
-            return HANDLED;
-        }
-    }
-
-    // Being in the ValidatedState State indicates a Network is:
-    // - Successfully validated, or
-    // - Wanted "as is" by the user, or
-    // - Does not satisfy the default NetworkRequest and so validation has been skipped.
-    private class ValidatedState extends State {
-        @Override
-        public void enter() {
-            maybeLogEvaluationResult(
-                    networkEventType(validationStage(), EvaluationResult.VALIDATED));
-            mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
-                    NETWORK_TEST_RESULT_VALID, mNetId, null));
-            mValidations++;
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_NETWORK_CONNECTED:
-                    transitionTo(mValidatedState);
-                    break;
-                case CMD_EVALUATE_PRIVATE_DNS:
-                    transitionTo(mEvaluatingPrivateDnsState);
-                    break;
-                case EVENT_DNS_NOTIFICATION:
-                    mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1);
-                    if (isDataStall()) {
-                        validationLog("Suspecting data stall, reevaluate");
-                        transitionTo(mEvaluatingState);
-                    }
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            return HANDLED;
-        }
-    }
-
-    // Being in the MaybeNotifyState State indicates the user may have been notified that sign-in
-    // is required.  This State takes care to clear the notification upon exit from the State.
-    private class MaybeNotifyState extends State {
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_LAUNCH_CAPTIVE_PORTAL_APP:
-                    final Intent intent = new Intent(
-                            ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
-                    // OneAddressPerFamilyNetwork is not parcelable across processes.
-                    intent.putExtra(ConnectivityManager.EXTRA_NETWORK, new Network(mNetwork));
-                    intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL,
-                            new CaptivePortal(new ICaptivePortal.Stub() {
-                                @Override
-                                public void appResponse(int response) {
-                                    if (response == APP_RETURN_WANTED_AS_IS) {
-                                        mContext.enforceCallingPermission(
-                                                android.Manifest.permission.CONNECTIVITY_INTERNAL,
-                                                "CaptivePortal");
-                                    }
-                                    sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response);
-                                }
-                            }));
-                    final CaptivePortalProbeResult probeRes = mLastPortalProbeResult;
-                    intent.putExtra(EXTRA_CAPTIVE_PORTAL_URL, probeRes.detectUrl);
-                    if (probeRes.probeSpec != null) {
-                        final String encodedSpec = probeRes.probeSpec.getEncodedSpec();
-                        intent.putExtra(EXTRA_CAPTIVE_PORTAL_PROBE_SPEC, encodedSpec);
-                    }
-                    intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT,
-                            mCaptivePortalUserAgent);
-                    intent.setFlags(
-                            Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
-                    mContext.startActivityAsUser(intent, UserHandle.CURRENT);
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        @Override
-        public void exit() {
-            Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 0, mNetId, null);
-            mConnectivityServiceHandler.sendMessage(message);
-        }
-    }
-
-    // Being in the EvaluatingState State indicates the Network is being evaluated for internet
-    // connectivity, or that the user has indicated that this network is unwanted.
-    private class EvaluatingState extends State {
-        @Override
-        public void enter() {
-            // If we have already started to track time spent in EvaluatingState
-            // don't reset the timer due simply to, say, commands or events that
-            // cause us to exit and re-enter EvaluatingState.
-            if (!mEvaluationTimer.isStarted()) {
-                mEvaluationTimer.start();
-            }
-            sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
-            if (mUidResponsibleForReeval != INVALID_UID) {
-                TrafficStats.setThreadStatsUid(mUidResponsibleForReeval);
-                mUidResponsibleForReeval = INVALID_UID;
-            }
-            mReevaluateDelayMs = INITIAL_REEVALUATE_DELAY_MS;
-            mEvaluateAttempts = 0;
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_REEVALUATE:
-                    if (message.arg1 != mReevaluateToken || mUserDoesNotWant)
-                        return HANDLED;
-                    // Don't bother validating networks that don't satisfy the default request.
-                    // This includes:
-                    //  - VPNs which can be considered explicitly desired by the user and the
-                    //    user's desire trumps whether the network validates.
-                    //  - Networks that don't provide Internet access.  It's unclear how to
-                    //    validate such networks.
-                    //  - Untrusted networks.  It's unsafe to prompt the user to sign-in to
-                    //    such networks and the user didn't express interest in connecting to
-                    //    such networks (an app did) so the user may be unhappily surprised when
-                    //    asked to sign-in to a network they didn't want to connect to in the
-                    //    first place.  Validation could be done to adjust the network scores
-                    //    however these networks are app-requested and may not be intended for
-                    //    general usage, in which case general validation may not be an accurate
-                    //    measure of the network's quality.  Only the app knows how to evaluate
-                    //    the network so don't bother validating here.  Furthermore sending HTTP
-                    //    packets over the network may be undesirable, for example an extremely
-                    //    expensive metered network, or unwanted leaking of the User Agent string.
-                    if (!isValidationRequired()) {
-                        validationLog("Network would not satisfy default request, not validating");
-                        transitionTo(mValidatedState);
-                        return HANDLED;
-                    }
-                    mEvaluateAttempts++;
-
-                    transitionTo(mProbingState);
-                    return HANDLED;
-                case CMD_FORCE_REEVALUATION:
-                    // Before IGNORE_REEVALUATE_ATTEMPTS attempts are made,
-                    // ignore any re-evaluation requests. After, restart the
-                    // evaluation process via EvaluatingState#enter.
-                    return (mEvaluateAttempts < IGNORE_REEVALUATE_ATTEMPTS) ? HANDLED : NOT_HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        @Override
-        public void exit() {
-            TrafficStats.clearThreadStatsUid();
-        }
-    }
-
-    // BroadcastReceiver that waits for a particular Intent and then posts a message.
-    private class CustomIntentReceiver extends BroadcastReceiver {
-        private final int mToken;
-        private final int mWhat;
-        private final String mAction;
-        CustomIntentReceiver(String action, int token, int what) {
-            mToken = token;
-            mWhat = what;
-            mAction = action + "_" + mNetId + "_" + token;
-            mContext.registerReceiver(this, new IntentFilter(mAction));
-        }
-        public PendingIntent getPendingIntent() {
-            final Intent intent = new Intent(mAction);
-            intent.setPackage(mContext.getPackageName());
-            return PendingIntent.getBroadcast(mContext, 0, intent, 0);
-        }
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().equals(mAction)) sendMessage(obtainMessage(mWhat, mToken));
-        }
-    }
-
-    // Being in the CaptivePortalState State indicates a captive portal was detected and the user
-    // has been shown a notification to sign-in.
-    private class CaptivePortalState extends State {
-        private static final String ACTION_LAUNCH_CAPTIVE_PORTAL_APP =
-                "android.net.netmon.launchCaptivePortalApp";
-
-        @Override
-        public void enter() {
-            maybeLogEvaluationResult(
-                    networkEventType(validationStage(), EvaluationResult.CAPTIVE_PORTAL));
-            // Don't annoy user with sign-in notifications.
-            if (mDontDisplaySigninNotification) return;
-            // Create a CustomIntentReceiver that sends us a
-            // CMD_LAUNCH_CAPTIVE_PORTAL_APP message when the user
-            // touches the notification.
-            if (mLaunchCaptivePortalAppBroadcastReceiver == null) {
-                // Wait for result.
-                mLaunchCaptivePortalAppBroadcastReceiver = new CustomIntentReceiver(
-                        ACTION_LAUNCH_CAPTIVE_PORTAL_APP, new Random().nextInt(),
-                        CMD_LAUNCH_CAPTIVE_PORTAL_APP);
-            }
-            // Display the sign in notification.
-            Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 1, mNetId,
-                    mLaunchCaptivePortalAppBroadcastReceiver.getPendingIntent());
-            mConnectivityServiceHandler.sendMessage(message);
-            // Retest for captive portal occasionally.
-            sendMessageDelayed(CMD_CAPTIVE_PORTAL_RECHECK, 0 /* no UID */,
-                    CAPTIVE_PORTAL_REEVALUATE_DELAY_MS);
-            mValidations++;
-        }
-
-        @Override
-        public void exit() {
-            removeMessages(CMD_CAPTIVE_PORTAL_RECHECK);
-        }
-    }
-
-    private class EvaluatingPrivateDnsState extends State {
-        private int mPrivateDnsReevalDelayMs;
-        private PrivateDnsConfig mPrivateDnsConfig;
-
-        @Override
-        public void enter() {
-            mPrivateDnsReevalDelayMs = INITIAL_REEVALUATE_DELAY_MS;
-            mPrivateDnsConfig = null;
-            sendMessage(CMD_EVALUATE_PRIVATE_DNS);
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_EVALUATE_PRIVATE_DNS:
-                    if (inStrictMode()) {
-                        if (!isStrictModeHostnameResolved()) {
-                            resolveStrictModeHostname();
-
-                            if (isStrictModeHostnameResolved()) {
-                                notifyPrivateDnsConfigResolved();
-                            } else {
-                                handlePrivateDnsEvaluationFailure();
-                                break;
-                            }
-                        }
-
-                        // Look up a one-time hostname, to bypass caching.
-                        //
-                        // Note that this will race with ConnectivityService
-                        // code programming the DNS-over-TLS server IP addresses
-                        // into netd (if invoked, above). If netd doesn't know
-                        // the IP addresses yet, or if the connections to the IP
-                        // addresses haven't yet been validated, netd will block
-                        // for up to a few seconds before failing the lookup.
-                        if (!sendPrivateDnsProbe()) {
-                            handlePrivateDnsEvaluationFailure();
-                            break;
-                        }
-                    }
-
-                    // All good!
-                    transitionTo(mValidatedState);
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            return HANDLED;
-        }
-
-        private boolean inStrictMode() {
-            return !TextUtils.isEmpty(mPrivateDnsProviderHostname);
-        }
-
-        private boolean isStrictModeHostnameResolved() {
-            return (mPrivateDnsConfig != null) &&
-                   mPrivateDnsConfig.hostname.equals(mPrivateDnsProviderHostname) &&
-                   (mPrivateDnsConfig.ips.length > 0);
-        }
-
-        private void resolveStrictModeHostname() {
-            try {
-                // Do a blocking DNS resolution using the network-assigned nameservers.
-                final InetAddress[] ips = mNetwork.getAllByName(mPrivateDnsProviderHostname);
-                mPrivateDnsConfig = new PrivateDnsConfig(mPrivateDnsProviderHostname, ips);
-                validationLog("Strict mode hostname resolved: " + mPrivateDnsConfig);
-            } catch (UnknownHostException uhe) {
-                mPrivateDnsConfig = null;
-                validationLog("Strict mode hostname resolution failed: " + uhe.getMessage());
-            }
-        }
-
-        private void notifyPrivateDnsConfigResolved() {
-            mConnectivityServiceHandler.sendMessage(obtainMessage(
-                    EVENT_PRIVATE_DNS_CONFIG_RESOLVED, 0, mNetId, mPrivateDnsConfig));
-        }
-
-        private void handlePrivateDnsEvaluationFailure() {
-            notifyNetworkTestResultInvalid(null);
-
-            // Queue up a re-evaluation with backoff.
-            //
-            // TODO: Consider abandoning this state after a few attempts and
-            // transitioning back to EvaluatingState, to perhaps give ourselves
-            // the opportunity to (re)detect a captive portal or something.
-            sendMessageDelayed(CMD_EVALUATE_PRIVATE_DNS, mPrivateDnsReevalDelayMs);
-            mPrivateDnsReevalDelayMs *= 2;
-            if (mPrivateDnsReevalDelayMs > MAX_REEVALUATE_DELAY_MS) {
-                mPrivateDnsReevalDelayMs = MAX_REEVALUATE_DELAY_MS;
-            }
-        }
-
-        private boolean sendPrivateDnsProbe() {
-            // q.v. system/netd/server/dns/DnsTlsTransport.cpp
-            final String ONE_TIME_HOSTNAME_SUFFIX = "-dnsotls-ds.metric.gstatic.com";
-            final String host = UUID.randomUUID().toString().substring(0, 8) +
-                    ONE_TIME_HOSTNAME_SUFFIX;
-            final Stopwatch watch = new Stopwatch().start();
-            try {
-                final InetAddress[] ips = mNetworkAgentInfo.network().getAllByName(host);
-                final long time = watch.stop();
-                final String strIps = Arrays.toString(ips);
-                final boolean success = (ips != null && ips.length > 0);
-                validationLog(PROBE_PRIVDNS, host, String.format("%dms: %s", time, strIps));
-                logValidationProbe(time, PROBE_PRIVDNS, success ? DNS_SUCCESS : DNS_FAILURE);
-                return success;
-            } catch (UnknownHostException uhe) {
-                final long time = watch.stop();
-                validationLog(PROBE_PRIVDNS, host,
-                        String.format("%dms - Error: %s", time, uhe.getMessage()));
-                logValidationProbe(time, PROBE_PRIVDNS, DNS_FAILURE);
-            }
-            return false;
-        }
-    }
-
-    private class ProbingState extends State {
-        private Thread mThread;
-
-        @Override
-        public void enter() {
-            if (mEvaluateAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) {
-                //Don't continue to blame UID forever.
-                TrafficStats.clearThreadStatsUid();
-            }
-
-            final int token = ++mProbeToken;
-            mThread = new Thread(() -> sendMessage(obtainMessage(CMD_PROBE_COMPLETE, token, 0,
-                    isCaptivePortal())));
-            mThread.start();
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_PROBE_COMPLETE:
-                    // Ensure that CMD_PROBE_COMPLETE from stale threads are ignored.
-                    if (message.arg1 != mProbeToken) {
-                        return HANDLED;
-                    }
-
-                    final CaptivePortalProbeResult probeResult =
-                            (CaptivePortalProbeResult) message.obj;
-                    mLastProbeTime = SystemClock.elapsedRealtime();
-                    if (probeResult.isSuccessful()) {
-                        // Transit EvaluatingPrivateDnsState to get to Validated
-                        // state (even if no Private DNS validation required).
-                        transitionTo(mEvaluatingPrivateDnsState);
-                    } else if (probeResult.isPortal()) {
-                        notifyNetworkTestResultInvalid(probeResult.redirectUrl);
-                        mLastPortalProbeResult = probeResult;
-                        transitionTo(mCaptivePortalState);
-                    } else {
-                        logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED);
-                        notifyNetworkTestResultInvalid(probeResult.redirectUrl);
-                        transitionTo(mWaitingForNextProbeState);
-                    }
-                    return HANDLED;
-                case EVENT_DNS_NOTIFICATION:
-                    // Leave the event to DefaultState to record correct dns timestamp.
-                    return NOT_HANDLED;
-                default:
-                    // Wait for probe result and defer events to next state by default.
-                    deferMessage(message);
-                    return HANDLED;
-            }
-        }
-
-        @Override
-        public void exit() {
-            if (mThread.isAlive()) {
-                mThread.interrupt();
-            }
-            mThread = null;
-        }
-    }
-
-    // Being in the WaitingForNextProbeState indicates that evaluating probes failed and state is
-    // transited from ProbingState. This ensures that the state machine is only in ProbingState
-    // while a probe is in progress, not while waiting to perform the next probe. That allows
-    // ProbingState to defer most messages until the probe is complete, which keeps the code simple
-    // and matches the pre-Q behaviour where probes were a blocking operation performed on the state
-    // machine thread.
-    private class WaitingForNextProbeState extends State {
-        @Override
-        public void enter() {
-            scheduleNextProbe();
-        }
-
-        private void scheduleNextProbe() {
-            final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
-            sendMessageDelayed(msg, mReevaluateDelayMs);
-            mReevaluateDelayMs *= 2;
-            if (mReevaluateDelayMs > MAX_REEVALUATE_DELAY_MS) {
-                mReevaluateDelayMs = MAX_REEVALUATE_DELAY_MS;
-            }
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            return NOT_HANDLED;
-        }
-    }
-
-    // Limits the list of IP addresses returned by getAllByName or tried by openConnection to at
-    // most one per address family. This ensures we only wait up to 20 seconds for TCP connections
-    // to complete, regardless of how many IP addresses a host has.
-    private static class OneAddressPerFamilyNetwork extends Network {
-        public OneAddressPerFamilyNetwork(Network network) {
-            // Always bypass Private DNS.
-            super(network.getPrivateDnsBypassingCopy());
-        }
-
-        @Override
-        public InetAddress[] getAllByName(String host) throws UnknownHostException {
-            final List<InetAddress> addrs = Arrays.asList(super.getAllByName(host));
-
-            // Ensure the address family of the first address is tried first.
-            LinkedHashMap<Class, InetAddress> addressByFamily = new LinkedHashMap<>();
-            addressByFamily.put(addrs.get(0).getClass(), addrs.get(0));
-            Collections.shuffle(addrs);
-
-            for (InetAddress addr : addrs) {
-                addressByFamily.put(addr.getClass(), addr);
-            }
-
-            return addressByFamily.values().toArray(new InetAddress[addressByFamily.size()]);
-        }
-    }
-
-    public boolean getIsCaptivePortalCheckEnabled() {
-        String symbol = Settings.Global.CAPTIVE_PORTAL_MODE;
-        int defaultValue = Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT;
-        int mode = mDependencies.getSetting(mContext, symbol, defaultValue);
-        return mode != Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE;
-    }
-
-    public boolean getUseHttpsValidation() {
-        return mDependencies.getSetting(mContext, Settings.Global.CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
-    }
-
-    public boolean getWifiScansAlwaysAvailableDisabled() {
-        return mDependencies.getSetting(mContext, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0;
-    }
-
-    private String getCaptivePortalServerHttpsUrl() {
-        return mDependencies.getSetting(mContext,
-                Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL);
-    }
-
-    private int getConsecutiveDnsTimeoutThreshold() {
-        return mDependencies.getSetting(mContext,
-                Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
-                DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD);
-    }
-
-    private int getDataStallMinEvaluateTime() {
-        return mDependencies.getSetting(mContext,
-                Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL,
-                DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS);
-    }
-
-    private int getDataStallValidDnsTimeThreshold() {
-        return mDependencies.getSetting(mContext,
-                Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD,
-                DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS);
-    }
-
-    private int getDataStallEvalutionType() {
-        return mDependencies.getSetting(mContext, Settings.Global.DATA_STALL_EVALUATION_TYPE,
-                DEFAULT_DATA_STALL_EVALUATION_TYPES);
-    }
-
-    // Static for direct access by ConnectivityService
-    public static String getCaptivePortalServerHttpUrl(Context context) {
-        return getCaptivePortalServerHttpUrl(Dependencies.DEFAULT, context);
-    }
-
-    public static String getCaptivePortalServerHttpUrl(Dependencies deps, Context context) {
-        return deps.getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTP_URL, DEFAULT_HTTP_URL);
-    }
-
-    private URL[] makeCaptivePortalFallbackUrls() {
-        try {
-            String separator = ",";
-            String firstUrl = mDependencies.getSetting(mContext,
-                    Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
-            String joinedUrls = firstUrl + separator + mDependencies.getSetting(mContext,
-                    Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
-                    DEFAULT_OTHER_FALLBACK_URLS);
-            List<URL> urls = new ArrayList<>();
-            for (String s : joinedUrls.split(separator)) {
-                URL u = makeURL(s);
-                if (u == null) {
-                    continue;
-                }
-                urls.add(u);
-            }
-            if (urls.isEmpty()) {
-                Log.e(TAG, String.format("could not create any url from %s", joinedUrls));
-            }
-            return urls.toArray(new URL[urls.size()]);
-        } catch (Exception e) {
-            // Don't let a misconfiguration bootloop the system.
-            Log.e(TAG, "Error parsing configured fallback URLs", e);
-            return new URL[0];
-        }
-    }
-
-    private CaptivePortalProbeSpec[] makeCaptivePortalFallbackProbeSpecs() {
-        try {
-            final String settingsValue = mDependencies.getSetting(
-                    mContext, Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
-            // Probe specs only used if configured in settings
-            if (TextUtils.isEmpty(settingsValue)) {
-                return null;
-            }
-
-            return CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue);
-        } catch (Exception e) {
-            // Don't let a misconfiguration bootloop the system.
-            Log.e(TAG, "Error parsing configured fallback probe specs", e);
-            return null;
-        }
-    }
-
-    private String getCaptivePortalUserAgent() {
-        return mDependencies.getSetting(mContext,
-                Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
-    }
-
-    private URL nextFallbackUrl() {
-        if (mCaptivePortalFallbackUrls.length == 0) {
-            return null;
-        }
-        int idx = Math.abs(mNextFallbackUrlIndex) % mCaptivePortalFallbackUrls.length;
-        mNextFallbackUrlIndex += mRandom.nextInt(); // randomly change url without memory.
-        return mCaptivePortalFallbackUrls[idx];
-    }
-
-    private CaptivePortalProbeSpec nextFallbackSpec() {
-        if (ArrayUtils.isEmpty(mCaptivePortalFallbackSpecs)) {
-            return null;
-        }
-        // Randomly change spec without memory. Also randomize the first attempt.
-        final int idx = Math.abs(mRandom.nextInt()) % mCaptivePortalFallbackSpecs.length;
-        return mCaptivePortalFallbackSpecs[idx];
-    }
-
-    @VisibleForTesting
-    protected CaptivePortalProbeResult isCaptivePortal() {
-        if (!mIsCaptivePortalCheckEnabled) {
-            validationLog("Validation disabled.");
-            return CaptivePortalProbeResult.SUCCESS;
-        }
-
-        URL pacUrl = null;
-        URL httpsUrl = mCaptivePortalHttpsUrl;
-        URL httpUrl = mCaptivePortalHttpUrl;
-
-        // On networks with a PAC instead of fetching a URL that should result in a 204
-        // response, we instead simply fetch the PAC script.  This is done for a few reasons:
-        // 1. At present our PAC code does not yet handle multiple PACs on multiple networks
-        //    until something like https://android-review.googlesource.com/#/c/115180/ lands.
-        //    Network.openConnection() will ignore network-specific PACs and instead fetch
-        //    using NO_PROXY.  If a PAC is in place, the only fetch we know will succeed with
-        //    NO_PROXY is the fetch of the PAC itself.
-        // 2. To proxy the generate_204 fetch through a PAC would require a number of things
-        //    happen before the fetch can commence, namely:
-        //        a) the PAC script be fetched
-        //        b) a PAC script resolver service be fired up and resolve the captive portal
-        //           server.
-        //    Network validation could be delayed until these prerequisities are satisifed or
-        //    could simply be left to race them.  Neither is an optimal solution.
-        // 3. PAC scripts are sometimes used to block or restrict Internet access and may in
-        //    fact block fetching of the generate_204 URL which would lead to false negative
-        //    results for network validation.
-        final ProxyInfo proxyInfo = mNetworkAgentInfo.linkProperties.getHttpProxy();
-        if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) {
-            pacUrl = makeURL(proxyInfo.getPacFileUrl().toString());
-            if (pacUrl == null) {
-                return CaptivePortalProbeResult.FAILED;
-            }
-        }
-
-        if ((pacUrl == null) && (httpUrl == null || httpsUrl == null)) {
-            return CaptivePortalProbeResult.FAILED;
-        }
-
-        long startTime = SystemClock.elapsedRealtime();
-
-        final CaptivePortalProbeResult result;
-        if (pacUrl != null) {
-            result = sendDnsAndHttpProbes(null, pacUrl, ValidationProbeEvent.PROBE_PAC);
-        } else if (mUseHttps) {
-            result = sendParallelHttpProbes(proxyInfo, httpsUrl, httpUrl);
-        } else {
-            result = sendDnsAndHttpProbes(proxyInfo, httpUrl, ValidationProbeEvent.PROBE_HTTP);
-        }
-
-        long endTime = SystemClock.elapsedRealtime();
-
-        sendNetworkConditionsBroadcast(true /* response received */,
-                result.isPortal() /* isCaptivePortal */,
-                startTime, endTime);
-
-        log("isCaptivePortal: isSuccessful()=" + result.isSuccessful()
-                + " isPortal()=" + result.isPortal()
-                + " RedirectUrl=" + result.redirectUrl
-                + " Time=" + (endTime - startTime) + "ms");
-
-        return result;
-    }
-
-    /**
-     * Do a DNS resolution and URL fetch on a known web server to see if we get the data we expect.
-     * @return a CaptivePortalProbeResult inferred from the HTTP response.
-     */
-    private CaptivePortalProbeResult sendDnsAndHttpProbes(ProxyInfo proxy, URL url, int probeType) {
-        // Pre-resolve the captive portal server host so we can log it.
-        // Only do this if HttpURLConnection is about to, to avoid any potentially
-        // unnecessary resolution.
-        final String host = (proxy != null) ? proxy.getHost() : url.getHost();
-        sendDnsProbe(host);
-        return sendHttpProbe(url, probeType, null);
-    }
-
-    /** Do a DNS resolution of the given server. */
-    private void sendDnsProbe(String host) {
-        if (TextUtils.isEmpty(host)) {
-            return;
-        }
-
-        final String name = ValidationProbeEvent.getProbeName(ValidationProbeEvent.PROBE_DNS);
-        final Stopwatch watch = new Stopwatch().start();
-        int result;
-        String connectInfo;
-        try {
-            InetAddress[] addresses = mNetwork.getAllByName(host);
-            StringBuffer buffer = new StringBuffer();
-            for (InetAddress address : addresses) {
-                buffer.append(',').append(address.getHostAddress());
-            }
-            result = ValidationProbeEvent.DNS_SUCCESS;
-            connectInfo = "OK " + buffer.substring(1);
-        } catch (UnknownHostException e) {
-            result = ValidationProbeEvent.DNS_FAILURE;
-            connectInfo = "FAIL";
-        }
-        final long latency = watch.stop();
-        validationLog(ValidationProbeEvent.PROBE_DNS, host,
-                String.format("%dms %s", latency, connectInfo));
-        logValidationProbe(latency, ValidationProbeEvent.PROBE_DNS, result);
-    }
-
-    /**
-     * Do a URL fetch on a known web server to see if we get the data we expect.
-     * @return a CaptivePortalProbeResult inferred from the HTTP response.
-     */
-    @VisibleForTesting
-    protected CaptivePortalProbeResult sendHttpProbe(URL url, int probeType,
-            @Nullable CaptivePortalProbeSpec probeSpec) {
-        HttpURLConnection urlConnection = null;
-        int httpResponseCode = CaptivePortalProbeResult.FAILED_CODE;
-        String redirectUrl = null;
-        final Stopwatch probeTimer = new Stopwatch().start();
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
-        try {
-            urlConnection = (HttpURLConnection) mNetwork.openConnection(url);
-            urlConnection.setInstanceFollowRedirects(probeType == ValidationProbeEvent.PROBE_PAC);
-            urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
-            urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
-            urlConnection.setUseCaches(false);
-            if (mCaptivePortalUserAgent != null) {
-                urlConnection.setRequestProperty("User-Agent", mCaptivePortalUserAgent);
-            }
-            // cannot read request header after connection
-            String requestHeader = urlConnection.getRequestProperties().toString();
-
-            // Time how long it takes to get a response to our request
-            long requestTimestamp = SystemClock.elapsedRealtime();
-
-            httpResponseCode = urlConnection.getResponseCode();
-            redirectUrl = urlConnection.getHeaderField("location");
-
-            // Time how long it takes to get a response to our request
-            long responseTimestamp = SystemClock.elapsedRealtime();
-
-            validationLog(probeType, url, "time=" + (responseTimestamp - requestTimestamp) + "ms" +
-                    " ret=" + httpResponseCode +
-                    " request=" + requestHeader +
-                    " headers=" + urlConnection.getHeaderFields());
-            // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive
-            // portal.  The only example of this seen so far was a captive portal.  For
-            // the time being go with prior behavior of assuming it's not a captive
-            // portal.  If it is considered a captive portal, a different sign-in URL
-            // is needed (i.e. can't browse a 204).  This could be the result of an HTTP
-            // proxy server.
-            if (httpResponseCode == 200) {
-                if (probeType == ValidationProbeEvent.PROBE_PAC) {
-                    validationLog(
-                            probeType, url, "PAC fetch 200 response interpreted as 204 response.");
-                    httpResponseCode = CaptivePortalProbeResult.SUCCESS_CODE;
-                } else if (urlConnection.getContentLengthLong() == 0) {
-                    // Consider 200 response with "Content-length=0" to not be a captive portal.
-                    // There's no point in considering this a captive portal as the user cannot
-                    // sign-in to an empty page. Probably the result of a broken transparent proxy.
-                    // See http://b/9972012.
-                    validationLog(probeType, url,
-                        "200 response with Content-length=0 interpreted as 204 response.");
-                    httpResponseCode = CaptivePortalProbeResult.SUCCESS_CODE;
-                } else if (urlConnection.getContentLengthLong() == -1) {
-                    // When no Content-length (default value == -1), attempt to read a byte from the
-                    // response. Do not use available() as it is unreliable. See http://b/33498325.
-                    if (urlConnection.getInputStream().read() == -1) {
-                        validationLog(
-                                probeType, url, "Empty 200 response interpreted as 204 response.");
-                        httpResponseCode = CaptivePortalProbeResult.SUCCESS_CODE;
-                    }
-                }
-            }
-        } catch (IOException e) {
-            validationLog(probeType, url, "Probe failed with exception " + e);
-            if (httpResponseCode == CaptivePortalProbeResult.FAILED_CODE) {
-                // TODO: Ping gateway and DNS server and log results.
-            }
-        } finally {
-            if (urlConnection != null) {
-                urlConnection.disconnect();
-            }
-            TrafficStats.setThreadStatsTag(oldTag);
-        }
-        logValidationProbe(probeTimer.stop(), probeType, httpResponseCode);
-
-        if (probeSpec == null) {
-            return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, url.toString());
-        } else {
-            return probeSpec.getResult(httpResponseCode, redirectUrl);
-        }
-    }
-
-    private CaptivePortalProbeResult sendParallelHttpProbes(
-            ProxyInfo proxy, URL httpsUrl, URL httpUrl) {
-        // Number of probes to wait for. If a probe completes with a conclusive answer
-        // it shortcuts the latch immediately by forcing the count to 0.
-        final CountDownLatch latch = new CountDownLatch(2);
-
-        final class ProbeThread extends Thread {
-            private final boolean mIsHttps;
-            private volatile CaptivePortalProbeResult mResult = CaptivePortalProbeResult.FAILED;
-
-            public ProbeThread(boolean isHttps) {
-                mIsHttps = isHttps;
-            }
-
-            public CaptivePortalProbeResult result() {
-                return mResult;
-            }
-
-            @Override
-            public void run() {
-                if (mIsHttps) {
-                    mResult =
-                            sendDnsAndHttpProbes(proxy, httpsUrl, ValidationProbeEvent.PROBE_HTTPS);
-                } else {
-                    mResult = sendDnsAndHttpProbes(proxy, httpUrl, ValidationProbeEvent.PROBE_HTTP);
-                }
-                if ((mIsHttps && mResult.isSuccessful()) || (!mIsHttps && mResult.isPortal())) {
-                    // Stop waiting immediately if https succeeds or if http finds a portal.
-                    while (latch.getCount() > 0) {
-                        latch.countDown();
-                    }
-                }
-                // Signal this probe has completed.
-                latch.countDown();
-            }
-        }
-
-        final ProbeThread httpsProbe = new ProbeThread(true);
-        final ProbeThread httpProbe = new ProbeThread(false);
-
-        try {
-            httpsProbe.start();
-            httpProbe.start();
-            latch.await(PROBE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        } catch (InterruptedException e) {
-            validationLog("Error: probes wait interrupted!");
-            return CaptivePortalProbeResult.FAILED;
-        }
-
-        final CaptivePortalProbeResult httpsResult = httpsProbe.result();
-        final CaptivePortalProbeResult httpResult = httpProbe.result();
-
-        // Look for a conclusive probe result first.
-        if (httpResult.isPortal()) {
-            return httpResult;
-        }
-        // httpsResult.isPortal() is not expected, but check it nonetheless.
-        if (httpsResult.isPortal() || httpsResult.isSuccessful()) {
-            return httpsResult;
-        }
-        // If a fallback method exists, use it to retry portal detection.
-        // If we have new-style probe specs, use those. Otherwise, use the fallback URLs.
-        final CaptivePortalProbeSpec probeSpec = nextFallbackSpec();
-        final URL fallbackUrl = (probeSpec != null) ? probeSpec.getUrl() : nextFallbackUrl();
-        if (fallbackUrl != null) {
-            CaptivePortalProbeResult result = sendHttpProbe(fallbackUrl, PROBE_FALLBACK, probeSpec);
-            if (result.isPortal()) {
-                return result;
-            }
-        }
-        // Otherwise wait until http and https probes completes and use their results.
-        try {
-            httpProbe.join();
-            if (httpProbe.result().isPortal()) {
-                return httpProbe.result();
-            }
-            httpsProbe.join();
-            return httpsProbe.result();
-        } catch (InterruptedException e) {
-            validationLog("Error: http or https probe wait interrupted!");
-            return CaptivePortalProbeResult.FAILED;
-        }
-    }
-
-    private URL makeURL(String url) {
-        if (url != null) {
-            try {
-                return new URL(url);
-            } catch (MalformedURLException e) {
-                validationLog("Bad URL: " + url);
-            }
-        }
-        return null;
-    }
-
-    /**
-     * @param responseReceived - whether or not we received a valid HTTP response to our request.
-     * If false, isCaptivePortal and responseTimestampMs are ignored
-     * TODO: This should be moved to the transports.  The latency could be passed to the transports
-     * along with the captive portal result.  Currently the TYPE_MOBILE broadcasts appear unused so
-     * perhaps this could just be added to the WiFi transport only.
-     */
-    private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal,
-            long requestTimestampMs, long responseTimestampMs) {
-        if (getWifiScansAlwaysAvailableDisabled()) {
-            return;
-        }
-
-        if (!systemReady) {
-            return;
-        }
-
-        Intent latencyBroadcast =
-                new Intent(ConnectivityConstants.ACTION_NETWORK_CONDITIONS_MEASURED);
-        switch (mNetworkAgentInfo.networkInfo.getType()) {
-            case ConnectivityManager.TYPE_WIFI:
-                WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
-                if (currentWifiInfo != null) {
-                    // NOTE: getSSID()'s behavior changed in API 17; before that, SSIDs were not
-                    // surrounded by double quotation marks (thus violating the Javadoc), but this
-                    // was changed to match the Javadoc in API 17. Since clients may have started
-                    // sanitizing the output of this method since API 17 was released, we should
-                    // not change it here as it would become impossible to tell whether the SSID is
-                    // simply being surrounded by quotes due to the API, or whether those quotes
-                    // are actually part of the SSID.
-                    latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_SSID,
-                            currentWifiInfo.getSSID());
-                    latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_BSSID,
-                            currentWifiInfo.getBSSID());
-                } else {
-                    if (VDBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
-                    return;
-                }
-                break;
-            case ConnectivityManager.TYPE_MOBILE:
-                latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_NETWORK_TYPE,
-                        mTelephonyManager.getNetworkType());
-                List<CellInfo> info = mTelephonyManager.getAllCellInfo();
-                if (info == null) return;
-                int numRegisteredCellInfo = 0;
-                for (CellInfo cellInfo : info) {
-                    if (cellInfo.isRegistered()) {
-                        numRegisteredCellInfo++;
-                        if (numRegisteredCellInfo > 1) {
-                            if (VDBG) logw("more than one registered CellInfo." +
-                                    " Can't tell which is active.  Bailing.");
-                            return;
-                        }
-                        if (cellInfo instanceof CellInfoCdma) {
-                            CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
-                        } else if (cellInfo instanceof CellInfoGsm) {
-                            CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
-                        } else if (cellInfo instanceof CellInfoLte) {
-                            CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
-                        } else if (cellInfo instanceof CellInfoWcdma) {
-                            CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
-                            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
-                        } else {
-                            if (VDBG) logw("Registered cellinfo is unrecognized");
-                            return;
-                        }
-                    }
-                }
-                break;
-            default:
-                return;
-        }
-        latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CONNECTIVITY_TYPE,
-                mNetworkAgentInfo.networkInfo.getType());
-        latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_RESPONSE_RECEIVED,
-                responseReceived);
-        latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_REQUEST_TIMESTAMP_MS,
-                requestTimestampMs);
-
-        if (responseReceived) {
-            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_IS_CAPTIVE_PORTAL,
-                    isCaptivePortal);
-            latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_RESPONSE_TIMESTAMP_MS,
-                    responseTimestampMs);
-        }
-        mContext.sendBroadcastAsUser(latencyBroadcast, UserHandle.CURRENT,
-                ConnectivityConstants.PERMISSION_ACCESS_NETWORK_CONDITIONS);
-    }
-
-    private void logNetworkEvent(int evtype) {
-        int[] transports = mNetworkAgentInfo.networkCapabilities.getTransportTypes();
-        mMetricsLog.log(mNetId, transports, new NetworkEvent(evtype));
-    }
-
-    private int networkEventType(ValidationStage s, EvaluationResult r) {
-        if (s.isFirstValidation) {
-            if (r.isValidated) {
-                return NetworkEvent.NETWORK_FIRST_VALIDATION_SUCCESS;
-            } else {
-                return NetworkEvent.NETWORK_FIRST_VALIDATION_PORTAL_FOUND;
-            }
-        } else {
-            if (r.isValidated) {
-                return NetworkEvent.NETWORK_REVALIDATION_SUCCESS;
-            } else {
-                return NetworkEvent.NETWORK_REVALIDATION_PORTAL_FOUND;
-            }
-        }
-    }
-
-    private void maybeLogEvaluationResult(int evtype) {
-        if (mEvaluationTimer.isRunning()) {
-            int[] transports = mNetworkAgentInfo.networkCapabilities.getTransportTypes();
-            mMetricsLog.log(mNetId, transports, new NetworkEvent(evtype, mEvaluationTimer.stop()));
-            mEvaluationTimer.reset();
-        }
-    }
-
-    private void logValidationProbe(long durationMs, int probeType, int probeResult) {
-        int[] transports = mNetworkAgentInfo.networkCapabilities.getTransportTypes();
-        boolean isFirstValidation = validationStage().isFirstValidation;
-        ValidationProbeEvent ev = new ValidationProbeEvent();
-        ev.probeType = ValidationProbeEvent.makeProbeType(probeType, isFirstValidation);
-        ev.returnCode = probeResult;
-        ev.durationMs = durationMs;
-        mMetricsLog.log(mNetId, transports, ev);
-    }
-
-    @VisibleForTesting
-    public static class Dependencies {
-        public Network getNetwork(NetworkAgentInfo networkAgentInfo) {
-            return new OneAddressPerFamilyNetwork(networkAgentInfo.network());
-        }
-
-        public Random getRandom() {
-            return new Random();
-        }
-
-        public int getSetting(Context context, String symbol, int defaultValue) {
-            return Settings.Global.getInt(context.getContentResolver(), symbol, defaultValue);
-        }
-
-        public String getSetting(Context context, String symbol, String defaultValue) {
-            final String value = Settings.Global.getString(context.getContentResolver(), symbol);
-            return value != null ? value : defaultValue;
-        }
-
-        public static final Dependencies DEFAULT = new Dependencies();
-    }
-
-    /**
-     * Methods in this class perform no locking because all accesses are performed on the state
-     * machine's thread. Need to consider the thread safety if it ever could be accessed outside the
-     * state machine.
-     */
-    @VisibleForTesting
-    protected class DnsStallDetector {
-        private static final int DEFAULT_DNS_LOG_SIZE = 50;
-        private int mConsecutiveTimeoutCount = 0;
-        private int mSize;
-        final DnsResult[] mDnsEvents;
-        final RingBufferIndices mResultIndices;
-
-        DnsStallDetector(int size) {
-            mSize = Math.max(DEFAULT_DNS_LOG_SIZE, size);
-            mDnsEvents = new DnsResult[mSize];
-            mResultIndices = new RingBufferIndices(mSize);
-        }
-
-        @VisibleForTesting
-        protected void accumulateConsecutiveDnsTimeoutCount(int code) {
-            final DnsResult result = new DnsResult(code);
-            mDnsEvents[mResultIndices.add()] = result;
-            if (result.isTimeout()) {
-                mConsecutiveTimeoutCount++;
-            } else {
-                // Keep the event in mDnsEvents without clearing it so that there are logs to do the
-                // simulation and analysis.
-                mConsecutiveTimeoutCount = 0;
-            }
-        }
-
-        private boolean isDataStallSuspected(int timeoutCountThreshold, int validTime) {
-            if (timeoutCountThreshold <= 0) {
-                Log.wtf(TAG, "Timeout count threshold should be larger than 0.");
-                return false;
-            }
-
-            // Check if the consecutive timeout count reach the threshold or not.
-            if (mConsecutiveTimeoutCount < timeoutCountThreshold) {
-                return false;
-            }
-
-            // Check if the target dns event index is valid or not.
-            final int firstConsecutiveTimeoutIndex =
-                    mResultIndices.indexOf(mResultIndices.size() - timeoutCountThreshold);
-
-            // If the dns timeout events happened long time ago, the events are meaningless for
-            // data stall evaluation. Thus, check if the first consecutive timeout dns event
-            // considered in the evaluation happened in defined threshold time.
-            final long now = SystemClock.elapsedRealtime();
-            final long firstTimeoutTime = now - mDnsEvents[firstConsecutiveTimeoutIndex].mTimeStamp;
-            return (firstTimeoutTime < validTime);
-        }
-
-        int getConsecutiveTimeoutCount() {
-            return mConsecutiveTimeoutCount;
-        }
-    }
-
-    private static class DnsResult {
-        // TODO: Need to move the DNS return code definition to a specific class once unify DNS
-        // response code is done.
-        private static final int RETURN_CODE_DNS_TIMEOUT = 255;
-
-        private final long mTimeStamp;
-        private final int mReturnCode;
-
-        DnsResult(int code) {
-            mTimeStamp = SystemClock.elapsedRealtime();
-            mReturnCode = code;
-        }
-
-        private boolean isTimeout() {
-            return mReturnCode == RETURN_CODE_DNS_TIMEOUT;
-        }
-    }
-
-
-    @VisibleForTesting
-    protected DnsStallDetector getDnsStallDetector() {
-        return mDnsStallDetector;
-    }
-
-    private boolean dataStallEvaluateTypeEnabled(int type) {
-        return (mDataStallEvaluationType & (1 << type)) != 0;
-    }
-
-    @VisibleForTesting
-    protected long getLastProbeTime() {
-        return mLastProbeTime;
-    }
-
-    @VisibleForTesting
-    protected boolean isDataStall() {
-        boolean result = false;
-        // Reevaluation will generate traffic. Thus, set a minimal reevaluation timer to limit the
-        // possible traffic cost in metered network.
-        if (mNetworkAgentInfo.networkCapabilities.isMetered()
-                && (SystemClock.elapsedRealtime() - getLastProbeTime()
-                < mDataStallMinEvaluateTime)) {
-            return false;
-        }
-
-        // Check dns signal. Suspect it may be a data stall if both :
-        // 1. The number of consecutive DNS query timeouts > mConsecutiveDnsTimeoutThreshold.
-        // 2. Those consecutive DNS queries happened in the last mValidDataStallDnsTimeThreshold ms.
-        if (dataStallEvaluateTypeEnabled(DATA_STALL_EVALUATION_TYPE_DNS)) {
-            if (mDnsStallDetector.isDataStallSuspected(mConsecutiveDnsTimeoutThreshold,
-                    mDataStallValidDnsTimeThreshold)) {
-                result = true;
-                logNetworkEvent(NetworkEvent.NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND);
-            }
-        }
-
-        if (VDBG_STALL) {
-            log("isDataStall: result=" + result + ", consecutive dns timeout count="
-                    + mDnsStallDetector.getConsecutiveTimeoutCount());
-        }
-
-        return result;
-    }
-}
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 3ea9810..9789688 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -282,6 +282,7 @@
     private void setCurrentProxyScript(String script) {
         if (mProxyService == null) {
             Log.e(TAG, "setCurrentProxyScript: no proxy service");
+            return;
         }
         try {
             mProxyService.setPacFile(script);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 9dfdddb..eb5be77 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1837,7 +1837,7 @@
         final TetherState tetherState = new TetherState(
                 new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
                              makeControlCallback(), mConfig.enableLegacyDhcpServer,
-                             mDeps.getIpServerDependencies()));
+                             mDeps.getIpServerDependencies(mContext)));
         mTetherStates.put(iface, tetherState);
         tetherState.ipServer.start();
     }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 602aedb..c72c9dd 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -60,7 +60,6 @@
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.UidRange;
-import android.net.Uri;
 import android.net.VpnService;
 import android.os.Binder;
 import android.os.Build.VERSION_CODES;
@@ -71,7 +70,6 @@
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
-import android.os.PatternMatcher;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -100,6 +98,8 @@
 import com.android.server.LocalServices;
 import com.android.server.net.BaseNetworkObserver;
 
+import libcore.io.IoUtils;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -121,8 +121,6 @@
 import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import libcore.io.IoUtils;
-
 /**
  * @hide
  */
@@ -346,11 +344,18 @@
      *
      * @return {@code true} if VPN lockdown is enabled.
      */
-    public boolean getLockdown() {
+    public synchronized boolean getLockdown() {
         return mLockdown;
     }
 
     /**
+     * Returns whether VPN is configured as always-on.
+     */
+    public synchronized boolean getAlwaysOn() {
+        return mAlwaysOn;
+    }
+
+    /**
      * Checks if a VPN app supports always-on mode.
      *
      * In order to support the always-on feature, an app has to
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 d56b167..a42efe9 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -34,32 +34,53 @@
  * @hide
  */
 public class TetheringDependencies {
+    /**
+     * Get a reference to the offload hardware interface to be used by tethering.
+     */
     public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
         return new OffloadHardwareInterface(h, log);
     }
 
+    /**
+     * Get a reference to the UpstreamNetworkMonitor to be used by tethering.
+     */
     public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx, StateMachine target,
             SharedLog log, int what) {
         return new UpstreamNetworkMonitor(ctx, target, log, what);
     }
 
+    /**
+     * Get a reference to the IPv6TetheringCoordinator to be used by tethering.
+     */
     public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
             ArrayList<IpServer> notifyList, SharedLog log) {
         return new IPv6TetheringCoordinator(notifyList, log);
     }
 
-    public IpServer.Dependencies getIpServerDependencies() {
-        return new IpServer.Dependencies();
+    /**
+     * Get dependencies to be used by IpServer.
+     */
+    public IpServer.Dependencies getIpServerDependencies(Context context) {
+        return new IpServer.Dependencies(context);
     }
 
+    /**
+     * Indicates whether tethering is supported on the device.
+     */
     public boolean isTetheringSupported() {
         return true;
     }
 
+    /**
+     * Get the NetworkRequest that should be fulfilled by the default network.
+     */
     public NetworkRequest getDefaultNetworkRequest() {
         return null;
     }
 
+    /**
+     * Get a reference to the EntitlementManager to be used by tethering.
+     */
     public EntitlementManager getEntitlementManager(Context ctx, SharedLog log,
             MockableSystemProperties systemProperties) {
         return new EntitlementManager(ctx, log, systemProperties);
diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java
index bfcc629..aaf9cbc 100644
--- a/services/core/java/com/android/server/content/SyncJobService.java
+++ b/services/core/java/com/android/server/content/SyncJobService.java
@@ -141,10 +141,7 @@
             final long runtime = nowUptime - startUptime;
 
 
-            if (startUptime == 0) {
-                wtf("Job " + jobId + " start uptime not found: "
-                        + " params=" + jobParametersToString(params));
-            } else if (runtime > 60 * 1000) {
+            if (runtime > 60 * 1000) {
                 // WTF if startSyncH() hasn't happened, *unless* onStopJob() was called too soon.
                 // (1 minute threshold.)
                 // Also don't wtf when it's not ready to sync.
diff --git a/services/core/java/com/android/server/content/SyncLogger.java b/services/core/java/com/android/server/content/SyncLogger.java
index 5cbe5b9..fc20ef20 100644
--- a/services/core/java/com/android/server/content/SyncLogger.java
+++ b/services/core/java/com/android/server/content/SyncLogger.java
@@ -16,6 +16,7 @@
 
 package com.android.server.content;
 
+import android.accounts.Account;
 import android.app.job.JobParameters;
 import android.os.Build;
 import android.os.Environment;
@@ -31,6 +32,8 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IntPair;
 import com.android.server.IoThread;
+import com.android.server.content.SyncManager.ActiveSyncContext;
+import com.android.server.content.SyncStorageEngine.EndPoint;
 
 import libcore.io.IoUtils;
 
@@ -309,4 +312,20 @@
             }
         }
     }
+
+    static String logSafe(Account account) {
+        return account == null ? "[null]" : account.toSafeString();
+    }
+
+    static String logSafe(EndPoint endPoint) {
+        return endPoint == null ? "[null]" : endPoint.toSafeString();
+    }
+
+    static String logSafe(SyncOperation operation) {
+        return operation == null ? "[null]" : operation.toSafeString();
+    }
+
+    static String logSafe(ActiveSyncContext asc) {
+        return asc == null ? "[null]" : asc.toSafeString();
+    }
 }
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 8b93e04..7096477 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -16,6 +16,8 @@
 
 package com.android.server.content;
 
+import static com.android.server.content.SyncLogger.logSafe;
+
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
 import android.accounts.AccountManager;
@@ -1140,7 +1142,7 @@
             /* ignore - local call */
         }
         if (checkAccountAccess && !canAccessAccount(account, owningPackage, owningUid)) {
-            Log.w(TAG, "Access to " + account + " denied for package "
+            Log.w(TAG, "Access to " + logSafe(account) + " denied for package "
                     + owningPackage + " in UID " + syncAdapterInfo.uid);
             return AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS;
         }
@@ -1474,7 +1476,8 @@
         if (!syncOperation.ignoreBackoff()) {
             Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(syncOperation.target);
             if (backoff == null) {
-                Slog.e(TAG, "Couldn't find backoff values for " + syncOperation.target);
+                Slog.e(TAG, "Couldn't find backoff values for "
+                        + logSafe(syncOperation.target));
                 backoff = new Pair<Long, Long>(SyncStorageEngine.NOT_IN_BACKOFF_MODE,
                         SyncStorageEngine.NOT_IN_BACKOFF_MODE);
             }
@@ -1745,8 +1748,8 @@
             scheduleSyncOperationH(operation);
         } else {
             // Otherwise do not reschedule.
-            Log.d(TAG, "not retrying sync operation because the error is a hard error: "
-                    + operation);
+            Log.e(TAG, "not retrying sync operation because the error is a hard error: "
+                    + logSafe(operation));
         }
     }
 
@@ -1881,11 +1884,12 @@
             sendSyncFinishedOrCanceledMessage(this, result);
         }
 
-        public void toString(StringBuilder sb) {
+        public void toString(StringBuilder sb, boolean logSafe) {
             sb.append("startTime ").append(mStartTime)
                     .append(", mTimeoutStartTime ").append(mTimeoutStartTime)
                     .append(", mHistoryRowId ").append(mHistoryRowId)
-                    .append(", syncOperation ").append(mSyncOperation);
+                    .append(", syncOperation ").append(
+                        logSafe ? logSafe(mSyncOperation) : mSyncOperation);
         }
 
         public void onServiceConnected(ComponentName name, IBinder service) {
@@ -1947,7 +1951,13 @@
 
         public String toString() {
             StringBuilder sb = new StringBuilder();
-            toString(sb);
+            toString(sb, false);
+            return sb.toString();
+        }
+
+        public String toSafeString() {
+            StringBuilder sb = new StringBuilder();
+            toString(sb, true);
             return sb.toString();
         }
 
@@ -2036,7 +2046,7 @@
         int count = 0;
         for (SyncOperation op: pendingSyncs) {
             if (!op.isPeriodic) {
-                pw.println(op.dump(null, false, buckets));
+                pw.println(op.dump(null, false, buckets, /*logSafe=*/ false));
                 count++;
             }
         }
@@ -2053,7 +2063,7 @@
         int count = 0;
         for (SyncOperation op: pendingSyncs) {
             if (op.isPeriodic) {
-                pw.println(op.dump(null, false, buckets));
+                pw.println(op.dump(null, false, buckets, /*logSafe=*/ false));
                 count++;
             }
         }
@@ -2186,7 +2196,7 @@
             sb.setLength(0);
             pw.print(formatDurationHMS(sb, durationInSeconds));
             pw.print(" - ");
-            pw.print(activeSyncContext.mSyncOperation.dump(pm, false, buckets));
+            pw.print(activeSyncContext.mSyncOperation.dump(pm, false, buckets, /*logSafe=*/ false));
             pw.println();
         }
         pw.println();
@@ -2974,7 +2984,7 @@
                     case SyncHandler.MESSAGE_CANCEL:
                         SyncStorageEngine.EndPoint endpoint = (SyncStorageEngine.EndPoint) msg.obj;
                         Bundle extras = msg.peekData();
-                        if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        if (isLoggable) {
                             Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_CANCEL: "
                                     + endpoint + " bundle: " + extras);
                         }
@@ -2985,9 +2995,11 @@
                         SyncFinishedOrCancelledMessagePayload payload =
                                 (SyncFinishedOrCancelledMessagePayload) msg.obj;
                         if (!isSyncStillActiveH(payload.activeSyncContext)) {
-                            Log.d(TAG, "handleSyncHandlerMessage: dropping since the "
-                                    + "sync is no longer active: "
-                                    + payload.activeSyncContext);
+                            if (isLoggable) {
+                                Log.d(TAG, "handleSyncHandlerMessage: dropping since the "
+                                        + "sync is no longer active: "
+                                        + payload.activeSyncContext);
+                            }
                             break;
                         }
                         if (isLoggable) {
@@ -3002,7 +3014,7 @@
 
                     case SyncHandler.MESSAGE_SERVICE_CONNECTED: {
                         ServiceConnectionData msgData = (ServiceConnectionData) msg.obj;
-                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        if (isLoggable) {
                             Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: "
                                     + msgData.activeSyncContext);
                         }
@@ -3018,7 +3030,7 @@
                     case SyncHandler.MESSAGE_SERVICE_DISCONNECTED: {
                         final ActiveSyncContext currentSyncContext =
                                 ((ServiceConnectionData) msg.obj).activeSyncContext;
-                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        if (isLoggable) {
                             Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_DISCONNECTED: "
                                     + currentSyncContext);
                         }
@@ -3053,7 +3065,7 @@
 
                     case SyncHandler.MESSAGE_MONITOR_SYNC:
                         ActiveSyncContext monitoredSyncContext = (ActiveSyncContext) msg.obj;
-                        if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        if (isLoggable) {
                             Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_MONITOR_SYNC: " +
                                     monitoredSyncContext.mSyncOperation.target);
                         }
@@ -3061,7 +3073,7 @@
                         if (isSyncNotUsingNetworkH(monitoredSyncContext)) {
                             Log.w(TAG, String.format(
                                     "Detected sync making no progress for %s. cancelling.",
-                                    monitoredSyncContext));
+                                    logSafe(monitoredSyncContext)));
                             SyncJobService.callJobFinished(
                                     monitoredSyncContext.mSyncOperation.jobId, false,
                                     "no network activity");
@@ -3558,7 +3570,8 @@
             } catch (RuntimeException exc) {
                 mLogger.log("Sync failed with RuntimeException: ", exc.toString());
                 closeActiveSyncContext(activeSyncContext);
-                Slog.e(TAG, "Caught RuntimeException while starting the sync " + syncOperation, exc);
+                Slog.e(TAG, "Caught RuntimeException while starting the sync "
+                        + logSafe(syncOperation), exc);
             }
         }
 
@@ -3658,7 +3671,8 @@
                         reschedulePeriodicSyncH(syncOperation);
                     }
                 } else {
-                    Log.w(TAG, "failed sync operation " + syncOperation + ", " + syncResult);
+                    Log.w(TAG, "failed sync operation "
+                            + logSafe(syncOperation) + ", " + syncResult);
 
                     syncOperation.retries++;
                     if (syncOperation.retries > mConstants.getMaxRetriesWithAppStandbyExemption()) {
@@ -4042,11 +4056,6 @@
         getJobScheduler().cancel(op.jobId);
     }
 
-    private void wtfWithLog(String message) {
-        Slog.wtf(TAG, message);
-        mLogger.log("WTF: ", message);
-    }
-
     public void resetTodayStats() {
         mSyncStorageEngine.resetTodayStats(/*force=*/ true);
     }
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 25edf40..2abc2e6 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -363,14 +363,19 @@
 
     @Override
     public String toString() {
-        return dump(null, true, null);
+        return dump(null, true, null, false);
     }
 
-    String dump(PackageManager pm, boolean shorter, SyncAdapterStateFetcher appStates) {
+    public String toSafeString() {
+        return dump(null, true, null, true);
+    }
+
+    String dump(PackageManager pm, boolean shorter, SyncAdapterStateFetcher appStates,
+            boolean logSafe) {
         StringBuilder sb = new StringBuilder();
         sb.append("JobId=").append(jobId)
                 .append(" ")
-                .append(target.account.name)
+                .append(logSafe ? "***" : target.account.name)
                 .append("/")
                 .append(target.account.type)
                 .append(" u")
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index bfd1791..6b441a0 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -16,6 +16,8 @@
 
 package com.android.server.content;
 
+import static com.android.server.content.SyncLogger.logSafe;
+
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
 import android.accounts.AccountManager;
@@ -225,6 +227,15 @@
             sb.append(":u" + userId);
             return sb.toString();
         }
+
+        public String toSafeString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(account == null ? "ALL ACCS" : logSafe(account))
+                    .append("/")
+                    .append(provider == null ? "ALL PDRS" : provider);
+            sb.append(":u" + userId);
+            return sb.toString();
+        }
     }
 
     public static class AuthorityInfo {
@@ -1861,8 +1872,8 @@
 
                 }
             } else {
-                Slog.w(TAG, "Failure adding authority: account="
-                        + accountName + " auth=" + authorityName
+                Slog.w(TAG, "Failure adding authority:"
+                        + " auth=" + authorityName
                         + " enabled=" + enabled
                         + " syncable=" + syncable);
             }
diff --git a/services/core/java/com/android/server/display/AppSaturationController.java b/services/core/java/com/android/server/display/AppSaturationController.java
new file mode 100644
index 0000000..5d5e4f7
--- /dev/null
+++ b/services/core/java/com/android/server/display/AppSaturationController.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import android.annotation.UserIdInt;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.ColorDisplayService.ColorTransformController;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+class AppSaturationController {
+
+    private final Object mLock = new Object();
+
+    /**
+     * A package name has one or more userIds it is running under. Each userId has zero or one
+     * saturation level, and zero or more ColorTransformControllers.
+     */
+    @GuardedBy("mLock")
+    private final Map<String, SparseArray<SaturationController>> mAppsMap = new HashMap<>();
+
+    @VisibleForTesting
+    static final float[] TRANSLATION_VECTOR = {0f, 0f, 0f};
+
+    /**
+     * Add an {@link WeakReference<ColorTransformController>} for a given package and userId.
+     */
+    boolean addColorTransformController(String packageName, @UserIdInt int userId,
+            WeakReference<ColorTransformController> controller) {
+        synchronized (mLock) {
+            return getSaturationControllerLocked(packageName, userId)
+                    .addColorTransformController(controller);
+        }
+    }
+
+    /**
+     * Set the saturation level ({@code ColorDisplayManager#SaturationLevel} constant for a given
+     * package name and userId.
+     */
+    public boolean setSaturationLevel(String packageName, @UserIdInt int userId,
+            int saturationLevel) {
+        synchronized (mLock) {
+            return getSaturationControllerLocked(packageName, userId)
+                    .setSaturationLevel(saturationLevel);
+        }
+    }
+
+    /**
+     * Dump state information.
+     */
+    public void dump(PrintWriter pw) {
+        synchronized (mLock) {
+            pw.println("App Saturation: ");
+            if (mAppsMap.size() == 0) {
+                pw.println("    No packages");
+                return;
+            }
+            final List<String> packageNames = new ArrayList<>(mAppsMap.keySet());
+            Collections.sort(packageNames);
+            for (String packageName : packageNames) {
+                pw.println("    " + packageName + ":");
+                final SparseArray<SaturationController> appUserIdMap = mAppsMap.get(packageName);
+                for (int i = 0; i < appUserIdMap.size(); i++) {
+                    pw.println("        " + appUserIdMap.keyAt(i) + ":");
+                    appUserIdMap.valueAt(i).dump(pw);
+                }
+            }
+        }
+    }
+
+    /**
+     * Retrieve the SaturationController for a given package and userId, creating all intermediate
+     * connections as needed.
+     */
+    private SaturationController getSaturationControllerLocked(String packageName,
+            @UserIdInt int userId) {
+        return getOrCreateSaturationControllerLocked(getOrCreateUserIdMapLocked(packageName),
+                userId);
+    }
+
+    /**
+     * Retrieve or create the mapping between the app's given package name and its userIds (and
+     * their SaturationControllers).
+     */
+    private SparseArray<SaturationController> getOrCreateUserIdMapLocked(String packageName) {
+        if (mAppsMap.get(packageName) != null) {
+            return mAppsMap.get(packageName);
+        }
+
+        final SparseArray<SaturationController> appUserIdMap = new SparseArray<>();
+        mAppsMap.put(packageName, appUserIdMap);
+        return appUserIdMap;
+    }
+
+    /**
+     * Retrieve or create the mapping between an app's given userId and SaturationController.
+     */
+    private SaturationController getOrCreateSaturationControllerLocked(
+            SparseArray<SaturationController> appUserIdMap, @UserIdInt int userId) {
+        if (appUserIdMap.get(userId) != null) {
+            return appUserIdMap.get(userId);
+        }
+
+        final SaturationController saturationController = new SaturationController();
+        appUserIdMap.put(userId, saturationController);
+        return saturationController;
+    }
+
+    @VisibleForTesting
+    static void computeGrayscaleTransformMatrix(float saturation, float[] matrix) {
+        float desaturation = 1.0f - saturation;
+        float[] luminance = {0.231f * desaturation, 0.715f * desaturation,
+                0.072f * desaturation};
+        matrix[0] = luminance[0] + saturation;
+        matrix[1] = luminance[0];
+        matrix[2] = luminance[0];
+        matrix[3] = luminance[1];
+        matrix[4] = luminance[1] + saturation;
+        matrix[5] = luminance[1];
+        matrix[6] = luminance[2];
+        matrix[7] = luminance[2];
+        matrix[8] = luminance[2] + saturation;
+    }
+
+    private static class SaturationController {
+
+        private final List<WeakReference<ColorTransformController>> mControllerRefs =
+                new ArrayList<>();
+        private int mSaturationLevel = 100;
+        private float[] mTransformMatrix = new float[9];
+
+        private boolean setSaturationLevel(int saturationLevel) {
+            mSaturationLevel = saturationLevel;
+            if (!mControllerRefs.isEmpty()) {
+                return updateState();
+            }
+            return false;
+        }
+
+        private boolean addColorTransformController(
+                WeakReference<ColorTransformController> controller) {
+            mControllerRefs.add(controller);
+            if (mSaturationLevel != 100) {
+                return updateState();
+            } else {
+                clearExpiredReferences();
+            }
+            return false;
+        }
+
+        private boolean updateState() {
+            computeGrayscaleTransformMatrix(mSaturationLevel / 100f, mTransformMatrix);
+
+            boolean updated = false;
+            final Iterator<WeakReference<ColorTransformController>> iterator = mControllerRefs
+                    .iterator();
+            while (iterator.hasNext()) {
+                WeakReference<ColorTransformController> controllerRef = iterator.next();
+                final ColorTransformController controller = controllerRef.get();
+                if (controller != null) {
+                    controller.applyAppSaturation(mTransformMatrix, TRANSLATION_VECTOR);
+                    updated = true;
+                } else {
+                    // Purge cleared refs lazily to avoid accumulating a lot of dead windows
+                    iterator.remove();
+                }
+            }
+            return updated;
+
+        }
+
+        private void clearExpiredReferences() {
+            final Iterator<WeakReference<ColorTransformController>> iterator = mControllerRefs
+                    .iterator();
+            while (iterator.hasNext()) {
+                WeakReference<ColorTransformController> controllerRef = iterator.next();
+                final ColorTransformController controller = controllerRef.get();
+                if (controller == null) {
+                    iterator.remove();
+                }
+            }
+        }
+
+        private void dump(PrintWriter pw) {
+            pw.println("            mSaturationLevel: " + mSaturationLevel);
+            pw.println("            mControllerRefs count: " + mControllerRefs.size());
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 52eccca..d57431e 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -17,13 +17,12 @@
 package com.android.server.display;
 
 import android.annotation.Nullable;
-import android.app.ActivityManager;
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
 import android.app.TaskStackListener;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageManager;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
@@ -34,7 +33,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
@@ -45,7 +43,6 @@
 
 import com.android.internal.os.BackgroundThread;
 import com.android.server.EventLogTags;
-import com.android.server.LocalServices;
 
 import java.io.PrintWriter;
 
@@ -66,13 +63,6 @@
     // the user is satisfied with the result before storing the sample.
     private static final int BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS = 10000;
 
-    // Timeout after which we remove the effects any user interactions might've had on the
-    // brightness mapping. This timeout doesn't start until we transition to a non-interactive
-    // display policy so that we don't reset while users are using their devices, but also so that
-    // we don't erroneously keep the short-term model if the device is dozing but the display is
-    // fully on.
-    private static final int SHORT_TERM_MODEL_TIMEOUT_MILLIS = 30000;
-
     private static final int MSG_UPDATE_AMBIENT_LUX = 1;
     private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
     private static final int MSG_INVALIDATE_SHORT_TERM_MODEL = 3;
@@ -140,6 +130,13 @@
 
     private boolean mLoggingEnabled;
 
+    // Timeout after which we remove the effects any user interactions might've had on the
+    // brightness mapping. This timeout doesn't start until we transition to a non-interactive
+    // display policy so that we don't reset while users are using their devices, but also so that
+    // we don't erroneously keep the short-term model if the device is dozing but the display is
+    // fully on.
+    private long mShortTermModelTimeout;
+
     // Amount of time to delay auto-brightness after screen on while waiting for
     // the light sensor to warm-up in milliseconds.
     // May be 0 if no warm-up is required.
@@ -210,14 +207,13 @@
     // package name and category, which is done by registering a TaskStackListener to call back to
     // us onTaskStackChanged, and then using the ActivityTaskManager to get the foreground app's
     // package namd and PackageManager to get its category (so might as well cache them).
-    private int mUserId;
     private String mForegroundAppPackageName;
     private String mPendingForegroundAppPackageName;
     private @ApplicationInfo.Category int mForegroundAppCategory;
     private @ApplicationInfo.Category int mPendingForegroundAppCategory;
     private TaskStackListenerImpl mTaskStackListener;
     private IActivityTaskManager mActivityTaskManager;
-    private PackageManagerInternal mPackageManagerInternal;
+    private PackageManager mPackageManager;
 
     public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
             SensorManager sensorManager, BrightnessMappingStrategy mapper,
@@ -225,7 +221,8 @@
             int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
             long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
             HysteresisLevels ambientBrightnessThresholds,
-            HysteresisLevels screenBrightnessThresholds) {
+            HysteresisLevels screenBrightnessThresholds, long shortTermModelTimeout,
+            PackageManager packageManager) {
         mCallbacks = callbacks;
         mSensorManager = sensorManager;
         mBrightnessMapper = mapper;
@@ -243,6 +240,7 @@
         mWeightingIntercept = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
         mAmbientBrightnessThresholds = ambientBrightnessThresholds;
         mScreenBrightnessThresholds = screenBrightnessThresholds;
+        mShortTermModelTimeout = shortTermModelTimeout;
         mShortTermModelValid = true;
         mShortTermModelAnchor = -1;
 
@@ -254,9 +252,8 @@
             mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
         }
 
-        mUserId = ActivityManager.getCurrentUser();
         mActivityTaskManager = ActivityTaskManager.getService();
-        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+        mPackageManager = packageManager;
         mTaskStackListener = new TaskStackListenerImpl();
         mForegroundAppPackageName = null;
         mPendingForegroundAppPackageName = null;
@@ -281,16 +278,6 @@
         return true;
     }
 
-    /**
-     * Update the current user's ID.
-     *
-     * @param userId
-     *      The current user's ID.
-     */
-    public void onSwitchUser(int userId) {
-        mUserId = userId;
-    }
-
     public int getAutomaticScreenBrightness() {
         if (!mAmbientLuxValid) {
             return -1;
@@ -358,7 +345,7 @@
         }
         if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) {
             mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL,
-                    SHORT_TERM_MODEL_TIMEOUT_MILLIS);
+                    mShortTermModelTimeout);
         } else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) {
             mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL);
         }
@@ -440,13 +427,13 @@
         pw.println("  mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
         pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
         pw.println("  mDisplayPolicy=" + DisplayPowerRequest.policyToString(mDisplayPolicy));
+        pw.println("  mShortTermModelTimeout=" + mShortTermModelTimeout);
         pw.println("  mShortTermModelAnchor=" + mShortTermModelAnchor);
         pw.println("  mShortTermModelValid=" + mShortTermModelValid);
         pw.println("  mBrightnessAdjustmentSamplePending=" + mBrightnessAdjustmentSamplePending);
         pw.println("  mBrightnessAdjustmentSampleOldLux=" + mBrightnessAdjustmentSampleOldLux);
         pw.println("  mBrightnessAdjustmentSampleOldBrightness="
                 + mBrightnessAdjustmentSampleOldBrightness);
-        pw.println("  mUserId=" + mUserId);
         pw.println("  mForegroundAppPackageName=" + mForegroundAppPackageName);
         pw.println("  mPendingForegroundAppPackageName=" + mPendingForegroundAppPackageName);
         pw.println("  mForegroundAppCategory=" + mForegroundAppCategory);
@@ -787,6 +774,13 @@
                 BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS);
     }
 
+    private void cancelBrightnessAdjustmentSample() {
+        if (mBrightnessAdjustmentSamplePending) {
+            mBrightnessAdjustmentSamplePending = false;
+            mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
+        }
+    }
+
     private void collectBrightnessAdjustmentSample() {
         if (mBrightnessAdjustmentSamplePending) {
             mBrightnessAdjustmentSamplePending = false;
@@ -816,6 +810,9 @@
             // call it explicitly to get the current foreground app's info.
             updateForegroundApp();
         } catch (RemoteException e) {
+            if (mLoggingEnabled) {
+                Slog.e(TAG, "Failed to register foreground app updater: " + e);
+            }
             // Nothing to do.
         }
     }
@@ -832,6 +829,9 @@
 
     // Set the foreground app's package name and category, so brightness can be corrected per app.
     private void updateForegroundApp() {
+        if (mLoggingEnabled) {
+            Slog.d(TAG, "Attempting to update foreground app");
+        }
         // The ActivityTaskManager's lock tends to get contended, so this is done in a background
         // thread and applied via this thread's handler synchronously.
         BackgroundThread.getHandler().post(new Runnable() {
@@ -850,18 +850,27 @@
                         return;
                     }
                     mPendingForegroundAppPackageName = packageName;
-                    ApplicationInfo app = mPackageManagerInternal.getApplicationInfo(packageName,
-                            0 /* flags */, Process.SYSTEM_UID /* filterCallingUid */, mUserId);
-                    mPendingForegroundAppCategory = app.category;
+                    mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
+                    try {
+                        ApplicationInfo app = mPackageManager.getApplicationInfo(packageName,
+                                PackageManager.MATCH_ANY_USER);
+                        mPendingForegroundAppCategory = app.category;
+                    } catch (PackageManager.NameNotFoundException e) {
+                        // Nothing to do
+                    }
                     mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP_SYNC);
                 } catch (RemoteException e) {
-                    // Nothing to do.
+                    // Nothing to do
                 }
             }
         });
     }
 
     private void updateForegroundAppSync() {
+        if (mLoggingEnabled) {
+            Slog.d(TAG, "Updating foreground app: packageName=" + mPendingForegroundAppPackageName
+                    + ", category=" + mPendingForegroundAppCategory);
+        }
         mForegroundAppPackageName = mPendingForegroundAppPackageName;
         mPendingForegroundAppPackageName = null;
         mForegroundAppCategory = mPendingForegroundAppCategory;
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 73d3d95..3a58160 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -18,20 +18,27 @@
 
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION;
 
+import android.Manifest;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.TypeEvaluator;
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Size;
+import android.annotation.UserIdInt;
 import android.app.AlarmManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.graphics.ColorSpace;
 import android.hardware.display.ColorDisplayManager;
 import android.hardware.display.IColorDisplayManager;
 import android.net.Uri;
@@ -39,28 +46,36 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Message;
 import android.os.UserHandle;
 import android.provider.Settings.Secure;
 import android.provider.Settings.System;
 import android.util.MathUtils;
 import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AnimationUtils;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ColorDisplayController;
+import com.android.internal.util.DumpUtils;
 import com.android.server.DisplayThread;
 import com.android.server.SystemService;
 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;
+import java.lang.ref.WeakReference;
 import java.time.DateTimeException;
 import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.ZoneId;
 import java.time.format.DateTimeParseException;
+import java.util.Arrays;
 
 /**
  * Controls the display's color transforms.
@@ -83,6 +98,10 @@
         Matrix.setIdentityM(MATRIX_IDENTITY, 0);
     }
 
+    private static final int MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE = 0;
+    private static final int MSG_APPLY_NIGHT_DISPLAY_ANIMATED = 1;
+    private static final int MSG_APPLY_GLOBAL_SATURATION = 2;
+
     /**
      * Evaluator used to animate color matrix transitions.
      */
@@ -139,30 +158,280 @@
     };
 
     private final TintController mDisplayWhiteBalanceTintController = new TintController() {
+        // Three chromaticity coordinates per color: X, Y, and Z
+        private final int NUM_VALUES_PER_PRIMARY = 3;
+        // Four colors: red, green, blue, and white
+        private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
 
+        private final Object mLock = new Object();
+        private int mTemperatureMin;
+        private int mTemperatureMax;
+        private int mTemperatureDefault;
+        private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+        private ColorSpace.Rgb mDisplayColorSpaceRGB;
+        private float[] mChromaticAdaptationMatrix;
+        private int mCurrentColorTemperature;
+        private float[] mCurrentColorTemperatureXYZ;
+        private boolean mSetUp = false;
         private float[] mMatrixDisplayWhiteBalance = new float[16];
 
         @Override
         public void setUp(Context context, boolean needsLinear) {
+            mSetUp = false;
+
+            final Resources res = getContext().getResources();
+            final String[] displayPrimariesValues = res.getStringArray(
+                    R.array.config_displayWhiteBalanceDisplayPrimaries);
+            final String[] nominalWhiteValues = res.getStringArray(
+                    R.array.config_displayWhiteBalanceDisplayNominalWhite);
+
+            if (displayPrimariesValues.length != NUM_DISPLAY_PRIMARIES_VALS) {
+                Slog.e(TAG, "Unexpected display white balance primaries resource length " +
+                        displayPrimariesValues.length);
+                return;
+            }
+
+            if (nominalWhiteValues.length != NUM_VALUES_PER_PRIMARY) {
+                Slog.e(TAG, "Unexpected display white balance nominal white resource length " +
+                        nominalWhiteValues.length);
+                return;
+            }
+
+            float[] displayRedGreenBlueXYZ =
+                new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
+            float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+            for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) {
+                displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]);
+            }
+            for (int i = 0; i < displayWhiteXYZ.length; i++) {
+                displayWhiteXYZ[i] = Float.parseFloat(
+                        displayPrimariesValues[displayRedGreenBlueXYZ.length + i]);
+            }
+
+            final ColorSpace.Rgb displayColorSpaceRGB = new ColorSpace.Rgb(
+                "Display Color Space",
+                displayRedGreenBlueXYZ,
+                displayWhiteXYZ,
+                2.2f // gamma, unused for display white balance
+            );
+
+            float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+            for (int i = 0; i < nominalWhiteValues.length; i++) {
+                displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
+            }
+
+            final int colorTemperatureMin = res.getInteger(
+                    R.integer.config_displayWhiteBalanceColorTemperatureMin);
+            if (colorTemperatureMin <= 0) {
+                Slog.e(TAG, "display white balance minimum temperature must be greater than 0");
+                return;
+            }
+
+            final int colorTemperatureMax = res.getInteger(
+                    R.integer.config_displayWhiteBalanceColorTemperatureMax);
+            if (colorTemperatureMax < colorTemperatureMin) {
+                Slog.e(TAG, "display white balance max temp must be greater or equal to min");
+                return;
+            }
+
+            final int colorTemperature = res.getInteger(
+                    R.integer.config_displayWhiteBalanceColorTemperatureDefault);
+
+            synchronized (mLock) {
+                mDisplayColorSpaceRGB = displayColorSpaceRGB;
+                mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
+                mTemperatureMin = colorTemperatureMin;
+                mTemperatureMax = colorTemperatureMax;
+                mTemperatureDefault = colorTemperature;
+                mSetUp = true;
+            }
+
+            setMatrix(mTemperatureDefault);
+        }
+
+        @Override
+        public float[] getMatrix() {
+            return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
+        }
+
+        @Override
+        public void setMatrix(int cct) {
+            if (!mSetUp) {
+                Slog.w(TAG, "Can't set display white balance temperature: uninitialized");
+                return;
+            }
+
+            if (cct < mTemperatureMin) {
+                Slog.w(TAG, "Requested display color temperature is below allowed minimum");
+                cct = mTemperatureMin;
+            } else if (cct > mTemperatureMax) {
+                Slog.w(TAG, "Requested display color temperature is above allowed maximum");
+                cct = mTemperatureMax;
+            }
+
+            Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct);
+
+            synchronized (mLock) {
+                mCurrentColorTemperature = cct;
+
+                // Adapt the display's nominal white point to match the requested CCT value
+                mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
+
+                mChromaticAdaptationMatrix =
+                    ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
+                            mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
+
+                // Convert the adaptation matrix to RGB space
+                float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix,
+                        mDisplayColorSpaceRGB.getTransform());
+                result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
+
+                // Normalize the transform matrix to peak white value in RGB space
+                final float adaptedMaxR = result[0] + result[3] + result[6];
+                final float adaptedMaxG = result[1] + result[4] + result[7];
+                final float adaptedMaxB = result[2] + result[5] + result[8];
+                final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
+                for (int i = 0; i < result.length; i++) {
+                    result[i] /= denum;
+                }
+
+                Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
+                java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
+                java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
+                java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
+            }
+        }
+
+        @Override
+        public int getLevel() {
+            return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
+        }
+
+        /**
+         * Format a given matrix into a string.
+         *
+         * @param matrix the matrix to format
+         * @param cols number of columns in the matrix
+         */
+        private String matrixToString(float[] matrix, int cols) {
+            if (matrix == null || cols <= 0) {
+                Slog.e(TAG, "Invalid arguments when formatting matrix to string");
+                return "";
+            }
+
+            StringBuilder sb = new StringBuilder("");
+            for (int i = 0; i < matrix.length; i++) {
+                if (i % cols == 0) {
+                    sb.append("\n    ");
+                }
+                sb.append(String.format("%9.6f ", matrix[i]));
+            }
+            return sb.toString();
+        }
+
+        @Override
+        public void dump(PrintWriter pw) {
+            synchronized (mLock) {
+                pw.println("ColorDisplayService");
+                pw.println("  mSetUp = " + mSetUp);
+
+                if (!mSetUp) {
+                    return;
+                }
+
+                pw.println("  isActivated = " + isActivated());
+                pw.println("  mTemperatureMin = " + mTemperatureMin);
+                pw.println("  mTemperatureMax = " + mTemperatureMax);
+                pw.println("  mTemperatureDefault = " + mTemperatureDefault);
+                pw.println("  mCurrentColorTemperature = " + mCurrentColorTemperature);
+                pw.println("  mCurrentColorTemperatureXYZ = " +
+                        matrixToString(mCurrentColorTemperatureXYZ, 3));
+                pw.println("  mDisplayColorSpaceRGB RGB-to-XYZ = " +
+                        matrixToString(mDisplayColorSpaceRGB.getTransform(), 3));
+                pw.println("  mChromaticAdaptationMatrix = " +
+                        matrixToString(mChromaticAdaptationMatrix, 3));
+                pw.println("  mDisplayColorSpaceRGB XYZ-to-RGB = " +
+                        matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3));
+                pw.println("  mMatrixDisplayWhiteBalance = " +
+                        matrixToString(mMatrixDisplayWhiteBalance, 4));
+            }
+        }
+    };
+
+    private final TintController mGlobalSaturationTintController = new TintController() {
+
+        private float[] mMatrixGlobalSaturation = new float[16];
+
+        @Override
+        public void setUp(Context context, boolean needsLinear) {
         }
 
         @Override
         public float[] getMatrix() {
-            return isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
+            return Arrays.copyOf(mMatrixGlobalSaturation, mMatrixGlobalSaturation.length);
         }
 
         @Override
-        public void setMatrix(int cct) {
+        public void setMatrix(int saturationLevel) {
+            if (saturationLevel < 0) {
+                saturationLevel = 0;
+            } else if (saturationLevel > 100) {
+                saturationLevel = 100;
+            }
+            Slog.d(TAG, "Setting saturation level: " + saturationLevel);
+
+            if (saturationLevel == 100) {
+                Matrix.setIdentityM(mMatrixGlobalSaturation, 0);
+            } else {
+                float saturation = saturationLevel * 0.1f;
+                float desaturation = 1.0f - saturation;
+                float[] luminance = {0.231f * desaturation, 0.715f * desaturation,
+                    0.072f * desaturation};
+                mMatrixGlobalSaturation[0] = luminance[0] + saturation;
+                mMatrixGlobalSaturation[1] = luminance[0];
+                mMatrixGlobalSaturation[2] = luminance[0];
+                mMatrixGlobalSaturation[4] = luminance[1];
+                mMatrixGlobalSaturation[5] = luminance[1] + saturation;
+                mMatrixGlobalSaturation[6] = luminance[1];
+                mMatrixGlobalSaturation[8] = luminance[2];
+                mMatrixGlobalSaturation[9] = luminance[2];
+                mMatrixGlobalSaturation[10] = luminance[2] + saturation;
+            }
         }
 
         @Override
         public int getLevel() {
-            return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
+            return LEVEL_COLOR_MATRIX_SATURATION;
         }
     };
 
+    /**
+     * Matrix and offset used for converting color to grayscale.
+     */
+    private static final float[] MATRIX_GRAYSCALE = new float[]{
+            .2126f, .2126f, .2126f, 0f,
+            .7152f, .7152f, .7152f, 0f,
+            .0722f, .0722f, .0722f, 0f,
+            0f, 0f, 0f, 1f
+    };
+
+    /**
+     * Matrix and offset used for luminance inversion. Represents a transform from RGB to YIQ color
+     * space, rotation around the Y axis by 180 degrees, transform back to RGB color space, and
+     * subtraction from 1. The last row represents a non-multiplied addition, see surfaceflinger's
+     * ProgramCache for full implementation details.
+     */
+    private static final float[] MATRIX_INVERT_COLOR = new float[] {
+            0.402f, -0.598f, -0.599f, 0f,
+            -1.174f, -0.174f, -1.175f, 0f,
+            -0.228f, -0.228f, 0.772f, 0f,
+            1f, 1f, 1f, 1f
+    };
+
     private final Handler mHandler;
 
+    private final AppSaturationController mAppSaturationController = new AppSaturationController();
+
     private int mCurrentUser = UserHandle.USER_NULL;
     private ContentObserver mUserSetupObserver;
     private boolean mBootCompleted;
@@ -174,11 +443,9 @@
 
     private NightDisplayAutoMode mNightDisplayAutoMode;
 
-    private Integer mDisplayWhiteBalanceColorTemperature;
-
     public ColorDisplayService(Context context) {
         super(context);
-        mHandler = new Handler(Looper.getMainLooper());
+        mHandler = new TintHandler(Looper.getMainLooper());
     }
 
     @Override
@@ -302,12 +569,19 @@
                             case System.DISPLAY_COLOR_MODE:
                                 onDisplayColorModeChanged(mNightDisplayController.getColorMode());
                                 break;
-                            case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
                             case Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED:
-                                onAccessibilityTransformChanged();
+                                onAccessibilityInversionChanged();
+                                onAccessibilityActivated();
+                                break;
+                            case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
+                                onAccessibilityDaltonizerChanged();
+                                onAccessibilityActivated();
+                                break;
+                            case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER:
+                                onAccessibilityDaltonizerChanged();
                                 break;
                             case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
-                                onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled());
+                                updateDisplayWhiteBalanceStatus();
                                 break;
                         }
                     }
@@ -333,6 +607,9 @@
         cr.registerContentObserver(
                 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
+        cr.registerContentObserver(
+                Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
+                false /* notifyForDescendants */, mContentObserver, mCurrentUser);
         cr.registerContentObserver(Secure.getUriFor(Secure.DISPLAY_WHITE_BALANCE_ENABLED),
                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
 
@@ -360,14 +637,9 @@
 
         if (ColorDisplayManager.isDisplayWhiteBalanceAvailable(getContext())) {
             // Prepare the display white balance transform matrix.
-            mDisplayWhiteBalanceTintController
-                    .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
-            if (mDisplayWhiteBalanceColorTemperature != null) {
-                mDisplayWhiteBalanceTintController
-                        .setMatrix(mDisplayWhiteBalanceColorTemperature);
-            }
+            mDisplayWhiteBalanceTintController.setUp(getContext(), true /* needsLinear */);
 
-            onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled());
+            updateDisplayWhiteBalanceStatus();
         }
     }
 
@@ -404,6 +676,8 @@
                 mNightDisplayAutoMode.onActivated(activated);
             }
 
+            updateDisplayWhiteBalanceStatus();
+
             applyTint(mNightDisplayTintController, false);
         }
     }
@@ -460,20 +734,49 @@
                 .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
         mNightDisplayTintController.setMatrix(mNightDisplayController.getColorTemperature());
 
-        mDisplayWhiteBalanceTintController
-                .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
-        if (mDisplayWhiteBalanceColorTemperature != null) {
-            mDisplayWhiteBalanceTintController.setMatrix(mDisplayWhiteBalanceColorTemperature);
-        }
+        updateDisplayWhiteBalanceStatus();
 
         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
         dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
     }
 
-    private void onAccessibilityTransformChanged() {
+    private void onAccessibilityActivated() {
         onDisplayColorModeChanged(mNightDisplayController.getColorMode());
     }
 
+    /**
+     * Apply the accessibility daltonizer transform based on the settings value.
+     */
+    private void onAccessibilityDaltonizerChanged() {
+        final boolean enabled = Secure.getIntForUser(getContext().getContentResolver(),
+                Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, mCurrentUser) != 0;
+        final int daltonizerMode = enabled ? Secure.getIntForUser(getContext().getContentResolver(),
+                Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
+                AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY, mCurrentUser)
+                : AccessibilityManager.DALTONIZER_DISABLED;
+
+        final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
+        if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
+            // Monochromacy isn't supported by the native Daltonizer implementation; use grayscale.
+            dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE,
+                    MATRIX_GRAYSCALE);
+            dtm.setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
+        } else {
+            dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, null);
+            dtm.setDaltonizerMode(daltonizerMode);
+        }
+    }
+
+    /**
+     * Apply the accessibility inversion transform based on the settings value.
+     */
+    private void onAccessibilityInversionChanged() {
+        final boolean enabled = Secure.getIntForUser(getContext().getContentResolver(),
+                Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, mCurrentUser) != 0;
+        final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
+        dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR,
+                enabled ? MATRIX_INVERT_COLOR : null);
+    }
 
     /**
      * Applies current color temperature matrix, or removes it if deactivated.
@@ -555,10 +858,21 @@
         return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
     }
 
-    private void onDisplayWhiteBalanceEnabled(boolean enabled) {
-        mDisplayWhiteBalanceTintController.setActivated(enabled);
-        if (mDisplayWhiteBalanceListener != null) {
-            mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(enabled);
+    private void updateDisplayWhiteBalanceStatus() {
+        boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated();
+        mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled() &&
+                !mNightDisplayTintController.isActivated() &&
+                DisplayTransformManager.needsLinearColorMatrix());
+        boolean activated = mDisplayWhiteBalanceTintController.isActivated();
+
+        if (mDisplayWhiteBalanceListener != null && oldActivated != activated) {
+            mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(activated);
+        }
+
+        // If disabled, clear the tint. If enabled, do nothing more here and let the next
+        // temperature update set the correct tint.
+        if (!activated) {
+            applyTint(mDisplayWhiteBalanceTintController, false);
         }
     }
 
@@ -572,6 +886,21 @@
         return dtm.isDeviceColorManaged();
     }
 
+    private int getTransformCapabilitiesInternal() {
+        int availabilityFlags = ColorDisplayManager.CAPABILITY_NONE;
+        if (SurfaceControl.getProtectedContentSupport()) {
+            availabilityFlags |= ColorDisplayManager.CAPABILITY_PROTECTED_CONTENT;
+        }
+        final Resources res = getContext().getResources();
+        if (res.getBoolean(R.bool.config_setColorTransformAccelerated)) {
+            availabilityFlags |= ColorDisplayManager.CAPABILITY_HARDWARE_ACCELERATION_GLOBAL;
+        }
+        if (res.getBoolean(R.bool.config_setColorTransformAcceleratedPerLayer)) {
+            availabilityFlags |= ColorDisplayManager.CAPABILITY_HARDWARE_ACCELERATION_PER_APP;
+        }
+        return availabilityFlags;
+    }
+
     /**
      * Returns the last time the night display transform activation state was changed, or {@link
      * LocalDateTime#MIN} if night display has never been activated.
@@ -596,6 +925,22 @@
         return LocalDateTime.MIN;
     }
 
+    private boolean setAppSaturationLevelInternal(String packageName, int saturationLevel) {
+        return mAppSaturationController
+                .setSaturationLevel(packageName, mCurrentUser, saturationLevel);
+    }
+
+    private void dumpInternal(PrintWriter pw) {
+        pw.println("COLOR DISPLAY MANAGER dumpsys (color_display)");
+        pw.println("Night Display:");
+        if (ColorDisplayManager.isNightDisplayAvailable(getContext())) {
+            pw.println("    Activated: " + mNightDisplayTintController.isActivated());
+        } else {
+            pw.println("    Not available");
+        }
+        mAppSaturationController.dump(pw);
+    }
+
     private abstract class NightDisplayAutoMode {
 
         public abstract void onActivated(boolean activated);
@@ -840,6 +1185,12 @@
         }
 
         /**
+         * Dump debug information.
+         */
+        public void dump(PrintWriter pw) {
+        }
+
+        /**
          * Set up any constants needed for computing the matrix.
          */
         public abstract void setUp(Context context, boolean needsLinear);
@@ -873,11 +1224,10 @@
          */
         public boolean setDisplayWhiteBalanceColorTemperature(int cct) {
             // Update the transform matrix even if it can't be applied.
-            mDisplayWhiteBalanceColorTemperature = cct;
             mDisplayWhiteBalanceTintController.setMatrix(cct);
 
             if (mDisplayWhiteBalanceTintController.isActivated()) {
-                applyTint(mDisplayWhiteBalanceTintController, true);
+                applyTint(mDisplayWhiteBalanceTintController, false);
                 return true;
             }
             return false;
@@ -890,6 +1240,20 @@
             mDisplayWhiteBalanceListener = listener;
             return mDisplayWhiteBalanceTintController.isActivated();
         }
+
+        public void dump(PrintWriter pw) {
+            mDisplayWhiteBalanceTintController.dump(pw);
+        }
+
+        /**
+         * Adds a {@link WeakReference<ColorTransformController>} for a newly started activity, and
+         * invokes {@link ColorTransformController#applyAppSaturation(float[], float[])} if needed.
+         */
+        public boolean attachColorTransformController(String packageName, @UserIdInt int userId,
+                WeakReference<ColorTransformController> controller) {
+            return mAppSaturationController
+                    .addColorTransformController(packageName, userId, controller);
+        }
     }
 
     /**
@@ -904,6 +1268,32 @@
         void onDisplayWhiteBalanceStatusChanged(boolean enabled);
     }
 
+    private final class TintHandler extends Handler {
+
+        TintHandler(Looper looper) {
+            super(looper, null, true /* async */);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_APPLY_GLOBAL_SATURATION:
+                    mGlobalSaturationTintController.setMatrix(msg.arg1);
+                    applyTint(mGlobalSaturationTintController, false);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Interface for applying transforms to a given AppWindow.
+     */
+    public interface ColorTransformController {
+
+        /** Apply the given saturation (grayscale) matrix to the associated AppWindow. */
+        void applyAppSaturation(@Size(9) float[] matrix, @Size(3) float[] translation);
+    }
+
     private final class BinderService extends IColorDisplayManager.Stub {
 
         @Override
@@ -915,5 +1305,64 @@
                 Binder.restoreCallingIdentity(token);
             }
         }
+
+        @Override
+        public boolean setSaturationLevel(int level) {
+            final boolean hasTransformsPermission = getContext()
+                    .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+                    == PackageManager.PERMISSION_GRANTED;
+            final boolean hasLegacyPermission = getContext()
+                    .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
+                    == PackageManager.PERMISSION_GRANTED;
+            if (!hasTransformsPermission && !hasLegacyPermission) {
+                throw new SecurityException("Permission required to set display saturation level");
+            }
+            final long token = Binder.clearCallingIdentity();
+            try {
+                final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION);
+                message.arg1 = level;
+                mHandler.sendMessage(message);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            return true;
+        }
+
+        @Override
+        public boolean setAppSaturationLevel(String packageName, int level) {
+            getContext().enforceCallingPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to set display saturation level");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return setAppSaturationLevelInternal(packageName, level);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        public int getTransformCapabilities() {
+            getContext().enforceCallingPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to query transform capabilities");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getTransformCapabilitiesInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                dumpInternal(pw);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index b1ba05c..cb3f91b 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -95,6 +95,7 @@
 import com.android.server.UiThread;
 import com.android.server.wm.SurfaceAnimationThread;
 import com.android.server.wm.WindowManagerInternal;
+import com.android.server.display.ColorDisplayService.ColorDisplayServiceInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -724,27 +725,6 @@
         }
     }
 
-    private void setSaturationLevelInternal(float level) {
-        if (level < 0 || level > 1) {
-            throw new IllegalArgumentException("Saturation level must be between 0 and 1");
-        }
-        float[] matrix = (level == 1.0f ? null : computeSaturationMatrix(level));
-        DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
-        dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION, matrix);
-    }
-
-    private static float[] computeSaturationMatrix(float saturation) {
-        float desaturation = 1.0f - saturation;
-        float[] luminance = {0.231f * desaturation, 0.715f * desaturation, 0.072f * desaturation};
-        float[] matrix = {
-            luminance[0] + saturation, luminance[0], luminance[0], 0,
-            luminance[1], luminance[1] + saturation, luminance[1], 0,
-            luminance[2], luminance[2], luminance[2] + saturation, 0,
-            0, 0, 0, 1
-        };
-        return matrix;
-    }
-
     private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
             IMediaProjection projection, int callingUid, String packageName, String name, int width,
             int height, int densityDpi, Surface surface, int flags, String uniqueId) {
@@ -812,6 +792,16 @@
         }
     }
 
+    private void setVirtualDisplayStateInternal(IBinder appToken, boolean isOn) {
+        synchronized (mSyncRoot) {
+            if (mVirtualDisplayAdapter == null) {
+                return;
+            }
+
+            mVirtualDisplayAdapter.setVirtualDisplayStateLocked(appToken, isOn);
+        }
+    }
+
     private void registerDefaultDisplayAdapters() {
         // Register default display adapters.
         synchronized (mSyncRoot) {
@@ -1480,6 +1470,13 @@
 
             pw.println();
             mPersistentDataStore.dump(pw);
+
+            final ColorDisplayServiceInternal cds = LocalServices.getService(
+                    ColorDisplayServiceInternal.class);
+            if (cds != null) {
+                pw.println();
+                cds.dump(pw);
+            }
         }
     }
 
@@ -1836,19 +1833,6 @@
         }
 
         @Override // Binder call
-        public void setSaturationLevel(float level) {
-            mContext.enforceCallingOrSelfPermission(
-                   Manifest.permission.CONTROL_DISPLAY_SATURATION,
-                   "Permission required to set display saturation level");
-            final long token = Binder.clearCallingIdentity();
-            try {
-                setSaturationLevelInternal(level);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override // Binder call
         public int createVirtualDisplay(IVirtualDisplayCallback callback,
                 IMediaProjection projection, String packageName, String name,
                 int width, int height, int densityDpi, Surface surface, int flags,
@@ -1956,6 +1940,16 @@
         }
 
         @Override // Binder call
+        public void setVirtualDisplayState(IVirtualDisplayCallback callback, boolean isOn) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                setVirtualDisplayStateInternal(callback.asBinder(), isOn);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
         public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index c9ed9f7..db3928e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -461,6 +461,8 @@
                         + initialLightSensorRate + ") to be less than or equal to "
                         + "config_autoBrightnessLightSensorRate (" + lightSensorRate + ").");
             }
+            int shortTermModelTimeout = resources.getInteger(
+                    com.android.internal.R.integer.config_autoBrightnessShortTermModelTimeout);
 
             mBrightnessMapper = BrightnessMappingStrategy.create(resources);
             if (mBrightnessMapper != null) {
@@ -470,7 +472,8 @@
                         mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
                         initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
                         autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds,
-                        screenBrightnessThresholds);
+                        screenBrightnessThresholds, shortTermModelTimeout,
+                        context.getPackageManager());
             } else {
                 mUseSoftwareAutoBrightnessConfig = false;
             }
@@ -523,9 +526,6 @@
     public void onSwitchUser(@UserIdInt int newUserId) {
         handleSettingsChange(true /* userSwitch */);
         mBrightnessTracker.onSwitchUser(newUserId);
-        if (mAutomaticBrightnessController != null) {
-            mAutomaticBrightnessController.onSwitchUser(newUserId);
-        }
     }
 
     public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats(
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 5aa585f..1ca8dd3 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -147,6 +147,13 @@
         return device;
     }
 
+    void setVirtualDisplayStateLocked(IBinder appToken, boolean isOn) {
+        VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
+        if (device != null) {
+            device.setDisplayState(isOn);
+        }
+    }
+
     /**
      * Returns the next unique index for the uniqueIdPrefix
      */
@@ -206,6 +213,7 @@
         private int mPendingChanges;
         private int mUniqueIndex;
         private Display.Mode mMode;
+        private boolean mIsDisplayOn;
 
         public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
                 int ownerUid, String ownerPackageName,
@@ -226,6 +234,7 @@
             mDisplayState = Display.STATE_UNKNOWN;
             mPendingChanges |= PENDING_SURFACE_CHANGE;
             mUniqueIndex = uniqueIndex;
+            mIsDisplayOn = surface != null;
         }
 
         @Override
@@ -304,6 +313,14 @@
             }
         }
 
+        void setDisplayState(boolean isOn) {
+            if (mIsDisplayOn != isOn) {
+                mIsDisplayOn = isOn;
+                mInfo = null;
+                sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
+            }
+        }
+
         public void stopLocked() {
             setSurfaceLocked(null);
             mStopped = true;
@@ -375,7 +392,9 @@
                 mInfo.type = Display.TYPE_VIRTUAL;
                 mInfo.touch = ((mFlags & VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH) == 0) ?
                         DisplayDeviceInfo.TOUCH_NONE : DisplayDeviceInfo.TOUCH_VIRTUAL;
-                mInfo.state = mSurface != null ? Display.STATE_ON : Display.STATE_OFF;
+
+                mInfo.state = mIsDisplayOn ? Display.STATE_ON : Display.STATE_OFF;
+
                 mInfo.ownerUid = mOwnerUid;
                 mInfo.ownerPackageName = mOwnerPackageName;
             }
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index ba05b49..bffa8f4 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -18,13 +18,6 @@
 
 import static android.Manifest.permission.BIND_DREAM_SERVICE;
 
-import com.android.internal.hardware.AmbientDisplayConfiguration;
-import com.android.internal.util.DumpUtils;
-import com.android.server.FgThread;
-import com.android.server.LocalServices;
-import com.android.server.SystemService;
-
-import android.Manifest;
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -53,6 +46,12 @@
 import android.util.Slog;
 import android.view.Display;
 
+import com.android.internal.hardware.AmbientDisplayConfiguration;
+import com.android.internal.util.DumpUtils;
+import com.android.server.FgThread;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -84,6 +83,7 @@
     private boolean mCurrentDreamCanDoze;
     private boolean mCurrentDreamIsDozing;
     private boolean mCurrentDreamIsWaking;
+    private boolean mForceAmbientDisplayEnabled;
     private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
     private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
 
@@ -139,6 +139,7 @@
         pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze);
         pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing);
         pw.println("mCurrentDreamIsWaking=" + mCurrentDreamIsWaking);
+        pw.println("mForceAmbientDisplayEnabled=" + mForceAmbientDisplayEnabled);
         pw.println("mCurrentDreamDozeScreenState="
                 + Display.stateToString(mCurrentDreamDozeScreenState));
         pw.println("mCurrentDreamDozeScreenBrightness=" + mCurrentDreamDozeScreenBrightness);
@@ -257,6 +258,16 @@
         }
     }
 
+    private void forceAmbientDisplayEnabledInternal(boolean enabled) {
+        if (DEBUG) {
+            Slog.d(TAG, "Force ambient display enabled: " + enabled);
+        }
+
+        synchronized (mLock) {
+            mForceAmbientDisplayEnabled = enabled;
+        }
+    }
+
     private ComponentName chooseDreamForUser(boolean doze, int userId) {
         if (doze) {
             ComponentName dozeComponent = getDozeComponent(userId);
@@ -328,7 +339,7 @@
     }
 
     private ComponentName getDozeComponent(int userId) {
-        if (mDozeConfig.enabled(userId)) {
+        if (mForceAmbientDisplayEnabled || mDozeConfig.enabled(userId)) {
             return ComponentName.unflattenFromString(mDozeConfig.ambientDisplayComponent());
         } else {
             return null;
@@ -631,6 +642,18 @@
                 Binder.restoreCallingIdentity(ident);
             }
         }
+
+        @Override // Binder call
+        public void forceAmbientDisplayEnabled(boolean enabled) {
+            checkPermission(android.Manifest.permission.DEVICE_POWER);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                forceAmbientDisplayEnabledInternal(enabled);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
     }
 
     private final class LocalService extends DreamManagerInternal {
diff --git a/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
index ed17de5..137833c 100644
--- a/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
@@ -21,14 +21,15 @@
  * Feature action that handles Audio Return Channel initiated by AVR devices.
  */
 public class ArcInitiationActionFromAvr extends HdmiCecFeatureAction {
-    // TODO(shubang): add tests
-
     // State in which waits for ARC response.
     private static final int STATE_WAITING_FOR_INITIATE_ARC_RESPONSE = 1;
     private static final int STATE_ARC_INITIATED = 2;
 
     // the required maximum response time specified in CEC 9.2
     private static final int TIMEOUT_MS = 1000;
+    private static final int MAX_RETRY_COUNT = 5;
+
+    private int mSendRequestActiveSourceRetryCount = 0;
 
     ArcInitiationActionFromAvr(HdmiCecLocalDevice source) {
         super(source);
@@ -50,13 +51,25 @@
         }
         switch (cmd.getOpcode()) {
             case Constants.MESSAGE_FEATURE_ABORT:
+                if ((cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_INITIATE_ARC) {
+                    audioSystem().setArcStatus(false);
+                    finish();
+                    return true;
+                } else {
+                    return false;
+                }
             case Constants.MESSAGE_REPORT_ARC_TERMINATED:
                 audioSystem().setArcStatus(false);
                 finish();
                 return true;
             case Constants.MESSAGE_REPORT_ARC_INITIATED:
                 mState = STATE_ARC_INITIATED;
-                finish();
+                if (audioSystem().getActiveSource().physicalAddress != getSourcePath()
+                        && audioSystem().isSystemAudioActivated()) {
+                    sendRequestActiveSource();
+                } else {
+                    finish();
+                }
                 return true;
         }
         return false;
@@ -91,4 +104,19 @@
         finish();
     }
 
+    protected void sendRequestActiveSource() {
+        sendCommand(HdmiCecMessageBuilder.buildRequestActiveSource(getSourceAddress()),
+                result -> {
+                    if (result != SendMessageResult.SUCCESS) {
+                        if (mSendRequestActiveSourceRetryCount < MAX_RETRY_COUNT) {
+                            mSendRequestActiveSourceRetryCount++;
+                            sendRequestActiveSource();
+                        } else {
+                            finish();
+                        }
+                    } else {
+                        finish();
+                    }
+                });
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java b/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
index 7e73321..eb7c0cd 100644
--- a/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
@@ -50,6 +50,9 @@
             case Constants.MESSAGE_REPORT_ARC_TERMINATED:
                 mState = STATE_ARC_TERMINATED;
                 audioSystem().setArcStatus(false);
+                if (audioSystem().getLocalActivePort() == Constants.CEC_SWITCH_ARC) {
+                    audioSystem().routeToInputFromPortId(audioSystem().getRoutingPort());
+                }
                 finish();
                 return true;
         }
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index d154830..297a418 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -17,7 +17,9 @@
 package com.android.server.hdmi;
 
 import android.annotation.IntDef;
+import android.annotation.StringDef;
 import android.hardware.hdmi.HdmiDeviceInfo;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -221,6 +223,15 @@
     static final int AUDIO_CODEC_WMAPRO = 0xE; // Support WMA-Pro
     static final int AUDIO_CODEC_MAX = 0xF;
 
+    @StringDef({
+        AUDIO_DEVICE_ARC_IN,
+        AUDIO_DEVICE_SPDIF,
+    })
+    public @interface AudioDevice {}
+
+    static final String AUDIO_DEVICE_ARC_IN = "ARC_IN";
+    static final String AUDIO_DEVICE_SPDIF = "SPDIF";
+
     // Bit mask used to get the routing path of the top level device.
     // When &'d with the path 1.2.2.0 (0x1220), for instance, gives 1.0.0.0.
     static final int ROUTING_PATH_TOP_MASK = 0xF000;
@@ -255,6 +266,41 @@
     static final int USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON = 1;
     static final int NEVER_SYSTEM_AUDIO_CONTROL_ON_POWER_ON = 2;
 
+    // Port id to record local active port for Routing Control features
+    // They are used to map to corresponding Inputs
+    // Current interface is only implemented for specific device.
+    // Developers can add more port number and map them to corresponding inputs on demand.
+    @IntDef({
+        CEC_SWITCH_HOME,
+        CEC_SWITCH_HDMI1,
+        CEC_SWITCH_HDMI2,
+        CEC_SWITCH_HDMI3,
+        CEC_SWITCH_HDMI4,
+        CEC_SWITCH_HDMI5,
+        CEC_SWITCH_HDMI6,
+        CEC_SWITCH_HDMI7,
+        CEC_SWITCH_HDMI8,
+        CEC_SWITCH_ARC,
+        CEC_SWITCH_BLUETOOTH,
+        CEC_SWITCH_OPTICAL,
+        CEC_SWITCH_AUX
+    })
+    @interface LocalActivePort {}
+    static final int CEC_SWITCH_HOME = 0;
+    static final int CEC_SWITCH_HDMI1 = 1;
+    static final int CEC_SWITCH_HDMI2 = 2;
+    static final int CEC_SWITCH_HDMI3 = 3;
+    static final int CEC_SWITCH_HDMI4 = 4;
+    static final int CEC_SWITCH_HDMI5 = 5;
+    static final int CEC_SWITCH_HDMI6 = 6;
+    static final int CEC_SWITCH_HDMI7 = 7;
+    static final int CEC_SWITCH_HDMI8 = 8;
+    static final int CEC_SWITCH_ARC = 17;
+    static final int CEC_SWITCH_BLUETOOTH = 18;
+    static final int CEC_SWITCH_OPTICAL = 19;
+    static final int CEC_SWITCH_AUX = 20;
+    static final int CEC_SWITCH_PORT_MAX = 21;
+
     static final String PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM =
             "persist.sys.hdmi.addr.audiosystem";
     static final String PROPERTY_PREFERRED_ADDRESS_PLAYBACK = "persist.sys.hdmi.addr.playback";
@@ -272,6 +318,41 @@
     // TODO(OEM): Set this to true to enable 'Set Menu Language' feature. False by default.
     static final String PROPERTY_SET_MENU_LANGUAGE = "ro.hdmi.set_menu_language";
 
+    /**
+     * Property to save the ARC port id on system audio device.
+     * <p>When ARC is initiated, this port will be used to turn on ARC.
+     */
+    static final String PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT =
+            "ro.hdmi.property_sytem_audio_device_arc_port";
+
+    /**
+     * Property to disable muting logic in System Audio Control handling. Default is true.
+     *
+     * <p>True means enabling muting logic.
+     * <p>False means never mute device.
+     */
+    static final String PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE =
+            "ro.hdmi.property_system_audio_mode_muting_enable";
+
+    /**
+     * When set to true the HdmiControlService will never request a Logical Address for the
+     * playback device type. Default is false.
+     *
+     * <p> This is useful when HDMI CEC multiple device types is not supported by the cec driver
+     */
+    static final String PROPERTY_HDMI_CEC_NEVER_CLAIM_PLAYBACK_LOGICAL_ADDRESS =
+            "ro.hdmi.property_hdmi_cec_never_claim_playback_logical_address";
+
+    /**
+     * A comma separated list of logical addresses that HdmiControlService
+     * will never assign local CEC devices to.
+     *
+     * <p> This is useful when HDMI CEC hardware module can't assign multiple logical addresses
+     * in the range same range of 0-7 or 8-15.
+     */
+    static final String PROPERTY_HDMI_CEC_NEVER_ASSIGN_LOGICAL_ADDRESSES =
+            "ro.hdmi.property_hdmi_cec_never_assign_logical_addresses";
+
     // Set to false to allow playback device to go to suspend mode even
     // when it's an active source. True by default.
     static final String PROPERTY_KEEP_AWAKE = "persist.sys.hdmi.keep_awake";
@@ -299,7 +380,7 @@
      * <p>Default is true.
      */
     static final String PROPERTY_ARC_SUPPORT =
-        "persist.sys.hdmi.property_arc_support";
+            "persist.sys.hdmi.property_arc_support";
 
     /**
      * Property to save the audio port to switch to when system audio control is on.
@@ -309,14 +390,16 @@
      * <p>Default is ARC port.
      */
     static final String PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT =
-        "persist.sys.hdmi.property_sytem_audio_mode_audio_port";
+            "persist.sys.hdmi.property_sytem_audio_mode_audio_port";
 
     /**
-     * Property to save the ARC port id on system audio device.
-     * <p>When ARC is initiated, this port will be used to turn on ARC.
+     * Property to indicate if a CEC audio device should forward volume keys when system audio mode
+     * is off.
+     *
+     * <p>Default is false.
      */
-    static final String PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT =
-        "persist.sys.hdmi.property_sytem_audio_device_arc_port";
+    static final String PROPERTY_CEC_AUDIO_DEVICE_FORWARD_VOLUME_KEYS_SYSTEM_AUDIO_MODE_OFF =
+            "persist.sys.hdmi.property_cec_audio_device_forward_volume_keys_system_audio_mode_off";
 
     /**
      * Property to strip local audio of amplifier and use local speaker
diff --git a/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java b/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java
index 0495ff8..7187319 100644
--- a/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java
+++ b/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java
@@ -50,8 +50,10 @@
             if (mState != STATE_WAITING_FOR_FEATURE_ABORT) {
                 return false;
             }
-            finishAction(false);
-            return true;
+            if ((cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE) {
+                finishAction(false);
+                return true;
+            }
         }
         return false;
     }
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index b75e75f..df0dc77 100755
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -16,6 +16,7 @@
 
 package com.android.server.hdmi;
 
+import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.util.Slog;
 
@@ -28,7 +29,7 @@
 
 /**
  * Feature action that handles device discovery sequences.
- * Device discovery is launched when TV device is woken from "Standby" state
+ * Device discovery is launched when device is woken from "Standby" state
  * or enabled "Control for Hdmi" from disabled state.
  *
  * <p>Device discovery goes through the following steps.
@@ -51,6 +52,10 @@
     private static final int STATE_WAITING_FOR_OSD_NAME = 3;
     // State in which the action is waiting for gathering vendor id of non-local devices.
     private static final int STATE_WAITING_FOR_VENDOR_ID = 4;
+    // State in which the action is waiting for devices to be ready.
+    private static final int STATE_WAITING_FOR_DEVICES = 5;
+    // State in which the action is waiting for gathering power status of non-local devices.
+    private static final int STATE_WAITING_FOR_POWER = 6;
 
     /**
      * Interface used to report result of device discovery.
@@ -72,6 +77,7 @@
         private int mPhysicalAddress = Constants.INVALID_PHYSICAL_ADDRESS;
         private int mPortId = Constants.INVALID_PORT_ID;
         private int mVendorId = Constants.UNKNOWN_VENDOR_ID;
+        private int mPowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
         private String mDisplayName = "";
         private int mDeviceType = HdmiDeviceInfo.DEVICE_INACTIVE;
 
@@ -81,7 +87,7 @@
 
         private HdmiDeviceInfo toHdmiDeviceInfo() {
             return new HdmiDeviceInfo(mLogicalAddress, mPhysicalAddress, mPortId, mDeviceType,
-                    mVendorId, mDisplayName);
+                    mVendorId, mDisplayName, mPowerStatus);
         }
     }
 
@@ -89,6 +95,20 @@
     private final DeviceDiscoveryCallback mCallback;
     private int mProcessedDeviceCount = 0;
     private int mTimeoutRetry = 0;
+    private boolean mIsTvDevice = localDevice().mService.isTvDevice();
+    private final int mDelayPeriod;
+
+    /**
+     * Constructor.
+     *
+     * @param source an instance of {@link HdmiCecLocalDevice}.
+     * @param delay delay action for this period between query Physical Address and polling
+     */
+    DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback, int delay) {
+        super(source);
+        mCallback = Preconditions.checkNotNull(callback);
+        mDelayPeriod = delay;
+    }
 
     /**
      * Constructor.
@@ -96,8 +116,7 @@
      * @param source an instance of {@link HdmiCecLocalDevice}.
      */
     DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback) {
-        super(source);
-        mCallback = Preconditions.checkNotNull(callback);
+        this(source, callback, 0);
     }
 
     @Override
@@ -116,7 +135,11 @@
 
                 Slog.v(TAG, "Device detected: " + ackedAddress);
                 allocateDevices(ackedAddress);
-                startPhysicalAddressStage();
+                if (mDelayPeriod > 0) {
+                    startToDelayAction();
+                } else {
+                    startPhysicalAddressStage();
+                }
             }
         }, Constants.POLL_ITERATION_REVERSE_ORDER
             | Constants.POLL_STRATEGY_REMOTES_DEVICES, HdmiConfig.DEVICE_POLLING_RETRY);
@@ -130,6 +153,13 @@
         }
     }
 
+    private void startToDelayAction() {
+        Slog.v(TAG, "Waiting for connected devices to be ready");
+        mState = STATE_WAITING_FOR_DEVICES;
+
+        checkAndProceedStage();
+    }
+
     private void startPhysicalAddressStage() {
         Slog.v(TAG, "Start [Physical Address Stage]:" + mDevices.size());
         mProcessedDeviceCount = 0;
@@ -158,6 +188,11 @@
         addTimer(mState, HdmiConfig.TIMEOUT_MS);
     }
 
+    private void delayActionWithTimePeriod(int timeDelay) {
+        mActionTimer.clearTimerMessage();
+        addTimer(mState, timeDelay);
+    }
+
     private void startOsdNameStage() {
         Slog.v(TAG, "Start [Osd Name Stage]:" + mDevices.size());
         mProcessedDeviceCount = 0;
@@ -206,6 +241,29 @@
         addTimer(mState, HdmiConfig.TIMEOUT_MS);
     }
 
+    private void startPowerStatusStage() {
+        Slog.v(TAG, "Start [Power Status Stage]:" + mDevices.size());
+        mProcessedDeviceCount = 0;
+        mState = STATE_WAITING_FOR_POWER;
+
+        checkAndProceedStage();
+    }
+
+    private void queryPowerStatus(int address) {
+        if (!verifyValidLogicalAddress(address)) {
+            checkAndProceedStage();
+            return;
+        }
+
+        mActionTimer.clearTimerMessage();
+
+        if (mayProcessMessageIfCached(address, Constants.MESSAGE_REPORT_POWER_STATUS)) {
+            return;
+        }
+        sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), address));
+        addTimer(mState, HdmiConfig.TIMEOUT_MS);
+    }
+
     private boolean mayProcessMessageIfCached(int address, int opcode) {
         HdmiCecMessage message = getCecMessageCache().getMessage(address, opcode);
         if (message != null) {
@@ -244,6 +302,16 @@
                     return true;
                 }
                 return false;
+            case STATE_WAITING_FOR_POWER:
+                if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) {
+                    handleReportPowerStatus(cmd);
+                    return true;
+                } else if ((cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT)
+                        && ((cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_REPORT_POWER_STATUS)) {
+                    handleReportPowerStatus(cmd);
+                    return true;
+                }
+                return false;
             case STATE_WAITING_FOR_DEVICE_POLLING:
                 // Fall through.
             default:
@@ -265,16 +333,21 @@
         current.mPhysicalAddress = HdmiUtils.twoBytesToInt(params);
         current.mPortId = getPortId(current.mPhysicalAddress);
         current.mDeviceType = params[2] & 0xFF;
+        current.mDisplayName = HdmiUtils.getDefaultDeviceName(current.mDeviceType);
 
-        tv().updateCecSwitchInfo(current.mLogicalAddress, current.mDeviceType,
+        // TODO(amyjojo): check if non-TV device needs to update cec switch info.
+        // This is to manager CEC device separately in case they don't have address.
+        if (mIsTvDevice) {
+            tv().updateCecSwitchInfo(current.mLogicalAddress, current.mDeviceType,
                     current.mPhysicalAddress);
-
+        }
         increaseProcessedDeviceCount();
         checkAndProceedStage();
     }
 
     private int getPortId(int physicalAddress) {
-        return tv().getPortId(physicalAddress);
+        return mIsTvDevice ? tv().getPortId(physicalAddress)
+            : source().getPortId(physicalAddress);
     }
 
     private void handleSetOsdName(HdmiCecMessage cmd) {
@@ -324,6 +397,26 @@
         checkAndProceedStage();
     }
 
+    private void handleReportPowerStatus(HdmiCecMessage cmd) {
+        Preconditions.checkState(mProcessedDeviceCount < mDevices.size());
+
+        DeviceInfo current = mDevices.get(mProcessedDeviceCount);
+        if (current.mLogicalAddress != cmd.getSource()) {
+            Slog.w(TAG, "Unmatched address[expected:" + current.mLogicalAddress + ", actual:"
+                    + cmd.getSource());
+            return;
+        }
+
+        if (cmd.getOpcode() != Constants.MESSAGE_FEATURE_ABORT) {
+            byte[] params = cmd.getParams();
+            int powerStatus = params[0] & 0xFF;
+            current.mPowerStatus = powerStatus;
+        }
+
+        increaseProcessedDeviceCount();
+        checkAndProceedStage();
+    }
+
     private void increaseProcessedDeviceCount() {
         mProcessedDeviceCount++;
         mTimeoutRetry = 0;
@@ -345,7 +438,9 @@
         mCallback.onDeviceDiscoveryDone(result);
         finish();
         // Process any commands buffered while device discovery action was in progress.
-        tv().processAllDelayedMessages();
+        if (mIsTvDevice) {
+            tv().processAllDelayedMessages();
+        }
     }
 
     private void checkAndProceedStage() {
@@ -365,6 +460,9 @@
                     startVendorIdStage();
                     return;
                 case STATE_WAITING_FOR_VENDOR_ID:
+                    startPowerStatusStage();
+                    return;
+                case STATE_WAITING_FOR_POWER:
                     wrapUpAndFinish();
                     return;
                 default:
@@ -378,6 +476,9 @@
     private void sendQueryCommand() {
         int address = mDevices.get(mProcessedDeviceCount).mLogicalAddress;
         switch (mState) {
+            case STATE_WAITING_FOR_DEVICES:
+                delayActionWithTimePeriod(mDelayPeriod);
+                return;
             case STATE_WAITING_FOR_PHYSICAL_ADDRESS:
                 queryPhysicalAddress(address);
                 return;
@@ -387,6 +488,9 @@
             case STATE_WAITING_FOR_VENDOR_ID:
                 queryVendorId(address);
                 return;
+            case STATE_WAITING_FOR_POWER:
+                queryPowerStatus(address);
+                return;
             default:
                 return;
         }
@@ -398,13 +502,24 @@
             return;
         }
 
+        if (mState == STATE_WAITING_FOR_DEVICES) {
+            startPhysicalAddressStage();
+            return;
+        }
         if (++mTimeoutRetry < HdmiConfig.TIMEOUT_RETRY) {
             sendQueryCommand();
             return;
         }
         mTimeoutRetry = 0;
         Slog.v(TAG, "Timeout[State=" + mState + ", Processed=" + mProcessedDeviceCount);
-        removeDevice(mProcessedDeviceCount);
+        if (mState != STATE_WAITING_FOR_POWER && mState != STATE_WAITING_FOR_OSD_NAME) {
+            // We don't need to remove the device info if the power status is unknown.
+            // Some device does not have preferred OSD name and does not respond to Give OSD name.
+            // Like LG TV. We can give it default device name and not remove it.
+            removeDevice(mProcessedDeviceCount);
+        } else {
+            increaseProcessedDeviceCount();
+        }
         checkAndProceedStage();
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index de6cdd4..86be585 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -22,20 +22,25 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
+import android.os.SystemProperties;
 import android.util.Slog;
 import android.util.SparseArray;
+
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
+
+import libcore.util.EmptyArray;
+
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.function.Predicate;
 import java.util.concurrent.ArrayBlockingQueue;
-import libcore.util.EmptyArray;
+import java.util.function.Predicate;
+
 import sun.util.locale.LanguageTag;
 
 /**
@@ -72,7 +77,7 @@
 
     private static final int NUM_LOGICAL_ADDRESS = 16;
 
-    private static final int MAX_CEC_MESSAGE_HISTORY = 20;
+    private static final int MAX_CEC_MESSAGE_HISTORY = 200;
 
     // Predicate for whether the given logical address is remote device's one or not.
     private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() {
@@ -112,10 +117,18 @@
 
     private final NativeWrapper mNativeWrapperImpl;
 
+    /** List of logical addresses that should not be assigned to the current device.
+     *
+     * <p>Parsed from {@link Constants#PROPERTY_HDMI_CEC_NEVER_ASSIGN_LOGICAL_ADDRESSES}
+     */
+    private final List<Integer> mNeverAssignLogicalAddresses;
+
     // Private constructor.  Use HdmiCecController.create().
     private HdmiCecController(HdmiControlService service, NativeWrapper nativeWrapper) {
         mService = service;
         mNativeWrapperImpl = nativeWrapper;
+        mNeverAssignLogicalAddresses = mService.getIntList(SystemProperties.get(
+            Constants.PROPERTY_HDMI_CEC_NEVER_ASSIGN_LOGICAL_ADDRESSES));
     }
 
     /**
@@ -208,7 +221,8 @@
         for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
             int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS;
             if (curAddress != Constants.ADDR_UNREGISTERED
-                    && deviceType == HdmiUtils.getTypeFromAddress(curAddress)) {
+                    && deviceType == HdmiUtils.getTypeFromAddress(curAddress)
+                    && !mNeverAssignLogicalAddresses.contains(curAddress)) {
                 boolean acked = false;
                 for (int j = 0; j < HdmiConfig.ADDRESS_ALLOCATION_RETRY; ++j) {
                     if (sendPollMessage(curAddress, curAddress, 1)) {
@@ -668,7 +682,7 @@
 
     void dump(final IndentingPrintWriter pw) {
         for (int i = 0; i < mLocalDevices.size(); ++i) {
-            pw.println("HdmiCecLocalDevice #" + i + ":");
+            pw.println("HdmiCecLocalDevice #" + mLocalDevices.keyAt(i) + ":");
             pw.increaseIndent();
             mLocalDevices.valueAt(i).dump(pw);
             pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
index 11faa56..2da698b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
@@ -252,6 +252,10 @@
         return (HdmiCecLocalDevicePlayback) mSource;
     }
 
+    protected final HdmiCecLocalDeviceSource source() {
+        return (HdmiCecLocalDeviceSource) mSource;
+    }
+
     protected final HdmiCecLocalDeviceTv tv() {
         return (HdmiCecLocalDeviceTv) mSource;
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 7860122..414f6bb 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -18,19 +18,24 @@
 
 import android.annotation.Nullable;
 import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.input.InputManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Slog;
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.hdmi.Constants.LocalActivePort;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
@@ -56,6 +61,7 @@
     protected final int mDeviceType;
     protected int mAddress;
     protected int mPreferredAddress;
+    @GuardedBy("mLock")
     protected HdmiDeviceInfo mDeviceInfo;
     protected int mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE;
     protected int mLastKeyRepeatCount = 0;
@@ -125,9 +131,6 @@
             return s.toString();
         }
     }
-    // Logical address of the active source.
-    @GuardedBy("mLock")
-    protected final ActiveSource mActiveSource = new ActiveSource();
 
     // Active routing path. Physical address of the active source but not all the time, such as
     // when the new active source does not claim itself to be one. Note that we don't keep
@@ -434,10 +437,14 @@
         return true;
     }
 
+    // Audio System device with no Playback device type
+    // needs to refactor this function if it's also a switch
     protected boolean handleRoutingChange(HdmiCecMessage message) {
         return false;
     }
 
+    // Audio System device with no Playback device type
+    // needs to refactor this function if it's also a switch
     protected boolean handleRoutingInformation(HdmiCecMessage message) {
         return false;
     }
@@ -706,16 +713,18 @@
         return mDeviceType;
     }
 
-    @ServiceThreadOnly
+    @GuardedBy("mLock")
     HdmiDeviceInfo getDeviceInfo() {
-        assertRunOnServiceThread();
-        return mDeviceInfo;
+        synchronized (mLock) {
+            return mDeviceInfo;
+        }
     }
 
-    @ServiceThreadOnly
+    @GuardedBy("mLock")
     void setDeviceInfo(HdmiDeviceInfo info) {
-        assertRunOnServiceThread();
-        mDeviceInfo = info;
+        synchronized (mLock) {
+            mDeviceInfo = info;
+        }
     }
 
     // Returns true if the logical address is same as the argument.
@@ -855,9 +864,7 @@
     }
 
     ActiveSource getActiveSource() {
-        synchronized (mLock) {
-            return mActiveSource;
-        }
+        return mService.getActiveSource();
     }
 
     void setActiveSource(ActiveSource newActive) {
@@ -869,10 +876,7 @@
     }
 
     void setActiveSource(int logicalAddress, int physicalAddress) {
-        synchronized (mLock) {
-            mActiveSource.logicalAddress = logicalAddress;
-            mActiveSource.physicalAddress = physicalAddress;
-        }
+        mService.setActiveSource(logicalAddress, physicalAddress);
         mService.setLastInputForMhl(Constants.INVALID_PORT_ID);
     }
 
@@ -910,6 +914,11 @@
         setActivePath(mService.portIdToPath(portId));
     }
 
+    // Returns the id of the port that the target device is connected to.
+    int getPortId(int physicalAddress) {
+        return mService.pathToPortId(physicalAddress);
+    }
+
     @ServiceThreadOnly
     HdmiCecMessageCache getCecMessageCache() {
         assertRunOnServiceThread();
@@ -1017,6 +1026,19 @@
         return Constants.ADDR_INVALID;
     }
 
+    @ServiceThreadOnly
+    void invokeCallback(IHdmiControlCallback callback, int result) {
+        assertRunOnServiceThread();
+        if (callback == null) {
+            return;
+        }
+        try {
+            callback.onComplete(result);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Invoking callback failed:" + e);
+        }
+    }
+
     void sendUserControlPressedAndReleased(int targetAddress, int cecKeycode) {
         mService.sendCecCommand(
                 HdmiCecMessageBuilder.buildUserControlPressed(mAddress, targetAddress, cecKeycode));
@@ -1030,7 +1052,30 @@
         pw.println("mAddress: " + mAddress);
         pw.println("mPreferredAddress: " + mPreferredAddress);
         pw.println("mDeviceInfo: " + mDeviceInfo);
-        pw.println("mActiveSource: " + mActiveSource);
+        pw.println("mActiveSource: " + getActiveSource());
         pw.println(String.format("mActiveRoutingPath: 0x%04x", mActiveRoutingPath));
     }
+
+    /** Calculates the physical address for {@code activePortId}.
+     *
+     * <p>This method assumes current device physical address is valid.
+     * <p>If the current device is already the leaf of the whole CEC system
+     * and can't have devices under it, will return its own physical address.
+     *
+     * @param activePortId is the local active port Id
+     * @return the calculated physical address of the port
+     */
+    protected int getActivePathOnSwitchFromActivePortId(@LocalActivePort int activePortId) {
+        int myPhysicalAddress = mService.getPhysicalAddress();
+        int finalMask = activePortId << 8;
+        int mask;
+        for (mask = 0x0F00; mask > 0x000F;  mask >>= 4) {
+            if ((myPhysicalAddress & mask) == 0)  {
+                break;
+            } else {
+                finalMask >>= 4;
+            }
+        }
+        return finalMask | myPhysicalAddress;
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 3845954..cac1a95 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -20,22 +20,50 @@
 import static com.android.server.hdmi.Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON;
 
 import android.annotation.Nullable;
+import android.content.Intent;
+import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.hdmi.IHdmiControlCallback;
 import android.media.AudioDeviceInfo;
+import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.AudioSystem;
+import android.media.tv.TvContract;
 import android.os.SystemProperties;
+import android.provider.Settings.Global;
+import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.Constants.AudioCodec;
+import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
+import com.android.server.hdmi.HdmiUtils.CodecSad;
+import com.android.server.hdmi.HdmiUtils.DeviceConfig;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.stream.Collectors;
+
 
 /**
  * Represent a logical device of type {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM} residing in Android
  * system.
  */
-public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDevice {
+public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
 
     private static final String TAG = "HdmiCecLocalDeviceAudioSystem";
 
@@ -54,12 +82,183 @@
     // AVR as audio receiver.
     @ServiceThreadOnly private boolean mArcEstablished = false;
 
+    // If the current device uses TvInput for ARC. We assume all other inputs also use TvInput
+    // when ARC is using TvInput.
+    private boolean mArcIntentUsed = SystemProperties
+            .get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT, "0").contains("tvinput");
+
+    // Keeps the mapping (HDMI port ID to TV input URI) to keep track of the TV inputs ready to
+    // accept input switching request from HDMI devices. Requests for which the corresponding
+    // input ID is not yet registered by TV input framework need to be buffered for delayed
+    // processing.
+    private final HashMap<Integer, String> mTvInputs = new HashMap<>();
+
+    // Copy of mDeviceInfos to guarantee thread-safety.
+    @GuardedBy("mLock")
+    private List<HdmiDeviceInfo> mSafeAllDeviceInfos = Collections.emptyList();
+
+    // Map-like container of all cec devices.
+    // device id is used as key of container.
+    private final SparseArray<HdmiDeviceInfo> mDeviceInfos = new SparseArray<>();
+
     protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
         super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
-        mSystemAudioControlFeatureEnabled = true;
-        // TODO(amyjojo) make System Audio Control controllable by users
-        /*mSystemAudioControlFeatureEnabled =
-        mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);*/
+        mRoutingControlFeatureEnabled =
+            mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, false);
+        mSystemAudioControlFeatureEnabled =
+            mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);
+        // TODO(amyjojo): Maintain a portId to TvinputId map.
+        mTvInputs.put(2, "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
+        mTvInputs.put(4, "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6");
+        mTvInputs.put(1, "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
+    }
+
+    private static final String SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH = "/vendor/etc/sadConfig.xml";
+
+    /**
+     * Called when a device is newly added or a new device is detected or
+     * an existing device is updated.
+     *
+     * @param info device info of a new device.
+     */
+    @ServiceThreadOnly
+    final void addCecDevice(HdmiDeviceInfo info) {
+        assertRunOnServiceThread();
+        HdmiDeviceInfo old = addDeviceInfo(info);
+        if (info.getPhysicalAddress() == mService.getPhysicalAddress()) {
+            // The addition of the device itself should not be notified.
+            // Note that different logical address could still be the same local device.
+            return;
+        }
+        if (old == null) {
+            invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
+        } else if (!old.equals(info)) {
+            invokeDeviceEventListener(old, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
+            invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
+        }
+    }
+
+    /**
+     * Called when a device is removed or removal of device is detected.
+     *
+     * @param address a logical address of a device to be removed
+     */
+    @ServiceThreadOnly
+    final void removeCecDevice(int address) {
+        assertRunOnServiceThread();
+        HdmiDeviceInfo info = removeDeviceInfo(HdmiDeviceInfo.idForCecDevice(address));
+
+        mCecMessageCache.flushMessagesFrom(address);
+        invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
+    }
+
+    /**
+     * Called when a device is updated.
+     *
+     * @param info device info of the updating device.
+     */
+    @ServiceThreadOnly
+    final void updateCecDevice(HdmiDeviceInfo info) {
+        assertRunOnServiceThread();
+        HdmiDeviceInfo old = addDeviceInfo(info);
+
+        if (old == null) {
+            invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE);
+        } else if (!old.equals(info)) {
+            invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE);
+        }
+    }
+
+    /**
+    * Add a new {@link HdmiDeviceInfo}. It returns old device info which has the same
+     * logical address as new device info's.
+     *
+     * @param deviceInfo a new {@link HdmiDeviceInfo} to be added.
+     * @return {@code null} if it is new device. Otherwise, returns old {@HdmiDeviceInfo}
+     *         that has the same logical address as new one has.
+     */
+    @ServiceThreadOnly
+    @VisibleForTesting
+    protected HdmiDeviceInfo addDeviceInfo(HdmiDeviceInfo deviceInfo) {
+        assertRunOnServiceThread();
+        HdmiDeviceInfo oldDeviceInfo = getCecDeviceInfo(deviceInfo.getLogicalAddress());
+        if (oldDeviceInfo != null) {
+            removeDeviceInfo(deviceInfo.getId());
+        }
+        mDeviceInfos.append(deviceInfo.getId(), deviceInfo);
+        updateSafeDeviceInfoList();
+        return oldDeviceInfo;
+    }
+
+    /**
+     * Remove a device info corresponding to the given {@code logicalAddress}.
+     * It returns removed {@link HdmiDeviceInfo} if exists.
+     *
+     * @param id id of device to be removed
+     * @return removed {@link HdmiDeviceInfo} it exists. Otherwise, returns {@code null}
+     */
+    @ServiceThreadOnly
+    private HdmiDeviceInfo removeDeviceInfo(int id) {
+        assertRunOnServiceThread();
+        HdmiDeviceInfo deviceInfo = mDeviceInfos.get(id);
+        if (deviceInfo != null) {
+            mDeviceInfos.remove(id);
+        }
+        updateSafeDeviceInfoList();
+        return deviceInfo;
+    }
+
+    /**
+     * Return a {@link HdmiDeviceInfo} corresponding to the given {@code logicalAddress}.
+     *
+     * @param logicalAddress logical address of the device to be retrieved
+     * @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}.
+     *         Returns null if no logical address matched
+     */
+    @ServiceThreadOnly
+    HdmiDeviceInfo getCecDeviceInfo(int logicalAddress) {
+        assertRunOnServiceThread();
+        return mDeviceInfos.get(HdmiDeviceInfo.idForCecDevice(logicalAddress));
+    }
+
+    @ServiceThreadOnly
+    private void updateSafeDeviceInfoList() {
+        assertRunOnServiceThread();
+        List<HdmiDeviceInfo> copiedDevices = HdmiUtils.sparseArrayToList(mDeviceInfos);
+        synchronized (mLock) {
+            mSafeAllDeviceInfos = copiedDevices;
+        }
+    }
+
+    @GuardedBy("mLock")
+    List<HdmiDeviceInfo> getSafeCecDevicesLocked() {
+        ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>();
+        for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
+            infoList.add(info);
+        }
+        return infoList;
+    }
+
+    private void invokeDeviceEventListener(HdmiDeviceInfo info, int status) {
+        mService.invokeDeviceEventListeners(info, status);
+    }
+
+    @Override
+    @ServiceThreadOnly
+    void onHotplug(int portId, boolean connected) {
+        assertRunOnServiceThread();
+        if (connected) {
+            mService.wakeUp();
+        }
+        if (mService.getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
+            mCecMessageCache.flushAll();
+        } else {
+            if (connected) {
+                launchDeviceDiscovery();
+            } else {
+                // TODO(amyjojo): remove device from mDeviceInfo
+            }
+        }
     }
 
     @Override
@@ -69,7 +268,7 @@
         mTvSystemAudioModeSupport = false;
         // Record the last state of System Audio Control before going to standby
         synchronized (mLock) {
-            SystemProperties.set(
+            mService.writeStringSystemProperty(
                     Constants.PROPERTY_LAST_SYSTEM_AUDIO_CONTROL,
                     mSystemAudioActivated ? "true" : "false");
         }
@@ -80,6 +279,10 @@
     @ServiceThreadOnly
     protected void onAddressAllocated(int logicalAddress, int reason) {
         assertRunOnServiceThread();
+        if (reason == mService.INITIATED_BY_ENABLE_CEC) {
+            mService.setAndBroadcastActiveSource(mService.getPhysicalAddress(),
+                    getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST);
+        }
         mService.sendCecCommand(
                 HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                         mAddress, mService.getPhysicalAddress(), mDeviceType));
@@ -92,49 +295,119 @@
         boolean lastSystemAudioControlStatus =
                 SystemProperties.getBoolean(Constants.PROPERTY_LAST_SYSTEM_AUDIO_CONTROL, true);
         systemAudioControlOnPowerOn(systemAudioControlOnPowerOnProp, lastSystemAudioControlStatus);
+        clearDeviceInfoList();
+        launchDeviceDiscovery();
         startQueuedActions();
     }
 
+    @Override
+    protected int findKeyReceiverAddress() {
+        if (getActiveSource().isValid()) {
+            return getActiveSource().logicalAddress;
+        }
+        return Constants.ADDR_INVALID;
+    }
+
     @VisibleForTesting
     protected void systemAudioControlOnPowerOn(
             int systemAudioOnPowerOnProp, boolean lastSystemAudioControlStatus) {
         if ((systemAudioOnPowerOnProp == ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
                 || ((systemAudioOnPowerOnProp == USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
-                        && lastSystemAudioControlStatus)) {
+                && lastSystemAudioControlStatus && isSystemAudioControlFeatureEnabled())) {
             addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
         }
     }
 
-    @ServiceThreadOnly
-    protected boolean handleActiveSource(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        int logicalAddress = message.getSource();
-        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
-        ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
-        if (!mActiveSource.equals(activeSource)) {
-            setActiveSource(activeSource);
-        }
-        return true;
-    }
-
     @Override
     @ServiceThreadOnly
     protected int getPreferredAddress() {
         assertRunOnServiceThread();
         return SystemProperties.getInt(
-                Constants.PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM, Constants.ADDR_UNREGISTERED);
+            Constants.PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM, Constants.ADDR_UNREGISTERED);
     }
 
     @Override
     @ServiceThreadOnly
     protected void setPreferredAddress(int addr) {
         assertRunOnServiceThread();
-        SystemProperties.set(
+        mService.writeStringSystemProperty(
                 Constants.PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM, String.valueOf(addr));
     }
 
     @Override
     @ServiceThreadOnly
+    protected boolean handleReportPhysicalAddress(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        int path = HdmiUtils.twoBytesToInt(message.getParams());
+        int address = message.getSource();
+        int type = message.getParams()[2];
+
+        // Ignore if [Device Discovery Action] is going on.
+        if (hasAction(DeviceDiscoveryAction.class)) {
+            Slog.i(TAG, "Ignored while Device Discovery Action is in progress: " + message);
+            return true;
+        }
+
+        // Update the device info with TIF, note that the same device info could have added in
+        // device discovery and we do not want to override it with default OSD name. Therefore we
+        // need the following check to skip redundant device info updating.
+        HdmiDeviceInfo oldDevice = getCecDeviceInfo(address);
+        if (oldDevice == null || oldDevice.getPhysicalAddress() != path) {
+            addCecDevice(new HdmiDeviceInfo(
+                    address, path, mService.pathToPortId(path), type,
+                    Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(address)));
+            // if we are adding a new device info, send out a give osd name command
+            // to update the name of the device in TIF
+            mService.sendCecCommand(
+                    HdmiCecMessageBuilder.buildGiveOsdNameCommand(mAddress, address));
+            return true;
+        }
+
+        Slog.w(TAG, "Device info exists. Not updating on Physical Address.");
+        return true;
+    }
+
+    @Override
+    protected boolean handleReportPowerStatus(HdmiCecMessage command) {
+        int newStatus = command.getParams()[0] & 0xFF;
+        updateDevicePowerStatus(command.getSource(), newStatus);
+        return true;
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleSetOsdName(HdmiCecMessage message) {
+        int source = message.getSource();
+        String osdName;
+        HdmiDeviceInfo deviceInfo = getCecDeviceInfo(source);
+        // If the device is not in device list, ignore it.
+        if (deviceInfo == null) {
+            Slog.i(TAG, "No source device info for <Set Osd Name>." + message);
+            return true;
+        }
+        try {
+            osdName = new String(message.getParams(), "US-ASCII");
+        } catch (UnsupportedEncodingException e) {
+            Slog.e(TAG, "Invalid <Set Osd Name> request:" + message, e);
+            return true;
+        }
+
+        if (deviceInfo.getDisplayName().equals(osdName)) {
+            Slog.d(TAG, "Ignore incoming <Set Osd Name> having same osd name:" + message);
+            return true;
+        }
+
+        Slog.d(TAG, "Updating device OSD name from "
+                + deviceInfo.getDisplayName()
+                + " to " + osdName);
+        updateCecDevice(new HdmiDeviceInfo(deviceInfo.getLogicalAddress(),
+                deviceInfo.getPhysicalAddress(), deviceInfo.getPortId(),
+                deviceInfo.getDeviceType(), deviceInfo.getVendorId(), osdName));
+        return true;
+    }
+
+    @Override
+    @ServiceThreadOnly
     protected boolean handleReportAudioStatus(HdmiCecMessage message) {
         assertRunOnServiceThread();
         // TODO(amyjojo): implement report audio status handler
@@ -173,8 +446,11 @@
     @ServiceThreadOnly
     protected boolean handleGiveAudioStatus(HdmiCecMessage message) {
         assertRunOnServiceThread();
-
-        reportAudioStatus(message);
+        if (isSystemAudioControlFeatureEnabled()) {
+            reportAudioStatus(message.getSource());
+        } else {
+            mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+        }
         return true;
     }
 
@@ -192,7 +468,8 @@
     @ServiceThreadOnly
     protected boolean handleRequestArcInitiate(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        if (!SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)) {
+        removeAction(ArcInitiationActionFromAvr.class);
+        if (!mService.readBooleanSystemProperty(Constants.PROPERTY_ARC_SUPPORT, true)) {
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNRECOGNIZED_OPCODE);
         } else if (!isDirectConnectToTv()) {
             HdmiLogger.debug("AVR device is not directly connected with TV");
@@ -213,6 +490,7 @@
             HdmiLogger.debug("ARC is not established between TV and AVR device");
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE);
         } else {
+            removeAction(ArcTerminationActionFromAvr.class);
             addAndStartAction(new ArcTerminationActionFromAvr(this));
         }
         return true;
@@ -230,13 +508,35 @@
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE);
             return true;
         }
-        AudioDeviceInfo deviceInfo = getSystemAudioDeviceInfo();
-        if (deviceInfo == null) {
-            mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNABLE_TO_DETERMINE);
-            return true;
+
+        List<DeviceConfig> config = null;
+        File file = new File(SHORT_AUDIO_DESCRIPTOR_CONFIG_PATH);
+        if (file.exists()) {
+            try {
+                InputStream in = new FileInputStream(file);
+                config = HdmiUtils.ShortAudioDescriptorXmlParser.parse(in);
+                in.close();
+            } catch (IOException e) {
+                Slog.e(TAG, "Error reading file: " + file, e);
+            } catch (XmlPullParserException e) {
+                Slog.e(TAG, "Unable to parse file: " + file, e);
+            }
         }
+
         @AudioCodec int[] audioFormatCodes = parseAudioFormatCodes(message.getParams());
-        byte[] sadBytes = getSupportedShortAudioDescriptors(deviceInfo, audioFormatCodes);
+        byte[] sadBytes;
+        if (config != null && config.size() > 0) {
+            sadBytes = getSupportedShortAudioDescriptorsFromConfig(config, audioFormatCodes);
+        } else {
+            AudioDeviceInfo deviceInfo = getSystemAudioDeviceInfo();
+            if (deviceInfo == null) {
+                mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNABLE_TO_DETERMINE);
+                return true;
+            }
+
+            sadBytes = getSupportedShortAudioDescriptors(deviceInfo, audioFormatCodes);
+        }
+
         if (sadBytes.length == 0) {
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_INVALID_OPERAND);
         } else {
@@ -249,14 +549,127 @@
 
     private byte[] getSupportedShortAudioDescriptors(
             AudioDeviceInfo deviceInfo, @AudioCodec int[] audioFormatCodes) {
-        // TODO(b/80297701) implement
-        return new byte[] {};
+        ArrayList<byte[]> sads = new ArrayList<>(audioFormatCodes.length);
+        for (@AudioCodec int audioFormatCode : audioFormatCodes) {
+            byte[] sad = getSupportedShortAudioDescriptor(deviceInfo, audioFormatCode);
+            if (sad != null) {
+                if (sad.length == 3) {
+
+                    sads.add(sad);
+                } else {
+                    HdmiLogger.warning(
+                            "Dropping Short Audio Descriptor with length %d for requested codec %x",
+                            sad.length, audioFormatCode);
+                }
+            }
+        }
+        return getShortAudioDescriptorBytes(sads);
+    }
+
+    private byte[] getSupportedShortAudioDescriptorsFromConfig(
+            List<DeviceConfig> deviceConfig, @AudioCodec int[] audioFormatCodes) {
+        DeviceConfig deviceConfigToUse = null;
+        for (DeviceConfig device : deviceConfig) {
+            // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
+            if (device.name.equals("VX_AUDIO_DEVICE_IN_HDMI_ARC")) {
+                deviceConfigToUse = device;
+                break;
+            }
+        }
+        if (deviceConfigToUse == null) {
+            // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
+            Slog.w(TAG, "sadConfig.xml does not have required device info for "
+                        + "VX_AUDIO_DEVICE_IN_HDMI_ARC");
+            return new byte[0];
+        }
+        HashMap<Integer, byte[]> map = new HashMap<>();
+        ArrayList<byte[]> sads = new ArrayList<>(audioFormatCodes.length);
+        for (CodecSad codecSad : deviceConfigToUse.supportedCodecs) {
+            map.put(codecSad.audioCodec, codecSad.sad);
+        }
+        for (int i = 0; i < audioFormatCodes.length; i++) {
+            if (map.containsKey(audioFormatCodes[i])) {
+                byte[] sad = map.get(audioFormatCodes[i]);
+                if (sad != null && sad.length == 3) {
+                    sads.add(sad);
+                }
+            }
+        }
+        return getShortAudioDescriptorBytes(sads);
+    }
+
+    private byte[] getShortAudioDescriptorBytes(ArrayList<byte[]> sads) {
+        // Short Audio Descriptors are always 3 bytes long.
+        byte[] bytes = new byte[sads.size() * 3];
+        int index = 0;
+        for (byte[] sad : sads) {
+            System.arraycopy(sad, 0, bytes, index, 3);
+            index += 3;
+        }
+        return bytes;
+    }
+
+    /**
+     * Returns a 3 byte short audio descriptor as described in CEC 1.4 table 29 or null if the
+     * audioFormatCode is not supported.
+     */
+    @Nullable
+    private byte[] getSupportedShortAudioDescriptor(
+            AudioDeviceInfo deviceInfo, @AudioCodec int audioFormatCode) {
+        switch (audioFormatCode) {
+            case Constants.AUDIO_CODEC_NONE: {
+                return null;
+            }
+            case Constants.AUDIO_CODEC_LPCM: {
+                return getLpcmShortAudioDescriptor(deviceInfo);
+            }
+            // TODO(b/80297701): implement the rest of the codecs
+            case Constants.AUDIO_CODEC_DD:
+            case Constants.AUDIO_CODEC_MPEG1:
+            case Constants.AUDIO_CODEC_MP3:
+            case Constants.AUDIO_CODEC_MPEG2:
+            case Constants.AUDIO_CODEC_AAC:
+            case Constants.AUDIO_CODEC_DTS:
+            case Constants.AUDIO_CODEC_ATRAC:
+            case Constants.AUDIO_CODEC_ONEBITAUDIO:
+            case Constants.AUDIO_CODEC_DDP:
+            case Constants.AUDIO_CODEC_DTSHD:
+            case Constants.AUDIO_CODEC_TRUEHD:
+            case Constants.AUDIO_CODEC_DST:
+            case Constants.AUDIO_CODEC_WMAPRO:
+            default: {
+                return null;
+            }
+        }
+    }
+
+    @Nullable
+    private byte[] getLpcmShortAudioDescriptor(AudioDeviceInfo deviceInfo) {
+        // TODO(b/80297701): implement
+        return null;
     }
 
     @Nullable
     private AudioDeviceInfo getSystemAudioDeviceInfo() {
-        // TODO(b/80297701) implement
-        // Get the audio device used for system audio mode.
+        AudioManager audioManager = mService.getContext().getSystemService(AudioManager.class);
+        if (audioManager == null) {
+            HdmiLogger.error(
+                    "Error getting system audio device because AudioManager not available.");
+            return null;
+        }
+        AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
+        HdmiLogger.debug("Found %d audio input devices", devices.length);
+        for (AudioDeviceInfo device : devices) {
+            HdmiLogger.debug("%s at port %s", device.getProductName(), device.getPort());
+            HdmiLogger.debug("Supported encodings are %s",
+                    Arrays.stream(device.getEncodings()).mapToObj(
+                            AudioFormat::toLogFriendlyEncoding
+                    ).collect(Collectors.joining(", ")));
+            // TODO(b/80297701) use the actual device type that system audio mode is connected to.
+            if (device.getType() == AudioDeviceInfo.TYPE_HDMI_ARC) {
+                return device;
+            }
+        }
         return null;
     }
 
@@ -266,7 +679,7 @@
         for (int i = 0; i < params.length; i++) {
             byte val = params[i];
             audioFormatCodes[i] =
-                    val >= 1 && val <= Constants.AUDIO_CODEC_MAX ? val : Constants.AUDIO_CODEC_NONE;
+                val >= 1 && val <= Constants.AUDIO_CODEC_MAX ? val : Constants.AUDIO_CODEC_NONE;
         }
         return audioFormatCodes;
     }
@@ -276,7 +689,23 @@
     protected boolean handleSystemAudioModeRequest(HdmiCecMessage message) {
         assertRunOnServiceThread();
         boolean systemAudioStatusOn = message.getParams().length != 0;
-        if (!setSystemAudioMode(systemAudioStatusOn)) {
+        // Check if the request comes from a non-TV device.
+        // Need to check if TV supports System Audio Control
+        // if non-TV device tries to turn on the feature
+        if (message.getSource() != Constants.ADDR_TV) {
+            if (systemAudioStatusOn) {
+                handleSystemAudioModeOnFromNonTvDevice(message);
+                return true;
+            }
+        } else {
+            // If TV request the feature on
+            // cache TV supporting System Audio Control
+            // until Audio System loses its physical address.
+            setTvSystemAudioModeSupport(true);
+        }
+        // If TV or Audio System does not support the feature,
+        // will send abort command.
+        if (!checkSupportAndSetSystemAudioMode(systemAudioStatusOn)) {
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
             return true;
         }
@@ -291,7 +720,8 @@
     @ServiceThreadOnly
     protected boolean handleSetSystemAudioMode(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        if (!setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message))) {
+        if (!checkSupportAndSetSystemAudioMode(
+                HdmiUtils.parseCommandParamSystemAudioStatus(message))) {
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
         }
         return true;
@@ -301,7 +731,8 @@
     @ServiceThreadOnly
     protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) {
         assertRunOnServiceThread();
-        if (!setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message))) {
+        if (!checkSupportAndSetSystemAudioMode(
+                HdmiUtils.parseCommandParamSystemAudioStatus(message))) {
             mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
         }
         return true;
@@ -333,23 +764,35 @@
     private void notifyArcStatusToAudioService(boolean enabled) {
         // Note that we don't set any name to ARC.
         mService.getAudioManager()
-                .setWiredDeviceConnectionState(AudioSystem.DEVICE_IN_HDMI, enabled ? 1 : 0, "", "");
+            .setWiredDeviceConnectionState(AudioSystem.DEVICE_IN_HDMI, enabled ? 1 : 0, "", "");
     }
 
-    private void reportAudioStatus(HdmiCecMessage message) {
+    void reportAudioStatus(int source) {
         assertRunOnServiceThread();
 
         int volume = mService.getAudioManager().getStreamVolume(AudioManager.STREAM_MUSIC);
         boolean mute = mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC);
         int maxVolume = mService.getAudioManager().getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        int minVolume = mService.getAudioManager().getStreamMinVolume(AudioManager.STREAM_MUSIC);
         int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume);
+        HdmiLogger.debug("Reporting volume %i (%i-%i) as CEC volume %i", volume,
+                minVolume, maxVolume, scaledVolume);
 
         mService.sendCecCommand(
                 HdmiCecMessageBuilder.buildReportAudioStatus(
-                        mAddress, message.getSource(), scaledVolume, mute));
+                        mAddress, source, scaledVolume, mute));
     }
 
-    protected boolean setSystemAudioMode(boolean newSystemAudioMode) {
+    /**
+     * Method to check if device support System Audio Control. If so, wake up device if necessary.
+     *
+     * <p> then call {@link #setSystemAudioMode(boolean)} to turn on or off System Audio Mode
+     * @param newSystemAudioMode turning feature on or off. True is on. False is off.
+     * @return true or false.
+     *
+     * <p>False when device does not support the feature. Otherwise returns true.
+     */
+    protected boolean checkSupportAndSetSystemAudioMode(boolean newSystemAudioMode) {
         if (!isSystemAudioControlFeatureEnabled()) {
             HdmiLogger.debug(
                     "Cannot turn "
@@ -361,15 +804,43 @@
         HdmiLogger.debug(
                 "System Audio Mode change[old:%b new:%b]",
                 mSystemAudioActivated, newSystemAudioMode);
-        // Wake up device if System Audio Control is turned on but device is still on standby
-        if (newSystemAudioMode && mService.isPowerStandbyOrTransient()) {
+        // Wake up device if System Audio Control is turned on
+        if (newSystemAudioMode) {
             mService.wakeUp();
         }
+        setSystemAudioMode(newSystemAudioMode);
+        return true;
+    }
+
+    /**
+     * Real work to turn on or off System Audio Mode.
+     *
+     * Use {@link #checkSupportAndSetSystemAudioMode(boolean)}
+     * if trying to turn on or off the feature.
+     */
+    private void setSystemAudioMode(boolean newSystemAudioMode) {
         int targetPhysicalAddress = getActiveSource().physicalAddress;
-        if (newSystemAudioMode && !isPhysicalAddressMeOrBelow(targetPhysicalAddress)) {
+        int port = mService.pathToPortId(targetPhysicalAddress);
+        if (newSystemAudioMode && port >= 0) {
             switchToAudioInput();
         }
-        // TODO(b/80297700): Mute device when TV terminates the system audio control
+        // Mute device when feature is turned off and unmute device when feature is turned on.
+        // PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE is false when device never needs to be muted.
+        boolean currentMuteStatus =
+                mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC);
+        if (currentMuteStatus == newSystemAudioMode) {
+            if (mService.readBooleanSystemProperty(
+                    Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, true)
+                            || newSystemAudioMode) {
+                mService.getAudioManager()
+                        .adjustStreamVolume(
+                                AudioManager.STREAM_MUSIC,
+                                newSystemAudioMode
+                                        ? AudioManager.ADJUST_UNMUTE
+                                        : AudioManager.ADJUST_MUTE,
+                                0);
+            }
+        }
         updateAudioManagerForSystemAudio(newSystemAudioMode);
         synchronized (mLock) {
             if (mSystemAudioActivated != newSystemAudioMode) {
@@ -377,31 +848,19 @@
                 mService.announceSystemAudioModeChange(newSystemAudioMode);
             }
         }
-        return true;
-    }
-
-    /**
-     * Method to check if the target device belongs to the subtree of the current device or not.
-     *
-     * <p>Return true if it does or if the two devices share the same physical address.
-     *
-     * <p>This check assumes both device physical address and target address are valid.
-     *
-     * @param targetPhysicalAddress is the physical address of the target device
-     */
-    protected boolean isPhysicalAddressMeOrBelow(int targetPhysicalAddress) {
-        int myPhysicalAddress = mService.getPhysicalAddress();
-        int xor = targetPhysicalAddress ^ myPhysicalAddress;
-        // Return true if two addresses are the same
-        // or if they only differs for one byte, but not the first byte,
-        // and myPhysicalAddress is 0 after that byte
-        if (xor == 0
-                || ((xor & 0x0f00) == xor && (myPhysicalAddress & 0x0fff) == 0)
-                || ((xor & 0x00f0) == xor && (myPhysicalAddress & 0x00ff) == 0)
-                || ((xor & 0x000f) == xor && (myPhysicalAddress & 0x000f) == 0)) {
-            return true;
+        // Init arc whenever System Audio Mode is on
+        // Terminate arc when System Audio Mode is off
+        // Since some TVs don't request ARC on with System Audio Mode on request
+        if (SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)
+                && isDirectConnectToTv()) {
+            if (newSystemAudioMode && !isArcEnabled()) {
+                removeAction(ArcInitiationActionFromAvr.class);
+                addAndStartAction(new ArcInitiationActionFromAvr(this));
+            } else if (!newSystemAudioMode && isArcEnabled()) {
+                removeAction(ArcTerminationActionFromAvr.class);
+                addAndStartAction(new ArcTerminationActionFromAvr(this));
+            }
         }
-        return false;
     }
 
     protected void switchToAudioInput() {
@@ -418,6 +877,13 @@
         HdmiLogger.debug("[A]UpdateSystemAudio mode[on=%b] output=[%X]", on, device);
     }
 
+    void onSystemAduioControlFeatureSupportChanged(boolean enabled) {
+        setSystemAudioControlFeatureEnabled(enabled);
+        if (enabled) {
+            addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
+        }
+    }
+
     @ServiceThreadOnly
     void setSystemAudioControlFeatureEnabled(boolean enabled) {
         assertRunOnServiceThread();
@@ -426,6 +892,42 @@
         }
     }
 
+    @ServiceThreadOnly
+    void setRoutingControlFeatureEnables(boolean enabled) {
+        assertRunOnServiceThread();
+        synchronized (mLock) {
+            mRoutingControlFeatureEnabled = enabled;
+        }
+    }
+
+    @ServiceThreadOnly
+    void doManualPortSwitching(int portId, IHdmiControlCallback callback) {
+        assertRunOnServiceThread();
+        // TODO: validate port ID
+        if (portId == getLocalActivePort()) {
+            invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
+            return;
+        }
+        if (!mService.isControlEnabled()) {
+            setRoutingPort(portId);
+            setLocalActivePort(portId);
+            invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
+            return;
+        }
+        int oldPath = getRoutingPort() != Constants.CEC_SWITCH_HOME
+                ? mService.portIdToPath(getRoutingPort())
+                : getDeviceInfo().getPhysicalAddress();
+        int newPath = mService.portIdToPath(portId);
+        if (oldPath == newPath) {
+            return;
+        }
+        setRoutingPort(portId);
+        setLocalActivePort(portId);
+        HdmiCecMessage routingChange =
+                HdmiCecMessageBuilder.buildRoutingChange(mAddress, oldPath, newPath);
+        mService.sendCecCommand(routingChange);
+    }
+
     boolean isSystemAudioControlFeatureEnabled() {
         synchronized (mLock) {
             return mSystemAudioControlFeatureEnabled;
@@ -445,7 +947,7 @@
             return;
         }
 
-        if (setSystemAudioMode(false)) {
+        if (checkSupportAndSetSystemAudioMode(false)) {
             // send <Set System Audio Mode> [“Off”]
             mService.sendCecCommand(
                     HdmiCecMessageBuilder.buildSetSystemAudioMode(
@@ -468,6 +970,7 @@
      * <p>The result of the query may be cached until Audio device type is put in standby or loses
      * its physical address.
      */
+    // TODO(amyjojo): making mTvSystemAudioModeSupport null originally and fix the logic.
     void queryTvSystemAudioModeSupport(TvSystemAudioModeSupportedCallback callback) {
         if (!mTvSystemAudioModeSupport) {
             addAndStartAction(new DetectTvSystemAudioModeSupportAction(this, callback));
@@ -476,6 +979,35 @@
         }
     }
 
+    /**
+     * Handler of System Audio Mode Request on from non TV device
+     */
+    void handleSystemAudioModeOnFromNonTvDevice(HdmiCecMessage message) {
+        if (!isSystemAudioControlFeatureEnabled()) {
+            HdmiLogger.debug(
+                    "Cannot turn on" + "system audio mode "
+                            + "because the System Audio Control feature is disabled.");
+            mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+            return;
+        }
+        // Wake up device
+        mService.wakeUp();
+        // Check if TV supports System Audio Control.
+        // Handle broadcasting setSystemAudioMode on or aborting message on callback.
+        queryTvSystemAudioModeSupport(new TvSystemAudioModeSupportedCallback() {
+            public void onResult(boolean supported) {
+                if (supported) {
+                    setSystemAudioMode(true);
+                    mService.sendCecCommand(
+                            HdmiCecMessageBuilder.buildSetSystemAudioMode(
+                                    mAddress, Constants.ADDR_BROADCAST, true));
+                } else {
+                    mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+                }
+            }
+        });
+    }
+
     void setTvSystemAudioModeSupport(boolean supported) {
         mTvSystemAudioModeSupport = supported;
     }
@@ -486,4 +1018,195 @@
             return mArcEstablished;
         }
     }
+
+    @Override
+    protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
+        int port = mService.pathToPortId(physicalAddress);
+        if (isSystemAudioActivated() && port < 0) {
+            // If system audio mode is on and the new active source is not under the current device,
+            // Will switch to ARC input.
+            // TODO(b/115637145): handle system aduio without ARC
+            routeToInputFromPortId(Constants.CEC_SWITCH_ARC);
+        } else if (mIsSwitchDevice && port >= 0) {
+            // If current device is a switch and the new active source is under it,
+            // will switch to the corresponding active path.
+            routeToInputFromPortId(port);
+        }
+    }
+
+    protected void routeToInputFromPortId(int portId) {
+        if (!isRoutingControlFeatureEnabled()) {
+            HdmiLogger.debug("Routing Control Feature is not enabled.");
+            return;
+        }
+        if (mArcIntentUsed) {
+            routeToTvInputFromPortId(portId);
+        } else {
+            // TODO(): implement input switching for devices not using TvInput.
+        }
+    }
+
+    protected void routeToTvInputFromPortId(int portId) {
+        if (portId < 0 || portId >= Constants.CEC_SWITCH_PORT_MAX) {
+            HdmiLogger.debug("Invalid port number for Tv Input switching.");
+            return;
+        }
+        // Wake up if the current device if ready to route.
+        mService.wakeUp();
+        if (portId == Constants.CEC_SWITCH_HOME && mService.isPlaybackDevice()) {
+            switchToHomeTvInput();
+        } else if (portId == Constants.CEC_SWITCH_ARC) {
+            switchToTvInput(SystemProperties.get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT));
+            setLocalActivePort(portId);
+            return;
+        } else {
+            String uri = mTvInputs.get(portId);
+            if (uri != null) {
+                switchToTvInput(mTvInputs.get(portId));
+            } else {
+                HdmiLogger.debug("Port number does not match any Tv Input.");
+                return;
+            }
+        }
+
+        setLocalActivePort(portId);
+        setRoutingPort(portId);
+    }
+
+    // For device to switch to specific TvInput with corresponding URI.
+    private void switchToTvInput(String uri) {
+        mService.getContext().startActivity(new Intent(Intent.ACTION_VIEW,
+                TvContract.buildChannelUriForPassthroughInput(uri))
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+    }
+
+    // For device using TvInput to switch to Home.
+    private void switchToHomeTvInput() {
+        Intent activityIntent = new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME)
+                .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
+                        | Intent.FLAG_ACTIVITY_SINGLE_TOP
+                        | Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_NO_ANIMATION);
+        mService.getContext().startActivity(activityIntent);
+    }
+
+    @Override
+    protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
+        int port = mService.pathToPortId(physicalAddress);
+        // Routing change or information sent from switches under the current device can be ignored.
+        if (port > 0) {
+            return;
+        }
+        // When other switches route to some other devices not under the current device,
+        // check system audio mode status and do ARC switch if needed.
+        if (port < 0 && isSystemAudioActivated()) {
+            handleRoutingChangeAndInformationForSystemAudio();
+            return;
+        }
+        // When other switches route to the current device
+        // and the current device is also a switch.
+        if (port == 0) {
+            handleRoutingChangeAndInformationForSwitch(message);
+        }
+    }
+
+    // Handle the system audio(ARC) part of the logic on receiving routing change or information.
+    private void handleRoutingChangeAndInformationForSystemAudio() {
+        // TODO(b/115637145): handle system aduio without ARC
+        routeToInputFromPortId(Constants.CEC_SWITCH_ARC);
+    }
+
+    // Handle the routing control part of the logic on receiving routing change or information.
+    private void handleRoutingChangeAndInformationForSwitch(HdmiCecMessage message) {
+        if (getRoutingPort() == Constants.CEC_SWITCH_HOME && mService.isPlaybackDevice()) {
+            routeToInputFromPortId(Constants.CEC_SWITCH_HOME);
+            mService.setAndBroadcastActiveSourceFromOneDeviceType(
+                    message.getSource(), mService.getPhysicalAddress());
+            return;
+        }
+
+        int routingInformationPath = mService.portIdToPath(getRoutingPort());
+        // If current device is already the leaf of the whole HDMI system, will do nothing.
+        if (routingInformationPath == mService.getPhysicalAddress()) {
+            HdmiLogger.debug("Current device can't assign valid physical address"
+                    + "to devices under it any more. "
+                    + "It's physical address is " + routingInformationPath);
+            return;
+        }
+        // Otherwise will switch to the current active port and broadcast routing information.
+        mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingInformation(
+                mAddress, routingInformationPath));
+        routeToInputFromPortId(getRoutingPort());
+    }
+
+    protected void updateDevicePowerStatus(int logicalAddress, int newPowerStatus) {
+        HdmiDeviceInfo info = getCecDeviceInfo(logicalAddress);
+        if (info == null) {
+            Slog.w(TAG, "Can not update power status of non-existing device:" + logicalAddress);
+            return;
+        }
+
+        if (info.getDevicePowerStatus() == newPowerStatus) {
+            return;
+        }
+
+        HdmiDeviceInfo newInfo = HdmiUtils.cloneHdmiDeviceInfo(info, newPowerStatus);
+        // addDeviceInfo replaces old device info with new one if exists.
+        addDeviceInfo(newInfo);
+
+        invokeDeviceEventListener(newInfo, HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE);
+    }
+
+    @ServiceThreadOnly
+    private void launchDeviceDiscovery() {
+        assertRunOnServiceThread();
+        if (hasAction(DeviceDiscoveryAction.class)) {
+            Slog.i(TAG, "Device Discovery Action is in progress. Restarting.");
+            removeAction(DeviceDiscoveryAction.class);
+        }
+        DeviceDiscoveryAction action = new DeviceDiscoveryAction(this,
+                new DeviceDiscoveryCallback() {
+                    @Override
+                    public void onDeviceDiscoveryDone(List<HdmiDeviceInfo> deviceInfos) {
+                        for (HdmiDeviceInfo info : deviceInfos) {
+                            addCecDevice(info);
+                        }
+                    }
+                });
+        addAndStartAction(action);
+    }
+
+    // Clear all device info.
+    @ServiceThreadOnly
+    private void clearDeviceInfoList() {
+        assertRunOnServiceThread();
+        for (HdmiDeviceInfo info : HdmiUtils.sparseArrayToList(mDeviceInfos)) {
+            if (info.getPhysicalAddress() == mService.getPhysicalAddress()) {
+                continue;
+            }
+            invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
+        }
+        mDeviceInfos.clear();
+        updateSafeDeviceInfoList();
+    }
+
+    @Override
+    protected void dump(IndentingPrintWriter pw) {
+        pw.println("HdmiCecLocalDeviceAudioSystem:");
+        pw.increaseIndent();
+        pw.println("mSystemAudioActivated: " + mSystemAudioActivated);
+        pw.println("isRoutingFeatureEnabled " + isRoutingControlFeatureEnabled());
+        pw.println("mSystemAudioControlFeatureEnabled: " + mSystemAudioControlFeatureEnabled);
+        pw.println("mTvSystemAudioModeSupport: " + mTvSystemAudioModeSupport);
+        pw.println("mArcEstablished: " + mArcEstablished);
+        pw.println("mArcIntentUsed: " + mArcIntentUsed);
+        pw.println("mRoutingPort: " + getRoutingPort());
+        pw.println("mLocalActivePort: " + getLocalActivePort());
+        HdmiUtils.dumpMap(pw, "mTvInputs:", mTvInputs);
+        HdmiUtils.dumpSparseArray(pw, "mDeviceInfos:", mDeviceInfos);
+        pw.decreaseIndent();
+        super.dump(pw);
+    }
+
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index d45b00b..ef7d241 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -21,11 +21,11 @@
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
-import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.provider.Settings.Global;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.LocalePicker;
 import com.android.internal.app.LocalePicker.LocaleInfo;
 import com.android.internal.util.IndentingPrintWriter;
@@ -35,12 +35,10 @@
 import java.util.List;
 import java.util.Locale;
 
-import java.util.List;
-
 /**
  * Represent a logical device of type Playback residing in Android system.
  */
-final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
+public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
     private static final String TAG = "HdmiCecLocalDevicePlayback";
 
     private static final boolean WAKE_ON_HOTPLUG =
@@ -49,8 +47,6 @@
     private static final boolean SET_MENU_LANGUAGE =
             SystemProperties.getBoolean(Constants.PROPERTY_SET_MENU_LANGUAGE, false);
 
-    private boolean mIsActiveSource = false;
-
     // Used to keep the device awake while it is the active source. For devices that
     // cannot wake up via CEC commands, this address the inconvenience of having to
     // turn them on. True by default, and can be disabled (i.e. device can go to sleep
@@ -62,6 +58,11 @@
     // If true, turn off TV upon standby. False by default.
     private boolean mAutoTvOff;
 
+    // Local active port number used for Routing Control.
+    // Default 0 means HOME is the current active path. Temp solution only.
+    // TODO(amyjojo): adding system constants for input ports to TIF mapping.
+    private int mLocalActivePath = 0;
+
     HdmiCecLocalDevicePlayback(HdmiControlService service) {
         super(service, HdmiDeviceInfo.DEVICE_PLAYBACK);
 
@@ -76,6 +77,10 @@
     @ServiceThreadOnly
     protected void onAddressAllocated(int logicalAddress, int reason) {
         assertRunOnServiceThread();
+        if (reason == mService.INITIATED_BY_ENABLE_CEC) {
+            mService.setAndBroadcastActiveSource(mService.getPhysicalAddress(),
+                    getDeviceInfo().getDeviceType(), Constants.ADDR_BROADCAST);
+        }
         mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                 mAddress, mService.getPhysicalAddress(), mDeviceType));
         mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
@@ -95,30 +100,11 @@
     @ServiceThreadOnly
     protected void setPreferredAddress(int addr) {
         assertRunOnServiceThread();
-        SystemProperties.set(Constants.PROPERTY_PREFERRED_ADDRESS_PLAYBACK,
+        mService.writeStringSystemProperty(Constants.PROPERTY_PREFERRED_ADDRESS_PLAYBACK,
                 String.valueOf(addr));
     }
 
     @ServiceThreadOnly
-    void oneTouchPlay(IHdmiControlCallback callback) {
-        assertRunOnServiceThread();
-        List<OneTouchPlayAction> actions = getActions(OneTouchPlayAction.class);
-        if (!actions.isEmpty()) {
-            Slog.i(TAG, "oneTouchPlay already in progress");
-            actions.get(0).addCallback(callback);
-            return;
-        }
-        OneTouchPlayAction action = OneTouchPlayAction.create(this, Constants.ADDR_TV,
-                callback);
-        if (action == null) {
-            Slog.w(TAG, "Cannot initiate oneTouchPlay");
-            invokeCallback(callback, HdmiControlManager.RESULT_EXCEPTION);
-            return;
-        }
-        addAndStartAction(action);
-    }
-
-    @ServiceThreadOnly
     void queryDisplayStatus(IHdmiControlCallback callback) {
         assertRunOnServiceThread();
         List<DevicePowerStatusAction> actions = getActions(DevicePowerStatusAction.class);
@@ -137,16 +123,6 @@
         addAndStartAction(action);
     }
 
-    @ServiceThreadOnly
-    private void invokeCallback(IHdmiControlCallback callback, int result) {
-        assertRunOnServiceThread();
-        try {
-            callback.onComplete(result);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Invoking callback failed:" + e);
-        }
-    }
-
     @Override
     @ServiceThreadOnly
     void onHotplug(int portId, boolean connected) {
@@ -189,7 +165,8 @@
     }
 
     @ServiceThreadOnly
-    void setActiveSource(boolean on) {
+    @VisibleForTesting
+    void setIsActiveSource(boolean on) {
         assertRunOnServiceThread();
         mIsActiveSource = on;
         if (on) {
@@ -227,21 +204,6 @@
         return !getWakeLock().isHeld();
     }
 
-    @Override
-    @ServiceThreadOnly
-    protected boolean handleActiveSource(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
-        mayResetActiveSource(physicalAddress);
-        return true;  // Broadcast message.
-    }
-
-    private void mayResetActiveSource(int physicalAddress) {
-        if (physicalAddress != mService.getPhysicalAddress()) {
-            setActiveSource(false);
-        }
-    }
-
     @ServiceThreadOnly
     protected boolean handleUserControlPressed(HdmiCecMessage message) {
         assertRunOnServiceThread();
@@ -250,42 +212,7 @@
     }
 
     @Override
-    @ServiceThreadOnly
-    protected boolean handleSetStreamPath(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
-        maySetActiveSource(physicalAddress);
-        maySendActiveSource(message.getSource());
-        wakeUpIfActiveSource();
-        return true;  // Broadcast message.
-    }
-
-    // Samsung model we tested sends <Routing Change> and <Request Active Source>
-    // in a row, and then changes the input to the internal source if there is no
-    // <Active Source> in response. To handle this, we'll set ActiveSource aggressively.
-    @Override
-    @ServiceThreadOnly
-    protected boolean handleRoutingChange(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        int newPath = HdmiUtils.twoBytesToInt(message.getParams(), 2);
-        maySetActiveSource(newPath);
-        return true;  // Broadcast message.
-    }
-
-    @Override
-    @ServiceThreadOnly
-    protected boolean handleRoutingInformation(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
-        maySetActiveSource(physicalAddress);
-        return true;  // Broadcast message.
-    }
-
-    private void maySetActiveSource(int physicalAddress) {
-        setActiveSource(physicalAddress == mService.getPhysicalAddress());
-    }
-
-    private void wakeUpIfActiveSource() {
+    protected void wakeUpIfActiveSource() {
         if (!mIsActiveSource) {
             return;
         }
@@ -296,7 +223,8 @@
         }
     }
 
-    private void maySendActiveSource(int dest) {
+    @Override
+    protected void maySendActiveSource(int dest) {
         if (mIsActiveSource) {
             mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
                     mAddress, mService.getPhysicalAddress()));
@@ -306,14 +234,6 @@
         }
     }
 
-    @Override
-    @ServiceThreadOnly
-    protected boolean handleRequestActiveSource(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        maySendActiveSource(message.getSource());
-        return true;  // Broadcast message.
-    }
-
     @ServiceThreadOnly
     protected boolean handleSetMenuLanguage(HdmiCecMessage message) {
         assertRunOnServiceThread();
@@ -361,16 +281,6 @@
 
     @Override
     @ServiceThreadOnly
-    protected void sendStandby(int deviceId) {
-        assertRunOnServiceThread();
-
-        // Playback device can send <Standby> to TV only. Ignore the parameter.
-        int targetAddress = Constants.ADDR_TV;
-        mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby(mAddress, targetAddress));
-    }
-
-    @Override
-    @ServiceThreadOnly
     protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) {
         super.disableDevice(initiatedByCec, callback);
 
@@ -379,10 +289,20 @@
             mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(
                     mAddress, mService.getPhysicalAddress()));
         }
-        setActiveSource(false);
+        setIsActiveSource(false);
         checkIfPendingActionsCleared();
     }
 
+    private void routeToPort(int portId) {
+        // TODO(AMYJOJO): route to specific input of the port
+        mLocalActivePath = portId;
+    }
+
+    @VisibleForTesting
+    protected int getLocalActivePath() {
+        return mLocalActivePath;
+    }
+
     @Override
     protected void dump(final IndentingPrintWriter pw) {
         super.dump(pw);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
new file mode 100644
index 0000000..ae008b4
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -0,0 +1,307 @@
+/*
+ * 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.hdmi;
+
+import static com.android.internal.os.RoSystemProperties.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH;
+
+import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.hdmi.Constants.LocalActivePort;
+import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
+
+import java.util.List;
+
+/**
+ * Represent a logical source device residing in Android system.
+ */
+abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
+
+    private static final String TAG = "HdmiCecLocalDeviceSource";
+
+    // Indicate if current device is Active Source or not
+    @VisibleForTesting
+    protected boolean mIsActiveSource = false;
+
+    // Device has cec switch functionality or not.
+    // Default is false.
+    protected boolean mIsSwitchDevice = SystemProperties.getBoolean(
+            PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH, false);
+
+    // Routing port number used for Routing Control.
+    // This records the default routing port or the previous valid routing port.
+    // Default is HOME input.
+    // Note that we don't save active path here because for source device,
+    // new Active Source physical address might not match the active path
+    @GuardedBy("mLock")
+    @LocalActivePort
+    private int mRoutingPort = Constants.CEC_SWITCH_HOME;
+
+    // This records the current input of the device.
+    // When device is switched to ARC input, mRoutingPort does not record it
+    // since it's not an HDMI port used for Routing Control.
+    // mLocalActivePort will record whichever input we switch to to keep tracking on
+    // the current input status of the device.
+    // This can help prevent duplicate switching and provide status information.
+    @GuardedBy("mLock")
+    @LocalActivePort
+    protected int mLocalActivePort = Constants.CEC_SWITCH_HOME;
+
+    // Whether the Routing Coutrol feature is enabled or not. False by default.
+    @GuardedBy("mLock")
+    protected boolean mRoutingControlFeatureEnabled;
+
+    protected HdmiCecLocalDeviceSource(HdmiControlService service, int deviceType) {
+        super(service, deviceType);
+    }
+
+    @Override
+    @ServiceThreadOnly
+    void onHotplug(int portId, boolean connected) {
+        assertRunOnServiceThread();
+        if (mService.getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
+            mCecMessageCache.flushAll();
+        }
+        // We'll not clear mIsActiveSource on the hotplug event to pass CETC 11.2.2-2 ~ 3.
+        if (connected) {
+            mService.wakeUp();
+        }
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected void sendStandby(int deviceId) {
+        assertRunOnServiceThread();
+
+        // Send standby to TV only for now
+        int targetAddress = Constants.ADDR_TV;
+        mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby(mAddress, targetAddress));
+    }
+
+    @ServiceThreadOnly
+    void oneTouchPlay(IHdmiControlCallback callback) {
+        assertRunOnServiceThread();
+        List<OneTouchPlayAction> actions = getActions(OneTouchPlayAction.class);
+        if (!actions.isEmpty()) {
+            Slog.i(TAG, "oneTouchPlay already in progress");
+            actions.get(0).addCallback(callback);
+            return;
+        }
+        OneTouchPlayAction action = OneTouchPlayAction.create(this, Constants.ADDR_TV,
+                callback);
+        if (action == null) {
+            Slog.w(TAG, "Cannot initiate oneTouchPlay");
+            invokeCallback(callback, HdmiControlManager.RESULT_EXCEPTION);
+            return;
+        }
+        addAndStartAction(action);
+    }
+
+    @ServiceThreadOnly
+    protected boolean handleActiveSource(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        int logicalAddress = message.getSource();
+        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+        ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
+        if (!getActiveSource().equals(activeSource)) {
+            setActiveSource(activeSource);
+        }
+        setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
+        updateDevicePowerStatus(logicalAddress, HdmiControlManager.POWER_STATUS_ON);
+        if (isRoutingControlFeatureEnabled()) {
+            switchInputOnReceivingNewActivePath(physicalAddress);
+        }
+        return true;
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleRequestActiveSource(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        maySendActiveSource(message.getSource());
+        return true;
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleSetStreamPath(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+        // If current device is the target path, set to Active Source.
+        // If the path is under the current device, should switch
+        if (physicalAddress == mService.getPhysicalAddress() && mService.isPlaybackDevice()) {
+            setAndBroadcastActiveSource(message, physicalAddress);
+        }
+        switchInputOnReceivingNewActivePath(physicalAddress);
+        return true;
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleRoutingChange(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        if (!isRoutingControlFeatureEnabled()) {
+            mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+            return true;
+        }
+        int newPath = HdmiUtils.twoBytesToInt(message.getParams(), 2);
+        // if the current device is a pure playback device
+        if (!mIsSwitchDevice
+                && newPath == mService.getPhysicalAddress()
+                && mService.isPlaybackDevice()) {
+            setAndBroadcastActiveSource(message, newPath);
+        }
+        handleRoutingChangeAndInformation(newPath, message);
+        return true;
+    }
+
+    @Override
+    @ServiceThreadOnly
+    protected boolean handleRoutingInformation(HdmiCecMessage message) {
+        assertRunOnServiceThread();
+        if (!isRoutingControlFeatureEnabled()) {
+            mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+            return true;
+        }
+        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+        // if the current device is a pure playback device
+        if (!mIsSwitchDevice
+                && physicalAddress == mService.getPhysicalAddress()
+                && mService.isPlaybackDevice()) {
+            setAndBroadcastActiveSource(message, physicalAddress);
+        }
+        handleRoutingChangeAndInformation(physicalAddress, message);
+        return true;
+    }
+
+    // Method to switch Input with the new Active Path.
+    // All the devices with Switch functionality should implement this.
+    protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
+        // do nothing
+    }
+
+    // Source device with Switch functionality should implement this method.
+    // TODO(): decide which type will handle the routing when multi device type is supported
+    protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
+        // do nothing
+    }
+
+    // Update the power status of the devices connected to the current device.
+    // This only works if the current device is a switch and keeps tracking the device info
+    // of the device connected to it.
+    protected void updateDevicePowerStatus(int logicalAddress, int newPowerStatus) {
+        // do nothing
+    }
+
+    // Active source claiming needs to be handled in Service
+    // since service can decide who will be the active source when the device supports
+    // multiple device types in this method.
+    // This method should only be called when the device can be the active source.
+    protected void setAndBroadcastActiveSource(HdmiCecMessage message, int physicalAddress) {
+        mService.setAndBroadcastActiveSource(
+                physicalAddress, getDeviceInfo().getDeviceType(), message.getSource());
+    }
+
+    @ServiceThreadOnly
+    void setIsActiveSource(boolean on) {
+        assertRunOnServiceThread();
+        mIsActiveSource = on;
+    }
+
+    protected void wakeUpIfActiveSource() {
+        if (!mIsActiveSource) {
+            return;
+        }
+        // Wake up the device
+        mService.wakeUp();
+        return;
+    }
+
+    protected void maySendActiveSource(int dest) {
+        if (mIsActiveSource) {
+            mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
+                    mAddress, mService.getPhysicalAddress()));
+        }
+    }
+
+    /**
+     * Set {@link #mRoutingPort} to a specific {@link LocalActivePort} to record the current active
+     * CEC Routing Control related port.
+     *
+     * @param portId The portId of the new routing port.
+     */
+    @VisibleForTesting
+    protected void setRoutingPort(@LocalActivePort int portId) {
+        synchronized (mLock) {
+            mRoutingPort = portId;
+        }
+    }
+
+    /**
+     * Get {@link #mRoutingPort}. This is useful when the device needs to route to the last valid
+     * routing port.
+     */
+    @LocalActivePort
+    protected int getRoutingPort() {
+        synchronized (mLock) {
+            return mRoutingPort;
+        }
+    }
+
+    /**
+     * Get {@link #mLocalActivePort}. This is useful when device needs to know the current active
+     * port.
+     */
+    @LocalActivePort
+    protected int getLocalActivePort() {
+        synchronized (mLock) {
+            return mLocalActivePort;
+        }
+    }
+
+    /**
+     * Set {@link #mLocalActivePort} to a specific {@link LocalActivePort} to record the current
+     * active port.
+     *
+     * <p>It does not have to be a Routing Control related port. For example it can be
+     * set to {@link Constants#CEC_SWITCH_ARC} but this port is System Audio related.
+     *
+     * @param activePort The portId of the new active port.
+     */
+    protected void setLocalActivePort(@LocalActivePort int activePort) {
+        synchronized (mLock) {
+            mLocalActivePort = activePort;
+        }
+    }
+
+    boolean isRoutingControlFeatureEnabled() {
+        synchronized (mLock) {
+            return mRoutingControlFeatureEnabled;
+        }
+    }
+
+    // Check if the device is trying to switch to the same input that is active right now.
+    // This can help avoid redundant port switching.
+    protected boolean isSwitchingToTheSameInput(@LocalActivePort int activePort) {
+        return activePort == getLocalActivePort();
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 25ca278..a8c4350 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -41,17 +41,18 @@
 import android.media.AudioSystem;
 import android.media.tv.TvInputInfo;
 import android.media.tv.TvInputManager.TvInputCallback;
-import android.os.RemoteException;
 import android.provider.Settings.Global;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -307,7 +308,7 @@
     private void handleSelectInternalSource() {
         assertRunOnServiceThread();
         // Seq #18
-        if (mService.isControlEnabled() && mActiveSource.logicalAddress != mAddress) {
+        if (mService.isControlEnabled() && getActiveSource().logicalAddress != mAddress) {
             updateActiveSource(mAddress, mService.getPhysicalAddress());
             if (mSkipRoutingControl) {
                 mSkipRoutingControl = false;
@@ -329,7 +330,7 @@
     void updateActiveSource(ActiveSource newActive) {
         assertRunOnServiceThread();
         // Seq #14
-        if (mActiveSource.equals(newActive)) {
+        if (getActiveSource().equals(newActive)) {
             return;
         }
         setActiveSource(newActive);
@@ -345,10 +346,6 @@
         }
     }
 
-    int getPortId(int physicalAddress) {
-        return mService.pathToPortId(physicalAddress);
-    }
-
     /**
      * Returns the previous port id kept to handle input switching on <Inactive Source>.
      */
@@ -402,7 +399,7 @@
             invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
             return;
         }
-        mActiveSource.invalidate();
+        getActiveSource().invalidate();
         if (!mService.isControlEnabled()) {
             setActivePortId(portId);
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
@@ -452,17 +449,6 @@
         return Constants.ADDR_INVALID;
     }
 
-    private static void invokeCallback(IHdmiControlCallback callback, int result) {
-        if (callback == null) {
-            return;
-        }
-        try {
-            callback.onComplete(result);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Invoking callback failed:" + e);
-        }
-    }
-
     @Override
     @ServiceThreadOnly
     protected boolean handleActiveSource(HdmiCecMessage message) {
@@ -518,7 +504,7 @@
         } else {
             // No HDMI port to switch to was found. Notify the input change listers to
             // switch to the lastly shown internal input.
-            mActiveSource.invalidate();
+            getActiveSource().invalidate();
             setActivePath(Constants.INVALID_PHYSICAL_ADDRESS);
             mService.invokeInputChangeListener(HdmiDeviceInfo.INACTIVE_DEVICE);
         }
@@ -685,7 +671,7 @@
         byte[] params = message.getParams();
         int currentPath = HdmiUtils.twoBytesToInt(params);
         if (HdmiUtils.isAffectingActiveRoutingPath(getActivePath(), currentPath)) {
-            mActiveSource.invalidate();
+            getActiveSource().invalidate();
             removeAction(RoutingControlAction.class);
             int newPath = HdmiUtils.twoBytesToInt(params, 2);
             addAndStartAction(new RoutingControlAction(this, newPath, true, null));
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
index c005615..f8b3962 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
@@ -17,6 +17,7 @@
 package com.android.server.hdmi;
 
 import android.annotation.Nullable;
+
 import libcore.util.EmptyArray;
 
 import java.util.Arrays;
@@ -111,12 +112,11 @@
     @Override
     public String toString() {
         StringBuffer s = new StringBuffer();
-        s.append(String.format("<%s> src: %d, dst: %d",
-                opcodeToString(mOpcode), mSource, mDestination));
+        s.append(String.format("<%s> %X%X:%02X",
+                opcodeToString(mOpcode), mSource, mDestination, mOpcode));
         if (mParams.length > 0) {
-            s.append(", params:");
             for (byte data : mParams) {
-                s.append(String.format(" %02X", data));
+                s.append(String.format(":%02X", data));
             }
         }
         return s.toString();
@@ -133,7 +133,7 @@
             case Constants.MESSAGE_TUNER_STEP_DECREMENT:
                 return "Tuner Step Decrement";
             case Constants.MESSAGE_TUNER_DEVICE_STATUS:
-                return "Tuner Device Staus";
+                return "Tuner Device Status";
             case Constants.MESSAGE_GIVE_TUNER_DEVICE_STATUS:
                 return "Give Tuner Device Status";
             case Constants.MESSAGE_RECORD_ON:
@@ -207,7 +207,7 @@
             case Constants.MESSAGE_DEVICE_VENDOR_ID:
                 return "Device Vendor Id";
             case Constants.MESSAGE_VENDOR_COMMAND:
-                return "Vendor Commandn";
+                return "Vendor Command";
             case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN:
                 return "Vendor Remote Button Down";
             case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP:
@@ -215,7 +215,7 @@
             case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID:
                 return "Give Device Vendor Id";
             case Constants.MESSAGE_MENU_REQUEST:
-                return "Menu REquest";
+                return "Menu Request";
             case Constants.MESSAGE_MENU_STATUS:
                 return "Menu Status";
             case Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS:
@@ -247,7 +247,7 @@
             case Constants.MESSAGE_SET_EXTERNAL_TIMER:
                 return "Set External Timer";
             case Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR:
-                return "Repot Short Audio Descriptor";
+                return "Report Short Audio Descriptor";
             case Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR:
                 return "Request Short Audio Descriptor";
             case Constants.MESSAGE_INITIATE_ARC:
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 941c321..3f949ba 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -365,6 +365,20 @@
     }
 
     /**
+     * Build &lt;Routing Information&gt; command.
+     *
+     * <p>This is a broadcast message sent to all devices on the bus.
+     *
+     * @param src source address of command
+     * @param physicalAddress physical address of the new active routing path
+     * @return newly created {@link HdmiCecMessage}
+     */
+    static HdmiCecMessage buildRoutingInformation(int src, int physicalAddress) {
+        return buildCommand(src, Constants.ADDR_BROADCAST,
+            Constants.MESSAGE_ROUTING_INFORMATION, physicalAddressToParam(physicalAddress));
+    }
+
+    /**
      * Build &lt;Give Device Power Status&gt; command.
      *
      * @param src source address of command
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index f468c0b..f3a1e46 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -18,12 +18,16 @@
 
 import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE;
 import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE;
+
+import static com.android.internal.os.RoSystemProperties.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH;
+import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
 import static com.android.server.hdmi.Constants.DISABLED;
 import static com.android.server.hdmi.Constants.ENABLED;
 import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE;
 import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING;
 import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE;
 import static com.android.server.hdmi.Constants.OPTION_MHL_SERVICE_CONTROL;
+import static com.android.server.power.ShutdownThread.SHUTDOWN_ACTION_PROPERTY;
 
 import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
@@ -67,6 +71,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
@@ -76,6 +81,9 @@
 import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
 import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
 import com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback;
+
+import libcore.util.EmptyArray;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -85,7 +93,6 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import libcore.util.EmptyArray;
 
 /**
  * Provides a service for sending and processing HDMI control messages,
@@ -136,6 +143,14 @@
     static final int STANDBY_SCREEN_OFF = 0;
     static final int STANDBY_SHUTDOWN = 1;
 
+    // Logical address of the active source.
+    @GuardedBy("mLock")
+    protected final ActiveSource mActiveSource = new ActiveSource();
+
+    private static final boolean isHdmiCecNeverClaimPlaybackLogicAddr =
+            SystemProperties.getBoolean(
+                    Constants.PROPERTY_HDMI_CEC_NEVER_CLAIM_PLAYBACK_LOGICAL_ADDRESS, false);
+
     /**
      * Interface to report send result.
      */
@@ -171,9 +186,10 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             assertRunOnServiceThread();
+            boolean isReboot = SystemProperties.get(SHUTDOWN_ACTION_PROPERTY).contains("1");
             switch (intent.getAction()) {
                 case Intent.ACTION_SCREEN_OFF:
-                    if (isPowerOnOrTransient()) {
+                    if (isPowerOnOrTransient() && !isReboot) {
                         onStandby(STANDBY_SCREEN_OFF);
                     }
                     break;
@@ -189,7 +205,7 @@
                     }
                     break;
                 case Intent.ACTION_SHUTDOWN:
-                    if (isPowerOnOrTransient()) {
+                    if (isPowerOnOrTransient() && !isReboot) {
                         onStandby(STANDBY_SHUTDOWN);
                     }
                     break;
@@ -332,6 +348,10 @@
     @Nullable
     private Looper mIoLooper;
 
+    // Thread safe physical address
+    @GuardedBy("mLock")
+    private int mPhysicalAddress = Constants.INVALID_PHYSICAL_ADDRESS;
+
     // Last input port before switching to the MHL port. Should switch back to this port
     // when the mobile device sends the request one touch play with off.
     // Gets invalidated if we go to other port/input.
@@ -409,7 +429,7 @@
         mSettingsObserver = new SettingsObserver(mHandler);
     }
 
-    private static List<Integer> getIntList(String string) {
+    protected static List<Integer> getIntList(String string) {
         ArrayList<Integer> list = new ArrayList<>();
         TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
         splitter.setString(string);
@@ -551,7 +571,8 @@
                 Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
                 Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
                 Global.MHL_INPUT_SWITCHING_ENABLED,
-                Global.MHL_POWER_CHARGE_ENABLED
+                Global.MHL_POWER_CHARGE_ENABLED,
+                Global.HDMI_CEC_SWITCH_ENABLED
         };
         for (String s : settings) {
             resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver,
@@ -592,6 +613,24 @@
                     if (isTvDeviceEnabled()) {
                         tv().setSystemAudioControlFeatureEnabled(enabled);
                     }
+                    if (isAudioSystemDevice()) {
+                        if (audioSystem() == null) {
+                            Slog.e(TAG, "Audio System device has not registered yet."
+                                    + " Can't turn system audio mode on.");
+                            break;
+                        }
+                        audioSystem().onSystemAduioControlFeatureSupportChanged(enabled);
+                    }
+                    break;
+                case Global.HDMI_CEC_SWITCH_ENABLED:
+                    if (isAudioSystemDevice()) {
+                        if (audioSystem() == null) {
+                            Slog.w(TAG, "Switch device has not registered yet."
+                                    + " Can't turn routing on.");
+                            break;
+                        }
+                        audioSystem().setRoutingControlFeatureEnables(enabled);
+                    }
                     break;
                 case Global.MHL_INPUT_SWITCHING_ENABLED:
                     setMhlInputChangeEnabled(enabled);
@@ -607,6 +646,7 @@
         return enabled ? ENABLED : DISABLED;
     }
 
+    @VisibleForTesting
     boolean readBooleanSetting(String key, boolean defVal) {
         ContentResolver cr = getContext().getContentResolver();
         return Global.getInt(cr, key, toInt(defVal)) == ENABLED;
@@ -617,6 +657,15 @@
         Global.putInt(cr, key, toInt(value));
     }
 
+    void writeStringSystemProperty(String key, String value) {
+        SystemProperties.set(key, value);
+    }
+
+    @VisibleForTesting
+    boolean readBooleanSystemProperty(String key, boolean defVal) {
+        return SystemProperties.getBoolean(key, defVal);
+    }
+
     private void initializeCec(int initiatedBy) {
         mAddressAllocated = false;
         mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
@@ -630,6 +679,10 @@
         // A container for [Device type, Local device info].
         ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
         for (int type : mLocalDevices) {
+            if (type == HdmiDeviceInfo.DEVICE_PLAYBACK
+                    && isHdmiCecNeverClaimPlaybackLogicAddr) {
+                continue;
+            }
             HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type);
             if (localDevice == null) {
                 localDevice = HdmiCecLocalDevice.create(this, type);
@@ -717,6 +770,10 @@
         assertRunOnServiceThread();
         HdmiPortInfo[] cecPortInfo = null;
 
+        synchronized (mLock) {
+            mPhysicalAddress = getPhysicalAddress();
+        }
+
         // CEC HAL provides majority of the info while MHL does only MHL support flag for
         // each port. Return empty array if CEC HAL didn't provide the info.
         if (mCecController != null) {
@@ -738,6 +795,9 @@
         mPortInfoMap = new UnmodifiableSparseArray<>(portInfoMap);
         mPortDeviceMap = new UnmodifiableSparseArray<>(portDeviceMap);
 
+        if (mMhlController == null) {
+            return;
+        }
         HdmiPortInfo[] mhlPortInfo = mMhlController.getPortInfos();
         ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length);
         for (HdmiPortInfo info : mhlPortInfo) {
@@ -792,13 +852,34 @@
     }
 
     /**
-     * Returns the id of HDMI port located at the top of the hierarchy of
-     * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance,
-     * the port id to be returned is the ID associated with the port address
-     * 0x1000 (1.0.0.0) which is the topmost path of the given routing path.
+     * Returns the id of HDMI port located at the current device that runs this method.
+     *
+     * For TV with physical address 0x0000, target device 0x1120, we want port physical address
+     * 0x1000 to get the correct port id from {@link #mPortIdMap}. For device with Physical Address
+     * 0x2000, target device 0x2420, we want port address 0x24000 to get the port id.
+     *
+     * <p>Return {@link Constants#INVALID_PORT_ID} if target device does not connect to.
+     *
+     * @param path the target device's physical address.
+     * @return the id of the port that the target device eventually connects to
+     * on the current device.
      */
     int pathToPortId(int path) {
-        int portAddress = path & Constants.ROUTING_PATH_TOP_MASK;
+        int mask = 0xF000;
+        int finalMask = 0xF000;
+        int physicalAddress;
+        synchronized (mLock) {
+            physicalAddress = mPhysicalAddress;
+        }
+        int maskedAddress = physicalAddress;
+
+        while (maskedAddress != 0) {
+            maskedAddress = physicalAddress & mask;
+            finalMask |= mask;
+            mask >>= 4;
+        }
+
+        int portAddress = path & finalMask;
         return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID);
     }
 
@@ -991,9 +1072,18 @@
     void onHotplug(int portId, boolean connected) {
         assertRunOnServiceThread();
 
-        if (connected && !isTvDevice()) {
+        if (connected && !isTvDevice()
+                && getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
+            if (isSwitchDevice()) {
+                initPortInfo();
+                HdmiLogger.debug("initPortInfo for switch device when onHotplug from tx.");
+            }
             ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
             for (int type : mLocalDevices) {
+                if (type == HdmiDeviceInfo.DEVICE_PLAYBACK
+                        && isHdmiCecNeverClaimPlaybackLogicAddr) {
+                    continue;
+                }
                 HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type);
                 if (localDevice == null) {
                     localDevice = HdmiCecLocalDevice.create(this, type);
@@ -1088,7 +1178,7 @@
         String displayName = Build.MODEL;
         return new HdmiDeviceInfo(logicalAddress,
                 getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType,
-                getVendorId(), displayName);
+                getVendorId(), displayName, powerStatus);
     }
 
     @ServiceThreadOnly
@@ -1307,6 +1397,33 @@
             HdmiCecLocalDeviceTv tv = tv();
             if (tv == null) {
                 Slog.w(TAG, "Local tv device not available");
+                if (isPlaybackDevice()) {
+                    // if playback device itself is the active source,
+                    // return its own device info.
+                    if (playback() != null && playback().mIsActiveSource) {
+                        return playback().getDeviceInfo();
+                    }
+                    // Otherwise get the active source and look for it from the device list
+                    ActiveSource activeSource = mActiveSource;
+                    // If the active source is not set yet, return null
+                    if (!activeSource.isValid()) {
+                        return null;
+                    }
+                    if (audioSystem() != null) {
+                        HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+                        for (HdmiDeviceInfo info : audioSystem.getSafeCecDevicesLocked()) {
+                            if (info.getLogicalAddress() == activeSource.logicalAddress) {
+                                return info;
+                            }
+                        }
+                    }
+                    // If the device info is not in the list yet, return a device info with minimum
+                    // information from mActiveSource.
+                    return new HdmiDeviceInfo(activeSource.logicalAddress,
+                        activeSource.physicalAddress, pathToPortId(activeSource.physicalAddress),
+                        HdmiUtils.getTypeFromAddress(activeSource.logicalAddress), 0,
+                        HdmiUtils.getDefaultDeviceName(activeSource.logicalAddress));
+                }
                 return null;
             }
             ActiveSource activeSource = tv.getActiveSource();
@@ -1373,17 +1490,24 @@
                         return;
                     }
                     HdmiCecLocalDeviceTv tv = tv();
-                    if (tv == null) {
-                        if (!mAddressAllocated) {
-                            mSelectRequestBuffer.set(SelectRequestBuffer.newPortSelect(
-                                    HdmiControlService.this, portId, callback));
-                            return;
-                        }
-                        Slog.w(TAG, "Local tv device not available");
-                        invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE);
+                    if (tv != null) {
+                        tv.doManualPortSwitching(portId, callback);
                         return;
                     }
-                    tv.doManualPortSwitching(portId, callback);
+                    HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+                    if (audioSystem != null) {
+                        audioSystem.doManualPortSwitching(portId, callback);
+                        return;
+                    }
+
+                    if (!mAddressAllocated) {
+                        mSelectRequestBuffer.set(SelectRequestBuffer.newPortSelect(
+                                HdmiControlService.this, portId, callback));
+                        return;
+                    }
+                    Slog.w(TAG, "Local device not available");
+                    invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE);
+                    return;
                 }
             });
         }
@@ -1469,12 +1593,20 @@
 
         @Override
         public boolean getSystemAudioMode() {
+            // TODO(shubang): handle getSystemAudioMode() for all device types
             enforceAccessPermission();
             HdmiCecLocalDeviceTv tv = tv();
-            if (tv == null) {
-                return false;
+            HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+            return (tv != null && tv.isSystemAudioActivated())
+                    || (audioSystem != null && audioSystem.isSystemAudioActivated());
+        }
+
+        @Override
+        public int getPhysicalAddress() {
+            enforceAccessPermission();
+            synchronized (mLock) {
+                return mPhysicalAddress;
             }
-            return tv.isSystemAudioActivated();
         }
 
         @Override
@@ -1534,14 +1666,62 @@
         public List<HdmiDeviceInfo> getDeviceList() {
             enforceAccessPermission();
             HdmiCecLocalDeviceTv tv = tv();
-            synchronized (mLock) {
-                return (tv == null)
+            if (tv != null) {
+                synchronized (mLock) {
+                    return tv.getSafeCecDevicesLocked();
+                }
+            } else {
+                HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+                synchronized (mLock) {
+                    return (audioSystem == null)
                         ? Collections.<HdmiDeviceInfo>emptyList()
-                        : tv.getSafeCecDevicesLocked();
+                        : audioSystem.getSafeCecDevicesLocked();
+                }
             }
         }
 
         @Override
+        public void powerOffRemoteDevice(int logicalAddress, int powerStatus) {
+            enforceAccessPermission();
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    Slog.w(TAG, "Device "
+                            + logicalAddress + " power status is " + powerStatus
+                            + " before standby command sent out");
+                    sendCecCommand(HdmiCecMessageBuilder.buildStandby(
+                            getRemoteControlSourceAddress(), logicalAddress));
+                }
+            });
+        }
+
+        @Override
+        public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {
+            // TODO(amyjojo): implement the method
+        }
+
+        @Override
+        // TODO(AMYJOJO): add a result callback
+        public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) {
+            enforceAccessPermission();
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(
+                            getRemoteControlSourceAddress(), physicalAddress);
+                    if (pathToPortId(physicalAddress) != Constants.INVALID_PORT_ID) {
+                        if (getSwitchDevice() != null) {
+                            getSwitchDevice().handleSetStreamPath(setStreamPath);
+                        } else {
+                            Slog.e(TAG, "Can't get the correct local device to handle routing.");
+                        }
+                    }
+                    sendCecCommand(setStreamPath);
+                }
+            });
+        }
+
+        @Override
         public void setSystemAudioVolume(final int oldIndex, final int newIndex,
                 final int maxIndex) {
             enforceAccessPermission();
@@ -1642,6 +1822,9 @@
                     }
                     HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType);
                     if (device == null) {
+                        device = audioSystem();
+                    }
+                    if (device == null) {
                         Slog.w(TAG, "Local device not available");
                         return;
                     }
@@ -1777,14 +1960,32 @@
                         Slog.w(TAG, "audio system is not in system audio mode");
                         return;
                     }
-                    int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume);
+                    audioSystem().reportAudioStatus(Constants.ADDR_TV);
+                }
+            });
+        }
 
-                    sendCecCommand(HdmiCecMessageBuilder
-                            .buildReportAudioStatus(
-                                    device.getDeviceInfo().getLogicalAddress(),
-                                    Constants.ADDR_TV,
-                                    scaledVolume,
-                                    isMute));
+        @Override
+        public void setSystemAudioModeOnForAudioOnlySource() {
+            enforceAccessPermission();
+            runOnServiceThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (!isAudioSystemDevice()) {
+                        Slog.e(TAG, "Not an audio system device. Won't set system audio mode on");
+                        return;
+                    }
+                    if (audioSystem() == null) {
+                        Slog.e(TAG, "Audio System local device is not registered");
+                        return;
+                    }
+                    if (!audioSystem().checkSupportAndSetSystemAudioMode(true)) {
+                        Slog.e(TAG, "System Audio Mode is not supported.");
+                        return;
+                    }
+                    sendCecCommand(
+                            HdmiCecMessageBuilder.buildSetSystemAudioMode(
+                                    audioSystem().mAddress, Constants.ADDR_BROADCAST, true));
                 }
             });
         }
@@ -1794,36 +1995,64 @@
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, writer)) return;
             final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
 
-            pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled);
             pw.println("mProhibitMode: " + mProhibitMode);
-            if (mCecController != null) {
-                pw.println("mCecController: ");
-                pw.increaseIndent();
-                mCecController.dump(pw);
-                pw.decreaseIndent();
-            }
+            pw.println("mPowerStatus: " + mPowerStatus);
+
+            // System settings
+            pw.println("System_settings:");
+            pw.increaseIndent();
+            pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled);
+            pw.println("mMhlInputChangeEnabled: " + mMhlInputChangeEnabled);
+            pw.decreaseIndent();
 
             pw.println("mMhlController: ");
             pw.increaseIndent();
             mMhlController.dump(pw);
             pw.decreaseIndent();
 
-            pw.println("mPortInfo: ");
-            pw.increaseIndent();
-            for (HdmiPortInfo hdmiPortInfo : mPortInfo) {
-                pw.println("- " + hdmiPortInfo);
+            HdmiUtils.dumpIterable(pw, "mPortInfo:", mPortInfo);
+            if (mCecController != null) {
+                pw.println("mCecController: ");
+                pw.increaseIndent();
+                mCecController.dump(pw);
+                pw.decreaseIndent();
             }
-            pw.decreaseIndent();
-            pw.println("mPowerStatus: " + mPowerStatus);
         }
     }
 
+    // Get the source address to send out commands to devices connected to the current device
+    // when other services interact with HdmiControlService.
+    private int getRemoteControlSourceAddress() {
+        if (isAudioSystemDevice()) {
+            return audioSystem().getDeviceInfo().getLogicalAddress();
+        } else if (isPlaybackDevice()) {
+            return playback().getDeviceInfo().getLogicalAddress();
+        }
+        return ADDR_UNREGISTERED;
+    }
+
+    // Get the switch device to do CEC routing control
+    @Nullable
+    private HdmiCecLocalDeviceSource getSwitchDevice() {
+        if (isAudioSystemDevice()) {
+            return audioSystem();
+        }
+        if (isPlaybackDevice()) {
+            return playback();
+        }
+        return null;
+    }
+
     @ServiceThreadOnly
     private void oneTouchPlay(final IHdmiControlCallback callback) {
         assertRunOnServiceThread();
-        HdmiCecLocalDevicePlayback source = playback();
+        HdmiCecLocalDeviceSource source = playback();
         if (source == null) {
-            Slog.w(TAG, "Local playback device not available");
+            source = audioSystem();
+        }
+
+        if (source == null) {
+            Slog.w(TAG, "Local source device not available");
             invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE);
             return;
         }
@@ -2086,11 +2315,20 @@
         return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
     }
 
+    boolean isPlaybackDevice() {
+        return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_PLAYBACK);
+    }
+
+    boolean isSwitchDevice() {
+        return SystemProperties.getBoolean(
+            PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH, false);
+    }
+
     boolean isTvDeviceEnabled() {
         return isTvDevice() && tv() != null;
     }
 
-    private HdmiCecLocalDevicePlayback playback() {
+    protected HdmiCecLocalDevicePlayback playback() {
         return (HdmiCecLocalDevicePlayback)
                 mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK);
     }
@@ -2461,6 +2699,77 @@
         setLastInputForMhl(Constants.INVALID_PORT_ID);
     }
 
+    ActiveSource getActiveSource() {
+        synchronized (mLock) {
+            return mActiveSource;
+        }
+    }
+
+    void setActiveSource(int logicalAddress, int physicalAddress) {
+        synchronized (mLock) {
+            mActiveSource.logicalAddress = logicalAddress;
+            mActiveSource.physicalAddress = physicalAddress;
+        }
+    }
+
+    // This method should only be called when the device can be the active source
+    // and all the device types call into this method.
+    // For example, when receiving broadcast messages, all the device types will call this
+    // method but only one of them will be the Active Source.
+    protected void setAndBroadcastActiveSource(
+            int physicalAddress, int deviceType, int source) {
+        // If the device has both playback and audio system logical addresses,
+        // playback will claim active source. Otherwise audio system will.
+        if (deviceType == HdmiDeviceInfo.DEVICE_PLAYBACK) {
+            HdmiCecLocalDevicePlayback playback = playback();
+            playback.setIsActiveSource(true);
+            playback.wakeUpIfActiveSource();
+            playback.maySendActiveSource(source);
+            setActiveSource(playback.mAddress, physicalAddress);
+        }
+
+        if (deviceType == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
+            HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+            if (playback() != null) {
+                audioSystem.setIsActiveSource(false);
+            } else {
+                audioSystem.setIsActiveSource(true);
+                audioSystem.wakeUpIfActiveSource();
+                audioSystem.maySendActiveSource(source);
+                setActiveSource(audioSystem.mAddress, physicalAddress);
+            }
+        }
+    }
+
+    // This method should only be called when the device can be the active source
+    // and only one of the device types calls into this method.
+    // For example, when receiving One Touch Play, only playback device handles it
+    // and this method updates Active Source in all the device types sharing the same
+    // Physical Address.
+    protected void setAndBroadcastActiveSourceFromOneDeviceType(
+            int sourceAddress, int physicalAddress) {
+        // If the device has both playback and audio system logical addresses,
+        // playback will claim active source. Otherwise audio system will.
+        HdmiCecLocalDevicePlayback playback = playback();
+        HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+        if (playback != null) {
+            playback.setIsActiveSource(true);
+            playback.wakeUpIfActiveSource();
+            playback.maySendActiveSource(sourceAddress);
+            if (audioSystem != null) {
+                audioSystem.setIsActiveSource(false);
+            }
+            setActiveSource(playback.mAddress, physicalAddress);
+        } else {
+            if (audioSystem != null) {
+                audioSystem.setIsActiveSource(true);
+                audioSystem.wakeUpIfActiveSource();
+                audioSystem.maySendActiveSource(sourceAddress);
+                setActiveSource(audioSystem.mAddress, physicalAddress);
+            }
+        }
+    }
+
     @ServiceThreadOnly
     void setLastInputForMhl(int portId) {
         assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index 2a8117f..e44f1d1 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -16,19 +16,35 @@
 
 package com.android.server.hdmi;
 
+import android.annotation.Nullable;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.Xml;
 
+import com.android.internal.util.HexDump;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.hdmi.Constants.AudioCodec;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+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;
+import java.util.Objects;
 
 /**
  * Various utilities to handle HDMI CEC messages.
  */
 final class HdmiUtils {
 
+    private static final String TAG = "HdmiUtils";
+
     private static final int[] ADDRESS_TO_TYPE = {
         HdmiDeviceInfo.DEVICE_TV,  // ADDR_TV
         HdmiDeviceInfo.DEVICE_RECORDER,  // ADDR_RECORDER_1
@@ -65,6 +81,12 @@
         "Secondary_TV",
     };
 
+    /**
+     * Return value of {@link #getLocalPortFromPhysicalAddress(int, int)}
+     */
+    static final int TARGET_NOT_UNDER_LOCAL_DEVICE = -1;
+    static final int TARGET_SAME_PHYSICAL_ADDRESS = 0;
+
     private HdmiUtils() { /* cannot be instantiated */ }
 
     /**
@@ -317,4 +339,339 @@
                 info.getPhysicalAddress(), info.getPortId(), info.getDeviceType(),
                 info.getVendorId(), info.getDisplayName(), newPowerStatus);
     }
+
+    /**
+     * Dump a {@link SparseArray} to the print writer.
+     *
+     * <p>The dump is formatted:
+     * <pre>
+     *     name:
+     *        key = value
+     *        key = value
+     *        ...
+     * </pre>
+     */
+    static <T> void dumpSparseArray(IndentingPrintWriter pw, String name,
+            SparseArray<T> sparseArray) {
+        printWithTrailingColon(pw, name);
+        pw.increaseIndent();
+        int size = sparseArray.size();
+        for (int i = 0; i < size; i++) {
+            int key = sparseArray.keyAt(i);
+            T value = sparseArray.get(key);
+            pw.printPair(Integer.toString(key), value);
+            pw.println();
+        }
+        pw.decreaseIndent();
+    }
+
+    private static void printWithTrailingColon(IndentingPrintWriter pw, String name) {
+        pw.println(name.endsWith(":") ? name : name.concat(":"));
+    }
+
+    /**
+     * Dump a {@link Map} to the print writer.
+     *
+     * <p>The dump is formatted:
+     * <pre>
+     *     name:
+     *        key = value
+     *        key = value
+     *        ...
+     * </pre>
+     */
+    static <K, V> void dumpMap(IndentingPrintWriter pw, String name, Map<K, V> map) {
+        printWithTrailingColon(pw, name);
+        pw.increaseIndent();
+        for (Map.Entry<K, V> entry: map.entrySet()) {
+            pw.printPair(entry.getKey().toString(), entry.getValue());
+            pw.println();
+        }
+        pw.decreaseIndent();
+    }
+
+    /**
+     * Dump a {@link Map} to the print writer.
+     *
+     * <p>The dump is formatted:
+     * <pre>
+     *     name:
+     *        value
+     *        value
+     *        ...
+     * </pre>
+     */
+    static <T> void dumpIterable(IndentingPrintWriter pw, String name, Iterable<T> values) {
+        printWithTrailingColon(pw, name);
+        pw.increaseIndent();
+        for (T value : values) {
+            pw.println(value);
+        }
+        pw.decreaseIndent();
+    }
+
+    /**
+     * Method to parse target physical address to the port number on the current device.
+     *
+     * <p>This check assumes target address is valid.
+     *
+     * @param targetPhysicalAddress is the physical address of the target device
+     * @param myPhysicalAddress is the physical address of the current device
+     * @return
+     * If the target device is under the current device, return the port number of current device
+     * that the target device is connected to. This also applies to the devices that are indirectly
+     * connected to the current device.
+     *
+     * <p>If the target device has the same physical address as the current device, return
+     * {@link #TARGET_SAME_PHYSICAL_ADDRESS}.
+     *
+     * <p>If the target device is not under the current device, return
+     * {@link #TARGET_NOT_UNDER_LOCAL_DEVICE}.
+     */
+    public static int getLocalPortFromPhysicalAddress(
+            int targetPhysicalAddress, int myPhysicalAddress) {
+        if (myPhysicalAddress == targetPhysicalAddress) {
+            return TARGET_SAME_PHYSICAL_ADDRESS;
+        }
+
+        int mask = 0xF000;
+        int finalMask = 0xF000;
+        int maskedAddress = myPhysicalAddress;
+
+        while (maskedAddress != 0) {
+            maskedAddress = myPhysicalAddress & mask;
+            finalMask |= mask;
+            mask >>= 4;
+        }
+
+        int portAddress = targetPhysicalAddress & finalMask;
+        if ((portAddress & (finalMask << 4)) != myPhysicalAddress) {
+            return TARGET_NOT_UNDER_LOCAL_DEVICE;
+        }
+
+        mask <<= 4;
+        int port = portAddress & mask;
+        while ((port >> 4) != 0) {
+            port >>= 4;
+        }
+        return port;
+    }
+
+    public static class ShortAudioDescriptorXmlParser {
+        // We don't use namespaces
+        private static final String NS = null;
+
+        // return a list of devices config
+        public static List<DeviceConfig> parse(InputStream in)
+                throws XmlPullParserException, IOException {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+            parser.setInput(in, null);
+            parser.nextTag();
+            return readDevices(parser);
+        }
+
+        private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                throw new IllegalStateException();
+            }
+            int depth = 1;
+            while (depth != 0) {
+                switch (parser.next()) {
+                    case XmlPullParser.END_TAG:
+                        depth--;
+                        break;
+                    case XmlPullParser.START_TAG:
+                        depth++;
+                        break;
+                }
+            }
+        }
+
+        private static List<DeviceConfig> readDevices(XmlPullParser parser)
+                throws XmlPullParserException, IOException {
+            List<DeviceConfig> devices = new ArrayList<>();
+
+            parser.require(XmlPullParser.START_TAG, NS, "config");
+            while (parser.next() != XmlPullParser.END_TAG) {
+                if (parser.getEventType() != XmlPullParser.START_TAG) {
+                    continue;
+                }
+                String name = parser.getName();
+                // Starts by looking for the device tag
+                if (name.equals("device")) {
+                    String deviceType = parser.getAttributeValue(null, "type");
+                    DeviceConfig config = null;
+                    if (deviceType != null) {
+                        config = readDeviceConfig(parser, deviceType);
+                    }
+                    if (config != null) {
+                        devices.add(config);
+                    }
+                } else {
+                    skip(parser);
+                }
+            }
+            return devices;
+        }
+
+        // Processes device tags in the config.
+        @Nullable
+        private static DeviceConfig readDeviceConfig(XmlPullParser parser, String deviceType)
+                throws XmlPullParserException, IOException {
+            List<CodecSad> codecSads = new ArrayList<>();
+            int format;
+            byte[] descriptor;
+
+            parser.require(XmlPullParser.START_TAG, NS, "device");
+            while (parser.next() != XmlPullParser.END_TAG) {
+                if (parser.getEventType() != XmlPullParser.START_TAG) {
+                    continue;
+                }
+                String tagName = parser.getName();
+
+                // Starts by looking for the supportedFormat tag
+                if (tagName.equals("supportedFormat")) {
+                    String codecAttriValue = parser.getAttributeValue(null, "format");
+                    String sadAttriValue = parser.getAttributeValue(null, "descriptor");
+                    format = (codecAttriValue) == null
+                            ? Constants.AUDIO_CODEC_NONE : formatNameToNum(codecAttriValue);
+                    descriptor = readSad(sadAttriValue);
+                    if (format != Constants.AUDIO_CODEC_NONE && descriptor != null) {
+                        codecSads.add(new CodecSad(format, descriptor));
+                    }
+                    parser.nextTag();
+                    parser.require(XmlPullParser.END_TAG, NS, "supportedFormat");
+                } else {
+                    skip(parser);
+                }
+            }
+            if (codecSads.size() == 0) {
+                return null;
+            }
+            return new DeviceConfig(deviceType, codecSads);
+        }
+
+        // Processes sad attribute in the supportedFormat.
+        @Nullable
+        private static byte[] readSad(String sad) {
+            if (sad == null || sad.length() == 0) {
+                return null;
+            }
+            byte[] sadBytes = HexDump.hexStringToByteArray(sad);
+            if (sadBytes.length != 3) {
+                Slog.w(TAG, "SAD byte array length is not 3. Length = " + sadBytes.length);
+                return null;
+            }
+            return sadBytes;
+        }
+
+        @AudioCodec
+        private static int formatNameToNum(String codecAttriValue) {
+            switch (codecAttriValue) {
+                case "AUDIO_FORMAT_NONE":
+                    return Constants.AUDIO_CODEC_NONE;
+                case "AUDIO_FORMAT_LPCM":
+                    return Constants.AUDIO_CODEC_LPCM;
+                case "AUDIO_FORMAT_DD":
+                    return Constants.AUDIO_CODEC_DD;
+                case "AUDIO_FORMAT_MPEG1":
+                    return Constants.AUDIO_CODEC_MPEG1;
+                case "AUDIO_FORMAT_MP3":
+                    return Constants.AUDIO_CODEC_MP3;
+                case "AUDIO_FORMAT_MPEG2":
+                    return Constants.AUDIO_CODEC_MPEG2;
+                case "AUDIO_FORMAT_AAC":
+                    return Constants.AUDIO_CODEC_AAC;
+                case "AUDIO_FORMAT_DTS":
+                    return Constants.AUDIO_CODEC_DTS;
+                case "AUDIO_FORMAT_ATRAC":
+                    return Constants.AUDIO_CODEC_ATRAC;
+                case "AUDIO_FORMAT_ONEBITAUDIO":
+                    return Constants.AUDIO_CODEC_ONEBITAUDIO;
+                case "AUDIO_FORMAT_DDP":
+                    return Constants.AUDIO_CODEC_DDP;
+                case "AUDIO_FORMAT_DTSHD":
+                    return Constants.AUDIO_CODEC_DTSHD;
+                case "AUDIO_FORMAT_TRUEHD":
+                    return Constants.AUDIO_CODEC_TRUEHD;
+                case "AUDIO_FORMAT_DST":
+                    return Constants.AUDIO_CODEC_DST;
+                case "AUDIO_FORMAT_WMAPRO":
+                    return Constants.AUDIO_CODEC_WMAPRO;
+                case "AUDIO_FORMAT_MAX":
+                    return Constants.AUDIO_CODEC_MAX;
+                default:
+                    return Constants.AUDIO_CODEC_NONE;
+            }
+        }
+    }
+
+    // Device configuration of its supported Codecs and their Short Audio Descriptors.
+    public static class DeviceConfig {
+        /** Name of the device. Should be {@link Constants.AudioDevice}. **/
+        public final String name;
+        /** List of a {@link CodecSad}. **/
+        public final List<CodecSad> supportedCodecs;
+
+        public DeviceConfig(String name, List<CodecSad> supportedCodecs) {
+            this.name = name;
+            this.supportedCodecs = supportedCodecs;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof DeviceConfig) {
+                DeviceConfig that = (DeviceConfig) obj;
+                return that.name.equals(this.name)
+                    && that.supportedCodecs.equals(this.supportedCodecs);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(
+                name,
+                supportedCodecs.hashCode());
+        }
+    }
+
+    // Short Audio Descriptor of a specific Codec
+    public static class CodecSad {
+        /** Audio Codec. Should be {@link Constants.AudioCodec}. **/
+        public final int audioCodec;
+        /**
+         * Three-byte Short Audio Descriptor. See HDMI Specification 1.4b CEC 13.15.3 and
+         * ANSI-CTA-861-F-FINAL 7.5.2 Audio Data Block for more details.
+         */
+        public final byte[] sad;
+
+        public CodecSad(int audioCodec, byte[] sad) {
+            this.audioCodec = audioCodec;
+            this.sad = sad;
+        }
+
+        public CodecSad(int audioCodec, String sad) {
+            this.audioCodec = audioCodec;
+            this.sad = HexDump.hexStringToByteArray(sad);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof CodecSad) {
+                CodecSad that = (CodecSad) obj;
+                return that.audioCodec == this.audioCodec
+                    && Arrays.equals(that.sad, this.sad);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(
+                audioCodec,
+                Arrays.hashCode(sad));
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 5c66316..354d8d1 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -16,8 +16,8 @@
 package com.android.server.hdmi;
 
 import android.hardware.hdmi.HdmiControlManager;
-import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
+import android.hardware.hdmi.IHdmiControlCallback;
 import android.os.RemoteException;
 import android.util.Slog;
 
@@ -55,7 +55,7 @@
     private int mPowerStatusCounter = 0;
 
     // Factory method. Ensures arguments are valid.
-    static OneTouchPlayAction create(HdmiCecLocalDevicePlayback source,
+    static OneTouchPlayAction create(HdmiCecLocalDeviceSource source,
             int targetAddress, IHdmiControlCallback callback) {
         if (source == null || callback == null) {
             Slog.e(TAG, "Wrong arguments");
@@ -83,9 +83,20 @@
     }
 
     private void broadcastActiveSource() {
-        sendCommand(HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(), getSourcePath()));
-        // Because only playback device can create this action, it's safe to cast.
-        playback().setActiveSource(true);
+        // Because only source device can create this action, it's safe to cast.
+        HdmiCecLocalDeviceSource source = source();
+        source.mService.setAndBroadcastActiveSourceFromOneDeviceType(
+                mTargetAddress, getSourcePath());
+        // Set local active port to HOME when One Touch Play.
+        // Active Port and Current Input are handled by the switch functionality device.
+        if (source.mService.audioSystem() != null) {
+            source = source.mService.audioSystem();
+        }
+        if (source.getLocalActivePort() != Constants.CEC_SWITCH_HOME) {
+            source.switchInputOnReceivingNewActivePath(getSourcePath());
+        }
+        source.setRoutingPort(Constants.CEC_SWITCH_HOME);
+        source.setLocalActivePort(Constants.CEC_SWITCH_HOME);
     }
 
     private void queryDevicePowerStatus() {
diff --git a/services/core/java/com/android/server/hdmi/SelectRequestBuffer.java b/services/core/java/com/android/server/hdmi/SelectRequestBuffer.java
index 75986c7..ba16260 100644
--- a/services/core/java/com/android/server/hdmi/SelectRequestBuffer.java
+++ b/services/core/java/com/android/server/hdmi/SelectRequestBuffer.java
@@ -56,6 +56,10 @@
             return mService.tv();
         }
 
+        protected HdmiCecLocalDeviceAudioSystem audioSystem() {
+            return mService.audioSystem();
+        }
+
         protected boolean isLocalDeviceReady() {
             if (tv() == null) {
                 Slog.e(TAG, "Local tv device not available");
@@ -105,7 +109,15 @@
         public void process() {
             if (isLocalDeviceReady()) {
                 Slog.v(TAG, "calling delayed portSelect id:" + mId);
-                tv().doManualPortSwitching(mId, mCallback);
+                HdmiCecLocalDeviceTv tv = tv();
+                if (tv != null) {
+                    tv.doManualPortSwitching(mId, mCallback);
+                    return;
+                }
+                HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+                if (audioSystem != null) {
+                    audioSystem.doManualPortSwitching(mId, mCallback);
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
index 2fdcb51..b6ebcd7c 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioInitiationActionFromAvr.java
@@ -16,6 +16,7 @@
 package com.android.server.hdmi;
 
 import android.hardware.tv.cec.V1_0.SendMessageResult;
+
 import com.android.internal.annotations.VisibleForTesting;
 
 /**
@@ -40,7 +41,7 @@
 
     @Override
     boolean start() {
-        if (audioSystem().mActiveSource.physicalAddress == Constants.INVALID_PHYSICAL_ADDRESS) {
+        if (audioSystem().getActiveSource().physicalAddress == Constants.INVALID_PHYSICAL_ADDRESS) {
             mState = STATE_WAITING_FOR_ACTIVE_SOURCE;
             addTimer(mState, HdmiConfig.TIMEOUT_MS);
             sendRequestActiveSource();
@@ -59,10 +60,8 @@
                     return false;
                 }
                 mActionTimer.clearTimerMessage();
-                int physicalAddress = HdmiUtils.twoBytesToInt(cmd.getParams());
-                if (physicalAddress != getSourcePath()) {
-                    audioSystem().setActiveSource(cmd.getSource(), physicalAddress);
-                }
+                // Broadcast message is also handled by other device types
+                audioSystem().handleActiveSource(cmd);
                 mState = STATE_WAITING_FOR_TV_SUPPORT;
                 queryTvSystemAudioModeSupport();
                 return true;
@@ -91,7 +90,7 @@
                             mSendRequestActiveSourceRetryCount++;
                             sendRequestActiveSource();
                         } else {
-                            audioSystem().setSystemAudioMode(false);
+                            audioSystem().checkSupportAndSetSystemAudioMode(false);
                             finish();
                         }
                     }
@@ -106,7 +105,7 @@
                             mSendSetSystemAudioModeRetryCount++;
                             sendSetSystemAudioMode(on, dest);
                         } else {
-                            audioSystem().setSystemAudioMode(false);
+                            audioSystem().checkSupportAndSetSystemAudioMode(false);
                             finish();
                         }
                     }
@@ -115,7 +114,16 @@
 
     private void handleActiveSourceTimeout() {
         HdmiLogger.debug("Cannot get active source.");
-        audioSystem().setSystemAudioMode(false);
+        // If not able to find Active Source and the current device has playbcak functionality,
+        // claim Active Source and start to query TV system audio mode support.
+        if (audioSystem().mService.isPlaybackDevice()) {
+            audioSystem().mService.setAndBroadcastActiveSourceFromOneDeviceType(
+                    Constants.ADDR_BROADCAST, getSourcePath());
+            mState = STATE_WAITING_FOR_TV_SUPPORT;
+            queryTvSystemAudioModeSupport();
+        } else {
+            audioSystem().checkSupportAndSetSystemAudioMode(false);
+        }
         finish();
     }
 
@@ -123,12 +131,12 @@
         audioSystem().queryTvSystemAudioModeSupport(
                 supported -> {
                     if (supported) {
-                        if (audioSystem().setSystemAudioMode(true)) {
+                        if (audioSystem().checkSupportAndSetSystemAudioMode(true)) {
                             sendSetSystemAudioMode(true, Constants.ADDR_BROADCAST);
                         }
                         finish();
                     } else {
-                        audioSystem().setSystemAudioMode(false);
+                        audioSystem().checkSupportAndSetSystemAudioMode(false);
                         finish();
                     }
                 });
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index a3ebe24..8e26097 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -274,10 +274,14 @@
         }
 
         synchronized (mLock) {
-            final S service = getServiceForUserLocked(userId);
-            if (service != null) {
-                service.setTemporaryServiceLocked(componentName, durationMs);
+            final S oldService = peekServiceForUserLocked(userId);
+            if (oldService != null) {
+                oldService.removeSelfFromCacheLocked();
             }
+            mServiceNameResolver.setTemporaryService(userId, componentName, durationMs);
+
+            // Must update the service on cache so its initialization code is triggered
+            updateCachedServiceLocked(userId);
         }
     }
 
@@ -500,6 +504,7 @@
     protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
         boolean realDebug = debug;
         boolean realVerbose = verbose;
+        final String prefix2 = "    ";
 
         try {
             // Temporarily turn on full logging;
@@ -510,6 +515,13 @@
             if (mServiceNameResolver != null) {
                 pw.print(prefix); pw.print("Name resolver: ");
                 mServiceNameResolver.dumpShort(pw); pw.println();
+                final UserManager um = getContext().getSystemService(UserManager.class);
+                final List<UserInfo> users = um.getUsers();
+                for (int i = 0; i < users.size(); i++) {
+                    final int userId = users.get(i).id;
+                    pw.print(prefix2); pw.print(userId); pw.print(": ");
+                    mServiceNameResolver.dumpShort(pw, userId); pw.println();
+                }
             }
             pw.print(prefix); pw.print("Disabled users: "); pw.println(mDisabledUsers);
             pw.print(prefix); pw.print("Allow instant service: "); pw.println(mAllowInstantService);
@@ -522,7 +534,6 @@
                 pw.println("none");
             } else {
                 pw.println(size);
-                final String prefix2 = "    ";
                 for (int i = 0; i < size; i++) {
                     pw.print(prefix); pw.print("Service at "); pw.print(i); pw.println(": ");
                     final S service = mServicesCache.valueAt(i);
diff --git a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
index 556e489..cd9ebcd 100644
--- a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
@@ -214,7 +214,7 @@
 
     /**
      * Gets the current name of the service, which is either the default service or the
-     *  {@link #setTemporaryServiceLocked(String, int) temporary one}.
+     *  {@link AbstractMasterSystemService#setTemporaryService(int, String, int) temporary one}.
      */
     protected final @Nullable String getComponentNameLocked() {
         return mMaster.mServiceNameResolver.getServiceName(mUserId);
@@ -228,17 +228,6 @@
     }
 
     /**
-     * Temporary sets the service implementation.
-     *
-     * @param componentName name of the new component
-     * @param durationMs how long the change will be valid (the service will be automatically reset
-     * to the default component after this timeout expires).
-     */
-    protected final void setTemporaryServiceLocked(@NonNull String componentName, int durationMs) {
-        mMaster.mServiceNameResolver.setTemporaryService(mUserId, componentName, durationMs);
-    }
-
-    /**
      * Resets the temporary service implementation to the default component.
      */
     protected final void resetTemporaryServiceLocked() {
diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
index 7027246..7f198ac 100644
--- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
@@ -159,7 +159,7 @@
 
     @Override
     public String toString() {
-        return "FrameworkResourcesServiceNamer: temps=" + mTemporaryServiceNames;
+        return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNames + "]";
     }
 
     // TODO(b/117779333): support proto
diff --git a/services/core/java/com/android/server/infra/SecureSettingsServiceNameResolver.java b/services/core/java/com/android/server/infra/SecureSettingsServiceNameResolver.java
index bcaa918..cac7f53 100644
--- a/services/core/java/com/android/server/infra/SecureSettingsServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/SecureSettingsServiceNameResolver.java
@@ -56,4 +56,9 @@
     public void dumpShort(@NonNull PrintWriter pw, @UserIdInt int userId) {
         pw.print("defaultService="); pw.print(getDefaultServiceName(userId));
     }
+
+    @Override
+    public String toString() {
+        return "SecureSettingsServiceNameResolver[" + mProperty + "]";
+    }
 }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index d96b6cb..669ff2b 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -138,6 +138,9 @@
     private final Context mContext;
     private final InputManagerHandler mHandler;
 
+    // Context cache used for loading pointer resources.
+    private Context mDisplayContext;
+
     private final File mDoubleTouchGestureEnableFile;
 
     private WindowManagerCallbacks mWindowManagerCallbacks;
@@ -213,8 +216,6 @@
     private static native void nativeSetFocusedApplication(long ptr,
             int displayId, InputApplicationHandle application);
     private static native void nativeSetFocusedDisplay(long ptr, int displayId);
-    private static native boolean nativeTransferTouchFocus(long ptr,
-            InputChannel fromChannel, InputChannel toChannel);
     private static native void nativeSetPointerSpeed(long ptr, int speed);
     private static native void nativeSetShowTouches(long ptr, boolean enabled);
     private static native void nativeSetInteractive(long ptr, boolean interactive);
@@ -1485,29 +1486,6 @@
         nativeSetSystemUiVisibility(mPtr, visibility);
     }
 
-    /**
-     * Atomically transfers touch focus from one window to another as identified by
-     * their input channels.  It is possible for multiple windows to have
-     * touch focus if they support split touch dispatch
-     * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
-     * method only transfers touch focus of the specified window without affecting
-     * other windows that may also have touch focus at the same time.
-     * @param fromChannel The channel of a window that currently has touch focus.
-     * @param toChannel The channel of the window that should receive touch focus in
-     * place of the first.
-     * @return True if the transfer was successful.  False if the window with the
-     * specified channel did not actually have touch focus at the time of the request.
-     */
-    public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
-        if (fromChannel == null) {
-            throw new IllegalArgumentException("fromChannel must not be null.");
-        }
-        if (toChannel == null) {
-            throw new IllegalArgumentException("toChannel must not be null.");
-        }
-        return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
-    }
-
     @Override // Binder call
     public void tryPointerSpeed(int speed) {
         if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
@@ -1785,15 +1763,17 @@
     }
 
     // Native callback
-    private void notifyFocusChanged(IBinder token) {
-        if (mFocusedWindow != token) {
-            if (mFocusedWindowHasCapture) {
-                setPointerCapture(false);
+    private void notifyFocusChanged(IBinder oldToken, IBinder newToken) {
+        if (mFocusedWindow != null) {
+            if (mFocusedWindow.asBinder() == newToken) {
+                Slog.w(TAG, "notifyFocusChanged called with unchanged mFocusedWindow="
+                        + mFocusedWindow);
+                return;
             }
-            if (token instanceof IWindow) {
-                mFocusedWindow = (IWindow) token;
-            }
+            setPointerCapture(false);
         }
+
+        mFocusedWindow = IWindow.Stub.asInterface(newToken);
     }
 
     // Native callback.
@@ -1946,8 +1926,30 @@
     }
 
     // Native callback.
-    private PointerIcon getPointerIcon() {
-        return PointerIcon.getDefaultIcon(mContext);
+    private PointerIcon getPointerIcon(int displayId) {
+        return PointerIcon.getDefaultIcon(getContextForDisplay(displayId));
+    }
+
+    private Context getContextForDisplay(int displayId) {
+        if (mDisplayContext != null && mDisplayContext.getDisplay().getDisplayId() == displayId) {
+            return mDisplayContext;
+        }
+
+        if (mContext.getDisplay().getDisplayId() == displayId) {
+            mDisplayContext = mContext;
+            return mDisplayContext;
+        }
+
+        // Create and cache context for non-default display.
+        final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+        final Display display = displayManager.getDisplay(displayId);
+        mDisplayContext = mContext.createDisplayContext(display);
+        return mDisplayContext;
+    }
+
+    // Native callback.
+    private int getPointerDisplayId() {
+        return mWindowManagerCallbacks.getPointerDisplayId();
     }
 
     // Native callback.
@@ -2017,6 +2019,8 @@
                 KeyEvent event, int policyFlags);
 
         public int getPointerLayer();
+
+        public int getPointerDisplayId();
     }
 
     /**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 3264790..944a95d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -16,7 +16,14 @@
 
 package com.android.server.inputmethod;
 
-import android.content.ComponentName;
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.view.inputmethod.InputMethodInfo;
+
+import com.android.server.LocalServices;
+
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Input method manager local system service interface.
@@ -34,14 +41,25 @@
     public abstract void hideCurrentInputMethod();
 
     /**
-     * Switches to VR InputMethod defined in the packageName of {@param componentName}.
+     * Returns the list of installed input methods for the specified user.
+     *
+     * @param userId The user ID to be queried.
+     * @return A list of {@link InputMethodInfo}.  VR-only IMEs are already excluded.
      */
-    public abstract void startVrInputMethodNoCheck(ComponentName componentName);
+    public abstract List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId);
+
+    /**
+     * Returns the list of installed input methods that are enabled for the specified user.
+     *
+     * @param userId The user ID to be queried.
+     * @return A list of {@link InputMethodInfo} that are enabled for {@code userId}.
+     */
+    public abstract List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId);
 
     /**
      * Fake implementation of {@link InputMethodManagerInternal}.  All the methods do nothing.
      */
-    public static final InputMethodManagerInternal NOP =
+    private static final InputMethodManagerInternal NOP =
             new InputMethodManagerInternal() {
                 @Override
                 public void setInteractive(boolean interactive) {
@@ -52,7 +70,23 @@
                 }
 
                 @Override
-                public void startVrInputMethodNoCheck(ComponentName componentName) {
+                public List<InputMethodInfo> getInputMethodListAsUser(int userId) {
+                    return Collections.emptyList();
+                }
+
+                @Override
+                public List<InputMethodInfo> getEnabledInputMethodListAsUser(int userId) {
+                    return Collections.emptyList();
                 }
             };
+
+    /**
+     * @return Global instance if exists.  Otherwise, a dummy no-op instance.
+     */
+    @NonNull
+    public static InputMethodManagerInternal get() {
+        final InputMethodManagerInternal instance =
+                LocalServices.getService(InputMethodManagerInternal.class);
+        return instance != null ? instance : NOP;
+    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 5a7739c..3fd3945 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -20,6 +20,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.inputmethod.InputMethodSystemProperty.PER_PROFILE_IME_ENABLED;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -88,9 +89,8 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.provider.Settings;
-import android.service.vr.IVrManager;
-import android.service.vr.IVrStateCallbacks;
 import android.text.TextUtils;
 import android.text.style.SuggestionSpan;
 import android.util.ArrayMap;
@@ -201,7 +201,6 @@
     static final int MSG_CREATE_SESSION = 1050;
 
     static final int MSG_START_INPUT = 2000;
-    static final int MSG_START_VR_INPUT = 2010;
 
     static final int MSG_UNBIND_CLIENT = 3000;
     static final int MSG_BIND_CLIENT = 3010;
@@ -291,6 +290,8 @@
                 new DebugFlag("debug.optimize_startinput", false);
     }
 
+    @UserIdInt
+    private int mLastSwitchUserId;
 
     final Context mContext;
     final Resources mRes;
@@ -306,6 +307,7 @@
     private final HardKeyboardListener mHardKeyboardListener;
     private final AppOpsManager mAppOpsManager;
     private final UserManager mUserManager;
+    private final UserManagerInternal mUserManagerInternal;
 
     // All known input methods.  mMethodMap also serves as the global
     // lock for this class.
@@ -376,28 +378,6 @@
         }
     }
 
-    /**
-     * VR state callback.
-     * Listens for when VR mode finishes.
-     */
-    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
-        @Override
-        public void onVrStateChanged(boolean enabled) {
-            if (!enabled) {
-                restoreNonVrImeFromSettingsNoCheck();
-            }
-        }
-    };
-
-    private void restoreNonVrImeFromSettingsNoCheck() {
-        // switch back to non-VR InputMethod from settings.
-        synchronized (mMethodMap) {
-            if (!mIsVrImeStarted) return;
-            mIsVrImeStarted = false;
-            updateFromSettingsLocked(false);
-        }
-    }
-
     private static final class ClientDeathRecipient implements IBinder.DeathRecipient {
         private final InputMethodManagerService mImms;
         private final IInputMethodClient mClient;
@@ -592,9 +572,6 @@
 
     final ImeDisplayValidator mImeDisplayValidator;
 
-    /** True if VR IME started by {@link #startVrInputMethodNoCheck}. */
-    boolean mIsVrImeStarted;
-
     /**
      * If non-null, this is the input method service we are currently connected
      * to.
@@ -972,31 +949,6 @@
     }
 
     /**
-     * Start a VR InputMethod that matches IME with package name of {@param component}.
-     * Note: This method is called from {@link android.app.VrManager}.
-     */
-    private void startVrInputMethodNoCheck(@Nullable ComponentName component) {
-        if (component == null) {
-            // clear the current VR-only IME (if any) and restore normal IME.
-            restoreNonVrImeFromSettingsNoCheck();
-            return;
-        }
-
-        synchronized (mMethodMap) {
-            String packageName = component.getPackageName();
-            for (InputMethodInfo info : mMethodList) {
-                if (TextUtils.equals(info.getPackageName(), packageName) && info.isVrOnly()) {
-                    // set this is as current inputMethod without updating settings.
-                    setInputMethodEnabledLocked(info.getId(), true);
-                    setInputMethodLocked(info.getId(), NOT_A_SUBTYPE_ID);
-                    mIsVrImeStarted = true;
-                    break;
-                }
-            }
-        }
-    }
-
-    /**
      * Handles {@link Intent#ACTION_LOCALE_CHANGED}.
      *
      * <p>Note: For historical reasons, {@link Intent#ACTION_LOCALE_CHANGED} has been sent to all
@@ -1238,7 +1190,7 @@
                             // Uh oh, current input method is no longer around!
                             // Pick another one...
                             Slog.i(TAG, "Current input method removed: " + curInputMethodId);
-                            updateSystemUiLocked(mCurToken, 0 /* vis */, mBackDisposition);
+                            updateSystemUiLocked(0 /* vis */, mBackDisposition);
                             if (!chooseNewDefaultIMELocked()) {
                                 changed = true;
                                 curIm = null;
@@ -1402,6 +1354,7 @@
         }, true /*asyncHandler*/);
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
         mUserManager = mContext.getSystemService(UserManager.class);
+        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
         mHardKeyboardListener = new HardKeyboardListener();
         mHasFeature = context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_INPUT_METHODS);
@@ -1436,6 +1389,8 @@
             Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
         }
 
+        mLastSwitchUserId = userId;
+
         // mSettings should be created before buildInputMethodListLocked
         mSettings = new InputMethodSettings(
                 mRes, context.getContentResolver(), mMethodMap, mMethodList, userId, !mSystemReady);
@@ -1444,15 +1399,6 @@
         AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
         mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
                 mSettings, context);
-        // Register VR-state listener.
-        IVrManager vrManager = (IVrManager) ServiceManager.getService(Context.VR_SERVICE);
-        if (vrManager != null) {
-            try {
-                vrManager.registerListener(mVrStateCallbacks);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to register VR mode state listener.");
-            }
-        }
     }
 
     private void resetDefaultImeLocked(Context context) {
@@ -1484,7 +1430,7 @@
         // If the system is not ready or the device is not yed unlocked by the user, then we use
         // copy-on-write settings.
         final boolean useCopyOnWriteSettings =
-                !mSystemReady || !mUserManager.isUserUnlockingOrUnlocked(newUserId);
+                !mSystemReady || !mUserManagerInternal.isUserUnlockingOrUnlocked(newUserId);
         mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
         updateCurrentProfileIds();
         // Additional subtypes should be reset when the user is changed
@@ -1523,6 +1469,8 @@
 
         if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
                 + " selectedIme=" + mSettings.getSelectedInputMethod());
+
+        mLastSwitchUserId = newUserId;
     }
 
     void updateCurrentProfileIds() {
@@ -1555,14 +1503,14 @@
                 mLastSystemLocales = mRes.getConfiguration().getLocales();
                 final int currentUserId = mSettings.getCurrentUserId();
                 mSettings.switchCurrentUser(currentUserId,
-                        !mUserManager.isUserUnlockingOrUnlocked(currentUserId));
+                        !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId));
                 mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
                 mNotificationManager = mContext.getSystemService(NotificationManager.class);
                 mStatusBar = statusBar;
                 if (mStatusBar != null) {
                     mStatusBar.setIconVisibility(mSlotIme, false);
                 }
-                updateSystemUiLocked(mCurToken, mImeWindowVis, mBackDisposition);
+                updateSystemUiLocked(mImeWindowVis, mBackDisposition);
                 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
                         com.android.internal.R.bool.show_ongoing_ime_switcher);
                 if (mShowOngoingImeSwitcherForPhones) {
@@ -1607,7 +1555,13 @@
                     + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()
                     + InputMethodUtils.getApiCallStack());
         }
-        if (uid == Process.SYSTEM_UID || mSettings.isCurrentProfile(userId)) {
+        if (uid == Process.SYSTEM_UID) {
+            return true;
+        }
+        if (userId == mSettings.getCurrentUserId()) {
+            return true;
+        }
+        if (!PER_PROFILE_IME_ENABLED && mSettings.isCurrentProfile(userId)) {
             return true;
         }
 
@@ -1638,16 +1592,11 @@
      * @return true if and only if non-null valid token is specified.
      */
     @GuardedBy("mMethodMap")
-    private boolean calledWithValidTokenLocked(@Nullable IBinder token) {
-        if (token == null && Binder.getCallingPid() == Process.myPid()) {
-            if (DEBUG) {
-                // TODO(b/34851776): Basically it's the caller's fault if we reach here.
-                Slog.d(TAG, "Bug 34851776 is detected callers=" + Debug.getCallers(10));
-            }
-            return false;
+    private boolean calledWithValidTokenLocked(@NonNull IBinder token) {
+        if (token == null) {
+            throw new InvalidParameterException("token must not be null.");
         }
-        if (token == null || token != mCurToken) {
-            // TODO(b/34886274): The semantics of this verification is actually not well-defined.
+        if (token != mCurToken) {
             Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token."
                     + " uid:" + Binder.getCallingUid() + " token:" + token);
             return false;
@@ -1668,40 +1617,73 @@
 
     @Override
     public List<InputMethodInfo> getInputMethodList() {
-        return getInputMethodList(false /* isVrOnly */);
-    }
-
-    @Override
-    public List<InputMethodInfo> getVrInputMethodList() {
-        return getInputMethodList(true /* isVrOnly */);
-    }
-
-    private List<InputMethodInfo> getInputMethodList(final boolean isVrOnly) {
+        final int callingUserId = UserHandle.getCallingUserId();
         synchronized (mMethodMap) {
-            // TODO: Make this work even for non-current users?
-            if (!calledFromValidUserLocked()) {
+            final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+                    mSettings.getCurrentUserId(), null);
+            if (resolvedUserIds.length != 1) {
                 return Collections.emptyList();
             }
-            ArrayList<InputMethodInfo> methodList = new ArrayList<>();
-            for (InputMethodInfo info : mMethodList) {
-
-                if (info.isVrOnly() == isVrOnly) {
-                    methodList.add(info);
-                }
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return getInputMethodListLocked(resolvedUserIds[0]);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
-            return methodList;
         }
     }
 
     @Override
     public List<InputMethodInfo> getEnabledInputMethodList() {
+        final int callingUserId = UserHandle.getCallingUserId();
         synchronized (mMethodMap) {
-            // TODO: Make this work even for non-current users?
-            if (!calledFromValidUserLocked()) {
+            final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+                    mSettings.getCurrentUserId(), null);
+            if (resolvedUserIds.length != 1) {
                 return Collections.emptyList();
             }
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return getEnabledInputMethodListLocked(resolvedUserIds[0]);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @GuardedBy("mMethodMap")
+    private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId) {
+        final ArrayList<InputMethodInfo> methodList;
+        if (userId == mSettings.getCurrentUserId()) {
+            // Create a copy.
+            methodList = new ArrayList<>(mMethodList);
+        } else {
+            final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
+            methodList = new ArrayList<>();
+            final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
+                    new ArrayMap<>();
+            AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
+            queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
+                    methodList);
+        }
+        return methodList;
+    }
+
+    @GuardedBy("mMethodMap")
+    private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId) {
+        if (userId == mSettings.getCurrentUserId()) {
             return mSettings.getEnabledInputMethodListLocked();
         }
+        final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
+        final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
+        final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
+                new ArrayMap<>();
+        AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
+        queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
+                methodList);
+        final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
+                mContext.getContentResolver(), methodMap, methodList, userId, true);
+        return settings.getEnabledInputMethodListLocked();
     }
 
     /**
@@ -1711,11 +1693,27 @@
     @Override
     public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
             boolean allowsImplicitlySelectedSubtypes) {
+        final int callingUserId = UserHandle.getCallingUserId();
         synchronized (mMethodMap) {
-            // TODO: Make this work even for non-current users?
-            if (!calledFromValidUserLocked()) {
+            final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+                    mSettings.getCurrentUserId(), null);
+            if (resolvedUserIds.length != 1) {
                 return Collections.emptyList();
             }
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return getEnabledInputMethodSubtypeListLocked(imiId,
+                        allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @GuardedBy("mMethodMap")
+    private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(String imiId,
+            boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
+        if (userId == mSettings.getCurrentUserId()) {
             final InputMethodInfo imi;
             if (imiId == null && mCurMethodId != null) {
                 imi = mMethodMap.get(mCurMethodId);
@@ -1728,6 +1726,21 @@
             return mSettings.getEnabledInputMethodSubtypeListLocked(
                     mContext, imi, allowsImplicitlySelectedSubtypes);
         }
+        final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
+        final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
+        final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
+                new ArrayMap<>();
+        AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
+        queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
+                methodList);
+        final InputMethodInfo imi = methodMap.get(imiId);
+        if (imi == null) {
+            return Collections.emptyList();
+        }
+        final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
+                mContext.getContentResolver(), methodMap, methodList, userId, true);
+        return settings.getEnabledInputMethodSubtypeListLocked(
+                mContext, imi, allowsImplicitlySelectedSubtypes);
     }
 
     /**
@@ -1926,8 +1939,8 @@
         }
         // Compute the final shown display ID with validated cs.selfReportedDisplayId for this
         // session & other conditions.
-        final int displayIdToShowIme = computeImeDisplayIdForTarget(
-                cs.selfReportedDisplayId, mIsVrImeStarted, mImeDisplayValidator);
+        final int displayIdToShowIme = computeImeDisplayIdForTarget(cs.selfReportedDisplayId,
+                mImeDisplayValidator);
 
         if (mCurClient != cs) {
             // Was the keyguard locked when switching over to the new client?
@@ -2036,17 +2049,11 @@
      * Find the display where the IME should be shown.
      *
      * @param displayId the ID of the display where the IME client target is.
-     * @param isVrImeStarted {@code true} if VR IME started, {@code false} otherwise.
      * @param checker instance of {@link ImeDisplayValidator} which is used for
      *                checking display config to adjust the final target display.
      * @return The ID of the display where the IME should be shown.
      */
-    static int computeImeDisplayIdForTarget(int displayId, boolean isVrImeStarted,
-            @NonNull ImeDisplayValidator checker) {
-        // For VR IME, we always show in default display.
-        if (isVrImeStarted) {
-            return DEFAULT_DISPLAY;
-        }
+    static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) {
         if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
             // We always assume that the default display id suitable to show the IME window.
             return DEFAULT_DISPLAY;
@@ -2160,7 +2167,7 @@
                     sessionState.session.finishSession();
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Session failed to close due to remote exception", e);
-                    updateSystemUiLocked(mCurToken, 0 /* vis */, mBackDisposition);
+                    updateSystemUiLocked(0 /* vis */, mBackDisposition);
                 }
                 sessionState.session = null;
             }
@@ -2319,14 +2326,14 @@
 
     @BinderThread
     @SuppressWarnings("deprecation")
-    private void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
+    private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
         synchronized (mMethodMap) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
             }
             mImeWindowVis = vis;
             mBackDisposition = backDisposition;
-            updateSystemUiLocked(token, vis, backDisposition);
+            updateSystemUiLocked(vis, backDisposition);
         }
 
         final boolean dismissImeOnBackKeyPressed;
@@ -2346,14 +2353,8 @@
                 (vis & InputMethodService.IME_VISIBLE) != 0, dismissImeOnBackKeyPressed);
     }
 
-    private void updateSystemUi(IBinder token, int vis, int backDisposition) {
-        synchronized (mMethodMap) {
-            updateSystemUiLocked(token, vis, backDisposition);
-        }
-    }
-
     @BinderThread
-    private void reportStartInput(IBinder token, IBinder startInputToken) {
+    private void reportStartInput(@NonNull IBinder token, IBinder startInputToken) {
         synchronized (mMethodMap) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
@@ -2367,11 +2368,10 @@
     }
 
     // Caution! This method is called in this class. Handle multi-user carefully
-    private void updateSystemUiLocked(IBinder token, int vis, int backDisposition) {
-        if (!calledWithValidTokenLocked(token)) {
+    private void updateSystemUiLocked(int vis, int backDisposition) {
+        if (mCurToken == null) {
             return;
         }
-
         // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
         // all updateSystemUi happens on system previlege.
         final long ident = Binder.clearCallingIdentity();
@@ -2383,7 +2383,7 @@
             // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
             final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
             if (mStatusBar != null) {
-                mStatusBar.setImeWindowStatus(token, vis, backDisposition,
+                mStatusBar.setImeWindowStatus(mCurToken, vis, backDisposition,
                         needsToShowImeSwitcher);
             }
             final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
@@ -2425,54 +2425,6 @@
         }
     }
 
-    @Override
-    public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) {
-        synchronized (mMethodMap) {
-            if (!calledFromValidUserLocked()) {
-                return;
-            }
-            final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
-            for (int i = 0; i < spans.length; ++i) {
-                SuggestionSpan ss = spans[i];
-                if (!TextUtils.isEmpty(ss.getNotificationTargetClassName())) {
-                    mSecureSuggestionSpans.put(ss, currentImi);
-                }
-            }
-        }
-    }
-
-    @Override
-    public boolean notifySuggestionPicked(SuggestionSpan span, String originalString, int index) {
-        synchronized (mMethodMap) {
-            if (!calledFromValidUserLocked()) {
-                return false;
-            }
-            final InputMethodInfo targetImi = mSecureSuggestionSpans.get(span);
-            // TODO: Do not send the intent if the process of the targetImi is already dead.
-            if (targetImi != null) {
-                final String[] suggestions = span.getSuggestions();
-                if (index < 0 || index >= suggestions.length) return false;
-                final String className = span.getNotificationTargetClassName();
-                final Intent intent = new Intent();
-                // Ensures that only a class in the original IME package will receive the
-                // notification.
-                intent.setClassName(targetImi.getPackageName(), className);
-                intent.setAction(SuggestionSpan.ACTION_SUGGESTION_PICKED);
-                intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_BEFORE, originalString);
-                intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_AFTER, suggestions[index]);
-                intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_HASHCODE, span.hashCode());
-                final long ident = Binder.clearCallingIdentity();
-                try {
-                    mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-                return true;
-            }
-        }
-        return false;
-    }
-
     void updateFromSettingsLocked(boolean enabledMayChange) {
         updateInputMethodsFromSettingsLocked(enabledMayChange);
         updateKeyboardFromSettingsLocked();
@@ -2573,7 +2525,7 @@
                 setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
                 if (mCurMethod != null) {
                     try {
-                        updateSystemUiLocked(mCurToken, mImeWindowVis, mBackDisposition);
+                        updateSystemUiLocked(mImeWindowVis, mBackDisposition);
                         mCurMethod.changeInputMethodSubtype(newSubtype);
                     } catch (RemoteException e) {
                         Slog.w(TAG, "Failed to call changeInputMethodSubtype");
@@ -2803,10 +2755,25 @@
             @SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
             IInputContext inputContext, @MissingMethodFlags int missingMethods,
             int unverifiedTargetSdkVersion) {
+        final int callingUserId = UserHandle.getCallingUserId();
+        final int userId;
+        if (attribute != null && attribute.targetInputMethodUser != null
+                && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
+            mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "Using EditorInfo.user requires INTERACT_ACROSS_USERS_FULL.");
+            userId = attribute.targetInputMethodUser.getIdentifier();
+            if (!mUserManagerInternal.isUserRunning(userId)) {
+                // There is a chance that we hit here because of race condition.  Let's just return
+                // an error code instead of crashing the caller process, which at least has
+                // INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important process.
+                Slog.e(TAG, "User #" + userId + " is not running.");
+                return InputBindResult.INVALID_USER;
+            }
+        } else {
+            userId = callingUserId;
+        }
         InputBindResult res = null;
         synchronized (mMethodMap) {
-            // Needs to check the validity before clearing calling identity
-            final boolean calledFromValidUser = calledFromValidUserLocked();
             final int windowDisplayId =
                     mWindowManagerInternal.getDisplayIdForWindow(windowToken);
             final long ident = Binder.clearCallingIdentity();
@@ -2850,14 +2817,20 @@
                     return InputBindResult.NOT_IME_TARGET_WINDOW;
                 }
 
-                if (!calledFromValidUser) {
+                // cross-profile access is always allowed here to allow profile-switching.
+                if (!mSettings.isCurrentProfile(userId)) {
                     Slog.w(TAG, "A background user is requesting window. Hiding IME.");
-                    Slog.w(TAG, "If you want to interect with IME, you need "
-                            + "android.permission.INTERACT_ACROSS_USERS_FULL");
+                    Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
+                            + " a background user, use EditorInfo.targetInputMethodUser with"
+                            + " INTERACT_ACROSS_USERS_FULL permission.");
                     hideCurrentInputLocked(0, null);
                     return InputBindResult.INVALID_USER;
                 }
 
+                if (PER_PROFILE_IME_ENABLED && userId != mSettings.getCurrentUserId()) {
+                    switchUserLocked(userId);
+                }
+
                 if (mCurFocusedWindow == windowToken) {
                     if (DEBUG) {
                         Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
@@ -3067,7 +3040,7 @@
     }
 
     @BinderThread
-    private void setInputMethod(IBinder token, String id) {
+    private void setInputMethod(@NonNull IBinder token, String id) {
         synchronized (mMethodMap) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
@@ -3077,7 +3050,8 @@
     }
 
     @BinderThread
-    private void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) {
+    private void setInputMethodAndSubtype(@NonNull IBinder token, String id,
+            InputMethodSubtype subtype) {
         synchronized (mMethodMap) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
@@ -3106,7 +3080,7 @@
     }
 
     @BinderThread
-    private boolean switchToPreviousInputMethod(IBinder token) {
+    private boolean switchToPreviousInputMethod(@NonNull IBinder token) {
         synchronized (mMethodMap) {
             if (!calledWithValidTokenLocked(token)) {
                 return false;
@@ -3178,7 +3152,7 @@
     }
 
     @BinderThread
-    private boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) {
+    private boolean switchToNextInputMethod(@NonNull IBinder token, boolean onlyCurrentIme) {
         synchronized (mMethodMap) {
             if (!calledWithValidTokenLocked(token)) {
                 return false;
@@ -3565,9 +3539,6 @@
             case MSG_SET_INTERACTIVE:
                 handleSetInteractive(msg.arg1 != 0);
                 return true;
-            case MSG_START_VR_INPUT:
-                startVrInputMethodNoCheck((ComponentName) msg.obj);
-                return true;
             case MSG_REPORT_FULLSCREEN_MODE: {
                 final boolean fullscreen = msg.arg1 != 0;
                 final ClientState clientState = (ClientState)msg.obj;
@@ -3596,7 +3567,7 @@
     private void handleSetInteractive(final boolean interactive) {
         synchronized (mMethodMap) {
             mIsInteractive = interactive;
-            updateSystemUiLocked(mCurToken, interactive ? mImeWindowVis : 0, mBackDisposition);
+            updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
 
             // Inform the current client of the change in active status
             if (mCurClient != null && mCurClient.client != null) {
@@ -3654,6 +3625,9 @@
             try {
                 final InputMethodInfo imi = new InputMethodInfo(context, ri,
                         additionalSubtypeMap.get(imeId));
+                if (imi.isVrOnly()) {
+                    continue;  // Skip VR-only IME, which isn't supported for now.
+                }
                 methodList.add(imi);
                 methodMap.put(imi.getId(), imi);
                 if (DEBUG) {
@@ -3927,7 +3901,7 @@
             attrs.privateFlags |= PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
             attrs.setTitle("Select input method");
             w.setAttributes(attrs);
-            updateSystemUi(mCurToken, mImeWindowVis, mBackDisposition);
+            updateSystemUiLocked(mImeWindowVis, mBackDisposition);
             mSwitchingDialog.show();
         }
     }
@@ -3987,7 +3961,7 @@
             mSwitchingDialogTitleView = null;
         }
 
-        updateSystemUiLocked(mCurToken, mImeWindowVis, mBackDisposition);
+        updateSystemUiLocked(mImeWindowVis, mBackDisposition);
         mDialogBuilder = null;
         mIms = null;
     }
@@ -4037,17 +4011,7 @@
 
     private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
             boolean setSubtypeOnly) {
-        // Updates to InputMethod are transient in VR mode. Its not included in history.
-        final boolean isVrInput = imi != null && imi.isVrOnly();
-        if (!isVrInput) {
-            // Update the history of InputMethod and Subtype
-            mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
-        }
-
-        if (isVrInput) {
-            // Updates to InputMethod are transient in VR mode. Any changes to Settings are skipped.
-            return;
-        }
+        mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
 
         // Set Subtype here
         if (imi == null || subtypeId < 0) {
@@ -4142,22 +4106,15 @@
         return mCurrentSubtype;
     }
 
-    @Override
-    public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
+    private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
         synchronized (mMethodMap) {
-            // TODO: Make this work even for non-current users?
-            if (!calledFromValidUserLocked()) {
-                return false;
-            }
-            if (subtype != null && mCurMethodId != null) {
-                InputMethodInfo imi = mMethodMap.get(mCurMethodId);
-                int subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(imi, subtype.hashCode());
-                if (subtypeId != NOT_A_SUBTYPE_ID) {
-                    setInputMethodLocked(mCurMethodId, subtypeId);
-                    return true;
-                }
-            }
-            return false;
+            return getInputMethodListLocked(userId);
+        }
+    }
+
+    private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
+        synchronized (mMethodMap) {
+            return getEnabledInputMethodListLocked(userId);
         }
     }
 
@@ -4183,8 +4140,13 @@
         }
 
         @Override
-        public void startVrInputMethodNoCheck(@Nullable ComponentName componentName) {
-            mService.mHandler.obtainMessage(MSG_START_VR_INPUT, componentName).sendToTarget();
+        public List<InputMethodInfo> getInputMethodListAsUser(int userId) {
+            return mService.getInputMethodListAsUser(userId);
+        }
+
+        @Override
+        public List<InputMethodInfo> getEnabledInputMethodListAsUser(int userId) {
+            return mService.getEnabledInputMethodListAsUser(userId);
         }
     }
 
@@ -4243,7 +4205,7 @@
     }
 
     @BinderThread
-    private void reportFullscreenMode(IBinder token, boolean fullscreen) {
+    private void reportFullscreenMode(@NonNull IBinder token, boolean fullscreen) {
         synchronized (mMethodMap) {
             if (!calledWithValidTokenLocked(token)) {
                 return;
@@ -4424,6 +4386,10 @@
                 return refreshDebugProperties();
             }
 
+            if ("get-last-switch-user-id".equals(cmd)) {
+                return mService.getLastSwitchUserId(this);
+            }
+
             // For existing "adb shell ime <command>".
             if ("ime".equals(cmd)) {
                 final String imeCommand = getNextArg();
@@ -4516,6 +4482,15 @@
     // ----------------------------------------------------------------------
     // Shell command handlers:
 
+    @BinderThread
+    @ShellCommandResult
+    private int getLastSwitchUserId(@NonNull ShellCommand shellCommand) {
+        synchronized (mMethodMap) {
+            shellCommand.getOutPrintWriter().println(mLastSwitchUserId);
+            return ShellCommandResult.SUCCESS;
+        }
+    }
+
     /**
      * Handles {@code adb shell ime list}.
      * @param shellCommand {@link ShellCommand} object that is handling this command.
@@ -4526,6 +4501,7 @@
     private int handleShellCommandListInputMethods(@NonNull ShellCommand shellCommand) {
         boolean all = false;
         boolean brief = false;
+        int userIdToBeResolved = UserHandle.USER_CURRENT;
         while (true) {
             final String nextOption = shellCommand.getNextOption();
             if (nextOption == null) {
@@ -4538,19 +4514,34 @@
                 case "-s":
                     brief = true;
                     break;
+                case "-u":
+                case "--user":
+                    userIdToBeResolved = UserHandle.parseUserArg(shellCommand.getNextArgRequired());
+                    break;
             }
         }
-        final List<InputMethodInfo> methods = all ?
-                getInputMethodList() : getEnabledInputMethodList();
-        final PrintWriter pr = shellCommand.getOutPrintWriter();
-        final Printer printer = x -> pr.println(x);
-        final int N = methods.size();
-        for (int i = 0; i < N; ++i) {
-            if (brief) {
-                pr.println(methods.get(i).getId());
-            } else {
-                pr.print(methods.get(i).getId()); pr.println(":");
-                methods.get(i).dump(printer, "  ");
+        synchronized (mMethodMap) {
+            final PrintWriter pr = shellCommand.getOutPrintWriter();
+            final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
+                    mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
+            for (int userId : userIds) {
+                final List<InputMethodInfo> methods = all
+                        ? getInputMethodListLocked(userId)
+                        : getEnabledInputMethodListLocked(userId);
+                if (userIds.length > 1) {
+                    pr.print("User #");
+                    pr.print(userId);
+                    pr.println(":");
+                }
+                for (InputMethodInfo info : methods) {
+                    if (brief) {
+                        pr.println(info.getId());
+                    } else {
+                        pr.print(info.getId());
+                        pr.println(":");
+                        info.dump(pr::println, "  ");
+                    }
+                }
             }
         }
         return ShellCommandResult.SUCCESS;
@@ -4649,8 +4640,10 @@
     private static final class InputMethodPrivilegedOperationsImpl
             extends IInputMethodPrivilegedOperations.Stub {
         private final InputMethodManagerService mImms;
+        @NonNull
         private final IBinder mToken;
-        InputMethodPrivilegedOperationsImpl(InputMethodManagerService imms, IBinder token) {
+        InputMethodPrivilegedOperationsImpl(InputMethodManagerService imms,
+                @NonNull IBinder token) {
             mImms = imms;
             mToken = token;
         }
@@ -4730,7 +4723,7 @@
 
         @BinderThread
         @Override
-        public void notifyUserActionAsync() {
+        public void notifyUserAction() {
             mImms.notifyUserAction(mToken);
         }
     }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 1137bf9..88d1a9c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -29,21 +29,27 @@
 import android.os.Build;
 import android.os.LocaleList;
 import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManagerInternal;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.IntArray;
 import android.util.Pair;
 import android.util.Printer;
 import android.util.Slog;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
+import android.view.inputmethod.InputMethodSystemProperty;
 import android.view.textservice.SpellCheckerInfo;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.StartInputFlags;
+import com.android.server.LocalServices;
 import com.android.server.textservices.TextServicesManagerInternal;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedHashSet;
@@ -1286,4 +1292,62 @@
         return true;
     }
 
+    /**
+     * Converts a user ID, which can be a pseudo user ID such as {@link UserHandle#USER_ALL} to a
+     * list of real user IDs.
+     *
+     * <p>This method also converts profile user ID to profile parent user ID unless
+     * {@link InputMethodSystemProperty#PER_PROFILE_IME_ENABLED} is {@code true}.</p>
+     *
+     * @param userIdToBeResolved A user ID. Two pseudo user ID {@link UserHandle#USER_CURRENT} and
+     *                           {@link UserHandle#USER_ALL} are also supported
+     * @param currentUserId A real user ID, which will be used when {@link UserHandle#USER_CURRENT}
+     *                      is specified in {@code userIdToBeResolved}.
+     * @param warningWriter A {@link PrintWriter} to output some debug messages. {@code null} if
+     *                      no debug message is required.
+     * @return An integer array that contain user IDs.
+     */
+    static int[] resolveUserId(@UserIdInt int userIdToBeResolved,
+            @UserIdInt int currentUserId, @Nullable PrintWriter warningWriter) {
+        final UserManagerInternal userManagerInternal =
+                LocalServices.getService(UserManagerInternal.class);
+
+        if (userIdToBeResolved == UserHandle.USER_ALL) {
+            if (InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
+                return userManagerInternal.getUserIds();
+            }
+            final IntArray result = new IntArray();
+            for (int userId : userManagerInternal.getUserIds()) {
+                final int parentUserId = userManagerInternal.getProfileParentId(userId);
+                if (result.indexOf(parentUserId) < 0) {
+                    result.add(parentUserId);
+                }
+            }
+            return result.toArray();
+        }
+
+        final int sourceUserId;
+        if (userIdToBeResolved == UserHandle.USER_CURRENT) {
+            sourceUserId = currentUserId;
+        } else if (userIdToBeResolved < 0) {
+            if (warningWriter != null) {
+                warningWriter.print("Pseudo user ID ");
+                warningWriter.print(userIdToBeResolved);
+                warningWriter.println(" is not supported.");
+            }
+            return new int[]{};
+        } else if (userManagerInternal.exists(userIdToBeResolved)) {
+            sourceUserId = userIdToBeResolved;
+        } else {
+            if (warningWriter != null) {
+                warningWriter.print("User #");
+                warningWriter.print(userIdToBeResolved);
+                warningWriter.println(" does not exit.");
+            }
+            return new int[]{};
+        }
+        final int resolvedUserId = InputMethodSystemProperty.PER_PROFILE_IME_ENABLED
+                ? sourceUserId : userManagerInternal.getProfileParentId(sourceUserId);
+        return new int[]{resolvedUserId};
+    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 98ed3ea..3222143 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -53,7 +53,6 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
-import android.text.style.SuggestionSpan;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -160,8 +159,15 @@
                         }
 
                         @Override
-                        public void startVrInputMethodNoCheck(ComponentName componentName) {
-                            reportNotSupported();
+                        public List<InputMethodInfo> getInputMethodListAsUser(
+                                @UserIdInt int userId) {
+                            return userIdToInputMethodInfoMapper.getAsList(userId);
+                        }
+
+                        @Override
+                        public List<InputMethodInfo> getEnabledInputMethodListAsUser(
+                                @UserIdInt int userId) {
+                            return userIdToInputMethodInfoMapper.getAsList(userId);
                         }
                     });
         }
@@ -1233,13 +1239,6 @@
 
         @BinderThread
         @Override
-        public List<InputMethodInfo> getVrInputMethodList() {
-            reportNotSupported();
-            return Collections.emptyList();
-        }
-
-        @BinderThread
-        @Override
         public List<InputMethodInfo> getEnabledInputMethodList() {
             return mInputMethodInfoMap.getAsList(UserHandle.getUserId(Binder.getCallingUid()));
         }
@@ -1513,20 +1512,6 @@
 
         @BinderThread
         @Override
-        public void registerSuggestionSpansForNotification(SuggestionSpan[] suggestionSpans) {
-            reportNotSupported();
-        }
-
-        @BinderThread
-        @Override
-        public boolean notifySuggestionPicked(
-                SuggestionSpan span, String originalString, int index) {
-            reportNotSupported();
-            return false;
-        }
-
-        @BinderThread
-        @Override
         public InputMethodSubtype getCurrentInputMethodSubtype() {
             reportNotSupported();
             return null;
@@ -1534,13 +1519,6 @@
 
         @BinderThread
         @Override
-        public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
-            reportNotSupported();
-            return false;
-        }
-
-        @BinderThread
-        @Override
         public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
             reportNotSupported();
         }
diff --git a/services/core/java/com/android/server/job/JobConcurrencyManager.java b/services/core/java/com/android/server/job/JobConcurrencyManager.java
index 827c0f1..4d9b5f5 100644
--- a/services/core/java/com/android/server/job/JobConcurrencyManager.java
+++ b/services/core/java/com/android/server/job/JobConcurrencyManager.java
@@ -18,16 +18,34 @@
 
 import android.app.ActivityManager;
 import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.util.Slog;
+import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.StatLogger;
+import com.android.server.job.JobSchedulerService.Constants;
 import com.android.server.job.controllers.JobStatus;
 import com.android.server.job.controllers.StateController;
 
 import java.util.Iterator;
 import java.util.List;
 
+/**
+ * This class decides, given the various configuration and the system status, how many more jobs
+ * can start.
+ */
 class JobConcurrencyManager {
     private static final String TAG = JobSchedulerService.TAG;
     private static final boolean DEBUG = JobSchedulerService.DEBUG;
@@ -35,6 +53,16 @@
     private final Object mLock;
     private final JobSchedulerService mService;
     private final JobSchedulerService.Constants mConstants;
+    private final Context mContext;
+    private final Handler mHandler;
+
+    private PowerManager mPowerManager;
+
+    private boolean mCurrentInteractiveState;
+    private boolean mEffectiveInteractiveState;
+
+    private long mLastScreenOnRealtime;
+    private long mLastScreenOffRealtime;
 
     private static final int MAX_JOB_CONTEXTS_COUNT = JobSchedulerService.MAX_JOB_CONTEXTS_COUNT;
 
@@ -50,10 +78,193 @@
 
     int[] mRecycledPreferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT];
 
+    /** Max job counts according to the current system state. */
+    private JobSchedulerService.MaxJobCounts mMaxJobCounts;
+
+    private final JobCountTracker mJobCountTracker = new JobCountTracker();
+
+    /** Current memory trim level. */
+    private int mLastMemoryTrimLevel;
+
+    /** Used to throttle heavy API calls. */
+    private long mNextSystemStateRefreshTime;
+    private static final int SYSTEM_STATE_REFRESH_MIN_INTERVAL = 1000;
+
+    private final StatLogger mStatLogger = new StatLogger(new String[]{
+            "assignJobsToContexts",
+            "refreshSystemState",
+    });
+
+    interface Stats {
+        int ASSIGN_JOBS_TO_CONTEXTS = 0;
+        int REFRESH_SYSTEM_STATE = 1;
+
+        int COUNT = REFRESH_SYSTEM_STATE + 1;
+    }
+
     JobConcurrencyManager(JobSchedulerService service) {
         mService = service;
         mLock = mService.mLock;
         mConstants = service.mConstants;
+        mContext = service.getContext();
+
+        mHandler = BackgroundThread.getHandler();
+    }
+
+    public void onSystemReady() {
+        mPowerManager = mContext.getSystemService(PowerManager.class);
+
+        final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        mContext.registerReceiver(mReceiver, filter);
+
+        onInteractiveStateChanged(mPowerManager.isInteractive());
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            switch (intent.getAction()) {
+                case Intent.ACTION_SCREEN_ON:
+                    onInteractiveStateChanged(true);
+                    break;
+                case Intent.ACTION_SCREEN_OFF:
+                    onInteractiveStateChanged(false);
+                    break;
+            }
+        }
+    };
+
+    /**
+     * Called when the screen turns on / off.
+     */
+    private void onInteractiveStateChanged(boolean interactive) {
+        synchronized (mLock) {
+            if (mCurrentInteractiveState == interactive) {
+                return;
+            }
+            mCurrentInteractiveState = interactive;
+            if (DEBUG) {
+                Slog.d(TAG, "Interactive: " + interactive);
+            }
+
+            final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+            if (interactive) {
+                mLastScreenOnRealtime = now;
+                mEffectiveInteractiveState = true;
+
+                mHandler.removeCallbacks(mRampUpForScreenOff);
+            } else {
+                mLastScreenOffRealtime = now;
+
+                // Set mEffectiveInteractiveState to false after the delay, when we may increase
+                // the concurrency.
+                // We don't need a wakeup alarm here. When there's a pending job, there should
+                // also be jobs running too, meaning the device should be awake.
+
+                // Note: we can't directly do postDelayed(this::rampUpForScreenOn), because
+                // we need the exact same instance for removeCallbacks().
+                mHandler.postDelayed(mRampUpForScreenOff,
+                        mConstants.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.getValue());
+            }
+        }
+    }
+
+    private final Runnable mRampUpForScreenOff = this::rampUpForScreenOff;
+
+    /**
+     * Called in {@link Constants#SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS} after
+     * the screen turns off, in order to increase concurrency.
+     */
+    private void rampUpForScreenOff() {
+        synchronized (mLock) {
+            // Make sure the screen has really been off for the configured duration.
+            // (There could be a race.)
+            if (!mEffectiveInteractiveState) {
+                return;
+            }
+            if (mLastScreenOnRealtime > mLastScreenOffRealtime) {
+                return;
+            }
+            final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+            if ((mLastScreenOffRealtime
+                    + mConstants.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.getValue())
+                    > now) {
+                return;
+            }
+
+            mEffectiveInteractiveState = false;
+
+            if (DEBUG) {
+                Slog.d(TAG, "Ramping up concurrency");
+            }
+
+            mService.maybeRunPendingJobsLocked();
+        }
+    }
+
+    private boolean isFgJob(JobStatus job) {
+        return job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP;
+    }
+
+    @GuardedBy("mLock")
+    private void refreshSystemStateLocked() {
+        final long nowUptime = JobSchedulerService.sUptimeMillisClock.millis();
+
+        // Only refresh the information every so often.
+        if (nowUptime < mNextSystemStateRefreshTime) {
+            return;
+        }
+
+        final long start = mStatLogger.getTime();
+        mNextSystemStateRefreshTime = nowUptime + SYSTEM_STATE_REFRESH_MIN_INTERVAL;
+
+        mLastMemoryTrimLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+        try {
+            mLastMemoryTrimLevel = ActivityManager.getService().getMemoryTrimLevel();
+        } catch (RemoteException e) {
+        }
+
+        mStatLogger.logDurationStat(Stats.REFRESH_SYSTEM_STATE, start);
+    }
+
+    @GuardedBy("mLock")
+    private void updateMaxCountsLocked() {
+        refreshSystemStateLocked();
+
+        if (mEffectiveInteractiveState) {
+            // Screen on
+            switch (mLastMemoryTrimLevel) {
+                case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
+                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_ON_MODERATE;
+                    break;
+                case ProcessStats.ADJ_MEM_FACTOR_LOW:
+                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_ON_LOW;
+                    break;
+                case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_ON_CRITICAL;
+                    break;
+                default:
+                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_ON_NORMAL;
+                    break;
+            }
+        } else {
+            // Screen off
+            switch (mLastMemoryTrimLevel) {
+                case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
+                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_OFF_MODERATE;
+                    break;
+                case ProcessStats.ADJ_MEM_FACTOR_LOW:
+                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_OFF_LOW;
+                    break;
+                case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_OFF_CRITICAL;
+                    break;
+                default:
+                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_OFF_NORMAL;
+                    break;
+            }
+        }
     }
 
     /**
@@ -62,7 +273,17 @@
      * run higher priority ones.
      * Lock on mJobs before calling this function.
      */
+    @GuardedBy("mLock")
     void assignJobsToContextsLocked() {
+        final long start = mStatLogger.getTime();
+
+        assignJobsToContextsInternalLocked();
+
+        mStatLogger.logDurationStat(Stats.ASSIGN_JOBS_TO_CONTEXTS, start);
+    }
+
+    @GuardedBy("mLock")
+    private void assignJobsToContextsInternalLocked() {
         if (DEBUG) {
             Slog.d(TAG, printPendingQueueLocked());
         }
@@ -72,60 +293,63 @@
         final List<JobServiceContext> activeServices = mService.mActiveServices;
         final List<StateController> controllers = mService.mControllers;
 
-        int memLevel;
-        try {
-            memLevel = ActivityManager.getService().getMemoryTrimLevel();
-        } catch (RemoteException e) {
-            memLevel = ProcessStats.ADJ_MEM_FACTOR_NORMAL;
-        }
-        switch (memLevel) {
-            case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
-                mService.mMaxActiveJobs = mConstants.BG_MODERATE_JOB_COUNT;
-                break;
-            case ProcessStats.ADJ_MEM_FACTOR_LOW:
-                mService.mMaxActiveJobs = mConstants.BG_LOW_JOB_COUNT;
-                break;
-            case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
-                mService.mMaxActiveJobs = mConstants.BG_CRITICAL_JOB_COUNT;
-                break;
-            default:
-                mService.mMaxActiveJobs = mConstants.BG_NORMAL_JOB_COUNT;
-                break;
-        }
+        updateMaxCountsLocked();
 
         // To avoid GC churn, we recycle the arrays.
         JobStatus[] contextIdToJobMap = mRecycledAssignContextIdToJobMap;
         boolean[] slotChanged = mRecycledSlotChanged;
         int[] preferredUidForContext = mRecycledPreferredUidForContext;
 
-        int numTotalRunningJobs = 0;
-        int numForegroundJobs = 0;
+
+        // Initialize the work variables and also count running jobs.
+        mJobCountTracker.reset(
+                mMaxJobCounts.getTotalMax(),
+                mMaxJobCounts.getMaxBg(),
+                mMaxJobCounts.getMinBg());
+
         for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
             final JobServiceContext js = mService.mActiveServices.get(i);
             final JobStatus status = js.getRunningJobLocked();
+
             if ((contextIdToJobMap[i] = status) != null) {
-                numTotalRunningJobs++;
-                if (status.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
-                    numForegroundJobs++;
-                }
+                mJobCountTracker.incrementRunningJobCount(isFgJob(status));
             }
+
             slotChanged[i] = false;
             preferredUidForContext[i] = js.getPreferredUid();
         }
         if (DEBUG) {
             Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial"));
         }
-        for (int i=0; i<pendingJobs.size(); i++) {
-            final JobStatus nextPending = pendingJobs.get(i);
+
+        // Next, update the job priorities, and also count the pending FG / BG jobs.
+        for (int i = 0; i < pendingJobs.size(); i++) {
+            final JobStatus pending = pendingJobs.get(i);
 
             // If job is already running, go to next job.
+            int jobRunningContext = findJobContextIdFromMap(pending, contextIdToJobMap);
+            if (jobRunningContext != -1) {
+                continue;
+            }
+
+            final int priority = mService.evaluateJobPriorityLocked(pending);
+            pending.lastEvaluatedPriority = priority;
+
+            mJobCountTracker.incrementPendingJobCount(isFgJob(pending));
+        }
+
+        mJobCountTracker.onCountDone();
+
+        for (int i = 0; i < pendingJobs.size(); i++) {
+            final JobStatus nextPending = pendingJobs.get(i);
+
+            // Unfortunately we need to repeat this relatively expensive check.
             int jobRunningContext = findJobContextIdFromMap(nextPending, contextIdToJobMap);
             if (jobRunningContext != -1) {
                 continue;
             }
 
-            final int priority = mService.evaluateJobPriorityLocked(nextPending);
-            nextPending.lastEvaluatedPriority = priority;
+            final boolean isPendingFg = isFgJob(nextPending);
 
             // Find an available slot for nextPending. The context should be available OR
             // it should have lowest priority among all running jobs
@@ -137,18 +361,10 @@
                 JobStatus job = contextIdToJobMap[j];
                 int preferredUid = preferredUidForContext[j];
                 if (job == null) {
-                    final boolean totalCountOk = numTotalRunningJobs < mService.mMaxActiveJobs;
-                    final boolean fgCountOk = (priority >= JobInfo.PRIORITY_TOP_APP)
-                            && (numForegroundJobs < mConstants.FG_JOB_COUNT);
                     final boolean preferredUidOkay = (preferredUid == nextPending.getUid())
                             || (preferredUid == JobServiceContext.NO_PREFERRED_UID);
 
-                    // TODO: The following check is slightly wrong.
-                    // Depending on how the pending jobs are sorted, we sometimes cap the total
-                    // job count at mMaxActiveJobs (when all jobs are FG jobs), or
-                    // at [mMaxActiveJobs + FG_JOB_COUNT] (when there are mMaxActiveJobs BG jobs
-                    // and then FG_JOB_COUNT FG jobs.)
-                    if ((totalCountOk || fgCountOk) && preferredUidOkay) {
+                    if (preferredUidOkay && mJobCountTracker.canJobStart(isPendingFg)) {
                         // This slot is free, and we haven't yet hit the limit on
                         // concurrent jobs...  we can just throw the job in to here.
                         selectedContextId = j;
@@ -183,16 +399,18 @@
             }
             if (startingJob) {
                 // Increase the counters when we're going to start a job.
-                numTotalRunningJobs++;
-                if (priority >= JobInfo.PRIORITY_TOP_APP) {
-                    numForegroundJobs++;
-                }
+                mJobCountTracker.onStartingNewJob(isPendingFg);
             }
         }
         if (DEBUG) {
             Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final"));
         }
-        tracker.noteConcurrency(numTotalRunningJobs, numForegroundJobs);
+
+        mJobCountTracker.logStatus();
+
+        tracker.noteConcurrency(mJobCountTracker.getTotalRunningJobCountToNote(),
+                mJobCountTracker.getFgRunningJobCountToNote());
+
         for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
             boolean preservePreferredUid = false;
             if (slotChanged[i]) {
@@ -228,7 +446,7 @@
         }
     }
 
-    int findJobContextIdFromMap(JobStatus jobStatus, JobStatus[] map) {
+    private static int findJobContextIdFromMap(JobStatus jobStatus, JobStatus[] map) {
         for (int i=0; i<map.length; i++) {
             if (map[i] != null && map[i].matches(jobStatus.getUid(), jobStatus.getJobId())) {
                 return i;
@@ -237,6 +455,7 @@
         return -1;
     }
 
+    @GuardedBy("mLock")
     private String printPendingQueueLocked() {
         StringBuilder s = new StringBuilder("Pending queue: ");
         Iterator<JobStatus> it = mService.mPendingJobs.iterator();
@@ -251,7 +470,7 @@
         return s.toString();
     }
 
-    private String printContextIdToJobMap(JobStatus[] map, String initial) {
+    private static String printContextIdToJobMap(JobStatus[] map, String initial) {
         StringBuilder s = new StringBuilder(initial + ": ");
         for (int i=0; i<map.length; i++) {
             s.append("(")
@@ -262,4 +481,222 @@
         return s.toString();
     }
 
+
+    public void dumpLocked(IndentingPrintWriter pw) {
+        final long now = System.currentTimeMillis();
+        final long nowRealtime = JobSchedulerService.sElapsedRealtimeClock.millis();
+
+        pw.println("Concurrency:");
+
+        pw.increaseIndent();
+        try {
+            pw.print("Screen state: current ");
+            pw.print(mCurrentInteractiveState ? "ON" : "OFF");
+            pw.print("  effective ");
+            pw.print(mEffectiveInteractiveState ? "ON" : "OFF");
+            pw.println();
+
+            pw.print("Last screen ON : ");
+            TimeUtils.dumpTimeWithDelta(pw, now - nowRealtime + mLastScreenOnRealtime, now);
+            pw.println();
+
+            pw.print("Last screen OFF: ");
+            TimeUtils.dumpTimeWithDelta(pw, now - nowRealtime + mLastScreenOffRealtime, now);
+            pw.println();
+
+            pw.println();
+
+            pw.println("Current max jobs:");
+            pw.println("  ");
+            pw.println(mJobCountTracker);
+
+            pw.println();
+
+            pw.print("mLastMemoryTrimLevel: ");
+            pw.print(mLastMemoryTrimLevel);
+            pw.println();
+
+            mStatLogger.dump(pw);
+        } finally {
+            pw.decreaseIndent();
+        }
+    }
+
+    public void dumpProtoLocked(ProtoOutputStream proto) {
+        // TODO Implement it.
+    }
+
+    /**
+     * This class decides, taking into account {@link #mMaxJobCounts} and how many jos are running /
+     * pending, how many more job can start.
+     *
+     * Extracted for testing and logging.
+     */
+    @VisibleForTesting
+    static class JobCountTracker {
+        private int mConfigNumTotalMaxJobs;
+        private int mConfigNumMaxBgJobs;
+        private int mConfigNumMinBgJobs;
+
+        private int mNumRunningFgJobs;
+        private int mNumRunningBgJobs;
+
+        private int mNumPendingFgJobs;
+        private int mNumPendingBgJobs;
+
+        private int mNumStartingFgJobs;
+        private int mNumStartingBgJobs;
+
+        private int mNumReservedForBg;
+        private int mNumActualMaxFgJobs;
+        private int mNumActualMaxBgJobs;
+
+        void reset(int numTotalMaxJobs, int numMaxBgJobs, int numMinBgJobs) {
+            mConfigNumTotalMaxJobs = numTotalMaxJobs;
+            mConfigNumMaxBgJobs = numMaxBgJobs;
+            mConfigNumMinBgJobs = numMinBgJobs;
+
+            mNumRunningFgJobs = 0;
+            mNumRunningBgJobs = 0;
+
+            mNumPendingFgJobs = 0;
+            mNumPendingBgJobs = 0;
+
+            mNumStartingFgJobs = 0;
+            mNumStartingBgJobs = 0;
+
+            mNumReservedForBg = 0;
+            mNumActualMaxFgJobs = 0;
+            mNumActualMaxBgJobs = 0;
+        }
+
+        void incrementRunningJobCount(boolean isFg) {
+            if (isFg) {
+                mNumRunningFgJobs++;
+            } else {
+                mNumRunningBgJobs++;
+            }
+        }
+
+        void incrementPendingJobCount(boolean isFg) {
+            if (isFg) {
+                mNumPendingFgJobs++;
+            } else {
+                mNumPendingBgJobs++;
+            }
+        }
+
+        void onStartingNewJob(boolean isFg) {
+            if (isFg) {
+                mNumStartingFgJobs++;
+            } else {
+                mNumStartingBgJobs++;
+            }
+        }
+
+        void onCountDone() {
+            // Note some variables are used only here but are made class members in order to have
+            // them on logcat / dumpsys.
+
+            // How many slots should we allocate to BG jobs at least?
+            // That's basically "getMinBg()", but if there are less jobs, decrease it.
+            // (e.g. even if min-bg is 2, if there's only 1 running+pending job, this has to be 1.)
+            final int reservedForBg = Math.min(
+                    mConfigNumMinBgJobs,
+                    mNumRunningBgJobs + mNumPendingBgJobs);
+
+            // However, if there are FG jobs already running, we have to adjust it.
+            mNumReservedForBg = Math.min(reservedForBg,
+                    mConfigNumTotalMaxJobs - mNumRunningFgJobs);
+
+            // Max FG is [total - [number needed for BG jobs]]
+            // [number needed for BG jobs] is the bigger one of [running BG] or [reserved BG]
+            final int maxFg =
+                    mConfigNumTotalMaxJobs - Math.max(mNumRunningBgJobs, mNumReservedForBg);
+
+            // The above maxFg is the theoretical max. If there are less FG jobs, the actual
+            // max FG will be lower accordingly.
+            mNumActualMaxFgJobs = Math.min(
+                    maxFg,
+                    mNumRunningFgJobs + mNumPendingFgJobs);
+
+            // Max BG is [total - actual max FG], but cap at [config max BG].
+            final int maxBg = Math.min(
+                    mConfigNumMaxBgJobs,
+                    mConfigNumTotalMaxJobs - mNumActualMaxFgJobs);
+
+            // If there are less BG jobs than maxBg, then reduce the actual max BG accordingly.
+            // This isn't needed for the logic to work, but this will give consistent output
+            // on logcat and dumpsys.
+            mNumActualMaxBgJobs = Math.min(
+                    maxBg,
+                    mNumRunningBgJobs + mNumPendingBgJobs);
+        }
+
+        boolean canJobStart(boolean isFg) {
+            if (isFg) {
+                return mNumRunningFgJobs + mNumStartingFgJobs < mNumActualMaxFgJobs;
+            } else {
+                return mNumRunningBgJobs + mNumStartingBgJobs < mNumActualMaxBgJobs;
+            }
+        }
+
+        public int getNumStartingFgJobs() {
+            return mNumStartingFgJobs;
+        }
+
+        public int getNumStartingBgJobs() {
+            return mNumStartingBgJobs;
+        }
+
+        int getTotalRunningJobCountToNote() {
+            return mNumRunningFgJobs + mNumRunningBgJobs
+                    + mNumStartingFgJobs + mNumStartingBgJobs;
+        }
+
+        int getFgRunningJobCountToNote() {
+            return mNumRunningFgJobs + mNumStartingFgJobs;
+        }
+
+        void logStatus() {
+            if (DEBUG) {
+                Slog.d(TAG, "assignJobsToContexts: " + this);
+            }
+        }
+
+        public String toString() {
+            final int totalFg = mNumRunningFgJobs + mNumStartingFgJobs;
+            final int totalBg = mNumRunningBgJobs + mNumStartingBgJobs;
+            return String.format(
+                    "Config={tot=%d bg min/max=%d/%d}"
+                            + " Running: %d / %d (%d)"
+                            + " Pending: %d / %d (%d)"
+                            + " Actual max: %d%s / %d%s (%d%s)"
+                            + " Starting: %d / %d (%d)"
+                            + " Total: %d%s / %d%s (%d%s)",
+                    mConfigNumTotalMaxJobs,
+                    mConfigNumMinBgJobs,
+                    mConfigNumMaxBgJobs,
+
+                    mNumRunningFgJobs, mNumRunningBgJobs,
+                    mNumRunningFgJobs + mNumRunningBgJobs,
+
+                    mNumPendingFgJobs, mNumPendingBgJobs,
+                    mNumPendingFgJobs + mNumPendingBgJobs,
+
+                    mNumActualMaxFgJobs, (totalFg <= mConfigNumTotalMaxJobs) ? "" : "*",
+                    mNumActualMaxBgJobs, (totalBg <= mConfigNumMaxBgJobs) ? "" : "*",
+
+                    mNumActualMaxFgJobs + mNumActualMaxBgJobs,
+                    (mNumActualMaxFgJobs + mNumActualMaxBgJobs <= mConfigNumTotalMaxJobs)
+                            ? "" : "*",
+
+                    mNumStartingFgJobs, mNumStartingBgJobs, mNumStartingFgJobs + mNumStartingBgJobs,
+
+                    totalFg, (totalFg <= mNumActualMaxFgJobs) ? "" : "*",
+                    totalBg, (totalBg <= mNumActualMaxBgJobs) ? "" : "*",
+                    totalFg + totalBg, (totalFg + totalBg <= mConfigNumTotalMaxJobs) ? "" : "*"
+            );
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 3f9d928..bd12075 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -224,12 +224,6 @@
     volatile boolean mInParole;
 
     /**
-     * Current limit on the number of concurrent JobServiceContext entries we want to
-     * keep actively running a job.
-     */
-    int mMaxActiveJobs = 1;
-
-    /**
      * A mapping of which uids are currently in the foreground to their effective priority.
      */
     final SparseIntArray mUidPriorityOverride = new SparseIntArray();
@@ -332,6 +326,71 @@
         }
     }
 
+    static class MaxJobCounts {
+        private final KeyValueListParser.IntValue mTotal;
+        private final KeyValueListParser.IntValue mMaxBg;
+        private final KeyValueListParser.IntValue mMinBg;
+
+        MaxJobCounts(int totalDefault, String totalKey,
+                int maxBgDefault, String maxBgKey, int minBgDefault, String minBgKey) {
+            mTotal = new KeyValueListParser.IntValue(totalKey, totalDefault);
+            mMaxBg = new KeyValueListParser.IntValue(maxBgKey, maxBgDefault);
+            mMinBg = new KeyValueListParser.IntValue(minBgKey, minBgDefault);
+        }
+
+        public void parse(KeyValueListParser parser) {
+            mTotal.parse(parser);
+            mMaxBg.parse(parser);
+            mMinBg.parse(parser);
+
+            if (mTotal.getValue() < 1) {
+                mTotal.setValue(1);
+            } else if (mTotal.getValue() > MAX_JOB_CONTEXTS_COUNT) {
+                mTotal.setValue(MAX_JOB_CONTEXTS_COUNT);
+            }
+
+            if (mMaxBg.getValue() < 1) {
+                mMaxBg.setValue(1);
+            } else if (mMaxBg.getValue() > mTotal.getValue()) {
+                mMaxBg.setValue(mTotal.getValue());
+            }
+            if (mMinBg.getValue() < 0) {
+                mMinBg.setValue(0);
+            } else {
+                if (mMinBg.getValue() > mMaxBg.getValue()) {
+                    mMinBg.setValue(mMaxBg.getValue());
+                }
+                if (mMinBg.getValue() >= mTotal.getValue()) {
+                    mMinBg.setValue(mTotal.getValue() - 1);
+                }
+            }
+        }
+
+        public int getTotalMax() {
+            return mTotal.getValue();
+        }
+
+        public int getMaxBg() {
+            return mMaxBg.getValue();
+        }
+
+        public int getMinBg() {
+            return mMinBg.getValue();
+        }
+
+        public void dump(PrintWriter pw, String prefix) {
+            mTotal.dump(pw, prefix);
+            mMaxBg.dump(pw, prefix);
+            mMinBg.dump(pw, prefix);
+        }
+
+        public void dumpProto(ProtoOutputStream proto, long tagTotal, long tagBg) {
+            mTotal.dumpProto(proto, tagTotal);
+            mMaxBg.dumpProto(proto, tagBg);
+            mMinBg.dumpProto(proto, tagBg);
+        }
+    }
+
     /**
      * All times are in milliseconds. These constants are kept synchronized with the system
      * global Settings. Any access to this class or its fields should be done while
@@ -348,11 +407,14 @@
         private static final String KEY_MIN_READY_JOBS_COUNT = "min_ready_jobs_count";
         private static final String KEY_HEAVY_USE_FACTOR = "heavy_use_factor";
         private static final String KEY_MODERATE_USE_FACTOR = "moderate_use_factor";
-        private static final String KEY_FG_JOB_COUNT = "fg_job_count";
-        private static final String KEY_BG_NORMAL_JOB_COUNT = "bg_normal_job_count";
-        private static final String KEY_BG_MODERATE_JOB_COUNT = "bg_moderate_job_count";
-        private static final String KEY_BG_LOW_JOB_COUNT = "bg_low_job_count";
-        private static final String KEY_BG_CRITICAL_JOB_COUNT = "bg_critical_job_count";
+
+        // The following values used to be used on P and below. Do not reuse them.
+        private static final String DEPRECATED_KEY_FG_JOB_COUNT = "fg_job_count";
+        private static final String DEPRECATED_KEY_BG_NORMAL_JOB_COUNT = "bg_normal_job_count";
+        private static final String DEPRECATED_KEY_BG_MODERATE_JOB_COUNT = "bg_moderate_job_count";
+        private static final String DEPRECATED_KEY_BG_LOW_JOB_COUNT = "bg_low_job_count";
+        private static final String DEPRECATED_KEY_BG_CRITICAL_JOB_COUNT = "bg_critical_job_count";
+
         private static final String KEY_MAX_STANDARD_RESCHEDULE_COUNT
                 = "max_standard_reschedule_count";
         private static final String KEY_MAX_WORK_RESCHEDULE_COUNT = "max_work_reschedule_count";
@@ -381,6 +443,16 @@
                 "qc_window_size_rare_ms";
         private static final String KEY_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS =
                 "qc_max_execution_time_ms";
+        private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE =
+                "qc_max_job_count_active";
+        private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING =
+                "qc_max_job_count_working";
+        private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT =
+                "qc_max_job_count_frequent";
+        private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE =
+                "qc_max_job_count_rare";
+        private static final String KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME =
+                "qc_max_count_per_allowed_time";
 
         private static final int DEFAULT_MIN_IDLE_COUNT = 1;
         private static final int DEFAULT_MIN_CHARGING_COUNT = 1;
@@ -391,11 +463,6 @@
         private static final int DEFAULT_MIN_READY_JOBS_COUNT = 1;
         private static final float DEFAULT_HEAVY_USE_FACTOR = .9f;
         private static final float DEFAULT_MODERATE_USE_FACTOR = .5f;
-        private static final int DEFAULT_FG_JOB_COUNT = 4;
-        private static final int DEFAULT_BG_NORMAL_JOB_COUNT = 6;
-        private static final int DEFAULT_BG_MODERATE_JOB_COUNT = 4;
-        private static final int DEFAULT_BG_LOW_JOB_COUNT = 1;
-        private static final int DEFAULT_BG_CRITICAL_JOB_COUNT = 1;
         private static final int DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT = Integer.MAX_VALUE;
         private static final int DEFAULT_MAX_WORK_RESCHEDULE_COUNT = Integer.MAX_VALUE;
         private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
@@ -422,6 +489,15 @@
                 24 * 60 * 60 * 1000L; // 24 hours
         private static final long DEFAULT_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS =
                 4 * 60 * 60 * 1000L; // 4 hours
+        private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE =
+                200; // 1200/hr
+        private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING =
+                1200; // 600/hr
+        private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT =
+                1800; // 225/hr
+        private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE =
+                2400; // 100/hr
+        private static final int DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = 20;
 
         /**
          * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
@@ -468,30 +544,53 @@
          * This is the job execution factor that is considered to be moderate use of the system.
          */
         float MODERATE_USE_FACTOR = DEFAULT_MODERATE_USE_FACTOR;
-        /**
-         * The number of MAX_JOB_CONTEXTS_COUNT we reserve for the foreground app.
-         */
-        int FG_JOB_COUNT = DEFAULT_FG_JOB_COUNT;
-        /**
-         * The maximum number of background jobs we allow when the system is in a normal
-         * memory state.
-         */
-        int BG_NORMAL_JOB_COUNT = DEFAULT_BG_NORMAL_JOB_COUNT;
-        /**
-         * The maximum number of background jobs we allow when the system is in a moderate
-         * memory state.
-         */
-        int BG_MODERATE_JOB_COUNT = DEFAULT_BG_MODERATE_JOB_COUNT;
-        /**
-         * The maximum number of background jobs we allow when the system is in a low
-         * memory state.
-         */
-        int BG_LOW_JOB_COUNT = DEFAULT_BG_LOW_JOB_COUNT;
-        /**
-         * The maximum number of background jobs we allow when the system is in a critical
-         * memory state.
-         */
-        int BG_CRITICAL_JOB_COUNT = DEFAULT_BG_CRITICAL_JOB_COUNT;
+
+        // Max job counts for screen on / off, for each memory trim level.
+        final MaxJobCounts MAX_JOB_COUNTS_ON_NORMAL = new MaxJobCounts(
+                8, "max_job_total_on_normal",
+                6, "max_job_max_bg_on_normal",
+                2, "max_job_min_bg_on_normal");
+
+        final MaxJobCounts MAX_JOB_COUNTS_ON_MODERATE = new MaxJobCounts(
+                8, "max_job_total_on_moderate",
+                4, "max_job_max_bg_on_moderate",
+                2, "max_job_min_bg_on_moderate");
+
+        final MaxJobCounts MAX_JOB_COUNTS_ON_LOW = new MaxJobCounts(
+                5, "max_job_total_on_low",
+                1, "max_job_max_bg_on_low",
+                1, "max_job_min_bg_on_low");
+
+        final MaxJobCounts MAX_JOB_COUNTS_ON_CRITICAL = new MaxJobCounts(
+                5, "max_job_total_on_critical",
+                1, "max_job_max_bg_on_critical",
+                1, "max_job_min_bg_on_critical");
+
+        final MaxJobCounts MAX_JOB_COUNTS_OFF_NORMAL = new MaxJobCounts(
+                10, "max_job_total_off_normal",
+                6, "max_job_max_bg_off_normal",
+                2, "max_job_min_bg_off_normal");
+
+        final MaxJobCounts MAX_JOB_COUNTS_OFF_MODERATE = new MaxJobCounts(
+                10, "max_job_total_off_moderate",
+                4, "max_job_max_bg_off_moderate",
+                2, "max_job_min_bg_off_moderate");
+
+        final MaxJobCounts MAX_JOB_COUNTS_OFF_LOW = new MaxJobCounts(
+                5, "max_job_total_off_low",
+                1, "max_job_max_bg_off_low",
+                1, "max_job_min_bg_off_low");
+
+        final MaxJobCounts MAX_JOB_COUNTS_OFF_CRITICAL = new MaxJobCounts(
+                5, "max_job_total_off_critical",
+                1, "max_job_max_bg_off_critical",
+                1, "max_job_min_bg_off_critical");
+
+        /** Wait for this long after screen off before increasing the job concurrency. */
+        final KeyValueListParser.IntValue SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS =
+                new KeyValueListParser.IntValue(
+                        "screen_off_job_concurrency_increase_delay_ms", 30_000);
+
         /**
          * The maximum number of times we allow a job to have itself rescheduled before
          * giving up on it, for standard jobs.
@@ -566,7 +665,7 @@
 
         /**
          * The quota window size of the particular standby bucket. Apps in this standby bucket are
-         * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+         * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
          * WINDOW_SIZE_MS.
          */
         public long QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS =
@@ -574,7 +673,7 @@
 
         /**
          * The quota window size of the particular standby bucket. Apps in this standby bucket are
-         * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+         * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
          * WINDOW_SIZE_MS.
          */
         public long QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS =
@@ -582,7 +681,7 @@
 
         /**
          * The quota window size of the particular standby bucket. Apps in this standby bucket are
-         * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+         * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
          * WINDOW_SIZE_MS.
          */
         public long QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS =
@@ -590,7 +689,7 @@
 
         /**
          * The quota window size of the particular standby bucket. Apps in this standby bucket are
-         * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+         * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
          * WINDOW_SIZE_MS.
          */
         public long QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS =
@@ -602,6 +701,41 @@
         public long QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS =
                 DEFAULT_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS;
 
+        /**
+         * The maximum number of jobs an app can run within this particular standby bucket's
+         * window size.
+         */
+        public int QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE =
+                DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE;
+
+        /**
+         * The maximum number of jobs an app can run within this particular standby bucket's
+         * window size.
+         */
+        public int QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING =
+                DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING;
+
+        /**
+         * The maximum number of jobs an app can run within this particular standby bucket's
+         * window size.
+         */
+        public int QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT =
+                DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT;
+
+        /**
+         * The maximum number of jobs an app can run within this particular standby bucket's
+         * window size.
+         */
+        public int QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE =
+                DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE;
+
+        /**
+         * The maximum number of jobs that can run within the past
+         * {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS}.
+         */
+        public int QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME =
+                DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME;
+
         private final KeyValueListParser mParser = new KeyValueListParser(',');
 
         void updateConstantsLocked(String value) {
@@ -631,28 +765,17 @@
                     DEFAULT_HEAVY_USE_FACTOR);
             MODERATE_USE_FACTOR = mParser.getFloat(KEY_MODERATE_USE_FACTOR,
                     DEFAULT_MODERATE_USE_FACTOR);
-            FG_JOB_COUNT = mParser.getInt(KEY_FG_JOB_COUNT,
-                    DEFAULT_FG_JOB_COUNT);
-            BG_NORMAL_JOB_COUNT = mParser.getInt(KEY_BG_NORMAL_JOB_COUNT,
-                    DEFAULT_BG_NORMAL_JOB_COUNT);
-            if ((FG_JOB_COUNT+BG_NORMAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
-                BG_NORMAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
-            }
-            BG_MODERATE_JOB_COUNT = mParser.getInt(KEY_BG_MODERATE_JOB_COUNT,
-                    DEFAULT_BG_MODERATE_JOB_COUNT);
-            if ((FG_JOB_COUNT+BG_MODERATE_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
-                BG_MODERATE_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
-            }
-            BG_LOW_JOB_COUNT = mParser.getInt(KEY_BG_LOW_JOB_COUNT,
-                    DEFAULT_BG_LOW_JOB_COUNT);
-            if ((FG_JOB_COUNT+BG_LOW_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
-                BG_LOW_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
-            }
-            BG_CRITICAL_JOB_COUNT = mParser.getInt(KEY_BG_CRITICAL_JOB_COUNT,
-                    DEFAULT_BG_CRITICAL_JOB_COUNT);
-            if ((FG_JOB_COUNT+BG_CRITICAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
-                BG_CRITICAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
-            }
+
+            MAX_JOB_COUNTS_ON_NORMAL.parse(mParser);
+            MAX_JOB_COUNTS_ON_MODERATE.parse(mParser);
+            MAX_JOB_COUNTS_ON_LOW.parse(mParser);
+            MAX_JOB_COUNTS_ON_CRITICAL.parse(mParser);
+
+            MAX_JOB_COUNTS_OFF_NORMAL.parse(mParser);
+            MAX_JOB_COUNTS_OFF_MODERATE.parse(mParser);
+            MAX_JOB_COUNTS_OFF_LOW.parse(mParser);
+            MAX_JOB_COUNTS_OFF_CRITICAL.parse(mParser);
+
             MAX_STANDARD_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_STANDARD_RESCHEDULE_COUNT,
                     DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT);
             MAX_WORK_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_WORK_RESCHEDULE_COUNT,
@@ -698,6 +821,21 @@
             QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = mParser.getDurationMillis(
                     KEY_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS,
                     DEFAULT_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS);
+            QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = mParser.getInt(
+                    KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE,
+                    DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE);
+            QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = mParser.getInt(
+                    KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING,
+                    DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING);
+            QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = mParser.getInt(
+                    KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT,
+                    DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT);
+            QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = mParser.getInt(
+                    KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE,
+                    DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE);
+            QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = mParser.getInt(
+                    KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME,
+                    DEFAULT_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME);
         }
 
         void dump(IndentingPrintWriter pw) {
@@ -712,11 +850,17 @@
             pw.printPair(KEY_MIN_READY_JOBS_COUNT, MIN_READY_JOBS_COUNT).println();
             pw.printPair(KEY_HEAVY_USE_FACTOR, HEAVY_USE_FACTOR).println();
             pw.printPair(KEY_MODERATE_USE_FACTOR, MODERATE_USE_FACTOR).println();
-            pw.printPair(KEY_FG_JOB_COUNT, FG_JOB_COUNT).println();
-            pw.printPair(KEY_BG_NORMAL_JOB_COUNT, BG_NORMAL_JOB_COUNT).println();
-            pw.printPair(KEY_BG_MODERATE_JOB_COUNT, BG_MODERATE_JOB_COUNT).println();
-            pw.printPair(KEY_BG_LOW_JOB_COUNT, BG_LOW_JOB_COUNT).println();
-            pw.printPair(KEY_BG_CRITICAL_JOB_COUNT, BG_CRITICAL_JOB_COUNT).println();
+
+            MAX_JOB_COUNTS_ON_NORMAL.dump(pw, "");
+            MAX_JOB_COUNTS_ON_MODERATE.dump(pw, "");
+            MAX_JOB_COUNTS_ON_LOW.dump(pw, "");
+            MAX_JOB_COUNTS_ON_CRITICAL.dump(pw, "");
+
+            MAX_JOB_COUNTS_OFF_NORMAL.dump(pw, "");
+            MAX_JOB_COUNTS_OFF_MODERATE.dump(pw, "");
+            MAX_JOB_COUNTS_OFF_LOW.dump(pw, "");
+            MAX_JOB_COUNTS_OFF_CRITICAL.dump(pw, "");
+
             pw.printPair(KEY_MAX_STANDARD_RESCHEDULE_COUNT, MAX_STANDARD_RESCHEDULE_COUNT).println();
             pw.printPair(KEY_MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT).println();
             pw.printPair(KEY_MIN_LINEAR_BACKOFF_TIME, MIN_LINEAR_BACKOFF_TIME).println();
@@ -748,6 +892,16 @@
                     QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS).println();
             pw.printPair(KEY_QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS,
                     QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS).println();
+            pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE,
+                    QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE).println();
+            pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING,
+                    QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING).println();
+            pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT,
+                    QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT).println();
+            pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE,
+                    QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE).println();
+            pw.printPair(KEY_QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME,
+                    QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME).println();
             pw.decreaseIndent();
         }
 
@@ -762,11 +916,9 @@
             proto.write(ConstantsProto.MIN_READY_JOBS_COUNT, MIN_READY_JOBS_COUNT);
             proto.write(ConstantsProto.HEAVY_USE_FACTOR, HEAVY_USE_FACTOR);
             proto.write(ConstantsProto.MODERATE_USE_FACTOR, MODERATE_USE_FACTOR);
-            proto.write(ConstantsProto.FG_JOB_COUNT, FG_JOB_COUNT);
-            proto.write(ConstantsProto.BG_NORMAL_JOB_COUNT, BG_NORMAL_JOB_COUNT);
-            proto.write(ConstantsProto.BG_MODERATE_JOB_COUNT, BG_MODERATE_JOB_COUNT);
-            proto.write(ConstantsProto.BG_LOW_JOB_COUNT, BG_LOW_JOB_COUNT);
-            proto.write(ConstantsProto.BG_CRITICAL_JOB_COUNT, BG_CRITICAL_JOB_COUNT);
+
+            // TODO Dump max job counts.
+
             proto.write(ConstantsProto.MAX_STANDARD_RESCHEDULE_COUNT, MAX_STANDARD_RESCHEDULE_COUNT);
             proto.write(ConstantsProto.MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT);
             proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME);
@@ -799,6 +951,16 @@
                     QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS);
             proto.write(ConstantsProto.QuotaController.MAX_EXECUTION_TIME_MS,
                     QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS);
+            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_ACTIVE,
+                    QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE);
+            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_WORKING,
+                    QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING);
+            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_FREQUENT,
+                    QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT);
+            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_RARE,
+                    QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE);
+            proto.write(ConstantsProto.QuotaController.MAX_JOB_COUNT_PER_ALLOWED_TIME,
+                    QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME);
             proto.end(qcToken);
 
             proto.end(token);
@@ -1458,6 +1620,9 @@
             } catch (RemoteException e) {
                 // ignored; both services live in system_server
             }
+
+            mConcurrencyManager.onSystemReady();
+
             // Remove any jobs that are not associated with any of the current users.
             cancelJobsForNonExistentUsers();
             // Register thermal callback
@@ -1585,7 +1750,7 @@
      * Reschedules the given job based on the job's backoff policy. It doesn't make sense to
      * specify an override deadline on a failed job (the failed job will run even though it's not
      * ready), so we reschedule it with {@link JobStatus#NO_LATEST_RUNTIME}, but specify that any
-     * ready job with {@link JobStatus#numFailures} > 0 will be executed.
+     * ready job with {@link JobStatus#getNumFailures()} > 0 will be executed.
      *
      * @param failureToReschedule Provided job status that we will reschedule.
      * @return A newly instantiated JobStatus with the same constraints as the last job except
@@ -2367,7 +2532,7 @@
      * A controller can force a job into the pending queue even if it's already running, but
      * here is where we decide whether to actually execute it.
      */
-    private void maybeRunPendingJobsLocked() {
+    void maybeRunPendingJobsLocked() {
         if (DEBUG) {
             Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");
         }
@@ -3380,9 +3545,12 @@
                 pw.println();
                 pw.print("mReadyToRock="); pw.println(mReadyToRock);
                 pw.print("mReportedActive="); pw.println(mReportedActive);
-                pw.print("mMaxActiveJobs="); pw.println(mMaxActiveJobs);
             }
             pw.println();
+
+            mConcurrencyManager.dumpLocked(pw);
+
+            pw.println();
             pw.print("PersistStats: ");
             pw.println(mJobs.getPersistStats());
         }
@@ -3534,8 +3702,8 @@
             if (filterUid == -1) {
                 proto.write(JobSchedulerServiceDumpProto.IS_READY_TO_ROCK, mReadyToRock);
                 proto.write(JobSchedulerServiceDumpProto.REPORTED_ACTIVE, mReportedActive);
-                proto.write(JobSchedulerServiceDumpProto.MAX_ACTIVE_JOBS, mMaxActiveJobs);
             }
+            mConcurrencyManager.dumpProtoLocked(proto);
         }
 
         proto.flush();
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java
index ac2dbdf..5a0b991 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/services/core/java/com/android/server/job/controllers/QuotaController.java
@@ -26,7 +26,10 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
+import android.app.IUidObserver;
 import android.app.usage.UsageStatsManagerInternal;
 import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
 import android.content.BroadcastReceiver;
@@ -38,12 +41,14 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -69,6 +74,11 @@
  * bucket, it will be eligible to run. When a job's bucket changes, its new quota is immediately
  * applied to it.
  *
+ * Jobs are throttled while an app is not in a foreground state. All jobs are allowed to run
+ * freely when an app enters the foreground state and are restricted when the app leaves the
+ * foreground state. However, jobs that are started while the app is in the TOP state are not
+ * restricted regardless of the app's state change.
+ *
  * Test: atest com.android.server.job.controllers.QuotaControllerTest
  */
 public final class QuotaController extends StateController {
@@ -97,6 +107,12 @@
             data.put(packageName, obj);
         }
 
+        public void clear() {
+            for (int i = 0; i < mData.size(); ++i) {
+                mData.valueAt(i).clear();
+            }
+        }
+
         /** Removes all the data for the user, if there was any. */
         public void delete(int userId) {
             mData.delete(userId);
@@ -119,6 +135,11 @@
             return null;
         }
 
+        /** @see SparseArray#indexOfKey */
+        public int indexOfKey(int userId) {
+            return mData.indexOfKey(userId);
+        }
+
         /** Returns the userId at the given index. */
         public int keyAt(int index) {
             return mData.keyAt(index);
@@ -209,10 +230,10 @@
     @VisibleForTesting
     static class ExecutionStats {
         /**
-         * The time at which this record should be considered invalid, in the elapsed realtime
-         * timebase.
+         * The time after which this record should be considered invalid (out of date), in the
+         * elapsed realtime timebase.
          */
-        public long invalidTimeElapsed;
+        public long expirationTimeElapsed;
 
         public long windowSizeMs;
 
@@ -220,29 +241,45 @@
         public long executionTimeInWindowMs;
         public int bgJobCountInWindow;
 
-        /** The total amount of time the app ran in the last {@link MAX_PERIOD_MS}. */
+        /** The total amount of time the app ran in the last {@link #MAX_PERIOD_MS}. */
         public long executionTimeInMaxPeriodMs;
         public int bgJobCountInMaxPeriod;
 
         /**
-         * The time after which the sum of all the app's sessions plus {@link mQuotaBufferMs} equals
-         * the quota. This is only valid if
-         * executionTimeInWindowMs >= {@link mAllowedTimePerPeriodMs} or
-         * executionTimeInMaxPeriodMs >= {@link mMaxExecutionTimeMs}.
+         * The time after which the sum of all the app's sessions plus {@link #mQuotaBufferMs}
+         * equals the quota. This is only valid if
+         * executionTimeInWindowMs >= {@link #mAllowedTimePerPeriodMs} or
+         * executionTimeInMaxPeriodMs >= {@link #mMaxExecutionTimeMs}.
          */
         public long quotaCutoffTimeElapsed;
 
+        /**
+         * The time after which {@link #jobCountInAllowedTime} should be considered invalid, in the
+         * elapsed realtime timebase.
+         */
+        public long jobCountExpirationTimeElapsed;
+
+        /**
+         * The number of jobs that ran in at least the last {@link #mAllowedTimePerPeriodMs}.
+         * It may contain a few stale entries since cleanup won't happen exactly every
+         * {@link #mAllowedTimePerPeriodMs}.
+         */
+        public int jobCountInAllowedTime;
+
         @Override
         public String toString() {
             return new StringBuilder()
-                    .append("invalidTime=").append(invalidTimeElapsed).append(", ")
+                    .append("expirationTime=").append(expirationTimeElapsed).append(", ")
                     .append("windowSize=").append(windowSizeMs).append(", ")
                     .append("executionTimeInWindow=").append(executionTimeInWindowMs).append(", ")
                     .append("bgJobCountInWindow=").append(bgJobCountInWindow).append(", ")
                     .append("executionTimeInMaxPeriod=").append(executionTimeInMaxPeriodMs)
                     .append(", ")
                     .append("bgJobCountInMaxPeriod=").append(bgJobCountInMaxPeriod).append(", ")
-                    .append("quotaCutoffTime=").append(quotaCutoffTimeElapsed)
+                    .append("quotaCutoffTime=").append(quotaCutoffTimeElapsed).append(", ")
+                    .append("jobCountExpirationTime").append(jobCountExpirationTimeElapsed)
+                    .append(", ")
+                    .append("jobCountInAllowedTime").append(jobCountInAllowedTime)
                     .toString();
         }
 
@@ -250,13 +287,15 @@
         public boolean equals(Object obj) {
             if (obj instanceof ExecutionStats) {
                 ExecutionStats other = (ExecutionStats) obj;
-                return this.invalidTimeElapsed == other.invalidTimeElapsed
+                return this.expirationTimeElapsed == other.expirationTimeElapsed
                         && this.windowSizeMs == other.windowSizeMs
                         && this.executionTimeInWindowMs == other.executionTimeInWindowMs
                         && this.bgJobCountInWindow == other.bgJobCountInWindow
                         && this.executionTimeInMaxPeriodMs == other.executionTimeInMaxPeriodMs
                         && this.bgJobCountInMaxPeriod == other.bgJobCountInMaxPeriod
-                        && this.quotaCutoffTimeElapsed == other.quotaCutoffTimeElapsed;
+                        && this.quotaCutoffTimeElapsed == other.quotaCutoffTimeElapsed
+                        && this.jobCountExpirationTimeElapsed == other.jobCountExpirationTimeElapsed
+                        && this.jobCountInAllowedTime == other.jobCountInAllowedTime;
             } else {
                 return false;
             }
@@ -265,13 +304,15 @@
         @Override
         public int hashCode() {
             int result = 0;
-            result = 31 * result + hashLong(invalidTimeElapsed);
+            result = 31 * result + hashLong(expirationTimeElapsed);
             result = 31 * result + hashLong(windowSizeMs);
             result = 31 * result + hashLong(executionTimeInWindowMs);
             result = 31 * result + bgJobCountInWindow;
             result = 31 * result + hashLong(executionTimeInMaxPeriodMs);
             result = 31 * result + bgJobCountInMaxPeriod;
             result = 31 * result + hashLong(quotaCutoffTimeElapsed);
+            result = 31 * result + hashLong(jobCountExpirationTimeElapsed);
+            result = 31 * result + jobCountInAllowedTime;
             return result;
         }
     }
@@ -294,6 +335,17 @@
     /** Cached calculation results for each app, with the standby buckets as the array indices. */
     private final UserPackageMap<ExecutionStats[]> mExecutionStatsCache = new UserPackageMap<>();
 
+    /** List of UIDs currently in the foreground. */
+    private final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
+
+    /**
+     * List of jobs that started while the UID was in the TOP state. There will be no more than
+     * 16 ({@link JobSchedulerService#MAX_JOB_CONTEXTS_COUNT}) running at once, so an ArraySet is
+     * fine.
+     */
+    private final ArraySet<JobStatus> mTopStartedJobs = new ArraySet<>();
+
+    private final ActivityManagerInternal mActivityManagerInternal;
     private final AlarmManager mAlarmManager;
     private final ChargingTracker mChargeTracker;
     private final Handler mHandler;
@@ -311,7 +363,7 @@
     private long mAllowedTimePerPeriodMs = 10 * MINUTE_IN_MILLIS;
 
     /**
-     * The maximum amount of time an app can have its jobs running within a {@link MAX_PERIOD_MS}
+     * The maximum amount of time an app can have its jobs running within a {@link #MAX_PERIOD_MS}
      * window.
      */
     private long mMaxExecutionTimeMs = 4 * 60 * MINUTE_IN_MILLIS;
@@ -323,17 +375,20 @@
     private long mQuotaBufferMs = 30 * 1000L; // 30 seconds
 
     /**
-     * {@link mAllowedTimePerPeriodMs} - {@link mQuotaBufferMs}. This can be used to determine when
-     * an app will have enough quota to transition from out-of-quota to in-quota.
+     * {@link #mAllowedTimePerPeriodMs} - {@link #mQuotaBufferMs}. This can be used to determine
+     * when an app will have enough quota to transition from out-of-quota to in-quota.
      */
     private long mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs;
 
     /**
-     * {@link mMaxExecutionTimeMs} - {@link mQuotaBufferMs}. This can be used to determine when an
+     * {@link #mMaxExecutionTimeMs} - {@link #mQuotaBufferMs}. This can be used to determine when an
      * app will have enough quota to transition from out-of-quota to in-quota.
      */
     private long mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs;
 
+    /** The maximum number of jobs that can run within the past {@link #mAllowedTimePerPeriodMs}. */
+    private int mMaxJobCountPerAllowedTime = 20;
+
     private long mNextCleanupTimeElapsed = 0;
     private final AlarmManager.OnAlarmListener mSessionCleanupAlarmListener =
             new AlarmManager.OnAlarmListener() {
@@ -343,6 +398,29 @@
                 }
             };
 
+    private final IUidObserver mUidObserver = new IUidObserver.Stub() {
+        @Override
+        public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+            mHandler.obtainMessage(MSG_UID_PROCESS_STATE_CHANGED, uid, procState).sendToTarget();
+        }
+
+        @Override
+        public void onUidGone(int uid, boolean disabled) {
+        }
+
+        @Override
+        public void onUidActive(int uid) {
+        }
+
+        @Override
+        public void onUidIdle(int uid, boolean disabled) {
+        }
+
+        @Override
+        public void onUidCachedChanged(int uid, boolean cached) {
+        }
+    };
+
     /**
      * The rolling window size for each standby bucket. Within each window, an app will have 10
      * minutes to run its jobs.
@@ -357,18 +435,38 @@
     /** The maximum period any bucket can have. */
     private static final long MAX_PERIOD_MS = 24 * 60 * MINUTE_IN_MILLIS;
 
+    /**
+     * The maximum number of jobs based on its standby bucket. For each max value count in the
+     * array, the app will not be allowed to run more than that many number of jobs within the
+     * latest time interval of its rolling window size.
+     *
+     * @see #mBucketPeriodsMs
+     */
+    private final int[] mMaxBucketJobCounts = new int[] {
+            200,  // ACTIVE   -- 1200/hr
+            1200, // WORKING  -- 600/hr
+            1800, // FREQUENT -- 225/hr
+            2400  // RARE     -- 100/hr
+    };
+
+    /** The minimum number of jobs that any bucket will be allowed to run. */
+    private static final int MIN_BUCKET_JOB_COUNT = 100;
+
     /** An app has reached its quota. The message should contain a {@link Package} object. */
     private static final int MSG_REACHED_QUOTA = 0;
     /** Drop any old timing sessions. */
     private static final int MSG_CLEAN_UP_SESSIONS = 1;
     /** Check if a package is now within its quota. */
     private static final int MSG_CHECK_PACKAGE = 2;
+    /** Process state for a UID has changed. */
+    private static final int MSG_UID_PROCESS_STATE_CHANGED = 3;
 
     public QuotaController(JobSchedulerService service) {
         super(service);
         mHandler = new QcHandler(mContext.getMainLooper());
         mChargeTracker = new ChargingTracker();
         mChargeTracker.startTracking();
+        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
 
         // Set up the app standby bucketing tracker
@@ -376,6 +474,14 @@
                 UsageStatsManagerInternal.class);
         usageStats.addAppIdleStateChangeListener(new StandbyTracker());
 
+        try {
+            ActivityManager.getService().registerUidObserver(mUidObserver,
+                    ActivityManager.UID_OBSERVER_PROCSTATE,
+                    ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, null);
+        } catch (RemoteException e) {
+            // ignored; both services live in system_server
+        }
+
         onConstantsUpdatedLocked();
     }
 
@@ -397,11 +503,19 @@
     @Override
     public void prepareForExecutionLocked(JobStatus jobStatus) {
         if (DEBUG) Slog.d(TAG, "Prepping for " + jobStatus.toShortString());
+
+        final int uid = jobStatus.getSourceUid();
+        if (mActivityManagerInternal.getUidProcessState(uid) <= ActivityManager.PROCESS_STATE_TOP) {
+            mTopStartedJobs.add(jobStatus);
+            // Top jobs won't count towards quota so there's no need to involve the Timer.
+            return;
+        }
+
         final int userId = jobStatus.getSourceUserId();
         final String packageName = jobStatus.getSourcePackageName();
         Timer timer = mPkgTimers.get(userId, packageName);
         if (timer == null) {
-            timer = new Timer(userId, packageName);
+            timer = new Timer(uid, userId, packageName);
             mPkgTimers.add(userId, packageName, timer);
         }
         timer.startTrackingJob(jobStatus);
@@ -421,6 +535,7 @@
             if (jobs != null) {
                 jobs.remove(jobStatus);
             }
+            mTopStartedJobs.remove(jobStatus);
         }
     }
 
@@ -477,6 +592,36 @@
             mMaxExecutionTimeIntoQuotaMs = mMaxExecutionTimeMs - mQuotaBufferMs;
             changed = true;
         }
+        int newMaxCountPerAllowedPeriod = Math.max(10,
+                mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME);
+        if (mMaxJobCountPerAllowedTime != newMaxCountPerAllowedPeriod) {
+            mMaxJobCountPerAllowedTime = newMaxCountPerAllowedPeriod;
+            changed = true;
+        }
+        int newActiveMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
+                Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE));
+        if (mMaxBucketJobCounts[ACTIVE_INDEX] != newActiveMaxJobCount) {
+            mMaxBucketJobCounts[ACTIVE_INDEX] = newActiveMaxJobCount;
+            changed = true;
+        }
+        int newWorkingMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
+                Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING));
+        if (mMaxBucketJobCounts[WORKING_INDEX] != newWorkingMaxJobCount) {
+            mMaxBucketJobCounts[WORKING_INDEX] = newWorkingMaxJobCount;
+            changed = true;
+        }
+        int newFrequentMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
+                Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT));
+        if (mMaxBucketJobCounts[FREQUENT_INDEX] != newFrequentMaxJobCount) {
+            mMaxBucketJobCounts[FREQUENT_INDEX] = newFrequentMaxJobCount;
+            changed = true;
+        }
+        int newRareMaxJobCount = Math.max(mMaxJobCountPerAllowedTime,
+                Math.max(MIN_BUCKET_JOB_COUNT, mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE));
+        if (mMaxBucketJobCounts[RARE_INDEX] != newRareMaxJobCount) {
+            mMaxBucketJobCounts[RARE_INDEX] = newRareMaxJobCount;
+            changed = true;
+        }
 
         if (changed) {
             // Update job bookkeeping out of band.
@@ -511,6 +656,7 @@
             mInQuotaAlarmListeners.delete(userId, packageName);
         }
         mExecutionStatsCache.delete(userId, packageName);
+        mForegroundUids.delete(uid);
     }
 
     @Override
@@ -522,6 +668,20 @@
         mExecutionStatsCache.delete(userId);
     }
 
+    private boolean isUidInForeground(int uid) {
+        if (UserHandle.isCore(uid)) {
+            return true;
+        }
+        synchronized (mLock) {
+            return mForegroundUids.get(uid);
+        }
+    }
+
+    /** @return true if the job was started while the app was in the TOP state. */
+    private boolean isTopStartedJob(@NonNull final JobStatus jobStatus) {
+        return mTopStartedJobs.contains(jobStatus);
+    }
+
     /**
      * Returns an appropriate standby bucket for the job, taking into account any standby
      * exemptions.
@@ -537,20 +697,47 @@
 
     private boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {
         final int standbyBucket = getEffectiveStandbyBucket(jobStatus);
-        // Jobs for the active app should always be able to run.
-        return jobStatus.uidActive || isWithinQuotaLocked(
+        Timer timer = mPkgTimers.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
+        // A job is within quota if one of the following is true:
+        //   1. it was started while the app was in the TOP state
+        //   2. the app is currently in the foreground
+        //   3. the app overall is within its quota
+        return isTopStartedJob(jobStatus)
+                || isUidInForeground(jobStatus.getSourceUid())
+                || isWithinQuotaLocked(
                 jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket);
     }
 
-    private boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName,
+    @VisibleForTesting
+    boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName,
             final int standbyBucket) {
         if (standbyBucket == NEVER_INDEX) return false;
         // This check is needed in case the flag is toggled after a job has been registered.
         if (!mShouldThrottle) return true;
 
         // Quota constraint is not enforced while charging or when parole is on.
-        return mChargeTracker.isCharging() || mInParole
-                || getRemainingExecutionTimeLocked(userId, packageName, standbyBucket) > 0;
+        if (mChargeTracker.isCharging() || mInParole) {
+            return true;
+        }
+
+        return getRemainingExecutionTimeLocked(userId, packageName, standbyBucket) > 0
+                && isUnderJobCountQuotaLocked(userId, packageName, standbyBucket);
+    }
+
+    private boolean isUnderJobCountQuotaLocked(final int userId, @NonNull final String packageName,
+            final int standbyBucket) {
+        ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket, false);
+        return isUnderJobCountQuotaLocked(stats, standbyBucket);
+    }
+
+    private boolean isUnderJobCountQuotaLocked(@NonNull ExecutionStats stats,
+            final int standbyBucket) {
+        final long now = sElapsedRealtimeClock.millis();
+        final boolean isUnderAllowedTimeQuota =
+                (stats.jobCountExpirationTimeElapsed <= now
+                        || stats.jobCountInAllowedTime < mMaxJobCountPerAllowedTime);
+        return isUnderAllowedTimeQuota
+                && (stats.bgJobCountInWindow < mMaxBucketJobCounts[standbyBucket]);
     }
 
     @VisibleForTesting
@@ -587,6 +774,13 @@
     @NonNull
     ExecutionStats getExecutionStatsLocked(final int userId, @NonNull final String packageName,
             final int standbyBucket) {
+        return getExecutionStatsLocked(userId, packageName, standbyBucket, true);
+    }
+
+    @NonNull
+    private ExecutionStats getExecutionStatsLocked(final int userId,
+            @NonNull final String packageName, final int standbyBucket,
+            final boolean refreshStatsIfOld) {
         if (standbyBucket == NEVER_INDEX) {
             Slog.wtf(TAG, "getExecutionStatsLocked called for a NEVER app.");
             return new ExecutionStats();
@@ -601,14 +795,16 @@
             stats = new ExecutionStats();
             appStats[standbyBucket] = stats;
         }
-        final long bucketWindowSizeMs = mBucketPeriodsMs[standbyBucket];
-        Timer timer = mPkgTimers.get(userId, packageName);
-        if ((timer != null && timer.isActive())
-                || stats.invalidTimeElapsed <= sElapsedRealtimeClock.millis()
-                || stats.windowSizeMs != bucketWindowSizeMs) {
-            // The stats are no longer valid.
-            stats.windowSizeMs = bucketWindowSizeMs;
-            updateExecutionStatsLocked(userId, packageName, stats);
+        if (refreshStatsIfOld) {
+            final long bucketWindowSizeMs = mBucketPeriodsMs[standbyBucket];
+            Timer timer = mPkgTimers.get(userId, packageName);
+            if ((timer != null && timer.isActive())
+                    || stats.expirationTimeElapsed <= sElapsedRealtimeClock.millis()
+                    || stats.windowSizeMs != bucketWindowSizeMs) {
+                // The stats are no longer valid.
+                stats.windowSizeMs = bucketWindowSizeMs;
+                updateExecutionStatsLocked(userId, packageName, stats);
+            }
         }
 
         return stats;
@@ -625,14 +821,14 @@
 
         Timer timer = mPkgTimers.get(userId, packageName);
         final long nowElapsed = sElapsedRealtimeClock.millis();
-        stats.invalidTimeElapsed = nowElapsed + MAX_PERIOD_MS;
+        stats.expirationTimeElapsed = nowElapsed + MAX_PERIOD_MS;
         if (timer != null && timer.isActive()) {
             stats.executionTimeInWindowMs =
                     stats.executionTimeInMaxPeriodMs = timer.getCurrentDuration(nowElapsed);
             stats.bgJobCountInWindow = stats.bgJobCountInMaxPeriod = timer.getBgJobCount();
             // If the timer is active, the value will be stale at the next method call, so
             // invalidate now.
-            stats.invalidTimeElapsed = nowElapsed;
+            stats.expirationTimeElapsed = nowElapsed;
             if (stats.executionTimeInWindowMs >= mAllowedTimeIntoQuotaMs) {
                 stats.quotaCutoffTimeElapsed = Math.max(stats.quotaCutoffTimeElapsed,
                         nowElapsed - mAllowedTimeIntoQuotaMs);
@@ -708,7 +904,7 @@
                 break;
             }
         }
-        stats.invalidTimeElapsed = nowElapsed + emptyTimeMs;
+        stats.expirationTimeElapsed = nowElapsed + emptyTimeMs;
     }
 
     private void invalidateAllExecutionStatsLocked(final int userId,
@@ -719,13 +915,35 @@
             for (int i = 0; i < appStats.length; ++i) {
                 ExecutionStats stats = appStats[i];
                 if (stats != null) {
-                    stats.invalidTimeElapsed = nowElapsed;
+                    stats.expirationTimeElapsed = nowElapsed;
                 }
             }
         }
     }
 
     @VisibleForTesting
+    void incrementJobCount(final int userId, @NonNull final String packageName, int count) {
+        final long now = sElapsedRealtimeClock.millis();
+        ExecutionStats[] appStats = mExecutionStatsCache.get(userId, packageName);
+        if (appStats == null) {
+            appStats = new ExecutionStats[mBucketPeriodsMs.length];
+            mExecutionStatsCache.add(userId, packageName, appStats);
+        }
+        for (int i = 0; i < appStats.length; ++i) {
+            ExecutionStats stats = appStats[i];
+            if (stats == null) {
+                stats = new ExecutionStats();
+                appStats[i] = stats;
+            }
+            if (stats.jobCountExpirationTimeElapsed <= now) {
+                stats.jobCountExpirationTimeElapsed = now + mAllowedTimePerPeriodMs;
+                stats.jobCountInAllowedTime = 0;
+            }
+            stats.jobCountInAllowedTime += count;
+        }
+    }
+
+    @VisibleForTesting
     void saveTimingSession(final int userId, @NonNull final String packageName,
             @NonNull final TimingSession session) {
         synchronized (mLock) {
@@ -800,7 +1018,7 @@
         final boolean isCharging = mChargeTracker.isCharging();
         if (DEBUG) Slog.d(TAG, "handleNewChargingStateLocked: " + isCharging);
         // Deal with Timers first.
-        mPkgTimers.forEach((t) -> t.onChargingChanged(nowElapsed, isCharging));
+        mPkgTimers.forEach((t) -> t.onStateChanged(nowElapsed, isCharging));
         // Now update jobs.
         maybeUpdateAllConstraintsLocked();
     }
@@ -837,10 +1055,15 @@
         boolean changed = false;
         for (int i = jobs.size() - 1; i >= 0; --i) {
             final JobStatus js = jobs.valueAt(i);
-            if (js.uidActive) {
-                // Jobs for the active app should always be able to run.
+            if (isTopStartedJob(js)) {
+                // Job was started while the app was in the TOP state so we should allow it to
+                // finish.
                 changed |= js.setQuotaConstraintSatisfied(true);
-            } else if (realStandbyBucket == getEffectiveStandbyBucket(js)) {
+            } else if (realStandbyBucket != ACTIVE_INDEX
+                    && realStandbyBucket == getEffectiveStandbyBucket(js)) {
+                // An app in the ACTIVE bucket may be out of quota while the job could be in quota
+                // for some reason. Therefore, avoid setting the real value here and check each job
+                // individually.
                 changed |= js.setQuotaConstraintSatisfied(realInQuota);
             } else {
                 // This job is somehow exempted. Need to determine its own quota status.
@@ -854,7 +1077,7 @@
             maybeScheduleStartAlarmLocked(userId, packageName, realStandbyBucket);
         } else {
             QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName);
-            if (alarmListener != null) {
+            if (alarmListener != null && alarmListener.isWaiting()) {
                 mAlarmManager.cancel(alarmListener);
                 // Set the trigger time to 0 so that the alarm doesn't think it's still waiting.
                 alarmListener.setTriggerTime(0);
@@ -863,6 +1086,56 @@
         return changed;
     }
 
+    private class UidConstraintUpdater implements Consumer<JobStatus> {
+        private final UserPackageMap<Integer> mToScheduleStartAlarms = new UserPackageMap<>();
+        public boolean wasJobChanged;
+
+        @Override
+        public void accept(JobStatus jobStatus) {
+            wasJobChanged |= jobStatus.setQuotaConstraintSatisfied(isWithinQuotaLocked(jobStatus));
+            final int userId = jobStatus.getSourceUserId();
+            final String packageName = jobStatus.getSourcePackageName();
+            final int realStandbyBucket = jobStatus.getStandbyBucket();
+            if (isWithinQuotaLocked(userId, packageName, realStandbyBucket)) {
+                QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName);
+                if (alarmListener != null && alarmListener.isWaiting()) {
+                    mAlarmManager.cancel(alarmListener);
+                    // Set the trigger time to 0 so that the alarm doesn't think it's still waiting.
+                    alarmListener.setTriggerTime(0);
+                }
+            } else {
+                mToScheduleStartAlarms.add(userId, packageName, realStandbyBucket);
+            }
+        }
+
+        void postProcess() {
+            for (int u = 0; u < mToScheduleStartAlarms.numUsers(); ++u) {
+                final int userId = mToScheduleStartAlarms.keyAt(u);
+                for (int p = 0; p < mToScheduleStartAlarms.numPackagesForUser(userId); ++p) {
+                    final String packageName = mToScheduleStartAlarms.keyAt(u, p);
+                    final int standbyBucket = mToScheduleStartAlarms.get(userId, packageName);
+                    maybeScheduleStartAlarmLocked(userId, packageName, standbyBucket);
+                }
+            }
+        }
+
+        void reset() {
+            wasJobChanged = false;
+            mToScheduleStartAlarms.clear();
+        }
+    }
+
+    private final UidConstraintUpdater mUpdateUidConstraints = new UidConstraintUpdater();
+
+    private boolean maybeUpdateConstraintForUidLocked(final int uid) {
+        mService.getJobStore().forEachJobForSourceUid(uid, mUpdateUidConstraints);
+
+        mUpdateUidConstraints.postProcess();
+        boolean changed = mUpdateUidConstraints.wasJobChanged;
+        mUpdateUidConstraints.reset();
+        return changed;
+    }
+
     /**
      * Maybe schedule a non-wakeup alarm for the next time this package will have quota to run
      * again. This should only be called if the package is already out of quota.
@@ -876,9 +1149,12 @@
 
         final String pkgString = string(userId, packageName);
         ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
+        final boolean isUnderJobCountQuota = isUnderJobCountQuotaLocked(stats, standbyBucket);
+
         QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName);
         if (stats.executionTimeInWindowMs < mAllowedTimePerPeriodMs
-                && stats.executionTimeInMaxPeriodMs < mMaxExecutionTimeMs) {
+                && stats.executionTimeInMaxPeriodMs < mMaxExecutionTimeMs
+                && isUnderJobCountQuota) {
             // Already in quota. Why was this method called?
             if (DEBUG) {
                 Slog.e(TAG, "maybeScheduleStartAlarmLocked called for " + pkgString
@@ -895,18 +1171,22 @@
             mHandler.obtainMessage(MSG_CHECK_PACKAGE, userId, 0, packageName).sendToTarget();
             return;
         }
+
         if (alarmListener == null) {
             alarmListener = new QcAlarmListener(userId, packageName);
             mInQuotaAlarmListeners.add(userId, packageName, alarmListener);
         }
 
         // The time this app will have quota again.
-        long inQuotaTimeElapsed =
-                stats.quotaCutoffTimeElapsed + stats.windowSizeMs;
+        long inQuotaTimeElapsed = stats.quotaCutoffTimeElapsed + stats.windowSizeMs;
         if (stats.executionTimeInMaxPeriodMs >= mMaxExecutionTimeMs) {
             inQuotaTimeElapsed = Math.max(inQuotaTimeElapsed,
                     stats.quotaCutoffTimeElapsed + MAX_PERIOD_MS);
         }
+        if (!isUnderJobCountQuota) {
+            inQuotaTimeElapsed = Math.max(inQuotaTimeElapsed,
+                    stats.jobCountExpirationTimeElapsed + mAllowedTimePerPeriodMs);
+        }
         // Only schedule the alarm if:
         // 1. There isn't one currently scheduled
         // 2. The new alarm is significantly earlier than the previous alarm (which could be the
@@ -1052,6 +1332,7 @@
 
     private final class Timer {
         private final Package mPkg;
+        private final int mUid;
 
         // List of jobs currently running for this app that started when the app wasn't in the
         // foreground.
@@ -1059,16 +1340,18 @@
         private long mStartTimeElapsed;
         private int mBgJobCount;
 
-        Timer(int userId, String packageName) {
+        Timer(int uid, int userId, String packageName) {
             mPkg = new Package(userId, packageName);
+            mUid = uid;
         }
 
         void startTrackingJob(@NonNull JobStatus jobStatus) {
-            if (jobStatus.uidActive) {
-                // We intentionally don't pay attention to fg state changes after a job has started.
+            if (isTopStartedJob(jobStatus)) {
+                // We intentionally don't pay attention to fg state changes after a TOP job has
+                // started.
                 if (DEBUG) {
                     Slog.v(TAG,
-                            "Timer ignoring " + jobStatus.toShortString() + " because uidActive");
+                            "Timer ignoring " + jobStatus.toShortString() + " because isTop");
                 }
                 return;
             }
@@ -1076,8 +1359,9 @@
             synchronized (mLock) {
                 // Always track jobs, even when charging.
                 mRunningBgJobs.add(jobStatus);
-                if (!mChargeTracker.isCharging()) {
+                if (shouldTrackLocked()) {
                     mBgJobCount++;
+                    incrementJobCount(mPkg.userId, mPkg.packageName, 1);
                     if (mRunningBgJobs.size() == 1) {
                         // Started tracking the first job.
                         mStartTimeElapsed = sElapsedRealtimeClock.millis();
@@ -1142,6 +1426,10 @@
             }
         }
 
+        boolean isRunning(JobStatus jobStatus) {
+            return mRunningBgJobs.contains(jobStatus);
+        }
+
         long getCurrentDuration(long nowElapsed) {
             synchronized (mLock) {
                 return !isActive() ? 0 : nowElapsed - mStartTimeElapsed;
@@ -1154,18 +1442,23 @@
             }
         }
 
-        void onChargingChanged(long nowElapsed, boolean isCharging) {
+        private boolean shouldTrackLocked() {
+            return !mChargeTracker.isCharging() && !mForegroundUids.get(mUid);
+        }
+
+        void onStateChanged(long nowElapsed, boolean isQuotaFree) {
             synchronized (mLock) {
-                if (isCharging) {
+                if (isQuotaFree) {
                     emitSessionLocked(nowElapsed);
-                } else {
+                } else if (shouldTrackLocked()) {
                     // Start timing from unplug.
                     if (mRunningBgJobs.size() > 0) {
                         mStartTimeElapsed = nowElapsed;
                         // NOTE: this does have the unfortunate consequence that if the device is
-                        // repeatedly plugged in and unplugged, the job count for a package may be
-                        // artificially high.
+                        // repeatedly plugged in and unplugged, or an app changes foreground state
+                        // very frequently, the job count for a package may be artificially high.
                         mBgJobCount = mRunningBgJobs.size();
+                        incrementJobCount(mPkg.userId, mPkg.packageName, mBgJobCount);
                         // Starting the timer means that all cached execution stats are now
                         // incorrect.
                         invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName);
@@ -1371,6 +1664,38 @@
                         }
                         break;
                     }
+                    case MSG_UID_PROCESS_STATE_CHANGED: {
+                        final int uid = msg.arg1;
+                        final int procState = msg.arg2;
+                        final int userId = UserHandle.getUserId(uid);
+                        final long nowElapsed = sElapsedRealtimeClock.millis();
+
+                        synchronized (mLock) {
+                            boolean isQuotaFree;
+                            if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+                                mForegroundUids.put(uid, true);
+                                isQuotaFree = true;
+                            } else {
+                                mForegroundUids.delete(uid);
+                                isQuotaFree = false;
+                            }
+                            // Update Timers first.
+                            final int userIndex = mPkgTimers.indexOfKey(userId);
+                            if (userIndex != -1) {
+                                final int numPkgs = mPkgTimers.numPackagesForUser(userId);
+                                for (int p = 0; p < numPkgs; ++p) {
+                                    Timer t = mPkgTimers.valueAt(userIndex, p);
+                                    if (t != null) {
+                                        t.onStateChanged(nowElapsed, isQuotaFree);
+                                    }
+                                }
+                            }
+                            if (maybeUpdateConstraintForUidLocked(uid)) {
+                                mStateChangedListener.onControllerStateChanged();
+                            }
+                        }
+                        break;
+                    }
                 }
             }
         }
@@ -1414,12 +1739,24 @@
 
     @VisibleForTesting
     @NonNull
+    int[] getBucketMaxJobCounts() {
+        return mMaxBucketJobCounts;
+    }
+
+    @VisibleForTesting
+    @NonNull
     long[] getBucketWindowSizes() {
         return mBucketPeriodsMs;
     }
 
     @VisibleForTesting
     @NonNull
+    SparseBooleanArray getForegroundUids() {
+        return mForegroundUids;
+    }
+
+    @VisibleForTesting
+    @NonNull
     Handler getHandler() {
         return mHandler;
     }
@@ -1435,6 +1772,11 @@
     }
 
     @VisibleForTesting
+    int getMaxJobCountPerAllowedTime() {
+        return mMaxJobCountPerAllowedTime;
+    }
+
+    @VisibleForTesting
     @Nullable
     List<TimingSession> getTimingSessions(int userId, String packageName) {
         return mTimingSessions.get(userId, packageName);
@@ -1450,6 +1792,10 @@
         pw.println("In parole: " + mInParole);
         pw.println();
 
+        pw.print("Foreground UIDs: ");
+        pw.println(mForegroundUids.toString());
+        pw.println();
+
         mTrackedJobs.forEach((jobs) -> {
             for (int j = 0; j < jobs.size(); j++) {
                 final JobStatus js = jobs.valueAt(j);
@@ -1460,6 +1806,9 @@
                 js.printUniqueId(pw);
                 pw.print(" from ");
                 UserHandle.formatUid(pw, js.getSourceUid());
+                if (mTopStartedJobs.contains(js)) {
+                    pw.print(" (TOP)");
+                }
                 pw.println();
 
                 pw.increaseIndent();
@@ -1511,6 +1860,11 @@
         proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isCharging());
         proto.write(StateControllerProto.QuotaController.IS_IN_PAROLE, mInParole);
 
+        for (int i = 0; i < mForegroundUids.size(); ++i) {
+            proto.write(StateControllerProto.QuotaController.FOREGROUND_UIDS,
+                    mForegroundUids.keyAt(i));
+        }
+
         mTrackedJobs.forEach((jobs) -> {
             for (int j = 0; j < jobs.size(); j++) {
                 final JobStatus js = jobs.valueAt(j);
@@ -1526,6 +1880,8 @@
                 proto.write(
                         StateControllerProto.QuotaController.TrackedJob.EFFECTIVE_STANDBY_BUCKET,
                         getEffectiveStandbyBucket(js));
+                proto.write(StateControllerProto.QuotaController.TrackedJob.IS_TOP_STARTED_JOB,
+                        mTopStartedJobs.contains(js));
                 proto.write(StateControllerProto.QuotaController.TrackedJob.HAS_QUOTA,
                         js.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
                 proto.write(StateControllerProto.QuotaController.TrackedJob.REMAINING_QUOTA_MS,
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index 4c7c420..b3f1018 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -29,7 +29,7 @@
 import java.util.List;
 
 /**
- * Location Manager's interface for location providers.
+ * Location Manager's interface for location providers. Always starts as disabled.
  *
  * @hide
  */
@@ -41,12 +41,6 @@
     public interface LocationProviderManager {
 
         /**
-         * Called on location provider construction to make the location service aware of this
-         * provider and what it's initial enabled/disabled state should be.
-         */
-        void onAttachProvider(AbstractLocationProvider locationProvider, boolean initiallyEnabled);
-
-        /**
          * May be called to inform the location service of a change in this location provider's
          * enabled/disabled state.
          */
@@ -74,13 +68,7 @@
     private final LocationProviderManager mLocationProviderManager;
 
     protected AbstractLocationProvider(LocationProviderManager locationProviderManager) {
-        this(locationProviderManager, true);
-    }
-
-    protected AbstractLocationProvider(LocationProviderManager locationProviderManager,
-            boolean initiallyEnabled) {
         mLocationProviderManager = locationProviderManager;
-        mLocationProviderManager.onAttachProvider(this, initiallyEnabled);
     }
 
     /**
diff --git a/services/core/java/com/android/server/location/GeofenceProxy.java b/services/core/java/com/android/server/location/GeofenceProxy.java
index ca4f7fe..38c7d49 100644
--- a/services/core/java/com/android/server/location/GeofenceProxy.java
+++ b/services/core/java/com/android/server/location/GeofenceProxy.java
@@ -113,8 +113,12 @@
             IGeofenceHardware geofenceHardware = IGeofenceHardware.Stub.asInterface(service);
 
             try {
-                geofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
-                geofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware);
+                if (mGpsGeofenceHardware != null) {
+                    geofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
+                }
+                if (mFusedGeofenceHardware != null) {
+                    geofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware);
+                }
 
                 mGeofenceHardware = geofenceHardware;
                 mServiceWatcher.runOnBinder(mUpdateGeofenceHardware);
diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java
new file mode 100644
index 0000000..7225926
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssConfiguration.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.content.Context;
+import android.os.PersistableBundle;
+import android.os.SystemProperties;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.StatsLog;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+/**
+ * A utility class to hold GNSS configuration properties.
+ *
+ * The trigger to load/reload the configuration parameters should be managed by the class
+ * that owns an instance of this class.
+ *
+ * Instances of this class are not thread-safe and should either be used from a single thread
+ * or with external synchronization when used by multiple threads.
+ */
+class GnssConfiguration {
+    private static final String TAG = "GnssConfiguration";
+
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    //TODO(b/33112647): Create gps_debug.conf with commented career parameters.
+    private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf";
+
+    // config.xml properties
+    private static final String CONFIG_SUPL_HOST = "SUPL_HOST";
+    private static final String CONFIG_SUPL_PORT = "SUPL_PORT";
+    private static final String CONFIG_C2K_HOST = "C2K_HOST";
+    private static final String CONFIG_C2K_PORT = "C2K_PORT";
+    private static final String CONFIG_SUPL_VER = "SUPL_VER";
+    private static final String CONFIG_SUPL_MODE = "SUPL_MODE";
+    private static final String CONFIG_SUPL_ES = "SUPL_ES";
+    private static final String CONFIG_LPP_PROFILE = "LPP_PROFILE";
+    private static final String CONFIG_A_GLONASS_POS_PROTOCOL_SELECT =
+            "A_GLONASS_POS_PROTOCOL_SELECT";
+    private static final String CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL =
+            "USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL";
+    private static final String CONFIG_GPS_LOCK = "GPS_LOCK";
+    private static final String CONFIG_ES_EXTENSION_SEC = "ES_EXTENSION_SEC";
+    public static final String CONFIG_NFW_PROXY_APPS = "NFW_PROXY_APPS";
+
+    // Limit on NI emergency mode time extension after emergency sessions ends
+    private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300;  // 5 minute maximum
+
+    // Persist property for LPP_PROFILE
+    static final String LPP_PROFILE = "persist.sys.gps.lpp";
+
+    // Represents an HAL interface version. Instances of this class are created in the JNI layer
+    // and returned through native methods.
+    private static class HalInterfaceVersion {
+        final int mMajor;
+        final int mMinor;
+
+        HalInterfaceVersion(int major, int minor) {
+            mMajor = major;
+            mMinor = minor;
+        }
+    }
+
+    /**
+     * Properties loaded from PROPERTIES_FILE.
+     */
+    private Properties mProperties;
+
+    private int mEsExtensionSec = 0;
+
+    private final Context mContext;
+
+    GnssConfiguration(Context context) {
+        mContext = context;
+        mProperties = new Properties();
+    }
+
+    /**
+     * Returns the full set of properties loaded.
+     */
+    Properties getProperties() {
+        return mProperties;
+    }
+
+    /**
+     * Returns the value of config parameter ES_EXTENSION_SEC. The value is range checked
+     * and constrained to min/max limits.
+     */
+    int getEsExtensionSec() {
+        return mEsExtensionSec;
+    }
+
+    /**
+     * Returns the value of config parameter SUPL_HOST or {@code null} if no value is
+     * provided.
+     */
+    String getSuplHost() {
+        return mProperties.getProperty(CONFIG_SUPL_HOST);
+    }
+
+    /**
+     * Returns the value of config parameter SUPL_PORT or {@code defaultPort} if no value is
+     * provided or if there is an error parsing the configured value.
+     */
+    int getSuplPort(int defaultPort) {
+        return getIntConfig(CONFIG_SUPL_PORT, defaultPort);
+    }
+
+    /**
+     * Returns the value of config parameter C2K_HOST or {@code null} if no value is
+     * provided.
+     */
+    String getC2KHost() {
+        return mProperties.getProperty(CONFIG_C2K_HOST);
+    }
+
+    /**
+     * Returns the value of config parameter C2K_PORT or {@code defaultPort} if no value is
+     * provided or if there is an error parsing the configured value.
+     */
+    int getC2KPort(int defaultPort) {
+        return getIntConfig(CONFIG_C2K_PORT, defaultPort);
+    }
+
+    /**
+     * Returns the value of config parameter SUPL_MODE or {@code defaultMode} if no value is
+     * provided or if there is an error parsing the configured value.
+     */
+    int getSuplMode(int defaultMode) {
+        return getIntConfig(CONFIG_SUPL_MODE, defaultMode);
+    }
+
+    /**
+     * Returns the value of config parameter SUPL_ES or {@code defaultSuplEs} if no value is
+     * provided or if there is an error parsing the configured value.
+     */
+    int getSuplEs(int defaulSuplEs) {
+        return getIntConfig(CONFIG_SUPL_ES, defaulSuplEs);
+    }
+
+    /**
+     * Returns the value of config parameter LPP_PROFILE or {@code null} if no value is
+     * provided.
+     */
+    String getLppProfile() {
+        return mProperties.getProperty(CONFIG_LPP_PROFILE);
+    }
+
+    /**
+     * Returns the list of proxy apps from the value of config parameter NFW_PROXY_APPS or
+     * {@Collections.EMPTY_LIST} if no value is provided.
+     */
+    List<String> getProxyApps() {
+        // Space separated list of Android proxy app package names.
+        String proxyAppsStr = mProperties.getProperty(CONFIG_NFW_PROXY_APPS);
+        if (TextUtils.isEmpty(proxyAppsStr)) {
+            return Collections.EMPTY_LIST;
+        }
+
+        String[] proxyAppsArray = proxyAppsStr.trim().split("\\s+");
+        if (proxyAppsArray.length == 0) {
+            return Collections.EMPTY_LIST;
+        }
+
+        // TODO(b/122856486): Validate proxy app names so that a system app or some popular app
+        //                    with location permission is not specified as a proxy app.
+        ArrayList proxyApps = new ArrayList(proxyAppsArray.length);
+        for (String proxyApp : proxyAppsArray) {
+            proxyApps.add(proxyApp);
+        }
+
+        return proxyApps;
+    }
+
+    /**
+     * Updates the GNSS HAL satellite blacklist.
+     */
+    void setSatelliteBlacklist(int[] constellations, int[] svids) {
+        native_set_satellite_blacklist(constellations, svids);
+    }
+
+    interface SetCarrierProperty {
+        boolean set(int value);
+    }
+
+    /**
+     * Loads the GNSS properties from carrier config file followed by the properties from
+     * gps debug config file.
+     */
+    void reloadGpsProperties() {
+        if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + mProperties.size());
+        loadPropertiesFromCarrierConfig();
+
+        String lpp_prof = SystemProperties.get(LPP_PROFILE);
+        if (!TextUtils.isEmpty(lpp_prof)) {
+            // override default value of this if lpp_prof is not empty
+            mProperties.setProperty(CONFIG_LPP_PROFILE, lpp_prof);
+        }
+        /*
+         * Overlay carrier properties from a debug configuration file.
+         */
+        loadPropertiesFromGpsDebugConfig(mProperties);
+
+        mEsExtensionSec = getRangeCheckedConfigEsExtensionSec();
+
+        logConfigurations();
+
+        final HalInterfaceVersion gnssConfigurationIfaceVersion =
+                native_get_gnss_configuration_version();
+        if (gnssConfigurationIfaceVersion != null) {
+            // Set to a range checked value.
+            if (isConfigEsExtensionSecSupported(gnssConfigurationIfaceVersion)
+                    && !native_set_es_extension_sec(mEsExtensionSec)) {
+                Log.e(TAG, "Unable to set " + CONFIG_ES_EXTENSION_SEC + ": " + mEsExtensionSec);
+            }
+
+            Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
+                {
+                    put(CONFIG_SUPL_VER, GnssConfiguration::native_set_supl_version);
+                    put(CONFIG_SUPL_MODE, GnssConfiguration::native_set_supl_mode);
+
+                    if (isConfigSuplEsSupported(gnssConfigurationIfaceVersion)) {
+                        put(CONFIG_SUPL_ES, GnssConfiguration::native_set_supl_es);
+                    }
+
+                    put(CONFIG_LPP_PROFILE, GnssConfiguration::native_set_lpp_profile);
+                    put(CONFIG_A_GLONASS_POS_PROTOCOL_SELECT,
+                            GnssConfiguration::native_set_gnss_pos_protocol_select);
+                    put(CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL,
+                            GnssConfiguration::native_set_emergency_supl_pdn);
+
+                    if (isConfigGpsLockSupported(gnssConfigurationIfaceVersion)) {
+                        put(CONFIG_GPS_LOCK, GnssConfiguration::native_set_gps_lock);
+                    }
+                }
+            };
+
+            for (Entry<String, SetCarrierProperty> entry : map.entrySet()) {
+                String propertyName = entry.getKey();
+                String propertyValueString = mProperties.getProperty(propertyName);
+                if (propertyValueString != null) {
+                    try {
+                        int propertyValueInt = Integer.decode(propertyValueString);
+                        boolean result = entry.getValue().set(propertyValueInt);
+                        if (!result) {
+                            Log.e(TAG, "Unable to set " + propertyName);
+                        }
+                    } catch (NumberFormatException e) {
+                        Log.e(TAG, "Unable to parse propertyName: " + propertyValueString);
+                    }
+                }
+            }
+        } else if (DEBUG) {
+            Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
+                    + " supported");
+        }
+    }
+
+    private void logConfigurations() {
+        StatsLog.write(StatsLog.GNSS_CONFIGURATION_REPORTED,
+                getSuplHost(),
+                getSuplPort(0),
+                getC2KHost(),
+                getC2KPort(0),
+                getIntConfig(CONFIG_SUPL_VER, 0),
+                getSuplMode(0),
+                getSuplEs(0) == 1,
+                getIntConfig(CONFIG_LPP_PROFILE, 0),
+                getIntConfig(CONFIG_A_GLONASS_POS_PROTOCOL_SELECT, 0),
+                getIntConfig(CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL, 0) == 1,
+                getIntConfig(CONFIG_GPS_LOCK, 0),
+                getEsExtensionSec(),
+                mProperties.getProperty(CONFIG_NFW_PROXY_APPS));
+    }
+
+    /**
+     * Loads GNSS properties from carrier config file.
+     */
+    void loadPropertiesFromCarrierConfig() {
+        CarrierConfigManager configManager = (CarrierConfigManager)
+                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        if (configManager == null) {
+            return;
+        }
+        PersistableBundle configs = configManager.getConfigForSubId(
+                SubscriptionManager.getDefaultDataSubscriptionId());
+        if (configs == null) {
+            if (DEBUG) Log.d(TAG, "SIM not ready, use default carrier config.");
+            configs = CarrierConfigManager.getDefaultConfig();
+        }
+        for (String configKey : configs.keySet()) {
+            if (configKey.startsWith(CarrierConfigManager.Gps.KEY_PREFIX)) {
+                String key = configKey
+                        .substring(CarrierConfigManager.Gps.KEY_PREFIX.length())
+                        .toUpperCase();
+                Object value = configs.get(configKey);
+                if (value instanceof String) {
+                    // All GPS properties are of String type; convert so.
+                    if (DEBUG) Log.d(TAG, "Gps config: " + key + " = " + value);
+                    mProperties.setProperty(key, (String) value);
+                }
+            }
+        }
+    }
+
+    private void loadPropertiesFromGpsDebugConfig(Properties properties) {
+        try {
+            File file = new File(DEBUG_PROPERTIES_FILE);
+            FileInputStream stream = null;
+            try {
+                stream = new FileInputStream(file);
+                properties.load(stream);
+            } finally {
+                IoUtils.closeQuietly(stream);
+            }
+        } catch (IOException e) {
+            if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + DEBUG_PROPERTIES_FILE);
+        }
+    }
+
+    private int getRangeCheckedConfigEsExtensionSec() {
+        int emergencyExtensionSeconds = getIntConfig(CONFIG_ES_EXTENSION_SEC, 0);
+        if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) {
+            Log.w(TAG, CONFIG_ES_EXTENSION_SEC + ": " + emergencyExtensionSeconds
+                    + " too high, reset to " + MAX_EMERGENCY_MODE_EXTENSION_SECONDS);
+            emergencyExtensionSeconds = MAX_EMERGENCY_MODE_EXTENSION_SECONDS;
+        } else if (emergencyExtensionSeconds < 0) {
+            Log.w(TAG, CONFIG_ES_EXTENSION_SEC + ": " + emergencyExtensionSeconds
+                    + " is negative, reset to zero.");
+            emergencyExtensionSeconds = 0;
+        }
+        return emergencyExtensionSeconds;
+    }
+
+    private int getIntConfig(String configParameter, int defaultValue) {
+        String valueString = mProperties.getProperty(configParameter);
+        if (TextUtils.isEmpty(valueString)) {
+            return defaultValue;
+        }
+        try {
+            return Integer.parseInt(valueString);
+        } catch (NumberFormatException e) {
+            Log.e(TAG, "Unable to parse config parameter " + configParameter + " value: "
+                    + valueString + ". Using default value: " + defaultValue);
+            return defaultValue;
+        }
+    }
+
+    private static boolean isConfigEsExtensionSecSupported(
+            HalInterfaceVersion gnssConfiguartionIfaceVersion) {
+        // ES_EXTENSION_SEC is introduced in @2.0::IGnssConfiguration.hal
+        return gnssConfiguartionIfaceVersion.mMajor >= 2;
+    }
+
+    private static boolean isConfigSuplEsSupported(
+            HalInterfaceVersion gnssConfiguartionIfaceVersion) {
+        // SUPL_ES is deprecated in @2.0::IGnssConfiguration.hal
+        return gnssConfiguartionIfaceVersion.mMajor < 2;
+    }
+
+    private static boolean isConfigGpsLockSupported(
+            HalInterfaceVersion gnssConfiguartionIfaceVersion) {
+        // GPS_LOCK is deprecated in @2.0::IGnssConfiguration.hal
+        return gnssConfiguartionIfaceVersion.mMajor < 2;
+    }
+
+    private static native HalInterfaceVersion native_get_gnss_configuration_version();
+
+    private static native boolean native_set_supl_version(int version);
+
+    private static native boolean native_set_supl_mode(int mode);
+
+    private static native boolean native_set_supl_es(int es);
+
+    private static native boolean native_set_lpp_profile(int lppProfile);
+
+    private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect);
+
+    private static native boolean native_set_gps_lock(int gpsLock);
+
+    private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
+
+    private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);
+
+    private static native boolean native_set_es_extension_sec(int emergencyExtensionSeconds);
+}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 05d77ab..d346ddc 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -64,6 +64,7 @@
 import android.telephony.gsm.GsmCellLocation;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.StatsLog;
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.location.GpsNetInitiatedHandler;
@@ -74,12 +75,7 @@
 import com.android.server.location.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback;
 import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback;
 
-import libcore.io.IoUtils;
-
-import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -87,11 +83,7 @@
 import java.lang.annotation.Target;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
 
 /**
  * A GNSS implementation of LocationProvider used by LocationManager.
@@ -147,7 +139,6 @@
     private static final int LOCATION_HAS_SPEED_ACCURACY = 64;
     private static final int LOCATION_HAS_BEARING_ACCURACY = 128;
 
-
     // IMPORTANT - the GPS_DELETE_* symbols here must match GnssAidingData enum in IGnss.hal
     private static final int GPS_DELETE_EPHEMERIS = 0x0001;
     private static final int GPS_DELETE_ALMANAC = 0x0002;
@@ -200,9 +191,6 @@
     private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
     private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
 
-    //TODO(b/33112647): Create gps_debug.conf with commented career parameters.
-    private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf";
-
     // ref. location info
     private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
     private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
@@ -375,7 +363,7 @@
      * Properties loaded from PROPERTIES_FILE.
      * It must be accessed only inside {@link #mHandler}.
      */
-    private Properties mProperties;
+    private GnssConfiguration mGnssConfiguration;
 
     private String mSuplServerHost;
     private int mSuplServerPort = TCP_MIN_PORT;
@@ -384,6 +372,7 @@
     private boolean mSuplEsEnabled = false;
 
     private final Context mContext;
+    private final Looper mLooper;
     private final LocationExtras mLocationExtras = new LocationExtras();
     private final GnssStatusListenerHelper mGnssStatusListenerHelper;
     private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper;
@@ -394,6 +383,7 @@
     private final NtpTimeHelper mNtpTimeHelper;
     private final GnssBatchingProvider mGnssBatchingProvider;
     private final GnssGeofenceProvider mGnssGeofenceProvider;
+    private GnssVisibilityControl mGnssVisibilityControl;
 
     // Handler for processing events
     private Handler mHandler;
@@ -411,10 +401,6 @@
     private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
     private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
 
-    // Persist property for LPP_PROFILE
-    private final static String LPP_PROFILE = "persist.sys.gps.lpp";
-
-
     private final PowerManager mPowerManager;
     private final AlarmManager mAlarmManager;
     private final PendingIntent mWakeupIntent;
@@ -502,7 +488,7 @@
      */
     @Override
     public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) {
-        mHandler.post(() -> native_set_satellite_blacklist(constellations, svids));
+        mHandler.post(() -> mGnssConfiguration.setSatelliteBlacklist(constellations, svids));
     }
 
     private void subscriptionOrCarrierConfigChanged(Context context) {
@@ -525,17 +511,17 @@
                 }
                 if (isKeepLppProfile) {
                     // load current properties for the carrier
-                    loadPropertiesFromCarrierConfig(context, mProperties);
-                    String lpp_profile = mProperties.getProperty("LPP_PROFILE");
+                    mGnssConfiguration.loadPropertiesFromCarrierConfig();
+                    String lpp_profile = mGnssConfiguration.getLppProfile();
                     // set the persist property LPP_PROFILE for the value
                     if (lpp_profile != null) {
-                        SystemProperties.set(LPP_PROFILE, lpp_profile);
+                        SystemProperties.set(GnssConfiguration.LPP_PROFILE, lpp_profile);
                     }
                 } else {
                     // reset the persist property
-                    SystemProperties.set(LPP_PROFILE, "");
+                    SystemProperties.set(GnssConfiguration.LPP_PROFILE, "");
                 }
-                reloadGpsProperties(context, mProperties);
+                reloadGpsProperties();
                 mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
             }
         } else {
@@ -564,140 +550,25 @@
         return native_is_supported();
     }
 
-    interface SetCarrierProperty {
-        boolean set(int value);
-    }
-
-    private void reloadGpsProperties(Context context, Properties properties) {
-        if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
-        loadPropertiesFromCarrierConfig(context, properties);
-
-        String lpp_prof = SystemProperties.get(LPP_PROFILE);
-        if (!TextUtils.isEmpty(lpp_prof)) {
-            // override default value of this if lpp_prof is not empty
-            properties.setProperty("LPP_PROFILE", lpp_prof);
-        }
-        /*
-         * Overlay carrier properties from a debug configuration file.
-         */
-        loadPropertiesFromGpsDebugConfig(properties);
+    private void reloadGpsProperties() {
+        mGnssConfiguration.reloadGpsProperties();
+        setSuplHostPort();
         // TODO: we should get rid of C2K specific setting.
-        setSuplHostPort(properties.getProperty("SUPL_HOST"),
-                properties.getProperty("SUPL_PORT"));
-        mC2KServerHost = properties.getProperty("C2K_HOST");
-        String portString = properties.getProperty("C2K_PORT");
-        if (mC2KServerHost != null && portString != null) {
-            try {
-                mC2KServerPort = Integer.parseInt(portString);
-            } catch (NumberFormatException e) {
-                Log.e(TAG, "unable to parse C2K_PORT: " + portString);
-            }
-        }
-        if (native_is_gnss_configuration_supported()) {
-            Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
-                {
-                    put("SUPL_VER", GnssLocationProvider::native_set_supl_version);
-                    put("SUPL_MODE", GnssLocationProvider::native_set_supl_mode);
-                    put("SUPL_ES", GnssLocationProvider::native_set_supl_es);
-                    put("LPP_PROFILE", GnssLocationProvider::native_set_lpp_profile);
-                    put("A_GLONASS_POS_PROTOCOL_SELECT",
-                            GnssLocationProvider::native_set_gnss_pos_protocol_select);
-                    put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL",
-                            GnssLocationProvider::native_set_emergency_supl_pdn);
-                    put("GPS_LOCK", GnssLocationProvider::native_set_gps_lock);
-                }
-            };
-
-            for (Entry<String, SetCarrierProperty> entry : map.entrySet()) {
-                String propertyName = entry.getKey();
-                String propertyValueString = properties.getProperty(propertyName);
-                if (propertyValueString != null) {
-                    try {
-                        int propertyValueInt = Integer.decode(propertyValueString);
-                        boolean result = entry.getValue().set(propertyValueInt);
-                        if (!result) {
-                            Log.e(TAG, "Unable to set " + propertyName);
-                        }
-                    } catch (NumberFormatException e) {
-                        Log.e(TAG, "unable to parse propertyName: " + propertyValueString);
-                    }
-                }
-            }
-        } else if (DEBUG) {
-            Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
-                    + " supported");
-        }
-
-        // SUPL_ES configuration.
-        String suplESProperty = mProperties.getProperty("SUPL_ES");
-        if (suplESProperty != null) {
-            try {
-                mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1);
-            } catch (NumberFormatException e) {
-                Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
-            }
-        }
-
-        String emergencyExtensionSecondsString
-                = properties.getProperty("ES_EXTENSION_SEC", "0");
-        try {
-            int emergencyExtensionSeconds =
-                    Integer.parseInt(emergencyExtensionSecondsString);
-            mNIHandler.setEmergencyExtensionSeconds(emergencyExtensionSeconds);
-        } catch (NumberFormatException e) {
-            Log.e(TAG, "unable to parse ES_EXTENSION_SEC: "
-                    + emergencyExtensionSecondsString);
-        }
-    }
-
-    private void loadPropertiesFromCarrierConfig(Context context, Properties properties) {
-        CarrierConfigManager configManager = (CarrierConfigManager)
-                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        if (configManager == null) {
-            return;
-        }
-        PersistableBundle configs = configManager.getConfigForSubId(
-                SubscriptionManager.getDefaultDataSubscriptionId());
-        if (configs == null) {
-            if (DEBUG) Log.d(TAG, "SIM not ready, use default carrier config.");
-            configs = CarrierConfigManager.getDefaultConfig();
-        }
-        for (String configKey : configs.keySet()) {
-            if (configKey.startsWith(CarrierConfigManager.Gps.KEY_PREFIX)) {
-                String key = configKey
-                        .substring(CarrierConfigManager.Gps.KEY_PREFIX.length())
-                        .toUpperCase();
-                Object value = configs.get(configKey);
-                if (value instanceof String) {
-                    // All GPS properties are of String type; convert so.
-                    if (DEBUG) Log.d(TAG, "Gps config: " + key + " = " + value);
-                    properties.setProperty(key, (String) value);
-                }
-            }
-        }
-    }
-
-    private void loadPropertiesFromGpsDebugConfig(Properties properties) {
-        try {
-            File file = new File(DEBUG_PROPERTIES_FILE);
-            FileInputStream stream = null;
-            try {
-                stream = new FileInputStream(file);
-                properties.load(stream);
-            } finally {
-                IoUtils.closeQuietly(stream);
-            }
-
-        } catch (IOException e) {
-            if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + DEBUG_PROPERTIES_FILE);
+        mC2KServerHost = mGnssConfiguration.getC2KHost();
+        mC2KServerPort = mGnssConfiguration.getC2KPort(TCP_MIN_PORT);
+        mNIHandler.setEmergencyExtensionSeconds(mGnssConfiguration.getEsExtensionSec());
+        mSuplEsEnabled = mGnssConfiguration.getSuplEs(0) == 1;
+        if (mGnssVisibilityControl != null) {
+            mGnssVisibilityControl.updateProxyApps(mGnssConfiguration.getProxyApps());
         }
     }
 
     public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager,
             Looper looper) {
-        super(locationProviderManager, true);
+        super(locationProviderManager);
 
         mContext = context;
+        mLooper = looper;
 
         // Create a wake lock
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -733,7 +604,7 @@
         // relative long time, so the ctor() is kept to create objects needed by this instance,
         // while IO initialization and registration is delegated to our internal handler
         // this approach is just fine because events are posted to our handler anyway
-        mProperties = new Properties();
+        mGnssConfiguration = new GnssConfiguration(mContext);
         sendMessage(INITIALIZE_HANDLER, 0, null);
 
         // Create a GPS net-initiated handler.
@@ -788,6 +659,7 @@
         }, UserHandle.ALL, intentFilter, null, mHandler);
 
         setProperties(PROPERTIES);
+        setEnabled(true);
     }
 
     /**
@@ -918,7 +790,8 @@
         mDownloadXtraWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS);
         Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
         AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
-            GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
+            GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(
+                    mGnssConfiguration.getProperties());
             byte[] data = xtraDownloader.downloadXtraData();
             if (data != null) {
                 if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
@@ -963,17 +836,9 @@
         }
     }
 
-    private void setSuplHostPort(String hostString, String portString) {
-        if (hostString != null) {
-            mSuplServerHost = hostString;
-        }
-        if (portString != null) {
-            try {
-                mSuplServerPort = Integer.parseInt(portString);
-            } catch (NumberFormatException e) {
-                Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
-            }
-        }
+    private void setSuplHostPort() {
+        mSuplServerHost = mGnssConfiguration.getSuplHost();
+        mSuplServerPort = mGnssConfiguration.getSuplPort(TCP_MIN_PORT);
         if (mSuplServerHost != null
                 && mSuplServerPort > TCP_MIN_PORT
                 && mSuplServerPort <= TCP_MAX_PORT) {
@@ -986,23 +851,17 @@
      * Checks what SUPL mode to use, according to the AGPS mode as well as the
      * allowed mode from properties.
      *
-     * @param properties  GPS properties
      * @param agpsEnabled whether AGPS is enabled by settings value
      * @param singleShot  whether "singleshot" is needed
      * @return SUPL mode (MSA vs MSB vs STANDALONE)
      */
-    private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
+    private int getSuplMode(boolean agpsEnabled, boolean singleShot) {
         if (agpsEnabled) {
-            String modeString = properties.getProperty("SUPL_MODE");
-            int suplMode = 0;
-            if (!TextUtils.isEmpty(modeString)) {
-                try {
-                    suplMode = Integer.parseInt(modeString);
-                } catch (NumberFormatException e) {
-                    Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
-                    return GPS_POSITION_MODE_STANDALONE;
-                }
+            int suplMode = mGnssConfiguration.getSuplMode(0);
+            if (suplMode == 0) {
+                return GPS_POSITION_MODE_STANDALONE;
             }
+
             // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
             // such mode when it is available
             if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
@@ -1307,7 +1166,7 @@
             boolean agpsEnabled =
                     (Settings.Global.getInt(mContext.getContentResolver(),
                             Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
-            mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
+            mPositionMode = getSuplMode(agpsEnabled, singleShot);
 
             if (DEBUG) {
                 String mode;
@@ -1670,7 +1529,7 @@
                 // re-calls native_init() and other setup.
                 handleEnable();
                 // resend configuration into the restarted HAL service.
-                reloadGpsProperties(mContext, mProperties);
+                reloadGpsProperties();
             }
         });
     }
@@ -1852,6 +1711,24 @@
                         ", response: " + userResponse);
             }
             native_send_ni_response(notificationId, userResponse);
+
+            StatsLog.write(StatsLog.GNSS_NI_EVENT_REPORTED,
+                    StatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_RESPONSE,
+                    notificationId,
+                    /* niType= */ 0,
+                    /* needNotify= */ false,
+                    /* needVerify= */ false,
+                    /* privacyOverride= */ false,
+                    /* timeout= */ 0,
+                    /* defaultResponse= */ 0,
+                    /* requestorId= */ null,
+                    /* text= */ null,
+                    /* requestorIdEncoding= */ 0,
+                    /* textEncoding= */ 0,
+                    mSuplEsEnabled,
+                    mEnabled,
+                    userResponse);
+
             return true;
         }
     };
@@ -1901,6 +1778,22 @@
         notification.textEncoding = textEncoding;
 
         mNIHandler.handleNiNotification(notification);
+        StatsLog.write(StatsLog.GNSS_NI_EVENT_REPORTED,
+                StatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_REQUEST,
+                notification.notificationId,
+                notification.niType,
+                notification.needNotify,
+                notification.needVerify,
+                notification.privacyOverride,
+                notification.timeout,
+                notification.defaultResponse,
+                notification.requestorId,
+                notification.text,
+                notification.requestorIdEncoding,
+                notification.textEncoding,
+                mSuplEsEnabled,
+                mEnabled,
+                /* userResponse= */ 0);
     }
 
     /**
@@ -1982,6 +1875,27 @@
         }
     }
 
+    // Implements method nfwNotifyCb() in IGnssVisibilityControlCallback.hal.
+    @NativeEntryPoint
+    private void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
+            String otherProtocolStackName, byte requestor, String requestorId, byte responseType,
+            boolean inEmergencyMode, boolean isCachedLocation) {
+        if (mGnssVisibilityControl == null) {
+            Log.e(TAG, "reportNfwNotification: mGnssVisibilityControl is not initialized.");
+            return;
+        }
+
+        mGnssVisibilityControl.reportNfwNotification(proxyAppPackageName, protocolStack,
+                otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode,
+                isCachedLocation);
+    }
+
+    // Implements method isInEmergencySession() in IGnssVisibilityControlCallback.hal.
+    @NativeEntryPoint
+    boolean isInEmergencySession() {
+        return mNIHandler.getInEmergency();
+    }
+
     private void sendMessage(int message, int arg, Object obj) {
         // hold a wake lock until this message is delivered
         // note that this assumes the message will not be removed from the queue before
@@ -2070,9 +1984,13 @@
                 native_cleanup();
             }
 
+            if (native_is_gnss_visibility_control_supported()) {
+                mGnssVisibilityControl = new GnssVisibilityControl(mContext, mLooper);
+            }
+
             // load default GPS configuration
             // (this configuration might change in the future based on SIM changes)
-            reloadGpsProperties(mContext, mProperties);
+            reloadGpsProperties();
 
             // TODO: When this object "finishes" we should unregister by invoking
             // SubscriptionManager.getInstance(mContext).unregister
@@ -2227,7 +2145,7 @@
 
     private static native boolean native_is_supported();
 
-    private static native boolean native_is_gnss_configuration_supported();
+    private static native boolean native_is_gnss_visibility_control_supported();
 
     private static native void native_init_once();
 
@@ -2284,21 +2202,4 @@
             int lac, int cid);
 
     private native void native_agps_set_id(int type, String setid);
-
-    // GNSS Configuration
-    private static native boolean native_set_supl_version(int version);
-
-    private static native boolean native_set_supl_mode(int mode);
-
-    private static native boolean native_set_supl_es(int es);
-
-    private static native boolean native_set_lpp_profile(int lppProfile);
-
-    private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect);
-
-    private static native boolean native_set_gps_lock(int gpsLock);
-
-    private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
-
-    private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);
-}
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
new file mode 100644
index 0000000..591889d
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.annotation.SuppressLint;
+import android.app.AppOpsManager;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.StatsLog;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Handles GNSS non-framework location access user visibility and control.
+ *
+ * The state of the GnssVisibilityControl object must be accessed/modified through the Handler
+ * thread only.
+ */
+class GnssVisibilityControl {
+    private static final String TAG = "GnssVisibilityControl";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    // Constants related to non-framework (NFW) location access permission proxy apps.
+    private static final String NFW_PROXY_APP_PKG_ACTIVITY_NAME_SUFFIX =
+            ".NonFrameworkLocationAccessActivity";
+    private static final String NFW_INTENT_ACTION_NFW_LOCATION_ACCESS_SUFFIX =
+            ".intent.action.NON_FRAMEWORK_LOCATION_ACCESS";
+    private static final String NFW_INTENT_TYPE = "text/plain";
+
+    private static final String LOCATION_PERMISSION_NAME =
+            "android.permission.ACCESS_FINE_LOCATION";
+
+    // Wakelocks
+    private static final String WAKELOCK_KEY = TAG;
+    private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
+    private final PowerManager.WakeLock mWakeLock;
+
+    private final AppOpsManager mAppOps;
+    private final PackageManager mPackageManager;
+
+    private final Handler mHandler;
+    private final Context mContext;
+
+    // Number of non-framework location access proxy apps is expected to be small (< 5).
+    private static final int HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
+    private HashMap<String, Boolean> mProxyAppToLocationPermissions = new HashMap<>(
+            HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS);
+
+    private PackageManager.OnPermissionsChangedListener mOnPermissionsChangedListener =
+            uid -> postEvent(() -> handlePermissionsChanged(uid));
+
+    GnssVisibilityControl(Context context, Looper looper) {
+        mContext = context;
+        PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
+        mHandler = new Handler(looper);
+        mAppOps = mContext.getSystemService(AppOpsManager.class);
+        mPackageManager = mContext.getPackageManager();
+        // TODO(b/122855984): Handle global location settings on/off.
+        // TODO(b/122856189): Handle roaming case.
+    }
+
+    void updateProxyApps(List<String> nfwLocationAccessProxyApps) {
+        // NOTE: This class doesn't explicitly register and listen for SIM_STATE_CHANGED event
+        //       but rather piggy backs on the GnssLocationProvider SIM_STATE_CHANGED handling
+        //       so that the order of processing is preserved. GnssLocationProvider should
+        //       first load the new config parameters for the new SIM and then call this method.
+        postEvent(() -> handleSubscriptionOrSimChanged(nfwLocationAccessProxyApps));
+    }
+
+    void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
+            String otherProtocolStackName, byte requestor, String requestorId, byte responseType,
+            boolean inEmergencyMode, boolean isCachedLocation) {
+        postEvent(() -> handleNfwNotification(
+                new NfwNotification(proxyAppPackageName, protocolStack, otherProtocolStackName,
+                        requestor, requestorId, responseType, inEmergencyMode, isCachedLocation)));
+    }
+
+    private void handleSubscriptionOrSimChanged(List<String> nfwLocationAccessProxyApps) {
+        if (nfwLocationAccessProxyApps.isEmpty()) {
+            // Stop listening for app permission changes. Clear the app list in GNSS HAL.
+            if (!mProxyAppToLocationPermissions.isEmpty()) {
+                mPackageManager.removeOnPermissionsChangeListener(mOnPermissionsChangedListener);
+                mProxyAppToLocationPermissions.clear();
+                updateNfwLocationAccessProxyAppsInGnssHal();
+            }
+            return;
+        }
+
+        if (mProxyAppToLocationPermissions.isEmpty()) {
+            mPackageManager.addOnPermissionsChangeListener(mOnPermissionsChangedListener);
+        } else {
+            mProxyAppToLocationPermissions.clear();
+        }
+
+        for (String proxApp : nfwLocationAccessProxyApps) {
+            mProxyAppToLocationPermissions.put(proxApp, hasLocationPermission(proxApp));
+        }
+
+        updateNfwLocationAccessProxyAppsInGnssHal();
+    }
+
+    // Represents NfwNotification structure in IGnssVisibilityControlCallback.hal
+    private static class NfwNotification {
+        private static final String KEY_PROTOCOL_STACK = "ProtocolStack";
+        private static final String KEY_OTHER_PROTOCOL_STACK_NAME = "OtherProtocolStackName";
+        private static final String KEY_REQUESTOR = "Requestor";
+        private static final String KEY_REQUESTOR_ID = "RequestorId";
+        private static final String KEY_RESPONSE_TYPE = "ResponseType";
+        private static final String KEY_IN_EMERGENCY_MODE = "InEmergencyMode";
+        private static final String KEY_IS_CACHED_LOCATION = "IsCachedLocation";
+
+        // This must match with NfwResponseType enum in IGnssVisibilityControlCallback.hal.
+        private static final byte NFW_RESPONSE_TYPE_REJECTED = 0;
+        private static final byte NFW_RESPONSE_TYPE_ACCEPTED_NO_LOCATION_PROVIDED = 1;
+        private static final byte NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED = 2;
+
+        private final String mProxyAppPackageName;
+        private final byte mProtocolStack;
+        private final String mOtherProtocolStackName;
+        private final byte mRequestor;
+        private final String mRequestorId;
+        private final byte mResponseType;
+        private final boolean mInEmergencyMode;
+        private final boolean mIsCachedLocation;
+
+        NfwNotification(String proxyAppPackageName, byte protocolStack,
+                String otherProtocolStackName, byte requestor, String requestorId,
+                byte responseType, boolean inEmergencyMode, boolean isCachedLocation) {
+            mProxyAppPackageName = proxyAppPackageName;
+            mProtocolStack = protocolStack;
+            mOtherProtocolStackName = otherProtocolStackName;
+            mRequestor = requestor;
+            mRequestorId = requestorId;
+            mResponseType = responseType;
+            mInEmergencyMode = inEmergencyMode;
+            mIsCachedLocation = isCachedLocation;
+        }
+
+        void copyFieldsToIntent(Intent intent) {
+            intent.putExtra(KEY_PROTOCOL_STACK, mProtocolStack);
+            if (!TextUtils.isEmpty(mOtherProtocolStackName)) {
+                intent.putExtra(KEY_OTHER_PROTOCOL_STACK_NAME, mOtherProtocolStackName);
+            }
+            intent.putExtra(KEY_REQUESTOR, mRequestor);
+            if (!TextUtils.isEmpty(mRequestorId)) {
+                intent.putExtra(KEY_REQUESTOR_ID, mRequestorId);
+            }
+            intent.putExtra(KEY_RESPONSE_TYPE, mResponseType);
+            intent.putExtra(KEY_IN_EMERGENCY_MODE, mInEmergencyMode);
+            if (mResponseType == NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED) {
+                intent.putExtra(KEY_IS_CACHED_LOCATION, mIsCachedLocation);
+            }
+        }
+
+        @SuppressLint("DefaultLocale")
+        public String toString() {
+            return String.format(
+                    "[Notification] proxyAppPackageName: %s, protocolStack: %d"
+                            + ", otherProtocolStackName: %s, requestor: %d, requestorId: %s"
+                            + ", responseType: %d, inEmergencyMode: %b, isCachedLocation: %b",
+                    mProxyAppPackageName, mProtocolStack, mOtherProtocolStackName,
+                    mRequestor, mRequestorId, mResponseType, mInEmergencyMode, mIsCachedLocation);
+        }
+
+        String getResponseTypeAsString() {
+            switch (mResponseType) {
+                case NFW_RESPONSE_TYPE_REJECTED:
+                    return "REJECTED";
+                case NFW_RESPONSE_TYPE_ACCEPTED_NO_LOCATION_PROVIDED:
+                    return "ACCEPTED_NO_LOCATION_PROVIDED";
+                case NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED:
+                    return "ACCEPTED_LOCATION_PROVIDED";
+                default:
+                    return "<Unknown>";
+            }
+        }
+    }
+
+    private void handlePermissionsChanged(int uid) {
+        if (mProxyAppToLocationPermissions.isEmpty()) {
+            return;
+        }
+
+        for (Map.Entry<String, Boolean> entry : mProxyAppToLocationPermissions.entrySet()) {
+            // Cannot cache uid since the application could be uninstalled and reinstalled.
+            final String proxyApp = entry.getKey();
+            final Integer nfwProxyAppUid = getApplicationUid(proxyApp);
+            if (nfwProxyAppUid == null || nfwProxyAppUid != uid) {
+                continue;
+            }
+
+            final boolean isLocationPermissionEnabled = hasLocationPermission(proxyApp);
+            if (isLocationPermissionEnabled != entry.getValue()) {
+                Log.i(TAG, "Location permission setting is changed to "
+                        + (isLocationPermissionEnabled ? "enabled" : "disabled")
+                        + " for non-framework location access proxy app "
+                        + proxyApp);
+                entry.setValue(isLocationPermissionEnabled);
+                updateNfwLocationAccessProxyAppsInGnssHal();
+                return;
+            }
+        }
+    }
+
+    private Integer getApplicationUid(String pkgName) {
+        try {
+            return mPackageManager.getApplicationInfo(pkgName, 0).uid;
+        } catch (PackageManager.NameNotFoundException e) {
+            if (DEBUG) {
+                Log.d(TAG, "Non-framework location access proxy app "
+                        + pkgName + " is not found.");
+            }
+            return null;
+        }
+    }
+
+    private boolean hasLocationPermission(String pkgName) {
+        return mPackageManager.checkPermission(LOCATION_PERMISSION_NAME, pkgName)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    private void updateNfwLocationAccessProxyAppsInGnssHal() {
+        // Get a count of proxy apps with location permission enabled to array creation size.
+        int countLocationPermissionEnabledProxyApps = 0;
+        for (Boolean hasLocationPermissionEnabled : mProxyAppToLocationPermissions.values()) {
+            if (hasLocationPermissionEnabled) {
+                ++countLocationPermissionEnabledProxyApps;
+            }
+        }
+
+        int i = 0;
+        String[] locationPermissionEnabledProxyApps =
+                new String[countLocationPermissionEnabledProxyApps];
+        for (Map.Entry<String, Boolean> entry : mProxyAppToLocationPermissions.entrySet()) {
+            final String proxyApp = entry.getKey();
+            final boolean hasLocationPermissionEnabled = entry.getValue();
+            if (hasLocationPermissionEnabled) {
+                locationPermissionEnabledProxyApps[i++] = proxyApp;
+            }
+        }
+
+        String proxyAppsStr = Arrays.toString(locationPermissionEnabledProxyApps);
+        Log.i(TAG, "Updating non-framework location access proxy apps in the GNSS HAL to: "
+                + proxyAppsStr);
+        boolean result = native_enable_nfw_location_access(locationPermissionEnabledProxyApps);
+        if (!result) {
+            Log.e(TAG, "Failed to update non-framework location access proxy apps in the"
+                    + " GNSS HAL to: " + proxyAppsStr);
+        }
+    }
+
+    private void handleNfwNotification(NfwNotification nfwNotification) {
+        if (DEBUG) Log.d(TAG, nfwNotification.toString());
+
+        final String proxyAppPackageName = nfwNotification.mProxyAppPackageName;
+        Boolean isLocationPermissionEnabled = mProxyAppToLocationPermissions.get(
+                proxyAppPackageName);
+        boolean isLocationRequestAccepted =
+                nfwNotification.mResponseType != NfwNotification.NFW_RESPONSE_TYPE_REJECTED;
+        boolean isPermissionMismatched;
+        if (isLocationPermissionEnabled == null) {
+            isPermissionMismatched = isLocationRequestAccepted;
+        } else {
+            isPermissionMismatched = (isLocationPermissionEnabled != isLocationRequestAccepted);
+        }
+        logEvent(nfwNotification, isPermissionMismatched);
+
+        if (TextUtils.isEmpty(proxyAppPackageName)) {
+            Log.e(TAG, "ProxyAppPackageName field is not set. Not sending intent to proxy app for "
+                    + nfwNotification);
+            return;
+        }
+
+        if (isLocationPermissionEnabled == null) {
+            // App is not in the configured list.
+            Log.e(TAG, "Could not find proxy app with name: " + proxyAppPackageName + " in the "
+                    + "value specified for config parameter: "
+                    + GnssConfiguration.CONFIG_NFW_PROXY_APPS + ". Not sending intent to proxy app"
+                    + " for " + nfwNotification);
+            return;
+        }
+
+        // Send intent to non-framework location proxy app with notification information.
+        final Intent intent = new Intent(
+                proxyAppPackageName + NFW_INTENT_ACTION_NFW_LOCATION_ACCESS_SUFFIX);
+        final String proxAppActivityName =
+                proxyAppPackageName + NFW_PROXY_APP_PKG_ACTIVITY_NAME_SUFFIX;
+        intent.setClassName(proxyAppPackageName, proxAppActivityName);
+        intent.setType(NFW_INTENT_TYPE);
+        nfwNotification.copyFieldsToIntent(intent);
+
+        // Check if the proxy app is still installed.
+        final Integer clsAppUid = getApplicationUid(proxyAppPackageName);
+        if (clsAppUid == null || intent.resolveActivity(mPackageManager) == null) {
+            Log.i(TAG, "Proxy application " + proxyAppPackageName + " and/or activity "
+                    + proxAppActivityName + " is not found. Not sending"
+                    + " intent to proxy app for " + nfwNotification);
+            return;
+        }
+
+        // Display location icon attributed to this proxy app.
+        mAppOps.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, clsAppUid, proxyAppPackageName);
+
+        // Log proxy app permission mismatch between framework and GNSS HAL.
+        if (isPermissionMismatched) {
+            Log.w(TAG, "Permission mismatch. Framework proxy app " + proxyAppPackageName
+                    + " location permission is set to " + isLocationPermissionEnabled
+                    + " but GNSS non-framework location access response type is "
+                    + nfwNotification.getResponseTypeAsString() + " for " + nfwNotification);
+        }
+
+        // Notify proxy app.
+        try {
+            if (DEBUG) {
+                Log.d(TAG, "Sending non-framework location access notification intent: " + intent);
+            }
+            mContext.startActivityAsUser(intent, UserHandle.getUserHandleForUid(clsAppUid));
+        } catch (ActivityNotFoundException e) {
+            Log.w(TAG, "Activity not found. Failed to send non-framework location access"
+                    + " notification intent to proxy app activity: " + proxAppActivityName);
+        }
+    }
+
+    private void logEvent(NfwNotification notification, boolean isPermissionMismatched) {
+        StatsLog.write(StatsLog.GNSS_NFW_NOTIFICATION_REPORTED,
+                notification.mProxyAppPackageName,
+                notification.mProtocolStack,
+                notification.mOtherProtocolStackName,
+                notification.mRequestor,
+                notification.mRequestorId,
+                notification.mResponseType,
+                notification.mInEmergencyMode,
+                notification.mIsCachedLocation,
+                isPermissionMismatched);
+    }
+
+    private void postEvent(Runnable event) {
+        // Hold a wake lock until this message is delivered.
+        // Note that this assumes the message will not be removed from the queue before
+        // it is handled (otherwise the wake lock would be leaked).
+        mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
+        if (!mHandler.post(runEventAndReleaseWakeLock(event))) {
+            mWakeLock.release();
+        }
+    }
+
+    private Runnable runEventAndReleaseWakeLock(Runnable event) {
+        return () -> {
+            try {
+                event.run();
+            } finally {
+                mWakeLock.release();
+            }
+        };
+    }
+
+    private native boolean native_enable_nfw_location_access(String[] proxyApps);
+}
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index dfcef70..a6da8c5 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -101,7 +101,7 @@
     private LocationProviderProxy(Context context, LocationProviderManager locationProviderManager,
             String action, int overlaySwitchResId, int defaultServicePackageNameResId,
             int initialPackageNamesResId) {
-        super(locationProviderManager, false);
+        super(locationProviderManager);
 
         mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId,
                 defaultServicePackageNameResId, initialPackageNamesResId,
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
index b7934d9..b7ccb26 100644
--- a/services/core/java/com/android/server/location/LocationRequestStatistics.java
+++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java
@@ -123,6 +123,9 @@
         // in foreground.
         private long mForegroundDurationMs;
 
+        // Time when package last went dormant (stopped requesting location)
+        private long mLastStopElapsedTimeMs;
+
         private PackageStatistics() {
             mInitialElapsedTimeMs = SystemClock.elapsedRealtime();
             mNumActiveRequests = 0;
@@ -131,6 +134,7 @@
             mSlowestIntervalMs = 0;
             mForegroundDurationMs = 0;
             mLastForegroundElapsedTimeMs = 0;
+            mLastStopElapsedTimeMs = 0;
         }
 
         private void startRequesting(long intervalMs) {
@@ -167,8 +171,8 @@
 
             mNumActiveRequests--;
             if (mNumActiveRequests == 0) {
-                long lastDurationMs
-                        = SystemClock.elapsedRealtime() - mLastActivitationElapsedTimeMs;
+                mLastStopElapsedTimeMs = SystemClock.elapsedRealtime();
+                long lastDurationMs = mLastStopElapsedTimeMs - mLastActivitationElapsedTimeMs;
                 mTotalDurationMs += lastDurationMs;
                 updateForeground(false);
             }
@@ -206,6 +210,13 @@
         }
 
         /**
+         * Returns the time since the last request stopped in ms.
+         */
+        public long getTimeSinceLastRequestStoppedMs() {
+            return SystemClock.elapsedRealtime() - mLastStopElapsedTimeMs;
+        }
+
+        /**
          * Returns the fastest interval that has been tracked.
          */
         public long getFastestIntervalMs() {
@@ -244,6 +255,10 @@
                     .append(" minutes");
             if (isActive()) {
                 s.append(": Currently active");
+            } else {
+                s.append(": Last active ")
+                        .append((getTimeSinceLastRequestStoppedMs() / 1000) / 60)
+                        .append(" minutes ago");
             }
             return s.toString();
         }
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index bfbebf7..fe91c63 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -43,7 +43,7 @@
 
     public MockProvider(
             LocationProviderManager locationProviderManager, ProviderProperties properties) {
-        super(locationProviderManager, true);
+        super(locationProviderManager);
 
         mEnabled = true;
         mLocation = null;
@@ -63,8 +63,11 @@
     /** Sets the location to report for this mock provider. */
     public void setLocation(Location l) {
         mLocation = new Location(l);
+        if (!mLocation.isFromMockProvider()) {
+            mLocation.setIsFromMockProvider(true);
+        }
         if (mEnabled) {
-            reportLocation(l);
+            reportLocation(mLocation);
         }
     }
 
diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java
index 70d64b0..30260b2 100644
--- a/services/core/java/com/android/server/location/PassiveProvider.java
+++ b/services/core/java/com/android/server/location/PassiveProvider.java
@@ -43,11 +43,12 @@
     private boolean mReportLocation;
 
     public PassiveProvider(LocationProviderManager locationProviderManager) {
-        super(locationProviderManager, true);
+        super(locationProviderManager);
 
         mReportLocation = false;
 
         setProperties(PROPERTIES);
+        setEnabled(true);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index ea8c792..a9ae74f 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -21,10 +21,10 @@
 import static android.content.Context.KEYGUARD_SERVICE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 import static com.android.internal.widget.LockPatternUtils.USER_FRP;
 import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled;
 import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential;
@@ -81,9 +81,9 @@
 import android.security.keystore.KeyProtection;
 import android.security.keystore.UserNotAuthenticatedException;
 import android.security.keystore.recovery.KeyChainProtectionParams;
+import android.security.keystore.recovery.KeyChainSnapshot;
 import android.security.keystore.recovery.RecoveryCertPath;
 import android.security.keystore.recovery.WrappedApplicationKey;
-import android.security.keystore.recovery.KeyChainSnapshot;
 import android.service.gatekeeper.GateKeeperResponse;
 import android.service.gatekeeper.IGateKeeperService;
 import android.text.TextUtils;
@@ -109,9 +109,9 @@
 import com.android.server.SystemService;
 import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
 import com.android.server.locksettings.LockSettingsStorage.PersistentData;
-import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager;
 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken;
+import com.android.server.locksettings.recoverablekeystore.RecoverableKeyStoreManager;
 import com.android.server.wm.WindowManagerInternal;
 
 import libcore.util.HexEncoding;
@@ -130,8 +130,8 @@
 import java.security.SecureRandom;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateException;
-import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
@@ -947,6 +947,10 @@
     public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
             String managedUserPassword) {
         checkWritePermission(userId);
+        if (!mLockPatternUtils.hasSecureLockScreen()) {
+            throw new UnsupportedOperationException(
+                    "This operation requires secure lock screen feature.");
+        }
         synchronized (mSeparateChallengeLock) {
             setSeparateProfileChallengeEnabledLocked(userId, enabled, managedUserPassword);
         }
@@ -1305,6 +1309,10 @@
     public void setLockCredential(String credential, int type, String savedCredential,
             int requestedQuality, int userId)
             throws RemoteException {
+        if (!mLockPatternUtils.hasSecureLockScreen()) {
+            throw new UnsupportedOperationException(
+                    "This operation requires secure lock screen feature");
+        }
         checkWritePermission(userId);
         synchronized (mSeparateChallengeLock) {
             setLockCredentialInternal(credential, type, savedCredential, requestedQuality, userId);
@@ -2103,11 +2111,24 @@
     }
 
     @Override
-    public @Nullable String importKey(@NonNull String alias, byte[] keyBytes) throws RemoteException {
+    public @Nullable String generateKeyWithMetadata(
+            @NonNull String alias, @Nullable byte[] metadata) throws RemoteException {
+        return mRecoverableKeyStoreManager.generateKeyWithMetadata(alias, metadata);
+    }
+
+    @Override
+    public @Nullable String importKey(@NonNull String alias, @NonNull byte[] keyBytes)
+            throws RemoteException {
         return mRecoverableKeyStoreManager.importKey(alias, keyBytes);
     }
 
     @Override
+    public @Nullable String importKeyWithMetadata(@NonNull String alias, @NonNull byte[] keyBytes,
+            @Nullable byte[] metadata) throws RemoteException {
+        return mRecoverableKeyStoreManager.importKeyWithMetadata(alias, keyBytes, metadata);
+    }
+
+    @Override
     public @Nullable String getKey(@NonNull String alias) throws RemoteException {
         return mRecoverableKeyStoreManager.getKey(alias);
     }
@@ -2893,6 +2914,10 @@
         @Override
         public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
                 byte[] token, int requestedQuality, int userId) {
+            if (!mLockPatternUtils.hasSecureLockScreen()) {
+                throw new UnsupportedOperationException(
+                        "This operation requires secure lock screen feature.");
+            }
             try {
                 return LockSettingsService.this.setLockCredentialWithToken(credential, type,
                         tokenHandle, token, requestedQuality, userId);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index 07f23ce..6163077 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -18,6 +18,7 @@
 
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+
 import static com.android.internal.widget.LockPatternUtils.stringToPattern;
 
 import android.app.ActivityManager;
@@ -58,6 +59,18 @@
             mCurrentUserId = ActivityManager.getService().getCurrentUser().id;
 
             parseArgs();
+            if (!mLockPatternUtils.hasSecureLockScreen()) {
+                switch (cmd) {
+                    case COMMAND_HELP:
+                    case COMMAND_GET_DISABLED:
+                    case COMMAND_SET_DISABLED:
+                        break;
+                    default:
+                        getErrPrintWriter().println(
+                                "The device does not support lock screen - ignoring the command.");
+                        return -1;
+                }
+            }
             if (!checkCredential()) {
                 return -1;
             }
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index f1951b1..1f9b027 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -26,6 +26,7 @@
 import android.security.keystore.recovery.KeyDerivationParams;
 import android.security.keystore.recovery.WrappedApplicationKey;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
@@ -258,9 +259,9 @@
             localLskfHash = hashCredentialsBySaltedSha256(salt, mCredential);
         }
 
-        Map<String, SecretKey> rawKeys;
+        Map<String, Pair<SecretKey, byte[]>> rawKeysWithMetadata;
         try {
-            rawKeys = getKeysToSync(recoveryAgentUid);
+            rawKeysWithMetadata = getKeysToSync(recoveryAgentUid);
         } catch (GeneralSecurityException e) {
             Log.e(TAG, "Failed to load recoverable keys for sync", e);
             return;
@@ -278,7 +279,9 @@
         }
         // Only include insecure key material for test
         if (mTestOnlyInsecureCertificateHelper.isTestOnlyCertificateAlias(rootCertAlias)) {
-            rawKeys = mTestOnlyInsecureCertificateHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
+            rawKeysWithMetadata =
+                    mTestOnlyInsecureCertificateHelper.keepOnlyWhitelistedInsecureKeys(
+                            rawKeysWithMetadata);
         }
 
         SecretKey recoveryKey;
@@ -292,7 +295,7 @@
         Map<String, byte[]> encryptedApplicationKeys;
         try {
             encryptedApplicationKeys = KeySyncUtils.encryptKeysWithRecoveryKey(
-                    recoveryKey, rawKeys);
+                    recoveryKey, rawKeysWithMetadata);
         } catch (InvalidKeyException | NoSuchAlgorithmException e) {
             Log.wtf(TAG,
                     "Should be impossible: could not encrypt application keys with random key",
@@ -356,7 +359,8 @@
                 .setCounterId(counterId)
                 .setServerParams(vaultHandle)
                 .setKeyChainProtectionParams(metadataList)
-                .setWrappedApplicationKeys(createApplicationKeyEntries(encryptedApplicationKeys))
+                .setWrappedApplicationKeys(
+                        createApplicationKeyEntries(encryptedApplicationKeys, rawKeysWithMetadata))
                 .setEncryptedRecoveryKeyBlob(encryptedRecoveryKey);
         try {
             keyChainSnapshotBuilder.setTrustedHardwareCertPath(certPath);
@@ -405,7 +409,7 @@
     /**
      * Returns all of the recoverable keys for the user.
      */
-    private Map<String, SecretKey> getKeysToSync(int recoveryAgentUid)
+    private Map<String, Pair<SecretKey, byte[]>> getKeysToSync(int recoveryAgentUid)
             throws InsecureUserException, KeyStoreException, UnrecoverableKeyException,
             NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException,
             InvalidKeyException, InvalidAlgorithmParameterException, IOException {
@@ -521,12 +525,14 @@
     }
 
     private static List<WrappedApplicationKey> createApplicationKeyEntries(
-            Map<String, byte[]> encryptedApplicationKeys) {
+            Map<String, byte[]> encryptedApplicationKeys,
+            Map<String, Pair<SecretKey, byte[]>> originalKeysWithMetadata) {
         ArrayList<WrappedApplicationKey> keyEntries = new ArrayList<>();
         for (String alias : encryptedApplicationKeys.keySet()) {
             keyEntries.add(new WrappedApplicationKey.Builder()
                     .setAlias(alias)
                     .setEncryptedKeyMaterial(encryptedApplicationKeys.get(alias))
+                    .setMetadata(originalKeysWithMetadata.get(alias).second)
                     .build());
         }
         return keyEntries;
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
index 8e6f9cb..24d575e 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
@@ -16,6 +16,9 @@
 
 package com.android.server.locksettings.recoverablekeystore;
 
+import android.annotation.Nullable;
+import android.util.Pair;
+
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.nio.ByteBuffer;
@@ -152,15 +155,28 @@
      * @hide
      */
     public static Map<String, byte[]> encryptKeysWithRecoveryKey(
-            SecretKey recoveryKey, Map<String, SecretKey> keys)
+            SecretKey recoveryKey, Map<String, Pair<SecretKey, byte[]>> keys)
             throws NoSuchAlgorithmException, InvalidKeyException {
         HashMap<String, byte[]> encryptedKeys = new HashMap<>();
         for (String alias : keys.keySet()) {
-            SecretKey key = keys.get(alias);
+            SecretKey key = keys.get(alias).first;
+            byte[] metadata = keys.get(alias).second;
+            byte[] header;
+            if (metadata == null) {
+                header = ENCRYPTED_APPLICATION_KEY_HEADER;
+            } else {
+                // The provided metadata, if non-empty, will be bound to the authenticated
+                // encryption process of the key material. As a result, the ciphertext cannot be
+                // decrypted if a wrong metadata is provided during the recovery/decryption process.
+                // Note that Android P devices do not have the API to provide the optional metadata,
+                // so all the keys with non-empty metadata stored on Android Q+ devices cannot be
+                // recovered on Android P devices.
+                header = concat(ENCRYPTED_APPLICATION_KEY_HEADER, metadata);
+            }
             byte[] encryptedKey = SecureBox.encrypt(
                     /*theirPublicKey=*/ null,
                     /*sharedSecret=*/ recoveryKey.getEncoded(),
-                    /*header=*/ ENCRYPTED_APPLICATION_KEY_HEADER,
+                    /*header=*/ header,
                     /*payload=*/ key.getEncoded());
             encryptedKeys.put(alias, encryptedKey);
         }
@@ -257,12 +273,19 @@
      * @throws AEADBadTagException if the message has been tampered with or was encrypted with a
      *     different key.
      */
-    public static byte[] decryptApplicationKey(byte[] recoveryKey, byte[] encryptedApplicationKey)
+    public static byte[] decryptApplicationKey(byte[] recoveryKey, byte[] encryptedApplicationKey,
+            @Nullable byte[] applicationKeyMetadata)
             throws NoSuchAlgorithmException, InvalidKeyException, AEADBadTagException {
+        byte[] header;
+        if (applicationKeyMetadata == null) {
+            header = ENCRYPTED_APPLICATION_KEY_HEADER;
+        } else {
+            header = concat(ENCRYPTED_APPLICATION_KEY_HEADER, applicationKeyMetadata);
+        }
         return SecureBox.decrypt(
                 /*ourPrivateKey=*/ null,
                 /*sharedSecret=*/ recoveryKey,
-                /*header=*/ ENCRYPTED_APPLICATION_KEY_HEADER,
+                /*header=*/ header,
                 /*encryptedPayload=*/ encryptedApplicationKey);
     }
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
index c249468..1692e5c 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
@@ -17,6 +17,8 @@
 package com.android.server.locksettings.recoverablekeystore;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
 
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
 
@@ -24,7 +26,6 @@
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.util.Locale;
-import android.util.Log;
 
 import javax.crypto.KeyGenerator;
 import javax.crypto.SecretKey;
@@ -84,6 +85,8 @@
      * @param userId The user ID of the profile to which the calling app belongs.
      * @param uid The uid of the application that will own the key.
      * @param alias The alias by which the key will be known in the recoverable key store.
+     * @param metadata The optional metadata that will be authenticated (but unencrypted) together
+     *     with the key material when the key is uploaded to cloud.
      * @throws RecoverableKeyStorageException if there is some error persisting the key either to
      *     the database.
      * @throws KeyStoreException if there is a KeyStore error wrapping the generated key.
@@ -92,12 +95,13 @@
      * @hide
      */
     public byte[] generateAndStoreKey(
-            PlatformEncryptionKey platformKey, int userId, int uid, String alias)
+            PlatformEncryptionKey platformKey, int userId, int uid, String alias,
+            @Nullable byte[] metadata)
             throws RecoverableKeyStorageException, KeyStoreException, InvalidKeyException {
         mKeyGenerator.init(KEY_SIZE_BITS);
         SecretKey key = mKeyGenerator.generateKey();
 
-        WrappedKey wrappedKey = WrappedKey.fromSecretKey(platformKey, key);
+        WrappedKey wrappedKey = WrappedKey.fromSecretKey(platformKey, key, metadata);
         long result = mDatabase.insertKey(userId, uid, alias, wrappedKey);
 
         if (result == RESULT_CANNOT_INSERT_ROW) {
@@ -126,6 +130,8 @@
      * @param uid The uid of the application that will own the key.
      * @param alias The alias by which the key will be known in the recoverable key store.
      * @param keyBytes The raw bytes of the AES key to be imported.
+     * @param metadata The optional metadata that will be authenticated (but unencrypted) together
+     *     with the key material when the key is uploaded to cloud.
      * @throws RecoverableKeyStorageException if there is some error persisting the key either to
      *     the database.
      * @throws KeyStoreException if there is a KeyStore error wrapping the generated key.
@@ -135,11 +141,11 @@
      */
     public void importKey(
             @NonNull PlatformEncryptionKey platformKey, int userId, int uid, @NonNull String alias,
-            @NonNull byte[] keyBytes)
+            @NonNull byte[] keyBytes, @Nullable byte[] metadata)
             throws RecoverableKeyStorageException, KeyStoreException, InvalidKeyException {
         SecretKey key = new SecretKeySpec(keyBytes, SECRET_KEY_ALGORITHM);
 
-        WrappedKey wrappedKey = WrappedKey.fromSecretKey(platformKey, key);
+        WrappedKey wrappedKey = WrappedKey.fromSecretKey(platformKey, key, metadata);
         long result = mDatabase.insertKey(userId, uid, alias, wrappedKey);
 
         if (result == RESULT_CANNOT_INSERT_ROW) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index fc5184d..ed864c0 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -20,8 +20,8 @@
 import static android.security.keystore.recovery.RecoveryController.ERROR_DECRYPTION_FAILED;
 import static android.security.keystore.recovery.RecoveryController.ERROR_DOWNGRADE_CERTIFICATE;
 import static android.security.keystore.recovery.RecoveryController.ERROR_INSECURE_USER;
-import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_KEY_FORMAT;
 import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_CERTIFICATE;
+import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_KEY_FORMAT;
 import static android.security.keystore.recovery.RecoveryController.ERROR_NO_SNAPSHOT_PENDING;
 import static android.security.keystore.recovery.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR;
 import static android.security.keystore.recovery.RecoveryController.ERROR_SESSION_EXPIRED;
@@ -35,12 +35,12 @@
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.UserHandle;
+import android.security.KeyStore;
 import android.security.keystore.recovery.KeyChainProtectionParams;
 import android.security.keystore.recovery.KeyChainSnapshot;
 import android.security.keystore.recovery.RecoveryCertPath;
 import android.security.keystore.recovery.RecoveryController;
 import android.security.keystore.recovery.WrappedApplicationKey;
-import android.security.KeyStore;
 import android.util.ArrayMap;
 import android.util.Log;
 
@@ -59,7 +59,6 @@
 
 import java.io.IOException;
 import java.security.InvalidKeyException;
-import java.security.KeyFactory;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
@@ -70,7 +69,6 @@
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.security.spec.InvalidKeySpecException;
-import java.security.spec.X509EncodedKeySpec;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -606,7 +604,8 @@
 
         try {
             byte[] recoveryKey = decryptRecoveryKey(sessionEntry, encryptedRecoveryKey);
-            Map<String, byte[]> keysByAlias = recoverApplicationKeys(recoveryKey, applicationKeys);
+            Map<String, byte[]> keysByAlias = recoverApplicationKeys(recoveryKey,
+                    applicationKeys);
             return importKeyMaterials(userId, uid, keysByAlias);
         } catch (KeyStoreException e) {
             throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
@@ -625,7 +624,8 @@
      * @throws KeyStoreException if an error occurs importing the key or getting the grant.
      */
     private @NonNull Map<String, String> importKeyMaterials(
-            int userId, int uid, Map<String, byte[]> keysByAlias) throws KeyStoreException {
+            int userId, int uid, Map<String, byte[]> keysByAlias)
+            throws KeyStoreException {
         ArrayMap<String, String> grantAliasesByAlias = new ArrayMap<>(keysByAlias.size());
         for (String alias : keysByAlias.keySet()) {
             mApplicationKeyStorage.setSymmetricKeyEntry(userId, uid, alias, keysByAlias.get(alias));
@@ -674,9 +674,29 @@
      * Generates a key named {@code alias} in caller's namespace.
      * The key is stored in system service keystore namespace.
      *
+     * @param alias the alias provided by caller as a reference to the key.
      * @return grant alias, which caller can use to access the key.
+     * @throws RemoteException if certain internal errors occur.
+     *
+     * @deprecated Use {@link #generateKeyWithMetadata(String, byte[])} instead.
      */
+    @Deprecated
     public String generateKey(@NonNull String alias) throws RemoteException {
+        return generateKeyWithMetadata(alias, /*metadata=*/ null);
+    }
+
+    /**
+     * Generates a key named {@code alias} with the {@code metadata} in caller's namespace.
+     * The key is stored in system service keystore namespace.
+     *
+     * @param alias the alias provided by caller as a reference to the key.
+     * @param metadata the optional metadata blob that will authenticated (but unencrypted) together
+     *         with the key material when the key is uploaded to cloud.
+     * @return grant alias, which caller can use to access the key.
+     * @throws RemoteException if certain internal errors occur.
+     */
+    public String generateKeyWithMetadata(@NonNull String alias, @Nullable byte[] metadata)
+            throws RemoteException {
         checkRecoverKeyStorePermission();
         Preconditions.checkNotNull(alias, "alias is null");
         int uid = Binder.getCallingUid();
@@ -695,8 +715,8 @@
         }
 
         try {
-            byte[] secretKey =
-                    mRecoverableKeyGenerator.generateAndStoreKey(encryptionKey, userId, uid, alias);
+            byte[] secretKey = mRecoverableKeyGenerator.generateAndStoreKey(encryptionKey, userId,
+                    uid, alias, metadata);
             mApplicationKeyStorage.setSymmetricKeyEntry(userId, uid, alias, secretKey);
             return getAlias(userId, uid, alias);
         } catch (KeyStoreException | InvalidKeyException | RecoverableKeyStorageException e) {
@@ -713,10 +733,30 @@
      * @return grant alias, which caller can use to access the key.
      * @throws RemoteException if the given key is invalid or some internal errors occur.
      *
+     * @deprecated Use {{@link #importKeyWithMetadata(String, byte[], byte[])}} instead.
+     *
      * @hide
      */
+    @Deprecated
     public @Nullable String importKey(@NonNull String alias, @NonNull byte[] keyBytes)
             throws RemoteException {
+        return importKeyWithMetadata(alias, keyBytes, /*metadata=*/ null);
+    }
+
+    /**
+     * Imports a 256-bit AES-GCM key named {@code alias} with the given {@code metadata}. The key is
+     * stored in system service keystore namespace.
+     *
+     * @param alias the alias provided by caller as a reference to the key.
+     * @param keyBytes the raw bytes of the 256-bit AES key.
+     * @param metadata the metadata to be authenticated (but unencrypted) together with the key.
+     * @return grant alias, which caller can use to access the key.
+     * @throws RemoteException if the given key is invalid or some internal errors occur.
+     *
+     * @hide
+     */
+    public @Nullable String importKeyWithMetadata(@NonNull String alias, @NonNull byte[] keyBytes,
+            @Nullable byte[] metadata) throws RemoteException {
         checkRecoverKeyStorePermission();
         Preconditions.checkNotNull(alias, "alias is null");
         Preconditions.checkNotNull(keyBytes, "keyBytes is null");
@@ -745,7 +785,8 @@
 
         try {
             // Wrap the key by the platform key and store the wrapped key locally
-            mRecoverableKeyGenerator.importKey(encryptionKey, userId, uid, alias, keyBytes);
+            mRecoverableKeyGenerator.importKey(encryptionKey, userId, uid, alias, keyBytes,
+                    metadata);
 
             // Import the key to Android KeyStore and get grant
             mApplicationKeyStorage.setSymmetricKeyEntry(userId, uid, alias, keyBytes);
@@ -812,17 +853,17 @@
      * @return Map from alias to raw key material.
      * @throws RemoteException if an error occurred decrypting the keys.
      */
-    private @NonNull Map<String, byte[]> recoverApplicationKeys(
-            @NonNull byte[] recoveryKey,
+    private @NonNull Map<String, byte[]> recoverApplicationKeys(@NonNull byte[] recoveryKey,
             @NonNull List<WrappedApplicationKey> applicationKeys) throws RemoteException {
         HashMap<String, byte[]> keyMaterialByAlias = new HashMap<>();
         for (WrappedApplicationKey applicationKey : applicationKeys) {
             String alias = applicationKey.getAlias();
             byte[] encryptedKeyMaterial = applicationKey.getEncryptedKeyMaterial();
+            byte[] keyMetadata = applicationKey.getMetadata();
 
             try {
-                byte[] keyMaterial =
-                        KeySyncUtils.decryptApplicationKey(recoveryKey, encryptedKeyMaterial);
+                byte[] keyMaterial = KeySyncUtils.decryptApplicationKey(recoveryKey,
+                        encryptedKeyMaterial, keyMetadata);
                 keyMaterialByAlias.put(alias, keyMaterial);
             } catch (NoSuchAlgorithmException e) {
                 Log.wtf(TAG, "Missing SecureBox algorithm. AOSP required to support this.", e);
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
index 5ba3cce..057429c 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
@@ -18,17 +18,20 @@
 
 import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_CERTIFICATE;
 
-import com.android.internal.widget.LockPatternUtils;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.security.keystore.recovery.TrustedRootCertificates;
 import android.util.Log;
+import android.util.Pair;
 
-import java.util.HashMap;
+import com.android.internal.widget.LockPatternUtils;
+
 import java.security.cert.X509Certificate;
+import java.util.HashMap;
 import java.util.Map;
+
 import javax.crypto.SecretKey;
 
 /**
@@ -90,16 +93,18 @@
             && credential.startsWith(TrustedRootCertificates.INSECURE_PASSWORD_PREFIX);
     }
 
-    public Map<String, SecretKey> keepOnlyWhitelistedInsecureKeys(Map<String, SecretKey> rawKeys) {
+    public Map<String, Pair<SecretKey, byte[]>> keepOnlyWhitelistedInsecureKeys(
+            Map<String, Pair<SecretKey, byte[]>> rawKeys) {
         if (rawKeys == null) {
             return null;
         }
-        Map<String, SecretKey> filteredKeys = new HashMap<>();
-        for (Map.Entry<String, SecretKey> entry : rawKeys.entrySet()) {
+        Map<String, Pair<SecretKey, byte[]>> filteredKeys = new HashMap<>();
+        for (Map.Entry<String, Pair<SecretKey, byte[]>> entry : rawKeys.entrySet()) {
             String alias = entry.getKey();
             if (alias != null
                     && alias.startsWith(TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX)) {
-                filteredKeys.put(entry.getKey(), entry.getValue());
+                filteredKeys.put(entry.getKey(),
+                        Pair.create(entry.getValue().first, entry.getValue().second));
                 Log.d(TAG, "adding key with insecure alias " + alias + " to the recovery snapshot");
             }
         }
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
index 0077242..09d7541 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java
@@ -16,8 +16,10 @@
 
 package com.android.server.locksettings.recoverablekeystore;
 
+import android.annotation.Nullable;
 import android.security.keystore.recovery.RecoveryController;
 import android.util.Log;
+import android.util.Pair;
 
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
@@ -49,6 +51,7 @@
     private final int mRecoveryStatus;
     private final byte[] mNonce;
     private final byte[] mKeyMaterial;
+    private final byte[] mKeyMetadata;
 
     /**
      * Returns a wrapped form of {@code key}, using {@code wrappingKey} to encrypt the key material.
@@ -58,7 +61,8 @@
      *     {@link android.security.keystore.AndroidKeyStoreKey} for an example of a key that does
      *     not expose its key material.
      */
-    public static WrappedKey fromSecretKey(PlatformEncryptionKey wrappingKey, SecretKey key)
+    public static WrappedKey fromSecretKey(PlatformEncryptionKey wrappingKey, SecretKey key,
+            @Nullable byte[] metadata)
             throws InvalidKeyException, KeyStoreException {
         if (key.getEncoded() == null) {
             throw new InvalidKeyException(
@@ -96,6 +100,7 @@
         return new WrappedKey(
                 /*nonce=*/ cipher.getIV(),
                 /*keyMaterial=*/ encryptedKeyMaterial,
+                /*keyMetadata=*/ metadata,
                 /*platformKeyGenerationId=*/ wrappingKey.getGenerationId(),
                 RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
     }
@@ -110,11 +115,10 @@
      * @see RecoveryController#RECOVERY_STATUS_SYNC_IN_PROGRESS
      * @hide
      */
-    public WrappedKey(byte[] nonce, byte[] keyMaterial, int platformKeyGenerationId) {
-        mNonce = nonce;
-        mKeyMaterial = keyMaterial;
-        mPlatformKeyGenerationId = platformKeyGenerationId;
-        mRecoveryStatus = RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS;
+    public WrappedKey(byte[] nonce, byte[] keyMaterial, @Nullable byte[] keyMetadata,
+            int platformKeyGenerationId) {
+        this(nonce, keyMaterial, keyMetadata, platformKeyGenerationId,
+                RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
     }
 
     /**
@@ -122,15 +126,18 @@
      *
      * @param nonce The nonce with which the key material was encrypted.
      * @param keyMaterial The encrypted bytes of the key material.
+     * @param keyMetadata The metadata that will be authenticated (but unencrypted) together with
+     *     the key material when the key is uploaded to cloud.
      * @param platformKeyGenerationId The generation ID of the key used to wrap this key.
      * @param recoveryStatus recovery status of the key.
      *
      * @hide
      */
-    public WrappedKey(byte[] nonce, byte[] keyMaterial, int platformKeyGenerationId,
-            int recoveryStatus) {
+    public WrappedKey(byte[] nonce, byte[] keyMaterial, @Nullable byte[] keyMetadata,
+            int platformKeyGenerationId, int recoveryStatus) {
         mNonce = nonce;
         mKeyMaterial = keyMaterial;
+        mKeyMetadata = keyMetadata;
         mPlatformKeyGenerationId = platformKeyGenerationId;
         mRecoveryStatus = recoveryStatus;
     }
@@ -154,6 +161,15 @@
     }
 
     /**
+     * Returns the key metadata.
+     *
+     * @hide
+     */
+    public @Nullable byte[] getKeyMetadata() {
+        return mKeyMetadata;
+    }
+
+    /**
      * Returns the generation ID of the platform key, with which this key was wrapped.
      *
      * @hide
@@ -181,12 +197,12 @@
      *
      * @hide
      */
-    public static Map<String, SecretKey> unwrapKeys(
+    public static Map<String, Pair<SecretKey, byte[]>> unwrapKeys(
             PlatformDecryptionKey platformKey,
             Map<String, WrappedKey> wrappedKeys)
             throws NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException,
             InvalidKeyException, InvalidAlgorithmParameterException {
-        HashMap<String, SecretKey> unwrappedKeys = new HashMap<>();
+        HashMap<String, Pair<SecretKey, byte[]>> unwrappedKeys = new HashMap<>();
         Cipher cipher = Cipher.getInstance(KEY_WRAP_CIPHER_ALGORITHM);
         int platformKeyGenerationId = platformKey.getGenerationId();
 
@@ -219,7 +235,7 @@
                         e);
                 continue;
             }
-            unwrappedKeys.put(alias, key);
+            unwrappedKeys.put(alias, Pair.create(key, wrappedKey.getKeyMetadata()));
         }
 
         return unwrappedKeys;
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
index b486834..8a19d62 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
@@ -23,19 +23,18 @@
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEYS;
-
-import static com.android.server.locksettings.recoverablekeystore.serialization
-        .KeyChainSnapshotSchema.TAG_BACKEND_PUBLIC_KEY;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_BACKEND_PUBLIC_KEY;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_COUNTER_ID;
-import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_RECOVERY_KEY_MATERIAL;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_SNAPSHOT;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_DERIVATION_PARAMS;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_MATERIAL;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_METADATA;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_LOCK_SCREEN_UI_TYPE;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MAX_ATTEMPTS;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MEMORY_DIFFICULTY;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_RECOVERY_KEY_MATERIAL;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SALT;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SERVER_PARAMS;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SNAPSHOT_VERSION;
@@ -49,6 +48,9 @@
 import android.util.Base64;
 import android.util.Xml;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -59,9 +61,6 @@
 import java.util.List;
 import java.util.Locale;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 /**
  * Deserializes a {@link android.security.keystore.recovery.KeyChainSnapshot} instance from XML.
  */
@@ -191,6 +190,10 @@
                     builder.setEncryptedKeyMaterial(readBlobTag(parser, TAG_KEY_MATERIAL));
                     break;
 
+                case TAG_KEY_METADATA:
+                    builder.setMetadata(readBlobTag(parser, TAG_KEY_METADATA));
+                    break;
+
                 default:
                     throw new KeyChainSnapshotParserException(String.format(
                             Locale.US, "Unexpected tag %s in wrappedApplicationKey", name));
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java
index 0f2c2fc..8f85a27 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java
@@ -52,6 +52,7 @@
     static final String TAG_APPLICATION_KEY = "applicationKey";
     static final String TAG_ALIAS = "alias";
     static final String TAG_KEY_MATERIAL = "keyMaterial";
+    static final String TAG_KEY_METADATA = "keyMetadata";
 
     // Statics only
     private KeyChainSnapshotSchema() {}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
index 235df69..527e879 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
@@ -24,25 +24,24 @@
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEYS;
-
-import static com.android.server.locksettings.recoverablekeystore.serialization
-        .KeyChainSnapshotSchema.TAG_BACKEND_PUBLIC_KEY;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_COUNTER_ID;
-import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_RECOVERY_KEY_MATERIAL;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_SNAPSHOT;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_DERIVATION_PARAMS;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_MATERIAL;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_METADATA;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_LOCK_SCREEN_UI_TYPE;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MAX_ATTEMPTS;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MEMORY_DIFFICULTY;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_RECOVERY_KEY_MATERIAL;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SALT;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SERVER_PARAMS;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SNAPSHOT_VERSION;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_TRUSTED_HARDWARE_CERT_PATH;
 import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_USER_SECRET_TYPE;
 
+import android.annotation.Nullable;
 import android.security.keystore.recovery.KeyChainProtectionParams;
 import android.security.keystore.recovery.KeyChainSnapshot;
 import android.security.keystore.recovery.KeyDerivationParams;
@@ -103,6 +102,7 @@
             XmlSerializer xmlSerializer, WrappedApplicationKey applicationKey) throws IOException {
         writePropertyTag(xmlSerializer, TAG_ALIAS, applicationKey.getAlias());
         writePropertyTag(xmlSerializer, TAG_KEY_MATERIAL, applicationKey.getEncryptedKeyMaterial());
+        writePropertyTag(xmlSerializer, TAG_KEY_METADATA, applicationKey.getMetadata());
     }
 
     private static void writeKeyChainProtectionParams(
@@ -181,8 +181,11 @@
     }
 
     private static void writePropertyTag(
-            XmlSerializer xmlSerializer, String propertyName, byte[] propertyValue)
+            XmlSerializer xmlSerializer, String propertyName, @Nullable byte[] propertyValue)
             throws IOException {
+        if (propertyValue == null) {
+            return;
+        }
         xmlSerializer.startTag(NAMESPACE, propertyName);
         xmlSerializer.text(Base64.encodeToString(propertyValue, /*flags=*/ Base64.DEFAULT));
         xmlSerializer.endTag(NAMESPACE, propertyName);
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
index e69f73d..dffaffe 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
@@ -104,6 +104,12 @@
         values.put(KeysEntry.COLUMN_NAME_LAST_SYNCED_AT, LAST_SYNCED_AT_UNSYNCED);
         values.put(KeysEntry.COLUMN_NAME_GENERATION_ID, wrappedKey.getPlatformKeyGenerationId());
         values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS, wrappedKey.getRecoveryStatus());
+        byte[] keyMetadata = wrappedKey.getKeyMetadata();
+        if (keyMetadata == null) {
+            values.putNull(KeysEntry.COLUMN_NAME_KEY_METADATA);
+        } else {
+            values.put(KeysEntry.COLUMN_NAME_KEY_METADATA, keyMetadata);
+        }
         return db.replace(KeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values);
     }
 
@@ -119,7 +125,8 @@
                 KeysEntry.COLUMN_NAME_NONCE,
                 KeysEntry.COLUMN_NAME_WRAPPED_KEY,
                 KeysEntry.COLUMN_NAME_GENERATION_ID,
-                KeysEntry.COLUMN_NAME_RECOVERY_STATUS};
+                KeysEntry.COLUMN_NAME_RECOVERY_STATUS,
+                KeysEntry.COLUMN_NAME_KEY_METADATA};
         String selection =
                 KeysEntry.COLUMN_NAME_UID + " = ? AND "
                 + KeysEntry.COLUMN_NAME_ALIAS + " = ?";
@@ -155,7 +162,17 @@
                     cursor.getColumnIndexOrThrow(KeysEntry.COLUMN_NAME_GENERATION_ID));
             int recoveryStatus = cursor.getInt(
                     cursor.getColumnIndexOrThrow(KeysEntry.COLUMN_NAME_RECOVERY_STATUS));
-            return new WrappedKey(nonce, keyMaterial, generationId, recoveryStatus);
+
+            // Retrieve the metadata associated with the key
+            byte[] keyMetadata;
+            int metadataIdx = cursor.getColumnIndexOrThrow(KeysEntry.COLUMN_NAME_KEY_METADATA);
+            if (cursor.isNull(metadataIdx)) {
+                keyMetadata = null;
+            } else {
+                keyMetadata = cursor.getBlob(metadataIdx);
+            }
+
+            return new WrappedKey(nonce, keyMaterial, keyMetadata, generationId, recoveryStatus);
         }
     }
 
@@ -252,7 +269,8 @@
                 KeysEntry.COLUMN_NAME_NONCE,
                 KeysEntry.COLUMN_NAME_WRAPPED_KEY,
                 KeysEntry.COLUMN_NAME_ALIAS,
-                KeysEntry.COLUMN_NAME_RECOVERY_STATUS};
+                KeysEntry.COLUMN_NAME_RECOVERY_STATUS,
+                KeysEntry.COLUMN_NAME_KEY_METADATA};
         String selection =
                 KeysEntry.COLUMN_NAME_USER_ID + " = ? AND "
                 + KeysEntry.COLUMN_NAME_UID + " = ? AND "
@@ -283,8 +301,18 @@
                         cursor.getColumnIndexOrThrow(KeysEntry.COLUMN_NAME_ALIAS));
                 int recoveryStatus = cursor.getInt(
                         cursor.getColumnIndexOrThrow(KeysEntry.COLUMN_NAME_RECOVERY_STATUS));
-                keys.put(alias, new WrappedKey(nonce, keyMaterial, platformKeyGenerationId,
-                        recoveryStatus));
+
+                // Retrieve the metadata associated with the key
+                byte[] keyMetadata;
+                int metadataIdx = cursor.getColumnIndexOrThrow(KeysEntry.COLUMN_NAME_KEY_METADATA);
+                if (cursor.isNull(metadataIdx)) {
+                    keyMetadata = null;
+                } else {
+                    keyMetadata = cursor.getBlob(metadataIdx);
+                }
+
+                keys.put(alias, new WrappedKey(nonce, keyMaterial, keyMetadata,
+                        platformKeyGenerationId, recoveryStatus));
             }
             return keys;
         }
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
index 22e77cc..b58ee4b 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
@@ -67,6 +67,12 @@
          * Status of the key sync {@code RecoveryController#setRecoveryStatus}
          */
         static final String COLUMN_NAME_RECOVERY_STATUS = "recovery_status";
+
+        /**
+         * Data blob that will be authenticated (but encrypted) together with the key when the key
+         * is uploaded to cloud.
+         */
+        static final String COLUMN_NAME_KEY_METADATA = "key_metadata";
     }
 
     /**
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
index 43efe9c..b0613da 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelper.java
@@ -32,7 +32,7 @@
 class RecoverableKeyStoreDbHelper extends SQLiteOpenHelper {
     private static final String TAG = "RecoverableKeyStoreDbHp";
 
-    static final int DATABASE_VERSION = 4;
+    static final int DATABASE_VERSION = 5;
     private static final String DATABASE_NAME = "recoverablekeystore.db";
 
     private static final String SQL_CREATE_KEYS_ENTRY =
@@ -46,6 +46,7 @@
                     + KeysEntry.COLUMN_NAME_GENERATION_ID + " INTEGER,"
                     + KeysEntry.COLUMN_NAME_LAST_SYNCED_AT + " INTEGER,"
                     + KeysEntry.COLUMN_NAME_RECOVERY_STATUS + " INTEGER,"
+                    + KeysEntry.COLUMN_NAME_KEY_METADATA + " BLOB,"
                     + "UNIQUE(" + KeysEntry.COLUMN_NAME_UID + ","
                     + KeysEntry.COLUMN_NAME_ALIAS + "))";
 
@@ -135,6 +136,11 @@
             oldVersion = 4;
         }
 
+        if (oldVersion < 5 && newVersion >= 5) {
+            upgradeDbForVersion5(db);
+            oldVersion = 5;
+        }
+
         if (oldVersion != newVersion) {
             Log.e(TAG, "Failed to update recoverablekeystore database to the most recent version");
         }
@@ -166,6 +172,13 @@
                 /*defaultStr=*/ null);
     }
 
+    private void upgradeDbForVersion5(SQLiteDatabase db) {
+        Log.d(TAG, "Updating recoverable keystore database to version 5");
+        // adds a column to store the metadata for application keys
+        addColumnToTable(db, KeysEntry.TABLE_NAME,
+                KeysEntry.COLUMN_NAME_KEY_METADATA, "BLOB", /*defaultStr=*/ null);
+    }
+
     private static void addColumnToTable(
             SQLiteDatabase db, String tableName, String column, String columnType,
             String defaultStr) {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index dd2abde..af790f2 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -27,15 +27,14 @@
 import android.media.Rating;
 import android.media.VolumeProvider;
 import android.media.session.ControllerCallbackLink;
-import android.media.session.ISession;
-import android.media.session.ISessionController;
+import android.media.session.ControllerLink;
 import android.media.session.MediaController;
 import android.media.session.MediaController.PlaybackInfo;
 import android.media.session.MediaSession;
 import android.media.session.MediaSession.QueueItem;
-import android.media.session.ParcelableVolumeInfo;
 import android.media.session.PlaybackState;
 import android.media.session.SessionCallbackLink;
+import android.media.session.SessionLink;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -78,10 +77,11 @@
     private final int mUserId;
     private final String mPackageName;
     private final String mTag;
-    private final ControllerStub mController;
-    private final SessionStub mSession;
+    private final ControllerLink mController;
+    private final MediaSession.Token mSessionToken;
+    private final SessionLink mSession;
     private final SessionCb mSessionCb;
-    private final MediaSessionService mService;
+    private final MediaSessionService.ServiceImpl mService;
     private final Context mContext;
 
     private final Object mLock = new Object();
@@ -117,18 +117,20 @@
     private boolean mIsActive = false;
     private boolean mDestroyed = false;
 
-    private long mDuration;
+    private long mDuration = -1;
     private String mMetadataDescription;
 
     public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
-            SessionCallbackLink cb, String tag, MediaSessionService service, Looper handlerLooper) {
+            SessionCallbackLink cb, String tag, MediaSessionService.ServiceImpl service,
+            Looper handlerLooper) {
         mOwnerPid = ownerPid;
         mOwnerUid = ownerUid;
         mUserId = userId;
         mPackageName = ownerPackageName;
         mTag = tag;
-        mController = new ControllerStub();
-        mSession = new SessionStub();
+        mController = new ControllerLink(new ControllerStub());
+        mSessionToken = new MediaSession.Token(mController);
+        mSession = new SessionLink(new SessionStub());
         mSessionCb = new SessionCb(cb);
         mService = service;
         mContext = mService.getContext();
@@ -139,24 +141,33 @@
     }
 
     /**
-     * Get the binder for the {@link MediaSession}.
+     * Get the session link for the {@link MediaSession}.
      *
-     * @return The session binder apps talk to.
+     * @return The session link apps talk to.
      */
-    public ISession getSessionBinder() {
+    public SessionLink getSessionBinder() {
         return mSession;
     }
 
     /**
-     * Get the binder for the {@link MediaController}.
+     * Get the controller link for the {@link MediaController}.
      *
-     * @return The controller binder apps talk to.
+     * @return The controller link apps talk to.
      */
-    public ISessionController getControllerBinder() {
+    public ControllerLink getControllerLink() {
         return mController;
     }
 
     /**
+     * Get the session token for creating {@link MediaController}.
+     *
+     * @return The session token.
+     */
+    public MediaSession.Token getSessionToken() {
+        return mSessionToken;
+    }
+
+    /**
      * Get the info for this session.
      *
      * @return Info that identifies this session.
@@ -236,6 +247,7 @@
      * {@link AudioManager#ADJUST_SAME}.
      *
      * @param packageName The package that made the original volume request.
+     * @param opPackageName The op package that made the original volume request.
      * @param pid The pid that made the original volume request.
      * @param uid The uid that made the original volume request.
      * @param caller caller binder. can be {@code null} if it's from the volume key.
@@ -248,7 +260,7 @@
      * @param flags Any of the flags from {@link AudioManager}.
      * @param useSuggested True to use adjustSuggestedStreamVolume instead of
      */
-    public void adjustVolume(String packageName, int pid, int uid,
+    public void adjustVolume(String packageName, String opPackageName, int pid, int uid,
             ControllerCallbackLink caller, boolean asSystemService, int direction, int flags,
             boolean useSuggested) {
         int previousFlagPlaySound = flags & AudioManager.FLAG_PLAY_SOUND;
@@ -258,8 +270,8 @@
         if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
             // Adjust the volume with a handler not to be blocked by other system service.
             int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
-            postAdjustLocalVolume(stream, direction, flags, packageName, uid, asSystemService,
-                    useSuggested, previousFlagPlaySound);
+            postAdjustLocalVolume(stream, direction, flags, opPackageName, pid, uid,
+                    asSystemService, useSuggested, previousFlagPlaySound);
         } else {
             if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
                 // Nothing to do, the volume cannot be changed
@@ -290,11 +302,23 @@
         }
     }
 
-    private void setVolumeTo(String packageName, int pid, int uid,
+    private void setVolumeTo(String packageName, String opPackageName, int pid, int uid,
             ControllerCallbackLink caller, int value, int flags) {
         if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
             int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
-            mAudioManagerInternal.setStreamVolumeForUid(stream, value, flags, packageName, uid);
+            final int volumeValue = value;
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mAudioManagerInternal.setStreamVolumeForUid(stream, volumeValue, flags,
+                                opPackageName, uid);
+                    } catch (IllegalArgumentException | SecurityException e) {
+                        Log.e(TAG, "Cannot set volume: stream=" + stream + ", value=" + volumeValue
+                                + ", flags=" + flags, e);
+                    }
+                }
+            });
         } else {
             if (mVolumeControlType != VolumeProvider.VOLUME_CONTROL_ABSOLUTE) {
                 // Nothing to do. The volume can't be set directly.
@@ -465,11 +489,19 @@
     }
 
     private void postAdjustLocalVolume(final int stream, final int direction, final int flags,
-            final String callingPackageName, final int callingUid, final boolean asSystemService,
-            final boolean useSuggested, final int previousFlagPlaySound) {
-        final String packageName = asSystemService
-                ? mContext.getOpPackageName() : callingPackageName;
-        final int uid = asSystemService ? Process.SYSTEM_UID : callingUid;
+            final String callingOpPackageName, final int callingPid, final int callingUid,
+            final boolean asSystemService, final boolean useSuggested,
+            final int previousFlagPlaySound) {
+        // Must use opPackageName for adjusting volumes with UID.
+        final String opPackageName;
+        final int uid;
+        if (asSystemService) {
+            opPackageName = mContext.getOpPackageName();
+            uid = Process.SYSTEM_UID;
+        } else {
+            opPackageName = callingOpPackageName;
+            uid = callingUid;
+        }
         mHandler.post(new Runnable() {
             @Override
             public void run() {
@@ -477,19 +509,19 @@
                     if (useSuggested) {
                         if (AudioSystem.isStreamActive(stream, 0)) {
                             mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream,
-                                    direction, flags, packageName, uid);
+                                    direction, flags, opPackageName, uid);
                         } else {
                             mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
                                     AudioManager.USE_DEFAULT_STREAM_TYPE, direction,
-                                    flags | previousFlagPlaySound, packageName, uid);
+                                    flags | previousFlagPlaySound, opPackageName, uid);
                         }
                     } else {
                         mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
-                                packageName, uid);
+                                opPackageName, uid);
                     }
                 } catch (IllegalArgumentException | SecurityException e) {
                     Log.e(TAG, "Cannot adjust volume: direction=" + direction + ", stream="
-                            + stream + ", flags=" + flags + ", packageName=" + packageName
+                            + stream + ", flags=" + flags + ", opPackageName=" + opPackageName
                             + ", uid=" + uid + ", useSuggested=" + useSuggested
                             + ", previousFlagPlaySound=" + previousFlagPlaySound, e);
                 }
@@ -621,12 +653,11 @@
             if (mDestroyed) {
                 return;
             }
-            ParcelableVolumeInfo info = mController.getVolumeAttributes();
+            PlaybackInfo info = getVolumeAttributes();
             for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) {
                 ControllerCallbackLinkHolder holder = mControllerCallbackHolders.get(i);
                 try {
-                    holder.mCallback.notifyVolumeInfoChanged(info.volumeType, info.audioAttrs,
-                            info.controlType, info.maxVolume, info.currentVolume);
+                    holder.mCallback.notifyVolumeInfoChanged(info);
                 } catch (RuntimeException e) {
                     if (e.getCause() instanceof DeadObjectException) {
                         mControllerCallbackHolders.remove(i);
@@ -730,6 +761,25 @@
         return -1;
     }
 
+    private PlaybackInfo getVolumeAttributes() {
+        int volumeType;
+        AudioAttributes attributes;
+        synchronized (mLock) {
+            if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
+                int current = mOptimisticVolume != -1 ? mOptimisticVolume : mCurrentVolume;
+                return new PlaybackInfo(mVolumeType, mVolumeControlType, mMaxVolume, current,
+                        mAudioAttrs);
+            }
+            volumeType = mVolumeType;
+            attributes = mAudioAttrs;
+        }
+        int stream = AudioAttributes.toLegacyStreamType(attributes);
+        int max = mAudioManager.getStreamMaxVolume(stream);
+        int current = mAudioManager.getStreamVolume(stream);
+        return new PlaybackInfo(volumeType, VolumeProvider.VOLUME_CONTROL_ABSOLUTE, max,
+                current, attributes);
+    }
+
     private final Runnable mClearOptimisticVolumeRunnable = new Runnable() {
         @Override
         public void run() {
@@ -741,9 +791,9 @@
         }
     };
 
-    private final class SessionStub extends ISession.Stub {
+    private final class SessionStub extends SessionLink.SessionStub {
         @Override
-        public void destroy() {
+        public void destroySession() {
             final long token = Binder.clearCallingIdentity();
             try {
                 mService.destroySession(MediaSessionRecord.this);
@@ -759,7 +809,7 @@
         }
 
         @Override
-        public ISessionController getController() {
+        public ControllerLink getController() {
             return mController;
         }
 
@@ -778,8 +828,8 @@
         @Override
         public void setFlags(int flags) {
             if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
-                int pid = getCallingPid();
-                int uid = getCallingUid();
+                int pid = Binder.getCallingPid();
+                int uid = Binder.getCallingUid();
                 mService.enforcePhoneStatePermission(pid, uid);
             }
             mFlags = flags;
@@ -1163,7 +1213,7 @@
         }
     }
 
-    class ControllerStub extends ISessionController.Stub {
+    class ControllerStub extends ControllerLink.ControllerStub {
         @Override
         public void sendCommand(String packageName, ControllerCallbackLink caller,
                 String command, Bundle args, ResultReceiver cb) {
@@ -1179,7 +1229,7 @@
         }
 
         @Override
-        public void registerCallbackListener(String packageName, ControllerCallbackLink cb) {
+        public void registerCallback(String packageName, ControllerCallbackLink cb) {
             synchronized (mLock) {
                 // If this session is already destroyed tell the caller and
                 // don't add them.
@@ -1203,7 +1253,7 @@
         }
 
         @Override
-        public void unregisterCallbackListener(ControllerCallbackLink cb) {
+        public void unregisterCallback(ControllerCallbackLink cb) {
             synchronized (mLock) {
                 int index = getControllerHolderIndexForCb(cb);
                 if (index != -1) {
@@ -1236,47 +1286,34 @@
         }
 
         @Override
-        public ParcelableVolumeInfo getVolumeAttributes() {
-            int volumeType;
-            AudioAttributes attributes;
-            synchronized (mLock) {
-                if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
-                    int current = mOptimisticVolume != -1 ? mOptimisticVolume : mCurrentVolume;
-                    return new ParcelableVolumeInfo(
-                            mVolumeType, mAudioAttrs, mVolumeControlType, mMaxVolume, current);
-                }
-                volumeType = mVolumeType;
-                attributes = mAudioAttrs;
-            }
-            int stream = AudioAttributes.toLegacyStreamType(attributes);
-            int max = mAudioManager.getStreamMaxVolume(stream);
-            int current = mAudioManager.getStreamVolume(stream);
-            return new ParcelableVolumeInfo(
-                    volumeType, attributes, VolumeProvider.VOLUME_CONTROL_ABSOLUTE, max, current);
+        public PlaybackInfo getVolumeAttributes() {
+            return MediaSessionRecord.this.getVolumeAttributes();
         }
 
         @Override
-        public void adjustVolume(String packageName, ControllerCallbackLink caller,
-                boolean asSystemService, int direction, int flags) {
+        public void adjustVolume(String packageName, String opPackageName,
+                ControllerCallbackLink caller, boolean asSystemService, int direction,
+                int flags) {
             int pid = Binder.getCallingPid();
             int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionRecord.this.adjustVolume(packageName, pid, uid, caller, asSystemService,
-                        direction, flags, false /* useSuggested */);
+                MediaSessionRecord.this.adjustVolume(packageName, opPackageName, pid, uid, caller,
+                        asSystemService, direction, flags, false /* useSuggested */);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
-        public void setVolumeTo(String packageName, ControllerCallbackLink caller,
-                int value, int flags) {
+        public void setVolumeTo(String packageName, String opPackageName,
+                ControllerCallbackLink caller, int value, int flags) {
             int pid = Binder.getCallingPid();
             int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionRecord.this.setVolumeTo(packageName, pid, uid, caller, value, flags);
+                MediaSessionRecord.this.setVolumeTo(packageName, opPackageName, pid, uid, caller,
+                        value, flags);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -1427,11 +1464,6 @@
         public int getRatingType() {
             return mRatingType;
         }
-
-        @Override
-        public boolean isTransportControlEnabled() {
-            return MediaSessionRecord.this.isTransportControlEnabled();
-        }
     }
 
     private class ControllerCallbackLinkHolder {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index b807c47..d20ed8c 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -16,69 +16,15 @@
 
 package com.android.server.media;
 
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.INotificationManager;
-import android.app.KeyguardManager;
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
-import android.database.ContentObserver;
-import android.media.AudioManager;
-import android.media.AudioPlaybackConfiguration;
-import android.media.AudioSystem;
-import android.media.IAudioService;
-import android.media.IRemoteVolumeController;
-import android.media.session.IActiveSessionsListener;
-import android.media.session.ICallback;
-import android.media.session.IOnMediaKeyListener;
-import android.media.session.IOnVolumeKeyLongPressListener;
-import android.media.session.ISession;
-import android.media.session.ISessionManager;
-import android.media.session.MediaSession;
-import android.media.session.MediaSessionManager;
-import android.media.session.SessionCallbackLink;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
+import android.media.Session2Token;
 import android.os.IBinder;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.speech.RecognizerIntent;
-import android.text.TextUtils;
 import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
 
-import com.android.internal.util.DumpUtils;
 import com.android.server.SystemService;
 import com.android.server.Watchdog;
 import com.android.server.Watchdog.Monitor;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -87,1824 +33,124 @@
 public class MediaSessionService extends SystemService implements Monitor {
     private static final String TAG = "MediaSessionService";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    // Leave log for key event always.
-    private static final boolean DEBUG_KEY_EVENT = true;
 
-    private static final int WAKELOCK_TIMEOUT = 5000;
-    private static final int MEDIA_KEY_LISTENER_TIMEOUT = 1000;
-
-    private final SessionManagerImpl mSessionManagerImpl;
-
-    // Keeps the full user id for each user.
-    private final SparseIntArray mFullUserIds = new SparseIntArray();
-    private final SparseArray<FullUserRecord> mUserRecords = new SparseArray<FullUserRecord>();
-    private final ArrayList<SessionsListenerRecord> mSessionsListeners
-            = new ArrayList<SessionsListenerRecord>();
-    private final Object mLock = new Object();
-    private final MessageHandler mHandler = new MessageHandler();
-    private final PowerManager.WakeLock mMediaEventWakeLock;
-    private final int mLongPressTimeout;
-    private final INotificationManager mNotificationManager;
-
-    private KeyguardManager mKeyguardManager;
-    private IAudioService mAudioService;
-    private ContentResolver mContentResolver;
-    private SettingsObserver mSettingsObserver;
-    private boolean mHasFeatureLeanback;
-
-    // The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile)
-    // It's always not null after the MediaSessionService is started.
-    private FullUserRecord mCurrentFullUserRecord;
-    private MediaSessionRecord mGlobalPrioritySession;
-    private AudioPlayerStateMonitor mAudioPlayerStateMonitor;
-
-    // Used to notify system UI when remote volume was changed. TODO find a
-    // better way to handle this.
-    private IRemoteVolumeController mRvc;
+    private final ServiceImpl mImpl;
 
     public MediaSessionService(Context context) {
         super(context);
-        mSessionManagerImpl = new SessionManagerImpl();
-        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
-        mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
-        mNotificationManager = INotificationManager.Stub.asInterface(
-                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+        mImpl = new MediaSessionServiceImpl(context);
     }
 
     @Override
     public void onStart() {
-        publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl);
+        publishBinderService(Context.MEDIA_SESSION_SERVICE, mImpl.getServiceBinder());
         Watchdog.getInstance().addMonitor(this);
-        mKeyguardManager =
-                (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
-        mAudioService = getAudioService();
-        mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
-        mAudioPlayerStateMonitor.registerListener(
-                (config, isRemoved) -> {
-                    if (isRemoved || !config.isActive() || config.getPlayerType()
-                            == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
-                        return;
-                    }
-                    synchronized (mLock) {
-                        FullUserRecord user = getFullUserRecordLocked(
-                                UserHandle.getUserId(config.getClientUid()));
-                        if (user != null) {
-                            user.mPriorityStack.updateMediaButtonSessionIfNeeded();
-                        }
-                    }
-                }, null /* handler */);
-        mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
-        mContentResolver = getContext().getContentResolver();
-        mSettingsObserver = new SettingsObserver();
-        mSettingsObserver.observe();
-        mHasFeatureLeanback = getContext().getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_LEANBACK);
 
-        updateUser();
+        mImpl.onStart();
     }
 
-    private IAudioService getAudioService() {
-        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
-        return IAudioService.Stub.asInterface(b);
+    @Override
+    public void onStartUser(int userId) {
+        mImpl.onStartUser(userId);
     }
 
-    private boolean isGlobalPriorityActiveLocked() {
-        return mGlobalPrioritySession != null && mGlobalPrioritySession.isActive();
+    @Override
+    public void onSwitchUser(int userId) {
+        mImpl.onSwitchUser(userId);
     }
 
+    // Called when the user with the userId is removed.
+    @Override
+    public void onStopUser(int userId) {
+        mImpl.onStopUser(userId);
+    }
+
+    @Override
+    public void monitor() {
+        mImpl.monitor();
+    }
+
+    /**
+     * Updates session.
+     */
     public void updateSession(MediaSessionRecord record) {
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
-            if (user == null) {
-                Log.w(TAG, "Unknown session updated. Ignoring.");
-                return;
-            }
-            if ((record.getFlags() & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
-                if (DEBUG_KEY_EVENT) {
-                    Log.d(TAG, "Global priority session is updated, active=" + record.isActive());
-                }
-                user.pushAddressedPlayerChangedLocked();
-            } else {
-                if (!user.mPriorityStack.contains(record)) {
-                    Log.w(TAG, "Unknown session updated. Ignoring.");
-                    return;
-                }
-                user.mPriorityStack.onSessionStateChange(record);
-            }
-            mHandler.postSessionsChanged(record.getUserId());
-        }
+        mImpl.updateSession(record);
     }
 
+    /**
+     * Sets global priority session.
+     */
     public void setGlobalPrioritySession(MediaSessionRecord record) {
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
-            if (mGlobalPrioritySession != record) {
-                Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession
-                        + " to " + record);
-                mGlobalPrioritySession = record;
-                if (user != null && user.mPriorityStack.contains(record)) {
-                    // Handle the global priority session separately.
-                    // Otherwise, it can be the media button session regardless of the active state
-                    // because it or other system components might have been the lastly played media
-                    // app.
-                    user.mPriorityStack.removeSession(record);
-                }
-            }
-        }
+        mImpl.setGlobalPrioritySession(record);
     }
 
-    private List<MediaSessionRecord> getActiveSessionsLocked(int userId) {
-        List<MediaSessionRecord> records = new ArrayList<>();
-        if (userId == UserHandle.USER_ALL) {
-            int size = mUserRecords.size();
-            for (int i = 0; i < size; i++) {
-                records.addAll(mUserRecords.valueAt(i).mPriorityStack.getActiveSessions(userId));
-            }
-        } else {
-            FullUserRecord user = getFullUserRecordLocked(userId);
-            if (user == null) {
-                Log.w(TAG, "getSessions failed. Unknown user " + userId);
-                return records;
-            }
-            records.addAll(user.mPriorityStack.getActiveSessions(userId));
-        }
-
-        // Return global priority session at the first whenever it's asked.
-        if (isGlobalPriorityActiveLocked()
-                && (userId == UserHandle.USER_ALL
-                    || userId == mGlobalPrioritySession.getUserId())) {
-            records.add(0, mGlobalPrioritySession);
-        }
-        return records;
+    List<Session2Token> getSession2TokensLocked(int userId) {
+        return mImpl.getSession2TokensLocked(userId);
     }
 
     /**
      * Tells the system UI that volume has changed on an active remote session.
      */
     public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
-        if (mRvc == null || !session.isActive()) {
-            return;
-        }
-        try {
-            mRvc.remoteVolumeChanged(session.getControllerBinder(), flags);
-        } catch (Exception e) {
-            Log.wtf(TAG, "Error sending volume change to system UI.", e);
-        }
+        mImpl.notifyRemoteVolumeChanged(flags, session);
     }
 
+    /**
+     * Called when session playstate is changed.
+     */
     public void onSessionPlaystateChanged(MediaSessionRecord record, int oldState, int newState) {
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
-            if (user == null || !user.mPriorityStack.contains(record)) {
-                Log.d(TAG, "Unknown session changed playback state. Ignoring.");
-                return;
-            }
-            user.mPriorityStack.onPlaystateChanged(record, oldState, newState);
-        }
+        mImpl.onSessionPlaystateChanged(record, oldState, newState);
     }
 
+    /**
+     * Called when session playback type is changed.
+     */
     public void onSessionPlaybackTypeChanged(MediaSessionRecord record) {
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
-            if (user == null || !user.mPriorityStack.contains(record)) {
-                Log.d(TAG, "Unknown session changed playback type. Ignoring.");
-                return;
-            }
-            pushRemoteVolumeUpdateLocked(record.getUserId());
-        }
-    }
-
-    @Override
-    public void onStartUser(int userId) {
-        if (DEBUG) Log.d(TAG, "onStartUser: " + userId);
-        updateUser();
-    }
-
-    @Override
-    public void onSwitchUser(int userId) {
-        if (DEBUG) Log.d(TAG, "onSwitchUser: " + userId);
-        updateUser();
-    }
-
-    @Override
-    public void onStopUser(int userId) {
-        if (DEBUG) Log.d(TAG, "onStopUser: " + userId);
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(userId);
-            if (user != null) {
-                if (user.mFullUserId == userId) {
-                    user.destroySessionsForUserLocked(UserHandle.USER_ALL);
-                    mUserRecords.remove(userId);
-                } else {
-                    user.destroySessionsForUserLocked(userId);
-                }
-            }
-            updateUser();
-        }
-    }
-
-    @Override
-    public void monitor() {
-        synchronized (mLock) {
-            // Check for deadlock
-        }
+        mImpl.onSessionPlaybackTypeChanged(record);
     }
 
     protected void enforcePhoneStatePermission(int pid, int uid) {
-        if (getContext().checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Must hold the MODIFY_PHONE_STATE permission.");
-        }
+        mImpl.enforcePhoneStatePermission(pid, uid);
     }
 
     void sessionDied(MediaSessionRecord session) {
-        synchronized (mLock) {
-            destroySessionLocked(session);
-        }
+        mImpl.sessionDied(session);
     }
 
     void destroySession(MediaSessionRecord session) {
-        synchronized (mLock) {
-            destroySessionLocked(session);
-        }
+        mImpl.destroySession(session);
     }
 
-    private void updateUser() {
-        synchronized (mLock) {
-            UserManager manager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
-            mFullUserIds.clear();
-            List<UserInfo> allUsers = manager.getUsers();
-            if (allUsers != null) {
-                for (UserInfo userInfo : allUsers) {
-                    if (userInfo.isManagedProfile()) {
-                        mFullUserIds.put(userInfo.id, userInfo.profileGroupId);
-                    } else {
-                        mFullUserIds.put(userInfo.id, userInfo.id);
-                        if (mUserRecords.get(userInfo.id) == null) {
-                            mUserRecords.put(userInfo.id, new FullUserRecord(userInfo.id));
-                        }
-                    }
-                }
-            }
-            // Ensure that the current full user exists.
-            int currentFullUserId = ActivityManager.getCurrentUser();
-            mCurrentFullUserRecord = mUserRecords.get(currentFullUserId);
-            if (mCurrentFullUserRecord == null) {
-                Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
-                mCurrentFullUserRecord = new FullUserRecord(currentFullUserId);
-                mUserRecords.put(currentFullUserId, mCurrentFullUserRecord);
-            }
-            mFullUserIds.put(currentFullUserId, currentFullUserId);
-        }
-    }
-
-    private void updateActiveSessionListeners() {
-        synchronized (mLock) {
-            for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
-                SessionsListenerRecord listener = mSessionsListeners.get(i);
-                try {
-                    enforceMediaPermissions(listener.mComponentName, listener.mPid, listener.mUid,
-                            listener.mUserId);
-                } catch (SecurityException e) {
-                    Log.i(TAG, "ActiveSessionsListener " + listener.mComponentName
-                            + " is no longer authorized. Disconnecting.");
-                    mSessionsListeners.remove(i);
-                    try {
-                        listener.mListener
-                                .onActiveSessionsChanged(new ArrayList<MediaSession.Token>());
-                    } catch (Exception e1) {
-                        // ignore
-                    }
-                }
-            }
-        }
-    }
-
-    /*
-     * When a session is removed several things need to happen.
-     * 1. We need to remove it from the relevant user.
-     * 2. We need to remove it from the priority stack.
-     * 3. We need to remove it from all sessions.
-     * 4. If this is the system priority session we need to clear it.
-     * 5. We need to unlink to death from the cb binder
-     * 6. We need to tell the session to do any final cleanup (onDestroy)
-     */
-    private void destroySessionLocked(MediaSessionRecord session) {
-        if (DEBUG) {
-            Log.d(TAG, "Destroying " + session);
-        }
-        FullUserRecord user = getFullUserRecordLocked(session.getUserId());
-        if (mGlobalPrioritySession == session) {
-            mGlobalPrioritySession = null;
-            if (session.isActive() && user != null) {
-                user.pushAddressedPlayerChangedLocked();
-            }
-        } else {
-            if (user != null) {
-                user.mPriorityStack.removeSession(session);
-            }
-        }
-
-        try {
-            session.getCallback().getBinder().unlinkToDeath(session, 0);
-        } catch (Exception e) {
-            // ignore exceptions while destroying a session.
-        }
-        session.onDestroy();
-        mHandler.postSessionsChanged(session.getUserId());
-    }
-
-    private void enforcePackageName(String packageName, int uid) {
-        if (TextUtils.isEmpty(packageName)) {
-            throw new IllegalArgumentException("packageName may not be empty");
-        }
-        String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
-        final int packageCount = packages.length;
-        for (int i = 0; i < packageCount; i++) {
-            if (packageName.equals(packages[i])) {
-                return;
-            }
-        }
-        throw new IllegalArgumentException("packageName is not owned by the calling process");
+    void pushSession2TokensChangedLocked(int userId) {
+        mImpl.pushSession2TokensChangedLocked(userId);
     }
 
     /**
-     * Checks a caller's authorization to register an IRemoteControlDisplay.
-     * Authorization is granted if one of the following is true:
-     * <ul>
-     * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL
-     * permission</li>
-     * <li>the caller's listener is one of the enabled notification listeners
-     * for the caller's user</li>
-     * </ul>
-     */
-    private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
-            int resolvedUserId) {
-        if (isCurrentVolumeController(pid, uid)) return;
-        if (getContext()
-                .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
-                    != PackageManager.PERMISSION_GRANTED
-                && !isEnabledNotificationListener(compName, UserHandle.getUserId(uid),
-                        resolvedUserId)) {
-            throw new SecurityException("Missing permission to control media.");
-        }
-    }
-
-    private boolean isCurrentVolumeController(int pid, int uid) {
-        return getContext().checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
-                pid, uid) == PackageManager.PERMISSION_GRANTED;
-    }
-
-    private void enforceSystemUiPermission(String action, int pid, int uid) {
-        if (!isCurrentVolumeController(pid, uid)) {
-            throw new SecurityException("Only system ui may " + action);
-        }
-    }
-
-    /**
-     * This checks if the component is an enabled notification listener for the
-     * specified user. Enabled components may only operate on behalf of the user
-     * they're running as.
-     *
-     * @param compName The component that is enabled.
-     * @param userId The user id of the caller.
-     * @param forUserId The user id they're making the request on behalf of.
-     * @return True if the component is enabled, false otherwise
-     */
-    private boolean isEnabledNotificationListener(ComponentName compName, int userId,
-            int forUserId) {
-        if (userId != forUserId) {
-            // You may not access another user's content as an enabled listener.
-            return false;
-        }
-        if (DEBUG) {
-            Log.d(TAG, "Checking if enabled notification listener " + compName);
-        }
-        if (compName != null) {
-            try {
-                return mNotificationManager.isNotificationListenerAccessGrantedForUser(
-                        compName, userId);
-            } catch(RemoteException e) {
-                Log.w(TAG, "Dead NotificationManager in isEnabledNotificationListener", e);
-            }
-        }
-        return false;
-    }
-
-    private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
-            String callerPackageName, SessionCallbackLink cb, String tag) throws RemoteException {
-        synchronized (mLock) {
-            return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag);
-        }
-    }
-
-    /*
-     * When a session is created the following things need to happen.
-     * 1. Its callback binder needs a link to death
-     * 2. It needs to be added to all sessions.
-     * 3. It needs to be added to the priority stack.
-     * 4. It needs to be added to the relevant user record.
-     */
-    private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
-            String callerPackageName, SessionCallbackLink cb, String tag) {
-        FullUserRecord user = getFullUserRecordLocked(userId);
-        if (user == null) {
-            Log.wtf(TAG, "Request from invalid user: " +  userId);
-            throw new RuntimeException("Session request from invalid user.");
-        }
-
-        final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
-                callerPackageName, cb, tag, this, mHandler.getLooper());
-        try {
-            cb.getBinder().linkToDeath(session, 0);
-        } catch (RemoteException e) {
-            throw new RuntimeException("Media Session owner died prematurely.", e);
-        }
-
-        user.mPriorityStack.addSession(session);
-        mHandler.postSessionsChanged(userId);
-
-        if (DEBUG) {
-            Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
-        }
-        return session;
-    }
-
-    private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
-        for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
-            if (mSessionsListeners.get(i).mListener.asBinder() == listener.asBinder()) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    private void pushSessionsChanged(int userId) {
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(userId);
-            if (user == null) {
-                Log.w(TAG, "pushSessionsChanged failed. No user with id=" + userId);
-                return;
-            }
-            List<MediaSessionRecord> records = getActiveSessionsLocked(userId);
-            int size = records.size();
-            ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();
-            for (int i = 0; i < size; i++) {
-                tokens.add(new MediaSession.Token(records.get(i).getControllerBinder()));
-            }
-            pushRemoteVolumeUpdateLocked(userId);
-            for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
-                SessionsListenerRecord record = mSessionsListeners.get(i);
-                if (record.mUserId == UserHandle.USER_ALL || record.mUserId == userId) {
-                    try {
-                        record.mListener.onActiveSessionsChanged(tokens);
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Dead ActiveSessionsListener in pushSessionsChanged, removing",
-                                e);
-                        mSessionsListeners.remove(i);
-                    }
-                }
-            }
-        }
-    }
-
-    private void pushRemoteVolumeUpdateLocked(int userId) {
-        if (mRvc != null) {
-            try {
-                FullUserRecord user = getFullUserRecordLocked(userId);
-                if (user == null) {
-                    Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId);
-                    return;
-                }
-                MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
-                mRvc.updateRemoteController(record == null ? null : record.getControllerBinder());
-            } catch (RemoteException e) {
-                Log.wtf(TAG, "Error sending default remote volume to sys ui.", e);
-            }
-        }
-    }
-
-    /**
-     * Called when the media button receiver for the {@param record} is changed.
-     *
-     * @param record the media session whose media button receiver is updated.
+     * Called when media button receiver changed.
      */
     public void onMediaButtonReceiverChanged(MediaSessionRecord record) {
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
-            MediaSessionRecord mediaButtonSession =
-                    user.mPriorityStack.getMediaButtonSession();
-            if (record == mediaButtonSession) {
-                user.rememberMediaButtonReceiverLocked(mediaButtonSession);
-            }
-        }
+        mImpl.onMediaButtonReceiverChanged(record);
     }
 
-    private String getCallingPackageName(int uid) {
-        String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
-        if (packages != null && packages.length > 0) {
-            return packages[0];
-        }
-        return "";
-    }
-
-    private void dispatchVolumeKeyLongPressLocked(KeyEvent keyEvent) {
-        if (mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
-            return;
-        }
-        try {
-            mCurrentFullUserRecord.mOnVolumeKeyLongPressListener.onVolumeKeyLongPress(keyEvent);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to send " + keyEvent + " to volume key long-press listener");
-        }
-    }
-
-    private FullUserRecord getFullUserRecordLocked(int userId) {
-        int fullUserId = mFullUserIds.get(userId, -1);
-        if (fullUserId < 0) {
-            return null;
-        }
-        return mUserRecords.get(fullUserId);
-    }
-
-    /**
-     * Information about a full user and its corresponding managed profiles.
-     *
-     * <p>Since the full user runs together with its managed profiles, a user wouldn't differentiate
-     * them when he/she presses a media/volume button. So keeping media sessions for them in one
-     * place makes more sense and increases the readability.</p>
-     * <p>The contents of this object is guarded by {@link #mLock}.
-     */
-    final class FullUserRecord implements MediaSessionStack.OnMediaButtonSessionChangedListener {
-        public static final int COMPONENT_TYPE_INVALID = 0;
-        public static final int COMPONENT_TYPE_BROADCAST = 1;
-        public static final int COMPONENT_TYPE_ACTIVITY = 2;
-        public static final int COMPONENT_TYPE_SERVICE = 3;
-        private static final String COMPONENT_NAME_USER_ID_DELIM = ",";
-
-        private final int mFullUserId;
-        private final MediaSessionStack mPriorityStack;
-        private PendingIntent mLastMediaButtonReceiver;
-        private ComponentName mRestoredMediaButtonReceiver;
-        private int mRestoredMediaButtonReceiverComponentType;
-        private int mRestoredMediaButtonReceiverUserId;
-
-        private IOnVolumeKeyLongPressListener mOnVolumeKeyLongPressListener;
-        private int mOnVolumeKeyLongPressListenerUid;
-        private KeyEvent mInitialDownVolumeKeyEvent;
-        private int mInitialDownVolumeStream;
-        private boolean mInitialDownMusicOnly;
-
-        private IOnMediaKeyListener mOnMediaKeyListener;
-        private int mOnMediaKeyListenerUid;
-        private ICallback mCallback;
-
-        public FullUserRecord(int fullUserId) {
-            mFullUserId = fullUserId;
-            mPriorityStack = new MediaSessionStack(mAudioPlayerStateMonitor, this);
-            // Restore the remembered media button receiver before the boot.
-            String mediaButtonReceiverInfo = Settings.Secure.getStringForUser(mContentResolver,
-                    Settings.System.MEDIA_BUTTON_RECEIVER, mFullUserId);
-            if (mediaButtonReceiverInfo == null) {
-                return;
-            }
-            String[] tokens = mediaButtonReceiverInfo.split(COMPONENT_NAME_USER_ID_DELIM);
-            if (tokens == null || (tokens.length != 2 && tokens.length != 3)) {
-                return;
-            }
-            mRestoredMediaButtonReceiver = ComponentName.unflattenFromString(tokens[0]);
-            mRestoredMediaButtonReceiverUserId = Integer.parseInt(tokens[1]);
-            if (tokens.length == 3) {
-                mRestoredMediaButtonReceiverComponentType = Integer.parseInt(tokens[2]);
-            } else {
-                mRestoredMediaButtonReceiverComponentType =
-                        getComponentType(mRestoredMediaButtonReceiver);
-            }
-        }
-
-        public void destroySessionsForUserLocked(int userId) {
-            List<MediaSessionRecord> sessions = mPriorityStack.getPriorityList(false, userId);
-            for (MediaSessionRecord session : sessions) {
-                MediaSessionService.this.destroySessionLocked(session);
-            }
-        }
-
-        public void dumpLocked(PrintWriter pw, String prefix) {
-            pw.print(prefix + "Record for full_user=" + mFullUserId);
-            // Dump managed profile user ids associated with this user.
-            int size = mFullUserIds.size();
-            for (int i = 0; i < size; i++) {
-                if (mFullUserIds.keyAt(i) != mFullUserIds.valueAt(i)
-                        && mFullUserIds.valueAt(i) == mFullUserId) {
-                    pw.print(", profile_user=" + mFullUserIds.keyAt(i));
-                }
-            }
-            pw.println();
-            String indent = prefix + "  ";
-            pw.println(indent + "Volume key long-press listener: " + mOnVolumeKeyLongPressListener);
-            pw.println(indent + "Volume key long-press listener package: " +
-                    getCallingPackageName(mOnVolumeKeyLongPressListenerUid));
-            pw.println(indent + "Media key listener: " + mOnMediaKeyListener);
-            pw.println(indent + "Media key listener package: " +
-                    getCallingPackageName(mOnMediaKeyListenerUid));
-            pw.println(indent + "Callback: " + mCallback);
-            pw.println(indent + "Last MediaButtonReceiver: " + mLastMediaButtonReceiver);
-            pw.println(indent + "Restored MediaButtonReceiver: " + mRestoredMediaButtonReceiver);
-            pw.println(indent + "Restored MediaButtonReceiverComponentType: "
-                    + mRestoredMediaButtonReceiverComponentType);
-            mPriorityStack.dump(pw, indent);
-        }
-
-        @Override
-        public void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession,
-                MediaSessionRecord newMediaButtonSession) {
-            if (DEBUG_KEY_EVENT) {
-                Log.d(TAG, "Media button session is changed to " + newMediaButtonSession);
-            }
-            synchronized (mLock) {
-                if (oldMediaButtonSession != null) {
-                    mHandler.postSessionsChanged(oldMediaButtonSession.getUserId());
-                }
-                if (newMediaButtonSession != null) {
-                    rememberMediaButtonReceiverLocked(newMediaButtonSession);
-                    mHandler.postSessionsChanged(newMediaButtonSession.getUserId());
-                }
-                pushAddressedPlayerChangedLocked();
-            }
-        }
-
-        // Remember media button receiver and keep it in the persistent storage.
-        public void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {
-            PendingIntent receiver = record.getMediaButtonReceiver();
-            mLastMediaButtonReceiver = receiver;
-            mRestoredMediaButtonReceiver = null;
-            mRestoredMediaButtonReceiverComponentType = COMPONENT_TYPE_INVALID;
-
-            String mediaButtonReceiverInfo = "";
-            if (receiver != null) {
-                ComponentName component = receiver.getIntent().getComponent();
-                if (component != null
-                        && record.getPackageName().equals(component.getPackageName())) {
-                    String componentName = component.flattenToString();
-                    int componentType = getComponentType(component);
-                    mediaButtonReceiverInfo = String.join(COMPONENT_NAME_USER_ID_DELIM,
-                            componentName, String.valueOf(record.getUserId()),
-                            String.valueOf(componentType));
-                }
-            }
-            Settings.Secure.putStringForUser(mContentResolver,
-                    Settings.System.MEDIA_BUTTON_RECEIVER, mediaButtonReceiverInfo,
-                    mFullUserId);
-        }
-
-        private void pushAddressedPlayerChangedLocked() {
-            if (mCallback == null) {
-                return;
-            }
-            try {
-                MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked();
-                if (mediaButtonSession != null) {
-                    mCallback.onAddressedPlayerChangedToMediaSession(
-                            new MediaSession.Token(mediaButtonSession.getControllerBinder()));
-                } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
-                    mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
-                            mCurrentFullUserRecord.mLastMediaButtonReceiver
-                                    .getIntent().getComponent());
-                } else if (mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
-                    mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
-                            mCurrentFullUserRecord.mRestoredMediaButtonReceiver);
-                }
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e);
-            }
-        }
-
-        private MediaSessionRecord getMediaButtonSessionLocked() {
-            return isGlobalPriorityActiveLocked()
-                    ? mGlobalPrioritySession : mPriorityStack.getMediaButtonSession();
-        }
-
-        private int getComponentType(@Nullable ComponentName componentName) {
-            if (componentName == null) {
-                return COMPONENT_TYPE_INVALID;
-            }
-            PackageManager pm = getContext().getPackageManager();
-            try {
-                ActivityInfo activityInfo = pm.getActivityInfo(componentName,
-                        PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                                | PackageManager.GET_ACTIVITIES);
-                if (activityInfo != null) {
-                    return COMPONENT_TYPE_ACTIVITY;
-                }
-            } catch (NameNotFoundException e) {
-            }
-            try {
-                ServiceInfo serviceInfo = pm.getServiceInfo(componentName,
-                        PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                                | PackageManager.GET_SERVICES);
-                if (serviceInfo != null) {
-                    return COMPONENT_TYPE_SERVICE;
-                }
-            } catch (NameNotFoundException e) {
-            }
-            // Pick legacy behavior for BroadcastReceiver or unknown.
-            return COMPONENT_TYPE_BROADCAST;
-        }
-    }
-
-    final class SessionsListenerRecord implements IBinder.DeathRecipient {
-        private final IActiveSessionsListener mListener;
-        private final ComponentName mComponentName;
-        private final int mUserId;
-        private final int mPid;
-        private final int mUid;
-
-        public SessionsListenerRecord(IActiveSessionsListener listener,
-                ComponentName componentName,
-                int userId, int pid, int uid) {
-            mListener = listener;
-            mComponentName = componentName;
-            mUserId = userId;
-            mPid = pid;
-            mUid = uid;
-        }
-
-        @Override
-        public void binderDied() {
-            synchronized (mLock) {
-                mSessionsListeners.remove(this);
-            }
-        }
-    }
-
-    final class SettingsObserver extends ContentObserver {
-        private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(
-                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
-
-        private SettingsObserver() {
-            super(null);
-        }
-
-        private void observe() {
-            mContentResolver.registerContentObserver(mSecureSettingsUri,
-                    false, this, UserHandle.USER_ALL);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            updateActiveSessionListeners();
-        }
-    }
-
-    class SessionManagerImpl extends ISessionManager.Stub {
-        private static final String EXTRA_WAKELOCK_ACQUIRED =
-                "android.media.AudioService.WAKELOCK_ACQUIRED";
-        private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number
-
-        private boolean mVoiceButtonDown = false;
-        private boolean mVoiceButtonHandled = false;
-
-        @Override
-        public ISession createSession(String packageName, SessionCallbackLink cb, String tag,
-                int userId) throws RemoteException {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                enforcePackageName(packageName, uid);
-                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
-                        false /* allowAll */, true /* requireFull */, "createSession", packageName);
-                if (cb == null) {
-                    throw new IllegalArgumentException("Controller callback cannot be null");
-                }
-                return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag)
-                        .getSessionBinder();
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public List<IBinder> getSessions(ComponentName componentName, int userId) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-
-            try {
-                int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
-                ArrayList<IBinder> binders = new ArrayList<IBinder>();
-                synchronized (mLock) {
-                    List<MediaSessionRecord> records = getActiveSessionsLocked(resolvedUserId);
-                    for (MediaSessionRecord record : records) {
-                        binders.add(record.getControllerBinder().asBinder());
-                    }
-                }
-                return binders;
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void addSessionsListener(IActiveSessionsListener listener,
-                ComponentName componentName, int userId) throws RemoteException {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-
-            try {
-                int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
-                synchronized (mLock) {
-                    int index = findIndexOfSessionsListenerLocked(listener);
-                    if (index != -1) {
-                        Log.w(TAG, "ActiveSessionsListener is already added, ignoring");
-                        return;
-                    }
-                    SessionsListenerRecord record = new SessionsListenerRecord(listener,
-                            componentName, resolvedUserId, pid, uid);
-                    try {
-                        listener.asBinder().linkToDeath(record, 0);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "ActiveSessionsListener is dead, ignoring it", e);
-                        return;
-                    }
-                    mSessionsListeners.add(record);
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void removeSessionsListener(IActiveSessionsListener listener)
-                throws RemoteException {
-            synchronized (mLock) {
-                int index = findIndexOfSessionsListenerLocked(listener);
-                if (index != -1) {
-                    SessionsListenerRecord record = mSessionsListeners.remove(index);
-                    try {
-                        record.mListener.asBinder().unlinkToDeath(record, 0);
-                    } catch (Exception e) {
-                        // ignore exceptions, the record is being removed
-                    }
-                }
-            }
-        }
-
-        /**
-         * Handles the dispatching of the media button events to one of the
-         * registered listeners, or if there was none, broadcast an
-         * ACTION_MEDIA_BUTTON intent to the rest of the system.
-         *
-         * @param packageName The caller package
-         * @param asSystemService {@code true} if the event sent to the session as if it was come
-         *          from the system service instead of the app process. This helps sessions to
-         *          distinguish between the key injection by the app and key events from the
-         *          hardware devices. Should be used only when the volume key events aren't handled
-         *          by foreground activity. {@code false} otherwise to tell session about the real
-         *          caller.
-         * @param keyEvent a non-null KeyEvent whose key code is one of the
-         *            supported media buttons
-         * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held
-         *            while this key event is dispatched.
-         */
-        @Override
-        public void dispatchMediaKeyEvent(String packageName, boolean asSystemService,
-                KeyEvent keyEvent, boolean needWakeLock) {
-            if (keyEvent == null || !KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
-                Log.w(TAG, "Attempted to dispatch null or non-media key event.");
-                return;
-            }
-
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                if (DEBUG) {
-                    Log.d(TAG, "dispatchMediaKeyEvent, pkg=" + packageName + " pid=" + pid
-                            + ", uid=" + uid + ", asSystem=" + asSystemService + ", event="
-                            + keyEvent);
-                }
-                if (!isUserSetupComplete()) {
-                    // Global media key handling can have the side-effect of starting new
-                    // activities which is undesirable while setup is in progress.
-                    Slog.i(TAG, "Not dispatching media key event because user "
-                            + "setup is in progress.");
-                    return;
-                }
-
-                synchronized (mLock) {
-                    boolean isGlobalPriorityActive = isGlobalPriorityActiveLocked();
-                    if (isGlobalPriorityActive && uid != Process.SYSTEM_UID) {
-                        // Prevent dispatching key event through reflection while the global
-                        // priority session is active.
-                        Slog.i(TAG, "Only the system can dispatch media key event "
-                                + "to the global priority session.");
-                        return;
-                    }
-                    if (!isGlobalPriorityActive) {
-                        if (mCurrentFullUserRecord.mOnMediaKeyListener != null) {
-                            if (DEBUG_KEY_EVENT) {
-                                Log.d(TAG, "Send " + keyEvent + " to the media key listener");
-                            }
-                            try {
-                                mCurrentFullUserRecord.mOnMediaKeyListener.onMediaKey(keyEvent,
-                                        new MediaKeyListenerResultReceiver(packageName, pid, uid,
-                                                asSystemService, keyEvent, needWakeLock));
-                                return;
-                            } catch (RemoteException e) {
-                                Log.w(TAG, "Failed to send " + keyEvent
-                                        + " to the media key listener");
-                            }
-                        }
-                    }
-                    if (!isGlobalPriorityActive && isVoiceKey(keyEvent.getKeyCode())) {
-                        handleVoiceKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
-                                needWakeLock);
-                    } else {
-                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
-                                keyEvent, needWakeLock);
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void setCallback(ICallback callback) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                if (!UserHandle.isSameApp(uid, Process.BLUETOOTH_UID)) {
-                    throw new SecurityException("Only Bluetooth service processes can set"
-                            + " Callback");
-                }
-                synchronized (mLock) {
-                    int userId = UserHandle.getUserId(uid);
-                    FullUserRecord user = getFullUserRecordLocked(userId);
-                    if (user == null || user.mFullUserId != userId) {
-                        Log.w(TAG, "Only the full user can set the callback"
-                                + ", userId=" + userId);
-                        return;
-                    }
-                    user.mCallback = callback;
-                    Log.d(TAG, "The callback " + user.mCallback
-                            + " is set by " + getCallingPackageName(uid));
-                    if (user.mCallback == null) {
-                        return;
-                    }
-                    try {
-                        user.mCallback.asBinder().linkToDeath(
-                                new IBinder.DeathRecipient() {
-                                    @Override
-                                    public void binderDied() {
-                                        synchronized (mLock) {
-                                            user.mCallback = null;
-                                        }
-                                    }
-                                }, 0);
-                        user.pushAddressedPlayerChangedLocked();
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Failed to set callback", e);
-                        user.mCallback = null;
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void setOnVolumeKeyLongPressListener(IOnVolumeKeyLongPressListener listener) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                // Enforce SET_VOLUME_KEY_LONG_PRESS_LISTENER permission.
-                if (getContext().checkPermission(
-                        android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER, pid, uid)
-                            != PackageManager.PERMISSION_GRANTED) {
-                    throw new SecurityException("Must hold the SET_VOLUME_KEY_LONG_PRESS_LISTENER" +
-                            " permission.");
-                }
-
-                synchronized (mLock) {
-                    int userId = UserHandle.getUserId(uid);
-                    FullUserRecord user = getFullUserRecordLocked(userId);
-                    if (user == null || user.mFullUserId != userId) {
-                        Log.w(TAG, "Only the full user can set the volume key long-press listener"
-                                + ", userId=" + userId);
-                        return;
-                    }
-                    if (user.mOnVolumeKeyLongPressListener != null &&
-                            user.mOnVolumeKeyLongPressListenerUid != uid) {
-                        Log.w(TAG, "The volume key long-press listener cannot be reset"
-                                + " by another app , mOnVolumeKeyLongPressListener="
-                                + user.mOnVolumeKeyLongPressListenerUid
-                                + ", uid=" + uid);
-                        return;
-                    }
-
-                    user.mOnVolumeKeyLongPressListener = listener;
-                    user.mOnVolumeKeyLongPressListenerUid = uid;
-
-                    Log.d(TAG, "The volume key long-press listener "
-                            + listener + " is set by " + getCallingPackageName(uid));
-
-                    if (user.mOnVolumeKeyLongPressListener != null) {
-                        try {
-                            user.mOnVolumeKeyLongPressListener.asBinder().linkToDeath(
-                                    new IBinder.DeathRecipient() {
-                                        @Override
-                                        public void binderDied() {
-                                            synchronized (mLock) {
-                                                user.mOnVolumeKeyLongPressListener = null;
-                                            }
-                                        }
-                                    }, 0);
-                        } catch (RemoteException e) {
-                            Log.w(TAG, "Failed to set death recipient "
-                                    + user.mOnVolumeKeyLongPressListener);
-                            user.mOnVolumeKeyLongPressListener = null;
-                        }
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void setOnMediaKeyListener(IOnMediaKeyListener listener) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                // Enforce SET_MEDIA_KEY_LISTENER permission.
-                if (getContext().checkPermission(
-                        android.Manifest.permission.SET_MEDIA_KEY_LISTENER, pid, uid)
-                            != PackageManager.PERMISSION_GRANTED) {
-                    throw new SecurityException("Must hold the SET_MEDIA_KEY_LISTENER" +
-                            " permission.");
-                }
-
-                synchronized (mLock) {
-                    int userId = UserHandle.getUserId(uid);
-                    FullUserRecord user = getFullUserRecordLocked(userId);
-                    if (user == null || user.mFullUserId != userId) {
-                        Log.w(TAG, "Only the full user can set the media key listener"
-                                + ", userId=" + userId);
-                        return;
-                    }
-                    if (user.mOnMediaKeyListener != null && user.mOnMediaKeyListenerUid != uid) {
-                        Log.w(TAG, "The media key listener cannot be reset by another app. "
-                                + ", mOnMediaKeyListenerUid=" + user.mOnMediaKeyListenerUid
-                                + ", uid=" + uid);
-                        return;
-                    }
-
-                    user.mOnMediaKeyListener = listener;
-                    user.mOnMediaKeyListenerUid = uid;
-
-                    Log.d(TAG, "The media key listener " + user.mOnMediaKeyListener
-                            + " is set by " + getCallingPackageName(uid));
-
-                    if (user.mOnMediaKeyListener != null) {
-                        try {
-                            user.mOnMediaKeyListener.asBinder().linkToDeath(
-                                    new IBinder.DeathRecipient() {
-                                        @Override
-                                        public void binderDied() {
-                                            synchronized (mLock) {
-                                                user.mOnMediaKeyListener = null;
-                                            }
-                                        }
-                                    }, 0);
-                        } catch (RemoteException e) {
-                            Log.w(TAG, "Failed to set death recipient " + user.mOnMediaKeyListener);
-                            user.mOnMediaKeyListener = null;
-                        }
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        /**
-         * Handles the dispatching of the volume button events to one of the
-         * registered listeners. If there's a volume key long-press listener and
-         * there's no active global priority session, long-pressess will be sent to the
-         * long-press listener instead of adjusting volume.
-         *
-         * @param packageName The caller package.
-         * @param asSystemService {@code true} if the event sent to the session as if it was come
-         *          from the system service instead of the app process. This helps sessions to
-         *          distinguish between the key injection by the app and key events from the
-         *          hardware devices. Should be used only when the volume key events aren't handled
-         *          by foreground activity. {@code false} otherwise to tell session about the real
-         *          caller.
-         * @param keyEvent a non-null KeyEvent whose key code is one of the
-         *            {@link KeyEvent#KEYCODE_VOLUME_UP},
-         *            {@link KeyEvent#KEYCODE_VOLUME_DOWN},
-         *            or {@link KeyEvent#KEYCODE_VOLUME_MUTE}.
-         * @param stream stream type to adjust volume.
-         * @param musicOnly true if both UI nor haptic feedback aren't needed when adjust volume.
-         */
-        @Override
-        public void dispatchVolumeKeyEvent(String packageName, boolean asSystemService,
-                KeyEvent keyEvent, int stream, boolean musicOnly) {
-            if (keyEvent == null ||
-                    (keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_UP
-                             && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_DOWN
-                             && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_MUTE)) {
-                Log.w(TAG, "Attempted to dispatch null or non-volume key event.");
-                return;
-            }
-
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-
-            if (DEBUG_KEY_EVENT) {
-                Log.d(TAG, "dispatchVolumeKeyEvent, pkg=" + packageName + ", pid=" + pid + ", uid="
-                        + uid + ", asSystem=" + asSystemService + ", event=" + keyEvent);
-            }
-
-            try {
-                synchronized (mLock) {
-                    if (isGlobalPriorityActiveLocked()
-                            || mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
-                        dispatchVolumeKeyEventLocked(packageName, pid, uid, asSystemService,
-                                keyEvent, stream, musicOnly);
-                    } else {
-                        // TODO: Consider the case when both volume up and down keys are pressed
-                        //       at the same time.
-                        if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
-                            if (keyEvent.getRepeatCount() == 0) {
-                                // Keeps the copy of the KeyEvent because it can be reused.
-                                mCurrentFullUserRecord.mInitialDownVolumeKeyEvent =
-                                        KeyEvent.obtain(keyEvent);
-                                mCurrentFullUserRecord.mInitialDownVolumeStream = stream;
-                                mCurrentFullUserRecord.mInitialDownMusicOnly = musicOnly;
-                                mHandler.sendMessageDelayed(
-                                        mHandler.obtainMessage(
-                                                MessageHandler.MSG_VOLUME_INITIAL_DOWN,
-                                                mCurrentFullUserRecord.mFullUserId, 0),
-                                        mLongPressTimeout);
-                            }
-                            if (keyEvent.getRepeatCount() > 0 || keyEvent.isLongPress()) {
-                                mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
-                                if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null) {
-                                    dispatchVolumeKeyLongPressLocked(
-                                            mCurrentFullUserRecord.mInitialDownVolumeKeyEvent);
-                                    // Mark that the key is already handled.
-                                    mCurrentFullUserRecord.mInitialDownVolumeKeyEvent = null;
-                                }
-                                dispatchVolumeKeyLongPressLocked(keyEvent);
-                            }
-                        } else { // if up
-                            mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
-                            if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null
-                                    && mCurrentFullUserRecord.mInitialDownVolumeKeyEvent
-                                            .getDownTime() == keyEvent.getDownTime()) {
-                                // Short-press. Should change volume.
-                                dispatchVolumeKeyEventLocked(packageName, pid, uid, asSystemService,
-                                        mCurrentFullUserRecord.mInitialDownVolumeKeyEvent,
-                                        mCurrentFullUserRecord.mInitialDownVolumeStream,
-                                        mCurrentFullUserRecord.mInitialDownMusicOnly);
-                                dispatchVolumeKeyEventLocked(packageName, pid, uid, asSystemService,
-                                        keyEvent, stream, musicOnly);
-                            } else {
-                                dispatchVolumeKeyLongPressLocked(keyEvent);
-                            }
-                        }
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        private void dispatchVolumeKeyEventLocked(String packageName, int pid, int uid,
-                boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly) {
-            boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
-            boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP;
-            int direction = 0;
-            boolean isMute = false;
-            switch (keyEvent.getKeyCode()) {
-                case KeyEvent.KEYCODE_VOLUME_UP:
-                    direction = AudioManager.ADJUST_RAISE;
-                    break;
-                case KeyEvent.KEYCODE_VOLUME_DOWN:
-                    direction = AudioManager.ADJUST_LOWER;
-                    break;
-                case KeyEvent.KEYCODE_VOLUME_MUTE:
-                    isMute = true;
-                    break;
-            }
-            if (down || up) {
-                int flags = AudioManager.FLAG_FROM_KEY;
-                if (musicOnly) {
-                    // This flag is used when the screen is off to only affect active media.
-                    flags |= AudioManager.FLAG_ACTIVE_MEDIA_ONLY;
-                } else {
-                    // These flags are consistent with the home screen
-                    if (up) {
-                        flags |= AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE;
-                    } else {
-                        flags |= AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE;
-                    }
-                }
-                if (direction != 0) {
-                    // If this is action up we want to send a beep for non-music events
-                    if (up) {
-                        direction = 0;
-                    }
-                    dispatchAdjustVolumeLocked(packageName, pid, uid, asSystemService, stream,
-                            direction, flags);
-                } else if (isMute) {
-                    if (down && keyEvent.getRepeatCount() == 0) {
-                        dispatchAdjustVolumeLocked(packageName, pid, uid, asSystemService, stream,
-                                AudioManager.ADJUST_TOGGLE_MUTE, flags);
-                    }
-                }
-            }
-        }
-
-        @Override
-        public void dispatchAdjustVolume(String packageName, int suggestedStream, int delta,
-                int flags) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                synchronized (mLock) {
-                    dispatchAdjustVolumeLocked(packageName, pid, uid, false,
-                            suggestedStream, delta, flags);
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void setRemoteVolumeController(IRemoteVolumeController rvc) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                enforceSystemUiPermission("listen for volume changes", pid, uid);
-                mRvc = rvc;
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public boolean isGlobalPriorityActive() {
-            synchronized (mLock) {
-                return isGlobalPriorityActiveLocked();
-            }
-        }
-
-        @Override
-        public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
-            if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
-
-            pw.println("MEDIA SESSION SERVICE (dumpsys media_session)");
-            pw.println();
-
-            synchronized (mLock) {
-                pw.println(mSessionsListeners.size() + " sessions listeners.");
-                pw.println("Global priority session is " + mGlobalPrioritySession);
-                if (mGlobalPrioritySession != null) {
-                    mGlobalPrioritySession.dump(pw, "  ");
-                }
-                pw.println("User Records:");
-                int count = mUserRecords.size();
-                for (int i = 0; i < count; i++) {
-                    mUserRecords.valueAt(i).dumpLocked(pw, "");
-                }
-                mAudioPlayerStateMonitor.dump(getContext(), pw, "");
-            }
-        }
-
-        /**
-         * Returns if the controller's package is trusted (i.e. has either MEDIA_CONTENT_CONTROL
-         * permission or an enabled notification listener)
-         *
-         * @param controllerPackageName package name of the controller app
-         * @param controllerPid pid of the controller app
-         * @param controllerUid uid of the controller app
-         */
-        @Override
-        public boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid)
-                throws RemoteException {
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                int controllerUserId = UserHandle.getUserId(controllerUid);
-                int controllerUidFromPackageName;
-                try {
-                    controllerUidFromPackageName = getContext().getPackageManager()
-                            .getPackageUidAsUser(controllerPackageName, controllerUserId);
-                } catch (NameNotFoundException e) {
-                    if (DEBUG) {
-                        Log.d(TAG, "Package " + controllerPackageName + " doesn't exist");
-                    }
-                    return false;
-                }
-                if (controllerUidFromPackageName != controllerUid) {
-                    if (DEBUG) {
-                        Log.d(TAG, "Package name " + controllerPackageName
-                                + " doesn't match with the uid " + controllerUid);
-                    }
-                    return false;
-                }
-                return hasMediaControlPermission(UserHandle.getUserId(uid), controllerPackageName,
-                        controllerPid, controllerUid);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        // For MediaSession
-        private int verifySessionsRequest(ComponentName componentName, int userId, final int pid,
-                final int uid) {
-            String packageName = null;
-            if (componentName != null) {
-                // If they gave us a component name verify they own the
-                // package
-                packageName = componentName.getPackageName();
-                enforcePackageName(packageName, uid);
-            }
-            // Check that they can make calls on behalf of the user and
-            // get the final user id
-            int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
-                    true /* allowAll */, true /* requireFull */, "getSessions", packageName);
-            // Check if they have the permissions or their component is
-            // enabled for the user they're calling from.
-            enforceMediaPermissions(componentName, pid, uid, resolvedUserId);
-            return resolvedUserId;
-        }
-
-        private boolean hasMediaControlPermission(int resolvedUserId, String packageName,
-                int pid, int uid) throws RemoteException {
-            // Allow API calls from the System UI
-            if (isCurrentVolumeController(pid, uid)) {
-                return true;
-            }
-
-            // Check if it's system server or has MEDIA_CONTENT_CONTROL.
-            // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
-            // check here.
-            if (uid == Process.SYSTEM_UID || getContext().checkPermission(
-                    android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
-                    == PackageManager.PERMISSION_GRANTED) {
-                return true;
-            } else if (DEBUG) {
-                Log.d(TAG, packageName + " (uid=" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
-            }
-
-            // You may not access another user's content as an enabled listener.
-            final int userId = UserHandle.getUserId(uid);
-            if (resolvedUserId != userId) {
-                return false;
-            }
-
-            // TODO(jaewan): (Post-P) Propose NotificationManager#hasEnabledNotificationListener(
-            //               String pkgName) to notification team for optimization
-            final List<ComponentName> enabledNotificationListeners =
-                    mNotificationManager.getEnabledNotificationListeners(userId);
-            if (enabledNotificationListeners != null) {
-                for (int i = 0; i < enabledNotificationListeners.size(); i++) {
-                    if (TextUtils.equals(packageName,
-                            enabledNotificationListeners.get(i).getPackageName())) {
-                        return true;
-                    }
-                }
-            }
-            if (DEBUG) {
-                Log.d(TAG, packageName + " (uid=" + uid + ") doesn't have an enabled "
-                        + "notification listener");
-            }
-            return false;
-        }
-
-        private void dispatchAdjustVolumeLocked(String packageName, int pid, int uid,
-                boolean asSystemService, int suggestedStream, int direction, int flags) {
-            MediaSessionRecord session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
-                    : mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
-
-            boolean preferSuggestedStream = false;
-            if (isValidLocalStreamType(suggestedStream)
-                    && AudioSystem.isStreamActive(suggestedStream, 0)) {
-                preferSuggestedStream = true;
-            }
-            if (DEBUG_KEY_EVENT) {
-                Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags="
-                        + flags + ", suggestedStream=" + suggestedStream
-                        + ", preferSuggestedStream=" + preferSuggestedStream);
-            }
-            if (session == null || preferSuggestedStream) {
-                if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0
-                        && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
-                    if (DEBUG) {
-                        Log.d(TAG, "No active session to adjust, skipping media only volume event");
-                    }
-                    return;
-                }
-
-                // Execute mAudioService.adjustSuggestedStreamVolume() on
-                // handler thread of MediaSessionService.
-                // This will release the MediaSessionService.mLock sooner and avoid
-                // a potential deadlock between MediaSessionService.mLock and
-                // ActivityManagerService lock.
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        try {
-                            String packageName = getContext().getOpPackageName();
-                            mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
-                                    flags, packageName, TAG);
-                        } catch (RemoteException|SecurityException e) {
-                            Log.e(TAG, "Error adjusting default volume.", e);
-                        } catch (IllegalArgumentException e) {
-                            Log.e(TAG, "Cannot adjust volume: direction=" + direction
-                                    + ", suggestedStream=" + suggestedStream + ", flags=" + flags,
-                                    e);
-                        }
-                    }
-                });
-            } else {
-                session.adjustVolume(packageName, pid, uid, null, asSystemService,
-                        direction, flags, true);
-            }
-        }
-
-        private void handleVoiceKeyEventLocked(String packageName, int pid, int uid,
-                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
-            int action = keyEvent.getAction();
-            boolean isLongPress = (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
-            if (action == KeyEvent.ACTION_DOWN) {
-                if (keyEvent.getRepeatCount() == 0) {
-                    mVoiceButtonDown = true;
-                    mVoiceButtonHandled = false;
-                } else if (mVoiceButtonDown && !mVoiceButtonHandled && isLongPress) {
-                    mVoiceButtonHandled = true;
-                    startVoiceInput(needWakeLock);
-                }
-            } else if (action == KeyEvent.ACTION_UP) {
-                if (mVoiceButtonDown) {
-                    mVoiceButtonDown = false;
-                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
-                        // Resend the down then send this event through
-                        KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
-                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
-                                downEvent, needWakeLock);
-                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
-                                keyEvent, needWakeLock);
-                    }
-                }
-            }
-        }
-
-        private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
-                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
-            MediaSessionRecord session = mCurrentFullUserRecord.getMediaButtonSessionLocked();
-            if (session != null) {
-                if (DEBUG_KEY_EVENT) {
-                    Log.d(TAG, "Sending " + keyEvent + " to " + session);
-                }
-                if (needWakeLock) {
-                    mKeyEventReceiver.aquireWakeLockLocked();
-                }
-                // If we don't need a wakelock use -1 as the id so we won't release it later.
-                session.sendMediaButton(packageName, pid, uid, asSystemService, keyEvent,
-                        needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
-                        mKeyEventReceiver);
-                if (mCurrentFullUserRecord.mCallback != null) {
-                    try {
-                        mCurrentFullUserRecord.mCallback.onMediaKeyEventDispatchedToMediaSession(
-                                keyEvent, new MediaSession.Token(session.getControllerBinder()));
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Failed to send callback", e);
-                    }
-                }
-            } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null
-                    || mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
-                if (needWakeLock) {
-                    mKeyEventReceiver.aquireWakeLockLocked();
-                }
-                Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
-                mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-                mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
-                // TODO: Find a way to also send PID/UID in secure way.
-                String callerPackageName =
-                        (asSystemService) ? getContext().getPackageName() : packageName;
-                mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callerPackageName);
-                try {
-                    if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
-                        PendingIntent receiver = mCurrentFullUserRecord.mLastMediaButtonReceiver;
-                        if (DEBUG_KEY_EVENT) {
-                            Log.d(TAG, "Sending " + keyEvent
-                                    + " to the last known PendingIntent " + receiver);
-                        }
-                        receiver.send(getContext(),
-                                needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
-                                mediaButtonIntent, mKeyEventReceiver, mHandler);
-                        if (mCurrentFullUserRecord.mCallback != null) {
-                            ComponentName componentName = mCurrentFullUserRecord
-                                    .mLastMediaButtonReceiver.getIntent().getComponent();
-                            if (componentName != null) {
-                                mCurrentFullUserRecord.mCallback
-                                        .onMediaKeyEventDispatchedToMediaButtonReceiver(
-                                                keyEvent, componentName);
-                            }
-                        }
-                    } else {
-                        ComponentName receiver =
-                                mCurrentFullUserRecord.mRestoredMediaButtonReceiver;
-                        int componentType = mCurrentFullUserRecord
-                                .mRestoredMediaButtonReceiverComponentType;
-                        UserHandle userHandle = UserHandle.of(mCurrentFullUserRecord
-                                .mRestoredMediaButtonReceiverUserId);
-                        if (DEBUG_KEY_EVENT) {
-                            Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
-                                    + receiver + ", type=" + componentType);
-                        }
-                        mediaButtonIntent.setComponent(receiver);
-                        try {
-                            switch (componentType) {
-                                case FullUserRecord.COMPONENT_TYPE_ACTIVITY:
-                                    getContext().startActivityAsUser(mediaButtonIntent, userHandle);
-                                    break;
-                                case FullUserRecord.COMPONENT_TYPE_SERVICE:
-                                    getContext().startForegroundServiceAsUser(mediaButtonIntent,
-                                            userHandle);
-                                    break;
-                                default:
-                                    // Legacy behavior for other cases.
-                                    getContext().sendBroadcastAsUser(mediaButtonIntent, userHandle);
-                            }
-                        } catch (Exception e) {
-                            Log.w(TAG, "Error sending media button to the restored intent "
-                                    + receiver + ", type=" + componentType, e);
-                        }
-                        if (mCurrentFullUserRecord.mCallback != null) {
-                            mCurrentFullUserRecord.mCallback
-                                    .onMediaKeyEventDispatchedToMediaButtonReceiver(
-                                            keyEvent, receiver);
-                        }
-                    }
-                } catch (CanceledException e) {
-                    Log.i(TAG, "Error sending key event to media button receiver "
-                            + mCurrentFullUserRecord.mLastMediaButtonReceiver, e);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Failed to send callback", e);
-                }
-            }
-        }
-
-        private void startVoiceInput(boolean needWakeLock) {
-            Intent voiceIntent = null;
-            // select which type of search to launch:
-            // - screen on and device unlocked: action is ACTION_WEB_SEARCH
-            // - device locked or screen off: action is
-            // ACTION_VOICE_SEARCH_HANDS_FREE
-            // with EXTRA_SECURE set to true if the device is securely locked
-            PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
-            boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
-            if (!isLocked && pm.isScreenOn()) {
-                voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
-                Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
-            } else {
-                voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
-                voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
-                        isLocked && mKeyguardManager.isKeyguardSecure());
-                Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
-            }
-            // start the search activity
-            if (needWakeLock) {
-                mMediaEventWakeLock.acquire();
-            }
-            try {
-                if (voiceIntent != null) {
-                    voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                    if (DEBUG) Log.d(TAG, "voiceIntent: " + voiceIntent);
-                    getContext().startActivityAsUser(voiceIntent, UserHandle.CURRENT);
-                }
-            } catch (ActivityNotFoundException e) {
-                Log.w(TAG, "No activity for search: " + e);
-            } finally {
-                if (needWakeLock) {
-                    mMediaEventWakeLock.release();
-                }
-            }
-        }
-
-        private boolean isVoiceKey(int keyCode) {
-            return keyCode == KeyEvent.KEYCODE_HEADSETHOOK
-                    || (!mHasFeatureLeanback && keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
-        }
-
-        private boolean isUserSetupComplete() {
-            return Settings.Secure.getIntForUser(getContext().getContentResolver(),
-                    Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
-        }
-
-        // we only handle public stream types, which are 0-5
-        private boolean isValidLocalStreamType(int streamType) {
-            return streamType >= AudioManager.STREAM_VOICE_CALL
-                    && streamType <= AudioManager.STREAM_NOTIFICATION;
-        }
-
-        private class MediaKeyListenerResultReceiver extends ResultReceiver implements Runnable {
-            private final String mPackageName;
-            private final int mPid;
-            private final int mUid;
-            private final boolean mAsSystemService;
-            private final KeyEvent mKeyEvent;
-            private final boolean mNeedWakeLock;
-            private boolean mHandled;
-
-            private MediaKeyListenerResultReceiver(String packageName, int pid, int uid,
-                    boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
-                super(mHandler);
-                mHandler.postDelayed(this, MEDIA_KEY_LISTENER_TIMEOUT);
-                mPackageName = packageName;
-                mPid = pid;
-                mUid = uid;
-                mAsSystemService = asSystemService;
-                mKeyEvent = keyEvent;
-                mNeedWakeLock = needWakeLock;
-            }
-
-            @Override
-            public void run() {
-                Log.d(TAG, "The media key listener is timed-out for " + mKeyEvent);
-                dispatchMediaKeyEvent();
-            }
-
-            @Override
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                if (resultCode == MediaSessionManager.RESULT_MEDIA_KEY_HANDLED) {
-                    mHandled = true;
-                    mHandler.removeCallbacks(this);
-                    return;
-                }
-                dispatchMediaKeyEvent();
-            }
-
-            private void dispatchMediaKeyEvent() {
-                if (mHandled) {
-                    return;
-                }
-                mHandled = true;
-                mHandler.removeCallbacks(this);
-                synchronized (mLock) {
-                    if (!isGlobalPriorityActiveLocked()
-                            && isVoiceKey(mKeyEvent.getKeyCode())) {
-                        handleVoiceKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
-                                mKeyEvent, mNeedWakeLock);
-                    } else {
-                        dispatchMediaKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
-                                mKeyEvent, mNeedWakeLock);
-                    }
-                }
-            }
-        }
-
-        private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler);
-
-        class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable,
-                PendingIntent.OnFinished {
-            private final Handler mHandler;
-            private int mRefCount = 0;
-            private int mLastTimeoutId = 0;
-
-            public KeyEventWakeLockReceiver(Handler handler) {
-                super(handler);
-                mHandler = handler;
-            }
-
-            public void onTimeout() {
-                synchronized (mLock) {
-                    if (mRefCount == 0) {
-                        // We've already released it, so just return
-                        return;
-                    }
-                    mLastTimeoutId++;
-                    mRefCount = 0;
-                    releaseWakeLockLocked();
-                }
-            }
-
-            public void aquireWakeLockLocked() {
-                if (mRefCount == 0) {
-                    mMediaEventWakeLock.acquire();
-                }
-                mRefCount++;
-                mHandler.removeCallbacks(this);
-                mHandler.postDelayed(this, WAKELOCK_TIMEOUT);
-
-            }
-
-            @Override
-            public void run() {
-                onTimeout();
-            }
-
-            @Override
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                if (resultCode < mLastTimeoutId) {
-                    // Ignore results from calls that were before the last
-                    // timeout, just in case.
-                    return;
-                } else {
-                    synchronized (mLock) {
-                        if (mRefCount > 0) {
-                            mRefCount--;
-                            if (mRefCount == 0) {
-                                releaseWakeLockLocked();
-                            }
-                        }
-                    }
-                }
-            }
-
-            private void releaseWakeLockLocked() {
-                mMediaEventWakeLock.release();
-                mHandler.removeCallbacks(this);
-            }
-
-            @Override
-            public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
-                    String resultData, Bundle resultExtras) {
-                onReceiveResult(resultCode, null);
-            }
-        };
-
-        BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (intent == null) {
-                    return;
-                }
-                Bundle extras = intent.getExtras();
-                if (extras == null) {
-                    return;
-                }
-                synchronized (mLock) {
-                    if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)
-                            && mMediaEventWakeLock.isHeld()) {
-                        mMediaEventWakeLock.release();
-                    }
-                }
-            }
-        };
-    }
-
-    final class MessageHandler extends Handler {
-        private static final int MSG_SESSIONS_CHANGED = 1;
-        private static final int MSG_VOLUME_INITIAL_DOWN = 2;
-        private final SparseArray<Integer> mIntegerCache = new SparseArray<>();
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_SESSIONS_CHANGED:
-                    pushSessionsChanged((int) msg.obj);
-                    break;
-                case MSG_VOLUME_INITIAL_DOWN:
-                    synchronized (mLock) {
-                        FullUserRecord user = mUserRecords.get((int) msg.arg1);
-                        if (user != null && user.mInitialDownVolumeKeyEvent != null) {
-                            dispatchVolumeKeyLongPressLocked(user.mInitialDownVolumeKeyEvent);
-                            // Mark that the key is already handled.
-                            user.mInitialDownVolumeKeyEvent = null;
-                        }
-                    }
-                    break;
-            }
-        }
-
-        public void postSessionsChanged(int userId) {
-            // Use object instead of the arguments when posting message to remove pending requests.
-            Integer userIdInteger = mIntegerCache.get(userId);
-            if (userIdInteger == null) {
-                userIdInteger = Integer.valueOf(userId);
-                mIntegerCache.put(userId, userIdInteger);
-            }
-            removeMessages(MSG_SESSIONS_CHANGED, userIdInteger);
-            obtainMessage(MSG_SESSIONS_CHANGED, userIdInteger).sendToTarget();
-        }
+    abstract static class ServiceImpl {
+        public abstract void onStart();
+        public abstract void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session);
+        public abstract void onSessionPlaystateChanged(
+                MediaSessionRecord record, int oldState, int newState);
+        public abstract void onSessionPlaybackTypeChanged(MediaSessionRecord record);
+        public abstract void onStartUser(int userId);
+        public abstract void onSwitchUser(int userId);
+        public abstract void monitor();
+        public abstract void onMediaButtonReceiverChanged(MediaSessionRecord record);
+        protected abstract void enforcePhoneStatePermission(int pid, int uid);
+        abstract void updateSession(MediaSessionRecord record);
+        abstract void setGlobalPrioritySession(MediaSessionRecord record);
+        abstract List<Session2Token> getSession2TokensLocked(int userId);
+        abstract void onStopUser(int userId);
+        abstract void sessionDied(MediaSessionRecord session);
+        abstract void destroySession(MediaSessionRecord session);
+        abstract void pushSession2TokensChangedLocked(int userId);
+        abstract Context getContext();
+        abstract IBinder getServiceBinder();
     }
 }
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
new file mode 100644
index 0000000..1541b1d
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -0,0 +1,2143 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import static android.os.UserHandle.USER_ALL;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.INotificationManager;
+import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.media.AudioManager;
+import android.media.AudioManagerInternal;
+import android.media.AudioPlaybackConfiguration;
+import android.media.AudioSystem;
+import android.media.IAudioService;
+import android.media.IRemoteVolumeController;
+import android.media.MediaController2;
+import android.media.Session2CommandGroup;
+import android.media.Session2Token;
+import android.media.session.ControllerLink;
+import android.media.session.IActiveSessionsListener;
+import android.media.session.ICallback;
+import android.media.session.IOnMediaKeyListener;
+import android.media.session.IOnVolumeKeyLongPressListener;
+import android.media.session.ISession2TokensListener;
+import android.media.session.ISessionManager;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
+import android.media.session.SessionCallbackLink;
+import android.media.session.SessionLink;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.speech.RecognizerIntent;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.DumpUtils;
+import com.android.server.LocalServices;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * System implementation of MediaSessionManager
+ */
+public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
+    private static final String TAG = "MediaSessionService";
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    // Leave log for key event always.
+    private static final boolean DEBUG_KEY_EVENT = true;
+
+    private static final int WAKELOCK_TIMEOUT = 5000;
+    private static final int MEDIA_KEY_LISTENER_TIMEOUT = 1000;
+
+    private final Context mContext;
+    private final SessionManagerImpl mSessionManagerImpl;
+    private final MessageHandler mHandler = new MessageHandler();
+    private final PowerManager.WakeLock mMediaEventWakeLock;
+    private final int mLongPressTimeout;
+    private final INotificationManager mNotificationManager;
+    private final Object mLock = new Object();
+    // Keeps the full user id for each user.
+    @GuardedBy("mLock")
+    private final SparseIntArray mFullUserIds = new SparseIntArray();
+    @GuardedBy("mLock")
+    private final SparseArray<FullUserRecord> mUserRecords = new SparseArray<FullUserRecord>();
+    @GuardedBy("mLock")
+    private final ArrayList<SessionsListenerRecord> mSessionsListeners =
+            new ArrayList<SessionsListenerRecord>();
+    // Map user id as index to list of Session2Tokens
+    // TODO: Keep session2 info in MediaSessionStack for prioritizing both session1 and session2 in
+    //       one place.
+    @GuardedBy("mLock")
+    private final SparseArray<List<Session2Token>> mSession2TokensPerUser = new SparseArray<>();
+    @GuardedBy("mLock")
+    private final List<Session2TokensListenerRecord> mSession2TokensListenerRecords =
+            new ArrayList<>();
+
+    private KeyguardManager mKeyguardManager;
+    private IAudioService mAudioService;
+    private AudioManagerInternal mAudioManagerInternal;
+    private ActivityManager mActivityManager;
+    private ContentResolver mContentResolver;
+    private SettingsObserver mSettingsObserver;
+    private boolean mHasFeatureLeanback;
+
+    // The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile)
+    // It's always not null after the MediaSessionService is started.
+    private FullUserRecord mCurrentFullUserRecord;
+    private MediaSessionRecord mGlobalPrioritySession;
+    private AudioPlayerStateMonitor mAudioPlayerStateMonitor;
+
+    // Used to notify system UI when remote volume was changed. TODO find a
+    // better way to handle this.
+    private IRemoteVolumeController mRvc;
+
+    public MediaSessionServiceImpl(Context context) {
+        mContext = context;
+        mSessionManagerImpl = new SessionManagerImpl();
+        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
+        mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
+        mNotificationManager = INotificationManager.Stub.asInterface(
+                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+    }
+
+    Context getContext() {
+        return mContext;
+    }
+
+    IBinder getServiceBinder() {
+        return mSessionManagerImpl;
+    }
+
+    @Override
+    public void onStart() {
+        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        mAudioService = getAudioService();
+        mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
+        mActivityManager =
+                (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+        mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
+        mAudioPlayerStateMonitor.registerListener(
+                (config, isRemoved) -> {
+                    if (isRemoved || !config.isActive() || config.getPlayerType()
+                            == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
+                        return;
+                    }
+                    synchronized (mLock) {
+                        FullUserRecord user = getFullUserRecordLocked(
+                                UserHandle.getUserId(config.getClientUid()));
+                        if (user != null) {
+                            user.mPriorityStack.updateMediaButtonSessionIfNeeded();
+                        }
+                    }
+                }, null /* handler */);
+        mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
+        mContentResolver = mContext.getContentResolver();
+        mSettingsObserver = new SettingsObserver();
+        mSettingsObserver.observe();
+        mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_LEANBACK);
+
+        updateUser();
+    }
+
+    private IAudioService getAudioService() {
+        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+        return IAudioService.Stub.asInterface(b);
+    }
+
+    private boolean isGlobalPriorityActiveLocked() {
+        return mGlobalPrioritySession != null && mGlobalPrioritySession.isActive();
+    }
+
+    @Override
+    public void updateSession(MediaSessionRecord record) {
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+            if (user == null) {
+                Log.w(TAG, "Unknown session updated. Ignoring.");
+                return;
+            }
+            if ((record.getFlags() & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
+                if (DEBUG_KEY_EVENT) {
+                    Log.d(TAG, "Global priority session is updated, active=" + record.isActive());
+                }
+                user.pushAddressedPlayerChangedLocked();
+            } else {
+                if (!user.mPriorityStack.contains(record)) {
+                    Log.w(TAG, "Unknown session updated. Ignoring.");
+                    return;
+                }
+                user.mPriorityStack.onSessionStateChange(record);
+            }
+            mHandler.postSessionsChanged(record.getUserId());
+        }
+    }
+
+    @Override
+    public void setGlobalPrioritySession(MediaSessionRecord record) {
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+            if (mGlobalPrioritySession != record) {
+                Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession
+                        + " to " + record);
+                mGlobalPrioritySession = record;
+                if (user != null && user.mPriorityStack.contains(record)) {
+                    // Handle the global priority session separately.
+                    // Otherwise, it can be the media button session regardless of the active state
+                    // because it or other system components might have been the lastly played media
+                    // app.
+                    user.mPriorityStack.removeSession(record);
+                }
+            }
+        }
+    }
+
+    private List<MediaSessionRecord> getActiveSessionsLocked(int userId) {
+        List<MediaSessionRecord> records = new ArrayList<>();
+        if (userId == USER_ALL) {
+            int size = mUserRecords.size();
+            for (int i = 0; i < size; i++) {
+                records.addAll(mUserRecords.valueAt(i).mPriorityStack.getActiveSessions(userId));
+            }
+        } else {
+            FullUserRecord user = getFullUserRecordLocked(userId);
+            if (user == null) {
+                Log.w(TAG, "getSessions failed. Unknown user " + userId);
+                return records;
+            }
+            records.addAll(user.mPriorityStack.getActiveSessions(userId));
+        }
+
+        // Return global priority session at the first whenever it's asked.
+        if (isGlobalPriorityActiveLocked()
+                && (userId == USER_ALL || userId == mGlobalPrioritySession.getUserId())) {
+            records.add(0, mGlobalPrioritySession);
+        }
+        return records;
+    }
+
+    List<Session2Token> getSession2TokensLocked(int userId) {
+        List<Session2Token> list = new ArrayList<>();
+        if (userId == USER_ALL) {
+            for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
+                list.addAll(mSession2TokensPerUser.valueAt(i));
+            }
+        } else {
+            list.addAll(mSession2TokensPerUser.get(userId));
+        }
+        return list;
+    }
+
+    /**
+     * Tells the system UI that volume has changed on an active remote session.
+     */
+    public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
+        if (mRvc == null || !session.isActive()) {
+            return;
+        }
+        try {
+            mRvc.remoteVolumeChanged(session.getSessionToken(), flags);
+        } catch (Exception e) {
+            Log.wtf(TAG, "Error sending volume change to system UI.", e);
+        }
+    }
+
+    @Override
+    public void onSessionPlaystateChanged(MediaSessionRecord record, int oldState, int newState) {
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+            if (user == null || !user.mPriorityStack.contains(record)) {
+                Log.d(TAG, "Unknown session changed playback state. Ignoring.");
+                return;
+            }
+            user.mPriorityStack.onPlaystateChanged(record, oldState, newState);
+        }
+    }
+
+    @Override
+    public void onSessionPlaybackTypeChanged(MediaSessionRecord record) {
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+            if (user == null || !user.mPriorityStack.contains(record)) {
+                Log.d(TAG, "Unknown session changed playback type. Ignoring.");
+                return;
+            }
+            pushRemoteVolumeUpdateLocked(record.getUserId());
+        }
+    }
+
+    @Override
+    public void onStartUser(int userId) {
+        if (DEBUG) Log.d(TAG, "onStartUser: " + userId);
+        updateUser();
+    }
+
+    @Override
+    public void onSwitchUser(int userId) {
+        if (DEBUG) Log.d(TAG, "onSwitchUser: " + userId);
+        updateUser();
+    }
+
+    // Called when the user with the userId is removed.
+    @Override
+    public void onStopUser(int userId) {
+        if (DEBUG) Log.d(TAG, "onStopUser: " + userId);
+        synchronized (mLock) {
+            // TODO: Also handle removing user in updateUser() because adding/switching user is
+            //       handled in updateUser().
+            FullUserRecord user = getFullUserRecordLocked(userId);
+            if (user != null) {
+                if (user.mFullUserId == userId) {
+                    user.destroySessionsForUserLocked(USER_ALL);
+                    mUserRecords.remove(userId);
+                } else {
+                    user.destroySessionsForUserLocked(userId);
+                }
+            }
+            mSession2TokensPerUser.remove(userId);
+            updateUser();
+        }
+    }
+
+    @Override
+    public void monitor() {
+        synchronized (mLock) {
+            // Check for deadlock
+        }
+    }
+
+    protected void enforcePhoneStatePermission(int pid, int uid) {
+        if (mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold the MODIFY_PHONE_STATE permission.");
+        }
+    }
+
+    void sessionDied(MediaSessionRecord session) {
+        synchronized (mLock) {
+            destroySessionLocked(session);
+        }
+    }
+
+    void destroySession(MediaSessionRecord session) {
+        synchronized (mLock) {
+            destroySessionLocked(session);
+        }
+    }
+
+    private void updateUser() {
+        synchronized (mLock) {
+            UserManager manager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            mFullUserIds.clear();
+            List<UserInfo> allUsers = manager.getUsers();
+            if (allUsers != null) {
+                for (UserInfo userInfo : allUsers) {
+                    if (userInfo.isManagedProfile()) {
+                        mFullUserIds.put(userInfo.id, userInfo.profileGroupId);
+                    } else {
+                        mFullUserIds.put(userInfo.id, userInfo.id);
+                        if (mUserRecords.get(userInfo.id) == null) {
+                            mUserRecords.put(userInfo.id, new FullUserRecord(userInfo.id));
+                        }
+                    }
+                    if (mSession2TokensPerUser.get(userInfo.id) == null) {
+                        mSession2TokensPerUser.put(userInfo.id, new ArrayList<>());
+                    }
+                }
+            }
+            // Ensure that the current full user exists.
+            int currentFullUserId = ActivityManager.getCurrentUser();
+            mCurrentFullUserRecord = mUserRecords.get(currentFullUserId);
+            if (mCurrentFullUserRecord == null) {
+                Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
+                mCurrentFullUserRecord = new FullUserRecord(currentFullUserId);
+                mUserRecords.put(currentFullUserId, mCurrentFullUserRecord);
+                if (mSession2TokensPerUser.get(currentFullUserId) == null) {
+                    mSession2TokensPerUser.put(currentFullUserId, new ArrayList<>());
+                }
+            }
+            mFullUserIds.put(currentFullUserId, currentFullUserId);
+        }
+    }
+
+    private void updateActiveSessionListeners() {
+        synchronized (mLock) {
+            for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
+                SessionsListenerRecord listener = mSessionsListeners.get(i);
+                try {
+                    enforceMediaPermissions(listener.componentName, listener.pid, listener.uid,
+                            listener.userId);
+                } catch (SecurityException e) {
+                    Log.i(TAG, "ActiveSessionsListener " + listener.componentName
+                            + " is no longer authorized. Disconnecting.");
+                    mSessionsListeners.remove(i);
+                    try {
+                        listener.listener
+                                .onActiveSessionsChanged(new ArrayList<MediaSession.Token>());
+                    } catch (Exception e1) {
+                        // ignore
+                    }
+                }
+            }
+        }
+    }
+
+    /*
+     * When a session is removed several things need to happen.
+     * 1. We need to remove it from the relevant user.
+     * 2. We need to remove it from the priority stack.
+     * 3. We need to remove it from all sessions.
+     * 4. If this is the system priority session we need to clear it.
+     * 5. We need to unlink to death from the cb binder
+     * 6. We need to tell the session to do any final cleanup (onDestroy)
+     */
+    private void destroySessionLocked(MediaSessionRecord session) {
+        if (DEBUG) {
+            Log.d(TAG, "Destroying " + session);
+        }
+        FullUserRecord user = getFullUserRecordLocked(session.getUserId());
+        if (mGlobalPrioritySession == session) {
+            mGlobalPrioritySession = null;
+            if (session.isActive() && user != null) {
+                user.pushAddressedPlayerChangedLocked();
+            }
+        } else {
+            if (user != null) {
+                user.mPriorityStack.removeSession(session);
+            }
+        }
+
+        try {
+            session.getCallback().getBinder().unlinkToDeath(session, 0);
+        } catch (Exception e) {
+            // ignore exceptions while destroying a session.
+        }
+        session.onDestroy();
+        mHandler.postSessionsChanged(session.getUserId());
+    }
+
+    private void enforcePackageName(String packageName, int uid) {
+        if (TextUtils.isEmpty(packageName)) {
+            throw new IllegalArgumentException("packageName may not be empty");
+        }
+        String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
+        final int packageCount = packages.length;
+        for (int i = 0; i < packageCount; i++) {
+            if (packageName.equals(packages[i])) {
+                return;
+            }
+        }
+        throw new IllegalArgumentException("packageName is not owned by the calling process");
+    }
+
+    /**
+     * Checks a caller's authorization to register an IRemoteControlDisplay.
+     * Authorization is granted if one of the following is true:
+     * <ul>
+     * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL
+     * permission</li>
+     * <li>the caller's listener is one of the enabled notification listeners
+     * for the caller's user</li>
+     * </ul>
+     */
+    private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
+            int resolvedUserId) {
+        if (isCurrentVolumeController(pid, uid)) return;
+        if (mContext
+                .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
+                != PackageManager.PERMISSION_GRANTED
+                && !isEnabledNotificationListener(compName, UserHandle.getUserId(uid),
+                resolvedUserId)) {
+            throw new SecurityException("Missing permission to control media.");
+        }
+    }
+
+    private boolean isCurrentVolumeController(int pid, int uid) {
+        return mContext.checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
+                pid, uid) == PackageManager.PERMISSION_GRANTED;
+    }
+
+    private void enforceSystemUiPermission(String action, int pid, int uid) {
+        if (!isCurrentVolumeController(pid, uid)) {
+            throw new SecurityException("Only system ui may " + action);
+        }
+    }
+
+    /**
+     * This checks if the component is an enabled notification listener for the
+     * specified user. Enabled components may only operate on behalf of the user
+     * they're running as.
+     *
+     * @param compName The component that is enabled.
+     * @param userId The user id of the caller.
+     * @param forUserId The user id they're making the request on behalf of.
+     * @return True if the component is enabled, false otherwise
+     */
+    private boolean isEnabledNotificationListener(ComponentName compName, int userId,
+            int forUserId) {
+        if (userId != forUserId) {
+            // You may not access another user's content as an enabled listener.
+            return false;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Checking if enabled notification listener " + compName);
+        }
+        if (compName != null) {
+            try {
+                return mNotificationManager.isNotificationListenerAccessGrantedForUser(
+                        compName, userId);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Dead NotificationManager in isEnabledNotificationListener", e);
+            }
+        }
+        return false;
+    }
+
+    private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
+            String callerPackageName, SessionCallbackLink cb, String tag) throws RemoteException {
+        synchronized (mLock) {
+            return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag);
+        }
+    }
+
+    /*
+     * When a session is created the following things need to happen.
+     * 1. Its callback binder needs a link to death
+     * 2. It needs to be added to all sessions.
+     * 3. It needs to be added to the priority stack.
+     * 4. It needs to be added to the relevant user record.
+     */
+    private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
+            String callerPackageName, SessionCallbackLink cb, String tag) {
+        FullUserRecord user = getFullUserRecordLocked(userId);
+        if (user == null) {
+            Log.wtf(TAG, "Request from invalid user: " +  userId);
+            throw new RuntimeException("Session request from invalid user.");
+        }
+
+        final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
+                callerPackageName, cb, tag, this, mHandler.getLooper());
+        try {
+            cb.getBinder().linkToDeath(session, 0);
+        } catch (RemoteException e) {
+            throw new RuntimeException("Media Session owner died prematurely.", e);
+        }
+
+        user.mPriorityStack.addSession(session);
+        mHandler.postSessionsChanged(userId);
+
+        if (DEBUG) {
+            Log.d(TAG, "Created session for " + callerPackageName + " with tag " + tag);
+        }
+        return session;
+    }
+
+    private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
+        for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
+            if (mSessionsListeners.get(i).listener.asBinder() == listener.asBinder()) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private int findIndexOfSession2TokensListenerLocked(ISession2TokensListener listener) {
+        for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
+            if (mSession2TokensListenerRecords.get(i).listener.asBinder() == listener.asBinder()) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+
+    private void pushSessionsChanged(int userId) {
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(userId);
+            if (user == null) {
+                Log.w(TAG, "pushSessionsChanged failed. No user with id=" + userId);
+                return;
+            }
+            List<MediaSessionRecord> records = getActiveSessionsLocked(userId);
+            int size = records.size();
+            ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();
+            for (int i = 0; i < size; i++) {
+                tokens.add(records.get(i).getSessionToken());
+            }
+            pushRemoteVolumeUpdateLocked(userId);
+            for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
+                SessionsListenerRecord record = mSessionsListeners.get(i);
+                if (record.userId == USER_ALL || record.userId == userId) {
+                    try {
+                        record.listener.onActiveSessionsChanged(tokens);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Dead ActiveSessionsListener in pushSessionsChanged, removing",
+                                e);
+                        mSessionsListeners.remove(i);
+                    }
+                }
+            }
+        }
+    }
+
+    private void pushRemoteVolumeUpdateLocked(int userId) {
+        if (mRvc != null) {
+            try {
+                FullUserRecord user = getFullUserRecordLocked(userId);
+                if (user == null) {
+                    Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId);
+                    return;
+                }
+                MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
+                mRvc.updateRemoteController(record == null ? null : record.getSessionToken());
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error sending default remote volume to sys ui.", e);
+            }
+        }
+    }
+
+    void pushSession2TokensChangedLocked(int userId) {
+        List<Session2Token> allSession2Tokens = getSession2TokensLocked(USER_ALL);
+        List<Session2Token> session2Tokens = getSession2TokensLocked(userId);
+
+        for (int i = mSession2TokensListenerRecords.size() - 1; i >= 0; i--) {
+            Session2TokensListenerRecord listenerRecord = mSession2TokensListenerRecords.get(i);
+            try {
+                if (listenerRecord.userId == USER_ALL) {
+                    listenerRecord.listener.onSession2TokensChanged(allSession2Tokens);
+                } else if (listenerRecord.userId == userId) {
+                    listenerRecord.listener.onSession2TokensChanged(session2Tokens);
+                }
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to notify Session2Token change. Removing listener.", e);
+                mSession2TokensListenerRecords.remove(i);
+            }
+        }
+    }
+
+    /**
+     * Called when the media button receiver for the {@code record} is changed.
+     *
+     * @param record the media session whose media button receiver is updated.
+     */
+    public void onMediaButtonReceiverChanged(MediaSessionRecord record) {
+        synchronized (mLock) {
+            FullUserRecord user = getFullUserRecordLocked(record.getUserId());
+            MediaSessionRecord mediaButtonSession =
+                    user.mPriorityStack.getMediaButtonSession();
+            if (record == mediaButtonSession) {
+                user.rememberMediaButtonReceiverLocked(mediaButtonSession);
+            }
+        }
+    }
+
+    private String getCallingPackageName(int uid) {
+        String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
+        if (packages != null && packages.length > 0) {
+            return packages[0];
+        }
+        return "";
+    }
+
+    private void dispatchVolumeKeyLongPressLocked(KeyEvent keyEvent) {
+        if (mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
+            return;
+        }
+        try {
+            mCurrentFullUserRecord.mOnVolumeKeyLongPressListener.onVolumeKeyLongPress(keyEvent);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to send " + keyEvent + " to volume key long-press listener");
+        }
+    }
+
+    private FullUserRecord getFullUserRecordLocked(int userId) {
+        int fullUserId = mFullUserIds.get(userId, -1);
+        if (fullUserId < 0) {
+            return null;
+        }
+        return mUserRecords.get(fullUserId);
+    }
+
+    /**
+     * Information about a full user and its corresponding managed profiles.
+     *
+     * <p>Since the full user runs together with its managed profiles, a user wouldn't differentiate
+     * them when he/she presses a media/volume button. So keeping media sessions for them in one
+     * place makes more sense and increases the readability.</p>
+     * <p>The contents of this object is guarded by {@link #mLock}.
+     */
+    final class FullUserRecord implements MediaSessionStack.OnMediaButtonSessionChangedListener {
+        public static final int COMPONENT_TYPE_INVALID = 0;
+        public static final int COMPONENT_TYPE_BROADCAST = 1;
+        public static final int COMPONENT_TYPE_ACTIVITY = 2;
+        public static final int COMPONENT_TYPE_SERVICE = 3;
+        private static final String COMPONENT_NAME_USER_ID_DELIM = ",";
+
+        private final int mFullUserId;
+        private final MediaSessionStack mPriorityStack;
+        private PendingIntent mLastMediaButtonReceiver;
+        private ComponentName mRestoredMediaButtonReceiver;
+        private int mRestoredMediaButtonReceiverComponentType;
+        private int mRestoredMediaButtonReceiverUserId;
+
+        private IOnVolumeKeyLongPressListener mOnVolumeKeyLongPressListener;
+        private int mOnVolumeKeyLongPressListenerUid;
+        private KeyEvent mInitialDownVolumeKeyEvent;
+        private int mInitialDownVolumeStream;
+        private boolean mInitialDownMusicOnly;
+
+        private IOnMediaKeyListener mOnMediaKeyListener;
+        private int mOnMediaKeyListenerUid;
+        private ICallback mCallback;
+
+        FullUserRecord(int fullUserId) {
+            mFullUserId = fullUserId;
+            mPriorityStack = new MediaSessionStack(mAudioPlayerStateMonitor, this);
+            // Restore the remembered media button receiver before the boot.
+            String mediaButtonReceiverInfo = Settings.Secure.getStringForUser(mContentResolver,
+                    Settings.System.MEDIA_BUTTON_RECEIVER, mFullUserId);
+            if (mediaButtonReceiverInfo == null) {
+                return;
+            }
+            String[] tokens = mediaButtonReceiverInfo.split(COMPONENT_NAME_USER_ID_DELIM);
+            if (tokens == null || (tokens.length != 2 && tokens.length != 3)) {
+                return;
+            }
+            mRestoredMediaButtonReceiver = ComponentName.unflattenFromString(tokens[0]);
+            mRestoredMediaButtonReceiverUserId = Integer.parseInt(tokens[1]);
+            if (tokens.length == 3) {
+                mRestoredMediaButtonReceiverComponentType = Integer.parseInt(tokens[2]);
+            } else {
+                mRestoredMediaButtonReceiverComponentType =
+                        getComponentType(mRestoredMediaButtonReceiver);
+            }
+        }
+
+        public void destroySessionsForUserLocked(int userId) {
+            List<MediaSessionRecord> sessions = mPriorityStack.getPriorityList(false, userId);
+            for (MediaSessionRecord session : sessions) {
+                MediaSessionServiceImpl.this.destroySessionLocked(session);
+            }
+        }
+
+        public void dumpLocked(PrintWriter pw, String prefix) {
+            pw.print(prefix + "Record for full_user=" + mFullUserId);
+            // Dump managed profile user ids associated with this user.
+            int size = mFullUserIds.size();
+            for (int i = 0; i < size; i++) {
+                if (mFullUserIds.keyAt(i) != mFullUserIds.valueAt(i)
+                        && mFullUserIds.valueAt(i) == mFullUserId) {
+                    pw.print(", profile_user=" + mFullUserIds.keyAt(i));
+                }
+            }
+            pw.println();
+            String indent = prefix + "  ";
+            pw.println(indent + "Volume key long-press listener: " + mOnVolumeKeyLongPressListener);
+            pw.println(indent + "Volume key long-press listener package: "
+                    + getCallingPackageName(mOnVolumeKeyLongPressListenerUid));
+            pw.println(indent + "Media key listener: " + mOnMediaKeyListener);
+            pw.println(indent + "Media key listener package: "
+                    + getCallingPackageName(mOnMediaKeyListenerUid));
+            pw.println(indent + "Callback: " + mCallback);
+            pw.println(indent + "Last MediaButtonReceiver: " + mLastMediaButtonReceiver);
+            pw.println(indent + "Restored MediaButtonReceiver: " + mRestoredMediaButtonReceiver);
+            pw.println(indent + "Restored MediaButtonReceiverComponentType: "
+                    + mRestoredMediaButtonReceiverComponentType);
+            mPriorityStack.dump(pw, indent);
+            pw.println(indent + "Session2Tokens:");
+            for (int i = 0; i < mSession2TokensPerUser.size(); i++) {
+                List<Session2Token> list = mSession2TokensPerUser.valueAt(i);
+                if (list == null || list.size() == 0) {
+                    continue;
+                }
+                for (Session2Token token : list) {
+                    pw.println(indent + "  " + token);
+                }
+            }
+        }
+
+        @Override
+        public void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession,
+                MediaSessionRecord newMediaButtonSession) {
+            if (DEBUG_KEY_EVENT) {
+                Log.d(TAG, "Media button session is changed to " + newMediaButtonSession);
+            }
+            synchronized (mLock) {
+                if (oldMediaButtonSession != null) {
+                    mHandler.postSessionsChanged(oldMediaButtonSession.getUserId());
+                }
+                if (newMediaButtonSession != null) {
+                    rememberMediaButtonReceiverLocked(newMediaButtonSession);
+                    mHandler.postSessionsChanged(newMediaButtonSession.getUserId());
+                }
+                pushAddressedPlayerChangedLocked();
+            }
+        }
+
+        // Remember media button receiver and keep it in the persistent storage.
+        public void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {
+            PendingIntent receiver = record.getMediaButtonReceiver();
+            mLastMediaButtonReceiver = receiver;
+            mRestoredMediaButtonReceiver = null;
+            mRestoredMediaButtonReceiverComponentType = COMPONENT_TYPE_INVALID;
+
+            String mediaButtonReceiverInfo = "";
+            if (receiver != null) {
+                ComponentName component = receiver.getIntent().getComponent();
+                if (component != null
+                        && record.getPackageName().equals(component.getPackageName())) {
+                    String componentName = component.flattenToString();
+                    int componentType = getComponentType(component);
+                    mediaButtonReceiverInfo = String.join(COMPONENT_NAME_USER_ID_DELIM,
+                            componentName, String.valueOf(record.getUserId()),
+                            String.valueOf(componentType));
+                }
+            }
+            Settings.Secure.putStringForUser(mContentResolver,
+                    Settings.System.MEDIA_BUTTON_RECEIVER, mediaButtonReceiverInfo,
+                    mFullUserId);
+        }
+
+        private void pushAddressedPlayerChangedLocked() {
+            if (mCallback == null) {
+                return;
+            }
+            try {
+                MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked();
+                if (mediaButtonSession != null) {
+                    mCallback.onAddressedPlayerChangedToMediaSession(
+                            mediaButtonSession.getSessionToken());
+                } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
+                    mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
+                            mCurrentFullUserRecord.mLastMediaButtonReceiver
+                                    .getIntent().getComponent());
+                } else if (mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
+                    mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
+                            mCurrentFullUserRecord.mRestoredMediaButtonReceiver);
+                }
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e);
+            }
+        }
+
+        private MediaSessionRecord getMediaButtonSessionLocked() {
+            return isGlobalPriorityActiveLocked()
+                    ? mGlobalPrioritySession : mPriorityStack.getMediaButtonSession();
+        }
+
+        private int getComponentType(@Nullable ComponentName componentName) {
+            if (componentName == null) {
+                return COMPONENT_TYPE_INVALID;
+            }
+            PackageManager pm = mContext.getPackageManager();
+            try {
+                ActivityInfo activityInfo = pm.getActivityInfo(componentName,
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                                | PackageManager.GET_ACTIVITIES);
+                if (activityInfo != null) {
+                    return COMPONENT_TYPE_ACTIVITY;
+                }
+            } catch (NameNotFoundException e) {
+            }
+            try {
+                ServiceInfo serviceInfo = pm.getServiceInfo(componentName,
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+                                | PackageManager.GET_SERVICES);
+                if (serviceInfo != null) {
+                    return COMPONENT_TYPE_SERVICE;
+                }
+            } catch (NameNotFoundException e) {
+            }
+            // Pick legacy behavior for BroadcastReceiver or unknown.
+            return COMPONENT_TYPE_BROADCAST;
+        }
+    }
+
+    final class SessionsListenerRecord implements IBinder.DeathRecipient {
+        public final IActiveSessionsListener listener;
+        public final ComponentName componentName;
+        public final int userId;
+        public final int pid;
+        public final int uid;
+
+        SessionsListenerRecord(IActiveSessionsListener listener,
+                ComponentName componentName,
+                int userId, int pid, int uid) {
+            this.listener = listener;
+            this.componentName = componentName;
+            this.userId = userId;
+            this.pid = pid;
+            this.uid = uid;
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (mLock) {
+                mSessionsListeners.remove(this);
+            }
+        }
+    }
+
+    final class Session2TokensListenerRecord implements IBinder.DeathRecipient {
+        public final ISession2TokensListener listener;
+        public final int userId;
+
+        Session2TokensListenerRecord(ISession2TokensListener listener,
+                int userId) {
+            this.listener = listener;
+            this.userId = userId;
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (mLock) {
+                mSession2TokensListenerRecords.remove(this);
+            }
+        }
+    }
+
+    final class SettingsObserver extends ContentObserver {
+        private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(
+                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+
+        private SettingsObserver() {
+            super(null);
+        }
+
+        private void observe() {
+            mContentResolver.registerContentObserver(mSecureSettingsUri,
+                    false, this, USER_ALL);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            updateActiveSessionListeners();
+        }
+    }
+
+    class SessionManagerImpl extends ISessionManager.Stub {
+        private static final String EXTRA_WAKELOCK_ACQUIRED =
+                "android.media.AudioService.WAKELOCK_ACQUIRED";
+        private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number
+
+        private boolean mVoiceButtonDown = false;
+        private boolean mVoiceButtonHandled = false;
+
+        @Override
+        public SessionLink createSession(String packageName, SessionCallbackLink cb, String tag,
+                int userId) throws RemoteException {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                enforcePackageName(packageName, uid);
+                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                        false /* allowAll */, true /* requireFull */, "createSession", packageName);
+                if (cb == null) {
+                    throw new IllegalArgumentException("Controller callback cannot be null");
+                }
+                return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag)
+                        .getSessionBinder();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifySession2Created(Session2Token sessionToken) throws RemoteException {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (DEBUG) {
+                    Log.d(TAG, "Session2 is created " + sessionToken);
+                }
+                if (uid != sessionToken.getUid()) {
+                    throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
+                            + " but actually=" + sessionToken.getUid());
+                }
+                Controller2Callback callback = new Controller2Callback(sessionToken);
+                // Note: It's safe not to keep controller here because it wouldn't be GC'ed until
+                //       it's closed.
+                // TODO: Keep controller as well for better readability
+                //       because the GC behavior isn't straightforward.
+                MediaController2 controller = new MediaController2(mContext, sessionToken,
+                        new HandlerExecutor(mHandler), callback);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public List<ControllerLink> getSessions(ComponentName componentName, int userId) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
+                ArrayList<ControllerLink> binders = new ArrayList<>();
+                synchronized (mLock) {
+                    List<MediaSessionRecord> records = getActiveSessionsLocked(resolvedUserId);
+                    for (MediaSessionRecord record : records) {
+                        binders.add(record.getControllerLink());
+                    }
+                }
+                return binders;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public List<Session2Token> getSession2Tokens(int userId) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                // Check that they can make calls on behalf of the user and
+                // get the final user id
+                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                        true /* allowAll */, true /* requireFull */, "getSession2Tokens",
+                        null /* optional packageName */);
+                List<Session2Token> result;
+                synchronized (mLock) {
+                    result = getSession2TokensLocked(resolvedUserId);
+                }
+                return result;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void addSessionsListener(IActiveSessionsListener listener,
+                ComponentName componentName, int userId) throws RemoteException {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
+                synchronized (mLock) {
+                    int index = findIndexOfSessionsListenerLocked(listener);
+                    if (index != -1) {
+                        Log.w(TAG, "ActiveSessionsListener is already added, ignoring");
+                        return;
+                    }
+                    SessionsListenerRecord record = new SessionsListenerRecord(listener,
+                            componentName, resolvedUserId, pid, uid);
+                    try {
+                        listener.asBinder().linkToDeath(record, 0);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "ActiveSessionsListener is dead, ignoring it", e);
+                        return;
+                    }
+                    mSessionsListeners.add(record);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void removeSessionsListener(IActiveSessionsListener listener)
+                throws RemoteException {
+            synchronized (mLock) {
+                int index = findIndexOfSessionsListenerLocked(listener);
+                if (index != -1) {
+                    SessionsListenerRecord record = mSessionsListeners.remove(index);
+                    try {
+                        record.listener.asBinder().unlinkToDeath(record, 0);
+                    } catch (Exception e) {
+                        // ignore exceptions, the record is being removed
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void addSession2TokensListener(ISession2TokensListener listener,
+                int userId) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                // Check that they can make calls on behalf of the user and get the final user id.
+                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                        true /* allowAll */, true /* requireFull */, "addSession2TokensListener",
+                        null /* optional packageName */);
+                synchronized (mLock) {
+                    int index = findIndexOfSession2TokensListenerLocked(listener);
+                    if (index >= 0) {
+                        Log.w(TAG, "addSession2TokensListener is already added, ignoring");
+                        return;
+                    }
+                    mSession2TokensListenerRecords.add(
+                            new Session2TokensListenerRecord(listener, resolvedUserId));
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void removeSession2TokensListener(ISession2TokensListener listener) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                synchronized (mLock) {
+                    int index = findIndexOfSession2TokensListenerLocked(listener);
+                    if (index >= 0) {
+                        Session2TokensListenerRecord listenerRecord =
+                                mSession2TokensListenerRecords.remove(index);
+                        try {
+                            listenerRecord.listener.asBinder().unlinkToDeath(listenerRecord, 0);
+                        } catch (Exception e) {
+                            // Ignore exception.
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        /**
+         * Handles the dispatching of the media button events to one of the
+         * registered listeners, or if there was none, broadcast an
+         * ACTION_MEDIA_BUTTON intent to the rest of the system.
+         *
+         * @param packageName The caller package
+         * @param asSystemService {@code true} if the event sent to the session as if it was come
+         *          from the system service instead of the app process. This helps sessions to
+         *          distinguish between the key injection by the app and key events from the
+         *          hardware devices. Should be used only when the volume key events aren't handled
+         *          by foreground activity. {@code false} otherwise to tell session about the real
+         *          caller.
+         * @param keyEvent a non-null KeyEvent whose key code is one of the
+         *            supported media buttons
+         * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held
+         *            while this key event is dispatched.
+         */
+        @Override
+        public void dispatchMediaKeyEvent(String packageName, boolean asSystemService,
+                KeyEvent keyEvent, boolean needWakeLock) {
+            if (keyEvent == null || !KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
+                Log.w(TAG, "Attempted to dispatch null or non-media key event.");
+                return;
+            }
+
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (DEBUG) {
+                    Log.d(TAG, "dispatchMediaKeyEvent, pkg=" + packageName + " pid=" + pid
+                            + ", uid=" + uid + ", asSystem=" + asSystemService + ", event="
+                            + keyEvent);
+                }
+                if (!isUserSetupComplete()) {
+                    // Global media key handling can have the side-effect of starting new
+                    // activities which is undesirable while setup is in progress.
+                    Slog.i(TAG, "Not dispatching media key event because user "
+                            + "setup is in progress.");
+                    return;
+                }
+
+                synchronized (mLock) {
+                    boolean isGlobalPriorityActive = isGlobalPriorityActiveLocked();
+                    if (isGlobalPriorityActive && uid != Process.SYSTEM_UID) {
+                        // Prevent dispatching key event through reflection while the global
+                        // priority session is active.
+                        Slog.i(TAG, "Only the system can dispatch media key event "
+                                + "to the global priority session.");
+                        return;
+                    }
+                    if (!isGlobalPriorityActive) {
+                        if (mCurrentFullUserRecord.mOnMediaKeyListener != null) {
+                            if (DEBUG_KEY_EVENT) {
+                                Log.d(TAG, "Send " + keyEvent + " to the media key listener");
+                            }
+                            try {
+                                mCurrentFullUserRecord.mOnMediaKeyListener.onMediaKey(keyEvent,
+                                        new MediaKeyListenerResultReceiver(packageName, pid, uid,
+                                                asSystemService, keyEvent, needWakeLock));
+                                return;
+                            } catch (RemoteException e) {
+                                Log.w(TAG, "Failed to send " + keyEvent
+                                        + " to the media key listener");
+                            }
+                        }
+                    }
+                    if (!isGlobalPriorityActive && isVoiceKey(keyEvent.getKeyCode())) {
+                        handleVoiceKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
+                                needWakeLock);
+                    } else {
+                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+                                keyEvent, needWakeLock);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void setCallback(ICallback callback) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (!UserHandle.isSameApp(uid, Process.BLUETOOTH_UID)) {
+                    throw new SecurityException("Only Bluetooth service processes can set"
+                            + " Callback");
+                }
+                synchronized (mLock) {
+                    int userId = UserHandle.getUserId(uid);
+                    FullUserRecord user = getFullUserRecordLocked(userId);
+                    if (user == null || user.mFullUserId != userId) {
+                        Log.w(TAG, "Only the full user can set the callback"
+                                + ", userId=" + userId);
+                        return;
+                    }
+                    user.mCallback = callback;
+                    Log.d(TAG, "The callback " + user.mCallback
+                            + " is set by " + getCallingPackageName(uid));
+                    if (user.mCallback == null) {
+                        return;
+                    }
+                    try {
+                        user.mCallback.asBinder().linkToDeath(
+                                new IBinder.DeathRecipient() {
+                                    @Override
+                                    public void binderDied() {
+                                        synchronized (mLock) {
+                                            user.mCallback = null;
+                                        }
+                                    }
+                                }, 0);
+                        user.pushAddressedPlayerChangedLocked();
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to set callback", e);
+                        user.mCallback = null;
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void setOnVolumeKeyLongPressListener(IOnVolumeKeyLongPressListener listener) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                // Enforce SET_VOLUME_KEY_LONG_PRESS_LISTENER permission.
+                if (mContext.checkPermission(
+                        android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER, pid, uid)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException("Must hold the SET_VOLUME_KEY_LONG_PRESS_LISTENER"
+                            + " permission.");
+                }
+
+                synchronized (mLock) {
+                    int userId = UserHandle.getUserId(uid);
+                    FullUserRecord user = getFullUserRecordLocked(userId);
+                    if (user == null || user.mFullUserId != userId) {
+                        Log.w(TAG, "Only the full user can set the volume key long-press listener"
+                                + ", userId=" + userId);
+                        return;
+                    }
+                    if (user.mOnVolumeKeyLongPressListener != null
+                            && user.mOnVolumeKeyLongPressListenerUid != uid) {
+                        Log.w(TAG, "The volume key long-press listener cannot be reset"
+                                + " by another app , mOnVolumeKeyLongPressListener="
+                                + user.mOnVolumeKeyLongPressListenerUid
+                                + ", uid=" + uid);
+                        return;
+                    }
+
+                    user.mOnVolumeKeyLongPressListener = listener;
+                    user.mOnVolumeKeyLongPressListenerUid = uid;
+
+                    Log.d(TAG, "The volume key long-press listener "
+                            + listener + " is set by " + getCallingPackageName(uid));
+
+                    if (user.mOnVolumeKeyLongPressListener != null) {
+                        try {
+                            user.mOnVolumeKeyLongPressListener.asBinder().linkToDeath(
+                                    new IBinder.DeathRecipient() {
+                                        @Override
+                                        public void binderDied() {
+                                            synchronized (mLock) {
+                                                user.mOnVolumeKeyLongPressListener = null;
+                                            }
+                                        }
+                                    }, 0);
+                        } catch (RemoteException e) {
+                            Log.w(TAG, "Failed to set death recipient "
+                                    + user.mOnVolumeKeyLongPressListener);
+                            user.mOnVolumeKeyLongPressListener = null;
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void setOnMediaKeyListener(IOnMediaKeyListener listener) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                // Enforce SET_MEDIA_KEY_LISTENER permission.
+                if (mContext.checkPermission(
+                        android.Manifest.permission.SET_MEDIA_KEY_LISTENER, pid, uid)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException("Must hold the SET_MEDIA_KEY_LISTENER permission.");
+                }
+
+                synchronized (mLock) {
+                    int userId = UserHandle.getUserId(uid);
+                    FullUserRecord user = getFullUserRecordLocked(userId);
+                    if (user == null || user.mFullUserId != userId) {
+                        Log.w(TAG, "Only the full user can set the media key listener"
+                                + ", userId=" + userId);
+                        return;
+                    }
+                    if (user.mOnMediaKeyListener != null && user.mOnMediaKeyListenerUid != uid) {
+                        Log.w(TAG, "The media key listener cannot be reset by another app. "
+                                + ", mOnMediaKeyListenerUid=" + user.mOnMediaKeyListenerUid
+                                + ", uid=" + uid);
+                        return;
+                    }
+
+                    user.mOnMediaKeyListener = listener;
+                    user.mOnMediaKeyListenerUid = uid;
+
+                    Log.d(TAG, "The media key listener " + user.mOnMediaKeyListener
+                            + " is set by " + getCallingPackageName(uid));
+
+                    if (user.mOnMediaKeyListener != null) {
+                        try {
+                            user.mOnMediaKeyListener.asBinder().linkToDeath(
+                                    new IBinder.DeathRecipient() {
+                                        @Override
+                                        public void binderDied() {
+                                            synchronized (mLock) {
+                                                user.mOnMediaKeyListener = null;
+                                            }
+                                        }
+                                    }, 0);
+                        } catch (RemoteException e) {
+                            Log.w(TAG, "Failed to set death recipient " + user.mOnMediaKeyListener);
+                            user.mOnMediaKeyListener = null;
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        /**
+         * Handles the dispatching of the volume button events to one of the
+         * registered listeners. If there's a volume key long-press listener and
+         * there's no active global priority session, long-pressess will be sent to the
+         * long-press listener instead of adjusting volume.
+         *
+         * @param packageName The caller's package name, obtained by Context#getPackageName()
+         * @param opPackageName The caller's op package name, obtained by Context#getOpPackageName()
+         * @param asSystemService {@code true} if the event sent to the session as if it was come
+         *          from the system service instead of the app process. This helps sessions to
+         *          distinguish between the key injection by the app and key events from the
+         *          hardware devices. Should be used only when the volume key events aren't handled
+         *          by foreground activity. {@code false} otherwise to tell session about the real
+         *          caller.
+         * @param keyEvent a non-null KeyEvent whose key code is one of the
+         *            {@link KeyEvent#KEYCODE_VOLUME_UP},
+         *            {@link KeyEvent#KEYCODE_VOLUME_DOWN},
+         *            or {@link KeyEvent#KEYCODE_VOLUME_MUTE}.
+         * @param stream stream type to adjust volume.
+         * @param musicOnly true if both UI nor haptic feedback aren't needed when adjust volume.
+         */
+        @Override
+        public void dispatchVolumeKeyEvent(String packageName, String opPackageName,
+                boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly) {
+            if (keyEvent == null
+                    || (keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_UP
+                            && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_DOWN
+                            && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_MUTE)) {
+                Log.w(TAG, "Attempted to dispatch null or non-volume key event.");
+                return;
+            }
+
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+
+            if (DEBUG_KEY_EVENT) {
+                Log.d(TAG, "dispatchVolumeKeyEvent, pkg=" + packageName + ", pid=" + pid + ", uid="
+                        + uid + ", asSystem=" + asSystemService + ", event=" + keyEvent);
+            }
+
+            try {
+                synchronized (mLock) {
+                    if (isGlobalPriorityActiveLocked()
+                            || mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
+                        dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+                                asSystemService, keyEvent, stream, musicOnly);
+                    } else {
+                        // TODO: Consider the case when both volume up and down keys are pressed
+                        //       at the same time.
+                        if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
+                            if (keyEvent.getRepeatCount() == 0) {
+                                // Keeps the copy of the KeyEvent because it can be reused.
+                                mCurrentFullUserRecord.mInitialDownVolumeKeyEvent =
+                                        KeyEvent.obtain(keyEvent);
+                                mCurrentFullUserRecord.mInitialDownVolumeStream = stream;
+                                mCurrentFullUserRecord.mInitialDownMusicOnly = musicOnly;
+                                mHandler.sendMessageDelayed(
+                                        mHandler.obtainMessage(
+                                                MessageHandler.MSG_VOLUME_INITIAL_DOWN,
+                                                mCurrentFullUserRecord.mFullUserId, 0),
+                                        mLongPressTimeout);
+                            }
+                            if (keyEvent.getRepeatCount() > 0 || keyEvent.isLongPress()) {
+                                mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
+                                if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null) {
+                                    dispatchVolumeKeyLongPressLocked(
+                                            mCurrentFullUserRecord.mInitialDownVolumeKeyEvent);
+                                    // Mark that the key is already handled.
+                                    mCurrentFullUserRecord.mInitialDownVolumeKeyEvent = null;
+                                }
+                                dispatchVolumeKeyLongPressLocked(keyEvent);
+                            }
+                        } else { // if up
+                            mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
+                            if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null
+                                    && mCurrentFullUserRecord.mInitialDownVolumeKeyEvent
+                                    .getDownTime() == keyEvent.getDownTime()) {
+                                // Short-press. Should change volume.
+                                dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+                                        asSystemService,
+                                        mCurrentFullUserRecord.mInitialDownVolumeKeyEvent,
+                                        mCurrentFullUserRecord.mInitialDownVolumeStream,
+                                        mCurrentFullUserRecord.mInitialDownMusicOnly);
+                                dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+                                        asSystemService, keyEvent, stream, musicOnly);
+                            } else {
+                                dispatchVolumeKeyLongPressLocked(keyEvent);
+                            }
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        private void dispatchVolumeKeyEventLocked(String packageName, String opPackageName, int pid,
+                int uid, boolean asSystemService, KeyEvent keyEvent, int stream,
+                boolean musicOnly) {
+            boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
+            boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP;
+            int direction = 0;
+            boolean isMute = false;
+            switch (keyEvent.getKeyCode()) {
+                case KeyEvent.KEYCODE_VOLUME_UP:
+                    direction = AudioManager.ADJUST_RAISE;
+                    break;
+                case KeyEvent.KEYCODE_VOLUME_DOWN:
+                    direction = AudioManager.ADJUST_LOWER;
+                    break;
+                case KeyEvent.KEYCODE_VOLUME_MUTE:
+                    isMute = true;
+                    break;
+            }
+            if (down || up) {
+                int flags = AudioManager.FLAG_FROM_KEY;
+                if (musicOnly) {
+                    // This flag is used when the screen is off to only affect active media.
+                    flags |= AudioManager.FLAG_ACTIVE_MEDIA_ONLY;
+                } else {
+                    // These flags are consistent with the home screen
+                    if (up) {
+                        flags |= AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE;
+                    } else {
+                        flags |= AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE;
+                    }
+                }
+                if (direction != 0) {
+                    // If this is action up we want to send a beep for non-music events
+                    if (up) {
+                        direction = 0;
+                    }
+                    dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
+                            asSystemService, stream, direction, flags);
+                } else if (isMute) {
+                    if (down && keyEvent.getRepeatCount() == 0) {
+                        dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid,
+                                asSystemService, stream, AudioManager.ADJUST_TOGGLE_MUTE, flags);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void dispatchAdjustVolume(String packageName, String opPackageName,
+                int suggestedStream, int delta, int flags) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    dispatchAdjustVolumeLocked(packageName, opPackageName, pid, uid, false,
+                            suggestedStream, delta, flags);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void setRemoteVolumeController(IRemoteVolumeController rvc) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                enforceSystemUiPermission("listen for volume changes", pid, uid);
+                mRvc = rvc;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public boolean isGlobalPriorityActive() {
+            synchronized (mLock) {
+                return isGlobalPriorityActiveLocked();
+            }
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
+            if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+
+            pw.println("MEDIA SESSION SERVICE (dumpsys media_session)");
+            pw.println();
+
+            synchronized (mLock) {
+                pw.println(mSessionsListeners.size() + " sessions listeners.");
+                pw.println("Global priority session is " + mGlobalPrioritySession);
+                if (mGlobalPrioritySession != null) {
+                    mGlobalPrioritySession.dump(pw, "  ");
+                }
+                pw.println("User Records:");
+                int count = mUserRecords.size();
+                for (int i = 0; i < count; i++) {
+                    mUserRecords.valueAt(i).dumpLocked(pw, "");
+                }
+                mAudioPlayerStateMonitor.dump(mContext, pw, "");
+            }
+        }
+
+        /**
+         * Returns if the controller's package is trusted (i.e. has either MEDIA_CONTENT_CONTROL
+         * permission or an enabled notification listener)
+         *
+         * @param controllerPackageName package name of the controller app
+         * @param controllerPid pid of the controller app
+         * @param controllerUid uid of the controller app
+         */
+        @Override
+        public boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid)
+                throws RemoteException {
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                // Don't perform sanity check between controllerPackageName and controllerUid.
+                // When an (activity|service) runs on the another apps process by specifying
+                // android:process in the AndroidManifest.xml, then PID and UID would have the
+                // running process' information instead of the (activity|service) that has created
+                // MediaController.
+                // Note that we can use Context#getOpPackageName() instead of
+                // Context#getPackageName() for getting package name that matches with the PID/UID,
+                // but it doesn't tell which package has created the MediaController, so useless.
+                return hasMediaControlPermission(UserHandle.getUserId(uid), controllerPackageName,
+                        controllerPid, controllerUid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        // For MediaSession
+        private int verifySessionsRequest(ComponentName componentName, int userId, final int pid,
+                final int uid) {
+            String packageName = null;
+            if (componentName != null) {
+                // If they gave us a component name verify they own the
+                // package
+                packageName = componentName.getPackageName();
+                enforcePackageName(packageName, uid);
+            }
+            // Check that they can make calls on behalf of the user and
+            // get the final user id
+            int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                    true /* allowAll */, true /* requireFull */, "getSessions", packageName);
+            // Check if they have the permissions or their component is
+            // enabled for the user they're calling from.
+            enforceMediaPermissions(componentName, pid, uid, resolvedUserId);
+            return resolvedUserId;
+        }
+
+        private boolean hasMediaControlPermission(int resolvedUserId, String packageName,
+                int pid, int uid) throws RemoteException {
+            // Allow API calls from the System UI
+            if (isCurrentVolumeController(pid, uid)) {
+                return true;
+            }
+
+            // Check if it's system server or has MEDIA_CONTENT_CONTROL.
+            // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
+            // check here.
+            if (uid == Process.SYSTEM_UID || mContext.checkPermission(
+                    android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
+                    == PackageManager.PERMISSION_GRANTED) {
+                return true;
+            } else if (DEBUG) {
+                Log.d(TAG, packageName + " (uid=" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
+            }
+
+            // You may not access another user's content as an enabled listener.
+            final int userId = UserHandle.getUserId(uid);
+            if (resolvedUserId != userId) {
+                return false;
+            }
+
+            // TODO(jaewan): (Post-P) Propose NotificationManager#hasEnabledNotificationListener(
+            //               String pkgName) to notification team for optimization
+            final List<ComponentName> enabledNotificationListeners =
+                    mNotificationManager.getEnabledNotificationListeners(userId);
+            if (enabledNotificationListeners != null) {
+                for (int i = 0; i < enabledNotificationListeners.size(); i++) {
+                    if (TextUtils.equals(packageName,
+                            enabledNotificationListeners.get(i).getPackageName())) {
+                        return true;
+                    }
+                }
+            }
+            if (DEBUG) {
+                Log.d(TAG, packageName + " (uid=" + uid + ") doesn't have an enabled "
+                        + "notification listener");
+            }
+            return false;
+        }
+
+        private void dispatchAdjustVolumeLocked(String packageName, String opPackageName, int pid,
+                int uid, boolean asSystemService, int suggestedStream, int direction, int flags) {
+            MediaSessionRecord session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
+                    : mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
+
+            boolean preferSuggestedStream = false;
+            if (isValidLocalStreamType(suggestedStream)
+                    && AudioSystem.isStreamActive(suggestedStream, 0)) {
+                preferSuggestedStream = true;
+            }
+            if (DEBUG_KEY_EVENT) {
+                Log.d(TAG, "Adjusting " + session + " by " + direction + ". flags="
+                        + flags + ", suggestedStream=" + suggestedStream
+                        + ", preferSuggestedStream=" + preferSuggestedStream);
+            }
+            if (session == null || preferSuggestedStream) {
+                if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0
+                        && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
+                    if (DEBUG) {
+                        Log.d(TAG, "No active session to adjust, skipping media only volume event");
+                    }
+                    return;
+                }
+
+                // Execute mAudioService.adjustSuggestedStreamVolume() on
+                // handler thread of MediaSessionService.
+                // This will release the MediaSessionService.mLock sooner and avoid
+                // a potential deadlock between MediaSessionService.mLock and
+                // ActivityManagerService lock.
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        final String callingOpPackageName;
+                        final int callingUid;
+                        if (asSystemService) {
+                            callingOpPackageName = mContext.getOpPackageName();
+                            callingUid = Process.myUid();
+                        } else {
+                            callingOpPackageName = opPackageName;
+                            callingUid = uid;
+                        }
+                        try {
+                            mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(suggestedStream,
+                                    direction, flags, callingOpPackageName, callingUid);
+                        } catch (SecurityException | IllegalArgumentException e) {
+                            Log.e(TAG, "Cannot adjust volume: direction=" + direction
+                                    + ", suggestedStream=" + suggestedStream + ", flags=" + flags
+                                    + ", packageName=" + packageName + ", uid=" + uid
+                                    + ", asSystemService=" + asSystemService, e);
+                        }
+                    }
+                });
+            } else {
+                session.adjustVolume(packageName, opPackageName, pid, uid, null, asSystemService,
+                        direction, flags, true);
+            }
+        }
+
+        private void handleVoiceKeyEventLocked(String packageName, int pid, int uid,
+                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
+            int action = keyEvent.getAction();
+            boolean isLongPress = (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
+            if (action == KeyEvent.ACTION_DOWN) {
+                if (keyEvent.getRepeatCount() == 0) {
+                    mVoiceButtonDown = true;
+                    mVoiceButtonHandled = false;
+                } else if (mVoiceButtonDown && !mVoiceButtonHandled && isLongPress) {
+                    mVoiceButtonHandled = true;
+                    startVoiceInput(needWakeLock);
+                }
+            } else if (action == KeyEvent.ACTION_UP) {
+                if (mVoiceButtonDown) {
+                    mVoiceButtonDown = false;
+                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
+                        // Resend the down then send this event through
+                        KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
+                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+                                downEvent, needWakeLock);
+                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+                                keyEvent, needWakeLock);
+                    }
+                }
+            }
+        }
+
+        private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
+                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
+            MediaSessionRecord session = mCurrentFullUserRecord.getMediaButtonSessionLocked();
+            if (session != null) {
+                if (DEBUG_KEY_EVENT) {
+                    Log.d(TAG, "Sending " + keyEvent + " to " + session);
+                }
+                if (needWakeLock) {
+                    mKeyEventReceiver.aquireWakeLockLocked();
+                }
+                // If we don't need a wakelock use -1 as the id so we won't release it later.
+                session.sendMediaButton(packageName, pid, uid, asSystemService, keyEvent,
+                        needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
+                        mKeyEventReceiver);
+                if (mCurrentFullUserRecord.mCallback != null) {
+                    try {
+                        mCurrentFullUserRecord.mCallback.onMediaKeyEventDispatchedToMediaSession(
+                                keyEvent, session.getSessionToken());
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to send callback", e);
+                    }
+                }
+            } else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null
+                    || mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
+                if (needWakeLock) {
+                    mKeyEventReceiver.aquireWakeLockLocked();
+                }
+                Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+                mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+                // TODO: Find a way to also send PID/UID in secure way.
+                String callerPackageName =
+                        (asSystemService) ? mContext.getPackageName() : packageName;
+                mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callerPackageName);
+                try {
+                    if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
+                        PendingIntent receiver = mCurrentFullUserRecord.mLastMediaButtonReceiver;
+                        if (DEBUG_KEY_EVENT) {
+                            Log.d(TAG, "Sending " + keyEvent
+                                    + " to the last known PendingIntent " + receiver);
+                        }
+                        receiver.send(mContext,
+                                needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
+                                mediaButtonIntent, mKeyEventReceiver, mHandler);
+                        if (mCurrentFullUserRecord.mCallback != null) {
+                            ComponentName componentName = mCurrentFullUserRecord
+                                    .mLastMediaButtonReceiver.getIntent().getComponent();
+                            if (componentName != null) {
+                                mCurrentFullUserRecord.mCallback
+                                        .onMediaKeyEventDispatchedToMediaButtonReceiver(
+                                                keyEvent, componentName);
+                            }
+                        }
+                    } else {
+                        ComponentName receiver =
+                                mCurrentFullUserRecord.mRestoredMediaButtonReceiver;
+                        int componentType = mCurrentFullUserRecord
+                                .mRestoredMediaButtonReceiverComponentType;
+                        UserHandle userHandle = UserHandle.of(mCurrentFullUserRecord
+                                .mRestoredMediaButtonReceiverUserId);
+                        if (DEBUG_KEY_EVENT) {
+                            Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
+                                    + receiver + ", type=" + componentType);
+                        }
+                        mediaButtonIntent.setComponent(receiver);
+                        try {
+                            switch (componentType) {
+                                case FullUserRecord.COMPONENT_TYPE_ACTIVITY:
+                                    mContext.startActivityAsUser(mediaButtonIntent, userHandle);
+                                    break;
+                                case FullUserRecord.COMPONENT_TYPE_SERVICE:
+                                    mContext.startForegroundServiceAsUser(mediaButtonIntent,
+                                            userHandle);
+                                    break;
+                                default:
+                                    // Legacy behavior for other cases.
+                                    mContext.sendBroadcastAsUser(mediaButtonIntent, userHandle);
+                            }
+                        } catch (Exception e) {
+                            Log.w(TAG, "Error sending media button to the restored intent "
+                                    + receiver + ", type=" + componentType, e);
+                        }
+                        if (mCurrentFullUserRecord.mCallback != null) {
+                            mCurrentFullUserRecord.mCallback
+                                    .onMediaKeyEventDispatchedToMediaButtonReceiver(
+                                            keyEvent, receiver);
+                        }
+                    }
+                } catch (CanceledException e) {
+                    Log.i(TAG, "Error sending key event to media button receiver "
+                            + mCurrentFullUserRecord.mLastMediaButtonReceiver, e);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to send callback", e);
+                }
+            }
+        }
+
+        private void startVoiceInput(boolean needWakeLock) {
+            Intent voiceIntent = null;
+            // select which type of search to launch:
+            // - screen on and device unlocked: action is ACTION_WEB_SEARCH
+            // - device locked or screen off: action is
+            // ACTION_VOICE_SEARCH_HANDS_FREE
+            // with EXTRA_SECURE set to true if the device is securely locked
+            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+            boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+            if (!isLocked && pm.isScreenOn()) {
+                voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
+                Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
+            } else {
+                voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+                voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
+                        isLocked && mKeyguardManager.isKeyguardSecure());
+                Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
+            }
+            // start the search activity
+            if (needWakeLock) {
+                mMediaEventWakeLock.acquire();
+            }
+            try {
+                if (voiceIntent != null) {
+                    voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                    if (DEBUG) Log.d(TAG, "voiceIntent: " + voiceIntent);
+                    mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT);
+                }
+            } catch (ActivityNotFoundException e) {
+                Log.w(TAG, "No activity for search: " + e);
+            } finally {
+                if (needWakeLock) {
+                    mMediaEventWakeLock.release();
+                }
+            }
+        }
+
+        private boolean isVoiceKey(int keyCode) {
+            return keyCode == KeyEvent.KEYCODE_HEADSETHOOK
+                    || (!mHasFeatureLeanback && keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+        }
+
+        private boolean isUserSetupComplete() {
+            return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
+        }
+
+        // we only handle public stream types, which are 0-5
+        private boolean isValidLocalStreamType(int streamType) {
+            return streamType >= AudioManager.STREAM_VOICE_CALL
+                    && streamType <= AudioManager.STREAM_NOTIFICATION;
+        }
+
+        private class MediaKeyListenerResultReceiver extends ResultReceiver implements Runnable {
+            private final String mPackageName;
+            private final int mPid;
+            private final int mUid;
+            private final boolean mAsSystemService;
+            private final KeyEvent mKeyEvent;
+            private final boolean mNeedWakeLock;
+            private boolean mHandled;
+
+            private MediaKeyListenerResultReceiver(String packageName, int pid, int uid,
+                    boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
+                super(mHandler);
+                mHandler.postDelayed(this, MEDIA_KEY_LISTENER_TIMEOUT);
+                mPackageName = packageName;
+                mPid = pid;
+                mUid = uid;
+                mAsSystemService = asSystemService;
+                mKeyEvent = keyEvent;
+                mNeedWakeLock = needWakeLock;
+            }
+
+            @Override
+            public void run() {
+                Log.d(TAG, "The media key listener is timed-out for " + mKeyEvent);
+                dispatchMediaKeyEvent();
+            }
+
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                if (resultCode == MediaSessionManager.RESULT_MEDIA_KEY_HANDLED) {
+                    mHandled = true;
+                    mHandler.removeCallbacks(this);
+                    return;
+                }
+                dispatchMediaKeyEvent();
+            }
+
+            private void dispatchMediaKeyEvent() {
+                if (mHandled) {
+                    return;
+                }
+                mHandled = true;
+                mHandler.removeCallbacks(this);
+                synchronized (mLock) {
+                    if (!isGlobalPriorityActiveLocked()
+                            && isVoiceKey(mKeyEvent.getKeyCode())) {
+                        handleVoiceKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
+                                mKeyEvent, mNeedWakeLock);
+                    } else {
+                        dispatchMediaKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
+                                mKeyEvent, mNeedWakeLock);
+                    }
+                }
+            }
+        }
+
+        private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler);
+
+        class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable,
+                PendingIntent.OnFinished {
+            private final Handler mHandler;
+            private int mRefCount = 0;
+            private int mLastTimeoutId = 0;
+
+            KeyEventWakeLockReceiver(Handler handler) {
+                super(handler);
+                mHandler = handler;
+            }
+
+            public void onTimeout() {
+                synchronized (mLock) {
+                    if (mRefCount == 0) {
+                        // We've already released it, so just return
+                        return;
+                    }
+                    mLastTimeoutId++;
+                    mRefCount = 0;
+                    releaseWakeLockLocked();
+                }
+            }
+
+            public void aquireWakeLockLocked() {
+                if (mRefCount == 0) {
+                    mMediaEventWakeLock.acquire();
+                }
+                mRefCount++;
+                mHandler.removeCallbacks(this);
+                mHandler.postDelayed(this, WAKELOCK_TIMEOUT);
+
+            }
+
+            @Override
+            public void run() {
+                onTimeout();
+            }
+
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                if (resultCode < mLastTimeoutId) {
+                    // Ignore results from calls that were before the last
+                    // timeout, just in case.
+                    return;
+                } else {
+                    synchronized (mLock) {
+                        if (mRefCount > 0) {
+                            mRefCount--;
+                            if (mRefCount == 0) {
+                                releaseWakeLockLocked();
+                            }
+                        }
+                    }
+                }
+            }
+
+            private void releaseWakeLockLocked() {
+                mMediaEventWakeLock.release();
+                mHandler.removeCallbacks(this);
+            }
+
+            @Override
+            public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
+                    String resultData, Bundle resultExtras) {
+                onReceiveResult(resultCode, null);
+            }
+        };
+
+        BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent == null) {
+                    return;
+                }
+                Bundle extras = intent.getExtras();
+                if (extras == null) {
+                    return;
+                }
+                synchronized (mLock) {
+                    if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)
+                            && mMediaEventWakeLock.isHeld()) {
+                        mMediaEventWakeLock.release();
+                    }
+                }
+            }
+        };
+    }
+
+    final class MessageHandler extends Handler {
+        private static final int MSG_SESSIONS_CHANGED = 1;
+        private static final int MSG_VOLUME_INITIAL_DOWN = 2;
+        private final SparseArray<Integer> mIntegerCache = new SparseArray<>();
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SESSIONS_CHANGED:
+                    pushSessionsChanged((int) msg.obj);
+                    break;
+                case MSG_VOLUME_INITIAL_DOWN:
+                    synchronized (mLock) {
+                        FullUserRecord user = mUserRecords.get((int) msg.arg1);
+                        if (user != null && user.mInitialDownVolumeKeyEvent != null) {
+                            dispatchVolumeKeyLongPressLocked(user.mInitialDownVolumeKeyEvent);
+                            // Mark that the key is already handled.
+                            user.mInitialDownVolumeKeyEvent = null;
+                        }
+                    }
+                    break;
+            }
+        }
+
+        public void postSessionsChanged(int userId) {
+            // Use object instead of the arguments when posting message to remove pending requests.
+            Integer userIdInteger = mIntegerCache.get(userId);
+            if (userIdInteger == null) {
+                userIdInteger = Integer.valueOf(userId);
+                mIntegerCache.put(userId, userIdInteger);
+            }
+            removeMessages(MSG_SESSIONS_CHANGED, userIdInteger);
+            obtainMessage(MSG_SESSIONS_CHANGED, userIdInteger).sendToTarget();
+        }
+    }
+
+    private class Controller2Callback extends MediaController2.ControllerCallback {
+        private final Session2Token mToken;
+
+        Controller2Callback(Session2Token token) {
+            mToken = token;
+        }
+
+        @Override
+        public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) {
+            synchronized (mLock) {
+                int userId = UserHandle.getUserId(mToken.getUid());
+                mSession2TokensPerUser.get(userId).add(mToken);
+                pushSession2TokensChangedLocked(userId);
+            }
+        }
+
+        @Override
+        public void onDisconnected(MediaController2 controller) {
+            synchronized (mLock) {
+                int userId = UserHandle.getUserId(mToken.getUid());
+                mSession2TokensPerUser.get(userId).remove(mToken);
+                pushSession2TokensChangedLocked(userId);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java b/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
index 6a5f563..64c451d 100644
--- a/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
+++ b/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
@@ -159,12 +159,13 @@
                     + serviceInfo.packageName + "/" + serviceInfo.name);
             return false;
         }
-        if (!hasCaptureVideoPermission(serviceInfo.packageName)) {
-            // If the service does not have permission to capture video then it
-            // isn't going to be terribly useful as a remote display, is it?
-            // Kind of makes you wonder what it's doing there in the first place.
+        if (mPackageManager.checkPermission(Manifest.permission.REMOTE_DISPLAY_PROVIDER,
+                        serviceInfo.packageName) != PackageManager.PERMISSION_GRANTED) {
+            // If the service does not have this permission then the system will not bind to it.
+            // This is to prevent non privileged apps declaring themselves as remote display
+            // providers just to be bound to by the system and keep their process alive.
             Slog.w(TAG, "Ignoring remote display provider service because it does not "
-                    + "have the CAPTURE_VIDEO_OUTPUT or CAPTURE_SECURE_VIDEO_OUTPUT "
+                    + "have the REMOTE_DISPLAY_PROVIDER "
                     + "permission: " + serviceInfo.packageName + "/" + serviceInfo.name);
             return false;
         }
@@ -172,18 +173,6 @@
         return true;
     }
 
-    private boolean hasCaptureVideoPermission(String packageName) {
-        if (mPackageManager.checkPermission(Manifest.permission.CAPTURE_VIDEO_OUTPUT,
-                packageName) == PackageManager.PERMISSION_GRANTED) {
-            return true;
-        }
-        if (mPackageManager.checkPermission(Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT,
-                packageName) == PackageManager.PERMISSION_GRANTED) {
-            return true;
-        }
-        return false;
-    }
-
     private int findProvider(String packageName, String className) {
         int count = mProviders.size();
         for (int i = 0; i < count; i++) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 0d6dadf..af55605 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -270,14 +270,12 @@
  * enforcement.
  *
  * <p>
- * This class uses 2-3 locks to synchronize state:
+ * This class uses 2 locks to synchronize state:
  * <ul>
  * <li>{@code mUidRulesFirstLock}: used to guard state related to individual UIDs (such as firewall
  * rules).
  * <li>{@code mNetworkPoliciesSecondLock}: used to guard state related to network interfaces (such
  * as network policies).
- * <li>{@code allLocks}: not a "real" lock, but an indication (through @GuardedBy) that all locks
- * must be held.
  * </ul>
  *
  * <p>
@@ -419,7 +417,8 @@
     final Object mUidRulesFirstLock = new Object();
     final Object mNetworkPoliciesSecondLock = new Object();
 
-    @GuardedBy("allLocks") volatile boolean mSystemReady;
+    @GuardedBy({"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"})
+    volatile boolean mSystemReady;
 
     @GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictBackground;
     @GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictPower;
@@ -558,7 +557,7 @@
 
     private final ServiceThread mUidEventThread;
 
-    @GuardedBy("allLocks")
+    @GuardedBy({"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"})
     private final AtomicFile mPolicyFile;
 
     private final AppOpsManager mAppOps;
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index dc3bfbc..bffd60b 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -368,7 +368,7 @@
         mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers");
         mSystemDir = checkNotNull(systemDir, "missing systemDir");
         mBaseDir = checkNotNull(baseDir, "missing baseDir");
-        mUseBpfTrafficStats = new File("/sys/fs/bpf/traffic_uid_stats_map").exists();
+        mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists();
     }
 
     private void registerLocalService() {
@@ -962,12 +962,64 @@
 
     @Override
     public long getIfaceStats(String iface, int type) {
-        return nativeGetIfaceStat(iface, type, checkBpfStatsEnable());
+        long nativeIfaceStats = nativeGetIfaceStat(iface, type, checkBpfStatsEnable());
+        if (nativeIfaceStats == -1) {
+            return nativeIfaceStats;
+        } else {
+            // When tethering offload is in use, nativeIfaceStats does not contain usage from
+            // offload, add it back here.
+            // When tethering offload is not in use, nativeIfaceStats contains tethering usage.
+            // this does not cause double-counting of tethering traffic, because
+            // NetdTetheringStatsProvider returns zero NetworkStats
+            // when called with STATS_PER_IFACE.
+            return nativeIfaceStats + getTetherStats(iface, type);
+        }
     }
 
     @Override
     public long getTotalStats(int type) {
-        return nativeGetTotalStat(type, checkBpfStatsEnable());
+        long nativeTotalStats = nativeGetTotalStat(type, checkBpfStatsEnable());
+        if (nativeTotalStats == -1) {
+            return nativeTotalStats;
+        } else {
+            // Refer to comment in getIfaceStats
+            return nativeTotalStats + getTetherStats(IFACE_ALL, type);
+        }
+    }
+
+    private long getTetherStats(String iface, int type) {
+        final NetworkStats tetherSnapshot;
+        final long token = Binder.clearCallingIdentity();
+        try {
+            tetherSnapshot = getNetworkStatsTethering(STATS_PER_IFACE);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Error get TetherStats: " + e);
+            return 0;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        HashSet<String> limitIfaces;
+        if (iface == IFACE_ALL) {
+            limitIfaces = null;
+        } else {
+            limitIfaces = new HashSet<String>();
+            limitIfaces.add(iface);
+        }
+        NetworkStats.Entry entry = tetherSnapshot.getTotal(null, limitIfaces);
+        if (LOGD) Slog.d(TAG, "TetherStats: iface=" + iface + " type=" + type +
+                " entry=" + entry);
+        switch (type) {
+            case 0: // TYPE_RX_BYTES
+                return entry.rxBytes;
+            case 1: // TYPE_RX_PACKETS
+                return entry.rxPackets;
+            case 2: // TYPE_TX_BYTES
+                return entry.txBytes;
+            case 3: // TYPE_TX_PACKETS
+                return entry.txPackets;
+            default:
+                return 0;
+        }
     }
 
     private boolean checkBpfStatsEnable() {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 6187583..c222e69 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -558,7 +558,7 @@
         if (pkgList != null && (pkgList.length > 0)) {
             boolean anyServicesInvolved = false;
             // Remove notification settings for uninstalled package
-            if (removingPackage) {
+            if (removingPackage && uidList != null) {
                 int size = Math.min(pkgList.length, uidList.length);
                 for (int i = 0; i < size; i++) {
                     final String pkg = pkgList[i];
@@ -570,9 +570,11 @@
                 if (mEnabledServicesPackageNames.contains(pkgName)) {
                     anyServicesInvolved = true;
                 }
-                for (int uid : uidList) {
-                    if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
-                        anyServicesInvolved = true;
+                if (uidList != null && uidList.length > 0) {
+                    for (int uid : uidList) {
+                        if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
+                            anyServicesInvolved = true;
+                        }
                     }
                 }
             }
@@ -765,6 +767,23 @@
         return installed;
     }
 
+    protected Set<String> getAllowedPackages() {
+        final Set<String> allowedPackages = new ArraySet<>();
+        for (int k = 0; k < mApproved.size(); k++) {
+            ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
+            for (int i = 0; i < allowedByType.size(); i++) {
+                final ArraySet<String> allowed = allowedByType.valueAt(i);
+                for (int j = 0; j < allowed.size(); j++) {
+                    String pkgName = getPackageName(allowed.valueAt(j));
+                    if (!TextUtils.isEmpty(pkgName)) {
+                        allowedPackages.add(pkgName);
+                    }
+                }
+            }
+        }
+        return allowedPackages;
+    }
+
     private void trimApprovedListsAccordingToInstalledServices() {
         int N = mApproved.size();
         for (int i = 0 ; i < N; i++) {
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index ee60daa..c2dc554 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -42,7 +42,8 @@
     void onNotificationVisibilityChanged(
             NotificationVisibility[] newlyVisibleKeys,
             NotificationVisibility[] noLongerVisibleKeys);
-    void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded);
+    void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded,
+            int notificationLocation);
     void onNotificationDirectReplied(String key);
     void onNotificationSettingsViewed(String key);
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e2cb75e..a164686 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -75,6 +75,9 @@
 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
+import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
+import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
+import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
 import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
@@ -763,8 +766,7 @@
                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
                         .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count)
                         .addTaggedData(MetricsEvent.NOTIFICATION_ACTION_IS_SMART,
-                                (Notification.Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION
-                                        == action.getSemanticAction()) ? 1 : 0)
+                                action.isContextual() ? 1 : 0)
                         .addTaggedData(
                                 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
                                 generatedByAssistant ? 1 : 0));
@@ -843,10 +845,12 @@
                         reportSeen(r);
                     }
                     r.setVisibility(true, nv.rank, nv.count);
+                    boolean isHun = (nv.location
+                            == NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP);
                     // hasBeenVisiblyExpanded must be called after updating the expansion state of
                     // the NotificationRecord to ensure the expansion state is up-to-date.
-                    if (r.hasBeenVisiblyExpanded()) {
-                        logSmartSuggestionsVisible(r);
+                    if (isHun || r.hasBeenVisiblyExpanded()) {
+                        logSmartSuggestionsVisible(r, nv.location.toMetricsEventEnum());
                     }
                     maybeRecordInterruptionLocked(r);
                     nv.recycle();
@@ -866,7 +870,7 @@
 
         @Override
         public void onNotificationExpansionChanged(String key,
-                boolean userAction, boolean expanded) {
+                boolean userAction, boolean expanded, int notificationLocation) {
             synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r != null) {
@@ -874,9 +878,8 @@
                     // hasBeenVisiblyExpanded must be called after updating the expansion state of
                     // the NotificationRecord to ensure the expansion state is up-to-date.
                     if (r.hasBeenVisiblyExpanded()) {
-                        logSmartSuggestionsVisible(r);
+                        logSmartSuggestionsVisible(r, notificationLocation);
                     }
-                    final long now = System.currentTimeMillis();
                     if (userAction) {
                         MetricsLogger.action(r.getItemLogMaker()
                                 .setType(expanded ? MetricsEvent.TYPE_DETAIL
@@ -886,9 +889,6 @@
                         r.recordExpanded();
                         reportUserInteraction(r);
                     }
-                    EventLogTags.writeNotificationExpansion(key,
-                            userAction ? 1 : 0, expanded ? 1 : 0,
-                            r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
                     mAssistants.notifyAssistantExpansionChangedLocked(r.sbn, userAction, expanded);
                 }
             }
@@ -954,7 +954,7 @@
     };
 
     @VisibleForTesting
-    void logSmartSuggestionsVisible(NotificationRecord r) {
+    void logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation) {
         // If the newly visible notification has smart suggestions
         // then log that the user has seen them.
         if ((r.getNumSmartRepliesAdded() > 0 || r.getNumSmartActionsAdded() > 0)
@@ -968,7 +968,10 @@
                             r.getNumSmartActionsAdded())
                     .addTaggedData(
                             MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
-                            r.getSuggestionsGeneratedByAssistant());
+                            r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
+                    // The fields in the NotificationVisibility.NotificationLocation enum map
+                    // directly to the fields in the MetricsEvent.NotificationLocation enum.
+                    .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, notificationLocation);
             mMetricsLogger.write(logMaker);
         }
     }
@@ -1314,6 +1317,11 @@
     }
 
     @VisibleForTesting
+    void setHints(int hints) {
+        mListenerHints = hints;
+    }
+
+    @VisibleForTesting
     void setVibrator(Vibrator vibrator) {
         mVibrator = vibrator;
     }
@@ -1574,6 +1582,9 @@
 
         mIsAutomotive =
                 mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0);
+
+        mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray(
+                com.android.internal.R.array.config_nonBlockableNotificationPackages));
     }
 
     @Override
@@ -1695,8 +1706,16 @@
     }
 
     private void sendRegisteredOnlyBroadcast(String action) {
-        getContext().sendBroadcastAsUser(new Intent(action)
-                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
+        Intent intent = new Intent(action);
+        getContext().sendBroadcastAsUser(intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
+                UserHandle.ALL, null);
+        // explicitly send the broadcast to all DND packages, even if they aren't currently running
+        intent.setFlags(0);
+        final Set<String> dndApprovedPackages = mConditionProviders.getAllowedPackages();
+        for (String pkg : dndApprovedPackages) {
+            intent.setPackage(pkg);
+            getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
+        }
     }
 
     @Override
@@ -2293,22 +2312,22 @@
         }
 
         @Override
-        public boolean areAppOverlaysAllowed(String pkg) {
-            return areAppOverlaysAllowedForPackage(pkg, Binder.getCallingUid());
+        public boolean areBubblesAllowed(String pkg) {
+            return areBubblesAllowedForPackage(pkg, Binder.getCallingUid());
         }
 
         @Override
-        public boolean areAppOverlaysAllowedForPackage(String pkg, int uid) {
-            checkCallerIsSystemOrSameApp(pkg);
-
-            return mPreferencesHelper.areAppOverlaysAllowed(pkg, uid);
+        public boolean areBubblesAllowedForPackage(String pkg, int uid) {
+            enforceSystemOrSystemUIOrSamePackage(pkg,
+                    "Caller not system or systemui or same package");
+            return mPreferencesHelper.areBubblessAllowed(pkg, uid);
         }
 
         @Override
-        public void setAppOverlaysAllowed(String pkg, int uid, boolean allowed) {
+        public void setBubblesAllowed(String pkg, int uid, boolean allowed) {
             checkCallerIsSystem();
 
-            mPreferencesHelper.setAppOverlaysAllowed(pkg, uid, allowed);
+            mPreferencesHelper.setBubblesAllowed(pkg, uid, allowed);
             handleSavePolicyFile();
         }
 
@@ -2635,6 +2654,9 @@
             // Zen
             mConditionProviders.onPackagesChanged(true, packages, uids);
 
+            // Snoozing
+            mSnoozeHelper.clearData(UserHandle.getUserId(uid), packageName);
+
             // Reset notification preferences
             if (!fromApp) {
                 mPreferencesHelper.onPackagesChanged(
@@ -3488,7 +3510,7 @@
                     getContext().sendBroadcastAsUser(new Intent(
                             NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
                                     .setPackage(pkg)
-                                    .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
+                                    .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
                             UserHandle.of(userId), null);
                     handleSavePolicyFile();
                 }
@@ -3990,6 +4012,20 @@
         if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
             return "listenerHints";
         }
+        if (record != null && record.getAudioAttributes() != null) {
+            if ((mListenerHints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
+                if (record.getAudioAttributes().getUsage()
+                        != AudioAttributes.USAGE_VOICE_COMMUNICATION) {
+                    return "listenerNoti";
+                }
+            }
+            if ((mListenerHints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
+                if (record.getAudioAttributes().getUsage()
+                        == AudioAttributes.USAGE_VOICE_COMMUNICATION) {
+                    return "listenerCall";
+                }
+            }
+        }
         if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
             return "callState";
         }
@@ -4420,6 +4456,9 @@
                     if (pendingIntent != null) {
                         am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
                                 WHITELIST_TOKEN, duration);
+                        am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
+                                WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
+                                        | FLAG_SERVICE_SENDER));
                     }
                 }
             }
@@ -5258,22 +5297,25 @@
                     }
                     if (DBG) Slog.v(TAG, "Interrupting!");
                     if (hasValidSound) {
-                        mSoundNotificationKey = key;
                         if (mInCall) {
                             playInCallNotification();
                             beep = true;
                         } else {
                             beep = playSound(record, soundUri);
                         }
+                        if(beep) {
+                            mSoundNotificationKey = key;
+                        }
                     }
 
                     final boolean ringerModeSilent =
                             mAudioManager.getRingerModeInternal()
                                     == AudioManager.RINGER_MODE_SILENT;
                     if (!mInCall && hasValidVibrate && !ringerModeSilent) {
-                        mVibrateNotificationKey = key;
-
                         buzz = playVibration(record, vibration, hasValidSound);
+                        if(buzz) {
+                            mVibrateNotificationKey = key;
+                        }
                     }
                 } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
                     hasValidSound = false;
@@ -5454,8 +5496,17 @@
                     try {
                         Thread.sleep(waitMs);
                     } catch (InterruptedException e) { }
-                    mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
-                            effect, "Notification (delayed)", record.getAudioAttributes());
+
+                    // Notifications might be canceled before it actually vibrates due to waitMs,
+                    // so need to check the notification still valide for vibrate.
+                    synchronized (mNotificationLock) {
+                        if (mNotificationsByKey.get(record.getKey()) != null) {
+                            mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
+                                    effect, "Notification (delayed)", record.getAudioAttributes());
+                        } else {
+                            Slog.e(TAG, "No vibration for canceled notification : " + record.getKey());
+                        }
+                    }
                 }).start();
             } else {
                 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
@@ -5663,19 +5714,17 @@
             }
             int indexBefore = findNotificationRecordIndexLocked(record);
             boolean interceptBefore = record.isIntercepted();
-            float contactAffinityBefore = record.getContactAffinity();
             int visibilityBefore = record.getPackageVisibilityOverride();
             recon.applyChangesLocked(record);
             applyZenModeLocked(record);
             mRankingHelper.sort(mNotificationList);
             int indexAfter = findNotificationRecordIndexLocked(record);
             boolean interceptAfter = record.isIntercepted();
-            float contactAffinityAfter = record.getContactAffinity();
             int visibilityAfter = record.getPackageVisibilityOverride();
             changed = indexBefore != indexAfter || interceptBefore != interceptAfter
                     || visibilityBefore != visibilityAfter;
             if (interceptBefore && !interceptAfter
-                    && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
+                    && record.isNewEnoughForAlerting(System.currentTimeMillis())) {
                 buzzBeepBlinkLocked(record);
             }
         }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index e2c64ca..02fc51f 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -91,7 +91,8 @@
 public final class NotificationRecord {
     static final String TAG = "NotificationRecord";
     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final int MAX_LOGTAG_LENGTH = 35;
+    // the period after which a notification is updated where it can make sound
+    private static final int MAX_SOUND_DELAY_MS = 2000;
     final StatusBarNotification sbn;
     IActivityManager mAm;
     UriGrantsManagerInternal mUgmInternal;
@@ -125,7 +126,8 @@
     private long mVisibleSinceMs;
 
     // The most recent update time, or the creation time if no updates.
-    private long mUpdateTimeMs;
+    @VisibleForTesting
+    final long mUpdateTimeMs;
 
     // The most recent interruption time, or the creation time if no updates. Differs from the
     // above value because updates are filtered based on whether they actually interrupted the
@@ -159,13 +161,10 @@
     private ArrayList<String> mPeopleOverride;
     private ArrayList<SnoozeCriterion> mSnoozeCriteria;
     private boolean mShowBadge;
-    private LogMaker mLogMaker;
     private Light mLight;
-    private String mGroupLogTag;
-    private String mChannelIdLogTag;
     /**
      * This list contains system generated smart actions from NAS, app-generated smart actions are
-     * stored in Notification.actions marked as SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION.
+     * stored in Notification.actions with isContextual() set to true.
      */
     private ArrayList<Notification.Action> mSystemGeneratedSmartActions;
     private ArrayList<CharSequence> mSmartReplies;
@@ -786,7 +785,8 @@
             mImportanceExplanation = "user";
         }
         if (!getChannel().hasUserSetImportance()
-                && mAssistantImportance != IMPORTANCE_UNSPECIFIED) {
+                && mAssistantImportance != IMPORTANCE_UNSPECIFIED
+                && !getChannel().isImportanceLockedByOEM()) {
             mImportance = mAssistantImportance;
             mImportanceExplanation = "asst";
         }
@@ -826,6 +826,10 @@
         return mIntercept;
     }
 
+    public boolean isNewEnoughForAlerting(long now) {
+        return getFreshnessMs(now) <= MAX_SOUND_DELAY_MS;
+    }
+
     public void setHidden(boolean hidden) {
         mHidden = hidden;
     }
@@ -962,33 +966,6 @@
 
     public void setOverrideGroupKey(String overrideGroupKey) {
         sbn.setOverrideGroupKey(overrideGroupKey);
-        mGroupLogTag = null;
-    }
-
-    private String getGroupLogTag() {
-        if (mGroupLogTag == null) {
-            mGroupLogTag = shortenTag(sbn.getGroup());
-        }
-        return mGroupLogTag;
-    }
-
-    private String getChannelIdLogTag() {
-        if (mChannelIdLogTag == null) {
-            mChannelIdLogTag = shortenTag(mChannel.getId());
-        }
-        return mChannelIdLogTag;
-    }
-
-    private String shortenTag(String longTag) {
-        if (longTag == null) {
-            return null;
-        }
-        if (longTag.length() < MAX_LOGTAG_LENGTH) {
-            return longTag;
-        } else {
-            return longTag.substring(0, MAX_LOGTAG_LENGTH - 8) + "-" +
-                    Integer.toHexString(longTag.hashCode());
-        }
     }
 
     public NotificationChannel getChannel() {
@@ -1265,24 +1242,9 @@
     }
 
     public LogMaker getLogMaker(long now) {
-        if (mLogMaker == null) {
-            // initialize fields that only change on update (so a new record)
-            mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
-                    .setPackageName(sbn.getPackageName())
-                    .addTaggedData(MetricsEvent.NOTIFICATION_ID, sbn.getId())
-                    .addTaggedData(MetricsEvent.NOTIFICATION_TAG, sbn.getTag())
-                    .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID, getChannelIdLogTag());
-        }
-        // reset fields that can change between updates, or are used by multiple logs
-        return mLogMaker
-                .clearCategory()
-                .clearType()
-                .clearSubtype()
+        return sbn.getLogMaker()
                 .clearTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX)
                 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE, mImportance)
-                .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag())
-                .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY,
-                        sbn.getNotification().isGroupSummary() ? 1 : 0)
                 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now))
                 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now))
                 .addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now))
@@ -1301,7 +1263,7 @@
     public LogMaker getAdjustmentLogMaker() {
         return getLogMaker()
                 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
-                .setType(MetricsEvent.NOTIFICATION_ASSISTANT_ADJUSTMENT);
+                .setType(MetricsEvent.TYPE_NOTIFICATION_ASSISTANT_ADJUSTMENT);
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 7c0e0b0..7a21aa2 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -68,6 +68,7 @@
     private static final String TAG = "NotificationPrefHelper";
     private static final int XML_VERSION = 1;
     private static final int UNKNOWN_UID = UserHandle.USER_NULL;
+    private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":";
 
     @VisibleForTesting
     static final String TAG_RANKING = "ranking";
@@ -80,7 +81,7 @@
     private static final String ATT_NAME = "name";
     private static final String ATT_UID = "uid";
     private static final String ATT_ID = "id";
-    private static final String ATT_APP_OVERLAY = "overlay";
+    private static final String ATT_ALLOW_BUBBLE = "allow_bubble";
     private static final String ATT_PRIORITY = "priority";
     private static final String ATT_VISIBILITY = "visibility";
     private static final String ATT_IMPORTANCE = "importance";
@@ -93,7 +94,9 @@
     private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
     private static final int DEFAULT_IMPORTANCE = NotificationManager.IMPORTANCE_UNSPECIFIED;
     private static final boolean DEFAULT_SHOW_BADGE = true;
-    private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true;
+    private static final boolean DEFAULT_ALLOW_BUBBLE = true;
+    private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE  = false;
+
     /**
      * Default value for what fields are user locked. See {@link LockableAppFields} for all lockable
      * fields.
@@ -106,7 +109,7 @@
     @IntDef({LockableAppFields.USER_LOCKED_IMPORTANCE})
     public @interface LockableAppFields {
         int USER_LOCKED_IMPORTANCE = 0x00000001;
-        int USER_LOCKED_APP_OVERLAY = 0x00000002;
+        int USER_LOCKED_BUBBLE = 0x00000002;
     }
 
     // pkg|uid => PackagePreferences
@@ -174,7 +177,7 @@
                                     XmlUtils.readBooleanAttribute(
                                             parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE),
                                     XmlUtils.readBooleanAttribute(
-                                            parser, ATT_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY));
+                                            parser, ATT_ALLOW_BUBBLE, DEFAULT_ALLOW_BUBBLE));
                             r.importance = XmlUtils.readIntAttribute(
                                     parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
                             r.priority = XmlUtils.readIntAttribute(
@@ -270,11 +273,11 @@
     private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid) {
         return getOrCreatePackagePreferences(pkg, uid,
                 DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE,
-                DEFAULT_ALLOW_APP_OVERLAY);
+                DEFAULT_ALLOW_BUBBLE);
     }
 
     private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid, int importance,
-            int priority, int visibility, boolean showBadge, boolean allowAppOverlay) {
+            int priority, int visibility, boolean showBadge, boolean allowBubble) {
         final String key = packagePreferencesKey(pkg, uid);
         synchronized (mPackagePreferences) {
             PackagePreferences
@@ -288,7 +291,7 @@
                 r.priority = priority;
                 r.visibility = visibility;
                 r.showBadge = showBadge;
-                r.appOverlay = allowAppOverlay;
+                r.allowBubble = allowBubble;
 
                 try {
                     createDefaultChannelIfNeeded(r);
@@ -390,7 +393,7 @@
                                 || r.channels.size() > 0
                                 || r.groups.size() > 0
                                 || r.delegate != null
-                                || r.appOverlay != DEFAULT_ALLOW_APP_OVERLAY;
+                                || r.allowBubble != DEFAULT_ALLOW_BUBBLE;
                 if (hasNonDefaultSettings) {
                     out.startTag(null, TAG_PACKAGE);
                     out.attribute(null, ATT_NAME, r.pkg);
@@ -403,8 +406,8 @@
                     if (r.visibility != DEFAULT_VISIBILITY) {
                         out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
                     }
-                    if (r.appOverlay != DEFAULT_ALLOW_APP_OVERLAY) {
-                        out.attribute(null, ATT_APP_OVERLAY, Boolean.toString(r.appOverlay));
+                    if (r.allowBubble != DEFAULT_ALLOW_BUBBLE) {
+                        out.attribute(null, ATT_ALLOW_BUBBLE, Boolean.toString(r.allowBubble));
                     }
                     out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(r.showBadge));
                     out.attribute(null, ATT_APP_USER_LOCKED_FIELDS,
@@ -450,14 +453,28 @@
         out.endTag(null, TAG_RANKING);
     }
 
-    public void setAppOverlaysAllowed(String pkg, int uid, boolean allowed) {
+    /**
+     * Sets whether bubbles are allowed.
+     *
+     * @param pkg the package to allow or not allow bubbles for.
+     * @param uid the uid to allow or not allow bubbles for.
+     * @param allowed whether bubbles are allowed.
+     */
+    public void setBubblesAllowed(String pkg, int uid, boolean allowed) {
         PackagePreferences p = getOrCreatePackagePreferences(pkg, uid);
-        p.appOverlay = allowed;
-        p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_APP_OVERLAY;
+        p.allowBubble = allowed;
+        p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_BUBBLE;
     }
 
-    public boolean areAppOverlaysAllowed(String pkg, int uid) {
-        return getOrCreatePackagePreferences(pkg, uid).appOverlay;
+    /**
+     * Whether bubbles are allowed.
+     *
+     * @param pkg the package to check if bubbles are allowed for
+     * @param uid the uid to check if bubbles are allowed for.
+     * @return whether bubbles are allowed.
+     */
+    public boolean areBubblessAllowed(String pkg, int uid) {
+        return getOrCreatePackagePreferences(pkg, uid).allowBubble;
     }
 
     public int getAppLockedFields(String pkg, int uid) {
@@ -621,6 +638,12 @@
             channel.setLockscreenVisibility(r.visibility);
         }
         clearLockedFields(channel);
+        channel.setImportanceLockedByOEM(r.oemLockedImportance);
+        if (!channel.isImportanceLockedByOEM()) {
+            if (r.futureOemLockedChannels.remove(channel.getId())) {
+                channel.setImportanceLockedByOEM(true);
+            }
+        }
         if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
             channel.setLockscreenVisibility(
                     NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
@@ -664,6 +687,12 @@
         } else {
             updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
         }
+        // no importance updates are allowed if OEM blocked it
+        updatedChannel.setImportanceLockedByOEM(channel.isImportanceLockedByOEM());
+        if (updatedChannel.isImportanceLockedByOEM()) {
+            updatedChannel.setImportance(channel.getImportance());
+        }
+
         r.channels.put(updatedChannel.getId(), updatedChannel);
 
         if (onlyHasDefaultChannel(pkg, uid)) {
@@ -753,6 +782,44 @@
         }
     }
 
+    public void lockChannelsForOEM(String[] appOrChannelList) {
+        if (appOrChannelList == null) {
+            return;
+        }
+        for (String appOrChannel : appOrChannelList) {
+            if (!TextUtils.isEmpty(appOrChannel)) {
+                String[] appSplit = appOrChannel.split(NON_BLOCKABLE_CHANNEL_DELIM);
+                if (appSplit != null && appSplit.length > 0) {
+                    String appName = appSplit[0];
+                    String channelId = appSplit.length == 2 ? appSplit[1] : null;
+
+                    synchronized (mPackagePreferences) {
+                        for (PackagePreferences r : mPackagePreferences.values()) {
+                            if (r.pkg.equals(appName)) {
+                                if (channelId == null) {
+                                    // lock all channels for the app
+                                    r.oemLockedImportance = true;
+                                    for (NotificationChannel channel : r.channels.values()) {
+                                        channel.setImportanceLockedByOEM(true);
+                                    }
+                                } else {
+                                    NotificationChannel channel = r.channels.get(channelId);
+                                    if (channel != null) {
+                                        channel.setImportanceLockedByOEM(true);
+                                    } else {
+                                        // if this channel shows up in the future, make sure it'll
+                                        // be locked immediately
+                                        r.futureOemLockedChannels.add(channelId);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     public NotificationChannelGroup getNotificationChannelGroupWithChannels(String pkg,
             int uid, String groupId, boolean includeDeleted) {
         Preconditions.checkNotNull(pkg);
@@ -1180,8 +1247,8 @@
         if (original.canShowBadge() != update.canShowBadge()) {
             update.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
         }
-        if (original.isAppOverlayAllowed() != update.isAppOverlayAllowed()) {
-            update.lockFields(NotificationChannel.USER_LOCKED_ALLOW_APP_OVERLAY);
+        if (original.isBubbleAllowed() != update.isBubbleAllowed()) {
+            update.lockFields(NotificationChannel.USER_LOCKED_ALLOW_BUBBLE);
         }
     }
 
@@ -1602,8 +1669,10 @@
         int priority = DEFAULT_PRIORITY;
         int visibility = DEFAULT_VISIBILITY;
         boolean showBadge = DEFAULT_SHOW_BADGE;
-        boolean appOverlay = DEFAULT_ALLOW_APP_OVERLAY;
+        boolean allowBubble = DEFAULT_ALLOW_BUBBLE;
         int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
+        boolean oemLockedImportance = DEFAULT_OEM_LOCKED_IMPORTANCE;
+        List<String> futureOemLockedChannels = new ArrayList<>();
 
         Delegate delegate = null;
         ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index b1e9144..b145e1e 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -106,9 +106,7 @@
 
         synchronized (mProxyByGroupTmp) {
             // record individual ranking result and nominate proxies for each group
-            // Note: iteration is done backwards such that the index can be used as a sort key
-            // in a string compare below
-            for (int i = N - 1; i >= 0; i--) {
+            for (int i = 0; i < N; i++) {
                 final NotificationRecord record = notificationList.get(i);
                 record.setAuthoritativeRank(i);
                 final String groupKey = record.getGroupKey();
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 2b581d6..abc9841 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -17,6 +17,7 @@
 
 import android.annotation.NonNull;
 import android.app.AlarmManager;
+import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -163,7 +164,6 @@
                     mSnoozedNotifications.get(userId).get(pkg);
             if (recordsForPkg != null) {
                 final Set<Map.Entry<String, NotificationRecord>> records = recordsForPkg.entrySet();
-                String key = null;
                 for (Map.Entry<String, NotificationRecord> record : records) {
                     final StatusBarNotification sbn = record.getValue().sbn;
                     if (Objects.equals(sbn.getTag(), tag) && sbn.getId() == id) {
@@ -305,6 +305,30 @@
         }
     }
 
+    protected void clearData(int userId, String pkg) {
+        ArrayMap<String, ArrayMap<String, NotificationRecord>> records =
+                mSnoozedNotifications.get(userId);
+        if (records == null) {
+            return;
+        }
+        ArrayMap<String, NotificationRecord> pkgRecords = records.get(pkg);
+        if (pkgRecords == null) {
+            return;
+        }
+        for (int i = pkgRecords.size() - 1; i >= 0; i--) {
+            final NotificationRecord r = pkgRecords.removeAt(i);
+            if (r != null) {
+                mPackages.remove(r.getKey());
+                mUsers.remove(r.getKey());
+                final PendingIntent pi = createPendingIntent(pkg, r.getKey(), userId);
+                mAm.cancel(pi);
+                MetricsLogger.action(r.getLogMaker()
+                        .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)
+                        .setType(MetricsProto.MetricsEvent.TYPE_DISMISS));
+            }
+        }
+    }
+
     private PendingIntent createPendingIntent(String pkg, String key, int userId) {
         return PendingIntent.getBroadcast(mContext,
                 REQUEST_CODE_REPOST,
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index e5b1878..afc0b72 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -375,8 +375,7 @@
             newConfig = mConfig.copy();
             for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
                 ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
-                if (rule.component.getPackageName().equals(packageName)
-                        && canManageAutomaticZenRule(rule)) {
+                if (rule.pkg.equals(packageName) && canManageAutomaticZenRule(rule)) {
                     newConfig.automaticRules.removeAt(i);
                 }
             }
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 16143d3..74fbea1 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -24,11 +24,14 @@
 
 import android.annotation.NonNull;
 import android.content.om.OverlayInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.os.Build.VERSION_CODES;
 import android.os.IBinder;
 import android.os.IIdmap2;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.Slog;
 
@@ -51,6 +54,13 @@
     private final Installer mInstaller;
     private IIdmap2 mIdmap2Service;
 
+    private static final boolean VENDOR_IS_Q_OR_LATER;
+    static {
+        // STOPSHIP(b/119390857): Check api version once Q sdk version is finalized
+        final String value = SystemProperties.get("ro.vndk.version", "Q");
+        VENDOR_IS_Q_OR_LATER = value.equals("Q") || value.equals("q");
+    }
+
     IdmapManager(final Installer installer) {
         mInstaller = installer;
         if (FEATURE_FLAG_IDMAP2) {
@@ -69,10 +79,13 @@
         final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
         try {
             if (FEATURE_FLAG_IDMAP2) {
-                if (mIdmap2Service.verifyIdmap(overlayPath, userId)) {
+                int policies = determineFulfilledPolicies(overlayPackage);
+                boolean enforce = enforceOverlayable(overlayPackage);
+                if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) {
                     return true;
                 }
-                return mIdmap2Service.createIdmap(targetPath, overlayPath, userId) != null;
+                return mIdmap2Service.createIdmap(targetPath, overlayPath, policies, enforce,
+                    userId) != null;
             } else {
                 mInstaller.idmap(targetPath, overlayPath, sharedGid);
                 return true;
@@ -156,4 +169,71 @@
             }, SECOND_IN_MILLIS);
         }
     }
+
+    /**
+     * Checks if overlayable and policies should be enforced on the specified overlay for backwards
+     * compatibility with pre-Q overlays.
+     */
+    private boolean enforceOverlayable(@NonNull final PackageInfo overlayPackage) {
+        final ApplicationInfo ai = overlayPackage.applicationInfo;
+        if (ai.targetSdkVersion >= VERSION_CODES.Q) {
+            // Always enforce policies for overlays targeting Q+.
+            return true;
+        }
+
+        if (ai.isVendor() && !VENDOR_IS_Q_OR_LATER) {
+            // If the overlay is on a pre-Q vendor partition, do not enforce overlayable
+            // restrictions on this overlay because the pre-Q platform has no understanding of
+            // overlayable.
+            return false;
+        }
+
+        // Do not enforce overlayable restrictions on pre-Q overlays signed with the
+        // platform signature.
+        return !ai.isSignedWithPlatformKey();
+    }
+
+    /**
+     * Retrieves a bitmask for idmap2 that represents the policies the specified overlay fulfills.
+     * @throws SecurityException if the overlay is not allowed to overlay any resource
+     */
+    private int determineFulfilledPolicies(@NonNull final PackageInfo overlayPackage)
+            throws SecurityException {
+        final ApplicationInfo ai = overlayPackage.applicationInfo;
+        final boolean overlayIsQOrLater = ai.targetSdkVersion >= VERSION_CODES.Q;
+
+        int fulfilledPolicies = 0;
+
+        // TODO(b/119402606) : Add signature policy
+
+        // Vendor partition (/vendor)
+        if (ai.isVendor()) {
+            if (overlayIsQOrLater) {
+                fulfilledPolicies |= IIdmap2.POLICY_VENDOR_PARTITION;
+            } else if (VENDOR_IS_Q_OR_LATER) {
+                throw new SecurityException("Overlay must target Q sdk or higher");
+            }
+        }
+
+        // Product partition (/product)
+        if (ai.isProduct()) {
+            if (overlayIsQOrLater) {
+                fulfilledPolicies |= IIdmap2.POLICY_PRODUCT_PARTITION;
+            } else {
+                throw new SecurityException("Overlay must target Q sdk or higher");
+            }
+        }
+
+        // System partition (/system)
+        if (ai.isSystemApp()) {
+            if (overlayIsQOrLater) {
+                fulfilledPolicies |= IIdmap2.POLICY_SYSTEM_PARTITION;
+            } else {
+                throw new SecurityException("Overlay must target Q sdk or higher");
+            }
+        }
+
+        // All overlays can overlay resources with the public policy
+        return fulfilledPolicies | IIdmap2.POLICY_PUBLIC;
+    }
 }
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index b0d2704..1cbf0bf 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -270,7 +270,9 @@
             Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId);
         }
 
-        updateAllOverlaysForTarget(packageName, userId, 0);
+        if (updateAllOverlaysForTarget(packageName, userId, 0)) {
+            mListener.onOverlaysChanged(packageName, userId);
+        }
     }
 
     void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
diff --git a/services/core/java/com/android/server/os/BugreportManagerService.java b/services/core/java/com/android/server/os/BugreportManagerService.java
new file mode 100644
index 0000000..bee7a8b
--- /dev/null
+++ b/services/core/java/com/android/server/os/BugreportManagerService.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.os;
+
+import android.content.Context;
+
+import com.android.server.SystemService;
+
+/**
+ * Service that provides a privileged API to capture and consume bugreports.
+ *
+ * @hide
+ */
+public class BugreportManagerService extends SystemService {
+    private static final String TAG = "BugreportManagerService";
+
+    private BugreportManagerServiceImpl mService;
+
+    public BugreportManagerService(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+        mService = new BugreportManagerServiceImpl(getContext());
+        publishBinderService(Context.BUGREPORT_SERVICE, mService);
+    }
+}
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
new file mode 100644
index 0000000..f736056
--- /dev/null
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.os;
+
+import android.annotation.RequiresPermission;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.os.Binder;
+import android.os.BugreportParams;
+import android.os.IDumpstate;
+import android.os.IDumpstateListener;
+import android.os.IDumpstateToken;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+
+// TODO(b/111441001):
+// 1. Handle the case where another bugreport is in progress
+// 2. Make everything threadsafe
+// 3. Pass validation & other errors on listener
+
+/**
+ * Implementation of the service that provides a privileged API to capture and consume bugreports.
+ *
+ * <p>Delegates the actualy generation to a native implementation of {@code Dumpstate}.
+ */
+class BugreportManagerServiceImpl extends IDumpstate.Stub {
+    private static final String TAG = "BugreportManagerService";
+    private static final String BUGREPORT_SERVICE = "bugreportd";
+    private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000;
+
+    private IDumpstate mDs = null;
+    private final Context mContext;
+    private final AppOpsManager mAppOps;
+
+    BugreportManagerServiceImpl(Context context) {
+        mContext = context;
+        mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+    }
+
+    @Override
+    @RequiresPermission(android.Manifest.permission.DUMP)
+    public IDumpstateToken setListener(String name, IDumpstateListener listener,
+            boolean getSectionDetails) throws RemoteException {
+        // TODO(b/111441001): Figure out if lazy setting of listener should be allowed
+        // and if so how to handle it.
+        throw new UnsupportedOperationException("setListener is not allowed on this service");
+    }
+
+    // TODO(b/111441001): Intercept onFinished here in system server and shutdown
+    // the bugreportd service.
+    @Override
+    @RequiresPermission(android.Manifest.permission.DUMP)
+    public void startBugreport(int callingUidUnused, String callingPackage,
+            FileDescriptor bugreportFd, FileDescriptor screenshotFd,
+            int bugreportMode, IDumpstateListener listener) throws RemoteException {
+        int callingUid = Binder.getCallingUid();
+        // TODO(b/111441001): validate all arguments & ensure primary user
+        validate(bugreportMode);
+
+        mAppOps.checkPackage(callingUid, callingPackage);
+        mDs = getDumpstateService();
+        if (mDs == null) {
+            Slog.w(TAG, "Unable to get bugreport service");
+            // TODO(b/111441001): pass error on listener
+            return;
+        }
+        mDs.startBugreport(callingUid, callingPackage,
+                bugreportFd, screenshotFd, bugreportMode, listener);
+    }
+
+    @Override
+    @RequiresPermission(android.Manifest.permission.DUMP)
+    public void cancelBugreport() throws RemoteException {
+        // This tells init to cancel bugreportd service.
+        SystemProperties.set("ctl.stop", BUGREPORT_SERVICE);
+        mDs = null;
+    }
+
+    private boolean validate(@BugreportParams.BugreportMode int mode) {
+        if (mode != BugreportParams.BUGREPORT_MODE_FULL
+                && mode != BugreportParams.BUGREPORT_MODE_INTERACTIVE
+                && mode != BugreportParams.BUGREPORT_MODE_REMOTE
+                && mode != BugreportParams.BUGREPORT_MODE_WEAR
+                && mode != BugreportParams.BUGREPORT_MODE_TELEPHONY
+                && mode != BugreportParams.BUGREPORT_MODE_WIFI) {
+            Slog.w(TAG, "Unknown bugreport mode: " + mode);
+            return false;
+        }
+        return true;
+    }
+
+    /*
+     * Start and get a handle to the native implementation of {@code IDumpstate} which does the
+     * actual bugreport generation.
+     *
+     * <p>Generating bugreports requires root privileges. To limit the footprint
+     * of the root access, the actual generation in Dumpstate binary is accessed as a
+     * oneshot service 'bugreport'.
+     */
+    private IDumpstate getDumpstateService() {
+        // Start bugreport service.
+        SystemProperties.set("ctl.start", BUGREPORT_SERVICE);
+
+        IDumpstate ds = null;
+        boolean timedOut = false;
+        int totalTimeWaitedMillis = 0;
+        int seedWaitTimeMillis = 500;
+        while (!timedOut) {
+            // Note that the binder service on the native side is "dumpstate".
+            ds = IDumpstate.Stub.asInterface(ServiceManager.getService("dumpstate"));
+            if (ds != null) {
+                Slog.i(TAG, "Got bugreport service handle.");
+                break;
+            }
+            SystemClock.sleep(seedWaitTimeMillis);
+            Slog.i(TAG,
+                    "Waiting to get dumpstate service handle (" + totalTimeWaitedMillis + "ms)");
+            totalTimeWaitedMillis += seedWaitTimeMillis;
+            seedWaitTimeMillis *= 2;
+            timedOut = totalTimeWaitedMillis > DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS;
+        }
+        if (timedOut) {
+            Slog.w(TAG,
+                    "Timed out waiting to get dumpstate service handle ("
+                    + totalTimeWaitedMillis + "ms)");
+        }
+        return ds;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index d6ab5f7..65fc982 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -27,24 +27,29 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
 import android.os.BatteryManager;
 import android.os.Environment;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.StatsLog;
 
-import com.android.server.pm.dex.DexManager;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
 import com.android.server.PinnerService;
+import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.DexoptOptions;
 
 import java.io.File;
+import java.nio.file.Paths;
 import java.util.List;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * {@hide}
@@ -289,6 +294,50 @@
         return result;
     }
 
+    /**
+     * Get the size of the directory. It uses recursion to go over all files.
+     * @param f
+     * @return
+     */
+    private long getDirectorySize(File f) {
+        long size = 0;
+        if (f.isDirectory()) {
+            for (File file: f.listFiles()) {
+                size += getDirectorySize(file);
+            }
+        } else {
+            size = f.length();
+        }
+        return size;
+    }
+
+    /**
+     * Get the size of a package.
+     * @param pkg
+     */
+    private long getPackageSize(PackageManagerService pm, String pkg) {
+        PackageInfo info = pm.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+        long size = 0;
+        if (info != null && info.applicationInfo != null) {
+            File path = Paths.get(info.applicationInfo.sourceDir).toFile();
+            if (path.isFile()) {
+                path = path.getParentFile();
+            }
+            size += getDirectorySize(path);
+            if (!ArrayUtils.isEmpty(info.applicationInfo.splitSourceDirs)) {
+                for (String splitSourceDir : info.applicationInfo.splitSourceDirs) {
+                    path = Paths.get(splitSourceDir).toFile();
+                    if (path.isFile()) {
+                        path = path.getParentFile();
+                    }
+                    size += getDirectorySize(path);
+                }
+            }
+            return size;
+        }
+        return 0;
+    }
+
     private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
             long lowStorageThreshold, boolean is_for_primary_dex,
             ArraySet<String> failedPackageNames) {
@@ -315,8 +364,10 @@
 
             int reason;
             boolean downgrade;
+            long package_size_before = 0; //used when the app is downgraded
             // Downgrade unused packages.
             if (unusedPackages.contains(pkg) && shouldDowngrade) {
+                package_size_before = getPackageSize(pm, pkg);
                 // This applies for system apps or if packages location is not a directory, i.e.
                 // monolithic install.
                 if (is_for_primary_dex && !pm.canHaveOatDir(pkg)) {
@@ -366,6 +417,10 @@
                 synchronized (failedPackageNames) {
                     failedPackageNames.remove(pkg);
                 }
+                if (downgrade) {
+                    StatsLog.write(StatsLog.APP_DOWNGRADED, pkg, package_size_before,
+                            getPackageSize(pm, pkg), /*aggressive=*/ false);
+                }
             }
         }
         notifyPinService(updatedPackages);
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index 3b11525..8facce1 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -42,6 +42,7 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.DebugUtils;
 import android.util.Log;
 import android.util.LogPrinter;
 import android.util.Pair;
@@ -60,6 +61,7 @@
 
 /** Resolves all Android component types [activities, services, providers and receivers]. */
 public class ComponentResolver {
+    private static final boolean DEBUG = false;
     private static final String TAG = "PackageManager";
     private static final boolean DEBUG_FILTERS = false;
     private static final boolean DEBUG_SHOW_INFO = false;
@@ -1198,22 +1200,48 @@
             return packageName.equals(info.activity.owner.packageName);
         }
 
+        private void log(String reason, ActivityIntentInfo info, int match,
+                int userId) {
+            Slog.w(TAG, reason
+                    + "; match: "
+                    + DebugUtils.flagsToString(IntentFilter.class, "MATCH_", match)
+                    + "; userId: " + userId
+                    + "; intent info: " + info);
+        }
+
         @Override
         protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
                 int match, int userId) {
-            if (!sUserManager.exists(userId)) return null;
+            if (!sUserManager.exists(userId)) {
+                if (DEBUG) {
+                    log("User doesn't exist", info, match, userId);
+                }
+                return null;
+            }
             if (!sPackageManagerInternal.isEnabledAndMatches(info.activity.info, mFlags, userId)) {
+                if (DEBUG) {
+                    log("!PackageManagerInternal.isEnabledAndMatches; mFlags="
+                            + DebugUtils.flagsToString(PackageManager.class, "MATCH_", mFlags),
+                            info, match, userId);
+                }
                 return null;
             }
             final PackageParser.Activity activity = info.activity;
             PackageSetting ps = (PackageSetting) activity.owner.mExtras;
             if (ps == null) {
+                if (DEBUG) {
+                    log("info.activity.owner.mExtras == null", info, match, userId);
+                }
                 return null;
             }
             final PackageUserState userState = ps.readUserState(userId);
             ActivityInfo ai =
                     PackageParser.generateActivityInfo(activity, mFlags, userState, userId);
             if (ai == null) {
+                if (DEBUG) {
+                    log("Failed to create ActivityInfo based on " + info.activity, info, match,
+                            userId);
+                }
                 return null;
             }
             final boolean matchExplicitlyVisibleOnly =
@@ -1227,15 +1255,31 @@
             final boolean matchInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
             // throw out filters that aren't visible to ephemeral apps
             if (matchVisibleToInstantApp && !(componentVisible || userState.instantApp)) {
+                if (DEBUG) {
+                    log("Filter(s) not visible to ephemeral apps"
+                            + "; matchVisibleToInstantApp=" + matchVisibleToInstantApp
+                            + "; matchInstantApp=" + matchInstantApp
+                            + "; info.isVisibleToInstantApp()=" + info.isVisibleToInstantApp()
+                            + "; matchExplicitlyVisibleOnly=" + matchExplicitlyVisibleOnly
+                            + "; info.isExplicitlyVisibleToInstantApp()="
+                                    + info.isExplicitlyVisibleToInstantApp(),
+                            info, match, userId);
+                }
                 return null;
             }
             // throw out instant app filters if we're not explicitly requesting them
             if (!matchInstantApp && userState.instantApp) {
+                if (DEBUG) {
+                    log("Instant app filter is not explicitly requested", info, match, userId);
+                }
                 return null;
             }
             // throw out instant app filters if updates are available; will trigger
             // instant app resolution
             if (userState.instantApp && ps.isUpdateAvailable()) {
+                if (DEBUG) {
+                    log("Instant app update is available", info, match, userId);
+                }
                 return null;
             }
             final ResolveInfo res = new ResolveInfo();
diff --git a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
index 2ae424d..5b765df 100644
--- a/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
+++ b/services/core/java/com/android/server/pm/DynamicCodeLoggingService.java
@@ -22,63 +22,117 @@
 import android.app.job.JobService;
 import android.content.ComponentName;
 import android.content.Context;
+import android.os.Process;
 import android.os.ServiceManager;
+import android.util.ByteStringUtils;
+import android.util.EventLog;
 import android.util.Log;
 
 import com.android.server.pm.dex.DexLogger;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
- * Scheduled job to trigger logging of app dynamic code loading. This runs daily while idle and
- * charging. The actual logging is performed by {@link DexLogger}.
+ * Scheduled jobs related to logging of app dynamic code loading. The idle logging job runs daily
+ * while idle and charging  and calls {@link DexLogger} to write dynamic code information to the
+ * event log. The audit watching job scans the event log periodically while idle to find AVC audit
+ * messages indicating use of dynamic native code and adds the information to {@link DexLogger}.
  * {@hide}
  */
 public class DynamicCodeLoggingService extends JobService {
     private static final String TAG = DynamicCodeLoggingService.class.getName();
 
-    private static final int JOB_ID = 2030028;
-    private static final long PERIOD_MILLIS = TimeUnit.DAYS.toMillis(1);
-
-    private volatile boolean mStopRequested = false;
-
     private static final boolean DEBUG = false;
 
+    private static final int IDLE_LOGGING_JOB_ID = 2030028;
+    private static final int AUDIT_WATCHING_JOB_ID = 203142925;
+
+    private static final long IDLE_LOGGING_PERIOD_MILLIS = TimeUnit.DAYS.toMillis(1);
+    private static final long AUDIT_WATCHING_PERIOD_MILLIS = TimeUnit.HOURS.toMillis(2);
+
+    private static final int AUDIT_AVC = 1400;  // Defined in linux/audit.h
+    private static final String AVC_PREFIX = "type=" + AUDIT_AVC + " ";
+
+    private static final Pattern EXECUTE_NATIVE_AUDIT_PATTERN =
+            Pattern.compile(".*\\bavc: granted \\{ execute(?:_no_trans|) \\} .*"
+                    + "\\bpath=(?:\"([^\" ]*)\"|([0-9A-F]+)) .*"
+                    + "\\bscontext=u:r:untrusted_app_2(?:5|7):.*"
+                    + "\\btcontext=u:object_r:app_data_file:.*"
+                    + "\\btclass=file\\b.*");
+
+    private volatile boolean mIdleLoggingStopRequested = false;
+    private volatile boolean mAuditWatchingStopRequested = false;
+
     /**
-     * Schedule our job with the {@link JobScheduler}.
+     * Schedule our jobs with the {@link JobScheduler}.
      */
     public static void schedule(Context context) {
         ComponentName serviceName = new ComponentName(
                 "android", DynamicCodeLoggingService.class.getName());
 
         JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-        js.schedule(new JobInfo.Builder(JOB_ID, serviceName)
+        js.schedule(new JobInfo.Builder(IDLE_LOGGING_JOB_ID, serviceName)
                 .setRequiresDeviceIdle(true)
                 .setRequiresCharging(true)
-                .setPeriodic(PERIOD_MILLIS)
+                .setPeriodic(IDLE_LOGGING_PERIOD_MILLIS)
                 .build());
+        js.schedule(new JobInfo.Builder(AUDIT_WATCHING_JOB_ID, serviceName)
+                .setRequiresDeviceIdle(true)
+                .setRequiresBatteryNotLow(true)
+                .setPeriodic(AUDIT_WATCHING_PERIOD_MILLIS)
+                .build());
+
         if (DEBUG) {
-            Log.d(TAG, "Job scheduled");
+            Log.d(TAG, "Jobs scheduled");
         }
     }
 
     @Override
     public boolean onStartJob(JobParameters params) {
+        int jobId = params.getJobId();
         if (DEBUG) {
-            Log.d(TAG, "onStartJob");
+            Log.d(TAG, "onStartJob " + jobId);
         }
-        mStopRequested = false;
-        new IdleLoggingThread(params).start();
-        return true;  // Job is running on another thread
+        switch (jobId) {
+            case IDLE_LOGGING_JOB_ID:
+                mIdleLoggingStopRequested = false;
+                new IdleLoggingThread(params).start();
+                return true;  // Job is running on another thread
+            case AUDIT_WATCHING_JOB_ID:
+                mAuditWatchingStopRequested = false;
+                new AuditWatchingThread(params).start();
+                return true;  // Job is running on another thread
+            default:
+                // Shouldn't happen, but indicate nothing is running.
+                return false;
+        }
     }
 
     @Override
     public boolean onStopJob(JobParameters params) {
+        int jobId = params.getJobId();
         if (DEBUG) {
-            Log.d(TAG, "onStopJob");
+            Log.d(TAG, "onStopJob " + jobId);
         }
-        mStopRequested = true;
-        return true;  // Requests job be re-scheduled.
+        switch (jobId) {
+            case IDLE_LOGGING_JOB_ID:
+                mIdleLoggingStopRequested = true;
+                return true;  // Requests job be re-scheduled.
+            case AUDIT_WATCHING_JOB_ID:
+                mAuditWatchingStopRequested = true;
+                return true;  // Requests job be re-scheduled.
+            default:
+                return false;
+        }
+    }
+
+    private static DexLogger getDexLogger() {
+        PackageManagerService pm = (PackageManagerService) ServiceManager.getService("package");
+        return pm.getDexManager().getDexLogger();
     }
 
     private class IdleLoggingThread extends Thread {
@@ -92,14 +146,13 @@
         @Override
         public void run() {
             if (DEBUG) {
-                Log.d(TAG, "Starting logging run");
+                Log.d(TAG, "Starting IdleLoggingJob run");
             }
 
-            PackageManagerService pm = (PackageManagerService) ServiceManager.getService("package");
-            DexLogger dexLogger = pm.getDexManager().getDexLogger();
+            DexLogger dexLogger = getDexLogger();
             for (String packageName : dexLogger.getAllPackagesWithDynamicCodeLoading()) {
-                if (mStopRequested) {
-                    Log.w(TAG, "Stopping logging run at scheduler request");
+                if (mIdleLoggingStopRequested) {
+                    Log.w(TAG, "Stopping IdleLoggingJob run at scheduler request");
                     return;
                 }
 
@@ -108,8 +161,128 @@
 
             jobFinished(mParams, /* reschedule */ false);
             if (DEBUG) {
-                Log.d(TAG, "Finished logging run");
+                Log.d(TAG, "Finished IdleLoggingJob run");
             }
         }
     }
+
+    private class AuditWatchingThread extends Thread {
+        private final JobParameters mParams;
+
+        AuditWatchingThread(JobParameters params) {
+            super("DynamicCodeLoggingService_AuditWatchingJob");
+            mParams = params;
+        }
+
+        @Override
+        public void run() {
+            if (DEBUG) {
+                Log.d(TAG, "Starting AuditWatchingJob run");
+            }
+
+            if (processAuditEvents()) {
+                jobFinished(mParams, /* reschedule */ false);
+                if (DEBUG) {
+                    Log.d(TAG, "Finished AuditWatchingJob run");
+                }
+            }
+        }
+
+        private boolean processAuditEvents() {
+            // Scan the event log for SELinux (avc) audit messages indicating when an
+            // (untrusted) app has executed native code from an app data
+            // file. Matches are recorded in DexLogger.
+            //
+            // These messages come from the kernel audit system via logd. (Note that
+            // some devices may not generate these messages at all, or the format may
+            // be different, in which case nothing will be recorded.)
+            //
+            // The messages use the auditd tag and the uid of the app that executed
+            // the code.
+            //
+            // A typical message might look like this:
+            // type=1400 audit(0.0:521): avc: granted { execute } for comm="executable"
+            //  path="/data/data/com.dummy.app/executable" dev="sda13" ino=1655302
+            //  scontext=u:r:untrusted_app_27:s0:c66,c257,c512,c768
+            //  tcontext=u:object_r:app_data_file:s0:c66,c257,c512,c768 tclass=file
+            //
+            // The information we want is the uid and the path. (Note this may be
+            // either a quoted string, as shown above, or a sequence of hex-encoded
+            // bytes.)
+            //
+            // On each run we process all the matching events in the log. This may
+            // mean re-processing events we have already seen, and in any case there
+            // may be duplicate events for the same app+file. These are de-duplicated
+            // by DexLogger.
+            //
+            // Note that any app can write a message to the event log, including one
+            // that looks exactly like an AVC audit message, so the information may
+            // be spoofed by an app; in such a case the uid we see will be the app
+            // that generated the spoof message.
+
+            try {
+                int[] tags = { EventLog.getTagCode("auditd") };
+                if (tags[0] == -1) {
+                    // auditd is not a registered tag on this system, so there can't be any messages
+                    // of interest.
+                    return true;
+                }
+
+                DexLogger dexLogger = getDexLogger();
+
+                List<EventLog.Event> events = new ArrayList<>();
+                EventLog.readEvents(tags, events);
+
+                for (int i = 0; i < events.size(); ++i) {
+                    if (mAuditWatchingStopRequested) {
+                        Log.w(TAG, "Stopping AuditWatchingJob run at scheduler request");
+                        return false;
+                    }
+
+                    EventLog.Event event = events.get(i);
+
+                    // Discard clearly unrelated messages as quickly as we can.
+                    int uid = event.getUid();
+                    if (!Process.isApplicationUid(uid)) {
+                        continue;
+                    }
+                    Object data = event.getData();
+                    if (!(data instanceof String)) {
+                        continue;
+                    }
+                    String message = (String) data;
+                    if (!message.startsWith(AVC_PREFIX)) {
+                        continue;
+                    }
+
+                    // And then use a regular expression to verify it's one of the messages we're
+                    // interested in and to extract the path of the file being loaded.
+                    Matcher matcher = EXECUTE_NATIVE_AUDIT_PATTERN.matcher(message);
+                    if (!matcher.matches()) {
+                        continue;
+                    }
+                    String path = matcher.group(1);
+                    if (path == null) {
+                        // If the path contains spaces or various weird characters the kernel
+                        // hex-encodes the bytes; we need to undo that.
+                        path = unhex(matcher.group(2));
+                    }
+                    dexLogger.recordNative(uid, path);
+                }
+
+                return true;
+            } catch (Exception e) {
+                Log.e(TAG, "AuditWatchingJob failed", e);
+                return true;
+            }
+        }
+    }
+
+    private static String unhex(String hexEncodedPath) {
+        byte[] bytes = ByteStringUtils.fromHexToByteArray(hexEncodedPath);
+        if (bytes == null || bytes.length == 0) {
+            return "";
+        }
+        return new String(bytes);
+    }
 }
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index a5c083e..efafdfa 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -611,6 +611,31 @@
         }
     }
 
+    public boolean snapshotAppData(String pkg, @UserIdInt int userId, int storageFlags)
+            throws InstallerException {
+        if (!checkBeforeRemote()) return false;
+
+        try {
+            mInstalld.snapshotAppData(null, pkg, userId, storageFlags);
+            return true;
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
+    public boolean restoreAppDataSnapshot(String pkg, @AppIdInt  int appId, long ceDataInode,
+            String seInfo, @UserIdInt int userId, int storageFlags) throws InstallerException {
+        if (!checkBeforeRemote()) return false;
+
+        try {
+            mInstalld.restoreAppDataSnapshot(null, pkg, appId, ceDataInode, seInfo, userId,
+                    storageFlags);
+            return true;
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
     private static void assertValidInstructionSet(String instructionSet)
             throws InstallerException {
         for (String abi : Build.SUPPORTED_ABIS) {
@@ -621,6 +646,14 @@
         throw new InstallerException("Invalid instruction set: " + instructionSet);
     }
 
+    public boolean compileLayouts(String apkPath, String packageName, String outDexFile, int uid) {
+        try {
+            return mInstalld.compileLayouts(apkPath, packageName, outDexFile, uid);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
     public static class InstallerException extends Exception {
         public InstallerException(String detailMessage) {
             super(detailMessage);
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 7f1fb6c..a33f14b 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -24,6 +24,7 @@
 import android.app.AppGlobals;
 import android.app.IApplicationThread;
 import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -32,6 +33,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ILauncherApps;
 import android.content.pm.IOnAppsChangedListener;
+import android.content.pm.LauncherApps;
 import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -41,6 +43,8 @@
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutServiceInternal;
 import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
+import android.content.pm.Signature;
+import android.content.pm.SigningInfo;
 import android.content.pm.UserInfo;
 import android.graphics.Rect;
 import android.net.Uri;
@@ -55,21 +59,31 @@
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.provider.Settings;
+import android.util.ByteStringUtils;
 import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.StatLogger;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Service that manages requests and callbacks for launchers that support
@@ -107,6 +121,17 @@
     static class LauncherAppsImpl extends ILauncherApps.Stub {
         private static final boolean DEBUG = false;
         private static final String TAG = "LauncherAppsService";
+
+        // Stats
+        @VisibleForTesting
+        interface Stats {
+            int INIT_VOUCHED_SIGNATURES = 0;
+            int COUNT = INIT_VOUCHED_SIGNATURES + 1;
+        }
+        private final StatLogger mStatLogger = new StatLogger(new String[] {
+                "initVouchedSignatures"
+        });
+
         private final Context mContext;
         private final UserManager mUm;
         private final UserManagerInternal mUserManagerInternal;
@@ -115,11 +140,17 @@
         private final ShortcutServiceInternal mShortcutServiceInternal;
         private final PackageCallbackList<IOnAppsChangedListener> mListeners
                 = new PackageCallbackList<IOnAppsChangedListener>();
+        private final DevicePolicyManager mDpm;
+        private final ConcurrentHashMap<UserHandle, Set<String>> mVouchedSignaturesByUser;
+        private final Set<String> mVouchProviders;
 
         private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
+        private final VouchesChangedMonitor mVouchesChangedMonitor = new VouchesChangedMonitor();
 
         private final Handler mCallbackHandler;
 
+        private final Object mVouchedSignaturesLocked = new Object();
+
         public LauncherAppsImpl(Context context) {
             mContext = context;
             mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
@@ -133,6 +164,10 @@
                     LocalServices.getService(ShortcutServiceInternal.class));
             mShortcutServiceInternal.addListener(mPackageMonitor);
             mCallbackHandler = BackgroundThread.getHandler();
+            mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+            mVouchedSignaturesByUser = new ConcurrentHashMap<>();
+            mVouchProviders = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
+            mVouchesChangedMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler);
         }
 
         @VisibleForTesting
@@ -301,6 +336,17 @@
         }
 
         @Override
+        public boolean shouldHideFromSuggestions(String packageName, UserHandle user) {
+            if (!canAccessProfile(user.getIdentifier(), "cannot get shouldHideFromSuggestions")) {
+                return false;
+            }
+            final PackageManagerInternal pmi = LocalServices.getService(
+                    PackageManagerInternal.class);
+            int flags = pmi.getDistractingPackageRestrictions(packageName, user.getIdentifier());
+            return (flags & PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS) != 0;
+        }
+
+        @Override
         public ParceledListSlice<ResolveInfo> getLauncherActivities(String callingPackage,
                 String packageName, UserHandle user) throws RemoteException {
             ParceledListSlice<ResolveInfo> launcherActivities = queryActivitiesForUser(
@@ -313,30 +359,42 @@
                     Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, 1) == 0) {
                 return launcherActivities;
             }
-
-            final int callingUid = injectBinderCallingUid();
-            final ArrayList<ResolveInfo> result = new ArrayList<>(launcherActivities.getList());
-            final PackageManagerInternal pmInt =
-                    LocalServices.getService(PackageManagerInternal.class);
-            if (packageName != null) {
-                // If this hidden app should not be shown, return the original list.
-                // Otherwise, inject hidden activity that forwards user to app details page.
-                if (result.size() > 0) {
-                    return launcherActivities;
-                }
-                ApplicationInfo appInfo = pmInt.getApplicationInfo(packageName, /*flags*/ 0,
-                        callingUid, user.getIdentifier());
-                if (shouldShowHiddenApp(appInfo)) {
-                    ResolveInfo info = getHiddenAppActivityInfo(packageName, callingUid, user);
-                    if (info != null) {
-                        result.add(info);
-                    }
-                }
-                return new ParceledListSlice<>(result);
+            if (launcherActivities == null) {
+                // Cannot access profile, so we don't even return any hidden apps.
+                return null;
             }
 
-            long ident = injectClearCallingIdentity();
+            final int callingUid = injectBinderCallingUid();
+            final long ident = injectClearCallingIdentity();
             try {
+                if (mUm.getUserInfo(user.getIdentifier()).isManagedProfile()) {
+                    // Managed profile should not show hidden apps
+                    return launcherActivities;
+                }
+                if (mDpm.getDeviceOwnerComponentOnAnyUser() != null) {
+                    // Device owner devices should not show hidden apps
+                    return launcherActivities;
+                }
+
+                final ArrayList<ResolveInfo> result = new ArrayList<>(launcherActivities.getList());
+                final PackageManagerInternal pmInt =
+                        LocalServices.getService(PackageManagerInternal.class);
+                if (packageName != null) {
+                    // If this hidden app should not be shown, return the original list.
+                    // Otherwise, inject hidden activity that forwards user to app details page.
+                    if (result.size() > 0) {
+                        return launcherActivities;
+                    }
+                    ApplicationInfo appInfo = pmInt.getApplicationInfo(packageName, /*flags*/ 0,
+                            callingUid, user.getIdentifier());
+                    if (shouldShowHiddenApp(user, appInfo)) {
+                        ResolveInfo info = getHiddenAppActivityInfo(packageName, callingUid, user);
+                        if (info != null) {
+                            result.add(info);
+                        }
+                    }
+                    return new ParceledListSlice<>(result);
+                }
                 final HashSet<String> visiblePackages = new HashSet<>();
                 for (ResolveInfo info : result) {
                     visiblePackages.add(info.activityInfo.packageName);
@@ -345,7 +403,7 @@
                         user.getIdentifier(), callingUid);
                 for (ApplicationInfo applicationInfo : installedPackages) {
                     if (!visiblePackages.contains(applicationInfo.packageName)) {
-                        if (!shouldShowHiddenApp(applicationInfo)) {
+                        if (!shouldShowHiddenApp(user, applicationInfo)) {
                             continue;
                         }
                         ResolveInfo info = getHiddenAppActivityInfo(applicationInfo.packageName,
@@ -361,13 +419,130 @@
             }
         }
 
-        private static boolean shouldShowHiddenApp(ApplicationInfo appInfo) {
+        private boolean shouldShowHiddenApp(UserHandle user, ApplicationInfo appInfo) {
             if (appInfo == null || appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) {
                 return false;
             }
+            if (!mVouchedSignaturesByUser.containsKey(user)) {
+                initVouchedSignatures(user);
+            }
+            if (mVouchProviders.contains(appInfo.packageName)) {
+                // If it's a vouching packages then we must show hidden app
+                return true;
+            }
+            // If app's signature is in vouch list, do not show hidden app
+            final Set<String> vouches = mVouchedSignaturesByUser.get(user);
+            try {
+                final PackageInfo pkgInfo = mContext.getPackageManager().getPackageInfo(
+                        appInfo.packageName, PackageManager.GET_SIGNING_CERTIFICATES);
+                final Signature[] signatures = getLatestSignatures(pkgInfo.signingInfo);
+                // If any of the signatures appears in vouches, then we don't show hidden app
+                for (Signature signature : signatures) {
+                    final String certDigest = computePackageCertDigest(signature);
+                    if (vouches.contains(certDigest)) {
+                        return false;
+                    }
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                // Should not happen
+            }
             return true;
         }
 
+        @VisibleForTesting
+        static String computePackageCertDigest(Signature signature) {
+            MessageDigest messageDigest;
+            try {
+                messageDigest = MessageDigest.getInstance("SHA1");
+            } catch (NoSuchAlgorithmException e) {
+                // Should not happen
+                return null;
+            }
+            messageDigest.update(signature.toByteArray());
+            final byte[] digest = messageDigest.digest();
+            return ByteStringUtils.toHexString(digest);
+        }
+
+        @VisibleForTesting
+        static Signature[] getLatestSignatures(SigningInfo signingInfo) {
+            if (signingInfo.hasMultipleSigners()) {
+                return signingInfo.getApkContentsSigners();
+            } else {
+                final Signature[] signatures = signingInfo.getSigningCertificateHistory();
+                return new Signature[]{signatures[0]};
+            }
+        }
+
+        private void updateVouches(String packageName, UserHandle user) {
+            final PackageManagerInternal pmInt =
+                    LocalServices.getService(PackageManagerInternal.class);
+            ApplicationInfo appInfo = pmInt.getApplicationInfo(packageName,
+                    PackageManager.GET_META_DATA, Binder.getCallingUid(), user.getIdentifier());
+            if (appInfo == null) {
+                Log.w(TAG, "appInfo " + packageName + " is null");
+                return;
+            }
+            updateVouches(appInfo, user);
+        }
+
+        private void updateVouches(ApplicationInfo appInfo, UserHandle user) {
+            if (appInfo == null || appInfo.metaData == null) {
+                // No meta-data
+                return;
+            }
+            int tokenResourceId = appInfo.metaData.getInt(LauncherApps.VOUCHED_CERTS_KEY);
+            if (tokenResourceId == 0) {
+                // No xml file
+                return;
+            }
+            mVouchProviders.add(appInfo.packageName);
+            Set<String> vouches = mVouchedSignaturesByUser.get(user);
+            try {
+                List<String> signatures = Arrays.asList(
+                        mContext.getPackageManager().getResourcesForApplication(
+                                appInfo.packageName).getStringArray(tokenResourceId));
+                for (String signature : signatures) {
+                    vouches.add(signature.toUpperCase());
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                // Should not happen
+            }
+        }
+
+        private void initVouchedSignatures(UserHandle user) {
+            synchronized (mVouchedSignaturesLocked) {
+                if (mVouchedSignaturesByUser.contains(user)) {
+                    return;
+                }
+                final long startTime = mStatLogger.getTime();
+
+                Set<String> vouches = Collections.newSetFromMap(
+                        new ConcurrentHashMap<String, Boolean>());
+
+                final int callingUid = injectBinderCallingUid();
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    final PackageManagerInternal pmInt =
+                            LocalServices.getService(PackageManagerInternal.class);
+                    List<ApplicationInfo> installedPackages = pmInt.getInstalledApplications(
+                            PackageManager.GET_META_DATA, user.getIdentifier(), callingUid);
+                    for (ApplicationInfo appInfo : installedPackages) {
+                        updateVouches(appInfo, user);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+                mVouchedSignaturesByUser.putIfAbsent(user, vouches);
+                mStatLogger.logDurationStat(Stats.INIT_VOUCHED_SIGNATURES, startTime);
+            }
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
+            mStatLogger.dump(pw, "  ");
+        }
+
         @Override
         public ActivityInfo resolveActivity(
                 String callingPackage, ComponentName component, UserHandle user)
@@ -734,6 +909,18 @@
             mCallbackHandler.post(r);
         }
 
+        private class VouchesChangedMonitor extends PackageMonitor {
+            @Override
+            public void onPackageAdded(String packageName, int uid) {
+                updateVouches(packageName, new UserHandle(getChangingUserId()));
+            }
+
+            @Override
+            public void onPackageModified(String packageName) {
+                updateVouches(packageName, new UserHandle(getChangingUserId()));
+            }
+        }
+
         private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener {
 
             // TODO Simplify with lambdas.
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
new file mode 100644
index 0000000..60d7925
--- /dev/null
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -0,0 +1,76 @@
+hackbod@android.com
+hackbod@google.com
+jsharkey@android.com
+jsharkey@google.com
+narayan@google.com
+patb@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
+toddke@android.com
+toddke@google.com
+
+# dex
+per-file AbstractStatsBase.java = agampe@google.com
+per-file AbstractStatsBase.java = calin@google.com
+per-file AbstractStatsBase.java = ngeoffray@google.com
+per-file BackgroundDexOptService.java = agampe@google.com
+per-file BackgroundDexOptService.java = calin@google.com
+per-file BackgroundDexOptService.java = ngeoffray@google.com
+per-file CompilerStats.java = agampe@google.com
+per-file CompilerStats.java = calin@google.com
+per-file CompilerStats.java = ngeoffray@google.com
+per-file InstructionSets.java = agampe@google.com
+per-file InstructionSets.java = calin@google.com
+per-file InstructionSets.java = ngeoffray@google.com
+per-file OtaDexoptService.java = agampe@google.com
+per-file OtaDexoptService.java = calin@google.com
+per-file OtaDexoptService.java = ngeoffray@google.com
+per-file OtaDexoptShellCommand.java = agampe@google.com
+per-file OtaDexoptShellCommand.java = calin@google.com
+per-file OtaDexoptShellCommand.java = ngeoffray@google.com
+per-file PackageDexOptimizer.java = agampe@google.com
+per-file PackageDexOptimizer.java = calin@google.com
+per-file PackageDexOptimizer.java = ngeoffray@google.com
+per-file PackageManagerServiceCompilerMapping.java = agampe@google.com
+per-file PackageManagerServiceCompilerMapping.java = calin@google.com
+per-file PackageManagerServiceCompilerMapping.java = ngeoffray@google.com
+per-file PackageUsage.java = agampe@google.com
+per-file PackageUsage.java = calin@google.com
+per-file PackageUsage.java = ngeoffray@google.com
+
+# multi user / cross profile
+per-file CrossProfileAppsServiceImpl.java = omakoto@google.com
+per-file CrossProfileAppsServiceImpl.java = yamasani@google.com
+per-file CrossProfileAppsService.java = omakoto@google.com
+per-file CrossProfileAppsService.java = yamasani@google.com
+per-file CrossProfileIntentFilter.java = omakoto@google.com
+per-file CrossProfileIntentFilter.java = yamasani@google.com
+per-file CrossProfileIntentResolver.java = omakoto@google.com
+per-file CrossProfileIntentResolver.java = yamasani@google.com
+per-file UserManagerService.java = omakoto@google.com
+per-file UserManagerService.java = yamasani@google.com
+per-file UserRestrictionsUtils.java = omakoto@google.com
+per-file UserRestrictionsUtils.java = yamasani@google.com
+
+# security
+per-file KeySetHandle.java = cbrubaker@google.com
+per-file KeySetManagerService.java = cbrubaker@google.com
+per-file PackageKeySetData.java = cbrubaker@google.com
+per-file PackageSignatures.java = cbrubaker@google.com
+per-file SELinuxMMAC.java = cbrubaker@google.com
+
+# shortcuts
+per-file LauncherAppsService.java = omakoto@google.com
+per-file ShareTargetInfo.java = omakoto@google.com
+per-file ShortcutBitmapSaver.java = omakoto@google.com
+per-file ShortcutDumpFiles.java = omakoto@google.com
+per-file ShortcutLauncher.java = omakoto@google.com
+per-file ShortcutNonPersistentUser.java = omakoto@google.com
+per-file ShortcutPackage.java = omakoto@google.com
+per-file ShortcutPackageInfo.java = omakoto@google.com
+per-file ShortcutPackageItem.java = omakoto@google.com
+per-file ShortcutParser.java = omakoto@google.com
+per-file ShortcutRequestPinProcessor.java = omakoto@google.com
+per-file ShortcutService.java = omakoto@google.com
+per-file ShortcutUser.java = omakoto@google.com
+
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index db7e99d..94b1b36 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -85,9 +85,6 @@
     // One minute over PM WATCHDOG_TIMEOUT
     private static final long WAKELOCK_TIMEOUT_MS = WATCHDOG_TIMEOUT + 1000 * 60;
 
-    /** Special library name that skips shared libraries check during compilation. */
-    public static final String SKIP_SHARED_LIBRARY_CHECK = "&";
-
     @GuardedBy("mInstallLock")
     private final Installer mInstaller;
     private final Object mInstallLock;
@@ -397,23 +394,23 @@
             Slog.e(TAG, "Could not infer CE/DE storage for package " + info.packageName);
             return DEX_OPT_FAILED;
         }
-        Log.d(TAG, "Running dexopt on: " + path
-                + " pkg=" + info.packageName + " isa=" + dexUseInfo.getLoaderIsas()
-                + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
-                + " target-filter=" + compilerFilter);
-
-        String classLoaderContext;
+        String classLoaderContext = null;
         if (dexUseInfo.isUnknownClassLoaderContext() || dexUseInfo.isVariableClassLoaderContext()) {
-            // If we have an unknown (not yet set), or a variable class loader chain, compile
-            // without a context and mark the oat file with SKIP_SHARED_LIBRARY_CHECK. Note that
-            // this might lead to a incorrect compilation.
-            // TODO(calin): We should just extract in this case.
-            classLoaderContext = SKIP_SHARED_LIBRARY_CHECK;
+            // If we have an unknown (not yet set), or a variable class loader chain. Just extract
+            // the dex file.
+            compilerFilter = "extract";
         } else {
             classLoaderContext = dexUseInfo.getClassLoaderContext();
         }
 
         int reason = options.getCompilationReason();
+        Log.d(TAG, "Running dexopt on: " + path
+                + " pkg=" + info.packageName + " isa=" + dexUseInfo.getLoaderIsas()
+                + " reason=" + getReasonName(reason)
+                + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
+                + " target-filter=" + compilerFilter
+                + " class-loader-context=" + classLoaderContext);
+
         try {
             for (String isa : dexUseInfo.getLoaderIsas()) {
                 // Reuse the same dexopt path as for the primary apks. We don't need all the
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 66eae5e..0ab2a73 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -209,8 +209,7 @@
         synchronized (mSessions) {
             readSessionsLocked();
 
-            reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, false /*isInstant*/);
-            reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, true /*isInstant*/);
+            reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL);
 
             final ArraySet<File> unclaimedIcons = newArraySet(
                     mSessionsDir.listFiles());
@@ -226,12 +225,23 @@
                 Slog.w(TAG, "Deleting orphan icon " + icon);
                 icon.delete();
             }
+
+            // Invalid sessions might have been marked while parsing. Re-write the database with
+            // the updated information.
+            writeSessionsLocked();
+
+            for (int i = 0; i < mSessions.size(); i++) {
+                final PackageInstallerSession session = mSessions.valueAt(i);
+                if (session.isStaged()) {
+                    mStagingManager.restoreSession(session);
+                }
+            }
         }
     }
 
     @GuardedBy("mSessions")
-    private void reconcileStagesLocked(String volumeUuid, boolean isEphemeral) {
-        final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
+    private void reconcileStagesLocked(String volumeUuid) {
+        final File stagingDir = getTmpSessionDir(volumeUuid);
         final ArraySet<File> unclaimedStages = newArraySet(
                 stagingDir.listFiles(sStageFilter));
 
@@ -252,7 +262,7 @@
 
     public void onPrivateVolumeMounted(String volumeUuid) {
         synchronized (mSessions) {
-            reconcileStagesLocked(volumeUuid, false /*isInstant*/);
+            reconcileStagesLocked(volumeUuid);
         }
     }
 
@@ -269,9 +279,9 @@
             try {
                 final int sessionId = allocateSessionIdLocked();
                 mLegacySessions.put(sessionId, true);
-                final File stageDir = buildStageDir(volumeUuid, sessionId, isEphemeral);
-                prepareStageDir(stageDir);
-                return stageDir;
+                final File sessionStageDir = buildTmpSessionDir(sessionId, volumeUuid);
+                prepareStageDir(sessionStageDir);
+                return sessionStageDir;
             } catch (IllegalStateException e) {
                 throw new IOException(e);
             }
@@ -300,7 +310,6 @@
             in.setInput(fis, StandardCharsets.UTF_8.name());
 
             int type;
-            PackageInstallerSession currentSession = null;
             while ((type = in.next()) != END_DOCUMENT) {
                 if (type == START_TAG) {
                     final String tag = in.getName();
@@ -310,9 +319,7 @@
                             session = PackageInstallerSession.readFromXml(in, mInternalCallback,
                                     mContext, mPm, mInstallThread.getLooper(), mStagingManager,
                                     mSessionsDir, this);
-                            currentSession = session;
                         } catch (Exception e) {
-                            currentSession = null;
                             Slog.e(TAG, "Could not read session", e);
                             continue;
                         }
@@ -337,10 +344,6 @@
                             addHistoricalSessionLocked(session);
                         }
                         mAllocatedSessions.put(session.sessionId, true);
-                    } else if (currentSession != null
-                            && PackageInstallerSession.TAG_CHILD_SESSION.equals(tag)) {
-                        currentSession.addChildSessionIdInternal(
-                                PackageInstallerSession.readChildSessionIdFromXml(in));
                     }
                 }
             }
@@ -526,9 +529,7 @@
         String stageCid = null;
         if (!params.isMultiPackage) {
             if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
-                final boolean isInstant =
-                        (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
-                stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
+                stageDir = buildSessionDir(sessionId, params);
             } else {
                 stageCid = buildExternalStageCid(sessionId);
             }
@@ -536,7 +537,7 @@
         session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
                 mInstallThread.getLooper(), mStagingManager, sessionId, userId,
                 installerPackageName, callingUid, params, createdMillis, stageDir, stageCid, false,
-                false, null, SessionInfo.INVALID_ID);
+                false, null, SessionInfo.INVALID_ID, false, false, false, SessionInfo.NO_ERROR);
 
         synchronized (mSessions) {
             mSessions.put(sessionId, session);
@@ -634,13 +635,21 @@
         throw new IllegalStateException("Failed to allocate session ID");
     }
 
-    private File buildStagingDir(String volumeUuid, boolean isEphemeral) {
+    private File getTmpSessionDir(String volumeUuid) {
         return Environment.getDataAppDirectory(volumeUuid);
     }
 
-    private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) {
-        final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
-        return new File(stagingDir, "vmdl" + sessionId + ".tmp");
+    private File buildTmpSessionDir(int sessionId, String volumeUuid) {
+        final File sessionStagingDir = getTmpSessionDir(volumeUuid);
+        return new File(sessionStagingDir, "vmdl" + sessionId + ".tmp");
+    }
+
+    private File buildSessionDir(int sessionId, SessionParams params) {
+        if (params.isStaged) {
+            final File sessionStagingDir = Environment.getDataStagingDirectory(params.volumeUuid);
+            return new File(sessionStagingDir, "session_" + sessionId);
+        }
+        return buildTmpSessionDir(sessionId, params.volumeUuid);
     }
 
     static void prepareStageDir(File stageDir) throws IOException {
@@ -1114,6 +1123,12 @@
             mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress);
         }
 
+        public void onStagedSessionChanged(PackageInstallerSession session) {
+            writeSessionsAsync();
+            // TODO(b/118865310): don't send broadcast if system is not ready.
+            mPm.sendSessionUpdatedBroadcast(session.generateInfo(false), session.userId);
+        }
+
         public void onSessionFinished(final PackageInstallerSession session, boolean success) {
             mCallbacks.notifySessionFinished(session.sessionId, session.userId, success);
 
@@ -1126,7 +1141,9 @@
                         }
                     }
                     synchronized (mSessions) {
-                        mSessions.remove(session.sessionId);
+                        if (!session.isStaged() || !success) {
+                            mSessions.remove(session.sessionId);
+                        }
                         addHistoricalSessionLocked(session);
 
                         final File appIconFile = buildAppIconFile(session.sessionId);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d290f3f..b8825bb 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
+import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_SIGNATURE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
@@ -56,6 +57,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.PackageInstaller.SessionInfo.StagedSessionErrorCode;
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
@@ -106,6 +108,7 @@
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
 import com.android.server.pm.dex.DexManager;
+import com.android.server.security.VerityUtils;
 
 import libcore.io.IoUtils;
 
@@ -148,6 +151,10 @@
     private static final String ATTR_MULTI_PACKAGE = "multiPackage";
     private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
     private static final String ATTR_STAGED_SESSION = "stagedSession";
+    private static final String ATTR_IS_READY = "isReady";
+    private static final String ATTR_IS_FAILED = "isFailed";
+    private static final String ATTR_IS_APPLIED = "isApplied";
+    private static final String ATTR_STAGED_SESSION_ERROR_CODE = "errorCode";
     private static final String ATTR_MODE = "mode";
     private static final String ATTR_INSTALL_FLAGS = "installFlags";
     private static final String ATTR_INSTALL_LOCATION = "installLocation";
@@ -285,6 +292,8 @@
     private final List<String> mResolvedNativeLibPaths = new ArrayList<>();
     @GuardedBy("mLock")
     private File mInheritedFilesBase;
+    @GuardedBy("mLock")
+    private boolean mVerityFound;
 
     private static final FileFilter sAddedFilter = new FileFilter() {
         @Override
@@ -294,6 +303,7 @@
             if (file.isDirectory()) return false;
             if (file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
             if (DexMetadataHelper.isDexMetadataFile(file)) return false;
+            if (VerityUtils.isFsveritySignatureFile(file)) return false;
             return true;
         }
     };
@@ -402,7 +412,8 @@
             int sessionId, int userId,
             String installerPackageName, int installerUid, SessionParams params, long createdMillis,
             File stageDir, String stageCid, boolean prepared, boolean sealed,
-            @Nullable int[] childSessionIds, int parentSessionId) {
+            @Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
+            boolean isFailed, boolean isApplied, int stagedSessionErrorCode) {
         mCallback = callback;
         mContext = context;
         mPm = pm;
@@ -432,7 +443,10 @@
         }
 
         mPrepared = prepared;
-
+        mStagedSessionReady = isReady;
+        mStagedSessionFailed = isFailed;
+        mStagedSessionApplied = isApplied;
+        mStagedSessionErrorCode = stagedSessionErrorCode;
         if (sealed) {
             synchronized (mLock) {
                 try {
@@ -977,26 +991,21 @@
         mSealed = true;
 
         // Read transfers from the original owner stay open, but as the session's data
-        // cannot be modified anymore, there is no leak of information.
+        // cannot be modified anymore, there is no leak of information. For staged sessions,
+        // further validation is performed by the staging manager.
         if (!params.isMultiPackage) {
+            if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+                // For APEX, validation is done by StagingManager post-commit.
+                return;
+            }
             final PackageInfo pkgInfo = mPm.getPackageInfo(
                     params.appPackageName, PackageManager.GET_SIGNATURES
                             | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
 
             resolveStageDirLocked();
 
-            // Verify that stage looks sane with respect to existing application.
-            // This currently only ensures packageName, versionCode, and certificate
-            // consistency.
             try {
-                if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
-                    validateApexInstallLocked(pkgInfo);
-                } else {
-                    // Verify that stage looks sane with respect to existing application.
-                    // This currently only ensures packageName, versionCode, and certificate
-                    // consistency.
-                    validateApkInstallLocked(pkgInfo);
-                }
+                validateApkInstallLocked(pkgInfo);
             } catch (PackageManagerException e) {
                 throw e;
             } catch (Throwable e) {
@@ -1062,16 +1071,17 @@
     @GuardedBy("mLock")
     private void commitLocked()
             throws PackageManagerException {
+        if (params.isStaged) {
+            mStagingManager.commitSession(this);
+            destroyInternal();
+            dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
+            return;
+        }
         final PackageManagerService.ActiveInstallSession committingSession =
                 makeSessionActiveLocked();
         if (committingSession == null) {
             return;
         }
-        if (isStaged()) {
-            mStagingManager.commitSession(this);
-            dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
-            return;
-        }
         if (isMultiPackage()) {
             final int[] childSessionIds = getChildSessionIds();
             List<PackageManagerService.ActiveInstallSession> childSessions =
@@ -1286,57 +1296,6 @@
                 (params.installFlags & PackageManager.DONT_KILL_APP) != 0;
     }
 
-    @GuardedBy("mLock")
-    private void validateApexInstallLocked(@Nullable PackageInfo pkgInfo)
-            throws PackageManagerException {
-        mResolvedStagedFiles.clear();
-        mResolvedInheritedFiles.clear();
-
-        try {
-            resolveStageDirLocked();
-        } catch (IOException e) {
-            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
-                "Failed to resolve stage location", e);
-        }
-
-        final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
-        if (ArrayUtils.isEmpty(addedFiles)) {
-            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
-        }
-
-        if (addedFiles.length > 1) {
-            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
-                "Only one APEX file at a time might be installed");
-        }
-        File addedFile = addedFiles[0];
-        final ApkLite apk;
-        try {
-            apk = PackageParser.parseApkLite(
-                addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
-        } catch (PackageParserException e) {
-            throw PackageManagerException.from(e);
-        }
-
-        mPackageName = apk.packageName;
-        mVersionCode = apk.getLongVersionCode();
-        mSigningDetails = apk.signingDetails;
-        mResolvedBaseFile = addedFile;
-
-        assertApkConsistentLocked(String.valueOf(addedFile), apk);
-
-        if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
-            try {
-                // STOPSHIP: For APEX we should also implement proper APK Signature verification.
-                mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
-                    pkgInfo.applicationInfo.sourceDir,
-                    PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
-            } catch (PackageParserException e) {
-                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
-                    "Couldn't obtain signatures from base APK");
-            }
-        }
-    }
-
     /**
      * Validate install by confirming that all application packages are have
      * consistent package name, version code, and signing certificates.
@@ -1361,6 +1320,17 @@
         mResolvedStagedFiles.clear();
         mResolvedInheritedFiles.clear();
 
+        // Partial installs must be consistent with existing install
+        if (params.mode == SessionParams.MODE_INHERIT_EXISTING
+                && (pkgInfo == null || pkgInfo.applicationInfo == null)) {
+            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                    "Missing existing base package");
+        }
+        // Default to require only if existing base has fs-verity.
+        mVerityFound = PackageManagerServiceUtils.isApkVerityEnabled()
+                && params.mode == SessionParams.MODE_INHERIT_EXISTING
+                && VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath());
+
         try {
             resolveStageDirLocked();
         } catch (IOException e) {
@@ -1424,7 +1394,7 @@
             }
 
             final File targetFile = new File(mResolvedStageDir, targetName);
-            maybeRenameFile(addedFile, targetFile);
+            resolveAndStageFile(addedFile, targetFile);
 
             // Base is coming from session
             if (apk.splitName == null) {
@@ -1432,8 +1402,6 @@
                 baseApk = apk;
             }
 
-            mResolvedStagedFiles.add(targetFile);
-
             final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
             if (dexMetadataFile != null) {
                 if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
@@ -1442,8 +1410,7 @@
                 }
                 final File targetDexMetadataFile = new File(mResolvedStageDir,
                         DexMetadataHelper.buildDexMetadataPathForApk(targetName));
-                mResolvedStagedFiles.add(targetDexMetadataFile);
-                maybeRenameFile(dexMetadataFile, targetDexMetadataFile);
+                resolveAndStageFile(dexMetadataFile, targetDexMetadataFile);
             }
         }
 
@@ -1486,12 +1453,6 @@
             }
 
         } else {
-            // Partial installs must be consistent with existing install
-            if (pkgInfo == null || pkgInfo.applicationInfo == null) {
-                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
-                        "Missing existing base package for " + mPackageName);
-            }
-
             final PackageLite existing;
             final ApkLite existingBase;
             ApplicationInfo appInfo = pkgInfo.applicationInfo;
@@ -1611,6 +1572,39 @@
         }
     }
 
+    private void resolveAndStageFile(File origFile, File targetFile)
+            throws PackageManagerException {
+        mResolvedStagedFiles.add(targetFile);
+        maybeRenameFile(origFile, targetFile);
+
+        final File originalSignature = new File(
+                VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
+        // Make sure .fsv_sig exists when it should, then resolve and stage it.
+        if (originalSignature.exists()) {
+            // mVerityFound can only change from false to true here during the staging loop. Since
+            // all or none of files should have .fsv_sig, this should only happen in the first time
+            // (or never), otherwise bail out.
+            if (!mVerityFound) {
+                mVerityFound = true;
+                if (mResolvedStagedFiles.size() > 1) {
+                    throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
+                            "Some file is missing fs-verity signature");
+                }
+            }
+        } else {
+            if (!mVerityFound) {
+                return;
+            }
+            throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
+                    "Missing corresponding fs-verity signature to " + origFile);
+        }
+
+        final File stagedSignature = new File(
+                VerityUtils.getFsveritySignatureFilePath(targetFile.getPath()));
+        maybeRenameFile(originalSignature, stagedSignature);
+        mResolvedStagedFiles.add(stagedSignature);
+    }
+
     @GuardedBy("mLock")
     private void assertApkConsistentLocked(String tag, ApkLite apk)
             throws PackageManagerException {
@@ -1864,22 +1858,30 @@
     }
 
     @Override
-    public void addChildSessionId(int sessionId) {
-        final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
-        if (session == null) {
+    public void addChildSessionId(int childSessionId) {
+        final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId);
+        if (childSession == null) {
             throw new RemoteException("Unable to add child.",
-                    new PackageManagerException("Child session " + sessionId + " does not exist"),
+                    new PackageManagerException("Child session " + childSessionId
+                            + " does not exist"),
+                    false, true).rethrowAsRuntimeException();
+        }
+        // Session groups must be consistent wrt to isStaged parameter. Non-staging session
+        // cannot be grouped with staging sessions.
+        if (this.params.isStaged ^ childSession.params.isStaged) {
+            throw new RemoteException("Unable to add child.",
+                    new PackageManagerException("Child session " + childSessionId
+                            + " and parent session " + this.sessionId + " do not have consistent"
+                            + " staging session settings."),
                     false, true).rethrowAsRuntimeException();
         }
         synchronized (mLock) {
-            final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
+            final int indexOfSession = mChildSessionIds.indexOfKey(childSessionId);
             if (indexOfSession >= 0) {
                 return;
             }
-            session.setParentSessionId(this.sessionId);
-            // TODO: sanity check, if parent session is staged then child session should be
-            //       marked as staged.
-            addChildSessionIdInternal(sessionId);
+            childSession.setParentSessionId(this.sessionId);
+            addChildSessionIdInternal(childSessionId);
         }
     }
 
@@ -1962,6 +1964,7 @@
         mCallback.onSessionFinished(this, success);
     }
 
+    /** {@hide} */
     void setStagedSessionReady() {
         synchronized (mLock) {
             mStagedSessionReady = true;
@@ -1969,13 +1972,57 @@
             mStagedSessionFailed = false;
             mStagedSessionErrorCode = SessionInfo.NO_ERROR;
         }
+        mCallback.onStagedSessionChanged(this);
+    }
+
+    /** {@hide} */
+    void setStagedSessionFailed(@StagedSessionErrorCode int errorCode) {
+        synchronized (mLock) {
+            mStagedSessionReady = false;
+            mStagedSessionApplied = false;
+            mStagedSessionFailed = true;
+            mStagedSessionErrorCode = errorCode;
+        }
+        mCallback.onStagedSessionChanged(this);
+    }
+
+    /** {@hide} */
+    void setStagedSessionApplied() {
+        synchronized (mLock) {
+            mStagedSessionReady = false;
+            mStagedSessionApplied = true;
+            mStagedSessionFailed = false;
+            mStagedSessionErrorCode = SessionInfo.NO_ERROR;
+        }
+        mCallback.onStagedSessionChanged(this);
+    }
+
+    /** {@hide} */
+    boolean isStagedSessionReady() {
+        return mStagedSessionReady;
+    }
+
+    /** {@hide} */
+    boolean isStagedSessionApplied() {
+        return mStagedSessionApplied;
+    }
+
+    /** {@hide} */
+    boolean isStagedSessionFailed() {
+        return mStagedSessionFailed;
+    }
+
+    /** {@hide} */
+    @StagedSessionErrorCode int getStagedSessionErrorCode() {
+        return mStagedSessionErrorCode;
     }
 
     private void destroyInternal() {
         synchronized (mLock) {
             mSealed = true;
-            mDestroyed = true;
-
+            if (!params.isStaged) {
+                mDestroyed = true;
+            }
             // Force shut down all bridges
             for (RevocableFileDescriptor fd : mFds) {
                 fd.revoke();
@@ -1984,7 +2031,11 @@
                 bridge.forceClose();
             }
         }
-        if (stageDir != null) {
+        // For staged sessions, we don't delete the directory where the packages have been copied,
+        // since these packages are supposed to be read on reboot. StagingManager is in charge of
+        // deleting these dirs when the staged session has reached a final state.
+        // TODO(b/118865310): Implement packageDir deletion in StagingManager.
+        if (stageDir != null && !params.isStaged) {
             try {
                 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
             } catch (InstallerException ignored) {
@@ -2078,6 +2129,10 @@
 
             writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
             writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged);
+            writeBooleanAttribute(out, ATTR_IS_READY, mStagedSessionReady);
+            writeBooleanAttribute(out, ATTR_IS_FAILED, mStagedSessionFailed);
+            writeBooleanAttribute(out, ATTR_IS_APPLIED, mStagedSessionApplied);
+            writeIntAttribute(out, ATTR_STAGED_SESSION_ERROR_CODE, mStagedSessionErrorCode);
             // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after
             //                       we've read all sessions.
             writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId);
@@ -2126,33 +2181,14 @@
         out.endTag(null, TAG_SESSION);
     }
 
-    private static String[] readGrantedRuntimePermissions(XmlPullParser in)
-            throws IOException, XmlPullParserException {
-        List<String> permissions = null;
-
-        final int outerDepth = in.getDepth();
-        int type;
-        while ((type = in.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-            if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
-                String permission = readStringAttribute(in, ATTR_NAME);
-                if (permissions == null) {
-                    permissions = new ArrayList<>();
-                }
-                permissions.add(permission);
-            }
-        }
-
-        if (permissions == null) {
-            return null;
-        }
-
-        String[] permissionsArray = new String[permissions.size()];
-        permissions.toArray(permissionsArray);
-        return permissionsArray;
+    // Sanity check to be performed when the session is restored from an external file. Only one
+    // of the session states should be true, or none of them.
+    private static boolean isStagedSessionStateValid(boolean isReady, boolean isApplied,
+                                                     boolean isFailed) {
+        return (!isReady && !isApplied && !isFailed)
+                || (isReady && !isApplied && !isFailed)
+                || (!isReady && isApplied && !isFailed)
+                || (!isReady && !isApplied && isFailed);
     }
 
     /**
@@ -2168,8 +2204,6 @@
      * @param sessionProvider
      * @return The newly created session
      */
-    // TODO(patb,109941548): modify readFromXml to consume to the next tag session tag so we
-    //                       can have a complete session for the constructor
     public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
             @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
             @NonNull PackageManagerService pm, Looper installerThread,
@@ -2209,17 +2243,60 @@
         params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
         params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
 
-        params.grantedRuntimePermissions = readGrantedRuntimePermissions(in);
-
         final File appIconFile = buildAppIconFile(sessionId, sessionsDir);
         if (appIconFile.exists()) {
             params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
             params.appIconLastModified = appIconFile.lastModified();
         }
+        final boolean isReady = readBooleanAttribute(in, ATTR_IS_READY);
+        final boolean isFailed = readBooleanAttribute(in, ATTR_IS_FAILED);
+        final boolean isApplied = readBooleanAttribute(in, ATTR_IS_APPLIED);
+        final int stagedSessionErrorCode = readIntAttribute(in, ATTR_STAGED_SESSION_ERROR_CODE,
+                SessionInfo.NO_ERROR);
+
+        if (!isStagedSessionStateValid(isReady, isApplied, isFailed)) {
+            throw new IllegalArgumentException("Can't restore staged session with invalid state.");
+        }
+
+        // Parse sub tags of this session, typically used for repeated values / arrays.
+        // Sub tags can come in any order, therefore we need to keep track of what we find while
+        // parsing and only set the right values at the end.
+
+        // Store the current depth. We should stop parsing when we reach an end tag at the same
+        // depth.
+        List<String> permissions = new ArrayList<>();
+        List<Integer> childSessionIds = new ArrayList<>();
+        int outerDepth = in.getDepth();
+        int type;
+        while ((type = in.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
+                permissions.add(readStringAttribute(in, ATTR_NAME));
+            }
+            if (TAG_CHILD_SESSION.equals(in.getName())) {
+                childSessionIds.add(readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID));
+            }
+        }
+
+        if (permissions.size() > 0) {
+            params.grantedRuntimePermissions = permissions.stream().toArray(String[]::new);
+        }
+
+        int[] childSessionIdsArray;
+        if (childSessionIds.size() > 0) {
+            childSessionIdsArray = childSessionIds.stream().mapToInt(i -> i).toArray();
+        } else {
+            childSessionIdsArray = EMPTY_CHILD_SESSION_ARRAY;
+        }
+
         return new PackageInstallerSession(callback, context, pm, sessionProvider,
                 installerThread, stagingManager, sessionId, userId, installerPackageName,
                 installerUid, params, createdMillis, stageDir, stageCid, prepared, sealed,
-                EMPTY_CHILD_SESSION_ARRAY, parentSessionId);
+                childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied,
+                stagedSessionErrorCode);
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 136c7c9..9100f6a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -42,6 +42,7 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
+import static android.content.pm.PackageManager.INSTALL_ALLOW_DOWNGRADE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
@@ -84,6 +85,7 @@
 import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.RESTRICTION_NONE;
 import static android.content.pm.PackageParser.isApkFile;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
@@ -200,6 +202,7 @@
 import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.dex.IArtManager;
+import android.content.rollback.IRollbackManager;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
@@ -238,6 +241,7 @@
 import android.os.storage.StorageManagerInternal;
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
+import android.permission.PermissionControllerManager;
 import android.provider.MediaStore;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
@@ -309,6 +313,7 @@
 import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.DexoptOptions;
 import com.android.server.pm.dex.PackageDexUsage;
+import com.android.server.pm.dex.ViewCompiler;
 import com.android.server.pm.permission.BasePermission;
 import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
 import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
@@ -316,7 +321,6 @@
 import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionsState;
-import com.android.server.pm.permission.PermissionsState.PermissionState;
 import com.android.server.security.VerityUtils;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
@@ -369,6 +373,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -442,6 +447,11 @@
     private static final boolean ENABLE_FREE_CACHE_V2 =
             SystemProperties.getBoolean("fw.free_cache_v2", true);
 
+    private static final long BACKUP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(60);
+
+    private static final boolean PRECOMPILED_LAYOUT_ENABLED =
+            SystemProperties.getBoolean("view.precompiled_layout_enabled", false);
+
     private static final int RADIO_UID = Process.PHONE_UID;
     private static final int LOG_UID = Process.LOG_UID;
     private static final int NFC_UID = Process.NFC_UID;
@@ -884,6 +894,8 @@
     // is used by other apps).
     private final DexManager mDexManager;
 
+    private final ViewCompiler mViewCompiler;
+
     private AtomicInteger mNextMoveId = new AtomicInteger();
     private final MoveCallbacks mMoveCallbacks;
 
@@ -1338,6 +1350,8 @@
     final @Nullable String mSystemTextClassifierPackage;
     final @Nullable String mWellbeingPackage;
     final @Nullable String mDocumenterPackage;
+    final @Nullable String mConfiguratorPackage;
+    final @Nullable String mAppPredictionServicePackage;
     final @NonNull String mServicesSystemSharedLibraryPackageName;
     final @NonNull String mSharedSystemSharedLibraryPackageName;
 
@@ -1454,8 +1468,9 @@
                             Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
                                     args.traceCookie);
                         }
-                    } else {
-                        Slog.e(TAG, "Bogus post-install token " + msg.arg1);
+                    } else if (DEBUG_INSTALL) {
+                        // No post-install when we run restore from installExistingPackageForUser
+                        Slog.i(TAG, "Nothing to do for post-install token " + msg.arg1);
                     }
 
                     Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
@@ -2255,6 +2270,8 @@
         mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
         mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
 
+        mViewCompiler = new ViewCompiler(mInstallLock, mInstaller);
+
         mOnPermissionChangeListeners = new OnPermissionChangeListeners(
                 FgThread.get().getLooper());
 
@@ -2861,6 +2878,9 @@
 
             mWellbeingPackage = getWellbeingPackageName();
             mDocumenterPackage = getDocumenterPackageName();
+            mConfiguratorPackage =
+                    mContext.getString(R.string.config_deviceConfiguratorPackageName);
+            mAppPredictionServicePackage = getAppPredictionServicePackageName();
 
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
@@ -3743,7 +3763,7 @@
     /**
      * Returns whether or not a full application can see an instant application.
      * <p>
-     * Currently, there are three cases in which this can occur:
+     * Currently, there are four cases in which this can occur:
      * <ol>
      * <li>The calling application is a "special" process. Special processes
      *     are those with a UID < {@link Process#FIRST_APPLICATION_UID}.</li>
@@ -3751,6 +3771,7 @@
      *     {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.</li>
      * <li>The calling application is the default launcher on the
      *     system partition.</li>
+     * <li>The calling application is the default app prediction service.</li>
      * </ol>
      */
     private boolean canViewInstantApps(int callingUid, int userId) {
@@ -3768,6 +3789,11 @@
                     && isCallerSameApp(homeComponent.getPackageName(), callingUid)) {
                 return true;
             }
+            // TODO(b/122900055) Change/Remove this and replace with new permission role.
+            if (mAppPredictionServicePackage != null
+                    && isCallerSameApp(mAppPredictionServicePackage, callingUid)) {
+                return true;
+            }
         }
         return false;
     }
@@ -5483,13 +5509,13 @@
         final int callingUserId = UserHandle.getUserId(callingUid);
         final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
         // Map to base uids.
-        uid1 = UserHandle.getAppId(uid1);
-        uid2 = UserHandle.getAppId(uid2);
+        final int appId1 = UserHandle.getAppId(uid1);
+        final int appId2 = UserHandle.getAppId(uid2);
         // reader
         synchronized (mPackages) {
             Signature[] s1;
             Signature[] s2;
-            Object obj = mSettings.getSettingLPr(uid1);
+            Object obj = mSettings.getSettingLPr(appId1);
             if (obj != null) {
                 if (obj instanceof SharedUserSetting) {
                     if (isCallerInstantApp) {
@@ -5508,7 +5534,7 @@
             } else {
                 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
             }
-            obj = mSettings.getSettingLPr(uid2);
+            obj = mSettings.getSettingLPr(appId2);
             if (obj != null) {
                 if (obj instanceof SharedUserSetting) {
                     if (isCallerInstantApp) {
@@ -5563,11 +5589,11 @@
         final int callingUid = Binder.getCallingUid();
         final int callingUserId = UserHandle.getUserId(callingUid);
         // Map to base uids.
-        uid = UserHandle.getAppId(uid);
+        final int appId = UserHandle.getAppId(uid);
         // reader
         synchronized (mPackages) {
             final PackageParser.SigningDetails signingDetails;
-            final Object obj = mSettings.getSettingLPr(uid);
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj != null) {
                 if (obj instanceof SharedUserSetting) {
                     final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
@@ -5683,10 +5709,10 @@
         final int callingUid = Binder.getCallingUid();
         final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
         final int userId = UserHandle.getUserId(uid);
-        uid = UserHandle.getAppId(uid);
+        final int appId = UserHandle.getAppId(uid);
         // reader
         synchronized (mPackages) {
-            Object obj = mSettings.getSettingLPr(uid);
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj instanceof SharedUserSetting) {
                 if (isCallerInstantApp) {
                     return null;
@@ -5721,8 +5747,9 @@
         if (getInstantAppPackageName(callingUid) != null) {
             return null;
         }
+        final int appId = UserHandle.getAppId(uid);
         synchronized (mPackages) {
-            Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj instanceof SharedUserSetting) {
                 final SharedUserSetting sus = (SharedUserSetting) obj;
                 return sus.name + ":" + sus.userId;
@@ -5749,8 +5776,8 @@
         final String[] names = new String[uids.length];
         synchronized (mPackages) {
             for (int i = uids.length - 1; i >= 0; i--) {
-                final int uid = uids[i];
-                Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+                final int appId = UserHandle.getAppId(uids[i]);
+                final Object obj = mSettings.getSettingLPr(appId);
                 if (obj instanceof SharedUserSetting) {
                     final SharedUserSetting sus = (SharedUserSetting) obj;
                     names[i] = "shared:" + sus.name;
@@ -5798,8 +5825,9 @@
         if (getInstantAppPackageName(callingUid) != null) {
             return 0;
         }
+        final int appId = UserHandle.getAppId(uid);
         synchronized (mPackages) {
-            Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj instanceof SharedUserSetting) {
                 final SharedUserSetting sus = (SharedUserSetting) obj;
                 return sus.pkgFlags;
@@ -5820,8 +5848,9 @@
         if (getInstantAppPackageName(callingUid) != null) {
             return 0;
         }
+        final int appId = UserHandle.getAppId(uid);
         synchronized (mPackages) {
-            Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj instanceof SharedUserSetting) {
                 final SharedUserSetting sus = (SharedUserSetting) obj;
                 return sus.pkgPrivateFlags;
@@ -5841,10 +5870,10 @@
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return false;
         }
-        uid = UserHandle.getAppId(uid);
+        final int appId = UserHandle.getAppId(uid);
         // reader
         synchronized (mPackages) {
-            Object obj = mSettings.getSettingLPr(uid);
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj instanceof SharedUserSetting) {
                 final SharedUserSetting sus = (SharedUserSetting) obj;
                 final Iterator<PackageSetting> it = sus.packages.iterator();
@@ -7865,8 +7894,13 @@
                 if (apex != null) {
                     try {
                         final ApexInfo[] activePkgs = apex.getActivePackages();
-                        for (ApexInfo apexInfo : activePkgs) {
-                            list.add(new PackageInfo(apexInfo));
+                        for (ApexInfo ai : activePkgs) {
+                            try {
+                                 list.add(PackageParser.generatePackageInfoFromApex(
+                                         new File(ai.packagePath), true /* collect certs */));
+                            } catch (PackageParserException pe) {
+                                 throw new IllegalStateException("Unable to parse: " + ai, pe);
+                            }
                         }
                     } catch (RemoteException e) {
                         Log.e(TAG, "Unable to retrieve packages from apexservice: " + e.toString());
@@ -8549,16 +8583,16 @@
     }
 
     /**
-     * Returns if full apk verification can be skipped for the whole package, including the splits.
+     * Returns if forced apk verification can be skipped for the whole package, including splits.
      */
-    private boolean canSkipFullPackageVerification(PackageParser.Package pkg) {
-        if (!canSkipFullApkVerification(pkg.baseCodePath)) {
+    private boolean canSkipForcedPackageVerification(PackageParser.Package pkg) {
+        if (!canSkipForcedApkVerification(pkg.baseCodePath)) {
             return false;
         }
         // TODO: Allow base and splits to be verified individually.
         if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
             for (int i = 0; i < pkg.splitCodePaths.length; i++) {
-                if (!canSkipFullApkVerification(pkg.splitCodePaths[i])) {
+                if (!canSkipForcedApkVerification(pkg.splitCodePaths[i])) {
                     return false;
                 }
             }
@@ -8567,14 +8601,17 @@
     }
 
     /**
-     * Returns if full apk verification can be skipped, depending on current FSVerity setup and
+     * Returns if forced apk verification can be skipped, depending on current FSVerity setup and
      * whether the apk contains signed root hash.  Note that the signer's certificate still needs to
      * match one in a trusted source, and should be done separately.
      */
-    private boolean canSkipFullApkVerification(String apkPath) {
-        final byte[] rootHashObserved;
+    private boolean canSkipForcedApkVerification(String apkPath) {
+        if (!PackageManagerServiceUtils.isLegacyApkVerityEnabled()) {
+            return VerityUtils.hasFsverity(apkPath);
+        }
+
         try {
-            rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath);
+            final byte[] rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath);
             if (rootHashObserved == null) {
                 return false;  // APK does not contain Merkle tree root hash.
             }
@@ -8746,7 +8783,7 @@
         // in verified partition, or can be verified on access (when apk verity is enabled). In both
         // cases, only data in Signing Block is verified instead of the whole file.
         final boolean skipVerify = scanSystemPartition
-                || (forceCollect && canSkipFullPackageVerification(pkg));
+                || (forceCollect && canSkipForcedPackageVerification(pkg));
         collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);
 
         // Reset profile if the application version is changed
@@ -9082,6 +9119,10 @@
                 pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
             }
 
+            if (PRECOMPILED_LAYOUT_ENABLED) {
+                mArtManagerService.compileLayouts(pkg);
+            }
+
             // checkProfiles is false to avoid merging profiles during boot which
             // might interfere with background compilation (b/28612421).
             // Unfortunately this will also means that "pm.dexopt.boot=speed-profile" will
@@ -9226,6 +9267,21 @@
         return performDexOpt(new DexoptOptions(packageName, compilerFilter, flags));
     }
 
+    /**
+    * Ask the package manager to compile layouts in the given package.
+    */
+    @Override
+    public boolean compileLayouts(String packageName) {
+        PackageParser.Package pkg;
+        synchronized (mPackages) {
+            pkg = mPackages.get(packageName);
+            if (pkg == null) {
+                return false;
+            }
+        }
+        return mViewCompiler.compileLayouts(pkg);
+    }
+
     /*package*/ boolean performDexOpt(DexoptOptions options) {
         if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
             return false;
@@ -10518,8 +10574,6 @@
                 Log.d(TAG, "Scanning package " + pkg.packageName);
         }
 
-        DexManager.maybeLogUnexpectedPackageDetails(pkg);
-
         // Initialize package source and resource directories
         final File scanFile = new File(pkg.codePath);
         final File destCodeFile = new File(pkg.applicationInfo.getCodePath());
@@ -12654,22 +12708,30 @@
         info.sendPackageRemovedBroadcasts(true /*killApp*/);
     }
 
+    private void sendDistractingPackagesChanged(String[] pkgList, int[] uidList, int userId,
+            int distractionFlags) {
+        final Bundle extras = new Bundle(3);
+        extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
+        extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
+        extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, distractionFlags);
+        sendPackageBroadcast(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED, null, extras,
+                Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null, new int[]{userId}, null);
+    }
+
     private void sendPackagesSuspendedForUser(String[] pkgList, int[] uidList, int userId,
             boolean suspended, PersistableBundle launcherExtras) {
-        if (pkgList.length > 0) {
-            Bundle extras = new Bundle(1);
-            extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
-            extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
-            if (launcherExtras != null) {
-                extras.putBundle(Intent.EXTRA_LAUNCHER_EXTRAS,
-                        new Bundle(launcherExtras.deepCopy()));
-            }
-            sendPackageBroadcast(
-                    suspended ? Intent.ACTION_PACKAGES_SUSPENDED
-                            : Intent.ACTION_PACKAGES_UNSUSPENDED,
-                    null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null,
-                    new int[] {userId}, null);
+        final Bundle extras = new Bundle(3);
+        extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
+        extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
+        if (launcherExtras != null) {
+            extras.putBundle(Intent.EXTRA_LAUNCHER_EXTRAS,
+                    new Bundle(launcherExtras.deepCopy()));
         }
+        sendPackageBroadcast(
+                suspended ? Intent.ACTION_PACKAGES_SUSPENDED
+                        : Intent.ACTION_PACKAGES_UNSUSPENDED,
+                null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null,
+                new int[] {userId}, null);
     }
 
     /**
@@ -12708,6 +12770,11 @@
     @Override
     public int installExistingPackageAsUser(String packageName, int userId, int installFlags,
             int installReason) {
+        if (DEBUG_INSTALL) {
+            Log.v(TAG, "installExistingPackageAsUser package=" + packageName + " userId=" + userId
+                    + " installFlags=" + installFlags + " installReason=" + installReason);
+        }
+
         final int callingUid = Binder.getCallingUid();
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES)
                 != PackageManager.PERMISSION_GRANTED
@@ -12778,6 +12845,11 @@
                 synchronized (mPackages) {
                     updateSequenceNumberLP(pkgSetting, new int[]{ userId });
                 }
+                // start async restore with no post-install since we finish install here
+                PackageInstalledInfo res =
+                        createPackageInstalledInfo(PackageManager.INSTALL_SUCCEEDED);
+                res.pkg = pkgSetting.pkg;
+                restoreAndPostInstall(userId, res, null);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -12819,6 +12891,62 @@
     }
 
     @Override
+    public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames,
+            int restrictionFlags, int userId) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS,
+                "setPackagesSuspendedAsUser");
+
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.ROOT_UID && callingUid != Process.SYSTEM_UID
+                && UserHandle.getUserId(callingUid) != userId) {
+            throw new SecurityException("Calling uid " + callingUid + " cannot call for user "
+                    + userId);
+        }
+        Preconditions.checkNotNull(packageNames, "packageNames cannot be null");
+
+        final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
+        final IntArray changedUids = new IntArray(packageNames.length);
+        final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
+
+        for (int i = 0; i < packageNames.length; i++) {
+            final String packageName = packageNames[i];
+            final PackageSetting pkgSetting;
+            synchronized (mPackages) {
+                pkgSetting = mSettings.mPackages.get(packageName);
+                if (pkgSetting == null || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+                    Slog.w(TAG, "Could not find package setting for package: " + packageName
+                            + ". Skipping...");
+                    unactionedPackages.add(packageName);
+                    continue;
+                }
+            }
+            if (restrictionFlags != 0 && !canSuspendPackageForUserInternal(packageName, userId)) {
+                unactionedPackages.add(packageName);
+                continue;
+            }
+            synchronized (mPackages) {
+                final int oldDistractionFlags = pkgSetting.getDistractionFlags(userId);
+                if (restrictionFlags != oldDistractionFlags) {
+                    pkgSetting.setDistractionFlags(restrictionFlags, userId);
+                    changedPackagesList.add(packageName);
+                    changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
+                }
+            }
+        }
+
+        if (!changedPackagesList.isEmpty()) {
+            final String[] changedPackages = changedPackagesList.toArray(
+                    new String[changedPackagesList.size()]);
+            sendDistractingPackagesChanged(changedPackages, changedUids.toArray(), userId,
+                    restrictionFlags);
+            synchronized (mPackages) {
+                scheduleWritePackageRestrictionsLocked(userId);
+            }
+        }
+        return unactionedPackages.toArray(new String[0]);
+    }
+
+    @Override
     public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
             PersistableBundle appExtras, PersistableBundle launcherExtras,
             SuspendDialogInfo dialogInfo, String callingPackage, int userId) {
@@ -12843,44 +12971,37 @@
         final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
         final IntArray changedUids = new IntArray(packageNames.length);
         final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
-        final long callingId = Binder.clearCallingIdentity();
-        try {
-            for (int i = 0; i < packageNames.length; i++) {
-                final String packageName = packageNames[i];
-                if (callingPackage.equals(packageName)) {
-                    Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
-                            + (suspended ? "" : "un") + "suspend itself. Ignoring");
-                    unactionedPackages.add(packageName);
-                    continue;
-                }
-                PackageSetting pkgSetting;
-                synchronized (mPackages) {
-                    pkgSetting = mSettings.mPackages.get(packageName);
-                    if (pkgSetting == null
-                            || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
-                        Slog.w(TAG, "Could not find package setting for package: " + packageName
-                                + ". Skipping suspending/un-suspending.");
-                        unactionedPackages.add(packageName);
-                        continue;
-                    }
-                }
-                if (suspended && !canSuspendPackageForUserInternal(packageName, userId)) {
-                    unactionedPackages.add(packageName);
-                    continue;
-                }
-                synchronized (mPackages) {
-                    pkgSetting = mSettings.mPackages.get(packageName);
-                    if (pkgSetting != null) {
-                        pkgSetting.setSuspended(suspended, callingPackage, dialogInfo, appExtras,
-                                launcherExtras, userId);
-                    }
-                }
-                changedPackagesList.add(packageName);
-                changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
+
+        for (int i = 0; i < packageNames.length; i++) {
+            final String packageName = packageNames[i];
+            if (callingPackage.equals(packageName)) {
+                Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
+                        + (suspended ? "" : "un") + "suspend itself. Ignoring");
+                unactionedPackages.add(packageName);
+                continue;
             }
-        } finally {
-            Binder.restoreCallingIdentity(callingId);
+            final PackageSetting pkgSetting;
+            synchronized (mPackages) {
+                pkgSetting = mSettings.mPackages.get(packageName);
+                if (pkgSetting == null || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+                    Slog.w(TAG, "Could not find package setting for package: " + packageName
+                            + ". Skipping suspending/un-suspending.");
+                    unactionedPackages.add(packageName);
+                    continue;
+                }
+            }
+            if (suspended && !canSuspendPackageForUserInternal(packageName, userId)) {
+                unactionedPackages.add(packageName);
+                continue;
+            }
+            synchronized (mPackages) {
+                pkgSetting.setSuspended(suspended, callingPackage, dialogInfo, appExtras,
+                        launcherExtras, userId);
+            }
+            changedPackagesList.add(packageName);
+            changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
         }
+
         if (!changedPackagesList.isEmpty()) {
             final String[] changedPackages = changedPackagesList.toArray(
                     new String[changedPackagesList.size()]);
@@ -13032,88 +13153,87 @@
                     + " cannot query getUnsuspendablePackagesForUser for user " + userId);
         }
         final ArraySet<String> unactionablePackages = new ArraySet<>();
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            for (String packageName : packageNames) {
-                if (!canSuspendPackageForUserInternal(packageName, userId)) {
-                    unactionablePackages.add(packageName);
-                }
+        for (String packageName : packageNames) {
+            if (!canSuspendPackageForUserInternal(packageName, userId)) {
+                unactionablePackages.add(packageName);
             }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
         }
         return unactionablePackages.toArray(new String[unactionablePackages.size()]);
     }
 
     private boolean canSuspendPackageForUserInternal(String packageName, int userId) {
-        if (isPackageDeviceAdmin(packageName, userId)) {
-            Slog.w(TAG, "Cannot suspend package \"" + packageName
-                    + "\": has an active device admin");
-            return false;
-        }
-
-        String activeLauncherPackageName = getActiveLauncherPackageName(userId);
-        if (packageName.equals(activeLauncherPackageName)) {
-            Slog.w(TAG, "Cannot suspend package \"" + packageName
-                    + "\": contains the active launcher");
-            return false;
-        }
-
-        if (packageName.equals(mRequiredInstallerPackage)) {
-            Slog.w(TAG, "Cannot suspend package \"" + packageName
-                    + "\": required for package installation");
-            return false;
-        }
-
-        if (packageName.equals(mRequiredUninstallerPackage)) {
-            Slog.w(TAG, "Cannot suspend package \"" + packageName
-                    + "\": required for package uninstallation");
-            return false;
-        }
-
-        if (packageName.equals(mRequiredVerifierPackage)) {
-            Slog.w(TAG, "Cannot suspend package \"" + packageName
-                    + "\": required for package verification");
-            return false;
-        }
-
-        if (packageName.equals(getDefaultDialerPackageName(userId))) {
-            Slog.w(TAG, "Cannot suspend package \"" + packageName
-                    + "\": is the default dialer");
-            return false;
-        }
-
-        if (packageName.equals(mRequiredPermissionControllerPackage)) {
-            Slog.w(TAG, "Cannot suspend package \"" + packageName
-                    + "\": required for permissions management");
-            return false;
-        }
-
-        synchronized (mPackages) {
-            if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+        final long callingId = Binder.clearCallingIdentity();
+        try {
+            if (isPackageDeviceAdmin(packageName, userId)) {
                 Slog.w(TAG, "Cannot suspend package \"" + packageName
-                        + "\": protected package");
+                        + "\": has an active device admin");
                 return false;
             }
 
-            // Cannot suspend static shared libs as they are considered
-            // a part of the using app (emulating static linking). Also
-            // static libs are installed always on internal storage.
-            PackageParser.Package pkg = mPackages.get(packageName);
-            if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
-                Slog.w(TAG, "Cannot suspend package: " + packageName
-                        + " providing static shared library: "
-                        + pkg.staticSharedLibName);
+            String activeLauncherPackageName = getActiveLauncherPackageName(userId);
+            if (packageName.equals(activeLauncherPackageName)) {
+                Slog.w(TAG, "Cannot suspend package \"" + packageName
+                        + "\": contains the active launcher");
                 return false;
             }
-        }
 
-        if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
-            Slog.w(TAG, "Cannot suspend the platform package: " + packageName);
-            return false;
-        }
+            if (packageName.equals(mRequiredInstallerPackage)) {
+                Slog.w(TAG, "Cannot suspend package \"" + packageName
+                        + "\": required for package installation");
+                return false;
+            }
 
-        return true;
+            if (packageName.equals(mRequiredUninstallerPackage)) {
+                Slog.w(TAG, "Cannot suspend package \"" + packageName
+                        + "\": required for package uninstallation");
+                return false;
+            }
+
+            if (packageName.equals(mRequiredVerifierPackage)) {
+                Slog.w(TAG, "Cannot suspend package \"" + packageName
+                        + "\": required for package verification");
+                return false;
+            }
+
+            if (packageName.equals(getDefaultDialerPackageName(userId))) {
+                Slog.w(TAG, "Cannot suspend package \"" + packageName
+                        + "\": is the default dialer");
+                return false;
+            }
+
+            if (packageName.equals(mRequiredPermissionControllerPackage)) {
+                Slog.w(TAG, "Cannot suspend package \"" + packageName
+                        + "\": required for permissions management");
+                return false;
+            }
+
+            synchronized (mPackages) {
+                if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+                    Slog.w(TAG, "Cannot suspend package \"" + packageName
+                            + "\": protected package");
+                    return false;
+                }
+
+                // Cannot suspend static shared libs as they are considered
+                // a part of the using app (emulating static linking). Also
+                // static libs are installed always on internal storage.
+                PackageParser.Package pkg = mPackages.get(packageName);
+                if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
+                    Slog.w(TAG, "Cannot suspend package: " + packageName
+                            + " providing static shared library: "
+                            + pkg.staticSharedLibName);
+                    return false;
+                }
+            }
+
+            if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
+                Slog.w(TAG, "Cannot suspend the platform package: " + packageName);
+                return false;
+            }
+            return true;
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
     }
 
     private String getActiveLauncherPackageName(int userId) {
@@ -13559,7 +13679,8 @@
             }
 
             Signature[] callerSignature;
-            Object obj = mSettings.getSettingLPr(callingUid);
+            final int appId = UserHandle.getAppId(callingUid);
+            final Object obj = mSettings.getSettingLPr(appId);
             if (obj != null) {
                 if (obj instanceof SharedUserSetting) {
                     callerSignature =
@@ -13668,8 +13789,8 @@
                 }
             }
             for (InstallRequest request : installRequests) {
-                resolvePackageInstalledInfo(request.args,
-                        request.installResult);
+                restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
+                        new PostInstallData(request.args, request.installResult));
             }
         });
     }
@@ -13684,7 +13805,14 @@
         return res;
     }
 
-    private void resolvePackageInstalledInfo(InstallArgs args, PackageInstalledInfo res) {
+    /** @param data Post-install is performed only if this is non-null. */
+    private void restoreAndPostInstall(
+            int userId, PackageInstalledInfo res, @Nullable PostInstallData data) {
+        if (DEBUG_INSTALL) {
+            Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package="
+                    + res.pkg.packageName);
+        }
+
         // A restore should be performed at this point if (a) the install
         // succeeded, (b) the operation is not an update, and (c) the new
         // package has not opted out of backup participation.
@@ -13700,9 +13828,12 @@
         int token;
         if (mNextInstallToken < 0) mNextInstallToken = 1;
         token = mNextInstallToken++;
+        if (data != null) {
+            mRunningInstalls.put(token, data);
+        } else if (DEBUG_INSTALL) {
+            Log.v(TAG, "No post-install required for " + token);
+        }
 
-        PostInstallData data = new PostInstallData(args, res);
-        mRunningInstalls.put(token, data);
         if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
 
         if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
@@ -13713,14 +13844,19 @@
             IBackupManager bm = IBackupManager.Stub.asInterface(
                     ServiceManager.getService(Context.BACKUP_SERVICE));
             if (bm != null) {
+                // For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM
+                // in the BackupManager. USER_ALL is used in compatibility tests.
+                if (userId == UserHandle.USER_ALL) {
+                    userId = UserHandle.USER_SYSTEM;
+                }
                 if (DEBUG_INSTALL) {
-                    Log.v(TAG, "token " + token + " to BM for possible restore");
+                    Log.v(TAG, "token " + token + " to BM for possible restore for user " + userId);
                 }
                 Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
                 try {
-                    // TODO: http://b/22388012
-                    if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
-                        bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
+                    if (bm.isBackupServiceActive(userId)) {
+                        bm.restoreAtInstallForUser(
+                                userId, res.pkg.applicationInfo.packageName, token);
                     } else {
                         doRestore = false;
                     }
@@ -13736,6 +13872,38 @@
             }
         }
 
+        // If this is an update to a package that might be potentially downgraded, then we
+        // need to check with the rollback manager whether there's any userdata that might
+        // need to be restored for the package.
+        //
+        // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL.
+        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
+            IRollbackManager rm = IRollbackManager.Stub.asInterface(
+                    ServiceManager.getService(Context.ROLLBACK_SERVICE));
+
+            final String packageName = res.pkg.applicationInfo.packageName;
+            final String seInfo = res.pkg.applicationInfo.seInfo;
+            final PackageSetting ps;
+            int appId = -1;
+            long ceDataInode = -1;
+            synchronized (mSettings) {
+                ps = mSettings.getPackageLPr(packageName);
+                if (ps != null) {
+                    appId = ps.appId;
+                    ceDataInode = ps.getCeDataInode(userId);
+                }
+            }
+
+            if (ps != null) {
+                try {
+                    rm.restoreUserData(packageName, userId, appId, ceDataInode, seInfo, token);
+                } catch (RemoteException re) {
+                    // Cannot happen, the RollbackManager is hosted in the same process.
+                }
+                doRestore = true;
+            }
+        }
+
         if (!doRestore) {
             // No restore possible, or the Backup Manager was mysteriously not
             // available -- just fire the post-install work request directly.
@@ -14433,6 +14601,9 @@
                     enableRollbackIntent.putExtra(
                             PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS,
                             installFlags);
+                    enableRollbackIntent.putExtra(
+                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS,
+                            resolveUserIds(args.user.getIdentifier()));
                     enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
                             PACKAGE_MIME_TYPE);
                     enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
@@ -15615,13 +15786,25 @@
         if (!hasDynamicLibraries) {
             return null;
         }
+        final boolean isUpdatedSystemApp = pkg.isUpdatedSystemApp();
+        // We may not yet have disabled the updated package yet, so be sure to grab the
+        // current setting if that's the case.
+        final PackageSetting updatedSystemPs = isUpdatedSystemApp
+                ? scanResult.request.disabledPkgSetting == null
+                        ? scanResult.request.oldPkgSetting
+                        : scanResult.request.disabledPkgSetting
+                : null;
+        if (isUpdatedSystemApp && (updatedSystemPs.pkg == null
+                || updatedSystemPs.pkg.libraryNames == null)) {
+            Slog.w(TAG, "Package " + pkg.packageName + " declares libraries that are not "
+                    + "declared on the system image; skipping");
+            return null;
+        }
         final ArrayList<SharedLibraryInfo> infos =
                 new ArrayList<>(scanResult.dynamicSharedLibraryInfos.size());
-        final boolean updatedSystemApp = pkg.isUpdatedSystemApp();
         for (SharedLibraryInfo info : scanResult.dynamicSharedLibraryInfos) {
-            String name = info.getName();
-            boolean allowed = false;
-            if (updatedSystemApp) {
+            final String name = info.getName();
+            if (isUpdatedSystemApp) {
                 // New library entries can only be added through the
                 // system image.  This is important to get rid of a lot
                 // of nasty edge cases: for example if we allowed a non-
@@ -15631,36 +15814,20 @@
                 // have allowed apps on the device which aren't compatible
                 // with it.  Better to just have the restriction here, be
                 // conservative, and create many fewer cases that can negatively
-                // impact the user experience. We may not yet have disabled the
-                // updated package yet, so be sure to grab the current setting if
-                // that's the case.
-                final PackageSetting sysPs = scanResult.request.disabledPkgSetting == null
-                        ? scanResult.request.oldPkgSetting
-                        : scanResult.request.disabledPkgSetting;
-                if (sysPs.pkg != null && sysPs.pkg.libraryNames != null) {
-                    for (int j = 0; j < sysPs.pkg.libraryNames.size(); j++) {
-                        if (name.equals(sysPs.pkg.libraryNames.get(j))) {
-                            allowed = true;
-                            break;
-                        }
-                    }
-                }
-            } else {
-                allowed = true;
-            }
-            if (allowed) {
-                if (sharedLibExists(
-                        name, SharedLibraryInfo.VERSION_UNDEFINED, existingSharedLibraries)) {
-                    Slog.w(TAG, "Package " + pkg.packageName + " library "
-                            + name + " already exists; skipping");
+                // impact the user experience.
+                if (!updatedSystemPs.pkg.libraryNames.contains(name)) {
+                    Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name
+                            + " that is not declared on system image; skipping");
                     continue;
                 }
-                infos.add(info);
-            } else {
-                Slog.w(TAG, "Package " + pkg.packageName + " declares lib "
-                        + name + " that is not declared on system image; skipping");
+            }
+            if (sharedLibExists(
+                    name, SharedLibraryInfo.VERSION_UNDEFINED, existingSharedLibraries)) {
+                Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name
+                        + " that already exists; skipping");
                 continue;
             }
+            infos.add(info);
         }
         return infos;
     }
@@ -16043,6 +16210,13 @@
                     && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
 
             if (performDexopt) {
+                // Compile the layout resources.
+                if (PRECOMPILED_LAYOUT_ENABLED) {
+                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
+                    mViewCompiler.compileLayouts(pkg);
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
                 // Do not run PackageDexOptimizer through the local performDexOpt
                 // method because `pkg` may not be in `mPackages` yet.
@@ -16552,44 +16726,11 @@
             throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
         }
 
-        if (PackageManagerServiceUtils.isApkVerityEnabled()) {
-            String apkPath = null;
-            synchronized (mPackages) {
-                // Note that if the attacker managed to skip verify setup, for example by tampering
-                // with the package settings, upon reboot we will do full apk verification when
-                // verity is not detected.
-                final PackageSetting ps = mSettings.mPackages.get(pkgName);
-                if (ps != null && ps.isPrivileged()) {
-                    apkPath = pkg.baseCodePath;
-                }
-            }
-            if (apkPath != null) {
-                final VerityUtils.SetupResult result =
-                        VerityUtils.generateApkVeritySetupData(apkPath, null /* signaturePath */,
-                                true /* skipSigningBlock */);
-                if (result.isOk()) {
-                    if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling apk verity to " + apkPath);
-                    FileDescriptor fd = result.getUnownedFileDescriptor();
-                    try {
-                        final byte[] signedRootHash =
-                                VerityUtils.generateApkVerityRootHash(apkPath);
-                        mInstaller.installApkVerity(apkPath, fd, result.getContentSize());
-                        mInstaller.assertFsverityRootHashMatches(apkPath, signedRootHash);
-                    } catch (InstallerException | IOException | DigestException |
-                            NoSuchAlgorithmException e) {
-                        throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
-                                "Failed to set up verity: " + e);
-                    } finally {
-                        IoUtils.closeQuietly(fd);
-                    }
-                } else if (result.isFailed()) {
-                    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.
-                }
-            }
+        try {
+            setUpFsVerityIfPossible(pkg);
+        } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) {
+            throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
+                    "Failed to set up verity: " + e);
         }
 
         if (!instantApp) {
@@ -16887,6 +17028,96 @@
         }
     }
 
+    /**
+     * Set up fs-verity for the given package if possible.  This requires a feature flag of system
+     * property to be enabled only if the kernel supports fs-verity.
+     *
+     * <p>When the feature flag is set to legacy mode, only APK is supported (with some experimental
+     * kernel patches). In normal mode, all file format can be supported.
+     */
+    private void setUpFsVerityIfPossible(PackageParser.Package pkg) throws InstallerException,
+            PrepareFailure, IOException, DigestException, NoSuchAlgorithmException {
+        final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled();
+        final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled();
+        if (!standardMode && !legacyMode) {
+            return;
+        }
+
+        // Collect files we care for fs-verity setup.
+        ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
+        if (legacyMode) {
+            synchronized (mPackages) {
+                final PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
+                if (ps != null && ps.isPrivileged()) {
+                    fsverityCandidates.put(pkg.baseCodePath, null);
+                    if (pkg.splitCodePaths != null) {
+                        for (String splitPath : pkg.splitCodePaths) {
+                            fsverityCandidates.put(splitPath, null);
+                        }
+                    }
+                }
+            }
+        } else {
+            // NB: These files will become only accessible if the signing key is loaded in kernel's
+            // .fs-verity keyring.
+            fsverityCandidates.put(pkg.baseCodePath,
+                    VerityUtils.getFsveritySignatureFilePath(pkg.baseCodePath));
+
+            final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(pkg.baseCodePath);
+            if (new File(dmPath).exists()) {
+                fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath));
+            }
+
+            if (pkg.splitCodePaths != null) {
+                for (String path : pkg.splitCodePaths) {
+                    fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path));
+
+                    final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path);
+                    if (new File(splitDmPath).exists()) {
+                        fsverityCandidates.put(splitDmPath,
+                                VerityUtils.getFsveritySignatureFilePath(splitDmPath));
+                    }
+                }
+            }
+        }
+
+        for (Map.Entry<String, String> entry : fsverityCandidates.entrySet()) {
+            final String filePath = entry.getKey();
+            final String signaturePath = entry.getValue();
+
+            if (!legacyMode) {
+                // fs-verity is optional for now.  Only set up if signature is provided.
+                if (new File(signaturePath).exists()) {
+                    try {
+                        VerityUtils.setUpFsverity(filePath, signaturePath);
+                    } catch (IOException | DigestException | NoSuchAlgorithmException
+                            | SecurityException e) {
+                        throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
+                                "Failed to enable fs-verity: " + e);
+                    }
+                }
+                continue;
+            }
+
+            // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN.
+            final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(filePath);
+            if (result.isOk()) {
+                if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath);
+                final FileDescriptor fd = result.getUnownedFileDescriptor();
+                try {
+                    mInstaller.installApkVerity(filePath, fd, result.getContentSize());
+                    final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath);
+                    mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
+                } finally {
+                    IoUtils.closeQuietly(fd);
+                }
+            } else if (result.isFailed()) {
+                throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
+                        "Failed to generate verity");
+            }
+        }
+    }
+
     private void startIntentFilterVerifications(int userId, boolean replacing,
             PackageParser.Package pkg) {
         if (mIntentFilterVerifierComponent == null) {
@@ -18368,6 +18599,7 @@
                     true /*stopped*/,
                     true /*notLaunched*/,
                     false /*hidden*/,
+                    0 /*distractionFlags*/,
                     false /*suspended*/,
                     null /*suspendingPackage*/,
                     null /*dialogInfo*/,
@@ -18825,7 +19057,8 @@
 
     @GuardedBy("mPackages")
     private int getUidTargetSdkVersionLockedLPr(int uid) {
-        Object obj = mSettings.getSettingLPr(uid);
+        final int appId = UserHandle.getAppId(uid);
+        final Object obj = mSettings.getSettingLPr(appId);
         if (obj instanceof SharedUserSetting) {
             final SharedUserSetting sus = (SharedUserSetting) obj;
             int vers = Build.VERSION_CODES.CUR_DEVELOPMENT;
@@ -19016,7 +19249,7 @@
         // writer
         synchronized (mPackages) {
             PackageParser.Package pkg = mPackages.get(packageName);
-            if (pkg == null || pkg.applicationInfo.uid != callingUid) {
+            if (pkg == null || !isCallerSameApp(packageName, callingUid)) {
                 if (mContext.checkCallingOrSelfPermission(
                         android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
                         != PackageManager.PERMISSION_GRANTED) {
@@ -19457,28 +19690,32 @@
             throw new SecurityException("Only the system may call getPermissionGrantBackup()");
         }
 
-        ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
-        try {
-            final XmlSerializer serializer = new FastXmlSerializer();
-            serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
-            serializer.startDocument(null, true);
-            serializer.startTag(null, TAG_PERMISSION_BACKUP);
+        AtomicReference<byte[]> backup = new AtomicReference<>();
+        mContext.getSystemService(PermissionControllerManager.class).getRuntimePermissionBackup(
+                UserHandle.of(userId), mContext.getMainExecutor(), (b) -> {
+                    synchronized (backup) {
+                        backup.set(b);
+                        backup.notifyAll();
+                    }
+                });
 
-            synchronized (mPackages) {
-                serializeRuntimePermissionGrantsLPr(serializer, userId);
-            }
+        long start = System.currentTimeMillis();
+        synchronized (backup) {
+            while (backup.get() == null) {
+                long timeLeft = start + BACKUP_TIMEOUT_MILLIS - System.currentTimeMillis();
+                if (timeLeft <= 0) {
+                    return null;
+                }
 
-            serializer.endTag(null, TAG_PERMISSION_BACKUP);
-            serializer.endDocument();
-            serializer.flush();
-        } catch (Exception e) {
-            if (DEBUG_BACKUP) {
-                Slog.e(TAG, "Unable to write default apps for backup", e);
+                try {
+                    backup.wait(timeLeft);
+                } catch (InterruptedException ignored) {
+                    return null;
+                }
             }
-            return null;
         }
 
-        return dataStream.toByteArray();
+        return backup.get();
     }
 
     @Override
@@ -19504,66 +19741,6 @@
     }
 
     @GuardedBy("mPackages")
-    private void serializeRuntimePermissionGrantsLPr(XmlSerializer serializer, final int userId)
-            throws IOException {
-        serializer.startTag(null, TAG_ALL_GRANTS);
-
-        final int N = mSettings.mPackages.size();
-        for (int i = 0; i < N; i++) {
-            final PackageSetting ps = mSettings.mPackages.valueAt(i);
-            boolean pkgGrantsKnown = false;
-
-            PermissionsState packagePerms = ps.getPermissionsState();
-
-            for (PermissionState state : packagePerms.getRuntimePermissionStates(userId)) {
-                final int grantFlags = state.getFlags();
-                // only look at grants that are not system/policy fixed
-                if ((grantFlags & SYSTEM_RUNTIME_GRANT_MASK) == 0) {
-                    final boolean isGranted = state.isGranted();
-                    // And only back up the user-twiddled state bits
-                    if (isGranted || (grantFlags & USER_RUNTIME_GRANT_MASK) != 0) {
-                        final String packageName = mSettings.mPackages.keyAt(i);
-                        if (!pkgGrantsKnown) {
-                            serializer.startTag(null, TAG_GRANT);
-                            serializer.attribute(null, ATTR_PACKAGE_NAME, packageName);
-                            pkgGrantsKnown = true;
-                        }
-
-                        final boolean userSet =
-                                (grantFlags & FLAG_PERMISSION_USER_SET) != 0;
-                        final boolean userFixed =
-                                (grantFlags & FLAG_PERMISSION_USER_FIXED) != 0;
-                        final boolean revoke =
-                                (grantFlags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;
-
-                        serializer.startTag(null, TAG_PERMISSION);
-                        serializer.attribute(null, ATTR_PERMISSION_NAME, state.getName());
-                        if (isGranted) {
-                            serializer.attribute(null, ATTR_IS_GRANTED, "true");
-                        }
-                        if (userSet) {
-                            serializer.attribute(null, ATTR_USER_SET, "true");
-                        }
-                        if (userFixed) {
-                            serializer.attribute(null, ATTR_USER_FIXED, "true");
-                        }
-                        if (revoke) {
-                            serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
-                        }
-                        serializer.endTag(null, TAG_PERMISSION);
-                    }
-                }
-            }
-
-            if (pkgGrantsKnown) {
-                serializer.endTag(null, TAG_GRANT);
-            }
-        }
-
-        serializer.endTag(null, TAG_ALL_GRANTS);
-    }
-
-    @GuardedBy("mPackages")
     private void processRestoredPermissionGrantsLPr(XmlPullParser parser, int userId)
             throws XmlPullParserException, IOException {
         String pkgName = null;
@@ -19745,6 +19922,14 @@
                         .setPackage(launcherComponent.getPackageName());
                 mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid));
             }
+            // TODO(b/122900055) Change/Remove this and replace with new permission role.
+            if (mAppPredictionServicePackage != null) {
+                Intent predictorIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED)
+                        .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo)
+                        .putExtra(Intent.EXTRA_USER, UserHandle.of(userId))
+                        .setPackage(mAppPredictionServicePackage);
+                mContext.sendBroadcastAsUser(predictorIntent, UserHandle.of(launcherUid));
+            }
         }
     }
 
@@ -19897,6 +20082,20 @@
         return mContext.getString(R.string.config_defaultWellbeingPackage);
     }
 
+    private String getAppPredictionServicePackageName() {
+        String flattenedAppPredictionServiceComponentName =
+                mContext.getString(R.string.config_defaultAppPredictionService);
+        if (flattenedAppPredictionServiceComponentName == null) {
+            return null;
+        }
+        ComponentName appPredictionServiceComponentName =
+                ComponentName.unflattenFromString(flattenedAppPredictionServiceComponentName);
+        if (appPredictionServiceComponentName == null) {
+            return null;
+        }
+        return appPredictionServiceComponentName.getPackageName();
+    }
+
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId, String callingPackage) {
@@ -20471,7 +20670,6 @@
         storage.registerListener(mStorageListener);
 
         mInstallerService.systemReady();
-        mDexManager.systemReady();
         mPackageDexOptimizer.systemReady();
 
         getStorageManagerInternal().addExternalStoragePolicy(
@@ -23059,6 +23257,8 @@
                     return mWellbeingPackage;
                 case PackageManagerInternal.PACKAGE_DOCUMENTER:
                     return mDocumenterPackage;
+                case PackageManagerInternal.PACKAGE_CONFIGURATOR:
+                    return mConfiguratorPackage;
             }
             return null;
         }
@@ -23075,6 +23275,11 @@
         }
 
         @Override
+        public void setLocationExtraPackagesProvider(PackagesProvider provider) {
+            mDefaultPermissionPolicy.setLocationExtraPackagesProvider(provider);
+        }
+
+        @Override
         public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
             mDefaultPermissionPolicy.setVoiceInteractionPackagesProvider(provider);
         }
@@ -23183,6 +23388,14 @@
         }
 
         @Override
+        public int getDistractingPackageRestrictions(String packageName, int userId) {
+            synchronized (mPackages) {
+                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                return (ps != null) ? ps.getDistractionFlags(userId) : RESTRICTION_NONE;
+            }
+        }
+
+        @Override
         public int getPackageUid(String packageName, int flags, int userId) {
             return PackageManagerService.this
                     .getPackageUid(packageName, flags, userId);
@@ -23597,6 +23810,26 @@
         public void setEnableRollbackCode(int token, int enableRollbackCode) {
             PackageManagerService.this.setEnableRollbackCode(token, enableRollbackCode);
         }
+
+        /**
+         * Ask the package manager to compile layouts in the given package.
+         */
+        @Override
+        public boolean compileLayouts(String packageName) {
+            PackageParser.Package pkg;
+            synchronized (mPackages) {
+                pkg = mPackages.get(packageName);
+                if (pkg == null) {
+                    return false;
+                }
+            }
+            return mArtManagerService.compileLayouts(pkg);
+        }
+
+        @Override
+        public void finishPackageInstall(int token, boolean didLaunch) {
+            PackageManagerService.this.finishPackageInstall(token, didLaunch);
+        }
     }
 
     @GuardedBy("mPackages")
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 36948fc..6134d30 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -543,14 +543,31 @@
         }
     }
 
-    /** Returns true if APK Verity is enabled. */
+    /** Default is to not use fs-verity since it depends on kernel support. */
+    private static final int FSVERITY_DISABLED = 0;
+
+    /**
+     * Experimental implementation targeting priv apps, with Android specific kernel patches to
+     * extend fs-verity.
+     */
+    private static final int FSVERITY_LEGACY = 1;
+
+    /** Standard fs-verity. */
+    private static final int FSVERITY_ENABLED = 2;
+
+    /** Returns true if standard APK Verity is enabled. */
     static boolean isApkVerityEnabled() {
-        return SystemProperties.getInt("ro.apk_verity.mode", 0) != 0;
+        return SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED) == FSVERITY_ENABLED;
+    }
+
+    static boolean isLegacyApkVerityEnabled() {
+        return SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED) == FSVERITY_LEGACY;
     }
 
     /** Returns true to force apk verification if the updated package (in /data) is a priv app. */
     static boolean isApkVerificationForced(@Nullable PackageSetting disabledPs) {
-        return disabledPs != null && disabledPs.isPrivileged() && isApkVerityEnabled();
+        return disabledPs != null && disabledPs.isPrivileged() && (
+                isApkVerityEnabled() || isLegacyApkVerityEnabled());
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index ac9c6ef..3562630 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -43,6 +43,7 @@
 import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.ApkLite;
 import android.content.pm.PackageParser.PackageLite;
@@ -633,9 +634,9 @@
                 if (showVersionCode) {
                     pw.print(" versionCode:");
                     if (info.applicationInfo != null) {
-                        pw.print(info.applicationInfo.versionCode);
+                        pw.print(info.applicationInfo.longVersionCode);
                     } else {
-                        pw.print(info.versionCode);
+                        pw.print(info.getLongVersionCode());
                     }
                 }
                 if (listInstaller && !isApex) {
@@ -1170,6 +1171,7 @@
         String checkProfilesRaw = null;
         boolean secondaryDex = false;
         String split = null;
+        boolean compileLayouts = false;
 
         String opt;
         while ((opt = getNextOption()) != null) {
@@ -1189,6 +1191,9 @@
                 case "-r":
                     compilationReason = getNextArgRequired();
                     break;
+                case "--compile-layouts":
+                    compileLayouts = true;
+                    break;
                 case "--check-prof":
                     checkProfilesRaw = getNextArgRequired();
                     break;
@@ -1220,14 +1225,16 @@
             }
         }
 
-        if (compilerFilter != null && compilationReason != null) {
-            pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " +
-                    "at the same time");
-            return 1;
-        }
-        if (compilerFilter == null && compilationReason == null) {
-            pw.println("Cannot run without any of compilation filter (\"-m\") and compilation " +
-                    "reason (\"-r\") at the same time");
+        final boolean compilerFilterGiven = compilerFilter != null;
+        final boolean compilationReasonGiven = compilationReason != null;
+        // Make sure exactly one of -m, -r, or --compile-layouts is given.
+        if ((!compilerFilterGiven && !compilationReasonGiven && !compileLayouts)
+            || (!compilerFilterGiven && compilationReasonGiven && compileLayouts)
+            || (compilerFilterGiven && !compilationReasonGiven && compileLayouts)
+            || (compilerFilterGiven && compilationReasonGiven && !compileLayouts)
+            || (compilerFilterGiven && compilationReasonGiven && compileLayouts)) {
+            pw.println("Must specify exactly one of compilation filter (\"-m\"), compilation " +
+                    "reason (\"-r\"), or compile layouts (\"--compile-layouts\")");
             return 1;
         }
 
@@ -1241,15 +1248,16 @@
             return 1;
         }
 
-        String targetCompilerFilter;
-        if (compilerFilter != null) {
+        String targetCompilerFilter = null;
+        if (compilerFilterGiven) {
             if (!DexFile.isValidCompilerFilter(compilerFilter)) {
                 pw.println("Error: \"" + compilerFilter +
                         "\" is not a valid compilation filter.");
                 return 1;
             }
             targetCompilerFilter = compilerFilter;
-        } else {
+        }
+        if (compilationReasonGiven) {
             int reason = -1;
             for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
                 if (PackageManagerServiceCompilerMapping.REASON_STRINGS[i].equals(
@@ -1291,12 +1299,19 @@
                 pw.flush();
             }
 
-            boolean result = secondaryDex
+            boolean result = true;
+            if (compileLayouts) {
+                PackageManagerInternal internal = LocalServices.getService(
+                        PackageManagerInternal.class);
+                result = internal.compileLayouts(packageName);
+            } else {
+                result = secondaryDex
                     ? mInterface.performDexOptSecondary(packageName,
                             targetCompilerFilter, forceCompilation)
                     : mInterface.performDexOptMode(packageName,
                             checkProfiles, targetCompilerFilter, forceCompilation,
                             true /* bootComplete */, split);
+            }
             if (!result) {
                 failedPackages.add(packageName);
             }
@@ -2293,6 +2308,7 @@
                     break;
                 case "--apex":
                     sessionParams.installFlags |= PackageManager.INSTALL_APEX;
+                    sessionParams.setStaged();
                     break;
                 case "--multi-package":
                     sessionParams.setMultiPackage();
@@ -2588,7 +2604,7 @@
         try {
             session = new PackageInstaller.Session(
                     mInterface.getPackageInstaller().openSession(sessionId));
-            if (!session.isMultiPackage()) {
+            if (!session.isMultiPackage() && !session.isStaged()) {
                 // Sanity check that all .dm files match an apk.
                 // (The installer does not support standalone .dm files and will not process them.)
                 try {
@@ -3003,6 +3019,7 @@
         pw.println("      --check-prof (true | false): look at profiles when doing dexopt?");
         pw.println("      --secondary-dex: compile app secondary dex files");
         pw.println("      --split SPLIT: compile only the given split name");
+        pw.println("      --compile-layouts: compile layout resources for faster inflation");
         pw.println("");
         pw.println("  force-dex-opt PACKAGE");
         pw.println("    Force immediate execution of dex opt for the given PACKAGE.");
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 3c22f07..58f262c 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -392,6 +392,14 @@
         modifyUserState(userId).hidden = hidden;
     }
 
+    int getDistractionFlags(int userId) {
+        return readUserState(userId).distractionFlags;
+    }
+
+    void setDistractionFlags(int distractionFlags, int userId) {
+        modifyUserState(userId).distractionFlags = distractionFlags;
+    }
+
     boolean getSuspended(int userId) {
         return readUserState(userId).suspended;
     }
@@ -423,7 +431,8 @@
     }
 
     void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
-            boolean notLaunched, boolean hidden, boolean suspended, String suspendingPackage,
+            boolean notLaunched, boolean hidden, int distractionFlags, boolean suspended,
+            String suspendingPackage,
             SuspendDialogInfo dialogInfo, PersistableBundle suspendedAppExtras,
             PersistableBundle suspendedLauncherExtras, boolean instantApp,
             boolean virtualPreload, String lastDisableAppCaller,
@@ -437,6 +446,7 @@
         state.stopped = stopped;
         state.notLaunched = notLaunched;
         state.hidden = hidden;
+        state.distractionFlags = distractionFlags;
         state.suspended = suspended;
         state.suspendingPackage = suspendingPackage;
         state.dialogInfo = dialogInfo;
@@ -607,6 +617,7 @@
             }
             proto.write(PackageProto.UserInfoProto.INSTALL_TYPE, installType);
             proto.write(PackageProto.UserInfoProto.IS_HIDDEN, state.hidden);
+            proto.write(PackageProto.UserInfoProto.DISTRACTION_FLAGS, state.distractionFlags);
             proto.write(PackageProto.UserInfoProto.IS_SUSPENDED, state.suspended);
             if (state.suspended) {
                 proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE, state.suspendingPackage);
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index b47d966..b4154c7 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -17,8 +17,8 @@
 package com.android.server.pm;
 
 import android.content.pm.PackageParser;
-import android.content.pm.Signature;
 import android.content.pm.PackageParser.SigningDetails;
+import android.content.pm.Signature;
 import android.os.Environment;
 import android.util.Slog;
 import android.util.Xml;
@@ -81,6 +81,13 @@
         sMacPermissions.add(new File(
             Environment.getRootDirectory(), "/etc/selinux/plat_mac_permissions.xml"));
 
+        // Product mac permissions (optional).
+        final File productMacPermission = new File(
+                Environment.getProductDirectory(), "/etc/selinux/product_mac_permissions.xml");
+        if (productMacPermission.exists()) {
+            sMacPermissions.add(productMacPermission);
+        }
+
         // Vendor mac permissions.
         // The filename has been renamed from nonplat_mac_permissions to
         // vendor_mac_permissions. Either of them should exist.
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index c524dba..b0f2326 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -223,6 +223,7 @@
     private static final String ATTR_BLOCKED = "blocked";
     // New name for the above attribute.
     private static final String ATTR_HIDDEN = "hidden";
+    private static final String ATTR_DISTRACTION_FLAGS = "distraction_flags";
     private static final String ATTR_SUSPENDED = "suspended";
     private static final String ATTR_SUSPENDING_PACKAGE = "suspending-package";
     /**
@@ -734,6 +735,7 @@
                                 true /*stopped*/,
                                 true /*notLaunched*/,
                                 false /*hidden*/,
+                                0 /*distractionFlags*/,
                                 false /*suspended*/,
                                 null /*suspendingPackage*/,
                                 null /*dialogInfo*/,
@@ -1628,6 +1630,7 @@
                                 false /*stopped*/,
                                 false /*notLaunched*/,
                                 false /*hidden*/,
+                                0 /*distractionFlags*/,
                                 false /*suspended*/,
                                 null /*suspendingPackage*/,
                                 null /*dialogInfo*/,
@@ -1703,6 +1706,8 @@
                     hidden = hiddenStr == null
                             ? hidden : Boolean.parseBoolean(hiddenStr);
 
+                    final int distractionFlags = XmlUtils.readIntAttribute(parser,
+                            ATTR_DISTRACTION_FLAGS, 0);
                     final boolean suspended = XmlUtils.readBooleanAttribute(parser, ATTR_SUSPENDED,
                             false);
                     String suspendingPackage = parser.getAttributeValue(null,
@@ -1781,7 +1786,8 @@
                         setBlockUninstallLPw(userId, name, true);
                     }
                     ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
-                            hidden, suspended, suspendingPackage, suspendDialogInfo,
+                            hidden, distractionFlags, suspended, suspendingPackage,
+                            suspendDialogInfo,
                             suspendedAppExtras, suspendedLauncherExtras, instantApp, virtualPreload,
                             enabledCaller, enabledComponents, disabledComponents, verifState,
                             linkGeneration, installReason, harmfulAppWarning);
@@ -2089,6 +2095,10 @@
                 if (ustate.hidden) {
                     serializer.attribute(null, ATTR_HIDDEN, "true");
                 }
+                if (ustate.distractionFlags != 0) {
+                    serializer.attribute(null, ATTR_DISTRACTION_FLAGS,
+                            Integer.toString(ustate.distractionFlags));
+                }
                 if (ustate.suspended) {
                     serializer.attribute(null, ATTR_SUSPENDED, "true");
                     if (ustate.suspendingPackage != null) {
@@ -2780,13 +2790,13 @@
                 // dataPath   - path to package's data path
                 // seinfo     - seinfo label for the app (assigned at install time)
                 // gids       - supplementary gids this app launches with
+                // profileableFromShellFlag  - 0 or 1 if the package is profileable from shell.
                 //
                 // NOTE: We prefer not to expose all ApplicationInfo flags for now.
                 //
                 // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
                 // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
-                //   frameworks/base/libs/packagelistparser
-                //   system/core/run-as/run-as.c
+                //   system/core/libpackagelistparser
                 //
                 sb.setLength(0);
                 sb.append(ai.packageName);
@@ -2806,6 +2816,8 @@
                 } else {
                     sb.append("none");
                 }
+                sb.append(" ");
+                sb.append(ai.isProfileableByShell() ? "1" : "0");
                 sb.append("\n");
                 writer.append(sb);
             }
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 83f0fde..563fd7f 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -20,8 +20,10 @@
 import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageInfo;
 import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
 import android.content.res.Resources;
 import android.os.PersistableBundle;
 import android.text.format.Formatter;
@@ -640,6 +642,55 @@
     }
 
     /**
+     * Returns a list of ShortcutInfos that match the given intent filter and the category of
+     * available ShareTarget definitions in this package.
+     */
+    public List<ShortcutManager.ShareShortcutInfo> getMatchingShareTargets(
+            @NonNull IntentFilter filter) {
+        final List<ShareTargetInfo> matchedTargets = new ArrayList<>();
+        for (int i = 0; i < mShareTargets.size(); i++) {
+            final ShareTargetInfo target = mShareTargets.get(i);
+            for (ShareTargetInfo.TargetData data : target.mTargetData) {
+                if (filter.hasDataType(data.mMimeType)) {
+                    // Matched at least with one data type
+                    matchedTargets.add(target);
+                    break;
+                }
+            }
+        }
+
+        if (matchedTargets.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        // Get the list of all dynamic shortcuts in this package
+        final ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
+        findAll(shortcuts, ShortcutInfo::isDynamicVisible, ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+        final List<ShortcutManager.ShareShortcutInfo> result = new ArrayList<>();
+        for (int i = 0; i < shortcuts.size(); i++) {
+            final ShortcutInfo si = shortcuts.get(i);
+            for (int j = 0; j < matchedTargets.size(); j++) {
+                // Shortcut must have all of share target categories
+                boolean hasAllCategories = true;
+                final ShareTargetInfo target = matchedTargets.get(j);
+                for (int q = 0; q < target.mCategories.length; q++) {
+                    if (!si.getCategories().contains(target.mCategories[q])) {
+                        hasAllCategories = false;
+                        break;
+                    }
+                }
+                if (hasAllCategories) {
+                    result.add(new ShortcutManager.ShareShortcutInfo(si, new ComponentName(
+                            getPackageName(), target.mTargetClass)));
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
      * Return the filenames (excluding path names) of icon bitmap files from this package.
      */
     public ArraySet<String> getUsedBitmapFiles() {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 2b773f4..fdbaba2 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -46,6 +46,7 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
 import android.content.pm.ShortcutServiceInternal;
 import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
 import android.content.res.Resources;
@@ -2149,6 +2150,23 @@
         }
     }
 
+    @Override
+    public ParceledListSlice<ShortcutManager.ShareShortcutInfo> getShareTargets(String packageName,
+            IntentFilter filter, @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+
+        synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
+            final List<ShortcutManager.ShareShortcutInfo> shortcutInfoList = new ArrayList<>();
+
+            final ShortcutUser user = getUserShortcutsLocked(userId);
+            user.forAllPackages(p -> shortcutInfoList.addAll(p.getMatchingShareTargets(filter)));
+
+            return new ParceledListSlice<>(shortcutInfoList);
+        }
+    }
+
     @GuardedBy("mLock")
     private ParceledListSlice<ShortcutInfo> getShortcutsWithQueryLocked(@NonNull String packageName,
             @UserIdInt int userId, int cloneFlags, @NonNull Predicate<ShortcutInfo> query) {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 223f99e..5311c2a 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -17,14 +17,33 @@
 package com.android.server.pm;
 
 import android.annotation.NonNull;
+import android.apex.ApexInfo;
+import android.apex.ApexInfoList;
+import android.apex.ApexSessionInfo;
+import android.apex.IApexService;
 import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.PackageParser.SigningDetails;
+import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.ParceledListSlice;
+import android.content.pm.Signature;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.text.TextUtils;
+import android.util.Slog;
 import android.util.SparseArray;
+import android.util.apk.ApkSignatureVerifier;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * This class handles staged install sessions, i.e. install sessions that require packages to
@@ -35,25 +54,24 @@
     private static final String TAG = "StagingManager";
 
     private final PackageManagerService mPm;
+    private final Handler mBgHandler;
 
-    // STOPSHIP: This is a temporary mock implementation of staged sessions. This variable
-    //           shouldn't be needed at all.
-    // TODO(b/118865310): Implement staged sessions logic.
     @GuardedBy("mStagedSessions")
     private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
 
     StagingManager(PackageManagerService pm) {
         mPm = pm;
+        mBgHandler = BackgroundThread.getHandler();
     }
 
     private void updateStoredSession(@NonNull PackageInstallerSession sessionInfo) {
         synchronized (mStagedSessions) {
             PackageInstallerSession storedSession = mStagedSessions.get(sessionInfo.sessionId);
-            if (storedSession == null) {
-                throw new IllegalStateException("Attempting to change state of a session not "
-                        + "known to StagingManager");
+            // storedSession might be null if a call to abortSession was made before the session
+            // is updated.
+            if (storedSession != null) {
+                mStagedSessions.put(sessionInfo.sessionId, sessionInfo);
             }
-            mStagedSessions.put(sessionInfo.sessionId, sessionInfo);
         }
     }
 
@@ -67,12 +85,151 @@
         return new ParceledListSlice<>(result);
     }
 
-    void commitSession(@NonNull PackageInstallerSession sessionInfo) {
-        updateStoredSession(sessionInfo);
-        // TODO(b/118865310): Dispatch the session to apexd/PackageManager for verification. For
-        //                    now we directly mark it as ready.
-        sessionInfo.setStagedSessionReady();
-        mPm.sendSessionUpdatedBroadcast(sessionInfo.generateInfo(), sessionInfo.userId);
+    private static boolean validateApexSignatureLocked(String apexPath, String packageName) {
+        final SigningDetails signingDetails;
+        try {
+            signingDetails = ApkSignatureVerifier.verify(apexPath, SignatureSchemeVersion.JAR);
+        } catch (PackageParserException e) {
+            Slog.e(TAG, "Unable to parse APEX package: " + apexPath, e);
+            return false;
+        }
+
+        final IApexService apex = IApexService.Stub.asInterface(
+                ServiceManager.getService("apexservice"));
+        final ApexInfo apexInfo;
+        try {
+            apexInfo = apex.getActivePackage(packageName);
+        } catch (RemoteException re) {
+            Slog.e(TAG, "Unable to contact APEXD", re);
+            return false;
+        }
+
+        if (apexInfo == null || TextUtils.isEmpty(apexInfo.packageName)) {
+            // TODO: What is the right thing to do here ? This implies there's no active package
+            // with the given name. This should never be the case in production (where we only
+            // accept updates to existing APEXes) but may be required for testing.
+            return true;
+        }
+
+        final SigningDetails existingSigningDetails;
+        try {
+            existingSigningDetails = ApkSignatureVerifier.verify(
+                apexInfo.packagePath, SignatureSchemeVersion.JAR);
+        } catch (PackageParserException e) {
+            Slog.e(TAG, "Unable to parse APEX package: " + apexInfo.packagePath, e);
+            return false;
+        }
+
+        // Now that we have both sets of signatures, demand that they're an exact match.
+        if (Signature.areExactMatch(existingSigningDetails.signatures, signingDetails.signatures)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private static boolean submitSessionToApexService(@NonNull PackageInstallerSession session,
+                                                      List<PackageInstallerSession> childSessions,
+                                                      ApexInfoList apexInfoList) {
+        return sendSubmitStagedSessionRequest(
+                session.sessionId,
+                childSessions != null
+                        ? childSessions.stream().mapToInt(s -> s.sessionId).toArray() :
+                        new int[]{},
+                apexInfoList);
+    }
+
+    private static boolean sendSubmitStagedSessionRequest(
+            int sessionId, int[] childSessionIds, ApexInfoList apexInfoList) {
+        final IApexService apex = IApexService.Stub.asInterface(
+                ServiceManager.getService("apexservice"));
+        boolean success;
+        try {
+            success = apex.submitStagedSession(sessionId, childSessionIds, apexInfoList);
+        } catch (RemoteException re) {
+            Slog.e(TAG, "Unable to contact apexservice", re);
+            return false;
+        }
+        return success;
+    }
+
+    private static boolean isApexSession(@NonNull PackageInstallerSession session) {
+        return (session.params.installFlags & PackageManager.INSTALL_APEX) != 0;
+    }
+
+    private void preRebootVerification(@NonNull PackageInstallerSession session) {
+        boolean success = true;
+
+        final ApexInfoList apexInfoList = new ApexInfoList();
+        // APEX checks. For single-package sessions, check if they contain an APEX. For
+        // multi-package sessions, find all the child sessions that contain an APEX.
+        if (!session.isMultiPackage()
+                && isApexSession(session)) {
+            success = submitSessionToApexService(session, null, apexInfoList);
+        } else if (session.isMultiPackage()) {
+            List<PackageInstallerSession> childSessions =
+                    Arrays.stream(session.getChildSessionIds())
+                            // Retrieve cached sessions matching ids.
+                            .mapToObj(i -> mStagedSessions.get(i))
+                            // Filter only the ones containing APEX.
+                            .filter(childSession -> isApexSession(childSession))
+                            .collect(Collectors.toList());
+            if (!childSessions.isEmpty()) {
+                success = submitSessionToApexService(session, childSessions, apexInfoList);
+            } // else this is a staged multi-package session with no APEX files.
+        }
+
+        if (success && (apexInfoList.apexInfos.length > 0)) {
+            // For APEXes, we validate the signature here before we mark the session as ready,
+            // so we fail the session early if there is a signature mismatch. For APKs, the
+            // signature verification will be done by the package manager at the point at which
+            // it applies the staged install.
+            //
+            // TODO: Decide whether we want to fail fast by detecting signature mismatches for APKs,
+            // right away.
+            for (ApexInfo apexPackage : apexInfoList.apexInfos) {
+                if (!validateApexSignatureLocked(apexPackage.packagePath,
+                        apexPackage.packageName)) {
+                    success = false;
+                    break;
+                }
+            }
+        }
+
+        if (success) {
+            session.setStagedSessionReady();
+        } else {
+            session.setStagedSessionFailed(SessionInfo.VERIFICATION_FAILED);
+        }
+    }
+
+    private void resumeSession(@NonNull PackageInstallerSession session) {
+        // Check with apexservice whether the apex
+        // packages have been activated.
+        final IApexService apex = IApexService.Stub.asInterface(
+                ServiceManager.getService("apexservice"));
+        ApexSessionInfo apexSessionInfo;
+        try {
+            apexSessionInfo = apex.getStagedSessionInfo(session.sessionId);
+        } catch (RemoteException re) {
+            Slog.e(TAG, "Unable to contact apexservice", re);
+            // TODO should we retry here? Mark the session as failed?
+            return;
+        }
+        if (apexSessionInfo.isActivationFailed || apexSessionInfo.isUnknown) {
+            session.setStagedSessionFailed(SessionInfo.ACTIVATION_FAILED);
+        }
+        if (apexSessionInfo.isActivated) {
+            session.setStagedSessionApplied();
+            // TODO(b/118865310) if multi-package proceed with the installation of APKs.
+        }
+        // TODO(b/118865310) if (apexSessionInfo.isVerified) { /* mark this as staged in apexd */ }
+        // In every other case apexd will retry to apply the session at next boot.
+    }
+
+    void commitSession(@NonNull PackageInstallerSession session) {
+        updateStoredSession(session);
+        mBgHandler.post(() -> preRebootVerification(session));
     }
 
     void createSession(@NonNull PackageInstallerSession sessionInfo) {
@@ -81,10 +238,74 @@
         }
     }
 
-    void abortSession(@NonNull PackageInstallerSession sessionInfo) {
-        updateStoredSession(sessionInfo);
+    void abortSession(@NonNull PackageInstallerSession session) {
         synchronized (mStagedSessions) {
-            mStagedSessions.remove(sessionInfo.sessionId);
+            updateStoredSession(session);
+            mStagedSessions.remove(session.sessionId);
+        }
+    }
+
+    @GuardedBy("mStagedSessions")
+    private boolean isMultiPackageSessionComplete(@NonNull PackageInstallerSession session) {
+        // This method assumes that the argument is either a parent session of a multi-package
+        // i.e. isMultiPackage() returns true, or that it is a child session, i.e.
+        // hasParentSessionId() returns true.
+        if (session.isMultiPackage()) {
+            // Parent session of a multi-package group. Check that we restored all the children.
+            for (int childSession : session.getChildSessionIds()) {
+                if (mStagedSessions.get(childSession) == null) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        if (session.hasParentSessionId()) {
+            PackageInstallerSession parent = mStagedSessions.get(session.getParentSessionId());
+            if (parent == null) {
+                return false;
+            }
+            return isMultiPackageSessionComplete(parent);
+        }
+        Slog.wtf(TAG, "Attempting to restore an invalid multi-package session.");
+        return false;
+    }
+
+    void restoreSession(@NonNull PackageInstallerSession session) {
+        PackageInstallerSession sessionToResume = session;
+        synchronized (mStagedSessions) {
+            mStagedSessions.append(session.sessionId, session);
+            // For multi-package sessions, we don't know in which order they will be restored. We
+            // need to wait until we have restored all the session in a group before restoring them.
+            if (session.isMultiPackage() || session.hasParentSessionId()) {
+                if (!isMultiPackageSessionComplete(session)) {
+                    // Still haven't recovered all sessions of the group, return.
+                    return;
+                }
+                // Group recovered, find the parent if necessary and resume the installation.
+                if (session.hasParentSessionId()) {
+                    sessionToResume = mStagedSessions.get(session.getParentSessionId());
+                }
+            }
+        }
+        checkStateAndResume(sessionToResume);
+    }
+
+    private void checkStateAndResume(@NonNull PackageInstallerSession session) {
+        // Check the state of the session and decide what to do next.
+        if (session.isStagedSessionFailed() || session.isStagedSessionApplied()) {
+            // Final states, nothing to do.
+            return;
+        }
+        if (!session.isStagedSessionReady()) {
+            // The framework got restarted before the pre-reboot verification could complete,
+            // restart the verification.
+            mBgHandler.post(() -> preRebootVerification(session));
+        } else {
+            // Session had already being marked ready. Start the checks to verify if there is any
+            // follow-up work.
+            // TODO(b/118865310): should this be synchronous to ensure it completes before
+            //                    systemReady() finishes?
+            mBgHandler.post(() -> resumeSession(session));
         }
     }
 }
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index dd04652..aaa1874 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -620,9 +620,6 @@
                         && callingUid != Process.SYSTEM_UID) {
                     return true;
                 } else if (String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(value)) {
-                    // Note LOCATION_MODE will be converted into LOCATION_PROVIDERS_ALLOWED
-                    // in android.provider.Settings.Secure.putStringForUser(), so we shouldn't come
-                    // here normally, but we still protect it here from a direct provider write.
                     return false;
                 }
                 restriction = UserManager.DISALLOW_SHARE_LOCATION;
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 1f05dc9..863bfd5 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -472,6 +472,33 @@
     }
 
     /**
+     * Compile layout resources in a given package.
+     */
+    public boolean compileLayouts(PackageParser.Package pkg) {
+        try {
+            final String packageName = pkg.packageName;
+            final String apkPath = pkg.baseCodePath;
+            final ApplicationInfo appInfo = pkg.applicationInfo;
+            final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex";
+            Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
+                    ") to " + outDexFile);
+            long callingId = Binder.clearCallingIdentity();
+            try {
+                synchronized (mInstallLock) {
+                    return mInstaller.compileLayouts(apkPath, packageName, outDexFile,
+                            appInfo.uid);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(callingId);
+            }
+        }
+        catch (Throwable e) {
+            Log.e("PackageManager", "Failed to compile layouts", e);
+            return false;
+        }
+    }
+
+    /**
      * Build the profiles names for all the package code paths (excluding resource only paths).
      * Return the map [code path -> profile name].
      */
diff --git a/services/core/java/com/android/server/pm/dex/DexLogger.java b/services/core/java/com/android/server/pm/dex/DexLogger.java
index 68a755b..59cc0cf 100644
--- a/services/core/java/com/android/server/pm/dex/DexLogger.java
+++ b/services/core/java/com/android/server/pm/dex/DexLogger.java
@@ -16,11 +16,15 @@
 
 package com.android.server.pm.dex;
 
+import static com.android.server.pm.dex.PackageDynamicCodeLoading.FILE_TYPE_DEX;
+import static com.android.server.pm.dex.PackageDynamicCodeLoading.FILE_TYPE_NATIVE;
+
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.os.FileUtils;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.util.ByteStringUtils;
 import android.util.EventLog;
@@ -28,7 +32,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.pm.Installer;
 import com.android.server.pm.Installer.InstallerException;
@@ -36,38 +39,38 @@
 import com.android.server.pm.dex.PackageDynamicCodeLoading.PackageDynamicCode;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.Map;
 import java.util.Set;
 
 /**
- * This class is responsible for logging data about secondary dex files.
- * The data logged includes hashes of the name and content of each file.
+ * This class is responsible for logging data about secondary dex files and, despite the name,
+ * native code executed from an app's private directory. The data logged includes hashes of the
+ * name and content of each file.
  */
 public class DexLogger {
     private static final String TAG = "DexLogger";
 
-    // Event log tag & subtag used for SafetyNet logging of dynamic
-    // code loading (DCL) - see b/63927552.
+    // Event log tag & subtags used for SafetyNet logging of dynamic code loading (DCL) -
+    // see b/63927552.
     private static final int SNET_TAG = 0x534e4554;
-    private static final String DCL_SUBTAG = "dcl";
+    private static final String DCL_DEX_SUBTAG = "dcl";
+    private static final String DCL_NATIVE_SUBTAG = "dcln";
 
     private final IPackageManager mPackageManager;
     private final PackageDynamicCodeLoading mPackageDynamicCodeLoading;
-    private final Object mInstallLock;
-    @GuardedBy("mInstallLock")
     private final Installer mInstaller;
 
-    public DexLogger(IPackageManager pms, Installer installer, Object installLock) {
-        this(pms, installer, installLock, new PackageDynamicCodeLoading());
+    public DexLogger(IPackageManager pms, Installer installer) {
+        this(pms, installer, new PackageDynamicCodeLoading());
     }
 
     @VisibleForTesting
-    DexLogger(IPackageManager pms, Installer installer, Object installLock,
+    DexLogger(IPackageManager pms, Installer installer,
             PackageDynamicCodeLoading packageDynamicCodeLoading) {
         mPackageManager = pms;
         mPackageDynamicCodeLoading = packageDynamicCodeLoading;
         mInstaller = installer;
-        mInstallLock = installLock;
     }
 
     public Set<String> getAllPackagesWithDynamicCodeLoading() {
@@ -118,12 +121,11 @@
             }
 
             int storageFlags;
-            if (appInfo.deviceProtectedDataDir != null
-                    && FileUtils.contains(appInfo.deviceProtectedDataDir, filePath)) {
-                storageFlags = StorageManager.FLAG_STORAGE_DE;
-            } else if (appInfo.credentialProtectedDataDir != null
-                    && FileUtils.contains(appInfo.credentialProtectedDataDir, filePath)) {
+
+            if (fileIsUnder(filePath, appInfo.credentialProtectedDataDir)) {
                 storageFlags = StorageManager.FLAG_STORAGE_CE;
+            } else if (fileIsUnder(filePath, appInfo.deviceProtectedDataDir)) {
+                storageFlags = StorageManager.FLAG_STORAGE_DE;
             } else {
                 Slog.e(TAG, "Could not infer CE/DE storage for path " + filePath);
                 needWrite |= mPackageDynamicCodeLoading.removeFile(packageName, filePath, userId);
@@ -131,16 +133,21 @@
             }
 
             byte[] hash = null;
-            synchronized (mInstallLock) {
-                try {
-                    hash = mInstaller.hashSecondaryDexFile(filePath, packageName, appInfo.uid,
-                            appInfo.volumeUuid, storageFlags);
-                } catch (InstallerException e) {
-                    Slog.e(TAG, "Got InstallerException when hashing file " + filePath
-                            + ": " + e.getMessage());
-                }
+            try {
+                // Note that we do not take the install lock here. Hashing should never interfere
+                // with app update/compilation/removal. We may get anomalous results if a file
+                // changes while we hash it, but that can happen anyway and is harmless for our
+                // purposes.
+                hash = mInstaller.hashSecondaryDexFile(filePath, packageName, appInfo.uid,
+                        appInfo.volumeUuid, storageFlags);
+            } catch (InstallerException e) {
+                Slog.e(TAG, "Got InstallerException when hashing file " + filePath
+                        + ": " + e.getMessage());
             }
 
+            String subtag = fileInfo.mFileType == FILE_TYPE_DEX
+                    ? DCL_DEX_SUBTAG
+                    : DCL_NATIVE_SUBTAG;
             String fileName = new File(filePath).getName();
             String message = PackageUtils.computeSha256Digest(fileName.getBytes());
 
@@ -167,7 +174,7 @@
                 }
 
                 if (loadingUid != -1) {
-                    writeDclEvent(loadingUid, message);
+                    writeDclEvent(subtag, loadingUid, message);
                 }
             }
         }
@@ -177,21 +184,58 @@
         }
     }
 
+    private boolean fileIsUnder(String filePath, String directoryPath) {
+        if (directoryPath == null) {
+            return false;
+        }
+
+        try {
+            return FileUtils.contains(new File(directoryPath).getCanonicalPath(),
+                    new File(filePath).getCanonicalPath());
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
     @VisibleForTesting
     PackageDynamicCode getPackageDynamicCodeInfo(String packageName) {
         return mPackageDynamicCodeLoading.getPackageDynamicCodeInfo(packageName);
     }
 
     @VisibleForTesting
-    void writeDclEvent(int uid, String message) {
-        EventLog.writeEvent(SNET_TAG, DCL_SUBTAG, uid, message);
+    void writeDclEvent(String subtag, int uid, String message) {
+        EventLog.writeEvent(SNET_TAG, subtag, uid, message);
     }
 
-    void record(int loaderUserId, String dexPath,
-            String owningPackageName, String loadingPackageName) {
+    void recordDex(int loaderUserId, String dexPath, String owningPackageName,
+            String loadingPackageName) {
         if (mPackageDynamicCodeLoading.record(owningPackageName, dexPath,
-                PackageDynamicCodeLoading.FILE_TYPE_DEX, loaderUserId,
-                loadingPackageName)) {
+                FILE_TYPE_DEX, loaderUserId, loadingPackageName)) {
+            mPackageDynamicCodeLoading.maybeWriteAsync();
+        }
+    }
+
+    /**
+     * Record that an app running in the specified uid has executed native code from the file at
+     * {@link path}.
+     */
+    public void recordNative(int loadingUid, String path) {
+        String[] packages;
+        try {
+            packages = mPackageManager.getPackagesForUid(loadingUid);
+            if (packages == null || packages.length == 0) {
+                return;
+            }
+        } catch (RemoteException e) {
+            // Can't happen, we're local.
+            return;
+        }
+
+        String loadingPackageName = packages[0];
+        int loadingUserId = UserHandle.getUserId(loadingUid);
+
+        if (mPackageDynamicCodeLoading.record(loadingPackageName, path,
+                FILE_TYPE_NATIVE, loadingUserId, loadingPackageName)) {
             mPackageDynamicCodeLoading.maybeWriteAsync();
         }
     }
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index e57d9d7..7ac7395 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -16,31 +16,28 @@
 
 package com.android.server.pm.dex;
 
+import static android.provider.DeviceConfig.FsiBoot;
+
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
 import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
 
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageParser;
-import android.database.ContentObserver;
-import android.os.Build;
 import android.os.FileUtils;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
-import android.provider.Settings.Global;
+import android.provider.DeviceConfig;
 import android.util.Log;
 import android.util.Slog;
 import android.util.jar.StrictJarFile;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
 import com.android.server.pm.Installer;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.PackageDexOptimizer;
@@ -129,17 +126,13 @@
         mPackageDexOptimizer = pdo;
         mInstaller = installer;
         mInstallLock = installLock;
-        mDexLogger = new DexLogger(pms, installer, installLock);
+        mDexLogger = new DexLogger(pms, installer);
     }
 
     public DexLogger getDexLogger() {
         return mDexLogger;
     }
 
-    public void systemReady() {
-        registerSettingObserver();
-    }
-
     /**
      * Notify about dex files loads.
      * Note that this method is invoked when apps load dex files and it should
@@ -235,7 +228,7 @@
                     continue;
                 }
 
-                mDexLogger.record(loaderUserId, dexPath, searchResult.mOwningPackageName,
+                mDexLogger.recordDex(loaderUserId, dexPath, searchResult.mOwningPackageName,
                         loadingAppInfo.packageName);
 
                 if (classLoaderContexts != null) {
@@ -699,47 +692,10 @@
         mDexLogger.writeNow();
     }
 
-    private void registerSettingObserver() {
-        final ContentResolver resolver = mContext.getContentResolver();
-
-        // This observer provides a one directional mapping from Global.PRIV_APP_OOB_ENABLED to
-        // pm.dexopt.priv-apps-oob property. This is only for experiment and should be removed once
-        // it is done.
-        ContentObserver privAppOobObserver = new ContentObserver(null) {
-            @Override
-            public void onChange(boolean selfChange) {
-                int oobEnabled = Global.getInt(resolver, Global.PRIV_APP_OOB_ENABLED, 0);
-                SystemProperties.set(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB,
-                        oobEnabled == 1 ? "true" : "false");
-            }
-        };
-        resolver.registerContentObserver(
-                Global.getUriFor(Global.PRIV_APP_OOB_ENABLED), false, privAppOobObserver,
-                UserHandle.USER_SYSTEM);
-        // At boot, restore the value from the setting, which persists across reboot.
-        privAppOobObserver.onChange(true);
-
-        ContentObserver privAppOobListObserver = new ContentObserver(null) {
-            @Override
-            public void onChange(boolean selfChange) {
-                String oobList = Global.getString(resolver, Global.PRIV_APP_OOB_LIST);
-                if (oobList == null) {
-                    oobList = "ALL";
-                }
-                SystemProperties.set(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST, oobList);
-            }
-        };
-        resolver.registerContentObserver(
-                Global.getUriFor(Global.PRIV_APP_OOB_LIST), false, privAppOobListObserver,
-                UserHandle.USER_SYSTEM);
-        // At boot, restore the value from the setting, which persists across reboot.
-        privAppOobListObserver.onChange(true);
-    }
-
     /**
      * Returns whether the given package is in the list of privilaged apps that should run out of
-     * box. This only makes sense if PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB is true. Note that when
-     * the the OOB list is empty, all priv apps will run in OOB mode.
+     * box. This only makes sense if the feature is enabled. Note that when the the OOB list is
+     * empty, all priv apps will run in OOB mode.
      */
     public static boolean isPackageSelectedToRunOob(String packageName) {
         return isPackageSelectedToRunOob(Arrays.asList(packageName));
@@ -747,19 +703,35 @@
 
     /**
      * Returns whether any of the given packages are in the list of privilaged apps that should run
-     * out of box. This only makes sense if PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB is true. Note that
-     * when the the OOB list is empty, all priv apps will run in OOB mode.
+     * out of box. This only makes sense if the feature is enabled. Note that when the the OOB list
+     * is empty, all priv apps will run in OOB mode.
      */
     public static boolean isPackageSelectedToRunOob(Collection<String> packageNamesInSameProcess) {
-        if (!SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false)) {
+        return isPackageSelectedToRunOobInternal(
+                SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false),
+                SystemProperties.get(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST, "ALL"),
+                DeviceConfig.getProperty(FsiBoot.NAMESPACE, FsiBoot.OOB_ENABLED),
+                DeviceConfig.getProperty(FsiBoot.NAMESPACE, FsiBoot.OOB_WHITELIST),
+                packageNamesInSameProcess);
+    }
+
+    @VisibleForTesting
+    /* package */ static boolean isPackageSelectedToRunOobInternal(
+            boolean isDefaultEnabled, String defaultWhitelist, String overrideEnabled,
+            String overrideWhitelist, Collection<String> packageNamesInSameProcess) {
+        // Allow experiment (if exists) to override device configuration.
+        boolean enabled = overrideEnabled != null ? overrideEnabled.equals("true")
+                : isDefaultEnabled;
+        if (!enabled) {
             return false;
         }
-        String oobListProperty = SystemProperties.get(
-                PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST, "ALL");
-        if ("ALL".equals(oobListProperty)) {
+
+        // Similarly, experiment flag can override the whitelist.
+        String whitelist = overrideWhitelist != null ? overrideWhitelist : defaultWhitelist;
+        if ("ALL".equals(whitelist)) {
             return true;
         }
-        for (String oobPkgName : oobListProperty.split(",")) {
+        for (String oobPkgName : whitelist.split(",")) {
             if (packageNamesInSameProcess.contains(oobPkgName)) {
                 return true;
             }
@@ -768,32 +740,6 @@
     }
 
     /**
-     * Generates package related log if the package has code stored in unexpected way.
-     */
-    public static void maybeLogUnexpectedPackageDetails(PackageParser.Package pkg) {
-        if (!Build.IS_DEBUGGABLE) {
-            return;
-        }
-
-        if (pkg.isPrivileged() && isPackageSelectedToRunOob(pkg.packageName)) {
-            logIfPackageHasUncompressedCode(pkg);
-        }
-    }
-
-    /**
-     * Generates log if the APKs in the given package have uncompressed dex file and so
-     * files that can be direclty mapped.
-     */
-    private static void logIfPackageHasUncompressedCode(PackageParser.Package pkg) {
-        auditUncompressedCodeInApk(pkg.baseCodePath);
-        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
-            for (int i = 0; i < pkg.splitCodePaths.length; i++) {
-                auditUncompressedCodeInApk(pkg.splitCodePaths[i]);
-            }
-        }
-    }
-
-    /**
      * Generates log if the archive located at {@code fileName} has uncompressed dex file and so
      * files that can be direclty mapped.
      */
diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
index 93ee44c..91ad11e 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
@@ -22,7 +22,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.os.ClassLoaderFactory;
-import com.android.server.pm.PackageDexOptimizer;
 
 import java.io.File;
 import java.util.List;
@@ -275,15 +274,11 @@
     /**
      * Encodes a single class loader dependency starting from {@param path} and
      * {@param classLoaderName}.
-     * When classpath is {@link PackageDexOptimizer#SKIP_SHARED_LIBRARY_CHECK}, the method returns
-     * the same. This special property is used only during OTA.
      * NOTE: Keep this in sync with the dexopt expectations! Right now that is either "PCL[path]"
      * for a PathClassLoader or "DLC[path]" for a DelegateLastClassLoader.
      */
     /*package*/ static String encodeClassLoader(String classpath, String classLoaderName) {
-        if (classpath.equals(PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK)) {
-            return classpath;
-        }
+        classpath.getClass();  // Throw NPE if classpath is null
         String classLoaderDexoptEncoding = classLoaderName;
         if (ClassLoaderFactory.isPathClassLoaderName(classLoaderName)) {
             classLoaderDexoptEncoding = "PCL";
@@ -306,16 +301,10 @@
     /**
      * Links to dependencies together in a format accepted by dexopt.
      * For the special case when either of cl1 or cl2 equals
-     * {@link PackageDexOptimizer#SKIP_SHARED_LIBRARY_CHECK}, the method returns the same. This
-     * property is used only during OTA.
      * NOTE: Keep this in sync with the dexopt expectations! Right now that is a list of split
      * dependencies {@see encodeClassLoader} separated by ';'.
      */
     /*package*/ static String encodeClassLoaderChain(String cl1, String cl2) {
-        if (cl1.equals(PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK) ||
-                cl2.equals(PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK)) {
-            return PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK;
-        }
         if (cl1.isEmpty()) return cl2;
         if (cl2.isEmpty()) return cl1;
         return cl1 + ";" + cl2;
diff --git a/services/core/java/com/android/server/pm/dex/OWNERS b/services/core/java/com/android/server/pm/dex/OWNERS
new file mode 100644
index 0000000..fcc1f6c
--- /dev/null
+++ b/services/core/java/com/android/server/pm/dex/OWNERS
@@ -0,0 +1,4 @@
+agampe@google.com
+calin@google.com
+ngeoffray@google.com
+sehr@google.com
diff --git a/services/core/java/com/android/server/pm/dex/PackageDynamicCodeLoading.java b/services/core/java/com/android/server/pm/dex/PackageDynamicCodeLoading.java
index 6d4bc82..cc26c9b 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDynamicCodeLoading.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDynamicCodeLoading.java
@@ -53,6 +53,9 @@
     // is represented in the text file format.)
     static final int FILE_TYPE_DEX = 'D';
 
+    // Type code to indicate a secondary file containing native code.
+    static final int FILE_TYPE_NATIVE = 'N';
+
     private static final String TAG = "PackageDynamicCodeLoading";
 
     private static final String FILE_VERSION_HEADER = "DCL1";
@@ -107,7 +110,7 @@
      */
     boolean record(String owningPackageName, String filePath, int fileType, int ownerUserId,
             String loadingPackageName) {
-        if (fileType != FILE_TYPE_DEX) {
+        if (!isValidFileType(fileType)) {
             throw new IllegalArgumentException("Bad file type: " + fileType);
         }
         synchronized (mLock) {
@@ -120,6 +123,10 @@
         }
     }
 
+    private static boolean isValidFileType(int fileType) {
+        return fileType == FILE_TYPE_DEX || fileType == FILE_TYPE_NATIVE;
+    }
+
     /**
      * Return all packages that contain records of secondary dex files. (Note that data updates
      * asynchronously, so {@link #getPackageDynamicCodeInfo} may still return null if passed
@@ -407,7 +414,7 @@
             if (packages.length == 0) {
                 throw new IOException("Malformed line: " + line);
             }
-            if (type != FILE_TYPE_DEX) {
+            if (!isValidFileType(type)) {
                 throw new IOException("Unknown file type: " + line);
             }
 
diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
new file mode 100644
index 0000000..8d8e17e
--- /dev/null
+++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm.dex;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageParser;
+import android.os.Binder;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.pm.Installer;
+
+public class ViewCompiler {
+    private final Object mInstallLock;
+    @GuardedBy("mInstallLock")
+    private final Installer mInstaller;
+
+    public ViewCompiler(Object installLock, Installer installer) {
+        mInstallLock = installLock;
+        mInstaller = installer;
+    }
+
+    public boolean compileLayouts(PackageParser.Package pkg) {
+        try {
+            final String packageName = pkg.packageName;
+            final String apkPath = pkg.baseCodePath;
+            final ApplicationInfo appInfo = pkg.applicationInfo;
+            final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex";
+            Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
+                ") to " + outDexFile);
+            long callingId = Binder.clearCallingIdentity();
+            try {
+                synchronized (mInstallLock) {
+                    return mInstaller.compileLayouts(apkPath, packageName, outDexFile,
+                        appInfo.uid);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(callingId);
+            }
+        } catch (Throwable e) {
+            Log.e("PackageManager", "Failed to compile layouts", e);
+            return false;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 3a49412..17f8347 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -247,6 +247,10 @@
     public boolean isDocumenter() {
         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_DOCUMENTER) != 0;
     }
+    public boolean isConfigurator() {
+        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_CONFIGURATOR)
+            != 0;
+    }
 
     public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
         if (!origPackageName.equals(sourcePackageName)) {
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 789664d..20d6d4e 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -225,6 +225,7 @@
     private final Handler mHandler;
 
     private PackagesProvider mLocationPackagesProvider;
+    private PackagesProvider mLocationExtraPackagesProvider;
     private PackagesProvider mVoiceInteractionPackagesProvider;
     private PackagesProvider mSmsAppPackagesProvider;
     private PackagesProvider mDialerAppPackagesProvider;
@@ -270,6 +271,13 @@
         }
     }
 
+    /** Sets the provider for loction extra packages. */
+    public void setLocationExtraPackagesProvider(PackagesProvider provider) {
+        synchronized (mLock) {
+            mLocationExtraPackagesProvider = provider;
+        }
+    }
+
     public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
         synchronized (mLock) {
             mVoiceInteractionPackagesProvider = provider;
@@ -403,6 +411,7 @@
         Log.i(TAG, "Granting permissions to default platform handlers for user " + userId);
 
         final PackagesProvider locationPackagesProvider;
+        final PackagesProvider locationExtraPackagesProvider;
         final PackagesProvider voiceInteractionPackagesProvider;
         final PackagesProvider smsAppPackagesProvider;
         final PackagesProvider dialerAppPackagesProvider;
@@ -412,6 +421,7 @@
 
         synchronized (mLock) {
             locationPackagesProvider = mLocationPackagesProvider;
+            locationExtraPackagesProvider = mLocationExtraPackagesProvider;
             voiceInteractionPackagesProvider = mVoiceInteractionPackagesProvider;
             smsAppPackagesProvider = mSmsAppPackagesProvider;
             dialerAppPackagesProvider = mDialerAppPackagesProvider;
@@ -424,6 +434,8 @@
                 ? voiceInteractionPackagesProvider.getPackages(userId) : null;
         String[] locationPackageNames = (locationPackagesProvider != null)
                 ? locationPackagesProvider.getPackages(userId) : null;
+        String[] locationExtraPackageNames = (locationExtraPackagesProvider != null)
+                ? locationExtraPackagesProvider.getPackages(userId) : null;
         String[] smsAppPackageNames = (smsAppPackagesProvider != null)
                 ? smsAppPackagesProvider.getPackages(userId) : null;
         String[] dialerAppPackageNames = (dialerAppPackagesProvider != null)
@@ -523,7 +535,7 @@
         }
 
         // Cell Broadcast Receiver
-        grantPermissionsToSystemPackage(
+        grantSystemFixedPermissionsToSystemPackage(
                 getDefaultSystemHandlerActivityPackage(Intents.SMS_CB_RECEIVED_ACTION, userId),
                 userId, SMS_PERMISSIONS);
 
@@ -638,6 +650,12 @@
                         LOCATION_PERMISSIONS, ACTIVITY_RECOGNITION_PERMISSIONS);
             }
         }
+        if (locationExtraPackageNames != null) {
+            // Also grant location permission to location extra packages.
+            for (String packageName : locationExtraPackageNames) {
+                grantPermissionsToSystemPackage(packageName, userId, LOCATION_PERMISSIONS);
+            }
+        }
 
         // Music
         Intent musicIntent = new Intent(Intent.ACTION_VIEW)
@@ -1272,6 +1290,7 @@
             return mContext.getPackageManager().getPackageInfo(pkg,
                     DEFAULT_PACKAGE_INFO_QUERY_FLAGS | extraFlags);
         } catch (NameNotFoundException e) {
+            Slog.e(TAG, "PackageNot found: " + pkg, e);
             return null;
         }
     }
diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS
index 88b97ea..01dc01e 100644
--- a/services/core/java/com/android/server/pm/permission/OWNERS
+++ b/services/core/java/com/android/server/pm/permission/OWNERS
@@ -1,4 +1,4 @@
-per-file DefaultPermissionGrantPolicy.java = bpoiesz@google.com
+moltmann@google.com
 per-file DefaultPermissionGrantPolicy.java = hackbod@android.com
 per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com
 per-file DefaultPermissionGrantPolicy.java = svetoslavganov@google.com
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 93964cb..30b5e49 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1640,6 +1640,13 @@
                 // Special permissions for the system default text classifier.
                 allowed = true;
             }
+            if (!allowed && bp.isConfigurator()
+                    && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+                    PackageManagerInternal.PACKAGE_CONFIGURATOR,
+                    UserHandle.USER_SYSTEM))) {
+                // Special permissions for the device configurator.
+                allowed = true;
+            }
             if (!allowed && bp.isWellbeing()
                     && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
                     PackageManagerInternal.PACKAGE_WELLBEING, UserHandle.USER_SYSTEM))) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f370edf..0e40a00 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -24,6 +24,7 @@
 import static android.content.Context.CONTEXT_RESTRICTED;
 import static android.content.Context.DISPLAY_SERVICE;
 import static android.content.Context.WINDOW_SERVICE;
+import static android.content.pm.PackageManager.FEATURE_HDMI_CEC;
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.content.pm.PackageManager.FEATURE_WATCH;
@@ -83,8 +84,10 @@
 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;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs
+        .CAMERA_LENS_COVER_ABSENT;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs
+        .CAMERA_LENS_UNCOVERED;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
 import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_DELEGATE;
@@ -126,6 +129,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManager;
+import android.hardware.hdmi.HdmiAudioSystemClient;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiPlaybackClient;
 import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
@@ -195,6 +199,7 @@
 import com.android.internal.accessibility.AccessibilityShortcutController;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.os.RoSystemProperties;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.internal.policy.PhoneWindow;
@@ -373,6 +378,7 @@
     private ScreenshotHelper mScreenshotHelper;
     private boolean mHasFeatureWatch;
     private boolean mHasFeatureLeanback;
+    private boolean mHasFeatureHdmiCec;
 
     // Assigned on main thread, accessed on UI thread
     volatile VrManagerInternal mVrManagerInternal;
@@ -474,6 +480,7 @@
     int mShortPressOnSleepBehavior;
     int mShortPressOnWindowBehavior;
     boolean mHasSoftInput = false;
+    boolean mHapticTextHandleEnabled;
     boolean mUseTvRouting;
     int mVeryLongPressTimeout;
     boolean mAllowStartActivityForLongPressOnPowerDuringSetup;
@@ -561,6 +568,10 @@
     private boolean mScreenshotChordPowerKeyTriggered;
     private long mScreenshotChordPowerKeyTime;
 
+    private static final long MOVING_DISPLAY_TO_TOP_DURATION_MILLIS = 10;
+    private volatile boolean mMovingDisplayToTopKeyTriggered;
+    private volatile long mMovingDisplayToTopKeyTime;
+
     // Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
     private int mRingerToggleChord = VOLUME_HUSH_OFF;
 
@@ -600,7 +611,7 @@
     private boolean mAodShowing;
 
     private boolean mPerDisplayFocusEnabled = false;
-    private int mTopFocusedDisplayId = INVALID_DISPLAY;
+    private volatile int mTopFocusedDisplayId = INVALID_DISPLAY;
 
     private static final int MSG_ENABLE_POINTER_LOCATION = 1;
     private static final int MSG_DISABLE_POINTER_LOCATION = 2;
@@ -628,6 +639,7 @@
     private static final int MSG_POWER_VERY_LONG_PRESS = 25;
     private static final int MSG_NOTIFY_USER_ACTIVITY = 26;
     private static final int MSG_RINGER_TOGGLE_CHORD = 27;
+    private static final int MSG_MOVE_DISPLAY_TO_TOP = 28;
 
     private class PolicyHandler extends Handler {
         @Override
@@ -723,6 +735,10 @@
                 case MSG_RINGER_TOGGLE_CHORD:
                     handleRingerChordGesture();
                     break;
+                case MSG_MOVE_DISPLAY_TO_TOP:
+                    mWindowManagerFuncs.moveDisplayToTop(msg.arg1);
+                    mMovingDisplayToTopKeyTriggered = false;
+                    break;
             }
         }
     }
@@ -804,6 +820,13 @@
         }
     };
 
+    private Runnable mPossibleVeryLongPressReboot = new Runnable() {
+        @Override
+        public void run() {
+            mActivityManagerInternal.prepareForPossibleShutdown();
+        }
+    };
+
     private void handleRingerChordGesture() {
         if (mRingerToggleChord == VOLUME_HUSH_OFF) {
             return;
@@ -844,7 +867,7 @@
     }
 
     private void interceptBackKeyDown() {
-        MetricsLogger.count(mContext, "key_back_down", 1);
+        mLogger.count("key_back_down", 1);
         // Reset back key state for long press
         mBackKeyHandled = false;
 
@@ -858,6 +881,7 @@
 
     // returns true if the key was handled and should not be passed to the user
     private boolean interceptBackKeyUp(KeyEvent event) {
+        mLogger.count("key_back_up", 1);
         // Cache handled state
         boolean handled = mBackKeyHandled;
 
@@ -948,6 +972,8 @@
         // Inform the StatusBar; but do not allow it to consume the event.
         sendSystemKeyToStatusBarAsync(event.getKeyCode());
 
+        schedulePossibleVeryLongPressReboot();
+
         // If the power key has still not yet been handled, then detect short
         // press, long press, or multi press and decide what to do.
         mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
@@ -1051,6 +1077,7 @@
         if (hasVeryLongPressOnPowerBehavior()) {
             mHandler.removeMessages(MSG_POWER_VERY_LONG_PRESS);
         }
+        cancelPossibleVeryLongPressReboot();
     }
 
     private void cancelPendingBackKeyAction() {
@@ -1452,7 +1479,7 @@
      */
     private HdmiControl getHdmiControl() {
         if (null == mHdmiControl) {
-            if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
+            if (!mHasFeatureHdmiCec) {
                 return null;
             }
             HdmiControlManager manager = (HdmiControlManager) mContext.getSystemService(
@@ -1688,6 +1715,7 @@
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);
         mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK);
+        mHasFeatureHdmiCec = mContext.getPackageManager().hasSystemFeature(FEATURE_HDMI_CEC);
         mAccessibilityShortcutController =
                 new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId);
         mLogger = new MetricsLogger();
@@ -1809,6 +1837,9 @@
         mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowStartActivityForLongPressOnPowerInSetup);
 
+        mHapticTextHandleEnabled = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableHapticTextHandle);
+
         mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
 
         mHandleVolumeKeysInWM = mContext.getResources().getBoolean(
@@ -1870,9 +1901,8 @@
 
         mWindowManagerInternal.registerAppTransitionListener(new AppTransitionListener() {
             @Override
-            public int onAppTransitionStartingLocked(int transit, IBinder openToken,
-                    IBinder closeToken, long duration, long statusBarAnimationStartTime,
-                    long statusBarAnimationDuration) {
+            public int onAppTransitionStartingLocked(int transit, long duration,
+                    long statusBarAnimationStartTime, long statusBarAnimationDuration) {
                 return handleStartTransitionForKeyguardLw(transit, duration);
             }
 
@@ -2264,9 +2294,8 @@
         }
 
         final LayoutParams attrs = win.getAttrs();
-        final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleLw() &&
-                ((imeTarget.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0
-                        || !canBeHiddenByKeyguardLw(imeTarget));
+        final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleLw()
+                && (imeTarget.canShowWhenLocked() || !canBeHiddenByKeyguardLw(imeTarget));
 
         // Show IME over the keyguard if the target allows it
         boolean allowWhenLocked = (win.isInputMethodWindow() || imeTarget == this)
@@ -2274,7 +2303,7 @@
 
         if (isKeyguardLocked() && isKeyguardOccluded()) {
             // Show SHOW_WHEN_LOCKED windows if Keyguard is occluded.
-            allowWhenLocked |= (attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
+            allowWhenLocked |= win.canShowWhenLocked()
                     // Show error dialogs over apps that are shown on lockscreen
                     || (attrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
         }
@@ -2552,12 +2581,25 @@
         final int eventDisplayId = event.getDisplayId();
         if (result == 0 && !mPerDisplayFocusEnabled
                 && eventDisplayId != INVALID_DISPLAY && eventDisplayId != mTopFocusedDisplayId) {
-            // Someone tries to send a key event to a display which doesn't have a focused window.
-            // We drop the event here, or it will cause ANR.
-            // TODO (b/121057974): The user may be confused about why the key doesn't work, so we
-            // may need to deal with this problem.
-            Slog.i(TAG, "Dropping this event targeting display #" + eventDisplayId
-                    + " because the focus is on display #" + mTopFocusedDisplayId);
+            // An event is targeting a non-focused display. Try to move the display to top so that
+            // it can become the focused display to interact with the user.
+            final long eventDownTime = event.getDownTime();
+            if (mMovingDisplayToTopKeyTime < eventDownTime) {
+                // We have not handled this event yet. Move the display to top, and then tell
+                // dispatcher to try again later.
+                mMovingDisplayToTopKeyTime = eventDownTime;
+                mMovingDisplayToTopKeyTriggered = true;
+                mHandler.sendMessage(
+                        mHandler.obtainMessage(MSG_MOVE_DISPLAY_TO_TOP, eventDisplayId, 0));
+                return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
+            } else if (mMovingDisplayToTopKeyTriggered) {
+                // The message has not been handled yet. Tell dispatcher to try again later.
+                return MOVING_DISPLAY_TO_TOP_DURATION_MILLIS;
+            }
+            // The target display is still not the top focused display. Drop the event because the
+            // display may not contain any window which can receive keys.
+            Slog.w(TAG, "Dropping key targeting non-focused display #" + eventDisplayId
+                    + " keyCode=" + KeyEvent.keyCodeToString(event.getKeyCode()));
             return -1;
         }
         return result;
@@ -4115,6 +4157,19 @@
     }
 
     private void dispatchDirectAudioEvent(KeyEvent event) {
+        // When System Audio Mode is off, volume keys received by AVR can be either consumed by AVR
+        // or forwarded to the TV. It's up to Amplifier manufacturer’s implementation.
+        HdmiControlManager hdmiControlManager = getHdmiControlManager();
+        if (null != hdmiControlManager
+                && !hdmiControlManager.getSystemAudioMode()
+                && shouldCecAudioDeviceForwardVolumeKeysSystemAudioModeOff()) {
+            HdmiAudioSystemClient audioSystemClient = hdmiControlManager.getAudioSystemClient();
+            if (audioSystemClient != null) {
+                audioSystemClient.sendKeyEvent(
+                        event.getKeyCode(), event.getAction() == KeyEvent.ACTION_DOWN);
+                return;
+            }
+        }
         if (event.getAction() != KeyEvent.ACTION_DOWN) {
             return;
         }
@@ -4122,6 +4177,7 @@
         int flags = AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_PLAY_SOUND
                 | AudioManager.FLAG_FROM_KEY;
         String pkgName = mContext.getOpPackageName();
+
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_UP:
                 try {
@@ -4153,6 +4209,18 @@
         }
     }
 
+    @Nullable
+    private HdmiControlManager getHdmiControlManager() {
+        if (!mHasFeatureHdmiCec) {
+            return null;
+        }
+        return (HdmiControlManager) mContext.getSystemService(HdmiControlManager.class);
+    }
+
+    private boolean shouldCecAudioDeviceForwardVolumeKeysSystemAudioModeOff() {
+        return RoSystemProperties.CEC_AUDIO_DEVICE_FORWARD_VOLUME_KEYS_SYSTEM_AUDIO_MODE_OFF;
+    }
+
     void dispatchMediaKeyWithWakeLock(KeyEvent event) {
         if (DEBUG_INPUT) {
             Slog.d(TAG, "dispatchMediaKeyWithWakeLock: " + event);
@@ -4869,6 +4937,15 @@
         }
     }
 
+    private void schedulePossibleVeryLongPressReboot() {
+        mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
+        mHandler.postDelayed(mPossibleVeryLongPressReboot, mVeryLongPressTimeout);
+    }
+
+    private void cancelPossibleVeryLongPressReboot() {
+        mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
+    }
+
     // TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
     private void updateScreenOffSleepToken(boolean acquire) {
         if (acquire) {
@@ -5126,8 +5203,11 @@
             case HapticFeedbackConstants.CLOCK_TICK:
             case HapticFeedbackConstants.CONTEXT_CLICK:
                 return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
-            case HapticFeedbackConstants.KEYBOARD_RELEASE:
             case HapticFeedbackConstants.TEXT_HANDLE_MOVE:
+                if (!mHapticTextHandleEnabled) {
+                    return null;
+                }
+            case HapticFeedbackConstants.KEYBOARD_RELEASE:
             case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE:
             case HapticFeedbackConstants.ENTRY_BUMP:
             case HapticFeedbackConstants.DRAG_CROSSING:
@@ -5292,11 +5372,13 @@
                 pw.println(mAllowStartActivityForLongPressOnPowerDuringSetup);
         pw.print(prefix);
                 pw.print("mHasSoftInput="); pw.print(mHasSoftInput);
-                pw.print(" mDismissImeOnBackKeyPressed="); pw.println(mDismissImeOnBackKeyPressed);
+                pw.print(" mHapticTextHandleEnabled="); pw.println(mHapticTextHandleEnabled);
         pw.print(prefix);
-                pw.print("mIncallPowerBehavior=");
-                pw.print(incallPowerBehaviorToString(mIncallPowerBehavior));
-                pw.print(" mIncallBackBehavior=");
+                pw.print("mDismissImeOnBackKeyPressed="); pw.print(mDismissImeOnBackKeyPressed);
+                pw.print(" mIncallPowerBehavior=");
+                pw.println(incallPowerBehaviorToString(mIncallPowerBehavior));
+        pw.print(prefix);
+                pw.print("mIncallBackBehavior=");
                 pw.print(incallBackBehaviorToString(mIncallBackBehavior));
                 pw.print(" mEndcallBehavior=");
                 pw.println(endcallBehaviorToString(mEndcallBehavior));
diff --git a/services/core/java/com/android/server/policy/TEST_MAPPING b/services/core/java/com/android/server/policy/TEST_MAPPING
index e212b04..437ef73 100644
--- a/services/core/java/com/android/server/policy/TEST_MAPPING
+++ b/services/core/java/com/android/server/policy/TEST_MAPPING
@@ -10,7 +10,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/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 3da325c..e1a911e 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -468,6 +468,9 @@
         /** @return true if this window desires key events. */
         boolean canReceiveKeys();
 
+        /** @return true if the window can show over keyguard. */
+        boolean canShowWhenLocked();
+
         /**
          * Writes {@link com.android.server.wm.IdentifierProto} to stream.
          */
@@ -634,6 +637,12 @@
          * Notifies window manager that user is switched.
          */
         void onUserSwitched();
+
+        /**
+         * Hint to window manager that the user is interacting with a display that should be treated
+         * as the top display.
+         */
+        void moveDisplayToTop(int displayId);
     }
 
     /**
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
new file mode 100644
index 0000000..055c941
--- /dev/null
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.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 com.android.server.policy.role;
+
+import android.annotation.NonNull;
+import android.app.role.RoleManager;
+import android.content.Context;
+import android.os.Debug;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.telephony.SmsApplication;
+import com.android.internal.util.CollectionUtils;
+import com.android.server.role.RoleManagerService;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Logic to retrieve the various legacy(pre-Q) equivalents of role holders.
+ *
+ * Unlike {@link RoleManagerService} this is meant to be pretty high-level to allow for depending
+ * on all kinds of various systems that are historically involved in legacy role resolution,
+ * e.g. {@link SmsApplication}
+ *
+ * @see RoleManagerService#migrateRoleIfNecessary
+ */
+public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHoldersResolver {
+
+    private static final boolean DEBUG = false;
+    private static final String LOG_TAG = "LegacyRoleResolutionPol";
+
+    @NonNull
+    private final Context mContext;
+
+    public LegacyRoleResolutionPolicy(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public List<String> getRoleHolders(String roleName, int userId) {
+        switch (roleName) {
+            case RoleManager.ROLE_SMS: {
+                // Moved over from SmsApplication#getApplication
+                String result = Settings.Secure.getStringForUser(
+                        mContext.getContentResolver(),
+                        Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
+
+                // TODO: STOPSHIP: Remove the following code once we remove default_sms_application
+                // and use the new config_defaultRoleHolders.
+                if (result == null) {
+                    Collection<SmsApplication.SmsApplicationData> applications =
+                            SmsApplication.getApplicationCollectionAsUser(mContext, userId);
+                    SmsApplication.SmsApplicationData applicationData;
+                    String defaultPackage = mContext.getResources()
+                            .getString(com.android.internal.R.string.default_sms_application);
+                    applicationData =
+                            SmsApplication.getApplicationForPackage(applications, defaultPackage);
+
+                    if (applicationData == null) {
+                        // Are there any applications?
+                        if (applications.size() != 0) {
+                            applicationData =
+                                    (SmsApplication.SmsApplicationData) applications.toArray()[0];
+                        }
+                    }
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "Found default sms app: " + applicationData
+                                + " among: " + applications + " from " + Debug.getCallers(4));
+                    }
+                    SmsApplication.SmsApplicationData app = applicationData;
+                    result = app == null ? null : app.mPackageName;
+                }
+
+                return CollectionUtils.singletonOrEmpty(result);
+            }
+            default: {
+                Slog.e(LOG_TAG, "Don't know how to find legacy role holders for " + roleName);
+                return Collections.emptyList();
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
deleted file mode 100644
index cedb548..0000000
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ /dev/null
@@ -1,715 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.power;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.os.PowerManager.ServiceType;
-import android.os.PowerSaveState;
-import android.provider.Settings;
-import android.provider.Settings.Global;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.KeyValueListParser;
-import android.util.Slog;
-import android.view.accessibility.AccessibilityManager;
-
-import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.ConcurrentUtils;
-import com.android.server.power.batterysaver.BatterySavingStats;
-import com.android.server.power.batterysaver.CpuFrequencies;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Class to decide whether to turn on battery saver mode for specific service
- *
- * IMPORTANT: This class shares the power manager lock, which is very low in the lock hierarchy.
- * Do not call out with the lock held, such as AccessibilityManager. (Settings provider is okay.)
- *
- * Test:
- atest ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
- */
-public class BatterySaverPolicy extends ContentObserver {
-    private static final String TAG = "BatterySaverPolicy";
-
-    public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE.
-
-    private static final String KEY_GPS_MODE = "gps_mode";
-    private static final String KEY_VIBRATION_DISABLED = "vibration_disabled";
-    private static final String KEY_ANIMATION_DISABLED = "animation_disabled";
-    private static final String KEY_SOUNDTRIGGER_DISABLED = "soundtrigger_disabled";
-
-    /**
-     * Disable turning on the network firewall when Battery Saver is turned on.
-     * If set to false, the firewall WILL be turned on when Battery Saver is turned on.
-     * If set to true, the firewall WILL NOT be turned on when Battery Saver is turned on.
-     */
-    private static final String KEY_ACTIVATE_FIREWALL_DISABLED = "firewall_disabled";
-
-    /**
-     * Disable turning on the special low power screen brightness dimming when Battery Saver is
-     * turned on.
-     * If set to false, the screen brightness dimming WILL be turned on by Battery Saver.
-     * If set to true, the screen brightness WILL NOT be turned on by Battery Saver.
-     */
-    private static final String KEY_ADJUST_BRIGHTNESS_DISABLED = "adjust_brightness_disabled";
-
-    /**
-     * Disable turning on Data Saver when Battery Saver is turned on.
-     * If set to false, Data Saver WILL be turned on when Battery Saver is turned on.
-     * If set to true, Data Saver WILL NOT be turned on when Battery Saver is turned on.
-     */
-    private static final String KEY_ACTIVATE_DATASAVER_DISABLED = "datasaver_disabled";
-    private static final String KEY_LAUNCH_BOOST_DISABLED = "launch_boost_disabled";
-    private static final String KEY_ADJUST_BRIGHTNESS_FACTOR = "adjust_brightness_factor";
-    private static final String KEY_FULLBACKUP_DEFERRED = "fullbackup_deferred";
-    private static final String KEY_KEYVALUE_DEFERRED = "keyvaluebackup_deferred";
-    private static final String KEY_FORCE_ALL_APPS_STANDBY = "force_all_apps_standby";
-    private static final String KEY_FORCE_BACKGROUND_CHECK = "force_background_check";
-    private static final String KEY_OPTIONAL_SENSORS_DISABLED = "optional_sensors_disabled";
-    private static final String KEY_AOD_DISABLED = "aod_disabled";
-    // Go into deep Doze as soon as the screen turns off.
-    private static final String KEY_QUICK_DOZE_ENABLED = "quick_doze_enabled";
-    private static final String KEY_SEND_TRON_LOG = "send_tron_log";
-
-    private static final String KEY_CPU_FREQ_INTERACTIVE = "cpufreq-i";
-    private static final String KEY_CPU_FREQ_NONINTERACTIVE = "cpufreq-n";
-
-    private static final Policy sDefaultPolicy = new Policy(
-            0.5f,  /* adjustBrightnessFactor */
-            true,  /* deferFullBackup */
-            true,  /* deferKeyValueBackup */
-            false, /* disableAnimation */
-            true,  /* disableAod */
-            true,  /* disableLaunchBoost */
-            true,  /* disableOptionalSensors */
-            true,  /* disableSoundTrigger */
-            true,  /* disableVibration */
-            false, /* enableAdjustBrightness */
-            false, /* enableDataSaver */
-            true,  /* enableFirewall */
-            true, /* enableQuickDoze */
-            new ArrayMap<>(), /* filesForInteractive */
-            new ArrayMap<>(), /* filesForNoninteractive */
-            true, /* forceAllAppsStandby */
-            true, /* forceBackgroundCheck */
-            PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF, /* gpsMode */
-            false /* sendTronLog */
-    );
-
-    private final Object mLock;
-    private final Handler mHandler;
-
-    @GuardedBy("mLock")
-    private String mSettings;
-
-    @GuardedBy("mLock")
-    private String mDeviceSpecificSettings;
-
-    @GuardedBy("mLock")
-    private String mDeviceSpecificSettingsSource; // For dump() only.
-
-    /**
-     * A short string describing which battery saver is now enabled, which we dump in the eventlog.
-     */
-    @GuardedBy("mLock")
-    private String mEventLogKeys;
-
-    /**
-     * Whether vibration should *really* be disabled -- i.e. {@link Policy#disableVibration}
-     * is true *and* {@link #mAccessibilityEnabled} is false.
-     */
-    @GuardedBy("mLock")
-    private boolean mDisableVibrationEffective;
-
-    /**
-     * Whether accessibility is currently enabled or not.
-     */
-    @GuardedBy("mLock")
-    private boolean mAccessibilityEnabled;
-
-    @GuardedBy("mLock")
-    private Policy mCurrPolicy = sDefaultPolicy;
-
-    private final Context mContext;
-    private final ContentResolver mContentResolver;
-    private final BatterySavingStats mBatterySavingStats;
-
-    @GuardedBy("mLock")
-    private final List<BatterySaverPolicyListener> mListeners = new ArrayList<>();
-
-    public interface BatterySaverPolicyListener {
-        void onBatterySaverPolicyChanged(BatterySaverPolicy policy);
-    }
-
-    public BatterySaverPolicy(Object lock, Context context, BatterySavingStats batterySavingStats) {
-        super(BackgroundThread.getHandler());
-        mLock = lock;
-        mHandler = BackgroundThread.getHandler();
-        mContext = context;
-        mContentResolver = context.getContentResolver();
-        mBatterySavingStats = batterySavingStats;
-    }
-
-    /**
-     * Called by {@link PowerManagerService#systemReady}, *with no lock held.*
-     */
-    public void systemReady() {
-        ConcurrentUtils.wtfIfLockHeld(TAG, mLock);
-
-        mContentResolver.registerContentObserver(Settings.Global.getUriFor(
-                Settings.Global.BATTERY_SAVER_CONSTANTS), false, this);
-        mContentResolver.registerContentObserver(Settings.Global.getUriFor(
-                Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS), false, this);
-
-        final AccessibilityManager acm = mContext.getSystemService(AccessibilityManager.class);
-
-        acm.addAccessibilityStateChangeListener((enabled) -> {
-            synchronized (mLock) {
-                mAccessibilityEnabled = enabled;
-            }
-            refreshSettings();
-        });
-        final boolean enabled = acm.isEnabled();
-        synchronized (mLock) {
-            mAccessibilityEnabled = enabled;
-        }
-        onChange(true, null);
-    }
-
-    public void addListener(BatterySaverPolicyListener listener) {
-        synchronized (mLock) {
-            mListeners.add(listener);
-        }
-    }
-
-    @VisibleForTesting
-    String getGlobalSetting(String key) {
-        return Settings.Global.getString(mContentResolver, key);
-    }
-
-    @VisibleForTesting
-    int getDeviceSpecificConfigResId() {
-        return R.string.config_batterySaverDeviceSpecificConfig;
-    }
-
-    @Override
-    public void onChange(boolean selfChange, Uri uri) {
-        refreshSettings();
-    }
-
-    private void refreshSettings() {
-        final BatterySaverPolicyListener[] listeners;
-        synchronized (mLock) {
-            // Load the non-device-specific setting.
-            final String setting = getGlobalSetting(Settings.Global.BATTERY_SAVER_CONSTANTS);
-
-            // Load the device specific setting.
-            // We first check the global setting, and if it's empty or the string "null" is set,
-            // use the default value from config.xml.
-            String deviceSpecificSetting = getGlobalSetting(
-                    Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS);
-            mDeviceSpecificSettingsSource =
-                    Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS;
-
-            if (TextUtils.isEmpty(deviceSpecificSetting) || "null".equals(deviceSpecificSetting)) {
-                deviceSpecificSetting =
-                        mContext.getString(getDeviceSpecificConfigResId());
-                mDeviceSpecificSettingsSource = "(overlay)";
-            }
-
-            // Update.
-            updateConstantsLocked(setting, deviceSpecificSetting);
-
-            listeners = mListeners.toArray(new BatterySaverPolicyListener[mListeners.size()]);
-        }
-
-        // Notify the listeners.
-        mHandler.post(() -> {
-            for (BatterySaverPolicyListener listener : listeners) {
-                listener.onBatterySaverPolicyChanged(this);
-            }
-        });
-    }
-
-    @GuardedBy("mLock")
-    @VisibleForTesting
-    void updateConstantsLocked(final String setting, final String deviceSpecificSetting) {
-        mSettings = setting;
-        mDeviceSpecificSettings = deviceSpecificSetting;
-
-        if (DEBUG) {
-            Slog.i(TAG, "mSettings=" + mSettings);
-            Slog.i(TAG, "mDeviceSpecificSettings=" + mDeviceSpecificSettings);
-        }
-
-        final KeyValueListParser parser = new KeyValueListParser(',');
-
-        // Device-specific parameters.
-        try {
-            parser.setString(deviceSpecificSetting);
-        } catch (IllegalArgumentException e) {
-            Slog.wtf(TAG, "Bad device specific battery saver constants: "
-                    + deviceSpecificSetting);
-        }
-
-        final String cpuFreqInteractive = parser.getString(KEY_CPU_FREQ_INTERACTIVE, "");
-        final String cpuFreqNoninteractive = parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "");
-
-        // Non-device-specific parameters.
-        try {
-            parser.setString(setting);
-        } catch (IllegalArgumentException e) {
-            Slog.wtf(TAG, "Bad battery saver constants: " + setting);
-        }
-
-        float adjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR,
-                sDefaultPolicy.adjustBrightnessFactor);
-        boolean deferFullBackup = parser.getBoolean(KEY_FULLBACKUP_DEFERRED,
-                sDefaultPolicy.deferFullBackup);
-        boolean deferKeyValueBackup = parser.getBoolean(KEY_KEYVALUE_DEFERRED,
-                sDefaultPolicy.deferKeyValueBackup);
-        boolean disableAnimation = parser.getBoolean(KEY_ANIMATION_DISABLED,
-                sDefaultPolicy.disableAnimation);
-        boolean disableAod = parser.getBoolean(KEY_AOD_DISABLED, sDefaultPolicy.disableAod);
-        boolean disableLaunchBoost = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED,
-                sDefaultPolicy.disableLaunchBoost);
-        boolean disableOptionalSensors = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED,
-                sDefaultPolicy.disableOptionalSensors);
-        boolean disableSoundTrigger = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED,
-                sDefaultPolicy.disableSoundTrigger);
-        boolean disableVibrationConfig = parser.getBoolean(KEY_VIBRATION_DISABLED,
-                sDefaultPolicy.disableVibration);
-        boolean enableAdjustBrightness = !parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED,
-                !sDefaultPolicy.enableAdjustBrightness);
-        boolean enableDataSaver = !parser.getBoolean(KEY_ACTIVATE_DATASAVER_DISABLED,
-                !sDefaultPolicy.enableDataSaver);
-        boolean enableFirewall = !parser.getBoolean(KEY_ACTIVATE_FIREWALL_DISABLED,
-                !sDefaultPolicy.enableFirewall);
-        boolean enableQuickDoze = parser.getBoolean(KEY_QUICK_DOZE_ENABLED,
-                sDefaultPolicy.enableQuickDoze);
-        boolean forceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY,
-                sDefaultPolicy.forceAllAppsStandby);
-        boolean forceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK,
-                sDefaultPolicy.forceBackgroundCheck);
-        int gpsMode = parser.getInt(KEY_GPS_MODE, sDefaultPolicy.gpsMode);
-        boolean sendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, sDefaultPolicy.sendTronLog);
-
-        mCurrPolicy = new Policy(
-                adjustBrightnessFactor,
-                deferFullBackup,
-                deferKeyValueBackup,
-                disableAnimation,
-                disableAod,
-                disableLaunchBoost,
-                disableOptionalSensors,
-                disableSoundTrigger,
-                /* disableVibration */
-                disableVibrationConfig,
-                enableAdjustBrightness,
-                enableDataSaver,
-                enableFirewall,
-                enableQuickDoze,
-                /* filesForInteractive */
-                (new CpuFrequencies()).parseString(cpuFreqInteractive).toSysFileMap(),
-                /* filesForNoninteractive */
-                (new CpuFrequencies()).parseString(cpuFreqNoninteractive).toSysFileMap(),
-                forceAllAppsStandby,
-                forceBackgroundCheck,
-                gpsMode,
-                sendTronLog
-        );
-
-        // Update the effective policy.
-        mDisableVibrationEffective = mCurrPolicy.disableVibration
-                && !mAccessibilityEnabled; // Don't disable vibration when accessibility is on.
-
-        final StringBuilder sb = new StringBuilder();
-
-        if (mCurrPolicy.forceAllAppsStandby) sb.append("A");
-        if (mCurrPolicy.forceBackgroundCheck) sb.append("B");
-
-        if (mDisableVibrationEffective) sb.append("v");
-        if (mCurrPolicy.disableAnimation) sb.append("a");
-        if (mCurrPolicy.disableSoundTrigger) sb.append("s");
-        if (mCurrPolicy.deferFullBackup) sb.append("F");
-        if (mCurrPolicy.deferKeyValueBackup) sb.append("K");
-        if (mCurrPolicy.enableFirewall) sb.append("f");
-        if (mCurrPolicy.enableDataSaver) sb.append("d");
-        if (mCurrPolicy.enableAdjustBrightness) sb.append("b");
-
-        if (mCurrPolicy.disableLaunchBoost) sb.append("l");
-        if (mCurrPolicy.disableOptionalSensors) sb.append("S");
-        if (mCurrPolicy.disableAod) sb.append("o");
-        if (mCurrPolicy.enableQuickDoze) sb.append("q");
-        if (mCurrPolicy.sendTronLog) sb.append("t");
-
-        sb.append(mCurrPolicy.gpsMode);
-
-        mEventLogKeys = sb.toString();
-
-        mBatterySavingStats.setSendTronLog(mCurrPolicy.sendTronLog);
-    }
-
-    private static class Policy {
-        /**
-         * This is the flag to decide the how much to adjust the screen brightness. This is
-         * the float value from 0 to 1 where 1 means don't change brightness.
-         *
-         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_ADJUST_BRIGHTNESS_FACTOR
-         */
-        public final float adjustBrightnessFactor;
-
-        /**
-         * {@code true} if full backup is deferred in battery saver mode.
-         *
-         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_FULLBACKUP_DEFERRED
-         */
-        public final boolean deferFullBackup;
-
-        /**
-         * {@code true} if key value backup is deferred in battery saver mode.
-         *
-         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_KEYVALUE_DEFERRED
-         */
-        public final boolean deferKeyValueBackup;
-
-        /**
-         * {@code true} if animation is disabled in battery saver mode.
-         *
-         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_ANIMATION_DISABLED
-         */
-        public final boolean disableAnimation;
-
-        /**
-         * {@code true} if AOD is disabled in battery saver mode.
-         */
-        public final boolean disableAod;
-
-        /**
-         * {@code true} if launch boost should be disabled on battery saver.
-         */
-        public final boolean disableLaunchBoost;
-
-        /**
-         * Whether to show non-essential sensors (e.g. edge sensors) or not.
-         */
-        public final boolean disableOptionalSensors;
-
-        /**
-         * {@code true} if sound trigger is disabled in battery saver mode
-         * in battery saver mode.
-         *
-         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_SOUNDTRIGGER_DISABLED
-         */
-        public final boolean disableSoundTrigger;
-
-        /**
-         * {@code true} if vibration is disabled in battery saver mode.
-         *
-         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_VIBRATION_DISABLED
-         */
-        public final boolean disableVibration;
-
-        /**
-         * {@code true} if low power mode brightness adjustment should be turned on in battery saver
-         * mode.
-         *
-         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_ADJUST_BRIGHTNESS_DISABLED
-         */
-        public final boolean enableAdjustBrightness;
-
-        /**
-         * {@code true} if data saver should be turned on in battery saver mode.
-         *
-         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_ACTIVATE_DATASAVER_DISABLED
-         */
-        public final boolean enableDataSaver;
-
-        /**
-         * {@code true} if network policy firewall should be turned on in battery saver mode.
-         *
-         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_ACTIVATE_FIREWALL_DISABLED
-         */
-        public final boolean enableFirewall;
-
-        /**
-         * Whether Quick Doze is enabled or not.
-         */
-        public final boolean enableQuickDoze;
-
-        /**
-         * List of [Filename -> content] that should be written when battery saver is activated
-         * and the device is interactive.
-         *
-         * We use this to change the max CPU frequencies.
-         */
-        public final ArrayMap<String, String> filesForInteractive;
-
-        /**
-         * List of [Filename -> content] that should be written when battery saver is activated
-         * and the device is non-interactive.
-         *
-         * We use this to change the max CPU frequencies.
-         */
-        public final ArrayMap<String, String> filesForNoninteractive;
-
-        /**
-         * Whether to put all apps in the stand-by mode.
-         */
-        public final boolean forceAllAppsStandby;
-
-        /**
-         * Whether to force background check.
-         */
-        public final boolean forceBackgroundCheck;
-
-        /**
-         * This is the flag to decide the gps mode in battery saver mode.
-         *
-         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_GPS_MODE
-         */
-        public final int gpsMode;
-
-        /**
-         * Whether BatterySavingStats should send tron events.
-         */
-        public final boolean sendTronLog;
-
-        Policy(
-                float adjustBrightnessFactor,
-                boolean deferFullBackup,
-                boolean deferKeyValueBackup,
-                boolean disableAnimation,
-                boolean disableAod,
-                boolean disableLaunchBoost,
-                boolean disableOptionalSensors,
-                boolean disableSoundTrigger,
-                boolean disableVibration,
-                boolean enableAdjustBrightness,
-                boolean enableDataSaver,
-                boolean enableFirewall,
-                boolean enableQuickDoze,
-                ArrayMap<String, String> filesForInteractive,
-                ArrayMap<String, String> filesForNoninteractive,
-                boolean forceAllAppsStandby,
-                boolean forceBackgroundCheck,
-                int gpsMode,
-                boolean sendTronLog) {
-
-            this.adjustBrightnessFactor = adjustBrightnessFactor;
-            this.deferFullBackup = deferFullBackup;
-            this.deferKeyValueBackup = deferKeyValueBackup;
-            this.disableAnimation = disableAnimation;
-            this.disableAod = disableAod;
-            this.disableLaunchBoost = disableLaunchBoost;
-            this.disableOptionalSensors = disableOptionalSensors;
-            this.disableSoundTrigger = disableSoundTrigger;
-            this.disableVibration = disableVibration;
-            this.enableAdjustBrightness = enableAdjustBrightness;
-            this.enableDataSaver = enableDataSaver;
-            this.enableFirewall = enableFirewall;
-            this.enableQuickDoze = enableQuickDoze;
-            this.filesForInteractive = filesForInteractive;
-            this.filesForNoninteractive = filesForNoninteractive;
-            this.forceAllAppsStandby = forceAllAppsStandby;
-            this.forceBackgroundCheck = forceBackgroundCheck;
-            this.gpsMode = gpsMode;
-            this.sendTronLog = sendTronLog;
-        }
-    }
-
-    /**
-     * Get the {@link PowerSaveState} based on {@paramref type} and {@paramref realMode}.
-     * The result will have {@link PowerSaveState#batterySaverEnabled} and some other
-     * parameters when necessary.
-     *
-     * @param type     type of the service, one of {@link ServiceType}
-     * @param realMode whether the battery saver is on by default
-     * @return State data that contains battery saver data
-     */
-    public PowerSaveState getBatterySaverPolicy(@ServiceType int type, boolean realMode) {
-        synchronized (mLock) {
-            final PowerSaveState.Builder builder = new PowerSaveState.Builder()
-                    .setGlobalBatterySaverEnabled(realMode);
-            if (!realMode) {
-                return builder.setBatterySaverEnabled(realMode)
-                        .build();
-            }
-            switch (type) {
-                case ServiceType.GPS:
-                    return builder.setBatterySaverEnabled(realMode)
-                            .setGpsMode(mCurrPolicy.gpsMode)
-                            .build();
-                case ServiceType.ANIMATION:
-                    return builder.setBatterySaverEnabled(mCurrPolicy.disableAnimation)
-                            .build();
-                case ServiceType.FULL_BACKUP:
-                    return builder.setBatterySaverEnabled(mCurrPolicy.deferFullBackup)
-                            .build();
-                case ServiceType.KEYVALUE_BACKUP:
-                    return builder.setBatterySaverEnabled(mCurrPolicy.deferKeyValueBackup)
-                            .build();
-                case ServiceType.NETWORK_FIREWALL:
-                    return builder.setBatterySaverEnabled(mCurrPolicy.enableFirewall)
-                            .build();
-                case ServiceType.SCREEN_BRIGHTNESS:
-                    return builder.setBatterySaverEnabled(mCurrPolicy.enableAdjustBrightness)
-                            .setBrightnessFactor(mCurrPolicy.adjustBrightnessFactor)
-                            .build();
-                case ServiceType.DATA_SAVER:
-                    return builder.setBatterySaverEnabled(mCurrPolicy.enableDataSaver)
-                            .build();
-                case ServiceType.SOUND:
-                    return builder.setBatterySaverEnabled(mCurrPolicy.disableSoundTrigger)
-                            .build();
-                case ServiceType.VIBRATION:
-                    return builder.setBatterySaverEnabled(mDisableVibrationEffective)
-                            .build();
-                case ServiceType.FORCE_ALL_APPS_STANDBY:
-                    return builder.setBatterySaverEnabled(mCurrPolicy.forceAllAppsStandby)
-                            .build();
-                case ServiceType.FORCE_BACKGROUND_CHECK:
-                    return builder.setBatterySaverEnabled(mCurrPolicy.forceBackgroundCheck)
-                            .build();
-                case ServiceType.OPTIONAL_SENSORS:
-                    return builder.setBatterySaverEnabled(mCurrPolicy.disableOptionalSensors)
-                            .build();
-                case ServiceType.AOD:
-                    return builder.setBatterySaverEnabled(mCurrPolicy.disableAod)
-                            .build();
-                case ServiceType.QUICK_DOZE:
-                    return builder.setBatterySaverEnabled(mCurrPolicy.enableQuickDoze)
-                            .build();
-                default:
-                    return builder.setBatterySaverEnabled(realMode)
-                            .build();
-            }
-        }
-    }
-
-    public int getGpsMode() {
-        synchronized (mLock) {
-            return mCurrPolicy.gpsMode;
-        }
-    }
-
-    public ArrayMap<String, String> getFileValues(boolean interactive) {
-        synchronized (mLock) {
-            return interactive ? mCurrPolicy.filesForInteractive
-                    : mCurrPolicy.filesForNoninteractive;
-        }
-    }
-
-    public boolean isLaunchBoostDisabled() {
-        synchronized (mLock) {
-            return mCurrPolicy.disableLaunchBoost;
-        }
-    }
-
-    public String toEventLogString() {
-        synchronized (mLock) {
-            return mEventLogKeys;
-        }
-    }
-
-    public void dump(PrintWriter pw) {
-        synchronized (mLock) {
-            pw.println();
-            mBatterySavingStats.dump(pw, "");
-
-            pw.println();
-            pw.println("Battery saver policy (*NOTE* they only apply when battery saver is ON):");
-            pw.println("  Settings: " + Settings.Global.BATTERY_SAVER_CONSTANTS);
-            pw.println("    value: " + mSettings);
-            pw.println("  Settings: " + mDeviceSpecificSettingsSource);
-            pw.println("    value: " + mDeviceSpecificSettings);
-
-            pw.println();
-            pw.println("  mAccessibilityEnabled=" + mAccessibilityEnabled);
-            pw.println("  " + KEY_VIBRATION_DISABLED + ":config=" + mCurrPolicy.disableVibration);
-            pw.println("  " + KEY_VIBRATION_DISABLED + ":effective=" + mDisableVibrationEffective);
-            pw.println("  " + KEY_ANIMATION_DISABLED + "=" + mCurrPolicy.disableAnimation);
-            pw.println("  " + KEY_FULLBACKUP_DEFERRED + "=" + mCurrPolicy.deferFullBackup);
-            pw.println("  " + KEY_KEYVALUE_DEFERRED + "=" + mCurrPolicy.deferKeyValueBackup);
-            pw.println("  " + KEY_ACTIVATE_FIREWALL_DISABLED + "=" + !mCurrPolicy.enableFirewall);
-            pw.println("  " + KEY_ACTIVATE_DATASAVER_DISABLED + "=" + !mCurrPolicy.enableDataSaver);
-            pw.println("  " + KEY_LAUNCH_BOOST_DISABLED + "=" + mCurrPolicy.disableLaunchBoost);
-            pw.println("  " + KEY_ADJUST_BRIGHTNESS_DISABLED + "="
-                    + !mCurrPolicy.enableAdjustBrightness);
-            pw.println(
-                    "  " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mCurrPolicy.adjustBrightnessFactor);
-            pw.println("  " + KEY_GPS_MODE + "=" + mCurrPolicy.gpsMode);
-            pw.println("  " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mCurrPolicy.forceAllAppsStandby);
-            pw.println("  " + KEY_FORCE_BACKGROUND_CHECK + "=" + mCurrPolicy.forceBackgroundCheck);
-            pw.println("  " + KEY_OPTIONAL_SENSORS_DISABLED + "="
-                    + mCurrPolicy.disableOptionalSensors);
-            pw.println("  " + KEY_AOD_DISABLED + "=" + mCurrPolicy.disableAod);
-            pw.println("  " + KEY_SOUNDTRIGGER_DISABLED + "=" + mCurrPolicy.disableSoundTrigger);
-            pw.println("  " + KEY_QUICK_DOZE_ENABLED + "=" + mCurrPolicy.enableQuickDoze);
-            pw.println("  " + KEY_SEND_TRON_LOG + "=" + mCurrPolicy.sendTronLog);
-            pw.println();
-
-            pw.print("  Interactive File values:\n");
-            dumpMap(pw, "    ", mCurrPolicy.filesForInteractive);
-            pw.println();
-
-            pw.print("  Noninteractive File values:\n");
-            dumpMap(pw, "    ", mCurrPolicy.filesForNoninteractive);
-        }
-    }
-
-    private void dumpMap(PrintWriter pw, String prefix, ArrayMap<String, String> map) {
-        if (map == null) {
-            return;
-        }
-        final int size = map.size();
-        for (int i = 0; i < size; i++) {
-            pw.print(prefix);
-            pw.print(map.keyAt(i));
-            pw.print(": '");
-            pw.print(map.valueAt(i));
-            pw.println("'");
-        }
-    }
-
-    @VisibleForTesting
-    public void setAccessibilityEnabledForTest(boolean enabled) {
-        synchronized (mLock) {
-            mAccessibilityEnabled = enabled;
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 5adc248..c3f20aa 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -755,9 +755,10 @@
     };
 
     /**
-     * Plays the wireless charging sound for both wireless and non-wireless charging
+     * If enabled, plays a sound and/or vibration when wireless or non-wireless charging has started
      */
-    private void playChargingStartedSound(@UserIdInt int userId) {
+    private void playChargingStartedFeedback(@UserIdInt int userId) {
+        playChargingStartedVibration(userId);
         final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.CHARGING_STARTED_SOUND);
         if (isChargingFeedbackEnabled(userId) && soundPath != null) {
@@ -773,8 +774,7 @@
     }
 
     private void showWirelessChargingStarted(int batteryLevel, @UserIdInt int userId) {
-        playWirelessChargingVibration(userId);
-        playChargingStartedSound(userId);
+        playChargingStartedFeedback(userId);
         if (mStatusBarManagerInternal != null) {
             mStatusBarManagerInternal.showChargingAnimation(batteryLevel);
         }
@@ -782,7 +782,7 @@
     }
 
     private void showWiredChargingStarted(@UserIdInt int userId) {
-        playChargingStartedSound(userId);
+        playChargingStartedFeedback(userId);
         mSuspendBlocker.release();
     }
 
@@ -790,7 +790,7 @@
         mTrustManager.setDeviceLockedForUser(userId, true /*locked*/);
     }
 
-    private void playWirelessChargingVibration(@UserIdInt int userId) {
+    private void playChargingStartedVibration(@UserIdInt int userId) {
         final boolean vibrateEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.CHARGING_VIBRATION_ENABLED, 1, userId) != 0;
         if (vibrateEnabled && isChargingFeedbackEnabled(userId)) {
diff --git a/services/core/java/com/android/server/power/OWNERS b/services/core/java/com/android/server/power/OWNERS
index 244ccb6..5cbe74c 100644
--- a/services/core/java/com/android/server/power/OWNERS
+++ b/services/core/java/com/android/server/power/OWNERS
@@ -1,6 +1,4 @@
 michaelwr@google.com
 santoscordon@google.com
 
-per-file BatterySaverPolicy.java=omakoto@google.com
-per-file ShutdownThread.java=fkupolov@google.com
-per-file ThermalManagerService.java=wvw@google.com
\ No newline at end of file
+per-file ThermalManagerService.java=wvw@google.com
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 565bb706..a027873 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -96,6 +96,7 @@
 import com.android.server.lights.LightsManager;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.power.batterysaver.BatterySaverController;
+import com.android.server.power.batterysaver.BatterySaverPolicy;
 import com.android.server.power.batterysaver.BatterySaverStateMachine;
 import com.android.server.power.batterysaver.BatterySavingStats;
 
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 02689a9..7d03d82 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -134,10 +134,14 @@
             if (!halConnected) {
                 mHalWrapper = new ThermalHal20Wrapper();
                 halConnected = mHalWrapper.connectToHal();
-                if (!halConnected) {
-                    mHalWrapper = new ThermalHal11Wrapper();
-                    halConnected = mHalWrapper.connectToHal();
-                }
+            }
+            if (!halConnected) {
+                mHalWrapper = new ThermalHal11Wrapper();
+                halConnected = mHalWrapper.connectToHal();
+            }
+            if (!halConnected) {
+                mHalWrapper = new ThermalHal10Wrapper();
+                halConnected = mHalWrapper.connectToHal();
             }
             mHalWrapper.setCallback(this::onTemperatureChangedCallback);
             if (!halConnected) {
@@ -616,6 +620,81 @@
         }
     }
 
+
+    static class ThermalHal10Wrapper extends ThermalHalWrapper {
+        /** Proxy object for the Thermal HAL 1.0 service. */
+        @GuardedBy("mHalLock")
+        private android.hardware.thermal.V1_0.IThermal mThermalHal10 = null;
+
+        @Override
+        protected List<Temperature> getCurrentTemperatures(boolean shouldFilter,
+                int type) {
+            synchronized (mHalLock) {
+                List<Temperature> ret = new ArrayList<>();
+                if (mThermalHal10 == null) {
+                    return ret;
+                }
+                try {
+                    mThermalHal10.getTemperatures(
+                            (ThermalStatus status,
+                                    ArrayList<android.hardware.thermal.V1_0.Temperature>
+                                            temperatures) -> {
+                                if (ThermalStatusCode.SUCCESS == status.code) {
+                                    for (android.hardware.thermal.V1_0.Temperature
+                                            temperature : temperatures) {
+                                        if (shouldFilter && type != temperature.type) {
+                                            continue;
+                                        }
+                                        // Thermal HAL 1.0 doesn't report current throttling status
+                                        ret.add(new Temperature(
+                                                temperature.currentValue, temperature.type,
+                                                temperature.name,
+                                                Temperature.THROTTLING_NONE));
+                                    }
+                                } else {
+                                    Slog.e(TAG,
+                                            "Couldn't get temperatures because of HAL error: "
+                                                    + status.debugMessage);
+                                }
+
+                            });
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e);
+                    connectToHal();
+                }
+                return ret;
+            }
+        }
+
+        @Override
+        protected boolean connectToHal() {
+            synchronized (mHalLock) {
+                try {
+                    mThermalHal10 = android.hardware.thermal.V1_0.IThermal.getService();
+                    mThermalHal10.linkToDeath(new DeathRecipient(),
+                            THERMAL_HAL_DEATH_COOKIE);
+                    Slog.i(TAG,
+                            "Thermal HAL 1.0 service connected, no thermal call back will be "
+                                    + "called due to legacy API.");
+                } catch (NoSuchElementException | RemoteException e) {
+                    Slog.e(TAG,
+                            "Thermal HAL 1.0 service not connected.");
+                    mThermalHal10 = null;
+                }
+                return (mThermalHal10 != null);
+            }
+        }
+
+        @Override
+        protected void dump(PrintWriter pw, String prefix) {
+            synchronized (mHalLock) {
+                pw.print(prefix);
+                pw.println("ThermalHAL 1.0 connected: " + (mThermalHal10 != null ? "yes"
+                        : "no"));
+            }
+        }
+    }
+
     static class ThermalHal11Wrapper extends ThermalHalWrapper {
         /** Proxy object for the Thermal HAL 1.1 service. */
         @GuardedBy("mHalLock")
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index 6400c88..ab2807a 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -35,13 +35,13 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
-import com.android.server.power.BatterySaverPolicy;
-import com.android.server.power.BatterySaverPolicy.BatterySaverPolicyListener;
 import com.android.server.power.PowerManagerService;
+import com.android.server.power.batterysaver.BatterySaverPolicy.BatterySaverPolicyListener;
 import com.android.server.power.batterysaver.BatterySavingStats.BatterySaverState;
 import com.android.server.power.batterysaver.BatterySavingStats.DozeState;
 import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState;
@@ -104,6 +104,7 @@
     public static final int REASON_SETTING_CHANGED = 8;
     public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON = 9;
     public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF = 10;
+    public static final int REASON_STICKY_RESTORE_OFF = 13;
 
     /**
      * Plugin interface. All methods are guaranteed to be called on the same (handler) thread.
@@ -158,10 +159,9 @@
         mBatterySavingStats = batterySavingStats;
 
         // Initialize plugins.
-        final ArrayList<Plugin> plugins = new ArrayList<>();
-        plugins.add(new BatterySaverLocationPlugin(mContext));
-
-        mPlugins = plugins.toArray(new Plugin[plugins.size()]);
+        mPlugins = new Plugin[] {
+                new BatterySaverLocationPlugin(mContext)
+        };
     }
 
     /**
@@ -217,7 +217,7 @@
             super(looper);
         }
 
-        public void postStateChanged(boolean sendBroadcast, int reason) {
+        void postStateChanged(boolean sendBroadcast, int reason) {
             obtainMessage(MSG_STATE_CHANGED, sendBroadcast ?
                     ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, reason).sendToTarget();
         }
@@ -244,9 +244,8 @@
         }
     }
 
-    /**
-     * Called by {@link PowerManagerService} to update the battery saver state.
-     */
+    /** Enable or disable full battery saver. */
+    @VisibleForTesting
     public void enableBatterySaver(boolean enable, int reason) {
         synchronized (mLock) {
             if (mEnabled == enable) {
@@ -311,7 +310,7 @@
                     reason);
             mPreviouslyEnabled = mEnabled;
 
-            listeners = mListeners.toArray(new LowPowerModeListener[mListeners.size()]);
+            listeners = mListeners.toArray(new LowPowerModeListener[0]);
 
             enabled = mEnabled;
             mIsInteractive = isInteractive;
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
new file mode 100644
index 0000000..48a041e
--- /dev/null
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
@@ -0,0 +1,715 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.power.batterysaver;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
+import android.os.PowerSaveState;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ConcurrentUtils;
+import com.android.server.power.PowerManagerService;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class to decide whether to turn on battery saver mode for specific services.
+ *
+ * IMPORTANT: This class shares the power manager lock, which is very low in the lock hierarchy.
+ * Do not call out with the lock held, such as AccessibilityManager. (Settings provider is okay.)
+ *
+ * Test: atest com.android.server.power.batterysaver.BatterySaverPolicyTest.java
+ */
+public class BatterySaverPolicy extends ContentObserver {
+    private static final String TAG = "BatterySaverPolicy";
+
+    public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE.
+
+    private static final String KEY_GPS_MODE = "gps_mode";
+    private static final String KEY_VIBRATION_DISABLED = "vibration_disabled";
+    private static final String KEY_ANIMATION_DISABLED = "animation_disabled";
+    private static final String KEY_SOUNDTRIGGER_DISABLED = "soundtrigger_disabled";
+
+    /**
+     * Disable turning on the network firewall when Battery Saver is turned on.
+     * If set to false, the firewall WILL be turned on when Battery Saver is turned on.
+     * If set to true, the firewall WILL NOT be turned on when Battery Saver is turned on.
+     */
+    private static final String KEY_ACTIVATE_FIREWALL_DISABLED = "firewall_disabled";
+
+    /**
+     * Disable turning on the special low power screen brightness dimming when Battery Saver is
+     * turned on.
+     * If set to false, the screen brightness dimming WILL be turned on by Battery Saver.
+     * If set to true, the screen brightness WILL NOT be turned on by Battery Saver.
+     */
+    private static final String KEY_ADJUST_BRIGHTNESS_DISABLED = "adjust_brightness_disabled";
+
+    /**
+     * Disable turning on Data Saver when Battery Saver is turned on.
+     * If set to false, Data Saver WILL be turned on when Battery Saver is turned on.
+     * If set to true, Data Saver WILL NOT be turned on when Battery Saver is turned on.
+     */
+    private static final String KEY_ACTIVATE_DATASAVER_DISABLED = "datasaver_disabled";
+    private static final String KEY_LAUNCH_BOOST_DISABLED = "launch_boost_disabled";
+    private static final String KEY_ADJUST_BRIGHTNESS_FACTOR = "adjust_brightness_factor";
+    private static final String KEY_FULLBACKUP_DEFERRED = "fullbackup_deferred";
+    private static final String KEY_KEYVALUE_DEFERRED = "keyvaluebackup_deferred";
+    private static final String KEY_FORCE_ALL_APPS_STANDBY = "force_all_apps_standby";
+    private static final String KEY_FORCE_BACKGROUND_CHECK = "force_background_check";
+    private static final String KEY_OPTIONAL_SENSORS_DISABLED = "optional_sensors_disabled";
+    private static final String KEY_AOD_DISABLED = "aod_disabled";
+    // Go into deep Doze as soon as the screen turns off.
+    private static final String KEY_QUICK_DOZE_ENABLED = "quick_doze_enabled";
+    private static final String KEY_SEND_TRON_LOG = "send_tron_log";
+
+    private static final String KEY_CPU_FREQ_INTERACTIVE = "cpufreq-i";
+    private static final String KEY_CPU_FREQ_NONINTERACTIVE = "cpufreq-n";
+
+    private static final Policy sDefaultPolicy = new Policy(
+            0.5f,  /* adjustBrightnessFactor */
+            true,  /* deferFullBackup */
+            true,  /* deferKeyValueBackup */
+            false, /* disableAnimation */
+            true,  /* disableAod */
+            true,  /* disableLaunchBoost */
+            true,  /* disableOptionalSensors */
+            true,  /* disableSoundTrigger */
+            true,  /* disableVibration */
+            false, /* enableAdjustBrightness */
+            false, /* enableDataSaver */
+            true,  /* enableFirewall */
+            true, /* enableQuickDoze */
+            new ArrayMap<>(), /* filesForInteractive */
+            new ArrayMap<>(), /* filesForNoninteractive */
+            true, /* forceAllAppsStandby */
+            true, /* forceBackgroundCheck */
+            PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF, /* gpsMode */
+            false /* sendTronLog */
+    );
+
+    private final Object mLock;
+    private final Handler mHandler;
+
+    @GuardedBy("mLock")
+    private String mSettings;
+
+    @GuardedBy("mLock")
+    private String mDeviceSpecificSettings;
+
+    @GuardedBy("mLock")
+    private String mDeviceSpecificSettingsSource; // For dump() only.
+
+    /**
+     * A short string describing which battery saver is now enabled, which we dump in the eventlog.
+     */
+    @GuardedBy("mLock")
+    private String mEventLogKeys;
+
+    /**
+     * Whether vibration should *really* be disabled -- i.e. {@link Policy#disableVibration}
+     * is true *and* {@link #mAccessibilityEnabled} is false.
+     */
+    @GuardedBy("mLock")
+    private boolean mDisableVibrationEffective;
+
+    /**
+     * Whether accessibility is currently enabled or not.
+     */
+    @GuardedBy("mLock")
+    private boolean mAccessibilityEnabled;
+
+    @GuardedBy("mLock")
+    private Policy mCurrPolicy = sDefaultPolicy;
+
+    private final Context mContext;
+    private final ContentResolver mContentResolver;
+    private final BatterySavingStats mBatterySavingStats;
+
+    @GuardedBy("mLock")
+    private final List<BatterySaverPolicyListener> mListeners = new ArrayList<>();
+
+    public interface BatterySaverPolicyListener {
+        void onBatterySaverPolicyChanged(BatterySaverPolicy policy);
+    }
+
+    public BatterySaverPolicy(Object lock, Context context, BatterySavingStats batterySavingStats) {
+        super(BackgroundThread.getHandler());
+        mLock = lock;
+        mHandler = BackgroundThread.getHandler();
+        mContext = context;
+        mContentResolver = context.getContentResolver();
+        mBatterySavingStats = batterySavingStats;
+    }
+
+    /**
+     * Called by {@link PowerManagerService#systemReady}, *with no lock held.*
+     */
+    public void systemReady() {
+        ConcurrentUtils.wtfIfLockHeld(TAG, mLock);
+
+        mContentResolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.BATTERY_SAVER_CONSTANTS), false, this);
+        mContentResolver.registerContentObserver(Settings.Global.getUriFor(
+                Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS), false, this);
+
+        final AccessibilityManager acm = mContext.getSystemService(AccessibilityManager.class);
+
+        acm.addAccessibilityStateChangeListener((enabled) -> {
+            synchronized (mLock) {
+                mAccessibilityEnabled = enabled;
+            }
+            refreshSettings();
+        });
+        final boolean enabled = acm.isEnabled();
+        synchronized (mLock) {
+            mAccessibilityEnabled = enabled;
+        }
+        onChange(true, null);
+    }
+
+    @VisibleForTesting
+    public void addListener(BatterySaverPolicyListener listener) {
+        synchronized (mLock) {
+            // TODO: set this in the constructor instead
+            mListeners.add(listener);
+        }
+    }
+
+    @VisibleForTesting
+    String getGlobalSetting(String key) {
+        return Settings.Global.getString(mContentResolver, key);
+    }
+
+    @VisibleForTesting
+    int getDeviceSpecificConfigResId() {
+        return R.string.config_batterySaverDeviceSpecificConfig;
+    }
+
+    @Override
+    public void onChange(boolean selfChange, Uri uri) {
+        refreshSettings();
+    }
+
+    private void refreshSettings() {
+        final BatterySaverPolicyListener[] listeners;
+        synchronized (mLock) {
+            // Load the non-device-specific setting.
+            final String setting = getGlobalSetting(Settings.Global.BATTERY_SAVER_CONSTANTS);
+
+            // Load the device specific setting.
+            // We first check the global setting, and if it's empty or the string "null" is set,
+            // use the default value from config.xml.
+            String deviceSpecificSetting = getGlobalSetting(
+                    Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS);
+            mDeviceSpecificSettingsSource =
+                    Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS;
+
+            if (TextUtils.isEmpty(deviceSpecificSetting) || "null".equals(deviceSpecificSetting)) {
+                deviceSpecificSetting =
+                        mContext.getString(getDeviceSpecificConfigResId());
+                mDeviceSpecificSettingsSource = "(overlay)";
+            }
+
+            // Update.
+            updateConstantsLocked(setting, deviceSpecificSetting);
+
+            listeners = mListeners.toArray(new BatterySaverPolicyListener[0]);
+        }
+
+        // Notify the listeners.
+        mHandler.post(() -> {
+            for (BatterySaverPolicyListener listener : listeners) {
+                listener.onBatterySaverPolicyChanged(this);
+            }
+        });
+    }
+
+    @GuardedBy("mLock")
+    @VisibleForTesting
+    void updateConstantsLocked(final String setting, final String deviceSpecificSetting) {
+        mSettings = setting;
+        mDeviceSpecificSettings = deviceSpecificSetting;
+
+        if (DEBUG) {
+            Slog.i(TAG, "mSettings=" + mSettings);
+            Slog.i(TAG, "mDeviceSpecificSettings=" + mDeviceSpecificSettings);
+        }
+
+        final KeyValueListParser parser = new KeyValueListParser(',');
+
+        // Device-specific parameters.
+        try {
+            parser.setString(deviceSpecificSetting);
+        } catch (IllegalArgumentException e) {
+            Slog.wtf(TAG, "Bad device specific battery saver constants: "
+                    + deviceSpecificSetting);
+        }
+
+        final String cpuFreqInteractive = parser.getString(KEY_CPU_FREQ_INTERACTIVE, "");
+        final String cpuFreqNoninteractive = parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "");
+
+        // Non-device-specific parameters.
+        try {
+            parser.setString(setting);
+        } catch (IllegalArgumentException e) {
+            Slog.wtf(TAG, "Bad battery saver constants: " + setting);
+        }
+
+        float adjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR,
+                sDefaultPolicy.adjustBrightnessFactor);
+        boolean deferFullBackup = parser.getBoolean(KEY_FULLBACKUP_DEFERRED,
+                sDefaultPolicy.deferFullBackup);
+        boolean deferKeyValueBackup = parser.getBoolean(KEY_KEYVALUE_DEFERRED,
+                sDefaultPolicy.deferKeyValueBackup);
+        boolean disableAnimation = parser.getBoolean(KEY_ANIMATION_DISABLED,
+                sDefaultPolicy.disableAnimation);
+        boolean disableAod = parser.getBoolean(KEY_AOD_DISABLED, sDefaultPolicy.disableAod);
+        boolean disableLaunchBoost = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED,
+                sDefaultPolicy.disableLaunchBoost);
+        boolean disableOptionalSensors = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED,
+                sDefaultPolicy.disableOptionalSensors);
+        boolean disableSoundTrigger = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED,
+                sDefaultPolicy.disableSoundTrigger);
+        boolean disableVibrationConfig = parser.getBoolean(KEY_VIBRATION_DISABLED,
+                sDefaultPolicy.disableVibration);
+        boolean enableAdjustBrightness = !parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED,
+                !sDefaultPolicy.enableAdjustBrightness);
+        boolean enableDataSaver = !parser.getBoolean(KEY_ACTIVATE_DATASAVER_DISABLED,
+                !sDefaultPolicy.enableDataSaver);
+        boolean enableFirewall = !parser.getBoolean(KEY_ACTIVATE_FIREWALL_DISABLED,
+                !sDefaultPolicy.enableFirewall);
+        boolean enableQuickDoze = parser.getBoolean(KEY_QUICK_DOZE_ENABLED,
+                sDefaultPolicy.enableQuickDoze);
+        boolean forceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY,
+                sDefaultPolicy.forceAllAppsStandby);
+        boolean forceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK,
+                sDefaultPolicy.forceBackgroundCheck);
+        int gpsMode = parser.getInt(KEY_GPS_MODE, sDefaultPolicy.gpsMode);
+        boolean sendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, sDefaultPolicy.sendTronLog);
+
+        mCurrPolicy = new Policy(
+                adjustBrightnessFactor,
+                deferFullBackup,
+                deferKeyValueBackup,
+                disableAnimation,
+                disableAod,
+                disableLaunchBoost,
+                disableOptionalSensors,
+                disableSoundTrigger,
+                /* disableVibration */
+                disableVibrationConfig,
+                enableAdjustBrightness,
+                enableDataSaver,
+                enableFirewall,
+                enableQuickDoze,
+                /* filesForInteractive */
+                (new CpuFrequencies()).parseString(cpuFreqInteractive).toSysFileMap(),
+                /* filesForNoninteractive */
+                (new CpuFrequencies()).parseString(cpuFreqNoninteractive).toSysFileMap(),
+                forceAllAppsStandby,
+                forceBackgroundCheck,
+                gpsMode,
+                sendTronLog
+        );
+
+        // Update the effective policy.
+        mDisableVibrationEffective = mCurrPolicy.disableVibration
+                && !mAccessibilityEnabled; // Don't disable vibration when accessibility is on.
+
+        final StringBuilder sb = new StringBuilder();
+
+        if (mCurrPolicy.forceAllAppsStandby) sb.append("A");
+        if (mCurrPolicy.forceBackgroundCheck) sb.append("B");
+
+        if (mDisableVibrationEffective) sb.append("v");
+        if (mCurrPolicy.disableAnimation) sb.append("a");
+        if (mCurrPolicy.disableSoundTrigger) sb.append("s");
+        if (mCurrPolicy.deferFullBackup) sb.append("F");
+        if (mCurrPolicy.deferKeyValueBackup) sb.append("K");
+        if (mCurrPolicy.enableFirewall) sb.append("f");
+        if (mCurrPolicy.enableDataSaver) sb.append("d");
+        if (mCurrPolicy.enableAdjustBrightness) sb.append("b");
+
+        if (mCurrPolicy.disableLaunchBoost) sb.append("l");
+        if (mCurrPolicy.disableOptionalSensors) sb.append("S");
+        if (mCurrPolicy.disableAod) sb.append("o");
+        if (mCurrPolicy.enableQuickDoze) sb.append("q");
+        if (mCurrPolicy.sendTronLog) sb.append("t");
+
+        sb.append(mCurrPolicy.gpsMode);
+
+        mEventLogKeys = sb.toString();
+
+        mBatterySavingStats.setSendTronLog(mCurrPolicy.sendTronLog);
+    }
+
+    private static class Policy {
+        /**
+         * This is the flag to decide the how much to adjust the screen brightness. This is
+         * the float value from 0 to 1 where 1 means don't change brightness.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_ADJUST_BRIGHTNESS_FACTOR
+         */
+        public final float adjustBrightnessFactor;
+
+        /**
+         * {@code true} if full backup is deferred in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_FULLBACKUP_DEFERRED
+         */
+        public final boolean deferFullBackup;
+
+        /**
+         * {@code true} if key value backup is deferred in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_KEYVALUE_DEFERRED
+         */
+        public final boolean deferKeyValueBackup;
+
+        /**
+         * {@code true} if animation is disabled in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_ANIMATION_DISABLED
+         */
+        public final boolean disableAnimation;
+
+        /**
+         * {@code true} if AOD is disabled in battery saver mode.
+         */
+        public final boolean disableAod;
+
+        /**
+         * {@code true} if launch boost should be disabled on battery saver.
+         */
+        public final boolean disableLaunchBoost;
+
+        /**
+         * Whether to show non-essential sensors (e.g. edge sensors) or not.
+         */
+        public final boolean disableOptionalSensors;
+
+        /**
+         * {@code true} if sound trigger is disabled in battery saver mode
+         * in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_SOUNDTRIGGER_DISABLED
+         */
+        public final boolean disableSoundTrigger;
+
+        /**
+         * {@code true} if vibration is disabled in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_VIBRATION_DISABLED
+         */
+        public final boolean disableVibration;
+
+        /**
+         * {@code true} if low power mode brightness adjustment should be turned on in battery saver
+         * mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_ADJUST_BRIGHTNESS_DISABLED
+         */
+        public final boolean enableAdjustBrightness;
+
+        /**
+         * {@code true} if data saver should be turned on in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_ACTIVATE_DATASAVER_DISABLED
+         */
+        public final boolean enableDataSaver;
+
+        /**
+         * {@code true} if network policy firewall should be turned on in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_ACTIVATE_FIREWALL_DISABLED
+         */
+        public final boolean enableFirewall;
+
+        /**
+         * Whether Quick Doze is enabled or not.
+         */
+        public final boolean enableQuickDoze;
+
+        /**
+         * List of [Filename -> content] that should be written when battery saver is activated
+         * and the device is interactive.
+         *
+         * We use this to change the max CPU frequencies.
+         */
+        public final ArrayMap<String, String> filesForInteractive;
+
+        /**
+         * List of [Filename -> content] that should be written when battery saver is activated
+         * and the device is non-interactive.
+         *
+         * We use this to change the max CPU frequencies.
+         */
+        public final ArrayMap<String, String> filesForNoninteractive;
+
+        /**
+         * Whether to put all apps in the stand-by mode.
+         */
+        public final boolean forceAllAppsStandby;
+
+        /**
+         * Whether to force background check.
+         */
+        public final boolean forceBackgroundCheck;
+
+        /**
+         * This is the flag to decide the gps mode in battery saver mode.
+         *
+         * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+         * @see #KEY_GPS_MODE
+         */
+        public final int gpsMode;
+
+        /**
+         * Whether BatterySavingStats should send tron events.
+         */
+        public final boolean sendTronLog;
+
+        Policy(
+                float adjustBrightnessFactor,
+                boolean deferFullBackup,
+                boolean deferKeyValueBackup,
+                boolean disableAnimation,
+                boolean disableAod,
+                boolean disableLaunchBoost,
+                boolean disableOptionalSensors,
+                boolean disableSoundTrigger,
+                boolean disableVibration,
+                boolean enableAdjustBrightness,
+                boolean enableDataSaver,
+                boolean enableFirewall,
+                boolean enableQuickDoze,
+                ArrayMap<String, String> filesForInteractive,
+                ArrayMap<String, String> filesForNoninteractive,
+                boolean forceAllAppsStandby,
+                boolean forceBackgroundCheck,
+                int gpsMode,
+                boolean sendTronLog) {
+
+            this.adjustBrightnessFactor = adjustBrightnessFactor;
+            this.deferFullBackup = deferFullBackup;
+            this.deferKeyValueBackup = deferKeyValueBackup;
+            this.disableAnimation = disableAnimation;
+            this.disableAod = disableAod;
+            this.disableLaunchBoost = disableLaunchBoost;
+            this.disableOptionalSensors = disableOptionalSensors;
+            this.disableSoundTrigger = disableSoundTrigger;
+            this.disableVibration = disableVibration;
+            this.enableAdjustBrightness = enableAdjustBrightness;
+            this.enableDataSaver = enableDataSaver;
+            this.enableFirewall = enableFirewall;
+            this.enableQuickDoze = enableQuickDoze;
+            this.filesForInteractive = filesForInteractive;
+            this.filesForNoninteractive = filesForNoninteractive;
+            this.forceAllAppsStandby = forceAllAppsStandby;
+            this.forceBackgroundCheck = forceBackgroundCheck;
+            this.gpsMode = gpsMode;
+            this.sendTronLog = sendTronLog;
+        }
+    }
+
+    /**
+     * Get the {@link PowerSaveState} based on {@paramref type} and {@paramref realMode}.
+     * The result will have {@link PowerSaveState#batterySaverEnabled} and some other
+     * parameters when necessary.
+     *
+     * @param type     type of the service, one of {@link ServiceType}
+     * @param realMode whether the battery saver is on by default
+     * @return State data that contains battery saver data
+     */
+    public PowerSaveState getBatterySaverPolicy(@ServiceType int type, boolean realMode) {
+        synchronized (mLock) {
+            final PowerSaveState.Builder builder = new PowerSaveState.Builder()
+                    .setGlobalBatterySaverEnabled(realMode);
+            if (!realMode) {
+                return builder.setBatterySaverEnabled(realMode)
+                        .build();
+            }
+            switch (type) {
+                case ServiceType.GPS:
+                    return builder.setBatterySaverEnabled(realMode)
+                            .setGpsMode(mCurrPolicy.gpsMode)
+                            .build();
+                case ServiceType.ANIMATION:
+                    return builder.setBatterySaverEnabled(mCurrPolicy.disableAnimation)
+                            .build();
+                case ServiceType.FULL_BACKUP:
+                    return builder.setBatterySaverEnabled(mCurrPolicy.deferFullBackup)
+                            .build();
+                case ServiceType.KEYVALUE_BACKUP:
+                    return builder.setBatterySaverEnabled(mCurrPolicy.deferKeyValueBackup)
+                            .build();
+                case ServiceType.NETWORK_FIREWALL:
+                    return builder.setBatterySaverEnabled(mCurrPolicy.enableFirewall)
+                            .build();
+                case ServiceType.SCREEN_BRIGHTNESS:
+                    return builder.setBatterySaverEnabled(mCurrPolicy.enableAdjustBrightness)
+                            .setBrightnessFactor(mCurrPolicy.adjustBrightnessFactor)
+                            .build();
+                case ServiceType.DATA_SAVER:
+                    return builder.setBatterySaverEnabled(mCurrPolicy.enableDataSaver)
+                            .build();
+                case ServiceType.SOUND:
+                    return builder.setBatterySaverEnabled(mCurrPolicy.disableSoundTrigger)
+                            .build();
+                case ServiceType.VIBRATION:
+                    return builder.setBatterySaverEnabled(mDisableVibrationEffective)
+                            .build();
+                case ServiceType.FORCE_ALL_APPS_STANDBY:
+                    return builder.setBatterySaverEnabled(mCurrPolicy.forceAllAppsStandby)
+                            .build();
+                case ServiceType.FORCE_BACKGROUND_CHECK:
+                    return builder.setBatterySaverEnabled(mCurrPolicy.forceBackgroundCheck)
+                            .build();
+                case ServiceType.OPTIONAL_SENSORS:
+                    return builder.setBatterySaverEnabled(mCurrPolicy.disableOptionalSensors)
+                            .build();
+                case ServiceType.AOD:
+                    return builder.setBatterySaverEnabled(mCurrPolicy.disableAod)
+                            .build();
+                case ServiceType.QUICK_DOZE:
+                    return builder.setBatterySaverEnabled(mCurrPolicy.enableQuickDoze)
+                            .build();
+                default:
+                    return builder.setBatterySaverEnabled(realMode)
+                            .build();
+            }
+        }
+    }
+
+    public int getGpsMode() {
+        synchronized (mLock) {
+            return mCurrPolicy.gpsMode;
+        }
+    }
+
+    public ArrayMap<String, String> getFileValues(boolean interactive) {
+        synchronized (mLock) {
+            return interactive ? mCurrPolicy.filesForInteractive
+                    : mCurrPolicy.filesForNoninteractive;
+        }
+    }
+
+    public boolean isLaunchBoostDisabled() {
+        synchronized (mLock) {
+            return mCurrPolicy.disableLaunchBoost;
+        }
+    }
+
+    public String toEventLogString() {
+        synchronized (mLock) {
+            return mEventLogKeys;
+        }
+    }
+
+    public void dump(PrintWriter pw) {
+        synchronized (mLock) {
+            pw.println();
+            mBatterySavingStats.dump(pw, "");
+
+            pw.println();
+            pw.println("Battery saver policy (*NOTE* they only apply when battery saver is ON):");
+            pw.println("  Settings: " + Settings.Global.BATTERY_SAVER_CONSTANTS);
+            pw.println("    value: " + mSettings);
+            pw.println("  Settings: " + mDeviceSpecificSettingsSource);
+            pw.println("    value: " + mDeviceSpecificSettings);
+
+            pw.println();
+            pw.println("  mAccessibilityEnabled=" + mAccessibilityEnabled);
+            pw.println("  " + KEY_VIBRATION_DISABLED + ":config=" + mCurrPolicy.disableVibration);
+            pw.println("  " + KEY_VIBRATION_DISABLED + ":effective=" + mDisableVibrationEffective);
+            pw.println("  " + KEY_ANIMATION_DISABLED + "=" + mCurrPolicy.disableAnimation);
+            pw.println("  " + KEY_FULLBACKUP_DEFERRED + "=" + mCurrPolicy.deferFullBackup);
+            pw.println("  " + KEY_KEYVALUE_DEFERRED + "=" + mCurrPolicy.deferKeyValueBackup);
+            pw.println("  " + KEY_ACTIVATE_FIREWALL_DISABLED + "=" + !mCurrPolicy.enableFirewall);
+            pw.println("  " + KEY_ACTIVATE_DATASAVER_DISABLED + "=" + !mCurrPolicy.enableDataSaver);
+            pw.println("  " + KEY_LAUNCH_BOOST_DISABLED + "=" + mCurrPolicy.disableLaunchBoost);
+            pw.println("  " + KEY_ADJUST_BRIGHTNESS_DISABLED + "="
+                    + !mCurrPolicy.enableAdjustBrightness);
+            pw.println(
+                    "  " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mCurrPolicy.adjustBrightnessFactor);
+            pw.println("  " + KEY_GPS_MODE + "=" + mCurrPolicy.gpsMode);
+            pw.println("  " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mCurrPolicy.forceAllAppsStandby);
+            pw.println("  " + KEY_FORCE_BACKGROUND_CHECK + "=" + mCurrPolicy.forceBackgroundCheck);
+            pw.println("  " + KEY_OPTIONAL_SENSORS_DISABLED + "="
+                    + mCurrPolicy.disableOptionalSensors);
+            pw.println("  " + KEY_AOD_DISABLED + "=" + mCurrPolicy.disableAod);
+            pw.println("  " + KEY_SOUNDTRIGGER_DISABLED + "=" + mCurrPolicy.disableSoundTrigger);
+            pw.println("  " + KEY_QUICK_DOZE_ENABLED + "=" + mCurrPolicy.enableQuickDoze);
+            pw.println("  " + KEY_SEND_TRON_LOG + "=" + mCurrPolicy.sendTronLog);
+            pw.println();
+
+            pw.print("  Interactive File values:\n");
+            dumpMap(pw, "    ", mCurrPolicy.filesForInteractive);
+            pw.println();
+
+            pw.print("  Noninteractive File values:\n");
+            dumpMap(pw, "    ", mCurrPolicy.filesForNoninteractive);
+        }
+    }
+
+    private void dumpMap(PrintWriter pw, String prefix, ArrayMap<String, String> map) {
+        if (map == null) {
+            return;
+        }
+        final int size = map.size();
+        for (int i = 0; i < size; i++) {
+            pw.print(prefix);
+            pw.print(map.keyAt(i));
+            pw.print(": '");
+            pw.print(map.valueAt(i));
+            pw.println("'");
+        }
+    }
+
+    @VisibleForTesting
+    public void setAccessibilityEnabledForTest(boolean enabled) {
+        synchronized (mLock) {
+            mAccessibilityEnabled = enabled;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index f262f6d..404e450 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -15,22 +15,27 @@
  */
 package com.android.server.power.batterysaver;
 
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.provider.Settings.Global;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
 import com.android.server.EventLogTags;
-import com.android.server.power.BatterySaverPolicy;
 import com.android.server.power.BatterySaverStateMachineProto;
 
 import java.io.PrintWriter;
@@ -46,6 +51,8 @@
  */
 public class BatterySaverStateMachine {
     private static final String TAG = "BatterySaverStateMachine";
+    private static final String DYNAMIC_MODE_NOTIF_CHANNEL_ID = "dynamic_mode_notification";
+    private static final int DYNAMIC_MODE_NOTIFICATION_ID = 1992;
     private final Object mLock;
 
     private static final boolean DEBUG = BatterySaverPolicy.DEBUG;
@@ -77,42 +84,56 @@
     @GuardedBy("mLock")
     private boolean mIsBatteryLevelLow;
 
-    /** Previously known value of Global.LOW_POWER_MODE. */
+    /** Previously known value of Settings.Global.LOW_POWER_MODE. */
     @GuardedBy("mLock")
     private boolean mSettingBatterySaverEnabled;
 
-    /** Previously known value of Global.LOW_POWER_MODE_STICKY. */
+    /** Previously known value of Settings.Global.LOW_POWER_MODE_STICKY. */
     @GuardedBy("mLock")
     private boolean mSettingBatterySaverEnabledSticky;
 
     /** Config flag to track if battery saver's sticky behaviour is disabled. */
     private final boolean mBatterySaverStickyBehaviourDisabled;
 
+    /**
+     * Whether or not to end sticky battery saver upon reaching a level specified by
+     * {@link #mSettingBatterySaverStickyAutoDisableThreshold}.
+     */
+    @GuardedBy("mLock")
+    private boolean mSettingBatterySaverStickyAutoDisableEnabled;
+
+    /**
+     * The battery level at which to end sticky battery saver. Only useful if
+     * {@link #mSettingBatterySaverStickyAutoDisableEnabled} is {@code true}.
+     */
+    @GuardedBy("mLock")
+    private int mSettingBatterySaverStickyAutoDisableThreshold;
+
     /** Config flag to track default disable threshold for Dynamic Power Savings enabled battery
      * saver. */
     @GuardedBy("mLock")
     private final int mDynamicPowerSavingsDefaultDisableThreshold;
 
     /**
-     * Previously known value of Global.LOW_POWER_MODE_TRIGGER_LEVEL.
+     * Previously known value of Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL.
      * (Currently only used in dumpsys.)
      */
     @GuardedBy("mLock")
     private int mSettingBatterySaverTriggerThreshold;
 
-    /** Previously known value of Global.AUTOMATIC_POWER_SAVER_MODE. */
+    /** Previously known value of Settings.Global.AUTOMATIC_POWER_SAVER_MODE. */
     @GuardedBy("mLock")
     private int mSettingAutomaticBatterySaver;
 
     /** When to disable battery saver again if it was enabled due to an external suggestion.
-     *  Corresponds to Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD.
+     *  Corresponds to Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD.
      */
     @GuardedBy("mLock")
     private int mDynamicPowerSavingsDisableThreshold;
 
     /**
      * Whether we've received a suggestion that battery saver should be on from an external app.
-     * Updates when Global.DYNAMIC_POWER_SAVINGS_ENABLED changes.
+     * Updates when Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED changes.
      */
     @GuardedBy("mLock")
     private boolean mDynamicPowerSavingsBatterySaver;
@@ -173,7 +194,7 @@
             Slog.d(TAG, "onBootCompleted");
         }
         // Just booted. We don't want LOW_POWER_MODE to be persisted, so just always clear it.
-        putGlobalSetting(Global.LOW_POWER_MODE, 0);
+        putGlobalSetting(Settings.Global.LOW_POWER_MODE, 0);
 
         // This is called with the power manager lock held. Don't do anything that may call to
         // upper services. (e.g. don't call into AM directly)
@@ -191,13 +212,19 @@
                     Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
             cr.registerContentObserver(Settings.Global.getUriFor(
-                    Global.AUTOMATIC_POWER_SAVER_MODE),
+                    Settings.Global.AUTOMATIC_POWER_SAVER_MODE),
                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
             cr.registerContentObserver(Settings.Global.getUriFor(
-                    Global.DYNAMIC_POWER_SAVINGS_ENABLED),
+                    Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED),
                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
             cr.registerContentObserver(Settings.Global.getUriFor(
-                    Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD),
+                    Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD),
+                    false, mSettingsObserver, UserHandle.USER_SYSTEM);
+            cr.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED),
+                    false, mSettingsObserver, UserHandle.USER_SYSTEM);
+            cr.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL),
                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
 
             synchronized (mLock) {
@@ -220,8 +247,8 @@
     }
 
     /**
-     * Run a {@link Runnable} on a background handler, but lazily. If the same {@link Runnable},
-     * it'll be first removed before a new one is posted.
+     * Run a {@link Runnable} on a background handler, but lazily. If the same {@link Runnable} is
+     * already registered, it'll be first removed before being re-posted.
      */
     @VisibleForTesting
     void runOnBgThreadLazy(Runnable r, int delayMillis) {
@@ -231,25 +258,31 @@
     }
 
     @GuardedBy("mLock")
-    void refreshSettingsLocked() {
+    private void refreshSettingsLocked() {
         final boolean lowPowerModeEnabled = getGlobalSetting(
                 Settings.Global.LOW_POWER_MODE, 0) != 0;
         final boolean lowPowerModeEnabledSticky = getGlobalSetting(
                 Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0;
         final boolean dynamicPowerSavingsBatterySaver = getGlobalSetting(
-                Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0) != 0;
+                Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0) != 0;
         final int lowPowerModeTriggerLevel = getGlobalSetting(
                 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
-        final int automaticBatterySaver = getGlobalSetting(
-                Global.AUTOMATIC_POWER_SAVER_MODE,
+        final int automaticBatterySaverMode = getGlobalSetting(
+                Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
                 PowerManager.POWER_SAVER_MODE_PERCENTAGE);
         final int dynamicPowerSavingsDisableThreshold = getGlobalSetting(
-                Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
+                Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
                 mDynamicPowerSavingsDefaultDisableThreshold);
+        final boolean isStickyAutoDisableEnabled = getGlobalSetting(
+                Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 0) != 0;
+        final int stickyAutoDisableThreshold = getGlobalSetting(
+                Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90);
 
         setSettingsLocked(lowPowerModeEnabled, lowPowerModeEnabledSticky,
-                lowPowerModeTriggerLevel, automaticBatterySaver, dynamicPowerSavingsBatterySaver,
-                dynamicPowerSavingsDisableThreshold);
+                lowPowerModeTriggerLevel,
+                isStickyAutoDisableEnabled, stickyAutoDisableThreshold,
+                automaticBatterySaverMode,
+                dynamicPowerSavingsBatterySaver, dynamicPowerSavingsDisableThreshold);
     }
 
     /**
@@ -261,12 +294,16 @@
     @GuardedBy("mLock")
     @VisibleForTesting
     void setSettingsLocked(boolean batterySaverEnabled, boolean batterySaverEnabledSticky,
-            int batterySaverTriggerThreshold, int automaticBatterySaver,
+            int batterySaverTriggerThreshold,
+            boolean isStickyAutoDisableEnabled, int stickyAutoDisableThreshold,
+            int automaticBatterySaver,
             boolean dynamicPowerSavingsBatterySaver, int dynamicPowerSavingsDisableThreshold) {
         if (DEBUG) {
             Slog.d(TAG, "setSettings: enabled=" + batterySaverEnabled
                     + " sticky=" + batterySaverEnabledSticky
                     + " threshold=" + batterySaverTriggerThreshold
+                    + " stickyAutoDisableEnabled=" + isStickyAutoDisableEnabled
+                    + " stickyAutoDisableThreshold=" + stickyAutoDisableThreshold
                     + " automaticBatterySaver=" + automaticBatterySaver
                     + " dynamicPowerSavingsBatterySaver=" + dynamicPowerSavingsBatterySaver
                     + " dynamicPowerSavingsDisableThreshold="
@@ -275,11 +312,19 @@
 
         mSettingsLoaded = true;
 
+        // Set sensible limits.
+        stickyAutoDisableThreshold = Math.max(stickyAutoDisableThreshold,
+                batterySaverTriggerThreshold);
+
         final boolean enabledChanged = mSettingBatterySaverEnabled != batterySaverEnabled;
         final boolean stickyChanged =
                 mSettingBatterySaverEnabledSticky != batterySaverEnabledSticky;
         final boolean thresholdChanged
                 = mSettingBatterySaverTriggerThreshold != batterySaverTriggerThreshold;
+        final boolean stickyAutoDisableEnabledChanged =
+                mSettingBatterySaverStickyAutoDisableEnabled != isStickyAutoDisableEnabled;
+        final boolean stickyAutoDisableThresholdChanged =
+                mSettingBatterySaverStickyAutoDisableThreshold != stickyAutoDisableThreshold;
         final boolean automaticModeChanged = mSettingAutomaticBatterySaver != automaticBatterySaver;
         final boolean dynamicPowerSavingsThresholdChanged =
                 mDynamicPowerSavingsDisableThreshold != dynamicPowerSavingsDisableThreshold;
@@ -287,6 +332,7 @@
                 mDynamicPowerSavingsBatterySaver != dynamicPowerSavingsBatterySaver;
 
         if (!(enabledChanged || stickyChanged || thresholdChanged || automaticModeChanged
+                || stickyAutoDisableEnabledChanged || stickyAutoDisableThresholdChanged
                 || dynamicPowerSavingsThresholdChanged || dynamicPowerSavingsBatterySaverChanged)) {
             return;
         }
@@ -294,6 +340,8 @@
         mSettingBatterySaverEnabled = batterySaverEnabled;
         mSettingBatterySaverEnabledSticky = batterySaverEnabledSticky;
         mSettingBatterySaverTriggerThreshold = batterySaverTriggerThreshold;
+        mSettingBatterySaverStickyAutoDisableEnabled = isStickyAutoDisableEnabled;
+        mSettingBatterySaverStickyAutoDisableThreshold = stickyAutoDisableThreshold;
         mSettingAutomaticBatterySaver = automaticBatterySaver;
         mDynamicPowerSavingsDisableThreshold = dynamicPowerSavingsDisableThreshold;
         mDynamicPowerSavingsBatterySaver = dynamicPowerSavingsBatterySaver;
@@ -368,7 +416,9 @@
                     + " mBatterySaverSnoozing=" + mBatterySaverSnoozing
                     + " mIsPowered=" + mIsPowered
                     + " mSettingAutomaticBatterySaver=" + mSettingAutomaticBatterySaver
-                    + " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky);
+                    + " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky
+                    + " mSettingBatterySaverStickyAutoDisableEnabled="
+                    + mSettingBatterySaverStickyAutoDisableEnabled);
         }
         if (!(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
             return; // Not fully initialized yet.
@@ -384,10 +434,15 @@
                     "Plugged in");
 
         } else if (mSettingBatterySaverEnabledSticky && !mBatterySaverStickyBehaviourDisabled) {
-            // Re-enable BS.
-            enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true,
-                    BatterySaverController.REASON_STICKY_RESTORE,
-                    "Sticky restore");
+            if (mSettingBatterySaverStickyAutoDisableEnabled
+                    && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold) {
+                setStickyActive(false);
+            } else {
+                // Re-enable BS.
+                enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true,
+                        BatterySaverController.REASON_STICKY_RESTORE,
+                        "Sticky restore");
+            }
 
         } else if (mSettingAutomaticBatterySaver
                 == PowerManager.POWER_SAVER_MODE_PERCENTAGE
@@ -475,15 +530,20 @@
         }
 
         mSettingBatterySaverEnabled = enable;
-        putGlobalSetting(Global.LOW_POWER_MODE, enable ? 1 : 0);
+        putGlobalSetting(Settings.Global.LOW_POWER_MODE, enable ? 1 : 0);
 
         if (manual) {
-            mSettingBatterySaverEnabledSticky = !mBatterySaverStickyBehaviourDisabled && enable;
-            putGlobalSetting(Global.LOW_POWER_MODE_STICKY,
-                    mSettingBatterySaverEnabledSticky ? 1 : 0);
+            setStickyActive(!mBatterySaverStickyBehaviourDisabled && enable);
         }
         mBatterySaverController.enableBatterySaver(enable, intReason);
 
+        // Handle triggering the notification to show/hide when appropriate
+        if (intReason == BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON) {
+            runOnBgThread(this::triggerDynamicModeNotification);
+        } else if (!enable) {
+            runOnBgThread(this::hideDynamicModeNotification);
+        }
+
         if (DEBUG) {
             Slog.d(TAG, "Battery saver: Enabled=" + enable
                     + " manual=" + manual
@@ -491,6 +551,45 @@
         }
     }
 
+    @VisibleForTesting
+    void triggerDynamicModeNotification() {
+        NotificationManager manager = mContext.getSystemService(NotificationManager.class);
+        ensureNotificationChannelExists(manager);
+
+        manager.notify(DYNAMIC_MODE_NOTIFICATION_ID, buildNotification());
+    }
+
+    private void ensureNotificationChannelExists(NotificationManager manager) {
+        NotificationChannel channel = new NotificationChannel(
+                DYNAMIC_MODE_NOTIF_CHANNEL_ID,
+                mContext.getText(
+                        R.string.dynamic_mode_notification_channel_name),
+                NotificationManager.IMPORTANCE_DEFAULT);
+        channel.setSound(null, null);
+        manager.createNotificationChannel(channel);
+    }
+
+    private Notification buildNotification() {
+        Resources res = mContext.getResources();
+        Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        PendingIntent batterySaverIntent = PendingIntent.getActivity(
+                mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+        return new Notification.Builder(mContext, DYNAMIC_MODE_NOTIF_CHANNEL_ID)
+                .setSmallIcon(R.drawable.ic_battery)
+                .setContentTitle(res.getString(R.string.dynamic_mode_notification_title))
+                .setContentText(res.getString(R.string.dynamic_mode_notification_summary))
+                .setContentIntent(batterySaverIntent)
+                .setOnlyAlertOnce(true)
+                .build();
+    }
+
+    private void hideDynamicModeNotification() {
+        NotificationManager manager = mContext.getSystemService(NotificationManager.class);
+        manager.cancel(DYNAMIC_MODE_NOTIFICATION_ID);
+    }
+
     @GuardedBy("mLock")
     private void updateSnoozingLocked(boolean snoozing, String reason) {
         if (mBatterySaverSnoozing == snoozing) {
@@ -500,14 +599,20 @@
         mBatterySaverSnoozing = snoozing;
     }
 
+    private void setStickyActive(boolean active) {
+        mSettingBatterySaverEnabledSticky = active;
+        putGlobalSetting(Settings.Global.LOW_POWER_MODE_STICKY,
+                mSettingBatterySaverEnabledSticky ? 1 : 0);
+    }
+
     @VisibleForTesting
     protected void putGlobalSetting(String key, int value) {
-        Global.putInt(mContext.getContentResolver(), key, value);
+        Settings.Global.putInt(mContext.getContentResolver(), key, value);
     }
 
     @VisibleForTesting
     protected int getGlobalSetting(String key, int defValue) {
-        return Global.getInt(mContext.getContentResolver(), key, defValue);
+        return Settings.Global.getInt(mContext.getContentResolver(), key, defValue);
     }
 
     public void dump(PrintWriter pw) {
@@ -544,6 +649,10 @@
             pw.println(mSettingBatterySaverEnabled);
             pw.print("  mSettingBatterySaverEnabledSticky=");
             pw.println(mSettingBatterySaverEnabledSticky);
+            pw.print("  mSettingBatterySaverStickyAutoDisableEnabled=");
+            pw.println(mSettingBatterySaverStickyAutoDisableEnabled);
+            pw.print("  mSettingBatterySaverStickyAutoDisableThreshold=");
+            pw.println(mSettingBatterySaverStickyAutoDisableThreshold);
             pw.print("  mSettingBatterySaverTriggerThreshold=");
             pw.println(mSettingBatterySaverTriggerThreshold);
             pw.print("  mBatterySaverStickyBehaviourDisabled=");
@@ -575,6 +684,13 @@
                     mSettingBatterySaverEnabledSticky);
             proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_TRIGGER_THRESHOLD,
                     mSettingBatterySaverTriggerThreshold);
+            proto.write(
+                    BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_STICKY_AUTO_DISABLE_ENABLED,
+                    mSettingBatterySaverStickyAutoDisableEnabled);
+            proto.write(
+                    BatterySaverStateMachineProto
+                            .SETTING_BATTERY_SAVER_STICKY_AUTO_DISABLE_THRESHOLD,
+                    mSettingBatterySaverStickyAutoDisableThreshold);
 
             proto.end(token);
         }
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
index 8213205..79b44eb 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
@@ -29,7 +29,6 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
-import com.android.server.power.BatterySaverPolicy;
 
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index f37ca12..c0517fd 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -35,6 +35,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -92,6 +93,15 @@
     @NonNull
     private final Object mLock = new Object();
 
+    @NonNull
+    private final RoleHoldersResolver mLegacyRoleResolver;
+
+    /** @see #getRoleHolders(String, int) */
+    public interface RoleHoldersResolver {
+        /** @return a list of packages that hold a given role for a given user */
+        List<String> getRoleHolders(String roleName, int userId);
+    }
+
     /**
      * Maps user id to its state.
      */
@@ -118,9 +128,12 @@
     @NonNull
     private final Handler mListenerHandler = FgThread.getHandler();
 
-    public RoleManagerService(@NonNull Context context) {
+    public RoleManagerService(@NonNull Context context,
+            @NonNull RoleHoldersResolver legacyRoleResolver) {
         super(context);
 
+        mLegacyRoleResolver = legacyRoleResolver;
+
         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
         mAppOpsManager = context.getSystemService(AppOpsManager.class);
 
@@ -175,10 +188,17 @@
     private void performInitialGrantsIfNecessary(@UserIdInt int userId) {
         RoleUserState userState;
         userState = getOrCreateUserState(userId);
+
         String packagesHash = computeComponentStateHash(userId);
         String oldPackagesHash = userState.getPackagesHash();
         boolean needGrant = !Objects.equals(packagesHash, oldPackagesHash);
         if (needGrant) {
+
+            //TODO gradually add more role migrations statements here for remaining roles
+            // Make sure to implement LegacyRoleResolutionPolicy#getRoleHolders
+            // for a given role before adding a migration statement for it here
+            migrateRoleIfNecessary(RoleManager.ROLE_SMS, userId);
+
             // Some vital packages state has changed since last role grant
             // Run grants again
             Slog.i(LOG_TAG, "Granting default permissions...");
@@ -205,6 +225,23 @@
         }
     }
 
+    private void migrateRoleIfNecessary(String role, @UserIdInt int userId) {
+        // Any role for which we have a record are already migrated
+        RoleUserState userState = getOrCreateUserState(userId);
+        if (!userState.isRoleAvailable(role)) {
+            List<String> roleHolders = mLegacyRoleResolver.getRoleHolders(role, userId);
+            if (roleHolders.isEmpty()) {
+                return;
+            }
+            Slog.i(LOG_TAG, "Migrating " + role + ", legacy holders: " + roleHolders);
+            userState.addRoleName(role);
+            int size = roleHolders.size();
+            for (int i = 0; i < size; i++) {
+                userState.addRoleHolder(role, roleHolders.get(i));
+            }
+        }
+    }
+
     @Nullable
     private static String computeComponentStateHash(@UserIdInt int userId) {
         PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
@@ -305,10 +342,21 @@
     @WorkerThread
     private void notifyRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
         RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getListeners(userId);
-        if (listeners == null) {
-            return;
+        if (listeners != null) {
+            notifyRoleHoldersChangedForListeners(listeners, roleName, userId);
         }
 
+        RemoteCallbackList<IOnRoleHoldersChangedListener> allUserListeners = getListeners(
+                UserHandle.USER_ALL);
+        if (allUserListeners != null) {
+            notifyRoleHoldersChangedForListeners(allUserListeners, roleName, userId);
+        }
+    }
+
+    @WorkerThread
+    private void notifyRoleHoldersChangedForListeners(
+            @NonNull RemoteCallbackList<IOnRoleHoldersChangedListener> listeners,
+            @NonNull String roleName, @UserIdInt int userId) {
         int broadcastCount = listeners.beginBroadcast();
         try {
             for (int i = 0; i < broadcastCount; i++) {
@@ -358,7 +406,7 @@
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return Collections.emptyList();
             }
-            userId = handleIncomingUser(userId, "getRoleHoldersAsUser");
+            userId = handleIncomingUser(userId, "getRoleHoldersAsUser", false);
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "getRoleHoldersAsUser");
 
@@ -386,7 +434,7 @@
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
             }
-            userId = handleIncomingUser(userId, "addRoleHolderAsUser");
+            userId = handleIncomingUser(userId, "addRoleHolderAsUser", false);
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "addRoleHolderAsUser");
 
@@ -403,7 +451,7 @@
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
             }
-            userId = handleIncomingUser(userId, "removeRoleHolderAsUser");
+            userId = handleIncomingUser(userId, "removeRoleHolderAsUser", false);
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "removeRoleHolderAsUser");
 
@@ -420,7 +468,7 @@
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
             }
-            userId = handleIncomingUser(userId, "clearRoleHoldersAsUser");
+            userId = handleIncomingUser(userId, "clearRoleHoldersAsUser", false);
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "clearRoleHoldersAsUser");
 
@@ -431,11 +479,12 @@
         public void addOnRoleHoldersChangedListenerAsUser(
                 @NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
             Preconditions.checkNotNull(listener, "listener cannot be null");
-            if (!mUserManagerInternal.exists(userId)) {
+            if (userId != UserHandle.USER_ALL && !mUserManagerInternal.exists(userId)) {
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
             }
-            userId = handleIncomingUser(userId, "addOnRoleHoldersChangedListenerAsUser");
+            userId = handleIncomingUser(userId, "addOnRoleHoldersChangedListenerAsUser",
+                    true);
             getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
                     "addOnRoleHoldersChangedListenerAsUser");
 
@@ -448,11 +497,12 @@
         public void removeOnRoleHoldersChangedListenerAsUser(
                 @NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
             Preconditions.checkNotNull(listener, "listener cannot be null");
-            if (!mUserManagerInternal.exists(userId)) {
+            if (userId != UserHandle.USER_ALL && !mUserManagerInternal.exists(userId)) {
                 Slog.e(LOG_TAG, "user " + userId + " does not exist");
                 return;
             }
-            userId = handleIncomingUser(userId, "removeOnRoleHoldersChangedListenerAsUser");
+            userId = handleIncomingUser(userId, "removeOnRoleHoldersChangedListenerAsUser",
+                    true);
             getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
                     "removeOnRoleHoldersChangedListenerAsUser");
 
@@ -516,9 +566,10 @@
         }
 
         @CheckResult
-        private int handleIncomingUser(@UserIdInt int userId, @NonNull String name) {
+        private int handleIncomingUser(@UserIdInt int userId, @NonNull String name,
+                boolean allowAll) {
             return ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
-                    false, true, name, null);
+                    allowAll, true, name, null);
         }
 
         @Override
@@ -530,6 +581,17 @@
         }
 
         @Override
+        public String getDefaultSmsPackage(int userId) {
+            long identity = Binder.clearCallingIdentity();
+            try {
+                return CollectionUtils.firstOrNull(
+                        getRoleHoldersAsUser(RoleManager.ROLE_SMS, userId));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
                 @Nullable String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), LOG_TAG, fout)) {
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 630a39c..02dcc49 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -193,14 +193,40 @@
      *
      * @param roleName the name of the role to query for
      *
-     * @return the set of role holders. {@code null} should not be returned and indicates an issue.
+     * @return the set of role holders, or {@code null} if and only if the role is not found
      */
     @Nullable
     public ArraySet<String> getRoleHolders(@NonNull String roleName) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
 
-            return new ArraySet<>(mRoles.get(roleName));
+            ArraySet<String> packageNames = mRoles.get(roleName);
+            if (packageNames == null) {
+                return null;
+            }
+            return new ArraySet<>(packageNames);
+        }
+    }
+
+    /**
+     * Adds the given role, effectively marking it as {@link #isRoleAvailable available}
+     *
+     * @param roleName the name of the role
+     *
+     * @return whether any changes were made
+     */
+    public boolean addRoleName(@NonNull String roleName) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+
+            if (!mRoles.containsKey(roleName)) {
+                mRoles.put(roleName, new ArraySet<>());
+                Slog.i(LOG_TAG, "Added new role: " + roleName);
+                scheduleWriteFileLocked();
+                return true;
+            } else {
+                return false;
+            }
         }
     }
 
@@ -231,13 +257,7 @@
 
             int roleNamesSize = roleNames.size();
             for (int i = 0; i < roleNamesSize; i++) {
-                String roleName = roleNames.get(i);
-
-                if (!mRoles.containsKey(roleName)) {
-                    mRoles.put(roleName, new ArraySet<>());
-                    Slog.i(LOG_TAG, "Added new role: " + roleName);
-                    changed = true;
-                }
+                changed |= addRoleName(roleNames.get(i));
             }
 
             if (changed) {
@@ -252,8 +272,7 @@
      * @param roleName the name of the role to add the holder to
      * @param packageName the package name of the new holder
      *
-     * @return {@code false} only if the set of role holders is null, which should not happen and
-     *         indicates an issue.
+     * @return {@code false} if and only if the role is not found
      */
     @CheckResult
     public boolean addRoleHolder(@NonNull String roleName, @NonNull String packageName) {
@@ -286,8 +305,7 @@
      * @param roleName the name of the role to remove the holder from
      * @param packageName the package name of the holder to remove
      *
-     * @return {@code false} only if the set of role holders is null, which should not happen and
-     *         indicates an issue.
+     * @return {@code false} if and only if the role is not found
      */
     @CheckResult
     public boolean removeRoleHolder(@NonNull String roleName, @NonNull String packageName) {
diff --git a/services/core/java/com/android/server/rollback/PackageRollbackData.java b/services/core/java/com/android/server/rollback/PackageRollbackData.java
deleted file mode 100644
index 15d1242..0000000
--- a/services/core/java/com/android/server/rollback/PackageRollbackData.java
+++ /dev/null
@@ -1,49 +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.rollback;
-
-import android.content.rollback.PackageRollbackInfo;
-
-import java.io.File;
-import java.time.Instant;
-
-/**
- * Information about a rollback available for a particular package.
- * This is similar to {@link PackageRollbackInfo}, but extended with
- * additional information for internal bookkeeping.
- */
-class PackageRollbackData {
-    public final PackageRollbackInfo info;
-
-    /**
-     * The directory where the apk backup is stored.
-     */
-    public final File backupDir;
-
-    /**
-     * The time when the upgrade occurred, for purposes of expiring
-     * rollback data.
-     */
-    public final Instant timestamp;
-
-    PackageRollbackData(PackageRollbackInfo info,
-            File backupDir, Instant timestamp) {
-        this.info = info;
-        this.backupDir = backupDir;
-        this.timestamp = timestamp;
-    }
-}
diff --git a/services/core/java/com/android/server/rollback/RollbackData.java b/services/core/java/com/android/server/rollback/RollbackData.java
new file mode 100644
index 0000000..4015c4f
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/RollbackData.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 com.android.server.rollback;
+
+import android.content.rollback.PackageRollbackInfo;
+
+import java.io.File;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Information about a rollback available for a set of atomically installed
+ * packages.
+ */
+class RollbackData {
+    /**
+     * A unique identifier for this rollback.
+     */
+    public final int rollbackId;
+
+    /**
+     * The per-package rollback information.
+     */
+    public final List<PackageRollbackInfo> packages = new ArrayList<>();
+
+    /**
+     * The directory where the rollback data is stored.
+     */
+    public final File backupDir;
+
+    /**
+     * The time when the upgrade occurred, for purposes of expiring
+     * rollback data.
+     */
+    public Instant timestamp;
+
+    RollbackData(int rollbackId, File backupDir) {
+        this.rollbackId = rollbackId;
+        this.backupDir = backupDir;
+    }
+}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerService.java b/services/core/java/com/android/server/rollback/RollbackManagerService.java
index 5bf2040..4b5e764 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerService.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerService.java
@@ -16,831 +16,27 @@
 
 package com.android.server.rollback;
 
-import android.app.AppOpsManager;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.IIntentReceiver;
-import android.content.IIntentSender;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.StringParceledListSlice;
-import android.content.rollback.IRollbackManager;
-import android.content.rollback.PackageRollbackInfo;
-import android.content.rollback.RollbackInfo;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.SELinux;
-import android.util.Log;
 
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.pm.PackageManagerServiceUtils;
-
-import libcore.io.IoUtils;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.file.Files;
-import java.time.Instant;
-import java.time.format.DateTimeParseException;
-import java.time.temporal.ChronoUnit;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
 
 /**
- * Service that manages APK level rollbacks.
- *
- * TODO: Make RollbackManagerService extend SystemService and move the
- * IRollbackManager.Stub implementation to a new private
- * RollbackManagerServiceImpl class.
+ * Service that manages APK level rollbacks. Publishes
+ * Context.ROLLBACK_SERVICE.
  *
  * @hide
  */
-public class RollbackManagerService extends IRollbackManager.Stub {
+public final class RollbackManagerService extends SystemService {
 
-    private static final String TAG = "RollbackManager";
+    private RollbackManagerServiceImpl mService;
 
-    // Rollbacks expire after 48 hours.
-    // TODO: How to test rollback expiration works properly?
-    private static final long ROLLBACK_LIFETIME_DURATION_MILLIS = 48 * 60 * 60 * 1000;
-
-    // Lock used to synchronize accesses to in-memory rollback data
-    // structures. By convention, methods with the suffix "Locked" require
-    // mLock is held when they are called.
-    private final Object mLock = new Object();
-
-    // Package rollback data available to be used for rolling back a package.
-    // This list is null until the rollback data has been loaded.
-    @GuardedBy("mLock")
-    private List<PackageRollbackData> mAvailableRollbacks;
-
-    // The list of recently executed rollbacks.
-    // This list is null until the rollback data has been loaded.
-    @GuardedBy("mLock")
-    private List<RollbackInfo> mRecentlyExecutedRollbacks;
-
-    // Data for available rollbacks and recently executed rollbacks is
-    // persisted in storage. Assuming the rollback data directory is
-    // /data/rollback, we use the following directory structure
-    // to store this data:
-    //   /data/rollback/
-    //      available/
-    //          com.package.A-XXX/
-    //              base.apk
-    //              rollback.json
-    //          com.package.B-YYY/
-    //              base.apk
-    //              rollback.json
-    //      recently_executed.json
-    // TODO: Use AtomicFile for rollback.json and recently_executed.json.
-    private final File mRollbackDataDir;
-    private final File mAvailableRollbacksDir;
-    private final File mRecentlyExecutedRollbacksFile;
-
-    private final Context mContext;
-    private final HandlerThread mHandlerThread;
-
-    RollbackManagerService(Context context) {
-        mContext = context;
-        mHandlerThread = new HandlerThread("RollbackManagerServiceHandler");
-        mHandlerThread.start();
-
-        mRollbackDataDir = new File(Environment.getDataDirectory(), "rollback");
-        mAvailableRollbacksDir = new File(mRollbackDataDir, "available");
-        mRecentlyExecutedRollbacksFile = new File(mRollbackDataDir, "recently_executed.json");
-
-        // Kick off loading of the rollback data from strorage in a background
-        // thread.
-        // TODO: Consider loading the rollback data directly here instead, to
-        // avoid the need to call ensureRollbackDataLoaded every time before
-        // accessing the rollback data?
-        // TODO: Test that this kicks off initial scheduling of rollback
-        // expiration.
-        getHandler().post(() -> ensureRollbackDataLoaded());
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
-        filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
-        filter.addDataScheme("package");
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
-                if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
-                    String packageName = intent.getData().getSchemeSpecificPart();
-                    onPackageReplaced(packageName);
-                }
-                if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
-                    String packageName = intent.getData().getSchemeSpecificPart();
-                    onPackageFullyRemoved(packageName);
-                }
-            }
-        }, filter, null, getHandler());
-
-        IntentFilter enableRollbackFilter = new IntentFilter();
-        enableRollbackFilter.addAction(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
-        try {
-            enableRollbackFilter.addDataType("application/vnd.android.package-archive");
-        } catch (IntentFilter.MalformedMimeTypeException e) {
-            Log.e(TAG, "addDataType", e);
-        }
-
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (Intent.ACTION_PACKAGE_ENABLE_ROLLBACK.equals(intent.getAction())) {
-                    int token = intent.getIntExtra(
-                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1);
-                    int installFlags = intent.getIntExtra(
-                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, 0);
-                    File newPackageCodePath = new File(intent.getData().getPath());
-
-                    getHandler().post(() -> {
-                        boolean success = enableRollback(installFlags, newPackageCodePath);
-                        int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED;
-                        if (!success) {
-                            ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED;
-                        }
-
-                        PackageManagerInternal pm = LocalServices.getService(
-                                PackageManagerInternal.class);
-                        pm.setEnableRollbackCode(token, ret);
-                    });
-
-                    // We're handling the ordered broadcast. Abort the
-                    // broadcast because there is no need for it to go to
-                    // anyone else.
-                    abortBroadcast();
-                }
-            }
-        }, enableRollbackFilter, null, getHandler());
+    public RollbackManagerService(Context context) {
+        super(context);
     }
 
     @Override
-    public RollbackInfo getAvailableRollback(String packageName) {
-        PackageRollbackInfo.PackageVersion installedVersion =
-                getInstalledPackageVersion(packageName);
-        if (installedVersion == null) {
-            return null;
-        }
-
-        synchronized (mLock) {
-            // TODO: Have ensureRollbackDataLoadedLocked return the list of
-            // available rollbacks, to hopefully avoid forgetting to call it?
-            ensureRollbackDataLoadedLocked();
-            for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
-                PackageRollbackData data = mAvailableRollbacks.get(i);
-                if (data.info.higherVersion.equals(installedVersion)) {
-                    // TODO: For atomic installs, check all dependent packages
-                    // for available rollbacks and include that info here.
-                    return new RollbackInfo(data.info);
-                }
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    public StringParceledListSlice getPackagesWithAvailableRollbacks() {
-        // TODO: This may return packages whose rollback is out of date or
-        // expired.  Presumably that's okay because the package rollback could
-        // be expired anyway between when the caller calls this method and
-        // when the caller calls getAvailableRollback for more details.
-        final Set<String> packageNames = new HashSet<>();
-        synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-            for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
-                PackageRollbackData data = mAvailableRollbacks.get(i);
-                packageNames.add(data.info.packageName);
-            }
-        }
-        return new StringParceledListSlice(new ArrayList<>(packageNames));
-    }
-
-    @Override
-    public ParceledListSlice<RollbackInfo> getRecentlyExecutedRollbacks() {
-        synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-            List<RollbackInfo> rollbacks = new ArrayList<>(mRecentlyExecutedRollbacks);
-            return new ParceledListSlice<>(rollbacks);
-        }
-    }
-
-    @Override
-    public void executeRollback(RollbackInfo rollback, String callerPackageName,
-            IntentSender statusReceiver) {
-        final int callingUid = Binder.getCallingUid();
-        if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
-            AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
-            appOps.checkPackage(callingUid, callerPackageName);
-        }
-
-        getHandler().post(() ->
-                executeRollbackInternal(rollback, callerPackageName, statusReceiver));
-    }
-
-    /**
-     * Performs the actual work to execute a rollback.
-     * The work is done on the current thread. This may be a long running
-     * operation.
-     */
-    private void executeRollbackInternal(RollbackInfo rollback,
-            String callerPackageName, IntentSender statusReceiver) {
-        String packageName = rollback.targetPackage.packageName;
-        Log.i(TAG, "Initiating rollback of " + packageName);
-
-        PackageRollbackInfo.PackageVersion installedVersion =
-                getInstalledPackageVersion(packageName);
-        if (installedVersion == null) {
-            // TODO: Test this case
-            sendFailure(statusReceiver, "Target package to roll back is not installed");
-            return;
-        }
-
-        if (!rollback.targetPackage.higherVersion.equals(installedVersion)) {
-            // TODO: Test this case
-            sendFailure(statusReceiver, "Target package version to roll back not installed.");
-            return;
-        }
-
-        // TODO: We assume that between now and the time we commit the
-        // downgrade install, the currently installed package version does not
-        // change. This is not safe to assume, particularly in the case of a
-        // rollback racing with a roll-forward fix of a buggy package.
-        // Figure out how to ensure we don't commit the rollback if
-        // roll forward happens at the same time.
-        PackageRollbackData data = null;
-        synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-            for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
-                PackageRollbackData available = mAvailableRollbacks.get(i);
-                // TODO: Check if available.info.lowerVersion matches
-                // rollback.targetPackage.lowerVersion?
-                if (available.info.higherVersion.equals(installedVersion)) {
-                    data = available;
-                    break;
-                }
-            }
-        }
-
-        if (data == null) {
-            sendFailure(statusReceiver, "Rollback not available");
-            return;
-        }
-
-        // Get a context for the caller to use to install the downgraded
-        // version of the package.
-        Context context = null;
-        try {
-            context = mContext.createPackageContext(callerPackageName, 0);
-        } catch (PackageManager.NameNotFoundException e) {
-            sendFailure(statusReceiver, "Invalid callerPackageName");
-            return;
-        }
-
-        PackageManager pm = context.getPackageManager();
-        try {
-            PackageInstaller.Session session = null;
-
-            PackageInstaller packageInstaller = pm.getPackageInstaller();
-            PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
-                    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-            params.setAllowDowngrade(true);
-            int sessionId = packageInstaller.createSession(params);
-            session = packageInstaller.openSession(sessionId);
-
-            // TODO: Will it always be called "base.apk"? What about splits?
-            File baseApk = new File(data.backupDir, "base.apk");
-            try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(baseApk,
-                    ParcelFileDescriptor.MODE_READ_ONLY)) {
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    session.write("base.apk", 0, baseApk.length(), fd);
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-            }
-
-            final LocalIntentReceiver receiver = new LocalIntentReceiver();
-            session.commit(receiver.getIntentSender());
-
-            Intent result = receiver.getResult();
-            int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                    PackageInstaller.STATUS_FAILURE);
-            if (status != PackageInstaller.STATUS_SUCCESS) {
-                sendFailure(statusReceiver, "Rollback downgrade install failed: "
-                        + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE));
-                return;
-            }
-
-            addRecentlyExecutedRollback(rollback);
-            sendSuccess(statusReceiver);
-
-            // TODO: Restrict permissions for who can listen for this
-            // broadcast?
-            Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED,
-                    Uri.fromParts("package", packageName, null));
-
-            // TODO: This call emits the warning "Calling a method in the
-            // system process without a qualified user". Fix that.
-            mContext.sendBroadcast(broadcast);
-        } catch (IOException e) {
-            Log.e(TAG, "Unable to roll back " + packageName, e);
-            sendFailure(statusReceiver, "IOException: " + e.toString());
-            return;
-        }
-    }
-
-    @Override
-    public void reloadPersistedData() {
-        synchronized (mLock) {
-            mAvailableRollbacks = null;
-            mRecentlyExecutedRollbacks = null;
-        }
-        getHandler().post(() -> ensureRollbackDataLoaded());
-    }
-
-    @Override
-    public void expireRollbackForPackage(String packageName) {
-        // TODO: Should this take a package version number in addition to
-        // package name? For now, just remove all rollbacks matching the
-        // package name. This method is only currently used to facilitate
-        // testing anyway.
-        synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-            Iterator<PackageRollbackData> iter = mAvailableRollbacks.iterator();
-            while (iter.hasNext()) {
-                PackageRollbackData data = iter.next();
-                if (data.info.packageName.equals(packageName)) {
-                    iter.remove();
-                    removeFile(data.backupDir);
-                }
-            }
-        }
-    }
-
-    /**
-     * Load rollback data from storage if it has not already been loaded.
-     * After calling this funciton, mAvailableRollbacks and
-     * mRecentlyExecutedRollbacks will be non-null.
-     */
-    private void ensureRollbackDataLoaded() {
-        synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-        }
-    }
-
-    /**
-     * Load rollback data from storage if it has not already been loaded.
-     * After calling this function, mAvailableRollbacks and
-     * mRecentlyExecutedRollbacks will be non-null.
-     */
-    @GuardedBy("mLock")
-    private void ensureRollbackDataLoadedLocked() {
-        if (mAvailableRollbacks == null) {
-            loadRollbackDataLocked();
-        }
-    }
-
-    /**
-     * Load rollback data from storage.
-     * Note: We do potentially heavy IO here while holding mLock, because we
-     * have to have the rollback data loaded before we can do anything else
-     * meaningful.
-     */
-    @GuardedBy("mLock")
-    private void loadRollbackDataLocked() {
-        mAvailableRollbacksDir.mkdirs();
-        mAvailableRollbacks = new ArrayList<>();
-        for (File rollbackDir : mAvailableRollbacksDir.listFiles()) {
-            if (rollbackDir.isDirectory()) {
-                // TODO: How to detect and clean up an invalid rollback
-                // directory? We don't know if it's invalid because something
-                // went wrong, or if it's only temporarily invalid because
-                // it's in the process of being created.
-                try {
-                    File jsonFile = new File(rollbackDir, "rollback.json");
-                    String jsonString = IoUtils.readFileAsString(jsonFile.getAbsolutePath());
-                    JSONObject jsonObject = new JSONObject(jsonString);
-                    String packageName = jsonObject.getString("packageName");
-                    long higherVersionCode = jsonObject.getLong("higherVersionCode");
-                    long lowerVersionCode = jsonObject.getLong("lowerVersionCode");
-                    Instant timestamp = Instant.parse(jsonObject.getString("timestamp"));
-                    PackageRollbackData data = new PackageRollbackData(
-                            new PackageRollbackInfo(packageName,
-                                new PackageRollbackInfo.PackageVersion(higherVersionCode),
-                                new PackageRollbackInfo.PackageVersion(lowerVersionCode)),
-                            rollbackDir, timestamp);
-                    mAvailableRollbacks.add(data);
-                } catch (IOException | JSONException | DateTimeParseException e) {
-                    Log.e(TAG, "Unable to read rollback data at " + rollbackDir, e);
-                }
-            }
-        }
-
-        mRecentlyExecutedRollbacks = new ArrayList<>();
-        if (mRecentlyExecutedRollbacksFile.exists()) {
-            try {
-                // TODO: How to cope with changes to the format of this file from
-                // when RollbackStore is updated in the future?
-                String jsonString = IoUtils.readFileAsString(
-                        mRecentlyExecutedRollbacksFile.getAbsolutePath());
-                JSONObject object = new JSONObject(jsonString);
-                JSONArray array = object.getJSONArray("recentlyExecuted");
-                for (int i = 0; i < array.length(); ++i) {
-                    JSONObject element = array.getJSONObject(i);
-                    String packageName = element.getString("packageName");
-                    long higherVersionCode = element.getLong("higherVersionCode");
-                    long lowerVersionCode = element.getLong("lowerVersionCode");
-                    PackageRollbackInfo target = new PackageRollbackInfo(packageName,
-                            new PackageRollbackInfo.PackageVersion(higherVersionCode),
-                            new PackageRollbackInfo.PackageVersion(lowerVersionCode));
-                    RollbackInfo rollback = new RollbackInfo(target);
-                    mRecentlyExecutedRollbacks.add(rollback);
-                }
-            } catch (IOException | JSONException e) {
-                // TODO: What to do here? Surely we shouldn't just forget about
-                // everything after the point of exception?
-                Log.e(TAG, "Failed to read recently executed rollbacks", e);
-            }
-        }
-
-        scheduleExpiration(0);
-    }
-
-    /**
-     * Called when a package has been replaced with a different version.
-     * Removes all backups for the package not matching the currently
-     * installed package version.
-     */
-    private void onPackageReplaced(String packageName) {
-        // TODO: Could this end up incorrectly deleting a rollback for a
-        // package that is about to be installed?
-        PackageRollbackInfo.PackageVersion installedVersion =
-                getInstalledPackageVersion(packageName);
-
-        synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-            Iterator<PackageRollbackData> iter = mAvailableRollbacks.iterator();
-            while (iter.hasNext()) {
-                PackageRollbackData data = iter.next();
-                if (data.info.packageName.equals(packageName)
-                        && !data.info.higherVersion.equals(installedVersion)) {
-                    iter.remove();
-                    removeFile(data.backupDir);
-                }
-            }
-        }
-    }
-
-    /**
-     * Called when a package has been completely removed from the device.
-     * Removes all backups and rollback history for the given package.
-     */
-    private void onPackageFullyRemoved(String packageName) {
-        expireRollbackForPackage(packageName);
-
-        synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-            Iterator<RollbackInfo> iter = mRecentlyExecutedRollbacks.iterator();
-            boolean changed = false;
-            while (iter.hasNext()) {
-                RollbackInfo rollback = iter.next();
-                if (packageName.equals(rollback.targetPackage.packageName)) {
-                    iter.remove();
-                    changed = true;
-                }
-            }
-
-            if (changed) {
-                saveRecentlyExecutedRollbacksLocked();
-            }
-        }
-    }
-
-    /**
-     * Write the list of recently executed rollbacks to storage.
-     * Note: This happens while mLock is held, which should be okay because we
-     * expect executed rollbacks to be modified only in exceptional cases.
-     */
-    @GuardedBy("mLock")
-    private void saveRecentlyExecutedRollbacksLocked() {
-        try {
-            JSONObject json = new JSONObject();
-            JSONArray array = new JSONArray();
-            json.put("recentlyExecuted", array);
-
-            for (int i = 0; i < mRecentlyExecutedRollbacks.size(); ++i) {
-                RollbackInfo rollback = mRecentlyExecutedRollbacks.get(i);
-                JSONObject element = new JSONObject();
-                element.put("packageName", rollback.targetPackage.packageName);
-                element.put("higherVersionCode", rollback.targetPackage.higherVersion.versionCode);
-                element.put("lowerVersionCode", rollback.targetPackage.lowerVersion.versionCode);
-                array.put(element);
-            }
-
-            PrintWriter pw = new PrintWriter(mRecentlyExecutedRollbacksFile);
-            pw.println(json.toString());
-            pw.close();
-        } catch (IOException | JSONException e) {
-            // TODO: What to do here?
-            Log.e(TAG, "Failed to save recently executed rollbacks", e);
-        }
-    }
-
-    /**
-     * Records that the given package has been recently rolled back.
-     */
-    private void addRecentlyExecutedRollback(RollbackInfo rollback) {
-        // TODO: if the list of rollbacks gets too big, trim it to only those
-        // that are necessary to keep track of.
-        synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-            mRecentlyExecutedRollbacks.add(rollback);
-            saveRecentlyExecutedRollbacksLocked();
-        }
-    }
-
-    /**
-     * Notifies an IntentSender of failure.
-     *
-     * @param statusReceiver where to send the failure
-     * @param message the failure message.
-     */
-    private void sendFailure(IntentSender statusReceiver, String message) {
-        Log.e(TAG, message);
-        try {
-            // TODO: More context on which rollback failed?
-            // TODO: More refined failure code?
-            final Intent fillIn = new Intent();
-            fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
-            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, message);
-            statusReceiver.sendIntent(mContext, 0, fillIn, null, null);
-        } catch (IntentSender.SendIntentException e) {
-            // Nowhere to send the result back to, so don't bother.
-        }
-    }
-
-    /**
-     * Notifies an IntentSender of success.
-     */
-    private void sendSuccess(IntentSender statusReceiver) {
-        try {
-            final Intent fillIn = new Intent();
-            fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_SUCCESS);
-            statusReceiver.sendIntent(mContext, 0, fillIn, null, null);
-        } catch (IntentSender.SendIntentException e) {
-            // Nowhere to send the result back to, so don't bother.
-        }
-    }
-
-    // Check to see if anything needs expiration, and if so, expire it.
-    // Schedules future expiration as appropriate.
-    // TODO: Handle cases where the user changes time on the device.
-    private void runExpiration() {
-        Instant now = Instant.now();
-        Instant oldest = null;
-        synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-
-            Iterator<PackageRollbackData> iter = mAvailableRollbacks.iterator();
-            while (iter.hasNext()) {
-                PackageRollbackData data = iter.next();
-                if (!now.isBefore(data.timestamp.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS))) {
-                    iter.remove();
-                    removeFile(data.backupDir);
-                } else if (oldest == null || oldest.isAfter(data.timestamp)) {
-                    oldest = data.timestamp;
-                }
-            }
-        }
-
-        if (oldest != null) {
-            scheduleExpiration(now.until(oldest.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS),
-                        ChronoUnit.MILLIS));
-        }
-    }
-
-    /**
-     * Schedules an expiration check to be run after the given duration in
-     * milliseconds has gone by.
-     */
-    private void scheduleExpiration(long duration) {
-        getHandler().postDelayed(() -> runExpiration(), duration);
-    }
-
-    /**
-     * Gets the RollbackManagerService's handler.
-     * To allow PackageManagerService to call into RollbackManagerService
-     * without fear of blocking the PackageManagerService thread.
-     */
-    public Handler getHandler() {
-        return mHandlerThread.getThreadHandler();
-    }
-
-    /**
-     * Called via broadcast by the package manager when a package is being
-     * staged for install with rollback enabled. Called before the package has
-     * been installed.
-     *
-     * @param id the id of the enable rollback request
-     * @param installFlags information about what is being installed.
-     * @param newPackageCodePath path to the package about to be installed.
-     * @return true if enabling the rollback succeeds, false otherwise.
-     */
-    private boolean enableRollback(int installFlags, File newPackageCodePath) {
-        if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
-            Log.e(TAG, "Rollbacks not supported for instant app install");
-            return false;
-        }
-        if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
-            Log.e(TAG, "Rollbacks not supported for apex install");
-            return false;
-        }
-
-        // Get information about the package to be installed.
-        PackageParser.PackageLite newPackage = null;
-        try {
-            newPackage = PackageParser.parsePackageLite(newPackageCodePath, 0);
-        } catch (PackageParser.PackageParserException e) {
-            Log.e(TAG, "Unable to parse new package", e);
-            return false;
-        }
-
-        String packageName = newPackage.packageName;
-        Log.i(TAG, "Enabling rollback for install of " + packageName);
-
-        PackageRollbackInfo.PackageVersion newVersion =
-                new PackageRollbackInfo.PackageVersion(newPackage.versionCode);
-
-        // Get information about the currently installed package.
-        PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
-        PackageParser.Package installedPackage = pm.getPackage(packageName);
-        if (installedPackage == null) {
-            // TODO: Support rolling back fresh package installs rather than
-            // fail here. Test this case.
-            Log.e(TAG, packageName + " is not installed");
-            return false;
-        }
-        PackageRollbackInfo.PackageVersion installedVersion =
-                new PackageRollbackInfo.PackageVersion(installedPackage.getLongVersionCode());
-
-        File backupDir;
-        try {
-            backupDir = Files.createTempDirectory(
-                mAvailableRollbacksDir.toPath(), packageName + "-").toFile();
-        } catch (IOException e) {
-            Log.e(TAG, "Unable to create rollback for " + packageName, e);
-            return false;
-        }
-
-        // TODO: Should the timestamp be for when we commit the install, not
-        // when we create the pending one?
-        Instant timestamp = Instant.now();
-        try {
-            JSONObject json = new JSONObject();
-            json.put("packageName", packageName);
-            json.put("higherVersionCode", newVersion.versionCode);
-            json.put("lowerVersionCode", installedVersion.versionCode);
-            json.put("timestamp", timestamp.toString());
-
-            File jsonFile = new File(backupDir, "rollback.json");
-            PrintWriter pw = new PrintWriter(jsonFile);
-            pw.println(json.toString());
-            pw.close();
-        } catch (IOException | JSONException e) {
-            Log.e(TAG, "Unable to create rollback for " + packageName, e);
-            removeFile(backupDir);
-            return false;
-        }
-
-        // TODO: Copy by hard link instead to save on cpu and storage space?
-        int status = PackageManagerServiceUtils.copyPackage(installedPackage.codePath, backupDir);
-        if (status != PackageManager.INSTALL_SUCCEEDED) {
-            Log.e(TAG, "Unable to copy package for rollback for " + packageName);
-            removeFile(backupDir);
-            return false;
-        }
-
-        PackageRollbackData data = new PackageRollbackData(
-                new PackageRollbackInfo(packageName, newVersion, installedVersion),
-                backupDir, timestamp);
-
-        synchronized (mLock) {
-            ensureRollbackDataLoadedLocked();
-            mAvailableRollbacks.add(data);
-        }
-
-        return true;
-    }
-
-    // TODO: Don't copy this from PackageManagerShellCommand like this?
-    private static class LocalIntentReceiver {
-        private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>();
-
-        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
-            @Override
-            public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
-                    IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
-                try {
-                    mResult.offer(intent, 5, TimeUnit.SECONDS);
-                } catch (InterruptedException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        };
-
-        public IntentSender getIntentSender() {
-            return new IntentSender((IIntentSender) mLocalSender);
-        }
-
-        public Intent getResult() {
-            try {
-                return mResult.take();
-            } catch (InterruptedException e) {
-                throw new RuntimeException(e);
-            }
-        }
-    }
-
-    /**
-     * Deletes a file completely.
-     * If the file is a directory, its contents are deleted as well.
-     * Has no effect if the directory does not exist.
-     */
-    private void removeFile(File file) {
-        if (file.isDirectory()) {
-            for (File child : file.listFiles()) {
-                removeFile(child);
-            }
-        }
-        if (file.exists()) {
-            file.delete();
-        }
-    }
-
-    /**
-     * Gets the version of the package currently installed.
-     * Returns null if the package is not currently installed.
-     */
-    private PackageRollbackInfo.PackageVersion getInstalledPackageVersion(String packageName) {
-        PackageManager pm = mContext.getPackageManager();
-        PackageInfo pkgInfo = null;
-        try {
-            pkgInfo = pm.getPackageInfo(packageName, 0);
-        } catch (PackageManager.NameNotFoundException e) {
-            return null;
-        }
-
-        return new PackageRollbackInfo.PackageVersion(pkgInfo.getLongVersionCode());
-    }
-
-    /**
-     * Manages the lifecycle of RollbackManagerService within System Server.
-     */
-    public static class Lifecycle extends SystemService {
-        private RollbackManagerService mService;
-
-        public Lifecycle(Context context) {
-            super(context);
-        }
-
-        @Override
-        public void onStart() {
-            mService = new RollbackManagerService(getContext());
-
-            // TODO: Set up sepolicy to allow publishing the service.
-            if (SELinux.isSELinuxEnforced()) {
-                Log.w(TAG, "RollbackManager disabled pending selinux policy updates");
-            } else {
-                publishBinderService(Context.ROLLBACK_SERVICE, mService);
-            }
-        }
+    public void onStart() {
+        mService = new RollbackManagerServiceImpl(getContext());
+        publishBinderService(Context.ROLLBACK_SERVICE, mService);
     }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
new file mode 100644
index 0000000..7f515bf
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -0,0 +1,945 @@
+/*
+ * 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.rollback;
+
+import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageParser;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.StringParceledListSlice;
+import android.content.pm.VersionedPackage;
+import android.content.rollback.IRollbackManager;
+import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.RollbackInfo;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.storage.StorageManager;
+import android.util.Log;
+import android.util.SparseBooleanArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.pm.Installer;
+import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.PackageManagerServiceUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.SecureRandom;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.function.Consumer;
+
+/**
+ * Implementation of service that manages APK level rollbacks.
+ */
+class RollbackManagerServiceImpl extends IRollbackManager.Stub {
+
+    private static final String TAG = "RollbackManager";
+
+    // Rollbacks expire after 48 hours.
+    // TODO: How to test rollback expiration works properly?
+    private static final long ROLLBACK_LIFETIME_DURATION_MILLIS = 48 * 60 * 60 * 1000;
+
+    // Lock used to synchronize accesses to in-memory rollback data
+    // structures. By convention, methods with the suffix "Locked" require
+    // mLock is held when they are called.
+    private final Object mLock = new Object();
+
+    // Used for generating rollback IDs.
+    private final Random mRandom = new SecureRandom();
+
+    // Set of allocated rollback ids
+    @GuardedBy("mLock")
+    private final SparseBooleanArray mAllocatedRollbackIds = new SparseBooleanArray();
+
+    // Package rollback data for rollback-enabled installs that have not yet
+    // been committed. Maps from sessionId to rollback data.
+    @GuardedBy("mLock")
+    private final Map<Integer, RollbackData> mPendingRollbacks = new HashMap<>();
+
+    // Map from child session id's for enabled rollbacks to their
+    // corresponding parent session ids.
+    @GuardedBy("mLock")
+    private final Map<Integer, Integer> mChildSessions = new HashMap<>();
+
+    // Package rollback data available to be used for rolling back a package.
+    // This list is null until the rollback data has been loaded.
+    @GuardedBy("mLock")
+    private List<RollbackData> mAvailableRollbacks;
+
+    // The list of recently executed rollbacks.
+    // This list is null until the rollback data has been loaded.
+    @GuardedBy("mLock")
+    private List<RollbackInfo> mRecentlyExecutedRollbacks;
+
+    private final RollbackStore mRollbackStore;
+
+    private final Context mContext;
+    private final HandlerThread mHandlerThread;
+    private final Installer mInstaller;
+
+    RollbackManagerServiceImpl(Context context) {
+        mContext = context;
+        // Note that we're calling onStart here because this object is only constructed on
+        // SystemService#onStart.
+        mInstaller = new Installer(mContext);
+        mInstaller.onStart();
+        mHandlerThread = new HandlerThread("RollbackManagerServiceHandler");
+        mHandlerThread.start();
+
+        mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));
+
+        // Kick off loading of the rollback data from strorage in a background
+        // thread.
+        // TODO: Consider loading the rollback data directly here instead, to
+        // avoid the need to call ensureRollbackDataLoaded every time before
+        // accessing the rollback data?
+        // TODO: Test that this kicks off initial scheduling of rollback
+        // expiration.
+        getHandler().post(() -> ensureRollbackDataLoaded());
+
+        PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller();
+        packageInstaller.registerSessionCallback(new SessionCallback(), getHandler());
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+        filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+        filter.addDataScheme("package");
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
+                    String packageName = intent.getData().getSchemeSpecificPart();
+                    onPackageReplaced(packageName);
+                }
+                if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
+                    String packageName = intent.getData().getSchemeSpecificPart();
+                    onPackageFullyRemoved(packageName);
+                }
+            }
+        }, filter, null, getHandler());
+
+        IntentFilter enableRollbackFilter = new IntentFilter();
+        enableRollbackFilter.addAction(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
+        try {
+            enableRollbackFilter.addDataType("application/vnd.android.package-archive");
+        } catch (IntentFilter.MalformedMimeTypeException e) {
+            Log.e(TAG, "addDataType", e);
+        }
+
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (Intent.ACTION_PACKAGE_ENABLE_ROLLBACK.equals(intent.getAction())) {
+                    int token = intent.getIntExtra(
+                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1);
+                    int installFlags = intent.getIntExtra(
+                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, 0);
+                    int[] installedUsers = intent.getIntArrayExtra(
+                            PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALLED_USERS);
+                    File newPackageCodePath = new File(intent.getData().getPath());
+
+                    getHandler().post(() -> {
+                        boolean success = enableRollback(installFlags, newPackageCodePath,
+                                installedUsers);
+                        int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED;
+                        if (!success) {
+                            ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED;
+                        }
+
+                        PackageManagerInternal pm = LocalServices.getService(
+                                PackageManagerInternal.class);
+                        pm.setEnableRollbackCode(token, ret);
+                    });
+
+                    // We're handling the ordered broadcast. Abort the
+                    // broadcast because there is no need for it to go to
+                    // anyone else.
+                    abortBroadcast();
+                }
+            }
+        }, enableRollbackFilter, null, getHandler());
+    }
+
+    @Override
+    public RollbackInfo getAvailableRollback(String packageName) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_ROLLBACKS,
+                "getAvailableRollback");
+
+        RollbackData data = getRollbackForPackage(packageName);
+        if (data == null) {
+            return null;
+        }
+
+        // Note: The rollback for the package ought to be for the currently
+        // installed version, otherwise the rollback data is out of date. In
+        // that rare case, we'll check when we execute the rollback whether
+        // it's out of date or not, so no need to check package versions here.
+
+        for (PackageRollbackInfo info : data.packages) {
+            if (info.getPackageName().equals(packageName)) {
+                // TODO: Once the RollbackInfo API supports info about
+                // dependant packages, add that info here.
+                return new RollbackInfo(data.rollbackId, info);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public StringParceledListSlice getPackagesWithAvailableRollbacks() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_ROLLBACKS,
+                "getPackagesWithAvailableRollbacks");
+
+        final Set<String> packageNames = new HashSet<>();
+        synchronized (mLock) {
+            ensureRollbackDataLoadedLocked();
+            for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
+                RollbackData data = mAvailableRollbacks.get(i);
+                for (PackageRollbackInfo info : data.packages) {
+                    packageNames.add(info.getPackageName());
+                }
+            }
+        }
+        return new StringParceledListSlice(new ArrayList<>(packageNames));
+    }
+
+    @Override
+    public ParceledListSlice<RollbackInfo> getRecentlyExecutedRollbacks() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_ROLLBACKS,
+                "getRecentlyExecutedRollbacks");
+
+        synchronized (mLock) {
+            ensureRollbackDataLoadedLocked();
+            List<RollbackInfo> rollbacks = new ArrayList<>(mRecentlyExecutedRollbacks);
+            return new ParceledListSlice<>(rollbacks);
+        }
+    }
+
+    @Override
+    public void executeRollback(RollbackInfo rollback, String callerPackageName,
+            IntentSender statusReceiver) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_ROLLBACKS,
+                "executeRollback");
+
+        final int callingUid = Binder.getCallingUid();
+        AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+        appOps.checkPackage(callingUid, callerPackageName);
+
+        getHandler().post(() ->
+                executeRollbackInternal(rollback, callerPackageName, statusReceiver));
+    }
+
+    /**
+     * Performs the actual work to execute a rollback.
+     * The work is done on the current thread. This may be a long running
+     * operation.
+     */
+    private void executeRollbackInternal(RollbackInfo rollback,
+            String callerPackageName, IntentSender statusReceiver) {
+        String targetPackageName = rollback.targetPackage.getPackageName();
+        Log.i(TAG, "Initiating rollback of " + targetPackageName);
+
+        // Get the latest RollbackData for the target package.
+        RollbackData data = getRollbackForPackage(targetPackageName);
+        if (data == null) {
+            sendFailure(statusReceiver, "No rollback available for package.");
+            return;
+        }
+
+        if (data.rollbackId != rollback.getRollbackId()) {
+            sendFailure(statusReceiver, "Rollback for package is out of date");
+            return;
+        }
+
+        // Verify the RollbackData is up to date with what's installed on
+        // device.
+        // TODO: We assume that between now and the time we commit the
+        // downgrade install, the currently installed package version does not
+        // change. This is not safe to assume, particularly in the case of a
+        // rollback racing with a roll-forward fix of a buggy package.
+        // Figure out how to ensure we don't commit the rollback if
+        // roll forward happens at the same time.
+        for (PackageRollbackInfo info : data.packages) {
+            VersionedPackage installedVersion = getInstalledPackageVersion(info.getPackageName());
+            if (installedVersion == null) {
+                // TODO: Test this case
+                sendFailure(statusReceiver, "Package to roll back is not installed");
+                return;
+            }
+
+            if (!packageVersionsEqual(info.getVersionRolledBackFrom(), installedVersion)) {
+                // TODO: Test this case
+                sendFailure(statusReceiver, "Package version to roll back not installed.");
+                return;
+            }
+        }
+
+        // Get a context for the caller to use to install the downgraded
+        // version of the package.
+        Context context = null;
+        try {
+            context = mContext.createPackageContext(callerPackageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            sendFailure(statusReceiver, "Invalid callerPackageName");
+            return;
+        }
+
+        PackageManager pm = context.getPackageManager();
+        try {
+            PackageInstaller packageInstaller = pm.getPackageInstaller();
+            String installerPackageName = pm.getInstallerPackageName(targetPackageName);
+            if (installerPackageName == null) {
+                sendFailure(statusReceiver, "Cannot find installer package");
+                return;
+            }
+            PackageInstaller.SessionParams parentParams = new PackageInstaller.SessionParams(
+                    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+            parentParams.setInstallerPackageName(installerPackageName);
+            parentParams.setAllowDowngrade(true);
+            parentParams.setMultiPackage();
+            int parentSessionId = packageInstaller.createSession(parentParams);
+            PackageInstaller.Session parentSession = packageInstaller.openSession(parentSessionId);
+
+            for (PackageRollbackInfo info : data.packages) {
+                PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+                        PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+                params.setInstallerPackageName(installerPackageName);
+                params.setAllowDowngrade(true);
+                int sessionId = packageInstaller.createSession(params);
+                PackageInstaller.Session session = packageInstaller.openSession(sessionId);
+
+                // TODO: Will it always be called "base.apk"? What about splits?
+                // What about apex?
+                File packageDir = new File(data.backupDir, info.getPackageName());
+                File baseApk = new File(packageDir, "base.apk");
+                try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(baseApk,
+                        ParcelFileDescriptor.MODE_READ_ONLY)) {
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        session.write("base.apk", 0, baseApk.length(), fd);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+                parentSession.addChildSessionId(sessionId);
+            }
+
+            final LocalIntentReceiver receiver = new LocalIntentReceiver(
+                    (Intent result) -> {
+                        int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                                PackageInstaller.STATUS_FAILURE);
+                        if (status != PackageInstaller.STATUS_SUCCESS) {
+                            sendFailure(statusReceiver, "Rollback downgrade install failed: "
+                                    + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE));
+                            return;
+                        }
+
+                        addRecentlyExecutedRollback(rollback);
+                        sendSuccess(statusReceiver);
+
+                        Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
+
+                        // TODO: This call emits the warning "Calling a method in the
+                        // system process without a qualified user". Fix that.
+                        // TODO: Limit this to receivers holding the
+                        // MANAGE_ROLLBACKS permission?
+                        mContext.sendBroadcast(broadcast);
+                    }
+            );
+
+            parentSession.commit(receiver.getIntentSender());
+        } catch (IOException e) {
+            Log.e(TAG, "Unable to roll back " + targetPackageName, e);
+            sendFailure(statusReceiver, "IOException: " + e.toString());
+            return;
+        }
+    }
+
+    @Override
+    public void reloadPersistedData() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_ROLLBACKS,
+                "reloadPersistedData");
+
+        synchronized (mLock) {
+            mAvailableRollbacks = null;
+            mRecentlyExecutedRollbacks = null;
+        }
+        getHandler().post(() -> ensureRollbackDataLoaded());
+    }
+
+    @Override
+    public void expireRollbackForPackage(String packageName) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_ROLLBACKS,
+                "expireRollbackForPackage");
+
+        // TODO: Should this take a package version number in addition to
+        // package name? For now, just remove all rollbacks matching the
+        // package name. This method is only currently used to facilitate
+        // testing anyway.
+        synchronized (mLock) {
+            ensureRollbackDataLoadedLocked();
+            Iterator<RollbackData> iter = mAvailableRollbacks.iterator();
+            while (iter.hasNext()) {
+                RollbackData data = iter.next();
+                for (PackageRollbackInfo info : data.packages) {
+                    if (info.getPackageName().equals(packageName)) {
+                        iter.remove();
+                        mRollbackStore.deleteAvailableRollback(data);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Load rollback data from storage if it has not already been loaded.
+     * After calling this funciton, mAvailableRollbacks and
+     * mRecentlyExecutedRollbacks will be non-null.
+     */
+    private void ensureRollbackDataLoaded() {
+        synchronized (mLock) {
+            ensureRollbackDataLoadedLocked();
+        }
+    }
+
+    /**
+     * Load rollback data from storage if it has not already been loaded.
+     * After calling this function, mAvailableRollbacks and
+     * mRecentlyExecutedRollbacks will be non-null.
+     */
+    @GuardedBy("mLock")
+    private void ensureRollbackDataLoadedLocked() {
+        if (mAvailableRollbacks == null) {
+            loadAllRollbackDataLocked();
+        }
+    }
+
+    /**
+     * Load all rollback data from storage.
+     * Note: We do potentially heavy IO here while holding mLock, because we
+     * have to have the rollback data loaded before we can do anything else
+     * meaningful.
+     */
+    @GuardedBy("mLock")
+    private void loadAllRollbackDataLocked() {
+        mAvailableRollbacks = mRollbackStore.loadAvailableRollbacks();
+        for (RollbackData data : mAvailableRollbacks) {
+            mAllocatedRollbackIds.put(data.rollbackId, true);
+        }
+
+        mRecentlyExecutedRollbacks = mRollbackStore.loadRecentlyExecutedRollbacks();
+        for (RollbackInfo info : mRecentlyExecutedRollbacks) {
+            mAllocatedRollbackIds.put(info.getRollbackId(), true);
+        }
+
+        scheduleExpiration(0);
+    }
+
+    /**
+     * Called when a package has been replaced with a different version.
+     * Removes all backups for the package not matching the currently
+     * installed package version.
+     */
+    private void onPackageReplaced(String packageName) {
+        // TODO: Could this end up incorrectly deleting a rollback for a
+        // package that is about to be installed?
+        VersionedPackage installedVersion = getInstalledPackageVersion(packageName);
+
+        synchronized (mLock) {
+            ensureRollbackDataLoadedLocked();
+            Iterator<RollbackData> iter = mAvailableRollbacks.iterator();
+            while (iter.hasNext()) {
+                RollbackData data = iter.next();
+                for (PackageRollbackInfo info : data.packages) {
+                    if (info.getPackageName().equals(packageName)
+                            && !packageVersionsEqual(
+                                        info.getVersionRolledBackFrom(),
+                                        installedVersion)) {
+                        iter.remove();
+                        mRollbackStore.deleteAvailableRollback(data);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Called when a package has been completely removed from the device.
+     * Removes all backups and rollback history for the given package.
+     */
+    private void onPackageFullyRemoved(String packageName) {
+        expireRollbackForPackage(packageName);
+
+        synchronized (mLock) {
+            ensureRollbackDataLoadedLocked();
+            Iterator<RollbackInfo> iter = mRecentlyExecutedRollbacks.iterator();
+            boolean changed = false;
+            while (iter.hasNext()) {
+                RollbackInfo rollback = iter.next();
+                if (packageName.equals(rollback.targetPackage.getPackageName())) {
+                    iter.remove();
+                    changed = true;
+                }
+            }
+
+            if (changed) {
+                mRollbackStore.saveRecentlyExecutedRollbacks(mRecentlyExecutedRollbacks);
+            }
+        }
+    }
+
+    /**
+     * Records that the given package has been recently rolled back.
+     */
+    private void addRecentlyExecutedRollback(RollbackInfo rollback) {
+        // TODO: if the list of rollbacks gets too big, trim it to only those
+        // that are necessary to keep track of.
+        synchronized (mLock) {
+            ensureRollbackDataLoadedLocked();
+            mRecentlyExecutedRollbacks.add(rollback);
+            mRollbackStore.saveRecentlyExecutedRollbacks(mRecentlyExecutedRollbacks);
+        }
+    }
+
+    /**
+     * Notifies an IntentSender of failure.
+     *
+     * @param statusReceiver where to send the failure
+     * @param message the failure message.
+     */
+    private void sendFailure(IntentSender statusReceiver, String message) {
+        Log.e(TAG, message);
+        try {
+            // TODO: More context on which rollback failed?
+            // TODO: More refined failure code?
+            final Intent fillIn = new Intent();
+            fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
+            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, message);
+            statusReceiver.sendIntent(mContext, 0, fillIn, null, null);
+        } catch (IntentSender.SendIntentException e) {
+            // Nowhere to send the result back to, so don't bother.
+        }
+    }
+
+    /**
+     * Notifies an IntentSender of success.
+     */
+    private void sendSuccess(IntentSender statusReceiver) {
+        try {
+            final Intent fillIn = new Intent();
+            fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_SUCCESS);
+            statusReceiver.sendIntent(mContext, 0, fillIn, null, null);
+        } catch (IntentSender.SendIntentException e) {
+            // Nowhere to send the result back to, so don't bother.
+        }
+    }
+
+    // Check to see if anything needs expiration, and if so, expire it.
+    // Schedules future expiration as appropriate.
+    // TODO: Handle cases where the user changes time on the device.
+    private void runExpiration() {
+        Instant now = Instant.now();
+        Instant oldest = null;
+        synchronized (mLock) {
+            ensureRollbackDataLoadedLocked();
+
+            Iterator<RollbackData> iter = mAvailableRollbacks.iterator();
+            while (iter.hasNext()) {
+                RollbackData data = iter.next();
+                if (!now.isBefore(data.timestamp.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS))) {
+                    iter.remove();
+                    mRollbackStore.deleteAvailableRollback(data);
+                } else if (oldest == null || oldest.isAfter(data.timestamp)) {
+                    oldest = data.timestamp;
+                }
+            }
+        }
+
+        if (oldest != null) {
+            scheduleExpiration(now.until(oldest.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS),
+                        ChronoUnit.MILLIS));
+        }
+    }
+
+    /**
+     * Schedules an expiration check to be run after the given duration in
+     * milliseconds has gone by.
+     */
+    private void scheduleExpiration(long duration) {
+        getHandler().postDelayed(() -> runExpiration(), duration);
+    }
+
+    private Handler getHandler() {
+        return mHandlerThread.getThreadHandler();
+    }
+
+    // Returns true if <code>session</code> has installFlags and code path
+    // matching the installFlags and new package code path given to
+    // enableRollback.
+    private boolean sessionMatchesForEnableRollback(PackageInstaller.SessionInfo session,
+            int installFlags, File newPackageCodePath) {
+        if (session == null || session.resolvedBaseCodePath == null) {
+            return false;
+        }
+
+        File packageCodePath = new File(session.resolvedBaseCodePath).getParentFile();
+        if (newPackageCodePath.equals(packageCodePath) && installFlags == session.installFlags) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Called via broadcast by the package manager when a package is being
+     * staged for install with rollback enabled. Called before the package has
+     * been installed.
+     *
+     * @param installFlags information about what is being installed.
+     * @param newPackageCodePath path to the package about to be installed.
+     * @param installedUsers the set of users for which a given package is installed.
+     * @return true if enabling the rollback succeeds, false otherwise.
+     */
+    private boolean enableRollback(int installFlags, File newPackageCodePath,
+            int[] installedUsers) {
+        if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
+            Log.e(TAG, "Rollbacks not supported for instant app install");
+            return false;
+        }
+        if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
+            Log.e(TAG, "Rollbacks not supported for apex install");
+            return false;
+        }
+
+        // Get information about the package to be installed.
+        PackageParser.PackageLite newPackage = null;
+        try {
+            newPackage = PackageParser.parsePackageLite(newPackageCodePath, 0);
+        } catch (PackageParser.PackageParserException e) {
+            Log.e(TAG, "Unable to parse new package", e);
+            return false;
+        }
+
+        String packageName = newPackage.packageName;
+        Log.i(TAG, "Enabling rollback for install of " + packageName);
+
+        // Figure out the session id associated with this install.
+        int parentSessionId = PackageInstaller.SessionInfo.INVALID_ID;
+        int childSessionId = PackageInstaller.SessionInfo.INVALID_ID;
+        PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
+        for (PackageInstaller.SessionInfo info : installer.getAllSessions()) {
+            if (info.isMultiPackage()) {
+                for (int childId : info.getChildSessionIds()) {
+                    PackageInstaller.SessionInfo child = installer.getSessionInfo(childId);
+                    if (sessionMatchesForEnableRollback(child, installFlags, newPackageCodePath)) {
+                        // TODO: Check we only have one matching session?
+                        parentSessionId = info.getSessionId();
+                        childSessionId = childId;
+                    }
+                }
+            } else {
+                if (sessionMatchesForEnableRollback(info, installFlags, newPackageCodePath)) {
+                    // TODO: Check we only have one matching session?
+                    parentSessionId = info.getSessionId();
+                    childSessionId = parentSessionId;
+                }
+            }
+        }
+
+        if (parentSessionId == PackageInstaller.SessionInfo.INVALID_ID) {
+            Log.e(TAG, "Unable to find session id for enabled rollback.");
+            return false;
+        }
+
+        VersionedPackage newVersion = new VersionedPackage(packageName, newPackage.versionCode);
+
+        // Get information about the currently installed package.
+        PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
+        PackageParser.Package installedPackage = pm.getPackage(packageName);
+        if (installedPackage == null) {
+            // TODO: Support rolling back fresh package installs rather than
+            // fail here. Test this case.
+            Log.e(TAG, packageName + " is not installed");
+            return false;
+        }
+        VersionedPackage installedVersion = new VersionedPackage(packageName,
+                installedPackage.getLongVersionCode());
+
+        for (int user : installedUsers) {
+            final int storageFlags;
+            if (StorageManager.isFileEncryptedNativeOrEmulated()
+                    && !StorageManager.isUserKeyUnlocked(user)) {
+                // We've encountered a user that hasn't unlocked on a FBE device, so we can't copy
+                // across app user data until the user unlocks their device.
+                Log.e(TAG, "User: " + user + " isn't unlocked, skipping CE userdata backup.");
+                storageFlags = Installer.FLAG_STORAGE_DE;
+            } else {
+                storageFlags = Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE;
+            }
+
+            try {
+                mInstaller.snapshotAppData(packageName, user, storageFlags);
+            } catch (InstallerException ie) {
+                Log.e(TAG, "Unable to create app data snapshot for: " + packageName, ie);
+            }
+        }
+
+        PackageRollbackInfo info = new PackageRollbackInfo(newVersion, installedVersion);
+
+        RollbackData data;
+        try {
+            synchronized (mLock) {
+                mChildSessions.put(childSessionId, parentSessionId);
+                data = mPendingRollbacks.get(parentSessionId);
+                if (data == null) {
+                    int rollbackId = allocateRollbackIdLocked();
+                    data = mRollbackStore.createAvailableRollback(rollbackId);
+                    mPendingRollbacks.put(parentSessionId, data);
+                }
+                data.packages.add(info);
+            }
+        } catch (IOException e) {
+            Log.e(TAG, "Unable to create rollback for " + packageName, e);
+            return false;
+        }
+
+        File packageDir = mRollbackStore.packageCodePathForAvailableRollback(data, packageName);
+        packageDir.mkdirs();
+
+        // TODO: Copy by hard link instead to save on cpu and storage space?
+        int status = PackageManagerServiceUtils.copyPackage(installedPackage.codePath, packageDir);
+        if (status != PackageManager.INSTALL_SUCCEEDED) {
+            Log.e(TAG, "Unable to copy package for rollback for " + packageName);
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public void restoreUserData(String packageName, int userId, int appId, long ceDataInode,
+            String seInfo, int token) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("restoureUserData may only be called by the system.");
+        }
+
+        getHandler().post(() -> {
+            PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+            // TODO(narayan): Should we make sure we're in the middle of a session commit for a
+            // a package with this package name ? Otherwise it's possible we may roll back data
+            // for some other downgrade.
+            if (getRollbackForPackage(packageName) == null) {
+                pmi.finishPackageInstall(token, false);
+                return;
+            }
+
+            final int storageFlags;
+            if (StorageManager.isFileEncryptedNativeOrEmulated()
+                    && !StorageManager.isUserKeyUnlocked(userId)) {
+                // We've encountered a user that hasn't unlocked on a FBE device, so we can't copy
+                // across app user data until the user unlocks their device.
+                Log.e(TAG, "User: " + userId + " isn't unlocked, skipping CE userdata restore.");
+
+                storageFlags = Installer.FLAG_STORAGE_DE;
+            } else {
+                storageFlags = Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE;
+            }
+
+            try {
+                mInstaller.restoreAppDataSnapshot(packageName, appId, ceDataInode,
+                        seInfo, userId, storageFlags);
+            } catch (InstallerException ie) {
+                Log.e(TAG, "Unable to restore app data snapshot: " + packageName, ie);
+            }
+
+            pmi.finishPackageInstall(token, false);
+        });
+    }
+
+    private class LocalIntentReceiver {
+        final Consumer<Intent> mConsumer;
+
+        LocalIntentReceiver(Consumer<Intent> consumer) {
+            mConsumer = consumer;
+        }
+
+        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+            @Override
+            public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+                    IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
+                getHandler().post(() -> mConsumer.accept(intent));
+            }
+        };
+
+        public IntentSender getIntentSender() {
+            return new IntentSender((IIntentSender) mLocalSender);
+        }
+    }
+
+    /**
+     * Gets the version of the package currently installed.
+     * Returns null if the package is not currently installed.
+     */
+    private VersionedPackage getInstalledPackageVersion(String packageName) {
+        PackageManager pm = mContext.getPackageManager();
+        PackageInfo pkgInfo = null;
+        try {
+            pkgInfo = pm.getPackageInfo(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            return null;
+        }
+
+        return new VersionedPackage(packageName, pkgInfo.getLongVersionCode());
+    }
+
+    private boolean packageVersionsEqual(VersionedPackage a, VersionedPackage b) {
+        return a.getPackageName().equals(b.getPackageName())
+            && a.getLongVersionCode() == b.getLongVersionCode();
+    }
+
+    private class SessionCallback extends PackageInstaller.SessionCallback {
+
+        @Override
+        public void onCreated(int sessionId) { }
+
+        @Override
+        public void onBadgingChanged(int sessionId) { }
+
+        @Override
+        public void onActiveChanged(int sessionId, boolean active) { }
+
+        @Override
+        public void onProgressChanged(int sessionId, float progress) { }
+
+        @Override
+        public void onFinished(int sessionId, boolean success) {
+            RollbackData data = null;
+            synchronized (mLock) {
+                Integer parentSessionId = mChildSessions.remove(sessionId);
+                if (parentSessionId != null) {
+                    sessionId = parentSessionId;
+                }
+                data = mPendingRollbacks.remove(sessionId);
+            }
+
+            if (data != null) {
+                if (success) {
+                    try {
+                        data.timestamp = Instant.now();
+
+                        mRollbackStore.saveAvailableRollback(data);
+                        synchronized (mLock) {
+                            // Note: There is a small window of time between when
+                            // the session has been committed by the package
+                            // manager and when we make the rollback available
+                            // here. Presumably the window is small enough that
+                            // nobody will want to roll back the newly installed
+                            // package before we make the rollback available.
+                            // TODO: We'll lose the rollback data if the
+                            // device reboots between when the session is
+                            // committed and this point. Revisit this after
+                            // adding support for rollback of staged installs.
+                            ensureRollbackDataLoadedLocked();
+                            mAvailableRollbacks.add(data);
+                        }
+
+                        scheduleExpiration(ROLLBACK_LIFETIME_DURATION_MILLIS);
+                    } catch (IOException e) {
+                        Log.e(TAG, "Unable to enable rollback", e);
+                        mRollbackStore.deleteAvailableRollback(data);
+                    }
+                } else {
+                    // The install session was aborted, clean up the pending
+                    // install.
+                    mRollbackStore.deleteAvailableRollback(data);
+                }
+            }
+        }
+    }
+
+    /*
+     * Returns the RollbackData, if any, for an available rollback that would
+     * roll back the given package. Note: This assumes we have at most one
+     * available rollback for a given package at any one time.
+     */
+    private RollbackData getRollbackForPackage(String packageName) {
+        synchronized (mLock) {
+            // TODO: Have ensureRollbackDataLoadedLocked return the list of
+            // available rollbacks, to hopefully avoid forgetting to call it?
+            ensureRollbackDataLoadedLocked();
+            for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
+                RollbackData data = mAvailableRollbacks.get(i);
+                for (PackageRollbackInfo info : data.packages) {
+                    if (info.getPackageName().equals(packageName)) {
+                        return data;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    @GuardedBy("mLock")
+    private int allocateRollbackIdLocked() throws IOException {
+        int n = 0;
+        int rollbackId;
+        do {
+            rollbackId = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
+            if (!mAllocatedRollbackIds.get(rollbackId, false)) {
+                mAllocatedRollbackIds.put(rollbackId, true);
+                return rollbackId;
+            }
+        } while (n++ < 32);
+
+        throw new IOException("Failed to allocate rollback ID");
+    }
+}
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
new file mode 100644
index 0000000..7738be9
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -0,0 +1,266 @@
+/*
+ * 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.rollback;
+
+import android.content.pm.VersionedPackage;
+import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.RollbackInfo;
+import android.util.Log;
+
+import libcore.io.IoUtils;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.time.Instant;
+import java.time.format.DateTimeParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class for loading and saving rollback data to persistent storage.
+ */
+class RollbackStore {
+    private static final String TAG = "RollbackManager";
+
+    // Assuming the rollback data directory is /data/rollback, we use the
+    // following directory structure to store persisted data for available and
+    // recently executed rollbacks:
+    //   /data/rollback/
+    //      available/
+    //          XXX/
+    //              rollback.json
+    //              com.package.A/
+    //                  base.apk
+    //              com.package.B/
+    //                  base.apk
+    //          YYY/
+    //              rollback.json
+    //              com.package.C/
+    //                  base.apk
+    //      recently_executed.json
+    //
+    // * XXX, YYY are the rollbackIds for the corresponding rollbacks.
+    // * rollback.json contains all relevant metadata for the rollback. This
+    //   file is not written until the rollback is made available.
+    //
+    // TODO: Use AtomicFile for all the .json files?
+    private final File mRollbackDataDir;
+    private final File mAvailableRollbacksDir;
+    private final File mRecentlyExecutedRollbacksFile;
+
+    RollbackStore(File rollbackDataDir) {
+        mRollbackDataDir = rollbackDataDir;
+        mAvailableRollbacksDir = new File(mRollbackDataDir, "available");
+        mRecentlyExecutedRollbacksFile = new File(mRollbackDataDir, "recently_executed.json");
+    }
+
+    /**
+     * Reads the list of available rollbacks from persistent storage.
+     */
+    List<RollbackData> loadAvailableRollbacks() {
+        List<RollbackData> availableRollbacks = new ArrayList<>();
+        mAvailableRollbacksDir.mkdirs();
+        for (File rollbackDir : mAvailableRollbacksDir.listFiles()) {
+            if (rollbackDir.isDirectory()) {
+                try {
+                    RollbackData data = loadRollbackData(rollbackDir);
+                    availableRollbacks.add(data);
+                } catch (IOException e) {
+                    // Note: Deleting the rollbackDir here will cause pending
+                    // rollbacks to be deleted. This should only ever happen
+                    // if reloadPersistedData is called while there are
+                    // pending rollbacks. The reloadPersistedData method is
+                    // currently only for testing, so that should be okay.
+                    Log.e(TAG, "Unable to read rollback data at " + rollbackDir, e);
+                    removeFile(rollbackDir);
+                }
+            }
+        }
+        return availableRollbacks;
+    }
+
+    /**
+     * Reads the list of recently executed rollbacks from persistent storage.
+     */
+    List<RollbackInfo> loadRecentlyExecutedRollbacks() {
+        List<RollbackInfo> recentlyExecutedRollbacks = new ArrayList<>();
+        if (mRecentlyExecutedRollbacksFile.exists()) {
+            try {
+                // TODO: How to cope with changes to the format of this file from
+                // when RollbackStore is updated in the future?
+                String jsonString = IoUtils.readFileAsString(
+                        mRecentlyExecutedRollbacksFile.getAbsolutePath());
+                JSONObject object = new JSONObject(jsonString);
+                JSONArray array = object.getJSONArray("recentlyExecuted");
+                for (int i = 0; i < array.length(); ++i) {
+                    JSONObject element = array.getJSONObject(i);
+                    int rollbackId = element.getInt("rollbackId");
+                    String packageName = element.getString("packageName");
+                    long higherVersionCode = element.getLong("higherVersionCode");
+                    long lowerVersionCode = element.getLong("lowerVersionCode");
+                    PackageRollbackInfo target = new PackageRollbackInfo(
+                            new VersionedPackage(packageName, higherVersionCode),
+                            new VersionedPackage(packageName, lowerVersionCode));
+                    RollbackInfo rollback = new RollbackInfo(rollbackId, target);
+                    recentlyExecutedRollbacks.add(rollback);
+                }
+            } catch (IOException | JSONException e) {
+                // TODO: What to do here? Surely we shouldn't just forget about
+                // everything after the point of exception?
+                Log.e(TAG, "Failed to read recently executed rollbacks", e);
+            }
+        }
+
+        return recentlyExecutedRollbacks;
+    }
+
+    /**
+     * Creates a new RollbackData instance with backupDir assigned.
+     */
+    RollbackData createAvailableRollback(int rollbackId) throws IOException {
+        File backupDir = new File(mAvailableRollbacksDir, Integer.toString(rollbackId));
+        return new RollbackData(rollbackId, backupDir);
+    }
+
+    /**
+     * Returns the directory where the code for a package should be stored for
+     * given rollback <code>data</code> and <code>packageName</code>.
+     */
+    File packageCodePathForAvailableRollback(RollbackData data, String packageName) {
+        return new File(data.backupDir, packageName);
+    }
+
+    /**
+     * Writes the metadata for an available rollback to persistent storage.
+     */
+    void saveAvailableRollback(RollbackData data) throws IOException {
+        try {
+            JSONObject dataJson = new JSONObject();
+            JSONArray packagesJson = new JSONArray();
+            for (PackageRollbackInfo info : data.packages) {
+                JSONObject infoJson = new JSONObject();
+                infoJson.put("packageName", info.getPackageName());
+                infoJson.put("higherVersionCode",
+                        info.getVersionRolledBackFrom().getLongVersionCode());
+                infoJson.put("lowerVersionCode",
+                        info.getVersionRolledBackTo().getVersionCode());
+                packagesJson.put(infoJson);
+            }
+            dataJson.put("rollbackId", data.rollbackId);
+            dataJson.put("packages", packagesJson);
+            dataJson.put("timestamp", data.timestamp.toString());
+
+            PrintWriter pw = new PrintWriter(new File(data.backupDir, "rollback.json"));
+            pw.println(dataJson.toString());
+            pw.close();
+        } catch (JSONException e) {
+            throw new IOException(e);
+        }
+    }
+
+    /**
+     * Removes all persistant storage associated with the given available
+     * rollback.
+     */
+    void deleteAvailableRollback(RollbackData data) {
+        // TODO(narayan): Make sure we delete the userdata snapshot along with the backup of the
+        // actual app.
+        removeFile(data.backupDir);
+    }
+
+    /**
+     * Writes the list of recently executed rollbacks to storage.
+     */
+    void saveRecentlyExecutedRollbacks(List<RollbackInfo> recentlyExecutedRollbacks) {
+        try {
+            JSONObject json = new JSONObject();
+            JSONArray array = new JSONArray();
+            json.put("recentlyExecuted", array);
+
+            for (int i = 0; i < recentlyExecutedRollbacks.size(); ++i) {
+                RollbackInfo rollback = recentlyExecutedRollbacks.get(i);
+                JSONObject element = new JSONObject();
+                element.put("rollbackId", rollback.getRollbackId());
+                element.put("packageName", rollback.targetPackage.getPackageName());
+                element.put("higherVersionCode",
+                        rollback.targetPackage.getVersionRolledBackFrom().getLongVersionCode());
+                element.put("lowerVersionCode",
+                        rollback.targetPackage.getVersionRolledBackTo().getLongVersionCode());
+                array.put(element);
+            }
+
+            PrintWriter pw = new PrintWriter(mRecentlyExecutedRollbacksFile);
+            pw.println(json.toString());
+            pw.close();
+        } catch (IOException | JSONException e) {
+            // TODO: What to do here?
+            Log.e(TAG, "Failed to save recently executed rollbacks", e);
+        }
+    }
+
+    /**
+     * Reads the metadata for a rollback from the given directory.
+     * @throws IOException in case of error reading the data.
+     */
+    private RollbackData loadRollbackData(File backupDir) throws IOException {
+        try {
+            File rollbackJsonFile = new File(backupDir, "rollback.json");
+            JSONObject dataJson = new JSONObject(
+                    IoUtils.readFileAsString(rollbackJsonFile.getAbsolutePath()));
+
+            int rollbackId = dataJson.getInt("rollbackId");
+            RollbackData data = new RollbackData(rollbackId, backupDir);
+
+            JSONArray packagesJson = dataJson.getJSONArray("packages");
+            for (int i = 0; i < packagesJson.length(); ++i) {
+                JSONObject infoJson = packagesJson.getJSONObject(i);
+                String packageName = infoJson.getString("packageName");
+                long higherVersionCode = infoJson.getLong("higherVersionCode");
+                long lowerVersionCode = infoJson.getLong("lowerVersionCode");
+                data.packages.add(new PackageRollbackInfo(
+                        new VersionedPackage(packageName, higherVersionCode),
+                        new VersionedPackage(packageName, lowerVersionCode)));
+            }
+
+            data.timestamp = Instant.parse(dataJson.getString("timestamp"));
+            return data;
+        } catch (JSONException | DateTimeParseException e) {
+            throw new IOException(e);
+        }
+    }
+
+    /**
+     * Deletes a file completely.
+     * If the file is a directory, its contents are deleted as well.
+     * Has no effect if the directory does not exist.
+     */
+    private void removeFile(File file) {
+        if (file.isDirectory()) {
+            for (File child : file.listFiles()) {
+                removeFile(child);
+            }
+        }
+        if (file.exists()) {
+            file.delete();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/rollback/TEST_MAPPING b/services/core/java/com/android/server/rollback/TEST_MAPPING
new file mode 100644
index 0000000..c1d95ac
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "RollbackTest"
+    }
+  ]
+}
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 667d21d..b1db46f 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -30,11 +30,13 @@
 
 import libcore.util.HexEncoding;
 
+import java.io.File;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -49,11 +51,71 @@
 abstract public class VerityUtils {
     private static final String TAG = "VerityUtils";
 
+    /**
+     * File extension of the signature file. For example, foo.apk.fsv_sig is the signature file of
+     * foo.apk.
+     */
+    public static final String FSVERITY_SIGNATURE_FILE_EXTENSION = ".fsv_sig";
+
     /** The maximum size of signature file.  This is just to avoid potential abuse. */
     private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192;
 
+    private static final int COMMON_LINUX_PAGE_SIZE_IN_BYTES = 4096;
+
     private static final boolean DEBUG = false;
 
+    /** Returns true if the given file looks like containing an fs-verity signature. */
+    public static boolean isFsveritySignatureFile(File file) {
+        return file.getName().endsWith(FSVERITY_SIGNATURE_FILE_EXTENSION);
+    }
+
+    /** Returns the fs-verity signature file path of the given file. */
+    public static String getFsveritySignatureFilePath(String filePath) {
+        return filePath + FSVERITY_SIGNATURE_FILE_EXTENSION;
+    }
+
+    /** Generates Merkle tree and fs-verity metadata then enables fs-verity. */
+    public static void setUpFsverity(@NonNull String filePath, String signaturePath)
+            throws IOException, DigestException, NoSuchAlgorithmException {
+        final PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(Paths.get(signaturePath)));
+        final byte[] expectedMeasurement = pkcs7.getContentInfo().getContentBytes();
+        if (DEBUG) {
+            Slog.d(TAG, "Enabling fs-verity with signed fs-verity measurement "
+                    + bytesToString(expectedMeasurement));
+            Slog.d(TAG, "PKCS#7 info: " + pkcs7);
+        }
+
+        final TrackedBufferFactory bufferFactory = new TrackedBufferFactory();
+        final byte[] actualMeasurement = generateFsverityMetadata(filePath, signaturePath,
+                bufferFactory);
+        try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) {
+            FileChannel ch = raf.getChannel();
+            ch.position(roundUpToNextMultiple(ch.size(), COMMON_LINUX_PAGE_SIZE_IN_BYTES));
+            ByteBuffer buffer = bufferFactory.getBuffer();
+
+            long offset = buffer.position();
+            long size = buffer.limit();
+            while (offset < size) {
+                long s = ch.write(buffer);
+                offset += s;
+                size -= s;
+            }
+        }
+
+        if (!Arrays.equals(expectedMeasurement, actualMeasurement)) {
+            throw new SecurityException("fs-verity measurement mismatch: "
+                    + bytesToString(actualMeasurement) + " != "
+                    + bytesToString(expectedMeasurement));
+        }
+
+        // This can fail if the public key is not already in .fs-verity kernel keyring.
+        int errno = enableFsverityNative(filePath);
+        if (errno != 0) {
+            throw new IOException("Failed to enable fs-verity on " + filePath + ": "
+                    + Os.strerror(errno));
+        }
+    }
+
     /** Returns whether the file has fs-verity enabled. */
     public static boolean hasFsverity(@NonNull String filePath) {
         // NB: only measure but not check the actual measurement here. As long as this succeeds,
@@ -70,36 +132,18 @@
     }
 
     /**
-     * Generates Merkle tree and fs-verity metadata.
+     * Generates legacy Merkle tree and fs-verity metadata with Signing Block skipped.
      *
      * @return {@code SetupResult} that contains the result code, and when success, the
      *         {@code FileDescriptor} to read all the data from.
      */
-    public static SetupResult generateApkVeritySetupData(@NonNull String apkPath,
-            String signaturePath, boolean skipSigningBlock) {
+    public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) {
         if (DEBUG) {
-            Slog.d(TAG, "Trying to install apk verity to " + apkPath + " with signature file "
-                    + signaturePath);
+            Slog.d(TAG, "Trying to install legacy apk verity to " + apkPath);
         }
         SharedMemory shm = null;
         try {
-            byte[] signedVerityHash;
-            if (skipSigningBlock) {
-                signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath);
-            } else {
-                Path path = Paths.get(signaturePath);
-                if (Files.exists(path)) {
-                    // TODO(112037636): fail early if the signing key is not in .fs-verity keyring.
-                    PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(path));
-                    signedVerityHash = pkcs7.getContentInfo().getContentBytes();
-                    if (DEBUG) {
-                        Slog.d(TAG, "fs-verity measurement = " + bytesToString(signedVerityHash));
-                    }
-                } else {
-                    signedVerityHash = null;
-                }
-            }
-
+            final byte[] signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath);
             if (signedVerityHash == null) {
                 if (DEBUG) {
                     Slog.d(TAG, "Skip verity tree generation since there is no signed root hash");
@@ -107,8 +151,8 @@
                 return SetupResult.skipped();
             }
 
-            Pair<SharedMemory, Integer> result = generateFsVerityIntoSharedMemory(apkPath,
-                    signaturePath, signedVerityHash, skipSigningBlock);
+            Pair<SharedMemory, Integer> result =
+                    generateFsVerityIntoSharedMemory(apkPath, signedVerityHash);
             shm = result.first;
             int contentSize = result.second;
             FileDescriptor rfd = shm.getFileDescriptor();
@@ -139,7 +183,7 @@
      * {@see ApkSignatureVerifier#getVerityRootHash(String)}.
      */
     public static byte[] getVerityRootHash(@NonNull String apkPath)
-            throws IOException, SignatureNotFoundException, SecurityException {
+            throws IOException, SignatureNotFoundException {
         return ApkSignatureVerifier.getVerityRootHash(apkPath);
     }
 
@@ -155,9 +199,8 @@
      *         includes SHA-256 of fs-verity descriptor and authenticated extensions.
      */
     private static byte[] generateFsverityMetadata(String filePath, String signaturePath,
-            @NonNull TrackedShmBufferFactory trackedBufferFactory)
-            throws IOException, SignatureNotFoundException, SecurityException, DigestException,
-                   NoSuchAlgorithmException {
+            @NonNull ByteBufferFactory trackedBufferFactory)
+            throws IOException, DigestException, NoSuchAlgorithmException {
         try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) {
             VerityBuilder.VerityResult result = VerityBuilder.generateFsVerityTree(
                     file, trackedBufferFactory);
@@ -167,6 +210,7 @@
 
             final byte[] measurement = generateFsverityDescriptorAndMeasurement(file,
                     result.rootHash, signaturePath, buffer);
+            buffer.flip();
             return constructFsveritySignedDataNative(measurement);
         }
     }
@@ -226,6 +270,7 @@
         return md.digest();
     }
 
+    private static native int enableFsverityNative(@NonNull String filePath);
     private static native int measureFsverityNative(@NonNull String filePath);
     private static native byte[] constructFsveritySignedDataNative(@NonNull byte[] measurement);
     private static native byte[] constructFsverityDescriptorNative(long fileSize);
@@ -239,18 +284,13 @@
      * for fsverity setup. The data is aligned to the beginning of {@code SharedMemory}, and has
      * length equals to the returned {@code Integer}.
      */
-    private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory(
-            String apkPath, String signaturePath, @NonNull byte[] expectedRootHash,
-            boolean skipSigningBlock)
-            throws IOException, SecurityException, DigestException, NoSuchAlgorithmException,
+    private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory(String apkPath,
+            @NonNull byte[] expectedRootHash)
+            throws IOException, DigestException, NoSuchAlgorithmException,
                    SignatureNotFoundException {
         TrackedShmBufferFactory shmBufferFactory = new TrackedShmBufferFactory();
-        byte[] generatedRootHash;
-        if (skipSigningBlock) {
-            generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory);
-        } else {
-            generatedRootHash = generateFsverityMetadata(apkPath, signaturePath, shmBufferFactory);
-        }
+        byte[] generatedRootHash =
+                ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory);
         // We only generate Merkle tree once here, so it's important to make sure the root hash
         // matches the signed one in the apk.
         if (!Arrays.equals(expectedRootHash, generatedRootHash)) {
@@ -328,7 +368,7 @@
         private ByteBuffer mBuffer;
 
         @Override
-        public ByteBuffer create(int capacity) throws SecurityException {
+        public ByteBuffer create(int capacity) {
             try {
                 if (DEBUG) Slog.d(TAG, "Creating shared memory for apk verity");
                 // NB: This method is supposed to be called once according to the contract with
@@ -361,4 +401,30 @@
             return mBuffer == null ? -1 : mBuffer.limit();
         }
     }
+
+    /** A {@code ByteBufferFactory} that tracks the {@code ByteBuffer} it creates. */
+    private static class TrackedBufferFactory implements ByteBufferFactory {
+        private ByteBuffer mBuffer;
+
+        @Override
+        public ByteBuffer create(int capacity) {
+            if (mBuffer != null) {
+                throw new IllegalStateException("Multiple instantiation from this factory");
+            }
+            mBuffer = ByteBuffer.allocate(capacity);
+            return mBuffer;
+        }
+
+        public ByteBuffer getBuffer() {
+            return mBuffer;
+        }
+    }
+
+    /** Round up the number to the next multiple of the divisor. */
+    private static long roundUpToNextMultiple(long number, long divisor) {
+        if (number > (Long.MAX_VALUE - divisor)) {
+            throw new IllegalArgumentException("arithmetic overflow");
+        }
+        return ((number + (divisor - 1)) / divisor) * divisor;
+    }
 }
diff --git a/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java b/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java
new file mode 100644
index 0000000..d77cf90
--- /dev/null
+++ b/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java
@@ -0,0 +1,144 @@
+/*
+ * 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.signedconfig;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.provider.Settings;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.StatsLog;
+
+import java.security.GeneralSecurityException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+class GlobalSettingsConfigApplicator {
+
+    private static final String TAG = "SignedConfig";
+
+    private static final Set<String> ALLOWED_KEYS = Collections.unmodifiableSet(new ArraySet<>(
+            Arrays.asList(
+                    Settings.Global.HIDDEN_API_POLICY,
+                    Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS
+            )));
+
+    private static final Map<String, String> HIDDEN_API_POLICY_KEY_MAP = makeMap(
+            "DEFAULT", String.valueOf(ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT),
+            "DISABLED", String.valueOf(ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED),
+            "JUST_WARN", String.valueOf(ApplicationInfo.HIDDEN_API_ENFORCEMENT_JUST_WARN),
+            "ENABLED", String.valueOf(ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED)
+    );
+
+    private static final Map<String, Map<String, String>> KEY_VALUE_MAPPERS = makeMap(
+            Settings.Global.HIDDEN_API_POLICY, HIDDEN_API_POLICY_KEY_MAP
+    );
+
+    private static <K, V> Map<K, V> makeMap(Object... keyValuePairs) {
+        if (keyValuePairs.length % 2 != 0) {
+            throw new IllegalArgumentException();
+        }
+        final int len = keyValuePairs.length / 2;
+        ArrayMap<K, V> m = new ArrayMap<>(len);
+        for (int i = 0; i < len;  ++i) {
+            m.put((K) keyValuePairs[i * 2], (V) keyValuePairs[(i * 2) + 1]);
+        }
+        return Collections.unmodifiableMap(m);
+
+    }
+
+    private final Context mContext;
+    private final String mSourcePackage;
+    private final SignedConfigEvent mEvent;
+    private final SignatureVerifier mVerifier;
+
+    GlobalSettingsConfigApplicator(Context context, String sourcePackage, SignedConfigEvent event) {
+        mContext = context;
+        mSourcePackage = sourcePackage;
+        mEvent = event;
+        mVerifier = new SignatureVerifier(mEvent);
+    }
+
+    private boolean checkSignature(String data, String signature) {
+        try {
+            return mVerifier.verifySignature(data, signature);
+        } catch (GeneralSecurityException e) {
+            Slog.e(TAG, "Failed to verify signature", e);
+            mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__SECURITY_EXCEPTION;
+            return false;
+        }
+    }
+
+    private int getCurrentConfigVersion() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.SIGNED_CONFIG_VERSION, 0);
+    }
+
+    private void updateCurrentConfig(int version, Map<String, String> values) {
+        for (Map.Entry<String, String> e: values.entrySet()) {
+            Settings.Global.putString(
+                    mContext.getContentResolver(),
+                    e.getKey(),
+                    e.getValue());
+        }
+        Settings.Global.putInt(
+                mContext.getContentResolver(), Settings.Global.SIGNED_CONFIG_VERSION, version);
+    }
+
+
+    void applyConfig(String configStr, String signature) {
+        if (!checkSignature(configStr, signature)) {
+            Slog.e(TAG, "Signature check on global settings in package " + mSourcePackage
+                    + " failed; ignoring");
+            return;
+        }
+        SignedConfig config;
+        try {
+            config = SignedConfig.parse(configStr, ALLOWED_KEYS, KEY_VALUE_MAPPERS);
+            mEvent.version = config.version;
+        } catch (InvalidConfigException e) {
+            Slog.e(TAG, "Failed to parse global settings from package " + mSourcePackage, e);
+            mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__INVALID_CONFIG;
+            return;
+        }
+        int currentVersion = getCurrentConfigVersion();
+        if (currentVersion >= config.version) {
+            Slog.i(TAG, "Global settings from package " + mSourcePackage
+                    + " is older than existing: " + config.version + "<=" + currentVersion);
+            mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__OLD_CONFIG;
+            return;
+        }
+        // We have new config!
+        Slog.i(TAG, "Got new global settings from package " + mSourcePackage + ": version "
+                + config.version + " replacing existing version " + currentVersion);
+        SignedConfig.PerSdkConfig matchedConfig =
+                config.getMatchingConfig(Build.VERSION.SDK_INT);
+        if (matchedConfig == null) {
+            Slog.i(TAG, "Settings is not applicable to current SDK version; ignoring");
+            mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__NOT_APPLICABLE;
+            return;
+        }
+
+        Slog.i(TAG, "Updating global settings to version " + config.version);
+        updateCurrentConfig(config.version, matchedConfig.values);
+        mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__APPLIED;
+    }
+}
diff --git a/services/core/java/com/android/server/signedconfig/SignatureVerifier.java b/services/core/java/com/android/server/signedconfig/SignatureVerifier.java
index 944db84..56db32a 100644
--- a/services/core/java/com/android/server/signedconfig/SignatureVerifier.java
+++ b/services/core/java/com/android/server/signedconfig/SignatureVerifier.java
@@ -18,6 +18,7 @@
 
 import android.os.Build;
 import android.util.Slog;
+import android.util.StatsLog;
 
 import java.nio.charset.StandardCharsets;
 import java.security.InvalidKeyException;
@@ -42,11 +43,18 @@
     private static final String DEBUG_KEY =
             "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaAn2XVifsLTHg616nTsOMVmlhBoECGbTEBTKKvdd2hO60"
             + "pj1pnU8SMkhYfaNxZuKgw9LNvOwlFwStboIYeZ3lQ==";
+    private static final String PROD_KEY =
+            "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+lky6wKyGL6lE1VrD0YTMHwb0Xwc+tzC8MvnrzVxodvTp"
+            + "VY/jV7V+Zktcx+pry43XPABFRXtbhTo+qykhyBA1g==";
 
+    private final SignedConfigEvent mEvent;
     private final PublicKey mDebugKey;
+    private final PublicKey mProdKey;
 
-    public SignatureVerifier() {
-        mDebugKey = createKey(DEBUG_KEY);
+    public SignatureVerifier(SignedConfigEvent event) {
+        mEvent = event;
+        mDebugKey = Build.IS_DEBUGGABLE ? createKey(DEBUG_KEY) : null;
+        mProdKey = createKey(PROD_KEY);
     }
 
     private static PublicKey createKey(String base64) {
@@ -67,6 +75,14 @@
         }
     }
 
+    private boolean verifyWithPublicKey(PublicKey key, byte[] data, byte[] signature)
+            throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+        Signature verifier = Signature.getInstance("SHA256withECDSA");
+        verifier.initVerify(key);
+        verifier.update(data);
+        return verifier.verify(signature);
+    }
+
     /**
      * Verify a signature for signed config.
      *
@@ -80,6 +96,7 @@
         try {
             signature = Base64.getDecoder().decode(base64Signature);
         } catch (IllegalArgumentException e) {
+            mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__BASE64_FAILURE_SIGNATURE;
             Slog.e(TAG, "Failed to base64 decode signature");
             return false;
         }
@@ -89,11 +106,9 @@
         if (Build.IS_DEBUGGABLE) {
             if (mDebugKey != null) {
                 if (DBG) Slog.w(TAG, "Trying to verify signature using debug key");
-                Signature verifier = Signature.getInstance("SHA256withECDSA");
-                verifier.initVerify(mDebugKey);
-                verifier.update(data);
-                if (verifier.verify(signature)) {
+                if (verifyWithPublicKey(mDebugKey, data, signature)) {
                     Slog.i(TAG, "Verified config using debug key");
+                    mEvent.verifiedWith = StatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__DEBUG;
                     return true;
                 } else {
                     if (DBG) Slog.i(TAG, "Config verification failed using debug key");
@@ -102,8 +117,20 @@
                 Slog.w(TAG, "Debuggable build, but have no debug key");
             }
         }
-        // TODO verify production key.
-        Slog.w(TAG, "NO PRODUCTION KEY YET, FAILING VERIFICATION");
-        return false;
+        if (mProdKey ==  null) {
+            Slog.e(TAG, "No prod key; construction failed?");
+            mEvent.status =
+                    StatsLog.SIGNED_CONFIG_REPORTED__STATUS__SIGNATURE_CHECK_FAILED_PROD_KEY_ABSENT;
+            return false;
+        }
+        if (verifyWithPublicKey(mProdKey, data, signature)) {
+            Slog.i(TAG, "Verified config using production key");
+            mEvent.verifiedWith = StatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__PRODUCTION;
+            return true;
+        } else {
+            if (DBG) Slog.i(TAG, "Verification failed using production key");
+            mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__SIGNATURE_CHECK_FAILED;
+            return false;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java b/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java
deleted file mode 100644
index 4908964..0000000
--- a/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java
+++ /dev/null
@@ -1,135 +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.signedconfig;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.os.Build;
-import android.provider.Settings;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Slog;
-
-import java.security.GeneralSecurityException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
-class SignedConfigApplicator {
-
-    private static final String TAG = "SignedConfig";
-
-    private static final Set<String> ALLOWED_KEYS = Collections.unmodifiableSet(new ArraySet<>(
-            Arrays.asList(
-                    Settings.Global.HIDDEN_API_POLICY,
-                    Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS
-            )));
-
-    private static final Map<String, String> HIDDEN_API_POLICY_KEY_MAP = makeMap(
-            "DEFAULT", String.valueOf(ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT),
-            "DISABLED", String.valueOf(ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED),
-            "JUST_WARN", String.valueOf(ApplicationInfo.HIDDEN_API_ENFORCEMENT_JUST_WARN),
-            "ENABLED", String.valueOf(ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED)
-    );
-
-    private static final Map<String, Map<String, String>> KEY_VALUE_MAPPERS = makeMap(
-            Settings.Global.HIDDEN_API_POLICY, HIDDEN_API_POLICY_KEY_MAP
-    );
-
-    private static <K, V> Map<K, V> makeMap(Object... keyValuePairs) {
-        if (keyValuePairs.length % 2 != 0) {
-            throw new IllegalArgumentException();
-        }
-        final int len = keyValuePairs.length / 2;
-        ArrayMap<K, V> m = new ArrayMap<>(len);
-        for (int i = 0; i < len;  ++i) {
-            m.put((K) keyValuePairs[i * 2], (V) keyValuePairs[(i * 2) + 1]);
-        }
-        return Collections.unmodifiableMap(m);
-
-    }
-
-    private final Context mContext;
-    private final String mSourcePackage;
-    private final SignatureVerifier mVerifier;
-
-    SignedConfigApplicator(Context context, String sourcePackage) {
-        mContext = context;
-        mSourcePackage = sourcePackage;
-        mVerifier = new SignatureVerifier();
-    }
-
-    private boolean checkSignature(String data, String signature) {
-        try {
-            return mVerifier.verifySignature(data, signature);
-        } catch (GeneralSecurityException e) {
-            Slog.e(TAG, "Failed to verify signature", e);
-            return false;
-        }
-    }
-
-    private int getCurrentConfigVersion() {
-        return Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.SIGNED_CONFIG_VERSION, 0);
-    }
-
-    private void updateCurrentConfig(int version, Map<String, String> values) {
-        for (Map.Entry<String, String> e: values.entrySet()) {
-            Settings.Global.putString(
-                    mContext.getContentResolver(),
-                    e.getKey(),
-                    e.getValue());
-        }
-        Settings.Global.putInt(
-                mContext.getContentResolver(), Settings.Global.SIGNED_CONFIG_VERSION, version);
-    }
-
-
-    void applyConfig(String configStr, String signature) {
-        if (!checkSignature(configStr, signature)) {
-            Slog.e(TAG, "Signature check on signed configuration in package " + mSourcePackage
-                    + " failed; ignoring");
-            return;
-        }
-        SignedConfig config;
-        try {
-            config = SignedConfig.parse(configStr, ALLOWED_KEYS, KEY_VALUE_MAPPERS);
-        } catch (InvalidConfigException e) {
-            Slog.e(TAG, "Failed to parse config from package " + mSourcePackage, e);
-            return;
-        }
-        int currentVersion = getCurrentConfigVersion();
-        if (currentVersion >= config.version) {
-            Slog.i(TAG, "Config from package " + mSourcePackage + " is older than existing: "
-                    + config.version + "<=" + currentVersion);
-            return;
-        }
-        // We have new config!
-        Slog.i(TAG, "Got new signed config from package " + mSourcePackage + ": version "
-                + config.version + " replacing existing version " + currentVersion);
-        SignedConfig.PerSdkConfig matchedConfig =
-                config.getMatchingConfig(Build.VERSION.SDK_INT);
-        if (matchedConfig == null) {
-            Slog.i(TAG, "Config is not applicable to current SDK version; ignoring");
-            return;
-        }
-
-        Slog.i(TAG, "Updating signed config to version " + config.version);
-        updateCurrentConfig(config.version, matchedConfig.values);
-    }
-}
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigEvent.java b/services/core/java/com/android/server/signedconfig/SignedConfigEvent.java
new file mode 100644
index 0000000..2f2062c
--- /dev/null
+++ b/services/core/java/com/android/server/signedconfig/SignedConfigEvent.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.signedconfig;
+
+import android.util.StatsLog;
+
+/**
+ * Helper class to allow a SignedConfigReported event to be built up in stages.
+ */
+public class SignedConfigEvent {
+
+    public int type = StatsLog.SIGNED_CONFIG_REPORTED__TYPE__UNKNOWN_TYPE;
+    public int status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__UNKNOWN_STATUS;
+    public int version = 0;
+    public String fromPackage = null;
+    public int verifiedWith = StatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__NO_KEY;
+
+    /**
+     * Write this event to statslog.
+     */
+    public void send() {
+        StatsLog.write(StatsLog.SIGNED_CONFIG_REPORTED,
+                type, status, version, fromPackage, verifiedWith);
+    }
+
+}
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigService.java b/services/core/java/com/android/server/signedconfig/SignedConfigService.java
index 84ce93f..dc39542 100644
--- a/services/core/java/com/android/server/signedconfig/SignedConfigService.java
+++ b/services/core/java/com/android/server/signedconfig/SignedConfigService.java
@@ -26,6 +26,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.util.Slog;
+import android.util.StatsLog;
 
 import com.android.server.LocalServices;
 
@@ -42,8 +43,8 @@
     private static final String TAG = "SignedConfig";
 
     // TODO should these be elsewhere? In a public API?
-    private static final String KEY_CONFIG = "android.signedconfig";
-    private static final String KEY_CONFIG_SIGNATURE = "android.signedconfig.signature";
+    private static final String KEY_GLOBAL_SETTINGS = "android.settings.global";
+    private static final String KEY_GLOBAL_SETTINGS_SIGNATURE = "android.settings.global.signature";
 
     private static class UpdateReceiver extends BroadcastReceiver {
         @Override
@@ -80,25 +81,34 @@
             if (DBG) Slog.d(TAG, "handlePackageBroadcast: no metadata");
             return;
         }
-        if (metaData.containsKey(KEY_CONFIG)
-                && metaData.containsKey(KEY_CONFIG_SIGNATURE)) {
-            String config = metaData.getString(KEY_CONFIG);
-            String signature = metaData.getString(KEY_CONFIG_SIGNATURE);
+        if (metaData.containsKey(KEY_GLOBAL_SETTINGS)
+                && metaData.containsKey(KEY_GLOBAL_SETTINGS_SIGNATURE)) {
+            SignedConfigEvent event = new SignedConfigEvent();
             try {
-                // Base64 encoding is standard (not URL safe) encoding: RFC4648
-                config = new String(Base64.getDecoder().decode(config), StandardCharsets.UTF_8);
-            } catch (IllegalArgumentException iae) {
-                Slog.e(TAG, "Failed to base64 decode config from " + packageName);
-                return;
+                event.type = StatsLog.SIGNED_CONFIG_REPORTED__TYPE__GLOBAL_SETTINGS;
+                event.fromPackage = packageName;
+                String config = metaData.getString(KEY_GLOBAL_SETTINGS);
+                String signature = metaData.getString(KEY_GLOBAL_SETTINGS_SIGNATURE);
+                try {
+                    // Base64 encoding is standard (not URL safe) encoding: RFC4648
+                    config = new String(Base64.getDecoder().decode(config), StandardCharsets.UTF_8);
+                } catch (IllegalArgumentException iae) {
+                    Slog.e(TAG, "Failed to base64 decode global settings config from "
+                            + packageName);
+                    event.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__BASE64_FAILURE_CONFIG;
+                    return;
+                }
+                if (DBG) {
+                    Slog.d(TAG, "Got global settings config: " + config);
+                    Slog.d(TAG, "Got global settings signature: " + signature);
+                }
+                new GlobalSettingsConfigApplicator(mContext, packageName, event).applyConfig(
+                        config, signature);
+            } finally {
+                event.send();
             }
-            if (DBG) {
-                Slog.d(TAG, "Got signed config: " + config);
-                Slog.d(TAG, "Got config signature: " + signature);
-            }
-            new SignedConfigApplicator(mContext, packageName).applyConfig(
-                    config, signature);
         } else {
-            if (DBG) Slog.d(TAG, "Package has no config/signature.");
+            if (DBG) Slog.d(TAG, "Package has no global settings config/signature.");
         }
     }
 
diff --git a/services/core/java/com/android/server/slice/SlicePermissionManager.java b/services/core/java/com/android/server/slice/SlicePermissionManager.java
index 315d5e3..1d1c28f 100644
--- a/services/core/java/com/android/server/slice/SlicePermissionManager.java
+++ b/services/core/java/com/android/server/slice/SlicePermissionManager.java
@@ -175,18 +175,24 @@
                 handlePersist();
             }
             for (String file : new File(mSliceDir.getAbsolutePath()).list()) {
-                if (file.isEmpty()) continue;
                 try (ParserHolder parser = getParser(file)) {
-                    Persistable p;
-                    while (parser.parser.getEventType() != XmlPullParser.START_TAG) {
+                    Persistable p = null;
+                    while (parser.parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+                        if (parser.parser.getEventType() == XmlPullParser.START_TAG) {
+                            if (SliceClientPermissions.TAG_CLIENT.equals(parser.parser.getName())) {
+                                p = SliceClientPermissions.createFrom(parser.parser, tracker);
+                            } else {
+                                p = SliceProviderPermissions.createFrom(parser.parser, tracker);
+                            }
+                            break;
+                        }
                         parser.parser.next();
                     }
-                    if (SliceClientPermissions.TAG_CLIENT.equals(parser.parser.getName())) {
-                        p = SliceClientPermissions.createFrom(parser.parser, tracker);
+                    if (p != null) {
+                        p.writeTo(out);
                     } else {
-                        p = SliceProviderPermissions.createFrom(parser.parser, tracker);
+                        Slog.w(TAG, "Invalid or empty slice permissions file: " + file);
                     }
-                    p.writeTo(out);
                 }
             }
 
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 30aa528..acede7d 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -43,6 +43,7 @@
 import android.content.pm.UserInfo;
 import android.hardware.fingerprint.FingerprintManager;
 import android.net.ConnectivityManager;
+import android.net.INetworkStatsService;
 import android.net.Network;
 import android.net.NetworkRequest;
 import android.net.NetworkStats;
@@ -90,16 +91,15 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.procstats.IProcessStats;
 import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.net.NetworkStatsFactory;
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.os.BinderCallsStats.ExportedCallStat;
 import com.android.internal.os.KernelCpuSpeedReader;
 import com.android.internal.os.KernelCpuThreadReader;
-import com.android.internal.os.KernelUidCpuActiveTimeReader;
-import com.android.internal.os.KernelUidCpuClusterTimeReader;
-import com.android.internal.os.KernelUidCpuFreqTimeReader;
-import com.android.internal.os.KernelUidCpuTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
+import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;
 import com.android.internal.os.KernelWakelockReader;
 import com.android.internal.os.KernelWakelockStats;
 import com.android.internal.os.LooperStats;
@@ -210,6 +210,7 @@
 
     private final Context mContext;
     private final AlarmManager mAlarmManager;
+    private final INetworkStatsService mNetworkStatsService;
     @GuardedBy("sStatsdLock")
     private static IStatsManager sStatsd;
     private static final Object sStatsdLock = new Object();
@@ -230,14 +231,16 @@
     private final HashMap<Long, String> mDeletedFiles = new HashMap<>();
     private final CompanionHandler mHandler;
 
-    private KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader();
+    // Disables throttler on CPU time readers.
+    private KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader =
+            new KernelCpuUidUserSysTimeReader(false);
     private KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
-    private KernelUidCpuFreqTimeReader mKernelUidCpuFreqTimeReader =
-            new KernelUidCpuFreqTimeReader();
-    private KernelUidCpuActiveTimeReader mKernelUidCpuActiveTimeReader =
-            new KernelUidCpuActiveTimeReader();
-    private KernelUidCpuClusterTimeReader mKernelUidCpuClusterTimeReader =
-            new KernelUidCpuClusterTimeReader();
+    private KernelCpuUidFreqTimeReader mCpuUidFreqTimeReader =
+            new KernelCpuUidFreqTimeReader(false);
+    private KernelCpuUidActiveTimeReader mCpuUidActiveTimeReader =
+            new KernelCpuUidActiveTimeReader(false);
+    private KernelCpuUidClusterTimeReader mCpuUidClusterTimeReader =
+            new KernelCpuUidClusterTimeReader(false);
     private StoragedUidIoStatsReader mStoragedUidIoStatsReader =
             new StoragedUidIoStatsReader();
     @Nullable
@@ -257,6 +260,8 @@
         super();
         mContext = context;
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+        mNetworkStatsService = INetworkStatsService.Stub.asInterface(
+              ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
         mBaseDir.mkdirs();
         mAppUpdateReceiver = new AppUpdateReceiver();
         mUserUpdateReceiver = new BroadcastReceiver() {
@@ -291,12 +296,6 @@
                     numSpeedSteps);
             firstCpuOfCluster += powerProfile.getNumCoresInCpuCluster(i);
         }
-        // use default throttling in
-        // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
-        mKernelUidCpuFreqTimeReader.setThrottleInterval(0);
-        long[] freqs = mKernelUidCpuFreqTimeReader.readFreqs(powerProfile);
-        mKernelUidCpuClusterTimeReader.setThrottleInterval(0);
-        mKernelUidCpuActiveTimeReader.setThrottleInterval(0);
 
         // Enable push notifications of throttling from vendor thermal
         // management subsystem via thermalservice.
@@ -788,14 +787,14 @@
             if (ifaces.length == 0) {
                 return;
             }
-            NetworkStatsFactory nsf = new NetworkStatsFactory();
+            if (mNetworkStatsService == null) {
+                Slog.e(TAG, "NetworkStats Service is not available!");
+                return;
+            }
             // Combine all the metrics per Uid into one record.
-            NetworkStats stats =
-                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
-                            null)
-                            .groupedByUid();
+            NetworkStats stats = mNetworkStatsService.getDetailedUidStats(ifaces).groupedByUid();
             addNetworkStats(tagId, pulledData, stats, false);
-        } catch (java.io.IOException e) {
+        } catch (RemoteException e) {
             Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -812,12 +811,14 @@
             if (ifaces.length == 0) {
                 return;
             }
-            NetworkStatsFactory nsf = new NetworkStatsFactory();
+            if (mNetworkStatsService == null) {
+                Slog.e(TAG, "NetworkStats Service is not available!");
+                return;
+            }
             NetworkStats stats = rollupNetworkStatsByFGBG(
-                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
-                            null));
+                    mNetworkStatsService.getDetailedUidStats(ifaces));
             addNetworkStats(tagId, pulledData, stats, true);
-        } catch (java.io.IOException e) {
+        } catch (RemoteException e) {
             Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -834,14 +835,14 @@
             if (ifaces.length == 0) {
                 return;
             }
-            NetworkStatsFactory nsf = new NetworkStatsFactory();
+            if (mNetworkStatsService == null) {
+                Slog.e(TAG, "NetworkStats Service is not available!");
+                return;
+            }
             // Combine all the metrics per Uid into one record.
-            NetworkStats stats =
-                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
-                            null)
-                            .groupedByUid();
+            NetworkStats stats = mNetworkStatsService.getDetailedUidStats(ifaces).groupedByUid();
             addNetworkStats(tagId, pulledData, stats, false);
-        } catch (java.io.IOException e) {
+        } catch (RemoteException e) {
             Slog.e(TAG, "Pulling netstats for mobile bytes has error", e);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -874,12 +875,14 @@
             if (ifaces.length == 0) {
                 return;
             }
-            NetworkStatsFactory nsf = new NetworkStatsFactory();
+            if (mNetworkStatsService == null) {
+                Slog.e(TAG, "NetworkStats Service is not available!");
+                return;
+            }
             NetworkStats stats = rollupNetworkStatsByFGBG(
-                    nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE,
-                            null));
+                    mNetworkStatsService.getDetailedUidStats(ifaces));
             addNetworkStats(tagId, pulledData, stats, true);
-        } catch (java.io.IOException e) {
+        } catch (RemoteException e) {
             Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -907,7 +910,8 @@
     private void pullKernelUidCpuTime(
             int tagId, long elapsedNanos, long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
-        mKernelUidCpuTimeReader.readAbsolute((uid, userTimeUs, systemTimeUs) -> {
+        mCpuUidUserSysTimeReader.readAbsolute((uid, timesUs) -> {
+            long userTimeUs = timesUs[0], systemTimeUs = timesUs[1];
             StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(uid);
             e.writeLong(userTimeUs);
@@ -919,7 +923,7 @@
     private void pullKernelUidCpuFreqTime(
             int tagId, long elapsedNanos, long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
-        mKernelUidCpuFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> {
+        mCpuUidFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> {
             for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) {
                 if (cpuFreqTimeMs[freqIndex] != 0) {
                     StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
@@ -936,7 +940,7 @@
     private void pullKernelUidCpuClusterTime(
             int tagId, long elapsedNanos, long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
-        mKernelUidCpuClusterTimeReader.readAbsolute((uid, cpuClusterTimesMs) -> {
+        mCpuUidClusterTimeReader.readAbsolute((uid, cpuClusterTimesMs) -> {
             for (int i = 0; i < cpuClusterTimesMs.length; i++) {
                 StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
                         wallClockNanos);
@@ -951,7 +955,7 @@
     private void pullKernelUidCpuActiveTime(
             int tagId, long elapsedNanos, long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
-        mKernelUidCpuActiveTimeReader.readAbsolute((uid, cpuActiveTimesMs) -> {
+        mCpuUidActiveTimeReader.readAbsolute((uid, cpuActiveTimesMs) -> {
             StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(uid);
             e.writeLong((long) cpuActiveTimesMs);
@@ -1701,6 +1705,27 @@
         }
     }
 
+    private void pullTemperature(int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
+        long callingToken = Binder.clearCallingIdentity();
+        try {
+            List<Temperature> temperatures = sThermalService.getCurrentTemperatures();
+            for (Temperature temp : temperatures) {
+                StatsLogEventWrapper e =
+                        new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+                e.writeInt(temp.getType());
+                e.writeString(temp.getName());
+                e.writeInt((int) (temp.getValue() * 10));
+                pulledData.add(e);
+            }
+        } catch (RemoteException e) {
+            // Should not happen.
+            Slog.e(TAG, "Disconnected from thermal service. Cannot pull temperatures.");
+        } finally {
+            Binder.restoreCallingIdentity(callingToken);
+        }
+    }
+
     /**
      * Pulls various data.
      */
@@ -1863,6 +1888,10 @@
                 pullDeviceCalculatedPowerBlameOther(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+            case StatsLog.TEMPERATURE: {
+                pullTemperature(tagId, elapsedNanos, wallClockNanos, ret);
+                break;
+            }
             default:
                 Slog.w(TAG, "No such tagId data as " + tagId);
                 return null;
@@ -2058,6 +2087,17 @@
         mContext.unregisterReceiver(mShutdownEventReceiver);
         cancelAnomalyAlarm();
         cancelPullingAlarm();
+
+        BinderCallsStatsService.Internal binderStats =
+                LocalServices.getService(BinderCallsStatsService.Internal.class);
+        if (binderStats != null) {
+            binderStats.reset();
+        }
+
+        LooperStats looperStats = LocalServices.getService(LooperStats.class);
+        if (looperStats != null) {
+            looperStats.reset();
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index fc21adb..8d2bab4 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -598,11 +598,11 @@
     }
 
     @Override
-    public void onBiometricAuthenticated() {
+    public void onBiometricAuthenticated(boolean authenticated) {
         enforceBiometricDialog();
         if (mBar != null) {
             try {
-                mBar.onBiometricAuthenticated();
+                mBar.onBiometricAuthenticated(authenticated);
             } catch (RemoteException ex) {
             }
         }
@@ -641,17 +641,6 @@
         }
     }
 
-    @Override
-    public void showBiometricTryAgain() {
-        enforceBiometricDialog();
-        if (mBar != null) {
-            try {
-                mBar.showBiometricTryAgain();
-            } catch (RemoteException ex) {
-            }
-        }
-    }
-
     // TODO(b/117478341): make it aware of multi-display if needed.
     @Override
     public void disable(int what, IBinder token, String pkg) {
@@ -1230,13 +1219,13 @@
     }
 
     @Override
-    public void onNotificationExpansionChanged(String key, boolean userAction,
-            boolean expanded) throws RemoteException {
+    public void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded,
+            int location) throws RemoteException {
         enforceStatusBarService();
         long identity = Binder.clearCallingIdentity();
         try {
             mNotificationDelegate.onNotificationExpansionChanged(
-                    key, userAction, expanded);
+                    key, userAction, expanded, location);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index f7cc443..2700f9d 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -24,7 +24,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.net.TrafficStats;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.FileObserver;
@@ -42,13 +41,13 @@
 import android.util.ArrayMap;
 import android.util.DataUnit;
 import android.util.Slog;
+import android.util.StatsLog;
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.EventLogTags;
-import com.android.server.IoThread;
 import com.android.server.SystemService;
 import com.android.server.pm.InstructionSets;
 import com.android.server.pm.PackageManagerService;
@@ -499,9 +498,15 @@
             notification.flags |= Notification.FLAG_NO_CLEAR;
             mNotifManager.notifyAsUser(uuid.toString(), SystemMessage.NOTE_LOW_STORAGE,
                     notification, UserHandle.ALL);
+            StatsLog.write(StatsLog.LOW_STORAGE_STATE_CHANGED,
+                    Objects.toString(vol.getDescription()),
+                    StatsLog.LOW_STORAGE_STATE_CHANGED__STATE__ON);
         } else if (State.isLeaving(State.LEVEL_LOW, oldLevel, newLevel)) {
             mNotifManager.cancelAsUser(uuid.toString(), SystemMessage.NOTE_LOW_STORAGE,
                     UserHandle.ALL);
+            StatsLog.write(StatsLog.LOW_STORAGE_STATE_CHANGED,
+                    Objects.toString(vol.getDescription()),
+                    StatsLog.LOW_STORAGE_STATE_CHANGED__STATE__OFF);
         }
     }
 
diff --git a/services/core/java/com/android/server/testharness/TestHarnessModeService.java b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
new file mode 100644
index 0000000..23c042a
--- /dev/null
+++ b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.testharness;
+
+import android.annotation.Nullable;
+import android.app.KeyguardManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.os.BatteryManager;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.PersistentDataBlockManagerInternal;
+import com.android.server.SystemService;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Set;
+
+/**
+ * Manages the Test Harness Mode service for setting up test harness mode on the device.
+ *
+ * <p>Test Harness Mode is a feature that allows the user to clean their device, retain ADB keys,
+ * and provision the device for Instrumentation testing. This means that all parts of the device
+ * that would otherwise interfere with testing (auto-syncing accounts, package verification,
+ * automatic updates, etc.) are all disabled by default but may be re-enabled by the user.
+ */
+public class TestHarnessModeService extends SystemService {
+    private static final String TAG = TestHarnessModeService.class.getSimpleName();
+    private static final String TEST_HARNESS_MODE_PROPERTY = "persist.sys.test_harness";
+
+    private PersistentDataBlockManagerInternal mPersistentDataBlockManagerInternal;
+
+    public TestHarnessModeService(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService("testharness", mService);
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        switch (phase) {
+            case PHASE_SYSTEM_SERVICES_READY:
+                setUpTestHarnessMode();
+                break;
+            case PHASE_BOOT_COMPLETED:
+                disableAutoSync();
+                break;
+        }
+        super.onBootPhase(phase);
+    }
+
+    private void setUpTestHarnessMode() {
+        Slog.d(TAG, "Setting up test harness mode");
+        byte[] testHarnessModeData = getPersistentDataBlock().getTestHarnessModeData();
+        if (testHarnessModeData == null || testHarnessModeData.length == 0) {
+            // There's no data to apply, so leave it as-is.
+            return;
+        }
+        PersistentData persistentData = PersistentData.fromBytes(testHarnessModeData);
+
+        SystemProperties.set(TEST_HARNESS_MODE_PROPERTY, persistentData.mEnabled ? "1" : "0");
+        writeAdbKeysFile(persistentData);
+        // Clear out the data block so that we don't revert the ADB keys on every boot.
+        getPersistentDataBlock().clearTestHarnessModeData();
+
+        ContentResolver cr = getContext().getContentResolver();
+        if (Settings.Global.getInt(cr, Settings.Global.ADB_ENABLED, 0) == 0) {
+            // Enable ADB
+            Settings.Global.putInt(cr, Settings.Global.ADB_ENABLED, 1);
+        } else {
+            // ADB is already enabled, we should restart the service so it picks up the new keys
+            android.os.SystemService.restart("adbd");
+        }
+
+        Settings.Global.putInt(cr, Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
+        Settings.Global.putInt(
+                cr,
+                Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
+                BatteryManager.BATTERY_PLUGGED_ANY);
+        Settings.Global.putInt(cr, Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE, 1);
+        Settings.Global.putInt(cr, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+
+        setDeviceProvisioned();
+    }
+
+    private void disableAutoSync() {
+        UserInfo primaryUser = UserManager.get(getContext()).getPrimaryUser();
+        ContentResolver
+            .setMasterSyncAutomaticallyAsUser(false, primaryUser.getUserHandle().getIdentifier());
+    }
+
+    private void writeAdbKeysFile(PersistentData persistentData) {
+        Path adbKeys = Paths.get("/data/misc/adb/adb_keys");
+        try {
+            OutputStream fileOutputStream = Files.newOutputStream(adbKeys);
+            fileOutputStream.write(persistentData.mAdbKeys);
+            fileOutputStream.close();
+
+            Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(adbKeys);
+            permissions.add(PosixFilePermission.GROUP_READ);
+            Files.setPosixFilePermissions(adbKeys, permissions);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to set up adb keys", e);
+            // Note: if a device enters this block, it will remain UNAUTHORIZED in ADB, but all
+            // other settings will be set up.
+        }
+    }
+
+    // Setting the device as provisioned skips the setup wizard.
+    private void setDeviceProvisioned() {
+        ContentResolver cr = getContext().getContentResolver();
+        Settings.Global.putInt(cr, Settings.Global.DEVICE_PROVISIONED, 1);
+        Settings.Secure.putIntForUser(
+                cr,
+                Settings.Secure.USER_SETUP_COMPLETE,
+                1,
+                UserHandle.USER_CURRENT);
+    }
+
+    @Nullable
+    private PersistentDataBlockManagerInternal getPersistentDataBlock() {
+        if (mPersistentDataBlockManagerInternal == null) {
+            Slog.d(TAG, "Getting PersistentDataBlockManagerInternal from LocalServices");
+            mPersistentDataBlockManagerInternal =
+                    LocalServices.getService(PersistentDataBlockManagerInternal.class);
+        }
+        return mPersistentDataBlockManagerInternal;
+    }
+
+    private final IBinder mService = new Binder() {
+        @Override
+        public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+                String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+            (new TestHarnessModeShellCommand())
+                .exec(this, in, out, err, args, callback, resultReceiver);
+        }
+    };
+
+    private class TestHarnessModeShellCommand extends ShellCommand {
+        @Override
+        public int onCommand(String cmd) {
+            switch (cmd) {
+                case "enable":
+                case "restore":
+                    checkPermissions();
+                    final long originalId = Binder.clearCallingIdentity();
+                    try {
+                        if (isDeviceSecure()) {
+                            getErrPrintWriter().println(
+                                    "Test Harness Mode cannot be enabled if there is a lock "
+                                            + "screen");
+                            return 2;
+                        }
+                        return handleEnable();
+                    } finally {
+                        Binder.restoreCallingIdentity(originalId);
+                    }
+                default:
+                    return handleDefaultCommands(cmd);
+            }
+        }
+
+        private void checkPermissions() {
+            getContext().enforceCallingPermission(
+                    android.Manifest.permission.ENABLE_TEST_HARNESS_MODE,
+                    "You must hold android.permission.ENABLE_TEST_HARNESS_MODE "
+                            + "to enable Test Harness Mode");
+        }
+
+        private boolean isDeviceSecure() {
+            UserInfo primaryUser = UserManager.get(getContext()).getPrimaryUser();
+            KeyguardManager keyguardManager = getContext().getSystemService(KeyguardManager.class);
+            return keyguardManager.isDeviceSecure(primaryUser.id);
+        }
+
+        private int handleEnable() {
+            Path adbKeys = Paths.get("/data/misc/adb/adb_keys");
+            if (!Files.exists(adbKeys)) {
+                // This should only be accessible on eng builds that haven't yet set up ADB keys
+                getErrPrintWriter()
+                    .println("No ADB keys stored; not enabling test harness mode");
+                return 1;
+            }
+
+            try (InputStream inputStream = Files.newInputStream(adbKeys)) {
+                long size = Files.size(adbKeys);
+                byte[] adbKeysBytes = new byte[(int) size];
+                int numBytes = inputStream.read(adbKeysBytes);
+                if (numBytes != size) {
+                    getErrPrintWriter().println("Failed to read all bytes of adb_keys");
+                    return 1;
+                }
+                PersistentData persistentData = new PersistentData(true, adbKeysBytes);
+                getPersistentDataBlock().setTestHarnessModeData(persistentData.toBytes());
+            } catch (IOException e) {
+                Slog.e(TAG, "Failed to store ADB keys.", e);
+                getErrPrintWriter().println("Failed to enable Test Harness Mode");
+                return 1;
+            }
+
+            Intent i = new Intent(Intent.ACTION_FACTORY_RESET);
+            i.setPackage("android");
+            i.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+            i.putExtra(Intent.EXTRA_REASON, TAG);
+            i.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, true);
+            getContext().sendBroadcastAsUser(i, UserHandle.SYSTEM);
+            return 0;
+        }
+
+        @Override
+        public void onHelp() {
+            PrintWriter pw = getOutPrintWriter();
+            pw.println("About:");
+            pw.println("  Test Harness Mode is a mode that the device can be placed in to prepare");
+            pw.println("  the device for running UI tests. The device is placed into this mode by");
+            pw.println("  first wiping all data from the device, preserving ADB keys.");
+            pw.println();
+            pw.println("  By default, the following settings are configured:");
+            pw.println("    * Package Verifier is disabled");
+            pw.println("    * Stay Awake While Charging is enabled");
+            pw.println("    * OTA Updates are disabled");
+            pw.println("    * Auto-Sync for accounts is disabled");
+            pw.println();
+            pw.println("  Other apps may configure themselves differently in Test Harness Mode by");
+            pw.println("  checking ActivityManager.isRunningInUserTestHarness()");
+            pw.println();
+            pw.println("Test Harness Mode commands:");
+            pw.println("  help");
+            pw.println("    Print this help text.");
+            pw.println();
+            pw.println("  enable|restore");
+            pw.println("    Erase all data from this device and enable Test Harness Mode,");
+            pw.println("    preserving the stored ADB keys currently on the device and toggling");
+            pw.println("    settings in a way that are conducive to Instrumentation testing.");
+        }
+    }
+
+    /**
+     * The object that will serialize/deserialize the Test Harness Mode data to and from the
+     * persistent data block.
+     */
+    public static class PersistentData {
+        static final byte VERSION_1 = 1;
+
+        final int mVersion;
+        final boolean mEnabled;
+        final byte[] mAdbKeys;
+
+        PersistentData(boolean enabled, byte[] adbKeys) {
+            this(VERSION_1, enabled, adbKeys);
+        }
+
+        PersistentData(int version, boolean enabled, byte[] adbKeys) {
+            this.mVersion = version;
+            this.mEnabled = enabled;
+            this.mAdbKeys = adbKeys;
+        }
+
+        static PersistentData fromBytes(byte[] bytes) {
+            try {
+                DataInputStream is = new DataInputStream(new ByteArrayInputStream(bytes));
+                int version = is.readInt();
+                boolean enabled = is.readBoolean();
+                int adbKeysLength = is.readInt();
+                byte[] adbKeys = new byte[adbKeysLength];
+                is.readFully(adbKeys);
+                return new PersistentData(version, enabled, adbKeys);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        byte[] toBytes() {
+            try {
+                ByteArrayOutputStream os = new ByteArrayOutputStream();
+                DataOutputStream dos = new DataOutputStream(os);
+                dos.writeInt(VERSION_1);
+                dos.writeBoolean(mEnabled);
+                dos.writeInt(mAdbKeys.length);
+                dos.write(mAdbKeys);
+                dos.close();
+                return os.toByteArray();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 2cab63a..ef77140 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -510,7 +510,8 @@
                 Slog.d(LOG_TAG, "Binding to " + serviceIntent.getComponent());
                 willBind = mContext.bindServiceAsUser(
                         serviceIntent, mConnection,
-                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+                                | Context.BIND_RESTRICT_ASSOCIATIONS,
                         UserHandle.of(mUserId));
                 mBinding = willBind;
             } finally {
diff --git a/services/core/java/com/android/server/textservices/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
index 65d5b10..d4aa59d 100644
--- a/services/core/java/com/android/server/textservices/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
@@ -16,7 +16,7 @@
 
 package com.android.server.textservices;
 
-import static android.view.textservice.TextServicesManager.DISABLE_PER_PROFILE_SPELL_CHECKER;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -43,6 +43,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.inputmethod.InputMethodSystemProperty;
 import android.view.textservice.SpellCheckerInfo;
 import android.view.textservice.SpellCheckerSubtype;
 
@@ -334,7 +335,7 @@
         mContext = context;
         mUserManager = mContext.getSystemService(UserManager.class);
         mSpellCheckerOwnerUserIdMap = new LazyIntToIntMap(callingUserId -> {
-            if (DISABLE_PER_PROFILE_SPELL_CHECKER) {
+            if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
                 final long token = Binder.clearCallingIdentity();
                 try {
                     final UserInfo parent = mUserManager.getProfileParent(callingUserId);
@@ -355,7 +356,7 @@
     private void initializeInternalStateLocked(@UserIdInt int userId) {
         // When DISABLE_PER_PROFILE_SPELL_CHECKER is true, we make sure here that work profile users
         // will never have non-null TextServicesData for their user ID.
-        if (DISABLE_PER_PROFILE_SPELL_CHECKER
+        if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED
                 && userId != mSpellCheckerOwnerUserIdMap.get(userId)) {
             return;
         }
@@ -514,8 +515,8 @@
     // TODO: Save SpellCheckerService by supported languages. Currently only one spell
     // checker is saved.
     @Override
-    public SpellCheckerInfo getCurrentSpellChecker(String locale) {
-        int userId = UserHandle.getCallingUserId();
+    public SpellCheckerInfo getCurrentSpellChecker(@UserIdInt int userId, String locale) {
+        verifyUser(userId);
         synchronized (mLock) {
             final TextServicesData tsd = getDataFromCallingUserIdLocked(userId);
             if (tsd == null) return null;
@@ -528,11 +529,12 @@
     // TODO: Save SpellCheckerSubtype by supported languages by looking at "locale".
     @Override
     public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
-            boolean allowImplicitlySelectedSubtype) {
+            @UserIdInt int userId, boolean allowImplicitlySelectedSubtype) {
+        verifyUser(userId);
+
         final int subtypeHashCode;
         final SpellCheckerInfo sci;
         final Locale systemLocale;
-        final int userId = UserHandle.getCallingUserId();
 
         synchronized (mLock) {
             final TextServicesData tsd = getDataFromCallingUserIdLocked(userId);
@@ -592,17 +594,17 @@
     }
 
     @Override
-    public void getSpellCheckerService(String sciId, String locale,
+    public void getSpellCheckerService(@UserIdInt int userId, String sciId, String locale,
             ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener,
             Bundle bundle) {
+        verifyUser(userId);
         if (TextUtils.isEmpty(sciId) || tsListener == null || scListener == null) {
             Slog.e(TAG, "getSpellCheckerService: Invalid input.");
             return;
         }
-        int callingUserId = UserHandle.getCallingUserId();
 
         synchronized (mLock) {
-            final TextServicesData tsd = getDataFromCallingUserIdLocked(callingUserId);
+            final TextServicesData tsd = getDataFromCallingUserIdLocked(userId);
             if (tsd == null) return;
 
             HashMap<String, SpellCheckerInfo> spellCheckerMap = tsd.mSpellCheckerMap;
@@ -635,8 +637,8 @@
     }
 
     @Override
-    public boolean isSpellCheckerEnabled() {
-        int userId = UserHandle.getCallingUserId();
+    public boolean isSpellCheckerEnabled(@UserIdInt int userId) {
+        verifyUser(userId);
 
         synchronized (mLock) {
             final TextServicesData tsd = getDataFromCallingUserIdLocked(userId);
@@ -672,11 +674,11 @@
     }
 
     @Override
-    public SpellCheckerInfo[] getEnabledSpellCheckers() {
-        int callingUserId = UserHandle.getCallingUserId();
+    public SpellCheckerInfo[] getEnabledSpellCheckers(@UserIdInt int userId) {
+        verifyUser(userId);
 
         synchronized (mLock) {
-            final TextServicesData tsd = getDataFromCallingUserIdLocked(callingUserId);
+            final TextServicesData tsd = getDataFromCallingUserIdLocked(userId);
             if (tsd == null) return null;
 
             ArrayList<SpellCheckerInfo> spellCheckerList = tsd.mSpellCheckerList;
@@ -692,11 +694,12 @@
     }
 
     @Override
-    public void finishSpellCheckerService(ISpellCheckerSessionListener listener) {
+    public void finishSpellCheckerService(@UserIdInt int userId,
+            ISpellCheckerSessionListener listener) {
         if (DBG) {
             Slog.d(TAG, "FinishSpellCheckerService");
         }
-        int userId = UserHandle.getCallingUserId();
+        verifyUser(userId);
 
         synchronized (mLock) {
             final TextServicesData tsd = getDataFromCallingUserIdLocked(userId);
@@ -717,6 +720,15 @@
         }
     }
 
+    private void verifyUser(@UserIdInt int userId) {
+        final int callingUserId = UserHandle.getCallingUserId();
+        if (userId != callingUserId) {
+            mContext.enforceCallingPermission(INTERACT_ACROSS_USERS_FULL,
+                    "Cross-user interaction requires INTERACT_ACROSS_USERS_FULL. userId=" + userId
+                            + " callingUserId=" + callingUserId);
+        }
+    }
+
     private void setCurrentSpellCheckerLocked(@Nullable SpellCheckerInfo sci, TextServicesData tsd) {
         final String sciId = (sci != null) ? sci.getId() : "";
         if (DBG) {
@@ -780,7 +792,7 @@
     private TextServicesData getDataFromCallingUserIdLocked(@UserIdInt int callingUserId) {
         final int spellCheckerOwnerUserId = mSpellCheckerOwnerUserIdMap.get(callingUserId);
         final TextServicesData data = mUserData.get(spellCheckerOwnerUserId);
-        if (DISABLE_PER_PROFILE_SPELL_CHECKER) {
+        if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
             if (spellCheckerOwnerUserId != callingUserId) {
                 // Calling process is running under child profile.
                 if (data == null) {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index ced5935..423ec4c 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -22,10 +22,8 @@
 import android.app.AlarmManager;
 import android.app.AlarmManager.OnAlarmListener;
 import android.app.admin.DevicePolicyManager;
-import android.hardware.biometrics.BiometricSourceType;
 import android.app.trust.ITrustListener;
 import android.app.trust.ITrustManager;
-import android.app.UserSwitchObserver;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -41,6 +39,7 @@
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
 import android.graphics.drawable.Drawable;
+import android.hardware.biometrics.BiometricSourceType;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -72,13 +71,15 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.SystemService;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
+
 
 /**
  * Manages trust agents and trust listeners.
@@ -119,7 +120,7 @@
 
     private static final int TRUST_USUALLY_MANAGED_FLUSH_DELAY = 2 * 60 * 1000;
     private static final String TRUST_TIMEOUT_ALARM_TAG = "TrustManagerService.trustTimeoutForUser";
-    private static final long TRUST_TIMEOUT_IN_MILLIS = 20 * 1000; //4 * 60 * 60 * 1000;
+    private static final long TRUST_TIMEOUT_IN_MILLIS = 4 * 60 * 60 * 1000;
 
     private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<>();
     private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<>();
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 9a7e75e..744efab 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -1129,7 +1129,8 @@
          * In this case, we grant a uri permission, even if the ContentProvider does not normally
          * grant uri permissions.
          */
-        boolean specialCrossUserGrant = UserHandle.getUserId(targetUid) != grantUri.sourceUserId
+        boolean specialCrossUserGrant = targetUid >= 0
+                && UserHandle.getUserId(targetUid) != grantUri.sourceUserId
                 && checkHoldingPermissionsInternal(pm, pi, grantUri, callingUid,
                 modeFlags, false /*without considering the uid permissions*/);
 
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index b3eafa4..45689ce 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -65,7 +65,6 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
-import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.utils.ManagedApplicationService;
 import com.android.server.utils.ManagedApplicationService.BinderChecker;
 import com.android.server.utils.ManagedApplicationService.LogEvent;
@@ -623,14 +622,6 @@
         }
 
         @Override
-        public void setVrInputMethod(ComponentName componentName) {
-            enforceCallerPermissionAnyOf(Manifest.permission.RESTRICTED_VR_ACCESS);
-            InputMethodManagerInternal imm =
-                    LocalServices.getService(InputMethodManagerInternal.class);
-            imm.startVrInputMethodNoCheck(componentName);
-        }
-
-        @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index f008770..69040a2 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -84,11 +84,13 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.EventLog;
+import android.util.FeatureFlagUtils;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.Xml;
 import android.view.Display;
+import android.view.DisplayInfo;
 import android.view.IWindowManager;
 
 import com.android.internal.R;
@@ -350,12 +352,34 @@
     }
 
     private void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) {
+        if (wallpaper.connection != null) {
+            wallpaper.connection.forEachDisplayConnector(connector -> {
+                notifyWallpaperColorsChangedOnDisplay(wallpaper, which, connector.mDisplayId);
+            });
+        } else { // Lock wallpaper does not have WallpaperConnection.
+            notifyWallpaperColorsChangedOnDisplay(wallpaper, which, DEFAULT_DISPLAY);
+        }
+    }
+
+    private RemoteCallbackList<IWallpaperManagerCallback> getWallpaperCallbacks(int userId,
+            int displayId) {
+        RemoteCallbackList<IWallpaperManagerCallback> listeners = null;
+        final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> displayListeners =
+                mColorsChangedListeners.get(userId);
+        if (displayListeners != null) {
+            listeners = displayListeners.get(displayId);
+        }
+        return listeners;
+    }
+
+    private void notifyWallpaperColorsChangedOnDisplay(@NonNull WallpaperData wallpaper, int which,
+            int displayId) {
         boolean needsExtraction;
         synchronized (mLock) {
             final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners =
-                    mColorsChangedListeners.get(wallpaper.userId);
+                    getWallpaperCallbacks(wallpaper.userId, displayId);
             final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners =
-                    mColorsChangedListeners.get(UserHandle.USER_ALL);
+                    getWallpaperCallbacks(UserHandle.USER_ALL, displayId);
             // No-op until someone is listening to it.
             if (emptyCallbackList(currentUserColorListeners)  &&
                     emptyCallbackList(userAllColorListeners)) {
@@ -363,7 +387,7 @@
             }
 
             if (DEBUG) {
-                Slog.v(TAG, "notifyWallpaperColorsChanged " + which);
+                Slog.v(TAG, "notifyWallpaperColorsChangedOnDisplay " + which);
             }
 
             needsExtraction = wallpaper.primaryColors == null;
@@ -371,7 +395,7 @@
 
         // Let's notify the current values, it's fine if it's null, it just means
         // that we don't know yet.
-        notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId);
+        notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId);
 
         if (needsExtraction) {
             extractColors(wallpaper);
@@ -381,7 +405,7 @@
                     return;
                 }
             }
-            notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId);
+            notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId);
         }
     }
 
@@ -390,14 +414,14 @@
     }
 
     private void notifyColorListeners(@NonNull WallpaperColors wallpaperColors, int which,
-            int userId) {
+            int userId, int displayId) {
         final IWallpaperManagerCallback keyguardListener;
         final ArrayList<IWallpaperManagerCallback> colorListeners = new ArrayList<>();
         synchronized (mLock) {
             final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners =
-                    mColorsChangedListeners.get(userId);
+                    getWallpaperCallbacks(userId, displayId);
             final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners =
-                    mColorsChangedListeners.get(UserHandle.USER_ALL);
+                    getWallpaperCallbacks(UserHandle.USER_ALL, displayId);
             keyguardListener = mKeyguardListener;
 
             if (currentUserColorListeners != null) {
@@ -427,7 +451,8 @@
             }
         }
 
-        if (keyguardListener != null) {
+        // Only shows Keyguard on default display
+        if (keyguardListener != null && displayId == DEFAULT_DISPLAY) {
             try {
                 keyguardListener.onWallpaperColorsChanged(wallpaperColors, which, userId);
             } catch (RemoteException e) {
@@ -446,6 +471,11 @@
         String cropFile = null;
         int wallpaperId;
 
+        if (wallpaper.equals(mFallbackWallpaper)) {
+            extractDefaultImageWallpaperColors();
+            return;
+        }
+
         synchronized (mLock) {
             // Not having a wallpaperComponent means it's a lock screen wallpaper.
             final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent)
@@ -482,6 +512,39 @@
         }
     }
 
+    private void extractDefaultImageWallpaperColors() {
+        synchronized (mLock) {
+            if (mFallbackWallpaper.primaryColors != null) return;
+        }
+
+        if (DEBUG) Slog.d(TAG, "Extract default image wallpaper colors");
+        WallpaperColors colors = null;
+        final InputStream is = WallpaperManager.openDefaultWallpaper(mContext, FLAG_SYSTEM);
+        if (is != null) {
+            try {
+                final BitmapFactory.Options options = new BitmapFactory.Options();
+                final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
+                if (bitmap != null) {
+                    colors = WallpaperColors.fromBitmap(bitmap);
+                    bitmap.recycle();
+                }
+            } catch (OutOfMemoryError e) {
+                Slog.w(TAG, "Can't decode default wallpaper stream", e);
+            } finally {
+                IoUtils.closeQuietly(is);
+            }
+        }
+
+        if (colors == null) {
+            Slog.e(TAG, "Extract default image wallpaper colors failed");
+            return;
+        }
+
+        synchronized (mLock) {
+            mFallbackWallpaper.primaryColors = colors;
+        }
+    }
+
     /**
      * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
      * for display.
@@ -539,6 +602,20 @@
             // scale if the crop height winds up not matching the recommended metrics
             needScale = (wpData.mHeight != cropHint.height());
 
+            //make sure screen aspect ratio is preserved if width is scaled under screen size
+            if (needScale) {
+                final DisplayInfo displayInfo = new DisplayInfo();
+                mDisplayManager.getDisplay(DEFAULT_DISPLAY).getDisplayInfo(displayInfo);
+                final float scaleByHeight = (float) wpData.mHeight / (float) cropHint.height();
+                final int newWidth = (int) (cropHint.width() * scaleByHeight);
+                if (newWidth < displayInfo.logicalWidth) {
+                    final float screenAspectRatio =
+                            (float) displayInfo.logicalHeight / (float) displayInfo.logicalWidth;
+                    cropHint.bottom = (int) (cropHint.width() * screenAspectRatio);
+                    needCrop = true;
+                }
+            }
+
             if (DEBUG) {
                 Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height());
                 Slog.v(TAG, "dims: w=" + wpData.mWidth + " h=" + wpData.mHeight);
@@ -696,6 +773,11 @@
                     targetWallpaper.connection.removeDisplayConnector(displayId);
                     removeDisplayData(displayId);
                 }
+                for (int i = mColorsChangedListeners.size() - 1; i >= 0; i--) {
+                    final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> callbacks =
+                            mColorsChangedListeners.valueAt(i);
+                    callbacks.delete(displayId);
+                }
             }
         }
 
@@ -706,9 +788,11 @@
 
     /**
      * Map of color listeners per user id.
-     * The key will be the id of a user or UserHandle.USER_ALL - for wildcard listeners.
+     * The first key will be the id of a user or UserHandle.USER_ALL - for wildcard listeners.
+     * The secondary key will be the display id, which means which display the listener is
+     * interested in.
      */
-    private final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>
+    private final SparseArray<SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>>
             mColorsChangedListeners;
     private WallpaperData mLastWallpaper;
     private IWallpaperManagerCallback mKeyguardListener;
@@ -904,14 +988,15 @@
             Slog.w(TAG, "Fallback wallpaper connection has not been created yet!!");
             return;
         }
-        if (supportsMultiDisplay(systemConnection)
-                && fallbackConnection.mDisplayConnector.size() != 0) {
-            fallbackConnection.forEachDisplayConnector(connector -> {
-                if (connector.mEngine != null) {
-                    connector.disconnectLocked();
-                }
-            });
-            fallbackConnection.mDisplayConnector.clear();
+        if (supportsMultiDisplay(systemConnection)) {
+            if (fallbackConnection.mDisplayConnector.size() != 0) {
+                fallbackConnection.forEachDisplayConnector(connector -> {
+                    if (connector.mEngine != null) {
+                        connector.disconnectLocked();
+                    }
+                });
+                fallbackConnection.mDisplayConnector.clear();
+            }
         } else {
             fallbackConnection.appendConnectorWithCondition(display ->
                     fallbackConnection.isUsableDisplay(display)
@@ -1228,9 +1313,10 @@
         /**
          * Called by a live wallpaper if its colors have changed.
          * @param primaryColors representation of wallpaper primary colors
+         * @param displayId for which display
          */
         @Override
-        public void onWallpaperColorsChanged(WallpaperColors primaryColors) {
+        public void onWallpaperColorsChanged(WallpaperColors primaryColors, int displayId) {
             int which;
             synchronized (mLock) {
                 // Do not broadcast changes on ImageWallpaper since it's handled
@@ -1243,14 +1329,16 @@
 
                 // Live wallpapers always are system wallpapers.
                 which = FLAG_SYSTEM;
-                // It's also the lock screen wallpaper when we don't have a bitmap in there
-                WallpaperData lockedWallpaper = mLockWallpaperMap.get(mWallpaper.userId);
-                if (lockedWallpaper == null) {
-                    which |= FLAG_LOCK;
+                // It's also the lock screen wallpaper when we don't have a bitmap in there.
+                if (displayId == DEFAULT_DISPLAY) {
+                    final WallpaperData lockedWallpaper = mLockWallpaperMap.get(mWallpaper.userId);
+                    if (lockedWallpaper == null) {
+                        which |= FLAG_LOCK;
+                    }
                 }
             }
             if (which != 0) {
-                notifyWallpaperColorsChanged(mWallpaper, which);
+                notifyWallpaperColorsChangedOnDisplay(mWallpaper, which, displayId);
             }
         }
 
@@ -1277,16 +1365,12 @@
                         Slog.w(TAG, "Failed to set ambient mode state", e);
                     }
                 }
-                // TODO(multi-display) So far, we have shared the same wallpaper on each display.
-                // Once we have multiple wallpapers on multiple displays, please complete here.
-                if (displayId == DEFAULT_DISPLAY) {
-                    try {
-                        // This will trigger onComputeColors in the wallpaper engine.
-                        // It's fine to be locked in here since the binder is oneway.
-                        connector.mEngine.requestWallpaperColors();
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Failed to request wallpaper colors", e);
-                    }
+                try {
+                    // This will trigger onComputeColors in the wallpaper engine.
+                    // It's fine to be locked in here since the binder is oneway.
+                    connector.mEngine.requestWallpaperColors();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to request wallpaper colors", e);
                 }
             }
         }
@@ -1681,6 +1765,7 @@
         FgThread.getHandler().post(() -> {
             notifyWallpaperColorsChanged(systemWallpaper, FLAG_SYSTEM);
             notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK);
+            notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
         });
     }
 
@@ -1743,6 +1828,7 @@
         // When clearing a wallpaper, broadcast new valid colors
         if (data != null) {
             notifyWallpaperColorsChanged(data, which);
+            notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
         }
     }
 
@@ -2084,35 +2170,47 @@
     }
 
     @Override
-    public void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId) {
+    public void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId,
+            int displayId) {
         userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, true, true, "registerWallpaperColorsCallback", null);
         synchronized (mLock) {
-            RemoteCallbackList<IWallpaperManagerCallback> userColorsChangedListeners =
-                    mColorsChangedListeners.get(userId);
-            if (userColorsChangedListeners == null) {
-                userColorsChangedListeners = new RemoteCallbackList<>();
-                mColorsChangedListeners.put(userId, userColorsChangedListeners);
+            SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>
+                    userDisplayColorsChangedListeners = mColorsChangedListeners.get(userId);
+            if (userDisplayColorsChangedListeners == null) {
+                userDisplayColorsChangedListeners = new SparseArray<>();
+                mColorsChangedListeners.put(userId, userDisplayColorsChangedListeners);
             }
-            userColorsChangedListeners.register(cb);
+            RemoteCallbackList<IWallpaperManagerCallback> displayChangedListeners =
+                    userDisplayColorsChangedListeners.get(displayId);
+            if (displayChangedListeners == null) {
+                displayChangedListeners = new RemoteCallbackList<>();
+                userDisplayColorsChangedListeners.put(displayId, displayChangedListeners);
+            }
+            displayChangedListeners.register(cb);
         }
     }
 
     @Override
-    public void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId) {
+    public void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId,
+            int displayId) {
         userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, true, true, "unregisterWallpaperColorsCallback", null);
         synchronized (mLock) {
-            final RemoteCallbackList<IWallpaperManagerCallback> userColorsChangedListeners =
-                    mColorsChangedListeners.get(userId);
-            if (userColorsChangedListeners != null) {
-                userColorsChangedListeners.unregister(cb);
+            SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>
+                    userDisplayColorsChangedListeners = mColorsChangedListeners.get(userId);
+            if (userDisplayColorsChangedListeners != null) {
+                RemoteCallbackList<IWallpaperManagerCallback> displayChangedListeners =
+                        userDisplayColorsChangedListeners.get(displayId);
+                if (displayChangedListeners != null) {
+                    displayChangedListeners.unregister(cb);
+                }
             }
         }
     }
 
     /**
-     * TODO(b/115486823) Extends this method with specific display.
+     * TODO(multi-display) Extends this method with specific display.
      * Propagate ambient state to wallpaper engine.
      *
      * @param inAmbientMode {@code true} when in ambient mode, {@code false} otherwise.
@@ -2123,9 +2221,13 @@
         synchronized (mLock) {
             mInAmbientMode = inAmbientMode;
             final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
-            if (data != null && data.connection != null && data.connection.mInfo != null
-                    && data.connection.mInfo.supportsAmbientMode()) {
-                // TODO(b/115486823) Extends this method with specific display.
+            final boolean hasConnection = data != null && data.connection != null;
+            final WallpaperInfo info = hasConnection ? data.connection.mInfo : null;
+
+            // The wallpaper info is null for image wallpaper, also use the engine in this case.
+            if (hasConnection && (info == null && isAodImageWallpaperEnabled()
+                    || info != null && info.supportsAmbientMode())) {
+                // TODO(multi-display) Extends this method with specific display.
                 engine = data.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
             } else {
                 engine = null;
@@ -2141,6 +2243,10 @@
         }
     }
 
+    private boolean isAodImageWallpaperEnabled() {
+        return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.AOD_IMAGEWALLPAPER_ENABLED);
+    }
+
     @Override
     public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
         checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
@@ -2151,7 +2257,8 @@
     }
 
     @Override
-    public WallpaperColors getWallpaperColors(int which, int userId) throws RemoteException {
+    public WallpaperColors getWallpaperColors(int which, int userId, int displayId)
+            throws RemoteException {
         if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
             throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM");
         }
@@ -2169,7 +2276,7 @@
             // Try to get the system wallpaper anyway since it might
             // also be the lock screen wallpaper
             if (wallpaperData == null) {
-                wallpaperData = mWallpaperMap.get(userId);
+                wallpaperData = findWallpaperAtDisplay(userId, displayId);
             }
 
             if (wallpaperData == null) {
@@ -2187,6 +2294,15 @@
         }
     }
 
+    private WallpaperData findWallpaperAtDisplay(int userId, int displayId) {
+        if (mFallbackWallpaper != null && mFallbackWallpaper.connection != null
+                && mFallbackWallpaper.connection.containsDisplay(displayId)) {
+            return mFallbackWallpaper;
+        } else {
+            return mWallpaperMap.get(userId);
+        }
+    }
+
     @Override
     public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
             Rect cropHint, boolean allowBackup, Bundle extras, int which,
@@ -2382,6 +2498,7 @@
 
         if (shouldNotifyColors) {
             notifyWallpaperColorsChanged(wallpaper, which);
+            notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index fe0b5c2..545b69b 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -49,6 +49,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TypedValue;
+import android.view.Display;
 import android.view.MagnificationSpec;
 import android.view.Surface;
 import android.view.Surface.OutOfResourcesException;
@@ -83,23 +84,36 @@
         mService = service;
     }
 
-    private DisplayMagnifier mDisplayMagnifier;
+    private SparseArray<DisplayMagnifier> mDisplayMagnifiers = new SparseArray<>();
 
     private WindowsForAccessibilityObserver mWindowsForAccessibilityObserver;
 
-    public void setMagnificationCallbacksLocked(MagnificationCallbacks callbacks) {
+    public boolean setMagnificationCallbacksLocked(int displayId,
+            MagnificationCallbacks callbacks) {
+        boolean result = false;
         if (callbacks != null) {
-            if (mDisplayMagnifier != null) {
+            if (mDisplayMagnifiers.get(displayId) != null) {
                 throw new IllegalStateException("Magnification callbacks already set!");
             }
-            mDisplayMagnifier = new DisplayMagnifier(mService, callbacks);
+            final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+            if (dc != null) {
+                final Display display = dc.getDisplay();
+                if (display != null && display.getType() != Display.TYPE_OVERLAY) {
+                    mDisplayMagnifiers.put(displayId, new DisplayMagnifier(
+                            mService, dc, display, callbacks));
+                    result = true;
+                }
+            }
         } else {
-            if  (mDisplayMagnifier == null) {
+            final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+            if  (displayMagnifier == null) {
                 throw new IllegalStateException("Magnification callbacks already cleared!");
             }
-            mDisplayMagnifier.destroyLocked();
-            mDisplayMagnifier = null;
+            displayMagnifier.destroyLocked();
+            mDisplayMagnifiers.remove(displayId);
+            result = true;
         }
+        return result;
     }
 
     public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
@@ -129,58 +143,72 @@
         }
     }
 
-    public void setMagnificationSpecLocked(MagnificationSpec spec) {
-        if (mDisplayMagnifier != null) {
-            mDisplayMagnifier.setMagnificationSpecLocked(spec);
+    public void setMagnificationSpecLocked(int displayId, MagnificationSpec spec) {
+        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+        if (displayMagnifier != null) {
+            displayMagnifier.setMagnificationSpecLocked(spec);
         }
-        if (mWindowsForAccessibilityObserver != null) {
+        // TODO: support multi-display for windows observer
+        if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
             mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
-    public void getMagnificationRegionLocked(Region outMagnificationRegion) {
-        if (mDisplayMagnifier != null) {
-            mDisplayMagnifier.getMagnificationRegionLocked(outMagnificationRegion);
+    public void getMagnificationRegionLocked(int displayId, Region outMagnificationRegion) {
+        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+        if (displayMagnifier != null) {
+            displayMagnifier.getMagnificationRegionLocked(outMagnificationRegion);
         }
     }
 
-    public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
-        if (mDisplayMagnifier != null) {
-            mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
+    public void onRectangleOnScreenRequestedLocked(int displayId, Rect rectangle) {
+        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+        if (displayMagnifier != null) {
+            displayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
         }
         // Not relevant for the window observer.
     }
 
-    public void onWindowLayersChangedLocked() {
-        if (mDisplayMagnifier != null) {
-            mDisplayMagnifier.onWindowLayersChangedLocked();
+    public void onWindowLayersChangedLocked(int displayId) {
+        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+        if (displayMagnifier != null) {
+            displayMagnifier.onWindowLayersChangedLocked();
         }
-        if (mWindowsForAccessibilityObserver != null) {
+        // TODO: support multi-display for windows observer
+        if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
             mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
     public void onRotationChangedLocked(DisplayContent displayContent) {
-        if (mDisplayMagnifier != null) {
-            mDisplayMagnifier.onRotationChangedLocked(displayContent);
+        final int displayId = displayContent.getDisplayId();
+        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+        if (displayMagnifier != null) {
+            displayMagnifier.onRotationChangedLocked(displayContent);
         }
-        if (mWindowsForAccessibilityObserver != null) {
+        // TODO: support multi-display for windows observer
+        if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
             mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
     public void onAppWindowTransitionLocked(WindowState windowState, int transition) {
-        if (mDisplayMagnifier != null) {
-            mDisplayMagnifier.onAppWindowTransitionLocked(windowState, transition);
+        final int displayId = windowState.getDisplayId();
+        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+        if (displayMagnifier != null) {
+            displayMagnifier.onAppWindowTransitionLocked(windowState, transition);
         }
         // Not relevant for the window observer.
     }
 
     public void onWindowTransitionLocked(WindowState windowState, int transition) {
-        if (mDisplayMagnifier != null) {
-            mDisplayMagnifier.onWindowTransitionLocked(windowState, transition);
+        final int displayId = windowState.getDisplayId();
+        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+        if (displayMagnifier != null) {
+            displayMagnifier.onWindowTransitionLocked(windowState, transition);
         }
-        if (mWindowsForAccessibilityObserver != null) {
+        // TODO: support multi-display for windows observer
+        if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
             mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
@@ -197,7 +225,6 @@
         }
     }
 
-
     public void onSomeWindowResizedOrMovedLocked() {
         // Not relevant for the display magnifier.
 
@@ -207,29 +234,34 @@
     }
 
     /** NOTE: This has to be called within a surface transaction. */
-    public void drawMagnifiedRegionBorderIfNeededLocked() {
-        if (mDisplayMagnifier != null) {
-            mDisplayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
+    public void drawMagnifiedRegionBorderIfNeededLocked(int displayId) {
+        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+        if (displayMagnifier != null) {
+            displayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
         }
         // Not relevant for the window observer.
     }
 
     public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
-        if (mDisplayMagnifier != null) {
-            return mDisplayMagnifier.getMagnificationSpecForWindowLocked(windowState);
+        final int displayId = windowState.getDisplayId();
+        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+        if (displayMagnifier != null) {
+            return displayMagnifier.getMagnificationSpecForWindowLocked(windowState);
         }
         return null;
     }
 
     public boolean hasCallbacksLocked() {
-        return (mDisplayMagnifier != null
+        // TODO: support multi-display for windows observer
+        return (mDisplayMagnifiers.size() > 0
                 || mWindowsForAccessibilityObserver != null);
     }
 
-    public void setForceShowMagnifiableBoundsLocked(boolean show) {
-        if (mDisplayMagnifier != null) {
-            mDisplayMagnifier.setForceShowMagnifiableBoundsLocked(show);
-            mDisplayMagnifier.showMagnificationBoundsIfNeeded();
+    public void setForceShowMagnifiableBoundsLocked(int displayId, boolean show) {
+        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+        if (displayMagnifier != null) {
+            displayMagnifier.setForceShowMagnifiableBoundsLocked(show);
+            displayMagnifier.showMagnificationBoundsIfNeeded();
         }
     }
 
@@ -263,6 +295,8 @@
         private final WindowManagerService mService;
         private final MagnifiedViewport mMagnifedViewport;
         private final Handler mHandler;
+        private final DisplayContent mDisplayContent;
+        private final Display mDisplay;
 
         private final MagnificationCallbacks mCallbacks;
 
@@ -271,10 +305,14 @@
         private boolean mForceShowMagnifiableBounds = false;
 
         public DisplayMagnifier(WindowManagerService windowManagerService,
+                DisplayContent displayContent,
+                Display display,
                 MagnificationCallbacks callbacks) {
             mContext = windowManagerService.mContext;
             mService = windowManagerService;
             mCallbacks = callbacks;
+            mDisplayContent = displayContent;
+            mDisplay = display;
             mHandler = new MyHandler(mService.mH.getLooper());
             mMagnifedViewport = new MagnifiedViewport();
             mLongAnimationDuration = mContext.getResources().getInteger(
@@ -285,7 +323,7 @@
             mMagnifedViewport.updateMagnificationSpecLocked(spec);
             mMagnifedViewport.recomputeBoundsLocked();
 
-            mService.applyMagnificationSpec(spec);
+            mService.applyMagnificationSpecLocked(mDisplay.getDisplayId(), spec);
             mService.scheduleAnimationLocked();
         }
 
@@ -482,7 +520,7 @@
 
                 if (mContext.getResources().getConfiguration().isScreenRound()) {
                     mCircularPath = new Path();
-                    mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
+                    mDisplay.getRealSize(mTempPoint);
                     final int centerXY = mTempPoint.x / 2;
                     mCircularPath.addCircle(centerXY, centerXY, centerXY, Path.Direction.CW);
                 } else {
@@ -512,7 +550,7 @@
             }
 
             public void recomputeBoundsLocked() {
-                mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
+                mDisplay.getRealSize(mTempPoint);
                 final int screenWidth = mTempPoint.x;
                 final int screenHeight = mTempPoint.y;
 
@@ -671,9 +709,8 @@
             }
 
             private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
-                final DisplayContent dc = mService.getDefaultDisplayContentLocked();
                 mTempLayer = 0;
-                dc.forAllWindows((w) -> {
+                mDisplayContent.forAllWindows((w) -> {
                     if (w.isOnScreen() && w.isVisibleLw()
                             && (w.mAttrs.alpha != 0)
                             && !w.mWinAnimator.mEnterAnimationPending) {
@@ -703,8 +740,9 @@
                 public ViewportWindow(Context context) {
                     SurfaceControl surfaceControl = null;
                     try {
-                        mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
-                        surfaceControl = mService.getDefaultDisplayContentLocked().makeOverlay()
+                        mDisplay.getRealSize(mTempPoint);
+                        surfaceControl = mDisplayContent
+                                .makeOverlay()
                                 .setName(SURFACE_TITLE)
                                 .setBufferSize(mTempPoint.x, mTempPoint.y) // not a typo
                                 .setFormat(PixelFormat.TRANSLUCENT)
@@ -1066,93 +1104,19 @@
 
                 final int visibleWindowCount = visibleWindows.size();
                 HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
-                for (int i = visibleWindowCount - 1; i >= 0; i--) {
+
+                // Iterate until we figure out what is touchable for the entire screen.
+                for (int i = visibleWindowCount - 1; i >= 0 && !unaccountedSpace.isEmpty(); i--) {
                     final WindowState windowState = visibleWindows.valueAt(i);
-                    final int flags = windowState.mAttrs.flags;
-                    final Task task = windowState.getTask();
 
-                    // If the window is part of a task that we're finished with - ignore.
-                    if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
-                        continue;
-                    }
-
-                    // Ignore non-touchable windows, except the split-screen divider, which is
-                    // occasionally non-touchable but still useful for identifying split-screen
-                    // mode.
-                    if (((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
-                            && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)) {
-                        continue;
-                    }
-
-                    // Compute the bounds in the screen.
                     final Rect boundsInScreen = mTempRect;
                     computeWindowBoundsInScreen(windowState, boundsInScreen);
 
-                    // If the window is completely covered by other windows - ignore.
-                    if (unaccountedSpace.quickReject(boundsInScreen)) {
-                        continue;
-                    }
-
-                    // Add windows of certain types not covered by modal windows.
-                    if (isReportedWindowType(windowState.mAttrs.type)) {
-                        // Add the window to the ones to be reported.
+                    if (windowMattersToAccessibility(windowState, boundsInScreen, unaccountedSpace,
+                            skipRemainingWindowsForTasks)) {
                         addPopulatedWindowInfo(windowState, boundsInScreen, windows, addedWindows);
-                        if (windowState.isFocused()) {
-                            focusedWindowAdded = true;
-                        }
-                    }
-
-                    if (windowState.mAttrs.type !=
-                            WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
-
-                        // Account for the space this window takes if the window
-                        // is not an accessibility overlay which does not change
-                        // the reported windows.
-                        unaccountedSpace.op(boundsInScreen, unaccountedSpace,
-                                Region.Op.REVERSE_DIFFERENCE);
-
-                        // If a window is modal it prevents other windows from being touched
-                        if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
-                            // Account for all space in the task, whether the windows in it are
-                            // touchable or not. The modal window blocks all touches from the task's
-                            // area.
-                            unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace,
-                                    Region.Op.REVERSE_DIFFERENCE);
-
-                            if (task != null) {
-                                // If the window is associated with a particular task, we can skip the
-                                // rest of the windows for that task.
-                                skipRemainingWindowsForTasks.add(task.mTaskId);
-                                continue;
-                            } else {
-                                // If the window is not associated with a particular task, then it is
-                                // globally modal. In this case we can skip all remaining windows.
-                                break;
-                            }
-                        }
-                    }
-
-                    // We figured out what is touchable for the entire screen - done.
-                    if (unaccountedSpace.isEmpty()) {
-                        break;
-                    }
-                }
-
-                // Always report the focused window.
-                if (!focusedWindowAdded) {
-                    for (int i = visibleWindowCount - 1; i >= 0; i--) {
-                        WindowState windowState = visibleWindows.valueAt(i);
-                        if (windowState.isFocused()) {
-                            // Compute the bounds in the screen.
-                            Rect boundsInScreen = mTempRect;
-                            computeWindowBoundsInScreen(windowState, boundsInScreen);
-
-                            // Add the window to the ones to be reported.
-                            addPopulatedWindowInfo(
-                                    windowState, boundsInScreen, windows, addedWindows);
-                            break;
-                        }
+                        updateUnaccountedSpace(windowState, boundsInScreen, unaccountedSpace,
+                                skipRemainingWindowsForTasks);
                     }
                 }
 
@@ -1221,6 +1185,73 @@
             clearAndRecycleWindows(windows);
         }
 
+        private boolean windowMattersToAccessibility(WindowState windowState, Rect boundsInScreen,
+                Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks) {
+            if (windowState.isFocused()) {
+                return true;
+            }
+
+            // If the window is part of a task that we're finished with - ignore.
+            final Task task = windowState.getTask();
+            if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
+                return false;
+            }
+
+            // Ignore non-touchable windows, except the split-screen divider, which is
+            // occasionally non-touchable but still useful for identifying split-screen
+            // mode.
+            if (((windowState.mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0)
+                    && (windowState.mAttrs.type != TYPE_DOCK_DIVIDER)) {
+                return false;
+            }
+
+            // If the window is completely covered by other windows - ignore.
+            if (unaccountedSpace.quickReject(boundsInScreen)) {
+                return false;
+            }
+
+            // Add windows of certain types not covered by modal windows.
+            if (isReportedWindowType(windowState.mAttrs.type)) {
+                return true;
+            }
+
+            return false;
+        }
+
+        private void updateUnaccountedSpace(WindowState windowState, Rect boundsInScreen,
+                Region unaccountedSpace, HashSet<Integer> skipRemainingWindowsForTasks) {
+            if (windowState.mAttrs.type
+                    != WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
+
+                // Account for the space this window takes if the window
+                // is not an accessibility overlay which does not change
+                // the reported windows.
+                unaccountedSpace.op(boundsInScreen, unaccountedSpace,
+                        Region.Op.REVERSE_DIFFERENCE);
+
+                // If a window is modal it prevents other windows from being touched
+                if ((windowState.mAttrs.flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
+                    // Account for all space in the task, whether the windows in it are
+                    // touchable or not. The modal window blocks all touches from the task's
+                    // area.
+                    unaccountedSpace.op(windowState.getDisplayFrameLw(), unaccountedSpace,
+                            Region.Op.REVERSE_DIFFERENCE);
+
+                    final Task task = windowState.getTask();
+                    if (task != null) {
+                        // If the window is associated with a particular task, we can skip the
+                        // rest of the windows for that task.
+                        skipRemainingWindowsForTasks.add(task.mTaskId);
+                    } else {
+                        // If the window is not associated with a particular task, then it is
+                        // globally modal. In this case we can skip all remaining windows.
+                        unaccountedSpace.setEmpty();
+                    }
+                }
+            }
+        }
+
         private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
             // Get the touchable frame.
             Region touchableRegion = mTempRegion1;
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 1f638c7..65d66f4 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -278,12 +278,12 @@
         }
 
         // Since positionChildAt() is called during the creation process of pinned stacks,
-        // ActivityStack#getWindowContainerController() can be null. In this special case,
+        // ActivityStack#getStack() can be null. In this special case,
         // since DisplayContest#positionStackAt() is called in TaskStack#onConfigurationChanged(),
         // we don't have to call WindowContainerController#positionChildAt() here.
-        if (stack.getWindowContainerController() != null && mDisplayContent != null) {
+        if (stack.getTaskStack() != null && mDisplayContent != null) {
             mDisplayContent.positionStackAt(insertPosition,
-                    stack.getWindowContainerController().mContainer, includingParents);
+                    stack.getTaskStack(), includingParents);
         }
         if (!wasContained) {
             stack.setParent(this);
@@ -450,13 +450,12 @@
     @VisibleForTesting
     <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
             int stackId, boolean onTop) {
-        if (windowingMode == WINDOWING_MODE_PINNED) {
-            return (T) new PinnedActivityStack(this, stackId,
-                    mRootActivityContainer.mStackSupervisor, onTop);
+        if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
+            throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
+                    + "activity type.");
         }
         return (T) new ActivityStack(this, stackId,
-                mRootActivityContainer.mStackSupervisor, windowingMode, activityType,
-                onTop);
+                mRootActivityContainer.mStackSupervisor, windowingMode, activityType, onTop);
     }
 
     /**
@@ -626,6 +625,10 @@
             return;
         }
 
+        // Collect the stacks that are necessary to be removed instead of performing the removal
+        // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+        // stacks reordered.
+        final ArrayList<ActivityStack> stacks = new ArrayList<>();
         for (int j = windowingModes.length - 1 ; j >= 0; --j) {
             final int windowingMode = windowingModes[j];
             for (int i = mStacks.size() - 1; i >= 0; --i) {
@@ -636,9 +639,13 @@
                 if (stack.getWindowingMode() != windowingMode) {
                     continue;
                 }
-                mRootActivityContainer.mStackSupervisor.removeStack(stack);
+                stacks.add(stack);
             }
         }
+
+        for (int i = stacks.size() - 1; i >= 0; --i) {
+            mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
+        }
     }
 
     void removeStacksWithActivityTypes(int... activityTypes) {
@@ -646,15 +653,23 @@
             return;
         }
 
+        // Collect the stacks that are necessary to be removed instead of performing the removal
+        // by looping mStacks, so that we don't miss any stacks after the stack size changed or
+        // stacks reordered.
+        final ArrayList<ActivityStack> stacks = new ArrayList<>();
         for (int j = activityTypes.length - 1 ; j >= 0; --j) {
             final int activityType = activityTypes[j];
             for (int i = mStacks.size() - 1; i >= 0; --i) {
                 final ActivityStack stack = mStacks.get(i);
                 if (stack.getActivityType() == activityType) {
-                    mRootActivityContainer.mStackSupervisor.removeStack(stack);
+                    stacks.add(stack);
                 }
             }
         }
+
+        for (int i = stacks.size() - 1; i >= 0; --i) {
+            mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
+        }
     }
 
     void onStackWindowingModeChanged(ActivityStack stack) {
@@ -1019,8 +1034,8 @@
         return mSplitScreenPrimaryStack != null;
     }
 
-    PinnedActivityStack getPinnedStack() {
-        return (PinnedActivityStack) mPinnedStack;
+    ActivityStack getPinnedStack() {
+        return mPinnedStack;
     }
 
     boolean hasPinnedStack() {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 2cd0168..b8634d8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -54,6 +54,7 @@
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
 import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
 import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
+import static android.content.pm.ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED;
 import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS;
 import static android.content.pm.ActivityInfo.FLAG_NO_HISTORY;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
@@ -142,6 +143,7 @@
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityOptions;
 import android.app.PendingIntent;
@@ -271,7 +273,10 @@
     boolean fullscreen; // The activity is opaque and fills the entire space of this task.
     // TODO: See if it possible to combine this with the fullscreen field.
     final boolean hasWallpaper; // Has a wallpaper window as a background.
-    final boolean noDisplay;  // activity is not displayed?
+    @VisibleForTesting
+    boolean noDisplay;  // activity is not displayed?
+    @VisibleForTesting
+    int mHandoverLaunchDisplayId = INVALID_DISPLAY; // Handover launch display id to next activity.
     private final boolean componentSpecified;  // did caller specify an explicit component?
     final boolean rootVoiceInteraction;  // was this the root activity of a voice interaction?
 
@@ -384,9 +389,15 @@
     int mRotationAnimationHint = -1;
 
     private boolean mShowWhenLocked;
+    private boolean mInheritShownWhenLocked;
     private boolean mTurnScreenOn;
 
     /**
+     * Current sequencing integer of the configuration, for skipping old activity configurations.
+     */
+    private int mConfigurationSeq;
+
+    /**
      * Temp configs used in {@link #ensureActivityConfiguration(int, boolean)}
      */
     private final Configuration mTmpConfig = new Configuration();
@@ -725,9 +736,10 @@
             mLastReportedMultiWindowMode = inPictureInPictureMode;
             final Configuration newConfig = new Configuration();
             if (targetStackBounds != null && !targetStackBounds.isEmpty()) {
-                task.computeResolvedOverrideConfiguration(newConfig,
-                        task.getParent().getConfiguration(),
-                        task.getRequestedOverrideConfiguration());
+                newConfig.setTo(task.getRequestedOverrideConfiguration());
+                Rect outBounds = newConfig.windowConfiguration.getBounds();
+                task.adjustForMinimalTaskDimensions(outBounds, outBounds);
+                task.computeConfigResourceOverrides(newConfig, task.getParent().getConfiguration());
             }
             schedulePictureInPictureModeChanged(newConfig);
             scheduleMultiWindowModeChanged(newConfig);
@@ -993,6 +1005,7 @@
                 null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
 
         mShowWhenLocked = (aInfo.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
+        mInheritShownWhenLocked = (aInfo.privateFlags & FLAG_INHERIT_SHOW_WHEN_LOCKED) != 0;
         mTurnScreenOn = (aInfo.flags & FLAG_TURN_SCREEN_ON) != 0;
 
         mRotationAnimationHint = aInfo.rotationAnimation;
@@ -1019,6 +1032,8 @@
             if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) {
                 lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
             }
+            // Gets launch display id from options. It returns INVALID_DISPLAY if not set.
+            mHandoverLaunchDisplayId = options.getLaunchDisplayId();
         }
     }
 
@@ -1476,14 +1491,6 @@
         return true;
     }
 
-    /**
-     * @return true if the activity contains windows that have
-     *         {@link LayoutParams#FLAG_DISMISS_KEYGUARD} set
-     */
-    boolean hasDismissKeyguardWindows() {
-        return mAtmService.mWindowManager.containsDismissKeyguardWindow(appToken);
-    }
-
     void makeFinishingLocked() {
         if (finishing) {
             return;
@@ -2498,8 +2505,16 @@
             return;
         }
 
-        final IBinder binder = freezeScreenIfNeeded ? appToken.asBinder() : null;
+        final IBinder binder =
+                (freezeScreenIfNeeded && appToken != null) ? appToken.asBinder() : null;
         mAppWindowToken.setOrientation(requestedOrientation, binder, this);
+
+        // Push the new configuration to the requested app in case where it's not pushed, e.g. when
+        // the request is handled at task level with letterbox.
+        if (!getMergedOverrideConfiguration().equals(
+                mLastReportedConfiguration.getMergedConfiguration())) {
+            ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+        }
     }
 
     int getOrientation() {
@@ -2542,7 +2557,6 @@
 
     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
     private void updateOverrideConfiguration() {
-        mTmpConfig.unset();
         computeBounds(mTmpBounds);
 
         if (mTmpBounds.equals(getRequestedOverrideBounds())) {
@@ -2553,13 +2567,54 @@
 
         // Bounds changed...update configuration to match.
         if (!matchParentBounds()) {
-            task.computeResolvedOverrideConfiguration(mTmpConfig,
-                    task.getParent().getConfiguration(), getRequestedOverrideConfiguration());
+            mTmpConfig.setTo(getRequestedOverrideConfiguration());
+            task.computeConfigResourceOverrides(mTmpConfig, task.getParent().getConfiguration());
+        } else {
+            mTmpConfig.unset();
         }
 
         onRequestedOverrideConfigurationChanged(mTmpConfig);
     }
 
+    @Override
+    void resolveOverrideConfiguration(Configuration newParentConfiguration) {
+        super.resolveOverrideConfiguration(newParentConfiguration);
+
+        // Assign configuration sequence number into hierarchy because there is a different way than
+        // ensureActivityConfiguration() in this class that uses configuration in WindowState during
+        // layout traversals.
+        mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
+        getResolvedOverrideConfiguration().seq = mConfigurationSeq;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newParentConfig) {
+        super.onConfigurationChanged(newParentConfig);
+
+        // Configuration's equality doesn't consider seq so if only seq number changes in resolved
+        // override configuration. Therefore ConfigurationContainer doesn't change merged override
+        // configuration, but it's used to push configuration changes so explicitly update that.
+        if (getMergedOverrideConfiguration().seq != getResolvedOverrideConfiguration().seq) {
+            onMergedOverrideConfigurationChanged();
+        }
+
+        // TODO(b/80414790): Remove code below after unification.
+        // Same as above it doesn't notify configuration listeners, and consequently AppWindowToken
+        // can't get updated seq number. However WindowState's merged override configuration needs
+        // to have this seq number because that's also used for activity config pushes during layout
+        // traversal. Therefore explicitly update them here.
+        if (mAppWindowToken == null) {
+            return;
+        }
+        final Configuration appWindowTokenRequestedOverrideConfig =
+                mAppWindowToken.getRequestedOverrideConfiguration();
+        if (appWindowTokenRequestedOverrideConfig.seq != getResolvedOverrideConfiguration().seq) {
+            appWindowTokenRequestedOverrideConfig.seq =
+                    getResolvedOverrideConfiguration().seq;
+            mAppWindowToken.onMergedOverrideConfigurationChanged();
+        }
+    }
+
     /** Returns true if the configuration is compatible with this activity. */
     boolean isConfigurationCompatible(Configuration config) {
         final int orientation = mAppWindowToken != null
@@ -3172,16 +3227,45 @@
                 false /* preserveWindows */);
     }
 
+    void setInheritShowWhenLocked(boolean inheritShowWhenLocked) {
+        mInheritShownWhenLocked = inheritShowWhenLocked;
+        mRootActivityContainer.ensureActivitiesVisible(null, 0, false);
+    }
+
     /**
      * @return true if the activity windowing mode is not
-     *         {@link android.app.WindowConfiguration#WINDOWING_MODE_PINNED} and activity contains
-     *         windows that have {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set or if the activity
-     *         has set {@link #mShowWhenLocked}.
+     *         {@link android.app.WindowConfiguration#WINDOWING_MODE_PINNED} and a) activity
+     *         contains windows that have {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set or if the
+     *         activity has set {@link #mShowWhenLocked}, or b) if the activity has set
+     *         {@link #mInheritShownWhenLocked} and the activity behind this satisfies the
+     *         conditions a) above.
      *         Multi-windowing mode will be exited if true is returned.
      */
     boolean canShowWhenLocked() {
-        return !inPinnedWindowingMode() && (mShowWhenLocked
-                || mAtmService.mWindowManager.containsShowWhenLockedWindow(appToken));
+        if (!inPinnedWindowingMode() && (mShowWhenLocked
+                || (mAppWindowToken != null && mAppWindowToken.containsShowWhenLockedWindow()))) {
+            return true;
+        } else if (mInheritShownWhenLocked) {
+            ActivityRecord r = getActivityBelow();
+            return r != null && !r.inPinnedWindowingMode() && (r.mShowWhenLocked
+                    || (r.mAppWindowToken != null
+                        && r.mAppWindowToken.containsShowWhenLockedWindow()));
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * @return an {@link ActivityRecord} of the activity below this activity, or {@code null} if no
+     * such activity exists.
+     */
+    @Nullable
+    private ActivityRecord getActivityBelow() {
+        final int pos = task.mActivities.indexOf(this);
+        if (pos == -1) {
+            throw new IllegalStateException("Activity not found in its task");
+        }
+        return pos == 0 ? null : task.getChildAt(pos - 1);
     }
 
     void setTurnScreenOn(boolean turnScreenOn) {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 4581a0f..891c3da 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -114,6 +114,7 @@
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityController;
+import android.app.RemoteAction;
 import android.app.ResultInfo;
 import android.app.WindowConfiguration.ActivityType;
 import android.app.WindowConfiguration.WindowingMode;
@@ -173,8 +174,7 @@
 /**
  * State and management of a single stack of activities.
  */
-class ActivityStack<T extends StackWindowController> extends ConfigurationContainer
-        implements StackWindowListener {
+class ActivityStack extends ConfigurationContainer {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM;
     private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
     private static final String TAG_APP = TAG + POSTFIX_APP;
@@ -297,8 +297,7 @@
     static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2;
 
     final ActivityTaskManagerService mService;
-    private final WindowManagerService mWindowManager;
-    T mWindowContainerController;
+    final WindowManagerService mWindowManager;
 
     /**
      * The back history of all previous (and possibly still
@@ -397,6 +396,9 @@
     static final int DESTROY_ACTIVITIES_MSG = FIRST_ACTIVITY_STACK_MSG + 5;
     static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 6;
 
+    // TODO: remove after unification.
+    TaskStack mTaskStack;
+
     private static class ScheduleDestroyArgs {
         final WindowProcessController mOwner;
         final String mReason;
@@ -495,21 +497,30 @@
         // stacks on a wrong display.
         mDisplayId = display.mDisplayId;
         setActivityType(activityType);
-        mWindowContainerController = createStackWindowController(display.mDisplayId, onTop,
-                mTmpRect2);
+        createTaskStack(display.mDisplayId, onTop, mTmpRect2);
         setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
                 false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
                 true /* creating */);
         display.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
     }
 
-    T createStackWindowController(int displayId, boolean onTop, Rect outBounds) {
-        return (T) new StackWindowController(mStackId, this, displayId, onTop, outBounds,
-                mRootActivityContainer.mWindowManager);
+    void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
+        final DisplayContent dc = mWindowManager.mRoot.getDisplayContent(displayId);
+        if (dc == null) {
+            throw new IllegalArgumentException("Trying to add stackId=" + mStackId
+                    + " to unknown displayId=" + displayId);
+        }
+        mTaskStack = new TaskStack(mWindowManager, mStackId, this);
+        dc.setStackOnDisplay(mStackId, onTop, mTaskStack);
+        if (mTaskStack.matchParentBounds()) {
+            outBounds.setEmpty();
+        } else {
+            mTaskStack.getRawBounds(outBounds);
+        }
     }
 
-    T getWindowContainerController() {
-        return mWindowContainerController;
+    TaskStack getTaskStack() {
+        return mTaskStack;
     }
 
     /**
@@ -553,6 +564,9 @@
         if (display == null) {
             return;
         }
+        if (getTaskStack() == null) {
+            return;
+        }
 
         // Update bounds if applicable
         boolean hasNewOverrideBounds = false;
@@ -560,8 +574,7 @@
         if (getRequestedOverrideWindowingMode() == WINDOWING_MODE_PINNED) {
             // Pinned calculation already includes rotation
             mTmpRect2.set(mTmpRect);
-            hasNewOverrideBounds = getWindowContainerController().mContainer
-                            .calculatePinnedBoundsForConfigChange(mTmpRect2);
+            hasNewOverrideBounds = getTaskStack().calculatePinnedBoundsForConfigChange(mTmpRect2);
         } else {
             final int newRotation = getWindowConfiguration().getRotation();
             if (!matchParentBounds()) {
@@ -588,7 +601,7 @@
                             || getRequestedOverrideWindowingMode()
                             == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
                         mTmpRect2.set(mTmpRect);
-                        getWindowContainerController().mContainer
+                        getTaskStack()
                                 .calculateDockedBoundsForConfigChange(newParentConfig, mTmpRect2);
                         hasNewOverrideBounds = true;
                     }
@@ -786,7 +799,11 @@
 
             mTmpRect2.setEmpty();
             if (windowingMode != WINDOWING_MODE_FULLSCREEN) {
-                mWindowContainerController.getRawBounds(mTmpRect2);
+                if (mTaskStack.matchParentBounds()) {
+                    mTmpRect2.setEmpty();
+                } else {
+                    mTaskStack.getRawBounds(mTmpRect2);
+                }
             }
 
             if (!Objects.equals(getRequestedOverrideBounds(), mTmpRect2)) {
@@ -843,7 +860,12 @@
         // Reparent the window container before we try to update the position when adding it to
         // the new display below
         mTmpRect2.setEmpty();
-        mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
+        if (mTaskStack == null) {
+            // TODO: Remove after unification.
+            Log.w(TAG, "Task stack is not valid when reparenting.");
+        } else {
+            mTaskStack.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
+        }
         setBounds(mTmpRect2.isEmpty() ? null : mTmpRect2);
         activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
         if (!displayRemoved) {
@@ -876,8 +898,10 @@
     /** Removes the stack completely. Also calls WindowManager to do the same on its side. */
     void remove() {
         removeFromDisplay();
-        mWindowContainerController.removeContainer();
-        mWindowContainerController = null;
+        if (mTaskStack != null) {
+            mTaskStack.removeIfPossible();
+            mTaskStack = null;
+        }
         onParentChanged();
     }
 
@@ -890,26 +914,35 @@
      */
     void getStackDockedModeBounds(Rect dockedBounds, Rect currentTempTaskBounds,
             Rect outStackBounds, Rect outTempTaskBounds) {
-        mWindowContainerController.getStackDockedModeBounds(getParent().getConfiguration(),
-                dockedBounds, currentTempTaskBounds,
-                outStackBounds, outTempTaskBounds);
+        if (mTaskStack != null) {
+            mTaskStack.getStackDockedModeBoundsLocked(getParent().getConfiguration(), dockedBounds,
+                    currentTempTaskBounds, outStackBounds, outTempTaskBounds);
+        } else {
+            outStackBounds.setEmpty();
+            outTempTaskBounds.setEmpty();
+        }
     }
 
     void prepareFreezingTaskBounds() {
-        mWindowContainerController.prepareFreezingTaskBounds();
+        if (mTaskStack != null) {
+            // TODO: This cannot be false after unification.
+            mTaskStack.prepareFreezingTaskBounds();
+        }
     }
 
     void getWindowContainerBounds(Rect outBounds) {
-        if (mWindowContainerController != null) {
-            mWindowContainerController.getBounds(outBounds);
+        if (mTaskStack != null) {
+            mTaskStack.getBounds(outBounds);
             return;
         }
         outBounds.setEmpty();
     }
 
     void positionChildWindowContainerAtTop(TaskRecord child) {
-        mWindowContainerController.positionChildAtTop(child.getTask(),
-                true /* includingParents */);
+        if (mTaskStack != null) {
+            // TODO: Remove after unification. This cannot be false after that.
+            mTaskStack.positionChildAtTop(child.getTask(), true /* includingParents */);
+        }
     }
 
     void positionChildWindowContainerAtBottom(TaskRecord child) {
@@ -918,14 +951,27 @@
         // task to bottom, the next focusable stack on the same display should be focused.
         final ActivityStack nextFocusableStack = getDisplay().getNextFocusableStack(
                 child.getStack(), true /* ignoreCurrent */);
-        mWindowContainerController.positionChildAtBottom(child.getTask(),
-                nextFocusableStack == null /* includingParents */);
+        if (mTaskStack != null) {
+            // TODO: Remove after unification. This cannot be false after that.
+            mTaskStack.positionChildAtBottom(child.getTask(),
+                    nextFocusableStack == null /* includingParents */);
+        }
     }
 
     /**
      * Returns whether to defer the scheduling of the multi-window mode.
      */
     boolean deferScheduleMultiWindowModeChanged() {
+        if (inPinnedWindowingMode()) {
+            // For the pinned stack, the deferring of the multi-window mode changed is tied to the
+            // transition animation into picture-in-picture, and is called once the animation
+            // completes, or is interrupted in a way that would leave the stack in a non-fullscreen
+            // state.
+            // @see BoundsAnimationController
+            // @see BoundsAnimationControllerTests
+            if (getTaskStack() == null) return false;
+            return getTaskStack().deferScheduleMultiWindowModeChanged();
+        }
         return false;
     }
 
@@ -2204,7 +2250,8 @@
                 .isKeyguardOrAodShowing(displayId);
         final boolean keyguardLocked = mStackSupervisor.getKeyguardController().isKeyguardLocked();
         final boolean showWhenLocked = r.canShowWhenLocked();
-        final boolean dismissKeyguard = r.hasDismissKeyguardWindows();
+        final boolean dismissKeyguard = r.mAppWindowToken != null
+                && r.mAppWindowToken.containsDismissKeyguardWindow();
         if (shouldBeVisible) {
             if (dismissKeyguard && mTopDismissingKeyguardActivity == null) {
                 mTopDismissingKeyguardActivity = r;
@@ -2561,7 +2608,9 @@
                 final boolean canShowWhenLocked = !mTopActivityOccludesKeyguard
                         && next.canShowWhenLocked();
                 final boolean mayDismissKeyguard = mTopDismissingKeyguardActivity != next
-                        && next.hasDismissKeyguardWindows();
+                        && next.mAppWindowToken != null
+                        && next.mAppWindowToken.containsDismissKeyguardWindow();
+
                 if (canShowWhenLocked || mayDismissKeyguard) {
                     ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
                             !PRESERVE_WINDOWS);
@@ -2991,7 +3040,10 @@
         position = getAdjustedPositionForTask(task, position, null /* starting */);
         mTaskHistory.remove(task);
         mTaskHistory.add(position, task);
-        mWindowContainerController.positionChildAt(task.getTask(), position);
+        if (mTaskStack != null) {
+            // TODO: this could not be false after unification.
+            mTaskStack.positionChildAt(task.getTask(), position);
+        }
         updateTaskMovement(task, true);
     }
 
@@ -4906,8 +4958,7 @@
     }
 
     // TODO: Figure-out a way to consolidate with resize() method below.
-    @Override
-    public void requestResize(Rect bounds) {
+    void requestResize(Rect bounds) {
         mService.resizeStack(mStackId, bounds,
                 true /* allowResizeInDockedMode */, false /* preserveWindows */,
                 false /* animate */, -1 /* animationDuration */);
@@ -4945,7 +4996,8 @@
     }
 
     void onPipAnimationEndResize() {
-        mWindowContainerController.onPipAnimationEndResize();
+        if (mTaskStack == null) return;
+        mTaskStack.onPipAnimationEndResize();
     }
 
 
@@ -5491,6 +5543,65 @@
         }
     }
 
+
+    Rect getDefaultPictureInPictureBounds(float aspectRatio) {
+        if (getTaskStack() == null) return null;
+        return getTaskStack().getPictureInPictureBounds(aspectRatio, null /* currentStackBounds */);
+    }
+
+    void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
+            boolean fromFullscreen) {
+        if (!inPinnedWindowingMode()) return;
+        if (skipResizeAnimation(toBounds == null /* toFullscreen */)) {
+            mService.moveTasksToFullscreenStack(mStackId, true /* onTop */);
+        } else {
+            if (getTaskStack() == null) return;
+            getTaskStack().animateResizePinnedStack(toBounds, sourceHintBounds,
+                    animationDuration, fromFullscreen);
+        }
+    }
+
+    private boolean skipResizeAnimation(boolean toFullscreen) {
+        if (!toFullscreen) {
+            return false;
+        }
+        final Configuration parentConfig = getParent().getConfiguration();
+        final ActivityRecord top = topRunningNonOverlayTaskActivity();
+        return top != null && !top.isConfigurationCompatible(parentConfig);
+    }
+
+    void setPictureInPictureAspectRatio(float aspectRatio) {
+        if (getTaskStack() == null) return;
+        getTaskStack().setPictureInPictureAspectRatio(aspectRatio);
+    }
+
+    void setPictureInPictureActions(List<RemoteAction> actions) {
+        if (getTaskStack() == null) return;
+        getTaskStack().setPictureInPictureActions(actions);
+    }
+
+    boolean isAnimatingBoundsToFullscreen() {
+        if (getTaskStack() == null) return false;
+        return getTaskStack().isAnimatingBoundsToFullscreen();
+    }
+
+    public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
+            boolean forceUpdate) {
+        // It is guaranteed that the activities requiring the update will be in the pinned stack at
+        // this point (either reparented before the animation into PiP, or before reparenting after
+        // the animation out of PiP)
+        synchronized (mService.mGlobalLock) {
+            if (!isAttached()) {
+                return;
+            }
+            ArrayList<TaskRecord> tasks = getAllTasks();
+            for (int i = 0; i < tasks.size(); i++) {
+                mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
+                        forceUpdate);
+            }
+        }
+    }
+
     public int getStackId() {
         return mStackId;
     }
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index f58b83d..3a288ca 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -947,6 +947,7 @@
         final WindowProcessController wpc =
                 mService.getProcessController(r.processName, r.info.applicationInfo.uid);
 
+        boolean knownToBeDead = false;
         if (wpc != null && wpc.hasThread()) {
             try {
                 if ((r.info.flags & ActivityInfo.FLAG_MULTIPROCESS) == 0
@@ -965,6 +966,7 @@
 
             // If a dead object exception was thrown -- fall through to
             // restart the application.
+            knownToBeDead = true;
         }
 
         // Suppress transition until the new activity becomes ready, otherwise the keyguard can
@@ -978,7 +980,7 @@
         // ATMS lock held.
         final Message msg = PooledLambda.obtainMessage(
                 ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
-                r.info.applicationInfo, true, "activity", r.intent.getComponent());
+                r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
         mService.mH.sendMessage(msg);
     }
 
@@ -1672,8 +1674,8 @@
     }
 
     void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
-        // TODO(multi-display): Pinned stack display should be passed in.
-        final PinnedActivityStack stack =
+        // TODO(multi-display): The display containing the stack should be passed in.
+        final ActivityStack stack =
                 mRootActivityContainer.getDefaultDisplay().getPinnedStack();
         if (stack == null) {
             Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found");
@@ -1684,7 +1686,7 @@
         // another AM call that is holding the AMS lock. In such a case, the pinnedBounds may be
         // incorrect if AMS.resizeStackWithBoundsFromWindowManager() is already called while waiting
         // for the AMS lock to be freed. So check and make sure these bounds are still good.
-        final PinnedStackWindowController stackController = stack.getWindowContainerController();
+        final TaskStack stackController = stack.getTaskStack();
         if (stackController.pinnedStackResizeDisallowed()) {
             return;
         }
@@ -1728,15 +1730,14 @@
              * invisible as well and added to the stopping list.  After which we process the
              * stopping list by handling the idle.
              */
-            final PinnedActivityStack pinnedStack = (PinnedActivityStack) stack;
-            pinnedStack.mForceHidden = true;
-            pinnedStack.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
-            pinnedStack.mForceHidden = false;
+            stack.mForceHidden = true;
+            stack.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
+            stack.mForceHidden = false;
             activityIdleInternalLocked(null, false /* fromTimeout */,
                     true /* processPausingActivites */, null /* configuration */);
 
             // Move all the tasks to the bottom of the fullscreen stack
-            moveTasksToFullscreenStackLocked(pinnedStack, !ON_TOP);
+            moveTasksToFullscreenStackLocked(stack, !ON_TOP);
         } else {
             for (int i = tasks.size() - 1; i >= 0; i--) {
                 removeTaskByIdLocked(tasks.get(i).taskId, true /* killProcess */,
@@ -2640,6 +2641,9 @@
                 try {
                     mService.moveTaskToFrontLocked(task.taskId, 0, options,
                             true /* fromRecents */);
+                    // Apply options to prevent pendingOptions be taken by client to make sure
+                    // the override pending app transition will be applied immediately.
+                    targetActivity.applyOptionsLocked();
                 } finally {
                     mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
                             targetActivity);
@@ -2657,7 +2661,8 @@
             return mService.getActivityStartController().startActivityInPackage(
                     task.mCallingUid, callingPid, callingUid, callingPackage, intent, null, null,
                     null, 0, 0, options, userId, task, "startActivityFromRecents",
-                    false /* validateIncomingUser */, null /* originatingPendingIntent */);
+                    false /* validateIncomingUser */, null /* originatingPendingIntent */,
+                    false /* allowBackgroundActivityStart */);
         } finally {
             if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && task != null) {
                 // If we are launching the task in the docked stack, put it into resizing mode so
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index b4d5d9f..2807094 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -258,7 +258,7 @@
             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) {
+            PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
 
         userId = checkTargetUser(userId, validateIncomingUser, realCallingPid, realCallingUid,
                 reason);
@@ -278,6 +278,7 @@
                 .setMayWait(userId)
                 .setInTask(inTask)
                 .setOriginatingPendingIntent(originatingPendingIntent)
+                .setAllowBackgroundActivityStart(allowBackgroundActivityStart)
                 .execute();
     }
 
@@ -294,7 +295,31 @@
      */
     final int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
             String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
-            boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent) {
+            boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
+            boolean allowBackgroundActivityStart) {
+        return startActivitiesInPackage(uid, 0 /* realCallingPid */, -1 /* realCallingUid */,
+            callingPackage, intents, resolvedTypes, resultTo, options, userId, validateIncomingUser,
+            originatingPendingIntent, allowBackgroundActivityStart);
+    }
+
+    /**
+     * Start intents as a package.
+     *
+     * @param uid Make a call as if this UID did.
+     * @param realCallingPid PID of the real caller.
+     * @param realCallingUid UID of the real caller.
+     * @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
+     */
+    final int startActivitiesInPackage(int uid, int realCallingPid, int realCallingUid,
+            String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo,
+            SafeActivityOptions options, int userId, boolean validateIncomingUser,
+            PendingIntentRecord originatingPendingIntent,
+            boolean allowBackgroundActivityStart) {
 
         final String reason = "startActivityInPackage";
 
@@ -302,13 +327,16 @@
                 Binder.getCallingUid(), reason);
 
         // TODO: Switch to user app stacks here.
-        return startActivities(null, uid, callingPackage, intents, resolvedTypes, resultTo, options,
-                userId, reason, originatingPendingIntent);
+        return startActivities(null, uid, realCallingPid, realCallingUid, callingPackage, intents,
+                resolvedTypes, resultTo, options, userId, reason, originatingPendingIntent,
+                allowBackgroundActivityStart);
     }
 
-    int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
-            Intent[] intents, String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options,
-            int userId, String reason, PendingIntentRecord originatingPendingIntent) {
+    int startActivities(IApplicationThread caller, int callingUid, int incomingRealCallingPid,
+            int incomingRealCallingUid, String callingPackage, Intent[] intents,
+            String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options,
+            int userId, String reason, PendingIntentRecord originatingPendingIntent,
+            boolean allowBackgroundActivityStart) {
         if (intents == null) {
             throw new NullPointerException("intents is null");
         }
@@ -319,8 +347,12 @@
             throw new IllegalArgumentException("intents are length different than resolvedTypes");
         }
 
-        final int realCallingPid = Binder.getCallingPid();
-        final int realCallingUid = Binder.getCallingUid();
+        final int realCallingPid = incomingRealCallingPid != 0
+                ? incomingRealCallingPid
+                : Binder.getCallingPid();
+        final int realCallingUid = incomingRealCallingUid != -1
+                ? incomingRealCallingUid
+                : Binder.getCallingUid();
 
         int callingPid;
         if (callingUid >= 0) {
@@ -387,6 +419,7 @@
                             // top one as otherwise an activity below might consume it.
                             .setAllowPendingRemoteAnimationRegistryLookup(top /* allowLookup*/)
                             .setOriginatingPendingIntent(originatingPendingIntent)
+                            .setAllowBackgroundActivityStart(allowBackgroundActivityStart)
                             .execute();
 
                     if (res < 0) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 36701ea..d36e545 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
 import static android.app.Activity.RESULT_CANCELED;
 import static android.app.ActivityManager.START_ABORTED;
 import static android.app.ActivityManager.START_CANCELED;
@@ -50,6 +51,7 @@
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 
@@ -292,6 +294,8 @@
     private static class Request {
         private static final int DEFAULT_CALLING_UID = -1;
         private static final int DEFAULT_CALLING_PID = 0;
+        static final int DEFAULT_REAL_CALLING_UID = -1;
+        static final int DEFAULT_REAL_CALLING_PID = 0;
 
         IApplicationThread caller;
         Intent intent;
@@ -304,11 +308,11 @@
         IBinder resultTo;
         String resultWho;
         int requestCode;
-        int callingPid = DEFAULT_CALLING_UID;
-        int callingUid = DEFAULT_CALLING_PID;
+        int callingPid = DEFAULT_CALLING_PID;
+        int callingUid = DEFAULT_CALLING_UID;
         String callingPackage;
-        int realCallingPid;
-        int realCallingUid;
+        int realCallingPid = DEFAULT_REAL_CALLING_PID;
+        int realCallingUid = DEFAULT_REAL_CALLING_UID;
         int startFlags;
         SafeActivityOptions activityOptions;
         boolean ignoreTargetSecurity;
@@ -323,6 +327,7 @@
         WaitResult waitResult;
         int filterCallingUid;
         PendingIntentRecord originatingPendingIntent;
+        boolean allowBackgroundActivityStart;
 
         /**
          * If set to {@code true}, allows this activity start to look into
@@ -362,8 +367,8 @@
             callingPid = DEFAULT_CALLING_PID;
             callingUid = DEFAULT_CALLING_UID;
             callingPackage = null;
-            realCallingPid = 0;
-            realCallingUid = 0;
+            realCallingPid = DEFAULT_REAL_CALLING_PID;
+            realCallingUid = DEFAULT_REAL_CALLING_UID;
             startFlags = 0;
             activityOptions = null;
             ignoreTargetSecurity = false;
@@ -380,6 +385,7 @@
             allowPendingRemoteAnimationRegistryLookup = true;
             filterCallingUid = UserHandle.USER_NULL;
             originatingPendingIntent = null;
+            allowBackgroundActivityStart = false;
         }
 
         /**
@@ -419,6 +425,7 @@
                     = request.allowPendingRemoteAnimationRegistryLookup;
             filterCallingUid = request.filterCallingUid;
             originatingPendingIntent = request.originatingPendingIntent;
+            allowBackgroundActivityStart = request.allowBackgroundActivityStart;
         }
     }
 
@@ -497,14 +504,15 @@
             // for transactional diffs and preprocessing.
             if (mRequest.mayWait) {
                 return startActivityMayWait(mRequest.caller, mRequest.callingUid,
-                        mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
+                        mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid,
+                        mRequest.intent, mRequest.resolvedType,
                         mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                         mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
                         mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
                         mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
                         mRequest.inTask, mRequest.reason,
                         mRequest.allowPendingRemoteAnimationRegistryLookup,
-                        mRequest.originatingPendingIntent);
+                        mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
             } else {
                 return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
                         mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
@@ -515,7 +523,7 @@
                         mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
                         mRequest.outActivity, mRequest.inTask, mRequest.reason,
                         mRequest.allowPendingRemoteAnimationRegistryLookup,
-                        mRequest.originatingPendingIntent);
+                        mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
             }
         } finally {
             onExecutionComplete();
@@ -548,7 +556,7 @@
             SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
             ActivityRecord[] outActivity, TaskRecord inTask, String reason,
             boolean allowPendingRemoteAnimationRegistryLookup,
-            PendingIntentRecord originatingPendingIntent) {
+            PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
 
         if (TextUtils.isEmpty(reason)) {
             throw new IllegalArgumentException("Need to specify a reason.");
@@ -561,7 +569,8 @@
                 aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
                 callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                 options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
-                inTask, allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent);
+                inTask, allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent,
+                allowBackgroundActivityStart);
 
         if (outActivity != null) {
             // mLastStartActivityRecord[0] is set in the call to startActivity above.
@@ -592,7 +601,7 @@
             SafeActivityOptions options,
             boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
             TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,
-            PendingIntentRecord originatingPendingIntent) {
+            PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
         int err = ActivityManager.START_SUCCESS;
         // Pull the optional Ephemeral Installer-only bundle out of the options early.
         final Bundle verificationBundle
@@ -741,8 +750,9 @@
         // not sure if we need to create START_ABORTED_BACKGROUND so for now piggybacking
         // on START_ABORTED
         if (!abort) {
-            abort |= shouldAbortBackgroundActivityStart(callingUid, callingPackage, realCallingUid,
-                    callerApp);
+            abort |= shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage,
+                    realCallingUid, callerApp, originatingPendingIntent,
+                    allowBackgroundActivityStart, intent);
         }
 
         // Merge the two options bundles, while realCallerOptions takes precedence.
@@ -889,8 +899,10 @@
                 true /* doResume */, checkedOptions, inTask, outActivity);
     }
 
-    private boolean shouldAbortBackgroundActivityStart(int callingUid, final String callingPackage,
-            int realCallingUid, WindowProcessController callerApp) {
+    private boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
+            final String callingPackage, int realCallingUid, WindowProcessController callerApp,
+            PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart,
+            Intent intent) {
         if (mService.isBackgroundActivityStartsEnabled()) {
             return false;
         }
@@ -902,12 +914,35 @@
         if (callerApp != null && callerApp.hasForegroundActivities()) {
             return false;
         }
-        // don't abort if the callingUid is in the foreground
-        if (isUidForeground(callingUid)) {
+        // don't abort if the callingUid is in the foreground or is a persistent system process
+        final boolean isCallingUidForeground = isUidForeground(callingUid);
+        final boolean isCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
+                callingUid);
+        if (isCallingUidForeground || isCallingUidPersistentSystemProcess) {
             return false;
         }
-        // don't abort if the realCallingUid is in the foreground and callingUid isn't
-        if ((realCallingUid != callingUid) && isUidForeground(realCallingUid)) {
+        // take realCallingUid into consideration
+        final boolean isRealCallingUidForeground = isUidForeground(realCallingUid);
+        final boolean isRealCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
+                realCallingUid);
+        if (realCallingUid != callingUid) {
+            // don't abort if the realCallingUid is in the foreground and callingUid isn't
+            if (isRealCallingUidForeground) {
+                return false;
+            }
+            // if the realCallingUid is a persistent system process, abort if the IntentSender
+            // wasn't whitelisted to start an activity
+            if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) {
+                return false;
+            }
+        }
+        // don't abort if the caller is currently temporarily whitelisted
+        if (callerApp != null && callerApp.areBackgroundActivityStartsAllowed()) {
+            return false;
+        }
+        // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
+        if (mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
+                == PERMISSION_GRANTED) {
             return false;
         }
         // don't abort if the caller has the same uid as the recents component
@@ -915,6 +950,18 @@
             return false;
         }
         // anything that has fallen through will currently be aborted
+        Slog.w(TAG, "Blocking background activity start [callingPackage: " + callingPackage
+                + "; callingUid: " + callingUid
+                + "; isCallingUidForeground: " + isCallingUidForeground
+                + "; isCallingUidPersistentSystemProcess: " + isCallingUidPersistentSystemProcess
+                + "; realCallingUid: " + realCallingUid
+                + "; isRealCallingUidForeground: " + isRealCallingUidForeground
+                + "; isRealCallingUidPersistentSystemProcess: "
+                        + isRealCallingUidPersistentSystemProcess
+                + "; originatingPendingIntent: " + originatingPendingIntent
+                + "; isBgStartWhitelisted: " + allowBackgroundActivityStart
+                + "; intent: " + intent
+                + "]");
         // TODO: remove this toast after feature development is done
         mService.mUiHandler.post(() -> {
             Toast.makeText(mService.mContext,
@@ -924,10 +971,15 @@
         return true;
     }
 
-    /** Returns true if uid has a visible window or its process is in top or persistent state. */
+    /** Returns true if uid has a visible window or its process is in a top state. */
     private boolean isUidForeground(int uid) {
-        return (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_TOP)
-            || mService.mWindowManager.isAnyWindowVisibleForUid(uid);
+        return (mService.getUidStateLocked(uid) == ActivityManager.PROCESS_STATE_TOP)
+            || mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
+    }
+
+    /** Returns true if uid is in a persistent state. */
+    private boolean isUidPersistentSystemProcess(int uid) {
+        return (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_PERSISTENT_UI);
     }
 
     private void maybeLogActivityStart(int callingUid, String callingPackage, int realCallingUid,
@@ -945,18 +997,19 @@
             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "logActivityStart");
             final int callingUidProcState = mService.getUidStateLocked(callingUid);
             final boolean callingUidHasAnyVisibleWindow =
-                    mService.mWindowManager.isAnyWindowVisibleForUid(callingUid);
+                    mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(callingUid);
             final int realCallingUidProcState = (callingUid == realCallingUid)
                     ? callingUidProcState
                     : mService.getUidStateLocked(realCallingUid);
             final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid)
                     ? callingUidHasAnyVisibleWindow
-                    : mService.mWindowManager.isAnyWindowVisibleForUid(realCallingUid);
+                    : mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(
+                            realCallingUid);
             final String targetPackage = (r != null) ? r.packageName : null;
             final int targetUid = (r!= null) ? ((r.appInfo != null) ? r.appInfo.uid : -1) : -1;
             final int targetUidProcState = mService.getUidStateLocked(targetUid);
             final boolean targetUidHasAnyVisibleWindow = (targetUid != -1)
-                    ? mService.mWindowManager.isAnyWindowVisibleForUid(targetUid)
+                    ? mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(targetUid)
                     : false;
             final String targetWhitelistTag = (targetUid != -1)
                     ? mService.getPendingTempWhitelistTagForUidLocked(targetUid)
@@ -1042,14 +1095,14 @@
     }
 
     private int startActivityMayWait(IApplicationThread caller, int callingUid,
-            String callingPackage, Intent intent, String resolvedType,
-            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            IBinder resultTo, String resultWho, int requestCode, int startFlags,
-            ProfilerInfo profilerInfo, WaitResult outResult,
+            String callingPackage, int requestRealCallingPid, int requestRealCallingUid,
+            Intent intent, String resolvedType, IVoiceInteractionSession voiceSession,
+            IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode,
+            int startFlags, ProfilerInfo profilerInfo, WaitResult outResult,
             Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
             int userId, TaskRecord inTask, String reason,
             boolean allowPendingRemoteAnimationRegistryLookup,
-            PendingIntentRecord originatingPendingIntent) {
+            PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
         // Refuse possible leaked file descriptors
         if (intent != null && intent.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -1057,8 +1110,12 @@
         mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
         boolean componentSpecified = intent.getComponent() != null;
 
-        final int realCallingPid = Binder.getCallingPid();
-        final int realCallingUid = Binder.getCallingUid();
+        final int realCallingPid = requestRealCallingPid != Request.DEFAULT_REAL_CALLING_PID
+                ? requestRealCallingPid
+                : Binder.getCallingPid();
+        final int realCallingUid = requestRealCallingUid != Request.DEFAULT_REAL_CALLING_UID
+                ? requestRealCallingUid
+                : Binder.getCallingUid();
 
         int callingPid;
         if (callingUid >= 0) {
@@ -1195,7 +1252,8 @@
                     voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
                     callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
                     ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
-                    allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent);
+                    allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent,
+                    allowBackgroundActivityStart);
 
             Binder.restoreCallingIdentity(origId);
 
@@ -2731,6 +2789,11 @@
         return this;
     }
 
+    ActivityStarter setAllowBackgroundActivityStart(boolean allowBackgroundActivityStart) {
+        mRequest.allowBackgroundActivityStart = allowBackgroundActivityStart;
+        return this;
+    }
+
     void dump(PrintWriter pw, String prefix) {
         prefix = prefix + "  ";
         pw.print(prefix);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 0fc890a..67b00b2 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.ActivityManager;
 import android.app.AppProtoEnums;
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
@@ -191,22 +192,28 @@
      * Start intents as a package.
      *
      * @param uid Make a call as if this UID did.
+     * @param realCallingPid PID of the real caller.
+     * @param realCallingUid UID of the real caller.
      * @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
+     * @param allowBackgroundActivityStart Whether the background activity start should be allowed
+     *        from originatingPendingIntent
      */
-    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 startActivitiesInPackage(int uid, int realCallingPid, int realCallingUid,
+            String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo,
+            SafeActivityOptions options, int userId, boolean validateIncomingUser,
+            PendingIntentRecord originatingPendingIntent,
+            boolean allowBackgroundActivityStart);
 
     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);
+            PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart);
 
     /**
      * Start activity {@code intent} without calling user-id check.
@@ -476,4 +483,10 @@
     public abstract void setProfilerInfo(ProfilerInfo profilerInfo);
 
     public abstract ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry();
+
+    /**
+     * Gets bitmap snapshot of the provided task id.
+     */
+    public abstract ActivityManager.TaskSnapshot getTaskSnapshot(int taskId,
+            boolean reducedResolution);
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 86c5d4d..ea6f4cc 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -82,13 +82,10 @@
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.HOME_PROC;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.LAUNCHING_ACTIVITY;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto
-        .PREVIOUS_PROC_VISIBLE_TIME_MS;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
-        .MODE;
-import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage
-        .PACKAGE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -210,6 +207,7 @@
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionManagerInternal;
+import android.sysprop.DisplayProperties;
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
 import android.text.format.Time;
@@ -245,7 +243,6 @@
 import com.android.internal.util.FastPrintWriter;
 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;
 import com.android.server.SystemService;
@@ -261,6 +258,7 @@
 import com.android.server.am.PendingIntentController;
 import com.android.server.am.PendingIntentRecord;
 import com.android.server.am.UserState;
+import com.android.server.appop.AppOpsService;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.pm.UserManagerService;
 import com.android.server.uri.UriGrantsManagerInternal;
@@ -639,7 +637,8 @@
         }
     }
 
-    ActivityTaskManagerService(Context context) {
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    public ActivityTaskManagerService(Context context) {
         mContext = context;
         mFactoryTest = FactoryTest.getMode();
         mSystemThread = ActivityThread.currentActivityThread();
@@ -693,7 +692,7 @@
         final boolean isPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
 
         // Transfer any global setting for forcing RTL layout, into a System Property
-        SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
+        DisplayProperties.debug_force_rtl(forceRtl);
 
         final Configuration configuration = new Configuration();
         Settings.System.getConfiguration(resolver, configuration);
@@ -958,9 +957,10 @@
         enforceNotIsolatedCaller(reason);
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, reason);
         // TODO: Switch to user app stacks here.
-        return getActivityStartController().startActivities(caller, -1, callingPackage, intents,
-                resolvedTypes, resultTo, SafeActivityOptions.fromBundle(bOptions), userId, reason,
-                null /* originatingPendingIntent */);
+        return getActivityStartController().startActivities(caller, -1, 0, -1, callingPackage,
+                intents, resolvedTypes, resultTo, SafeActivityOptions.fromBundle(bOptions), userId,
+                reason, null /* originatingPendingIntent */,
+                false /* allowBackgroundActivityStart */);
     }
 
     @Override
@@ -2406,7 +2406,7 @@
         try {
             synchronized (mGlobalLock) {
                 if (animate) {
-                    final PinnedActivityStack stack = mRootActivityContainer.getStack(stackId);
+                    final ActivityStack stack = mRootActivityContainer.getStack(stackId);
                     if (stack == null) {
                         Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
                         return;
@@ -3711,7 +3711,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                final PinnedActivityStack stack =
+                final ActivityStack stack =
                         mRootActivityContainer.getDefaultDisplay().getPinnedStack();
                 if (stack == null) {
                     Slog.w(TAG, "dismissPip: pinned stack not found.");
@@ -3833,9 +3833,8 @@
 
         // If we are animating to fullscreen then we have already dispatched the PIP mode
         // changed, so we should reflect that check here as well.
-        final PinnedActivityStack stack = r.getActivityStack();
-        final PinnedStackWindowController windowController = stack.getWindowContainerController();
-        return !windowController.mContainer.isAnimatingBoundsToFullscreen();
+        final TaskStack taskStack = r.getActivityStack().getTaskStack();
+        return !taskStack.isAnimatingBoundsToFullscreen();
     }
 
     @Override
@@ -3869,7 +3868,7 @@
                                 r.pictureInPictureArgs.getSourceRectHint());
                         mRootActivityContainer.moveActivityToPinnedStack(
                                 r, sourceBounds, aspectRatio, "enterPictureInPictureMode");
-                        final PinnedActivityStack stack = r.getActivityStack();
+                        final ActivityStack stack = r.getActivityStack();
                         stack.setPictureInPictureAspectRatio(aspectRatio);
                         stack.setPictureInPictureActions(actions);
                         MetricsLoggerWrapper.logPictureInPictureEnter(mContext, r.appInfo.uid,
@@ -3913,7 +3912,7 @@
                     // If the activity is already in picture-in-picture, update the pinned stack now
                     // if it is not already expanding to fullscreen. Otherwise, the arguments will
                     // be used the next time the activity enters PiP
-                    final PinnedActivityStack stack = r.getActivityStack();
+                    final ActivityStack stack = r.getActivityStack();
                     if (!stack.isAnimatingBoundsToFullscreen()) {
                         stack.setPictureInPictureAspectRatio(
                                 r.pictureInPictureArgs.getAspectRatio());
@@ -4333,6 +4332,22 @@
     }
 
     @Override
+    public void setInheritShowWhenLocked(IBinder token, boolean inheritShowWhenLocked) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r == null) {
+                return;
+            }
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                r.setInheritShowWhenLocked(inheritShowWhenLocked);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+
+    @Override
     public void setTurnScreenOn(IBinder token, boolean turnScreenOn) {
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.isInStackLocked(token);
@@ -5298,9 +5313,18 @@
     }
 
     void updateActivityUsageStats(ActivityRecord activity, int event) {
+        ComponentName taskRoot = null;
+        final TaskRecord task = activity.getTaskRecord();
+        if (task != null) {
+            final ActivityRecord rootActivity = task.getRootActivity();
+            if (rootActivity != null) {
+                taskRoot = rootActivity.mActivityComponent;
+            }
+        }
+
         final Message m = PooledLambda.obtainMessage(
                 ActivityManagerInternal::updateActivityUsageStats, mAmInternal,
-                activity.mActivityComponent, activity.mUserId, event, activity.appToken);
+                activity.mActivityComponent, activity.mUserId, event, activity.appToken, taskRoot);
         mH.sendMessage(m);
     }
 
@@ -5807,18 +5831,22 @@
                         packageUid, packageName,
                         intents, resolvedTypes, null /* resultTo */,
                         SafeActivityOptions.fromBundle(bOptions), userId,
-                        false /* validateIncomingUser */, null /* originatingPendingIntent */);
+                        false /* validateIncomingUser */, null /* originatingPendingIntent */,
+                        false /* allowBackgroundActivityStart */);
             }
         }
 
         @Override
-        public int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
-                String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId,
-                boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent) {
+        public int startActivitiesInPackage(int uid, int realCallingPid, int realCallingUid,
+                String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo,
+                SafeActivityOptions options, int userId, boolean validateIncomingUser,
+                PendingIntentRecord originatingPendingIntent,
+                boolean allowBackgroundActivityStart) {
             synchronized (mGlobalLock) {
-                return getActivityStartController().startActivitiesInPackage(uid, callingPackage,
-                        intents, resolvedTypes, resultTo, options, userId, validateIncomingUser,
-                        originatingPendingIntent);
+                return getActivityStartController().startActivitiesInPackage(uid, realCallingPid,
+                        realCallingUid, callingPackage, intents, resolvedTypes, resultTo, options,
+                        userId, validateIncomingUser, originatingPendingIntent,
+                        allowBackgroundActivityStart);
             }
         }
 
@@ -5827,12 +5855,14 @@
                 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) {
+                PendingIntentRecord originatingPendingIntent,
+                boolean allowBackgroundActivityStart) {
             synchronized (mGlobalLock) {
                 return getActivityStartController().startActivityInPackage(uid, realCallingPid,
                         realCallingUid, callingPackage, intent, resolvedType, resultTo, resultWho,
                         requestCode, startFlags, options, userId, inTask, reason,
-                        validateIncomingUser, originatingPendingIntent);
+                        validateIncomingUser, originatingPendingIntent,
+                        allowBackgroundActivityStart);
             }
         }
 
@@ -6192,30 +6222,27 @@
                 }
                 return;
             }
-            mH.post(() -> {
-                synchronized (mGlobalLock) {
-                    final ActivityDisplay activityDisplay =
-                            mRootActivityContainer.getActivityDisplay(displayId);
-                    if (activityDisplay == null) {
-                        // Call might come when display is not yet added or has been removed.
-                        if (DEBUG_CONFIGURATION) {
-                            Slog.w(TAG, "Trying to update display configuration for non-existing "
-                                    + "displayId=" + displayId);
-                        }
-                        return;
+            synchronized (mGlobalLock) {
+                final ActivityDisplay activityDisplay =
+                        mRootActivityContainer.getActivityDisplay(displayId);
+                if (activityDisplay == null) {
+                    // Call might come when display is not yet added or has been removed.
+                    if (DEBUG_CONFIGURATION) {
+                        Slog.w(TAG, "Trying to update display configuration for non-existing "
+                                + "displayId=" + displayId);
                     }
-                    final WindowProcessController process = mPidMap.get(pid);
-                    if (process == null) {
-                        if (DEBUG_CONFIGURATION) {
-                            Slog.w(TAG, "Trying to update display configuration for invalid "
-                                    + "process, pid=" + pid);
-                        }
-                        return;
-                    }
-                    process.registerDisplayConfigurationListenerLocked(activityDisplay);
+                    return;
                 }
-            });
-
+                final WindowProcessController process = mPidMap.get(pid);
+                if (process == null) {
+                    if (DEBUG_CONFIGURATION) {
+                        Slog.w(TAG, "Trying to update display configuration for invalid "
+                                + "process, pid=" + pid);
+                    }
+                    return;
+                }
+                process.registerDisplayConfigurationListenerLocked(activityDisplay);
+            }
         }
 
         @Override
@@ -7007,5 +7034,12 @@
                 return mStackSupervisor.getActivityMetricsLogger().getLaunchObserverRegistry();
             }
         }
+
+        @Override
+        public ActivityManager.TaskSnapshot getTaskSnapshot(int taskId, boolean reducedResolution) {
+            synchronized (mGlobalLock) {
+                return ActivityTaskManagerService.this.getTaskSnapshot(taskId, reducedResolution);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 089640b..f3a363a 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -65,6 +65,8 @@
 import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
+import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE;
+import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -73,8 +75,6 @@
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
-import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE;
-import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION;
 
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
@@ -84,6 +84,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.ResourceId;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -173,6 +174,7 @@
     private int mLastUsedAppTransition = TRANSIT_UNSET;
     private String mLastOpeningApp;
     private String mLastClosingApp;
+    private String mLastChangingApp;
 
     private static final int NEXT_TRANSIT_TYPE_NONE = 0;
     private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1;
@@ -317,14 +319,16 @@
     private void setAppTransition(int transit, int flags) {
         mNextAppTransition = transit;
         mNextAppTransitionFlags |= flags;
-        setLastAppTransition(TRANSIT_UNSET, null, null);
+        setLastAppTransition(TRANSIT_UNSET, null, null, null);
         updateBooster();
     }
 
-    void setLastAppTransition(int transit, AppWindowToken openingApp, AppWindowToken closingApp) {
+    void setLastAppTransition(int transit, AppWindowToken openingApp, AppWindowToken closingApp,
+            AppWindowToken changingApp) {
         mLastUsedAppTransition = transit;
         mLastOpeningApp = "" + openingApp;
         mLastClosingApp = "" + closingApp;
+        mLastChangingApp = "" + changingApp;
     }
 
     boolean isReady() {
@@ -411,9 +415,7 @@
      * @return bit-map of WindowManagerPolicy#FINISH_LAYOUT_REDO_* to indicate whether another
      *         layout pass needs to be done
      */
-    int goodToGo(int transit, AppWindowToken topOpeningApp,
-            AppWindowToken topClosingApp, ArraySet<AppWindowToken> openingApps,
-            ArraySet<AppWindowToken> closingApps) {
+    int goodToGo(int transit, AppWindowToken topOpeningApp, ArraySet<AppWindowToken> openingApps) {
         mNextAppTransition = TRANSIT_UNSET;
         mNextAppTransitionFlags = 0;
         setAppTransitionState(APP_STATE_RUNNING);
@@ -421,8 +423,6 @@
                 ? topOpeningApp.getAnimation()
                 : null;
         int redoLayout = notifyAppTransitionStartingLocked(transit,
-                topOpeningApp != null ? topOpeningApp.token : null,
-                topClosingApp != null ? topClosingApp.token : null,
                 topOpeningAnim != null ? topOpeningAnim.getDurationHint() : 0,
                 topOpeningAnim != null
                         ? topOpeningAnim.getStatusBarTransitionsStartTime()
@@ -499,13 +499,12 @@
         }
     }
 
-    private int notifyAppTransitionStartingLocked(int transit, IBinder openToken,
-            IBinder closeToken, long duration, long statusBarAnimationStartTime,
-            long statusBarAnimationDuration) {
+    private int notifyAppTransitionStartingLocked(int transit, long duration,
+            long statusBarAnimationStartTime, long statusBarAnimationDuration) {
         int redoLayout = 0;
         for (int i = 0; i < mListeners.size(); i++) {
-            redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(transit, openToken,
-                    closeToken, duration, statusBarAnimationStartTime, statusBarAnimationDuration);
+            redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(transit, duration,
+                    statusBarAnimationStartTime, statusBarAnimationDuration);
         }
         return redoLayout;
     }
@@ -547,7 +546,7 @@
     }
 
     Animation loadAnimationAttr(LayoutParams lp, int animAttr, int transit) {
-        int resId = ResourceId.ID_NULL;
+        int resId = Resources.ID_NULL;
         Context context = mContext;
         if (animAttr >= 0) {
             AttributeCache.Entry ent = getCachedAnimations(lp);
@@ -2127,6 +2126,8 @@
                     pw.println(mLastOpeningApp);
             pw.print(prefix); pw.print("mLastClosingApp=");
                     pw.println(mLastClosingApp);
+            pw.print(prefix); pw.print("mLastChangingApp=");
+            pw.println(mLastChangingApp);
         }
     }
 
@@ -2225,14 +2226,16 @@
             if (dc == null) {
                 return;
             }
-            if (isTransitionSet() || !dc.mOpeningApps.isEmpty() || !dc.mClosingApps.isEmpty()) {
+            if (isTransitionSet() || !dc.mOpeningApps.isEmpty() || !dc.mClosingApps.isEmpty()
+                    || !dc.mChangingApps.isEmpty()) {
                 if (DEBUG_APP_TRANSITIONS) {
                     Slog.v(TAG_WM, "*** APP TRANSITION TIMEOUT."
                             + " displayId=" + dc.getDisplayId()
                             + " isTransitionSet()="
                             + dc.mAppTransition.isTransitionSet()
                             + " mOpeningApps.size()=" + dc.mOpeningApps.size()
-                            + " mClosingApps.size()=" + dc.mClosingApps.size());
+                            + " mClosingApps.size()=" + dc.mClosingApps.size()
+                            + " mChangingApps.size()=" + dc.mChangingApps.size());
                 }
                 setTimeout();
                 mService.mWindowPlacerLocked.performSurfacePlacement();
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index bf00ffb..49308b8 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -49,8 +49,8 @@
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 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.H.NOTIFY_APP_TRANSITION_STARTING;
 
+import android.os.SystemClock;
 import android.os.Trace;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -89,8 +89,9 @@
      * Handle application transition for given display.
      */
     void handleAppTransitionReady() {
-        final int appsCount = mDisplayContent.mOpeningApps.size();
-        if (!transitionGoodToGo(appsCount, mTempTransitionReasons)) {
+        mTempTransitionReasons.clear();
+        if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
+                || !transitionGoodToGo(mDisplayContent.mChangingApps, mTempTransitionReasons)) {
             return;
         }
         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
@@ -108,21 +109,25 @@
 
         mDisplayContent.mWallpaperMayChange = false;
 
-        int i;
-        for (i = 0; i < appsCount; i++) {
-            final AppWindowToken wtoken = mDisplayContent.mOpeningApps.valueAt(i);
+        int appCount = mDisplayContent.mOpeningApps.size();
+        for (int i = 0; i < appCount; ++i) {
             // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
             // window is removed, or window relayout to invisible. This also affects window
             // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
             // transition selection depends on wallpaper target visibility.
-            wtoken.clearAnimatingFlags();
+            mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
+        }
+        appCount = mDisplayContent.mChangingApps.size();
+        for (int i = 0; i < appCount; ++i) {
+            // Clearing for same reason as above.
+            mDisplayContent.mChangingApps.valueAtUnchecked(i).clearAnimatingFlags();
         }
 
         // Adjust wallpaper before we pull the lower/upper target, since pending changes
         // (like the clearAnimatingFlags() above) might affect wallpaper target result.
         // Or, the opening app window should be a wallpaper target.
         mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
-                mDisplayContent.mOpeningApps);
+                mDisplayContent.mOpeningApps, mDisplayContent.mChangingApps);
 
         // Determine if closing and opening app token sets are wallpaper targets, in which case
         // special animations are needed.
@@ -141,7 +146,7 @@
         // no need to do an animation. This is the case, for example, when this transition is being
         // done behind a dream window.
         final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
-                mDisplayContent.mClosingApps);
+                mDisplayContent.mClosingApps, mDisplayContent.mChangingApps);
         final boolean allowAnimations = mDisplayContent.getDisplayPolicy().allowAppAnimationsLw();
         final AppWindowToken animLpToken = allowAnimations
                 ? findAnimLayoutParamsToken(transit, activityTypes)
@@ -152,11 +157,15 @@
         final AppWindowToken topClosingApp = allowAnimations
                 ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
                 : null;
+        final AppWindowToken topChangingApp = allowAnimations
+                ? getTopApp(mDisplayContent.mChangingApps, false /* ignoreHidden */)
+                : null;
         final WindowManager.LayoutParams animLp = getAnimLp(animLpToken);
         overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes);
 
         final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
-                || containsVoiceInteraction(mDisplayContent.mOpeningApps);
+                || containsVoiceInteraction(mDisplayContent.mOpeningApps)
+                || containsVoiceInteraction(mDisplayContent.mChangingApps);
 
         final int layoutRedo;
         mService.mSurfaceAnimationRunner.deferStartingAnimations();
@@ -165,13 +174,14 @@
 
             handleClosingApps(transit, animLp, voiceInteraction);
             handleOpeningApps(transit, animLp, voiceInteraction);
+            handleChangingApps(transit, animLp, voiceInteraction);
 
             appTransition.setLastAppTransition(transit, topOpeningApp,
-                    topClosingApp);
+                    topClosingApp, topChangingApp);
 
             final int flags = appTransition.getTransitFlags();
             layoutRedo = appTransition.goodToGo(transit, topOpeningApp,
-                    topClosingApp, mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps);
+                    mDisplayContent.mOpeningApps);
             handleNonAppWindowsInTransition(transit, flags);
             appTransition.postAnimationCallback();
             appTransition.clear();
@@ -183,6 +193,7 @@
 
         mDisplayContent.mOpeningApps.clear();
         mDisplayContent.mClosingApps.clear();
+        mDisplayContent.mChangingApps.clear();
         mDisplayContent.mUnknownAppVisibilityController.clear();
 
         // This has changed the visibility of windows, so perform
@@ -191,8 +202,8 @@
 
         mDisplayContent.computeImeTarget(true /* updateImeTarget */);
 
-        mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING,
-                mTempTransitionReasons.clone()).sendToTarget();
+        mService.mAtmInternal.notifyAppTransitionStarting(mTempTransitionReasons.clone(),
+                SystemClock.uptimeMillis());
 
         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
 
@@ -237,29 +248,30 @@
         AppWindowToken result;
         final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
         final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
+        final ArraySet<AppWindowToken> changingApps = mDisplayContent.mChangingApps;
 
         // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
-        result = lookForHighestTokenWithFilter(closingApps, openingApps,
+        result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
                 w -> w.getRemoteAnimationDefinition() != null
                         && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
         if (result != null) {
             return result;
         }
-        result = lookForHighestTokenWithFilter(closingApps, openingApps,
+        result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
                 w -> w.fillsParent() && w.findMainWindow() != null);
         if (result != null) {
             return result;
         }
-        return lookForHighestTokenWithFilter(closingApps, openingApps,
+        return lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
                 w -> w.findMainWindow() != null);
     }
 
     /**
      * @return The set of {@link android.app.WindowConfiguration.ActivityType}s contained in the set
-     *         of apps in {@code array1} and {@code array2}.
+     *         of apps in {@code array1}, {@code array2}, and {@code array3}.
      */
     private static ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1,
-            ArraySet<AppWindowToken> array2) {
+            ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3) {
         final ArraySet<Integer> result = new ArraySet<>();
         for (int i = array1.size() - 1; i >= 0; i--) {
             result.add(array1.valueAt(i).getActivityType());
@@ -267,19 +279,26 @@
         for (int i = array2.size() - 1; i >= 0; i--) {
             result.add(array2.valueAt(i).getActivityType());
         }
+        for (int i = array3.size() - 1; i >= 0; i--) {
+            result.add(array3.valueAt(i).getActivityType());
+        }
         return result;
     }
 
     private static AppWindowToken lookForHighestTokenWithFilter(ArraySet<AppWindowToken> array1,
-            ArraySet<AppWindowToken> array2, Predicate<AppWindowToken> filter) {
-        final int array1count = array1.size();
-        final int count = array1count + array2.size();
+            ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3,
+            Predicate<AppWindowToken> filter) {
+        final int array2base = array1.size();
+        final int array3base = array2.size() + array2base;
+        final int count = array3base + array3.size();
         int bestPrefixOrderIndex = Integer.MIN_VALUE;
         AppWindowToken bestToken = null;
         for (int i = 0; i < count; i++) {
-            final AppWindowToken wtoken = i < array1count
+            final AppWindowToken wtoken = i < array2base
                     ? array1.valueAt(i)
-                    : array2.valueAt(i - array1count);
+                    : (i < array3base
+                            ? array2.valueAt(i - array2base)
+                            : array3.valueAt(i - array3base));
             final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
             if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
                 bestPrefixOrderIndex = prefixOrderIndex;
@@ -360,6 +379,24 @@
         }
     }
 
+    private void handleChangingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
+        final ArraySet<AppWindowToken> apps = mDisplayContent.mChangingApps;
+        final int appsCount = apps.size();
+        for (int i = 0; i < appsCount; i++) {
+            AppWindowToken wtoken = apps.valueAt(i);
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now changing app" + wtoken);
+            wtoken.cancelAnimationOnly();
+            wtoken.applyAnimationLocked(null, transit, true, false);
+            wtoken.updateReportedVisibilityLocked();
+            mService.openSurfaceTransaction();
+            try {
+                wtoken.showAllWindowsLocked();
+            } finally {
+                mService.closeSurfaceTransaction("handleChangingApps");
+            }
+        }
+    }
+
     private void handleNonAppWindowsInTransition(int transit, int flags) {
         if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
             if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
@@ -379,16 +416,15 @@
         }
     }
 
-    private boolean transitionGoodToGo(int appsCount, SparseIntArray outReasons) {
+    private boolean transitionGoodToGo(ArraySet<AppWindowToken> apps, SparseIntArray outReasons) {
         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                "Checking " + appsCount + " opening apps (frozen="
+                "Checking " + apps.size() + " opening apps (frozen="
                         + mService.mDisplayFrozen + " timeout="
                         + mDisplayContent.mAppTransition.isTimeout() + ")...");
         final ScreenRotationAnimation screenRotationAnimation =
                 mService.mAnimator.getScreenRotationAnimationLocked(
                         Display.DEFAULT_DISPLAY);
 
-        outReasons.clear();
         if (!mDisplayContent.mAppTransition.isTimeout()) {
             // Imagine the case where we are changing orientation due to an app transition, but a
             // previous orientation change is still in progress. We won't process the orientation
@@ -404,8 +440,8 @@
                 }
                 return false;
             }
-            for (int i = 0; i < appsCount; i++) {
-                AppWindowToken wtoken = mDisplayContent.mOpeningApps.valueAt(i);
+            for (int i = 0; i < apps.size(); i++) {
+                AppWindowToken wtoken = apps.valueAt(i);
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                         "Check opening app=" + wtoken + ": allDrawn="
                                 + wtoken.allDrawn + " startingDisplayed="
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index bb38f30..29645f6 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -50,9 +50,23 @@
     private final SurfaceAnimator mSurfaceAnimator;
     private final int mWidth;
     private final int mHeight;
+    private final boolean mRelative;
 
     AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader) {
+        this(t, appToken, thumbnailHeader, false /* relative */);
+    }
+
+    /**
+     * @param t Transaction to create the thumbnail in.
+     * @param appToken {@link AppWindowToken} to associate this thumbnail with.
+     * @param thumbnailHeader A thumbnail or placeholder for thumbnail to initialize with.
+     * @param relative Whether this thumbnail will be a child of appToken (and thus positioned
+     *                 relative to it) or not.
+     */
+    AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader,
+            boolean relative) {
         mAppToken = appToken;
+        mRelative = relative;
         mSurfaceAnimator =
                 new SurfaceAnimator(this, this::onAnimationFinished, appToken.mWmService);
         mWidth = thumbnailHeader.getWidth();
@@ -86,6 +100,9 @@
         // We parent the thumbnail to the task, and just place it on top of anything else in the
         // task.
         t.setLayer(mSurfaceControl, Integer.MAX_VALUE);
+        if (relative) {
+            t.reparent(mSurfaceControl, appToken.getSurfaceControl());
+        }
     }
 
     void startAnimation(Transaction t, Animation anim) {
@@ -101,6 +118,13 @@
                 mAppToken.mWmService.mSurfaceAnimationRunner), false /* hidden */);
     }
 
+    /**
+     * Start animation with existing adapter.
+     */
+    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
+        mSurfaceAnimator.startAnimation(t, anim, hidden);
+    }
+
     private void onAnimationFinished() {
     }
 
@@ -147,6 +171,9 @@
     @Override
     public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
         t.setLayer(leash, Integer.MAX_VALUE);
+        if (mRelative) {
+            t.reparent(leash, mAppToken.getSurfaceControl());
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index d8b2b52..65b36a0 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 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_UNDEFINED;
@@ -25,7 +26,6 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
@@ -34,6 +34,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
+import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
 import static android.view.WindowManager.TRANSIT_UNSET;
 import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
 
@@ -82,6 +83,7 @@
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 
 import android.annotation.CallSuper;
+import android.annotation.Size;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.content.ComponentName;
@@ -97,6 +99,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.DisplayInfo;
@@ -113,11 +116,15 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.AttributeCache;
+import com.android.server.LocalServices;
+import com.android.server.display.ColorDisplayService;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.policy.WindowManagerPolicy.StartingSurface;
+import com.android.server.wm.RemoteAnimationController.RemoteAnimationRecord;
 import com.android.server.wm.WindowManagerService.H;
 
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.function.Consumer;
@@ -258,7 +265,18 @@
     /** Whether our surface was set to be showing in the last call to {@link #prepareSurfaces} */
     private boolean mLastSurfaceShowing = true;
 
+    /**
+     * This gets used during some open/close transitions as well as during a change transition
+     * where it represents the starting-state snapshot.
+     */
     private AppWindowThumbnail mThumbnail;
+    private final Rect mTransitStartRect = new Rect();
+
+    /**
+     * This leash is used to "freeze" the app surface in place after the state change, but before
+     * the animation is ready to start.
+     */
+    private SurfaceControl mTransitChangeLeash = null;
 
     /** Have we been asked to have this token keep the screen frozen? */
     private boolean mFreezingScreen;
@@ -269,6 +287,7 @@
 
     private final Point mTmpPoint = new Point();
     private final Rect mTmpRect = new Rect();
+    private final Rect mTmpPrevBounds = new Rect();
     private RemoteAnimationDefinition mRemoteAnimationDefinition;
     private AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry;
 
@@ -289,6 +308,20 @@
     private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
     private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
 
+    private AppSaturationInfo mLastAppSaturationInfo;
+
+    private final ColorDisplayService.ColorTransformController mColorTransformController =
+            (matrix, translation) -> mWmService.mH.post(() -> {
+                synchronized (mWmService.mGlobalLock) {
+                    if (mLastAppSaturationInfo == null) {
+                        mLastAppSaturationInfo = new AppSaturationInfo();
+                    }
+
+                    mLastAppSaturationInfo.setSaturation(matrix, translation);
+                    updateColorTransform();
+                }
+            });
+
     AppWindowToken(WindowManagerService service, IApplicationToken token,
             ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc,
             long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers,
@@ -311,6 +344,11 @@
         // Application tokens start out hidden.
         setHidden(true);
         hiddenRequested = true;
+
+        ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService(
+                ColorDisplayService.ColorDisplayServiceInternal.class);
+        cds.attachColorTransformController(activityRecord.packageName, activityRecord.mUserId,
+                new WeakReference<>(mColorTransformController));
     }
 
     AppWindowToken(WindowManagerService service, IApplicationToken token,
@@ -568,9 +606,7 @@
                     delayed = runningAppAnimation = true;
                 }
                 final WindowState window = findMainWindow();
-                //TODO (multidisplay): Magnification is supported only for the default display.
-                if (window != null && accessibilityController != null
-                        && getDisplayContent().getDisplayId() == DEFAULT_DISPLAY) {
+                if (window != null && accessibilityController != null) {
                     accessibilityController.onAppWindowTransitionLocked(window, transit);
                 }
                 changed = true;
@@ -790,6 +826,7 @@
         boolean delayed = commitVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction);
 
         getDisplayContent().mOpeningApps.remove(this);
+        getDisplayContent().mChangingApps.remove(this);
         getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
         mWmService.mTaskSnapshotController.onAppRemoved(this);
         waitingToShow = false;
@@ -968,6 +1005,8 @@
                 : null;
 
         mLastParent = task;
+
+        updateColorTransform();
     }
 
     void postWindowRemoveStartingWindowCleanup(WindowState win) {
@@ -1506,6 +1545,7 @@
     @Override
     public void onConfigurationChanged(Configuration newParentConfig) {
         final int prevWinMode = getWindowingMode();
+        mTmpPrevBounds.set(getBounds());
         super.onConfigurationChanged(newParentConfig);
         final int winMode = getWindowingMode();
 
@@ -1537,9 +1577,68 @@
                 mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(this,
                         stackBounds);
             }
+        } else if (shouldStartChangeTransition(prevWinMode, winMode)) {
+            initializeChangeTransition(mTmpPrevBounds);
         }
     }
 
+    private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
+        if (!isVisible() || getDisplayContent().mAppTransition.isTransitionSet()) {
+            return false;
+        }
+        // Only do an animation into and out-of freeform mode for now. Other mode
+        // transition animations are currently handled by system-ui.
+        return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM);
+    }
+
+    /**
+     * Initializes a change transition. Because the app is visible already, there is a small period
+     * of time where the user can see the app content/window update before the transition starts.
+     * To prevent this, we immediately take a snapshot and place the app/snapshot into a leash which
+     * "freezes" the location/crop until the transition starts.
+     * <p>
+     * Here's a walk-through of the process:
+     * 1. Create a temporary leash ("interim-change-leash") and reparent the app to it.
+     * 2. Set the temporary leash's position/crop to the current state.
+     * 3. Create a snapshot and place that at the top of the leash to cover up content changes.
+     * 4. Once the transition is ready, it will reparent the app to the animation leash.
+     * 5. Detach the interim-change-leash.
+     */
+    private void initializeChangeTransition(Rect startBounds) {
+        mDisplayContent.prepareAppTransition(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
+                false /* alwaysKeepCurrent */, 0, false /* forceOverride */);
+        mDisplayContent.mChangingApps.add(this);
+        mTransitStartRect.set(startBounds);
+
+        final SurfaceControl.Builder builder = makeAnimationLeash()
+                .setParent(getAnimationLeashParent())
+                .setName(getSurfaceControl() + " - interim-change-leash");
+        mTransitChangeLeash = builder.build();
+        Transaction t = getPendingTransaction();
+        t.setWindowCrop(mTransitChangeLeash, startBounds.width(), startBounds.height());
+        t.setPosition(mTransitChangeLeash, startBounds.left, startBounds.top);
+        t.show(mTransitChangeLeash);
+        t.reparent(getSurfaceControl(), mTransitChangeLeash);
+        onAnimationLeashCreated(t, mTransitChangeLeash);
+
+        if (mThumbnail == null && getTask() != null) {
+            final TaskSnapshotController snapshotCtrl = mWmService.mTaskSnapshotController;
+            final ArraySet<Task> tasks = new ArraySet<>();
+            tasks.add(getTask());
+            snapshotCtrl.snapshotTasks(tasks);
+            snapshotCtrl.addSkipClosingAppSnapshotTasks(tasks);
+            final ActivityManager.TaskSnapshot snapshot = snapshotCtrl.getSnapshot(
+                    getTask().mTaskId, getTask().mUserId, false /* restoreFromDisk */,
+                    false /* reducedResolution */);
+            mThumbnail = new AppWindowThumbnail(t, this, snapshot.getSnapshot(),
+                    true /* relative */);
+        }
+    }
+
+    boolean isInChangeTransition() {
+        return mTransitChangeLeash != null || isChangeTransition(mTransit);
+    }
+
     @Override
     void checkAppWindowsReadyToShow() {
         if (allDrawn == mLastAllDrawn) {
@@ -1714,7 +1813,8 @@
             if (mLetterbox == null) {
                 mLetterbox = new Letterbox(() -> makeChildSurface(null));
             }
-            mLetterbox.layout(getParent().getBounds(), w.getFrameLw());
+            getPosition(mTmpPoint);
+            mLetterbox.layout(getParent().getBounds(), w.getFrameLw(), mTmpPoint);
         } else if (mLetterbox != null) {
             mLetterbox.hide();
         }
@@ -1949,6 +2049,11 @@
         } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
             return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
         } else if (taskSwitch && allowTaskSnapshot) {
+            if (mWmService.mLowRamTaskSnapshotsAndRecents) {
+                // For low RAM devices, we use the splash screen starting window instead of the
+                // task snapshot starting window.
+                return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
+            }
             return snapshot == null ? STARTING_WINDOW_TYPE_NONE
                     : snapshotOrientationSameAsTask(snapshot) || fromRecents
                             ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
@@ -2214,6 +2319,15 @@
         return getBounds();
     }
 
+    private static boolean isChangeTransition(int transit) {
+        return transit == TRANSIT_TASK_CHANGE_WINDOWING_MODE;
+    }
+
+    private int getDefaultChangeTransitionDuration() {
+        return (int) (AppTransition.DEFAULT_APP_TRANSITION_DURATION
+                        * mWmService.getTransitionAnimationScaleLocked());
+    }
+
     boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
             boolean isVoiceInteraction) {
 
@@ -2232,13 +2346,35 @@
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AWT#applyAnimationLocked");
         if (okToAnimate()) {
             final AnimationAdapter adapter;
+            AnimationAdapter thumbnailAdapter = null;
             getAnimationBounds(mTmpPoint, mTmpRect);
 
+            boolean isChanging = isChangeTransition(transit) && mThumbnail != null;
+
             // Delaying animation start isn't compatible with remote animations at all.
             if (getDisplayContent().mAppTransition.getRemoteAnimationController() != null
                     && !mSurfaceAnimator.isAnimationStartDelayed()) {
-                adapter = getDisplayContent().mAppTransition.getRemoteAnimationController()
-                        .createAnimationAdapter(this, mTmpPoint, mTmpRect);
+                RemoteAnimationRecord adapters =
+                        getDisplayContent().mAppTransition.getRemoteAnimationController()
+                                .createRemoteAnimationRecord(this, mTmpPoint, mTmpRect,
+                                        (isChanging ? mTransitStartRect : null));
+                adapter = adapters.mAdapter;
+                thumbnailAdapter = adapters.mThumbnailAdapter;
+            } else if (isChanging) {
+                int duration = getDefaultChangeTransitionDuration();
+                mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y);
+                adapter = new LocalAnimationAdapter(
+                        new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect,
+                                getDisplayContent().getDisplayInfo(), duration,
+                                true /* isAppAnimation */, false /* isThumbnail */),
+                        mWmService.mSurfaceAnimationRunner);
+                thumbnailAdapter = new LocalAnimationAdapter(
+                        new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect,
+                                getDisplayContent().getDisplayInfo(), duration,
+                                true /* isAppAnimation */, true /* isThumbnail */),
+                        mWmService.mSurfaceAnimationRunner);
+                mTransit = transit;
+                mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
             } else {
                 final int appStackClipMode =
                         getDisplayContent().mAppTransition.getAppStackClipMode();
@@ -2266,6 +2402,10 @@
                 if (adapter.getShowWallpaper()) {
                     mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                 }
+                if (thumbnailAdapter != null) {
+                    mThumbnail.startAnimation(
+                            getPendingTransaction(), thumbnailAdapter, !isVisible());
+                }
             }
         } else {
             cancelAnimation();
@@ -2350,7 +2490,7 @@
     public void onAnimationLeashDestroyed(Transaction t) {
         super.onAnimationLeashDestroyed(t);
         if (mAnimationBoundsLayer != null) {
-            t.destroy(mAnimationBoundsLayer);
+            t.reparent(mAnimationBoundsLayer, null);
             mAnimationBoundsLayer = null;
         }
 
@@ -2376,7 +2516,7 @@
     @Override
     protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
         if (!mSurfaceAnimator.hasLeash()) {
-            t.reparent(mSurfaceControl, newParent.getHandle());
+            t.reparent(mSurfaceControl, newParent);
         }
     }
 
@@ -2401,6 +2541,17 @@
 
         final DisplayContent dc = getDisplayContent();
         dc.assignStackOrdering();
+
+        if (leash == mTransitChangeLeash) {
+            // This is a temporary state so skip any animation notifications
+            return;
+        } else if (mTransitChangeLeash != null) {
+            // unparent mTransitChangeLeash for clean-up
+            t.hide(mTransitChangeLeash);
+            t.reparent(mTransitChangeLeash, null);
+            mTransitChangeLeash = null;
+        }
+
         if (mAnimatingAppWindowTokenRegistry != null) {
             mAnimatingAppWindowTokenRegistry.notifyStarting(this);
         }
@@ -2422,7 +2573,7 @@
             t.setWindowCrop(mAnimationBoundsLayer, mTmpRect);
 
             // Reparent leash to animation bounds layer.
-            t.reparent(leash, mAnimationBoundsLayer.getHandle());
+            t.reparent(leash, mAnimationBoundsLayer);
         }
     }
 
@@ -2459,6 +2610,12 @@
                 + " okToAnimate=" + okToAnimate()
                 + " startingDisplayed=" + startingDisplayed);
 
+        // clean up thumbnail window
+        if (mThumbnail != null) {
+            mThumbnail.destroy();
+            mThumbnail = null;
+        }
+
         // WindowState.onExitAnimationDone might modify the children list, so make a copy and then
         // traverse the copy.
         final ArrayList<WindowState> children = new ArrayList<>(mChildren);
@@ -2490,14 +2647,30 @@
 
     @Override
     void cancelAnimation() {
-        super.cancelAnimation();
+        cancelAnimationOnly();
         clearThumbnail();
+        if (mTransitChangeLeash != null) {
+            getPendingTransaction().hide(mTransitChangeLeash);
+            getPendingTransaction().reparent(mTransitChangeLeash, null);
+            mTransitChangeLeash = null;
+        }
+    }
+
+    /**
+     * This only cancels the animation. It doesn't do other teardown like cleaning-up thumbnail
+     * or interim leashes.
+     * <p>
+     * Used when canceling in preparation for starting a new animation.
+     */
+    void cancelAnimationOnly() {
+        super.cancelAnimation();
     }
 
     boolean isWaitingForTransitionStart() {
         return getDisplayContent().mAppTransition.isTransitionSet()
                 && (getDisplayContent().mOpeningApps.contains(this)
-                    || getDisplayContent().mClosingApps.contains(this));
+                    || getDisplayContent().mClosingApps.contains(this)
+                    || getDisplayContent().mChangingApps.contains(this));
     }
 
     public int getTransit() {
@@ -2807,7 +2980,26 @@
     void removeFromPendingTransition() {
         if (isWaitingForTransitionStart() && mDisplayContent != null) {
             mDisplayContent.mOpeningApps.remove(this);
+            mDisplayContent.mChangingApps.remove(this);
             mDisplayContent.mClosingApps.remove(this);
         }
     }
+
+    private void updateColorTransform() {
+        if (mSurfaceControl != null && mLastAppSaturationInfo != null) {
+            mPendingTransaction.setColorTransform(mSurfaceControl, mLastAppSaturationInfo.mMatrix,
+                    mLastAppSaturationInfo.mTranslation);
+            mWmService.scheduleAnimationLocked();
+        }
+    }
+
+    private static class AppSaturationInfo {
+        float[] mMatrix = new float[9];
+        float[] mTranslation = new float[3];
+
+        void setSaturation(@Size(9) float[] matrix, @Size(3) float[] translation) {
+            System.arraycopy(matrix, 0, mMatrix, 0, mMatrix.length);
+            System.arraycopy(translation, 0, mTranslation, 0, mTranslation.length);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index 5b20af3..9bc8462 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -62,7 +62,8 @@
     private StatusBarManagerInternal mStatusBarInternal;
 
     protected WindowState mWin;
-    private int mState = StatusBarManager.WINDOW_STATE_SHOWING;
+    private @StatusBarManager.WindowVisibleState int mState =
+            StatusBarManager.WINDOW_STATE_SHOWING;
     private int mTransientBarState;
     private boolean mPendingShow;
     private long mLastTranslucent;
@@ -199,7 +200,8 @@
         return !mWin.isDrawnLw();
     }
 
-    private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
+    private @StatusBarManager.WindowVisibleState int computeStateLw(
+            boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
         if (win.isDrawnLw()) {
             final boolean vis = win.isVisibleLw();
             final boolean anim = win.isAnimatingLw();
@@ -218,7 +220,7 @@
         return mState;
     }
 
-    private boolean updateStateLw(final int state) {
+    private boolean updateStateLw(@StatusBarManager.WindowVisibleState final int state) {
         if (mWin != null && state != mState) {
             mState = state;
             if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state));
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index ded45c9..650d0be 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -37,6 +37,7 @@
 import android.annotation.CallSuper;
 import android.app.WindowConfiguration;
 import android.content.res.Configuration;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.proto.ProtoOutputStream;
 
@@ -243,6 +244,14 @@
     }
 
     /**
+     * Sets {@code out} to the top-left corner of the bounds as returned by {@link #getBounds()}.
+     */
+    public void getPosition(Point out) {
+        Rect bounds = getBounds();
+        out.set(bounds.left, bounds.top);
+    }
+
+    /**
      * Returns the bounds requested on this container. These may not be the actual bounds the
      * container ends up with due to policy constraints. The {@link Rect} handed back is
      * shared for all calls to this method and should not be modified.
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index aea071f..c39060e 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -129,7 +129,7 @@
             final DimAnimatable dimAnimatable = new DimAnimatable(dimLayer);
             mSurfaceAnimator = new SurfaceAnimator(dimAnimatable, () -> {
                 if (!mDimming) {
-                    dimAnimatable.getPendingTransaction().destroy(mDimLayer);
+                    dimAnimatable.getPendingTransaction().reparent(mDimLayer, null);
                 }
             }, mHost.mWmService);
         }
@@ -300,7 +300,7 @@
 
         if (!mDimState.mDimming) {
             if (!mDimState.mAnimateExit) {
-                t.destroy(mDimState.mDimLayer);
+                t.reparent(mDimState.mDimLayer, null);
             } else {
                 startDimExit(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t);
             }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a5ceee2..8f976e7 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -30,11 +30,14 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.FLAG_PRIVATE;
 import static android.view.InsetsState.TYPE_IME;
+import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
+import static android.view.InsetsState.TYPE_TOP_BAR;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_180;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 import static android.view.View.GONE;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
 import static android.view.WindowManager.DOCKED_BOTTOM;
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.DOCKED_TOP;
@@ -164,6 +167,7 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.SurfaceSession;
 import android.view.View;
+import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
 
@@ -246,6 +250,7 @@
 
     final ArraySet<AppWindowToken> mOpeningApps = new ArraySet<>();
     final ArraySet<AppWindowToken> mClosingApps = new ArraySet<>();
+    final ArraySet<AppWindowToken> mChangingApps = new ArraySet<>();
     final UnknownAppVisibilityController mUnknownAppVisibilityController;
     BoundsAnimationController mBoundsAnimationController;
 
@@ -328,14 +333,6 @@
     private int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
 
     /**
-     * Flag indicating that the application is receiving an orientation that has different metrics
-     * than it expected. E.g. Portrait instead of Landscape.
-     *
-     * @see #updateRotationUnchecked()
-     */
-    private boolean mAltOrientation = false;
-
-    /**
      * Orientation forced by some window. If there is no visible window that specifies orientation
      * it is set to {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}.
      *
@@ -1059,6 +1056,11 @@
      */
     void setInsetProvider(@InternalInsetType int type, WindowState win,
             @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider) {
+        if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL) {
+            if (type == TYPE_TOP_BAR || type == TYPE_NAVIGATION_BAR) {
+                return;
+            }
+        }
         mInsetsStateController.getSourceProvider(type).setWindow(win, frameProvider);
     }
 
@@ -1085,10 +1087,6 @@
         return mLastOrientation;
     }
 
-    boolean getAltOrientation() {
-        return mAltOrientation;
-    }
-
     int getLastWindowForcedOrientation() {
         return mLastWindowForcedOrientation;
     }
@@ -1130,15 +1128,9 @@
     boolean rotationNeedsUpdate() {
         final int lastOrientation = getLastOrientation();
         final int oldRotation = getRotation();
-        final boolean oldAltOrientation = getAltOrientation();
 
         final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation);
-        final boolean altOrientation = !mDisplayRotation.rotationHasCompatibleMetrics(
-                lastOrientation, rotation);
-        if (oldRotation == rotation && oldAltOrientation == altOrientation) {
-            return false;
-        }
-        return true;
+        return oldRotation != rotation;
     }
 
     /**
@@ -1160,12 +1152,14 @@
     @Override
     boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
             ConfigurationContainer requestingContainer) {
+        final int previousRotation = mRotation;
         final Configuration config = updateOrientationFromAppTokens(
                 getRequestedOverrideConfiguration(), freezeDisplayToken, false);
-        // If display rotation class tells us that it doesn't consider app requested orientation,
-        // this display won't rotate just because of an app changes its requested orientation. Thus
-        // it indicates that this display chooses not to handle this request.
-        final boolean handled = getDisplayRotation().respectAppRequestedOrientation();
+        // This event is considered handled iff a configuration propagation is triggered, because
+        // that's the only place lower level containers check if they need to do something to this
+        // request. The only guaranteed signal is that the display is rotated to a different
+        // orientation (i.e. rotating 180 degrees doesn't count).
+        final boolean handled = (mRotation - previousRotation) % 2 != 0;
         if (config == null) {
             return handled;
         }
@@ -1334,7 +1328,6 @@
 
         final int oldRotation = mRotation;
         final int lastOrientation = mLastOrientation;
-        final boolean oldAltOrientation = mAltOrientation;
         final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation);
         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Computed rotation=" + rotation + " for display id="
                 + mDisplayId + " based on lastOrientation=" + lastOrientation
@@ -1366,35 +1359,26 @@
         }
         final boolean rotateSeamlessly = mayRotateSeamlessly;
 
-        // TODO: Implement forced rotation changes.
-        //       Set mAltOrientation to indicate that the application is receiving
-        //       an orientation that has different metrics than it expected.
-        //       eg. Portrait instead of Landscape.
-
-        final boolean altOrientation = !mDisplayRotation.rotationHasCompatibleMetrics(
-                lastOrientation, rotation);
-
         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
                 + " selected orientation " + lastOrientation
                 + ", got rotation " + rotation + " which has "
-                + (altOrientation ? "incompatible" : "compatible") + " metrics");
+                + " metrics");
 
-        if (oldRotation == rotation && oldAltOrientation == altOrientation) {
+        if (oldRotation == rotation) {
             // No change.
             return false;
         }
 
         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
                 + " rotation changed to " + rotation
-                + (altOrientation ? " (alt)" : "") + " from " + oldRotation
-                + (oldAltOrientation ? " (alt)" : "") + ", lastOrientation=" + lastOrientation);
+                + " from " + oldRotation
+                + ", lastOrientation=" + lastOrientation);
 
         if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
             mWaitingForConfig = true;
         }
 
         mRotation = rotation;
-        mAltOrientation = altOrientation;
 
         mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
         mWmService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
@@ -1483,11 +1467,9 @@
             }
         }
 
-        // TODO (multi-display): Magnification is supported only for the default display.
         // Announce rotation only if we will not animate as we already have the
         // windows in final state. Otherwise, we make this call at the rotation end.
-        if (screenRotationAnimation == null && mWmService.mAccessibilityController != null
-                && isDefaultDisplay) {
+        if (screenRotationAnimation == null && mWmService.mAccessibilityController != null) {
             mWmService.mAccessibilityController.onRotationChangedLocked(this);
         }
     }
@@ -1536,26 +1518,8 @@
     private DisplayInfo updateDisplayAndOrientation(int uiMode) {
         // Use the effective "visual" dimensions based on current rotation
         final boolean rotated = (mRotation == ROTATION_90 || mRotation == ROTATION_270);
-        final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
-        final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
-        int dw = realdw;
-        int dh = realdh;
-
-        if (mAltOrientation) {
-            if (realdw > realdh) {
-                // Turn landscape into portrait.
-                int maxw = (int)(realdh/1.3f);
-                if (maxw < realdw) {
-                    dw = maxw;
-                }
-            } else {
-                // Turn portrait into landscape.
-                int maxh = (int)(realdw/1.3f);
-                if (maxh < realdh) {
-                    dh = maxh;
-                }
-            }
-        }
+        final int dw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
+        final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
 
         // Update application display metrics.
         final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(mRotation);
@@ -2307,13 +2271,12 @@
         out.set(mDisplayFrames.mStable);
     }
 
-    TaskStack createStack(int stackId, boolean onTop, StackWindowController controller) {
-        if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId="
-                + mDisplayId);
+    void setStackOnDisplay(int stackId, boolean onTop, TaskStack stack) {
+        if (DEBUG_STACK) {
+            Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId=" + mDisplayId);
+        }
 
-        final TaskStack stack = new TaskStack(mWmService, stackId, controller);
         mTaskStackContainers.addStackToDisplay(stack, onTop);
-        return stack;
     }
 
     void moveStackToDisplay(TaskStack stack, boolean onTop) {
@@ -2492,6 +2455,7 @@
             // Clear all transitions & screen frozen states when removing display.
             mOpeningApps.clear();
             mClosingApps.clear();
+            mChangingApps.clear();
             mUnknownAppVisibilityController.clear();
             mAppTransition.removeAppTransitionTimeoutCallbacks();
             handleAnimatingStoppedAndTransition();
@@ -2506,6 +2470,7 @@
             mWmService.mAnimator.removeDisplayLocked(mDisplayId);
             mWindowingLayer.release();
             mOverlayLayer.release();
+            mInputMonitor.onDisplayRemoved();
         } finally {
             mDisplayReady = false;
             mRemovingDisplay = false;
@@ -3321,7 +3286,7 @@
             }
         }
 
-        if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty()) {
+        if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty() || !mChangingApps.isEmpty()) {
             pw.println();
             if (mOpeningApps.size() > 0) {
                 pw.print("  mOpeningApps="); pw.println(mOpeningApps);
@@ -3329,6 +3294,9 @@
             if (mClosingApps.size() > 0) {
                 pw.print("  mClosingApps="); pw.println(mClosingApps);
             }
+            if (mChangingApps.size() > 0) {
+                pw.print("  mChangingApps="); pw.println(mChangingApps);
+            }
         }
 
         mUnknownAppVisibilityController.dump(pw, "  ");
@@ -3655,6 +3623,12 @@
         }
     }
 
+    /** @returns the orientation of the display when it's rotation is ROTATION_0. */
+    int getNaturalOrientation() {
+        return mBaseDisplayWidth < mBaseDisplayHeight
+                ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+    }
+
     void performLayout(boolean initial, boolean updateInputWindows) {
         if (!isLayoutNeeded()) {
             return;
@@ -4008,7 +3982,6 @@
 
         /**
          * Adds the stack to this container.
-         * @see DisplayContent#createStack(int, boolean, StackWindowController)
          */
         void addStackToDisplay(TaskStack stack, boolean onTop) {
             addStackReferenceIfNeeded(stack);
@@ -4620,7 +4593,7 @@
      * Reparents the given surface to mOverlayLayer.
      */
     void reparentToOverlay(Transaction transaction, SurfaceControl surface) {
-        transaction.reparent(surface, mOverlayLayer.getHandle());
+        transaction.reparent(surface, mOverlayLayer);
     }
 
     void applyMagnificationSpec(MagnificationSpec spec) {
@@ -4863,11 +4836,11 @@
      * Re-parent the DisplayContent's top surfaces, {@link #mWindowingLayer} and
      * {@link #mOverlayLayer} to the specified surfaceControl.
      *
-     * @param surfaceControlHandle The handle for the new SurfaceControl, where the DisplayContent's
+     * @param surfaceControlHandle The new SurfaceControl, where the DisplayContent's
      *                             surfaces will be re-parented to.
      */
-    void reparentDisplayContent(IBinder surfaceControlHandle) {
-        mPendingTransaction.reparent(mWindowingLayer, surfaceControlHandle)
-                .reparent(mOverlayLayer, surfaceControlHandle);
+    void reparentDisplayContent(SurfaceControl sc) {
+        mPendingTransaction.reparent(mWindowingLayer, sc)
+                .reparent(mOverlayLayer, sc);
     }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index bcc7be4..bc165dc 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -329,15 +329,6 @@
         return mFixedToUserRotation;
     }
 
-    /**
-     * Returns {@code true} if this display rotation takes app requested orientation into
-     * consideration; {@code false} otherwise. For the time being the only case where this is {@code
-     * false} is when {@link #isFixedToUserRotation()} is {@code true}.
-     */
-    boolean respectAppRequestedOrientation() {
-        return !mFixedToUserRotation;
-    }
-
     public int getLandscapeRotation() {
         return mLandscapeRotation;
     }
@@ -685,36 +676,6 @@
         return rotation == mPortraitRotation || rotation == mUpsideDownRotation;
     }
 
-    /**
-     * Given an orientation constant and a rotation, returns true if the rotation
-     * has compatible metrics to the requested orientation.  For example, if
-     * the application requested landscape and got seascape, then the rotation
-     * has compatible metrics; if the application requested portrait and got landscape,
-     * then the rotation has incompatible metrics; if the application did not specify
-     * a preference, then anything goes.
-     *
-     * @param orientation An orientation constant, such as
-     * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
-     * @param rotation The rotation to check.
-     * @return True if the rotation is compatible with the requested orientation.
-     */
-    boolean rotationHasCompatibleMetrics(int orientation, int rotation) {
-        switch (orientation) {
-            case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
-            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
-            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
-                return isAnyPortrait(rotation);
-
-            case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
-            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
-            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
-                return isLandscapeOrSeascape(rotation);
-
-            default:
-                return true;
-        }
-    }
-
     private boolean isValidRotationChoice(final int preferredRotation) {
         // Determine if the given app orientation is compatible with the provided rotation choice.
         switch (mCurrentAppOrientation) {
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 7ea88bb..ea65dd9 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -36,7 +36,6 @@
 import static com.android.server.wm.DockedStackDividerControllerProto.MINIMIZED_DOCK;
 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.H.NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED;
 import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
 
 import android.content.Context;
@@ -566,9 +565,7 @@
             mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
             animDuration = (long) (mAnimationDuration * mMaximizeMeetFraction);
         }
-        mService.mH.removeMessages(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED);
-        mService.mH.obtainMessage(NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED,
-                minimizedDock ? 1 : 0, 0).sendToTarget();
+        mService.mAtmInternal.notifyDockedStackMinimizedChanged(minimizedDock);
         final int size = mDockedStackListeners.beginBroadcast();
         for (int i = 0; i < size; ++i) {
             final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 607ee76..3f77e1c 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -120,6 +120,8 @@
     // A surface used to catch input events for the drag-and-drop operation.
     SurfaceControl mInputSurface;
 
+    private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+
     private final Rect mTmpClipRect = new Rect();
 
     /**
@@ -127,6 +129,7 @@
      * {@code true} when {@link #closeLocked()} is called.
      */
     private boolean mIsClosing;
+    IBinder mTransferTouchFromToken;
 
     DragState(WindowManagerService service, DragDropController controller, IBinder token,
             SurfaceControl surface, int flags, IBinder localWin) {
@@ -177,6 +180,8 @@
 
         mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
         t.setWindowCrop(mInputSurface, mTmpClipRect);
+        t.transferTouchFocus(mTransferTouchFromToken, h.token);
+        mTransferTouchFromToken = null;
     }
 
     /**
@@ -237,7 +242,7 @@
 
         // Clear the internal variables.
         if (mSurfaceControl != null) {
-            mSurfaceControl.destroy();
+            mTransaction.reparent(mSurfaceControl, null).apply();
             mSurfaceControl = null;
         }
         if (mAnimator != null && !mAnimationCompleted) {
@@ -497,18 +502,13 @@
         mCurrentY = y;
 
         // Move the surface to the given touch
-        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
-                TAG_WM, ">>> OPEN TRANSACTION notifyMoveLocked");
-        mService.openSurfaceTransaction();
-        try {
-            mSurfaceControl.setPosition(x - mThumbOffsetX, y - mThumbOffsetY);
-            if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  DRAG "
-                    + mSurfaceControl + ": pos=(" +
-                    (int)(x - mThumbOffsetX) + "," + (int)(y - mThumbOffsetY) + ")");
-        } finally {
-            mService.closeSurfaceTransaction("notifyMoveLw");
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
-                    TAG_WM, "<<< CLOSE TRANSACTION notifyMoveLocked");
+        if (SHOW_LIGHT_TRANSACTIONS) {
+            Slog.i(TAG_WM, ">>> OPEN TRANSACTION notifyMoveLocked");
+        }
+        mTransaction.setPosition(mSurfaceControl, x - mThumbOffsetX, y - mThumbOffsetY).apply();
+        if (SHOW_TRANSACTIONS) {
+            Slog.i(TAG_WM, "  DRAG " + mSurfaceControl + ": pos=(" + (int) (x - mThumbOffsetX) + ","
+                    + (int) (y - mThumbOffsetY) + ")");
         }
         notifyLocationLocked(x, y);
     }
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 639ed02..f9c9d33 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -1,5 +1,6 @@
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
@@ -9,7 +10,6 @@
 import android.os.Debug;
 import android.os.IBinder;
 import android.util.Slog;
-import android.view.InputApplicationHandle;
 import android.view.KeyEvent;
 import android.view.WindowManager;
 
@@ -204,6 +204,37 @@
                 + WindowManagerService.TYPE_LAYER_OFFSET;
     }
 
+    /** Callback to get pointer display id. */
+    @Override
+    public int getPointerDisplayId() {
+        synchronized (mService.mGlobalLock) {
+            // If desktop mode is not enabled, show on the default display.
+            if (!mService.mForceDesktopModeOnExternalDisplays) {
+                return DEFAULT_DISPLAY;
+            }
+
+            // Look for the topmost freeform display.
+            int firstExternalDisplayId = DEFAULT_DISPLAY;
+            for (int i = mService.mRoot.mChildren.size() - 1; i >= 0; --i) {
+                final DisplayContent displayContent = mService.mRoot.mChildren.get(i);
+                // Heuristic solution here. Currently when "Freeform windows" developer option is
+                // enabled we automatically put secondary displays in freeform mode and emulating
+                // "desktop mode". It also makes sense to show the pointer on the same display.
+                if (displayContent.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+                    return displayContent.getDisplayId();
+                }
+
+                if (firstExternalDisplayId == DEFAULT_DISPLAY
+                        && displayContent.getDisplayId() != DEFAULT_DISPLAY) {
+                    firstExternalDisplayId = displayContent.getDisplayId();
+                }
+            }
+
+            // Look for the topmost non-default display
+            return firstExternalDisplayId;
+        }
+    }
+
     /** Waits until the built-in input devices have been configured. */
     public boolean waitForInputDevicesReady(long timeoutMillis) {
         synchronized (mInputDevicesReadyMonitor) {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index fc1c65c..3c5d911 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -32,6 +32,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.graphics.Rect;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Process;
@@ -46,6 +47,7 @@
 import android.view.InputWindowHandle;
 import android.view.SurfaceControl;
 
+import com.android.server.AnimationThread;
 import com.android.server.policy.WindowManagerPolicy;
 
 import java.io.PrintWriter;
@@ -60,18 +62,21 @@
 
     // When true, need to call updateInputWindowsLw().
     private boolean mUpdateInputWindowsNeeded = true;
+    private boolean mUpdateInputWindowsPending;
 
     // Currently focused input window handle.
     private InputWindowHandle mFocusedInputWindowHandle;
 
     private boolean mDisableWallpaperTouchEvents;
     private final Rect mTmpRect = new Rect();
-    private final UpdateInputForAllWindowsConsumer mUpdateInputForAllWindowsConsumer =
-            new UpdateInputForAllWindowsConsumer();
+    private final UpdateInputForAllWindowsConsumer mUpdateInputForAllWindowsConsumer;
 
     private final int mDisplayId;
+    private final DisplayContent mDisplayContent;
+    private boolean mDisplayRemoved;
 
     private final SurfaceControl.Transaction mInputTransaction;
+    private final Handler mHandler;
 
     /**
      * The set of input consumer added to the window manager by name, which consumes input events
@@ -105,10 +110,65 @@
         }
     }
 
+    private final Runnable mUpdateInputWindows = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mService.mGlobalLock) {
+                mUpdateInputWindowsPending = false;
+                mUpdateInputWindowsNeeded = false;
+
+                if (mDisplayRemoved) {
+                    return;
+                }
+
+                // Populate the input window list with information about all of the windows that
+                // could potentially receive input.
+                // As an optimization, we could try to prune the list of windows but this turns
+                // out to be difficult because only the native code knows for sure which window
+                // currently has touch focus.
+
+                // If there's a drag in flight, provide a pseudo-window to catch drag input
+                final boolean inDrag = mService.mDragDropController.dragDropActiveLocked();
+                if (inDrag) {
+                    if (DEBUG_DRAG) {
+                        Log.d(TAG_WM, "Inserting drag window");
+                    }
+                    mService.mDragDropController.showInputSurface(mInputTransaction, mDisplayId);
+                } else {
+                    mService.mDragDropController.hideInputSurface(mInputTransaction, mDisplayId);
+                }
+
+                final boolean inPositioning =
+                        mService.mTaskPositioningController.isPositioningLocked();
+                if (inPositioning) {
+                    if (DEBUG_TASK_POSITIONING) {
+                        Log.d(TAG_WM, "Inserting window handle for repositioning");
+                    }
+                    mService.mTaskPositioningController.showInputSurface(mInputTransaction,
+                            mDisplayId);
+                } else {
+                    mService.mTaskPositioningController.hideInputSurface(mInputTransaction,
+                            mDisplayId);
+                }
+
+                // Add all windows on the default display.
+                mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
+            }
+        }
+    };
+
     public InputMonitor(WindowManagerService service, int displayId) {
         mService = service;
+        mDisplayContent = mService.mRoot.getDisplayContent(displayId);
         mDisplayId = displayId;
-        mInputTransaction = mService.mRoot.getDisplayContent(mDisplayId).getPendingTransaction();
+        mInputTransaction = mDisplayContent.getPendingTransaction();
+        mHandler = AnimationThread.getHandler();
+        mUpdateInputForAllWindowsConsumer = new UpdateInputForAllWindowsConsumer();
+    }
+
+    void onDisplayRemoved() {
+        mHandler.removeCallbacks(mUpdateInputWindows);
+        mDisplayRemoved = true;
     }
 
     private void addInputConsumer(String name, InputConsumerImpl consumer) {
@@ -248,41 +308,18 @@
         if (!force && !mUpdateInputWindowsNeeded) {
             return;
         }
-        mUpdateInputWindowsNeeded = false;
+        scheduleUpdateInputWindows();
+    }
 
-        if (false) Slog.d(TAG_WM, ">>>>>> ENTERED updateInputWindowsLw");
-
-        // Populate the input window list with information about all of the windows that
-        // could potentially receive input.
-        // As an optimization, we could try to prune the list of windows but this turns
-        // out to be difficult because only the native code knows for sure which window
-        // currently has touch focus.
-
-        // If there's a drag in flight, provide a pseudo-window to catch drag input
-        final boolean inDrag = mService.mDragDropController.dragDropActiveLocked();
-        if (inDrag) {
-            if (DEBUG_DRAG) {
-                Log.d(TAG_WM, "Inserting drag window");
-            }
-            mService.mDragDropController.showInputSurface(mInputTransaction, mDisplayId);
-        } else {
-            mService.mDragDropController.hideInputSurface(mInputTransaction, mDisplayId);
+    private void scheduleUpdateInputWindows() {
+        if (mDisplayRemoved) {
+            return;
         }
 
-        final boolean inPositioning = mService.mTaskPositioningController.isPositioningLocked();
-        if (inPositioning) {
-            if (DEBUG_TASK_POSITIONING) {
-                Log.d(TAG_WM, "Inserting window handle for repositioning");
-            }
-            mService.mTaskPositioningController.showInputSurface(mInputTransaction, mDisplayId);
-        } else {
-            mService.mTaskPositioningController.hideInputSurface(mInputTransaction, mDisplayId);
+        if (!mUpdateInputWindowsPending) {
+            mUpdateInputWindowsPending = true;
+            mHandler.post(mUpdateInputWindows);
         }
-
-        // Add all windows on the default display.
-        mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
-
-        if (false) Slog.d(TAG_WM, "<<<<<<< EXITED updateInputWindowsLw");
     }
 
     /* Called when the current input focus changes.
@@ -369,6 +406,9 @@
         boolean inDrag;
         WallpaperController wallpaperController;
 
+        // An invalid window handle that tells SurfaceFlinger not update the input info.
+        final InputWindowHandle mInvalidInputWindow = new InputWindowHandle(null, null, mDisplayId);
+
         private void updateInputWindows(boolean inDrag) {
             Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
 
@@ -385,19 +425,18 @@
             mTmpRect.setEmpty();
             mDisableWallpaperTouchEvents = false;
             this.inDrag = inDrag;
-            final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
-            wallpaperController = dc.mWallpaperController;
+            wallpaperController = mDisplayContent.mWallpaperController;
 
             resetInputConsumers(mInputTransaction);
 
-            dc.forAllWindows(this,
+            mDisplayContent.forAllWindows(this,
                     true /* traverseTopToBottom */);
 
             if (mAddWallpaperInputConsumerHandle) {
                 wallpaperInputConsumer.show(mInputTransaction, 0);
             }
 
-            dc.scheduleAnimation();
+            mDisplayContent.scheduleAnimation();
 
             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
         }
@@ -408,6 +447,10 @@
             final InputWindowHandle inputWindowHandle = w.mInputWindowHandle;
             if (inputChannel == null || inputWindowHandle == null || w.mRemoved
                     || w.cantReceiveTouchInput()) {
+                if (w.mWinAnimator.hasSurface()) {
+                    mInputTransaction.setInputWindowInfo(
+                            w.mWinAnimator.mSurfaceController.mSurfaceControl, mInvalidInputWindow);
+                }
                 // Skip this window because it cannot possibly receive input.
                 return;
             }
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 49a3186..e49e4c0 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -16,9 +16,10 @@
 
 package com.android.server.wm;
 
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.proto.ProtoOutputStream;
 import android.view.InsetsState;
@@ -26,8 +27,10 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.InsetsSource;
 import android.view.InsetsSourceControl;
+import android.view.ViewRootImpl;
 
 import com.android.internal.util.function.TriConsumer;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 
 import java.io.PrintWriter;
@@ -106,8 +109,8 @@
             mTmpRect.inset(mWin.mGivenContentInsets);
         }
         mSource.setFrame(mTmpRect);
-        setServerVisible(mWin.isVisible() && !mWin.mGivenInsetsPending);
-
+        setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.mPolicyVisibility
+                && !mWin.mGivenInsetsPending);
     }
 
     void updateControlForTarget(@Nullable WindowState target) {
@@ -115,15 +118,15 @@
             return;
         }
         if (target == null) {
-            revokeControl();
+            // Cancelling the animation will invoke onAnimationCancelled, resetting all the fields.
+            mWin.cancelAnimation();
             return;
         }
         mAdapter = new ControlAdapter();
         mWin.startAnimation(mDisplayContent.getPendingTransaction(), mAdapter,
-                false /* TODO hidden */);
+                !mClientVisible /* hidden */);
         mControllingWin = target;
         mControl = new InsetsSourceControl(mSource.getType(), mAdapter.mCapturedLeash);
-        setClientVisible(InsetsState.getDefaultVisibly(mSource.getType()));
     }
 
     boolean onInsetsModified(WindowState caller, InsetsSource modifiedSource) {
@@ -135,7 +138,12 @@
     }
 
     private void setClientVisible(boolean clientVisible) {
+        if (mClientVisible == clientVisible) {
+            return;
+        }
         mClientVisible = clientVisible;
+        mDisplayContent.mWmService.mH.sendMessage(PooledLambda.obtainMessage(
+                DisplayContent::layoutAndAssignWindowLayersIfNeeded, mDisplayContent));
         updateVisibility();
     }
 
@@ -152,13 +160,8 @@
         return mControl;
     }
 
-    void revokeControl() {
-        if (mControllingWin != null) {
-
-            // Cancelling the animation will invoke onAnimationCancelled, resetting all the fields.
-            mWin.cancelAnimation();
-        }
-        setClientVisible(InsetsState.getDefaultVisibly(mSource.getType()));
+    boolean isClientVisible() {
+        return ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE || mClientVisible;
     }
 
     private class ControlAdapter implements AnimationAdapter {
@@ -186,6 +189,7 @@
         public void onAnimationCancelled(SurfaceControl animationLeash) {
             if (mAdapter == this) {
                 mStateController.notifyControlRevoked(mControllingWin, InsetsSourceProvider.this);
+                setClientVisible(InsetsState.getDefaultVisibly(mSource.getType()));
                 mControl = null;
                 mControllingWin = null;
                 mAdapter = null;
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 8e119bb..32dbe96 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -19,6 +19,9 @@
 import static android.view.InsetsState.TYPE_IME;
 import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.TYPE_TOP_BAR;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
+import static android.view.ViewRootImpl.sNewInsetsMode;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -160,7 +163,7 @@
     }
 
     private void onControlChanged(int type, @Nullable WindowState win) {
-        if (!ViewRootImpl.USE_NEW_INSETS) {
+        if (sNewInsetsMode == NEW_INSETS_MODE_NONE) {
             return;
         }
         final WindowState previous = mTypeWinControlMap.get(type);
@@ -202,6 +205,9 @@
     }
 
     private void notifyPendingInsetsControlChanged() {
+        if (mPendingControlChanged.isEmpty()) {
+            return;
+        }
         mDisplayContent.mWmService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
             for (int i = mPendingControlChanged.size() - 1; i >= 0; i--) {
                 final WindowState controllingWin = mPendingControlChanged.valueAt(i);
@@ -218,5 +224,11 @@
     void dump(String prefix, PrintWriter pw) {
         pw.println(prefix + "WindowInsetsStateController");
         mState.dump(prefix + "  ", pw);
+        pw.println(prefix + "  " + "Control map:");
+        for (int i = mTypeWinControlMap.size() - 1; i >= 0; i--) {
+            pw.print(prefix + "  ");
+            pw.println(InsetsState.typeToString(mTypeWinControlMap.keyAt(i)) + " -> "
+                    + mTypeWinControlMap.valueAt(i));
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 5f56fe5..177f244 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -462,22 +462,19 @@
             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(
+            final ActivityStack stack = getStackForControllingOccluding(display);
+            if (stack != null) {
+                final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
+                mOccluded = stack.topActivityOccludesKeyguard() || (topDismissing != null
+                        && stack.topRunningActivityLocked() == topDismissing
+                        && controller.canShowWhileOccluded(
                                 true /* dismissKeyguard */,
                                 false /* showWhenLocked */));
-                if (focusedStack.getTopDismissingKeyguardActivity() != null) {
-                    mDismissingKeyguardActivity = focusedStack.getTopDismissingKeyguardActivity();
+                if (stack.getTopDismissingKeyguardActivity() != null) {
+                    mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
                 }
-                mOccluded |= controller.mWindowManager.isShowingDream();
             }
+            mOccluded |= controller.mWindowManager.isShowingDream();
 
             // TODO(b/113840485): Handle app transition for individual display, and apply occluded
             // state change to secondary displays.
@@ -492,6 +489,23 @@
             }
         }
 
+        /**
+         * Gets the stack used to check the occluded state.
+         * <p>
+         * Only the top non-pinned activity of the focusable stack on each display can control its
+         * occlusion state.
+         */
+        private ActivityStack getStackForControllingOccluding(ActivityDisplay display) {
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                if (stack != null && stack.isFocusableAndVisible()
+                        && !stack.inPinnedWindowingMode()) {
+                    return stack;
+                }
+            }
+            return null;
+        }
+
         void dumpStatus(PrintWriter pw, String prefix) {
             final StringBuilder sb = new StringBuilder();
             sb.append(prefix);
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 3062d34..86dc66d 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -221,7 +221,7 @@
     }
 
     private boolean saveTaskToLaunchParam(TaskRecord task, PersistableLaunchParams params) {
-        final ActivityStack<?> stack = task.getStack();
+        final ActivityStack stack = task.getStack();
         final int displayId = stack.mDisplayId;
         final ActivityDisplay display =
                 mSupervisor.mRootActivityContainer.getActivityDisplay(displayId);
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 1a2aa2f..434084c 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -18,6 +18,7 @@
 
 import static android.view.SurfaceControl.HIDDEN;
 
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.SurfaceControl;
 
@@ -30,6 +31,7 @@
 public class Letterbox {
 
     private static final Rect EMPTY_RECT = new Rect();
+    private static final Point ZERO_POINT = new Point(0, 0);
 
     private final Supplier<SurfaceControl.Builder> mFactory;
     private final Rect mOuter = new Rect();
@@ -53,19 +55,20 @@
      * frames will be covered by black color surfaces.
      *
      * The caller must use {@link #applySurfaceChanges} to apply the new layout to the surface.
-     *
      * @param outer the outer frame of the letterbox (this frame will be black, except the area
-     *              that intersects with the {code inner} frame).
-     * @param inner the inner frame of the letterbox (this frame will be clear)
+     *              that intersects with the {code inner} frame), in global coordinates
+     * @param inner the inner frame of the letterbox (this frame will be clear), in global
+     *              coordinates
+     * @param surfaceOrigin the origin of the surface factory in global coordinates
      */
-    public void layout(Rect outer, Rect inner) {
+    public void layout(Rect outer, Rect inner, Point surfaceOrigin) {
         mOuter.set(outer);
         mInner.set(inner);
 
-        mTop.layout(outer.left, outer.top, inner.right, inner.top);
-        mLeft.layout(outer.left, inner.top, inner.left, outer.bottom);
-        mBottom.layout(inner.left, inner.bottom, outer.right, outer.bottom);
-        mRight.layout(inner.right, outer.top, outer.right, inner.bottom);
+        mTop.layout(outer.left, outer.top, inner.right, inner.top, surfaceOrigin);
+        mLeft.layout(outer.left, inner.top, inner.left, outer.bottom, surfaceOrigin);
+        mBottom.layout(inner.left, inner.bottom, outer.right, outer.bottom, surfaceOrigin);
+        mRight.layout(inner.right, outer.top, outer.right, inner.bottom, surfaceOrigin);
     }
 
 
@@ -94,7 +97,7 @@
      * The caller must use {@link #applySurfaceChanges} to apply the new layout to the surface.
      */
     public void hide() {
-        layout(EMPTY_RECT, EMPTY_RECT);
+        layout(EMPTY_RECT, EMPTY_RECT, ZERO_POINT);
     }
 
     /**
@@ -130,20 +133,18 @@
         private final String mType;
         private SurfaceControl mSurface;
 
-        private final Rect mSurfaceFrame = new Rect();
-        private final Rect mLayoutFrame = new Rect();
+        private final Rect mSurfaceFrameRelative = new Rect();
+        private final Rect mLayoutFrameGlobal = new Rect();
+        private final Rect mLayoutFrameRelative = new Rect();
 
         public LetterboxSurface(String type) {
             mType = type;
         }
 
-        public void layout(int left, int top, int right, int bottom) {
-            if (mLayoutFrame.left == left && mLayoutFrame.top == top
-                    && mLayoutFrame.right == right && mLayoutFrame.bottom == bottom) {
-                // Nothing changed.
-                return;
-            }
-            mLayoutFrame.set(left, top, right, bottom);
+        public void layout(int left, int top, int right, int bottom, Point surfaceOrigin) {
+            mLayoutFrameGlobal.set(left, top, right, bottom);
+            mLayoutFrameRelative.set(mLayoutFrameGlobal);
+            mLayoutFrameRelative.offset(-surfaceOrigin.x, -surfaceOrigin.y);
         }
 
         private void createSurface() {
@@ -161,32 +162,37 @@
         }
 
         public int getWidth() {
-            return Math.max(0, mLayoutFrame.width());
+            return Math.max(0, mLayoutFrameGlobal.width());
         }
 
         public int getHeight() {
-            return Math.max(0, mLayoutFrame.height());
+            return Math.max(0, mLayoutFrameGlobal.height());
         }
 
+        /**
+         * Returns if the given {@code rect} overlaps with this letterbox piece.
+         * @param rect the area to check for overlap in global coordinates
+         */
         public boolean isOverlappingWith(Rect rect) {
-            if (getWidth() <= 0 || getHeight() <= 0) {
+            if (mLayoutFrameGlobal.isEmpty()) {
                 return false;
             }
-            return Rect.intersects(rect, mLayoutFrame);
+            return Rect.intersects(rect, mLayoutFrameGlobal);
         }
 
         public void applySurfaceChanges(SurfaceControl.Transaction t) {
-            if (mSurfaceFrame.equals(mLayoutFrame)) {
+            if (mSurfaceFrameRelative.equals(mLayoutFrameRelative)) {
                 // Nothing changed.
                 return;
             }
-            mSurfaceFrame.set(mLayoutFrame);
-            if (!mSurfaceFrame.isEmpty()) {
+            mSurfaceFrameRelative.set(mLayoutFrameRelative);
+            if (!mSurfaceFrameRelative.isEmpty()) {
                 if (mSurface == null) {
                     createSurface();
                 }
-                t.setPosition(mSurface, mSurfaceFrame.left, mSurfaceFrame.top);
-                t.setWindowCrop(mSurface, mSurfaceFrame.width(), mSurfaceFrame.height());
+                t.setPosition(mSurface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top);
+                t.setWindowCrop(mSurface, mSurfaceFrameRelative.width(),
+                        mSurfaceFrameRelative.height());
                 t.show(mSurface);
             } else if (mSurface != null) {
                 t.hide(mSurface);
@@ -194,7 +200,7 @@
         }
 
         public boolean needsApplySurfaceChanges() {
-            return !mSurfaceFrame.equals(mLayoutFrame);
+            return !mSurfaceFrameRelative.equals(mLayoutFrameRelative);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/PinnedActivityStack.java b/services/core/java/com/android/server/wm/PinnedActivityStack.java
deleted file mode 100644
index 2a05af4..0000000
--- a/services/core/java/com/android/server/wm/PinnedActivityStack.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-
-import android.app.RemoteAction;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * State and management of the pinned stack of activities.
- */
-class PinnedActivityStack extends ActivityStack<PinnedStackWindowController>
-        implements PinnedStackWindowListener {
-
-    PinnedActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
-            boolean onTop) {
-        super(display, stackId, supervisor, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, onTop);
-    }
-
-    @Override
-    PinnedStackWindowController createStackWindowController(int displayId, boolean onTop,
-            Rect outBounds) {
-        return new PinnedStackWindowController(mStackId, this, displayId, onTop, outBounds,
-                mRootActivityContainer.mWindowManager);
-    }
-
-    Rect getDefaultPictureInPictureBounds(float aspectRatio) {
-        return getWindowContainerController().getPictureInPictureBounds(aspectRatio,
-                null /* currentStackBounds */);
-    }
-
-    void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
-            boolean fromFullscreen) {
-        if (skipResizeAnimation(toBounds == null /* toFullscreen */)) {
-            mService.moveTasksToFullscreenStack(mStackId, true /* onTop */);
-        } else {
-            getWindowContainerController().animateResizePinnedStack(toBounds, sourceHintBounds,
-                    animationDuration, fromFullscreen);
-        }
-    }
-
-    private boolean skipResizeAnimation(boolean toFullscreen) {
-        if (!toFullscreen) {
-            return false;
-        }
-        final Configuration parentConfig = getParent().getConfiguration();
-        final ActivityRecord top = topRunningNonOverlayTaskActivity();
-        return top != null && !top.isConfigurationCompatible(parentConfig);
-    }
-
-    void setPictureInPictureAspectRatio(float aspectRatio) {
-        getWindowContainerController().setPictureInPictureAspectRatio(aspectRatio);
-    }
-
-    void setPictureInPictureActions(List<RemoteAction> actions) {
-        getWindowContainerController().setPictureInPictureActions(actions);
-    }
-
-    boolean isAnimatingBoundsToFullscreen() {
-        return getWindowContainerController().mContainer.isAnimatingBoundsToFullscreen();
-    }
-
-    /**
-     * Returns whether to defer the scheduling of the multi-window mode.
-     */
-    boolean deferScheduleMultiWindowModeChanged() {
-        // For the pinned stack, the deferring of the multi-window mode changed is tied to the
-        // transition animation into picture-in-picture, and is called once the animation completes,
-        // or is interrupted in a way that would leave the stack in a non-fullscreen state.
-        // @see BoundsAnimationController
-        // @see BoundsAnimationControllerTests
-        return mWindowContainerController.deferScheduleMultiWindowModeChanged();
-    }
-
-    public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
-            boolean forceUpdate) {
-        // It is guaranteed that the activities requiring the update will be in the pinned stack at
-        // this point (either reparented before the animation into PiP, or before reparenting after
-        // the animation out of PiP)
-        synchronized (mService.mGlobalLock) {
-            if (!isAttached()) {
-                return;
-            }
-            ArrayList<TaskRecord> tasks = getAllTasks();
-            for (int i = 0; i < tasks.size(); i++ ) {
-                mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
-                        forceUpdate);
-            }
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
deleted file mode 100644
index 518e39b..0000000
--- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-
-import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
-import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
-import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
-import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState;
-
-import android.app.RemoteAction;
-import android.graphics.Rect;
-
-import java.util.List;
-
-/**
- * Controller for the pinned stack container. See {@link StackWindowController}.
- */
-public class PinnedStackWindowController extends StackWindowController {
-
-    private Rect mTmpFromBounds = new Rect();
-    private Rect mTmpToBounds = new Rect();
-
-    public PinnedStackWindowController(int stackId, PinnedStackWindowListener listener,
-            int displayId, boolean onTop, Rect outBounds, WindowManagerService service) {
-        super(stackId, listener, displayId, onTop, outBounds, service);
-    }
-
-    /**
-     * @return the {@param currentStackBounds} transformed to the give {@param aspectRatio}.  If
-     *         {@param currentStackBounds} is null, then the {@param aspectRatio} is applied to the
-     *         default bounds.
-     */
-    public Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) {
-        synchronized (mGlobalLock) {
-            if (!mService.mSupportsPictureInPicture || mContainer == null) {
-                return null;
-            }
-
-            final DisplayContent displayContent = mContainer.getDisplayContent();
-            if (displayContent == null) {
-                return null;
-            }
-
-            final PinnedStackController pinnedStackController =
-                    displayContent.getPinnedStackController();
-            if (stackBounds == null) {
-                // Calculate the aspect ratio bounds from the default bounds
-                stackBounds = pinnedStackController.getDefaultOrLastSavedBounds();
-            }
-
-            if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {
-                return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio,
-                        true /* useCurrentMinEdgeSize */);
-            } else {
-                return stackBounds;
-            }
-        }
-    }
-
-    /**
-     * Animates the pinned stack.
-     */
-    public void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds,
-            int animationDuration, boolean fromFullscreen) {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                throw new IllegalArgumentException("Pinned stack container not found :(");
-            }
-
-            // Get the from-bounds
-            final Rect fromBounds = new Rect();
-            mContainer.getBounds(fromBounds);
-
-            // Get non-null fullscreen to-bounds for animating if the bounds are null
-            @SchedulePipModeChangedState int schedulePipModeChangedState =
-                NO_PIP_MODE_CHANGED_CALLBACKS;
-            final boolean toFullscreen = toBounds == null;
-            if (toFullscreen) {
-                if (fromFullscreen) {
-                    throw new IllegalArgumentException("Should not defer scheduling PiP mode"
-                            + " change on animation to fullscreen.");
-                }
-                schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START;
-
-                mService.getStackBounds(
-                        WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mTmpToBounds);
-                if (!mTmpToBounds.isEmpty()) {
-                    // If there is a fullscreen bounds, use that
-                    toBounds = new Rect(mTmpToBounds);
-                } else {
-                    // Otherwise, use the display bounds
-                    toBounds = new Rect();
-                    mContainer.getDisplayContent().getBounds(toBounds);
-                }
-            } else if (fromFullscreen) {
-                schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
-            }
-
-            mContainer.setAnimationFinalBounds(sourceHintBounds, toBounds, toFullscreen);
-
-            final Rect finalToBounds = toBounds;
-            final @SchedulePipModeChangedState int finalSchedulePipModeChangedState =
-                schedulePipModeChangedState;
-            final DisplayContent displayContent = mContainer.getDisplayContent();
-            displayContent.mBoundsAnimationController.getHandler().post(() -> {
-                if (mContainer == null) {
-                    return;
-                }
-                displayContent.mBoundsAnimationController.animateBounds(mContainer, fromBounds,
-                        finalToBounds, animationDuration, finalSchedulePipModeChangedState,
-                        fromFullscreen, toFullscreen);
-            });
-        }
-    }
-
-    /**
-     * Sets the current picture-in-picture aspect ratio.
-     */
-    public void setPictureInPictureAspectRatio(float aspectRatio) {
-        synchronized (mGlobalLock) {
-            if (!mService.mSupportsPictureInPicture || mContainer == null) {
-                return;
-            }
-
-            final PinnedStackController pinnedStackController =
-                    mContainer.getDisplayContent().getPinnedStackController();
-
-            if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) != 0) {
-                mContainer.getAnimationOrCurrentBounds(mTmpFromBounds);
-                mTmpToBounds.set(mTmpFromBounds);
-                getPictureInPictureBounds(aspectRatio, mTmpToBounds);
-                if (!mTmpToBounds.equals(mTmpFromBounds)) {
-                    animateResizePinnedStack(mTmpToBounds, null /* sourceHintBounds */,
-                            -1 /* duration */, false /* fromFullscreen */);
-                }
-                pinnedStackController.setAspectRatio(
-                        pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
-                                ? aspectRatio : -1f);
-            }
-        }
-    }
-
-    /**
-     * Sets the current picture-in-picture actions.
-     */
-    public void setPictureInPictureActions(List<RemoteAction> actions) {
-        synchronized (mGlobalLock) {
-            if (!mService.mSupportsPictureInPicture || mContainer == null) {
-                return;
-            }
-
-            mContainer.getDisplayContent().getPinnedStackController().setActions(actions);
-        }
-    }
-
-    /**
-     * @return whether the multi-window mode change should be deferred as a part of a transition
-     * from fullscreen to non-fullscreen bounds.
-     */
-    public boolean deferScheduleMultiWindowModeChanged() {
-        synchronized (mGlobalLock) {
-            return mContainer.deferScheduleMultiWindowModeChanged();
-        }
-    }
-
-    /**
-     * @return whether the stack can be resized from the bounds animation.
-     */
-    public boolean pinnedStackResizeDisallowed() {
-        synchronized (mGlobalLock) {
-            return mContainer.pinnedStackResizeDisallowed();
-        }
-    }
-
-    /**
-     * The following calls are made from WM to AM.
-     */
-
-    /** Calls directly into activity manager so window manager lock shouldn't held. */
-    public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
-            boolean forceUpdate) {
-        if (mListener != null) {
-            PinnedStackWindowListener listener = (PinnedStackWindowListener) mListener;
-            listener.updatePictureInPictureModeForPinnedStackAnimation(targetStackBounds,
-                    forceUpdate);
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowListener.java b/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
deleted file mode 100644
index 33e8a60..0000000
--- a/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import android.graphics.Rect;
-
-/**
- * Interface used by the creator of {@link PinnedStackWindowController} to listen to changes with
- * the stack container.
- */
-public interface PinnedStackWindowListener extends StackWindowListener {
-
-    /**
-     * Called when the stack container pinned stack animation will change the picture-in-picture
-     * mode. This is a direct call into ActivityManager.
-     */
-    default void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
-            boolean forceUpdate) {}
-}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 83ba384..105ff06 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -29,7 +29,6 @@
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
-import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
 
 import android.annotation.IntDef;
 import android.app.ActivityManager.TaskSnapshot;
@@ -413,8 +412,7 @@
         }
         final SparseIntArray reasons = new SparseIntArray();
         reasons.put(WINDOWING_MODE_FULLSCREEN, APP_TRANSITION_RECENTS_ANIM);
-        mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING,
-                reasons).sendToTarget();
+        mService.mAtmInternal.notifyAppTransitionStarting(reasons, SystemClock.uptimeMillis());
     }
 
     void cancelAnimation(@ReorderMode int reorderMode, String reason) {
@@ -626,7 +624,7 @@
             mTarget = new RemoteAnimationTarget(mTask.mTaskId, mode, mCapturedLeash,
                     !topApp.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
                     insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
-                    mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
+                    mTask.getWindowConfiguration(), mIsRecentTaskInvisible, null, null);
             return mTarget;
         }
 
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index f5acdcc..f760b39 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -57,7 +57,7 @@
 
     private final WindowManagerService mService;
     private final RemoteAnimationAdapter mRemoteAnimationAdapter;
-    private final ArrayList<RemoteAnimationAdapterWrapper> mPendingAnimations = new ArrayList<>();
+    private final ArrayList<RemoteAnimationRecord> mPendingAnimations = new ArrayList<>();
     private final Rect mTmpRect = new Rect();
     private final Handler mHandler;
     private final Runnable mTimeoutRunnable = () -> cancelAnimation("timeoutRunnable");
@@ -74,21 +74,22 @@
     }
 
     /**
-     * Creates an animation for each individual {@link AppWindowToken}.
+     * Creates an animation record for each individual {@link AppWindowToken}.
      *
      * @param appWindowToken The app to animate.
      * @param position The position app bounds, in screen coordinates.
-     * @param stackBounds The stack bounds of the app.
-     * @return The adapter to be run on the app.
+     * @param stackBounds The stack bounds of the app relative to position.
+     * @param startBounds The stack bounds before the transition, in screen coordinates
+     * @return The record representing animation(s) to run on the app.
      */
-    AnimationAdapter createAnimationAdapter(AppWindowToken appWindowToken, Point position,
-            Rect stackBounds) {
+    RemoteAnimationRecord createRemoteAnimationRecord(AppWindowToken appWindowToken,
+            Point position, Rect stackBounds, Rect startBounds) {
         if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "createAnimationAdapter(): token="
                 + appWindowToken);
-        final RemoteAnimationAdapterWrapper adapter = new RemoteAnimationAdapterWrapper(
-                appWindowToken, position, stackBounds);
-        mPendingAnimations.add(adapter);
-        return adapter;
+        final RemoteAnimationRecord adapters =
+                new RemoteAnimationRecord(appWindowToken, position, stackBounds, startBounds);
+        mPendingAnimations.add(adapters);
+        return adapters;
     }
 
     /**
@@ -148,7 +149,7 @@
         final StringWriter sw = new StringWriter();
         final FastPrintWriter pw = new FastPrintWriter(sw);
         for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
-            mPendingAnimations.get(i).dump(pw, "");
+            mPendingAnimations.get(i).mAdapter.dump(pw, "");
         }
         pw.close();
         Slog.i(TAG, sw.toString());
@@ -158,19 +159,26 @@
         if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "createAnimations()");
         final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
         for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
-            final RemoteAnimationAdapterWrapper wrapper = mPendingAnimations.get(i);
-            final RemoteAnimationTarget target = wrapper.createRemoteAppAnimation();
+            final RemoteAnimationRecord wrappers = mPendingAnimations.get(i);
+            final RemoteAnimationTarget target = wrappers.createRemoteAnimationTarget();
             if (target != null) {
-                if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\tAdd token=" + wrapper.mAppWindowToken);
+                if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\tAdd token=" + wrappers.mAppWindowToken);
                 targets.add(target);
             } else {
                 if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\tRemove token="
-                        + wrapper.mAppWindowToken);
+                        + wrappers.mAppWindowToken);
 
                 // We can't really start an animation but we still need to make sure to finish the
                 // pending animation that was started by SurfaceAnimator
-                if (wrapper.mCapturedFinishCallback != null) {
-                    wrapper.mCapturedFinishCallback.onAnimationFinished(wrapper);
+                if (wrappers.mAdapter != null
+                        && wrappers.mAdapter.mCapturedFinishCallback != null) {
+                    wrappers.mAdapter.mCapturedFinishCallback
+                            .onAnimationFinished(wrappers.mAdapter);
+                }
+                if (wrappers.mThumbnailAdapter != null
+                        && wrappers.mThumbnailAdapter.mCapturedFinishCallback != null) {
+                    wrappers.mThumbnailAdapter.mCapturedFinishCallback
+                            .onAnimationFinished(wrappers.mThumbnailAdapter);
                 }
                 mPendingAnimations.remove(i);
             }
@@ -190,9 +198,16 @@
                 if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG,
                         "onAnimationFinished(): Notify animation finished:");
                 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
-                    final RemoteAnimationAdapterWrapper adapter = mPendingAnimations.get(i);
-                    adapter.mCapturedFinishCallback.onAnimationFinished(adapter);
-                    if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\t" + adapter.mAppWindowToken);
+                    final RemoteAnimationRecord adapters = mPendingAnimations.get(i);
+                    if (adapters.mAdapter != null) {
+                        adapters.mAdapter.mCapturedFinishCallback
+                                .onAnimationFinished(adapters.mAdapter);
+                    }
+                    if (adapters.mThumbnailAdapter != null) {
+                        adapters.mThumbnailAdapter.mCapturedFinishCallback
+                                .onAnimationFinished(adapters.mThumbnailAdapter);
+                    }
+                    if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\t" + adapters.mAppWindowToken);
                 }
             } catch (Exception e) {
                 Slog.e(TAG, "Failed to finish remote animation", e);
@@ -282,47 +297,84 @@
         }
     };
 
-    private class RemoteAnimationAdapterWrapper implements AnimationAdapter {
+    /**
+     * Contains information about a remote-animation for one AppWindowToken. This keeps track of,
+     * potentially, multiple animating surfaces (AdapterWrappers) associated with one
+     * Window/Transition. For example, a change transition has an adapter controller for the
+     * main window and an adapter controlling the start-state snapshot.
+     * <p>
+     * This can be thought of as a bridge between the information that the remote animator sees (via
+     * {@link RemoteAnimationTarget}) and what the server sees (the
+     * {@link RemoteAnimationAdapterWrapper}(s) interfacing with the moving surfaces).
+     */
+    public class RemoteAnimationRecord {
+        RemoteAnimationAdapterWrapper mAdapter;
+        RemoteAnimationAdapterWrapper mThumbnailAdapter = null;
+        RemoteAnimationTarget mTarget;
+        final AppWindowToken mAppWindowToken;
+        final Rect mStartBounds;
 
-        private final AppWindowToken mAppWindowToken;
-        private SurfaceControl mCapturedLeash;
-        private OnAnimationFinishedCallback mCapturedFinishCallback;
-        private final Point mPosition = new Point();
-        private final Rect mStackBounds = new Rect();
-        private RemoteAnimationTarget mTarget;
-
-        RemoteAnimationAdapterWrapper(AppWindowToken appWindowToken, Point position,
-                Rect stackBounds) {
+        RemoteAnimationRecord(AppWindowToken appWindowToken, Point endPos, Rect endBounds,
+                Rect startBounds) {
             mAppWindowToken = appWindowToken;
-            mPosition.set(position.x, position.y);
-            mStackBounds.set(stackBounds);
+            mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, endBounds);
+            if (startBounds != null) {
+                mStartBounds = new Rect(startBounds);
+                mTmpRect.set(startBounds);
+                mTmpRect.offsetTo(0, 0);
+                mThumbnailAdapter =
+                        new RemoteAnimationAdapterWrapper(this, new Point(0, 0), mTmpRect);
+            } else {
+                mStartBounds = null;
+            }
         }
 
-        RemoteAnimationTarget createRemoteAppAnimation() {
+        RemoteAnimationTarget createRemoteAnimationTarget() {
             final Task task = mAppWindowToken.getTask();
             final WindowState mainWindow = mAppWindowToken.findMainWindow();
-            if (task == null || mainWindow == null || mCapturedFinishCallback == null
-                    || mCapturedLeash == null) {
+            if (task == null || mainWindow == null || mAdapter == null
+                    || mAdapter.mCapturedFinishCallback == null
+                    || mAdapter.mCapturedLeash == null) {
                 return null;
             }
             final Rect insets = new Rect();
             mainWindow.getContentInsets(insets);
             InsetUtils.addInsets(insets, mAppWindowToken.getLetterboxInsets());
             mTarget = new RemoteAnimationTarget(task.mTaskId, getMode(),
-                    mCapturedLeash, !mAppWindowToken.fillsParent(),
+                    mAdapter.mCapturedLeash, !mAppWindowToken.fillsParent(),
                     mainWindow.mWinAnimator.mLastClipRect, insets,
-                    mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds,
-                    task.getWindowConfiguration(), false /*isNotInRecents*/);
+                    mAppWindowToken.getPrefixOrderIndex(), mAdapter.mPosition,
+                    mAdapter.mStackBounds, task.getWindowConfiguration(), false /*isNotInRecents*/,
+                    mThumbnailAdapter != null ? mThumbnailAdapter.mCapturedLeash : null,
+                    mStartBounds);
             return mTarget;
         }
 
         private int getMode() {
-            if (mAppWindowToken.getDisplayContent().mOpeningApps.contains(mAppWindowToken)) {
+            final DisplayContent dc = mAppWindowToken.getDisplayContent();
+            if (dc.mOpeningApps.contains(mAppWindowToken)) {
                 return RemoteAnimationTarget.MODE_OPENING;
+            } else if (dc.mChangingApps.contains(mAppWindowToken)) {
+                return RemoteAnimationTarget.MODE_CHANGING;
             } else {
                 return RemoteAnimationTarget.MODE_CLOSING;
             }
         }
+    }
+
+    private class RemoteAnimationAdapterWrapper implements AnimationAdapter {
+        private final RemoteAnimationRecord mRecord;
+        SurfaceControl mCapturedLeash;
+        private OnAnimationFinishedCallback mCapturedFinishCallback;
+        private final Point mPosition = new Point();
+        private final Rect mStackBounds = new Rect();
+
+        RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position,
+                Rect stackBounds) {
+            mRecord = record;
+            mPosition.set(position.x, position.y);
+            mStackBounds.set(stackBounds);
+        }
 
         @Override
         public boolean getShowWallpaper() {
@@ -340,7 +392,7 @@
             if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "startAnimation");
 
             // Restore z-layering, position and stack crop until client has a chance to modify it.
-            t.setLayer(animationLeash, mAppWindowToken.getPrefixOrderIndex());
+            t.setLayer(animationLeash, mRecord.mAppWindowToken.getPrefixOrderIndex());
             t.setPosition(animationLeash, mPosition.x, mPosition.y);
             mTmpRect.set(mStackBounds);
             mTmpRect.offsetTo(0, 0);
@@ -351,7 +403,14 @@
 
         @Override
         public void onAnimationCancelled(SurfaceControl animationLeash) {
-            mPendingAnimations.remove(this);
+            if (mRecord.mAdapter == this) {
+                mRecord.mAdapter = null;
+            } else {
+                mRecord.mThumbnailAdapter = null;
+            }
+            if (mRecord.mAdapter == null && mRecord.mThumbnailAdapter == null) {
+                mPendingAnimations.remove(mRecord);
+            }
             if (mPendingAnimations.isEmpty()) {
                 mHandler.removeCallbacks(mTimeoutRunnable);
                 releaseFinishedCallback();
@@ -373,10 +432,10 @@
 
         @Override
         public void dump(PrintWriter pw, String prefix) {
-            pw.print(prefix); pw.print("token="); pw.println(mAppWindowToken);
-            if (mTarget != null) {
+            pw.print(prefix); pw.print("token="); pw.println(mRecord.mAppWindowToken);
+            if (mRecord.mTarget != null) {
                 pw.print(prefix); pw.println("Target:");
-                mTarget.dump(pw, prefix + "  ");
+                mRecord.mTarget.dump(pw, prefix + "  ");
             } else {
                 pw.print(prefix); pw.println("Target: null");
             }
@@ -385,8 +444,8 @@
         @Override
         public void writeToProto(ProtoOutputStream proto) {
             final long token = proto.start(REMOTE);
-            if (mTarget != null) {
-                mTarget.writeToProto(proto, TARGET);
+            if (mRecord.mTarget != null) {
+                mRecord.mTarget.writeToProto(proto, TARGET);
             }
             proto.end(token);
         }
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index f55c7c9..9b72141 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -234,7 +234,7 @@
         mWindowManager = wm;
         setWindowContainer(mWindowManager.mRoot);
         mDisplayManager = mService.mContext.getSystemService(DisplayManager.class);
-        mDisplayManager.registerDisplayListener(this, mService.mH);
+        mDisplayManager.registerDisplayListener(this, mService.mUiHandler);
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
 
         final Display[] displays = mDisplayManager.getDisplays();
@@ -955,7 +955,7 @@
         mWindowManager.deferSurfaceLayout();
 
         final ActivityDisplay display = r.getActivityStack().getDisplay();
-        PinnedActivityStack stack = display.getPinnedStack();
+        ActivityStack stack = display.getPinnedStack();
 
         // This will clear the pinned stack by moving an existing task to the full screen stack,
         // ensuring only one task is present.
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 4e70bbc..8fb7947 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -23,6 +23,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -280,6 +281,15 @@
     }
 
     /**
+     * Returns true if the callingUid has any non-toast window currently visible to the user.
+     */
+    boolean isAnyNonToastWindowVisibleForUid(int callingUid) {
+        return forAllWindows(w -> {
+            return w.getOwningUid() == callingUid && w.isVisible() && w.mAttrs.type != TYPE_TOAST;
+        }, true /* traverseTopToBottom */);
+    }
+
+    /**
      * Returns the app window token for the input binder if it exist in the system.
      * NOTE: Only one AppWindowToken is allowed to exist in the system for a binder token, since
      * AppWindowToken represents an activity which can only exist on one display.
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index d85fdb0..58cf73a 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -47,10 +47,9 @@
 import android.view.IWindowSession;
 import android.view.IWindowSessionCallback;
 import android.view.InputChannel;
-import android.view.Surface;
+import android.view.InsetsState;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
-import android.view.InsetsState;
 import android.view.WindowManager;
 
 import com.android.internal.os.logging.MetricsLoggerWrapper;
@@ -187,7 +186,7 @@
             Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
             Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
             DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
-            Surface outSurface, InsetsState outInsetsState) {
+            SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
         if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                 + Binder.getCallingPid());
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
@@ -195,7 +194,7 @@
                 requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
                 outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
                 outStableInsets, outsets, outBackdropFrame, cutout,
-                mergedConfiguration, outSurface, outInsetsState);
+                mergedConfiguration, outSurfaceControl, outInsetsState);
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
                 + Binder.getCallingPid());
@@ -432,7 +431,7 @@
 
     @Override
     public void insetsModified(IWindow window, InsetsState state) {
-        synchronized (mService.mWindowMap) {
+        synchronized (mService.mGlobalLock) {
             final WindowState windowState = mService.windowForClientLocked(this, window,
                     false /* throwOnError */);
             if (windowState != null) {
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
deleted file mode 100644
index ada807b..0000000
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ /dev/null
@@ -1,245 +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.wm;
-
-import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
-import static com.android.server.wm.WindowContainer.POSITION_TOP;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.ref.WeakReference;
-
-/**
- * Controller for the stack container. This is created by activity manager to link activity stacks
- * to the stack container they use in window manager.
- *
- * Test class: {@link StackWindowControllerTests}
- */
-public class StackWindowController
-        extends WindowContainerController<TaskStack, StackWindowListener> {
-
-    private final int mStackId;
-
-    private final H mHandler;
-
-    final Rect mTmpBounds = new Rect();
-
-    public StackWindowController(int stackId, StackWindowListener listener, int displayId,
-            boolean onTop, Rect outBounds) {
-        this(stackId, listener, displayId, onTop, outBounds, WindowManagerService.getInstance());
-    }
-
-    @VisibleForTesting
-    public StackWindowController(int stackId, StackWindowListener listener,
-            int displayId, boolean onTop, Rect outBounds, WindowManagerService service) {
-        super(listener, service);
-        mStackId = stackId;
-        mHandler = new H(new WeakReference<>(this), service.mH.getLooper());
-
-        final DisplayContent dc = mRoot.getDisplayContent(displayId);
-        if (dc == null) {
-            throw new IllegalArgumentException("Trying to add stackId=" + stackId
-                    + " to unknown displayId=" + displayId);
-        }
-
-        dc.createStack(stackId, onTop, this);
-        getRawBounds(outBounds);
-    }
-
-    @Override
-    public void removeContainer() {
-        if (mContainer != null) {
-            mContainer.removeIfPossible();
-            super.removeContainer();
-        }
-    }
-
-    void reparent(int displayId, Rect outStackBounds, boolean onTop) {
-        if (mContainer == null) {
-            throw new IllegalArgumentException("Trying to move unknown stackId=" + mStackId
-                    + " to displayId=" + displayId);
-        }
-
-        final DisplayContent targetDc = mRoot.getDisplayContent(displayId);
-        if (targetDc == null) {
-            throw new IllegalArgumentException("Trying to move stackId=" + mStackId
-                    + " to unknown displayId=" + displayId);
-        }
-
-        targetDc.moveStackToDisplay(mContainer, onTop);
-        getRawBounds(outStackBounds);
-    }
-
-    void positionChildAt(Task child, int position) {
-        if (DEBUG_STACK) {
-            Slog.i(TAG_WM, "positionChildAt: positioning task=" + child + " at " + position);
-        }
-        if (child == null) {
-            if (DEBUG_STACK) {
-                Slog.i(TAG_WM, "positionChildAt: could not find task=" + this);
-            }
-            return;
-        }
-        if (mContainer == null) {
-            if (DEBUG_STACK) {
-                Slog.i(TAG_WM, "positionChildAt: could not find stack for task=" + mContainer);
-            }
-            return;
-        }
-        child.positionAt(position);
-        mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
-    }
-
-    void positionChildAtTop(Task child, boolean includingParents) {
-        if (child == null) {
-            // TODO: Fix the call-points that cause this to happen.
-            return;
-        }
-
-        mContainer.positionChildAt(POSITION_TOP, child, includingParents);
-
-        final DisplayContent displayContent = mContainer.getDisplayContent();
-        if (displayContent.mAppTransition.isTransitionSet()) {
-            child.setSendingToBottom(false);
-        }
-        displayContent.layoutAndAssignWindowLayersIfNeeded();
-    }
-
-    void positionChildAtBottom(Task child, boolean includingParents) {
-        if (child == null) {
-            // TODO: Fix the call-points that cause this to happen.
-            return;
-        }
-
-        mContainer.positionChildAt(POSITION_BOTTOM, child, includingParents);
-
-        if (mContainer.getDisplayContent().mAppTransition.isTransitionSet()) {
-            child.setSendingToBottom(true);
-        }
-        mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
-    }
-
-    /**
-     * Re-sizes a stack and its containing tasks.
-     *
-     * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
-     * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
-     * @param taskTempInsetBounds Inset bounds for individual tasks, keyed by task id.
-     */
-    public void resize(Rect bounds, SparseArray<Rect> taskBounds,
-            SparseArray<Rect> taskTempInsetBounds) {
-        if (mContainer == null) {
-            throw new IllegalArgumentException("resizeStack: stack " + this + " not found.");
-        }
-        // We might trigger a configuration change. Save the current task bounds for freezing.
-        mContainer.prepareFreezingTaskBounds();
-        if (mContainer.setBounds(bounds, taskBounds, taskTempInsetBounds)
-                && mContainer.isVisible()) {
-            mContainer.getDisplayContent().setLayoutNeeded();
-            mService.mWindowPlacerLocked.performSurfacePlacement();
-        }
-    }
-
-    public void onPipAnimationEndResize() {
-        mContainer.onPipAnimationEndResize();
-    }
-
-    /**
-     * @see TaskStack.getStackDockedModeBoundsLocked(ConfigurationContainer, Rect, Rect, Rect)
-     */
-    public void getStackDockedModeBounds(Configuration parentConfig, Rect dockedBounds,
-            Rect currentTempTaskBounds,
-            Rect outStackBounds, Rect outTempTaskBounds) {
-        if (mContainer != null) {
-            mContainer.getStackDockedModeBoundsLocked(parentConfig, dockedBounds,
-                    currentTempTaskBounds, outStackBounds, outTempTaskBounds);
-            return;
-        }
-        outStackBounds.setEmpty();
-        outTempTaskBounds.setEmpty();
-    }
-
-    public void prepareFreezingTaskBounds() {
-        if (mContainer == null) {
-            throw new IllegalArgumentException("prepareFreezingTaskBounds: stack " + this
-                    + " not found.");
-        }
-        mContainer.prepareFreezingTaskBounds();
-    }
-
-    public void getRawBounds(Rect outBounds) {
-        if (mContainer.matchParentBounds()) {
-            outBounds.setEmpty();
-        } else {
-            mContainer.getRawBounds(outBounds);
-        }
-    }
-
-    public void getBounds(Rect outBounds) {
-        if (mContainer != null) {
-            mContainer.getBounds(outBounds);
-            return;
-        }
-        outBounds.setEmpty();
-    }
-
-    void requestResize(Rect bounds) {
-        mHandler.obtainMessage(H.REQUEST_RESIZE, bounds).sendToTarget();
-    }
-
-    @Override
-    public String toString() {
-        return "{StackWindowController stackId=" + mStackId + "}";
-    }
-
-    private static final class H extends Handler {
-
-        static final int REQUEST_RESIZE = 0;
-
-        private final WeakReference<StackWindowController> mController;
-
-        H(WeakReference<StackWindowController> controller, Looper looper) {
-            super(looper);
-            mController = controller;
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            final StackWindowController controller = mController.get();
-            final StackWindowListener listener = (controller != null)
-                    ? controller.mListener : null;
-            if (listener == null) {
-                return;
-            }
-            switch (msg.what) {
-                case REQUEST_RESIZE:
-                    listener.requestResize((Rect) msg.obj);
-                    break;
-            }
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/StackWindowListener.java b/services/core/java/com/android/server/wm/StackWindowListener.java
deleted file mode 100644
index c763c17..0000000
--- a/services/core/java/com/android/server/wm/StackWindowListener.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import android.graphics.Rect;
-
-/**
- * Interface used by the creator of {@link StackWindowController} to listen to changes with
- * the stack container.
- */
-public interface StackWindowListener extends WindowContainerListener {
-
-    /** Called when the stack container would like its controller to resize. */
-    void requestResize(Rect bounds);
-}
diff --git a/services/core/java/com/android/server/wm/StatusBarController.java b/services/core/java/com/android/server/wm/StatusBarController.java
index b4de75b..6db606d 100644
--- a/services/core/java/com/android/server/wm/StatusBarController.java
+++ b/services/core/java/com/android/server/wm/StatusBarController.java
@@ -61,9 +61,8 @@
         }
 
         @Override
-        public int onAppTransitionStartingLocked(int transit, IBinder openToken,
-                IBinder closeToken, long duration, long statusBarAnimationStartTime,
-                long statusBarAnimationDuration) {
+        public int onAppTransitionStartingLocked(int transit, long duration,
+                long statusBarAnimationStartTime, long statusBarAnimationDuration) {
             mHandler.post(() -> {
                 StatusBarManagerInternal statusBar = getStatusBarInternal();
                 if (statusBar != null && mWin != null) {
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 11068ce..1a8a911 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -199,7 +199,7 @@
      * @see #setLayer
      */
     void reparent(Transaction t, SurfaceControl newParent) {
-        t.reparent(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), newParent.getHandle());
+        t.reparent(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), newParent);
     }
 
     /**
@@ -228,8 +228,8 @@
 
         // Cancel source animation, but don't let animation runner cancel the animation.
         from.cancelAnimation(t, false /* restarting */, false /* forwardCancel */);
-        t.reparent(surface, mLeash.getHandle());
-        t.reparent(mLeash, parent.getHandle());
+        t.reparent(surface, mLeash);
+        t.reparent(mLeash, parent);
         mAnimatable.onAnimationLeashCreated(t, mLeash);
         mService.mAnimationTransferMap.put(mAnimation, this);
     }
@@ -275,12 +275,12 @@
         final boolean destroy = mLeash != null && surface != null && parent != null;
         if (destroy) {
             if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent");
-            t.reparent(surface, parent.getHandle());
+            t.reparent(surface, parent);
             scheduleAnim = true;
         }
         mService.mAnimationTransferMap.remove(mAnimation);
         if (mLeash != null && destroyLeash) {
-            t.destroy(mLeash);
+            t.reparent(mLeash, null);
             scheduleAnim = true;
         }
         mLeash = null;
@@ -308,7 +308,7 @@
         if (!hidden) {
             t.show(leash);
         }
-        t.reparent(surface, leash.getHandle());
+        t.reparent(surface, leash);
         return leash;
     }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d334bd2..a7dd55b 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -209,26 +209,14 @@
         super.removeImmediately();
     }
 
-    void reparent(StackWindowController stackController, int position, boolean moveParents) {
-        if (DEBUG_STACK) {
-            Slog.i(TAG_WM, "reparent: moving taskId=" + mTaskId
-                    + " to stack=" + stackController + " at " + position);
-        }
-        final TaskStack stack = stackController.mContainer;
-        if (stack == null) {
-            throw new IllegalArgumentException("reparent: could not find stack="
-                    + stackController);
-        }
-        reparent(stack, position, moveParents);
-        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
-    }
-
-
     void reparent(TaskStack stack, int position, boolean moveParents) {
         if (stack == mStack) {
             throw new IllegalArgumentException(
                     "task=" + this + " already child of stack=" + mStack);
         }
+        if (stack == null) {
+            throw new IllegalArgumentException("reparent: could not find stack.");
+        }
         if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
                 + " from stack=" + mStack);
         EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
@@ -254,6 +242,7 @@
             onDisplayChanged(displayContent);
             prevDisplayContent.setLayoutNeeded();
         }
+        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
     }
 
     /** @see ActivityTaskManagerService#positionTaskInStack(int, int, int). */
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 5107b52..f3050a9 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -219,10 +219,16 @@
                 }
             }
 
-            if (launchMode == WINDOWING_MODE_FREEFORM && !currentParams.mBounds.isEmpty()) {
+            if (!currentParams.mBounds.isEmpty()) {
+                // Carry over bounds from callers regardless of launch mode because bounds is still
+                // used to restore last non-fullscreen bounds when launch mode is not freeform.
+                // Therefore it's not a resolution step for non-freeform launch mode and only
+                // consider it fully resolved only when launch mode is freeform.
                 outParams.mBounds.set(currentParams.mBounds);
-                fullyResolvedCurrentParam = true;
-                if (DEBUG) appendLog("inherit-bounds=" + outParams.mBounds);
+                if (launchMode == WINDOWING_MODE_FREEFORM) {
+                    fullyResolvedCurrentParam = true;
+                    if (DEBUG) appendLog("inherit-bounds=" + outParams.mBounds);
+                }
             }
         }
 
@@ -305,6 +311,13 @@
             displayId = optionLaunchId;
         }
 
+        // If the source activity is a no-display activity, pass on the launch display id from
+        // source activity as currently preferred.
+        if (displayId == INVALID_DISPLAY && source != null && source.noDisplay) {
+            displayId = source.mHandoverLaunchDisplayId;
+            if (DEBUG) appendLog("display-from-no-display-source=" + displayId);
+        }
+
         ActivityStack stack =
                 (displayId == INVALID_DISPLAY && task != null) ? task.getStack() : null;
         if (stack != null) {
@@ -696,7 +709,7 @@
 
         final List<TaskRecord> tasksToCheck = new ArrayList<>();
         for (int i = 0; i < display.getChildCount(); ++i) {
-            ActivityStack<?> stack = display.getChildAt(i);
+            final ActivityStack stack = display.getChildAt(i);
             if (!stack.inFreeformWindowingMode()) {
                 continue;
             }
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index e15bf5b..9163165 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -24,6 +24,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.util.Slog;
@@ -50,6 +51,7 @@
     private @Nullable TaskPositioner mTaskPositioner;
 
     private final Rect mTmpClipRect = new Rect();
+    private IBinder mTransferTouchFromToken;
 
     boolean isPositioningLocked() {
         return mTaskPositioner != null;
@@ -102,6 +104,8 @@
 
         mTmpClipRect.set(0, 0, p.x, p.y);
         t.setWindowCrop(mInputSurface, mTmpClipRect);
+        t.transferTouchFocus(mTransferTouchFromToken, h.token);
+        mTransferTouchFromToken = null;
     }
 
     boolean startMovingTask(IWindow window, float startX, float startY) {
@@ -170,7 +174,6 @@
         mPositioningDisplay = displayContent;
 
         mTaskPositioner = TaskPositioner.create(mService);
-        mTaskPositioner.register(displayContent);
 
         // 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
@@ -181,12 +184,8 @@
                 && displayContent.mCurrentFocus.mAppToken == win.mAppToken) {
             transferFocusFromWin = displayContent.mCurrentFocus;
         }
-        if (!mInputManager.transferTouchFocus(
-                transferFocusFromWin.mInputChannel, mTaskPositioner.mServerChannel)) {
-            Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
-            cleanUpTaskPositioner();
-            return false;
-        }
+        mTransferTouchFromToken = transferFocusFromWin.mInputChannel.getToken();
+        mTaskPositioner.register(displayContent);
 
         mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY);
         return true;
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index f1b0c0696..69dcaf4 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -44,6 +44,9 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -452,17 +455,10 @@
         }
 
         final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
-        final StackWindowController stackController = getStack().getWindowContainerController();
+        final TaskStack stack = getStack().getTaskStack();
 
-        if (DEBUG_STACK) {
-            Slog.i(TAG_WM, "TaskRecord: taskId=" + taskId
-                    + " stack=" + stackController + " bounds=" + bounds);
-        }
-
-        final TaskStack stack = stackController.mContainer;
         if (stack == null) {
-            throw new IllegalArgumentException("TaskRecord: invalid stack="
-                    + stackController);
+            throw new IllegalArgumentException("TaskRecord: invalid stack=" + mStack);
         }
         EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId);
         mTask = new Task(taskId, stack, userId, mService.mWindowManager, mResizeMode,
@@ -739,7 +735,7 @@
 
             // Must reparent first in window manager to avoid a situation where AM can delete the
             // we are coming from in WM before we reparent because it became empty.
-            mTask.reparent(toStack.getWindowContainerController(), position,
+            mTask.reparent(toStack.getTaskStack(), position,
                     moveStackMode == REPARENT_MOVE_STACK_TO_FRONT);
 
             final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
@@ -911,7 +907,6 @@
                     info.packageName, info.targetActivity);
             if (_intent != null) {
                 Intent targetIntent = new Intent(_intent);
-                targetIntent.setComponent(targetComponent);
                 targetIntent.setSelector(null);
                 targetIntent.setSourceBounds(null);
                 if (DEBUG_TASKS) Slog.v(TAG_TASKS,
@@ -972,10 +967,11 @@
      */
     boolean isSameIntentFilter(ActivityRecord r) {
         final Intent intent = new Intent(r.intent);
-        // Correct the activity intent for aliasing. The task record intent will always be based on
-        // the real activity that will be launched not the alias, so we need to use an intent with
-        // the component name pointing to the real activity not the alias in the activity record.
-        intent.setComponent(r.mActivityComponent);
+        // Make sure the component are the same if the input activity has the same real activity
+        // as the one in the task because either one of them could be the alias activity.
+        if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) {
+            intent.setComponent(this.intent.getComponent());
+        }
         return intent.filterEquals(this.intent);
     }
 
@@ -1260,10 +1256,6 @@
         setFrontOfTask();
     }
 
-    void addActivityAtBottom(ActivityRecord r) {
-        addActivityAtIndex(0, r);
-    }
-
     void addActivityToTop(ActivityRecord r) {
         addActivityAtIndex(mActivities.size(), r);
     }
@@ -1279,6 +1271,34 @@
     }
 
     /**
+     * Checks if the top activity requires a particular orientation (either by override or
+     * activityInfo) and returns that. Otherwise, this returns ORIENTATION_UNDEFINED.
+     */
+    private int getTopActivityRequestedOrientation() {
+        ActivityRecord top = getTopActivity();
+        if (getRequestedOverrideConfiguration().orientation != ORIENTATION_UNDEFINED
+                || top == null) {
+            return getRequestedOverrideConfiguration().orientation;
+        }
+        int screenOrientation = top.getOrientation();
+        if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
+            // NOSENSOR means the display's "natural" orientation, so return that.
+            ActivityDisplay display = mStack != null ? mStack.getDisplay() : null;
+            if (display != null && display.mDisplayContent != null) {
+                return mStack.getDisplay().mDisplayContent.getNaturalOrientation();
+            }
+        } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
+            // LOCKED means the activity's orientation remains unchanged, so return existing value.
+            return top.getConfiguration().orientation;
+        } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) {
+            return ORIENTATION_LANDSCAPE;
+        } else if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) {
+            return ORIENTATION_PORTRAIT;
+        }
+        return ORIENTATION_UNDEFINED;
+    }
+
+    /**
      * Adds an activity {@param r} at the given {@param index}. The activity {@param r} must either
      * be in the current task or unparented to any task.
      */
@@ -1742,7 +1762,7 @@
         updateTaskDescription();
     }
 
-    private void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
+    void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
         if (bounds == null) {
             return;
         }
@@ -1854,11 +1874,27 @@
 
     @Override
     public void onConfigurationChanged(Configuration newParentConfig) {
+        // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
+        // restore the last recorded non-fullscreen bounds.
+        final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
+        final boolean nextPersistTaskBounds =
+                getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds()
+                || newParentConfig.windowConfiguration.persistTaskBounds();
+        if (!prevPersistTaskBounds && nextPersistTaskBounds
+                && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) {
+            // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop.
+            getRequestedOverrideConfiguration().windowConfiguration
+                    .setBounds(mLastNonFullscreenBounds);
+        }
+
         final boolean wasInMultiWindowMode = inMultiWindowMode();
         super.onConfigurationChanged(newParentConfig);
         if (wasInMultiWindowMode != inMultiWindowMode()) {
             mService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
         }
+
+        // If the configuration supports persistent bounds (eg. Freeform), keep track of the
+        // current (non-fullscreen) bounds for persistence.
         if (getWindowConfiguration().persistTaskBounds()) {
             final Rect currentBounds = getRequestedOverrideBounds();
             if (!currentBounds.isEmpty()) {
@@ -2048,7 +2084,7 @@
      * configuring an "inherit-bounds" window which means that all configuration settings would
      * just be inherited from the parent configuration.
      **/
-    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, @NonNull Rect bounds,
+    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
             @NonNull Configuration parentConfig) {
         int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
@@ -2061,6 +2097,7 @@
         }
         density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
 
+        final Rect bounds = inOutConfig.windowConfiguration.getBounds();
         Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
         if (outAppBounds == null || outAppBounds.isEmpty()) {
             inOutConfig.windowConfiguration.setAppBounds(bounds);
@@ -2108,13 +2145,14 @@
                     // Iterating across all screen orientations, and return the minimum of the task
                     // width taking into account that the bounds might change because the snap
                     // algorithm snaps to a different value
-                    getSmallestScreenWidthDpForDockedBounds(bounds);
+                    inOutConfig.smallestScreenWidthDp =
+                            getSmallestScreenWidthDpForDockedBounds(bounds);
                 }
                 // otherwise, it will just inherit
             }
         }
 
-        if (inOutConfig.orientation == Configuration.ORIENTATION_UNDEFINED) {
+        if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
             inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
                     ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
         }
@@ -2135,36 +2173,56 @@
         }
     }
 
-    // TODO(b/113900640): remove this once ActivityRecord is changed to not need it anymore.
-    void computeResolvedOverrideConfiguration(Configuration inOutConfig, Configuration parentConfig,
-            Configuration overrideConfig) {
-        // Save previous bounds because adjustForMinimalTaskDimensions uses that to determine if it
-        // changes left bound vs. right bound, or top bound vs. bottom bound.
-        mTmpBounds.set(inOutConfig.windowConfiguration.getBounds());
-
-        inOutConfig.setTo(overrideConfig);
-
-        Rect outOverrideBounds = inOutConfig.windowConfiguration.getBounds();
-        if (outOverrideBounds != null && !outOverrideBounds.isEmpty()) {
-            adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
-
-            int windowingMode = overrideConfig.windowConfiguration.getWindowingMode();
-            if (windowingMode == WINDOWING_MODE_UNDEFINED) {
-                windowingMode = parentConfig.windowConfiguration.getWindowingMode();
-            }
-            if (windowingMode == WINDOWING_MODE_FREEFORM) {
-                // by policy, make sure the window remains within parent
-                fitWithinBounds(outOverrideBounds, parentConfig.windowConfiguration.getBounds());
-            }
-
-            computeConfigResourceOverrides(inOutConfig, outOverrideBounds, parentConfig);
-        }
-    }
-
     @Override
     void resolveOverrideConfiguration(Configuration newParentConfig) {
-        computeResolvedOverrideConfiguration(getResolvedOverrideConfiguration(), newParentConfig,
-                getRequestedOverrideConfiguration());
+        mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
+        super.resolveOverrideConfiguration(newParentConfig);
+        int windowingMode =
+                getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode();
+        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+            windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
+        }
+        Rect outOverrideBounds =
+                getResolvedOverrideConfiguration().windowConfiguration.getBounds();
+
+        if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
+            // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent"
+            outOverrideBounds.setEmpty();
+
+            // If the task or its top activity requires a different orientation, make it fit the
+            // available bounds by scaling down its bounds.
+            int forcedOrientation = getTopActivityRequestedOrientation();
+            if (forcedOrientation != ORIENTATION_UNDEFINED
+                    && forcedOrientation != newParentConfig.orientation) {
+                final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
+                final int parentWidth = parentBounds.width();
+                final int parentHeight = parentBounds.height();
+                final float aspect = ((float) parentHeight) / parentWidth;
+                if (forcedOrientation == ORIENTATION_LANDSCAPE) {
+                    final int height = (int) (parentWidth / aspect);
+                    final int top = parentBounds.centerY() - height / 2;
+                    outOverrideBounds.set(
+                            parentBounds.left, top, parentBounds.right, top + height);
+                } else {
+                    final int width = (int) (parentHeight * aspect);
+                    final int left = parentBounds.centerX() - width / 2;
+                    outOverrideBounds.set(
+                            left, parentBounds.top, left + width, parentBounds.bottom);
+                }
+            }
+        }
+
+        if (outOverrideBounds.isEmpty()) {
+            // If the task fills the parent, just inherit all the other configs from parent.
+            return;
+        }
+
+        adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
+        if (windowingMode == WINDOWING_MODE_FREEFORM) {
+            // by policy, make sure the window remains within parent somewhere
+            fitWithinBounds(outOverrideBounds, newParentConfig.windowConfiguration.getBounds());
+        }
+        computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
     }
 
     Rect updateOverrideConfigurationFromLaunchBounds() {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 01a5622..beb3d82 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static com.android.server.wm.TaskSnapshotPersister.DISABLE_FULL_SIZED_BITMAPS;
-import static com.android.server.wm.TaskSnapshotPersister.REDUCED_SCALE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -90,9 +89,8 @@
     private final WindowManagerService mService;
 
     private final TaskSnapshotCache mCache;
-    private final TaskSnapshotPersister mPersister = new TaskSnapshotPersister(
-            Environment::getDataSystemCeDirectory);
-    private final TaskSnapshotLoader mLoader = new TaskSnapshotLoader(mPersister);
+    private final TaskSnapshotPersister mPersister;
+    private final TaskSnapshotLoader mLoader;
     private final ArraySet<Task> mSkipClosingAppSnapshotTasks = new ArraySet<>();
     private final ArraySet<Task> mTmpTasks = new ArraySet<>();
     private final Handler mHandler = new Handler();
@@ -116,6 +114,8 @@
 
     TaskSnapshotController(WindowManagerService service) {
         mService = service;
+        mPersister = new TaskSnapshotPersister(mService, Environment::getDataSystemCeDirectory);
+        mLoader = new TaskSnapshotLoader(mPersister);
         mCache = new TaskSnapshotCache(mService, mLoader);
         mIsRunningOnTv = mService.mContext.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_LEANBACK);
@@ -270,7 +270,7 @@
         }
 
         final boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
-        final float scaleFraction = isLowRamDevice ? REDUCED_SCALE : 1f;
+        final float scaleFraction = isLowRamDevice ? mPersister.getReducedScale() : 1f;
         task.getBounds(mTmpRect);
         mTmpRect.offsetTo(0, 0);
 
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
index 0e1570b..d30843b 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static com.android.server.wm.TaskSnapshotPersister.*;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -92,7 +91,7 @@
                     proto.topActivityComponent);
             return new TaskSnapshot(topActivityComponent, buffer, proto.orientation,
                     new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom),
-                    reducedResolution, reducedResolution ? REDUCED_SCALE : 1f,
+                    reducedResolution, reducedResolution ? mPersister.getReducedScale() : 1f,
                     proto.isRealSnapshot, proto.windowingMode, proto.systemUiVisibility,
                     proto.isTranslucent);
         } catch (IOException e) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 24b5b61..e6d646c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -52,7 +52,9 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotPersister" : TAG_WM;
     private static final String SNAPSHOTS_DIRNAME = "snapshots";
     private static final String REDUCED_POSTFIX = "_reduced";
-    static final float REDUCED_SCALE = ActivityManager.isLowRamDeviceStatic() ? 0.6f : 0.5f;
+    private static final float REDUCED_SCALE = .5f;
+    private static final float LOW_RAM_REDUCED_SCALE = .6f;
+    private static final float LOW_RAM_RECENTS_REDUCED_SCALE = .1f;
     static final boolean DISABLE_FULL_SIZED_BITMAPS = ActivityManager.isLowRamDeviceStatic();
     private static final long DELAY_MS = 100;
     private static final int QUALITY = 95;
@@ -71,6 +73,7 @@
     private boolean mStarted;
     private final Object mLock = new Object();
     private final DirectoryResolver mDirectoryResolver;
+    private final float mReducedScale;
 
     /**
      * The list of ids of the tasks that have been persisted since {@link #removeObsoleteFiles} was
@@ -79,8 +82,16 @@
     @GuardedBy("mLock")
     private final ArraySet<Integer> mPersistedTaskIdsSinceLastRemoveObsolete = new ArraySet<>();
 
-    TaskSnapshotPersister(DirectoryResolver resolver) {
+    TaskSnapshotPersister(WindowManagerService service, DirectoryResolver resolver) {
         mDirectoryResolver = resolver;
+        if (service.mLowRamTaskSnapshotsAndRecents) {
+            // Use very low res snapshots if we are using Go version of recents.
+            mReducedScale = LOW_RAM_RECENTS_REDUCED_SCALE;
+        } else {
+            // TODO(122671846) Replace the low RAM value scale with the above when it is fully built
+            mReducedScale = ActivityManager.isLowRamDeviceStatic()
+                    ? LOW_RAM_REDUCED_SCALE : REDUCED_SCALE;
+        }
     }
 
     /**
@@ -144,6 +155,15 @@
         }
     }
 
+    /**
+     * Gets the scaling the persister uses for low resolution task snapshots.
+     *
+     * @return the reduced scale of task snapshots when they are set to be low res
+     */
+    float getReducedScale() {
+        return mReducedScale;
+    }
+
     @TestApi
     void waitForQueueEmpty() {
         while (true) {
@@ -350,8 +370,8 @@
             final Bitmap reduced = mSnapshot.isReducedResolution()
                     ? swBitmap
                     : Bitmap.createScaledBitmap(swBitmap,
-                            (int) (bitmap.getWidth() * REDUCED_SCALE),
-                            (int) (bitmap.getHeight() * REDUCED_SCALE), true /* filter */);
+                            (int) (bitmap.getWidth() * mReducedScale),
+                            (int) (bitmap.getHeight() * mReducedScale), true /* filter */);
             try {
                 FileOutputStream reducedFos = new FileOutputStream(reducedFile);
                 reduced.compress(JPEG, QUALITY, reducedFos);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 9a56606..2d3e3ae 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -111,6 +111,7 @@
     private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
     private final Window mWindow;
     private final Surface mSurface;
+    private SurfaceControl mSurfaceControl;
     private SurfaceControl mChildSurfaceControl;
     private final IWindowSession mSession;
     private final WindowManagerService mService;
@@ -136,7 +137,7 @@
         final Window window = new Window();
         final IWindowSession session = WindowManagerGlobal.getWindowSession();
         window.setSession(session);
-        final Surface surface = new Surface();
+        final SurfaceControl surfaceControl = new SurfaceControl();
         final Rect tmpRect = new Rect();
         final DisplayCutout.ParcelableWrapper tmpCutout = new DisplayCutout.ParcelableWrapper();
         final Rect tmpFrame = new Rect();
@@ -213,14 +214,14 @@
             // Local call.
         }
         final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
-                surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
+                surfaceControl, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
                 navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds,
                 currentOrientation);
         window.setOuter(snapshotSurface);
         try {
             session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
                     tmpFrame, tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
-                    tmpCutout, tmpMergedConfiguration, surface, mTmpInsetsState);
+                    tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState);
         } catch (RemoteException e) {
             // Local call.
         }
@@ -230,15 +231,16 @@
     }
 
     @VisibleForTesting
-    TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface,
+    TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl,
             TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor,
             int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags,
             Rect taskBounds, int currentOrientation) {
         mService = service;
+        mSurface = new Surface();
         mHandler = new Handler(mService.mH.getLooper());
         mSession = WindowManagerGlobal.getWindowSession();
         mWindow = window;
-        mSurface = surface;
+        mSurfaceControl = surfaceControl;
         mSnapshot = snapshot;
         mTitle = title;
         mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
@@ -281,6 +283,8 @@
 
     private void drawSnapshot() {
         final GraphicBuffer buffer = mSnapshot.getSnapshot();
+        mSurface.copyFrom(mSurfaceControl);
+
         if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Drawing snapshot surface sizeMismatch="
                 + mSizeMismatch);
         if (mSizeMismatch) {
@@ -310,13 +314,14 @@
         if (!mSurface.isValid()) {
             throw new IllegalStateException("mSurface does not hold a valid surface.");
         }
-        final SurfaceSession session = new SurfaceSession(mSurface);
+        final SurfaceSession session = new SurfaceSession();
 
         // Keep a reference to it such that it doesn't get destroyed when finalized.
         mChildSurfaceControl = new SurfaceControl.Builder(session)
                 .setName(mTitle + " - task-snapshot-surface")
                 .setBufferSize(buffer.getWidth(), buffer.getHeight())
                 .setFormat(buffer.getFormat())
+                .setParent(mSurfaceControl)
                 .build();
         Surface surface = new Surface();
         surface.copyFrom(mChildSurfaceControl);
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index ee74bdf..8ed7d04 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -21,6 +21,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
@@ -33,6 +34,10 @@
 import static android.view.WindowManager.DOCKED_RIGHT;
 import static android.view.WindowManager.DOCKED_TOP;
 
+import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
+import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
+import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
+import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS;
 import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME;
@@ -47,10 +52,12 @@
 import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT;
 import static com.android.server.wm.StackProto.TASKS;
 import static com.android.server.wm.StackProto.WINDOW_CONTAINER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.CallSuper;
+import android.app.RemoteAction;
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -71,9 +78,10 @@
 import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
+import java.util.List;
 
 public class TaskStack extends WindowContainer<Task> implements
-        BoundsAnimationTarget {
+        BoundsAnimationTarget, ConfigurationContainerListener {
     /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
      * restrict IME adjustment so that a min portion of top stack remains visible.*/
     private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
@@ -93,6 +101,10 @@
     private Rect mTmpRect2 = new Rect();
     private Rect mTmpRect3 = new Rect();
 
+    /** For Pinned stack controlling. */
+    private Rect mTmpFromBounds = new Rect();
+    private Rect mTmpToBounds = new Rect();
+
     /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
     private final Rect mAdjustedBounds = new Rect();
 
@@ -141,6 +153,9 @@
 
     private Dimmer mDimmer = new Dimmer(this);
 
+    // TODO: remove after unification.
+    ActivityStack mActivityStack;
+
     /**
      * For {@link #prepareSurfaces}.
      */
@@ -150,10 +165,11 @@
     private final AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry =
             new AnimatingAppWindowTokenRegistry();
 
-    TaskStack(WindowManagerService service, int stackId, StackWindowController controller) {
+    TaskStack(WindowManagerService service, int stackId, ActivityStack activityStack) {
         super(service);
         mStackId = stackId;
-        setController(controller);
+        mActivityStack = activityStack;
+        activityStack.registerConfigurationChangeListener(this);
         mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.docked_stack_minimize_thickness);
         EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
@@ -572,6 +588,49 @@
         positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers);
     }
 
+    void positionChildAt(Task child, int position) {
+        if (DEBUG_STACK) {
+            Slog.i(TAG_WM, "positionChildAt: positioning task=" + child + " at " + position);
+        }
+        if (child == null) {
+            if (DEBUG_STACK) {
+                Slog.i(TAG_WM, "positionChildAt: could not find task=" + this);
+            }
+            return;
+        }
+        child.positionAt(position);
+        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+    }
+
+    void positionChildAtTop(Task child, boolean includingParents) {
+        if (child == null) {
+            // TODO: Fix the call-points that cause this to happen.
+            return;
+        }
+
+        positionChildAt(POSITION_TOP, child, includingParents);
+
+        final DisplayContent displayContent = getDisplayContent();
+        if (displayContent.mAppTransition.isTransitionSet()) {
+            child.setSendingToBottom(false);
+        }
+        displayContent.layoutAndAssignWindowLayersIfNeeded();
+    }
+
+    void positionChildAtBottom(Task child, boolean includingParents) {
+        if (child == null) {
+            // TODO: Fix the call-points that cause this to happen.
+            return;
+        }
+
+        positionChildAt(POSITION_BOTTOM, child, includingParents);
+
+        if (getDisplayContent().mAppTransition.isTransitionSet()) {
+            child.setSendingToBottom(true);
+        }
+        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+    }
+
     @Override
     void positionChildAt(int position, Task child, boolean includingParents) {
         positionChildAt(position, child, includingParents, child.showForAllUsers());
@@ -596,6 +655,21 @@
         EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop, targetPosition);
     }
 
+    void reparent(int displayId, Rect outStackBounds, boolean onTop) {
+        final DisplayContent targetDc = mWmService.mRoot.getDisplayContent(displayId);
+        if (targetDc == null) {
+            throw new IllegalArgumentException("Trying to move stackId=" + mStackId
+                    + " to unknown displayId=" + displayId);
+        }
+
+        targetDc.moveStackToDisplay(this, onTop);
+        if (matchParentBounds()) {
+            outStackBounds.setEmpty();
+        } else {
+            getRawBounds(outStackBounds);
+        }
+    }
+
     // TODO: We should really have users as a window container in the hierarchy so that we don't
     // have to do complicated things like we are doing in this method.
     private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers,
@@ -725,6 +799,23 @@
     }
 
     /**
+     * Re-sizes a stack and its containing tasks.
+     *
+     * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
+     * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
+     * @param taskTempInsetBounds Inset bounds for individual tasks, keyed by task id.
+     */
+    void resize(Rect bounds, SparseArray<Rect> taskBounds,
+            SparseArray<Rect> taskTempInsetBounds) {
+        // We might trigger a configuration change. Save the current task bounds for freezing.
+        prepareFreezingTaskBounds();
+        if (setBounds(bounds, taskBounds, taskTempInsetBounds) && isVisible()) {
+            getDisplayContent().setLayoutNeeded();
+            mWmService.mWindowPlacerLocked.performSurfacePlacement();
+        }
+    }
+
+    /**
      * Calculate an amount by which to expand the stack bounds in each direction.
      * Used to make room for shadows in the pinned windowing mode.
      */
@@ -929,12 +1020,7 @@
                 (dockedStack == null || dockedStack == this) ? null : dockedStack.getRawBounds();
         getStackDockedModeBoundsLocked(mDisplayContent.getConfiguration(), dockedBounds,
                 null /* currentTempTaskBounds */, bounds, tempBounds);
-        getController().requestResize(bounds);
-    }
-
-    @Override
-    StackWindowController getController() {
-        return (StackWindowController) super.getController();
+        mActivityStack.requestResize(bounds);
     }
 
     @Override
@@ -947,6 +1033,14 @@
     }
 
     @Override
+    void removeImmediately() {
+        if (mActivityStack != null) {
+            mActivityStack.unregisterConfigurationChangeListener(this);
+        }
+        super.removeImmediately();
+    }
+
+    @Override
     void onParentSet() {
         super.onParentSet();
 
@@ -1572,14 +1666,13 @@
                 // I don't believe you...
             }
 
-            final PinnedStackWindowController controller =
-                    (PinnedStackWindowController) getController();
-            if (schedulePipModeChangedCallback && controller != null) {
+            if (schedulePipModeChangedCallback && mActivityStack != null) {
                 // We need to schedule the PiP mode change before the animation up. It is possible
                 // in this case for the animation down to not have been completed, so always
                 // force-schedule and update to the client to ensure that it is notified that it
                 // is no longer in picture-in-picture mode
-                controller.updatePictureInPictureModeForPinnedStackAnimation(null, forceUpdate);
+                mActivityStack.updatePictureInPictureModeForPinnedStackAnimation(null,
+                        forceUpdate);
             }
         }
         return true;
@@ -1592,12 +1685,10 @@
             // Update to the final bounds if requested. This is done here instead of in the bounds
             // animator to allow us to coordinate this after we notify the PiP mode changed
 
-            final PinnedStackWindowController controller =
-                    (PinnedStackWindowController) getController();
-            if (schedulePipModeChangedCallback && controller != null) {
+            if (schedulePipModeChangedCallback) {
                 // We need to schedule the PiP mode change after the animation down, so use the
                 // final bounds
-                controller.updatePictureInPictureModeForPinnedStackAnimation(
+                mActivityStack.updatePictureInPictureModeForPinnedStackAnimation(
                         mBoundsAnimationTarget, false /* forceUpdate */);
             }
 
@@ -1624,6 +1715,135 @@
         }
     }
 
+    /**
+     * @return the current stack bounds transformed to the given {@param aspectRatio}. If
+     *         the default bounds is {@code null}, then the {@param aspectRatio} is applied to the
+     *         default bounds.
+     */
+    Rect getPictureInPictureBounds(float aspectRatio, Rect stackBounds) {
+        if (!mWmService.mSupportsPictureInPicture) {
+            return null;
+        }
+
+        final DisplayContent displayContent = getDisplayContent();
+        if (displayContent == null) {
+            return null;
+        }
+
+        if (!inPinnedWindowingMode()) {
+            return null;
+        }
+
+        final PinnedStackController pinnedStackController =
+                displayContent.getPinnedStackController();
+        if (stackBounds == null) {
+            // Calculate the aspect ratio bounds from the default bounds
+            stackBounds = pinnedStackController.getDefaultOrLastSavedBounds();
+        }
+
+        if (pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)) {
+            return pinnedStackController.transformBoundsToAspectRatio(stackBounds, aspectRatio,
+                    true /* useCurrentMinEdgeSize */);
+        } else {
+            return stackBounds;
+        }
+    }
+
+    /**
+     * Animates the pinned stack.
+     */
+    void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds,
+            int animationDuration, boolean fromFullscreen) {
+        if (!inPinnedWindowingMode()) {
+            return;
+        }
+        // Get the from-bounds
+        final Rect fromBounds = new Rect();
+        getBounds(fromBounds);
+
+        // Get non-null fullscreen to-bounds for animating if the bounds are null
+        @SchedulePipModeChangedState int schedulePipModeChangedState =
+                NO_PIP_MODE_CHANGED_CALLBACKS;
+        final boolean toFullscreen = toBounds == null;
+        if (toFullscreen) {
+            if (fromFullscreen) {
+                throw new IllegalArgumentException("Should not defer scheduling PiP mode"
+                        + " change on animation to fullscreen.");
+            }
+            schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START;
+
+            mWmService.getStackBounds(
+                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mTmpToBounds);
+            if (!mTmpToBounds.isEmpty()) {
+                // If there is a fullscreen bounds, use that
+                toBounds = new Rect(mTmpToBounds);
+            } else {
+                // Otherwise, use the display bounds
+                toBounds = new Rect();
+                getDisplayContent().getBounds(toBounds);
+            }
+        } else if (fromFullscreen) {
+            schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
+        }
+
+        setAnimationFinalBounds(sourceHintBounds, toBounds, toFullscreen);
+
+        final Rect finalToBounds = toBounds;
+        final @SchedulePipModeChangedState int finalSchedulePipModeChangedState =
+                schedulePipModeChangedState;
+        final DisplayContent displayContent = getDisplayContent();
+        displayContent.mBoundsAnimationController.getHandler().post(() -> {
+            displayContent.mBoundsAnimationController.animateBounds(this, fromBounds,
+                    finalToBounds, animationDuration, finalSchedulePipModeChangedState,
+                    fromFullscreen, toFullscreen);
+        });
+    }
+
+    /**
+     * Sets the current picture-in-picture aspect ratio.
+     */
+    void setPictureInPictureAspectRatio(float aspectRatio) {
+        if (!mWmService.mSupportsPictureInPicture) {
+            return;
+        }
+
+        if (!inPinnedWindowingMode()) {
+            return;
+        }
+
+        final PinnedStackController pinnedStackController =
+                getDisplayContent().getPinnedStackController();
+
+        if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) == 0) {
+            return;
+        }
+        getAnimationOrCurrentBounds(mTmpFromBounds);
+        mTmpToBounds.set(mTmpFromBounds);
+        getPictureInPictureBounds(aspectRatio, mTmpToBounds);
+        if (!mTmpToBounds.equals(mTmpFromBounds)) {
+            animateResizePinnedStack(mTmpToBounds, null /* sourceHintBounds */,
+                    -1 /* duration */, false /* fromFullscreen */);
+        }
+        pinnedStackController.setAspectRatio(
+                pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
+                        ? aspectRatio : -1f);
+    }
+
+    /**
+     * Sets the current picture-in-picture actions.
+     */
+    void setPictureInPictureActions(List<RemoteAction> actions) {
+        if (!mWmService.mSupportsPictureInPicture) {
+            return;
+        }
+
+        if (!inPinnedWindowingMode()) {
+            return;
+        }
+
+        getDisplayContent().getPinnedStackController().setActions(actions);
+    }
+
     @Override
     public boolean isAttached() {
         synchronized (mWmService.mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index b219419..2e5df45 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -31,6 +31,10 @@
 
 import com.android.server.wm.WindowManagerService.H;
 
+/**
+ * 1. Adjust the top most focus display if touch down on some display.
+ * 2. Adjust the pointer icon when cursor moves to the task bounds.
+ */
 public class TaskTapPointerEventListener implements PointerEventListener {
 
     private final Region mTouchExcludeRegion = new Region();
@@ -67,7 +71,7 @@
                     return;
                 }
                 WindowContainer parent = mDisplayContent.getParent();
-                if (parent != null) {
+                if (parent != null && parent.getTopChild() != mDisplayContent) {
                     parent.positionChildAt(WindowContainer.POSITION_TOP, mDisplayContent,
                             true /* includingParents */);
                 }
@@ -80,8 +84,7 @@
         if (motionEvent.getDisplayId() != getDisplayId()) {
             return;
         }
-        final int action = motionEvent.getAction();
-        switch (action & MotionEvent.ACTION_MASK) {
+        switch (motionEvent.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
                 final int x = (int) motionEvent.getX();
                 final int y = (int) motionEvent.getY();
@@ -97,7 +100,7 @@
                 }
             }
             break;
-
+            case MotionEvent.ACTION_HOVER_ENTER:
             case MotionEvent.ACTION_HOVER_MOVE: {
                 final int x = (int) motionEvent.getX();
                 final int y = (int) motionEvent.getY();
@@ -125,6 +128,7 @@
                     mPointerIconType = iconType;
                     if (mPointerIconType == TYPE_NOT_SPECIFIED) {
                         // Find the underlying window and ask it restore the pointer icon.
+                        mService.mH.removeMessages(H.RESTORE_POINTER_ICON);
                         mService.mH.obtainMessage(H.RESTORE_POINTER_ICON,
                                 x, y, mDisplayContent).sendToTarget();
                     } else {
@@ -133,6 +137,18 @@
                 }
             }
             break;
+            case MotionEvent.ACTION_HOVER_EXIT: {
+                final int x = (int) motionEvent.getX();
+                final int y = (int) motionEvent.getY();
+                if (mPointerIconType != TYPE_NOT_SPECIFIED) {
+                    mPointerIconType = TYPE_NOT_SPECIFIED;
+                    // Find the underlying window and ask it to restore the pointer icon.
+                    mService.mH.removeMessages(H.RESTORE_POINTER_ICON);
+                    mService.mH.obtainMessage(H.RESTORE_POINTER_ICON,
+                            x, y, mDisplayContent).sendToTarget();
+                }
+            }
+            break;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 15239c7..c15afc5 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -661,7 +661,8 @@
      * Adjusts the wallpaper windows if the input display has a pending wallpaper layout or one of
      * the opening apps should be a wallpaper target.
      */
-    void adjustWallpaperWindowsForAppTransitionIfNeeded(ArraySet<AppWindowToken> openingApps) {
+    void adjustWallpaperWindowsForAppTransitionIfNeeded(ArraySet<AppWindowToken> openingApps,
+            ArraySet<AppWindowToken> changingApps) {
         boolean adjust = false;
         if ((mDisplayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
             adjust = true;
@@ -673,6 +674,15 @@
                     break;
                 }
             }
+            if (!adjust) {
+                for (int i = changingApps.size() - 1; i >= 0; --i) {
+                    final AppWindowToken token = changingApps.valueAt(i);
+                    if (token.windowsCanBeWallpaperTarget()) {
+                        adjust = true;
+                        break;
+                    }
+                }
+            }
         }
 
         if (adjust) {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index b8a0739..b8db98b 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -167,13 +167,11 @@
                             screenRotationAnimation.kill();
                             displayAnimator.mScreenRotationAnimation = null;
 
-                            //TODO (multidisplay): Accessibility supported only for the default
                             // display.
-                            if (accessibilityController != null && dc.isDefaultDisplay) {
+                            if (accessibilityController != null) {
                                 // We just finished rotation animation which means we did not
                                 // announce the rotation and waited for it to end, announce now.
-                                accessibilityController.onRotationChangedLocked(
-                                        mService.getDefaultDisplayContentLocked());
+                                accessibilityController.onRotationChangedLocked(dc);
                             }
                         }
                     }
@@ -197,9 +195,8 @@
                         screenRotationAnimation.updateSurfaces(mTransaction);
                     }
                     orAnimating(dc.getDockedDividerController().animate(mCurrentTime));
-                    //TODO (multidisplay): Magnification is supported only for the default display.
-                    if (accessibilityController != null && dc.isDefaultDisplay) {
-                        accessibilityController.drawMagnifiedRegionBorderIfNeededLocked();
+                    if (accessibilityController != null) {
+                        accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId);
                     }
                 }
 
diff --git a/services/core/java/com/android/server/wm/WindowChangeAnimationSpec.java b/services/core/java/com/android/server/wm/WindowChangeAnimationSpec.java
new file mode 100644
index 0000000..7dd7c4f
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowChangeAnimationSpec.java
@@ -0,0 +1,203 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.AnimationAdapter.STATUS_BAR_TRANSITION_DURATION;
+import static com.android.server.wm.AnimationSpecProto.WINDOW;
+import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
+
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.util.proto.ProtoOutputStream;
+import android.view.DisplayInfo;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.ClipRectAnimation;
+import android.view.animation.ScaleAnimation;
+import android.view.animation.Transformation;
+import android.view.animation.TranslateAnimation;
+
+import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
+
+import java.io.PrintWriter;
+
+/**
+ * Animation spec for changing window animations.
+ */
+public class WindowChangeAnimationSpec implements AnimationSpec {
+
+    private final ThreadLocal<TmpValues> mThreadLocalTmps = ThreadLocal.withInitial(TmpValues::new);
+    private final boolean mIsAppAnimation;
+    private final Rect mStartBounds;
+    private final Rect mEndBounds;
+    private final Rect mTmpRect = new Rect();
+
+    private Animation mAnimation;
+    private final boolean mIsThumbnail;
+
+    public WindowChangeAnimationSpec(Rect startBounds, Rect endBounds, DisplayInfo displayInfo,
+            long duration, boolean isAppAnimation, boolean isThumbnail) {
+        mStartBounds = new Rect(startBounds);
+        mEndBounds = new Rect(endBounds);
+        mIsAppAnimation = isAppAnimation;
+        mIsThumbnail = isThumbnail;
+        createBoundsInterpolator(duration, displayInfo);
+    }
+
+    @Override
+    public boolean getShowWallpaper() {
+        return false;
+    }
+
+    @Override
+    public int getBackgroundColor() {
+        return 0;
+    }
+
+    @Override
+    public long getDuration() {
+        return mAnimation.getDuration();
+    }
+
+    /**
+     * This animator behaves slightly differently depending on whether the window is growing
+     * or shrinking:
+     * If growing, it will do a clip-reveal after quicker fade-out/scale of the smaller (old)
+     * snapshot.
+     * If shrinking, it will do an opposite clip-reveal on the old snapshot followed by a quicker
+     * fade-out of the bigger (old) snapshot while simultaneously shrinking the new window into
+     * place.
+     * @param duration
+     * @param displayInfo
+     */
+    private void createBoundsInterpolator(long duration, DisplayInfo displayInfo) {
+        boolean growing = mEndBounds.width() - mStartBounds.width()
+                + mEndBounds.height() - mStartBounds.height() >= 0;
+        float scalePart = 0.7f;
+        long scalePeriod = (long) (duration * scalePart);
+        float startScaleX = scalePart * ((float) mStartBounds.width()) / mEndBounds.width()
+                + (1.f - scalePart);
+        float startScaleY = scalePart * ((float) mStartBounds.height()) / mEndBounds.height()
+                + (1.f - scalePart);
+        if (mIsThumbnail) {
+            AnimationSet animSet = new AnimationSet(true);
+            Animation anim = new AlphaAnimation(1.f, 0.f);
+            anim.setDuration(scalePeriod);
+            if (!growing) {
+                anim.setStartOffset(duration - scalePeriod);
+            }
+            animSet.addAnimation(anim);
+            float endScaleX = 1.f / startScaleX;
+            float endScaleY = 1.f / startScaleY;
+            anim = new ScaleAnimation(endScaleX, endScaleX, endScaleY, endScaleY);
+            anim.setDuration(duration);
+            animSet.addAnimation(anim);
+            mAnimation = animSet;
+            mAnimation.initialize(mStartBounds.width(), mStartBounds.height(),
+                    mEndBounds.width(), mEndBounds.height());
+        } else {
+            AnimationSet animSet = new AnimationSet(true);
+            final Animation scaleAnim = new ScaleAnimation(startScaleX, 1, startScaleY, 1);
+            scaleAnim.setDuration(scalePeriod);
+            if (!growing) {
+                scaleAnim.setStartOffset(duration - scalePeriod);
+            }
+            animSet.addAnimation(scaleAnim);
+            final Animation translateAnim = new TranslateAnimation(mStartBounds.left,
+                    mEndBounds.left, mStartBounds.top, mEndBounds.top);
+            translateAnim.setDuration(duration);
+            animSet.addAnimation(translateAnim);
+            Rect startClip = new Rect(mStartBounds);
+            Rect endClip = new Rect(mEndBounds);
+            startClip.offsetTo(0, 0);
+            endClip.offsetTo(0, 0);
+            final Animation clipAnim = new ClipRectAnimation(startClip, endClip);
+            clipAnim.setDuration(duration);
+            animSet.addAnimation(clipAnim);
+            mAnimation = animSet;
+            mAnimation.initialize(mStartBounds.width(), mStartBounds.height(),
+                    displayInfo.appWidth, displayInfo.appHeight);
+        }
+    }
+
+    @Override
+    public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
+        final TmpValues tmp = mThreadLocalTmps.get();
+        if (mIsThumbnail) {
+            mAnimation.getTransformation(currentPlayTime, tmp.mTransformation);
+            t.setMatrix(leash, tmp.mTransformation.getMatrix(), tmp.mFloats);
+            t.setAlpha(leash, tmp.mTransformation.getAlpha());
+        } else {
+            mAnimation.getTransformation(currentPlayTime, tmp.mTransformation);
+            final Matrix matrix = tmp.mTransformation.getMatrix();
+            t.setMatrix(leash, matrix, tmp.mFloats);
+
+            // The following applies an inverse scale to the clip-rect so that it crops "after" the
+            // scale instead of before.
+            tmp.mVecs[1] = tmp.mVecs[2] = 0;
+            tmp.mVecs[0] = tmp.mVecs[3] = 1;
+            matrix.mapVectors(tmp.mVecs);
+            tmp.mVecs[0] = 1.f / tmp.mVecs[0];
+            tmp.mVecs[3] = 1.f / tmp.mVecs[3];
+            final Rect clipRect = tmp.mTransformation.getClipRect();
+            mTmpRect.left = (int) (clipRect.left * tmp.mVecs[0] + 0.5f);
+            mTmpRect.right = (int) (clipRect.right * tmp.mVecs[0] + 0.5f);
+            mTmpRect.top = (int) (clipRect.top * tmp.mVecs[3] + 0.5f);
+            mTmpRect.bottom = (int) (clipRect.bottom * tmp.mVecs[3] + 0.5f);
+            t.setWindowCrop(leash, mTmpRect);
+        }
+    }
+
+    @Override
+    public long calculateStatusBarTransitionStartTime() {
+        long uptime = SystemClock.uptimeMillis();
+        return Math.max(uptime, uptime + ((long) (((float) mAnimation.getDuration()) * 0.99f))
+                - STATUS_BAR_TRANSITION_DURATION);
+    }
+
+    @Override
+    public boolean canSkipFirstFrame() {
+        return false;
+    }
+
+    @Override
+    public boolean needsEarlyWakeup() {
+        return mIsAppAnimation;
+    }
+
+    @Override
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.println(mAnimation.getDuration());
+    }
+
+    @Override
+    public void writeToProtoInner(ProtoOutputStream proto) {
+        final long token = proto.start(WINDOW);
+        proto.write(ANIMATION, mAnimation.toString());
+        proto.end(token);
+    }
+
+    private static class TmpValues {
+        final Transformation mTransformation = new Transformation();
+        final float[] mFloats = new float[9];
+        final float[] mVecs = new float[4];
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 32c5a3b..1905877 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -326,7 +326,7 @@
         }
 
         if (mSurfaceControl != null) {
-            mPendingTransaction.destroy(mSurfaceControl);
+            mPendingTransaction.reparent(mSurfaceControl, null);
 
             // Merge to parent transaction to ensure the transactions on this WindowContainer are
             // applied in native even if WindowContainer is removed.
@@ -437,6 +437,7 @@
                 if (mChildren.peekLast() != child) {
                     mChildren.remove(child);
                     mChildren.add(child);
+                    onChildPositionChanged();
                 }
                 if (includingParents && getParent() != null) {
                     getParent().positionChildAt(POSITION_TOP, this /* child */,
@@ -447,6 +448,7 @@
                 if (mChildren.peekFirst() != child) {
                     mChildren.remove(child);
                     mChildren.addFirst(child);
+                    onChildPositionChanged();
                 }
                 if (includingParents && getParent() != null) {
                     getParent().positionChildAt(POSITION_BOTTOM, this /* child */,
@@ -460,8 +462,8 @@
                 //       doing this adjustment here and remove any adjustments in the callers.
                 mChildren.remove(child);
                 mChildren.add(position, child);
+                onChildPositionChanged();
         }
-        onChildPositionChanged();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 646fdd9..e204697 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -118,8 +118,6 @@
          *
          * @param transit transition type indicating what kind of transition gets run, must be one
          *                of AppTransition.TRANSIT_* values
-         * @param openToken the token for the opening app
-         * @param closeToken the token for the closing app
          * @param duration the total duration of the transition
          * @param statusBarAnimationStartTime the desired start time for all visual animations in
          *        the status bar caused by this app transition in uptime millis
@@ -131,8 +129,8 @@
          * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER},
          * or {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
          */
-        public int onAppTransitionStartingLocked(int transit, IBinder openToken, IBinder closeToken,
-                long duration, long statusBarAnimationStartTime, long statusBarAnimationDuration) {
+        public int onAppTransitionStartingLocked(int transit, long duration,
+                long statusBarAnimationStartTime, long statusBarAnimationDuration) {
             return 0;
         }
 
@@ -158,8 +156,9 @@
         default boolean registerInputChannel(
                 DragState state, Display display, InputManagerService service,
                 InputChannel source) {
+            state.mTransferTouchFromToken = source.getToken();
             state.register(display);
-            return service.transferTouchFocus(source, state.getInputChannel());
+            return true;
         }
 
         /**
@@ -211,34 +210,40 @@
      * and has access to the raw window data while the accessibility layer serves
      * as a controller.
      *
+     * @param displayId The logical display id.
      * @param callbacks The callbacks to invoke.
+     * @return {@code false} if display id is not valid.
      */
-    public abstract void setMagnificationCallbacks(@Nullable MagnificationCallbacks callbacks);
+    public abstract boolean setMagnificationCallbacks(int displayId,
+            @Nullable MagnificationCallbacks callbacks);
 
     /**
      * Set by the accessibility layer to specify the magnification and panning to
      * be applied to all windows that should be magnified.
      *
+     * @param displayId The logical display id.
      * @param spec The MagnficationSpec to set.
      *
-     * @see #setMagnificationCallbacks(MagnificationCallbacks)
+     * @see #setMagnificationCallbacks(int, MagnificationCallbacks)
      */
-    public abstract void setMagnificationSpec(MagnificationSpec spec);
+    public abstract void setMagnificationSpec(int displayId, MagnificationSpec spec);
 
     /**
      * Set by the accessibility framework to indicate whether the magnifiable regions of the display
      * should be shown.
      *
+     * @param displayId The logical display id.
      * @param show {@code true} to show magnifiable region bounds, {@code false} to hide
      */
-    public abstract void setForceShowMagnifiableBounds(boolean show);
+    public abstract void setForceShowMagnifiableBounds(int displayId, boolean show);
 
     /**
      * Obtains the magnification regions.
      *
+     * @param displayId The logical display id.
      * @param magnificationRegion the current magnification region
      */
-    public abstract void getMagnificationRegion(@NonNull Region magnificationRegion);
+    public abstract void getMagnificationRegion(int displayId, @NonNull Region magnificationRegion);
 
     /**
      * Gets the magnification and translation applied to a window given its token.
@@ -250,7 +255,7 @@
      *
      * @return The magnification spec for the window.
      *
-     * @see #setMagnificationCallbacks(MagnificationCallbacks)
+     * @see #setMagnificationCallbacks(int, MagnificationCallbacks)
      */
     public abstract MagnificationSpec getCompatibleMagnificationSpecForWindow(
             IBinder windowToken);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b6a4a51..5eff7d8 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -184,7 +184,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.util.TypedValue;
 import android.util.proto.ProtoOutputStream;
@@ -433,6 +432,13 @@
     final long mDrawLockTimeoutMillis;
     final boolean mAllowAnimationsInLowPowerMode;
 
+    // TODO(b/122671846) Remove the flag below in favor of isLowRam once feature is stable
+    /**
+     * Use very low resolution task snapshots. Replaces task snapshot starting windows with
+     * splashscreen starting windows. Used on low RAM devices to save memory.
+     */
+    final boolean mLowRamTaskSnapshotsAndRecents;
+
     final boolean mAllowBootMessages;
 
     final boolean mLimitedAlphaCompositing;
@@ -717,7 +723,7 @@
 
         void updateSystemUiSettings() {
             boolean changed;
-            synchronized (mWindowMap) {
+            synchronized (mGlobalLock) {
                 changed = ImmersiveModeConfirmation.loadSetting(mCurrentUserId, mContext)
                         || PolicyControl.reloadFromSetting(mContext);
             }
@@ -850,12 +856,12 @@
 
         @Override
         public void onAppTransitionCancelledLocked(int transit) {
-            mH.sendEmptyMessage(H.NOTIFY_APP_TRANSITION_CANCELLED);
+            mAtmInternal.notifyAppTransitionCancelled();
         }
 
         @Override
         public void onAppTransitionFinishedLocked(IBinder token) {
-            mH.sendEmptyMessage(H.NOTIFY_APP_TRANSITION_FINISHED);
+            mAtmInternal.notifyAppTransitionFinished();
             final AppWindowToken atoken = mRoot.getAppWindowToken(token);
             if (atoken == null) {
                 return;
@@ -949,6 +955,8 @@
                 com.android.internal.R.bool.config_disableTransitionAnimation);
         mPerDisplayFocusEnabled = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_perDisplayFocusEnabled);
+        mLowRamTaskSnapshotsAndRecents = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_lowRamTaskSnapshotsAndRecents);
         mInputManager = inputManager; // Must be before createDisplayContentLocked.
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
         mDisplayWindowSettings = new DisplayWindowSettings(this);
@@ -1837,9 +1845,9 @@
         synchronized (mGlobalLock) {
             if (mAccessibilityController != null) {
                 WindowState window = mWindowMap.get(token);
-                //TODO (multidisplay): Magnification is supported only for the default display.
-                if (window != null && window.getDisplayId() == DEFAULT_DISPLAY) {
-                    mAccessibilityController.onRectangleOnScreenRequestedLocked(rectangle);
+                if (window != null) {
+                    mAccessibilityController.onRectangleOnScreenRequestedLocked(
+                            window.getDisplayId(), rectangle);
                 }
             }
         }
@@ -1866,7 +1874,7 @@
             long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
             Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
             DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
-            Surface outSurface, InsetsState outInsetsState) {
+            SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
         int result = 0;
         boolean configChanged;
         final boolean hasStatusBarPermission =
@@ -2039,7 +2047,7 @@
                 result = win.relayoutVisibleWindow(result, attrChanges, oldVisibility);
 
                 try {
-                    result = createSurfaceControl(outSurface, result, win, winAnimator);
+                    result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
                 } catch (Exception e) {
                     displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
 
@@ -2070,7 +2078,7 @@
                     // handled yet, or it might want to draw a last frame. If we already have a
                     // surface, let the client use that, but don't create new surface at this point.
                     Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: getSurface");
-                    winAnimator.mSurfaceController.getSurface(outSurface);
+                    winAnimator.mSurfaceController.getSurfaceControl(outSurfaceControl);
                     Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                 } else {
                     if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
@@ -2078,7 +2086,7 @@
                     try {
                         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmReleaseOutSurface_"
                                 + win.mAttrs.getTitle());
-                        outSurface.release();
+                        outSurfaceControl.release();
                     } finally {
                         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                     }
@@ -2174,7 +2182,7 @@
                 + ", requestedHeight=" + requestedHeight
                 + ", viewVisibility=" + viewVisibility
                 + "\nRelayout returning frame=" + outFrame
-                + ", surface=" + outSurface);
+                + ", surface=" + outSurfaceControl);
 
             if (localLOGV || DEBUG_FOCUS) Slog.v(
                 TAG_WM, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
@@ -2228,8 +2236,7 @@
             win.mDestroying = true;
             win.destroySurface(false, stopped);
         }
-        // TODO(multidisplay): Magnification is supported only for the default display.
-        if (mAccessibilityController != null && win.getDisplayId() == DEFAULT_DISPLAY) {
+        if (mAccessibilityController != null) {
             mAccessibilityController.onWindowTransitionLocked(win, transit);
         }
 
@@ -2244,7 +2251,7 @@
         return focusMayChange;
     }
 
-    private int createSurfaceControl(Surface outSurface, int result, WindowState win,
+    private int createSurfaceControl(SurfaceControl outSurfaceControl, int result, WindowState win,
             WindowStateAnimator winAnimator) {
         if (!win.mHasSurface) {
             result |= RELAYOUT_RES_SURFACE_CHANGED;
@@ -2258,13 +2265,13 @@
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
         if (surfaceController != null) {
-            surfaceController.getSurface(outSurface);
-            if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  OUT SURFACE " + outSurface + ": copied");
+            surfaceController.getSurfaceControl(outSurfaceControl);
+            if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  OUT SURFACE " + outSurfaceControl + ": copied");
         } else {
             // For some reason there isn't a surface.  Clear the
             // caller's object so they see the same state.
             Slog.w(TAG_WM, "Failed to create surface control for " + win);
-            outSurface.release();
+            outSurfaceControl.release();
         }
 
         return result;
@@ -2594,7 +2601,7 @@
 
     @Override
     public void notifyKeyguardTrustedChanged() {
-        mH.sendEmptyMessage(H.NOTIFY_KEYGUARD_TRUSTED_CHANGED);
+        mAtmInternal.notifyKeyguardTrustedChanged();
     }
 
     @Override
@@ -2621,12 +2628,23 @@
     @Override
     public void onUserSwitched() {
         mSettingsObserver.updateSystemUiSettings();
-        synchronized (mWindowMap) {
+        synchronized (mGlobalLock) {
             // force a re-application of focused window sysui visibility on each display.
             mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemUiVisibilityLw);
         }
     }
 
+    @Override
+    public void moveDisplayToTop(int displayId) {
+        synchronized (mGlobalLock) {
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+            if (displayContent != null && mRoot.getTopChild() != displayContent) {
+                mRoot.positionChildAt(WindowContainer.POSITION_TOP, displayContent,
+                        true /* includingParents */);
+            }
+        }
+    }
+
     /**
      * Starts deferring layout passes. Useful when doing multiple changes but to optimize
      * performance, only one layout pass should be done. This can be called multiple times, and
@@ -2643,38 +2661,12 @@
     }
 
     /**
-     * @return true if the activity contains windows that have
-     *         {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set
-     */
-    public boolean containsShowWhenLockedWindow(IBinder token) {
-        synchronized (mGlobalLock) {
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            return wtoken != null && wtoken.containsShowWhenLockedWindow();
-        }
-    }
-
-    /**
-     * @return true if the activity contains windows that have
-     *         {@link LayoutParams#FLAG_DISMISS_KEYGUARD} set
-     */
-    public boolean containsDismissKeyguardWindow(IBinder token) {
-        synchronized (mGlobalLock) {
-            final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
-            return wtoken != null && wtoken.containsDismissKeyguardWindow();
-        }
-    }
-
-    /**
      * Notifies activity manager that some Keyguard flags have changed and that it needs to
      * reevaluate the visibilities of the activities.
      * @param callback Runnable to be called when activity manager is done reevaluating visibilities
      */
     void notifyKeyguardFlagsChanged(@Nullable Runnable callback, int displayId) {
-        final Runnable wrappedCallback = callback != null
-                ? () -> { synchronized (mGlobalLock) { callback.run(); } }
-                : null;
-        mH.obtainMessage(H.NOTIFY_KEYGUARD_FLAGS_CHANGED, displayId, 0,
-                wrappedCallback).sendToTarget();
+        mAtmInternal.notifyKeyguardFlagsChanged(callback, displayId);
     }
 
     public boolean isKeyguardTrusted() {
@@ -4366,16 +4358,10 @@
 
         public static final int WINDOW_REPLACEMENT_TIMEOUT = 46;
 
-        public static final int NOTIFY_APP_TRANSITION_STARTING = 47;
-        public static final int NOTIFY_APP_TRANSITION_CANCELLED = 48;
-        public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
         public static final int UPDATE_ANIMATION_SCALE = 51;
         public static final int WINDOW_HIDE_TIMEOUT = 52;
-        public static final int NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED = 53;
         public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
         public static final int RESTORE_POINTER_ICON = 55;
-        public static final int NOTIFY_KEYGUARD_FLAGS_CHANGED = 56;
-        public static final int NOTIFY_KEYGUARD_TRUSTED_CHANGED = 57;
         public static final int SET_HAS_OVERLAY_UI = 58;
         public static final int SET_RUNNING_REMOTE_ANIMATION = 59;
         public static final int ANIMATION_FAILSAFE = 60;
@@ -4711,19 +4697,6 @@
                     }
                 }
                 break;
-                case NOTIFY_APP_TRANSITION_STARTING: {
-                    mAtmInternal.notifyAppTransitionStarting((SparseIntArray) msg.obj,
-                            msg.getWhen());
-                }
-                break;
-                case NOTIFY_APP_TRANSITION_CANCELLED: {
-                    mAtmInternal.notifyAppTransitionCancelled();
-                }
-                break;
-                case NOTIFY_APP_TRANSITION_FINISHED: {
-                    mAtmInternal.notifyAppTransitionFinished();
-                }
-                break;
                 case WINDOW_HIDE_TIMEOUT: {
                     final WindowState window = (WindowState) msg.obj;
                     synchronized (mGlobalLock) {
@@ -4745,10 +4718,6 @@
                     }
                 }
                 break;
-                case NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED: {
-                    mAtmInternal.notifyDockedStackMinimizedChanged(msg.arg1 == 1);
-                }
-                break;
                 case RESTORE_POINTER_ICON: {
                     synchronized (mGlobalLock) {
                         restorePointerIconLocked((DisplayContent)msg.obj, msg.arg1, msg.arg2);
@@ -4762,14 +4731,6 @@
                     }
                 }
                 break;
-                case NOTIFY_KEYGUARD_FLAGS_CHANGED: {
-                    mAtmInternal.notifyKeyguardFlagsChanged((Runnable) msg.obj, msg.arg1);
-                }
-                break;
-                case NOTIFY_KEYGUARD_TRUSTED_CHANGED: {
-                    mAtmInternal.notifyKeyguardTrustedChanged();
-                }
-                break;
                 case SET_HAS_OVERLAY_UI: {
                     mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1);
                 }
@@ -5730,17 +5691,6 @@
     }
 
     /**
-     * Returns true if the callingUid has any window currently visible to the user.
-     */
-    public boolean isAnyWindowVisibleForUid(int callingUid) {
-        synchronized (mGlobalLock) {
-            return mRoot.forAllWindows(w -> {
-                return w.getOwningUid() == callingUid && w.isVisible();
-            }, true /* traverseTopToBottom */);
-        }
-    }
-
-    /**
      * Called when a task has been removed from the recent tasks list.
      * <p>
      * Note: This doesn't go through {@link TaskWindowContainerController} yet as the window
@@ -5957,8 +5907,6 @@
                     pw.print(" apps="); pw.print(mAppsFreezingScreen);
             final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked();
             pw.print("  mRotation="); pw.print(defaultDisplayContent.getRotation());
-                    pw.print(" mAltOrientation=");
-                            pw.println(defaultDisplayContent.getAltOrientation());
             pw.print("  mLastWindowForcedOrientation=");
                     pw.print(defaultDisplayContent.getLastWindowForcedOrientation());
                     pw.print(" mLastOrientation=");
@@ -6158,7 +6106,7 @@
                     dumpWindowsLocked(pw, true, null);
                 }
                 return;
-            } else if ("all".equals(cmd) || "a".equals(cmd)) {
+            } else if ("all".equals(cmd)) {
                 synchronized (mGlobalLock) {
                     dumpWindowsLocked(pw, true, null);
                 }
@@ -6404,7 +6352,7 @@
     }
 
     void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) {
-        synchronized (mWindowMap) {
+        synchronized (mGlobalLock) {
             mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays;
         }
     }
@@ -6838,10 +6786,10 @@
         }
 
         @Override
-        public void setMagnificationSpec(MagnificationSpec spec) {
+        public void setMagnificationSpec(int displayId, MagnificationSpec spec) {
             synchronized (mGlobalLock) {
                 if (mAccessibilityController != null) {
-                    mAccessibilityController.setMagnificationSpecLocked(spec);
+                    mAccessibilityController.setMagnificationSpecLocked(displayId, spec);
                 } else {
                     throw new IllegalStateException("Magnification callbacks not set!");
                 }
@@ -6852,10 +6800,10 @@
         }
 
         @Override
-        public void setForceShowMagnifiableBounds(boolean show) {
+        public void setForceShowMagnifiableBounds(int displayId, boolean show) {
             synchronized (mGlobalLock) {
                 if (mAccessibilityController != null) {
-                    mAccessibilityController.setForceShowMagnifiableBoundsLocked(show);
+                    mAccessibilityController.setForceShowMagnifiableBoundsLocked(displayId, show);
                 } else {
                     throw new IllegalStateException("Magnification callbacks not set!");
                 }
@@ -6863,10 +6811,11 @@
         }
 
         @Override
-        public void getMagnificationRegion(@NonNull Region magnificationRegion) {
+        public void getMagnificationRegion(int displayId, @NonNull Region magnificationRegion) {
             synchronized (mGlobalLock) {
                 if (mAccessibilityController != null) {
-                    mAccessibilityController.getMagnificationRegionLocked(magnificationRegion);
+                    mAccessibilityController.getMagnificationRegionLocked(displayId,
+                            magnificationRegion);
                 } else {
                     throw new IllegalStateException("Magnification callbacks not set!");
                 }
@@ -6894,16 +6843,19 @@
         }
 
         @Override
-        public void setMagnificationCallbacks(@Nullable MagnificationCallbacks callbacks) {
+        public boolean setMagnificationCallbacks(int displayId,
+                @Nullable MagnificationCallbacks callbacks) {
             synchronized (mGlobalLock) {
                 if (mAccessibilityController == null) {
                     mAccessibilityController = new AccessibilityController(
                             WindowManagerService.this);
                 }
-                mAccessibilityController.setMagnificationCallbacksLocked(callbacks);
+                boolean result = mAccessibilityController.setMagnificationCallbacksLocked(
+                        displayId, callbacks);
                 if (!mAccessibilityController.hasCallbacksLocked()) {
                     mAccessibilityController = null;
                 }
+                return result;
             }
         }
 
@@ -7282,8 +7234,12 @@
         }, false /* traverseTopToBottom */);
     }
 
-    public void applyMagnificationSpec(MagnificationSpec spec) {
-        getDefaultDisplayContentLocked().applyMagnificationSpec(spec);
+    /** Called from Accessibility Controller to apply magnification spec */
+    public void applyMagnificationSpecLocked(int displayId, MagnificationSpec spec) {
+        final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+        if (displayContent != null) {
+            displayContent.applyMagnificationSpec(spec);
+        }
     }
 
     SurfaceControl.Builder makeSurfaceBuilder(SurfaceSession s) {
@@ -7342,7 +7298,7 @@
     }
 
     @Override
-    public void reparentDisplayContent(int displayId, IBinder surfaceControlHandle) {
+    public void reparentDisplayContent(int displayId, SurfaceControl sc) {
         final Display display = mDisplayManager.getDisplay(displayId);
         if (display == null) {
             throw new IllegalArgumentException(
@@ -7359,7 +7315,7 @@
             long token = Binder.clearCallingIdentity();
             try {
                 DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
-                displayContent.reparentDisplayContent(surfaceControlHandle);
+                displayContent.reparentDisplayContent(sc);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index f7f7528..c38a974 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -141,6 +141,9 @@
     private volatile boolean mPerceptible;
     // Set to true when process was launched with a wrapper attached
     private volatile boolean mUsingWrapper;
+    // Set to true if this process is currently temporarily whitelisted to start activities even if
+    // it's not in the foreground
+    private volatile boolean mAllowBackgroundActivityStarts;
 
     // Thread currently set for VR scheduling
     int mVrThreadTid;
@@ -343,6 +346,14 @@
         return mUsingWrapper;
     }
 
+    public void setAllowBackgroundActivityStarts(boolean allowBackgroundActivityStarts) {
+        mAllowBackgroundActivityStarts = allowBackgroundActivityStarts;
+    }
+
+    public boolean areBackgroundActivityStartsAllowed() {
+        return mAllowBackgroundActivityStarts;
+    }
+
     public void setInstrumenting(boolean instrumenting) {
         mInstrumenting = instrumenting;
     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e78c12c..ce5eb84 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1373,12 +1373,15 @@
 
     @Override
     boolean isVisible() {
-        return wouldBeVisibleIfPolicyIgnored() && mPolicyVisibility;
+        return wouldBeVisibleIfPolicyIgnored() && mPolicyVisibility
+                // If we don't have a provider, this window isn't used as a window generating
+                // insets, so nobody can hide it over the inset APIs.
+                && (mInsetProvider == null || mInsetProvider.isClientVisible());
     }
 
     /**
-     * @return True if the window would be visible if we'd ignore policy visibility, false
-     *         otherwise.
+     * @return {@code true} if the window would be visible if we'd ignore policy visibility,
+     *         {@code false} otherwise.
      */
     boolean wouldBeVisibleIfPolicyIgnored() {
         return mHasSurface && !isParentWindowHidden()
@@ -1604,8 +1607,7 @@
                         mWmService.mAccessibilityController;
                 final int winTransit = TRANSIT_EXIT;
                 mWinAnimator.applyAnimationLocked(winTransit, false /* isEntrance */);
-                //TODO (multidisplay): Magnification is supported only for the default
-                if (accessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
+                if (accessibilityController != null) {
                     accessibilityController.onWindowTransitionLocked(this, winTransit);
                 }
             }
@@ -1622,8 +1624,7 @@
 
         if (isVisibleNow()) {
             mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
-            //TODO (multidisplay): Magnification is supported only for the default
-            if (mWmService.mAccessibilityController != null && isDefaultDisplay()) {
+            if (mWmService.mAccessibilityController != null) {
                 mWmService.mAccessibilityController.onWindowTransitionLocked(this, TRANSIT_EXIT);
             }
             changed = true;
@@ -1912,9 +1913,7 @@
                         setDisplayLayoutNeeded();
                         mWmService.requestTraversal();
                     }
-                    //TODO (multidisplay): Magnification is supported only for the default display.
-                    if (mWmService.mAccessibilityController != null
-                            && displayId == DEFAULT_DISPLAY) {
+                    if (mWmService.mAccessibilityController != null) {
                         mWmService.mAccessibilityController.onWindowTransitionLocked(this, transit);
                     }
                 }
@@ -2402,6 +2401,14 @@
                 && !cantReceiveTouchInput();
     }
 
+    @Override
+    public boolean canShowWhenLocked() {
+        final boolean showBecauseOfActivity =
+                mAppToken != null && mAppToken.mActivityRecord.canShowWhenLocked();
+        final boolean showBecauseOfWindow = (getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0;
+        return showBecauseOfActivity || showBecauseOfWindow;
+    }
+
     /** @return false if this window desires touch events. */
     boolean cantReceiveTouchInput() {
         return mAppToken != null && mAppToken.getTask() != null
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index fb5c556..6b4d6d2 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
 import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
@@ -1308,9 +1307,7 @@
             transit = WindowManagerPolicy.TRANSIT_SHOW;
         }
         applyAnimationLocked(transit, true);
-        //TODO (multidisplay): Magnification is supported only for the default display.
-        if (mService.mAccessibilityController != null
-                && mWin.getDisplayId() == DEFAULT_DISPLAY) {
+        if (mService.mAccessibilityController != null) {
             mService.mAccessibilityController.onWindowTransitionLocked(mWin, transit);
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index ce627e2..c2a8e7e 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -478,8 +478,8 @@
         return mSurfaceControl.getHandle();
     }
 
-    void getSurface(Surface outSurface) {
-        outSurface.copyFrom(mSurfaceControl);
+    void getSurfaceControl(SurfaceControl outSurfaceControl) {
+        outSurfaceControl.copyFrom(mSurfaceControl);
     }
 
     int getLayer() {
diff --git a/services/core/java/com/android/server/wm/WindowTraceBuffer.java b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
new file mode 100644
index 0000000..936ee85
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
+
+import android.os.Trace;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Buffer used for window tracing.
+ */
+abstract class WindowTraceBuffer {
+    private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+    final Object mBufferSizeLock = new Object();
+    final BlockingQueue<byte[]> mBuffer;
+    int mBufferSize;
+    private final int mBufferCapacity;
+    private final File mTraceFile;
+
+    WindowTraceBuffer(int size, File traceFile) throws IOException {
+        mBufferCapacity = size;
+        mTraceFile = traceFile;
+        mBuffer = new LinkedBlockingQueue<>();
+
+        initTraceFile();
+    }
+
+    int getAvailableSpace() {
+        return mBufferCapacity - mBufferSize;
+    }
+
+    /**
+     * Inserts the specified element into this buffer.
+     *
+     * This method is synchronized with {@code #take()} and {@code #clear()}
+     * for consistency.
+     *
+     * @param proto the element to add
+     * @return {@code true} if the inserted item was inserted into the buffer
+     * @throws IllegalStateException if the element cannot be added because it is larger
+     *                               than the buffer size.
+     */
+    boolean add(ProtoOutputStream proto) throws InterruptedException {
+        byte[] protoBytes = proto.getBytes();
+        int protoLength = protoBytes.length;
+        if (protoLength > mBufferCapacity) {
+            throw new IllegalStateException("Trace object too large for the buffer. Buffer size:"
+                    + mBufferCapacity + " Object size: " + protoLength);
+        }
+        synchronized (mBufferSizeLock) {
+            boolean canAdd = canAdd(protoBytes);
+            if (canAdd) {
+                mBuffer.offer(protoBytes);
+                mBufferSize += protoLength;
+            }
+            return canAdd;
+        }
+    }
+
+    void writeNextBufferElementToFile() throws IOException {
+        byte[] proto;
+        try {
+            proto = take();
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            return;
+        }
+
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToFile");
+            try (OutputStream os = new FileOutputStream(mTraceFile, true)) {
+                os.write(proto);
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * until an element becomes available.
+     *
+     * This method is synchronized with {@code #add(ProtoOutputStream)} and {@code #clear()}
+     * for consistency.
+     *
+     * @return the head of this buffer, or {@code null} if this buffer is empty
+     */
+    private byte[] take() throws InterruptedException {
+        byte[] item = mBuffer.take();
+        synchronized (mBufferSizeLock) {
+            mBufferSize -= item.length;
+            return item;
+        }
+    }
+
+    private void initTraceFile() throws IOException {
+        mTraceFile.delete();
+        try (OutputStream os = new FileOutputStream(mTraceFile)) {
+            mTraceFile.setReadable(true, false);
+            ProtoOutputStream proto = new ProtoOutputStream(os);
+            proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+            proto.flush();
+        }
+    }
+
+    /**
+     * Checks if the element can be added to the buffer. The element is already certain to be
+     * smaller than the overall buffer size.
+     *
+     * @param protoBytes byte array representation of the Proto object to add
+     * @return <tt>true<</tt> if the element can be added to the buffer or not
+     */
+    abstract boolean canAdd(byte[] protoBytes) throws InterruptedException;
+
+    /**
+     * Flush all buffer content to the disk.
+     *
+     * @throws IOException if the buffer cannot write its contents to the {@link #mTraceFile}
+     */
+    abstract void writeToDisk() throws IOException, InterruptedException;
+
+    /**
+     * Builder for a {@code WindowTraceBuffer} which creates a {@link WindowTraceQueueBuffer}
+     */
+    static class Builder {
+        private File mTraceFile;
+        private int mBufferCapacity;
+
+
+        Builder setTraceFile(File traceFile) {
+            mTraceFile = traceFile;
+            return this;
+        }
+
+        Builder setBufferCapacity(int size) {
+            mBufferCapacity = size;
+            return this;
+        }
+
+        File getFile() {
+            return mTraceFile;
+        }
+
+        WindowTraceBuffer build() throws IOException {
+            if (mBufferCapacity <= 0) {
+                throw new IllegalStateException("Buffer capacity must be greater than 0.");
+            }
+
+            if (mTraceFile == null) {
+                throw new IllegalArgumentException("A valid trace file must be specified.");
+            }
+
+            return new WindowTraceQueueBuffer(mBufferCapacity, mTraceFile);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java b/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
new file mode 100644
index 0000000..b7fc7ac
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.os.Build.IS_USER;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * A buffer structure backed by a {@link java.util.concurrent.BlockingQueue} to store the first
+ * {@code #size size} bytes of window trace elements.
+ * Once the buffer is full it will no longer accepts new elements.
+ */
+class WindowTraceQueueBuffer extends WindowTraceBuffer {
+    private Thread mWriterThread;
+    private boolean mCancel;
+
+    @VisibleForTesting
+    WindowTraceQueueBuffer(int size, File traceFile, boolean startWriterThread) throws IOException {
+        super(size, traceFile);
+        if (startWriterThread) {
+            initializeWriterThread();
+        }
+    }
+
+    WindowTraceQueueBuffer(int size, File traceFile) throws IOException {
+        this(size, traceFile, !IS_USER);
+    }
+
+    private void initializeWriterThread() {
+        mCancel = false;
+        mWriterThread = new Thread(() -> {
+            try {
+                loop();
+            } catch (IOException e) {
+                throw new IllegalStateException("Failed to execute trace write loop thread", e);
+            }
+        }, "window_tracing");
+        mWriterThread.start();
+    }
+
+    private void loop() throws IOException {
+        while (!mCancel) {
+            writeNextBufferElementToFile();
+        }
+    }
+
+    private void restartWriterThread() throws InterruptedException {
+        if (mWriterThread != null) {
+            mCancel = true;
+            mWriterThread.interrupt();
+            mWriterThread.join();
+            initializeWriterThread();
+        }
+    }
+
+    @Override
+    boolean canAdd(byte[] protoBytes) {
+        long availableSpace = getAvailableSpace();
+        return availableSpace >= protoBytes.length;
+    }
+
+    @Override
+    void writeToDisk() throws InterruptedException {
+        while (!mBuffer.isEmpty()) {
+            mBufferSizeLock.wait();
+            mBufferSizeLock.notify();
+        }
+        restartWriterThread();
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index 8fa56bb..63539c4 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -17,31 +17,23 @@
 package com.android.server.wm;
 
 import static android.os.Build.IS_USER;
+
 import static com.android.server.wm.WindowManagerTraceFileProto.ENTRY;
-import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
-import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
-import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
 import static com.android.server.wm.WindowManagerTraceProto.ELAPSED_REALTIME_NANOS;
 import static com.android.server.wm.WindowManagerTraceProto.WHERE;
 import static com.android.server.wm.WindowManagerTraceProto.WINDOW_MANAGER_SERVICE;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.ShellCommand;
 import android.os.SystemClock;
 import android.os.Trace;
-import android.annotation.Nullable;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.OutputStream;
 import java.io.PrintWriter;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
 
 /**
  * A class that allows window manager to dump its state continuously to a trace file, such that a
@@ -49,35 +41,42 @@
  */
 class WindowTracing {
 
+    /**
+     * Maximum buffer size, currently defined as 512 KB
+     * Size was experimentally defined to fit between 100 to 150 elements.
+     */
+    private static final int WINDOW_TRACE_BUFFER_SIZE = 512 * 1024;
     private static final String TAG = "WindowTracing";
-    private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
 
     private final Object mLock = new Object();
-    private final File mTraceFile;
-    private final BlockingQueue<ProtoOutputStream> mWriteQueue = new ArrayBlockingQueue<>(200);
+    private final WindowTraceBuffer.Builder mBufferBuilder;
+
+    private WindowTraceBuffer mTraceBuffer;
 
     private boolean mEnabled;
     private volatile boolean mEnabledLockFree;
 
     WindowTracing(File file) {
-        mTraceFile = file;
+        mBufferBuilder = new WindowTraceBuffer.Builder()
+                .setTraceFile(file)
+                .setBufferCapacity(WINDOW_TRACE_BUFFER_SIZE);
     }
 
     void startTrace(@Nullable PrintWriter pw) throws IOException {
-        if (IS_USER){
+        if (IS_USER) {
             logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
             return;
         }
         synchronized (mLock) {
-            logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
-            mWriteQueue.clear();
-            mTraceFile.delete();
-            try (OutputStream os = new FileOutputStream(mTraceFile)) {
-                mTraceFile.setReadable(true, false);
-                ProtoOutputStream proto = new ProtoOutputStream(os);
-                proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
-                proto.flush();
+            logAndPrintln(pw, "Start tracing to " + mBufferBuilder.getFile() + ".");
+            if (mTraceBuffer != null) {
+                try {
+                    mTraceBuffer.writeToDisk();
+                } catch (InterruptedException e) {
+                    logAndPrintln(pw, "Error: Unable to flush the previous buffer.");
+                }
             }
+            mTraceBuffer = mBufferBuilder.build();
             mEnabled = mEnabledLockFree = true;
         }
     }
@@ -91,67 +90,42 @@
     }
 
     void stopTrace(@Nullable PrintWriter pw) {
-        if (IS_USER){
+        if (IS_USER) {
             logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
             return;
         }
         synchronized (mLock) {
-            logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
+            logAndPrintln(pw, "Stop tracing to " + mBufferBuilder.getFile()
+                    + ". Waiting for traces to flush.");
             mEnabled = mEnabledLockFree = false;
-            while (!mWriteQueue.isEmpty()) {
+
+            synchronized (mLock) {
                 if (mEnabled) {
                     logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
                     throw new IllegalStateException("tracing enabled while waiting for flush.");
                 }
                 try {
-                    mLock.wait();
-                    mLock.notify();
+                    mTraceBuffer.writeToDisk();
+                } catch (IOException e) {
+                    Log.e(TAG, "Unable to write buffer to file", e);
                 } catch (InterruptedException e) {
-                    Thread.currentThread().interrupt();
+                    Log.e(TAG, "Unable to interrupt window tracing file write thread", e);
                 }
             }
-            logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
+            logAndPrintln(pw, "Trace written to " + mBufferBuilder.getFile() + ".");
         }
     }
 
-    void appendTraceEntry(ProtoOutputStream proto) {
+    private void appendTraceEntry(ProtoOutputStream proto) {
         if (!mEnabledLockFree) {
             return;
         }
 
-        if (!mWriteQueue.offer(proto)) {
-            Log.e(TAG, "Dropping window trace entry, queue full");
-        }
-    }
-
-    void loop() {
-        for (;;) {
-            loopOnce();
-        }
-    }
-
-    @VisibleForTesting
-    void loopOnce() {
-        ProtoOutputStream proto;
         try {
-            proto = mWriteQueue.take();
+            mTraceBuffer.add(proto);
         } catch (InterruptedException e) {
+            Log.e(TAG, "Unable to add element to trace", e);
             Thread.currentThread().interrupt();
-            return;
-        }
-
-        synchronized (mLock) {
-            try {
-                Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToFile");
-                try (OutputStream os = new FileOutputStream(mTraceFile, true /* append */)) {
-                    os.write(proto.getBytes());
-                }
-            } catch (IOException e) {
-                Log.e(TAG, "Failed to write file " + mTraceFile, e);
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
-            }
-            mLock.notify();
         }
     }
 
@@ -161,11 +135,7 @@
 
     static WindowTracing createDefaultAndStartLooper(Context context) {
         File file = new File("/data/misc/wmtrace/wm_trace.pb");
-        WindowTracing windowTracing = new WindowTracing(file);
-        if (!IS_USER){
-            new Thread(windowTracing::loop, "window_tracing").start();
-        }
-        return windowTracing;
+        return new WindowTracing(file);
     }
 
     int onShellCommand(ShellCommand shell, String cmd) {
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index b4fe837..3729eaf 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -53,6 +53,7 @@
     ],
 
     include_dirs: [
+        "bionic/libc/private",
         "frameworks/base/libs",
         "frameworks/native/services",
         "system/gatekeeper/include",
@@ -107,6 +108,8 @@
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@2.0",
+        "android.hardware.gnss.visibility_control@1.0",
+        "android.hardware.input.classifier@1.0",
         "android.hardware.ir@1.0",
         "android.hardware.light@2.0",
         "android.hardware.power@1.0",
@@ -119,6 +122,7 @@
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
+        "android.hardware.vibrator@1.3",
         "android.hardware.vr@1.0",
         "android.frameworks.schedulerservice@1.0",
         "android.frameworks.sensorservice@1.0",
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index dc0d53b..159a496 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -24,6 +24,8 @@
 #include <sensorservice/SensorService.h>
 #include <sensorservicehidl/SensorManager.h>
 
+#include <bionic_malloc.h>
+
 #include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/misc.h>
@@ -64,6 +66,11 @@
     ALOGE_IF(err != OK, "Cannot register %s: %d", ISchedulingPolicyService::descriptor, err);
 }
 
+static void android_server_SystemServer_initZygoteChildHeapProfiling(JNIEnv* /* env */,
+                                                                     jobject /* clazz */) {
+   android_mallopt(M_INIT_ZYGOTE_CHILD_PROFILING, nullptr, 0);
+}
+
 /*
  * JNI registration.
  */
@@ -71,6 +78,8 @@
     /* name, signature, funcPtr */
     { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService },
     { "startHidlServices", "()V", (void*) android_server_SystemServer_startHidlServices },
+    { "initZygoteChildHeapProfiling", "()V",
+      (void*) android_server_SystemServer_initZygoteChildHeapProfiling },
 };
 
 int register_android_server_SystemServer(JNIEnv* env)
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index defcfd9..63dca62 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -22,6 +22,7 @@
 #include <android/hardware/vibrator/1.1/types.h>
 #include <android/hardware/vibrator/1.2/IVibrator.h>
 #include <android/hardware/vibrator/1.2/types.h>
+#include <android/hardware/vibrator/1.3/IVibrator.h>
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
@@ -42,6 +43,7 @@
 namespace V1_0 = android::hardware::vibrator::V1_0;
 namespace V1_1 = android::hardware::vibrator::V1_1;
 namespace V1_2 = android::hardware::vibrator::V1_2;
+namespace V1_3 = android::hardware::vibrator::V1_3;
 
 namespace android {
 
@@ -136,6 +138,19 @@
     }
 }
 
+static jboolean vibratorSupportsExternalControl(JNIEnv*, jobject) {
+    return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false);
+}
+
+static void vibratorSetExternalControl(JNIEnv*, jobject, jboolean enabled) {
+    Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled))
+        .withDefault(Status::UNKNOWN_ERROR);
+    if (status != Status::OK) {
+      ALOGE("Failed to set vibrator external control (%" PRIu32 ").",
+            static_cast<uint32_t>(status));
+    }
+}
+
 static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength) {
     Status status;
     uint32_t lengthMs;
@@ -187,7 +202,9 @@
     { "vibratorOff", "()V", (void*)vibratorOff },
     { "vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl},
     { "vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude},
-    { "vibratorPerformEffect", "(JJ)J", (void*)vibratorPerformEffect}
+    { "vibratorPerformEffect", "(JJ)J", (void*)vibratorPerformEffect},
+    { "vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl},
+    { "vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl},
 };
 
 int register_android_server_VibratorService(JNIEnv *env)
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 43d2dcf..ff0b0d6 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -107,9 +107,11 @@
     jmethodID getLongPressTimeout;
     jmethodID getPointerLayer;
     jmethodID getPointerIcon;
+    jmethodID getPointerDisplayId;
     jmethodID getKeyboardLayoutOverlay;
     jmethodID getDeviceAlias;
     jmethodID getTouchCalibrationForInputDevice;
+    jmethodID getContextForDisplay;
 } gServiceClassInfo;
 
 static struct {
@@ -174,15 +176,6 @@
     loadSystemIconAsSpriteWithPointerIcon(env, contextObj, style, &pointerIcon, outSpriteIcon);
 }
 
-static void updatePointerControllerFromViewport(
-        sp<PointerController> controller, const DisplayViewport* const viewport) {
-    if (controller != nullptr && viewport != nullptr) {
-        const int32_t width = viewport->logicalRight - viewport->logicalLeft;
-        const int32_t height = viewport->logicalBottom - viewport->logicalTop;
-        controller->setDisplayViewport(width, height, viewport->orientation);
-    }
-}
-
 enum {
     WM_ACTION_PASS_TO_USER = 1,
 };
@@ -252,7 +245,7 @@
             const sp<IBinder>& token,
             const std::string& reason);
     virtual void notifyInputChannelBroken(const sp<IBinder>& token);
-    virtual void notifyFocusChanged(const sp<IBinder>& token);
+    virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken);
     virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
     virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
@@ -268,17 +261,16 @@
 
     /* --- PointerControllerPolicyInterface implementation --- */
 
-    virtual void loadPointerIcon(SpriteIcon* icon);
-    virtual void loadPointerResources(PointerResources* outResources);
+    virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId);
+    virtual void loadPointerResources(PointerResources* outResources, int32_t displayId);
     virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
-            std::map<int32_t, PointerAnimation>* outAnimationResources);
+            std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId);
     virtual int32_t getDefaultPointerIconId();
     virtual int32_t getCustomPointerIconId();
 
 private:
     sp<InputManager> mInputManager;
 
-    jobject mContextObj;
     jobject mServiceObj;
     sp<Looper> mLooper;
 
@@ -310,14 +302,19 @@
 
         // Input devices to be disabled
         SortedVector<int32_t> disabledInputDevices;
+
+        // Associated Pointer controller display.
+        int32_t pointerDisplayId;
     } mLocked GUARDED_BY(mLock);
 
     std::atomic<bool> mInteractive;
 
-    void updateInactivityTimeoutLocked(const sp<PointerController>& controller);
+    void updateInactivityTimeoutLocked();
     void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
     void ensureSpriteControllerLocked();
-
+    const DisplayViewport* findDisplayViewportLocked(int32_t displayId);
+    int32_t getPointerDisplayId();
+    void updatePointerDisplayLocked();
     static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
 
     static inline JNIEnv* jniEnv() {
@@ -332,7 +329,6 @@
         mLooper(looper), mInteractive(true) {
     JNIEnv* env = jniEnv();
 
-    mContextObj = env->NewGlobalRef(contextObj);
     mServiceObj = env->NewGlobalRef(serviceObj);
 
     {
@@ -342,6 +338,7 @@
         mLocked.pointerGesturesEnabled = true;
         mLocked.showTouches = false;
         mLocked.pointerCapture = false;
+        mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
     }
     mInteractive = true;
 
@@ -353,7 +350,6 @@
 NativeInputManager::~NativeInputManager() {
     JNIEnv* env = jniEnv();
 
-    env->DeleteGlobalRef(mContextObj);
     env->DeleteGlobalRef(mServiceObj);
 }
 
@@ -391,9 +387,10 @@
     return false;
 }
 
-static const DisplayViewport* findInternalViewport(const std::vector<DisplayViewport>& viewports) {
-    for (const DisplayViewport& v : viewports) {
-        if (v.type == ViewportType::VIEWPORT_INTERNAL) {
+const DisplayViewport* NativeInputManager::findDisplayViewportLocked(int32_t displayId)
+        REQUIRES(mLock) {
+    for (const DisplayViewport& v : mLocked.viewports) {
+        if (v.displayId == displayId) {
             return &v;
         }
     }
@@ -420,20 +417,14 @@
         }
     }
 
-    const DisplayViewport* newInternalViewport = findInternalViewport(viewports);
-    {
+    // Get the preferred pointer controller displayId.
+    int32_t pointerDisplayId = getPointerDisplayId();
+
+    { // acquire lock
         AutoMutex _l(mLock);
-        const DisplayViewport* oldInternalViewport = findInternalViewport(mLocked.viewports);
-        // Internal viewport has changed if there wasn't one earlier, and there is one now, or,
-        // if they are different.
-        const bool internalViewportChanged = (newInternalViewport != nullptr) &&
-                (oldInternalViewport == nullptr || (*oldInternalViewport != *newInternalViewport));
-        if (internalViewportChanged) {
-            sp<PointerController> controller = mLocked.pointerController.promote();
-            updatePointerControllerFromViewport(controller, newInternalViewport);
-        }
         mLocked.viewports = viewports;
-    }
+        mLocked.pointerDisplayId = pointerDisplayId;
+    } // release lock
 
     mInputManager->getReader()->requestRefreshConfiguration(
             InputReaderConfiguration::CHANGE_DISPLAY_INFO);
@@ -556,15 +547,42 @@
 
         controller = new PointerController(this, mLooper, mLocked.spriteController);
         mLocked.pointerController = controller;
-
-        const DisplayViewport* internalViewport = findInternalViewport(mLocked.viewports);
-        updatePointerControllerFromViewport(controller, internalViewport);
-
-        updateInactivityTimeoutLocked(controller);
+        updateInactivityTimeoutLocked();
     }
+
+    updatePointerDisplayLocked();
+
     return controller;
 }
 
+int32_t NativeInputManager::getPointerDisplayId() {
+    JNIEnv* env = jniEnv();
+    jint pointerDisplayId = env->CallIntMethod(mServiceObj,
+            gServiceClassInfo.getPointerDisplayId);
+    if (checkAndClearExceptionFromCallback(env, "getPointerDisplayId")) {
+        pointerDisplayId = ADISPLAY_ID_DEFAULT;
+    }
+
+    return pointerDisplayId;
+}
+
+void NativeInputManager::updatePointerDisplayLocked() REQUIRES(mLock) {
+    ATRACE_CALL();
+
+    sp<PointerController> controller = mLocked.pointerController.promote();
+    if (controller != nullptr) {
+        const DisplayViewport* viewport = findDisplayViewportLocked(mLocked.pointerDisplayId);
+        if (viewport == nullptr) {
+            ALOGW("Can't find pointer display viewport, fallback to default display.");
+            viewport = findDisplayViewportLocked(ADISPLAY_ID_DEFAULT);
+        }
+
+        if (viewport != nullptr) {
+            controller->setDisplayViewport(*viewport);
+        }
+    }
+}
+
 void NativeInputManager::ensureSpriteControllerLocked() REQUIRES(mLock) {
     if (mLocked.spriteController == nullptr) {
         JNIEnv* env = jniEnv();
@@ -718,7 +736,8 @@
     }
 }
 
-void NativeInputManager::notifyFocusChanged(const sp<IBinder>& token) {
+void NativeInputManager::notifyFocusChanged(const sp<IBinder>& oldToken,
+        const sp<IBinder>& newToken) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
     ALOGD("notifyFocusChanged");
 #endif
@@ -726,12 +745,11 @@
 
     JNIEnv* env = jniEnv();
 
-    jobject tokenObj = javaObjectForIBinder(env, token);
-    if (tokenObj) {
-        env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyFocusChanged,
-                tokenObj);
-        checkAndClearExceptionFromCallback(env, "notifyFocusChanged");
-    }
+    jobject oldTokenObj = javaObjectForIBinder(env, oldToken);
+    jobject newTokenObj = javaObjectForIBinder(env, newToken);
+    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyFocusChanged,
+            oldTokenObj, newTokenObj);
+    checkAndClearExceptionFromCallback(env, "notifyFocusChanged");
 }
 
 void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
@@ -764,7 +782,7 @@
             }
 
             sp<InputWindowHandle> windowHandle =
-                    android_server_InputWindowHandle_getHandle(env, windowHandleObj);
+                    android_view_InputWindowHandle_getHandle(env, windowHandleObj);
             if (windowHandle != nullptr) {
                 windowHandles.push(windowHandle);
             }
@@ -804,7 +822,7 @@
 void NativeInputManager::setFocusedApplication(JNIEnv* env, int32_t displayId,
         jobject applicationHandleObj) {
     sp<InputApplicationHandle> applicationHandle =
-            android_server_InputApplicationHandle_getHandle(env, applicationHandleObj);
+            android_view_InputApplicationHandle_getHandle(env, applicationHandleObj);
     mInputManager->getDispatcher()->setFocusedApplication(displayId, applicationHandle);
 }
 
@@ -821,16 +839,16 @@
 
     if (mLocked.systemUiVisibility != visibility) {
         mLocked.systemUiVisibility = visibility;
-
-        sp<PointerController> controller = mLocked.pointerController.promote();
-        if (controller != nullptr) {
-            updateInactivityTimeoutLocked(controller);
-        }
+        updateInactivityTimeoutLocked();
     }
 }
 
-void NativeInputManager::updateInactivityTimeoutLocked(const sp<PointerController>& controller)
-        REQUIRES(mLock) {
+void NativeInputManager::updateInactivityTimeoutLocked() REQUIRES(mLock) {
+    sp<PointerController> controller = mLocked.pointerController.promote();
+    if (controller == nullptr) {
+        return;
+    }
+
     bool lightsOut = mLocked.systemUiVisibility & ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN;
     controller->setInactivityTimeout(lightsOut
             ? PointerController::INACTIVITY_TIMEOUT_SHORT
@@ -1182,19 +1200,22 @@
     return result;
 }
 
-void NativeInputManager::loadPointerIcon(SpriteIcon* icon) {
+void NativeInputManager::loadPointerIcon(SpriteIcon* icon, int32_t displayId) {
     ATRACE_CALL();
     JNIEnv* env = jniEnv();
 
     ScopedLocalRef<jobject> pointerIconObj(env, env->CallObjectMethod(
-            mServiceObj, gServiceClassInfo.getPointerIcon));
+            mServiceObj, gServiceClassInfo.getPointerIcon, displayId));
     if (checkAndClearExceptionFromCallback(env, "getPointerIcon")) {
         return;
     }
 
+    ScopedLocalRef<jobject> displayContext(env, env->CallObjectMethod(
+            mServiceObj, gServiceClassInfo.getContextForDisplay, displayId));
+
     PointerIcon pointerIcon;
     status_t status = android_view_PointerIcon_load(env, pointerIconObj.get(),
-                                                    mContextObj, &pointerIcon);
+            displayContext.get(), &pointerIcon);
     if (!status && !pointerIcon.isNullIcon()) {
         *icon = SpriteIcon(pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY);
     } else {
@@ -1202,28 +1223,34 @@
     }
 }
 
-void NativeInputManager::loadPointerResources(PointerResources* outResources) {
+void NativeInputManager::loadPointerResources(PointerResources* outResources, int32_t displayId) {
     ATRACE_CALL();
     JNIEnv* env = jniEnv();
 
-    loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_HOVER,
+    ScopedLocalRef<jobject> displayContext(env, env->CallObjectMethod(
+            mServiceObj, gServiceClassInfo.getContextForDisplay, displayId));
+
+    loadSystemIconAsSprite(env, displayContext.get(), POINTER_ICON_STYLE_SPOT_HOVER,
             &outResources->spotHover);
-    loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_TOUCH,
+    loadSystemIconAsSprite(env, displayContext.get(), POINTER_ICON_STYLE_SPOT_TOUCH,
             &outResources->spotTouch);
-    loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_ANCHOR,
+    loadSystemIconAsSprite(env, displayContext.get(), POINTER_ICON_STYLE_SPOT_ANCHOR,
             &outResources->spotAnchor);
 }
 
 void NativeInputManager::loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
-        std::map<int32_t, PointerAnimation>* outAnimationResources) {
+        std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) {
     ATRACE_CALL();
     JNIEnv* env = jniEnv();
 
+    ScopedLocalRef<jobject> displayContext(env, env->CallObjectMethod(
+            mServiceObj, gServiceClassInfo.getContextForDisplay, displayId));
+
     for (int iconId = POINTER_ICON_STYLE_CONTEXT_MENU; iconId <= POINTER_ICON_STYLE_GRABBING;
              ++iconId) {
         PointerIcon pointerIcon;
         loadSystemIconAsSpriteWithPointerIcon(
-                env, mContextObj, iconId, &pointerIcon, &((*outResources)[iconId]));
+                env, displayContext.get(), iconId, &pointerIcon, &((*outResources)[iconId]));
         if (!pointerIcon.bitmapFrames.empty()) {
             PointerAnimation& animationData = (*outAnimationResources)[iconId];
             size_t numFrames = pointerIcon.bitmapFrames.size() + 1;
@@ -1238,7 +1265,7 @@
             }
         }
     }
-    loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_NULL,
+    loadSystemIconAsSprite(env, displayContext.get(), POINTER_ICON_STYLE_NULL,
             &((*outResources)[POINTER_ICON_STYLE_NULL]));
 }
 
@@ -1480,27 +1507,6 @@
     im->setSystemUiVisibility(visibility);
 }
 
-static jboolean nativeTransferTouchFocus(JNIEnv* env,
-        jclass /* clazz */, jlong ptr, jobject fromChannelObj, jobject toChannelObj) {
-    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
-
-    sp<InputChannel> fromChannel =
-            android_view_InputChannel_getInputChannel(env, fromChannelObj);
-    sp<InputChannel> toChannel =
-            android_view_InputChannel_getInputChannel(env, toChannelObj);
-
-    if (fromChannel == nullptr || toChannel == nullptr) {
-        return JNI_FALSE;
-    }
-
-    if (im->getInputManager()->getDispatcher()->
-            transferTouchFocus(fromChannel, toChannel)) {
-        return JNI_TRUE;
-    } else {
-        return JNI_FALSE;
-    }
-}
-
 static void nativeSetPointerSpeed(JNIEnv* /* env */,
         jclass /* clazz */, jlong ptr, jint speed) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -1688,8 +1694,6 @@
             (void*) nativeSetInputDispatchMode },
     { "nativeSetSystemUiVisibility", "(JI)V",
             (void*) nativeSetSystemUiVisibility },
-    { "nativeTransferTouchFocus", "(JLandroid/view/InputChannel;Landroid/view/InputChannel;)Z",
-            (void*) nativeTransferTouchFocus },
     { "nativeSetPointerSpeed", "(JI)V",
             (void*) nativeSetPointerSpeed },
     { "nativeSetShowTouches", "(JZ)V",
@@ -1765,7 +1769,7 @@
             "notifyInputChannelBroken", "(Landroid/os/IBinder;)V");
     
     GET_METHOD_ID(gServiceClassInfo.notifyFocusChanged, clazz,
-            "notifyFocusChanged", "(Landroid/os/IBinder;)V");
+            "notifyFocusChanged", "(Landroid/os/IBinder;Landroid/os/IBinder;)V");
 
     GET_METHOD_ID(gServiceClassInfo.notifyANR, clazz,
             "notifyANR",
@@ -1822,7 +1826,10 @@
             "getPointerLayer", "()I");
 
     GET_METHOD_ID(gServiceClassInfo.getPointerIcon, clazz,
-            "getPointerIcon", "()Landroid/view/PointerIcon;");
+            "getPointerIcon", "(I)Landroid/view/PointerIcon;");
+
+    GET_METHOD_ID(gServiceClassInfo.getPointerDisplayId, clazz,
+            "getPointerDisplayId", "()I");
 
     GET_METHOD_ID(gServiceClassInfo.getKeyboardLayoutOverlay, clazz,
             "getKeyboardLayoutOverlay",
@@ -1835,6 +1842,10 @@
             "getTouchCalibrationForInputDevice",
             "(Ljava/lang/String;I)Landroid/hardware/input/TouchCalibration;");
 
+    GET_METHOD_ID(gServiceClassInfo.getContextForDisplay, clazz,
+            "getContextForDisplay",
+            "(I)Landroid/content/Context;")
+
     // InputDevice
 
     FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 6d8fc1c..f3c19d0 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -26,6 +26,7 @@
 #include <android/hardware/gnss/1.1/IGnssMeasurement.h>
 #include <android/hardware/gnss/2.0/IGnssMeasurement.h>
 #include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
 #include <nativehelper/JNIHelp.h>
 #include "jni.h"
 #include "hardware_legacy/power.h"
@@ -80,7 +81,7 @@
 static jmethodID method_correctionSatConstType;
 static jmethodID method_correctionSatId;
 static jmethodID method_correctionSatCarrierFreq;
-static jmethodID method_correctionSatIsLos;
+static jmethodID method_correctionSatIsLosProb;
 static jmethodID method_correctionSatEpl;
 static jmethodID method_correctionSatEplUnc;
 static jmethodID method_correctionSatRefPlane;
@@ -88,6 +89,8 @@
 static jmethodID method_correctionPlaneLngDeg;
 static jmethodID method_correctionPlaneAltDeg;
 static jmethodID method_correctionPlaneAzimDeg;
+static jmethodID method_reportNfwNotification;
+static jmethodID method_isInEmergencySession;
 
 /*
  * Save a pointer to JavaVm to attach/detach threads executing
@@ -135,6 +138,7 @@
 using IGnss_V2_0 = android::hardware::gnss::V2_0::IGnss;
 using IGnssConfiguration_V1_0 = android::hardware::gnss::V1_0::IGnssConfiguration;
 using IGnssConfiguration_V1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
+using IGnssConfiguration_V2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
 using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
 using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
 using IGnssMeasurement_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
@@ -151,6 +155,9 @@
 using IMeasurementCorrections =
     android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
 
+using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl;
+using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback;
+
 struct GnssDeathRecipient : virtual public hidl_death_recipient
 {
     // hidl_death_recipient interface
@@ -179,6 +186,7 @@
 sp<IGnssDebug> gnssDebugIface = nullptr;
 sp<IGnssConfiguration_V1_0> gnssConfigurationIface = nullptr;
 sp<IGnssConfiguration_V1_1> gnssConfigurationIface_V1_1 = nullptr;
+sp<IGnssConfiguration_V2_0> gnssConfigurationIface_V2_0 = nullptr;
 sp<IGnssNi> gnssNiIface = nullptr;
 sp<IGnssMeasurement_V1_0> gnssMeasurementIface = nullptr;
 sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr;
@@ -188,7 +196,7 @@
 // This boolean is needed to ensure that Gnsss Measurement Corrections related method are only
 // initalized when needed which will be few devices initially
 bool firstGnssMeasurementCorrectionInjected = false;
-
+sp<IGnssVisibilityControl> gnssVisibilityControlIface = nullptr;
 
 #define WAKE_LOCK_NAME  "GPS"
 
@@ -313,6 +321,15 @@
     }
 }
 
+static jobject createHalInterfaceVersionJavaObject(JNIEnv* env, jint major, jint minor) {
+    jclass versionClass =
+            env->FindClass("com/android/server/location/GnssConfiguration$HalInterfaceVersion");
+    jmethodID versionCtor = env->GetMethodID(versionClass, "<init>", "(II)V");
+    jobject version = env->NewObject(versionClass, versionCtor, major, minor);
+    env->DeleteLocalRef(versionClass);
+    return version;
+}
+
 struct ScopedJniString {
     ScopedJniString(JNIEnv* env, jstring javaString) : mEnv(env), mJavaString(javaString) {
         mNativeString = mEnv->GetStringUTFChars(mJavaString, nullptr);
@@ -845,7 +862,7 @@
 
 Return<void> GnssMeasurementCallback::gnssMeasurementCb_2_0(
         const IGnssMeasurementCallback_V2_0::GnssData& data) {
-    // TODO(b/119571122): implement gnssMeasurementCb_2_0
+    translateAndSetGnssData(data);
     return Void();
 }
 
@@ -883,9 +900,8 @@
     return data.measurementCount;
 }
 
-template<>
-size_t GnssMeasurementCallback::getMeasurementCount<IGnssMeasurementCallback_V1_1::GnssData>
-        (const IGnssMeasurementCallback_V1_1::GnssData& data) {
+template<class T>
+size_t GnssMeasurementCallback::getMeasurementCount(const T& data) {
     return data.measurements.size();
 }
 
@@ -947,6 +963,17 @@
             ADR_STATE_HALF_CYCLE_REPORTED));
 }
 
+// Preallocate object as: JavaObject object(env, "android/location/GnssMeasurement");
+template<>
+void GnssMeasurementCallback::translateSingleGnssMeasurement
+        <IGnssMeasurementCallback_V2_0::GnssMeasurement>(
+        const IGnssMeasurementCallback_V2_0::GnssMeasurement* measurement_V2_0,
+        JavaObject& object) {
+    translateSingleGnssMeasurement(&(measurement_V2_0->v1_1), object);
+
+    SET(CodeType, (static_cast<int32_t>(measurement_V2_0->codeType)));
+}
+
 jobject GnssMeasurementCallback::translateGnssClock(
        JNIEnv* env, const IGnssMeasurementCallback_V1_0::GnssClock* clock) {
     JavaObject object(env, "android/location/GnssClock");
@@ -1069,6 +1096,54 @@
 }
 
 /*
+ * GnssVisibilityControlCallback implements callback methods of IGnssVisibilityControlCallback.hal.
+ */
+struct GnssVisibilityControlCallback : public IGnssVisibilityControlCallback {
+    Return<void> nfwNotifyCb(const IGnssVisibilityControlCallback::NfwNotification& notification)
+            override;
+    Return<bool> isInEmergencySession() override;
+};
+
+Return<void> GnssVisibilityControlCallback::nfwNotifyCb(
+        const IGnssVisibilityControlCallback::NfwNotification& notification) {
+    JNIEnv* env = getJniEnv();
+    jstring proxyAppPackageName = env->NewStringUTF(notification.proxyAppPackageName.c_str());
+    jstring otherProtocolStackName = env->NewStringUTF(notification.otherProtocolStackName.c_str());
+    jstring requestorId = env->NewStringUTF(notification.requestorId.c_str());
+
+    if (proxyAppPackageName && otherProtocolStackName && requestorId) {
+        env->CallVoidMethod(mCallbacksObj, method_reportNfwNotification, proxyAppPackageName,
+                            notification.protocolStack, otherProtocolStackName,
+                            notification.requestor, requestorId,
+                            notification.inEmergencyMode, notification.isCachedLocation);
+    } else {
+        ALOGE("%s: OOM Error\n", __func__);
+    }
+
+    if (requestorId) {
+        env->DeleteLocalRef(requestorId);
+    }
+
+    if (otherProtocolStackName) {
+        env->DeleteLocalRef(otherProtocolStackName);
+    }
+
+    if (proxyAppPackageName) {
+        env->DeleteLocalRef(proxyAppPackageName);
+    }
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+Return<bool> GnssVisibilityControlCallback::isInEmergencySession() {
+    JNIEnv* env = getJniEnv();
+    auto result = env->CallBooleanMethod(mCallbacksObj, method_isInEmergencySession);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return result;
+}
+
+/*
  * AGnssCallback_V1_0 implements callback methods required by the IAGnssCallback 1.0 interface.
  */
 struct AGnssCallback_V1_0 : public IAGnssCallback_V1_0 {
@@ -1302,6 +1377,9 @@
             "reportLocationBatch",
             "([Landroid/location/Location;)V");
     method_reportGnssServiceDied = env->GetMethodID(clazz, "reportGnssServiceDied", "()V");
+    method_reportNfwNotification = env->GetMethodID(clazz, "reportNfwNotification",
+            "(Ljava/lang/String;BLjava/lang/String;BLjava/lang/String;BZZ)V");
+    method_isInEmergencySession = env->GetMethodID(clazz, "isInEmergencySession", "()Z");
 
     /*
      * Save a pointer to JVM.
@@ -1377,12 +1455,6 @@
     if (gnssHal_V2_0 != nullptr) {
         // TODO(b/119638366): getExtensionGnssMeasurement_1_1 from gnssHal_V2_0
         auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
-        auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections();
-        if (!gnssCorrections.isOk()) {
-            ALOGD("Unable to get a handle to GnssMeasurementCorrections interface");
-        } else {
-            gnssCorrectionsIface = gnssCorrections;
-        }
         if (!gnssMeasurement.isOk()) {
             ALOGD("Unable to get a handle to GnssMeasurement_V2_0");
         } else {
@@ -1390,6 +1462,12 @@
             gnssMeasurementIface_V1_1 = gnssMeasurementIface_V2_0;
             gnssMeasurementIface = gnssMeasurementIface_V2_0;
         }
+        auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections();
+        if (!gnssCorrections.isOk()) {
+            ALOGD("Unable to get a handle to GnssMeasurementCorrections interface");
+        } else {
+            gnssCorrectionsIface = gnssCorrections;
+        }
     } else if (gnssHal_V1_1 != nullptr) {
          auto gnssMeasurement = gnssHal_V1_1->getExtensionGnssMeasurement_1_1();
          if (!gnssMeasurement.isOk()) {
@@ -1421,10 +1499,19 @@
         gnssNiIface = gnssNi;
     }
 
-    if (gnssHal_V1_1 != nullptr) {
+    if (gnssHal_V2_0 != nullptr) {
+        auto gnssConfiguration = gnssHal_V2_0->getExtensionGnssConfiguration_2_0();
+        if (!gnssConfiguration.isOk()) {
+            ALOGD("Unable to get a handle to GnssConfiguration_V2_0");
+        } else {
+            gnssConfigurationIface_V2_0 = gnssConfiguration;
+            gnssConfigurationIface_V1_1 = gnssConfigurationIface_V2_0;
+            gnssConfigurationIface = gnssConfigurationIface_V2_0;
+        }
+    } else if (gnssHal_V1_1 != nullptr) {
         auto gnssConfiguration = gnssHal_V1_1->getExtensionGnssConfiguration_1_1();
         if (!gnssConfiguration.isOk()) {
-            ALOGD("Unable to get a handle to GnssConfiguration");
+            ALOGD("Unable to get a handle to GnssConfiguration_V1_1");
         } else {
             gnssConfigurationIface_V1_1 = gnssConfiguration;
             gnssConfigurationIface = gnssConfigurationIface_V1_1;
@@ -1451,6 +1538,15 @@
     } else {
         gnssBatchingIface = gnssBatching;
     }
+
+    if (gnssHal_V2_0 != nullptr) {
+        auto gnssVisibilityControl = gnssHal_V2_0->getExtensionVisibilityControl();
+        if (!gnssVisibilityControl.isOk()) {
+            ALOGD("Unable to get a handle to GnssVisibilityControl interface");
+        } else {
+            gnssVisibilityControlIface = gnssVisibilityControl;
+        }
+    }
 }
 
 static jboolean android_location_GnssLocationProvider_is_supported(
@@ -1463,9 +1559,23 @@
     return (agnssRilIface != nullptr) ? JNI_TRUE : JNI_FALSE;
 }
 
-static jboolean android_location_gpsLocationProvider_is_gnss_configuration_supported(
-        JNIEnv* /* env */, jclass /* jclazz */) {
-    return (gnssConfigurationIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+static jobject android_location_GnssConfiguration_get_gnss_configuration_version(
+        JNIEnv* env, jclass /* jclazz */) {
+    jint major, minor;
+    if (gnssConfigurationIface_V2_0 != nullptr) {
+        major = 2;
+        minor = 0;
+    } else if (gnssConfigurationIface_V1_1 != nullptr) {
+        major = 1;
+        minor = 1;
+    } else if (gnssConfigurationIface != nullptr) {
+        major = 1;
+        minor = 0;
+    } else {
+        return nullptr;
+    }
+
+    return createHalInterfaceVersionJavaObject(env, major, minor);
 }
 
 static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject obj) {
@@ -1538,7 +1648,13 @@
     if (agnssRilIface != nullptr) {
         agnssRilIface->setCallback(aGnssRilCbIface);
     } else {
-        ALOGI("Unable to Initialize AGnss Ril interface\n");
+        ALOGI("Unable to initialize AGnss Ril interface\n");
+    }
+
+    if (gnssVisibilityControlIface != nullptr) {
+        sp<IGnssVisibilityControlCallback> gnssVisibilityControlCbIface =
+                new GnssVisibilityControlCallback();
+        gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
     }
 
     return JNI_TRUE;
@@ -1940,6 +2056,11 @@
     return result;
 }
 
+static jboolean android_location_GnssLocationProvider_is_gnss_visibility_control_supported(
+        JNIEnv* /* env */, jclass /* clazz */) {
+    return (gnssVisibilityControlIface != nullptr) ?  JNI_TRUE : JNI_FALSE;
+}
+
 static void android_location_GnssNetworkConnectivityHandler_update_network_state(JNIEnv* env,
                                                                        jobject /* obj */,
                                                                        jboolean connected,
@@ -2156,8 +2277,8 @@
                 singleSatCorrClass, "getSatId", "()I");
             method_correctionSatCarrierFreq = env->GetMethodID(
                 singleSatCorrClass, "getCarrierFrequencyHz", "()F");
-            method_correctionSatIsLos = env->GetMethodID(
-                singleSatCorrClass,"getSatIsLos", "()Z");
+            method_correctionSatIsLosProb = env->GetMethodID(
+                singleSatCorrClass,"getProbSatIsLos", "()F");
             method_correctionSatEpl = env->GetMethodID(
                 singleSatCorrClass, "getExcessPathLengthMeters", "()F");
             method_correctionSatEplUnc = env->GetMethodID(
@@ -2175,8 +2296,8 @@
             env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
         jfloat carrierFreqHz = env->CallFloatMethod(
             singleSatCorrectionObj, method_correctionSatCarrierFreq);
-        jboolean satIsLos = env->CallBooleanMethod(singleSatCorrectionObj,
-            method_correctionSatIsLos);
+        jfloat probSatIsLos = env->CallFloatMethod(singleSatCorrectionObj,
+            method_correctionSatIsLosProb);
         jfloat eplMeters =
             env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
         jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj,
@@ -2216,7 +2337,7 @@
             .constellation = static_cast<GnssConstellationType>(constType),
             .svid = static_cast<uint16_t>(satId),
             .carrierFrequencyHz = carrierFreqHz,
-            .satIsLos = static_cast<bool>(satIsLos),
+            .probSatIsLos = probSatIsLos,
             .excessPathLengthMeters = eplMeters,
             .excessPathLengthUncertaintyMeters = eplUncMeters,
             .reflectingPlane = reflectingPlane,
@@ -2278,9 +2399,9 @@
     return boolToJbool(result.isOk());
 }
 
-static jboolean android_location_GnssLocationProvider_set_emergency_supl_pdn(JNIEnv*,
-                                                                    jobject,
-                                                                    jint emergencySuplPdn) {
+static jboolean android_location_GnssConfiguration_set_emergency_supl_pdn(JNIEnv*,
+                                                                          jobject,
+                                                                          jint emergencySuplPdn) {
     if (gnssConfigurationIface == nullptr) {
         ALOGE("no GNSS configuration interface available");
         return JNI_FALSE;
@@ -2294,7 +2415,7 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_supl_version(JNIEnv*,
+static jboolean android_location_GnssConfiguration_set_supl_version(JNIEnv*,
                                                                     jobject,
                                                                     jint version) {
     if (gnssConfigurationIface == nullptr) {
@@ -2309,9 +2430,14 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_supl_es(JNIEnv*,
-                                                                    jobject,
-                                                                    jint suplEs) {
+static jboolean android_location_GnssConfiguration_set_supl_es(JNIEnv*,
+                                                               jobject,
+                                                               jint suplEs) {
+    if (gnssConfigurationIface_V2_0 != nullptr) {
+        ALOGI("Config parameter SUPL_ES is deprecated in IGnssConfiguration.hal version 2.0.");
+        return JNI_FALSE;
+    }
+
     if (gnssConfigurationIface == nullptr) {
         ALOGE("no GNSS configuration interface available");
         return JNI_FALSE;
@@ -2325,9 +2451,9 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_supl_mode(JNIEnv*,
-                                                                    jobject,
-                                                                    jint mode) {
+static jboolean android_location_GnssConfiguration_set_supl_mode(JNIEnv*,
+                                                                 jobject,
+                                                                 jint mode) {
     if (gnssConfigurationIface == nullptr) {
         ALOGE("no GNSS configuration interface available");
         return JNI_FALSE;
@@ -2341,9 +2467,14 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_gps_lock(JNIEnv*,
-                                                                   jobject,
-                                                                   jint gpsLock) {
+static jboolean android_location_GnssConfiguration_set_gps_lock(JNIEnv*,
+                                                                jobject,
+                                                                jint gpsLock) {
+    if (gnssConfigurationIface_V2_0 != nullptr) {
+        ALOGI("Config parameter GPS_LOCK is deprecated in IGnssConfiguration.hal version 2.0.");
+        return JNI_FALSE;
+    }
+
     if (gnssConfigurationIface == nullptr) {
         ALOGE("no GNSS configuration interface available");
         return JNI_FALSE;
@@ -2357,7 +2488,7 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_lpp_profile(JNIEnv*,
+static jboolean android_location_GnssConfiguration_set_lpp_profile(JNIEnv*,
                                                                    jobject,
                                                                    jint lppProfile) {
     if (gnssConfigurationIface == nullptr) {
@@ -2374,9 +2505,9 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_gnss_pos_protocol_select(JNIEnv*,
-                                                                   jobject,
-                                                                   jint gnssPosProtocol) {
+static jboolean android_location_GnssConfiguration_set_gnss_pos_protocol_select(JNIEnv*,
+                                                                            jobject,
+                                                                            jint gnssPosProtocol) {
     if (gnssConfigurationIface == nullptr) {
         ALOGE("no GNSS configuration interface available");
         return JNI_FALSE;
@@ -2390,7 +2521,7 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_satellite_blacklist(
+static jboolean android_location_GnssConfiguration_set_satellite_blacklist(
         JNIEnv* env, jobject, jintArray constellations, jintArray sv_ids) {
     if (gnssConfigurationIface_V1_1 == nullptr) {
         ALOGI("No GNSS Satellite Blacklist interface available");
@@ -2431,6 +2562,27 @@
     }
 }
 
+static jboolean android_location_GnssConfiguration_set_es_extension_sec(
+        JNIEnv*, jobject, jint emergencyExtensionSeconds) {
+    if (gnssConfigurationIface == nullptr) {
+        ALOGE("no GNSS configuration interface available");
+        return JNI_FALSE;
+    }
+
+    if (gnssConfigurationIface_V2_0 == nullptr) {
+        ALOGI("Config parameter ES_EXTENSION_SEC is not supported in IGnssConfiguration.hal"
+                " versions earlier than 2.0.");
+        return JNI_FALSE;
+    }
+
+    auto result = gnssConfigurationIface_V2_0->setEsExtensionSec(emergencyExtensionSeconds);
+    if (result.isOk()) {
+        return result;
+    } else {
+        return JNI_FALSE;
+    }
+}
+
 static jint android_location_GnssBatchingProvider_get_batch_size(JNIEnv*, jclass) {
     if (gnssBatchingIface == nullptr) {
         return 0; // batching not supported, size = 0
@@ -2492,23 +2644,43 @@
     return gnssBatchingIface->stop();
 }
 
+static jboolean android_location_GnssVisibilityControl_enable_nfw_location_access(
+        JNIEnv* env, jobject, jobjectArray proxyApps) {
+    if (gnssVisibilityControlIface == nullptr) {
+        ALOGI("No GNSS Visibility Control interface available");
+        return JNI_FALSE;
+    }
+
+    const jsize length = env->GetArrayLength(proxyApps);
+    hidl_vec<hidl_string> hidlProxyApps(length);
+    for (int i = 0; i < length; ++i) {
+        jstring proxyApp = (jstring) (env->GetObjectArrayElement(proxyApps, i));
+        ScopedJniString jniProxyApp(env, proxyApp);
+        hidlProxyApps[i] = jniProxyApp;
+    }
+
+    auto result = gnssVisibilityControlIface->enableNfwLocationAccess(hidlProxyApps);
+    if (result.isOk()) {
+        return result;
+    } else {
+        return JNI_FALSE;
+    }
+}
+
 static const JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"class_init_native", "()V", reinterpret_cast<void *>(
             android_location_GnssLocationProvider_class_init_native)},
     {"native_is_supported", "()Z", reinterpret_cast<void *>(
             android_location_GnssLocationProvider_is_supported)},
-    {"native_is_gnss_configuration_supported", "()Z",
-            reinterpret_cast<void *>(
-                    android_location_gpsLocationProvider_is_gnss_configuration_supported)},
     {"native_init_once", "()V", reinterpret_cast<void *>(
             android_location_GnssLocationProvider_init_once)},
     {"native_init", "()Z", reinterpret_cast<void *>(android_location_GnssLocationProvider_init)},
     {"native_cleanup", "()V", reinterpret_cast<void *>(
             android_location_GnssLocationProvider_cleanup)},
     {"native_set_position_mode",
-                "(IIIIIZ)Z",
-                reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)},
+            "(IIIIIZ)Z",
+            reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)},
     {"native_start", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_start)},
     {"native_stop", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_stop)},
     {"native_delete_aiding_data",
@@ -2545,31 +2717,8 @@
     {"native_get_internal_state",
             "()Ljava/lang/String;",
             reinterpret_cast<void *>(android_location_GnssLocationProvider_get_internal_state)},
-    {"native_set_supl_es",
-            "(I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_es)},
-    {"native_set_supl_version",
-            "(I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_version)},
-    {"native_set_supl_mode",
-            "(I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_mode)},
-    {"native_set_lpp_profile",
-            "(I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_lpp_profile)},
-    {"native_set_gnss_pos_protocol_select",
-            "(I)Z",
-            reinterpret_cast<void *>(
-                    android_location_GnssLocationProvider_set_gnss_pos_protocol_select)},
-    {"native_set_gps_lock",
-            "(I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_gps_lock)},
-    {"native_set_emergency_supl_pdn",
-            "(I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_emergency_supl_pdn)},
-    {"native_set_satellite_blacklist",
-            "([I[I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_satellite_blacklist)},
+    {"native_is_gnss_visibility_control_supported", "()Z", reinterpret_cast<void *>(
+            android_location_GnssLocationProvider_is_gnss_visibility_control_supported)},
 };
 
 static const JNINativeMethod sMethodsBatching[] = {
@@ -2663,6 +2812,50 @@
             reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed)},
 };
 
+static const JNINativeMethod sConfigurationMethods[] = {
+     /* name, signature, funcPtr */
+    {"native_get_gnss_configuration_version",
+            "()Lcom/android/server/location/GnssConfiguration$HalInterfaceVersion;",
+            reinterpret_cast<void *>(
+                    android_location_GnssConfiguration_get_gnss_configuration_version)},
+    {"native_set_supl_es",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_supl_es)},
+    {"native_set_supl_version",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_supl_version)},
+    {"native_set_supl_mode",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_supl_mode)},
+    {"native_set_lpp_profile",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_lpp_profile)},
+    {"native_set_gnss_pos_protocol_select",
+            "(I)Z",
+            reinterpret_cast<void *>(
+                    android_location_GnssConfiguration_set_gnss_pos_protocol_select)},
+    {"native_set_gps_lock",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_gps_lock)},
+    {"native_set_emergency_supl_pdn",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_emergency_supl_pdn)},
+    {"native_set_satellite_blacklist",
+            "([I[I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_satellite_blacklist)},
+    {"native_set_es_extension_sec",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_es_extension_sec)},
+};
+
+static const JNINativeMethod sVisibilityControlMethods[] = {
+     /* name, signature, funcPtr */
+    {"native_enable_nfw_location_access",
+            "([Ljava/lang/String;)Z",
+            reinterpret_cast<void *>(
+                    android_location_GnssVisibilityControl_enable_nfw_location_access)},
+};
+
 int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
     jniRegisterNativeMethods(
             env,
@@ -2689,6 +2882,16 @@
             "com/android/server/location/GnssNetworkConnectivityHandler",
             sNetworkConnectivityMethods,
             NELEM(sNetworkConnectivityMethods));
+    jniRegisterNativeMethods(
+            env,
+            "com/android/server/location/GnssConfiguration",
+            sConfigurationMethods,
+            NELEM(sConfigurationMethods));
+    jniRegisterNativeMethods(
+            env,
+            "com/android/server/location/GnssVisibilityControl",
+            sVisibilityControlMethods,
+            NELEM(sVisibilityControlMethods));
     return jniRegisterNativeMethods(
             env,
             "com/android/server/location/GnssLocationProvider",
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
index 3c87e42..7dd30bd 100644
--- a/services/core/jni/com_android_server_security_VerityUtils.cpp
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -75,6 +75,23 @@
     jbyte* mElements;
 };
 
+int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
+#if HAS_FSVERITY
+    const char* path = env->GetStringUTFChars(filePath, nullptr);
+    ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC));
+    if (rfd.get() < 0) {
+      return errno;
+    }
+    if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) {
+      return errno;
+    }
+    return 0;
+#else
+    LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
+    return ENOSYS;
+#endif  // HAS_FSVERITY
+}
+
 int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
 #if HAS_FSVERITY
     auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest) + kSha256Bytes);
@@ -82,14 +99,17 @@
     data->digest_size = kSha256Bytes;  // the only input/output parameter
 
     const char* path = env->GetStringUTFChars(filePath, nullptr);
-    ::android::base::unique_fd rfd(open(path, O_RDONLY));
+    ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC));
+    if (rfd.get() < 0) {
+      return errno;
+    }
     if (ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data) < 0) {
       return errno;
     }
     return 0;
 #else
     LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
-    return -1;
+    return ENOSYS;
 #endif  // HAS_FSVERITY
 }
 
@@ -172,6 +192,7 @@
 }
 
 const JNINativeMethod sMethods[] = {
+    { "enableFsverityNative", "(Ljava/lang/String;)I", (void *)enableFsverity },
     { "measureFsverityNative", "(Ljava/lang/String;)I", (void *)measureFsverity },
     { "constructFsveritySignedDataNative", "([B)[B", (void *)constructFsveritySignedData },
     { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor },
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 918f57e..6e31aed 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -26,8 +26,6 @@
 int register_android_server_AlarmManagerService(JNIEnv* env);
 int register_android_server_BatteryStatsService(JNIEnv* env);
 int register_android_server_ConsumerIrService(JNIEnv *env);
-int register_android_server_InputApplicationHandle(JNIEnv* env);
-int register_android_server_InputWindowHandle(JNIEnv* env);
 int register_android_server_InputManager(JNIEnv* env);
 int register_android_server_LightsService(JNIEnv* env);
 int register_android_server_PowerManagerService(JNIEnv* env);
@@ -74,8 +72,6 @@
     register_android_server_broadcastradio_Tuner(vm, env);
     register_android_server_PowerManagerService(env);
     register_android_server_SerialService(env);
-    register_android_server_InputApplicationHandle(env);
-    register_android_server_InputWindowHandle(env);
     register_android_server_InputManager(env);
     register_android_server_LightsService(env);
     register_android_server_AlarmManagerService(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
index 05912a5..de5dd17 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
@@ -66,6 +66,9 @@
         map.put(
                 DOWNLOAD_STATE_INITIALIZATION_ERROR,
                 InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION);
+        map.put(
+                UpdateEngine.ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR,
+                InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION);
 
         // Error constants corresponding to errors related to bad update file.
         map.put(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 781e1c4..54053a8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -221,7 +221,7 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.IAccessibilityManager;
 import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -245,6 +245,7 @@
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemService;
 import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
+import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.server.pm.UserRestrictionsUtils;
 import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -491,7 +492,6 @@
     final UsageStatsManagerInternal mUsageStatsManagerInternal;
     final TelephonyManager mTelephonyManager;
     private final LockPatternUtils mLockPatternUtils;
-    private final DevicePolicyConstants mConstants;
     private final DeviceAdminServiceController mDeviceAdminServiceController;
     private final OverlayPackagesProvider mOverlayPackagesProvider;
 
@@ -538,6 +538,9 @@
     private final AtomicBoolean mRemoteBugreportSharingAccepted = new AtomicBoolean();
 
     private final SetupContentObserver mSetupContentObserver;
+    private final DevicePolicyConstantsObserver mConstantsObserver;
+
+    private DevicePolicyConstants mConstants;
 
     private static boolean ENABLE_LOCK_GUARD = Build.IS_ENG
             || true // STOPSHIP Remove it.
@@ -2168,8 +2171,10 @@
         mInjector = injector;
         mContext = Preconditions.checkNotNull(injector.mContext);
         mHandler = new Handler(Preconditions.checkNotNull(injector.getMyLooper()));
-        mConstants = DevicePolicyConstants.loadFromString(
-                mInjector.settingsGlobalGetString(Global.DEVICE_POLICY_CONSTANTS));
+
+        mConstantsObserver = new DevicePolicyConstantsObserver(mHandler);
+        mConstantsObserver.register();
+        mConstants = loadConstants();
 
         mOwners = Preconditions.checkNotNull(injector.newOwners());
 
@@ -4218,7 +4223,7 @@
 
     @Override
     public void setPasswordHistoryLength(ComponentName who, int length, boolean parent) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
@@ -4241,13 +4246,16 @@
 
     @Override
     public int getPasswordHistoryLength(ComponentName who, int userHandle, boolean parent) {
+        if (!mLockPatternUtils.hasSecureLockScreen()) {
+            return 0;
+        }
         return getStrictestPasswordRequirement(who, userHandle, parent,
                 admin -> admin.passwordHistoryLength, PASSWORD_QUALITY_UNSPECIFIED);
     }
 
     @Override
     public void setPasswordExpirationTimeout(ComponentName who, long timeout, boolean parent) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
@@ -4283,7 +4291,7 @@
      */
     @Override
     public long getPasswordExpirationTimeout(ComponentName who, int userHandle, boolean parent) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return 0L;
         }
         enforceFullCrossUsersPermission(userHandle);
@@ -4418,7 +4426,7 @@
 
     @Override
     public long getPasswordExpiration(ComponentName who, int userHandle, boolean parent) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return 0L;
         }
         enforceFullCrossUsersPermission(userHandle);
@@ -4765,6 +4773,9 @@
 
     @Override
     public int getCurrentFailedPasswordAttempts(int userHandle, boolean parent) {
+        if (!mLockPatternUtils.hasSecureLockScreen()) {
+            return 0;
+        }
         enforceFullCrossUsersPermission(userHandle);
         synchronized (getLockObject()) {
             if (!isCallerWithSystemUid()) {
@@ -4784,7 +4795,7 @@
 
     @Override
     public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, boolean parent) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
@@ -4810,7 +4821,7 @@
 
     @Override
     public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle, boolean parent) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return 0;
         }
         enforceFullCrossUsersPermission(userHandle);
@@ -4824,7 +4835,7 @@
 
     @Override
     public int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return UserHandle.USER_NULL;
         }
         enforceFullCrossUsersPermission(userHandle);
@@ -4905,6 +4916,11 @@
     }
     @Override
     public boolean resetPassword(String passwordOrNull, int flags) throws RemoteException {
+        if (!mLockPatternUtils.hasSecureLockScreen()) {
+            Slog.w(LOG_TAG, "Cannot reset password when the device has no lock screen");
+            return false;
+        }
+
         final int callingUid = mInjector.binderGetCallingUid();
         final int userHandle = mInjector.userHandleGetCallingUserId();
 
@@ -4990,26 +5006,22 @@
     private boolean resetPasswordInternal(String password, long tokenHandle, byte[] token,
             int flags, int callingUid, int userHandle) {
         int quality;
-        final int realQuality;
         synchronized (getLockObject()) {
             quality = getPasswordQuality(null, userHandle, /* parent */ false);
             if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
                 quality = PASSWORD_QUALITY_UNSPECIFIED;
             }
             final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
-            realQuality = metrics.quality;
-            if (quality != PASSWORD_QUALITY_UNSPECIFIED) {
-
-                if (realQuality < quality
-                        && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
-                    Slog.w(LOG_TAG, "resetPassword: password quality 0x"
-                            + Integer.toHexString(realQuality)
-                            + " does not meet required quality 0x"
-                            + Integer.toHexString(quality));
-                    return false;
-                }
-                quality = Math.max(realQuality, quality);
+            final int realQuality = metrics.quality;
+            if (realQuality < quality
+                    && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
+                Slog.w(LOG_TAG, "resetPassword: password quality 0x"
+                        + Integer.toHexString(realQuality)
+                        + " does not meet required quality 0x"
+                        + Integer.toHexString(quality));
+                return false;
             }
+            quality = Math.max(realQuality, quality);
             int length = getPasswordMinimumLength(null, userHandle, /* parent */ false);
             if (password.length() < length) {
                 Slog.w(LOG_TAG, "resetPassword: password length " + password.length()
@@ -5086,7 +5098,7 @@
         try {
             if (token == null) {
                 if (!TextUtils.isEmpty(password)) {
-                    mLockPatternUtils.saveLockPassword(password, null, realQuality, userHandle);
+                    mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
                 } else {
                     mLockPatternUtils.clearLock(null, userHandle);
                 }
@@ -5095,7 +5107,7 @@
                 result = mLockPatternUtils.setLockCredentialWithToken(password,
                         TextUtils.isEmpty(password) ? LockPatternUtils.CREDENTIAL_TYPE_NONE
                                 : LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                        realQuality, tokenHandle, token, userHandle);
+                        quality, tokenHandle, token, userHandle);
             }
             boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
             if (requireEntry) {
@@ -5251,7 +5263,7 @@
     @Override
     public void setRequiredStrongAuthTimeout(ComponentName who, long timeoutMs,
             boolean parent) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
@@ -5284,7 +5296,7 @@
      */
     @Override
     public long getRequiredStrongAuthTimeout(ComponentName who, int userId, boolean parent) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
         }
         enforceFullCrossUsersPermission(userId);
@@ -5326,6 +5338,7 @@
         }
 
         final int callingUserId = mInjector.userHandleGetCallingUserId();
+        ComponentName adminComponent = null;
         synchronized (getLockObject()) {
             // Make sure the caller has any active admin with the right policy or
             // the required permission.
@@ -5336,8 +5349,7 @@
                     android.Manifest.permission.LOCK_DEVICE);
             final long ident = mInjector.binderClearCallingIdentity();
             try {
-                final ComponentName adminComponent = admin == null ?
-                        null : admin.info.getComponent();
+                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) {
@@ -5389,6 +5401,7 @@
         }
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.LOCK_NOW)
+                .setAdmin(adminComponent)
                 .setInt(flags)
                 .write();
     }
@@ -6105,7 +6118,9 @@
         synchronized (getLockObject()) {
             delegates = getDelegatePackagesInternalLocked(scope, userId);
         }
-        if (delegates.size() != 1) {
+        if (delegates.size() == 0) {
+            return null;
+        } else if (delegates.size() > 1) {
             Slog.wtf(LOG_TAG, "More than one delegate holds " + scope);
             return null;
         }
@@ -6490,7 +6505,7 @@
      */
     @Override
     public void setActivePasswordState(PasswordMetrics metrics, int userHandle) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return;
         }
         enforceFullCrossUsersPermission(userHandle);
@@ -6510,7 +6525,7 @@
 
     @Override
     public void reportPasswordChanged(@UserIdInt int userId) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return;
         }
         enforceFullCrossUsersPermission(userId);
@@ -8786,7 +8801,7 @@
     @Override
     public void setTrustAgentConfiguration(ComponentName admin, ComponentName agent,
             PersistableBundle args, boolean parent) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return;
         }
         Preconditions.checkNotNull(admin, "admin is null");
@@ -8803,7 +8818,7 @@
     @Override
     public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
             ComponentName agent, int userHandle, boolean parent) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return null;
         }
         Preconditions.checkNotNull(agent, "agent null");
@@ -9192,21 +9207,15 @@
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
 
-        // TODO When InputMethodManager supports per user calls remove
-        //      this restriction.
-        if (!checkCallerIsCurrentUserOrProfile()) {
+        // TODO When InputMethodManager supports per user calls remove this restriction.
+        if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED
+                && !checkCallerIsCurrentUserOrProfile()) {
             return false;
         }
-
         final int callingUserId = mInjector.userHandleGetCallingUserId();
         if (packageList != null) {
-            // InputMethodManager fetches input methods for current user.
-            // So this can only be set when calling user is the current user
-            // or parent is current user in case of managed profiles.
-            InputMethodManager inputMethodManager =
-                    mContext.getSystemService(InputMethodManager.class);
-            List<InputMethodInfo> enabledImes = inputMethodManager.getEnabledInputMethodList();
-
+            List<InputMethodInfo> enabledImes = InputMethodManagerInternal.get()
+                    .getEnabledInputMethodListAsUser(callingUserId);
             if (enabledImes != null) {
                 List<String> enabledPackages = new ArrayList<String>();
                 for (InputMethodInfo ime : enabledImes) {
@@ -9254,22 +9263,16 @@
     @Override
     public List getPermittedInputMethodsForCurrentUser() {
         enforceManageUsers();
-        UserInfo currentUser;
-        try {
-            currentUser = mInjector.getIActivityManager().getCurrentUser();
-        } catch (RemoteException e) {
-            Slog.e(LOG_TAG, "Failed to make remote calls to get current user", e);
-            // Activity managed is dead, just allow all IMEs
-            return null;
-        }
 
-        int userId = currentUser.id;
+        final int callingUserId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             List<String> result = null;
             // If we have multiple profiles we return the intersection of the
             // permitted lists. This can happen in cases where we have a device
             // and profile owner.
-            int[] profileIds = mUserManager.getProfileIdsWithDisabled(userId);
+            int[] profileIds = InputMethodSystemProperty.PER_PROFILE_IME_ENABLED
+                    ? new int[]{callingUserId}
+                    : mUserManager.getProfileIdsWithDisabled(callingUserId);
             for (int profileId : profileIds) {
                 // Just loop though all admins, only device or profiles
                 // owners can have permitted lists set.
@@ -9290,9 +9293,8 @@
 
             // If we have a permitted list add all system input methods.
             if (result != null) {
-                InputMethodManager inputMethodManager =
-                        mContext.getSystemService(InputMethodManager.class);
-                List<InputMethodInfo> imes = inputMethodManager.getInputMethodList();
+                List<InputMethodInfo> imes =
+                        InputMethodManagerInternal.get().getInputMethodListAsUser(callingUserId);
                 if (imes != null) {
                     for (InputMethodInfo ime : imes) {
                         ServiceInfo serviceInfo = ime.getServiceInfo();
@@ -10967,6 +10969,25 @@
         }
     }
 
+    private class DevicePolicyConstantsObserver extends ContentObserver {
+        final Uri mConstantsUri =
+                Settings.Global.getUriFor(Settings.Global.DEVICE_POLICY_CONSTANTS);
+
+        DevicePolicyConstantsObserver(Handler handler) {
+            super(handler);
+        }
+
+        void register() {
+            mInjector.registerContentObserver(
+                    mConstantsUri, /* notifyForDescendents= */ false, this, UserHandle.USER_ALL);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri, int userId) {
+            mConstants = loadConstants();
+        }
+    }
+
     @VisibleForTesting
     final class LocalService extends DevicePolicyManagerInternal {
         private List<OnCrossProfileWidgetProvidersChangeListener> mWidgetProviderListeners;
@@ -12999,7 +13020,12 @@
                 throw new IllegalStateException("logging is not available");
             }
             if (mNetworkLogger != null) {
-                return mNetworkLogger.forceBatchFinalization();
+                final long ident = mInjector.binderClearCallingIdentity();
+                try {
+                    return mNetworkLogger.forceBatchFinalization();
+                } finally {
+                    mInjector.binderRestoreCallingIdentity(ident);
+                }
             }
             return 0;
         }
@@ -13201,7 +13227,7 @@
 
     @Override
     public boolean setResetPasswordToken(ComponentName admin, byte[] token) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return false;
         }
         if (token == null || token.length < 32) {
@@ -13229,7 +13255,7 @@
 
     @Override
     public boolean clearResetPasswordToken(ComponentName admin) {
-        if (!mHasFeature) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return false;
         }
         synchronized (getLockObject()) {
@@ -13255,6 +13281,9 @@
 
     @Override
     public boolean isResetPasswordTokenActive(ComponentName admin) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
+            return false;
+        }
         synchronized (getLockObject()) {
             final int userHandle = mInjector.userHandleGetCallingUserId();
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -13276,6 +13305,9 @@
     @Override
     public boolean resetPasswordWithToken(ComponentName admin, String passwordOrNull, byte[] token,
             int flags) {
+        if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
+            return false;
+        }
         Preconditions.checkNotNull(token);
         synchronized (getLockObject()) {
             final int userHandle = mInjector.userHandleGetCallingUserId();
@@ -14180,4 +14212,9 @@
             return false;
         }
     }
+
+    private DevicePolicyConstants loadConstants() {
+        return DevicePolicyConstants.loadFromString(
+                mInjector.settingsGlobalGetString(Global.DEVICE_POLICY_CONSTANTS));
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
index d0ec0ee..699bec2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
@@ -23,6 +23,7 @@
 import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.app.admin.DeviceAdminReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -30,15 +31,13 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.util.ArraySet;
 import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.view.IInputMethodManager;
+import com.android.server.inputmethod.InputMethodManagerInternal;
 
 import java.util.Arrays;
 import java.util.List;
@@ -53,18 +52,38 @@
     protected static final String TAG = "OverlayPackagesProvider";
 
     private final PackageManager mPm;
-    private final IInputMethodManager mIInputMethodManager;
     private final Context mContext;
+    private final Injector mInjector;
 
     public OverlayPackagesProvider(Context context) {
-        this(context, getIInputMethodManager());
+        this(context, new DefaultInjector());
     }
 
     @VisibleForTesting
-    OverlayPackagesProvider(Context context, IInputMethodManager iInputMethodManager) {
+    interface Injector {
+        boolean isPerProfileImeEnabled();
+        @NonNull
+        List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId);
+    }
+
+    private static final class DefaultInjector implements Injector {
+        @Override
+        public boolean isPerProfileImeEnabled() {
+            return InputMethodSystemProperty.PER_PROFILE_IME_ENABLED;
+        }
+
+        @NonNull
+        @Override
+        public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
+            return InputMethodManagerInternal.get().getInputMethodListAsUser(userId);
+        }
+    }
+
+    @VisibleForTesting
+    OverlayPackagesProvider(Context context, Injector injector) {
         mContext = context;
         mPm = checkNotNull(context.getPackageManager());
-        mIInputMethodManager = checkNotNull(iInputMethodManager);
+        mInjector = checkNotNull(injector);
     }
 
     /**
@@ -89,10 +108,12 @@
         // Newly installed system apps are uninstalled when they are not required and are either
         // disallowed or have a launcher icon.
         nonRequiredApps.removeAll(getRequiredApps(provisioningAction, admin.getPackageName()));
-        // Don't delete the system input method packages in case of Device owner provisioning.
-        if (ACTION_PROVISION_MANAGED_DEVICE.equals(provisioningAction)
+        if (mInjector.isPerProfileImeEnabled()) {
+            nonRequiredApps.removeAll(getSystemInputMethods(userId));
+        } else if (ACTION_PROVISION_MANAGED_DEVICE.equals(provisioningAction)
                 || ACTION_PROVISION_MANAGED_USER.equals(provisioningAction)) {
-            nonRequiredApps.removeAll(getSystemInputMethods());
+            // Don't delete the system input method packages in case of Device owner provisioning.
+            nonRequiredApps.removeAll(getSystemInputMethods(userId));
         }
         nonRequiredApps.addAll(getDisallowedApps(provisioningAction));
         return nonRequiredApps;
@@ -114,16 +135,8 @@
         return apps;
     }
 
-    private Set<String> getSystemInputMethods() {
-        // InputMethodManager is final so it cannot be mocked.
-        // So, we're using IInputMethodManager directly because it can be mocked.
-        final List<InputMethodInfo> inputMethods;
-        try {
-            inputMethods = mIInputMethodManager.getInputMethodList();
-        } catch (RemoteException e) {
-            // Should not happen
-            return null;
-        }
+    private Set<String> getSystemInputMethods(int userId) {
+        final List<InputMethodInfo> inputMethods = mInjector.getInputMethodListAsUser(userId);
         final Set<String> systemInputMethods = new ArraySet<>();
         for (InputMethodInfo inputMethodInfo : inputMethods) {
             ApplicationInfo applicationInfo = inputMethodInfo.getServiceInfo().applicationInfo;
@@ -149,11 +162,6 @@
         return disallowedApps;
     }
 
-    private static IInputMethodManager getIInputMethodManager() {
-        final IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
-        return IInputMethodManager.Stub.asInterface(b);
-    }
-
     private Set<String> getRequiredAppsSet(String provisioningAction) {
         final int resId;
         switch (provisioningAction) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
index d8a875d..cf68ccf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
@@ -16,10 +16,13 @@
 
 package com.android.server.devicepolicy;
 
+import android.annotation.Nullable;
 import android.app.admin.DevicePolicyEventLogger;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.StartInstallingUpdateCallback;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.BatteryManager;
 import android.os.Environment;
 import android.os.FileUtils;
@@ -41,7 +44,8 @@
     private ParcelFileDescriptor mUpdateFileDescriptor;
     private DevicePolicyConstants mConstants;
     protected Context mContext;
-    protected File mCopiedUpdateFile;
+
+    @Nullable protected File mCopiedUpdateFile;
 
     static final String TAG = "UpdateInstaller";
     private DevicePolicyManagerService.Injector mInjector;
@@ -59,7 +63,8 @@
     public abstract void installUpdateInThread();
 
     public void startInstallUpdate() {
-        if (!checkIfBatteryIsSufficient()) {
+        mCopiedUpdateFile = null;
+        if (!isBatteryLevelSufficient()) {
             notifyCallbackOnError(
                     DevicePolicyManager.InstallUpdateCallback.UPDATE_ERROR_BATTERY_LOW,
                     "The battery level must be above "
@@ -81,17 +86,21 @@
         thread.start();
     }
 
-    private boolean checkIfBatteryIsSufficient() {
-        BatteryManager batteryManager =
-                (BatteryManager) mContext.getSystemService(Context.BATTERY_SERVICE);
-        if (batteryManager != null) {
-            int chargePercentage = batteryManager
-                    .getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
-            return batteryManager.isCharging()
-                    ? chargePercentage >= mConstants.BATTERY_THRESHOLD_CHARGING
-                    : chargePercentage >= mConstants.BATTERY_THRESHOLD_NOT_CHARGING;
-        }
-        return false;
+    private boolean isBatteryLevelSufficient() {
+        Intent batteryStatus = mContext.registerReceiver(
+                /* receiver= */ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+        float batteryPercentage = calculateBatteryPercentage(batteryStatus);
+        boolean isBatteryPluggedIn =
+                batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, /* defaultValue= */ -1) > 0;
+        return isBatteryPluggedIn
+                ? batteryPercentage >= mConstants.BATTERY_THRESHOLD_CHARGING
+                : batteryPercentage >= mConstants.BATTERY_THRESHOLD_NOT_CHARGING;
+    }
+
+    private float calculateBatteryPercentage(Intent batteryStatus) {
+        int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, /* defaultValue= */ -1);
+        int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, /* defaultValue= */ -1);
+        return 100 * level / (float) scale;
     }
 
     private File copyUpdateFileToDataOtaPackageDir() {
@@ -127,7 +136,7 @@
     }
 
     void cleanupUpdateFile() {
-        if (mCopiedUpdateFile.exists()) {
+        if (mCopiedUpdateFile != null && mCopiedUpdateFile.exists()) {
             mCopiedUpdateFile.delete();
         }
     }
diff --git a/services/ipmemorystore/Android.bp b/services/ipmemorystore/Android.bp
new file mode 100644
index 0000000..013cf56
--- /dev/null
+++ b/services/ipmemorystore/Android.bp
@@ -0,0 +1,4 @@
+java_library_static {
+    name: "services.ipmemorystore",
+    srcs: ["java/**/*.java"],
+}
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
new file mode 100644
index 0000000..e99dd4f
--- /dev/null
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net.ipmemorystore;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteCursor;
+import android.database.sqlite.SQLiteCursorDriver;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteQuery;
+import android.net.NetworkUtils;
+import android.net.ipmemorystore.NetworkAttributes;
+import android.net.ipmemorystore.Status;
+import android.util.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringJoiner;
+
+/**
+ * Encapsulating class for using the SQLite database backing the memory store.
+ *
+ * This class groups together the contracts and the SQLite helper used to
+ * use the database.
+ *
+ * @hide
+ */
+public class IpMemoryStoreDatabase {
+    private static final String TAG = IpMemoryStoreDatabase.class.getSimpleName();
+    // A pair of NetworkAttributes objects is group-close if the confidence that they are
+    // the same is above this cutoff. See NetworkAttributes and SameL3NetworkResponse.
+    private static final float GROUPCLOSE_CONFIDENCE = 0.5f;
+
+    /**
+     * Contract class for the Network Attributes table.
+     */
+    public static class NetworkAttributesContract {
+        public static final String TABLENAME = "NetworkAttributes";
+
+        public static final String COLNAME_L2KEY = "l2Key";
+        public static final String COLTYPE_L2KEY = "TEXT NOT NULL";
+
+        public static final String COLNAME_EXPIRYDATE = "expiryDate";
+        // Milliseconds since the Epoch, in true Java style
+        public static final String COLTYPE_EXPIRYDATE = "BIGINT";
+
+        public static final String COLNAME_ASSIGNEDV4ADDRESS = "assignedV4Address";
+        public static final String COLTYPE_ASSIGNEDV4ADDRESS = "INTEGER";
+
+        // Please note that the group hint is only a *hint*, hence its name. The client can offer
+        // this information to nudge the grouping in the decision it thinks is right, but it can't
+        // decide for the memory store what is the same L3 network.
+        public static final String COLNAME_GROUPHINT = "groupHint";
+        public static final String COLTYPE_GROUPHINT = "TEXT";
+
+        public static final String COLNAME_DNSADDRESSES = "dnsAddresses";
+        // Stored in marshalled form as is
+        public static final String COLTYPE_DNSADDRESSES = "BLOB";
+
+        public static final String COLNAME_MTU = "mtu";
+        public static final String COLTYPE_MTU = "INTEGER DEFAULT -1";
+
+        public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS "
+                + TABLENAME                 + " ("
+                + COLNAME_L2KEY             + " " + COLTYPE_L2KEY + " PRIMARY KEY NOT NULL, "
+                + COLNAME_EXPIRYDATE        + " " + COLTYPE_EXPIRYDATE        + ", "
+                + COLNAME_ASSIGNEDV4ADDRESS + " " + COLTYPE_ASSIGNEDV4ADDRESS + ", "
+                + COLNAME_GROUPHINT         + " " + COLTYPE_GROUPHINT         + ", "
+                + COLNAME_DNSADDRESSES      + " " + COLTYPE_DNSADDRESSES      + ", "
+                + COLNAME_MTU               + " " + COLTYPE_MTU               + ")";
+        public static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLENAME;
+    }
+
+    /**
+     * Contract class for the Private Data table.
+     */
+    public static class PrivateDataContract {
+        public static final String TABLENAME = "PrivateData";
+
+        public static final String COLNAME_L2KEY = "l2Key";
+        public static final String COLTYPE_L2KEY = "TEXT NOT NULL";
+
+        public static final String COLNAME_CLIENT = "client";
+        public static final String COLTYPE_CLIENT = "TEXT NOT NULL";
+
+        public static final String COLNAME_DATANAME = "dataName";
+        public static final String COLTYPE_DATANAME = "TEXT NOT NULL";
+
+        public static final String COLNAME_DATA = "data";
+        public static final String COLTYPE_DATA = "BLOB NOT NULL";
+
+        public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS "
+                + TABLENAME        + " ("
+                + COLNAME_L2KEY    + " " + COLTYPE_L2KEY    + ", "
+                + COLNAME_CLIENT   + " " + COLTYPE_CLIENT   + ", "
+                + COLNAME_DATANAME + " " + COLTYPE_DATANAME + ", "
+                + COLNAME_DATA     + " " + COLTYPE_DATA     + ", "
+                + "PRIMARY KEY ("
+                + COLNAME_L2KEY    + ", "
+                + COLNAME_CLIENT   + ", "
+                + COLNAME_DATANAME + "))";
+        public static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLENAME;
+    }
+
+    // To save memory when the DB is not used, close it after 30s of inactivity. This is
+    // determined manually based on what feels right.
+    private static final long IDLE_CONNECTION_TIMEOUT_MS = 30_000;
+
+    /** The SQLite DB helper */
+    public static class DbHelper extends SQLiteOpenHelper {
+        // Update this whenever changing the schema.
+        private static final int SCHEMA_VERSION = 2;
+        private static final String DATABASE_FILENAME = "IpMemoryStore.db";
+
+        public DbHelper(@NonNull final Context context) {
+            super(context, DATABASE_FILENAME, null, SCHEMA_VERSION);
+            setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
+        }
+
+        /** Called when the database is created */
+        @Override
+        public void onCreate(@NonNull final SQLiteDatabase db) {
+            db.execSQL(NetworkAttributesContract.CREATE_TABLE);
+            db.execSQL(PrivateDataContract.CREATE_TABLE);
+        }
+
+        /** Called when the database is upgraded */
+        @Override
+        public void onUpgrade(@NonNull final SQLiteDatabase db, final int oldVersion,
+                final int newVersion) {
+            // No upgrade supported yet.
+            db.execSQL(NetworkAttributesContract.DROP_TABLE);
+            db.execSQL(PrivateDataContract.DROP_TABLE);
+            onCreate(db);
+        }
+
+        /** Called when the database is downgraded */
+        @Override
+        public void onDowngrade(@NonNull final SQLiteDatabase db, final int oldVersion,
+                final int newVersion) {
+            // Downgrades always nuke all data and recreate an empty table.
+            db.execSQL(NetworkAttributesContract.DROP_TABLE);
+            db.execSQL(PrivateDataContract.DROP_TABLE);
+            onCreate(db);
+        }
+    }
+
+    @NonNull
+    private static byte[] encodeAddressList(@NonNull final List<InetAddress> addresses) {
+        final ByteArrayOutputStream os = new ByteArrayOutputStream();
+        for (final InetAddress address : addresses) {
+            final byte[] b = address.getAddress();
+            os.write(b.length);
+            os.write(b, 0, b.length);
+        }
+        return os.toByteArray();
+    }
+
+    @NonNull
+    private static ArrayList<InetAddress> decodeAddressList(@NonNull final byte[] encoded) {
+        final ByteArrayInputStream is = new ByteArrayInputStream(encoded);
+        final ArrayList<InetAddress> addresses = new ArrayList<>();
+        int d = -1;
+        while ((d = is.read()) != -1) {
+            final byte[] bytes = new byte[d];
+            is.read(bytes, 0, d);
+            try {
+                addresses.add(InetAddress.getByAddress(bytes));
+            } catch (UnknownHostException e) { /* Hopefully impossible */ }
+        }
+        return addresses;
+    }
+
+    @NonNull
+    private static ContentValues toContentValues(@Nullable final NetworkAttributes attributes) {
+        final ContentValues values = new ContentValues();
+        if (null == attributes) return values;
+        if (null != attributes.assignedV4Address) {
+            values.put(NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS,
+                    NetworkUtils.inet4AddressToIntHTH(attributes.assignedV4Address));
+        }
+        if (null != attributes.groupHint) {
+            values.put(NetworkAttributesContract.COLNAME_GROUPHINT, attributes.groupHint);
+        }
+        if (null != attributes.dnsAddresses) {
+            values.put(NetworkAttributesContract.COLNAME_DNSADDRESSES,
+                    encodeAddressList(attributes.dnsAddresses));
+        }
+        if (null != attributes.mtu) {
+            values.put(NetworkAttributesContract.COLNAME_MTU, attributes.mtu);
+        }
+        return values;
+    }
+
+    // Convert a NetworkAttributes object to content values to store them in a table compliant
+    // with the contract defined in NetworkAttributesContract.
+    @NonNull
+    private static ContentValues toContentValues(@NonNull final String key,
+            @Nullable final NetworkAttributes attributes, final long expiry) {
+        final ContentValues values = toContentValues(attributes);
+        values.put(NetworkAttributesContract.COLNAME_L2KEY, key);
+        values.put(NetworkAttributesContract.COLNAME_EXPIRYDATE, expiry);
+        return values;
+    }
+
+    // Convert a byte array into content values to store it in a table compliant with the
+    // contract defined in PrivateDataContract.
+    @NonNull
+    private static ContentValues toContentValues(@NonNull final String key,
+            @NonNull final String clientId, @NonNull final String name,
+            @NonNull final byte[] data) {
+        final ContentValues values = new ContentValues();
+        values.put(PrivateDataContract.COLNAME_L2KEY, key);
+        values.put(PrivateDataContract.COLNAME_CLIENT, clientId);
+        values.put(PrivateDataContract.COLNAME_DATANAME, name);
+        values.put(PrivateDataContract.COLNAME_DATA, data);
+        return values;
+    }
+
+    @Nullable
+    private static NetworkAttributes readNetworkAttributesLine(@NonNull final Cursor cursor) {
+        // Make sure the data hasn't expired
+        final long expiry = getLong(cursor, NetworkAttributesContract.COLNAME_EXPIRYDATE, -1L);
+        if (expiry < System.currentTimeMillis()) return null;
+
+        final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
+        final int assignedV4AddressInt = getInt(cursor,
+                NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS, 0);
+        final String groupHint = getString(cursor, NetworkAttributesContract.COLNAME_GROUPHINT);
+        final byte[] dnsAddressesBlob =
+                getBlob(cursor, NetworkAttributesContract.COLNAME_DNSADDRESSES);
+        final int mtu = getInt(cursor, NetworkAttributesContract.COLNAME_MTU, -1);
+        if (0 != assignedV4AddressInt) {
+            builder.setAssignedV4Address(NetworkUtils.intToInet4AddressHTH(assignedV4AddressInt));
+        }
+        builder.setGroupHint(groupHint);
+        if (null != dnsAddressesBlob) {
+            builder.setDnsAddresses(decodeAddressList(dnsAddressesBlob));
+        }
+        if (mtu >= 0) {
+            builder.setMtu(mtu);
+        }
+        return builder.build();
+    }
+
+    private static final String[] EXPIRY_COLUMN = new String[] {
+        NetworkAttributesContract.COLNAME_EXPIRYDATE
+    };
+    static final int EXPIRY_ERROR = -1; // Legal values for expiry are positive
+
+    static final String SELECT_L2KEY = NetworkAttributesContract.COLNAME_L2KEY + " = ?";
+
+    // Returns the expiry date of the specified row, or one of the error codes above if the
+    // row is not found or some other error
+    static long getExpiry(@NonNull final SQLiteDatabase db, @NonNull final String key) {
+        final Cursor cursor = db.query(NetworkAttributesContract.TABLENAME,
+                EXPIRY_COLUMN, // columns
+                SELECT_L2KEY, // selection
+                new String[] { key }, // selectionArgs
+                null, // groupBy
+                null, // having
+                null // orderBy
+        );
+        // L2KEY is the primary key ; it should not be possible to get more than one
+        // result here. 0 results means the key was not found.
+        if (cursor.getCount() != 1) return EXPIRY_ERROR;
+        cursor.moveToFirst();
+        final long result = cursor.getLong(0); // index in the EXPIRY_COLUMN array
+        cursor.close();
+        return result;
+    }
+
+    static final int RELEVANCE_ERROR = -1; // Legal values for relevance are positive
+
+    // Returns the relevance of the specified row, or one of the error codes above if the
+    // row is not found or some other error
+    static int getRelevance(@NonNull final SQLiteDatabase db, @NonNull final String key) {
+        final long expiry = getExpiry(db, key);
+        return expiry < 0 ? (int) expiry : RelevanceUtils.computeRelevanceForNow(expiry);
+    }
+
+    // If the attributes are null, this will only write the expiry.
+    // Returns an int out of Status.{SUCCESS,ERROR_*}
+    static int storeNetworkAttributes(@NonNull final SQLiteDatabase db, @NonNull final String key,
+            final long expiry, @Nullable final NetworkAttributes attributes) {
+        final ContentValues cv = toContentValues(key, attributes, expiry);
+        db.beginTransaction();
+        try {
+            // Unfortunately SQLite does not have any way to do INSERT OR UPDATE. Options are
+            // to either insert with on conflict ignore then update (like done here), or to
+            // construct a custom SQL INSERT statement with nested select.
+            final long resultId = db.insertWithOnConflict(NetworkAttributesContract.TABLENAME,
+                    null, cv, SQLiteDatabase.CONFLICT_IGNORE);
+            if (resultId < 0) {
+                db.update(NetworkAttributesContract.TABLENAME, cv, SELECT_L2KEY, new String[]{key});
+            }
+            db.setTransactionSuccessful();
+            return Status.SUCCESS;
+        } catch (SQLiteException e) {
+            // No space left on disk or something
+            Log.e(TAG, "Could not write to the memory store", e);
+        } finally {
+            db.endTransaction();
+        }
+        return Status.ERROR_STORAGE;
+    }
+
+    // Returns an int out of Status.{SUCCESS,ERROR_*}
+    static int storeBlob(@NonNull final SQLiteDatabase db, @NonNull final String key,
+            @NonNull final String clientId, @NonNull final String name,
+            @NonNull final byte[] data) {
+        final long res = db.insertWithOnConflict(PrivateDataContract.TABLENAME, null,
+                toContentValues(key, clientId, name, data), SQLiteDatabase.CONFLICT_REPLACE);
+        return (res == -1) ? Status.ERROR_STORAGE : Status.SUCCESS;
+    }
+
+    @Nullable
+    static NetworkAttributes retrieveNetworkAttributes(@NonNull final SQLiteDatabase db,
+            @NonNull final String key) {
+        final Cursor cursor = db.query(NetworkAttributesContract.TABLENAME,
+                null, // columns, null means everything
+                NetworkAttributesContract.COLNAME_L2KEY + " = ?", // selection
+                new String[] { key }, // selectionArgs
+                null, // groupBy
+                null, // having
+                null); // orderBy
+        // L2KEY is the primary key ; it should not be possible to get more than one
+        // result here. 0 results means the key was not found.
+        if (cursor.getCount() != 1) return null;
+        cursor.moveToFirst();
+        final NetworkAttributes attributes = readNetworkAttributesLine(cursor);
+        cursor.close();
+        return attributes;
+    }
+
+    private static final String[] DATA_COLUMN = new String[] {
+            PrivateDataContract.COLNAME_DATA
+    };
+    @Nullable
+    static byte[] retrieveBlob(@NonNull final SQLiteDatabase db, @NonNull final String key,
+            @NonNull final String clientId, @NonNull final String name) {
+        final Cursor cursor = db.query(PrivateDataContract.TABLENAME,
+                DATA_COLUMN, // columns
+                PrivateDataContract.COLNAME_L2KEY + " = ? AND " // selection
+                + PrivateDataContract.COLNAME_CLIENT + " = ? AND "
+                + PrivateDataContract.COLNAME_DATANAME + " = ?",
+                new String[] { key, clientId, name }, // selectionArgs
+                null, // groupBy
+                null, // having
+                null); // orderBy
+        // The query above is querying by (composite) primary key, so it should not be possible to
+        // get more than one result here. 0 results means the key was not found.
+        if (cursor.getCount() != 1) return null;
+        cursor.moveToFirst();
+        final byte[] result = cursor.getBlob(0); // index in the DATA_COLUMN array
+        cursor.close();
+        return result;
+    }
+
+    /**
+     * The following is a horrible hack that is necessary because the Android SQLite API does not
+     * have a way to query a binary blob. This, almost certainly, is an overlook.
+     *
+     * The Android SQLite API has two family of methods : one for query that returns data, and
+     * one for more general SQL statements that can execute any statement but may not return
+     * anything. All the query methods, however, take only String[] for the arguments.
+     *
+     * In principle it is simple to write a function that will encode the binary blob in the
+     * way SQLite expects it. However, because the API forces the argument to be coerced into a
+     * String, the SQLiteQuery object generated by the default query methods will bind all
+     * arguments as Strings and SQL will *sanitize* them. This works okay for numeric types,
+     * but the format for blobs is x'<hex string>'. Note the presence of quotes, which will
+     * be sanitized, changing the contents of the field, and the query will fail to match the
+     * blob.
+     *
+     * As far as I can tell, there are two possible ways around this problem. The first one
+     * is to put the data in the query string and eschew it being an argument. This would
+     * require doing the sanitizing by hand. The other is to call bindBlob directly on the
+     * generated SQLiteQuery object, which not only is a lot less dangerous than rolling out
+     * sanitizing, but also will do the right thing if the underlying format ever changes.
+     *
+     * But none of the methods that take an SQLiteQuery object can return data ; this *must*
+     * be called with SQLiteDatabase#query. This object is not accessible from outside.
+     * However, there is a #query version that accepts a CursorFactory and this is pretty
+     * straightforward to implement as all the arguments are coming in and the SQLiteCursor
+     * class is public API.
+     * With this, it's possible to intercept the SQLiteQuery object, and assuming the args
+     * are available, to bind them directly and work around the API's oblivious coercion into
+     * Strings.
+     *
+     * This is really sad, but I don't see another way of having this work than this or the
+     * hand-rolled sanitizing, and this is the lesser evil.
+     */
+    private static class CustomCursorFactory implements SQLiteDatabase.CursorFactory {
+        @NonNull
+        private final ArrayList<Object> mArgs;
+        CustomCursorFactory(@NonNull final ArrayList<Object> args) {
+            mArgs = args;
+        }
+        @Override
+        public Cursor newCursor(final SQLiteDatabase db, final SQLiteCursorDriver masterQuery,
+                final String editTable,
+                final SQLiteQuery query) {
+            int index = 1; // bind is 1-indexed
+            for (final Object arg : mArgs) {
+                if (arg instanceof String) {
+                    query.bindString(index++, (String) arg);
+                } else if (arg instanceof Long) {
+                    query.bindLong(index++, (Long) arg);
+                } else if (arg instanceof Integer) {
+                    query.bindLong(index++, Long.valueOf((Integer) arg));
+                } else if (arg instanceof byte[]) {
+                    query.bindBlob(index++, (byte[]) arg);
+                } else {
+                    throw new IllegalStateException("Unsupported type CustomCursorFactory "
+                            + arg.getClass().toString());
+                }
+            }
+            return new SQLiteCursor(masterQuery, editTable, query);
+        }
+    }
+
+    // Returns the l2key of the closest match, if and only if it matches
+    // closely enough (as determined by group-closeness).
+    @Nullable
+    static String findClosestAttributes(@NonNull final SQLiteDatabase db,
+            @NonNull final NetworkAttributes attr) {
+        if (attr.isEmpty()) return null;
+        final ContentValues values = toContentValues(attr);
+
+        // Build the selection and args. To cut down on the number of lines to search, limit
+        // the search to those with at least one argument equals to the requested attributes.
+        // This works only because null attributes match only will not result in group-closeness.
+        final StringJoiner sj = new StringJoiner(" OR ");
+        final ArrayList<Object> args = new ArrayList<>();
+        args.add(System.currentTimeMillis());
+        for (final String field : values.keySet()) {
+            sj.add(field + " = ?");
+            args.add(values.get(field));
+        }
+
+        final String selection = NetworkAttributesContract.COLNAME_EXPIRYDATE + " > ? AND ("
+                + sj.toString() + ")";
+        final Cursor cursor = db.queryWithFactory(new CustomCursorFactory(args),
+                false, // distinct
+                NetworkAttributesContract.TABLENAME,
+                null, // columns, null means everything
+                selection, // selection
+                null, // selectionArgs, horrendously passed to the cursor factory instead
+                null, // groupBy
+                null, // having
+                null, // orderBy
+                null); // limit
+        if (cursor.getCount() <= 0) return null;
+        cursor.moveToFirst();
+        String bestKey = null;
+        float bestMatchConfidence = GROUPCLOSE_CONFIDENCE; // Never return a match worse than this.
+        while (!cursor.isAfterLast()) {
+            final NetworkAttributes read = readNetworkAttributesLine(cursor);
+            final float confidence = read.getNetworkGroupSamenessConfidence(attr);
+            if (confidence > bestMatchConfidence) {
+                bestKey = getString(cursor, NetworkAttributesContract.COLNAME_L2KEY);
+                bestMatchConfidence = confidence;
+            }
+            cursor.moveToNext();
+        }
+        cursor.close();
+        return bestKey;
+    }
+
+    // Helper methods
+    private static String getString(final Cursor cursor, final String columnName) {
+        final int columnIndex = cursor.getColumnIndex(columnName);
+        return (columnIndex >= 0) ? cursor.getString(columnIndex) : null;
+    }
+    private static byte[] getBlob(final Cursor cursor, final String columnName) {
+        final int columnIndex = cursor.getColumnIndex(columnName);
+        return (columnIndex >= 0) ? cursor.getBlob(columnIndex) : null;
+    }
+    private static int getInt(final Cursor cursor, final String columnName,
+            final int defaultValue) {
+        final int columnIndex = cursor.getColumnIndex(columnName);
+        return (columnIndex >= 0) ? cursor.getInt(columnIndex) : defaultValue;
+    }
+    private static long getLong(final Cursor cursor, final String columnName,
+            final long defaultValue) {
+        final int columnIndex = cursor.getColumnIndex(columnName);
+        return (columnIndex >= 0) ? cursor.getLong(columnIndex) : defaultValue;
+    }
+}
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
new file mode 100644
index 0000000..d43dc6a
--- /dev/null
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
@@ -0,0 +1,398 @@
+/*
+ * 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.net.ipmemorystore;
+
+import static android.net.ipmemorystore.Status.ERROR_DATABASE_CANNOT_BE_OPENED;
+import static android.net.ipmemorystore.Status.ERROR_GENERIC;
+import static android.net.ipmemorystore.Status.ERROR_ILLEGAL_ARGUMENT;
+import static android.net.ipmemorystore.Status.SUCCESS;
+
+import static com.android.server.net.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.IIpMemoryStore;
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.IOnBlobRetrievedListener;
+import android.net.ipmemorystore.IOnL2KeyResponseListener;
+import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
+import android.net.ipmemorystore.IOnSameNetworkResponseListener;
+import android.net.ipmemorystore.IOnStatusListener;
+import android.net.ipmemorystore.NetworkAttributes;
+import android.net.ipmemorystore.NetworkAttributesParcelable;
+import android.net.ipmemorystore.SameL3NetworkResponse;
+import android.net.ipmemorystore.Status;
+import android.net.ipmemorystore.StatusParcelable;
+import android.net.ipmemorystore.Utils;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Implementation for the IP memory store.
+ * This component offers specialized services for network components to store and retrieve
+ * knowledge about networks, and provides intelligence that groups level 2 networks together
+ * into level 3 networks.
+ *
+ * @hide
+ */
+public class IpMemoryStoreService extends IIpMemoryStore.Stub {
+    private static final String TAG = IpMemoryStoreService.class.getSimpleName();
+    private static final int MAX_CONCURRENT_THREADS = 4;
+    private static final boolean DBG = true;
+
+    @NonNull
+    final Context mContext;
+    @Nullable
+    final SQLiteDatabase mDb;
+    @NonNull
+    final ExecutorService mExecutor;
+
+    /**
+     * Construct an IpMemoryStoreService object.
+     * This constructor will block on disk access to open the database.
+     * @param context the context to access storage with.
+     */
+    public IpMemoryStoreService(@NonNull final Context context) {
+        // Note that constructing the service will access the disk and block
+        // for some time, but it should make no difference to the clients. Because
+        // the interface is one-way, clients fire and forget requests, and the callback
+        // will get called eventually in any case, and the framework will wait for the
+        // service to be created to deliver subsequent requests.
+        // Avoiding this would mean the mDb member can't be final, which means the service would
+        // have to test for nullity, care for failure, and allow for a wait at every single access,
+        // which would make the code a lot more complex and require all methods to possibly block.
+        mContext = context;
+        SQLiteDatabase db;
+        final IpMemoryStoreDatabase.DbHelper helper = new IpMemoryStoreDatabase.DbHelper(context);
+        try {
+            db = helper.getWritableDatabase();
+            if (null == db) Log.e(TAG, "Unexpected null return of getWriteableDatabase");
+        } catch (final SQLException e) {
+            Log.e(TAG, "Can't open the Ip Memory Store database", e);
+            db = null;
+        } catch (final Exception e) {
+            Log.wtf(TAG, "Impossible exception Ip Memory Store database", e);
+            db = null;
+        }
+        mDb = db;
+        // The work-stealing thread pool executor will spawn threads as needed up to
+        // the max only when there is no free thread available. This generally behaves
+        // exactly like one would expect it intuitively :
+        // - When work arrives, it will spawn a new thread iff there are no available threads
+        // - When there is no work to do it will shutdown threads after a while (the while
+        //   being equal to 2 seconds (not configurable) when max threads are spun up and
+        //   twice as much for every one less thread)
+        // - When all threads are busy the work is enqueued and waits for any worker
+        //   to become available.
+        // Because the stealing pool is made for very heavily parallel execution of
+        // small tasks that spawn others, it creates a queue per thread that in this
+        // case is overhead. However, the three behaviors above make it a superior
+        // choice to cached or fixedThreadPoolExecutor, neither of which can actually
+        // enqueue a task waiting for a thread to be free. This can probably be solved
+        // with judicious subclassing of ThreadPoolExecutor, but that's a lot of dangerous
+        // complexity for little benefit in this case.
+        mExecutor = Executors.newWorkStealingPool(MAX_CONCURRENT_THREADS);
+    }
+
+    /**
+     * Shutdown the memory store service, cancelling running tasks and dropping queued tasks.
+     *
+     * This is provided to give a way to clean up, and is meant to be available in case of an
+     * emergency shutdown.
+     */
+    public void shutdown() {
+        // By contrast with ExecutorService#shutdown, ExecutorService#shutdownNow tries
+        // to cancel the existing tasks, and does not wait for completion. It does not
+        // guarantee the threads can be terminated in any given amount of time.
+        mExecutor.shutdownNow();
+        if (mDb != null) mDb.close();
+    }
+
+    /** Helper function to make a status object */
+    private StatusParcelable makeStatus(final int code) {
+        return new Status(code).toParcelable();
+    }
+
+    /**
+     * Store network attributes for a given L2 key.
+     *
+     * @param l2Key The L2 key for the L2 network. Clients that don't know or care about the L2
+     *              key and only care about grouping can pass a unique ID here like the ones
+     *              generated by {@code java.util.UUID.randomUUID()}, but keep in mind the low
+     *              relevance of such a network will lead to it being evicted soon if it's not
+     *              refreshed. Use findL2Key to try and find a similar L2Key to these attributes.
+     * @param attributes The attributes for this network.
+     * @param listener A listener to inform of the completion of this call, or null if the client
+     *        is not interested in learning about success/failure.
+     * Through the listener, returns the L2 key. This is useful if the L2 key was not specified.
+     * If the call failed, the L2 key will be null.
+     */
+    // Note that while l2Key and attributes are non-null in spirit, they are received from
+    // another process. If the remote process decides to ignore everything and send null, this
+    // process should still not crash.
+    @Override
+    public void storeNetworkAttributes(@Nullable final String l2Key,
+            @Nullable final NetworkAttributesParcelable attributes,
+            @Nullable final IOnStatusListener listener) {
+        // Because the parcelable is 100% mutable, the thread may not see its members initialized.
+        // Therefore either an immutable object is created on this same thread before it's passed
+        // to the executor, or there need to be a write barrier here and a read barrier in the
+        // remote thread.
+        final NetworkAttributes na = null == attributes ? null : new NetworkAttributes(attributes);
+        mExecutor.execute(() -> {
+            try {
+                final int code = storeNetworkAttributesAndBlobSync(l2Key, na,
+                        null /* clientId */, null /* name */, null /* data */);
+                if (null != listener) listener.onComplete(makeStatus(code));
+            } catch (final RemoteException e) {
+                // Client at the other end died
+            }
+        });
+    }
+
+    /**
+     * Store a binary blob associated with an L2 key and a name.
+     *
+     * @param l2Key The L2 key for this network.
+     * @param clientId The ID of the client.
+     * @param name The name of this data.
+     * @param blob The data to store.
+     * @param listener The listener that will be invoked to return the answer, or null if the
+     *        is not interested in learning about success/failure.
+     * Through the listener, returns a status to indicate success or failure.
+     */
+    @Override
+    public void storeBlob(@Nullable final String l2Key, @Nullable final String clientId,
+            @Nullable final String name, @Nullable final Blob blob,
+            @Nullable final IOnStatusListener listener) {
+        final byte[] data = null == blob ? null : blob.data;
+        mExecutor.execute(() -> {
+            try {
+                final int code = storeNetworkAttributesAndBlobSync(l2Key,
+                        null /* NetworkAttributes */, clientId, name, data);
+                if (null != listener) listener.onComplete(makeStatus(code));
+            } catch (final RemoteException e) {
+                // Client at the other end died
+            }
+        });
+    }
+
+    /**
+     * Helper method for storeNetworkAttributes and storeBlob.
+     *
+     * Either attributes or none of clientId, name and data may be null. This will write the
+     * passed data if non-null, and will write attributes if non-null, but in any case it will
+     * bump the relevance up.
+     * Returns a success code from Status.
+     */
+    private int storeNetworkAttributesAndBlobSync(@Nullable final String l2Key,
+            @Nullable final NetworkAttributes attributes,
+            @Nullable final String clientId,
+            @Nullable final String name, @Nullable final byte[] data) {
+        if (null == l2Key) return ERROR_ILLEGAL_ARGUMENT;
+        if (null == attributes && null == data) return ERROR_ILLEGAL_ARGUMENT;
+        if (null != data && (null == clientId || null == name)) return ERROR_ILLEGAL_ARGUMENT;
+        if (null == mDb) return ERROR_DATABASE_CANNOT_BE_OPENED;
+        try {
+            final long oldExpiry = IpMemoryStoreDatabase.getExpiry(mDb, l2Key);
+            final long newExpiry = RelevanceUtils.bumpExpiryDate(
+                    oldExpiry == EXPIRY_ERROR ? System.currentTimeMillis() : oldExpiry);
+            final int errorCode =
+                    IpMemoryStoreDatabase.storeNetworkAttributes(mDb, l2Key, newExpiry, attributes);
+            // If no blob to store, the client is interested in the result of storing the attributes
+            if (null == data) return errorCode;
+            // Otherwise it's interested in the result of storing the blob
+            return IpMemoryStoreDatabase.storeBlob(mDb, l2Key, clientId, name, data);
+        } catch (Exception e) {
+            if (DBG) {
+                Log.e(TAG, "Exception while storing for key {" + l2Key
+                        + "} ; NetworkAttributes {" + (null == attributes ? "null" : attributes)
+                        + "} ; clientId {" + (null == clientId ? "null" : clientId)
+                        + "} ; name {" + (null == name ? "null" : name)
+                        + "} ; data {" + Utils.byteArrayToString(data) + "}", e);
+            }
+        }
+        return ERROR_GENERIC;
+    }
+
+    /**
+     * Returns the best L2 key associated with the attributes.
+     *
+     * This will find a record that would be in the same group as the passed attributes. This is
+     * useful to choose the key for storing a sample or private data when the L2 key is not known.
+     * If multiple records are group-close to these attributes, the closest match is returned.
+     * If multiple records have the same closeness, the one with the smaller (unicode codepoint
+     * order) L2 key is returned.
+     * If no record matches these attributes, null is returned.
+     *
+     * @param attributes The attributes of the network to find.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, returns the L2 key if one matched, or null.
+     */
+    @Override
+    public void findL2Key(@Nullable final NetworkAttributesParcelable attributes,
+            @Nullable final IOnL2KeyResponseListener listener) {
+        if (null == listener) return;
+        mExecutor.execute(() -> {
+            try {
+                if (null == attributes) {
+                    listener.onL2KeyResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
+                    return;
+                }
+                if (null == mDb) {
+                    listener.onL2KeyResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
+                    return;
+                }
+                final String key = IpMemoryStoreDatabase.findClosestAttributes(mDb,
+                        new NetworkAttributes(attributes));
+                listener.onL2KeyResponse(makeStatus(SUCCESS), key);
+            } catch (final RemoteException e) {
+                // Client at the other end died
+            }
+        });
+    }
+
+    /**
+     * Returns whether, to the best of the store's ability to tell, the two specified L2 keys point
+     * to the same L3 network. Group-closeness is used to determine this.
+     *
+     * @param l2Key1 The key for the first network.
+     * @param l2Key2 The key for the second network.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, a SameL3NetworkResponse containing the answer and confidence.
+     */
+    @Override
+    public void isSameNetwork(@Nullable final String l2Key1, @Nullable final String l2Key2,
+            @Nullable final IOnSameNetworkResponseListener listener) {
+        if (null == listener) return;
+        mExecutor.execute(() -> {
+            try {
+                if (null == l2Key1 || null == l2Key2) {
+                    listener.onSameNetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
+                    return;
+                }
+                if (null == mDb) {
+                    listener.onSameNetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
+                    return;
+                }
+                try {
+                    final NetworkAttributes attr1 =
+                            IpMemoryStoreDatabase.retrieveNetworkAttributes(mDb, l2Key1);
+                    final NetworkAttributes attr2 =
+                            IpMemoryStoreDatabase.retrieveNetworkAttributes(mDb, l2Key2);
+                    if (null == attr1 || null == attr2) {
+                        listener.onSameNetworkResponse(makeStatus(SUCCESS),
+                                new SameL3NetworkResponse(l2Key1, l2Key2,
+                                        -1f /* never connected */).toParcelable());
+                        return;
+                    }
+                    final float confidence = attr1.getNetworkGroupSamenessConfidence(attr2);
+                    listener.onSameNetworkResponse(makeStatus(SUCCESS),
+                            new SameL3NetworkResponse(l2Key1, l2Key2, confidence).toParcelable());
+                } catch (Exception e) {
+                    listener.onSameNetworkResponse(makeStatus(ERROR_GENERIC), null);
+                }
+            } catch (final RemoteException e) {
+                // Client at the other end died
+            }
+        });
+    }
+
+    /**
+     * Retrieve the network attributes for a key.
+     * If no record is present for this key, this will return null attributes.
+     *
+     * @param l2Key The key of the network to query.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, returns the network attributes and the L2 key associated with
+     *         the query.
+     */
+    @Override
+    public void retrieveNetworkAttributes(@Nullable final String l2Key,
+            @Nullable final IOnNetworkAttributesRetrieved listener) {
+        if (null == listener) return;
+        mExecutor.execute(() -> {
+            try {
+                if (null == l2Key) {
+                    listener.onNetworkAttributesRetrieved(
+                            makeStatus(ERROR_ILLEGAL_ARGUMENT), l2Key, null);
+                    return;
+                }
+                if (null == mDb) {
+                    listener.onNetworkAttributesRetrieved(
+                            makeStatus(ERROR_DATABASE_CANNOT_BE_OPENED), l2Key, null);
+                    return;
+                }
+                try {
+                    final NetworkAttributes attributes =
+                            IpMemoryStoreDatabase.retrieveNetworkAttributes(mDb, l2Key);
+                    listener.onNetworkAttributesRetrieved(makeStatus(SUCCESS), l2Key,
+                            null == attributes ? null : attributes.toParcelable());
+                } catch (final Exception e) {
+                    listener.onNetworkAttributesRetrieved(makeStatus(ERROR_GENERIC), l2Key, null);
+                }
+            } catch (final RemoteException e) {
+                // Client at the other end died
+            }
+        });
+    }
+
+    /**
+     * Retrieve previously stored private data.
+     * If no data was stored for this L2 key and name this will return null.
+     *
+     * @param l2Key The L2 key.
+     * @param clientId The id of the client that stored this data.
+     * @param name The name of the data.
+     * @param listener The listener that will be invoked to return the answer.
+     * Through the listener, returns the private data if any or null if none, with the L2 key
+     *         and the name of the data associated with the query.
+     */
+    @Override
+    public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId,
+            @NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) {
+        if (null == listener) return;
+        mExecutor.execute(() -> {
+            try {
+                if (null == l2Key) {
+                    listener.onBlobRetrieved(makeStatus(ERROR_ILLEGAL_ARGUMENT), l2Key, name, null);
+                    return;
+                }
+                if (null == mDb) {
+                    listener.onBlobRetrieved(makeStatus(ERROR_DATABASE_CANNOT_BE_OPENED), l2Key,
+                            name, null);
+                    return;
+                }
+                try {
+                    final Blob b = new Blob();
+                    b.data = IpMemoryStoreDatabase.retrieveBlob(mDb, l2Key, clientId, name);
+                    listener.onBlobRetrieved(makeStatus(SUCCESS), l2Key, name, b);
+                } catch (final Exception e) {
+                    listener.onBlobRetrieved(makeStatus(ERROR_GENERIC), l2Key, name, null);
+                }
+            } catch (final RemoteException e) {
+                // Client at the other end died
+            }
+        });
+    }
+}
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
new file mode 100644
index 0000000..aa45400
--- /dev/null
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
@@ -0,0 +1,307 @@
+/*
+ * 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.net.ipmemorystore;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A class containing the logic around the relevance value for
+ * IP Memory Store.
+ *
+ * @hide
+ */
+public class RelevanceUtils {
+    /**
+     * The relevance is a decaying value that gets lower and lower until it
+     * reaches 0 after some time passes. It follows an exponential decay law,
+     * dropping slowly at first then faster and faster, because a network is
+     * likely to be visited again if it was visited not long ago, and the longer
+     * it hasn't been visited the more likely it is that it won't be visited
+     * again. For example, a network visited on holiday should stay fresh for
+     * the duration of the holiday and persist for a while, but after the venue
+     * hasn't been visited for a while it should quickly be discarded. What
+     * should accelerate forgetting the network is extended periods without
+     * visits, so that occasional venues get discarded but regular visits keep
+     * the network relevant, even if the visits are infrequent.
+     *
+     * This function must be stable by iteration, meaning that adjusting the same value
+     * for different dates iteratively multiple times should give the same result.
+     * Formally, if f is the decay function that associates a relevance x at a date d1
+     * to the value at ulterior date d3, then for any date d2 between d1 and d3 :
+     * f(x, d3 - d1) = f(f(x, d3 - d2), d2 - d1). Intuitively, this property simply
+     * means it should be the same to compute and store back the value after two months,
+     * or to do it once after one month, store it back, and do it again after another
+     * months has passed.
+     * The pair of the relevance and date define the entire curve, so any pair
+     * of values on the curve will define the same curve. Setting one of them to a
+     * constant, so as not to have to store it, means the other one will always suffice
+     * to describe the curve. For example, only storing the date for a known, constant
+     * value of the relevance is an efficient way of remembering this information (and
+     * to compare relevances together, as f is monotonically decreasing).
+     *
+     *** Choosing the function :
+     * Functions of the kind described above are standard exponential decay functions
+     * like the ones that govern atomic decay where the value at any given date can be
+     * computed uniformly from the value at a previous date and the time elapsed since
+     * that date. It is simple to picture this kind of function as one where after a
+     * given period of time called the half-life, the relevance value will have been
+     * halved. Decay of this kind is expressed in function of the previous value by
+     * functions like
+     * f(x, t) = x * F ^ (t / L)
+     * ...where x is the value, t is the elapsed time, L is the half-life (or more
+     * generally the F-th-life) and F the decay factor (typically 0.5, hence why L is
+     * usually called the half-life). The ^ symbol here is used for exponentiation.
+     * Or, starting at a given M for t = 0 :
+     * f(t) = M * F ^ (t / L)
+     *
+     * Because a line in the store needs to become irrelevant at some point but
+     * this class of functions never go to 0, a minimum cutoff has to be chosen to
+     * represent irrelevance. The simpler way of doing this is to simply add this
+     * minimum cutoff to the computation before and removing it after.
+     * Thus the function becomes :
+     * f(x, t) = ((x + K) * F ^ (t / L)) - K
+     * ...where K is the minimum cutoff, L the half-life, and F the factor between
+     * the original x and x after its half-life. Strictly speaking using the word
+     * "half-life" implies that F = 0.5, but the relation works for any value of F.
+     *
+     * It is easy enough to check that this function satisfies the stability
+     * relation that was given above for any value of F, L and K, which become
+     * parameters that can be defined at will.
+     *
+     * relevance
+     *  1.0 |
+     *      |\
+     *      | \
+     *      |  \            (this graph rendered with L = 75 days and K = 1/40)
+     *  0.75|   ',
+     *      |     \
+     *      |      '.
+     *      |        \.
+     *      |          \
+     *  0.5 |           '\
+     *      |             ''.
+     *      |                ''.
+     *      |                   ''.
+     *  0.25|                      '''..
+     *      |                           '''..
+     *      |                                ''''....
+     *      |                                        '''''..........
+     *    0 +-------------------------------------------------------''''''''''----
+     *      0       50       100      150     200      250     300      350     400 days
+     *
+     *** Choosing the parameters
+     * The maximum M is an arbitrary parameter that simply scales the curve.
+     * The tradeoff for M is pretty simple : if the relevance is going to be an
+     * integer, the bigger M is the more precision there is in the relevance.
+     * However, values of M that are easy for humans to read are preferable to
+     * help debugging, and a suitably low value may be enough to ensure there
+     * won't be integer overflows in intermediate computations.
+     * A value of 1_000_000 probably is plenty for precision, while still in the
+     * low range of what ints can represent.
+     *
+     * F and L are parameters to be chosen arbitrarily and have an impact on how
+     * fast the relevance will be decaying at first, keeping in mind that
+     * the 400 days value and the cap stay the same. In simpler words, F and L
+     * define the steepness of the curve.
+     * To keep things simple (and familiar) F is arbitrarily chosen to be 0.5, and
+     * L is set to 200 days visually to achieve the desired effect. Refer to the
+     * illustration above to get a feel of how that feels.
+     *
+     * Moreover, the memory store works on an assumption that the relevance should
+     * be capped, and that an entry with capped relevance should decay in 400 days.
+     * This is on premises that the networks a device will need to remember the
+     * longest should be networks visited about once a year.
+     * For this reason, the relevance is at the maximum M 400 days before expiry :
+     * f(M, 400 days) = 0
+     * From replacing this with the value of the function, K can then be derived
+     * from the values of M, F and L :
+     * (M + K) * F ^ (t / L) - K = 0
+     * K = M * F ^ (400 days / L) / (1 - F ^ (400 days / L))
+     * Replacing with actual values this gives :
+     * K = 1_000_000 * 0.5 ^ (400 / 200) / (1 - 0.5 ^ (400 / 200))
+     *   = 1_000_000 / 3 ≈ 333_333.3
+     * This ensures the function has the desired profile, the desired value at
+     * cap, and the desired value at expiry.
+     *
+     *** Useful relations
+     * Let's define the expiry time for any given relevance x as the interval of
+     * time such as :
+     * f(x, expiry) = 0
+     * which can be rewritten
+     * ((x + K) * F ^ (expiry / L)) = K
+     * ...giving an expression of the expiry in function of the relevance x as
+     * expiry = L * logF(K / (x + K))
+     * Conversely the relevance x can be expressed in function of the expiry as
+     * x = K / F ^ (expiry / L) - K
+     * These relations are useful in utility functions.
+     *
+     *** Bumping things up
+     * The last issue therefore is to decide how to bump up the relevance. The
+     * simple approach is to simply lift up the curve a little bit by a constant
+     * normalized amount, delaying the time of expiry. For example increasing
+     * the relevance by an amount I gives :
+     * x2 = x1 + I
+     * x2 and x1 correspond to two different expiry times expiry2 and expiry1,
+     * and replacing x1 and x2 in the relation above with their expression in
+     * function of the expiry comes :
+     * K / F ^ (expiry2 / L) - K = K / F ^ (expiry1 / L) - K + I
+     * which resolves to :
+     * expiry2 = L * logF(K / (I + K / F ^ (expiry1 / L)))
+     *
+     * In this implementation, the bump is defined as 1/25th of the cap for
+     * the relevance. This means a network will be remembered for the maximum
+     * period of 400 days if connected 25 times in succession not accounting
+     * for decay. Of course decay actually happens so it will take more than 25
+     * connections for any given network to actually reach the cap, but because
+     * decay is slow at first, it is a good estimate of how fast cap happens.
+     *
+     * Specifically, it gives the following four results :
+     * - A network that a device connects to once hits irrelevance about 32.7 days after
+     *   it was first registered if never connected again.
+     * - A network that a device connects to once a day at a fixed hour will hit the cap
+     *   on the 27th connection.
+     * - A network that a device connects to once a week at a fixed hour will hit the cap
+     *   on the 57th connection.
+     * - A network that a device connects to every day for 7 straight days then never again
+     *   expires 144 days after the last connection.
+     * These metrics tend to match pretty well the requirements.
+     */
+
+    // TODO : make these constants configurable at runtime. Don't forget to build it so that
+    // changes will wipe the database, migrate the values, or otherwise make sure the relevance
+    // values are still meaningful.
+
+    // How long, in milliseconds, is a capped relevance valid for, or in other
+    // words how many milliseconds after its relevance was set to RELEVANCE_CAP does
+    // any given line expire. 400 days.
+    @VisibleForTesting
+    public static final long CAPPED_RELEVANCE_LIFETIME_MS = 400L * 24 * 60 * 60 * 1000;
+
+    // The constant that represents a normalized 1.0 value for the relevance. In other words,
+    // the cap for the relevance. This is referred to as M in the explanation above.
+    @VisibleForTesting
+    public static final int CAPPED_RELEVANCE = 1_000_000;
+
+    // The decay factor. After a half-life, the relevance will have decayed by this value.
+    // This is referred to as F in the explanation above.
+    private static final double DECAY_FACTOR = 0.5;
+
+    // The half-life. After this time, the relevance will have decayed by a factor DECAY_FACTOR.
+    // This is referred to as L in the explanation above.
+    private static final long HALF_LIFE_MS = 200L * 24 * 60 * 60 * 1000;
+
+    // The value of the frame change. This is referred to as K in the explanation above.
+    private static final double IRRELEVANCE_FLOOR =
+            CAPPED_RELEVANCE * powF((double) CAPPED_RELEVANCE_LIFETIME_MS / HALF_LIFE_MS)
+            / (1 - powF((double) CAPPED_RELEVANCE_LIFETIME_MS / HALF_LIFE_MS));
+
+    // How much to bump the relevance by every time a line is written to.
+    @VisibleForTesting
+    public static final int RELEVANCE_BUMP = CAPPED_RELEVANCE / 25;
+
+    // Java doesn't include a function for the logarithm in an arbitrary base, so implement it
+    private static final double LOG_DECAY_FACTOR = Math.log(DECAY_FACTOR);
+    private static double logF(final double value) {
+        return Math.log(value) / LOG_DECAY_FACTOR;
+    }
+
+    // Utility function to get a power of the decay factor, to simplify the code.
+    private static double powF(final double value) {
+        return Math.pow(DECAY_FACTOR, value);
+    }
+
+    /**
+     * Compute the value of the relevance now given an expiry date.
+     *
+     * @param expiry the date at which the column in the database expires.
+     * @return the adjusted value of the relevance for this moment in time.
+     */
+    public static int computeRelevanceForNow(final long expiry) {
+        return computeRelevanceForTargetDate(expiry, System.currentTimeMillis());
+    }
+
+    /**
+     * Compute the value of the relevance at a given date from an expiry date.
+     *
+     * Because relevance decays with time, a relevance in the past corresponds to
+     * a different relevance later.
+     *
+     * Relevance is always a positive value. 0 means not relevant at all.
+     *
+     * See the explanation at the top of this file to get the justification for this
+     * computation.
+     *
+     * @param expiry the date at which the column in the database expires.
+     * @param target the target date to adjust the relevance to.
+     * @return the adjusted value of the relevance for the target moment.
+     */
+    public static int computeRelevanceForTargetDate(final long expiry, final long target) {
+        final long delay = expiry - target;
+        if (delay >= CAPPED_RELEVANCE_LIFETIME_MS) return CAPPED_RELEVANCE;
+        if (delay <= 0) return 0;
+        return (int) (IRRELEVANCE_FLOOR / powF((float) delay / HALF_LIFE_MS) - IRRELEVANCE_FLOOR);
+    }
+
+    /**
+     * Compute the expiry duration adjusted up for a new fresh write.
+     *
+     * Every time data is written to the memory store for a given line, the
+     * relevance is bumped up by a certain amount, which will boost the priority
+     * of this line for computation of group attributes, and delay (possibly
+     * indefinitely, if the line is accessed regularly) forgetting the data stored
+     * in that line.
+     * As opposed to bumpExpiryDate, this function uses a duration from now to expiry.
+     *
+     * See the explanation at the top of this file for a justification of this computation.
+     *
+     * @param oldExpiryDuration the old expiry duration in milliseconds from now.
+     * @return the expiry duration representing a bumped up relevance value.
+     */
+    public static long bumpExpiryDuration(final long oldExpiryDuration) {
+        // L * logF(K / (I + K / F ^ (expiry1 / L))), as documented above
+        final double divisionFactor = powF(((double) oldExpiryDuration) / HALF_LIFE_MS);
+        final double oldRelevance = IRRELEVANCE_FLOOR / divisionFactor;
+        final long newDuration =
+                (long) (HALF_LIFE_MS * logF(IRRELEVANCE_FLOOR / (RELEVANCE_BUMP + oldRelevance)));
+        return Math.min(newDuration, CAPPED_RELEVANCE_LIFETIME_MS);
+    }
+
+    /**
+     * Compute the new expiry date adjusted up for a new fresh write.
+     *
+     * Every time data is written to the memory store for a given line, the
+     * relevance is bumped up by a certain amount, which will boost the priority
+     * of this line for computation of group attributes, and delay (possibly
+     * indefinitely, if the line is accessed regularly) forgetting the data stored
+     * in that line.
+     * As opposed to bumpExpiryDuration, this function takes the old timestamp and returns the
+     * new timestamp.
+     *
+     * {@see bumpExpiryDuration}, and keep in mind that the bump depends on when this is called,
+     * because the relevance decays exponentially, therefore bumping up a high relevance (for a
+     * date far in the future) is less potent than bumping up a low relevance (for a date in
+     * a close future).
+     *
+     * @param oldExpiryDate the old date of expiration.
+     * @return the new expiration date after the relevance bump.
+     */
+    public static long bumpExpiryDate(final long oldExpiryDate) {
+        final long now = System.currentTimeMillis();
+        final long newDuration = bumpExpiryDuration(oldExpiryDate - now);
+        return now + newDuration;
+    }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 855fb50..65eaf554 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -74,6 +74,7 @@
 import com.android.internal.widget.ILockSettings;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.appbinding.AppBindingService;
+import com.android.server.attention.AttentionManagerService;
 import com.android.server.audio.AudioService;
 import com.android.server.biometrics.BiometricService;
 import com.android.server.biometrics.face.FaceService;
@@ -102,10 +103,12 @@
 import com.android.server.media.projection.MediaProjectionManagerService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
+import com.android.server.net.ipmemorystore.IpMemoryStoreService;
 import com.android.server.net.watchlist.NetworkWatchlistService;
 import com.android.server.notification.NotificationManagerService;
 import com.android.server.oemlock.OemLockService;
 import com.android.server.om.OverlayManagerService;
+import com.android.server.os.BugreportManagerService;
 import com.android.server.os.DeviceIdentifiersPolicyService;
 import com.android.server.os.SchedulingPolicyService;
 import com.android.server.pm.BackgroundDexOptService;
@@ -118,6 +121,7 @@
 import com.android.server.pm.ShortcutService;
 import com.android.server.pm.UserManagerService;
 import com.android.server.policy.PhoneWindowManager;
+import com.android.server.policy.role.LegacyRoleResolutionPolicy;
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
 import com.android.server.power.ThermalManagerService;
@@ -132,6 +136,7 @@
 import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.storage.DeviceStorageMonitorService;
 import com.android.server.telecom.TelecomLoaderService;
+import com.android.server.testharness.TestHarnessModeService;
 import com.android.server.textclassifier.TextClassificationManagerService;
 import com.android.server.textservices.TextServicesManagerService;
 import com.android.server.trust.TrustManagerService;
@@ -148,6 +153,8 @@
 
 import dalvik.system.VMRuntime;
 
+import com.google.android.startop.iorap.IorapForwardingService;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.Locale;
@@ -259,6 +266,10 @@
             "com.android.server.accessibility.AccessibilityManagerService$Lifecycle";
     private static final String ADB_SERVICE_CLASS =
             "com.android.server.adb.AdbService$Lifecycle";
+    private static final String APP_PREDICTION_MANAGER_SERVICE_CLASS =
+            "com.android.server.appprediction.AppPredictionManagerService";
+    private static final String CONTENT_SUGGESTIONS_SERVICE_CLASS =
+            "com.android.server.contentsuggestions.ContentSuggestionsManagerService";
 
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
 
@@ -317,6 +328,11 @@
     private static native void startHidlServices();
 
     /**
+     * Mark this process' heap as profileable. Only for debug builds.
+     */
+    private static native void initZygoteChildHeapProfiling();
+
+    /**
      * The main entry point from zygote.
      */
     public static void main(String[] args) {
@@ -438,6 +454,11 @@
             // Initialize native services.
             System.loadLibrary("android_servers");
 
+            // Debug builds - allow heap profiling.
+            if (Build.IS_DEBUGGABLE) {
+                initZygoteChildHeapProfiling();
+            }
+
             // Check whether we failed to shut down last time we tried.
             // This call may not return.
             performPendingShutdown();
@@ -783,7 +804,12 @@
 
         // Manages apk rollbacks.
         traceBeginAndSlog("StartRollbackManagerService");
-        mSystemServiceManager.startService(RollbackManagerService.Lifecycle.class);
+        mSystemServiceManager.startService(RollbackManagerService.class);
+        traceEnd();
+
+        // Service to capture bugreports.
+        traceBeginAndSlog("StartBugreportManagerService");
+        mSystemServiceManager.startService(BugreportManagerService.class);
         traceEnd();
     }
 
@@ -847,7 +873,7 @@
                     TimingsTraceLog traceLog = new TimingsTraceLog(
                             SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
                     traceLog.traceBegin(SECONDARY_ZYGOTE_PRELOAD);
-                    if (!Process.zygoteProcess.preloadDefault(Build.SUPPORTED_32_BIT_ABIS[0])) {
+                    if (!Process.ZYGOTE_PROCESS.preloadDefault(Build.SUPPORTED_32_BIT_ABIS[0])) {
                         Slog.e(TAG, "Unable to preload default resources");
                     }
                     traceLog.traceEnd();
@@ -1007,15 +1033,30 @@
             mSystemServiceManager.startService(PinnerService.class);
             traceEnd();
 
+            traceBeginAndSlog("IorapForwardingService");
+            mSystemServiceManager.startService(IorapForwardingService.class);
+            traceEnd();
+
             traceBeginAndSlog("SignedConfigService");
             SignedConfigService.registerUpdateReceiver(mSystemContext);
             traceEnd();
-
         } catch (RuntimeException e) {
             Slog.e("System", "******************************************");
             Slog.e("System", "************ Failure starting core service", e);
         }
 
+        // Before things start rolling, be sure we have decided whether
+        // we are in safe mode.
+        final boolean safeMode = wm.detectSafeMode();
+        if (safeMode) {
+            // If yes, immediately turn on the global setting for airplane mode.
+            // Note that this does not send broadcasts at this stage because
+            // subsystems are not yet up. We will send broadcasts later to ensure
+            // all listeners have the chance to react with special handling.
+            Settings.Global.putInt(context.getContentResolver(),
+                    Settings.Global.AIRPLANE_MODE_ON, 1);
+        }
+
         StatusBarManagerService statusBar = null;
         INotificationManager notification = null;
         LocationManagerService location = null;
@@ -1117,6 +1158,10 @@
                 traceBeginAndSlog("StartPersistentDataBlock");
                 mSystemServiceManager.startService(PersistentDataBlockService.class);
                 traceEnd();
+
+                traceBeginAndSlog("StartTestHarnessMode");
+                mSystemServiceManager.startService(TestHarnessModeService.class);
+                traceEnd();
             }
 
             if (hasPdb || OemLockService.isHalPresent()) {
@@ -1149,6 +1194,16 @@
 
             startContentCaptureService(context);
 
+            // App prediction manager service
+            traceBeginAndSlog("StartAppPredictionService");
+            mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS);
+            traceEnd();
+
+            // Content suggestions manager service
+            traceBeginAndSlog("StartContentSuggestionsService");
+            mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS);
+            traceEnd();
+
             // NOTE: ClipboardService indirectly depends on IntelligenceService
             traceBeginAndSlog("StartClipboardService");
             mSystemServiceManager.startService(ClipboardService.class);
@@ -1163,6 +1218,15 @@
             }
             traceEnd();
 
+            traceBeginAndSlog("StartIpMemoryStoreService");
+            try {
+                ServiceManager.addService(Context.IP_MEMORY_STORE_SERVICE,
+                        new IpMemoryStoreService(context));
+            } catch (Throwable e) {
+                reportWtf("starting IP Memory Store Service", e);
+            }
+            traceEnd();
+
             traceBeginAndSlog("StartIpSecService");
             try {
                 ipSecService = IpSecService.create(context);
@@ -1183,6 +1247,10 @@
                 traceEnd();
             }
 
+            traceBeginAndSlog("StartAttentionManagerService");
+            mSystemServiceManager.startService(AttentionManagerService.class);
+            traceEnd();
+
             traceBeginAndSlog("StartNetworkScoreService");
             mSystemServiceManager.startService(NetworkScoreService.Lifecycle.class);
             traceEnd();
@@ -1782,9 +1850,6 @@
         mSystemServiceManager.startService(StatsCompanionService.Lifecycle.class);
         traceEnd();
 
-        // Before things start rolling, be sure we have decided whether
-        // we are in safe mode.
-        final boolean safeMode = wm.detectSafeMode();
         if (safeMode) {
             traceBeginAndSlog("EnterSafeModeAndDisableJitCompilation");
             mActivityManagerService.enterSafeMode();
@@ -1948,7 +2013,8 @@
 
             // Grants default permissions and defines roles
             traceBeginAndSlog("StartRoleManagerService");
-            mSystemServiceManager.startService(RoleManagerService.class);
+            mSystemServiceManager.startService(new RoleManagerService(
+                    mSystemContext, new LegacyRoleResolutionPolicy(mSystemContext)));
             traceEnd();
 
             // No dependency on Webview preparation in system server. But this should
@@ -1981,6 +2047,20 @@
                 reportWtf("starting System UI", e);
             }
             traceEnd();
+            // Enable airplane mode in safe mode. setAirplaneMode() cannot be called
+            // earlier as it sends broadcasts to other services.
+            // TODO: This may actually be too late if radio firmware already started leaking
+            // RF before the respective services start. However, fixing this requires changes
+            // to radio firmware and interfaces.
+            if (safeMode) {
+                traceBeginAndSlog("EnableAirplaneModeInSafeMode");
+                try {
+                    connectivityF.setAirplaneMode(true);
+                } catch (Throwable e) {
+                    reportWtf("enabling Airplane Mode during Safe Mode bootup", e);
+                }
+                traceEnd();
+            }
             traceBeginAndSlog("MakeNetworkManagementServiceReady");
             try {
                 if (networkManagementF != null) {
@@ -2175,7 +2255,7 @@
         windowManager.onSystemUiStarted();
     }
 
-    private static void traceBeginAndSlog(String name) {
+    private static void traceBeginAndSlog(@NonNull String name) {
         Slog.i(TAG, name);
         BOOT_TIMINGS_TRACE_LOG.traceBegin(name);
     }
diff --git a/services/net/Android.bp b/services/net/Android.bp
index e0ae68f..30c7de5 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -2,3 +2,19 @@
     name: "services.net",
     srcs: ["java/**/*.java"],
 }
+
+filegroup {
+    name: "services-networkstack-shared-srcs",
+    srcs: [
+        "java/android/net/ip/InterfaceController.java", // TODO: move to NetworkStack with tethering
+        "java/android/net/util/InterfaceParams.java", // TODO: move to NetworkStack with IpServer
+        "java/android/net/shared/*.java",
+    ],
+}
+
+java_library {
+    name: "services-netlink-lib",
+    srcs: [
+        "java/android/net/netlink/*.java",
+    ]
+}
diff --git a/services/net/java/android/net/apf/ApfCapabilities.java b/services/net/java/android/net/apf/ApfCapabilities.java
deleted file mode 100644
index dec8ca2..0000000
--- a/services/net/java/android/net/apf/ApfCapabilities.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.apf;
-
-/**
- * APF program support capabilities.
- *
- * @hide
- */
-public class ApfCapabilities {
-    /**
-     * Version of APF instruction set supported for packet filtering. 0 indicates no support for
-     * packet filtering using APF programs.
-     */
-    public final int apfVersionSupported;
-
-    /**
-     * Maximum size of APF program allowed.
-     */
-    public final int maximumApfProgramSize;
-
-    /**
-     * Format of packets passed to APF filter. Should be one of ARPHRD_*
-     */
-    public final int apfPacketFormat;
-
-    public ApfCapabilities(int apfVersionSupported, int maximumApfProgramSize, int apfPacketFormat)
-    {
-        this.apfVersionSupported = apfVersionSupported;
-        this.maximumApfProgramSize = maximumApfProgramSize;
-        this.apfPacketFormat = apfPacketFormat;
-    }
-
-    public String toString() {
-        return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
-                apfVersionSupported, maximumApfProgramSize, apfPacketFormat);
-    }
-
-    /**
-     * Returns true if the APF interpreter advertises support for the data buffer access opcodes
-     * LDDW and STDW.
-     *
-     * Full LDDW and STDW support is present from APFv4 on.
-     */
-    public boolean hasDataAccess() {
-        return apfVersionSupported >= 4;
-    }
-}
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
deleted file mode 100644
index f037905..0000000
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ /dev/null
@@ -1,1561 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.apf;
-
-import static android.net.util.NetworkConstants.*;
-import static android.system.OsConstants.*;
-import static com.android.internal.util.BitUtils.bytesToBEInt;
-import static com.android.internal.util.BitUtils.getUint16;
-import static com.android.internal.util.BitUtils.getUint32;
-import static com.android.internal.util.BitUtils.getUint8;
-import static com.android.internal.util.BitUtils.uint32;
-
-import android.annotation.Nullable;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.NetworkUtils;
-import android.net.apf.ApfGenerator.IllegalInstructionException;
-import android.net.apf.ApfGenerator.Register;
-import android.net.ip.IpClient;
-import android.net.metrics.ApfProgramEvent;
-import android.net.metrics.ApfStats;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.RaEvent;
-import android.net.util.InterfaceParams;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.PacketSocketAddress;
-import android.text.format.DateUtils;
-import android.util.Log;
-import android.util.Pair;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.HexDump;
-import com.android.internal.util.IndentingPrintWriter;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import libcore.io.IoBridge;
-
-/**
- * For networks that support packet filtering via APF programs, {@code ApfFilter}
- * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
- * filter out redundant duplicate ones.
- *
- * Threading model:
- * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to
- * know what RAs to filter for, thus generating APF programs is dependent on mRas.
- * mRas can be accessed by multiple threads:
- * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs.
- * - callers of:
- *    - setMulticastFilter(), which can cause an APF program to be generated.
- *    - dump(), which dumps mRas among other things.
- *    - shutdown(), which clears mRas.
- * So access to mRas is synchronized.
- *
- * @hide
- */
-public class ApfFilter {
-
-    // Helper class for specifying functional filter parameters.
-    public static class ApfConfiguration {
-        public ApfCapabilities apfCapabilities;
-        public boolean multicastFilter;
-        public boolean ieee802_3Filter;
-        public int[] ethTypeBlackList;
-    }
-
-    // Enums describing the outcome of receiving an RA packet.
-    private static enum ProcessRaResult {
-        MATCH,          // Received RA matched a known RA
-        DROPPED,        // Received RA ignored due to MAX_RAS
-        PARSE_ERROR,    // Received RA could not be parsed
-        ZERO_LIFETIME,  // Received RA had 0 lifetime
-        UPDATE_NEW_RA,  // APF program updated for new RA
-        UPDATE_EXPIRY   // APF program updated for expiry
-    }
-
-    /**
-     * APF packet counters.
-     *
-     * Packet counters are 32bit big-endian values, and allocated near the end of the APF data
-     * buffer, using negative byte offsets, where -4 is equivalent to maximumApfProgramSize - 4,
-     * the last writable 32bit word.
-     */
-    @VisibleForTesting
-    public static enum Counter {
-        RESERVED_OOB,  // Points to offset 0 from the end of the buffer (out-of-bounds)
-        TOTAL_PACKETS,
-        PASSED_ARP,
-        PASSED_DHCP,
-        PASSED_IPV4,
-        PASSED_IPV6_NON_ICMP,
-        PASSED_IPV4_UNICAST,
-        PASSED_IPV6_ICMP,
-        PASSED_IPV6_UNICAST_NON_ICMP,
-        PASSED_ARP_NON_IPV4,
-        PASSED_ARP_UNKNOWN,
-        PASSED_ARP_UNICAST_REPLY,
-        PASSED_NON_IP_UNICAST,
-        DROPPED_ETH_BROADCAST,
-        DROPPED_RA,
-        DROPPED_GARP_REPLY,
-        DROPPED_ARP_OTHER_HOST,
-        DROPPED_IPV4_L2_BROADCAST,
-        DROPPED_IPV4_BROADCAST_ADDR,
-        DROPPED_IPV4_BROADCAST_NET,
-        DROPPED_IPV4_MULTICAST,
-        DROPPED_IPV6_ROUTER_SOLICITATION,
-        DROPPED_IPV6_MULTICAST_NA,
-        DROPPED_IPV6_MULTICAST,
-        DROPPED_IPV6_MULTICAST_PING,
-        DROPPED_IPV6_NON_ICMP_MULTICAST,
-        DROPPED_802_3_FRAME,
-        DROPPED_ETHERTYPE_BLACKLISTED,
-        DROPPED_ARP_REPLY_SPA_NO_HOST;
-
-        // Returns the negative byte offset from the end of the APF data segment for
-        // a given counter.
-        public int offset() {
-            return - this.ordinal() * 4;  // Currently, all counters are 32bit long.
-        }
-
-        // Returns the total size of the data segment in bytes.
-        public static int totalSize() {
-            return (Counter.class.getEnumConstants().length - 1) * 4;
-        }
-    }
-
-    /**
-     * When APFv4 is supported, loads R1 with the offset of the specified counter.
-     */
-    private void maybeSetupCounter(ApfGenerator gen, Counter c) {
-        if (mApfCapabilities.hasDataAccess()) {
-            gen.addLoadImmediate(Register.R1, c.offset());
-        }
-    }
-
-    // When APFv4 is supported, these point to the trampolines generated by emitEpilogue().
-    // Otherwise, they're just aliases for PASS_LABEL and DROP_LABEL.
-    private final String mCountAndPassLabel;
-    private final String mCountAndDropLabel;
-
-    // Thread to listen for RAs.
-    @VisibleForTesting
-    class ReceiveThread extends Thread {
-        private final byte[] mPacket = new byte[1514];
-        private final FileDescriptor mSocket;
-        private final long mStart = SystemClock.elapsedRealtime();
-        private final ApfStats mStats = new ApfStats();
-
-        private volatile boolean mStopped;
-
-        public ReceiveThread(FileDescriptor socket) {
-            mSocket = socket;
-        }
-
-        public void halt() {
-            mStopped = true;
-            try {
-                // Interrupts the read() call the thread is blocked in.
-                IoBridge.closeAndSignalBlockedThreads(mSocket);
-            } catch (IOException ignored) {}
-        }
-
-        @Override
-        public void run() {
-            log("begin monitoring");
-            while (!mStopped) {
-                try {
-                    int length = Os.read(mSocket, mPacket, 0, mPacket.length);
-                    updateStats(processRa(mPacket, length));
-                } catch (IOException|ErrnoException e) {
-                    if (!mStopped) {
-                        Log.e(TAG, "Read error", e);
-                    }
-                }
-            }
-            logStats();
-        }
-
-        private void updateStats(ProcessRaResult result) {
-            mStats.receivedRas++;
-            switch(result) {
-                case MATCH:
-                    mStats.matchingRas++;
-                    return;
-                case DROPPED:
-                    mStats.droppedRas++;
-                    return;
-                case PARSE_ERROR:
-                    mStats.parseErrors++;
-                    return;
-                case ZERO_LIFETIME:
-                    mStats.zeroLifetimeRas++;
-                    return;
-                case UPDATE_EXPIRY:
-                    mStats.matchingRas++;
-                    mStats.programUpdates++;
-                    return;
-                case UPDATE_NEW_RA:
-                    mStats.programUpdates++;
-                    return;
-            }
-        }
-
-        private void logStats() {
-            final long nowMs = SystemClock.elapsedRealtime();
-            synchronized (this) {
-                mStats.durationMs = nowMs - mStart;
-                mStats.maxProgramSize = mApfCapabilities.maximumApfProgramSize;
-                mStats.programUpdatesAll = mNumProgramUpdates;
-                mStats.programUpdatesAllowingMulticast = mNumProgramUpdatesAllowingMulticast;
-                mMetricsLog.log(mStats);
-                logApfProgramEventLocked(nowMs / DateUtils.SECOND_IN_MILLIS);
-            }
-        }
-    }
-
-    private static final String TAG = "ApfFilter";
-    private static final boolean DBG = true;
-    private static final boolean VDBG = false;
-
-    private static final int ETH_HEADER_LEN = 14;
-    private static final int ETH_DEST_ADDR_OFFSET = 0;
-    private static final int ETH_ETHERTYPE_OFFSET = 12;
-    private static final int ETH_TYPE_MIN = 0x0600;
-    private static final int ETH_TYPE_MAX = 0xFFFF;
-    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
-            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
-    // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
-    private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
-    // Endianness is not an issue for this constant because the APF interpreter always operates in
-    // network byte order.
-    private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff;
-    private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
-    private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
-    private static final int IPV4_ANY_HOST_ADDRESS = 0;
-    private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
-
-    // Traffic class and Flow label are not byte aligned. Luckily we
-    // don't care about either value so we'll consider bytes 1-3 of the
-    // IPv6 header as don't care.
-    private static final int IPV6_FLOW_LABEL_OFFSET = ETH_HEADER_LEN + 1;
-    private static final int IPV6_FLOW_LABEL_LEN = 3;
-    private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
-    private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
-    private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
-    private static final int IPV6_HEADER_LEN = 40;
-    // The IPv6 all nodes address ff02::1
-    private static final byte[] IPV6_ALL_NODES_ADDRESS =
-            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
-
-    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
-
-    // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
-    private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
-    private static final int UDP_HEADER_LEN = 8;
-
-    private static final int DHCP_CLIENT_PORT = 68;
-    // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
-    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
-
-    private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
-    private static final byte[] ARP_IPV4_HEADER = {
-            0, 1, // Hardware type: Ethernet (1)
-            8, 0, // Protocol type: IP (0x0800)
-            6,    // Hardware size: 6
-            4,    // Protocol size: 4
-    };
-    private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
-    // Opcode: ARP request (0x0001), ARP reply (0x0002)
-    private static final short ARP_OPCODE_REQUEST = 1;
-    private static final short ARP_OPCODE_REPLY = 2;
-    private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
-    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
-    // Do not log ApfProgramEvents whose actual lifetimes was less than this.
-    private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2;
-    // Limit on the Black List size to cap on program usage for this
-    // TODO: Select a proper max length
-    private static final int APF_MAX_ETH_TYPE_BLACK_LIST_LEN = 20;
-
-    private final ApfCapabilities mApfCapabilities;
-    private final IpClient.Callback mIpClientCallback;
-    private final InterfaceParams mInterfaceParams;
-    private final IpConnectivityLog mMetricsLog;
-
-    @VisibleForTesting
-    byte[] mHardwareAddress;
-    @VisibleForTesting
-    ReceiveThread mReceiveThread;
-    @GuardedBy("this")
-    private long mUniqueCounter;
-    @GuardedBy("this")
-    private boolean mMulticastFilter;
-    @GuardedBy("this")
-    private boolean mInDozeMode;
-    private final boolean mDrop802_3Frames;
-    private final int[] mEthTypeBlackList;
-
-    // Detects doze mode state transitions.
-    private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
-                PowerManager powerManager =
-                        (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-                final boolean deviceIdle = powerManager.isDeviceIdleMode();
-                setDozeMode(deviceIdle);
-            }
-        }
-    };
-    private final Context mContext;
-
-    // Our IPv4 address, if we have just one, otherwise null.
-    @GuardedBy("this")
-    private byte[] mIPv4Address;
-    // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
-    @GuardedBy("this")
-    private int mIPv4PrefixLength;
-
-    @VisibleForTesting
-    ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
-            IpClient.Callback ipClientCallback, IpConnectivityLog log) {
-        mApfCapabilities = config.apfCapabilities;
-        mIpClientCallback = ipClientCallback;
-        mInterfaceParams = ifParams;
-        mMulticastFilter = config.multicastFilter;
-        mDrop802_3Frames = config.ieee802_3Filter;
-        mContext = context;
-
-        if (mApfCapabilities.hasDataAccess()) {
-            mCountAndPassLabel = "countAndPass";
-            mCountAndDropLabel = "countAndDrop";
-        } else {
-            // APFv4 unsupported: turn jumps to the counter trampolines to immediately PASS or DROP,
-            // preserving the original pre-APFv4 behavior.
-            mCountAndPassLabel = ApfGenerator.PASS_LABEL;
-            mCountAndDropLabel = ApfGenerator.DROP_LABEL;
-        }
-
-        // Now fill the black list from the passed array
-        mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
-
-        mMetricsLog = log;
-
-        // TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
-        maybeStartFilter();
-
-        // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter.
-        mContext.registerReceiver(mDeviceIdleReceiver,
-                new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
-    }
-
-    public synchronized void setDataSnapshot(byte[] data) {
-        mDataSnapshot = data;
-    }
-
-    private void log(String s) {
-        Log.d(TAG, "(" + mInterfaceParams.name + "): " + s);
-    }
-
-    @GuardedBy("this")
-    private long getUniqueNumberLocked() {
-        return mUniqueCounter++;
-    }
-
-    @GuardedBy("this")
-    private static int[] filterEthTypeBlackList(int[] ethTypeBlackList) {
-        ArrayList<Integer> bl = new ArrayList<Integer>();
-
-        for (int p : ethTypeBlackList) {
-            // Check if the protocol is a valid ether type
-            if ((p < ETH_TYPE_MIN) || (p > ETH_TYPE_MAX)) {
-                continue;
-            }
-
-            // Check if the protocol is not repeated in the passed array
-            if (bl.contains(p)) {
-                continue;
-            }
-
-            // Check if list reach its max size
-            if (bl.size() == APF_MAX_ETH_TYPE_BLACK_LIST_LEN) {
-                Log.w(TAG, "Passed EthType Black List size too large (" + bl.size() +
-                        ") using top " + APF_MAX_ETH_TYPE_BLACK_LIST_LEN + " protocols");
-                break;
-            }
-
-            // Now add the protocol to the list
-            bl.add(p);
-        }
-
-        return bl.stream().mapToInt(Integer::intValue).toArray();
-    }
-
-    /**
-     * Attempt to start listening for RAs and, if RAs are received, generating and installing
-     * filters to ignore useless RAs.
-     */
-    @VisibleForTesting
-    void maybeStartFilter() {
-        FileDescriptor socket;
-        try {
-            mHardwareAddress = mInterfaceParams.macAddr.toByteArray();
-            synchronized(this) {
-                // Clear the APF memory to reset all counters upon connecting to the first AP
-                // in an SSID. This is limited to APFv4 devices because this large write triggers
-                // a crash on some older devices (b/78905546).
-                if (mApfCapabilities.hasDataAccess()) {
-                    byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize];
-                    mIpClientCallback.installPacketFilter(zeroes);
-                }
-
-                // Install basic filters
-                installNewProgramLocked();
-            }
-            socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
-            PacketSocketAddress addr = new PacketSocketAddress(
-                    (short) ETH_P_IPV6, mInterfaceParams.index);
-            Os.bind(socket, addr);
-            NetworkUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat);
-        } catch(SocketException|ErrnoException e) {
-            Log.e(TAG, "Error starting filter", e);
-            return;
-        }
-        mReceiveThread = new ReceiveThread(socket);
-        mReceiveThread.start();
-    }
-
-    // Returns seconds since device boot.
-    @VisibleForTesting
-    protected long currentTimeSeconds() {
-        return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
-    }
-
-    public static class InvalidRaException extends Exception {
-        public InvalidRaException(String m) {
-            super(m);
-        }
-    }
-
-    // A class to hold information about an RA.
-    @VisibleForTesting
-    class Ra {
-        // From RFC4861:
-        private static final int ICMP6_RA_HEADER_LEN = 16;
-        private static final int ICMP6_RA_CHECKSUM_OFFSET =
-                ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
-        private static final int ICMP6_RA_CHECKSUM_LEN = 2;
-        private static final int ICMP6_RA_OPTION_OFFSET =
-                ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
-        private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
-                ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
-        private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2;
-        // Prefix information option.
-        private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
-        private static final int ICMP6_PREFIX_OPTION_LEN = 32;
-        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
-        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4;
-        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
-        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4;
-
-        // From RFC6106: Recursive DNS Server option
-        private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
-        // From RFC6106: DNS Search List option
-        private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
-
-        // From RFC4191: Route Information option
-        private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
-        // Above three options all have the same format:
-        private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
-        private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
-
-        // Note: mPacket's position() cannot be assumed to be reset.
-        private final ByteBuffer mPacket;
-        // List of binary ranges that include the whole packet except the lifetimes.
-        // Pairs consist of offset and length.
-        private final ArrayList<Pair<Integer, Integer>> mNonLifetimes =
-                new ArrayList<Pair<Integer, Integer>>();
-        // Minimum lifetime in packet
-        long mMinLifetime;
-        // When the packet was last captured, in seconds since Unix Epoch
-        long mLastSeen;
-
-        // For debugging only. Offsets into the packet where PIOs are.
-        private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>();
-
-        // For debugging only. Offsets into the packet where RDNSS options are.
-        private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>();
-
-        // For debugging only. How many times this RA was seen.
-        int seenCount = 0;
-
-        // For debugging only. Returns the hex representation of the last matching packet.
-        String getLastMatchingPacket() {
-            return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(),
-                    false /* lowercase */);
-        }
-
-        // For debugging only. Returns the string representation of the IPv6 address starting at
-        // position pos in the packet.
-        private String IPv6AddresstoString(int pos) {
-            try {
-                byte[] array = mPacket.array();
-                // Can't just call copyOfRange() and see if it throws, because if it reads past the
-                // end it pads with zeros instead of throwing.
-                if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) {
-                    return "???";
-                }
-                byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16);
-                InetAddress address = (Inet6Address) InetAddress.getByAddress(addressBytes);
-                return address.getHostAddress();
-            } catch (UnsupportedOperationException e) {
-                // array() failed. Cannot happen, mPacket is array-backed and read-write.
-                return "???";
-            } catch (ClassCastException|UnknownHostException e) {
-                // Cannot happen.
-                return "???";
-            }
-        }
-
-        // Can't be static because it's in a non-static inner class.
-        // TODO: Make this static once RA is its own class.
-        private void prefixOptionToString(StringBuffer sb, int offset) {
-            String prefix = IPv6AddresstoString(offset + 16);
-            int length = getUint8(mPacket, offset + 2);
-            long valid = getUint32(mPacket, offset + 4);
-            long preferred = getUint32(mPacket, offset + 8);
-            sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
-        }
-
-        private void rdnssOptionToString(StringBuffer sb, int offset) {
-            int optLen = getUint8(mPacket, offset + 1) * 8;
-            if (optLen < 24) return;  // Malformed or empty.
-            long lifetime = getUint32(mPacket, offset + 4);
-            int numServers = (optLen - 8) / 16;
-            sb.append("DNS ").append(lifetime).append("s");
-            for (int server = 0; server < numServers; server++) {
-                sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server));
-            }
-        }
-
-        public String toString() {
-            try {
-                StringBuffer sb = new StringBuffer();
-                sb.append(String.format("RA %s -> %s %ds ",
-                        IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
-                        IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
-                        getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)));
-                for (int i: mPrefixOptionOffsets) {
-                    prefixOptionToString(sb, i);
-                }
-                for (int i: mRdnssOptionOffsets) {
-                    rdnssOptionToString(sb, i);
-                }
-                return sb.toString();
-            } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
-                return "<Malformed RA>";
-            }
-        }
-
-        /**
-         * Add a binary range of the packet that does not include a lifetime to mNonLifetimes.
-         * Assumes mPacket.position() is as far as we've parsed the packet.
-         * @param lastNonLifetimeStart offset within packet of where the last binary range of
-         *                             data not including a lifetime.
-         * @param lifetimeOffset offset from mPacket.position() to the next lifetime data.
-         * @param lifetimeLength length of the next lifetime data.
-         * @return offset within packet of where the next binary range of data not including
-         *         a lifetime. This can be passed into the next invocation of this function
-         *         via {@code lastNonLifetimeStart}.
-         */
-        private int addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset,
-                int lifetimeLength) {
-            lifetimeOffset += mPacket.position();
-            mNonLifetimes.add(new Pair<Integer, Integer>(lastNonLifetimeStart,
-                    lifetimeOffset - lastNonLifetimeStart));
-            return lifetimeOffset + lifetimeLength;
-        }
-
-        private int addNonLifetimeU32(int lastNonLifetimeStart) {
-            return addNonLifetime(lastNonLifetimeStart,
-                    ICMP6_4_BYTE_LIFETIME_OFFSET, ICMP6_4_BYTE_LIFETIME_LEN);
-        }
-
-        // Note that this parses RA and may throw InvalidRaException (from
-        // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
-        // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
-        // specifications.
-        Ra(byte[] packet, int length) throws InvalidRaException {
-            if (length < ICMP6_RA_OPTION_OFFSET) {
-                throw new InvalidRaException("Not an ICMP6 router advertisement");
-            }
-
-            mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
-            mLastSeen = currentTimeSeconds();
-
-            // Sanity check packet in case a packet arrives before we attach RA filter
-            // to our packet socket. b/29586253
-            if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
-                    getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
-                    getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) {
-                throw new InvalidRaException("Not an ICMP6 router advertisement");
-            }
-
-
-            RaEvent.Builder builder = new RaEvent.Builder();
-
-            // Ignore the flow label and low 4 bits of traffic class.
-            int lastNonLifetimeStart = addNonLifetime(0,
-                    IPV6_FLOW_LABEL_OFFSET,
-                    IPV6_FLOW_LABEL_LEN);
-
-            // Ignore the checksum.
-            lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
-                    ICMP6_RA_CHECKSUM_OFFSET,
-                    ICMP6_RA_CHECKSUM_LEN);
-
-            // Parse router lifetime
-            lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
-                    ICMP6_RA_ROUTER_LIFETIME_OFFSET,
-                    ICMP6_RA_ROUTER_LIFETIME_LEN);
-            builder.updateRouterLifetime(getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET));
-
-            // Ensures that the RA is not truncated.
-            mPacket.position(ICMP6_RA_OPTION_OFFSET);
-            while (mPacket.hasRemaining()) {
-                final int position = mPacket.position();
-                final int optionType = getUint8(mPacket, position);
-                final int optionLength = getUint8(mPacket, position + 1) * 8;
-                long lifetime;
-                switch (optionType) {
-                    case ICMP6_PREFIX_OPTION_TYPE:
-                        // Parse valid lifetime
-                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
-                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
-                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN);
-                        lifetime = getUint32(mPacket,
-                                position + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
-                        builder.updatePrefixValidLifetime(lifetime);
-                        // Parse preferred lifetime
-                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
-                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
-                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN);
-                        lifetime = getUint32(mPacket,
-                                position + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET);
-                        builder.updatePrefixPreferredLifetime(lifetime);
-                        mPrefixOptionOffsets.add(position);
-                        break;
-                    // These three options have the same lifetime offset and size, and
-                    // are processed with the same specialized addNonLifetimeU32:
-                    case ICMP6_RDNSS_OPTION_TYPE:
-                        mRdnssOptionOffsets.add(position);
-                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
-                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
-                        builder.updateRdnssLifetime(lifetime);
-                        break;
-                    case ICMP6_ROUTE_INFO_OPTION_TYPE:
-                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
-                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
-                        builder.updateRouteInfoLifetime(lifetime);
-                        break;
-                    case ICMP6_DNSSL_OPTION_TYPE:
-                        lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
-                        lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
-                        builder.updateDnsslLifetime(lifetime);
-                        break;
-                    default:
-                        // RFC4861 section 4.2 dictates we ignore unknown options for fowards
-                        // compatibility.
-                        break;
-                }
-                if (optionLength <= 0) {
-                    throw new InvalidRaException(String.format(
-                        "Invalid option length opt=%d len=%d", optionType, optionLength));
-                }
-                mPacket.position(position + optionLength);
-            }
-            // Mark non-lifetime bytes since last lifetime.
-            addNonLifetime(lastNonLifetimeStart, 0, 0);
-            mMinLifetime = minLifetime(packet, length);
-            mMetricsLog.log(builder.build());
-        }
-
-        // Ignoring lifetimes (which may change) does {@code packet} match this RA?
-        boolean matches(byte[] packet, int length) {
-            if (length != mPacket.capacity()) return false;
-            byte[] referencePacket = mPacket.array();
-            for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) {
-                for (int i = nonLifetime.first; i < (nonLifetime.first + nonLifetime.second); i++) {
-                    if (packet[i] != referencePacket[i]) return false;
-                }
-            }
-            return true;
-        }
-
-        // What is the minimum of all lifetimes within {@code packet} in seconds?
-        // Precondition: matches(packet, length) already returned true.
-        long minLifetime(byte[] packet, int length) {
-            long minLifetime = Long.MAX_VALUE;
-            // Wrap packet in ByteBuffer so we can read big-endian values easily
-            ByteBuffer byteBuffer = ByteBuffer.wrap(packet);
-            for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) {
-                int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second;
-
-                // The flow label is in mNonLifetimes, but it's not a lifetime.
-                if (offset == IPV6_FLOW_LABEL_OFFSET) {
-                    continue;
-                }
-
-                // The checksum is in mNonLifetimes, but it's not a lifetime.
-                if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
-                    continue;
-                }
-
-                final int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
-                final long optionLifetime;
-                switch (lifetimeLength) {
-                    case 2:
-                        optionLifetime = getUint16(byteBuffer, offset);
-                        break;
-                    case 4:
-                        optionLifetime = getUint32(byteBuffer, offset);
-                        break;
-                    default:
-                        throw new IllegalStateException("bogus lifetime size " + lifetimeLength);
-                }
-                minLifetime = Math.min(minLifetime, optionLifetime);
-            }
-            return minLifetime;
-        }
-
-        // How many seconds does this RA's have to live, taking into account the fact
-        // that we might have seen it a while ago.
-        long currentLifetime() {
-            return mMinLifetime - (currentTimeSeconds() - mLastSeen);
-        }
-
-        boolean isExpired() {
-            // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll
-            // have to calculte the filter lifetime specially as a fraction of 0 is still 0.
-            return currentLifetime() <= 0;
-        }
-
-        // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
-        // Jump to the next filter if packet doesn't match this RA.
-        @GuardedBy("ApfFilter.this")
-        long generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
-            String nextFilterLabel = "Ra" + getUniqueNumberLocked();
-            // Skip if packet is not the right size
-            gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
-            gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
-            int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
-            // Skip filter if expired
-            gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
-            gen.addJumpIfR0GreaterThan(filterLifetime, nextFilterLabel);
-            for (int i = 0; i < mNonLifetimes.size(); i++) {
-                // Generate code to match the packet bytes
-                Pair<Integer, Integer> nonLifetime = mNonLifetimes.get(i);
-                // Don't generate JNEBS instruction for 0 bytes as it always fails the
-                // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check where cmp_imm is
-                // the number of bytes to compare. nonLifetime is zero between the
-                // valid and preferred lifetimes in the prefix option.
-                if (nonLifetime.second != 0) {
-                    gen.addLoadImmediate(Register.R0, nonLifetime.first);
-                    gen.addJumpIfBytesNotEqual(Register.R0,
-                            Arrays.copyOfRange(mPacket.array(), nonLifetime.first,
-                                               nonLifetime.first + nonLifetime.second),
-                            nextFilterLabel);
-                }
-                // Generate code to test the lifetimes haven't gone down too far
-                if ((i + 1) < mNonLifetimes.size()) {
-                    Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1);
-                    int offset = nonLifetime.first + nonLifetime.second;
-
-                    // Skip the Flow label.
-                    if (offset == IPV6_FLOW_LABEL_OFFSET) {
-                        continue;
-                    }
-                    // Skip the checksum.
-                    if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
-                        continue;
-                    }
-                    int length = nextNonLifetime.first - offset;
-                    switch (length) {
-                        case 4: gen.addLoad32(Register.R0, offset); break;
-                        case 2: gen.addLoad16(Register.R0, offset); break;
-                        default: throw new IllegalStateException("bogus lifetime size " + length);
-                    }
-                    gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel);
-                }
-            }
-            maybeSetupCounter(gen, Counter.DROPPED_RA);
-            gen.addJump(mCountAndDropLabel);
-            gen.defineLabel(nextFilterLabel);
-            return filterLifetime;
-        }
-    }
-
-    // Maximum number of RAs to filter for.
-    private static final int MAX_RAS = 10;
-
-    @GuardedBy("this")
-    private ArrayList<Ra> mRas = new ArrayList<Ra>();
-
-    // There is always some marginal benefit to updating the installed APF program when an RA is
-    // seen because we can extend the program's lifetime slightly, but there is some cost to
-    // updating the program, so don't bother unless the program is going to expire soon. This
-    // constant defines "soon" in seconds.
-    private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30;
-    // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
-    // see a refresh.  Using half the lifetime might be a good idea except for the fact that
-    // packets may be dropped, so let's use 6.
-    private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
-
-    // When did we last install a filter program? In seconds since Unix Epoch.
-    @GuardedBy("this")
-    private long mLastTimeInstalledProgram;
-    // How long should the last installed filter program live for? In seconds.
-    @GuardedBy("this")
-    private long mLastInstalledProgramMinLifetime;
-    @GuardedBy("this")
-    private ApfProgramEvent mLastInstallEvent;
-
-    // For debugging only. The last program installed.
-    @GuardedBy("this")
-    private byte[] mLastInstalledProgram;
-
-    /**
-     * For debugging only. Contains the latest APF buffer snapshot captured from the firmware.
-     *
-     * A typical size for this buffer is 4KB. It is present only if the WiFi HAL supports
-     * IWifiStaIface#readApfPacketFilterData(), and the APF interpreter advertised support for
-     * the opcodes to access the data buffer (LDDW and STDW).
-     */
-    @GuardedBy("this") @Nullable
-    private byte[] mDataSnapshot;
-
-    // How many times the program was updated since we started.
-    @GuardedBy("this")
-    private int mNumProgramUpdates = 0;
-    // How many times the program was updated since we started for allowing multicast traffic.
-    @GuardedBy("this")
-    private int mNumProgramUpdatesAllowingMulticast = 0;
-
-    /**
-     * Generate filter code to process ARP packets. Execution of this code ends in either the
-     * DROP_LABEL or PASS_LABEL and does not fall off the end.
-     * Preconditions:
-     *  - Packet being filtered is ARP
-     */
-    @GuardedBy("this")
-    private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
-        // Here's a basic summary of what the ARP filter program does:
-        //
-        // if not ARP IPv4
-        //   pass
-        // if not ARP IPv4 reply or request
-        //   pass
-        // if ARP reply source ip is 0.0.0.0
-        //   drop
-        // if unicast ARP reply
-        //   pass
-        // if interface has no IPv4 address
-        //   if target ip is 0.0.0.0
-        //      drop
-        // else
-        //   if target ip is not the interface ip
-        //      drop
-        // pass
-
-        final String checkTargetIPv4 = "checkTargetIPv4";
-
-        // Pass if not ARP IPv4.
-        gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
-        maybeSetupCounter(gen, Counter.PASSED_ARP_NON_IPV4);
-        gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, mCountAndPassLabel);
-
-        // Pass if unknown ARP opcode.
-        gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET);
-        gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check
-        maybeSetupCounter(gen, Counter.PASSED_ARP_UNKNOWN);
-        gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, mCountAndPassLabel);
-
-        // Drop if ARP reply source IP is 0.0.0.0
-        gen.addLoad32(Register.R0, ARP_SOURCE_IP_ADDRESS_OFFSET);
-        maybeSetupCounter(gen, Counter.DROPPED_ARP_REPLY_SPA_NO_HOST);
-        gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
-
-        // Pass if unicast reply.
-        gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
-        maybeSetupCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY);
-        gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
-
-        // Either a unicast request, a unicast reply, or a broadcast reply.
-        gen.defineLabel(checkTargetIPv4);
-        if (mIPv4Address == null) {
-            // When there is no IPv4 address, drop GARP replies (b/29404209).
-            gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
-            maybeSetupCounter(gen, Counter.DROPPED_GARP_REPLY);
-            gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
-        } else {
-            // When there is an IPv4 address, drop unicast/broadcast requests
-            // and broadcast replies with a different target IPv4 address.
-            gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
-            maybeSetupCounter(gen, Counter.DROPPED_ARP_OTHER_HOST);
-            gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, mCountAndDropLabel);
-        }
-
-        maybeSetupCounter(gen, Counter.PASSED_ARP);
-        gen.addJump(mCountAndPassLabel);
-    }
-
-    /**
-     * Generate filter code to process IPv4 packets. Execution of this code ends in either the
-     * DROP_LABEL or PASS_LABEL and does not fall off the end.
-     * Preconditions:
-     *  - Packet being filtered is IPv4
-     */
-    @GuardedBy("this")
-    private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
-        // Here's a basic summary of what the IPv4 filter program does:
-        //
-        // if filtering multicast (i.e. multicast lock not held):
-        //   if it's DHCP destined to our MAC:
-        //     pass
-        //   if it's L2 broadcast:
-        //     drop
-        //   if it's IPv4 multicast:
-        //     drop
-        //   if it's IPv4 broadcast:
-        //     drop
-        // pass
-
-        if (mMulticastFilter) {
-            final String skipDhcpv4Filter = "skip_dhcp_v4_filter";
-
-            // Pass DHCP addressed to us.
-            // Check it's UDP.
-            gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
-            gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter);
-            // Check it's not a fragment. This matches the BPF filter installed by the DHCP client.
-            gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
-            gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter);
-            // Check it's addressed to DHCP client port.
-            gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
-            gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
-            gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
-            // Check it's DHCP to our MAC address.
-            gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
-            // NOTE: Relies on R1 containing IPv4 header offset.
-            gen.addAddR1();
-            gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
-            maybeSetupCounter(gen, Counter.PASSED_DHCP);
-            gen.addJump(mCountAndPassLabel);
-
-            // Drop all multicasts/broadcasts.
-            gen.defineLabel(skipDhcpv4Filter);
-
-            // If IPv4 destination address is in multicast range, drop.
-            gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
-            gen.addAnd(0xf0);
-            maybeSetupCounter(gen, Counter.DROPPED_IPV4_MULTICAST);
-            gen.addJumpIfR0Equals(0xe0, mCountAndDropLabel);
-
-            // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
-            maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_ADDR);
-            gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
-            gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, mCountAndDropLabel);
-            if (mIPv4Address != null && mIPv4PrefixLength < 31) {
-                maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_NET);
-                int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
-                gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
-            }
-
-            // If L2 broadcast packet, drop.
-            // TODO: can we invert this condition to fall through to the common pass case below?
-            maybeSetupCounter(gen, Counter.PASSED_IPV4_UNICAST);
-            gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
-            gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
-            maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
-            gen.addJump(mCountAndDropLabel);
-        }
-
-        // Otherwise, pass
-        maybeSetupCounter(gen, Counter.PASSED_IPV4);
-        gen.addJump(mCountAndPassLabel);
-    }
-
-
-    /**
-     * Generate filter code to process IPv6 packets. Execution of this code ends in either the
-     * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
-     * Preconditions:
-     *  - Packet being filtered is IPv6
-     */
-    @GuardedBy("this")
-    private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
-        // Here's a basic summary of what the IPv6 filter program does:
-        //
-        // if we're dropping multicast
-        //   if it's not IPCMv6 or it's ICMPv6 but we're in doze mode:
-        //     if it's multicast:
-        //       drop
-        //     pass
-        // if it's ICMPv6 RS to any:
-        //   drop
-        // if it's ICMPv6 NA to ff02::1:
-        //   drop
-
-        gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
-
-        // Drop multicast if the multicast filter is enabled.
-        if (mMulticastFilter) {
-            final String skipIPv6MulticastFilterLabel = "skipIPv6MulticastFilter";
-            final String dropAllIPv6MulticastsLabel = "dropAllIPv6Multicast";
-
-            // While in doze mode, drop ICMPv6 multicast pings, let the others pass.
-            // While awake, let all ICMPv6 multicasts through.
-            if (mInDozeMode) {
-                // Not ICMPv6? -> Proceed to multicast filtering
-                gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel);
-
-                // ICMPv6 but not ECHO? -> Skip the multicast filter.
-                // (ICMPv6 ECHO requests will go through the multicast filter below).
-                gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
-                gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel);
-            } else {
-                gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel);
-            }
-
-            // Drop all other packets sent to ff00::/8 (multicast prefix).
-            gen.defineLabel(dropAllIPv6MulticastsLabel);
-            maybeSetupCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
-            gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
-            gen.addJumpIfR0Equals(0xff, mCountAndDropLabel);
-            // Not multicast. Pass.
-            maybeSetupCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP);
-            gen.addJump(mCountAndPassLabel);
-            gen.defineLabel(skipIPv6MulticastFilterLabel);
-        } else {
-            // If not ICMPv6, pass.
-            maybeSetupCounter(gen, Counter.PASSED_IPV6_NON_ICMP);
-            gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel);
-        }
-
-        // If we got this far, the packet is ICMPv6.  Drop some specific types.
-
-        // Add unsolicited multicast neighbor announcements filter
-        String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
-        gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
-        // Drop all router solicitations (b/32833400)
-        maybeSetupCounter(gen, Counter.DROPPED_IPV6_ROUTER_SOLICITATION);
-        gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, mCountAndDropLabel);
-        // If not neighbor announcements, skip filter.
-        gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
-        // If to ff02::1, drop.
-        // TODO: Drop only if they don't contain the address of on-link neighbours.
-        gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
-        gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
-                skipUnsolicitedMulticastNALabel);
-        maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
-        gen.addJump(mCountAndDropLabel);
-        gen.defineLabel(skipUnsolicitedMulticastNALabel);
-    }
-
-    /**
-     * Begin generating an APF program to:
-     * <ul>
-     * <li>Drop/Pass 802.3 frames (based on policy)
-     * <li>Drop packets with EtherType within the Black List
-     * <li>Drop ARP requests not for us, if mIPv4Address is set,
-     * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
-     * <li>Drop IPv4 multicast packets, if mMulticastFilter,
-     * <li>Pass all other IPv4 packets,
-     * <li>Drop all broadcast non-IP non-ARP packets.
-     * <li>Pass all non-ICMPv6 IPv6 packets,
-     * <li>Pass all non-IPv4 and non-IPv6 packets,
-     * <li>Drop IPv6 ICMPv6 NAs to ff02::1.
-     * <li>Drop IPv6 ICMPv6 RSs.
-     * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
-     *     insertion of RA filters here, or if there aren't any, just passes the packets.
-     * </ul>
-     */
-    @GuardedBy("this")
-    private ApfGenerator emitPrologueLocked() throws IllegalInstructionException {
-        // This is guaranteed to succeed because of the check in maybeCreate.
-        ApfGenerator gen = new ApfGenerator(mApfCapabilities.apfVersionSupported);
-
-        if (mApfCapabilities.hasDataAccess()) {
-            // Increment TOTAL_PACKETS
-            maybeSetupCounter(gen, Counter.TOTAL_PACKETS);
-            gen.addLoadData(Register.R0, 0);  // load counter
-            gen.addAdd(1);
-            gen.addStoreData(Register.R0, 0);  // write-back counter
-        }
-
-        // Here's a basic summary of what the initial program does:
-        //
-        // if it's a 802.3 Frame (ethtype < 0x0600):
-        //    drop or pass based on configurations
-        // if it has a ether-type that belongs to the black list
-        //    drop
-        // if it's ARP:
-        //   insert ARP filter to drop or pass these appropriately
-        // if it's IPv4:
-        //   insert IPv4 filter to drop or pass these appropriately
-        // if it's not IPv6:
-        //   if it's broadcast:
-        //     drop
-        //   pass
-        // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
-
-        gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
-
-        if (mDrop802_3Frames) {
-            // drop 802.3 frames (ethtype < 0x0600)
-            maybeSetupCounter(gen, Counter.DROPPED_802_3_FRAME);
-            gen.addJumpIfR0LessThan(ETH_TYPE_MIN, mCountAndDropLabel);
-        }
-
-        // Handle ether-type black list
-        maybeSetupCounter(gen, Counter.DROPPED_ETHERTYPE_BLACKLISTED);
-        for (int p : mEthTypeBlackList) {
-            gen.addJumpIfR0Equals(p, mCountAndDropLabel);
-        }
-
-        // Add ARP filters:
-        String skipArpFiltersLabel = "skipArpFilters";
-        gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
-        generateArpFilterLocked(gen);
-        gen.defineLabel(skipArpFiltersLabel);
-
-        // Add IPv4 filters:
-        String skipIPv4FiltersLabel = "skipIPv4Filters";
-        // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
-        // execute the ARP filter, since that filter does not fall through, but either drops or
-        // passes.
-        gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
-        generateIPv4FilterLocked(gen);
-        gen.defineLabel(skipIPv4FiltersLabel);
-
-        // Check for IPv6:
-        // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
-        // execute the ARP or IPv4 filters, since those filters do not fall through, but either
-        // drop or pass.
-        String ipv6FilterLabel = "IPv6Filters";
-        gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel);
-
-        // Drop non-IP non-ARP broadcasts, pass the rest
-        gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
-        maybeSetupCounter(gen, Counter.PASSED_NON_IP_UNICAST);
-        gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
-        maybeSetupCounter(gen, Counter.DROPPED_ETH_BROADCAST);
-        gen.addJump(mCountAndDropLabel);
-
-        // Add IPv6 filters:
-        gen.defineLabel(ipv6FilterLabel);
-        generateIPv6FilterLocked(gen);
-        return gen;
-    }
-
-    /**
-     * Append packet counting epilogue to the APF program.
-     *
-     * Currently, the epilogue consists of two trampolines which count passed and dropped packets
-     * before jumping to the actual PASS and DROP labels.
-     */
-    @GuardedBy("this")
-    private void emitEpilogue(ApfGenerator gen) throws IllegalInstructionException {
-        // If APFv4 is unsupported, no epilogue is necessary: if execution reached this far, it
-        // will just fall-through to the PASS label.
-        if (!mApfCapabilities.hasDataAccess()) return;
-
-        // Execution will reach the bottom of the program if none of the filters match,
-        // which will pass the packet to the application processor.
-        maybeSetupCounter(gen, Counter.PASSED_IPV6_ICMP);
-
-        // Append the count & pass trampoline, which increments the counter at the data address
-        // pointed to by R1, then jumps to the pass label. This saves a few bytes over inserting
-        // the entire sequence inline for every counter.
-        gen.defineLabel(mCountAndPassLabel);
-        gen.addLoadData(Register.R0, 0);   // R0 = *(R1 + 0)
-        gen.addAdd(1);                     // R0++
-        gen.addStoreData(Register.R0, 0);  // *(R1 + 0) = R0
-        gen.addJump(gen.PASS_LABEL);
-
-        // Same as above for the count & drop trampoline.
-        gen.defineLabel(mCountAndDropLabel);
-        gen.addLoadData(Register.R0, 0);   // R0 = *(R1 + 0)
-        gen.addAdd(1);                     // R0++
-        gen.addStoreData(Register.R0, 0);  // *(R1 + 0) = R0
-        gen.addJump(gen.DROP_LABEL);
-    }
-
-    /**
-     * Generate and install a new filter program.
-     */
-    @GuardedBy("this")
-    @VisibleForTesting
-    void installNewProgramLocked() {
-        purgeExpiredRasLocked();
-        ArrayList<Ra> rasToFilter = new ArrayList<>();
-        final byte[] program;
-        long programMinLifetime = Long.MAX_VALUE;
-        long maximumApfProgramSize = mApfCapabilities.maximumApfProgramSize;
-        if (mApfCapabilities.hasDataAccess()) {
-            // Reserve space for the counters.
-            maximumApfProgramSize -= Counter.totalSize();
-        }
-
-        try {
-            // Step 1: Determine how many RA filters we can fit in the program.
-            ApfGenerator gen = emitPrologueLocked();
-
-            // The epilogue normally goes after the RA filters, but add it early to include its
-            // length when estimating the total.
-            emitEpilogue(gen);
-
-            // Can't fit the program even without any RA filters?
-            if (gen.programLengthOverEstimate() > maximumApfProgramSize) {
-                Log.e(TAG, "Program exceeds maximum size " + maximumApfProgramSize);
-                return;
-            }
-
-            for (Ra ra : mRas) {
-                ra.generateFilterLocked(gen);
-                // Stop if we get too big.
-                if (gen.programLengthOverEstimate() > maximumApfProgramSize) break;
-                rasToFilter.add(ra);
-            }
-
-            // Step 2: Actually generate the program
-            gen = emitPrologueLocked();
-            for (Ra ra : rasToFilter) {
-                programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen));
-            }
-            emitEpilogue(gen);
-            program = gen.generate();
-        } catch (IllegalInstructionException|IllegalStateException e) {
-            Log.e(TAG, "Failed to generate APF program.", e);
-            return;
-        }
-        final long now = currentTimeSeconds();
-        mLastTimeInstalledProgram = now;
-        mLastInstalledProgramMinLifetime = programMinLifetime;
-        mLastInstalledProgram = program;
-        mNumProgramUpdates++;
-
-        if (VDBG) {
-            hexDump("Installing filter: ", program, program.length);
-        }
-        mIpClientCallback.installPacketFilter(program);
-        logApfProgramEventLocked(now);
-        mLastInstallEvent = new ApfProgramEvent();
-        mLastInstallEvent.lifetime = programMinLifetime;
-        mLastInstallEvent.filteredRas = rasToFilter.size();
-        mLastInstallEvent.currentRas = mRas.size();
-        mLastInstallEvent.programLength = program.length;
-        mLastInstallEvent.flags = ApfProgramEvent.flagsFor(mIPv4Address != null, mMulticastFilter);
-    }
-
-    @GuardedBy("this")
-    private void logApfProgramEventLocked(long now) {
-        if (mLastInstallEvent == null) {
-            return;
-        }
-        ApfProgramEvent ev = mLastInstallEvent;
-        mLastInstallEvent = null;
-        ev.actualLifetime = now - mLastTimeInstalledProgram;
-        if (ev.actualLifetime < APF_PROGRAM_EVENT_LIFETIME_THRESHOLD) {
-            return;
-        }
-        mMetricsLog.log(ev);
-    }
-
-    /**
-     * Returns {@code true} if a new program should be installed because the current one dies soon.
-     */
-    private boolean shouldInstallnewProgram() {
-        long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
-        return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
-    }
-
-    private void hexDump(String msg, byte[] packet, int length) {
-        log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */));
-    }
-
-    @GuardedBy("this")
-    private void purgeExpiredRasLocked() {
-        for (int i = 0; i < mRas.size();) {
-            if (mRas.get(i).isExpired()) {
-                log("Expiring " + mRas.get(i));
-                mRas.remove(i);
-            } else {
-                i++;
-            }
-        }
-    }
-
-    /**
-     * Process an RA packet, updating the list of known RAs and installing a new APF program
-     * if the current APF program should be updated.
-     * @return a ProcessRaResult enum describing what action was performed.
-     */
-    @VisibleForTesting
-    synchronized ProcessRaResult processRa(byte[] packet, int length) {
-        if (VDBG) hexDump("Read packet = ", packet, length);
-
-        // Have we seen this RA before?
-        for (int i = 0; i < mRas.size(); i++) {
-            Ra ra = mRas.get(i);
-            if (ra.matches(packet, length)) {
-                if (VDBG) log("matched RA " + ra);
-                // Update lifetimes.
-                ra.mLastSeen = currentTimeSeconds();
-                ra.mMinLifetime = ra.minLifetime(packet, length);
-                ra.seenCount++;
-
-                // Keep mRas in LRU order so as to prioritize generating filters for recently seen
-                // RAs. LRU prioritizes this because RA filters are generated in order from mRas
-                // until the filter program exceeds the maximum filter program size allowed by the
-                // chipset, so RAs appearing earlier in mRas are more likely to make it into the
-                // filter program.
-                // TODO: consider sorting the RAs in order of increasing expiry time as well.
-                // Swap to front of array.
-                mRas.add(0, mRas.remove(i));
-
-                // If the current program doesn't expire for a while, don't update.
-                if (shouldInstallnewProgram()) {
-                    installNewProgramLocked();
-                    return ProcessRaResult.UPDATE_EXPIRY;
-                }
-                return ProcessRaResult.MATCH;
-            }
-        }
-        purgeExpiredRasLocked();
-        // TODO: figure out how to proceed when we've received more then MAX_RAS RAs.
-        if (mRas.size() >= MAX_RAS) {
-            return ProcessRaResult.DROPPED;
-        }
-        final Ra ra;
-        try {
-            ra = new Ra(packet, length);
-        } catch (Exception e) {
-            Log.e(TAG, "Error parsing RA", e);
-            return ProcessRaResult.PARSE_ERROR;
-        }
-        // Ignore 0 lifetime RAs.
-        if (ra.isExpired()) {
-            return ProcessRaResult.ZERO_LIFETIME;
-        }
-        log("Adding " + ra);
-        mRas.add(ra);
-        installNewProgramLocked();
-        return ProcessRaResult.UPDATE_NEW_RA;
-    }
-
-    /**
-     * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
-     * filtering using APF programs.
-     */
-    public static ApfFilter maybeCreate(Context context, ApfConfiguration config,
-            InterfaceParams ifParams, IpClient.Callback ipClientCallback) {
-        if (context == null || config == null || ifParams == null) return null;
-        ApfCapabilities apfCapabilities =  config.apfCapabilities;
-        if (apfCapabilities == null) return null;
-        if (apfCapabilities.apfVersionSupported == 0) return null;
-        if (apfCapabilities.maximumApfProgramSize < 512) {
-            Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize);
-            return null;
-        }
-        // For now only support generating programs for Ethernet frames. If this restriction is
-        // lifted:
-        //   1. the program generator will need its offsets adjusted.
-        //   2. the packet filter attached to our packet socket will need its offset adjusted.
-        if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null;
-        if (!ApfGenerator.supportsVersion(apfCapabilities.apfVersionSupported)) {
-            Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
-            return null;
-        }
-
-        return new ApfFilter(context, config, ifParams, ipClientCallback, new IpConnectivityLog());
-    }
-
-    public synchronized void shutdown() {
-        if (mReceiveThread != null) {
-            log("shutting down");
-            mReceiveThread.halt();  // Also closes socket.
-            mReceiveThread = null;
-        }
-        mRas.clear();
-        mContext.unregisterReceiver(mDeviceIdleReceiver);
-    }
-
-    public synchronized void setMulticastFilter(boolean isEnabled) {
-        if (mMulticastFilter == isEnabled) return;
-        mMulticastFilter = isEnabled;
-        if (!isEnabled) {
-            mNumProgramUpdatesAllowingMulticast++;
-        }
-        installNewProgramLocked();
-    }
-
-    @VisibleForTesting
-    public synchronized void setDozeMode(boolean isEnabled) {
-        if (mInDozeMode == isEnabled) return;
-        mInDozeMode = isEnabled;
-        installNewProgramLocked();
-    }
-
-    /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
-    private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
-        LinkAddress ipv4Address = null;
-        for (LinkAddress address : lp.getLinkAddresses()) {
-            if (!(address.getAddress() instanceof Inet4Address)) {
-                continue;
-            }
-            if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
-                // More than one IPv4 address, abort.
-                return null;
-            }
-            ipv4Address = address;
-        }
-        return ipv4Address;
-    }
-
-    public synchronized void setLinkProperties(LinkProperties lp) {
-        // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
-        final LinkAddress ipv4Address = findIPv4LinkAddress(lp);
-        final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
-        final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
-        if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) {
-            return;
-        }
-        mIPv4Address = addr;
-        mIPv4PrefixLength = prefix;
-        installNewProgramLocked();
-    }
-
-    static public long counterValue(byte[] data, Counter counter)
-            throws ArrayIndexOutOfBoundsException {
-        // Follow the same wrap-around addressing scheme of the interpreter.
-        int offset = counter.offset();
-        if (offset < 0) {
-            offset = data.length + offset;
-        }
-
-        // Decode 32bit big-endian integer into a long so we can count up beyond 2^31.
-        long value = 0;
-        for (int i = 0; i < 4; i++) {
-            value = value << 8 | (data[offset] & 0xFF);
-            offset++;
-        }
-        return value;
-    }
-
-    public synchronized void dump(IndentingPrintWriter pw) {
-        pw.println("Capabilities: " + mApfCapabilities);
-        pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
-        pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW"));
-        try {
-            pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress());
-        } catch (UnknownHostException|NullPointerException e) {}
-
-        if (mLastTimeInstalledProgram == 0) {
-            pw.println("No program installed.");
-            return;
-        }
-        pw.println("Program updates: " + mNumProgramUpdates);
-        pw.println(String.format(
-                "Last program length %d, installed %ds ago, lifetime %ds",
-                mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram,
-                mLastInstalledProgramMinLifetime));
-
-        pw.println("RA filters:");
-        pw.increaseIndent();
-        for (Ra ra: mRas) {
-            pw.println(ra);
-            pw.increaseIndent();
-            pw.println(String.format(
-                    "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen));
-            if (DBG) {
-                pw.println("Last match:");
-                pw.increaseIndent();
-                pw.println(ra.getLastMatchingPacket());
-                pw.decreaseIndent();
-            }
-            pw.decreaseIndent();
-        }
-        pw.decreaseIndent();
-
-        if (DBG) {
-            pw.println("Last program:");
-            pw.increaseIndent();
-            pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
-            pw.decreaseIndent();
-        }
-
-        pw.println("APF packet counters: ");
-        pw.increaseIndent();
-        if (!mApfCapabilities.hasDataAccess()) {
-            pw.println("APF counters not supported");
-        } else if (mDataSnapshot == null) {
-            pw.println("No last snapshot.");
-        } else {
-            try {
-                Counter[] counters = Counter.class.getEnumConstants();
-                for (Counter c : Arrays.asList(counters).subList(1, counters.length)) {
-                    long value = counterValue(mDataSnapshot, c);
-                    // Only print non-zero counters
-                    if (value != 0) {
-                        pw.println(c.toString() + ": " + value);
-                    }
-                }
-            } catch (ArrayIndexOutOfBoundsException e) {
-                pw.println("Uh-oh: " + e);
-            }
-            if (VDBG) {
-                pw.println("Raw data dump: ");
-                pw.println(HexDump.dumpHexString(mDataSnapshot));
-            }
-        }
-        pw.decreaseIndent();
-    }
-
-    // TODO: move to android.net.NetworkUtils
-    @VisibleForTesting
-    public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
-        return bytesToBEInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
-    }
-}
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index a956cef..cddb91f 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,1019 +16,14 @@
 
 package android.net.dhcp;
 
-import com.android.internal.util.HexDump;
-import com.android.internal.util.Protocol;
-import com.android.internal.util.State;
-import com.android.internal.util.MessageUtils;
-import com.android.internal.util.StateMachine;
-import com.android.internal.util.WakeupMessage;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.DhcpResults;
-import android.net.InterfaceConfiguration;
-import android.net.LinkAddress;
-import android.net.NetworkUtils;
-import android.net.TrafficStats;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.DhcpClientEvent;
-import android.net.metrics.DhcpErrorEvent;
-import android.net.util.InterfaceParams;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.PacketSocketAddress;
-import android.util.EventLog;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.TimeUtils;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.lang.Thread;
-import java.net.Inet4Address;
-import java.net.SocketException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.Random;
-
-import libcore.io.IoBridge;
-
-import static android.system.OsConstants.*;
-import static android.net.dhcp.DhcpPacket.*;
-
 /**
- * A DHCPv4 client.
- *
- * Written to behave similarly to the DhcpStateMachine + dhcpcd 5.5.6 combination used in Android
- * 5.1 and below, as configured on Nexus 6. The interface is the same as DhcpStateMachine.
- *
- * TODO:
- *
- * - Exponential backoff when receiving NAKs (not specified by the RFC, but current behaviour).
- * - Support persisting lease state and support INIT-REBOOT. Android 5.1 does this, but it does not
- *   do so correctly: instead of requesting the lease last obtained on a particular network (e.g., a
- *   given SSID), it requests the last-leased IP address on the same interface, causing a delay if
- *   the server NAKs or a timeout if it doesn't.
- *
- * Known differences from current behaviour:
- *
- * - Does not request the "static routes" option.
- * - Does not support BOOTP servers. DHCP has been around since 1993, should be everywhere now.
- * - Requests the "broadcast" option, but does nothing with it.
- * - Rejects invalid subnet masks such as 255.255.255.1 (current code treats that as 255.255.255.0).
- *
- * @hide
+ * TODO: remove this class after migrating clients.
  */
-public class DhcpClient extends StateMachine {
+public class DhcpClient {
+    public static final int CMD_PRE_DHCP_ACTION = 1003;
+    public static final int CMD_POST_DHCP_ACTION = 1004;
+    public static final int CMD_PRE_DHCP_ACTION_COMPLETE = 1006;
 
-    private static final String TAG = "DhcpClient";
-    private static final boolean DBG = true;
-    private static final boolean STATE_DBG = false;
-    private static final boolean MSG_DBG = false;
-    private static final boolean PACKET_DBG = false;
-
-    // Timers and timeouts.
-    private static final int SECONDS = 1000;
-    private static final int FIRST_TIMEOUT_MS   =   2 * SECONDS;
-    private static final int MAX_TIMEOUT_MS     = 128 * SECONDS;
-
-    // This is not strictly needed, since the client is asynchronous and implements exponential
-    // backoff. It's maintained for backwards compatibility with the previous DHCP code, which was
-    // a blocking operation with a 30-second timeout. We pick 36 seconds so we can send packets at
-    // t=0, t=2, t=6, t=14, t=30, allowing for 10% jitter.
-    private static final int DHCP_TIMEOUT_MS    =  36 * SECONDS;
-
-    private static final int PUBLIC_BASE = Protocol.BASE_DHCP;
-
-    /* Commands from controller to start/stop DHCP */
-    public static final int CMD_START_DHCP                  = PUBLIC_BASE + 1;
-    public static final int CMD_STOP_DHCP                   = PUBLIC_BASE + 2;
-
-    /* Notification from DHCP state machine prior to DHCP discovery/renewal */
-    public static final int CMD_PRE_DHCP_ACTION             = PUBLIC_BASE + 3;
-    /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
-     * success/failure */
-    public static final int CMD_POST_DHCP_ACTION            = PUBLIC_BASE + 4;
-    /* Notification from DHCP state machine before quitting */
-    public static final int CMD_ON_QUIT                     = PUBLIC_BASE + 5;
-
-    /* Command from controller to indicate DHCP discovery/renewal can continue
-     * after pre DHCP action is complete */
-    public static final int CMD_PRE_DHCP_ACTION_COMPLETE    = PUBLIC_BASE + 6;
-
-    /* Command and event notification to/from IpManager requesting the setting
-     * (or clearing) of an IPv4 LinkAddress.
-     */
-    public static final int CMD_CLEAR_LINKADDRESS           = PUBLIC_BASE + 7;
-    public static final int CMD_CONFIGURE_LINKADDRESS       = PUBLIC_BASE + 8;
-    public static final int EVENT_LINKADDRESS_CONFIGURED    = PUBLIC_BASE + 9;
-
-    /* Message.arg1 arguments to CMD_POST_DHCP_ACTION notification */
     public static final int DHCP_SUCCESS = 1;
     public static final int DHCP_FAILURE = 2;
-
-    // Internal messages.
-    private static final int PRIVATE_BASE         = Protocol.BASE_DHCP + 100;
-    private static final int CMD_KICK             = PRIVATE_BASE + 1;
-    private static final int CMD_RECEIVED_PACKET  = PRIVATE_BASE + 2;
-    private static final int CMD_TIMEOUT          = PRIVATE_BASE + 3;
-    private static final int CMD_RENEW_DHCP       = PRIVATE_BASE + 4;
-    private static final int CMD_REBIND_DHCP      = PRIVATE_BASE + 5;
-    private static final int CMD_EXPIRE_DHCP      = PRIVATE_BASE + 6;
-
-    // For message logging.
-    private static final Class[] sMessageClasses = { DhcpClient.class };
-    private static final SparseArray<String> sMessageNames =
-            MessageUtils.findMessageNames(sMessageClasses);
-
-    // DHCP parameters that we request.
-    /* package */ static final byte[] REQUESTED_PARAMS = new byte[] {
-        DHCP_SUBNET_MASK,
-        DHCP_ROUTER,
-        DHCP_DNS_SERVER,
-        DHCP_DOMAIN_NAME,
-        DHCP_MTU,
-        DHCP_BROADCAST_ADDRESS,  // TODO: currently ignored.
-        DHCP_LEASE_TIME,
-        DHCP_RENEWAL_TIME,
-        DHCP_REBINDING_TIME,
-        DHCP_VENDOR_INFO,
-    };
-
-    // DHCP flag that means "yes, we support unicast."
-    private static final boolean DO_UNICAST   = false;
-
-    // System services / libraries we use.
-    private final Context mContext;
-    private final Random mRandom;
-    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
-
-    // Sockets.
-    // - We use a packet socket to receive, because servers send us packets bound for IP addresses
-    //   which we have not yet configured, and the kernel protocol stack drops these.
-    // - We use a UDP socket to send, so the kernel handles ARP and routing for us (DHCP servers can
-    //   be off-link as well as on-link).
-    private FileDescriptor mPacketSock;
-    private FileDescriptor mUdpSock;
-    private ReceiveThread mReceiveThread;
-
-    // State variables.
-    private final StateMachine mController;
-    private final WakeupMessage mKickAlarm;
-    private final WakeupMessage mTimeoutAlarm;
-    private final WakeupMessage mRenewAlarm;
-    private final WakeupMessage mRebindAlarm;
-    private final WakeupMessage mExpiryAlarm;
-    private final String mIfaceName;
-
-    private boolean mRegisteredForPreDhcpNotification;
-    private InterfaceParams mIface;
-    // TODO: MacAddress-ify more of this class hierarchy.
-    private byte[] mHwAddr;
-    private PacketSocketAddress mInterfaceBroadcastAddr;
-    private int mTransactionId;
-    private long mTransactionStartMillis;
-    private DhcpResults mDhcpLease;
-    private long mDhcpLeaseExpiry;
-    private DhcpResults mOffer;
-
-    // Milliseconds SystemClock timestamps used to record transition times to DhcpBoundState.
-    private long mLastInitEnterTime;
-    private long mLastBoundExitTime;
-
-    // States.
-    private State mStoppedState = new StoppedState();
-    private State mDhcpState = new DhcpState();
-    private State mDhcpInitState = new DhcpInitState();
-    private State mDhcpSelectingState = new DhcpSelectingState();
-    private State mDhcpRequestingState = new DhcpRequestingState();
-    private State mDhcpHaveLeaseState = new DhcpHaveLeaseState();
-    private State mConfiguringInterfaceState = new ConfiguringInterfaceState();
-    private State mDhcpBoundState = new DhcpBoundState();
-    private State mDhcpRenewingState = new DhcpRenewingState();
-    private State mDhcpRebindingState = new DhcpRebindingState();
-    private State mDhcpInitRebootState = new DhcpInitRebootState();
-    private State mDhcpRebootingState = new DhcpRebootingState();
-    private State mWaitBeforeStartState = new WaitBeforeStartState(mDhcpInitState);
-    private State mWaitBeforeRenewalState = new WaitBeforeRenewalState(mDhcpRenewingState);
-
-    private WakeupMessage makeWakeupMessage(String cmdName, int cmd) {
-        cmdName = DhcpClient.class.getSimpleName() + "." + mIfaceName + "." + cmdName;
-        return new WakeupMessage(mContext, getHandler(), cmdName, cmd);
-    }
-
-    // TODO: Take an InterfaceParams instance instead of an interface name String.
-    private DhcpClient(Context context, StateMachine controller, String iface) {
-        super(TAG, controller.getHandler());
-
-        mContext = context;
-        mController = controller;
-        mIfaceName = iface;
-
-        addState(mStoppedState);
-        addState(mDhcpState);
-            addState(mDhcpInitState, mDhcpState);
-            addState(mWaitBeforeStartState, mDhcpState);
-            addState(mDhcpSelectingState, mDhcpState);
-            addState(mDhcpRequestingState, mDhcpState);
-            addState(mDhcpHaveLeaseState, mDhcpState);
-                addState(mConfiguringInterfaceState, mDhcpHaveLeaseState);
-                addState(mDhcpBoundState, mDhcpHaveLeaseState);
-                addState(mWaitBeforeRenewalState, mDhcpHaveLeaseState);
-                addState(mDhcpRenewingState, mDhcpHaveLeaseState);
-                addState(mDhcpRebindingState, mDhcpHaveLeaseState);
-            addState(mDhcpInitRebootState, mDhcpState);
-            addState(mDhcpRebootingState, mDhcpState);
-
-        setInitialState(mStoppedState);
-
-        mRandom = new Random();
-
-        // Used to schedule packet retransmissions.
-        mKickAlarm = makeWakeupMessage("KICK", CMD_KICK);
-        // Used to time out PacketRetransmittingStates.
-        mTimeoutAlarm = makeWakeupMessage("TIMEOUT", CMD_TIMEOUT);
-        // Used to schedule DHCP reacquisition.
-        mRenewAlarm = makeWakeupMessage("RENEW", CMD_RENEW_DHCP);
-        mRebindAlarm = makeWakeupMessage("REBIND", CMD_REBIND_DHCP);
-        mExpiryAlarm = makeWakeupMessage("EXPIRY", CMD_EXPIRE_DHCP);
-    }
-
-    public void registerForPreDhcpNotification() {
-        mRegisteredForPreDhcpNotification = true;
-    }
-
-    public static DhcpClient makeDhcpClient(
-            Context context, StateMachine controller, InterfaceParams ifParams) {
-        DhcpClient client = new DhcpClient(context, controller, ifParams.name);
-        client.mIface = ifParams;
-        client.start();
-        return client;
-    }
-
-    private boolean initInterface() {
-        if (mIface == null) mIface = InterfaceParams.getByName(mIfaceName);
-        if (mIface == null) {
-            Log.e(TAG, "Can't determine InterfaceParams for " + mIfaceName);
-            return false;
-        }
-
-        mHwAddr = mIface.macAddr.toByteArray();
-        mInterfaceBroadcastAddr = new PacketSocketAddress(mIface.index, DhcpPacket.ETHER_BROADCAST);
-        return true;
-    }
-
-    private void startNewTransaction() {
-        mTransactionId = mRandom.nextInt();
-        mTransactionStartMillis = SystemClock.elapsedRealtime();
-    }
-
-    private boolean initSockets() {
-        return initPacketSocket() && initUdpSocket();
-    }
-
-    private boolean initPacketSocket() {
-        try {
-            mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP);
-            PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IP, mIface.index);
-            Os.bind(mPacketSock, addr);
-            NetworkUtils.attachDhcpFilter(mPacketSock);
-        } catch(SocketException|ErrnoException e) {
-            Log.e(TAG, "Error creating packet socket", e);
-            return false;
-        }
-        return true;
-    }
-
-    private boolean initUdpSocket() {
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_DHCP);
-        try {
-            mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-            Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1);
-            Os.setsockoptIfreq(mUdpSock, SOL_SOCKET, SO_BINDTODEVICE, mIfaceName);
-            Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_BROADCAST, 1);
-            Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_RCVBUF, 0);
-            Os.bind(mUdpSock, Inet4Address.ANY, DhcpPacket.DHCP_CLIENT);
-            NetworkUtils.protectFromVpn(mUdpSock);
-        } catch(SocketException|ErrnoException e) {
-            Log.e(TAG, "Error creating UDP socket", e);
-            return false;
-        } finally {
-            TrafficStats.setThreadStatsTag(oldTag);
-        }
-        return true;
-    }
-
-    private boolean connectUdpSock(Inet4Address to) {
-        try {
-            Os.connect(mUdpSock, to, DhcpPacket.DHCP_SERVER);
-            return true;
-        } catch (SocketException|ErrnoException e) {
-            Log.e(TAG, "Error connecting UDP socket", e);
-            return false;
-        }
-    }
-
-    private static void closeQuietly(FileDescriptor fd) {
-        try {
-            IoBridge.closeAndSignalBlockedThreads(fd);
-        } catch (IOException ignored) {}
-    }
-
-    private void closeSockets() {
-        closeQuietly(mUdpSock);
-        closeQuietly(mPacketSock);
-    }
-
-    class ReceiveThread extends Thread {
-
-        private final byte[] mPacket = new byte[DhcpPacket.MAX_LENGTH];
-        private volatile boolean mStopped = false;
-
-        public void halt() {
-            mStopped = true;
-            closeSockets();  // Interrupts the read() call the thread is blocked in.
-        }
-
-        @Override
-        public void run() {
-            if (DBG) Log.d(TAG, "Receive thread started");
-            while (!mStopped) {
-                int length = 0;  // Or compiler can't tell it's initialized if a parse error occurs.
-                try {
-                    length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
-                    DhcpPacket packet = null;
-                    packet = DhcpPacket.decodeFullPacket(mPacket, length, DhcpPacket.ENCAP_L2);
-                    if (DBG) Log.d(TAG, "Received packet: " + packet);
-                    sendMessage(CMD_RECEIVED_PACKET, packet);
-                } catch (IOException|ErrnoException e) {
-                    if (!mStopped) {
-                        Log.e(TAG, "Read error", e);
-                        logError(DhcpErrorEvent.RECEIVE_ERROR);
-                    }
-                } catch (DhcpPacket.ParseException e) {
-                    Log.e(TAG, "Can't parse packet: " + e.getMessage());
-                    if (PACKET_DBG) {
-                        Log.d(TAG, HexDump.dumpHexString(mPacket, 0, length));
-                    }
-                    if (e.errorCode == DhcpErrorEvent.DHCP_NO_COOKIE) {
-                        int snetTagId = 0x534e4554;
-                        String bugId = "31850211";
-                        int uid = -1;
-                        String data = DhcpPacket.ParseException.class.getName();
-                        EventLog.writeEvent(snetTagId, bugId, uid, data);
-                    }
-                    logError(e.errorCode);
-                }
-            }
-            if (DBG) Log.d(TAG, "Receive thread stopped");
-        }
-    }
-
-    private short getSecs() {
-        return (short) ((SystemClock.elapsedRealtime() - mTransactionStartMillis) / 1000);
-    }
-
-    private boolean transmitPacket(ByteBuffer buf, String description, int encap, Inet4Address to) {
-        try {
-            if (encap == DhcpPacket.ENCAP_L2) {
-                if (DBG) Log.d(TAG, "Broadcasting " + description);
-                Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr);
-            } else if (encap == DhcpPacket.ENCAP_BOOTP && to.equals(INADDR_BROADCAST)) {
-                if (DBG) Log.d(TAG, "Broadcasting " + description);
-                // We only send L3-encapped broadcasts in DhcpRebindingState,
-                // where we have an IP address and an unconnected UDP socket.
-                //
-                // N.B.: We only need this codepath because DhcpRequestPacket
-                // hardcodes the source IP address to 0.0.0.0. We could reuse
-                // the packet socket if this ever changes.
-                Os.sendto(mUdpSock, buf, 0, to, DhcpPacket.DHCP_SERVER);
-            } else {
-                // It's safe to call getpeername here, because we only send unicast packets if we
-                // have an IP address, and we connect the UDP socket in DhcpBoundState#enter.
-                if (DBG) Log.d(TAG, String.format("Unicasting %s to %s",
-                        description, Os.getpeername(mUdpSock)));
-                Os.write(mUdpSock, buf);
-            }
-        } catch(ErrnoException|IOException e) {
-            Log.e(TAG, "Can't send packet: ", e);
-            return false;
-        }
-        return true;
-    }
-
-    private boolean sendDiscoverPacket() {
-        ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
-                DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
-                DO_UNICAST, REQUESTED_PARAMS);
-        return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST);
-    }
-
-    private boolean sendRequestPacket(
-            Inet4Address clientAddress, Inet4Address requestedAddress,
-            Inet4Address serverAddress, Inet4Address to) {
-        // TODO: should we use the transaction ID from the server?
-        final int encap = INADDR_ANY.equals(clientAddress)
-                ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP;
-
-        ByteBuffer packet = DhcpPacket.buildRequestPacket(
-                encap, mTransactionId, getSecs(), clientAddress,
-                DO_UNICAST, mHwAddr, requestedAddress,
-                serverAddress, REQUESTED_PARAMS, null);
-        String serverStr = (serverAddress != null) ? serverAddress.getHostAddress() : null;
-        String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() +
-                             " request=" + requestedAddress.getHostAddress() +
-                             " serverid=" + serverStr;
-        return transmitPacket(packet, description, encap, to);
-    }
-
-    private void scheduleLeaseTimers() {
-        if (mDhcpLeaseExpiry == 0) {
-            Log.d(TAG, "Infinite lease, no timer scheduling needed");
-            return;
-        }
-
-        final long now = SystemClock.elapsedRealtime();
-
-        // TODO: consider getting the renew and rebind timers from T1 and T2.
-        // See also:
-        //     https://tools.ietf.org/html/rfc2131#section-4.4.5
-        //     https://tools.ietf.org/html/rfc1533#section-9.9
-        //     https://tools.ietf.org/html/rfc1533#section-9.10
-        final long remainingDelay = mDhcpLeaseExpiry - now;
-        final long renewDelay = remainingDelay / 2;
-        final long rebindDelay = remainingDelay * 7 / 8;
-        mRenewAlarm.schedule(now + renewDelay);
-        mRebindAlarm.schedule(now + rebindDelay);
-        mExpiryAlarm.schedule(now + remainingDelay);
-        Log.d(TAG, "Scheduling renewal in " + (renewDelay / 1000) + "s");
-        Log.d(TAG, "Scheduling rebind in " + (rebindDelay / 1000) + "s");
-        Log.d(TAG, "Scheduling expiry in " + (remainingDelay / 1000) + "s");
-    }
-
-    private void notifySuccess() {
-        mController.sendMessage(
-                CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
-    }
-
-    private void notifyFailure() {
-        mController.sendMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0, null);
-    }
-
-    private void acceptDhcpResults(DhcpResults results, String msg) {
-        mDhcpLease = results;
-        mOffer = null;
-        Log.d(TAG, msg + " lease: " + mDhcpLease);
-        notifySuccess();
-    }
-
-    private void clearDhcpState() {
-        mDhcpLease = null;
-        mDhcpLeaseExpiry = 0;
-        mOffer = null;
-    }
-
-    /**
-     * Quit the DhcpStateMachine.
-     *
-     * @hide
-     */
-    public void doQuit() {
-        Log.d(TAG, "doQuit");
-        quit();
-    }
-
-    @Override
-    protected void onQuitting() {
-        Log.d(TAG, "onQuitting");
-        mController.sendMessage(CMD_ON_QUIT);
-    }
-
-    abstract class LoggingState extends State {
-        private long mEnterTimeMs;
-
-        @Override
-        public void enter() {
-            if (STATE_DBG) Log.d(TAG, "Entering state " + getName());
-            mEnterTimeMs = SystemClock.elapsedRealtime();
-        }
-
-        @Override
-        public void exit() {
-            long durationMs = SystemClock.elapsedRealtime() - mEnterTimeMs;
-            logState(getName(), (int) durationMs);
-        }
-
-        private String messageName(int what) {
-            return sMessageNames.get(what, Integer.toString(what));
-        }
-
-        private String messageToString(Message message) {
-            long now = SystemClock.uptimeMillis();
-            StringBuilder b = new StringBuilder(" ");
-            TimeUtils.formatDuration(message.getWhen() - now, b);
-            b.append(" ").append(messageName(message.what))
-                    .append(" ").append(message.arg1)
-                    .append(" ").append(message.arg2)
-                    .append(" ").append(message.obj);
-            return b.toString();
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            if (MSG_DBG) {
-                Log.d(TAG, getName() + messageToString(message));
-            }
-            return NOT_HANDLED;
-        }
-
-        @Override
-        public String getName() {
-            // All DhcpClient's states are inner classes with a well defined name.
-            // Use getSimpleName() and avoid super's getName() creating new String instances.
-            return getClass().getSimpleName();
-        }
-    }
-
-    // Sends CMD_PRE_DHCP_ACTION to the controller, waits for the controller to respond with
-    // CMD_PRE_DHCP_ACTION_COMPLETE, and then transitions to mOtherState.
-    abstract class WaitBeforeOtherState extends LoggingState {
-        protected State mOtherState;
-
-        @Override
-        public void enter() {
-            super.enter();
-            mController.sendMessage(CMD_PRE_DHCP_ACTION);
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            super.processMessage(message);
-            switch (message.what) {
-                case CMD_PRE_DHCP_ACTION_COMPLETE:
-                    transitionTo(mOtherState);
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-    }
-
-    class StoppedState extends State {
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_START_DHCP:
-                    if (mRegisteredForPreDhcpNotification) {
-                        transitionTo(mWaitBeforeStartState);
-                    } else {
-                        transitionTo(mDhcpInitState);
-                    }
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-    }
-
-    class WaitBeforeStartState extends WaitBeforeOtherState {
-        public WaitBeforeStartState(State otherState) {
-            super();
-            mOtherState = otherState;
-        }
-    }
-
-    class WaitBeforeRenewalState extends WaitBeforeOtherState {
-        public WaitBeforeRenewalState(State otherState) {
-            super();
-            mOtherState = otherState;
-        }
-    }
-
-    class DhcpState extends State {
-        @Override
-        public void enter() {
-            clearDhcpState();
-            if (initInterface() && initSockets()) {
-                mReceiveThread = new ReceiveThread();
-                mReceiveThread.start();
-            } else {
-                notifyFailure();
-                transitionTo(mStoppedState);
-            }
-        }
-
-        @Override
-        public void exit() {
-            if (mReceiveThread != null) {
-                mReceiveThread.halt();  // Also closes sockets.
-                mReceiveThread = null;
-            }
-            clearDhcpState();
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            super.processMessage(message);
-            switch (message.what) {
-                case CMD_STOP_DHCP:
-                    transitionTo(mStoppedState);
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-    }
-
-    public boolean isValidPacket(DhcpPacket packet) {
-        // TODO: check checksum.
-        int xid = packet.getTransactionId();
-        if (xid != mTransactionId) {
-            Log.d(TAG, "Unexpected transaction ID " + xid + ", expected " + mTransactionId);
-            return false;
-        }
-        if (!Arrays.equals(packet.getClientMac(), mHwAddr)) {
-            Log.d(TAG, "MAC addr mismatch: got " +
-                    HexDump.toHexString(packet.getClientMac()) + ", expected " +
-                    HexDump.toHexString(packet.getClientMac()));
-            return false;
-        }
-        return true;
-    }
-
-    public void setDhcpLeaseExpiry(DhcpPacket packet) {
-        long leaseTimeMillis = packet.getLeaseTimeMillis();
-        mDhcpLeaseExpiry =
-                (leaseTimeMillis > 0) ? SystemClock.elapsedRealtime() + leaseTimeMillis : 0;
-    }
-
-    /**
-     * Retransmits packets using jittered exponential backoff with an optional timeout. Packet
-     * transmission is triggered by CMD_KICK, which is sent by an AlarmManager alarm. If a subclass
-     * sets mTimeout to a positive value, then timeout() is called by an AlarmManager alarm mTimeout
-     * milliseconds after entering the state. Kicks and timeouts are cancelled when leaving the
-     * state.
-     *
-     * Concrete subclasses must implement sendPacket, which is called when the alarm fires and a
-     * packet needs to be transmitted, and receivePacket, which is triggered by CMD_RECEIVED_PACKET
-     * sent by the receive thread. They may also set mTimeout and implement timeout.
-     */
-    abstract class PacketRetransmittingState extends LoggingState {
-
-        private int mTimer;
-        protected int mTimeout = 0;
-
-        @Override
-        public void enter() {
-            super.enter();
-            initTimer();
-            maybeInitTimeout();
-            sendMessage(CMD_KICK);
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            super.processMessage(message);
-            switch (message.what) {
-                case CMD_KICK:
-                    sendPacket();
-                    scheduleKick();
-                    return HANDLED;
-                case CMD_RECEIVED_PACKET:
-                    receivePacket((DhcpPacket) message.obj);
-                    return HANDLED;
-                case CMD_TIMEOUT:
-                    timeout();
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        @Override
-        public void exit() {
-            super.exit();
-            mKickAlarm.cancel();
-            mTimeoutAlarm.cancel();
-        }
-
-        abstract protected boolean sendPacket();
-        abstract protected void receivePacket(DhcpPacket packet);
-        protected void timeout() {}
-
-        protected void initTimer() {
-            mTimer = FIRST_TIMEOUT_MS;
-        }
-
-        protected int jitterTimer(int baseTimer) {
-            int maxJitter = baseTimer / 10;
-            int jitter = mRandom.nextInt(2 * maxJitter) - maxJitter;
-            return baseTimer + jitter;
-        }
-
-        protected void scheduleKick() {
-            long now = SystemClock.elapsedRealtime();
-            long timeout = jitterTimer(mTimer);
-            long alarmTime = now + timeout;
-            mKickAlarm.schedule(alarmTime);
-            mTimer *= 2;
-            if (mTimer > MAX_TIMEOUT_MS) {
-                mTimer = MAX_TIMEOUT_MS;
-            }
-        }
-
-        protected void maybeInitTimeout() {
-            if (mTimeout > 0) {
-                long alarmTime = SystemClock.elapsedRealtime() + mTimeout;
-                mTimeoutAlarm.schedule(alarmTime);
-            }
-        }
-    }
-
-    class DhcpInitState extends PacketRetransmittingState {
-        public DhcpInitState() {
-            super();
-        }
-
-        @Override
-        public void enter() {
-            super.enter();
-            startNewTransaction();
-            mLastInitEnterTime = SystemClock.elapsedRealtime();
-        }
-
-        protected boolean sendPacket() {
-            return sendDiscoverPacket();
-        }
-
-        protected void receivePacket(DhcpPacket packet) {
-            if (!isValidPacket(packet)) return;
-            if (!(packet instanceof DhcpOfferPacket)) return;
-            mOffer = packet.toDhcpResults();
-            if (mOffer != null) {
-                Log.d(TAG, "Got pending lease: " + mOffer);
-                transitionTo(mDhcpRequestingState);
-            }
-        }
-    }
-
-    // Not implemented. We request the first offer we receive.
-    class DhcpSelectingState extends LoggingState {
-    }
-
-    class DhcpRequestingState extends PacketRetransmittingState {
-        public DhcpRequestingState() {
-            mTimeout = DHCP_TIMEOUT_MS / 2;
-        }
-
-        protected boolean sendPacket() {
-            return sendRequestPacket(
-                    INADDR_ANY,                                    // ciaddr
-                    (Inet4Address) mOffer.ipAddress.getAddress(),  // DHCP_REQUESTED_IP
-                    (Inet4Address) mOffer.serverAddress,           // DHCP_SERVER_IDENTIFIER
-                    INADDR_BROADCAST);                             // packet destination address
-        }
-
-        protected void receivePacket(DhcpPacket packet) {
-            if (!isValidPacket(packet)) return;
-            if ((packet instanceof DhcpAckPacket)) {
-                DhcpResults results = packet.toDhcpResults();
-                if (results != null) {
-                    setDhcpLeaseExpiry(packet);
-                    acceptDhcpResults(results, "Confirmed");
-                    transitionTo(mConfiguringInterfaceState);
-                }
-            } else if (packet instanceof DhcpNakPacket) {
-                // TODO: Wait a while before returning into INIT state.
-                Log.d(TAG, "Received NAK, returning to INIT");
-                mOffer = null;
-                transitionTo(mDhcpInitState);
-            }
-        }
-
-        @Override
-        protected void timeout() {
-            // After sending REQUESTs unsuccessfully for a while, go back to init.
-            transitionTo(mDhcpInitState);
-        }
-    }
-
-    class DhcpHaveLeaseState extends State {
-        @Override
-        public boolean processMessage(Message message) {
-            switch (message.what) {
-                case CMD_EXPIRE_DHCP:
-                    Log.d(TAG, "Lease expired!");
-                    notifyFailure();
-                    transitionTo(mDhcpInitState);
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        @Override
-        public void exit() {
-            // Clear any extant alarms.
-            mRenewAlarm.cancel();
-            mRebindAlarm.cancel();
-            mExpiryAlarm.cancel();
-            clearDhcpState();
-            // Tell IpManager to clear the IPv4 address. There is no need to
-            // wait for confirmation since any subsequent packets are sent from
-            // INADDR_ANY anyway (DISCOVER, REQUEST).
-            mController.sendMessage(CMD_CLEAR_LINKADDRESS);
-        }
-    }
-
-    class ConfiguringInterfaceState extends LoggingState {
-        @Override
-        public void enter() {
-            super.enter();
-            mController.sendMessage(CMD_CONFIGURE_LINKADDRESS, mDhcpLease.ipAddress);
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            super.processMessage(message);
-            switch (message.what) {
-                case EVENT_LINKADDRESS_CONFIGURED:
-                    transitionTo(mDhcpBoundState);
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-    }
-
-    class DhcpBoundState extends LoggingState {
-        @Override
-        public void enter() {
-            super.enter();
-            if (mDhcpLease.serverAddress != null && !connectUdpSock(mDhcpLease.serverAddress)) {
-                // There's likely no point in going into DhcpInitState here, we'll probably
-                // just repeat the transaction, get the same IP address as before, and fail.
-                //
-                // NOTE: It is observed that connectUdpSock() basically never fails, due to
-                // SO_BINDTODEVICE. Examining the local socket address shows it will happily
-                // return an IPv4 address from another interface, or even return "0.0.0.0".
-                //
-                // TODO: Consider deleting this check, following testing on several kernels.
-                notifyFailure();
-                transitionTo(mStoppedState);
-            }
-
-            scheduleLeaseTimers();
-            logTimeToBoundState();
-        }
-
-        @Override
-        public void exit() {
-            super.exit();
-            mLastBoundExitTime = SystemClock.elapsedRealtime();
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            super.processMessage(message);
-            switch (message.what) {
-                case CMD_RENEW_DHCP:
-                    if (mRegisteredForPreDhcpNotification) {
-                        transitionTo(mWaitBeforeRenewalState);
-                    } else {
-                        transitionTo(mDhcpRenewingState);
-                    }
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        private void logTimeToBoundState() {
-            long now = SystemClock.elapsedRealtime();
-            if (mLastBoundExitTime > mLastInitEnterTime) {
-                logState(DhcpClientEvent.RENEWING_BOUND, (int)(now - mLastBoundExitTime));
-            } else {
-                logState(DhcpClientEvent.INITIAL_BOUND, (int)(now - mLastInitEnterTime));
-            }
-        }
-    }
-
-    abstract class DhcpReacquiringState extends PacketRetransmittingState {
-        protected String mLeaseMsg;
-
-        @Override
-        public void enter() {
-            super.enter();
-            startNewTransaction();
-        }
-
-        abstract protected Inet4Address packetDestination();
-
-        protected boolean sendPacket() {
-            return sendRequestPacket(
-                    (Inet4Address) mDhcpLease.ipAddress.getAddress(),  // ciaddr
-                    INADDR_ANY,                                        // DHCP_REQUESTED_IP
-                    null,                                              // DHCP_SERVER_IDENTIFIER
-                    packetDestination());                              // packet destination address
-        }
-
-        protected void receivePacket(DhcpPacket packet) {
-            if (!isValidPacket(packet)) return;
-            if ((packet instanceof DhcpAckPacket)) {
-                final DhcpResults results = packet.toDhcpResults();
-                if (results != null) {
-                    if (!mDhcpLease.ipAddress.equals(results.ipAddress)) {
-                        Log.d(TAG, "Renewed lease not for our current IP address!");
-                        notifyFailure();
-                        transitionTo(mDhcpInitState);
-                    }
-                    setDhcpLeaseExpiry(packet);
-                    // Updating our notion of DhcpResults here only causes the
-                    // DNS servers and routes to be updated in LinkProperties
-                    // in IpManager and by any overridden relevant handlers of
-                    // the registered IpManager.Callback.  IP address changes
-                    // are not supported here.
-                    acceptDhcpResults(results, mLeaseMsg);
-                    transitionTo(mDhcpBoundState);
-                }
-            } else if (packet instanceof DhcpNakPacket) {
-                Log.d(TAG, "Received NAK, returning to INIT");
-                notifyFailure();
-                transitionTo(mDhcpInitState);
-            }
-        }
-    }
-
-    class DhcpRenewingState extends DhcpReacquiringState {
-        public DhcpRenewingState() {
-            mLeaseMsg = "Renewed";
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            if (super.processMessage(message) == HANDLED) {
-                return HANDLED;
-            }
-
-            switch (message.what) {
-                case CMD_REBIND_DHCP:
-                    transitionTo(mDhcpRebindingState);
-                    return HANDLED;
-                default:
-                    return NOT_HANDLED;
-            }
-        }
-
-        @Override
-        protected Inet4Address packetDestination() {
-            // Not specifying a SERVER_IDENTIFIER option is a violation of RFC 2131, but...
-            // http://b/25343517 . Try to make things work anyway by using broadcast renews.
-            return (mDhcpLease.serverAddress != null) ?
-                    mDhcpLease.serverAddress : INADDR_BROADCAST;
-        }
-    }
-
-    class DhcpRebindingState extends DhcpReacquiringState {
-        public DhcpRebindingState() {
-            mLeaseMsg = "Rebound";
-        }
-
-        @Override
-        public void enter() {
-            super.enter();
-
-            // We need to broadcast and possibly reconnect the socket to a
-            // completely different server.
-            closeQuietly(mUdpSock);
-            if (!initUdpSocket()) {
-                Log.e(TAG, "Failed to recreate UDP socket");
-                transitionTo(mDhcpInitState);
-            }
-        }
-
-        @Override
-        protected Inet4Address packetDestination() {
-            return INADDR_BROADCAST;
-        }
-    }
-
-    class DhcpInitRebootState extends LoggingState {
-    }
-
-    class DhcpRebootingState extends LoggingState {
-    }
-
-    private void logError(int errorCode) {
-        mMetricsLog.log(mIfaceName, new DhcpErrorEvent(errorCode));
-    }
-
-    private void logState(String name, int durationMs) {
-        mMetricsLog.log(mIfaceName, new DhcpClientEvent(name, durationMs));
-    }
 }
diff --git a/services/net/java/android/net/dhcp/DhcpLease.java b/services/net/java/android/net/dhcp/DhcpLease.java
deleted file mode 100644
index 6cdd2aa..0000000
--- a/services/net/java/android/net/dhcp/DhcpLease.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dhcp;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.MacAddress;
-import android.os.SystemClock;
-import android.text.TextUtils;
-
-import com.android.internal.util.HexDump;
-
-import java.net.Inet4Address;
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * An IPv4 address assignment done through DHCPv4.
- * @hide
- */
-public class DhcpLease {
-    public static final long EXPIRATION_NEVER = Long.MAX_VALUE;
-    public static final String HOSTNAME_NONE = null;
-
-    @Nullable
-    private final byte[] mClientId;
-    @NonNull
-    private final MacAddress mHwAddr;
-    @NonNull
-    private final Inet4Address mNetAddr;
-    /**
-     * Expiration time for the lease, to compare with {@link SystemClock#elapsedRealtime()}.
-     */
-    private final long mExpTime;
-    @Nullable
-    private final String mHostname;
-
-    public DhcpLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
-            @NonNull Inet4Address netAddr, long expTime, @Nullable String hostname) {
-        mClientId = (clientId == null ? null : Arrays.copyOf(clientId, clientId.length));
-        mHwAddr = hwAddr;
-        mNetAddr = netAddr;
-        mExpTime = expTime;
-        mHostname = hostname;
-    }
-
-    @Nullable
-    public byte[] getClientId() {
-        if (mClientId == null) {
-            return null;
-        }
-        return Arrays.copyOf(mClientId, mClientId.length);
-    }
-
-    @NonNull
-    public MacAddress getHwAddr() {
-        return mHwAddr;
-    }
-
-    @Nullable
-    public String getHostname() {
-        return mHostname;
-    }
-
-    @NonNull
-    public Inet4Address getNetAddr() {
-        return mNetAddr;
-    }
-
-    public long getExpTime() {
-        return mExpTime;
-    }
-
-    /**
-     * Push back the expiration time of this lease. If the provided time is sooner than the original
-     * expiration time, the lease time will not be updated.
-     *
-     * <p>The lease hostname is updated with the provided one if set.
-     * @return A {@link DhcpLease} with expiration time set to max(expTime, currentExpTime)
-     */
-    public DhcpLease renewedLease(long expTime, @Nullable String hostname) {
-        return new DhcpLease(mClientId, mHwAddr, mNetAddr, Math.max(expTime, mExpTime),
-                (hostname == null ? mHostname : hostname));
-    }
-
-    public boolean matchesClient(@Nullable byte[] clientId, @NonNull MacAddress hwAddr) {
-        if (mClientId != null) {
-            return Arrays.equals(mClientId, clientId);
-        } else {
-            return clientId == null && mHwAddr.equals(hwAddr);
-        }
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof DhcpLease)) {
-            return false;
-        }
-        final DhcpLease other = (DhcpLease)obj;
-        return Arrays.equals(mClientId, other.mClientId)
-                && mHwAddr.equals(other.mHwAddr)
-                && mNetAddr.equals(other.mNetAddr)
-                && mExpTime == other.mExpTime
-                && TextUtils.equals(mHostname, other.mHostname);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mClientId, mHwAddr, mNetAddr, mHostname, mExpTime);
-    }
-
-    static String clientIdToString(byte[] bytes) {
-        if (bytes == null) {
-            return "null";
-        }
-        return HexDump.toHexString(bytes);
-    }
-
-    static String inet4AddrToString(@Nullable Inet4Address addr) {
-        return (addr == null) ? "null" : addr.getHostAddress();
-    }
-
-    @Override
-    public String toString() {
-        return String.format("clientId: %s, hwAddr: %s, netAddr: %s, expTime: %d, hostname: %s",
-                clientIdToString(mClientId), mHwAddr.toString(), inet4AddrToString(mNetAddr),
-                mExpTime, mHostname);
-    }
-}
diff --git a/services/net/java/android/net/dhcp/DhcpLeaseRepository.java b/services/net/java/android/net/dhcp/DhcpLeaseRepository.java
deleted file mode 100644
index 2dda421..0000000
--- a/services/net/java/android/net/dhcp/DhcpLeaseRepository.java
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dhcp;
-
-import static android.net.NetworkUtils.inet4AddressToIntHTH;
-import static android.net.NetworkUtils.intToInet4AddressHTH;
-import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH;
-import static android.net.dhcp.DhcpLease.EXPIRATION_NEVER;
-import static android.net.dhcp.DhcpLease.inet4AddrToString;
-import static android.net.util.NetworkConstants.IPV4_ADDR_BITS;
-
-import static java.lang.Math.min;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.IpPrefix;
-import android.net.MacAddress;
-import android.net.util.SharedLog;
-import android.net.dhcp.DhcpServer.Clock;
-import android.util.ArrayMap;
-
-import java.net.Inet4Address;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.function.Function;
-
-/**
- * A repository managing IPv4 address assignments through DHCPv4.
- *
- * <p>This class is not thread-safe. All public methods should be called on a common thread or
- * use some synchronization mechanism.
- *
- * <p>Methods are optimized for a small number of allocated leases, assuming that most of the time
- * only 2~10 addresses will be allocated, which is the common case. Managing a large number of
- * addresses is supported but will be slower: some operations have complexity in O(num_leases).
- * @hide
- */
-class DhcpLeaseRepository {
-    public static final byte[] CLIENTID_UNSPEC = null;
-    public static final Inet4Address INETADDR_UNSPEC = null;
-
-    @NonNull
-    private final SharedLog mLog;
-    @NonNull
-    private final Clock mClock;
-
-    @NonNull
-    private IpPrefix mPrefix;
-    @NonNull
-    private Set<Inet4Address> mReservedAddrs;
-    private int mSubnetAddr;
-    private int mSubnetMask;
-    private int mNumAddresses;
-    private long mLeaseTimeMs;
-
-    /**
-     * Next timestamp when committed or declined leases should be checked for expired ones. This
-     * will always be lower than or equal to the time for the first lease to expire: it's OK not to
-     * update this when removing entries, but it must always be updated when adding/updating.
-     */
-    private long mNextExpirationCheck = EXPIRATION_NEVER;
-
-    static class DhcpLeaseException extends Exception {
-        DhcpLeaseException(String message) {
-            super(message);
-        }
-    }
-
-    static class OutOfAddressesException extends DhcpLeaseException {
-        OutOfAddressesException(String message) {
-            super(message);
-        }
-    }
-
-    static class InvalidAddressException extends DhcpLeaseException {
-        InvalidAddressException(String message) {
-            super(message);
-        }
-    }
-
-    static class InvalidSubnetException extends DhcpLeaseException {
-        InvalidSubnetException(String message) {
-            super(message);
-        }
-    }
-
-    /**
-     * Leases by IP address
-     */
-    private final ArrayMap<Inet4Address, DhcpLease> mCommittedLeases = new ArrayMap<>();
-
-    /**
-     * Map address -> expiration timestamp in ms. Addresses are guaranteed to be valid as defined
-     * by {@link #isValidAddress(Inet4Address)}, but are not necessarily otherwise available for
-     * assignment.
-     */
-    private final LinkedHashMap<Inet4Address, Long> mDeclinedAddrs = new LinkedHashMap<>();
-
-    public DhcpLeaseRepository(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs,
-            long leaseTimeMs, @NonNull SharedLog log, @NonNull Clock clock) {
-        updateParams(prefix, reservedAddrs, leaseTimeMs);
-        mLog = log;
-        mClock = clock;
-    }
-
-    public void updateParams(@NonNull IpPrefix prefix, @NonNull Set<Inet4Address> reservedAddrs,
-            long leaseTimeMs) {
-        mPrefix = prefix;
-        mReservedAddrs = Collections.unmodifiableSet(new HashSet<>(reservedAddrs));
-        mSubnetMask = prefixLengthToV4NetmaskIntHTH(prefix.getPrefixLength());
-        mSubnetAddr = inet4AddressToIntHTH((Inet4Address) prefix.getAddress()) & mSubnetMask;
-        mNumAddresses = 1 << (IPV4_ADDR_BITS - prefix.getPrefixLength());
-        mLeaseTimeMs = leaseTimeMs;
-
-        cleanMap(mCommittedLeases);
-        cleanMap(mDeclinedAddrs);
-    }
-
-    /**
-     * From a map keyed by {@link Inet4Address}, remove entries where the key is invalid (as
-     * specified by {@link #isValidAddress(Inet4Address)}), or is a reserved address.
-     */
-    private <T> void cleanMap(Map<Inet4Address, T> map) {
-        final Iterator<Entry<Inet4Address, T>> it = map.entrySet().iterator();
-        while (it.hasNext()) {
-            final Inet4Address addr = it.next().getKey();
-            if (!isValidAddress(addr) || mReservedAddrs.contains(addr)) {
-                it.remove();
-            }
-        }
-    }
-
-    /**
-     * Get a DHCP offer, to reply to a DHCPDISCOVER. Follows RFC2131 #4.3.1.
-     *
-     * @param clientId Client identifier option if specified, or {@link #CLIENTID_UNSPEC}
-     * @param relayAddr Internet address of the relay (giaddr), can be {@link Inet4Address#ANY}
-     * @param reqAddr Requested address by the client (option 50), or {@link #INETADDR_UNSPEC}
-     * @param hostname Client-provided hostname, or {@link DhcpLease#HOSTNAME_NONE}
-     * @throws OutOfAddressesException The server does not have any available address
-     * @throws InvalidSubnetException The lease was requested from an unsupported subnet
-     */
-    @NonNull
-    public DhcpLease getOffer(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
-            @NonNull Inet4Address relayAddr, @Nullable Inet4Address reqAddr,
-            @Nullable String hostname) throws OutOfAddressesException, InvalidSubnetException {
-        final long currentTime = mClock.elapsedRealtime();
-        final long expTime = currentTime + mLeaseTimeMs;
-
-        removeExpiredLeases(currentTime);
-        checkValidRelayAddr(relayAddr);
-
-        final DhcpLease currentLease = findByClient(clientId, hwAddr);
-        final DhcpLease newLease;
-        if (currentLease != null) {
-            newLease = currentLease.renewedLease(expTime, hostname);
-            mLog.log("Offering extended lease " + newLease);
-            // Do not update lease time in the map: the offer is not committed yet.
-        } else if (reqAddr != null && isValidAddress(reqAddr) && isAvailable(reqAddr)) {
-            newLease = new DhcpLease(clientId, hwAddr, reqAddr, expTime, hostname);
-            mLog.log("Offering requested lease " + newLease);
-        } else {
-            newLease = makeNewOffer(clientId, hwAddr, expTime, hostname);
-            mLog.log("Offering new generated lease " + newLease);
-        }
-        return newLease;
-    }
-
-    private void checkValidRelayAddr(@Nullable Inet4Address relayAddr)
-            throws InvalidSubnetException {
-        // As per #4.3.1, addresses are assigned based on the relay address if present. This
-        // implementation only assigns addresses if the relayAddr is inside our configured subnet.
-        // This also applies when the client requested a specific address for consistency between
-        // requests, and with older behavior.
-        if (isIpAddrOutsidePrefix(mPrefix, relayAddr)) {
-            throw new InvalidSubnetException("Lease requested by relay from outside of subnet");
-        }
-    }
-
-    private static boolean isIpAddrOutsidePrefix(@NonNull IpPrefix prefix,
-            @Nullable Inet4Address addr) {
-        return addr != null && !addr.equals(Inet4Address.ANY) && !prefix.contains(addr);
-    }
-
-    @Nullable
-    private DhcpLease findByClient(@Nullable byte[] clientId, @NonNull MacAddress hwAddr) {
-        for (DhcpLease lease : mCommittedLeases.values()) {
-            if (lease.matchesClient(clientId, hwAddr)) {
-                return lease;
-            }
-        }
-
-        // Note this differs from dnsmasq behavior, which would match by hwAddr if clientId was
-        // given but no lease keyed on clientId matched. This would prevent one interface from
-        // obtaining multiple leases with different clientId.
-        return null;
-    }
-
-    /**
-     * Make a lease conformant to a client DHCPREQUEST or renew the client's existing lease,
-     * commit it to the repository and return it.
-     *
-     * <p>This method always succeeds and commits the lease if it does not throw, and has no side
-     * effects if it throws.
-     *
-     * @param clientId Client identifier option if specified, or {@link #CLIENTID_UNSPEC}
-     * @param reqAddr Requested address by the client (option 50), or {@link #INETADDR_UNSPEC}
-     * @param sidSet Whether the server identifier was set in the request
-     * @return The newly created or renewed lease
-     * @throws InvalidAddressException The client provided an address that conflicts with its
-     *                                 current configuration, or other committed/reserved leases.
-     */
-    @NonNull
-    public DhcpLease requestLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
-            @NonNull Inet4Address clientAddr, @NonNull Inet4Address relayAddr,
-            @Nullable Inet4Address reqAddr, boolean sidSet, @Nullable String hostname)
-            throws InvalidAddressException, InvalidSubnetException {
-        final long currentTime = mClock.elapsedRealtime();
-        removeExpiredLeases(currentTime);
-        checkValidRelayAddr(relayAddr);
-        final DhcpLease assignedLease = findByClient(clientId, hwAddr);
-
-        final Inet4Address leaseAddr = reqAddr != null ? reqAddr : clientAddr;
-        if (assignedLease != null) {
-            if (sidSet && reqAddr != null) {
-                // Client in SELECTING state; remove any current lease before creating a new one.
-                mCommittedLeases.remove(assignedLease.getNetAddr());
-            } else if (!assignedLease.getNetAddr().equals(leaseAddr)) {
-                // reqAddr null (RENEWING/REBINDING): client renewing its own lease for clientAddr.
-                // reqAddr set with sid not set (INIT-REBOOT): client verifying configuration.
-                // In both cases, throw if clientAddr or reqAddr does not match the known lease.
-                throw new InvalidAddressException("Incorrect address for client in " +
-                        (reqAddr != null ? "INIT-REBOOT" : "RENEWING/REBINDING"));
-            }
-        }
-
-        // In the init-reboot case, RFC2131 #4.3.2 says that the server must not reply if
-        // assignedLease == null, but dnsmasq will let the client use the requested address if
-        // available, when configured with --dhcp-authoritative. This is preferable to avoid issues
-        // if the server lost the lease DB: the client would not get a reply because the server
-        // does not know their lease.
-        // Similarly in RENEWING/REBINDING state, create a lease when possible if the
-        // client-provided lease is unknown.
-        final DhcpLease lease =
-                checkClientAndMakeLease(clientId, hwAddr, leaseAddr, hostname, currentTime);
-        mLog.logf("DHCPREQUEST assignedLease %s, reqAddr=%s, sidSet=%s: created/renewed lease %s",
-                assignedLease, inet4AddrToString(reqAddr), sidSet, lease);
-        return lease;
-    }
-
-    /**
-     * Check that the client can request the specified address, make or renew the lease if yes, and
-     * commit it.
-     *
-     * <p>This method always succeeds and returns the lease if it does not throw, and has no
-     * side-effect if it throws.
-     *
-     * @return The newly created or renewed, committed lease
-     * @throws InvalidAddressException The client provided an address that conflicts with its
-     *                                 current configuration, or other committed/reserved leases.
-     */
-    private DhcpLease checkClientAndMakeLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
-            @NonNull Inet4Address addr, @Nullable String hostname, long currentTime)
-            throws InvalidAddressException {
-        final long expTime = currentTime + mLeaseTimeMs;
-        final DhcpLease currentLease = mCommittedLeases.getOrDefault(addr, null);
-        if (currentLease != null && !currentLease.matchesClient(clientId, hwAddr)) {
-            throw new InvalidAddressException("Address in use");
-        }
-
-        final DhcpLease lease;
-        if (currentLease == null) {
-            if (isValidAddress(addr) && !mReservedAddrs.contains(addr)) {
-                lease = new DhcpLease(clientId, hwAddr, addr, expTime, hostname);
-            } else {
-                throw new InvalidAddressException("Lease not found and address unavailable");
-            }
-        } else {
-            lease = currentLease.renewedLease(expTime, hostname);
-        }
-        commitLease(lease);
-        return lease;
-    }
-
-    private void commitLease(@NonNull DhcpLease lease) {
-        mCommittedLeases.put(lease.getNetAddr(), lease);
-        maybeUpdateEarliestExpiration(lease.getExpTime());
-    }
-
-    /**
-     * Delete a committed lease from the repository.
-     *
-     * @return true if a lease matching parameters was found.
-     */
-    public boolean releaseLease(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
-            @NonNull Inet4Address addr) {
-        final DhcpLease currentLease = mCommittedLeases.getOrDefault(addr, null);
-        if (currentLease == null) {
-            mLog.w("Could not release unknown lease for " + inet4AddrToString(addr));
-            return false;
-        }
-        if (currentLease.matchesClient(clientId, hwAddr)) {
-            mCommittedLeases.remove(addr);
-            mLog.log("Released lease " + currentLease);
-            return true;
-        }
-        mLog.w(String.format("Not releasing lease %s: does not match client (cid %s, hwAddr %s)",
-                currentLease, DhcpLease.clientIdToString(clientId), hwAddr));
-        return false;
-    }
-
-    public void markLeaseDeclined(@NonNull Inet4Address addr) {
-        if (mDeclinedAddrs.containsKey(addr) || !isValidAddress(addr)) {
-            mLog.logf("Not marking %s as declined: already declined or not assignable",
-                    inet4AddrToString(addr));
-            return;
-        }
-        final long expTime = mClock.elapsedRealtime() + mLeaseTimeMs;
-        mDeclinedAddrs.put(addr, expTime);
-        mLog.logf("Marked %s as declined expiring %d", inet4AddrToString(addr), expTime);
-        maybeUpdateEarliestExpiration(expTime);
-    }
-
-    /**
-     * Get the list of currently valid committed leases in the repository.
-     */
-    @NonNull
-    public List<DhcpLease> getCommittedLeases() {
-        removeExpiredLeases(mClock.elapsedRealtime());
-        return new ArrayList<>(mCommittedLeases.values());
-    }
-
-    /**
-     * Get the set of addresses that have been marked as declined in the repository.
-     */
-    @NonNull
-    public Set<Inet4Address> getDeclinedAddresses() {
-        removeExpiredLeases(mClock.elapsedRealtime());
-        return new HashSet<>(mDeclinedAddrs.keySet());
-    }
-
-    /**
-     * Given the expiration time of a new committed lease or declined address, update
-     * {@link #mNextExpirationCheck} so it stays lower than or equal to the time for the first lease
-     * to expire.
-     */
-    private void maybeUpdateEarliestExpiration(long expTime) {
-        if (expTime < mNextExpirationCheck) {
-            mNextExpirationCheck = expTime;
-        }
-    }
-
-    /**
-     * Remove expired entries from a map keyed by {@link Inet4Address}.
-     *
-     * @param tag Type of lease in the map, for logging
-     * @param getExpTime Functor returning the expiration time for an object in the map.
-     *                   Must not return null.
-     * @return The lowest expiration time among entries remaining in the map
-     */
-    private <T> long removeExpired(long currentTime, @NonNull Map<Inet4Address, T> map,
-            @NonNull String tag, @NonNull Function<T, Long> getExpTime) {
-        final Iterator<Entry<Inet4Address, T>> it = map.entrySet().iterator();
-        long firstExpiration = EXPIRATION_NEVER;
-        while (it.hasNext()) {
-            final Entry<Inet4Address, T> lease = it.next();
-            final long expTime = getExpTime.apply(lease.getValue());
-            if (expTime <= currentTime) {
-                mLog.logf("Removing expired %s lease for %s (expTime=%s, currentTime=%s)",
-                        tag, lease.getKey(), expTime, currentTime);
-                it.remove();
-            } else {
-                firstExpiration = min(firstExpiration, expTime);
-            }
-        }
-        return firstExpiration;
-    }
-
-    /**
-     * Go through committed and declined leases and remove the expired ones.
-     */
-    private void removeExpiredLeases(long currentTime) {
-        if (currentTime < mNextExpirationCheck) {
-            return;
-        }
-
-        final long commExp = removeExpired(
-                currentTime, mCommittedLeases, "committed", DhcpLease::getExpTime);
-        final long declExp = removeExpired(
-                currentTime, mDeclinedAddrs, "declined", Function.identity());
-
-        mNextExpirationCheck = min(commExp, declExp);
-    }
-
-    private boolean isAvailable(@NonNull Inet4Address addr) {
-        return !mReservedAddrs.contains(addr) && !mCommittedLeases.containsKey(addr);
-    }
-
-    /**
-     * Get the 0-based index of an address in the subnet.
-     *
-     * <p>Given ordering of addresses 5.6.7.8 < 5.6.7.9 < 5.6.8.0, the index on a subnet is defined
-     * so that the first address is 0, the second 1, etc. For example on a /16, 192.168.0.0 -> 0,
-     * 192.168.0.1 -> 1, 192.168.1.0 -> 256
-     *
-     */
-    private int getAddrIndex(int addr) {
-        return addr & ~mSubnetMask;
-    }
-
-    private int getAddrByIndex(int index) {
-        return mSubnetAddr | index;
-    }
-
-    /**
-     * Get a valid address starting from the supplied one.
-     *
-     * <p>This only checks that the address is numerically valid for assignment, not whether it is
-     * already in use. The return value is always inside the configured prefix, even if the supplied
-     * address is not.
-     *
-     * <p>If the provided address is valid, it is returned as-is. Otherwise, the next valid
-     * address (with the ordering in {@link #getAddrIndex(int)}) is returned.
-     */
-    private int getValidAddress(int addr) {
-        final int lastByteMask = 0xff;
-        int addrIndex = getAddrIndex(addr); // 0-based index of the address in the subnet
-
-        // Some OSes do not handle addresses in .255 or .0 correctly: avoid those.
-        final int lastByte = getAddrByIndex(addrIndex) & lastByteMask;
-        if (lastByte == lastByteMask) {
-            // Avoid .255 address, and .0 address that follows
-            addrIndex = (addrIndex + 2) % mNumAddresses;
-        } else if (lastByte == 0) {
-            // Avoid .0 address
-            addrIndex = (addrIndex + 1) % mNumAddresses;
-        }
-
-        // Do not use first or last address of range
-        if (addrIndex == 0 || addrIndex == mNumAddresses - 1) {
-            // Always valid and not end of range since prefixLength is at most 30 in serving params
-            addrIndex = 1;
-        }
-        return getAddrByIndex(addrIndex);
-    }
-
-    /**
-     * Returns whether the address is in the configured subnet and part of the assignable range.
-     */
-    private boolean isValidAddress(Inet4Address addr) {
-        final int intAddr = inet4AddressToIntHTH(addr);
-        return getValidAddress(intAddr) == intAddr;
-    }
-
-    private int getNextAddress(int addr) {
-        final int addrIndex = getAddrIndex(addr);
-        final int nextAddress = getAddrByIndex((addrIndex + 1) % mNumAddresses);
-        return getValidAddress(nextAddress);
-    }
-
-    /**
-     * Calculate a first candidate address for a client by hashing the hardware address.
-     *
-     * <p>This will be a valid address as checked by {@link #getValidAddress(int)}, but may be
-     * in use.
-     *
-     * @return An IPv4 address encoded as 32-bit int
-     */
-    private int getFirstClientAddress(MacAddress hwAddr) {
-        // This follows dnsmasq behavior. Advantages are: clients will often get the same
-        // offers for different DISCOVER even if the lease was not yet accepted or has expired,
-        // and address generation will generally not need to loop through many allocated addresses
-        // until it finds a free one.
-        int hash = 0;
-        for (byte b : hwAddr.toByteArray()) {
-            hash += b + (b << 8) + (b << 16);
-        }
-        // This implementation will not always result in the same IPs as dnsmasq would give out in
-        // Android <= P, because it includes invalid and reserved addresses in mNumAddresses while
-        // the configured ranges for dnsmasq did not.
-        final int addrIndex = hash % mNumAddresses;
-        return getValidAddress(getAddrByIndex(addrIndex));
-    }
-
-    /**
-     * Create a lease that can be offered to respond to a client DISCOVER.
-     *
-     * <p>This method always succeeds and returns the lease if it does not throw. If no non-declined
-     * address is available, it will try to offer the oldest declined address if valid.
-     *
-     * @throws OutOfAddressesException The server has no address left to offer
-     */
-    private DhcpLease makeNewOffer(@Nullable byte[] clientId, @NonNull MacAddress hwAddr,
-            long expTime, @Nullable String hostname) throws OutOfAddressesException {
-        int intAddr = getFirstClientAddress(hwAddr);
-        // Loop until a free address is found, or there are no more addresses.
-        // There is slightly less than this many usable addresses, but some extra looping is OK
-        for (int i = 0; i < mNumAddresses; i++) {
-            final Inet4Address addr = intToInet4AddressHTH(intAddr);
-            if (isAvailable(addr) && !mDeclinedAddrs.containsKey(addr)) {
-                return new DhcpLease(clientId, hwAddr, addr, expTime, hostname);
-            }
-            intAddr = getNextAddress(intAddr);
-        }
-
-        // Try freeing DECLINEd addresses if out of addresses.
-        final Iterator<Inet4Address> it = mDeclinedAddrs.keySet().iterator();
-        while (it.hasNext()) {
-            final Inet4Address addr = it.next();
-            it.remove();
-            mLog.logf("Out of addresses in address pool: dropped declined addr %s",
-                    inet4AddrToString(addr));
-            // isValidAddress() is always verified for entries in mDeclinedAddrs.
-            // However declined addresses may have been requested (typically by the machine that was
-            // already using the address) after being declined.
-            if (isAvailable(addr)) {
-                return new DhcpLease(clientId, hwAddr, addr, expTime, hostname);
-            }
-        }
-
-        throw new OutOfAddressesException("No address available for offer");
-    }
-}
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
deleted file mode 100644
index 6ba7d94..0000000
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ /dev/null
@@ -1,1364 +0,0 @@
-package android.net.dhcp;
-
-import static android.net.util.NetworkConstants.IPV4_MAX_MTU;
-import static android.net.util.NetworkConstants.IPV4_MIN_MTU;
-
-import android.annotation.Nullable;
-import android.net.DhcpResults;
-import android.net.LinkAddress;
-import android.net.NetworkUtils;
-import android.net.metrics.DhcpErrorEvent;
-import android.os.Build;
-import android.os.SystemProperties;
-import android.system.OsConstants;
-import android.text.TextUtils;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.UnsupportedEncodingException;
-import java.net.Inet4Address;
-import java.net.UnknownHostException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.ShortBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Defines basic data and operations needed to build and use packets for the
- * DHCP protocol.  Subclasses create the specific packets used at each
- * stage of the negotiation.
- *
- * @hide
- */
-public abstract class DhcpPacket {
-    protected static final String TAG = "DhcpPacket";
-
-    // dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the
-    // CPU for anything shorter than 5 minutes. For sanity's sake, this must be higher than the
-    // DHCP client timeout.
-    public static final int MINIMUM_LEASE = 60;
-    public static final int INFINITE_LEASE = (int) 0xffffffff;
-
-    public static final Inet4Address INADDR_ANY = (Inet4Address) Inet4Address.ANY;
-    public static final Inet4Address INADDR_BROADCAST = (Inet4Address) Inet4Address.ALL;
-    public static final byte[] ETHER_BROADCAST = new byte[] {
-            (byte) 0xff, (byte) 0xff, (byte) 0xff,
-            (byte) 0xff, (byte) 0xff, (byte) 0xff,
-    };
-
-    /**
-     * Packet encapsulations.
-     */
-    public static final int ENCAP_L2 = 0;    // EthernetII header included
-    public static final int ENCAP_L3 = 1;    // IP/UDP header included
-    public static final int ENCAP_BOOTP = 2; // BOOTP contents only
-
-    /**
-     * Minimum length of a DHCP packet, excluding options, in the above encapsulations.
-     */
-    public static final int MIN_PACKET_LENGTH_BOOTP = 236;  // See diagram in RFC 2131, section 2.
-    public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8;
-    public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14;
-
-    public static final int HWADDR_LEN = 16;
-    public static final int MAX_OPTION_LEN = 255;
-
-    /**
-     * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum
-     * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280,
-     * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500
-     * because in general it is risky to assume that the hardware is able to send/receive packets
-     * larger than 1500 bytes even if the network supports it.
-     */
-    private static final int MIN_MTU = 1280;
-    private static final int MAX_MTU = 1500;
-
-    /**
-     * IP layer definitions.
-     */
-    private static final byte IP_TYPE_UDP = (byte) 0x11;
-
-    /**
-     * IP: Version 4, Header Length 20 bytes
-     */
-    private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45;
-
-    /**
-     * IP: Flags 0, Fragment Offset 0, Don't Fragment
-     */
-    private static final short IP_FLAGS_OFFSET = (short) 0x4000;
-
-    /**
-     * IP: TOS
-     */
-    private static final byte IP_TOS_LOWDELAY = (byte) 0x10;
-
-    /**
-     * IP: TTL -- use default 64 from RFC1340
-     */
-    private static final byte IP_TTL = (byte) 0x40;
-
-    /**
-     * The client DHCP port.
-     */
-    static final short DHCP_CLIENT = (short) 68;
-
-    /**
-     * The server DHCP port.
-     */
-    static final short DHCP_SERVER = (short) 67;
-
-    /**
-     * The message op code indicating a request from a client.
-     */
-    protected static final byte DHCP_BOOTREQUEST = (byte) 1;
-
-    /**
-     * The message op code indicating a response from the server.
-     */
-    protected static final byte DHCP_BOOTREPLY = (byte) 2;
-
-    /**
-     * The code type used to identify an Ethernet MAC address in the
-     * Client-ID field.
-     */
-    protected static final byte CLIENT_ID_ETHER = (byte) 1;
-
-    /**
-     * The maximum length of a packet that can be constructed.
-     */
-    protected static final int MAX_LENGTH = 1500;
-
-    /**
-     * The magic cookie that identifies this as a DHCP packet instead of BOOTP.
-     */
-    private static final int DHCP_MAGIC_COOKIE = 0x63825363;
-
-    /**
-     * DHCP Optional Type: DHCP Subnet Mask
-     */
-    protected static final byte DHCP_SUBNET_MASK = 1;
-    protected Inet4Address mSubnetMask;
-
-    /**
-     * DHCP Optional Type: DHCP Router
-     */
-    protected static final byte DHCP_ROUTER = 3;
-    protected List <Inet4Address> mGateways;
-
-    /**
-     * DHCP Optional Type: DHCP DNS Server
-     */
-    protected static final byte DHCP_DNS_SERVER = 6;
-    protected List<Inet4Address> mDnsServers;
-
-    /**
-     * DHCP Optional Type: DHCP Host Name
-     */
-    protected static final byte DHCP_HOST_NAME = 12;
-    protected String mHostName;
-
-    /**
-     * DHCP Optional Type: DHCP DOMAIN NAME
-     */
-    protected static final byte DHCP_DOMAIN_NAME = 15;
-    protected String mDomainName;
-
-    /**
-     * DHCP Optional Type: DHCP Interface MTU
-     */
-    protected static final byte DHCP_MTU = 26;
-    protected Short mMtu;
-
-    /**
-     * DHCP Optional Type: DHCP BROADCAST ADDRESS
-     */
-    protected static final byte DHCP_BROADCAST_ADDRESS = 28;
-    protected Inet4Address mBroadcastAddress;
-
-    /**
-     * DHCP Optional Type: Vendor specific information
-     */
-    protected static final byte DHCP_VENDOR_INFO = 43;
-    protected String mVendorInfo;
-
-    /**
-     * Value of the vendor specific option used to indicate that the network is metered
-     */
-    public static final String VENDOR_INFO_ANDROID_METERED = "ANDROID_METERED";
-
-    /**
-     * DHCP Optional Type: DHCP Requested IP Address
-     */
-    protected static final byte DHCP_REQUESTED_IP = 50;
-    protected Inet4Address mRequestedIp;
-
-    /**
-     * DHCP Optional Type: DHCP Lease Time
-     */
-    protected static final byte DHCP_LEASE_TIME = 51;
-    protected Integer mLeaseTime;
-
-    /**
-     * DHCP Optional Type: DHCP Message Type
-     */
-    protected static final byte DHCP_MESSAGE_TYPE = 53;
-    // the actual type values
-    protected static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1;
-    protected static final byte DHCP_MESSAGE_TYPE_OFFER = 2;
-    protected static final byte DHCP_MESSAGE_TYPE_REQUEST = 3;
-    protected static final byte DHCP_MESSAGE_TYPE_DECLINE = 4;
-    protected static final byte DHCP_MESSAGE_TYPE_ACK = 5;
-    protected static final byte DHCP_MESSAGE_TYPE_NAK = 6;
-    protected static final byte DHCP_MESSAGE_TYPE_RELEASE = 7;
-    protected static final byte DHCP_MESSAGE_TYPE_INFORM = 8;
-
-    /**
-     * DHCP Optional Type: DHCP Server Identifier
-     */
-    protected static final byte DHCP_SERVER_IDENTIFIER = 54;
-    protected Inet4Address mServerIdentifier;
-
-    /**
-     * DHCP Optional Type: DHCP Parameter List
-     */
-    protected static final byte DHCP_PARAMETER_LIST = 55;
-    protected byte[] mRequestedParams;
-
-    /**
-     * DHCP Optional Type: DHCP MESSAGE
-     */
-    protected static final byte DHCP_MESSAGE = 56;
-    protected String mMessage;
-
-    /**
-     * DHCP Optional Type: Maximum DHCP Message Size
-     */
-    protected static final byte DHCP_MAX_MESSAGE_SIZE = 57;
-    protected Short mMaxMessageSize;
-
-    /**
-     * DHCP Optional Type: DHCP Renewal Time Value
-     */
-    protected static final byte DHCP_RENEWAL_TIME = 58;
-    protected Integer mT1;
-
-    /**
-     * DHCP Optional Type: Rebinding Time Value
-     */
-    protected static final byte DHCP_REBINDING_TIME = 59;
-    protected Integer mT2;
-
-    /**
-     * DHCP Optional Type: Vendor Class Identifier
-     */
-    protected static final byte DHCP_VENDOR_CLASS_ID = 60;
-    protected String mVendorId;
-
-    /**
-     * DHCP Optional Type: DHCP Client Identifier
-     */
-    protected static final byte DHCP_CLIENT_IDENTIFIER = 61;
-    protected byte[] mClientId;
-
-    /**
-     * DHCP zero-length option code: pad
-     */
-    protected static final byte DHCP_OPTION_PAD = 0x00;
-
-    /**
-     * DHCP zero-length option code: end of options
-     */
-    protected static final byte DHCP_OPTION_END = (byte) 0xff;
-
-    /**
-     * The transaction identifier used in this particular DHCP negotiation
-     */
-    protected final int mTransId;
-
-    /**
-     * The seconds field in the BOOTP header. Per RFC, should be nonzero in client requests only.
-     */
-    protected final short mSecs;
-
-    /**
-     * The IP address of the client host.  This address is typically
-     * proposed by the client (from an earlier DHCP negotiation) or
-     * supplied by the server.
-     */
-    protected final Inet4Address mClientIp;
-    protected final Inet4Address mYourIp;
-    private final Inet4Address mNextIp;
-    protected final Inet4Address mRelayIp;
-
-    /**
-     * Does the client request a broadcast response?
-     */
-    protected boolean mBroadcast;
-
-    /**
-     * The six-octet MAC of the client.
-     */
-    protected final byte[] mClientMac;
-
-    /**
-     * Asks the packet object to create a ByteBuffer serialization of
-     * the packet for transmission.
-     */
-    public abstract ByteBuffer buildPacket(int encap, short destUdp,
-        short srcUdp);
-
-    /**
-     * Allows the concrete class to fill in packet-type-specific details,
-     * typically optional parameters at the end of the packet.
-     */
-    abstract void finishPacket(ByteBuffer buffer);
-
-    // Set in unit tests, to ensure that the test does not break when run on different devices and
-    // on different releases.
-    static String testOverrideVendorId = null;
-    static String testOverrideHostname = null;
-
-    protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp,
-                         Inet4Address nextIp, Inet4Address relayIp,
-                         byte[] clientMac, boolean broadcast) {
-        mTransId = transId;
-        mSecs = secs;
-        mClientIp = clientIp;
-        mYourIp = yourIp;
-        mNextIp = nextIp;
-        mRelayIp = relayIp;
-        mClientMac = clientMac;
-        mBroadcast = broadcast;
-    }
-
-    /**
-     * Returns the transaction ID.
-     */
-    public int getTransactionId() {
-        return mTransId;
-    }
-
-    /**
-     * Returns the client MAC.
-     */
-    public byte[] getClientMac() {
-        return mClientMac;
-    }
-
-    // TODO: refactor DhcpClient to set clientId when constructing packets and remove
-    // hasExplicitClientId logic
-    /**
-     * Returns whether a client ID was set in the options for this packet.
-     */
-    public boolean hasExplicitClientId() {
-        return mClientId != null;
-    }
-
-    /**
-     * Convenience method to return the client ID if it was set explicitly, or null otherwise.
-     */
-    @Nullable
-    public byte[] getExplicitClientIdOrNull() {
-        return hasExplicitClientId() ? getClientId() : null;
-    }
-
-    /**
-     * Returns the client ID. If not set explicitly, this follows RFC 2132 and creates a client ID
-     * based on the hardware address.
-     */
-    public byte[] getClientId() {
-        final byte[] clientId;
-        if (hasExplicitClientId()) {
-            clientId = Arrays.copyOf(mClientId, mClientId.length);
-        } else {
-            clientId = new byte[mClientMac.length + 1];
-            clientId[0] = CLIENT_ID_ETHER;
-            System.arraycopy(mClientMac, 0, clientId, 1, mClientMac.length);
-        }
-        return clientId;
-    }
-
-    /**
-     * Returns whether a parameter is included in the parameter request list option of this packet.
-     *
-     * <p>If there is no parameter request list option in the packet, false is returned.
-     *
-     * @param paramId ID of the parameter, such as {@link #DHCP_MTU} or {@link #DHCP_HOST_NAME}.
-     */
-    public boolean hasRequestedParam(byte paramId) {
-        if (mRequestedParams == null) {
-            return false;
-        }
-
-        for (byte reqParam : mRequestedParams) {
-            if (reqParam == paramId) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Creates a new L3 packet (including IP header) containing the
-     * DHCP udp packet.  This method relies upon the delegated method
-     * finishPacket() to insert the per-packet contents.
-     */
-    protected void fillInPacket(int encap, Inet4Address destIp,
-        Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf,
-        byte requestCode, boolean broadcast) {
-        byte[] destIpArray = destIp.getAddress();
-        byte[] srcIpArray = srcIp.getAddress();
-        int ipHeaderOffset = 0;
-        int ipLengthOffset = 0;
-        int ipChecksumOffset = 0;
-        int endIpHeader = 0;
-        int udpHeaderOffset = 0;
-        int udpLengthOffset = 0;
-        int udpChecksumOffset = 0;
-
-        buf.clear();
-        buf.order(ByteOrder.BIG_ENDIAN);
-
-        if (encap == ENCAP_L2) {
-            buf.put(ETHER_BROADCAST);
-            buf.put(mClientMac);
-            buf.putShort((short) OsConstants.ETH_P_IP);
-        }
-
-        // if a full IP packet needs to be generated, put the IP & UDP
-        // headers in place, and pre-populate with artificial values
-        // needed to seed the IP checksum.
-        if (encap <= ENCAP_L3) {
-            ipHeaderOffset = buf.position();
-            buf.put(IP_VERSION_HEADER_LEN);
-            buf.put(IP_TOS_LOWDELAY);    // tos: IPTOS_LOWDELAY
-            ipLengthOffset = buf.position();
-            buf.putShort((short)0);  // length
-            buf.putShort((short)0);  // id
-            buf.putShort(IP_FLAGS_OFFSET); // ip offset: don't fragment
-            buf.put(IP_TTL);    // TTL: use default 64 from RFC1340
-            buf.put(IP_TYPE_UDP);
-            ipChecksumOffset = buf.position();
-            buf.putShort((short) 0); // checksum
-
-            buf.put(srcIpArray);
-            buf.put(destIpArray);
-            endIpHeader = buf.position();
-
-            // UDP header
-            udpHeaderOffset = buf.position();
-            buf.putShort(srcUdp);
-            buf.putShort(destUdp);
-            udpLengthOffset = buf.position();
-            buf.putShort((short) 0); // length
-            udpChecksumOffset = buf.position();
-            buf.putShort((short) 0); // UDP checksum -- initially zero
-        }
-
-        // DHCP payload
-        buf.put(requestCode);
-        buf.put((byte) 1); // Hardware Type: Ethernet
-        buf.put((byte) mClientMac.length); // Hardware Address Length
-        buf.put((byte) 0); // Hop Count
-        buf.putInt(mTransId);  // Transaction ID
-        buf.putShort(mSecs); // Elapsed Seconds
-
-        if (broadcast) {
-            buf.putShort((short) 0x8000); // Flags
-        } else {
-            buf.putShort((short) 0x0000); // Flags
-        }
-
-        buf.put(mClientIp.getAddress());
-        buf.put(mYourIp.getAddress());
-        buf.put(mNextIp.getAddress());
-        buf.put(mRelayIp.getAddress());
-        buf.put(mClientMac);
-        buf.position(buf.position() +
-                     (HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes
-                     + 64     // empty server host name (64 bytes)
-                     + 128);  // empty boot file name (128 bytes)
-        buf.putInt(DHCP_MAGIC_COOKIE); // magic number
-        finishPacket(buf);
-
-        // round up to an even number of octets
-        if ((buf.position() & 1) == 1) {
-            buf.put((byte) 0);
-        }
-
-        // If an IP packet is being built, the IP & UDP checksums must be
-        // computed.
-        if (encap <= ENCAP_L3) {
-            // fix UDP header: insert length
-            short udpLen = (short)(buf.position() - udpHeaderOffset);
-            buf.putShort(udpLengthOffset, udpLen);
-            // fix UDP header: checksum
-            // checksum for UDP at udpChecksumOffset
-            int udpSeed = 0;
-
-            // apply IPv4 pseudo-header.  Read IP address src and destination
-            // values from the IP header and accumulate checksum.
-            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 2));
-            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 4));
-            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 6));
-            udpSeed += intAbs(buf.getShort(ipChecksumOffset + 8));
-
-            // accumulate extra data for the pseudo-header
-            udpSeed += IP_TYPE_UDP;
-            udpSeed += udpLen;
-            // and compute UDP checksum
-            buf.putShort(udpChecksumOffset, (short) checksum(buf, udpSeed,
-                                                             udpHeaderOffset,
-                                                             buf.position()));
-            // fix IP header: insert length
-            buf.putShort(ipLengthOffset, (short)(buf.position() - ipHeaderOffset));
-            // fixup IP-header checksum
-            buf.putShort(ipChecksumOffset,
-                         (short) checksum(buf, 0, ipHeaderOffset, endIpHeader));
-        }
-    }
-
-    /**
-     * Converts a signed short value to an unsigned int value.  Needed
-     * because Java does not have unsigned types.
-     */
-    private static int intAbs(short v) {
-        return v & 0xFFFF;
-    }
-
-    /**
-     * Performs an IP checksum (used in IP header and across UDP
-     * payload) on the specified portion of a ByteBuffer.  The seed
-     * allows the checksum to commence with a specified value.
-     */
-    private int checksum(ByteBuffer buf, int seed, int start, int end) {
-        int sum = seed;
-        int bufPosition = buf.position();
-
-        // set position of original ByteBuffer, so that the ShortBuffer
-        // will be correctly initialized
-        buf.position(start);
-        ShortBuffer shortBuf = buf.asShortBuffer();
-
-        // re-set ByteBuffer position
-        buf.position(bufPosition);
-
-        short[] shortArray = new short[(end - start) / 2];
-        shortBuf.get(shortArray);
-
-        for (short s : shortArray) {
-            sum += intAbs(s);
-        }
-
-        start += shortArray.length * 2;
-
-        // see if a singleton byte remains
-        if (end != start) {
-            short b = buf.get(start);
-
-            // make it unsigned
-            if (b < 0) {
-                b += 256;
-            }
-
-            sum += b * 256;
-        }
-
-        sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF);
-        sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF);
-        int negated = ~sum;
-        return intAbs((short) negated);
-    }
-
-    /**
-     * Adds an optional parameter containing a single byte value.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, byte value) {
-        buf.put(type);
-        buf.put((byte) 1);
-        buf.put(value);
-    }
-
-    /**
-     * Adds an optional parameter containing an array of bytes.
-     *
-     * <p>This method is a no-op if the payload argument is null.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, @Nullable byte[] payload) {
-        if (payload != null) {
-            if (payload.length > MAX_OPTION_LEN) {
-                throw new IllegalArgumentException("DHCP option too long: "
-                        + payload.length + " vs. " + MAX_OPTION_LEN);
-            }
-            buf.put(type);
-            buf.put((byte) payload.length);
-            buf.put(payload);
-        }
-    }
-
-    /**
-     * Adds an optional parameter containing an IP address.
-     *
-     * <p>This method is a no-op if the address argument is null.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, @Nullable Inet4Address addr) {
-        if (addr != null) {
-            addTlv(buf, type, addr.getAddress());
-        }
-    }
-
-    /**
-     * Adds an optional parameter containing a list of IP addresses.
-     *
-     * <p>This method is a no-op if the addresses argument is null or empty.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, @Nullable List<Inet4Address> addrs) {
-        if (addrs == null || addrs.size() == 0) return;
-
-        int optionLen = 4 * addrs.size();
-        if (optionLen > MAX_OPTION_LEN) {
-            throw new IllegalArgumentException("DHCP option too long: "
-                    + optionLen + " vs. " + MAX_OPTION_LEN);
-        }
-
-        buf.put(type);
-        buf.put((byte)(optionLen));
-
-        for (Inet4Address addr : addrs) {
-            buf.put(addr.getAddress());
-        }
-    }
-
-    /**
-     * Adds an optional parameter containing a short integer.
-     *
-     * <p>This method is a no-op if the value argument is null.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, @Nullable Short value) {
-        if (value != null) {
-            buf.put(type);
-            buf.put((byte) 2);
-            buf.putShort(value.shortValue());
-        }
-    }
-
-    /**
-     * Adds an optional parameter containing a simple integer.
-     *
-     * <p>This method is a no-op if the value argument is null.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, @Nullable Integer value) {
-        if (value != null) {
-            buf.put(type);
-            buf.put((byte) 4);
-            buf.putInt(value.intValue());
-        }
-    }
-
-    /**
-     * Adds an optional parameter containing an ASCII string.
-     *
-     * <p>This method is a no-op if the string argument is null.
-     */
-    protected static void addTlv(ByteBuffer buf, byte type, @Nullable String str) {
-        if (str != null) {
-            try {
-                addTlv(buf, type, str.getBytes("US-ASCII"));
-            } catch (UnsupportedEncodingException e) {
-                throw new IllegalArgumentException("String is not US-ASCII: " + str);
-            }
-        }
-    }
-
-    /**
-     * Adds the special end-of-optional-parameters indicator.
-     */
-    protected static void addTlvEnd(ByteBuffer buf) {
-        buf.put((byte) 0xFF);
-    }
-
-    private String getVendorId() {
-        if (testOverrideVendorId != null) return testOverrideVendorId;
-        return "android-dhcp-" + Build.VERSION.RELEASE;
-    }
-
-    private String getHostname() {
-        if (testOverrideHostname != null) return testOverrideHostname;
-        return SystemProperties.get("net.hostname");
-    }
-
-    /**
-     * Adds common client TLVs.
-     *
-     * TODO: Does this belong here? The alternative would be to modify all the buildXyzPacket
-     * methods to take them.
-     */
-    protected void addCommonClientTlvs(ByteBuffer buf) {
-        addTlv(buf, DHCP_MAX_MESSAGE_SIZE, (short) MAX_LENGTH);
-        addTlv(buf, DHCP_VENDOR_CLASS_ID, getVendorId());
-        final String hn = getHostname();
-        if (!TextUtils.isEmpty(hn)) addTlv(buf, DHCP_HOST_NAME, hn);
-    }
-
-    protected void addCommonServerTlvs(ByteBuffer buf) {
-        addTlv(buf, DHCP_LEASE_TIME, mLeaseTime);
-        if (mLeaseTime != null && mLeaseTime != INFINITE_LEASE) {
-            // The client should renew at 1/2 the lease-expiry interval
-            addTlv(buf, DHCP_RENEWAL_TIME, (int) (Integer.toUnsignedLong(mLeaseTime) / 2));
-            // Default rebinding time is set as below by RFC2131
-            addTlv(buf, DHCP_REBINDING_TIME,
-                    (int) (Integer.toUnsignedLong(mLeaseTime) * 875L / 1000L));
-        }
-        addTlv(buf, DHCP_SUBNET_MASK, mSubnetMask);
-        addTlv(buf, DHCP_BROADCAST_ADDRESS, mBroadcastAddress);
-        addTlv(buf, DHCP_ROUTER, mGateways);
-        addTlv(buf, DHCP_DNS_SERVER, mDnsServers);
-        addTlv(buf, DHCP_DOMAIN_NAME, mDomainName);
-        addTlv(buf, DHCP_HOST_NAME, mHostName);
-        addTlv(buf, DHCP_VENDOR_INFO, mVendorInfo);
-        if (mMtu != null && Short.toUnsignedInt(mMtu) >= IPV4_MIN_MTU) {
-            addTlv(buf, DHCP_MTU, mMtu);
-        }
-    }
-
-    /**
-     * Converts a MAC from an array of octets to an ASCII string.
-     */
-    public static String macToString(byte[] mac) {
-        String macAddr = "";
-
-        for (int i = 0; i < mac.length; i++) {
-            String hexString = "0" + Integer.toHexString(mac[i]);
-
-            // substring operation grabs the last 2 digits: this
-            // allows signed bytes to be converted correctly.
-            macAddr += hexString.substring(hexString.length() - 2);
-
-            if (i != (mac.length - 1)) {
-                macAddr += ":";
-            }
-        }
-
-        return macAddr;
-    }
-
-    public String toString() {
-        String macAddr = macToString(mClientMac);
-
-        return macAddr;
-    }
-
-    /**
-     * Reads a four-octet value from a ByteBuffer and construct
-     * an IPv4 address from that value.
-     */
-    private static Inet4Address readIpAddress(ByteBuffer packet) {
-        Inet4Address result = null;
-        byte[] ipAddr = new byte[4];
-        packet.get(ipAddr);
-
-        try {
-            result = (Inet4Address) Inet4Address.getByAddress(ipAddr);
-        } catch (UnknownHostException ex) {
-            // ipAddr is numeric, so this should not be
-            // triggered.  However, if it is, just nullify
-            result = null;
-        }
-
-        return result;
-    }
-
-    /**
-     * Reads a string of specified length from the buffer.
-     */
-    private static String readAsciiString(ByteBuffer buf, int byteCount, boolean nullOk) {
-        byte[] bytes = new byte[byteCount];
-        buf.get(bytes);
-        int length = bytes.length;
-        if (!nullOk) {
-            // Stop at the first null byte. This is because some DHCP options (e.g., the domain
-            // name) are passed to netd via FrameworkListener, which refuses arguments containing
-            // null bytes. We don't do this by default because vendorInfo is an opaque string which
-            // could in theory contain null bytes.
-            for (length = 0; length < bytes.length; length++) {
-                if (bytes[length] == 0) {
-                    break;
-                }
-            }
-        }
-        return new String(bytes, 0, length, StandardCharsets.US_ASCII);
-    }
-
-    private static boolean isPacketToOrFromClient(short udpSrcPort, short udpDstPort) {
-        return (udpSrcPort == DHCP_CLIENT) || (udpDstPort == DHCP_CLIENT);
-    }
-
-    private static boolean isPacketServerToServer(short udpSrcPort, short udpDstPort) {
-        return (udpSrcPort == DHCP_SERVER) && (udpDstPort == DHCP_SERVER);
-    }
-
-    public static class ParseException extends Exception {
-        public final int errorCode;
-        public ParseException(int errorCode, String msg, Object... args) {
-            super(String.format(msg, args));
-            this.errorCode = errorCode;
-        }
-    }
-
-    /**
-     * Creates a concrete DhcpPacket from the supplied ByteBuffer.  The
-     * buffer may have an L2 encapsulation (which is the full EthernetII
-     * format starting with the source-address MAC) or an L3 encapsulation
-     * (which starts with the IP header).
-     * <br>
-     * A subset of the optional parameters are parsed and are stored
-     * in object fields.
-     */
-    @VisibleForTesting
-    static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
-    {
-        // bootp parameters
-        int transactionId;
-        short secs;
-        Inet4Address clientIp;
-        Inet4Address yourIp;
-        Inet4Address nextIp;
-        Inet4Address relayIp;
-        byte[] clientMac;
-        byte[] clientId = null;
-        List<Inet4Address> dnsServers = new ArrayList<>();
-        List<Inet4Address> gateways = new ArrayList<>();  // aka router
-        Inet4Address serverIdentifier = null;
-        Inet4Address netMask = null;
-        String message = null;
-        String vendorId = null;
-        String vendorInfo = null;
-        byte[] expectedParams = null;
-        String hostName = null;
-        String domainName = null;
-        Inet4Address ipSrc = null;
-        Inet4Address ipDst = null;
-        Inet4Address bcAddr = null;
-        Inet4Address requestedIp = null;
-
-        // The following are all unsigned integers. Internally we store them as signed integers of
-        // the same length because that way we're guaranteed that they can't be out of the range of
-        // the unsigned field in the packet. Callers wanting to pass in an unsigned value will need
-        // to cast it.
-        Short mtu = null;
-        Short maxMessageSize = null;
-        Integer leaseTime = null;
-        Integer T1 = null;
-        Integer T2 = null;
-
-        // dhcp options
-        byte dhcpType = (byte) 0xFF;
-
-        packet.order(ByteOrder.BIG_ENDIAN);
-
-        // check to see if we need to parse L2, IP, and UDP encaps
-        if (pktType == ENCAP_L2) {
-            if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
-                throw new ParseException(DhcpErrorEvent.L2_TOO_SHORT,
-                        "L2 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L2);
-            }
-
-            byte[] l2dst = new byte[6];
-            byte[] l2src = new byte[6];
-
-            packet.get(l2dst);
-            packet.get(l2src);
-
-            short l2type = packet.getShort();
-
-            if (l2type != OsConstants.ETH_P_IP) {
-                throw new ParseException(DhcpErrorEvent.L2_WRONG_ETH_TYPE,
-                        "Unexpected L2 type 0x%04x, expected 0x%04x", l2type, OsConstants.ETH_P_IP);
-            }
-        }
-
-        if (pktType <= ENCAP_L3) {
-            if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
-                throw new ParseException(DhcpErrorEvent.L3_TOO_SHORT,
-                        "L3 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L3);
-            }
-
-            byte ipTypeAndLength = packet.get();
-            int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
-            if (ipVersion != 4) {
-                throw new ParseException(
-                        DhcpErrorEvent.L3_NOT_IPV4, "Invalid IP version %d", ipVersion);
-            }
-
-            // System.out.println("ipType is " + ipType);
-            byte ipDiffServicesField = packet.get();
-            short ipTotalLength = packet.getShort();
-            short ipIdentification = packet.getShort();
-            byte ipFlags = packet.get();
-            byte ipFragOffset = packet.get();
-            byte ipTTL = packet.get();
-            byte ipProto = packet.get();
-            short ipChksm = packet.getShort();
-
-            ipSrc = readIpAddress(packet);
-            ipDst = readIpAddress(packet);
-
-            if (ipProto != IP_TYPE_UDP) {
-                throw new ParseException(
-                        DhcpErrorEvent.L4_NOT_UDP, "Protocol not UDP: %d", ipProto);
-            }
-
-            // Skip options. This cannot cause us to read beyond the end of the buffer because the
-            // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than
-            // MIN_PACKET_LENGTH_L3.
-            int optionWords = ((ipTypeAndLength & 0x0f) - 5);
-            for (int i = 0; i < optionWords; i++) {
-                packet.getInt();
-            }
-
-            // assume UDP
-            short udpSrcPort = packet.getShort();
-            short udpDstPort = packet.getShort();
-            short udpLen = packet.getShort();
-            short udpChkSum = packet.getShort();
-
-            // Only accept packets to or from the well-known client port (expressly permitting
-            // packets from ports other than the well-known server port; http://b/24687559), and
-            // server-to-server packets, e.g. for relays.
-            if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) &&
-                !isPacketServerToServer(udpSrcPort, udpDstPort)) {
-                // This should almost never happen because we use SO_ATTACH_FILTER on the packet
-                // socket to drop packets that don't have the right source ports. However, it's
-                // possible that a packet arrives between when the socket is bound and when the
-                // filter is set. http://b/26696823 .
-                throw new ParseException(DhcpErrorEvent.L4_WRONG_PORT,
-                        "Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
-            }
-        }
-
-        // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
-        if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
-            throw new ParseException(DhcpErrorEvent.BOOTP_TOO_SHORT,
-                        "Invalid type or BOOTP packet too short, %d < %d",
-                        packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
-        }
-
-        byte type = packet.get();
-        byte hwType = packet.get();
-        int addrLen = packet.get() & 0xff;
-        byte hops = packet.get();
-        transactionId = packet.getInt();
-        secs = packet.getShort();
-        short bootpFlags = packet.getShort();
-        boolean broadcast = (bootpFlags & 0x8000) != 0;
-        byte[] ipv4addr = new byte[4];
-
-        try {
-            packet.get(ipv4addr);
-            clientIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
-            packet.get(ipv4addr);
-            yourIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
-            packet.get(ipv4addr);
-            nextIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
-            packet.get(ipv4addr);
-            relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
-        } catch (UnknownHostException ex) {
-            throw new ParseException(DhcpErrorEvent.L3_INVALID_IP,
-                    "Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
-        }
-
-        // Some DHCP servers have been known to announce invalid client hardware address values such
-        // as 0xff. The legacy DHCP client accepted these becuause it does not check the length at
-        // all but only checks that the interface MAC address matches the first bytes of the address
-        // in the packets. We're a bit stricter: if the length is obviously invalid (i.e., bigger
-        // than the size of the field), we fudge it to 6 (Ethernet). http://b/23725795
-        // TODO: evaluate whether to make this test more liberal.
-        if (addrLen > HWADDR_LEN) {
-            addrLen = ETHER_BROADCAST.length;
-        }
-
-        clientMac = new byte[addrLen];
-        packet.get(clientMac);
-
-        // skip over address padding (16 octets allocated)
-        packet.position(packet.position() + (16 - addrLen)
-                        + 64    // skip server host name (64 chars)
-                        + 128); // skip boot file name (128 chars)
-
-        // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211
-        if (packet.remaining() < 4) {
-            throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message");
-        }
-
-        int dhcpMagicCookie = packet.getInt();
-        if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
-            throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE,
-                    "Bad magic cookie 0x%08x, should be 0x%08x",
-                    dhcpMagicCookie, DHCP_MAGIC_COOKIE);
-        }
-
-        // parse options
-        boolean notFinishedOptions = true;
-
-        while ((packet.position() < packet.limit()) && notFinishedOptions) {
-            final byte optionType = packet.get(); // cannot underflow because position < limit
-            try {
-                if (optionType == DHCP_OPTION_END) {
-                    notFinishedOptions = false;
-                } else if (optionType == DHCP_OPTION_PAD) {
-                    // The pad option doesn't have a length field. Nothing to do.
-                } else {
-                    int optionLen = packet.get() & 0xFF;
-                    int expectedLen = 0;
-
-                    switch(optionType) {
-                        case DHCP_SUBNET_MASK:
-                            netMask = readIpAddress(packet);
-                            expectedLen = 4;
-                            break;
-                        case DHCP_ROUTER:
-                            for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
-                                gateways.add(readIpAddress(packet));
-                            }
-                            break;
-                        case DHCP_DNS_SERVER:
-                            for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
-                                dnsServers.add(readIpAddress(packet));
-                            }
-                            break;
-                        case DHCP_HOST_NAME:
-                            expectedLen = optionLen;
-                            hostName = readAsciiString(packet, optionLen, false);
-                            break;
-                        case DHCP_MTU:
-                            expectedLen = 2;
-                            mtu = packet.getShort();
-                            break;
-                        case DHCP_DOMAIN_NAME:
-                            expectedLen = optionLen;
-                            domainName = readAsciiString(packet, optionLen, false);
-                            break;
-                        case DHCP_BROADCAST_ADDRESS:
-                            bcAddr = readIpAddress(packet);
-                            expectedLen = 4;
-                            break;
-                        case DHCP_REQUESTED_IP:
-                            requestedIp = readIpAddress(packet);
-                            expectedLen = 4;
-                            break;
-                        case DHCP_LEASE_TIME:
-                            leaseTime = Integer.valueOf(packet.getInt());
-                            expectedLen = 4;
-                            break;
-                        case DHCP_MESSAGE_TYPE:
-                            dhcpType = packet.get();
-                            expectedLen = 1;
-                            break;
-                        case DHCP_SERVER_IDENTIFIER:
-                            serverIdentifier = readIpAddress(packet);
-                            expectedLen = 4;
-                            break;
-                        case DHCP_PARAMETER_LIST:
-                            expectedParams = new byte[optionLen];
-                            packet.get(expectedParams);
-                            expectedLen = optionLen;
-                            break;
-                        case DHCP_MESSAGE:
-                            expectedLen = optionLen;
-                            message = readAsciiString(packet, optionLen, false);
-                            break;
-                        case DHCP_MAX_MESSAGE_SIZE:
-                            expectedLen = 2;
-                            maxMessageSize = Short.valueOf(packet.getShort());
-                            break;
-                        case DHCP_RENEWAL_TIME:
-                            expectedLen = 4;
-                            T1 = Integer.valueOf(packet.getInt());
-                            break;
-                        case DHCP_REBINDING_TIME:
-                            expectedLen = 4;
-                            T2 = Integer.valueOf(packet.getInt());
-                            break;
-                        case DHCP_VENDOR_CLASS_ID:
-                            expectedLen = optionLen;
-                            // Embedded nulls are safe as this does not get passed to netd.
-                            vendorId = readAsciiString(packet, optionLen, true);
-                            break;
-                        case DHCP_CLIENT_IDENTIFIER: { // Client identifier
-                            byte[] id = new byte[optionLen];
-                            packet.get(id);
-                            expectedLen = optionLen;
-                        } break;
-                        case DHCP_VENDOR_INFO:
-                            expectedLen = optionLen;
-                            // Embedded nulls are safe as this does not get passed to netd.
-                            vendorInfo = readAsciiString(packet, optionLen, true);
-                            break;
-                        default:
-                            // ignore any other parameters
-                            for (int i = 0; i < optionLen; i++) {
-                                expectedLen++;
-                                byte throwaway = packet.get();
-                            }
-                    }
-
-                    if (expectedLen != optionLen) {
-                        final int errorCode = DhcpErrorEvent.errorCodeWithOption(
-                                DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
-                        throw new ParseException(errorCode,
-                                "Invalid length %d for option %d, expected %d",
-                                optionLen, optionType, expectedLen);
-                    }
-                }
-            } catch (BufferUnderflowException e) {
-                final int errorCode = DhcpErrorEvent.errorCodeWithOption(
-                        DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
-                throw new ParseException(errorCode, "BufferUnderflowException");
-            }
-        }
-
-        DhcpPacket newPacket;
-
-        switch(dhcpType) {
-            case (byte) 0xFF:
-                throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE,
-                        "No DHCP message type option");
-            case DHCP_MESSAGE_TYPE_DISCOVER:
-                newPacket = new DhcpDiscoverPacket(transactionId, secs, relayIp, clientMac,
-                        broadcast, ipSrc);
-                break;
-            case DHCP_MESSAGE_TYPE_OFFER:
-                newPacket = new DhcpOfferPacket(
-                    transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac);
-                break;
-            case DHCP_MESSAGE_TYPE_REQUEST:
-                newPacket = new DhcpRequestPacket(
-                    transactionId, secs, clientIp, relayIp, clientMac, broadcast);
-                break;
-            case DHCP_MESSAGE_TYPE_DECLINE:
-                newPacket = new DhcpDeclinePacket(
-                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
-                    clientMac);
-                break;
-            case DHCP_MESSAGE_TYPE_ACK:
-                newPacket = new DhcpAckPacket(
-                    transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac);
-                break;
-            case DHCP_MESSAGE_TYPE_NAK:
-                newPacket = new DhcpNakPacket(
-                        transactionId, secs, relayIp, clientMac, broadcast);
-                break;
-            case DHCP_MESSAGE_TYPE_RELEASE:
-                if (serverIdentifier == null) {
-                    throw new ParseException(DhcpErrorEvent.MISC_ERROR,
-                            "DHCPRELEASE without server identifier");
-                }
-                newPacket = new DhcpReleasePacket(
-                        transactionId, serverIdentifier, clientIp, relayIp, clientMac);
-                break;
-            case DHCP_MESSAGE_TYPE_INFORM:
-                newPacket = new DhcpInformPacket(
-                    transactionId, secs, clientIp, yourIp, nextIp, relayIp,
-                    clientMac);
-                break;
-            default:
-                throw new ParseException(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE,
-                        "Unimplemented DHCP type %d", dhcpType);
-        }
-
-        newPacket.mBroadcastAddress = bcAddr;
-        newPacket.mClientId = clientId;
-        newPacket.mDnsServers = dnsServers;
-        newPacket.mDomainName = domainName;
-        newPacket.mGateways = gateways;
-        newPacket.mHostName = hostName;
-        newPacket.mLeaseTime = leaseTime;
-        newPacket.mMessage = message;
-        newPacket.mMtu = mtu;
-        newPacket.mRequestedIp = requestedIp;
-        newPacket.mRequestedParams = expectedParams;
-        newPacket.mServerIdentifier = serverIdentifier;
-        newPacket.mSubnetMask = netMask;
-        newPacket.mMaxMessageSize = maxMessageSize;
-        newPacket.mT1 = T1;
-        newPacket.mT2 = T2;
-        newPacket.mVendorId = vendorId;
-        newPacket.mVendorInfo = vendorInfo;
-        return newPacket;
-    }
-
-    /**
-     * Parse a packet from an array of bytes, stopping at the given length.
-     */
-    public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
-            throws ParseException {
-        ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
-        try {
-            return decodeFullPacket(buffer, pktType);
-        } catch (ParseException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage());
-        }
-    }
-
-    /**
-     *  Construct a DhcpResults object from a DHCP reply packet.
-     */
-    public DhcpResults toDhcpResults() {
-        Inet4Address ipAddress = mYourIp;
-        if (ipAddress.equals(Inet4Address.ANY)) {
-            ipAddress = mClientIp;
-            if (ipAddress.equals(Inet4Address.ANY)) {
-                return null;
-            }
-        }
-
-        int prefixLength;
-        if (mSubnetMask != null) {
-            try {
-                prefixLength = NetworkUtils.netmaskToPrefixLength(mSubnetMask);
-            } catch (IllegalArgumentException e) {
-                // Non-contiguous netmask.
-                return null;
-            }
-        } else {
-            prefixLength = NetworkUtils.getImplicitNetmask(ipAddress);
-        }
-
-        DhcpResults results = new DhcpResults();
-        try {
-            results.ipAddress = new LinkAddress(ipAddress, prefixLength);
-        } catch (IllegalArgumentException e) {
-            return null;
-        }
-
-        if (mGateways.size() > 0) {
-            results.gateway = mGateways.get(0);
-        }
-
-        results.dnsServers.addAll(mDnsServers);
-        results.domains = mDomainName;
-        results.serverAddress = mServerIdentifier;
-        results.vendorInfo = mVendorInfo;
-        results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
-        results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
-
-        return results;
-    }
-
-    /**
-     * Returns the parsed lease time, in milliseconds, or 0 for infinite.
-     */
-    public long getLeaseTimeMillis() {
-        // dhcpcd treats the lack of a lease time option as an infinite lease.
-        if (mLeaseTime == null || mLeaseTime == INFINITE_LEASE) {
-            return 0;
-        } else if (0 <= mLeaseTime && mLeaseTime < MINIMUM_LEASE) {
-            return MINIMUM_LEASE * 1000;
-        } else {
-            return (mLeaseTime & 0xffffffffL) * 1000;
-        }
-    }
-
-    /**
-     * Builds a DHCP-DISCOVER packet from the required specified
-     * parameters.
-     */
-    public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
-        short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams) {
-        DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, INADDR_ANY /* relayIp */,
-                clientMac, broadcast, INADDR_ANY /* srcIp */);
-        pkt.mRequestedParams = expectedParams;
-        return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
-    }
-
-    /**
-     * Builds a DHCP-OFFER packet from the required specified
-     * parameters.
-     */
-    public static ByteBuffer buildOfferPacket(int encap, int transactionId,
-        boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp,
-        Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask,
-        Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
-        Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
-        short mtu) {
-        DhcpPacket pkt = new DhcpOfferPacket(
-                transactionId, (short) 0, broadcast, serverIpAddr, relayIp,
-                INADDR_ANY /* clientIp */, yourIp, mac);
-        pkt.mGateways = gateways;
-        pkt.mDnsServers = dnsServers;
-        pkt.mLeaseTime = timeout;
-        pkt.mDomainName = domainName;
-        pkt.mHostName = hostname;
-        pkt.mServerIdentifier = dhcpServerIdentifier;
-        pkt.mSubnetMask = netMask;
-        pkt.mBroadcastAddress = bcAddr;
-        pkt.mMtu = mtu;
-        if (metered) {
-            pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
-        }
-        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
-    }
-
-    /**
-     * Builds a DHCP-ACK packet from the required specified parameters.
-     */
-    public static ByteBuffer buildAckPacket(int encap, int transactionId,
-        boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp,
-        Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask,
-        Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers,
-        Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered,
-        short mtu) {
-        DhcpPacket pkt = new DhcpAckPacket(
-                transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp,
-                mac);
-        pkt.mGateways = gateways;
-        pkt.mDnsServers = dnsServers;
-        pkt.mLeaseTime = timeout;
-        pkt.mDomainName = domainName;
-        pkt.mHostName = hostname;
-        pkt.mSubnetMask = netMask;
-        pkt.mServerIdentifier = dhcpServerIdentifier;
-        pkt.mBroadcastAddress = bcAddr;
-        pkt.mMtu = mtu;
-        if (metered) {
-            pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED;
-        }
-        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
-    }
-
-    /**
-     * Builds a DHCP-NAK packet from the required specified parameters.
-     */
-    public static ByteBuffer buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr,
-            Inet4Address relayIp, byte[] mac, boolean broadcast, String message) {
-        DhcpPacket pkt = new DhcpNakPacket(
-                transactionId, (short) 0, relayIp, mac, broadcast);
-        pkt.mMessage = message;
-        pkt.mServerIdentifier = serverIpAddr;
-        return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
-    }
-
-    /**
-     * Builds a DHCP-REQUEST packet from the required specified parameters.
-     */
-    public static ByteBuffer buildRequestPacket(int encap,
-        int transactionId, short secs, Inet4Address clientIp, boolean broadcast,
-        byte[] clientMac, Inet4Address requestedIpAddress,
-        Inet4Address serverIdentifier, byte[] requestedParams, String hostName) {
-        DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp,
-                INADDR_ANY /* relayIp */, clientMac, broadcast);
-        pkt.mRequestedIp = requestedIpAddress;
-        pkt.mServerIdentifier = serverIdentifier;
-        pkt.mHostName = hostName;
-        pkt.mRequestedParams = requestedParams;
-        ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
-        return result;
-    }
-}
diff --git a/services/net/java/android/net/dhcp/DhcpPacketListener.java b/services/net/java/android/net/dhcp/DhcpPacketListener.java
deleted file mode 100644
index 6f620c5..0000000
--- a/services/net/java/android/net/dhcp/DhcpPacketListener.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dhcp;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.util.FdEventsReader;
-import android.os.Handler;
-import android.system.Os;
-
-import java.io.FileDescriptor;
-import java.net.Inet4Address;
-import java.net.InetSocketAddress;
-
-/**
- * A {@link FdEventsReader} to receive and parse {@link DhcpPacket}.
- * @hide
- */
-abstract class DhcpPacketListener extends FdEventsReader<DhcpPacketListener.Payload> {
-    static final class Payload {
-        final byte[] bytes = new byte[DhcpPacket.MAX_LENGTH];
-        Inet4Address srcAddr;
-        int srcPort;
-    }
-
-    public DhcpPacketListener(@NonNull Handler handler) {
-        super(handler, new Payload());
-    }
-
-    @Override
-    protected int recvBufSize(@NonNull Payload buffer) {
-        return buffer.bytes.length;
-    }
-
-    @Override
-    protected final void handlePacket(@NonNull Payload recvbuf, int length) {
-        if (recvbuf.srcAddr == null) {
-            return;
-        }
-
-        try {
-            final DhcpPacket packet = DhcpPacket.decodeFullPacket(recvbuf.bytes, length,
-                    DhcpPacket.ENCAP_BOOTP);
-            onReceive(packet, recvbuf.srcAddr, recvbuf.srcPort);
-        } catch (DhcpPacket.ParseException e) {
-            logParseError(recvbuf.bytes, length, e);
-        }
-    }
-
-    @Override
-    protected int readPacket(@NonNull FileDescriptor fd, @NonNull Payload packetBuffer)
-            throws Exception {
-        final InetSocketAddress addr = new InetSocketAddress();
-        final int read = Os.recvfrom(
-                fd, packetBuffer.bytes, 0, packetBuffer.bytes.length, 0 /* flags */, addr);
-
-        // Buffers with null srcAddr will be dropped in handlePacket()
-        packetBuffer.srcAddr = inet4AddrOrNull(addr);
-        packetBuffer.srcPort = addr.getPort();
-        return read;
-    }
-
-    @Nullable
-    private static Inet4Address inet4AddrOrNull(@NonNull InetSocketAddress addr) {
-        return addr.getAddress() instanceof Inet4Address
-                ? (Inet4Address) addr.getAddress()
-                : null;
-    }
-
-    protected abstract void onReceive(@NonNull DhcpPacket packet, @NonNull Inet4Address srcAddr,
-            int srcPort);
-    protected abstract void logParseError(@NonNull byte[] packet, int length,
-            @NonNull DhcpPacket.ParseException e);
-}
diff --git a/services/net/java/android/net/dhcp/DhcpServer.java b/services/net/java/android/net/dhcp/DhcpServer.java
deleted file mode 100644
index 35d29e7..0000000
--- a/services/net/java/android/net/dhcp/DhcpServer.java
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dhcp;
-
-import static android.net.NetworkUtils.getBroadcastAddress;
-import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
-import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER;
-import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
-import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
-import static android.net.dhcp.DhcpPacket.DHCP_SERVER;
-import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
-import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOL_SOCKET;
-import static android.system.OsConstants.SO_BINDTODEVICE;
-import static android.system.OsConstants.SO_BROADCAST;
-import static android.system.OsConstants.SO_REUSEADDR;
-
-import static java.lang.Integer.toUnsignedLong;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.MacAddress;
-import android.net.NetworkUtils;
-import android.net.TrafficStats;
-import android.net.util.SharedLog;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.SystemClock;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.text.TextUtils;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.HexDump;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-
-/**
- * A DHCPv4 server.
- *
- * <p>This server listens for and responds to packets on a single interface. It considers itself
- * authoritative for all leases on the subnet, which means that DHCP requests for unknown leases of
- * unknown hosts receive a reply instead of being ignored.
- *
- * <p>The server is single-threaded (including send/receive operations): all internal operations are
- * done on the provided {@link Looper}. Public methods are thread-safe and will schedule operations
- * on the looper asynchronously.
- * @hide
- */
-public class DhcpServer {
-    private static final String REPO_TAG = "Repository";
-
-    // Lease time to transmit to client instead of a negative time in case a lease expired before
-    // the server could send it (if the server process is suspended for example).
-    private static final int EXPIRED_FALLBACK_LEASE_TIME_SECS = 120;
-
-    private static final int CMD_START_DHCP_SERVER = 1;
-    private static final int CMD_STOP_DHCP_SERVER = 2;
-    private static final int CMD_UPDATE_PARAMS = 3;
-
-    @NonNull
-    private final ServerHandler mHandler;
-    @NonNull
-    private final String mIfName;
-    @NonNull
-    private final DhcpLeaseRepository mLeaseRepo;
-    @NonNull
-    private final SharedLog mLog;
-    @NonNull
-    private final Dependencies mDeps;
-    @NonNull
-    private final Clock mClock;
-    @NonNull
-    private final DhcpPacketListener mPacketListener;
-
-    @Nullable
-    private FileDescriptor mSocket;
-    @NonNull
-    private DhcpServingParams mServingParams;
-
-    public static class Clock {
-        /**
-         * @see SystemClock#elapsedRealtime()
-         */
-        public long elapsedRealtime() {
-            return SystemClock.elapsedRealtime();
-        }
-    }
-
-    public interface Dependencies {
-        void sendPacket(@NonNull FileDescriptor fd, @NonNull ByteBuffer buffer,
-                @NonNull InetAddress dst) throws ErrnoException, IOException;
-        DhcpLeaseRepository makeLeaseRepository(@NonNull DhcpServingParams servingParams,
-                @NonNull SharedLog log, @NonNull Clock clock);
-        DhcpPacketListener makePacketListener();
-        Clock makeClock();
-        void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr,
-                @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException;
-    }
-
-    private class DependenciesImpl implements Dependencies {
-        @Override
-        public void sendPacket(@NonNull FileDescriptor fd, @NonNull ByteBuffer buffer,
-                @NonNull InetAddress dst) throws ErrnoException, IOException {
-            Os.sendto(fd, buffer, 0, dst, DhcpPacket.DHCP_CLIENT);
-        }
-
-        @Override
-        public DhcpLeaseRepository makeLeaseRepository(@NonNull DhcpServingParams servingParams,
-                @NonNull SharedLog log, @NonNull Clock clock) {
-            return new DhcpLeaseRepository(
-                    DhcpServingParams.makeIpPrefix(servingParams.serverAddr),
-                    servingParams.excludedAddrs,
-                    servingParams.dhcpLeaseTimeSecs*1000, log.forSubComponent(REPO_TAG), clock);
-        }
-
-        @Override
-        public DhcpPacketListener makePacketListener() {
-            return new PacketListener();
-        }
-
-        @Override
-        public Clock makeClock() {
-            return new Clock();
-        }
-
-        @Override
-        public void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr,
-                @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException {
-            NetworkUtils.addArpEntry(ipv4Addr, ethAddr, ifname, fd);
-        }
-    }
-
-    private static class MalformedPacketException extends Exception {
-        MalformedPacketException(String message, Throwable t) {
-            super(message, t);
-        }
-    }
-
-    public DhcpServer(@NonNull Looper looper, @NonNull String ifName,
-            @NonNull DhcpServingParams params, @NonNull SharedLog log) {
-        this(looper, ifName, params, log, null);
-    }
-
-    @VisibleForTesting
-    DhcpServer(@NonNull Looper looper, @NonNull String ifName,
-            @NonNull DhcpServingParams params, @NonNull SharedLog log,
-            @Nullable Dependencies deps) {
-        if (deps == null) {
-            deps = new DependenciesImpl();
-        }
-        mHandler = new ServerHandler(looper);
-        mIfName = ifName;
-        mServingParams = params;
-        mLog = log;
-        mDeps = deps;
-        mClock = deps.makeClock();
-        mPacketListener = deps.makePacketListener();
-        mLeaseRepo = deps.makeLeaseRepository(mServingParams, mLog, mClock);
-    }
-
-    /**
-     * Start listening for and responding to packets.
-     */
-    public void start() {
-        mHandler.sendEmptyMessage(CMD_START_DHCP_SERVER);
-    }
-
-    /**
-     * Update serving parameters. All subsequently received requests will be handled with the new
-     * parameters, and current leases that are incompatible with the new parameters are dropped.
-     */
-    public void updateParams(@NonNull DhcpServingParams params) {
-        sendMessage(CMD_UPDATE_PARAMS, params);
-    }
-
-    /**
-     * Stop listening for packets.
-     *
-     * <p>As the server is stopped asynchronously, some packets may still be processed shortly after
-     * calling this method.
-     */
-    public void stop() {
-        mHandler.sendEmptyMessage(CMD_STOP_DHCP_SERVER);
-    }
-
-    private void sendMessage(int what, @Nullable Object obj) {
-        mHandler.sendMessage(mHandler.obtainMessage(what, obj));
-    }
-
-    private class ServerHandler extends Handler {
-        public ServerHandler(@NonNull Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(@NonNull Message msg) {
-            switch (msg.what) {
-                case CMD_UPDATE_PARAMS:
-                    final DhcpServingParams params = (DhcpServingParams) msg.obj;
-                    mServingParams = params;
-                    mLeaseRepo.updateParams(
-                            DhcpServingParams.makeIpPrefix(mServingParams.serverAddr),
-                            params.excludedAddrs,
-                            params.dhcpLeaseTimeSecs);
-                    break;
-                case CMD_START_DHCP_SERVER:
-                    // This is a no-op if the listener is already started
-                    mPacketListener.start();
-                    break;
-                case CMD_STOP_DHCP_SERVER:
-                    // This is a no-op if the listener was not started
-                    mPacketListener.stop();
-                    break;
-            }
-        }
-    }
-
-    @VisibleForTesting
-    void processPacket(@NonNull DhcpPacket packet, int srcPort) {
-        final String packetType = packet.getClass().getSimpleName();
-        if (srcPort != DHCP_CLIENT) {
-            mLog.logf("Ignored packet of type %s sent from client port %d", packetType, srcPort);
-            return;
-        }
-
-        mLog.log("Received packet of type " + packetType);
-        final Inet4Address sid = packet.mServerIdentifier;
-        if (sid != null && !sid.equals(mServingParams.serverAddr.getAddress())) {
-            mLog.log("Packet ignored due to wrong server identifier: " + sid);
-            return;
-        }
-
-        try {
-            if (packet instanceof DhcpDiscoverPacket) {
-                processDiscover((DhcpDiscoverPacket) packet);
-            } else if (packet instanceof DhcpRequestPacket) {
-                processRequest((DhcpRequestPacket) packet);
-            } else if (packet instanceof DhcpReleasePacket) {
-                processRelease((DhcpReleasePacket) packet);
-            } else {
-                mLog.e("Unknown packet type: " + packet.getClass().getSimpleName());
-            }
-        } catch (MalformedPacketException e) {
-            // Not an internal error: only logging exception message, not stacktrace
-            mLog.e("Ignored malformed packet: " + e.getMessage());
-        }
-    }
-
-    private void logIgnoredPacketInvalidSubnet(DhcpLeaseRepository.InvalidSubnetException e) {
-        // Not an internal error: only logging exception message, not stacktrace
-        mLog.e("Ignored packet from invalid subnet: " + e.getMessage());
-    }
-
-    private void processDiscover(@NonNull DhcpDiscoverPacket packet)
-            throws MalformedPacketException {
-        final DhcpLease lease;
-        final MacAddress clientMac = getMacAddr(packet);
-        try {
-            lease = mLeaseRepo.getOffer(packet.getExplicitClientIdOrNull(), clientMac,
-                    packet.mRelayIp, packet.mRequestedIp, packet.mHostName);
-        } catch (DhcpLeaseRepository.OutOfAddressesException e) {
-            transmitNak(packet, "Out of addresses to offer");
-            return;
-        } catch (DhcpLeaseRepository.InvalidSubnetException e) {
-            logIgnoredPacketInvalidSubnet(e);
-            return;
-        }
-
-        transmitOffer(packet, lease, clientMac);
-    }
-
-    private void processRequest(@NonNull DhcpRequestPacket packet) throws MalformedPacketException {
-        // If set, packet SID matches with this server's ID as checked in processPacket().
-        final boolean sidSet = packet.mServerIdentifier != null;
-        final DhcpLease lease;
-        final MacAddress clientMac = getMacAddr(packet);
-        try {
-            lease = mLeaseRepo.requestLease(packet.getExplicitClientIdOrNull(), clientMac,
-                    packet.mClientIp, packet.mRelayIp, packet.mRequestedIp, sidSet,
-                    packet.mHostName);
-        } catch (DhcpLeaseRepository.InvalidAddressException e) {
-            transmitNak(packet, "Invalid requested address");
-            return;
-        } catch (DhcpLeaseRepository.InvalidSubnetException e) {
-            logIgnoredPacketInvalidSubnet(e);
-            return;
-        }
-
-        transmitAck(packet, lease, clientMac);
-    }
-
-    private void processRelease(@NonNull DhcpReleasePacket packet)
-            throws MalformedPacketException {
-        final byte[] clientId = packet.getExplicitClientIdOrNull();
-        final MacAddress macAddr = getMacAddr(packet);
-        // Don't care about success (there is no ACK/NAK); logging is already done in the repository
-        mLeaseRepo.releaseLease(clientId, macAddr, packet.mClientIp);
-    }
-
-    private Inet4Address getAckOrOfferDst(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
-            boolean broadcastFlag) {
-        // Unless relayed or broadcast, send to client IP if already configured on the client, or to
-        // the lease address if the client has no configured address
-        if (!isEmpty(request.mRelayIp)) {
-            return request.mRelayIp;
-        } else if (broadcastFlag) {
-            return (Inet4Address) Inet4Address.ALL;
-        } else if (!isEmpty(request.mClientIp)) {
-            return request.mClientIp;
-        } else {
-            return lease.getNetAddr();
-        }
-    }
-
-    /**
-     * Determine whether the broadcast flag should be set in the BOOTP packet flags. This does not
-     * apply to NAK responses, which should always have it set.
-     */
-    private static boolean getBroadcastFlag(@NonNull DhcpPacket request, @NonNull DhcpLease lease) {
-        // No broadcast flag if the client already has a configured IP to unicast to. RFC2131 #4.1
-        // has some contradictions regarding broadcast behavior if a client already has an IP
-        // configured and sends a request with both ciaddr (renew/rebind) and the broadcast flag
-        // set. Sending a unicast response to ciaddr matches previous behavior and is more
-        // efficient.
-        // If the client has no configured IP, broadcast if requested by the client or if the lease
-        // address cannot be used to send a unicast reply either.
-        return isEmpty(request.mClientIp) && (request.mBroadcast || isEmpty(lease.getNetAddr()));
-    }
-
-    /**
-     * Get the hostname from a lease if non-empty and requested in the incoming request.
-     * @param request The incoming request.
-     * @return The hostname, or null if not requested or empty.
-     */
-    @Nullable
-    private static String getHostnameIfRequested(@NonNull DhcpPacket request,
-            @NonNull DhcpLease lease) {
-        return request.hasRequestedParam(DHCP_HOST_NAME) && !TextUtils.isEmpty(lease.getHostname())
-                ? lease.getHostname()
-                : null;
-    }
-
-    private boolean transmitOffer(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
-            @NonNull MacAddress clientMac) {
-        final boolean broadcastFlag = getBroadcastFlag(request, lease);
-        final int timeout = getLeaseTimeout(lease);
-        final Inet4Address prefixMask =
-                getPrefixMaskAsInet4Address(mServingParams.serverAddr.getPrefixLength());
-        final Inet4Address broadcastAddr = getBroadcastAddress(
-                mServingParams.getServerInet4Addr(), mServingParams.serverAddr.getPrefixLength());
-        final String hostname = getHostnameIfRequested(request, lease);
-        final ByteBuffer offerPacket = DhcpPacket.buildOfferPacket(
-                ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(),
-                request.mRelayIp, lease.getNetAddr(), request.mClientMac, timeout, prefixMask,
-                broadcastAddr, new ArrayList<>(mServingParams.defaultRouters),
-                new ArrayList<>(mServingParams.dnsServers),
-                mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
-                mServingParams.metered, (short) mServingParams.linkMtu);
-
-        return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag);
-    }
-
-    private boolean transmitAck(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
-            @NonNull MacAddress clientMac) {
-        // TODO: replace DhcpPacket's build methods with real builders and use common code with
-        // transmitOffer above
-        final boolean broadcastFlag = getBroadcastFlag(request, lease);
-        final int timeout = getLeaseTimeout(lease);
-        final String hostname = getHostnameIfRequested(request, lease);
-        final ByteBuffer ackPacket = DhcpPacket.buildAckPacket(ENCAP_BOOTP, request.mTransId,
-                broadcastFlag, mServingParams.getServerInet4Addr(), request.mRelayIp,
-                lease.getNetAddr(), request.mClientIp, request.mClientMac, timeout,
-                mServingParams.getPrefixMaskAsAddress(), mServingParams.getBroadcastAddress(),
-                new ArrayList<>(mServingParams.defaultRouters),
-                new ArrayList<>(mServingParams.dnsServers),
-                mServingParams.getServerInet4Addr(), null /* domainName */, hostname,
-                mServingParams.metered, (short) mServingParams.linkMtu);
-
-        return transmitOfferOrAckPacket(ackPacket, request, lease, clientMac, broadcastFlag);
-    }
-
-    private boolean transmitNak(DhcpPacket request, String message) {
-        mLog.w("Transmitting NAK: " + message);
-        // Always set broadcast flag for NAK: client may not have a correct IP
-        final ByteBuffer nakPacket = DhcpPacket.buildNakPacket(
-                ENCAP_BOOTP, request.mTransId, mServingParams.getServerInet4Addr(),
-                request.mRelayIp, request.mClientMac, true /* broadcast */, message);
-
-        final Inet4Address dst = isEmpty(request.mRelayIp)
-                ? (Inet4Address) Inet4Address.ALL
-                : request.mRelayIp;
-        return transmitPacket(nakPacket, DhcpNakPacket.class.getSimpleName(), dst);
-    }
-
-    private boolean transmitOfferOrAckPacket(@NonNull ByteBuffer buf, @NonNull DhcpPacket request,
-            @NonNull DhcpLease lease, @NonNull MacAddress clientMac, boolean broadcastFlag) {
-        mLog.logf("Transmitting %s with lease %s", request.getClass().getSimpleName(), lease);
-        // Client may not yet respond to ARP for the lease address, which may be the destination
-        // address. Add an entry to the ARP cache to save future ARP probes and make sure the
-        // packet reaches its destination.
-        if (!addArpEntry(clientMac, lease.getNetAddr())) {
-            // Logging for error already done
-            return false;
-        }
-        final Inet4Address dst = getAckOrOfferDst(request, lease, broadcastFlag);
-        return transmitPacket(buf, request.getClass().getSimpleName(), dst);
-    }
-
-    private boolean transmitPacket(@NonNull ByteBuffer buf, @NonNull String packetTypeTag,
-            @NonNull Inet4Address dst) {
-        try {
-            mDeps.sendPacket(mSocket, buf, dst);
-        } catch (ErrnoException | IOException e) {
-            mLog.e("Can't send packet " + packetTypeTag, e);
-            return false;
-        }
-        return true;
-    }
-
-    private boolean addArpEntry(@NonNull MacAddress macAddr, @NonNull Inet4Address inetAddr) {
-        try {
-            mDeps.addArpEntry(inetAddr, macAddr, mIfName, mSocket);
-            return true;
-        } catch (IOException e) {
-            mLog.e("Error adding client to ARP table", e);
-            return false;
-        }
-    }
-
-    /**
-     * Get the remaining lease time in seconds, starting from {@link Clock#elapsedRealtime()}.
-     *
-     * <p>This is an unsigned 32-bit integer, so it cannot be read as a standard (signed) Java int.
-     * The return value is only intended to be used to populate the lease time field in a DHCP
-     * response, considering that lease time is an unsigned 32-bit integer field in DHCP packets.
-     *
-     * <p>Lease expiration times are tracked internally with millisecond precision: this method
-     * returns a rounded down value.
-     */
-    private int getLeaseTimeout(@NonNull DhcpLease lease) {
-        final long remainingTimeSecs = (lease.getExpTime() - mClock.elapsedRealtime()) / 1000;
-        if (remainingTimeSecs < 0) {
-            mLog.e("Processing expired lease " + lease);
-            return EXPIRED_FALLBACK_LEASE_TIME_SECS;
-        }
-
-        if (remainingTimeSecs >= toUnsignedLong(INFINITE_LEASE)) {
-            return INFINITE_LEASE;
-        }
-
-        return (int) remainingTimeSecs;
-    }
-
-    /**
-     * Get the client MAC address from a packet.
-     *
-     * @throws MalformedPacketException The address in the packet uses an unsupported format.
-     */
-    @NonNull
-    private MacAddress getMacAddr(@NonNull DhcpPacket packet) throws MalformedPacketException {
-        try {
-            return MacAddress.fromBytes(packet.getClientMac());
-        } catch (IllegalArgumentException e) {
-            final String message = "Invalid MAC address in packet: "
-                    + HexDump.dumpHexString(packet.getClientMac());
-            throw new MalformedPacketException(message, e);
-        }
-    }
-
-    private static boolean isEmpty(@Nullable Inet4Address address) {
-        return address == null || Inet4Address.ANY.equals(address);
-    }
-
-    private class PacketListener extends DhcpPacketListener {
-        public PacketListener() {
-            super(mHandler);
-        }
-
-        @Override
-        protected void onReceive(DhcpPacket packet, Inet4Address srcAddr, int srcPort) {
-            processPacket(packet, srcPort);
-        }
-
-        @Override
-        protected void logError(String msg, Exception e) {
-            mLog.e("Error receiving packet: " + msg, e);
-        }
-
-        @Override
-        protected void logParseError(byte[] packet, int length, DhcpPacket.ParseException e) {
-            mLog.e("Error parsing packet", e);
-        }
-
-        @Override
-        protected FileDescriptor createFd() {
-            // TODO: have and use an API to set a socket tag without going through the thread tag
-            final int oldTag = TrafficStats.getAndSetThreadStatsTag(TAG_SYSTEM_DHCP_SERVER);
-            try {
-                mSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-                Os.setsockoptInt(mSocket, SOL_SOCKET, SO_REUSEADDR, 1);
-                // SO_BINDTODEVICE actually takes a string. This works because the first member
-                // of struct ifreq is a NULL-terminated interface name.
-                // TODO: add a setsockoptString()
-                Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mIfName);
-                Os.setsockoptInt(mSocket, SOL_SOCKET, SO_BROADCAST, 1);
-                Os.bind(mSocket, Inet4Address.ANY, DHCP_SERVER);
-                NetworkUtils.protectFromVpn(mSocket);
-
-                return mSocket;
-            } catch (IOException | ErrnoException e) {
-                mLog.e("Error creating UDP socket", e);
-                DhcpServer.this.stop();
-                return null;
-            } finally {
-                TrafficStats.setThreadStatsTag(oldTag);
-            }
-        }
-    }
-}
diff --git a/services/net/java/android/net/dhcp/DhcpServingParams.java b/services/net/java/android/net/dhcp/DhcpServingParams.java
deleted file mode 100644
index df15ba1..0000000
--- a/services/net/java/android/net/dhcp/DhcpServingParams.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dhcp;
-
-import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
-import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
-import static android.net.util.NetworkConstants.IPV4_MAX_MTU;
-import static android.net.util.NetworkConstants.IPV4_MIN_MTU;
-
-import static java.lang.Integer.toUnsignedLong;
-
-import android.annotation.NonNull;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.NetworkUtils;
-
-import com.google.android.collect.Sets;
-
-import java.net.Inet4Address;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Parameters used by the DhcpServer to serve requests.
- *
- * <p>Instances are immutable. Use {@link DhcpServingParams.Builder} to instantiate.
- * @hide
- */
-public class DhcpServingParams {
-    public static final int MTU_UNSET = 0;
-    public static final int MIN_PREFIX_LENGTH = 16;
-    public static final int MAX_PREFIX_LENGTH = 30;
-
-    /** Server inet address and prefix to serve */
-    @NonNull
-    public final LinkAddress serverAddr;
-
-    /**
-     * Default routers to be advertised to DHCP clients. May be empty.
-     * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
-     */
-    @NonNull
-    public final Set<Inet4Address> defaultRouters;
-
-    /**
-     * DNS servers to be advertised to DHCP clients. May be empty.
-     * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
-     */
-    @NonNull
-    public final Set<Inet4Address> dnsServers;
-
-    /**
-     * Excluded addresses that the DHCP server is not allowed to assign to clients.
-     * This set is provided by {@link DhcpServingParams.Builder} and is immutable.
-     */
-    @NonNull
-    public final Set<Inet4Address> excludedAddrs;
-
-    // DHCP uses uint32. Use long for clearer code, and check range when building.
-    public final long dhcpLeaseTimeSecs;
-    public final int linkMtu;
-
-    /**
-     * Indicates whether the DHCP server should send the ANDROID_METERED vendor-specific option.
-     */
-    public final boolean metered;
-
-    /**
-     * Checked exception thrown when some parameters used to build {@link DhcpServingParams} are
-     * missing or invalid.
-     */
-    public static class InvalidParameterException extends Exception {
-        public InvalidParameterException(String message) {
-            super(message);
-        }
-    }
-
-    private DhcpServingParams(@NonNull LinkAddress serverAddr,
-            @NonNull Set<Inet4Address> defaultRouters,
-            @NonNull Set<Inet4Address> dnsServers, @NonNull Set<Inet4Address> excludedAddrs,
-            long dhcpLeaseTimeSecs, int linkMtu, boolean metered) {
-        this.serverAddr = serverAddr;
-        this.defaultRouters = defaultRouters;
-        this.dnsServers = dnsServers;
-        this.excludedAddrs = excludedAddrs;
-        this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
-        this.linkMtu = linkMtu;
-        this.metered = metered;
-    }
-
-    @NonNull
-    public Inet4Address getServerInet4Addr() {
-        return (Inet4Address) serverAddr.getAddress();
-    }
-
-    /**
-     * Get the served prefix mask as an IPv4 address.
-     *
-     * <p>For example, if the served prefix is 192.168.42.0/24, this will return 255.255.255.0.
-     */
-    @NonNull
-    public Inet4Address getPrefixMaskAsAddress() {
-        return getPrefixMaskAsInet4Address(serverAddr.getPrefixLength());
-    }
-
-    /**
-     * Get the server broadcast address.
-     *
-     * <p>For example, if the server {@link LinkAddress} is 192.168.42.1/24, this will return
-     * 192.168.42.255.
-     */
-    @NonNull
-    public Inet4Address getBroadcastAddress() {
-        return NetworkUtils.getBroadcastAddress(getServerInet4Addr(), serverAddr.getPrefixLength());
-    }
-
-    /**
-     * Utility class to create new instances of {@link DhcpServingParams} while checking validity
-     * of the parameters.
-     */
-    public static class Builder {
-        private LinkAddress serverAddr;
-        private Set<Inet4Address> defaultRouters;
-        private Set<Inet4Address> dnsServers;
-        private Set<Inet4Address> excludedAddrs;
-        private long dhcpLeaseTimeSecs;
-        private int linkMtu = MTU_UNSET;
-        private boolean metered;
-
-        /**
-         * Set the server address and served prefix for the DHCP server.
-         *
-         * <p>This parameter is required.
-         */
-        public Builder setServerAddr(@NonNull LinkAddress serverAddr) {
-            this.serverAddr = serverAddr;
-            return this;
-        }
-
-        /**
-         * Set the default routers to be advertised to DHCP clients.
-         *
-         * <p>Each router must be inside the served prefix. This may be an empty set, but it must
-         * always be set explicitly before building the {@link DhcpServingParams}.
-         */
-        public Builder setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) {
-            this.defaultRouters = defaultRouters;
-            return this;
-        }
-
-        /**
-         * Set the default routers to be advertised to DHCP clients.
-         *
-         * <p>Each router must be inside the served prefix. This may be an empty list of routers,
-         * but it must always be set explicitly before building the {@link DhcpServingParams}.
-         */
-        public Builder setDefaultRouters(@NonNull Inet4Address... defaultRouters) {
-            return setDefaultRouters(Sets.newArraySet(defaultRouters));
-        }
-
-        /**
-         * Convenience method to build the parameters with no default router.
-         *
-         * <p>Equivalent to calling {@link #setDefaultRouters(Inet4Address...)} with no address.
-         */
-        public Builder withNoDefaultRouter() {
-            return setDefaultRouters();
-        }
-
-        /**
-         * Set the DNS servers to be advertised to DHCP clients.
-         *
-         * <p>This may be an empty set, but it must always be set explicitly before building the
-         * {@link DhcpServingParams}.
-         */
-        public Builder setDnsServers(@NonNull Set<Inet4Address> dnsServers) {
-            this.dnsServers = dnsServers;
-            return this;
-        }
-
-        /**
-         * Set the DNS servers to be advertised to DHCP clients.
-         *
-         * <p>This may be an empty list of servers, but it must always be set explicitly before
-         * building the {@link DhcpServingParams}.
-         */
-        public Builder setDnsServers(@NonNull Inet4Address... dnsServers) {
-            return setDnsServers(Sets.newArraySet(dnsServers));
-        }
-
-        /**
-         * Convenience method to build the parameters with no DNS server.
-         *
-         * <p>Equivalent to calling {@link #setDnsServers(Inet4Address...)} with no address.
-         */
-        public Builder withNoDnsServer() {
-            return setDnsServers();
-        }
-
-        /**
-         * Set excluded addresses that the DHCP server is not allowed to assign to clients.
-         *
-         * <p>This parameter is optional. DNS servers and default routers are always excluded
-         * and do not need to be set here.
-         */
-        public Builder setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) {
-            this.excludedAddrs = excludedAddrs;
-            return this;
-        }
-
-        /**
-         * Set excluded addresses that the DHCP server is not allowed to assign to clients.
-         *
-         * <p>This parameter is optional. DNS servers and default routers are always excluded
-         * and do not need to be set here.
-         */
-        public Builder setExcludedAddrs(@NonNull Inet4Address... excludedAddrs) {
-            return setExcludedAddrs(Sets.newArraySet(excludedAddrs));
-        }
-
-        /**
-         * Set the lease time for leases assigned by the DHCP server.
-         *
-         * <p>This parameter is required.
-         */
-        public Builder setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) {
-            this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
-            return this;
-        }
-
-        /**
-         * Set the link MTU to be advertised to DHCP clients.
-         *
-         * <p>If set to {@link #MTU_UNSET}, no MTU will be advertised to clients. This parameter
-         * is optional and defaults to {@link #MTU_UNSET}.
-         */
-        public Builder setLinkMtu(int linkMtu) {
-            this.linkMtu = linkMtu;
-            return this;
-        }
-
-        /**
-         * Set whether the DHCP server should send the ANDROID_METERED vendor-specific option.
-         *
-         * <p>If not set, the default value is false.
-         */
-        public Builder setMetered(boolean metered) {
-            this.metered = metered;
-            return this;
-        }
-
-        /**
-         * Create a new {@link DhcpServingParams} instance based on parameters set in the builder.
-         *
-         * <p>This method has no side-effects. If it does not throw, a valid
-         * {@link DhcpServingParams} is returned.
-         * @return The constructed parameters.
-         * @throws InvalidParameterException At least one parameter is missing or invalid.
-         */
-        @NonNull
-        public DhcpServingParams build() throws InvalidParameterException {
-            if (serverAddr == null) {
-                throw new InvalidParameterException("Missing serverAddr");
-            }
-            if (defaultRouters == null) {
-                throw new InvalidParameterException("Missing defaultRouters");
-            }
-            if (dnsServers == null) {
-                // Empty set is OK, but enforce explicitly setting it
-                throw new InvalidParameterException("Missing dnsServers");
-            }
-            if (dhcpLeaseTimeSecs <= 0 || dhcpLeaseTimeSecs > toUnsignedLong(INFINITE_LEASE)) {
-                throw new InvalidParameterException("Invalid lease time: " + dhcpLeaseTimeSecs);
-            }
-            if (linkMtu != MTU_UNSET && (linkMtu < IPV4_MIN_MTU || linkMtu > IPV4_MAX_MTU)) {
-                throw new InvalidParameterException("Invalid link MTU: " + linkMtu);
-            }
-            if (!serverAddr.isIPv4()) {
-                throw new InvalidParameterException("serverAddr must be IPv4");
-            }
-            if (serverAddr.getPrefixLength() < MIN_PREFIX_LENGTH
-                    || serverAddr.getPrefixLength() > MAX_PREFIX_LENGTH) {
-                throw new InvalidParameterException("Prefix length is not in supported range");
-            }
-
-            final IpPrefix prefix = makeIpPrefix(serverAddr);
-            for (Inet4Address addr : defaultRouters) {
-                if (!prefix.contains(addr)) {
-                    throw new InvalidParameterException(String.format(
-                            "Default router %s is not in server prefix %s", addr, serverAddr));
-                }
-            }
-
-            final Set<Inet4Address> excl = new HashSet<>();
-            if (excludedAddrs != null) {
-                excl.addAll(excludedAddrs);
-            }
-            excl.add((Inet4Address) serverAddr.getAddress());
-            excl.addAll(defaultRouters);
-            excl.addAll(dnsServers);
-
-            return new DhcpServingParams(serverAddr,
-                    Collections.unmodifiableSet(new HashSet<>(defaultRouters)),
-                    Collections.unmodifiableSet(new HashSet<>(dnsServers)),
-                    Collections.unmodifiableSet(excl),
-                    dhcpLeaseTimeSecs, linkMtu, metered);
-        }
-    }
-
-    @NonNull
-    static IpPrefix makeIpPrefix(@NonNull LinkAddress addr) {
-        return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
-    }
-}
diff --git a/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
new file mode 100644
index 0000000..f068c3a
--- /dev/null
+++ b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
@@ -0,0 +1,172 @@
+/*
+ * 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.dhcp;
+
+import static android.net.NetworkUtils.inet4AddressToIntHTH;
+
+import android.annotation.NonNull;
+import android.net.LinkAddress;
+
+import com.google.android.collect.Sets;
+
+import java.net.Inet4Address;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Subclass of {@link DhcpServingParamsParcel} with additional utility methods for building.
+ *
+ * <p>This utility class does not check for validity of the parameters: invalid parameters are
+ * reported by the receiving module when unparceling the parcel.
+ *
+ * @see DhcpServingParams
+ * @hide
+ */
+public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel {
+    public static final int MTU_UNSET = 0;
+
+    /**
+     * Set the server address and served prefix for the DHCP server.
+     *
+     * <p>This parameter is required.
+     */
+    public DhcpServingParamsParcelExt setServerAddr(@NonNull LinkAddress serverAddr) {
+        this.serverAddr = inet4AddressToIntHTH((Inet4Address) serverAddr.getAddress());
+        this.serverAddrPrefixLength = serverAddr.getPrefixLength();
+        return this;
+    }
+
+    /**
+     * Set the default routers to be advertised to DHCP clients.
+     *
+     * <p>Each router must be inside the served prefix. This may be an empty set, but it must
+     * always be set explicitly.
+     */
+    public DhcpServingParamsParcelExt setDefaultRouters(@NonNull Set<Inet4Address> defaultRouters) {
+        this.defaultRouters = toIntArray(defaultRouters);
+        return this;
+    }
+
+    /**
+     * Set the default routers to be advertised to DHCP clients.
+     *
+     * <p>Each router must be inside the served prefix. This may be an empty list of routers,
+     * but it must always be set explicitly.
+     */
+    public DhcpServingParamsParcelExt setDefaultRouters(@NonNull Inet4Address... defaultRouters) {
+        return setDefaultRouters(Sets.newArraySet(defaultRouters));
+    }
+
+    /**
+     * Convenience method to build the parameters with no default router.
+     *
+     * <p>Equivalent to calling {@link #setDefaultRouters(Inet4Address...)} with no address.
+     */
+    public DhcpServingParamsParcelExt setNoDefaultRouter() {
+        return setDefaultRouters();
+    }
+
+    /**
+     * Set the DNS servers to be advertised to DHCP clients.
+     *
+     * <p>This may be an empty set, but it must always be set explicitly.
+     */
+    public DhcpServingParamsParcelExt setDnsServers(@NonNull Set<Inet4Address> dnsServers) {
+        this.dnsServers = toIntArray(dnsServers);
+        return this;
+    }
+
+    /**
+     * Set the DNS servers to be advertised to DHCP clients.
+     *
+     * <p>This may be an empty list of servers, but it must always be set explicitly.
+     */
+    public DhcpServingParamsParcelExt setDnsServers(@NonNull Inet4Address... dnsServers) {
+        return setDnsServers(Sets.newArraySet(dnsServers));
+    }
+
+    /**
+     * Convenience method to build the parameters with no DNS server.
+     *
+     * <p>Equivalent to calling {@link #setDnsServers(Inet4Address...)} with no address.
+     */
+    public DhcpServingParamsParcelExt setNoDnsServer() {
+        return setDnsServers();
+    }
+
+    /**
+     * Set excluded addresses that the DHCP server is not allowed to assign to clients.
+     *
+     * <p>This parameter is optional. DNS servers and default routers are always excluded
+     * and do not need to be set here.
+     */
+    public DhcpServingParamsParcelExt setExcludedAddrs(@NonNull Set<Inet4Address> excludedAddrs) {
+        this.excludedAddrs = toIntArray(excludedAddrs);
+        return this;
+    }
+
+    /**
+     * Set excluded addresses that the DHCP server is not allowed to assign to clients.
+     *
+     * <p>This parameter is optional. DNS servers and default routers are always excluded
+     * and do not need to be set here.
+     */
+    public DhcpServingParamsParcelExt setExcludedAddrs(@NonNull Inet4Address... excludedAddrs) {
+        return setExcludedAddrs(Sets.newArraySet(excludedAddrs));
+    }
+
+    /**
+     * Set the lease time for leases assigned by the DHCP server.
+     *
+     * <p>This parameter is required.
+     */
+    public DhcpServingParamsParcelExt setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) {
+        this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
+        return this;
+    }
+
+    /**
+     * Set the link MTU to be advertised to DHCP clients.
+     *
+     * <p>If set to {@link #MTU_UNSET}, no MTU will be advertised to clients. This parameter
+     * is optional and defaults to {@link #MTU_UNSET}.
+     */
+    public DhcpServingParamsParcelExt setLinkMtu(int linkMtu) {
+        this.linkMtu = linkMtu;
+        return this;
+    }
+
+    /**
+     * Set whether the DHCP server should send the ANDROID_METERED vendor-specific option.
+     *
+     * <p>If not set, the default value is false.
+     */
+    public DhcpServingParamsParcelExt setMetered(boolean metered) {
+        this.metered = metered;
+        return this;
+    }
+
+    private static int[] toIntArray(@NonNull Collection<Inet4Address> addrs) {
+        int[] res = new int[addrs.size()];
+        int i = 0;
+        for (Inet4Address addr : addrs) {
+            res[i] = inet4AddressToIntHTH(addr);
+            i++;
+        }
+        return res;
+    }
+}
diff --git a/services/net/java/android/net/ip/ConnectivityPacketTracker.java b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
deleted file mode 100644
index e6ddbbc..0000000
--- a/services/net/java/android/net/ip/ConnectivityPacketTracker.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ip;
-
-import static android.system.OsConstants.*;
-
-import android.net.NetworkUtils;
-import android.net.util.PacketReader;
-import android.net.util.ConnectivityPacketSummary;
-import android.net.util.InterfaceParams;
-import android.os.Handler;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.PacketSocketAddress;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.LocalLog;
-
-import libcore.io.IoBridge;
-import libcore.util.HexEncoding;
-
-import java.io.FileDescriptor;
-import java.io.InterruptedIOException;
-import java.io.IOException;
-import java.net.SocketException;
-
-
-/**
- * Critical connectivity packet tracking daemon.
- *
- * Tracks ARP, DHCPv4, and IPv6 RS/RA/NS/NA packets.
- *
- * This class's constructor, start() and stop() methods must only be called
- * from the same thread on which the passed in |log| is accessed.
- *
- * Log lines include a hexdump of the packet, which can be decoded via:
- *
- *     echo -n H3XSTR1NG | sed -e 's/\([0-9A-F][0-9A-F]\)/\1 /g' -e 's/^/000000 /'
- *                       | text2pcap - -
- *                       | tcpdump -n -vv -e -r -
- *
- * @hide
- */
-public class ConnectivityPacketTracker {
-    private static final String TAG = ConnectivityPacketTracker.class.getSimpleName();
-    private static final boolean DBG = false;
-    private static final String MARK_START = "--- START ---";
-    private static final String MARK_STOP = "--- STOP ---";
-    private static final String MARK_NAMED_START = "--- START (%s) ---";
-    private static final String MARK_NAMED_STOP = "--- STOP (%s) ---";
-
-    private final String mTag;
-    private final LocalLog mLog;
-    private final PacketReader mPacketListener;
-    private boolean mRunning;
-    private String mDisplayName;
-
-    public ConnectivityPacketTracker(Handler h, InterfaceParams ifParams, LocalLog log) {
-        if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams");
-
-        mTag = TAG + "." + ifParams.name;
-        mLog = log;
-        mPacketListener = new PacketListener(h, ifParams);
-    }
-
-    public void start(String displayName) {
-        mRunning = true;
-        mDisplayName = displayName;
-        mPacketListener.start();
-    }
-
-    public void stop() {
-        mPacketListener.stop();
-        mRunning = false;
-        mDisplayName = null;
-    }
-
-    private final class PacketListener extends PacketReader {
-        private final InterfaceParams mInterface;
-
-        PacketListener(Handler h, InterfaceParams ifParams) {
-            super(h, ifParams.defaultMtu);
-            mInterface = ifParams;
-        }
-
-        @Override
-        protected FileDescriptor createFd() {
-            FileDescriptor s = null;
-            try {
-                s = Os.socket(AF_PACKET, SOCK_RAW, 0);
-                NetworkUtils.attachControlPacketFilter(s, ARPHRD_ETHER);
-                Os.bind(s, new PacketSocketAddress((short) ETH_P_ALL, mInterface.index));
-            } catch (ErrnoException | IOException e) {
-                logError("Failed to create packet tracking socket: ", e);
-                closeFd(s);
-                return null;
-            }
-            return s;
-        }
-
-        @Override
-        protected void handlePacket(byte[] recvbuf, int length) {
-            final String summary = ConnectivityPacketSummary.summarize(
-                    mInterface.macAddr, recvbuf, length);
-            if (summary == null) return;
-
-            if (DBG) Log.d(mTag, summary);
-            addLogEntry(summary +
-                        "\n[" + new String(HexEncoding.encode(recvbuf, 0, length)) + "]");
-        }
-
-        @Override
-        protected void onStart() {
-            final String msg = TextUtils.isEmpty(mDisplayName)
-                    ? MARK_START
-                    : String.format(MARK_NAMED_START, mDisplayName);
-            mLog.log(msg);
-        }
-
-        @Override
-        protected void onStop() {
-            String msg = TextUtils.isEmpty(mDisplayName)
-                    ? MARK_STOP
-                    : String.format(MARK_NAMED_STOP, mDisplayName);
-            if (!mRunning) msg += " (packet listener stopped unexpectedly)";
-            mLog.log(msg);
-        }
-
-        @Override
-        protected void logError(String msg, Exception e) {
-            Log.e(mTag, msg, e);
-            addLogEntry(msg + e);
-        }
-
-        private void addLogEntry(String entry) {
-            mLog.log(entry);
-        }
-    }
-}
diff --git a/services/net/java/android/net/ip/InterfaceController.java b/services/net/java/android/net/ip/InterfaceController.java
index 02e4f87..b3af67c 100644
--- a/services/net/java/android/net/ip/InterfaceController.java
+++ b/services/net/java/android/net/ip/InterfaceController.java
@@ -18,14 +18,14 @@
 
 import android.net.INetd;
 import android.net.InterfaceConfiguration;
+import android.net.InterfaceConfigurationParcel;
 import android.net.LinkAddress;
-import android.net.util.NetdService;
 import android.net.util.SharedLog;
-import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.system.OsConstants;
 
+import java.net.Inet4Address;
 import java.net.InetAddress;
 
 
@@ -40,76 +40,96 @@
     private final static boolean DBG = false;
 
     private final String mIfName;
-    private final INetworkManagementService mNMS;
     private final INetd mNetd;
     private final SharedLog mLog;
 
-    public InterfaceController(String ifname, INetworkManagementService nms, INetd netd,
-            SharedLog log) {
+    public InterfaceController(String ifname, INetd netd, SharedLog log) {
         mIfName = ifname;
-        mNMS = nms;
         mNetd = netd;
         mLog = log;
     }
 
+    private boolean setInterfaceConfig(InterfaceConfiguration config) {
+        final InterfaceConfigurationParcel cfgParcel = config.toParcel(mIfName);
+
+        try {
+            mNetd.interfaceSetCfg(cfgParcel);
+        } catch (RemoteException | ServiceSpecificException e) {
+            logError("Setting IPv4 address to %s/%d failed: %s",
+                    cfgParcel.ipv4Addr, cfgParcel.prefixLength, e);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Set the IPv4 address of the interface.
+     */
     public boolean setIPv4Address(LinkAddress address) {
-        final InterfaceConfiguration ifcg = new InterfaceConfiguration();
-        ifcg.setLinkAddress(address);
-        try {
-            mNMS.setInterfaceConfig(mIfName, ifcg);
-            if (DBG) mLog.log("IPv4 configuration succeeded");
-        } catch (IllegalStateException | RemoteException e) {
-            logError("IPv4 configuration failed: %s", e);
+        if (!(address.getAddress() instanceof Inet4Address)) {
             return false;
         }
-        return true;
+        final InterfaceConfiguration ifConfig = new InterfaceConfiguration();
+        ifConfig.setLinkAddress(address);
+        return setInterfaceConfig(ifConfig);
     }
 
+    /**
+     * Clear the IPv4Address of the interface.
+     */
     public boolean clearIPv4Address() {
+        final InterfaceConfiguration ifConfig = new InterfaceConfiguration();
+        ifConfig.setLinkAddress(new LinkAddress("0.0.0.0/0"));
+        return setInterfaceConfig(ifConfig);
+    }
+
+    private boolean setEnableIPv6(boolean enabled) {
         try {
-            final InterfaceConfiguration ifcg = new InterfaceConfiguration();
-            ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0"));
-            mNMS.setInterfaceConfig(mIfName, ifcg);
-        } catch (IllegalStateException | RemoteException e) {
-            logError("Failed to clear IPv4 address on interface %s: %s", mIfName, e);
+            mNetd.interfaceSetEnableIPv6(mIfName, enabled);
+        } catch (RemoteException | ServiceSpecificException e) {
+            logError("%s IPv6 failed: %s", (enabled ? "enabling" : "disabling"), e);
             return false;
         }
         return true;
     }
 
+    /**
+     * Enable IPv6 on the interface.
+     */
     public boolean enableIPv6() {
-        try {
-            mNMS.enableIpv6(mIfName);
-        } catch (IllegalStateException | RemoteException e) {
-            logError("enabling IPv6 failed: %s", e);
-            return false;
-        }
-        return true;
+        return setEnableIPv6(true);
     }
 
+    /**
+     * Disable IPv6 on the interface.
+     */
     public boolean disableIPv6() {
-        try {
-            mNMS.disableIpv6(mIfName);
-        } catch (IllegalStateException | RemoteException e) {
-            logError("disabling IPv6 failed: %s", e);
-            return false;
-        }
-        return true;
+        return setEnableIPv6(false);
     }
 
+    /**
+     * Enable or disable IPv6 privacy extensions on the interface.
+     * @param enabled Whether the extensions should be enabled.
+     */
     public boolean setIPv6PrivacyExtensions(boolean enabled) {
         try {
-            mNMS.setInterfaceIpv6PrivacyExtensions(mIfName, enabled);
-        } catch (IllegalStateException | RemoteException e) {
-            logError("error setting IPv6 privacy extensions: %s", e);
+            mNetd.interfaceSetIPv6PrivacyExtensions(mIfName, enabled);
+        } catch (RemoteException | ServiceSpecificException e) {
+            logError("error %s IPv6 privacy extensions: %s",
+                    (enabled ? "enabling" : "disabling"), e);
             return false;
         }
         return true;
     }
 
+    /**
+     * Set IPv6 address generation mode on the interface.
+     *
+     * <p>IPv6 should be disabled before changing the mode.
+     */
     public boolean setIPv6AddrGenModeIfSupported(int mode) {
         try {
-            mNMS.setIPv6AddrGenMode(mIfName, mode);
+            mNetd.setIPv6AddrGenMode(mIfName, mode);
         } catch (RemoteException e) {
             logError("Unable to set IPv6 addrgen mode: %s", e);
             return false;
@@ -122,10 +142,16 @@
         return true;
     }
 
+    /**
+     * Add an address to the interface.
+     */
     public boolean addAddress(LinkAddress addr) {
         return addAddress(addr.getAddress(), addr.getPrefixLength());
     }
 
+    /**
+     * Add an address to the interface.
+     */
     public boolean addAddress(InetAddress ip, int prefixLen) {
         try {
             mNetd.interfaceAddAddress(mIfName, ip.getHostAddress(), prefixLen);
@@ -136,6 +162,9 @@
         return true;
     }
 
+    /**
+     * Remove an address from the interface.
+     */
     public boolean removeAddress(InetAddress ip, int prefixLen) {
         try {
             mNetd.interfaceDelAddress(mIfName, ip.getHostAddress(), prefixLen);
@@ -146,9 +175,12 @@
         return true;
     }
 
+    /**
+     * Remove all addresses from the interface.
+     */
     public boolean clearAllAddresses() {
         try {
-            mNMS.clearInterfaceAddresses(mIfName);
+            mNetd.interfaceClearAddrs(mIfName);
         } catch (Exception e) {
             logError("Failed to clear addresses: %s", e);
             return false;
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 0176dd4..a61c2ef 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,184 +16,53 @@
 
 package android.net.ip;
 
-import com.android.internal.util.HexDump;
-import com.android.internal.util.MessageUtils;
-import com.android.internal.util.WakeupMessage;
+import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable;
 
 import android.content.Context;
-import android.net.DhcpResults;
-import android.net.INetd;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties.ProvisioningChange;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.ProxyInfo;
-import android.net.RouteInfo;
 import android.net.StaticIpConfiguration;
 import android.net.apf.ApfCapabilities;
-import android.net.apf.ApfFilter;
-import android.net.dhcp.DhcpClient;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.IpManagerEvent;
-import android.net.util.InterfaceParams;
-import android.net.util.MultinetworkPolicyTracker;
-import android.net.util.NetdService;
-import android.net.util.NetworkConstants;
-import android.net.util.SharedLog;
 import android.os.ConditionVariable;
 import android.os.INetworkManagementService;
-import android.os.Message;
 import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import android.util.LocalLog;
 import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.R;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.IState;
-import com.android.internal.util.Preconditions;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-import com.android.server.net.NetlinkTracker;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.SocketException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.List;
-import java.util.Set;
-import java.util.StringJoiner;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-
 
 /**
- * IpClient
- *
- * This class provides the interface to IP-layer provisioning and maintenance
- * functionality that can be used by transport layers like Wi-Fi, Ethernet,
- * et cetera.
- *
- * [ Lifetime ]
- * IpClient is designed to be instantiated as soon as the interface name is
- * known and can be as long-lived as the class containing it (i.e. declaring
- * it "private final" is okay).
- *
+ * Proxy for the IpClient in the NetworkStack. To be removed once clients are migrated.
  * @hide
  */
-public class IpClient extends StateMachine {
-    private static final boolean DBG = false;
+public class IpClient {
+    private static final String TAG = IpClient.class.getSimpleName();
+    private static final int IPCLIENT_BLOCK_TIMEOUT_MS = 10_000;
 
-    // For message logging.
-    private static final Class[] sMessageClasses = { IpClient.class, DhcpClient.class };
-    private static final SparseArray<String> sWhatToString =
-            MessageUtils.findMessageNames(sMessageClasses);
-    // Two static concurrent hashmaps of interface name to logging classes.
-    // One holds StateMachine logs and the other connectivity packet logs.
-    private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>();
-    private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>();
+    public static final String DUMP_ARG = "ipclient";
 
-    // If |args| is non-empty, assume it's a list of interface names for which
-    // we should print IpClient logs (filter out all others).
-    public static void dumpAllLogs(PrintWriter writer, String[] args) {
-        for (String ifname : sSmLogs.keySet()) {
-            if (!ArrayUtils.isEmpty(args) && !ArrayUtils.contains(args, ifname)) continue;
+    private final ConditionVariable mIpClientCv;
+    private final ConditionVariable mShutdownCv;
 
-            writer.println(String.format("--- BEGIN %s ---", ifname));
-
-            final SharedLog smLog = sSmLogs.get(ifname);
-            if (smLog != null) {
-                writer.println("State machine log:");
-                smLog.dump(null, writer, null);
-            }
-
-            writer.println("");
-
-            final LocalLog pktLog = sPktLogs.get(ifname);
-            if (pktLog != null) {
-                writer.println("Connectivity packet log:");
-                pktLog.readOnlyLocalLog().dump(null, writer, null);
-            }
-
-            writer.println(String.format("--- END %s ---", ifname));
-        }
-    }
+    private volatile IIpClient mIpClient;
 
     /**
-     * Callbacks for handling IpClient events.
-     *
-     * These methods are called by IpClient on its own thread. Implementations
-     * of this class MUST NOT carry out long-running computations or hold locks
-     * for which there might be contention with other code calling public
-     * methods of the same IpClient instance.
+     * @see IpClientCallbacks
      */
-    public static class Callback {
-        // In order to receive onPreDhcpAction(), call #withPreDhcpAction()
-        // when constructing a ProvisioningConfiguration.
-        //
-        // Implementations of onPreDhcpAction() must call
-        // IpClient#completedPreDhcpAction() to indicate that DHCP is clear
-        // to proceed.
-        public void onPreDhcpAction() {}
-        public void onPostDhcpAction() {}
+    public static class Callback extends IpClientCallbacks {}
 
-        // This is purely advisory and not an indication of provisioning
-        // success or failure.  This is only here for callers that want to
-        // expose DHCPv4 results to other APIs (e.g., WifiInfo#setInetAddress).
-        // DHCPv4 or static IPv4 configuration failure or success can be
-        // determined by whether or not the passed-in DhcpResults object is
-        // null or not.
-        public void onNewDhcpResults(DhcpResults dhcpResults) {}
-
-        public void onProvisioningSuccess(LinkProperties newLp) {}
-        public void onProvisioningFailure(LinkProperties newLp) {}
-
-        // Invoked on LinkProperties changes.
-        public void onLinkPropertiesChange(LinkProperties newLp) {}
-
-        // Called when the internal IpReachabilityMonitor (if enabled) has
-        // detected the loss of a critical number of required neighbors.
-        public void onReachabilityLost(String logMsg) {}
-
-        // Called when the IpClient state machine terminates.
-        public void onQuit() {}
-
-        // Install an APF program to filter incoming packets.
-        public void installPacketFilter(byte[] filter) {}
-
-        // Asynchronously read back the APF program & data buffer from the wifi driver.
-        // Due to Wifi HAL limitations, the current implementation only supports dumping the entire
-        // buffer. In response to this request, the driver returns the data buffer asynchronously
-        // by sending an IpClient#EVENT_READ_PACKET_FILTER_COMPLETE message.
-        public void startReadPacketFilter() {}
-
-        // If multicast filtering cannot be accomplished with APF, this function will be called to
-        // actuate multicast filtering using another means.
-        public void setFallbackMulticastFilter(boolean enabled) {}
-
-        // Enabled/disable Neighbor Discover offload functionality. This is
-        // called, for example, whenever 464xlat is being started or stopped.
-        public void setNeighborDiscoveryOffload(boolean enable) {}
-    }
-
+    /**
+     * IpClient callback that allows clients to block until provisioning is complete.
+     */
     public static class WaitForProvisioningCallback extends Callback {
         private final ConditionVariable mCV = new ConditionVariable();
         private LinkProperties mCallbackLinkProperties;
 
+        /**
+         * Block until either {@link #onProvisioningSuccess(LinkProperties)} or
+         * {@link #onProvisioningFailure(LinkProperties)} is called.
+         */
         public LinkProperties waitForProvisioning() {
             mCV.block();
             return mCallbackLinkProperties;
@@ -212,1720 +81,240 @@
         }
     }
 
-    // Use a wrapper class to log in order to ensure complete and detailed
-    // logging. This method is lighter weight than annotations/reflection
-    // and has the following benefits:
-    //
-    //     - No invoked method can be forgotten.
-    //       Any new method added to IpClient.Callback must be overridden
-    //       here or it will never be called.
-    //
-    //     - No invoking call site can be forgotten.
-    //       Centralized logging in this way means call sites don't need to
-    //       remember to log, and therefore no call site can be forgotten.
-    //
-    //     - No variation in log format among call sites.
-    //       Encourages logging of any available arguments, and all call sites
-    //       are necessarily logged identically.
-    //
-    // NOTE: Log first because passed objects may or may not be thread-safe and
-    // once passed on to the callback they may be modified by another thread.
-    //
-    // TODO: Find an lighter weight approach.
-    private class LoggingCallbackWrapper extends Callback {
-        private static final String PREFIX = "INVOKE ";
-        private final Callback mCallback;
-
-        public LoggingCallbackWrapper(Callback callback) {
-            mCallback = (callback != null) ? callback : new Callback();
-        }
-
-        private void log(String msg) {
-            mLog.log(PREFIX + msg);
+    private class CallbackImpl extends IpClientUtil.IpClientCallbacksProxy {
+        /**
+         * Create a new IpClientCallbacksProxy.
+         */
+        CallbackImpl(IpClientCallbacks cb) {
+            super(cb);
         }
 
         @Override
-        public void onPreDhcpAction() {
-            log("onPreDhcpAction()");
-            mCallback.onPreDhcpAction();
+        public void onIpClientCreated(IIpClient ipClient) {
+            mIpClient = ipClient;
+            mIpClientCv.open();
+            super.onIpClientCreated(ipClient);
         }
-        @Override
-        public void onPostDhcpAction() {
-            log("onPostDhcpAction()");
-            mCallback.onPostDhcpAction();
-        }
-        @Override
-        public void onNewDhcpResults(DhcpResults dhcpResults) {
-            log("onNewDhcpResults({" + dhcpResults + "})");
-            mCallback.onNewDhcpResults(dhcpResults);
-        }
-        @Override
-        public void onProvisioningSuccess(LinkProperties newLp) {
-            log("onProvisioningSuccess({" + newLp + "})");
-            mCallback.onProvisioningSuccess(newLp);
-        }
-        @Override
-        public void onProvisioningFailure(LinkProperties newLp) {
-            log("onProvisioningFailure({" + newLp + "})");
-            mCallback.onProvisioningFailure(newLp);
-        }
-        @Override
-        public void onLinkPropertiesChange(LinkProperties newLp) {
-            log("onLinkPropertiesChange({" + newLp + "})");
-            mCallback.onLinkPropertiesChange(newLp);
-        }
-        @Override
-        public void onReachabilityLost(String logMsg) {
-            log("onReachabilityLost(" + logMsg + ")");
-            mCallback.onReachabilityLost(logMsg);
-        }
+
         @Override
         public void onQuit() {
-            log("onQuit()");
-            mCallback.onQuit();
-        }
-        @Override
-        public void installPacketFilter(byte[] filter) {
-            log("installPacketFilter(byte[" + filter.length + "])");
-            mCallback.installPacketFilter(filter);
-        }
-        @Override
-        public void startReadPacketFilter() {
-            log("startReadPacketFilter()");
-            mCallback.startReadPacketFilter();
-        }
-        @Override
-        public void setFallbackMulticastFilter(boolean enabled) {
-            log("setFallbackMulticastFilter(" + enabled + ")");
-            mCallback.setFallbackMulticastFilter(enabled);
-        }
-        @Override
-        public void setNeighborDiscoveryOffload(boolean enable) {
-            log("setNeighborDiscoveryOffload(" + enable + ")");
-            mCallback.setNeighborDiscoveryOffload(enable);
+            mShutdownCv.open();
+            super.onQuit();
         }
     }
 
     /**
-     * This class encapsulates parameters to be passed to
-     * IpClient#startProvisioning(). A defensive copy is made by IpClient
-     * and the values specified herein are in force until IpClient#stop()
-     * is called.
-     *
-     * Example use:
-     *
-     *     final ProvisioningConfiguration config =
-     *             mIpClient.buildProvisioningConfiguration()
-     *                     .withPreDhcpAction()
-     *                     .withProvisioningTimeoutMs(36 * 1000)
-     *                     .build();
-     *     mIpClient.startProvisioning(config);
-     *     ...
-     *     mIpClient.stop();
-     *
-     * The specified provisioning configuration will only be active until
-     * IpClient#stop() is called. Future calls to IpClient#startProvisioning()
-     * must specify the configuration again.
+     * Create a new IpClient.
      */
-    public static class ProvisioningConfiguration {
-        // TODO: Delete this default timeout once those callers that care are
-        // fixed to pass in their preferred timeout.
-        //
-        // We pick 36 seconds so we can send DHCP requests at
-        //
-        //     t=0, t=2, t=6, t=14, t=30
-        //
-        // allowing for 10% jitter.
-        private static final int DEFAULT_TIMEOUT_MS = 36 * 1000;
+    public IpClient(Context context, String iface, Callback callback) {
+        mIpClientCv = new ConditionVariable(false);
+        mShutdownCv = new ConditionVariable(false);
 
-        public static class Builder {
-            private ProvisioningConfiguration mConfig = new ProvisioningConfiguration();
-
-            public Builder withoutIPv4() {
-                mConfig.mEnableIPv4 = false;
-                return this;
-            }
-
-            public Builder withoutIPv6() {
-                mConfig.mEnableIPv6 = false;
-                return this;
-            }
-
-            public Builder withoutMultinetworkPolicyTracker() {
-                mConfig.mUsingMultinetworkPolicyTracker = false;
-                return this;
-            }
-
-            public Builder withoutIpReachabilityMonitor() {
-                mConfig.mUsingIpReachabilityMonitor = false;
-                return this;
-            }
-
-            public Builder withPreDhcpAction() {
-                mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS;
-                return this;
-            }
-
-            public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
-                mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs;
-                return this;
-            }
-
-            public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
-                mConfig.mInitialConfig = initialConfig;
-                return this;
-            }
-
-            public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
-                mConfig.mStaticIpConfig = staticConfig;
-                return this;
-            }
-
-            public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
-                mConfig.mApfCapabilities = apfCapabilities;
-                return this;
-            }
-
-            public Builder withProvisioningTimeoutMs(int timeoutMs) {
-                mConfig.mProvisioningTimeoutMs = timeoutMs;
-                return this;
-            }
-
-            public Builder withRandomMacAddress() {
-                mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64;
-                return this;
-            }
-
-            public Builder withStableMacAddress() {
-                mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
-                return this;
-            }
-
-            public Builder withNetwork(Network network) {
-                mConfig.mNetwork = network;
-                return this;
-            }
-
-            public Builder withDisplayName(String displayName) {
-                mConfig.mDisplayName = displayName;
-                return this;
-            }
-
-            public ProvisioningConfiguration build() {
-                return new ProvisioningConfiguration(mConfig);
-            }
-        }
-
-        /* package */ boolean mEnableIPv4 = true;
-        /* package */ boolean mEnableIPv6 = true;
-        /* package */ boolean mUsingMultinetworkPolicyTracker = true;
-        /* package */ boolean mUsingIpReachabilityMonitor = true;
-        /* package */ int mRequestedPreDhcpActionMs;
-        /* package */ InitialConfiguration mInitialConfig;
-        /* package */ StaticIpConfiguration mStaticIpConfig;
-        /* package */ ApfCapabilities mApfCapabilities;
-        /* package */ int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
-        /* package */ int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
-        /* package */ Network mNetwork = null;
-        /* package */ String mDisplayName = null;
-
-        public ProvisioningConfiguration() {} // used by Builder
-
-        public ProvisioningConfiguration(ProvisioningConfiguration other) {
-            mEnableIPv4 = other.mEnableIPv4;
-            mEnableIPv6 = other.mEnableIPv6;
-            mUsingMultinetworkPolicyTracker = other.mUsingMultinetworkPolicyTracker;
-            mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
-            mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
-            mInitialConfig = InitialConfiguration.copy(other.mInitialConfig);
-            mStaticIpConfig = other.mStaticIpConfig;
-            mApfCapabilities = other.mApfCapabilities;
-            mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
-            mIPv6AddrGenMode = other.mIPv6AddrGenMode;
-            mNetwork = other.mNetwork;
-            mDisplayName = other.mDisplayName;
-        }
-
-        @Override
-        public String toString() {
-            return new StringJoiner(", ", getClass().getSimpleName() + "{", "}")
-                    .add("mEnableIPv4: " + mEnableIPv4)
-                    .add("mEnableIPv6: " + mEnableIPv6)
-                    .add("mUsingMultinetworkPolicyTracker: " + mUsingMultinetworkPolicyTracker)
-                    .add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
-                    .add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
-                    .add("mInitialConfig: " + mInitialConfig)
-                    .add("mStaticIpConfig: " + mStaticIpConfig)
-                    .add("mApfCapabilities: " + mApfCapabilities)
-                    .add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
-                    .add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
-                    .add("mNetwork: " + mNetwork)
-                    .add("mDisplayName: " + mDisplayName)
-                    .toString();
-        }
-
-        public boolean isValid() {
-            return (mInitialConfig == null) || mInitialConfig.isValid();
-        }
-    }
-
-    public static class InitialConfiguration {
-        public final Set<LinkAddress> ipAddresses = new HashSet<>();
-        public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>();
-        public final Set<InetAddress> dnsServers = new HashSet<>();
-        public Inet4Address gateway; // WiFi legacy behavior with static ipv4 config
-
-        public static InitialConfiguration copy(InitialConfiguration config) {
-            if (config == null) {
-                return null;
-            }
-            InitialConfiguration configCopy = new InitialConfiguration();
-            configCopy.ipAddresses.addAll(config.ipAddresses);
-            configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes);
-            configCopy.dnsServers.addAll(config.dnsServers);
-            return configCopy;
-        }
-
-        @Override
-        public String toString() {
-            return String.format(
-                    "InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s}, v4 gateway: %s)",
-                    join(", ", ipAddresses), join(", ", directlyConnectedRoutes),
-                    join(", ", dnsServers), gateway);
-        }
-
-        public boolean isValid() {
-            if (ipAddresses.isEmpty()) {
-                return false;
-            }
-
-            // For every IP address, there must be at least one prefix containing that address.
-            for (LinkAddress addr : ipAddresses) {
-                if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) {
-                    return false;
-                }
-            }
-            // For every dns server, there must be at least one prefix containing that address.
-            for (InetAddress addr : dnsServers) {
-                if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) {
-                    return false;
-                }
-            }
-            // All IPv6 LinkAddresses have an RFC7421-suitable prefix length
-            // (read: compliant with RFC4291#section2.5.4).
-            if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) {
-                return false;
-            }
-            // If directlyConnectedRoutes contains an IPv6 default route
-            // then ipAddresses MUST contain at least one non-ULA GUA.
-            if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute)
-                    && all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) {
-                return false;
-            }
-            // The prefix length of routes in directlyConnectedRoutes be within reasonable
-            // bounds for IPv6: /48-/64 just as we’d accept in RIOs.
-            if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) {
-                return false;
-            }
-            // There no more than one IPv4 address
-            if (ipAddresses.stream().filter(LinkAddress::isIPv4).count() > 1) {
-                return false;
-            }
-
-            return true;
-        }
-
-        /**
-         * @return true if the given list of addressess and routes satisfies provisioning for this
-         * InitialConfiguration. LinkAddresses and RouteInfo objects are not compared with equality
-         * because addresses and routes seen by Netlink will contain additional fields like flags,
-         * interfaces, and so on. If this InitialConfiguration has no IP address specified, the
-         * provisioning check always fails.
-         *
-         * If the given list of routes is null, only addresses are taken into considerations.
-         */
-        public boolean isProvisionedBy(List<LinkAddress> addresses, List<RouteInfo> routes) {
-            if (ipAddresses.isEmpty()) {
-                return false;
-            }
-
-            for (LinkAddress addr : ipAddresses) {
-                if (!any(addresses, (addrSeen) -> addr.isSameAddressAs(addrSeen))) {
-                    return false;
-                }
-            }
-
-            if (routes != null) {
-                for (IpPrefix prefix : directlyConnectedRoutes) {
-                    if (!any(routes, (routeSeen) -> isDirectlyConnectedRoute(routeSeen, prefix))) {
-                        return false;
-                    }
-                }
-            }
-
-            return true;
-        }
-
-        private static boolean isDirectlyConnectedRoute(RouteInfo route, IpPrefix prefix) {
-            return !route.hasGateway() && prefix.equals(route.getDestination());
-        }
-
-        private static boolean isPrefixLengthCompliant(LinkAddress addr) {
-            return addr.isIPv4() || isCompliantIPv6PrefixLength(addr.getPrefixLength());
-        }
-
-        private static boolean isPrefixLengthCompliant(IpPrefix prefix) {
-            return prefix.isIPv4() || isCompliantIPv6PrefixLength(prefix.getPrefixLength());
-        }
-
-        private static boolean isCompliantIPv6PrefixLength(int prefixLength) {
-            return (NetworkConstants.RFC6177_MIN_PREFIX_LENGTH <= prefixLength)
-                    && (prefixLength <= NetworkConstants.RFC7421_PREFIX_LENGTH);
-        }
-
-        private static boolean isIPv6DefaultRoute(IpPrefix prefix) {
-            return prefix.getAddress().equals(Inet6Address.ANY);
-        }
-
-        private static boolean isIPv6GUA(LinkAddress addr) {
-            return addr.isIPv6() && addr.isGlobalPreferred();
-        }
-    }
-
-    public static final String DUMP_ARG = "ipclient";
-    public static final String DUMP_ARG_CONFIRM = "confirm";
-
-    private static final int CMD_TERMINATE_AFTER_STOP             = 1;
-    private static final int CMD_STOP                             = 2;
-    private static final int CMD_START                            = 3;
-    private static final int CMD_CONFIRM                          = 4;
-    private static final int EVENT_PRE_DHCP_ACTION_COMPLETE       = 5;
-    // Sent by NetlinkTracker to communicate netlink events.
-    private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 6;
-    private static final int CMD_UPDATE_TCP_BUFFER_SIZES          = 7;
-    private static final int CMD_UPDATE_HTTP_PROXY                = 8;
-    private static final int CMD_SET_MULTICAST_FILTER             = 9;
-    private static final int EVENT_PROVISIONING_TIMEOUT           = 10;
-    private static final int EVENT_DHCPACTION_TIMEOUT             = 11;
-    private static final int EVENT_READ_PACKET_FILTER_COMPLETE    = 12;
-
-    // Internal commands to use instead of trying to call transitionTo() inside
-    // a given State's enter() method. Calling transitionTo() from enter/exit
-    // encounters a Log.wtf() that can cause trouble on eng builds.
-    private static final int CMD_JUMP_STARTED_TO_RUNNING          = 100;
-    private static final int CMD_JUMP_RUNNING_TO_STOPPING         = 101;
-    private static final int CMD_JUMP_STOPPING_TO_STOPPED         = 102;
-
-    private static final int MAX_LOG_RECORDS = 500;
-    private static final int MAX_PACKET_RECORDS = 100;
-
-    private static final boolean NO_CALLBACKS = false;
-    private static final boolean SEND_CALLBACKS = true;
-
-    // This must match the interface prefix in clatd.c.
-    // TODO: Revert this hack once IpClient and Nat464Xlat work in concert.
-    private static final String CLAT_PREFIX = "v4-";
-
-    private static final int IMMEDIATE_FAILURE_DURATION = 0;
-
-    private final State mStoppedState = new StoppedState();
-    private final State mStoppingState = new StoppingState();
-    private final State mStartedState = new StartedState();
-    private final State mRunningState = new RunningState();
-
-    private final String mTag;
-    private final Context mContext;
-    private final String mInterfaceName;
-    private final String mClatInterfaceName;
-    @VisibleForTesting
-    protected final Callback mCallback;
-    private final Dependencies mDependencies;
-    private final CountDownLatch mShutdownLatch;
-    private final INetworkManagementService mNwService;
-    private final NetlinkTracker mNetlinkTracker;
-    private final WakeupMessage mProvisioningTimeoutAlarm;
-    private final WakeupMessage mDhcpActionTimeoutAlarm;
-    private final SharedLog mLog;
-    private final LocalLog mConnectivityPacketLog;
-    private final MessageHandlingLogger mMsgStateLogger;
-    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
-    private final InterfaceController mInterfaceCtrl;
-
-    private InterfaceParams mInterfaceParams;
-
-    /**
-     * Non-final member variables accessed only from within our StateMachine.
-     */
-    private LinkProperties mLinkProperties;
-    private ProvisioningConfiguration mConfiguration;
-    private MultinetworkPolicyTracker mMultinetworkPolicyTracker;
-    private IpReachabilityMonitor mIpReachabilityMonitor;
-    private DhcpClient mDhcpClient;
-    private DhcpResults mDhcpResults;
-    private String mTcpBufferSizes;
-    private ProxyInfo mHttpProxy;
-    private ApfFilter mApfFilter;
-    private boolean mMulticastFiltering;
-    private long mStartTimeMillis;
-
-    /**
-     * Reading the snapshot is an asynchronous operation initiated by invoking
-     * Callback.startReadPacketFilter() and completed when the WiFi Service responds with an
-     * EVENT_READ_PACKET_FILTER_COMPLETE message. The mApfDataSnapshotComplete condition variable
-     * signals when a new snapshot is ready.
-     */
-    private final ConditionVariable mApfDataSnapshotComplete = new ConditionVariable();
-
-    public static class Dependencies {
-        public INetworkManagementService getNMS() {
-            return INetworkManagementService.Stub.asInterface(
-                    ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
-        }
-
-        public INetd getNetd() {
-            return NetdService.getInstance();
-        }
-
-        public InterfaceParams getInterfaceParams(String ifname) {
-            return InterfaceParams.getByName(ifname);
-        }
-    }
-
-    public IpClient(Context context, String ifName, Callback callback) {
-        this(context, ifName, callback, new Dependencies());
+        IpClientUtil.makeIpClient(context, iface, new CallbackImpl(callback));
     }
 
     /**
-     * An expanded constructor, useful for dependency injection.
-     * TODO: migrate all test users to mock IpClient directly and remove this ctor.
+     * @see IpClient#IpClient(Context, String, IpClient.Callback)
      */
-    public IpClient(Context context, String ifName, Callback callback,
-            INetworkManagementService nwService) {
-        this(context, ifName, callback, new Dependencies() {
-            @Override
-            public INetworkManagementService getNMS() { return nwService; }
-        });
+    public IpClient(Context context, String iface, Callback callback,
+            INetworkManagementService nms) {
+        this(context, iface, callback);
     }
 
-    @VisibleForTesting
-    IpClient(Context context, String ifName, Callback callback, Dependencies deps) {
-        super(IpClient.class.getSimpleName() + "." + ifName);
-        Preconditions.checkNotNull(ifName);
-        Preconditions.checkNotNull(callback);
-
-        mTag = getName();
-
-        mContext = context;
-        mInterfaceName = ifName;
-        mClatInterfaceName = CLAT_PREFIX + ifName;
-        mCallback = new LoggingCallbackWrapper(callback);
-        mDependencies = deps;
-        mShutdownLatch = new CountDownLatch(1);
-        mNwService = deps.getNMS();
-
-        sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
-        mLog = sSmLogs.get(mInterfaceName);
-        sPktLogs.putIfAbsent(mInterfaceName, new LocalLog(MAX_PACKET_RECORDS));
-        mConnectivityPacketLog = sPktLogs.get(mInterfaceName);
-        mMsgStateLogger = new MessageHandlingLogger();
-
-        // TODO: Consider creating, constructing, and passing in some kind of
-        // InterfaceController.Dependencies class.
-        mInterfaceCtrl = new InterfaceController(mInterfaceName, mNwService, deps.getNetd(), mLog);
-
-        mNetlinkTracker = new NetlinkTracker(
-                mInterfaceName,
-                new NetlinkTracker.Callback() {
-                    @Override
-                    public void update() {
-                        sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED);
-                    }
-                }) {
-            @Override
-            public void interfaceAdded(String iface) {
-                super.interfaceAdded(iface);
-                if (mClatInterfaceName.equals(iface)) {
-                    mCallback.setNeighborDiscoveryOffload(false);
-                } else if (!mInterfaceName.equals(iface)) {
-                    return;
-                }
-
-                final String msg = "interfaceAdded(" + iface +")";
-                logMsg(msg);
-            }
-
-            @Override
-            public void interfaceRemoved(String iface) {
-                super.interfaceRemoved(iface);
-                // TODO: Also observe mInterfaceName going down and take some
-                // kind of appropriate action.
-                if (mClatInterfaceName.equals(iface)) {
-                    // TODO: consider sending a message to the IpClient main
-                    // StateMachine thread, in case "NDO enabled" state becomes
-                    // tied to more things that 464xlat operation.
-                    mCallback.setNeighborDiscoveryOffload(true);
-                } else if (!mInterfaceName.equals(iface)) {
-                    return;
-                }
-
-                final String msg = "interfaceRemoved(" + iface +")";
-                logMsg(msg);
-            }
-
-            private void logMsg(String msg) {
-                Log.d(mTag, msg);
-                getHandler().post(() -> { mLog.log("OBSERVED " + msg); });
-            }
-        };
-
-        mLinkProperties = new LinkProperties();
-        mLinkProperties.setInterfaceName(mInterfaceName);
-
-        mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
-                mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT);
-        mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
-                mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT);
-
-        // Anything the StateMachine may access must have been instantiated
-        // before this point.
-        configureAndStartStateMachine();
-
-        // Anything that may send messages to the StateMachine must only be
-        // configured to do so after the StateMachine has started (above).
-        startStateMachineUpdaters();
+    private interface IpClientAction {
+        void useIpClient(IIpClient ipClient) throws RemoteException;
     }
 
-    private void configureAndStartStateMachine() {
-        addState(mStoppedState);
-        addState(mStartedState);
-            addState(mRunningState, mStartedState);
-        addState(mStoppingState);
-
-        setInitialState(mStoppedState);
-
-        super.start();
-    }
-
-    private void startStateMachineUpdaters() {
+    private void doWithIpClient(IpClientAction action) {
+        mIpClientCv.block(IPCLIENT_BLOCK_TIMEOUT_MS);
         try {
-            mNwService.registerObserver(mNetlinkTracker);
+            action.useIpClient(mIpClient);
         } catch (RemoteException e) {
-            logError("Couldn't register NetlinkTracker: %s", e);
+            Log.e(TAG, "Error communicating with IpClient", e);
         }
     }
 
-    private void stopStateMachineUpdaters() {
-        try {
-            mNwService.unregisterObserver(mNetlinkTracker);
-        } catch (RemoteException e) {
-            logError("Couldn't unregister NetlinkTracker: %s", e);
-        }
+    /**
+     * Notify IpClient that PreDhcpAction is completed.
+     */
+    public void completedPreDhcpAction() {
+        doWithIpClient(c -> c.completedPreDhcpAction());
     }
 
-    @Override
-    protected void onQuitting() {
-        mCallback.onQuit();
-        mShutdownLatch.countDown();
+    /**
+     * Confirm the provisioning configuration.
+     */
+    public void confirmConfiguration() {
+        doWithIpClient(c -> c.confirmConfiguration());
     }
 
-    // Shut down this IpClient instance altogether.
+    /**
+     * Notify IpClient that packet filter read is complete.
+     */
+    public void readPacketFilterComplete(byte[] data) {
+        doWithIpClient(c -> c.readPacketFilterComplete(data));
+    }
+
+    /**
+     * Shutdown the IpClient altogether.
+     */
     public void shutdown() {
-        stop();
-        sendMessage(CMD_TERMINATE_AFTER_STOP);
+        doWithIpClient(c -> c.shutdown());
     }
 
-    // In order to avoid deadlock, this method MUST NOT be called on the
-    // IpClient instance's thread. This prohibition includes code executed by
-    // when methods on the passed-in IpClient.Callback instance are called.
+    /**
+     * Start the IpClient provisioning.
+     */
+    public void startProvisioning(ProvisioningConfiguration config) {
+        doWithIpClient(c -> c.startProvisioning(config.toStableParcelable()));
+    }
+
+    /**
+     * Stop the IpClient.
+     */
+    public void stop() {
+        doWithIpClient(c -> c.stop());
+    }
+
+    /**
+     * Set the IpClient TCP buffer sizes.
+     */
+    public void setTcpBufferSizes(String tcpBufferSizes) {
+        doWithIpClient(c -> c.setTcpBufferSizes(tcpBufferSizes));
+    }
+
+    /**
+     * Set the IpClient HTTP proxy.
+     */
+    public void setHttpProxy(ProxyInfo proxyInfo) {
+        doWithIpClient(c -> c.setHttpProxy(toStableParcelable(proxyInfo)));
+    }
+
+    /**
+     * Set the IpClient multicast filter.
+     */
+    public void setMulticastFilter(boolean enabled) {
+        doWithIpClient(c -> c.setMulticastFilter(enabled));
+    }
+
+    /**
+     * Dump IpClient logs.
+     */
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        doWithIpClient(c -> IpClientUtil.dumpIpClient(c, fd, pw, args));
+    }
+
+    /**
+     * Block until IpClient shutdown.
+     */
     public void awaitShutdown() {
-        try {
-            mShutdownLatch.await();
-        } catch (InterruptedException e) {
-            mLog.e("Interrupted while awaiting shutdown: " + e);
-        }
+        mShutdownCv.block(IPCLIENT_BLOCK_TIMEOUT_MS);
     }
 
+    /**
+     * Create a new ProvisioningConfiguration.
+     */
     public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() {
         return new ProvisioningConfiguration.Builder();
     }
 
-    public void startProvisioning(ProvisioningConfiguration req) {
-        if (!req.isValid()) {
-            doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
-            return;
-        }
-
-        mInterfaceParams = mDependencies.getInterfaceParams(mInterfaceName);
-        if (mInterfaceParams == null) {
-            logError("Failed to find InterfaceParams for " + mInterfaceName);
-            doImmediateProvisioningFailure(IpManagerEvent.ERROR_INTERFACE_NOT_FOUND);
-            return;
-        }
-
-        mCallback.setNeighborDiscoveryOffload(true);
-        sendMessage(CMD_START, new ProvisioningConfiguration(req));
-    }
-
-    // TODO: Delete this.
-    public void startProvisioning(StaticIpConfiguration staticIpConfig) {
-        startProvisioning(buildProvisioningConfiguration()
-                .withStaticConfiguration(staticIpConfig)
-                .build());
-    }
-
-    public void startProvisioning() {
-        startProvisioning(new ProvisioningConfiguration());
-    }
-
-    public void stop() {
-        sendMessage(CMD_STOP);
-    }
-
-    public void confirmConfiguration() {
-        sendMessage(CMD_CONFIRM);
-    }
-
-    public void completedPreDhcpAction() {
-        sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
-    }
-
-    public void readPacketFilterComplete(byte[] data) {
-        sendMessage(EVENT_READ_PACKET_FILTER_COMPLETE, data);
-    }
-
     /**
-     * Set the TCP buffer sizes to use.
-     *
-     * This may be called, repeatedly, at any time before or after a call to
-     * #startProvisioning(). The setting is cleared upon calling #stop().
+     * TODO: remove after migrating clients to use the shared configuration class directly.
+     * @see android.net.shared.ProvisioningConfiguration
      */
-    public void setTcpBufferSizes(String tcpBufferSizes) {
-        sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes);
-    }
-
-    /**
-     * Set the HTTP Proxy configuration to use.
-     *
-     * This may be called, repeatedly, at any time before or after a call to
-     * #startProvisioning(). The setting is cleared upon calling #stop().
-     */
-    public void setHttpProxy(ProxyInfo proxyInfo) {
-        sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
-    }
-
-    /**
-     * Enable or disable the multicast filter.  Attempts to use APF to accomplish the filtering,
-     * if not, Callback.setFallbackMulticastFilter() is called.
-     */
-    public void setMulticastFilter(boolean enabled) {
-        sendMessage(CMD_SET_MULTICAST_FILTER, enabled);
-    }
-
-    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        if (args != null && args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) {
-            // Execute confirmConfiguration() and take no further action.
-            confirmConfiguration();
-            return;
+    public static class ProvisioningConfiguration
+            extends android.net.shared.ProvisioningConfiguration {
+        public ProvisioningConfiguration(android.net.shared.ProvisioningConfiguration other) {
+            super(other);
         }
 
-        // Thread-unsafe access to mApfFilter but just used for debugging.
-        final ApfFilter apfFilter = mApfFilter;
-        final ProvisioningConfiguration provisioningConfig = mConfiguration;
-        final ApfCapabilities apfCapabilities = (provisioningConfig != null)
-                ? provisioningConfig.mApfCapabilities : null;
-
-        IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
-        pw.println(mTag + " APF dump:");
-        pw.increaseIndent();
-        if (apfFilter != null) {
-            if (apfCapabilities.hasDataAccess()) {
-                // Request a new snapshot, then wait for it.
-                mApfDataSnapshotComplete.close();
-                mCallback.startReadPacketFilter();
-                if (!mApfDataSnapshotComplete.block(1000)) {
-                    pw.print("TIMEOUT: DUMPING STALE APF SNAPSHOT");
-                }
-            }
-            apfFilter.dump(pw);
-
-        } else {
-            pw.print("No active ApfFilter; ");
-            if (provisioningConfig == null) {
-                pw.println("IpClient not yet started.");
-            } else if (apfCapabilities == null || apfCapabilities.apfVersionSupported == 0) {
-                pw.println("Hardware does not support APF.");
-            } else {
-                pw.println("ApfFilter not yet started, APF capabilities: " + apfCapabilities);
-            }
-        }
-        pw.decreaseIndent();
-        pw.println();
-        pw.println(mTag + " current ProvisioningConfiguration:");
-        pw.increaseIndent();
-        pw.println(Objects.toString(provisioningConfig, "N/A"));
-        pw.decreaseIndent();
-
-        final IpReachabilityMonitor iprm = mIpReachabilityMonitor;
-        if (iprm != null) {
-            pw.println();
-            pw.println(mTag + " current IpReachabilityMonitor state:");
-            pw.increaseIndent();
-            iprm.dump(pw);
-            pw.decreaseIndent();
-        }
-
-        pw.println();
-        pw.println(mTag + " StateMachine dump:");
-        pw.increaseIndent();
-        mLog.dump(fd, pw, args);
-        pw.decreaseIndent();
-
-        pw.println();
-        pw.println(mTag + " connectivity packet log:");
-        pw.println();
-        pw.println("Debug with python and scapy via:");
-        pw.println("shell$ python");
-        pw.println(">>> from scapy import all as scapy");
-        pw.println(">>> scapy.Ether(\"<paste_hex_string>\".decode(\"hex\")).show2()");
-        pw.println();
-
-        pw.increaseIndent();
-        mConnectivityPacketLog.readOnlyLocalLog().dump(fd, pw, args);
-        pw.decreaseIndent();
-    }
-
-
-    /**
-     * Internals.
-     */
-
-    @Override
-    protected String getWhatToString(int what) {
-        return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what));
-    }
-
-    @Override
-    protected String getLogRecString(Message msg) {
-        final String logLine = String.format(
-                "%s/%d %d %d %s [%s]",
-                mInterfaceName, (mInterfaceParams == null) ? -1 : mInterfaceParams.index,
-                msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
-
-        final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
-        mLog.log(richerLogLine);
-        if (DBG) {
-            Log.d(mTag, richerLogLine);
-        }
-
-        mMsgStateLogger.reset();
-        return logLine;
-    }
-
-    @Override
-    protected boolean recordLogRec(Message msg) {
-        // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy,
-        // and we already log any LinkProperties change that results in an
-        // invocation of IpClient.Callback#onLinkPropertiesChange().
-        final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED);
-        if (!shouldLog) {
-            mMsgStateLogger.reset();
-        }
-        return shouldLog;
-    }
-
-    private void logError(String fmt, Object... args) {
-        final String msg = "ERROR " + String.format(fmt, args);
-        Log.e(mTag, msg);
-        mLog.log(msg);
-    }
-
-    // This needs to be called with care to ensure that our LinkProperties
-    // are in sync with the actual LinkProperties of the interface. For example,
-    // we should only call this if we know for sure that there are no IP addresses
-    // assigned to the interface, etc.
-    private void resetLinkProperties() {
-        mNetlinkTracker.clearLinkProperties();
-        mConfiguration = null;
-        mDhcpResults = null;
-        mTcpBufferSizes = "";
-        mHttpProxy = null;
-
-        mLinkProperties = new LinkProperties();
-        mLinkProperties.setInterfaceName(mInterfaceName);
-    }
-
-    private void recordMetric(final int type) {
-        // We may record error metrics prior to starting.
-        // Map this to IMMEDIATE_FAILURE_DURATION.
-        final long duration = (mStartTimeMillis > 0)
-                ? (SystemClock.elapsedRealtime() - mStartTimeMillis)
-                : IMMEDIATE_FAILURE_DURATION;
-        mMetricsLog.log(mInterfaceName, new IpManagerEvent(type, duration));
-    }
-
-    // For now: use WifiStateMachine's historical notion of provisioned.
-    @VisibleForTesting
-    static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) {
-        // For historical reasons, we should connect even if all we have is
-        // an IPv4 address and nothing else.
-        if (lp.hasIPv4Address() || lp.isProvisioned()) {
-            return true;
-        }
-        if (config == null) {
-            return false;
-        }
-
-        // When an InitialConfiguration is specified, ignore any difference with previous
-        // properties and instead check if properties observed match the desired properties.
-        return config.isProvisionedBy(lp.getLinkAddresses(), lp.getRoutes());
-    }
-
-    // TODO: Investigate folding all this into the existing static function
-    // LinkProperties.compareProvisioning() or some other single function that
-    // takes two LinkProperties objects and returns a ProvisioningChange
-    // object that is a correct and complete assessment of what changed, taking
-    // account of the asymmetries described in the comments in this function.
-    // Then switch to using it everywhere (IpReachabilityMonitor, etc.).
-    private ProvisioningChange compareProvisioning(LinkProperties oldLp, LinkProperties newLp) {
-        ProvisioningChange delta;
-        InitialConfiguration config = mConfiguration != null ? mConfiguration.mInitialConfig : null;
-        final boolean wasProvisioned = isProvisioned(oldLp, config);
-        final boolean isProvisioned = isProvisioned(newLp, config);
-
-        if (!wasProvisioned && isProvisioned) {
-            delta = ProvisioningChange.GAINED_PROVISIONING;
-        } else if (wasProvisioned && isProvisioned) {
-            delta = ProvisioningChange.STILL_PROVISIONED;
-        } else if (!wasProvisioned && !isProvisioned) {
-            delta = ProvisioningChange.STILL_NOT_PROVISIONED;
-        } else {
-            // (wasProvisioned && !isProvisioned)
-            //
-            // Note that this is true even if we lose a configuration element
-            // (e.g., a default gateway) that would not be required to advance
-            // into provisioned state. This is intended: if we have a default
-            // router and we lose it, that's a sure sign of a problem, but if
-            // we connect to a network with no IPv4 DNS servers, we consider
-            // that to be a network without DNS servers and connect anyway.
-            //
-            // See the comment below.
-            delta = ProvisioningChange.LOST_PROVISIONING;
-        }
-
-        final boolean lostIPv6 = oldLp.isIPv6Provisioned() && !newLp.isIPv6Provisioned();
-        final boolean lostIPv4Address = oldLp.hasIPv4Address() && !newLp.hasIPv4Address();
-        final boolean lostIPv6Router = oldLp.hasIPv6DefaultRoute() && !newLp.hasIPv6DefaultRoute();
-
-        // If bad wifi avoidance is disabled, then ignore IPv6 loss of
-        // provisioning. Otherwise, when a hotspot that loses Internet
-        // access sends out a 0-lifetime RA to its clients, the clients
-        // will disconnect and then reconnect, avoiding the bad hotspot,
-        // instead of getting stuck on the bad hotspot. http://b/31827713 .
-        //
-        // This is incorrect because if the hotspot then regains Internet
-        // access with a different prefix, TCP connections on the
-        // deprecated addresses will remain stuck.
-        //
-        // Note that we can still be disconnected by IpReachabilityMonitor
-        // if the IPv6 default gateway (but not the IPv6 DNS servers; see
-        // accompanying code in IpReachabilityMonitor) is unreachable.
-        final boolean ignoreIPv6ProvisioningLoss = (mMultinetworkPolicyTracker != null)
-                && !mMultinetworkPolicyTracker.getAvoidBadWifi();
-
-        // Additionally:
-        //
-        // Partial configurations (e.g., only an IPv4 address with no DNS
-        // servers and no default route) are accepted as long as DHCPv4
-        // succeeds. On such a network, isProvisioned() will always return
-        // false, because the configuration is not complete, but we want to
-        // connect anyway. It might be a disconnected network such as a
-        // Chromecast or a wireless printer, for example.
-        //
-        // Because on such a network isProvisioned() will always return false,
-        // delta will never be LOST_PROVISIONING. So check for loss of
-        // provisioning here too.
-        if (lostIPv4Address || (lostIPv6 && !ignoreIPv6ProvisioningLoss)) {
-            delta = ProvisioningChange.LOST_PROVISIONING;
-        }
-
-        // Additionally:
-        //
-        // If the previous link properties had a global IPv6 address and an
-        // IPv6 default route then also consider the loss of that default route
-        // to be a loss of provisioning. See b/27962810.
-        if (oldLp.hasGlobalIPv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) {
-            delta = ProvisioningChange.LOST_PROVISIONING;
-        }
-
-        return delta;
-    }
-
-    private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) {
-        switch (delta) {
-            case GAINED_PROVISIONING:
-                if (DBG) { Log.d(mTag, "onProvisioningSuccess()"); }
-                recordMetric(IpManagerEvent.PROVISIONING_OK);
-                mCallback.onProvisioningSuccess(newLp);
-                break;
-
-            case LOST_PROVISIONING:
-                if (DBG) { Log.d(mTag, "onProvisioningFailure()"); }
-                recordMetric(IpManagerEvent.PROVISIONING_FAIL);
-                mCallback.onProvisioningFailure(newLp);
-                break;
-
-            default:
-                if (DBG) { Log.d(mTag, "onLinkPropertiesChange()"); }
-                mCallback.onLinkPropertiesChange(newLp);
-                break;
-        }
-    }
-
-    // Updates all IpClient-related state concerned with LinkProperties.
-    // Returns a ProvisioningChange for possibly notifying other interested
-    // parties that are not fronted by IpClient.
-    private ProvisioningChange setLinkProperties(LinkProperties newLp) {
-        if (mApfFilter != null) {
-            mApfFilter.setLinkProperties(newLp);
-        }
-        if (mIpReachabilityMonitor != null) {
-            mIpReachabilityMonitor.updateLinkProperties(newLp);
-        }
-
-        ProvisioningChange delta = compareProvisioning(mLinkProperties, newLp);
-        mLinkProperties = new LinkProperties(newLp);
-
-        if (delta == ProvisioningChange.GAINED_PROVISIONING) {
-            // TODO: Add a proper ProvisionedState and cancel the alarm in
-            // its enter() method.
-            mProvisioningTimeoutAlarm.cancel();
-        }
-
-        return delta;
-    }
-
-    private LinkProperties assembleLinkProperties() {
-        // [1] Create a new LinkProperties object to populate.
-        LinkProperties newLp = new LinkProperties();
-        newLp.setInterfaceName(mInterfaceName);
-
-        // [2] Pull in data from netlink:
-        //         - IPv4 addresses
-        //         - IPv6 addresses
-        //         - IPv6 routes
-        //         - IPv6 DNS servers
-        //
-        // N.B.: this is fundamentally race-prone and should be fixed by
-        // changing NetlinkTracker from a hybrid edge/level model to an
-        // edge-only model, or by giving IpClient its own netlink socket(s)
-        // so as to track all required information directly.
-        LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
-        newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
-        for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
-            newLp.addRoute(route);
-        }
-        addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());
-
-        // [3] Add in data from DHCPv4, if available.
-        //
-        // mDhcpResults is never shared with any other owner so we don't have
-        // to worry about concurrent modification.
-        if (mDhcpResults != null) {
-            for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
-                newLp.addRoute(route);
-            }
-            addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
-            newLp.setDomains(mDhcpResults.domains);
-
-            if (mDhcpResults.mtu != 0) {
-                newLp.setMtu(mDhcpResults.mtu);
-            }
-        }
-
-        // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
-        if (!TextUtils.isEmpty(mTcpBufferSizes)) {
-            newLp.setTcpBufferSizes(mTcpBufferSizes);
-        }
-        if (mHttpProxy != null) {
-            newLp.setHttpProxy(mHttpProxy);
-        }
-
-        // [5] Add data from InitialConfiguration
-        if (mConfiguration != null && mConfiguration.mInitialConfig != null) {
-            InitialConfiguration config = mConfiguration.mInitialConfig;
-            // Add InitialConfiguration routes and dns server addresses once all addresses
-            // specified in the InitialConfiguration have been observed with Netlink.
-            if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) {
-                for (IpPrefix prefix : config.directlyConnectedRoutes) {
-                    newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName));
-                }
-            }
-            addAllReachableDnsServers(newLp, config.dnsServers);
-        }
-        final LinkProperties oldLp = mLinkProperties;
-        if (DBG) {
-            Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s",
-                    netlinkLinkProperties, newLp, oldLp));
-        }
-
-        // TODO: also learn via netlink routes specified by an InitialConfiguration and specified
-        // from a static IP v4 config instead of manually patching them in in steps [3] and [5].
-        return newLp;
-    }
-
-    private static void addAllReachableDnsServers(
-            LinkProperties lp, Iterable<InetAddress> dnses) {
-        // TODO: Investigate deleting this reachability check.  We should be
-        // able to pass everything down to netd and let netd do evaluation
-        // and RFC6724-style sorting.
-        for (InetAddress dns : dnses) {
-            if (!dns.isAnyLocalAddress() && lp.isReachable(dns)) {
-                lp.addDnsServer(dns);
-            }
-        }
-    }
-
-    // Returns false if we have lost provisioning, true otherwise.
-    private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
-        final LinkProperties newLp = assembleLinkProperties();
-        if (Objects.equals(newLp, mLinkProperties)) {
-            return true;
-        }
-        final ProvisioningChange delta = setLinkProperties(newLp);
-        if (sendCallbacks) {
-            dispatchCallback(delta, newLp);
-        }
-        return (delta != ProvisioningChange.LOST_PROVISIONING);
-    }
-
-    private void handleIPv4Success(DhcpResults dhcpResults) {
-        mDhcpResults = new DhcpResults(dhcpResults);
-        final LinkProperties newLp = assembleLinkProperties();
-        final ProvisioningChange delta = setLinkProperties(newLp);
-
-        if (DBG) {
-            Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
-        }
-        mCallback.onNewDhcpResults(dhcpResults);
-        dispatchCallback(delta, newLp);
-    }
-
-    private void handleIPv4Failure() {
-        // TODO: Investigate deleting this clearIPv4Address() call.
-        //
-        // DhcpClient will send us CMD_CLEAR_LINKADDRESS in all circumstances
-        // that could trigger a call to this function. If we missed handling
-        // that message in StartedState for some reason we would still clear
-        // any addresses upon entry to StoppedState.
-        mInterfaceCtrl.clearIPv4Address();
-        mDhcpResults = null;
-        if (DBG) { Log.d(mTag, "onNewDhcpResults(null)"); }
-        mCallback.onNewDhcpResults(null);
-
-        handleProvisioningFailure();
-    }
-
-    private void handleProvisioningFailure() {
-        final LinkProperties newLp = assembleLinkProperties();
-        ProvisioningChange delta = setLinkProperties(newLp);
-        // If we've gotten here and we're still not provisioned treat that as
-        // a total loss of provisioning.
-        //
-        // Either (a) static IP configuration failed or (b) DHCPv4 failed AND
-        // there was no usable IPv6 obtained before a non-zero provisioning
-        // timeout expired.
-        //
-        // Regardless: GAME OVER.
-        if (delta == ProvisioningChange.STILL_NOT_PROVISIONED) {
-            delta = ProvisioningChange.LOST_PROVISIONING;
-        }
-
-        dispatchCallback(delta, newLp);
-        if (delta == ProvisioningChange.LOST_PROVISIONING) {
-            transitionTo(mStoppingState);
-        }
-    }
-
-    private void doImmediateProvisioningFailure(int failureType) {
-        logError("onProvisioningFailure(): %s", failureType);
-        recordMetric(failureType);
-        mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties));
-    }
-
-    private boolean startIPv4() {
-        // If we have a StaticIpConfiguration attempt to apply it and
-        // handle the result accordingly.
-        if (mConfiguration.mStaticIpConfig != null) {
-            if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) {
-                handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
-            } else {
-                return false;
-            }
-        } else {
-            // Start DHCPv4.
-            mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpClient.this, mInterfaceParams);
-            mDhcpClient.registerForPreDhcpNotification();
-            mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
-        }
-
-        return true;
-    }
-
-    private boolean startIPv6() {
-        return mInterfaceCtrl.setIPv6PrivacyExtensions(true) &&
-               mInterfaceCtrl.setIPv6AddrGenModeIfSupported(mConfiguration.mIPv6AddrGenMode) &&
-               mInterfaceCtrl.enableIPv6();
-    }
-
-    private boolean applyInitialConfig(InitialConfiguration config) {
-        // TODO: also support specifying a static IPv4 configuration in InitialConfiguration.
-        for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIPv6)) {
-            if (!mInterfaceCtrl.addAddress(addr)) return false;
-        }
-
-        return true;
-    }
-
-    private boolean startIpReachabilityMonitor() {
-        try {
-            // TODO: Fetch these parameters from settings, and install a
-            // settings observer to watch for update and re-program these
-            // parameters (Q: is this level of dynamic updatability really
-            // necessary or does reading from settings at startup suffice?).
-            final int NUM_SOLICITS = 5;
-            final int INTER_SOLICIT_INTERVAL_MS = 750;
-            setNeighborParameters(mDependencies.getNetd(), mInterfaceName,
-                    NUM_SOLICITS, INTER_SOLICIT_INTERVAL_MS);
-        } catch (Exception e) {
-            mLog.e("Failed to adjust neighbor parameters", e);
-            // Carry on using the system defaults (currently: 3, 1000);
-        }
-
-        try {
-            mIpReachabilityMonitor = new IpReachabilityMonitor(
-                    mContext,
-                    mInterfaceParams,
-                    getHandler(),
-                    mLog,
-                    new IpReachabilityMonitor.Callback() {
-                        @Override
-                        public void notifyLost(InetAddress ip, String logMsg) {
-                            mCallback.onReachabilityLost(logMsg);
-                        }
-                    },
-                    mMultinetworkPolicyTracker);
-        } catch (IllegalArgumentException iae) {
-            // Failed to start IpReachabilityMonitor. Log it and call
-            // onProvisioningFailure() immediately.
-            //
-            // See http://b/31038971.
-            logError("IpReachabilityMonitor failure: %s", iae);
-            mIpReachabilityMonitor = null;
-        }
-
-        return (mIpReachabilityMonitor != null);
-    }
-
-    private void stopAllIP() {
-        // We don't need to worry about routes, just addresses, because:
-        //     - disableIpv6() will clear autoconf IPv6 routes as well, and
-        //     - we don't get IPv4 routes from netlink
-        // so we neither react to nor need to wait for changes in either.
-
-        mInterfaceCtrl.disableIPv6();
-        mInterfaceCtrl.clearAllAddresses();
-    }
-
-    class StoppedState extends State {
-        @Override
-        public void enter() {
-            stopAllIP();
-
-            resetLinkProperties();
-            if (mStartTimeMillis > 0) {
-                // Completed a life-cycle; send a final empty LinkProperties
-                // (cleared in resetLinkProperties() above) and record an event.
-                mCallback.onLinkPropertiesChange(new LinkProperties(mLinkProperties));
-                recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
-                mStartTimeMillis = 0;
-            }
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_TERMINATE_AFTER_STOP:
-                    stopStateMachineUpdaters();
-                    quit();
-                    break;
-
-                case CMD_STOP:
-                    break;
-
-                case CMD_START:
-                    mConfiguration = (ProvisioningConfiguration) msg.obj;
-                    transitionTo(mStartedState);
-                    break;
-
-                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
-                    handleLinkPropertiesUpdate(NO_CALLBACKS);
-                    break;
-
-                case CMD_UPDATE_TCP_BUFFER_SIZES:
-                    mTcpBufferSizes = (String) msg.obj;
-                    handleLinkPropertiesUpdate(NO_CALLBACKS);
-                    break;
-
-                case CMD_UPDATE_HTTP_PROXY:
-                    mHttpProxy = (ProxyInfo) msg.obj;
-                    handleLinkPropertiesUpdate(NO_CALLBACKS);
-                    break;
-
-                case CMD_SET_MULTICAST_FILTER:
-                    mMulticastFiltering = (boolean) msg.obj;
-                    break;
-
-                case DhcpClient.CMD_ON_QUIT:
-                    // Everything is already stopped.
-                    logError("Unexpected CMD_ON_QUIT (already stopped).");
-                    break;
-
-                default:
-                    return NOT_HANDLED;
+        /**
+         * @see android.net.shared.ProvisioningConfiguration.Builder
+         */
+        public static class Builder extends android.net.shared.ProvisioningConfiguration.Builder {
+            // Override all methods to have a return type matching this Builder
+            @Override
+            public Builder withoutIPv4() {
+                super.withoutIPv4();
+                return this;
             }
 
-            mMsgStateLogger.handled(this, getCurrentState());
-            return HANDLED;
-        }
-    }
+            @Override
+            public Builder withoutIPv6() {
+                super.withoutIPv6();
+                return this;
+            }
 
-    class StoppingState extends State {
-        @Override
-        public void enter() {
-            if (mDhcpClient == null) {
-                // There's no DHCPv4 for which to wait; proceed to stopped.
-                deferMessage(obtainMessage(CMD_JUMP_STOPPING_TO_STOPPED));
+            @Override
+            public Builder withoutMultinetworkPolicyTracker() {
+                super.withoutMultinetworkPolicyTracker();
+                return this;
+            }
+
+            @Override
+            public Builder withoutIpReachabilityMonitor() {
+                super.withoutIpReachabilityMonitor();
+                return this;
+            }
+
+            @Override
+            public Builder withPreDhcpAction() {
+                super.withPreDhcpAction();
+                return this;
+            }
+
+            @Override
+            public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
+                super.withPreDhcpAction(dhcpActionTimeoutMs);
+                return this;
+            }
+
+            @Override
+            public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
+                super.withStaticConfiguration(staticConfig);
+                return this;
+            }
+
+            @Override
+            public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
+                super.withApfCapabilities(apfCapabilities);
+                return this;
+            }
+
+            @Override
+            public Builder withProvisioningTimeoutMs(int timeoutMs) {
+                super.withProvisioningTimeoutMs(timeoutMs);
+                return this;
+            }
+
+            @Override
+            public Builder withRandomMacAddress() {
+                super.withRandomMacAddress();
+                return this;
+            }
+
+            @Override
+            public Builder withStableMacAddress() {
+                super.withStableMacAddress();
+                return this;
+            }
+
+            @Override
+            public Builder withNetwork(Network network) {
+                super.withNetwork(network);
+                return this;
+            }
+
+            @Override
+            public Builder withDisplayName(String displayName) {
+                super.withDisplayName(displayName);
+                return this;
+            }
+
+            @Override
+            public ProvisioningConfiguration build() {
+                return new ProvisioningConfiguration(mConfig);
             }
         }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_JUMP_STOPPING_TO_STOPPED:
-                    transitionTo(mStoppedState);
-                    break;
-
-                case CMD_STOP:
-                    break;
-
-                case DhcpClient.CMD_CLEAR_LINKADDRESS:
-                    mInterfaceCtrl.clearIPv4Address();
-                    break;
-
-                case DhcpClient.CMD_ON_QUIT:
-                    mDhcpClient = null;
-                    transitionTo(mStoppedState);
-                    break;
-
-                default:
-                    deferMessage(msg);
-            }
-
-            mMsgStateLogger.handled(this, getCurrentState());
-            return HANDLED;
-        }
-    }
-
-    class StartedState extends State {
-        @Override
-        public void enter() {
-            mStartTimeMillis = SystemClock.elapsedRealtime();
-
-            if (mConfiguration.mProvisioningTimeoutMs > 0) {
-                final long alarmTime = SystemClock.elapsedRealtime() +
-                        mConfiguration.mProvisioningTimeoutMs;
-                mProvisioningTimeoutAlarm.schedule(alarmTime);
-            }
-
-            if (readyToProceed()) {
-                deferMessage(obtainMessage(CMD_JUMP_STARTED_TO_RUNNING));
-            } else {
-                // Clear all IPv4 and IPv6 before proceeding to RunningState.
-                // Clean up any leftover state from an abnormal exit from
-                // tethering or during an IpClient restart.
-                stopAllIP();
-            }
-        }
-
-        @Override
-        public void exit() {
-            mProvisioningTimeoutAlarm.cancel();
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_JUMP_STARTED_TO_RUNNING:
-                    transitionTo(mRunningState);
-                    break;
-
-                case CMD_STOP:
-                    transitionTo(mStoppingState);
-                    break;
-
-                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
-                    handleLinkPropertiesUpdate(NO_CALLBACKS);
-                    if (readyToProceed()) {
-                        transitionTo(mRunningState);
-                    }
-                    break;
-
-                case EVENT_PROVISIONING_TIMEOUT:
-                    handleProvisioningFailure();
-                    break;
-
-                default:
-                    // It's safe to process messages out of order because the
-                    // only message that can both
-                    //     a) be received at this time and
-                    //     b) affect provisioning state
-                    // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above).
-                    deferMessage(msg);
-            }
-
-            mMsgStateLogger.handled(this, getCurrentState());
-            return HANDLED;
-        }
-
-        private boolean readyToProceed() {
-            return (!mLinkProperties.hasIPv4Address() &&
-                    !mLinkProperties.hasGlobalIPv6Address());
-        }
-    }
-
-    class RunningState extends State {
-        private ConnectivityPacketTracker mPacketTracker;
-        private boolean mDhcpActionInFlight;
-
-        @Override
-        public void enter() {
-            ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();
-            apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
-            apfConfig.multicastFilter = mMulticastFiltering;
-            // Get the Configuration for ApfFilter from Context
-            apfConfig.ieee802_3Filter =
-                    mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
-            apfConfig.ethTypeBlackList =
-                    mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
-            mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback);
-            // TODO: investigate the effects of any multicast filtering racing/interfering with the
-            // rest of this IP configuration startup.
-            if (mApfFilter == null) {
-                mCallback.setFallbackMulticastFilter(mMulticastFiltering);
-            }
-
-            mPacketTracker = createPacketTracker();
-            if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
-
-            if (mConfiguration.mEnableIPv6 && !startIPv6()) {
-                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
-                enqueueJumpToStoppingState();
-                return;
-            }
-
-            if (mConfiguration.mEnableIPv4 && !startIPv4()) {
-                doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
-                enqueueJumpToStoppingState();
-                return;
-            }
-
-            final InitialConfiguration config = mConfiguration.mInitialConfig;
-            if ((config != null) && !applyInitialConfig(config)) {
-                // TODO introduce a new IpManagerEvent constant to distinguish this error case.
-                doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
-                enqueueJumpToStoppingState();
-                return;
-            }
-
-            if (mConfiguration.mUsingMultinetworkPolicyTracker) {
-                mMultinetworkPolicyTracker = new MultinetworkPolicyTracker(
-                        mContext, getHandler(),
-                        () -> { mLog.log("OBSERVED AvoidBadWifi changed"); });
-                mMultinetworkPolicyTracker.start();
-            }
-
-            if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
-                doImmediateProvisioningFailure(
-                        IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
-                enqueueJumpToStoppingState();
-                return;
-            }
-        }
-
-        @Override
-        public void exit() {
-            stopDhcpAction();
-
-            if (mIpReachabilityMonitor != null) {
-                mIpReachabilityMonitor.stop();
-                mIpReachabilityMonitor = null;
-            }
-
-            if (mMultinetworkPolicyTracker != null) {
-                mMultinetworkPolicyTracker.shutdown();
-                mMultinetworkPolicyTracker = null;
-            }
-
-            if (mDhcpClient != null) {
-                mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
-                mDhcpClient.doQuit();
-            }
-
-            if (mPacketTracker != null) {
-                mPacketTracker.stop();
-                mPacketTracker = null;
-            }
-
-            if (mApfFilter != null) {
-                mApfFilter.shutdown();
-                mApfFilter = null;
-            }
-
-            resetLinkProperties();
-        }
-
-        private void enqueueJumpToStoppingState() {
-            deferMessage(obtainMessage(CMD_JUMP_RUNNING_TO_STOPPING));
-        }
-
-        private ConnectivityPacketTracker createPacketTracker() {
-            try {
-                return new ConnectivityPacketTracker(
-                        getHandler(), mInterfaceParams, mConnectivityPacketLog);
-            } catch (IllegalArgumentException e) {
-                return null;
-            }
-        }
-
-        private void ensureDhcpAction() {
-            if (!mDhcpActionInFlight) {
-                mCallback.onPreDhcpAction();
-                mDhcpActionInFlight = true;
-                final long alarmTime = SystemClock.elapsedRealtime() +
-                        mConfiguration.mRequestedPreDhcpActionMs;
-                mDhcpActionTimeoutAlarm.schedule(alarmTime);
-            }
-        }
-
-        private void stopDhcpAction() {
-            mDhcpActionTimeoutAlarm.cancel();
-            if (mDhcpActionInFlight) {
-                mCallback.onPostDhcpAction();
-                mDhcpActionInFlight = false;
-            }
-        }
-
-        @Override
-        public boolean processMessage(Message msg) {
-            switch (msg.what) {
-                case CMD_JUMP_RUNNING_TO_STOPPING:
-                case CMD_STOP:
-                    transitionTo(mStoppingState);
-                    break;
-
-                case CMD_START:
-                    logError("ALERT: START received in StartedState. Please fix caller.");
-                    break;
-
-                case CMD_CONFIRM:
-                    // TODO: Possibly introduce a second type of confirmation
-                    // that both probes (a) on-link neighbors and (b) does
-                    // a DHCPv4 RENEW.  We used to do this on Wi-Fi framework
-                    // roams.
-                    if (mIpReachabilityMonitor != null) {
-                        mIpReachabilityMonitor.probeAll();
-                    }
-                    break;
-
-                case EVENT_PRE_DHCP_ACTION_COMPLETE:
-                    // It's possible to reach here if, for example, someone
-                    // calls completedPreDhcpAction() after provisioning with
-                    // a static IP configuration.
-                    if (mDhcpClient != null) {
-                        mDhcpClient.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
-                    }
-                    break;
-
-                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
-                    if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) {
-                        transitionTo(mStoppingState);
-                    }
-                    break;
-
-                case CMD_UPDATE_TCP_BUFFER_SIZES:
-                    mTcpBufferSizes = (String) msg.obj;
-                    // This cannot possibly change provisioning state.
-                    handleLinkPropertiesUpdate(SEND_CALLBACKS);
-                    break;
-
-                case CMD_UPDATE_HTTP_PROXY:
-                    mHttpProxy = (ProxyInfo) msg.obj;
-                    // This cannot possibly change provisioning state.
-                    handleLinkPropertiesUpdate(SEND_CALLBACKS);
-                    break;
-
-                case CMD_SET_MULTICAST_FILTER: {
-                    mMulticastFiltering = (boolean) msg.obj;
-                    if (mApfFilter != null) {
-                        mApfFilter.setMulticastFilter(mMulticastFiltering);
-                    } else {
-                        mCallback.setFallbackMulticastFilter(mMulticastFiltering);
-                    }
-                    break;
-                }
-
-                case EVENT_READ_PACKET_FILTER_COMPLETE: {
-                    if (mApfFilter != null) {
-                        mApfFilter.setDataSnapshot((byte[]) msg.obj);
-                    }
-                    mApfDataSnapshotComplete.open();
-                    break;
-                }
-
-                case EVENT_DHCPACTION_TIMEOUT:
-                    stopDhcpAction();
-                    break;
-
-                case DhcpClient.CMD_PRE_DHCP_ACTION:
-                    if (mConfiguration.mRequestedPreDhcpActionMs > 0) {
-                        ensureDhcpAction();
-                    } else {
-                        sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
-                    }
-                    break;
-
-                case DhcpClient.CMD_CLEAR_LINKADDRESS:
-                    mInterfaceCtrl.clearIPv4Address();
-                    break;
-
-                case DhcpClient.CMD_CONFIGURE_LINKADDRESS: {
-                    final LinkAddress ipAddress = (LinkAddress) msg.obj;
-                    if (mInterfaceCtrl.setIPv4Address(ipAddress)) {
-                        mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED);
-                    } else {
-                        logError("Failed to set IPv4 address.");
-                        dispatchCallback(ProvisioningChange.LOST_PROVISIONING,
-                                new LinkProperties(mLinkProperties));
-                        transitionTo(mStoppingState);
-                    }
-                    break;
-                }
-
-                // This message is only received when:
-                //
-                //     a) initial address acquisition succeeds,
-                //     b) renew succeeds or is NAK'd,
-                //     c) rebind succeeds or is NAK'd, or
-                //     c) the lease expires,
-                //
-                // but never when initial address acquisition fails. The latter
-                // condition is now governed by the provisioning timeout.
-                case DhcpClient.CMD_POST_DHCP_ACTION:
-                    stopDhcpAction();
-
-                    switch (msg.arg1) {
-                        case DhcpClient.DHCP_SUCCESS:
-                            handleIPv4Success((DhcpResults) msg.obj);
-                            break;
-                        case DhcpClient.DHCP_FAILURE:
-                            handleIPv4Failure();
-                            break;
-                        default:
-                            logError("Unknown CMD_POST_DHCP_ACTION status: %s", msg.arg1);
-                    }
-                    break;
-
-                case DhcpClient.CMD_ON_QUIT:
-                    // DHCPv4 quit early for some reason.
-                    logError("Unexpected CMD_ON_QUIT.");
-                    mDhcpClient = null;
-                    break;
-
-                default:
-                    return NOT_HANDLED;
-            }
-
-            mMsgStateLogger.handled(this, getCurrentState());
-            return HANDLED;
-        }
-    }
-
-    private static class MessageHandlingLogger {
-        public String processedInState;
-        public String receivedInState;
-
-        public void reset() {
-            processedInState = null;
-            receivedInState = null;
-        }
-
-        public void handled(State processedIn, IState receivedIn) {
-            processedInState = processedIn.getClass().getSimpleName();
-            receivedInState = receivedIn.getName();
-        }
-
-        public String toString() {
-            return String.format("rcvd_in=%s, proc_in=%s",
-                                 receivedInState, processedInState);
-        }
-    }
-
-    private static void setNeighborParameters(
-            INetd netd, String ifName, int num_solicits, int inter_solicit_interval_ms)
-            throws RemoteException, IllegalArgumentException {
-        Preconditions.checkNotNull(netd);
-        Preconditions.checkArgument(!TextUtils.isEmpty(ifName));
-        Preconditions.checkArgument(num_solicits > 0);
-        Preconditions.checkArgument(inter_solicit_interval_ms > 0);
-
-        for (int family : new Integer[]{INetd.IPV4, INetd.IPV6}) {
-            netd.setProcSysNet(family, INetd.NEIGH, ifName, "retrans_time_ms", Integer.toString(inter_solicit_interval_ms));
-            netd.setProcSysNet(family, INetd.NEIGH, ifName, "ucast_solicit", Integer.toString(num_solicits));
-        }
-    }
-
-    // TODO: extract out into CollectionUtils.
-    static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
-        for (T t : coll) {
-            if (fn.test(t)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
-        return !any(coll, not(fn));
-    }
-
-    static <T> Predicate<T> not(Predicate<T> fn) {
-        return (t) -> !fn.test(t);
-    }
-
-    static <T> String join(String delimiter, Collection<T> coll) {
-        return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter));
-    }
-
-    static <T> T find(Iterable<T> coll, Predicate<T> fn) {
-        for (T t: coll) {
-            if (fn.test(t)) {
-              return t;
-            }
-        }
-        return null;
-    }
-
-    static <T> List<T> findAll(Collection<T> coll, Predicate<T> fn) {
-        return coll.stream().filter(fn).collect(Collectors.toList());
     }
 }
diff --git a/services/net/java/android/net/ip/IpClientUtil.java b/services/net/java/android/net/ip/IpClientUtil.java
new file mode 100644
index 0000000..2a2a67a
--- /dev/null
+++ b/services/net/java/android/net/ip/IpClientUtil.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static android.net.shared.IpConfigurationParcelableUtil.fromStableParcelable;
+import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
+
+import android.content.Context;
+import android.net.DhcpResultsParcelable;
+import android.net.LinkProperties;
+import android.net.LinkPropertiesParcelable;
+import android.net.NetworkStack;
+import android.net.ip.IIpClientCallbacks;
+import android.os.ConditionVariable;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+
+/**
+ * Utilities and wrappers to simplify communication with IpClient, which lives in the NetworkStack
+ * process.
+ *
+ * @hide
+ */
+public class IpClientUtil {
+    // TODO: remove with its callers
+    public static final String DUMP_ARG = "ipclient";
+
+    /**
+     * Subclass of {@link IpClientCallbacks} allowing clients to block until provisioning is
+     * complete with {@link WaitForProvisioningCallbacks#waitForProvisioning()}.
+     */
+    public static class WaitForProvisioningCallbacks extends IpClientCallbacks {
+        private final ConditionVariable mCV = new ConditionVariable();
+        private LinkProperties mCallbackLinkProperties;
+
+        /**
+         * Block until either {@link #onProvisioningSuccess(LinkProperties)} or
+         * {@link #onProvisioningFailure(LinkProperties)} is called.
+         */
+        public LinkProperties waitForProvisioning() {
+            mCV.block();
+            return mCallbackLinkProperties;
+        }
+
+        @Override
+        public void onProvisioningSuccess(LinkProperties newLp) {
+            mCallbackLinkProperties = newLp;
+            mCV.open();
+        }
+
+        @Override
+        public void onProvisioningFailure(LinkProperties newLp) {
+            mCallbackLinkProperties = null;
+            mCV.open();
+        }
+    }
+
+    /**
+     * Create a new IpClient.
+     *
+     * <p>This is a convenience method to allow clients to use {@link IpClientCallbacks} instead of
+     * {@link IIpClientCallbacks}.
+     * @see {@link NetworkStack#makeIpClient(String, IIpClientCallbacks)}
+     */
+    public static void makeIpClient(Context context, String ifName, IpClientCallbacks callback) {
+        context.getSystemService(NetworkStack.class)
+                .makeIpClient(ifName, new IpClientCallbacksProxy(callback));
+    }
+
+    /**
+     * Create a new IpClient.
+     *
+     * <p>This is a convenience method to allow clients to use {@link IpClientCallbacksProxy}
+     * instead of {@link IIpClientCallbacks}.
+     * @see {@link NetworkStack#makeIpClient(String, IIpClientCallbacks)}
+     */
+    public static void makeIpClient(
+            Context context, String ifName, IpClientCallbacksProxy callback) {
+        context.getSystemService(NetworkStack.class)
+                .makeIpClient(ifName, callback);
+    }
+
+    /**
+     * Wrapper to relay calls from {@link IIpClientCallbacks} to {@link IpClientCallbacks}.
+     */
+    public static class IpClientCallbacksProxy extends IIpClientCallbacks.Stub {
+        protected final IpClientCallbacks mCb;
+
+        /**
+         * Create a new IpClientCallbacksProxy.
+         */
+        public IpClientCallbacksProxy(IpClientCallbacks cb) {
+            mCb = cb;
+        }
+
+        @Override
+        public void onIpClientCreated(IIpClient ipClient) {
+            mCb.onIpClientCreated(ipClient);
+        }
+
+        @Override
+        public void onPreDhcpAction() {
+            mCb.onPreDhcpAction();
+        }
+
+        @Override
+        public void onPostDhcpAction() {
+            mCb.onPostDhcpAction();
+        }
+
+        // This is purely advisory and not an indication of provisioning
+        // success or failure.  This is only here for callers that want to
+        // expose DHCPv4 results to other APIs (e.g., WifiInfo#setInetAddress).
+        // DHCPv4 or static IPv4 configuration failure or success can be
+        // determined by whether or not the passed-in DhcpResults object is
+        // null or not.
+        @Override
+        public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) {
+            mCb.onNewDhcpResults(fromStableParcelable(dhcpResults));
+        }
+
+        @Override
+        public void onProvisioningSuccess(LinkPropertiesParcelable newLp) {
+            mCb.onProvisioningSuccess(fromStableParcelable(newLp));
+        }
+        @Override
+        public void onProvisioningFailure(LinkPropertiesParcelable newLp) {
+            mCb.onProvisioningFailure(fromStableParcelable(newLp));
+        }
+
+        // Invoked on LinkProperties changes.
+        @Override
+        public void onLinkPropertiesChange(LinkPropertiesParcelable newLp) {
+            mCb.onLinkPropertiesChange(fromStableParcelable(newLp));
+        }
+
+        // Called when the internal IpReachabilityMonitor (if enabled) has
+        // detected the loss of a critical number of required neighbors.
+        @Override
+        public void onReachabilityLost(String logMsg) {
+            mCb.onReachabilityLost(logMsg);
+        }
+
+        // Called when the IpClient state machine terminates.
+        @Override
+        public void onQuit() {
+            mCb.onQuit();
+        }
+
+        // Install an APF program to filter incoming packets.
+        @Override
+        public void installPacketFilter(byte[] filter) {
+            mCb.installPacketFilter(filter);
+        }
+
+        // Asynchronously read back the APF program & data buffer from the wifi driver.
+        // Due to Wifi HAL limitations, the current implementation only supports dumping the entire
+        // buffer. In response to this request, the driver returns the data buffer asynchronously
+        // by sending an IpClient#EVENT_READ_PACKET_FILTER_COMPLETE message.
+        @Override
+        public void startReadPacketFilter() {
+            mCb.startReadPacketFilter();
+        }
+
+        // If multicast filtering cannot be accomplished with APF, this function will be called to
+        // actuate multicast filtering using another means.
+        @Override
+        public void setFallbackMulticastFilter(boolean enabled) {
+            mCb.setFallbackMulticastFilter(enabled);
+        }
+
+        // Enabled/disable Neighbor Discover offload functionality. This is
+        // called, for example, whenever 464xlat is being started or stopped.
+        @Override
+        public void setNeighborDiscoveryOffload(boolean enable) {
+            mCb.setNeighborDiscoveryOffload(enable);
+        }
+    }
+
+    /**
+     * Dump logs for the specified IpClient.
+     * TODO: remove callers and delete
+     */
+    public static void dumpIpClient(
+            IIpClient connector, FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("IpClient logs have moved to dumpsys network_stack");
+    }
+}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
deleted file mode 100644
index 2eb36a2..0000000
--- a/services/net/java/android/net/ip/IpManager.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ip;
-
-import android.content.Context;
-import android.net.INetd;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.StaticIpConfiguration;
-import android.net.apf.ApfCapabilities;
-import android.net.util.NetdService;
-import android.os.INetworkManagementService;
-import android.os.ServiceManager;
-import android.net.apf.ApfCapabilities;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-
-/*
- * TODO: Delete this altogether in favor of its renamed successor: IpClient.
- *
- * @hide
- */
-public class IpManager extends IpClient {
-    public static class ProvisioningConfiguration extends IpClient.ProvisioningConfiguration {
-        public ProvisioningConfiguration(IpClient.ProvisioningConfiguration ipcConfig) {
-            super(ipcConfig);
-        }
-
-        public static class Builder extends IpClient.ProvisioningConfiguration.Builder {
-            @Override
-            public Builder withoutIPv4() {
-                super.withoutIPv4();
-                return this;
-            }
-            @Override
-            public Builder withoutIPv6() {
-                super.withoutIPv6();
-                return this;
-            }
-            @Override
-            public Builder withoutIpReachabilityMonitor() {
-                super.withoutIpReachabilityMonitor();
-                return this;
-            }
-            @Override
-            public Builder withPreDhcpAction() {
-                super.withPreDhcpAction();
-                return this;
-            }
-            @Override
-            public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
-                super.withPreDhcpAction(dhcpActionTimeoutMs);
-                return this;
-            }
-            // No Override; locally defined type.
-            public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
-                super.withInitialConfiguration((IpClient.InitialConfiguration) initialConfig);
-                return this;
-            }
-            @Override
-            public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
-                super.withStaticConfiguration(staticConfig);
-                return this;
-            }
-            @Override
-            public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
-                super.withApfCapabilities(apfCapabilities);
-                return this;
-            }
-            @Override
-            public Builder withProvisioningTimeoutMs(int timeoutMs) {
-                super.withProvisioningTimeoutMs(timeoutMs);
-                return this;
-            }
-            @Override
-            public Builder withNetwork(Network network) {
-                super.withNetwork(network);
-                return this;
-            }
-            @Override
-            public Builder withDisplayName(String displayName) {
-                super.withDisplayName(displayName);
-                return this;
-            }
-            @Override
-            public ProvisioningConfiguration build() {
-                return new ProvisioningConfiguration(super.build());
-            }
-        }
-    }
-
-    public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() {
-        return new ProvisioningConfiguration.Builder();
-    }
-
-    public static class InitialConfiguration extends IpClient.InitialConfiguration {
-    }
-
-    public static class Callback extends IpClient.Callback {
-    }
-
-    public IpManager(Context context, String ifName, Callback callback) {
-        super(context, ifName, callback);
-    }
-
-    public void startProvisioning(ProvisioningConfiguration req) {
-        super.startProvisioning((IpClient.ProvisioningConfiguration) req);
-    }
-}
diff --git a/services/net/java/android/net/ip/IpNeighborMonitor.java b/services/net/java/android/net/ip/IpNeighborMonitor.java
deleted file mode 100644
index 9512f1b..0000000
--- a/services/net/java/android/net/ip/IpNeighborMonitor.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ip;
-
-import static android.net.netlink.NetlinkConstants.hexify;
-import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH;
-import static android.net.netlink.NetlinkConstants.stringForNlMsgType;
-
-import android.net.MacAddress;
-import android.net.netlink.NetlinkErrorMessage;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.NetlinkSocket;
-import android.net.netlink.RtNetlinkNeighborMessage;
-import android.net.netlink.StructNdMsg;
-import android.net.netlink.StructNlMsgHdr;
-import android.net.util.PacketReader;
-import android.net.util.SharedLog;
-import android.os.Handler;
-import android.os.SystemClock;
-import android.system.ErrnoException;
-import android.system.NetlinkSocketAddress;
-import android.system.Os;
-import android.system.OsConstants;
-import android.util.Log;
-
-import com.android.internal.util.BitUtils;
-
-import libcore.io.IoUtils;
-
-import java.io.FileDescriptor;
-import java.net.InetAddress;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.StringJoiner;
-
-
-/**
- * IpNeighborMonitor.
- *
- * Monitors the kernel rtnetlink neighbor notifications and presents to callers
- * NeighborEvents describing each event. Callers can provide a consumer instance
- * to both filter (e.g. by interface index and IP address) and handle the
- * generated NeighborEvents.
- *
- * @hide
- */
-public class IpNeighborMonitor extends PacketReader {
-    private static final String TAG = IpNeighborMonitor.class.getSimpleName();
-    private static final boolean DBG = false;
-    private static final boolean VDBG = false;
-
-    /**
-     * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
-     * for the given IP address on the specified interface index.
-     *
-     * @return 0 if the request was successfully passed to the kernel; otherwise return
-     *         a non-zero error code.
-     */
-    public static int startKernelNeighborProbe(int ifIndex, InetAddress ip) {
-        final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex;
-        if (DBG) { Log.d(TAG, msgSnippet); }
-
-        final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
-                1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
-
-        try {
-            NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_ROUTE, msg);
-        } catch (ErrnoException e) {
-            Log.e(TAG, "Error " + msgSnippet + ": " + e);
-            return -e.errno;
-        }
-
-        return 0;
-    }
-
-    public static class NeighborEvent {
-        final long elapsedMs;
-        final short msgType;
-        final int ifindex;
-        final InetAddress ip;
-        final short nudState;
-        final MacAddress macAddr;
-
-        public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip,
-                short nudState, MacAddress macAddr) {
-            this.elapsedMs = elapsedMs;
-            this.msgType = msgType;
-            this.ifindex = ifindex;
-            this.ip = ip;
-            this.nudState = nudState;
-            this.macAddr = macAddr;
-        }
-
-        boolean isConnected() {
-            return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState);
-        }
-
-        boolean isValid() {
-            return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState);
-        }
-
-        @Override
-        public String toString() {
-            final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}");
-            return j.add("@" + elapsedMs)
-                    .add(stringForNlMsgType(msgType))
-                    .add("if=" + ifindex)
-                    .add(ip.getHostAddress())
-                    .add(StructNdMsg.stringForNudState(nudState))
-                    .add("[" + macAddr + "]")
-                    .toString();
-        }
-    }
-
-    public interface NeighborEventConsumer {
-        // Every neighbor event received on the netlink socket is passed in
-        // here. Subclasses should filter for events of interest.
-        public void accept(NeighborEvent event);
-    }
-
-    private final SharedLog mLog;
-    private final NeighborEventConsumer mConsumer;
-
-    public IpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb) {
-        super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE);
-        mLog = log.forSubComponent(TAG);
-        mConsumer = (cb != null) ? cb : (event) -> { /* discard */ };
-    }
-
-    @Override
-    protected FileDescriptor createFd() {
-        FileDescriptor fd = null;
-
-        try {
-            fd = NetlinkSocket.forProto(OsConstants.NETLINK_ROUTE);
-            Os.bind(fd, (SocketAddress)(new NetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH)));
-            Os.connect(fd, (SocketAddress)(new NetlinkSocketAddress(0, 0)));
-
-            if (VDBG) {
-                final NetlinkSocketAddress nlAddr = (NetlinkSocketAddress) Os.getsockname(fd);
-                Log.d(TAG, "bound to sockaddr_nl{"
-                        + BitUtils.uint32(nlAddr.getPortId()) + ", "
-                        + nlAddr.getGroupsMask()
-                        + "}");
-            }
-        } catch (ErrnoException|SocketException e) {
-            logError("Failed to create rtnetlink socket", e);
-            IoUtils.closeQuietly(fd);
-            return null;
-        }
-
-        return fd;
-    }
-
-    @Override
-    protected void handlePacket(byte[] recvbuf, int length) {
-        final long whenMs = SystemClock.elapsedRealtime();
-
-        final ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf, 0, length);
-        byteBuffer.order(ByteOrder.nativeOrder());
-
-        parseNetlinkMessageBuffer(byteBuffer, whenMs);
-    }
-
-    private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) {
-        while (byteBuffer.remaining() > 0) {
-            final int position = byteBuffer.position();
-            final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
-            if (nlMsg == null || nlMsg.getHeader() == null) {
-                byteBuffer.position(position);
-                mLog.e("unparsable netlink msg: " + hexify(byteBuffer));
-                break;
-            }
-
-            final int srcPortId = nlMsg.getHeader().nlmsg_pid;
-            if (srcPortId !=  0) {
-                mLog.e("non-kernel source portId: " + BitUtils.uint32(srcPortId));
-                break;
-            }
-
-            if (nlMsg instanceof NetlinkErrorMessage) {
-                mLog.e("netlink error: " + nlMsg);
-                continue;
-            } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) {
-                mLog.i("non-rtnetlink neighbor msg: " + nlMsg);
-                continue;
-            }
-
-            evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);
-        }
-    }
-
-    private void evaluateRtNetlinkNeighborMessage(
-            RtNetlinkNeighborMessage neighMsg, long whenMs) {
-        final short msgType = neighMsg.getHeader().nlmsg_type;
-        final StructNdMsg ndMsg = neighMsg.getNdHeader();
-        if (ndMsg == null) {
-            mLog.e("RtNetlinkNeighborMessage without ND message header!");
-            return;
-        }
-
-        final int ifindex = ndMsg.ndm_ifindex;
-        final InetAddress destination = neighMsg.getDestination();
-        final short nudState =
-                (msgType == RTM_DELNEIGH)
-                ? StructNdMsg.NUD_NONE
-                : ndMsg.ndm_state;
-
-        final NeighborEvent event = new NeighborEvent(
-                whenMs, msgType, ifindex, destination, nudState,
-                getMacAddress(neighMsg.getLinkLayerAddress()));
-
-        if (VDBG) {
-            Log.d(TAG, neighMsg.toString());
-        }
-        if (DBG) {
-            Log.d(TAG, event.toString());
-        }
-
-        mConsumer.accept(event);
-    }
-
-    private static MacAddress getMacAddress(byte[] linkLayerAddress) {
-        if (linkLayerAddress != null) {
-            try {
-                return MacAddress.fromBytes(linkLayerAddress);
-            } catch (IllegalArgumentException e) {
-                Log.e(TAG, "Failed to parse link-layer address: " + hexify(linkLayerAddress));
-            }
-        }
-
-        return null;
-    }
-}
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
deleted file mode 100644
index 7e02a28..0000000
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ip;
-
-import android.content.Context;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.LinkProperties.ProvisioningChange;
-import android.net.ProxyInfo;
-import android.net.RouteInfo;
-import android.net.ip.IpNeighborMonitor.NeighborEvent;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.IpReachabilityEvent;
-import android.net.netlink.StructNdMsg;
-import android.net.util.InterfaceParams;
-import android.net.util.MultinetworkPolicyTracker;
-import android.net.util.SharedLog;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.SystemClock;
-import android.system.ErrnoException;
-import android.system.OsConstants;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.DumpUtils.Dump;
-
-import java.io.InterruptedIOException;
-import java.io.PrintWriter;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-
-/**
- * IpReachabilityMonitor.
- *
- * Monitors on-link IP reachability and notifies callers whenever any on-link
- * addresses of interest appear to have become unresponsive.
- *
- * This code does not concern itself with "why" a neighbour might have become
- * unreachable. Instead, it primarily reacts to the kernel's notion of IP
- * reachability for each of the neighbours we know to be critically important
- * to normal network connectivity. As such, it is often "just the messenger":
- * the neighbours about which it warns are already deemed by the kernel to have
- * become unreachable.
- *
- *
- * How it works:
- *
- *   1. The "on-link neighbours of interest" found in a given LinkProperties
- *      instance are added to a "watch list" via #updateLinkProperties().
- *      This usually means all default gateways and any on-link DNS servers.
- *
- *   2. We listen continuously for netlink neighbour messages (RTM_NEWNEIGH,
- *      RTM_DELNEIGH), watching only for neighbours in the watch list.
- *
- *        - A neighbour going into NUD_REACHABLE, NUD_STALE, NUD_DELAY, and
- *          even NUD_PROBE is perfectly normal; we merely record the new state.
- *
- *        - A neighbour's entry may be deleted (RTM_DELNEIGH), for example due
- *          to garbage collection.  This is not necessarily of immediate
- *          concern; we record the neighbour as moving to NUD_NONE.
- *
- *        - A neighbour transitioning to NUD_FAILED (for any reason) is
- *          critically important and is handled as described below in #4.
- *
- *   3. All on-link neighbours in the watch list can be forcibly "probed" by
- *      calling #probeAll(). This should be called whenever it is important to
- *      verify that critical neighbours on the link are still reachable, e.g.
- *      when roaming between BSSIDs.
- *
- *        - The kernel will send unicast ARP requests for IPv4 neighbours and
- *          unicast NS packets for IPv6 neighbours.  The expected replies will
- *          likely be unicast.
- *
- *        - The forced probing is done holding a wakelock. The kernel may,
- *          however, initiate probing of a neighbor on its own, i.e. whenever
- *          a neighbour has expired from NUD_DELAY.
- *
- *        - The kernel sends:
- *
- *              /proc/sys/net/ipv{4,6}/neigh/<ifname>/ucast_solicit
- *
- *          number of probes (usually 3) every:
- *
- *              /proc/sys/net/ipv{4,6}/neigh/<ifname>/retrans_time_ms
- *
- *          number of milliseconds (usually 1000ms). This normally results in
- *          3 unicast packets, 1 per second.
- *
- *        - If no response is received to any of the probe packets, the kernel
- *          marks the neighbour as being in state NUD_FAILED, and the listening
- *          process in #2 will learn of it.
- *
- *   4. We call the supplied Callback#notifyLost() function if the loss of a
- *      neighbour in NUD_FAILED would cause IPv4 or IPv6 configuration to
- *      become incomplete (a loss of provisioning).
- *
- *        - For example, losing all our IPv4 on-link DNS servers (or losing
- *          our only IPv6 default gateway) constitutes a loss of IPv4 (IPv6)
- *          provisioning; Callback#notifyLost() would be called.
- *
- *        - Since it can be non-trivial to reacquire certain IP provisioning
- *          state it may be best for the link to disconnect completely and
- *          reconnect afresh.
- *
- * Accessing an instance of this class from multiple threads is NOT safe.
- *
- * @hide
- */
-public class IpReachabilityMonitor {
-    private static final String TAG = "IpReachabilityMonitor";
-    private static final boolean DBG = false;
-    private static final boolean VDBG = false;
-
-    public interface Callback {
-        // This callback function must execute as quickly as possible as it is
-        // run on the same thread that listens to kernel neighbor updates.
-        //
-        // TODO: refactor to something like notifyProvisioningLost(String msg).
-        public void notifyLost(InetAddress ip, String logMsg);
-    }
-
-    /**
-     * Encapsulates IpReachabilityMonitor depencencies on systems that hinder unit testing.
-     * TODO: consider also wrapping MultinetworkPolicyTracker in this interface.
-     */
-    interface Dependencies {
-        void acquireWakeLock(long durationMs);
-
-        static Dependencies makeDefault(Context context, String iface) {
-            final String lockName = TAG + "." + iface;
-            final PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-            final WakeLock lock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, lockName);
-
-            return new Dependencies() {
-                public void acquireWakeLock(long durationMs) {
-                    lock.acquire(durationMs);
-                }
-            };
-        }
-    }
-
-    private final InterfaceParams mInterfaceParams;
-    private final IpNeighborMonitor mIpNeighborMonitor;
-    private final SharedLog mLog;
-    private final Callback mCallback;
-    private final Dependencies mDependencies;
-    private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
-    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
-    private LinkProperties mLinkProperties = new LinkProperties();
-    private Map<InetAddress, NeighborEvent> mNeighborWatchList = new HashMap<>();
-    // Time in milliseconds of the last forced probe request.
-    private volatile long mLastProbeTimeMs;
-
-    public IpReachabilityMonitor(
-            Context context, InterfaceParams ifParams, Handler h, SharedLog log, Callback callback,
-            MultinetworkPolicyTracker tracker) {
-        this(ifParams, h, log, callback, tracker, Dependencies.makeDefault(context, ifParams.name));
-    }
-
-    @VisibleForTesting
-    IpReachabilityMonitor(InterfaceParams ifParams, Handler h, SharedLog log, Callback callback,
-            MultinetworkPolicyTracker tracker, Dependencies dependencies) {
-        if (ifParams == null) throw new IllegalArgumentException("null InterfaceParams");
-
-        mInterfaceParams = ifParams;
-        mLog = log.forSubComponent(TAG);
-        mCallback = callback;
-        mMultinetworkPolicyTracker = tracker;
-        mDependencies = dependencies;
-
-        mIpNeighborMonitor = new IpNeighborMonitor(h, mLog,
-                (NeighborEvent event) -> {
-                    if (mInterfaceParams.index != event.ifindex) return;
-                    if (!mNeighborWatchList.containsKey(event.ip)) return;
-
-                    final NeighborEvent prev = mNeighborWatchList.put(event.ip, event);
-
-                    // TODO: Consider what to do with other states that are not within
-                    // NeighborEvent#isValid() (i.e. NUD_NONE, NUD_INCOMPLETE).
-                    if (event.nudState == StructNdMsg.NUD_FAILED) {
-                        mLog.w("ALERT neighbor went from: " + prev + " to: " + event);
-                        handleNeighborLost(event);
-                    }
-                });
-        mIpNeighborMonitor.start();
-    }
-
-    public void stop() {
-        mIpNeighborMonitor.stop();
-        clearLinkProperties();
-    }
-
-    public void dump(PrintWriter pw) {
-        DumpUtils.dumpAsync(
-                mIpNeighborMonitor.getHandler(),
-                new Dump() {
-                    @Override
-                    public void dump(PrintWriter pw, String prefix) {
-                        pw.println(describeWatchList("\n"));
-                    }
-                },
-                pw, "", 1000);
-    }
-
-    private String describeWatchList() { return describeWatchList(" "); }
-
-    private String describeWatchList(String sep) {
-        final StringBuilder sb = new StringBuilder();
-        sb.append("iface{" + mInterfaceParams + "}," + sep);
-        sb.append("ntable=[" + sep);
-        String delimiter = "";
-        for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) {
-            sb.append(delimiter).append(entry.getKey().getHostAddress() + "/" + entry.getValue());
-            delimiter = "," + sep;
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-
-    private static boolean isOnLink(List<RouteInfo> routes, InetAddress ip) {
-        for (RouteInfo route : routes) {
-            if (!route.hasGateway() && route.matches(ip)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public void updateLinkProperties(LinkProperties lp) {
-        if (!mInterfaceParams.name.equals(lp.getInterfaceName())) {
-            // TODO: figure out whether / how to cope with interface changes.
-            Log.wtf(TAG, "requested LinkProperties interface '" + lp.getInterfaceName() +
-                    "' does not match: " + mInterfaceParams.name);
-            return;
-        }
-
-        mLinkProperties = new LinkProperties(lp);
-        Map<InetAddress, NeighborEvent> newNeighborWatchList = new HashMap<>();
-
-        final List<RouteInfo> routes = mLinkProperties.getRoutes();
-        for (RouteInfo route : routes) {
-            if (route.hasGateway()) {
-                InetAddress gw = route.getGateway();
-                if (isOnLink(routes, gw)) {
-                    newNeighborWatchList.put(gw, mNeighborWatchList.getOrDefault(gw, null));
-                }
-            }
-        }
-
-        for (InetAddress dns : lp.getDnsServers()) {
-            if (isOnLink(routes, dns)) {
-                newNeighborWatchList.put(dns, mNeighborWatchList.getOrDefault(dns, null));
-            }
-        }
-
-        mNeighborWatchList = newNeighborWatchList;
-        if (DBG) { Log.d(TAG, "watch: " + describeWatchList()); }
-    }
-
-    public void clearLinkProperties() {
-        mLinkProperties.clear();
-        mNeighborWatchList.clear();
-        if (DBG) { Log.d(TAG, "clear: " + describeWatchList()); }
-    }
-
-    private void handleNeighborLost(NeighborEvent event) {
-        final LinkProperties whatIfLp = new LinkProperties(mLinkProperties);
-
-        InetAddress ip = null;
-        for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) {
-            // TODO: Consider using NeighborEvent#isValid() here; it's more
-            // strict but may interact badly if other entries are somehow in
-            // NUD_INCOMPLETE (say, during network attach).
-            if (entry.getValue().nudState != StructNdMsg.NUD_FAILED) continue;
-
-            ip = entry.getKey();
-            for (RouteInfo route : mLinkProperties.getRoutes()) {
-                if (ip.equals(route.getGateway())) {
-                    whatIfLp.removeRoute(route);
-                }
-            }
-
-            if (avoidingBadLinks() || !(ip instanceof Inet6Address)) {
-                // We should do this unconditionally, but alas we cannot: b/31827713.
-                whatIfLp.removeDnsServer(ip);
-            }
-        }
-
-        final ProvisioningChange delta = LinkProperties.compareProvisioning(
-                mLinkProperties, whatIfLp);
-
-        if (delta == ProvisioningChange.LOST_PROVISIONING) {
-            final String logMsg = "FAILURE: LOST_PROVISIONING, " + event;
-            Log.w(TAG, logMsg);
-            if (mCallback != null) {
-                // TODO: remove |ip| when the callback signature no longer has
-                // an InetAddress argument.
-                mCallback.notifyLost(ip, logMsg);
-            }
-        }
-        logNudFailed(delta);
-    }
-
-    private boolean avoidingBadLinks() {
-        return (mMultinetworkPolicyTracker == null) || mMultinetworkPolicyTracker.getAvoidBadWifi();
-    }
-
-    public void probeAll() {
-        final List<InetAddress> ipProbeList = new ArrayList<>(mNeighborWatchList.keySet());
-
-        if (!ipProbeList.isEmpty()) {
-            // Keep the CPU awake long enough to allow all ARP/ND
-            // probes a reasonable chance at success. See b/23197666.
-            //
-            // The wakelock we use is (by default) refcounted, and this version
-            // of acquire(timeout) queues a release message to keep acquisitions
-            // and releases balanced.
-            mDependencies.acquireWakeLock(getProbeWakeLockDuration());
-        }
-
-        for (InetAddress ip : ipProbeList) {
-            final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceParams.index, ip);
-            mLog.log(String.format("put neighbor %s into NUD_PROBE state (rval=%d)",
-                     ip.getHostAddress(), rval));
-            logEvent(IpReachabilityEvent.PROBE, rval);
-        }
-        mLastProbeTimeMs = SystemClock.elapsedRealtime();
-    }
-
-    private static long getProbeWakeLockDuration() {
-        // Ideally, this would be computed by examining the values of:
-        //
-        //     /proc/sys/net/ipv[46]/neigh/<ifname>/ucast_solicit
-        //
-        // and:
-        //
-        //     /proc/sys/net/ipv[46]/neigh/<ifname>/retrans_time_ms
-        //
-        // For now, just make some assumptions.
-        final long numUnicastProbes = 3;
-        final long retransTimeMs = 1000;
-        final long gracePeriodMs = 500;
-        return (numUnicastProbes * retransTimeMs) + gracePeriodMs;
-    }
-
-    private void logEvent(int probeType, int errorCode) {
-        int eventType = probeType | (errorCode & 0xff);
-        mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
-    }
-
-    private void logNudFailed(ProvisioningChange delta) {
-        long duration = SystemClock.elapsedRealtime() - mLastProbeTimeMs;
-        boolean isFromProbe = (duration < getProbeWakeLockDuration());
-        boolean isProvisioningLost = (delta == ProvisioningChange.LOST_PROVISIONING);
-        int eventType = IpReachabilityEvent.nudFailureEventType(isFromProbe, isProvisioningLost);
-        mMetricsLog.log(mInterfaceParams.name, new IpReachabilityEvent(eventType));
-    }
-}
diff --git a/services/net/java/android/net/ip/IpServer.java b/services/net/java/android/net/ip/IpServer.java
index 493350d..f7360f5 100644
--- a/services/net/java/android/net/ip/IpServer.java
+++ b/services/net/java/android/net/ip/IpServer.java
@@ -17,24 +17,30 @@
 package android.net.ip;
 
 import static android.net.NetworkUtils.numericToInetAddress;
-import static android.net.util.NetworkConstants.asByte;
+import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
 import static android.net.util.NetworkConstants.FF;
 import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
+import static android.net.util.NetworkConstants.asByte;
 
+import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.INetd;
+import android.net.INetworkStackStatusCallback;
 import android.net.INetworkStatsService;
 import android.net.InterfaceConfiguration;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
+import android.net.NetworkStack;
 import android.net.RouteInfo;
-import android.net.dhcp.DhcpServer;
-import android.net.dhcp.DhcpServingParams;
+import android.net.dhcp.DhcpServerCallbacks;
+import android.net.dhcp.DhcpServingParamsParcel;
+import android.net.dhcp.DhcpServingParamsParcelExt;
+import android.net.dhcp.IDhcpServer;
 import android.net.ip.RouterAdvertisementDaemon.RaParams;
 import android.net.util.InterfaceParams;
 import android.net.util.InterfaceSet;
-import android.net.util.NetdService;
+import android.net.shared.NetdService;
 import android.net.util.SharedLog;
 import android.os.INetworkManagementService;
 import android.os.Looper;
@@ -126,6 +132,10 @@
     }
 
     public static class Dependencies {
+        private final Context mContext;
+        public Dependencies(Context context) {
+            mContext = context;
+        }
         public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
             return new RouterAdvertisementDaemon(ifParams);
         }
@@ -138,9 +148,12 @@
             return NetdService.getInstance();
         }
 
-        public DhcpServer makeDhcpServer(Looper looper, String ifName,
-                DhcpServingParams params, SharedLog log) {
-            return new DhcpServer(looper, ifName, params, log);
+        /**
+         * Create a DhcpServer instance to be used by IpServer.
+         */
+        public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
+                DhcpServerCallbacks cb) {
+            mContext.getSystemService(NetworkStack.class).makeDhcpServer(ifName, params, cb);
         }
     }
 
@@ -197,7 +210,10 @@
     // Advertisements (otherwise, we do not add them to mLinkProperties at all).
     private LinkProperties mLastIPv6LinkProperties;
     private RouterAdvertisementDaemon mRaDaemon;
-    private DhcpServer mDhcpServer;
+
+    // To be accessed only on the handler thread
+    private int mDhcpServerStartIndex = 0;
+    private IDhcpServer mDhcpServer;
     private RaParams mLastRaParams;
 
     public IpServer(
@@ -210,7 +226,7 @@
         mNetd = deps.getNetdService();
         mStatsService = statsService;
         mCallback = callback;
-        mInterfaceCtrl = new InterfaceController(ifaceName, nMService, mNetd, mLog);
+        mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog);
         mIfaceName = ifaceName;
         mInterfaceType = interfaceType;
         mLinkProperties = new LinkProperties();
@@ -252,35 +268,109 @@
 
     private boolean startIPv4() { return configureIPv4(true); }
 
+    /**
+     * Convenience wrapper around INetworkStackStatusCallback to run callbacks on the IpServer
+     * handler.
+     *
+     * <p>Different instances of this class can be created for each call to IDhcpServer methods,
+     * with different implementations of the callback, to differentiate handling of success/error in
+     * each call.
+     */
+    private abstract class OnHandlerStatusCallback extends INetworkStackStatusCallback.Stub {
+        @Override
+        public void onStatusAvailable(int statusCode) {
+            getHandler().post(() -> callback(statusCode));
+        }
+
+        public abstract void callback(int statusCode);
+    }
+
+    private class DhcpServerCallbacksImpl extends DhcpServerCallbacks {
+        private final int mStartIndex;
+
+        private DhcpServerCallbacksImpl(int startIndex) {
+            mStartIndex = startIndex;
+        }
+
+        @Override
+        public void onDhcpServerCreated(int statusCode, IDhcpServer server) throws RemoteException {
+            getHandler().post(() -> {
+                // We are on the handler thread: mDhcpServerStartIndex can be read safely.
+                if (mStartIndex != mDhcpServerStartIndex) {
+                    // This start request is obsolete. When the |server| binder token goes out of
+                    // scope, the garbage collector will finalize it, which causes the network stack
+                    // process garbage collector to collect the server itself.
+                    return;
+                }
+
+                if (statusCode != STATUS_SUCCESS) {
+                    mLog.e("Error obtaining DHCP server: " + statusCode);
+                    handleError();
+                    return;
+                }
+
+                mDhcpServer = server;
+                try {
+                    mDhcpServer.start(new OnHandlerStatusCallback() {
+                        @Override
+                        public void callback(int startStatusCode) {
+                            if (startStatusCode != STATUS_SUCCESS) {
+                                mLog.e("Error starting DHCP server: " + startStatusCode);
+                                handleError();
+                            }
+                        }
+                    });
+                } catch (RemoteException e) {
+                    e.rethrowFromSystemServer();
+                }
+            });
+        }
+
+        private void handleError() {
+            mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR;
+            transitionTo(mInitialState);
+        }
+    }
+
     private boolean startDhcp(Inet4Address addr, int prefixLen) {
         if (mUsingLegacyDhcp) {
             return true;
         }
-        final DhcpServingParams params;
-        try {
-            params = new DhcpServingParams.Builder()
-                    .setDefaultRouters(addr)
-                    .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
-                    .setDnsServers(addr)
-                    .setServerAddr(new LinkAddress(addr, prefixLen))
-                    .setMetered(true)
-                    .build();
-            // TODO: also advertise link MTU
-        } catch (DhcpServingParams.InvalidParameterException e) {
-            Log.e(TAG, "Invalid DHCP parameters", e);
-            return false;
-        }
+        final DhcpServingParamsParcel params;
+        params = new DhcpServingParamsParcelExt()
+                .setDefaultRouters(addr)
+                .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
+                .setDnsServers(addr)
+                .setServerAddr(new LinkAddress(addr, prefixLen))
+                .setMetered(true);
+        // TODO: also advertise link MTU
 
-        mDhcpServer = mDeps.makeDhcpServer(getHandler().getLooper(), mIfaceName, params,
-                mLog.forSubComponent("DHCP"));
-        mDhcpServer.start();
+        mDhcpServerStartIndex++;
+        mDeps.makeDhcpServer(
+                mIfaceName, params, new DhcpServerCallbacksImpl(mDhcpServerStartIndex));
         return true;
     }
 
     private void stopDhcp() {
+        // Make all previous start requests obsolete so servers are not started later
+        mDhcpServerStartIndex++;
+
         if (mDhcpServer != null) {
-            mDhcpServer.stop();
-            mDhcpServer = null;
+            try {
+                mDhcpServer.stop(new OnHandlerStatusCallback() {
+                    @Override
+                    public void callback(int statusCode) {
+                        if (statusCode != STATUS_SUCCESS) {
+                            mLog.e("Error stopping DHCP server: " + statusCode);
+                            mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR;
+                            // Not much more we can do here
+                        }
+                    }
+                });
+                mDhcpServer = null;
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
         }
     }
 
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index d197d01..8e3023b 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -18,11 +18,15 @@
 
 import static android.net.util.NetworkConstants.IPV6_MIN_MTU;
 import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
-import static android.system.OsConstants.*;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.SOCK_RAW;
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_BINDTODEVICE;
+import static android.system.OsConstants.SO_SNDTIMEO;
 
 import android.net.IpPrefix;
 import android.net.LinkAddress;
-import android.net.LinkProperties;
 import android.net.NetworkUtils;
 import android.net.TrafficStats;
 import android.net.util.InterfaceParams;
@@ -34,10 +38,8 @@
 import com.android.internal.annotations.GuardedBy;
 
 import libcore.io.IoBridge;
-import libcore.util.HexEncoding;
 
 import java.io.FileDescriptor;
-import java.io.InterruptedIOException;
 import java.io.IOException;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -47,7 +49,6 @@
 import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
diff --git a/services/net/java/android/net/netlink/ConntrackMessage.java b/services/net/java/android/net/netlink/ConntrackMessage.java
index 605c46b..6978739 100644
--- a/services/net/java/android/net/netlink/ConntrackMessage.java
+++ b/services/net/java/android/net/netlink/ConntrackMessage.java
@@ -16,23 +16,15 @@
 
 package android.net.netlink;
 
-import static android.net.netlink.NetlinkConstants.alignedLengthOf;
-import static android.net.netlink.StructNlAttr.makeNestedType;
-import static android.net.netlink.StructNlAttr.NLA_HEADERLEN;
 import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
 import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
 import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-import static android.net.util.NetworkConstants.IPV4_ADDR_LEN;
+
 import static java.nio.ByteOrder.BIG_ENDIAN;
 
 import android.system.OsConstants;
-import android.util.Log;
-import libcore.io.SizeOf;
 
 import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
index 40098c1..2a98d90 100644
--- a/services/net/java/android/net/netlink/NetlinkSocket.java
+++ b/services/net/java/android/net/netlink/NetlinkSocket.java
@@ -16,26 +16,26 @@
 
 package android.net.netlink;
 
+import static android.net.util.SocketUtils.makeNetlinkSocketAddress;
 import static android.system.OsConstants.AF_NETLINK;
 import static android.system.OsConstants.EIO;
 import static android.system.OsConstants.EPROTO;
 import static android.system.OsConstants.ETIMEDOUT;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOL_SOCKET;
 import static android.system.OsConstants.SO_RCVBUF;
 import static android.system.OsConstants.SO_RCVTIMEO;
 import static android.system.OsConstants.SO_SNDTIMEO;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOL_SOCKET;
 
 import android.system.ErrnoException;
-import android.system.NetlinkSocketAddress;
 import android.system.Os;
 import android.system.StructTimeval;
 import android.util.Log;
+
 import libcore.io.IoUtils;
 
 import java.io.FileDescriptor;
 import java.io.InterruptedIOException;
-import java.net.SocketAddress;
 import java.net.SocketException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -106,7 +106,7 @@
     }
 
     public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException {
-        Os.connect(fd, (SocketAddress) (new NetlinkSocketAddress(0, 0)));
+        Os.connect(fd, makeNetlinkSocketAddress(0, 0));
     }
 
     private static void checkTimeout(long timeoutMs) {
diff --git a/services/net/java/android/net/netlink/StructNfGenMsg.java b/services/net/java/android/net/netlink/StructNfGenMsg.java
index 99695e2..8155977 100644
--- a/services/net/java/android/net/netlink/StructNfGenMsg.java
+++ b/services/net/java/android/net/netlink/StructNfGenMsg.java
@@ -16,8 +16,6 @@
 
 package android.net.netlink;
 
-import libcore.io.SizeOf;
-
 import java.nio.ByteBuffer;
 
 
@@ -29,7 +27,7 @@
  * @hide
  */
 public class StructNfGenMsg {
-    public static final int STRUCT_SIZE = 2 + SizeOf.SHORT;
+    public static final int STRUCT_SIZE = 2 + Short.BYTES;
 
     public static final int NFNETLINK_V0 = 0;
 
diff --git a/services/net/java/android/net/netlink/StructNlAttr.java b/services/net/java/android/net/netlink/StructNlAttr.java
index 811bdbb..28a4e88 100644
--- a/services/net/java/android/net/netlink/StructNlAttr.java
+++ b/services/net/java/android/net/netlink/StructNlAttr.java
@@ -17,7 +17,6 @@
 package android.net.netlink;
 
 import android.net.netlink.NetlinkConstants;
-import libcore.io.SizeOf;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -117,7 +116,7 @@
     public StructNlAttr(short type, short value, ByteOrder order) {
         this(order);
         nla_type = type;
-        setValue(new byte[SizeOf.SHORT]);
+        setValue(new byte[Short.BYTES]);
         getValueAsByteBuffer().putShort(value);
     }
 
@@ -128,7 +127,7 @@
     public StructNlAttr(short type, int value, ByteOrder order) {
         this(order);
         nla_type = type;
-        setValue(new byte[SizeOf.INT]);
+        setValue(new byte[Integer.BYTES]);
         getValueAsByteBuffer().putInt(value);
     }
 
@@ -164,7 +163,7 @@
 
     public int getValueAsInt(int defaultValue) {
         final ByteBuffer byteBuffer = getValueAsByteBuffer();
-        if (byteBuffer == null || byteBuffer.remaining() != SizeOf.INT) {
+        if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) {
             return defaultValue;
         }
         return getValueAsByteBuffer().getInt();
diff --git a/services/net/java/android/net/netlink/StructNlMsgErr.java b/services/net/java/android/net/netlink/StructNlMsgErr.java
index f095af4..6fcc6e6 100644
--- a/services/net/java/android/net/netlink/StructNlMsgErr.java
+++ b/services/net/java/android/net/netlink/StructNlMsgErr.java
@@ -18,7 +18,6 @@
 
 import android.net.netlink.NetlinkConstants;
 import android.net.netlink.StructNlMsgHdr;
-import libcore.io.SizeOf;
 
 import java.nio.ByteBuffer;
 
@@ -31,7 +30,7 @@
  * @hide
  */
 public class StructNlMsgErr {
-    public static final int STRUCT_SIZE = SizeOf.INT + StructNlMsgHdr.STRUCT_SIZE;
+    public static final int STRUCT_SIZE = Integer.BYTES + StructNlMsgHdr.STRUCT_SIZE;
 
     public static boolean hasAvailableSpace(ByteBuffer byteBuffer) {
         return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE;
diff --git a/services/net/java/android/net/shared/InitialConfiguration.java b/services/net/java/android/net/shared/InitialConfiguration.java
new file mode 100644
index 0000000..bc2373f
--- /dev/null
+++ b/services/net/java/android/net/shared/InitialConfiguration.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static android.net.shared.ParcelableUtil.fromParcelableArray;
+import static android.net.shared.ParcelableUtil.toParcelableArray;
+import static android.text.TextUtils.join;
+
+import android.net.InitialConfigurationParcelable;
+import android.net.IpPrefix;
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddress;
+import android.net.LinkAddressParcelable;
+import android.net.RouteInfo;
+
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+
+/** @hide */
+public class InitialConfiguration {
+    public final Set<LinkAddress> ipAddresses = new HashSet<>();
+    public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>();
+    public final Set<InetAddress> dnsServers = new HashSet<>();
+
+    private static final int RFC6177_MIN_PREFIX_LENGTH = 48;
+    private static final int RFC7421_PREFIX_LENGTH = 64;
+
+    /**
+     * Create a InitialConfiguration that is a copy of the specified configuration.
+     */
+    public static InitialConfiguration copy(InitialConfiguration config) {
+        if (config == null) {
+            return null;
+        }
+        InitialConfiguration configCopy = new InitialConfiguration();
+        configCopy.ipAddresses.addAll(config.ipAddresses);
+        configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes);
+        configCopy.dnsServers.addAll(config.dnsServers);
+        return configCopy;
+    }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s})",
+                join(", ", ipAddresses), join(", ", directlyConnectedRoutes),
+                join(", ", dnsServers));
+    }
+
+    /**
+     * Tests whether the contents of this IpConfiguration represent a valid configuration.
+     */
+    public boolean isValid() {
+        if (ipAddresses.isEmpty()) {
+            return false;
+        }
+
+        // For every IP address, there must be at least one prefix containing that address.
+        for (LinkAddress addr : ipAddresses) {
+            if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) {
+                return false;
+            }
+        }
+        // For every dns server, there must be at least one prefix containing that address.
+        for (InetAddress addr : dnsServers) {
+            if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) {
+                return false;
+            }
+        }
+        // All IPv6 LinkAddresses have an RFC7421-suitable prefix length
+        // (read: compliant with RFC4291#section2.5.4).
+        if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) {
+            return false;
+        }
+        // If directlyConnectedRoutes contains an IPv6 default route
+        // then ipAddresses MUST contain at least one non-ULA GUA.
+        if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute)
+                && all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) {
+            return false;
+        }
+        // The prefix length of routes in directlyConnectedRoutes be within reasonable
+        // bounds for IPv6: /48-/64 just as we’d accept in RIOs.
+        if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) {
+            return false;
+        }
+        // There no more than one IPv4 address
+        if (ipAddresses.stream().filter(LinkAddress::isIPv4).count() > 1) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @return true if the given list of addressess and routes satisfies provisioning for this
+     * InitialConfiguration. LinkAddresses and RouteInfo objects are not compared with equality
+     * because addresses and routes seen by Netlink will contain additional fields like flags,
+     * interfaces, and so on. If this InitialConfiguration has no IP address specified, the
+     * provisioning check always fails.
+     *
+     * If the given list of routes is null, only addresses are taken into considerations.
+     */
+    public boolean isProvisionedBy(List<LinkAddress> addresses, List<RouteInfo> routes) {
+        if (ipAddresses.isEmpty()) {
+            return false;
+        }
+
+        for (LinkAddress addr : ipAddresses) {
+            if (!any(addresses, (addrSeen) -> addr.isSameAddressAs(addrSeen))) {
+                return false;
+            }
+        }
+
+        if (routes != null) {
+            for (IpPrefix prefix : directlyConnectedRoutes) {
+                if (!any(routes, (routeSeen) -> isDirectlyConnectedRoute(routeSeen, prefix))) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Convert this configuration to a {@link InitialConfigurationParcelable}.
+     */
+    public InitialConfigurationParcelable toStableParcelable() {
+        final InitialConfigurationParcelable p = new InitialConfigurationParcelable();
+        p.ipAddresses = toParcelableArray(ipAddresses,
+                LinkPropertiesParcelableUtil::toStableParcelable, LinkAddressParcelable.class);
+        p.directlyConnectedRoutes = toParcelableArray(directlyConnectedRoutes,
+                LinkPropertiesParcelableUtil::toStableParcelable, IpPrefixParcelable.class);
+        p.dnsServers = toParcelableArray(
+                dnsServers, IpConfigurationParcelableUtil::parcelAddress, String.class);
+        return p;
+    }
+
+    /**
+     * Create an instance of {@link InitialConfiguration} based on the contents of the specified
+     * {@link InitialConfigurationParcelable}.
+     */
+    public static InitialConfiguration fromStableParcelable(InitialConfigurationParcelable p) {
+        if (p == null) return null;
+        final InitialConfiguration config = new InitialConfiguration();
+        config.ipAddresses.addAll(fromParcelableArray(
+                p.ipAddresses, LinkPropertiesParcelableUtil::fromStableParcelable));
+        config.directlyConnectedRoutes.addAll(fromParcelableArray(
+                p.directlyConnectedRoutes, LinkPropertiesParcelableUtil::fromStableParcelable));
+        config.dnsServers.addAll(
+                fromParcelableArray(p.dnsServers, IpConfigurationParcelableUtil::unparcelAddress));
+        return config;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof InitialConfiguration)) return false;
+        final InitialConfiguration other = (InitialConfiguration) obj;
+        return ipAddresses.equals(other.ipAddresses)
+                && directlyConnectedRoutes.equals(other.directlyConnectedRoutes)
+                && dnsServers.equals(other.dnsServers);
+    }
+
+    private static boolean isDirectlyConnectedRoute(RouteInfo route, IpPrefix prefix) {
+        return !route.hasGateway() && prefix.equals(route.getDestination());
+    }
+
+    private static boolean isPrefixLengthCompliant(LinkAddress addr) {
+        return addr.isIPv4() || isCompliantIPv6PrefixLength(addr.getPrefixLength());
+    }
+
+    private static boolean isPrefixLengthCompliant(IpPrefix prefix) {
+        return prefix.isIPv4() || isCompliantIPv6PrefixLength(prefix.getPrefixLength());
+    }
+
+    private static boolean isCompliantIPv6PrefixLength(int prefixLength) {
+        return (RFC6177_MIN_PREFIX_LENGTH <= prefixLength)
+                && (prefixLength <= RFC7421_PREFIX_LENGTH);
+    }
+
+    private static boolean isIPv6DefaultRoute(IpPrefix prefix) {
+        return prefix.getAddress().equals(Inet6Address.ANY);
+    }
+
+    private static boolean isIPv6GUA(LinkAddress addr) {
+        return addr.isIPv6() && addr.isGlobalPreferred();
+    }
+
+    // TODO: extract out into CollectionUtils.
+
+    /**
+     * Indicate whether any element of the specified iterable verifies the specified predicate.
+     */
+    public static <T> boolean any(Iterable<T> coll, Predicate<T> fn) {
+        for (T t : coll) {
+            if (fn.test(t)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Indicate whether all elements of the specified iterable verifies the specified predicate.
+     */
+    public static <T> boolean all(Iterable<T> coll, Predicate<T> fn) {
+        return !any(coll, not(fn));
+    }
+
+    /**
+     * Create a predicate that returns the opposite value of the specified predicate.
+     */
+    public static <T> Predicate<T> not(Predicate<T> fn) {
+        return (t) -> !fn.test(t);
+    }
+}
diff --git a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
new file mode 100644
index 0000000..2c368c8
--- /dev/null
+++ b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static android.net.shared.ParcelableUtil.fromParcelableArray;
+import static android.net.shared.ParcelableUtil.toParcelableArray;
+
+import android.annotation.Nullable;
+import android.net.ApfCapabilitiesParcelable;
+import android.net.DhcpResults;
+import android.net.DhcpResultsParcelable;
+import android.net.InetAddresses;
+import android.net.StaticIpConfiguration;
+import android.net.StaticIpConfigurationParcelable;
+import android.net.apf.ApfCapabilities;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+
+/**
+ * Collection of utility methods to convert to and from stable AIDL parcelables for IpClient
+ * configuration classes.
+ * @hide
+ */
+public final class IpConfigurationParcelableUtil {
+    /**
+     * Convert a StaticIpConfiguration to a StaticIpConfigurationParcelable.
+     */
+    public static StaticIpConfigurationParcelable toStableParcelable(
+            @Nullable StaticIpConfiguration config) {
+        if (config == null) return null;
+        final StaticIpConfigurationParcelable p = new StaticIpConfigurationParcelable();
+        p.ipAddress = LinkPropertiesParcelableUtil.toStableParcelable(config.ipAddress);
+        p.gateway = parcelAddress(config.gateway);
+        p.dnsServers = toParcelableArray(
+                config.dnsServers, IpConfigurationParcelableUtil::parcelAddress, String.class);
+        p.domains = config.domains;
+        return p;
+    }
+
+    /**
+     * Convert a StaticIpConfigurationParcelable to a StaticIpConfiguration.
+     */
+    public static StaticIpConfiguration fromStableParcelable(
+            @Nullable StaticIpConfigurationParcelable p) {
+        if (p == null) return null;
+        final StaticIpConfiguration config = new StaticIpConfiguration();
+        config.ipAddress = LinkPropertiesParcelableUtil.fromStableParcelable(p.ipAddress);
+        config.gateway = unparcelAddress(p.gateway);
+        config.dnsServers.addAll(fromParcelableArray(
+                p.dnsServers, IpConfigurationParcelableUtil::unparcelAddress));
+        config.domains = p.domains;
+        return config;
+    }
+
+    /**
+     * Convert DhcpResults to a DhcpResultsParcelable.
+     */
+    public static DhcpResultsParcelable toStableParcelable(@Nullable DhcpResults results) {
+        if (results == null) return null;
+        final DhcpResultsParcelable p = new DhcpResultsParcelable();
+        p.baseConfiguration = toStableParcelable((StaticIpConfiguration) results);
+        p.leaseDuration = results.leaseDuration;
+        p.mtu = results.mtu;
+        p.serverAddress = parcelAddress(results.serverAddress);
+        p.vendorInfo = results.vendorInfo;
+        return p;
+    }
+
+    /**
+     * Convert a DhcpResultsParcelable to DhcpResults.
+     */
+    public static DhcpResults fromStableParcelable(@Nullable DhcpResultsParcelable p) {
+        if (p == null) return null;
+        final DhcpResults results = new DhcpResults(fromStableParcelable(p.baseConfiguration));
+        results.leaseDuration = p.leaseDuration;
+        results.mtu = p.mtu;
+        results.serverAddress = (Inet4Address) unparcelAddress(p.serverAddress);
+        results.vendorInfo = p.vendorInfo;
+        return results;
+    }
+
+    /**
+     * Convert ApfCapabilities to ApfCapabilitiesParcelable.
+     */
+    public static ApfCapabilitiesParcelable toStableParcelable(@Nullable ApfCapabilities caps) {
+        if (caps == null) return null;
+        final ApfCapabilitiesParcelable p = new ApfCapabilitiesParcelable();
+        p.apfVersionSupported = caps.apfVersionSupported;
+        p.maximumApfProgramSize = caps.maximumApfProgramSize;
+        p.apfPacketFormat = caps.apfPacketFormat;
+        return p;
+    }
+
+    /**
+     * Convert ApfCapabilitiesParcelable toApfCapabilities.
+     */
+    public static ApfCapabilities fromStableParcelable(@Nullable ApfCapabilitiesParcelable p) {
+        if (p == null) return null;
+        return new ApfCapabilities(
+                p.apfVersionSupported, p.maximumApfProgramSize, p.apfPacketFormat);
+    }
+
+    /**
+     * Convert InetAddress to String.
+     * TODO: have an InetAddressParcelable
+     */
+    public static String parcelAddress(@Nullable InetAddress addr) {
+        if (addr == null) return null;
+        return addr.getHostAddress();
+    }
+
+    /**
+     * Convert String to InetAddress.
+     * TODO: have an InetAddressParcelable
+     */
+    public static InetAddress unparcelAddress(@Nullable String addr) {
+        if (addr == null) return null;
+        return InetAddresses.parseNumericAddress(addr);
+    }
+}
diff --git a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
new file mode 100644
index 0000000..51d955d
--- /dev/null
+++ b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static android.net.shared.IpConfigurationParcelableUtil.parcelAddress;
+import static android.net.shared.IpConfigurationParcelableUtil.unparcelAddress;
+import static android.net.shared.ParcelableUtil.fromParcelableArray;
+import static android.net.shared.ParcelableUtil.toParcelableArray;
+
+import android.annotation.Nullable;
+import android.net.IpPrefix;
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddress;
+import android.net.LinkAddressParcelable;
+import android.net.LinkProperties;
+import android.net.LinkPropertiesParcelable;
+import android.net.ProxyInfo;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfo;
+import android.net.RouteInfoParcelable;
+import android.net.Uri;
+
+import java.util.Arrays;
+
+/**
+ * Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties
+ * and its attributes.
+ * @hide
+ */
+public final class LinkPropertiesParcelableUtil {
+
+    /**
+     * Convert a ProxyInfo to a ProxyInfoParcelable
+     */
+    public static ProxyInfoParcelable toStableParcelable(@Nullable ProxyInfo proxyInfo) {
+        if (proxyInfo == null) {
+            return null;
+        }
+        final ProxyInfoParcelable parcel = new ProxyInfoParcelable();
+        parcel.host = proxyInfo.getHost();
+        parcel.port = proxyInfo.getPort();
+        parcel.exclusionList = proxyInfo.getExclusionList();
+        parcel.pacFileUrl = proxyInfo.getPacFileUrl().toString();
+        return parcel;
+    }
+
+    /**
+     * Convert a ProxyInfoParcelable to a ProxyInfo
+     */
+    public static ProxyInfo fromStableParcelable(@Nullable ProxyInfoParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        if (Uri.EMPTY.toString().equals(parcel.pacFileUrl)) {
+            return ProxyInfo.buildDirectProxy(
+                    parcel.host, parcel.port, Arrays.asList(parcel.exclusionList));
+        } else {
+            return ProxyInfo.buildPacProxy(Uri.parse(parcel.pacFileUrl));
+        }
+    }
+
+    /**
+     * Convert an IpPrefixParcelable to an IpPrefix
+     */
+    public static IpPrefixParcelable toStableParcelable(@Nullable IpPrefix ipPrefix) {
+        if (ipPrefix == null) {
+            return null;
+        }
+        final IpPrefixParcelable parcel = new IpPrefixParcelable();
+        parcel.address = parcelAddress(ipPrefix.getAddress());
+        parcel.prefixLength = ipPrefix.getPrefixLength();
+        return parcel;
+    }
+
+    /**
+     * Convert an IpPrefix to an IpPrefixParcelable
+     */
+    public static IpPrefix fromStableParcelable(@Nullable IpPrefixParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        return new IpPrefix(unparcelAddress(parcel.address), parcel.prefixLength);
+    }
+
+    /**
+     * Convert a RouteInfoParcelable to a RouteInfo
+     */
+    public static RouteInfoParcelable toStableParcelable(@Nullable RouteInfo routeInfo) {
+        if (routeInfo == null) {
+            return null;
+        }
+        final RouteInfoParcelable parcel = new RouteInfoParcelable();
+        parcel.destination = toStableParcelable(routeInfo.getDestination());
+        parcel.gatewayAddr = parcelAddress(routeInfo.getGateway());
+        parcel.ifaceName = routeInfo.getInterface();
+        parcel.type = routeInfo.getType();
+        return parcel;
+    }
+
+    /**
+     * Convert a RouteInfo to a RouteInfoParcelable
+     */
+    public static RouteInfo fromStableParcelable(@Nullable RouteInfoParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        final IpPrefix destination = fromStableParcelable(parcel.destination);
+        return new RouteInfo(
+                destination, unparcelAddress(parcel.gatewayAddr),
+                parcel.ifaceName, parcel.type);
+    }
+
+    /**
+     * Convert a LinkAddressParcelable to a LinkAddress
+     */
+    public static LinkAddressParcelable toStableParcelable(@Nullable LinkAddress la) {
+        if (la == null) {
+            return null;
+        }
+        final LinkAddressParcelable parcel = new LinkAddressParcelable();
+        parcel.address = parcelAddress(la.getAddress());
+        parcel.prefixLength = la.getPrefixLength();
+        parcel.flags = la.getFlags();
+        parcel.scope = la.getScope();
+        return parcel;
+    }
+
+    /**
+     * Convert a LinkAddress to a LinkAddressParcelable
+     */
+    public static LinkAddress fromStableParcelable(@Nullable LinkAddressParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        return new LinkAddress(
+                unparcelAddress(parcel.address),
+                parcel.prefixLength,
+                parcel.flags,
+                parcel.scope);
+    }
+
+    /**
+     * Convert a LinkProperties to a LinkPropertiesParcelable
+     */
+    public static LinkPropertiesParcelable toStableParcelable(@Nullable LinkProperties lp) {
+        if (lp == null) {
+            return null;
+        }
+        final LinkPropertiesParcelable parcel = new LinkPropertiesParcelable();
+        parcel.ifaceName = lp.getInterfaceName();
+        parcel.linkAddresses = toParcelableArray(
+                lp.getLinkAddresses(),
+                LinkPropertiesParcelableUtil::toStableParcelable,
+                LinkAddressParcelable.class);
+        parcel.dnses = toParcelableArray(
+                lp.getDnsServers(), IpConfigurationParcelableUtil::parcelAddress, String.class);
+        parcel.pcscfs = toParcelableArray(
+                lp.getPcscfServers(), IpConfigurationParcelableUtil::parcelAddress, String.class);
+        parcel.validatedPrivateDnses = toParcelableArray(lp.getValidatedPrivateDnsServers(),
+                IpConfigurationParcelableUtil::parcelAddress, String.class);
+        parcel.usePrivateDns = lp.isPrivateDnsActive();
+        parcel.privateDnsServerName = lp.getPrivateDnsServerName();
+        parcel.domains = lp.getDomains();
+        parcel.routes = toParcelableArray(
+                lp.getRoutes(), LinkPropertiesParcelableUtil::toStableParcelable,
+                RouteInfoParcelable.class);
+        parcel.httpProxy = toStableParcelable(lp.getHttpProxy());
+        parcel.mtu = lp.getMtu();
+        parcel.tcpBufferSizes = lp.getTcpBufferSizes();
+        parcel.nat64Prefix = toStableParcelable(lp.getNat64Prefix());
+        return parcel;
+    }
+
+    /**
+     * Convert a LinkPropertiesParcelable to a LinkProperties
+     */
+    public static LinkProperties fromStableParcelable(@Nullable LinkPropertiesParcelable parcel) {
+        if (parcel == null) {
+            return null;
+        }
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(parcel.ifaceName);
+        lp.setLinkAddresses(fromParcelableArray(parcel.linkAddresses,
+                LinkPropertiesParcelableUtil::fromStableParcelable));
+        lp.setDnsServers(fromParcelableArray(
+                parcel.dnses, IpConfigurationParcelableUtil::unparcelAddress));
+        lp.setPcscfServers(fromParcelableArray(
+                parcel.pcscfs, IpConfigurationParcelableUtil::unparcelAddress));
+        lp.setValidatedPrivateDnsServers(
+                fromParcelableArray(parcel.validatedPrivateDnses,
+                IpConfigurationParcelableUtil::unparcelAddress));
+        lp.setUsePrivateDns(parcel.usePrivateDns);
+        lp.setPrivateDnsServerName(parcel.privateDnsServerName);
+        lp.setDomains(parcel.domains);
+        for (RouteInfoParcelable route : parcel.routes) {
+            lp.addRoute(fromStableParcelable(route));
+        }
+        lp.setHttpProxy(fromStableParcelable(parcel.httpProxy));
+        lp.setMtu(parcel.mtu);
+        lp.setTcpBufferSizes(parcel.tcpBufferSizes);
+        lp.setNat64Prefix(fromStableParcelable(parcel.nat64Prefix));
+        return lp;
+    }
+}
diff --git a/services/net/java/android/net/shared/NetdService.java b/services/net/java/android/net/shared/NetdService.java
new file mode 100644
index 0000000..be0f5f2
--- /dev/null
+++ b/services/net/java/android/net/shared/NetdService.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import android.net.INetd;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+
+/**
+ * @hide
+ */
+public class NetdService {
+    private static final String TAG = NetdService.class.getSimpleName();
+    private static final String NETD_SERVICE_NAME = "netd";
+    private static final long BASE_TIMEOUT_MS = 100;
+    private static final long MAX_TIMEOUT_MS = 1000;
+
+
+    /**
+     * Return an INetd instance, or null if not available.
+     *
+     * It is the caller's responsibility to check for a null return value
+     * and to handle RemoteException errors from invocations on the returned
+     * interface if, for example, netd dies and is restarted.
+     *
+     * Returned instances of INetd should not be cached.
+     *
+     * @return an INetd instance or null.
+     */
+    public static INetd getInstance() {
+        // NOTE: ServiceManager does no caching for the netd service,
+        // because netd is not one of the defined common services.
+        final INetd netdInstance = INetd.Stub.asInterface(
+                ServiceManager.getService(NETD_SERVICE_NAME));
+        if (netdInstance == null) {
+            Log.w(TAG, "WARNING: returning null INetd instance.");
+        }
+        return netdInstance;
+    }
+
+    /**
+     * Blocks for a specified time until an INetd instance is available.
+     *
+     * It is the caller's responsibility to handle RemoteException errors
+     * from invocations on the returned interface if, for example, netd
+     * dies after this interface was returned.
+     *
+     * Returned instances of INetd should not be cached.
+     *
+     * Special values of maxTimeoutMs include: 0, meaning try to obtain an
+     * INetd instance only once, and -1 (or any value less than 0), meaning
+     * try to obtain an INetd instance indefinitely.
+     *
+     * @param maxTimeoutMs the maximum time to spend getting an INetd instance
+     * @return an INetd instance or null if no instance is available
+     * within |maxTimeoutMs| milliseconds.
+     */
+    public static INetd get(long maxTimeoutMs) {
+        if (maxTimeoutMs == 0) return getInstance();
+
+        final long stop = (maxTimeoutMs > 0)
+                ? SystemClock.elapsedRealtime() + maxTimeoutMs
+                : Long.MAX_VALUE;
+
+        long timeoutMs = 0;
+        while (true) {
+            final INetd netdInstance = getInstance();
+            if (netdInstance != null) {
+                return netdInstance;
+            }
+
+            final long remaining = stop - SystemClock.elapsedRealtime();
+            if (remaining <= 0) break;
+
+            // No netdInstance was received; sleep and retry.
+            timeoutMs = Math.min(timeoutMs + BASE_TIMEOUT_MS, MAX_TIMEOUT_MS);
+            timeoutMs = Math.min(timeoutMs, remaining);
+            try {
+                Thread.sleep(timeoutMs);
+            } catch (InterruptedException e) {}
+        }
+        return null;
+    }
+
+    /**
+     * Blocks until an INetd instance is available.
+     *
+     * It is the caller's responsibility to handle RemoteException errors
+     * from invocations on the returned interface if, for example, netd
+     * dies after this interface was returned.
+     *
+     * Returned instances of INetd should not be cached.
+     *
+     * @return an INetd instance.
+     */
+    public static INetd get() {
+        return get(-1);
+    }
+
+    public static interface NetdCommand {
+        void run(INetd netd) throws RemoteException;
+    }
+
+    /**
+     * Blocks until an INetd instance is availabe, and retries until either
+     * the command succeeds or a runtime exception is thrown.
+     */
+    public static void run(NetdCommand cmd) {
+        while (true) {
+            try {
+                cmd.run(get());
+                return;
+            } catch (RemoteException re) {
+                Log.e(TAG, "error communicating with netd: " + re);
+            }
+        }
+    }
+}
diff --git a/services/net/java/android/net/shared/NetworkMonitorUtils.java b/services/net/java/android/net/shared/NetworkMonitorUtils.java
new file mode 100644
index 0000000..3d2a2de
--- /dev/null
+++ b/services/net/java/android/net/shared/NetworkMonitorUtils.java
@@ -0,0 +1,74 @@
+/*
+ * 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.shared;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+
+import android.content.Context;
+import android.net.NetworkCapabilities;
+import android.provider.Settings;
+
+/** @hide */
+public class NetworkMonitorUtils {
+
+    // Network conditions broadcast constants
+    public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
+            "android.net.conn.NETWORK_CONDITIONS_MEASURED";
+    public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
+    public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
+    public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
+    public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
+    public static final String EXTRA_CELL_ID = "extra_cellid";
+    public static final String EXTRA_SSID = "extra_ssid";
+    public static final String EXTRA_BSSID = "extra_bssid";
+    /** real time since boot */
+    public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
+    public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
+    public static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
+            "android.permission.ACCESS_NETWORK_CONDITIONS";
+
+    // TODO: once the URL is a resource overlay, remove and have the resource define the default
+    private static final String DEFAULT_HTTP_URL =
+            "http://connectivitycheck.gstatic.com/generate_204";
+
+    /**
+     * Get the captive portal server HTTP URL that is configured on the device.
+     */
+    public static String getCaptivePortalServerHttpUrl(Context context) {
+        final String settingUrl = Settings.Global.getString(
+                context.getContentResolver(),
+                Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
+        return settingUrl != null ? settingUrl : DEFAULT_HTTP_URL;
+    }
+
+    /**
+     * Return whether validation is required for a network.
+     * @param dfltNetCap Default requested network capabilities.
+     * @param nc Network capabilities of the network to test.
+     */
+    public static boolean isValidationRequired(NetworkCapabilities nc) {
+        // TODO: Consider requiring validation for DUN networks.
+        return nc != null
+                && nc.hasCapability(NET_CAPABILITY_INTERNET)
+                && nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
+                && nc.hasCapability(NET_CAPABILITY_TRUSTED)
+                && nc.hasCapability(NET_CAPABILITY_NOT_VPN);
+    }
+}
diff --git a/services/net/java/android/net/shared/NetworkParcelableUtil.java b/services/net/java/android/net/shared/NetworkParcelableUtil.java
new file mode 100644
index 0000000..d0b54b8
--- /dev/null
+++ b/services/net/java/android/net/shared/NetworkParcelableUtil.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import android.annotation.Nullable;
+import android.net.Network;
+import android.net.NetworkParcelable;
+
+/**
+ * Utility methods to convert to/from stable AIDL parcelables for network attribute classes.
+ * @hide
+ */
+public final class NetworkParcelableUtil {
+    /**
+     * Convert from a Network to a NetworkParcelable.
+     */
+    public static NetworkParcelable toStableParcelable(@Nullable Network network) {
+        if (network == null) {
+            return null;
+        }
+        final NetworkParcelable p = new NetworkParcelable();
+        p.networkHandle = network.getNetworkHandle();
+
+        return p;
+    }
+
+    /**
+     * Convert from a NetworkParcelable to a Network.
+     */
+    public static Network fromStableParcelable(@Nullable NetworkParcelable p) {
+        if (p == null) {
+            return null;
+        }
+        return Network.fromNetworkHandle(p.networkHandle);
+    }
+}
diff --git a/services/net/java/android/net/shared/ParcelableUtil.java b/services/net/java/android/net/shared/ParcelableUtil.java
new file mode 100644
index 0000000..3f40300
--- /dev/null
+++ b/services/net/java/android/net/shared/ParcelableUtil.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import android.annotation.NonNull;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.function.Function;
+
+/**
+ * Utility methods to help convert to/from stable parcelables.
+ * @hide
+ */
+public final class ParcelableUtil {
+    // Below methods could be implemented easily with streams, but streams are frowned upon in
+    // frameworks code.
+
+    /**
+     * Convert a list of BaseType items to an array of ParcelableType items using the specified
+     * converter function.
+     */
+    public static <ParcelableType, BaseType> ParcelableType[] toParcelableArray(
+            @NonNull Collection<BaseType> base,
+            @NonNull Function<BaseType, ParcelableType> conv,
+            @NonNull Class<ParcelableType> parcelClass) {
+        final ParcelableType[] out = (ParcelableType[]) Array.newInstance(parcelClass, base.size());
+        int i = 0;
+        for (BaseType b : base) {
+            out[i] = conv.apply(b);
+            i++;
+        }
+        return out;
+    }
+
+    /**
+     * Convert an array of ParcelableType items to a list of BaseType items using the specified
+     * converter function.
+     */
+    public static <ParcelableType, BaseType> ArrayList<BaseType> fromParcelableArray(
+            @NonNull ParcelableType[] parceled, @NonNull Function<ParcelableType, BaseType> conv) {
+        final ArrayList<BaseType> out = new ArrayList<>(parceled.length);
+        for (ParcelableType t : parceled) {
+            out.add(conv.apply(t));
+        }
+        return out;
+    }
+}
diff --git a/services/net/java/android/net/shared/PrivateDnsConfig.java b/services/net/java/android/net/shared/PrivateDnsConfig.java
new file mode 100644
index 0000000..c7dc530
--- /dev/null
+++ b/services/net/java/android/net/shared/PrivateDnsConfig.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 android.net.shared;
+
+import static android.net.shared.ParcelableUtil.fromParcelableArray;
+import static android.net.shared.ParcelableUtil.toParcelableArray;
+
+import android.net.PrivateDnsConfigParcel;
+import android.text.TextUtils;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+
+/** @hide */
+public class PrivateDnsConfig {
+    public final boolean useTls;
+    public final String hostname;
+    public final InetAddress[] ips;
+
+    public PrivateDnsConfig() {
+        this(false);
+    }
+
+    public PrivateDnsConfig(boolean useTls) {
+        this.useTls = useTls;
+        this.hostname = "";
+        this.ips = new InetAddress[0];
+    }
+
+    public PrivateDnsConfig(String hostname, InetAddress[] ips) {
+        this.useTls = !TextUtils.isEmpty(hostname);
+        this.hostname = useTls ? hostname : "";
+        this.ips = (ips != null) ? ips : new InetAddress[0];
+    }
+
+    public PrivateDnsConfig(PrivateDnsConfig cfg) {
+        useTls = cfg.useTls;
+        hostname = cfg.hostname;
+        ips = cfg.ips;
+    }
+
+    /**
+     * Indicates whether this is a strict mode private DNS configuration.
+     */
+    public boolean inStrictMode() {
+        return useTls && !TextUtils.isEmpty(hostname);
+    }
+
+    @Override
+    public String toString() {
+        return PrivateDnsConfig.class.getSimpleName()
+                + "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}";
+    }
+
+    /**
+     * Create a stable AIDL-compatible parcel from the current instance.
+     */
+    public PrivateDnsConfigParcel toParcel() {
+        final PrivateDnsConfigParcel parcel = new PrivateDnsConfigParcel();
+        parcel.hostname = hostname;
+        parcel.ips = toParcelableArray(
+                Arrays.asList(ips), IpConfigurationParcelableUtil::parcelAddress, String.class);
+
+        return parcel;
+    }
+
+    /**
+     * Build a configuration from a stable AIDL-compatible parcel.
+     */
+    public static PrivateDnsConfig fromParcel(PrivateDnsConfigParcel parcel) {
+        InetAddress[] ips = new InetAddress[parcel.ips.length];
+        ips = fromParcelableArray(parcel.ips, IpConfigurationParcelableUtil::unparcelAddress)
+                .toArray(ips);
+        return new PrivateDnsConfig(parcel.hostname, ips);
+    }
+}
diff --git a/services/net/java/android/net/shared/ProvisioningConfiguration.java b/services/net/java/android/net/shared/ProvisioningConfiguration.java
new file mode 100644
index 0000000..f937065
--- /dev/null
+++ b/services/net/java/android/net/shared/ProvisioningConfiguration.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import android.annotation.Nullable;
+import android.net.INetd;
+import android.net.Network;
+import android.net.ProvisioningConfigurationParcelable;
+import android.net.StaticIpConfiguration;
+import android.net.apf.ApfCapabilities;
+import android.net.ip.IIpClient;
+
+import java.util.Objects;
+import java.util.StringJoiner;
+
+/**
+ * This class encapsulates parameters to be passed to
+ * IpClient#startProvisioning(). A defensive copy is made by IpClient
+ * and the values specified herein are in force until IpClient#stop()
+ * is called.
+ *
+ * Example use:
+ *
+ *     final ProvisioningConfiguration config =
+ *             new ProvisioningConfiguration.Builder()
+ *                     .withPreDhcpAction()
+ *                     .withProvisioningTimeoutMs(36 * 1000)
+ *                     .build();
+ *     mIpClient.startProvisioning(config.toStableParcelable());
+ *     ...
+ *     mIpClient.stop();
+ *
+ * The specified provisioning configuration will only be active until
+ * IIpClient#stop() is called. Future calls to IIpClient#startProvisioning()
+ * must specify the configuration again.
+ * @hide
+ */
+public class ProvisioningConfiguration {
+    // TODO: Delete this default timeout once those callers that care are
+    // fixed to pass in their preferred timeout.
+    //
+    // We pick 36 seconds so we can send DHCP requests at
+    //
+    //     t=0, t=2, t=6, t=14, t=30
+    //
+    // allowing for 10% jitter.
+    private static final int DEFAULT_TIMEOUT_MS = 36 * 1000;
+
+    /**
+     * Builder to create a {@link ProvisioningConfiguration}.
+     */
+    public static class Builder {
+        protected ProvisioningConfiguration mConfig = new ProvisioningConfiguration();
+
+        /**
+         * Specify that the configuration should not enable IPv4. It is enabled by default.
+         */
+        public Builder withoutIPv4() {
+            mConfig.mEnableIPv4 = false;
+            return this;
+        }
+
+        /**
+         * Specify that the configuration should not enable IPv6. It is enabled by default.
+         */
+        public Builder withoutIPv6() {
+            mConfig.mEnableIPv6 = false;
+            return this;
+        }
+
+        /**
+         * Specify that the configuration should not use a MultinetworkPolicyTracker. It is used
+         * by default.
+         */
+        public Builder withoutMultinetworkPolicyTracker() {
+            mConfig.mUsingMultinetworkPolicyTracker = false;
+            return this;
+        }
+
+        /**
+         * Specify that the configuration should not use a IpReachabilityMonitor. It is used by
+         * default.
+         */
+        public Builder withoutIpReachabilityMonitor() {
+            mConfig.mUsingIpReachabilityMonitor = false;
+            return this;
+        }
+
+        /**
+         * Identical to {@link #withPreDhcpAction(int)}, using a default timeout.
+         * @see #withPreDhcpAction(int)
+         */
+        public Builder withPreDhcpAction() {
+            mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS;
+            return this;
+        }
+
+        /**
+         * Specify that {@link IpClientCallbacks#onPreDhcpAction()} should be called. Clients must
+         * call {@link IIpClient#completedPreDhcpAction()} when the callback called. This behavior
+         * is disabled by default.
+         * @param dhcpActionTimeoutMs Timeout for clients to call completedPreDhcpAction().
+         */
+        public Builder withPreDhcpAction(int dhcpActionTimeoutMs) {
+            mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs;
+            return this;
+        }
+
+        /**
+         * Specify the initial provisioning configuration.
+         */
+        public Builder withInitialConfiguration(InitialConfiguration initialConfig) {
+            mConfig.mInitialConfig = initialConfig;
+            return this;
+        }
+
+        /**
+         * Specify a static configuration for provisioning.
+         */
+        public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
+            mConfig.mStaticIpConfig = staticConfig;
+            return this;
+        }
+
+        /**
+         * Specify ApfCapabilities.
+         */
+        public Builder withApfCapabilities(ApfCapabilities apfCapabilities) {
+            mConfig.mApfCapabilities = apfCapabilities;
+            return this;
+        }
+
+        /**
+         * Specify the timeout to use for provisioning.
+         */
+        public Builder withProvisioningTimeoutMs(int timeoutMs) {
+            mConfig.mProvisioningTimeoutMs = timeoutMs;
+            return this;
+        }
+
+        /**
+         * Specify that IPv6 address generation should use a random MAC address.
+         */
+        public Builder withRandomMacAddress() {
+            mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64;
+            return this;
+        }
+
+        /**
+         * Specify that IPv6 address generation should use a stable MAC address.
+         */
+        public Builder withStableMacAddress() {
+            mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
+            return this;
+        }
+
+        /**
+         * Specify the network to use for provisioning.
+         */
+        public Builder withNetwork(Network network) {
+            mConfig.mNetwork = network;
+            return this;
+        }
+
+        /**
+         * Specify the display name that the IpClient should use.
+         */
+        public Builder withDisplayName(String displayName) {
+            mConfig.mDisplayName = displayName;
+            return this;
+        }
+
+        /**
+         * Build the configuration using previously specified parameters.
+         */
+        public ProvisioningConfiguration build() {
+            return new ProvisioningConfiguration(mConfig);
+        }
+    }
+
+    public boolean mEnableIPv4 = true;
+    public boolean mEnableIPv6 = true;
+    public boolean mUsingMultinetworkPolicyTracker = true;
+    public boolean mUsingIpReachabilityMonitor = true;
+    public int mRequestedPreDhcpActionMs;
+    public InitialConfiguration mInitialConfig;
+    public StaticIpConfiguration mStaticIpConfig;
+    public ApfCapabilities mApfCapabilities;
+    public int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
+    public int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
+    public Network mNetwork = null;
+    public String mDisplayName = null;
+
+    public ProvisioningConfiguration() {} // used by Builder
+
+    public ProvisioningConfiguration(ProvisioningConfiguration other) {
+        mEnableIPv4 = other.mEnableIPv4;
+        mEnableIPv6 = other.mEnableIPv6;
+        mUsingMultinetworkPolicyTracker = other.mUsingMultinetworkPolicyTracker;
+        mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
+        mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs;
+        mInitialConfig = InitialConfiguration.copy(other.mInitialConfig);
+        mStaticIpConfig = other.mStaticIpConfig == null
+                ? null
+                : new StaticIpConfiguration(other.mStaticIpConfig);
+        mApfCapabilities = other.mApfCapabilities;
+        mProvisioningTimeoutMs = other.mProvisioningTimeoutMs;
+        mIPv6AddrGenMode = other.mIPv6AddrGenMode;
+        mNetwork = other.mNetwork;
+        mDisplayName = other.mDisplayName;
+    }
+
+    /**
+     * Create a ProvisioningConfigurationParcelable from this ProvisioningConfiguration.
+     */
+    public ProvisioningConfigurationParcelable toStableParcelable() {
+        final ProvisioningConfigurationParcelable p = new ProvisioningConfigurationParcelable();
+        p.enableIPv4 = mEnableIPv4;
+        p.enableIPv6 = mEnableIPv6;
+        p.usingMultinetworkPolicyTracker = mUsingMultinetworkPolicyTracker;
+        p.usingIpReachabilityMonitor = mUsingIpReachabilityMonitor;
+        p.requestedPreDhcpActionMs = mRequestedPreDhcpActionMs;
+        p.initialConfig = mInitialConfig == null ? null : mInitialConfig.toStableParcelable();
+        p.staticIpConfig = IpConfigurationParcelableUtil.toStableParcelable(mStaticIpConfig);
+        p.apfCapabilities = IpConfigurationParcelableUtil.toStableParcelable(mApfCapabilities);
+        p.provisioningTimeoutMs = mProvisioningTimeoutMs;
+        p.ipv6AddrGenMode = mIPv6AddrGenMode;
+        p.network = NetworkParcelableUtil.toStableParcelable(mNetwork);
+        p.displayName = mDisplayName;
+        return p;
+    }
+
+    /**
+     * Create a ProvisioningConfiguration from a ProvisioningConfigurationParcelable.
+     */
+    public static ProvisioningConfiguration fromStableParcelable(
+            @Nullable ProvisioningConfigurationParcelable p) {
+        if (p == null) return null;
+        final ProvisioningConfiguration config = new ProvisioningConfiguration();
+        config.mEnableIPv4 = p.enableIPv4;
+        config.mEnableIPv6 = p.enableIPv6;
+        config.mUsingMultinetworkPolicyTracker = p.usingMultinetworkPolicyTracker;
+        config.mUsingIpReachabilityMonitor = p.usingIpReachabilityMonitor;
+        config.mRequestedPreDhcpActionMs = p.requestedPreDhcpActionMs;
+        config.mInitialConfig = InitialConfiguration.fromStableParcelable(p.initialConfig);
+        config.mStaticIpConfig = IpConfigurationParcelableUtil.fromStableParcelable(
+                p.staticIpConfig);
+        config.mApfCapabilities = IpConfigurationParcelableUtil.fromStableParcelable(
+                p.apfCapabilities);
+        config.mProvisioningTimeoutMs = p.provisioningTimeoutMs;
+        config.mIPv6AddrGenMode = p.ipv6AddrGenMode;
+        config.mNetwork = NetworkParcelableUtil.fromStableParcelable(p.network);
+        config.mDisplayName = p.displayName;
+        return config;
+    }
+
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", getClass().getSimpleName() + "{", "}")
+                .add("mEnableIPv4: " + mEnableIPv4)
+                .add("mEnableIPv6: " + mEnableIPv6)
+                .add("mUsingMultinetworkPolicyTracker: " + mUsingMultinetworkPolicyTracker)
+                .add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor)
+                .add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs)
+                .add("mInitialConfig: " + mInitialConfig)
+                .add("mStaticIpConfig: " + mStaticIpConfig)
+                .add("mApfCapabilities: " + mApfCapabilities)
+                .add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
+                .add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
+                .add("mNetwork: " + mNetwork)
+                .add("mDisplayName: " + mDisplayName)
+                .toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof ProvisioningConfiguration)) return false;
+        final ProvisioningConfiguration other = (ProvisioningConfiguration) obj;
+        return mEnableIPv4 == other.mEnableIPv4
+                && mEnableIPv6 == other.mEnableIPv6
+                && mUsingMultinetworkPolicyTracker == other.mUsingMultinetworkPolicyTracker
+                && mUsingIpReachabilityMonitor == other.mUsingIpReachabilityMonitor
+                && mRequestedPreDhcpActionMs == other.mRequestedPreDhcpActionMs
+                && Objects.equals(mInitialConfig, other.mInitialConfig)
+                && Objects.equals(mStaticIpConfig, other.mStaticIpConfig)
+                && Objects.equals(mApfCapabilities, other.mApfCapabilities)
+                && mProvisioningTimeoutMs == other.mProvisioningTimeoutMs
+                && mIPv6AddrGenMode == other.mIPv6AddrGenMode
+                && Objects.equals(mNetwork, other.mNetwork)
+                && Objects.equals(mDisplayName, other.mDisplayName);
+    }
+
+    public boolean isValid() {
+        return (mInitialConfig == null) || mInitialConfig.isValid();
+    }
+}
diff --git a/services/net/java/android/net/util/ConnectivityPacketSummary.java b/services/net/java/android/net/util/ConnectivityPacketSummary.java
deleted file mode 100644
index 4951400..0000000
--- a/services/net/java/android/net/util/ConnectivityPacketSummary.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util;
-
-import android.net.dhcp.DhcpPacket;
-import android.net.MacAddress;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-import java.util.StringJoiner;
-
-import static android.system.OsConstants.*;
-import static android.net.util.NetworkConstants.*;
-
-
-/**
- * Critical connectivity packet summarizing class.
- *
- * Outputs short descriptions of ARP, DHCPv4, and IPv6 RS/RA/NS/NA packets.
- *
- * @hide
- */
-public class ConnectivityPacketSummary {
-    private static final String TAG = ConnectivityPacketSummary.class.getSimpleName();
-
-    private final byte[] mHwAddr;
-    private final byte[] mBytes;
-    private final int mLength;
-    private final ByteBuffer mPacket;
-    private final String mSummary;
-
-    public static String summarize(MacAddress hwaddr, byte[] buffer) {
-        return summarize(hwaddr, buffer, buffer.length);
-    }
-
-    // Methods called herein perform some but by no means all error checking.
-    // They may throw runtime exceptions on malformed packets.
-    public static String summarize(MacAddress macAddr, byte[] buffer, int length) {
-        if ((macAddr == null) || (buffer == null)) return null;
-        length = Math.min(length, buffer.length);
-        return (new ConnectivityPacketSummary(macAddr, buffer, length)).toString();
-    }
-
-    private ConnectivityPacketSummary(MacAddress macAddr, byte[] buffer, int length) {
-        mHwAddr = macAddr.toByteArray();
-        mBytes = buffer;
-        mLength = Math.min(length, mBytes.length);
-        mPacket = ByteBuffer.wrap(mBytes, 0, mLength);
-        mPacket.order(ByteOrder.BIG_ENDIAN);
-
-        final StringJoiner sj = new StringJoiner(" ");
-        // TODO: support other link-layers, or even no link-layer header.
-        parseEther(sj);
-        mSummary = sj.toString();
-    }
-
-    public String toString() {
-        return mSummary;
-    }
-
-    private void parseEther(StringJoiner sj) {
-        if (mPacket.remaining() < ETHER_HEADER_LEN) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        mPacket.position(ETHER_SRC_ADDR_OFFSET);
-        final ByteBuffer srcMac = (ByteBuffer) mPacket.slice().limit(ETHER_ADDR_LEN);
-        sj.add(ByteBuffer.wrap(mHwAddr).equals(srcMac) ? "TX" : "RX");
-        sj.add(getMacAddressString(srcMac));
-
-        mPacket.position(ETHER_DST_ADDR_OFFSET);
-        final ByteBuffer dstMac = (ByteBuffer) mPacket.slice().limit(ETHER_ADDR_LEN);
-        sj.add(">").add(getMacAddressString(dstMac));
-
-        mPacket.position(ETHER_TYPE_OFFSET);
-        final int etherType = asUint(mPacket.getShort());
-        switch (etherType) {
-            case ETHER_TYPE_ARP:
-                sj.add("arp");
-                parseARP(sj);
-                break;
-            case ETHER_TYPE_IPV4:
-                sj.add("ipv4");
-                parseIPv4(sj);
-                break;
-            case ETHER_TYPE_IPV6:
-                sj.add("ipv6");
-                parseIPv6(sj);
-                break;
-            default:
-                // Unknown ether type.
-                sj.add("ethtype").add(asString(etherType));
-                break;
-        }
-    }
-
-    private void parseARP(StringJoiner sj) {
-        if (mPacket.remaining() < ARP_PAYLOAD_LEN) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        if (asUint(mPacket.getShort()) != ARP_HWTYPE_ETHER ||
-            asUint(mPacket.getShort()) != ETHER_TYPE_IPV4 ||
-            asUint(mPacket.get()) != ETHER_ADDR_LEN ||
-            asUint(mPacket.get()) != IPV4_ADDR_LEN) {
-            sj.add("unexpected header");
-            return;
-        }
-
-        final int opCode = asUint(mPacket.getShort());
-
-        final String senderHwAddr = getMacAddressString(mPacket);
-        final String senderIPv4 = getIPv4AddressString(mPacket);
-        getMacAddressString(mPacket);  // target hardware address, unused
-        final String targetIPv4 = getIPv4AddressString(mPacket);
-
-        if (opCode == ARP_REQUEST) {
-            sj.add("who-has").add(targetIPv4);
-        } else if (opCode == ARP_REPLY) {
-            sj.add("reply").add(senderIPv4).add(senderHwAddr);
-        } else {
-            sj.add("unknown opcode").add(asString(opCode));
-        }
-    }
-
-    private void parseIPv4(StringJoiner sj) {
-        if (!mPacket.hasRemaining()) {
-            sj.add("runt");
-            return;
-        }
-
-        final int startOfIpLayer = mPacket.position();
-        final int ipv4HeaderLength = (mPacket.get(startOfIpLayer) & IPV4_IHL_MASK) * 4;
-        if (mPacket.remaining() < ipv4HeaderLength ||
-            mPacket.remaining() < IPV4_HEADER_MIN_LEN) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-        final int startOfTransportLayer = startOfIpLayer + ipv4HeaderLength;
-
-        mPacket.position(startOfIpLayer + IPV4_FLAGS_OFFSET);
-        final int flagsAndFragment = asUint(mPacket.getShort());
-        final boolean isFragment = (flagsAndFragment & IPV4_FRAGMENT_MASK) != 0;
-
-        mPacket.position(startOfIpLayer + IPV4_PROTOCOL_OFFSET);
-        final int protocol = asUint(mPacket.get());
-
-        mPacket.position(startOfIpLayer + IPV4_SRC_ADDR_OFFSET);
-        final String srcAddr = getIPv4AddressString(mPacket);
-
-        mPacket.position(startOfIpLayer + IPV4_DST_ADDR_OFFSET);
-        final String dstAddr = getIPv4AddressString(mPacket);
-
-        sj.add(srcAddr).add(">").add(dstAddr);
-
-        mPacket.position(startOfTransportLayer);
-        if (protocol == IPPROTO_UDP) {
-            sj.add("udp");
-            if (isFragment) sj.add("fragment");
-            else parseUDP(sj);
-        } else {
-            sj.add("proto").add(asString(protocol));
-            if (isFragment) sj.add("fragment");
-        }
-    }
-
-    private void parseIPv6(StringJoiner sj) {
-        if (mPacket.remaining() < IPV6_HEADER_LEN) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        final int startOfIpLayer = mPacket.position();
-
-        mPacket.position(startOfIpLayer + IPV6_PROTOCOL_OFFSET);
-        final int protocol = asUint(mPacket.get());
-
-        mPacket.position(startOfIpLayer + IPV6_SRC_ADDR_OFFSET);
-        final String srcAddr = getIPv6AddressString(mPacket);
-        final String dstAddr = getIPv6AddressString(mPacket);
-
-        sj.add(srcAddr).add(">").add(dstAddr);
-
-        mPacket.position(startOfIpLayer + IPV6_HEADER_LEN);
-        if (protocol == IPPROTO_ICMPV6) {
-            sj.add("icmp6");
-            parseICMPv6(sj);
-        } else {
-            sj.add("proto").add(asString(protocol));
-        }
-    }
-
-    private void parseICMPv6(StringJoiner sj) {
-        if (mPacket.remaining() < ICMPV6_HEADER_MIN_LEN) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        final int icmp6Type = asUint(mPacket.get());
-        final int icmp6Code = asUint(mPacket.get());
-        mPacket.getShort();  // checksum, unused
-
-        switch (icmp6Type) {
-            case ICMPV6_ROUTER_SOLICITATION:
-                sj.add("rs");
-                parseICMPv6RouterSolicitation(sj);
-                break;
-            case ICMPV6_ROUTER_ADVERTISEMENT:
-                sj.add("ra");
-                parseICMPv6RouterAdvertisement(sj);
-                break;
-            case ICMPV6_NEIGHBOR_SOLICITATION:
-                sj.add("ns");
-                parseICMPv6NeighborMessage(sj);
-                break;
-            case ICMPV6_NEIGHBOR_ADVERTISEMENT:
-                sj.add("na");
-                parseICMPv6NeighborMessage(sj);
-                break;
-            default:
-                sj.add("type").add(asString(icmp6Type));
-                sj.add("code").add(asString(icmp6Code));
-                break;
-        }
-    }
-
-    private void parseICMPv6RouterSolicitation(StringJoiner sj) {
-        final int RESERVED = 4;
-        if (mPacket.remaining() < RESERVED) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        mPacket.position(mPacket.position() + RESERVED);
-        parseICMPv6NeighborDiscoveryOptions(sj);
-    }
-
-    private void parseICMPv6RouterAdvertisement(StringJoiner sj) {
-        final int FLAGS_AND_TIMERS = 3 * 4;
-        if (mPacket.remaining() < FLAGS_AND_TIMERS) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        mPacket.position(mPacket.position() + FLAGS_AND_TIMERS);
-        parseICMPv6NeighborDiscoveryOptions(sj);
-    }
-
-    private void parseICMPv6NeighborMessage(StringJoiner sj) {
-        final int RESERVED = 4;
-        final int minReq = RESERVED + IPV6_ADDR_LEN;
-        if (mPacket.remaining() < minReq) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        mPacket.position(mPacket.position() + RESERVED);
-        sj.add(getIPv6AddressString(mPacket));
-        parseICMPv6NeighborDiscoveryOptions(sj);
-    }
-
-    private void parseICMPv6NeighborDiscoveryOptions(StringJoiner sj) {
-        // All ND options are TLV, where T is one byte and L is one byte equal
-        // to the length of T + L + V in units of 8 octets.
-        while (mPacket.remaining() >= ICMPV6_ND_OPTION_MIN_LENGTH) {
-            final int ndType = asUint(mPacket.get());
-            final int ndLength = asUint(mPacket.get());
-            final int ndBytes = ndLength * ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR - 2;
-            if (ndBytes < 0 || ndBytes > mPacket.remaining()) {
-                sj.add("<malformed>");
-                break;
-            }
-            final int position = mPacket.position();
-
-            switch (ndType) {
-                    case ICMPV6_ND_OPTION_SLLA:
-                        sj.add("slla");
-                        sj.add(getMacAddressString(mPacket));
-                        break;
-                    case ICMPV6_ND_OPTION_TLLA:
-                        sj.add("tlla");
-                        sj.add(getMacAddressString(mPacket));
-                        break;
-                    case ICMPV6_ND_OPTION_MTU:
-                        sj.add("mtu");
-                        final short reserved = mPacket.getShort();
-                        sj.add(asString(mPacket.getInt()));
-                        break;
-                    default:
-                        // Skip.
-                        break;
-            }
-
-            mPacket.position(position + ndBytes);
-        }
-    }
-
-    private void parseUDP(StringJoiner sj) {
-        if (mPacket.remaining() < UDP_HEADER_LEN) {
-            sj.add("runt:").add(asString(mPacket.remaining()));
-            return;
-        }
-
-        final int previous = mPacket.position();
-        final int srcPort = asUint(mPacket.getShort());
-        final int dstPort = asUint(mPacket.getShort());
-        sj.add(asString(srcPort)).add(">").add(asString(dstPort));
-
-        mPacket.position(previous + UDP_HEADER_LEN);
-        if (srcPort == DHCP4_CLIENT_PORT || dstPort == DHCP4_CLIENT_PORT) {
-            sj.add("dhcp4");
-            parseDHCPv4(sj);
-        }
-    }
-
-    private void parseDHCPv4(StringJoiner sj) {
-        final DhcpPacket dhcpPacket;
-        try {
-            dhcpPacket = DhcpPacket.decodeFullPacket(mBytes, mLength, DhcpPacket.ENCAP_L2);
-            sj.add(dhcpPacket.toString());
-        } catch (DhcpPacket.ParseException e) {
-            sj.add("parse error: " + e);
-        }
-    }
-
-    private static String getIPv4AddressString(ByteBuffer ipv4) {
-        return getIpAddressString(ipv4, IPV4_ADDR_LEN);
-    }
-
-    private static String getIPv6AddressString(ByteBuffer ipv6) {
-        return getIpAddressString(ipv6, IPV6_ADDR_LEN);
-    }
-
-    private static String getIpAddressString(ByteBuffer ip, int byteLength) {
-        if (ip == null || ip.remaining() < byteLength) return "invalid";
-
-        byte[] bytes = new byte[byteLength];
-        ip.get(bytes, 0, byteLength);
-        try {
-            InetAddress addr = InetAddress.getByAddress(bytes);
-            return addr.getHostAddress();
-        } catch (UnknownHostException uhe) {
-            return "unknown";
-        }
-    }
-
-    private static String getMacAddressString(ByteBuffer mac) {
-        if (mac == null || mac.remaining() < ETHER_ADDR_LEN) return "invalid";
-
-        byte[] bytes = new byte[ETHER_ADDR_LEN];
-        mac.get(bytes, 0, bytes.length);
-        Object[] printableBytes = new Object[bytes.length];
-        int i = 0;
-        for (byte b : bytes) printableBytes[i++] = new Byte(b);
-
-        final String MAC48_FORMAT = "%02x:%02x:%02x:%02x:%02x:%02x";
-        return String.format(MAC48_FORMAT, printableBytes);
-    }
-}
diff --git a/services/net/java/android/net/util/InterfaceParams.java b/services/net/java/android/net/util/InterfaceParams.java
index a4b2fbb..f6bb873 100644
--- a/services/net/java/android/net/util/InterfaceParams.java
+++ b/services/net/java/android/net/util/InterfaceParams.java
@@ -16,9 +16,6 @@
 
 package android.net.util;
 
-import static android.net.MacAddress.ALL_ZEROS_ADDRESS;
-import static android.net.util.NetworkConstants.ETHER_MTU;
-import static android.net.util.NetworkConstants.IPV6_MIN_MTU;
 import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.net.MacAddress;
@@ -44,6 +41,11 @@
     public final MacAddress macAddr;
     public final int defaultMtu;
 
+    // TODO: move the below to NetworkStackConstants when this class is moved to the NetworkStack.
+    private static final int ETHER_MTU = 1500;
+    private static final int IPV6_MIN_MTU = 1280;
+
+
     public static InterfaceParams getByName(String name) {
         final NetworkInterface netif = getNetworkInterfaceByName(name);
         if (netif == null) return null;
@@ -67,7 +69,8 @@
         checkArgument((index > 0), "invalid interface index");
         this.name = name;
         this.index = index;
-        this.macAddr = (macAddr != null) ? macAddr : ALL_ZEROS_ADDRESS;
+        this.macAddr = (macAddr != null) ? macAddr : MacAddress.fromBytes(new byte[] {
+                0x02, 0x00, 0x00, 0x00, 0x00, 0x00 });
         this.defaultMtu = (defaultMtu > IPV6_MIN_MTU) ? defaultMtu : IPV6_MIN_MTU;
     }
 
diff --git a/services/net/java/android/net/util/NetdService.java b/services/net/java/android/net/util/NetdService.java
deleted file mode 100644
index 6e69ff5..0000000
--- a/services/net/java/android/net/util/NetdService.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util;
-
-import android.net.INetd;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.ServiceSpecificException;
-import android.os.SystemClock;
-import android.util.Log;
-
-
-/**
- * @hide
- */
-public class NetdService {
-    private static final String TAG = NetdService.class.getSimpleName();
-    private static final String NETD_SERVICE_NAME = "netd";
-    private static final long BASE_TIMEOUT_MS = 100;
-    private static final long MAX_TIMEOUT_MS = 1000;
-
-
-    /**
-     * Return an INetd instance, or null if not available.
-     *
-     * It is the caller's responsibility to check for a null return value
-     * and to handle RemoteException errors from invocations on the returned
-     * interface if, for example, netd dies and is restarted.
-     *
-     * Returned instances of INetd should not be cached.
-     *
-     * @return an INetd instance or null.
-     */
-    public static INetd getInstance() {
-        // NOTE: ServiceManager does no caching for the netd service,
-        // because netd is not one of the defined common services.
-        final INetd netdInstance = INetd.Stub.asInterface(
-                ServiceManager.getService(NETD_SERVICE_NAME));
-        if (netdInstance == null) {
-            Log.w(TAG, "WARNING: returning null INetd instance.");
-        }
-        return netdInstance;
-    }
-
-    /**
-     * Blocks for a specified time until an INetd instance is available.
-     *
-     * It is the caller's responsibility to handle RemoteException errors
-     * from invocations on the returned interface if, for example, netd
-     * dies after this interface was returned.
-     *
-     * Returned instances of INetd should not be cached.
-     *
-     * Special values of maxTimeoutMs include: 0, meaning try to obtain an
-     * INetd instance only once, and -1 (or any value less than 0), meaning
-     * try to obtain an INetd instance indefinitely.
-     *
-     * @param maxTimeoutMs the maximum time to spend getting an INetd instance
-     * @return an INetd instance or null if no instance is available
-     * within |maxTimeoutMs| milliseconds.
-     */
-    public static INetd get(long maxTimeoutMs) {
-        if (maxTimeoutMs == 0) return getInstance();
-
-        final long stop = (maxTimeoutMs > 0)
-                ? SystemClock.elapsedRealtime() + maxTimeoutMs
-                : Long.MAX_VALUE;
-
-        long timeoutMs = 0;
-        while (true) {
-            final INetd netdInstance = getInstance();
-            if (netdInstance != null) {
-                return netdInstance;
-            }
-
-            final long remaining = stop - SystemClock.elapsedRealtime();
-            if (remaining <= 0) break;
-
-            // No netdInstance was received; sleep and retry.
-            timeoutMs = Math.min(timeoutMs + BASE_TIMEOUT_MS, MAX_TIMEOUT_MS);
-            timeoutMs = Math.min(timeoutMs, remaining);
-            try {
-                Thread.sleep(timeoutMs);
-            } catch (InterruptedException e) {}
-        }
-        return null;
-    }
-
-    /**
-     * Blocks until an INetd instance is available.
-     *
-     * It is the caller's responsibility to handle RemoteException errors
-     * from invocations on the returned interface if, for example, netd
-     * dies after this interface was returned.
-     *
-     * Returned instances of INetd should not be cached.
-     *
-     * @return an INetd instance.
-     */
-    public static INetd get() {
-        return get(-1);
-    }
-
-    public static interface NetdCommand {
-        void run(INetd netd) throws RemoteException;
-    }
-
-    /**
-     * Blocks until an INetd instance is availabe, and retries until either
-     * the command succeeds or a runtime exception is thrown.
-     */
-    public static void run(NetdCommand cmd) {
-        while (true) {
-            try {
-                cmd.run(get());
-                return;
-            } catch (RemoteException re) {
-                Log.e(TAG, "error communicating with netd: " + re);
-            }
-        }
-    }
-}
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index 3defe56..ea5ce65 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -16,9 +16,6 @@
 
 package android.net.util;
 
-import java.nio.ByteBuffer;
-
-
 /**
  * Networking protocol constants.
  *
@@ -31,28 +28,6 @@
 public final class NetworkConstants {
     private NetworkConstants() { throw new RuntimeException("no instance permitted"); }
 
-    /**
-     * Ethernet constants.
-     *
-     * See also:
-     *     - https://tools.ietf.org/html/rfc894
-     *     - https://tools.ietf.org/html/rfc2464
-     *     - https://tools.ietf.org/html/rfc7042
-     *     - http://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml
-     *     - http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml
-     */
-    public static final int ETHER_DST_ADDR_OFFSET = 0;
-    public static final int ETHER_SRC_ADDR_OFFSET = 6;
-    public static final int ETHER_ADDR_LEN = 6;
-
-    public static final int ETHER_TYPE_OFFSET = 12;
-    public static final int ETHER_TYPE_LENGTH = 2;
-    public static final int ETHER_TYPE_ARP  = 0x0806;
-    public static final int ETHER_TYPE_IPV4 = 0x0800;
-    public static final int ETHER_TYPE_IPV6 = 0x86dd;
-
-    public static final int ETHER_HEADER_LEN = 14;
-
     public static final byte FF = asByte(0xff);
     public static final byte[] ETHER_ADDR_BROADCAST = {
         FF, FF, FF, FF, FF, FF
@@ -61,36 +36,12 @@
     public static final int ETHER_MTU = 1500;
 
     /**
-     * ARP constants.
-     *
-     * See also:
-     *     - https://tools.ietf.org/html/rfc826
-     *     - http://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml
-     */
-    public static final int ARP_PAYLOAD_LEN = 28;  // For Ethernet+IPv4.
-    public static final int ARP_REQUEST = 1;
-    public static final int ARP_REPLY   = 2;
-    public static final int ARP_HWTYPE_RESERVED_LO = 0;
-    public static final int ARP_HWTYPE_ETHER       = 1;
-    public static final int ARP_HWTYPE_RESERVED_HI = 0xffff;
-
-    /**
      * IPv4 constants.
      *
      * See also:
      *     - https://tools.ietf.org/html/rfc791
      */
-    public static final int IPV4_HEADER_MIN_LEN = 20;
-    public static final int IPV4_MIN_MTU = 68;
-    public static final int IPV4_MAX_MTU = 65_535;
-    public static final int IPV4_IHL_MASK = 0xf;
-    public static final int IPV4_FLAGS_OFFSET = 6;
-    public static final int IPV4_FRAGMENT_MASK = 0x1fff;
-    public static final int IPV4_PROTOCOL_OFFSET = 9;
-    public static final int IPV4_SRC_ADDR_OFFSET = 12;
-    public static final int IPV4_DST_ADDR_OFFSET = 16;
     public static final int IPV4_ADDR_BITS = 32;
-    public static final int IPV4_ADDR_LEN = 4;
 
     /**
      * IPv6 constants.
@@ -98,15 +49,10 @@
      * See also:
      *     - https://tools.ietf.org/html/rfc2460
      */
-    public static final int IPV6_HEADER_LEN = 40;
-    public static final int IPV6_PROTOCOL_OFFSET = 6;
-    public static final int IPV6_SRC_ADDR_OFFSET = 8;
-    public static final int IPV6_DST_ADDR_OFFSET = 24;
     public static final int IPV6_ADDR_BITS = 128;
     public static final int IPV6_ADDR_LEN = 16;
     public static final int IPV6_MIN_MTU = 1280;
     public static final int RFC7421_PREFIX_LENGTH = 64;
-    public static final int RFC6177_MIN_PREFIX_LENGTH = 48;
 
     /**
      * ICMP common (v4/v6) constants.
@@ -129,45 +75,7 @@
      *     - https://tools.ietf.org/html/rfc792
      */
     public static final int ICMPV4_ECHO_REQUEST_TYPE = 8;
-
-    /**
-     * ICMPv6 constants.
-     *
-     * See also:
-     *     - https://tools.ietf.org/html/rfc4443
-     *     - https://tools.ietf.org/html/rfc4861
-     */
-    public static final int ICMPV6_HEADER_MIN_LEN = 4;
     public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
-    public static final int ICMPV6_ECHO_REPLY_TYPE = 129;
-    public static final int ICMPV6_ROUTER_SOLICITATION    = 133;
-    public static final int ICMPV6_ROUTER_ADVERTISEMENT   = 134;
-    public static final int ICMPV6_NEIGHBOR_SOLICITATION  = 135;
-    public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136;
-
-    public static final int ICMPV6_ND_OPTION_MIN_LENGTH = 8;
-    public static final int ICMPV6_ND_OPTION_LENGTH_SCALING_FACTOR = 8;
-    public static final int ICMPV6_ND_OPTION_SLLA = 1;
-    public static final int ICMPV6_ND_OPTION_TLLA = 2;
-    public static final int ICMPV6_ND_OPTION_MTU  = 5;
-
-
-    /**
-     * UDP constants.
-     *
-     * See also:
-     *     - https://tools.ietf.org/html/rfc768
-     */
-    public static final int UDP_HEADER_LEN = 8;
-
-    /**
-     * DHCP(v4) constants.
-     *
-     * See also:
-     *     - https://tools.ietf.org/html/rfc2131
-     */
-    public static final int DHCP4_SERVER_PORT = 67;
-    public static final int DHCP4_CLIENT_PORT = 68;
 
     /**
      * DNS constants.
@@ -181,9 +89,4 @@
      * Utility functions.
      */
     public static byte asByte(int i) { return (byte) i; }
-
-    public static String asString(int i) { return Integer.toString(i); }
-
-    public static int asUint(byte b) { return (b & 0xff); }
-    public static int asUint(short s) { return (s & 0xffff); }
 }
diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java
index 5a73a4e..2cdb2b0 100644
--- a/services/net/java/android/net/util/SharedLog.java
+++ b/services/net/java/android/net/util/SharedLog.java
@@ -32,11 +32,12 @@
  *
  * All access to class methods other than dump() must be on the same thread.
  *
+ * TODO: this is a copy of SharedLog in the NetworkStack. Remove after Tethering is migrated.
  * @hide
  */
 public class SharedLog {
-    private final static int DEFAULT_MAX_RECORDS = 500;
-    private final static String COMPONENT_DELIMITER = ".";
+    private static final int DEFAULT_MAX_RECORDS = 500;
+    private static final String COMPONENT_DELIMITER = ".";
 
     private enum Category {
         NONE,
@@ -69,6 +70,13 @@
         mComponent = component;
     }
 
+    public String getTag() {
+        return mTag;
+    }
+
+    /**
+     * Create a SharedLog based on this log with an additional component prefix on each logged line.
+     */
     public SharedLog forSubComponent(String component) {
         if (!isRootLogInstance()) {
             component = mComponent + COMPONENT_DELIMITER + component;
@@ -76,6 +84,11 @@
         return new SharedLog(mLocalLog, mTag, component);
     }
 
+    /**
+     * Dump the contents of this log.
+     *
+     * <p>This method may be called on any thread.
+     */
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mLocalLog.readOnlyLocalLog().dump(fd, writer, args);
     }
@@ -84,10 +97,21 @@
     // Methods that both log an entry and emit it to the system log.
     //////
 
+    /**
+     * Log an error due to an exception. This does not include the exception stacktrace.
+     *
+     * <p>The log entry will be also added to the system log.
+     * @see #e(String, Throwable)
+     */
     public void e(Exception e) {
         Log.e(mTag, record(Category.ERROR, e.toString()));
     }
 
+    /**
+     * Log an error message.
+     *
+     * <p>The log entry will be also added to the system log.
+     */
     public void e(String msg) {
         Log.e(mTag, record(Category.ERROR, msg));
     }
@@ -96,7 +120,7 @@
      * 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).
+     * logged in general log output (logcat). The log entry will be also added to the system log.
      */
     public void e(@NonNull String msg, @Nullable Throwable exception) {
         if (exception == null) {
@@ -106,10 +130,20 @@
         Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception);
     }
 
+    /**
+     * Log an informational message.
+     *
+     * <p>The log entry will be also added to the system log.
+     */
     public void i(String msg) {
         Log.i(mTag, record(Category.NONE, msg));
     }
 
+    /**
+     * Log a warning message.
+     *
+     * <p>The log entry will be also added to the system log.
+     */
     public void w(String msg) {
         Log.w(mTag, record(Category.WARN, msg));
     }
@@ -118,14 +152,30 @@
     // Methods that only log an entry (and do NOT emit to the system log).
     //////
 
+    /**
+     * Log a general message to be only included in the in-memory log.
+     *
+     * <p>The log entry will *not* be added to the system log.
+     */
     public void log(String msg) {
         record(Category.NONE, msg);
     }
 
+    /**
+     * Log a general, formatted message to be only included in the in-memory log.
+     *
+     * <p>The log entry will *not* be added to the system log.
+     * @see String#format(String, Object...)
+     */
     public void logf(String fmt, Object... args) {
         log(String.format(fmt, args));
     }
 
+    /**
+     * Log a message with MARK level.
+     *
+     * <p>The log entry will *not* be added to the system log.
+     */
     public void mark(String msg) {
         record(Category.MARK, msg);
     }
diff --git a/services/net/java/android/net/util/Stopwatch.java b/services/net/java/android/net/util/Stopwatch.java
deleted file mode 100644
index cb15ee5..0000000
--- a/services/net/java/android/net/util/Stopwatch.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util;
-
-import android.os.SystemClock;
-
-
-/**
- * @hide
- */
-public class Stopwatch {
-    private long mStartTimeMs;
-    private long mStopTimeMs;
-
-    public boolean isStarted() {
-        return (mStartTimeMs > 0);
-    }
-
-    public boolean isStopped() {
-        return (mStopTimeMs > 0);
-    }
-
-    public boolean isRunning() {
-        return (isStarted() && !isStopped());
-    }
-
-    // Returning |this| makes possible the following usage pattern:
-    //
-    //     Stopwatch s = new Stopwatch().start();
-    public Stopwatch start() {
-        if (!isStarted()) {
-            mStartTimeMs = SystemClock.elapsedRealtime();
-        }
-        return this;
-    }
-
-    // Returns the total time recorded, in milliseconds, or 0 if not started.
-    public long stop() {
-        if (isRunning()) {
-            mStopTimeMs = SystemClock.elapsedRealtime();
-        }
-        // Return either the delta after having stopped, or 0.
-        return (mStopTimeMs - mStartTimeMs);
-    }
-
-    // Returns the total time recorded to date, in milliseconds.
-    // If the Stopwatch is not running, returns the same value as stop(),
-    // i.e. either the total time recorded before stopping or 0.
-    public long lap() {
-        if (isRunning()) {
-            return (SystemClock.elapsedRealtime() - mStartTimeMs);
-        } else {
-            return stop();
-        }
-    }
-
-    public void reset() {
-        mStartTimeMs = 0;
-        mStopTimeMs = 0;
-    }
-}
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index 9159f0d..0cf0d34 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -26,9 +26,6 @@
 LOCAL_PRIVILEGED_MODULE := true
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    bmgrlib \
-    bu \
-    services.backup \
     services.core \
     services.net
 
@@ -41,8 +38,7 @@
 
 LOCAL_MODULE := FrameworksServicesRoboTests
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-    $(call all-java-files-under, backup/src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_RESOURCE_DIR := \
     $(LOCAL_PATH)/res
@@ -82,8 +78,7 @@
 
 LOCAL_TEST_PACKAGE := FrameworksServicesLib
 
-LOCAL_ROBOTEST_FILES := $(call find-files-in-subdirs,$(LOCAL_PATH)/src,*Test.java,.) \
-    $(call find-files-in-subdirs,$(LOCAL_PATH)/backup/src,*Test.java,.)
+LOCAL_ROBOTEST_FILES := $(call find-files-in-subdirs,$(LOCAL_PATH)/src,*Test.java,.)
 
 include external/robolectric-shadows/run_robotests.mk
 
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
index b8723c5..b8db3f3 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.backup;
 
+import static android.Manifest.permission.BACKUP;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 
 import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThread;
@@ -45,6 +46,7 @@
 import android.util.SparseArray;
 
 import com.android.server.backup.testing.TransportData;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
 import com.android.server.testing.shadows.ShadowBinder;
 
 import org.junit.After;
@@ -64,7 +66,7 @@
 
 /** Tests for the user-aware backup/restore system service {@link BackupManagerService}. */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowBinder.class})
+@Config(shadows = {ShadowApplicationPackageManager.class, ShadowBinder.class})
 @Presubmit
 public class BackupManagerServiceTest {
     private static final String TEST_PACKAGE = "package";
@@ -192,6 +194,19 @@
 
     /** Test that the service unregisters users when stopped. */
     @Test
+    public void testStopServiceForUser_forRegisteredUser_tearsDownCorrectUser() throws Exception {
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
+
+        backupManagerService.stopServiceForUser(mUserOneId);
+
+        verify(mUserOneService).tearDownService();
+        verify(mUserTwoService, never()).tearDownService();
+    }
+
+    /** Test that the service unregisters users when stopped. */
+    @Test
     public void testStopServiceForUser_forUnknownUser_doesNothing() throws Exception {
         BackupManagerService backupManagerService = createService();
 
@@ -1061,7 +1076,7 @@
                 createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
         FullBackupJob job = new FullBackupJob();
 
-        backupManagerService.beginFullBackup(job);
+        backupManagerService.beginFullBackup(UserHandle.USER_SYSTEM, job);
 
         verify(mUserOneService).beginFullBackup(job);
     }
@@ -1072,7 +1087,7 @@
         BackupManagerService backupManagerService = createService();
         FullBackupJob job = new FullBackupJob();
 
-        backupManagerService.beginFullBackup(job);
+        backupManagerService.beginFullBackup(UserHandle.USER_SYSTEM, job);
 
         verify(mUserOneService, never()).beginFullBackup(job);
     }
@@ -1083,7 +1098,7 @@
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
 
-        backupManagerService.endFullBackup();
+        backupManagerService.endFullBackup(UserHandle.USER_SYSTEM);
 
         verify(mUserOneService).endFullBackup();
     }
@@ -1093,7 +1108,7 @@
     public void testEndFullBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
         BackupManagerService backupManagerService = createService();
 
-        backupManagerService.endFullBackup();
+        backupManagerService.endFullBackup(UserHandle.USER_SYSTEM);
 
         verify(mUserOneService, never()).endFullBackup();
     }
@@ -1528,6 +1543,7 @@
     }
 
     private BackupManagerService createService() {
+        mShadowContext.grantPermissions(BACKUP);
         return new BackupManagerService(
                 mContext, new Trampoline(mContext), startBackupThread(null));
     }
diff --git a/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java b/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
new file mode 100644
index 0000000..9a78d0b3
--- /dev/null
+++ b/services/robotests/backup/src/com/android/server/backup/FullBackupJobTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.annotation.UserIdInt;
+import android.app.job.JobScheduler;
+import android.content.Context;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowJobScheduler;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowJobScheduler.class})
+@Presubmit
+public class FullBackupJobTest {
+    private Context mContext;
+    private BackupManagerConstants mConstants;
+    private ShadowJobScheduler mShadowJobScheduler;
+
+    @UserIdInt private int mUserOneId;
+    @UserIdInt private int mUserTwoId;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = RuntimeEnvironment.application;
+        mConstants = new BackupManagerConstants(Handler.getMain(), mContext.getContentResolver());
+        mConstants.start();
+
+        mShadowJobScheduler = Shadows.shadowOf(mContext.getSystemService(JobScheduler.class));
+
+        mUserOneId = UserHandle.USER_SYSTEM;
+        mUserTwoId = mUserOneId + 1;
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mConstants.stop();
+        FullBackupJob.cancel(mUserOneId, mContext);
+        FullBackupJob.cancel(mUserTwoId, mContext);
+    }
+
+    @Test
+    public void testSchedule_afterScheduling_jobExists() {
+        FullBackupJob.schedule(mUserOneId, mContext, 0, mConstants);
+        FullBackupJob.schedule(mUserTwoId, mContext, 0, mConstants);
+
+        assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserOneId))).isNotNull();
+        assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserTwoId))).isNotNull();
+    }
+
+    @Test
+    public void testCancel_afterCancelling_jobDoesntExist() {
+        FullBackupJob.schedule(mUserOneId, mContext, 0, mConstants);
+        FullBackupJob.schedule(mUserTwoId, mContext, 0, mConstants);
+        FullBackupJob.cancel(mUserOneId, mContext);
+        FullBackupJob.cancel(mUserTwoId, mContext);
+
+        assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserOneId))).isNull();
+        assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserTwoId))).isNull();
+    }
+//
+    @Test
+    public void testSchedule_onlySchedulesForRequestedUser() {
+        FullBackupJob.schedule(mUserOneId, mContext, 0, mConstants);
+
+        assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserOneId))).isNotNull();
+        assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserTwoId))).isNull();
+    }
+//
+    @Test
+    public void testCancel_onlyCancelsForRequestedUser() {
+        FullBackupJob.schedule(mUserOneId, mContext, 0, mConstants);
+        FullBackupJob.schedule(mUserTwoId, mContext, 0, mConstants);
+        FullBackupJob.cancel(mUserOneId, mContext);
+
+        assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserOneId))).isNull();
+        assertThat(mShadowJobScheduler.getPendingJob(getJobIdForUserId(mUserTwoId))).isNotNull();
+    }
+
+    private static int getJobIdForUserId(int userId) {
+        return JobIdManager.getJobIdForUserId(FullBackupJob.MIN_JOB_ID, FullBackupJob.MAX_JOB_ID,
+                userId);
+    }
+}
diff --git a/services/robotests/backup/src/com/android/server/backup/JobIdManagerTest.java b/services/robotests/backup/src/com/android/server/backup/JobIdManagerTest.java
new file mode 100644
index 0000000..f8bb1ee
--- /dev/null
+++ b/services/robotests/backup/src/com/android/server/backup/JobIdManagerTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.annotation.UserIdInt;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import static org.testng.Assert.expectThrows;
+
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class JobIdManagerTest {
+    private static final int MIN_JOB_ID = 10;
+    private static final int MAX_JOB_ID = 20;
+
+    @UserIdInt private int mUserOneId;
+    @UserIdInt private int mUserTwoId;
+
+    @Before
+    public void setUp() {
+        mUserOneId = UserHandle.USER_SYSTEM;
+        mUserTwoId = mUserOneId + 1;
+    }
+
+    @Test
+    public void testGetJobIdForUserId_returnsDifferentJobIdsForDifferentUsers() {
+        int jobIdOne = JobIdManager.getJobIdForUserId(MIN_JOB_ID, MAX_JOB_ID, mUserOneId);
+        int jobIdTwo = JobIdManager.getJobIdForUserId(MIN_JOB_ID, MAX_JOB_ID, mUserTwoId);
+
+        assertThat(jobIdOne).isNotEqualTo(jobIdTwo);
+    }
+
+    @Test
+    public void testGetJobIdForUserId_returnsSameJobIdForSameUser() {
+        int jobIdOne = JobIdManager.getJobIdForUserId(MIN_JOB_ID, MAX_JOB_ID, mUserOneId);
+        int jobIdTwo = JobIdManager.getJobIdForUserId(MIN_JOB_ID, MAX_JOB_ID, mUserOneId);
+
+        assertThat(jobIdOne).isEqualTo(jobIdTwo);
+    }
+
+    @Test
+    public void testGetJobIdForUserId_throwsExceptionIfRangeIsExceeded() {
+        expectThrows(
+                RuntimeException.class,
+                () -> JobIdManager.getJobIdForUserId(MIN_JOB_ID, MAX_JOB_ID,
+                        MAX_JOB_ID + 1));
+    }
+}
diff --git a/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java b/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
index 8e17209..8d9e44f 100644
--- a/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/KeyValueBackupJobTest.java
@@ -18,8 +18,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.annotation.UserIdInt;
 import android.content.Context;
 import android.os.Handler;
+import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 
 import org.junit.After;
@@ -35,32 +37,67 @@
     private Context mContext;
     private BackupManagerConstants mConstants;
 
+    @UserIdInt private int mUserOneId;
+    @UserIdInt private int mUserTwoId;
+
     @Before
     public void setUp() throws Exception {
         mContext = RuntimeEnvironment.application;
         mConstants = new BackupManagerConstants(Handler.getMain(), mContext.getContentResolver());
         mConstants.start();
+
+        mUserOneId = UserHandle.USER_SYSTEM;
+        mUserTwoId = mUserOneId + 1;
     }
 
     @After
     public void tearDown() throws Exception {
         mConstants.stop();
-        KeyValueBackupJob.cancel(mContext);
+        KeyValueBackupJob.cancel(mUserOneId, mContext);
+        KeyValueBackupJob.cancel(mUserTwoId, mContext);
     }
 
     @Test
     public void testIsScheduled_beforeScheduling_returnsFalse() {
-        boolean isScheduled = KeyValueBackupJob.isScheduled();
-
-        assertThat(isScheduled).isFalse();
+        assertThat(KeyValueBackupJob.isScheduled(mUserOneId)).isFalse();
+        assertThat(KeyValueBackupJob.isScheduled(mUserTwoId)).isFalse();
     }
 
     @Test
     public void testIsScheduled_afterScheduling_returnsTrue() {
-        KeyValueBackupJob.schedule(mContext, mConstants);
+        KeyValueBackupJob.schedule(mUserOneId, mContext, mConstants);
+        KeyValueBackupJob.schedule(mUserTwoId, mContext, mConstants);
 
-        boolean isScheduled = KeyValueBackupJob.isScheduled();
+        assertThat(KeyValueBackupJob.isScheduled(mUserOneId)).isTrue();
+        assertThat(KeyValueBackupJob.isScheduled(mUserTwoId)).isTrue();
+    }
 
-        assertThat(isScheduled).isTrue();
+    @Test
+    public void testIsScheduled_afterCancelling_returnsFalse() {
+        KeyValueBackupJob.schedule(mUserOneId, mContext, mConstants);
+        KeyValueBackupJob.schedule(mUserTwoId, mContext, mConstants);
+        KeyValueBackupJob.cancel(mUserOneId, mContext);
+        KeyValueBackupJob.cancel(mUserTwoId, mContext);
+
+        assertThat(KeyValueBackupJob.isScheduled(mUserOneId)).isFalse();
+        assertThat(KeyValueBackupJob.isScheduled(mUserTwoId)).isFalse();
+    }
+
+    @Test
+    public void testIsScheduled_afterScheduling_returnsTrueOnlyForScheduledUser() {
+        KeyValueBackupJob.schedule(mUserOneId, mContext, mConstants);
+
+        assertThat(KeyValueBackupJob.isScheduled(mUserOneId)).isTrue();
+        assertThat(KeyValueBackupJob.isScheduled(mUserTwoId)).isFalse();
+    }
+
+    @Test
+    public void testIsScheduled_afterCancelling_returnsFalseOnlyForCancelledUser() {
+        KeyValueBackupJob.schedule(mUserOneId, mContext, mConstants);
+        KeyValueBackupJob.schedule(mUserTwoId, mContext, mConstants);
+        KeyValueBackupJob.cancel(mUserOneId, mContext);
+
+        assertThat(KeyValueBackupJob.isScheduled(mUserOneId)).isFalse();
+        assertThat(KeyValueBackupJob.isScheduled(mUserTwoId)).isTrue();
     }
 }
diff --git a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
index 693092d..9a6e003 100644
--- a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
@@ -41,6 +41,7 @@
 import static java.util.stream.Stream.concat;
 
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.backup.BackupManager;
 import android.app.backup.BackupTransport;
 import android.content.ComponentName;
@@ -48,6 +49,7 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 
 import com.android.server.backup.testing.TransportData;
@@ -56,7 +58,9 @@
 import com.android.server.backup.transport.TransportClient;
 import com.android.server.backup.transport.TransportClientManager;
 import com.android.server.backup.transport.TransportNotRegisteredException;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -64,6 +68,7 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowPackageManager;
 
 import java.util.ArrayList;
@@ -73,6 +78,7 @@
 import java.util.stream.Stream;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowApplicationPackageManager.class})
 @Presubmit
 public class TransportManagerTest {
     private static final String PACKAGE_A = "some.package.a";
@@ -84,12 +90,14 @@
     private TransportData mTransportA2;
     private TransportData mTransportB1;
     private ShadowPackageManager mShadowPackageManager;
+    private @UserIdInt int mUserId;
     private Context mContext;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
+        mUserId = UserHandle.USER_SYSTEM;
         mContext = RuntimeEnvironment.application;
         mShadowPackageManager = shadowOf(mContext.getPackageManager());
 
@@ -98,6 +106,12 @@
         mTransportB1 = genericTransport(PACKAGE_B, "TransportBaz");
     }
 
+    /** Reset shadow state. */
+    @After
+    public void tearDown() throws Exception {
+        ShadowApplicationPackageManager.reset();
+    }
+
     @Test
     public void testRegisterTransports() throws Exception {
         setUpPackage(PACKAGE_A, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
@@ -662,7 +676,8 @@
         packageInfo.packageName = packageName;
         packageInfo.applicationInfo = new ApplicationInfo();
         packageInfo.applicationInfo.privateFlags = flags;
-        mShadowPackageManager.addPackage(packageInfo);
+        mShadowPackageManager.installPackage(packageInfo);
+        ShadowApplicationPackageManager.addInstalledPackage(packageName, packageInfo);
     }
 
     private TransportManager createTransportManagerWithRegisteredTransports(
@@ -684,6 +699,7 @@
             @Nullable TransportData selectedTransport, TransportData... transports) {
         TransportManager transportManager =
                 new TransportManager(
+                        mUserId,
                         mContext,
                         merge(selectedTransport, transports)
                                 .stream()
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index bb60c27..427aed7 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -42,6 +42,8 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.os.Binder;
 import android.os.HandlerThread;
 import android.os.PowerManager;
@@ -54,6 +56,7 @@
 import com.android.server.backup.testing.TransportTestUtils.TransportMock;
 import com.android.server.backup.transport.TransportNotRegisteredException;
 import com.android.server.testing.shadows.ShadowAppBackupUtils;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
 import com.android.server.testing.shadows.ShadowBinder;
 import com.android.server.testing.shadows.ShadowKeyValueBackupJob;
 import com.android.server.testing.shadows.ShadowKeyValueBackupTask;
@@ -80,7 +83,7 @@
  * UserBackupManagerService} that performs operations for its target user.
  */
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowAppBackupUtils.class})
+@Config(shadows = {ShadowAppBackupUtils.class, ShadowApplicationPackageManager.class})
 @Presubmit
 public class UserBackupManagerServiceTest {
     private static final String TAG = "BMSTest";
@@ -137,6 +140,7 @@
     public void tearDown() throws Exception {
         mBackupThread.quit();
         ShadowAppBackupUtils.reset();
+        ShadowApplicationPackageManager.reset();
     }
 
     /**
@@ -195,6 +199,7 @@
     public void testIsAppEligibleForBackup_whenAppNotEligible() throws Exception {
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
         setUpCurrentTransport(mTransportManager, mTransport);
+        registerPackages(PACKAGE_1);
         UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
 
         boolean result = backupManagerService.isAppEligibleForBackup(PACKAGE_1);
@@ -210,6 +215,7 @@
     public void testIsAppEligibleForBackup_whenAppEligible() throws Exception {
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
         TransportMock transportMock = setUpCurrentTransport(mTransportManager, backupTransport());
+        registerPackages(PACKAGE_1);
         ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
         UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
 
@@ -228,6 +234,7 @@
     public void testIsAppEligibleForBackup_withoutPermission() throws Exception {
         mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
         setUpCurrentTransport(mTransportManager, mTransport);
+        registerPackages(PACKAGE_1);
         ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
         UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
 
@@ -245,6 +252,7 @@
     public void testFilterAppsEligibleForBackup() throws Exception {
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
         TransportMock transportMock = setUpCurrentTransport(mTransportManager, mTransport);
+        registerPackages(PACKAGE_1, PACKAGE_2);
         ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
         UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
 
@@ -264,6 +272,7 @@
     @Test
     public void testFilterAppsEligibleForBackup_whenNoneIsEligible() throws Exception {
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+        registerPackages(PACKAGE_1, PACKAGE_2);
         UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
 
         String[] filtered =
@@ -281,6 +290,7 @@
     public void testFilterAppsEligibleForBackup_withoutPermission() throws Exception {
         mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
         setUpCurrentTransport(mTransportManager, mTransport);
+        registerPackages(PACKAGE_1, PACKAGE_2);
         UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
 
         expectThrows(
@@ -504,10 +514,14 @@
     private void setUpForUpdateTransportAttributes() throws Exception {
         mTransportComponent = mTransport.getTransportComponent();
         String transportPackage = mTransportComponent.getPackageName();
+        PackageInfo packageInfo = getPackageInfo(transportPackage);
 
         ShadowPackageManager shadowPackageManager = shadowOf(mContext.getPackageManager());
-        shadowPackageManager.addPackage(transportPackage);
+        shadowPackageManager.installPackage(packageInfo);
         shadowPackageManager.setPackagesForUid(PACKAGE_UID, transportPackage);
+        // Set up for user invocations on ApplicationPackageManager.
+        ShadowApplicationPackageManager.addInstalledPackage(transportPackage, packageInfo);
+        ShadowApplicationPackageManager.setPackageUid(transportPackage, PACKAGE_UID);
 
         mTransportUid = mContext.getPackageManager().getPackageUid(transportPackage, 0);
     }
@@ -749,7 +763,7 @@
     private void setUpForRequestBackup(String... packages) throws Exception {
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
         for (String packageName : packages) {
-            mShadowPackageManager.addPackage(packageName);
+            registerPackages(packageName);
             ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(packageName);
         }
         setUpCurrentTransport(mTransportManager, mTransport);
@@ -829,7 +843,7 @@
     public void testRequestBackup_whenNotProvisioned() throws Exception {
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
         UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
-        backupManagerService.setProvisioned(false);
+        backupManagerService.setSetupComplete(false);
 
         int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0);
 
@@ -848,7 +862,7 @@
         setUpCurrentTransport(mTransportManager, mTransport.unregistered());
         UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
         backupManagerService.setEnabled(true);
-        backupManagerService.setProvisioned(true);
+        backupManagerService.setSetupComplete(true);
 
         int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0);
 
@@ -864,11 +878,11 @@
     @Test
     public void testRequestBackup_whenAppNotEligibleForBackup() throws Exception {
         mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
-        mShadowPackageManager.addPackage(PACKAGE_1);
+        registerPackages(PACKAGE_1);
         setUpCurrentTransport(mTransportManager, mTransport);
         UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
         backupManagerService.setEnabled(true);
-        backupManagerService.setProvisioned(true);
+        backupManagerService.setSetupComplete(true);
         // Haven't set PACKAGE_1 as eligible
 
         int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0);
@@ -965,14 +979,13 @@
     private UserBackupManagerService createBackupManagerServiceForRequestBackup() {
         UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
         backupManagerService.setEnabled(true);
-        backupManagerService.setProvisioned(true);
+        backupManagerService.setSetupComplete(true);
         return backupManagerService;
     }
 
     /**
-     * Test verifying that {@link UserBackupManagerService#createAndInitializeService(Context,
-     * Trampoline, HandlerThread, File, File, TransportManager)} posts a transport registration task
-     * to the backup thread.
+     * Test verifying that creating a new instance posts a transport registration task to the backup
+     * thread.
      */
     @Test
     public void testCreateAndInitializeService_postRegisterTransports() {
@@ -992,9 +1005,8 @@
     }
 
     /**
-     * Test verifying that {@link UserBackupManagerService#createAndInitializeService(Context,
-     * Trampoline, HandlerThread, File, File, TransportManager)} does not directly register
-     * transports on the main thread.
+     * Test verifying that creating a new instance does not directly register transports on the main
+     * thread.
      */
     @Test
     public void testCreateAndInitializeService_doesNotRegisterTransportsSynchronously() {
@@ -1013,11 +1025,7 @@
         verify(mTransportManager, never()).registerTransports();
     }
 
-    /**
-     * Test checking non-null argument on {@link
-     * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
-     * File, TransportManager)}.
-     */
+    /** Test checking non-null argument on instance creation. */
     @Test
     public void testCreateAndInitializeService_withNullContext_throws() {
         expectThrows(
@@ -1033,11 +1041,7 @@
                                 mTransportManager));
     }
 
-    /**
-     * Test checking non-null argument on {@link
-     * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
-     * File, TransportManager)}.
-     */
+    /** Test checking non-null argument on instance creation. */
     @Test
     public void testCreateAndInitializeService_withNullTrampoline_throws() {
         expectThrows(
@@ -1053,11 +1057,7 @@
                                 mTransportManager));
     }
 
-    /**
-     * Test checking non-null argument on {@link
-     * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
-     * File, TransportManager)}.
-     */
+    /** Test checking non-null argument on instance creation. */
     @Test
     public void testCreateAndInitializeService_withNullBackupThread_throws() {
         expectThrows(
@@ -1073,11 +1073,7 @@
                                 mTransportManager));
     }
 
-    /**
-     * Test checking non-null argument on {@link
-     * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
-     * File, TransportManager)}.
-     */
+    /** Test checking non-null argument on instance creation. */
     @Test
     public void testCreateAndInitializeService_withNullStateDir_throws() {
         expectThrows(
@@ -1145,6 +1141,22 @@
         backupManagerService.setPowerManager(powerManagerMock);
     }
 
+    private PackageInfo getPackageInfo(String packageName) {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = packageName;
+        packageInfo.applicationInfo = new ApplicationInfo();
+        packageInfo.applicationInfo.packageName = packageName;
+        return packageInfo;
+    }
+
+    private void registerPackages(String... packages) {
+        for (String packageName : packages) {
+            PackageInfo packageInfo = getPackageInfo(packageName);
+            mShadowPackageManager.installPackage(packageInfo);
+            ShadowApplicationPackageManager.addInstalledPackage(packageName, packageInfo);
+        }
+    }
+
     /**
      * We can't mock the void method {@link #schedule(Context, long, BackupManagerConstants)} so we
      * extend {@link ShadowKeyValueBackupJob} and throw an exception at the end of the method.
@@ -1155,8 +1167,9 @@
          * Implementation of {@link ShadowKeyValueBackupJob#schedule(Context, long,
          * BackupManagerConstants)} that throws an {@link IllegalArgumentException}.
          */
-        public static void schedule(Context ctx, long delay, BackupManagerConstants constants) {
-            ShadowKeyValueBackupJob.schedule(ctx, delay, constants);
+        public static void schedule(int userId, Context ctx, long delay,
+                BackupManagerConstants constants) {
+            ShadowKeyValueBackupJob.schedule(userId, ctx, delay, constants);
             throw new IllegalArgumentException();
         }
     }
diff --git a/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java b/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java
index 423512c..aca48b6 100644
--- a/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/fullbackup/AppMetadataBackupWriterTest.java
@@ -12,6 +12,7 @@
 import static org.testng.Assert.expectThrows;
 
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.Application;
 import android.app.backup.BackupDataInput;
 import android.app.backup.FullBackupDataOutput;
@@ -62,6 +63,7 @@
     private static final String TEST_PACKAGE_INSTALLER = "com.test.package.installer";
     private static final Long TEST_PACKAGE_VERSION_CODE = 100L;
 
+    private @UserIdInt int mUserId;
     private PackageManager mPackageManager;
     private ShadowApplicationPackageManager mShadowPackageManager;
     private File mFilesDir;
@@ -72,6 +74,7 @@
     public void setUp() throws Exception {
         Application application = RuntimeEnvironment.application;
 
+        mUserId = UserHandle.USER_SYSTEM;
         mPackageManager = application.getPackageManager();
         mShadowPackageManager = (ShadowApplicationPackageManager) shadowOf(mPackageManager);
 
@@ -352,7 +355,7 @@
         byte[] obbBytes = "obb".getBytes();
         File obbFile = createObbFileAndWrite(obbDir, obbBytes);
 
-        mBackupWriter.backupObb(packageInfo);
+        mBackupWriter.backupObb(mUserId, packageInfo);
 
         byte[] writtenBytes = getWrittenBytes(mBackupDataOutputFile, /* includeTarHeader */ false);
         assertThat(writtenBytes).isEqualTo(obbBytes);
@@ -366,7 +369,7 @@
         File obbDir = createObbDirForPackage(packageInfo.packageName);
         // No obb file created.
 
-        mBackupWriter.backupObb(packageInfo);
+        mBackupWriter.backupObb(mUserId, packageInfo);
 
         assertThat(mBackupDataOutputFile.length()).isEqualTo(0);
     }
diff --git a/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
new file mode 100644
index 0000000..bfb2b14
--- /dev/null
+++ b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.internal;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
+
+import com.android.server.backup.KeyValueBackupJob;
+import com.android.server.backup.TransportManager;
+import com.android.server.backup.UserBackupManagerService;
+import com.android.server.backup.testing.BackupManagerServiceTestUtils;
+import com.android.server.backup.testing.TestUtils;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.io.File;
+
+/**
+ * Tests verifying the interaction between {@link SetupObserver} and {@link
+ * UserBackupManagerService}.
+ */
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowApplicationPackageManager.class})
+@Presubmit
+public class SetupObserverTest {
+    private static final String TAG = "SetupObserverTest";
+    private static final int USER_ID = 10;
+
+    @Mock private TransportManager mTransportManager;
+
+    private Context mContext;
+    private UserBackupManagerService mUserBackupManagerService;
+    private HandlerThread mHandlerThread;
+
+    /** Setup state. */
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mHandlerThread = BackupManagerServiceTestUtils.startSilentBackupThread(TAG);
+        mUserBackupManagerService =
+                BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks(
+                        USER_ID,
+                        mContext,
+                        mHandlerThread,
+                        new File(mContext.getDataDir(), "test1"),
+                        new File(mContext.getDataDir(), "test2"),
+                        mTransportManager);
+    }
+
+    /** Test observer handles changes from not setup -> setup correctly. */
+    @Test
+    public void testOnChange_whenNewlySetup_updatesState() throws Exception {
+        SetupObserver setupObserver = new SetupObserver(mUserBackupManagerService, new Handler());
+        mUserBackupManagerService.setSetupComplete(false);
+        changeSetupCompleteSettingForUser(true, USER_ID);
+
+        setupObserver.onChange(true);
+
+        assertThat(mUserBackupManagerService.isSetupComplete()).isTrue();
+    }
+
+    /** Test observer handles changes from setup -> not setup correctly. */
+    @Test
+    public void testOnChange_whenPreviouslySetup_doesNotUpdateState() throws Exception {
+        SetupObserver setupObserver = new SetupObserver(mUserBackupManagerService, new Handler());
+        mUserBackupManagerService.setSetupComplete(true);
+        changeSetupCompleteSettingForUser(false, USER_ID);
+
+        setupObserver.onChange(true);
+
+        assertThat(mUserBackupManagerService.isSetupComplete()).isTrue();
+    }
+
+    /** Test observer handles changes from not setup -> not setup correctly. */
+    @Test
+    public void testOnChange_whenNotPreviouslySetup_doesNotUpdateStateIfNoChange()
+            throws Exception {
+        SetupObserver setupObserver = new SetupObserver(mUserBackupManagerService, new Handler());
+        mUserBackupManagerService.setSetupComplete(false);
+        changeSetupCompleteSettingForUser(false, USER_ID);
+
+        setupObserver.onChange(true);
+
+        assertThat(mUserBackupManagerService.isSetupComplete()).isFalse();
+    }
+
+    /** Test observer handles changes from not setup -> setup correctly. */
+    @Test
+    public void testOnChange_whenNewlySetup_schedulesBackup() throws Exception {
+        SetupObserver setupObserver = new SetupObserver(mUserBackupManagerService, new Handler());
+        mUserBackupManagerService.setSetupComplete(false);
+        changeSetupCompleteSettingForUser(true, USER_ID);
+        // Setup conditions for a full backup job to be scheduled.
+        mUserBackupManagerService.setEnabled(true);
+        mUserBackupManagerService.enqueueFullBackup("testPackage", /* lastBackedUp */ 0);
+        // Clear the handler of all pending tasks. This is to prevent the below assertion on the
+        // handler from encountering false positives due to other tasks being scheduled as part of
+        // setup work.
+        TestUtils.runToEndOfTasks(mHandlerThread.getLooper());
+
+        setupObserver.onChange(true);
+
+        assertThat(KeyValueBackupJob.isScheduled(mUserBackupManagerService.getUserId())).isTrue();
+        // Verifies that the full backup job is scheduled. The job is scheduled via a posted message
+        // on the backup handler so we verify that a message exists.
+        assertThat(mUserBackupManagerService.getBackupHandler().hasMessagesOrCallbacks()).isTrue();
+    }
+
+    private void changeSetupCompleteSettingForUser(boolean value, int userId) {
+        Settings.Secure.putIntForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.USER_SETUP_COMPLETE,
+                value ? 1 : 0,
+                userId);
+    }
+}
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 5e84ab0..164570a 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -115,6 +115,8 @@
 import com.android.server.backup.testing.TransportTestUtils;
 import com.android.server.backup.testing.TransportTestUtils.TransportMock;
 import com.android.server.testing.shadows.FrameworkShadowLooper;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
+import com.android.server.testing.shadows.ShadowBackupActivityThread;
 import com.android.server.testing.shadows.ShadowBackupDataInput;
 import com.android.server.testing.shadows.ShadowBackupDataOutput;
 import com.android.server.testing.shadows.ShadowEventLog;
@@ -157,10 +159,12 @@
 @Config(
         shadows = {
             FrameworkShadowLooper.class,
+            ShadowApplicationPackageManager.class,
             ShadowBackupDataInput.class,
             ShadowBackupDataOutput.class,
             ShadowEventLog.class,
             ShadowQueuedWork.class,
+            ShadowBackupActivityThread.class,
         })
 @Presubmit
 public class KeyValueBackupTaskTest {
@@ -244,6 +248,7 @@
     @After
     public void tearDown() throws Exception {
         ShadowBackupDataInput.reset();
+        ShadowApplicationPackageManager.reset();
     }
 
     @Test
@@ -2432,10 +2437,12 @@
 
     private AgentMock setUpAgent(PackageData packageData) {
         try {
+            String packageName = packageData.packageName;
             mPackageManager.setApplicationEnabledSetting(
-                    packageData.packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+                    packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
             PackageInfo packageInfo = getPackageInfo(packageData);
-            mShadowPackageManager.addPackage(packageInfo);
+            mShadowPackageManager.installPackage(packageInfo);
+            ShadowApplicationPackageManager.addInstalledPackage(packageName, packageInfo);
             mContext.sendBroadcast(getPackageAddedIntent(packageData));
             // Run the backup looper because on the receiver we post MSG_SCHEDULE_BACKUP_PACKAGE
             mShadowBackupLooper.runToEndOfTasks();
@@ -2531,7 +2538,7 @@
 
     private PackageManagerBackupAgent createPmAgent() {
         PackageManagerBackupAgent pmAgent =
-                new PackageManagerBackupAgent(mApplication.getPackageManager());
+                new PackageManagerBackupAgent(mApplication.getPackageManager(), USER_ID);
         pmAgent.attach(mApplication);
         pmAgent.onCreate();
         return pmAgent;
@@ -2721,7 +2728,7 @@
             throws RemoteException, IOException {
         verify(transportMock.transport).requestBackupTime();
         assertBackupPendingFor(packages);
-        assertThat(KeyValueBackupJob.isScheduled()).isTrue();
+        assertThat(KeyValueBackupJob.isScheduled(mBackupManagerService.getUserId())).isTrue();
     }
 
     private void assertBackupPendingFor(PackageData... packages) throws IOException {
@@ -2836,7 +2843,7 @@
 
         ThrowingPackageManagerBackupAgent(
                 PackageManager packageManager, RuntimeException exception) {
-            super(packageManager);
+            super(packageManager, USER_ID);
             mException = exception;
         }
 
diff --git a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
index 4009876..f17a9fe 100644
--- a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
@@ -57,6 +57,7 @@
 import com.android.server.backup.testing.TransportData;
 import com.android.server.backup.testing.TransportTestUtils;
 import com.android.server.backup.testing.TransportTestUtils.TransportMock;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
 import com.android.server.testing.shadows.ShadowEventLog;
 import com.android.server.testing.shadows.ShadowPerformUnifiedRestoreTask;
 
@@ -77,7 +78,13 @@
 import java.util.ArrayDeque;
 
 @RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowEventLog.class, ShadowPerformUnifiedRestoreTask.class, ShadowBinder.class})
+@Config(
+        shadows = {
+            ShadowApplicationPackageManager.class,
+            ShadowBinder.class,
+            ShadowEventLog.class,
+            ShadowPerformUnifiedRestoreTask.class
+        })
 @Presubmit
 public class ActiveRestoreSessionTest {
     private static final String PACKAGE_1 = "com.example.package1";
@@ -140,6 +147,7 @@
 
     @After
     public void tearDown() throws Exception {
+        ShadowApplicationPackageManager.reset();
         ShadowPerformUnifiedRestoreTask.reset();
     }
 
@@ -561,7 +569,8 @@
         packageInfo.packageName = packageName;
         packageInfo.applicationInfo = new ApplicationInfo();
         packageInfo.applicationInfo.uid = uid;
-        mShadowPackageManager.addPackage(packageInfo);
+        mShadowPackageManager.installPackage(packageInfo);
+        ShadowApplicationPackageManager.addInstalledPackage(packageName, packageInfo);
     }
 
     private IRestoreSession createActiveRestoreSession(
diff --git a/services/robotests/backup/src/com/android/server/backup/transport/TransportClientManagerTest.java b/services/robotests/backup/src/com/android/server/backup/transport/TransportClientManagerTest.java
index 7dd0d92..f033af8 100644
--- a/services/robotests/backup/src/com/android/server/backup/transport/TransportClientManagerTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/transport/TransportClientManagerTest.java
@@ -25,6 +25,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -49,6 +50,7 @@
 
     @Mock private Context mContext;
     @Mock private TransportConnectionListener mTransportConnectionListener;
+    private @UserIdInt int mUserId;
     private TransportClientManager mTransportClientManager;
     private ComponentName mTransportComponent;
     private Intent mBindIntent;
@@ -57,7 +59,9 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mTransportClientManager = new TransportClientManager(mContext, new TransportStats());
+        mUserId = UserHandle.USER_SYSTEM;
+        mTransportClientManager =
+                new TransportClientManager(mUserId, mContext, new TransportStats());
         mTransportComponent = new ComponentName(PACKAGE_NAME, CLASS_NAME);
         mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent);
 
diff --git a/services/robotests/backup/src/com/android/server/backup/transport/TransportClientTest.java b/services/robotests/backup/src/com/android/server/backup/transport/TransportClientTest.java
index 7281a3c..392f2ca 100644
--- a/services/robotests/backup/src/com/android/server/backup/transport/TransportClientTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/transport/TransportClientTest.java
@@ -36,6 +36,7 @@
 import static org.testng.Assert.expectThrows;
 
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -83,6 +84,7 @@
     @Mock private TransportConnectionListener mTransportConnectionListener;
     @Mock private TransportConnectionListener mTransportConnectionListener2;
     @Mock private IBackupTransport.Stub mTransportBinder;
+    @UserIdInt private int mUserId;
     private TransportStats mTransportStats;
     private TransportClient mTransportClient;
     private ComponentName mTransportComponent;
@@ -96,6 +98,7 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
+        mUserId = UserHandle.USER_SYSTEM;
         Looper mainLooper = Looper.getMainLooper();
         mShadowMainLooper = extract(mainLooper);
         mTransportComponent =
@@ -105,6 +108,7 @@
         mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent);
         mTransportClient =
                 new TransportClient(
+                        mUserId,
                         mContext,
                         mTransportStats,
                         mBindIntent,
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java b/services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java
index 5fffb14..33b8aa7 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java
@@ -54,12 +54,15 @@
 
     @Implementation
     protected static boolean appIsRunningAndEligibleForBackupWithTransport(
-            @Nullable TransportClient transportClient, String packageName, PackageManager pm) {
+            @Nullable TransportClient transportClient,
+            String packageName,
+            PackageManager pm,
+            int userId) {
         return sAppsRunningAndEligibleForBackupWithTransport.contains(packageName);
     }
 
     @Implementation
-    protected static boolean appIsEligibleForBackup(ApplicationInfo app, PackageManager pm) {
+    protected static boolean appIsEligibleForBackup(ApplicationInfo app, int userId) {
         return sAppsEligibleForBackup.contains(app.packageName);
     }
 
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
new file mode 100644
index 0000000..ab121ed
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.testing.shadows;
+
+import static android.content.pm.PackageManager.NameNotFoundException;
+
+import android.app.ApplicationPackageManager;
+import android.content.pm.PackageInfo;
+import android.util.ArrayMap;
+
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Extends {@link org.robolectric.shadows.ShadowApplicationPackageManager} to return the correct
+ * package in user-specific invocations.
+ */
+@Implements(value = ApplicationPackageManager.class)
+public class ShadowApplicationPackageManager
+        extends org.robolectric.shadows.ShadowApplicationPackageManager {
+    private static final Map<String, PackageInfo> sPackageInfos = new ArrayMap<>();
+    private static final List<PackageInfo> sInstalledPackages = new ArrayList<>();
+    private static final Map<String, Integer> sPackageUids = new ArrayMap<>();
+
+    /**
+     * Registers the package {@code packageName} to be returned when invoking {@link
+     * ApplicationPackageManager#getPackageInfoAsUser(String, int, int)} and {@link
+     * ApplicationPackageManager#getInstalledPackagesAsUser(int, int)}.
+     */
+    public static void addInstalledPackage(String packageName, PackageInfo packageInfo) {
+        sPackageInfos.put(packageName, packageInfo);
+        sInstalledPackages.add(packageInfo);
+    }
+
+    /**
+     * Sets the package uid {@code packageUid} for the package {@code packageName} to be returned
+     * when invoking {@link ApplicationPackageManager#getPackageUidAsUser(String, int, int)}.
+     */
+    public static void setPackageUid(String packageName, int packageUid) {
+        sPackageUids.put(packageName, packageUid);
+    }
+
+    @Override
+    protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
+            throws NameNotFoundException {
+        if (!sPackageInfos.containsKey(packageName)) {
+            throw new NameNotFoundException(packageName);
+        }
+        return sPackageInfos.get(packageName);
+    }
+
+    @Override
+    protected List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
+        return sInstalledPackages;
+    }
+
+    @Override
+    protected int getPackageUidAsUser(String packageName, int flags, int userId)
+            throws NameNotFoundException {
+        if (!sPackageUids.containsKey(packageName)) {
+            throw new NameNotFoundException(packageName);
+        }
+        return sPackageUids.get(packageName);
+    }
+
+    /** Clear package state. */
+    @Resetter
+    public static void reset() {
+        sPackageInfos.clear();
+        sInstalledPackages.clear();
+        org.robolectric.shadows.ShadowApplicationPackageManager.reset();
+    }
+}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupActivityThread.java b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupActivityThread.java
new file mode 100644
index 0000000..ca2e3b6
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupActivityThread.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.testing.shadows;
+
+import android.app.ActivityThread;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowActivityThread;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Extends the existing {@link ShadowActivityThread} to add support for
+ * {@link PackageManager#getApplicationEnabledSetting(String)} in the shadow {@link PackageManager}
+ * returned  by {@link ShadowBackupActivityThread#getPackageManager()}.
+ */
+@Implements(value = ActivityThread.class, isInAndroidSdk = false, looseSignatures = true)
+public class ShadowBackupActivityThread extends ShadowActivityThread {
+    @Implementation
+    public static Object getPackageManager() {
+        ClassLoader classLoader = ShadowActivityThread.class.getClassLoader();
+        Class<?> iPackageManagerClass;
+        try {
+            iPackageManagerClass = classLoader.loadClass("android.content.pm.IPackageManager");
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+
+        return Proxy.newProxyInstance(
+                classLoader,
+                new Class[] {iPackageManagerClass},
+                new InvocationHandler() {
+                    @Override
+                    public Object invoke(Object proxy, @Nonnull Method method, Object[] args)
+                            throws Exception {
+                        if (method.getName().equals("getApplicationInfo")) {
+                            String packageName = (String) args[0];
+                            int flags = (Integer) args[1];
+
+                            try {
+                                return RuntimeEnvironment.application
+                                        .getPackageManager()
+                                        .getApplicationInfo(packageName, flags);
+                            } catch (PackageManager.NameNotFoundException e) {
+                                throw new RemoteException(e.getMessage());
+                            }
+                        } else if (method.getName().equals("getApplicationEnabledSetting")) {
+                            return 0;
+                        } else {
+                            return null;
+                        }
+                    }
+                });
+    }
+}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupJob.java b/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupJob.java
index 23c44b0..f90ea6a 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupJob.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupJob.java
@@ -34,7 +34,8 @@
     }
 
     @Implementation
-    protected static void schedule(Context ctx, long delay, BackupManagerConstants constants) {
+    protected static void schedule(int userId, Context ctx, long delay,
+            BackupManagerConstants constants) {
         callingUid = Binder.getCallingUid();
     }
 }
diff --git a/services/startop/Android.bp b/services/startop/Android.bp
new file mode 100644
index 0000000..093b4ec
--- /dev/null
+++ b/services/startop/Android.bp
@@ -0,0 +1,24 @@
+/*
+ * 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_library_static {
+    name: "services.startop",
+
+    static_libs: [
+        // frameworks/base/startop/iorap
+        "services.startop.iorap",
+    ],
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 148faad..6386b3b3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -28,14 +28,18 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.AlarmManagerService.ACTIVE_INDEX;
+import static com.android.server.AlarmManagerService.AlarmHandler.APP_STANDBY_BUCKET_CHANGED;
+import static com.android.server.AlarmManagerService.AlarmHandler.APP_STANDBY_PAROLE_CHANGED;
 import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_LONG_TIME;
 import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_SHORT_TIME;
-import static com.android.server.AlarmManagerService.Constants
-        .KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
+import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
+import static com.android.server.AlarmManagerService.Constants.KEY_APP_STANDBY_QUOTAS_ENABLED;
 import static com.android.server.AlarmManagerService.Constants.KEY_LISTENER_TIMEOUT;
 import static com.android.server.AlarmManagerService.Constants.KEY_MAX_INTERVAL;
 import static com.android.server.AlarmManagerService.Constants.KEY_MIN_FUTURITY;
 import static com.android.server.AlarmManagerService.Constants.KEY_MIN_INTERVAL;
+import static com.android.server.AlarmManagerService.WORKING_INDEX;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -58,13 +62,14 @@
 import android.content.Intent;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Message;
 import android.os.PowerManager;
 import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.SparseArray;
 
-import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.annotations.GuardedBy;
@@ -81,7 +86,7 @@
 
 import java.util.ArrayList;
 
-@SmallTest
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class AlarmManagerServiceTest {
     private static final String TAG = AlarmManagerServiceTest.class.getSimpleName();
@@ -89,7 +94,9 @@
     private static final int SYSTEM_UI_UID = 123456789;
     private static final int TEST_CALLING_UID = 12345;
 
+    private long mAppStandbyWindow;
     private AlarmManagerService mService;
+    private UsageStatsManagerInternal.AppIdleStateChangeListener mAppStandbyListener;
     @Mock
     private ContentResolver mMockResolver;
     @Mock
@@ -227,16 +234,23 @@
         mService = new AlarmManagerService(mMockContext, mInjector);
         spyOn(mService);
         doNothing().when(mService).publishBinderService(any(), any());
-        mService.onStart();
-        mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
-        spyOn(mService.mHandler);
 
-        assertEquals(0, mService.mConstants.MIN_FUTURITY);
+        mService.onStart();
+        spyOn(mService.mHandler);
         assertEquals(mService.mSystemUiUid, SYSTEM_UI_UID);
         assertEquals(mService.mClockReceiver, mClockReceiver);
         assertEquals(mService.mWakeLock, mWakeLock);
         verify(mIActivityManager).registerUidObserver(any(IUidObserver.class), anyInt(), anyInt(),
                 isNull());
+
+        // Other boot phases don't matter
+        mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+        assertEquals(0, mService.mConstants.MIN_FUTURITY);
+        mAppStandbyWindow = mService.mConstants.APP_STANDBY_WINDOW;
+        ArgumentCaptor<UsageStatsManagerInternal.AppIdleStateChangeListener> captor =
+                ArgumentCaptor.forClass(UsageStatsManagerInternal.AppIdleStateChangeListener.class);
+        verify(mUsageStatsManagerInternal).addAppIdleStateChangeListener(captor.capture());
+        mAppStandbyListener = captor.getValue();
     }
 
     private void setTestAlarm(int type, long triggerTime, PendingIntent operation) {
@@ -252,6 +266,28 @@
         return mockPi;
     }
 
+    /**
+     * Careful while calling as this will replace any existing settings for the calling test.
+     */
+    private void setQuotasEnabled(boolean enabled) {
+        final StringBuilder constantsBuilder = new StringBuilder();
+        constantsBuilder.append(KEY_MIN_FUTURITY);
+        constantsBuilder.append("=0,");
+        // Capping active and working quotas to make testing feasible.
+        constantsBuilder.append(mService.mConstants.KEYS_APP_STANDBY_QUOTAS[ACTIVE_INDEX]);
+        constantsBuilder.append("=8,");
+        constantsBuilder.append(mService.mConstants.KEYS_APP_STANDBY_QUOTAS[WORKING_INDEX]);
+        constantsBuilder.append("=5,");
+        if (!enabled) {
+            constantsBuilder.append(KEY_APP_STANDBY_QUOTAS_ENABLED);
+            constantsBuilder.append("=false,");
+        }
+        doReturn(constantsBuilder.toString()).when(() -> Settings.Global.getString(mMockResolver,
+                Settings.Global.ALARM_MANAGER_CONSTANTS));
+        mService.mConstants.onChange(false, null);
+        assertEquals(mService.mConstants.APP_STANDBY_QUOTAS_ENABLED, enabled);
+    }
+
     @Test
     public void testSingleAlarmSet() {
         final long triggerTime = mNowElapsedTest + 5000;
@@ -344,6 +380,7 @@
 
     @Test
     public void testStandbyBucketDelay_workingSet() throws Exception {
+        setQuotasEnabled(false);
         setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, getNewMockPendingIntent());
         setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, getNewMockPendingIntent());
         assertEquals(mNowElapsedTest + 5, mTestTimer.getElapsed());
@@ -364,6 +401,7 @@
 
     @Test
     public void testStandbyBucketDelay_frequent() throws Exception {
+        setQuotasEnabled(false);
         setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, getNewMockPendingIntent());
         setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, getNewMockPendingIntent());
         assertEquals(mNowElapsedTest + 5, mTestTimer.getElapsed());
@@ -383,6 +421,7 @@
 
     @Test
     public void testStandbyBucketDelay_rare() throws Exception {
+        setQuotasEnabled(false);
         setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, getNewMockPendingIntent());
         setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, getNewMockPendingIntent());
         assertEquals(mNowElapsedTest + 5, mTestTimer.getElapsed());
@@ -400,6 +439,253 @@
         assertEquals("Incorrect next alarm trigger.", expectedNextTrigger, mTestTimer.getElapsed());
     }
 
+    private void testQuotasDeferralOnSet(int standbyBucket) throws Exception {
+        final int quota = mService.getQuotaForBucketLocked(standbyBucket);
+        when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
+                anyLong())).thenReturn(standbyBucket);
+        final long firstTrigger = mNowElapsedTest + 10;
+        for (int i = 0; i < quota; i++) {
+            setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 10 + i,
+                    getNewMockPendingIntent());
+            mNowElapsedTest = mTestTimer.getElapsed();
+            mTestTimer.expire();
+        }
+        // This one should get deferred on set
+        setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + quota + 10,
+                getNewMockPendingIntent());
+        final long expectedNextTrigger = firstTrigger + 1 + mAppStandbyWindow;
+        assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed());
+    }
+
+    private void testQuotasDeferralOnExpiration(int standbyBucket) throws Exception {
+        final int quota = mService.getQuotaForBucketLocked(standbyBucket);
+        when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
+                anyLong())).thenReturn(standbyBucket);
+        final long firstTrigger = mNowElapsedTest + 10;
+        for (int i = 0; i < quota; i++) {
+            setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 10 + i,
+                    getNewMockPendingIntent());
+        }
+        // This one should get deferred after the latest alarm expires
+        setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + quota + 10,
+                getNewMockPendingIntent());
+        for (int i = 0; i < quota; i++) {
+            mNowElapsedTest = mTestTimer.getElapsed();
+            mTestTimer.expire();
+        }
+        final long expectedNextTrigger = firstTrigger + 1 + mAppStandbyWindow;
+        assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed());
+    }
+
+    private void testQuotasNoDeferral(int standbyBucket) throws Exception {
+        final int quota = mService.getQuotaForBucketLocked(standbyBucket);
+        when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
+                anyLong())).thenReturn(standbyBucket);
+        final long firstTrigger = mNowElapsedTest + 10;
+        for (int i = 0; i < quota; i++) {
+            setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 10 + i,
+                    getNewMockPendingIntent());
+        }
+        // This delivery time maintains the quota invariant. Should not be deferred.
+        final long expectedNextTrigger = firstTrigger + mAppStandbyWindow + 5;
+        setTestAlarm(ELAPSED_REALTIME_WAKEUP, expectedNextTrigger, getNewMockPendingIntent());
+        for (int i = 0; i < quota; i++) {
+            mNowElapsedTest = mTestTimer.getElapsed();
+            mTestTimer.expire();
+        }
+        assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed());
+    }
+
+    @Test
+    public void testActiveQuota_deferredOnSet() throws Exception {
+        setQuotasEnabled(true);
+        testQuotasDeferralOnSet(STANDBY_BUCKET_ACTIVE);
+    }
+
+    @Test
+    public void testActiveQuota_deferredOnExpiration() throws Exception {
+        setQuotasEnabled(true);
+        testQuotasDeferralOnExpiration(STANDBY_BUCKET_ACTIVE);
+    }
+
+    @Test
+    public void testActiveQuota_notDeferred() throws Exception {
+        setQuotasEnabled(true);
+        testQuotasNoDeferral(STANDBY_BUCKET_ACTIVE);
+    }
+
+    @Test
+    public void testWorkingQuota_deferredOnSet() throws Exception {
+        setQuotasEnabled(true);
+        testQuotasDeferralOnSet(STANDBY_BUCKET_WORKING_SET);
+    }
+
+    @Test
+    public void testWorkingQuota_deferredOnExpiration() throws Exception {
+        setQuotasEnabled(true);
+        testQuotasDeferralOnExpiration(STANDBY_BUCKET_WORKING_SET);
+    }
+
+    @Test
+    public void testWorkingQuota_notDeferred() throws Exception {
+        setQuotasEnabled(true);
+        testQuotasNoDeferral(STANDBY_BUCKET_WORKING_SET);
+    }
+
+    @Test
+    public void testFrequentQuota_deferredOnSet() throws Exception {
+        setQuotasEnabled(true);
+        testQuotasDeferralOnSet(STANDBY_BUCKET_FREQUENT);
+    }
+
+    @Test
+    public void testFrequentQuota_deferredOnExpiration() throws Exception {
+        setQuotasEnabled(true);
+        testQuotasDeferralOnExpiration(STANDBY_BUCKET_FREQUENT);
+    }
+
+    @Test
+    public void testFrequentQuota_notDeferred() throws Exception {
+        setQuotasEnabled(true);
+        testQuotasNoDeferral(STANDBY_BUCKET_FREQUENT);
+    }
+
+    @Test
+    public void testRareQuota_deferredOnSet() throws Exception {
+        setQuotasEnabled(true);
+        testQuotasDeferralOnSet(STANDBY_BUCKET_RARE);
+    }
+
+    @Test
+    public void testRareQuota_deferredOnExpiration() throws Exception {
+        setQuotasEnabled(true);
+        testQuotasDeferralOnExpiration(STANDBY_BUCKET_RARE);
+    }
+
+    @Test
+    public void testRareQuota_notDeferred() throws Exception {
+        setQuotasEnabled(true);
+        testQuotasNoDeferral(STANDBY_BUCKET_RARE);
+    }
+
+    private void sendAndHandleBucketChanged(int bucket) {
+        when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
+                anyLong())).thenReturn(bucket);
+        // Stubbing the handler call to simulate it synchronously here.
+        doReturn(true).when(mService.mHandler).sendMessage(any(Message.class));
+        mAppStandbyListener.onAppIdleStateChanged(TEST_CALLING_PACKAGE,
+                UserHandle.getUserId(TEST_CALLING_UID), false, bucket, 0);
+        final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+        verify(mService.mHandler, atLeastOnce()).sendMessage(messageCaptor.capture());
+        final Message lastMessage = messageCaptor.getValue();
+        assertEquals("Unexpected message send to handler", lastMessage.what,
+                APP_STANDBY_BUCKET_CHANGED);
+        mService.mHandler.handleMessage(lastMessage);
+    }
+
+    @Test
+    public void testQuotaDowngrade() throws Exception {
+        setQuotasEnabled(true);
+        final int workingQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_WORKING_SET);
+        when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
+                anyLong())).thenReturn(STANDBY_BUCKET_WORKING_SET);
+
+        final long firstTrigger = mNowElapsedTest + 10;
+        for (int i = 0; i < workingQuota; i++) {
+            setTestAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i, getNewMockPendingIntent());
+        }
+        // No deferrals now.
+        for (int i = 0; i < workingQuota - 1; i++) {
+            mNowElapsedTest = mTestTimer.getElapsed();
+            assertEquals(firstTrigger + i, mNowElapsedTest);
+            mTestTimer.expire();
+        }
+        // The next upcoming alarm in queue should also be set as expected.
+        assertEquals(firstTrigger + workingQuota - 1, mTestTimer.getElapsed());
+        // Downgrading the bucket now
+        sendAndHandleBucketChanged(STANDBY_BUCKET_RARE);
+        final int rareQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_RARE);
+        // The last alarm should now be deferred.
+        final long expectedNextTrigger = (firstTrigger + workingQuota - 1 - rareQuota)
+                + mAppStandbyWindow + 1;
+        assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed());
+    }
+
+    @Test
+    public void testQuotaUpgrade() throws Exception {
+        setQuotasEnabled(true);
+        final int frequentQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_FREQUENT);
+        when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
+                anyLong())).thenReturn(STANDBY_BUCKET_FREQUENT);
+
+        final long firstTrigger = mNowElapsedTest + 10;
+        for (int i = 0; i < frequentQuota + 1; i++) {
+            setTestAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i, getNewMockPendingIntent());
+            if (i < frequentQuota) {
+                mNowElapsedTest = mTestTimer.getElapsed();
+                mTestTimer.expire();
+            }
+        }
+        // The last alarm should be deferred due to exceeding the quota
+        final long deferredTrigger = firstTrigger + 1 + mAppStandbyWindow;
+        assertEquals(deferredTrigger, mTestTimer.getElapsed());
+
+        // Upgrading the bucket now
+        sendAndHandleBucketChanged(STANDBY_BUCKET_ACTIVE);
+        // The last alarm should now be rescheduled to go as per original expectations
+        final long originalTrigger = firstTrigger + frequentQuota;
+        assertEquals("Incorrect next alarm trigger", originalTrigger, mTestTimer.getElapsed());
+    }
+
+    private void sendAndHandleParoleChanged(boolean parole) {
+        // Stubbing the handler call to simulate it synchronously here.
+        doReturn(true).when(mService.mHandler).sendMessage(any(Message.class));
+        mAppStandbyListener.onParoleStateChanged(parole);
+        final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+        verify(mService.mHandler, atLeastOnce()).sendMessage(messageCaptor.capture());
+        final Message lastMessage = messageCaptor.getValue();
+        assertEquals("Unexpected message send to handler", lastMessage.what,
+                APP_STANDBY_PAROLE_CHANGED);
+        mService.mHandler.handleMessage(lastMessage);
+    }
+
+    @Test
+    public void testParole() throws Exception {
+        setQuotasEnabled(true);
+        final int workingQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_WORKING_SET);
+        when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
+                anyLong())).thenReturn(STANDBY_BUCKET_WORKING_SET);
+
+        final long firstTrigger = mNowElapsedTest + 10;
+        final int totalAlarms = workingQuota + 10;
+        for (int i = 0; i < totalAlarms; i++) {
+            setTestAlarm(ELAPSED_REALTIME_WAKEUP, firstTrigger + i, getNewMockPendingIntent());
+        }
+        // Use up the quota, no deferrals expected.
+        for (int i = 0; i < workingQuota; i++) {
+            mNowElapsedTest = mTestTimer.getElapsed();
+            assertEquals(firstTrigger + i, mNowElapsedTest);
+            mTestTimer.expire();
+        }
+        // Any subsequent alarms in queue should all be deferred
+        assertEquals(firstTrigger + mAppStandbyWindow + 1, mTestTimer.getElapsed());
+        // Paroling now
+        sendAndHandleParoleChanged(true);
+
+        // Subsequent alarms should now go off as per original expectations.
+        for (int i = 0; i < 5; i++) {
+            mNowElapsedTest = mTestTimer.getElapsed();
+            assertEquals(firstTrigger + workingQuota + i, mNowElapsedTest);
+            mTestTimer.expire();
+        }
+        // Come out of parole
+        sendAndHandleParoleChanged(false);
+
+        // Subsequent alarms should again get deferred
+        final long expectedNextTrigger = (firstTrigger + 5) + 1 + mAppStandbyWindow;
+        assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed());
+    }
+
     @Test
     public void testAlarmRestrictedInBatterSaver() throws Exception {
         final ArgumentCaptor<AppStateTracker.Listener> listenerArgumentCaptor =
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 1a16e56..53d72bb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -1376,6 +1376,45 @@
         verifyLightStateConditions(LIGHT_STATE_ACTIVE);
     }
 
+    @Test
+    public void testStepToIdleMode() {
+        float delta = mDeviceIdleController.MIN_PRE_IDLE_FACTOR_CHANGE;
+        for (int mode = PowerManager.PRE_IDLE_TIMEOUT_MODE_NORMAL;
+                mode <= PowerManager.PRE_IDLE_TIMEOUT_MODE_LONG;
+                mode++) {
+            int ret = mDeviceIdleController.setPreIdleTimeoutMode(mode);
+            if (mode == PowerManager.PRE_IDLE_TIMEOUT_MODE_NORMAL) {
+                assertEquals("setPreIdleTimeoutMode: " + mode + " failed.",
+                        mDeviceIdleController.SET_IDLE_FACTOR_RESULT_IGNORED, ret);
+            } else {
+                assertEquals("setPreIdleTimeoutMode: " + mode + " failed.",
+                        mDeviceIdleController.SET_IDLE_FACTOR_RESULT_OK, ret);
+            }
+            //TODO(b/123045185): Mocked Handler of DeviceIdleController to make message loop
+            //workable in this test class
+            mDeviceIdleController.updatePreIdleFactor();
+            float expectedfactor = mDeviceIdleController.getPreIdleTimeoutByMode(mode);
+            float curfactor = mDeviceIdleController.getPreIdleTimeoutFactor();
+            assertEquals("Pre idle time factor of mode [" + mode + "].",
+                    expectedfactor, curfactor, delta);
+            mDeviceIdleController.resetPreIdleTimeoutMode();
+            mDeviceIdleController.updatePreIdleFactor();
+
+            checkNextAlarmTimeWithNewPreIdleFactor(expectedfactor, STATE_INACTIVE);
+            checkNextAlarmTimeWithNewPreIdleFactor(expectedfactor, STATE_IDLE_PENDING);
+
+            checkNextAlarmTimeWithNewPreIdleFactor(expectedfactor, STATE_SENSING);
+            checkNextAlarmTimeWithNewPreIdleFactor(expectedfactor, STATE_LOCATING);
+            checkNextAlarmTimeWithNewPreIdleFactor(expectedfactor, STATE_QUICK_DOZE_DELAY);
+            checkNextAlarmTimeWithNewPreIdleFactor(expectedfactor, STATE_IDLE_MAINTENANCE);
+            checkNextAlarmTimeWithNewPreIdleFactor(expectedfactor, STATE_IDLE);
+            checkMaybeDoAnImmediateMaintenance(expectedfactor);
+        }
+        float curfactor = mDeviceIdleController.getPreIdleTimeoutFactor();
+        assertEquals("Pre idle time factor of mode default.",
+                1.0f, curfactor, delta);
+    }
+
     private void enterDeepState(int state) {
         switch (state) {
             case STATE_ACTIVE:
@@ -1599,4 +1638,84 @@
                 fail("Conditions for " + lightStateToString(expectedLightState) + " unknown.");
         }
     }
+
+    private void checkNextAlarmTimeWithNewPreIdleFactor(float factor, int state) {
+        final long errorTolerance = 1000;
+        enterDeepState(state);
+        long now = SystemClock.elapsedRealtime();
+        long alarm = mDeviceIdleController.getNextAlarmTime();
+        if (state == STATE_INACTIVE || state == STATE_IDLE_PENDING) {
+            int ret = mDeviceIdleController.setPreIdleTimeoutFactor(factor);
+            if (Float.compare(factor, 1.0f) == 0) {
+                assertEquals("setPreIdleTimeoutMode: " + factor + " failed.",
+                        mDeviceIdleController.SET_IDLE_FACTOR_RESULT_IGNORED, ret);
+            } else {
+                assertEquals("setPreIdleTimeoutMode: " + factor + " failed.",
+                        mDeviceIdleController.SET_IDLE_FACTOR_RESULT_OK, ret);
+            }
+            if (ret == mDeviceIdleController.SET_IDLE_FACTOR_RESULT_OK) {
+                mDeviceIdleController.updatePreIdleFactor();
+                long newAlarm = mDeviceIdleController.getNextAlarmTime();
+                long newDelay = (long) ((alarm - now) * factor);
+                assertTrue("setPreIdleTimeoutFactor: " + factor,
+                        Math.abs(newDelay - (newAlarm - now)) <  errorTolerance);
+                mDeviceIdleController.resetPreIdleTimeoutMode();
+                mDeviceIdleController.updatePreIdleFactor();
+                mDeviceIdleController.maybeDoImmediateMaintenance();
+                newAlarm = mDeviceIdleController.getNextAlarmTime();
+                assertTrue("resetPreIdleTimeoutMode from: " + factor,
+                        Math.abs(newAlarm - alarm) < errorTolerance);
+                mDeviceIdleController.setPreIdleTimeoutFactor(factor);
+                now = SystemClock.elapsedRealtime();
+                enterDeepState(state);
+                newAlarm = mDeviceIdleController.getNextAlarmTime();
+                assertTrue("setPreIdleTimeoutFactor: " + factor + " before step to idle",
+                        Math.abs(newDelay - (newAlarm - now)) <  errorTolerance);
+                mDeviceIdleController.resetPreIdleTimeoutMode();
+                mDeviceIdleController.updatePreIdleFactor();
+                mDeviceIdleController.maybeDoImmediateMaintenance();
+            }
+        } else {
+            mDeviceIdleController.setPreIdleTimeoutFactor(factor);
+            mDeviceIdleController.updatePreIdleFactor();
+            long newAlarm = mDeviceIdleController.getNextAlarmTime();
+            assertTrue("setPreIdleTimeoutFactor: " + factor
+                    + " shounld not change next alarm" ,
+                    (newAlarm == alarm));
+            mDeviceIdleController.resetPreIdleTimeoutMode();
+            mDeviceIdleController.updatePreIdleFactor();
+            mDeviceIdleController.maybeDoImmediateMaintenance();
+        }
+    }
+
+    private void checkMaybeDoAnImmediateMaintenance(float factor) {
+        int ret = mDeviceIdleController.setPreIdleTimeoutFactor(factor);
+        final long minuteInMillis = 60 * 1000;
+        if (Float.compare(factor, 1.0f) == 0) {
+            assertEquals("setPreIdleTimeoutMode: " + factor + " failed.",
+                    mDeviceIdleController.SET_IDLE_FACTOR_RESULT_IGNORED, ret);
+        } else {
+            assertEquals("setPreIdleTimeoutMode: " + factor + " failed.",
+                    mDeviceIdleController.SET_IDLE_FACTOR_RESULT_OK, ret);
+        }
+        if (ret == mDeviceIdleController.SET_IDLE_FACTOR_RESULT_OK) {
+            enterDeepState(STATE_IDLE);
+            long now = SystemClock.elapsedRealtime();
+            long alarm = mDeviceIdleController.getNextAlarmTime();
+            mDeviceIdleController.setIdleStartTimeForTest(
+                    now - (long) (mConstants.IDLE_TIMEOUT * 0.6));
+            mDeviceIdleController.maybeDoImmediateMaintenance();
+            long newAlarm = mDeviceIdleController.getNextAlarmTime();
+            assertTrue("maintenance not reschedule IDLE_TIMEOUT * 0.6",
+                    newAlarm == alarm);
+            mDeviceIdleController.setIdleStartTimeForTest(
+                    now - (long) (mConstants.IDLE_TIMEOUT * 1.2));
+            mDeviceIdleController.maybeDoImmediateMaintenance();
+            newAlarm = mDeviceIdleController.getNextAlarmTime();
+            assertTrue("maintenance not reschedule IDLE_TIMEOUT * 1.2",
+                    (newAlarm - now) < minuteInMillis);
+            mDeviceIdleController.resetPreIdleTimeoutMode();
+            mDeviceIdleController.updatePreIdleFactor();
+        }
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index f1cd0cd..cad71a2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -25,6 +25,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
 import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX;
+import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
 import static com.android.server.job.JobSchedulerService.RARE_INDEX;
 import static com.android.server.job.JobSchedulerService.WORKING_INDEX;
 
@@ -33,6 +34,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -43,7 +45,12 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
+import android.app.AppGlobals;
+import android.app.IActivityManager;
+import android.app.IUidObserver;
 import android.app.job.JobInfo;
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
@@ -56,13 +63,16 @@
 import android.os.BatteryManagerInternal;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.os.SystemClock;
+import android.util.SparseBooleanArray;
 
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.JobSchedulerService.Constants;
+import com.android.server.job.JobStore;
 import com.android.server.job.controllers.QuotaController.ExecutionStats;
 import com.android.server.job.controllers.QuotaController.TimingSession;
 
@@ -96,9 +106,13 @@
     private BroadcastReceiver mChargingReceiver;
     private Constants mConstants;
     private QuotaController mQuotaController;
+    private int mSourceUid;
+    private IUidObserver mUidObserver;
 
     private MockitoSession mMockingSession;
     @Mock
+    private ActivityManagerInternal mActivityMangerInternal;
+    @Mock
     private AlarmManager mAlarmManager;
     @Mock
     private Context mContext;
@@ -107,6 +121,8 @@
     @Mock
     private UsageStatsManagerInternal mUsageStatsManager;
 
+    private JobStore mJobStore;
+
     @Before
     public void setUp() {
         mMockingSession = mockitoSession()
@@ -123,8 +139,17 @@
         when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService);
         when(mJobSchedulerService.getConstants()).thenReturn(mConstants);
         // Called in QuotaController constructor.
+        IActivityManager activityManager = ActivityManager.getService();
+        spyOn(activityManager);
+        try {
+            doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
+        } catch (RemoteException e) {
+            fail("registerUidObserver threw exception: " + e.getMessage());
+        }
         when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
         when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
+        doReturn(mActivityMangerInternal)
+                .when(() -> LocalServices.getService(ActivityManagerInternal.class));
         doReturn(mock(BatteryManagerInternal.class))
                 .when(() -> LocalServices.getService(BatteryManagerInternal.class));
         doReturn(mUsageStatsManager)
@@ -132,6 +157,9 @@
         // Used in JobStatus.
         doReturn(mock(PackageManagerInternal.class))
                 .when(() -> LocalServices.getService(PackageManagerInternal.class));
+        // Used in QuotaController.Handler.
+        mJobStore = JobStore.initAndGetForTesting(mContext, mContext.getFilesDir());
+        when(mJobSchedulerService.getJobStore()).thenReturn(mJobStore);
 
         // Freeze the clocks at 24 hours after this moment in time. Several tests create sessions
         // in the past, and QuotaController sometimes floors values at 0, so if the test time
@@ -150,10 +178,23 @@
         // Capture the listeners.
         ArgumentCaptor<BroadcastReceiver> receiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
+        ArgumentCaptor<IUidObserver> uidObserverCaptor =
+                ArgumentCaptor.forClass(IUidObserver.class);
         mQuotaController = new QuotaController(mJobSchedulerService);
 
         verify(mContext).registerReceiver(receiverCaptor.capture(), any());
         mChargingReceiver = receiverCaptor.getValue();
+        try {
+            verify(activityManager).registerUidObserver(
+                    uidObserverCaptor.capture(),
+                    eq(ActivityManager.UID_OBSERVER_PROCSTATE),
+                    eq(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE),
+                    any());
+            mUidObserver = uidObserverCaptor.getValue();
+            mSourceUid = AppGlobals.getPackageManager().getPackageUid(SOURCE_PACKAGE, 0, 0);
+        } catch (RemoteException e) {
+            fail(e.getMessage());
+        }
     }
 
     @After
@@ -182,6 +223,25 @@
         mChargingReceiver.onReceive(mContext, intent);
     }
 
+    private void setProcessState(int procState) {
+        try {
+            doReturn(procState).when(mActivityMangerInternal).getUidProcessState(mSourceUid);
+            SparseBooleanArray foregroundUids = mQuotaController.getForegroundUids();
+            spyOn(foregroundUids);
+            mUidObserver.onUidStateChanged(mSourceUid, procState, 0);
+            if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+                verify(foregroundUids, timeout(SECOND_IN_MILLIS).times(1))
+                        .put(eq(mSourceUid), eq(true));
+                assertTrue(foregroundUids.get(mSourceUid));
+            } else {
+                verify(foregroundUids, timeout(SECOND_IN_MILLIS).times(1)).delete(eq(mSourceUid));
+                assertFalse(foregroundUids.get(mSourceUid));
+            }
+        } catch (RemoteException e) {
+            fail("registerUidObserver threw exception: " + e.getMessage());
+        }
+    }
+
     private void setStandbyBucket(int bucketIndex) {
         int bucket;
         switch (bucketIndex) {
@@ -204,9 +264,18 @@
                 anyLong())).thenReturn(bucket);
     }
 
-    private void setStandbyBucket(int bucketIndex, JobStatus job) {
+    private void setStandbyBucket(int bucketIndex, JobStatus... jobs) {
         setStandbyBucket(bucketIndex);
-        job.setStandbyBucket(bucketIndex);
+        for (JobStatus job : jobs) {
+            job.setStandbyBucket(bucketIndex);
+        }
+    }
+
+    private void trackJobs(JobStatus... jobs) {
+        for (JobStatus job : jobs) {
+            mJobStore.add(job);
+            mQuotaController.maybeStartTrackingJobLocked(job, null);
+        }
     }
 
     private JobStatus createJobStatus(String testTag, int jobId) {
@@ -214,8 +283,11 @@
                 new ComponentName(mContext, "TestQuotaJobService"))
                 .setMinimumLatency(Math.abs(jobId) + 1)
                 .build();
-        return JobStatus.createFromJobInfo(
+        JobStatus js = JobStatus.createFromJobInfo(
                 jobInfo, CALLING_UID, SOURCE_PACKAGE, SOURCE_USER_ID, testTag);
+        // Make sure tests aren't passing just because the default bucket is likely ACTIVE.
+        js.setStandbyBucket(FREQUENT_INDEX);
+        return js;
     }
 
     private TimingSession createTimingSession(long start, long duration, int count) {
@@ -299,16 +371,19 @@
         mQuotaController.saveTimingSession(0, "com.android.test.stay", one);
 
         ExecutionStats expectedStats = new ExecutionStats();
-        expectedStats.invalidTimeElapsed = now + 24 * HOUR_IN_MILLIS;
+        expectedStats.expirationTimeElapsed = now + 24 * HOUR_IN_MILLIS;
         expectedStats.windowSizeMs = 24 * HOUR_IN_MILLIS;
 
-        mQuotaController.onAppRemovedLocked("com.android.test.remove", 10001);
+        final int uid = 10001;
+        mQuotaController.onAppRemovedLocked("com.android.test.remove", uid);
         assertNull(mQuotaController.getTimingSessions(0, "com.android.test.remove"));
         assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test.stay"));
         assertEquals(expectedStats,
                 mQuotaController.getExecutionStatsLocked(0, "com.android.test.remove", RARE_INDEX));
         assertNotEquals(expectedStats,
                 mQuotaController.getExecutionStatsLocked(0, "com.android.test.stay", RARE_INDEX));
+
+        assertFalse(mQuotaController.getForegroundUids().get(uid));
     }
 
     @Test
@@ -334,7 +409,7 @@
         mQuotaController.saveTimingSession(10, "com.android.test", one);
 
         ExecutionStats expectedStats = new ExecutionStats();
-        expectedStats.invalidTimeElapsed = now + 24 * HOUR_IN_MILLIS;
+        expectedStats.expirationTimeElapsed = now + 24 * HOUR_IN_MILLIS;
         expectedStats.windowSizeMs = 24 * HOUR_IN_MILLIS;
 
         mQuotaController.onUserRemovedLocked(0);
@@ -369,14 +444,14 @@
 
         inputStats.windowSizeMs = expectedStats.windowSizeMs = 12 * HOUR_IN_MILLIS;
         // Invalid time is now +24 hours since there are no sessions at all for the app.
-        expectedStats.invalidTimeElapsed = now + 24 * HOUR_IN_MILLIS;
+        expectedStats.expirationTimeElapsed = now + 24 * HOUR_IN_MILLIS;
         mQuotaController.updateExecutionStatsLocked(0, "com.android.test.not.run", inputStats);
         assertEquals(expectedStats, inputStats);
 
         inputStats.windowSizeMs = expectedStats.windowSizeMs = MINUTE_IN_MILLIS;
         // Invalid time is now +18 hours since there are no sessions in the window but the earliest
         // session is 6 hours ago.
-        expectedStats.invalidTimeElapsed = now + 18 * HOUR_IN_MILLIS;
+        expectedStats.expirationTimeElapsed = now + 18 * HOUR_IN_MILLIS;
         expectedStats.executionTimeInWindowMs = 0;
         expectedStats.bgJobCountInWindow = 0;
         expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
@@ -386,7 +461,7 @@
 
         inputStats.windowSizeMs = expectedStats.windowSizeMs = 3 * MINUTE_IN_MILLIS;
         // Invalid time is now since the session straddles the window cutoff time.
-        expectedStats.invalidTimeElapsed = now;
+        expectedStats.expirationTimeElapsed = now;
         expectedStats.executionTimeInWindowMs = 2 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 3;
         expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
@@ -397,7 +472,7 @@
         inputStats.windowSizeMs = expectedStats.windowSizeMs = 5 * MINUTE_IN_MILLIS;
         // Invalid time is now since the start of the session is at the very edge of the window
         // cutoff time.
-        expectedStats.invalidTimeElapsed = now;
+        expectedStats.expirationTimeElapsed = now;
         expectedStats.executionTimeInWindowMs = 4 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 3;
         expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
@@ -408,7 +483,7 @@
         inputStats.windowSizeMs = expectedStats.windowSizeMs = 49 * MINUTE_IN_MILLIS;
         // Invalid time is now +44 minutes since the earliest session in the window is now-5
         // minutes.
-        expectedStats.invalidTimeElapsed = now + 44 * MINUTE_IN_MILLIS;
+        expectedStats.expirationTimeElapsed = now + 44 * MINUTE_IN_MILLIS;
         expectedStats.executionTimeInWindowMs = 4 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 3;
         expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
@@ -418,7 +493,7 @@
 
         inputStats.windowSizeMs = expectedStats.windowSizeMs = 50 * MINUTE_IN_MILLIS;
         // Invalid time is now since the session is at the very edge of the window cutoff time.
-        expectedStats.invalidTimeElapsed = now;
+        expectedStats.expirationTimeElapsed = now;
         expectedStats.executionTimeInWindowMs = 5 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 4;
         expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
@@ -429,7 +504,7 @@
         inputStats.windowSizeMs = expectedStats.windowSizeMs = HOUR_IN_MILLIS;
         // Invalid time is now since the start of the session is at the very edge of the window
         // cutoff time.
-        expectedStats.invalidTimeElapsed = now;
+        expectedStats.expirationTimeElapsed = now;
         expectedStats.executionTimeInWindowMs = 6 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 5;
         expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
@@ -439,7 +514,7 @@
 
         inputStats.windowSizeMs = expectedStats.windowSizeMs = 2 * HOUR_IN_MILLIS;
         // Invalid time is now since the session straddles the window cutoff time.
-        expectedStats.invalidTimeElapsed = now;
+        expectedStats.expirationTimeElapsed = now;
         expectedStats.executionTimeInWindowMs = 11 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 10;
         expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
@@ -452,7 +527,7 @@
         inputStats.windowSizeMs = expectedStats.windowSizeMs = 3 * HOUR_IN_MILLIS;
         // Invalid time is now +59 minutes since the earliest session in the window is now-121
         // minutes.
-        expectedStats.invalidTimeElapsed = now + 59 * MINUTE_IN_MILLIS;
+        expectedStats.expirationTimeElapsed = now + 59 * MINUTE_IN_MILLIS;
         expectedStats.executionTimeInWindowMs = 12 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 10;
         expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
@@ -465,7 +540,7 @@
         inputStats.windowSizeMs = expectedStats.windowSizeMs = 6 * HOUR_IN_MILLIS;
         // Invalid time is now since the start of the session is at the very edge of the window
         // cutoff time.
-        expectedStats.invalidTimeElapsed = now;
+        expectedStats.expirationTimeElapsed = now;
         expectedStats.executionTimeInWindowMs = 22 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 15;
         expectedStats.executionTimeInMaxPeriodMs = 22 * MINUTE_IN_MILLIS;
@@ -475,14 +550,14 @@
         mQuotaController.updateExecutionStatsLocked(0, "com.android.test", inputStats);
         assertEquals(expectedStats, inputStats);
 
-        // Make sure invalidTimeElapsed is set correctly when it's dependent on the max period.
+        // Make sure expirationTimeElapsed is set correctly when it's dependent on the max period.
         mQuotaController.getTimingSessions(0, "com.android.test")
                 .add(0,
                         createTimingSession(now - (23 * HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 3));
         inputStats.windowSizeMs = expectedStats.windowSizeMs = 8 * HOUR_IN_MILLIS;
         // Invalid time is now +1 hour since the earliest session in the max period is 1 hour
         // before the end of the max period cutoff time.
-        expectedStats.invalidTimeElapsed = now + HOUR_IN_MILLIS;
+        expectedStats.expirationTimeElapsed = now + HOUR_IN_MILLIS;
         expectedStats.executionTimeInWindowMs = 22 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 15;
         expectedStats.executionTimeInMaxPeriodMs = 23 * MINUTE_IN_MILLIS;
@@ -498,7 +573,7 @@
                                 2 * MINUTE_IN_MILLIS, 2));
         inputStats.windowSizeMs = expectedStats.windowSizeMs = 8 * HOUR_IN_MILLIS;
         // Invalid time is now since the earlist session straddles the max period cutoff time.
-        expectedStats.invalidTimeElapsed = now;
+        expectedStats.expirationTimeElapsed = now;
         expectedStats.executionTimeInWindowMs = 22 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 15;
         expectedStats.executionTimeInMaxPeriodMs = 24 * MINUTE_IN_MILLIS;
@@ -528,7 +603,7 @@
 
         // Active
         expectedStats.windowSizeMs = 10 * MINUTE_IN_MILLIS;
-        expectedStats.invalidTimeElapsed = now + 4 * MINUTE_IN_MILLIS;
+        expectedStats.expirationTimeElapsed = now + 4 * MINUTE_IN_MILLIS;
         expectedStats.executionTimeInWindowMs = 3 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 5;
         expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS;
@@ -538,7 +613,7 @@
 
         // Working
         expectedStats.windowSizeMs = 2 * HOUR_IN_MILLIS;
-        expectedStats.invalidTimeElapsed = now;
+        expectedStats.expirationTimeElapsed = now;
         expectedStats.executionTimeInWindowMs = 13 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 10;
         expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS;
@@ -550,7 +625,7 @@
 
         // Frequent
         expectedStats.windowSizeMs = 8 * HOUR_IN_MILLIS;
-        expectedStats.invalidTimeElapsed = now + HOUR_IN_MILLIS;
+        expectedStats.expirationTimeElapsed = now + HOUR_IN_MILLIS;
         expectedStats.executionTimeInWindowMs = 23 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 15;
         expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS;
@@ -562,7 +637,7 @@
 
         // Rare
         expectedStats.windowSizeMs = 24 * HOUR_IN_MILLIS;
-        expectedStats.invalidTimeElapsed = now + HOUR_IN_MILLIS;
+        expectedStats.expirationTimeElapsed = now + HOUR_IN_MILLIS;
         expectedStats.executionTimeInWindowMs = 33 * MINUTE_IN_MILLIS;
         expectedStats.bgJobCountInWindow = 20;
         expectedStats.executionTimeInMaxPeriodMs = 33 * MINUTE_IN_MILLIS;
@@ -604,7 +679,7 @@
 
         ExecutionStats expectedStats = new ExecutionStats();
         expectedStats.windowSizeMs = originalStatsActive.windowSizeMs;
-        expectedStats.invalidTimeElapsed = originalStatsActive.invalidTimeElapsed;
+        expectedStats.expirationTimeElapsed = originalStatsActive.expirationTimeElapsed;
         expectedStats.executionTimeInWindowMs = originalStatsActive.executionTimeInWindowMs;
         expectedStats.bgJobCountInWindow = originalStatsActive.bgJobCountInWindow;
         expectedStats.executionTimeInMaxPeriodMs = originalStatsActive.executionTimeInMaxPeriodMs;
@@ -617,7 +692,7 @@
         assertEquals(expectedStats, newStatsActive);
 
         expectedStats.windowSizeMs = originalStatsWorking.windowSizeMs;
-        expectedStats.invalidTimeElapsed = originalStatsWorking.invalidTimeElapsed;
+        expectedStats.expirationTimeElapsed = originalStatsWorking.expirationTimeElapsed;
         expectedStats.executionTimeInWindowMs = originalStatsWorking.executionTimeInWindowMs;
         expectedStats.bgJobCountInWindow = originalStatsWorking.bgJobCountInWindow;
         expectedStats.quotaCutoffTimeElapsed = originalStatsWorking.quotaCutoffTimeElapsed;
@@ -627,7 +702,7 @@
         assertNotEquals(expectedStats, newStatsWorking);
 
         expectedStats.windowSizeMs = originalStatsFrequent.windowSizeMs;
-        expectedStats.invalidTimeElapsed = originalStatsFrequent.invalidTimeElapsed;
+        expectedStats.expirationTimeElapsed = originalStatsFrequent.expirationTimeElapsed;
         expectedStats.executionTimeInWindowMs = originalStatsFrequent.executionTimeInWindowMs;
         expectedStats.bgJobCountInWindow = originalStatsFrequent.bgJobCountInWindow;
         expectedStats.quotaCutoffTimeElapsed = originalStatsFrequent.quotaCutoffTimeElapsed;
@@ -637,7 +712,7 @@
         assertNotEquals(expectedStats, newStatsFrequent);
 
         expectedStats.windowSizeMs = originalStatsRare.windowSizeMs;
-        expectedStats.invalidTimeElapsed = originalStatsRare.invalidTimeElapsed;
+        expectedStats.expirationTimeElapsed = originalStatsRare.expirationTimeElapsed;
         expectedStats.executionTimeInWindowMs = originalStatsRare.executionTimeInWindowMs;
         expectedStats.bgJobCountInWindow = originalStatsRare.bgJobCountInWindow;
         expectedStats.quotaCutoffTimeElapsed = originalStatsRare.quotaCutoffTimeElapsed;
@@ -648,6 +723,77 @@
     }
 
     @Test
+    public void testIsWithinQuotaLocked_NeverApp() {
+        assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test.never", NEVER_INDEX));
+    }
+
+    @Test
+    public void testIsWithinQuotaLocked_Charging() {
+        setCharging();
+        assertTrue(mQuotaController.isWithinQuotaLocked(0, "com.android.test", RARE_INDEX));
+    }
+
+    @Test
+    public void testIsWithinQuotaLocked_UnderDuration_UnderJobCount() {
+        setDischarging();
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.saveTimingSession(0, "com.android.test",
+                createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+        mQuotaController.saveTimingSession(0, "com.android.test",
+                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+        mQuotaController.incrementJobCount(0, "com.android.test", 5);
+        assertTrue(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX));
+    }
+
+    @Test
+    public void testIsWithinQuotaLocked_UnderDuration_OverJobCount() {
+        setDischarging();
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        final int jobCount = mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME;
+        mQuotaController.saveTimingSession(0, "com.android.test.spam",
+                createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25));
+        mQuotaController.saveTimingSession(0, "com.android.test.spam",
+                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount));
+        mQuotaController.incrementJobCount(0, "com.android.test.spam", jobCount);
+        assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test.spam",
+                WORKING_INDEX));
+
+        mQuotaController.saveTimingSession(0, "com.android.test.frequent",
+                createTimingSession(now - (2 * HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 2000));
+        mQuotaController.saveTimingSession(0, "com.android.test.frequent",
+                createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 500));
+        assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test.frequent",
+                FREQUENT_INDEX));
+    }
+
+    @Test
+    public void testIsWithinQuotaLocked_OverDuration_UnderJobCount() {
+        setDischarging();
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.saveTimingSession(0, "com.android.test",
+                createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+        mQuotaController.saveTimingSession(0, "com.android.test",
+                createTimingSession(now - (30 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+        mQuotaController.saveTimingSession(0, "com.android.test",
+                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 4 * MINUTE_IN_MILLIS, 5));
+        mQuotaController.incrementJobCount(0, "com.android.test", 5);
+        assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX));
+    }
+
+    @Test
+    public void testIsWithinQuotaLocked_OverDuration_OverJobCount() {
+        setDischarging();
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        final int jobCount = mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME;
+        mQuotaController.saveTimingSession(0, "com.android.test",
+                createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25));
+        mQuotaController.saveTimingSession(0, "com.android.test",
+                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount));
+        mQuotaController.incrementJobCount(0, "com.android.test", jobCount);
+        assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX));
+    }
+
+    @Test
     public void testMaybeScheduleCleanupAlarmLocked() {
         // No sessions saved yet.
         mQuotaController.maybeScheduleCleanupAlarmLocked();
@@ -681,6 +827,7 @@
 
         // Active window size is 10 minutes.
         final int standbyBucket = ACTIVE_INDEX;
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
 
         // No sessions saved yet.
         mQuotaController.maybeScheduleStartAlarmLocked(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -709,6 +856,7 @@
         verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
 
         JobStatus jobStatus = createJobStatus("testMaybeScheduleStartAlarmLocked_Active", 1);
+        setStandbyBucket(standbyBucket, jobStatus);
         mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
         mQuotaController.prepareForExecutionLocked(jobStatus);
         advanceElapsedClock(5 * MINUTE_IN_MILLIS);
@@ -944,11 +1092,37 @@
                 .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
 
         mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", ACTIVE_INDEX);
-        inOrder.verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
-                any());
+        inOrder.verify(mAlarmManager, never())
+                .set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
         inOrder.verify(mAlarmManager, times(1)).cancel(any(AlarmManager.OnAlarmListener.class));
     }
 
+    @Test
+    public void testMaybeScheduleStartAlarmLocked_JobCount_AllowedTime() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        final int standbyBucket = WORKING_INDEX;
+        ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID,
+                SOURCE_PACKAGE, standbyBucket);
+        stats.jobCountInAllowedTime =
+                mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME + 2;
+
+        // Invalid time in the past, so the count shouldn't be used.
+        stats.jobCountExpirationTimeElapsed =
+                now - mQuotaController.getAllowedTimePerPeriodMs() / 2;
+        mQuotaController.maybeScheduleStartAlarmLocked(
+                SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
+        verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+        // Invalid time in the future, so the count should be used.
+        stats.jobCountExpirationTimeElapsed =
+                now + mQuotaController.getAllowedTimePerPeriodMs() / 2;
+        final long expectedWorkingAlarmTime =
+                stats.jobCountExpirationTimeElapsed + mQuotaController.getAllowedTimePerPeriodMs();
+        mQuotaController.maybeScheduleStartAlarmLocked(
+                SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
+        verify(mAlarmManager, times(1))
+                .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+    }
 
     /**
      * Tests that the start alarm is properly rescheduled if the earliest session that contributes
@@ -1100,6 +1274,11 @@
         mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = 45 * MINUTE_IN_MILLIS;
         mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = 60 * MINUTE_IN_MILLIS;
         mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = 3 * HOUR_IN_MILLIS;
+        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = 5000;
+        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = 4000;
+        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = 3000;
+        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = 2000;
+        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = 500;
 
         mQuotaController.onConstantsUpdatedLocked();
 
@@ -1111,11 +1290,16 @@
                 mQuotaController.getBucketWindowSizes()[FREQUENT_INDEX]);
         assertEquals(60 * MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[RARE_INDEX]);
         assertEquals(3 * HOUR_IN_MILLIS, mQuotaController.getMaxExecutionTimeMs());
+        assertEquals(500, mQuotaController.getMaxJobCountPerAllowedTime());
+        assertEquals(5000, mQuotaController.getBucketMaxJobCounts()[ACTIVE_INDEX]);
+        assertEquals(4000, mQuotaController.getBucketMaxJobCounts()[WORKING_INDEX]);
+        assertEquals(3000, mQuotaController.getBucketMaxJobCounts()[FREQUENT_INDEX]);
+        assertEquals(2000, mQuotaController.getBucketMaxJobCounts()[RARE_INDEX]);
     }
 
     @Test
     public void testConstantsUpdating_InvalidValues() {
-        // Test negatives
+        // Test negatives/too low.
         mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = -MINUTE_IN_MILLIS;
         mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = -MINUTE_IN_MILLIS;
         mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = -MINUTE_IN_MILLIS;
@@ -1123,6 +1307,11 @@
         mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = -MINUTE_IN_MILLIS;
         mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = -MINUTE_IN_MILLIS;
         mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS = -MINUTE_IN_MILLIS;
+        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_ACTIVE = -1;
+        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_WORKING = 1;
+        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_FREQUENT = 1;
+        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_RARE = 1;
+        mConstants.QUOTA_CONTROLLER_MAX_JOB_COUNT_PER_ALLOWED_TIME = 0;
 
         mQuotaController.onConstantsUpdatedLocked();
 
@@ -1133,6 +1322,11 @@
         assertEquals(MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[FREQUENT_INDEX]);
         assertEquals(MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[RARE_INDEX]);
         assertEquals(HOUR_IN_MILLIS, mQuotaController.getMaxExecutionTimeMs());
+        assertEquals(10, mQuotaController.getMaxJobCountPerAllowedTime());
+        assertEquals(100, mQuotaController.getBucketMaxJobCounts()[ACTIVE_INDEX]);
+        assertEquals(100, mQuotaController.getBucketMaxJobCounts()[WORKING_INDEX]);
+        assertEquals(100, mQuotaController.getBucketMaxJobCounts()[FREQUENT_INDEX]);
+        assertEquals(100, mQuotaController.getBucketMaxJobCounts()[RARE_INDEX]);
 
         // Test larger than a day. Controller should cap at one day.
         mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = 25 * HOUR_IN_MILLIS;
@@ -1174,6 +1368,7 @@
     @Test
     public void testTimerTracking_Discharging() {
         setDischarging();
+        setProcessState(ActivityManager.PROCESS_STATE_BACKUP);
 
         JobStatus jobStatus = createJobStatus("testTimerTracking_Discharging", 1);
         mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
@@ -1221,6 +1416,8 @@
      */
     @Test
     public void testTimerTracking_ChargingAndDischarging() {
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+
         JobStatus jobStatus = createJobStatus("testTimerTracking_ChargingAndDischarging", 1);
         mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
         JobStatus jobStatus2 = createJobStatus("testTimerTracking_ChargingAndDischarging", 2);
@@ -1291,6 +1488,7 @@
     @Test
     public void testTimerTracking_AllBackground() {
         setDischarging();
+        setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
 
         JobStatus jobStatus = createJobStatus("testTimerTracking_AllBackground", 1);
         mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
@@ -1339,19 +1537,23 @@
         setDischarging();
 
         JobStatus jobStatus = createJobStatus("testTimerTracking_AllForeground", 1);
-        jobStatus.uidActive = true;
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
         mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
 
         assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
 
         mQuotaController.prepareForExecutionLocked(jobStatus);
         advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        // Change to a state that should still be considered foreground.
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
         mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
         assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
     }
 
     /**
-     * Tests that Timers properly track overlapping foreground and background jobs.
+     * Tests that Timers properly track sessions when switching between foreground and background
+     * states.
      */
     @Test
     public void testTimerTracking_ForegroundAndBackground() {
@@ -1360,7 +1562,6 @@
         JobStatus jobBg1 = createJobStatus("testTimerTracking_ForegroundAndBackground", 1);
         JobStatus jobBg2 = createJobStatus("testTimerTracking_ForegroundAndBackground", 2);
         JobStatus jobFg3 = createJobStatus("testTimerTracking_ForegroundAndBackground", 3);
-        jobFg3.uidActive = true;
         mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
         mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
         mQuotaController.maybeStartTrackingJobLocked(jobFg3, null);
@@ -1368,6 +1569,7 @@
         List<TimingSession> expected = new ArrayList<>();
 
         // UID starts out inactive.
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
         long start = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.prepareForExecutionLocked(jobBg1);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
@@ -1379,48 +1581,281 @@
 
         // Bg job starts while inactive, spans an entire active session, and ends after the
         // active session.
-        // Fg job starts after the bg job and ends before the bg job.
-        // Entire bg job duration should be counted since it started before active session. However,
-        // count should only be 1 since Timer shouldn't count fg jobs.
+        // App switching to foreground state then fg job starts.
+        // App remains in foreground state after coming to foreground, so there should only be one
+        // session.
         start = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
         mQuotaController.prepareForExecutionLocked(jobBg2);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
         mQuotaController.prepareForExecutionLocked(jobFg3);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
-        expected.add(createTimingSession(start, 30 * SECOND_IN_MILLIS, 1));
         assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
 
         advanceElapsedClock(SECOND_IN_MILLIS);
 
         // Bg job 1 starts, then fg job starts. Bg job 1 job ends. Shortly after, uid goes
         // "inactive" and then bg job 2 starts. Then fg job ends.
-        // This should result in two TimingSessions with a count of one each.
+        // This should result in two TimingSessions:
+        //  * The first should have a count of 1
+        //  * The second should have a count of 2 since it will include both jobs
         start = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
         mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
         mQuotaController.maybeStartTrackingJobLocked(jobFg3, null);
+        setProcessState(ActivityManager.PROCESS_STATE_LAST_ACTIVITY);
         mQuotaController.prepareForExecutionLocked(jobBg1);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
         mQuotaController.prepareForExecutionLocked(jobFg3);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
-        expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 1));
         advanceElapsedClock(10 * SECOND_IN_MILLIS); // UID "inactive" now
         start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
         mQuotaController.prepareForExecutionLocked(jobBg2);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false);
         advanceElapsedClock(10 * SECOND_IN_MILLIS);
         mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
-        expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 1));
+        expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
         assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
     }
 
     /**
+     * Tests that Timers don't track job counts while in the foreground.
+     */
+    @Test
+    public void testTimerTracking_JobCount_Foreground() {
+        setDischarging();
+
+        final int standbyBucket = ACTIVE_INDEX;
+        JobStatus jobFg1 = createJobStatus("testTimerTracking_JobCount_Foreground", 1);
+        JobStatus jobFg2 = createJobStatus("testTimerTracking_JobCount_Foreground", 2);
+
+        mQuotaController.maybeStartTrackingJobLocked(jobFg1, null);
+        mQuotaController.maybeStartTrackingJobLocked(jobFg2, null);
+        assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID,
+                SOURCE_PACKAGE, standbyBucket);
+        assertEquals(0, stats.jobCountInAllowedTime);
+
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        mQuotaController.prepareForExecutionLocked(jobFg1);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.prepareForExecutionLocked(jobFg2);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobFg1, null, false);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobFg2, null, false);
+        assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        assertEquals(0, stats.jobCountInAllowedTime);
+    }
+
+    /**
+     * Tests that Timers properly track job counts while in the background.
+     */
+    @Test
+    public void testTimerTracking_JobCount_Background() {
+        final int standbyBucket = WORKING_INDEX;
+        JobStatus jobBg1 = createJobStatus("testTimerTracking_JobCount_Background", 1);
+        JobStatus jobBg2 = createJobStatus("testTimerTracking_JobCount_Background", 2);
+        mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
+        mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+
+        ExecutionStats stats = mQuotaController.getExecutionStatsLocked(SOURCE_USER_ID,
+                SOURCE_PACKAGE, standbyBucket);
+        assertEquals(0, stats.jobCountInAllowedTime);
+
+        setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+        mQuotaController.prepareForExecutionLocked(jobBg1);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.prepareForExecutionLocked(jobBg2);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobBg1, null, false);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+
+        assertEquals(2, stats.jobCountInAllowedTime);
+    }
+
+    /**
+     * Tests that Timers properly track overlapping top and background jobs.
+     */
+    @Test
+    public void testTimerTracking_TopAndNonTop() {
+        setDischarging();
+
+        JobStatus jobBg1 = createJobStatus("testTimerTracking_TopAndNonTop", 1);
+        JobStatus jobBg2 = createJobStatus("testTimerTracking_TopAndNonTop", 2);
+        JobStatus jobFg1 = createJobStatus("testTimerTracking_TopAndNonTop", 3);
+        JobStatus jobTop = createJobStatus("testTimerTracking_TopAndNonTop", 4);
+        mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
+        mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+        mQuotaController.maybeStartTrackingJobLocked(jobFg1, null);
+        mQuotaController.maybeStartTrackingJobLocked(jobTop, null);
+        assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        List<TimingSession> expected = new ArrayList<>();
+
+        // UID starts out inactive.
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.prepareForExecutionLocked(jobBg1);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        // Bg job starts while inactive, spans an entire active session, and ends after the
+        // active session.
+        // App switching to top state then fg job starts.
+        // App remains in top state after coming to top, so there should only be one
+        // session.
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+        mQuotaController.prepareForExecutionLocked(jobBg2);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        mQuotaController.prepareForExecutionLocked(jobTop);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+        assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        // Bg job 1 starts, then top job starts. Bg job 1 job ends. Then app goes to
+        // foreground_service and a new job starts. Shortly after, uid goes
+        // "inactive" and then bg job 2 starts. Then top job ends, followed by bg and fg jobs.
+        // This should result in two TimingSessions:
+        //  * The first should have a count of 1
+        //  * The second should have a count of 2, which accounts for the bg2 and fg, but not top
+        //    jobs.
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
+        mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+        mQuotaController.maybeStartTrackingJobLocked(jobTop, null);
+        setProcessState(ActivityManager.PROCESS_STATE_LAST_ACTIVITY);
+        mQuotaController.prepareForExecutionLocked(jobBg1);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        mQuotaController.prepareForExecutionLocked(jobTop);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        mQuotaController.prepareForExecutionLocked(jobFg1);
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS); // UID "inactive" now
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+        mQuotaController.prepareForExecutionLocked(jobBg2);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+        mQuotaController.maybeStopTrackingJobLocked(jobFg1, null, false);
+        expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
+        assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
+     * Tests that TOP jobs aren't stopped when an app runs out of quota.
+     */
+    @Test
+    public void testTracking_OutOfQuota_ForegroundAndBackground() {
+        setDischarging();
+
+        JobStatus jobBg = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 1);
+        JobStatus jobTop = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 2);
+        trackJobs(jobBg, jobTop);
+        setStandbyBucket(WORKING_INDEX, jobTop, jobBg); // 2 hour window
+        // Now the package only has 20 seconds to run.
+        final long remainingTimeMs = 20 * SECOND_IN_MILLIS;
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS,
+                        10 * MINUTE_IN_MILLIS - remainingTimeMs, 1));
+
+        InOrder inOrder = inOrder(mJobSchedulerService);
+
+        // UID starts out inactive.
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+        // Start the job.
+        mQuotaController.prepareForExecutionLocked(jobBg);
+        advanceElapsedClock(remainingTimeMs / 2);
+        // New job starts after UID is in the foreground. Since the app is now in the foreground, it
+        // should continue to have remainingTimeMs / 2 time remaining.
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        mQuotaController.prepareForExecutionLocked(jobTop);
+        advanceElapsedClock(remainingTimeMs);
+
+        // Wait for some extra time to allow for job processing.
+        inOrder.verify(mJobSchedulerService,
+                timeout(remainingTimeMs + 2 * SECOND_IN_MILLIS).times(0))
+                .onControllerStateChanged();
+        assertEquals(remainingTimeMs / 2, mQuotaController.getRemainingExecutionTimeLocked(jobBg));
+        assertEquals(remainingTimeMs / 2, mQuotaController.getRemainingExecutionTimeLocked(jobTop));
+        // Go to a background state.
+        setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+        advanceElapsedClock(remainingTimeMs / 2 + 1);
+        inOrder.verify(mJobSchedulerService,
+                timeout(remainingTimeMs / 2 + 2 * SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged();
+        // Top job should still be allowed to run.
+        assertFalse(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+        // New jobs to run.
+        JobStatus jobBg2 = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 3);
+        JobStatus jobTop2 = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 4);
+        JobStatus jobFg = createJobStatus("testTracking_OutOfQuota_ForegroundAndBackground", 5);
+        setStandbyBucket(WORKING_INDEX, jobBg2, jobTop2, jobFg);
+
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged();
+        trackJobs(jobFg, jobTop);
+        mQuotaController.prepareForExecutionLocked(jobTop);
+        assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+        // App still in foreground so everything should be in quota.
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+        inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged();
+        // App is now in background and out of quota. Fg should now change to out of quota since it
+        // wasn't started. Top should remain in quota since it started when the app was in TOP.
+        assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertFalse(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        assertFalse(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        trackJobs(jobBg2);
+        assertFalse(jobBg2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+    }
+
+    /**
      * Tests that a job is properly updated and JobSchedulerService is notified when a job reaches
      * its quota.
      */
@@ -1429,6 +1864,7 @@
         JobStatus jobStatus = createJobStatus("testTracking_OutOfQuota", 1);
         mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
         setStandbyBucket(WORKING_INDEX, jobStatus); // 2 hour window
+        setProcessState(ActivityManager.PROCESS_STATE_HOME);
         // Now the package only has two seconds to run.
         final long remainingTimeMs = 2 * SECOND_IN_MILLIS;
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -1456,6 +1892,7 @@
         JobStatus jobStatus = createJobStatus("testTracking_OutOfQuota", 1);
         mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
         setStandbyBucket(WORKING_INDEX, jobStatus); // 2 hour window
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
         Handler handler = mQuotaController.getHandler();
         spyOn(handler);
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
new file mode 100644
index 0000000..5009d64
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -0,0 +1,954 @@
+/*
+ * 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.power.batterysaver;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.provider.Settings.Global;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+import java.util.Objects;
+
+/**
+ * atest com.android.server.power.batterysaver.BatterySaverStateMachineTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BatterySaverStateMachineTest {
+
+    private Context mMockContext;
+    private ContentResolver mMockContextResolver;
+    private BatterySaverController mMockBatterySaverController;
+    private NotificationManager mMockNotificationManager;
+    private Device mDevice;
+    private TestableBatterySaverStateMachine mTarget;
+    private Resources mMockResources;
+
+    private DevicePersistedState mPersistedState;
+
+    private class DevicePersistedState {
+        // Current battery level.
+        public int batteryLevel = 100;
+
+        // Whether battery level is currently low or not.
+        public boolean batteryLow = false;
+
+        // Whether the device is plugged in or not.
+        public boolean powered = false;
+
+        // Global settings.
+        public final HashMap<String, Integer> global = new HashMap<>();
+    }
+
+    /**
+     * This class simulates a device's volatile status that will be reset by {@link #initDevice()}.
+     */
+    private class Device {
+        public boolean batterySaverEnabled = false;
+
+        public int getLowPowerModeTriggerLevel() {
+            return mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+        }
+
+        public void setBatteryLevel(int level) {
+            mPersistedState.batteryLevel = level;
+            if (mPersistedState.batteryLevel <= Math.max(15, getLowPowerModeTriggerLevel())) {
+                mPersistedState.batteryLow = true;
+            } else if (mPersistedState.batteryLow
+                    && (mPersistedState.batteryLevel >= (getLowPowerModeTriggerLevel() + 5))) {
+                mPersistedState.batteryLow = false;
+            }
+            pushBatteryStatus();
+        }
+
+        public void setPowered(boolean newPowered) {
+            mPersistedState.powered = newPowered;
+            pushBatteryStatus();
+        }
+
+        public void pushBatteryStatus() {
+            mTarget.setBatteryStatus(mPersistedState.powered, mPersistedState.batteryLevel,
+                    mPersistedState.batteryLow);
+        }
+
+        public void pushGlobalSettings() {
+            mTarget.setSettingsLocked(
+                    mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE, 0) != 0,
+                    mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE_STICKY, 0) != 0,
+                    mDevice.getLowPowerModeTriggerLevel(),
+                    mPersistedState.global.getOrDefault(
+                            Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 0) != 0,
+                    mPersistedState.global.getOrDefault(
+                            Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90),
+                    mPersistedState.global.getOrDefault(Global.AUTOMATIC_POWER_SAVER_MODE, 0),
+                    mPersistedState.global.getOrDefault(
+                            Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0) != 0,
+                    mPersistedState.global.getOrDefault(
+                            Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 100));
+        }
+
+        public void putGlobalSetting(String key, int value) {
+            mPersistedState.global.put(key, value);
+            pushGlobalSettings();
+        }
+
+        public int getGlobalSetting(String key, int defValue) {
+            return mPersistedState.global.getOrDefault(key, defValue);
+        }
+    }
+
+    /**
+     * Test target class.
+     */
+    private class TestableBatterySaverStateMachine extends BatterySaverStateMachine {
+        TestableBatterySaverStateMachine() {
+            super(new Object(), mMockContext, mMockBatterySaverController);
+        }
+
+        @Override
+        protected void putGlobalSetting(String key, int value) {
+            if (Objects.equals(mPersistedState.global.get(key), value)) {
+                return;
+            }
+            mDevice.putGlobalSetting(key, value);
+        }
+
+        @Override
+        protected int getGlobalSetting(String key, int defValue) {
+            return mDevice.getGlobalSetting(key, defValue);
+        }
+
+        @Override
+        void runOnBgThread(Runnable r) {
+            r.run();
+        }
+
+        @Override
+        void runOnBgThreadLazy(Runnable r, int delayMillis) {
+            r.run();
+        }
+
+        @Override
+        void triggerDynamicModeNotification() {
+            // Do nothing
+        }
+    }
+
+    @Before
+    public void setUp() {
+        mMockContext = mock(Context.class);
+        mMockContextResolver = mock(ContentResolver.class);
+        mMockBatterySaverController = mock(BatterySaverController.class);
+        mMockNotificationManager = mock(NotificationManager.class);
+        mMockResources = mock(Resources.class);
+
+        doReturn(mMockContextResolver).when(mMockContext).getContentResolver();
+        doReturn(mMockResources).when(mMockContext).getResources();
+        doReturn(mMockNotificationManager).when(mMockContext)
+                .getSystemService(NotificationManager.class);
+        doAnswer((inv) -> mDevice.batterySaverEnabled = inv.getArgument(0))
+                .when(mMockBatterySaverController).enableBatterySaver(anyBoolean(), anyInt());
+        when(mMockBatterySaverController.isEnabled())
+                .thenAnswer((inv) -> mDevice.batterySaverEnabled);
+        when(mMockResources.getBoolean(
+                com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
+                .thenReturn(false);
+        when(mMockResources.getInteger(
+                com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold))
+                .thenReturn(80);
+
+        mPersistedState = new DevicePersistedState();
+        initDevice();
+    }
+
+    private void initDevice() {
+        mDevice = new Device();
+
+        mTarget = new TestableBatterySaverStateMachine();
+
+        mDevice.pushBatteryStatus();
+        mTarget.onBootCompleted();
+    }
+
+    @Test
+    public void testNoAutoBatterySaver() {
+        assertEquals(0, mDevice.getLowPowerModeTriggerLevel());
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(16);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(16, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // When LOW_POWER_MODE_TRIGGER_LEVEL is 0, 15% will still trigger low-battery, but
+        // BS wont be enabled.
+        mDevice.setBatteryLevel(15);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(15, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(10);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(10, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        // Manually enable BS.
+        mTarget.setBatterySaverEnabledManually(true);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(10, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Start charging. It'll disable BS.
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(60);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Unplug.
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(10);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(10, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(80);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Reboot the device.
+        initDevice();
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Sticky.
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(30);
+        initDevice();
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Still sticky.
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mTarget.setBatterySaverEnabledManually(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        initDevice(); // reboot.
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+    }
+
+    @Test
+    public void testAutoBatterySaver() {
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 0);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(51);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(51, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Hit the threshold. BS should be enabled.
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        // Battery goes up, but until it hits 55%, we still keep BS on.
+        mDevice.setBatteryLevel(54);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(54, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        // 50% + 5%, now BS will be off.
+        mDevice.setBatteryLevel(55);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(55, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(40);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(40, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(40, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(40, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(40, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        // Plug in and out, snooze will reset.
+        mDevice.setPowered(true);
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(60);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(70);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(70, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Bump ump the threshold.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 70);
+        mDevice.setBatteryLevel(mPersistedState.batteryLevel);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(70, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        // Then down.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 60);
+        mDevice.setBatteryLevel(mPersistedState.batteryLevel);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(70, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Reboot in low state -> automatically enable BS.
+        mDevice.setPowered(false);
+        mDevice.setBatteryLevel(30);
+        mTarget.setBatterySaverEnabledManually(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        initDevice();
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+    }
+
+    @Test
+    public void testAutoBatterySaver_withSticky_withAutoOffDisabled() {
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 0);
+
+        mTarget.setBatterySaverEnabledManually(true);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(80);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Still enabled.
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Restores BS.
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        initDevice();
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mTarget.setBatterySaverEnabledManually(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        initDevice();
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+    }
+
+    @Test
+    public void testAutoBatterySaver_withSticky_withAutoOffEnabled() {
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90);
+
+        // Scenario 1: User turns BS on manually above the threshold, it shouldn't turn off even
+        // with battery level change above threshold.
+        mDevice.setBatteryLevel(100);
+        mTarget.setBatterySaverEnabledManually(true);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(95);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
+        assertEquals(95, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Scenario 2: User turns BS on manually above the threshold then charges device. BS
+        // shouldn't turn back on.
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(95, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(97);
+        mDevice.setPowered(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled); // Sticky BS no longer enabled.
+        assertEquals(97, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Scenario 3: User turns BS on manually above the threshold. Device drains below
+        // threshold and then charged to below threshold. Sticky BS should activate.
+        mTarget.setBatterySaverEnabledManually(true);
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(80);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Still enabled.
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        // Scenario 4: User turns BS on manually above the threshold. Device drains below
+        // threshold and is eventually charged to above threshold. Sticky BS should turn off.
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled); // Sticky BS no longer enabled.
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Scenario 5: User turns BS on manually below threshold and charges to below threshold.
+        // Sticky BS should activate.
+        mDevice.setBatteryLevel(70);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(70, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mTarget.setBatterySaverEnabledManually(true);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(70, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(80);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Sticky BS still on.
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Scenario 6: User turns BS on manually below threshold and eventually charges to above
+        // threshold. Sticky BS should turn off.
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(95);
+        mDevice.setPowered(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(95, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Scenario 7: User turns BS on above threshold and then reboots device. Sticky BS
+        // shouldn't activate.
+        mTarget.setBatterySaverEnabledManually(true);
+        mPersistedState.batteryLevel = 93;
+
+        initDevice();
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(93, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Scenario 8: User turns BS on below threshold and then reboots device without charging.
+        // Sticky BS should activate.
+        mDevice.setBatteryLevel(75);
+        mTarget.setBatterySaverEnabledManually(true);
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(75, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        initDevice();
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(75, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Scenario 9: User turns BS on below threshold and then reboots device after charging
+        // above threshold. Sticky BS shouldn't activate.
+        mDevice.setBatteryLevel(80);
+        mTarget.setBatterySaverEnabledManually(true);
+        mPersistedState.batteryLevel = 100;
+
+        initDevice();
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Scenario 10: Somehow autoDisableLevel is set to a value below lowPowerModeTriggerLevel
+        // and then user enables manually above both thresholds, discharges below
+        // autoDisableLevel and then charges up to between autoDisableLevel and
+        // lowPowerModeTriggerLevel. Sticky BS shouldn't activate, but BS should still be on
+        // because the level is below lowPowerModeTriggerLevel.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 75);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 60);
+        initDevice();
+
+        mDevice.setBatteryLevel(90);
+        mTarget.setBatterySaverEnabledManually(true);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(65);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(65, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(65, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+    }
+
+    @Test
+    public void testAutoBatterySaver_withStickyDisabled() {
+        when(mMockResources.getBoolean(
+                com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
+                .thenReturn(true);
+        initDevice();
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 0);
+
+        mTarget.setBatterySaverEnabledManually(true);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(80);
+
+        assertEquals(false, mDevice.batterySaverEnabled); // Not sticky.
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(80, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Restores BS.
+        assertEquals(30, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        initDevice();
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setPowered(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mTarget.setBatterySaverEnabledManually(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        initDevice();
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+    }
+
+    @Test
+    public void testNoAutoBatterySaver_fromAdb() {
+        assertEquals(0, mDevice.getLowPowerModeTriggerLevel());
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Enable
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 1);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Disable
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 0);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Enable again
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 1);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Reboot -- setting BS from adb is also sticky.
+        initDevice();
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+    }
+
+    @Test
+    public void testAutoBatterySaver_smartBatterySaverEnabled() {
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 1);
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(51);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(51, mPersistedState.batteryLevel);
+
+        // Hit the threshold. BS should be disabled since dynamic power savings still off
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+
+        // dynamic power savings comes on, battery saver should turn on
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1);
+        mDevice.setBatteryLevel(40);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(40, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(40, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(40, mPersistedState.batteryLevel);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(40, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        // Plug in and out, snooze will reset.
+        mDevice.setPowered(true);
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(60);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(40);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(40, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(70);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(70, mPersistedState.batteryLevel);
+
+        // Bump up the threshold.
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 71);
+        mDevice.setBatteryLevel(mPersistedState.batteryLevel);
+
+        // changes are only registered if some battery level changed
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(70, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(69);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(69, mPersistedState.batteryLevel);
+
+        // Then down.
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 60);
+        mDevice.setBatteryLevel(mPersistedState.batteryLevel);
+
+        // changes are only registered if battery level changed
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(69, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(68);
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(68, mPersistedState.batteryLevel);
+
+        // Reboot in low state -> automatically enable BS.
+        mDevice.setPowered(false);
+        mDevice.setBatteryLevel(30);
+        mTarget.setBatterySaverEnabledManually(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        initDevice();
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+    }
+}
diff --git a/services/tests/rescueparty/Android.bp b/services/tests/rescueparty/Android.bp
new file mode 100644
index 0000000..6733af4
--- /dev/null
+++ b/services/tests/rescueparty/Android.bp
@@ -0,0 +1,23 @@
+// Copyright (C) 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.
+
+cc_test {
+    name: "log_rescueparty_reset_event_reported",
+    srcs: ["log_rescueparty_reset_event_reported.cpp"],
+    shared_libs: [
+        "libbase",
+        "libstatslog",
+    ],
+    gtest: false,
+}
diff --git a/services/tests/rescueparty/how_to_run.txt b/services/tests/rescueparty/how_to_run.txt
new file mode 100644
index 0000000..9528d39
--- /dev/null
+++ b/services/tests/rescueparty/how_to_run.txt
@@ -0,0 +1,9 @@
+# Per http://go/westworld-local-development#step3-test-atom-and-metric-locally-on-device ,
+# In one terminal:
+make statsd_testdrive
+./out/host/linux-x86/bin/statsd_testdrive 122
+
+# In another terminal:
+mma -j $(nproc) log_rescueparty_reset_event_reported
+adb push $OUT/testcases/log_rescueparty_reset_event_reported/arm64/log_rescueparty_reset_event_reported /data
+adb shell /data/log_rescueparty_reset_event_reported 1234
diff --git a/services/tests/rescueparty/log_rescueparty_reset_event_reported.cpp b/services/tests/rescueparty/log_rescueparty_reset_event_reported.cpp
new file mode 100644
index 0000000..4aea917
--- /dev/null
+++ b/services/tests/rescueparty/log_rescueparty_reset_event_reported.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 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.
+
+#include <statslog.h>
+#include <cstdlib>
+
+int main(int argc, const char** argv) {
+    int level = 0;
+    if (argc > 1) {
+        level = std::atoi(argv[1]);
+    }
+    android::util::stats_write(android::util::RESCUE_PARTY_RESET_REPORTED, level);
+}
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 1b5ba26..dc31c0f 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -156,6 +156,7 @@
         </activity>
 
         <activity android:name="com.android.server.accounts.AccountAuthenticatorDummyActivity" />
+        <activity android:name="com.android.server.adb.AdbDebuggingManagerTestActivity" />
 
         <activity-alias android:name="a.ShortcutEnabled"
             android:targetActivity="com.android.server.pm.ShortcutTestActivity"
diff --git a/services/tests/servicestests/src/com/android/server/AppOpsUpgradeTest.java b/services/tests/servicestests/src/com/android/server/AppOpsUpgradeTest.java
deleted file mode 100644
index aac96a1..0000000
--- a/services/tests/servicestests/src/com/android/server/AppOpsUpgradeTest.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.content.res.AssetManager;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.Xml;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-
-/**
- * Tests app ops version upgrades
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AppOpsUpgradeTest {
-    private static final String TAG = AppOpsUpgradeTest.class.getSimpleName();
-    private static final String APP_OPS_UNVERSIONED_ASSET_PATH =
-            "AppOpsUpgradeTest/appops-unversioned.xml";
-    private static final String APP_OPS_FILENAME = "appops-test.xml";
-    private static final int NON_DEFAULT_OPS_IN_FILE = 4;
-    private static final int CURRENT_VERSION = 1;
-
-    private File mAppOpsFile;
-    private Context mContext;
-    private Handler mHandler;
-
-    private void extractAppOpsFile() {
-        mAppOpsFile.getParentFile().mkdirs();
-        if (mAppOpsFile.exists()) {
-            mAppOpsFile.delete();
-        }
-        try (FileOutputStream out = new FileOutputStream(mAppOpsFile);
-             InputStream in = mContext.getAssets().open(APP_OPS_UNVERSIONED_ASSET_PATH,
-                     AssetManager.ACCESS_BUFFER)) {
-            byte[] buffer = new byte[4096];
-            int bytesRead;
-            while ((bytesRead = in.read(buffer)) >= 0) {
-                out.write(buffer, 0, bytesRead);
-            }
-            out.flush();
-            Log.d(TAG, "Successfully copied xml to " + mAppOpsFile.getAbsolutePath());
-        } catch (IOException exc) {
-            Log.e(TAG, "Exception while copying appops xml", exc);
-            fail();
-        }
-    }
-
-    private void assertSameModes(SparseArray<AppOpsService.UidState> uidStates, int op1, int op2) {
-        int numberOfNonDefaultOps = 0;
-        final int defaultModeOp1 = AppOpsManager.opToDefaultMode(op1);
-        final int defaultModeOp2 = AppOpsManager.opToDefaultMode(op2);
-        for(int i = 0; i < uidStates.size(); i++) {
-            final AppOpsService.UidState uidState = uidStates.valueAt(i);
-            if (uidState.opModes != null) {
-                final int uidMode1 = uidState.opModes.get(op1, defaultModeOp1);
-                final int uidMode2 = uidState.opModes.get(op2, defaultModeOp2);
-                assertEquals(uidMode1, uidMode2);
-                if (uidMode1 != defaultModeOp1) {
-                    numberOfNonDefaultOps++;
-                }
-            }
-            if (uidState.pkgOps == null) {
-                continue;
-            }
-            for (int j = 0; j < uidState.pkgOps.size(); j++) {
-                final AppOpsService.Ops ops = uidState.pkgOps.valueAt(j);
-                if (ops == null) {
-                    continue;
-                }
-                final AppOpsService.Op _op1 = ops.get(op1);
-                final AppOpsService.Op _op2 = ops.get(op2);
-                final int mode1 = (_op1 == null) ? defaultModeOp1 : _op1.mode;
-                final int mode2 = (_op2 == null) ? defaultModeOp2 : _op2.mode;
-                assertEquals(mode1, mode2);
-                if (mode1 != defaultModeOp1) {
-                    numberOfNonDefaultOps++;
-                }
-            }
-        }
-        assertEquals(numberOfNonDefaultOps, NON_DEFAULT_OPS_IN_FILE);
-    }
-
-    @Before
-    public void setUp() {
-        mContext = InstrumentationRegistry.getTargetContext();
-        mAppOpsFile = new File(mContext.getFilesDir(), APP_OPS_FILENAME);
-        extractAppOpsFile();
-        HandlerThread handlerThread = new HandlerThread(TAG);
-        handlerThread.start();
-        mHandler = new Handler(handlerThread.getLooper());
-    }
-
-    @Test
-    public void testUpgradeFromNoVersion() throws Exception {
-        AppOpsDataParser parser = new AppOpsDataParser(mAppOpsFile);
-        assertTrue(parser.parse());
-        assertEquals(AppOpsDataParser.NO_VERSION, parser.mVersion);
-        AppOpsService testService = new AppOpsService(mAppOpsFile, mHandler); // trigger upgrade
-        assertSameModes(testService.mUidStates, AppOpsManager.OP_RUN_IN_BACKGROUND,
-                AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
-        testService.mContext = mContext;
-        mHandler.removeCallbacks(testService.mWriteRunner);
-        testService.writeState();
-        assertTrue(parser.parse());
-        assertEquals(CURRENT_VERSION, parser.mVersion);
-    }
-
-    /**
-     * Class to parse data from the appops xml. Currently only parses and holds the version number.
-     * Other fields may be added as and when required for testing.
-     */
-    private static final class AppOpsDataParser {
-        static final int NO_VERSION = -1;
-        int mVersion;
-        private File mFile;
-
-        AppOpsDataParser(File file) {
-            mFile = file;
-            mVersion = NO_VERSION;
-        }
-
-        boolean parse() {
-            try (FileInputStream stream = new FileInputStream(mFile)) {
-                XmlPullParser parser = Xml.newPullParser();
-                parser.setInput(stream, StandardCharsets.UTF_8.name());
-                int type;
-                while ((type = parser.next()) != XmlPullParser.START_TAG
-                        && type != XmlPullParser.END_DOCUMENT) {
-                    ;
-                }
-                if (type != XmlPullParser.START_TAG) {
-                    throw new IllegalStateException("no start tag found");
-                }
-                final String versionString = parser.getAttributeValue(null, "v");
-                if (versionString != null) {
-                    mVersion = Integer.parseInt(versionString);
-                }
-            } catch (Exception e) {
-                Log.e(TAG, "Failed while parsing test appops xml", e);
-                return false;
-            }
-            return true;
-        }
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
index ec5d93e..68f696b 100644
--- a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
@@ -227,6 +227,22 @@
     }
 
     @Test
+    public void testPackageInLegacyMode() throws Exception {
+        setStorageMountMode(PID_RED, UID_COLORS, Zygote.MOUNT_EXTERNAL_LEGACY);
+
+        // Both app and system have the same view
+        assertTranslation(
+                "/storage/emulated/0/Android/data/com.red/foo.jpg",
+                "/storage/emulated/0/Android/data/com.red/foo.jpg",
+                PID_RED, UID_COLORS);
+
+        assertTranslation(
+                "/storage/emulated/0/Android/sandbox/com.grey/bar.jpg",
+                "/storage/emulated/0/Android/sandbox/com.grey/bar.jpg",
+                PID_RED, UID_COLORS);
+    }
+
+    @Test
     public void testInstallerPackage() throws Exception {
         setStorageMountMode(PID_GREY, UID_GREY, Zygote.MOUNT_EXTERNAL_INSTALLER);
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
new file mode 100644
index 0000000..782dc3e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.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 com.android.server.accessibility;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+import static android.view.WindowManagerPolicyConstants.FLAG_PASS_TO_USER;
+
+import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK;
+import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER;
+import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS;
+import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS;
+import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
+import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.display.DisplayManagerGlobal;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for AccessibilityInputFilterTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityInputFilterTest {
+    private static int sNextDisplayId = DEFAULT_DISPLAY;
+    private static final int SECOND_DISPLAY = DEFAULT_DISPLAY + 1;
+    private static final float DEFAULT_X = 100f;
+    private static final float DEFAULT_Y = 100f;
+
+    private final SparseArray<EventStreamTransformation> mEventHandler = new SparseArray<>(0);
+    private final ArrayList<Display> mDisplayList = new ArrayList<>();
+    private final int mFeatures = FLAG_FEATURE_AUTOCLICK
+            | FLAG_FEATURE_TOUCH_EXPLORATION
+            | FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER
+            | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER
+            | FLAG_FEATURE_INJECT_MOTION_EVENTS
+            | FLAG_FEATURE_FILTER_KEY_EVENTS;
+
+    // The expected order of EventStreamTransformations.
+    private final Class[] mExpectedEventHandlerTypes =
+            {KeyboardInterceptor.class, MotionEventInjector.class,
+                    MagnificationGestureHandler.class, TouchExplorer.class,
+                    AutoclickController.class, AccessibilityInputFilter.class};
+
+    private MagnificationController mMockMagnificationController;
+    private AccessibilityManagerService mAms;
+    private AccessibilityInputFilter mA11yInputFilter;
+    private EventCaptor mCaptor1;
+    private EventCaptor mCaptor2;
+    private long mLastDownTime = Integer.MIN_VALUE;
+
+    private class EventCaptor implements EventStreamTransformation {
+        List<InputEvent> mEvents = new ArrayList<>();
+
+        @Override
+        public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+            mEvents.add(event.copy());
+        }
+
+        @Override
+        public void onKeyEvent(KeyEvent event, int policyFlags) {
+            mEvents.add(event.copy());
+        }
+
+        @Override
+        public void setNext(EventStreamTransformation next) {
+        }
+
+        @Override
+        public EventStreamTransformation getNext() {
+            return null;
+        }
+
+        @Override
+        public void clearEvents(int inputSource) {
+            clear();
+        }
+
+        private void clear() {
+            mEvents.clear();
+        }
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        Context context = InstrumentationRegistry.getContext();
+
+        setDisplayCount(1);
+        mAms = spy(new AccessibilityManagerService(context));
+        mMockMagnificationController = mock(MagnificationController.class);
+        mA11yInputFilter = new AccessibilityInputFilter(context, mAms, mEventHandler);
+        mA11yInputFilter.onInstalled();
+
+        when(mAms.getValidDisplayList()).thenReturn(mDisplayList);
+        when(mAms.getMagnificationController()).thenReturn(mMockMagnificationController);
+    }
+
+    @After
+    public void tearDown() {
+        mA11yInputFilter.onUninstalled();
+    }
+
+    @Test
+    public void testEventHandler_shouldChangeAfterSetUserAndEnabledFeatures() {
+        prepareLooper();
+
+        // Check if there is no mEventHandler when no feature is set.
+        assertEquals(0, mEventHandler.size());
+
+        // Check if mEventHandler is added/removed after setting a11y features.
+        mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures);
+        assertEquals(1, mEventHandler.size());
+
+        mA11yInputFilter.setUserAndEnabledFeatures(0, 0);
+        assertEquals(0, mEventHandler.size());
+    }
+
+    @Test
+    public void testEventHandler_shouldChangeAfterOnDisplayChanged() {
+        prepareLooper();
+
+        // Check if there is only one mEventHandler when there is one default display.
+        mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures);
+        assertEquals(1, mEventHandler.size());
+
+        // Check if it has correct numbers of mEventHandler for corresponding displays.
+        setDisplayCount(4);
+        mA11yInputFilter.onDisplayChanged();
+        assertEquals(4, mEventHandler.size());
+
+        setDisplayCount(2);
+        mA11yInputFilter.onDisplayChanged();
+        assertEquals(2, mEventHandler.size());
+    }
+
+    @Test
+    public void testEventHandler_shouldHaveCorrectOrderForEventStreamTransformation() {
+        prepareLooper();
+
+        setDisplayCount(2);
+        mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures);
+        assertEquals(2, mEventHandler.size());
+
+        // Check if mEventHandler for each display has correct order of the
+        // EventStreamTransformations.
+        EventStreamTransformation next = mEventHandler.get(DEFAULT_DISPLAY);
+        for (int i = 0; next != null; i++) {
+            assertEquals(next.getClass(), mExpectedEventHandlerTypes[i]);
+            next = next.getNext();
+        }
+
+        next = mEventHandler.get(SECOND_DISPLAY);
+        // Start from index 1 because KeyboardInterceptor only exists in EventHandler for
+        // DEFAULT_DISPLAY.
+        for (int i = 1; next != null; i++) {
+            assertEquals(next.getClass(), mExpectedEventHandlerTypes[i]);
+            next = next.getNext();
+        }
+    }
+
+    @Test
+    public void testInputEvent_shouldDispatchToCorrespondingEventHandlers() {
+        prepareLooper();
+
+        setDisplayCount(2);
+        mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures);
+        assertEquals(2, mEventHandler.size());
+
+        mCaptor1 = new EventCaptor();
+        mCaptor2 = new EventCaptor();
+        mEventHandler.put(DEFAULT_DISPLAY, mCaptor1);
+        mEventHandler.put(SECOND_DISPLAY, mCaptor2);
+
+        // InputEvent with different displayId should be dispatched to corresponding EventHandler.
+        send(downEvent(DEFAULT_DISPLAY, InputDevice.SOURCE_TOUCHSCREEN));
+        send(downEvent(SECOND_DISPLAY, InputDevice.SOURCE_TOUCHSCREEN));
+
+        assertEquals(1, mCaptor1.mEvents.size());
+        assertEquals(1, mCaptor2.mEvents.size());
+    }
+
+    @Test
+    public void testInputEvent_shouldClearEventsForAllEventHandlers() {
+        prepareLooper();
+
+        mA11yInputFilter.setUserAndEnabledFeatures(0, mFeatures);
+        assertEquals(1, mEventHandler.size());
+
+        mCaptor1 = new EventCaptor();
+        mEventHandler.put(DEFAULT_DISPLAY, mCaptor1);
+
+        send(downEvent(DEFAULT_DISPLAY, InputDevice.SOURCE_TOUCHSCREEN));
+        send(downEvent(DEFAULT_DISPLAY, InputDevice.SOURCE_TOUCHSCREEN));
+        assertEquals(2, mCaptor1.mEvents.size());
+
+        // InputEvent with different input source should trigger clearEvents() for each
+        // EventStreamTransformation in EventHandler.
+        send(downEvent(DEFAULT_DISPLAY, InputDevice.SOURCE_MOUSE));
+        assertEquals(1, mCaptor1.mEvents.size());
+    }
+
+    private static void prepareLooper() {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+    }
+
+    private Display createStubDisplay(DisplayInfo displayInfo) {
+        final int displayId = sNextDisplayId++;
+        final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
+                displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
+        return display;
+    }
+
+    private void setDisplayCount(int count) {
+        sNextDisplayId = DEFAULT_DISPLAY;
+        mDisplayList.clear();
+        for (int i = 0; i < count; i++) {
+            mDisplayList.add(createStubDisplay(new DisplayInfo()));
+        }
+    }
+
+    private void send(InputEvent event) {
+        mA11yInputFilter.onInputEvent(event, /* policyFlags */ FLAG_PASS_TO_USER);
+    }
+
+    private MotionEvent downEvent(int displayId, int source) {
+        mLastDownTime = SystemClock.uptimeMillis();
+        final MotionEvent ev = MotionEvent.obtain(mLastDownTime, mLastDownTime,
+                MotionEvent.ACTION_DOWN, DEFAULT_X, DEFAULT_Y, 0);
+        ev.setDisplayId(displayId);
+        ev.setSource(source);
+        return ev;
+    }
+}
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 feffeef..773b877 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationControllerTest.java
@@ -20,7 +20,9 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
@@ -36,19 +38,15 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.IntentFilter;
-import android.content.res.Resources;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.os.Handler;
 import android.os.Looper;
-import android.os.Message;
 import android.view.MagnificationSpec;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.internal.R;
 import com.android.server.wm.WindowManagerInternal;
 import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
 
@@ -81,48 +79,36 @@
     static final Region OTHER_REGION = new Region(OTHER_MAGNIFICATION_BOUNDS);
     static final int SERVICE_ID_1 = 1;
     static final int SERVICE_ID_2 = 2;
+    static final int DISPLAY_0 = 0;
+    static final int DISPLAY_1 = 1;
+    static final int DISPLAY_COUNT = 2;
+    static final int INVALID_DISPLAY = 2;
 
+    final MagnificationController.ControllerContext mMockControllerCtx =
+            mock(MagnificationController.ControllerContext.class);
     final Context mMockContext = mock(Context.class);
     final AccessibilityManagerService mMockAms = mock(AccessibilityManagerService.class);
     final WindowManagerInternal mMockWindowManager = mock(WindowManagerInternal.class);
-    final MessageCapturingHandler mMessageCapturingHandler =
-            new MessageCapturingHandler(null);
+    final MessageCapturingHandler mMessageCapturingHandler = new MessageCapturingHandler(null);
 
-    final ValueAnimator mMockValueAnimator = mock(ValueAnimator.class);
-    MagnificationController.SettingsBridge mMockSettingsBridge;
+    ValueAnimator mMockValueAnimator;
+    ValueAnimator.AnimatorUpdateListener mTargetAnimationListener;
 
     MagnificationController mMagnificationController;
-    ValueAnimator.AnimatorUpdateListener mTargetAnimationListener;
 
     @Before
     public void setUp() {
         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))
-                .thenReturn(1000);
-        mMockSettingsBridge = mock(MagnificationController.SettingsBridge.class);
-        mMagnificationController = new MagnificationController(mMockContext, mMockAms, new Object(),
-                mMessageCapturingHandler, mMockWindowManager, mMockValueAnimator,
-                mMockSettingsBridge);
+        when(mMockControllerCtx.getContext()).thenReturn(mMockContext);
+        when(mMockControllerCtx.getAms()).thenReturn(mMockAms);
+        when(mMockControllerCtx.getWindowManager()).thenReturn(mMockWindowManager);
+        when(mMockControllerCtx.getHandler()).thenReturn(mMessageCapturingHandler);
+        when(mMockControllerCtx.getAnimationDuration()).thenReturn(1000L);
+        initMockWindowManager();
 
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
-                Object[] args = invocationOnMock.getArguments();
-                Region regionArg = (Region) args[0];
-                regionArg.set(INITIAL_MAGNIFICATION_REGION);
-                return null;
-            }
-        }).when(mMockWindowManager).getMagnificationRegion((Region) anyObject());
-
-        ArgumentCaptor<ValueAnimator.AnimatorUpdateListener> listenerArgumentCaptor =
-                ArgumentCaptor.forClass(ValueAnimator.AnimatorUpdateListener.class);
-        verify(mMockValueAnimator).addUpdateListener(listenerArgumentCaptor.capture());
-        mTargetAnimationListener = listenerArgumentCaptor.getValue();
-        Mockito.reset(mMockValueAnimator); // Ignore other initialization
+        mMagnificationController = new MagnificationController(mMockControllerCtx, new Object());
     }
 
     @After
@@ -133,88 +119,132 @@
 
     @Test
     public void testRegister_WindowManagerAndContextRegisterListeners() {
-        mMagnificationController.register();
+        register(DISPLAY_0);
+        register(DISPLAY_1);
+        register(INVALID_DISPLAY);
         verify(mMockContext).registerReceiver(
                 (BroadcastReceiver) anyObject(), (IntentFilter) anyObject());
-        verify(mMockWindowManager).setMagnificationCallbacks((MagnificationCallbacks) anyObject());
-        assertTrue(mMagnificationController.isRegisteredLocked());
+        verify(mMockWindowManager).setMagnificationCallbacks(
+                eq(DISPLAY_0), (MagnificationCallbacks) anyObject());
+        verify(mMockWindowManager).setMagnificationCallbacks(
+                eq(DISPLAY_1), (MagnificationCallbacks) anyObject());
+        verify(mMockWindowManager).setMagnificationCallbacks(
+                eq(INVALID_DISPLAY), (MagnificationCallbacks) anyObject());
+        assertTrue(mMagnificationController.isRegistered(DISPLAY_0));
+        assertTrue(mMagnificationController.isRegistered(DISPLAY_1));
+        assertFalse(mMagnificationController.isRegistered(INVALID_DISPLAY));
     }
 
     @Test
     public void testRegister_WindowManagerAndContextUnregisterListeners() {
-        mMagnificationController.register();
-        mMagnificationController.unregister();
-
+        register(DISPLAY_0);
+        register(DISPLAY_1);
+        mMagnificationController.unregister(DISPLAY_0);
+        verify(mMockContext, times(0)).unregisterReceiver((BroadcastReceiver) anyObject());
+        mMagnificationController.unregister(DISPLAY_1);
         verify(mMockContext).unregisterReceiver((BroadcastReceiver) anyObject());
-        verify(mMockWindowManager).setMagnificationCallbacks(null);
-        assertFalse(mMagnificationController.isRegisteredLocked());
+        verify(mMockWindowManager).setMagnificationCallbacks(eq(DISPLAY_0), eq(null));
+        verify(mMockWindowManager).setMagnificationCallbacks(eq(DISPLAY_1), eq(null));
+        assertFalse(mMagnificationController.isRegistered(DISPLAY_0));
+        assertFalse(mMagnificationController.isRegistered(DISPLAY_1));
     }
 
     @Test
     public void testInitialState_noMagnificationAndMagnificationRegionReadFromWindowManager() {
-        mMagnificationController.register();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            initialState_noMagnificationAndMagnificationRegionReadFromWindowManager(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void initialState_noMagnificationAndMagnificationRegionReadFromWindowManager(
+            int displayId) {
+        register(displayId);
         MagnificationSpec expectedInitialSpec = getMagnificationSpec(1.0f, 0.0f, 0.0f);
         Region initialMagRegion = new Region();
         Rect initialBounds = new Rect();
 
-        assertEquals(expectedInitialSpec, getCurrentMagnificationSpec());
-        mMagnificationController.getMagnificationRegion(initialMagRegion);
-        mMagnificationController.getMagnificationBounds(initialBounds);
+        assertEquals(expectedInitialSpec, getCurrentMagnificationSpec(displayId));
+        mMagnificationController.getMagnificationRegion(displayId, initialMagRegion);
+        mMagnificationController.getMagnificationBounds(displayId, initialBounds);
         assertEquals(INITIAL_MAGNIFICATION_REGION, initialMagRegion);
         assertEquals(INITIAL_MAGNIFICATION_BOUNDS, initialBounds);
         assertEquals(INITIAL_MAGNIFICATION_BOUNDS.centerX(),
-                mMagnificationController.getCenterX(), 0.0f);
+                mMagnificationController.getCenterX(displayId), 0.0f);
         assertEquals(INITIAL_MAGNIFICATION_BOUNDS.centerY(),
-                mMagnificationController.getCenterY(), 0.0f);
+                mMagnificationController.getCenterY(displayId), 0.0f);
     }
 
     @Test
     public void testNotRegistered_publicMethodsShouldBeBenign() {
-        assertFalse(mMagnificationController.isMagnifying());
-        assertFalse(mMagnificationController.magnificationRegionContains(100, 100));
-        assertFalse(mMagnificationController.reset(true));
-        assertFalse(mMagnificationController.setScale(2, 100, 100, true, 0));
-        assertFalse(mMagnificationController.setCenter(100, 100, false, 1));
-        assertFalse(mMagnificationController.setScaleAndCenter(1.5f, 100, 100, false, 2));
-        assertTrue(mMagnificationController.getIdOfLastServiceToMagnify() < 0);
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            notRegistered_publicMethodsShouldBeBenign(i);
+            resetMockWindowManager();
+        }
+    }
 
-        mMagnificationController.getMagnificationRegion(new Region());
-        mMagnificationController.getMagnificationBounds(new Rect());
-        mMagnificationController.getScale();
-        mMagnificationController.getOffsetX();
-        mMagnificationController.getOffsetY();
-        mMagnificationController.getCenterX();
-        mMagnificationController.getCenterY();
-        mMagnificationController.offsetMagnifiedRegion(50, 50, 1);
-        mMagnificationController.unregister();
+    private void notRegistered_publicMethodsShouldBeBenign(int displayId) {
+        assertFalse(mMagnificationController.isMagnifying(displayId));
+        assertFalse(mMagnificationController.magnificationRegionContains(displayId, 100, 100));
+        assertFalse(mMagnificationController.reset(displayId, true));
+        assertFalse(mMagnificationController.setScale(displayId, 2, 100, 100, true, 0));
+        assertFalse(mMagnificationController.setCenter(displayId, 100, 100, false, 1));
+        assertFalse(mMagnificationController.setScaleAndCenter(displayId,
+                1.5f, 100, 100, false, 2));
+        assertTrue(mMagnificationController.getIdOfLastServiceToMagnify(displayId) < 0);
+
+        mMagnificationController.getMagnificationRegion(displayId, new Region());
+        mMagnificationController.getMagnificationBounds(displayId, new Rect());
+        mMagnificationController.getScale(displayId);
+        mMagnificationController.getOffsetX(displayId);
+        mMagnificationController.getOffsetY(displayId);
+        mMagnificationController.getCenterX(displayId);
+        mMagnificationController.getCenterY(displayId);
+        mMagnificationController.offsetMagnifiedRegion(displayId, 50, 50, 1);
+        mMagnificationController.unregister(displayId);
     }
 
     @Test
     public void testSetScale_noAnimation_shouldGoStraightToWindowManagerAndUpdateState() {
-        mMagnificationController.register();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            setScale_noAnimation_shouldGoStraightToWindowManagerAndUpdateState(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void setScale_noAnimation_shouldGoStraightToWindowManagerAndUpdateState(int displayId) {
+        register(displayId);
         final float scale = 2.0f;
         final PointF center = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
         final PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, center, scale);
         assertTrue(mMagnificationController
-                .setScale(scale, center.x, center.y, false, SERVICE_ID_1));
+                .setScale(displayId, scale, center.x, center.y, false, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
         final MagnificationSpec expectedSpec = getMagnificationSpec(scale, offsets);
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedSpec)));
-        assertThat(getCurrentMagnificationSpec(), closeTo(expectedSpec));
-        assertEquals(center.x, mMagnificationController.getCenterX(), 0.0);
-        assertEquals(center.y, mMagnificationController.getCenterY(), 0.0);
+        verify(mMockWindowManager).setMagnificationSpec(
+                eq(displayId), argThat(closeTo(expectedSpec)));
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(expectedSpec));
+        assertEquals(center.x, mMagnificationController.getCenterX(displayId), 0.0);
+        assertEquals(center.y, mMagnificationController.getCenterY(displayId), 0.0);
         verify(mMockValueAnimator, times(0)).start();
     }
 
     @Test
     public void testSetScale_withPivotAndAnimation_stateChangesAndAnimationHappens() {
-        mMagnificationController.register();
-        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            setScale_withPivotAndAnimation_stateChangesAndAnimationHappens(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void setScale_withPivotAndAnimation_stateChangesAndAnimationHappens(int displayId) {
+        register(displayId);
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
         float scale = 2.0f;
         PointF pivotPoint = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         assertTrue(mMagnificationController
-                .setScale(scale, pivotPoint.x, pivotPoint.y, true, SERVICE_ID_1));
+                .setScale(displayId, scale, pivotPoint.x, pivotPoint.y, true, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
         // New center should be halfway between original center and pivot
@@ -223,467 +253,645 @@
         PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
         MagnificationSpec endSpec = getMagnificationSpec(scale, offsets);
 
-        assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5);
-        assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5);
-        assertThat(getCurrentMagnificationSpec(), closeTo(endSpec));
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(displayId), 0.5);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(displayId), 0.5);
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(endSpec));
         verify(mMockValueAnimator).start();
 
         // Initial value
         when(mMockValueAnimator.getAnimatedFraction()).thenReturn(0.0f);
         mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
-        verify(mMockWindowManager).setMagnificationSpec(startSpec);
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId), eq(startSpec));
 
         // Intermediate point
         Mockito.reset(mMockWindowManager);
         float fraction = 0.5f;
         when(mMockValueAnimator.getAnimatedFraction()).thenReturn(fraction);
         mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
-        verify(mMockWindowManager).setMagnificationSpec(
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId),
                 argThat(closeTo(getInterpolatedMagSpec(startSpec, endSpec, fraction))));
 
         // Final value
         Mockito.reset(mMockWindowManager);
         when(mMockValueAnimator.getAnimatedFraction()).thenReturn(1.0f);
         mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(endSpec)));
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId), argThat(closeTo(endSpec)));
     }
 
     @Test
     public void testSetCenter_whileMagnifying_noAnimation_centerMoves() {
-        mMagnificationController.register();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            setCenter_whileMagnifying_noAnimation_centerMoves(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void setCenter_whileMagnifying_noAnimation_centerMoves(int displayId) {
+        register(displayId);
         // First zoom in
         float scale = 2.0f;
-        assertTrue(mMagnificationController.setScale(scale,
+        assertTrue(mMagnificationController.setScale(displayId, scale,
                 INITIAL_MAGNIFICATION_BOUNDS.centerX(), INITIAL_MAGNIFICATION_BOUNDS.centerY(),
                 false, SERVICE_ID_1));
         Mockito.reset(mMockWindowManager);
 
         PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         assertTrue(mMagnificationController
-                .setCenter(newCenter.x, newCenter.y, false, SERVICE_ID_1));
+                .setCenter(displayId, newCenter.x, newCenter.y, false, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
         PointF expectedOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
         MagnificationSpec expectedSpec = getMagnificationSpec(scale, expectedOffsets);
 
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedSpec)));
-        assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.0);
-        assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.0);
+        verify(mMockWindowManager).setMagnificationSpec(
+                eq(displayId), argThat(closeTo(expectedSpec)));
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(displayId), 0.0);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(displayId), 0.0);
         verify(mMockValueAnimator, times(0)).start();
     }
 
     @Test
     public void testSetScaleAndCenter_animated_stateChangesAndAnimationHappens() {
-        mMagnificationController.register();
-        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            setScaleAndCenter_animated_stateChangesAndAnimationHappens(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void setScaleAndCenter_animated_stateChangesAndAnimationHappens(int displayId) {
+        register(displayId);
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
         float scale = 2.5f;
         PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale);
         MagnificationSpec endSpec = getMagnificationSpec(scale, offsets);
 
-        assertTrue(mMagnificationController.setScaleAndCenter(scale, newCenter.x, newCenter.y,
-                true, SERVICE_ID_1));
+        assertTrue(mMagnificationController.setScaleAndCenter(displayId, 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);
-        assertThat(getCurrentMagnificationSpec(), closeTo(endSpec));
-        verify(mMockAms).notifyMagnificationChanged(
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(displayId), 0.5);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(displayId), 0.5);
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(endSpec));
+        verify(mMockAms).notifyMagnificationChanged(displayId,
                 INITIAL_MAGNIFICATION_REGION, scale, newCenter.x, newCenter.y);
         verify(mMockValueAnimator).start();
 
         // Initial value
         when(mMockValueAnimator.getAnimatedFraction()).thenReturn(0.0f);
         mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
-        verify(mMockWindowManager).setMagnificationSpec(startSpec);
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId), eq(startSpec));
 
         // Intermediate point
         Mockito.reset(mMockWindowManager);
         float fraction = 0.33f;
         when(mMockValueAnimator.getAnimatedFraction()).thenReturn(fraction);
         mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
-        verify(mMockWindowManager).setMagnificationSpec(
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId),
                 argThat(closeTo(getInterpolatedMagSpec(startSpec, endSpec, fraction))));
 
         // Final value
         Mockito.reset(mMockWindowManager);
         when(mMockValueAnimator.getAnimatedFraction()).thenReturn(1.0f);
         mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(endSpec)));
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId), argThat(closeTo(endSpec)));
     }
 
     @Test
     public void testSetScaleAndCenter_scaleOutOfBounds_cappedAtLimits() {
-        mMagnificationController.register();
-        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            setScaleAndCenter_scaleOutOfBounds_cappedAtLimits(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void setScaleAndCenter_scaleOutOfBounds_cappedAtLimits(int displayId) {
+        register(displayId);
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
         PointF newCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         PointF offsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter,
                 MagnificationController.MAX_SCALE);
         MagnificationSpec endSpec = getMagnificationSpec(
                 MagnificationController.MAX_SCALE, offsets);
 
-        assertTrue(mMagnificationController.setScaleAndCenter(
+        assertTrue(mMagnificationController.setScaleAndCenter(displayId,
                 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);
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(endSpec)));
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(displayId), 0.5);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(displayId), 0.5);
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId), argThat(closeTo(endSpec)));
         Mockito.reset(mMockWindowManager);
 
         // Verify that we can't zoom below 1x
-        assertTrue(mMagnificationController.setScaleAndCenter(0.5f,
+        assertTrue(mMagnificationController.setScaleAndCenter(displayId, 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);
+                mMagnificationController.getCenterX(displayId), 0.5);
         assertEquals(INITIAL_MAGNIFICATION_BOUNDS_CENTER.y,
-                mMagnificationController.getCenterY(), 0.5);
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(startSpec)));
+                mMagnificationController.getCenterY(displayId), 0.5);
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId), argThat(closeTo(startSpec)));
     }
 
     @Test
     public void testSetScaleAndCenter_centerOutOfBounds_cappedAtLimits() {
-        mMagnificationController.register();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            setScaleAndCenter_centerOutOfBounds_cappedAtLimits(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void setScaleAndCenter_centerOutOfBounds_cappedAtLimits(int displayId) {
+        register(displayId);
         float scale = 2.0f;
 
         // Off the edge to the top and left
-        assertTrue(mMagnificationController.setScaleAndCenter(
+        assertTrue(mMagnificationController.setScaleAndCenter(displayId,
                 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);
-        assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.5);
-        assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5);
-        verify(mMockWindowManager).setMagnificationSpec(
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(displayId), 0.5);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(displayId), 0.5);
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId),
                 argThat(closeTo(getMagnificationSpec(scale, newOffsets))));
         Mockito.reset(mMockWindowManager);
 
         // Off the edge to the bottom and right
-        assertTrue(mMagnificationController.setScaleAndCenter(scale,
+        assertTrue(mMagnificationController.setScaleAndCenter(displayId, 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);
-        assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.5);
-        verify(mMockWindowManager).setMagnificationSpec(
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(displayId), 0.5);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(displayId), 0.5);
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId),
                 argThat(closeTo(getMagnificationSpec(scale, newOffsets))));
     }
 
     @Test
     public void testMagnificationRegionChanged_serviceNotified() {
-        mMagnificationController.register();
-        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            magnificationRegionChanged_serviceNotified(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void magnificationRegionChanged_serviceNotified(int displayId) {
+        register(displayId);
+        MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
         callbacks.onMagnificationRegionChanged(OTHER_REGION);
         mMessageCapturingHandler.sendAllMessages();
-        verify(mMockAms).notifyMagnificationChanged(OTHER_REGION, 1.0f,
+        verify(mMockAms).notifyMagnificationChanged(displayId, OTHER_REGION, 1.0f,
                 OTHER_MAGNIFICATION_BOUNDS.centerX(), OTHER_MAGNIFICATION_BOUNDS.centerY());
     }
 
     @Test
     public void testOffsetMagnifiedRegion_whileMagnifying_offsetsMove() {
-        mMagnificationController.register();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            offsetMagnifiedRegion_whileMagnifying_offsetsMove(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void offsetMagnifiedRegion_whileMagnifying_offsetsMove(int displayId) {
+        register(displayId);
         PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
         float scale = 2.0f;
         PointF startOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, startCenter, scale);
         // First zoom in
         assertTrue(mMagnificationController
-                .setScaleAndCenter(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1));
+                .setScaleAndCenter(displayId, 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);
+        mMagnificationController.offsetMagnifiedRegion(displayId,
+                startOffsets.x - newOffsets.x, startOffsets.y - newOffsets.y,
+                SERVICE_ID_1);
         mMessageCapturingHandler.sendAllMessages();
 
         MagnificationSpec expectedSpec = getMagnificationSpec(scale, newOffsets);
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedSpec)));
-        assertEquals(newCenter.x, mMagnificationController.getCenterX(), 0.0);
-        assertEquals(newCenter.y, mMagnificationController.getCenterY(), 0.0);
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId),
+                argThat(closeTo(expectedSpec)));
+        assertEquals(newCenter.x, mMagnificationController.getCenterX(displayId), 0.0);
+        assertEquals(newCenter.y, mMagnificationController.getCenterY(displayId), 0.0);
         verify(mMockValueAnimator, times(0)).start();
     }
 
     @Test
     public void testOffsetMagnifiedRegion_whileNotMagnifying_hasNoEffect() {
-        mMagnificationController.register();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            offsetMagnifiedRegion_whileNotMagnifying_hasNoEffect(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void offsetMagnifiedRegion_whileNotMagnifying_hasNoEffect(int displayId) {
+        register(displayId);
         Mockito.reset(mMockWindowManager);
-        MagnificationSpec startSpec = getCurrentMagnificationSpec();
-        mMagnificationController.offsetMagnifiedRegion(10, 10, SERVICE_ID_1);
-        assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
-        mMagnificationController.offsetMagnifiedRegion(-10, -10, SERVICE_ID_1);
-        assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
+        mMagnificationController.offsetMagnifiedRegion(displayId, 10, 10, SERVICE_ID_1);
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(startSpec));
+        mMagnificationController.offsetMagnifiedRegion(displayId, -10, -10, SERVICE_ID_1);
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(startSpec));
         verifyNoMoreInteractions(mMockWindowManager);
     }
 
     @Test
     public void testOffsetMagnifiedRegion_whileMagnifyingButAtEdge_hasNoEffect() {
-        mMagnificationController.register();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            offsetMagnifiedRegion_whileMagnifyingButAtEdge_hasNoEffect(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void offsetMagnifiedRegion_whileMagnifyingButAtEdge_hasNoEffect(int displayId) {
+        register(displayId);
         float scale = 2.0f;
 
         // Upper left edges
         PointF ulCenter = INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER;
         assertTrue(mMagnificationController
-                .setScaleAndCenter(scale, ulCenter.x, ulCenter.y, false, SERVICE_ID_1));
+                .setScaleAndCenter(displayId, scale, ulCenter.x, ulCenter.y, false,
+                        SERVICE_ID_1));
         Mockito.reset(mMockWindowManager);
-        MagnificationSpec ulSpec = getCurrentMagnificationSpec();
-        mMagnificationController.offsetMagnifiedRegion(-10, -10, SERVICE_ID_1);
-        assertThat(getCurrentMagnificationSpec(), closeTo(ulSpec));
+        MagnificationSpec ulSpec = getCurrentMagnificationSpec(displayId);
+        mMagnificationController.offsetMagnifiedRegion(displayId, -10, -10,
+                SERVICE_ID_1);
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(ulSpec));
         verifyNoMoreInteractions(mMockWindowManager);
 
         // Lower right edges
         PointF lrCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         assertTrue(mMagnificationController
-                .setScaleAndCenter(scale, lrCenter.x, lrCenter.y, false, SERVICE_ID_1));
+                .setScaleAndCenter(displayId, scale, lrCenter.x, lrCenter.y, false,
+                        SERVICE_ID_1));
         Mockito.reset(mMockWindowManager);
-        MagnificationSpec lrSpec = getCurrentMagnificationSpec();
-        mMagnificationController.offsetMagnifiedRegion(10, 10, SERVICE_ID_1);
-        assertThat(getCurrentMagnificationSpec(), closeTo(lrSpec));
+        MagnificationSpec lrSpec = getCurrentMagnificationSpec(displayId);
+        mMagnificationController.offsetMagnifiedRegion(displayId, 10, 10,
+                SERVICE_ID_1);
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(lrSpec));
         verifyNoMoreInteractions(mMockWindowManager);
     }
 
     @Test
     public void testGetIdOfLastServiceToChange_returnsCorrectValue() {
-        mMagnificationController.register();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            getIdOfLastServiceToChange_returnsCorrectValue(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void getIdOfLastServiceToChange_returnsCorrectValue(int displayId) {
+        register(displayId);
         PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
         assertTrue(mMagnificationController
-                .setScale(2.0f, startCenter.x, startCenter.y, false, SERVICE_ID_1));
-        assertEquals(SERVICE_ID_1, mMagnificationController.getIdOfLastServiceToMagnify());
+                .setScale(displayId, 2.0f, startCenter.x, startCenter.y, false,
+                        SERVICE_ID_1));
+        assertEquals(SERVICE_ID_1, mMagnificationController.getIdOfLastServiceToMagnify(displayId));
         assertTrue(mMagnificationController
-                .setScale(1.5f, startCenter.x, startCenter.y, false, SERVICE_ID_2));
-        assertEquals(SERVICE_ID_2, mMagnificationController.getIdOfLastServiceToMagnify());
+                .setScale(displayId, 1.5f, startCenter.x, startCenter.y, false,
+                        SERVICE_ID_2));
+        assertEquals(SERVICE_ID_2, mMagnificationController.getIdOfLastServiceToMagnify(displayId));
     }
 
     @Test
     public void testResetIfNeeded_resetsOnlyIfLastMagnifyingServiceIsDisabled() {
-        mMagnificationController.register();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            resetIfNeeded_resetsOnlyIfLastMagnifyingServiceIsDisabled(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void resetIfNeeded_resetsOnlyIfLastMagnifyingServiceIsDisabled(int displayId) {
+        register(displayId);
         PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
         mMagnificationController
-                .setScale(2.0f, startCenter.x, startCenter.y, false, SERVICE_ID_1);
+                .setScale(displayId, 2.0f, startCenter.x, startCenter.y, false,
+                        SERVICE_ID_1);
         mMagnificationController
-                .setScale(1.5f, startCenter.x, startCenter.y, false, SERVICE_ID_2);
-        assertFalse(mMagnificationController.resetIfNeeded(SERVICE_ID_1));
-        assertTrue(mMagnificationController.isMagnifying());
-        assertTrue(mMagnificationController.resetIfNeeded(SERVICE_ID_2));
-        assertFalse(mMagnificationController.isMagnifying());
+                .setScale(displayId, 1.5f, startCenter.x, startCenter.y, false,
+                        SERVICE_ID_2);
+        assertFalse(mMagnificationController.resetIfNeeded(displayId, SERVICE_ID_1));
+        assertTrue(mMagnificationController.isMagnifying(displayId));
+        assertTrue(mMagnificationController.resetIfNeeded(displayId, SERVICE_ID_2));
+        assertFalse(mMagnificationController.isMagnifying(displayId));
     }
 
     @Test
     public void testSetUserId_resetsOnlyIfIdChanges() {
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            testSetUserId_resetsOnlyIfIdChanges(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void testSetUserId_resetsOnlyIfIdChanges(int displayId) {
         final int userId1 = 1;
         final int userId2 = 2;
 
-        mMagnificationController.register();
+        register(displayId);
         mMagnificationController.setUserId(userId1);
         PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
         float scale = 2.0f;
-        mMagnificationController.setScale(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1);
+        mMagnificationController.setScale(displayId, scale, startCenter.x, startCenter.y, false,
+                SERVICE_ID_1);
 
         mMagnificationController.setUserId(userId1);
-        assertTrue(mMagnificationController.isMagnifying());
+        assertTrue(mMagnificationController.isMagnifying(displayId));
         mMagnificationController.setUserId(userId2);
-        assertFalse(mMagnificationController.isMagnifying());
+        assertFalse(mMagnificationController.isMagnifying(displayId));
     }
 
     @Test
     public void testResetIfNeeded_doesWhatItSays() {
-        mMagnificationController.register();
-        zoomIn2xToMiddle();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            testResetIfNeeded_doesWhatItSays(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void testResetIfNeeded_doesWhatItSays(int displayId) {
+        register(displayId);
+        zoomIn2xToMiddle(displayId);
         mMessageCapturingHandler.sendAllMessages();
         reset(mMockAms);
-        assertTrue(mMagnificationController.resetIfNeeded(false));
-        verify(mMockAms).notifyMagnificationChanged(
+        assertTrue(mMagnificationController.resetIfNeeded(displayId, false));
+        verify(mMockAms).notifyMagnificationChanged(eq(displayId),
                 eq(INITIAL_MAGNIFICATION_REGION), eq(1.0f), anyFloat(), anyFloat());
-        assertFalse(mMagnificationController.isMagnifying());
-        assertFalse(mMagnificationController.resetIfNeeded(false));
+        assertFalse(mMagnificationController.isMagnifying(displayId));
+        assertFalse(mMagnificationController.resetIfNeeded(displayId, false));
     }
 
     @Test
     public void testTurnScreenOff_resetsMagnification() {
-        mMagnificationController.register();
+        register(DISPLAY_0);
+        register(DISPLAY_1);
         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
         verify(mMockContext).registerReceiver(
                 broadcastReceiverCaptor.capture(), (IntentFilter) anyObject());
         BroadcastReceiver br = broadcastReceiverCaptor.getValue();
-        zoomIn2xToMiddle();
+        zoomIn2xToMiddle(DISPLAY_0);
+        zoomIn2xToMiddle(DISPLAY_1);
         mMessageCapturingHandler.sendAllMessages();
         br.onReceive(mMockContext, null);
         mMessageCapturingHandler.sendAllMessages();
-        assertFalse(mMagnificationController.isMagnifying());
+        assertFalse(mMagnificationController.isMagnifying(DISPLAY_0));
+        assertFalse(mMagnificationController.isMagnifying(DISPLAY_1));
     }
 
     @Test
     public void testUserContextChange_resetsMagnification() {
-        mMagnificationController.register();
-        MagnificationCallbacks callbacks = getMagnificationCallbacks();
-        zoomIn2xToMiddle();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            contextChange_resetsMagnification(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void contextChange_resetsMagnification(int displayId) {
+        register(displayId);
+        MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
+        zoomIn2xToMiddle(displayId);
         mMessageCapturingHandler.sendAllMessages();
         callbacks.onUserContextChanged();
         mMessageCapturingHandler.sendAllMessages();
-        assertFalse(mMagnificationController.isMagnifying());
+        assertFalse(mMagnificationController.isMagnifying(displayId));
     }
 
     @Test
     public void testRotation_resetsMagnification() {
-        mMagnificationController.register();
-        MagnificationCallbacks callbacks = getMagnificationCallbacks();
-        zoomIn2xToMiddle();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            rotation_resetsMagnification(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void rotation_resetsMagnification(int displayId) {
+        register(displayId);
+        MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
+        zoomIn2xToMiddle(displayId);
         mMessageCapturingHandler.sendAllMessages();
-        assertTrue(mMagnificationController.isMagnifying());
+        assertTrue(mMagnificationController.isMagnifying(displayId));
         callbacks.onRotationChanged(0);
         mMessageCapturingHandler.sendAllMessages();
-        assertFalse(mMagnificationController.isMagnifying());
+        assertFalse(mMagnificationController.isMagnifying(displayId));
     }
 
     @Test
     public void testBoundsChange_whileMagnifyingWithCompatibleSpec_noSpecChange() {
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            boundsChange_whileMagnifyingWithCompatibleSpec_noSpecChange(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void boundsChange_whileMagnifyingWithCompatibleSpec_noSpecChange(int displayId) {
         // Going from a small region to a large one leads to no issues
-        mMagnificationController.register();
-        zoomIn2xToMiddle();
+        register(displayId);
+        zoomIn2xToMiddle(displayId);
         mMessageCapturingHandler.sendAllMessages();
-        MagnificationSpec startSpec = getCurrentMagnificationSpec();
-        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
+        MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
         Mockito.reset(mMockWindowManager);
         callbacks.onMagnificationRegionChanged(OTHER_REGION_COMPAT);
         mMessageCapturingHandler.sendAllMessages();
-        assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(startSpec));
         verifyNoMoreInteractions(mMockWindowManager);
     }
 
     @Test
     public void testBoundsChange_whileZoomingWithCompatibleSpec_noSpecChange() {
-        mMagnificationController.register();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            boundsChange_whileZoomingWithCompatibleSpec_noSpecChange(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void boundsChange_whileZoomingWithCompatibleSpec_noSpecChange(int displayId) {
+        register(displayId);
         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();
+        mMagnificationController.setScale(displayId, scale, startCenter.x, startCenter.y, true,
+                SERVICE_ID_1);
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
+        MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
         Mockito.reset(mMockWindowManager);
         callbacks.onMagnificationRegionChanged(OTHER_REGION_COMPAT);
         mMessageCapturingHandler.sendAllMessages();
-        assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(startSpec));
         verifyNoMoreInteractions(mMockWindowManager);
     }
 
     @Test
     public void testBoundsChange_whileMagnifyingWithIncompatibleSpec_offsetsConstrained() {
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            boundsChange_whileMagnifyingWithIncompatibleSpec_offsetsConstrained(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void boundsChange_whileMagnifyingWithIncompatibleSpec_offsetsConstrained(
+            int displayId) {
         // In a large region, pan to the farthest point possible
-        mMagnificationController.register();
-        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        register(displayId);
+        MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
         callbacks.onMagnificationRegionChanged(OTHER_REGION);
         mMessageCapturingHandler.sendAllMessages();
         PointF startCenter = OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER;
         float scale = 2.0f;
-        mMagnificationController.setScale(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1);
+        mMagnificationController.setScale(displayId, scale, startCenter.x, startCenter.y, false,
+                SERVICE_ID_1);
         mMessageCapturingHandler.sendAllMessages();
-        MagnificationSpec startSpec = getCurrentMagnificationSpec();
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(startSpec)));
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId), argThat(closeTo(startSpec)));
         Mockito.reset(mMockWindowManager);
 
         callbacks.onMagnificationRegionChanged(INITIAL_MAGNIFICATION_REGION);
         mMessageCapturingHandler.sendAllMessages();
 
-        MagnificationSpec endSpec = getCurrentMagnificationSpec();
+        MagnificationSpec endSpec = getCurrentMagnificationSpec(displayId);
         assertThat(endSpec, CoreMatchers.not(closeTo(startSpec)));
         PointF expectedOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS,
                 INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER, scale);
         assertThat(endSpec, closeTo(getMagnificationSpec(scale, expectedOffsets)));
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(endSpec)));
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId), argThat(closeTo(endSpec)));
     }
 
     @Test
     public void testBoundsChange_whileZoomingWithIncompatibleSpec_jumpsToCompatibleSpec() {
-        mMagnificationController.register();
-        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            boundsChange_whileZoomingWithIncompatibleSpec_jumpsToCompatibleSpec(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void boundsChange_whileZoomingWithIncompatibleSpec_jumpsToCompatibleSpec(
+            int displayId) {
+        register(displayId);
+        MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
         callbacks.onMagnificationRegionChanged(OTHER_REGION);
         mMessageCapturingHandler.sendAllMessages();
         PointF startCenter = OTHER_BOUNDS_LOWER_RIGHT_2X_CENTER;
         float scale = 2.0f;
-        mMagnificationController.setScale(scale, startCenter.x, startCenter.y, true, SERVICE_ID_1);
+        mMagnificationController.setScale(displayId, scale, startCenter.x, startCenter.y, true,
+                SERVICE_ID_1);
         mMessageCapturingHandler.sendAllMessages();
-        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
         when(mMockValueAnimator.isRunning()).thenReturn(true);
 
         callbacks.onMagnificationRegionChanged(INITIAL_MAGNIFICATION_REGION);
         mMessageCapturingHandler.sendAllMessages();
         verify(mMockValueAnimator).cancel();
 
-        MagnificationSpec endSpec = getCurrentMagnificationSpec();
+        MagnificationSpec endSpec = getCurrentMagnificationSpec(displayId);
         assertThat(endSpec, CoreMatchers.not(closeTo(startSpec)));
         PointF expectedOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS,
                 INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER, scale);
         assertThat(endSpec, closeTo(getMagnificationSpec(scale, expectedOffsets)));
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(endSpec)));
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId), argThat(closeTo(endSpec)));
     }
 
     @Test
     public void testRequestRectOnScreen_rectAlreadyOnScreen_doesNothing() {
-        mMagnificationController.register();
-        zoomIn2xToMiddle();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            requestRectOnScreen_rectAlreadyOnScreen_doesNothing(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void requestRectOnScreen_rectAlreadyOnScreen_doesNothing(int displayId) {
+        register(displayId);
+        zoomIn2xToMiddle(displayId);
         mMessageCapturingHandler.sendAllMessages();
-        MagnificationSpec startSpec = getCurrentMagnificationSpec();
-        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
+        MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
         Mockito.reset(mMockWindowManager);
         int centerX = (int) INITIAL_MAGNIFICATION_BOUNDS_CENTER.x;
         int centerY = (int) INITIAL_MAGNIFICATION_BOUNDS_CENTER.y;
         callbacks.onRectangleOnScreenRequested(centerX - 1, centerY - 1, centerX + 1, centerY - 1);
         mMessageCapturingHandler.sendAllMessages();
-        assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(startSpec));
         verifyNoMoreInteractions(mMockWindowManager);
     }
 
     @Test
     public void testRequestRectOnScreen_rectCanFitOnScreen_pansToGetRectOnScreen() {
-        mMagnificationController.register();
-        zoomIn2xToMiddle();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            requestRectOnScreen_rectCanFitOnScreen_pansToGetRectOnScreen(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void requestRectOnScreen_rectCanFitOnScreen_pansToGetRectOnScreen(int displayId) {
+        register(displayId);
+        zoomIn2xToMiddle(displayId);
         mMessageCapturingHandler.sendAllMessages();
-        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
         Mockito.reset(mMockWindowManager);
         callbacks.onRectangleOnScreenRequested(0, 0, 1, 1);
         mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec expectedEndSpec = getMagnificationSpec(2.0f, 0, 0);
-        assertThat(getCurrentMagnificationSpec(), closeTo(expectedEndSpec));
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedEndSpec)));
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(expectedEndSpec));
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId),
+                argThat(closeTo(expectedEndSpec)));
     }
 
     @Test
     public void testRequestRectOnScreen_garbageInput_doesNothing() {
-        mMagnificationController.register();
-        zoomIn2xToMiddle();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            requestRectOnScreen_garbageInput_doesNothing(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void requestRectOnScreen_garbageInput_doesNothing(int displayId) {
+        register(displayId);
+        zoomIn2xToMiddle(displayId);
         mMessageCapturingHandler.sendAllMessages();
-        MagnificationSpec startSpec = getCurrentMagnificationSpec();
-        MagnificationCallbacks callbacks = getMagnificationCallbacks();
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
+        MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
         Mockito.reset(mMockWindowManager);
         callbacks.onRectangleOnScreenRequested(0, 0, -50, -50);
         mMessageCapturingHandler.sendAllMessages();
-        assertThat(getCurrentMagnificationSpec(), closeTo(startSpec));
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(startSpec));
         verifyNoMoreInteractions(mMockWindowManager);
     }
 
     @Test
     public void testRequestRectOnScreen_rectTooWide_pansToGetStartOnScreenBasedOnLocale() {
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            requestRectOnScreen_rectTooWide_pansToGetStartOnScreenBasedOnLocale(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void requestRectOnScreen_rectTooWide_pansToGetStartOnScreenBasedOnLocale(
+            int displayId) {
         Locale.setDefault(new Locale("en", "us"));
-        mMagnificationController.register();
-        zoomIn2xToMiddle();
+        register(displayId);
+        zoomIn2xToMiddle(displayId);
         mMessageCapturingHandler.sendAllMessages();
-        MagnificationCallbacks callbacks = getMagnificationCallbacks();
-        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
         Mockito.reset(mMockWindowManager);
         Rect wideRect = new Rect(0, 50, 100, 51);
         callbacks.onRectangleOnScreenRequested(
                 wideRect.left, wideRect.top, wideRect.right, wideRect.bottom);
         mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec expectedEndSpec = getMagnificationSpec(2.0f, 0, startSpec.offsetY);
-        assertThat(getCurrentMagnificationSpec(), closeTo(expectedEndSpec));
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedEndSpec)));
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(expectedEndSpec));
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId),
+                argThat(closeTo(expectedEndSpec)));
         Mockito.reset(mMockWindowManager);
 
         // Repeat with RTL
@@ -692,50 +900,66 @@
                 wideRect.left, wideRect.top, wideRect.right, wideRect.bottom);
         mMessageCapturingHandler.sendAllMessages();
         expectedEndSpec = getMagnificationSpec(2.0f, -100, startSpec.offsetY);
-        assertThat(getCurrentMagnificationSpec(), closeTo(expectedEndSpec));
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedEndSpec)));
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(expectedEndSpec));
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId),
+                argThat(closeTo(expectedEndSpec)));
     }
 
     @Test
     public void testRequestRectOnScreen_rectTooTall_pansMinimumToGetTopOnScreen() {
-        mMagnificationController.register();
-        zoomIn2xToMiddle();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            requestRectOnScreen_rectTooTall_pansMinimumToGetTopOnScreen(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void requestRectOnScreen_rectTooTall_pansMinimumToGetTopOnScreen(int displayId) {
+        register(displayId);
+        zoomIn2xToMiddle(displayId);
         mMessageCapturingHandler.sendAllMessages();
-        MagnificationCallbacks callbacks = getMagnificationCallbacks();
-        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
         Mockito.reset(mMockWindowManager);
         Rect tallRect = new Rect(50, 0, 51, 100);
         callbacks.onRectangleOnScreenRequested(
                 tallRect.left, tallRect.top, tallRect.right, tallRect.bottom);
         mMessageCapturingHandler.sendAllMessages();
         MagnificationSpec expectedEndSpec = getMagnificationSpec(2.0f, startSpec.offsetX, 0);
-        assertThat(getCurrentMagnificationSpec(), closeTo(expectedEndSpec));
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(expectedEndSpec)));
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(expectedEndSpec));
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId),
+                argThat(closeTo(expectedEndSpec)));
     }
 
     @Test
     public void testChangeMagnification_duringAnimation_animatesToNewValue() {
-        mMagnificationController.register();
-        MagnificationSpec startSpec = getCurrentMagnificationSpec();
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            changeMagnification_duringAnimation_animatesToNewValue(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void changeMagnification_duringAnimation_animatesToNewValue(int displayId) {
+        register(displayId);
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
         float scale = 2.5f;
         PointF firstCenter = INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER;
         MagnificationSpec firstEndSpec = getMagnificationSpec(
                 scale, computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, firstCenter, scale));
 
-        assertTrue(mMagnificationController.setScaleAndCenter(scale, firstCenter.x, firstCenter.y,
-                true, SERVICE_ID_1));
+        assertTrue(mMagnificationController.setScaleAndCenter(displayId,
+                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);
-        assertThat(getCurrentMagnificationSpec(), closeTo(firstEndSpec));
+        assertEquals(firstCenter.x, mMagnificationController.getCenterX(displayId), 0.5);
+        assertEquals(firstCenter.y, mMagnificationController.getCenterY(displayId), 0.5);
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(firstEndSpec));
         verify(mMockValueAnimator, times(1)).start();
 
         // Initial value
         when(mMockValueAnimator.getAnimatedFraction()).thenReturn(0.0f);
         mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
-        verify(mMockWindowManager).setMagnificationSpec(startSpec);
-        verify(mMockAms).notifyMagnificationChanged(
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId), eq(startSpec));
+        verify(mMockAms).notifyMagnificationChanged(displayId,
                 INITIAL_MAGNIFICATION_REGION, scale, firstCenter.x, firstCenter.y);
         Mockito.reset(mMockWindowManager);
 
@@ -745,32 +969,34 @@
         mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
         MagnificationSpec intermediateSpec1 =
                 getInterpolatedMagSpec(startSpec, firstEndSpec, fraction);
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(intermediateSpec1)));
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId),
+                argThat(closeTo(intermediateSpec1)));
         Mockito.reset(mMockWindowManager);
 
         PointF newCenter = INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER;
         MagnificationSpec newEndSpec = getMagnificationSpec(
                 scale, computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, newCenter, scale));
-        assertTrue(mMagnificationController.setCenter(
+        assertTrue(mMagnificationController.setCenter(displayId,
                 newCenter.x, newCenter.y, true, SERVICE_ID_1));
         mMessageCapturingHandler.sendAllMessages();
 
         // Animation should have been restarted
         verify(mMockValueAnimator, times(2)).start();
-        verify(mMockAms).notifyMagnificationChanged(
+        verify(mMockAms).notifyMagnificationChanged(displayId,
                 INITIAL_MAGNIFICATION_REGION, scale, newCenter.x, newCenter.y);
 
         // New starting point should be where we left off
         when(mMockValueAnimator.getAnimatedFraction()).thenReturn(0.0f);
         mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(intermediateSpec1)));
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId),
+                argThat(closeTo(intermediateSpec1)));
         Mockito.reset(mMockWindowManager);
 
         // Second intermediate point
         fraction = 0.5f;
         when(mMockValueAnimator.getAnimatedFraction()).thenReturn(fraction);
         mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
-        verify(mMockWindowManager).setMagnificationSpec(
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId),
                 argThat(closeTo(getInterpolatedMagSpec(intermediateSpec1, newEndSpec, fraction))));
         Mockito.reset(mMockWindowManager);
 
@@ -778,21 +1004,54 @@
         Mockito.reset(mMockWindowManager);
         when(mMockValueAnimator.getAnimatedFraction()).thenReturn(1.0f);
         mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
-        verify(mMockWindowManager).setMagnificationSpec(argThat(closeTo(newEndSpec)));
+        verify(mMockWindowManager).setMagnificationSpec(eq(displayId),
+                argThat(closeTo(newEndSpec)));
     }
 
-    private void zoomIn2xToMiddle() {
+    private void initMockWindowManager() {
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            when(mMockWindowManager.setMagnificationCallbacks(eq(i), any())).thenReturn(true);
+        }
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
+                Object[] args = invocationOnMock.getArguments();
+                Region regionArg = (Region) args[1];
+                regionArg.set(INITIAL_MAGNIFICATION_REGION);
+                return null;
+            }
+        }).when(mMockWindowManager).getMagnificationRegion(anyInt(), (Region) anyObject());
+    }
+
+    private void resetMockWindowManager() {
+        Mockito.reset(mMockWindowManager);
+        initMockWindowManager();
+    }
+
+    private void register(int displayId) {
+        mMockValueAnimator = mock(ValueAnimator.class);
+        when(mMockControllerCtx.newValueAnimator()).thenReturn(mMockValueAnimator);
+        mMagnificationController.register(displayId);
+        ArgumentCaptor<ValueAnimator.AnimatorUpdateListener> listenerArgumentCaptor =
+                ArgumentCaptor.forClass(ValueAnimator.AnimatorUpdateListener.class);
+        verify(mMockValueAnimator).addUpdateListener(listenerArgumentCaptor.capture());
+        mTargetAnimationListener = listenerArgumentCaptor.getValue();
+        Mockito.reset(mMockValueAnimator); // Ignore other initialization
+    }
+
+    private void zoomIn2xToMiddle(int displayId) {
         PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
         float scale = 2.0f;
-        mMagnificationController.setScale(scale, startCenter.x, startCenter.y, false, SERVICE_ID_1);
-        assertTrue(mMagnificationController.isMagnifying());
+        mMagnificationController.setScale(displayId, scale, startCenter.x, startCenter.y, false,
+                SERVICE_ID_1);
+        assertTrue(mMagnificationController.isMagnifying(displayId));
     }
 
-    private MagnificationCallbacks getMagnificationCallbacks() {
+    private MagnificationCallbacks getMagnificationCallbacks(int displayId) {
         ArgumentCaptor<MagnificationCallbacks> magnificationCallbacksCaptor =
                 ArgumentCaptor.forClass(MagnificationCallbacks.class);
         verify(mMockWindowManager)
-                .setMagnificationCallbacks(magnificationCallbacksCaptor.capture());
+                .setMagnificationCallbacks(eq(displayId), magnificationCallbacksCaptor.capture());
         return magnificationCallbacksCaptor.getValue();
     }
 
@@ -823,9 +1082,10 @@
         return spec;
     }
 
-    private MagnificationSpec getCurrentMagnificationSpec() {
-        return getMagnificationSpec(mMagnificationController.getScale(),
-                mMagnificationController.getOffsetX(), mMagnificationController.getOffsetY());
+    private MagnificationSpec getCurrentMagnificationSpec(int displayId) {
+        return getMagnificationSpec(mMagnificationController.getScale(displayId),
+                mMagnificationController.getOffsetX(displayId),
+                mMagnificationController.getOffsetY(displayId));
     }
 
     private MagSpecMatcher closeTo(MagnificationSpec spec) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
index 032074a..d91ce39 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
@@ -26,16 +26,19 @@
 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.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.content.Context;
+import android.os.Handler;
 import android.os.Message;
 import android.util.DebugUtils;
 import android.view.InputDevice;
@@ -104,14 +107,9 @@
     public static final float DEFAULT_X = 301;
     public static final float DEFAULT_Y = 299;
 
+    private static final int DISPLAY_0 = 0;
+
     private Context mContext;
-    final AccessibilityManagerService mMockAms = mock(AccessibilityManagerService.class);
-    final WindowManagerInternal mMockWindowManager = mock(WindowManagerInternal.class);
-    final MessageCapturingHandler mMessageCapturingHandler =
-            new MessageCapturingHandler(null);
-    final ValueAnimator mMockValueAnimator = mock(ValueAnimator.class);
-    MagnificationController.SettingsBridge mMockSettingsBridge =
-            mock(MagnificationController.SettingsBridge.class);
     MagnificationController mMagnificationController;
 
     private OffsettableClock mClock;
@@ -123,18 +121,26 @@
     @Before
     public void setUp() {
         mContext = InstrumentationRegistry.getContext();
-        mMagnificationController = new MagnificationController(mContext, mMockAms, new Object(),
-                mMessageCapturingHandler, mMockWindowManager, mMockValueAnimator,
-                mMockSettingsBridge) {
+        final MagnificationController.ControllerContext mockController =
+                mock(MagnificationController.ControllerContext.class);
+        final WindowManagerInternal mockWindowManager = mock(WindowManagerInternal.class);
+        when(mockController.getContext()).thenReturn(mContext);
+        when(mockController.getAms()).thenReturn(mock(AccessibilityManagerService.class));
+        when(mockController.getWindowManager()).thenReturn(mockWindowManager);
+        when(mockController.getHandler()).thenReturn(new Handler(mContext.getMainLooper()));
+        when(mockController.newValueAnimator()).thenReturn(new ValueAnimator());
+        when(mockController.getAnimationDuration()).thenReturn(1000L);
+        when(mockWindowManager.setMagnificationCallbacks(eq(DISPLAY_0), any())).thenReturn(true);
+        mMagnificationController = new MagnificationController(mockController, new Object()) {
             @Override
-            public boolean magnificationRegionContains(float x, float y) {
+            public boolean magnificationRegionContains(int displayId, float x, float y) {
                 return true;
             }
 
             @Override
-            void setForceShowMagnifiableBounds(boolean show) {}
+            void setForceShowMagnifiableBounds(int displayId, boolean show) {}
         };
-        mMagnificationController.register();
+        mMagnificationController.register(DISPLAY_0);
         mClock = new OffsettableClock.Stopped();
 
         boolean detectTripleTap = true;
@@ -144,7 +150,7 @@
 
     @After
     public void tearDown() {
-        mMagnificationController.unregister();
+        mMagnificationController.unregister(DISPLAY_0);
     }
 
     @NonNull
@@ -302,6 +308,24 @@
         assertZoomsImmediatelyOnSwipeFrom(STATE_SHORTCUT_TRIGGERED);
     }
 
+    @Test
+    public void testMultiTap_outOfDistanceSlop_shouldInIdle() {
+        // All delay motion events should be sent, if multi-tap with out of distance slop.
+        // STATE_IDLE will check if tapCount() < 2.
+        allowEventDelegation();
+        assertStaysIn(STATE_IDLE, () -> {
+            tap();
+            tap(DEFAULT_X * 2, DEFAULT_Y * 2);
+        });
+        assertStaysIn(STATE_IDLE, () -> {
+            tap();
+            tap(DEFAULT_X * 2, DEFAULT_Y * 2);
+            tap();
+            tap(DEFAULT_X * 2, DEFAULT_Y * 2);
+            tap();
+        });
+    }
+
     private void assertZoomsImmediatelyOnSwipeFrom(int state) {
         goFromStateIdleTo(state);
         swipeAndHold();
@@ -509,7 +533,7 @@
     }
 
     private boolean isZoomed() {
-        return mMgh.mMagnificationController.isMagnifying();
+        return mMgh.mMagnificationController.isMagnifying(DISPLAY_0);
     }
 
     private int tapCount() {
@@ -525,6 +549,11 @@
         send(upEvent());
     }
 
+    private void tap(float x, float y) {
+        send(downEvent(x, y));
+        send(upEvent(x, y));
+    }
+
     private void swipe() {
         swipeAndHold();
         send(upEvent());
@@ -566,18 +595,26 @@
     }
 
     private MotionEvent downEvent() {
+        return downEvent(DEFAULT_X, DEFAULT_Y);
+    }
+
+    private MotionEvent downEvent(float x, float y) {
         mLastDownTime = mClock.now();
         return fromTouchscreen(MotionEvent.obtain(mLastDownTime, mLastDownTime,
-                ACTION_DOWN, DEFAULT_X, DEFAULT_Y, 0));
+                ACTION_DOWN, x, y, 0));
     }
 
     private MotionEvent upEvent() {
-        return upEvent(mLastDownTime);
+        return upEvent(DEFAULT_X, DEFAULT_Y, mLastDownTime);
     }
 
-    private MotionEvent upEvent(long downTime) {
+    private MotionEvent upEvent(float x, float y) {
+        return upEvent(x, y, mLastDownTime);
+    }
+
+    private MotionEvent upEvent(float x, float y, long downTime) {
         return fromTouchscreen(MotionEvent.obtain(downTime, mClock.now(),
-                MotionEvent.ACTION_UP, DEFAULT_X, DEFAULT_Y, 0));
+                MotionEvent.ACTION_UP, x, y, 0));
     }
 
     private MotionEvent pointerEvent(int action, float x, float y) {
diff --git a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java
new file mode 100644
index 0000000..65af677
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java
@@ -0,0 +1,497 @@
+/*
+ * 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.adb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.server.FgThread;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(JUnit4.class)
+public final class AdbDebuggingManagerTest {
+
+    private static final String TAG = "AdbDebuggingManagerTest";
+
+    // This component is passed to the AdbDebuggingManager to act as the activity that can confirm
+    // unknown adb keys.  An overlay package was first attempted to override the
+    // config_customAdbPublicKeyConfirmationComponent config, but the value from that package was
+    // not being read.
+    private static final String ADB_CONFIRM_COMPONENT =
+            "com.android.frameworks.servicestests/"
+                    + "com.android.server.adb.AdbDebuggingManagerTestActivity";
+
+    // The base64 encoding of the values 'test key 1' and 'test key 2'.
+    private static final String TEST_KEY_1 = "dGVzdCBrZXkgMQo=";
+    private static final String TEST_KEY_2 = "dGVzdCBrZXkgMgo=";
+
+    // This response is received from the AdbDebuggingHandler when the key is allowed to connect
+    private static final String RESPONSE_KEY_ALLOWED = "OK";
+    // This response is received from the AdbDebuggingHandler when the key is not allowed to connect
+    private static final String RESPONSE_KEY_DENIED = "NO";
+
+    // wait up to 5 seconds for any blocking queries
+    private static final long TIMEOUT = 5000;
+    private static final TimeUnit TIMEOUT_TIME_UNIT = TimeUnit.MILLISECONDS;
+
+    private Context mContext;
+    private AdbDebuggingManager mManager;
+    private AdbDebuggingManager.AdbDebuggingThread mThread;
+    private AdbDebuggingManager.AdbDebuggingHandler mHandler;
+    private AdbDebuggingManager.AdbKeyStore mKeyStore;
+    private BlockingQueue<TestResult> mBlockingQueue;
+    private long mOriginalAllowedConnectionTime;
+    private File mKeyFile;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+        mManager = new AdbDebuggingManager(mContext, ADB_CONFIRM_COMPONENT);
+        mKeyFile = new File(mContext.getFilesDir(), "test_adb_keys.xml");
+        if (mKeyFile.exists()) {
+            mKeyFile.delete();
+        }
+        mThread = new AdbDebuggingThreadTest();
+        mKeyStore = mManager.new AdbKeyStore(mKeyFile);
+        mHandler = mManager.new AdbDebuggingHandler(FgThread.get().getLooper(), mThread, mKeyStore);
+        mOriginalAllowedConnectionTime = mKeyStore.getAllowedConnectionTime();
+        mBlockingQueue = new ArrayBlockingQueue<>(1);
+
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mKeyStore.deleteKeyStore();
+        setAllowedConnectionTime(mOriginalAllowedConnectionTime);
+    }
+
+    /**
+     * Sets the allowed connection time within which a subsequent connection from a key for which
+     * the user selected the 'Always allow' option will be allowed without user interaction.
+     */
+    private void setAllowedConnectionTime(long connectionTime) {
+        Settings.Global.putLong(mContext.getContentResolver(),
+                Settings.Global.ADB_ALLOWED_CONNECTION_TIME, connectionTime);
+    };
+
+    @Test
+    public void testAllowNewKeyOnce() throws Exception {
+        // Verifies the behavior when a new key first attempts to connect to a device. During the
+        // first connection the ADB confirmation activity should be launched to prompt the user to
+        // allow the connection with an option to always allow connections from this key.
+
+        // Verify if the user allows the key but does not select the option to 'always
+        // allow' that the connection is allowed but the key is not stored.
+        runAdbTest(TEST_KEY_1, true, false, false);
+    }
+
+    @Test
+    public void testDenyNewKey() throws Exception {
+        // Verifies if the user does not allow the key then the connection is not allowed and the
+        // key is not stored.
+        runAdbTest(TEST_KEY_1, false, false, false);
+    }
+
+    @Test
+    public void testDisconnectAlwaysAllowKey() throws Exception {
+        // When a key is disconnected from a device ADB should send a disconnect message; this
+        // message should trigger an update of the last connection time for the currently connected
+        // key.
+
+        // Allow a connection from a new key with the 'Always allow' option selected.
+        runAdbTest(TEST_KEY_1, true, true, false);
+
+        // Get the last connection time for the currently connected key to verify that it is updated
+        // after the disconnect.
+        long lastConnectionTime = mKeyStore.getLastConnectionTime(TEST_KEY_1);
+
+        // Sleep for a small amount of time to ensure a difference can be observed in the last
+        // connection time after a disconnect.
+        Thread.sleep(10);
+
+        // Send the disconnect message for the currently connected key to trigger an update of the
+        // last connection time.
+        mHandler.obtainMessage(
+                AdbDebuggingManager.AdbDebuggingHandler.MESSAGE_ADB_DISCONNECT).sendToTarget();
+
+        // Use a latch to ensure the test does not exit untill the Runnable has been processed.
+        CountDownLatch latch = new CountDownLatch(1);
+
+        // Post a new Runnable to the handler to ensure it runs after the disconnect message is
+        // processed.
+        mHandler.post(() -> {
+            assertNotEquals(
+                    "The last connection time was not updated after the disconnect",
+                    lastConnectionTime,
+                    mKeyStore.getLastConnectionTime(TEST_KEY_1));
+            latch.countDown();
+        });
+        if (!latch.await(TIMEOUT, TIMEOUT_TIME_UNIT)) {
+            fail("The Runnable to verify the last connection time was updated did not complete "
+                    + "within the timeout period");
+        }
+    }
+
+    @Test
+    public void testDisconnectAllowedOnceKey() throws Exception {
+        // When a key is disconnected ADB should send a disconnect message; this message should
+        // essentially result in a noop for keys that the user only allows once since the last
+        // connection time is not maintained for these keys.
+
+        // Allow a connection from a new key with the 'Always allow' option set to false
+        runAdbTest(TEST_KEY_1, true, false, false);
+
+        // Send the disconnect message for the currently connected key.
+        mHandler.obtainMessage(
+                AdbDebuggingManager.AdbDebuggingHandler.MESSAGE_ADB_DISCONNECT).sendToTarget();
+
+        // Verify that the disconnected key is not automatically allowed on a subsequent connection.
+        runAdbTest(TEST_KEY_1, true, false, false);
+    }
+
+    @Test
+    public void testAlwaysAllowConnectionFromKey() throws Exception {
+        // Verifies when the user selects the 'Always allow' option for the current key that
+        // subsequent connection attempts from that key are allowed.
+
+        // Allow a connection from a new key with the 'Always allow' option selected.
+        runAdbTest(TEST_KEY_1, true, true, false);
+
+        // Next attempt another connection with the same key and verify that the activity to prompt
+        // the user to accept the key is not launched.
+        runAdbTest(TEST_KEY_1, true, true, true);
+
+        // Verify that a different key is not automatically allowed.
+        runAdbTest(TEST_KEY_2, false, false, false);
+    }
+
+    @Test
+    public void testOriginalAlwaysAllowBehavior() throws Exception {
+        // If the Settings.Global.ADB_ALLOWED_CONNECTION_TIME setting is set to 0 then the original
+        // behavior of 'Always allow' should be restored.
+
+        // Accept the test key with the 'Always allow' option selected.
+        runAdbTest(TEST_KEY_1, true, true, false);
+
+        // Set the connection time to 0 to restore the original behavior.
+        setAllowedConnectionTime(0);
+
+        // Set the last connection time to the test key to a very small value to ensure it would
+        // fail the new test but would be allowed with the original behavior.
+        mKeyStore.setLastConnectionTime(TEST_KEY_1, 1);
+
+        // Run the test with the key and verify that the connection is automatically allowed.
+        runAdbTest(TEST_KEY_1, true, true, true);
+    }
+
+    @Test
+    public void testLastConnectionTimeUpdatedByScheduledJob() throws Exception {
+        // If a development device is left connected to a system beyond the allowed connection time
+        // a reboot of the device while connected could make it appear as though the last connection
+        // time is beyond the allowed window. A scheduled job runs daily while a key is connected
+        // to update the last connection time to the current time; this ensures if the device is
+        // rebooted while connected to a system the last connection time should be within 24 hours.
+
+        // Allow the key to connect with the 'Always allow' option selected
+        runAdbTest(TEST_KEY_1, true, true, false);
+
+        // Get the current last connection time for comparison after the scheduled job is run
+        long lastConnectionTime = mKeyStore.getLastConnectionTime(TEST_KEY_1);
+
+        // Sleep a small amount of time to ensure that the updated connection time changes
+        Thread.sleep(10);
+
+        // Send a message to the handler to update the last connection time for the active key
+        mHandler.obtainMessage(
+                AdbDebuggingManager.AdbDebuggingHandler.MESSAGE_ADB_UPDATE_KEY_CONNECTION_TIME)
+                .sendToTarget();
+
+        // Post a Runnable to the handler to ensure it runs after the update key connection time
+        // message is processed.
+        CountDownLatch latch = new CountDownLatch(1);
+        mHandler.post(() -> {
+            assertNotEquals(
+                    "The last connection time of the key was not updated after the update key "
+                            + "connection time message",
+                    lastConnectionTime, mKeyStore.getLastConnectionTime(TEST_KEY_1));
+            latch.countDown();
+        });
+        if (!latch.await(TIMEOUT, TIMEOUT_TIME_UNIT)) {
+            fail("The Runnable to verify the last connection time was updated did not complete "
+                    + "within the timeout period");
+        }
+    }
+
+    @Test
+    public void testKeystorePersisted() throws Exception {
+        // After any updates are made to the key store a message should be sent to persist the
+        // key store. This test verifies that a key that is always allowed is persisted in the key
+        // store along with its last connection time.
+
+        // Allow the key to connect with the 'Always allow' option selected
+        runAdbTest(TEST_KEY_1, true, true, false);
+
+        // Send a message to the handler to persist the updated keystore.
+        mHandler.obtainMessage(
+                AdbDebuggingManager.AdbDebuggingHandler.MESSAGE_ADB_PERSIST_KEY_STORE)
+                .sendToTarget();
+
+        // Post a Runnable to the handler to ensure the persist key store message has been processed
+        // using a new AdbKeyStore backed by the key file.
+        mHandler.post(() -> assertTrue(
+                "The key with the 'Always allow' option selected was not persisted in the keystore",
+                mManager.new AdbKeyStore(mKeyFile).isKeyAuthorized(TEST_KEY_1)));
+
+        // Get the current last connection time to ensure it is updated in the persisted keystore.
+        long lastConnectionTime = mKeyStore.getLastConnectionTime(TEST_KEY_1);
+
+        // Sleep a small amount of time to ensure the last connection time is updated.
+        Thread.sleep(10);
+
+        // Send a message to the handler to update the last connection time for the active key.
+        mHandler.obtainMessage(
+                AdbDebuggingManager.AdbDebuggingHandler.MESSAGE_ADB_UPDATE_KEY_CONNECTION_TIME)
+                .sendToTarget();
+
+        // Persist the updated last connection time.
+        mHandler.obtainMessage(
+                AdbDebuggingManager.AdbDebuggingHandler.MESSAGE_ADB_PERSIST_KEY_STORE)
+                .sendToTarget();
+
+        // Post a Runnable with a new key store backed by the key file to verify that the last
+        // connection time obtained above is different from the persisted updated value.
+        CountDownLatch latch = new CountDownLatch(1);
+        mHandler.post(() -> {
+            assertNotEquals(
+                    "The last connection time in the key file was not updated after the update "
+                            + "connection time message", lastConnectionTime,
+                    mManager.new AdbKeyStore(mKeyFile).getLastConnectionTime(TEST_KEY_1));
+            latch.countDown();
+        });
+        if (!latch.await(TIMEOUT, TIMEOUT_TIME_UNIT)) {
+            fail("The Runnable to verify the last connection time was updated did not complete "
+                    + "within the timeout period");
+        }
+    }
+
+    @Test
+    public void testAdbClearRemovesActiveKey() throws Exception {
+        // If the user selects the option to 'Revoke USB debugging authorizations' while an 'Always
+        // allow' key is connected that key should be deleted as well.
+
+        // Allow the key to connect with the 'Always allow' option selected
+        runAdbTest(TEST_KEY_1, true, true, false);
+
+        // Send a message to the handler to clear the adb authorizations.
+        mHandler.obtainMessage(
+                AdbDebuggingManager.AdbDebuggingHandler.MESSAGE_ADB_CLEAR).sendToTarget();
+
+        // Send a message to disconnect the currently connected key
+        mHandler.obtainMessage(
+                AdbDebuggingManager.AdbDebuggingHandler.MESSAGE_ADB_DISCONNECT).sendToTarget();
+
+        // Post a Runnable to ensure the disconnect has completed to verify the 'Always allow' key
+        // that was connected when the clear was sent requires authorization.
+        CountDownLatch latch = new CountDownLatch(1);
+        mHandler.post(() -> {
+            assertFalse(
+                    "The currently connected 'always allow' key should not be authorized after an"
+                            + " adb"
+                            + " clear message.",
+                    mKeyStore.isKeyAuthorized(TEST_KEY_1));
+            latch.countDown();
+        });
+        if (!latch.await(TIMEOUT, TIMEOUT_TIME_UNIT)) {
+            fail("The Runnable to verify the key is not authorized did not complete within the "
+                    + "timeout period");
+        }
+    }
+
+    @Test
+    public void testAdbGrantRevokedIfLastConnectionBeyondAllowedTime() throws Exception {
+        // If the user selects the 'Always allow' option then subsequent connections from the key
+        // will be allowed as long as the connection is within the allowed window. Once the last
+        // connection time is beyond this window the user should be prompted to allow the key again.
+
+        // Allow the key to connect with the 'Always allow' option selected
+        runAdbTest(TEST_KEY_1, true, true, false);
+
+        // Set the allowed window to a small value to ensure the time is beyond the allowed window.
+        setAllowedConnectionTime(1);
+
+        // Sleep for a small amount of time to exceed the allowed window.
+        Thread.sleep(10);
+
+        // A new connection from this key should prompt the user again.
+        runAdbTest(TEST_KEY_1, true, true, false);
+    }
+
+    @Test
+    public void testLastConnectionTimeCannotBeSetBack() throws Exception {
+        // When a device is first booted there is a possibility that the system time will be set to
+        // the build time of the system image. If a device is connected to a system during a reboot
+        // this could cause the connection time to be set in the past; if the device time is not
+        // corrected before the device is disconnected then a subsequent connection with the time
+        // corrected would appear as though the last connection time was beyond the allowed window,
+        // and the user would be required to authorize the connection again. This test verifies that
+        // the AdbKeyStore does not update the last connection time if it is less than the
+        // previously written connection time.
+
+        // Allow the key to connect with the 'Always allow' option selected
+        runAdbTest(TEST_KEY_1, true, true, false);
+
+        // Get the last connection time that was written to the key store.
+        long lastConnectionTime = mKeyStore.getLastConnectionTime(TEST_KEY_1);
+
+        // Attempt to set the last connection time to 1970
+        mKeyStore.setLastConnectionTime(TEST_KEY_1, 0);
+        assertEquals(
+                "The last connection time in the adb key store should not be set to a value less "
+                        + "than the previous connection time",
+                lastConnectionTime, mKeyStore.getLastConnectionTime(TEST_KEY_1));
+
+        // Attempt to set the last connection time just beyond the allowed window.
+        mKeyStore.setLastConnectionTime(TEST_KEY_1,
+                Math.max(0, lastConnectionTime - (mKeyStore.getAllowedConnectionTime() + 1)));
+        assertEquals(
+                "The last connection time in the adb key store should not be set to a value less "
+                        + "than the previous connection time",
+                lastConnectionTime, mKeyStore.getLastConnectionTime(TEST_KEY_1));
+    }
+
+    /**
+     * Runs an adb test with the provided configuration.
+     *
+     * @param key The base64 encoding of the key to be used during the test.
+     * @param allowKey boolean indicating whether the key should be allowed to connect.
+     * @param alwaysAllow boolean indicating whether the 'Always allow' option should be selected.
+     * @param autoAllowExpected boolean indicating whether the key is expected to be automatically
+     *                          allowed without user interaction.
+     */
+    private void runAdbTest(String key, boolean allowKey, boolean alwaysAllow,
+            boolean autoAllowExpected) throws Exception {
+        // if the key should not be automatically allowed then set up the activity
+        if (!autoAllowExpected) {
+            new AdbDebuggingManagerTestActivity.Configurator()
+                    .setExpectedKey(key)
+                    .setAllowKey(allowKey)
+                    .setAlwaysAllow(alwaysAllow)
+                    .setHandler(mHandler)
+                    .setBlockingQueue(mBlockingQueue);
+        }
+        // send the message indicating a new key is attempting to connect
+        mHandler.obtainMessage(AdbDebuggingManager.AdbDebuggingHandler.MESSAGE_ADB_CONFIRM,
+                key).sendToTarget();
+        // if the key should not be automatically allowed then the ADB public key confirmation
+        // activity should be launched
+        if (!autoAllowExpected) {
+            TestResult activityResult = mBlockingQueue.poll(TIMEOUT, TIMEOUT_TIME_UNIT);
+            assertNotNull(
+                    "The ADB public key confirmation activity did not complete within the timeout"
+                            + " period", activityResult);
+            assertEquals("The ADB public key activity failed with result: " + activityResult,
+                    TestResult.RESULT_ACTIVITY_LAUNCHED, activityResult.mReturnCode);
+        }
+        // If the activity was launched it should send a response back to the manager that would
+        // trigger a response to the thread, or if the key is a known valid key then a response
+        // should be sent back without requiring interaction with the activity.
+        TestResult threadResult = mBlockingQueue.poll(TIMEOUT, TIMEOUT_TIME_UNIT);
+        assertNotNull("A response was not sent to the thread within the timeout period",
+                threadResult);
+        // verify that the result is an expected message from the thread
+        assertEquals("An unexpected result was received: " + threadResult,
+                TestResult.RESULT_RESPONSE_RECEIVED, threadResult.mReturnCode);
+        assertEquals("The manager did not send the proper response for allowKey = " + allowKey,
+                allowKey ? RESPONSE_KEY_ALLOWED : RESPONSE_KEY_DENIED, threadResult.mMessage);
+        // if the key is not allowed or not always allowed verify it is not in the key store
+        if (!allowKey || !alwaysAllow) {
+            assertFalse(
+                    "The key should not be allowed automatically on subsequent connection attempts",
+                    mKeyStore.isKeyAuthorized(key));
+        }
+    }
+
+    /**
+     * Helper class that extends AdbDebuggingThread to receive the response from AdbDebuggingManager
+     * indicating whether the key should be allowed to  connect.
+     */
+    class AdbDebuggingThreadTest extends AdbDebuggingManager.AdbDebuggingThread {
+        AdbDebuggingThreadTest() {
+            mManager.super();
+        }
+
+        @Override
+        public void sendResponse(String msg) {
+            TestResult result = new TestResult(TestResult.RESULT_RESPONSE_RECEIVED, msg);
+            try {
+                mBlockingQueue.put(result);
+            } catch (InterruptedException e) {
+                Log.e(TAG,
+                        "Caught an InterruptedException putting the result in the queue: " + result,
+                        e);
+            }
+        }
+    }
+
+    /**
+     * Contains the result for the current portion of the test along with any corresponding
+     * messages.
+     */
+    public static class TestResult {
+        public int mReturnCode;
+        public String mMessage;
+
+        public static final int RESULT_ACTIVITY_LAUNCHED = 1;
+        public static final int RESULT_UNEXPECTED_KEY = 2;
+        public static final int RESULT_RESPONSE_RECEIVED = 3;
+
+        public TestResult(int returnCode) {
+            this(returnCode, null);
+        }
+
+        public TestResult(int returnCode, String message) {
+            mReturnCode = returnCode;
+            mMessage = message;
+        }
+
+        @Override
+        public String toString() {
+            return "{mReturnCode = " + mReturnCode + ", mMessage = " + mMessage + "}";
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTestActivity.java b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTestActivity.java
new file mode 100644
index 0000000..1a9c180
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTestActivity.java
@@ -0,0 +1,142 @@
+/*
+ * 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.adb;
+
+import static com.android.server.adb.AdbDebuggingManagerTest.TestResult;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Message;
+import android.util.Log;
+
+import java.util.concurrent.BlockingQueue;
+
+/**
+ * Helper Activity used to test the AdbDebuggingManager's prompt to allow an adb key.
+ */
+public class AdbDebuggingManagerTestActivity extends Activity {
+
+    private static final String TAG = "AdbDebuggingManagerTestActivity";
+
+    /*
+     * Static values that must be set before each test to modify the behavior of the Activity.
+     */
+    private static AdbDebuggingManager.AdbDebuggingHandler sHandler;
+    private static boolean sAllowKey;
+    private static boolean sAlwaysAllow;
+    private static String sExpectedKey;
+    private static BlockingQueue sBlockingQueue;
+
+    /**
+     * Receives the Intent sent from the AdbDebuggingManager and sends the preconfigured response.
+     */
+    @Override
+    public void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+        Intent intent = getIntent();
+        String key = intent.getStringExtra("key");
+        if (!key.equals(sExpectedKey)) {
+            TestResult result = new TestResult(TestResult.RESULT_UNEXPECTED_KEY, key);
+            postResult(result);
+            finish();
+            return;
+        }
+        // Post the result that the activity was successfully launched as expected and a response
+        // is being sent to let the test method know that it should move on to waiting for the next
+        // expected response from the AdbDebuggingManager.
+        TestResult result = new TestResult(
+                AdbDebuggingManagerTest.TestResult.RESULT_ACTIVITY_LAUNCHED);
+        postResult(result);
+
+        // Initialize the message based on the preconfigured values. If the key is accepted the
+        // AdbDebuggingManager expects the key to be in the obj field of the message, and if the
+        // user selects the 'Always allow' option the manager expects the arg1 field to be set to 1.
+        int messageType;
+        if (sAllowKey) {
+            messageType = AdbDebuggingManager.AdbDebuggingHandler.MESSAGE_ADB_ALLOW;
+        } else {
+            messageType = AdbDebuggingManager.AdbDebuggingHandler.MESSAGE_ADB_DENY;
+        }
+        Message message = sHandler.obtainMessage(messageType);
+        message.obj = key;
+        if (sAlwaysAllow) {
+            message.arg1 = 1;
+        }
+        finish();
+        sHandler.sendMessage(message);
+    }
+
+    /**
+     * Posts the result of the activity to the test method.
+     */
+    private void postResult(TestResult result) {
+        try {
+            sBlockingQueue.put(result);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Caught an InterruptedException posting the result " + result, e);
+        }
+    }
+
+    /**
+     * Allows test methods to specify the behavior of the Activity before it is invoked by the
+     * AdbDebuggingManager.
+     */
+    public static class Configurator {
+
+        /**
+         * Sets the test handler to be used by this activity to send the configured response.
+         */
+        public Configurator setHandler(AdbDebuggingManager.AdbDebuggingHandler handler) {
+            sHandler = handler;
+            return this;
+        }
+
+        /**
+         * Sets whether the key should be allowed for this test.
+         */
+        public Configurator setAllowKey(boolean allow) {
+            sAllowKey = allow;
+            return this;
+        }
+
+        /**
+         * Sets whether the 'Always allow' option should be selected for this test.
+         */
+        public Configurator setAlwaysAllow(boolean alwaysAllow) {
+            sAlwaysAllow = alwaysAllow;
+            return this;
+        }
+
+        /**
+         * Sets the key that should be expected from the AdbDebuggingManager for this test.
+         */
+        public Configurator setExpectedKey(String expectedKey) {
+            sExpectedKey = expectedKey;
+            return this;
+        }
+
+        /**
+         * Sets the BlockingQueue that should be used to post the result of the Activity back to the
+         * test method.
+         */
+        public Configurator setBlockingQueue(BlockingQueue blockingQueue) {
+            sBlockingQueue = blockingQueue;
+            return this;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
index e4fe599..00a60b9 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java
@@ -117,7 +117,7 @@
         thread2.assertWaiting("Unexpected state for " + record2);
         thread2.interrupt();
 
-        mAms.mActiveUids.clear();
+        mAms.mProcessList.mActiveUids.clear();
     }
 
     private UidRecord addActiveUidRecord(int uid, long curProcStateSeq,
@@ -126,7 +126,7 @@
         record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq;
         record.curProcStateSeq = curProcStateSeq;
         record.waitingForNetwork = true;
-        mAms.mActiveUids.put(uid, record);
+        mAms.mProcessList.mActiveUids.put(uid, record);
         return record;
     }
 
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 767eb60..419c736 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -29,6 +29,8 @@
 import static android.app.ActivityManager.PROCESS_STATE_TOP;
 import static android.util.DebugUtils.valueToString;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static com.android.server.am.ActivityManagerInternalTest.CustomThread;
 import static com.android.server.am.ActivityManagerService.DISPATCH_UIDS_CHANGED_UI_MSG;
 import static com.android.server.am.ActivityManagerService.Injector;
@@ -68,7 +70,10 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
+import com.android.server.am.ProcessList.IsolatedUidRange;
+import com.android.server.am.ProcessList.IsolatedUidRangeAllocator;
+import com.android.server.wm.ActivityTaskManagerService;
 
 import org.junit.After;
 import org.junit.Before;
@@ -109,7 +114,7 @@
         UidRecord.CHANGE_ACTIVE
     };
 
-    @Mock private Context mContext;
+    private Context mContext = getInstrumentation().getTargetContext();
     @Mock private AppOpsService mAppOpsService;
     @Mock private PackageManager mPackageManager;
 
@@ -128,8 +133,8 @@
         mInjector = new TestInjector();
         mAms = new ActivityManagerService(mInjector);
         mAms.mWaitForNetworkTimeoutMs = 2000;
-
-        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        mAms.mActivityTaskManager = new ActivityTaskManagerService(mContext);
+        mAms.mActivityTaskManager.initialize(null, null, mHandler.getLooper());
     }
 
     @After
@@ -248,7 +253,7 @@
         final UidRecord uidRec = new UidRecord(uid, null /* atmInternal */);
         uidRec.waitingForNetwork = true;
         uidRec.hasInternetPermission = true;
-        mAms.mActiveUids.put(uid, uidRec);
+        mAms.mProcessList.mActiveUids.put(uid, uidRec);
 
         final ProcessRecord appRec = new ProcessRecord(mAms, new ApplicationInfo(), TAG, uid);
         appRec.thread = Mockito.mock(IApplicationThread.class);
@@ -291,6 +296,113 @@
         }
     }
 
+    private void validateAppZygoteIsolatedUidRange(IsolatedUidRange uidRange) {
+        assertNotNull(uidRange);
+        assertTrue(uidRange.mFirstUid >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID
+                && uidRange.mFirstUid <= Process.LAST_APP_ZYGOTE_ISOLATED_UID);
+        assertTrue(uidRange.mLastUid >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID
+                && uidRange.mLastUid <= Process.LAST_APP_ZYGOTE_ISOLATED_UID);
+        assertTrue(uidRange.mLastUid > uidRange.mFirstUid
+                && ((uidRange.mLastUid - uidRange.mFirstUid + 1)
+                     == Process.NUM_UIDS_PER_APP_ZYGOTE));
+    }
+
+    private void verifyUidRangesNoOverlap(IsolatedUidRange uidRange1, IsolatedUidRange uidRange2) {
+        IsolatedUidRange lowRange = uidRange1.mFirstUid <= uidRange2.mFirstUid ? uidRange1 : uidRange2;
+        IsolatedUidRange highRange = lowRange == uidRange1  ? uidRange2 : uidRange1;
+
+        assertTrue(highRange.mFirstUid > lowRange.mLastUid);
+    }
+
+    @Test
+    public void testIsolatedUidRangeAllocator() {
+        final IsolatedUidRangeAllocator allocator = mAms.mProcessList.mAppIsolatedUidRangeAllocator;
+
+        // Create initial range
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.processName = "com.android.test.app";
+        appInfo.uid = 10000;
+        final IsolatedUidRange range = allocator.getOrCreateIsolatedUidRangeLocked(appInfo);
+        validateAppZygoteIsolatedUidRange(range);
+        verifyIsolatedUidAllocator(range);
+
+        // Create a second range
+        ApplicationInfo appInfo2 = new ApplicationInfo();
+        appInfo2.processName = "com.android.test.app2";
+        appInfo2.uid = 10001;
+        IsolatedUidRange range2 = allocator.getOrCreateIsolatedUidRangeLocked(appInfo2);
+        validateAppZygoteIsolatedUidRange(range2);
+        verifyIsolatedUidAllocator(range2);
+
+        // Verify ranges don't overlap
+        verifyUidRangesNoOverlap(range, range2);
+
+        // Free range, reallocate and verify
+        allocator.freeUidRangeLocked(appInfo2);
+        range2 = allocator.getOrCreateIsolatedUidRangeLocked(appInfo2);
+        validateAppZygoteIsolatedUidRange(range2);
+        verifyUidRangesNoOverlap(range, range2);
+        verifyIsolatedUidAllocator(range2);
+
+        // Free both, then try to allocate the maximum number of UID ranges
+        allocator.freeUidRangeLocked(appInfo);
+        allocator.freeUidRangeLocked(appInfo2);
+
+        int maxNumUidRanges = (Process.LAST_APP_ZYGOTE_ISOLATED_UID
+                - Process.FIRST_APP_ZYGOTE_ISOLATED_UID + 1) / Process.NUM_UIDS_PER_APP_ZYGOTE;
+        for (int i = 0; i < maxNumUidRanges; i++) {
+            appInfo = new ApplicationInfo();
+            appInfo.uid = 10000 + i;
+            appInfo.processName = "com.android.test.app" + Integer.toString(i);
+            IsolatedUidRange uidRange = allocator.getOrCreateIsolatedUidRangeLocked(appInfo);
+            validateAppZygoteIsolatedUidRange(uidRange);
+            verifyIsolatedUidAllocator(uidRange);
+        }
+
+        // Try to allocate another one and make sure it fails
+        appInfo = new ApplicationInfo();
+        appInfo.uid = 9000;
+        appInfo.processName = "com.android.test.app.failed";
+        IsolatedUidRange failedRange = allocator.getOrCreateIsolatedUidRangeLocked(appInfo);
+
+        assertNull(failedRange);
+    }
+
+    public void verifyIsolatedUid(ProcessList.IsolatedUidRange range, int uid) {
+        assertTrue(uid >= range.mFirstUid && uid <= range.mLastUid);
+    }
+
+    public void verifyIsolatedUidAllocator(ProcessList.IsolatedUidRange range) {
+        int uid = range.allocateIsolatedUidLocked(0);
+        verifyIsolatedUid(range, uid);
+
+        int uid2 = range.allocateIsolatedUidLocked(0);
+        verifyIsolatedUid(range, uid2);
+        assertTrue(uid2 != uid);
+
+        // Free both
+        range.freeIsolatedUidLocked(uid);
+        range.freeIsolatedUidLocked(uid2);
+
+        // Allocate the entire range
+        for (int i = 0; i < (range.mLastUid - range.mFirstUid + 1); ++i) {
+            uid = range.allocateIsolatedUidLocked(0);
+            verifyIsolatedUid(range, uid);
+        }
+
+        // Ensure the next one fails
+        uid = range.allocateIsolatedUidLocked(0);
+        assertEquals(uid, -1);
+    }
+
+    @Test
+    public void testGlobalIsolatedUidAllocator() {
+        final IsolatedUidRange globalUidRange = mAms.mProcessList.mGlobalIsolatedUids;
+        assertEquals(globalUidRange.mFirstUid, Process.FIRST_ISOLATED_UID);
+        assertEquals(globalUidRange.mLastUid, Process.LAST_ISOLATED_UID);
+        verifyIsolatedUidAllocator(globalUidRange);
+    }
+
     @Test
     public void testBlockStateForUid() {
         final UidRecord uidRec = new UidRecord(TEST_UID, null /* atmInternal */);
@@ -603,7 +715,8 @@
 
         // Verify that when uid state changes to CHANGE_GONE or CHANGE_GONE_IDLE, then it
         // will be removed from validateUids.
-        assertNotEquals("validateUids should not be empty", 0, mAms.mValidateUids.size());
+        assertNotEquals("validateUids should not be empty", 0,
+                mAms.mValidateUids.size());
         for (int i = 0; i < pendingItemsForUids.size(); ++i) {
             final UidRecord.ChangeItem item = pendingItemsForUids.get(i);
             // Assign CHANGE_GONE_IDLE to some items and CHANGE_GONE to the others, using even/odd
@@ -741,7 +854,7 @@
         record.curProcStateSeq = curProcStateSeq;
         record.lastDispatchedProcStateSeq = lastDispatchedProcStateSeq;
         record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq;
-        mAms.mActiveUids.put(Process.myUid(), record);
+        mAms.mProcessList.mActiveUids.put(Process.myUid(), record);
 
         CustomThread thread = new CustomThread(record.networkStateLock, new Runnable() {
             @Override
@@ -764,7 +877,7 @@
             thread.assertTerminated(errMsg);
         }
 
-        mAms.mActiveUids.clear();
+        mAms.mProcessList.mActiveUids.clear();
     }
 
     private static class TestHandler extends Handler {
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 05cb48b..1dfce51 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
@@ -25,7 +25,8 @@
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
+import com.android.server.wm.ActivityTaskManagerService;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -62,13 +63,15 @@
                 return false;
             }
         });
+        mService.mActivityTaskManager = new ActivityTaskManagerService(mContext);
+        mService.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
     }
 
     @Test
     @UiThreadTest
     public void testCreateWorks() {
         AppErrorDialog.Data data = new AppErrorDialog.Data();
-        data.proc = new ProcessRecord(null, mContext.getApplicationInfo(), "name", 12345);
+        data.proc = new ProcessRecord(mService, mContext.getApplicationInfo(), "name", 12345);
         data.result = new AppErrorResult();
 
         AppErrorDialog dialog = new AppErrorDialog(mContext, mService, data);
diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
index 0889265..d4bb636 100644
--- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -193,6 +193,7 @@
                 false /* serialized */,
                 false /* sticky */,
                 false /* initialSticky */,
-                userId);
+                userId,
+                false /* allowBackgroundActivityStarts */);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
index 9626990..cbdc6c3 100644
--- a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
@@ -34,7 +34,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.AppOpsService;
+import com.android.server.appop.AppOpsService;
 
 import org.junit.AfterClass;
 import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
new file mode 100644
index 0000000..65c5781
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsActiveWatcherTest.java
@@ -0,0 +1,158 @@
+/*
+ * 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.appop;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.OnOpActiveChangedListener;
+import android.content.Context;
+import android.os.Process;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+/**
+ * Tests app ops version upgrades
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppOpsActiveWatcherTest {
+
+    private static final long NOTIFICATION_TIMEOUT_MILLIS = 5000;
+
+    @Test
+    public void testWatchActiveOps() {
+        // Create a mock listener
+        final OnOpActiveChangedListener listener = mock(OnOpActiveChangedListener.class);
+
+        // Start watching active ops
+        final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+        appOpsManager.startWatchingActive(new int[] {AppOpsManager.OP_CAMERA,
+                AppOpsManager.OP_RECORD_AUDIO}, listener);
+
+        // Start the op
+        appOpsManager.startOp(AppOpsManager.OP_CAMERA);
+
+        // Verify that we got called for the op being active
+        verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
+                .times(1)).onOpActiveChanged(eq(AppOpsManager.OP_CAMERA),
+                eq(Process.myUid()), eq(getContext().getPackageName()), eq(true));
+
+        // This should be the only callback we got
+        verifyNoMoreInteractions(listener);
+
+        // Start with a clean slate
+        reset(listener);
+
+        // Verify that the op is active
+        assertThat(appOpsManager.isOperationActive(AppOpsManager.OP_CAMERA,
+                Process.myUid(), getContext().getPackageName())).isTrue();
+
+        // Finish the op
+        appOpsManager.finishOp(AppOpsManager.OP_CAMERA);
+
+        // Verify that we got called for the op being active
+        verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
+                .times(1)).onOpActiveChanged(eq(AppOpsManager.OP_CAMERA),
+                eq(Process.myUid()), eq(getContext().getPackageName()), eq(false));
+
+        // Verify that the op is not active
+        assertThat(appOpsManager.isOperationActive(AppOpsManager.OP_CAMERA,
+                Process.myUid(), getContext().getPackageName())).isFalse();
+
+        // This should be the only callback we got
+        verifyNoMoreInteractions(listener);
+
+        // Start with a clean slate
+        reset(listener);
+
+        // Stop watching active ops
+        appOpsManager.stopWatchingActive(listener);
+
+        // Start the op
+        appOpsManager.startOp(AppOpsManager.OP_CAMERA);
+
+        // We should not be getting any callbacks
+        verifyNoMoreInteractions(listener);
+
+        // Finish the op
+        appOpsManager.finishOp(AppOpsManager.OP_CAMERA);
+
+        // We should not be getting any callbacks
+        verifyNoMoreInteractions(listener);
+    }
+
+    @Test
+    public void testIsRunning() throws Exception {
+        final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+        // Start the op
+        appOpsManager.startOp(AppOpsManager.OP_CAMERA);
+
+        assertTrue("Camera should be running", isCameraOn(appOpsManager));
+
+        // Finish the op
+        appOpsManager.finishOp(AppOpsManager.OP_CAMERA);
+
+        assertFalse("Camera should not be running", isCameraOn(appOpsManager));
+    }
+
+    private boolean isCameraOn(AppOpsManager appOpsManager) {
+        List<AppOpsManager.PackageOps> packages
+                = appOpsManager.getPackagesForOps(new int[] {AppOpsManager.OP_CAMERA});
+        // AppOpsManager can return null when there is no requested data.
+        if (packages != null) {
+            final int numPackages = packages.size();
+            for (int packageInd = 0; packageInd < numPackages; packageInd++) {
+                AppOpsManager.PackageOps packageOp = packages.get(packageInd);
+                List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
+                if (opEntries != null) {
+                    final int numOps = opEntries.size();
+                    for (int opInd = 0; opInd < numOps; opInd++) {
+                        AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
+                        if (opEntry.getOp() == AppOpsManager.OP_CAMERA) {
+                            if (opEntry.isRunning()) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private static Context getContext() {
+        return InstrumentationRegistry.getContext();
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsNotedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/appops/AppOpsNotedWatcherTest.java
rename to services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java
new file mode 100644
index 0000000..36f84d0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -0,0 +1,257 @@
+/*
+ * 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.appop;
+
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_ERRORED;
+import static android.app.AppOpsManager.OP_COARSE_LOCATION;
+import static android.app.AppOpsManager.OP_READ_SMS;
+import static android.app.AppOpsManager.OP_WIFI_SCAN;
+import static android.app.AppOpsManager.OP_WRITE_SMS;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.AppOpsManager.OpEntry;
+import android.app.AppOpsManager.PackageOps;
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.appop.AppOpsService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Unit tests for AppOpsService. Covers functionality that is difficult to test using CTS tests
+ * or for which we can write more detailed unit tests than CTS tests (because the internal APIs are
+ * more finegrained data than the public ones).
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppOpsServiceTest {
+
+    private static final String TAG = AppOpsServiceTest.class.getSimpleName();
+    // State will be persisted into this XML file.
+    private static final String APP_OPS_FILENAME = "appops-service-test.xml";
+
+    private File mAppOpsFile;
+    private Context mContext;
+    private Handler mHandler;
+    private AppOpsService mAppOpsService;
+    private String mMyPackageName;
+    private int mMyUid;
+    private long mTestStartMillis;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mAppOpsFile = new File(mContext.getFilesDir(), APP_OPS_FILENAME);
+        if (mAppOpsFile.exists()) {
+            // Start with a clean state (persisted into XML).
+            mAppOpsFile.delete();
+        }
+
+        HandlerThread handlerThread = new HandlerThread(TAG);
+        handlerThread.start();
+        mHandler = new Handler(handlerThread.getLooper());
+        mMyPackageName = mContext.getOpPackageName();
+        mMyUid = Process.myUid();
+
+        mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
+        mAppOpsService.mContext = mContext;
+        mTestStartMillis = System.currentTimeMillis();
+    }
+
+    @Test
+    public void testGetOpsForPackage_noOpsLogged() {
+        assertThat(getLoggedOps()).isNull();
+    }
+
+    @Test
+    public void testNoteOperationAndGetOpsForPackage() {
+        mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
+        mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED);
+
+        // Note an op that's allowed.
+        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+        List<PackageOps> loggedOps = getLoggedOps();
+        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+
+        // Note another op that's not allowed.
+        mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName);
+        loggedOps = getLoggedOps();
+        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+        assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
+    }
+
+    /**
+     * Tests the scenario where an operation's permission is controlled by another operation.
+     * For example the results of a WIFI_SCAN can be used to infer the location of a user, so the
+     * ACCESS_COARSE_LOCATION op is used to check whether WIFI_SCAN is allowed.
+     */
+    @Test
+    public void testNoteOperationAndGetOpsForPackage_controlledByDifferentOp() {
+        // This op controls WIFI_SCAN
+        mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ALLOWED);
+
+        assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName))
+                .isEqualTo(MODE_ALLOWED);
+
+        assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, -1,
+                MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
+
+        // Now set COARSE_LOCATION to ERRORED -> this will make WIFI_SCAN disabled as well.
+        mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ERRORED);
+        assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName))
+                .isEqualTo(MODE_ERRORED);
+
+        assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, mTestStartMillis,
+                MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
+    }
+
+    // Tests the dumping and restoring of the in-memory state to/from XML.
+    @Test
+    public void testStatePersistence() {
+        mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
+        mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED);
+        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+        mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName);
+        mAppOpsService.writeState();
+
+        // Create a new app ops service, and initialize its state from XML.
+        mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
+        mAppOpsService.mContext = mContext;
+        mAppOpsService.readState();
+
+        // Query the state of the 2nd service.
+        List<PackageOps> loggedOps = getLoggedOps();
+        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+        assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
+    }
+
+    // Tests that ops are persisted during shutdown.
+    @Test
+    public void testShutdown() {
+        mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
+        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+        mAppOpsService.shutdown();
+
+        // Create a new app ops service, and initialize its state from XML.
+        mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
+        mAppOpsService.mContext = mContext;
+        mAppOpsService.readState();
+
+        // Query the state of the 2nd service.
+        List<PackageOps> loggedOps = getLoggedOps();
+        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+    }
+
+    @Test
+    public void testGetOpsForPackage() {
+        mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
+        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+
+        // Query all ops
+        List<PackageOps> loggedOps = mAppOpsService.getOpsForPackage(
+                mMyUid, mMyPackageName, null /* all ops */);
+        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+
+        // Query specific ops
+        loggedOps = mAppOpsService.getOpsForPackage(
+                mMyUid, mMyPackageName, new int[]{OP_READ_SMS, OP_WRITE_SMS});
+        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+
+        // Query unknown UID
+        loggedOps = mAppOpsService.getOpsForPackage(mMyUid + 1, mMyPackageName, null /* all ops */);
+        assertThat(loggedOps).isNull();
+
+        // Query unknown package name
+        loggedOps = mAppOpsService.getOpsForPackage(mMyUid, "fake.package", null /* all ops */);
+        assertThat(loggedOps).isNull();
+
+        // Query op code that's not been logged
+        loggedOps = mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName,
+                new int[]{OP_WRITE_SMS});
+        assertThat(loggedOps).isNull();
+    }
+
+    @Test
+    public void testPackageRemoved() {
+        mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
+        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+
+        List<PackageOps> loggedOps = getLoggedOps();
+        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+
+        mAppOpsService.packageRemoved(mMyUid, mMyPackageName);
+        assertThat(getLoggedOps()).isNull();
+    }
+
+    @Test
+    public void testUidRemoved() {
+        mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
+        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+
+        List<PackageOps> loggedOps = getLoggedOps();
+        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
+
+        mAppOpsService.uidRemoved(mMyUid);
+        assertThat(getLoggedOps()).isNull();
+    }
+
+    private List<PackageOps> getLoggedOps() {
+        return mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName, null /* all ops */);
+    }
+
+    private void assertContainsOp(List<PackageOps> loggedOps, int opCode, long minMillis,
+            long minRejectMillis, int mode) {
+
+        boolean opLogged = false;
+        for (PackageOps pkgOps : loggedOps) {
+            assertWithMessage("Unexpected UID").that(mMyUid).isEqualTo(pkgOps.getUid());
+            assertWithMessage("Unexpected package name").that(mMyPackageName).isEqualTo(
+                    pkgOps.getPackageName());
+
+            for (OpEntry opEntry : pkgOps.getOps()) {
+                if (opCode != opEntry.getOp()) {
+                    continue;
+                }
+                opLogged = true;
+
+                assertWithMessage("Unexpected mode").that(mode).isEqualTo(opEntry.getMode());
+                if (minMillis > 0) {
+                    assertWithMessage("Unexpected timestamp")
+                            .that(opEntry.getTime()).isAtLeast(minMillis);
+                }
+                if (minRejectMillis > 0) {
+                    assertWithMessage("Unexpected rejection timestamp")
+                            .that(opEntry.getRejectTime()).isAtLeast(minRejectMillis);
+                }
+            }
+        }
+        assertWithMessage("Op was not logged").that(opLogged).isTrue();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
new file mode 100644
index 0000000..eb0c627
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appop;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.Xml;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Tests app ops version upgrades
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppOpsUpgradeTest {
+    private static final String TAG = AppOpsUpgradeTest.class.getSimpleName();
+    private static final String APP_OPS_UNVERSIONED_ASSET_PATH =
+            "AppOpsUpgradeTest/appops-unversioned.xml";
+    private static final String APP_OPS_FILENAME = "appops-test.xml";
+    private static final int NON_DEFAULT_OPS_IN_FILE = 4;
+    private static final int CURRENT_VERSION = 1;
+
+    private File mAppOpsFile;
+    private Context mContext;
+    private Handler mHandler;
+
+    private void extractAppOpsFile() {
+        mAppOpsFile.getParentFile().mkdirs();
+        if (mAppOpsFile.exists()) {
+            mAppOpsFile.delete();
+        }
+        try (FileOutputStream out = new FileOutputStream(mAppOpsFile);
+             InputStream in = mContext.getAssets().open(APP_OPS_UNVERSIONED_ASSET_PATH,
+                     AssetManager.ACCESS_BUFFER)) {
+            byte[] buffer = new byte[4096];
+            int bytesRead;
+            while ((bytesRead = in.read(buffer)) >= 0) {
+                out.write(buffer, 0, bytesRead);
+            }
+            out.flush();
+            Log.d(TAG, "Successfully copied xml to " + mAppOpsFile.getAbsolutePath());
+        } catch (IOException exc) {
+            Log.e(TAG, "Exception while copying appops xml", exc);
+            fail();
+        }
+    }
+
+    private void assertSameModes(SparseArray<AppOpsService.UidState> uidStates, int op1, int op2) {
+        int numberOfNonDefaultOps = 0;
+        final int defaultModeOp1 = AppOpsManager.opToDefaultMode(op1);
+        final int defaultModeOp2 = AppOpsManager.opToDefaultMode(op2);
+        for(int i = 0; i < uidStates.size(); i++) {
+            final AppOpsService.UidState uidState = uidStates.valueAt(i);
+            if (uidState.opModes != null) {
+                final int uidMode1 = uidState.opModes.get(op1, defaultModeOp1);
+                final int uidMode2 = uidState.opModes.get(op2, defaultModeOp2);
+                assertEquals(uidMode1, uidMode2);
+                if (uidMode1 != defaultModeOp1) {
+                    numberOfNonDefaultOps++;
+                }
+            }
+            if (uidState.pkgOps == null) {
+                continue;
+            }
+            for (int j = 0; j < uidState.pkgOps.size(); j++) {
+                final AppOpsService.Ops ops = uidState.pkgOps.valueAt(j);
+                if (ops == null) {
+                    continue;
+                }
+                final AppOpsService.Op _op1 = ops.get(op1);
+                final AppOpsService.Op _op2 = ops.get(op2);
+                final int mode1 = (_op1 == null) ? defaultModeOp1 : _op1.mode;
+                final int mode2 = (_op2 == null) ? defaultModeOp2 : _op2.mode;
+                assertEquals(mode1, mode2);
+                if (mode1 != defaultModeOp1) {
+                    numberOfNonDefaultOps++;
+                }
+            }
+        }
+        assertEquals(numberOfNonDefaultOps, NON_DEFAULT_OPS_IN_FILE);
+    }
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mAppOpsFile = new File(mContext.getFilesDir(), APP_OPS_FILENAME);
+        extractAppOpsFile();
+        HandlerThread handlerThread = new HandlerThread(TAG);
+        handlerThread.start();
+        mHandler = new Handler(handlerThread.getLooper());
+    }
+
+    @Test
+    public void testUpgradeFromNoVersion() throws Exception {
+        AppOpsDataParser parser = new AppOpsDataParser(mAppOpsFile);
+        assertTrue(parser.parse());
+        assertEquals(AppOpsDataParser.NO_VERSION, parser.mVersion);
+        AppOpsService testService = new AppOpsService(mAppOpsFile, mHandler); // trigger upgrade
+        assertSameModes(testService.mUidStates, AppOpsManager.OP_RUN_IN_BACKGROUND,
+                AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
+        testService.mContext = mContext;
+        mHandler.removeCallbacks(testService.mWriteRunner);
+        testService.writeState();
+        assertTrue(parser.parse());
+        assertEquals(CURRENT_VERSION, parser.mVersion);
+    }
+
+    /**
+     * Class to parse data from the appops xml. Currently only parses and holds the version number.
+     * Other fields may be added as and when required for testing.
+     */
+    private static final class AppOpsDataParser {
+        static final int NO_VERSION = -1;
+        int mVersion;
+        private File mFile;
+
+        AppOpsDataParser(File file) {
+            mFile = file;
+            mVersion = NO_VERSION;
+        }
+
+        boolean parse() {
+            try (FileInputStream stream = new FileInputStream(mFile)) {
+                XmlPullParser parser = Xml.newPullParser();
+                parser.setInput(stream, StandardCharsets.UTF_8.name());
+                int type;
+                while ((type = parser.next()) != XmlPullParser.START_TAG
+                        && type != XmlPullParser.END_DOCUMENT) {
+                    ;
+                }
+                if (type != XmlPullParser.START_TAG) {
+                    throw new IllegalStateException("no start tag found");
+                }
+                final String versionString = parser.getAttributeValue(null, "v");
+                if (versionString != null) {
+                    mVersion = Integer.parseInt(versionString);
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "Failed while parsing test appops xml", e);
+                return false;
+            }
+            return true;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java b/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java
deleted file mode 100644
index 7e0dfcf..0000000
--- a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java
+++ /dev/null
@@ -1,158 +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.appops;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.app.AppOpsManager;
-import android.app.AppOpsManager.OnOpActiveChangedListener;
-import android.content.Context;
-import android.os.Process;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-/**
- * Tests app ops version upgrades
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AppOpsActiveWatcherTest {
-
-    private static final long NOTIFICATION_TIMEOUT_MILLIS = 5000;
-
-    @Test
-    public void testWatchActiveOps() {
-        // Create a mock listener
-        final OnOpActiveChangedListener listener = mock(OnOpActiveChangedListener.class);
-
-        // Start watching active ops
-        final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
-        appOpsManager.startWatchingActive(new int[] {AppOpsManager.OP_CAMERA,
-                AppOpsManager.OP_RECORD_AUDIO}, listener);
-
-        // Start the op
-        appOpsManager.startOp(AppOpsManager.OP_CAMERA);
-
-        // Verify that we got called for the op being active
-        verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
-                .times(1)).onOpActiveChanged(eq(AppOpsManager.OP_CAMERA),
-                eq(Process.myUid()), eq(getContext().getPackageName()), eq(true));
-
-        // This should be the only callback we got
-        verifyNoMoreInteractions(listener);
-
-        // Start with a clean slate
-        reset(listener);
-
-        // Verify that the op is active
-        assertThat(appOpsManager.isOperationActive(AppOpsManager.OP_CAMERA,
-                Process.myUid(), getContext().getPackageName())).isTrue();
-
-        // Finish the op
-        appOpsManager.finishOp(AppOpsManager.OP_CAMERA);
-
-        // Verify that we got called for the op being active
-        verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
-                .times(1)).onOpActiveChanged(eq(AppOpsManager.OP_CAMERA),
-                eq(Process.myUid()), eq(getContext().getPackageName()), eq(false));
-
-        // Verify that the op is not active
-        assertThat(appOpsManager.isOperationActive(AppOpsManager.OP_CAMERA,
-                Process.myUid(), getContext().getPackageName())).isFalse();
-
-        // This should be the only callback we got
-        verifyNoMoreInteractions(listener);
-
-        // Start with a clean slate
-        reset(listener);
-
-        // Stop watching active ops
-        appOpsManager.stopWatchingActive(listener);
-
-        // Start the op
-        appOpsManager.startOp(AppOpsManager.OP_CAMERA);
-
-        // We should not be getting any callbacks
-        verifyNoMoreInteractions(listener);
-
-        // Finish the op
-        appOpsManager.finishOp(AppOpsManager.OP_CAMERA);
-
-        // We should not be getting any callbacks
-        verifyNoMoreInteractions(listener);
-    }
-
-    @Test
-    public void testIsRunning() throws Exception {
-        final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
-        // Start the op
-        appOpsManager.startOp(AppOpsManager.OP_CAMERA);
-
-        assertTrue("Camera should be running", isCameraOn(appOpsManager));
-
-        // Finish the op
-        appOpsManager.finishOp(AppOpsManager.OP_CAMERA);
-
-        assertFalse("Camera should not be running", isCameraOn(appOpsManager));
-    }
-
-    private boolean isCameraOn(AppOpsManager appOpsManager) {
-        List<AppOpsManager.PackageOps> packages
-                = appOpsManager.getPackagesForOps(new int[] {AppOpsManager.OP_CAMERA});
-        // AppOpsManager can return null when there is no requested data.
-        if (packages != null) {
-            final int numPackages = packages.size();
-            for (int packageInd = 0; packageInd < numPackages; packageInd++) {
-                AppOpsManager.PackageOps packageOp = packages.get(packageInd);
-                List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
-                if (opEntries != null) {
-                    final int numOps = opEntries.size();
-                    for (int opInd = 0; opInd < numOps; opInd++) {
-                        AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
-                        if (opEntry.getOp() == AppOpsManager.OP_CAMERA) {
-                            if (opEntry.isRunning()) {
-                                return true;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        return false;
-    }
-
-    private static Context getContext() {
-        return InstrumentationRegistry.getContext();
-    }
-}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsServiceTest.java b/services/tests/servicestests/src/com/android/server/appops/AppOpsServiceTest.java
deleted file mode 100644
index 4ae9bea..0000000
--- a/services/tests/servicestests/src/com/android/server/appops/AppOpsServiceTest.java
+++ /dev/null
@@ -1,256 +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;
-
-import static android.app.AppOpsManager.MODE_ALLOWED;
-import static android.app.AppOpsManager.MODE_ERRORED;
-import static android.app.AppOpsManager.OP_COARSE_LOCATION;
-import static android.app.AppOpsManager.OP_READ_SMS;
-import static android.app.AppOpsManager.OP_WIFI_SCAN;
-import static android.app.AppOpsManager.OP_WRITE_SMS;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.app.AppOpsManager.OpEntry;
-import android.app.AppOpsManager.PackageOps;
-import android.content.Context;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Process;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * Unit tests for AppOpsService. Covers functionality that is difficult to test using CTS tests
- * or for which we can write more detailed unit tests than CTS tests (because the internal APIs are
- * more finegrained data than the public ones).
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AppOpsServiceTest {
-
-    private static final String TAG = AppOpsServiceTest.class.getSimpleName();
-    // State will be persisted into this XML file.
-    private static final String APP_OPS_FILENAME = "appops-service-test.xml";
-
-    private File mAppOpsFile;
-    private Context mContext;
-    private Handler mHandler;
-    private AppOpsService mAppOpsService;
-    private String mMyPackageName;
-    private int mMyUid;
-    private long mTestStartMillis;
-
-    @Before
-    public void setUp() {
-        mContext = InstrumentationRegistry.getTargetContext();
-        mAppOpsFile = new File(mContext.getFilesDir(), APP_OPS_FILENAME);
-        if (mAppOpsFile.exists()) {
-            // Start with a clean state (persisted into XML).
-            mAppOpsFile.delete();
-        }
-
-        HandlerThread handlerThread = new HandlerThread(TAG);
-        handlerThread.start();
-        mHandler = new Handler(handlerThread.getLooper());
-        mMyPackageName = mContext.getOpPackageName();
-        mMyUid = Process.myUid();
-
-        mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
-        mAppOpsService.mContext = mContext;
-        mTestStartMillis = System.currentTimeMillis();
-    }
-
-    @Test
-    public void testGetOpsForPackage_noOpsLogged() {
-        assertThat(getLoggedOps()).isNull();
-    }
-
-    @Test
-    public void testNoteOperationAndGetOpsForPackage() {
-        mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
-        mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED);
-
-        // Note an op that's allowed.
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
-        List<PackageOps> loggedOps = getLoggedOps();
-        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
-
-        // Note another op that's not allowed.
-        mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName);
-        loggedOps = getLoggedOps();
-        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
-        assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
-    }
-
-    /**
-     * Tests the scenario where an operation's permission is controlled by another operation.
-     * For example the results of a WIFI_SCAN can be used to infer the location of a user, so the
-     * ACCESS_COARSE_LOCATION op is used to check whether WIFI_SCAN is allowed.
-     */
-    @Test
-    public void testNoteOperationAndGetOpsForPackage_controlledByDifferentOp() {
-        // This op controls WIFI_SCAN
-        mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ALLOWED);
-
-        assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName))
-                .isEqualTo(MODE_ALLOWED);
-
-        assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, -1,
-                MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
-
-        // Now set COARSE_LOCATION to ERRORED -> this will make WIFI_SCAN disabled as well.
-        mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ERRORED);
-        assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName))
-                .isEqualTo(MODE_ERRORED);
-
-        assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, mTestStartMillis,
-                MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
-    }
-
-    // Tests the dumping and restoring of the in-memory state to/from XML.
-    @Test
-    public void testStatePersistence() {
-        mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
-        mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
-        mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName);
-        mAppOpsService.writeState();
-
-        // Create a new app ops service, and initialize its state from XML.
-        mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
-        mAppOpsService.mContext = mContext;
-        mAppOpsService.readState();
-
-        // Query the state of the 2nd service.
-        List<PackageOps> loggedOps = getLoggedOps();
-        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
-        assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
-    }
-
-    // Tests that ops are persisted during shutdown.
-    @Test
-    public void testShutdown() {
-        mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
-        mAppOpsService.shutdown();
-
-        // Create a new app ops service, and initialize its state from XML.
-        mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
-        mAppOpsService.mContext = mContext;
-        mAppOpsService.readState();
-
-        // Query the state of the 2nd service.
-        List<PackageOps> loggedOps = getLoggedOps();
-        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
-    }
-
-    @Test
-    public void testGetOpsForPackage() {
-        mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
-
-        // Query all ops
-        List<PackageOps> loggedOps = mAppOpsService.getOpsForPackage(
-                mMyUid, mMyPackageName, null /* all ops */);
-        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
-
-        // Query specific ops
-        loggedOps = mAppOpsService.getOpsForPackage(
-                mMyUid, mMyPackageName, new int[]{OP_READ_SMS, OP_WRITE_SMS});
-        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
-
-        // Query unknown UID
-        loggedOps = mAppOpsService.getOpsForPackage(mMyUid + 1, mMyPackageName, null /* all ops */);
-        assertThat(loggedOps).isNull();
-
-        // Query unknown package name
-        loggedOps = mAppOpsService.getOpsForPackage(mMyUid, "fake.package", null /* all ops */);
-        assertThat(loggedOps).isNull();
-
-        // Query op code that's not been logged
-        loggedOps = mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName,
-                new int[]{OP_WRITE_SMS});
-        assertThat(loggedOps).isNull();
-    }
-
-    @Test
-    public void testPackageRemoved() {
-        mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
-
-        List<PackageOps> loggedOps = getLoggedOps();
-        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
-
-        mAppOpsService.packageRemoved(mMyUid, mMyPackageName);
-        assertThat(getLoggedOps()).isNull();
-    }
-
-    @Test
-    public void testUidRemoved() {
-        mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
-
-        List<PackageOps> loggedOps = getLoggedOps();
-        assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
-
-        mAppOpsService.uidRemoved(mMyUid);
-        assertThat(getLoggedOps()).isNull();
-    }
-
-    private List<PackageOps> getLoggedOps() {
-        return mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName, null /* all ops */);
-    }
-
-    private void assertContainsOp(List<PackageOps> loggedOps, int opCode, long minMillis,
-            long minRejectMillis, int mode) {
-
-        boolean opLogged = false;
-        for (PackageOps pkgOps : loggedOps) {
-            assertWithMessage("Unexpected UID").that(mMyUid).isEqualTo(pkgOps.getUid());
-            assertWithMessage("Unexpected package name").that(mMyPackageName).isEqualTo(
-                    pkgOps.getPackageName());
-
-            for (OpEntry opEntry : pkgOps.getOps()) {
-                if (opCode != opEntry.getOp()) {
-                    continue;
-                }
-                opLogged = true;
-
-                assertWithMessage("Unexpected mode").that(mode).isEqualTo(opEntry.getMode());
-                if (minMillis > 0) {
-                    assertWithMessage("Unexpected timestamp")
-                            .that(opEntry.getTime()).isAtLeast(minMillis);
-                }
-                if (minRejectMillis > 0) {
-                    assertWithMessage("Unexpected rejection timestamp")
-                            .that(opEntry.getRejectTime()).isAtLeast(minRejectMillis);
-                }
-            }
-        }
-        assertWithMessage("Op was not logged").that(opLogged).isTrue();
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index db83505..ac4a5fe 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -25,7 +25,6 @@
 
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
@@ -48,6 +47,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
+import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -90,17 +90,30 @@
     };
     private static final int NON_USER_SYSTEM = UserHandle.USER_SYSTEM + 1;
 
-    @UserIdInt private int mUserId;
-    @Mock private BackupManagerService mBackupManagerServiceMock;
-    @Mock private Context mContextMock;
-    @Mock private File mSuppressFileMock;
-    @Mock private File mSuppressFileParentMock;
-    @Mock private IBinder mAgentMock;
-    @Mock private ParcelFileDescriptor mParcelFileDescriptorMock;
-    @Mock private IFullBackupRestoreObserver mFullBackupRestoreObserverMock;
-    @Mock private IBackupObserver mBackupObserverMock;
-    @Mock private IBackupManagerMonitor mBackupManagerMonitorMock;
-    @Mock private PrintWriter mPrintWriterMock;
+    @UserIdInt
+    private int mUserId;
+    @Mock
+    private BackupManagerService mBackupManagerServiceMock;
+    @Mock
+    private UserBackupManagerService mUserBackupManagerService;
+    @Mock
+    private Context mContextMock;
+    @Mock
+    private File mSuppressFileMock;
+    @Mock
+    private File mSuppressFileParentMock;
+    @Mock
+    private IBinder mAgentMock;
+    @Mock
+    private ParcelFileDescriptor mParcelFileDescriptorMock;
+    @Mock
+    private IFullBackupRestoreObserver mFullBackupRestoreObserverMock;
+    @Mock
+    private IBackupObserver mBackupObserverMock;
+    @Mock
+    private IBackupManagerMonitor mBackupManagerMonitorMock;
+    @Mock
+    private PrintWriter mPrintWriterMock;
 
     private FileDescriptor mFileDescriptorStub = new FileDescriptor();
 
@@ -110,16 +123,20 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        mUserId = NON_USER_SYSTEM;
+
+        SparseArray<UserBackupManagerService> serviceUsers = new SparseArray<>();
+        serviceUsers.append(UserHandle.SYSTEM.getIdentifier(), mUserBackupManagerService);
+        serviceUsers.append(NON_USER_SYSTEM, mUserBackupManagerService);
+        when(mBackupManagerServiceMock.getServiceUsers()).thenReturn(serviceUsers);
 
         TrampolineTestable.sBackupManagerServiceMock = mBackupManagerServiceMock;
-        TrampolineTestable.sSuppressFile = mSuppressFileMock;
         TrampolineTestable.sCallingUserId = UserHandle.USER_SYSTEM;
         TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
         TrampolineTestable.sBackupDisabled = false;
 
         when(mSuppressFileMock.getParentFile()).thenReturn(mSuppressFileParentMock);
 
-        mUserId = NON_USER_SYSTEM;
         mTrampoline = new TrampolineTestable(mContextMock);
 
         mContentResolver = new MockContentResolver();
@@ -128,11 +145,6 @@
     }
 
     @Test
-    public void constructor_createsSuppressFileDirectory() {
-        verify(mSuppressFileParentMock).mkdirs();
-    }
-
-    @Test
     public void unlockUser_whenMultiUserSettingDisabled_callsBackupManagerServiceForSystemUser() {
         Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
         mTrampoline.initializeService();
@@ -147,9 +159,9 @@
         Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
         mTrampoline.initializeService();
 
-        mTrampoline.unlockUser(10);
+        mTrampoline.unlockUser(NON_USER_SYSTEM);
 
-        verify(mBackupManagerServiceMock, never()).startServiceForUser(10);
+        verify(mBackupManagerServiceMock, never()).startServiceForUser(NON_USER_SYSTEM);
     }
 
     @Test
@@ -157,9 +169,9 @@
         Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 1);
         mTrampoline.initializeService();
 
-        mTrampoline.unlockUser(10);
+        mTrampoline.unlockUser(NON_USER_SYSTEM);
 
-        verify(mBackupManagerServiceMock).startServiceForUser(10);
+        verify(mBackupManagerServiceMock).startServiceForUser(NON_USER_SYSTEM);
     }
 
     @Test
@@ -177,19 +189,20 @@
         Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
         mTrampoline.initializeService();
 
-        mTrampoline.stopUser(10);
+        mTrampoline.stopUser(NON_USER_SYSTEM);
 
-        verify(mBackupManagerServiceMock, never()).stopServiceForUser(10);
+        verify(mBackupManagerServiceMock, never()).stopServiceForUser(NON_USER_SYSTEM);
     }
 
     @Test
     public void stopUser_whenMultiUserSettingEnabled_callsBackupManagerServiceForNonSystemUser() {
         Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 1);
+
         mTrampoline.initializeService();
 
-        mTrampoline.stopUser(10);
+        mTrampoline.stopUser(NON_USER_SYSTEM);
 
-        verify(mBackupManagerServiceMock).stopServiceForUser(10);
+        verify(mBackupManagerServiceMock).stopServiceForUser(NON_USER_SYSTEM);
     }
 
     @Test
@@ -211,9 +224,10 @@
 
     // Verify that BackupManagerService is not initialized if suppress file exists.
     @Test
-    public void initializeService_suppressFileExists_nonInitialized() {
-        when(mSuppressFileMock.exists()).thenReturn(true);
+    public void initializeService_suppressFileExists_nonInitialized() throws Exception {
         TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
+        trampoline.createBackupSuppressFileForUser(UserHandle.USER_SYSTEM);
+
 
         trampoline.initializeService();
 
@@ -233,6 +247,14 @@
     }
 
     @Test
+    public void isBackupServiceActive_forNonSysUser_whenSysUserIsDeactivated_returnsFalse() {
+        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+
+        assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+    }
+
+    @Test
     public void setBackupServiceActive_callerSystemUid_serviceCreated() {
         TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
 
@@ -292,11 +314,18 @@
     }
 
     @Test
+    public void setBackupServiceActive_makeNonActive_alreadyNonActive_ignored() {
+        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+
+        assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+    }
+
+    @Test
     public void setBackupServiceActive_makeActive_serviceCreatedAndSuppressFileDeleted() {
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
-        verify(mSuppressFileMock).delete();
     }
 
     @Test
@@ -308,40 +337,25 @@
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
 
         assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
-        verify(mSuppressFileMock).createNewFile();
     }
 
     @Test
-    public void
-    setBackupServiceActive_makeNonActive_serviceDeletedAndSuppressFileCreated_ioExceptionHandled()
-            throws IOException {
-        when(mSuppressFileMock.createNewFile()).thenThrow(new IOException());
+    public void setBackupActive_nonSystemUser_disabledForSystemUser_ignored() {
         mTrampoline.initializeService();
-        assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
-
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
 
-        assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
-        verify(mSuppressFileMock).createNewFile();
+        assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
     }
 
     @Test
-    public void setBackupServiceActive_makeNonActive_alreadyNonActive_ignored() throws IOException {
-        reset(mSuppressFileMock);
-
-        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
-
-        verifyNoMoreInteractions(mSuppressFileMock);
-    }
-
-    @Test
-    public void dataChanged_calledBeforeInitialize_ignored() throws RemoteException {
+    public void dataChanged_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.dataChanged(PACKAGE_NAME);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void dataChangedForUser_forwarded() throws RemoteException {
+    public void dataChangedForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.dataChangedForUser(mUserId, PACKAGE_NAME);
@@ -350,7 +364,7 @@
     }
 
     @Test
-    public void dataChanged_forwarded() throws RemoteException {
+    public void dataChanged_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService();
 
@@ -360,13 +374,13 @@
     }
 
     @Test
-    public void clearBackupData_calledBeforeInitialize_ignored() throws RemoteException {
+    public void clearBackupData_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.clearBackupData(TRANSPORT_NAME, PACKAGE_NAME);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void clearBackupDataForUser_forwarded() throws RemoteException {
+    public void clearBackupDataForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.clearBackupDataForUser(mUserId, TRANSPORT_NAME, PACKAGE_NAME);
@@ -375,7 +389,7 @@
     }
 
     @Test
-    public void clearBackupData_forwarded() throws RemoteException {
+    public void clearBackupData_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService();
 
@@ -385,13 +399,13 @@
     }
 
     @Test
-    public void agentConnected_calledBeforeInitialize_ignored() throws RemoteException {
+    public void agentConnected_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.agentConnected(PACKAGE_NAME, mAgentMock);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void agentConnectedForUser_forwarded() throws RemoteException {
+    public void agentConnectedForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.agentConnectedForUser(mUserId, PACKAGE_NAME, mAgentMock);
@@ -400,7 +414,7 @@
     }
 
     @Test
-    public void agentConnected_forwarded() throws RemoteException {
+    public void agentConnected_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService();
 
@@ -410,13 +424,13 @@
     }
 
     @Test
-    public void agentDisconnected_calledBeforeInitialize_ignored() throws RemoteException {
+    public void agentDisconnected_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.agentDisconnected(PACKAGE_NAME);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void agentDisconnectedForUser_forwarded() throws RemoteException {
+    public void agentDisconnectedForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.agentDisconnectedForUser(mUserId, PACKAGE_NAME);
@@ -425,7 +439,7 @@
     }
 
     @Test
-    public void agentDisconnected_forwarded() throws RemoteException {
+    public void agentDisconnected_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService();
 
@@ -435,13 +449,13 @@
     }
 
     @Test
-    public void restoreAtInstall_calledBeforeInitialize_ignored() throws RemoteException {
+    public void restoreAtInstall_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.restoreAtInstall(PACKAGE_NAME, 123);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void restoreAtInstallForUser_forwarded() throws RemoteException {
+    public void restoreAtInstallForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.restoreAtInstallForUser(mUserId, PACKAGE_NAME, 123);
@@ -450,7 +464,7 @@
     }
 
     @Test
-    public void restoreAtInstall_forwarded() throws RemoteException {
+    public void restoreAtInstall_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService();
 
@@ -460,13 +474,13 @@
     }
 
     @Test
-    public void setBackupEnabled_calledBeforeInitialize_ignored() throws RemoteException {
+    public void setBackupEnabled_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.setBackupEnabled(true);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void setBackupEnabledForUser_forwarded() throws RemoteException {
+    public void setBackupEnabledForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.setBackupEnabledForUser(mUserId, true);
@@ -475,7 +489,7 @@
     }
 
     @Test
-    public void setBackupEnabled_forwardedToCallingUserId() throws RemoteException {
+    public void setBackupEnabled_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService();
 
@@ -485,13 +499,13 @@
     }
 
     @Test
-    public void setAutoRestore_calledBeforeInitialize_ignored() throws RemoteException {
+    public void setAutoRestore_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.setAutoRestore(true);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void setAutoRestoreForUser_forwarded() throws RemoteException {
+    public void setAutoRestoreForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.setAutoRestoreForUser(mUserId, true);
@@ -500,7 +514,7 @@
     }
 
     @Test
-    public void setAutoRestore_forwarded() throws RemoteException {
+    public void setAutoRestore_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService();
 
@@ -510,13 +524,13 @@
     }
 
     @Test
-    public void isBackupEnabled_calledBeforeInitialize_ignored() throws RemoteException {
+    public void isBackupEnabled_calledBeforeInitialize_ignored() throws Exception {
         assertFalse(mTrampoline.isBackupEnabled());
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void isBackupEnabledForUser_forwarded() throws RemoteException {
+    public void isBackupEnabledForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.isBackupEnabledForUser(mUserId);
@@ -525,7 +539,7 @@
     }
 
     @Test
-    public void isBackupEnabled_forwardedToCallingUserId() throws RemoteException {
+    public void isBackupEnabled_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService();
 
@@ -535,39 +549,39 @@
     }
 
     @Test
-    public void setBackupPassword_calledBeforeInitialize_ignored() throws RemoteException {
+    public void setBackupPassword_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void setBackupPassword_forwarded() throws RemoteException {
+    public void setBackupPassword_forwarded() throws Exception {
         mTrampoline.initializeService();
         mTrampoline.setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD);
         verify(mBackupManagerServiceMock).setBackupPassword(CURRENT_PASSWORD, NEW_PASSWORD);
     }
 
     @Test
-    public void hasBackupPassword_calledBeforeInitialize_ignored() throws RemoteException {
+    public void hasBackupPassword_calledBeforeInitialize_ignored() throws Exception {
         assertFalse(mTrampoline.hasBackupPassword());
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void hasBackupPassword_forwarded() throws RemoteException {
+    public void hasBackupPassword_forwarded() throws Exception {
         mTrampoline.initializeService();
         mTrampoline.hasBackupPassword();
         verify(mBackupManagerServiceMock).hasBackupPassword();
     }
 
     @Test
-    public void backupNow_calledBeforeInitialize_ignored() throws RemoteException {
+    public void backupNow_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.backupNow();
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void backupNowForUser_forwarded() throws RemoteException {
+    public void backupNowForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.backupNowForUser(mUserId);
@@ -576,7 +590,7 @@
     }
 
     @Test
-    public void backupNow_forwardedToCallingUserId() throws RemoteException {
+    public void backupNow_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService();
 
@@ -586,7 +600,7 @@
     }
 
     @Test
-    public void adbBackup_calledBeforeInitialize_ignored() throws RemoteException {
+    public void adbBackup_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.adbBackup(mUserId, mParcelFileDescriptorMock, true, true,
                 true, true, true, true, true, true,
                 PACKAGE_NAMES);
@@ -594,7 +608,7 @@
     }
 
     @Test
-    public void adbBackup_forwarded() throws RemoteException {
+    public void adbBackup_forwarded() throws Exception {
         mTrampoline.initializeService();
         mTrampoline.adbBackup(mUserId, mParcelFileDescriptorMock, true, true,
                 true, true, true, true, true, true,
@@ -604,13 +618,13 @@
     }
 
     @Test
-    public void fullTransportBackup_calledBeforeInitialize_ignored() throws RemoteException {
+    public void fullTransportBackup_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.fullTransportBackupForUser(mUserId, PACKAGE_NAMES);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void fullTransportBackupForUser_forwarded() throws RemoteException {
+    public void fullTransportBackupForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.fullTransportBackupForUser(mUserId, PACKAGE_NAMES);
@@ -619,13 +633,13 @@
     }
 
     @Test
-    public void adbRestore_calledBeforeInitialize_ignored() throws RemoteException {
+    public void adbRestore_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.adbRestore(mUserId, mParcelFileDescriptorMock);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void adbRestore_forwarded() throws RemoteException {
+    public void adbRestore_forwarded() throws Exception {
         mTrampoline.initializeService();
         mTrampoline.adbRestore(mUserId, mParcelFileDescriptorMock);
         verify(mBackupManagerServiceMock).adbRestore(mUserId, mParcelFileDescriptorMock);
@@ -633,14 +647,14 @@
 
     @Test
     public void acknowledgeFullBackupOrRestore_calledBeforeInitialize_ignored()
-            throws RemoteException {
+            throws Exception {
         mTrampoline.acknowledgeFullBackupOrRestore(123, true, CURRENT_PASSWORD, ENCRYPTION_PASSWORD,
                 mFullBackupRestoreObserverMock);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void acknowledgeFullBackupOrRestoreForUser_forwarded() throws RemoteException {
+    public void acknowledgeFullBackupOrRestoreForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.acknowledgeFullBackupOrRestoreForUser(
@@ -662,7 +676,7 @@
     }
 
     @Test
-    public void acknowledgeFullBackupOrRestore_forwarded() throws RemoteException {
+    public void acknowledgeFullBackupOrRestore_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService();
 
@@ -680,13 +694,13 @@
     }
 
     @Test
-    public void getCurrentTransport_calledBeforeInitialize_ignored() throws RemoteException {
+    public void getCurrentTransport_calledBeforeInitialize_ignored() throws Exception {
         assertNull(mTrampoline.getCurrentTransport());
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void getCurrentTransportForUser_forwarded() throws RemoteException {
+    public void getCurrentTransportForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME);
         mTrampoline.initializeService();
 
@@ -695,7 +709,7 @@
     }
 
     @Test
-    public void getCurrentTransport_forwarded() throws RemoteException {
+    public void getCurrentTransport_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME);
         mTrampoline.initializeService();
@@ -705,13 +719,13 @@
     }
 
     @Test
-    public void listAllTransports_calledBeforeInitialize_ignored() throws RemoteException {
+    public void listAllTransports_calledBeforeInitialize_ignored() throws Exception {
         assertNull(mTrampoline.listAllTransports());
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void listAllTransportsForUser_forwarded() throws RemoteException {
+    public void listAllTransportsForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS);
         mTrampoline.initializeService();
 
@@ -721,7 +735,7 @@
 
 
     @Test
-    public void listAllTransports_forwarded() throws RemoteException {
+    public void listAllTransports_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS);
         mTrampoline.initializeService();
@@ -732,13 +746,13 @@
 
     @Test
     public void listAllTransportComponentsForUser_calledBeforeInitialize_ignored()
-            throws RemoteException {
+            throws Exception {
         assertNull(mTrampoline.listAllTransportComponentsForUser(mUserId));
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void listAllTransportComponentsForUser_forwarded() throws RemoteException {
+    public void listAllTransportComponentsForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.listAllTransportComponents(mUserId)).thenReturn(
                 TRANSPORT_COMPONENTS);
         mTrampoline.initializeService();
@@ -748,13 +762,13 @@
     }
 
     @Test
-    public void getTransportWhitelist_calledBeforeInitialize_ignored() throws RemoteException {
+    public void getTransportWhitelist_calledBeforeInitialize_ignored() throws Exception {
         assertNull(mTrampoline.getTransportWhitelist());
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void getTransportWhitelist_forwarded() throws RemoteException {
+    public void getTransportWhitelist_forwarded() {
         when(mBackupManagerServiceMock.getTransportWhitelist()).thenReturn(TRANSPORTS);
         mTrampoline.initializeService();
 
@@ -763,8 +777,7 @@
     }
 
     @Test
-    public void updateTransportAttributesForUser_calledBeforeInitialize_ignored()
-            throws RemoteException {
+    public void updateTransportAttributesForUser_calledBeforeInitialize_ignored() {
         mTrampoline.updateTransportAttributesForUser(
                 mUserId,
                 TRANSPORT_COMPONENT_NAME,
@@ -778,7 +791,7 @@
     }
 
     @Test
-    public void updateTransportAttributesForUser_forwarded() throws RemoteException {
+    public void updateTransportAttributesForUser_forwarded() {
         when(mBackupManagerServiceMock.getTransportWhitelist()).thenReturn(TRANSPORTS);
         mTrampoline.initializeService();
 
@@ -809,7 +822,7 @@
     }
 
     @Test
-    public void selectBackupTransportForUser_forwarded() throws RemoteException {
+    public void selectBackupTransportForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.selectBackupTransportForUser(mUserId, TRANSPORT_NAME);
@@ -818,7 +831,7 @@
     }
 
     @Test
-    public void selectBackupTransport_forwarded() throws RemoteException {
+    public void selectBackupTransport_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService();
 
@@ -895,7 +908,7 @@
     }
 
     @Test
-    public void selectBackupTransportAsyncForUser_forwarded() throws RemoteException {
+    public void selectBackupTransportAsyncForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null);
@@ -905,13 +918,13 @@
     }
 
     @Test
-    public void getConfigurationIntent_calledBeforeInitialize_ignored() throws RemoteException {
+    public void getConfigurationIntent_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.getConfigurationIntent(TRANSPORT_NAME);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void getConfigurationIntentForUser_forwarded() throws RemoteException {
+    public void getConfigurationIntentForUser_forwarded() throws Exception {
         Intent configurationIntentStub = new Intent();
         when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 configurationIntentStub);
@@ -924,7 +937,7 @@
     }
 
     @Test
-    public void getConfigurationIntent_forwarded() throws RemoteException {
+    public void getConfigurationIntent_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         Intent configurationIntentStub = new Intent();
         when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn(
@@ -936,13 +949,13 @@
     }
 
     @Test
-    public void getDestinationString_calledBeforeInitialize_ignored() throws RemoteException {
+    public void getDestinationString_calledBeforeInitialize_ignored() throws Exception {
         assertNull(mTrampoline.getDestinationString(TRANSPORT_NAME));
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void getDestinationStringForUser_forwarded() throws RemoteException {
+    public void getDestinationStringForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn(
                 DESTINATION_STRING);
         mTrampoline.initializeService();
@@ -954,7 +967,7 @@
     }
 
     @Test
-    public void getDestinationString_forwarded() throws RemoteException {
+    public void getDestinationString_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn(
                 DESTINATION_STRING);
@@ -965,13 +978,13 @@
     }
 
     @Test
-    public void getDataManagementIntent_calledBeforeInitialize_ignored() throws RemoteException {
+    public void getDataManagementIntent_calledBeforeInitialize_ignored() throws Exception {
         assertNull(mTrampoline.getDataManagementIntent(TRANSPORT_NAME));
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void getDataManagementIntentForUser_forwarded() throws RemoteException {
+    public void getDataManagementIntentForUser_forwarded() throws Exception {
         Intent dataManagementIntent = new Intent();
         when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 dataManagementIntent);
@@ -984,7 +997,7 @@
     }
 
     @Test
-    public void getDataManagementIntent_forwarded() throws RemoteException {
+    public void getDataManagementIntent_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         Intent dataManagementIntent = new Intent();
         when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn(
@@ -996,13 +1009,13 @@
     }
 
     @Test
-    public void getDataManagementLabel_calledBeforeInitialize_ignored() throws RemoteException {
+    public void getDataManagementLabel_calledBeforeInitialize_ignored() throws Exception {
         assertNull(mTrampoline.getDataManagementLabel(TRANSPORT_NAME));
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void getDataManagementLabelForUser_forwarded() throws RemoteException {
+    public void getDataManagementLabelForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.getDataManagementLabel(mUserId, TRANSPORT_NAME)).thenReturn(
                 DATA_MANAGEMENT_LABEL);
         mTrampoline.initializeService();
@@ -1014,7 +1027,7 @@
     }
 
     @Test
-    public void getDataManagementLabel_forwarded() throws RemoteException {
+    public void getDataManagementLabel_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         when(mBackupManagerServiceMock.getDataManagementLabel(mUserId, TRANSPORT_NAME)).thenReturn(
                 DATA_MANAGEMENT_LABEL);
@@ -1025,13 +1038,13 @@
     }
 
     @Test
-    public void beginRestoreSession_calledBeforeInitialize_ignored() throws RemoteException {
+    public void beginRestoreSession_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.beginRestoreSessionForUser(mUserId, PACKAGE_NAME, TRANSPORT_NAME);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void beginRestoreSessionForUser_forwarded() throws RemoteException {
+    public void beginRestoreSessionForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.beginRestoreSessionForUser(mUserId, PACKAGE_NAME, TRANSPORT_NAME);
@@ -1041,13 +1054,13 @@
     }
 
     @Test
-    public void opComplete_calledBeforeInitialize_ignored() throws RemoteException {
+    public void opComplete_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.opComplete(1, 2);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void opComplete_forwarded() throws RemoteException {
+    public void opComplete_forwarded() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService();
 
@@ -1057,14 +1070,13 @@
     }
 
     @Test
-    public void getAvailableRestoreTokenForUser_calledBeforeInitialize_ignored()
-            throws RemoteException {
+    public void getAvailableRestoreTokenForUser_calledBeforeInitialize_ignored() {
         assertEquals(0, mTrampoline.getAvailableRestoreTokenForUser(mUserId, PACKAGE_NAME));
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void getAvailableRestoreTokenForUser_forwarded() throws RemoteException {
+    public void getAvailableRestoreTokenForUser_forwarded() {
         when(mBackupManagerServiceMock.getAvailableRestoreToken(mUserId, PACKAGE_NAME))
                 .thenReturn(123L);
         mTrampoline.initializeService();
@@ -1074,14 +1086,13 @@
     }
 
     @Test
-    public void isAppEligibleForBackupForUser_calledBeforeInitialize_ignored()
-            throws RemoteException {
+    public void isAppEligibleForBackupForUser_calledBeforeInitialize_ignored() {
         assertFalse(mTrampoline.isAppEligibleForBackupForUser(mUserId, PACKAGE_NAME));
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void isAppEligibleForBackupForUser_forwarded() throws RemoteException {
+    public void isAppEligibleForBackupForUser_forwarded() {
         when(mBackupManagerServiceMock.isAppEligibleForBackup(mUserId, PACKAGE_NAME))
                 .thenReturn(true);
         mTrampoline.initializeService();
@@ -1098,7 +1109,7 @@
     }
 
     @Test
-    public void requestBackupForUser_forwarded() throws RemoteException {
+    public void requestBackupForUser_forwarded() throws Exception {
         when(mBackupManagerServiceMock.requestBackup(mUserId, PACKAGE_NAMES,
                 mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456);
         mTrampoline.initializeService();
@@ -1110,7 +1121,7 @@
     }
 
     @Test
-    public void requestBackup_forwardedToCallingUserId() throws RemoteException {
+    public void requestBackup_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         when(mBackupManagerServiceMock.requestBackup(NON_USER_SYSTEM, PACKAGE_NAMES,
                 mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456);
@@ -1123,13 +1134,13 @@
     }
 
     @Test
-    public void cancelBackups_calledBeforeInitialize_ignored() throws RemoteException {
+    public void cancelBackups_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.cancelBackups();
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void cancelBackupsForUser_forwarded() throws RemoteException {
+    public void cancelBackupsForUser_forwarded() throws Exception {
         mTrampoline.initializeService();
 
         mTrampoline.cancelBackupsForUser(mUserId);
@@ -1138,7 +1149,7 @@
     }
 
     @Test
-    public void cancelBackups_forwardedToCallingUserId() throws RemoteException {
+    public void cancelBackups_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService();
 
@@ -1148,36 +1159,36 @@
     }
 
     @Test
-    public void beginFullBackup_calledBeforeInitialize_ignored() throws RemoteException {
-        mTrampoline.beginFullBackup(new FullBackupJob());
+    public void beginFullBackup_calledBeforeInitialize_ignored() throws Exception {
+        mTrampoline.beginFullBackup(mUserId, new FullBackupJob());
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void beginFullBackup_forwarded() throws RemoteException {
+    public void beginFullBackup_forwarded() throws Exception {
         FullBackupJob fullBackupJob = new FullBackupJob();
-        when(mBackupManagerServiceMock.beginFullBackup(fullBackupJob)).thenReturn(true);
+        when(mBackupManagerServiceMock.beginFullBackup(mUserId, fullBackupJob)).thenReturn(true);
 
         mTrampoline.initializeService();
-        assertTrue(mTrampoline.beginFullBackup(fullBackupJob));
-        verify(mBackupManagerServiceMock).beginFullBackup(fullBackupJob);
+        assertTrue(mTrampoline.beginFullBackup(mUserId, fullBackupJob));
+        verify(mBackupManagerServiceMock).beginFullBackup(mUserId, fullBackupJob);
     }
 
     @Test
-    public void endFullBackup_calledBeforeInitialize_ignored() throws RemoteException {
-        mTrampoline.endFullBackup();
+    public void endFullBackup_calledBeforeInitialize_ignored() {
+        mTrampoline.endFullBackup(mUserId);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
-    public void endFullBackup_forwarded() throws RemoteException {
+    public void endFullBackup_forwarded() {
         mTrampoline.initializeService();
-        mTrampoline.endFullBackup();
-        verify(mBackupManagerServiceMock).endFullBackup();
+        mTrampoline.endFullBackup(mUserId);
+        verify(mBackupManagerServiceMock).endFullBackup(mUserId);
     }
 
     @Test
-    public void dump_callerDoesNotHavePermission_ignored() throws RemoteException {
+    public void dump_callerDoesNotHavePermission_ignored() {
         when(mContextMock.checkCallingOrSelfPermission(
                 android.Manifest.permission.DUMP)).thenReturn(
                 PackageManager.PERMISSION_DENIED);
@@ -1189,7 +1200,7 @@
     }
 
     @Test
-    public void dump_calledBeforeInitialize_ignored() throws RemoteException {
+    public void dump_calledBeforeInitialize_ignored() {
         when(mContextMock.checkCallingOrSelfPermission(
                 android.Manifest.permission.DUMP)).thenReturn(
                 PackageManager.PERMISSION_GRANTED);
@@ -1200,7 +1211,7 @@
     }
 
     @Test
-    public void dump_callerHasPermission_forwarded() throws RemoteException {
+    public void dump_callerHasPermission_forwarded() {
         when(mContextMock.checkCallingOrSelfPermission(
                 android.Manifest.permission.DUMP)).thenReturn(
                 PackageManager.PERMISSION_GRANTED);
@@ -1213,11 +1224,36 @@
 
     private static class TrampolineTestable extends Trampoline {
         static boolean sBackupDisabled = false;
-        static File sSuppressFile = null;
         static int sCallingUserId = -1;
         static int sCallingUid = -1;
         static BackupManagerService sBackupManagerServiceMock = null;
         private int mCreateServiceCallsCount = 0;
+        private SparseArray<FakeFile> mSuppressFiles = new SparseArray<>();
+
+        private static class FakeFile extends File {
+            private boolean mExists;
+
+            FakeFile(String pathname) {
+                super(pathname);
+            }
+
+            @Override
+            public boolean exists() {
+                return mExists;
+            }
+
+            @Override
+            public boolean delete() {
+                mExists = false;
+                return true;
+            }
+
+            @Override
+            public boolean createNewFile() throws IOException {
+                mExists = true;
+                return true;
+            }
+        }
 
         TrampolineTestable(Context context) {
             super(context);
@@ -1229,8 +1265,12 @@
         }
 
         @Override
-        public File getSuppressFile() {
-            return sSuppressFile;
+        public File getSuppressFileForUser(int userId) {
+            if (mSuppressFiles.get(userId) == null) {
+                FakeFile file = new FakeFile(Integer.toString(userId));
+                mSuppressFiles.append(userId, file);
+            }
+            return mSuppressFiles.get(userId);
         }
 
         protected int binderGetCallingUserId() {
@@ -1249,6 +1289,11 @@
         }
 
         @Override
+        protected void createBackupSuppressFileForUser(int userId) throws IOException {
+            getSuppressFileForUser(userId).createNewFile();
+        }
+
+        @Override
         protected void postToHandler(Runnable runnable) {
             runnable.run();
         }
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
new file mode 100644
index 0000000..095a1de
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
@@ -0,0 +1,1172 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.testutils;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ChangedPackages;
+import android.content.pm.IDexModuleRegisterCallback;
+import android.content.pm.IOnPermissionsChangeListener;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageDeleteObserver2;
+import android.content.pm.IPackageInstaller;
+import android.content.pm.IPackageManager;
+import android.content.pm.IPackageMoveObserver;
+import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.KeySet;
+import android.content.pm.ModuleInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.SuspendDialogInfo;
+import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.VersionedPackage;
+import android.content.pm.dex.IArtManager;
+import android.graphics.Bitmap;
+import android.os.IBinder;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
+import java.util.List;
+
+/**
+ * Stub for IPackageManager to use in tests.
+ */
+public class IPackageManagerStub implements IPackageManager {
+    public static PackageInfo sPackageInfo;
+    public static int sApplicationEnabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+
+    @Override
+    public PackageInfo getPackageInfo(String packageName, int flags, int userId)
+        throws RemoteException {
+        return sPackageInfo;
+    }
+
+    @Override
+    public int getApplicationEnabledSetting(String packageName, int userId) throws RemoteException {
+        return sApplicationEnabledSetting;
+    }
+
+    @Override
+    public void checkPackageStartable(String packageName, int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public boolean isPackageAvailable(String packageName, int userId) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage, int flags,
+        int userId) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public int getPackageUid(String packageName, int flags, int userId) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public int[] getPackageGids(String packageName, int flags, int userId) throws RemoteException {
+        return new int[0];
+    }
+
+    @Override
+    public String[] currentToCanonicalPackageNames(String[] names) throws RemoteException {
+        return new String[0];
+    }
+
+    @Override
+    public String[] canonicalToCurrentPackageNames(String[] names) throws RemoteException {
+        return new String[0];
+    }
+
+    @Override
+    public PermissionInfo getPermissionInfo(String name, String packageName, int flags)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ParceledListSlice queryPermissionsByGroup(String group, int flags)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public PermissionGroupInfo getPermissionGroupInfo(String name, int flags)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ParceledListSlice getAllPermissionGroups(int flags) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ActivityInfo getActivityInfo(ComponentName className, int flags, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public boolean activitySupportsIntent(ComponentName className, Intent intent,
+        String resolvedType)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public ActivityInfo getReceiverInfo(ComponentName className, int flags, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ServiceInfo getServiceInfo(ComponentName className, int flags, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ProviderInfo getProviderInfo(ComponentName className, int flags, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public int checkPermission(String permName, String pkgName, int userId) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public int checkUidPermission(String permName, int uid) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public boolean addPermission(PermissionInfo info) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public void removePermission(String name) throws RemoteException {
+
+    }
+
+    @Override
+    public void grantRuntimePermission(String packageName, String permissionName, int userId)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public void revokeRuntimePermission(String packageName, String permissionName, int userId)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public void resetRuntimePermissions() throws RemoteException {
+
+    }
+
+    @Override
+    public int getPermissionFlags(String permissionName, String packageName, int userId)
+        throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public void updatePermissionFlags(String permissionName, String packageName, int flagMask,
+        int flagValues, int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public boolean shouldShowRequestPermissionRationale(String permissionName, String packageName,
+        int userId) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean isProtectedBroadcast(String actionName) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public int checkSignatures(String pkg1, String pkg2) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public int checkUidSignatures(int uid1, int uid2) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public List<String> getAllPackages() throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public String[] getPackagesForUid(int uid) throws RemoteException {
+        return new String[0];
+    }
+
+    @Override
+    public String getNameForUid(int uid) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public String[] getNamesForUids(int[] uids) throws RemoteException {
+        return new String[0];
+    }
+
+    @Override
+    public int getUidForSharedUser(String sharedUserName) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public int getFlagsForUid(int uid) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public int getPrivateFlagsForUid(int uid) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public boolean isUidPrivileged(int uid) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public String[] getAppOpPermissionPackages(String permissionName) throws RemoteException {
+        return new String[0];
+    }
+
+    @Override
+    public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ResolveInfo findPersistentPreferredActivity(Intent intent, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public boolean canForwardTo(Intent intent, String resolvedType, int sourceUserId,
+        int targetUserId) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public ParceledListSlice queryIntentActivities(Intent intent, String resolvedType, int flags,
+        int userId) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ParceledListSlice queryIntentActivityOptions(ComponentName caller, Intent[] specifics,
+        String[] specificTypes, Intent intent, String resolvedType, int flags, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ParceledListSlice queryIntentReceivers(Intent intent, String resolvedType, int flags,
+        int userId) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ParceledListSlice queryIntentServices(Intent intent, String resolvedType, int flags,
+        int userId) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ParceledListSlice queryIntentContentProviders(Intent intent, String resolvedType,
+        int flags, int userId) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ParceledListSlice getInstalledPackages(int flags, int userId) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ParceledListSlice getPackagesHoldingPermissions(String[] permissions, int flags,
+        int userId) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ParceledListSlice getInstalledApplications(int flags, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ParceledListSlice getPersistentApplications(int flags) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ProviderInfo resolveContentProvider(String name, int flags, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public ParceledListSlice queryContentProviders(String processName, int uid, int flags,
+        String metaDataKey) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public InstrumentationInfo getInstrumentationInfo(ComponentName className, int flags)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ParceledListSlice queryInstrumentation(String targetPackage, int flags)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public void finishPackageInstall(int token, boolean didLaunch) throws RemoteException {
+
+    }
+
+    @Override
+    public void setInstallerPackageName(String targetPackage, String installerPackageName)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public void setApplicationCategoryHint(String packageName, int categoryHint,
+        String callerPackageName) throws RemoteException {
+
+    }
+
+    @Override
+    public void deletePackageAsUser(String packageName, int versionCode,
+        IPackageDeleteObserver observer, int userId, int flags) throws RemoteException {
+
+    }
+
+    @Override
+    public void deletePackageVersioned(VersionedPackage versionedPackage,
+        IPackageDeleteObserver2 observer, int userId, int flags) throws RemoteException {
+
+    }
+
+    @Override
+    public String getInstallerPackageName(String packageName) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public void resetApplicationPreferences(int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public void setLastChosenActivity(Intent intent, String resolvedType, int flags,
+        IntentFilter filter, int match, ComponentName activity) throws RemoteException {
+
+    }
+
+    @Override
+    public void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set,
+        ComponentName activity, int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public void replacePreferredActivity(IntentFilter filter, int match, ComponentName[] set,
+        ComponentName activity, int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public void clearPackagePreferredActivities(String packageName) throws RemoteException {
+
+    }
+
+    @Override
+    public int getPreferredActivities(List<IntentFilter> outFilters,
+        List<ComponentName> outActivities, String packageName) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity,
+        int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public void clearPackagePersistentPreferredActivities(String packageName, int userId)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
+        int sourceUserId, int targetUserId, int flags) throws RemoteException {
+
+    }
+
+    @Override
+    public void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames,
+        int restrictionFlags, int userId) throws RemoteException {
+        return new String[0];
+    }
+
+    @Override
+    public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
+        PersistableBundle appExtras, PersistableBundle launcherExtras, SuspendDialogInfo dialogInfo,
+        String callingPackage, int userId) throws RemoteException {
+        return new String[0];
+    }
+
+    @Override
+    public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId)
+        throws RemoteException {
+        return new String[0];
+    }
+
+    @Override
+    public boolean isPackageSuspendedForUser(String packageName, int userId)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public PersistableBundle getSuspendedPackageAppExtras(String packageName, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public byte[] getPreferredActivityBackup(int userId) throws RemoteException {
+        return new byte[0];
+    }
+
+    @Override
+    public void restorePreferredActivities(byte[] backup, int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public byte[] getDefaultAppsBackup(int userId) throws RemoteException {
+        return new byte[0];
+    }
+
+    @Override
+    public void restoreDefaultApps(byte[] backup, int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public byte[] getIntentFilterVerificationBackup(int userId) throws RemoteException {
+        return new byte[0];
+    }
+
+    @Override
+    public void restoreIntentFilterVerification(byte[] backup, int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public byte[] getPermissionGrantBackup(int userId) throws RemoteException {
+        return new byte[0];
+    }
+
+    @Override
+    public void restorePermissionGrants(byte[] backup, int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public ComponentName getHomeActivities(List<ResolveInfo> outHomeCandidates)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public void setHomeActivity(ComponentName className, int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags,
+        int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public int getComponentEnabledSetting(ComponentName componentName, int userId)
+        throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public void setApplicationEnabledSetting(String packageName, int newState, int flags,
+        int userId,
+        String callingPackage) throws RemoteException {
+
+    }
+
+    @Override
+    public void logAppProcessStartIfNeeded(String processName, int uid, String seinfo,
+        String apkFile,
+        int pid) throws RemoteException {
+
+    }
+
+    @Override
+    public void flushPackageRestrictionsAsUser(int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public void setPackageStoppedState(String packageName, boolean stopped, int userId)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public void freeStorageAndNotify(String volumeUuid, long freeStorageSize, int storageFlags,
+        IPackageDataObserver observer) throws RemoteException {
+
+    }
+
+    @Override
+    public void freeStorage(String volumeUuid, long freeStorageSize, int storageFlags,
+        IntentSender pi) throws RemoteException {
+
+    }
+
+    @Override
+    public void deleteApplicationCacheFiles(String packageName, IPackageDataObserver observer)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public void deleteApplicationCacheFilesAsUser(String packageName, int userId,
+        IPackageDataObserver observer) throws RemoteException {
+
+    }
+
+    @Override
+    public void clearApplicationUserData(String packageName, IPackageDataObserver observer,
+        int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public void clearApplicationProfileData(String packageName) throws RemoteException {
+
+    }
+
+    @Override
+    public void getPackageSizeInfo(String packageName, int userHandle,
+        IPackageStatsObserver observer)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public String[] getSystemSharedLibraryNames() throws RemoteException {
+        return new String[0];
+    }
+
+    @Override
+    public ParceledListSlice getSystemAvailableFeatures() throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public boolean hasSystemFeature(String name, int version) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public void enterSafeMode() throws RemoteException {
+
+    }
+
+    @Override
+    public boolean isSafeMode() throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public void systemReady() throws RemoteException {
+
+    }
+
+    @Override
+    public boolean hasSystemUidErrors() throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public void performFstrimIfNeeded() throws RemoteException {
+
+    }
+
+    @Override
+    public void updatePackagesIfNeeded() throws RemoteException {
+
+    }
+
+    @Override
+    public void notifyPackageUse(String packageName, int reason) throws RemoteException {
+
+    }
+
+    @Override
+    public void notifyDexLoad(String loadingPackageName, List<String> classLoadersNames,
+        List<String> classPaths, String loaderIsa) throws RemoteException {
+
+    }
+
+    @Override
+    public void registerDexModule(String packageName, String dexModulePath, boolean isSharedModule,
+        IDexModuleRegisterCallback callback) throws RemoteException {
+
+    }
+
+    @Override
+    public boolean performDexOptMode(String packageName, boolean checkProfiles,
+        String targetCompilerFilter, boolean force, boolean bootComplete, String splitName)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean performDexOptSecondary(String packageName, String targetCompilerFilter,
+        boolean force) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean compileLayouts(String packageName) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public void dumpProfiles(String packageName) throws RemoteException {
+
+    }
+
+    @Override
+    public void forceDexOpt(String packageName) throws RemoteException {
+
+    }
+
+    @Override
+    public boolean runBackgroundDexoptJob(List<String> packageNames) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public void reconcileSecondaryDexFiles(String packageName) throws RemoteException {
+
+    }
+
+    @Override
+    public int getMoveStatus(int moveId) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public void registerMoveCallback(IPackageMoveObserver callback) throws RemoteException {
+
+    }
+
+    @Override
+    public void unregisterMoveCallback(IPackageMoveObserver callback) throws RemoteException {
+
+    }
+
+    @Override
+    public int movePackage(String packageName, String volumeUuid) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public int movePrimaryStorage(String volumeUuid) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public boolean addPermissionAsync(PermissionInfo info) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean setInstallLocation(int loc) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public int getInstallLocation() throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public int installExistingPackageAsUser(String packageName, int userId, int installFlags,
+        int installReason) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
+
+    }
+
+    @Override
+    public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
+        long millisecondsToDelay) throws RemoteException {
+
+    }
+
+    @Override
+    public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public int getIntentVerificationStatus(String packageName, int userId) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public boolean updateIntentVerificationStatus(String packageName, int status, int userId)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public ParceledListSlice getIntentFilterVerifications(String packageName)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ParceledListSlice getAllIntentFilters(String packageName) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public boolean setDefaultBrowserPackageName(String packageName, int userId)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public String getDefaultBrowserPackageName(int userId) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public boolean isFirstBoot() throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean isOnlyCoreApps() throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean isUpgrade() throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public void setPermissionEnforced(String permission, boolean enforced) throws RemoteException {
+
+    }
+
+    @Override
+    public boolean isPermissionEnforced(String permission) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean isStorageLow() throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean getApplicationHiddenSettingAsUser(String packageName, int userId)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public boolean setSystemAppInstallState(String packageName, boolean installed, int userId)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public IPackageInstaller getPackageInstaller() throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean getBlockUninstallForUser(String packageName, int userId) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public KeySet getKeySetByAlias(String packageName, String alias) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public KeySet getSigningKeySet(String packageName) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public boolean isPackageSignedByKeySet(String packageName, KeySet ks) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean isPackageSignedByKeySetExactly(String packageName, KeySet ks)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public void removeOnPermissionsChangeListener(IOnPermissionsChangeListener listener)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public void grantDefaultPermissionsToEnabledTelephonyDataServices(String[] packageNames,
+        int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(String[] packageNames,
+        int userId) throws RemoteException {
+
+    }
+
+    @Override
+    public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public String getPermissionControllerPackageName() throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ParceledListSlice getInstantApps(int userId) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public byte[] getInstantAppCookie(String packageName, int userId) throws RemoteException {
+        return new byte[0];
+    }
+
+    @Override
+    public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public Bitmap getInstantAppIcon(String packageName, int userId) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public boolean isInstantApp(String packageName, int userId) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean setRequiredForSystemUser(String packageName, boolean systemUserApp)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public void setUpdateAvailable(String packageName, boolean updateAvaialble)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public String getServicesSystemSharedLibraryPackageName() throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public String getSharedSystemSharedLibraryPackageName() throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ChangedPackages getChangedPackages(int sequenceNumber, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public boolean isPackageDeviceAdminOnAnyUser(String packageName) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public int getInstallReason(String packageName, int userId) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public ParceledListSlice getSharedLibraries(String packageName, int flags, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public boolean canRequestPackageInstalls(String packageName, int userId)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public void deletePreloadsFileCache() throws RemoteException {
+
+    }
+
+    @Override
+    public ComponentName getInstantAppResolverComponent() throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ComponentName getInstantAppResolverSettingsComponent() throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ComponentName getInstantAppInstallerComponent() throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public String getInstantAppAndroidId(String packageName, int userId) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public IArtManager getArtManager() throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public void setHarmfulAppWarning(String packageName, CharSequence warning, int userId)
+        throws RemoteException {
+
+    }
+
+    @Override
+    public CharSequence getHarmfulAppWarning(String packageName, int userId)
+        throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public boolean hasSigningCertificate(String packageName, byte[] signingCertificate, int flags)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean hasUidSigningCertificate(int uid, byte[] signingCertificate, int flags)
+        throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public String getSystemTextClassifierPackageName() throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public String getWellbeingPackageName() throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public boolean isPackageStateProtected(String packageName, int userId) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public void sendDeviceCustomizationReadyBroadcast() throws RemoteException {
+
+    }
+
+    @Override
+    public List<ModuleInfo> getInstalledModules(int flags) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public ModuleInfo getModuleInfo(String packageName, int flags) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public IBinder asBinder() {
+        return null;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
index 525135c..7172752 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
@@ -48,11 +48,7 @@
     @Override
     public PackageInfo getPackageInfo(String packageName, int flags)
             throws NameNotFoundException {
-        if (sPackageInfo == null) {
-            throw new NameNotFoundException();
-        }
-
-        return sPackageInfo;
+        return getPackageInfoAsUser(packageName, flags, UserHandle.USER_SYSTEM);
     }
 
     @Override
@@ -64,7 +60,11 @@
     @Override
     public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
             throws NameNotFoundException {
-        return null;
+        if (sPackageInfo == null) {
+            throw new NameNotFoundException();
+        }
+
+        return sPackageInfo;
     }
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
index 479a19b..a92b576 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
@@ -29,13 +29,14 @@
 import android.content.pm.Signature;
 import android.content.pm.SigningInfo;
 import android.os.Process;
+import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.backup.UserBackupManagerService;
-import com.android.server.backup.testutils.PackageManagerStub;
+import com.android.server.backup.testutils.IPackageManagerStub;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -53,13 +54,17 @@
     private static final Signature SIGNATURE_3 = generateSignature((byte) 3);
     private static final Signature SIGNATURE_4 = generateSignature((byte) 4);
 
-    private PackageManagerStub mPackageManagerStub;
+    private IPackageManagerStub mPackageManagerStub;
     private PackageManagerInternal mMockPackageManagerInternal;
 
+    private int mUserId;
+
     @Before
     public void setUp() throws Exception {
-        mPackageManagerStub = new PackageManagerStub();
+        mPackageManagerStub = new IPackageManagerStub();
         mMockPackageManagerInternal = mock(PackageManagerInternal.class);
+
+        mUserId = UserHandle.USER_SYSTEM;
     }
 
     @Test
@@ -71,7 +76,7 @@
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub);
+                mPackageManagerStub, mUserId);
 
         assertThat(isEligible).isFalse();
     }
@@ -86,7 +91,7 @@
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub);
+                mPackageManagerStub, mUserId);
 
         assertThat(isEligible).isFalse();
     }
@@ -100,7 +105,7 @@
         applicationInfo.packageName = UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub);
+                mPackageManagerStub, mUserId);
 
         assertThat(isEligible).isFalse();
     }
@@ -114,11 +119,11 @@
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
-        PackageManagerStub.sApplicationEnabledSetting =
+        IPackageManagerStub.sApplicationEnabledSetting =
                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub);
+                mPackageManagerStub, mUserId);
 
         assertThat(isEligible).isTrue();
     }
@@ -132,11 +137,11 @@
         applicationInfo.backupAgentName = null;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
-        PackageManagerStub.sApplicationEnabledSetting =
+        IPackageManagerStub.sApplicationEnabledSetting =
                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub);
+                mPackageManagerStub, mUserId);
 
         assertThat(isEligible).isTrue();
     }
@@ -150,11 +155,11 @@
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
-        PackageManagerStub.sApplicationEnabledSetting =
+        IPackageManagerStub.sApplicationEnabledSetting =
                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub);
+                mPackageManagerStub, mUserId);
 
         assertThat(isEligible).isTrue();
     }
@@ -168,11 +173,11 @@
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
-        PackageManagerStub.sApplicationEnabledSetting =
+        IPackageManagerStub.sApplicationEnabledSetting =
                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub);
+                mPackageManagerStub, mUserId);
 
         assertThat(isEligible).isFalse();
     }
@@ -186,11 +191,11 @@
         applicationInfo.backupAgentName = null;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
-        PackageManagerStub.sApplicationEnabledSetting =
+        IPackageManagerStub.sApplicationEnabledSetting =
                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub);
+                mPackageManagerStub, mUserId);
 
         assertThat(isEligible).isFalse();
     }
@@ -204,11 +209,11 @@
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
-        PackageManagerStub.sApplicationEnabledSetting =
+        IPackageManagerStub.sApplicationEnabledSetting =
                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub);
+                mPackageManagerStub, mUserId);
 
         assertThat(isEligible).isFalse();
     }
@@ -222,10 +227,11 @@
         applicationInfo.packageName = TEST_PACKAGE_NAME;
         applicationInfo.enabled = true;
 
-        PackageManagerStub.sApplicationEnabledSetting =
+        IPackageManagerStub.sApplicationEnabledSetting =
                 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 
-        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub);
+        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub,
+            mUserId);
 
         assertThat(isDisabled).isFalse();
     }
@@ -239,10 +245,11 @@
         applicationInfo.packageName = TEST_PACKAGE_NAME;
         applicationInfo.enabled = false;
 
-        PackageManagerStub.sApplicationEnabledSetting =
+        IPackageManagerStub.sApplicationEnabledSetting =
                 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 
-        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub);
+        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub,
+            mUserId);
 
         assertThat(isDisabled).isTrue();
     }
@@ -255,10 +262,11 @@
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
-        PackageManagerStub.sApplicationEnabledSetting =
+        IPackageManagerStub.sApplicationEnabledSetting =
                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
-        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub);
+        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub,
+            mUserId);
 
         assertThat(isDisabled).isFalse();
     }
@@ -271,10 +279,11 @@
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
-        PackageManagerStub.sApplicationEnabledSetting =
+        IPackageManagerStub.sApplicationEnabledSetting =
                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 
-        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub);
+        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub,
+            mUserId);
 
         assertThat(isDisabled).isTrue();
     }
@@ -287,10 +296,11 @@
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
-        PackageManagerStub.sApplicationEnabledSetting =
+        IPackageManagerStub.sApplicationEnabledSetting =
                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 
-        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub);
+        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub,
+            mUserId);
 
         assertThat(isDisabled).isTrue();
     }
@@ -303,10 +313,11 @@
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
-        PackageManagerStub.sApplicationEnabledSetting =
+        IPackageManagerStub.sApplicationEnabledSetting =
                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
 
-        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub);
+        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub,
+            mUserId);
 
         assertThat(isDisabled).isTrue();
     }
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
index d43b677..5fcce67 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
@@ -44,6 +44,7 @@
 import android.content.pm.SigningInfo;
 import android.os.Bundle;
 import android.os.Process;
+import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.InstrumentationRegistry;
@@ -88,12 +89,14 @@
 
     private final PackageManagerStub mPackageManagerStub = new PackageManagerStub();
     private Context mContext;
+    private int mUserId;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
         mContext = InstrumentationRegistry.getContext();
+        mUserId = UserHandle.USER_SYSTEM;
     }
 
     @Test
@@ -146,7 +149,7 @@
                 fileMetadata);
         RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy(
                 mPackageManagerStub, false /* allowApks */, fileMetadata, signatures,
-                mMockPackageManagerInternal);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE);
         assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME);
@@ -160,7 +163,7 @@
                 fileMetadata);
         restorePolicy = tarBackupReader.chooseRestorePolicy(
                 mPackageManagerStub, false /* allowApks */, fileMetadata, signatures,
-                mMockPackageManagerInternal);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE);
         assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME);
@@ -223,7 +226,7 @@
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
                 true /* allowApks */, new FileMetadata(), null /* signatures */,
-                mMockPackageManagerInternal);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
         verifyZeroInteractions(mBackupManagerMonitorMock);
@@ -244,7 +247,7 @@
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
                 true /* allowApks */, info, new Signature[0] /* signatures */,
-                mMockPackageManagerInternal);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -269,7 +272,7 @@
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
                 true /* allowApks */, info, new Signature[0] /* signatures */,
-                mMockPackageManagerInternal);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -295,7 +298,7 @@
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
                 false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */,
-                mMockPackageManagerInternal);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -320,7 +323,7 @@
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
                 false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */,
-                mMockPackageManagerInternal);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -347,7 +350,7 @@
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
                 false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */,
-                mMockPackageManagerInternal);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -381,7 +384,8 @@
         PackageManagerStub.sPackageInfo = packageInfo;
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal);
+                false /* allowApks */, new FileMetadata(), signatures,
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -419,7 +423,8 @@
         doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
                 packageInfo.packageName);
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal);
+                false /* allowApks */, new FileMetadata(), signatures,
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(policy).isEqualTo(RestorePolicy.ACCEPT);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -456,7 +461,8 @@
         doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
                 packageInfo.packageName);
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal);
+                false /* allowApks */, new FileMetadata(), signatures,
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(policy).isEqualTo(RestorePolicy.ACCEPT);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -497,7 +503,8 @@
         doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
                 packageInfo.packageName);
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                false /* allowApks */, info, signatures, mMockPackageManagerInternal);
+                false /* allowApks */, info, signatures, mMockPackageManagerInternal,
+                mUserId);
 
         assertThat(policy).isEqualTo(RestorePolicy.ACCEPT);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -540,7 +547,8 @@
         doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
                 packageInfo.packageName);
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                true /* allowApks */, info, signatures, mMockPackageManagerInternal);
+                true /* allowApks */, info, signatures, mMockPackageManagerInternal,
+                mUserId);
 
         assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK);
         verifyNoMoreInteractions(mBackupManagerMonitorMock);
@@ -579,7 +587,8 @@
         doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
                 packageInfo.packageName);
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                false /* allowApks */, info, signatures, mMockPackageManagerInternal);
+                false /* allowApks */, info, signatures, mMockPackageManagerInternal,
+                mUserId);
 
         assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 38e8ac2..0813e6fa 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -206,6 +206,8 @@
         mAdmin1Context.binder.callingUid = DpmMockContext.CALLER_UID;
 
         setUpUserManager();
+
+        when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(true);
     }
 
     private TransferOwnershipMetadataManager getMockTransferMetadataManager() {
@@ -836,6 +838,7 @@
                 MockUtils.checkIntent(intent),
                 MockUtils.checkUserHandle(MANAGED_PROFILE_USER_ID));
     }
+
     /**
      * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs successfully.
      */
@@ -2618,6 +2621,7 @@
         when(getServices().lockPatternUtils
                 .isSeparateProfileChallengeEnabled(eq(PROFILE_USER))).thenReturn(false);
         dpmi.reportSeparateProfileChallengeChanged(PROFILE_USER);
+        when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(true);
 
         verifyScreenTimeoutCall(Long.MAX_VALUE, PROFILE_USER);
         verifyScreenTimeoutCall(10L , UserHandle.USER_SYSTEM);
@@ -4233,6 +4237,41 @@
         assertTrue(dpm.isActivePasswordSufficient());
     }
 
+    public void testIsActivePasswordSufficient_noLockScreen() throws Exception {
+        // If there is no lock screen, the password is considered empty no matter what, because
+        // it provides no security.
+        when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(false);
+
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        mContext.packageName = admin1.getPackageName();
+        setupDeviceOwner();
+
+        // If no password requirements are set, isActivePasswordSufficient should succeed.
+        assertTrue(dpm.isActivePasswordSufficient());
+
+        // Now set some password quality requirements.
+        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+
+        reset(mContext.spiedContext);
+        final int userHandle = UserHandle.getUserId(mContext.binder.callingUid);
+        PasswordMetrics passwordMetricsNoSymbols = new PasswordMetrics(
+                DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 9,
+                8, 2,
+                6, 1,
+                0, 1);
+        // This should be ignored, as there is no lock screen.
+        dpm.setActivePasswordState(passwordMetricsNoSymbols, userHandle);
+        dpm.reportPasswordChanged(userHandle);
+
+        // No broadcast should be sent.
+        verify(mContext.spiedContext, times(0)).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED),
+                MockUtils.checkUserHandle(userHandle));
+
+        // The active (nonexistent) password doesn't comply with the requirements.
+        assertFalse(dpm.isActivePasswordSufficient());
+    }
+
     private void setActivePasswordState(PasswordMetrics passwordMetrics)
             throws Exception {
         final int userHandle = UserHandle.getUserId(mContext.binder.callingUid);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java
index 34edd9f..757a046 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java
@@ -32,7 +32,6 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
-import android.os.RemoteException;
 import android.test.AndroidTestCase;
 import android.test.mock.MockPackageManager;
 import android.view.inputmethod.InputMethodInfo;
@@ -40,7 +39,6 @@
 import androidx.test.InstrumentationRegistry;
 
 import com.android.internal.R;
-import com.android.internal.view.IInputMethodManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -61,8 +59,8 @@
 
     private @Mock
     Resources mResources;
-    private @Mock
-    IInputMethodManager mIInputMethodManager;
+    @Mock
+    private OverlayPackagesProvider.Injector mInjector;
     private @Mock
     Context mTestContext;
     private Resources mRealResources;
@@ -81,6 +79,7 @@
                 InstrumentationRegistry.getTargetContext().getCacheDir());
 
         setSystemInputMethods();
+        setIsPerProfileModeEnabled(false);
         setRequiredAppsManagedDevice();
         setVendorRequiredAppsManagedDevice();
         setDisallowedAppsManagedDevice();
@@ -95,7 +94,7 @@
         setVendorDisallowedAppsManagedUser();
 
         mRealResources = InstrumentationRegistry.getTargetContext().getResources();
-        mHelper = new OverlayPackagesProvider(mTestContext, mIInputMethodManager);
+        mHelper = new OverlayPackagesProvider(mTestContext, mInjector);
     }
 
     @Test
@@ -165,6 +164,15 @@
     }
 
     @Test
+    public void testProfileOwnerImesAreRequiredForPerProfileImeMode() {
+        setSystemAppsWithLauncher("app.a", "app.b");
+        setSystemInputMethods("app.a");
+        setIsPerProfileModeEnabled(true);
+
+        verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_PROFILE, "app.b");
+    }
+
+    @Test
     public void testManagedUserImesAreRequired() {
         setSystemAppsWithLauncher("app.a", "app.b");
         setSystemInputMethods("app.a");
@@ -333,11 +341,11 @@
             InputMethodInfo inputMethodInfo = new InputMethodInfo(ri, false, null, null, 0, false);
             inputMethods.add(inputMethodInfo);
         }
-        try {
-            when(mIInputMethodManager.getInputMethodList()).thenReturn(inputMethods);
-        } catch (RemoteException e) {
-            fail(e.toString());
-        }
+        when(mInjector.getInputMethodListAsUser(eq(TEST_USER_ID))).thenReturn(inputMethods);
+    }
+
+    private void setIsPerProfileModeEnabled(boolean enabled) {
+        when(mInjector.isPerProfileImeEnabled()).thenReturn(enabled);
     }
 
     private void setSystemAppsWithLauncher(String... apps) {
diff --git a/services/tests/servicestests/src/com/android/server/display/AppSaturationControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AppSaturationControllerTest.java
new file mode 100644
index 0000000..e518844
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/AppSaturationControllerTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static com.android.server.display.AppSaturationController.TRANSLATION_VECTOR;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.os.UserHandle;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.display.ColorDisplayService.ColorTransformController;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.lang.ref.WeakReference;
+
+@RunWith(AndroidJUnit4.class)
+public class AppSaturationControllerTest {
+
+    private static final String TEST_PACKAGE_NAME = "com.android.test";
+
+    private int mUserId;
+    private AppSaturationController mAppSaturationController;
+    private float[] mMatrix;
+
+    @Mock
+    private ColorTransformController mColorTransformController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mUserId = ActivityManager.getCurrentUser();
+        mAppSaturationController = new AppSaturationController();
+        mMatrix = new float[9];
+    }
+
+    @After
+    public void tearDown() {
+        mAppSaturationController = null;
+        mUserId = UserHandle.USER_NULL;
+    }
+
+    @Test
+    public void addColorTransformController_appliesExistingSaturation() {
+        final WeakReference<ColorTransformController> ref = new WeakReference<>(
+                mColorTransformController);
+        mAppSaturationController.setSaturationLevel(TEST_PACKAGE_NAME, mUserId, 30);
+        mAppSaturationController.addColorTransformController(TEST_PACKAGE_NAME, mUserId, ref);
+        AppSaturationController.computeGrayscaleTransformMatrix(.3f, mMatrix);
+        verify(mColorTransformController).applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR));
+    }
+
+    @Test
+    public void setSaturationLevel_resetToDefault() {
+        final WeakReference<ColorTransformController> ref = new WeakReference<>(
+                mColorTransformController);
+        mAppSaturationController.addColorTransformController(TEST_PACKAGE_NAME, mUserId, ref);
+        verify(mColorTransformController, never())
+                .applyAppSaturation(any(), eq(TRANSLATION_VECTOR));
+        mAppSaturationController.setSaturationLevel(TEST_PACKAGE_NAME, mUserId, 30);
+        AppSaturationController.computeGrayscaleTransformMatrix(.3f, mMatrix);
+        verify(mColorTransformController, times(1))
+                .applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR));
+        mAppSaturationController.setSaturationLevel(TEST_PACKAGE_NAME, mUserId, 100);
+        AppSaturationController.computeGrayscaleTransformMatrix(1.0f, mMatrix);
+        verify(mColorTransformController, times(2))
+                .applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR));
+    }
+
+    @Test
+    public void setSaturationLevel_updateLevel() {
+        final WeakReference<ColorTransformController> ref = new WeakReference<>(
+                mColorTransformController);
+        mAppSaturationController.addColorTransformController(TEST_PACKAGE_NAME, mUserId, ref);
+        verify(mColorTransformController, never())
+                .applyAppSaturation(any(), eq(TRANSLATION_VECTOR));
+        mAppSaturationController.setSaturationLevel(TEST_PACKAGE_NAME, mUserId, 30);
+        AppSaturationController.computeGrayscaleTransformMatrix(.3f, mMatrix);
+        verify(mColorTransformController).applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR));
+        mAppSaturationController.setSaturationLevel(TEST_PACKAGE_NAME, mUserId, 70);
+        AppSaturationController.computeGrayscaleTransformMatrix(.7f, mMatrix);
+        verify(mColorTransformController, times(2))
+                .applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR));
+        mAppSaturationController.setSaturationLevel(TEST_PACKAGE_NAME, mUserId, 100);
+        AppSaturationController.computeGrayscaleTransformMatrix(1.0f, mMatrix);
+        verify(mColorTransformController, times(3))
+                .applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index abf9040..4742a73 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -389,7 +389,7 @@
         if (attr == null) return; //sampling not supported on device, skip remainder of test.
 
         boolean enabled = displayManager.setDisplayedContentSamplingEnabledInternal(0, true, 0, 0);
-        assertTrue(!enabled);
+        assertTrue(enabled);
 
         displayManager.setDisplayedContentSamplingEnabledInternal(0, false, 0, 0);
         DisplayedContentSample sample = displayManager.getDisplayedContentSampleInternal(0, 0, 0);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
new file mode 100644
index 0000000..eb9b98e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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.hdmi;
+
+import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.annotation.Nullable;
+import android.app.Instrumentation;
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
+import android.os.Looper;
+import android.os.test.TestLooper;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+
+/** Tests for {@link ArcInitiationActionFromAvrTest} */
+@SmallTest
+@RunWith(JUnit4.class)
+public class ArcInitiationActionFromAvrTest {
+
+    private HdmiDeviceInfo mDeviceInfoForTests;
+    private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
+    private HdmiCecController mHdmiCecController;
+    private HdmiControlService mHdmiControlService;
+    private FakeNativeWrapper mNativeWrapper;
+    private ArcInitiationActionFromAvr mAction;
+
+    private TestLooper mTestLooper = new TestLooper();
+    private boolean mSendCecCommandSuccess;
+    private boolean mShouldDispatchARCInitiated;
+    private boolean mArcInitSent;
+    private boolean mRequestActiveSourceSent;
+    private Instrumentation mInstrumentation;
+    private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
+
+    @Before
+    public void setUp() {
+        mDeviceInfoForTests = new HdmiDeviceInfo(1000, 1);
+
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+
+        mHdmiControlService =
+                new HdmiControlService(mInstrumentation.getTargetContext()) {
+                    @Override
+                    void sendCecCommand(
+                            HdmiCecMessage command, @Nullable SendMessageCallback callback) {
+                        switch (command.getOpcode()) {
+                            case Constants.MESSAGE_REQUEST_ACTIVE_SOURCE:
+                                if (callback != null) {
+                                    callback.onSendCompleted(
+                                            mSendCecCommandSuccess
+                                                    ? SendMessageResult.SUCCESS
+                                                    : SendMessageResult.NACK);
+                                }
+                                mRequestActiveSourceSent = true;
+                                break;
+                            case Constants.MESSAGE_INITIATE_ARC:
+                                if (callback != null) {
+                                    callback.onSendCompleted(
+                                            mSendCecCommandSuccess
+                                                    ? SendMessageResult.SUCCESS
+                                                    : SendMessageResult.NACK);
+                                }
+                                mArcInitSent = true;
+                                if (mShouldDispatchARCInitiated) {
+                                    mHdmiCecLocalDeviceAudioSystem.dispatchMessage(
+                                            HdmiCecMessageBuilder.buildReportArcInitiated(
+                                                    Constants.ADDR_TV,
+                                                    Constants.ADDR_AUDIO_SYSTEM));
+                                }
+                                break;
+                            default:
+                        }
+                    }
+
+                    @Override
+                    boolean isPowerStandby() {
+                        return false;
+                    }
+
+                    @Override
+                    boolean isAddressAllocated() {
+                        return true;
+                    }
+
+                    @Override
+                    Looper getServiceLooper() {
+                        return mTestLooper.getLooper();
+                    }
+                };
+
+        mHdmiCecLocalDeviceAudioSystem =
+                new HdmiCecLocalDeviceAudioSystem(mHdmiControlService) {
+                    @Override
+                    HdmiDeviceInfo getDeviceInfo() {
+                        return mDeviceInfoForTests;
+                    }
+
+                    @Override
+                    void setArcStatus(boolean enabled) {
+                        // do nothing
+                    }
+
+                    @Override
+                    protected boolean isSystemAudioActivated() {
+                        return true;
+                    }
+                };
+
+        mHdmiCecLocalDeviceAudioSystem.init();
+        Looper looper = mTestLooper.getLooper();
+        mHdmiControlService.setIoLooper(looper);
+        mNativeWrapper = new FakeNativeWrapper();
+        mHdmiCecController =
+                HdmiCecController.createWithNativeWrapper(this.mHdmiControlService, mNativeWrapper);
+        mHdmiControlService.setCecController(mHdmiCecController);
+        mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
+        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
+        mHdmiControlService.initPortInfo();
+        mAction = new ArcInitiationActionFromAvr(mHdmiCecLocalDeviceAudioSystem);
+
+        mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+    }
+
+    @Ignore("b/120845532")
+    @Test
+    public void arcInitiation_requestActiveSource() {
+        mSendCecCommandSuccess = true;
+        mShouldDispatchARCInitiated = true;
+        mRequestActiveSourceSent = false;
+        mArcInitSent = false;
+
+        mHdmiCecLocalDeviceAudioSystem.addAndStartAction(mAction);
+        mTestLooper.dispatchAll();
+
+        assertThat(mArcInitSent).isTrue();
+        assertThat(mRequestActiveSourceSent).isTrue();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
index 7484edd..8607ec6 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
@@ -18,8 +18,12 @@
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.MessageQueue;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.hdmi.HdmiCecController.NativeWrapper;
+
+import com.google.common.collect.Iterables;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -45,8 +49,8 @@
             };
 
     private final List<HdmiCecMessage> mResultMessages = new ArrayList<>();
-    private HdmiCecMessage mResultMessage;
     private int mMyPhysicalAddress = 0;
+    private HdmiPortInfo[] mHdmiPortInfo = null;
 
     @Override
     public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) {
@@ -89,9 +93,11 @@
 
     @Override
     public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) {
-        HdmiPortInfo[] hdmiPortInfo = new HdmiPortInfo[1];
-        hdmiPortInfo[0] = new HdmiPortInfo(1, 1, 0x1000, true, true, true);
-        return hdmiPortInfo;
+        if (mHdmiPortInfo == null) {
+            mHdmiPortInfo = new HdmiPortInfo[1];
+            mHdmiPortInfo[0] = new HdmiPortInfo(1, 1, 0x1000, true, true, true);
+        }
+        return mHdmiPortInfo;
     }
 
     @Override
@@ -112,11 +118,12 @@
         return new ArrayList<>(mResultMessages);
     }
 
-    public HdmiCecMessage getOnlyResultMessage() throws Exception {
-        if (mResultMessages.size() != 1) {
-            throw new Exception("There is not exactly one message");
-        }
-        return mResultMessages.get(0);
+    public HdmiCecMessage getOnlyResultMessage() throws IllegalArgumentException {
+        return Iterables.getOnlyElement(mResultMessages);
+    }
+
+    public void clearResultMessages() {
+        mResultMessages.clear();
     }
 
     public void setPollAddressResponse(int logicalAddress, int response) {
@@ -127,4 +134,10 @@
     protected void setPhysicalAddress(int physicalAddress) {
         mMyPhysicalAddress = physicalAddress;
     }
+
+    @VisibleForTesting
+    protected void setPortInfo(HdmiPortInfo[] hdmiPortInfo) {
+        mHdmiPortInfo = new HdmiPortInfo[hdmiPortInfo.length];
+        System.arraycopy(hdmiPortInfo, 0, mHdmiPortInfo, 0, hdmiPortInfo.length);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
index da840be..5d8131f 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -18,6 +18,7 @@
 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM;
 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_PLAYBACK;
 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV;
+
 import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
@@ -25,15 +26,19 @@
 import static com.android.server.hdmi.Constants.ADDR_SPECIFIC_USE;
 import static com.android.server.hdmi.Constants.ADDR_TV;
 import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
+
 import static junit.framework.Assert.assertEquals;
 
 import android.content.Context;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.Looper;
 import android.os.test.TestLooper;
+
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
+
 import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 9e3a0ea..a89198a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -15,23 +15,29 @@
  */
 package com.android.server.hdmi;
 
+import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE;
+import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE;
+
 import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
 import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
+import static com.android.server.hdmi.Constants.ADDR_TUNER_1;
 import static com.android.server.hdmi.Constants.ADDR_TV;
 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
 import static com.android.server.hdmi.HdmiControlService.STANDBY_SCREEN_OFF;
+
 import static com.google.common.truth.Truth.assertThat;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.HdmiPortInfo;
 import android.media.AudioManager;
 import android.os.Looper;
-import android.os.SystemProperties;
 import android.os.test.TestLooper;
+
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
+
 import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
 
 import org.junit.Before;
@@ -41,7 +47,6 @@
 import org.junit.runners.JUnit4;
 
 import java.util.ArrayList;
-
 @SmallTest
 @RunWith(JUnit4.class)
 /** Tests for {@link HdmiCecLocalDeviceAudioSystem} class. */
@@ -54,6 +59,7 @@
     private HdmiControlService mHdmiControlService;
     private HdmiCecController mHdmiCecController;
     private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
+    private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
     private FakeNativeWrapper mNativeWrapper;
     private Looper mMyLooper;
     private TestLooper mTestLooper = new TestLooper();
@@ -61,90 +67,156 @@
     private int mMusicVolume;
     private int mMusicMaxVolume;
     private boolean mMusicMute;
+    private static final int SELF_PHYSICAL_ADDRESS = 0x2000;
+    private static final int HDMI_1_PHYSICAL_ADDRESS = 0x2100;
+    private static final int HDMI_2_PHYSICAL_ADDRESS = 0x2200;
+    private static final int HDMI_3_PHYSICAL_ADDRESS = 0x2300;
+    private int mInvokeDeviceEventState;
+    private HdmiDeviceInfo mDeviceInfo;
+    private boolean mMutingEnabled;
+    private boolean mArcSupport;
+    private HdmiPortInfo[] mHdmiPortInfo;
 
     @Before
     public void setUp() {
         mHdmiControlService =
-                new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
-                    @Override
-                    AudioManager getAudioManager() {
-                        return new AudioManager() {
-                            @Override
-                            public int getStreamVolume(int streamType) {
-                                switch (streamType) {
-                                    case STREAM_MUSIC:
-                                        return mMusicVolume;
-                                    default:
-                                        return 0;
-                                }
+            new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
+                @Override
+                AudioManager getAudioManager() {
+                    return new AudioManager() {
+                        @Override
+                        public int getStreamVolume(int streamType) {
+                            switch (streamType) {
+                                case STREAM_MUSIC:
+                                    return mMusicVolume;
+                                default:
+                                    return 0;
                             }
+                        }
 
-                            @Override
-                            public boolean isStreamMute(int streamType) {
-                                switch (streamType) {
-                                    case STREAM_MUSIC:
-                                        return mMusicMute;
-                                    default:
-                                        return false;
-                                }
+                        @Override
+                        public boolean isStreamMute(int streamType) {
+                            switch (streamType) {
+                                case STREAM_MUSIC:
+                                    return mMusicMute;
+                                default:
+                                    return false;
                             }
+                        }
 
-                            @Override
-                            public int getStreamMaxVolume(int streamType) {
-                                switch (streamType) {
-                                    case STREAM_MUSIC:
-                                        return mMusicMaxVolume;
-                                    default:
-                                        return 100;
-                                }
+                        @Override
+                        public int getStreamMaxVolume(int streamType) {
+                            switch (streamType) {
+                                case STREAM_MUSIC:
+                                    return mMusicMaxVolume;
+                                default:
+                                    return 100;
                             }
+                        }
 
-                            @Override
-                            public void adjustStreamVolume(
-                                    int streamType, int direction, int flags) {
-                                switch (streamType) {
-                                    case STREAM_MUSIC:
-                                        if (direction == AudioManager.ADJUST_UNMUTE) {
-                                            mMusicMute = false;
-                                        } else if (direction == AudioManager.ADJUST_MUTE) {
-                                            mMusicMute = true;
-                                        }
-                                    default:
-                                }
+                        @Override
+                        public void adjustStreamVolume(
+                                int streamType, int direction, int flags) {
+                            switch (streamType) {
+                                case STREAM_MUSIC:
+                                    if (direction == AudioManager.ADJUST_UNMUTE) {
+                                        mMusicMute = false;
+                                    } else if (direction == AudioManager.ADJUST_MUTE) {
+                                        mMusicMute = true;
+                                    }
+                                    break;
+                                default:
                             }
+                        }
 
-                            @Override
-                            public void setWiredDeviceConnectionState(
+                        @Override
+                        public void setWiredDeviceConnectionState(
                                 int type, int state, String address, String name) {
-                                // Do nothing.
-                            }
-                        };
-                    }
+                            // Do nothing.
+                        }
+                    };
+                }
 
-                    @Override
-                    void wakeUp() {}
-                };
+                @Override
+                void wakeUp() {}
+
+                @Override
+                void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) {
+                    mDeviceInfo = device;
+                    mInvokeDeviceEventState = status;
+                }
+
+                @Override
+                void writeStringSystemProperty(String key, String value) {
+                    // do nothing
+                }
+
+                @Override
+                boolean readBooleanSystemProperty(String key, boolean defVal) {
+                    switch (key) {
+                        case Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE:
+                            return mMutingEnabled;
+                        case Constants.PROPERTY_ARC_SUPPORT:
+                            return mArcSupport;
+                        default:
+                            return defVal;
+                    }
+                }
+            };
 
         mMyLooper = mTestLooper.getLooper();
         mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService);
+        mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
+            @Override
+            void setIsActiveSource(boolean on) {
+                mIsActiveSource = on;
+            }
+
+            @Override
+            protected int getPreferredAddress() {
+                return ADDR_PLAYBACK_1;
+            }
+        };
         mHdmiCecLocalDeviceAudioSystem.init();
+        mHdmiCecLocalDevicePlayback.init();
         mHdmiControlService.setIoLooper(mMyLooper);
         mNativeWrapper = new FakeNativeWrapper();
+        mNativeWrapper.setPhysicalAddress(SELF_PHYSICAL_ADDRESS);
         mHdmiCecController =
-                HdmiCecController.createWithNativeWrapper(mHdmiControlService, mNativeWrapper);
+            HdmiCecController.createWithNativeWrapper(mHdmiControlService, mNativeWrapper);
         mHdmiControlService.setCecController(mHdmiCecController);
         mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
         mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
         mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
+        mLocalDevices.add(mHdmiCecLocalDevicePlayback);
+        mHdmiCecLocalDeviceAudioSystem.setRoutingControlFeatureEnables(true);
+        mHdmiPortInfo = new HdmiPortInfo[4];
+        mHdmiPortInfo[0] =
+            new HdmiPortInfo(
+                0, HdmiPortInfo.PORT_INPUT, SELF_PHYSICAL_ADDRESS, true, false, false);
+        mHdmiPortInfo[1] =
+            new HdmiPortInfo(
+                2, HdmiPortInfo.PORT_INPUT, HDMI_1_PHYSICAL_ADDRESS, true, false, false);
+        mHdmiPortInfo[2] =
+            new HdmiPortInfo(
+                1, HdmiPortInfo.PORT_INPUT, HDMI_2_PHYSICAL_ADDRESS, true, false, false);
+        mHdmiPortInfo[3] =
+            new HdmiPortInfo(
+                4, HdmiPortInfo.PORT_INPUT, HDMI_3_PHYSICAL_ADDRESS, true, false, false);
+        mNativeWrapper.setPortInfo(mHdmiPortInfo);
         mHdmiControlService.initPortInfo();
         // No TV device interacts with AVR so system audio control won't be turned on here
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTestLooper.dispatchAll();
-        SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "true");
+        mNativeWrapper.clearResultMessages();
+        mMutingEnabled = true;
+        mArcSupport = true;
+        mInvokeDeviceEventState = 0;
+        mDeviceInfo = null;
     }
 
     @Test
-    public void handleGiveAudioStatus_volume_10_mute_true() {
+    public void handleGiveAudioStatus_volume_10_mute_true() throws Exception {
         mMusicVolume = 10;
         mMusicMute = true;
         mMusicMaxVolume = 20;
@@ -154,25 +226,24 @@
                         ADDR_AUDIO_SYSTEM, ADDR_TV, scaledVolume, true);
         HdmiCecMessage messageGive =
                 HdmiCecMessageBuilder.buildGiveAudioStatus(ADDR_TV, ADDR_AUDIO_SYSTEM);
-        assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(messageGive))
-                .isTrue();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveAudioStatus(messageGive)).isTrue();
         mTestLooper.dispatchAll();
-        assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
 
     @Test
-    public void handleGiveSystemAudioModeStatus_originalOff() {
+    public void handleGiveSystemAudioModeStatus_originalOff() throws Exception {
         HdmiCecMessage expectedMessage =
-                HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
+                HdmiCecMessageBuilder.buildReportSystemAudioMode(
+                        ADDR_AUDIO_SYSTEM, ADDR_TV, false);
         HdmiCecMessage messageGive =
                 HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(ADDR_TV, ADDR_AUDIO_SYSTEM);
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
-                .isTrue();
+            .isTrue();
         mTestLooper.dispatchAll();
-        assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
 
-    @Ignore("b/80297700")
     @Test
     public void handleRequestShortAudioDescriptor_featureDisabled() throws Exception {
         HdmiCecMessage expectedMessage =
@@ -184,9 +255,9 @@
 
         mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(false);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor(
-                                MESSAGE_REQUEST_SAD_LCPM))
-                .isTrue();
+            mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor(
+                MESSAGE_REQUEST_SAD_LCPM))
+            .isTrue();
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
@@ -200,15 +271,17 @@
                         Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR,
                         Constants.ABORT_NOT_IN_CORRECT_MODE);
 
-        mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(false);
+        mHdmiCecLocalDeviceAudioSystem.checkSupportAndSetSystemAudioMode(false);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor(
-                                MESSAGE_REQUEST_SAD_LCPM))
-                .isEqualTo(true);
+            mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor(
+                MESSAGE_REQUEST_SAD_LCPM))
+            .isEqualTo(true);
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
 
+    // Testing device has sadConfig.xml
+    @Ignore("b/120845532")
     @Test
     public void handleRequestShortAudioDescriptor_noAudioDeviceInfo() throws Exception {
         HdmiCecMessage expectedMessage =
@@ -218,17 +291,17 @@
                         Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR,
                         Constants.ABORT_UNABLE_TO_DETERMINE);
 
-        mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true);
+        mHdmiCecLocalDeviceAudioSystem.checkSupportAndSetSystemAudioMode(true);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor(
-                                MESSAGE_REQUEST_SAD_LCPM))
-                .isEqualTo(true);
+            mHdmiCecLocalDeviceAudioSystem.handleRequestShortAudioDescriptor(
+                MESSAGE_REQUEST_SAD_LCPM))
+            .isEqualTo(true);
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
     }
 
     @Test
-    public void handleSetSystemAudioMode_setOn_orignalOff() {
+    public void handleSetSystemAudioMode_setOn_orignalOff() throws Exception {
         mMusicMute = true;
         HdmiCecMessage messageSet =
                 HdmiCecMessageBuilder.buildSetSystemAudioMode(ADDR_TV, ADDR_AUDIO_SYSTEM, true);
@@ -238,25 +311,24 @@
         HdmiCecMessage expectedMessage =
                 HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
-                .isTrue();
+            .isTrue();
         mTestLooper.dispatchAll();
-        assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
         // Check if correctly turned on
+        mNativeWrapper.clearResultMessages();
         expectedMessage =
-                HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, true);
-        assertThat(mHdmiCecLocalDeviceAudioSystem.handleSetSystemAudioMode(messageSet))
-                .isTrue();
+            HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, true);
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleSetSystemAudioMode(messageSet)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
-                .isTrue();
+            .isTrue();
         mTestLooper.dispatchAll();
-        assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
         assertThat(mMusicMute).isFalse();
     }
 
-    @Ignore("b/80297700")
     @Test
-    public void handleSystemAudioModeRequest_turnOffByTv() {
+    public void handleSystemAudioModeRequest_turnOffByTv() throws Exception {
         assertThat(mMusicMute).isFalse();
         // Check if feature correctly turned off
         HdmiCecMessage messageGive =
@@ -268,91 +340,91 @@
                 HdmiCecMessageBuilder.buildSetSystemAudioMode(
                         ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false);
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleSystemAudioModeRequest(messageRequestOff))
-                .isTrue();
+            .isTrue();
         mTestLooper.dispatchAll();
-        assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
+
+        mNativeWrapper.clearResultMessages();
         expectedMessage =
-                HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
+            HdmiCecMessageBuilder.buildReportSystemAudioMode(ADDR_AUDIO_SYSTEM, ADDR_TV, false);
         assertThat(mHdmiCecLocalDeviceAudioSystem.handleGiveSystemAudioModeStatus(messageGive))
-                .isTrue();
+            .isTrue();
         mTestLooper.dispatchAll();
-        assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
         assertThat(mMusicMute).isTrue();
     }
 
-    @Ignore("b/80297700")
     @Test
-    public void onStandbyAudioSystem_currentSystemAudioControlOn() {
+    public void onStandbyAudioSystem_currentSystemAudioControlOn() throws Exception {
         // Set system audio control on first
-        mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true);
+        mHdmiCecLocalDeviceAudioSystem.checkSupportAndSetSystemAudioMode(true);
         // Check if standby correctly turns off the feature
         mHdmiCecLocalDeviceAudioSystem.onStandby(false, STANDBY_SCREEN_OFF);
         mTestLooper.dispatchAll();
         HdmiCecMessage expectedMessage =
                 HdmiCecMessageBuilder.buildSetSystemAudioMode(
                         ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false);
-        assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
         assertThat(mMusicMute).isTrue();
     }
 
     @Test
-    public void systemAudioControlOnPowerOn_alwaysOn() {
+    public void systemAudioControlOnPowerOn_alwaysOn() throws Exception {
         mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class);
         mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
                 Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.getActions(
-                                SystemAudioInitiationActionFromAvr.class))
-                .isNotEmpty();
+            mHdmiCecLocalDeviceAudioSystem.getActions(
+                SystemAudioInitiationActionFromAvr.class))
+            .isNotEmpty();
     }
 
     @Test
-    public void systemAudioControlOnPowerOn_neverOn() {
+    public void systemAudioControlOnPowerOn_neverOn() throws Exception {
         mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class);
         mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
                 Constants.NEVER_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, false);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.getActions(
-                                SystemAudioInitiationActionFromAvr.class))
-                .isEmpty();
+            mHdmiCecLocalDeviceAudioSystem.getActions(
+                SystemAudioInitiationActionFromAvr.class))
+            .isEmpty();
     }
 
     @Test
-    public void systemAudioControlOnPowerOn_useLastState_off() {
+    public void systemAudioControlOnPowerOn_useLastState_off() throws Exception {
         mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class);
         mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
                 Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, false);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.getActions(
-                                SystemAudioInitiationActionFromAvr.class))
-                .isEmpty();
+            mHdmiCecLocalDeviceAudioSystem.getActions(
+                SystemAudioInitiationActionFromAvr.class))
+            .isEmpty();
     }
 
     @Test
-    public void systemAudioControlOnPowerOn_useLastState_on() {
+    public void systemAudioControlOnPowerOn_useLastState_on() throws Exception {
         mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class);
         mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
                 Constants.USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true);
         assertThat(
-                        mHdmiCecLocalDeviceAudioSystem.getActions(
-                                SystemAudioInitiationActionFromAvr.class))
-                .isNotEmpty();
+            mHdmiCecLocalDeviceAudioSystem.getActions(
+                SystemAudioInitiationActionFromAvr.class))
+            .isNotEmpty();
     }
 
     @Test
-    public void handleActiveSource_updateActiveSource() {
+    public void handleActiveSource_updateActiveSource() throws Exception {
         HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
         ActiveSource expectedActiveSource = new ActiveSource(ADDR_TV, 0x0000);
-        assertThat(mHdmiCecLocalDeviceAudioSystem.handleActiveSource(message))
-                .isTrue();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleActiveSource(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().equals(expectedActiveSource))
-                .isTrue();
+            .isTrue();
     }
 
     @Test
-    public void terminateSystemAudioMode_systemAudioModeOff() {
-        mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(false);
+    public void terminateSystemAudioMode_systemAudioModeOff() throws Exception {
+        mHdmiCecLocalDeviceAudioSystem.checkSupportAndSetSystemAudioMode(false);
         assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isFalse();
         mMusicMute = false;
         HdmiCecMessage message =
@@ -361,13 +433,12 @@
         mHdmiCecLocalDeviceAudioSystem.terminateSystemAudioMode();
         assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isFalse();
         assertThat(mMusicMute).isFalse();
-        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(message);
+        assertThat(mNativeWrapper.getResultMessages()).isEmpty();
     }
 
-    @Ignore("b/80297700")
     @Test
-    public void terminateSystemAudioMode_systemAudioModeOn() {
-        mHdmiCecLocalDeviceAudioSystem.setSystemAudioMode(true);
+    public void terminateSystemAudioMode_systemAudioModeOn() throws Exception {
+        mHdmiCecLocalDeviceAudioSystem.checkSupportAndSetSystemAudioMode(true);
         assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isTrue();
         mMusicMute = false;
         HdmiCecMessage expectedMessage =
@@ -381,124 +452,244 @@
     }
 
     @Test
-    public void isPhysicalAddressMeOrBelow_isMe() {
-        int targetPhysicalAddress = 0x1000;
-        mNativeWrapper.setPhysicalAddress(0x1000);
-        assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress))
-            .isTrue();
-    }
-
-    @Test
-    public void isPhysicalAddressMeOrBelow_isBelow() {
-        int targetPhysicalAddress = 0x1100;
-        mNativeWrapper.setPhysicalAddress(0x1000);
-        assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress))
-            .isTrue();
-    }
-
-    @Test
-    public void isPhysicalAddressMeOrBelow_neitherMeNorBelow() {
-        int targetPhysicalAddress = 0x3000;
-        mNativeWrapper.setPhysicalAddress(0x2000);
-        assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress))
-            .isFalse();
-
-        targetPhysicalAddress = 0x2200;
-        mNativeWrapper.setPhysicalAddress(0x3300);
-        assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress))
-            .isFalse();
-
-        targetPhysicalAddress = 0x2213;
-        mNativeWrapper.setPhysicalAddress(0x2212);
-        assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress))
-            .isFalse();
-
-        targetPhysicalAddress = 0x2340;
-        mNativeWrapper.setPhysicalAddress(0x2310);
-        assertThat(mHdmiCecLocalDeviceAudioSystem.isPhysicalAddressMeOrBelow(targetPhysicalAddress))
-            .isFalse();
-    }
-
-    @Test
-    public void handleRequestArcInitiate_isNotDirectConnectedToTv() {
-        HdmiCecMessage message = HdmiCecMessageBuilder
-            .buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
-        HdmiCecMessage expectedMessage = HdmiCecMessageBuilder
-            .buildFeatureAbortCommand(
-                ADDR_AUDIO_SYSTEM, ADDR_TV,
-                Constants.MESSAGE_REQUEST_ARC_INITIATION,
-                Constants.ABORT_NOT_IN_CORRECT_MODE);
+    public void handleRequestArcInitiate_isNotDirectConnectedToTv() throws Exception {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildFeatureAbortCommand(
+                        ADDR_AUDIO_SYSTEM,
+                        ADDR_TV,
+                        Constants.MESSAGE_REQUEST_ARC_INITIATION,
+                        Constants.ABORT_NOT_IN_CORRECT_MODE);
         mNativeWrapper.setPhysicalAddress(0x1100);
 
-        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message))
-            .isTrue();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
     }
 
     @Test
-    public void handleRequestArcInitiate_startArcInitiationActionFromAvr() {
-        HdmiCecMessage message = HdmiCecMessageBuilder
-            .buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
+    public void handleRequestArcInitiate_startArcInitiationActionFromAvr() throws Exception {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
         mNativeWrapper.setPhysicalAddress(0x1000);
-        mHdmiCecLocalDeviceAudioSystem.removeAction(
-            ArcInitiationActionFromAvr.class);
+        mHdmiCecLocalDeviceAudioSystem.removeAction(ArcInitiationActionFromAvr.class);
 
-        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message))
-            .isTrue();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)).isTrue();
         mTestLooper.dispatchAll();
-        assertThat(mHdmiCecLocalDeviceAudioSystem
-            .getActions(ArcInitiationActionFromAvr.class)).isNotEmpty();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActions(ArcInitiationActionFromAvr.class))
+            .isNotEmpty();
     }
 
     @Test
-    public void handleRequestArcTerminate_arcIsOn_startTerminationActionFromAvr() {
+    public void handleRequestArcTerminate_arcIsOn_startTerminationActionFromAvr() throws Exception {
         mHdmiCecLocalDeviceAudioSystem.setArcStatus(true);
         assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isTrue();
 
-        HdmiCecMessage message = HdmiCecMessageBuilder
-            .buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM);
-        mHdmiCecLocalDeviceAudioSystem.removeAction(
-            ArcTerminationActionFromAvr.class);
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM);
+        mHdmiCecLocalDeviceAudioSystem.removeAction(ArcTerminationActionFromAvr.class);
 
-        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message))
-            .isTrue();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message)).isTrue();
         mTestLooper.dispatchAll();
-        assertThat(mHdmiCecLocalDeviceAudioSystem
-            .getActions(ArcTerminationActionFromAvr.class)).isNotEmpty();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActions(ArcTerminationActionFromAvr.class))
+            .isNotEmpty();
     }
 
     @Test
-    public void handleRequestArcTerminate_arcIsNotOn() {
+    public void handleRequestArcTerminate_arcIsNotOn() throws Exception {
         assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
-        HdmiCecMessage message = HdmiCecMessageBuilder
-            .buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM);
-        HdmiCecMessage expectedMessage = HdmiCecMessageBuilder
-            .buildFeatureAbortCommand(
-                ADDR_AUDIO_SYSTEM, ADDR_TV,
-                Constants.MESSAGE_REQUEST_ARC_TERMINATION,
-                Constants.ABORT_NOT_IN_CORRECT_MODE);
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRequestArcTermination(ADDR_TV, ADDR_AUDIO_SYSTEM);
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildFeatureAbortCommand(
+                        ADDR_AUDIO_SYSTEM,
+                        ADDR_TV,
+                        Constants.MESSAGE_REQUEST_ARC_TERMINATION,
+                        Constants.ABORT_NOT_IN_CORRECT_MODE);
 
-        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message))
-            .isTrue();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcTermination(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
     }
 
     @Test
-    public void handleRequestArcInit_arcIsNotSupported() {
-        HdmiCecMessage message = HdmiCecMessageBuilder
-            .buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
-        HdmiCecMessage expectedMessage = HdmiCecMessageBuilder
-            .buildFeatureAbortCommand(
-                ADDR_AUDIO_SYSTEM, ADDR_TV,
-                Constants.MESSAGE_REQUEST_ARC_INITIATION,
-                Constants.ABORT_UNRECOGNIZED_OPCODE);
-        SystemProperties.set(Constants.PROPERTY_ARC_SUPPORT, "false");
+    public void handleRequestArcInit_arcIsNotSupported() throws Exception {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRequestArcInitiation(ADDR_TV, ADDR_AUDIO_SYSTEM);
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildFeatureAbortCommand(
+                        ADDR_AUDIO_SYSTEM,
+                        ADDR_TV,
+                        Constants.MESSAGE_REQUEST_ARC_INITIATION,
+                        Constants.ABORT_UNRECOGNIZED_OPCODE);
+        mArcSupport = false;
 
-        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message))
-            .isTrue();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRequestArcInitiate(message)).isTrue();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
+    }
+
+    public void handleSystemAudioModeRequest_fromNonTV_tVNotSupport() {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildSystemAudioModeRequest(
+                        ADDR_TUNER_1, ADDR_AUDIO_SYSTEM,
+                        SELF_PHYSICAL_ADDRESS, true);
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildFeatureAbortCommand(
+                        ADDR_AUDIO_SYSTEM,
+                        ADDR_TUNER_1,
+                        Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST,
+                        Constants.ABORT_REFUSED);
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleSystemAudioModeRequest(message)).isTrue();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
+    }
+
+    @Test
+    public void handleSystemAudioModeRequest_fromNonTV_tVSupport() {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildSystemAudioModeRequest(
+                        ADDR_TUNER_1, ADDR_AUDIO_SYSTEM,
+                        SELF_PHYSICAL_ADDRESS, true);
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildSetSystemAudioMode(
+                        ADDR_AUDIO_SYSTEM, Constants.ADDR_BROADCAST, true);
+        mHdmiCecLocalDeviceAudioSystem.setTvSystemAudioModeSupport(true);
+
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleSystemAudioModeRequest(message)).isTrue();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
+    }
+
+    @Test
+    public void handleActiveSource_activeSourceFromTV_swithToArc() {
+        mHdmiCecLocalDeviceAudioSystem.setArcStatus(true);
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
+
+        ActiveSource expectedActiveSource = ActiveSource.of(ADDR_TV, 0x0000);
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleActiveSource(message)).isTrue();
+        mTestLooper.dispatchAll();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource())
+            .isEqualTo(expectedActiveSource);
+    }
+
+    @Test
+    public void handleRoutingChange_currentActivePortIsHome() {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x3000, SELF_PHYSICAL_ADDRESS);
+
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, SELF_PHYSICAL_ADDRESS);
+        ActiveSource expectedActiveSource = ActiveSource.of(ADDR_PLAYBACK_1, SELF_PHYSICAL_ADDRESS);
+        int expectedLocalActivePort = Constants.CEC_SWITCH_HOME;
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingChange(message)).isTrue();
+        mTestLooper.dispatchAll();
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource())
+            .isEqualTo(expectedActiveSource);
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getRoutingPort())
+            .isEqualTo(expectedLocalActivePort);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
+    }
+
+    @Test
+    public void handleRoutingInformation_currentActivePortIsHDMI1() {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, SELF_PHYSICAL_ADDRESS);
+        mHdmiCecLocalDeviceAudioSystem.setRoutingPort(mHdmiPortInfo[1].getId());
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildRoutingInformation(
+                        ADDR_AUDIO_SYSTEM, HDMI_1_PHYSICAL_ADDRESS);
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingInformation(message)).isTrue();
+        mTestLooper.dispatchAll();
+        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
+    }
+
+    @Ignore("b/120845532")
+    @Test
+    public void handleRoutingChange_homeIsActive_playbackSendActiveSource() {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x2000);
+
+        HdmiCecMessage expectedMessage =
+                HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, 0x2000);
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.handleRoutingChange(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
     }
+
+    @Test
+    public void updateCecDevice_deviceNotExists_addDevice() {
+        assertThat(mInvokeDeviceEventState).isNotEqualTo(DEVICE_EVENT_ADD_DEVICE);
+        HdmiDeviceInfo newDevice = new HdmiDeviceInfo(
+                ADDR_PLAYBACK_1, 0x2100, 2, HdmiDeviceInfo.DEVICE_PLAYBACK,
+                Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_1));
+
+        mHdmiCecLocalDeviceAudioSystem.updateCecDevice(newDevice);
+        assertThat(mDeviceInfo).isEqualTo(newDevice);
+        assertThat(mHdmiCecLocalDeviceAudioSystem
+            .getCecDeviceInfo(newDevice.getLogicalAddress())).isEqualTo(newDevice);
+        assertThat(mInvokeDeviceEventState).isEqualTo(DEVICE_EVENT_ADD_DEVICE);
+    }
+
+    @Test
+    public void updateCecDevice_deviceExists_doNothing() {
+        mInvokeDeviceEventState = 0;
+        HdmiDeviceInfo oldDevice = new HdmiDeviceInfo(
+                ADDR_PLAYBACK_1, 0x2100, 2, HdmiDeviceInfo.DEVICE_PLAYBACK,
+                Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_1));
+        mHdmiCecLocalDeviceAudioSystem.addDeviceInfo(oldDevice);
+
+        mHdmiCecLocalDeviceAudioSystem.updateCecDevice(oldDevice);
+        assertThat(mInvokeDeviceEventState).isEqualTo(0);
+    }
+
+    @Test
+    public void updateCecDevice_deviceInfoDifferent_updateDevice() {
+        assertThat(mInvokeDeviceEventState).isNotEqualTo(DEVICE_EVENT_UPDATE_DEVICE);
+        HdmiDeviceInfo oldDevice = new HdmiDeviceInfo(
+                ADDR_PLAYBACK_1, 0x2100, 2, HdmiDeviceInfo.DEVICE_PLAYBACK,
+                Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_1));
+        mHdmiCecLocalDeviceAudioSystem.addDeviceInfo(oldDevice);
+
+        HdmiDeviceInfo differentDevice = new HdmiDeviceInfo(
+                ADDR_PLAYBACK_1, 0x2300, 4, HdmiDeviceInfo.DEVICE_PLAYBACK,
+                Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_1));
+
+        mHdmiCecLocalDeviceAudioSystem.updateCecDevice(differentDevice);
+        assertThat(mDeviceInfo).isEqualTo(differentDevice);
+        assertThat(mHdmiCecLocalDeviceAudioSystem
+            .getCecDeviceInfo(differentDevice.getLogicalAddress())).isEqualTo(differentDevice);
+        assertThat(mInvokeDeviceEventState).isEqualTo(DEVICE_EVENT_UPDATE_DEVICE);
+    }
+
+    @Test
+    public void handleReportPhysicalAddress_differentPath_addDevice() {
+        assertThat(mInvokeDeviceEventState).isNotEqualTo(DEVICE_EVENT_ADD_DEVICE);
+        HdmiDeviceInfo oldDevice = new HdmiDeviceInfo(
+                ADDR_PLAYBACK_1, 0x2100, 2, HdmiDeviceInfo.DEVICE_PLAYBACK,
+                Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_1));
+        mHdmiCecLocalDeviceAudioSystem.addDeviceInfo(oldDevice);
+
+        HdmiDeviceInfo differentDevice = new HdmiDeviceInfo(
+                ADDR_PLAYBACK_2, 0x2200, 1, HdmiDeviceInfo.DEVICE_PLAYBACK,
+                Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(ADDR_PLAYBACK_2));
+        HdmiCecMessage reportPhysicalAddress = HdmiCecMessageBuilder
+                .buildReportPhysicalAddressCommand(
+                        ADDR_PLAYBACK_2, 0x2200, HdmiDeviceInfo.DEVICE_PLAYBACK);
+        mHdmiCecLocalDeviceAudioSystem.handleReportPhysicalAddress(reportPhysicalAddress);
+
+        mTestLooper.dispatchAll();
+        assertThat(mDeviceInfo).isEqualTo(differentDevice);
+        assertThat(mHdmiCecLocalDeviceAudioSystem
+            .getCecDeviceInfo(differentDevice.getLogicalAddress())).isEqualTo(differentDevice);
+        assertThat(mInvokeDeviceEventState).isEqualTo(DEVICE_EVENT_ADD_DEVICE);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
new file mode 100644
index 0000000..feae4ee
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.hdmi;
+
+import static com.android.server.hdmi.Constants.ADDR_TV;
+import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Looper;
+import android.os.test.TestLooper;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/** Tests for {@link HdmiCecLocalDevicePlayback} class. */
+public class HdmiCecLocalDevicePlaybackTest {
+
+    private HdmiControlService mHdmiControlService;
+    private HdmiCecController mHdmiCecController;
+    private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
+    private FakeNativeWrapper mNativeWrapper;
+    private Looper mMyLooper;
+    private TestLooper mTestLooper = new TestLooper();
+    private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
+    private int mPlaybackPhysicalAddress;
+
+    @Before
+    public void setUp() {
+        mHdmiControlService =
+            new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
+                @Override
+                void wakeUp() {
+                }
+
+                @Override
+                boolean isControlEnabled() {
+                    return true;
+                }
+            };
+
+        mMyLooper = mTestLooper.getLooper();
+        mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService);
+        mHdmiCecLocalDevicePlayback.init();
+        mHdmiControlService.setIoLooper(mMyLooper);
+        mNativeWrapper = new FakeNativeWrapper();
+        mHdmiCecController =
+            HdmiCecController.createWithNativeWrapper(mHdmiControlService, mNativeWrapper);
+        mHdmiControlService.setCecController(mHdmiCecController);
+        mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
+        mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
+        mLocalDevices.add(mHdmiCecLocalDevicePlayback);
+        mHdmiControlService.initPortInfo();
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+        mNativeWrapper.clearResultMessages();
+        mPlaybackPhysicalAddress = 0x2000;
+        mNativeWrapper.setPhysicalAddress(mPlaybackPhysicalAddress);
+    }
+
+    // Playback device does not handle routing control related feature right now
+    @Ignore("b/120845532")
+    @Test
+    public void handleSetStreamPath_underCurrentDevice() {
+        assertThat(mHdmiCecLocalDevicePlayback.getLocalActivePath()).isEqualTo(0);
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x2100);
+        assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue();
+        // TODO(amyjojo): Move set and get LocalActivePath to Control Service.
+        assertThat(mHdmiCecLocalDevicePlayback.getLocalActivePath()).isEqualTo(1);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
index c7809d3..ef974f2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
@@ -18,6 +18,7 @@
 import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
 import static com.android.server.hdmi.Constants.ADDR_TV;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.hardware.hdmi.HdmiDeviceInfo;
@@ -51,6 +52,14 @@
         assertThat(message).isEqualTo(buildMessage("05:A4:06:01"));
     }
 
+    @Test
+    public void buildRoutingInformation() {
+        HdmiCecMessage message =
+                HdmiCecMessageBuilder.buildRoutingInformation(
+                        ADDR_AUDIO_SYSTEM, 0x2100);
+        assertThat(message).isEqualTo(buildMessage("5F:81:21:00"));
+    }
+
     /**
      * Build a CEC message from a hex byte string with bytes separated by {@code :}.
      *
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 18c9a65..1f66074 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -20,13 +20,18 @@
 
 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import android.hardware.hdmi.HdmiPortInfo;
 import android.os.Looper;
 import android.os.test.TestLooper;
+
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -102,6 +107,7 @@
     private TestLooper mTestLooper = new TestLooper();
     private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
     private boolean mStandbyMessageReceived;
+    private HdmiPortInfo[] mHdmiPortInfo;
 
     @Before
     public void SetUp() {
@@ -131,6 +137,16 @@
 
         mLocalDevices.add(mMyAudioSystemDevice);
         mLocalDevices.add(mMyPlaybackDevice);
+        mHdmiPortInfo = new HdmiPortInfo[4];
+        mHdmiPortInfo[0] =
+            new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, 0x2100, true, false, false);
+        mHdmiPortInfo[1] =
+            new HdmiPortInfo(2, HdmiPortInfo.PORT_INPUT, 0x2200, true, false, false);
+        mHdmiPortInfo[2] =
+            new HdmiPortInfo(3, HdmiPortInfo.PORT_INPUT, 0x2000, true, false, false);
+        mHdmiPortInfo[3] =
+            new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false);
+        mNativeWrapper.setPortInfo(mHdmiPortInfo);
         mHdmiControlService.initPortInfo();
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
 
@@ -159,4 +175,27 @@
         assertTrue(mMyPlaybackDevice.isDisabled());
         assertTrue(mMyAudioSystemDevice.isDisabled());
     }
+
+    @Test
+    public void pathToPort_pathExists_weAreNonTv() {
+        mNativeWrapper.setPhysicalAddress(0x2000);
+        mHdmiControlService.initPortInfo();
+        assertThat(mHdmiControlService.pathToPortId(0x2120)).isEqualTo(1);
+        assertThat(mHdmiControlService.pathToPortId(0x2234)).isEqualTo(2);
+    }
+
+    @Test
+    public void pathToPort_pathExists_weAreTv() {
+        mNativeWrapper.setPhysicalAddress(0x0000);
+        mHdmiControlService.initPortInfo();
+        assertThat(mHdmiControlService.pathToPortId(0x2120)).isEqualTo(3);
+        assertThat(mHdmiControlService.pathToPortId(0x3234)).isEqualTo(4);
+    }
+
+    @Test
+    public void pathToPort_pathInvalid() {
+        mNativeWrapper.setPhysicalAddress(0x2000);
+        mHdmiControlService.initPortInfo();
+        assertThat(mHdmiControlService.pathToPortId(0x1000)).isEqualTo(Constants.INVALID_PORT_ID);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
new file mode 100644
index 0000000..985c647
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.hdmi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.util.Slog;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.hdmi.HdmiUtils.CodecSad;
+import com.android.server.hdmi.HdmiUtils.DeviceConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/** Tests for {@link HdmiUtils} class. */
+public class HdmiUtilsTest {
+
+    private static final String TAG = "HdmiUtilsTest";
+
+    private final String mExampleXML =
+            "<!-- A sample Short Audio Descriptor configuration xml -->"
+                    + "<config version=\"1.0\" xmlns:xi=\"http://www.w3.org/2001/XInclude\">"
+                    + "<device type=\"VX_AUDIO_DEVICE_IN_HDMI_ARC\">"
+                    + "<supportedFormat format=\"AUDIO_FORMAT_LPCM\" descriptor=\"011a03\"/>"
+                    + "<supportedFormat format=\"AUDIO_FORMAT_DD\" descriptor=\"0d0506\"/>"
+                    + "</device>"
+                    + "<device type=\"AUDIO_DEVICE_IN_SPDIF\">"
+                    + "<supportedFormat format=\"AUDIO_FORMAT_LPCM\" descriptor=\"010203\"/>"
+                    + "<supportedFormat format=\"AUDIO_FORMAT_DD\" descriptor=\"040506\"/>"
+                    + "</device>"
+                    + "</config>";
+
+    @Test
+    public void pathToPort_isMe() {
+        int targetPhysicalAddress = 0x1000;
+        int myPhysicalAddress = 0x1000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                        HdmiUtils.TARGET_SAME_PHYSICAL_ADDRESS);
+    }
+
+    @Test
+    public void pathToPort_isDirectlyBelow() {
+        int targetPhysicalAddress = 0x1100;
+        int myPhysicalAddress = 0x1000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+    }
+
+    @Test
+    public void pathToPort_isBelow() {
+        int targetPhysicalAddress = 0x1110;
+        int myPhysicalAddress = 0x1000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(1);
+    }
+
+    @Test
+    public void pathToPort_neitherMeNorBelow() {
+        int targetPhysicalAddress = 0x3000;
+        int myPhysicalAddress = 0x2000;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                        HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+        targetPhysicalAddress = 0x2200;
+        myPhysicalAddress = 0x3300;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                        HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+        targetPhysicalAddress = 0x2213;
+        myPhysicalAddress = 0x2212;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                        HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+
+        targetPhysicalAddress = 0x2340;
+        myPhysicalAddress = 0x2310;
+        assertThat(HdmiUtils.getLocalPortFromPhysicalAddress(
+                targetPhysicalAddress, myPhysicalAddress)).isEqualTo(
+                        HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE);
+    }
+
+    @Test
+    public void parseSampleXML() {
+        List<DeviceConfig> config = new ArrayList<>();
+        try {
+            config = HdmiUtils.ShortAudioDescriptorXmlParser.parse(
+                    new ByteArrayInputStream(mExampleXML.getBytes(StandardCharsets.UTF_8)));
+        } catch (IOException e) {
+            Slog.e(TAG, e.getMessage(), e);
+        } catch (XmlPullParserException e) {
+            Slog.e(TAG, e.getMessage(), e);
+        }
+
+        CodecSad expectedCodec1 = new CodecSad(Constants.AUDIO_CODEC_LPCM, "011a03");
+        CodecSad expectedCodec2 = new CodecSad(Constants.AUDIO_CODEC_DD, "0d0506");
+        CodecSad expectedCodec3 = new CodecSad(Constants.AUDIO_CODEC_LPCM, "010203");
+        CodecSad expectedCodec4 = new CodecSad(Constants.AUDIO_CODEC_DD, "040506");
+
+        List<CodecSad> expectedList1 = new ArrayList<>();
+        expectedList1.add(expectedCodec1);
+        expectedList1.add(expectedCodec2);
+
+        List<CodecSad> expectedList2 = new ArrayList<>();
+        expectedList2.add(expectedCodec3);
+        expectedList2.add(expectedCodec4);
+
+        DeviceConfig expectedDevice1 = new DeviceConfig(
+                "VX_AUDIO_DEVICE_IN_HDMI_ARC", expectedList1);
+        DeviceConfig expectedDevice2 = new DeviceConfig(
+                "AUDIO_DEVICE_IN_SPDIF", expectedList2);
+
+        List<DeviceConfig> expectedConfig = new ArrayList<>();
+        expectedConfig.add(expectedDevice1);
+        expectedConfig.add(expectedDevice2);
+
+        assertThat(config).isEqualTo(expectedConfig);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index d914b9a..440a49a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -26,9 +26,12 @@
 import android.media.AudioManager;
 import android.os.Looper;
 import android.os.test.TestLooper;
+
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
+
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -49,6 +52,9 @@
     private int mMsgRequestActiveSourceCount;
     private int mMsgSetSystemAudioModeCount;
     private int mQueryTvSystemAudioModeSupportCount;
+    private boolean mArcEnabled;
+    private boolean mIsPlaybackDevice;
+    private boolean mBroadcastActiveSource;
 
     @Before
     public void SetUp() {
@@ -80,6 +86,8 @@
                                     callback.onSendCompleted(SendMessageResult.NACK);
                                 }
                                 break;
+                            case Constants.MESSAGE_INITIATE_ARC:
+                                break;
                             default:
                                 throw new IllegalArgumentException("Unexpected message");
                         }
@@ -132,6 +140,22 @@
                     int getPhysicalAddress() {
                         return 0;
                     }
+
+                    @Override
+                    boolean isPlaybackDevice() {
+                        return mIsPlaybackDevice;
+                    }
+
+                    @Override
+                    public void setAndBroadcastActiveSourceFromOneDeviceType(
+                            int sourceAddress, int physicalAddress) {
+                        mBroadcastActiveSource = true;
+                    }
+
+                    @Override
+                    int pathToPortId(int path) {
+                        return -1;
+                    }
                 };
         mHdmiCecLocalDeviceAudioSystem =
                 new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
@@ -148,6 +172,11 @@
                     HdmiDeviceInfo getDeviceInfo() {
                         return mDeviceInfoForTests;
                     }
+
+                    @Override
+                    void setArcStatus(boolean enabled) {
+                        mArcEnabled = enabled;
+                    }
                 };
         mHdmiCecLocalDeviceAudioSystem.init();
         Looper looper = mTestLooper.getLooper();
@@ -159,7 +188,7 @@
         resetTestVariables();
         mShouldDispatchActiveSource = false;
 
-        assertThat(mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress)
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
                 .isEqualTo(Constants.INVALID_PHYSICAL_ADDRESS);
 
         mHdmiCecLocalDeviceAudioSystem.addAndStartAction(
@@ -171,7 +200,7 @@
         assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(0);
         assertFalse(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated());
 
-        assertThat(mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress)
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
                 .isEqualTo(Constants.INVALID_PHYSICAL_ADDRESS);
     }
 
@@ -206,14 +235,15 @@
         assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(1);
         assertTrue(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated());
 
-        assertThat(mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress).isEqualTo(1002);
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
+            .isEqualTo(1002);
     }
 
     @Test
     public void testKnownActiveSource() {
         resetTestVariables();
         mTvSystemAudioModeSupport = true;
-        mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress = 1001;
+        mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress = 1001;
 
         mHdmiCecLocalDeviceAudioSystem.addAndStartAction(
                 new SystemAudioInitiationActionFromAvr(mHdmiCecLocalDeviceAudioSystem));
@@ -233,7 +263,7 @@
         mTryCountBeforeSucceed = 3;
         assertThat(mTryCountBeforeSucceed)
                 .isAtMost(SystemAudioInitiationActionFromAvr.MAX_RETRY_COUNT);
-        assertThat(mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress)
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
                 .isEqualTo(Constants.INVALID_PHYSICAL_ADDRESS);
 
         mHdmiCecLocalDeviceAudioSystem.addAndStartAction(
@@ -246,12 +276,33 @@
         assertTrue(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated());
     }
 
+    @Ignore("b/120845532")
+    @Test
+    public void testIsPlaybackDevice_cannotReceiveActiveSource() {
+        resetTestVariables();
+        mIsPlaybackDevice = true;
+        assertThat(mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress)
+            .isEqualTo(Constants.INVALID_PHYSICAL_ADDRESS);
+
+        mHdmiCecLocalDeviceAudioSystem.addAndStartAction(
+                new SystemAudioInitiationActionFromAvr(mHdmiCecLocalDeviceAudioSystem));
+        mTestLooper.dispatchAll();
+
+        assertThat(mMsgRequestActiveSourceCount).isEqualTo(1);
+        assertThat(mBroadcastActiveSource).isTrue();
+        assertThat(mQueryTvSystemAudioModeSupportCount).isEqualTo(1);
+        assertThat(mMsgSetSystemAudioModeCount).isEqualTo(1);
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isSystemAudioActivated()).isTrue();
+    }
+
     private void resetTestVariables() {
         mMsgRequestActiveSourceCount = 0;
         mMsgSetSystemAudioModeCount = 0;
         mQueryTvSystemAudioModeSupportCount = 0;
         mTryCountBeforeSucceed = 0;
-        mHdmiCecLocalDeviceAudioSystem.mActiveSource.physicalAddress =
+        mIsPlaybackDevice = false;
+        mBroadcastActiveSource = false;
+        mHdmiCecLocalDeviceAudioSystem.getActiveSource().physicalAddress =
                 Constants.INVALID_PHYSICAL_ADDRESS;
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
index 0328621..8afc3d3 100644
--- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodManagerServiceTests.java
@@ -22,7 +22,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -58,8 +57,7 @@
         // Make sure that there is a short-circuit for DEFAULT_DISPLAY.
         assertEquals(DEFAULT_DISPLAY,
                 InputMethodManagerService.computeImeDisplayIdForTarget(
-                        DEFAULT_DISPLAY, false /* isVrImeStarted */,
-                        sMustNotBeCalledChecker));
+                        DEFAULT_DISPLAY, sMustNotBeCalledChecker));
     }
 
     @Test
@@ -67,17 +65,7 @@
         // Make sure that there is a short-circuit for INVALID_DISPLAY.
         assertEquals(DEFAULT_DISPLAY,
                 InputMethodManagerService.computeImeDisplayIdForTarget(
-                        INVALID_DISPLAY, false /* isVrImeStarted */,
-                        sMustNotBeCalledChecker));
-    }
-
-    @Test
-    public void testComputeImeDisplayId_VrIme() {
-        // Make sure that there is a short-circuit for VR IME.
-        assertEquals(DEFAULT_DISPLAY,
-                InputMethodManagerService.computeImeDisplayIdForTarget(
-                        SYSTEM_DECORATION_SUPPORT_DISPLAY_ID, true /* isVrImeStarted */,
-                        sMustNotBeCalledChecker));
+                        INVALID_DISPLAY, sMustNotBeCalledChecker));
     }
 
     @Test
@@ -86,8 +74,7 @@
         // Make sure IME displayId is DEFAULT_DISPLAY.
         assertEquals(DEFAULT_DISPLAY,
                 InputMethodManagerService.computeImeDisplayIdForTarget(
-                        NO_SYSTEM_DECORATION_SUPPORT_DISPLAY_ID, false /* isVrImeStarted */,
-                        sChecker));
+                        NO_SYSTEM_DECORATION_SUPPORT_DISPLAY_ID, sChecker));
     }
 
     @Test
@@ -96,7 +83,6 @@
         // Make sure IME displayId is the same display.
         assertEquals(SYSTEM_DECORATION_SUPPORT_DISPLAY_ID,
                 InputMethodManagerService.computeImeDisplayIdForTarget(
-                        SYSTEM_DECORATION_SUPPORT_DISPLAY_ID, false /* isVrImeStarted */,
-                        sChecker));
+                        SYSTEM_DECORATION_SUPPORT_DISPLAY_ID, sChecker));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/job/JobCountTrackerTest.java b/services/tests/servicestests/src/com/android/server/job/JobCountTrackerTest.java
new file mode 100644
index 0000000..e5529cb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/job/JobCountTrackerTest.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.job;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.util.Log;
+
+import com.android.server.job.JobConcurrencyManager.JobCountTracker;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Random;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+/**
+ * Test for {@link com.android.server.job.JobConcurrencyManager.JobCountTracker}.
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class JobCountTrackerTest {
+    private static final String TAG = "JobCountTrackerTest";
+
+    private Random mRandom;
+    private JobCountTracker mJobCountTracker;
+
+    @Before
+    public void setUp() {
+        mRandom = new Random(1); // Always use the same series of pseudo random values.
+        mJobCountTracker = new JobCountTracker();
+    }
+
+    /**
+     * Represents running and pending jobs.
+     */
+    class Jobs {
+        public int runningFg;
+        public int runningBg;
+        public int pendingFg;
+        public int pendingBg;
+
+        public void maybeEnqueueJobs(double startRatio, double fgJobRatio) {
+            while (mRandom.nextDouble() < startRatio) {
+                if (mRandom.nextDouble() < fgJobRatio) {
+                    pendingFg++;
+                } else {
+                    pendingBg++;
+                }
+            }
+        }
+
+        public void maybeFinishJobs(double stopRatio) {
+            for (int i = runningBg; i > 0; i--) {
+                if (mRandom.nextDouble() < stopRatio) {
+                    runningBg--;
+                }
+            }
+            for (int i = runningFg; i > 0; i--) {
+                if (mRandom.nextDouble() < stopRatio) {
+                    runningFg--;
+                }
+            }
+        }
+    }
+
+
+    private void startPendingJobs(Jobs jobs, int totalMax, int maxBg, int minBg) {
+        mJobCountTracker.reset(totalMax, maxBg, minBg);
+
+        for (int i = 0; i < jobs.runningFg; i++) {
+            mJobCountTracker.incrementRunningJobCount(true);
+        }
+        for (int i = 0; i < jobs.runningBg; i++) {
+            mJobCountTracker.incrementRunningJobCount(false);
+        }
+
+        for (int i = 0; i < jobs.pendingFg; i++) {
+            mJobCountTracker.incrementPendingJobCount(true);
+        }
+        for (int i = 0; i < jobs.pendingBg; i++) {
+            mJobCountTracker.incrementPendingJobCount(false);
+        }
+
+        mJobCountTracker.onCountDone();
+
+        while ((jobs.pendingFg > 0 && mJobCountTracker.canJobStart(true))
+                || (jobs.pendingBg > 0 && mJobCountTracker.canJobStart(false))) {
+            final boolean isStartingFg = mRandom.nextBoolean();
+
+            if (isStartingFg) {
+                if (jobs.pendingFg > 0 && mJobCountTracker.canJobStart(true)) {
+                    jobs.pendingFg--;
+                    jobs.runningFg++;
+                    mJobCountTracker.onStartingNewJob(true);
+                }
+            } else {
+                if (jobs.pendingBg > 0 && mJobCountTracker.canJobStart(false)) {
+                    jobs.pendingBg--;
+                    jobs.runningBg++;
+                    mJobCountTracker.onStartingNewJob(false);
+                }
+            }
+        }
+
+        Log.i(TAG, "" + mJobCountTracker);
+    }
+
+    /**
+     * Used by the following testRandom* tests.
+     */
+    private void checkRandom(Jobs jobs, int numTests, int totalMax, int maxBg, int minBg,
+            double startRatio, double fgJobRatio, double stopRatio) {
+        for (int i = 0; i < numTests; i++) {
+
+            jobs.maybeFinishJobs(stopRatio);
+            jobs.maybeEnqueueJobs(startRatio, fgJobRatio);
+
+            startPendingJobs(jobs, totalMax, maxBg, minBg);
+
+            assertThat(jobs.runningFg).isAtMost(totalMax);
+            assertThat(jobs.runningBg).isAtMost(totalMax);
+            assertThat(jobs.runningFg + jobs.runningBg).isAtMost(totalMax);
+            assertThat(jobs.runningBg).isAtMost(maxBg);
+        }
+    }
+
+    /**
+     * Randomly enqueue / stop jobs and make sure we won't run more jobs than we should.
+     */
+    @Test
+    public void testRandom1() {
+        final Jobs jobs = new Jobs();
+
+        final int numTests = 5000;
+        final int totalMax = 6;
+        final int maxBg = 4;
+        final int minBg = 2;
+        final double stopRatio = 0.1;
+        final double fgJobRatio = 0.5;
+        final double startRatio = 0.1;
+
+        checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio , stopRatio);
+    }
+
+    @Test
+    public void testRandom2() {
+        final Jobs jobs = new Jobs();
+
+        final int numTests = 5000;
+        final int totalMax = 2;
+        final int maxBg = 2;
+        final int minBg = 0;
+        final double stopRatio = 0.5;
+        final double fgJobRatio = 0.5;
+        final double startRatio = 0.5;
+
+        checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+    }
+
+    @Test
+    public void testRandom3() {
+        final Jobs jobs = new Jobs();
+
+        final int numTests = 5000;
+        final int totalMax = 2;
+        final int maxBg = 2;
+        final int minBg = 2;
+        final double stopRatio = 0.5;
+        final double fgJobRatio = 0.5;
+        final double startRatio = 0.5;
+
+        checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+    }
+
+    @Test
+    public void testRandom4() {
+        final Jobs jobs = new Jobs();
+
+        final int numTests = 5000;
+        final int totalMax = 10;
+        final int maxBg = 2;
+        final int minBg = 0;
+        final double stopRatio = 0.5;
+        final double fgJobRatio = 0.5;
+        final double startRatio = 0.5;
+
+        checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+    }
+
+    @Test
+    public void testRandom5() {
+        final Jobs jobs = new Jobs();
+
+        final int numTests = 5000;
+        final int totalMax = 6;
+        final int maxBg = 4;
+        final int minBg = 2;
+        final double stopRatio = 0.5;
+        final double fgJobRatio = 0.1;
+        final double startRatio = 0.5;
+
+        checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+    }
+
+    @Test
+    public void testRandom6() {
+        final Jobs jobs = new Jobs();
+
+        final int numTests = 5000;
+        final int totalMax = 6;
+        final int maxBg = 4;
+        final int minBg = 2;
+        final double stopRatio = 0.5;
+        final double fgJobRatio = 0.9;
+        final double startRatio = 0.5;
+
+        checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+    }
+
+    @Test
+    public void testRandom7() {
+        final Jobs jobs = new Jobs();
+
+        final int numTests = 5000;
+        final int totalMax = 6;
+        final int maxBg = 4;
+        final int minBg = 2;
+        final double stopRatio = 0.4;
+        final double fgJobRatio = 0.1;
+        final double startRatio = 0.5;
+
+        checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+    }
+
+    @Test
+    public void testRandom8() {
+        final Jobs jobs = new Jobs();
+
+        final int numTests = 5000;
+        final int totalMax = 6;
+        final int maxBg = 4;
+        final int minBg = 2;
+        final double stopRatio = 0.4;
+        final double fgJobRatio = 0.9;
+        final double startRatio = 0.5;
+
+        checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+    }
+
+    /** Used by the following tests */
+    private void checkSimple(int totalMax, int maxBg, int minBg,
+            int runningFg, int runningBg, int pendingFg, int pendingBg,
+            int resultRunningFg, int resultRunningBg, int resultPendingFg, int resultPendingBg) {
+        final Jobs jobs = new Jobs();
+        jobs.runningFg = runningFg;
+        jobs.runningBg = runningBg;
+        jobs.pendingFg = pendingFg;
+        jobs.pendingBg = pendingBg;
+
+        startPendingJobs(jobs, totalMax, maxBg, minBg);
+
+        assertThat(jobs.runningFg).isEqualTo(resultRunningFg);
+        assertThat(jobs.runningBg).isEqualTo(resultRunningBg);
+
+        assertThat(jobs.pendingFg).isEqualTo(resultPendingFg);
+        assertThat(jobs.pendingBg).isEqualTo(resultPendingBg);
+    }
+
+
+    @Test
+    public void testBasic() {
+        // Args are:
+        // First 3: Total-max, bg-max, bg-min.
+        // Next 2:  Running FG / BG
+        // Next 2:  Pending FG / BG
+        // Next 4:  Result running FG / BG, pending FG/BG.
+        checkSimple(6, 4, 2, /*run=*/ 0, 0, /*pen=*/ 1, 0, /*res run/pen=*/ 1, 0, 0, 0);
+
+        checkSimple(6, 4, 2, /*run=*/ 0, 0, /*pen=*/ 10, 0, /*res run/pen=*/ 6, 0, 4, 0);
+
+        // When there are BG jobs pending, 2 (min-BG) jobs should run.
+        checkSimple(6, 4, 2, /*run=*/ 0, 0, /*pen=*/ 10, 1, /*res run/pen=*/ 5, 1, 5, 0);
+        checkSimple(6, 4, 2, /*run=*/ 0, 0, /*pen=*/ 10, 3, /*res run/pen=*/ 4, 2, 6, 1);
+
+        checkSimple(6, 4, 2, /*run=*/ 6, 0, /*pen=*/ 10, 3, /*res run/pen=*/ 6, 0, 10, 3);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java b/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java
new file mode 100644
index 0000000..01199a3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.job;
+
+import android.util.KeyValueListParser;
+
+import com.android.server.job.JobSchedulerService.MaxJobCounts;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MaxJobCountsTest {
+
+    private void check(String config,
+            int defaultTotal, int defaultMaxBg, int defaultMinBg,
+            int expectedTotal, int expectedMaxBg, int expectedMinBg) {
+        final KeyValueListParser parser = new KeyValueListParser(',');
+        parser.setString(config);
+
+        final MaxJobCounts counts = new JobSchedulerService.MaxJobCounts(
+                defaultTotal, "total",
+                defaultMaxBg, "maxbg",
+                defaultMinBg, "minbg");
+
+        counts.parse(parser);
+
+        Assert.assertEquals(expectedTotal, counts.getTotalMax());
+        Assert.assertEquals(expectedMaxBg, counts.getMaxBg());
+        Assert.assertEquals(expectedMinBg, counts.getMinBg());
+    }
+
+    @Test
+    public void test() {
+        check("", /*default*/ 5, 1, 0, /*expected*/ 5, 1, 0);
+        check("", /*default*/ 5, 0, 0, /*expected*/ 5, 1, 0);
+        check("", /*default*/ 0, 0, 0, /*expected*/ 1, 1, 0);
+        check("", /*default*/ -1, -1, -1, /*expected*/ 1, 1, 0);
+        check("", /*default*/ 5, 5, 5, /*expected*/ 5, 5, 4);
+        check("", /*default*/ 6, 5, 6, /*expected*/ 6, 5, 5);
+        check("", /*default*/ 4, 5, 6, /*expected*/ 4, 4, 3);
+        check("", /*default*/ 5, 1, 1, /*expected*/ 5, 1, 1);
+
+        check("total=5,maxbg=4,minbg=3", /*default*/ 9, 9, 9, /*expected*/ 5, 4, 3);
+        check("total=5", /*default*/ 9, 9, 9, /*expected*/ 5, 5, 4);
+        check("maxbg=4", /*default*/ 9, 9, 9, /*expected*/ 9, 4, 4);
+        check("minbg=3", /*default*/ 9, 9, 9, /*expected*/ 9, 9, 3);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index 2dc3510..cf89cb8 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -37,8 +37,8 @@
 import android.os.IProgressListener;
 import android.os.RemoteException;
 import android.os.UserManager;
-import android.os.storage.StorageManager;
 import android.os.storage.IStorageManager;
+import android.os.storage.StorageManager;
 import android.security.KeyStore;
 import android.test.AndroidTestCase;
 
@@ -46,6 +46,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockSettingsInternal;
 import com.android.server.LocalServices;
+import com.android.server.wm.WindowManagerInternal;
 
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
@@ -85,6 +86,8 @@
     KeyStore mKeyStore;
     MockSyntheticPasswordManager mSpManager;
     IAuthSecret mAuthSecretService;
+    WindowManagerInternal mMockWindowManager;
+    protected boolean mHasSecureLockScreen;
 
     @Override
     protected void setUp() throws Exception {
@@ -97,10 +100,13 @@
         mActivityManager = mock(IActivityManager.class);
         mDevicePolicyManager = mock(DevicePolicyManager.class);
         mDevicePolicyManagerInternal = mock(DevicePolicyManagerInternal.class);
+        mMockWindowManager = mock(WindowManagerInternal.class);
 
         LocalServices.removeServiceForTest(LockSettingsInternal.class);
         LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+        LocalServices.removeServiceForTest(WindowManagerInternal.class);
         LocalServices.addService(DevicePolicyManagerInternal.class, mDevicePolicyManagerInternal);
+        LocalServices.addService(WindowManagerInternal.class, mMockWindowManager);
 
         mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager,
                 mDevicePolicyManager, mock(StorageManager.class), mock(TrustManager.class),
@@ -114,11 +120,17 @@
             storageDir.mkdirs();
         }
 
+        mHasSecureLockScreen = true;
         mLockPatternUtils = new LockPatternUtils(mContext) {
             @Override
             public ILockSettings getLockSettings() {
                 return mService;
             }
+
+            @Override
+            public boolean hasSecureLockScreen() {
+                return mHasSecureLockScreen;
+            }
         };
         mSpManager = new MockSyntheticPasswordManager(mContext, mStorage, mGateKeeperService,
                 mUserManager);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index e12f6d3..5124803 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -26,13 +26,12 @@
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
 
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.service.gatekeeper.GateKeeperResponse;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.VerifyCredentialResponse;
-import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
 import com.android.server.locksettings.FakeGateKeeperService.VerifyHandle;
+import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
 
 /**
  * runtest frameworks-services -c com.android.server.locksettings.LockSettingsServiceTests
@@ -54,11 +53,21 @@
                 PASSWORD_QUALITY_ALPHABETIC);
     }
 
+    public void testCreatePasswordFailsWithoutLockScreen() throws RemoteException {
+        testCreateCredentialFailsWithoutLockScreen(PRIMARY_USER_ID, "password",
+                CREDENTIAL_TYPE_PASSWORD, PASSWORD_QUALITY_ALPHABETIC);
+    }
+
     public void testCreatePatternPrimaryUser() throws RemoteException {
         testCreateCredential(PRIMARY_USER_ID, "123456789", CREDENTIAL_TYPE_PATTERN,
                 PASSWORD_QUALITY_SOMETHING);
     }
 
+    public void testCreatePatternFailsWithoutLockScreen() throws RemoteException {
+        testCreateCredentialFailsWithoutLockScreen(PRIMARY_USER_ID, "123456789",
+                CREDENTIAL_TYPE_PATTERN, PASSWORD_QUALITY_SOMETHING);
+    }
+
     public void testChangePasswordPrimaryUser() throws RemoteException {
         testChangeCredentials(PRIMARY_USER_ID, "78963214", CREDENTIAL_TYPE_PATTERN,
                 "asdfghjk", CREDENTIAL_TYPE_PASSWORD, PASSWORD_QUALITY_ALPHABETIC);
@@ -198,6 +207,21 @@
         assertVerifyCredentials(userId, credential, type, -1);
     }
 
+    private void testCreateCredentialFailsWithoutLockScreen(
+            int userId, String credential, int type, int quality) throws RemoteException {
+        mHasSecureLockScreen = false;
+
+        try {
+            mService.setLockCredential(credential, type, null, quality, userId);
+            fail("An exception should have been thrown.");
+        } catch (UnsupportedOperationException e) {
+            // Success - the exception was expected.
+        }
+
+        assertFalse(mService.havePassword(userId));
+        assertFalse(mService.havePattern(userId));
+    }
+
     private void testChangeCredentials(int userId, String newCredential, int newType,
             String oldCredential, int oldType, int quality) throws RemoteException {
         final long sid = 1234;
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
index a28a5a1..929c3b5 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
@@ -77,6 +78,7 @@
         final Context context = InstrumentationRegistry.getTargetContext();
         mUserId = ActivityManager.getCurrentUser();
         mCommand = new LockSettingsShellCommand(mLockPatternUtils);
+        when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(true);
     }
 
     @Test
@@ -103,6 +105,16 @@
     }
 
     @Test
+    public void testChangePin_noLockScreen() throws Exception {
+        when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(false);
+        assertEquals(-1, mCommand.exec(new Binder(), in, out, err,
+                new String[] { "set-pin", "--old", "1234", "4321" },
+                mShellCallback, mResultReceiver));
+        verify(mLockPatternUtils).hasSecureLockScreen();
+        verifyNoMoreInteractions(mLockPatternUtils);
+    }
+
+    @Test
     public void testChangePassword() throws Exception {
         when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
         when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
@@ -115,6 +127,16 @@
     }
 
     @Test
+    public void testChangePassword_noLockScreen() throws Exception {
+        when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(false);
+        assertEquals(-1,  mCommand.exec(new Binder(), in, out, err,
+                new String[] { "set-password", "--old", "1234", "4321" },
+                mShellCallback, mResultReceiver));
+        verify(mLockPatternUtils).hasSecureLockScreen();
+        verifyNoMoreInteractions(mLockPatternUtils);
+    }
+
+    @Test
     public void testChangePattern() throws Exception {
         when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
         when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
@@ -126,6 +148,16 @@
     }
 
     @Test
+    public void testChangePattern_noLockScreen() throws Exception {
+        when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(false);
+        assertEquals(-1, mCommand.exec(new Binder(), in, out, err,
+                new String[] { "set-pattern", "--old", "1234", "4321" },
+                mShellCallback, mResultReceiver));
+        verify(mLockPatternUtils).hasSecureLockScreen();
+        verifyNoMoreInteractions(mLockPatternUtils);
+    }
+
+    @Test
     public void testClear() throws Exception {
         when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
         when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 94e02bc..0595a5b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -40,10 +40,10 @@
 import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken;
 import com.android.server.locksettings.SyntheticPasswordManager.PasswordData;
 
-import java.util.ArrayList;
-
 import org.mockito.ArgumentCaptor;
 
+import java.util.ArrayList;
+
 
 /**
  * runtest frameworks-services -c com.android.server.locksettings.SyntheticPasswordTests
@@ -448,6 +448,37 @@
         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
     }
 
+    public void testSetLockCredentialWithTokenFailsWithoutLockScreen() throws Exception {
+        final String password = "password";
+        final String pattern = "123654";
+        final String token = "some-high-entropy-secure-token";
+
+        mHasSecureLockScreen = false;
+        enableSyntheticPassword();
+        long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID);
+        assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+
+        try {
+            mLocalService.setLockCredentialWithToken(password,
+                    LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token.getBytes(),
+                    PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+            fail("An exception should have been thrown.");
+        } catch (UnsupportedOperationException e) {
+            // Success - the exception was expected.
+        }
+        assertFalse(mService.havePassword(PRIMARY_USER_ID));
+
+        try {
+            mLocalService.setLockCredentialWithToken(pattern,
+                    LockPatternUtils.CREDENTIAL_TYPE_PATTERN, handle, token.getBytes(),
+                    PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+            fail("An exception should have been thrown.");
+        } catch (UnsupportedOperationException e) {
+            // Success - the exception was expected.
+        }
+        assertFalse(mService.havePattern(PRIMARY_USER_ID));
+    }
+
     public void testgetHashFactorPrimaryUser() throws RemoteException {
         final String password = "password";
         mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index 8a9e5d1..c2d4846 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -23,6 +23,7 @@
 
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -91,6 +92,9 @@
     private static final byte[] TEST_VAULT_HANDLE =
             new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
     private static final String TEST_APP_KEY_ALIAS = "rcleaver";
+    private static final byte[] TEST_APP_KEY_METADATA_NULL = null;
+    private static final byte[] TEST_APP_KEY_METADATA_NON_NULL =
+            "mdata".getBytes(StandardCharsets.UTF_8);
     private static final int TEST_GENERATION_ID = 2;
     private static final int TEST_CREDENTIAL_TYPE = CREDENTIAL_TYPE_PATTERN;
     private static final String TEST_CREDENTIAL = "pas123";
@@ -251,7 +255,7 @@
                 TEST_USER_ID,
                 TEST_RECOVERY_AGENT_UID,
                 TEST_APP_KEY_ALIAS,
-                WrappedKey.fromSecretKey(mEncryptKey, applicationKey));
+                WrappedKey.fromSecretKey(mEncryptKey, applicationKey, TEST_APP_KEY_METADATA_NULL));
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
 
         mKeySyncTask.run();
@@ -267,7 +271,7 @@
                 TEST_USER_ID,
                 TEST_RECOVERY_AGENT_UID,
                 TEST_APP_KEY_ALIAS,
-                WrappedKey.fromSecretKey(mEncryptKey, applicationKey));
+                WrappedKey.fromSecretKey(mEncryptKey, applicationKey, TEST_APP_KEY_METADATA_NULL));
         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
@@ -545,18 +549,20 @@
         assertEquals(TEST_APP_KEY_ALIAS, keyData.getAlias());
         assertThat(keyData.getAlias()).isEqualTo(keyData.getAlias());
         byte[] appKey = KeySyncUtils.decryptApplicationKey(
-                recoveryKey, keyData.getEncryptedKeyMaterial());
+                recoveryKey, keyData.getEncryptedKeyMaterial(), TEST_APP_KEY_METADATA_NULL);
         assertThat(appKey).isEqualTo(applicationKey.getEncoded());
     }
 
     @Test
-    public void run_sendsEncryptedKeysIfAvailableToSync_withCertPath() throws Exception {
+    public void run_sendsEncryptedKeysIfAvailableToSync_withCertPath_withNullKeyMetadata()
+            throws Exception {
         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
         mRecoverableKeyStoreDb.setServerParams(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
         when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
-        addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS);
+        addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS,
+                TEST_APP_KEY_METADATA_NULL);
 
         mKeySyncTask.run();
 
@@ -564,6 +570,33 @@
         verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID);
         List<WrappedApplicationKey> applicationKeys = keyChainSnapshot.getWrappedApplicationKeys();
         assertThat(applicationKeys).hasSize(1);
+        WrappedApplicationKey keyData = applicationKeys.get(0);
+        assertThat(keyData.getAlias()).isEqualTo(TEST_APP_KEY_ALIAS);
+        assertThat(keyData.getMetadata()).isEqualTo(TEST_APP_KEY_METADATA_NULL);
+        assertThat(keyChainSnapshot.getTrustedHardwareCertPath())
+                .isEqualTo(TestData.CERT_PATH_1);
+    }
+
+    @Test
+    public void run_sendsEncryptedKeysIfAvailableToSync_withCertPath_withNonNullKeyMetadata()
+            throws Exception {
+        mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
+        mRecoverableKeyStoreDb.setServerParams(
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
+        when(mSnapshotListenersStorage.hasListener(TEST_RECOVERY_AGENT_UID)).thenReturn(true);
+        addApplicationKey(TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_APP_KEY_ALIAS,
+                TEST_APP_KEY_METADATA_NON_NULL);
+
+        mKeySyncTask.run();
+
+        KeyChainSnapshot keyChainSnapshot = mRecoverySnapshotStorage.get(TEST_RECOVERY_AGENT_UID);
+        verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID);
+        List<WrappedApplicationKey> applicationKeys = keyChainSnapshot.getWrappedApplicationKeys();
+        assertThat(applicationKeys).hasSize(1);
+        WrappedApplicationKey keyData = applicationKeys.get(0);
+        assertThat(keyData.getAlias()).isEqualTo(TEST_APP_KEY_ALIAS);
+        assertThat(keyData.getMetadata()).isEqualTo(TEST_APP_KEY_METADATA_NON_NULL);
         assertThat(keyChainSnapshot.getTrustedHardwareCertPath())
                 .isEqualTo(TestData.CERT_PATH_1);
     }
@@ -788,6 +821,11 @@
 
     private SecretKey addApplicationKey(int userId, int recoveryAgentUid, String alias)
             throws Exception{
+        return addApplicationKey(userId, recoveryAgentUid, alias, TEST_APP_KEY_METADATA_NULL);
+    }
+
+    private SecretKey addApplicationKey(int userId, int recoveryAgentUid, String alias,
+            byte[] metadata) throws Exception {
         SecretKey applicationKey = generateKey();
         mRecoverableKeyStoreDb.setServerParams(
                 userId, recoveryAgentUid, TEST_VAULT_HANDLE);
@@ -800,7 +838,7 @@
                 userId,
                 recoveryAgentUid,
                 alias,
-                WrappedKey.fromSecretKey(mEncryptKey, applicationKey));
+                WrappedKey.fromSecretKey(mEncryptKey, applicationKey, metadata));
         return applicationKey;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
index f832d3c..178fd10 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncUtilsTest.java
@@ -22,6 +22,8 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 
+import android.util.Pair;
+
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -65,7 +67,8 @@
     private static final byte[] RECOVERY_RESPONSE_HEADER =
             "V1 reencrypted_recovery_key".getBytes(StandardCharsets.UTF_8);
     private static final int PUBLIC_KEY_LENGTH_BYTES = 65;
-
+    private static final byte[] NULL_METADATA = null;
+    private static final byte[] NON_NULL_METADATA = "somemetadata".getBytes(StandardCharsets.UTF_8);
 
     @Test
     public void calculateThmKfHash_isShaOfLockScreenHashWithPrefix() throws Exception {
@@ -125,18 +128,35 @@
     }
 
     @Test
-    public void decryptApplicationKey_decryptsAnApplicationKeyEncryptedWithSecureBox()
-            throws Exception {
+    public void decryptApplicationKey_decryptsAnApplicationKey_nullMetadata() throws Exception {
         String alias = "phoebe";
         SecretKey recoveryKey = KeySyncUtils.generateRecoveryKey();
         SecretKey applicationKey = generateApplicationKey();
         Map<String, byte[]> encryptedKeys =
                 KeySyncUtils.encryptKeysWithRecoveryKey(
-                        recoveryKey, ImmutableMap.of(alias, applicationKey));
+                        recoveryKey,
+                        ImmutableMap.of(alias, Pair.create(applicationKey, NULL_METADATA)));
         byte[] encryptedKey = encryptedKeys.get(alias);
 
-        byte[] keyMaterial =
-                KeySyncUtils.decryptApplicationKey(recoveryKey.getEncoded(), encryptedKey);
+        byte[] keyMaterial = KeySyncUtils.decryptApplicationKey(recoveryKey.getEncoded(),
+                encryptedKey, NULL_METADATA);
+
+        assertArrayEquals(applicationKey.getEncoded(), keyMaterial);
+    }
+
+    @Test
+    public void decryptApplicationKey_decryptsAnApplicationKey_nonNullMetadata() throws Exception {
+        String alias = "phoebe";
+        SecretKey recoveryKey = KeySyncUtils.generateRecoveryKey();
+        SecretKey applicationKey = generateApplicationKey();
+        Map<String, byte[]> encryptedKeys =
+                KeySyncUtils.encryptKeysWithRecoveryKey(
+                        recoveryKey,
+                        ImmutableMap.of(alias, Pair.create(applicationKey, NON_NULL_METADATA)));
+        byte[] encryptedKey = encryptedKeys.get(alias);
+
+        byte[] keyMaterial = KeySyncUtils.decryptApplicationKey(recoveryKey.getEncoded(),
+                encryptedKey, NON_NULL_METADATA);
 
         assertArrayEquals(applicationKey.getEncoded(), keyMaterial);
     }
@@ -147,12 +167,13 @@
         Map<String, byte[]> encryptedKeys =
                 KeySyncUtils.encryptKeysWithRecoveryKey(
                         KeySyncUtils.generateRecoveryKey(),
-                        ImmutableMap.of("casper", generateApplicationKey()));
+                        ImmutableMap.of("casper",
+                                Pair.create(generateApplicationKey(), NULL_METADATA)));
         byte[] encryptedKey = encryptedKeys.get(alias);
 
         try {
-            KeySyncUtils.decryptApplicationKey(
-                    KeySyncUtils.generateRecoveryKey().getEncoded(), encryptedKey);
+            KeySyncUtils.decryptApplicationKey(KeySyncUtils.generateRecoveryKey().getEncoded(),
+                    encryptedKey, NULL_METADATA);
             fail("Did not throw decrypting with bad key.");
         } catch (AEADBadTagException error) {
             // expected
@@ -160,6 +181,47 @@
     }
 
     @Test
+    public void decryptApplicationKey_throwsIfWrongMetadata() throws Exception {
+        String alias1 = "casper1";
+        String alias2 = "casper2";
+        String alias3 = "casper3";
+        SecretKey recoveryKey = KeySyncUtils.generateRecoveryKey();
+
+        Map<String, byte[]> encryptedKeys =
+                KeySyncUtils.encryptKeysWithRecoveryKey(
+                        recoveryKey,
+                        ImmutableMap.of(
+                                alias1,
+                                Pair.create(generateApplicationKey(), NULL_METADATA),
+                                alias2,
+                                Pair.create(generateApplicationKey(), NON_NULL_METADATA),
+                                alias3,
+                                Pair.create(generateApplicationKey(), NON_NULL_METADATA)));
+
+        try {
+            KeySyncUtils.decryptApplicationKey(recoveryKey.getEncoded(),
+                    encryptedKeys.get(alias1), NON_NULL_METADATA);
+            fail("Did not throw decrypting with wrong metadata.");
+        } catch (AEADBadTagException error) {
+            // expected
+        }
+        try {
+            KeySyncUtils.decryptApplicationKey(recoveryKey.getEncoded(),
+                    encryptedKeys.get(alias2), NULL_METADATA);
+            fail("Did not throw decrypting with wrong metadata.");
+        } catch (AEADBadTagException error) {
+            // expected
+        }
+        try {
+            KeySyncUtils.decryptApplicationKey(recoveryKey.getEncoded(),
+                    encryptedKeys.get(alias3), "different".getBytes(StandardCharsets.UTF_8));
+            fail("Did not throw decrypting with wrong metadata.");
+        } catch (AEADBadTagException error) {
+            // expected
+        }
+    }
+
+    @Test
     public void decryptRecoveryKey_decryptsALocallyEncryptedKey() throws Exception {
         SecretKey recoveryKey = KeySyncUtils.generateRecoveryKey();
         byte[] encrypted = KeySyncUtils.locallyEncryptRecoveryKey(
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
index 48afb8b..c295177 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java
@@ -20,6 +20,7 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 
 import android.content.Context;
 import android.security.keystore.AndroidKeyStoreSecretKey;
@@ -60,6 +61,9 @@
     private static final int TEST_USER_ID = 1000;
     private static final int KEYSTORE_UID_SELF = -1;
     private static final int GCM_TAG_LENGTH_BITS = 128;
+    private static final byte[] NULL_METADATA = null;
+    private static final byte[] NON_NULL_METADATA = "test-metadata".getBytes(
+            StandardCharsets.UTF_8);
 
     private PlatformEncryptionKey mPlatformKey;
     private PlatformDecryptionKey mDecryptKey;
@@ -90,18 +94,29 @@
     }
 
     @Test
-    public void generateAndStoreKey_storesWrappedKey() throws Exception {
+    public void generateAndStoreKey_storesWrappedKey_nullMetadata() throws Exception {
         mRecoverableKeyGenerator.generateAndStoreKey(
-                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS);
+                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, NULL_METADATA);
 
         WrappedKey wrappedKey = mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS);
         assertNotNull(wrappedKey);
+        assertNull(wrappedKey.getKeyMetadata());
+    }
+
+    @Test
+    public void generateAndStoreKey_storesWrappedKey_nonNullMetadata() throws Exception {
+        mRecoverableKeyGenerator.generateAndStoreKey(
+                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, NON_NULL_METADATA);
+
+        WrappedKey wrappedKey = mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS);
+        assertNotNull(wrappedKey);
+        assertArrayEquals(NON_NULL_METADATA, wrappedKey.getKeyMetadata());
     }
 
     @Test
     public void generateAndStoreKey_returnsRawMaterialOfCorrectLength() throws Exception {
         byte[] rawKey = mRecoverableKeyGenerator.generateAndStoreKey(
-                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS);
+                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, NON_NULL_METADATA);
 
         assertEquals(KEY_SIZE_BYTES, rawKey.length);
     }
@@ -109,7 +124,7 @@
     @Test
     public void generateAndStoreKey_storesTheWrappedVersionOfTheRawMaterial() throws Exception {
         byte[] rawMaterial = mRecoverableKeyGenerator.generateAndStoreKey(
-                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS);
+                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, NULL_METADATA);
 
         WrappedKey wrappedKey = mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS);
         Cipher cipher = Cipher.getInstance(KEY_WRAP_ALGORITHM);
@@ -120,10 +135,30 @@
     }
 
     @Test
+    public void importKey_storesNullMetadata() throws Exception {
+        mRecoverableKeyGenerator.importKey(
+                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS,
+                randomBytes(KEY_SIZE_BYTES),
+                NULL_METADATA);
+        assertNull(mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS).getKeyMetadata());
+    }
+
+    @Test
+    public void importKey_storesNonNullMetadata() throws Exception {
+        mRecoverableKeyGenerator.importKey(
+                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS,
+                randomBytes(KEY_SIZE_BYTES),
+                NON_NULL_METADATA);
+        assertArrayEquals(NON_NULL_METADATA,
+                mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS).getKeyMetadata());
+    }
+
+    @Test
     public void importKey_storesTheWrappedVersionOfTheRawMaterial() throws Exception {
         byte[] rawMaterial = randomBytes(KEY_SIZE_BYTES);
         mRecoverableKeyGenerator.importKey(
-                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, rawMaterial);
+                mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, rawMaterial,
+                NULL_METADATA);
 
         WrappedKey wrappedKey = mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS);
         Cipher cipher = Cipher.getInstance(KEY_WRAP_ALGORITHM);
@@ -145,10 +180,6 @@
         return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
     }
 
-    private static byte[] getUtf8Bytes(String s) {
-        return s.getBytes(StandardCharsets.UTF_8);
-    }
-
     private static byte[] randomBytes(int n) {
         byte[] bytes = new byte[n];
         new Random().nextBytes(bytes);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index b15863d..c78b96d 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -52,6 +52,7 @@
 import android.security.keystore.recovery.RecoveryCertPath;
 import android.security.keystore.recovery.TrustedRootCertificates;
 import android.security.keystore.recovery.WrappedApplicationKey;
+import android.util.Pair;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -134,6 +135,8 @@
     private static final int GENERATION_ID = 1;
     private static final byte[] NONCE = getUtf8Bytes("nonce");
     private static final byte[] KEY_MATERIAL = getUtf8Bytes("keymaterial");
+    private static final byte[] KEY_METADATA_NULL = null;
+    private static final byte[] KEY_METADATA_NON_NULL = getUtf8Bytes("keymetametadata");
     private static final String KEY_ALGORITHM = "AES";
     private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
     private static final String WRAPPING_KEY_ALIAS = "RecoverableKeyStoreManagerTest/WrappingKey";
@@ -231,6 +234,77 @@
     }
 
     @Test
+    public void importKeyWithMetadata_nullMetadata_storesTheKey() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        byte[] keyMaterial = randomBytes(APPLICATION_KEY_SIZE_BYTES);
+
+        mRecoverableKeyStoreManager.importKeyWithMetadata(
+                TEST_ALIAS, keyMaterial, KEY_METADATA_NULL);
+
+        assertThat(mRecoverableKeyStoreDb.getKey(uid, TEST_ALIAS)).isNotNull();
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+    }
+
+    @Test
+    public void importKeyWithMetadata_nonNullMetadata_storesTheKey() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+        byte[] keyMaterial = randomBytes(APPLICATION_KEY_SIZE_BYTES);
+
+        mRecoverableKeyStoreManager.importKeyWithMetadata(
+                TEST_ALIAS, keyMaterial, KEY_METADATA_NON_NULL);
+
+        assertThat(mRecoverableKeyStoreDb.getKey(uid, TEST_ALIAS)).isNotNull();
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+    }
+
+    @Test
+    public void importKeyWithMetadata_throwsIfInvalidLength() throws Exception {
+        byte[] keyMaterial = randomBytes(APPLICATION_KEY_SIZE_BYTES - 1);
+        try {
+            mRecoverableKeyStoreManager.importKeyWithMetadata(
+                    TEST_ALIAS, keyMaterial, KEY_METADATA_NON_NULL);
+            fail("should have thrown");
+        } catch (ServiceSpecificException e) {
+            assertThat(e.getMessage()).contains("not contain 256 bits");
+        }
+    }
+
+    @Test
+    public void importKeyWithMetadata_throwsIfNullKey() throws Exception {
+        try {
+            mRecoverableKeyStoreManager.importKeyWithMetadata(
+                    TEST_ALIAS, /*keyBytes=*/ null, KEY_METADATA_NON_NULL);
+            fail("should have thrown");
+        } catch (NullPointerException e) {
+            assertThat(e.getMessage()).contains("is null");
+        }
+    }
+
+    @Test
+    public void generateKeyWithMetadata_nullMetadata_storesTheKey() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+
+        mRecoverableKeyStoreManager.generateKeyWithMetadata(TEST_ALIAS, KEY_METADATA_NULL);
+
+        assertThat(mRecoverableKeyStoreDb.getKey(uid, TEST_ALIAS)).isNotNull();
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+    }
+
+    @Test
+    public void generateKeyWithMetadata_nonNullMetadata_storesTheKey() throws Exception {
+        int uid = Binder.getCallingUid();
+        int userId = UserHandle.getCallingUserId();
+
+        mRecoverableKeyStoreManager.generateKeyWithMetadata(TEST_ALIAS, KEY_METADATA_NON_NULL);
+
+        assertThat(mRecoverableKeyStoreDb.getKey(uid, TEST_ALIAS)).isNotNull();
+        assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue();
+    }
+
+    @Test
     public void removeKey_removesAKey() throws Exception {
         int uid = Binder.getCallingUid();
         mRecoverableKeyStoreManager.generateKey(TEST_ALIAS);
@@ -1143,7 +1217,10 @@
         int status = 100;
         int status2 = 200;
         String alias = "key1";
-        WrappedKey wrappedKey = new WrappedKey(NONCE, KEY_MATERIAL, GENERATION_ID, status);
+        byte[] keyMetadata = null;
+
+        WrappedKey wrappedKey = new WrappedKey(NONCE, KEY_MATERIAL, keyMetadata, GENERATION_ID,
+                status);
         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
         Map<String, Integer> statuses =
                 mRecoverableKeyStoreManager.getRecoveryStatus();
@@ -1169,7 +1246,8 @@
     private static byte[] encryptedApplicationKey(
             SecretKey recoveryKey, byte[] applicationKey) throws Exception {
         return KeySyncUtils.encryptKeysWithRecoveryKey(recoveryKey, ImmutableMap.of(
-                TEST_ALIAS, new SecretKeySpec(applicationKey, "AES")
+                TEST_ALIAS,
+                Pair.create(new SecretKeySpec(applicationKey, "AES"), /*metadata=*/ null)
         )).get(TEST_ALIAS);
     }
 
@@ -1203,7 +1281,7 @@
 
     private void generateKeyAndSimulateSync(int userId, int uid, int snapshotVersion)
             throws Exception{
-        mRecoverableKeyStoreManager.generateKey(TEST_ALIAS);
+        mRecoverableKeyStoreManager.generateKeyWithMetadata(TEST_ALIAS, KEY_METADATA_NULL);
         // Simulate key sync.
         mRecoverableKeyStoreDb.setSnapshotVersion(userId, uid, snapshotVersion);
         mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
index 944d6e0..9b4c3be 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
@@ -3,6 +3,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.security.keystore.recovery.TrustedRootCertificates;
+import android.util.Pair;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -64,10 +65,10 @@
 
     @Test
     public void testKeepOnlyWhitelistedInsecureKeys_emptyKeysList() throws Exception {
-        Map<String, SecretKey> rawKeys = new HashMap<>();
-        Map<String, SecretKey> expectedResult = new HashMap<>();
+        Map<String, Pair<SecretKey, byte[]>> rawKeys = new HashMap<>();
+        Map<String, Pair<SecretKey, byte[]>> expectedResult = new HashMap<>();
 
-        Map<String, SecretKey> filteredKeys =
+        Map<String, Pair<SecretKey, byte[]>> filteredKeys =
                 mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
         assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
         assertThat(filteredKeys.entrySet()).containsAllIn(rawKeys.entrySet());
@@ -75,13 +76,13 @@
 
     @Test
     public void testKeepOnlyWhitelistedInsecureKeys_singleNonWhitelistedKey() throws Exception {
-        Map<String, SecretKey> rawKeys = new HashMap<>();
-        Map<String, SecretKey> expectedResult = new HashMap<>();
+        Map<String, Pair<SecretKey, byte[]>> rawKeys = new HashMap<>();
+        Map<String, Pair<SecretKey, byte[]>> expectedResult = new HashMap<>();
 
         String alias = "secureAlias";
-        rawKeys.put(alias, TestData.generateKey());
+        rawKeys.put(alias, Pair.create(TestData.generateKey(), /*metadata=*/ null));
 
-        Map<String, SecretKey> filteredKeys =
+        Map<String, Pair<SecretKey, byte[]>> filteredKeys =
                 mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
         assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
         assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet());
@@ -89,14 +90,14 @@
 
     @Test
     public void testKeepOnlyWhitelistedInsecureKeys_singleWhitelistedKey() throws Exception {
-        Map<String, SecretKey> rawKeys = new HashMap<>();
-        Map<String, SecretKey> expectedResult = new HashMap<>();
+        Map<String, Pair<SecretKey, byte[]>> rawKeys = new HashMap<>();
+        Map<String, Pair<SecretKey, byte[]>> expectedResult = new HashMap<>();
 
         String alias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX;
-        rawKeys.put(alias, TestData.generateKey());
+        rawKeys.put(alias, Pair.create(TestData.generateKey(), /*metadata=*/ null));
         expectedResult.put(alias, rawKeys.get(alias));
 
-        Map<String, SecretKey> filteredKeys =
+        Map<String, Pair<SecretKey, byte[]>> filteredKeys =
                 mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
         assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
         assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet());
@@ -104,21 +105,21 @@
 
     @Test
     public void testKeepOnlyWhitelistedInsecureKeys() throws Exception {
-        Map<String, SecretKey> rawKeys = new HashMap<>();
-        Map<String, SecretKey> expectedResult = new HashMap<>();
+        Map<String, Pair<SecretKey, byte[]>> rawKeys = new HashMap<>();
+        Map<String, Pair<SecretKey, byte[]>> expectedResult = new HashMap<>();
 
         String alias = "SECURE_ALIAS" + TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX;
-        rawKeys.put(alias, TestData.generateKey());
+        rawKeys.put(alias, Pair.create(TestData.generateKey(), /*metadata=*/ null));
 
         alias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX + "1";
-        rawKeys.put(alias, TestData.generateKey());
+        rawKeys.put(alias, Pair.create(TestData.generateKey(), /*metadata=*/ null));
         expectedResult.put(alias, rawKeys.get(alias));
 
         alias = TrustedRootCertificates.INSECURE_KEY_ALIAS_PREFIX + "2";
-        rawKeys.put(alias, TestData.generateKey());
+        rawKeys.put(alias, Pair.create(TestData.generateKey(), /*metadata=*/ null));
         expectedResult.put(alias, rawKeys.get(alias));
 
-        Map<String, SecretKey> filteredKeys =
+        Map<String, Pair<SecretKey, byte[]>> filteredKeys =
                 mHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
         assertThat(filteredKeys.entrySet()).containsExactlyElementsIn(expectedResult.entrySet());
         assertThat(rawKeys.entrySet()).containsAllIn(filteredKeys.entrySet());
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java
index b5ee60e..9813ab7 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/WrappedKeyTest.java
@@ -24,6 +24,7 @@
 import android.security.keystore.AndroidKeyStoreSecretKey;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
+import android.util.Pair;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -32,6 +33,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.nio.charset.StandardCharsets;
 import java.security.KeyStore;
 import java.util.HashMap;
 import java.util.Map;
@@ -47,26 +49,49 @@
     private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
     private static final String KEY_ALGORITHM = "AES";
     private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
-    private static final String WRAPPING_KEY_ALIAS = "WrappedKeyTestWrappingKeyAlias";
+    private static final String WRAPPED_KEY_ALIAS = "WrappedKeyTestWrappingKeyAlias";
     private static final int GENERATION_ID = 1;
     private static final int GCM_TAG_LENGTH_BYTES = 16;
     private static final int BITS_PER_BYTE = 8;
     private static final int GCM_TAG_LENGTH_BITS = GCM_TAG_LENGTH_BYTES * BITS_PER_BYTE;
+    private static final byte[] NULL_METADATA = null;
+    private static final byte[] NON_NULL_METADATA = "keyMetadata".getBytes(StandardCharsets.UTF_8);
 
     @After
     public void tearDown() throws Exception {
         KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
         keyStore.load(/*param=*/ null);
-        keyStore.deleteEntry(WRAPPING_KEY_ALIAS);
+        keyStore.deleteEntry(WRAPPED_KEY_ALIAS);
     }
 
+    // TODO: Add tests for non-null metadata
+
     @Test
-    public void fromSecretKey_createsWrappedKeyThatCanBeUnwrapped() throws Exception {
+    public void fromSecretKey_createsWrappedKeyThatCanBeUnwrapped_nullMetadata() throws Exception {
         PlatformEncryptionKey wrappingKey = new PlatformEncryptionKey(
                 GENERATION_ID, generateAndroidKeyStoreKey());
         SecretKey rawKey = generateKey();
 
-        WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey);
+        WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey, NULL_METADATA);
+
+        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+        cipher.init(
+                Cipher.UNWRAP_MODE,
+                wrappingKey.getKey(),
+                new GCMParameterSpec(GCM_TAG_LENGTH_BITS, wrappedKey.getNonce()));
+        SecretKey unwrappedKey = (SecretKey) cipher.unwrap(
+                wrappedKey.getKeyMaterial(), KEY_ALGORITHM, Cipher.SECRET_KEY);
+        assertEquals(rawKey, unwrappedKey);
+    }
+
+    @Test
+    public void fromSecretKey_createsWrappedKeyThatCanBeUnwrapped_nonNullMetadata()
+            throws Exception {
+        PlatformEncryptionKey wrappingKey = new PlatformEncryptionKey(
+                GENERATION_ID, generateAndroidKeyStoreKey());
+        SecretKey rawKey = generateKey();
+
+        WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey, NON_NULL_METADATA);
 
         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
         cipher.init(
@@ -84,27 +109,47 @@
                 GENERATION_ID, generateAndroidKeyStoreKey());
         SecretKey rawKey = generateKey();
 
-        WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey);
+        WrappedKey wrappedKey = WrappedKey.fromSecretKey(wrappingKey, rawKey, NULL_METADATA);
 
         assertEquals(GENERATION_ID, wrappedKey.getPlatformKeyGenerationId());
     }
 
     @Test
-    public void decryptWrappedKeys_decryptsWrappedKeys() throws Exception {
+    public void decryptWrappedKeys_decryptsWrappedKeys_nullMetadata() throws Exception {
         String alias = "karlin";
         AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
         SecretKey appKey = generateKey();
         WrappedKey wrappedKey = WrappedKey.fromSecretKey(
-                new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey);
+                new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey, NULL_METADATA);
         HashMap<String, WrappedKey> keysByAlias = new HashMap<>();
         keysByAlias.put(alias, wrappedKey);
 
-        Map<String, SecretKey> unwrappedKeys = WrappedKey.unwrapKeys(
+        Map<String, Pair<SecretKey, byte[]>> unwrappedKeys = WrappedKey.unwrapKeys(
                 new PlatformDecryptionKey(GENERATION_ID, platformKey), keysByAlias);
 
         assertEquals(1, unwrappedKeys.size());
         assertTrue(unwrappedKeys.containsKey(alias));
-        assertArrayEquals(appKey.getEncoded(), unwrappedKeys.get(alias).getEncoded());
+        assertArrayEquals(appKey.getEncoded(), unwrappedKeys.get(alias).first.getEncoded());
+        assertArrayEquals(null, unwrappedKeys.get(alias).second);
+    }
+
+    @Test
+    public void decryptWrappedKeys_decryptsWrappedKeys_nonNullMetadata() throws Exception {
+        String alias = "karlin";
+        AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
+        SecretKey appKey = generateKey();
+        WrappedKey wrappedKey = WrappedKey.fromSecretKey(
+                new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey, NON_NULL_METADATA);
+        HashMap<String, WrappedKey> keysByAlias = new HashMap<>();
+        keysByAlias.put(alias, wrappedKey);
+
+        Map<String, Pair<SecretKey, byte[]>> unwrappedKeys = WrappedKey.unwrapKeys(
+                new PlatformDecryptionKey(GENERATION_ID, platformKey), keysByAlias);
+
+        assertEquals(1, unwrappedKeys.size());
+        assertTrue(unwrappedKeys.containsKey(alias));
+        assertArrayEquals(appKey.getEncoded(), unwrappedKeys.get(alias).first.getEncoded());
+        assertArrayEquals(NON_NULL_METADATA, unwrappedKeys.get(alias).second);
     }
 
     @Test
@@ -113,11 +158,11 @@
         AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
         SecretKey appKey = generateKey();
         WrappedKey wrappedKey = WrappedKey.fromSecretKey(
-                new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey);
+                new PlatformEncryptionKey(GENERATION_ID, platformKey), appKey, NULL_METADATA);
         HashMap<String, WrappedKey> keysByAlias = new HashMap<>();
         keysByAlias.put(alias, wrappedKey);
 
-        Map<String, SecretKey> unwrappedKeys = WrappedKey.unwrapKeys(
+        Map<String, Pair<SecretKey, byte[]>> unwrappedKeys = WrappedKey.unwrapKeys(
                 new PlatformDecryptionKey(GENERATION_ID, generateAndroidKeyStoreKey()),
                 keysByAlias);
 
@@ -128,7 +173,8 @@
     public void decryptWrappedKeys_throwsIfPlatformKeyGenerationIdDoesNotMatch() throws Exception {
         AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey();
         WrappedKey wrappedKey = WrappedKey.fromSecretKey(
-                new PlatformEncryptionKey(GENERATION_ID, platformKey), generateKey());
+                new PlatformEncryptionKey(GENERATION_ID, platformKey), generateKey(),
+                /*metadata=*/ null);
         HashMap<String, WrappedKey> keysByAlias = new HashMap<>();
         keysByAlias.put("benji", wrappedKey);
 
@@ -156,19 +202,11 @@
                 KEY_ALGORITHM,
                 ANDROID_KEY_STORE_PROVIDER);
         keyGenerator.init(new KeyGenParameterSpec.Builder(
-                WRAPPING_KEY_ALIAS,
+                WRAPPED_KEY_ALIAS,
                 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                 .build());
         return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
     }
-
-    private PlatformDecryptionKey generatePlatformDecryptionKey() throws Exception {
-        return generatePlatformDecryptionKey(GENERATION_ID);
-    }
-
-    private PlatformDecryptionKey generatePlatformDecryptionKey(int generationId) throws Exception {
-        return new PlatformDecryptionKey(generationId, generateAndroidKeyStoreKey());
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java
index 880255d..9c03df8 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java
@@ -55,12 +55,15 @@
 
     private static final String TEST_KEY_1_ALIAS = "key1";
     private static final byte[] TEST_KEY_1_BYTES = new byte[] { 66, 77, 88 };
+    private static final byte[] TEST_KEY_1_METADATA = new byte[] { 89, 87 };
 
     private static final String TEST_KEY_2_ALIAS = "key2";
     private static final byte[] TEST_KEY_2_BYTES = new byte[] { 99, 33, 11 };
+    private static final byte[] TEST_KEY_2_METADATA = new byte[] {};
 
     private static final String TEST_KEY_3_ALIAS = "key3";
     private static final byte[] TEST_KEY_3_BYTES = new byte[] { 2, 8, 100 };
+    private static final byte[] TEST_KEY_3_METADATA = new byte[] { 121 };
 
     @Test
     public void roundTrip_persistsCounterId() throws Exception {
@@ -144,6 +147,17 @@
     }
 
     @Test
+    public void roundTripKeys_0_persistsKeyMetadata_absent() throws Exception {
+        assertThat(roundTripKeys(/*withKeyMetadata=*/ false).get(0).getMetadata()).isEqualTo(null);
+    }
+
+    @Test
+    public void roundTripKeys_0_persistsKeyMetadata_present() throws Exception {
+        assertThat(roundTripKeys(/*withKeyMetadata=*/ true).get(0).getMetadata())
+                .isEqualTo(TEST_KEY_1_METADATA);
+    }
+
+    @Test
     public void roundTripKeys_1_persistsAlias() throws Exception {
         assertThat(roundTripKeys().get(1).getAlias()).isEqualTo(TEST_KEY_2_ALIAS);
     }
@@ -154,6 +168,17 @@
     }
 
     @Test
+    public void roundTripKeys_1_persistsKeyMetadata_absent() throws Exception {
+        assertThat(roundTripKeys(/*withKeyMetadata=*/ false).get(1).getMetadata()).isEqualTo(null);
+    }
+
+    @Test
+    public void roundTripKeys_1_persistsKeyMetadata_present() throws Exception {
+        assertThat(roundTripKeys(/*withKeyMetadata=*/ true).get(1).getMetadata())
+                .isEqualTo(TEST_KEY_2_METADATA);
+    }
+
+    @Test
     public void roundTripKeys_2_persistsAlias() throws Exception {
         assertThat(roundTripKeys().get(2).getAlias()).isEqualTo(TEST_KEY_3_ALIAS);
     }
@@ -164,28 +189,74 @@
     }
 
     @Test
-    public void serialize_doesNotThrowForTestSnapshot() throws Exception {
+    public void roundTripKeys_2_persistsKeyMetadata_absent() throws Exception {
+        assertThat(roundTripKeys(/*withKeyMetadata=*/ false).get(2).getMetadata()).isEqualTo(null);
+    }
+
+    @Test
+    public void roundTripKeys_2_persistsKeyMetadata_present() throws Exception {
+        assertThat(roundTripKeys(/*withKeyMetadata=*/ true).get(2).getMetadata())
+                .isEqualTo(TEST_KEY_3_METADATA);
+    }
+
+    @Test
+    public void serialize_doesNotThrowForTestSnapshotWithoutKeyMetadata() throws Exception {
         KeyChainSnapshotSerializer.serialize(
-                createTestKeyChainSnapshot(), new ByteArrayOutputStream());
+                createTestKeyChainSnapshot(/*withKeyMetadata=*/ false),
+                new ByteArrayOutputStream());
+    }
+
+    @Test
+    public void serialize_doesNotThrowForTestSnapshotWithKeyMetadata() throws Exception {
+        KeyChainSnapshotSerializer.serialize(
+                createTestKeyChainSnapshotWithKeyMetadata(), new ByteArrayOutputStream());
     }
 
     private static List<WrappedApplicationKey> roundTripKeys() throws Exception {
         return roundTrip().getWrappedApplicationKeys();
     }
 
+    private static List<WrappedApplicationKey> roundTripKeys(boolean withKeyMetadata)
+            throws Exception {
+        return roundTrip(withKeyMetadata).getWrappedApplicationKeys();
+    }
+
     private static KeyChainProtectionParams roundTripParams() throws Exception {
-        return roundTrip().getKeyChainProtectionParams().get(0);
+        return roundTrip(/*withKeyMetadata=*/ false).getKeyChainProtectionParams().get(0);
     }
 
     public static KeyChainSnapshot roundTrip() throws Exception {
-        KeyChainSnapshot snapshot = createTestKeyChainSnapshot();
+        return roundTrip(/*withKeyMetadata=*/ false);
+    }
+
+    public static KeyChainSnapshot roundTrip(boolean withKeyMetadata) throws Exception {
+        KeyChainSnapshot snapshot = createTestKeyChainSnapshot(withKeyMetadata);
         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
         KeyChainSnapshotSerializer.serialize(snapshot, byteArrayOutputStream);
         return KeyChainSnapshotDeserializer.deserialize(
                 new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
     }
 
-    private static KeyChainSnapshot createTestKeyChainSnapshot() throws Exception {
+    private static KeyChainSnapshot createTestKeyChainSnapshot(boolean withKeyMetadata)
+            throws Exception {
+        KeyChainSnapshot.Builder builder = new KeyChainSnapshot.Builder()
+                .setCounterId(COUNTER_ID)
+                .setSnapshotVersion(SNAPSHOT_VERSION)
+                .setServerParams(SERVER_PARAMS)
+                .setMaxAttempts(MAX_ATTEMPTS)
+                .setEncryptedRecoveryKeyBlob(KEY_BLOB)
+                .setKeyChainProtectionParams(createKeyChainProtectionParamsList())
+                .setTrustedHardwareCertPath(CERT_PATH);
+        if (withKeyMetadata) {
+            builder.setWrappedApplicationKeys(createKeysWithMetadata());
+        } else {
+            builder.setWrappedApplicationKeys(createKeysWithoutMetadata());
+        }
+        return builder.build();
+    }
+
+    private static KeyChainSnapshot createTestKeyChainSnapshotWithKeyMetadata()
+            throws Exception {
         return new KeyChainSnapshot.Builder()
                 .setCounterId(COUNTER_ID)
                 .setSnapshotVersion(SNAPSHOT_VERSION)
@@ -193,16 +264,24 @@
                 .setMaxAttempts(MAX_ATTEMPTS)
                 .setEncryptedRecoveryKeyBlob(KEY_BLOB)
                 .setKeyChainProtectionParams(createKeyChainProtectionParamsList())
-                .setWrappedApplicationKeys(createKeys())
+                .setWrappedApplicationKeys(createKeysWithMetadata())
                 .setTrustedHardwareCertPath(CERT_PATH)
                 .build();
     }
 
-    private static List<WrappedApplicationKey> createKeys() {
+    private static List<WrappedApplicationKey> createKeysWithoutMetadata() {
         ArrayList<WrappedApplicationKey> keyList = new ArrayList<>();
-        keyList.add(createKey(TEST_KEY_1_ALIAS, TEST_KEY_1_BYTES));
-        keyList.add(createKey(TEST_KEY_2_ALIAS, TEST_KEY_2_BYTES));
-        keyList.add(createKey(TEST_KEY_3_ALIAS, TEST_KEY_3_BYTES));
+        keyList.add(createKey(TEST_KEY_1_ALIAS, TEST_KEY_1_BYTES, /*metadata=*/ null));
+        keyList.add(createKey(TEST_KEY_2_ALIAS, TEST_KEY_2_BYTES, /*metadata=*/ null));
+        keyList.add(createKey(TEST_KEY_3_ALIAS, TEST_KEY_3_BYTES, /*metadata=*/ null));
+        return keyList;
+    }
+
+    private static List<WrappedApplicationKey> createKeysWithMetadata() {
+        ArrayList<WrappedApplicationKey> keyList = new ArrayList<>();
+        keyList.add(createKey(TEST_KEY_1_ALIAS, TEST_KEY_1_BYTES, TEST_KEY_1_METADATA));
+        keyList.add(createKey(TEST_KEY_2_ALIAS, TEST_KEY_2_BYTES, TEST_KEY_2_METADATA));
+        keyList.add(createKey(TEST_KEY_3_ALIAS, TEST_KEY_3_BYTES, TEST_KEY_3_METADATA));
         return keyList;
     }
 
@@ -221,10 +300,13 @@
         return keyChainProtectionParamsList;
     }
 
-    private static WrappedApplicationKey createKey(String alias, byte[] bytes) {
-        return new WrappedApplicationKey.Builder()
+    private static WrappedApplicationKey createKey(String alias, byte[] bytes, byte[] metadata) {
+        WrappedApplicationKey.Builder builder = new WrappedApplicationKey.Builder()
                 .setAlias(alias)
-                .setEncryptedKeyMaterial(bytes)
-                .build();
+                .setEncryptedKeyMaterial(bytes);
+        if (metadata != null) {
+            builder.setMetadata(metadata);
+        }
+        return builder.build();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
index 7130b42..35215c3 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java
@@ -60,6 +60,7 @@
     private static final String TEST_ROOT_ALIAS = "root_cert_alias";
     private static final byte[] TEST_CERT_PATH = "test-cert-path".getBytes(UTF_8);
     private static final long TEST_CERT_SERIAL = 1000L;
+    private static final byte[] TEST_KEY_METADATA = "test-key-metadata".getBytes(UTF_8);
 
     private static final String SQL_CREATE_V2_TABLE_KEYS =
             "CREATE TABLE " + KeysEntry.TABLE_NAME + "( "
@@ -120,14 +121,14 @@
     @Test
     public void onCreate() throws Exception {
         mDatabaseHelper.onCreate(mDatabase);
-        checkAllColumns();
+        checkAllColumns_latest();
     }
 
     @Test
     public void onUpgrade_beforeV2() throws Exception {
         mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 1,
                 RecoverableKeyStoreDbHelper.DATABASE_VERSION);
-        checkAllColumns();
+        checkAllColumns_latest();
     }
 
     @Test
@@ -135,11 +136,11 @@
         createV2Tables();
         mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 2,
                 RecoverableKeyStoreDbHelper.DATABASE_VERSION);
-        checkAllColumns();
+        checkAllColumns_latest();
     }
 
     @Test
-    public void onUpgrade_v2_to_v3_to_v4() throws Exception {
+    public void onUpgrade_v2_to_v3_to_v4_to_latest() throws Exception {
         createV2Tables();
 
         assertThat(isRootOfTrustTableAvailable()).isFalse(); // V2 doesn't have the table;
@@ -148,9 +149,12 @@
 
         assertThat(isRootOfTrustTableAvailable()).isFalse(); // V3 doesn't have the table;
 
-        mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 3,
+        mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 3, /*newVersion=*/ 4);
+        checkAllColumns_v4();
+
+        mDatabaseHelper.onUpgrade(mDatabase, /*oldVersion=*/ 4,
                 RecoverableKeyStoreDbHelper.DATABASE_VERSION);
-        checkAllColumns();
+        checkAllColumns_latest();
     }
 
     private boolean isRootOfTrustTableAvailable() {
@@ -160,11 +164,11 @@
         values.put(RootOfTrustEntry.COLUMN_NAME_ROOT_ALIAS, TEST_ROOT_ALIAS);
         values.put(RootOfTrustEntry.COLUMN_NAME_CERT_PATH, TEST_CERT_PATH);
         values.put(RootOfTrustEntry.COLUMN_NAME_CERT_SERIAL, TEST_CERT_SERIAL);
-        return mDatabase.insert(RootOfTrustEntry.TABLE_NAME, /*nullColumnHack=*/ null, values)
+        return mDatabase.replace(RootOfTrustEntry.TABLE_NAME, /*nullColumnHack=*/ null, values)
                 > -1;
     }
 
-    private void checkAllColumns() throws Exception {
+    private void checkAllColumns_v4() throws Exception {
         // Check the table containing encrypted application keys
         ContentValues values = new ContentValues();
         values.put(KeysEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
@@ -175,7 +179,7 @@
         values.put(KeysEntry.COLUMN_NAME_GENERATION_ID, TEST_GENERATION_ID);
         values.put(KeysEntry.COLUMN_NAME_LAST_SYNCED_AT, TEST_LAST_SYNCED_AT);
         values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS, TEST_RECOVERY_STATUS);
-        assertThat(mDatabase.insert(KeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
+        assertThat(mDatabase.replace(KeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
                 .isGreaterThan(-1L);
 
         // Check the table about user metadata
@@ -183,7 +187,8 @@
         values.put(UserMetadataEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
         values.put(UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID,
                 TEST_PLATFORM_KEY_GENERATION_ID);
-        assertThat(mDatabase.insert(UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
+        assertThat(
+                mDatabase.replace(UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
                 .isGreaterThan(-1L);
 
         // Check the table about recovery service metadata
@@ -202,11 +207,32 @@
         values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_PATH, TEST_CERT_PATH);
         values.put(RecoveryServiceMetadataEntry.COLUMN_NAME_CERT_SERIAL, TEST_CERT_SERIAL);
         assertThat(
-                mDatabase.insert(RecoveryServiceMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null,
+                mDatabase.replace(RecoveryServiceMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null,
                         values))
                 .isGreaterThan(-1L);
 
         // Check the table about recovery service and root of trust data introduced in V4
         assertThat(isRootOfTrustTableAvailable()).isTrue();
     }
+
+    private void checkAllColumns_latest() throws Exception {
+        // Check all columns of the previous version first.
+        checkAllColumns_v4();
+
+        ContentValues values = new ContentValues();
+        values.put(KeysEntry.COLUMN_NAME_USER_ID, TEST_USER_ID);
+        values.put(KeysEntry.COLUMN_NAME_UID, TEST_UID);
+        values.put(KeysEntry.COLUMN_NAME_ALIAS, TEST_ALIAS);
+        values.put(KeysEntry.COLUMN_NAME_NONCE, TEST_NONCE);
+        values.put(KeysEntry.COLUMN_NAME_WRAPPED_KEY, TEST_WRAPPED_KEY);
+        values.put(KeysEntry.COLUMN_NAME_GENERATION_ID, TEST_GENERATION_ID);
+        values.put(KeysEntry.COLUMN_NAME_LAST_SYNCED_AT, TEST_LAST_SYNCED_AT);
+        values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS, TEST_RECOVERY_STATUS);
+
+        // This column is added when upgrading from v4 to v5
+        values.put(KeysEntry.COLUMN_NAME_KEY_METADATA, TEST_KEY_METADATA);
+
+        assertThat(mDatabase.replace(KeysEntry.TABLE_NAME, /*nullColumnHack=*/ null, values))
+                .isGreaterThan(-1L);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
index 6a26f8c..7de9ffc 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
@@ -80,25 +80,33 @@
     public void insertKey_replacesOldKey() {
         int userId = 12;
         int uid = 10009;
-        String alias = "test";
-        WrappedKey oldWrappedKey = new WrappedKey(
-                getUtf8Bytes("nonce1"),
-                getUtf8Bytes("keymaterial1"),
-                /*platformKeyGenerationId=*/ 1);
-        mRecoverableKeyStoreDb.insertKey(
-                userId, uid, alias, oldWrappedKey);
-        byte[] nonce = getUtf8Bytes("nonce2");
-        byte[] keyMaterial = getUtf8Bytes("keymaterial2");
-        WrappedKey newWrappedKey = new WrappedKey(
-                nonce, keyMaterial, /*platformKeyGenerationId=*/2);
+        String alias = "test-alias";
 
-        mRecoverableKeyStoreDb.insertKey(
-                userId, uid, alias, newWrappedKey);
+        byte[] nonce = getUtf8Bytes("nonce1");
+        byte[] keyMaterial = getUtf8Bytes("keymaterial1");
+        byte[] keyMetadata = null;
+        int generationId = 1;
+        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId);
+        mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
 
         WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
         assertArrayEquals(nonce, retrievedKey.getNonce());
         assertArrayEquals(keyMaterial, retrievedKey.getKeyMaterial());
-        assertEquals(2, retrievedKey.getPlatformKeyGenerationId());
+        assertArrayEquals(keyMetadata, retrievedKey.getKeyMetadata());
+        assertEquals(generationId, retrievedKey.getPlatformKeyGenerationId());
+
+        nonce = getUtf8Bytes("nonce2");
+        keyMaterial = getUtf8Bytes("keymaterial2");
+        keyMetadata = getUtf8Bytes("keymetadata2");
+        generationId = 2;
+        wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId);
+        mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
+
+        retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
+        assertArrayEquals(nonce, retrievedKey.getNonce());
+        assertArrayEquals(keyMaterial, retrievedKey.getKeyMaterial());
+        assertArrayEquals(keyMetadata, retrievedKey.getKeyMetadata());
+        assertEquals(generationId, retrievedKey.getPlatformKeyGenerationId());
     }
 
     @Test
@@ -108,10 +116,12 @@
         WrappedKey key1 = new WrappedKey(
                 getUtf8Bytes("nonce1"),
                 getUtf8Bytes("key1"),
+                /*metadata=*/ null,
                 /*platformKeyGenerationId=*/ 1);
         WrappedKey key2 = new WrappedKey(
                 getUtf8Bytes("nonce2"),
                 getUtf8Bytes("key2"),
+                /*metadata=*/ null,
                 /*platformKeyGenerationId=*/ 1);
 
         mRecoverableKeyStoreDb.insertKey(userId, /*uid=*/ 1, alias, key1);
@@ -133,6 +143,7 @@
         WrappedKey key = new WrappedKey(
                 getUtf8Bytes("nonce1"),
                 getUtf8Bytes("key1"),
+                /*metadata=*/ null,
                 /*platformKeyGenerationId=*/ 1);
         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, key);
 
@@ -158,13 +169,16 @@
         String alias = "test";
         byte[] nonce = getUtf8Bytes("nonce");
         byte[] keyMaterial = getUtf8Bytes("keymaterial");
-        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId, 120);
+        byte[] keyMetadata = getUtf8Bytes("keymetametametadata");
+
+        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId, 120);
         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
 
         WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
 
         assertArrayEquals(nonce, retrievedKey.getNonce());
         assertArrayEquals(keyMaterial, retrievedKey.getKeyMaterial());
+        assertArrayEquals(keyMetadata, retrievedKey.getKeyMetadata());
         assertEquals(generationId, retrievedKey.getPlatformKeyGenerationId());
         assertEquals(status,retrievedKey.getRecoveryStatus());
     }
@@ -174,20 +188,37 @@
         int userId = 12;
         int uid = 1009;
         int generationId = 6;
-        String alias = "test";
-        byte[] nonce = getUtf8Bytes("nonce");
-        byte[] keyMaterial = getUtf8Bytes("keymaterial");
-        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId);
-        mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
+
+        String alias1 = "alias1";
+        byte[] nonce1 = getUtf8Bytes("nonce1");
+        byte[] keyMaterial1 = getUtf8Bytes("keymaterial1");
+        byte[] keyMetadata1 = getUtf8Bytes("keyallmetadata1");
+        WrappedKey wrappedKey1 = new WrappedKey(nonce1, keyMaterial1, keyMetadata1, generationId);
+        mRecoverableKeyStoreDb.insertKey(userId, uid, alias1, wrappedKey1);
+
+        String alias2 = "alias2";
+        byte[] nonce2 = getUtf8Bytes("nonce2");
+        byte[] keyMaterial2 = getUtf8Bytes("keymaterial2");
+        byte[] keyMetadata2 = null;
+        WrappedKey wrappedKey2 = new WrappedKey(nonce2, keyMaterial2, keyMetadata2, generationId);
+        mRecoverableKeyStoreDb.insertKey(userId, uid, alias2, wrappedKey2);
 
         Map<String, WrappedKey> keys = mRecoverableKeyStoreDb.getAllKeys(userId, uid, generationId);
+        assertEquals(2, keys.size());
 
-        assertEquals(1, keys.size());
-        assertTrue(keys.containsKey(alias));
-        WrappedKey retrievedKey = keys.get(alias);
-        assertArrayEquals(nonce, retrievedKey.getNonce());
-        assertArrayEquals(keyMaterial, retrievedKey.getKeyMaterial());
-        assertEquals(generationId, retrievedKey.getPlatformKeyGenerationId());
+        assertTrue(keys.containsKey(alias1));
+        WrappedKey retrievedKey1 = keys.get(alias1);
+        assertArrayEquals(nonce1, retrievedKey1.getNonce());
+        assertArrayEquals(keyMaterial1, retrievedKey1.getKeyMaterial());
+        assertArrayEquals(keyMetadata1, retrievedKey1.getKeyMetadata());
+        assertEquals(generationId, retrievedKey1.getPlatformKeyGenerationId());
+
+        assertTrue(keys.containsKey(alias2));
+        WrappedKey retrievedKey2 = keys.get(alias2);
+        assertArrayEquals(nonce2, retrievedKey2.getNonce());
+        assertArrayEquals(keyMaterial2, retrievedKey2.getKeyMaterial());
+        assertArrayEquals(keyMetadata2, retrievedKey2.getKeyMetadata());
+        assertEquals(generationId, retrievedKey2.getPlatformKeyGenerationId());
     }
 
     @Test
@@ -197,6 +228,7 @@
         WrappedKey wrappedKey = new WrappedKey(
                 getUtf8Bytes("nonce"),
                 getUtf8Bytes("keymaterial"),
+                /*metadata=*/ null,
                 /*platformKeyGenerationId=*/ 5);
         mRecoverableKeyStoreDb.insertKey(
                 userId, uid, /*alias=*/ "test", wrappedKey);
@@ -212,7 +244,8 @@
         int generationId = 12;
         int uid = 10009;
         WrappedKey wrappedKey = new WrappedKey(
-                getUtf8Bytes("nonce"), getUtf8Bytes("keymaterial"), generationId);
+                getUtf8Bytes("nonce"), getUtf8Bytes("keymaterial"), /*metadata=*/ null,
+                generationId);
         mRecoverableKeyStoreDb.insertKey(
                 /*userId=*/ 1, uid, /*alias=*/ "test", wrappedKey);
 
@@ -255,7 +288,10 @@
         String alias = "test";
         byte[] nonce = getUtf8Bytes("nonce");
         byte[] keyMaterial = getUtf8Bytes("keymaterial");
-        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId, status);
+        byte[] keyMetadata = null;
+
+        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
+                status);
         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
 
         WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
@@ -279,12 +315,16 @@
         String alias3 = "test3";
         byte[] nonce = getUtf8Bytes("nonce");
         byte[] keyMaterial = getUtf8Bytes("keymaterial");
+        byte[] keyMetadata = null;
 
-        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId, status);
+        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
+                status);
         mRecoverableKeyStoreDb.insertKey(userId, uid, alias2, wrappedKey);
-        WrappedKey wrappedKey2 = new WrappedKey(nonce, keyMaterial, generationId, status);
-        mRecoverableKeyStoreDb.insertKey(userId, uid, alias3, wrappedKey);
-        WrappedKey wrappedKeyWithDefaultStatus = new WrappedKey(nonce, keyMaterial, generationId);
+        WrappedKey wrappedKey2 = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
+                status);
+        mRecoverableKeyStoreDb.insertKey(userId, uid, alias3, wrappedKey2);
+        WrappedKey wrappedKeyWithDefaultStatus = new WrappedKey(nonce, keyMaterial, keyMetadata,
+                generationId);
         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKeyWithDefaultStatus);
 
         Map<String, Integer> statuses = mRecoverableKeyStoreDb.getStatusForAllKeys(uid);
@@ -333,7 +373,10 @@
         String alias = "test";
         byte[] nonce = getUtf8Bytes("nonce");
         byte[] keyMaterial = getUtf8Bytes("keymaterial");
-        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId, status);
+        byte[] keyMetadata = null;
+
+        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
+                status);
         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
 
         WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
@@ -357,7 +400,10 @@
         String alias = "test";
         byte[] nonce = getUtf8Bytes("nonce");
         byte[] keyMaterial = getUtf8Bytes("keymaterial");
-        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId, status);
+        byte[] keyMetadata = null;
+
+        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, keyMetadata, generationId,
+                status);
         mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
 
         WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 1f5c64e..bc1f798 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -42,6 +42,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.IUidObserver;
+import android.app.Person;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -1588,6 +1589,14 @@
     }
 
     /**
+     * Make a Person.
+     */
+    protected Person makePerson(CharSequence name, String key, String uri) {
+        final Person.Builder builder = new Person.Builder();
+        return builder.setName(name).setKey(key).setUri(uri).build();
+    }
+
+    /**
      * Make an component name, with the client context.
      */
     @NonNull
diff --git a/services/tests/servicestests/src/com/android/server/pm/LauncherAppsServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/LauncherAppsServiceTest.java
new file mode 100644
index 0000000..d7dc58d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/LauncherAppsServiceTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.pm.PackageParser;
+import android.content.pm.Signature;
+import android.content.pm.SigningInfo;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@Presubmit
+@RunWith(MockitoJUnitRunner.class)
+public class LauncherAppsServiceTest {
+
+    private static final Signature SIGNATURE_1 = new Signature(new byte[]{0x00, 0x01, 0x02, 0x03});
+    private static final Signature SIGNATURE_2 = new Signature(new byte[]{0x04, 0x05, 0x06, 0x07});
+    private static final Signature SIGNATURE_3 = new Signature(new byte[]{0x08, 0x09, 0x10, 0x11});
+
+    @Test
+    public void testComputePackageCertDigest() {
+        String digest = LauncherAppsService.LauncherAppsImpl.computePackageCertDigest(SIGNATURE_1);
+        assertEquals("A02A05B025B928C039CF1AE7E8EE04E7C190C0DB", digest);
+    }
+
+    @Test
+    public void testGetLatestSignaturesWithSingleCert() {
+        SigningInfo signingInfo = new SigningInfo(
+                new PackageParser.SigningDetails(
+                        new Signature[]{SIGNATURE_1},
+                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        null,
+                        null));
+        Signature[] signatures = LauncherAppsService.LauncherAppsImpl.getLatestSignatures(
+                signingInfo);
+        assertEquals(1, signatures.length);
+        assertEquals(SIGNATURE_1, signatures[0]);
+    }
+
+    @Test
+    public void testGetLatestSignaturesWithMultiCert() {
+        SigningInfo signingInfo = new SigningInfo(
+                new PackageParser.SigningDetails(
+                        new Signature[]{SIGNATURE_1, SIGNATURE_2},
+                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        null,
+                        null));
+        Signature[] signatures = LauncherAppsService.LauncherAppsImpl.getLatestSignatures(
+                signingInfo);
+        assertEquals(2, signatures.length);
+        assertEquals(SIGNATURE_1, signatures[0]);
+        assertEquals(SIGNATURE_2, signatures[1]);
+    }
+
+    @Test
+    public void testGetLatestSignaturesWithCertHistory() {
+        SigningInfo signingInfo = new SigningInfo(
+                new PackageParser.SigningDetails(
+                        new Signature[]{SIGNATURE_1},
+                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                        null,
+                        new Signature[]{SIGNATURE_2, SIGNATURE_3}));
+        Signature[] signatures = LauncherAppsService.LauncherAppsImpl.getLatestSignatures(
+                signingInfo);
+        assertEquals(1, signatures.length);
+        assertEquals(SIGNATURE_2, signatures[0]);
+    }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
new file mode 100644
index 0000000..73e9613
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
+import android.content.pm.PackageInstaller;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.FastXmlSerializer;
+
+import libcore.io.IoUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+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.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class PackageInstallerSessionTest {
+    private File mTmpDir;
+    private AtomicFile mSessionsFile;
+    private static final String TAG_SESSIONS = "sessions";
+
+    @Mock
+    PackageManagerService mMockPackageManagerInternal;
+
+    @Before
+    public void setUp() throws Exception {
+        mTmpDir = IoUtils.createTemporaryDirectory("PackageInstallerSessionTest");
+        mSessionsFile = new AtomicFile(
+                new File(mTmpDir.getAbsolutePath() + "/sessions.xml"), "package-session");
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testWriteAndRestoreSessionXmlSimpleSession() {
+        PackageInstallerSession session = createSimpleSession();
+        dumpSession(session);
+        List<PackageInstallerSession> restored = restoreSessions();
+        assertEquals(1, restored.size());
+        assertSessionsEquivalent(session, restored.get(0));
+    }
+
+    @Test
+    public void testWriteAndRestoreSessionXmlStagedSession() {
+        PackageInstallerSession session = createStagedSession();
+        dumpSession(session);
+        List<PackageInstallerSession> restored = restoreSessions();
+        assertEquals(1, restored.size());
+        assertSessionsEquivalent(session, restored.get(0));
+    }
+
+    @Test
+    public void testWriteAndRestoreSessionXmlGrantedPermission() {
+        PackageInstallerSession session = createSessionWithGrantedPermissions();
+        dumpSession(session);
+        List<PackageInstallerSession> restored = restoreSessions();
+        assertEquals(1, restored.size());
+        assertSessionsEquivalent(session, restored.get(0));
+    }
+
+    @Test
+    public void testWriteAndRestoreSessionXmlMultiPackageSessions() {
+        PackageInstallerSession session = createMultiPackageParentSession(123, new int[]{234, 345});
+        PackageInstallerSession childSession1 = createMultiPackageChildSession(234, 123);
+        PackageInstallerSession childSession2 = createMultiPackageChildSession(345, 123);
+        List<PackageInstallerSession> sessionGroup =
+                Arrays.asList(session, childSession1, childSession2);
+        dumpSessions(sessionGroup);
+        List<PackageInstallerSession> restored = restoreSessions();
+        assertEquals(3, restored.size());
+        assertSessionsEquivalent(sessionGroup, restored);
+    }
+
+    private PackageInstallerSession createSimpleSession() {
+        return createSession(false, false, 123, false, PackageInstaller.SessionInfo.INVALID_ID,
+                null);
+    }
+
+    private PackageInstallerSession createStagedSession() {
+        return createSession(true, false, 123, false, PackageInstaller.SessionInfo.INVALID_ID,
+                null);
+    }
+
+    private PackageInstallerSession createSessionWithGrantedPermissions() {
+        return createSession(false, true, 123, false, PackageInstaller.SessionInfo.INVALID_ID,
+                null);
+    }
+
+    private PackageInstallerSession createMultiPackageParentSession(int sessionId,
+                                                                    int[] childSessionIds) {
+        return createSession(false, false, sessionId, true,
+                PackageInstaller.SessionInfo.INVALID_ID, childSessionIds);
+    }
+
+    private PackageInstallerSession createMultiPackageChildSession(int sessionId,
+                                                                   int parentSessionId) {
+        return createSession(false, false, sessionId, false, parentSessionId, null);
+    }
+
+    private PackageInstallerSession createSession(boolean staged, boolean withGrantedPermissions,
+                                                  int sessionId, boolean isMultiPackage,
+                                                  int parentSessionId, int[] childSessionIds) {
+        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+        if (staged) {
+            params.isStaged = true;
+        }
+        if (withGrantedPermissions) {
+            params.grantedRuntimePermissions = new String[]{"permission1", "permission2"};
+        }
+        if (isMultiPackage) {
+            params.isMultiPackage = true;
+        }
+        return new PackageInstallerSession(
+                /* callback */ null,
+                /* context */null,
+                /* pm */ mMockPackageManagerInternal,
+                /* sessionProvider */ null,
+                /* looper */ BackgroundThread.getHandler().getLooper(),
+                /* stagingManager */ null,
+                /* sessionId */ sessionId,
+                /* userId */  456,
+                /* installerPackageName */ "testInstaller",
+                /* installerUid */ -1,
+                /* sessionParams */ params,
+                /* createdMillis */ 0L,
+                /* stageDir */ mTmpDir,
+                /* stageCid */ null,
+                /* prepared */ true,
+                /* sealed */ false,  // Setting to true would trigger some PM logic.
+                /* childSessionIds */ childSessionIds != null ? childSessionIds : new int[0],
+                /* parentSessionId */ parentSessionId,
+                /* isReady */ staged ? true : false,
+                /* isFailed */ false,
+                /* isApplied */false,
+                /* stagedSessionErrorCode */ PackageInstaller.SessionInfo.VERIFICATION_FAILED);
+    }
+
+    private void dumpSession(PackageInstallerSession session) {
+        dumpSessions(Arrays.asList(session));
+    }
+
+    private void dumpSessions(List<PackageInstallerSession> sessions) {
+        FileOutputStream fos = null;
+        try {
+            fos = mSessionsFile.startWrite();
+
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(fos, StandardCharsets.UTF_8.name());
+            out.startDocument(null, true);
+            out.startTag(null, TAG_SESSIONS);
+            for (PackageInstallerSession session : sessions) {
+                session.write(out, mTmpDir);
+            }
+            out.endTag(null, TAG_SESSIONS);
+            out.endDocument();
+
+            mSessionsFile.finishWrite(fos);
+            Slog.d("PackageInstallerSessionTest", new String(mSessionsFile.readFully()));
+        } catch (IOException e) {
+            if (fos != null) {
+                mSessionsFile.failWrite(fos);
+            }
+        }
+    }
+
+    // This is roughly the logic used in PackageInstallerService to read the session. Note that
+    // this test stresses readFromXml method from PackageInstallerSession, and doesn't cover the
+    // PackageInstallerService portion of the parsing.
+    private List<PackageInstallerSession> restoreSessions() {
+        List<PackageInstallerSession> ret = new ArrayList<>();
+        FileInputStream fis = null;
+        try {
+            fis = mSessionsFile.openRead();
+            final XmlPullParser in = Xml.newPullParser();
+            in.setInput(fis, StandardCharsets.UTF_8.name());
+
+            int type;
+            while ((type = in.next()) != END_DOCUMENT) {
+                if (type == START_TAG) {
+                    final String tag = in.getName();
+                    if (PackageInstallerSession.TAG_SESSION.equals(tag)) {
+                        final PackageInstallerSession session;
+                        try {
+                            session = PackageInstallerSession.readFromXml(in, null,
+                                    null, mMockPackageManagerInternal,
+                                    BackgroundThread.getHandler().getLooper(), null,
+                                    mTmpDir, null);
+                            ret.add(session);
+                        } catch (Exception e) {
+                            Slog.e("PackageInstallerSessionTest", "Exception ", e);
+                            continue;
+                        }
+                    }
+                }
+            }
+        } catch (FileNotFoundException e) {
+            // Missing sessions are okay, probably first boot
+        } catch (IOException | XmlPullParserException e) {
+
+        } finally {
+            IoUtils.closeQuietly(fis);
+        }
+        return ret;
+    }
+
+    private void assertSessionParamsEquivalent(PackageInstaller.SessionParams expected,
+                                               PackageInstaller.SessionParams actual) {
+        assertEquals(expected.mode, actual.mode);
+        assertEquals(expected.installFlags, actual.installFlags);
+        assertEquals(expected.installLocation, actual.installLocation);
+        assertEquals(expected.installReason, actual.installReason);
+        assertEquals(expected.sizeBytes, actual.sizeBytes);
+        assertEquals(expected.appPackageName, actual.appPackageName);
+        assertEquals(expected.appIcon, actual.appIcon);
+        assertEquals(expected.originatingUri, actual.originatingUri);
+        assertEquals(expected.originatingUid, actual.originatingUid);
+        assertEquals(expected.referrerUri, actual.referrerUri);
+        assertEquals(expected.abiOverride, actual.abiOverride);
+        assertEquals(expected.volumeUuid, actual.volumeUuid);
+        assertArrayEquals(expected.grantedRuntimePermissions, actual.grantedRuntimePermissions);
+        assertEquals(expected.installerPackageName, actual.installerPackageName);
+        assertEquals(expected.isMultiPackage, actual.isMultiPackage);
+        assertEquals(expected.isStaged, actual.isStaged);
+    }
+
+    private void assertSessionsEquivalent(List<PackageInstallerSession> expected,
+                                          List<PackageInstallerSession> actual) {
+        assertEquals(expected.size(), actual.size());
+        for (PackageInstallerSession expectedSession : expected) {
+            boolean foundSession = false;
+            for (PackageInstallerSession actualSession : actual) {
+                if (expectedSession.sessionId == actualSession.sessionId) {
+                    // We should only encounter each expected session once.
+                    assertFalse(foundSession);
+                    foundSession = true;
+                    assertSessionsEquivalent(expectedSession, actualSession);
+                }
+            }
+            assertTrue(foundSession);
+        }
+    }
+
+    private void assertSessionsEquivalent(PackageInstallerSession expected,
+                                          PackageInstallerSession actual) {
+        assertEquals(expected.sessionId, actual.sessionId);
+        assertEquals(expected.userId, actual.userId);
+        assertSessionParamsEquivalent(expected.params, actual.params);
+        assertEquals(expected.getInstallerUid(), actual.getInstallerUid());
+        assertEquals(expected.stageDir.getAbsolutePath(), actual.stageDir.getAbsolutePath());
+        assertEquals(expected.stageCid, actual.stageCid);
+        assertEquals(expected.isPrepared(), actual.isPrepared());
+        assertEquals(expected.isStaged(), actual.isStaged());
+        assertEquals(expected.isStagedSessionApplied(), actual.isStagedSessionApplied());
+        assertEquals(expected.isStagedSessionFailed(), actual.isStagedSessionFailed());
+        assertEquals(expected.isStagedSessionReady(), actual.isStagedSessionReady());
+        assertEquals(expected.getStagedSessionErrorCode(), actual.getStagedSessionErrorCode());
+        assertEquals(expected.isPrepared(), actual.isPrepared());
+        assertEquals(expected.isSealed(), actual.isSealed());
+        assertEquals(expected.isMultiPackage(), actual.isMultiPackage());
+        assertEquals(expected.hasParentSessionId(), actual.hasParentSessionId());
+        assertEquals(expected.getParentSessionId(), actual.getParentSessionId());
+        assertArrayEquals(expected.getChildSessionIds(), actual.getChildSessionIds());
+    }
+}
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 517b5ad..6d28ed1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -35,6 +35,7 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.SuspendDialogInfo;
@@ -226,8 +227,8 @@
         settingsUnderTest.mPackages.put(PACKAGE_NAME_3, createPackageSetting(PACKAGE_NAME_3));
         // now read and verify
         settingsUnderTest.readPackageRestrictionsLPr(0);
-        final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1).
-                readUserState(0);
+        final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1)
+                .readUserState(0);
         assertThat(readPus1.suspended, is(true));
         assertThat(readPus1.suspendingPackage, equalTo("suspendingPackage1"));
         assertThat(readPus1.dialogInfo, equalTo(dialogInfo1));
@@ -235,16 +236,16 @@
         assertThat(BaseBundle.kindofEquals(readPus1.suspendedLauncherExtras, launcherExtras1),
                 is(true));
 
-        final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2).
-                readUserState(0);
+        final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2)
+                .readUserState(0);
         assertThat(readPus2.suspended, is(true));
         assertThat(readPus2.suspendingPackage, equalTo("suspendingPackage2"));
         assertThat(readPus2.dialogInfo, is(nullValue()));
         assertThat(readPus2.suspendedAppExtras, is(nullValue()));
         assertThat(readPus2.suspendedLauncherExtras, is(nullValue()));
 
-        final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3).
-                readUserState(0);
+        final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3)
+                .readUserState(0);
         assertThat(readPus3.suspended, is(false));
         assertThat(readPus3.suspendingPackage, is(nullValue()));
         assertThat(readPus3.dialogInfo, is(nullValue()));
@@ -254,11 +255,59 @@
 
     @Test
     public void testPackageRestrictionsSuspendedDefault() {
-        final PackageSetting defaultSetting =  createPackageSetting(PACKAGE_NAME_1);
+        final PackageSetting defaultSetting = createPackageSetting(PACKAGE_NAME_1);
         assertThat(defaultSetting.getSuspended(0), is(false));
     }
 
     @Test
+    public void testReadWritePackageRestrictions_distractionFlags() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, new Object());
+        final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
+        final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
+        final PackageSetting ps3 = createPackageSetting(PACKAGE_NAME_3);
+
+        final int distractionFlags1 = PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
+        ps1.setDistractionFlags(distractionFlags1, 0);
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
+
+        final int distractionFlags2 = PackageManager.RESTRICTION_HIDE_NOTIFICATIONS
+                | PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
+        ps2.setDistractionFlags(distractionFlags2, 0);
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
+
+        final int distractionFlags3 = PackageManager.RESTRICTION_NONE;
+        ps3.setDistractionFlags(distractionFlags3, 0);
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
+
+        settingsUnderTest.writePackageRestrictionsLPr(0);
+
+        settingsUnderTest.mPackages.clear();
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_3, createPackageSetting(PACKAGE_NAME_3));
+        // now read and verify
+        settingsUnderTest.readPackageRestrictionsLPr(0);
+        final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1)
+                .readUserState(0);
+        assertThat(readPus1.distractionFlags, is(distractionFlags1));
+
+        final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2)
+                .readUserState(0);
+        assertThat(readPus2.distractionFlags, is(distractionFlags2));
+
+        final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3)
+                .readUserState(0);
+        assertThat(readPus3.distractionFlags, is(distractionFlags3));
+    }
+
+    @Test
+    public void testPackageRestrictionsDistractionFlagsDefault() {
+        final PackageSetting defaultSetting = createPackageSetting(PACKAGE_NAME_1);
+        assertThat(defaultSetting.getDistractionFlags(0), is(PackageManager.RESTRICTION_NONE));
+    }
+
+    @Test
     public void testEnableDisable() {
         // Write the package files and make sure they're parsed properly the first time
         writeOldFiles();
@@ -692,6 +741,7 @@
         assertThat(userState.notLaunched, is(notLaunched));
         assertThat(userState.stopped, is(stopped));
         assertThat(userState.suspended, is(false));
+        assertThat(userState.distractionFlags, is(0));
         if (oldUserState != null) {
             assertThat(userState.equals(oldUserState), is(not(userStateChanged)));
         }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index ce59e6e..85909d5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -276,6 +276,7 @@
         assertEquals(a.mRestrictedAccountType, b.mRestrictedAccountType);
         assertEquals(a.mRequiredAccountType, b.mRequiredAccountType);
         assertEquals(a.mOverlayTarget, b.mOverlayTarget);
+        assertEquals(a.mOverlayTargetName, b.mOverlayTargetName);
         assertEquals(a.mOverlayCategory, b.mOverlayCategory);
         assertEquals(a.mOverlayPriority, b.mOverlayPriority);
         assertEquals(a.mOverlayIsStatic, b.mOverlayIsStatic);
@@ -545,6 +546,7 @@
 
         pkg.mOverlayCategory = "foo24";
         pkg.mOverlayIsStatic = true;
+        pkg.mOverlayTargetName = "foo26";
 
         pkg.baseHardwareAccelerated = true;
         pkg.coreApp = true;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index f0ed612..8eaf35f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -22,6 +22,7 @@
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
 
+import android.content.pm.PackageManager;
 import android.content.pm.PackageUserState;
 import android.content.pm.SuspendDialogInfo;
 import android.os.PersistableBundle;
@@ -227,4 +228,19 @@
         assertThat(testUserState1.equals(testUserState2), is(true));
     }
 
+    @Test
+    public void testPackageUserState06() {
+        final PackageUserState userState1 = new PackageUserState();
+        assertThat(userState1.distractionFlags, is(PackageManager.RESTRICTION_NONE));
+        userState1.distractionFlags = PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
+
+        final PackageUserState copyOfUserState1 = new PackageUserState(userState1);
+        assertThat(userState1.distractionFlags, is(copyOfUserState1.distractionFlags));
+        assertThat(userState1.equals(copyOfUserState1), is(true));
+
+        final PackageUserState userState2 = new PackageUserState(userState1);
+        userState2.distractionFlags = PackageManager.RESTRICTION_HIDE_NOTIFICATIONS;
+        assertThat(userState1.equals(userState2), is(false));
+    }
+
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 9b59f91..8d0365b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -248,6 +248,8 @@
                 .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                 .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
                 .setRank(123)
+                .setPerson(makePerson("person", "personKey", "personUri"))
+                .setLongLived()
                 .setExtras(pb)
                 .build();
         si.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -267,9 +269,12 @@
         assertEquals("action", si.getIntent().getAction());
         assertEquals("val", si.getIntent().getStringExtra("key"));
         assertEquals(123, si.getRank());
+        assertEquals("person", si.getPersons()[0].getName());
+        assertEquals("personKey", si.getPersons()[0].getKey());
+        assertEquals("personUri", si.getPersons()[0].getUri());
         assertEquals(1, si.getExtras().getInt("k"));
 
-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
         assertEquals("abc", si.getBitmapPath());
         assertEquals(456, si.getIconResourceId());
 
@@ -345,6 +350,8 @@
                 .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
                 .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                 .setRank(123)
+                .setPerson(makePerson("person", "personKey", "personUri"))
+                .setLongLived()
                 .setExtras(pb)
                 .build();
         sorig.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -368,9 +375,12 @@
         assertEquals("action", si.getIntent().getAction());
         assertEquals("val", si.getIntent().getStringExtra("key"));
         assertEquals(123, si.getRank());
+        assertEquals("person", si.getPersons()[0].getName());
+        assertEquals("personKey", si.getPersons()[0].getKey());
+        assertEquals("personUri", si.getPersons()[0].getUri());
         assertEquals(1, si.getExtras().getInt("k"));
 
-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
         assertEquals("abc", si.getBitmapPath());
         assertEquals(456, si.getIconResourceId());
         assertEquals("string/r456", si.getIconResName());
@@ -388,9 +398,12 @@
         assertEquals("action", si.getIntent().getAction());
         assertEquals("val", si.getIntent().getStringExtra("key"));
         assertEquals(123, si.getRank());
+        assertEquals("person", si.getPersons()[0].getName());
+        assertEquals("personKey", si.getPersons()[0].getKey());
+        assertEquals("personUri", si.getPersons()[0].getUri());
         assertEquals(1, si.getExtras().getInt("k"));
 
-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
         assertEquals(null, si.getBitmapPath());
 
         assertEquals(456, si.getIconResourceId());
@@ -408,9 +421,12 @@
         assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
         assertEquals(null, si.getIntent());
         assertEquals(123, si.getRank());
+        assertEquals("person", si.getPersons()[0].getName());
+        assertEquals("personKey", si.getPersons()[0].getKey());
+        assertEquals("personUri", si.getPersons()[0].getUri());
         assertEquals(1, si.getExtras().getInt("k"));
 
-        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
         assertEquals(null, si.getBitmapPath());
 
         assertEquals(456, si.getIconResourceId());
@@ -428,9 +444,11 @@
         assertEquals(null, si.getCategories());
         assertEquals(null, si.getIntent());
         assertEquals(0, si.getRank());
+        assertEquals(null, si.getPersons());
         assertEquals(null, si.getExtras());
 
-        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY
+                | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
         assertEquals(null, si.getBitmapPath());
 
         assertEquals(456, si.getIconResourceId());
@@ -692,6 +710,12 @@
 
         si = sorig.clone(/* flags=*/ 0);
         si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setPerson(makePerson("person", "", "")).build());
+        assertEquals("text", si.getText());
+        assertEquals("person", si.getPersons()[0].getName());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
                 .setIntent(makeIntent("action2", ShortcutActivity.class)).build());
         assertEquals("text", si.getText());
         assertEquals("action2", si.getIntent().getAction());
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 823b7a5..3ebc6ad 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -544,6 +544,18 @@
         switchUser(-1, UserHandle.of(startUser), false);
     }
 
+    public void testSwitchUserByHandle_ThrowsException() {
+        synchronized (mUserSwitchLock) {
+            try {
+                ActivityManager am = getContext().getSystemService(ActivityManager.class);
+                am.switchUser(null);
+                fail("Expected IllegalArgumentException on passing in a null UserHandle.");
+            } catch (IllegalArgumentException expected) {
+                // Do nothing - exception is expected.
+            }
+        }
+    }
+
     @MediumTest
     public void testConcurrentUserCreate() throws Exception {
         int userCount = mUserManager.getUserCount();
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java
index 3b6b48b..6da202b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java
@@ -16,8 +16,6 @@
 
 package com.android.server.pm.dex;
 
-import static com.android.server.pm.dex.PackageDynamicCodeLoading.FILE_TYPE_DEX;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.atMost;
@@ -26,10 +24,12 @@
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
 
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
+import android.os.UserHandle;
 import android.os.storage.StorageManager;
 
 import androidx.test.filters.SmallTest;
@@ -56,41 +56,44 @@
 public class DexLoggerTests {
     private static final String OWNING_PACKAGE_NAME = "package.name";
     private static final String VOLUME_UUID = "volUuid";
-    private static final String DEX_PATH = "/bar/foo.jar";
+    private static final String FILE_PATH = "/bar/foo.jar";
     private static final int STORAGE_FLAGS = StorageManager.FLAG_STORAGE_DE;
     private static final int OWNER_UID = 43;
     private static final int OWNER_USER_ID = 44;
 
     // Obtained via: echo -n "foo.jar" | sha256sum
-    private static final String DEX_FILENAME_HASH =
+    private static final String FILENAME_HASH =
             "91D7B844D7CC9673748FF057D8DC83972280FC28537D381AA42015A9CF214B9F";
 
-    private static final byte[] CONTENT_HASH_BYTES = new byte[] {
-        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
-        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
+    private static final byte[] CONTENT_HASH_BYTES = new byte[]{
+            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
     };
     private static final String CONTENT_HASH =
             "0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20";
     private static final byte[] EMPTY_BYTES = {};
 
-    @Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
+    private static final String EXPECTED_MESSAGE_WITHOUT_CONTENT_HASH =
+            "dcl:" + FILENAME_HASH;
+    private static final String EXPECTED_MESSAGE_WITH_CONTENT_HASH =
+            EXPECTED_MESSAGE_WITHOUT_CONTENT_HASH + " " + CONTENT_HASH;
+    private static final String EXPECTED_MESSAGE_NATIVE_WITH_CONTENT_HASH =
+            "dcln:" + FILENAME_HASH + " " + CONTENT_HASH;
+
+    @Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.LENIENT);
 
     @Mock IPackageManager mPM;
     @Mock Installer mInstaller;
-    private final Object mInstallLock = new Object();
 
-    private PackageDynamicCodeLoading mPackageDynamicCodeLoading;
     private DexLogger mDexLogger;
 
     private final ListMultimap<Integer, String> mMessagesForUid = ArrayListMultimap.create();
     private boolean mWriteTriggered = false;
-    private static final String EXPECTED_MESSAGE_WITH_CONTENT_HASH =
-            DEX_FILENAME_HASH + " " + CONTENT_HASH;
 
     @Before
     public void setup() throws Exception {
         // Disable actually attempting to do file writes.
-        mPackageDynamicCodeLoading = new PackageDynamicCodeLoading() {
+        PackageDynamicCodeLoading packageDynamicCodeLoading = new PackageDynamicCodeLoading() {
             @Override
             void maybeWriteAsync() {
                 mWriteTriggered = true;
@@ -103,13 +106,13 @@
         };
 
         // For test purposes capture log messages as well as sending to the event log.
-        mDexLogger = new DexLogger(mPM, mInstaller, mInstallLock, mPackageDynamicCodeLoading) {
+        mDexLogger = new DexLogger(mPM, mInstaller, packageDynamicCodeLoading) {
             @Override
-                void writeDclEvent(int uid, String message) {
-                    super.writeDclEvent(uid, message);
-                    mMessagesForUid.put(uid, message);
-                }
-            };
+            void writeDclEvent(String subtag, int uid, String message) {
+                super.writeDclEvent(subtag, uid, message);
+                mMessagesForUid.put(uid, subtag + ":" + message);
+            }
+        };
 
         // Make the owning package exist in our mock PackageManager.
         ApplicationInfo appInfo = new ApplicationInfo();
@@ -125,9 +128,9 @@
 
     @Test
     public void testOneLoader_ownFile_withFileHash() throws Exception {
-        whenFileIsHashed(DEX_PATH, doReturn(CONTENT_HASH_BYTES));
+        whenFileIsHashed(FILE_PATH, doReturn(CONTENT_HASH_BYTES));
 
-        recordLoad(OWNING_PACKAGE_NAME, DEX_PATH);
+        recordLoad(OWNING_PACKAGE_NAME, FILE_PATH);
         mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
 
         assertThat(mMessagesForUid.keys()).containsExactly(OWNER_UID);
@@ -140,13 +143,13 @@
 
     @Test
     public void testOneLoader_ownFile_noFileHash() throws Exception {
-        whenFileIsHashed(DEX_PATH, doReturn(EMPTY_BYTES));
+        whenFileIsHashed(FILE_PATH, doReturn(EMPTY_BYTES));
 
-        recordLoad(OWNING_PACKAGE_NAME, DEX_PATH);
+        recordLoad(OWNING_PACKAGE_NAME, FILE_PATH);
         mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
 
         assertThat(mMessagesForUid.keys()).containsExactly(OWNER_UID);
-        assertThat(mMessagesForUid).containsEntry(OWNER_UID, DEX_FILENAME_HASH);
+        assertThat(mMessagesForUid).containsEntry(OWNER_UID, EXPECTED_MESSAGE_WITHOUT_CONTENT_HASH);
 
         // File should be removed from the DCL list, since we can't hash it.
         assertThat(mWriteTriggered).isTrue();
@@ -155,13 +158,14 @@
 
     @Test
     public void testOneLoader_ownFile_hashingFails() throws Exception {
-        whenFileIsHashed(DEX_PATH, doThrow(new InstallerException("Intentional failure for test")));
+        whenFileIsHashed(FILE_PATH,
+                doThrow(new InstallerException("Intentional failure for test")));
 
-        recordLoad(OWNING_PACKAGE_NAME, DEX_PATH);
+        recordLoad(OWNING_PACKAGE_NAME, FILE_PATH);
         mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
 
         assertThat(mMessagesForUid.keys()).containsExactly(OWNER_UID);
-        assertThat(mMessagesForUid).containsEntry(OWNER_UID, DEX_FILENAME_HASH);
+        assertThat(mMessagesForUid).containsEntry(OWNER_UID, EXPECTED_MESSAGE_WITHOUT_CONTENT_HASH);
 
         // File should be removed from the DCL list, since we can't hash it.
         assertThat(mWriteTriggered).isTrue();
@@ -179,11 +183,23 @@
     }
 
     @Test
+    public void testOneLoader_pathTraversal() throws Exception {
+        String filePath = "/bar/../secret/foo.jar";
+        whenFileIsHashed(filePath, doReturn(CONTENT_HASH_BYTES));
+        setPackageUid(OWNING_PACKAGE_NAME, -1);
+
+        recordLoad(OWNING_PACKAGE_NAME, filePath);
+        mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
+
+        assertThat(mMessagesForUid).isEmpty();
+    }
+
+    @Test
     public void testOneLoader_differentOwner() throws Exception {
-        whenFileIsHashed(DEX_PATH, doReturn(CONTENT_HASH_BYTES));
+        whenFileIsHashed(FILE_PATH, doReturn(CONTENT_HASH_BYTES));
         setPackageUid("other.package.name", 1001);
 
-        recordLoad("other.package.name", DEX_PATH);
+        recordLoad("other.package.name", FILE_PATH);
         mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
 
         assertThat(mMessagesForUid.keys()).containsExactly(1001);
@@ -193,10 +209,10 @@
 
     @Test
     public void testOneLoader_differentOwner_uninstalled() throws Exception {
-        whenFileIsHashed(DEX_PATH, doReturn(CONTENT_HASH_BYTES));
+        whenFileIsHashed(FILE_PATH, doReturn(CONTENT_HASH_BYTES));
         setPackageUid("other.package.name", -1);
 
-        recordLoad("other.package.name", DEX_PATH);
+        recordLoad("other.package.name", FILE_PATH);
         mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
 
         assertThat(mMessagesForUid).isEmpty();
@@ -204,22 +220,38 @@
     }
 
     @Test
+    public void testNativeCodeLoad() throws Exception {
+        whenFileIsHashed(FILE_PATH, doReturn(CONTENT_HASH_BYTES));
+
+        recordLoadNative(FILE_PATH);
+        mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
+
+        assertThat(mMessagesForUid.keys()).containsExactly(OWNER_UID);
+        assertThat(mMessagesForUid)
+                .containsEntry(OWNER_UID, EXPECTED_MESSAGE_NATIVE_WITH_CONTENT_HASH);
+
+        assertThat(mWriteTriggered).isFalse();
+        assertThat(mDexLogger.getAllPackagesWithDynamicCodeLoading())
+                .containsExactly(OWNING_PACKAGE_NAME);
+    }
+
+    @Test
     public void testMultipleLoadersAndFiles() throws Exception {
         String otherDexPath = "/bar/nosuchdir/foo.jar";
-        whenFileIsHashed(DEX_PATH, doReturn(CONTENT_HASH_BYTES));
+        whenFileIsHashed(FILE_PATH, doReturn(CONTENT_HASH_BYTES));
         whenFileIsHashed(otherDexPath, doReturn(EMPTY_BYTES));
         setPackageUid("other.package.name1", 1001);
         setPackageUid("other.package.name2", 1002);
 
-        recordLoad("other.package.name1", DEX_PATH);
+        recordLoad("other.package.name1", FILE_PATH);
         recordLoad("other.package.name1", otherDexPath);
-        recordLoad("other.package.name2", DEX_PATH);
-        recordLoad(OWNING_PACKAGE_NAME, DEX_PATH);
+        recordLoad("other.package.name2", FILE_PATH);
+        recordLoad(OWNING_PACKAGE_NAME, FILE_PATH);
         mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
 
         assertThat(mMessagesForUid.keys()).containsExactly(1001, 1001, 1002, OWNER_UID);
         assertThat(mMessagesForUid).containsEntry(1001, EXPECTED_MESSAGE_WITH_CONTENT_HASH);
-        assertThat(mMessagesForUid).containsEntry(1001, DEX_FILENAME_HASH);
+        assertThat(mMessagesForUid).containsEntry(1001, EXPECTED_MESSAGE_WITHOUT_CONTENT_HASH);
         assertThat(mMessagesForUid).containsEntry(1002, EXPECTED_MESSAGE_WITH_CONTENT_HASH);
         assertThat(mMessagesForUid).containsEntry(OWNER_UID, EXPECTED_MESSAGE_WITH_CONTENT_HASH);
 
@@ -234,7 +266,7 @@
     @Test
     public void testUnknownOwner() {
         reset(mPM);
-        recordLoad(OWNING_PACKAGE_NAME, DEX_PATH);
+        recordLoad(OWNING_PACKAGE_NAME, FILE_PATH);
         mDexLogger.logDynamicCodeLoading("other.package.name");
 
         assertThat(mMessagesForUid).isEmpty();
@@ -245,7 +277,7 @@
     @Test
     public void testUninstalledPackage() {
         reset(mPM);
-        recordLoad(OWNING_PACKAGE_NAME, DEX_PATH);
+        recordLoad(OWNING_PACKAGE_NAME, FILE_PATH);
         mDexLogger.logDynamicCodeLoading(OWNING_PACKAGE_NAME);
 
         assertThat(mMessagesForUid).isEmpty();
@@ -263,7 +295,16 @@
     }
 
     private void recordLoad(String loadingPackageName, String dexPath) {
-        mPackageDynamicCodeLoading.record(
-                OWNING_PACKAGE_NAME, dexPath, FILE_TYPE_DEX, OWNER_USER_ID, loadingPackageName);
+        mDexLogger.recordDex(OWNER_USER_ID, dexPath, OWNING_PACKAGE_NAME, loadingPackageName);
+        mWriteTriggered = false;
+    }
+
+    private void recordLoadNative(String nativePath) throws Exception {
+        int loadingUid = UserHandle.getUid(OWNER_USER_ID, OWNER_UID);
+        String[] packageNames = { OWNING_PACKAGE_NAME };
+        when(mPM.getPackagesForUid(loadingUid)).thenReturn(packageNames);
+
+        mDexLogger.recordNative(loadingUid, nativePath);
+        mWriteTriggered = false;
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 7cd8cedd..2ddc71f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -55,6 +55,7 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -685,4 +686,68 @@
             return mPackageInfo.applicationInfo.splitSourceDirs[length - 1];
         }
     }
+
+    private boolean shouldPackageRunOob(
+            boolean isDefaultEnabled, String defaultWhitelist, String overrideEnabled,
+            String overrideWhitelist, Collection<String> packageNamesInSameProcess) {
+        return DexManager.isPackageSelectedToRunOobInternal(
+                isDefaultEnabled, defaultWhitelist, overrideEnabled, overrideWhitelist,
+                packageNamesInSameProcess);
+    }
+
+    @Test
+    public void testOobPackageSelectionSwitch() {
+        // Feature is off by default, not overriden
+        assertFalse(shouldPackageRunOob(false, "ALL", null, null, null));
+
+        // Feature is off by default, overriden
+        assertTrue(shouldPackageRunOob(false, "ALL", "true", "ALL", null));
+        assertFalse(shouldPackageRunOob(false, "ALL", "false", null, null));
+        assertFalse(shouldPackageRunOob(false, "ALL", "false", "ALL", null));
+        assertFalse(shouldPackageRunOob(false, "ALL", "false", null, null));
+
+        // Feature is on by default, not overriden
+        assertTrue(shouldPackageRunOob(true, "ALL", null, null, null));
+        assertTrue(shouldPackageRunOob(true, "ALL", null, null, null));
+        assertTrue(shouldPackageRunOob(true, "ALL", null, "ALL", null));
+
+        // Feature is on by default, overriden
+        assertTrue(shouldPackageRunOob(true, "ALL", "true", null, null));
+        assertTrue(shouldPackageRunOob(true, "ALL", "true", "ALL", null));
+        assertFalse(shouldPackageRunOob(true, "ALL", "false", null, null));
+        assertFalse(shouldPackageRunOob(true, "ALL", "false", "ALL", null));
+    }
+
+    @Test
+    public void testOobPackageSelectionWhitelist() {
+        // Various whitelist of apps to run in OOB mode.
+        final String kWhitelistApp0 = "com.priv.app0";
+        final String kWhitelistApp1 = "com.priv.app1";
+        final String kWhitelistApp2 = "com.priv.app2";
+        final String kWhitelistApp1AndApp2 = "com.priv.app1,com.priv.app2";
+
+        // Packages that shares the targeting process.
+        final Collection<String> runningPackages = Arrays.asList("com.priv.app1", "com.priv.app2");
+
+        // Feature is off, whitelist does not matter
+        assertFalse(shouldPackageRunOob(false, kWhitelistApp0, null, null, runningPackages));
+        assertFalse(shouldPackageRunOob(false, kWhitelistApp1, null, null, runningPackages));
+        assertFalse(shouldPackageRunOob(false, "", null, kWhitelistApp1, runningPackages));
+        assertFalse(shouldPackageRunOob(false, "", null, "ALL", runningPackages));
+        assertFalse(shouldPackageRunOob(false, "ALL", null, "ALL", runningPackages));
+        assertFalse(shouldPackageRunOob(false, "ALL", null, "", runningPackages));
+
+        // Feature is on, app not in default or overridden whitelist
+        assertFalse(shouldPackageRunOob(true, kWhitelistApp0, null, null, runningPackages));
+        assertFalse(shouldPackageRunOob(true, "", null, kWhitelistApp0, runningPackages));
+        assertFalse(shouldPackageRunOob(true, "ALL", null, kWhitelistApp0, runningPackages));
+
+        // Feature is on, app in default or overridden whitelist
+        assertTrue(shouldPackageRunOob(true, kWhitelistApp1, null, null, runningPackages));
+        assertTrue(shouldPackageRunOob(true, kWhitelistApp2, null, null, runningPackages));
+        assertTrue(shouldPackageRunOob(true, kWhitelistApp1AndApp2, null, null, runningPackages));
+        assertTrue(shouldPackageRunOob(true, kWhitelistApp1, null, "ALL", runningPackages));
+        assertTrue(shouldPackageRunOob(true, "", null, kWhitelistApp1, runningPackages));
+        assertTrue(shouldPackageRunOob(true, "ALL", null, kWhitelistApp1, runningPackages));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 813fa82..d9faaa4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -16,8 +16,6 @@
 
 package com.android.server.pm.dex;
 
-import static com.android.server.pm.PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -31,16 +29,16 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 import dalvik.system.DelegateLastClassLoader;
 import dalvik.system.DexClassLoader;
 import dalvik.system.PathClassLoader;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.File;
-import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -412,12 +410,6 @@
 
     @Test
     public void testEncodeClassLoader() {
-        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoader(
-                SKIP_SHARED_LIBRARY_CHECK, "dalvik.system.PathClassLoader"));
-        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoader(
-                SKIP_SHARED_LIBRARY_CHECK, "dalvik.system.DexClassLoader"));
-        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoader(
-                SKIP_SHARED_LIBRARY_CHECK, "dalvik.system.DelegateLastClassLoader"));
         assertEquals("PCL[xyz]", DexoptUtils.encodeClassLoader("xyz",
                 "dalvik.system.PathClassLoader"));
         assertEquals("PCL[xyz]", DexoptUtils.encodeClassLoader("xyz",
@@ -435,15 +427,8 @@
 
     @Test
     public void testEncodeClassLoaderChain() {
-        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoaderChain(
-                SKIP_SHARED_LIBRARY_CHECK, "PCL[a]"));
-        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoaderChain("PCL[a]",
-                SKIP_SHARED_LIBRARY_CHECK));
         assertEquals("PCL[a];DLC[b]", DexoptUtils.encodeClassLoaderChain("PCL[a]",
                 "DLC[b]"));
-        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoaderChain("PCL[a]",
-                SKIP_SHARED_LIBRARY_CHECK));
-
         try {
             DexoptUtils.encodeClassLoaderChain("a", null);
             fail(); // exception is expected
diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
deleted file mode 100644
index acf511e..0000000
--- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.power;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.mock;
-
-import android.content.Context;
-import android.os.PowerManager;
-import android.os.PowerManager.ServiceType;
-import android.os.PowerSaveState;
-import android.provider.Settings.Global;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.ArrayMap;
-
-import com.android.frameworks.servicestests.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
-import com.android.server.power.batterysaver.BatterySavingStats;
-
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for {@link com.android.server.power.BatterySaverPolicy}
- */
-public class BatterySaverPolicyTest extends AndroidTestCase {
-    private static final boolean BATTERY_SAVER_ON = true;
-    private static final boolean BATTERY_SAVER_OFF = false;
-    private static final float BRIGHTNESS_FACTOR = 0.7f;
-    private static final float DEFAULT_BRIGHTNESS_FACTOR = 0.5f;
-    private static final float PRECISION = 0.001f;
-    private static final int GPS_MODE = 0;
-    private static final int DEFAULT_GPS_MODE =
-            PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
-    private static final String BATTERY_SAVER_CONSTANTS = "vibration_disabled=true,"
-            + "animation_disabled=false,"
-            + "soundtrigger_disabled=true,"
-            + "firewall_disabled=false,"
-            + "datasaver_disabled=false,"
-            + "adjust_brightness_disabled=true,"
-            + "adjust_brightness_factor=0.7,"
-            + "fullbackup_deferred=true,"
-            + "keyvaluebackup_deferred=false,"
-            + "gps_mode=0,"
-            + "quick_doze_enabled=true";
-    private static final String BATTERY_SAVER_INCORRECT_CONSTANTS = "vi*,!=,,true";
-
-    private class BatterySaverPolicyForTest extends BatterySaverPolicy {
-        public BatterySaverPolicyForTest(Object lock, Context context,
-                BatterySavingStats batterySavingStats) {
-            super(lock, context, batterySavingStats);
-        }
-
-        @Override
-        String getGlobalSetting(String key) {
-            return mMockGlobalSettings.get(key);
-        }
-
-        @Override
-        int getDeviceSpecificConfigResId() {
-            return mDeviceSpecificConfigResId;
-        }
-
-        @VisibleForTesting
-        void onChange() {
-            onChange(true, null);
-        }
-    }
-
-    @Mock
-    MetricsLogger mMetricsLogger = mock(MetricsLogger.class);
-
-    private BatterySaverPolicyForTest mBatterySaverPolicy;
-
-    private final ArrayMap<String, String> mMockGlobalSettings = new ArrayMap<>();
-    private int mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_1;
-
-    public void setUp() throws Exception {
-        super.setUp();
-        MockitoAnnotations.initMocks(this);
-        final Object lock = new Object();
-        mBatterySaverPolicy = new BatterySaverPolicyForTest(lock, getContext(),
-                new BatterySavingStats(lock, mMetricsLogger));
-        mBatterySaverPolicy.systemReady();
-    }
-
-    @SmallTest
-    public void testGetBatterySaverPolicy_PolicyNull_DefaultValueCorrect() {
-        testServiceDefaultValue_On(ServiceType.NULL);
-    }
-
-    @SmallTest
-    public void testGetBatterySaverPolicy_PolicyVibration_DefaultValueCorrect() {
-        testServiceDefaultValue_On(ServiceType.VIBRATION);
-    }
-
-    @SmallTest
-    public void testGetBatterySaverPolicy_PolicyVibration_WithAccessibilityEnabled() {
-        mBatterySaverPolicy.setAccessibilityEnabledForTest(true);
-        testServiceDefaultValue_Off(ServiceType.VIBRATION);
-    }
-
-    @SmallTest
-    public void testGetBatterySaverPolicy_PolicySound_DefaultValueCorrect() {
-        testServiceDefaultValue_On(ServiceType.SOUND);
-    }
-
-    @SmallTest
-    public void testGetBatterySaverPolicy_PolicyFullBackup_DefaultValueCorrect() {
-        testServiceDefaultValue_On(ServiceType.FULL_BACKUP);
-    }
-
-    @SmallTest
-    public void testGetBatterySaverPolicy_PolicyKeyValueBackup_DefaultValueCorrect() {
-        testServiceDefaultValue_On(ServiceType.KEYVALUE_BACKUP);
-    }
-
-    @SmallTest
-    public void testGetBatterySaverPolicy_PolicyAnimation_DefaultValueCorrect() {
-        testServiceDefaultValue_Off(ServiceType.ANIMATION);
-    }
-
-    @SmallTest
-    public void testGetBatterySaverPolicy_PolicyBatteryStats_DefaultValueCorrect() {
-        testServiceDefaultValue_On(ServiceType.BATTERY_STATS);
-    }
-
-    @SmallTest
-    public void testGetBatterySaverPolicy_PolicyNetworkFirewall_DefaultValueCorrect() {
-        testServiceDefaultValue_On(ServiceType.NETWORK_FIREWALL);
-    }
-
-    @SmallTest
-    public void testGetBatterySaverPolicy_PolicyDataSaver_DefaultValueCorrect() {
-        mBatterySaverPolicy.updateConstantsLocked("", "");
-        final PowerSaveState batterySaverStateOn =
-                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.DATA_SAVER, BATTERY_SAVER_ON);
-        assertThat(batterySaverStateOn.batterySaverEnabled).isFalse();
-
-        final PowerSaveState batterySaverStateOff = mBatterySaverPolicy.getBatterySaverPolicy(
-                ServiceType.DATA_SAVER, BATTERY_SAVER_OFF);
-        assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
-    }
-
-    @SmallTest
-    public void testGetBatterySaverPolicy_PolicyScreenBrightness_DefaultValueCorrect() {
-        testServiceDefaultValue_Off(ServiceType.SCREEN_BRIGHTNESS);
-    }
-
-    @SmallTest
-    public void testGetBatterySaverPolicy_PolicyGps_DefaultValueCorrect() {
-        testServiceDefaultValue_On(ServiceType.GPS);
-
-        PowerSaveState stateOn =
-                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.GPS, true);
-        assertThat(stateOn.gpsMode).isEqualTo(DEFAULT_GPS_MODE);
-    }
-
-    @SmallTest
-    public void testGetBatterySaverPolicy_PolicyQuickDoze_DefaultValueCorrect() {
-        testServiceDefaultValue_On(ServiceType.QUICK_DOZE);
-    }
-
-    @SmallTest
-    public void testUpdateConstants_getCorrectData() {
-        mBatterySaverPolicy.updateConstantsLocked(BATTERY_SAVER_CONSTANTS, "");
-
-        final PowerSaveState vibrationState =
-                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.VIBRATION, BATTERY_SAVER_ON);
-        assertThat(vibrationState.batterySaverEnabled).isTrue();
-
-        final PowerSaveState animationState =
-                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.ANIMATION, BATTERY_SAVER_ON);
-        assertThat(animationState.batterySaverEnabled).isFalse();
-
-        final PowerSaveState soundState =
-                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SOUND, BATTERY_SAVER_ON);
-        assertThat(soundState.batterySaverEnabled).isTrue();
-
-        final PowerSaveState networkState = mBatterySaverPolicy.getBatterySaverPolicy(
-                ServiceType.NETWORK_FIREWALL, BATTERY_SAVER_ON);
-        assertThat(networkState.batterySaverEnabled).isTrue();
-
-        final PowerSaveState screenState =
-                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS,
-                        BATTERY_SAVER_ON);
-        assertThat(screenState.batterySaverEnabled).isFalse();
-        assertThat(screenState.brightnessFactor).isWithin(PRECISION).of(BRIGHTNESS_FACTOR);
-
-        final PowerSaveState fullBackupState = mBatterySaverPolicy.getBatterySaverPolicy(
-                ServiceType.FULL_BACKUP, BATTERY_SAVER_ON);
-        assertThat(fullBackupState.batterySaverEnabled).isTrue();
-
-        final PowerSaveState keyValueBackupState = mBatterySaverPolicy.getBatterySaverPolicy(
-                ServiceType.KEYVALUE_BACKUP, BATTERY_SAVER_ON);
-        assertThat(keyValueBackupState.batterySaverEnabled).isFalse();
-
-        final PowerSaveState dataSaverState = mBatterySaverPolicy.getBatterySaverPolicy(
-                ServiceType.DATA_SAVER, BATTERY_SAVER_ON);
-        assertThat(dataSaverState.batterySaverEnabled).isTrue();
-
-        final PowerSaveState gpsState =
-                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.GPS, BATTERY_SAVER_ON);
-        assertThat(gpsState.batterySaverEnabled).isTrue();
-        assertThat(gpsState.gpsMode).isEqualTo(GPS_MODE);
-
-        final PowerSaveState quickDozeState = mBatterySaverPolicy.getBatterySaverPolicy(
-                ServiceType.QUICK_DOZE, BATTERY_SAVER_ON);
-        assertThat(quickDozeState.batterySaverEnabled).isTrue();
-    }
-
-    @SmallTest
-    public void testUpdateConstants_IncorrectData_NotCrash() {
-        //Should not crash
-        mBatterySaverPolicy.updateConstantsLocked(BATTERY_SAVER_INCORRECT_CONSTANTS, "");
-        mBatterySaverPolicy.updateConstantsLocked(null, "");
-    }
-
-    private void testServiceDefaultValue_On(@ServiceType int type) {
-        mBatterySaverPolicy.updateConstantsLocked("", "");
-        final PowerSaveState batterySaverStateOn =
-                mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_ON);
-        assertThat(batterySaverStateOn.batterySaverEnabled).isTrue();
-
-        final PowerSaveState batterySaverStateOff =
-                mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_OFF);
-        assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
-    }
-
-    private void testServiceDefaultValue_Off(@ServiceType int type) {
-        mBatterySaverPolicy.updateConstantsLocked("", "");
-        final PowerSaveState batterySaverStateOn =
-                mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_ON);
-        assertThat(batterySaverStateOn.batterySaverEnabled).isFalse();
-
-        final PowerSaveState batterySaverStateOff =
-                mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_OFF);
-        assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
-    }
-
-    public void testDeviceSpecific() {
-        mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_1;
-        mMockGlobalSettings.put(Global.BATTERY_SAVER_CONSTANTS, "");
-        mMockGlobalSettings.put(Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS, "");
-
-        mBatterySaverPolicy.onChange();
-        assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{}");
-        assertThat(mBatterySaverPolicy.getFileValues(false).toString()).isEqualTo("{}");
-
-
-        mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_2;
-
-        mBatterySaverPolicy.onChange();
-        assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{}");
-        assertThat(mBatterySaverPolicy.getFileValues(false).toString())
-                .isEqualTo("{/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq=123, " +
-                "/sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq=456}");
-
-        mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_3;
-
-        mBatterySaverPolicy.onChange();
-        assertThat(mBatterySaverPolicy.getFileValues(true).toString())
-                .isEqualTo("{/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq=333, " +
-                        "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq=444}");
-        assertThat(mBatterySaverPolicy.getFileValues(false).toString())
-                .isEqualTo("{/sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq=222}");
-
-
-        mMockGlobalSettings.put(Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
-                "cpufreq-i=3:1234567890/4:014/5:015");
-
-        mBatterySaverPolicy.onChange();
-        assertThat(mBatterySaverPolicy.getFileValues(true).toString())
-                .isEqualTo("{/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq=1234567890, " +
-                        "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq=14, " +
-                        "/sys/devices/system/cpu/cpu5/cpufreq/scaling_max_freq=15}");
-        assertThat(mBatterySaverPolicy.getFileValues(false).toString()).isEqualTo("{}");
-    }
-}
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 561c61f..0dff03f 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -47,6 +47,7 @@
 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.BatterySaverPolicy;
 import com.android.server.power.batterysaver.BatterySavingStats;
 
 import org.junit.Rule;
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
new file mode 100644
index 0000000..73eefcf
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.power.batterysaver;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
+import android.os.PowerSaveState;
+import android.provider.Settings.Global;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArrayMap;
+
+import com.android.frameworks.servicestests.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link com.android.server.power.batterysaver.BatterySaverPolicy}
+ */
+public class BatterySaverPolicyTest extends AndroidTestCase {
+    private static final boolean BATTERY_SAVER_ON = true;
+    private static final boolean BATTERY_SAVER_OFF = false;
+    private static final float BRIGHTNESS_FACTOR = 0.7f;
+    private static final float DEFAULT_BRIGHTNESS_FACTOR = 0.5f;
+    private static final float PRECISION = 0.001f;
+    private static final int GPS_MODE = 0;
+    private static final int DEFAULT_GPS_MODE =
+            PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
+    private static final String BATTERY_SAVER_CONSTANTS = "vibration_disabled=true,"
+            + "animation_disabled=false,"
+            + "soundtrigger_disabled=true,"
+            + "firewall_disabled=false,"
+            + "datasaver_disabled=false,"
+            + "adjust_brightness_disabled=true,"
+            + "adjust_brightness_factor=0.7,"
+            + "fullbackup_deferred=true,"
+            + "keyvaluebackup_deferred=false,"
+            + "gps_mode=0,"
+            + "quick_doze_enabled=true";
+    private static final String BATTERY_SAVER_INCORRECT_CONSTANTS = "vi*,!=,,true";
+
+    private class BatterySaverPolicyForTest extends BatterySaverPolicy {
+        BatterySaverPolicyForTest(Object lock, Context context,
+                BatterySavingStats batterySavingStats) {
+            super(lock, context, batterySavingStats);
+        }
+
+        @Override
+        String getGlobalSetting(String key) {
+            return mMockGlobalSettings.get(key);
+        }
+
+        @Override
+        int getDeviceSpecificConfigResId() {
+            return mDeviceSpecificConfigResId;
+        }
+
+        @VisibleForTesting
+        void onChange() {
+            onChange(true, null);
+        }
+    }
+
+    @Mock
+    MetricsLogger mMetricsLogger = mock(MetricsLogger.class);
+
+    private BatterySaverPolicyForTest mBatterySaverPolicy;
+
+    private final ArrayMap<String, String> mMockGlobalSettings = new ArrayMap<>();
+    private int mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_1;
+
+    public void setUp() throws Exception {
+        super.setUp();
+        MockitoAnnotations.initMocks(this);
+        final Object lock = new Object();
+        mBatterySaverPolicy = new BatterySaverPolicyForTest(lock, getContext(),
+                new BatterySavingStats(lock, mMetricsLogger));
+        mBatterySaverPolicy.systemReady();
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyNull_DefaultValueCorrect() {
+        testServiceDefaultValue_On(ServiceType.NULL);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyVibration_DefaultValueCorrect() {
+        testServiceDefaultValue_On(ServiceType.VIBRATION);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyVibration_WithAccessibilityEnabled() {
+        mBatterySaverPolicy.setAccessibilityEnabledForTest(true);
+        testServiceDefaultValue_Off(ServiceType.VIBRATION);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicySound_DefaultValueCorrect() {
+        testServiceDefaultValue_On(ServiceType.SOUND);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyFullBackup_DefaultValueCorrect() {
+        testServiceDefaultValue_On(ServiceType.FULL_BACKUP);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyKeyValueBackup_DefaultValueCorrect() {
+        testServiceDefaultValue_On(ServiceType.KEYVALUE_BACKUP);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyAnimation_DefaultValueCorrect() {
+        testServiceDefaultValue_Off(ServiceType.ANIMATION);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyBatteryStats_DefaultValueCorrect() {
+        testServiceDefaultValue_On(ServiceType.BATTERY_STATS);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyNetworkFirewall_DefaultValueCorrect() {
+        testServiceDefaultValue_On(ServiceType.NETWORK_FIREWALL);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyDataSaver_DefaultValueCorrect() {
+        mBatterySaverPolicy.updateConstantsLocked("", "");
+        final PowerSaveState batterySaverStateOn =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.DATA_SAVER, BATTERY_SAVER_ON);
+        assertThat(batterySaverStateOn.batterySaverEnabled).isFalse();
+
+        final PowerSaveState batterySaverStateOff = mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.DATA_SAVER, BATTERY_SAVER_OFF);
+        assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyScreenBrightness_DefaultValueCorrect() {
+        testServiceDefaultValue_Off(ServiceType.SCREEN_BRIGHTNESS);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyGps_DefaultValueCorrect() {
+        testServiceDefaultValue_On(ServiceType.GPS);
+
+        PowerSaveState stateOn =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.GPS, true);
+        assertThat(stateOn.gpsMode).isEqualTo(DEFAULT_GPS_MODE);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyQuickDoze_DefaultValueCorrect() {
+        testServiceDefaultValue_On(ServiceType.QUICK_DOZE);
+    }
+
+    @SmallTest
+    public void testUpdateConstants_getCorrectData() {
+        mBatterySaverPolicy.updateConstantsLocked(BATTERY_SAVER_CONSTANTS, "");
+
+        final PowerSaveState vibrationState =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.VIBRATION, BATTERY_SAVER_ON);
+        assertThat(vibrationState.batterySaverEnabled).isTrue();
+
+        final PowerSaveState animationState =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.ANIMATION, BATTERY_SAVER_ON);
+        assertThat(animationState.batterySaverEnabled).isFalse();
+
+        final PowerSaveState soundState =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SOUND, BATTERY_SAVER_ON);
+        assertThat(soundState.batterySaverEnabled).isTrue();
+
+        final PowerSaveState networkState = mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.NETWORK_FIREWALL, BATTERY_SAVER_ON);
+        assertThat(networkState.batterySaverEnabled).isTrue();
+
+        final PowerSaveState screenState =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS,
+                        BATTERY_SAVER_ON);
+        assertThat(screenState.batterySaverEnabled).isFalse();
+        assertThat(screenState.brightnessFactor).isWithin(PRECISION).of(BRIGHTNESS_FACTOR);
+
+        final PowerSaveState fullBackupState = mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.FULL_BACKUP, BATTERY_SAVER_ON);
+        assertThat(fullBackupState.batterySaverEnabled).isTrue();
+
+        final PowerSaveState keyValueBackupState = mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.KEYVALUE_BACKUP, BATTERY_SAVER_ON);
+        assertThat(keyValueBackupState.batterySaverEnabled).isFalse();
+
+        final PowerSaveState dataSaverState = mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.DATA_SAVER, BATTERY_SAVER_ON);
+        assertThat(dataSaverState.batterySaverEnabled).isTrue();
+
+        final PowerSaveState gpsState =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.GPS, BATTERY_SAVER_ON);
+        assertThat(gpsState.batterySaverEnabled).isTrue();
+        assertThat(gpsState.gpsMode).isEqualTo(GPS_MODE);
+
+        final PowerSaveState quickDozeState = mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.QUICK_DOZE, BATTERY_SAVER_ON);
+        assertThat(quickDozeState.batterySaverEnabled).isTrue();
+    }
+
+    @SmallTest
+    public void testUpdateConstants_IncorrectData_NotCrash() {
+        //Should not crash
+        mBatterySaverPolicy.updateConstantsLocked(BATTERY_SAVER_INCORRECT_CONSTANTS, "");
+        mBatterySaverPolicy.updateConstantsLocked(null, "");
+    }
+
+    private void testServiceDefaultValue_On(@ServiceType int type) {
+        mBatterySaverPolicy.updateConstantsLocked("", "");
+        final PowerSaveState batterySaverStateOn =
+                mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_ON);
+        assertThat(batterySaverStateOn.batterySaverEnabled).isTrue();
+
+        final PowerSaveState batterySaverStateOff =
+                mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_OFF);
+        assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
+    }
+
+    private void testServiceDefaultValue_Off(@ServiceType int type) {
+        mBatterySaverPolicy.updateConstantsLocked("", "");
+        final PowerSaveState batterySaverStateOn =
+                mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_ON);
+        assertThat(batterySaverStateOn.batterySaverEnabled).isFalse();
+
+        final PowerSaveState batterySaverStateOff =
+                mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_OFF);
+        assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
+    }
+
+    public void testDeviceSpecific() {
+        mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_1;
+        mMockGlobalSettings.put(Global.BATTERY_SAVER_CONSTANTS, "");
+        mMockGlobalSettings.put(Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS, "");
+
+        mBatterySaverPolicy.onChange();
+        assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{}");
+        assertThat(mBatterySaverPolicy.getFileValues(false).toString()).isEqualTo("{}");
+
+
+        mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_2;
+
+        mBatterySaverPolicy.onChange();
+        assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{}");
+        assertThat(mBatterySaverPolicy.getFileValues(false).toString())
+                .isEqualTo("{/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq=123, "
+                        + "/sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq=456}");
+
+        mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_3;
+
+        mBatterySaverPolicy.onChange();
+        assertThat(mBatterySaverPolicy.getFileValues(true).toString())
+                .isEqualTo("{/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq=333, "
+                        + "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq=444}");
+        assertThat(mBatterySaverPolicy.getFileValues(false).toString())
+                .isEqualTo("{/sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq=222}");
+
+
+        mMockGlobalSettings.put(Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
+                "cpufreq-i=3:1234567890/4:014/5:015");
+
+        mBatterySaverPolicy.onChange();
+        assertThat(mBatterySaverPolicy.getFileValues(true).toString())
+                .isEqualTo("{/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq=1234567890, "
+                        + "/sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq=14, "
+                        + "/sys/devices/system/cpu/cpu5/cpufreq/scaling_max_freq=15}");
+        assertThat(mBatterySaverPolicy.getFileValues(false).toString()).isEqualTo("{}");
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
deleted file mode 100644
index f31ca55..0000000
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ /dev/null
@@ -1,758 +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.power.batterysaver;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.content.ContentResolver;
-import android.content.res.Resources;
-import android.provider.Settings.Global;
-import android.test.mock.MockContext;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.common.base.Objects;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.HashMap;
-
-/**
- atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class BatterySaverStateMachineTest {
-
-    private MyMockContext mMockContext;
-    private ContentResolver mMockContextResolver;
-    private BatterySaverController mMockBatterySaverController;
-    private Device mDevice;
-    private TestableBatterySaverStateMachine mTarget;
-    private Resources mMockResources;
-
-    private class MyMockContext extends MockContext {
-        @Override
-        public ContentResolver getContentResolver() {
-            return mMockContextResolver;
-        }
-
-        @Override
-        public Resources getResources() {
-            return mMockResources;
-        }
-    }
-
-    private DevicePersistedState mPersistedState;
-
-    private class DevicePersistedState {
-        // Current battery level.
-        public int batteryLevel = 100;
-
-        // Whether battery level is currently low or not.
-        public boolean batteryLow = false;
-
-        // Whether the device is plugged in or not.
-        public boolean powered = false;
-
-        // Global settings.
-        public final HashMap<String, Integer> global = new HashMap<>();
-    }
-
-    /**
-     * This class simulates a device's volatile status that will be reset by {@link #initDevice()}.
-     */
-    private class Device {
-        public boolean batterySaverEnabled = false;
-
-        public int getLowPowerModeTriggerLevel() {
-            return mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
-        }
-
-        public void setBatteryLevel(int level) {
-            mPersistedState.batteryLevel = level;
-            if (mPersistedState.batteryLevel <= Math.max(15, getLowPowerModeTriggerLevel())) {
-                mPersistedState.batteryLow = true;
-            } else if (mPersistedState.batteryLow
-                    && (mPersistedState.batteryLevel >= (getLowPowerModeTriggerLevel() + 5))) {
-                mPersistedState.batteryLow = false;
-            }
-            pushBatteryStatus();
-        }
-
-        public void setPowered(boolean newPowered) {
-            mPersistedState.powered = newPowered;
-            pushBatteryStatus();
-        }
-
-        public void pushBatteryStatus() {
-            mTarget.setBatteryStatus(mPersistedState.powered, mPersistedState.batteryLevel,
-                    mPersistedState.batteryLow);
-        }
-
-        public void pushGlobalSettings() {
-            mTarget.setSettingsLocked(
-                    mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE, 0) != 0,
-                    mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE_STICKY, 0) != 0,
-                    mDevice.getLowPowerModeTriggerLevel(),
-                    mPersistedState.global.getOrDefault(Global.AUTOMATIC_POWER_SAVER_MODE, 0),
-                    mPersistedState.global.getOrDefault(
-                            Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0) != 0,
-                    mPersistedState.global.getOrDefault(
-                            Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 100));
-        }
-
-        public void putGlobalSetting(String key, int value) {
-            mPersistedState.global.put(key, value);
-            pushGlobalSettings();
-        }
-
-        public int getGlobalSetting(String key, int defValue) {
-            return mPersistedState.global.getOrDefault(key, defValue);
-        }
-    }
-
-    /**
-     * Test target class.
-     */
-    private class TestableBatterySaverStateMachine extends BatterySaverStateMachine {
-        public TestableBatterySaverStateMachine() {
-            super(new Object(), mMockContext, mMockBatterySaverController);
-        }
-
-        @Override
-        protected void putGlobalSetting(String key, int value) {
-            if (Objects.equal(mPersistedState.global.get(key), value)) {
-                return;
-            }
-            mDevice.putGlobalSetting(key, value);
-        }
-
-        @Override
-        protected int getGlobalSetting(String key, int defValue) {
-            return mDevice.getGlobalSetting(key, defValue);
-        }
-
-        @Override
-        void runOnBgThread(Runnable r) {
-            r.run();
-        }
-
-        @Override
-        void runOnBgThreadLazy(Runnable r, int delayMillis) {
-            r.run();
-        }
-    }
-
-    @Before
-    public void setUp() {
-        mMockContext = new MyMockContext();
-        mMockContextResolver = mock(ContentResolver.class);
-        mMockBatterySaverController = mock(BatterySaverController.class);
-        mMockResources = mock(Resources.class);
-
-        doAnswer((inv) -> mDevice.batterySaverEnabled = inv.getArgument(0))
-                .when(mMockBatterySaverController).enableBatterySaver(anyBoolean(), anyInt());
-        when(mMockBatterySaverController.isEnabled())
-                .thenAnswer((inv) -> mDevice.batterySaverEnabled);
-        when(mMockResources.getBoolean(
-                com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
-                .thenReturn(false);
-        when(mMockResources.getInteger(
-                com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold))
-                .thenReturn(80);
-
-        mPersistedState = new DevicePersistedState();
-        initDevice();
-    }
-
-    private void initDevice() {
-        mDevice = new Device();
-
-        mTarget = new TestableBatterySaverStateMachine();
-
-        mDevice.pushBatteryStatus();
-        mTarget.onBootCompleted();
-    }
-
-    @Test
-    public void testNoAutoBatterySaver() {
-        assertEquals(0, mDevice.getLowPowerModeTriggerLevel());
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(100, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(90);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(50);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(50, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(16);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(16, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        // When LOW_POWER_MODE_TRIGGER_LEVEL is 0, 15% will still trigger low-battery, but
-        // BS wont be enabled.
-        mDevice.setBatteryLevel(15);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(15, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(10);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(10, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        // Manually enable BS.
-        mTarget.setBatterySaverEnabledManually(true);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(10, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(50);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(50, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        // Start charging. It'll disable BS.
-        mDevice.setPowered(true);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(50, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(60);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(60, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        // Unplug.
-        mDevice.setPowered(false);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(60, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(10);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(10, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(80);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(80, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        // Reboot the device.
-        initDevice();
-
-        assertEquals(true, mDevice.batterySaverEnabled); // Sticky.
-        assertEquals(80, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(30);
-        initDevice();
-
-        assertEquals(true, mDevice.batterySaverEnabled); // Still sticky.
-        assertEquals(30, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mTarget.setBatterySaverEnabledManually(false);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        initDevice(); // reboot.
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-    }
-
-    @Test
-    public void testAutoBatterySaver() {
-        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
-        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 0);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(100, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(90);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(51);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(51, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        // Hit the threshold. BS should be enabled.
-        mDevice.setBatteryLevel(50);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(50, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        // Battery goes up, but until it hits 55%, we still keep BS on.
-        mDevice.setBatteryLevel(54);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(54, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        // 50% + 5%, now BS will be off.
-        mDevice.setBatteryLevel(55);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(55, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(40);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(40, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setPowered(true);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(40, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setPowered(false);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(40, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(40, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(30);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        // Plug in and out, snooze will reset.
-        mDevice.setPowered(true);
-        mDevice.setPowered(false);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setPowered(true);
-        mDevice.setBatteryLevel(60);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(60, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setPowered(false);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(60, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(50);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(50, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(70);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(70, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        // Bump ump the threshold.
-        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 70);
-        mDevice.setBatteryLevel(mPersistedState.batteryLevel);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(70, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        // Then down.
-        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 60);
-        mDevice.setBatteryLevel(mPersistedState.batteryLevel);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(70, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        // Reboot in low state -> automatically enable BS.
-        mDevice.setPowered(false);
-        mDevice.setBatteryLevel(30);
-        mTarget.setBatterySaverEnabledManually(false);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        initDevice();
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-    }
-
-    @Test
-    public void testAutoBatterySaver_withSticky() {
-        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
-
-        mTarget.setBatterySaverEnabledManually(true);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(100, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(30);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(80);
-
-        assertEquals(true, mDevice.batterySaverEnabled); // Still enabled.
-        assertEquals(80, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setPowered(true);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(80, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(30);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setPowered(false);
-
-        assertEquals(true, mDevice.batterySaverEnabled); // Restores BS.
-        assertEquals(30, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setPowered(true);
-        mDevice.setBatteryLevel(90);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        initDevice();
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setPowered(false);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mTarget.setBatterySaverEnabledManually(false);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        initDevice();
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-    }
-
-    @Test
-    public void testAutoBatterySaver_withStickyDisabled() {
-        when(mMockResources.getBoolean(
-                com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
-                .thenReturn(true);
-        initDevice();
-        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
-        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 0);
-
-        mTarget.setBatterySaverEnabledManually(true);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(100, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(30);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(80);
-
-        assertEquals(false, mDevice.batterySaverEnabled); // Not sticky.
-        assertEquals(80, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setPowered(true);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(80, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(30);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setPowered(false);
-
-        assertEquals(true, mDevice.batterySaverEnabled); // Restores BS.
-        assertEquals(30, mPersistedState.batteryLevel);
-        assertEquals(true, mPersistedState.batteryLow);
-
-        mDevice.setPowered(true);
-        mDevice.setBatteryLevel(90);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        initDevice();
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setPowered(false);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mTarget.setBatterySaverEnabledManually(false);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        initDevice();
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-    }
-
-    @Test
-    public void testNoAutoBatterySaver_fromAdb() {
-        assertEquals(0, mDevice.getLowPowerModeTriggerLevel());
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(100, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        mDevice.setBatteryLevel(90);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        // Enable
-        mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 1);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        // Disable
-        mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 0);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        // Enable again
-        mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 1);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-
-        // Reboot -- setting BS from adb is also sticky.
-        initDevice();
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-        assertEquals(false, mPersistedState.batteryLow);
-    }
-
-    @Test
-    public void testAutoBatterySaver_smartBatterySaverEnabled() {
-        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
-        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 1);
-        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(100, mPersistedState.batteryLevel);
-
-        mDevice.setBatteryLevel(90);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(90, mPersistedState.batteryLevel);
-
-        mDevice.setBatteryLevel(51);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(51, mPersistedState.batteryLevel);
-
-        // Hit the threshold. BS should be disabled since dynamic power savings still off
-        mDevice.setBatteryLevel(50);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(50, mPersistedState.batteryLevel);
-
-        // dynamic power savings comes on, battery saver should turn on
-        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1);
-        mDevice.setBatteryLevel(40);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(40, mPersistedState.batteryLevel);
-
-        mDevice.setPowered(true);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(40, mPersistedState.batteryLevel);
-
-        mDevice.setPowered(false);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(40, mPersistedState.batteryLevel);
-
-        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(40, mPersistedState.batteryLevel);
-
-        mDevice.setBatteryLevel(30);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-
-        // Plug in and out, snooze will reset.
-        mDevice.setPowered(true);
-        mDevice.setPowered(false);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-
-        mDevice.setPowered(true);
-        mDevice.setBatteryLevel(60);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(60, mPersistedState.batteryLevel);
-
-        mDevice.setPowered(false);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(60, mPersistedState.batteryLevel);
-
-        mDevice.setBatteryLevel(40);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(40, mPersistedState.batteryLevel);
-
-        mDevice.setBatteryLevel(70);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(70, mPersistedState.batteryLevel);
-
-        // Bump up the threshold.
-        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 71);
-        mDevice.setBatteryLevel(mPersistedState.batteryLevel);
-
-        // changes are only registered if some battery level changed
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(70, mPersistedState.batteryLevel);
-
-        mDevice.setBatteryLevel(69);
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(69, mPersistedState.batteryLevel);
-
-        // Then down.
-        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 60);
-        mDevice.setBatteryLevel(mPersistedState.batteryLevel);
-
-        // changes are only registered if battery level changed
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(69, mPersistedState.batteryLevel);
-
-        mDevice.setBatteryLevel(68);
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(68, mPersistedState.batteryLevel);
-
-        // Reboot in low state -> automatically enable BS.
-        mDevice.setPowered(false);
-        mDevice.setBatteryLevel(30);
-        mTarget.setBatterySaverEnabledManually(false);
-
-        assertEquals(false, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-
-        initDevice();
-
-        assertEquals(true, mDevice.batterySaverEnabled);
-        assertEquals(30, mPersistedState.batteryLevel);
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 41d5691..8171469 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -61,6 +61,7 @@
 import android.view.Display;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -416,6 +417,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 119774928)
     public void testEnabledState() throws Exception {
         TestParoleListener paroleListener = new TestParoleListener();
         mController.addListener(paroleListener);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
index 8496a96..b348aee 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
@@ -699,10 +699,52 @@
         assertTrue(hasUsageSessionObserver(UID, OBS_ID1));
     }
 
+    /** Verify the timeout message is delivered at the right time after past usage was reported */
+    @Test
+    public void testAppUsageObserver_PastUsage() throws Exception {
+        setTime(10_000L);
+        addAppUsageObserver(OBS_ID1, GROUP1, 6_000L);
+        setTime(20_000L);
+        startPastUsage(PKG_SOC1, 5_000);
+        setTime(21_000L);
+        assertTrue(mLimitReachedLatch.await(2_000L, TimeUnit.MILLISECONDS));
+        stopUsage(PKG_SOC1);
+        // Verify that the observer was removed
+        assertFalse(hasAppUsageObserver(UID, OBS_ID1));
+    }
+
+    /**
+     * Verify the timeout message is delivered at the right time after past usage was reported
+     * that overlaps with already known usage
+     */
+    @Test
+    public void testAppUsageObserver_PastUsageOverlap() throws Exception {
+        setTime(0L);
+        addAppUsageObserver(OBS_ID1, GROUP1, 20_000L);
+        setTime(10_000L);
+        startUsage(PKG_SOC1);
+        setTime(20_000L);
+        stopUsage(PKG_SOC1);
+        setTime(25_000L);
+        startPastUsage(PKG_SOC1, 9_000);
+        setTime(26_000L);
+        // the 4 seconds of overlapped usage should not be counted
+        assertFalse(mLimitReachedLatch.await(2_000L, TimeUnit.MILLISECONDS));
+        setTime(30_000L);
+        assertTrue(mLimitReachedLatch.await(4_000L, TimeUnit.MILLISECONDS));
+        stopUsage(PKG_SOC1);
+        // Verify that the observer was removed
+        assertFalse(hasAppUsageObserver(UID, OBS_ID1));
+    }
+
     private void startUsage(String packageName) {
         mController.noteUsageStart(packageName, USER_ID);
     }
 
+    private void startPastUsage(String packageName, int timeAgo) {
+        mController.noteUsageStart(packageName, USER_ID, timeAgo);
+    }
+
     private void stopUsage(String packageName) {
         mController.noteUsageStop(packageName, USER_ID);
     }
diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
index 860656b..8d9b3cf 100644
--- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
+++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
@@ -45,6 +45,8 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class UsageStatsDatabaseTest {
+
+    private static final int MAX_TESTED_VERSION = 4;
     protected Context mContext;
     private UsageStatsDatabase mUsageStatsDatabase;
     private File mTestDir;
@@ -131,8 +133,8 @@
 
         for (int i = 0; i < numberOfEvents; i++) {
             Event event = new Event();
-            final int packageInt = ((i / 3) % 7);
-            event.mPackage = "fake.package.name" + packageInt; //clusters of 3 events from 7 "apps"
+            final int packageInt = ((i / 3) % 7); //clusters of 3 events from 7 "apps"
+            event.mPackage = "fake.package.name" + packageInt;
             if (packageInt == 3) {
                 // Third app is an instant app
                 event.mFlags |= Event.FLAG_IS_PACKAGE_INSTANT_APP;
@@ -144,6 +146,13 @@
             event.mEventType = i % (MAX_EVENT_TYPE + 1); //"random" event type
             event.mInstanceId = instanceId;
 
+
+            final int rootPackageInt = (i % 5); // 5 "apps" start each task
+            event.mTaskRootPackage = "fake.package.name" + rootPackageInt;
+
+            final int rootClassInt = i % 6;
+            event.mTaskRootClass = ".fake.class.name" + rootClassInt;
+
             switch (event.mEventType) {
                 case Event.CONFIGURATION_CHANGE:
                     //empty config,
@@ -163,7 +172,7 @@
                     break;
             }
 
-            mIntervalStats.events.insert(event);
+            mIntervalStats.addEvent(event);
             mIntervalStats.update(event.mPackage, event.mClass, event.mTimeStamp, event.mEventType,
                     event.mInstanceId);
 
@@ -234,31 +243,40 @@
         assertEquals(us1.mChooserCounts, us2.mChooserCounts);
     }
 
-    void compareUsageEvent(Event e1, Event e2, int debugId) {
-        assertEquals(e1.mPackage, e2.mPackage, "Usage event " + debugId);
-        assertEquals(e1.mClass, e2.mClass, "Usage event " + debugId);
-        assertEquals(e1.mTimeStamp, e2.mTimeStamp, "Usage event " + debugId);
-        assertEquals(e1.mEventType, e2.mEventType, "Usage event " + debugId);
-        switch (e1.mEventType) {
-            case Event.CONFIGURATION_CHANGE:
-                assertEquals(e1.mConfiguration, e2.mConfiguration,
-                        "Usage event " + debugId + e2.mConfiguration.toString());
-                break;
-            case Event.SHORTCUT_INVOCATION:
-                assertEquals(e1.mShortcutId, e2.mShortcutId, "Usage event " + debugId);
-                break;
-            case Event.STANDBY_BUCKET_CHANGED:
-                assertEquals(e1.mBucketAndReason, e2.mBucketAndReason, "Usage event " + debugId);
-                break;
-            case Event.NOTIFICATION_INTERRUPTION:
-                assertEquals(e1.mNotificationChannelId, e2.mNotificationChannelId,
-                        "Usage event " + debugId);
-                break;
+    void compareUsageEvent(Event e1, Event e2, int debugId, int minVersion) {
+        switch (minVersion) {
+            case 4: // test fields added in version 4
+                assertEquals(e1.mInstanceId, e2.mInstanceId, "Usage event " + debugId);
+                assertEquals(e1.mTaskRootPackage, e2.mTaskRootPackage, "Usage event " + debugId);
+                assertEquals(e1.mTaskRootClass, e2.mTaskRootClass, "Usage event " + debugId);
+                // fallthrough
+            default:
+                assertEquals(e1.mPackage, e2.mPackage, "Usage event " + debugId);
+                assertEquals(e1.mClass, e2.mClass, "Usage event " + debugId);
+                assertEquals(e1.mTimeStamp, e2.mTimeStamp, "Usage event " + debugId);
+                assertEquals(e1.mEventType, e2.mEventType, "Usage event " + debugId);
+                switch (e1.mEventType) {
+                    case Event.CONFIGURATION_CHANGE:
+                        assertEquals(e1.mConfiguration, e2.mConfiguration,
+                                "Usage event " + debugId + e2.mConfiguration.toString());
+                        break;
+                    case Event.SHORTCUT_INVOCATION:
+                        assertEquals(e1.mShortcutId, e2.mShortcutId, "Usage event " + debugId);
+                        break;
+                    case Event.STANDBY_BUCKET_CHANGED:
+                        assertEquals(e1.mBucketAndReason, e2.mBucketAndReason,
+                                "Usage event " + debugId);
+                        break;
+                    case Event.NOTIFICATION_INTERRUPTION:
+                        assertEquals(e1.mNotificationChannelId, e2.mNotificationChannelId,
+                                "Usage event " + debugId);
+                        break;
+                }
+                assertEquals(e1.mFlags, e2.mFlags);
         }
-        assertEquals(e1.mFlags, e2.mFlags);
     }
 
-    void compareIntervalStats(IntervalStats stats1, IntervalStats stats2) {
+    void compareIntervalStats(IntervalStats stats1, IntervalStats stats2, int minVersion) {
         assertEquals(stats1.majorVersion, stats2.majorVersion);
         assertEquals(stats1.minorVersion, stats2.minorVersion);
         assertEquals(stats1.beginTime, stats2.beginTime);
@@ -311,7 +329,7 @@
         } else {
             assertEquals(stats1.events.size(), stats2.events.size());
             for (int i = 0; i < stats1.events.size(); i++) {
-                compareUsageEvent(stats1.events.get(i), stats2.events.get(i), i);
+                compareUsageEvent(stats1.events.get(i), stats2.events.get(i), i, minVersion);
             }
         }
     }
@@ -326,7 +344,7 @@
                 mIntervalStatsVerifier);
 
         assertEquals(1, stats.size());
-        compareIntervalStats(mIntervalStats, stats.get(0));
+        compareIntervalStats(mIntervalStats, stats.get(0), MAX_TESTED_VERSION);
     }
 
     /**
@@ -359,8 +377,10 @@
                 mIntervalStatsVerifier);
 
         assertEquals(1, stats.size());
+
+        final int minVersion = oldVersion < newVersion ? oldVersion : newVersion;
         // The written and read IntervalStats should match
-        compareIntervalStats(mIntervalStats, stats.get(0));
+        compareIntervalStats(mIntervalStats, stats.get(0), minVersion);
     }
 
     /**
@@ -401,7 +421,7 @@
         if (mIntervalStats.events != null) mIntervalStats.events.clear();
 
         // The written and read IntervalStats should match
-        compareIntervalStats(mIntervalStats, stats.get(0));
+        compareIntervalStats(mIntervalStats, stats.get(0), version);
     }
 
     /**
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index afbe6bc..20c5f5d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -60,6 +60,7 @@
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings;
+import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -114,7 +115,7 @@
     private static final Uri CUSTOM_SOUND = Settings.System.DEFAULT_ALARM_ALERT_URI;
     private static final AudioAttributes CUSTOM_ATTRIBUTES = new AudioAttributes.Builder()
             .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
-            .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+            .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
             .build();
     private static final int CUSTOM_LIGHT_COLOR = Color.BLACK;
     private static final int CUSTOM_LIGHT_ON = 10000;
@@ -237,11 +238,11 @@
                 false /* noisy */, false /* buzzy*/, true /* lights */);
     }
 
-    private NotificationRecord getCustomLightsNotification() {
-        return getNotificationRecord(mId, false /* insistent */, true /* once */,
-                false /* noisy */, true /* buzzy*/, true /* lights */,
-                true /* defaultVibration */, true /* defaultSound */, false /* defaultLights */,
-                null, Notification.GROUP_ALERT_ALL, false);
+    private NotificationRecord getCallRecord(int id, boolean insistent) {
+        return getNotificationRecord(id, false, false /* once */, true /* noisy */,
+                false /* buzzy */, false /* lights */, false /* default vib */,
+                false /* default sound */, false /* default lights */, "",
+                Notification.GROUP_ALERT_ALL, false);
     }
 
     private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
@@ -351,11 +352,6 @@
                 eq(false), (AudioAttributes) anyObject());
     }
 
-    private void verifyCustomBeep() throws RemoteException {
-        verify(mRingtonePlayer, times(1)).playAsync(eq(CUSTOM_SOUND), (UserHandle) anyObject(),
-                eq(false), (AudioAttributes) anyObject());
-    }
-
     private void verifyNeverStopAudio() throws RemoteException {
         verify(mRingtonePlayer, never()).stopAsync();
     }
@@ -1277,6 +1273,64 @@
         assertEquals(-1, group.getLastAudiblyAlertedMs());
     }
 
+    @Test
+    public void testListenerHintCall() throws Exception {
+        NotificationRecord r = getCallRecord(1, true);
+
+        mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverBeep();
+    }
+
+    @Test
+    public void testListenerHintCall_notificationSound() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+
+        mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyBeepLooped();
+    }
+
+    @Test
+    public void testListenerHintNotification() throws Exception {
+        NotificationRecord r = getBeepyNotification();
+
+        mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyNeverBeep();
+    }
+
+    @Test
+    public void testListenerHintBoth() throws Exception {
+        NotificationRecord r = getCallRecord(1, true);
+        NotificationRecord s = getBeepyNotification();
+
+        mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
+                | NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS);
+
+        mService.buzzBeepBlinkLocked(r);
+        mService.buzzBeepBlinkLocked(s);
+
+        verifyNeverBeep();
+    }
+
+    @Test
+    public void testListenerHintNotification_callSound() throws Exception {
+        NotificationRecord r = getCallRecord(1, true);
+
+        mService.setHints(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
+
+        mService.buzzBeepBlinkLocked(r);
+
+        verifyBeepLooped();
+    }
+
     static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> {
         private final int mRepeatIndex;
 
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 659c6e7..20f72bf 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -613,7 +613,7 @@
     }
 
     @Test
-    public void testGetAllowedPackages() throws Exception {
+    public void testGetAllowedPackages_byUser() throws Exception {
         for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
             ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
                     mIpm, approvalLevel);
@@ -681,6 +681,30 @@
     }
 
     @Test
+    public void testGetAllowedPackages() throws Exception {
+        ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
+                mIpm, APPROVAL_BY_COMPONENT);
+        loadXml(service);
+        service.mApprovalLevel = APPROVAL_BY_PACKAGE;
+        loadXml(service);
+
+        List<String> allowedPackages = new ArrayList<>();
+        allowedPackages.add("this.is.a.package.name");
+        allowedPackages.add("another.package");
+        allowedPackages.add("secondary");
+        allowedPackages.add("this.is.another.package");
+        allowedPackages.add("package");
+        allowedPackages.add("component");
+        allowedPackages.add("bananas!");
+
+        Set<String> actual = service.getAllowedPackages();
+        assertEquals(allowedPackages.size(), actual.size());
+        for (String pkg : allowedPackages) {
+            assertTrue(actual.contains(pkg));
+        }
+    }
+
+    @Test
     public void testOnUserRemoved() throws Exception {
         for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
             ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
@@ -859,6 +883,19 @@
         assertTrue(componentsToBind.get(10).contains(ComponentName.unflattenFromString("c/c")));
     }
 
+    @Test
+    public void testOnPackagesChanged_nullValuesPassed_noNullPointers() {
+        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
+            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
+                    mIpm, approvalLevel);
+            // null uid list
+            service.onPackagesChanged(true, new String[]{"this.is.a.package.name"}, null);
+
+            // null package list
+            service.onPackagesChanged(true, null, new int[]{103});
+        }
+    }
+
     private void loadXml(ManagedServices service) throws Exception {
         final StringBuffer xml = new StringBuffer();
         xml.append("<" + service.getConfig().xmlTag + ">\n");
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 83c1c76..6222923 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -185,6 +185,9 @@
 
     private NotificationChannel mTestNotificationChannel = new NotificationChannel(
             TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
+
+    private static final int NOTIFICATION_LOCATION_UNKNOWN = 0;
+
     @Mock
     private NotificationListeners mListeners;
     @Mock private NotificationAssistants mAssistants;
@@ -242,8 +245,8 @@
         }
 
         @Override
-        void logSmartSuggestionsVisible(NotificationRecord r) {
-            super.logSmartSuggestionsVisible(r);
+        void logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation) {
+            super.logSmartSuggestionsVisible(r, notificationLocation);
             countLogSmartSuggestionsVisible++;
         }
 
@@ -2528,11 +2531,13 @@
         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         mService.addNotification(r);
 
-        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, true);
+        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, true,
+                NOTIFICATION_LOCATION_UNKNOWN);
         verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.sbn), eq(true), eq((true)));
         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
 
-        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, false);
+        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, false,
+                NOTIFICATION_LOCATION_UNKNOWN);
         verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.sbn), eq(true), eq((false)));
         assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
     }
@@ -2542,11 +2547,13 @@
         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         mService.addNotification(r);
 
-        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true);
+        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true,
+                NOTIFICATION_LOCATION_UNKNOWN);
         assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
         verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.sbn), eq(false), eq((true)));
 
-        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, false);
+        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, false,
+                NOTIFICATION_LOCATION_UNKNOWN);
         assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
         verify(mAssistants).notifyAssistantExpansionChangedLocked(
                 eq(r.sbn), eq(false), eq((false)));
@@ -3511,9 +3518,9 @@
     }
 
     @Test
-    public void testAppOverlay() throws Exception {
-        mBinderService.setAppOverlaysAllowed(PKG, mUid, false);
-        assertFalse(mBinderService.areAppOverlaysAllowedForPackage(PKG, mUid));
+    public void testBubble() throws Exception {
+        mBinderService.setBubblesAllowed(PKG, mUid, false);
+        assertFalse(mBinderService.areBubblesAllowedForPackage(PKG, mUid));
     }
 
     @Test
@@ -3793,7 +3800,8 @@
         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         mService.addNotification(r);
 
-        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true);
+        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true,
+                NOTIFICATION_LOCATION_UNKNOWN);
         NotificationVisibility[] notificationVisibility = new NotificationVisibility[] {
                 NotificationVisibility.obtain(r.getKey(), 0, 0, true)
         };
@@ -3808,7 +3816,8 @@
         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         mService.addNotification(r);
 
-        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true);
+        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true,
+                NOTIFICATION_LOCATION_UNKNOWN);
 
         assertEquals(0, mService.countLogSmartSuggestionsVisible);
     }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 65e640f..b9ae7d5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -56,8 +56,8 @@
 import android.provider.Settings;
 import android.service.notification.Adjustment;
 import android.service.notification.StatusBarNotification;
+import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.R;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -87,14 +87,7 @@
     private final String channelId = "channel";
     private NotificationChannel channel =
             new NotificationChannel(channelId, "test", NotificationManager.IMPORTANCE_DEFAULT);
-    private final String channelIdLong =
-            "give_a_developer_a_string_argument_and_who_knows_what_they_will_pass_in_there";
     private final String groupId = "group";
-    private final String groupIdOverride = "other_group";
-    private final String groupIdLong =
-            "0|com.foo.bar|g:content://com.foo.bar.ui/account%3A-0000000/account/";
-    private NotificationChannel channelLongId =
-            new NotificationChannel(channelIdLong, "long", NotificationManager.IMPORTANCE_DEFAULT);
     private NotificationChannel defaultChannel =
             new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "test",
                     NotificationManager.IMPORTANCE_UNSPECIFIED);
@@ -408,73 +401,27 @@
     }
 
     @Test
-    public void testLogmakerShortChannel() {
+    public void testLogMaker() {
+        long timestamp = 1000L;
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
-        final LogMaker logMaker = record.getLogMaker();
+        final LogMaker logMaker = record.getLogMaker(timestamp);
+
+        assertNull(logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX));
         assertEquals(channelId,
                 (String) logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID));
         assertEquals(channel.getImportance(),
                 logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE));
-    }
-
-    @Test
-    public void testLogmakerLongChannel() {
-        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
-        true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
-        false /* lights */, false /*defaultLights */, null /* group */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channelLongId);
-        final String loggedId = (String)
-            record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID);
-        assertEquals(channelIdLong.substring(0,10), loggedId.substring(0, 10));
-    }
-
-    @Test
-    public void testLogmakerNoGroup() {
-        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
-                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
-                false /* lights */, false /*defaultLights */, null /* group */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
-        assertNull(record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
-    }
-
-    @Test
-    public void testLogmakerShortGroup() {
-        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
-                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
-                false /* lights */, false /* defaultLights */, groupId /* group */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
-        assertEquals(groupId,
-                record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
-    }
-
-    @Test
-    public void testLogmakerLongGroup() {
-        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
-                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
-                false /* lights */, false /* defaultLights */, groupIdLong /* group */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
-        final String loggedId = (String)
-                record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID);
-        assertEquals(groupIdLong.substring(0,10), loggedId.substring(0, 10));
-    }
-
-    @Test
-    public void testLogmakerOverrideGroup() {
-        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
-                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
-                false /* lights */, false /* defaultLights */, groupId /* group */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
-        assertEquals(groupId,
-                record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
-        record.setOverrideGroupKey(groupIdOverride);
-        assertEquals(groupIdOverride,
-                record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
-        record.setOverrideGroupKey(null);
-        assertEquals(groupId,
-                record.getLogMaker().getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
+        assertEquals(record.getLifespanMs(timestamp),
+                (int) logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS));
+        assertEquals(record.getFreshnessMs(timestamp),
+                (int) logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS));
+        assertEquals(record.getExposureMs(timestamp),
+                (int) logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS));
+        assertEquals(record.getInterruptionMs(timestamp),
+                (int) logMaker.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS));
     }
 
     @Test
@@ -825,4 +772,72 @@
 
         assertNotEquals(-1, record.getLastAudiblyAlertedMs());
     }
+
+    @Test
+    public void testIsNewEnoughForAlerting_new() {
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, groupId /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertTrue(record.isNewEnoughForAlerting(record.mUpdateTimeMs));
+    }
+
+    @Test
+    public void testIsNewEnoughForAlerting_old() {
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, groupId /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertFalse(record.isNewEnoughForAlerting(record.mUpdateTimeMs + (1000 * 60 * 60)));
+    }
+
+    @Test
+    public void testIgnoreImportanceAdjustmentsForOemLockedChannels() {
+        NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+        channel.setImportanceLockedByOEM(true);
+
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, groupId /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
+
+        Bundle bundle = new Bundle();
+        bundle.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW);
+        Adjustment adjustment = new Adjustment(
+                PKG_O, record.getKey(), bundle, "", record.getUserId());
+
+        record.addAdjustment(adjustment);
+        record.applyAdjustments();
+        record.calculateImportance();
+
+        assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
+    }
+
+    @Test
+    public void testApplyImportanceAdjustmentsForNonOemLockedChannels() {
+        NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+        channel.setImportanceLockedByOEM(false);
+
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, groupId /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
+
+        Bundle bundle = new Bundle();
+        bundle.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW);
+        Adjustment adjustment = new Adjustment(
+                PKG_O, record.getKey(), bundle, "", record.getUserId());
+
+        record.addAdjustment(adjustment);
+        record.applyAdjustments();
+        record.calculateImportance();
+
+        assertEquals(IMPORTANCE_LOW, record.getImportance());
+    }
 }
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 0b73481..24a1f8c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -809,7 +809,7 @@
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
         channel.setShowBadge(true);
-        channel.setAllowAppOverlay(false);
+        channel.setAllowBubbles(false);
         int lockMask = 0;
         for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
             lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
@@ -826,7 +826,7 @@
         assertFalse(savedChannel.canBypassDnd());
         assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
         assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
-        assertEquals(channel.canOverlayApps(), savedChannel.canOverlayApps());
+        assertEquals(channel.canBubble(), savedChannel.canBubble());
 
         verify(mHandler, never()).requestSort();
     }
@@ -840,7 +840,7 @@
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
         channel.setShowBadge(true);
-        channel.setAllowAppOverlay(false);
+        channel.setAllowBubbles(false);
         int lockMask = 0;
         for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
             lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
@@ -857,7 +857,7 @@
         assertFalse(savedChannel.canBypassDnd());
         assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
         assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
-        assertEquals(channel.canOverlayApps(), savedChannel.canOverlayApps());
+        assertEquals(channel.canBubble(), savedChannel.canBubble());
     }
 
     @Test
@@ -969,16 +969,16 @@
     }
 
     @Test
-    public void testLockFields_appOverlay() {
+    public void testLockFields_allowBubble() {
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
         assertEquals(0,
                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false)
                         .getUserLockedFields());
 
         final NotificationChannel update = getChannel();
-        update.setAllowAppOverlay(false);
+        update.setAllowBubbles(false);
         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true);
-        assertEquals(NotificationChannel.USER_LOCKED_ALLOW_APP_OVERLAY,
+        assertEquals(NotificationChannel.USER_LOCKED_ALLOW_BUBBLE,
                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update.getId(), false)
                         .getUserLockedFields());
     }
@@ -2161,30 +2161,147 @@
     }
 
     @Test
-    public void testAllowAppOverlay_defaults() throws Exception {
-        assertTrue(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
+    public void testAllowBubbles_defaults() throws Exception {
+        assertTrue(mHelper.areBubblessAllowed(PKG_O, UID_O));
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
         loadStreamXml(baos, false);
 
-        assertTrue(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
+        assertTrue(mHelper.areBubblessAllowed(PKG_O, UID_O));
         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
     }
 
     @Test
-    public void testAllowAppOverlay_xml() throws Exception {
-        mHelper.setAppOverlaysAllowed(PKG_O, UID_O, false);
-        assertFalse(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
-        assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_APP_OVERLAY,
+    public void testAllowBubbles_xml() throws Exception {
+        mHelper.setBubblesAllowed(PKG_O, UID_O, false);
+        assertFalse(mHelper.areBubblessAllowed(PKG_O, UID_O));
+        assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
                 mHelper.getAppLockedFields(PKG_O, UID_O));
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
         loadStreamXml(baos, false);
 
-        assertFalse(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
-        assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_APP_OVERLAY,
+        assertFalse(mHelper.areBubblessAllowed(PKG_O, UID_O));
+        assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
                 mHelper.getAppLockedFields(PKG_O, UID_O));
     }
+
+    @Test
+    public void testLockChannelsForOEM_emptyList() {
+        mHelper.lockChannelsForOEM(null);
+        mHelper.lockChannelsForOEM(new String[0]);
+        // no exception
+    }
+
+    @Test
+    public void testLockChannelsForOEM_appWide() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
+        // different uids, same package
+        mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
+        mHelper.createNotificationChannel(PKG_O, 3, b, false, false);
+        mHelper.createNotificationChannel(PKG_O, 30, c, true, true);
+
+        mHelper.lockChannelsForOEM(new String[] {PKG_O});
+
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
+                .isImportanceLockedByOEM());
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
+                .isImportanceLockedByOEM());
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 30, c.getId(), false)
+                .isImportanceLockedByOEM());
+    }
+
+    @Test
+    public void testLockChannelsForOEM_onlyGivenPkg() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, 30, b, false, false);
+
+        mHelper.lockChannelsForOEM(new String[] {PKG_O});
+
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
+                .isImportanceLockedByOEM());
+        assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 30, b.getId(), false)
+                .isImportanceLockedByOEM());
+    }
+
+    @Test
+    public void testLockChannelsForOEM_channelSpecific() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
+        // different uids, same package
+        mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
+        mHelper.createNotificationChannel(PKG_O, 3, b, false, false);
+        mHelper.createNotificationChannel(PKG_O, 30, c, true, true);
+
+        mHelper.lockChannelsForOEM(new String[] {PKG_O + ":b", PKG_O + ":c"});
+
+        assertFalse(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
+                .isImportanceLockedByOEM());
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
+                .isImportanceLockedByOEM());
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 30, c.getId(), false)
+                .isImportanceLockedByOEM());
+    }
+
+    @Test
+    public void testLockChannelsForOEM_channelDoesNotExistYet_appWide() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
+
+        mHelper.lockChannelsForOEM(new String[] {PKG_O});
+
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
+                .isImportanceLockedByOEM());
+
+        mHelper.createNotificationChannel(PKG_O, 3, b, true, false);
+        assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
+                .isImportanceLockedByOEM());
+    }
+
+    @Test
+    public void testLockChannelsForOEM_channelDoesNotExistYet_channelSpecific() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+
+        mHelper.lockChannelsForOEM(new String[] {PKG_O + ":a", PKG_O + ":b"});
+
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+                .isImportanceLockedByOEM());
+
+        mHelper.createNotificationChannel(PKG_O, UID_O, b, true, false);
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
+                .isImportanceLockedByOEM());
+    }
+
+    @Test
+    public void testUpdateNotificationChannel_oemLockedImportance() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+
+        mHelper.lockChannelsForOEM(new String[] {PKG_O});
+
+        NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
+        update.setAllowBubbles(false);
+
+        mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
+
+        assertEquals(IMPORTANCE_HIGH,
+                mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
+        assertEquals(false,
+                mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
+
+        mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
+
+        assertEquals(IMPORTANCE_HIGH,
+                mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
index 5638cb36..c79e1db0 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -15,8 +15,11 @@
  */
 package com.android.server.notification;
 
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 
+import static junit.framework.TestCase.assertEquals;
+
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Matchers.anyInt;
@@ -153,7 +156,7 @@
                 .build();
         mRecordGroupGSortA = new NotificationRecord(mContext, new StatusBarNotification(
                 PKG, PKG, 1, null, 0, 0, mNotiGroupGSortA, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
+                null, System.currentTimeMillis()), getLowChannel());
 
         mNotiGroupGSortB = new Notification.Builder(mContext, TEST_CHANNEL_ID)
                 .setContentTitle("B")
@@ -163,7 +166,7 @@
                 .build();
         mRecordGroupGSortB = new NotificationRecord(mContext, new StatusBarNotification(
                 PKG, PKG, 1, null, 0, 0, mNotiGroupGSortB, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
+                null, System.currentTimeMillis()), getLowChannel());
 
         mNotiNoGroup = new Notification.Builder(mContext, TEST_CHANNEL_ID)
                 .setContentTitle("C")
@@ -171,7 +174,7 @@
                 .build();
         mRecordNoGroup = new NotificationRecord(mContext, new StatusBarNotification(
                 PKG, PKG, 1, null, 0, 0, mNotiNoGroup, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
+                null, System.currentTimeMillis()), getLowChannel());
 
         mNotiNoGroup2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
                 .setContentTitle("D")
@@ -179,7 +182,7 @@
                 .build();
         mRecordNoGroup2 = new NotificationRecord(mContext, new StatusBarNotification(
                 PKG, PKG, 1, null, 0, 0, mNotiNoGroup2, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
+                null, System.currentTimeMillis()), getLowChannel());
 
         mNotiNoGroupSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID)
                 .setContentTitle("E")
@@ -188,7 +191,7 @@
                 .build();
         mRecordNoGroupSortA = new NotificationRecord(mContext, new StatusBarNotification(
                 PKG, PKG, 1, null, 0, 0, mNotiNoGroupSortA, user,
-                null, System.currentTimeMillis()), getDefaultChannel());
+                null, System.currentTimeMillis()), getLowChannel());
 
         mAudioAttributes = new AudioAttributes.Builder()
                 .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
@@ -197,11 +200,16 @@
                 .build();
     }
 
-    private NotificationChannel getDefaultChannel() {
+    private NotificationChannel getLowChannel() {
         return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
                 IMPORTANCE_LOW);
     }
 
+    private NotificationChannel getDefaultChannel() {
+        return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
+                IMPORTANCE_DEFAULT);
+    }
+
     @Test
     public void testSortShouldRespectCritical() throws Exception {
         ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(7);
@@ -285,4 +293,40 @@
         ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>();
         mHelper.sort(notificationList);
     }
+    
+    @Test
+    public void testGroupNotifications_highestIsProxy() {
+        ArrayList<NotificationRecord> notificationList = new ArrayList<>();
+        // this should be the last in the list, except it's in a group with a high child
+        Notification lowSummaryN = new Notification.Builder(mContext, "")
+                .setGroup("group")
+                .setGroupSummary(true)
+                .build();
+        NotificationRecord lowSummary = new NotificationRecord(mContext, new StatusBarNotification(
+                PKG, PKG, 1, "summary", 0, 0, lowSummaryN, USER,
+                null, System.currentTimeMillis()), getLowChannel());
+        notificationList.add(lowSummary);
+
+        Notification lowN = new Notification.Builder(mContext, "").build();
+        NotificationRecord low = new NotificationRecord(mContext, new StatusBarNotification(
+                PKG, PKG, 1, "low", 0, 0, lowN, USER,
+                null, System.currentTimeMillis()), getLowChannel());
+        low.setContactAffinity(0.5f);
+        notificationList.add(low);
+
+        Notification highChildN = new Notification.Builder(mContext, "")
+                .setGroup("group")
+                .setGroupSummary(false)
+                .build();
+        NotificationRecord highChild = new NotificationRecord(mContext, new StatusBarNotification(
+                PKG, PKG, 1, "child", 0, 0, highChildN, USER,
+                null, System.currentTimeMillis()), getDefaultChannel());
+        notificationList.add(highChild);
+
+        mHelper.sort(notificationList);
+
+        assertEquals(lowSummary, notificationList.get(0));
+        assertEquals(highChild, notificationList.get(1));
+        assertEquals(low, notificationList.get(2));
+    }
 }
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 49f134f..174c5fa 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -299,6 +299,59 @@
         assertEquals(1, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size());
     }
 
+    @Test
+    public void testClearData() {
+        // snooze 2 from same package
+        NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+        NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
+        mSnoozeHelper.snooze(r, 1000);
+        mSnoozeHelper.snooze(r2, 1000);
+        assertTrue(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+        assertTrue(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey()));
+
+        // clear data
+        mSnoozeHelper.clearData(UserHandle.USER_SYSTEM, "pkg");
+
+        // nothing snoozed; alarms canceled
+        assertFalse(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+        assertFalse(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey()));
+        // twice for initial snooze, twice for canceling the snooze
+        verify(mAm, times(4)).cancel(any(PendingIntent.class));
+    }
+
+    @Test
+    public void testClearData_otherRecordsUntouched() {
+        // 2 packages, 2 users
+        NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+        NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.ALL);
+        NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
+        mSnoozeHelper.snooze(r, 1000);
+        mSnoozeHelper.snooze(r2, 1000);
+        mSnoozeHelper.snooze(r3, 1000);
+        assertTrue(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+        assertTrue(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_ALL, r2.sbn.getPackageName(), r2.getKey()));
+        assertTrue(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r3.sbn.getPackageName(), r3.getKey()));
+
+        // clear data
+        mSnoozeHelper.clearData(UserHandle.USER_SYSTEM, "pkg");
+
+        assertFalse(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+        assertTrue(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_ALL, r2.sbn.getPackageName(), r2.getKey()));
+        assertTrue(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r3.sbn.getPackageName(), r3.getKey()));
+        // once for each initial snooze, once for canceling one snooze
+        verify(mAm, times(4)).cancel(any(PendingIntent.class));
+    }
+
     private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
             UserHandle user, String groupKey, boolean groupSummary) {
         Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
index b315e51..efefee1 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
@@ -16,6 +16,7 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.content.ContentProvider;
 import android.content.ContentResolver;
@@ -26,6 +27,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
+import android.util.Log;
 import android.util.Xml.Encoding;
 
 import com.android.server.UiServiceTestCase;
@@ -46,10 +48,12 @@
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 public class SlicePermissionManagerTest extends UiServiceTestCase {
+    private static final String TAG = "SlicePerManTest";
 
     @Test
     public void testGrant() {
-        File sliceDir = new File(mContext.getDataDir(), "system/slices");
+        File sliceDir = new File(mContext.getCacheDir(), "testGrantSlices");
+        Log.v(TAG, "testGrant: slice permissions stored in " + sliceDir.getAbsolutePath());
         SlicePermissionManager permissions = new SlicePermissionManager(mContext,
                 TestableLooper.get(this).getLooper(), sliceDir);
         Uri uri = new Builder().scheme(ContentResolver.SCHEME_CONTENT)
@@ -59,11 +63,15 @@
         permissions.grantSliceAccess("my.pkg", 0, "provider.pkg", 0, uri);
 
         assertTrue(permissions.hasPermission("my.pkg", 0, uri));
+
+        // Cleanup.
+        assertTrue(FileUtils.deleteContentsAndDir(sliceDir));
     }
 
     @Test
     public void testBackup() throws XmlPullParserException, IOException {
-        File sliceDir = new File(mContext.getDataDir(), "system/slices");
+        File sliceDir = new File(mContext.getCacheDir(), "testBackupSlices");
+        Log.v(TAG, "testBackup: slice permissions stored in " + sliceDir.getAbsolutePath());
         Uri uri = new Builder().scheme(ContentResolver.SCHEME_CONTENT)
                 .authority("authority")
                 .path("something").build();
@@ -90,7 +98,10 @@
                 TestableLooper.get(this).getLooper());
         permissions.readRestore(parser);
 
-        assertTrue(permissions.hasFullAccess("com.android.mypkg", 10));
+        if (!permissions.hasFullAccess("com.android.mypkg", 10)) {
+            fail("com.android.mypkg@10 did not have full access. backup file: "
+                    + output.toString());
+        }
         assertTrue(permissions.hasPermission("com.android.otherpkg", 0,
                 ContentProvider.maybeAddUserId(uri, 1)));
         permissions.removePkg("com.android.lastpkg", 1);
@@ -102,8 +113,9 @@
     }
 
     @Test
-    public void testInvalid() throws Exception {
-        File sliceDir = new File(mContext.getCacheDir(), "slices-test");
+    public void testInvalid() {
+        File sliceDir = new File(mContext.getCacheDir(), "testInvalidSlices");
+        Log.v(TAG, "testInvalid: slice permissions stored in " + sliceDir.getAbsolutePath());
         if (!sliceDir.exists()) {
             sliceDir.mkdir();
         }
@@ -118,7 +130,8 @@
 
             @Override
             public void writeTo(XmlSerializer out) throws IOException {
-                throw new RuntimeException("this doesn't work");
+                throw new RuntimeException("this RuntimeException inside junk.writeTo() "
+                        + "should be caught and suppressed by surrounding code");
             }
         };
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 5bf3d2d..56f4a85 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -36,6 +36,9 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 
 import android.platform.test.annotations.Presubmit;
 
@@ -54,11 +57,6 @@
 @Presubmit
 public class ActivityDisplayTests extends ActivityTestsBase {
 
-    @Before
-    public void setUp() throws Exception {
-        setupActivityTaskManagerService();
-    }
-
     @Test
     public void testLastFocusedStackIsUpdatedWhenMovingStack() {
         // Create a stack at bottom.
@@ -277,4 +275,60 @@
         assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
         assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 1));
     }
+
+    @Test
+    public void testRemoveStackInWindowingModes() {
+        removeStackTests(() -> mRootActivityContainer.removeStacksInWindowingModes(
+                WINDOWING_MODE_FULLSCREEN));
+    }
+
+    @Test
+    public void testRemoveStackWithActivityTypes() {
+        removeStackTests(
+                () -> mRootActivityContainer.removeStacksWithActivityTypes(ACTIVITY_TYPE_STANDARD));
+    }
+
+    private void removeStackTests(Runnable runnable) {
+        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
+        final ActivityStack stack1 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, ON_TOP);
+        final ActivityStack stack2 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, ON_TOP);
+        final ActivityStack stack3 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, ON_TOP);
+        final ActivityStack stack4 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+                ACTIVITY_TYPE_STANDARD, ON_TOP);
+        final TaskRecord task1 = new TaskBuilder(mService.mStackSupervisor).setStack(
+                stack1).setTaskId(1).build();
+        final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(
+                stack2).setTaskId(2).build();
+        final TaskRecord task3 = new TaskBuilder(mService.mStackSupervisor).setStack(
+                stack3).setTaskId(3).build();
+        final TaskRecord task4 = new TaskBuilder(mService.mStackSupervisor).setStack(
+                stack4).setTaskId(4).build();
+
+        // Reordering stacks while removing stacks.
+        doAnswer(invocation -> {
+            display.positionChildAtTop(stack3, false);
+            return true;
+        }).when(mSupervisor).removeTaskByIdLocked(eq(task4.taskId), anyBoolean(), anyBoolean(),
+                any());
+
+        // Removing stacks from the display while removing stacks.
+        doAnswer(invocation -> {
+            display.removeChild(stack2);
+            return true;
+        }).when(mSupervisor).removeTaskByIdLocked(eq(task2.taskId), anyBoolean(), anyBoolean(),
+                any());
+
+        runnable.run();
+        verify(mSupervisor).removeTaskByIdLocked(eq(task4.taskId), anyBoolean(), anyBoolean(),
+                any());
+        verify(mSupervisor).removeTaskByIdLocked(eq(task3.taskId), anyBoolean(), anyBoolean(),
+                any());
+        verify(mSupervisor).removeTaskByIdLocked(eq(task2.taskId), anyBoolean(), anyBoolean(),
+                any());
+        verify(mSupervisor).removeTaskByIdLocked(eq(task1.taskId), anyBoolean(), anyBoolean(),
+                any());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index cac9cf6..ee22861 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -70,8 +70,6 @@
 
     @Before
     public void setUpAMLO() throws Exception {
-        setupActivityTaskManagerService();
-
         mLaunchObserver = mock(ActivityMetricsLaunchObserver.class);
 
         // ActivityStackSupervisor always creates its own instance of ActivityMetricsLogger.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index b6f1817..8be63fc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -19,7 +19,12 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
@@ -36,10 +41,14 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.ActivityOptions;
+import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.PauseActivityItem;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
+import android.util.MergedConfiguration;
 import android.util.MutableBoolean;
 
 import androidx.test.filters.MediumTest;
@@ -63,8 +72,7 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
-        mStack = new StackBuilder(mRootActivityContainer).build();
+        mStack = (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
         mTask = mStack.getChildAt(0);
         mActivity = mTask.getTopActivity();
     }
@@ -210,4 +218,149 @@
         assertNull(mActivity.pendingOptions);
         assertNotNull(activity2.pendingOptions);
     }
+
+    @Test
+    public void testNewOverrideConfigurationIncrementsSeq() {
+        final Configuration newConfig = new Configuration();
+
+        final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
+        mActivity.onRequestedOverrideConfigurationChanged(newConfig);
+        assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
+    }
+
+    @Test
+    public void testNewParentConfigurationIncrementsSeq() {
+        final Configuration newConfig = new Configuration(
+                mTask.getRequestedOverrideConfiguration());
+        newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
+                ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+
+        final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
+        mTask.onRequestedOverrideConfigurationChanged(newConfig);
+        assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
+    }
+
+    @Test
+    public void testNotifiesSeqIncrementToAppToken() {
+        final Configuration appWindowTokenRequestedOrientation = mock(Configuration.class);
+        mActivity.mAppWindowToken = mock(AppWindowToken.class);
+        doReturn(appWindowTokenRequestedOrientation).when(mActivity.mAppWindowToken)
+                .getRequestedOverrideConfiguration();
+
+        final Configuration newConfig = new Configuration();
+        newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
+
+        final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
+        mActivity.onRequestedOverrideConfigurationChanged(newConfig);
+        assertEquals(prevSeq + 1, appWindowTokenRequestedOrientation.seq);
+        verify(mActivity.mAppWindowToken).onMergedOverrideConfigurationChanged();
+    }
+
+    @Test
+    public void testSetsRelaunchReason_NotDragResizing() {
+        mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
+
+        mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
+        mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
+                mActivity.getConfiguration()));
+
+        mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION;
+        final Configuration newConfig = new Configuration(mTask.getConfiguration());
+        newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
+                ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+        mTask.onRequestedOverrideConfigurationChanged(newConfig);
+
+        mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+
+        mActivity.ensureActivityConfiguration(0, false, false);
+
+        assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
+                mActivity.mRelaunchReason);
+    }
+
+    @Test
+    public void testSetsRelaunchReason_DragResizing() {
+        mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
+
+        mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
+        mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
+                mActivity.getConfiguration()));
+
+        mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION;
+        final Configuration newConfig = new Configuration(mTask.getConfiguration());
+        newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
+                ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
+        mTask.onRequestedOverrideConfigurationChanged(newConfig);
+
+        doReturn(true).when(mTask.getTask()).isDragResizing();
+
+        mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+
+        mActivity.ensureActivityConfiguration(0, false, false);
+
+        assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
+                mActivity.mRelaunchReason);
+    }
+
+    @Test
+    public void testSetsRelaunchReason_NonResizeConfigChanges() {
+        mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
+
+        mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
+        mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
+                mActivity.getConfiguration()));
+
+        mActivity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE;
+        final Configuration newConfig = new Configuration(mTask.getConfiguration());
+        newConfig.fontScale = 5;
+        mTask.onRequestedOverrideConfigurationChanged(newConfig);
+
+        mActivity.mRelaunchReason =
+                ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+
+        mActivity.ensureActivityConfiguration(0, false, false);
+
+        assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
+                mActivity.mRelaunchReason);
+    }
+
+    @Test
+    public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
+        mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
+
+        mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
+        mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
+                mActivity.getConfiguration()));
+
+        mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION;
+        final Configuration newConfig = new Configuration(mActivity.getConfiguration());
+        newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
+                ? Configuration.ORIENTATION_LANDSCAPE
+                : Configuration.ORIENTATION_PORTRAIT;
+
+        // Mimic the behavior that display doesn't handle app's requested orientation.
+        doAnswer(invocation -> {
+            mTask.onConfigurationChanged(newConfig);
+            return null;
+        }).when(mActivity.mAppWindowToken).setOrientation(anyInt(), any(), any());
+
+        final int requestedOrientation;
+        switch (newConfig.orientation) {
+            case Configuration.ORIENTATION_LANDSCAPE:
+                requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+                break;
+            case Configuration.ORIENTATION_PORTRAIT:
+                requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+                break;
+            default:
+                throw new IllegalStateException("Orientation in new config should be either"
+                        + "landscape or portrait.");
+        }
+        mActivity.setRequestedOrientation(requestedOrientation);
+
+        final ActivityConfigurationChangeItem expected =
+                ActivityConfigurationChangeItem.obtain(newConfig);
+        verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
+                eq(mActivity.appToken), eq(expected));
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index f7b5d26..59e71c4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -64,7 +64,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mFullscreenStack = mRootActivityContainer.getDefaultDisplay().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index b2a2869..35c1ede 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -36,6 +36,8 @@
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
+import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
+import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -73,7 +75,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mDefaultDisplay = mRootActivityContainer.getDefaultDisplay();
         mStack = spy(mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */));
@@ -264,13 +265,13 @@
 
         // Do not move display to back because there is still another stack.
         stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.topTask());
-        verify(stack2.getWindowContainerController()).positionChildAtBottom(any(),
+        verify(stack2.getTaskStack()).positionChildAtBottom(any(),
                 eq(false) /* includingParents */);
 
         // Also move display to back because there is only one stack left.
         display.removeChild(stack1);
         stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.topTask());
-        verify(stack2.getWindowContainerController()).positionChildAtBottom(any(),
+        verify(stack2.getTaskStack()).positionChildAtBottom(any(),
                 eq(true) /* includingParents */);
     }
 
@@ -687,6 +688,62 @@
     }
 
     @Test
+    public void testHandleAppDied_RelaunchesAfterCrashDuringWindowingModeResize() {
+        final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+
+        activity.mRelaunchReason = RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+        activity.launchCount = 1;
+        activity.haveState = false;
+
+        mStack.handleAppDiedLocked(activity.app);
+
+        assertEquals(1, mTask.mActivities.size());
+        assertEquals(1, mStack.getAllTasks().size());
+    }
+
+    @Test
+    public void testHandleAppDied_NotRelaunchAfterThreeCrashesDuringWindowingModeResize() {
+        final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+
+        activity.mRelaunchReason = RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+        activity.launchCount = 3;
+        activity.haveState = false;
+
+        mStack.handleAppDiedLocked(activity.app);
+
+        assertThat(mTask.mActivities).isEmpty();
+        assertThat(mStack.getAllTasks()).isEmpty();
+    }
+
+    @Test
+    public void testHandleAppDied_RelaunchesAfterCrashDuringFreeResize() {
+        final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+
+        activity.mRelaunchReason = RELAUNCH_REASON_FREE_RESIZE;
+        activity.launchCount = 1;
+        activity.haveState = false;
+
+        mStack.handleAppDiedLocked(activity.app);
+
+        assertEquals(1, mTask.mActivities.size());
+        assertEquals(1, mStack.getAllTasks().size());
+    }
+
+    @Test
+    public void testHandleAppDied_NotRelaunchAfterThreeCrashesDuringFreeResize() {
+        final ActivityRecord activity = new ActivityBuilder(mService).setTask(mTask).build();
+
+        activity.mRelaunchReason = RELAUNCH_REASON_FREE_RESIZE;
+        activity.launchCount = 3;
+        activity.haveState = false;
+
+        mStack.handleAppDiedLocked(activity.app);
+
+        assertThat(mTask.mActivities).isEmpty();
+        assertThat(mStack.getAllTasks()).isEmpty();
+    }
+
+    @Test
     public void testFinishCurrentActivity() {
         // Create 2 activities on a new display.
         final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
index 2ba2fdb..96db38b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
@@ -56,7 +56,6 @@
 
     @Before
     public void setUp() throws Exception {
-        mService = createActivityTaskManagerService();
         mFactory = mock(Factory.class);
         mController = new ActivityStartController(mService, mService.mStackSupervisor, mFactory);
         mStarter = spy(new ActivityStarter(mController, mService,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 61e968d..a381023 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -117,7 +117,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mController = mock(ActivityStartController.class);
         mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
         clearInvocations(mActivityMetricsLogger);
@@ -143,7 +142,7 @@
                 .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
                         WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */))
                 .build();
-        assertThat((Object) task2.getStack()).isInstanceOf(PinnedActivityStack.class);
+        assertThat((Object) task2.getStack()).isInstanceOf(ActivityStack.class);
         mStarter.updateBounds(task2, bounds);
 
         verify(mService, times(1)).resizeStack(eq(task2.getStack().mStackId),
@@ -565,7 +564,7 @@
         runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
                 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
                 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
-                false, false);
+                false, false, false);
     }
 
     /**
@@ -580,7 +579,7 @@
                 "disallowed_unsupportedUsecase_aborted", true,
                 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
                 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
-                false, false);
+                false, false, false);
     }
 
     /**
@@ -595,52 +594,58 @@
         runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
                 Process.ROOT_UID, false, PROCESS_STATE_TOP + 1,
                 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
-                false, false);
+                false, false, false);
         runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false,
                 Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1,
                 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
-                false, false);
+                false, false, false);
         runAndVerifyBackgroundActivityStartsSubtest(
                 "disallowed_callingUidHasVisibleWindow_notAborted", false,
                 UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1,
                 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
-                false, false);
+                false, false, false);
         runAndVerifyBackgroundActivityStartsSubtest(
                 "disallowed_callingUidProcessStateTop_notAborted", false,
                 UNIMPORTANT_UID, false, PROCESS_STATE_TOP,
                 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
-                false, false);
+                false, false, false);
         runAndVerifyBackgroundActivityStartsSubtest(
                 "disallowed_realCallingUidHasVisibleWindow_notAborted", false,
                 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
                 UNIMPORTANT_UID2, true, PROCESS_STATE_TOP + 1,
-                false, false);
+                false, false, false);
         runAndVerifyBackgroundActivityStartsSubtest(
                 "disallowed_realCallingUidProcessStateTop_notAborted", false,
                 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
                 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP,
-                false, false);
+                false, false, false);
         runAndVerifyBackgroundActivityStartsSubtest(
                 "disallowed_hasForegroundActivities_notAborted", false,
                 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
                 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
-                true, false);
+                true, false, false);
         runAndVerifyBackgroundActivityStartsSubtest(
                 "disallowed_callerIsRecents_notAborted", false,
                 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
                 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
-                false, true);
+                false, true, false);
+        runAndVerifyBackgroundActivityStartsSubtest(
+                "disallowed_callerIsWhitelisted_notAborted", false,
+                UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
+                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+                false, false, true);
     }
 
     private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
             int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
             int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
-            boolean hasForegroundActivities, boolean callerIsRecents) {
+            boolean hasForegroundActivities, boolean callerIsRecents,
+            boolean callerIsTempWhitelisted) {
         // window visibility
-        doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager).isAnyWindowVisibleForUid(
-                callingUid);
-        doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager)
-                .isAnyWindowVisibleForUid(realCallingUid);
+        doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
+                .isAnyNonToastWindowVisibleForUid(callingUid);
+        doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
+                .isAnyNonToastWindowVisibleForUid(realCallingUid);
         // process importance
         doReturn(callingUidProcState).when(mService).getUidStateLocked(callingUid);
         doReturn(realCallingUidProcState).when(mService).getUidStateLocked(realCallingUid);
@@ -656,6 +661,8 @@
         RecentTasks recentTasks = mock(RecentTasks.class);
         mService.mStackSupervisor.setRecentTasks(recentTasks);
         doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
+        // caller is temp whitelisted
+        callerApp.setAllowBackgroundActivityStarts(callerIsTempWhitelisted);
 
         final ActivityOptions options = spy(ActivityOptions.makeBasic());
         ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 569c6d4..68df87e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -31,6 +31,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -62,11 +63,11 @@
 import android.view.DisplayInfo;
 
 import com.android.internal.app.IVoiceInteractor;
-import com.android.server.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.ServiceThread;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.PendingIntentController;
+import com.android.server.appop.AppOpsService;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.uri.UriGrantsManagerInternal;
 
@@ -110,22 +111,19 @@
     @Before
     public void setUpBase() {
         mTestInjector.setUp();
+
+        mService = new TestActivityTaskManagerService(mContext);
+        mSupervisor = mService.mStackSupervisor;
+        mRootActivityContainer = mService.mRootActivityContainer;
     }
 
     @After
     public void tearDownBase() {
         mTestInjector.tearDown();
-    }
-
-    ActivityTaskManagerService createActivityTaskManagerService() {
-        mService = new TestActivityTaskManagerService(mContext);
-        mSupervisor = mService.mStackSupervisor;
-        mRootActivityContainer = mService.mRootActivityContainer;
-        return mService;
-    }
-
-    void setupActivityTaskManagerService() {
-        createActivityTaskManagerService();
+        if (mService != null) {
+            mService.setWindowManager(null);
+            mService = null;
+        }
     }
 
     /** Creates a {@link TestActivityDisplay}. */
@@ -144,6 +142,13 @@
         return display;
     }
 
+    /** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */
+    TestActivityDisplay addNewActivityDisplayAt(DisplayInfo info, int position) {
+        final TestActivityDisplay display = createNewActivityDisplay(info);
+        mRootActivityContainer.addChild(display, position);
+        return display;
+    }
+
     /**
      * Builder for creating new activities.
      */
@@ -154,6 +159,7 @@
         private final ActivityTaskManagerService mService;
 
         private ComponentName mComponent;
+        private String mTargetActivity;
         private TaskRecord mTaskRecord;
         private int mUid;
         private boolean mCreateTask;
@@ -170,6 +176,11 @@
             return this;
         }
 
+        ActivityBuilder setTargetActivity(String targetActivity) {
+            mTargetActivity = targetActivity;
+            return this;
+        }
+
         static ComponentName getDefaultComponent() {
             return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
                     DEFAULT_COMPONENT_PACKAGE_NAME);
@@ -224,6 +235,10 @@
             aInfo.applicationInfo = new ApplicationInfo();
             aInfo.applicationInfo.packageName = mComponent.getPackageName();
             aInfo.applicationInfo.uid = mUid;
+            aInfo.packageName = mComponent.getPackageName();
+            if (mTargetActivity != null) {
+                aInfo.targetActivity = mTargetActivity;
+            }
             aInfo.flags |= mActivityFlags;
             aInfo.launchMode = mLaunchMode;
 
@@ -234,7 +249,13 @@
                     mService.mStackSupervisor, null /* options */, null /* sourceRecord */);
             spyOn(activity);
             activity.mAppWindowToken = mock(AppWindowToken.class);
+            doCallRealMethod().when(activity.mAppWindowToken).getOrientationIgnoreVisibility();
+            doCallRealMethod().when(activity.mAppWindowToken)
+                    .setOrientation(anyInt(), any(), any());
+            doCallRealMethod().when(activity.mAppWindowToken).setOrientation(anyInt());
             doNothing().when(activity).removeWindowContainer();
+            doReturn(mock(Configuration.class)).when(activity.mAppWindowToken)
+                    .getRequestedOverrideConfiguration();
 
             if (mTaskRecord != null) {
                 mTaskRecord.addActivityToTop(activity);
@@ -346,6 +367,7 @@
                 mStack.addTask(task, true, "creating test task");
                 task.setStack(mStack);
                 task.setTask();
+                mStack.getTaskStack().addChild(task.mTask, 0);
             }
 
             task.touchActiveTime();
@@ -365,7 +387,10 @@
                 setTask();
             }
 
-            private void setTask() {
+            void setTask() {
+                Task mockTask = mock(Task.class);
+                mockTask.mTaskRecord = this;
+                doCallRealMethod().when(mockTask).onDescendantOrientationChanged(any(), any());
                 setTask(mock(Task.class));
             }
         }
@@ -597,7 +622,7 @@
 
         @SuppressWarnings("TypeParameterUnusedInFormals")
         @Override
-        <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
+        ActivityStack createStackUnchecked(int windowingMode, int activityType,
                 int stackId, boolean onTop) {
             return new StackBuilder(mSupervisor.mRootActivityContainer).setDisplay(this)
                     .setWindowingMode(windowingMode).setActivityType(activityType)
@@ -619,7 +644,13 @@
         }
     }
 
+    private static WindowManagerService sMockWindowManagerService;
+
     private static WindowManagerService prepareMockWindowManager() {
+        if (sMockWindowManagerService != null) {
+            return sMockWindowManagerService;
+        }
+
         final WindowManagerService service = mock(WindowManagerService.class);
         service.mRoot = mock(RootWindowContainer.class);
 
@@ -631,6 +662,7 @@
             return null;
         }).when(service).inSurfaceTransaction(any());
 
+        sMockWindowManagerService = service;
         return service;
     }
 
@@ -639,10 +671,9 @@
      * method is called. Note that its functionality depends on the implementations of the
      * construction arguments.
      */
-    protected static class TestActivityStack<T extends StackWindowController>
-            extends ActivityStack<T> {
+    protected static class TestActivityStack
+            extends ActivityStack {
         private int mOnActivityRemovedFromStackCount = 0;
-        private T mContainerController;
 
         static final int IS_TRANSLUCENT_UNSET = 0;
         static final int IS_TRANSLUCENT_FALSE = 1;
@@ -682,20 +713,20 @@
         }
 
         @Override
-        protected T createStackWindowController(int displayId, boolean onTop, Rect outBounds) {
-            mContainerController = (T) WindowTestUtils.createMockStackWindowContainerController();
+        protected void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
+            mTaskStack = WindowTestUtils.createMockTaskStack();
 
             // Primary pinned stacks require a non-empty out bounds to be set or else all tasks
             // will be moved to the full screen stack.
             if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                 outBounds.set(0, 0, 100, 100);
             }
-            return mContainerController;
+
         }
 
         @Override
-        T getWindowContainerController() {
-            return mContainerController;
+        TaskStack getTaskStack() {
+            return mTaskStack;
         }
 
         void setIsTranslucent(boolean isTranslucent) {
@@ -785,27 +816,23 @@
         }
 
         @SuppressWarnings("TypeParameterUnusedInFormals")
-        <T extends ActivityStack> T build() {
+        ActivityStack build() {
             final int stackId = mStackId >= 0 ? mStackId : mDisplay.getNextStackId();
             if (mWindowingMode == WINDOWING_MODE_PINNED) {
-                return (T) new PinnedActivityStack(mDisplay, stackId,
-                        mRootActivityContainer.mStackSupervisor, mOnTop) {
+                return new ActivityStack(mDisplay, stackId, mRootActivityContainer.mStackSupervisor,
+                        mWindowingMode, ACTIVITY_TYPE_STANDARD, mOnTop) {
                     @Override
                     Rect getDefaultPictureInPictureBounds(float aspectRatio) {
                         return new Rect(50, 50, 100, 100);
                     }
 
                     @Override
-                    PinnedStackWindowController createStackWindowController(int displayId,
-                            boolean onTop, Rect outBounds) {
-                        PinnedStackWindowController controller =
-                                mock(PinnedStackWindowController.class);
-                        controller.mContainer = mock(TaskStack.class);
-                        return controller;
+                    void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
+                        mTaskStack = mock(TaskStack.class);
                     }
                 };
             } else {
-                return (T) new TestActivityStack(mDisplay, stackId,
+                return new TestActivityStack(mDisplay, stackId,
                         mRootActivityContainer.mStackSupervisor, mWindowingMode,
                         mActivityType, mOnTop, mCreateActivity);
             }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index fa42289..123de2d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -39,7 +39,9 @@
 
 import androidx.test.filters.SmallTest;
 
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 /**
@@ -52,15 +54,34 @@
 @Presubmit
 public class AppTransitionTests extends WindowTestsBase {
 
+    private static RootWindowContainer sOriginalRootWindowContainer;
+
     private DisplayContent mDc;
 
+    @BeforeClass
+    public static void setUpRootWindowContainerMock() {
+        final WindowManagerService wm = TestSystemServices.getWindowManagerService();
+        // For unit test, we don't need to test performSurfacePlacement to prevent some abnormal
+        // interaction with surfaceflinger native side.
+        sOriginalRootWindowContainer = wm.mRoot;
+        // Creating spied mock of RootWindowContainer shouldn't be done in @Before, since it will
+        // create unnecessary nested spied objects chain, because WindowManagerService object under
+        // test is a single instance shared among all tests that extend WindowTestsBase class.
+        // Instead it should be done once before running all tests in this test class.
+        wm.mRoot = spy(wm.mRoot);
+        doNothing().when(wm.mRoot).performSurfacePlacement(anyBoolean());
+    }
+
+    @AfterClass
+    public static void tearDownRootWindowContainerMock() {
+        final WindowManagerService wm = TestSystemServices.getWindowManagerService();
+        wm.mRoot = sOriginalRootWindowContainer;
+        sOriginalRootWindowContainer = null;
+    }
+
     @Before
     public void setUp() throws Exception {
         mDc = mWm.getDefaultDisplayContentLocked();
-        // For unit test,  we don't need to test performSurfacePlacement to prevent some
-        // abnormal interaction with surfaceflinger native side.
-        mWm.mRoot = spy(mWm.mRoot);
-        doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
     }
 
     @Test
@@ -160,7 +181,7 @@
         assertTrue(dc1.mOpeningApps.size() > 0);
 
         // Move stack to another display.
-        stack1.getController().reparent(dc2.getDisplayId(),  new Rect(), true);
+        stack1.reparent(dc2.getDisplayId(),  new Rect(), true);
 
         // Verify if token are cleared from both pending transition list in former display.
         assertFalse(dc1.mOpeningApps.contains(token1));
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index dcfb879..ea5ab7b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -70,9 +70,9 @@
 
         mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
         verify(mTransaction).reparent(eq(mToken.getSurfaceControl()),
-                eq(mToken.mSurfaceAnimator.mLeash.getHandle()));
+                eq(mToken.mSurfaceAnimator.mLeash));
         verify(mTransaction).reparent(eq(mToken.mSurfaceAnimator.mLeash),
-                eq(mToken.mAnimationBoundsLayer.getHandle()));
+                eq(mToken.mAnimationBoundsLayer));
     }
 
     @Test
@@ -87,8 +87,8 @@
         verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
 
         callbackCaptor.getValue().onAnimationFinished(mSpec);
-        verify(mTransaction).destroy(eq(leash));
-        verify(mTransaction).destroy(eq(animationBoundsLayer));
+        verify(mTransaction).reparent(eq(leash), eq(null));
+        verify(mTransaction).reparent(eq(animationBoundsLayer), eq(null));
         assertThat(mToken.mNeedsAnimationBoundsLayer).isFalse();
     }
 
@@ -100,8 +100,8 @@
         final SurfaceControl animationBoundsLayer = mToken.mAnimationBoundsLayer;
 
         mToken.mSurfaceAnimator.cancelAnimation();
-        verify(mTransaction).destroy(eq(leash));
-        verify(mTransaction).destroy(eq(animationBoundsLayer));
+        verify(mTransaction).reparent(eq(leash), eq(null));
+        verify(mTransaction).reparent(eq(animationBoundsLayer), eq(null));
         assertThat(mToken.mNeedsAnimationBoundsLayer).isFalse();
     }
 
@@ -111,7 +111,7 @@
 
         mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
         verify(mTransaction).reparent(eq(mToken.getSurfaceControl()),
-                eq(mToken.mSurfaceAnimator.mLeash.getHandle()));
+                eq(mToken.mSurfaceAnimator.mLeash));
         assertThat(mToken.mAnimationBoundsLayer).isNull();
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index 1c5391e..9ce5795 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -106,7 +106,7 @@
         }
 
         public void notifyTransitionStarting(int transit) {
-            mListener.onAppTransitionStartingLocked(transit, null, null, 0, 0, 0);
+            mListener.onAppTransitionStartingLocked(transit, 0, 0, 0);
         }
 
         public void notifyTransitionFinished() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index ee1c8df..f99cd4b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -212,7 +212,7 @@
         mDimmer.updateDims(mTransaction, new Rect());
         verify(mSurfaceAnimatorStarter).startAnimation(any(SurfaceAnimator.class), any(
                 SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean());
-        verify(mHost.getPendingTransaction()).destroy(dimLayer);
+        verify(mHost.getPendingTransaction()).reparent(dimLayer, null);
     }
 
     @Test
@@ -269,7 +269,7 @@
         mDimmer.updateDims(mTransaction, new Rect());
         verify(mSurfaceAnimatorStarter, never()).startAnimation(any(SurfaceAnimator.class), any(
                 SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean());
-        verify(mTransaction).destroy(dimLayer);
+        verify(mTransaction).reparent(dimLayer, null);
     }
 
     private SurfaceControl getDimLayer() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 3826fac..f399463 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -59,6 +59,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.DisplayMetrics;
 import android.view.DisplayCutout;
+import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.Surface;
@@ -584,15 +585,17 @@
 
     @Test
     public void testOnDescendantOrientationRequestChanged() {
-        final DisplayContent dc = createNewDisplay();
+        final DisplayInfo info = new DisplayInfo();
+        info.logicalWidth = 1080;
+        info.logicalHeight = 1920;
+        info.logicalDensityDpi = 240;
+        final DisplayContent dc = createNewDisplay(info);
+        dc.configureDisplayPolicy();
         mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
-        final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
-                ? SCREEN_ORIENTATION_PORTRAIT
-                : SCREEN_ORIENTATION_LANDSCAPE;
 
         final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
         window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
-        window.mAppToken.setOrientation(newOrientation);
+        window.mAppToken.mOrientation = SCREEN_ORIENTATION_LANDSCAPE;
 
         ActivityRecord activityRecord = mock(ActivityRecord.class);
 
@@ -603,21 +606,22 @@
         verify(mWm.mAtmService).updateDisplayOverrideConfigurationLocked(captor.capture(),
                 same(activityRecord), anyBoolean(), eq(dc.getDisplayId()));
         final Configuration newDisplayConfig = captor.getValue();
-        assertEquals(Configuration.ORIENTATION_PORTRAIT, newDisplayConfig.orientation);
+        assertEquals(Configuration.ORIENTATION_LANDSCAPE, newDisplayConfig.orientation);
     }
 
     @Test
     public void testOnDescendantOrientationRequestChanged_FrozenToUserRotation() {
-        final DisplayContent dc = createNewDisplay();
+        final DisplayInfo info = new DisplayInfo();
+        info.logicalWidth = 1080;
+        info.logicalHeight = 1920;
+        info.logicalDensityDpi = 240;
+        final DisplayContent dc = createNewDisplay(info);
         dc.getDisplayRotation().setFixedToUserRotation(true);
         mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
-        final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
-                ? SCREEN_ORIENTATION_PORTRAIT
-                : SCREEN_ORIENTATION_LANDSCAPE;
 
         final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
         window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
-        window.mAppToken.setOrientation(newOrientation);
+        window.mAppToken.mOrientation = SCREEN_ORIENTATION_LANDSCAPE;
 
         ActivityRecord activityRecord = mock(ActivityRecord.class);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 6b31e6f..d05711e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -33,7 +33,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.content.ContentResolver;
@@ -63,6 +62,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
@@ -86,7 +86,7 @@
 
     private StatusBarManagerInternal mPreviousStatusBarManagerInternal;
 
-    private WindowManagerService mMockWm;
+    private static WindowManagerService sMockWm;
     private DisplayContent mMockDisplayContent;
     private DisplayPolicy mMockDisplayPolicy;
     private Context mMockContext;
@@ -108,13 +108,16 @@
 
     private DisplayRotation mTarget;
 
+    @BeforeClass
+    public static void setUpOnce() {
+        sMockWm = mock(WindowManagerService.class);
+        sMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class);
+    }
+
     @Before
     public void setUp() {
         FakeSettingsProvider.clearSettingsProvider();
 
-        mMockWm = mock(WindowManagerService.class);
-        mMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class);
-
         mPreviousStatusBarManagerInternal = LocalServices.getService(
                 StatusBarManagerInternal.class);
         LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
@@ -452,7 +455,7 @@
         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
         assertTrue(waitForUiHandler());
 
-        verify(mMockWm).updateRotation(false, false);
+        verify(sMockWm).updateRotation(false, false);
     }
 
     @Test
@@ -608,23 +611,6 @@
     // ========================
     // Non-rotation API Tests
     // ========================
-    @Test
-    public void testRespectsAppRequestedOrientationByDefault() throws Exception {
-        mBuilder.build();
-
-        assertTrue("Display rotation should respect app requested orientation by"
-                + " default.", mTarget.respectAppRequestedOrientation());
-    }
-
-    @Test
-    public void testNotRespectAppRequestedOrientation_FixedToUserRotation() throws Exception {
-        mBuilder.build();
-        mTarget.setFixedToUserRotation(true);
-
-        assertFalse("Display rotation shouldn't respect app requested orientation if"
-                + " fixed to user rotation.", mTarget.respectAppRequestedOrientation());
-    }
-
     /**
      * Call {@link DisplayRotation#configure(int, int, int, int)} to configure {@link #mTarget}
      * according to given parameters.
@@ -833,8 +819,9 @@
                     .thenReturn(mFakeSettingsProvider.getIContentProvider());
 
             mMockDisplayWindowSettings = mock(DisplayWindowSettings.class);
-            mTarget = new DisplayRotation(mMockWm, mMockDisplayContent, mMockDisplayPolicy,
+            mTarget = new DisplayRotation(sMockWm, mMockDisplayContent, mMockDisplayPolicy,
                     mMockDisplayWindowSettings, mMockContext, new Object());
+            reset(sMockWm);
 
             captureObservers();
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index f1c6eab..68d8bc0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -20,11 +20,9 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -96,8 +94,8 @@
     private WindowState createDropTargetWindow(String name, int ownerId) {
         final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
                 mDisplayContent);
-        final TaskStack stack = createStackControllerOnStackOnDisplay(
-                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
+        final TaskStack stack = createTaskStackOnDisplay(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent);
         final Task task = createTaskInStack(stack, ownerId);
         task.addChild(token, 0);
 
@@ -125,7 +123,6 @@
         mDisplayContent = spy(mDisplayContent);
         mWindow = createDropTargetWindow("Drag test window", 0);
         doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0);
-        when(mWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true);
 
         synchronized (mWm.mGlobalLock) {
             mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
@@ -176,7 +173,6 @@
                     .setFormat(PixelFormat.TRANSLUCENT)
                     .build();
 
-            assertTrue(mWm.mInputManager.transferTouchFocus(null, null));
             mToken = mTarget.performDrag(
                     new SurfaceSession(), 0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0,
                     data);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index 8c3dec7..b28ae40 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -71,7 +71,6 @@
 
     @Before
     public void setUp() throws Exception {
-        mService = createActivityTaskManagerService();
         mPersister = new TestLaunchParamsPersister();
         mController = new LaunchParamsController(mService, mPersister);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 8635364..aeda473 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -102,8 +102,6 @@
         mFolder = new File(cacheFolder, "launch_params_tests");
         deleteRecursively(mFolder);
 
-        setupActivityTaskManagerService();
-
         mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++);
         final DisplayInfo info = new DisplayInfo();
         info.uniqueId = mDisplayUniqueId;
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
new file mode 100644
index 0000000..c52c8d7
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.view.SurfaceControl;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+
+import java.util.function.Supplier;
+
+@SmallTest
+@Presubmit
+public class LetterboxTest {
+
+    Letterbox mLetterbox;
+    SurfaceControlMocker mSurfaces;
+    SurfaceControl.Transaction mTransaction;
+
+    @Before
+    public void setUp() throws Exception {
+        mSurfaces = new SurfaceControlMocker();
+        mLetterbox = new Letterbox(mSurfaces);
+        mTransaction = mock(SurfaceControl.Transaction.class);
+    }
+
+    @Test
+    public void testOverlappingWith_usesGlobalCoordinates() {
+        mLetterbox.layout(new Rect(0, 0, 10, 50), new Rect(0, 2, 10, 45), new Point(1000, 2000));
+        assertTrue(mLetterbox.isOverlappingWith(new Rect(0, 0, 1, 1)));
+    }
+
+    @Test
+    public void testSurfaceOrigin_applied() {
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+        mLetterbox.applySurfaceChanges(mTransaction);
+        verify(mTransaction).setPosition(mSurfaces.top, -1000, -2000);
+    }
+
+    @Test
+    public void testSurfaceOrigin_changeCausesReapply() {
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
+        mLetterbox.applySurfaceChanges(mTransaction);
+        clearInvocations(mTransaction);
+        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(0, 0));
+        assertTrue(mLetterbox.needsApplySurfaceChanges());
+        mLetterbox.applySurfaceChanges(mTransaction);
+        verify(mTransaction).setPosition(mSurfaces.top, 0, 0);
+    }
+
+    class SurfaceControlMocker implements Supplier<SurfaceControl.Builder> {
+        private SurfaceControl.Builder mLeftBuilder;
+        public SurfaceControl left;
+        private SurfaceControl.Builder mTopBuilder;
+        public SurfaceControl top;
+        private SurfaceControl.Builder mRightBuilder;
+        public SurfaceControl right;
+        private SurfaceControl.Builder mBottomBuilder;
+        public SurfaceControl bottom;
+
+        @Override
+        public SurfaceControl.Builder get() {
+            final SurfaceControl.Builder builder = mock(SurfaceControl.Builder.class,
+                    InvocationOnMock::getMock);
+            when(builder.setName(anyString())).then((i) -> {
+                if (((String) i.getArgument(0)).contains("left")) {
+                    mLeftBuilder = (SurfaceControl.Builder) i.getMock();
+                } else if (((String) i.getArgument(0)).contains("top")) {
+                    mTopBuilder = (SurfaceControl.Builder) i.getMock();
+                } else if (((String) i.getArgument(0)).contains("right")) {
+                    mRightBuilder = (SurfaceControl.Builder) i.getMock();
+                } else if (((String) i.getArgument(0)).contains("bottom")) {
+                    mBottomBuilder = (SurfaceControl.Builder) i.getMock();
+                }
+                return i.getMock();
+            });
+
+            doAnswer((i) -> {
+                final SurfaceControl control = mock(SurfaceControl.class);
+                if (i.getMock() == mLeftBuilder) {
+                    left = control;
+                } else if (i.getMock() == mTopBuilder) {
+                    top = control;
+                } else if (i.getMock() == mRightBuilder) {
+                    right = control;
+                } else if (i.getMock() == mBottomBuilder) {
+                    bottom = control;
+                }
+                return control;
+            }).when(builder).build();
+            return builder;
+        }
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index a9f150b..e24eb75 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -34,7 +34,12 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.isNull;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
@@ -47,10 +52,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
 
 import android.app.StatusBarManager;
 import android.app.admin.DevicePolicyManager;
@@ -115,6 +116,7 @@
 
     private LockTaskController mLockTaskController;
     private Context mContext;
+    private String mPackageName;
     private String mLockToAppSetting;
 
     @Before
@@ -122,6 +124,7 @@
         MockitoAnnotations.initMocks(this);
 
         mContext = getInstrumentation().getTargetContext();
+        mPackageName = mContext.getPackageName();
         mLockToAppSetting = Settings.Secure.getString(mContext.getContentResolver(),
                 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED);
 
@@ -146,6 +149,7 @@
 
     @After
     public void tearDown() throws Exception {
+        mLockTaskController.setWindowManager(null);
         Settings.Secure.putString(mContext.getContentResolver(),
                 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, mLockToAppSetting);
     }
@@ -223,7 +227,7 @@
         // THEN lock task mode should be started
         verifyLockTaskStarted(STATUS_BAR_MASK_PINNED, DISABLE2_NONE);
         // THEN screen pinning toast should be shown
-        verify(mStatusBarService).showPinningEnterExitToast(true /* entering */);
+        verify(mStatusBarService).showPinningEnterExitToast(eq(true /* entering */));
     }
 
     @Test
@@ -390,9 +394,9 @@
         // THEN lock task mode should have been finished
         verifyLockTaskStopped(times(1));
         // THEN the keyguard should be shown
-        verify(mLockPatternUtils).requireCredentialEntry(UserHandle.USER_ALL);
+        verify(mLockPatternUtils).requireCredentialEntry(eq(UserHandle.USER_ALL));
         // THEN screen pinning toast should be shown
-        verify(mStatusBarService).showPinningEnterExitToast(false /* entering */);
+        verify(mStatusBarService).showPinningEnterExitToast(eq(false /* entering */));
     }
 
     @Test
@@ -509,9 +513,9 @@
                 & ~DISABLE_HOME;
         int expectedFlags2 = DISABLE2_MASK;
         verify(mStatusBarService).disable(eq(expectedFlags), any(IBinder.class),
-                eq(mContext.getPackageName()));
+                eq(mPackageName));
         verify(mStatusBarService).disable2(eq(expectedFlags2), any(IBinder.class),
-                eq(mContext.getPackageName()));
+                eq(mPackageName));
 
         // reset invocation counter
         reset(mStatusBarService);
@@ -526,9 +530,9 @@
         expectedFlags2 = DISABLE2_MASK
                 & ~DISABLE2_NOTIFICATION_SHADE;
         verify(mStatusBarService).disable(eq(expectedFlags), any(IBinder.class),
-                eq(mContext.getPackageName()));
+                eq(mPackageName));
         verify(mStatusBarService).disable2(eq(expectedFlags2), any(IBinder.class),
-                eq(mContext.getPackageName()));
+                eq(mPackageName));
     }
 
     @Test
@@ -548,9 +552,9 @@
 
         // THEN status bar shouldn't change
         verify(mStatusBarService, never()).disable(anyInt(), any(IBinder.class),
-                eq(mContext.getPackageName()));
+                eq(mPackageName));
         verify(mStatusBarService, never()).disable2(anyInt(), any(IBinder.class),
-                eq(mContext.getPackageName()));
+                eq(mPackageName));
     }
 
     @Test
@@ -657,14 +661,14 @@
         verify(mWindowManager).disableKeyguard(any(IBinder.class), anyString(), eq(TEST_USER_ID));
         // THEN the status bar should have been disabled
         verify(mStatusBarService).disable(eq(statusBarMask), any(IBinder.class),
-                eq(mContext.getPackageName()));
+                eq(mPackageName));
         verify(mStatusBarService).disable2(eq(statusBarMask2), any(IBinder.class),
-                eq(mContext.getPackageName()));
+                eq(mPackageName));
         // THEN recents should have been notified
         verify(mRecentTasks).onLockTaskModeStateChanged(anyInt(), eq(TEST_USER_ID));
         // THEN the DO/PO should be informed about the operation
-        verify(mDevicePolicyManager).notifyLockTaskModeChanged(true, TEST_PACKAGE_NAME,
-                TEST_USER_ID);
+        verify(mDevicePolicyManager).notifyLockTaskModeChanged(eq(true), eq(TEST_PACKAGE_NAME),
+                eq(TEST_USER_ID));
     }
 
     private void verifyLockTaskStopped(VerificationMode mode) throws Exception {
@@ -672,11 +676,12 @@
         verify(mWindowManager, mode).reenableKeyguard(any(IBinder.class), eq(TEST_USER_ID));
         // THEN the status bar should have been disabled
         verify(mStatusBarService, mode).disable(eq(StatusBarManager.DISABLE_NONE),
-                any(IBinder.class), eq(mContext.getPackageName()));
+                any(IBinder.class), eq(mPackageName));
         verify(mStatusBarService, mode).disable2(eq(StatusBarManager.DISABLE2_NONE),
-                any(IBinder.class), eq(mContext.getPackageName()));
+                any(IBinder.class), eq(mPackageName));
         // THEN the DO/PO should be informed about the operation
-        verify(mDevicePolicyManager, mode).notifyLockTaskModeChanged(false, null, TEST_USER_ID);
+        verify(mDevicePolicyManager, mode).notifyLockTaskModeChanged(eq(false), isNull(),
+                eq(TEST_USER_ID));
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
index efd7d25..beaac8e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
@@ -52,7 +52,6 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mService = createActivityTaskManagerService();
         mService.mH.runWithScissors(() -> {
             mHandler = new TestHandler(null, mClock);
         }, 0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index ad2a708..9478be9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -25,6 +25,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.mockito.ArgumentMatchers.eq;
 
 import android.graphics.Point;
@@ -43,6 +44,7 @@
 
 import com.android.server.testutils.OffsettableClock;
 import com.android.server.testutils.TestHandler;
+import com.android.server.wm.RemoteAnimationController.RemoteAnimationRecord;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 
 import org.junit.Before;
@@ -60,8 +62,10 @@
 public class RemoteAnimationControllerTest extends WindowTestsBase {
 
     @Mock SurfaceControl mMockLeash;
+    @Mock SurfaceControl mMockThumbnailLeash;
     @Mock Transaction mMockTransaction;
     @Mock OnAnimationFinishedCallback mFinishedCallback;
+    @Mock OnAnimationFinishedCallback mThumbnailFinishedCallback;
     @Mock IRemoteAnimationRunner mMockRunner;
     private RemoteAnimationAdapter mAdapter;
     private RemoteAnimationController mController;
@@ -84,8 +88,8 @@
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
         mDisplayContent.mOpeningApps.add(win.mAppToken);
         try {
-            final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken,
-                    new Point(50, 100), new Rect(50, 100, 150, 150));
+            final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mAppToken,
+                    new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
             adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
             mController.goodToGo();
             mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
@@ -117,8 +121,8 @@
     @Test
     public void testCancel() throws Exception {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
-        final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken,
-                new Point(50, 100), new Rect(50, 100, 150, 150));
+        final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mAppToken,
+                new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
         adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
         mController.goodToGo();
 
@@ -129,8 +133,8 @@
     @Test
     public void testTimeout() throws Exception {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
-        final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken,
-                new Point(50, 100), new Rect(50, 100, 150, 150));
+        final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mAppToken,
+                new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
         adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
         mController.goodToGo();
 
@@ -143,12 +147,12 @@
 
     @Test
     public void testTimeout_scaled() throws Exception {
-        mWm.setAnimationScale(2, 5.0f);
         try {
+            mWm.setAnimationScale(2, 5.0f);
             final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
                     "testWin");
-            final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken,
-                    new Point(50, 100), new Rect(50, 100, 150, 150));
+            final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
+                    win.mAppToken, new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
             adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
             mController.goodToGo();
 
@@ -176,8 +180,8 @@
     @Test
     public void testNotReallyStarted() {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
-        mController.createAnimationAdapter(win.mAppToken,
-                new Point(50, 100), new Rect(50, 100, 150, 150));
+        mController.createRemoteAnimationRecord(win.mAppToken,
+                new Point(50, 100), new Rect(50, 100, 150, 150), null);
         mController.goodToGo();
         verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
     }
@@ -186,10 +190,10 @@
     public void testOneNotStarted() throws Exception {
         final WindowState win1 = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin1");
         final WindowState win2 = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin2");
-        mController.createAnimationAdapter(win1.mAppToken,
-                new Point(50, 100), new Rect(50, 100, 150, 150));
-        final AnimationAdapter adapter = mController.createAnimationAdapter(win2.mAppToken,
-                new Point(50, 100), new Rect(50, 100, 150, 150));
+        mController.createRemoteAnimationRecord(win1.mAppToken,
+                new Point(50, 100), new Rect(50, 100, 150, 150), null);
+        final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win2.mAppToken,
+                new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
         adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
         mController.goodToGo();
         mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
@@ -205,8 +209,8 @@
     @Test
     public void testRemovedBeforeStarted() {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
-        final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken,
-                new Point(50, 100), new Rect(50, 100, 150, 150));
+        final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mAppToken,
+                new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
         adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
         win.mAppToken.removeImmediately();
         mController.goodToGo();
@@ -214,6 +218,49 @@
         verify(mFinishedCallback).onAnimationFinished(eq(adapter));
     }
 
+    @Test
+    public void testChange() throws Exception {
+        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+        mDisplayContent.mChangingApps.add(win.mAppToken);
+        try {
+            final RemoteAnimationRecord record = mController.createRemoteAnimationRecord(
+                    win.mAppToken, new Point(50, 100), new Rect(50, 100, 150, 150),
+                    new Rect(0, 0, 200, 200));
+            assertNotNull(record.mThumbnailAdapter);
+            ((AnimationAdapter) record.mAdapter)
+                    .startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+            ((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
+                    mMockTransaction, mThumbnailFinishedCallback);
+            mController.goodToGo();
+            mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+            final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+                    ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+            final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+                    ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+            verify(mMockRunner).onAnimationStart(appsCaptor.capture(), finishedCaptor.capture());
+            assertEquals(1, appsCaptor.getValue().length);
+            final RemoteAnimationTarget app = appsCaptor.getValue()[0];
+            assertEquals(RemoteAnimationTarget.MODE_CHANGING, app.mode);
+            assertEquals(new Point(50, 100), app.position);
+            assertEquals(new Rect(50, 100, 150, 150), app.sourceContainerBounds);
+            assertEquals(new Rect(0, 0, 200, 200), app.startBounds);
+            assertEquals(mMockLeash, app.leash);
+            assertEquals(mMockThumbnailLeash, app.startLeash);
+            assertEquals(win.mWinAnimator.mLastClipRect, app.clipRect);
+            assertEquals(false, app.isTranslucent);
+            verify(mMockTransaction).setLayer(mMockLeash, app.prefixOrderIndex);
+            verify(mMockTransaction).setPosition(mMockLeash, app.position.x, app.position.y);
+            verify(mMockTransaction).setWindowCrop(mMockLeash, new Rect(0, 0, 200, 200));
+            verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
+
+            finishedCaptor.getValue().onAnimationFinished();
+            verify(mFinishedCallback).onAnimationFinished(eq(record.mAdapter));
+            verify(mThumbnailFinishedCallback).onAnimationFinished(eq(record.mThumbnailAdapter));
+        } finally {
+            mDisplayContent.mChangingApps.clear();
+        }
+    }
+
     private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
         verify(binder, atLeast(0)).asBinder();
         verifyNoMoreInteractions(binder);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 58302d6..e3bacf9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -82,7 +82,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mFullscreenStack = mRootActivityContainer.getDefaultDisplay().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
     }
@@ -323,8 +322,8 @@
     public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
         // Create stack/task on default display.
         final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
-        final TestActivityStack targetStack =
-                new StackBuilder(mRootActivityContainer).setOnTop(false).build();
+        final TestActivityStack targetStack = (TestActivityStack) new StackBuilder(
+                mRootActivityContainer).setOnTop(false).build();
         final TaskRecord targetTask = targetStack.getChildAt(0);
 
         // Create Recents on top of the display.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
new file mode 100644
index 0000000..45fe5d2
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Tests for RootWindowContainer.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:RootWindowContainerTests
+ */
+@SmallTest
+@Presubmit
+public class RootWindowContainerTests extends WindowTestsBase {
+
+    private static final int FAKE_CALLING_UID = 667;
+
+    @Test
+    public void testIsAnyNonToastWindowVisibleForUid_oneToastOneNonToastBothVisible() {
+        final WindowState toastyToast = createWindow(null, TYPE_TOAST, "toast", FAKE_CALLING_UID);
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app", FAKE_CALLING_UID);
+        toastyToast.mHasSurface = true;
+        app.mHasSurface = true;
+
+        assertTrue(toastyToast.isVisible());
+        assertTrue(app.isVisible());
+        assertTrue(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID));
+    }
+
+    @Test
+    public void testIsAnyNonToastWindowVisibleForUid_onlyToastVisible() {
+        final WindowState toastyToast = createWindow(null, TYPE_TOAST, "toast", FAKE_CALLING_UID);
+        toastyToast.mHasSurface = true;
+
+        assertTrue(toastyToast.isVisible());
+        assertFalse(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID));
+    }
+
+    @Test
+    public void testIsAnyNonToastWindowVisibleForUid_aFewNonToastButNoneVisible() {
+        final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar", FAKE_CALLING_UID);
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app", FAKE_CALLING_UID);
+
+        assertFalse(topBar.isVisible());
+        assertFalse(app.isVisible());
+        assertFalse(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID));
+    }
+}
+
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index a8b6dc3..dc96480 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -49,7 +49,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
         mRunningTasks = new RunningTasks();
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
index 36eccd1..03aba39 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
@@ -33,6 +33,8 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
@@ -58,7 +60,6 @@
 import android.view.WindowManager;
 import android.widget.TextView;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 
 import org.junit.After;
@@ -80,8 +81,8 @@
 @Presubmit
 public class ScreenDecorWindowTests {
 
-    private final Context mContext = InstrumentationRegistry.getTargetContext();
-    private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    private final Context mContext = getInstrumentation().getTargetContext();
+    private final Instrumentation mInstrumentation = getInstrumentation();
 
     private WindowManager mWm;
     private ArrayList<View> mWindows = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java
deleted file mode 100644
index 5690b58..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/StackWindowControllerTests.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Test class for {@link StackWindowController}.
- *
- * Build/Install/Run:
- *  atest FrameworksServicesTests:StackWindowControllerTests
- */
-@SmallTest
-@Presubmit
-public class StackWindowControllerTests extends WindowTestsBase {
-    @Test
-    public void testRemoveContainer() {
-        final StackWindowController stackController =
-                createStackControllerOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController);
-
-        final TaskStack stack = stackController.mContainer;
-        assertNotNull(stack);
-        assertNotNull(task);
-        stackController.removeContainer();
-        // Assert that the container was removed.
-        assertNull(stackController.mContainer);
-        assertNull(stack.getDisplayContent());
-        assertNull(task.getDisplayContent());
-        assertNull(task.mStack);
-    }
-
-    @Test
-    public void testRemoveContainer_deferRemoval() {
-        final StackWindowController stackController =
-                createStackControllerOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController);
-
-        final TaskStack stack = stackController.mContainer;
-        // Stack removal is deferred if one of its child is animating.
-        task.setLocalIsAnimating(true);
-
-        stackController.removeContainer();
-        // For the case of deferred removal the stack controller will no longer be connected to the
-        // container, but the task controller will still be connected to the its container until
-        // the stack window container is removed.
-        assertNull(stackController.mContainer);
-        assertNull(stack.getController());
-        assertNotNull(task);
-
-        stack.removeImmediately();
-        // After removing, the task will be isolated.
-        assertNull(task.getParent());
-        assertEquals(task.getChildCount(), 0);
-        assertNull(task.getController());
-    }
-
-    @Test
-    public void testReparent() {
-        // Create first stack on primary display.
-        final StackWindowController stack1Controller =
-                createStackControllerOnDisplay(mDisplayContent);
-        final TaskStack stack1 = stack1Controller.mContainer;
-        final WindowTestUtils.TestTask task1 = WindowTestUtils.createTestTask(stack1Controller);
-        task1.mOnDisplayChangedCalled = false;
-
-        // Create second display and put second stack on it.
-        final DisplayContent dc = createNewDisplay();
-        final StackWindowController stack2Controller =
-                createStackControllerOnDisplay(dc);
-        final TaskStack stack2 = stack2Controller.mContainer;
-
-        // Reparent
-        stack1Controller.reparent(dc.getDisplayId(), new Rect(), true /* onTop */);
-        assertEquals(dc, stack1.getDisplayContent());
-        final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
-        final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
-        assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
-        assertTrue(task1.mOnDisplayChangedCalled);
-    }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
index d14f30d..9b84215 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -90,13 +90,13 @@
         final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
                 OnAnimationFinishedCallback.class);
         assertAnimating(mAnimatable);
-        verify(mTransaction).reparent(eq(mAnimatable.mSurface), eq(mAnimatable.mLeash.getHandle()));
+        verify(mTransaction).reparent(eq(mAnimatable.mSurface), eq(mAnimatable.mLeash));
         verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
 
         callbackCaptor.getValue().onAnimationFinished(mSpec);
         assertNotAnimating(mAnimatable);
         assertTrue(mAnimatable.mFinishedCallbackCalled);
-        verify(mTransaction).destroy(eq(mAnimatable.mLeash));
+        verify(mTransaction).reparent(eq(mAnimatable.mLeash), eq(null));
         // TODO: Verify reparenting once we use mPendingTransaction to reparent it back
     }
 
@@ -106,7 +106,7 @@
         final SurfaceControl firstLeash = mAnimatable.mLeash;
         mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
 
-        verify(mTransaction).destroy(eq(firstLeash));
+        verify(mTransaction).reparent(eq(firstLeash), eq(null));
         assertFalse(mAnimatable.mFinishedCallbackCalled);
 
         final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
@@ -133,7 +133,7 @@
         assertNotAnimating(mAnimatable);
         verify(mSpec).onAnimationCancelled(any());
         assertTrue(mAnimatable.mFinishedCallbackCalled);
-        verify(mTransaction).destroy(eq(mAnimatable.mLeash));
+        verify(mTransaction).reparent(eq(mAnimatable.mLeash), eq(null));
     }
 
     @Test
@@ -155,7 +155,7 @@
         verifyZeroInteractions(mSpec);
         assertNotAnimating(mAnimatable);
         assertTrue(mAnimatable.mFinishedCallbackCalled);
-        verify(mTransaction).destroy(eq(mAnimatable.mLeash));
+        verify(mTransaction).reparent(eq(mAnimatable.mLeash), eq(null));
     }
 
     @Test
@@ -171,11 +171,11 @@
         assertNotAnimating(mAnimatable);
         assertAnimating(mAnimatable2);
         assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash);
-        verify(mTransaction, never()).destroy(eq(leash));
+        verify(mTransaction, never()).reparent(eq(leash), eq(null));
         callbackCaptor.getValue().onAnimationFinished(mSpec);
         assertNotAnimating(mAnimatable2);
         assertTrue(mAnimatable2.mFinishedCallbackCalled);
-        verify(mTransaction).destroy(eq(leash));
+        verify(mTransaction).reparent(eq(leash), eq(null));
     }
 
     @Test
@@ -198,7 +198,7 @@
         mDeferFinishAnimatable.mEndDeferFinishCallback.run();
         assertNotAnimating(mAnimatable2);
         assertTrue(mDeferFinishAnimatable.mFinishedCallbackCalled);
-        verify(mTransaction).destroy(eq(mDeferFinishAnimatable.mLeash));
+        verify(mTransaction).reparent(eq(mDeferFinishAnimatable.mLeash), eq(null));
     }
 
     private void assertAnimating(MyAnimatable animatable) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 7186e22..ace179a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -75,10 +75,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setupActivityTaskManagerService();
-        mService.mSupportsFreeformWindowManagement = true;
-        when(mSupervisor.canUseActivityOptionsLaunchBounds(any())).thenCallRealMethod();
-
         mActivity = new ActivityBuilder(mService).build();
         mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
         mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
@@ -199,6 +195,25 @@
         assertEquals(freeformDisplay.mDisplayId, mResult.mPreferredDisplayId);
     }
 
+    @Test
+    public void testUsesNoDisplaySourceHandoverDisplayIdIfSet() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+        final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FULLSCREEN);
+
+        mCurrent.mPreferredDisplayId = fullscreenDisplay.mDisplayId;
+        ActivityRecord reusableActivity = createSourceActivity(fullscreenDisplay);
+        ActivityRecord source = createSourceActivity(freeformDisplay);
+        source.mHandoverLaunchDisplayId = freeformDisplay.mDisplayId;
+        source.noDisplay = true;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(reusableActivity.getTaskRecord(),
+                null /* layout */, mActivity, source, null /* options */, mCurrent, mResult));
+
+        assertEquals(freeformDisplay.mDisplayId, mResult.mPreferredDisplayId);
+    }
+
     // =====================================
     // Launch Windowing Mode Related Tests
     // =====================================
@@ -768,6 +783,21 @@
     }
 
     @Test
+    public void testReturnBoundsForFullscreenWindowingMode() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+        mCurrent.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
+        mCurrent.mBounds.set(0, 0, 200, 100);
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(new Rect(0, 0, 200, 100), mResult.mBounds);
+    }
+
+    @Test
     public void testUsesDisplayOrientationForNoSensorOrientation() {
         final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
                 WINDOWING_MODE_FREEFORM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index b996bfb..c595868 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -19,6 +19,10 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.TaskPositioner.MIN_ASPECT;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
@@ -38,13 +42,12 @@
 
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.Mockito;
 
 /**
  * Tests for the {@link TaskPositioner} class.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:TaskPositionerTests
+ *  atest WmTests:TaskPositionerTests
  */
 @SmallTest
 public class TaskPositionerTests extends WindowTestsBase {
@@ -73,18 +76,17 @@
         mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm);
         mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm);
 
-        mPositioner = new TaskPositioner(mWm, Mockito.mock(IActivityTaskManager.class));
+        mPositioner = new TaskPositioner(mWm, mock(IActivityTaskManager.class));
         mPositioner.register(mDisplayContent);
 
-        mWindow = Mockito.spy(createWindow(null, TYPE_BASE_APPLICATION, "window"));
-        final Task task = Mockito.spy(mWindow.getTask());
-        Mockito.when(mWindow.getTask()).thenReturn(task);
-
-        Mockito.doAnswer(invocation -> {
+        mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
+        final Task task = mWindow.getTask();
+        spyOn(task);
+        doAnswer(invocation -> {
             final Rect rect = (Rect) invocation.getArguments()[0];
             rect.set(mDimBounds);
-            return (Void) null;
-        }).when(task).getDimBounds(Mockito.any(Rect.class));
+            return null;
+        }).when(task).getDimBounds(any(Rect.class));
 
         mWindow.getStack().setWindowingMode(WINDOWING_MODE_FREEFORM);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index c343fe7..8c6ac23 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -18,7 +18,6 @@
 
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
@@ -58,10 +57,6 @@
         assertNotNull(mWm.mTaskPositioningController);
         mTarget = mWm.mTaskPositioningController;
 
-        when(mWm.mInputManager.transferTouchFocus(
-                any(InputChannel.class),
-                any(InputChannel.class))).thenReturn(true);
-
         mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
         mWindow.mInputChannel = new InputChannel();
         synchronized (mWm.mGlobalLock) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 6b6b33c..e182c45 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -21,6 +21,18 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.sameInstance;
@@ -34,12 +46,14 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.Xml;
 import android.view.DisplayInfo;
+import android.view.Surface;
 
 import androidx.test.filters.MediumTest;
 
@@ -76,7 +90,6 @@
     @Before
     public void setUp() throws Exception {
         TaskRecord.setTaskRecordFactory(null);
-        setupActivityTaskManagerService();
         mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
     }
 
@@ -132,17 +145,6 @@
         assertTrue(task.returnsToHomeStack());
     }
 
-    /** Ensures that bounds are clipped to their parent. */
-    @Test
-    public void testAppBounds_BoundsClipping() {
-        final Rect shiftedBounds = new Rect(mParentBounds);
-        shiftedBounds.offset(10, 10);
-        final Rect expectedBounds = new Rect(mParentBounds);
-        expectedBounds.intersect(shiftedBounds);
-        testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, shiftedBounds,
-                expectedBounds);
-    }
-
     /** Ensures that empty bounds are not propagated to the configuration. */
     @Test
     public void testAppBounds_EmptyBounds() {
@@ -166,18 +168,201 @@
         final Rect insetBounds = new Rect(mParentBounds);
         insetBounds.inset(5, 5, 5, 5);
         testStackBoundsConfiguration(
-                WINDOWING_MODE_FULLSCREEN, mParentBounds, insetBounds, insetBounds);
+                WINDOWING_MODE_FREEFORM, mParentBounds, insetBounds, insetBounds);
     }
 
-    /** Ensures that full screen free form bounds are clipped */
+    /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
     @Test
-    public void testAppBounds_FullScreenFreeFormBounds() {
+    public void testBoundsOnModeChangeFreeformToFullscreen() {
         ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+        ActivityStack stack = new StackBuilder(mRootActivityContainer).setDisplay(display)
+                .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+        TaskRecord task = stack.getChildAt(0);
+        task.getRootActivity().mAppWindowToken.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
         DisplayInfo info = new DisplayInfo();
         display.mDisplay.getDisplayInfo(info);
         final Rect fullScreenBounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight);
-        testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, fullScreenBounds,
-                mParentBounds);
+        final Rect freeformBounds = new Rect(fullScreenBounds);
+        freeformBounds.inset((int) (freeformBounds.width() * 0.2),
+                (int) (freeformBounds.height() * 0.2));
+        task.setBounds(freeformBounds);
+
+        assertEquals(freeformBounds, task.getBounds());
+
+        // FULLSCREEN inherits bounds
+        stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        assertEquals(fullScreenBounds, task.getBounds());
+        assertEquals(freeformBounds, task.mLastNonFullscreenBounds);
+
+        // FREEFORM restores bounds
+        stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        assertEquals(freeformBounds, task.getBounds());
+    }
+
+    /**
+     * This is a temporary hack to trigger an onConfigurationChange at the task level after an
+     * orientation is requested. Normally this is done by the onDescendentOrientationChanged call
+     * up the WM hierarchy, but since the WM hierarchy is mocked out, it doesn't happen here.
+     * TODO: remove this when we either get a WM hierarchy or when hierarchies are merged.
+     */
+    private void setActivityRequestedOrientation(ActivityRecord activity, int orientation) {
+        activity.setRequestedOrientation(orientation);
+        ConfigurationContainer taskRecord = activity.getParent();
+        taskRecord.onConfigurationChanged(taskRecord.getParent().getConfiguration());
+    }
+
+    /**
+     * Tests that a task with forced orientation has orientation-consistent bounds within the
+     * parent.
+     */
+    @Test
+    public void testFullscreenBoundsForcedOrientation() {
+        final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
+        final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
+        DisplayInfo info = new DisplayInfo();
+        info.logicalWidth = fullScreenBounds.width();
+        info.logicalHeight = fullScreenBounds.height();
+        ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
+        assertTrue(mRootActivityContainer.getActivityDisplay(display.mDisplayId) != null);
+        // Override display orientation. Normally this is available via DisplayContent, but DC
+        // is mocked-out.
+        display.getRequestedOverrideConfiguration().orientation =
+                Configuration.ORIENTATION_LANDSCAPE;
+        display.onRequestedOverrideConfigurationChanged(
+                display.getRequestedOverrideConfiguration());
+        ActivityStack stack = new StackBuilder(mRootActivityContainer)
+                .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
+        TaskRecord task = stack.getChildAt(0);
+        ActivityRecord root = task.getTopActivity();
+        assertEquals(root, task.getTopActivity());
+
+        assertEquals(fullScreenBounds, task.getBounds());
+
+        // Setting app to fixed portrait fits within parent
+        setActivityRequestedOrientation(root, SCREEN_ORIENTATION_PORTRAIT);
+        assertEquals(root, task.getRootActivity());
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
+        assertTrue(task.getBounds().width() < task.getBounds().height());
+        assertEquals(fullScreenBounds.height(), task.getBounds().height());
+
+        // Top activity gets used
+        ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build();
+        assertEquals(top, task.getTopActivity());
+        setActivityRequestedOrientation(top, SCREEN_ORIENTATION_LANDSCAPE);
+        assertTrue(task.getBounds().width() > task.getBounds().height());
+        assertEquals(task.getBounds().width(), fullScreenBounds.width());
+
+        // Setting app to unspecified restores
+        setActivityRequestedOrientation(top, SCREEN_ORIENTATION_UNSPECIFIED);
+        assertEquals(fullScreenBounds, task.getBounds());
+
+        // Setting app to fixed landscape and changing display
+        setActivityRequestedOrientation(top, SCREEN_ORIENTATION_LANDSCAPE);
+        // simulate display orientation changing (normally done via DisplayContent)
+        display.getRequestedOverrideConfiguration().orientation =
+                Configuration.ORIENTATION_PORTRAIT;
+        display.setBounds(fullScreenBoundsPort);
+        assertTrue(task.getBounds().width() > task.getBounds().height());
+        assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
+
+        // in FREEFORM, no constraint
+        final Rect freeformBounds = new Rect(display.getBounds());
+        freeformBounds.inset((int) (freeformBounds.width() * 0.2),
+                (int) (freeformBounds.height() * 0.2));
+        stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        task.setBounds(freeformBounds);
+        assertEquals(freeformBounds, task.getBounds());
+
+        // FULLSCREEN letterboxes bounds
+        stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        assertTrue(task.getBounds().width() > task.getBounds().height());
+        assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
+
+        // FREEFORM restores bounds as before
+        stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        assertEquals(freeformBounds, task.getBounds());
+    }
+
+    @Test
+    public void testUpdatesForcedOrientationInBackground() {
+        final DisplayInfo info = new DisplayInfo();
+        info.logicalWidth = 1920;
+        info.logicalHeight = 1080;
+        final ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
+        doCallRealMethod().when(display.mDisplayContent).setDisplayRotation(any());
+        display.mDisplayContent.setDisplayRotation(mock(DisplayRotation.class));
+        doCallRealMethod().when(display.mDisplayContent).onDescendantOrientationChanged(any(),
+                any());
+        doCallRealMethod().when(display.mDisplayContent).setRotation(anyInt());
+        doAnswer(invocation -> {
+            display.mDisplayContent.setRotation(Surface.ROTATION_0);
+            return null;
+        }).when(display.mDisplayContent).updateOrientationFromAppTokens(any(), any(), anyBoolean());
+
+        final ActivityStack stack = new StackBuilder(mRootActivityContainer)
+                .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
+        final TaskRecord task = stack.getChildAt(0);
+        final ActivityRecord activity = task.getRootActivity();
+
+        // Wire up app window token and task.
+        doCallRealMethod().when(activity.mAppWindowToken).setOrientation(anyInt(), any(), any());
+        doCallRealMethod().when(activity.mAppWindowToken).onDescendantOrientationChanged(any(),
+                any());
+        doReturn(task.mTask).when(activity.mAppWindowToken).getParent();
+
+        // Wire up task and stack.
+        task.mTask.mTaskRecord = task;
+        doCallRealMethod().when(task.mTask).onDescendantOrientationChanged(any(), any());
+        doReturn(stack.getTaskStack()).when(task.mTask).getParent();
+
+        // Wire up stack and display content.
+        doCallRealMethod().when(stack.mTaskStack).onDescendantOrientationChanged(any(), any());
+        doReturn(display.mDisplayContent).when(stack.mTaskStack).getParent();
+
+        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+        assertTrue("Bounds of the task should be pillarboxed.",
+                task.getBounds().width() < task.getBounds().height());
+
+        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+        assertTrue("Bounds of the task should be fullscreen.",
+                task.getBounds().equals(new Rect(0, 0, 1920, 1080)));
+    }
+
+    /** Ensures that the alias intent won't have target component resolved. */
+    @Test
+    public void testTaskIntentActivityAlias() {
+        final String aliasClassName = DEFAULT_COMPONENT_PACKAGE_NAME + ".aliasActivity";
+        final String targetClassName = DEFAULT_COMPONENT_PACKAGE_NAME + ".targetActivity";
+        final ComponentName aliasComponent =
+                new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME, aliasClassName);
+        final ComponentName targetComponent =
+                new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME, targetClassName);
+
+        final Intent intent = new Intent();
+        intent.setComponent(aliasComponent);
+        final ActivityInfo info = new ActivityInfo();
+        info.applicationInfo = new ApplicationInfo();
+        info.packageName = DEFAULT_COMPONENT_PACKAGE_NAME;
+        info.targetActivity = targetClassName;
+
+        final TaskRecord task = TaskRecord.create(mService, 1 /* taskId */, info, intent,
+                null /* taskDescription */);
+        assertEquals("The alias activity component should be saved in task intent.", aliasClassName,
+                task.intent.getComponent().getClassName());
+
+        ActivityRecord aliasActivity = new ActivityBuilder(mService).setComponent(
+                aliasComponent).setTargetActivity(targetClassName).build();
+        assertEquals("Should be the same intent filter.", true,
+                task.isSameIntentFilter(aliasActivity));
+
+        ActivityRecord targetActivity = new ActivityBuilder(mService).setComponent(
+                targetComponent).build();
+        assertEquals("Should be the same intent filter.", true,
+                task.isSameIntentFilter(targetActivity));
+
+        ActivityRecord defaultActivity = new ActivityBuilder(mService).build();
+        assertEquals("Should not be the same intent filter.", false,
+                task.isSameIntentFilter(defaultActivity));
     }
 
     private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index 946ffb60..d29e3fa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -53,7 +53,7 @@
     public void setUp() {
         final UserManager um = UserManager.get(getInstrumentation().getTargetContext());
         mTestUserId = um.getUserHandle();
-        mPersister = new TaskSnapshotPersister(userId -> FILES_DIR);
+        mPersister = new TaskSnapshotPersister(mWm, userId -> FILES_DIR);
         mLoader = new TaskSnapshotLoader(mPersister);
         mPersister.start();
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 624ef9b..ca815ec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -39,6 +39,7 @@
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.view.Surface;
+import android.view.SurfaceControl;
 
 import androidx.test.filters.SmallTest;
 
@@ -65,7 +66,7 @@
         final TaskSnapshot snapshot = new TaskSnapshot(new ComponentName("", ""), buffer,
                 ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */,
                 WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */);
-        mSurface = new TaskSnapshotSurface(mWm, new Window(), new Surface(), snapshot, "Test",
+        mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test",
                 Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds,
                 ORIENTATION_PORTRAIT);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
index f01e9f0..74ccccc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -47,8 +47,8 @@
 
     @Before
     public void setUp() throws Exception {
-        mPinnedStack = createStackControllerOnStackOnDisplay(
-                WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
+        mPinnedStack = createTaskStackOnDisplay(
+                WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
         // Stack should contain visible app window to be considered visible.
         final Task pinnedTask = createTaskInStack(mPinnedStack, 0 /* userId */);
         assertFalse(mPinnedStack.isVisible());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 7ac3318..2554237 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -20,8 +20,12 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
+import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
@@ -106,4 +110,62 @@
         assertNull(stack.getDisplayContent());
         assertNull(task.mStack);
     }
+
+    @Test
+    public void testRemoveContainer() {
+        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack);
+
+        assertNotNull(stack);
+        assertNotNull(task);
+        stack.removeIfPossible();
+        // Assert that the container was removed.
+        assertNull(stack.getParent());
+        assertEquals(0, stack.getChildCount());
+        assertNull(stack.getDisplayContent());
+        assertNull(task.getDisplayContent());
+        assertNull(task.mStack);
+    }
+
+    @Test
+    public void testRemoveContainer_deferRemoval() {
+        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack);
+
+        // Stack removal is deferred if one of its child is animating.
+        task.setLocalIsAnimating(true);
+
+        stack.removeIfPossible();
+        // For the case of deferred removal the task controller will still be connected to the its
+        // container until the stack window container is removed.
+        assertNotNull(stack.getParent());
+        assertNotEquals(0, stack.getChildCount());
+        assertNotNull(task);
+
+        stack.removeImmediately();
+        // After removing, the task will be isolated.
+        assertNull(task.getParent());
+        assertEquals(0, task.getChildCount());
+        assertNull(task.getController());
+    }
+
+    @Test
+    public void testReparent() {
+        // Create first stack on primary display.
+        final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
+        final WindowTestUtils.TestTask task1 = WindowTestUtils.createTestTask(stack1);
+        task1.mOnDisplayChangedCalled = false;
+
+        // Create second display and put second stack on it.
+        final DisplayContent dc = createNewDisplay();
+        final TaskStack stack2 = createTaskStackOnDisplay(dc);
+
+        // Reparent
+        stack1.reparent(dc.getDisplayId(), new Rect(), true /* onTop */);
+        assertEquals(dc, stack1.getDisplayContent());
+        final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
+        final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
+        assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
+        assertTrue(task1.mOnDisplayChangedCalled);
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 3e32ed3..ae211d3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -40,8 +40,7 @@
 
     @Test
     public void testRemoveContainer() {
-        final StackWindowController stackController1 =
-                createStackControllerOnDisplay(mDisplayContent);
+        final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
         final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
         final WindowTestUtils.TestAppWindowToken appToken =
                 WindowTestUtils.createAppWindowTokenInTask(mDisplayContent, task);
@@ -49,14 +48,13 @@
         task.removeIfPossible();
         // Assert that the container was removed.
         assertNull(task.getParent());
-        assertEquals(task.getChildCount(), 0);
+        assertEquals(0, task.getChildCount());
         assertNull(appToken.getParent());
     }
 
     @Test
     public void testRemoveContainer_deferRemoval() {
-        final StackWindowController stackController1 =
-                createStackControllerOnDisplay(mDisplayContent);
+        final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
         final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
         final WindowTestUtils.TestAppWindowToken appToken =
                 WindowTestUtils.createAppWindowTokenInTask(mDisplayContent, task);
@@ -67,22 +65,20 @@
         // For the case of deferred removal the task will still be connected to the its app token
         // until the task window container is removed.
         assertNotNull(task.getParent());
-        assertNotEquals(task.getChildCount(), 0);
+        assertNotEquals(0, task.getChildCount());
         assertNotNull(appToken.getParent());
 
         task.removeImmediately();
         assertNull(task.getParent());
-        assertEquals(task.getChildCount(), 0);
+        assertEquals(0, task.getChildCount());
         assertNull(appToken.getParent());
     }
 
     @Test
     public void testReparent() {
-        final StackWindowController stackController1 =
-                createStackControllerOnDisplay(mDisplayContent);
+        final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
         final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
-        final StackWindowController stackController2 =
-                createStackControllerOnDisplay(mDisplayContent);
+        final TaskStack stackController2 = createTaskStackOnDisplay(mDisplayContent);
         final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stackController2);
 
         boolean gotException = false;
@@ -93,20 +89,17 @@
         }
         assertTrue("Should not be able to reparent to the same parent", gotException);
 
-        final StackWindowController stackController3 =
-                createStackControllerOnDisplay(mDisplayContent);
-        stackController3.setContainer(null);
         gotException = false;
         try {
-            task.reparent(stackController3, 0, false/* moveParents */);
+            task.reparent(null, 0, false/* moveParents */);
         } catch (IllegalArgumentException e) {
             gotException = true;
         }
-        assertTrue("Should not be able to reparent to a stack that doesn't have a container",
+        assertTrue("Should not be able to reparent to a stack that doesn't exist",
                 gotException);
 
         task.reparent(stackController2, 0, false/* moveParents */);
-        assertEquals(stackController2.mContainer, task.getParent());
+        assertEquals(stackController2, task.getParent());
         assertEquals(0, task.positionInParent());
         assertEquals(1, task2.positionInParent());
     }
@@ -114,20 +107,17 @@
     @Test
     public void testReparent_BetweenDisplays() {
         // Create first stack on primary display.
-        final StackWindowController stack1Controller =
-                createStackControllerOnDisplay(mDisplayContent);
-        final TaskStack stack1 = stack1Controller.mContainer;
-        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack1Controller);
+        final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
+        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack1);
         task.mOnDisplayChangedCalled = false;
         assertEquals(mDisplayContent, stack1.getDisplayContent());
 
         // Create second display and put second stack on it.
         final DisplayContent dc = createNewDisplay();
-        final StackWindowController stack2Controller = createStackControllerOnDisplay(dc);
-        final TaskStack stack2 = stack2Controller.mContainer;
-        final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stack2Controller);
+        final TaskStack stack2 = createTaskStackOnDisplay(dc);
+        final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stack2);
         // Reparent and check state
-        task.reparent(stack2Controller, 0, false /* moveParents */);
+        task.reparent(stack2, 0, false /* moveParents */);
         assertEquals(stack2, task.getParent());
         assertEquals(0, task.positionInParent());
         assertEquals(1, task2.positionInParent());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
new file mode 100644
index 0000000..b151fb7
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.nullable;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.app.ActivityManagerInternal;
+import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.hardware.display.DisplayManagerInternal;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.PowerManagerInternal;
+import android.os.PowerSaveState;
+import android.os.UserHandle;
+import android.view.Display;
+import android.view.InputChannel;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.server.LocalServices;
+import com.android.server.LockGuard;
+import com.android.server.Watchdog;
+import com.android.server.input.InputManagerService;
+import com.android.server.policy.WindowManagerPolicy;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.quality.Strictness;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * A Test utility class to create a mock {@link WindowManagerService} instance for tests.
+ */
+class TestSystemServices {
+    private static StaticMockitoSession sMockitoSession;
+    private static WindowManagerService sService;
+    private static TestWindowManagerPolicy sPolicy;
+
+    static void setUpWindowManagerService() {
+        sMockitoSession = mockitoSession()
+                .spyStatic(LockGuard.class)
+                .spyStatic(Watchdog.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+
+        runWithDexmakerShareClassLoader(TestSystemServices::setUpTestWindowService);
+    }
+
+    static void tearDownWindowManagerService() {
+        waitUntilWindowManagerHandlersIdle();
+        removeLocalServices();
+        sService = null;
+        sPolicy = null;
+
+        sMockitoSession.finishMocking();
+    }
+
+    private static void setUpTestWindowService() {
+        doReturn(null).when(() -> LockGuard.installLock(any(), anyInt()));
+        doReturn(mock(Watchdog.class)).when(Watchdog::getInstance);
+
+        final Context context = getInstrumentation().getTargetContext();
+        spyOn(context);
+
+        doReturn(null).when(context)
+                .registerReceiver(nullable(BroadcastReceiver.class), any(IntentFilter.class));
+        doReturn(null).when(context)
+                .registerReceiverAsUser(any(BroadcastReceiver.class), any(UserHandle.class),
+                        any(IntentFilter.class), nullable(String.class), nullable(Handler.class));
+
+        final ContentResolver contentResolver = context.getContentResolver();
+        spyOn(contentResolver);
+        doNothing().when(contentResolver)
+                .registerContentObserver(any(Uri.class), anyBoolean(), any(ContentObserver.class),
+                        anyInt());
+
+        final AppOpsManager appOpsManager = mock(AppOpsManager.class);
+        doReturn(appOpsManager).when(context)
+                .getSystemService(eq(Context.APP_OPS_SERVICE));
+
+        removeLocalServices();
+
+        final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class);
+        LocalServices.addService(DisplayManagerInternal.class, dmi);
+
+        final PowerManagerInternal pmi = mock(PowerManagerInternal.class);
+        LocalServices.addService(PowerManagerInternal.class, pmi);
+        final PowerSaveState state = new PowerSaveState.Builder().build();
+        doReturn(state).when(pmi).getLowPowerState(anyInt());
+
+        final ActivityManagerInternal ami = mock(ActivityManagerInternal.class);
+        LocalServices.addService(ActivityManagerInternal.class, ami);
+
+        final ActivityTaskManagerInternal atmi = mock(ActivityTaskManagerInternal.class);
+        LocalServices.addService(ActivityTaskManagerInternal.class, atmi);
+        doAnswer((InvocationOnMock invocationOnMock) -> {
+            final Runnable runnable = invocationOnMock.getArgument(0);
+            if (runnable != null) {
+                runnable.run();
+            }
+            return null;
+        }).when(atmi).notifyKeyguardFlagsChanged(nullable(Runnable.class), anyInt());
+
+        final InputManagerService ims = mock(InputManagerService.class);
+        // InputChannel is final and can't be mocked.
+        final InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM);
+        if (input != null && input.length > 1) {
+            doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt());
+        }
+
+        final ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class);
+        final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock();
+        doReturn(wmLock).when(atms).getGlobalLock();
+
+        sPolicy = new TestWindowManagerPolicy(TestSystemServices::getWindowManagerService);
+        sService = WindowManagerService.main(context, ims, false, false, sPolicy, atms);
+
+        sService.onInitReady();
+
+        final Display display = sService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
+        // Display creation is driven by the ActivityManagerService via
+        // ActivityStackSupervisor. We emulate those steps here.
+        sService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class));
+    }
+
+    private static void removeLocalServices() {
+        LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+        LocalServices.removeServiceForTest(PowerManagerInternal.class);
+        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+        LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
+        LocalServices.removeServiceForTest(WindowManagerInternal.class);
+        LocalServices.removeServiceForTest(WindowManagerPolicy.class);
+    }
+
+    static WindowManagerService getWindowManagerService() {
+        return sService;
+    }
+
+    static void cleanupWindowManagerHandlers() {
+        final WindowManagerService wm = getWindowManagerService();
+        if (wm == null) {
+            return;
+        }
+        wm.mH.removeCallbacksAndMessages(null);
+        wm.mAnimationHandler.removeCallbacksAndMessages(null);
+        SurfaceAnimationThread.getHandler().removeCallbacksAndMessages(null);
+    }
+
+    static void waitUntilWindowManagerHandlersIdle() {
+        final WindowManagerService wm = getWindowManagerService();
+        if (wm == null) {
+            return;
+        }
+        // Removing delayed FORCE_GC message decreases time for waiting idle.
+        wm.mH.removeMessages(WindowManagerService.H.FORCE_GC);
+        waitHandlerIdle(wm.mH);
+        waitHandlerIdle(wm.mAnimationHandler);
+        waitHandlerIdle(SurfaceAnimationThread.getHandler());
+    }
+
+    private static void waitHandlerIdle(Handler handler) {
+        if (!handler.hasMessagesOrCallbacks()) {
+            return;
+        }
+        final CountDownLatch latch = new CountDownLatch(1);
+        // Wait for delayed messages are processed.
+        handler.getLooper().getQueue().addIdleHandler(() -> {
+            if (handler.hasMessagesOrCallbacks()) {
+                return true; // keep idle handler.
+            }
+            latch.countDown();
+            return false; // remove idle handler.
+        });
+        try {
+            latch.await();
+        } catch (InterruptedException e) {
+        }
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index d9ef10d..0a4a8a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -16,12 +16,15 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
 import static android.view.DisplayCutout.fromBoundingRect;
 import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
 
 import android.app.ActivityManager.TaskDescription;
 import android.content.res.Configuration;
@@ -58,7 +61,7 @@
         boolean mDockedResizingForTest = false;
         WindowStateWithTask(WindowManagerService wm, IWindow iWindow, WindowToken windowToken,
                 WindowManager.LayoutParams attrs, Task t) {
-            super(wm, null, iWindow, windowToken, null, 0, 0, attrs, 0, 0,
+            super(wm, mock(Session.class), iWindow, windowToken, null, 0, 0, attrs, 0, 0,
                     false /* ownerCanAddInternalSystemWindow */);
             mTask = t;
         }
@@ -113,9 +116,9 @@
 
     @Before
     public void setUp() throws Exception {
-        mWindowToken = WindowTestUtils.createTestAppWindowToken(
-                mWm.getDefaultDisplayContentLocked());
-        mStubStack = new TaskStack(mWm, 0, null);
+        mWindowToken = createAppWindowToken(mWm.getDefaultDisplayContentLocked(),
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        mStubStack = WindowTestUtils.createMockTaskStack();
     }
 
     // Do not use this function directly in the tests below. Instead, use more explicit function
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java
deleted file mode 100644
index 04e433e..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ /dev/null
@@ -1,223 +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.wm;
-
-import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityManagerInternal;
-import android.content.Context;
-import android.hardware.display.DisplayManagerInternal;
-import android.os.PowerManagerInternal;
-import android.os.PowerSaveState;
-import android.view.Display;
-import android.view.InputChannel;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-
-import com.android.server.LocalServices;
-import com.android.server.input.InputManagerService;
-import com.android.server.policy.WindowManagerPolicy;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-import org.mockito.invocation.InvocationOnMock;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A test rule that sets up a fresh WindowManagerService instance before each test and makes sure
- * to properly tear it down after.
- *
- * <p>
- * Usage:
- * <pre>
- * {@literal @}Rule
- *  public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule();
- * </pre>
- */
-public class WindowManagerServiceRule implements TestRule {
-
-    private WindowManagerService mService;
-    private TestWindowManagerPolicy mPolicy;
-    // Record all {@link SurfaceControl.Transaction} created while testing and releases native
-    // resources when test finishes.
-    private final List<WeakReference<Transaction>> mSurfaceTransactions = new ArrayList<>();
-    // Record all {@link SurfaceControl} created while testing and releases native resources when
-    // test finishes.
-    private final List<WeakReference<SurfaceControl>> mSurfaceControls = new ArrayList<>();
-
-    @Override
-    public Statement apply(Statement base, Description description) {
-        return new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                runWithDexmakerShareClassLoader(this::setUp);
-                try {
-                    base.evaluate();
-                } finally {
-                    tearDown();
-                }
-            }
-
-            private void setUp() {
-                final Context context = getInstrumentation().getTargetContext();
-
-                removeServices();
-
-                LocalServices.addService(DisplayManagerInternal.class,
-                        mock(DisplayManagerInternal.class));
-
-                LocalServices.addService(PowerManagerInternal.class,
-                        mock(PowerManagerInternal.class));
-                final PowerManagerInternal pm =
-                        LocalServices.getService(PowerManagerInternal.class);
-                doNothing().when(pm).registerLowPowerModeObserver(any());
-                PowerSaveState state = new PowerSaveState.Builder().build();
-                doReturn(state).when(pm).getLowPowerState(anyInt());
-
-                LocalServices.addService(ActivityManagerInternal.class,
-                        mock(ActivityManagerInternal.class));
-                LocalServices.addService(ActivityTaskManagerInternal.class,
-                        mock(ActivityTaskManagerInternal.class));
-                final ActivityTaskManagerInternal atm =
-                        LocalServices.getService(ActivityTaskManagerInternal.class);
-                doAnswer((InvocationOnMock invocationOnMock) -> {
-                    final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
-                    if (runnable != null) {
-                        runnable.run();
-                    }
-                    return null;
-                }).when(atm).notifyKeyguardFlagsChanged(any(), anyInt());
-
-                InputManagerService ims = mock(InputManagerService.class);
-                // InputChannel is final and can't be mocked.
-                InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM);
-                if (input != null && input.length > 1) {
-                    doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt());
-                }
-                ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class);
-                when(atms.getGlobalLock()).thenReturn(new WindowManagerGlobalLock());
-
-                mService = WindowManagerService.main(context, ims, false, false,
-                        mPolicy = new TestWindowManagerPolicy(
-                                WindowManagerServiceRule.this::getWindowManagerService), atms);
-                mService.mTransactionFactory = () -> {
-                    final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
-                    mSurfaceTransactions.add(new WeakReference<>(transaction));
-                    return transaction;
-                };
-                mService.mSurfaceBuilderFactory = session -> new SurfaceControl.Builder(session) {
-                    @Override
-                    public SurfaceControl build() {
-                        final SurfaceControl control = super.build();
-                        mSurfaceControls.add(new WeakReference<>(control));
-                        return control;
-                    }
-                };
-
-                mService.onInitReady();
-
-                final Display display = mService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
-                // Display creation is driven by the ActivityManagerService via
-                // ActivityStackSupervisor. We emulate those steps here.
-                mService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class));
-            }
-
-            private void removeServices() {
-                LocalServices.removeServiceForTest(DisplayManagerInternal.class);
-                LocalServices.removeServiceForTest(PowerManagerInternal.class);
-                LocalServices.removeServiceForTest(ActivityManagerInternal.class);
-                LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
-                LocalServices.removeServiceForTest(WindowManagerInternal.class);
-                LocalServices.removeServiceForTest(WindowManagerPolicy.class);
-            }
-
-            private void tearDown() {
-                cancelAllPendingAnimations();
-                waitUntilWindowManagerHandlersIdle();
-                destroyAllSurfaceTransactions();
-                destroyAllSurfaceControls();
-                removeServices();
-                mService = null;
-                mPolicy = null;
-            }
-        };
-    }
-
-    WindowManagerService getWindowManagerService() {
-        return mService;
-    }
-
-    private void cancelAllPendingAnimations() {
-        for (final WeakReference<SurfaceControl> reference : mSurfaceControls) {
-            final SurfaceControl sc = reference.get();
-            if (sc != null) {
-                mService.mSurfaceAnimationRunner.onAnimationCancelled(sc);
-            }
-        }
-    }
-
-    void waitUntilWindowManagerHandlersIdle() {
-        final WindowManagerService wm = getWindowManagerService();
-        if (wm == null) {
-            return;
-        }
-        wm.mH.removeCallbacksAndMessages(null);
-        wm.mAnimationHandler.removeCallbacksAndMessages(null);
-        SurfaceAnimationThread.getHandler().removeCallbacksAndMessages(null);
-        wm.mH.runWithScissors(() -> { }, 0);
-        wm.mAnimationHandler.runWithScissors(() -> { }, 0);
-        SurfaceAnimationThread.getHandler().runWithScissors(() -> { }, 0);
-    }
-
-    private void destroyAllSurfaceTransactions() {
-        for (final WeakReference<Transaction> reference : mSurfaceTransactions) {
-            final Transaction transaction = reference.get();
-            if (transaction != null) {
-                reference.clear();
-                transaction.close();
-            }
-        }
-    }
-
-    private void destroyAllSurfaceControls() {
-        for (final WeakReference<SurfaceControl> reference : mSurfaceControls) {
-            final SurfaceControl control = reference.get();
-            if (control != null) {
-                reference.clear();
-                control.destroy();
-            }
-        }
-    }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRuleTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRuleTest.java
deleted file mode 100644
index 343d359..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRuleTest.java
+++ /dev/null
@@ -1,44 +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.wm;
-
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.junit.Assert.assertThat;
-
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Rule;
-import org.junit.Test;
-
-/**
- * Build/InstallRun:
- *  atest FrameworksServicesTests:WindowManagerServiceRuleTest
- */
-@Presubmit
-@SmallTest
-public class WindowManagerServiceRuleTest {
-
-    @Rule
-    public final WindowManagerServiceRule mRule = new WindowManagerServiceRule();
-
-    @Test
-    public void testWindowManagerSetUp() {
-        assertThat(mRule.getWindowManagerService(), notNullValue());
-    }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 7f78034..c09cd46 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.hardware.camera2.params.OutputConfiguration.ROTATION_90;
+import static android.view.InsetsState.TYPE_TOP_BAR;
 import static android.view.Surface.ROTATION_0;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -31,6 +32,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
@@ -56,6 +58,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.Size;
 import android.view.DisplayCutout;
+import android.view.InsetsSource;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 
@@ -326,6 +329,20 @@
     }
 
     @Test
+    public void testVisibleWithInsetsProvider() throws Exception {
+        final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar");
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        topBar.mHasSurface = true;
+        assertTrue(topBar.isVisible());
+        mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR)
+                .setWindow(topBar, null);
+        mDisplayContent.getInsetsStateController().onBarControllingWindowChanged(app);
+        mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR)
+                .onInsetsModified(app, new InsetsSource(TYPE_TOP_BAR));
+        assertFalse(topBar.isVisible());
+    }
+
+    @Test
     public void testIsSelfOrAncestorWindowAnimating() {
         final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
         final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, "child1");
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 20fc5ae..44e998b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -103,12 +103,10 @@
     }
 
     /**
-     * Creates a mock instance of {@link StackWindowController}.
+     * Creates a mock instance of {@link TestTaskStack}.
      */
-    public static StackWindowController createMockStackWindowContainerController() {
-        StackWindowController controller = mock(StackWindowController.class);
-        controller.mContainer = mock(TestTaskStack.class);
-        return controller;
+    public static TaskStack createMockTaskStack() {
+        return mock(TestTaskStack.class);
     }
 
     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
@@ -201,6 +199,11 @@
         }
 
         @Override
+        void onParentSet() {
+            // Do nothing.
+        }
+
+        @Override
         boolean isOnTop() {
             return mOnTop;
         }
@@ -283,10 +286,9 @@
         }
     }
 
-    public static TestTask createTestTask(StackWindowController stackWindowController) {
-        return new TestTask(sNextTaskId++, stackWindowController.mContainer, 0,
-                stackWindowController.mService, RESIZE_MODE_UNRESIZEABLE, false,
-                mock(TaskRecord.class));
+    public static TestTask createTestTask(TaskStack stack) {
+        return new TestTask(sNextTaskId++, stack, 0, stack.mWmService, RESIZE_MODE_UNRESIZEABLE,
+                false, mock(TaskRecord.class));
     }
 
     public static class TestIApplicationToken implements IApplicationToken {
@@ -334,5 +336,10 @@
 
             mHasSurface = hadSurface;
         }
+
+        @Override
+        void onParentSet() {
+            // Do nothing;
+        }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 5c3368b..e38118e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -41,7 +41,6 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
-import android.graphics.Rect;
 import android.hardware.display.DisplayManagerGlobal;
 import android.testing.DexmakerShareClassLoaderRule;
 import android.util.Log;
@@ -53,6 +52,7 @@
 import com.android.server.AttributeCache;
 
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Rule;
@@ -95,17 +95,22 @@
     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
             new DexmakerShareClassLoaderRule();
 
-    @Rule
-    public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule();
-
-    static WindowState.PowerManagerWrapper sPowerManagerWrapper;  // TODO(roosa): make non-static.
+    static WindowState.PowerManagerWrapper sPowerManagerWrapper;
 
     @BeforeClass
     public static void setUpOnceBase() {
         AttributeCache.init(getInstrumentation().getTargetContext());
+
+        TestSystemServices.setUpWindowManagerService();
+
         sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
     }
 
+    @AfterClass
+    public static void tearDonwOnceBase() {
+        TestSystemServices.tearDownWindowManagerService();
+    }
+
     @Before
     public void setUpBase() {
         // If @Before throws an exception, the error isn't logged. This will make sure any failures
@@ -115,7 +120,7 @@
 
             final Context context = getInstrumentation().getTargetContext();
 
-            mWm = mWmRule.getWindowManagerService();
+            mWm = TestSystemServices.getWindowManagerService();
             beforeCreateDisplay();
 
             context.getDisplay().getDisplayInfo(mDisplayInfo);
@@ -192,8 +197,8 @@
                 mDisplayContent.mInputMethodTarget = null;
             }
 
-            // Wait until everything is really cleaned up.
-            waitUntilHandlersIdle();
+            // Cleaned up everything in Handler.
+            TestSystemServices.cleanupWindowManagerHandlers();
         } catch (Exception e) {
             Log.e(TAG, "Failed to tear down test", e);
             throw e;
@@ -214,7 +219,7 @@
      * Waits until the main handler for WM has processed all messages.
      */
     void waitUntilHandlersIdle() {
-        mWmRule.waitUntilWindowManagerHandlersIdle();
+        TestSystemServices.waitUntilWindowManagerHandlersIdle();
     }
 
     private WindowToken createWindowToken(
@@ -234,8 +239,7 @@
 
     WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
             windowingMode, int activityType) {
-        final TaskStack stack = createStackControllerOnStackOnDisplay(windowingMode, activityType,
-                dc).mContainer;
+        final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
         final Task task = createTaskInStack(stack, 0 /* userId */);
         final WindowTestUtils.TestAppWindowToken appWindowToken =
                 WindowTestUtils.createTestAppWindowToken(dc);
@@ -251,6 +255,14 @@
         }
     }
 
+    WindowState createWindow(WindowState parent, int type, String name, int ownerId) {
+        synchronized (mWm.mGlobalLock) {
+            return (parent == null)
+                    ? createWindow(parent, type, mDisplayContent, name, ownerId)
+                    : createWindow(parent, type, parent.mToken, name, ownerId);
+        }
+    }
+
     WindowState createWindowOnStack(WindowState parent, int windowingMode, int activityType,
             int type, DisplayContent dc, String name) {
         synchronized (mWm.mGlobalLock) {
@@ -271,7 +283,16 @@
         synchronized (mWm.mGlobalLock) {
             final WindowToken token = createWindowToken(
                     dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
-            return createWindow(parent, type, token, name);
+            return createWindow(parent, type, token, name, 0 /* ownerId */);
+        }
+    }
+
+    WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
+            int ownerId) {
+        synchronized (mWm.mGlobalLock) {
+            final WindowToken token = createWindowToken(
+                    dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
+            return createWindow(parent, type, token, name, ownerId);
         }
     }
 
@@ -293,6 +314,14 @@
     }
 
     WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
+            int ownerId) {
+        synchronized (mWm.mGlobalLock) {
+            return createWindow(parent, type, token, name, ownerId,
+                    false /* ownerCanAddInternalSystemWindow */);
+        }
+    }
+
+    WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
             int ownerId, boolean ownerCanAddInternalSystemWindow) {
         return createWindow(parent, type, token, name, ownerId, ownerCanAddInternalSystemWindow,
                 mWm, mMockSession, mIWindow);
@@ -319,28 +348,20 @@
     /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
     TaskStack createTaskStackOnDisplay(DisplayContent dc) {
         synchronized (mWm.mGlobalLock) {
-            return createStackControllerOnDisplay(dc).mContainer;
+            return createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
         }
     }
 
-    StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
-        synchronized (mWm.mGlobalLock) {
-            return createStackControllerOnStackOnDisplay(
-                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
-        }
-    }
-
-    StackWindowController createStackControllerOnStackOnDisplay(
-            int windowingMode, int activityType, DisplayContent dc) {
+    TaskStack createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
         synchronized (mWm.mGlobalLock) {
             final Configuration overrideConfig = new Configuration();
             overrideConfig.windowConfiguration.setWindowingMode(windowingMode);
             overrideConfig.windowConfiguration.setActivityType(activityType);
             final int stackId = ++sNextStackId;
-            final StackWindowController controller = new StackWindowController(stackId, null,
-                    dc.getDisplayId(), true /* onTop */, new Rect(), mWm);
-            controller.onRequestedOverrideConfigurationChanged(overrideConfig);
-            return controller;
+            final TaskStack stack = new TaskStack(mWm, stackId, mock(ActivityStack.class));
+            dc.setStackOnDisplay(stackId, true, stack);
+            stack.onRequestedOverrideConfigurationChanged(overrideConfig);
+            return stack;
         }
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
new file mode 100644
index 0000000..8d83497
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
+import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+import android.util.proto.ProtoOutputStream;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+
+/**
+ * Test class for {@link WindowTraceBuffer} and {@link WindowTraceQueueBuffer}.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:WindowTraceBufferTest
+ */
+@SmallTest
+@Presubmit
+public class WindowTraceBufferTest {
+    private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+    private File mFile;
+
+    @Before
+    public void setUp() throws Exception {
+        final Context testContext = getInstrumentation().getContext();
+        mFile = testContext.getFileStreamPath("tracing_test.dat");
+        mFile.delete();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mFile.delete();
+    }
+
+    @Test
+    public void testTraceQueueBuffer_addItem() throws Exception {
+        ProtoOutputStream toWrite1 = getDummy(1);
+        ProtoOutputStream toWrite2 = getDummy(2);
+        ProtoOutputStream toWrite3 = getDummy(3);
+        byte[] toWrite1Bytes = toWrite1.getBytes();
+        byte[] toWrite2Bytes = toWrite2.getBytes();
+        byte[] toWrite3Bytes = toWrite3.getBytes();
+
+        final int objectSize = toWrite1.getBytes().length;
+        final int bufferCapacity = objectSize * 2;
+
+        final WindowTraceBuffer buffer = buildQueueBuffer(bufferCapacity);
+
+        buffer.add(toWrite1);
+        assertTrue("First element should be in the list",
+                buffer.mBuffer.stream().anyMatch(p -> Arrays.equals(p, toWrite1Bytes)));
+
+        buffer.add(toWrite2);
+        assertTrue("First element should be in the list",
+                buffer.mBuffer.stream().anyMatch(p -> Arrays.equals(p, toWrite1Bytes)));
+        assertTrue("Second element should be in the list",
+                buffer.mBuffer.stream().anyMatch(p -> Arrays.equals(p, toWrite2Bytes)));
+
+        buffer.add(toWrite3);
+
+        assertTrue("Third element should not be in the list",
+                buffer.mBuffer.stream().noneMatch(p -> Arrays.equals(p, toWrite3Bytes)));
+
+        assertEquals("Buffer should have 2 elements", buffer.mBuffer.size(), 2);
+        assertEquals(String.format("Buffer is full, used space should be %d", bufferCapacity),
+                buffer.mBufferSize, bufferCapacity);
+        assertEquals("Buffer is full, available space should be 0",
+                buffer.getAvailableSpace(), 0);
+    }
+
+    private ProtoOutputStream getDummy(int value) {
+        ProtoOutputStream toWrite = new ProtoOutputStream();
+        toWrite.write(MAGIC_NUMBER, value);
+        toWrite.flush();
+
+        return toWrite;
+    }
+
+    private WindowTraceBuffer buildQueueBuffer(int size) throws IOException {
+        return new WindowTraceQueueBuffer(size, mFile, false);
+    }
+}
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index 8e1ede1..2ed11fe 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -23,7 +23,6 @@
 import android.os.Message;
 import android.os.SystemClock;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -62,6 +61,8 @@
 
     private static final long ONE_MINUTE = 60_000L;
 
+    private static final Integer ONE = new Integer(1);
+
     /** Collection of data for each user that has reported usage */
     @GuardedBy("mLock")
     private final SparseArray<UserData> mUsers = new SparseArray<>();
@@ -79,11 +80,11 @@
         private @UserIdInt
         int userId;
 
-        /** Set of the currently active entities */
-        private final ArraySet<String> currentlyActive = new ArraySet<>();
+        /** Count of the currently active entities */
+        public final ArrayMap<String, Integer> currentlyActive = new ArrayMap<>();
 
         /** Map from entity name for quick lookup */
-        private final ArrayMap<String, ArrayList<UsageGroup>> observedMap = new ArrayMap<>();
+        public final ArrayMap<String, ArrayList<UsageGroup>> observedMap = new ArrayMap<>();
 
         private UserData(@UserIdInt int userId) {
             this.userId = userId;
@@ -94,7 +95,7 @@
             // TODO: Consider using a bloom filter here if number of actives becomes large
             final int size = entities.length;
             for (int i = 0; i < size; i++) {
-                if (currentlyActive.contains(entities[i])) {
+                if (currentlyActive.containsKey(entities[i])) {
                     return true;
                 }
             }
@@ -137,7 +138,7 @@
             pw.print(" Currently Active:");
             final int nActive = currentlyActive.size();
             for (int i = 0; i < nActive; i++) {
-                pw.print(currentlyActive.valueAt(i));
+                pw.print(currentlyActive.keyAt(i));
                 pw.print(", ");
             }
             pw.println();
@@ -233,6 +234,7 @@
         protected long mUsageTimeMs;
         protected int mActives;
         protected long mLastKnownUsageTimeMs;
+        protected long mLastUsageEndTimeMs;
         protected WeakReference<UserData> mUserRef;
         protected WeakReference<ObserverAppData> mObserverAppRef;
         protected PendingIntent mLimitReachedCallback;
@@ -271,9 +273,15 @@
         @GuardedBy("mLock")
         void noteUsageStart(long startTimeMs, long currentTimeMs) {
             if (mActives++ == 0) {
+                // If last known usage ended after the start of this usage, there is overlap
+                // between the last usage session and this one. Avoid double counting by only
+                // counting from the end of the last session. This has a rare side effect that some
+                // usage will not be accounted for if the previous session started and stopped
+                // within this current usage.
+                startTimeMs = mLastUsageEndTimeMs > startTimeMs ? mLastUsageEndTimeMs : startTimeMs;
                 mLastKnownUsageTimeMs = startTimeMs;
                 final long timeRemaining =
-                        mTimeLimitMs - mUsageTimeMs + currentTimeMs - startTimeMs;
+                        mTimeLimitMs - mUsageTimeMs - currentTimeMs + startTimeMs;
                 if (timeRemaining > 0) {
                     if (DEBUG) {
                         Slog.d(TAG, "Posting timeout for " + mObserverId + " for "
@@ -287,7 +295,7 @@
                     mActives = mObserved.length;
                     final UserData user = mUserRef.get();
                     if (user == null) return;
-                    final Object[] array = user.currentlyActive.toArray();
+                    final Object[] array = user.currentlyActive.keySet().toArray();
                     Slog.e(TAG,
                             "Too many noted usage starts! Observed entities: " + Arrays.toString(
                                     mObserved) + "   Active Entities: " + Arrays.toString(array));
@@ -300,6 +308,8 @@
             if (--mActives == 0) {
                 final boolean limitNotCrossed = mUsageTimeMs < mTimeLimitMs;
                 mUsageTimeMs += stopTimeMs - mLastKnownUsageTimeMs;
+
+                mLastUsageEndTimeMs = stopTimeMs;
                 if (limitNotCrossed && mUsageTimeMs >= mTimeLimitMs) {
                     // Crossed the limit
                     if (DEBUG) Slog.d(TAG, "MTB informing group obs=" + mObserverId);
@@ -312,7 +322,7 @@
                     mActives = 0;
                     final UserData user = mUserRef.get();
                     if (user == null) return;
-                    final Object[] array = user.currentlyActive.toArray();
+                    final Object[] array = user.currentlyActive.keySet().toArray();
                     Slog.e(TAG,
                             "Too many noted usage stops! Observed entities: " + Arrays.toString(
                                     mObserved) + "   Active Entities: " + Arrays.toString(array));
@@ -409,7 +419,6 @@
     }
 
     class SessionUsageGroup extends UsageGroup {
-        private long mLastUsageEndTimeMs;
         private long mNewSessionThresholdMs;
         private PendingIntent mSessionEndCallback;
 
@@ -451,7 +460,6 @@
         public void noteUsageStop(long stopTimeMs) {
             super.noteUsageStop(stopTimeMs);
             if (mActives == 0) {
-                mLastUsageEndTimeMs = stopTimeMs;
                 if (mUsageTimeMs >= mTimeLimitMs) {
                     // Usage has ended. Schedule the session end callback to be triggered once
                     // the new session threshold has been reached
@@ -467,7 +475,10 @@
             UserData user = mUserRef.get();
             if (user == null) return;
             if (mListener != null) {
-                mListener.onSessionEnd(mObserverId, user.userId, mUsageTimeMs, mSessionEndCallback);
+                mListener.onSessionEnd(mObserverId,
+                                       user.userId,
+                                       mUsageTimeMs,
+                                       mSessionEndCallback);
             }
         }
 
@@ -599,7 +610,7 @@
         // TODO: Consider using a bloom filter here if number of actives becomes large
         final int size = group.mObserved.length;
         for (int i = 0; i < size; i++) {
-            if (user.currentlyActive.contains(group.mObserved[i])) {
+            if (user.currentlyActive.containsKey(group.mObserved[i])) {
                 // Entity is currently active. Start group's usage.
                 group.noteUsageStart(currentTimeMs);
             }
@@ -717,21 +728,28 @@
     /**
      * Called when an entity becomes active.
      *
-     * @param name   The entity that became active
-     * @param userId The user
+     * @param name      The entity that became active
+     * @param userId    The user
+     * @param timeAgoMs Time since usage was started
      */
-    public void noteUsageStart(String name, int userId) throws IllegalArgumentException {
+    public void noteUsageStart(String name, int userId, long timeAgoMs)
+            throws IllegalArgumentException {
         synchronized (mLock) {
             UserData user = getOrCreateUserDataLocked(userId);
             if (DEBUG) Slog.d(TAG, "Usage entity " + name + " became active");
-            if (user.currentlyActive.contains(name)) {
-                throw new IllegalArgumentException(
-                        "Unable to start usage for " + name + ", already in use");
+
+            final int index = user.currentlyActive.indexOfKey(name);
+            if (index >= 0) {
+                final Integer count = user.currentlyActive.valueAt(index);
+                if (count != null) {
+                    // There are multiple instances of this entity. Just increment the count.
+                    user.currentlyActive.setValueAt(index, count + 1);
+                    return;
+                }
             }
             final long currentTime = getUptimeMillis();
 
-            // Add to the list of active entities
-            user.currentlyActive.add(name);
+            user.currentlyActive.put(name, ONE);
 
             ArrayList<UsageGroup> groups = user.observedMap.get(name);
             if (groups == null) return;
@@ -739,12 +757,22 @@
             final int size = groups.size();
             for (int i = 0; i < size; i++) {
                 UsageGroup group = groups.get(i);
-                group.noteUsageStart(currentTime);
+                group.noteUsageStart(currentTime - timeAgoMs, currentTime);
             }
         }
     }
 
     /**
+     * Called when an entity becomes active.
+     *
+     * @param name   The entity that became active
+     * @param userId The user
+     */
+    public void noteUsageStart(String name, int userId) throws IllegalArgumentException {
+        noteUsageStart(name, userId, 0);
+    }
+
+    /**
      * Called when an entity becomes inactive.
      *
      * @param name   The entity that became inactive
@@ -754,10 +782,21 @@
         synchronized (mLock) {
             UserData user = getOrCreateUserDataLocked(userId);
             if (DEBUG) Slog.d(TAG, "Usage entity " + name + " became inactive");
-            if (!user.currentlyActive.remove(name)) {
+
+            final int index = user.currentlyActive.indexOfKey(name);
+            if (index < 0) {
                 throw new IllegalArgumentException(
                         "Unable to stop usage for " + name + ", not in use");
             }
+
+            final Integer count = user.currentlyActive.valueAt(index);
+            if (!count.equals(ONE)) {
+                // There are multiple instances of this entity. Just decrement the count.
+                user.currentlyActive.setValueAt(index, count - 1);
+                return;
+            }
+
+            user.currentlyActive.removeAt(index);
             final long currentTime = getUptimeMillis();
 
             // Check if any of the groups need to watch for this entity
@@ -769,6 +808,7 @@
                 UsageGroup group = groups.get(i);
                 group.noteUsageStop(currentTime);
             }
+
         }
     }
 
@@ -780,7 +820,8 @@
 
     @GuardedBy("mLock")
     private void postInformSessionEndListenerLocked(SessionUsageGroup group, long timeout) {
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(MyHandler.MSG_INFORM_SESSION_END, group),
+        mHandler.sendMessageDelayed(
+                mHandler.obtainMessage(MyHandler.MSG_INFORM_SESSION_END, group),
                 timeout);
     }
 
@@ -800,7 +841,27 @@
         mHandler.removeMessages(MyHandler.MSG_CHECK_TIMEOUT, group);
     }
 
-    void dump(PrintWriter pw) {
+    void dump(String[] args, PrintWriter pw) {
+        if (args != null) {
+            for (int i = 0; i < args.length; i++) {
+                String arg = args[i];
+                if ("actives".equals(arg)) {
+                    synchronized (mLock) {
+                        final int nUsers = mUsers.size();
+                        for (int user = 0; user < nUsers; user++) {
+                            final ArrayMap<String, Integer> actives =
+                                    mUsers.valueAt(user).currentlyActive;
+                            final int nActive = actives.size();
+                            for (int active = 0; active < nActive; active++) {
+                                pw.println(actives.keyAt(active));
+                            }
+                        }
+                    }
+                    return;
+                }
+            }
+        }
+
         synchronized (mLock) {
             pw.println("\n  App Time Limits");
             final int nUsers = mUsers.size();
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index 94cc650..f1ddfe4 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -22,6 +22,7 @@
 import static android.app.usage.UsageEvents.Event.CONFIGURATION_CHANGE;
 import static android.app.usage.UsageEvents.Event.CONTINUE_PREVIOUS_DAY;
 import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE;
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
 import static android.app.usage.UsageEvents.Event.END_OF_DAY;
 import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK;
 import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START;
@@ -66,7 +67,7 @@
     public final ArrayMap<String, UsageStats> packageStats = new ArrayMap<>();
     public final ArrayMap<Configuration, ConfigurationStats> configurations = new ArrayMap<>();
     public Configuration activeConfiguration;
-    public EventList events;
+    public EventList events = new EventList();
 
     // A string cache. This is important as when we're parsing XML files, we don't want to
     // keep hundreds of strings that have the same contents. We will read the string
@@ -112,6 +113,9 @@
 
     }
 
+    public IntervalStats() {
+    }
+
     /**
      * Gets the UsageStats object for the given package, or creates one and adds it internally.
      */
@@ -214,6 +218,14 @@
                 case (int) IntervalStatsProto.Event.INSTANCE_ID:
                     event.mInstanceId = parser.readInt(IntervalStatsProto.Event.INSTANCE_ID);
                     break;
+                case (int) IntervalStatsProto.Event.TASK_ROOT_PACKAGE_INDEX:
+                    event.mTaskRootPackage = getCachedStringRef(stringPool.get(
+                            parser.readInt(IntervalStatsProto.Event.TASK_ROOT_PACKAGE_INDEX) - 1));
+                    break;
+                case (int) IntervalStatsProto.Event.TASK_ROOT_CLASS_INDEX:
+                    event.mTaskRootClass = getCachedStringRef(stringPool.get(
+                            parser.readInt(IntervalStatsProto.Event.TASK_ROOT_CLASS_INDEX) - 1));
+                    break;
                 case ProtoInputStream.NO_MORE_FIELDS:
                     // Handle default values for certain events types
                     switch (event.mEventType) {
@@ -253,6 +265,7 @@
             case ROLLOVER_FOREGROUND_SERVICE:
             case CONTINUE_PREVIOUS_DAY:
             case CONTINUING_FOREGROUND_SERVICE:
+            case DEVICE_SHUTDOWN:
                 return true;
         }
         return false;
@@ -281,8 +294,9 @@
     @VisibleForTesting
     public void update(String packageName, String className, long timeStamp, int eventType,
             int instanceId) {
-        if (eventType == FLUSH_TO_DISK) {
-            // FLUSH_TO_DISK are sent to all packages.
+        if (eventType == DEVICE_SHUTDOWN
+                || eventType == FLUSH_TO_DISK) {
+            // DEVICE_SHUTDOWN and FLUSH_TO_DISK are sent to all packages.
             final int size = packageStats.size();
             for (int i = 0; i < size; i++) {
                 UsageStats usageStats = packageStats.valueAt(i);
@@ -321,14 +335,17 @@
      */
     @VisibleForTesting
     public void addEvent(Event event) {
-        if (events == null) {
-            events = new EventList();
-        }
         // Cache common use strings
         event.mPackage = getCachedStringRef(event.mPackage);
         if (event.mClass != null) {
             event.mClass = getCachedStringRef(event.mClass);
         }
+        if (event.mTaskRootPackage != null) {
+            event.mTaskRootPackage = getCachedStringRef(event.mTaskRootPackage);
+        }
+        if (event.mTaskRootClass != null) {
+            event.mTaskRootClass = getCachedStringRef(event.mTaskRootClass);
+        }
         if (event.mEventType == NOTIFICATION_INTERRUPTION) {
             event.mNotificationChannelId = getCachedStringRef(event.mNotificationChannelId);
         }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProto.java b/services/usage/java/com/android/server/usage/UsageStatsProto.java
index d706537..11d49eb 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProto.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProto.java
@@ -442,6 +442,28 @@
         proto.write(IntervalStatsProto.Event.FLAGS, event.mFlags);
         proto.write(IntervalStatsProto.Event.TYPE, event.mEventType);
         proto.write(IntervalStatsProto.Event.INSTANCE_ID, event.mInstanceId);
+        if (event.mTaskRootPackage != null) {
+            final int taskRootPackageIndex = stats.mStringCache.indexOf(event.mTaskRootPackage);
+            if (taskRootPackageIndex >= 0) {
+                proto.write(IntervalStatsProto.Event.TASK_ROOT_PACKAGE_INDEX,
+                        taskRootPackageIndex + 1);
+            } else {
+                // Task root package not in Stringpool for some reason.
+                Slog.w(TAG, "Usage event task root package name (" + event.mTaskRootPackage
+                        + ") not found in IntervalStats string cache");
+            }
+        }
+        if (event.mTaskRootClass != null) {
+            final int taskRootClassIndex = stats.mStringCache.indexOf(event.mTaskRootClass);
+            if (taskRootClassIndex >= 0) {
+                proto.write(IntervalStatsProto.Event.TASK_ROOT_CLASS_INDEX,
+                        taskRootClassIndex + 1);
+            } else {
+                // Task root class not in Stringpool for some reason.
+                Slog.w(TAG, "Usage event task root class name (" + event.mTaskRootClass
+                        + ") not found in IntervalStats string cache");
+            }
+        }
         switch (event.mEventType) {
             case UsageEvents.Event.CONFIGURATION_CHANGE:
                 if (event.mConfiguration != null) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 57dc08f..6ad698b 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -18,9 +18,12 @@
 
 import static android.app.usage.UsageEvents.Event.CHOOSER_ACTION;
 import static android.app.usage.UsageEvents.Event.CONFIGURATION_CHANGE;
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
 import static android.app.usage.UsageEvents.Event.FLUSH_TO_DISK;
 import static android.app.usage.UsageEvents.Event.NOTIFICATION_INTERRUPTION;
 import static android.app.usage.UsageEvents.Event.SHORTCUT_INVOCATION;
+import static android.app.usage.UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY;
+import static android.app.usage.UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVITY;
 
 import android.Manifest;
 import android.app.ActivityManager;
@@ -38,6 +41,7 @@
 import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManager.StandbyBuckets;
+import android.app.usage.UsageStatsManager.UsageSource;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -53,6 +57,7 @@
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.IDeviceIdleController;
 import android.os.Looper;
 import android.os.Message;
@@ -63,6 +68,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -105,6 +111,8 @@
     private static final boolean ENABLE_KERNEL_UPDATES = true;
     private static final File KERNEL_COUNTER_FILE = new File("/proc/uid_procstat/set");
 
+    private static final char TOKEN_DELIMITER = '/';
+
     // Handler message types.
     static final int MSG_REPORT_EVENT = 0;
     static final int MSG_FLUSH_TO_DISK = 1;
@@ -128,6 +136,7 @@
     private File mUsageStatsDir;
     long mRealTimeSnapshot;
     long mSystemTimeSnapshot;
+    int mUsageSource;
 
     /** Manages the standby state of apps. */
     AppStandbyController mAppStandby;
@@ -135,6 +144,10 @@
     /** Manages app time limit observers */
     AppTimeLimitController mAppTimeLimit;
 
+    final SparseArray<ArraySet<String>> mUsageReporters = new SparseArray();
+    final SparseArray<String> mVisibleActivities = new SparseArray();
+
+
     private UsageStatsManagerInternal.AppIdleStateChangeListener mStandbyChangeListener =
             new UsageStatsManagerInternal.AppIdleStateChangeListener() {
                 @Override
@@ -250,6 +263,7 @@
             } else {
                 Slog.w(TAG, "Missing procfs interface: " + KERNEL_COUNTER_FILE);
             }
+            readUsageSourceSetting();
         }
     }
 
@@ -260,6 +274,13 @@
         return mDpmInternal;
     }
 
+    private void readUsageSourceSetting() {
+        synchronized (mLock) {
+            mUsageSource = Settings.Global.getInt(getContext().getContentResolver(),
+                    Settings.Global.APP_TIME_LIMIT_USAGE_SOURCE, USAGE_SOURCE_TASK_ROOT_ACTIVITY);
+        }
+    }
+
     private class UserActionsReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -270,7 +291,7 @@
                     mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
                 }
             } else if (Intent.ACTION_USER_STARTED.equals(action)) {
-                if (userId >=0) {
+                if (userId >= 0) {
                     mAppStandby.postCheckIdleStates(userId);
                 }
             }
@@ -409,11 +430,30 @@
      */
     void shutdown() {
         synchronized (mLock) {
+            mHandler.removeMessages(MSG_REPORT_EVENT);
+            Event event = new Event(DEVICE_SHUTDOWN, SystemClock.elapsedRealtime());
+            // orderly shutdown, the last event is DEVICE_SHUTDOWN.
+            reportEventToAllUserId(event);
             flushToDiskLocked();
         }
     }
 
     /**
+     * After power button is pressed for 3.5 seconds
+     * (as defined in {@link com.android.internal.R.integer#config_veryLongPressTimeout}),
+     * report DEVICE_SHUTDOWN event and persist the database. If the power button is pressed for 10
+     * seconds and the device is shutdown, the database is already persisted and we are not losing
+     * data.
+     * This method is called from PhoneWindowManager, do not synchronize on mLock otherwise
+     * PhoneWindowManager may be blocked.
+     */
+    void prepareForPossibleShutdown() {
+        Event event = new Event(DEVICE_SHUTDOWN, SystemClock.elapsedRealtime());
+        mHandler.obtainMessage(MSG_REPORT_EVENT_TO_ALL_USERID, event).sendToTarget();
+        mHandler.sendEmptyMessage(MSG_FLUSH_TO_DISK);
+    }
+
+    /**
      * Called by the Binder stub.
      */
     void reportEvent(Event event, int userId) {
@@ -432,19 +472,64 @@
             service.reportEvent(event);
 
             mAppStandby.reportEvent(event, elapsedRealtime, userId);
-            switch (event.mEventType) {
-                case Event.ACTIVITY_RESUMED:
-                    try {
-                        mAppTimeLimit.noteUsageStart(event.getPackageName(), userId);
-                    } catch (IllegalArgumentException iae) {
-                        Slog.e(TAG, "Failed to note usage start", iae);
+
+            String packageName;
+
+            switch(mUsageSource) {
+                case USAGE_SOURCE_CURRENT_ACTIVITY:
+                    packageName = event.getPackageName();
+                    break;
+                case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
+                default:
+                    packageName = event.getTaskRootPackageName();
+                    if (packageName == null) {
+                        packageName = event.getPackageName();
                     }
                     break;
-                case Event.ACTIVITY_PAUSED:
-                    try {
-                        mAppTimeLimit.noteUsageStop(event.getPackageName(), userId);
-                    } catch (IllegalArgumentException iae) {
-                        Slog.e(TAG, "Failed to note usage stop", iae);
+            }
+
+            switch (event.mEventType) {
+                case Event.ACTIVITY_RESUMED:
+                    synchronized (mVisibleActivities) {
+                        mVisibleActivities.put(event.mInstanceId, event.getClassName());
+                        try {
+                            mAppTimeLimit.noteUsageStart(packageName, userId);
+                        } catch (IllegalArgumentException iae) {
+                            Slog.e(TAG, "Failed to note usage start", iae);
+                        }
+                    }
+                    break;
+                case Event.ACTIVITY_STOPPED:
+                case Event.ACTIVITY_DESTROYED:
+                    ArraySet<String> tokens;
+                    synchronized (mUsageReporters) {
+                        tokens = mUsageReporters.removeReturnOld(event.mInstanceId);
+                    }
+                    if (tokens != null) {
+                        synchronized (tokens) {
+                            final int size = tokens.size();
+                            // Stop usage on behalf of a UsageReporter that stopped
+                            for (int i = 0; i < size; i++) {
+                                final String token = tokens.valueAt(i);
+                                try {
+                                    mAppTimeLimit.noteUsageStop(
+                                            buildFullToken(event.getPackageName(), token), userId);
+                                } catch (IllegalArgumentException iae) {
+                                    Slog.w(TAG, "Failed to stop usage for during reporter death: "
+                                            + iae);
+                                }
+                            }
+                        }
+                    }
+
+                    synchronized (mVisibleActivities) {
+                        if (mVisibleActivities.removeReturnOld(event.mInstanceId) != null) {
+                            try {
+                                mAppTimeLimit.noteUsageStop(packageName, userId);
+                            } catch (IllegalArgumentException iae) {
+                                Slog.w(TAG, "Failed to note usage stop", iae);
+                            }
+                        }
                     }
                     break;
             }
@@ -582,7 +667,7 @@
      * Called by the Binder stub.
      */
     UsageEvents queryEventsForPackage(int userId, long beginTime, long endTime,
-            String packageName) {
+            String packageName, boolean includeTaskRoot) {
         synchronized (mLock) {
             final long timeNow = checkAndGetTimeLocked();
             if (!validRange(timeNow, beginTime, endTime)) {
@@ -591,7 +676,7 @@
 
             final UserUsageStatsService service =
                     getUserDataAndInitializeIfNeededLocked(userId, timeNow);
-            return service.queryEventsForPackage(beginTime, endTime, packageName);
+            return service.queryEventsForPackage(beginTime, endTime, packageName, includeTaskRoot);
         }
     }
 
@@ -599,6 +684,14 @@
         return beginTime <= currentTime && beginTime < endTime;
     }
 
+    private String buildFullToken(String packageName, String token) {
+        final StringBuilder sb = new StringBuilder(packageName.length() + token.length() + 1);
+        sb.append(packageName);
+        sb.append(TOKEN_DELIMITER);
+        sb.append(token);
+        return sb.toString();
+    }
+
     private void flushToDiskLocked() {
         final int userCount = mUserState.size();
         for (int i = 0; i < userCount; i++) {
@@ -627,8 +720,7 @@
                     String arg = args[i];
                     if ("--checkin".equals(arg)) {
                         checkin = true;
-                    } else
-                    if ("-c".equals(arg)) {
+                    } else if ("-c".equals(arg)) {
                         compact = true;
                     } else if ("flush".equals(arg)) {
                         flushToDiskLocked();
@@ -637,6 +729,15 @@
                     } else if ("is-app-standby-enabled".equals(arg)) {
                         pw.println(mAppStandby.mAppIdleEnabled);
                         return;
+                    } else if ("apptimelimit".equals(arg)) {
+                        if (i + 1 >= args.length) {
+                            mAppTimeLimit.dump(null, pw);
+                        } else {
+                            final String[] remainingArgs =
+                                    Arrays.copyOfRange(args, i + 1, args.length);
+                            mAppTimeLimit.dump(remainingArgs, pw);
+                        }
+                        return;
                     } else if (arg != null && !arg.startsWith("-")) {
                         // Anything else that doesn't start with '-' is a pkg to filter
                         pkg = arg;
@@ -666,7 +767,11 @@
                 mAppStandby.dumpState(args, pw);
             }
 
-            mAppTimeLimit.dump(pw);
+            idpw.println();
+            idpw.printPair("Usage Source", UsageStatsManager.usageSourceToString(mUsageSource));
+            idpw.println();
+
+            mAppTimeLimit.dump(null, pw);
         }
     }
 
@@ -736,7 +841,7 @@
             return mode == AppOpsManager.MODE_ALLOWED;
         }
 
-        private boolean hasObserverPermission(String callingPackage) {
+        private boolean hasObserverPermission() {
             final int callingUid = Binder.getCallingUid();
             DevicePolicyManagerInternal dpmInternal = getDpmInternal();
             if (callingUid == Process.SYSTEM_UID
@@ -867,10 +972,12 @@
             final int callingUserId = UserHandle.getUserId(callingUid);
 
             checkCallerIsSameApp(callingPackage);
+            final boolean includeTaskRoot = hasPermission(callingPackage);
+
             final long token = Binder.clearCallingIdentity();
             try {
                 return UsageStatsService.this.queryEventsForPackage(callingUserId, beginTime,
-                        endTime, callingPackage);
+                        endTime, callingPackage, includeTaskRoot);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -917,7 +1024,7 @@
             final long token = Binder.clearCallingIdentity();
             try {
                 return UsageStatsService.this.queryEventsForPackage(userId, beginTime,
-                        endTime, pkg);
+                        endTime, pkg, true);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -1157,7 +1264,7 @@
         public void registerAppUsageObserver(int observerId,
                 String[] packages, long timeLimitMs, PendingIntent
                 callbackIntent, String callingPackage) {
-            if (!hasObserverPermission(callingPackage)) {
+            if (!hasObserverPermission()) {
                 throw new SecurityException("Caller doesn't have OBSERVE_APP_USAGE permission");
             }
 
@@ -1180,7 +1287,7 @@
 
         @Override
         public void unregisterAppUsageObserver(int observerId, String callingPackage) {
-            if (!hasObserverPermission(callingPackage)) {
+            if (!hasObserverPermission()) {
                 throw new SecurityException("Caller doesn't have OBSERVE_APP_USAGE permission");
             }
 
@@ -1199,7 +1306,7 @@
                 long timeLimitMs, long sessionThresholdTimeMs,
                 PendingIntent limitReachedCallbackIntent, PendingIntent sessionEndCallbackIntent,
                 String callingPackage) {
-            if (!hasObserverPermission(callingPackage)) {
+            if (!hasObserverPermission()) {
                 throw new SecurityException("Caller doesn't have OBSERVE_APP_USAGE permission");
             }
 
@@ -1223,7 +1330,7 @@
 
         @Override
         public void unregisterUsageSessionObserver(int sessionObserverId, String callingPackage) {
-            if (!hasObserverPermission(callingPackage)) {
+            if (!hasObserverPermission()) {
                 throw new SecurityException("Caller doesn't have OBSERVE_APP_USAGE permission");
             }
 
@@ -1231,16 +1338,97 @@
             final int userId = UserHandle.getUserId(callingUid);
             final long token = Binder.clearCallingIdentity();
             try {
-                UsageStatsService.this.unregisterUsageSessionObserver(callingUid, sessionObserverId, userId);
+                UsageStatsService.this.unregisterUsageSessionObserver(callingUid, sessionObserverId,
+                        userId);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
         }
+
+        @Override
+        public void reportUsageStart(IBinder activity, String token, String callingPackage) {
+            reportPastUsageStart(activity, token, 0, callingPackage);
+        }
+
+        @Override
+        public void reportPastUsageStart(IBinder activity, String token, long timeAgoMs,
+                String callingPackage) {
+
+            final int callingUid = Binder.getCallingUid();
+            final int userId = UserHandle.getUserId(callingUid);
+            final long binderToken = Binder.clearCallingIdentity();
+            try {
+                ArraySet<String> tokens;
+                synchronized (mUsageReporters) {
+                    tokens = mUsageReporters.get(activity.hashCode());
+                    if (tokens == null) {
+                        tokens = new ArraySet();
+                        mUsageReporters.put(activity.hashCode(), tokens);
+                    }
+                }
+
+                synchronized (tokens) {
+                    if (!tokens.add(token)) {
+                        throw new IllegalArgumentException(token + " for " + callingPackage
+                                + " is already reported as started for this activity");
+                    }
+                }
+
+                mAppTimeLimit.noteUsageStart(buildFullToken(callingPackage, token),
+                        userId, timeAgoMs);
+            } finally {
+                Binder.restoreCallingIdentity(binderToken);
+            }
+        }
+
+        @Override
+        public void reportUsageStop(IBinder activity, String token, String callingPackage) {
+            final int callingUid = Binder.getCallingUid();
+            final int userId = UserHandle.getUserId(callingUid);
+            final long binderToken = Binder.clearCallingIdentity();
+            try {
+                ArraySet<String> tokens;
+                synchronized (mUsageReporters) {
+                    tokens = mUsageReporters.get(activity.hashCode());
+                    if (tokens == null) {
+                        throw new IllegalArgumentException(
+                                "Unknown reporter trying to stop token " + token + " for "
+                                        + callingPackage);
+                    }
+                }
+
+                synchronized (tokens) {
+                    if (!tokens.remove(token)) {
+                        throw new IllegalArgumentException(token + " for " + callingPackage
+                                + " is already reported as stopped for this activity");
+                    }
+                }
+                mAppTimeLimit.noteUsageStop(buildFullToken(callingPackage, token), userId);
+            } finally {
+                Binder.restoreCallingIdentity(binderToken);
+            }
+        }
+
+        @Override
+        public @UsageSource int getUsageSource() {
+            if (!hasObserverPermission()) {
+                throw new SecurityException("Caller doesn't have OBSERVE_APP_USAGE permission");
+            }
+            synchronized (mLock) {
+                return mUsageSource;
+            }
+        }
+
+        @Override
+        public void forceUsageSourceSettingRead() {
+            readUsageSourceSetting();
+        }
     }
 
     void registerAppUsageObserver(int callingUid, int observerId, String[] packages,
             long timeLimitMs, PendingIntent callbackIntent, int userId) {
-        mAppTimeLimit.addAppUsageObserver(callingUid, observerId, packages, timeLimitMs, callbackIntent,
+        mAppTimeLimit.addAppUsageObserver(callingUid, observerId, packages, timeLimitMs,
+                callbackIntent,
                 userId);
     }
 
@@ -1268,7 +1456,7 @@
 
         @Override
         public void reportEvent(ComponentName component, int userId, int eventType,
-                int instanceId) {
+                int instanceId, ComponentName taskRoot) {
             if (component == null) {
                 Slog.w(TAG, "Event reported without a component name");
                 return;
@@ -1278,6 +1466,13 @@
             event.mPackage = component.getPackageName();
             event.mClass = component.getClassName();
             event.mInstanceId = instanceId;
+            if (taskRoot == null) {
+                event.mTaskRootPackage = null;
+                event.mTaskRootClass = null;
+            } else {
+                event.mTaskRootPackage = taskRoot.getPackageName();
+                event.mTaskRootClass = taskRoot.getClassName();
+            }
             mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
         }
 
@@ -1369,6 +1564,11 @@
         }
 
         @Override
+        public void prepareForPossibleShutdown() {
+            UsageStatsService.this.prepareForPossibleShutdown();
+        }
+
+        @Override
         public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) {
             mAppStandby.addListener(listener);
             listener.onParoleStateChanged(isAppIdleParoleOn());
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 5128ae1..d52d32f 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.usage;
 
+import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
 import static android.app.usage.UsageStatsManager.INTERVAL_BEST;
 import static android.app.usage.UsageStatsManager.INTERVAL_COUNT;
 import static android.app.usage.UsageStatsManager.INTERVAL_DAILY;
@@ -134,6 +135,18 @@
             updateRolloverDeadline();
         }
 
+        // During system reboot, add a DEVICE_SHUTDOWN event to the end of event list, the timestamp
+        // is last time UsageStatsDatabase is persisted to disk.
+        final IntervalStats currentDailyStats = mCurrentStats[INTERVAL_DAILY];
+        if (currentDailyStats != null) {
+            final int size = currentDailyStats.events.size();
+            if (size == 0 || currentDailyStats.events.get(size - 1).mEventType != DEVICE_SHUTDOWN) {
+                // The last event in event list is not DEVICE_SHUTDOWN, then we insert one.
+                final Event event = new Event(DEVICE_SHUTDOWN, currentDailyStats.lastTimeSaved);
+                currentDailyStats.addEvent(event);
+            }
+        }
+
         if (mDatabase.isNewUpdate()) {
             notifyNewUpdate();
         }
@@ -175,7 +188,9 @@
                 // ACTIVITY_STOPPED.
                 && event.mEventType != Event.ACTIVITY_DESTROYED
                 // FLUSH_TO_DISK is a private event.
-                && event.mEventType != Event.FLUSH_TO_DISK) {
+                && event.mEventType != Event.FLUSH_TO_DISK
+                // DEVICE_SHUTDOWN is added to event list after reboot.
+                && event.mEventType != Event.DEVICE_SHUTDOWN) {
             currentDailyStats.addEvent(event);
         }
 
@@ -386,17 +401,13 @@
     }
 
     UsageEvents queryEvents(final long beginTime, final long endTime,
-            boolean obfuscateInstantApps) {
+                            boolean obfuscateInstantApps) {
         final ArraySet<String> names = new ArraySet<>();
         List<Event> results = queryStats(INTERVAL_DAILY,
                 beginTime, endTime, new StatCombiner<Event>() {
                     @Override
                     public void combine(IntervalStats stats, boolean mutable,
                             List<Event> accumulatedResult) {
-                        if (stats.events == null) {
-                            return;
-                        }
-
                         final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
                         final int size = stats.events.size();
                         for (int i = startIndex; i < size; i++) {
@@ -414,6 +425,12 @@
                             if (event.mClass != null) {
                                 names.add(event.mClass);
                             }
+                            if (event.mTaskRootPackage != null) {
+                                names.add(event.mTaskRootPackage);
+                            }
+                            if (event.mTaskRootClass != null) {
+                                names.add(event.mTaskRootClass);
+                            }
                             accumulatedResult.add(event);
                         }
                     }
@@ -425,19 +442,15 @@
 
         String[] table = names.toArray(new String[names.size()]);
         Arrays.sort(table);
-        return new UsageEvents(results, table);
+        return new UsageEvents(results, table, true);
     }
 
     UsageEvents queryEventsForPackage(final long beginTime, final long endTime,
-            final String packageName) {
+            final String packageName, boolean includeTaskRoot) {
         final ArraySet<String> names = new ArraySet<>();
         names.add(packageName);
         final List<Event> results = queryStats(INTERVAL_DAILY,
                 beginTime, endTime, (stats, mutable, accumulatedResult) -> {
-                    if (stats.events == null) {
-                        return;
-                    }
-
                     final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
                     final int size = stats.events.size();
                     for (int i = startIndex; i < size; i++) {
@@ -452,6 +465,12 @@
                         if (event.mClass != null) {
                             names.add(event.mClass);
                         }
+                        if (includeTaskRoot && event.mTaskRootPackage != null) {
+                            names.add(event.mTaskRootPackage);
+                        }
+                        if (includeTaskRoot && event.mTaskRootClass != null) {
+                            names.add(event.mTaskRootClass);
+                        }
                         accumulatedResult.add(event);
                     }
                 });
@@ -462,7 +481,7 @@
 
         final String[] table = names.toArray(new String[names.size()]);
         Arrays.sort(table);
-        return new UsageEvents(results, table);
+        return new UsageEvents(results, table, includeTaskRoot);
     }
 
     void persistActiveStats() {
@@ -677,6 +696,14 @@
             pw.printPair("instanceId", event.getInstanceId());
         }
 
+        if (event.getTaskRootPackageName() != null) {
+            pw.printPair("taskRootPackage", event.getTaskRootPackageName());
+        }
+
+        if (event.getTaskRootClassName() != null) {
+            pw.printPair("taskRootClass", event.getTaskRootClassName());
+        }
+
         if (event.mNotificationChannelId != null) {
             pw.printPair("channelId", event.mNotificationChannelId);
         }
@@ -696,10 +723,6 @@
                     @Override
                     public void combine(IntervalStats stats, boolean mutable,
                             List<Event> accumulatedResult) {
-                        if (stats.events == null) {
-                            return;
-                        }
-
                         final int startIndex = stats.events.firstIndexOnOrAfter(beginTime);
                         final int size = stats.events.size();
                         for (int i = startIndex; i < size; i++) {
@@ -925,10 +948,12 @@
                 return "SCREEN_INTERACTIVE";
             case Event.SCREEN_NON_INTERACTIVE:
                 return "SCREEN_NON_INTERACTIVE";
-            case UsageEvents.Event.KEYGUARD_SHOWN:
+            case Event.KEYGUARD_SHOWN:
                 return "KEYGUARD_SHOWN";
-            case UsageEvents.Event.KEYGUARD_HIDDEN:
+            case Event.KEYGUARD_HIDDEN:
                 return "KEYGUARD_HIDDEN";
+            case Event.DEVICE_SHUTDOWN:
+                return "DEVICE_SHUTDOWN";
             default:
                 return "UNKNOWN_TYPE_" + eventType;
         }
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index feb7b76..20855b7 100644
--- a/services/usb/Android.bp
+++ b/services/usb/Android.bp
@@ -10,6 +10,7 @@
     static_libs: [
         "android.hardware.usb-V1.0-java",
         "android.hardware.usb-V1.1-java",
+        "android.hardware.usb-V1.2-java",
         "android.hardware.usb.gadget-V1.0-java",
     ],
 }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 294b750..f1e2281 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1744,8 +1744,8 @@
                     mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
                             USB_GADGET_HAL_DEATH_COOKIE);
                     mCurrentFunctions = UsbManager.FUNCTION_NONE;
-                    mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
                     mCurrentUsbFunctionsRequested = true;
+                    mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
                 }
                 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
                 updateState(state);
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 904d55e..00c7548 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -418,12 +418,10 @@
                         parser.getRawDescriptors());
 
                 // Stats collection
-                if (parser.hasAudioInterface()) {
-                    StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, newDevice.getVendorId(),
-                            newDevice.getProductId(), parser.hasAudioInterface(),
-                            parser.hasHIDInterface(), parser.hasStorageInterface(),
-                            StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_CONNECTED, 0);
-                }
+                StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, newDevice.getVendorId(),
+                        newDevice.getProductId(), parser.hasAudioInterface(),
+                        parser.hasHIDInterface(), parser.hasStorageInterface(),
+                        StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_CONNECTED, 0);
             }
         }
 
@@ -455,14 +453,12 @@
                 if (current != null) {
                     UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress,
                             current.mDescriptors);
-                    if (parser.hasAudioInterface()) {
                         // Stats collection
-                        StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, device.getVendorId(),
-                                device.getProductId(), parser.hasAudioInterface(),
-                                parser.hasHIDInterface(),  parser.hasStorageInterface(),
-                                StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_DISCONNECTED,
-                                System.currentTimeMillis() - current.mTimestamp);
-                    }
+                    StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, device.getVendorId(),
+                            device.getProductId(), parser.hasAudioInterface(),
+                            parser.hasHIDInterface(),  parser.hasStorageInterface(),
+                            StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_DISCONNECTED,
+                            System.currentTimeMillis() - current.mTimestamp);
                 }
             } else {
                 Slog.d(TAG, "Removed device at " + deviceAddress + " was already gone");
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 6f210e3..d0b7a5e8 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -16,6 +16,8 @@
 
 package com.android.server.usb;
 
+import static android.hardware.usb.UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
+import static android.hardware.usb.UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
 import static android.hardware.usb.UsbPortStatus.MODE_DFP;
@@ -29,19 +31,23 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.hardware.usb.ParcelableUsbPort;
 import android.hardware.usb.UsbManager;
 import android.hardware.usb.UsbPort;
 import android.hardware.usb.UsbPortStatus;
-import android.hardware.usb.V1_0.IUsb;
 import android.hardware.usb.V1_0.PortRole;
 import android.hardware.usb.V1_0.PortRoleType;
-import android.hardware.usb.V1_0.PortStatus;
 import android.hardware.usb.V1_0.Status;
-import android.hardware.usb.V1_1.IUsbCallback;
 import android.hardware.usb.V1_1.PortStatus_1_1;
+import android.hardware.usb.V1_2.IUsb;
+import android.hardware.usb.V1_2.IUsbCallback;
+import android.hardware.usb.V1_2.PortStatus;
 import android.hidl.manager.V1_0.IServiceManager;
 import android.hidl.manager.V1_0.IServiceNotification;
 import android.os.Bundle;
@@ -61,6 +67,8 @@
 import android.util.StatsLog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.dump.DualDumpOutputStream;
 import com.android.server.FgThread;
@@ -85,6 +93,7 @@
     private static final String TAG = "UsbPortManager";
 
     private static final int MSG_UPDATE_PORTS = 1;
+    private static final int MSG_SYSTEM_READY = 2;
 
     // All non-trivial role combinations.
     private static final int COMBO_SOURCE_HOST =
@@ -134,6 +143,14 @@
     // Uploads logs only when the connection status is changes.
     private final HashMap<String, Boolean> mConnected = new HashMap<>();
 
+    private NotificationManager mNotificationManager;
+
+    /**
+     * If there currently is a notification about contaminated USB port shown the id of the
+     * notification, or 0 if there is none.
+     */
+    private int mIsPortContaminatedNotificationId;
+
     public UsbPortManager(Context context) {
         mContext = context;
         try {
@@ -164,6 +181,90 @@
                         "ServiceStart: Failed to query port status", e);
             }
         }
+        mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
+    }
+
+    private void updateContaminantNotification() {
+        PortInfo currentPortInfo = null;
+        Resources r = mContext.getResources();
+
+        // Not handling multiple ports here. Showing the notification
+        // for the first port that returns CONTAMINANT_PRESENCE_DETECTED.
+        for (PortInfo portInfo : mPorts.values()) {
+            if (portInfo.mUsbPortStatus.getContaminantDetectionStatus()
+                    == UsbPortStatus.CONTAMINANT_DETECTION_DETECTED) {
+                currentPortInfo = portInfo;
+                break;
+            }
+        }
+
+        if (currentPortInfo != null && mIsPortContaminatedNotificationId
+                    != SystemMessage.NOTE_USB_CONTAMINANT_DETECTED) {
+            if (mIsPortContaminatedNotificationId
+                    == SystemMessage.NOTE_USB_CONTAMINANT_NOT_DETECTED) {
+                mNotificationManager.cancelAsUser(null, mIsPortContaminatedNotificationId,
+                        UserHandle.ALL);
+            }
+
+            mIsPortContaminatedNotificationId = SystemMessage.NOTE_USB_CONTAMINANT_DETECTED;
+            int titleRes = com.android.internal.R.string.usb_contaminant_detected_title;
+            CharSequence title = r.getText(titleRes);
+            String channel = SystemNotificationChannels.ALERTS;
+            CharSequence message = r.getText(
+                    com.android.internal.R.string.usb_contaminant_detected_message);
+
+            Intent intent = new Intent();
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            intent.setClassName("com.android.systemui",
+                    "com.android.systemui.usb.UsbContaminantActivity");
+            intent.putExtra(UsbManager.EXTRA_PORT, ParcelableUsbPort.of(currentPortInfo.mUsbPort));
+
+            PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
+                                intent, 0, null, UserHandle.CURRENT);
+
+            Notification.Builder builder = new Notification.Builder(mContext, channel)
+                    .setOngoing(true)
+                    .setTicker(title)
+                    .setColor(mContext.getColor(
+                           com.android.internal.R.color
+                           .system_notification_accent_color))
+                    .setContentIntent(pi)
+                    .setContentTitle(title)
+                    .setContentText(message)
+                    .setVisibility(Notification.VISIBILITY_PUBLIC)
+                    .setSmallIcon(android.R.drawable.stat_sys_warning)
+                    .setStyle(new Notification.BigTextStyle()
+                    .bigText(message));
+            Notification notification = builder.build();
+            mNotificationManager.notifyAsUser(null, mIsPortContaminatedNotificationId, notification,
+                    UserHandle.ALL);
+        } else if (currentPortInfo == null && mIsPortContaminatedNotificationId
+                == SystemMessage.NOTE_USB_CONTAMINANT_DETECTED) {
+            mNotificationManager.cancelAsUser(null, mIsPortContaminatedNotificationId,
+                    UserHandle.ALL);
+
+            mIsPortContaminatedNotificationId = SystemMessage.NOTE_USB_CONTAMINANT_NOT_DETECTED;
+            int titleRes = com.android.internal.R.string.usb_contaminant_not_detected_title;
+            CharSequence title = r.getText(titleRes);
+            String channel = SystemNotificationChannels.ALERTS;
+            CharSequence message = r.getText(
+                    com.android.internal.R.string.usb_contaminant_not_detected_message);
+
+            Notification.Builder builder = new Notification.Builder(mContext, channel)
+                    .setSmallIcon(com.android.internal.R.drawable.ic_usb_48dp)
+                    .setTicker(title)
+                    .setColor(mContext.getColor(
+                           com.android.internal.R.color
+                           .system_notification_accent_color))
+                    .setContentTitle(title)
+                    .setContentText(message)
+                    .setVisibility(Notification.VISIBILITY_PUBLIC)
+                    .setStyle(new Notification.BigTextStyle()
+                    .bigText(message));
+            Notification notification = builder.build();
+            mNotificationManager.notifyAsUser(null, mIsPortContaminatedNotificationId, notification,
+                    UserHandle.ALL);
+        }
     }
 
     public UsbPort[] getPorts() {
@@ -184,6 +285,43 @@
         }
     }
 
+    /**
+     * Enables/disables contaminant detection.
+     *
+     * @param portId port identifier.
+     * @param enable enable contaminant detection when set to true.
+     */
+    public void enableContaminantDetection(@NonNull String portId, boolean enable,
+            @NonNull IndentingPrintWriter pw) {
+        final PortInfo portInfo = mPorts.get(portId);
+        if (portInfo == null) {
+            if (pw != null) {
+                pw.println("No such USB port: " + portId);
+            }
+            return;
+        }
+
+        if (!portInfo.mUsbPort.supportsEnableContaminantPresenceDetection()) {
+            return;
+        }
+
+        if ((enable && portInfo.mUsbPortStatus.getContaminantDetectionStatus()
+                != UsbPortStatus.CONTAMINANT_DETECTION_DISABLED) || (!enable
+                && portInfo.mUsbPortStatus.getContaminantDetectionStatus()
+                == UsbPortStatus.CONTAMINANT_DETECTION_DISABLED)
+                || (portInfo.mUsbPortStatus.getContaminantDetectionStatus()
+                == UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED)) {
+            return;
+        }
+
+        try {
+            // Oneway call into the hal
+            mProxy.enableContaminantPresenceDetection(portId, enable);
+        } catch (RemoteException e) {
+            logAndPrintException(null, "Failed to set contaminant detection", e);
+        }
+    }
+
     public void setPortRoles(String portId, int newPowerRole, int newDataRole,
             IndentingPrintWriter pw) {
         synchronized (mLock) {
@@ -371,6 +509,27 @@
         }
     }
 
+    /**
+     * Sets contaminant status for simulated USB port objects.
+     */
+    public void simulateContaminantStatus(String portId, boolean detected,
+            IndentingPrintWriter pw) {
+        synchronized (mLock) {
+            final RawPortInfo portInfo = mSimulatedPorts.get(portId);
+            if (portInfo == null) {
+                pw.println("Simulated port not found.");
+                return;
+            }
+
+            pw.println("Simulating wet port: portId=" + portId
+                    + ", wet=" + detected);
+            portInfo.contaminantDetectionStatus = detected
+                    ? UsbPortStatus.CONTAMINANT_DETECTION_DETECTED
+                    : UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED;
+            updatePortsLocked(pw, null);
+        }
+    }
+
     public void disconnectSimulatedPort(String portId, IndentingPrintWriter pw) {
         synchronized (mLock) {
             final RawPortInfo portInfo = mSimulatedPorts.get(portId);
@@ -441,7 +600,8 @@
             this.portManager = portManager;
         }
 
-        public void notifyPortStatusChange(ArrayList<PortStatus> currentPortStatus, int retval) {
+        public void notifyPortStatusChange(
+                ArrayList<android.hardware.usb.V1_0.PortStatus> currentPortStatus, int retval) {
             if (!portManager.mSystemReady) {
                 return;
             }
@@ -453,14 +613,17 @@
 
             ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
 
-            for (PortStatus current : currentPortStatus) {
+            for (android.hardware.usb.V1_0.PortStatus current : currentPortStatus) {
                 RawPortInfo temp = new RawPortInfo(current.portName,
-                        current.supportedModes, current.currentMode,
+                        current.supportedModes, CONTAMINANT_PROTECTION_NONE,
+                        current.currentMode,
                         current.canChangeMode, current.currentPowerRole,
                         current.canChangePowerRole,
-                        current.currentDataRole, current.canChangeDataRole);
+                        current.currentDataRole, current.canChangeDataRole,
+                        false, CONTAMINANT_PROTECTION_NONE,
+                        false, CONTAMINANT_DETECTION_NOT_SUPPORTED);
                 newPortInfo.add(temp);
-                logAndPrint(Log.INFO, pw, "ClientCallback: " + current.portName);
+                logAndPrint(Log.INFO, pw, "ClientCallback V1_0: " + current.portName);
             }
 
             Message message = portManager.mHandler.obtainMessage();
@@ -485,14 +648,61 @@
 
             ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
 
-            for (PortStatus_1_1 current : currentPortStatus) {
+            int numStatus = currentPortStatus.size();
+            for (int i = 0; i < numStatus; i++) {
+                PortStatus_1_1 current = currentPortStatus.get(i);
                 RawPortInfo temp = new RawPortInfo(current.status.portName,
-                        current.supportedModes, current.currentMode,
+                        current.supportedModes, CONTAMINANT_PROTECTION_NONE,
+                        current.currentMode,
                         current.status.canChangeMode, current.status.currentPowerRole,
                         current.status.canChangePowerRole,
-                        current.status.currentDataRole, current.status.canChangeDataRole);
+                        current.status.currentDataRole, current.status.canChangeDataRole,
+                        false, CONTAMINANT_PROTECTION_NONE,
+                        false, CONTAMINANT_DETECTION_NOT_SUPPORTED);
                 newPortInfo.add(temp);
-                logAndPrint(Log.INFO, pw, "ClientCallback: " + current.status.portName);
+                logAndPrint(Log.INFO, pw, "ClientCallback V1_1: " + current.status.portName);
+            }
+
+            Message message = portManager.mHandler.obtainMessage();
+            Bundle bundle = new Bundle();
+            bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
+            message.what = MSG_UPDATE_PORTS;
+            message.setData(bundle);
+            portManager.mHandler.sendMessage(message);
+        }
+
+        public void notifyPortStatusChange_1_2(
+                ArrayList<PortStatus> currentPortStatus, int retval) {
+            if (!portManager.mSystemReady) {
+                return;
+            }
+
+            if (retval != Status.SUCCESS) {
+                logAndPrint(Log.ERROR, pw, "port status enquiry failed");
+                return;
+            }
+
+            ArrayList<RawPortInfo> newPortInfo = new ArrayList<>();
+
+            int numStatus = currentPortStatus.size();
+            for (int i = 0; i < numStatus; i++) {
+                PortStatus current = currentPortStatus.get(i);
+                RawPortInfo temp = new RawPortInfo(current.status_1_1.status.portName,
+                        current.status_1_1.supportedModes,
+                        current.supportedContaminantProtectionModes,
+                        current.status_1_1.currentMode,
+                        current.status_1_1.status.canChangeMode,
+                        current.status_1_1.status.currentPowerRole,
+                        current.status_1_1.status.canChangePowerRole,
+                        current.status_1_1.status.currentDataRole,
+                        current.status_1_1.status.canChangeDataRole,
+                        current.supportsEnableContaminantPresenceProtection,
+                        current.contaminantProtectionStatus,
+                        current.supportsEnableContaminantPresenceDetection,
+                        current.contaminantDetectionStatus);
+                newPortInfo.add(temp);
+                logAndPrint(Log.INFO, pw, "ClientCallback V1_2: "
+                        + current.status_1_1.status.portName);
             }
 
             Message message = portManager.mHandler.obtainMessage();
@@ -573,16 +783,26 @@
             for (int i = 0; i < count; i++) {
                 final RawPortInfo portInfo = mSimulatedPorts.valueAt(i);
                 addOrUpdatePortLocked(portInfo.portId, portInfo.supportedModes,
+                        portInfo.supportedContaminantProtectionModes,
                         portInfo.currentMode, portInfo.canChangeMode,
                         portInfo.currentPowerRole, portInfo.canChangePowerRole,
-                        portInfo.currentDataRole, portInfo.canChangeDataRole, pw);
+                        portInfo.currentDataRole, portInfo.canChangeDataRole,
+                        portInfo.supportsEnableContaminantPresenceProtection,
+                        portInfo.contaminantProtectionStatus,
+                        portInfo.supportsEnableContaminantPresenceDetection,
+                        portInfo.contaminantDetectionStatus, pw);
             }
         } else {
             for (RawPortInfo currentPortInfo : newPortInfo) {
                 addOrUpdatePortLocked(currentPortInfo.portId, currentPortInfo.supportedModes,
+                        currentPortInfo.supportedContaminantProtectionModes,
                         currentPortInfo.currentMode, currentPortInfo.canChangeMode,
                         currentPortInfo.currentPowerRole, currentPortInfo.canChangePowerRole,
-                        currentPortInfo.currentDataRole, currentPortInfo.canChangeDataRole, pw);
+                        currentPortInfo.currentDataRole, currentPortInfo.canChangeDataRole,
+                        currentPortInfo.supportsEnableContaminantPresenceProtection,
+                        currentPortInfo.contaminantProtectionStatus,
+                        currentPortInfo.supportsEnableContaminantPresenceDetection,
+                        currentPortInfo.contaminantDetectionStatus, pw);
             }
         }
 
@@ -608,12 +828,16 @@
         }
     }
 
-
     // Must only be called by updatePortsLocked.
     private void addOrUpdatePortLocked(String portId, int supportedModes,
+            int supportedContaminantProtectionModes,
             int currentMode, boolean canChangeMode,
             int currentPowerRole, boolean canChangePowerRole,
             int currentDataRole, boolean canChangeDataRole,
+            boolean supportsEnableContaminantPresenceProtection,
+            int contaminantProtectionStatus,
+            boolean supportsEnableContaminantPresenceDetection,
+            int contaminantDetectionStatus,
             IndentingPrintWriter pw) {
         // Only allow mode switch capability for dual role ports.
         // Validate that the current mode matches the supported modes we expect.
@@ -664,12 +888,15 @@
         // Update the port data structures.
         PortInfo portInfo = mPorts.get(portId);
         if (portInfo == null) {
-            portInfo = new PortInfo(mContext.getSystemService(UsbManager.class), portId,
-                    supportedModes);
+            portInfo = new PortInfo(mContext.getSystemService(UsbManager.class),
+                portId, supportedModes, supportedContaminantProtectionModes,
+                supportsEnableContaminantPresenceProtection,
+                supportsEnableContaminantPresenceDetection);
             portInfo.setStatus(currentMode, canChangeMode,
                     currentPowerRole, canChangePowerRole,
                     currentDataRole, canChangeDataRole,
-                    supportedRoleCombinations);
+                    supportedRoleCombinations, contaminantProtectionStatus,
+                    contaminantDetectionStatus);
             mPorts.put(portId, portInfo);
         } else {
             // Sanity check that ports aren't changing definition out from under us.
@@ -681,10 +908,32 @@
                         + ", current=" + UsbPort.modeToString(supportedModes));
             }
 
+            if (supportsEnableContaminantPresenceProtection
+                    != portInfo.mUsbPort.supportsEnableContaminantPresenceProtection()) {
+                logAndPrint(Log.WARN, pw,
+                        "Ignoring inconsistent supportsEnableContaminantPresenceProtection"
+                        + "USB port driver (should be immutable): "
+                        + "previous="
+                        + portInfo.mUsbPort.supportsEnableContaminantPresenceProtection()
+                        + ", current=" + supportsEnableContaminantPresenceProtection);
+            }
+
+            if (supportsEnableContaminantPresenceDetection
+                    != portInfo.mUsbPort.supportsEnableContaminantPresenceDetection()) {
+                logAndPrint(Log.WARN, pw,
+                        "Ignoring inconsistent supportsEnableContaminantPresenceDetection "
+                        + "USB port driver (should be immutable): "
+                        + "previous="
+                        + portInfo.mUsbPort.supportsEnableContaminantPresenceDetection()
+                        + ", current=" + supportsEnableContaminantPresenceDetection);
+            }
+
+
             if (portInfo.setStatus(currentMode, canChangeMode,
                     currentPowerRole, canChangePowerRole,
                     currentDataRole, canChangeDataRole,
-                    supportedRoleCombinations)) {
+                    supportedRoleCombinations, contaminantProtectionStatus,
+                    contaminantDetectionStatus)) {
                 portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED;
             } else {
                 portInfo.mDisposition = PortInfo.DISPOSITION_READY;
@@ -695,16 +944,19 @@
     private void handlePortAddedLocked(PortInfo portInfo, IndentingPrintWriter pw) {
         logAndPrint(Log.INFO, pw, "USB port added: " + portInfo);
         sendPortChangedBroadcastLocked(portInfo);
+        updateContaminantNotification();
     }
 
     private void handlePortChangedLocked(PortInfo portInfo, IndentingPrintWriter pw) {
         logAndPrint(Log.INFO, pw, "USB port changed: " + portInfo);
         sendPortChangedBroadcastLocked(portInfo);
+        updateContaminantNotification();
     }
 
     private void handlePortRemovedLocked(PortInfo portInfo, IndentingPrintWriter pw) {
         logAndPrint(Log.INFO, pw, "USB port removed: " + portInfo);
         sendPortChangedBroadcastLocked(portInfo);
+        updateContaminantNotification();
     }
 
     private void sendPortChangedBroadcastLocked(PortInfo portInfo) {
@@ -759,6 +1011,11 @@
                     }
                     break;
                 }
+                case MSG_SYSTEM_READY: {
+                    mNotificationManager = (NotificationManager)
+                            mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+                    break;
+                }
             }
         }
     };
@@ -784,8 +1041,14 @@
         // 0 when port is connected. Else reports the last connected duration
         public long mLastConnectDurationMillis;
 
-        PortInfo(@NonNull UsbManager usbManager, @NonNull String portId, int supportedModes) {
-            mUsbPort = new UsbPort(usbManager, portId, supportedModes);
+        PortInfo(@NonNull UsbManager usbManager, @NonNull String portId, int supportedModes,
+                int supportedContaminantProtectionModes,
+                boolean supportsEnableContaminantPresenceDetection,
+                boolean supportsEnableContaminantPresenceProtection) {
+            mUsbPort = new UsbPort(usbManager, portId, supportedModes,
+                    supportedContaminantProtectionModes,
+                    supportsEnableContaminantPresenceDetection,
+                    supportsEnableContaminantPresenceProtection);
         }
 
         public boolean setStatus(int currentMode, boolean canChangeMode,
@@ -804,7 +1067,45 @@
                     || mUsbPortStatus.getSupportedRoleCombinations()
                     != supportedRoleCombinations) {
                 mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
-                        supportedRoleCombinations);
+                        supportedRoleCombinations, UsbPortStatus.CONTAMINANT_PROTECTION_NONE,
+                        UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED);
+                dispositionChanged = true;
+            }
+
+            if (mUsbPortStatus.isConnected() && mConnectedAtMillis == 0) {
+                mConnectedAtMillis = SystemClock.elapsedRealtime();
+                mLastConnectDurationMillis = 0;
+            } else if (!mUsbPortStatus.isConnected() && mConnectedAtMillis != 0) {
+                mLastConnectDurationMillis = SystemClock.elapsedRealtime() - mConnectedAtMillis;
+                mConnectedAtMillis = 0;
+            }
+
+            return dispositionChanged;
+        }
+
+        public boolean setStatus(int currentMode, boolean canChangeMode,
+                int currentPowerRole, boolean canChangePowerRole,
+                int currentDataRole, boolean canChangeDataRole,
+                int supportedRoleCombinations, int contaminantProtectionStatus,
+                int contaminantDetectionStatus) {
+            boolean dispositionChanged = false;
+
+            mCanChangeMode = canChangeMode;
+            mCanChangePowerRole = canChangePowerRole;
+            mCanChangeDataRole = canChangeDataRole;
+            if (mUsbPortStatus == null
+                    || mUsbPortStatus.getCurrentMode() != currentMode
+                    || mUsbPortStatus.getCurrentPowerRole() != currentPowerRole
+                    || mUsbPortStatus.getCurrentDataRole() != currentDataRole
+                    || mUsbPortStatus.getSupportedRoleCombinations()
+                    != supportedRoleCombinations
+                    || mUsbPortStatus.getContaminantProtectionStatus()
+                    != contaminantProtectionStatus
+                    || mUsbPortStatus.getContaminantDetectionStatus()
+                    != contaminantDetectionStatus) {
+                mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
+                        supportedRoleCombinations, contaminantProtectionStatus,
+                        contaminantDetectionStatus);
                 dispositionChanged = true;
             }
 
@@ -855,32 +1156,54 @@
     private static final class RawPortInfo implements Parcelable {
         public final String portId;
         public final int supportedModes;
+        public final int supportedContaminantProtectionModes;
         public int currentMode;
         public boolean canChangeMode;
         public int currentPowerRole;
         public boolean canChangePowerRole;
         public int currentDataRole;
         public boolean canChangeDataRole;
+        public boolean supportsEnableContaminantPresenceProtection;
+        public int contaminantProtectionStatus;
+        public boolean supportsEnableContaminantPresenceDetection;
+        public int contaminantDetectionStatus;
 
         RawPortInfo(String portId, int supportedModes) {
             this.portId = portId;
             this.supportedModes = supportedModes;
+            this.supportedContaminantProtectionModes = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+            this.supportsEnableContaminantPresenceProtection = false;
+            this.contaminantProtectionStatus = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
+            this.supportsEnableContaminantPresenceDetection = false;
+            this.contaminantDetectionStatus = UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
         }
 
-        RawPortInfo(String portId, int supportedModes,
+        RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
                 int currentMode, boolean canChangeMode,
                 int currentPowerRole, boolean canChangePowerRole,
-                int currentDataRole, boolean canChangeDataRole) {
+                int currentDataRole, boolean canChangeDataRole,
+                boolean supportsEnableContaminantPresenceProtection,
+                int contaminantProtectionStatus,
+                boolean supportsEnableContaminantPresenceDetection,
+                int contaminantDetectionStatus) {
             this.portId = portId;
             this.supportedModes = supportedModes;
+            this.supportedContaminantProtectionModes = supportedContaminantProtectionModes;
             this.currentMode = currentMode;
             this.canChangeMode = canChangeMode;
             this.currentPowerRole = currentPowerRole;
             this.canChangePowerRole = canChangePowerRole;
             this.currentDataRole = currentDataRole;
             this.canChangeDataRole = canChangeDataRole;
+            this.supportsEnableContaminantPresenceProtection =
+                    supportsEnableContaminantPresenceProtection;
+            this.contaminantProtectionStatus = contaminantProtectionStatus;
+            this.supportsEnableContaminantPresenceDetection =
+                    supportsEnableContaminantPresenceDetection;
+            this.contaminantDetectionStatus = contaminantDetectionStatus;
         }
 
+
         @Override
         public int describeContents() {
             return 0;
@@ -890,35 +1213,50 @@
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeString(portId);
             dest.writeInt(supportedModes);
+            dest.writeInt(supportedContaminantProtectionModes);
             dest.writeInt(currentMode);
             dest.writeByte((byte) (canChangeMode ? 1 : 0));
             dest.writeInt(currentPowerRole);
             dest.writeByte((byte) (canChangePowerRole ? 1 : 0));
             dest.writeInt(currentDataRole);
             dest.writeByte((byte) (canChangeDataRole ? 1 : 0));
+            dest.writeBoolean(supportsEnableContaminantPresenceProtection);
+            dest.writeInt(contaminantProtectionStatus);
+            dest.writeBoolean(supportsEnableContaminantPresenceDetection);
+            dest.writeInt(contaminantDetectionStatus);
         }
 
         public static final Parcelable.Creator<RawPortInfo> CREATOR =
                 new Parcelable.Creator<RawPortInfo>() {
-                    @Override
-                    public RawPortInfo createFromParcel(Parcel in) {
-                        String id = in.readString();
-                        int supportedModes = in.readInt();
-                        int currentMode = in.readInt();
-                        boolean canChangeMode = in.readByte() != 0;
-                        int currentPowerRole = in.readInt();
-                        boolean canChangePowerRole = in.readByte() != 0;
-                        int currentDataRole = in.readInt();
-                        boolean canChangeDataRole = in.readByte() != 0;
-                        return new RawPortInfo(id, supportedModes, currentMode, canChangeMode,
-                                currentPowerRole, canChangePowerRole,
-                                currentDataRole, canChangeDataRole);
-                    }
+            @Override
+            public RawPortInfo createFromParcel(Parcel in) {
+                String id = in.readString();
+                int supportedModes = in.readInt();
+                int supportedContaminantProtectionModes = in.readInt();
+                int currentMode = in.readInt();
+                boolean canChangeMode = in.readByte() != 0;
+                int currentPowerRole = in.readInt();
+                boolean canChangePowerRole = in.readByte() != 0;
+                int currentDataRole = in.readInt();
+                boolean canChangeDataRole = in.readByte() != 0;
+                boolean supportsEnableContaminantPresenceProtection = in.readBoolean();
+                int contaminantProtectionStatus = in.readInt();
+                boolean supportsEnableContaminantPresenceDetection = in.readBoolean();
+                int contaminantDetectionStatus = in.readInt();
+                return new RawPortInfo(id, supportedModes,
+                        supportedContaminantProtectionModes, currentMode, canChangeMode,
+                        currentPowerRole, canChangePowerRole,
+                        currentDataRole, canChangeDataRole,
+                        supportsEnableContaminantPresenceProtection,
+                        contaminantProtectionStatus,
+                        supportsEnableContaminantPresenceDetection,
+                        contaminantDetectionStatus);
+            }
 
-                    @Override
-                    public RawPortInfo[] newArray(int size) {
-                        return new RawPortInfo[size];
-                    }
-                };
+            @Override
+            public RawPortInfo[] newArray(int size) {
+                return new RawPortInfo[size];
+            }
+        };
     }
 }
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 9115477..4be68b8 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -554,6 +554,21 @@
     }
 
     @Override
+    public void enableContaminantDetection(String portId, boolean enable) {
+        Preconditions.checkNotNull(portId, "portId must not be null");
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            if (mPortManager != null) {
+                mPortManager.enableContaminantDetection(portId, enable, null);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
     public void setUsbDeviceConnectionHandler(ComponentName usbDeviceConnectionHandler) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
         synchronized (mLock) {
@@ -747,6 +762,15 @@
                     mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, "  ")),
                             "", 0);
                 }
+            } else if ("set-contaminant-status".equals(args[0]) && args.length == 3) {
+                final String portId = args[1];
+                final Boolean wet = Boolean.parseBoolean(args[2]);
+                if (mPortManager != null) {
+                    mPortManager.simulateContaminantStatus(portId, wet, pw);
+                    pw.println();
+                    mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, "  ")),
+                            "", 0);
+                }
             } else if ("ports".equals(args[0]) && args.length == 1) {
                 if (mPortManager != null) {
                     mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, "  ")),
@@ -791,6 +815,11 @@
                 pw.println("  dumpsys usb connect-port \"matrix\" ufp sink device");
                 pw.println("  dumpsys usb reset");
                 pw.println();
+                pw.println("Example simulate contaminant status:");
+                pw.println("  dumpsys usb add-port \"matrix\" ufp");
+                pw.println("  dumpsys usb set-contaminant-status \"matrix\" true");
+                pw.println("  dumpsys usb set-contaminant-status \"matrix\" false");
+                pw.println();
                 pw.println("Example USB device descriptors:");
                 pw.println("  dumpsys usb dump-descriptors -dump-short");
                 pw.println("  dumpsys usb dump-descriptors -dump-tree");
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 38efc74..3d7cbb5 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -657,9 +657,8 @@
             return;
         }
 
-        if (event.status != SoundTrigger.RECOGNITION_STATUS_GET_STATE_RESPONSE) {
-            model.setStopped();
-        }
+        model.setStopped();
+
         try {
             callback.onGenericSoundTriggerDetected((GenericRecognitionEvent) event);
         } catch (DeadObjectException e) {
@@ -802,9 +801,7 @@
             return;
         }
 
-        if (event.status != SoundTrigger.RECOGNITION_STATUS_GET_STATE_RESPONSE) {
-            modelData.setStopped();
-        }
+        modelData.setStopped();
 
         try {
             modelData.getCallback().onKeyphraseDetected((KeyphraseRecognitionEvent) event);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index bbf3d45..bb01f04 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -19,9 +19,6 @@
 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;
 import android.content.ContentResolver;
@@ -62,8 +59,9 @@
 import android.util.Log;
 import android.util.Slog;
 
-import com.android.internal.app.IVoiceInteractionSessionListener;
+import com.android.internal.app.IVoiceActionCheckCallback;
 import com.android.internal.app.IVoiceInteractionManagerService;
+import com.android.internal.app.IVoiceInteractionSessionListener;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.content.PackageMonitor;
@@ -75,6 +73,7 @@
 import com.android.server.SystemService;
 import com.android.server.UiThread;
 import com.android.server.soundtrigger.SoundTriggerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -371,14 +370,15 @@
         }
 
         private boolean shouldEnableService(Context context) {
-            // VoiceInteractionService should not be enabled on any low RAM devices
-            // or devices that have not declared the recognition feature, unless the
-            // device's configuration has explicitly set the config flag for a fixed
+            // VoiceInteractionService should not be enabled on devices that have not declared the
+            // recognition feature (including low-ram devices where notLowRam="true" takes effect),
+            // unless the device's configuration has explicitly set the config flag for a fixed
             // voice interaction service.
-            return (!ActivityManager.isLowRamDeviceStatic()
-                            && context.getPackageManager().hasSystemFeature(
-                                    PackageManager.FEATURE_VOICE_RECOGNIZERS)) ||
-                    getForceVoiceInteractionServicePackage(context.getResources()) != null;
+            if (getForceVoiceInteractionServicePackage(context.getResources()) != null) {
+                return true;
+            }
+            return context.getPackageManager()
+                    .hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS);
         }
 
         private String getForceVoiceInteractionServicePackage(Resources res) {
@@ -1204,6 +1204,57 @@
             mSoundTriggerInternal.dump(fd, pw, args);
         }
 
+        @Override
+        public void setTranscription(String transcription) {
+            synchronized (this) {
+                final int size = mVoiceInteractionSessionListeners.beginBroadcast();
+                for (int i = 0; i < size; ++i) {
+                    final IVoiceInteractionSessionListener listener =
+                            mVoiceInteractionSessionListeners.getBroadcastItem(i);
+                    try {
+                        listener.onTranscriptionUpdate(transcription);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Error delivering voice transcription.", e);
+                    }
+                }
+                mVoiceInteractionSessionListeners.finishBroadcast();
+            }
+        }
+
+        @Override
+        public void clearTranscription(boolean immediate) {
+            synchronized (this) {
+                final int size = mVoiceInteractionSessionListeners.beginBroadcast();
+                for (int i = 0; i < size; ++i) {
+                    final IVoiceInteractionSessionListener listener =
+                            mVoiceInteractionSessionListeners.getBroadcastItem(i);
+                    try {
+                        listener.onTranscriptionComplete(immediate);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Error delivering transcription complete event.", e);
+                    }
+                }
+                mVoiceInteractionSessionListeners.finishBroadcast();
+            }
+        }
+
+        @Override
+        public void setVoiceState(int state) {
+            synchronized (this) {
+                final int size = mVoiceInteractionSessionListeners.beginBroadcast();
+                for (int i = 0; i < size; ++i) {
+                    final IVoiceInteractionSessionListener listener =
+                            mVoiceInteractionSessionListeners.getBroadcastItem(i);
+                    try {
+                        listener.onVoiceStateChange(state);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Error delivering voice state change.", e);
+                    }
+                }
+                mVoiceInteractionSessionListeners.finishBroadcast();
+            }
+        }
+
         private void enforceCallingPermission(String permission) {
             if (mContext.checkCallingOrSelfPermission(permission)
                     != PackageManager.PERMISSION_GRANTED) {
diff --git a/startop/OWNERS b/startop/OWNERS
index bfe96d3..5cf9582 100644
--- a/startop/OWNERS
+++ b/startop/OWNERS
@@ -2,4 +2,5 @@
 chriswailes@google.com
 eholk@google.com
 iam@google.com
+mathieuc@google.com
 sehr@google.com
diff --git a/startop/iorap/Android.bp b/startop/iorap/Android.bp
index b3b0900..59a80fb 100644
--- a/startop/iorap/Android.bp
+++ b/startop/iorap/Android.bp
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 java_library_static {
-  name: "libiorap-java",
+  name: "services.startop.iorap",
 
   aidl: {
     include_dirs: [
@@ -21,6 +21,8 @@
     ],
   },
 
+  libs: ["services.core"],
+
   srcs: [
       ":iorap-aidl",
       "**/*.java",
diff --git a/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
new file mode 100644
index 0000000..c2e4581
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
@@ -0,0 +1,368 @@
+/*
+ * 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.google.android.startop.iorap;
+
+import android.annotation.LongDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+// TODO: fix this. either move this class into system server or add a dependency on
+// these wm classes to libiorap-java and libiorap-java-tests (somehow).
+import com.android.server.wm.ActivityMetricsLaunchObserver;
+import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
+import com.android.server.wm.ActivityMetricsLaunchObserver.Temperature;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Objects;
+
+/**
+ * Provide a hint to iorapd that an app launch sequence has transitioned state.<br /><br />
+ *
+ * Knowledge of when an activity starts/stops can be used by iorapd to increase system
+ * performance (e.g. by launching perfetto tracing to record an io profile, or by
+ * playing back an ioprofile via readahead) over the long run.<br /><br />
+ *
+ * /@see com.google.android.startop.iorap.IIorap#onAppLaunchEvent <br /><br />
+ * @see com.android.server.wm.ActivityMetricsLaunchObserver
+ *      ActivityMetricsLaunchObserver for the possible event states.
+ * @hide
+ */
+public abstract class AppLaunchEvent implements Parcelable {
+    @LongDef
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SequenceId {}
+
+    public final @SequenceId
+    long sequenceId;
+
+    protected AppLaunchEvent(@SequenceId long sequenceId) {
+        this.sequenceId = sequenceId;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof AppLaunchEvent) {
+            return equals((AppLaunchEvent) other);
+        }
+        return false;
+    }
+
+    protected boolean equals(AppLaunchEvent other) {
+        return sequenceId == other.sequenceId;
+    }
+
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() +
+                "{" + "sequenceId=" + Long.toString(sequenceId) +
+                toStringBody() + "}";
+    }
+
+    protected String toStringBody() { return ""; };
+
+    // List of possible variants:
+
+    public static final class IntentStarted extends AppLaunchEvent {
+        @NonNull
+        public final Intent intent;
+
+        public IntentStarted(@SequenceId long sequenceId, Intent intent) {
+            super(sequenceId);
+            this.intent = intent;
+
+            Objects.requireNonNull(intent, "intent");
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof IntentStarted) {
+                return intent.equals(((IntentStarted)other).intent) &&
+                        super.equals(other);
+            }
+            return false;
+        }
+
+        @Override
+        protected String toStringBody() {
+            return ", intent=" + intent.toString();
+        }
+
+
+        @Override
+        protected void writeToParcelImpl(Parcel p, int flags) {
+            super.writeToParcelImpl(p, flags);
+            intent.writeToParcel(p, flags);
+        }
+
+        IntentStarted(Parcel p) {
+            super(p);
+            intent = Intent.CREATOR.createFromParcel(p);
+        }
+    }
+
+    public static final class IntentFailed extends AppLaunchEvent {
+        public IntentFailed(@SequenceId long sequenceId) {
+            super(sequenceId);
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof IntentFailed) {
+                return super.equals(other);
+            }
+            return false;
+        }
+
+        IntentFailed(Parcel p) {
+            super(p);
+        }
+    }
+
+    public static abstract class BaseWithActivityRecordData extends AppLaunchEvent {
+        public final @NonNull
+        @ActivityRecordProto byte[] activityRecordSnapshot;
+
+        protected BaseWithActivityRecordData(@SequenceId long sequenceId,
+                @NonNull @ActivityRecordProto byte[] snapshot) {
+            super(sequenceId);
+            activityRecordSnapshot = snapshot;
+
+            Objects.requireNonNull(snapshot, "snapshot");
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof BaseWithActivityRecordData) {
+                return activityRecordSnapshot.equals(
+                        ((BaseWithActivityRecordData)other).activityRecordSnapshot) &&
+                        super.equals(other);
+            }
+            return false;
+        }
+
+        @Override
+        protected String toStringBody() {
+            return ", " + activityRecordSnapshot.toString();
+        }
+
+        @Override
+        protected void writeToParcelImpl(Parcel p, int flags) {
+           super.writeToParcelImpl(p, flags);
+           ActivityRecordProtoParcelable.write(p, activityRecordSnapshot, flags);
+        }
+
+        BaseWithActivityRecordData(Parcel p) {
+            super(p);
+            activityRecordSnapshot = ActivityRecordProtoParcelable.create(p);
+        }
+    }
+
+    public static final class ActivityLaunched extends BaseWithActivityRecordData {
+        public final @ActivityMetricsLaunchObserver.Temperature
+        int temperature;
+
+        public ActivityLaunched(@SequenceId long sequenceId,
+                @NonNull @ActivityRecordProto byte[] snapshot, 
+                @ActivityMetricsLaunchObserver.Temperature int temperature) {
+            super(sequenceId, snapshot);
+            this.temperature = temperature;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof ActivityLaunched) {
+                return temperature == ((ActivityLaunched)other).temperature &&
+                        super.equals(other);
+            }
+            return false;
+        }
+
+        @Override
+        protected String toStringBody() {
+            return ", temperature=" + Integer.toString(temperature);
+        }
+
+        @Override
+        protected void writeToParcelImpl(Parcel p, int flags) {
+           super.writeToParcelImpl(p, flags);
+           p.writeInt(temperature);
+        }
+
+        ActivityLaunched(Parcel p) {
+            super(p);
+            temperature = p.readInt();
+        }
+    }
+
+    public static final class ActivityLaunchFinished extends BaseWithActivityRecordData {
+        public ActivityLaunchFinished(@SequenceId long sequenceId,
+                @NonNull @ActivityRecordProto byte[] snapshot) {
+            super(sequenceId, snapshot);
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof ActivityLaunched) {
+                return super.equals(other);
+            }
+            return false;
+        }
+    }
+
+     public static class ActivityLaunchCancelled extends AppLaunchEvent {
+        public final @Nullable
+        @ActivityRecordProto byte[] activityRecordSnapshot;
+
+        public ActivityLaunchCancelled(@SequenceId long sequenceId,
+                @Nullable @ActivityRecordProto byte[] snapshot) {
+            super(sequenceId);
+            activityRecordSnapshot = snapshot;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof ActivityLaunchCancelled) {
+                return Objects.equals(activityRecordSnapshot,
+                        ((ActivityLaunchCancelled)other).activityRecordSnapshot) &&
+                        super.equals(other);
+            }
+            return false;
+        }
+
+        @Override
+        protected String toStringBody() {
+            return ", " + activityRecordSnapshot.toString();
+        }
+
+        @Override
+        protected void writeToParcelImpl(Parcel p, int flags) {
+           super.writeToParcelImpl(p, flags);
+           if (activityRecordSnapshot != null) {
+               p.writeBoolean(true);
+               ActivityRecordProtoParcelable.write(p, activityRecordSnapshot, flags);
+           } else {
+               p.writeBoolean(false);
+           }
+        }
+
+        ActivityLaunchCancelled(Parcel p) {
+            super(p);
+            if (p.readBoolean()) {
+                activityRecordSnapshot = ActivityRecordProtoParcelable.create(p);
+            } else {
+                activityRecordSnapshot = null;
+            }
+        }
+    }
+
+    @Override
+    public @ContentsFlags int describeContents() { return 0; }
+
+    @Override
+    public void writeToParcel(Parcel p, @WriteFlags int flags) {
+        p.writeInt(getTypeIndex());
+
+        writeToParcelImpl(p, flags);
+    }
+
+
+    public static Creator<AppLaunchEvent> CREATOR =
+            new Creator<AppLaunchEvent>() {
+        @Override
+        public AppLaunchEvent createFromParcel(Parcel source) {
+            int typeIndex = source.readInt();
+
+            Class<?> kls = getClassFromTypeIndex(typeIndex);
+            if (kls == null) {
+                throw new IllegalArgumentException("Invalid type index: " + typeIndex);
+            }
+
+            try {
+                return (AppLaunchEvent) kls.getConstructor(Parcel.class).newInstance(source);
+            } catch (InstantiationException e) {
+                throw new AssertionError(e);
+            } catch (IllegalAccessException e) {
+                throw new AssertionError(e);
+            } catch (InvocationTargetException e) {
+                throw new AssertionError(e);
+            } catch (NoSuchMethodException e) {
+                throw new AssertionError(e);
+            }
+        }
+
+        @Override
+        public AppLaunchEvent[] newArray(int size) {
+            return new AppLaunchEvent[0];
+        }
+    };
+
+    protected void writeToParcelImpl(Parcel p, int flags) {
+        p.writeLong(sequenceId);
+    }
+
+    protected AppLaunchEvent(Parcel p) {
+        sequenceId = p.readLong();
+    }
+
+    private int getTypeIndex() {
+        for (int i = 0; i < sTypes.length; ++i) {
+            if (sTypes[i].equals(this.getClass())) {
+                return i;
+            }
+        }
+        throw new AssertionError("sTypes did not include this type: " + this.getClass());
+    }
+
+    private static @Nullable Class<?> getClassFromTypeIndex(int typeIndex) {
+        if (typeIndex >= 0 && typeIndex < sTypes.length) {
+            return sTypes[typeIndex];
+        }
+        return null;
+    }
+
+    // Index position matters: It is used to encode the specific type in parceling.
+    // Keep up-to-date with C++ side.
+    private static Class<?>[] sTypes = new Class[] {
+            IntentStarted.class,
+            IntentFailed.class,
+            ActivityLaunched.class,
+            ActivityLaunchFinished.class,
+            ActivityLaunchCancelled.class,
+    };
+
+    // TODO: move to @ActivityRecordProto byte[] once we have unit tests.
+    public static class ActivityRecordProtoParcelable {
+        public static void write(Parcel p, @ActivityRecordProto byte[] activityRecordSnapshot,
+                int flags) {
+            p.writeByteArray(activityRecordSnapshot);
+        }
+
+        public static @ActivityRecordProto byte[] create(Parcel p) {
+            byte[] data = p.createByteArray();
+
+            return data;
+        }
+    }
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
new file mode 100644
index 0000000..7fcad36
--- /dev/null
+++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
@@ -0,0 +1,216 @@
+/*
+ * 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.google.android.startop.iorap;
+// TODO: rename to com.android.server.startop.iorap
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.wm.ActivityMetricsLaunchObserver;
+import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
+import com.android.server.wm.ActivityMetricsLaunchObserver.Temperature;
+import com.android.server.wm.ActivityMetricsLaunchObserverRegistry;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+/**
+ * System-server-local proxy into the {@code IIorap} native service.
+ */
+public class IorapForwardingService extends SystemService {
+
+    public static final boolean DEBUG = true; // TODO: read from a getprop?
+    public static final String TAG = "IorapForwardingService";
+
+    private IIorap mIorapRemote;
+
+    /**
+     * 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 IorapForwardingService(Context context) {
+       super(context);
+    }
+
+    //<editor-fold desc="Providers">
+    /*
+     * Providers for external dependencies:
+     * - These are marked as protected to allow tests to inject different values via mocks.
+     */
+
+    @VisibleForTesting
+    protected ActivityMetricsLaunchObserverRegistry provideLaunchObserverRegistry() {
+        ActivityTaskManagerInternal amtInternal =
+                LocalServices.getService(ActivityTaskManagerInternal.class);
+        ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
+                amtInternal.getLaunchObserverRegistry();
+        return launchObserverRegistry;
+    }
+
+    @VisibleForTesting
+    protected IIorap provideIorapRemote() {
+        try {
+            return IIorap.Stub.asInterface(ServiceManager.getServiceOrThrow("iorapd"));
+        } catch (ServiceManager.ServiceNotFoundException e) {
+            // TODO: how do we handle service being missing?
+            throw new AssertionError(e);
+        }
+    }
+
+    //</editor-fold>
+
+    @Override
+    public void onStart() {
+        if (DEBUG) {
+            Log.v(TAG, "onStart");
+        }
+
+        // Connect to the native binder service.
+        mIorapRemote = provideIorapRemote();
+        invokeRemote( () -> mIorapRemote.setTaskListener(new RemoteTaskListener()) );
+
+        // Listen to App Launch Sequence events from ActivityTaskManager,
+        // and forward them to the native binder service.
+        ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
+                provideLaunchObserverRegistry();
+        launchObserverRegistry.registerLaunchObserver(new AppLaunchObserver());
+    }
+
+    private class AppLaunchObserver implements ActivityMetricsLaunchObserver {
+        // We add a synthetic sequence ID here to make it easier to differentiate new
+        // launch sequences on the native side.
+        private @AppLaunchEvent.SequenceId long mSequenceId = -1;
+
+        @Override
+        public void onIntentStarted(@NonNull Intent intent) {
+            // #onIntentStarted [is the only transition that] initiates a new launch sequence.
+            ++mSequenceId;
+
+            if (DEBUG) {
+                Log.v(TAG, String.format("AppLaunchObserver#onIntentStarted(%d, %s)",
+                        mSequenceId, intent));
+            }
+
+            invokeRemote(() ->
+                    mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+                        new AppLaunchEvent.IntentStarted(mSequenceId, intent))
+            );
+        }
+
+        @Override
+        public void onIntentFailed() {
+            if (DEBUG) {
+                Log.v(TAG, String.format("AppLaunchObserver#onIntentFailed(%d)", mSequenceId));
+            }
+
+            invokeRemote(() ->
+                    mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+                        new AppLaunchEvent.IntentFailed(mSequenceId))
+            );
+        }
+
+        @Override
+        public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
+                @Temperature int temperature) {
+            if (DEBUG) {
+                Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunched(%d, %s, %d)",
+                        mSequenceId, activity, temperature));
+            }
+
+            invokeRemote(() ->
+                    mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+                            new AppLaunchEvent.ActivityLaunched(mSequenceId, activity, temperature))
+            );
+        }
+
+        @Override
+        public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] activity) {
+            if (DEBUG) {
+                Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchCancelled(%d, %s)",
+                        mSequenceId, activity));
+            }
+
+            invokeRemote(() ->
+                    mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+                            new AppLaunchEvent.ActivityLaunchCancelled(mSequenceId,
+                                    activity)));
+        }
+
+        @Override
+        public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity) {
+            if (DEBUG) {
+                Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchFinished(%d, %s)",
+                        mSequenceId, activity));
+            }
+
+            invokeRemote(() ->
+                mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
+                        new AppLaunchEvent.ActivityLaunchCancelled(mSequenceId, activity))
+            );
+        }
+    }
+
+    private class RemoteTaskListener extends ITaskListener.Stub {
+        @Override
+        public void onProgress(RequestId requestId, TaskResult result) throws RemoteException {
+            if (DEBUG) {
+                Log.v(TAG,
+                        String.format("RemoteTaskListener#onProgress(%s, %s)", requestId, result));
+            }
+
+            // TODO: implement rest.
+        }
+
+        @Override
+        public void onComplete(RequestId requestId, TaskResult result) throws RemoteException {
+            if (DEBUG) {
+                Log.v(TAG,
+                        String.format("RemoteTaskListener#onComplete(%s, %s)", requestId, result));
+            }
+
+            // TODO: implement rest.
+        }
+    }
+
+    private interface RemoteRunnable {
+        void run() throws RemoteException;
+    }
+
+    private static void invokeRemote(RemoteRunnable r) {
+       try {
+           r.run();
+       } catch (RemoteException e) {
+           // TODO: what do we do with exceptions?
+           throw new AssertionError("not implemented", e);
+       }
+    }
+}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/RequestId.java b/startop/iorap/src/com/google/android/startop/iorap/RequestId.java
index 2c79319..adb3a91 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/RequestId.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/RequestId.java
@@ -71,7 +71,7 @@
 
     @Override
     public String toString() {
-        return String.format("{requestId: %ld}", requestId);
+        return String.format("{requestId: %d}", requestId);
     }
 
     @Override
diff --git a/startop/iorap/tests/Android.bp b/startop/iorap/tests/Android.bp
index 7605784..5ac4a46 100644
--- a/startop/iorap/tests/Android.bp
+++ b/startop/iorap/tests/Android.bp
@@ -18,8 +18,15 @@
     srcs: ["src/**/*.kt"],
 
     static_libs: [
-      // non-test dependencies
-      "libiorap-java",
+      // Non-test dependencies
+
+      // library under test
+      "services.startop.iorap",
+      // need the system_server code to be on the classpath,
+      "services.core",
+
+      // Test Dependencies
+
       // test android dependencies
       "platform-test-annotations",
       "android-support-test",
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index 91cec554..7dc83c3 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -22,26 +22,46 @@
     shared_libs: [
         "libbase",
         "libdexfile",
+        "libz",
         "slicer",
     ],
     static_libs: [
         "libtinyxml2",
+        "liblog",
+        "libutils",
+        "libziparchive",
     ],
+    cppflags: ["-std=c++17"],
+    target: {
+        android: {
+            shared_libs: [
+                "libandroidfw",
+            ],
+        },
+        host: {
+            static_libs: [
+                "libandroidfw",
+            ],
+        },
+    },
 }
 
-cc_library_host_static {
+cc_library_static {
     name: "libviewcompiler",
     defaults: ["viewcompiler_defaults"],
     srcs: [
+        "apk_layout_compiler.cc",
         "dex_builder.cc",
+        "dex_layout_compiler.cc",
         "java_lang_builder.cc",
         "tinyxml_layout_parser.cc",
         "util.cc",
         "layout_validation.cc",
     ],
+    host_supported: true,
 }
 
-cc_binary_host {
+cc_binary {
     name: "viewcompiler",
     defaults: ["viewcompiler_defaults"],
     srcs: [
@@ -51,6 +71,7 @@
         "libgflags",
         "libviewcompiler",
     ],
+    host_supported: true
 }
 
 cc_test_host {
diff --git a/startop/view_compiler/apk_layout_compiler.cc b/startop/view_compiler/apk_layout_compiler.cc
new file mode 100644
index 0000000..09cdbd5
--- /dev/null
+++ b/startop/view_compiler/apk_layout_compiler.cc
@@ -0,0 +1,174 @@
+/*
+ * 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 "apk_layout_compiler.h"
+#include "dex_layout_compiler.h"
+#include "java_lang_builder.h"
+#include "layout_validation.h"
+#include "util.h"
+
+#include "androidfw/ApkAssets.h"
+#include "androidfw/AssetManager2.h"
+#include "androidfw/ResourceTypes.h"
+
+#include <iostream>
+#include <locale>
+
+#include "android-base/stringprintf.h"
+
+namespace startop {
+
+using android::ResXMLParser;
+using android::base::StringPrintf;
+
+class ResXmlVisitorAdapter {
+ public:
+  ResXmlVisitorAdapter(ResXMLParser* parser) : parser_{parser} {}
+
+  template <typename Visitor>
+  void Accept(Visitor* visitor) {
+    size_t depth{0};
+    do {
+      switch (parser_->next()) {
+        case ResXMLParser::START_DOCUMENT:
+          depth++;
+          visitor->VisitStartDocument();
+          break;
+        case ResXMLParser::END_DOCUMENT:
+          depth--;
+          visitor->VisitEndDocument();
+          break;
+        case ResXMLParser::START_TAG: {
+          depth++;
+          size_t name_length = 0;
+          const char16_t* name = parser_->getElementName(&name_length);
+          visitor->VisitStartTag(std::u16string{name, name_length});
+          break;
+        }
+        case ResXMLParser::END_TAG:
+          depth--;
+          visitor->VisitEndTag();
+          break;
+        default:;
+      }
+    } while (depth > 0 || parser_->getEventType() == ResXMLParser::FIRST_CHUNK_CODE);
+  }
+
+ private:
+  ResXMLParser* parser_;
+};
+
+bool CanCompileLayout(ResXMLParser* parser) {
+  ResXmlVisitorAdapter adapter{parser};
+  LayoutValidationVisitor visitor;
+  adapter.Accept(&visitor);
+
+  return visitor.can_compile();
+}
+
+namespace {
+void CompileApkAssetsLayouts(const std::unique_ptr<const android::ApkAssets>& assets,
+                             CompilationTarget target, std::ostream& target_out) {
+  android::AssetManager2 resources;
+  resources.SetApkAssets({assets.get()});
+
+  std::string package_name;
+
+  // TODO: handle multiple packages better
+  bool first = true;
+  for (const auto& package : assets->GetLoadedArsc()->GetPackages()) {
+    CHECK(first);
+    package_name = package->GetPackageName();
+    first = false;
+  }
+
+  dex::DexBuilder dex_file;
+  dex::ClassBuilder compiled_view{
+      dex_file.MakeClass(StringPrintf("%s.CompiledView", package_name.c_str()))};
+  std::vector<dex::MethodBuilder> methods;
+
+  assets->ForEachFile("res/", [&](const android::StringPiece& s, android::FileType) {
+    if (s == "layout") {
+      auto path = StringPrintf("res/%s/", s.to_string().c_str());
+      assets->ForEachFile(path, [&](const android::StringPiece& layout_file, android::FileType) {
+        auto layout_path = StringPrintf("%s%s", path.c_str(), layout_file.to_string().c_str());
+        android::ApkAssetsCookie cookie = android::kInvalidCookie;
+        auto asset = resources.OpenNonAsset(layout_path, android::Asset::ACCESS_RANDOM, &cookie);
+        CHECK(asset);
+        CHECK(android::kInvalidCookie != cookie);
+        const auto dynamic_ref_table = resources.GetDynamicRefTableForCookie(cookie);
+        CHECK(nullptr != dynamic_ref_table);
+        android::ResXMLTree xml_tree{dynamic_ref_table};
+        xml_tree.setTo(asset->getBuffer(/*wordAligned=*/true),
+                       asset->getLength(),
+                       /*copy_data=*/true);
+        android::ResXMLParser parser{xml_tree};
+        parser.restart();
+        if (CanCompileLayout(&parser)) {
+          parser.restart();
+          const std::string layout_name = startop::util::FindLayoutNameFromFilename(layout_path);
+          ResXmlVisitorAdapter adapter{&parser};
+          switch (target) {
+            case CompilationTarget::kDex: {
+              methods.push_back(compiled_view.CreateMethod(
+                  layout_name,
+                  dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.View"),
+                                 dex::TypeDescriptor::FromClassname("android.content.Context"),
+                                 dex::TypeDescriptor::Int()}));
+              DexViewBuilder builder(&methods.back());
+              builder.Start();
+              LayoutCompilerVisitor visitor{&builder};
+              adapter.Accept(&visitor);
+              builder.Finish();
+              methods.back().Encode();
+              break;
+            }
+            case CompilationTarget::kJavaLanguage: {
+              JavaLangViewBuilder builder{package_name, layout_name, target_out};
+              builder.Start();
+              LayoutCompilerVisitor visitor{&builder};
+              adapter.Accept(&visitor);
+              builder.Finish();
+              break;
+            }
+          }
+        }
+      });
+    }
+  });
+
+  if (target == CompilationTarget::kDex) {
+    slicer::MemView image{dex_file.CreateImage()};
+    target_out.write(image.ptr<const char>(), image.size());
+  }
+}
+}  // namespace
+
+void CompileApkLayouts(const std::string& filename, CompilationTarget target,
+                       std::ostream& target_out) {
+  auto assets = android::ApkAssets::Load(filename);
+  CompileApkAssetsLayouts(assets, target, target_out);
+}
+
+void CompileApkLayoutsFd(android::base::unique_fd fd, CompilationTarget target,
+                         std::ostream& target_out) {
+  constexpr const char* friendly_name{"viewcompiler assets"};
+  auto assets = android::ApkAssets::LoadFromFd(
+      std::move(fd), friendly_name, /*system=*/false, /*force_shared_lib=*/false);
+  CompileApkAssetsLayouts(assets, target, target_out);
+}
+
+}  // namespace startop
diff --git a/startop/view_compiler/apk_layout_compiler.h b/startop/view_compiler/apk_layout_compiler.h
new file mode 100644
index 0000000..03bd545
--- /dev/null
+++ b/startop/view_compiler/apk_layout_compiler.h
@@ -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.
+ */
+
+#ifndef APK_LAYOUT_COMPILER_H_
+#define APK_LAYOUT_COMPILER_H_
+
+#include <string>
+
+#include "android-base/unique_fd.h"
+
+namespace startop {
+
+enum class CompilationTarget { kJavaLanguage, kDex };
+
+void CompileApkLayouts(const std::string& filename, CompilationTarget target,
+                       std::ostream& target_out);
+void CompileApkLayoutsFd(android::base::unique_fd fd, CompilationTarget target,
+                         std::ostream& target_out);
+
+}  // namespace startop
+
+#endif  // APK_LAYOUT_COMPILER_H_
\ No newline at end of file
diff --git a/startop/view_compiler/dex_builder_test/Android.bp b/startop/view_compiler/dex_builder_test/Android.bp
index 4449ea0..d4f38ed 100644
--- a/startop/view_compiler/dex_builder_test/Android.bp
+++ b/startop/view_compiler/dex_builder_test/Android.bp
@@ -14,16 +14,30 @@
 // limitations under the License.
 //
 
+genrule {
+    name: "generate_compiled_layout",
+    tools: [":viewcompiler"],
+    cmd: "$(location :viewcompiler) $(in) --dex --out $(out) --package android.startop.test",
+    srcs: ["res/layout/layout1.xml"],
+    out: [
+        "layout1.dex",
+    ],
+}
+
 android_test {
     name: "dex-builder-test",
-    srcs: ["src/android/startop/test/DexBuilderTest.java"],
+    srcs: [
+        "src/android/startop/test/DexBuilderTest.java",
+        "src/android/startop/test/LayoutCompilerTest.java",
+    ],
     sdk_version: "current",
-    data: [":generate_dex_testcases"],
+    data: [":generate_dex_testcases", ":generate_compiled_layout"],
     static_libs: [
         "android-support-test",
         "guava",
     ],
     manifest: "AndroidManifest.xml",
+    resource_dirs: ["res"],
     test_config: "AndroidTest.xml",
     test_suites: ["general-tests"],
 }
diff --git a/startop/view_compiler/dex_builder_test/AndroidTest.xml b/startop/view_compiler/dex_builder_test/AndroidTest.xml
index 6f90cf3..68d8fdc 100644
--- a/startop/view_compiler/dex_builder_test/AndroidTest.xml
+++ b/startop/view_compiler/dex_builder_test/AndroidTest.xml
@@ -25,6 +25,7 @@
         <option name="cleanup" value="true" />
         <option name="push" value="trivial.dex->/data/local/tmp/dex-builder-test/trivial.dex" />
         <option name="push" value="simple.dex->/data/local/tmp/dex-builder-test/simple.dex" />
+        <option name="push" value="layout1.dex->/data/local/tmp/dex-builder-test/layout1.dex" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/startop/view_compiler/dex_builder_test/res/layout/layout1.xml b/startop/view_compiler/dex_builder_test/res/layout/layout1.xml
new file mode 100644
index 0000000..0f9375c
--- /dev/null
+++ b/startop/view_compiler/dex_builder_test/res/layout/layout1.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+   android:layout_width="match_parent"
+   android:layout_height="match_parent"
+   android:paddingLeft="16dp"
+   android:paddingRight="16dp"
+   android:orientation="vertical"
+   android:gravity="center">
+
+    <Button
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+    <Button
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+ </LinearLayout>
diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java
new file mode 100644
index 0000000..ce3ce83
--- /dev/null
+++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.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 android.startop.test;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.view.View;
+import com.google.common.io.ByteStreams;
+import dalvik.system.InMemoryDexClassLoader;
+import dalvik.system.PathClassLoader;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import org.junit.Assert;
+import org.junit.Test;
+
+// Adding tests here requires changes in several other places. See README.md in
+// the view_compiler directory for more information.
+public class LayoutCompilerTest {
+    static ClassLoader loadDexFile(String filename) throws Exception {
+        return new PathClassLoader("/data/local/tmp/dex-builder-test/" + filename,
+                ClassLoader.getSystemClassLoader());
+    }
+
+    @Test
+    public void loadAndInflaterLayout1() throws Exception {
+        ClassLoader dex_file = loadDexFile("layout1.dex");
+        Class compiled_view = dex_file.loadClass("android.startop.test.CompiledView");
+        Method layout1 = compiled_view.getMethod("layout1", Context.class, int.class);
+        Context context = InstrumentationRegistry.getTargetContext();
+        layout1.invoke(null, context, R.layout.layout1);
+    }
+}
diff --git a/startop/view_compiler/dex_layout_compiler.cc b/startop/view_compiler/dex_layout_compiler.cc
new file mode 100644
index 0000000..c68793d
--- /dev/null
+++ b/startop/view_compiler/dex_layout_compiler.cc
@@ -0,0 +1,226 @@
+/*
+ * 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 "dex_layout_compiler.h"
+#include "layout_validation.h"
+
+#include "android-base/stringprintf.h"
+
+namespace startop {
+
+using android::base::StringPrintf;
+
+void LayoutValidationVisitor::VisitStartTag(const std::u16string& name) {
+  if (0 == name.compare(u"merge")) {
+    message_ = "Merge tags are not supported";
+    can_compile_ = false;
+  }
+  if (0 == name.compare(u"include")) {
+    message_ = "Include tags are not supported";
+    can_compile_ = false;
+  }
+  if (0 == name.compare(u"view")) {
+    message_ = "View tags are not supported";
+    can_compile_ = false;
+  }
+  if (0 == name.compare(u"fragment")) {
+    message_ = "Fragment tags are not supported";
+    can_compile_ = false;
+  }
+}
+
+DexViewBuilder::DexViewBuilder(dex::MethodBuilder* method)
+    : method_{method},
+      context_{dex::Value::Parameter(0)},
+      resid_{dex::Value::Parameter(1)},
+      inflater_{method->MakeRegister()},
+      xml_{method->MakeRegister()},
+      attrs_{method->MakeRegister()},
+      classname_tmp_{method->MakeRegister()},
+      xml_next_{method->dex_file()->GetOrDeclareMethod(
+          dex::TypeDescriptor::FromClassname("android.content.res.XmlResourceParser"), "next",
+          dex::Prototype{dex::TypeDescriptor::Int()})},
+      try_create_view_{method->dex_file()->GetOrDeclareMethod(
+          dex::TypeDescriptor::FromClassname("android.view.LayoutInflater"), "tryCreateView",
+          dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.View"),
+                         dex::TypeDescriptor::FromClassname("android.view.View"),
+                         dex::TypeDescriptor::FromClassname("java.lang.String"),
+                         dex::TypeDescriptor::FromClassname("android.content.Context"),
+                         dex::TypeDescriptor::FromClassname("android.util.AttributeSet")})},
+      generate_layout_params_{method->dex_file()->GetOrDeclareMethod(
+          dex::TypeDescriptor::FromClassname("android.view.ViewGroup"), "generateLayoutParams",
+          dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.ViewGroup$LayoutParams"),
+                         dex::TypeDescriptor::FromClassname("android.util.AttributeSet")})},
+      add_view_{method->dex_file()->GetOrDeclareMethod(
+          dex::TypeDescriptor::FromClassname("android.view.ViewGroup"), "addView",
+          dex::Prototype{
+              dex::TypeDescriptor::Void(),
+              dex::TypeDescriptor::FromClassname("android.view.View"),
+              dex::TypeDescriptor::FromClassname("android.view.ViewGroup$LayoutParams")})},
+      // The register stack starts with one register, which will be null for the root view.
+      register_stack_{{method->MakeRegister()}} {}
+
+void DexViewBuilder::Start() {
+  dex::DexBuilder* const dex = method_->dex_file();
+
+  // LayoutInflater inflater = LayoutInflater.from(context);
+  auto layout_inflater_from = dex->GetOrDeclareMethod(
+      dex::TypeDescriptor::FromClassname("android.view.LayoutInflater"),
+      "from",
+      dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.LayoutInflater"),
+                     dex::TypeDescriptor::FromClassname("android.content.Context")});
+  method_->AddInstruction(
+      dex::Instruction::InvokeStaticObject(layout_inflater_from.id, /*dest=*/inflater_, context_));
+
+  // Resources res = context.getResources();
+  auto context_type = dex::TypeDescriptor::FromClassname("android.content.Context");
+  auto resources_type = dex::TypeDescriptor::FromClassname("android.content.res.Resources");
+  auto get_resources =
+      dex->GetOrDeclareMethod(context_type, "getResources", dex::Prototype{resources_type});
+  method_->AddInstruction(dex::Instruction::InvokeVirtualObject(get_resources.id, xml_, context_));
+
+  // XmlResourceParser xml = res.getLayout(resid);
+  auto xml_resource_parser_type =
+      dex::TypeDescriptor::FromClassname("android.content.res.XmlResourceParser");
+  auto get_layout =
+      dex->GetOrDeclareMethod(resources_type,
+                              "getLayout",
+                              dex::Prototype{xml_resource_parser_type, dex::TypeDescriptor::Int()});
+  method_->AddInstruction(dex::Instruction::InvokeVirtualObject(get_layout.id, xml_, xml_, resid_));
+
+  // AttributeSet attrs = Xml.asAttributeSet(xml);
+  auto as_attribute_set = dex->GetOrDeclareMethod(
+      dex::TypeDescriptor::FromClassname("android.util.Xml"),
+      "asAttributeSet",
+      dex::Prototype{dex::TypeDescriptor::FromClassname("android.util.AttributeSet"),
+                     dex::TypeDescriptor::FromClassname("org.xmlpull.v1.XmlPullParser")});
+  method_->AddInstruction(dex::Instruction::InvokeStaticObject(as_attribute_set.id, attrs_, xml_));
+
+  // xml.next(); // start document
+  method_->AddInstruction(dex::Instruction::InvokeInterface(xml_next_.id, {}, xml_));
+}
+
+void DexViewBuilder::Finish() {}
+
+namespace {
+std::string ResolveName(const std::string& name) {
+  if (name == "View") return "android.view.View";
+  if (name == "ViewGroup") return "android.view.ViewGroup";
+  if (name.find(".") == std::string::npos) {
+    return StringPrintf("android.widget.%s", name.c_str());
+  }
+  return name;
+}
+}  // namespace
+
+void DexViewBuilder::StartView(const std::string& name, bool is_viewgroup) {
+  bool const is_root_view = view_stack_.empty();
+
+  // xml.next(); // start tag
+  method_->AddInstruction(dex::Instruction::InvokeInterface(xml_next_.id, {}, xml_));
+
+  dex::Value view = AcquireRegister();
+  // try to create the view using the factories
+  method_->BuildConstString(classname_tmp_,
+                            name);  // TODO: the need to fully qualify the classname
+  if (is_root_view) {
+    dex::Value null = AcquireRegister();
+    method_->BuildConst4(null, 0);
+    method_->AddInstruction(dex::Instruction::InvokeVirtualObject(
+        try_create_view_.id, view, inflater_, null, classname_tmp_, context_, attrs_));
+    ReleaseRegister();
+  } else {
+    method_->AddInstruction(dex::Instruction::InvokeVirtualObject(
+        try_create_view_.id, view, inflater_, GetCurrentView(), classname_tmp_, context_, attrs_));
+  }
+  auto label = method_->MakeLabel();
+  // branch if not null
+  method_->AddInstruction(
+      dex::Instruction::OpWithArgs(dex::Instruction::Op::kBranchNEqz, /*dest=*/{}, view, label));
+
+  // If null, create the class directly.
+  method_->BuildNew(view,
+                    dex::TypeDescriptor::FromClassname(ResolveName(name)),
+                    dex::Prototype{dex::TypeDescriptor::Void(),
+                                   dex::TypeDescriptor::FromClassname("android.content.Context"),
+                                   dex::TypeDescriptor::FromClassname("android.util.AttributeSet")},
+                    context_,
+                    attrs_);
+
+  method_->AddInstruction(
+      dex::Instruction::OpWithArgs(dex::Instruction::Op::kBindLabel, /*dest=*/{}, label));
+
+  if (is_viewgroup) {
+    // Cast to a ViewGroup so we can add children later.
+    const ir::Type* view_group_def = method_->dex_file()->GetOrAddType(
+        dex::TypeDescriptor::FromClassname("android.view.ViewGroup").descriptor());
+    method_->AddInstruction(dex::Instruction::Cast(view, dex::Value::Type(view_group_def->orig_index)));
+  }
+
+  if (!is_root_view) {
+    // layout_params = parent.generateLayoutParams(attrs);
+    dex::Value layout_params{AcquireRegister()};
+    method_->AddInstruction(dex::Instruction::InvokeVirtualObject(
+        generate_layout_params_.id, layout_params, GetCurrentView(), attrs_));
+    view_stack_.push_back({view, layout_params});
+  } else {
+    view_stack_.push_back({view, {}});
+  }
+}
+
+void DexViewBuilder::FinishView() {
+  if (view_stack_.size() == 1) {
+    method_->BuildReturn(GetCurrentView(), /*is_object=*/true);
+  } else {
+    // parent.add(view, layout_params)
+    method_->AddInstruction(dex::Instruction::InvokeVirtual(
+        add_view_.id, /*dest=*/{}, GetParentView(), GetCurrentView(), GetCurrentLayoutParams()));
+    // xml.next(); // end tag
+    method_->AddInstruction(dex::Instruction::InvokeInterface(xml_next_.id, {}, xml_));
+  }
+  PopViewStack();
+}
+
+dex::Value DexViewBuilder::AcquireRegister() {
+  top_register_++;
+  if (register_stack_.size() == top_register_) {
+    register_stack_.push_back(method_->MakeRegister());
+  }
+  return register_stack_[top_register_];
+}
+
+void DexViewBuilder::ReleaseRegister() { top_register_--; }
+
+dex::Value DexViewBuilder::GetCurrentView() const { return view_stack_.back().view; }
+dex::Value DexViewBuilder::GetCurrentLayoutParams() const {
+  return view_stack_.back().layout_params.value();
+}
+dex::Value DexViewBuilder::GetParentView() const {
+  return view_stack_[view_stack_.size() - 2].view;
+}
+
+void DexViewBuilder::PopViewStack() {
+  const auto& top = view_stack_.back();
+  // release the layout params if we have them
+  if (top.layout_params.has_value()) {
+    ReleaseRegister();
+  }
+  // Unconditionally release the view register.
+  ReleaseRegister();
+  view_stack_.pop_back();
+}
+
+}  // namespace startop
\ No newline at end of file
diff --git a/startop/view_compiler/dex_layout_compiler.h b/startop/view_compiler/dex_layout_compiler.h
new file mode 100644
index 0000000..170a1a6
--- /dev/null
+++ b/startop/view_compiler/dex_layout_compiler.h
@@ -0,0 +1,118 @@
+/*
+ * 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 DEX_LAYOUT_COMPILER_H_
+#define DEX_LAYOUT_COMPILER_H_
+
+#include "dex_builder.h"
+
+#include <codecvt>
+#include <locale>
+#include <string>
+#include <vector>
+
+namespace startop {
+
+// This visitor does the actual view compilation, using a supplied builder.
+template <typename Builder>
+class LayoutCompilerVisitor {
+ public:
+  explicit LayoutCompilerVisitor(Builder* builder) : builder_{builder} {}
+
+  void VisitStartDocument() { builder_->Start(); }
+  void VisitEndDocument() { builder_->Finish(); }
+  void VisitStartTag(const std::u16string& name) {
+    parent_stack_.push_back(ViewEntry{
+        std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(name), {}});
+  }
+  void VisitEndTag() {
+    auto entry = parent_stack_.back();
+    parent_stack_.pop_back();
+
+    if (parent_stack_.empty()) {
+      GenerateCode(entry);
+    } else {
+      parent_stack_.back().children.push_back(entry);
+    }
+  }
+
+ private:
+  struct ViewEntry {
+    std::string name;
+    std::vector<ViewEntry> children;
+  };
+
+  void GenerateCode(const ViewEntry& view) {
+    builder_->StartView(view.name, !view.children.empty());
+    for (const auto& child : view.children) {
+      GenerateCode(child);
+    }
+    builder_->FinishView();
+  }
+
+  Builder* builder_;
+
+  std::vector<ViewEntry> parent_stack_;
+};
+
+class DexViewBuilder {
+ public:
+  DexViewBuilder(dex::MethodBuilder* method);
+
+  void Start();
+  void Finish();
+  void StartView(const std::string& name, bool is_viewgroup);
+  void FinishView();
+
+ private:
+  // Accessors for the stack of views that are under construction.
+  dex::Value AcquireRegister();
+  void ReleaseRegister();
+  dex::Value GetCurrentView() const;
+  dex::Value GetCurrentLayoutParams() const;
+  dex::Value GetParentView() const;
+  void PopViewStack();
+
+  dex::MethodBuilder* method_;
+
+  // Registers used for code generation
+  dex::Value const context_;
+  dex::Value const resid_;
+  const dex::Value inflater_;
+  const dex::Value xml_;
+  const dex::Value attrs_;
+  const dex::Value classname_tmp_;
+
+  const dex::MethodDeclData xml_next_;
+  const dex::MethodDeclData try_create_view_;
+  const dex::MethodDeclData generate_layout_params_;
+  const dex::MethodDeclData add_view_;
+
+  // used for keeping track of which registers are in use
+  size_t top_register_{0};
+  std::vector<dex::Value> register_stack_;
+
+  // Keep track of the views currently in progress.
+  struct ViewEntry {
+    dex::Value view;
+    std::optional<dex::Value> layout_params;
+  };
+  std::vector<ViewEntry> view_stack_;
+};
+
+}  // namespace startop
+
+#endif  // DEX_LAYOUT_COMPILER_H_
diff --git a/startop/view_compiler/java_lang_builder.cc b/startop/view_compiler/java_lang_builder.cc
index 0b8754f..920caee 100644
--- a/startop/view_compiler/java_lang_builder.cc
+++ b/startop/view_compiler/java_lang_builder.cc
@@ -67,7 +67,7 @@
           "}\n";     // end CompiledView
 }
 
-void JavaLangViewBuilder::StartView(const string& class_name) {
+void JavaLangViewBuilder::StartView(const string& class_name, bool /*is_viewgroup*/) {
   const string view_var = MakeVar("view");
   const string layout_var = MakeVar("layout");
   std::string parent = "null";
diff --git a/startop/view_compiler/java_lang_builder.h b/startop/view_compiler/java_lang_builder.h
index c8d20b2..69356d3 100644
--- a/startop/view_compiler/java_lang_builder.h
+++ b/startop/view_compiler/java_lang_builder.h
@@ -35,7 +35,7 @@
   void Finish() const;
 
   // Begin creating a view (i.e. process the opening tag)
-  void StartView(const std::string& class_name);
+  void StartView(const std::string& class_name, bool is_viewgroup);
   // Finish a view, after all of its child nodes have been processed.
   void FinishView();
 
diff --git a/startop/view_compiler/main.cc b/startop/view_compiler/main.cc
index 609bcf3..11ecde2 100644
--- a/startop/view_compiler/main.cc
+++ b/startop/view_compiler/main.cc
@@ -16,8 +16,12 @@
 
 #include "gflags/gflags.h"
 
+#include "android-base/stringprintf.h"
+#include "apk_layout_compiler.h"
 #include "dex_builder.h"
+#include "dex_layout_compiler.h"
 #include "java_lang_builder.h"
+#include "layout_validation.h"
 #include "tinyxml_layout_parser.h"
 #include "util.h"
 
@@ -32,49 +36,67 @@
 namespace {
 
 using namespace tinyxml2;
+using android::base::StringPrintf;
+using startop::dex::ClassBuilder;
+using startop::dex::DexBuilder;
+using startop::dex::MethodBuilder;
+using startop::dex::Prototype;
+using startop::dex::TypeDescriptor;
 using namespace startop::util;
 using std::string;
 
 constexpr char kStdoutFilename[]{"stdout"};
 
+DEFINE_bool(apk, false, "Compile layouts in an APK");
 DEFINE_bool(dex, false, "Generate a DEX file instead of Java");
+DEFINE_int32(infd, -1, "Read input from the given file descriptor");
 DEFINE_string(out, kStdoutFilename, "Where to write the generated class");
 DEFINE_string(package, "", "The package name for the generated class (required)");
 
-class ViewCompilerXmlVisitor : public XMLVisitor {
+template <typename Visitor>
+class XmlVisitorAdapter : public XMLVisitor {
  public:
-  explicit ViewCompilerXmlVisitor(JavaLangViewBuilder* builder) : builder_(builder) {}
+  explicit XmlVisitorAdapter(Visitor* visitor) : visitor_{visitor} {}
 
   bool VisitEnter(const XMLDocument& /*doc*/) override {
-    builder_->Start();
+    visitor_->VisitStartDocument();
     return true;
   }
 
   bool VisitExit(const XMLDocument& /*doc*/) override {
-    builder_->Finish();
+    visitor_->VisitEndDocument();
     return true;
   }
 
   bool VisitEnter(const XMLElement& element, const XMLAttribute* /*firstAttribute*/) override {
-    builder_->StartView(element.Name());
+    visitor_->VisitStartTag(
+        std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(
+            element.Name()));
     return true;
   }
 
   bool VisitExit(const XMLElement& /*element*/) override {
-    builder_->FinishView();
+    visitor_->VisitEndTag();
     return true;
   }
 
  private:
-  JavaLangViewBuilder* builder_;
+  Visitor* visitor_;
 };
 
+template <typename Builder>
+void CompileLayout(XMLDocument* xml, Builder* builder) {
+  startop::LayoutCompilerVisitor visitor{builder};
+  XmlVisitorAdapter<decltype(visitor)> adapter{&visitor};
+  xml->Accept(&adapter);
+}
+
 }  // end namespace
 
 int main(int argc, char** argv) {
   constexpr size_t kProgramName = 0;
   constexpr size_t kFileNameParam = 1;
-  constexpr size_t kNumRequiredArgs = 2;
+  constexpr size_t kNumRequiredArgs = 1;
 
   gflags::SetUsageMessage(
       "Compile XML layout files into equivalent Java language code\n"
@@ -83,21 +105,37 @@
   gflags::ParseCommandLineFlags(&argc, &argv, /*remove_flags*/ true);
 
   gflags::CommandLineFlagInfo cmd = gflags::GetCommandLineFlagInfoOrDie("package");
-  if (argc != kNumRequiredArgs || cmd.is_default) {
+  if (argc < kNumRequiredArgs || cmd.is_default) {
     gflags::ShowUsageWithFlags(argv[kProgramName]);
     return 1;
   }
 
-  if (FLAGS_dex) {
-    startop::dex::WriteTestDexFile("test.dex");
+  const bool is_stdout = FLAGS_out == kStdoutFilename;
+
+  std::ofstream outfile;
+  if (!is_stdout) {
+    outfile.open(FLAGS_out);
+  }
+
+  if (FLAGS_apk) {
+    const startop::CompilationTarget target =
+        FLAGS_dex ? startop::CompilationTarget::kDex : startop::CompilationTarget::kJavaLanguage;
+    if (FLAGS_infd >= 0) {
+      startop::CompileApkLayoutsFd(
+          android::base::unique_fd{FLAGS_infd}, target, is_stdout ? std::cout : outfile);
+    } else {
+      if (argc < 2) {
+        gflags::ShowUsageWithFlags(argv[kProgramName]);
+        return 1;
+      }
+      const char* const filename = argv[kFileNameParam];
+      startop::CompileApkLayouts(filename, target, is_stdout ? std::cout : outfile);
+    }
     return 0;
   }
 
   const char* const filename = argv[kFileNameParam];
-  const string layout_name = FindLayoutNameFromFilename(filename);
-
-  // We want to generate Java language code to inflate exactly this layout. This means
-  // generating code to walk the resource XML too.
+  const string layout_name = startop::util::FindLayoutNameFromFilename(filename);
 
   XMLDocument xml;
   xml.LoadFile(filename);
@@ -108,15 +146,27 @@
     return 1;
   }
 
-  std::ofstream outfile;
-  if (FLAGS_out != kStdoutFilename) {
-    outfile.open(FLAGS_out);
+  if (FLAGS_dex) {
+    DexBuilder dex_file;
+    string class_name = StringPrintf("%s.CompiledView", FLAGS_package.c_str());
+    ClassBuilder compiled_view{dex_file.MakeClass(class_name)};
+    MethodBuilder method{compiled_view.CreateMethod(
+        layout_name,
+        Prototype{TypeDescriptor::FromClassname("android.view.View"),
+                  TypeDescriptor::FromClassname("android.content.Context"),
+                  TypeDescriptor::Int()})};
+    startop::DexViewBuilder builder{&method};
+    CompileLayout(&xml, &builder);
+    method.Encode();
+
+    slicer::MemView image{dex_file.CreateImage()};
+
+    (is_stdout ? std::cout : outfile).write(image.ptr<const char>(), image.size());
+  } else {
+    // Generate Java language output.
+    JavaLangViewBuilder builder{FLAGS_package, layout_name, is_stdout ? std::cout : outfile};
+
+    CompileLayout(&xml, &builder);
   }
-  JavaLangViewBuilder builder{
-      FLAGS_package, layout_name, FLAGS_out == kStdoutFilename ? std::cout : outfile};
-
-  ViewCompilerXmlVisitor visitor{&builder};
-  xml.Accept(&visitor);
-
   return 0;
 }
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 2820836..dcaa499 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -239,6 +239,30 @@
             "android.telecom.event.HANDOVER_FAILED";
 
     public static class Details {
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(
+                prefix = { "DIRECTION_" },
+                value = {DIRECTION_UNKNOWN, DIRECTION_INCOMING, DIRECTION_OUTGOING})
+        public @interface CallDirection {}
+
+        /**
+         * Indicates that the call is neither and incoming nor an outgoing call.  This can be the
+         * case for calls reported directly by a {@link ConnectionService} in special cases such as
+         * call handovers.
+         */
+        public static final int DIRECTION_UNKNOWN = -1;
+
+        /**
+         * Indicates that the call is an incoming call.
+         */
+        public static final int DIRECTION_INCOMING = 0;
+
+        /**
+         * Indicates that the call is an outgoing call.
+         */
+        public static final int DIRECTION_OUTGOING = 1;
+
 
         /** Call can currently be put on hold or unheld. */
         public static final int CAPABILITY_HOLD = 0x00000001;
@@ -519,6 +543,7 @@
         private final Bundle mIntentExtras;
         private final long mCreationTimeMillis;
         private final CallIdentification mCallIdentification;
+        private final @CallDirection int mCallDirection;
 
         /**
          * Whether the supplied capabilities  supports the specified capability.
@@ -838,6 +863,14 @@
             return mCallIdentification;
         }
 
+        /**
+         * Indicates whether the call is an incoming or outgoing call.
+         * @return The call's direction.
+         */
+        public @CallDirection int getCallDirection() {
+            return mCallDirection;
+        }
+
         @Override
         public boolean equals(Object o) {
             if (o instanceof Details) {
@@ -859,7 +892,8 @@
                         areBundlesEqual(mExtras, d.mExtras) &&
                         areBundlesEqual(mIntentExtras, d.mIntentExtras) &&
                         Objects.equals(mCreationTimeMillis, d.mCreationTimeMillis) &&
-                        Objects.equals(mCallIdentification, d.mCallIdentification);
+                        Objects.equals(mCallIdentification, d.mCallIdentification) &&
+                        Objects.equals(mCallDirection, d.mCallDirection);
             }
             return false;
         }
@@ -881,7 +915,8 @@
                             mExtras,
                             mIntentExtras,
                             mCreationTimeMillis,
-                            mCallIdentification);
+                            mCallIdentification,
+                            mCallDirection);
         }
 
         /** {@hide} */
@@ -902,7 +937,8 @@
                 Bundle extras,
                 Bundle intentExtras,
                 long creationTimeMillis,
-                CallIdentification callIdentification) {
+                CallIdentification callIdentification,
+                int callDirection) {
             mTelecomCallId = telecomCallId;
             mHandle = handle;
             mHandlePresentation = handlePresentation;
@@ -920,6 +956,7 @@
             mIntentExtras = intentExtras;
             mCreationTimeMillis = creationTimeMillis;
             mCallIdentification = callIdentification;
+            mCallDirection = callDirection;
         }
 
         /** {@hide} */
@@ -941,7 +978,8 @@
                     parcelableCall.getExtras(),
                     parcelableCall.getIntentExtras(),
                     parcelableCall.getCreationTimeMillis(),
-                    parcelableCall.getCallIdentification());
+                    parcelableCall.getCallIdentification(),
+                    parcelableCall.getCallDirection());
         }
 
         @Override
diff --git a/telecomm/java/android/telecom/CallIdentification.java b/telecomm/java/android/telecom/CallIdentification.java
index 97af06c..87834fd 100644
--- a/telecomm/java/android/telecom/CallIdentification.java
+++ b/telecomm/java/android/telecom/CallIdentification.java
@@ -250,8 +250,8 @@
         mDetails = details;
         mPhoto = photo;
         mNuisanceConfidence = nuisanceConfidence;
-        mCallScreeningAppName = callScreeningPackageName;
-        mCallScreeningPackageName = callScreeningAppName;
+        mCallScreeningAppName = callScreeningAppName;
+        mCallScreeningPackageName = callScreeningPackageName;
     }
 
     private String mName;
@@ -430,4 +430,22 @@
         return Objects.hash(mName, mDescription, mDetails, mPhoto, mNuisanceConfidence,
                 mCallScreeningAppName, mCallScreeningPackageName);
     }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[CallId mName=");
+        sb.append(Log.pii(mName));
+        sb.append(", mDesc=");
+        sb.append(mDescription);
+        sb.append(", mDet=");
+        sb.append(mDetails);
+        sb.append(", conf=");
+        sb.append(mNuisanceConfidence);
+        sb.append(", appName=");
+        sb.append(mCallScreeningAppName);
+        sb.append(", pkgName=");
+        sb.append(mCallScreeningPackageName);
+        return sb.toString();
+    }
 }
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index b906d0b..3299117 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -16,6 +16,7 @@
 
 package android.telecom;
 
+import android.annotation.NonNull;
 import android.annotation.SdkConstant;
 import android.app.Service;
 import android.content.Intent;
@@ -27,8 +28,8 @@
 import android.os.RemoteException;
 
 import com.android.internal.os.SomeArgs;
-import com.android.internal.telecom.ICallRedirectionService;
 import com.android.internal.telecom.ICallRedirectionAdapter;
+import com.android.internal.telecom.ICallRedirectionService;
 
 /**
  * This service can be implemented to interact between Telecom and its implementor
@@ -62,22 +63,35 @@
 
     /**
      * Telecom calls this method to inform the implemented {@link CallRedirectionService} of
-     * a new outgoing call which is being placed.
+     * a new outgoing call which is being placed. Telecom does not request to redirect emergency
+     * calls and does not request to redirect calls with gateway information.
      *
-     * The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
-     * {@link #redirectCall(Uri, PhoneAccountHandle)}, and {@link #cancelCall()} only from here.
+     * <p>Telecom will cancel the call if Telecom does not receive a response in 5 seconds from
+     * the implemented {@link CallRedirectionService} set by users.
      *
-     * @param handle the phone number dialed by the user
-     * @param targetPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
+     * <p>The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
+     * {@link #redirectCall(Uri, PhoneAccountHandle, boolean)}, and {@link #cancelCall()} only
+     * from here.
+     *
+     * @param handle the phone number dialed by the user, represented in E.164 format if possible
+     * @param initialPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
+     * @param allowInteractiveResponse a boolean to tell if the implemented
+     *                                 {@link CallRedirectionService} should allow interactive
+     *                                 responses with users. Will be {@code false} if, for example
+     *                                 the device is in car mode and the user would not be able to
+     *                                 interact with their device.
      */
-    public abstract void onPlaceCall(Uri handle, PhoneAccountHandle targetPhoneAccount);
+    public abstract void onPlaceCall(@NonNull Uri handle,
+                                     @NonNull PhoneAccountHandle initialPhoneAccount,
+                                     boolean allowInteractiveResponse);
 
     /**
      * The implemented {@link CallRedirectionService} calls this method to response a request
-     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that no changes
-     * are required to the outgoing call, and that the call should be placed as-is.
+     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+     * no changes are required to the outgoing call, and that the call should be placed as-is.
      *
-     * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+     * <p>This can only be called from implemented
+     * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
      *
      */
     public final void placeCallUnmodified() {
@@ -89,29 +103,39 @@
 
     /**
      * The implemented {@link CallRedirectionService} calls this method to response a request
-     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that changes
-     * are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing call.
+     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+     * changes are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing
+     * call. Telecom will cancel the call if the implemented {@link CallRedirectionService}
+     * replies Telecom a handle for an emergency number.
      *
-     * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+     * <p>This can only be called from implemented
+     * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
      *
      * @param handle the new phone number to dial
      * @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
      *                           If {@code null}, no change will be made to the
      *                           {@link PhoneAccountHandle} used to place the call.
+     * @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog
+     *                     if the confirmFirst is true, and if the redirection request of this
+     *                     response was sent with a true flag of allowInteractiveResponse via
+     *                     {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}
      */
-    public final void redirectCall(Uri handle, PhoneAccountHandle targetPhoneAccount) {
+    public final void redirectCall(@NonNull Uri handle,
+                                   @NonNull PhoneAccountHandle targetPhoneAccount,
+                                   boolean confirmFirst) {
         try {
-            mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount);
+            mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount, confirmFirst);
         } catch (RemoteException e) {
         }
     }
 
     /**
      * The implemented {@link CallRedirectionService} calls this method to response a request
-     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that an outgoing
-     * call should be canceled entirely.
+     * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+     * an outgoing call should be canceled entirely.
      *
-     * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+     * <p>This can only be called from implemented
+     * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
      *
      */
     public final void cancelCall() {
@@ -137,7 +161,8 @@
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
                         mCallRedirectionAdapter = (ICallRedirectionAdapter) args.arg1;
-                        onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3);
+                        onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3,
+                                (boolean) args.arg4);
                     } finally {
                         args.recycle();
                     }
@@ -152,15 +177,20 @@
          * Telecom calls this method to inform the CallRedirectionService of a new outgoing call
          * which is about to be placed.
          * @param handle the phone number dialed by the user
-         * @param targetPhoneAccount the URI of the number the user dialed
+         * @param initialPhoneAccount the URI of the number the user dialed
+         * @param allowInteractiveResponse a boolean to tell if the implemented
+         *                                 {@link CallRedirectionService} should allow interactive
+         *                                 responses with users.
          */
         @Override
-        public void placeCall(ICallRedirectionAdapter adapter, Uri handle,
-                              PhoneAccountHandle targetPhoneAccount) {
+        public void placeCall(@NonNull ICallRedirectionAdapter adapter, @NonNull Uri handle,
+                              @NonNull PhoneAccountHandle initialPhoneAccount,
+                              boolean allowInteractiveResponse) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = adapter;
             args.arg2 = handle;
-            args.arg3 = targetPhoneAccount;
+            args.arg3 = initialPhoneAccount;
+            args.arg4 = allowInteractiveResponse;
             mHandler.obtainMessage(MSG_PLACE_CALL, args).sendToTarget();
         }
     }
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index be96b3c..818ebd9 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -16,11 +16,13 @@
 
 package android.telecom;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SdkConstant;
 import android.app.Service;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -31,10 +33,14 @@
 import com.android.internal.telecom.ICallScreeningAdapter;
 import com.android.internal.telecom.ICallScreeningService;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * This service can be implemented by the default dialer (see
- * {@link TelecomManager#getDefaultDialerPackage()}) to allow or disallow incoming calls before
- * they are shown to a user.
+ * {@link TelecomManager#getDefaultDialerPackage()}) or a third party app to allow or disallow
+ * incoming calls before they are shown to a user.  This service can also provide
+ * {@link CallIdentification} information for calls.
  * <p>
  * Below is an example manifest registration for a {@code CallScreeningService}.
  * <pre>
@@ -56,8 +62,158 @@
  *     information about a {@link Call.Details call} which will be shown to the user in the
  *     Dialer app.</li>
  * </ol>
+ * <p>
+ * <h2>Becoming the {@link CallScreeningService}</h2>
+ * Telecom will bind to a single app chosen by the user which implements the
+ * {@link CallScreeningService} API when there are new incoming and outgoing calls.
+ * <p>
+ * The code snippet below illustrates how your app can request that it fills the call screening
+ * role.
+ * <pre>
+ * {@code
+ * private static final int REQUEST_ID = 1;
+ *
+ * public void requestRole() {
+ *     RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
+ *     Intent intent = roleManager.createRequestRoleIntent("android.app.role.CALL_SCREENING_APP");
+ *     startActivityForResult(intent, REQUEST_ID);
+ * }
+ *
+ * &#64;Override
+ * public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ *     if (requestCode == REQUEST_ID) {
+ *         if (resultCode == android.app.Activity.RESULT_OK) {
+ *             // Your app is now the call screening app
+ *         } else {
+ *             // Your app is not the call screening app
+ *         }
+ *     }
+ * }
+ * </pre>
  */
 public abstract class CallScreeningService extends Service {
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+            prefix = { "CALL_DURATION_" },
+            value = {CALL_DURATION_VERY_SHORT, CALL_DURATION_SHORT, CALL_DURATION_MEDIUM,
+                    CALL_DURATION_LONG})
+    public @interface CallDuration {}
+
+    /**
+     * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
+     * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
+     * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}).  The
+     * {@link CallScreeningService} can use this as a signal for training nuisance detection
+     * algorithms.  The call duration is reported in coarse grained buckets to minimize exposure of
+     * identifying call log information to the {@link CallScreeningService}.
+     * <p>
+     * Indicates the call was < 3 seconds in duration.
+     */
+    public static final int CALL_DURATION_VERY_SHORT = 1;
+
+    /**
+     * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
+     * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
+     * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}).  The
+     * {@link CallScreeningService} can use this as a signal for training nuisance detection
+     * algorithms.  The call duration is reported in coarse grained buckets to minimize exposure of
+     * identifying call log information to the {@link CallScreeningService}.
+     * <p>
+     * Indicates the call was greater than 3 seconds, but less than 60 seconds in duration.
+     */
+    public static final int CALL_DURATION_SHORT = 2;
+
+    /**
+     * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
+     * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
+     * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}).  The
+     * {@link CallScreeningService} can use this as a signal for training nuisance detection
+     * algorithms.  The call duration is reported in coarse grained buckets to minimize exposure of
+     * identifying call log information to the {@link CallScreeningService}.
+     * <p>
+     * Indicates the call was greater than 60 seconds, but less than 120 seconds in duration.
+     */
+    public static final int CALL_DURATION_MEDIUM = 3;
+
+    /**
+     * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
+     * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
+     * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}).  The
+     * {@link CallScreeningService} can use this as a signal for training nuisance detection
+     * algorithms.  The call duration is reported in coarse grained buckets to minimize exposure of
+     * identifying call log information to the {@link CallScreeningService}.
+     * <p>
+     * Indicates the call was greater than 120 seconds.
+     */
+    public static final int CALL_DURATION_LONG = 4;
+
+    /**
+     * Telecom sends this intent to the {@link CallScreeningService} which the user has chosen to
+     * fill the call screening role when the user indicates through the default dialer whether a
+     * call is a nuisance call or not (see
+     * {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}).
+     * <p>
+     * The following extra values are provided for the call:
+     * <ol>
+     *     <li>{@link #EXTRA_CALL_HANDLE} - the handle of the call.</li>
+     *     <li>{@link #EXTRA_IS_NUISANCE} - {@code true} if the user reported the call as a nuisance
+     *     call, {@code false} otherwise.</li>
+     *     <li>{@link #EXTRA_CALL_TYPE} - reports the type of call (incoming, rejected, missed,
+     *     blocked).</li>
+     *     <li>{@link #EXTRA_CALL_DURATION} - the duration of the call (see
+     *     {@link #EXTRA_CALL_DURATION} for valid values).</li>
+     * </ol>
+     * <p>
+     * {@link CallScreeningService} implementations which want to track whether the user reports
+     * calls are nuisance calls should use declare a broadcast receiver in their manifest for this
+     * intent.
+     * <p>
+     * Note: Only {@link CallScreeningService} implementations which have provided
+     * {@link CallIdentification} information for calls at some point will receive this intent.
+     */
+    public static final String ACTION_NUISANCE_CALL_STATUS_CHANGED =
+            "android.telecom.action.NUISANCE_CALL_STATUS_CHANGED";
+
+    /**
+     * Extra used to provide the handle of the call for
+     * {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED}.  The call handle is reported as a
+     * {@link Uri}.
+     */
+    public static final String EXTRA_CALL_HANDLE = "android.telecom.extra.CALL_HANDLE";
+
+    /**
+     * Boolean extra used to indicate whether the user reported a call as a nuisance call.
+     * When {@code true}, the user reported that a call was a nuisance call, {@code false}
+     * otherwise.  Sent with {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED}.
+     */
+    public static final String EXTRA_IS_NUISANCE = "android.telecom.extra.IS_NUISANCE";
+
+    /**
+     * Integer extra used with {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED} to report the type of
+     * call. Valid values are:
+     * <UL>
+     *   <li>{@link android.provider.CallLog.Calls#MISSED_TYPE}</li>
+     *   <li>{@link android.provider.CallLog.Calls#INCOMING_TYPE}</li>
+     *   <li>{@link android.provider.CallLog.Calls#BLOCKED_TYPE}</li>
+     *   <li>{@link android.provider.CallLog.Calls#REJECTED_TYPE}</li>
+     * </UL>
+     */
+    public static final String EXTRA_CALL_TYPE = "android.telecom.extra.CALL_TYPE";
+
+    /**
+     * Integer extra used to with {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED} to report how long
+     * the call lasted.  Valid values are:
+     * <UL>
+     *     <LI>{@link #CALL_DURATION_VERY_SHORT}</LI>
+     *     <LI>{@link #CALL_DURATION_SHORT}</LI>
+     *     <LI>{@link #CALL_DURATION_MEDIUM}</LI>
+     *     <LI>{@link #CALL_DURATION_LONG}</LI>
+     * </UL>
+     */
+    public static final String EXTRA_CALL_DURATION = "android.telecom.extra.CALL_DURATION";
+
     /**
      * The {@link Intent} that must be declared as handled by the service.
      */
@@ -222,30 +378,46 @@
     }
 
     /**
-     * Called when a new incoming call is added.
-     * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}
-     * should be called to allow or disallow the call.
+     * Called when a new incoming or outgoing call is added which is not in the user's contact list.
+     * <p>
+     * A {@link CallScreeningService} must indicate whether an incoming call is allowed or not by
+     * calling
+     * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}.
+     * Your app can tell if a call is an incoming call by checking to see if
+     * {@link Call.Details#getCallDirection()} is {@link Call.Details#DIRECTION_INCOMING}.
+     * <p>
+     * For incoming or outgoing calls, the {@link CallScreeningService} can call
+     * {@link #provideCallIdentification(Call.Details, CallIdentification)} in order to provide
+     * {@link CallIdentification} for the call.
      * <p>
      * Note: The {@link Call.Details} instance provided to a call screening service will only have
      * the following properties set.  The rest of the {@link Call.Details} properties will be set to
      * their default value or {@code null}.
      * <ul>
-     *     <li>{@link Call.Details#getState()}</li>
+     *     <li>{@link Call.Details#getCallDirection()}</li>
      *     <li>{@link Call.Details#getConnectTimeMillis()}</li>
      *     <li>{@link Call.Details#getCreationTimeMillis()}</li>
      *     <li>{@link Call.Details#getHandle()}</li>
      *     <li>{@link Call.Details#getHandlePresentation()}</li>
      * </ul>
+     * <p>
+     * Only calls where the {@link Call.Details#getHandle() handle} {@link Uri#getScheme() scheme}
+     * is {@link PhoneAccount#SCHEME_TEL} are passed for call
+     * screening.  Further, only calls which are not in the user's contacts are passed for
+     * screening.  For outgoing calls, no post-dial digits are passed.
      *
-     * @param callDetails Information about a new incoming call, see {@link Call.Details}.
+     * @param callDetails Information about a new call, see {@link Call.Details}.
      */
     public abstract void onScreenCall(@NonNull Call.Details callDetails);
 
     /**
-     * Responds to the given call, either allowing it or disallowing it.
+     * Responds to the given incoming call, either allowing it or disallowing it.
      * <p>
      * The {@link CallScreeningService} calls this method to inform the system whether the call
      * should be silently blocked or not.
+     * <p>
+     * Calls to this method are ignored unless the {@link Call.Details#getCallDirection()} is
+     * {@link Call.Details#DIRECTION_INCOMING}.
      *
      * @param callDetails The call to allow.
      *                    <p>
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index a39e885..7d1f8ce 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.telecom.Connection.VideoProvider;
@@ -64,6 +65,10 @@
         public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {}
         public void onExtrasChanged(Conference c, Bundle extras) {}
         public void onExtrasRemoved(Conference c, List<String> keys) {}
+        public void onConferenceStateChanged(Conference c, boolean isConference) {}
+        public void onAddressChanged(Conference c, Uri newAddress, int presentation) {}
+        public void onCallerDisplayNameChanged(
+                Conference c, String callerDisplayName, int presentation) {}
     }
 
     private final Set<Listener> mListeners = new CopyOnWriteArraySet<>();
@@ -946,6 +951,62 @@
     public void onExtrasChanged(Bundle extras) {}
 
     /**
+     * Set whether Telecom should treat this {@link Conference} as a conference call or if it
+     * should treat it as a single-party call.
+     * This method is used as part of a workaround regarding IMS conference calls and user
+     * expectation.  In IMS, once a conference is formed, the UE is connected to an IMS conference
+     * server.  If all participants of the conference drop out of the conference except for one, the
+     * UE is still connected to the IMS conference server.  At this point, the user logically
+     * assumes they're no longer in a conference, yet the underlying network actually is.
+     * To help provide a better user experiece, IMS conference calls can pretend to actually be a
+     * single-party call when the participant count drops to 1.  Although the dialer/phone app
+     * could perform this trickery, it makes sense to do this in Telephony since a fix there will
+     * ensure that bluetooth head units, auto and wearable apps all behave consistently.
+     *
+     * @param isConference {@code true} if this {@link Conference} should be treated like a
+     *      conference call, {@code false} if it should be treated like a single-party call.
+     * @hide
+     */
+    public void setConferenceState(boolean isConference) {
+        for (Listener l : mListeners) {
+            l.onConferenceStateChanged(this, isConference);
+        }
+    }
+
+    /**
+     * Sets the address of this {@link Conference}.  Used when {@link #setConferenceState(boolean)}
+     * is called to mark a conference temporarily as NOT a conference.
+     *
+     * @param address The new address.
+     * @param presentation The presentation requirements for the address.
+     *        See {@link TelecomManager} for valid values.
+     * @hide
+     */
+    public final void setAddress(Uri address, int presentation) {
+        Log.d(this, "setAddress %s", address);
+        for (Listener l : mListeners) {
+            l.onAddressChanged(this, address, presentation);
+        }
+    }
+
+    /**
+     * Sets the caller display name (CNAP) of this {@link Conference}.  Used when
+     * {@link #setConferenceState(boolean)} is called to mark a conference temporarily as NOT a
+     * conference.
+     *
+     * @param callerDisplayName The new display name.
+     * @param presentation The presentation requirements for the handle.
+     *        See {@link TelecomManager} for valid values.
+     * @hide
+     */
+    public final void setCallerDisplayName(String callerDisplayName, int presentation) {
+        Log.d(this, "setCallerDisplayName %s", callerDisplayName);
+        for (Listener l : mListeners) {
+            l.onCallerDisplayNameChanged(this, callerDisplayName, presentation);
+        }
+    }
+
+    /**
      * Handles a change to extras received from Telecom.
      *
      * @param extras The new extras.
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 8425603..05d5a13 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -505,6 +505,14 @@
             "android.telecom.extra.ORIGINAL_CONNECTION_ID";
 
     /**
+     * Boolean connection extra key set on the extras passed to
+     * {@link Connection#sendConnectionEvent} which indicates that audio is present
+     * on the RTT call when the extra value is true.
+     */
+    public static final String EXTRA_IS_RTT_AUDIO_PRESENT =
+            "android.telecom.extra.IS_RTT_AUDIO_PRESENT";
+
+    /**
      * Connection event used to inform Telecom that it should play the on hold tone.  This is used
      * to play a tone when the peer puts the current call on hold.  Sent to Telecom via
      * {@link #sendConnectionEvent(String, Bundle)}.
@@ -619,6 +627,13 @@
      */
     public static final String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE";
 
+    /**
+     * Connection event used to inform an {@link InCallService} that the RTT audio indication
+     * has changed.
+     */
+    public static final String EVENT_RTT_AUDIO_INDICATION_CHANGED =
+            "android.telecom.event.RTT_AUDIO_INDICATION_CHANGED";
+
     // Flag controlling whether PII is emitted into the logs
     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
 
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 4d5f5e1..9bafbe0 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1254,6 +1254,31 @@
                 mAdapter.removeExtras(id, keys);
             }
         }
+
+        @Override
+        public void onConferenceStateChanged(Conference c, boolean isConference) {
+            String id = mIdByConference.get(c);
+            if (id != null) {
+                mAdapter.setConferenceState(id, isConference);
+            }
+        }
+
+        @Override
+        public void onAddressChanged(Conference c, Uri newAddress, int presentation) {
+            String id = mIdByConference.get(c);
+            if (id != null) {
+                mAdapter.setAddress(id, newAddress, presentation);
+            }
+        }
+
+        @Override
+        public void onCallerDisplayNameChanged(Conference c, String callerDisplayName,
+                int presentation) {
+            String id = mIdByConference.get(c);
+            if (id != null) {
+                mAdapter.setCallerDisplayName(id, callerDisplayName, presentation);
+            }
+        }
     };
 
     private final Connection.Listener mConnectionListener = new Connection.Listener() {
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index 520e7ed..6c3f4f3 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -653,4 +653,22 @@
             }
         }
     }
+
+    /**
+     * Sets whether a conference is treated as a conference or a single party call.
+     * See {@link Conference#setConferenceState(boolean)} for more information.
+     *
+     * @param callId The ID of the telecom call.
+     * @param isConference {@code true} if this call should be treated as a conference,
+     * {@code false} otherwise.
+     */
+    void setConferenceState(String callId, boolean isConference) {
+        Log.v(this, "setConferenceState: %s %b", callId, isConference);
+        for (IConnectionServiceAdapter adapter : mAdapters) {
+            try {
+                adapter.setConferenceState(callId, isConference, Log.getExternalSession());
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
 }
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index 78d65e6..f99b218 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -74,6 +74,7 @@
     private static final int MSG_ON_RTT_UPGRADE_REQUEST = 33;
     private static final int MSG_SET_PHONE_ACCOUNT_CHANGED = 34;
     private static final int MSG_CONNECTION_SERVICE_FOCUS_RELEASED = 35;
+    private static final int MSG_SET_CONFERENCE_STATE = 36;
 
     private final IConnectionServiceAdapter mDelegate;
 
@@ -333,6 +334,14 @@
                 case MSG_CONNECTION_SERVICE_FOCUS_RELEASED:
                     mDelegate.onConnectionServiceFocusReleased(null /*Session.Info*/);
                     break;
+                case MSG_SET_CONFERENCE_STATE:
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        mDelegate.setConferenceState((String) args.arg1, (Boolean) args.arg2,
+                                (Session.Info) args.arg3);
+                    } finally {
+                        args.recycle();
+                    }
             }
         }
     };
@@ -615,6 +624,16 @@
         public void resetConnectionTime(String callId, Session.Info sessionInfo) {
             // Do nothing
         }
+
+        @Override
+        public void setConferenceState(String callId, boolean isConference,
+                Session.Info sessionInfo) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = isConference;
+            args.arg3 = sessionInfo;
+            mHandler.obtainMessage(MSG_SET_CONFERENCE_STATE, args).sendToTarget();
+        }
     };
 
     public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) {
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 1aeeca7..f5f0af7 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -40,11 +40,30 @@
 import java.util.List;
 
 /**
- * This service is implemented by any app that wishes to provide the user-interface for managing
- * phone calls. Telecom binds to this service while there exists a live (active or incoming) call,
- * and uses it to notify the in-call app of any live and recently disconnected calls. An app must
- * first be set as the default phone app (See {@link TelecomManager#getDefaultDialerPackage()})
- * before the telecom service will bind to its {@code InCallService} implementation.
+ * This service is implemented by an app that wishes to provide functionality for managing
+ * phone calls.
+ * <p>
+ * There are three types of apps which Telecom can bind to when there exists a live (active or
+ * incoming) call:
+ * <ol>
+ *     <li>Default Dialer/Phone app - the default dialer/phone app is one which provides the
+ *     in-call user interface while the device is in a call.  A device is bundled with a system
+ *     provided default dialer/phone app.  The user may choose a single app to take over this role
+ *     from the system app.</li>
+ *     <li>Default Car-mode Dialer/Phone app - the default car-mode dialer/phone app is one which
+ *     provides the in-call user interface while the device is in a call and the device is in car
+ *     mode.  The user may choose a single app to fill this role.</li>
+ *     <li>Call Companion app - a call companion app is one which provides no user interface itself,
+ *     but exposes call information to another display surface, such as a wearable device.  The
+ *     user may choose multiple apps to fill this role.</li>
+ * </ol>
+ * <p>
+ * Apps which wish to fulfill one of the above roles use the {@link android.app.role.RoleManager}
+ * to request that they fill the desired role.
+ *
+ * <h2>Becoming the Default Phone App</h2>
+ * An app filling the role of the default phone app provides a user interface while the device is in
+ * a call, and the device is not in car mode.
  * <p>
  * Below is an example manifest registration for an {@code InCallService}. The meta-data
  * {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} indicates that this particular
@@ -82,12 +101,34 @@
  * }
  * </pre>
  * <p>
- * When a user installs your application and runs it for the first time, you should prompt the user
- * to see if they would like your application to be the new default phone app.  See the
- * {@link TelecomManager#ACTION_CHANGE_DEFAULT_DIALER} intent documentation for more information on
- * how to do this.
+ * When a user installs your application and runs it for the first time, you should use the
+ * {@link android.app.role.RoleManager} to prompt the user to see if they would like your app to
+ * be the new default phone app.
+ * <p id="requestRole">
+ * The code below shows how your app can request to become the default phone/dialer app:
+ * <pre>
+ * {@code
+ * private static final int REQUEST_ID = 1;
+ *
+ * public void requestRole() {
+ *     RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
+ *     Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER);
+ *     startActivityForResult(intent, REQUEST_ID);
+ * }
+ *
+ * &#64;Override
+ * public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ *     if (requestCode == REQUEST_ID) {
+ *         if (resultCode == android.app.Activity.RESULT_OK) {
+ *             // Your app is now the default dialer app
+ *         } else {
+ *             // Your app is not the default dialer app
+ *         }
+ *     }
+ * }
+ * </pre>
  * <p id="incomingCallNotification">
- * <h2>Showing the Incoming Call Notification</h2>
+ * <h3>Showing the Incoming Call Notification</h3>
  * When your app receives a new incoming call via {@link InCallService#onCallAdded(Call)}, it is
  * responsible for displaying an incoming call UI for the incoming call.  It should do this using
  * {@link android.app.NotificationManager} APIs to post a new incoming call notification.
@@ -121,7 +162,7 @@
  * heads-up notification if the user is actively using the phone.  When the user is not using the
  * phone, your full-screen incoming call UI is used instead.
  * For example:
- * <pre><code>
+ * <pre><code>{@code
  * // Create an intent which triggers your fullscreen incoming call user interface.
  * Intent intent = new Intent(Intent.ACTION_MAIN, null);
  * intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -151,7 +192,49 @@
  * NotificationManager notificationManager = mContext.getSystemService(
  *     NotificationManager.class);
  * notificationManager.notify(YOUR_CHANNEL_ID, YOUR_TAG, YOUR_ID, builder.build());
- * </code></pre>
+ * }</pre>
+ * <p>
+ * <h2>Becoming the Default Car-mode Phone App</h2>
+ * An app filling the role of the default car-mode dialer/phone app provides a user interface while
+ * the device is in a call, and in car mode.  See
+ * {@link android.app.UiModeManager#ACTION_ENTER_CAR_MODE} for more information about car mode.
+ * When the device is in car mode, Telecom binds to the default car-mode dialer/phone app instead
+ * of the usual dialer/phone app.
+ * <p>
+ * Similar to the requirements for becoming the default dialer/phone app, your app must declare a
+ * manifest entry for its {@link InCallService} implementation.  Your manifest entry should ensure
+ * the following conditions are met:
+ * <ul>
+ *     <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} metadata.</li>
+ *     <li>Set the {@link TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI} metadata to
+ *     {@code true}<li>
+ *     <li>Your app must request the permission
+ *     {@link android.Manifest.permission.CALL_COMPANION_APP}.</li>
+ * </ul>
+ * <p>
+ * Your app should request to fill the role {@code android.app.role.CAR_MODE_DIALER_APP} in order to
+ * become the default (see <a href="#requestRole">above</a> for how to request your app fills this
+ * role).
+ *
+ * <h2>Becoming a Call Companion App</h2>
+ * An app which fills the companion app role does not directly provide a user interface while the
+ * device is in a call.  Instead, it is typically used to relay information about calls to another
+ * display surface, such as a wearable device.
+ * <p>
+ * Similar to the requirements for becoming the default dialer/phone app, your app must declare a
+ * manifest entry for its {@link InCallService} implementation.  Your manifest entry should
+ * ensure the following conditions are met:
+ * <ul>
+ *     <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} metadata.</li>
+ *     <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI}
+ *     metadata.</li>
+ *     <li>Your app must request the permission
+ *     {@link android.Manifest.permission.CALL_COMPANION_APP}.</li>
+ * </ul>
+ * <p>
+ * Your app should request to fill the role {@code android.app.role.CALL_COMPANION_APP} in order to
+ * become a call companion app (see <a href="#requestRole">above</a> for how to request your app
+ * fills this role).
  */
 public abstract class InCallService extends Service {
 
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 911786e..f7dec83 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -24,6 +24,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.telecom.Call.Details.CallDirection;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -64,6 +65,7 @@
     private final Bundle mExtras;
     private final long mCreationTimeMillis;
     private final CallIdentification mCallIdentification;
+    private final int mCallDirection;
 
     public ParcelableCall(
             String id,
@@ -92,7 +94,8 @@
             Bundle intentExtras,
             Bundle extras,
             long creationTimeMillis,
-            CallIdentification callIdentification) {
+            CallIdentification callIdentification,
+            int callDirection) {
         mId = id;
         mState = state;
         mDisconnectCause = disconnectCause;
@@ -120,6 +123,7 @@
         mExtras = extras;
         mCreationTimeMillis = creationTimeMillis;
         mCallIdentification = callIdentification;
+        mCallDirection = callDirection;
     }
 
     /** The unique ID of the call. */
@@ -318,6 +322,13 @@
         return mCallIdentification;
     }
 
+    /**
+     * Indicates whether the call is an incoming or outgoing call.
+     */
+    public @CallDirection int getCallDirection() {
+        return mCallDirection;
+    }
+
     /** Responsible for creating ParcelableCall objects for deserialized Parcels. */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static final Parcelable.Creator<ParcelableCall> CREATOR =
@@ -356,6 +367,7 @@
             ParcelableRttCall rttCall = source.readParcelable(classLoader);
             long creationTimeMillis = source.readLong();
             CallIdentification callIdentification = source.readParcelable(classLoader);
+            int callDirection = source.readInt();
             return new ParcelableCall(
                     id,
                     state,
@@ -383,7 +395,8 @@
                     intentExtras,
                     extras,
                     creationTimeMillis,
-                    callIdentification);
+                    callIdentification,
+                    callDirection);
         }
 
         @Override
@@ -429,6 +442,7 @@
         destination.writeParcelable(mRttCall, 0);
         destination.writeLong(mCreationTimeMillis);
         destination.writeParcelable(mCallIdentification, 0);
+        destination.writeInt(mCallDirection);
     }
 
     @Override
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 9821dcb..744544e 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -471,6 +471,12 @@
         public void resetConnectionTime(String callId, Session.Info sessionInfo) {
             // Do nothing
         }
+
+        @Override
+        public void setConferenceState(String callId, boolean isConference,
+                Session.Info sessionInfo) {
+            // Do nothing
+        }
     };
 
     private final ConnectionServiceAdapterServant mServant =
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 6c4b1af8..12a5344 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -793,15 +793,17 @@
      * <p>
      * Apps must be prepared for this method to return {@code null}, indicating that there currently
      * exists no user-chosen default {@code PhoneAccount}.
+     * <p>
+     * The default dialer has access to use this method.
      *
      * @return The user outgoing phone account selected by the user.
-     * @hide
      */
-    @UnsupportedAppUsage
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().getUserSelectedOutgoingPhoneAccount();
+                return getTelecomService().getUserSelectedOutgoingPhoneAccount(
+                        mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelecomService#getUserSelectedOutgoingPhoneAccount", e);
@@ -810,10 +812,14 @@
     }
 
     /**
-     * Sets the user-chosen default for making outgoing phone calls.
+     * Sets the user-chosen default {@link PhoneAccountHandle} for making outgoing phone calls.
+     *
+     * @param accountHandle The {@link PhoneAccountHandle} which will be used by default for making
+     *                      outgoing voice calls.
      * @hide
      */
-    @UnsupportedAppUsage
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @SystemApi
     public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
         try {
             if (isServiceConnected()) {
@@ -1964,6 +1970,33 @@
     }
 
     /**
+     * Called by the default dialer to report to Telecom when the user has marked a previous
+     * incoming call as a nuisance call or not.
+     * <p>
+     * Where the user has chosen a {@link CallScreeningService} to fill the call screening role,
+     * Telecom will notify that {@link CallScreeningService} of the user's report.
+     * <p>
+     * Requires that the caller is the default dialer app.
+     *
+     * @param handle The phone number of an incoming call which the user is reporting as either a
+     *               nuisance of non-nuisance call.
+     * @param isNuisanceCall {@code true} if the user is reporting the call as a nuisance call,
+     *                       {@code false} if the user is reporting the call as a non-nuisance call.
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public void reportNuisanceCallStatus(@NonNull Uri handle, boolean isNuisanceCall) {
+        ITelecomService service = getTelecomService();
+        if (service != null) {
+            try {
+                service.reportNuisanceCallStatus(handle, isNuisanceCall,
+                        mContext.getOpPackageName());
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling ITelecomService#showCallScreen", e);
+            }
+        }
+    }
+
+    /**
      * Handles {@link Intent#ACTION_CALL} intents trampolined from UserCallActivity.
      * @param intent The {@link Intent#ACTION_CALL} intent to handle.
      * @hide
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
index 46bf983..0a42a3f 100644
--- a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
@@ -31,5 +31,6 @@
 
     void placeCallUnmodified();
 
-    void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount);
+    void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount,
+            boolean confirmFirst);
 }
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
index d8d360b..c1bc440 100644
--- a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
@@ -30,5 +30,5 @@
  */
 oneway interface ICallRedirectionService {
     void placeCall(in ICallRedirectionAdapter adapter, in Uri handle,
-            in PhoneAccountHandle targetPhoneAccount);
+            in PhoneAccountHandle initialPhoneAccount, boolean allowInteractiveResponse);
 }
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index 0157a58..76ac88e 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -123,4 +123,6 @@
     void onConnectionServiceFocusReleased(in Session.Info sessionInfo);
 
     void resetConnectionTime(String callIdi, in Session.Info sessionInfo);
+
+    void setConferenceState(String callId, boolean isConference, in Session.Info sessionInfo);
 }
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 954a709..5030f90 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -45,7 +45,7 @@
     /**
      * @see TelecomServiceImpl#getUserSelectedOutgoingPhoneAccount
      */
-    PhoneAccountHandle getUserSelectedOutgoingPhoneAccount();
+    PhoneAccountHandle getUserSelectedOutgoingPhoneAccount(String callingPackage);
 
     /**
      * @see TelecomServiceImpl#setUserSelectedOutgoingPhoneAccount
@@ -285,6 +285,8 @@
      */
     boolean isInEmergencyCall();
 
+    oneway void reportNuisanceCallStatus(in Uri address, boolean isNuisance, String callingPackage);
+
     /**
      * @see TelecomServiceImpl#handleCallIntent
      */
@@ -299,4 +301,5 @@
     void addOrRemoveTestCallCompanionApp(String packageName, boolean isAdded);
 
     void setTestAutoModeApp(String packageName);
+
 }
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index c115a4b..5482270 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -2019,6 +2019,12 @@
 
     /**
      * Helper functions for the "threads" table used by MMS and SMS.
+     *
+     * Thread IDs are determined by the participants in a conversation and can be used to match
+     * both SMS and MMS messages.
+     *
+     * To avoid issues where applications might cache a thread ID, the thread ID of a deleted thread
+     * must not be reused to point at a new thread.
      */
     public static final class Threads implements ThreadsColumns {
 
@@ -2072,14 +2078,10 @@
         }
 
         /**
-         * Given the recipients list and subject of an unsaved message,
-         * return its thread ID.  If the message starts a new thread,
-         * allocate a new thread ID.  Otherwise, use the appropriate
-         * existing thread ID.
-         *
-         * <p>Find the thread ID of the same set of recipients (in any order,
-         * without any additions). If one is found, return it. Otherwise,
-         * return a unique thread ID.</p>
+         * Given a set of recipients return its thread ID.
+         * <p>
+         * If a thread exists containing the provided participants, return its thread ID. Otherwise,
+         * this will create a new thread containing the provided participants and return its ID.
          */
         public static long getOrCreateThreadId(
                 Context context, Set<String> recipients) {
@@ -2373,6 +2375,9 @@
 
         /**
          * Contains message parts.
+         *
+         * To avoid issues where applications might cache a part ID, the ID of a deleted part must
+         * not be reused to point at a new part.
          */
         public static final class Part implements BaseColumns {
 
@@ -2384,6 +2389,12 @@
             }
 
             /**
+             * The {@code content://} style URL for this table. Can be appended with a part ID to
+             * address individual parts.
+             */
+            public static final Uri CONTENT_URI = Uri.withAppendedPath(Mms.CONTENT_URI, "part");
+
+            /**
              * The identifier of the message which this part belongs to.
              * <P>Type: INTEGER</P>
              */
diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java
index fe07370..4da79b3 100644
--- a/telephony/java/android/telephony/AvailableNetworkInfo.java
+++ b/telephony/java/android/telephony/AvailableNetworkInfo.java
@@ -110,6 +110,7 @@
     private AvailableNetworkInfo(Parcel in) {
         mSubId = in.readInt();
         mPriority = in.readInt();
+        mMccMncs = new ArrayList<>();
         in.readStringList(mMccMncs);
     }
 
diff --git a/telephony/java/android/telephony/CallAttributes.aidl b/telephony/java/android/telephony/CallAttributes.aidl
new file mode 100644
index 0000000..69127df
--- /dev/null
+++ b/telephony/java/android/telephony/CallAttributes.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.telephony;
+
+parcelable CallAttributes;
+
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
new file mode 100644
index 0000000..2b99ce1
--- /dev/null
+++ b/telephony/java/android/telephony/CallAttributes.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 distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.TelephonyManager.NetworkType;
+
+import java.util.Objects;
+
+/**
+ * Contains information about a call's attributes as passed up from the HAL. If there are multiple
+ * ongoing calls, the CallAttributes will pertain to the call in the foreground.
+ * @hide
+ */
+@SystemApi
+public class CallAttributes implements Parcelable {
+    private PreciseCallState mPreciseCallState;
+    @NetworkType
+    private int mNetworkType; // TelephonyManager.NETWORK_TYPE_* ints
+    private CallQuality mCallQuality;
+
+
+    public CallAttributes(PreciseCallState state, @NetworkType int networkType,
+            CallQuality callQuality) {
+        this.mPreciseCallState = state;
+        this.mNetworkType = networkType;
+        this.mCallQuality = callQuality;
+    }
+
+    @Override
+    public String toString() {
+        return "mPreciseCallState=" + mPreciseCallState + " mNetworkType=" + mNetworkType
+                + " mCallQuality=" + mCallQuality;
+    }
+
+    private CallAttributes(Parcel in) {
+        mPreciseCallState = (PreciseCallState) in.readValue(mPreciseCallState.getClass()
+                .getClassLoader());
+        mNetworkType = in.readInt();
+        mCallQuality = (CallQuality) in.readValue(mCallQuality.getClass().getClassLoader());
+    }
+
+    // getters
+    /**
+     * Returns the {@link PreciseCallState} of the call.
+     */
+    public PreciseCallState getPreciseCallState() {
+        return mPreciseCallState;
+    }
+
+    /**
+     * Returns the {@link TelephonyManager#NetworkType} of the call.
+     *
+     * @see TelephonyManager#NETWORK_TYPE_UNKNOWN
+     * @see TelephonyManager#NETWORK_TYPE_GPRS
+     * @see TelephonyManager#NETWORK_TYPE_EDGE
+     * @see TelephonyManager#NETWORK_TYPE_UMTS
+     * @see TelephonyManager#NETWORK_TYPE_CDMA
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_0
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_A
+     * @see TelephonyManager#NETWORK_TYPE_1xRTT
+     * @see TelephonyManager#NETWORK_TYPE_HSDPA
+     * @see TelephonyManager#NETWORK_TYPE_HSUPA
+     * @see TelephonyManager#NETWORK_TYPE_HSPA
+     * @see TelephonyManager#NETWORK_TYPE_IDEN
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_B
+     * @see TelephonyManager#NETWORK_TYPE_LTE
+     * @see TelephonyManager#NETWORK_TYPE_EHRPD
+     * @see TelephonyManager#NETWORK_TYPE_HSPAP
+     * @see TelephonyManager#NETWORK_TYPE_GSM
+     * @see TelephonyManager#NETWORK_TYPE_TD_SCDMA
+     * @see TelephonyManager#NETWORK_TYPE_IWLAN
+     * @see TelephonyManager#NETWORK_TYPE_LTE_CA
+     * @see TelephonyManager#NETWORK_TYPE_NR
+     */
+    @NetworkType
+    public int getNetworkType() {
+        return mNetworkType;
+    }
+
+    /**
+     * Returns the {#link CallQuality} of the call.
+     */
+    public CallQuality getCallQuality() {
+        return mCallQuality;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mPreciseCallState, mNetworkType, mCallQuality);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof CallAttributes) || hashCode() != o.hashCode()) {
+            return false;
+        }
+
+        if (this == o) {
+            return true;
+        }
+
+        CallAttributes s = (CallAttributes) o;
+
+        return (mPreciseCallState == s.mPreciseCallState
+                && mNetworkType == s.mNetworkType
+                && mCallQuality == s.mCallQuality);
+    }
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    public @Parcelable.ContentsFlags int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    public void writeToParcel(Parcel dest, @Parcelable.WriteFlags int flags) {
+        mPreciseCallState.writeToParcel(dest, flags);
+        dest.writeInt(mNetworkType);
+        mCallQuality.writeToParcel(dest, flags);
+    }
+
+    public static final Parcelable.Creator<CallAttributes> CREATOR = new Parcelable.Creator() {
+        public CallAttributes createFromParcel(Parcel in) {
+            return new CallAttributes(in);
+        }
+
+        public CallAttributes[] newArray(int size) {
+            return new CallAttributes[size];
+        }
+    };
+}
diff --git a/telephony/java/android/telephony/CallQuality.aidl b/telephony/java/android/telephony/CallQuality.aidl
new file mode 100644
index 0000000..f54355f
--- /dev/null
+++ b/telephony/java/android/telephony/CallQuality.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.telephony;
+
+parcelable CallQuality;
+
diff --git a/telephony/java/android/telephony/CallQuality.java b/telephony/java/android/telephony/CallQuality.java
new file mode 100644
index 0000000..b27f6b4
--- /dev/null
+++ b/telephony/java/android/telephony/CallQuality.java
@@ -0,0 +1,341 @@
+/*
+ * 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.IntDef;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Parcelable object to handle call quality.
+ * <p>
+ * Currently this supports IMS calls.
+ * <p>
+ * It provides the call quality level, duration, and additional information related to RTP packets,
+ * jitter and delay.
+ * <p>
+ * If there are multiple active calls, the CallQuality will pertain to the call in the foreground.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CallQuality implements Parcelable {
+
+    // Constants representing the call quality level (see #CallQuality);
+    public static final int CALL_QUALITY_EXCELLENT = 0;
+    public static final int CALL_QUALITY_GOOD = 1;
+    public static final int CALL_QUALITY_FAIR = 2;
+    public static final int CALL_QUALITY_POOR = 3;
+    public static final int CALL_QUALITY_BAD = 4;
+    public static final int CALL_QUALITY_NOT_AVAILABLE = 5;
+
+    /**
+     * Call quality
+     * @hide
+     */
+    @IntDef(prefix = { "CALL_QUALITY_" }, value = {
+            CALL_QUALITY_EXCELLENT,
+            CALL_QUALITY_GOOD,
+            CALL_QUALITY_FAIR,
+            CALL_QUALITY_POOR,
+            CALL_QUALITY_BAD,
+            CALL_QUALITY_NOT_AVAILABLE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CallQualityLevel {}
+
+    @CallQualityLevel
+    private int mDownlinkCallQualityLevel;
+    @CallQualityLevel
+    private int mUplinkCallQualityLevel;
+    private int mCallDuration;
+    private int mNumRtpPacketsTransmitted;
+    private int mNumRtpPacketsReceived;
+    private int mNumRtpPacketsTransmittedLost;
+    private int mNumRtpPacketsNotReceived;
+    private int mAverageRelativeJitter;
+    private int mMaxRelativeJitter;
+    private int mAverageRoundTripTime;
+    private int mCodecType;
+
+    /** @hide **/
+    public CallQuality(Parcel in) {
+        mDownlinkCallQualityLevel = in.readInt();
+        mUplinkCallQualityLevel = in.readInt();
+        mCallDuration = in.readInt();
+        mNumRtpPacketsTransmitted = in.readInt();
+        mNumRtpPacketsReceived = in.readInt();
+        mNumRtpPacketsTransmittedLost = in.readInt();
+        mNumRtpPacketsNotReceived = in.readInt();
+        mAverageRelativeJitter = in.readInt();
+        mMaxRelativeJitter = in.readInt();
+        mAverageRoundTripTime = in.readInt();
+        mCodecType = in.readInt();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param callQualityLevel the call quality level (see #CallQualityLevel)
+     * @param callDuration the call duration in milliseconds
+     * @param numRtpPacketsTransmitted RTP packets sent to network
+     * @param numRtpPacketsReceived RTP packets received from network
+     * @param numRtpPacketsTransmittedLost RTP packets which were lost in network and never
+     * transmitted
+     * @param numRtpPacketsNotReceived RTP packets which were lost in network and never recieved
+     * @param averageRelativeJitter average relative jitter in milliseconds
+     * @param maxRelativeJitter maximum relative jitter in milliseconds
+     * @param averageRoundTripTime average round trip delay in milliseconds
+     * @param codecType the codec type
+     */
+    public CallQuality(
+            @CallQualityLevel int downlinkCallQualityLevel,
+            @CallQualityLevel int uplinkCallQualityLevel,
+            int callDuration,
+            int numRtpPacketsTransmitted,
+            int numRtpPacketsReceived,
+            int numRtpPacketsTransmittedLost,
+            int numRtpPacketsNotReceived,
+            int averageRelativeJitter,
+            int maxRelativeJitter,
+            int averageRoundTripTime,
+            int codecType) {
+        this.mDownlinkCallQualityLevel = downlinkCallQualityLevel;
+        this.mUplinkCallQualityLevel = uplinkCallQualityLevel;
+        this.mCallDuration = callDuration;
+        this.mNumRtpPacketsTransmitted = numRtpPacketsTransmitted;
+        this.mNumRtpPacketsReceived = numRtpPacketsReceived;
+        this.mNumRtpPacketsTransmittedLost = numRtpPacketsTransmittedLost;
+        this.mNumRtpPacketsNotReceived = numRtpPacketsNotReceived;
+        this.mAverageRelativeJitter = averageRelativeJitter;
+        this.mMaxRelativeJitter = maxRelativeJitter;
+        this.mAverageRoundTripTime = averageRoundTripTime;
+        this.mCodecType = codecType;
+    }
+
+    // getters
+    /**
+     * Returns the downlink CallQualityLevel for a given ongoing call.
+     */
+    @CallQualityLevel
+    public int getDownlinkCallQualityLevel() {
+        return mDownlinkCallQualityLevel;
+    }
+
+    /**
+     * Returns the uplink CallQualityLevel for a given ongoing call.
+     */
+    @CallQualityLevel
+    public int getUplinkCallQualityLevel() {
+        return mUplinkCallQualityLevel;
+    }
+
+    /**
+     * Returns the duration of the call, in milliseconds.
+     */
+    public int getCallDuration() {
+        return mCallDuration;
+    }
+
+    /**
+     * Returns the total number of RTP packets transmitted by this device for a given ongoing call.
+     */
+    public int getNumRtpPacketsTransmitted() {
+        return mNumRtpPacketsTransmitted;
+    }
+
+    /**
+     * Returns the total number of RTP packets received by this device for a given ongoing call.
+     */
+    public int getNumRtpPacketsReceived() {
+        return mNumRtpPacketsReceived;
+    }
+
+    /**
+     * Returns the number of RTP packets which were sent by this device but were lost in the
+     * network before reaching the other party.
+     */
+    public int getNumRtpPacketsTransmittedLost() {
+        return mNumRtpPacketsTransmittedLost;
+    }
+
+    /**
+     * Returns the number of RTP packets which were sent by the other party but were lost in the
+     * network before reaching this device.
+     */
+    public int getNumRtpPacketsNotReceived() {
+        return mNumRtpPacketsNotReceived;
+    }
+
+    /**
+     * Returns the average relative jitter in milliseconds. Jitter represents the amount of variance
+     * in interarrival time of packets, for example, if two packets are sent 2 milliseconds apart
+     * but received 3 milliseconds apart, the relative jitter between those packets is 1
+     * millisecond.
+     *
+     * <p>See RFC 3550 for more information on jitter calculations.
+     */
+    public int getAverageRelativeJitter() {
+        return mAverageRelativeJitter;
+    }
+
+    /**
+     * Returns the maximum relative jitter for a given ongoing call. Jitter represents the amount of
+     * variance in interarrival time of packets, for example, if two packets are sent 2 milliseconds
+     * apart but received 3 milliseconds apart, the relative jitter between those packets is 1
+     * millisecond.
+     *
+     * <p>See RFC 3550 for more information on jitter calculations.
+     */
+    public int getMaxRelativeJitter() {
+        return mMaxRelativeJitter;
+    }
+
+    /**
+     * Returns the average round trip time in milliseconds.
+     */
+    public int getAverageRoundTripTime() {
+        return mAverageRoundTripTime;
+    }
+
+    /**
+     * Returns the codec type. This value corresponds to the AUDIO_QUALITY_* constants in
+     * {@link ImsStreamMediaProfile}.
+     *
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_NONE
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_AMR
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_AMR_WB
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_QCELP13K
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVRC
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVRC_B
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVRC_WB
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVRC_NW
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_GSM_EFR
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_GSM_FR
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_GSM_HR
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_G711U
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_G723
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_G711A
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_G722
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_G711AB
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_G729
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVS_NB
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVS_WB
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVS_SWB
+     * @see ImsStreamMediaProfile#AUDIO_QUALITY_EVS_FB
+     */
+    public int getCodecType() {
+        return mCodecType;
+    }
+
+    // Parcelable things
+    @Override
+    public String toString() {
+        return "CallQuality: {downlinkCallQualityLevel=" + mDownlinkCallQualityLevel
+                + " uplinkCallQualityLevel=" + mUplinkCallQualityLevel
+                + " callDuration=" + mCallDuration
+                + " numRtpPacketsTransmitted=" + mNumRtpPacketsTransmitted
+                + " numRtpPacketsReceived=" + mNumRtpPacketsReceived
+                + " numRtpPacketsTransmittedLost=" + mNumRtpPacketsTransmittedLost
+                + " numRtpPacketsNotReceived=" + mNumRtpPacketsNotReceived
+                + " averageRelativeJitter=" + mAverageRelativeJitter
+                + " maxRelativeJitter=" + mMaxRelativeJitter
+                + " averageRoundTripTime=" + mAverageRoundTripTime
+                + " codecType=" + mCodecType
+                + "}";
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                mDownlinkCallQualityLevel,
+                mUplinkCallQualityLevel,
+                mCallDuration,
+                mNumRtpPacketsTransmitted,
+                mNumRtpPacketsReceived,
+                mNumRtpPacketsTransmittedLost,
+                mNumRtpPacketsNotReceived,
+                mAverageRelativeJitter,
+                mMaxRelativeJitter,
+                mAverageRoundTripTime,
+                mCodecType);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof CallQuality) || hashCode() != o.hashCode()) {
+            return false;
+        }
+
+        if (this == o) {
+            return true;
+        }
+
+        CallQuality s = (CallQuality) o;
+
+        return (mDownlinkCallQualityLevel == s.mDownlinkCallQualityLevel
+                && mUplinkCallQualityLevel == s.mUplinkCallQualityLevel
+                && mCallDuration == s.mCallDuration
+                && mNumRtpPacketsTransmitted == s.mNumRtpPacketsTransmitted
+                && mNumRtpPacketsReceived == s.mNumRtpPacketsReceived
+                && mNumRtpPacketsTransmittedLost == s.mNumRtpPacketsTransmittedLost
+                && mNumRtpPacketsNotReceived == s.mNumRtpPacketsNotReceived
+                && mAverageRelativeJitter == s.mAverageRelativeJitter
+                && mMaxRelativeJitter == s.mMaxRelativeJitter
+                && mAverageRoundTripTime == s.mAverageRoundTripTime
+                && mCodecType == s.mCodecType);
+    }
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    public @Parcelable.ContentsFlags int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    public void writeToParcel(Parcel dest, @Parcelable.WriteFlags int flags) {
+        dest.writeInt(mDownlinkCallQualityLevel);
+        dest.writeInt(mUplinkCallQualityLevel);
+        dest.writeInt(mCallDuration);
+        dest.writeInt(mNumRtpPacketsTransmitted);
+        dest.writeInt(mNumRtpPacketsReceived);
+        dest.writeInt(mNumRtpPacketsTransmittedLost);
+        dest.writeInt(mNumRtpPacketsNotReceived);
+        dest.writeInt(mAverageRelativeJitter);
+        dest.writeInt(mMaxRelativeJitter);
+        dest.writeInt(mAverageRoundTripTime);
+        dest.writeInt(mCodecType);
+    }
+
+    public static final Parcelable.Creator<CallQuality> CREATOR = new Parcelable.Creator() {
+        public CallQuality createFromParcel(Parcel in) {
+            return new CallQuality(in);
+        }
+
+        public CallQuality[] newArray(int size) {
+            return new CallQuality[size];
+        }
+    };
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a9a128b..a33b44c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2231,7 +2231,7 @@
      * e.g.) To use RSCP by default, set the value to "rscp". The signal strength level will
      * then be determined by #KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY
      * <p>
-     * Currently this only supports the value "rscp"
+     * Currently this supports the value "rscp" and "rssi".
      * @hide
      */
     // FIXME: this key and related keys must not be exposed without a consistent philosophy for
@@ -2508,10 +2508,18 @@
         public static final String KEY_GPS_LOCK_STRING = KEY_PREFIX + "gps_lock";
 
         /**
-         * SUPL NI emergency extension time in seconds. Default to "0".
+         * Control Plane / SUPL NI emergency extension time in seconds. Default to "0".
          */
         public static final String KEY_ES_EXTENSION_SEC = KEY_PREFIX + "es_extension_sec";
 
+        /**
+         * Space separated list of Android package names of proxy applications representing
+         * the non-framework entities requesting location directly from GNSS without involving
+         * the framework, as managed by IGnssVisibilityControl.hal. For example,
+         * "com.example.mdt com.example.ims".
+         */
+        public static final String KEY_NFW_PROXY_APPS = KEY_PREFIX + "nfw_proxy_apps";
+
         private static PersistableBundle getDefaults() {
             PersistableBundle defaults = new PersistableBundle();
             defaults.putBoolean(KEY_PERSIST_LPP_MODE_BOOL, true);
@@ -2525,6 +2533,7 @@
             defaults.putString(KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, "0");
             defaults.putString(KEY_GPS_LOCK_STRING, "3");
             defaults.putString(KEY_ES_EXTENSION_SEC, "0");
+            defaults.putString(KEY_NFW_PROXY_APPS, "");
             return defaults;
         }
     }
@@ -2875,7 +2884,7 @@
                         -95, /* SIGNAL_STRENGTH_GOOD */
                         -85  /* SIGNAL_STRENGTH_GREAT */
                 });
-        sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "");
+        sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "rssi");
         sDefaults.putBoolean(KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL, false);
         sDefaults.putBoolean(KEY_CALL_FORWARDING_OVER_UT_WARNING_BOOL, false);
diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.aidl b/telephony/java/android/telephony/CarrierRestrictionRules.aidl
new file mode 100644
index 0000000..8b1f0b9
--- /dev/null
+++ b/telephony/java/android/telephony/CarrierRestrictionRules.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/** @hide */
+package android.telephony;
+
+parcelable CarrierRestrictionRules;
diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java
new file mode 100644
index 0000000..37847ae
--- /dev/null
+++ b/telephony/java/android/telephony/CarrierRestrictionRules.java
@@ -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.
+ */
+
+package android.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.service.carrier.CarrierIdentifier;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Contains the list of carrier restrictions.
+ * Allowed list: it indicates the list of carriers that are allowed.
+ * Excluded list: it indicates the list of carriers that are excluded.
+ * Default carrier restriction: it indicates the default behavior and the priority between the two
+ * lists:
+ *  - not allowed: the device only allows usage of carriers that are present in the allowed list
+ *    and not present in the excluded list. This implies that if a carrier is not present in either
+ *    list, it is not allowed.
+ *  - allowed: the device allows all carriers, except those present in the excluded list and not
+ *    present in the allowed list. This implies that if a carrier is not present in either list,
+ *    it is allowed.
+ * MultiSim policy: it indicates the behavior in case of devices with two or more SIM cards.
+ *  - MULTISIM_POLICY_NONE: the same configuration is applied to all SIM slots independently. This
+ *    is the default value if none is set.
+ *  - MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT: it indicates that any SIM card can be used
+ *    as far as one SIM card matching the configuration is present in the device.
+ *
+ * Both lists support the character '?' as wild character. For example, an entry indicating
+ * MCC=310 and MNC=??? will match all networks with MCC=310.
+ *
+ * Example 1: Allowed list contains MCC and MNC of operator A. Excluded list contains operator B,
+ *            which has same MCC and MNC, but also GID1 value. The priority allowed list is set
+ *            to true. Only SIM cards of operator A are allowed, but not those of B or any other
+ *            operator.
+ * Example 2: Allowed list contains MCC and MNC of operator A. Excluded list contains an entry
+ *            with same MCC, and '???' as MNC. The priority allowed list is set to false.
+ *            SIM cards of operator A and all SIM cards with a different MCC value are allowed.
+ *            SIM cards of operators with same MCC value and different MNC are not allowed.
+ * @hide
+ */
+@SystemApi
+public final class CarrierRestrictionRules implements Parcelable {
+    /**
+     * The device only allows usage of carriers that are present in the allowed list and not
+     * present in the excluded list. This implies that if a carrier is not present in either list,
+     * it is not allowed.
+     */
+    public static final int CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED = 0;
+
+    /**
+     * The device allows all carriers, except those present in the excluded list and not present
+     * in the allowed list. This implies that if a carrier is not present in either list, it is
+     * allowed.
+     */
+    public static final int CARRIER_RESTRICTION_DEFAULT_ALLOWED = 1;
+
+    /** The same configuration is applied to all SIM slots independently. */
+    public static final int MULTISIM_POLICY_NONE = 0;
+
+    /** Any SIM card can be used as far as one SIM card matching the configuration is present. */
+    public static final int MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT = 1;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "MULTISIM_POLICY_",
+            value = {MULTISIM_POLICY_NONE, MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT})
+    public @interface MultiSimPolicy {}
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "CARRIER_RESTRICTION_DEFAULT_",
+            value = {CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED, CARRIER_RESTRICTION_DEFAULT_ALLOWED})
+    public @interface CarrierRestrictionDefault {}
+
+    private List<CarrierIdentifier> mAllowedCarriers;
+    private List<CarrierIdentifier> mExcludedCarriers;
+    @CarrierRestrictionDefault
+    private int mCarrierRestrictionDefault;
+    @MultiSimPolicy
+    private int mMultiSimPolicy;
+
+    private CarrierRestrictionRules() {
+        mAllowedCarriers = new ArrayList<CarrierIdentifier>();
+        mExcludedCarriers = new ArrayList<CarrierIdentifier>();
+        mCarrierRestrictionDefault = CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED;
+        mMultiSimPolicy = MULTISIM_POLICY_NONE;
+    }
+
+    private CarrierRestrictionRules(Parcel in) {
+        mAllowedCarriers = new ArrayList<CarrierIdentifier>();
+        mExcludedCarriers = new ArrayList<CarrierIdentifier>();
+
+        in.readTypedList(mAllowedCarriers, CarrierIdentifier.CREATOR);
+        in.readTypedList(mExcludedCarriers, CarrierIdentifier.CREATOR);
+        mCarrierRestrictionDefault = in.readInt();
+        mMultiSimPolicy = in.readInt();
+    }
+
+    /**
+     * Creates a new builder for this class
+     * @hide
+     */
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    /**
+     * Indicates if all carriers are allowed
+     */
+    public boolean isAllCarriersAllowed() {
+        return (mAllowedCarriers.isEmpty() && mExcludedCarriers.isEmpty()
+                && mCarrierRestrictionDefault == CARRIER_RESTRICTION_DEFAULT_ALLOWED);
+    }
+
+    /**
+     * Retrieves list of allowed carriers
+     *
+     * @return the list of allowed carriers
+     */
+    public @NonNull List<CarrierIdentifier> getAllowedCarriers() {
+        return mAllowedCarriers;
+    }
+
+    /**
+     * Retrieves list of excluded carriers
+     *
+     * @return the list of excluded carriers
+     */
+    public @NonNull List<CarrierIdentifier> getExcludedCarriers() {
+        return mExcludedCarriers;
+    }
+
+    /**
+     * Retrieves the default behavior of carrier restrictions
+     */
+    public @CarrierRestrictionDefault int getDefaultCarrierRestriction() {
+        return mCarrierRestrictionDefault;
+    }
+
+    /**
+     * @return The policy used for multi-SIM devices
+     */
+    public @MultiSimPolicy int getMultiSimPolicy() {
+        return mMultiSimPolicy;
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeTypedList(mAllowedCarriers);
+        out.writeTypedList(mExcludedCarriers);
+        out.writeInt(mCarrierRestrictionDefault);
+        out.writeInt(mMultiSimPolicy);
+    }
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@link Parcelable.Creator}
+     */
+    public static final Creator<CarrierRestrictionRules> CREATOR =
+            new Creator<CarrierRestrictionRules>() {
+        @Override
+        public CarrierRestrictionRules createFromParcel(Parcel in) {
+            return new CarrierRestrictionRules(in);
+        }
+
+        @Override
+        public CarrierRestrictionRules[] newArray(int size) {
+            return new CarrierRestrictionRules[size];
+        }
+    };
+
+    @Override
+    public String toString() {
+        return "CarrierRestrictionRules(allowed:" + mAllowedCarriers + ", excluded:"
+                + mExcludedCarriers + ", default:" + mCarrierRestrictionDefault
+                + ", multisim policy:" + mMultiSimPolicy + ")";
+    }
+
+    /**
+     * Builder for a {@link CarrierRestrictionRules}.
+     */
+    public static class Builder {
+        private final CarrierRestrictionRules mRules;
+
+        /** {@hide} */
+        public Builder() {
+            mRules = new CarrierRestrictionRules();
+        }
+
+        /** build command */
+        public CarrierRestrictionRules build() {
+            return mRules;
+        }
+
+        /**
+         * Indicate that all carriers are allowed.
+         */
+        public Builder setAllCarriersAllowed() {
+            mRules.mAllowedCarriers.clear();
+            mRules.mExcludedCarriers.clear();
+            mRules.mCarrierRestrictionDefault = CARRIER_RESTRICTION_DEFAULT_ALLOWED;
+            return this;
+        }
+
+        /**
+         * Set list of allowed carriers.
+         *
+         * @param allowedCarriers list of allowed carriers
+         */
+        public Builder setAllowedCarriers(List<CarrierIdentifier> allowedCarriers) {
+            mRules.mAllowedCarriers = new ArrayList<CarrierIdentifier>(allowedCarriers);
+            return this;
+        }
+
+        /**
+         * Set list of excluded carriers.
+         *
+         * @param excludedCarriers list of excluded carriers
+         */
+        public Builder setExcludedCarriers(List<CarrierIdentifier> excludedCarriers) {
+            mRules.mExcludedCarriers = new ArrayList<CarrierIdentifier>(excludedCarriers);
+            return this;
+        }
+
+        /**
+         * Set the default behavior of the carrier restrictions
+         *
+         * @param carrierRestrictionDefault prioritized carrier list
+         */
+        public Builder setDefaultCarrierRestriction(
+                @CarrierRestrictionDefault int carrierRestrictionDefault) {
+            mRules.mCarrierRestrictionDefault = carrierRestrictionDefault;
+            return this;
+        }
+
+        /**
+         * Set the policy to be used for multi-SIM devices
+         *
+         * @param multiSimPolicy multi SIM policy
+         */
+        public Builder setMultiSimPolicy(@MultiSimPolicy int multiSimPolicy) {
+            mRules.mMultiSimPolicy = multiSimPolicy;
+            return this;
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/CellConfigLte.java b/telephony/java/android/telephony/CellConfigLte.java
index 35769f0..eafbfbc 100644
--- a/telephony/java/android/telephony/CellConfigLte.java
+++ b/telephony/java/android/telephony/CellConfigLte.java
@@ -34,6 +34,11 @@
     }
 
     /** @hide */
+    public CellConfigLte(android.hardware.radio.V1_4.CellConfigLte cellConfig) {
+        mIsEndcAvailable = cellConfig.isEndcAvailable;
+    }
+
+    /** @hide */
     public CellConfigLte(boolean isEndcAvailable) {
         mIsEndcAvailable = isEndcAvailable;
     }
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index b761bd7..8ce5c54 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -19,8 +19,10 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
+import android.hardware.radio.V1_4.CellInfo.Info;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.SystemClock;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -318,6 +320,13 @@
     }
 
     /** @hide */
+    protected CellInfo(android.hardware.radio.V1_4.CellInfo ci) {
+        this.mRegistered = ci.isRegistered;
+        this.mTimeStamp = SystemClock.elapsedRealtimeNanos();
+        this.mCellConnectionStatus = ci.connectionStatus;
+    }
+
+    /** @hide */
     public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) {
         if (ci == null) return null;
         switch(ci.cellInfoType) {
@@ -342,4 +351,17 @@
             default: return null;
         }
     }
+
+    /** @hide */
+    public static CellInfo create(android.hardware.radio.V1_4.CellInfo ci) {
+        if (ci == null) return null;
+        switch (ci.info.getDiscriminator()) {
+            case Info.hidl_discriminator.gsm: return new CellInfoGsm(ci);
+            case Info.hidl_discriminator.cdma: return new CellInfoCdma(ci);
+            case Info.hidl_discriminator.lte: return new CellInfoLte(ci);
+            case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci);
+            case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci);
+            default: return null;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index c9f07da..4440108 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -67,6 +67,15 @@
             new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
     }
 
+    /** @hide */
+    public CellInfoCdma(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoCdma cic = ci.info.cdma();
+        mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
+        mCellSignalStrengthCdma =
+                new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+    }
+
     @Override
     public CellIdentityCdma getCellIdentity() {
         return mCellIdentityCdma;
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index ad16dfa..248adfc 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -63,6 +63,14 @@
         mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
     }
 
+    /** @hide */
+    public CellInfoGsm(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoGsm cig = ci.info.gsm();
+        mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
+        mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
+    }
+
     @Override
     public CellIdentityGsm getCellIdentity() {
         return mCellIdentityGsm;
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 7593831..8e8ce8a 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -70,6 +70,15 @@
         mCellConfig = new CellConfigLte();
     }
 
+    /** @hide */
+    public CellInfoLte(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_4.CellInfoLte cil = ci.info.lte();
+        mCellIdentityLte = new CellIdentityLte(cil.base.cellIdentityLte);
+        mCellSignalStrengthLte = new CellSignalStrengthLte(cil.base.signalStrengthLte);
+        mCellConfig = new CellConfigLte(cil.cellConfig);
+    }
+
     @Override
     public CellIdentityLte getCellIdentity() {
         if (DBG) log("getCellIdentity: " + mCellIdentityLte);
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index a8c49b7..2ab38fb 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -64,6 +64,14 @@
         mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
     }
 
+    /** @hide */
+    public CellInfoTdscdma(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.info.tdscdma();
+        mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
+        mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+    }
+
     @Override public CellIdentityTdscdma getCellIdentity() {
         return mCellIdentityTdscdma;
     }
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index a427e80..65e0470 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -63,6 +63,14 @@
         mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
     }
 
+    /** @hide */
+    public CellInfoWcdma(android.hardware.radio.V1_4.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.info.wcdma();
+        mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
+        mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+    }
+
     @Override
     public CellIdentityWcdma getCellIdentity() {
         return mCellIdentityWcdma;
diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java
index f2c14a1..e6182ed 100644
--- a/telephony/java/android/telephony/CellSignalStrength.java
+++ b/telephony/java/android/telephony/CellSignalStrength.java
@@ -42,6 +42,9 @@
     public static final int NUM_SIGNAL_STRENGTH_BINS = 5;
 
     /** @hide */
+    protected static final int NUM_SIGNAL_STRENGTH_THRESHOLDS = NUM_SIGNAL_STRENGTH_BINS - 1;
+
+    /** @hide */
     public static final String[] SIGNAL_STRENGTH_NAMES = {
         "none", "poor", "moderate", "good", "great"
     };
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 7b29f69..30e641d 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -148,8 +148,9 @@
 
     /**
      * Return the Bit Error Rate
-     * @returns the bit error rate (0-7, 99) as defined in TS 27.007 8.5 or UNAVAILABLE.
-     * @hide
+     *
+     * @return the bit error rate (0-7, 99) as defined in TS 27.007 8.5 or
+     *         {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE}.
      */
     public int getBitErrorRate() {
         return mBitErrorRate;
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 893dbe3..61c6b48 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -30,7 +30,7 @@
 public final class CellSignalStrengthLte extends CellSignalStrength implements Parcelable {
 
     private static final String LOG_TAG = "CellSignalStrengthLte";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     /**
      * Indicates the unknown or undetectable RSSI value in ASU.
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index 88f6fbc..0760407 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -21,6 +21,7 @@
 import android.os.Parcelable;
 import android.os.PersistableBundle;
 import android.telephony.Rlog;
+import android.text.TextUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -41,8 +42,18 @@
     private static final int WCDMA_RSSI_POOR = -107;
     private static final int WCDMA_RSSI_MIN = -113;
 
-    private static final int WCDMA_RSCP_MIN = -120;
+    private static final int[] sRssiThresholds = new int[]{
+            WCDMA_RSSI_POOR, WCDMA_RSSI_MODERATE, WCDMA_RSSI_GOOD, WCDMA_RSSI_GREAT};
+
     private static final int WCDMA_RSCP_MAX = -24;
+    private static final int WCDMA_RSCP_GREAT = -85;
+    private static final int WCDMA_RSCP_GOOD = -95;
+    private static final int WCDMA_RSCP_MODERATE = -105;
+    private static final int WCDMA_RSCP_POOR = -115;
+    private static final int WCDMA_RSCP_MIN = -120;
+
+    private static final int[] sRscpThresholds = new int[] {
+            WCDMA_RSCP_POOR, WCDMA_RSCP_MODERATE, WCDMA_RSCP_GOOD, WCDMA_RSCP_GREAT};
 
     // TODO: Because these are used as values in CarrierConfig, they should be exposed somehow.
     /** @hide */
@@ -54,6 +65,9 @@
     /** @hide */
     public static final String LEVEL_CALCULATION_METHOD_RSCP = "rscp";
 
+    // Default to RSSI for backwards compatibility with older devices
+    private static final String sLevelCalculationMethod = LEVEL_CALCULATION_METHOD_RSSI;
+
     private int mRssi; // in dBm [-113, 51] or CellInfo.UNAVAILABLE if unknown
     private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 or
                                // CellInfo.UNAVAILABLE if unknown
@@ -121,10 +135,6 @@
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
-    private static final String sLevelCalculationMethod = LEVEL_CALCULATION_METHOD_RSSI;
-    private static final int[] sThresholds = new int[]{
-            WCDMA_RSSI_POOR, WCDMA_RSSI_GOOD, WCDMA_RSSI_GOOD, WCDMA_RSSI_GREAT};
-
     /**
      * Retrieve an abstract level value for the overall signal strength.
      *
@@ -140,41 +150,46 @@
     @Override
     public void updateLevel(PersistableBundle cc, ServiceState ss) {
         String calcMethod;
-        int[] thresholds;
+        int[] rscpThresholds;
 
         if (cc == null) {
             calcMethod = sLevelCalculationMethod;
-            thresholds = sThresholds;
+            rscpThresholds = sRscpThresholds;
         } else {
             // TODO: abstract this entire thing into a series of functions
             calcMethod = cc.getString(
                     CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING,
                     sLevelCalculationMethod);
-            thresholds = cc.getIntArray(
+            if (TextUtils.isEmpty(calcMethod)) calcMethod = sLevelCalculationMethod;
+            rscpThresholds = cc.getIntArray(
                     CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY);
-            if (thresholds == null) thresholds = sThresholds;
+            if (rscpThresholds == null || rscpThresholds.length != NUM_SIGNAL_STRENGTH_THRESHOLDS) {
+                rscpThresholds = sRscpThresholds;
+            }
         }
 
-        int level = thresholds.length;
+        int level = NUM_SIGNAL_STRENGTH_THRESHOLDS;
         switch (calcMethod) {
             case LEVEL_CALCULATION_METHOD_RSCP:
                 if (mRscp < WCDMA_RSCP_MIN || mRscp > WCDMA_RSCP_MAX) {
                     mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
                     return;
                 }
-                while (level > 0 && mRscp < thresholds[level - 1]) level--;
+                while (level > 0 && mRscp < rscpThresholds[level - 1]) level--;
                 mLevel = level;
                 return;
+            default:
+                loge("Invalid Level Calculation Method for CellSignalStrengthWcdma = "
+                        + calcMethod);
+                /** fall through */
             case LEVEL_CALCULATION_METHOD_RSSI:
                 if (mRssi < WCDMA_RSSI_MIN || mRssi > WCDMA_RSSI_MAX) {
                     mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
                     return;
                 }
-                while (level > 0 && mRssi < thresholds[level - 1]) level--;
+                while (level > 0 && mRssi < sRssiThresholds[level - 1]) level--;
                 mLevel = level;
                 return;
-            default:
-                mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
         }
     }
 
@@ -204,7 +219,7 @@
     }
 
     /**
-     * Get the signal strength as dBm
+     * Get the RSSI as dBm
      *
      * @hide
      */
@@ -214,12 +229,32 @@
 
     /**
      * Get the RSCP as dBm
+     *
      * @hide
      */
     public int getRscp() {
         return mRscp;
     }
 
+    /**
+     * Get the Ec/No as dB
+     *
+     * @hide
+     */
+    public int getEcNo() {
+        return mEcNo;
+    }
+
+    /**
+     * Return the Bit Error Rate
+     *
+     * @returns the bit error rate (0-7, 99) as defined in TS 27.007 8.5 or UNAVAILABLE.
+     * @hide
+     */
+    public int getBitErrorRate() {
+        return mBitErrorRate;
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(mRssi, mBitErrorRate, mRscp, mEcNo, mLevel);
@@ -304,9 +339,16 @@
     };
 
     /**
-     * log
+     * log warning
      */
     private static void log(String s) {
         Rlog.w(LOG_TAG, s);
     }
+
+    /**
+     * log error
+     */
+    private static void loge(String s) {
+        Rlog.e(LOG_TAG, s);
+    }
 }
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index c53b37d..ca264f7 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -17,6 +17,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.os.PersistableBundle;
 
@@ -34,13 +35,14 @@
  * Returned as the reason for a data connection failure as defined by modem and some local errors.
  * @hide
  */
+@SystemApi
 public final class DataFailCause {
     /** There is no failure */
     public static final int NONE = 0;
 
     // This series of errors as specified by the standards
     // specified in ril.h
-    /** Operator determined barring. */
+    /** Operator determined barring. (no retry) */
     public static final int OPERATOR_BARRED = 0x08;
     /** NAS signalling. */
     public static final int NAS_SIGNALLING = 0x0E;
@@ -89,6 +91,11 @@
     public static final int FILTER_SYTAX_ERROR = 0x2D;
     /** Packet Data Protocol (PDP) without active traffic flow template (TFT). */
     public static final int PDP_WITHOUT_ACTIVE_TFT = 0x2E;
+    /**
+     * UE requested to modify QoS parameters or the bearer control mode, which is not compatible
+     * with the selected bearer control mode.
+     */
+    public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 0x30;
     /** Packet Data Protocol (PDP) type IPv4 only allowed. */
     public static final int ONLY_IPV4_ALLOWED = 0x32;                /* no retry */
     /** Packet Data Protocol (PDP) type IPv6 only allowed. */
@@ -101,8 +108,29 @@
     public static final int PDN_CONN_DOES_NOT_EXIST = 0x36;
     /** Multiple connections to a same PDN is not allowed. */
     public static final int MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37;
-    /** Packet Data Protocol (PDP) */
-    public static final int MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41;
+    /**
+     * Network has already initiated the activation, modification, or deactivation of bearer
+     * resources that was requested by the UE.
+     */
+    public static final int COLLISION_WITH_NETWORK_INITIATED_REQUEST = 0x38;
+    /**
+     * Network supports IPv4v6 PDP type only. Non-IP type is not allowed. In LTE mode of operation,
+     * this is a PDN throttling cause code, meaning the UE may throttle further requests to the
+     * same APN.
+     */
+    public static final int ONLY_IPV4V6_ALLOWED = 0x39;
+    /**
+     * Network supports non-IP PDP type only. IPv4, IPv6 and IPv4v6 is not allowed. In LTE mode of
+     * operation, this is a PDN throttling cause code, meaning the UE can throttle further requests
+     * to the same APN.
+     */
+    public static final int ONLY_NON_IP_ALLOWED = 0x3A;
+    /** QCI (QoS Class Identifier) indicated in the UE request cannot be supported. */
+    public static final int UNSUPPORTED_QCI_VALUE = 0x3B;
+    /** Procedure requested by the UE was rejected because the bearer handling is not supported. */
+    public static final int BEARER_HANDLING_NOT_SUPPORTED = 0x3C;
+    /** Max number of Packet Data Protocol (PDP) context reached. */
+    public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 0x41;
     /** Unsupported APN in current public land mobile network (PLMN). */
     public static final int UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42;
     /** Invalid transaction id. */
@@ -144,6 +172,742 @@
     public static final int EMM_ACCESS_BARRED_INFINITE_RETRY = 0x79;
     /** Authentication failure on emergency call. */
     public static final int AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A;
+    /** Not receiving a DNS address that was mandatory. */
+    public static final int INVALID_DNS_ADDR = 0x7B;
+    /** Not receiving either a PCSCF or a DNS address, one of them being mandatory. */
+    public static final int INVALID_PCSCF_OR_DNS_ADDRESS = 0x7C;
+    /** Emergency call bring up on a different ePDG. */
+    public static final int CALL_PREEMPT_BY_EMERGENCY_APN = 0x7F;
+    /** UE performs a detach or disconnect PDN action based on TE requirements. */
+    public static final int UE_INITIATED_DETACH_OR_DISCONNECT = 0x80;
+
+    /** Reason unspecified for foreign agent rejected MIP (Mobile IP) registration. */
+    public static final int MIP_FA_REASON_UNSPECIFIED = 0x7D0;
+    /** Foreign agent administratively prohibited MIP (Mobile IP) registration. */
+    public static final int MIP_FA_ADMIN_PROHIBITED = 0x7D1;
+    /** Foreign agent rejected MIP (Mobile IP) registration because of insufficient resources. */
+    public static final int MIP_FA_INSUFFICIENT_RESOURCES = 0x7D2;
+    /**
+     * Foreign agent rejected MIP (Mobile IP) registration because of MN-AAA authenticator was
+     * wrong.
+     */
+    public static final int MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE = 0x7D3;
+    /**
+     * Foreign agent rejected MIP (Mobile IP) registration because of home agent authentication
+     * failure.
+     */
+    public static final int MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE = 0x7D4;
+    /**
+     * Foreign agent rejected MIP (Mobile IP) registration because of requested lifetime was too
+     * long.
+     */
+    public static final int MIP_FA_REQUESTED_LIFETIME_TOO_LONG = 0x7D5;
+    /** Foreign agent rejected MIP (Mobile IP) registration because of malformed request. */
+    public static final int MIP_FA_MALFORMED_REQUEST = 0x7D6;
+    /** Foreign agent rejected MIP (Mobile IP) registration because of malformed reply. */
+    public static final int MIP_FA_MALFORMED_REPLY = 0x7D7;
+    /**
+     * Foreign agent rejected MIP (Mobile IP) registration because of requested encapsulation was
+     * unavailable.
+     */
+    public static final int MIP_FA_ENCAPSULATION_UNAVAILABLE = 0x7D8;
+    /**
+     * Foreign agent rejected MIP (Mobile IP) registration of VJ Header Compression was
+     * unavailable.
+     */
+    public static final int MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE = 0x7D9;
+    /**
+     * Foreign agent rejected MIP (Mobile IP) registration because of reverse tunnel was
+     * unavailable.
+     */
+    public static final int MIP_FA_REVERSE_TUNNEL_UNAVAILABLE = 0x7DA;
+    /**
+     * Foreign agent rejected MIP (Mobile IP) registration because of reverse tunnel was mandatory
+     * but not requested by device.
+     */
+    public static final int MIP_FA_REVERSE_TUNNEL_IS_MANDATORY = 0x7DB;
+    /**
+     * Foreign agent rejected MIP (Mobile IP) registration because of delivery style was not
+     * supported.
+     */
+    public static final int MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED = 0x7DC;
+    /**
+     * Foreign agent rejected MIP (Mobile IP) registration because of missing NAI (Network Access
+     * Identifier).
+     */
+    public static final int MIP_FA_MISSING_NAI = 0x7DD;
+    /** Foreign agent rejected MIP (Mobile IP) registration because of missing Home Agent. */
+    public static final int MIP_FA_MISSING_HOME_AGENT = 0x7DE;
+    /** Foreign agent rejected MIP (Mobile IP) registration because of missing Home Address. */
+    public static final int MIP_FA_MISSING_HOME_ADDRESS = 0x7DF;
+    /** Foreign agent rejected MIP (Mobile IP) registration because of unknown challenge. */
+    public static final int MIP_FA_UNKNOWN_CHALLENGE = 0x7E0;
+    /** Foreign agent rejected MIP (Mobile IP) registration because of missing challenge. */
+    public static final int MIP_FA_MISSING_CHALLENGE = 0x7E1;
+    /** Foreign agent rejected MIP (Mobile IP) registration because of stale challenge. */
+    public static final int MIP_FA_STALE_CHALLENGE = 0x7E2;
+    /** Reason unspecified for home agent rejected MIP (Mobile IP) registration. */
+    public static final int MIP_HA_REASON_UNSPECIFIED = 0x7E3;
+    /** Home agent administratively prohibited MIP (Mobile IP) registration. */
+    public static final int MIP_HA_ADMIN_PROHIBITED = 0x7E4;
+    /** Home agent rejected MIP (Mobile IP) registration because of insufficient resources. */
+    public static final int MIP_HA_INSUFFICIENT_RESOURCES = 0x7E5;
+    /**
+     * Home agent rejected MIP (Mobile IP) registration because of MN-HA authenticator was
+     * wrong.
+     */
+    public static final int MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE = 0x7E6;
+    /**
+     * Home agent rejected MIP (Mobile IP) registration because of foreign agent authentication
+     * failure.
+     */
+    public static final int MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE = 0x7E7;
+    /** Home agent rejected MIP (Mobile IP) registration because of registration id mismatch. */
+    public static final int MIP_HA_REGISTRATION_ID_MISMATCH = 0x7E8;
+    /** Home agent rejected MIP (Mobile IP) registration because of malformed request. */
+    public static final int MIP_HA_MALFORMED_REQUEST = 0x7E9;
+    /** Home agent rejected MIP (Mobile IP) registration because of unknown home agent address. */
+    public static final int MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS = 0x7EA;
+    /**
+     * Home agent rejected MIP (Mobile IP) registration because of reverse tunnel was
+     * unavailable.
+     */
+    public static final int MIP_HA_REVERSE_TUNNEL_UNAVAILABLE = 0x7EB;
+    /**
+     * Home agent rejected MIP (Mobile IP) registration because of reverse tunnel is mandatory but
+     * not requested by device.
+     */
+    public static final int MIP_HA_REVERSE_TUNNEL_IS_MANDATORY = 0x7EC;
+    /** Home agent rejected MIP (Mobile IP) registration because of encapsulation unavailable. */
+    public static final int MIP_HA_ENCAPSULATION_UNAVAILABLE = 0x7ED;
+    /** Tearing down is in progress. */
+    public static final int CLOSE_IN_PROGRESS = 0x7EE;
+    /** Brought down by the network. */
+    public static final int NETWORK_INITIATED_TERMINATION = 0x7EF;
+    /** Another application in modem preempts the data call. */
+    public static final int MODEM_APP_PREEMPTED = 0x7F0;
+    /**
+     * IPV4 PDN is in throttled state due to network providing only IPV6 address during the
+     * previous VSNCP bringup (subs_limited_to_v6).
+     */
+    public static final int PDN_IPV4_CALL_DISALLOWED = 0x7F1;
+    /** IPV4 PDN is in throttled state due to previous VSNCP bringup failure(s). */
+    public static final int PDN_IPV4_CALL_THROTTLED = 0x7F2;
+    /**
+     * IPV6 PDN is in throttled state due to network providing only IPV4 address during the
+     * previous VSNCP bringup (subs_limited_to_v4).
+     */
+    public static final int PDN_IPV6_CALL_DISALLOWED = 0x7F3;
+    /** IPV6 PDN is in throttled state due to previous VSNCP bringup failure(s). */
+    public static final int PDN_IPV6_CALL_THROTTLED = 0x7F4;
+    /** Modem restart. */
+    public static final int MODEM_RESTART = 0x7F5;
+    /** PDP PPP calls are not supported. */
+    public static final int PDP_PPP_NOT_SUPPORTED = 0x7F6;
+    /** RAT on which the data call is attempted/connected is no longer the preferred RAT. */
+    public static final int UNPREFERRED_RAT = 0x7F7;
+    /** Physical link is in the process of cleanup. */
+    public static final int PHYSICAL_LINK_CLOSE_IN_PROGRESS = 0x7F8;
+    /** Interface bring up is attempted for an APN that is yet to be handed over to target RAT. */
+    public static final int APN_PENDING_HANDOVER = 0x7F9;
+    /** APN bearer type in the profile does not match preferred network mode. */
+    public static final int PROFILE_BEARER_INCOMPATIBLE = 0x7FA;
+    /** Card was refreshed or removed. */
+    public static final int SIM_CARD_CHANGED = 0x7FB;
+    /** Device is going into lower power mode or powering down. */
+    public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 0x7FC;
+    /** APN has been disabled. */
+    public static final int APN_DISABLED = 0x7FD;
+    /** Maximum PPP inactivity timer expired. */
+    public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE;
+    /** IPv6 address transfer failed. */
+    public static final int IPV6_ADDRESS_TRANSFER_FAILED = 0x7FF;
+    /** Target RAT swap failed. */
+    public static final int TRAT_SWAP_FAILED = 0x800;
+    /** Device falls back from eHRPD to HRPD. */
+    public static final int EHRPD_TO_HRPD_FALLBACK = 0x801;
+    /**
+     * UE is in MIP-only configuration but the MIP configuration fails on call bring up due to
+     * incorrect provisioning.
+     */
+    public static final int MIP_CONFIG_FAILURE = 0x802;
+    /**
+     * PDN inactivity timer expired due to no data transmission in a configurable duration of time.
+     */
+    public static final int PDN_INACTIVITY_TIMER_EXPIRED = 0x803;
+    /**
+     * IPv4 data call bring up is rejected because the UE already maintains the allotted maximum
+     * number of IPv4 data connections.
+     */
+    public static final int MAX_IPV4_CONNECTIONS = 0x804;
+    /**
+     * IPv6 data call bring up is rejected because the UE already maintains the allotted maximum
+     * number of IPv6 data connections.
+     */
+    public static final int MAX_IPV6_CONNECTIONS = 0x805;
+    /**
+     * New PDN bring up is rejected during interface selection because the UE has already allotted
+     * the available interfaces for other PDNs.
+     */
+    public static final int APN_MISMATCH = 0x806;
+    /**
+     * New call bring up is rejected since the existing data call IP type doesn't match the
+     * requested IP.
+     */
+    public static final int IP_VERSION_MISMATCH = 0x807;
+    /** Dial up networking (DUN) call bring up is rejected since UE is in eHRPD RAT. */
+    public static final int DUN_CALL_DISALLOWED = 0x808;
+    /*** Rejected/Brought down since UE is transition between EPC and NONEPC RAT. */
+    public static final int INTERNAL_EPC_NONEPC_TRANSITION = 0x809;
+    /** The current interface is being in use. */
+    public static final int INTERFACE_IN_USE = 0x80A;
+    /** PDN connection to the APN is disallowed on the roaming network. */
+    public static final int APN_DISALLOWED_ON_ROAMING = 0x80B;
+    /** APN-related parameters are changed. */
+    public static final int APN_PARAMETERS_CHANGED = 0x80C;
+    /** PDN is attempted to be brought up with NULL APN but NULL APN is not supported. */
+    public static final int NULL_APN_DISALLOWED = 0x80D;
+    /**
+     * Thermal level increases and causes calls to be torn down when normal mode of operation is
+     * not allowed.
+     */
+    public static final int THERMAL_MITIGATION = 0x80E;
+    /**
+     * PDN Connection to a given APN is disallowed because data is disabled from the device user
+     * interface settings.
+     */
+    public static final int DATA_SETTINGS_DISABLED = 0x80F;
+    /**
+     * PDN Connection to a given APN is disallowed because data roaming is disabled from the device
+     * user interface settings and the UE is roaming.
+     */
+    public static final int DATA_ROAMING_SETTINGS_DISABLED = 0x810;
+    /** DDS (Default data subscription) switch occurs. */
+    public static final int DDS_SWITCHED = 0x811;
+    /** PDN being brought up with an APN that is part of forbidden APN Name list. */
+    public static final int FORBIDDEN_APN_NAME = 0x812;
+    /** Default data subscription switch is in progress. */
+    public static final int DDS_SWITCH_IN_PROGRESS = 0x813;
+    /** Roaming is disallowed during call bring up. */
+    public static final int CALL_DISALLOWED_IN_ROAMING = 0x814;
+    /**
+     * UE is unable to bring up a non-IP data call because the device is not camped on a NB1 cell.
+     */
+    public static final int NON_IP_NOT_SUPPORTED = 0x815;
+    /** Non-IP PDN is in throttled state due to previous VSNCP bringup failure(s). */
+    public static final int PDN_NON_IP_CALL_THROTTLED = 0x816;
+    /** Non-IP PDN is in disallowed state due to the network providing only an IP address. */
+    public static final int PDN_NON_IP_CALL_DISALLOWED = 0x817;
+    /** Device in CDMA locked state. */
+    public static final int CDMA_LOCK = 0x818;
+    /** Received an intercept order from the base station. */
+    public static final int CDMA_INTERCEPT = 0x819;
+    /** Receiving a reorder from the base station. */
+    public static final int CDMA_REORDER = 0x81A;
+    /** Receiving a release from the base station with a SO (Service Option) Reject reason. */
+    public static final int CDMA_RELEASE_DUE_TO_SO_REJECTION = 0x81B;
+    /** Receiving an incoming call from the base station. */
+    public static final int CDMA_INCOMING_CALL = 0x81C;
+    /** Received an alert stop from the base station due to incoming only. */
+    public static final int CDMA_ALERT_STOP = 0x81D;
+    /**
+     * Channel acquisition failures. This indicates that device has failed acquiring all the
+     * channels in the PRL.
+     */
+    public static final int CHANNEL_ACQUISITION_FAILURE = 0x81E;
+    /** Maximum access probes transmitted. */
+    public static final int MAX_ACCESS_PROBE = 0x81F;
+    /** Concurrent service is not supported by base station. */
+    public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 0x820;
+    /** There was no response received from the base station. */
+    public static final int NO_RESPONSE_FROM_BASE_STATION = 0x821;
+    /** The base station rejecting the call. */
+    public static final int REJECTED_BY_BASE_STATION = 0x822;
+    /** The concurrent services requested were not compatible. */
+    public static final int CONCURRENT_SERVICES_INCOMPATIBLE = 0x823;
+    /** Device does not have CDMA service. */
+    public static final int NO_CDMA_SERVICE = 0x824;
+    /** RUIM not being present. */
+    public static final int RUIM_NOT_PRESENT = 0x825;
+    /** Receiving a retry order from the base station. */
+    public static final int CDMA_RETRY_ORDER = 0x826;
+    /** Access blocked by the base station. */
+    public static final int ACCESS_BLOCK = 0x827;
+    /** Access blocked by the base station for all mobile devices. */
+    public static final int ACCESS_BLOCK_ALL = 0x828;
+    /** Maximum access probes for the IS-707B call. */
+    public static final int IS707B_MAX_ACCESS_PROBES = 0x829;
+    /** Put device in thermal emergency. */
+    public static final int THERMAL_EMERGENCY = 0x82A;
+    /** In favor of a voice call or SMS when concurrent voice and data are not supported. */
+    public static final int CONCURRENT_SERVICES_NOT_ALLOWED = 0x82B;
+    /** The other clients rejected incoming call. */
+    public static final int INCOMING_CALL_REJECTED = 0x82C;
+    /** No service on the gateway. */
+    public static final int NO_SERVICE_ON_GATEWAY = 0x82D;
+    /** GPRS context is not available. */
+    public static final int NO_GPRS_CONTEXT = 0x82E;
+    /**
+     * Network refuses service to the MS because either an identity of the MS is not acceptable to
+     * the network or the MS does not pass the authentication check.
+     */
+    public static final int ILLEGAL_MS = 0x82F;
+    /** ME could not be authenticated and the ME used is not acceptable to the network. */
+    public static final int ILLEGAL_ME = 0x830;
+    /** Not allowed to operate either GPRS or non-GPRS services. */
+    public static final int GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 0x831;
+    /** MS is not allowed to operate GPRS services. */
+    public static final int GPRS_SERVICES_NOT_ALLOWED = 0x832;
+    /** No matching identity or context could be found in the network. */
+    public static final int MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK = 0x833;
+    /**
+     * Mobile reachable timer has expired, or the GMM context data related to the subscription does
+     * not exist in the SGSN.
+     */
+    public static final int IMPLICITLY_DETACHED = 0x834;
+    /**
+     * UE requests GPRS service, or the network initiates a detach request in a PLMN which does not
+     * offer roaming for GPRS services to that MS.
+     */
+    public static final int PLMN_NOT_ALLOWED = 0x835;
+    /**
+     * MS requests service, or the network initiates a detach request, in a location area where the
+     * HPLMN determines that the MS, by subscription, is not allowed to operate.
+     */
+    public static final int LOCATION_AREA_NOT_ALLOWED = 0x836;
+    /**
+     * UE requests GPRS service or the network initiates a detach request in a PLMN that does not
+     * offer roaming for GPRS services.
+     */
+    public static final int GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN = 0x837;
+    /** PDP context already exists. */
+    public static final int PDP_DUPLICATE = 0x838;
+    /** RAT change on the UE. */
+    public static final int UE_RAT_CHANGE = 0x839;
+    /** Network cannot serve a request from the MS due to congestion. */
+    public static final int CONGESTION = 0x83A;
+    /**
+     * MS requests an establishment of the radio access bearers for all active PDP contexts by
+     * sending a service request message indicating data to the network, but the SGSN does not have
+     * any active PDP context.
+     */
+    public static final int NO_PDP_CONTEXT_ACTIVATED = 0x83B;
+    /** Access class blocking restrictions for the current camped cell. */
+    public static final int ACCESS_CLASS_DSAC_REJECTION = 0x83C;
+    /** SM attempts PDP activation for a maximum of four attempts. */
+    public static final int PDP_ACTIVATE_MAX_RETRY_FAILED = 0x83D;
+    /** Radio access bearer failure. */
+    public static final int RADIO_ACCESS_BEARER_FAILURE = 0x83E;
+    /** Invalid EPS bearer identity in the request. */
+    public static final int ESM_UNKNOWN_EPS_BEARER_CONTEXT = 0x83F;
+    /** Data radio bearer is released by the RRC. */
+    public static final int DRB_RELEASED_BY_RRC = 0x840;
+    /** Indicate the connection was released. */
+    public static final int CONNECTION_RELEASED = 0x841;
+    /** UE is detached. */
+    public static final int EMM_DETACHED = 0x842;
+    /** Attach procedure is rejected by the network. */
+    public static final int EMM_ATTACH_FAILED = 0x843;
+    /** Attach procedure is started for EMC purposes. */
+    public static final int EMM_ATTACH_STARTED = 0x844;
+    /** Service request procedure failure. */
+    public static final int LTE_NAS_SERVICE_REQUEST_FAILED = 0x845;
+    /** Active dedicated bearer was requested using the same default bearer ID. */
+    public static final int DUPLICATE_BEARER_ID = 0x846;
+    /** Collision scenarios for the UE and network-initiated procedures. */
+    public static final int ESM_COLLISION_SCENARIOS = 0x847;
+    /** Bearer must be deactivated to synchronize with the network. */
+    public static final int ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK = 0x848;
+    /** Active dedicated bearer was requested for an existing default bearer. */
+    public static final int ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER = 0x849;
+    /** Bad OTA message is received from the network. */
+    public static final int ESM_BAD_OTA_MESSAGE = 0x84A;
+    /** Download server rejected the call. */
+    public static final int ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL = 0x84B;
+    /** PDN was disconnected by the downlaod server due to IRAT. */
+    public static final int ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT = 0x84C;
+    /** Dedicated bearer will be deactivated regardless of the network response. */
+    public static final int DS_EXPLICIT_DEACTIVATION = 0x84D;
+    /** No specific local cause is mentioned, usually a valid OTA cause. */
+    public static final int ESM_LOCAL_CAUSE_NONE = 0x84E;
+    /** Throttling is not needed for this service request failure. */
+    public static final int LTE_THROTTLING_NOT_REQUIRED = 0x84F;
+    /** Access control list check failure at the lower layer. */
+    public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 0x850;
+    /** Service is not allowed on the requested PLMN. */
+    public static final int SERVICE_NOT_ALLOWED_ON_PLMN = 0x851;
+    /** T3417 timer expiration of the service request procedure. */
+    public static final int EMM_T3417_EXPIRED = 0x852;
+    /** Extended service request fails due to expiration of the T3417 EXT timer. */
+    public static final int EMM_T3417_EXT_EXPIRED = 0x853;
+    /** Transmission failure of radio resource control (RRC) uplink data. */
+    public static final int RRC_UPLINK_DATA_TRANSMISSION_FAILURE = 0x854;
+    /** Radio resource control (RRC) uplink data delivery failed due to a handover. */
+    public static final int RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER = 0x855;
+    /** Radio resource control (RRC) uplink data delivery failed due to a connection release. */
+    public static final int RRC_UPLINK_CONNECTION_RELEASE = 0x856;
+    /** Radio resource control (RRC) uplink data delivery failed due to a radio link failure. */
+    public static final int RRC_UPLINK_RADIO_LINK_FAILURE = 0x857;
+    /**
+     * Radio resource control (RRC) is not connected but the non-access stratum (NAS) sends an
+     * uplink data request.
+     */
+    public static final int RRC_UPLINK_ERROR_REQUEST_FROM_NAS = 0x858;
+    /** Radio resource control (RRC) connection failure at access stratum. */
+    public static final int RRC_CONNECTION_ACCESS_STRATUM_FAILURE = 0x859;
+    /**
+     * Radio resource control (RRC) connection establishment is aborted due to another procedure.
+     */
+    public static final int RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS = 0x85A;
+    /** Radio resource control (RRC) connection establishment failed due to access barrred. */
+    public static final int RRC_CONNECTION_ACCESS_BARRED = 0x85B;
+    /**
+     * Radio resource control (RRC) connection establishment failed due to cell reselection at
+     * access stratum.
+     */
+    public static final int RRC_CONNECTION_CELL_RESELECTION = 0x85C;
+    /**
+     * Connection establishment failed due to configuration failure at the radio resource control
+     * (RRC).
+     */
+    public static final int RRC_CONNECTION_CONFIG_FAILURE = 0x85D;
+    /** Radio resource control (RRC) connection could not be established in the time limit. */
+    public static final int RRC_CONNECTION_TIMER_EXPIRED = 0x85E;
+    /**
+     * Connection establishment failed due to a link failure at the radio resource control (RRC).
+     */
+    public static final int RRC_CONNECTION_LINK_FAILURE = 0x85F;
+    /**
+     * Connection establishment failed as the radio resource control (RRC) is not camped on any
+     * cell.
+     */
+    public static final int RRC_CONNECTION_CELL_NOT_CAMPED = 0x860;
+    /**
+     * Connection establishment failed due to a service interval failure at the radio resource
+     * control (RRC).
+     */
+    public static final int RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE = 0x861;
+    /**
+     * Radio resource control (RRC) connection establishment failed due to the network rejecting
+     * the UE connection request.
+     */
+    public static final int RRC_CONNECTION_REJECT_BY_NETWORK = 0x862;
+    /** Normal radio resource control (RRC) connection release. */
+    public static final int RRC_CONNECTION_NORMAL_RELEASE = 0x863;
+    /**
+     * Radio resource control (RRC) connection release failed due to radio link failure conditions.
+     */
+    public static final int RRC_CONNECTION_RADIO_LINK_FAILURE = 0x864;
+    /** Radio resource control (RRC) connection re-establishment failure. */
+    public static final int RRC_CONNECTION_REESTABLISHMENT_FAILURE = 0x865;
+    /** UE is out of service during the call register. */
+    public static final int RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER = 0x866;
+    /**
+     * Connection has been released by the radio resource control (RRC) due to an abort request.
+     */
+    public static final int RRC_CONNECTION_ABORT_REQUEST = 0x867;
+    /**
+     * Radio resource control (RRC) connection released due to a system information block read
+     * error.
+     */
+    public static final int RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR = 0x868;
+    /** Network-initiated detach with reattach. */
+    public static final int NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH = 0x869;
+    /** Network-initiated detach without reattach. */
+    public static final int NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH = 0x86A;
+    /** ESM procedure maximum attempt timeout failure. */
+    public static final int ESM_PROCEDURE_TIME_OUT = 0x86B;
+    /**
+     * No PDP exists with the given connection ID while modifying or deactivating or activation for
+     * an already active PDP.
+     */
+    public static final int INVALID_CONNECTION_ID = 0x86C;
+    /** Maximum NSAPIs have been exceeded during PDP activation. */
+    public static final int MAXIMIUM_NSAPIS_EXCEEDED = 0x86D;
+    /** Primary context for NSAPI does not exist. */
+    public static final int INVALID_PRIMARY_NSAPI = 0x86E;
+    /** Unable to encode the OTA message for MT PDP or deactivate PDP. */
+    public static final int CANNOT_ENCODE_OTA_MESSAGE = 0x86F;
+    /**
+     * Radio access bearer is not established by the lower layers during activation, modification,
+     * or deactivation.
+     */
+    public static final int RADIO_ACCESS_BEARER_SETUP_FAILURE = 0x870;
+    /** Expiration of the PDP establish timer with a maximum of five retries. */
+    public static final int PDP_ESTABLISH_TIMEOUT_EXPIRED = 0x871;
+    /** Expiration of the PDP modify timer with a maximum of four retries. */
+    public static final int PDP_MODIFY_TIMEOUT_EXPIRED = 0x872;
+    /** Expiration of the PDP deactivate timer with a maximum of four retries. */
+    public static final int PDP_INACTIVE_TIMEOUT_EXPIRED = 0x873;
+    /** PDP activation failed due to RRC_ABORT or a forbidden PLMN. */
+    public static final int PDP_LOWERLAYER_ERROR = 0x874;
+    /** MO PDP modify collision when the MT PDP is already in progress. */
+    public static final int PDP_MODIFY_COLLISION = 0x875;
+    /** Maximum size of the L2 message was exceeded. */
+    public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 0x876;
+    /** Non-access stratum (NAS) request was rejected by the network. */
+    public static final int NAS_REQUEST_REJECTED_BY_NETWORK = 0x877;
+    /**
+     * Radio resource control (RRC) connection establishment failure due to an error in the request
+     * message.
+     */
+    public static final int RRC_CONNECTION_INVALID_REQUEST = 0x878;
+    /**
+     * Radio resource control (RRC) connection establishment failure due to a change in the
+     * tracking area ID.
+     */
+    public static final int RRC_CONNECTION_TRACKING_AREA_ID_CHANGED = 0x879;
+    /**
+     * Radio resource control (RRC) connection establishment failure due to the RF was unavailable.
+     */
+    public static final int RRC_CONNECTION_RF_UNAVAILABLE = 0x87A;
+    /**
+     * Radio resource control (RRC) connection was aborted before deactivating the LTE stack due to
+     * a successful LTE to WCDMA/GSM/TD-SCDMA IRAT change.
+     */
+    public static final int RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE = 0x87B;
+    /**
+     * If the UE has an LTE radio link failure before security is established, the radio resource
+     * control (RRC) connection must be released and the UE must return to idle.
+     */
+    public static final int RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE = 0x87C;
+    /**
+     * Radio resource control (RRC) connection was aborted by the non-access stratum (NAS) after an
+     * IRAT to LTE IRAT handover.
+     */
+    public static final int RRC_CONNECTION_ABORTED_AFTER_HANDOVER = 0x87D;
+    /**
+     * Radio resource control (RRC) connection was aborted before deactivating the LTE stack after
+     * a successful LTE to GSM/EDGE IRAT cell change order procedure.
+     */
+    public static final int RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE = 0x87E;
+    /**
+     * Radio resource control (RRC) connection was aborted in the middle of a LTE to GSM IRAT cell
+     * change order procedure.
+     */
+    public static final int RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE = 0x87F;
+    /** IMSI present in the UE is unknown in the home subscriber server. */
+    public static final int IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER = 0x880;
+    /** IMEI of the UE is not accepted by the network. */
+    public static final int IMEI_NOT_ACCEPTED = 0x881;
+    /** EPS and non-EPS services are not allowed by the network. */
+    public static final int EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED = 0x882;
+    /** EPS services are not allowed in the PLMN. */
+    public static final int EPS_SERVICES_NOT_ALLOWED_IN_PLMN = 0x883;
+    /** Mobile switching center is temporarily unreachable. */
+    public static final int MSC_TEMPORARILY_NOT_REACHABLE = 0x884;
+    /** CS domain is not available. */
+    public static final int CS_DOMAIN_NOT_AVAILABLE = 0x885;
+    /** ESM level failure. */
+    public static final int ESM_FAILURE = 0x886;
+    /** MAC level failure. */
+    public static final int MAC_FAILURE = 0x887;
+    /** Synchronization failure. */
+    public static final int SYNCHRONIZATION_FAILURE = 0x888;
+    /** UE security capabilities mismatch. */
+    public static final int UE_SECURITY_CAPABILITIES_MISMATCH = 0x889;
+    /** Unspecified security mode reject. */
+    public static final int SECURITY_MODE_REJECTED = 0x88A;
+    /** Unacceptable non-EPS authentication. */
+    public static final int UNACCEPTABLE_NON_EPS_AUTHENTICATION = 0x88B;
+    /** CS fallback call establishment is not allowed. */
+    public static final int CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED = 0x88C;
+    /** No EPS bearer context was activated. */
+    public static final int NO_EPS_BEARER_CONTEXT_ACTIVATED = 0x88D;
+    /** Invalid EMM state. */
+    public static final int INVALID_EMM_STATE = 0x88E;
+    /** Non-Access Spectrum layer failure. */
+    public static final int NAS_LAYER_FAILURE = 0x88F;
+    /** Multiple PDP call feature is disabled. */
+    public static final int MULTIPLE_PDP_CALL_NOT_ALLOWED = 0x890;
+    /** Data call has been brought down because EMBMS is not enabled at the RRC layer. */
+    public static final int EMBMS_NOT_ENABLED = 0x891;
+    /** Data call was unsuccessfully transferred during the IRAT handover. */
+    public static final int IRAT_HANDOVER_FAILED = 0x892;
+    /** EMBMS data call has been successfully brought down. */
+    public static final int EMBMS_REGULAR_DEACTIVATION = 0x893;
+    /** Test loop-back data call has been successfully brought down. */
+    public static final int TEST_LOOPBACK_REGULAR_DEACTIVATION = 0x894;
+    /** Lower layer registration failure. */
+    public static final int LOWER_LAYER_REGISTRATION_FAILURE = 0x895;
+    /**
+     * Network initiates a detach on LTE with error cause ""data plan has been replenished or has
+     * expired.
+     */
+    public static final int DATA_PLAN_EXPIRED = 0x896;
+    /** UMTS interface is brought down due to handover from UMTS to iWLAN. */
+    public static final int UMTS_HANDOVER_TO_IWLAN = 0x897;
+    /** Received a connection deny due to general or network busy on EVDO network. */
+    public static final int EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY = 0x898;
+    /** Received a connection deny due to billing or authentication failure on EVDO network. */
+    public static final int EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE = 0x899;
+    /** HDR system has been changed due to redirection or the PRL was not preferred. */
+    public static final int EVDO_HDR_CHANGED = 0x89A;
+    /** Device exited HDR due to redirection or the PRL was not preferred. */
+    public static final int EVDO_HDR_EXITED = 0x89B;
+    /** Device does not have an HDR session. */
+    public static final int EVDO_HDR_NO_SESSION = 0x89C;
+    /** It is ending an HDR call origination in favor of a GPS fix. */
+    public static final int EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL = 0x89D;
+    /** Connection setup on the HDR system was time out. */
+    public static final int EVDO_HDR_CONNECTION_SETUP_TIMEOUT = 0x89E;
+    /** Device failed to acquire a co-located HDR for origination. */
+    public static final int FAILED_TO_ACQUIRE_COLOCATED_HDR = 0x89F;
+    /** OTASP commit is in progress. */
+    public static final int OTASP_COMMIT_IN_PROGRESS = 0x8A0;
+    /** Device has no hybrid HDR service. */
+    public static final int NO_HYBRID_HDR_SERVICE = 0x8A1;
+    /** HDR module could not be obtained because of the RF locked. */
+    public static final int HDR_NO_LOCK_GRANTED = 0x8A2;
+    /** DBM or SMS is in progress. */
+    public static final int DBM_OR_SMS_IN_PROGRESS = 0x8A3;
+    /** HDR module released the call due to fade. */
+    public static final int HDR_FADE = 0x8A4;
+    /** HDR system access failure. */
+    public static final int HDR_ACCESS_FAILURE = 0x8A5;
+    /**
+     * P_rev supported by 1 base station is less than 6, which is not supported for a 1X data call.
+     * The UE must be in the footprint of BS which has p_rev >= 6 to support this SO33 call.
+     */
+    public static final int UNSUPPORTED_1X_PREV = 0x8A6;
+    /** Client ended the data call. */
+    public static final int LOCAL_END = 0x8A7;
+    /** Device has no service. */
+    public static final int NO_SERVICE = 0x8A8;
+    /** Device lost the system due to fade. */
+    public static final int FADE = 0x8A9;
+    /** Receiving a release from the base station with no reason. */
+    public static final int NORMAL_RELEASE = 0x8AA;
+    /** Access attempt is already in progress. */
+    public static final int ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 0x8AB;
+    /** Device is in the process of redirecting or handing off to a different target system. */
+    public static final int REDIRECTION_OR_HANDOFF_IN_PROGRESS = 0x8AC;
+    /** Device is operating in Emergency mode. */
+    public static final int EMERGENCY_MODE = 0x8AD;
+    /** Device is in use (e.g., voice call). */
+    public static final int PHONE_IN_USE = 0x8AE;
+    /**
+     * Device operational mode is different from the mode requested in the traffic channel bring up.
+     */
+    public static final int INVALID_MODE = 0x8AF;
+    /** SIM was marked by the network as invalid for the circuit and/or packet service domain. */
+    public static final int INVALID_SIM_STATE = 0x8B0;
+    /** There is no co-located HDR. */
+    public static final int NO_COLLOCATED_HDR = 0x8B1;
+    /** UE is entering power save mode. */
+    public static final int UE_IS_ENTERING_POWERSAVE_MODE = 0x8B2;
+    /** Dual switch from single standby to dual standby is in progress. */
+    public static final int DUAL_SWITCH = 0x8B3;
+    /**
+     * Data call bring up fails in the PPP setup due to a timeout.
+     * (e.g., an LCP conf ack was not received from the network)
+     */
+    public static final int PPP_TIMEOUT = 0x8B4;
+    /**
+     * Data call bring up fails in the PPP setup due to an authorization failure.
+     * (e.g., authorization is required, but not negotiated with the network during an LCP phase)
+     */
+    public static final int PPP_AUTH_FAILURE = 0x8B5;
+    /** Data call bring up fails in the PPP setup due to an option mismatch. */
+    public static final int PPP_OPTION_MISMATCH = 0x8B6;
+    /** Data call bring up fails in the PPP setup due to a PAP failure. */
+    public static final int PPP_PAP_FAILURE = 0x8B7;
+    /** Data call bring up fails in the PPP setup due to a CHAP failure. */
+    public static final int PPP_CHAP_FAILURE = 0x8B8;
+    /**
+     * Data call bring up fails in the PPP setup because the PPP is in the process of cleaning the
+     * previous PPP session.
+     */
+    public static final int PPP_CLOSE_IN_PROGRESS = 0x8B9;
+    /**
+     * IPv6 interface bring up fails because the network provided only the IPv4 address for the
+     * upcoming PDN permanent client can reattempt a IPv6 call bring up after the IPv4 interface is
+     * also brought down. However, there is no guarantee that the network will provide a IPv6
+     * address.
+     */
+    public static final int LIMITED_TO_IPV4 = 0x8BA;
+    /**
+     * IPv4 interface bring up fails because the network provided only the IPv6 address for the
+     * upcoming PDN permanent client can reattempt a IPv4 call bring up after the IPv6 interface is
+     * also brought down. However there is no guarantee that the network will provide a IPv4
+     * address.
+     */
+    public static final int LIMITED_TO_IPV6 = 0x8BB;
+    /** Data call bring up fails in the VSNCP phase due to a VSNCP timeout error. */
+    public static final int VSNCP_TIMEOUT = 0x8BC;
+    /**
+     * Data call bring up fails in the VSNCP phase due to a general error. It's used when there is
+     * no other specific error code available to report the failure.
+     */
+    public static final int VSNCP_GEN_ERROR = 0x8BD;
+    /**
+     * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
+     * configuration request because the requested APN is unauthorized.
+     */
+    public static final int VSNCP_APN_UNATHORIZED = 0x8BE;
+    /**
+     * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
+     * configuration request because the PDN limit has been exceeded.
+     */
+    public static final int VSNCP_PDN_LIMIT_EXCEEDED = 0x8BF;
+    /**
+     * Data call bring up fails in the VSNCP phase due to the network rejected the VSNCP
+     * configuration request due to no PDN gateway address.
+     */
+    public static final int VSNCP_NO_PDN_GATEWAY_ADDRESS = 0x8C0;
+    /**
+     * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
+     * configuration request because the PDN gateway is unreachable.
+     */
+    public static final int VSNCP_PDN_GATEWAY_UNREACHABLE = 0x8C1;
+    /**
+     * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
+     * configuration request due to a PDN gateway reject.
+     */
+    public static final int VSNCP_PDN_GATEWAY_REJECT = 0x8C2;
+    /**
+     * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
+     * configuration request with the reason of insufficient parameter.
+     */
+    public static final int VSNCP_INSUFFICIENT_PARAMETERS = 0x8C3;
+    /**
+     * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
+     * configuration request with the reason of resource unavailable.
+     */
+    public static final int VSNCP_RESOURCE_UNAVAILABLE = 0x8C4;
+    /**
+     * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
+     * configuration request with the reason of administratively prohibited at the HSGW.
+     */
+    public static final int VSNCP_ADMINISTRATIVELY_PROHIBITED = 0x8C5;
+    /**
+     * Data call bring up fails in the VSNCP phase due to a network rejection of PDN ID in use, or
+     * all existing PDNs are brought down with this end reason because one of the PDN bring up was
+     * rejected by the network with the reason of PDN ID in use.
+     */
+    public static final int VSNCP_PDN_ID_IN_USE = 0x8C6;
+    /**
+     * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
+     * configuration request for the reason of subscriber limitation.
+     */
+    public static final int VSNCP_SUBSCRIBER_LIMITATION = 0x8C7;
+    /**
+     * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
+     * configuration request because the PDN exists for this APN.
+     */
+    public static final int VSNCP_PDN_EXISTS_FOR_THIS_APN = 0x8C8;
+    /**
+     * Data call bring up fails in the VSNCP phase due to a network rejection of the VSNCP
+     * configuration request with reconnect to this PDN not allowed, or an active data call is
+     * terminated by the network because reconnection to this PDN is not allowed. Upon receiving
+     * this error code from the network, the modem infinitely throttles the PDN until the next
+     * power cycle.
+     */
+    public static final int VSNCP_RECONNECT_NOT_ALLOWED = 0x8C9;
+    /** Device failure to obtain the prefix from the network. */
+    public static final int IPV6_PREFIX_UNAVAILABLE = 0x8CA;
+    /** System preference change back to SRAT during handoff */
+    public static final int HANDOFF_PREFERENCE_CHANGED = 0x8CB;
 
     // OEM sepecific error codes. To be used by OEMs when they don't
     // want to reveal error code which would be replaced by ERROR_UNSPECIFIED
@@ -165,24 +929,45 @@
 
     // Local errors generated by Vendor RIL
     // specified in ril.h
+    /** Data fail due to registration failure. */
     public static final int REGISTRATION_FAIL = -1;
+    /** Data fail due to GPRS registration failure. */
     public static final int GPRS_REGISTRATION_FAIL = -2;
+    /** Data call drop due to network/modem disconnect. */
     public static final int SIGNAL_LOST = -3;                        /* no retry */
+    /**
+     * Preferred technology has changed, must retry with parameters appropriate for new technology.
+     */
     public static final int PREF_RADIO_TECH_CHANGED = -4;
+    /** data call was disconnected because radio was resetting, powered off. */
     public static final int RADIO_POWER_OFF = -5;                    /* no retry */
+    /** Data call was disconnected by modem because tethered. */
     public static final int TETHERED_CALL_ACTIVE = -6;               /* no retry */
+    /** Data call fail due to unspecific errors. */
     public static final int ERROR_UNSPECIFIED = 0xFFFF;
 
     // Errors generated by the Framework
     // specified here
+    /** Unknown data failure cause. */
     public static final int UNKNOWN = 0x10000;
+    /** Data fail due to radio not unavailable. */
     public static final int RADIO_NOT_AVAILABLE = 0x10001;                   /* no retry */
+    /** @hide */
     public static final int UNACCEPTABLE_NETWORK_PARAMETER = 0x10002;        /* no retry */
+    /** @hide */
     public static final int CONNECTION_TO_DATACONNECTIONAC_BROKEN = 0x10003;
+    /** Data connection was lost. */
     public static final int LOST_CONNECTION = 0x10004;
-    /** Data was reset by framework. */
+    /** @hide */
     public static final int RESET_BY_FRAMEWORK = 0x10005;
 
+    /**
+     * Data handover failed.
+     *
+     * @hide
+     */
+    public static final int HANDOVER_FAILED = 0x10006;
+
     /** @hide */
     @IntDef(value = {
             NONE,
@@ -210,13 +995,19 @@
             FILTER_SEMANTIC_ERROR,
             FILTER_SYTAX_ERROR,
             PDP_WITHOUT_ACTIVE_TFT,
+            ACTIVATION_REJECTED_BCM_VIOLATION,
             ONLY_IPV4_ALLOWED,
             ONLY_IPV6_ALLOWED,
             ONLY_SINGLE_BEARER_ALLOWED,
             ESM_INFO_NOT_RECEIVED,
             PDN_CONN_DOES_NOT_EXIST,
             MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED,
-            MAX_ACTIVE_PDP_CONTEXT_REACHED,
+            COLLISION_WITH_NETWORK_INITIATED_REQUEST,
+            ONLY_IPV4V6_ALLOWED,
+            ONLY_NON_IP_ALLOWED,
+            UNSUPPORTED_QCI_VALUE,
+            BEARER_HANDLING_NOT_SUPPORTED,
+            ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED,
             UNSUPPORTED_APN_IN_CURRENT_PLMN,
             INVALID_TRANSACTION_ID,
             MESSAGE_INCORRECT_SEMANTIC,
@@ -226,7 +1017,7 @@
             UNKNOWN_INFO_ELEMENT,
             CONDITIONAL_IE_ERROR,
             MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE,
-            PROTOCOL_ERRORS,                 /* no retry */
+            PROTOCOL_ERRORS,
             APN_TYPE_CONFLICT,
             INVALID_PCSCF_ADDR,
             INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN,
@@ -238,6 +1029,262 @@
             IFACE_AND_POL_FAMILY_MISMATCH,
             EMM_ACCESS_BARRED_INFINITE_RETRY,
             AUTH_FAILURE_ON_EMERGENCY_CALL,
+            INVALID_DNS_ADDR,
+            INVALID_PCSCF_OR_DNS_ADDRESS,
+            CALL_PREEMPT_BY_EMERGENCY_APN,
+            UE_INITIATED_DETACH_OR_DISCONNECT,
+            MIP_FA_REASON_UNSPECIFIED,
+            MIP_FA_ADMIN_PROHIBITED,
+            MIP_FA_INSUFFICIENT_RESOURCES,
+            MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE,
+            MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE,
+            MIP_FA_REQUESTED_LIFETIME_TOO_LONG,
+            MIP_FA_MALFORMED_REQUEST,
+            MIP_FA_MALFORMED_REPLY,
+            MIP_FA_ENCAPSULATION_UNAVAILABLE,
+            MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE,
+            MIP_FA_REVERSE_TUNNEL_UNAVAILABLE,
+            MIP_FA_REVERSE_TUNNEL_IS_MANDATORY,
+            MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED,
+            MIP_FA_MISSING_NAI,
+            MIP_FA_MISSING_HOME_AGENT,
+            MIP_FA_MISSING_HOME_ADDRESS,
+            MIP_FA_UNKNOWN_CHALLENGE,
+            MIP_FA_MISSING_CHALLENGE,
+            MIP_FA_STALE_CHALLENGE,
+            MIP_HA_REASON_UNSPECIFIED,
+            MIP_HA_ADMIN_PROHIBITED,
+            MIP_HA_INSUFFICIENT_RESOURCES,
+            MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE,
+            MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE,
+            MIP_HA_REGISTRATION_ID_MISMATCH,
+            MIP_HA_MALFORMED_REQUEST,
+            MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS,
+            MIP_HA_REVERSE_TUNNEL_UNAVAILABLE,
+            MIP_HA_REVERSE_TUNNEL_IS_MANDATORY,
+            MIP_HA_ENCAPSULATION_UNAVAILABLE,
+            CLOSE_IN_PROGRESS,
+            NETWORK_INITIATED_TERMINATION,
+            MODEM_APP_PREEMPTED,
+            PDN_IPV4_CALL_DISALLOWED,
+            PDN_IPV4_CALL_THROTTLED,
+            PDN_IPV6_CALL_DISALLOWED,
+            PDN_IPV6_CALL_THROTTLED,
+            MODEM_RESTART,
+            PDP_PPP_NOT_SUPPORTED,
+            UNPREFERRED_RAT,
+            PHYSICAL_LINK_CLOSE_IN_PROGRESS,
+            APN_PENDING_HANDOVER,
+            PROFILE_BEARER_INCOMPATIBLE,
+            SIM_CARD_CHANGED,
+            LOW_POWER_MODE_OR_POWERING_DOWN,
+            APN_DISABLED,
+            MAX_PPP_INACTIVITY_TIMER_EXPIRED,
+            IPV6_ADDRESS_TRANSFER_FAILED,
+            TRAT_SWAP_FAILED,
+            EHRPD_TO_HRPD_FALLBACK,
+            MIP_CONFIG_FAILURE,
+            PDN_INACTIVITY_TIMER_EXPIRED,
+            MAX_IPV4_CONNECTIONS,
+            MAX_IPV6_CONNECTIONS,
+            APN_MISMATCH,
+            IP_VERSION_MISMATCH,
+            DUN_CALL_DISALLOWED,
+            INTERNAL_EPC_NONEPC_TRANSITION,
+            INTERFACE_IN_USE,
+            APN_DISALLOWED_ON_ROAMING,
+            APN_PARAMETERS_CHANGED,
+            NULL_APN_DISALLOWED,
+            THERMAL_MITIGATION,
+            DATA_SETTINGS_DISABLED,
+            DATA_ROAMING_SETTINGS_DISABLED,
+            DDS_SWITCHED,
+            FORBIDDEN_APN_NAME,
+            DDS_SWITCH_IN_PROGRESS,
+            CALL_DISALLOWED_IN_ROAMING,
+            NON_IP_NOT_SUPPORTED,
+            PDN_NON_IP_CALL_THROTTLED,
+            PDN_NON_IP_CALL_DISALLOWED,
+            CDMA_LOCK,
+            CDMA_INTERCEPT,
+            CDMA_REORDER,
+            CDMA_RELEASE_DUE_TO_SO_REJECTION,
+            CDMA_INCOMING_CALL,
+            CDMA_ALERT_STOP,
+            CHANNEL_ACQUISITION_FAILURE,
+            MAX_ACCESS_PROBE,
+            CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
+            NO_RESPONSE_FROM_BASE_STATION,
+            REJECTED_BY_BASE_STATION,
+            CONCURRENT_SERVICES_INCOMPATIBLE,
+            NO_CDMA_SERVICE,
+            RUIM_NOT_PRESENT,
+            CDMA_RETRY_ORDER,
+            ACCESS_BLOCK,
+            ACCESS_BLOCK_ALL,
+            IS707B_MAX_ACCESS_PROBES,
+            THERMAL_EMERGENCY,
+            CONCURRENT_SERVICES_NOT_ALLOWED,
+            INCOMING_CALL_REJECTED,
+            NO_SERVICE_ON_GATEWAY,
+            NO_GPRS_CONTEXT,
+            ILLEGAL_MS,
+            ILLEGAL_ME,
+            GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED,
+            GPRS_SERVICES_NOT_ALLOWED,
+            MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK,
+            IMPLICITLY_DETACHED,
+            PLMN_NOT_ALLOWED,
+            LOCATION_AREA_NOT_ALLOWED,
+            GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN,
+            PDP_DUPLICATE,
+            UE_RAT_CHANGE,
+            CONGESTION,
+            NO_PDP_CONTEXT_ACTIVATED,
+            ACCESS_CLASS_DSAC_REJECTION,
+            PDP_ACTIVATE_MAX_RETRY_FAILED,
+            RADIO_ACCESS_BEARER_FAILURE,
+            ESM_UNKNOWN_EPS_BEARER_CONTEXT,
+            DRB_RELEASED_BY_RRC,
+            CONNECTION_RELEASED,
+            EMM_DETACHED,
+            EMM_ATTACH_FAILED,
+            EMM_ATTACH_STARTED,
+            LTE_NAS_SERVICE_REQUEST_FAILED,
+            DUPLICATE_BEARER_ID,
+            ESM_COLLISION_SCENARIOS,
+            ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK,
+            ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER,
+            ESM_BAD_OTA_MESSAGE,
+            ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL,
+            ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT,
+            DS_EXPLICIT_DEACTIVATION,
+            ESM_LOCAL_CAUSE_NONE,
+            LTE_THROTTLING_NOT_REQUIRED,
+            ACCESS_CONTROL_LIST_CHECK_FAILURE,
+            SERVICE_NOT_ALLOWED_ON_PLMN,
+            EMM_T3417_EXPIRED,
+            EMM_T3417_EXT_EXPIRED,
+            RRC_UPLINK_DATA_TRANSMISSION_FAILURE,
+            RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER,
+            RRC_UPLINK_CONNECTION_RELEASE,
+            RRC_UPLINK_RADIO_LINK_FAILURE,
+            RRC_UPLINK_ERROR_REQUEST_FROM_NAS,
+            RRC_CONNECTION_ACCESS_STRATUM_FAILURE,
+            RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS,
+            RRC_CONNECTION_ACCESS_BARRED,
+            RRC_CONNECTION_CELL_RESELECTION,
+            RRC_CONNECTION_CONFIG_FAILURE,
+            RRC_CONNECTION_TIMER_EXPIRED,
+            RRC_CONNECTION_LINK_FAILURE,
+            RRC_CONNECTION_CELL_NOT_CAMPED,
+            RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE,
+            RRC_CONNECTION_REJECT_BY_NETWORK,
+            RRC_CONNECTION_NORMAL_RELEASE,
+            RRC_CONNECTION_RADIO_LINK_FAILURE,
+            RRC_CONNECTION_REESTABLISHMENT_FAILURE,
+            RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER,
+            RRC_CONNECTION_ABORT_REQUEST,
+            RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR,
+            NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH,
+            NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH,
+            ESM_PROCEDURE_TIME_OUT,
+            INVALID_CONNECTION_ID,
+            MAXIMIUM_NSAPIS_EXCEEDED,
+            INVALID_PRIMARY_NSAPI,
+            CANNOT_ENCODE_OTA_MESSAGE,
+            RADIO_ACCESS_BEARER_SETUP_FAILURE,
+            PDP_ESTABLISH_TIMEOUT_EXPIRED,
+            PDP_MODIFY_TIMEOUT_EXPIRED,
+            PDP_INACTIVE_TIMEOUT_EXPIRED,
+            PDP_LOWERLAYER_ERROR,
+            PDP_MODIFY_COLLISION,
+            MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED,
+            NAS_REQUEST_REJECTED_BY_NETWORK,
+            RRC_CONNECTION_INVALID_REQUEST,
+            RRC_CONNECTION_TRACKING_AREA_ID_CHANGED,
+            RRC_CONNECTION_RF_UNAVAILABLE,
+            RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE,
+            RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE,
+            RRC_CONNECTION_ABORTED_AFTER_HANDOVER,
+            RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE,
+            RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE,
+            IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER,
+            IMEI_NOT_ACCEPTED,
+            EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED,
+            EPS_SERVICES_NOT_ALLOWED_IN_PLMN,
+            MSC_TEMPORARILY_NOT_REACHABLE,
+            CS_DOMAIN_NOT_AVAILABLE,
+            ESM_FAILURE,
+            MAC_FAILURE,
+            SYNCHRONIZATION_FAILURE,
+            UE_SECURITY_CAPABILITIES_MISMATCH,
+            SECURITY_MODE_REJECTED,
+            UNACCEPTABLE_NON_EPS_AUTHENTICATION,
+            CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED,
+            NO_EPS_BEARER_CONTEXT_ACTIVATED,
+            INVALID_EMM_STATE,
+            NAS_LAYER_FAILURE,
+            MULTIPLE_PDP_CALL_NOT_ALLOWED,
+            EMBMS_NOT_ENABLED,
+            IRAT_HANDOVER_FAILED,
+            EMBMS_REGULAR_DEACTIVATION,
+            TEST_LOOPBACK_REGULAR_DEACTIVATION,
+            LOWER_LAYER_REGISTRATION_FAILURE,
+            DATA_PLAN_EXPIRED,
+            UMTS_HANDOVER_TO_IWLAN,
+            EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY,
+            EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE,
+            EVDO_HDR_CHANGED,
+            EVDO_HDR_EXITED,
+            EVDO_HDR_NO_SESSION,
+            EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL,
+            EVDO_HDR_CONNECTION_SETUP_TIMEOUT,
+            FAILED_TO_ACQUIRE_COLOCATED_HDR,
+            OTASP_COMMIT_IN_PROGRESS,
+            NO_HYBRID_HDR_SERVICE,
+            HDR_NO_LOCK_GRANTED,
+            DBM_OR_SMS_IN_PROGRESS,
+            HDR_FADE,
+            HDR_ACCESS_FAILURE,
+            UNSUPPORTED_1X_PREV,
+            LOCAL_END,
+            NO_SERVICE,
+            FADE,
+            NORMAL_RELEASE,
+            ACCESS_ATTEMPT_ALREADY_IN_PROGRESS,
+            REDIRECTION_OR_HANDOFF_IN_PROGRESS,
+            EMERGENCY_MODE,
+            PHONE_IN_USE,
+            INVALID_MODE,
+            INVALID_SIM_STATE,
+            NO_COLLOCATED_HDR,
+            UE_IS_ENTERING_POWERSAVE_MODE,
+            DUAL_SWITCH,
+            PPP_TIMEOUT,
+            PPP_AUTH_FAILURE,
+            PPP_OPTION_MISMATCH,
+            PPP_PAP_FAILURE,
+            PPP_CHAP_FAILURE,
+            PPP_CLOSE_IN_PROGRESS,
+            LIMITED_TO_IPV4,
+            LIMITED_TO_IPV6,
+            VSNCP_TIMEOUT,
+            VSNCP_GEN_ERROR,
+            VSNCP_APN_UNATHORIZED,
+            VSNCP_PDN_LIMIT_EXCEEDED,
+            VSNCP_NO_PDN_GATEWAY_ADDRESS,
+            VSNCP_PDN_GATEWAY_UNREACHABLE,
+            VSNCP_PDN_GATEWAY_REJECT,
+            VSNCP_INSUFFICIENT_PARAMETERS,
+            VSNCP_RESOURCE_UNAVAILABLE,
+            VSNCP_ADMINISTRATIVELY_PROHIBITED,
+            VSNCP_PDN_ID_IN_USE,
+            VSNCP_SUBSCRIBER_LIMITATION,
+            VSNCP_PDN_EXISTS_FOR_THIS_APN,
+            VSNCP_RECONNECT_NOT_ALLOWED,
+            IPV6_PREFIX_UNAVAILABLE,
+            HANDOFF_PREFERENCE_CHANGED,
             OEM_DCFAILCAUSE_1,
             OEM_DCFAILCAUSE_2,
             OEM_DCFAILCAUSE_3,
@@ -301,6 +1348,7 @@
         sFailCauseMap.put(FILTER_SEMANTIC_ERROR, "FILTER_SEMANTIC_ERROR");
         sFailCauseMap.put(FILTER_SYTAX_ERROR, "FILTER_SYTAX_ERROR");
         sFailCauseMap.put(PDP_WITHOUT_ACTIVE_TFT, "PDP_WITHOUT_ACTIVE_TFT");
+        sFailCauseMap.put(ACTIVATION_REJECTED_BCM_VIOLATION, "ACTIVATION_REJECTED_BCM_VIOLATION");
         sFailCauseMap.put(ONLY_IPV4_ALLOWED, "ONLY_IPV4_ALLOWED");
         sFailCauseMap.put(ONLY_IPV6_ALLOWED, "ONLY_IPV6_ALLOWED");
         sFailCauseMap.put(ONLY_SINGLE_BEARER_ALLOWED, "ONLY_SINGLE_BEARER_ALLOWED");
@@ -308,8 +1356,14 @@
         sFailCauseMap.put(PDN_CONN_DOES_NOT_EXIST, "PDN_CONN_DOES_NOT_EXIST");
         sFailCauseMap.put(MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED,
                 "MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED");
-        sFailCauseMap.put(MAX_ACTIVE_PDP_CONTEXT_REACHED,
-                "MAX_ACTIVE_PDP_CONTEXT_REACHED");
+        sFailCauseMap.put(COLLISION_WITH_NETWORK_INITIATED_REQUEST,
+                "COLLISION_WITH_NETWORK_INITIATED_REQUEST");
+        sFailCauseMap.put(ONLY_IPV4V6_ALLOWED, "ONLY_IPV4V6_ALLOWED");
+        sFailCauseMap.put(ONLY_NON_IP_ALLOWED, "ONLY_NON_IP_ALLOWED");
+        sFailCauseMap.put(UNSUPPORTED_QCI_VALUE, "UNSUPPORTED_QCI_VALUE");
+        sFailCauseMap.put(BEARER_HANDLING_NOT_SUPPORTED, "BEARER_HANDLING_NOT_SUPPORTED");
+        sFailCauseMap.put(ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED,
+                "ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED");
         sFailCauseMap.put(UNSUPPORTED_APN_IN_CURRENT_PLMN,
                 "UNSUPPORTED_APN_IN_CURRENT_PLMN");
         sFailCauseMap.put(INVALID_TRANSACTION_ID, "INVALID_TRANSACTION_ID");
@@ -337,6 +1391,301 @@
                 "EMM_ACCESS_BARRED_INFINITE_RETRY");
         sFailCauseMap.put(AUTH_FAILURE_ON_EMERGENCY_CALL,
                 "AUTH_FAILURE_ON_EMERGENCY_CALL");
+        sFailCauseMap.put(INVALID_DNS_ADDR, "INVALID_DNS_ADDR");
+        sFailCauseMap.put(INVALID_PCSCF_OR_DNS_ADDRESS, "INVALID_PCSCF_OR_DNS_ADDRESS");
+        sFailCauseMap.put(CALL_PREEMPT_BY_EMERGENCY_APN, "CALL_PREEMPT_BY_EMERGENCY_APN");
+        sFailCauseMap.put(UE_INITIATED_DETACH_OR_DISCONNECT, "UE_INITIATED_DETACH_OR_DISCONNECT");
+        sFailCauseMap.put(MIP_FA_REASON_UNSPECIFIED, "MIP_FA_REASON_UNSPECIFIED");
+        sFailCauseMap.put(MIP_FA_ADMIN_PROHIBITED, "MIP_FA_ADMIN_PROHIBITED");
+        sFailCauseMap.put(MIP_FA_INSUFFICIENT_RESOURCES, "MIP_FA_INSUFFICIENT_RESOURCES");
+        sFailCauseMap.put(MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE,
+                "MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE");
+        sFailCauseMap.put(MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE,
+                "MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE");
+        sFailCauseMap.put(MIP_FA_REQUESTED_LIFETIME_TOO_LONG, "MIP_FA_REQUESTED_LIFETIME_TOO_LONG");
+        sFailCauseMap.put(MIP_FA_MALFORMED_REQUEST, "MIP_FA_MALFORMED_REQUEST");
+        sFailCauseMap.put(MIP_FA_MALFORMED_REPLY, "MIP_FA_MALFORMED_REPLY");
+        sFailCauseMap.put(MIP_FA_ENCAPSULATION_UNAVAILABLE, "MIP_FA_ENCAPSULATION_UNAVAILABLE");
+        sFailCauseMap.put(MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE,
+                "MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE");
+        sFailCauseMap.put(MIP_FA_REVERSE_TUNNEL_UNAVAILABLE, "MIP_FA_REVERSE_TUNNEL_UNAVAILABLE");
+        sFailCauseMap.put(MIP_FA_REVERSE_TUNNEL_IS_MANDATORY, "MIP_FA_REVERSE_TUNNEL_IS_MANDATORY");
+        sFailCauseMap.put(MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED,
+                "MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED");
+        sFailCauseMap.put(MIP_FA_MISSING_NAI, "MIP_FA_MISSING_NAI");
+        sFailCauseMap.put(MIP_FA_MISSING_HOME_AGENT, "MIP_FA_MISSING_HOME_AGENT");
+        sFailCauseMap.put(MIP_FA_MISSING_HOME_ADDRESS, "MIP_FA_MISSING_HOME_ADDRESS");
+        sFailCauseMap.put(MIP_FA_UNKNOWN_CHALLENGE, "MIP_FA_UNKNOWN_CHALLENGE");
+        sFailCauseMap.put(MIP_FA_MISSING_CHALLENGE, "MIP_FA_MISSING_CHALLENGE");
+        sFailCauseMap.put(MIP_FA_STALE_CHALLENGE, "MIP_FA_STALE_CHALLENGE");
+        sFailCauseMap.put(MIP_HA_REASON_UNSPECIFIED, "MIP_HA_REASON_UNSPECIFIED");
+        sFailCauseMap.put(MIP_HA_ADMIN_PROHIBITED, "MIP_HA_ADMIN_PROHIBITED");
+        sFailCauseMap.put(MIP_HA_INSUFFICIENT_RESOURCES, "MIP_HA_INSUFFICIENT_RESOURCES");
+        sFailCauseMap.put(MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE,
+                "MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE");
+        sFailCauseMap.put(MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE,
+                "MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE");
+        sFailCauseMap.put(MIP_HA_REGISTRATION_ID_MISMATCH, "MIP_HA_REGISTRATION_ID_MISMATCH");
+        sFailCauseMap.put(MIP_HA_MALFORMED_REQUEST, "MIP_HA_MALFORMED_REQUEST");
+        sFailCauseMap.put(MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS, "MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS");
+        sFailCauseMap.put(MIP_HA_REVERSE_TUNNEL_UNAVAILABLE, "MIP_HA_REVERSE_TUNNEL_UNAVAILABLE");
+        sFailCauseMap.put(MIP_HA_REVERSE_TUNNEL_IS_MANDATORY, "MIP_HA_REVERSE_TUNNEL_IS_MANDATORY");
+        sFailCauseMap.put(MIP_HA_ENCAPSULATION_UNAVAILABLE, "MIP_HA_ENCAPSULATION_UNAVAILABLE");
+        sFailCauseMap.put(CLOSE_IN_PROGRESS, "CLOSE_IN_PROGRESS");
+        sFailCauseMap.put(NETWORK_INITIATED_TERMINATION, "NETWORK_INITIATED_TERMINATION");
+        sFailCauseMap.put(MODEM_APP_PREEMPTED, "MODEM_APP_PREEMPTED");
+        sFailCauseMap.put(PDN_IPV4_CALL_DISALLOWED, "PDN_IPV4_CALL_DISALLOWED");
+        sFailCauseMap.put(PDN_IPV4_CALL_THROTTLED, "PDN_IPV4_CALL_THROTTLED");
+        sFailCauseMap.put(PDN_IPV6_CALL_DISALLOWED, "PDN_IPV6_CALL_DISALLOWED");
+        sFailCauseMap.put(PDN_IPV6_CALL_THROTTLED, "PDN_IPV6_CALL_THROTTLED");
+        sFailCauseMap.put(MODEM_RESTART, "MODEM_RESTART");
+        sFailCauseMap.put(PDP_PPP_NOT_SUPPORTED, "PDP_PPP_NOT_SUPPORTED");
+        sFailCauseMap.put(UNPREFERRED_RAT, "UNPREFERRED_RAT");
+        sFailCauseMap.put(PHYSICAL_LINK_CLOSE_IN_PROGRESS, "PHYSICAL_LINK_CLOSE_IN_PROGRESS");
+        sFailCauseMap.put(APN_PENDING_HANDOVER, "APN_PENDING_HANDOVER");
+        sFailCauseMap.put(PROFILE_BEARER_INCOMPATIBLE, "PROFILE_BEARER_INCOMPATIBLE");
+        sFailCauseMap.put(SIM_CARD_CHANGED, "SIM_CARD_CHANGED");
+        sFailCauseMap.put(LOW_POWER_MODE_OR_POWERING_DOWN, "LOW_POWER_MODE_OR_POWERING_DOWN");
+        sFailCauseMap.put(APN_DISABLED, "APN_DISABLED");
+        sFailCauseMap.put(MAX_PPP_INACTIVITY_TIMER_EXPIRED, "MAX_PPP_INACTIVITY_TIMER_EXPIRED");
+        sFailCauseMap.put(IPV6_ADDRESS_TRANSFER_FAILED, "IPV6_ADDRESS_TRANSFER_FAILED");
+        sFailCauseMap.put(TRAT_SWAP_FAILED, "TRAT_SWAP_FAILED");
+        sFailCauseMap.put(EHRPD_TO_HRPD_FALLBACK, "EHRPD_TO_HRPD_FALLBACK");
+        sFailCauseMap.put(MIP_CONFIG_FAILURE, "MIP_CONFIG_FAILURE");
+        sFailCauseMap.put(PDN_INACTIVITY_TIMER_EXPIRED, "PDN_INACTIVITY_TIMER_EXPIRED");
+        sFailCauseMap.put(MAX_IPV4_CONNECTIONS, "MAX_IPV4_CONNECTIONS");
+        sFailCauseMap.put(MAX_IPV6_CONNECTIONS, "MAX_IPV6_CONNECTIONS");
+        sFailCauseMap.put(APN_MISMATCH, "APN_MISMATCH");
+        sFailCauseMap.put(IP_VERSION_MISMATCH, "IP_VERSION_MISMATCH");
+        sFailCauseMap.put(DUN_CALL_DISALLOWED, "DUN_CALL_DISALLOWED");
+        sFailCauseMap.put(INTERNAL_EPC_NONEPC_TRANSITION, "INTERNAL_EPC_NONEPC_TRANSITION");
+        sFailCauseMap.put(INTERFACE_IN_USE, "INTERFACE_IN_USE");
+        sFailCauseMap.put(APN_DISALLOWED_ON_ROAMING, "APN_DISALLOWED_ON_ROAMING");
+        sFailCauseMap.put(APN_PARAMETERS_CHANGED, "APN_PARAMETERS_CHANGED");
+        sFailCauseMap.put(NULL_APN_DISALLOWED, "NULL_APN_DISALLOWED");
+        sFailCauseMap.put(THERMAL_MITIGATION, "THERMAL_MITIGATION");
+        sFailCauseMap.put(DATA_SETTINGS_DISABLED, "DATA_SETTINGS_DISABLED");
+        sFailCauseMap.put(DATA_ROAMING_SETTINGS_DISABLED, "DATA_ROAMING_SETTINGS_DISABLED");
+        sFailCauseMap.put(DDS_SWITCHED, "DDS_SWITCHED");
+        sFailCauseMap.put(FORBIDDEN_APN_NAME, "FORBIDDEN_APN_NAME");
+        sFailCauseMap.put(DDS_SWITCH_IN_PROGRESS, "DDS_SWITCH_IN_PROGRESS");
+        sFailCauseMap.put(CALL_DISALLOWED_IN_ROAMING, "CALL_DISALLOWED_IN_ROAMING");
+        sFailCauseMap.put(NON_IP_NOT_SUPPORTED, "NON_IP_NOT_SUPPORTED");
+        sFailCauseMap.put(PDN_NON_IP_CALL_THROTTLED, "PDN_NON_IP_CALL_THROTTLED");
+        sFailCauseMap.put(PDN_NON_IP_CALL_DISALLOWED, "PDN_NON_IP_CALL_DISALLOWED");
+        sFailCauseMap.put(CDMA_LOCK, "CDMA_LOCK");
+        sFailCauseMap.put(CDMA_INTERCEPT, "CDMA_INTERCEPT");
+        sFailCauseMap.put(CDMA_REORDER, "CDMA_REORDER");
+        sFailCauseMap.put(CDMA_RELEASE_DUE_TO_SO_REJECTION, "CDMA_RELEASE_DUE_TO_SO_REJECTION");
+        sFailCauseMap.put(CDMA_INCOMING_CALL, "CDMA_INCOMING_CALL");
+        sFailCauseMap.put(CDMA_ALERT_STOP, "CDMA_ALERT_STOP");
+        sFailCauseMap.put(CHANNEL_ACQUISITION_FAILURE, "CHANNEL_ACQUISITION_FAILURE");
+        sFailCauseMap.put(MAX_ACCESS_PROBE, "MAX_ACCESS_PROBE");
+        sFailCauseMap.put(CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
+                "CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION");
+        sFailCauseMap.put(NO_RESPONSE_FROM_BASE_STATION, "NO_RESPONSE_FROM_BASE_STATION");
+        sFailCauseMap.put(REJECTED_BY_BASE_STATION, "REJECTED_BY_BASE_STATION");
+        sFailCauseMap.put(CONCURRENT_SERVICES_INCOMPATIBLE, "CONCURRENT_SERVICES_INCOMPATIBLE");
+        sFailCauseMap.put(NO_CDMA_SERVICE, "NO_CDMA_SERVICE");
+        sFailCauseMap.put(RUIM_NOT_PRESENT, "RUIM_NOT_PRESENT");
+        sFailCauseMap.put(CDMA_RETRY_ORDER, "CDMA_RETRY_ORDER");
+        sFailCauseMap.put(ACCESS_BLOCK, "ACCESS_BLOCK");
+        sFailCauseMap.put(ACCESS_BLOCK_ALL, "ACCESS_BLOCK_ALL");
+        sFailCauseMap.put(IS707B_MAX_ACCESS_PROBES, "IS707B_MAX_ACCESS_PROBES");
+        sFailCauseMap.put(THERMAL_EMERGENCY, "THERMAL_EMERGENCY");
+        sFailCauseMap.put(CONCURRENT_SERVICES_NOT_ALLOWED, "CONCURRENT_SERVICES_NOT_ALLOWED");
+        sFailCauseMap.put(INCOMING_CALL_REJECTED, "INCOMING_CALL_REJECTED");
+        sFailCauseMap.put(NO_SERVICE_ON_GATEWAY, "NO_SERVICE_ON_GATEWAY");
+        sFailCauseMap.put(NO_GPRS_CONTEXT, "NO_GPRS_CONTEXT");
+        sFailCauseMap.put(ILLEGAL_MS, "ILLEGAL_MS");
+        sFailCauseMap.put(ILLEGAL_ME, "ILLEGAL_ME");
+        sFailCauseMap.put(GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED,
+                "GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED");
+        sFailCauseMap.put(GPRS_SERVICES_NOT_ALLOWED, "GPRS_SERVICES_NOT_ALLOWED");
+        sFailCauseMap.put(MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK,
+                "MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK");
+        sFailCauseMap.put(IMPLICITLY_DETACHED, "IMPLICITLY_DETACHED");
+        sFailCauseMap.put(PLMN_NOT_ALLOWED, "PLMN_NOT_ALLOWED");
+        sFailCauseMap.put(LOCATION_AREA_NOT_ALLOWED, "LOCATION_AREA_NOT_ALLOWED");
+        sFailCauseMap.put(GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN,
+                "GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN");
+        sFailCauseMap.put(PDP_DUPLICATE, "PDP_DUPLICATE");
+        sFailCauseMap.put(UE_RAT_CHANGE, "UE_RAT_CHANGE");
+        sFailCauseMap.put(CONGESTION, "CONGESTION");
+        sFailCauseMap.put(NO_PDP_CONTEXT_ACTIVATED, "NO_PDP_CONTEXT_ACTIVATED");
+        sFailCauseMap.put(ACCESS_CLASS_DSAC_REJECTION, "ACCESS_CLASS_DSAC_REJECTION");
+        sFailCauseMap.put(PDP_ACTIVATE_MAX_RETRY_FAILED, "PDP_ACTIVATE_MAX_RETRY_FAILED");
+        sFailCauseMap.put(RADIO_ACCESS_BEARER_FAILURE, "RADIO_ACCESS_BEARER_FAILURE");
+        sFailCauseMap.put(ESM_UNKNOWN_EPS_BEARER_CONTEXT, "ESM_UNKNOWN_EPS_BEARER_CONTEXT");
+        sFailCauseMap.put(DRB_RELEASED_BY_RRC, "DRB_RELEASED_BY_RRC");
+        sFailCauseMap.put(CONNECTION_RELEASED, "CONNECTION_RELEASED");
+        sFailCauseMap.put(EMM_DETACHED, "EMM_DETACHED");
+        sFailCauseMap.put(EMM_ATTACH_FAILED, "EMM_ATTACH_FAILED");
+        sFailCauseMap.put(EMM_ATTACH_STARTED, "EMM_ATTACH_STARTED");
+        sFailCauseMap.put(LTE_NAS_SERVICE_REQUEST_FAILED, "LTE_NAS_SERVICE_REQUEST_FAILED");
+        sFailCauseMap.put(DUPLICATE_BEARER_ID, "DUPLICATE_BEARER_ID");
+        sFailCauseMap.put(ESM_COLLISION_SCENARIOS, "ESM_COLLISION_SCENARIOS");
+        sFailCauseMap.put(ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK,
+                "ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK");
+        sFailCauseMap.put(ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER,
+                "ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER");
+        sFailCauseMap.put(ESM_BAD_OTA_MESSAGE, "ESM_BAD_OTA_MESSAGE");
+        sFailCauseMap.put(ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL,
+                "ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL");
+        sFailCauseMap.put(ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT,
+                "ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT");
+        sFailCauseMap.put(DS_EXPLICIT_DEACTIVATION, "DS_EXPLICIT_DEACTIVATION");
+        sFailCauseMap.put(ESM_LOCAL_CAUSE_NONE, "ESM_LOCAL_CAUSE_NONE");
+        sFailCauseMap.put(LTE_THROTTLING_NOT_REQUIRED, "LTE_THROTTLING_NOT_REQUIRED");
+        sFailCauseMap.put(ACCESS_CONTROL_LIST_CHECK_FAILURE,
+                "ACCESS_CONTROL_LIST_CHECK_FAILURE");
+        sFailCauseMap.put(SERVICE_NOT_ALLOWED_ON_PLMN, "SERVICE_NOT_ALLOWED_ON_PLMN");
+        sFailCauseMap.put(EMM_T3417_EXPIRED, "EMM_T3417_EXPIRED");
+        sFailCauseMap.put(EMM_T3417_EXT_EXPIRED, "EMM_T3417_EXT_EXPIRED");
+        sFailCauseMap.put(RRC_UPLINK_DATA_TRANSMISSION_FAILURE,
+                "RRC_UPLINK_DATA_TRANSMISSION_FAILURE");
+        sFailCauseMap.put(RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER,
+                "RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER");
+        sFailCauseMap.put(RRC_UPLINK_CONNECTION_RELEASE, "RRC_UPLINK_CONNECTION_RELEASE");
+        sFailCauseMap.put(RRC_UPLINK_RADIO_LINK_FAILURE, "RRC_UPLINK_RADIO_LINK_FAILURE");
+        sFailCauseMap.put(RRC_UPLINK_ERROR_REQUEST_FROM_NAS, "RRC_UPLINK_ERROR_REQUEST_FROM_NAS");
+        sFailCauseMap.put(RRC_CONNECTION_ACCESS_STRATUM_FAILURE,
+                "RRC_CONNECTION_ACCESS_STRATUM_FAILURE");
+        sFailCauseMap.put(RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS,
+                "RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS");
+        sFailCauseMap.put(RRC_CONNECTION_ACCESS_BARRED, "RRC_CONNECTION_ACCESS_BARRED");
+        sFailCauseMap.put(RRC_CONNECTION_CELL_RESELECTION, "RRC_CONNECTION_CELL_RESELECTION");
+        sFailCauseMap.put(RRC_CONNECTION_CONFIG_FAILURE, "RRC_CONNECTION_CONFIG_FAILURE");
+        sFailCauseMap.put(RRC_CONNECTION_TIMER_EXPIRED, "RRC_CONNECTION_TIMER_EXPIRED");
+        sFailCauseMap.put(RRC_CONNECTION_LINK_FAILURE, "RRC_CONNECTION_LINK_FAILURE");
+        sFailCauseMap.put(RRC_CONNECTION_CELL_NOT_CAMPED, "RRC_CONNECTION_CELL_NOT_CAMPED");
+        sFailCauseMap.put(RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE,
+                "RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE");
+        sFailCauseMap.put(RRC_CONNECTION_REJECT_BY_NETWORK, "RRC_CONNECTION_REJECT_BY_NETWORK");
+        sFailCauseMap.put(RRC_CONNECTION_NORMAL_RELEASE, "RRC_CONNECTION_NORMAL_RELEASE");
+        sFailCauseMap.put(RRC_CONNECTION_RADIO_LINK_FAILURE, "RRC_CONNECTION_RADIO_LINK_FAILURE");
+        sFailCauseMap.put(RRC_CONNECTION_REESTABLISHMENT_FAILURE,
+                "RRC_CONNECTION_REESTABLISHMENT_FAILURE");
+        sFailCauseMap.put(RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER,
+                "RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER");
+        sFailCauseMap.put(RRC_CONNECTION_ABORT_REQUEST, "RRC_CONNECTION_ABORT_REQUEST");
+        sFailCauseMap.put(RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR,
+                "RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR");
+        sFailCauseMap.put(NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH,
+                "NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH");
+        sFailCauseMap.put(NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH,
+                "NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH");
+        sFailCauseMap.put(ESM_PROCEDURE_TIME_OUT, "ESM_PROCEDURE_TIME_OUT");
+        sFailCauseMap.put(INVALID_CONNECTION_ID, "INVALID_CONNECTION_ID");
+        sFailCauseMap.put(MAXIMIUM_NSAPIS_EXCEEDED, "MAXIMIUM_NSAPIS_EXCEEDED");
+        sFailCauseMap.put(INVALID_PRIMARY_NSAPI, "INVALID_PRIMARY_NSAPI");
+        sFailCauseMap.put(CANNOT_ENCODE_OTA_MESSAGE, "CANNOT_ENCODE_OTA_MESSAGE");
+        sFailCauseMap.put(RADIO_ACCESS_BEARER_SETUP_FAILURE, "RADIO_ACCESS_BEARER_SETUP_FAILURE");
+        sFailCauseMap.put(PDP_ESTABLISH_TIMEOUT_EXPIRED, "PDP_ESTABLISH_TIMEOUT_EXPIRED");
+        sFailCauseMap.put(PDP_MODIFY_TIMEOUT_EXPIRED, "PDP_MODIFY_TIMEOUT_EXPIRED");
+        sFailCauseMap.put(PDP_INACTIVE_TIMEOUT_EXPIRED, "PDP_INACTIVE_TIMEOUT_EXPIRED");
+        sFailCauseMap.put(PDP_LOWERLAYER_ERROR, "PDP_LOWERLAYER_ERROR");
+        sFailCauseMap.put(PDP_MODIFY_COLLISION, "PDP_MODIFY_COLLISION");
+        sFailCauseMap.put(MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED,
+                "MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED");
+        sFailCauseMap.put(NAS_REQUEST_REJECTED_BY_NETWORK, "NAS_REQUEST_REJECTED_BY_NETWORK");
+        sFailCauseMap.put(RRC_CONNECTION_INVALID_REQUEST, "RRC_CONNECTION_INVALID_REQUEST");
+        sFailCauseMap.put(RRC_CONNECTION_TRACKING_AREA_ID_CHANGED,
+                "RRC_CONNECTION_TRACKING_AREA_ID_CHANGED");
+        sFailCauseMap.put(RRC_CONNECTION_RF_UNAVAILABLE, "RRC_CONNECTION_RF_UNAVAILABLE");
+        sFailCauseMap.put(RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE,
+                "RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE");
+        sFailCauseMap.put(RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE,
+                "RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE");
+        sFailCauseMap.put(RRC_CONNECTION_ABORTED_AFTER_HANDOVER,
+                "RRC_CONNECTION_ABORTED_AFTER_HANDOVER");
+        sFailCauseMap.put(RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE,
+                "RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE");
+        sFailCauseMap.put(RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE,
+                "RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE");
+        sFailCauseMap.put(IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER,
+                "IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER");
+        sFailCauseMap.put(IMEI_NOT_ACCEPTED, "IMEI_NOT_ACCEPTED");
+        sFailCauseMap.put(EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED,
+                "EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED");
+        sFailCauseMap.put(EPS_SERVICES_NOT_ALLOWED_IN_PLMN, "EPS_SERVICES_NOT_ALLOWED_IN_PLMN");
+        sFailCauseMap.put(MSC_TEMPORARILY_NOT_REACHABLE, "MSC_TEMPORARILY_NOT_REACHABLE");
+        sFailCauseMap.put(CS_DOMAIN_NOT_AVAILABLE, "CS_DOMAIN_NOT_AVAILABLE");
+        sFailCauseMap.put(ESM_FAILURE, "ESM_FAILURE");
+        sFailCauseMap.put(MAC_FAILURE, "MAC_FAILURE");
+        sFailCauseMap.put(SYNCHRONIZATION_FAILURE, "SYNCHRONIZATION_FAILURE");
+        sFailCauseMap.put(UE_SECURITY_CAPABILITIES_MISMATCH, "UE_SECURITY_CAPABILITIES_MISMATCH");
+        sFailCauseMap.put(SECURITY_MODE_REJECTED, "SECURITY_MODE_REJECTED");
+        sFailCauseMap.put(UNACCEPTABLE_NON_EPS_AUTHENTICATION,
+                "UNACCEPTABLE_NON_EPS_AUTHENTICATION");
+        sFailCauseMap.put(CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED,
+                "CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED");
+        sFailCauseMap.put(NO_EPS_BEARER_CONTEXT_ACTIVATED, "NO_EPS_BEARER_CONTEXT_ACTIVATED");
+        sFailCauseMap.put(INVALID_EMM_STATE, "INVALID_EMM_STATE");
+        sFailCauseMap.put(NAS_LAYER_FAILURE, "NAS_LAYER_FAILURE");
+        sFailCauseMap.put(MULTIPLE_PDP_CALL_NOT_ALLOWED, "MULTIPLE_PDP_CALL_NOT_ALLOWED");
+        sFailCauseMap.put(EMBMS_NOT_ENABLED, "EMBMS_NOT_ENABLED");
+        sFailCauseMap.put(IRAT_HANDOVER_FAILED, "IRAT_HANDOVER_FAILED");
+        sFailCauseMap.put(EMBMS_REGULAR_DEACTIVATION, "EMBMS_REGULAR_DEACTIVATION");
+        sFailCauseMap.put(TEST_LOOPBACK_REGULAR_DEACTIVATION, "TEST_LOOPBACK_REGULAR_DEACTIVATION");
+        sFailCauseMap.put(LOWER_LAYER_REGISTRATION_FAILURE, "LOWER_LAYER_REGISTRATION_FAILURE");
+        sFailCauseMap.put(DATA_PLAN_EXPIRED, "DATA_PLAN_EXPIRED");
+        sFailCauseMap.put(UMTS_HANDOVER_TO_IWLAN, "UMTS_HANDOVER_TO_IWLAN");
+        sFailCauseMap.put(EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY,
+                "EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY");
+        sFailCauseMap.put(EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE,
+                "EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE");
+        sFailCauseMap.put(EVDO_HDR_CHANGED, "EVDO_HDR_CHANGED");
+        sFailCauseMap.put(EVDO_HDR_EXITED, "EVDO_HDR_EXITED");
+        sFailCauseMap.put(EVDO_HDR_NO_SESSION, "EVDO_HDR_NO_SESSION");
+        sFailCauseMap.put(EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL,
+                "EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL");
+        sFailCauseMap.put(EVDO_HDR_CONNECTION_SETUP_TIMEOUT, "EVDO_HDR_CONNECTION_SETUP_TIMEOUT");
+        sFailCauseMap.put(FAILED_TO_ACQUIRE_COLOCATED_HDR, "FAILED_TO_ACQUIRE_COLOCATED_HDR");
+        sFailCauseMap.put(OTASP_COMMIT_IN_PROGRESS, "OTASP_COMMIT_IN_PROGRESS");
+        sFailCauseMap.put(NO_HYBRID_HDR_SERVICE, "NO_HYBRID_HDR_SERVICE");
+        sFailCauseMap.put(HDR_NO_LOCK_GRANTED, "HDR_NO_LOCK_GRANTED");
+        sFailCauseMap.put(DBM_OR_SMS_IN_PROGRESS, "DBM_OR_SMS_IN_PROGRESS");
+        sFailCauseMap.put(HDR_FADE, "HDR_FADE");
+        sFailCauseMap.put(HDR_ACCESS_FAILURE, "HDR_ACCESS_FAILURE");
+        sFailCauseMap.put(UNSUPPORTED_1X_PREV, "UNSUPPORTED_1X_PREV");
+        sFailCauseMap.put(LOCAL_END, "LOCAL_END");
+        sFailCauseMap.put(NO_SERVICE, "NO_SERVICE");
+        sFailCauseMap.put(FADE, "FADE");
+        sFailCauseMap.put(NORMAL_RELEASE, "NORMAL_RELEASE");
+        sFailCauseMap.put(ACCESS_ATTEMPT_ALREADY_IN_PROGRESS, "ACCESS_ATTEMPT_ALREADY_IN_PROGRESS");
+        sFailCauseMap.put(REDIRECTION_OR_HANDOFF_IN_PROGRESS, "REDIRECTION_OR_HANDOFF_IN_PROGRESS");
+        sFailCauseMap.put(EMERGENCY_MODE, "EMERGENCY_MODE");
+        sFailCauseMap.put(PHONE_IN_USE, "PHONE_IN_USE");
+        sFailCauseMap.put(INVALID_MODE, "INVALID_MODE");
+        sFailCauseMap.put(INVALID_SIM_STATE, "INVALID_SIM_STATE");
+        sFailCauseMap.put(NO_COLLOCATED_HDR, "NO_COLLOCATED_HDR");
+        sFailCauseMap.put(UE_IS_ENTERING_POWERSAVE_MODE, "UE_IS_ENTERING_POWERSAVE_MODE");
+        sFailCauseMap.put(DUAL_SWITCH, "DUAL_SWITCH");
+        sFailCauseMap.put(PPP_TIMEOUT, "PPP_TIMEOUT");
+        sFailCauseMap.put(PPP_AUTH_FAILURE, "PPP_AUTH_FAILURE");
+        sFailCauseMap.put(PPP_OPTION_MISMATCH, "PPP_OPTION_MISMATCH");
+        sFailCauseMap.put(PPP_PAP_FAILURE, "PPP_PAP_FAILURE");
+        sFailCauseMap.put(PPP_CHAP_FAILURE, "PPP_CHAP_FAILURE");
+        sFailCauseMap.put(PPP_CLOSE_IN_PROGRESS, "PPP_CLOSE_IN_PROGRESS");
+        sFailCauseMap.put(LIMITED_TO_IPV4, "LIMITED_TO_IPV4");
+        sFailCauseMap.put(LIMITED_TO_IPV6, "LIMITED_TO_IPV6");
+        sFailCauseMap.put(VSNCP_TIMEOUT, "VSNCP_TIMEOUT");
+        sFailCauseMap.put(VSNCP_GEN_ERROR, "VSNCP_GEN_ERROR");
+        sFailCauseMap.put(VSNCP_APN_UNATHORIZED, "VSNCP_APN_UNATHORIZED");
+        sFailCauseMap.put(VSNCP_PDN_LIMIT_EXCEEDED, "VSNCP_PDN_LIMIT_EXCEEDED");
+        sFailCauseMap.put(VSNCP_NO_PDN_GATEWAY_ADDRESS, "VSNCP_NO_PDN_GATEWAY_ADDRESS");
+        sFailCauseMap.put(VSNCP_PDN_GATEWAY_UNREACHABLE, "VSNCP_PDN_GATEWAY_UNREACHABLE");
+        sFailCauseMap.put(VSNCP_PDN_GATEWAY_REJECT, "VSNCP_PDN_GATEWAY_REJECT");
+        sFailCauseMap.put(VSNCP_INSUFFICIENT_PARAMETERS, "VSNCP_INSUFFICIENT_PARAMETERS");
+        sFailCauseMap.put(VSNCP_RESOURCE_UNAVAILABLE, "VSNCP_RESOURCE_UNAVAILABLE");
+        sFailCauseMap.put(VSNCP_ADMINISTRATIVELY_PROHIBITED, "VSNCP_ADMINISTRATIVELY_PROHIBITED");
+        sFailCauseMap.put(VSNCP_PDN_ID_IN_USE, "VSNCP_PDN_ID_IN_USE");
+        sFailCauseMap.put(VSNCP_SUBSCRIBER_LIMITATION, "VSNCP_SUBSCRIBER_LIMITATION");
+        sFailCauseMap.put(VSNCP_PDN_EXISTS_FOR_THIS_APN, "VSNCP_PDN_EXISTS_FOR_THIS_APN");
+        sFailCauseMap.put(VSNCP_RECONNECT_NOT_ALLOWED, "VSNCP_RECONNECT_NOT_ALLOWED");
+        sFailCauseMap.put(IPV6_PREFIX_UNAVAILABLE, "IPV6_PREFIX_UNAVAILABLE");
+        sFailCauseMap.put(HANDOFF_PREFERENCE_CHANGED, "HANDOFF_PREFERENCE_CHANGED");
         sFailCauseMap.put(OEM_DCFAILCAUSE_1, "OEM_DCFAILCAUSE_1");
         sFailCauseMap.put(OEM_DCFAILCAUSE_2, "OEM_DCFAILCAUSE_2");
         sFailCauseMap.put(OEM_DCFAILCAUSE_3, "OEM_DCFAILCAUSE_3");
@@ -369,6 +1718,9 @@
         sFailCauseMap.put(RESET_BY_FRAMEWORK, "RESET_BY_FRAMEWORK");
     }
 
+    private DataFailCause() {
+    }
+
     /**
      * Map of subId -> set of data call setup permanent failure for the carrier.
      */
@@ -382,6 +1734,8 @@
      * @param cause data disconnect cause
      * @param subId subscription index
      * @return true if the fail cause code needs platform to trigger a modem restart.
+     *
+     * @hide
      */
     public static boolean isRadioRestartFailure(@NonNull Context context, @FailCause int cause,
                                                 int subId) {
@@ -410,6 +1764,7 @@
         return false;
     }
 
+    /** @hide */
     public static boolean isPermanentFailure(@NonNull Context context, @FailCause int failCause,
                                              int subId) {
         synchronized (sPermanentFailureCache) {
@@ -469,6 +1824,7 @@
         }
     }
 
+    /** @hide */
     public static boolean isEventLoggable(@FailCause int dataFailCause) {
         return (dataFailCause == OPERATOR_BARRED) || (dataFailCause == INSUFFICIENT_RESOURCES)
                 || (dataFailCause == UNKNOWN_PDP_ADDRESS_TYPE)
@@ -488,11 +1844,13 @@
                 || (dataFailCause == UNACCEPTABLE_NETWORK_PARAMETER);
     }
 
+    /** @hide */
     public static String toString(@FailCause int dataFailCause) {
         int cause = getFailCause(dataFailCause);
         return (cause == UNKNOWN) ? "UNKNOWN(" + dataFailCause + ")" : sFailCauseMap.get(cause);
     }
 
+    /** @hide */
     public static int getFailCause(@FailCause int failCause) {
         if (sFailCauseMap.containsKey(failCause)) {
             return failCause;
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationStates.java b/telephony/java/android/telephony/DataSpecificRegistrationStates.java
index 5d809d0..d6a8065 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationStates.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationStates.java
@@ -44,13 +44,19 @@
      */
     public final boolean isEnDcAvailable;
 
+    /**
+     * Provides network support info for LTE VoPS and LTE Emergency bearer support
+     */
+    public final LteVopsSupportInfo lteVopsSupportInfo;
+
     DataSpecificRegistrationStates(
             int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable,
-            boolean isEnDcAvailable) {
+            boolean isEnDcAvailable, LteVopsSupportInfo lteVops) {
         this.maxDataCalls = maxDataCalls;
         this.isDcNrRestricted = isDcNrRestricted;
         this.isNrAvailable = isNrAvailable;
         this.isEnDcAvailable = isEnDcAvailable;
+        this.lteVopsSupportInfo = lteVops;
     }
 
     private DataSpecificRegistrationStates(Parcel source) {
@@ -58,6 +64,7 @@
         isDcNrRestricted = source.readBoolean();
         isNrAvailable = source.readBoolean();
         isEnDcAvailable = source.readBoolean();
+        lteVopsSupportInfo = LteVopsSupportInfo.CREATOR.createFromParcel(source);
     }
 
     @Override
@@ -66,6 +73,7 @@
         dest.writeBoolean(isDcNrRestricted);
         dest.writeBoolean(isNrAvailable);
         dest.writeBoolean(isEnDcAvailable);
+        lteVopsSupportInfo.writeToParcel(dest, flags);
     }
 
     @Override
@@ -81,13 +89,15 @@
                 .append(" isDcNrRestricted = " + isDcNrRestricted)
                 .append(" isNrAvailable = " + isNrAvailable)
                 .append(" isEnDcAvailable = " + isEnDcAvailable)
+                .append(lteVopsSupportInfo.toString())
                 .append(" }")
                 .toString();
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable);
+        return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable,
+            lteVopsSupportInfo);
     }
 
     @Override
@@ -100,7 +110,8 @@
         return this.maxDataCalls == other.maxDataCalls
                 && this.isDcNrRestricted == other.isDcNrRestricted
                 && this.isNrAvailable == other.isNrAvailable
-                && this.isEnDcAvailable == other.isEnDcAvailable;
+                && this.isEnDcAvailable == other.isEnDcAvailable
+                && this.lteVopsSupportInfo.equals(other.lteVopsSupportInfo);
     }
 
     public static final Parcelable.Creator<DataSpecificRegistrationStates> CREATOR =
@@ -115,4 +126,4 @@
                     return new DataSpecificRegistrationStates[size];
                 }
             };
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/ICellInfoCallback.aidl b/telephony/java/android/telephony/ICellInfoCallback.aidl
index 7fb62682..ee3c1b1 100644
--- a/telephony/java/android/telephony/ICellInfoCallback.aidl
+++ b/telephony/java/android/telephony/ICellInfoCallback.aidl
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.os.ParcelableException;
 import android.telephony.CellInfo;
 
 import java.util.List;
@@ -27,4 +28,5 @@
 oneway interface ICellInfoCallback
 {
     void onCellInfo(in List<CellInfo> state);
+    void onError(in int errorCode, in ParcelableException detail);
 }
diff --git a/telephony/java/android/telephony/LteVopsSupportInfo.aidl b/telephony/java/android/telephony/LteVopsSupportInfo.aidl
new file mode 100644
index 0000000..5984598
--- /dev/null
+++ b/telephony/java/android/telephony/LteVopsSupportInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable LteVopsSupportInfo;
diff --git a/telephony/java/android/telephony/LteVopsSupportInfo.java b/telephony/java/android/telephony/LteVopsSupportInfo.java
new file mode 100644
index 0000000..0ae85c0
--- /dev/null
+++ b/telephony/java/android/telephony/LteVopsSupportInfo.java
@@ -0,0 +1,137 @@
+/*
+ * 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.IntDef;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Class stores information related to LTE network VoPS support
+ * @hide
+ */
+@SystemApi
+public final class LteVopsSupportInfo implements Parcelable {
+
+    /**@hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+            value = {LTE_STATUS_NOT_AVAILABLE, LTE_STATUS_SUPPORTED,
+                    LTE_STATUS_NOT_SUPPORTED}, prefix = "LTE_STATUS_")
+    public @interface LteVopsStatus {}
+    /**
+     * Indicates information not available from modem.
+     */
+    public static final int LTE_STATUS_NOT_AVAILABLE = 1;
+
+    /**
+     * Indicates network support the feature.
+     */
+    public static final int LTE_STATUS_SUPPORTED = 2;
+
+    /**
+     * Indicates network does not support the feature.
+     */
+    public static final int LTE_STATUS_NOT_SUPPORTED = 3;
+
+    @LteVopsStatus
+    private final int mVopsSupport;
+    @LteVopsStatus
+    private final int mEmcBearerSupport;
+
+    public LteVopsSupportInfo(@LteVopsStatus int vops, @LteVopsStatus int emergency) {
+        mVopsSupport = vops;
+        mEmcBearerSupport = emergency;
+    }
+
+    /**
+     * Provides the LTE VoPS support capability as described in:
+     * 3GPP 24.301 EPS network feature support -> IMS VoPS
+     */
+    public @LteVopsStatus int getVopsSupport() {
+        return mVopsSupport;
+    }
+
+    /**
+     * Provides the LTE Emergency bearer support capability as described in:
+     *    3GPP 24.301 EPS network feature support -> EMC BS
+     *    25.331 LTE RRC SIB1 : ims-EmergencySupport-r9
+     */
+    public @LteVopsStatus int getEmcBearerSupport() {
+        return mEmcBearerSupport;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mVopsSupport);
+        out.writeInt(mEmcBearerSupport);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof LteVopsSupportInfo)) {
+            return false;
+        }
+        if (this == o) return true;
+        LteVopsSupportInfo other = (LteVopsSupportInfo) o;
+        return mVopsSupport == other.mVopsSupport
+            && mEmcBearerSupport == other.mEmcBearerSupport;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mVopsSupport, mEmcBearerSupport);
+    }
+
+    /**
+     * @return string representation.
+     */
+    @Override
+    public String toString() {
+        return ("LteVopsSupportInfo : "
+                + " mVopsSupport = " + mVopsSupport
+                + " mEmcBearerSupport = " + mEmcBearerSupport);
+    }
+
+    public static final Creator<LteVopsSupportInfo> CREATOR =
+            new Creator<LteVopsSupportInfo>() {
+        @Override
+        public LteVopsSupportInfo createFromParcel(Parcel in) {
+            return new LteVopsSupportInfo(in);
+        }
+
+        @Override
+        public LteVopsSupportInfo[] newArray(int size) {
+            return new LteVopsSupportInfo[size];
+        }
+    };
+
+    private LteVopsSupportInfo(Parcel in) {
+        mVopsSupport = in.readInt();
+        mEmcBearerSupport = in.readInt();
+    }
+}
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java
index b00665e..ceb76b5 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -219,12 +219,13 @@
     public NetworkRegistrationState(int domain, int transportType, int regState,
             int accessNetworkTechnology, int rejectCause, boolean emergencyOnly,
             int[] availableServices, @Nullable CellIdentity cellIdentity, int maxDataCalls,
-            boolean isDcNrRestricted, boolean isNrAvailable, boolean isEndcAvailable) {
+            boolean isDcNrRestricted, boolean isNrAvailable, boolean isEndcAvailable,
+            LteVopsSupportInfo lteVopsSupportInfo) {
         this(domain, transportType, regState, accessNetworkTechnology, rejectCause, emergencyOnly,
                 availableServices, cellIdentity);
 
         mDataSpecificStates = new DataSpecificRegistrationStates(
-                maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable);
+                maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo);
         updateNrStatus(mDataSpecificStates);
     }
 
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 9317aa7..9fee593 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -184,14 +184,17 @@
     public static final int LISTEN_PRECISE_CALL_STATE                       = 0x00000800;
 
     /**
-     * Listen for precise changes and fails on the data connection (cellular).
+     * Listen for {@link PreciseDataConnectionState} on the data connection (cellular).
+     *
      * {@more}
      * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
      * READ_PRECISE_PHONE_STATE}
      *
      * @see #onPreciseDataConnectionStateChanged
+     *
      * @hide
      */
+    @SystemApi
     public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE            = 0x00001000;
 
     /**
@@ -293,7 +296,7 @@
 
     /**
      *  Listen for changes to preferred data subId.
-     *  See {@link SubscriptionManager#setPreferredData(int)}
+     *  See {@link SubscriptionManager#setPreferredDataSubId(int)}
      *  for more details.
      *
      *  @see #onPreferredDataSubIdChanged
@@ -332,6 +335,18 @@
     @SystemApi
     public static final int LISTEN_CALL_DISCONNECT_CAUSES                  = 0x02000000;
 
+    /**
+     * Listen for changes to the call attributes of a currently active call.
+     * {@more}
+     * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+     * READ_PRECISE_PHONE_STATE}
+     *
+     * @see #onCallAttributesChanged
+     * @hide
+     */
+    @SystemApi
+    public static final int LISTEN_CALL_ATTRIBUTES_CHANGED                 = 0x04000000;
+
     /*
      * Subscription used to listen to the phone state changes
      * @hide
@@ -564,10 +579,11 @@
 
     /**
      * Callback invoked when data connection state changes with precise information.
+     * @param dataConnectionState {@link PreciseDataConnectionState}
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public void onPreciseDataConnectionStateChanged(
             PreciseDataConnectionState dataConnectionState) {
         // default implementation empty
@@ -679,6 +695,17 @@
     }
 
     /**
+     * Callback invoked when the call attributes changes. Requires
+     * the READ_PRIVILEGED_PHONE_STATE permission.
+     * @param callAttributes the call attributes
+     * @hide
+     */
+    @SystemApi
+    public void onCallAttributesChanged(CallAttributes callAttributes) {
+        // default implementation empty
+    }
+
+    /**
      * Callback invoked when modem radio power state changes. Requires
      * the READ_PRIVILEGED_PHONE_STATE permission.
      * @param state the modem radio power state
@@ -778,9 +805,11 @@
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
 
-            Binder.withCleanCallingIdentity(
-                    () -> mExecutor.execute(
-                            () -> psl.onDataConnectionStateChanged(state, networkType)));
+            Binder.withCleanCallingIdentity(() -> mExecutor.execute(
+                    () -> {
+                        psl.onDataConnectionStateChanged(state, networkType);
+                        psl.onDataConnectionStateChanged(state);
+                    }));
         }
 
         public void onDataActivity(int direction) {
@@ -937,6 +966,14 @@
                     () -> mExecutor.execute(() -> psl.onRadioPowerStateChanged(state)));
         }
 
+        public void onCallAttributesChanged(CallAttributes callAttributes) {
+            PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
+            if (psl == null) return;
+
+            Binder.withCleanCallingIdentity(
+                    () -> mExecutor.execute(() -> psl.onCallAttributesChanged(callAttributes)));
+        }
+
         public void onPreferredDataSubIdChanged(int subId) {
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index b258f52..57a1826 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -16,11 +16,14 @@
 
 package android.telephony;
 
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
+import android.net.LinkProperties;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.TelephonyManager;
-import android.net.LinkProperties;
+import android.telephony.data.ApnSetting;
+
+import java.util.Objects;
 
 /**
  * Contains precise data connection state.
@@ -30,24 +33,23 @@
  * <ul>
  *   <li>Data connection state.
  *   <li>Network type of the connection.
- *   <li>APN type.
+ *   <li>APN types.
  *   <li>APN.
- *   <li>Data connection change reason.
  *   <li>The properties of the network link.
  *   <li>Data connection fail cause.
  * </ul>
  *
  * @hide
  */
-public class PreciseDataConnectionState implements Parcelable {
+@SystemApi
+public final class PreciseDataConnectionState implements Parcelable {
 
-    private int mState = TelephonyManager.DATA_UNKNOWN;
-    private int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-    private String mAPNType = "";
+    private @TelephonyManager.DataState int mState = TelephonyManager.DATA_UNKNOWN;
+    private @TelephonyManager.NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+    private @DataFailCause.FailCause int mFailCause = DataFailCause.NONE;
+    private @ApnSetting.ApnType int mAPNTypes = ApnSetting.TYPE_NONE;
     private String mAPN = "";
-    private String mReason = "";
     private LinkProperties mLinkProperties = null;
-    private String mFailCause = "";
 
     /**
      * Constructor
@@ -55,14 +57,15 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public PreciseDataConnectionState(int state, int networkType,
-            String apnType, String apn, String reason,
-            LinkProperties linkProperties, String failCause) {
+    public PreciseDataConnectionState(@TelephonyManager.DataState int state,
+                                      @TelephonyManager.NetworkType int networkType,
+                                      @ApnSetting.ApnType int apnTypes, String apn,
+                                      LinkProperties linkProperties,
+                                      @DataFailCause.FailCause int failCause) {
         mState = state;
         mNetworkType = networkType;
-        mAPNType = apnType;
+        mAPNTypes = apnTypes;
         mAPN = apn;
-        mReason = reason;
         mLinkProperties = linkProperties;
         mFailCause = failCause;
     }
@@ -77,82 +80,52 @@
 
     /**
      * Construct a PreciseDataConnectionState object from the given parcel.
+     *
+     * @hide
      */
     private PreciseDataConnectionState(Parcel in) {
         mState = in.readInt();
         mNetworkType = in.readInt();
-        mAPNType = in.readString();
+        mAPNTypes = in.readInt();
         mAPN = in.readString();
-        mReason = in.readString();
         mLinkProperties = (LinkProperties)in.readParcelable(null);
-        mFailCause = in.readString();
+        mFailCause = in.readInt();
     }
 
     /**
-     * Get data connection state
-     *
-     * @see TelephonyManager#DATA_UNKNOWN
-     * @see TelephonyManager#DATA_DISCONNECTED
-     * @see TelephonyManager#DATA_CONNECTING
-     * @see TelephonyManager#DATA_CONNECTED
-     * @see TelephonyManager#DATA_SUSPENDED
+     * Returns the state of data connection that supported the apn types returned by
+     * {@link #getDataConnectionApnTypeBitMask()}
      */
-    @UnsupportedAppUsage
-    public int getDataConnectionState() {
+    public @TelephonyManager.DataState int getDataConnectionState() {
         return mState;
     }
 
     /**
-     * Get data connection network type
-     *
-     * @see TelephonyManager#NETWORK_TYPE_UNKNOWN
-     * @see TelephonyManager#NETWORK_TYPE_GPRS
-     * @see TelephonyManager#NETWORK_TYPE_EDGE
-     * @see TelephonyManager#NETWORK_TYPE_UMTS
-     * @see TelephonyManager#NETWORK_TYPE_CDMA
-     * @see TelephonyManager#NETWORK_TYPE_EVDO_0
-     * @see TelephonyManager#NETWORK_TYPE_EVDO_A
-     * @see TelephonyManager#NETWORK_TYPE_1xRTT
-     * @see TelephonyManager#NETWORK_TYPE_HSDPA
-     * @see TelephonyManager#NETWORK_TYPE_HSUPA
-     * @see TelephonyManager#NETWORK_TYPE_HSPA
-     * @see TelephonyManager#NETWORK_TYPE_IDEN
-     * @see TelephonyManager#NETWORK_TYPE_EVDO_B
-     * @see TelephonyManager#NETWORK_TYPE_LTE
-     * @see TelephonyManager#NETWORK_TYPE_EHRPD
-     * @see TelephonyManager#NETWORK_TYPE_HSPAP
+     * Returns the network type associated with this data connection.
+     * @hide
      */
-    @UnsupportedAppUsage
-    public int getDataConnectionNetworkType() {
+    public @TelephonyManager.NetworkType int getDataConnectionNetworkType() {
         return mNetworkType;
     }
 
     /**
-     * Get data connection APN type
+     * Returns the data connection APN types supported by this connection and triggers
+     * {@link PreciseDataConnectionState} change.
      */
-    @UnsupportedAppUsage
-    public String getDataConnectionAPNType() {
-        return mAPNType;
+    public @ApnSetting.ApnType int getDataConnectionApnTypeBitMask() {
+        return mAPNTypes;
     }
 
     /**
-     * Get data connection APN.
+     * Returns APN {@link ApnSetting} of this data connection.
      */
-    @UnsupportedAppUsage
-    public String getDataConnectionAPN() {
+    public String getDataConnectionApn() {
         return mAPN;
     }
 
     /**
-     * Get data connection change reason.
-     */
-    @UnsupportedAppUsage
-    public String getDataConnectionChangeReason() {
-        return mReason;
-    }
-
-    /**
-     * Get the properties of the network link.
+     * Get the properties of the network link {@link LinkProperties}.
+     * @hide
      */
     @UnsupportedAppUsage
     public LinkProperties getDataConnectionLinkProperties() {
@@ -160,10 +133,9 @@
     }
 
     /**
-     * Get data connection fail cause, in case there was a failure.
+     * Returns data connection fail cause, in case there was a failure.
      */
-    @UnsupportedAppUsage
-    public String getDataConnectionFailCause() {
+    public @DataFailCause.FailCause int getDataConnectionFailCause() {
         return mFailCause;
     }
 
@@ -176,11 +148,10 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mState);
         out.writeInt(mNetworkType);
-        out.writeString(mAPNType);
+        out.writeInt(mAPNTypes);
         out.writeString(mAPN);
-        out.writeString(mReason);
         out.writeParcelable(mLinkProperties, flags);
-        out.writeString(mFailCause);
+        out.writeInt(mFailCause);
     }
 
     public static final Parcelable.Creator<PreciseDataConnectionState> CREATOR
@@ -197,72 +168,23 @@
 
     @Override
     public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + mState;
-        result = prime * result + mNetworkType;
-        result = prime * result + ((mAPNType == null) ? 0 : mAPNType.hashCode());
-        result = prime * result + ((mAPN == null) ? 0 : mAPN.hashCode());
-        result = prime * result + ((mReason == null) ? 0 : mReason.hashCode());
-        result = prime * result + ((mLinkProperties == null) ? 0 : mLinkProperties.hashCode());
-        result = prime * result + ((mFailCause == null) ? 0 : mFailCause.hashCode());
-        return result;
+        return Objects.hash(mState, mNetworkType, mAPNTypes, mAPN, mLinkProperties,
+                mFailCause);
     }
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
+
+        if (!(obj instanceof PreciseDataConnectionState)) {
             return false;
         }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
+
         PreciseDataConnectionState other = (PreciseDataConnectionState) obj;
-        if (mAPN == null) {
-            if (other.mAPN != null) {
-                return false;
-            }
-        } else if (!mAPN.equals(other.mAPN)) {
-            return false;
-        }
-        if (mAPNType == null) {
-            if (other.mAPNType != null) {
-                return false;
-            }
-        } else if (!mAPNType.equals(other.mAPNType)) {
-            return false;
-        }
-        if (mFailCause == null) {
-            if (other.mFailCause != null) {
-                return false;
-            }
-        } else if (!mFailCause.equals(other.mFailCause)) {
-            return false;
-        }
-        if (mLinkProperties == null) {
-            if (other.mLinkProperties != null) {
-                return false;
-            }
-        } else if (!mLinkProperties.equals(other.mLinkProperties)) {
-            return false;
-        }
-        if (mNetworkType != other.mNetworkType) {
-            return false;
-        }
-        if (mReason == null) {
-            if (other.mReason != null) {
-                return false;
-            }
-        } else if (!mReason.equals(other.mReason)) {
-            return false;
-        }
-        if (mState != other.mState) {
-            return false;
-        }
-        return true;
+        return Objects.equals(mAPN, other.mAPN) && mAPNTypes == other.mAPNTypes
+                && mFailCause == other.mFailCause
+                && Objects.equals(mLinkProperties, other.mLinkProperties)
+                && mNetworkType == other.mNetworkType
+                && mState == other.mState;
     }
 
     @Override
@@ -271,11 +193,10 @@
 
         sb.append("Data Connection state: " + mState);
         sb.append(", Network type: " + mNetworkType);
-        sb.append(", APN type: " + mAPNType);
+        sb.append(", APN types: " + ApnSetting.getApnTypesStringFromBitmask(mAPNTypes));
         sb.append(", APN: " + mAPN);
-        sb.append(", Change reason: " + mReason);
         sb.append(", Link properties: " + mLinkProperties);
-        sb.append(", Fail cause: " + mFailCause);
+        sb.append(", Fail cause: " + DataFailCause.toString(mFailCause));
 
         return sb.toString();
     }
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 9fc1b6f..bf9bf9a 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -170,7 +170,8 @@
                     RIL_RADIO_TECHNOLOGY_GSM,
                     RIL_RADIO_TECHNOLOGY_TD_SCDMA,
                     RIL_RADIO_TECHNOLOGY_IWLAN,
-                    RIL_RADIO_TECHNOLOGY_LTE_CA})
+                    RIL_RADIO_TECHNOLOGY_LTE_CA,
+                    RIL_RADIO_TECHNOLOGY_NR})
     public @interface RilRadioTechnology {}
     /**
      * Available radio technologies for GSM, UMTS and CDMA.
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index ef185c5..91375bc 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -24,6 +24,8 @@
 import android.os.Parcelable;
 import android.os.PersistableBundle;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -84,11 +86,6 @@
     CellSignalStrengthTdscdma mTdscdma;
     CellSignalStrengthLte mLte;
 
-    /** Parameters from the framework */
-    @UnsupportedAppUsage
-    private int mLteRsrpBoost; // offset to be reduced from the rsrp threshold while calculating
-                                // signal strength level
-
     /**
      * Create a new SignalStrength from a intent notifier Bundle
      *
@@ -138,7 +135,6 @@
         mWcdma = wcdma;
         mTdscdma = tdscdma;
         mLte = lte;
-        mLteRsrpBoost = 0;
     }
 
     /**
@@ -178,9 +174,37 @@
         return mLte;
     }
 
+    /**
+     * Returns a List of CellSignalStrength Components of this SignalStrength Report.
+     *
+     * Use this API to access underlying
+     * {@link android.telephony#CellSignalStrength CellSignalStrength} objects that provide more
+     * granular information about the SignalStrength report. Only valid (non-empty)
+     * CellSignalStrengths will be returned. The order of any returned elements is not guaranteed,
+     * and the list may contain more than one instance of a CellSignalStrength type.
+     *
+     * @return a List of CellSignalStrength or an empty List if there are no valid measurements.
+     *
+     * @see android.telephony#CellSignalStrength
+     * @see android.telephony#CellSignalStrengthNr
+     * @see android.telephony#CellSignalStrengthLte
+     * @see android.telephony#CellSignalStrengthTdscdma
+     * @see android.telephony#CellSignalStrengthWcdma
+     * @see android.telephony#CellSignalStrengthCdma
+     * @see android.telephony#CellSignalStrengthGsm
+     */
+    public @NonNull List<CellSignalStrength> getCellSignalStrengths() {
+        List<CellSignalStrength> cssList = new ArrayList<>(2); // Usually have 2 or fewer elems
+        if (mLte.isValid()) cssList.add(mLte);
+        if (mCdma.isValid()) cssList.add(mCdma);
+        if (mTdscdma.isValid()) cssList.add(mTdscdma);
+        if (mWcdma.isValid()) cssList.add(mWcdma);
+        if (mGsm.isValid()) cssList.add(mGsm);
+        return cssList;
+    }
+
     /** @hide */
     public void updateLevel(PersistableBundle cc, ServiceState ss) {
-        mLteRsrpBoost = ss.getLteEarfcnRsrpBoost();
         mCdma.updateLevel(cc, ss);
         mGsm.updateLevel(cc, ss);
         mWcdma.updateLevel(cc, ss);
@@ -210,7 +234,6 @@
         mWcdma = new CellSignalStrengthWcdma(s.mWcdma);
         mTdscdma = new CellSignalStrengthTdscdma(s.mTdscdma);
         mLte = new CellSignalStrengthLte(s.mLte);
-        mLteRsrpBoost = s.mLteRsrpBoost;
     }
 
     /**
@@ -227,7 +250,6 @@
         mWcdma = in.readParcelable(CellSignalStrengthWcdma.class.getClassLoader());
         mTdscdma = in.readParcelable(CellSignalStrengthTdscdma.class.getClassLoader());
         mLte = in.readParcelable(CellSignalStrengthLte.class.getClassLoader());
-        mLteRsrpBoost = in.readInt();
     }
 
     /**
@@ -239,8 +261,6 @@
         out.writeParcelable(mWcdma, flags);
         out.writeParcelable(mTdscdma, flags);
         out.writeParcelable(mLte, flags);
-
-        out.writeInt(mLteRsrpBoost);
     }
 
     /**
@@ -272,14 +292,27 @@
      * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
      *
      * @return RSSI in ASU 0..31, 99, or UNAVAILABLE
+     *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthGsm#getAsuLevel}.
+     * @see android.telephony#CellSignalStrengthGsm
+     * @see android.telephony.SignalStrength#getCellSignalStrengths
      */
+    @Deprecated
     public int getGsmSignalStrength() {
         return mGsm.getAsuLevel();
     }
 
     /**
      * Get the GSM bit error rate (0-7, 99) as defined in TS 27.007 8.5
+     *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthGsm#getBitErrorRate}.
+     *
+     * @see android.telephony#CellSignalStrengthGsm
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      */
+    @Deprecated
     public int getGsmBitErrorRate() {
         return mGsm.getBitErrorRate();
     }
@@ -288,14 +321,28 @@
      * Get the CDMA RSSI value in dBm
      *
      * @return the CDMA RSSI value or {@link #INVALID} if invalid
+     *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthCdma#getCdmaDbm}.
+     *
+     * @see android.telephony#CellSignalStrengthCdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      */
+    @Deprecated
     public int getCdmaDbm() {
         return mCdma.getCdmaDbm();
     }
 
     /**
      * Get the CDMA Ec/Io value in dB*10
+     *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthCdma#getCdmaEcio}.
+     *
+     * @see android.telephony#CellSignalStrengthCdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      */
+    @Deprecated
     public int getCdmaEcio() {
         return mCdma.getCdmaEcio();
     }
@@ -304,60 +351,116 @@
      * Get the EVDO RSSI value in dBm
      *
      * @return the EVDO RSSI value or {@link #INVALID} if invalid
+     *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthCdma#getEvdoDbm}.
+     *
+     * @see android.telephony#CellSignalStrengthCdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      */
+    @Deprecated
     public int getEvdoDbm() {
         return mCdma.getEvdoDbm();
     }
 
     /**
      * Get the EVDO Ec/Io value in dB*10
+     *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthCdma#getEvdoEcio}.
+     *
+     * @see android.telephony#CellSignalStrengthCdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      */
+    @Deprecated
     public int getEvdoEcio() {
         return mCdma.getEvdoEcio();
     }
 
     /**
      * Get the signal to noise ratio. Valid values are 0-8. 8 is the highest.
+     *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthCdma#getEvdoSnr}.
+     *
+     * @see android.telephony#CellSignalStrengthCdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      */
+    @Deprecated
     public int getEvdoSnr() {
         return mCdma.getEvdoSnr();
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthLte#getRssi}.
+     *
+     * @see android.telephony#CellSignalStrengthLte
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
+     * @hide
+     */
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getLteSignalStrength() {
         return mLte.getRssi();
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthLte#getRsrp}.
+     *
+     * @see android.telephony#CellSignalStrengthLte
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
+     * @hide
+     */
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getLteRsrp() {
         return mLte.getRsrp();
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthLte#getRsrq}.
+     *
+     * @see android.telephony#CellSignalStrengthLte
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
+     * @hide
+     */
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getLteRsrq() {
         return mLte.getRsrq();
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthLte#getRssnr}.
+     *
+     * @see android.telephony#CellSignalStrengthLte
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
+     * @hide
+     */
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getLteRssnr() {
         return mLte.getRssnr();
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
+    /**
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthLte#getCqi}.
+     *
+     * @see android.telephony#CellSignalStrengthLte
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
+     * @hide
+     */
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getLteCqi() {
         return mLte.getCqi();
     }
 
-    /** @hide */
-    public int getLteRsrpBoost() {
-        return mLteRsrpBoost;
-    }
-
     /**
      * Retrieve an abstract level value for the overall signal strength.
      *
@@ -369,18 +472,24 @@
     public int getLevel() {
         int level = getPrimary().getLevel();
         if (level < SIGNAL_STRENGTH_NONE_OR_UNKNOWN || level > SIGNAL_STRENGTH_GREAT) {
-            log("Invalid Level " + level + ", this=" + this);
+            loge("Invalid Level " + level + ", this=" + this);
             return SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
         }
         return getPrimary().getLevel();
     }
 
     /**
-     * Get the signal level as an asu value between 0..31, 99 is unknown
+     * Get the signal level as an asu value with a range dependent on the underlying technology.
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrength#getAsuLevel}. Because the levels vary by technology,
+     *             this method is misleading and should not be used.
+     * @see android.telephony#CellSignalStrength
+     * @see android.telephony.SignalStrength#getCellSignalStrengths
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getAsuLevel() {
         return getPrimary().getAsuLevel();
     }
@@ -388,9 +497,15 @@
     /**
      * Get the signal strength as dBm
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrength#getDbm()}. Because the levels vary by technology,
+     *             this method is misleading and should not be used.
+     * @see android.telephony#CellSignalStrength
+     * @see android.telephony.SignalStrength#getCellSignalStrengths
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getDbm() {
         return getPrimary().getDbm();
     }
@@ -398,9 +513,15 @@
     /**
      * Get Gsm signal strength as dBm
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthGsm#getDbm}.
+     *
+     * @see android.telephony#CellSignalStrengthGsm
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getGsmDbm() {
         return mGsm.getDbm();
     }
@@ -408,9 +529,15 @@
     /**
      * Get gsm as level 0..4
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthGsm#getLevel}.
+     *
+     * @see android.telephony#CellSignalStrengthGsm
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getGsmLevel() {
         return mGsm.getLevel();
     }
@@ -418,9 +545,15 @@
     /**
      * Get the gsm signal level as an asu value between 0..31, 99 is unknown
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthGsm#getAsuLevel}.
+     *
+     * @see android.telephony#CellSignalStrengthGsm
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getGsmAsuLevel() {
         return mGsm.getAsuLevel();
     }
@@ -428,9 +561,15 @@
     /**
      * Get cdma as level 0..4
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthCdma#getLevel}.
+     *
+     * @see android.telephony#CellSignalStrengthCdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getCdmaLevel() {
         return mCdma.getLevel();
     }
@@ -438,9 +577,17 @@
     /**
      * Get the cdma signal level as an asu value between 0..31, 99 is unknown
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthCdma#getAsuLevel}. Since there is no definition of
+     *             ASU for CDMA, the resultant value is Android-specific and is not recommended
+     *             for use.
+     *
+     * @see android.telephony#CellSignalStrengthCdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getCdmaAsuLevel() {
         return mCdma.getAsuLevel();
     }
@@ -448,9 +595,15 @@
     /**
      * Get Evdo as level 0..4
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthCdma#getEvdoLevel}.
+     *
+     * @see android.telephony#CellSignalStrengthCdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getEvdoLevel() {
         return mCdma.getEvdoLevel();
     }
@@ -458,9 +611,17 @@
     /**
      * Get the evdo signal level as an asu value between 0..31, 99 is unknown
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthCdma#getEvdoAsuLevel}. Since there is no definition of
+     *             ASU for EvDO, the resultant value is Android-specific and is not recommended
+     *             for use.
+     *
+     * @see android.telephony#CellSignalStrengthCdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getEvdoAsuLevel() {
         return mCdma.getEvdoAsuLevel();
     }
@@ -468,9 +629,15 @@
     /**
      * Get LTE as dBm
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthLte#getDbm}.
+     *
+     * @see android.telephony#CellSignalStrengthLte
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getLteDbm() {
         return mLte.getRsrp();
     }
@@ -478,9 +645,15 @@
     /**
      * Get LTE as level 0..4
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthLte#getLevel}.
+     *
+     * @see android.telephony#CellSignalStrengthLte
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getLteLevel() {
         return mLte.getLevel();
     }
@@ -489,26 +662,46 @@
      * Get the LTE signal level as an asu value between 0..97, 99 is unknown
      * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthLte#getAsuLevel}.
+     *
+     * @see android.telephony#CellSignalStrengthLte
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getLteAsuLevel() {
         return mLte.getAsuLevel();
     }
 
     /**
      * @return true if this is for GSM
+     *
+     * @deprecated This method returns true if there are any 3gpp type SignalStrength elements in
+     *             this SignalStrength report or if the report contains no valid SignalStrength
+     *             information. Instead callers should use
+     *             {@link android.telephony.SignalStrength#getCellSignalStrengths
+     *             getCellSignalStrengths()} to determine which types of information are contained
+     *             in the SignalStrength report.
      */
+    @Deprecated
     public boolean isGsm() {
         return !(getPrimary() instanceof CellSignalStrengthCdma);
     }
 
     /**
-     * @return get TD_SCDMA dbm
+     * @return get TD-SCDMA dBm
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthTdscdma#getDbm}.
+     *
+     * @see android.telephony#CellSignalStrengthTdscdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getTdScdmaDbm() {
         return mTdscdma.getRscp();
     }
@@ -519,9 +712,15 @@
      * INT_MAX: 0x7FFFFFFF denotes invalid value
      * Reference: 3GPP TS 25.123, section 9.1.1.1
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthTdscdma#getLevel}.
+     *
+     * @see android.telephony#CellSignalStrengthTdscdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getTdScdmaLevel() {
         return mTdscdma.getLevel();
      }
@@ -529,18 +728,30 @@
     /**
      * Get the TD-SCDMA signal level as an asu value.
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthTdscdma#getAsuLevel}.
+     *
+     * @see android.telephony#CellSignalStrengthTdscdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public int getTdScdmaAsuLevel() {
         return mTdscdma.getAsuLevel();
     }
 
     /**
-     * Gets WCDMA RSCP as a dbm value between -120 and -24, as defined in TS 27.007 8.69.
+     * Gets WCDMA RSCP as a dBm value between -120 and -24, as defined in TS 27.007 8.69.
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthWcdma#getRscp}.
+     *
+     * @see android.telephony#CellSignalStrengthWcdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
+    @Deprecated
     public int getWcdmaRscp() {
         return mWcdma.getRscp();
     }
@@ -548,8 +759,14 @@
     /**
      * Get the WCDMA signal level as an ASU value between 0-96, 255 is unknown
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthWcdma#getAsuLevel}.
+     *
+     * @see android.telephony#CellSignalStrengthWcdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
+    @Deprecated
     public int getWcdmaAsuLevel() {
         /*
          * 3GPP 27.007 (Ver 10.3.0) Sec 8.69
@@ -563,10 +780,16 @@
     }
 
     /**
-     * Gets WCDMA signal strength as a dbm value between -120 and -24, as defined in TS 27.007 8.69.
+     * Gets WCDMA signal strength as a dBm value between -120 and -24, as defined in TS 27.007 8.69.
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthWcdma#getDbm}.
+     *
+     * @see android.telephony#CellSignalStrengthWcdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
+    @Deprecated
     public int getWcdmaDbm() {
         return mWcdma.getDbm();
     }
@@ -574,18 +797,24 @@
     /**
      * Get WCDMA as level 0..4
      *
+     * @deprecated this information should be retrieved from
+     *             {@link CellSignalStrengthWcdma#getDbm}.
+     *
+     * @see android.telephony#CellSignalStrengthWcdma
+     * @see android.telephony.SignalStrength#getCellSignalStrengths()
      * @hide
      */
+    @Deprecated
     public int getWcdmaLevel() {
         return mWcdma.getLevel();
     }
 
-   /**
+    /**
      * @return hash code
      */
     @Override
     public int hashCode() {
-        return Objects.hash(mCdma, mGsm, mWcdma, mTdscdma, mLte, mLteRsrpBoost);
+        return Objects.hash(mCdma, mGsm, mWcdma, mTdscdma, mLte);
     }
 
     /**
@@ -601,8 +830,7 @@
             && mGsm.equals(s.mGsm)
             && mWcdma.equals(s.mWcdma)
             && mTdscdma.equals(s.mTdscdma)
-            && mLte.equals(s.mLte)
-            && mLteRsrpBoost == s.mLteRsrpBoost;
+            && mLte.equals(s.mLte);
     }
 
     /**
@@ -616,7 +844,6 @@
             .append(",mWcdma=").append(mWcdma)
             .append(",mTdscdma=").append(mTdscdma)
             .append(",mLte=").append(mLte)
-            .append(",mLteRsrpBoost=").append(mLteRsrpBoost)
             .append(",primary=").append(getPrimary().getClass().getSimpleName())
             .append("}")
             .toString();
@@ -626,40 +853,51 @@
      * Set SignalStrength based on intent notifier map
      *
      * @param m intent notifier map
+     *
+     * @deprecated this method relies on non-stable implementation details, and full access to
+     *             internal storage is available via {@link getCellSignalStrengths()}.
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private void setFromNotifierBundle(Bundle m) {
         mCdma = m.getParcelable("Cdma");
         mGsm = m.getParcelable("Gsm");
         mWcdma = m.getParcelable("Wcdma");
         mTdscdma = m.getParcelable("Tdscdma");
         mLte = m.getParcelable("Lte");
-
-        mLteRsrpBoost = m.getInt("LteRsrpBoost");
     }
 
     /**
      * Set intent notifier Bundle based on SignalStrength
      *
      * @param m intent notifier Bundle
+     *
+     * @deprecated this method relies on non-stable implementation details, and full access to
+     *             internal storage is available via {@link getCellSignalStrengths()}.
      * @hide
      */
-    @UnsupportedAppUsage
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public void fillInNotifierBundle(Bundle m) {
         m.putParcelable("Cdma", mCdma);
         m.putParcelable("Gsm", mGsm);
         m.putParcelable("Wcdma", mWcdma);
         m.putParcelable("Tdscdma", mTdscdma);
         m.putParcelable("Lte", mLte);
-
-        m.putInt("LteRsrpBoost", mLteRsrpBoost);
     }
 
     /**
-     * log
+     * log warning
      */
     private static void log(String s) {
         Rlog.w(LOG_TAG, s);
     }
+
+    /**
+     * log error
+     */
+    private static void loge(String s) {
+        Rlog.e(LOG_TAG, s);
+    }
 }
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 1378bb0..d777bf1 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -22,6 +22,10 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
 import android.app.PendingIntent;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothMapClient;
+import android.bluetooth.BluetoothProfile;
 import android.content.ActivityNotFoundException;
 import android.content.ContentValues;
 import android.content.Context;
@@ -32,6 +36,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.telecom.PhoneAccount;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -61,6 +66,8 @@
  */
 public final class SmsManager {
     private static final String TAG = "SmsManager";
+    private static final boolean DBG = false;
+
     /**
      * A psuedo-subId that represents the default subId at any given time. The actual subId it
      * represents changes as the default subId is changed.
@@ -339,6 +346,44 @@
             throw new IllegalArgumentException("Invalid message body");
         }
 
+        // A Manager code accessing another manager is *not* acceptable, in Android.
+        // In this particular case, it is unavoidable because of the following:
+        // If the subscription for this SmsManager instance belongs to a remote SIM
+        // then a listener to get BluetoothMapClient proxy needs to be started up.
+        // Doing that is possible only in a foreground thread or as a system user.
+        // i.e., Can't be done in ISms service.
+        // For that reason, SubscriptionManager needs to be accessed here to determine
+        // if the subscription belongs to a remote SIM.
+        // Ideally, there should be another API in ISms to service messages going thru
+        // remote SIM subscriptions (and ISms should be tweaked to be able to access
+        // BluetoothMapClient proxy)
+        Context context = ActivityThread.currentApplication().getApplicationContext();
+        SubscriptionManager manager = (SubscriptionManager) context
+                .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+        int subId = getSubscriptionId();
+        SubscriptionInfo info = manager.getActiveSubscriptionInfo(subId);
+        if (DBG) {
+            Log.d(TAG, "for subId: " + subId + ", subscription-info: " + info);
+        }
+        if (info == null) {
+            // There is no subscription for the given subId. That can only mean one thing:
+            // the caller is using a SmsManager instance with an obsolete subscription id.
+            // That is most probably because caller didn't invalidate SmsManager instance
+            // for an already deleted subscription id.
+            Log.e(TAG, "subId: " + subId + " for this SmsManager instance is obsolete.");
+            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
+        }
+
+        /* If the Subscription associated with this SmsManager instance belongs to a remote-sim,
+         * then send the message thru the remote-sim subscription.
+         */
+        if (info.getSubscriptionType() == SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM) {
+            if (DBG) Log.d(TAG, "sending message thru bluetooth");
+            sendTextMessageBluetooth(destinationAddress, scAddress, text, sentIntent,
+                    deliveryIntent, info);
+            return;
+        }
+
         try {
             ISms iccISms = getISmsServiceOrThrow();
             iccISms.sendTextForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
@@ -350,6 +395,79 @@
         }
     }
 
+    private void sendTextMessageBluetooth(String destAddr, String scAddress,
+            String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
+            SubscriptionInfo info) {
+        BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
+        if (btAdapter == null) {
+            // No bluetooth service on this platform?
+            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
+            return;
+        }
+        BluetoothDevice device = btAdapter.getRemoteDevice(info.getIccId());
+        if (device == null) {
+            if (DBG) Log.d(TAG, "Bluetooth device addr invalid: " + info.getIccId());
+            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
+            return;
+        }
+        btAdapter.getProfileProxy(ActivityThread.currentApplication().getApplicationContext(),
+                new MapMessageSender(destAddr, text, device, sentIntent, deliveryIntent),
+                BluetoothProfile.MAP_CLIENT);
+    }
+
+    private class MapMessageSender implements BluetoothProfile.ServiceListener {
+        final Uri[] mDestAddr;
+        private String mMessage;
+        final BluetoothDevice mDevice;
+        final PendingIntent mSentIntent;
+        final PendingIntent mDeliveryIntent;
+        MapMessageSender(final String destAddr, final String message, final BluetoothDevice device,
+                final PendingIntent sentIntent, final PendingIntent deliveryIntent) {
+            super();
+            mDestAddr = new Uri[] {new Uri.Builder()
+                    .appendPath(destAddr)
+                    .scheme(PhoneAccount.SCHEME_TEL)
+                    .build()};
+            mMessage = message;
+            mDevice = device;
+            mSentIntent = sentIntent;
+            mDeliveryIntent = deliveryIntent;
+        }
+
+        @Override
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (DBG) Log.d(TAG, "Service connected");
+            if (profile != BluetoothProfile.MAP_CLIENT) return;
+            BluetoothMapClient mapProfile = (BluetoothMapClient) proxy;
+            if (mMessage != null) {
+                if (DBG) Log.d(TAG, "Sending message thru bluetooth");
+                mapProfile.sendMessage(mDevice, mDestAddr, mMessage, mSentIntent, mDeliveryIntent);
+                mMessage = null;
+            }
+            BluetoothAdapter.getDefaultAdapter()
+                    .closeProfileProxy(BluetoothProfile.MAP_CLIENT, mapProfile);
+        }
+
+        @Override
+        public void onServiceDisconnected(int profile) {
+            if (mMessage != null) {
+                if (DBG) Log.d(TAG, "Bluetooth disconnected before sending the message");
+                sendErrorInPendingIntent(mSentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
+                mMessage = null;
+            }
+        }
+    }
+
+    private void sendErrorInPendingIntent(PendingIntent intent, int errorCode) {
+        try {
+            intent.send(errorCode);
+        } catch (PendingIntent.CanceledException e) {
+            // PendingIntent is cancelled. ignore sending this error code back to
+            // caller.
+            if (DBG) Log.d(TAG, "PendingIntent.CanceledException: " + e.getMessage());
+        }
+    }
+
     /**
      * Send a text based SMS without writing it into the SMS Provider.
      *
@@ -888,8 +1006,6 @@
         }
     }
 
-
-
     /**
      * Get the SmsManager associated with the default subscription id. The instance will always be
      * associated with the default subscription id, even if the default subscription id is changed.
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index a1e8b19..a3b3374 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -174,6 +174,21 @@
     private boolean mIsGroupDisabled = false;
 
     /**
+     * Profile class, PROFILE_CLASS_TESTING, PROFILE_CLASS_OPERATIONAL
+     * PROFILE_CLASS_PROVISIONING, or PROFILE_CLASS_UNSET.
+     * A profile on the eUICC can be defined as test, operational, provisioning, or unset.
+     * The profile class will be populated from the profile metadata if present. Otherwise,
+     * the profile class defaults to unset if there is no profile metadata or the subscription
+     * is not on an eUICC ({@link #isEmbedded} returns false).
+     */
+    private int mProfileClass;
+
+    /**
+     * Type of subscription
+     */
+    private int mSubscriptionType;
+
+    /**
      * @hide
      */
     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
@@ -182,7 +197,8 @@
             @Nullable UiccAccessRule[] accessRules, String cardString) {
         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
                 roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString,
-                false, null, true, TelephonyManager.UNKNOWN_CARRIER_ID);
+                false, null, true, TelephonyManager.UNKNOWN_CARRIER_ID,
+                SubscriptionManager.PROFILE_CLASS_DEFAULT);
     }
 
     /**
@@ -192,10 +208,11 @@
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
             @Nullable UiccAccessRule[] accessRules, String cardString, boolean isOpportunistic,
-            @Nullable String groupUUID, boolean isMetered, int carrierId) {
+            @Nullable String groupUUID, boolean isMetered, int carrierId, int profileClass) {
         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
                 roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1,
-                isOpportunistic, groupUUID, isMetered, false, carrierId);
+                isOpportunistic, groupUUID, isMetered, false, carrierId, profileClass,
+                SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
     }
 
     /**
@@ -206,7 +223,7 @@
             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
             @Nullable UiccAccessRule[] accessRules, String cardString, int cardId,
             boolean isOpportunistic, @Nullable String groupUUID, boolean isMetered,
-            boolean isGroupDisabled, int carrierid) {
+            boolean isGroupDisabled, int carrierId, int profileClass, int subType) {
         this.mId = id;
         this.mIccId = iccId;
         this.mSimSlotIndex = simSlotIndex;
@@ -228,10 +245,11 @@
         this.mGroupUUID = groupUUID;
         this.mIsMetered = isMetered;
         this.mIsGroupDisabled = isGroupDisabled;
-        this.mCarrierId = carrierid;
+        this.mCarrierId = carrierId;
+        this.mProfileClass = profileClass;
+        this.mSubscriptionType = subType;
     }
 
-
     /**
      * @return the subscription ID.
      */
@@ -466,6 +484,25 @@
     }
 
     /**
+     * @return the profile class of this subscription.
+     * @hide
+     */
+    @SystemApi
+    public @SubscriptionManager.ProfileClass int getProfileClass() {
+        return this.mProfileClass;
+    }
+
+    /**
+     * This method returns the type of a subscription. It can be
+     * {@link SubscriptionManager#SUBSCRIPTION_TYPE_LOCAL_SIM} or
+     * {@link SubscriptionManager#SUBSCRIPTION_TYPE_REMOTE_SIM}.
+     * @return the type of subscription
+     */
+    public @SubscriptionManager.SubscriptionType int getSubscriptionType() {
+        return mSubscriptionType;
+    }
+
+    /**
      * Checks whether the app with the given context is authorized to manage this subscription
      * according to its metadata. Only supported for embedded subscriptions (if {@link #isEmbedded}
      * returns true).
@@ -590,11 +627,13 @@
             boolean isMetered = source.readBoolean();
             boolean isGroupDisabled = source.readBoolean();
             int carrierid = source.readInt();
+            int profileClass = source.readInt();
+            int subType = source.readInt();
 
             return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
                     nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
                     isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID,
-                    isMetered, isGroupDisabled, carrierid);
+                    isMetered, isGroupDisabled, carrierid, profileClass, subType);
         }
 
         @Override
@@ -627,6 +666,8 @@
         dest.writeBoolean(mIsMetered);
         dest.writeBoolean(mIsGroupDisabled);
         dest.writeInt(mCarrierId);
+        dest.writeInt(mProfileClass);
+        dest.writeInt(mSubscriptionType);
     }
 
     @Override
@@ -662,7 +703,9 @@
                 + " accessRules " + Arrays.toString(mAccessRules)
                 + " cardString=" + cardStringToPrint + " cardId=" + mCardId
                 + " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID
-                + " isMetered=" + mIsMetered + " mIsGroupDisabled=" + mIsGroupDisabled + "}";
+                + " isMetered=" + mIsMetered + " mIsGroupDisabled=" + mIsGroupDisabled
+                + " profileClass=" + mProfileClass
+                + " subscriptionType=" + mSubscriptionType + "}";
     }
 
     @Override
@@ -670,7 +713,7 @@
         return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
                 mIsOpportunistic, mGroupUUID, mIsMetered, mIccId, mNumber, mMcc, mMnc,
                 mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mAccessRules,
-                mIsGroupDisabled, mCarrierId);
+                mIsGroupDisabled, mCarrierId, mProfileClass);
     }
 
     @Override
@@ -705,6 +748,7 @@
                 && Objects.equals(mCardId, toCompare.mCardId)
                 && TextUtils.equals(mDisplayName, toCompare.mDisplayName)
                 && TextUtils.equals(mCarrierName, toCompare.mCarrierName)
-                && Arrays.equals(mAccessRules, toCompare.mAccessRules);
+                && Arrays.equals(mAccessRules, toCompare.mAccessRules)
+                && mProfileClass == toCompare.mProfileClass;
     }
 }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2c712a1..869cf1c 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -22,6 +22,7 @@
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.DurationMillisLong;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -62,6 +63,8 @@
 import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.PhoneConstants;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -244,7 +247,9 @@
     public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
 
     /**
-     * TelephonyProvider column name for SIM ICC Identifier
+     * TelephonyProvider column name for a unique identifier for the subscription within the
+     * specific subscription type. For example, it contains SIM ICC Identifier subscriptions
+     * on Local SIMs. and Mac-address for Remote-SIM Subscriptions for Bluetooth devices.
      * <P>Type: TEXT (String)</P>
      */
     /** @hide */
@@ -262,6 +267,63 @@
     public static final int SIM_NOT_INSERTED = -1;
 
     /**
+     * The slot-index for Bluetooth Remote-SIM subscriptions
+     * @hide
+     */
+    public static final int SLOT_INDEX_FOR_REMOTE_SIM_SUB = INVALID_SIM_SLOT_INDEX;
+
+    /**
+     * TelephonyProvider column name Subscription-type.
+     * <P>Type: INTEGER (int)</P> {@link #SUBSCRIPTION_TYPE_LOCAL_SIM} for Local-SIM Subscriptions,
+     * {@link #SUBSCRIPTION_TYPE_REMOTE_SIM} for Remote-SIM Subscriptions.
+     * Default value is 0.
+     */
+    /** @hide */
+    public static final String SUBSCRIPTION_TYPE = "subscription_type";
+
+    /**
+     * This constant is to designate a subscription as a Local-SIM Subscription.
+     * <p> A Local-SIM can be a physical SIM inserted into a sim-slot in the device, or eSIM on the
+     * device.
+     * </p>
+     */
+    public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0;
+
+    /**
+     * This constant is to designate a subscription as a Remote-SIM Subscription.
+     * <p>
+     * A Remote-SIM subscription is for a SIM on a phone connected to this device via some
+     * connectivity mechanism, for example bluetooth. Similar to Local SIM, this subscription can
+     * be used for SMS, Voice and data by proxying data through the connected device.
+     * Certain data of the SIM, such as IMEI, are not accessible for Remote SIMs.
+     * </p>
+     *
+     * <p>
+     * A Remote-SIM is available only as long the phone stays connected to this device.
+     * When the phone disconnects, Remote-SIM subscription is removed from this device and is
+     * no longer known. All data associated with the subscription, such as stored SMS, call logs,
+     * contacts etc, are removed from this device.
+     * </p>
+     *
+     * <p>
+     * If the phone re-connects to this device, a new Remote-SIM subscription is created for
+     * the phone. The Subscription Id associated with the new subscription is different from
+     * the Subscription Id of the previous Remote-SIM subscription created (and removed) for the
+     * phone; i.e., new Remote-SIM subscription treats the reconnected phone as a Remote-SIM that
+     * was never seen before.
+     * </p>
+     */
+    public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"SUBSCRIPTION_TYPE_"},
+        value = {
+            SUBSCRIPTION_TYPE_LOCAL_SIM,
+            SUBSCRIPTION_TYPE_REMOTE_SIM})
+    public @interface SubscriptionType {}
+
+    /**
      * TelephonyProvider column name for user displayed name.
      * <P>Type: TEXT (String)</P>
      */
@@ -599,6 +661,73 @@
      * @hide
      */
     public static final String IS_METERED = "is_metered";
+
+    /**
+     * TelephonyProvider column name for the profile class of a subscription
+     * Only present if {@link #IS_EMBEDDED} is 1.
+     * <P>Type: INTEGER (int)</P>
+     * @hide
+     */
+    public static final String PROFILE_CLASS = "profile_class";
+
+    /**
+     * Profile class of the subscription
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "PROFILE_CLASS_" }, value = {
+            PROFILE_CLASS_TESTING,
+            PROFILE_CLASS_PROVISIONING,
+            PROFILE_CLASS_OPERATIONAL,
+            PROFILE_CLASS_UNSET,
+            PROFILE_CLASS_DEFAULT
+    })
+    public @interface ProfileClass {}
+
+    /**
+     * A testing profile can be pre-loaded or downloaded onto
+     * the eUICC and provides connectivity to test equipment
+     * for the purpose of testing the device and the eUICC. It
+     * is not intended to store any operator credentials.
+     * @hide
+     */
+    @SystemApi
+    public static final int PROFILE_CLASS_TESTING = 0;
+
+    /**
+     * A provisioning profile is pre-loaded onto the eUICC and
+     * provides connectivity to a mobile network solely for the
+     * purpose of provisioning profiles.
+     * @hide
+     */
+    @SystemApi
+    public static final int PROFILE_CLASS_PROVISIONING = 1;
+
+    /**
+     * An operational profile can be pre-loaded or downloaded
+     * onto the eUICC and provides services provided by the
+     * operator.
+     * @hide
+     */
+    @SystemApi
+    public static final int PROFILE_CLASS_OPERATIONAL = 2;
+
+    /**
+     * The profile class is unset. This occurs when profile class
+     * info is not available. The subscription either has no profile
+     * metadata or the profile metadata did not encode profile class.
+     * @hide
+     */
+    @SystemApi
+    public static final int PROFILE_CLASS_UNSET = -1;
+
+    /**
+     * Default profile class
+     * @hide
+     */
+    @SystemApi
+    public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
+
     /**
      * Broadcast Action: The user has changed one of the default subs related to
      * data, phone calls, or sms</p>
@@ -1075,7 +1204,7 @@
     }
 
     /**
-     * Get the SubscriptionInfo(s) of the currently inserted SIM(s). The records will be sorted
+     * Get the SubscriptionInfo(s) of the currently active SIM(s). The records will be sorted
      * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}.
      *
      * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -1102,17 +1231,33 @@
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public List<SubscriptionInfo> getActiveSubscriptionInfoList() {
-        List<SubscriptionInfo> result = null;
+        return getActiveSubscriptionInfoList(false);
+    }
+
+    /**
+     * This is similar to {@link #getActiveSubscriptionInfoList()}, but if userVisibleOnly
+     * is true, it will filter out the hidden subscriptions.
+     *
+     * @hide
+     */
+    public List<SubscriptionInfo> getActiveSubscriptionInfoList(boolean userVisibleOnly) {
+        List<SubscriptionInfo> activeList = null;
 
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                result = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName());
+                activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName());
             }
         } catch (RemoteException ex) {
             // ignore it
         }
-        return result;
+
+        if (!userVisibleOnly || activeList == null) {
+            return activeList;
+        } else {
+            return activeList.stream().filter(subInfo -> !shouldHideSubscription(subInfo))
+                    .collect(Collectors.toList());
+        }
     }
 
     /**
@@ -1341,17 +1486,7 @@
             logd("[addSubscriptionInfoRecord]- invalid slotIndex");
         }
 
-        try {
-            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
-            if (iSub != null) {
-                // FIXME: This returns 1 on success, 0 on error should should we return it?
-                iSub.addSubInfoRecord(iccId, slotIndex);
-            } else {
-                logd("[addSubscriptionInfoRecord]- ISub service is null");
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
+        addSubscriptionInfoRecord(iccId, null, slotIndex, SUBSCRIPTION_TYPE_LOCAL_SIM);
 
         // FIXME: Always returns null?
         return null;
@@ -1359,6 +1494,79 @@
     }
 
     /**
+     * Add a new SubscriptionInfo to SubscriptionInfo database if needed
+     * @param uniqueId This is the unique identifier for the subscription within the
+     *                 specific subscription type.
+     * @param displayName human-readable name of the device the subscription corresponds to.
+     * @param slotIndex the slot assigned to this subscription. It is ignored for subscriptionType
+     *                  of {@link #SUBSCRIPTION_TYPE_REMOTE_SIM}.
+     * @param subscriptionType the {@link #SUBSCRIPTION_TYPE}
+     * @hide
+     */
+    public void addSubscriptionInfoRecord(String uniqueId, String displayName, int slotIndex,
+            int subscriptionType) {
+        if (VDBG) {
+            logd("[addSubscriptionInfoRecord]+ uniqueId:" + uniqueId
+                    + ", displayName:" + displayName + ", slotIndex:" + slotIndex
+                    + ", subscriptionType: " + subscriptionType);
+        }
+        if (uniqueId == null) {
+            Log.e(LOG_TAG, "[addSubscriptionInfoRecord]- uniqueId is null");
+            return;
+        }
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub == null) {
+                Log.e(LOG_TAG, "[addSubscriptionInfoRecord]- ISub service is null");
+                return;
+            }
+            int result = iSub.addSubInfo(uniqueId, displayName, slotIndex, subscriptionType);
+            if (result < 0) {
+                Log.e(LOG_TAG, "Adding of subscription didn't succeed: error = " + result);
+            } else {
+                logd("successfully added new subscription");
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+    }
+
+    /**
+     * Remove SubscriptionInfo record from the SubscriptionInfo database
+     * @param uniqueId This is the unique identifier for the subscription within the specific
+     *                 subscription type.
+     * @param subscriptionType the {@link #SUBSCRIPTION_TYPE}
+     * @hide
+     */
+    public void removeSubscriptionInfoRecord(String uniqueId, int subscriptionType) {
+        if (VDBG) {
+            logd("[removeSubscriptionInfoRecord]+ uniqueId:" + uniqueId
+                    + ", subscriptionType: " + subscriptionType);
+        }
+        if (uniqueId == null) {
+            Log.e(LOG_TAG, "[addSubscriptionInfoRecord]- uniqueId is null");
+            return;
+        }
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub == null) {
+                Log.e(LOG_TAG, "[removeSubscriptionInfoRecord]- ISub service is null");
+                return;
+            }
+            int result = iSub.removeSubInfo(uniqueId, subscriptionType);
+            if (result < 0) {
+                Log.e(LOG_TAG, "Removal of subscription didn't succeed: error = " + result);
+            } else {
+                logd("successfully removed subscription");
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+    }
+
+    /**
      * Set SIM icon tint color by simInfo index
      * @param tint the RGB value of icon tint color of the SIM
      * @param subId the unique SubInfoRecord index in database
@@ -2367,10 +2575,39 @@
      *
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public void setPreferredData(int subId) {
-        if (VDBG) logd("[setPreferredData]+ subId:" + subId);
-        setSubscriptionPropertyHelper(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
-                "setPreferredData", (iSub)-> iSub.setPreferredData(subId));
+    public void setPreferredDataSubscriptionId(int subId) {
+        if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId);
+        setSubscriptionPropertyHelper(DEFAULT_SUBSCRIPTION_ID, "setPreferredDataSubscriptionId",
+                (iSub)-> iSub.setPreferredDataSubscriptionId(subId));
+    }
+
+    /**
+     * Get which subscription is preferred for cellular data.
+     * It's also usually the subscription we set up internet connection on.
+     *
+     * PreferredData overwrites user setting of default data subscription. And it's used
+     * by AlternativeNetworkService or carrier apps to switch primary and CBRS
+     * subscription dynamically in multi-SIM devices.
+     *
+     * @return preferred subscription id for cellular data. {@link DEFAULT_SUBSCRIPTION_ID} if
+     * there's no prefered subscription.
+     *
+     * @hide
+     *
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public int getPreferredDataSubscriptionId() {
+        int preferredSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                preferredSubId = iSub.getPreferredDataSubscriptionId();
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return preferredSubId;
     }
 
     /**
@@ -2622,6 +2859,95 @@
         }
     }
 
+    /**
+     * Enabled or disable a subscription. This is currently used in the settings page.
+     *
+     * <p>
+     * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+     *
+     * @param enable whether user is turning it on or off.
+     * @param subscriptionId Subscription to be enabled or disabled.
+     *                       It could be a eSIM or pSIM subscription.
+     *
+     * @return whether the operation is successful.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public boolean setSubscriptionEnabled(int subscriptionId, boolean enable) {
+        if (VDBG) {
+            logd("setSubscriptionActivated subId= " + subscriptionId + " enable " + enable);
+        }
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                return iSub.setSubscriptionEnabled(enable, subscriptionId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns whether the subscription is enabled or not. This is different from activated
+     * or deactivated for two aspects. 1) For when user disables a physical subscription, we
+     * actually disable the modem because we can't switch off the subscription. 2) For eSIM,
+     * user may enable one subscription but the system may activate another temporarily. In this
+     * case, user enabled one is different from current active one.
+
+     * @param subscriptionId The subscription it asks about.
+     * @return whether it's enabled or not. {@code true} if user set this subscription enabled
+     * earlier, or user never set subscription enable / disable on this slot explicitly, and
+     * this subscription is currently active. Otherwise, it returns {@code false}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public boolean isSubscriptionEnabled(int subscriptionId) {
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                return iSub.isSubscriptionEnabled(subscriptionId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return false;
+    }
+
+    /**
+     * Get which subscription is enabled on this slot. See {@link #isSubscriptionEnabled(int)}
+     * for more details.
+     *
+     * @param slotIndex which slot it asks about.
+     * @return which subscription is enabled on this slot. If there's no enabled subscription
+     *         in this slot, it will return {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public int getEnabledSubscriptionId(int slotIndex) {
+        int subId = INVALID_SUBSCRIPTION_ID;
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                subId = iSub.getEnabledSubscriptionId(slotIndex);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        if (VDBG) logd("getEnabledSubscriptionId, subId = " + subId);
+        return subId;
+    }
+
     private interface CallISubMethodHelper {
         int callMethod(ISub iSub) throws RemoteException;
     }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 4598afa..e710e0e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -76,8 +76,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telecom.ITelecomService;
 import com.android.internal.telephony.CellNetworkScanResult;
-import com.android.internal.telephony.IAns;
 import com.android.internal.telephony.INumberVerificationCallback;
+import com.android.internal.telephony.IOns;
 import com.android.internal.telephony.IPhoneSubInfo;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.ITelephonyRegistry;
@@ -93,6 +93,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.concurrent.Executor;
 import java.util.regex.Matcher;
@@ -772,7 +773,6 @@
      * The {@link #EXTRA_DATA_NETWORK_TYPE} extra indicates the connection network type.
      * The {@link #EXTRA_DATA_APN_TYPE} extra indicates the APN type.
      * The {@link #EXTRA_DATA_APN} extra indicates the APN.
-     * The {@link #EXTRA_DATA_CHANGE_REASON} extra indicates the connection change reason.
      * The {@link #EXTRA_DATA_IFACE_PROPERTIES} extra indicates the connection interface.
      * The {@link #EXTRA_DATA_FAILURE_CAUSE} extra indicates the connection fail cause.
      *
@@ -783,7 +783,6 @@
      * @see #EXTRA_DATA_NETWORK_TYPE
      * @see #EXTRA_DATA_APN_TYPE
      * @see #EXTRA_DATA_APN
-     * @see #EXTRA_DATA_CHANGE_REASON
      * @see #EXTRA_DATA_IFACE
      * @see #EXTRA_DATA_FAILURE_CAUSE
      * @hide
@@ -873,18 +872,6 @@
 
     /**
      * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
-     * for an String representation of the change reason.
-     *
-     * <p class="note">
-     * Retrieve with
-     * {@link android.content.Intent#getStringExtra(String name)}.
-     *
-     * @hide
-     */
-    public static final String EXTRA_DATA_CHANGE_REASON = PhoneConstants.STATE_CHANGE_REASON_KEY;
-
-    /**
-     * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
      * for an String representation of the data interface.
      *
      * <p class="note">
@@ -4599,9 +4586,18 @@
       }
     }
 
-    /** Data connection state: Unknown.  Used before we know the state.
-     * @hide
-     */
+    /** @hide */
+    @IntDef(prefix = {"DATA_"}, value = {
+            DATA_UNKNOWN,
+            DATA_DISCONNECTED,
+            DATA_CONNECTING,
+            DATA_CONNECTED,
+            DATA_SUSPENDED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DataState{}
+
+    /** Data connection state: Unknown.  Used before we know the state. */
     public static final int DATA_UNKNOWN        = -1;
     /** Data connection state: Disconnected. IP traffic not available. */
     public static final int DATA_DISCONNECTED   = 0;
@@ -4656,8 +4652,8 @@
         return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
     }
 
-    private IAns getIAns() {
-        return IAns.Stub.asInterface(ServiceManager.getService("ians"));
+    private IOns getIOns() {
+        return IOns.Stub.asInterface(ServiceManager.getService("ions"));
     }
 
     //
@@ -4903,19 +4899,53 @@
     /** Callback for providing asynchronous {@link CellInfo} on request */
     public abstract static class CellInfoCallback {
         /**
-         * Response to
+         * Success response to
          * {@link android.telephony.TelephonyManager#requestCellInfoUpdate requestCellInfoUpdate()}.
          *
-         * <p>Invoked when there is a response to
+         * Invoked when there is a response to
          * {@link android.telephony.TelephonyManager#requestCellInfoUpdate requestCellInfoUpdate()}
          * to provide a list of {@link CellInfo}. If no {@link CellInfo} is available then an empty
-         * list will be provided. If an error occurs, null will be provided.
+         * list will be provided. If an error occurs, null will be provided unless the onError
+         * callback is overridden.
          *
          * @param cellInfo a list of {@link CellInfo}, an empty list, or null.
          *
          * {@see android.telephony.TelephonyManager#getAllCellInfo getAllCellInfo()}
          */
-        public abstract void onCellInfo(List<CellInfo> cellInfo);
+        public abstract void onCellInfo(@NonNull List<CellInfo> cellInfo);
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = {"ERROR_"}, value = {ERROR_TIMEOUT, ERROR_MODEM_ERROR})
+        public @interface CellInfoCallbackError {}
+
+        /**
+         * The system timed out waiting for a response from the Radio.
+         */
+        public static final int ERROR_TIMEOUT = 1;
+
+        /**
+         * The modem returned a failure.
+         */
+        public static final int ERROR_MODEM_ERROR = 2;
+
+        /**
+         * Error response to
+         * {@link android.telephony.TelephonyManager#requestCellInfoUpdate requestCellInfoUpdate()}.
+         *
+         * Invoked when an error condition prevents updated {@link CellInfo} from being fetched
+         * and returned from the modem. Callers of requestCellInfoUpdate() should override this
+         * function to receive detailed status information in the event of an error. By default,
+         * this function will invoke onCellInfo() with null.
+         *
+         * @param errorCode an error code indicating the type of failure.
+         * @param detail a Throwable object with additional detail regarding the failure if
+         *     available, otherwise null.
+         */
+        public void onError(@CellInfoCallbackError int errorCode, @Nullable Throwable detail) {
+            // By default, simply invoke the success callback with an empty list.
+            onCellInfo(new ArrayList<CellInfo>());
+        }
     };
 
     /**
@@ -4942,6 +4972,12 @@
                             Binder.withCleanCallingIdentity(() ->
                                     executor.execute(() -> callback.onCellInfo(cellInfo)));
                         }
+
+                        public void onError(int errorCode, android.os.ParcelableException detail) {
+                            Binder.withCleanCallingIdentity(() ->
+                                    executor.execute(() -> callback.onError(
+                                            errorCode, detail.getCause())));
+                        }
                     }, getOpPackageName());
 
         } catch (RemoteException ex) {
@@ -4976,6 +5012,12 @@
                             Binder.withCleanCallingIdentity(() ->
                                     executor.execute(() -> callback.onCellInfo(cellInfo)));
                         }
+
+                        public void onError(int errorCode, android.os.ParcelableException detail) {
+                            Binder.withCleanCallingIdentity(() ->
+                                    executor.execute(() -> callback.onError(
+                                            errorCode, detail.getCause())));
+                        }
                     }, getOpPackageName(), workSource);
         } catch (RemoteException ex) {
         }
@@ -5863,9 +5905,14 @@
 
     /**
      * Returns the IMS Service Table (IST) that was loaded from the ISIM.
+     *
+     * See 3GPP TS 31.103 (Section 4.2.7) for the definition and more information on this table.
+     *
      * @return IMS Service Table or null if not present or not loaded
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getIsimIst() {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -8539,12 +8586,25 @@
     }
 
 
-    /** @hide */
-    public String getLocaleFromDefaultSim() {
+    /**
+     * Returns a well-formed IETF BCP 47 language tag representing the locale from the SIM, e.g,
+     * en-US. Returns {@code null} if no locale could be derived from subscriptions.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+     *
+     * @see Locale#toLanguageTag()
+     * @see Locale#forLanguageTag(String)
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @Nullable public String getSimLocale() {
         try {
             final ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getLocaleFromDefaultSim();
+                return telephony.getSimLocaleForSubscriber(getSubId());
             }
         } catch (RemoteException ex) {
         }
@@ -8552,6 +8612,22 @@
     }
 
     /**
+     * TODO delete after SuW migrates to new API.
+     * @hide
+     */
+    public String getLocaleFromDefaultSim() {
+        try {
+            final ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getSimLocaleForSubscriber(getSubId());
+            }
+        } catch (RemoteException ex) {
+        }
+        return null;
+    }
+
+
+    /**
      * Requests the modem activity info. The recipient will place the result
      * in `result`.
      * @param result The object on which the recipient will send the resulting
@@ -9009,6 +9085,8 @@
      * <p>This method works only on devices with {@link
      * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled.
      *
+     * @deprecated use setCarrierRestrictionRules instead
+     *
      * @return The number of carriers set successfully. Should be length of
      * carrierList on success; -1 if carrierList null or on error.
      * @hide
@@ -9016,44 +9094,144 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public int setAllowedCarriers(int slotIndex, List<CarrierIdentifier> carriers) {
+        // Execute the method setCarrierRestrictionRules with an empty excluded list and
+        // indicating priority for the allowed list.
+        CarrierRestrictionRules carrierRestrictionRules = CarrierRestrictionRules.newBuilder()
+                .setAllowedCarriers(carriers)
+                .setDefaultCarrierRestriction(
+                    CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED)
+                .build();
+
+        int result = setCarrierRestrictionRules(carrierRestrictionRules);
+
+        // Convert boolean result into int, as required by this method.
+        if (result == SET_CARRIER_RESTRICTION_SUCCESS) {
+            return carriers.size();
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * The carrier restrictions were successfully set.
+     * @hide
+     */
+    @SystemApi
+    public static final int SET_CARRIER_RESTRICTION_SUCCESS = 0;
+
+    /**
+     * The carrier restrictions were not set due to lack of support in the modem. This can happen
+     * if the modem does not support setting the carrier restrictions or if the configuration
+     * passed in the {@code setCarrierRestrictionRules} is not supported by the modem.
+     * @hide
+     */
+    @SystemApi
+    public static final int SET_CARRIER_RESTRICTION_NOT_SUPPORTED = 1;
+
+    /**
+     * The setting of carrier restrictions failed.
+     * @hide
+     */
+    @SystemApi
+    public static final int SET_CARRIER_RESTRICTION_ERROR = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"SET_CARRIER_RESTRICTION_"},
+            value = {
+                    SET_CARRIER_RESTRICTION_SUCCESS,
+                    SET_CARRIER_RESTRICTION_NOT_SUPPORTED,
+                    SET_CARRIER_RESTRICTION_ERROR
+            })
+    public @interface SetCarrierRestrictionResult {}
+
+    /**
+     * Set the allowed carrier list and the excluded carrier list indicating the priority between
+     * the two lists.
+     * Requires system privileges.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     *
+     * <p>This method works only on devices with {@link
+     * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled.
+     *
+     * @return {@link #SET_CARRIER_RESTRICTION_SUCCESS} in case of success.
+     * {@link #SET_CARRIER_RESTRICTION_NOT_SUPPORTED} if the modem does not support the
+     * configuration. {@link #SET_CARRIER_RESTRICTION_ERROR} in all other error cases.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @SetCarrierRestrictionResult
+    public int setCarrierRestrictionRules(@NonNull CarrierRestrictionRules rules) {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                return service.setAllowedCarriers(slotIndex, carriers);
+                return service.setAllowedCarriers(rules);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#setAllowedCarriers", e);
         } catch (NullPointerException e) {
             Log.e(TAG, "Error calling ITelephony#setAllowedCarriers", e);
         }
-        return -1;
+        return SET_CARRIER_RESTRICTION_ERROR;
     }
 
     /**
      * Get the allowed carrier list for slotIndex.
-     * Require system privileges. In the future we may add this to carrier APIs.
+     * Requires system privileges.
      *
      * <p>This method returns valid data on devices with {@link
      * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled.
      *
+     * @deprecated Apps should use {@link getCarriersRestrictionRules} to retrieve the list of
+     * allowed and excliuded carriers, as the result of this API is valid only when the excluded
+     * list is empty. This API could return an empty list, even if some restrictions are present.
+     *
      * @return List of {@link android.telephony.CarrierIdentifier}; empty list
      * means all carriers are allowed.
      * @hide
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public List<CarrierIdentifier> getAllowedCarriers(int slotIndex) {
+        CarrierRestrictionRules carrierRestrictionRule = getCarrierRestrictionRules();
+        if (carrierRestrictionRule != null) {
+            return carrierRestrictionRule.getAllowedCarriers();
+        }
+        return new ArrayList<CarrierIdentifier>(0);
+    }
+
+    /**
+     * Get the allowed carrier list and the excluded carrier list indicating the priority between
+     * the two lists.
+     * Require system privileges. In the future we may add this to carrier APIs.
+     *
+     * <p>This method returns valid data on devices with {@link
+     * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled.
+     *
+     * @return {@link CarrierRestrictionRules} which contains the allowed carrier list and the
+     * excluded carrier list with the priority between the two lists. Returns {@code null}
+     * in case of error.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @Nullable
+    public CarrierRestrictionRules getCarrierRestrictionRules() {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                return service.getAllowedCarriers(slotIndex);
+                return service.getAllowedCarriers();
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#getAllowedCarriers", e);
         } catch (NullPointerException e) {
             Log.e(TAG, "Error calling ITelephony#getAllowedCarriers", e);
         }
-        return new ArrayList<CarrierIdentifier>(0);
+        return null;
     }
 
     /**
@@ -9456,10 +9634,10 @@
     }
 
     /**
-     * Enable or disable AlternativeNetworkService.
+     * Enable or disable OpportunisticNetworkService.
      *
      * This method should be called to enable or disable
-     * AlternativeNetwork service on the device.
+     * OpportunisticNetwork service on the device.
      *
      * <p>
      * Requires Permission:
@@ -9470,25 +9648,25 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public boolean setAlternativeNetworkState(boolean enable) {
+    public boolean setOpportunisticNetworkState(boolean enable) {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         boolean ret = false;
         try {
-            IAns iAlternativeNetworkService = getIAns();
-            if (iAlternativeNetworkService != null) {
-                ret = iAlternativeNetworkService.setEnable(enable, pkgForDebug);
+            IOns iOpportunisticNetworkService = getIOns();
+            if (iOpportunisticNetworkService != null) {
+                ret = iOpportunisticNetworkService.setEnable(enable, pkgForDebug);
             }
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "enableAlternativeNetwork RemoteException", ex);
+            Rlog.e(TAG, "enableOpportunisticNetwork RemoteException", ex);
         }
 
         return ret;
     }
 
     /**
-     * is AlternativeNetworkService enabled
+     * is OpportunisticNetworkService enabled
      *
-     * This method should be called to determine if the AlternativeNetworkService is
+     * This method should be called to determine if the OpportunisticNetworkService is
      * enabled
      *
      * <p>
@@ -9497,17 +9675,17 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    public boolean isAlternativeNetworkEnabled() {
+    public boolean isOpportunisticNetworkEnabled() {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         boolean isEnabled = false;
 
         try {
-            IAns iAlternativeNetworkService = getIAns();
-            if (iAlternativeNetworkService != null) {
-                isEnabled = iAlternativeNetworkService.isEnabled(pkgForDebug);
+            IOns iOpportunisticNetworkService = getIOns();
+            if (iOpportunisticNetworkService != null) {
+                isEnabled = iOpportunisticNetworkService.isEnabled(pkgForDebug);
             }
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "enableAlternativeNetwork RemoteException", ex);
+            Rlog.e(TAG, "enableOpportunisticNetwork RemoteException", ex);
         }
 
         return isEnabled;
@@ -9862,12 +10040,13 @@
     public boolean setPreferredOpportunisticDataSubscription(int subId) {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         try {
-            IAns iAlternativeNetworkService = getIAns();
-            if (iAlternativeNetworkService != null) {
-                return iAlternativeNetworkService.setPreferredData(subId, pkgForDebug);
+            IOns iOpportunisticNetworkService = getIOns();
+            if (iOpportunisticNetworkService != null) {
+                return iOpportunisticNetworkService
+                        .setPreferredDataSubscriptionId(subId, pkgForDebug);
             }
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "setPreferredData RemoteException", ex);
+            Rlog.e(TAG, "setPreferredDataSubscriptionId RemoteException", ex);
         }
         return false;
     }
@@ -9886,12 +10065,12 @@
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         try {
-            IAns iAlternativeNetworkService = getIAns();
-            if (iAlternativeNetworkService != null) {
-                subId = iAlternativeNetworkService.getPreferredData(pkgForDebug);
+            IOns iOpportunisticNetworkService = getIOns();
+            if (iOpportunisticNetworkService != null) {
+                subId = iOpportunisticNetworkService.getPreferredDataSubscriptionId(pkgForDebug);
             }
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "getPreferredData RemoteException", ex);
+            Rlog.e(TAG, "getPreferredDataSubscriptionId RemoteException", ex);
         }
         return subId;
     }
@@ -9899,8 +10078,8 @@
     /**
      * Update availability of a list of networks in the current location.
      *
-     * This api should be called to inform AlternativeNetwork Service about the availability
-     * of a network at the current location. This information will be used by AlternativeNetwork
+     * This api should be called to inform OpportunisticNetwork Service about the availability
+     * of a network at the current location. This information will be used by OpportunisticNetwork
      * service to decide to attach to the network opportunistically. If an empty list is passed,
      * it is assumed that no network is available.
      * Requires that the calling app has carrier privileges on both primary and
@@ -9915,9 +10094,9 @@
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         boolean ret = false;
         try {
-            IAns iAlternativeNetworkService = getIAns();
-            if (iAlternativeNetworkService != null) {
-                ret = iAlternativeNetworkService.updateAvailableNetworks(availableNetworks,
+            IOns iOpportunisticNetworkService = getIOns();
+            if (iOpportunisticNetworkService != null && availableNetworks != null) {
+                ret = iOpportunisticNetworkService.updateAvailableNetworks(availableNetworks,
                         pkgForDebug);
             }
         } catch (RemoteException ex) {
@@ -9925,4 +10104,33 @@
         }
         return ret;
     }
+
+    /**
+     * Enable or disable a logical modem stack. When a logical modem is disabled, the corresponding
+     * SIM will still be visible to the user but its mapping modem will not have any radio activity.
+     * For example, we will disable a modem when user or system believes the corresponding SIM
+     * is temporarily not needed (e.g. out of coverage), and will enable it back on when needed.
+     *
+     * Requires that the calling app has permission
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     * @param slotIndex which corresponding modem will operate on.
+     * @param enable whether to enable or disable the modem stack.
+     * @return whether the operation is successful.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public boolean enableModemForSlot(int slotIndex, boolean enable) {
+        boolean ret = false;
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                ret = telephony.enableModemForSlot(slotIndex, enable);
+            }
+        } catch (RemoteException ex) {
+            Log.e(TAG, "enableModem RemoteException", ex);
+        }
+        return ret;
+    }
 }
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 8d148c3..0e69530 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -140,15 +140,19 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface AuthType {}
 
-    // Possible values for protocol.
-    /** Protocol type for IP. */
+    // Possible values for protocol which is defined in TS 27.007 section 10.1.1.
+    /** Internet protocol. */
     public static final int PROTOCOL_IP = 0;
-    /** Protocol type for IPV6. */
+    /** Internet protocol, version 6. */
     public static final int PROTOCOL_IPV6 = 1;
-    /** Protocol type for IPV4V6. */
+    /** Virtual PDP type introduced to handle dual IP stack UE capability. */
     public static final int PROTOCOL_IPV4V6 = 2;
-    /** Protocol type for PPP. */
+    /** Point to point protocol. */
     public static final int PROTOCOL_PPP = 3;
+    /** Transfer of Non-IP data to external packet data network. */
+    public static final int PROTOCOL_NON_IP = 4;
+    /** Transfer of Unstructured data to the Data Network via N6. */
+    public static final int PROTOCOL_UNSTRUCTURED = 5;
 
     /** @hide */
     @IntDef(prefix = { "PROTOCOL_" }, value = {
@@ -156,6 +160,8 @@
         PROTOCOL_IPV6,
         PROTOCOL_IPV4V6,
         PROTOCOL_PPP,
+        PROTOCOL_NON_IP,
+        PROTOCOL_UNSTRUCTURED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProtocolType {}
@@ -217,11 +223,15 @@
         PROTOCOL_STRING_MAP.put("IPV6", PROTOCOL_IPV6);
         PROTOCOL_STRING_MAP.put("IPV4V6", PROTOCOL_IPV4V6);
         PROTOCOL_STRING_MAP.put("PPP", PROTOCOL_PPP);
+        PROTOCOL_STRING_MAP.put("NON-IP", PROTOCOL_NON_IP);
+        PROTOCOL_STRING_MAP.put("UNSTRUCTURED", PROTOCOL_UNSTRUCTURED);
         PROTOCOL_INT_MAP = new ArrayMap<Integer, String>();
         PROTOCOL_INT_MAP.put(PROTOCOL_IP, "IP");
         PROTOCOL_INT_MAP.put(PROTOCOL_IPV6, "IPV6");
         PROTOCOL_INT_MAP.put(PROTOCOL_IPV4V6, "IPV4V6");
         PROTOCOL_INT_MAP.put(PROTOCOL_PPP, "PPP");
+        PROTOCOL_INT_MAP.put(PROTOCOL_NON_IP, "NON-IP");
+        PROTOCOL_INT_MAP.put(PROTOCOL_UNSTRUCTURED, "UNSTRUCTURED");
 
         MVNO_TYPE_STRING_MAP = new ArrayMap<String, Integer>();
         MVNO_TYPE_STRING_MAP.put("spn", MVNO_TYPE_SPN);
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 25f5133..294c79b 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -52,8 +52,7 @@
      * @param status Data call fail cause. 0 indicates no error.
      * @param suggestedRetryTime The suggested data retry time in milliseconds.
      * @param cid The unique id of the data connection.
-     * @param active Data connection active status. 0 = inactive, 1 = active/physical link down,
-     *               2 = active/physical link up.
+     * @param active Data connection active status. 0 = inactive, 1 = dormant, 2 = active.
      * @param type The connection protocol, should be one of the PDP_type values in TS 27.007
      *             section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
      * @param ifname The network interface name.
@@ -124,7 +123,7 @@
     public int getCallId() { return mCid; }
 
     /**
-     * @return 0 = inactive, 1 = active/physical link down, 2 = active/physical link up.
+     * @return 0 = inactive, 1 = dormant, 2 = active.
      */
     public int getActive() { return mActive; }
 
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index fe062d5..e68256d 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -27,8 +27,10 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -175,6 +177,12 @@
      * Bit-field which indicates the number is from the platform-maintained database.
      */
     public static final int EMERGENCY_NUMBER_SOURCE_DATABASE =  1 << 4;
+    /**
+     * Bit-field which indicates the number is from test mode.
+     *
+     * @hide
+     */
+    public static final int EMERGENCY_NUMBER_SOURCE_TEST =  1 << 5;
     /** Bit-field which indicates the number is from the modem config. */
     public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG =
             EmergencyNumberSource.MODEM_CONFIG;
@@ -198,21 +206,56 @@
         EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_DEFAULT);
     }
 
+    /**
+     * Indicated the framework does not know whether an emergency call should be placed using
+     * emergency or normal call routing. This means the underlying radio or IMS implementation is
+     * free to determine for itself how to route the call.
+     */
+    public static final int EMERGENCY_CALL_ROUTING_UNKNOWN = 0;
+    /**
+     * Indicates the radio or IMS implementation must handle the call through emergency routing.
+     */
+    public static final int EMERGENCY_CALL_ROUTING_EMERGENCY = 1;
+    /**
+     * Indicates the radio or IMS implementation must handle the call through normal call routing.
+     */
+    public static final int EMERGENCY_CALL_ROUTING_NORMAL = 2;
+
+    /**
+     * The routing to tell how to handle the call for the corresponding emergency number.
+     *
+     * @hide
+     */
+    @IntDef(flag = false, prefix = { "EMERGENCY_CALL_ROUTING_" }, value = {
+            EMERGENCY_CALL_ROUTING_UNKNOWN,
+            EMERGENCY_CALL_ROUTING_EMERGENCY,
+            EMERGENCY_CALL_ROUTING_NORMAL
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EmergencyCallRouting {}
+
+
     private final String mNumber;
     private final String mCountryIso;
     private final String mMnc;
     private final int mEmergencyServiceCategoryBitmask;
+    private final List<String> mEmergencyUrns;
     private final int mEmergencyNumberSourceBitmask;
+    private final int mEmergencyCallRouting;
 
     /** @hide */
-    public EmergencyNumber(@NonNull String number, @NonNull String countryIso,
-                           @NonNull String mnc, int emergencyServiceCategories,
-                           int emergencyNumberSources) {
+    public EmergencyNumber(@NonNull String number, @NonNull String countryIso, @NonNull String mnc,
+                           @EmergencyServiceCategories int emergencyServiceCategories,
+                           @NonNull List<String> emergencyUrns,
+                           @EmergencyNumberSources int emergencyNumberSources,
+                           @EmergencyCallRouting int emergencyCallRouting) {
         this.mNumber = number;
         this.mCountryIso = countryIso;
         this.mMnc = mnc;
         this.mEmergencyServiceCategoryBitmask = emergencyServiceCategories;
+        this.mEmergencyUrns = emergencyUrns;
         this.mEmergencyNumberSourceBitmask = emergencyNumberSources;
+        this.mEmergencyCallRouting = emergencyCallRouting;
     }
 
     /** @hide */
@@ -221,9 +264,36 @@
         mCountryIso = source.readString();
         mMnc = source.readString();
         mEmergencyServiceCategoryBitmask = source.readInt();
+        mEmergencyUrns = source.createStringArrayList();
         mEmergencyNumberSourceBitmask = source.readInt();
+        mEmergencyCallRouting = source.readInt();
     }
 
+    @Override
+    /** @hide */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mNumber);
+        dest.writeString(mCountryIso);
+        dest.writeString(mMnc);
+        dest.writeInt(mEmergencyServiceCategoryBitmask);
+        dest.writeStringList(mEmergencyUrns);
+        dest.writeInt(mEmergencyNumberSourceBitmask);
+        dest.writeInt(mEmergencyCallRouting);
+    }
+
+    public static final Parcelable.Creator<EmergencyNumber> CREATOR =
+            new Parcelable.Creator<EmergencyNumber>() {
+                @Override
+                public EmergencyNumber createFromParcel(Parcel in) {
+                    return new EmergencyNumber(in);
+                }
+
+                @Override
+                public EmergencyNumber[] newArray(int size) {
+                    return new EmergencyNumber[size];
+                }
+            };
+
     /**
      * Get the dialing number of the emergency number.
      *
@@ -264,6 +334,21 @@
     }
 
     /**
+     * Returns the bitmask of emergency service categories of the emergency number for
+     * internal dialing.
+     *
+     * @return bitmask of the emergency service categories
+     *
+     * @hide
+     */
+    public @EmergencyServiceCategories int getEmergencyServiceCategoryBitmaskInternalDial() {
+        if (mEmergencyNumberSourceBitmask == EMERGENCY_NUMBER_SOURCE_DATABASE) {
+            return EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED;
+        }
+        return mEmergencyServiceCategoryBitmask;
+    }
+
+    /**
      * Returns the emergency service categories of the emergency number.
      *
      * Note: if the emergency number is in {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}, only
@@ -287,6 +372,22 @@
     }
 
     /**
+     * Returns the list of emergency Uniform Resources Names (URN) of the emergency number.
+     *
+     * For example, {@code urn:service:sos} is the generic URN for contacting emergency services
+     * of all type.
+     *
+     * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General;
+     *            RFC 5031
+     *
+     * @return list of emergency Uniform Resources Names (URN) or an empty list if the emergency
+     *         number does not have a specified emergency Uniform Resource Name.
+     */
+    public @NonNull List<String> getEmergencyUrns() {
+        return mEmergencyUrns;
+    }
+
+    /**
      * Checks if the emergency service category is unspecified for the emergency number
      * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}.
      *
@@ -352,14 +453,17 @@
         return (mEmergencyNumberSourceBitmask & sources) == sources;
     }
 
-    @Override
-    /** @hide */
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mNumber);
-        dest.writeString(mCountryIso);
-        dest.writeString(mMnc);
-        dest.writeInt(mEmergencyServiceCategoryBitmask);
-        dest.writeInt(mEmergencyNumberSourceBitmask);
+    /**
+     * Returns the emergency call routing information.
+     *
+     * <p>Some regions require some emergency numbers which are not routed using typical emergency
+     * call processing, but are instead placed as regular phone calls. The emergency call routing
+     * field provides information about how an emergency call will be routed when it is placed.
+     *
+     * @return the emergency call routing requirement
+     */
+    public @EmergencyCallRouting int getEmergencyCallRouting() {
+        return mEmergencyCallRouting;
     }
 
     @Override
@@ -373,7 +477,9 @@
         return "EmergencyNumber:" + "Number-" + mNumber + "|CountryIso-" + mCountryIso
                 + "|Mnc-" + mMnc
                 + "|ServiceCategories-" + Integer.toBinaryString(mEmergencyServiceCategoryBitmask)
-                + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask);
+                + "|Urns-" + mEmergencyUrns
+                + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask)
+                + "|Routing-" + Integer.toBinaryString(mEmergencyCallRouting);
     }
 
     @Override
@@ -381,7 +487,20 @@
         if (!EmergencyNumber.class.isInstance(o)) {
             return false;
         }
-        return (o == this || toString().equals(o.toString()));
+        EmergencyNumber other = (EmergencyNumber) o;
+        return mNumber.equals(other.mNumber)
+                && mCountryIso.equals(other.mCountryIso)
+                && mMnc.equals(other.mMnc)
+                && mEmergencyServiceCategoryBitmask == other.mEmergencyServiceCategoryBitmask
+                && mEmergencyUrns.equals(other.mEmergencyUrns)
+                && mEmergencyNumberSourceBitmask == other.mEmergencyNumberSourceBitmask
+                && mEmergencyCallRouting == other.mEmergencyCallRouting;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mNumber, mCountryIso, mMnc, mEmergencyServiceCategoryBitmask,
+                mEmergencyUrns, mEmergencyNumberSourceBitmask, mEmergencyCallRouting);
     }
 
     /**
@@ -462,12 +581,12 @@
                 continue;
             }
             for (int j = i + 1; j < emergencyNumberList.size(); j++) {
-                if (isSameEmergencyNumber(
+                if (areSameEmergencyNumbers(
                         emergencyNumberList.get(i), emergencyNumberList.get(j))) {
                     Rlog.e(LOG_TAG, "Found unexpected duplicate numbers: "
                             + emergencyNumberList.get(i) + " vs " + emergencyNumberList.get(j));
                     // Set the merged emergency number in the current position
-                    emergencyNumberList.set(i, mergeNumbers(
+                    emergencyNumberList.set(i, mergeSameEmergencyNumbers(
                             emergencyNumberList.get(i), emergencyNumberList.get(j)));
                     // Mark the emergency number has been merged
                     mergedEmergencyNumber.add(emergencyNumberList.get(j));
@@ -480,14 +599,15 @@
                 emergencyNumberList.remove(i--);
             }
         }
+        Collections.sort(emergencyNumberList);
     }
 
     /**
      * Check if two emergency numbers are the same.
      *
      * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' and
-     * 'categories' fields. Multiple Emergency Number Sources should be merged into one bitfield
-     * for the same EmergencyNumber.
+     * 'categories', and 'routing' fields. Multiple Emergency Number Sources should be
+     * merged into one bitfield for the same EmergencyNumber.
      *
      * @param first first EmergencyNumber to compare
      * @param second second EmergencyNumber to compare
@@ -495,8 +615,8 @@
      *
      * @hide
      */
-    public static boolean isSameEmergencyNumber(@NonNull EmergencyNumber first,
-                                                @NonNull EmergencyNumber second) {
+    public static boolean areSameEmergencyNumbers(@NonNull EmergencyNumber first,
+                                                  @NonNull EmergencyNumber second) {
         if (!first.getNumber().equals(second.getNumber())) {
             return false;
         }
@@ -510,11 +630,24 @@
                 != second.getEmergencyServiceCategoryBitmask()) {
             return false;
         }
+        if (first.getEmergencyUrns().equals(second.getEmergencyUrns())) {
+            return false;
+        }
+        if (first.getEmergencyCallRouting() != second.getEmergencyCallRouting()) {
+            return false;
+        }
+        // Never merge two numbers if one of them is from test mode but the other one is not;
+        // This supports to remove a number from the test mode.
+        if (first.isFromSources(EMERGENCY_NUMBER_SOURCE_TEST)
+                ^ second.isFromSources(EMERGENCY_NUMBER_SOURCE_TEST)) {
+            return false;
+        }
         return true;
     }
 
     /**
-     * Get a merged EmergencyNumber for two numbers if they are the same.
+     * Get a merged EmergencyNumber from two same emergency numbers. Two emergency numbers are
+     * the same if {@link #areSameEmergencyNumbers} returns {@code true}.
      *
      * @param first first EmergencyNumber to compare
      * @param second second EmergencyNumber to compare
@@ -522,27 +655,25 @@
      *
      * @hide
      */
-    public static EmergencyNumber mergeNumbers(@NonNull EmergencyNumber first,
-                                         @NonNull EmergencyNumber second) {
-        if (isSameEmergencyNumber(first, second)) {
+    public static EmergencyNumber mergeSameEmergencyNumbers(@NonNull EmergencyNumber first,
+                                                            @NonNull EmergencyNumber second) {
+        if (areSameEmergencyNumbers(first, second)) {
             return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(),
                     first.getEmergencyServiceCategoryBitmask(),
+                    first.getEmergencyUrns(),
                     first.getEmergencyNumberSourceBitmask()
-                            | second.getEmergencyNumberSourceBitmask());
+                            | second.getEmergencyNumberSourceBitmask(),
+                    first.getEmergencyCallRouting());
         }
         return null;
     }
 
-    public static final Parcelable.Creator<EmergencyNumber> CREATOR =
-            new Parcelable.Creator<EmergencyNumber>() {
-        @Override
-        public EmergencyNumber createFromParcel(Parcel in) {
-            return new EmergencyNumber(in);
-        }
-
-        @Override
-        public EmergencyNumber[] newArray(int size) {
-            return new EmergencyNumber[size];
-        }
-    };
+    /**
+     * Validate Emergency Number address that only allows '0'-'9', '*', or '#'
+     *
+     * @hide
+     */
+    public static boolean validateEmergencyNumberAddress(String address) {
+        return address.matches("[0-9*#]+");
+    }
 }
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 6326cc6..0fa1b41 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -30,6 +30,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.telephony.TelephonyManager;
 
 import com.android.internal.telephony.euicc.IEuiccController;
 
@@ -40,7 +41,11 @@
  * EuiccManager is the application interface to eUICCs, or eSIMs/embedded SIMs.
  *
  * <p>You do not instantiate this class directly; instead, you retrieve an instance through
- * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}.
+ * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}. This instance will be
+ * created using the default eUICC.
+ *
+ * <p>On a device with multiple eUICCs, you may want to create multiple EuiccManagers. To do this
+ * you can call {@link #createForCardId}.
  *
  * <p>See {@link #isEnabled} before attempting to use these APIs.
  */
@@ -124,6 +129,66 @@
             "android.telephony.euicc.action.RESOLVE_ERROR";
 
     /**
+     * Intent action sent by system apps (such as the Settings app) to the Telephony framework to
+     * enable or disable a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID} and
+     * {@link #EXTRA_ENABLE_SUBSCRIPTION}.
+     *
+     * <p>Unlike {@link #switchToSubscription(int, PendingIntent)}, using this action allows the
+     * underlying eUICC service (i.e. the LPA app) to control the UI experience during this
+     * operation. The action is received by the Telephony framework, which in turn selects and
+     * launches an appropriate LPA activity to present UI to the user. For example, the activity may
+     * show a confirmation dialog, a progress dialog, or an error dialog when necessary.
+     *
+     * <p>The launched activity will immediately finish with
+     * {@link android.app.Activity#RESULT_CANCELED} if {@link #isEnabled} is false.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED =
+            "android.telephony.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED";
+
+    /**
+     * Intent action sent by system apps (such as the Settings app) to the Telephony framework to
+     * delete a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID}.
+     *
+     * <p>Unlike {@link #deleteSubscription(int, PendingIntent)}, using this action allows the
+     * underlying eUICC service (i.e. the LPA app) to control the UI experience during this
+     * operation. The action is received by the Telephony framework, which in turn selects and
+     * launches an appropriate LPA activity to present UI to the user. For example, the activity may
+     * show a confirmation dialog, a progress dialog, or an error dialog when necessary.
+     *
+     * <p>The launched activity will immediately finish with
+     * {@link android.app.Activity#RESULT_CANCELED} if {@link #isEnabled} is false.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED =
+            "android.telephony.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED";
+
+    /**
+     * Intent action sent by system apps (such as the Settings app) to the Telephony framework to
+     * rename a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID} and
+     * {@link #EXTRA_SUBSCRIPTION_NICKNAME}.
+     *
+     * <p>Unlike {@link #updateSubscriptionNickname(int, String, PendingIntent)}, using this action
+     * allows the the underlying eUICC service (i.e. the LPA app) to control the UI experience
+     * during this operation. The action is received by the Telephony framework, which in turn
+     * selects and launches an appropriate LPA activity to present UI to the user. For example, the
+     * activity may show a confirmation dialog, a progress dialog, or an error dialog when
+     * necessary.
+     *
+     * <p>The launched activity will immediately finish with
+     * {@link android.app.Activity#RESULT_CANCELED} if {@link #isEnabled} is false.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED =
+            "android.telephony.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED";
+
+    /**
      * Result code for an operation indicating that the operation succeeded.
      */
     public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0;
@@ -214,6 +279,37 @@
             "android.telephony.euicc.extra.FORCE_PROVISION";
 
     /**
+     * Key for an extra set on privileged actions {@link #ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED},
+     * {@link #ACTION_DELETE_SUBSCRIPTION_PRIVILEGED}, and
+     * {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing the ID of the targeted subscription.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_SUBSCRIPTION_ID =
+            "android.telephony.euicc.extra.SUBSCRIPTION_ID";
+
+    /**
+     * Key for an extra set on {@link #ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED} providing a boolean
+     * value of whether to enable or disable the targeted subscription.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_ENABLE_SUBSCRIPTION =
+            "android.telephony.euicc.extra.ENABLE_SUBSCRIPTION";
+
+    /**
+     * Key for an extra set on {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing a new
+     * nickname for the targeted subscription.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_SUBSCRIPTION_NICKNAME =
+            "android.telephony.euicc.extra.SUBSCRIPTION_NICKNAME";
+
+    /**
      * Optional meta-data attribute for a carrier app providing an icon to use to represent the
      * carrier. If not provided, the app's launcher icon will be used as a fallback.
      */
@@ -318,10 +414,29 @@
     public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5;
 
     private final Context mContext;
+    private final int mCardId;
 
     /** @hide */
     public EuiccManager(Context context) {
         mContext = context;
+        TelephonyManager tm = (TelephonyManager)
+                context.getSystemService(Context.TELEPHONY_SERVICE);
+        mCardId = tm.getCardIdForDefaultEuicc();
+    }
+
+    /** @hide */
+    private EuiccManager(Context context, int cardId) {
+        mContext = context;
+        mCardId = cardId;
+    }
+
+    /**
+     * Create a new EuiccManager object pinned to the given card ID.
+     *
+     * @return an EuiccManager that uses the given card ID for all calls.
+     */
+    public EuiccManager createForCardId(int cardId) {
+        return new EuiccManager(mContext, cardId);
     }
 
     /**
@@ -337,14 +452,15 @@
     public boolean isEnabled() {
         // In the future, this may reach out to IEuiccController (if non-null) to check any dynamic
         // restrictions.
-        return getIEuiccController() != null;
+        return getIEuiccController() != null && mCardId != TelephonyManager.INVALID_CARD_ID;
     }
 
     /**
      * Returns the EID identifying the eUICC hardware.
      *
      * <p>Requires that the calling app has carrier privileges on the active subscription on the
-     * eUICC.
+     * current eUICC. A calling app with carrier privileges for one eUICC may not necessarily have
+     * access to the EID of another eUICC.
      *
      * @return the EID. May be null if {@link #isEnabled()} is false or the eUICC is not ready.
      */
@@ -354,7 +470,7 @@
             return null;
         }
         try {
-            return getIEuiccController().getEid();
+            return getIEuiccController().getEid(mCardId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -377,7 +493,7 @@
             return EUICC_OTA_STATUS_UNAVAILABLE;
         }
         try {
-            return getIEuiccController().getOtaStatus();
+            return getIEuiccController().getOtaStatus(mCardId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -387,10 +503,10 @@
      * Attempt to download the given {@link DownloadableSubscription}.
      *
      * <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
-     * or the calling app must be authorized to manage both the currently-active subscription and
-     * the subscription to be downloaded according to the subscription metadata. Without the former,
-     * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
-     * intent to prompt the user to accept the download.
+     * or the calling app must be authorized to manage both the currently-active subscription on the
+     * current eUICC and the subscription to be downloaded according to the subscription metadata.
+     * Without the former, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be
+     * returned in the callback intent to prompt the user to accept the download.
      *
      * @param subscription the subscription to download.
      * @param switchAfterDownload if true, the profile will be activated upon successful download.
@@ -404,7 +520,7 @@
             return;
         }
         try {
-            getIEuiccController().downloadSubscription(subscription, switchAfterDownload,
+            getIEuiccController().downloadSubscription(mCardId, subscription, switchAfterDownload,
                     mContext.getOpPackageName(), null /* resolvedBundle */, callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -471,7 +587,7 @@
             return;
         }
         try {
-            getIEuiccController().continueOperation(resolutionIntent, resolutionExtras);
+            getIEuiccController().continueOperation(mCardId, resolutionIntent, resolutionExtras);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -503,8 +619,8 @@
             return;
         }
         try {
-            getIEuiccController().getDownloadableSubscriptionMetadata(
-                    subscription, mContext.getOpPackageName(), callbackIntent);
+            getIEuiccController().getDownloadableSubscriptionMetadata(mCardId, subscription,
+                    mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -533,7 +649,7 @@
             return;
         }
         try {
-            getIEuiccController().getDefaultDownloadableSubscriptionList(
+            getIEuiccController().getDefaultDownloadableSubscriptionList(mCardId,
                     mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -552,7 +668,7 @@
             return null;
         }
         try {
-            return getIEuiccController().getEuiccInfo();
+            return getIEuiccController().getEuiccInfo(mCardId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -578,7 +694,7 @@
             return;
         }
         try {
-            getIEuiccController().deleteSubscription(
+            getIEuiccController().deleteSubscription(mCardId,
                     subscriptionId, mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -606,7 +722,7 @@
             return;
         }
         try {
-            getIEuiccController().switchToSubscription(
+            getIEuiccController().switchToSubscription(mCardId,
                     subscriptionId, mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -616,14 +732,13 @@
     /**
      * Update the nickname for the given subscription.
      *
-     * <p>Requires that the calling app has the
-     * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. This is for
-     * internal system use only.
+     * <p>Requires that the calling app has carrier privileges according to the metadata of the
+     * profile to be updated, or the
+     * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
      *
      * @param subscriptionId the ID of the subscription to update.
      * @param nickname the new nickname to apply.
      * @param callbackIntent a PendingIntent to launch when the operation completes.
-     * @hide
      */
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void updateSubscriptionNickname(
@@ -633,8 +748,8 @@
             return;
         }
         try {
-            getIEuiccController().updateSubscriptionNickname(
-                    subscriptionId, nickname, callbackIntent);
+            getIEuiccController().updateSubscriptionNickname(mCardId,
+                    subscriptionId, nickname, mContext.getOpPackageName(), callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -657,7 +772,7 @@
             return;
         }
         try {
-            getIEuiccController().eraseSubscriptions(callbackIntent);
+            getIEuiccController().eraseSubscriptions(mCardId, callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -687,7 +802,7 @@
             return;
         }
         try {
-            getIEuiccController().retainSubscriptionsForFactoryReset(callbackIntent);
+            getIEuiccController().retainSubscriptionsForFactoryReset(mCardId, callbackIntent);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index cb6fcd7..59167b7 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -24,13 +24,17 @@
 import android.os.Parcelable;
 import android.telecom.VideoProfile;
 import android.telephony.emergency.EmergencyNumber;
+import android.telephony.emergency.EmergencyNumber.EmergencyCallRouting;
 import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.PhoneConstants;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Parcelable object to handle IMS call profile.
@@ -321,6 +325,32 @@
             EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED;
 
     /**
+     * The emergency Uniform Resource Names (URN), only valid if {@link #getServiceType} returns
+     * {@link #SERVICE_TYPE_EMERGENCY}.
+     *
+     * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General;
+     *            3gpp 22.101, Section 10 - Emergency Calls.
+     */
+    private List<String> mEmergencyUrns = new ArrayList<>();
+
+    /**
+     * The emergency call routing, only valid if {@link #getServiceType} returns
+     * {@link #SERVICE_TYPE_EMERGENCY}
+     *
+     * If valid, the value is any of the following constants:
+     * <ol>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li>
+     * </ol>
+     */
+    private @EmergencyCallRouting int mEmergencyCallRouting =
+            EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN;
+
+    /** Indicates if the call is for testing purpose */
+    private boolean mEmergencyCallTesting = false;
+
+    /**
      * Extras associated with this {@link ImsCallProfile}.
      * <p>
      * Valid data types include:
@@ -503,10 +533,14 @@
 
     @Override
     public String toString() {
-        return "{ serviceType=" + mServiceType +
-                ", callType=" + mCallType +
-                ", restrictCause=" + mRestrictCause +
-                ", mediaProfile=" + mMediaProfile.toString() + " }";
+        return "{ serviceType=" + mServiceType
+                + ", callType=" + mCallType
+                + ", restrictCause=" + mRestrictCause
+                + ", mediaProfile=" + mMediaProfile.toString()
+                + ", emergencyServiceCategories=" + mEmergencyServiceCategories
+                + ", emergencyUrns=" + mEmergencyUrns
+                + ", emergencyCallRouting=" + mEmergencyCallRouting
+                + ", emergencyCallTesting=" + mEmergencyCallTesting + " }";
     }
 
     @Override
@@ -522,6 +556,9 @@
         out.writeBundle(filteredExtras);
         out.writeParcelable(mMediaProfile, 0);
         out.writeInt(mEmergencyServiceCategories);
+        out.writeStringList(mEmergencyUrns);
+        out.writeInt(mEmergencyCallRouting);
+        out.writeBoolean(mEmergencyCallTesting);
     }
 
     private void readFromParcel(Parcel in) {
@@ -530,6 +567,9 @@
         mCallExtras = in.readBundle();
         mMediaProfile = in.readParcelable(ImsStreamMediaProfile.class.getClassLoader());
         mEmergencyServiceCategories = in.readInt();
+        mEmergencyUrns = in.createStringArrayList();
+        mEmergencyCallRouting = in.readInt();
+        mEmergencyCallTesting = in.readBoolean();
     }
 
     public static final Creator<ImsCallProfile> CREATOR = new Creator<ImsCallProfile>() {
@@ -740,6 +780,24 @@
     }
 
     /**
+     * Set the emergency number information. The set value is valid
+     * only if {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY}
+     *
+     * Reference: 3gpp 23.167, Section 6 - Functional description;
+     *            3gpp 24.503, Section 5.1.6.8.1 - General;
+     *            3gpp 22.101, Section 10 - Emergency Calls.
+     *
+     * @hide
+     */
+    public void setEmergencyCallInfo(EmergencyNumber num) {
+        setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmaskInternalDial());
+        setEmergencyUrns(num.getEmergencyUrns());
+        setEmergencyCallRouting(num.getEmergencyCallRouting());
+        setEmergencyCallTesting(num.getEmergencyNumberSourceBitmask()
+                == EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST);
+    }
+
+    /**
      * Set the emergency service categories. The set value is valid only if
      * {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY}
      *
@@ -758,12 +816,50 @@
      * Reference: 3gpp 23.167, Section 6 - Functional description;
      *            3gpp 22.101, Section 10 - Emergency Calls.
      */
+    @VisibleForTesting
     public void setEmergencyServiceCategories(
             @EmergencyServiceCategories int emergencyServiceCategories) {
         mEmergencyServiceCategories = emergencyServiceCategories;
     }
 
     /**
+     * Set the emergency Uniform Resource Names (URN), only valid if {@link #getServiceType}
+     * returns {@link #SERVICE_TYPE_EMERGENCY}.
+     *
+     * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General;
+     *            3gpp 22.101, Section 10 - Emergency Calls.
+     */
+    @VisibleForTesting
+    public void setEmergencyUrns(List<String> emergencyUrns) {
+        mEmergencyUrns = emergencyUrns;
+    }
+
+    /**
+     * Set the emergency call routing, only valid if {@link #getServiceType} returns
+     * {@link #SERVICE_TYPE_EMERGENCY}
+     *
+     * If valid, the value is any of the following constants:
+     * <ol>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li>
+     * </ol>
+     */
+    @VisibleForTesting
+    public void setEmergencyCallRouting(@EmergencyCallRouting int emergencyCallRouting) {
+        mEmergencyCallRouting = emergencyCallRouting;
+    }
+
+    /**
+     * Set if this is for testing emergency call, only valid if {@link #getServiceType} returns
+     * {@link #SERVICE_TYPE_EMERGENCY}.
+     */
+    @VisibleForTesting
+    public void setEmergencyCallTesting(boolean isTesting) {
+        mEmergencyCallTesting = isTesting;
+    }
+
+    /**
      * Get the emergency service categories, only valid if {@link #getServiceType} returns
      * {@link #SERVICE_TYPE_EMERGENCY}
      *
@@ -787,4 +883,37 @@
     public @EmergencyServiceCategories int getEmergencyServiceCategories() {
         return mEmergencyServiceCategories;
     }
+
+    /**
+     * Get the emergency Uniform Resource Names (URN), only valid if {@link #getServiceType}
+     * returns {@link #SERVICE_TYPE_EMERGENCY}.
+     *
+     * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General;
+     *            3gpp 22.101, Section 10 - Emergency Calls.
+     */
+    public List<String> getEmergencyUrns() {
+        return mEmergencyUrns;
+    }
+
+    /**
+     * Get the emergency call routing, only valid if {@link #getServiceType} returns
+     * {@link #SERVICE_TYPE_EMERGENCY}
+     *
+     * If valid, the value is any of the following constants:
+     * <ol>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li>
+     * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li>
+     * </ol>
+     */
+    public @EmergencyCallRouting int getEmergencyCallRouting() {
+        return mEmergencyCallRouting;
+    }
+
+    /**
+     * Get if the emergency call is for testing purpose.
+     */
+    public boolean isEmergencyCallTesting() {
+        return mEmergencyCallTesting;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index df903cc2..47c4681 100644
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -18,6 +18,7 @@
 
 import android.os.Message;
 import android.os.RemoteException;
+import android.telephony.CallQuality;
 import android.telephony.ims.aidl.IImsCallSessionListener;
 import android.util.Log;
 
@@ -443,6 +444,20 @@
         public void callSessionRttMessageReceived(String rttMessage) {
             // no-op
         }
+
+        /**
+         * While in call, there has been a change in RTT audio indicator.
+         */
+        public void callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile) {
+            // no-op
+        }
+
+        /**
+         * Called when the IMS service reports a change to the call quality.
+         */
+        public void callQualityChanged(CallQuality callQuality) {
+            // no-op
+        }
     }
 
     private final IImsCallSession miSession;
@@ -1397,6 +1412,26 @@
                 mListener.callSessionRttMessageReceived(rttMessage);
             }
         }
+
+        /**
+         * While in call, there has been a change in RTT audio indicator.
+         */
+        @Override
+        public void callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile) {
+            if (mListener != null) {
+                mListener.callSessionRttAudioIndicatorChanged(profile);
+            }
+        }
+
+        /**
+         * Call quality updated
+         */
+        @Override
+        public void callQualityChanged(CallQuality callQuality) {
+            if (mListener != null) {
+                mListener.callQualityChanged(callQuality);
+            }
+        }
     }
 
     /**
diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
index a7f124a..337375a 100644
--- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java
+++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SystemApi;
 import android.os.RemoteException;
+import android.telephony.CallQuality;
 import android.telephony.ims.aidl.IImsCallSessionListener;
 import android.telephony.ims.stub.ImsCallSessionImplBase;
 
@@ -599,5 +600,31 @@
             throw new RuntimeException(e);
         }
     }
+
+    /**
+     * While in call, there has been a change in RTT audio indicator.
+     *
+     * @param profile updated ImsStreamMediaProfile
+     */
+    public void callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile) {
+        try {
+            mListener.callSessionRttAudioIndicatorChanged(profile);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * The call quality has changed.
+     *
+     * @param callQuality The new call quality
+     */
+    public void callQualityChanged(CallQuality callQuality) {
+        try {
+            mListener.callQualityChanged(callQuality);
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }
 
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 122626f..9414abd 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -92,7 +92,7 @@
     public static final int WIFI_MODE_WIFI_PREFERRED = 2;
 
     /**
-     * Callback class for receiving Registration callback events.
+     * Callback class for receiving IMS network Registration callback events.
      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
      */
@@ -241,7 +241,8 @@
     }
 
     /**
-     * Receives IMS capability status updates from the ImsService.
+     * Receives IMS capability status updates from the ImsService. This information is also
+     * available via the {@link #isAvailable(int, int)} method below.
      *
      * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback)
      * @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
@@ -290,6 +291,8 @@
          * If unavailable, the feature is not able to support the unavailable capability at this
          * time.
          *
+         * This information can also be queried using the {@link #isAvailable(int, int)} API.
+         *
          * @param capabilities The new availability of the capabilities.
          */
         public void onCapabilitiesStatusChanged(
@@ -304,7 +307,7 @@
         /**@hide*/
         // Only exposed as public method for compatibility with deprecated ImsManager APIs.
         // TODO: clean up dependencies and change back to private visibility.
-        public void setExecutor(Executor executor) {
+        public final void setExecutor(Executor executor) {
             mBinder.setExecutor(executor);
         }
     }
@@ -342,8 +345,7 @@
      * Registers a {@link RegistrationCallback} with the system, which will provide registration
      * updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}. Use
      * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
-     * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up
-     * after a subscription is removed.
+     * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
      *
      * When the callback is registered, it will initiate the callback c to be called with the
      * current registration state.
@@ -351,6 +353,12 @@
      * @param executor The executor the callback events should be run on.
      * @param c The {@link RegistrationCallback} to be added.
      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
+     * @throws IllegalArgumentException if the subscription associated with this callback is not
+     * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
+     * {@link CapabilityCallback} callback.
+     * @throws IllegalStateException if the subscription associated with this callback is valid, but
+     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the service crashed, for example.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void registerImsRegistrationCallback(@CallbackExecutor Executor executor,
@@ -370,11 +378,17 @@
     }
 
     /**
-     * Removes an existing {@link RegistrationCallback}. Ensure to call this method when cleaning
-     * up to avoid memory leaks or when the subscription is removed.
+     * Removes an existing {@link RegistrationCallback}.
+     *
+     * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+     * etc...), this callback will automatically be removed. If this method is called for an
+     * inactive subscription, it will result in a no-op.
+     *
      * @param c The {@link RegistrationCallback} to be removed.
      * @see SubscriptionManager.OnSubscriptionsChangedListener
      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
+     * @throws IllegalArgumentException if the subscription ID associated with this callback is
+     * invalid.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
@@ -389,12 +403,14 @@
     }
 
     /**
-     * Registers a {@link CapabilityCallback} with the system, which will provide MmTel capability
-     * updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}.
+     * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
+     * availability updates for the subscription specified in
+     * {@link #createForSubscriptionId(Context, int)}. The method {@link #isAvailable(int, int)}
+     * can also be used to query this information at any time.
+     *
      * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
      * subscription changed events and call
-     * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up after a
-     * subscription is removed.
+     * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
      *
      * When the callback is registered, it will initiate the callback c to be called with the
      * current capabilities.
@@ -402,9 +418,15 @@
      * @param executor The executor the callback events should be run on.
      * @param c The MmTel {@link CapabilityCallback} to be registered.
      * @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
+     * @throws IllegalArgumentException if the subscription associated with this callback is not
+     * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
+     * {@link CapabilityCallback} callback.
+     * @throws IllegalStateException if the subscription associated with this callback is valid, but
+     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the service crashed, for example.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void registerMmTelCapabilityCallback(@CallbackExecutor Executor executor,
+    public void registerMmTelCapabilityCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull CapabilityCallback c) {
         if (c == null) {
             throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
@@ -421,10 +443,15 @@
     }
 
     /**
-     * Removes an existing MmTel {@link CapabilityCallback}. Be sure to call this when cleaning
-     * up to avoid memory leaks.
+     * Removes an existing MmTel {@link CapabilityCallback}.
+     *
+     * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+     * etc...), this callback will automatically be removed. If this method is called for an
+     * inactive subscription, it will result in a no-op.
      * @param c The MmTel {@link CapabilityCallback} to be removed.
      * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
+     * @throws IllegalArgumentException if the subscription ID associated with this callback is
+     * invalid.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
@@ -714,7 +741,7 @@
      * @see #setVoWiFiRoamingSetting(boolean)
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    @WiFiCallingMode int getVoWiFiRoamingModeSetting() {
+    public @WiFiCallingMode int getVoWiFiRoamingModeSetting() {
         try {
             return getITelephony().getVoWiFiRoamingModeSetting(mSubId);
         } catch (RemoteException e) {
diff --git a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
index 52d72b5..837ef54 100644
--- a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
+++ b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
@@ -97,6 +97,9 @@
     // Rtt related information
     /** @hide */
     public int mRttMode;
+    // RTT Audio Speech Indicator
+    /** @hide */
+    public boolean mHasRttAudioSpeech = false;
 
     /** @hide */
     public ImsStreamMediaProfile(Parcel in) {
@@ -197,7 +200,8 @@
                 ", audioDirection=" + mAudioDirection +
                 ", videoQuality=" + mVideoQuality +
                 ", videoDirection=" + mVideoDirection +
-                ", rttMode=" + mRttMode + " }";
+                ", rttMode=" + mRttMode +
+                ", hasRttAudioSpeech=" + mHasRttAudioSpeech + " }";
     }
 
     @Override
@@ -212,6 +216,7 @@
         out.writeInt(mVideoQuality);
         out.writeInt(mVideoDirection);
         out.writeInt(mRttMode);
+        out.writeBoolean(mHasRttAudioSpeech);
     }
 
     private void readFromParcel(Parcel in) {
@@ -220,6 +225,7 @@
         mVideoQuality = in.readInt();
         mVideoDirection = in.readInt();
         mRttMode = in.readInt();
+        mHasRttAudioSpeech = in.readBoolean();
     }
 
     public static final Creator<ImsStreamMediaProfile> CREATOR =
@@ -250,6 +256,10 @@
         mRttMode = rttMode;
     }
 
+    public void setRttAudioSpeech(boolean audioOn) {
+        mHasRttAudioSpeech = audioOn;
+    }
+
     public int getAudioQuality() {
         return mAudioQuality;
     }
@@ -269,4 +279,8 @@
     public int getRttMode() {
         return mRttMode;
     }
+
+    public boolean getRttAudioSpeech() {
+        return mHasRttAudioSpeech;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 916e282..d37198a 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -133,33 +133,40 @@
     }
 
     /**
-     * Register a new {@link Callback} to listen to changes to changes in
-     * IMS provisioning. Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
-     * Subscription changed events and call
-     * {@link #unregisterProvisioningChangedCallback(Callback)} to clean up after a
-     * subscription is removed.
+     * Register a new {@link Callback} to listen to changes to changes in IMS provisioning.
+     *
+     * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+     * etc...), this callback will automatically be removed.
      * @param executor The {@link Executor} to call the callback methods on
      * @param callback The provisioning callbackto be registered.
      * @see #unregisterProvisioningChangedCallback(Callback)
      * @see SubscriptionManager.OnSubscriptionsChangedListener
+     * @throws IllegalArgumentException if the subscription associated with this callback is not
+     * active (SIM is not inserted, ESIM inactive) or the subscription is invalid.
+     * @throws IllegalStateException if the subscription associated with this callback is valid, but
+     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the service crashed, for example.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void registerProvisioningChangedCallback(@CallbackExecutor Executor executor,
             @NonNull Callback callback) {
         callback.setExecutor(executor);
         try {
-            getITelephony().registerImsProvisioningChangedCallback(mSubId,
-                    callback.getBinder());
+            getITelephony().registerImsProvisioningChangedCallback(mSubId, callback.getBinder());
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
     }
 
     /**
-     * Unregister an existing {@link Callback}. Ensure to call this method when cleaning
-     * up to avoid memory leaks or when the subscription is removed.
+     * Unregister an existing {@link Callback}. When the subscription associated with this
+     * callback is removed (SIM removed, ESIM swap, etc...), this callback will automatically be
+     * removed. If this method is called for an inactive subscription, it will result in a no-op.
      * @param callback The existing {@link Callback} to be removed.
      * @see #registerProvisioningChangedCallback(Executor, Callback)
+     *
+     * @throws IllegalArgumentException if the subscription associated with this callback is
+     * invalid.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterProvisioningChangedCallback(@NonNull Callback callback) {
diff --git a/telephony/java/android/telephony/ims/Rcs1To1Thread.aidl b/telephony/java/android/telephony/ims/Rcs1To1Thread.aidl
new file mode 100644
index 0000000..9fdc41d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/Rcs1To1Thread.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable Rcs1To1Thread;
diff --git a/telephony/java/android/telephony/ims/Rcs1To1Thread.java b/telephony/java/android/telephony/ims/Rcs1To1Thread.java
new file mode 100644
index 0000000..709b3aa
--- /dev/null
+++ b/telephony/java/android/telephony/ims/Rcs1To1Thread.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * Rcs1To1Thread represents a single RCS conversation thread with a total of two
+ * {@link RcsParticipant}s.
+ * @hide - TODO(sahinc) make this public
+ */
+public class Rcs1To1Thread extends RcsThread {
+    public Rcs1To1Thread(int threadId) {
+        super(threadId);
+    }
+
+    public static final Creator<Rcs1To1Thread> CREATOR = new Creator<Rcs1To1Thread>() {
+        @Override
+        public Rcs1To1Thread createFromParcel(Parcel in) {
+            return new Rcs1To1Thread(in);
+        }
+
+        @Override
+        public Rcs1To1Thread[] newArray(int size) {
+            return new Rcs1To1Thread[size];
+        }
+    };
+
+    protected Rcs1To1Thread(Parcel in) {
+        super(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(RCS_1_TO_1_TYPE);
+        super.writeToParcel(dest, flags);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsFileTransferPart.aidl b/telephony/java/android/telephony/ims/RcsFileTransferPart.aidl
new file mode 100644
index 0000000..eaf3128
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsFileTransferPart.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsFileTransferPart;
diff --git a/telephony/java/android/telephony/ims/RcsFileTransferPart.java b/telephony/java/android/telephony/ims/RcsFileTransferPart.java
new file mode 100644
index 0000000..39c58dd
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsFileTransferPart.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * A part of a composite {@link RcsMessage} that holds a file transfer.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsFileTransferPart extends RcsPart {
+    public static final Creator<RcsFileTransferPart> CREATOR = new Creator<RcsFileTransferPart>() {
+        @Override
+        public RcsFileTransferPart createFromParcel(Parcel in) {
+            return new RcsFileTransferPart(in);
+        }
+
+        @Override
+        public RcsFileTransferPart[] newArray(int size) {
+            return new RcsFileTransferPart[size];
+        }
+    };
+
+    protected RcsFileTransferPart(Parcel in) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsGroupThread.aidl b/telephony/java/android/telephony/ims/RcsGroupThread.aidl
new file mode 100644
index 0000000..c4ce529
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThread.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsGroupThread;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThread.java b/telephony/java/android/telephony/ims/RcsGroupThread.java
new file mode 100644
index 0000000..d954b2d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThread.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * RcsGroupThread represents a single RCS conversation thread where {@link RcsParticipant}s can join
+ * or leave.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsGroupThread extends RcsThread {
+    public static final Creator<RcsGroupThread> CREATOR = new Creator<RcsGroupThread>() {
+        @Override
+        public RcsGroupThread createFromParcel(Parcel in) {
+            return new RcsGroupThread(in);
+        }
+
+        @Override
+        public RcsGroupThread[] newArray(int size) {
+            return new RcsGroupThread[size];
+        }
+    };
+
+    protected RcsGroupThread(Parcel in) {
+        super(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(RCS_GROUP_TYPE);
+        super.writeToParcel(dest, flags);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessage.aidl b/telephony/java/android/telephony/ims/RcsIncomingMessage.aidl
new file mode 100644
index 0000000..6552a82
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessage.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsIncomingMessage;
diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessage.java b/telephony/java/android/telephony/ims/RcsIncomingMessage.java
new file mode 100644
index 0000000..f39e06d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessage.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * This is a single instance of a message received over RCS.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsIncomingMessage extends RcsMessage {
+    public static final Creator<RcsIncomingMessage> CREATOR = new Creator<RcsIncomingMessage>() {
+        @Override
+        public RcsIncomingMessage createFromParcel(Parcel in) {
+            return new RcsIncomingMessage(in);
+        }
+
+        @Override
+        public RcsIncomingMessage[] newArray(int size) {
+            return new RcsIncomingMessage[size];
+        }
+    };
+
+    protected RcsIncomingMessage(Parcel in) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsLocationPart.aidl b/telephony/java/android/telephony/ims/RcsLocationPart.aidl
new file mode 100644
index 0000000..4fe5ca9
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsLocationPart.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsLocationPart;
diff --git a/telephony/java/android/telephony/ims/RcsLocationPart.java b/telephony/java/android/telephony/ims/RcsLocationPart.java
new file mode 100644
index 0000000..19be4ce
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsLocationPart.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * A part of a composite {@link RcsMessage} that holds a location
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsLocationPart extends RcsPart {
+    public static final Creator<RcsLocationPart> CREATOR = new Creator<RcsLocationPart>() {
+        @Override
+        public RcsLocationPart createFromParcel(Parcel in) {
+            return new RcsLocationPart(in);
+        }
+
+        @Override
+        public RcsLocationPart[] newArray(int size) {
+            return new RcsLocationPart[size];
+        }
+    };
+
+    protected RcsLocationPart(Parcel in) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsManager.aidl b/telephony/java/android/telephony/ims/RcsManager.aidl
new file mode 100644
index 0000000..63bc71c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsManager.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsManager;
diff --git a/telephony/java/android/telephony/ims/RcsManager.java b/telephony/java/android/telephony/ims/RcsManager.java
index d50b516..df108c8 100644
--- a/telephony/java/android/telephony/ims/RcsManager.java
+++ b/telephony/java/android/telephony/ims/RcsManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/telephony/java/android/telephony/ims/RcsMessage.aidl b/telephony/java/android/telephony/ims/RcsMessage.aidl
new file mode 100644
index 0000000..b32cd12
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMessage.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * 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.ims;
+
+parcelable RcsMessage;
diff --git a/telephony/java/android/telephony/ims/RcsMessage.java b/telephony/java/android/telephony/ims/RcsMessage.java
new file mode 100644
index 0000000..d46685c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMessage.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcelable;
+
+/**
+ * This is a single instance of a message sent or received over RCS.
+ * @hide - TODO(sahinc) make this public
+ */
+public abstract class RcsMessage implements Parcelable {
+}
diff --git a/telephony/java/android/telephony/ims/RcsMessageStore.java b/telephony/java/android/telephony/ims/RcsMessageStore.java
index c89c0be..1bf6ffd 100644
--- a/telephony/java/android/telephony/ims/RcsMessageStore.java
+++ b/telephony/java/android/telephony/ims/RcsMessageStore.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
 
 package android.telephony.ims;
 
+import android.annotation.Nullable;
+import android.annotation.WorkerThread;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.telephony.Rlog;
@@ -27,26 +29,93 @@
  * @hide - TODO make this public
  */
 public class RcsMessageStore {
-    private static final String TAG = "RcsMessageStore";
-    private static final boolean VDBG = false;
+    static final String TAG = "RcsMessageStore";
 
     /**
-     * Delete the RcsThread identified by the given threadId.
+     * Returns the first chunk of existing {@link RcsThread}s in the common storage.
+     * @param queryParameters Parameters to specify to return a subset of all RcsThreads.
+     *                        Passing a value of null will return all threads.
+     */
+    @WorkerThread
+    public RcsThreadQueryResult getRcsThreads(@Nullable RcsThreadQueryParameters queryParameters) {
+        try {
+            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+            if (iRcs != null) {
+                return iRcs.getRcsThreads(queryParameters);
+            }
+        } catch (RemoteException re) {
+            Rlog.e(TAG, "RcsMessageStore: Exception happened during getRcsThreads", re);
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the next chunk of {@link RcsThread}s in the common storage.
+     * @param continuationToken A token to continue the query to get the next chunk. This is
+     *                          obtained through {@link RcsThreadQueryResult#nextChunkToken}.
+     */
+    @WorkerThread
+    public RcsThreadQueryResult getRcsThreads(RcsThreadQueryContinuationToken continuationToken) {
+        try {
+            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+            if (iRcs != null) {
+                return iRcs.getRcsThreadsWithToken(continuationToken);
+            }
+        } catch (RemoteException re) {
+            Rlog.e(TAG, "RcsMessageStore: Exception happened during getRcsThreads", re);
+        }
+
+        return null;
+    }
+
+    /**
+     * Creates a new 1 to 1 thread with the given participant and persists it in the storage.
+     */
+    @WorkerThread
+    public Rcs1To1Thread createRcs1To1Thread(RcsParticipant recipient) {
+        try {
+            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+            if (iRcs != null) {
+                return iRcs.createRcs1To1Thread(recipient);
+            }
+        } catch (RemoteException re) {
+            Rlog.e(TAG, "RcsMessageStore: Exception happened during createRcs1To1Thread", re);
+        }
+
+        return null;
+    }
+
+    /**
+     * Delete the {@link RcsThread} identified by the given threadId.
      * @param threadId threadId of the thread to be deleted.
      */
+    @WorkerThread
     public void deleteThread(int threadId) {
-        if (VDBG) logd("deleteThread: threadId: " + threadId);
         try {
             IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
             if (iRcs != null) {
                 iRcs.deleteThread(threadId);
             }
         } catch (RemoteException re) {
-
+            Rlog.e(TAG, "RcsMessageStore: Exception happened during deleteThread", re);
         }
     }
 
-    private static void logd(String msg) {
-        Rlog.d(TAG, msg);
+    /**
+     * Creates a new participant and persists it in the storage.
+     * @param canonicalAddress The defining address (e.g. phone number) of the participant.
+     */
+    public RcsParticipant createRcsParticipant(String canonicalAddress) {
+        try {
+            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+            if (iRcs != null) {
+                return iRcs.createRcsParticipant(canonicalAddress);
+            }
+        } catch (RemoteException re) {
+            Rlog.e(TAG, "RcsMessageStore: Exception happened during createRcsParticipant", re);
+        }
+
+        return null;
     }
 }
diff --git a/telephony/java/android/telephony/ims/RcsMultiMediaPart.java b/telephony/java/android/telephony/ims/RcsMultiMediaPart.java
new file mode 100644
index 0000000..d295fba
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMultiMediaPart.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * A part of a composite {@link RcsMessage} that holds a media that is rendered on the screen
+ * (i.e. image, video etc)
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsMultiMediaPart extends RcsFileTransferPart {
+    public static final Creator<RcsMultiMediaPart> CREATOR = new Creator<RcsMultiMediaPart>() {
+        @Override
+        public RcsMultiMediaPart createFromParcel(Parcel in) {
+            return new RcsMultiMediaPart(in);
+        }
+
+        @Override
+        public RcsMultiMediaPart[] newArray(int size) {
+            return new RcsMultiMediaPart[size];
+        }
+    };
+
+    protected RcsMultiMediaPart(Parcel in) {
+        super(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsMultimediaPart.aidl b/telephony/java/android/telephony/ims/RcsMultimediaPart.aidl
new file mode 100644
index 0000000..5992d95
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMultimediaPart.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsMultimediaPart;
diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessage.aidl b/telephony/java/android/telephony/ims/RcsOutgoingMessage.aidl
new file mode 100644
index 0000000..6e0c80f
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessage.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsOutgoingMessage;
diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessage.java b/telephony/java/android/telephony/ims/RcsOutgoingMessage.java
new file mode 100644
index 0000000..bfb1611
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessage.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * This is a single instance of a message sent over RCS.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsOutgoingMessage extends RcsMessage {
+    public static final Creator<RcsOutgoingMessage> CREATOR = new Creator<RcsOutgoingMessage>() {
+        @Override
+        public RcsOutgoingMessage createFromParcel(Parcel in) {
+            return new RcsOutgoingMessage(in);
+        }
+
+        @Override
+        public RcsOutgoingMessage[] newArray(int size) {
+            return new RcsOutgoingMessage[size];
+        }
+    };
+
+    protected RcsOutgoingMessage(Parcel in) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsPart.aidl b/telephony/java/android/telephony/ims/RcsPart.aidl
new file mode 100644
index 0000000..8b8077d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsPart.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsPart;
diff --git a/telephony/java/android/telephony/ims/RcsPart.java b/telephony/java/android/telephony/ims/RcsPart.java
new file mode 100644
index 0000000..da50173
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsPart.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcelable;
+
+/**
+ * A part of a composite {@link RcsMessage}.
+ * @hide - TODO(sahinc) make this public
+ */
+public abstract class RcsPart implements Parcelable {
+}
diff --git a/telephony/java/android/telephony/ims/RcsParticipant.aidl b/telephony/java/android/telephony/ims/RcsParticipant.aidl
new file mode 100644
index 0000000..1c44363
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipant.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsParticipant;
diff --git a/telephony/java/android/telephony/ims/RcsParticipant.java b/telephony/java/android/telephony/ims/RcsParticipant.java
new file mode 100644
index 0000000..f678ec7
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipant.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import static android.telephony.ims.RcsMessageStore.TAG;
+
+import android.annotation.NonNull;
+import android.annotation.WorkerThread;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.Rlog;
+import android.telephony.ims.aidl.IRcs;
+import android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * RcsParticipant is an RCS capable contact that can participate in {@link RcsThread}s.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsParticipant implements Parcelable {
+    // The row ID of this participant in the database
+    private int mId;
+    // The phone number of this participant
+    private String mCanonicalAddress;
+    // The RCS alias of this participant. This is different than the name of the contact in the
+    // Contacts app - i.e. RCS protocol allows users to define aliases for themselves that doesn't
+    // require other users to add them as contacts and give them a name.
+    private String mAlias;
+
+    /**
+     * Constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController}
+     * to create instances of participants. This is not meant to be part of the SDK.
+     *
+     * @hide
+     */
+    public RcsParticipant(int id, @NonNull String canonicalAddress) {
+        mId = id;
+        mCanonicalAddress = canonicalAddress;
+    }
+
+    /**
+     * @return Returns the canonical address (i.e. normalized phone number) for this participant
+     */
+    public String getCanonicalAddress() {
+        return mCanonicalAddress;
+    }
+
+    /**
+     * Sets the canonical address for this participant and updates it in storage.
+     * @param canonicalAddress the canonical address to update to.
+     */
+    @WorkerThread
+    public void setCanonicalAddress(@NonNull String canonicalAddress) {
+        Preconditions.checkNotNull(canonicalAddress);
+        if (canonicalAddress.equals(mCanonicalAddress)) {
+            return;
+        }
+
+        mCanonicalAddress = canonicalAddress;
+
+        try {
+            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+            if (iRcs != null) {
+                iRcs.updateRcsParticipantCanonicalAddress(mId, mCanonicalAddress);
+            }
+        } catch (RemoteException re) {
+            Rlog.e(TAG, "RcsParticipant: Exception happened during setCanonicalAddress", re);
+        }
+    }
+
+    /**
+     * @return Returns the alias for this participant. Alias is usually the real name of the person
+     * themselves.
+     */
+    public String getAlias() {
+        return mAlias;
+    }
+
+    /**
+     * Sets the alias for this participant and persists it in storage. Alias is usually the real
+     * name of the person themselves.
+     */
+    @WorkerThread
+    public void setAlias(String alias) {
+        if (TextUtils.equals(mAlias, alias)) {
+            return;
+        }
+        mAlias = alias;
+
+        try {
+            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+            if (iRcs != null) {
+                iRcs.updateRcsParticipantAlias(mId, mAlias);
+            }
+        } catch (RemoteException re) {
+            Rlog.e(TAG, "RcsParticipant: Exception happened during setCanonicalAddress", re);
+        }
+    }
+
+    /**
+     * Returns the row id of this participant. This is not meant to be part of the SDK
+     *
+     * @hide
+     */
+    public int getId() {
+        return mId;
+    }
+
+    public static final Creator<RcsParticipant> CREATOR = new Creator<RcsParticipant>() {
+        @Override
+        public RcsParticipant createFromParcel(Parcel in) {
+            return new RcsParticipant(in);
+        }
+
+        @Override
+        public RcsParticipant[] newArray(int size) {
+            return new RcsParticipant[size];
+        }
+    };
+
+    protected RcsParticipant(Parcel in) {
+        mId = in.readInt();
+        mCanonicalAddress = in.readString();
+        mAlias = in.readString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mId);
+        dest.writeString(mCanonicalAddress);
+        dest.writeString(mAlias);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.aidl
new file mode 100644
index 0000000..b9d8190
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsParticipantAliasChangedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
new file mode 100644
index 0000000..b9ca5a8
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * An event that indicates an {@link RcsParticipant}'s alias was changed.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsParticipantAliasChangedEvent extends RcsParticipantEvent {
+    public static final Creator<RcsParticipantAliasChangedEvent> CREATOR =
+            new Creator<RcsParticipantAliasChangedEvent>() {
+        @Override
+        public RcsParticipantAliasChangedEvent createFromParcel(Parcel in) {
+            return new RcsParticipantAliasChangedEvent(in);
+        }
+
+        @Override
+        public RcsParticipantAliasChangedEvent[] newArray(int size) {
+            return new RcsParticipantAliasChangedEvent[size];
+        }
+    };
+
+    protected RcsParticipantAliasChangedEvent(Parcel in) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsParticipantEvent.aidl b/telephony/java/android/telephony/ims/RcsParticipantEvent.aidl
new file mode 100644
index 0000000..c0a7789
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipantEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsParticipantEvent;
diff --git a/telephony/java/android/telephony/ims/RcsParticipantEvent.java b/telephony/java/android/telephony/ims/RcsParticipantEvent.java
new file mode 100644
index 0000000..371b8b7
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipantEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcelable;
+
+/**
+ * An event that is associated with an {@link RcsParticipant}
+ * @hide - TODO(sahinc) make this public
+ */
+public abstract class RcsParticipantEvent implements Parcelable {
+}
diff --git a/telephony/java/android/telephony/ims/RcsTextPart.aidl b/telephony/java/android/telephony/ims/RcsTextPart.aidl
new file mode 100644
index 0000000..4f9fe1f
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsTextPart.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsTextPart;
diff --git a/telephony/java/android/telephony/ims/RcsTextPart.java b/telephony/java/android/telephony/ims/RcsTextPart.java
new file mode 100644
index 0000000..2a72df1
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsTextPart.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * A part of a composite {@link RcsMessage} that holds a string
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsTextPart extends RcsPart {
+    public static final Creator<RcsTextPart> CREATOR = new Creator<RcsTextPart>() {
+        @Override
+        public RcsTextPart createFromParcel(Parcel in) {
+            return new RcsTextPart(in);
+        }
+
+        @Override
+        public RcsTextPart[] newArray(int size) {
+            return new RcsTextPart[size];
+        }
+    };
+
+    protected RcsTextPart(Parcel in) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThread.aidl b/telephony/java/android/telephony/ims/RcsThread.aidl
index 79d4732..d9cf6db 100644
--- a/telephony/java/android/telephony/ims/RcsThread.aidl
+++ b/telephony/java/android/telephony/ims/RcsThread.aidl
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2018, The Android Open Source Project
+ * Copyright 2019, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/telephony/java/android/telephony/ims/RcsThread.java b/telephony/java/android/telephony/ims/RcsThread.java
index b7f440d..c0a0d94 100644
--- a/telephony/java/android/telephony/ims/RcsThread.java
+++ b/telephony/java/android/telephony/ims/RcsThread.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,51 +18,51 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.telephony.ims.aidl.IRcs;
+import android.util.Log;
 
 /**
  * RcsThread represents a single RCS conversation thread. It holds messages that were sent and
- * received and events that occured on that thread.
+ * received and events that occurred on that thread.
  * @hide - TODO(sahinc) make this public
  */
-public class RcsThread implements Parcelable {
+public abstract class RcsThread implements Parcelable {
+    // Since this is an abstract class that gets parcelled, the sub-classes need to write these
+    // magic values into the parcel so that we know which type to unparcel into.
+    protected static final int RCS_1_TO_1_TYPE = 998;
+    protected static final int RCS_GROUP_TYPE = 999;
+
+    protected int mThreadId;
+
+    protected RcsThread(int threadId) {
+        mThreadId = threadId;
+    }
+
+    protected RcsThread(Parcel in) {
+        mThreadId = in.readInt();
+    }
+
     public static final Creator<RcsThread> CREATOR = new Creator<RcsThread>() {
         @Override
         public RcsThread createFromParcel(Parcel in) {
-            return new RcsThread(in);
+            int type = in.readInt();
+
+            switch (type) {
+                case RCS_1_TO_1_TYPE:
+                    return new Rcs1To1Thread(in);
+                case RCS_GROUP_TYPE:
+                    return new RcsGroupThread(in);
+                default:
+                    Log.e(RcsMessageStore.TAG, "Cannot unparcel RcsThread, wrong type: " + type);
+            }
+            return null;
         }
 
         @Override
         public RcsThread[] newArray(int size) {
-            return new RcsThread[size];
+            return new RcsThread[0];
         }
     };
 
-    protected RcsThread(Parcel in) {
-    }
-
-    /**
-     * Returns the number of messages in this RCS thread.
-     *
-     * @hide
-     */
-    public int getMessageCount() {
-        try {
-            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
-            if (iRcs != null) {
-                // TODO(sahinc): substitute to the regular thread id once we have database
-                // TODO(sahinc): connection in place
-                return iRcs.getMessageCount(/* rcsThreadId= */ 123);
-            }
-        } catch (RemoteException re) {
-            // TODO(sahinc): Log something meaningful
-        }
-        return 0;
-    }
-
-    /** Implement the Parcelable interface */
     @Override
     public int describeContents() {
         return 0;
@@ -70,5 +70,6 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mThreadId);
     }
 }
diff --git a/telephony/java/android/telephony/ims/RcsThreadEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadEvent.aidl
new file mode 100644
index 0000000..4a40d89
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsThreadEvent;
diff --git a/telephony/java/android/telephony/ims/RcsThreadEvent.java b/telephony/java/android/telephony/ims/RcsThreadEvent.java
new file mode 100644
index 0000000..e10baab
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcelable;
+
+/**
+ * An event that happened on an {@link RcsThread}.
+ * @hide - TODO(sahinc) make this public
+ */
+public abstract class RcsThreadEvent implements Parcelable {
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
new file mode 100644
index 0000000..82d985d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsThreadIconChangedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.java b/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.java
new file mode 100644
index 0000000..b308fef
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * An event that indicates an {@link RcsGroupThread}'s icon was changed.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsThreadIconChangedEvent extends RcsThreadEvent {
+    public static final Creator<RcsThreadIconChangedEvent> CREATOR =
+            new Creator<RcsThreadIconChangedEvent>() {
+        @Override
+        public RcsThreadIconChangedEvent createFromParcel(Parcel in) {
+            return new RcsThreadIconChangedEvent(in);
+        }
+
+        @Override
+        public RcsThreadIconChangedEvent[] newArray(int size) {
+            return new RcsThreadIconChangedEvent[size];
+        }
+    };
+
+    protected RcsThreadIconChangedEvent(Parcel in) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.aidl
new file mode 100644
index 0000000..54a311d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsThreadNameChangedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.java b/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.java
new file mode 100644
index 0000000..6f5cfdf
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * An event that indicates an {@link RcsGroupThread}'s name was changed.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsThreadNameChangedEvent extends RcsThreadEvent {
+    public static final Creator<RcsThreadNameChangedEvent> CREATOR =
+            new Creator<RcsThreadNameChangedEvent>() {
+        @Override
+        public RcsThreadNameChangedEvent createFromParcel(Parcel in) {
+            return new RcsThreadNameChangedEvent(in);
+        }
+
+        @Override
+        public RcsThreadNameChangedEvent[] newArray(int size) {
+            return new RcsThreadNameChangedEvent[size];
+        }
+    };
+
+    protected RcsThreadNameChangedEvent(Parcel in) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.aidl
new file mode 100644
index 0000000..047a424
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsThreadParticipantJoinedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.java b/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.java
new file mode 100644
index 0000000..5c4073c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * An event that indicates an RCS participant has joined an {@link RcsGroupThread}.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsThreadParticipantJoinedEvent extends RcsThreadEvent {
+    public static final Creator<RcsThreadParticipantJoinedEvent> CREATOR =
+            new Creator<RcsThreadParticipantJoinedEvent>() {
+        @Override
+        public RcsThreadParticipantJoinedEvent createFromParcel(Parcel in) {
+            return new RcsThreadParticipantJoinedEvent(in);
+        }
+
+        @Override
+        public RcsThreadParticipantJoinedEvent[] newArray(int size) {
+            return new RcsThreadParticipantJoinedEvent[size];
+        }
+    };
+
+    protected RcsThreadParticipantJoinedEvent(Parcel in) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.aidl
new file mode 100644
index 0000000..52f9bbd
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+parcelable RcsThreadParticipantLeftEvent;
diff --git a/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.java b/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.java
new file mode 100644
index 0000000..4bf86b9
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * An event that indicates an RCS participant has left an {@link RcsGroupThread}.
+ * @hide - TODO(sahinc) make this public
+ */
+public class RcsThreadParticipantLeftEvent extends RcsThreadEvent {
+    public static final Creator<RcsThreadParticipantLeftEvent> CREATOR =
+            new Creator<RcsThreadParticipantLeftEvent>() {
+        @Override
+        public RcsThreadParticipantLeftEvent createFromParcel(Parcel in) {
+            return new RcsThreadParticipantLeftEvent(in);
+        }
+
+        @Override
+        public RcsThreadParticipantLeftEvent[] newArray(int size) {
+            return new RcsThreadParticipantLeftEvent[size];
+        }
+    };
+
+    protected RcsThreadParticipantLeftEvent(Parcel in) {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.aidl b/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.aidl
new file mode 100644
index 0000000..7bcebfa
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** 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.ims;
+
+parcelable RcsThreadQueryContinuationToken;
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.java b/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.java
new file mode 100644
index 0000000..931e93d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.java
@@ -0,0 +1,52 @@
+/*
+ * 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.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A continuation token to provide for {@link RcsMessageStore#getRcsThreads}. Use this token to
+ * break large queries into manageable chunks
+ * @hide - TODO make this public
+ */
+public class RcsThreadQueryContinuationToken implements Parcelable {
+    protected RcsThreadQueryContinuationToken(Parcel in) {
+    }
+
+    public static final Creator<RcsThreadQueryContinuationToken> CREATOR =
+            new Creator<RcsThreadQueryContinuationToken>() {
+                @Override
+                public RcsThreadQueryContinuationToken createFromParcel(Parcel in) {
+                    return new RcsThreadQueryContinuationToken(in);
+                }
+
+                @Override
+                public RcsThreadQueryContinuationToken[] newArray(int size) {
+                    return new RcsThreadQueryContinuationToken[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryParameters.aidl b/telephony/java/android/telephony/ims/RcsThreadQueryParameters.aidl
new file mode 100644
index 0000000..feb2d4d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryParameters.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** 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.ims;
+
+parcelable RcsThreadQueryParameters;
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryParameters.java b/telephony/java/android/telephony/ims/RcsThreadQueryParameters.java
new file mode 100644
index 0000000..f2c4ab1
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryParameters.java
@@ -0,0 +1,225 @@
+/*
+ * 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.ims;
+
+import android.annotation.CheckResult;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.security.InvalidParameterException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * The parameters to pass into {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParameters)} in
+ * order to select a subset of {@link RcsThread}s present in the message store.
+ * @hide TODO - make the Builder and builder() public. The rest should stay internal only.
+ */
+public class RcsThreadQueryParameters implements Parcelable {
+    private final boolean mIsGroup;
+    private final Set<RcsParticipant> mRcsParticipants;
+    private final int mLimit;
+    private final boolean mIsAscending;
+
+    RcsThreadQueryParameters(boolean isGroup, Set<RcsParticipant> participants, int limit,
+            boolean isAscending) {
+        mIsGroup = isGroup;
+        mRcsParticipants = participants;
+        mLimit = limit;
+        mIsAscending = isAscending;
+    }
+
+    /**
+     * Returns a new builder to build a query with.
+     * TODO - make public
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
+     * the list of participants.
+     * @hide
+     */
+    public Set<RcsParticipant> getRcsParticipants() {
+        return mRcsParticipants;
+    }
+
+    /**
+     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
+     * whether group threads should be queried
+     * @hide
+     */
+    public boolean isGroupThread() {
+        return mIsGroup;
+    }
+
+    /**
+     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
+     * the number of tuples the result query should be limited to.
+     */
+    public int getLimit() {
+        return mLimit;
+    }
+
+    /**
+     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to
+     * determine the sort order.
+     */
+    public boolean isAscending() {
+        return mIsAscending;
+    }
+
+    /**
+     * A helper class to build the {@link RcsThreadQueryParameters}.
+     */
+    public static class Builder {
+        private boolean mIsGroupThread;
+        private Set<RcsParticipant> mParticipants;
+        private int mLimit = 100;
+        private boolean mIsAscending;
+
+        /**
+         * Package private constructor for {@link RcsThreadQueryParameters.Builder}. To obtain this,
+         * {@link RcsThreadQueryParameters#builder()} needs to be called.
+         */
+        Builder() {
+            mParticipants = new HashSet<>();
+        }
+
+        /**
+         * Limits the query to only return group threads.
+         * @param isGroupThread Whether to limit the query result to group threads.
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder isGroupThread(boolean isGroupThread) {
+            mIsGroupThread = isGroupThread;
+            return this;
+        }
+
+        /**
+         * Limits the query to only return threads that contain the given participant.
+         * @param participant The participant that must be included in all of the returned threads.
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder withParticipant(RcsParticipant participant) {
+            mParticipants.add(participant);
+            return this;
+        }
+
+        /**
+         * Limits the query to only return threads that contain the given list of participants.
+         * @param participants An iterable list of participants that must be included in all of the
+         *                     returned threads.
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder withParticipants(Iterable<RcsParticipant> participants) {
+            for (RcsParticipant participant : participants) {
+                mParticipants.add(participant);
+            }
+            return this;
+        }
+
+        /**
+         * Desired number of threads to be returned from the query. Passing in 0 will return all
+         * existing threads at once. The limit defaults to 100.
+         * @param limit The number to limit the query result to.
+         * @return The same instance of the builder to chain parameters.
+         * @throws InvalidParameterException If the given limit is negative.
+         */
+        @CheckResult
+        public Builder limitResultsTo(int limit) throws InvalidParameterException {
+            if (limit < 0) {
+                throw new InvalidParameterException("The query limit must be non-negative");
+            }
+
+            mLimit = limit;
+            return this;
+        }
+
+        /**
+         * Sorts the results returned from the query via thread IDs.
+         *
+         * TODO - add sorting support for other fields
+         *
+         * @param isAscending whether to sort in ascending order or not
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder sort(boolean isAscending) {
+            mIsAscending = isAscending;
+            return this;
+        }
+
+        /**
+         * Builds the {@link RcsThreadQueryParameters} to use in
+         * {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParameters)}
+         *
+         * @return An instance of {@link RcsThreadQueryParameters} to use with the thread query.
+         */
+        public RcsThreadQueryParameters build() {
+            return new RcsThreadQueryParameters(
+                    mIsGroupThread, mParticipants, mLimit, mIsAscending);
+        }
+    }
+
+    /**
+     * Parcelable boilerplate below.
+     */
+    protected RcsThreadQueryParameters(Parcel in) {
+        mIsGroup = in.readBoolean();
+
+        ArrayList<RcsParticipant> participantArrayList = new ArrayList<>();
+        in.readTypedList(participantArrayList, RcsParticipant.CREATOR);
+        mRcsParticipants = new HashSet<>(participantArrayList);
+
+        mLimit = in.readInt();
+        mIsAscending = in.readBoolean();
+    }
+
+    public static final Creator<RcsThreadQueryParameters> CREATOR =
+            new Creator<RcsThreadQueryParameters>() {
+                @Override
+                public RcsThreadQueryParameters createFromParcel(Parcel in) {
+                    return new RcsThreadQueryParameters(in);
+                }
+
+                @Override
+                public RcsThreadQueryParameters[] newArray(int size) {
+                    return new RcsThreadQueryParameters[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeBoolean(mIsGroup);
+        dest.writeTypedList(new ArrayList<>(mRcsParticipants));
+        dest.writeInt(mLimit);
+        dest.writeBoolean(mIsAscending);
+    }
+
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl b/telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl
new file mode 100644
index 0000000..4b06529
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** 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.ims;
+
+parcelable RcsThreadQueryResult;
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResult.java b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
new file mode 100644
index 0000000..47715f8
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
@@ -0,0 +1,92 @@
+/*
+ * 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.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * The result of a {@link RcsMessageStore#getRcsThreads(RcsThreadQueryContinuationToken,
+ * RcsThreadQueryParameters)}
+ * call. This class allows getting the token for querying the next batch of threads in order to
+ * prevent handling large amounts of data at once.
+ *
+ * @hide
+ */
+public class RcsThreadQueryResult implements Parcelable {
+    private RcsThreadQueryContinuationToken mContinuationToken;
+    private List<RcsThread> mRcsThreads;
+
+    /**
+     * Internal constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController}
+     * to create query results
+     *
+     * @hide
+     */
+    public RcsThreadQueryResult(
+            RcsThreadQueryContinuationToken continuationToken, List<RcsThread> rcsThreads) {
+        mContinuationToken = continuationToken;
+        mRcsThreads = rcsThreads;
+    }
+
+    /**
+     * Returns a token to call
+     * {@link RcsMessageStore#getRcsThreads(RcsThreadQueryContinuationToken)}
+     * to get the next batch of {@link RcsThread}s.
+     */
+    public RcsThreadQueryContinuationToken nextChunkToken() {
+        return mContinuationToken;
+    }
+
+    /**
+     * Returns all the RcsThreads in the current query result. Call {@link
+     * RcsMessageStore#getRcsThreads(RcsThreadQueryContinuationToken)} to get the next batch of
+     * {@link RcsThread}s.
+     */
+    public List<RcsThread> getThreads() {
+        return mRcsThreads;
+    }
+
+    protected RcsThreadQueryResult(Parcel in) {
+        // TODO - implement
+    }
+
+    public static final Creator<RcsThreadQueryResult> CREATOR =
+            new Creator<RcsThreadQueryResult>() {
+                @Override
+                public RcsThreadQueryResult createFromParcel(Parcel in) {
+                    return new RcsThreadQueryResult(in);
+                }
+
+                @Override
+                public RcsThreadQueryResult[] newArray(int size) {
+                    return new RcsThreadQueryResult[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        // TODO - implement
+    }
+}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
index f25b4b1..d64e67a 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
@@ -16,6 +16,7 @@
 
 package android.telephony.ims.aidl;
 
+import android.telephony.CallQuality;
 import android.telephony.ims.ImsStreamMediaProfile;
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsReasonInfo;
@@ -126,16 +127,29 @@
      */
     void callSessionRttModifyRequestReceived(in ImsCallProfile callProfile);
 
-    /* Device issued RTT modify request and inturn received response
+    /**
+     * Device issued RTT modify request and inturn received response
      * from Remote UE
      * @param status Will be one of the following values from:
      * - {@link Connection.RttModifyStatus}
      */
     void callSessionRttModifyResponseReceived(int status);
 
-    /*
+    /**
      * While in call, device received RTT message from Remote UE
      * @param rttMessage Received RTT message
      */
     void callSessionRttMessageReceived(in String rttMessage);
+
+    /**
+     * While in call, there has been a change in RTT audio indicator.
+     * @param profile updated ImsStreamMediaProfile
+     */
+    void callSessionRttAudioIndicatorChanged(in ImsStreamMediaProfile profile);
+
+    /**
+     * Notifies of a change to the call quality.
+     * @param callQuality then updated call quality
+     */
+    void callQualityChanged(in CallQuality callQuality);
 }
diff --git a/telephony/java/android/telephony/ims/aidl/IRcs.aidl b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
index b2e2fad..0c958ba 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcs.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
@@ -16,14 +16,34 @@
 
 package android.telephony.ims.aidl;
 
+import android.telephony.ims.RcsParticipant;
+import android.telephony.ims.Rcs1To1Thread;
+import android.telephony.ims.RcsThreadQueryContinuationToken;
+import android.telephony.ims.RcsThreadQueryParameters;
+import android.telephony.ims.RcsThreadQueryResult;
+
 /**
  * RPC definition between RCS storage APIs and phone process.
  * {@hide}
  */
 interface IRcs {
     // RcsMessageStore APIs
+    RcsThreadQueryResult getRcsThreads(in RcsThreadQueryParameters queryParameters);
+
+    RcsThreadQueryResult getRcsThreadsWithToken(
+        in RcsThreadQueryContinuationToken continuationToken);
+
     void deleteThread(int threadId);
 
+    Rcs1To1Thread createRcs1To1Thread(in RcsParticipant participant);
+
     // RcsThread APIs
     int getMessageCount(int rcsThreadId);
+
+    // RcsParticipant APIs
+    RcsParticipant createRcsParticipant(String canonicalAddress);
+
+    void updateRcsParticipantCanonicalAddress(int id, String canonicalAddress);
+
+    void updateRcsParticipantAlias(int id, String alias);
 }
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
index 23de2fd..38566fe 100644
--- a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
@@ -18,19 +18,18 @@
 
 import android.os.Message;
 import android.os.RemoteException;
-
+import android.telephony.CallQuality;
 import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsCallSession;
 import android.telephony.ims.ImsConferenceState;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ImsStreamMediaProfile;
 import android.telephony.ims.ImsSuppServiceNotification;
 import android.telephony.ims.aidl.IImsCallSessionListener;
+
 import com.android.ims.internal.IImsCallSession;
 import com.android.ims.internal.IImsVideoCallProvider;
 
-import android.annotation.UnsupportedAppUsage;
-import android.telephony.ims.ImsCallSession;
-
 /**
  * Compat implementation of ImsCallSessionImplBase for older implementations.
  *
@@ -591,5 +590,16 @@
         public void callSessionRttMessageReceived(String rttMessage) throws RemoteException {
             mNewListener.callSessionRttMessageReceived(rttMessage);
         }
+
+        @Override
+        public void callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile)
+                throws RemoteException {
+            mNewListener.callSessionRttAudioIndicatorChanged(profile);
+        }
+
+        @Override
+        public void callQualityChanged(CallQuality callQuality) throws RemoteException {
+            mNewListener.callQualityChanged(callQuality);
+        }
     }
 }
diff --git a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
index a8e8b7dd..579369f 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
@@ -16,6 +16,7 @@
 
 package com.android.ims.internal;
 
+import android.telephony.CallQuality;
 import android.telephony.ims.ImsStreamMediaProfile;
 import android.telephony.ims.ImsCallProfile;
 import android.telephony.ims.ImsReasonInfo;
@@ -140,16 +141,29 @@
     void callSessionRttModifyRequestReceived(in IImsCallSession session,
             in ImsCallProfile callProfile);
 
-    /* Device issued RTT modify request and inturn received response
+    /**
+     * Device issued RTT modify request and inturn received response
      * from Remote UE
      * @param status Will be one of the following values from:
      * - {@link Connection.RttModifyStatus}
      */
     void callSessionRttModifyResponseReceived(in int status);
 
-    /*
+    /**
      * While in call, device received RTT message from Remote UE
      * @param rttMessage Received RTT message
      */
     void callSessionRttMessageReceived(in String rttMessage);
+
+    /**
+     * While in call, there has been a change in RTT audio indicator.
+     * @param profile updated ImsStreamMediaProfile
+     */
+    void callSessionRttAudioIndicatorChanged(in ImsStreamMediaProfile profile);
+
+    /**
+     * Notifies of a change to the call quality.
+     * @param callQuality then updated call quality
+     */
+    void callQualityChanged(in CallQuality callQuality);
 }
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 96f7a1b..6e8d038 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -66,7 +66,8 @@
     public static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9;
     public static final int EVENT_ROAMING_ON = BASE + 11;
     public static final int EVENT_ROAMING_OFF = BASE + 12;
-    public static final int EVENT_ENABLE_NEW_APN = BASE + 13;
+    public static final int EVENT_ENABLE_APN = BASE + 13;
+    public static final int EVENT_DISABLE_APN = BASE + 14;
     public static final int EVENT_DISCONNECT_DONE = BASE + 15;
     public static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16;
     public static final int EVENT_DATA_STALL_ALARM = BASE + 17;
@@ -86,12 +87,13 @@
     public static final int CMD_NET_STAT_POLL = BASE + 40;
     public static final int EVENT_DATA_RAT_CHANGED = BASE + 41;
     public static final int CMD_CLEAR_PROVISIONING_SPINNER = BASE + 42;
-    public static final int EVENT_REDIRECTION_DETECTED = BASE + 44;
+    public static final int EVENT_NETWORK_STATUS_CHANGED = BASE + 44;
     public static final int EVENT_PCO_DATA_RECEIVED = BASE + 45;
     public static final int EVENT_DATA_ENABLED_CHANGED = BASE + 46;
     public static final int EVENT_DATA_RECONNECT = BASE + 47;
     public static final int EVENT_ROAMING_SETTING_CHANGE = BASE + 48;
     public static final int EVENT_DATA_SERVICE_BINDING_CHANGED = BASE + 49;
+    public static final int EVENT_DEVICE_PROVISIONED_CHANGE = BASE + 50;
 
     /***** Constants *****/
 
diff --git a/telephony/java/com/android/internal/telephony/IAns.aidl b/telephony/java/com/android/internal/telephony/IAns.aidl
deleted file mode 100755
index 98bcd41..0000000
--- a/telephony/java/com/android/internal/telephony/IAns.aidl
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import android.telephony.AvailableNetworkInfo;
-
-interface IAns {
-
-    /**
-    * Enable or disable Alternative Network service.
-    *
-    * This method should be called to enable or disable
-    * AlternativeNetwork service on the device.
-    *
-    * <p>
-    * Requires Permission:
-    *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
-    * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
-    *
-    * @param enable enable(True) or disable(False)
-    * @param callingPackage caller's package name
-    * @return returns true if successfully set.
-    */
-    boolean setEnable(boolean enable, String callingPackage);
-
-    /**
-     * is Alternative Network service enabled
-     *
-     * This method should be called to determine if the Alternative Network service is enabled
-    *
-    * <p>
-    * Requires Permission:
-    *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
-    * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
-    *
-    * @param callingPackage caller's package name
-    */
-    boolean isEnabled(String callingPackage);
-
-    /**
-     * Set preferred opportunistic data subscription id.
-     *
-     * <p>Requires that the calling app has carrier privileges on both primary and
-     * secondary subscriptions (see
-     * {@link #hasCarrierPrivileges}), or has permission
-     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
-     *
-     * @param subId which opportunistic subscription
-     * {@link SubscriptionManager#getOpportunisticSubscriptions} is preferred for cellular data.
-     * Pass {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} to unset the preference
-     * @param callingPackage caller's package name
-     * @return true if request is accepted, else false.
-     *
-     */
-    boolean setPreferredData(int subId, String callingPackage);
-
-    /**
-     * Get preferred opportunistic data subscription Id
-     *
-     * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}),
-     * or has permission {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}.
-     * @return subId preferred opportunistic subscription id or
-     * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} if there are no preferred
-     * subscription id
-     *
-     */
-    int getPreferredData(String callingPackage);
-
-    /**
-     * Update availability of a list of networks in the current location.
-     *
-     * This api should be called if the caller is aware of the availability of a network
-     * at the current location. This information will be used by AlternativeNetwork service
-     * to decide to attach to the network. If an empty list is passed,
-     * it is assumed that no network is available.
-     * Requires that the calling app has carrier privileges on both primary and
-     * secondary subscriptions (see
-     * {@link #hasCarrierPrivileges}), or has permission
-     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
-     *  @param availableNetworks is a list of available network information.
-     *  @param callingPackage caller's package name
-     *  @return true if request is accepted
-     *
-     */
-    boolean updateAvailableNetworks(in List<AvailableNetworkInfo> availableNetworks,
-            String callingPackage);
-}
diff --git a/telephony/java/com/android/internal/telephony/IOns.aidl b/telephony/java/com/android/internal/telephony/IOns.aidl
new file mode 100755
index 0000000..0e3d12b
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IOns.aidl
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.telephony.AvailableNetworkInfo;
+
+interface IOns {
+
+    /**
+    * Enable or disable Opportunistic Network service.
+    *
+    * This method should be called to enable or disable
+    * OpportunisticNetwork service on the device.
+    *
+    * <p>
+    * Requires Permission:
+    *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+    * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+    *
+    * @param enable enable(True) or disable(False)
+    * @param callingPackage caller's package name
+    * @return returns true if successfully set.
+    */
+    boolean setEnable(boolean enable, String callingPackage);
+
+    /**
+     * is Opportunistic Network service enabled
+     *
+     * This method should be called to determine if the Opportunistic Network service is enabled
+    *
+    * <p>
+    * Requires Permission:
+    *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+    * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+    *
+    * @param callingPackage caller's package name
+    */
+    boolean isEnabled(String callingPackage);
+
+    /**
+     * Set preferred opportunistic data subscription id.
+     *
+     * <p>Requires that the calling app has carrier privileges on both primary and
+     * secondary subscriptions (see
+     * {@link #hasCarrierPrivileges}), or has permission
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     *
+     * @param subId which opportunistic subscription
+     * {@link SubscriptionManager#getOpportunisticSubscriptions} is preferred for cellular data.
+     * Pass {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} to unset the preference
+     * @param callingPackage caller's package name
+     * @return true if request is accepted, else false.
+     *
+     */
+    boolean setPreferredDataSubscriptionId(int subId, String callingPackage);
+
+    /**
+     * Get preferred opportunistic data subscription Id
+     *
+     * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}),
+     * or has permission {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}.
+     * @return subId preferred opportunistic subscription id or
+     * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} if there are no preferred
+     * subscription id
+     *
+     */
+    int getPreferredDataSubscriptionId(String callingPackage);
+
+    /**
+     * Update availability of a list of networks in the current location.
+     *
+     * This api should be called if the caller is aware of the availability of a network
+     * at the current location. This information will be used by OpportunisticNetwork service
+     * to decide to attach to the network. If an empty list is passed,
+     * it is assumed that no network is available.
+     * Requires that the calling app has carrier privileges on both primary and
+     * secondary subscriptions (see
+     * {@link #hasCarrierPrivileges}), or has permission
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     *  @param availableNetworks is a list of available network information.
+     *  @param callingPackage caller's package name
+     *  @return true if request is accepted
+     *
+     */
+    boolean updateAvailableNetworks(in List<AvailableNetworkInfo> availableNetworks,
+            String callingPackage);
+}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 00cf9c3..3dbebe8 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -17,14 +17,15 @@
 package com.android.internal.telephony;
 
 import android.os.Bundle;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
+import android.telephony.CallAttributes;
 import android.telephony.CellInfo;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.PhoneCapability;
 import android.telephony.PhysicalChannelConfig;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
 import android.telephony.emergency.EmergencyNumber;
 
 oneway interface IPhoneStateListener {
@@ -54,6 +55,7 @@
     void onPhoneCapabilityChanged(in PhoneCapability capability);
     void onPreferredDataSubIdChanged(in int subId);
     void onRadioPowerStateChanged(in int state);
+    void onCallAttributesChanged(in CallAttributes callAttributes);
     void onEmergencyNumberListChanged(in Map emergencyNumberList);
     void onCallDisconnectCauseChanged(in int disconnectCause, in int preciseDisconnectCause);
 }
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index d169b7d..a49d2d9 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -52,8 +52,8 @@
     /**
      * Get the active SubscriptionInfo associated with the slotIndex
      * @param slotIndex the slot which the subscription is inserted
-     * @param callingPackage The package maing the call.
-     * @return SubscriptionInfo, maybe null if its not active
+     * @param callingPackage The package making the call.
+     * @return SubscriptionInfo, null for Remote-SIMs or non-active slotIndex.
      */
     SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, String callingPackage);
 
@@ -115,6 +115,26 @@
     int addSubInfoRecord(String iccId, int slotIndex);
 
     /**
+     * Add a new subscription info record, if needed
+     * @param uniqueId This is the unique identifier for the subscription within the specific
+     *                 subscription type.
+     * @param displayName human-readable name of the device the subscription corresponds to.
+     * @param slotIndex the slot assigned to this device
+     * @param subscriptionType the type of subscription to be added.
+     * @return 0 if success, < 0 on error.
+     */
+    int addSubInfo(String uniqueId, String displayName, int slotIndex, int subscriptionType);
+
+    /**
+     * Remove subscription info record for the given device.
+     * @param uniqueId This is the unique identifier for the subscription within the specific
+     *                      subscription type.
+     * @param subscriptionType the type of subscription to be removed
+     * @return 0 if success, < 0 on error.
+     */
+    int removeSubInfo(String uniqueId, int subscriptionType);
+
+    /**
      * Set SIM icon tint color by simInfo index
      * @param tint the icon tint color of the SIM
      * @param subId the unique SubscriptionInfo index in database
@@ -200,7 +220,15 @@
      * @hide
      *
      */
-    int setPreferredData(int subId);
+    int setPreferredDataSubscriptionId(int subId);
+
+    /**
+     * Get which subscription is preferred for cellular data.
+     *
+     * @hide
+     *
+     */
+    int getPreferredDataSubscriptionId();
 
     /**
      * Get User downloaded Profiles.
@@ -248,6 +276,11 @@
 
     String getSubscriptionProperty(int subId, String propKey, String callingPackage);
 
+    boolean setSubscriptionEnabled(boolean enable, int subId);
+
+    boolean isSubscriptionEnabled(int subId);
+
+    int getEnabledSubscriptionId(int slotIndex);
     /**
      * Get the SIM state for the slot index
      * @return SIM state as the ordinal of IccCardConstants.State
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index c5d82c5..9cc173c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -28,6 +28,7 @@
 import android.service.carrier.CarrierIdentifier;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telephony.CarrierRestrictionRules;
 import android.telephony.CellInfo;
 import android.telephony.ClientRequestStats;
 import android.telephony.IccOpenLogicalChannelResponse;
@@ -41,6 +42,7 @@
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyHistogram;
 import android.telephony.VisualVoicemailSmsFilterSettings;
+import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.aidl.IImsConfig;
 import android.telephony.ims.aidl.IImsConfigCallback;
@@ -1176,12 +1178,12 @@
     void factoryReset(int subId);
 
     /**
-     * An estimate of the users's current locale based on the default SIM.
+     * Returns users's current locale based on the SIM.
      *
      * The returned string will be a well formed BCP-47 language tag, or {@code null}
      * if no locale could be derived.
      */
-    String getLocaleFromDefaultSim();
+    String getSimLocaleForSubscriber(int subId);
 
     /**
      * Requests the modem activity info asynchronously.
@@ -1292,22 +1294,27 @@
     List<TelephonyHistogram> getTelephonyHistograms();
 
     /**
-     * Set the allowed carrier list for slotIndex
-     * Require system privileges. In the future we may add this to carrier APIs.
+     * Set the allowed carrier list and the excluded carrier list, indicating the priority between
+     * the two lists.
      *
-     * @return The number of carriers set successfully. Should match length of
-     * carriers on success.
+     * <p>Requires system privileges. In the future we may add this to carrier APIs.
+     *
+     * @return {@link #SET_CARRIER_RESTRICTION_SUCCESS} in case of success.
+     * {@link #SET_CARRIER_RESTRICTION_NOT_SUPPORTED} if the modem does not support the
+     * configuration. {@link #SET_CARRIER_RESTRICTION_ERROR} in all other error cases.
      */
-    int setAllowedCarriers(int slotIndex, in List<CarrierIdentifier> carriers);
+    int setAllowedCarriers(in CarrierRestrictionRules carrierRestrictionRules);
 
     /**
-     * Get the allowed carrier list for slotIndex.
-     * Require system privileges. In the future we may add this to carrier APIs.
+     * Get the allowed carrier list and the excluded carrier list indicating the priority between
+     * the two lists.
      *
-     * @return List of {@link android.service.carrier.CarrierIdentifier}; empty list
-     * means all carriers are allowed.
+     * <p>Requires system privileges. In the future we may add this to carrier APIs.
+     *
+     * @return {@link CarrierRestrictionRules}; empty lists mean all carriers are allowed. It
+     * returns null in case of error.
      */
-    List<CarrierIdentifier> getAllowedCarriers(int slotIndex);
+    CarrierRestrictionRules getAllowedCarriers();
 
    /**
      * Returns carrier id of the given subscription.
@@ -1776,4 +1783,19 @@
      * Set the String provisioning value for the provisioning key specified.
      */
     int setImsProvisioningString(int subId, int key, String value);
+
+    /**
+     * Update Emergency Number List for Test Mode.
+     */
+    void updateEmergencyNumberListTestMode(int action, in EmergencyNumber num);
+
+    /**
+     * Get the full emergency number list for Test Mode.
+     */
+    List<String> getEmergencyNumberListTestMode();
+
+    /**
+     * Enable or disable a logical modem stack associated with the slotIndex.
+     */
+    boolean enableModemForSlot(int slotIndex, boolean enable);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index d9f5c3f..2be1f41 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -20,6 +20,7 @@
 import android.net.LinkProperties;
 import android.net.NetworkCapabilities;
 import android.os.Bundle;
+import android.telephony.CallQuality;
 import android.telephony.CellInfo;
 import android.telephony.PhoneCapability;
 import android.telephony.PhysicalChannelConfig;
@@ -50,13 +51,13 @@
     void notifyDataActivity(int state);
     void notifyDataActivityForSubscriber(in int subId, int state);
     void notifyDataConnection(int state, boolean isDataConnectivityPossible,
-            String reason, String apn, String apnType, in LinkProperties linkProperties,
+            String apn, String apnType, in LinkProperties linkProperties,
             in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
     void notifyDataConnectionForSubscriber(int subId, int state, boolean isDataConnectivityPossible,
-            String reason, String apn, String apnType, in LinkProperties linkProperties,
+            String apn, String apnType, in LinkProperties linkProperties,
             in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
-    void notifyDataConnectionFailed(String reason, String apnType);
-    void notifyDataConnectionFailedForSubscriber(int subId, String reason, String apnType);
+    void notifyDataConnectionFailed(String apnType);
+    void notifyDataConnectionFailedForSubscriber(int subId, String apnType);
     void notifyCellLocation(in Bundle cellLocation);
     void notifyCellLocationForSubscriber(in int subId, in Bundle cellLocation);
     void notifyOtaspChanged(in int otaspMode);
@@ -65,10 +66,10 @@
     void notifyPhysicalChannelConfigurationForSubscriber(in int subId,
             in List<PhysicalChannelConfig> configs);
     void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
-            int backgroundCallState);
+            int backgroundCallState, int phoneId);
     void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause);
-    void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
-            String failCause);
+    void notifyPreciseDataConnectionFailed(String apnType, String apn,
+            int failCause);
     void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
     void notifySrvccStateChanged(in int subId, in int lteState);
     void notifySimActivationStateChangedForPhoneId(in int phoneId, in int subId,
@@ -82,4 +83,5 @@
     void notifyPreferredDataSubIdChanged(int preferredSubId);
     void notifyRadioPowerStateChanged(in int state);
     void notifyEmergencyNumberList();
+    void notifyCallQualityChanged(in CallQuality callQuality, int phoneId);
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 21f3b92..e87d28c 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -79,8 +79,6 @@
     public static final int SIM_ACTIVATION_TYPE_DATA = 1;
 
     public static final String PHONE_NAME_KEY = "phoneName";
-    public static final String FAILURE_REASON_KEY = "reason";
-    public static final String STATE_CHANGE_REASON_KEY = "reason";
     public static final String DATA_NETWORK_TYPE_KEY = "networkType";
     public static final String DATA_FAILURE_CAUSE_KEY = "failCause";
     public static final String DATA_APN_TYPE_KEY = "apnType";
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 1c103a9..9300034 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -489,6 +489,7 @@
     int RIL_REQUEST_STOP_NETWORK_SCAN = 143;
     int RIL_REQUEST_START_KEEPALIVE = 144;
     int RIL_REQUEST_STOP_KEEPALIVE = 145;
+    int RIL_REQUEST_ENABLE_MODEM = 146;
 
     /* The following requests are not defined in RIL.h */
     int RIL_REQUEST_HAL_NON_RIL_BASE = 200;
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index 9874f80..a508b06 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -18,6 +18,8 @@
 
 import android.Manifest.permission;
 import android.app.AppOpsManager;
+import android.app.role.RoleManager;
+import android.app.role.RoleManagerCallback;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -29,13 +31,12 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Debug;
 import android.os.Process;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.Rlog;
@@ -50,6 +51,10 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Class for managing the primary application that we will deliver SMS/MMS messages to
@@ -67,6 +72,7 @@
     private static final String SCHEME_SMSTO = "smsto";
     private static final String SCHEME_MMS = "mms";
     private static final String SCHEME_MMSTO = "mmsto";
+    private static final boolean DEBUG = false;
     private static final boolean DEBUG_MULTIUSER = false;
 
     private static final int[] DEFAULT_APP_EXCLUSIVE_APPOPS = {
@@ -240,7 +246,11 @@
 
         // Get the list of apps registered for SMS
         Intent intent = new Intent(Intents.SMS_DELIVER_ACTION);
-        List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
+        if (DEBUG) {
+            intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
+        }
+        List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceiversAsUser(intent,
+                PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                 userId);
 
         HashMap<String, SmsApplicationData> receivers = new HashMap<String, SmsApplicationData>();
@@ -266,7 +276,8 @@
         // Update any existing entries with mms receiver class
         intent = new Intent(Intents.WAP_PUSH_DELIVER_ACTION);
         intent.setDataAndType(null, "application/vnd.wap.mms-message");
-        List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
+        List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceiversAsUser(intent,
+                PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                 userId);
         for (ResolveInfo resolveInfo : mmsReceivers) {
             final ActivityInfo activityInfo = resolveInfo.activityInfo;
@@ -286,7 +297,8 @@
         // Update any existing entries with respond via message intent class.
         intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE,
                 Uri.fromParts(SCHEME_SMSTO, "", null));
-        List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent, 0,
+        List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent,
+                PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                 userId);
         for (ResolveInfo resolveInfo : respondServices) {
             final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
@@ -306,7 +318,8 @@
         // Update any existing entries with supports send to.
         intent = new Intent(Intent.ACTION_SENDTO,
                 Uri.fromParts(SCHEME_SMSTO, "", null));
-        List<ResolveInfo> sendToActivities = packageManager.queryIntentActivitiesAsUser(intent, 0,
+        List<ResolveInfo> sendToActivities = packageManager.queryIntentActivitiesAsUser(intent,
+                PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                 userId);
         for (ResolveInfo resolveInfo : sendToActivities) {
             final ActivityInfo activityInfo = resolveInfo.activityInfo;
@@ -323,7 +336,9 @@
         // Update any existing entries with the default sms changed handler.
         intent = new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
         List<ResolveInfo> smsAppChangedReceivers =
-                packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
+                packageManager.queryBroadcastReceiversAsUser(intent,
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
         if (DEBUG_MULTIUSER) {
             Log.i(LOG_TAG, "getApplicationCollectionInternal smsAppChangedActivities=" +
                     smsAppChangedReceivers);
@@ -348,7 +363,9 @@
         // Update any existing entries with the external provider changed handler.
         intent = new Intent(Telephony.Sms.Intents.ACTION_EXTERNAL_PROVIDER_CHANGE);
         List<ResolveInfo> providerChangedReceivers =
-                packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
+                packageManager.queryBroadcastReceiversAsUser(intent,
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
         if (DEBUG_MULTIUSER) {
             Log.i(LOG_TAG, "getApplicationCollectionInternal providerChangedActivities=" +
                     providerChangedReceivers);
@@ -373,7 +390,9 @@
         // Update any existing entries with the sim full handler.
         intent = new Intent(Intents.SIM_FULL_ACTION);
         List<ResolveInfo> simFullReceivers =
-                packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
+                packageManager.queryBroadcastReceiversAsUser(intent,
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
         if (DEBUG_MULTIUSER) {
             Log.i(LOG_TAG, "getApplicationCollectionInternal simFullReceivers="
                     + simFullReceivers);
@@ -406,7 +425,8 @@
             if (smsApplicationData != null) {
                 if (!smsApplicationData.isComplete()) {
                     Log.w(LOG_TAG, "Package " + packageName
-                            + " lacks required manifest declarations to be a default sms app");
+                            + " lacks required manifest declarations to be a default sms app: "
+                            + smsApplicationData);
                     receivers.remove(packageName);
                 }
             }
@@ -418,7 +438,7 @@
      * Checks to see if we have a valid installed SMS application for the specified package name
      * @return Data for the specified package name or null if there isn't one
      */
-    private static SmsApplicationData getApplicationForPackage(
+    public static SmsApplicationData getApplicationForPackage(
             Collection<SmsApplicationData> applications, String packageName) {
         if (packageName == null) {
             return null;
@@ -456,8 +476,7 @@
             Log.i(LOG_TAG, "getApplication userId=" + userId);
         }
         // Determine which application receives the broadcast
-        String defaultApplication = Settings.Secure.getStringForUser(context.getContentResolver(),
-                Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
+        String defaultApplication = getDefaultSmsPackage(context, userId);
         if (DEBUG_MULTIUSER) {
             Log.i(LOG_TAG, "getApplication defaultApp=" + defaultApplication);
         }
@@ -469,27 +488,6 @@
         if (DEBUG_MULTIUSER) {
             Log.i(LOG_TAG, "getApplication appData=" + applicationData);
         }
-        // Picking a new SMS app requires AppOps and Settings.Secure permissions, so we only do
-        // this if the caller asked us to.
-        if (updateIfNeeded && applicationData == null) {
-            // Try to find the default SMS package for this device
-            Resources r = context.getResources();
-            String defaultPackage =
-                    r.getString(com.android.internal.R.string.default_sms_application);
-            applicationData = getApplicationForPackage(applications, defaultPackage);
-
-            if (applicationData == null) {
-                // Are there any applications?
-                if (applications.size() != 0) {
-                    applicationData = (SmsApplicationData)applications.toArray()[0];
-                }
-            }
-
-            // If we found a new default app, update the setting
-            if (applicationData != null) {
-                setDefaultApplicationInternal(applicationData.mPackageName, context, userId);
-            }
-        }
 
         // If we found a package, make sure AppOps permissions are set up correctly
         if (applicationData != null) {
@@ -513,7 +511,7 @@
                 // current SMS app will already be the preferred activity - but checking whether or
                 // not this is true is just as expensive as reconfiguring the preferred activity so
                 // we just reconfigure every time.
-                updateDefaultSmsApp(context, userId, applicationData);
+                defaultSmsAppChanged(context);
             }
         }
         if (DEBUG_MULTIUSER) {
@@ -522,16 +520,17 @@
         return applicationData;
     }
 
-    private static void updateDefaultSmsApp(Context context, int userId,
-            SmsApplicationData applicationData) {
+    private static String getDefaultSmsPackage(Context context, int userId) {
+        return context.getSystemService(RoleManager.class).getDefaultSmsPackage(userId);
+    }
+
+    /**
+     * Grants various permissions and appops on sms app change
+     */
+    private static void defaultSmsAppChanged(Context context) {
         PackageManager packageManager = context.getPackageManager();
         AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
 
-        // Configure this as the preferred activity for SENDTO sms/mms intents
-        configurePreferredActivity(packageManager, new ComponentName(
-                        applicationData.mPackageName, applicationData.mSendToClass),
-                userId);
-
         // Assign permission to special system apps
         assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
                 PHONE_PACKAGE_NAME);
@@ -603,8 +602,7 @@
         final UserHandle userHandle = UserHandle.of(userId);
 
         // Get old package name
-        String oldPackageName = Settings.Secure.getStringForUser(context.getContentResolver(),
-                Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
+        String oldPackageName = getDefaultSmsPackage(context, userId);
 
         if (DEBUG_MULTIUSER) {
             Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldPackageName +
@@ -636,16 +634,29 @@
                 }
             }
 
-            // Update the secure setting.
-            Settings.Secure.putStringForUser(context.getContentResolver(),
-                    Settings.Secure.SMS_DEFAULT_APPLICATION, applicationData.mPackageName,
-                    userId);
+            // Update the setting.
+            CompletableFuture<Void> res = new CompletableFuture<>();
+            context.getSystemService(RoleManager.class).addRoleHolderAsUser(
+                    RoleManager.ROLE_SMS, applicationData.mPackageName, UserHandle.of(userId),
+                    AsyncTask.THREAD_POOL_EXECUTOR, new RoleManagerCallback() {
+                        @Override
+                        public void onSuccess() {
+                            res.complete(null);
+                        }
 
-            // Allow relevant appops for the newly configured default SMS app.
-            setExclusiveAppops(applicationData.mPackageName, appOps, applicationData.mUid,
-                    AppOpsManager.MODE_ALLOWED);
+                        @Override
+                        public void onFailure() {
+                            res.completeExceptionally(new RuntimeException());
+                        }
+                    });
+            try {
+                res.get(5, TimeUnit.SECONDS);
+            } catch (InterruptedException | ExecutionException | TimeoutException e) {
+                Log.e(LOG_TAG, "Exception while adding sms role holder " + applicationData, e);
+                return;
+            }
 
-            updateDefaultSmsApp(context, userId, applicationData);
+            defaultSmsAppChanged(context);
 
             if (DEBUG_MULTIUSER) {
                 Log.i(LOG_TAG, "setDefaultApplicationInternal oldAppData=" + oldAppData);
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 2a648bd..8523554 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -501,4 +501,18 @@
      */
     public static final String ACTION_LINE1_NUMBER_ERROR_DETECTED =
             "com.android.internal.telephony.ACTION_LINE1_NUMBER_ERROR_DETECTED";
+
+    /**
+     * Broadcast action to notify radio bug.
+     *
+     * Requires the READ_PRIVILEGED_PHONE_STATE permission.
+     *
+     * @hide
+     */
+    public static final String ACTION_REPORT_RADIO_BUG =
+            "com.android.internal.telephony.ACTION_REPORT_RADIO_BUG";
+
+    // ACTION_REPORT_RADIO_BUG extra keys
+    public static final String EXTRA_SLOT_ID = "slotId";
+    public static final String EXTRA_RADIO_BUG_TYPE = "radioBugType";
 }
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index 870a689..14a36c8 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -24,22 +24,25 @@
 
 /** @hide */
 interface IEuiccController {
-    oneway void continueOperation(in Intent resolutionIntent, in Bundle resolutionExtras);
-    oneway void getDownloadableSubscriptionMetadata(in DownloadableSubscription subscription,
+    oneway void continueOperation(int cardId, in Intent resolutionIntent,
+            in Bundle resolutionExtras);
+    oneway void getDownloadableSubscriptionMetadata(int cardId,
+            in DownloadableSubscription subscription,
         String callingPackage, in PendingIntent callbackIntent);
-    oneway void getDefaultDownloadableSubscriptionList(
+    oneway void getDefaultDownloadableSubscriptionList(int cardId,
         String callingPackage, in PendingIntent callbackIntent);
-    String getEid();
-    int getOtaStatus();
-    oneway void downloadSubscription(in DownloadableSubscription subscription,
-        boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle, in PendingIntent callbackIntent);
-    EuiccInfo getEuiccInfo();
-    oneway void deleteSubscription(int subscriptionId, String callingPackage,
+    String getEid(int cardId);
+    int getOtaStatus(int cardId);
+    oneway void downloadSubscription(int cardId, in DownloadableSubscription subscription,
+        boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle,
         in PendingIntent callbackIntent);
-    oneway void switchToSubscription(int subscriptionId, String callingPackage,
+    EuiccInfo getEuiccInfo(int cardId);
+    oneway void deleteSubscription(int cardId, int subscriptionId, String callingPackage,
         in PendingIntent callbackIntent);
-    oneway void updateSubscriptionNickname(int subscriptionId, String nickname,
+    oneway void switchToSubscription(int cardId, int subscriptionId, String callingPackage,
         in PendingIntent callbackIntent);
-    oneway void eraseSubscriptions(in PendingIntent callbackIntent);
-    oneway void retainSubscriptionsForFactoryReset(in PendingIntent callbackIntent);
-}
\ No newline at end of file
+    oneway void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname,
+        String callingPackage, in PendingIntent callbackIntent);
+    oneway void eraseSubscriptions(int cardId, in PendingIntent callbackIntent);
+    oneway void retainSubscriptionsForFactoryReset(int cardId, in PendingIntent callbackIntent);
+}
diff --git a/test-base/api/current.txt b/test-base/api/current.txt
index 7ebd6aa..750fb59 100644
--- a/test-base/api/current.txt
+++ b/test-base/api/current.txt
@@ -1,81 +1,87 @@
+// Signature format: 2.0
 package android.test {
 
-  public deprecated class AndroidTestCase extends junit.framework.TestCase {
-    ctor public AndroidTestCase();
-    method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String);
-    method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String);
-    method public void assertWritingContentUriRequiresPermission(android.net.Uri, java.lang.String);
-    method public android.content.Context getContext();
-    method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException;
-    method public void setContext(android.content.Context);
-    method public void testAndroidTestCaseSetupProperly();
-    field protected android.content.Context mContext;
+  @Deprecated public class AndroidTestCase extends junit.framework.TestCase {
+    ctor @Deprecated public AndroidTestCase();
+    method @Deprecated public void assertActivityRequiresPermission(String, String, String);
+    method @Deprecated public void assertReadingContentUriRequiresPermission(android.net.Uri, String);
+    method @Deprecated public void assertWritingContentUriRequiresPermission(android.net.Uri, String);
+    method @Deprecated public android.content.Context getContext();
+    method @Deprecated protected void scrubClass(Class<?>) throws java.lang.IllegalAccessException;
+    method @Deprecated public void setContext(android.content.Context);
+    method @Deprecated @android.test.suitebuilder.annotation.Suppress public void testAndroidTestCaseSetupProperly();
+    field @Deprecated protected android.content.Context mContext;
   }
 
-  public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation {
+  @Deprecated @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface FlakyTest {
+    method @Deprecated public abstract int tolerance() default 1;
   }
 
-  public deprecated class InstrumentationTestCase extends junit.framework.TestCase {
-    ctor public InstrumentationTestCase();
-    method public android.app.Instrumentation getInstrumentation();
-    method public deprecated void injectInsrumentation(android.app.Instrumentation);
-    method public void injectInstrumentation(android.app.Instrumentation);
-    method public final <T extends android.app.Activity> T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
-    method public final <T extends android.app.Activity> T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
-    method public void runTestOnUiThread(java.lang.Runnable) throws java.lang.Throwable;
-    method public void sendKeys(java.lang.String);
-    method public void sendKeys(int...);
-    method public void sendRepeatedKeys(int...);
+  @Deprecated public class InstrumentationTestCase extends junit.framework.TestCase {
+    ctor @Deprecated public InstrumentationTestCase();
+    method @Deprecated public android.app.Instrumentation getInstrumentation();
+    method @Deprecated public void injectInsrumentation(android.app.Instrumentation);
+    method @Deprecated public void injectInstrumentation(android.app.Instrumentation);
+    method @Deprecated public final <T extends android.app.Activity> T launchActivity(String, Class<T>, android.os.Bundle);
+    method @Deprecated public final <T extends android.app.Activity> T launchActivityWithIntent(String, Class<T>, android.content.Intent);
+    method @Deprecated public void runTestOnUiThread(Runnable) throws java.lang.Throwable;
+    method @Deprecated public void sendKeys(String);
+    method @Deprecated public void sendKeys(int...);
+    method @Deprecated public void sendRepeatedKeys(int...);
   }
 
-  public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite {
-    ctor public InstrumentationTestSuite(android.app.Instrumentation);
-    ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation);
-    ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation);
-    method public void addTestSuite(java.lang.Class);
+  @Deprecated public class InstrumentationTestSuite extends junit.framework.TestSuite {
+    ctor @Deprecated public InstrumentationTestSuite(android.app.Instrumentation);
+    ctor @Deprecated public InstrumentationTestSuite(String, android.app.Instrumentation);
+    ctor @Deprecated public InstrumentationTestSuite(Class, android.app.Instrumentation);
+    method @Deprecated public void addTestSuite(Class);
   }
 
-  public abstract deprecated interface PerformanceTestCase {
-    method public abstract boolean isPerformanceOnly();
-    method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates);
+  @Deprecated public interface PerformanceTestCase {
+    method @Deprecated public boolean isPerformanceOnly();
+    method @Deprecated public int startPerformance(android.test.PerformanceTestCase.Intermediates);
   }
 
-  public static abstract interface PerformanceTestCase.Intermediates {
-    method public abstract void addIntermediate(java.lang.String);
-    method public abstract void addIntermediate(java.lang.String, long);
-    method public abstract void finishTiming(boolean);
-    method public abstract void setInternalIterations(int);
-    method public abstract void startTiming(boolean);
+  @Deprecated public static interface PerformanceTestCase.Intermediates {
+    method @Deprecated public void addIntermediate(String);
+    method @Deprecated public void addIntermediate(String, long);
+    method @Deprecated public void finishTiming(boolean);
+    method @Deprecated public void setInternalIterations(int);
+    method @Deprecated public void startTiming(boolean);
   }
 
-  public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
+  @Deprecated @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface RepetitiveTest {
+    method @Deprecated public abstract int numIterations() default 1;
+  }
+
+  @Deprecated @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface UiThreadTest {
   }
 
 }
 
 package android.test.suitebuilder.annotation {
 
-  public abstract deprecated class LargeTest implements java.lang.annotation.Annotation {
+  @Deprecated @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE}) public @interface LargeTest {
   }
 
-  public abstract deprecated class MediumTest implements java.lang.annotation.Annotation {
+  @Deprecated @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE}) public @interface MediumTest {
   }
 
-  public abstract deprecated class SmallTest implements java.lang.annotation.Annotation {
+  @Deprecated @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE}) public @interface SmallTest {
   }
 
-  public abstract deprecated class Smoke implements java.lang.annotation.Annotation {
+  @Deprecated @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE}) public @interface Smoke {
   }
 
-  public abstract deprecated class Suppress implements java.lang.annotation.Annotation {
+  @Deprecated @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE}) public @interface Suppress {
   }
 
 }
 
 package com.android.internal.util {
 
-  public abstract deprecated interface Predicate<T> {
-    method public abstract boolean apply(T);
+  @Deprecated public interface Predicate<T> {
+    method @Deprecated public boolean apply(T);
   }
 
 }
@@ -84,117 +90,117 @@
 
   public class Assert {
     ctor protected Assert();
-    method public static void assertEquals(java.lang.String, java.lang.Object, java.lang.Object);
-    method public static void assertEquals(java.lang.Object, java.lang.Object);
-    method public static void assertEquals(java.lang.String, java.lang.String, java.lang.String);
-    method public static void assertEquals(java.lang.String, java.lang.String);
-    method public static void assertEquals(java.lang.String, double, double, double);
+    method public static void assertEquals(String, Object, Object);
+    method public static void assertEquals(Object, Object);
+    method public static void assertEquals(String, String, String);
+    method public static void assertEquals(String, String);
+    method public static void assertEquals(String, double, double, double);
     method public static void assertEquals(double, double, double);
-    method public static void assertEquals(java.lang.String, float, float, float);
+    method public static void assertEquals(String, float, float, float);
     method public static void assertEquals(float, float, float);
-    method public static void assertEquals(java.lang.String, long, long);
+    method public static void assertEquals(String, long, long);
     method public static void assertEquals(long, long);
-    method public static void assertEquals(java.lang.String, boolean, boolean);
+    method public static void assertEquals(String, boolean, boolean);
     method public static void assertEquals(boolean, boolean);
-    method public static void assertEquals(java.lang.String, byte, byte);
+    method public static void assertEquals(String, byte, byte);
     method public static void assertEquals(byte, byte);
-    method public static void assertEquals(java.lang.String, char, char);
+    method public static void assertEquals(String, char, char);
     method public static void assertEquals(char, char);
-    method public static void assertEquals(java.lang.String, short, short);
+    method public static void assertEquals(String, short, short);
     method public static void assertEquals(short, short);
-    method public static void assertEquals(java.lang.String, int, int);
+    method public static void assertEquals(String, int, int);
     method public static void assertEquals(int, int);
-    method public static void assertFalse(java.lang.String, boolean);
+    method public static void assertFalse(String, boolean);
     method public static void assertFalse(boolean);
-    method public static void assertNotNull(java.lang.Object);
-    method public static void assertNotNull(java.lang.String, java.lang.Object);
-    method public static void assertNotSame(java.lang.String, java.lang.Object, java.lang.Object);
-    method public static void assertNotSame(java.lang.Object, java.lang.Object);
-    method public static void assertNull(java.lang.Object);
-    method public static void assertNull(java.lang.String, java.lang.Object);
-    method public static void assertSame(java.lang.String, java.lang.Object, java.lang.Object);
-    method public static void assertSame(java.lang.Object, java.lang.Object);
-    method public static void assertTrue(java.lang.String, boolean);
+    method public static void assertNotNull(Object);
+    method public static void assertNotNull(String, Object);
+    method public static void assertNotSame(String, Object, Object);
+    method public static void assertNotSame(Object, Object);
+    method public static void assertNull(Object);
+    method public static void assertNull(String, Object);
+    method public static void assertSame(String, Object, Object);
+    method public static void assertSame(Object, Object);
+    method public static void assertTrue(String, boolean);
     method public static void assertTrue(boolean);
-    method public static void fail(java.lang.String);
+    method public static void fail(String);
     method public static void fail();
-    method public static void failNotEquals(java.lang.String, java.lang.Object, java.lang.Object);
-    method public static void failNotSame(java.lang.String, java.lang.Object, java.lang.Object);
-    method public static void failSame(java.lang.String);
-    method public static java.lang.String format(java.lang.String, java.lang.Object, java.lang.Object);
+    method public static void failNotEquals(String, Object, Object);
+    method public static void failNotSame(String, Object, Object);
+    method public static void failSame(String);
+    method public static String format(String, Object, Object);
   }
 
   public class AssertionFailedError extends java.lang.AssertionError {
     ctor public AssertionFailedError();
-    ctor public AssertionFailedError(java.lang.String);
+    ctor public AssertionFailedError(String);
   }
 
   public class ComparisonFailure extends junit.framework.AssertionFailedError {
-    ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
-    method public java.lang.String getActual();
-    method public java.lang.String getExpected();
+    ctor public ComparisonFailure(String, String, String);
+    method public String getActual();
+    method public String getExpected();
   }
 
-  public abstract interface Protectable {
-    method public abstract void protect() throws java.lang.Throwable;
+  public interface Protectable {
+    method public void protect() throws java.lang.Throwable;
   }
 
-  public abstract interface Test {
-    method public abstract int countTestCases();
-    method public abstract void run(junit.framework.TestResult);
+  public interface Test {
+    method public int countTestCases();
+    method public void run(junit.framework.TestResult);
   }
 
   public abstract class TestCase extends junit.framework.Assert implements junit.framework.Test {
     ctor public TestCase();
-    ctor public TestCase(java.lang.String);
+    ctor public TestCase(String);
     method public int countTestCases();
     method protected junit.framework.TestResult createResult();
-    method public java.lang.String getName();
+    method public String getName();
     method public junit.framework.TestResult run();
     method public void run(junit.framework.TestResult);
     method public void runBare() throws java.lang.Throwable;
     method protected void runTest() throws java.lang.Throwable;
-    method public void setName(java.lang.String);
+    method public void setName(String);
     method protected void setUp() throws java.lang.Exception;
     method protected void tearDown() throws java.lang.Exception;
   }
 
   public class TestFailure {
-    ctor public TestFailure(junit.framework.Test, java.lang.Throwable);
-    method public java.lang.String exceptionMessage();
+    ctor public TestFailure(junit.framework.Test, Throwable);
+    method public String exceptionMessage();
     method public junit.framework.Test failedTest();
     method public boolean isFailure();
-    method public java.lang.Throwable thrownException();
-    method public java.lang.String trace();
+    method public Throwable thrownException();
+    method public String trace();
     field protected junit.framework.Test fFailedTest;
-    field protected java.lang.Throwable fThrownException;
+    field protected Throwable fThrownException;
   }
 
-  public abstract interface TestListener {
-    method public abstract void addError(junit.framework.Test, java.lang.Throwable);
-    method public abstract void addFailure(junit.framework.Test, junit.framework.AssertionFailedError);
-    method public abstract void endTest(junit.framework.Test);
-    method public abstract void startTest(junit.framework.Test);
+  public interface TestListener {
+    method public void addError(junit.framework.Test, Throwable);
+    method public void addFailure(junit.framework.Test, junit.framework.AssertionFailedError);
+    method public void endTest(junit.framework.Test);
+    method public void startTest(junit.framework.Test);
   }
 
   public class TestResult {
     ctor public TestResult();
-    method public synchronized void addError(junit.framework.Test, java.lang.Throwable);
-    method public synchronized void addFailure(junit.framework.Test, junit.framework.AssertionFailedError);
-    method public synchronized void addListener(junit.framework.TestListener);
+    method public void addError(junit.framework.Test, Throwable);
+    method public void addFailure(junit.framework.Test, junit.framework.AssertionFailedError);
+    method public void addListener(junit.framework.TestListener);
     method public void endTest(junit.framework.Test);
-    method public synchronized int errorCount();
-    method public synchronized java.util.Enumeration<junit.framework.TestFailure> errors();
-    method public synchronized int failureCount();
-    method public synchronized java.util.Enumeration<junit.framework.TestFailure> failures();
-    method public synchronized void removeListener(junit.framework.TestListener);
+    method public int errorCount();
+    method public java.util.Enumeration<junit.framework.TestFailure> errors();
+    method public int failureCount();
+    method public java.util.Enumeration<junit.framework.TestFailure> failures();
+    method public void removeListener(junit.framework.TestListener);
     method protected void run(junit.framework.TestCase);
-    method public synchronized int runCount();
+    method public int runCount();
     method public void runProtected(junit.framework.Test, junit.framework.Protectable);
-    method public synchronized boolean shouldStop();
+    method public boolean shouldStop();
     method public void startTest(junit.framework.Test);
-    method public synchronized void stop();
-    method public synchronized boolean wasSuccessful();
+    method public void stop();
+    method public boolean wasSuccessful();
     field protected java.util.Vector<junit.framework.TestFailure> fErrors;
     field protected java.util.Vector<junit.framework.TestFailure> fFailures;
     field protected java.util.Vector<junit.framework.TestListener> fListeners;
@@ -203,24 +209,24 @@
 
   public class TestSuite implements junit.framework.Test {
     ctor public TestSuite();
-    ctor public TestSuite(java.lang.Class<?>);
-    ctor public TestSuite(java.lang.Class<? extends junit.framework.TestCase>, java.lang.String);
-    ctor public TestSuite(java.lang.String);
-    ctor public TestSuite(java.lang.Class<?>...);
-    ctor public TestSuite(java.lang.Class<? extends junit.framework.TestCase>[], java.lang.String);
+    ctor public TestSuite(Class<?>);
+    ctor public TestSuite(Class<? extends junit.framework.TestCase>, String);
+    ctor public TestSuite(String);
+    ctor public TestSuite(Class<?>...);
+    ctor public TestSuite(Class<? extends junit.framework.TestCase>[], String);
     method public void addTest(junit.framework.Test);
-    method public void addTestSuite(java.lang.Class<? extends junit.framework.TestCase>);
+    method public void addTestSuite(Class<? extends junit.framework.TestCase>);
     method public int countTestCases();
-    method public static junit.framework.Test createTest(java.lang.Class<?>, java.lang.String);
-    method public java.lang.String getName();
-    method public static java.lang.reflect.Constructor<?> getTestConstructor(java.lang.Class<?>) throws java.lang.NoSuchMethodException;
+    method public static junit.framework.Test createTest(Class<?>, String);
+    method public String getName();
+    method public static java.lang.reflect.Constructor<?> getTestConstructor(Class<?>) throws java.lang.NoSuchMethodException;
     method public void run(junit.framework.TestResult);
     method public void runTest(junit.framework.Test, junit.framework.TestResult);
-    method public void setName(java.lang.String);
+    method public void setName(String);
     method public junit.framework.Test testAt(int);
     method public int testCount();
     method public java.util.Enumeration<junit.framework.Test> tests();
-    method public static junit.framework.Test warning(java.lang.String);
+    method public static junit.framework.Test warning(String);
   }
 
 }
diff --git a/test-base/api/removed.txt b/test-base/api/removed.txt
index e69de29..d802177 100644
--- a/test-base/api/removed.txt
+++ b/test-base/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/test-base/api/system-current.txt b/test-base/api/system-current.txt
index e69de29..d802177 100644
--- a/test-base/api/system-current.txt
+++ b/test-base/api/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/test-base/api/system-removed.txt b/test-base/api/system-removed.txt
index e69de29..d802177 100644
--- a/test-base/api/system-removed.txt
+++ b/test-base/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/test-base/api/test-current.txt b/test-base/api/test-current.txt
index e69de29..d802177 100644
--- a/test-base/api/test-current.txt
+++ b/test-base/api/test-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/test-base/api/test-removed.txt b/test-base/api/test-removed.txt
index e69de29..d802177 100644
--- a/test-base/api/test-removed.txt
+++ b/test-base/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/test-base/src/android/test/RepetitiveTest.java b/test-base/src/android/test/RepetitiveTest.java
index 6a7130e..13e89d2 100644
--- a/test-base/src/android/test/RepetitiveTest.java
+++ b/test-base/src/android/test/RepetitiveTest.java
@@ -26,8 +26,10 @@
  * When the annotation is present, the test method is executed the number of times specified by
  * numIterations and defaults to 1.
  *
- * {@hide} Not needed for public API.
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
  */
+@Deprecated
 @Target(ElementType.METHOD)
 @Retention(RetentionPolicy.RUNTIME)
 public @interface RepetitiveTest {
@@ -37,4 +39,4 @@
      * @return The total number of iterations, the default is 1.
      */
     int numIterations() default 1;
-}
\ No newline at end of file
+}
diff --git a/test-legacy/Android.bp b/test-legacy/Android.bp
index 833c714..a69f422 100644
--- a/test-legacy/Android.bp
+++ b/test-legacy/Android.bp
@@ -25,7 +25,7 @@
     static_libs: [
         "android.test.base-minus-junit",
         "android.test.runner-minus-junit",
-        "android.test.mock.impl",
+        "android.test.mock_static",
     ],
 
     no_framework_libs: true,
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 37158e5..43b765d 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -25,7 +25,24 @@
         "android.test.mock",
     ],
 
+    srcs_lib: "framework",
+    srcs_lib_whitelist_dirs: ["core/java"],
     srcs_lib_whitelist_pkgs: ["android"],
-    metalava_enabled: false,
     compile_dex: true,
 }
+
+// Build the android.test.mock_static library
+// ==========================================
+// This is only intended for inclusion in the legacy-android-test.
+// Must not be used elewhere.
+java_library_static {
+    name: "android.test.mock_static",
+
+    java_version: "1.8",
+    srcs: ["src/**/*.java"],
+
+    no_framework_libs: true,
+    libs: [
+        "framework",
+    ],
+}
diff --git a/test-mock/api/current.txt b/test-mock/api/current.txt
index 5b58dd5..1110790 100644
--- a/test-mock/api/current.txt
+++ b/test-mock/api/current.txt
@@ -1,126 +1,125 @@
+// Signature format: 2.0
 package android.test.mock {
 
-  public deprecated class MockAccountManager {
-    method public static android.accounts.AccountManager newMockAccountManager(android.content.Context);
+  @Deprecated public class MockAccountManager {
+    method @Deprecated public static android.accounts.AccountManager newMockAccountManager(android.content.Context);
   }
 
-  public deprecated class MockApplication extends android.app.Application {
-    ctor public MockApplication();
+  @Deprecated public class MockApplication extends android.app.Application {
+    ctor @Deprecated public MockApplication();
   }
 
   public class MockContentProvider extends android.content.ContentProvider {
     ctor protected MockContentProvider();
     ctor public MockContentProvider(android.content.Context);
-    ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]);
+    ctor public MockContentProvider(android.content.Context, String, String, android.content.pm.PathPermission[]);
     method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>);
-    method public static deprecated void attachInfoForTesting(android.content.ContentProvider, android.content.Context, android.content.pm.ProviderInfo);
-    method public int delete(android.net.Uri, java.lang.String, java.lang.String[]);
-    method public java.lang.String getType(android.net.Uri);
+    method @Deprecated public static void attachInfoForTesting(android.content.ContentProvider, android.content.Context, android.content.pm.ProviderInfo);
+    method public int delete(android.net.Uri, String, String[]);
+    method public String getType(android.net.Uri);
     method public android.net.Uri insert(android.net.Uri, android.content.ContentValues);
     method public boolean onCreate();
-    method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle);
-    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+    method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, String, android.os.Bundle);
+    method public android.database.Cursor query(android.net.Uri, String[], String, String[], String);
+    method public int update(android.net.Uri, android.content.ContentValues, String, String[]);
   }
 
   public class MockContentResolver extends android.content.ContentResolver {
     ctor public MockContentResolver();
     ctor public MockContentResolver(android.content.Context);
-    method public void addProvider(java.lang.String, android.content.ContentProvider);
+    method public void addProvider(String, android.content.ContentProvider);
   }
 
   public class MockContext extends android.content.Context {
     ctor public MockContext();
-    method public boolean bindIsolatedService(android.content.Intent, android.content.ServiceConnection, int, java.lang.String);
     method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
-    method public int checkCallingOrSelfPermission(java.lang.String);
+    method public int checkCallingOrSelfPermission(String);
     method public int checkCallingOrSelfUriPermission(android.net.Uri, int);
-    method public int checkCallingPermission(java.lang.String);
+    method public int checkCallingPermission(String);
     method public int checkCallingUriPermission(android.net.Uri, int);
-    method public int checkPermission(java.lang.String, int, int);
-    method public int checkSelfPermission(java.lang.String);
+    method public int checkPermission(String, int, int);
+    method public int checkSelfPermission(String);
     method public int checkUriPermission(android.net.Uri, int, int, int);
-    method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
+    method public int checkUriPermission(android.net.Uri, String, String, int, int, int);
     method public void clearWallpaper();
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
-    method public android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public android.content.Context createContextForSplit(String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.Context createDeviceProtectedStorageContext();
     method public android.content.Context createDisplayContext(android.view.Display);
-    method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public java.lang.String[] databaseList();
-    method public boolean deleteDatabase(java.lang.String);
-    method public boolean deleteFile(java.lang.String);
-    method public boolean deleteSharedPreferences(java.lang.String);
-    method public void enforceCallingOrSelfPermission(java.lang.String, java.lang.String);
-    method public void enforceCallingOrSelfUriPermission(android.net.Uri, int, java.lang.String);
-    method public void enforceCallingPermission(java.lang.String, java.lang.String);
-    method public void enforceCallingUriPermission(android.net.Uri, int, java.lang.String);
-    method public void enforcePermission(java.lang.String, int, int, java.lang.String);
-    method public void enforceUriPermission(android.net.Uri, int, int, int, java.lang.String);
-    method public void enforceUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int, java.lang.String);
-    method public java.lang.String[] fileList();
+    method public android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public String[] databaseList();
+    method public boolean deleteDatabase(String);
+    method public boolean deleteFile(String);
+    method public boolean deleteSharedPreferences(String);
+    method public void enforceCallingOrSelfPermission(String, String);
+    method public void enforceCallingOrSelfUriPermission(android.net.Uri, int, String);
+    method public void enforceCallingPermission(String, String);
+    method public void enforceCallingUriPermission(android.net.Uri, int, String);
+    method public void enforcePermission(String, int, int, String);
+    method public void enforceUriPermission(android.net.Uri, int, int, int, String);
+    method public void enforceUriPermission(android.net.Uri, String, String, int, int, int, String);
+    method public String[] fileList();
     method public android.content.Context getApplicationContext();
     method public android.content.pm.ApplicationInfo getApplicationInfo();
     method public android.content.res.AssetManager getAssets();
     method public java.io.File getCacheDir();
-    method public java.lang.ClassLoader getClassLoader();
+    method public ClassLoader getClassLoader();
     method public java.io.File getCodeCacheDir();
     method public android.content.ContentResolver getContentResolver();
     method public java.io.File getDataDir();
-    method public java.io.File getDatabasePath(java.lang.String);
-    method public java.io.File getDir(java.lang.String, int);
+    method public java.io.File getDatabasePath(String);
+    method public java.io.File getDir(String, int);
     method public java.io.File getExternalCacheDir();
     method public java.io.File[] getExternalCacheDirs();
-    method public java.io.File getExternalFilesDir(java.lang.String);
-    method public java.io.File[] getExternalFilesDirs(java.lang.String);
+    method public java.io.File getExternalFilesDir(String);
+    method public java.io.File[] getExternalFilesDirs(String);
     method public java.io.File[] getExternalMediaDirs();
-    method public java.io.File getFileStreamPath(java.lang.String);
+    method public java.io.File getFileStreamPath(String);
     method public java.io.File getFilesDir();
     method public android.os.Looper getMainLooper();
     method public java.io.File getNoBackupFilesDir();
     method public java.io.File getObbDir();
     method public java.io.File[] getObbDirs();
-    method public java.lang.String getOpPackageName();
-    method public java.lang.String getPackageCodePath();
+    method public String getPackageCodePath();
     method public android.content.pm.PackageManager getPackageManager();
-    method public java.lang.String getPackageName();
-    method public java.lang.String getPackageResourcePath();
+    method public String getPackageName();
+    method public String getPackageResourcePath();
     method public android.content.res.Resources getResources();
-    method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
-    method public java.lang.Object getSystemService(java.lang.String);
-    method public java.lang.String getSystemServiceName(java.lang.Class<?>);
+    method public android.content.SharedPreferences getSharedPreferences(String, int);
+    method public Object getSystemService(String);
+    method public String getSystemServiceName(Class<?>);
     method public android.content.res.Resources.Theme getTheme();
     method public android.graphics.drawable.Drawable getWallpaper();
     method public int getWallpaperDesiredMinimumHeight();
     method public int getWallpaperDesiredMinimumWidth();
-    method public void grantUriPermission(java.lang.String, android.net.Uri, int);
+    method public void grantUriPermission(String, android.net.Uri, int);
     method public boolean isDeviceProtectedStorage();
-    method public boolean moveDatabaseFrom(android.content.Context, java.lang.String);
-    method public boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
-    method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
-    method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
-    method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
-    method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
+    method public boolean moveDatabaseFrom(android.content.Context, String);
+    method public boolean moveSharedPreferencesFrom(android.content.Context, String);
+    method public java.io.FileInputStream openFileInput(String) throws java.io.FileNotFoundException;
+    method public java.io.FileOutputStream openFileOutput(String, int) throws java.io.FileNotFoundException;
+    method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
+    method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
     method public android.graphics.drawable.Drawable peekWallpaper();
     method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
     method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
-    method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
-    method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
+    method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler);
+    method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler, int);
     method public void removeStickyBroadcast(android.content.Intent);
     method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public void revokeUriPermission(android.net.Uri, int);
-    method public void revokeUriPermission(java.lang.String, android.net.Uri, int);
+    method public void revokeUriPermission(String, android.net.Uri, int);
     method public void sendBroadcast(android.content.Intent);
-    method public void sendBroadcast(android.content.Intent, java.lang.String);
+    method public void sendBroadcast(android.content.Intent, String);
     method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle);
-    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String);
-    method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
-    method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, String);
+    method public void sendOrderedBroadcast(android.content.Intent, String);
+    method public void sendOrderedBroadcast(android.content.Intent, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
+    method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
     method public void sendStickyBroadcast(android.content.Intent);
     method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
-    method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
+    method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
     method public void setTheme(int);
     method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
     method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
@@ -129,178 +128,177 @@
     method public void startActivity(android.content.Intent);
     method public void startActivity(android.content.Intent, android.os.Bundle);
     method public android.content.ComponentName startForegroundService(android.content.Intent);
-    method public boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
+    method public boolean startInstrumentation(android.content.ComponentName, String, android.os.Bundle);
     method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public android.content.ComponentName startService(android.content.Intent);
     method public boolean stopService(android.content.Intent);
     method public void unbindService(android.content.ServiceConnection);
     method public void unregisterReceiver(android.content.BroadcastReceiver);
-    method public void updateServiceGroup(android.content.ServiceConnection, int, int);
   }
 
-  public deprecated class MockCursor implements android.database.Cursor {
-    ctor public MockCursor();
-    method public void close();
-    method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
-    method public deprecated void deactivate();
-    method public byte[] getBlob(int);
-    method public int getColumnCount();
-    method public int getColumnIndex(java.lang.String);
-    method public int getColumnIndexOrThrow(java.lang.String);
-    method public java.lang.String getColumnName(int);
-    method public java.lang.String[] getColumnNames();
-    method public int getCount();
-    method public double getDouble(int);
-    method public android.os.Bundle getExtras();
-    method public float getFloat(int);
-    method public int getInt(int);
-    method public long getLong(int);
-    method public android.net.Uri getNotificationUri();
-    method public int getPosition();
-    method public short getShort(int);
-    method public java.lang.String getString(int);
-    method public int getType(int);
-    method public boolean getWantsAllOnMoveCalls();
-    method public boolean isAfterLast();
-    method public boolean isBeforeFirst();
-    method public boolean isClosed();
-    method public boolean isFirst();
-    method public boolean isLast();
-    method public boolean isNull(int);
-    method public boolean move(int);
-    method public boolean moveToFirst();
-    method public boolean moveToLast();
-    method public boolean moveToNext();
-    method public boolean moveToPosition(int);
-    method public boolean moveToPrevious();
-    method public void registerContentObserver(android.database.ContentObserver);
-    method public void registerDataSetObserver(android.database.DataSetObserver);
-    method public deprecated boolean requery();
-    method public android.os.Bundle respond(android.os.Bundle);
-    method public void setExtras(android.os.Bundle);
-    method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
-    method public void unregisterContentObserver(android.database.ContentObserver);
-    method public void unregisterDataSetObserver(android.database.DataSetObserver);
+  @Deprecated public class MockCursor implements android.database.Cursor {
+    ctor @Deprecated public MockCursor();
+    method @Deprecated public void close();
+    method @Deprecated public void copyStringToBuffer(int, android.database.CharArrayBuffer);
+    method @Deprecated public void deactivate();
+    method @Deprecated public byte[] getBlob(int);
+    method @Deprecated public int getColumnCount();
+    method @Deprecated public int getColumnIndex(String);
+    method @Deprecated public int getColumnIndexOrThrow(String);
+    method @Deprecated public String getColumnName(int);
+    method @Deprecated public String[] getColumnNames();
+    method @Deprecated public int getCount();
+    method @Deprecated public double getDouble(int);
+    method @Deprecated public android.os.Bundle getExtras();
+    method @Deprecated public float getFloat(int);
+    method @Deprecated public int getInt(int);
+    method @Deprecated public long getLong(int);
+    method @Deprecated public android.net.Uri getNotificationUri();
+    method @Deprecated public int getPosition();
+    method @Deprecated public short getShort(int);
+    method @Deprecated public String getString(int);
+    method @Deprecated public int getType(int);
+    method @Deprecated public boolean getWantsAllOnMoveCalls();
+    method @Deprecated public boolean isAfterLast();
+    method @Deprecated public boolean isBeforeFirst();
+    method @Deprecated public boolean isClosed();
+    method @Deprecated public boolean isFirst();
+    method @Deprecated public boolean isLast();
+    method @Deprecated public boolean isNull(int);
+    method @Deprecated public boolean move(int);
+    method @Deprecated public boolean moveToFirst();
+    method @Deprecated public boolean moveToLast();
+    method @Deprecated public boolean moveToNext();
+    method @Deprecated public boolean moveToPosition(int);
+    method @Deprecated public boolean moveToPrevious();
+    method @Deprecated public void registerContentObserver(android.database.ContentObserver);
+    method @Deprecated public void registerDataSetObserver(android.database.DataSetObserver);
+    method @Deprecated public boolean requery();
+    method @Deprecated public android.os.Bundle respond(android.os.Bundle);
+    method @Deprecated public void setExtras(android.os.Bundle);
+    method @Deprecated public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
+    method @Deprecated public void unregisterContentObserver(android.database.ContentObserver);
+    method @Deprecated public void unregisterDataSetObserver(android.database.DataSetObserver);
   }
 
-  public deprecated class MockDialogInterface implements android.content.DialogInterface {
-    ctor public MockDialogInterface();
-    method public void cancel();
-    method public void dismiss();
+  @Deprecated public class MockDialogInterface implements android.content.DialogInterface {
+    ctor @Deprecated public MockDialogInterface();
+    method @Deprecated public void cancel();
+    method @Deprecated public void dismiss();
   }
 
-  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
-    ctor public MockPackageManager();
-    method public void addPackageToPreferred(java.lang.String);
-    method public boolean addPermission(android.content.pm.PermissionInfo);
-    method public boolean addPermissionAsync(android.content.pm.PermissionInfo);
-    method public void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
-    method public boolean canRequestPackageInstalls();
-    method public java.lang.String[] canonicalToCurrentPackageNames(java.lang.String[]);
-    method public int checkPermission(java.lang.String, java.lang.String);
-    method public int checkSignatures(java.lang.String, java.lang.String);
-    method public int checkSignatures(int, int);
+  @Deprecated public class MockPackageManager extends android.content.pm.PackageManager {
+    ctor @Deprecated public MockPackageManager();
+    method @Deprecated public void addPackageToPreferred(String);
+    method @Deprecated public boolean addPermission(android.content.pm.PermissionInfo);
+    method @Deprecated public boolean addPermissionAsync(android.content.pm.PermissionInfo);
+    method @Deprecated public void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
+    method @Deprecated public boolean canRequestPackageInstalls();
+    method @Deprecated public String[] canonicalToCurrentPackageNames(String[]);
+    method @Deprecated public int checkPermission(String, String);
+    method @Deprecated public int checkSignatures(String, String);
+    method @Deprecated public int checkSignatures(int, int);
     method public void clearInstantAppCookie();
-    method public void clearPackagePreferredActivities(java.lang.String);
-    method public java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
-    method public void extendVerificationTimeout(int, int, long);
-    method public android.graphics.drawable.Drawable getActivityBanner(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.graphics.drawable.Drawable getActivityBanner(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.graphics.drawable.Drawable getActivityIcon(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String);
-    method public java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
-    method public android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
-    method public android.graphics.drawable.Drawable getApplicationBanner(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public int getApplicationEnabledSetting(java.lang.String);
-    method public android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo);
-    method public android.graphics.drawable.Drawable getApplicationIcon(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public java.lang.CharSequence getApplicationLabel(android.content.pm.ApplicationInfo);
-    method public android.graphics.drawable.Drawable getApplicationLogo(android.content.pm.ApplicationInfo);
-    method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public void clearPackagePreferredActivities(String);
+    method @Deprecated public String[] currentToCanonicalPackageNames(String[]);
+    method @Deprecated public void extendVerificationTimeout(int, int, long);
+    method @Deprecated public android.graphics.drawable.Drawable getActivityBanner(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.graphics.drawable.Drawable getActivityBanner(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.graphics.drawable.Drawable getActivityIcon(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public java.util.List<android.content.IntentFilter> getAllIntentFilters(String);
+    method @Deprecated public java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
+    method @Deprecated public android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
+    method @Deprecated public android.graphics.drawable.Drawable getApplicationBanner(String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public int getApplicationEnabledSetting(String);
+    method @Deprecated public android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo);
+    method @Deprecated public android.graphics.drawable.Drawable getApplicationIcon(String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.content.pm.ApplicationInfo getApplicationInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public CharSequence getApplicationLabel(android.content.pm.ApplicationInfo);
+    method @Deprecated public android.graphics.drawable.Drawable getApplicationLogo(android.content.pm.ApplicationInfo);
+    method @Deprecated public android.graphics.drawable.Drawable getApplicationLogo(String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.ChangedPackages getChangedPackages(int);
-    method public int getComponentEnabledSetting(android.content.ComponentName);
-    method public android.graphics.drawable.Drawable getDefaultActivityIcon();
-    method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
-    method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
-    method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
-    method public java.lang.String getInstallerPackageName(java.lang.String);
+    method @Deprecated public int getComponentEnabledSetting(android.content.ComponentName);
+    method @Deprecated public android.graphics.drawable.Drawable getDefaultActivityIcon();
+    method @Deprecated public android.graphics.drawable.Drawable getDrawable(String, int, android.content.pm.ApplicationInfo);
+    method @Deprecated public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
+    method @Deprecated public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
+    method @Deprecated public String getInstallerPackageName(String);
     method public byte[] getInstantAppCookie();
     method public int getInstantAppCookieMaxBytes();
-    method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
-    method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
-    method public java.lang.String getNameForUid(int);
-    method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.content.Intent getLaunchIntentForPackage(String);
+    method @Deprecated public android.content.Intent getLeanbackLaunchIntentForPackage(String);
+    method @Deprecated public String getNameForUid(int);
+    method @Deprecated public int[] getPackageGids(String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public int[] getPackageGids(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.content.pm.PackageInfo getPackageInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInstaller getPackageInstaller();
-    method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public java.lang.String[] getPackagesForUid(int);
-    method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
-    method public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.content.pm.PermissionInfo getPermissionInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public int getPreferredActivities(java.util.List<android.content.IntentFilter>, java.util.List<android.content.ComponentName>, java.lang.String);
-    method public java.util.List<android.content.pm.PackageInfo> getPreferredPackages(int);
-    method public android.content.pm.ProviderInfo getProviderInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.content.pm.ActivityInfo getReceiverInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.content.res.Resources getResourcesForActivity(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo);
-    method public android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
-    method public android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
-    method public java.lang.String[] getSystemSharedLibraryNames();
-    method public java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
-    method public android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
-    method public android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle);
-    method public java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
-    method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
-    method public boolean hasSystemFeature(java.lang.String);
-    method public boolean hasSystemFeature(java.lang.String, int);
+    method @Deprecated public int getPackageUid(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public String[] getPackagesForUid(int);
+    method @Deprecated public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(String[], int);
+    method @Deprecated public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.content.pm.PermissionInfo getPermissionInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public int getPreferredActivities(java.util.List<android.content.IntentFilter>, java.util.List<android.content.ComponentName>, String);
+    method @Deprecated public java.util.List<android.content.pm.PackageInfo> getPreferredPackages(int);
+    method @Deprecated public android.content.pm.ProviderInfo getProviderInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.content.pm.ActivityInfo getReceiverInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.content.res.Resources getResourcesForActivity(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo);
+    method @Deprecated public android.content.res.Resources getResourcesForApplication(String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated @NonNull public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
+    method @Deprecated public android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
+    method @Deprecated public String[] getSystemSharedLibraryNames();
+    method @Deprecated public CharSequence getText(String, int, android.content.pm.ApplicationInfo);
+    method @Deprecated public android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
+    method @Deprecated public android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle);
+    method @Deprecated public CharSequence getUserBadgedLabel(CharSequence, android.os.UserHandle);
+    method @Deprecated public android.content.res.XmlResourceParser getXml(String, int, android.content.pm.ApplicationInfo);
+    method @Deprecated public boolean hasSystemFeature(String);
+    method @Deprecated public boolean hasSystemFeature(String, int);
     method public boolean isInstantApp();
-    method public boolean isInstantApp(java.lang.String);
-    method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
-    method public boolean isSafeMode();
-    method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
-    method public java.util.List<android.content.pm.ProviderInfo> queryContentProviders(java.lang.String, int, int);
-    method public java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
-    method public java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
-    method public java.util.List<android.content.pm.ResolveInfo> queryIntentActivityOptions(android.content.ComponentName, android.content.Intent[], android.content.Intent, int);
-    method public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int);
-    method public java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int);
-    method public java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public void removePackageFromPreferred(java.lang.String);
-    method public void removePermission(java.lang.String);
-    method public android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
-    method public android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
-    method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
-    method public android.content.pm.ResolveInfo resolveServiceAsUser(android.content.Intent, int, int);
-    method public void setApplicationCategoryHint(java.lang.String, int);
-    method public void setApplicationEnabledSetting(java.lang.String, int, int);
-    method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
-    method public void setInstallerPackageName(java.lang.String, java.lang.String);
-    method public void updateInstantAppCookie(byte[]);
-    method public void verifyPendingInstall(int, int);
+    method public boolean isInstantApp(String);
+    method @Deprecated public boolean isPermissionRevokedByPolicy(String, String);
+    method @Deprecated public boolean isSafeMode();
+    method @Deprecated public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
+    method @Deprecated public java.util.List<android.content.pm.ProviderInfo> queryContentProviders(String, int, int);
+    method @Deprecated public java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(String, int);
+    method @Deprecated public java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
+    method @Deprecated public java.util.List<android.content.pm.ResolveInfo> queryIntentActivityOptions(android.content.ComponentName, android.content.Intent[], android.content.Intent, int);
+    method @Deprecated public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int);
+    method @Deprecated public java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int);
+    method @Deprecated public java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public void removePackageFromPreferred(String);
+    method @Deprecated public void removePermission(String);
+    method @Deprecated public android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
+    method @Deprecated public android.content.pm.ProviderInfo resolveContentProvider(String, int);
+    method @Deprecated public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
+    method @Deprecated public android.content.pm.ResolveInfo resolveServiceAsUser(android.content.Intent, int, int);
+    method public void setApplicationCategoryHint(String, int);
+    method @Deprecated public void setApplicationEnabledSetting(String, int, int);
+    method @Deprecated public void setComponentEnabledSetting(android.content.ComponentName, int, int);
+    method @Deprecated public void setInstallerPackageName(String, String);
+    method public void updateInstantAppCookie(@NonNull byte[]);
+    method @Deprecated public void verifyPendingInstall(int, int);
   }
 
-  public deprecated class MockResources extends android.content.res.Resources {
-    ctor public MockResources();
-    method public int getColor(int) throws android.content.res.Resources.NotFoundException;
-    method public android.content.res.ColorStateList getColorStateList(int) throws android.content.res.Resources.NotFoundException;
-    method public android.graphics.drawable.Drawable getDrawable(int) throws android.content.res.Resources.NotFoundException;
-    method public android.graphics.Movie getMovie(int) throws android.content.res.Resources.NotFoundException;
-    method public void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
+  @Deprecated public class MockResources extends android.content.res.Resources {
+    ctor @Deprecated public MockResources();
+    method @Deprecated public int getColor(int) throws android.content.res.Resources.NotFoundException;
+    method @Deprecated public android.content.res.ColorStateList getColorStateList(int) throws android.content.res.Resources.NotFoundException;
+    method @Deprecated public android.graphics.drawable.Drawable getDrawable(int) throws android.content.res.Resources.NotFoundException;
+    method @Deprecated public android.graphics.Movie getMovie(int) throws android.content.res.Resources.NotFoundException;
+    method @Deprecated public void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
   }
 
-  public deprecated class MockService {
-    method public static <T extends android.app.Service> void attachForTesting(android.app.Service, android.content.Context, java.lang.String, android.app.Application);
+  @Deprecated public class MockService {
+    method @Deprecated public static <T extends android.app.Service> void attachForTesting(android.app.Service, android.content.Context, String, android.app.Application);
   }
 
 }
diff --git a/test-mock/api/removed.txt b/test-mock/api/removed.txt
index bd109a8..1496c35 100644
--- a/test-mock/api/removed.txt
+++ b/test-mock/api/removed.txt
@@ -1,14 +1,15 @@
+// Signature format: 2.0
 package android.test.mock {
 
   public class MockContext extends android.content.Context {
     method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
-    method public java.io.File getSharedPreferencesPath(java.lang.String);
+    method public java.io.File getSharedPreferencesPath(String);
   }
 
-  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
-    method public deprecated java.lang.String getDefaultBrowserPackageName(int);
-    method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
-    method public boolean setInstantAppCookie(byte[]);
+  @Deprecated public class MockPackageManager extends android.content.pm.PackageManager {
+    method @Deprecated public String getDefaultBrowserPackageName(int);
+    method @Deprecated public boolean setDefaultBrowserPackageName(String, int);
+    method public boolean setInstantAppCookie(@NonNull byte[]);
   }
 
 }
diff --git a/test-mock/api/system-current.txt b/test-mock/api/system-current.txt
index 2b968ae..f87785b 100644
--- a/test-mock/api/system-current.txt
+++ b/test-mock/api/system-current.txt
@@ -1,38 +1,39 @@
+// Signature format: 2.0
 package android.test.mock {
 
   public class MockContext extends android.content.Context {
     method public android.content.Context createCredentialProtectedStorageContext();
     method public java.io.File getPreloadsFileCache();
     method public boolean isCredentialProtectedStorage();
-    method public void sendBroadcast(android.content.Intent, java.lang.String, android.os.Bundle);
-    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.os.Bundle);
-    method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public void sendBroadcast(android.content.Intent, String, android.os.Bundle);
+    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, String, android.os.Bundle);
+    method public void sendOrderedBroadcast(android.content.Intent, String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
   }
 
-  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
+  @Deprecated public class MockPackageManager extends android.content.pm.PackageManager {
     method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public boolean arePermissionsIndividuallyControlled();
-    method public java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String);
-    method public java.lang.String getDefaultBrowserPackageNameAsUser(int);
+    method @Deprecated public java.util.List<android.content.IntentFilter> getAllIntentFilters(String);
+    method public String getDefaultBrowserPackageNameAsUser(int);
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
-    method public android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String);
+    method public android.graphics.drawable.Drawable getInstantAppIcon(String);
     method public android.content.ComponentName getInstantAppInstallerComponent();
     method public android.content.ComponentName getInstantAppResolverSettingsComponent();
     method public java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
-    method public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
-    method public int getIntentVerificationStatusAsUser(java.lang.String, int);
-    method public int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
-    method public void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
-    method public int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public void registerDexModule(java.lang.String, android.content.pm.PackageManager.DexModuleRegisterCallback);
+    method public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(String);
+    method public int getIntentVerificationStatusAsUser(String, int);
+    method public int getPermissionFlags(String, String, android.os.UserHandle);
+    method public void grantRuntimePermission(String, String, android.os.UserHandle);
+    method public int installExistingPackage(String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public int installExistingPackage(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public void registerDexModule(String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback);
     method public void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
-    method public void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
-    method public boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
-    method public java.lang.String[] setPackagesSuspended(java.lang.String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, java.lang.String);
-    method public void setUpdateAvailable(java.lang.String, boolean);
-    method public boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
-    method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
+    method public void revokeRuntimePermission(String, String, android.os.UserHandle);
+    method public boolean setDefaultBrowserPackageNameAsUser(String, int);
+    method public String[] setPackagesSuspended(String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, String);
+    method public void setUpdateAvailable(String, boolean);
+    method public boolean updateIntentVerificationStatusAsUser(String, int, int);
+    method public void updatePermissionFlags(String, String, int, int, android.os.UserHandle);
     method public void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
   }
 
diff --git a/test-mock/api/system-removed.txt b/test-mock/api/system-removed.txt
index e69de29..d802177 100644
--- a/test-mock/api/system-removed.txt
+++ b/test-mock/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/test-mock/api/test-current.txt b/test-mock/api/test-current.txt
index 8b2c815..ab10800 100644
--- a/test-mock/api/test-current.txt
+++ b/test-mock/api/test-current.txt
@@ -1,17 +1,18 @@
+// Signature format: 2.0
 package android.test.mock {
 
-  public deprecated class MockPackageManager extends android.content.pm.PackageManager {
+  @Deprecated public class MockPackageManager extends android.content.pm.PackageManager {
     method public boolean arePermissionsIndividuallyControlled();
-    method public java.lang.String getDefaultBrowserPackageNameAsUser(int);
-    method public int getInstallReason(java.lang.String, android.os.UserHandle);
+    method public String getDefaultBrowserPackageNameAsUser(int);
+    method public int getInstallReason(String, android.os.UserHandle);
     method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int);
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
-    method public java.lang.String[] getNamesForUids(int[]);
-    method public java.lang.String getPermissionControllerPackageName();
-    method public java.lang.String getServicesSystemSharedLibraryPackageName();
-    method public java.lang.String getSharedSystemSharedLibraryPackageName();
-    method public void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
-    method public void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
+    method public String[] getNamesForUids(int[]);
+    method public String getPermissionControllerPackageName();
+    method @NonNull public String getServicesSystemSharedLibraryPackageName();
+    method @NonNull public String getSharedSystemSharedLibraryPackageName();
+    method public void grantRuntimePermission(String, String, android.os.UserHandle);
+    method public void revokeRuntimePermission(String, String, android.os.UserHandle);
   }
 
 }
diff --git a/test-mock/api/test-removed.txt b/test-mock/api/test-removed.txt
index e69de29..d802177 100644
--- a/test-mock/api/test-removed.txt
+++ b/test-mock/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/test-mock/src/android/test/mock/MockContentProvider.java b/test-mock/src/android/test/mock/MockContentProvider.java
index 0ac35bc..e9a5ff7 100644
--- a/test-mock/src/android/test/mock/MockContentProvider.java
+++ b/test-mock/src/android/test/mock/MockContentProvider.java
@@ -119,7 +119,7 @@
 
         @Override
         public IBinder asBinder() {
-            throw new UnsupportedOperationException();
+            return MockContentProvider.this.getIContentProviderBinder();
         }
 
         @Override
@@ -279,6 +279,13 @@
     }
 
     /**
+     * @hide
+     */
+    public IBinder getIContentProviderBinder() {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    /**
      * Like {@link #attachInfo(Context, android.content.pm.ProviderInfo)}, but for use
      * when directly instantiating the provider for testing.
      *
diff --git a/test-runner/api/current.txt b/test-runner/api/current.txt
index 4ba1b8f..c093ac7 100644
--- a/test-runner/api/current.txt
+++ b/test-runner/api/current.txt
@@ -1,102 +1,103 @@
+// Signature format: 2.0
 package android.test {
 
-  public abstract deprecated class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
-    ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>);
-    ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>, boolean);
-    method public T getActivity();
-    method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
+  @Deprecated public abstract class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
+    ctor @Deprecated public ActivityInstrumentationTestCase(String, Class<T>);
+    ctor @Deprecated public ActivityInstrumentationTestCase(String, Class<T>, boolean);
+    method @Deprecated public T getActivity();
+    method @Deprecated public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract deprecated class ActivityInstrumentationTestCase2<T extends android.app.Activity> extends android.test.ActivityTestCase {
-    ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
-    ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
-    method public T getActivity();
-    method public void setActivityInitialTouchMode(boolean);
-    method public void setActivityIntent(android.content.Intent);
+  @Deprecated public abstract class ActivityInstrumentationTestCase2<T extends android.app.Activity> extends android.test.ActivityTestCase {
+    ctor @Deprecated public ActivityInstrumentationTestCase2(String, Class<T>);
+    ctor @Deprecated public ActivityInstrumentationTestCase2(Class<T>);
+    method @Deprecated public T getActivity();
+    method @Deprecated public void setActivityInitialTouchMode(boolean);
+    method @Deprecated public void setActivityIntent(android.content.Intent);
   }
 
-  public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase {
-    ctor public ActivityTestCase();
-    method protected android.app.Activity getActivity();
-    method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException;
-    method protected void setActivity(android.app.Activity);
+  @Deprecated public abstract class ActivityTestCase extends android.test.InstrumentationTestCase {
+    ctor @Deprecated public ActivityTestCase();
+    method @Deprecated protected android.app.Activity getActivity();
+    method @Deprecated protected void scrubClass(Class<?>) throws java.lang.IllegalAccessException;
+    method @Deprecated protected void setActivity(android.app.Activity);
   }
 
-  public abstract deprecated class ActivityUnitTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
-    ctor public ActivityUnitTestCase(java.lang.Class<T>);
-    method public T getActivity();
-    method public int getFinishedActivityRequest();
-    method public int getRequestedOrientation();
-    method public android.content.Intent getStartedActivityIntent();
-    method public int getStartedActivityRequest();
-    method public boolean isFinishCalled();
-    method public void setActivityContext(android.content.Context);
-    method public void setApplication(android.app.Application);
-    method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object);
+  @Deprecated public abstract class ActivityUnitTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
+    ctor @Deprecated public ActivityUnitTestCase(Class<T>);
+    method @Deprecated public T getActivity();
+    method @Deprecated public int getFinishedActivityRequest();
+    method @Deprecated public int getRequestedOrientation();
+    method @Deprecated public android.content.Intent getStartedActivityIntent();
+    method @Deprecated public int getStartedActivityRequest();
+    method @Deprecated public boolean isFinishCalled();
+    method @Deprecated public void setActivityContext(android.content.Context);
+    method @Deprecated public void setApplication(android.app.Application);
+    method @Deprecated protected T startActivity(android.content.Intent, android.os.Bundle, Object);
   }
 
-  public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner {
-    ctor public AndroidTestRunner();
-    method public void addTestListener(junit.framework.TestListener);
-    method public void clearTestListeners();
-    method protected junit.framework.TestResult createTestResult();
-    method public java.util.List<junit.framework.TestCase> getTestCases();
-    method public java.lang.String getTestClassName();
-    method public junit.framework.TestResult getTestResult();
-    method protected java.lang.Class loadSuiteClass(java.lang.String) throws java.lang.ClassNotFoundException;
-    method protected void runFailed(java.lang.String);
-    method public void runTest();
-    method public void runTest(junit.framework.TestResult);
-    method public void setContext(android.content.Context);
-    method public deprecated void setInstrumentaiton(android.app.Instrumentation);
-    method public void setInstrumentation(android.app.Instrumentation);
-    method public void setTest(junit.framework.Test);
-    method public void setTestClassName(java.lang.String, java.lang.String);
-    method public void testEnded(java.lang.String);
-    method public void testFailed(int, junit.framework.Test, java.lang.Throwable);
-    method public void testStarted(java.lang.String);
+  @Deprecated public class AndroidTestRunner extends junit.runner.BaseTestRunner {
+    ctor @Deprecated public AndroidTestRunner();
+    method @Deprecated public void addTestListener(junit.framework.TestListener);
+    method @Deprecated public void clearTestListeners();
+    method @Deprecated protected junit.framework.TestResult createTestResult();
+    method @Deprecated public java.util.List<junit.framework.TestCase> getTestCases();
+    method @Deprecated public String getTestClassName();
+    method @Deprecated public junit.framework.TestResult getTestResult();
+    method @Deprecated protected Class loadSuiteClass(String) throws java.lang.ClassNotFoundException;
+    method @Deprecated protected void runFailed(String);
+    method @Deprecated public void runTest();
+    method @Deprecated public void runTest(junit.framework.TestResult);
+    method @Deprecated public void setContext(android.content.Context);
+    method @Deprecated public void setInstrumentaiton(android.app.Instrumentation);
+    method @Deprecated public void setInstrumentation(android.app.Instrumentation);
+    method @Deprecated public void setTest(junit.framework.Test);
+    method @Deprecated public void setTestClassName(String, String);
+    method @Deprecated public void testEnded(String);
+    method @Deprecated public void testFailed(int, junit.framework.Test, Throwable);
+    method @Deprecated public void testStarted(String);
   }
 
-  public abstract deprecated class ApplicationTestCase<T extends android.app.Application> extends android.test.AndroidTestCase {
-    ctor public ApplicationTestCase(java.lang.Class<T>);
-    method protected final void createApplication();
-    method public T getApplication();
-    method public android.content.Context getSystemContext();
-    method protected final void terminateApplication();
-    method public final void testApplicationTestCaseSetUpProperly() throws java.lang.Exception;
+  @Deprecated public abstract class ApplicationTestCase<T extends android.app.Application> extends android.test.AndroidTestCase {
+    ctor @Deprecated public ApplicationTestCase(Class<T>);
+    method @Deprecated protected final void createApplication();
+    method @Deprecated public T getApplication();
+    method @Deprecated public android.content.Context getSystemContext();
+    method @Deprecated protected final void terminateApplication();
+    method @Deprecated public final void testApplicationTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public deprecated class AssertionFailedError extends java.lang.Error {
-    ctor public AssertionFailedError();
-    ctor public AssertionFailedError(java.lang.String);
+  @Deprecated public class AssertionFailedError extends java.lang.Error {
+    ctor @Deprecated public AssertionFailedError();
+    ctor @Deprecated public AssertionFailedError(String);
   }
 
-  public deprecated class ComparisonFailure extends android.test.AssertionFailedError {
-    ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
+  @Deprecated public class ComparisonFailure extends android.test.AssertionFailedError {
+    ctor @Deprecated public ComparisonFailure(String, String, String);
   }
 
-  public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
-    ctor public InstrumentationTestRunner();
-    method public junit.framework.TestSuite getAllTests();
-    method protected android.test.AndroidTestRunner getAndroidTestRunner();
-    method public android.os.Bundle getArguments();
-    method public java.lang.ClassLoader getLoader();
-    method public junit.framework.TestSuite getTestSuite();
-    field public static final java.lang.String REPORT_KEY_NAME_CLASS = "class";
-    field public static final java.lang.String REPORT_KEY_NAME_TEST = "test";
-    field public static final java.lang.String REPORT_KEY_NUM_CURRENT = "current";
-    field public static final java.lang.String REPORT_KEY_NUM_TOTAL = "numtests";
-    field public static final java.lang.String REPORT_KEY_STACK = "stack";
-    field public static final java.lang.String REPORT_VALUE_ID = "InstrumentationTestRunner";
-    field public static final int REPORT_VALUE_RESULT_ERROR = -1; // 0xffffffff
-    field public static final int REPORT_VALUE_RESULT_FAILURE = -2; // 0xfffffffe
-    field public static final int REPORT_VALUE_RESULT_OK = 0; // 0x0
-    field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1
+  @Deprecated public class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
+    ctor @Deprecated public InstrumentationTestRunner();
+    method @Deprecated public junit.framework.TestSuite getAllTests();
+    method @Deprecated protected android.test.AndroidTestRunner getAndroidTestRunner();
+    method @Deprecated public android.os.Bundle getArguments();
+    method @Deprecated public ClassLoader getLoader();
+    method @Deprecated public junit.framework.TestSuite getTestSuite();
+    field @Deprecated public static final String REPORT_KEY_NAME_CLASS = "class";
+    field @Deprecated public static final String REPORT_KEY_NAME_TEST = "test";
+    field @Deprecated public static final String REPORT_KEY_NUM_CURRENT = "current";
+    field @Deprecated public static final String REPORT_KEY_NUM_TOTAL = "numtests";
+    field @Deprecated public static final String REPORT_KEY_STACK = "stack";
+    field @Deprecated public static final String REPORT_VALUE_ID = "InstrumentationTestRunner";
+    field @Deprecated public static final int REPORT_VALUE_RESULT_ERROR = -1; // 0xffffffff
+    field @Deprecated public static final int REPORT_VALUE_RESULT_FAILURE = -2; // 0xfffffffe
+    field @Deprecated public static final int REPORT_VALUE_RESULT_OK = 0; // 0x0
+    field @Deprecated public static final int REPORT_VALUE_RESULT_START = 1; // 0x1
   }
 
-  public deprecated class IsolatedContext extends android.content.ContextWrapper {
-    ctor public IsolatedContext(android.content.ContentResolver, android.content.Context);
-    method public java.util.List<android.content.Intent> getAndClearBroadcastIntents();
+  @Deprecated public class IsolatedContext extends android.content.ContextWrapper {
+    ctor @Deprecated public IsolatedContext(android.content.ContentResolver, android.content.Context);
+    method @Deprecated public java.util.List<android.content.Intent> getAndClearBroadcastIntents();
   }
 
   public class LoaderTestCase extends android.test.AndroidTestCase {
@@ -104,184 +105,184 @@
     method public <T> T getLoaderResultSynchronously(android.content.Loader<T>);
   }
 
-  public final deprecated class MoreAsserts {
-    method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object);
-    method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>);
-    method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String);
-    method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String);
-    method public static void assertContentsInAnyOrder(java.lang.String, java.lang.Iterable<?>, java.lang.Object...);
-    method public static void assertContentsInAnyOrder(java.lang.Iterable<?>, java.lang.Object...);
-    method public static void assertContentsInOrder(java.lang.String, java.lang.Iterable<?>, java.lang.Object...);
-    method public static void assertContentsInOrder(java.lang.Iterable<?>, java.lang.Object...);
-    method public static void assertEmpty(java.lang.String, java.lang.Iterable<?>);
-    method public static void assertEmpty(java.lang.Iterable<?>);
-    method public static void assertEmpty(java.lang.String, java.util.Map<?, ?>);
-    method public static void assertEmpty(java.util.Map<?, ?>);
-    method public static void assertEquals(java.lang.String, byte[], byte[]);
-    method public static void assertEquals(byte[], byte[]);
-    method public static void assertEquals(java.lang.String, int[], int[]);
-    method public static void assertEquals(int[], int[]);
-    method public static void assertEquals(java.lang.String, double[], double[]);
-    method public static void assertEquals(double[], double[]);
-    method public static void assertEquals(java.lang.String, java.lang.Object[], java.lang.Object[]);
-    method public static void assertEquals(java.lang.Object[], java.lang.Object[]);
-    method public static void assertEquals(java.lang.String, java.util.Set<?>, java.util.Set<?>);
-    method public static void assertEquals(java.util.Set<?>, java.util.Set<?>);
-    method public static java.util.regex.MatchResult assertMatchesRegex(java.lang.String, java.lang.String, java.lang.String);
-    method public static java.util.regex.MatchResult assertMatchesRegex(java.lang.String, java.lang.String);
-    method public static void assertNotContainsRegex(java.lang.String, java.lang.String, java.lang.String);
-    method public static void assertNotContainsRegex(java.lang.String, java.lang.String);
-    method public static void assertNotEmpty(java.lang.String, java.lang.Iterable<?>);
-    method public static void assertNotEmpty(java.lang.Iterable<?>);
-    method public static void assertNotEmpty(java.lang.String, java.util.Map<?, ?>);
-    method public static void assertNotEmpty(java.util.Map<?, ?>);
-    method public static void assertNotEqual(java.lang.String, java.lang.Object, java.lang.Object);
-    method public static void assertNotEqual(java.lang.Object, java.lang.Object);
-    method public static void assertNotMatchesRegex(java.lang.String, java.lang.String, java.lang.String);
-    method public static void assertNotMatchesRegex(java.lang.String, java.lang.String);
-    method public static void checkEqualsAndHashCodeMethods(java.lang.String, java.lang.Object, java.lang.Object, boolean);
-    method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean);
+  @Deprecated public final class MoreAsserts {
+    method @Deprecated public static void assertAssignableFrom(Class<?>, Object);
+    method @Deprecated public static void assertAssignableFrom(Class<?>, Class<?>);
+    method @Deprecated public static java.util.regex.MatchResult assertContainsRegex(String, String, String);
+    method @Deprecated public static java.util.regex.MatchResult assertContainsRegex(String, String);
+    method @Deprecated public static void assertContentsInAnyOrder(String, Iterable<?>, java.lang.Object...);
+    method @Deprecated public static void assertContentsInAnyOrder(Iterable<?>, java.lang.Object...);
+    method @Deprecated public static void assertContentsInOrder(String, Iterable<?>, java.lang.Object...);
+    method @Deprecated public static void assertContentsInOrder(Iterable<?>, java.lang.Object...);
+    method @Deprecated public static void assertEmpty(String, Iterable<?>);
+    method @Deprecated public static void assertEmpty(Iterable<?>);
+    method @Deprecated public static void assertEmpty(String, java.util.Map<?,?>);
+    method @Deprecated public static void assertEmpty(java.util.Map<?,?>);
+    method @Deprecated public static void assertEquals(String, byte[], byte[]);
+    method @Deprecated public static void assertEquals(byte[], byte[]);
+    method @Deprecated public static void assertEquals(String, int[], int[]);
+    method @Deprecated public static void assertEquals(int[], int[]);
+    method @Deprecated public static void assertEquals(String, double[], double[]);
+    method @Deprecated public static void assertEquals(double[], double[]);
+    method @Deprecated public static void assertEquals(String, Object[], Object[]);
+    method @Deprecated public static void assertEquals(Object[], Object[]);
+    method @Deprecated public static void assertEquals(String, java.util.Set<?>, java.util.Set<?>);
+    method @Deprecated public static void assertEquals(java.util.Set<?>, java.util.Set<?>);
+    method @Deprecated public static java.util.regex.MatchResult assertMatchesRegex(String, String, String);
+    method @Deprecated public static java.util.regex.MatchResult assertMatchesRegex(String, String);
+    method @Deprecated public static void assertNotContainsRegex(String, String, String);
+    method @Deprecated public static void assertNotContainsRegex(String, String);
+    method @Deprecated public static void assertNotEmpty(String, Iterable<?>);
+    method @Deprecated public static void assertNotEmpty(Iterable<?>);
+    method @Deprecated public static void assertNotEmpty(String, java.util.Map<?,?>);
+    method @Deprecated public static void assertNotEmpty(java.util.Map<?,?>);
+    method @Deprecated public static void assertNotEqual(String, Object, Object);
+    method @Deprecated public static void assertNotEqual(Object, Object);
+    method @Deprecated public static void assertNotMatchesRegex(String, String, String);
+    method @Deprecated public static void assertNotMatchesRegex(String, String);
+    method @Deprecated public static void checkEqualsAndHashCodeMethods(String, Object, Object, boolean);
+    method @Deprecated public static void checkEqualsAndHashCodeMethods(Object, Object, boolean);
   }
 
-  public abstract deprecated class ProviderTestCase<T extends android.content.ContentProvider> extends android.test.InstrumentationTestCase {
-    ctor public ProviderTestCase(java.lang.Class<T>, java.lang.String);
-    method public android.test.mock.MockContentResolver getMockContentResolver();
-    method public android.test.IsolatedContext getMockContext();
-    method public T getProvider();
-    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+  @Deprecated public abstract class ProviderTestCase<T extends android.content.ContentProvider> extends android.test.InstrumentationTestCase {
+    ctor @Deprecated public ProviderTestCase(Class<T>, String);
+    method @Deprecated public android.test.mock.MockContentResolver getMockContentResolver();
+    method @Deprecated public android.test.IsolatedContext getMockContext();
+    method @Deprecated public T getProvider();
+    method @Deprecated public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, Class<T>, String, String, int, String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
   public abstract class ProviderTestCase2<T extends android.content.ContentProvider> extends android.test.AndroidTestCase {
-    ctor public ProviderTestCase2(java.lang.Class<T>, java.lang.String);
+    ctor public ProviderTestCase2(Class<T>, String);
     method public android.test.mock.MockContentResolver getMockContentResolver();
     method public android.test.IsolatedContext getMockContext();
     method public T getProvider();
-    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, String, Class<T>, String, String, int, String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
-    ctor public RenamingDelegatingContext(android.content.Context, java.lang.String);
-    ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
-    method public java.lang.String getDatabasePrefix();
-    method public void makeExistingFilesAndDbsAccessible();
-    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
-    method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+  @Deprecated public class RenamingDelegatingContext extends android.content.ContextWrapper {
+    ctor @Deprecated public RenamingDelegatingContext(android.content.Context, String);
+    ctor @Deprecated public RenamingDelegatingContext(android.content.Context, android.content.Context, String);
+    method @Deprecated public String getDatabasePrefix();
+    method @Deprecated public void makeExistingFilesAndDbsAccessible();
+    method @Deprecated public static <T extends android.content.ContentProvider> T providerWithRenamedContext(Class<T>, android.content.Context, String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method @Deprecated public static <T extends android.content.ContentProvider> T providerWithRenamedContext(Class<T>, android.content.Context, String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
   }
 
-  public abstract deprecated class ServiceTestCase<T extends android.app.Service> extends android.test.AndroidTestCase {
-    ctor public ServiceTestCase(java.lang.Class<T>);
-    method protected android.os.IBinder bindService(android.content.Intent);
-    method public android.app.Application getApplication();
-    method public T getService();
-    method public android.content.Context getSystemContext();
-    method public void setApplication(android.app.Application);
-    method protected void setupService();
-    method protected void shutdownService();
-    method protected void startService(android.content.Intent);
-    method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
+  @Deprecated public abstract class ServiceTestCase<T extends android.app.Service> extends android.test.AndroidTestCase {
+    ctor @Deprecated public ServiceTestCase(Class<T>);
+    method @Deprecated protected android.os.IBinder bindService(android.content.Intent);
+    method @Deprecated public android.app.Application getApplication();
+    method @Deprecated public T getService();
+    method @Deprecated public android.content.Context getSystemContext();
+    method @Deprecated public void setApplication(android.app.Application);
+    method @Deprecated protected void setupService();
+    method @Deprecated protected void shutdownService();
+    method @Deprecated protected void startService(android.content.Intent);
+    method @Deprecated public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public abstract deprecated class SingleLaunchActivityTestCase<T extends android.app.Activity> extends android.test.InstrumentationTestCase {
-    ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
-    method public T getActivity();
-    method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
+  @Deprecated public abstract class SingleLaunchActivityTestCase<T extends android.app.Activity> extends android.test.InstrumentationTestCase {
+    ctor @Deprecated public SingleLaunchActivityTestCase(String, Class<T>);
+    method @Deprecated public T getActivity();
+    method @Deprecated public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
   }
 
-  public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
-    ctor public SyncBaseInstrumentation();
-    method protected void cancelSyncsandDisableAutoSync();
-    method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception;
+  @Deprecated public class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
+    ctor @Deprecated public SyncBaseInstrumentation();
+    method @Deprecated protected void cancelSyncsandDisableAutoSync();
+    method @Deprecated protected void syncProvider(android.net.Uri, String, String) throws java.lang.Exception;
   }
 
-  public abstract deprecated interface TestSuiteProvider {
-    method public abstract junit.framework.TestSuite getTestSuite();
+  @Deprecated public interface TestSuiteProvider {
+    method @Deprecated public junit.framework.TestSuite getTestSuite();
   }
 
-  public deprecated class TouchUtils {
-    ctor public TouchUtils();
-    method public static void clickView(android.test.InstrumentationTestCase, android.view.View);
-    method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int);
-    method public static void drag(android.test.InstrumentationTestCase, float, float, float, float, int);
-    method public static deprecated void dragQuarterScreenDown(android.test.ActivityInstrumentationTestCase);
-    method public static void dragQuarterScreenDown(android.test.InstrumentationTestCase, android.app.Activity);
-    method public static deprecated void dragQuarterScreenUp(android.test.ActivityInstrumentationTestCase);
-    method public static void dragQuarterScreenUp(android.test.InstrumentationTestCase, android.app.Activity);
-    method public static deprecated int dragViewBy(android.test.ActivityInstrumentationTestCase, android.view.View, int, int, int);
-    method public static deprecated int dragViewBy(android.test.InstrumentationTestCase, android.view.View, int, int, int);
-    method public static deprecated int dragViewTo(android.test.ActivityInstrumentationTestCase, android.view.View, int, int, int);
-    method public static int dragViewTo(android.test.InstrumentationTestCase, android.view.View, int, int, int);
-    method public static deprecated void dragViewToBottom(android.test.ActivityInstrumentationTestCase, android.view.View);
-    method public static void dragViewToBottom(android.test.InstrumentationTestCase, android.app.Activity, android.view.View);
-    method public static deprecated void dragViewToBottom(android.test.ActivityInstrumentationTestCase, android.view.View, int);
-    method public static void dragViewToBottom(android.test.InstrumentationTestCase, android.app.Activity, android.view.View, int);
-    method public static deprecated void dragViewToTop(android.test.ActivityInstrumentationTestCase, android.view.View);
-    method public static deprecated void dragViewToTop(android.test.ActivityInstrumentationTestCase, android.view.View, int);
-    method public static void dragViewToTop(android.test.InstrumentationTestCase, android.view.View);
-    method public static void dragViewToTop(android.test.InstrumentationTestCase, android.view.View, int);
-    method public static deprecated int dragViewToX(android.test.ActivityInstrumentationTestCase, android.view.View, int, int);
-    method public static int dragViewToX(android.test.InstrumentationTestCase, android.view.View, int, int);
-    method public static deprecated int dragViewToY(android.test.ActivityInstrumentationTestCase, android.view.View, int, int);
-    method public static int dragViewToY(android.test.InstrumentationTestCase, android.view.View, int, int);
-    method public static deprecated void longClickView(android.test.ActivityInstrumentationTestCase, android.view.View);
-    method public static void longClickView(android.test.InstrumentationTestCase, android.view.View);
-    method public static deprecated void scrollToBottom(android.test.ActivityInstrumentationTestCase, android.view.ViewGroup);
-    method public static void scrollToBottom(android.test.InstrumentationTestCase, android.app.Activity, android.view.ViewGroup);
-    method public static deprecated void scrollToTop(android.test.ActivityInstrumentationTestCase, android.view.ViewGroup);
-    method public static void scrollToTop(android.test.InstrumentationTestCase, android.app.Activity, android.view.ViewGroup);
-    method public static void tapView(android.test.InstrumentationTestCase, android.view.View);
-    method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View);
+  @Deprecated public class TouchUtils {
+    ctor @Deprecated public TouchUtils();
+    method @Deprecated public static void clickView(android.test.InstrumentationTestCase, android.view.View);
+    method @Deprecated public static void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int);
+    method @Deprecated public static void drag(android.test.InstrumentationTestCase, float, float, float, float, int);
+    method @Deprecated public static void dragQuarterScreenDown(android.test.ActivityInstrumentationTestCase);
+    method @Deprecated public static void dragQuarterScreenDown(android.test.InstrumentationTestCase, android.app.Activity);
+    method @Deprecated public static void dragQuarterScreenUp(android.test.ActivityInstrumentationTestCase);
+    method @Deprecated public static void dragQuarterScreenUp(android.test.InstrumentationTestCase, android.app.Activity);
+    method @Deprecated public static int dragViewBy(android.test.ActivityInstrumentationTestCase, android.view.View, int, int, int);
+    method @Deprecated public static int dragViewBy(android.test.InstrumentationTestCase, android.view.View, int, int, int);
+    method @Deprecated public static int dragViewTo(android.test.ActivityInstrumentationTestCase, android.view.View, int, int, int);
+    method @Deprecated public static int dragViewTo(android.test.InstrumentationTestCase, android.view.View, int, int, int);
+    method @Deprecated public static void dragViewToBottom(android.test.ActivityInstrumentationTestCase, android.view.View);
+    method @Deprecated public static void dragViewToBottom(android.test.InstrumentationTestCase, android.app.Activity, android.view.View);
+    method @Deprecated public static void dragViewToBottom(android.test.ActivityInstrumentationTestCase, android.view.View, int);
+    method @Deprecated public static void dragViewToBottom(android.test.InstrumentationTestCase, android.app.Activity, android.view.View, int);
+    method @Deprecated public static void dragViewToTop(android.test.ActivityInstrumentationTestCase, android.view.View);
+    method @Deprecated public static void dragViewToTop(android.test.ActivityInstrumentationTestCase, android.view.View, int);
+    method @Deprecated public static void dragViewToTop(android.test.InstrumentationTestCase, android.view.View);
+    method @Deprecated public static void dragViewToTop(android.test.InstrumentationTestCase, android.view.View, int);
+    method @Deprecated public static int dragViewToX(android.test.ActivityInstrumentationTestCase, android.view.View, int, int);
+    method @Deprecated public static int dragViewToX(android.test.InstrumentationTestCase, android.view.View, int, int);
+    method @Deprecated public static int dragViewToY(android.test.ActivityInstrumentationTestCase, android.view.View, int, int);
+    method @Deprecated public static int dragViewToY(android.test.InstrumentationTestCase, android.view.View, int, int);
+    method @Deprecated public static void longClickView(android.test.ActivityInstrumentationTestCase, android.view.View);
+    method @Deprecated public static void longClickView(android.test.InstrumentationTestCase, android.view.View);
+    method @Deprecated public static void scrollToBottom(android.test.ActivityInstrumentationTestCase, android.view.ViewGroup);
+    method @Deprecated public static void scrollToBottom(android.test.InstrumentationTestCase, android.app.Activity, android.view.ViewGroup);
+    method @Deprecated public static void scrollToTop(android.test.ActivityInstrumentationTestCase, android.view.ViewGroup);
+    method @Deprecated public static void scrollToTop(android.test.InstrumentationTestCase, android.app.Activity, android.view.ViewGroup);
+    method @Deprecated public static void tapView(android.test.InstrumentationTestCase, android.view.View);
+    method @Deprecated public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View);
   }
 
-  public deprecated class ViewAsserts {
-    method public static void assertBaselineAligned(android.view.View, android.view.View);
-    method public static void assertBottomAligned(android.view.View, android.view.View);
-    method public static void assertBottomAligned(android.view.View, android.view.View, int);
-    method public static void assertGroupContains(android.view.ViewGroup, android.view.View);
-    method public static void assertGroupIntegrity(android.view.ViewGroup);
-    method public static void assertGroupNotContains(android.view.ViewGroup, android.view.View);
-    method public static void assertHasScreenCoordinates(android.view.View, android.view.View, int, int);
-    method public static void assertHorizontalCenterAligned(android.view.View, android.view.View);
-    method public static void assertLeftAligned(android.view.View, android.view.View);
-    method public static void assertLeftAligned(android.view.View, android.view.View, int);
-    method public static void assertOffScreenAbove(android.view.View, android.view.View);
-    method public static void assertOffScreenBelow(android.view.View, android.view.View);
-    method public static void assertOnScreen(android.view.View, android.view.View);
-    method public static void assertRightAligned(android.view.View, android.view.View);
-    method public static void assertRightAligned(android.view.View, android.view.View, int);
-    method public static void assertTopAligned(android.view.View, android.view.View);
-    method public static void assertTopAligned(android.view.View, android.view.View, int);
-    method public static void assertVerticalCenterAligned(android.view.View, android.view.View);
+  @Deprecated public class ViewAsserts {
+    method @Deprecated public static void assertBaselineAligned(android.view.View, android.view.View);
+    method @Deprecated public static void assertBottomAligned(android.view.View, android.view.View);
+    method @Deprecated public static void assertBottomAligned(android.view.View, android.view.View, int);
+    method @Deprecated public static void assertGroupContains(android.view.ViewGroup, android.view.View);
+    method @Deprecated public static void assertGroupIntegrity(android.view.ViewGroup);
+    method @Deprecated public static void assertGroupNotContains(android.view.ViewGroup, android.view.View);
+    method @Deprecated public static void assertHasScreenCoordinates(android.view.View, android.view.View, int, int);
+    method @Deprecated public static void assertHorizontalCenterAligned(android.view.View, android.view.View);
+    method @Deprecated public static void assertLeftAligned(android.view.View, android.view.View);
+    method @Deprecated public static void assertLeftAligned(android.view.View, android.view.View, int);
+    method @Deprecated public static void assertOffScreenAbove(android.view.View, android.view.View);
+    method @Deprecated public static void assertOffScreenBelow(android.view.View, android.view.View);
+    method @Deprecated public static void assertOnScreen(android.view.View, android.view.View);
+    method @Deprecated public static void assertRightAligned(android.view.View, android.view.View);
+    method @Deprecated public static void assertRightAligned(android.view.View, android.view.View, int);
+    method @Deprecated public static void assertTopAligned(android.view.View, android.view.View);
+    method @Deprecated public static void assertTopAligned(android.view.View, android.view.View, int);
+    method @Deprecated public static void assertVerticalCenterAligned(android.view.View, android.view.View);
   }
 
 }
 
 package android.test.suitebuilder {
 
-  public deprecated class TestMethod {
-    ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
-    ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
-    ctor public TestMethod(junit.framework.TestCase);
-    method public junit.framework.TestCase createTest() throws java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
-    method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
-    method public java.lang.Class<? extends junit.framework.TestCase> getEnclosingClass();
-    method public java.lang.String getEnclosingClassname();
-    method public java.lang.String getName();
+  @Deprecated public class TestMethod {
+    ctor @Deprecated public TestMethod(java.lang.reflect.Method, Class<? extends junit.framework.TestCase>);
+    ctor @Deprecated public TestMethod(String, Class<? extends junit.framework.TestCase>);
+    ctor @Deprecated public TestMethod(junit.framework.TestCase);
+    method @Deprecated public junit.framework.TestCase createTest() throws java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
+    method @Deprecated public <T extends java.lang.annotation.Annotation> T getAnnotation(Class<T>);
+    method @Deprecated public Class<? extends junit.framework.TestCase> getEnclosingClass();
+    method @Deprecated public String getEnclosingClassname();
+    method @Deprecated public String getName();
   }
 
-  public deprecated class TestSuiteBuilder {
-    ctor public TestSuiteBuilder(java.lang.Class);
-    ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
-    method public final junit.framework.TestSuite build();
-    method public android.test.suitebuilder.TestSuiteBuilder excludePackages(java.lang.String...);
-    method protected java.lang.String getSuiteName();
-    method public final android.test.suitebuilder.TestSuiteBuilder includeAllPackagesUnderHere();
-    method public android.test.suitebuilder.TestSuiteBuilder includePackages(java.lang.String...);
-    method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
+  @Deprecated public class TestSuiteBuilder {
+    ctor @Deprecated public TestSuiteBuilder(Class);
+    ctor @Deprecated public TestSuiteBuilder(String, ClassLoader);
+    method @Deprecated public final junit.framework.TestSuite build();
+    method @Deprecated public android.test.suitebuilder.TestSuiteBuilder excludePackages(java.lang.String...);
+    method @Deprecated protected String getSuiteName();
+    method @Deprecated public final android.test.suitebuilder.TestSuiteBuilder includeAllPackagesUnderHere();
+    method @Deprecated public android.test.suitebuilder.TestSuiteBuilder includePackages(java.lang.String...);
+    method @Deprecated public android.test.suitebuilder.TestSuiteBuilder named(String);
   }
 
-  public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
-    ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
-    method public void testSuiteConstructionFailed();
+  @Deprecated public static class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+    ctor @Deprecated public TestSuiteBuilder.FailedToCreateTests(Exception);
+    method @Deprecated public void testSuiteConstructionFailed();
   }
 
 }
@@ -290,44 +291,44 @@
 
   public abstract class BaseTestRunner implements junit.framework.TestListener {
     ctor public BaseTestRunner();
-    method public synchronized void addError(junit.framework.Test, java.lang.Throwable);
-    method public synchronized void addFailure(junit.framework.Test, junit.framework.AssertionFailedError);
+    method public void addError(junit.framework.Test, Throwable);
+    method public void addFailure(junit.framework.Test, junit.framework.AssertionFailedError);
     method protected void clearStatus();
-    method public java.lang.String elapsedTimeAsString(long);
-    method public synchronized void endTest(junit.framework.Test);
-    method public java.lang.String extractClassName(java.lang.String);
-    method public static java.lang.String getFilteredTrace(java.lang.Throwable);
-    method public static java.lang.String getFilteredTrace(java.lang.String);
-    method public deprecated junit.runner.TestSuiteLoader getLoader();
-    method public static java.lang.String getPreference(java.lang.String);
-    method public static int getPreference(java.lang.String, int);
+    method public String elapsedTimeAsString(long);
+    method public void endTest(junit.framework.Test);
+    method public String extractClassName(String);
+    method public static String getFilteredTrace(Throwable);
+    method public static String getFilteredTrace(String);
+    method @Deprecated public junit.runner.TestSuiteLoader getLoader();
+    method public static String getPreference(String);
+    method public static int getPreference(String, int);
     method protected static java.util.Properties getPreferences();
-    method public junit.framework.Test getTest(java.lang.String);
-    method public static deprecated boolean inVAJava();
-    method protected java.lang.Class<?> loadSuiteClass(java.lang.String) throws java.lang.ClassNotFoundException;
-    method protected java.lang.String processArguments(java.lang.String[]);
-    method protected abstract void runFailed(java.lang.String);
+    method public junit.framework.Test getTest(String);
+    method @Deprecated public static boolean inVAJava();
+    method protected Class<?> loadSuiteClass(String) throws java.lang.ClassNotFoundException;
+    method protected String processArguments(String[]);
+    method protected abstract void runFailed(String);
     method public static void savePreferences() throws java.io.IOException;
     method public void setLoading(boolean);
-    method public void setPreference(java.lang.String, java.lang.String);
+    method public void setPreference(String, String);
     method protected static void setPreferences(java.util.Properties);
     method protected static boolean showStackRaw();
-    method public synchronized void startTest(junit.framework.Test);
-    method public abstract void testEnded(java.lang.String);
-    method public abstract void testFailed(int, junit.framework.Test, java.lang.Throwable);
-    method public abstract void testStarted(java.lang.String);
-    method public static java.lang.String truncate(java.lang.String);
+    method public void startTest(junit.framework.Test);
+    method public abstract void testEnded(String);
+    method public abstract void testFailed(int, junit.framework.Test, Throwable);
+    method public abstract void testStarted(String);
+    method public static String truncate(String);
     method protected boolean useReloadingTestSuiteLoader();
-    field public static final java.lang.String SUITE_METHODNAME = "suite";
+    field public static final String SUITE_METHODNAME = "suite";
   }
 
-  public abstract interface TestSuiteLoader {
-    method public abstract java.lang.Class load(java.lang.String) throws java.lang.ClassNotFoundException;
-    method public abstract java.lang.Class reload(java.lang.Class) throws java.lang.ClassNotFoundException;
+  public interface TestSuiteLoader {
+    method public Class load(String) throws java.lang.ClassNotFoundException;
+    method public Class reload(Class) throws java.lang.ClassNotFoundException;
   }
 
   public class Version {
-    method public static java.lang.String id();
+    method public static String id();
   }
 
 }
diff --git a/test-runner/api/removed.txt b/test-runner/api/removed.txt
index e69de29..d802177 100644
--- a/test-runner/api/removed.txt
+++ b/test-runner/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/test-runner/api/system-current.txt b/test-runner/api/system-current.txt
index e69de29..d802177 100644
--- a/test-runner/api/system-current.txt
+++ b/test-runner/api/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/test-runner/api/system-removed.txt b/test-runner/api/system-removed.txt
index e69de29..d802177 100644
--- a/test-runner/api/system-removed.txt
+++ b/test-runner/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/test-runner/api/test-current.txt b/test-runner/api/test-current.txt
index e69de29..d802177 100644
--- a/test-runner/api/test-current.txt
+++ b/test-runner/api/test-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/test-runner/api/test-removed.txt b/test-runner/api/test-removed.txt
index e69de29..d802177 100644
--- a/test-runner/api/test-removed.txt
+++ b/test-runner/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/tests/ActivityViewTest/Android.mk b/tests/ActivityViewTest/Android.mk
index 9c80764..9c7ca7e 100644
--- a/tests/ActivityViewTest/Android.mk
+++ b/tests/ActivityViewTest/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := ActivityViewTest
 LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/tests/ActivityViewTest/AndroidManifest.xml b/tests/ActivityViewTest/AndroidManifest.xml
index de54cc9..17eb029 100644
--- a/tests/ActivityViewTest/AndroidManifest.xml
+++ b/tests/ActivityViewTest/AndroidManifest.xml
@@ -35,17 +35,20 @@
 
         <activity android:name=".ActivityViewActivity"
                   android:label="AV"
-                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"
+                  android:windowSoftInputMode="stateHidden|adjustResize">
         </activity>
 
         <activity android:name=".ActivityViewResizeActivity"
                   android:label="AV Resize"
-                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"
+                  android:windowSoftInputMode="stateHidden|adjustResize">
         </activity>
 
         <activity android:name=".ActivityViewScrollActivity"
                   android:label="AV Scroll"
-                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"
+                  android:windowSoftInputMode="stateHidden">
         </activity>
 
         <activity android:name=".ActivityViewTestActivity"
@@ -54,5 +57,10 @@
                   android:exported="true"
                   android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
         </activity>
+
+        <activity android:name=".ActivityViewVisibilityActivity"
+                  android:label="AV Visibility"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
+        </activity>
     </application>
 </manifest>
diff --git a/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml
index ba2e911..efcaef6 100644
--- a/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml
+++ b/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml
@@ -41,4 +41,10 @@
         android:text="Test Resize ActivityView"
         android:textAllCaps="false"/>
 
+    <Button
+        android:id="@+id/visibility_activity_view_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Test ActivityView Visibility"
+        android:textAllCaps="false"/>
 </LinearLayout>
diff --git a/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml
index f7ec562..338d68a 100644
--- a/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml
+++ b/tests/ActivityViewTest/res/layout/activity_view_test_activity.xml
@@ -15,6 +15,7 @@
 -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:id="@+id/test_activity_root"
                 android:orientation="vertical"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
@@ -60,11 +61,10 @@
         android:background="#00000000"
         android:gravity="center" />
 
-    <View
-        android:id="@+id/touch_intercept_view"
+    <EditText
+        android:id="@+id/test_activity_edittext"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="#00000000"
-    />
-
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_margin="16dp" />
 </RelativeLayout>
\ No newline at end of file
diff --git a/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml
new file mode 100644
index 0000000..d29d4df
--- /dev/null
+++ b/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:background="#cfd8dc">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/activity_launch_button"
+            android:layout_width="200dp"
+            android:layout_height="wrap_content"
+            android:text="Launch test activity" />
+
+        <Spinner
+            android:id="@+id/visibility_spinner"
+            android:layout_width="200dp"
+            android:layout_height="match_parent"/>
+
+    </LinearLayout>
+
+    <ActivityView
+        android:id="@+id/activity_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
index 66f0c6a..4f09c28 100644
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
@@ -35,5 +35,8 @@
 
         findViewById(R.id.resize_activity_view_button).setOnClickListener(
                 v -> startActivity(new Intent(this, ActivityViewResizeActivity.class)));
+
+        findViewById(R.id.visibility_activity_view_button).setOnClickListener(
+                v -> startActivity(new Intent(this, ActivityViewVisibilityActivity.class)));
     }
 }
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
index 0d62786..52aba2b 100644
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
@@ -24,31 +24,31 @@
 import android.app.Activity;
 import android.content.res.Configuration;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.widget.TextView;
 
-public class ActivityViewTestActivity extends Activity implements View.OnTouchListener {
+public class ActivityViewTestActivity extends Activity {
+    private static final String TAG = "ActivityViewTestActivity";
 
+    private View mRoot;
     private TextView mTextView;
     private TextView mWidthTextView;
     private TextView mHeightTextView;
     private TextView mTouchStateTextView;
-    private View mTouchInterceptView;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_view_test_activity);
-
+        mRoot = findViewById(R.id.test_activity_root);
         mTextView = findViewById(R.id.test_activity_title);
         mWidthTextView = findViewById(R.id.test_activity_width_text);
         mHeightTextView = findViewById(R.id.test_activity_height_text);
         mTouchStateTextView = findViewById(R.id.test_activity_touch_state);
-        mTouchInterceptView = findViewById(R.id.touch_intercept_view);
-        mTouchInterceptView.setOnTouchListener(this);
-        ViewTreeObserver viewTreeObserver = mTouchInterceptView.getViewTreeObserver();
+        ViewTreeObserver viewTreeObserver = mRoot.getViewTreeObserver();
         if (viewTreeObserver.isAlive()) {
             viewTreeObserver.addOnGlobalLayoutListener(this::updateDimensionTexts);
         }
@@ -86,12 +86,13 @@
     }
 
     private void updateStateText(String state) {
+        Log.d(TAG, state);
         mTextView.setText(state);
     }
 
     private void updateDimensionTexts() {
-        mWidthTextView.setText("" + mTouchInterceptView.getWidth());
-        mHeightTextView.setText("" + mTouchInterceptView.getHeight());
+        mWidthTextView.setText("" + mRoot.getWidth());
+        mHeightTextView.setText("" + mRoot.getHeight());
     }
 
     private void updateTouchState(MotionEvent event) {
@@ -108,8 +109,8 @@
     }
 
     @Override
-    public boolean onTouch(View v, MotionEvent event) {
+    public boolean dispatchTouchEvent(MotionEvent event) {
         updateTouchState(event);
-        return true;
+        return super.dispatchTouchEvent(event);
     }
 }
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java
new file mode 100644
index 0000000..ecd2cf3
--- /dev/null
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.activityview;
+
+import static android.view.View.GONE;
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+import android.app.Activity;
+import android.app.ActivityView;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+
+public class ActivityViewVisibilityActivity extends Activity {
+    private static final String[] sVisibilityOptions = {"VISIBLE", "INVISIBLE", "GONE"};
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_view_visibility_activity);
+
+        final ActivityView activityView = findViewById(R.id.activity_view);
+        final Button launchButton = findViewById(R.id.activity_launch_button);
+        launchButton.setOnClickListener(v -> {
+            final Intent intent = new Intent(this, ActivityViewTestActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+            activityView.startActivity(intent);
+        });
+
+        final Spinner visibilitySpinner = findViewById(R.id.visibility_spinner);
+        final ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
+                android.R.layout.simple_spinner_item, sVisibilityOptions);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        visibilitySpinner.setAdapter(adapter);
+        visibilitySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+                switch (position) {
+                    case 0:
+                        activityView.setVisibility(VISIBLE);
+                        break;
+                    case 1:
+                        activityView.setVisibility(INVISIBLE);
+                        break;
+                    case 2:
+                        activityView.setVisibility(GONE);
+                        break;
+                }
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> parent) {
+            }
+        });
+    }
+}
diff --git a/tests/DexLoggerIntegrationTests/Android.mk b/tests/DexLoggerIntegrationTests/Android.mk
index ee2ec0a..979d13a 100644
--- a/tests/DexLoggerIntegrationTests/Android.mk
+++ b/tests/DexLoggerIntegrationTests/Android.mk
@@ -29,6 +29,35 @@
 dexloggertest_jar := $(LOCAL_BUILT_MODULE)
 
 
+# Also build a native library that the test app can dynamically load
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := DexLoggerNativeTestLibrary
+LOCAL_MULTILIB := first
+LOCAL_SRC_FILES := src/cpp/com_android_dcl_Jni.cpp
+LOCAL_C_INCLUDES += \
+    $(JNI_H_INCLUDE)
+LOCAL_SDK_VERSION := 28
+LOCAL_NDK_STL_VARIANT := c++_static
+
+include $(BUILD_SHARED_LIBRARY)
+
+dexloggertest_so := $(LOCAL_BUILT_MODULE)
+
+# And a standalone native executable that we can exec.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE := DexLoggerNativeExecutable
+LOCAL_SRC_FILES := src/cpp/test_executable.cpp
+
+include $(BUILD_EXECUTABLE)
+
+dexloggertest_executable := $(LOCAL_BUILT_MODULE)
+
 # Build the test app itself
 
 include $(CLEAR_VARS)
@@ -37,14 +66,18 @@
 LOCAL_PACKAGE_NAME := DexLoggerIntegrationTests
 LOCAL_SDK_VERSION := current
 LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_CERTIFICATE := platform
+LOCAL_CERTIFICATE := shared
 LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/server/pm)
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-test \
     truth-prebuilt \
 
-# This gets us the javalib.jar built by DexLoggerTestLibrary above.
-LOCAL_JAVA_RESOURCE_FILES := $(dexloggertest_jar)
+# This gets us the javalib.jar built by DexLoggerTestLibrary above as well as the various
+# native binaries.
+LOCAL_JAVA_RESOURCE_FILES := \
+    $(dexloggertest_jar) \
+    $(dexloggertest_so) \
+    $(dexloggertest_executable)
 
 include $(BUILD_PACKAGE)
diff --git a/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java
index 75ee089..d68769b 100644
--- a/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java
+++ b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java
@@ -17,6 +17,7 @@
 package com.android.server.pm.dex;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.app.UiAutomation;
 import android.content.Context;
@@ -25,6 +26,7 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.util.EventLog;
+import android.util.EventLog.Event;
 
 import dalvik.system.DexClassLoader;
 
@@ -65,14 +67,13 @@
     // Event log tag used for SNET related events
     private static final int SNET_TAG = 0x534e4554;
 
-    // Subtag used to distinguish dynamic code loading events
-    private static final String DCL_SUBTAG = "dcl";
+    // Subtags used to distinguish dynamic code loading events
+    private static final String DCL_DEX_SUBTAG = "dcl";
+    private static final String DCL_NATIVE_SUBTAG = "dcln";
 
-    // All the tags we care about
-    private static final int[] TAG_LIST = new int[] { SNET_TAG };
-
-    // This is {@code DynamicCodeLoggingService#JOB_ID}
-    private static final int DYNAMIC_CODE_LOGGING_JOB_ID = 2030028;
+    // These are job IDs from DynamicCodeLoggingService
+    private static final int IDLE_LOGGING_JOB_ID = 2030028;
+    private static final int AUDIT_WATCHING_JOB_ID = 203142925;
 
     private static Context sContext;
     private static int sMyUid;
@@ -89,15 +90,20 @@
         // Without this the first test passes and others don't - we don't see new events in the
         // log. The exact reason is unclear.
         EventLog.writeEvent(SNET_TAG, "Dummy event");
+
+        // Audit log messages are throttled by the kernel (at the request of logd) to 5 per
+        // second, so running the tests too quickly in sequence means we lose some and get
+        // spurious failures. Sigh.
+        SystemClock.sleep(1000);
     }
 
     @Test
-    public void testDexLoggerGeneratesEvents() throws Exception {
-        File privateCopyFile = fileForJar("copied.jar");
+    public void testDexLoggerGeneratesEvents_standardClassLoader() throws Exception {
+        File privateCopyFile = privateFile("copied.jar");
         // Obtained via "echo -n copied.jar | sha256sum"
         String expectedNameHash =
                 "1B6C71DB26F36582867432CCA12FB6A517470C9F9AABE9198DD4C5C030D6DC0C";
-        String expectedContentHash = copyAndHashJar(privateCopyFile);
+        String expectedContentHash = copyAndHashResource("/javalib.jar", privateCopyFile);
 
         // Feed the jar to a class loader and make sure it contains what we expect.
         ClassLoader parentClassLoader = sContext.getClass().getClassLoader();
@@ -107,18 +113,18 @@
 
         // And make sure we log events about it
         long previousEventNanos = mostRecentEventTimeNanos();
-        runDexLogger();
+        runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID);
 
-        assertDclLoggedSince(previousEventNanos, expectedNameHash, expectedContentHash);
+        assertDclLoggedSince(previousEventNanos, DCL_DEX_SUBTAG,
+                expectedNameHash, expectedContentHash);
     }
 
     @Test
-
     public void testDexLoggerGeneratesEvents_unknownClassLoader() throws Exception {
-        File privateCopyFile = fileForJar("copied2.jar");
+        File privateCopyFile = privateFile("copied2.jar");
         String expectedNameHash =
                 "202158B6A3169D78F1722487205A6B036B3F2F5653FDCFB4E74710611AC7EB93";
-        String expectedContentHash = copyAndHashJar(privateCopyFile);
+        String expectedContentHash = copyAndHashResource("/javalib.jar", privateCopyFile);
 
         // This time make sure an unknown class loader is an ancestor of the class loader we use.
         ClassLoader knownClassLoader = sContext.getClass().getClassLoader();
@@ -129,22 +135,185 @@
 
         // And make sure we log events about it
         long previousEventNanos = mostRecentEventTimeNanos();
-        runDexLogger();
+        runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID);
 
-        assertDclLoggedSince(previousEventNanos, expectedNameHash, expectedContentHash);
+        assertDclLoggedSince(previousEventNanos, DCL_DEX_SUBTAG,
+                expectedNameHash, expectedContentHash);
     }
 
-    private static File fileForJar(String name) {
-        return new File(sContext.getDir("jars", Context.MODE_PRIVATE), name);
+    @Test
+    public void testDexLoggerGeneratesEvents_nativeLibrary() throws Exception {
+        File privateCopyFile = privateFile("copied.so");
+        String expectedNameHash =
+                "996223BAD4B4FE75C57A3DEC61DB9C0B38E0A7AD479FC95F33494F4BC55A0F0E";
+        String expectedContentHash =
+                copyAndHashResource("/DexLoggerNativeTestLibrary.so", privateCopyFile);
+
+        System.load(privateCopyFile.toString());
+
+        // Run the job to scan generated audit log entries
+        runDynamicCodeLoggingJob(AUDIT_WATCHING_JOB_ID);
+
+        // And then make sure we log events about it
+        long previousEventNanos = mostRecentEventTimeNanos();
+        runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID);
+
+        assertDclLoggedSince(previousEventNanos, DCL_NATIVE_SUBTAG,
+                expectedNameHash, expectedContentHash);
     }
 
-    private static String copyAndHashJar(File copyTo) throws Exception {
+    @Test
+    public void testDexLoggerGeneratesEvents_nativeLibrary_escapedName() throws Exception {
+        // A file name with a space will be escaped in the audit log; verify we un-escape it
+        // correctly.
+        File privateCopyFile = privateFile("second copy.so");
+        String expectedNameHash =
+                "8C39990C560B4F36F83E208E279F678746FE23A790E4C50F92686584EA2041CA";
+        String expectedContentHash =
+                copyAndHashResource("/DexLoggerNativeTestLibrary.so", privateCopyFile);
+
+        System.load(privateCopyFile.toString());
+
+        // Run the job to scan generated audit log entries
+        runDynamicCodeLoggingJob(AUDIT_WATCHING_JOB_ID);
+
+        // And then make sure we log events about it
+        long previousEventNanos = mostRecentEventTimeNanos();
+        runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID);
+
+        assertDclLoggedSince(previousEventNanos, DCL_NATIVE_SUBTAG,
+                expectedNameHash, expectedContentHash);
+    }
+
+    @Test
+    public void testDexLoggerGeneratesEvents_nativeExecutable() throws Exception {
+        File privateCopyFile = privateFile("test_executable");
+        String expectedNameHash =
+                "3FBEC3F925A132D18F347F11AE9A5BB8DE1238828F8B4E064AA86EB68BD46DCF";
+        String expectedContentHash =
+                copyAndHashResource("/DexLoggerNativeExecutable", privateCopyFile);
+        assertThat(privateCopyFile.setExecutable(true)).isTrue();
+
+        Process process = Runtime.getRuntime().exec(privateCopyFile.toString());
+        int exitCode = process.waitFor();
+        assertThat(exitCode).isEqualTo(0);
+
+        // Run the job to scan generated audit log entries
+        runDynamicCodeLoggingJob(AUDIT_WATCHING_JOB_ID);
+
+        // And then make sure we log events about it
+        long previousEventNanos = mostRecentEventTimeNanos();
+        runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID);
+
+        assertDclLoggedSince(previousEventNanos, DCL_NATIVE_SUBTAG,
+                expectedNameHash, expectedContentHash);
+    }
+
+    @Test
+    public void testDexLoggerGeneratesEvents_spoofed_validFile() throws Exception {
+        File privateCopyFile = privateFile("spoofed");
+
+        String expectedContentHash =
+                copyAndHashResource("/DexLoggerNativeExecutable", privateCopyFile);
+
+        EventLog.writeEvent(EventLog.getTagCode("auditd"),
+                "type=1400 avc: granted { execute_no_trans } "
+                        + "path=\"" + privateCopyFile + "\" "
+                        + "scontext=u:r:untrusted_app_27: "
+                        + "tcontext=u:object_r:app_data_file: "
+                        + "tclass=file ");
+
+        String expectedNameHash =
+                "1CF36F503A02877BB775DC23C1C5A47A95F2684B6A1A83B11795B856D88861E3";
+
+        // Run the job to scan generated audit log entries
+        runDynamicCodeLoggingJob(AUDIT_WATCHING_JOB_ID);
+
+        // And then make sure we log events about it
+        long previousEventNanos = mostRecentEventTimeNanos();
+        runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID);
+
+        assertDclLoggedSince(previousEventNanos, DCL_NATIVE_SUBTAG,
+                expectedNameHash, expectedContentHash);
+    }
+
+    @Test
+    public void testDexLoggerGeneratesEvents_spoofed_pathTraversal() throws Exception {
+        File privateDir = privateFile("x").getParentFile();
+
+        // Transform /a/b/c -> /a/b/c/../../.. so we get back to the root
+        File pathTraversalToRoot = privateDir;
+        File root = new File("/");
+        while (!privateDir.equals(root)) {
+            pathTraversalToRoot = new File(pathTraversalToRoot, "..");
+            privateDir = privateDir.getParentFile();
+        }
+
+        File spoofedFile = new File(pathTraversalToRoot, "dev/urandom");
+
+        assertWithMessage("Expected " + spoofedFile + " to be readable")
+                .that(spoofedFile.canRead()).isTrue();
+
+        EventLog.writeEvent(EventLog.getTagCode("auditd"),
+                "type=1400 avc: granted { execute_no_trans } "
+                        + "path=\"" + spoofedFile + "\" "
+                        + "scontext=u:r:untrusted_app_27: "
+                        + "tcontext=u:object_r:app_data_file: "
+                        + "tclass=file ");
+
+        String expectedNameHash =
+                "65528FE876BD676B0DFCC9A8ACA8988E026766F99EEC1E1FB48F46B2F635E225";
+
+        // Run the job to scan generated audit log entries
+        runDynamicCodeLoggingJob(AUDIT_WATCHING_JOB_ID);
+
+        // And then trigger generating DCL events
+        long previousEventNanos = mostRecentEventTimeNanos();
+        runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID);
+
+        assertNoDclLoggedSince(previousEventNanos, DCL_NATIVE_SUBTAG, expectedNameHash);
+    }
+
+    @Test
+    public void testDexLoggerGeneratesEvents_spoofed_otherAppFile() throws Exception {
+        File ourPath = sContext.getDatabasePath("android_pay");
+        File targetPath = new File(ourPath.toString()
+                .replace("com.android.frameworks.dexloggertest", "com.google.android.gms"));
+
+        assertWithMessage("Expected " + targetPath + " to not be readable")
+                .that(targetPath.canRead()).isFalse();
+
+        EventLog.writeEvent(EventLog.getTagCode("auditd"),
+                "type=1400 avc: granted { execute_no_trans } "
+                        + "path=\"" + targetPath + "\" "
+                        + "scontext=u:r:untrusted_app_27: "
+                        + "tcontext=u:object_r:app_data_file: "
+                        + "tclass=file ");
+
+        String expectedNameHash =
+                "CBE04E8AB9E7199FC19CBAAF9C774B88E56B3B19E823F2251693380AD6F515E6";
+
+        // Run the job to scan generated audit log entries
+        runDynamicCodeLoggingJob(AUDIT_WATCHING_JOB_ID);
+
+        // And then trigger generating DCL events
+        long previousEventNanos = mostRecentEventTimeNanos();
+        runDynamicCodeLoggingJob(IDLE_LOGGING_JOB_ID);
+
+        assertNoDclLoggedSince(previousEventNanos, DCL_NATIVE_SUBTAG, expectedNameHash);
+    }
+
+    private static File privateFile(String name) {
+        return new File(sContext.getDir("dcl", Context.MODE_PRIVATE), name);
+    }
+
+    private static String copyAndHashResource(String resourcePath, File copyTo) throws Exception {
         MessageDigest hasher = MessageDigest.getInstance("SHA-256");
 
         // Copy the jar from our Java resources to a private data directory
         Class<?> thisClass = DexLoggerIntegrationTests.class;
-        try (InputStream input = thisClass.getResourceAsStream("/javalib.jar");
-                OutputStream output = new FileOutputStream(copyTo)) {
+        try (InputStream input = thisClass.getResourceAsStream(resourcePath);
+             OutputStream output = new FileOutputStream(copyTo)) {
             byte[] buffer = new byte[1024];
             while (true) {
                 int numRead = input.read(buffer);
@@ -166,24 +335,18 @@
         return formatter.toString();
     }
 
-    private static long mostRecentEventTimeNanos() throws Exception {
-        List<EventLog.Event> events = new ArrayList<>();
-
-        EventLog.readEvents(TAG_LIST, events);
-        return events.isEmpty() ? 0 : events.get(events.size() - 1).getTimeNanos();
-    }
-
-    private static void runDexLogger() throws Exception {
-        // This forces {@code DynamicCodeLoggingService} to start now.
-        runCommand("cmd jobscheduler run -f android " + DYNAMIC_CODE_LOGGING_JOB_ID);
+    private static void runDynamicCodeLoggingJob(int jobId) throws Exception {
+        // This forces the DynamicCodeLoggingService job to start now.
+        runCommand("cmd jobscheduler run -f android " + jobId);
         // Wait for the job to have run.
         long startTime = SystemClock.elapsedRealtime();
         while (true) {
             String response = runCommand(
-                    "cmd jobscheduler get-job-state android " + DYNAMIC_CODE_LOGGING_JOB_ID);
+                    "cmd jobscheduler get-job-state android " + jobId);
             if (!response.contains("pending") && !response.contains("active")) {
                 break;
             }
+            // Don't wait forever - if it's taken > 10s then something is very wrong.
             if (SystemClock.elapsedRealtime() - startTime > TimeUnit.SECONDS.toMillis(10)) {
                 throw new AssertionError("Job has not completed: " + response);
             }
@@ -208,37 +371,68 @@
         return response.toString("UTF-8");
     }
 
-    private static void assertDclLoggedSince(long previousEventNanos, String expectedNameHash,
-            String expectedContentHash) throws Exception {
-        List<EventLog.Event> events = new ArrayList<>();
-        EventLog.readEvents(TAG_LIST, events);
-        int found = 0;
-        for (EventLog.Event event : events) {
+    private static long mostRecentEventTimeNanos() throws Exception {
+        List<Event> events = readSnetEvents();
+        return events.isEmpty() ? 0 : events.get(events.size() - 1).getTimeNanos();
+    }
+
+    private static void assertDclLoggedSince(long previousEventNanos, String expectedSubTag,
+            String expectedNameHash, String expectedContentHash) throws Exception {
+        List<String> messages =
+                findMatchingEvents(previousEventNanos, expectedSubTag, expectedNameHash);
+
+        assertWithMessage("Expected exactly one matching log entry").that(messages).hasSize(1);
+        assertThat(messages.get(0)).endsWith(expectedContentHash);
+    }
+
+    private static void assertNoDclLoggedSince(long previousEventNanos, String expectedSubTag,
+            String expectedNameHash) throws Exception {
+        List<String> messages =
+                findMatchingEvents(previousEventNanos, expectedSubTag, expectedNameHash);
+
+        assertWithMessage("Expected no matching log entries").that(messages).isEmpty();
+    }
+
+    private static List<String> findMatchingEvents(long previousEventNanos, String expectedSubTag,
+            String expectedNameHash) throws Exception {
+        List<String> messages = new ArrayList<>();
+
+        for (Event event : readSnetEvents()) {
             if (event.getTimeNanos() <= previousEventNanos) {
                 continue;
             }
-            Object[] data = (Object[]) event.getData();
 
-            // We only care about DCL events that we generated.
-            String subTag = (String) data[0];
-            if (!DCL_SUBTAG.equals(subTag)) {
+            Object data = event.getData();
+            if (!(data instanceof Object[])) {
                 continue;
             }
-            int uid = (int) data[1];
+            Object[] fields = (Object[]) data;
+
+            // We only care about DCL events that we generated.
+            String subTag = (String) fields[0];
+            if (!expectedSubTag.equals(subTag)) {
+                continue;
+            }
+            int uid = (int) fields[1];
             if (uid != sMyUid) {
                 continue;
             }
 
-            String message = (String) data[2];
+            String message = (String) fields[2];
             if (!message.startsWith(expectedNameHash)) {
                 continue;
             }
 
-            assertThat(message).endsWith(expectedContentHash);
-            ++found;
+            messages.add(message);
+            //assertThat(message).endsWith(expectedContentHash);
         }
+        return messages;
+    }
 
-        assertThat(found).isEqualTo(1);
+    private static List<Event> readSnetEvents() throws Exception {
+        List<Event> events = new ArrayList<>();
+        EventLog.readEvents(new int[] { SNET_TAG }, events);
+        return events;
     }
 
     /**
diff --git a/tests/DexLoggerIntegrationTests/src/cpp/com_android_dcl_Jni.cpp b/tests/DexLoggerIntegrationTests/src/cpp/com_android_dcl_Jni.cpp
new file mode 100644
index 0000000..0608883
--- /dev/null
+++ b/tests/DexLoggerIntegrationTests/src/cpp/com_android_dcl_Jni.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+
+extern "C" jint JNI_OnLoad(JavaVM* /* vm */, void* /* reserved */)
+{
+    return JNI_VERSION_1_6;
+}
diff --git a/tests/DexLoggerIntegrationTests/src/cpp/test_executable.cpp b/tests/DexLoggerIntegrationTests/src/cpp/test_executable.cpp
new file mode 100644
index 0000000..ad025e6
--- /dev/null
+++ b/tests/DexLoggerIntegrationTests/src/cpp/test_executable.cpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+int main() {
+    // This program just has to run, it doesn't need to do anything. So we don't.
+    return 0;
+}
diff --git a/tests/HwAccelerationTest/Android.mk b/tests/HwAccelerationTest/Android.mk
index 11ea954..79072fa 100644
--- a/tests/HwAccelerationTest/Android.mk
+++ b/tests/HwAccelerationTest/Android.mk
@@ -21,6 +21,7 @@
 
 LOCAL_PACKAGE_NAME := HwAccelerationTest
 LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_CERTIFICATE := platform
 
 LOCAL_MODULE_TAGS := tests
 
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index c8f96c9..f330b83 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -310,6 +310,15 @@
                 <category android:name="com.android.test.hwui.TEST" />
             </intent-filter>
         </activity>
+
+        <activity
+            android:name="PictureCaptureDemo"
+            android:label="Debug/Picture Capture">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.hwui.TEST" />
+            </intent-filter>
+        </activity>
         
         <activity
                 android:name="SmallCircleActivity"
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
new file mode 100644
index 0000000..029e302
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PictureCaptureDemo.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Picture;
+import android.os.Bundle;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewDebug;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.ProgressBar;
+
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+public class PictureCaptureDemo extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final LinearLayout layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.VERTICAL);
+
+        final LinearLayout inner = new LinearLayout(this);
+        inner.setOrientation(LinearLayout.HORIZONTAL);
+        ProgressBar spinner = new ProgressBar(this, null, android.R.attr.progressBarStyleLarge);
+        inner.addView(spinner,
+                new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+
+        inner.addView(new View(this), new LayoutParams(50, 1));
+
+        Picture picture = new Picture();
+        Canvas canvas = picture.beginRecording(100, 100);
+        canvas.drawColor(Color.RED);
+        Paint paint = new Paint();
+        paint.setTextSize(32);
+        paint.setColor(Color.BLACK);
+        canvas.drawText("Hello", 0, 50, paint);
+        picture.endRecording();
+
+        ImageView iv1 = new ImageView(this);
+        iv1.setImageBitmap(Bitmap.createBitmap(picture, 100, 100, Bitmap.Config.ARGB_8888));
+        inner.addView(iv1, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+
+        inner.addView(new View(this), new LayoutParams(50, 1));
+
+        ImageView iv2 = new ImageView(this);
+        iv2.setImageBitmap(Bitmap.createBitmap(picture, 100, 100, Bitmap.Config.HARDWARE));
+        inner.addView(iv2, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+
+        layout.addView(inner,
+                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+        // For testing with a functor in the tree
+        WebView wv = new WebView(this);
+        wv.setWebViewClient(new WebViewClient());
+        wv.setWebChromeClient(new WebChromeClient());
+        wv.loadUrl("https://google.com");
+        layout.addView(wv, new LayoutParams(LayoutParams.MATCH_PARENT, 400));
+
+        SurfaceView mySurfaceView = new SurfaceView(this);
+        layout.addView(mySurfaceView,
+                new LayoutParams(LayoutParams.MATCH_PARENT, 600));
+
+        setContentView(layout);
+
+        mySurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
+            private AutoCloseable mStopCapture;
+
+            @Override
+            public void surfaceCreated(SurfaceHolder holder) {
+                final Random rand = new Random();
+                mStopCapture = ViewDebug.startRenderingCommandsCapture(mySurfaceView,
+                        mCaptureThread, (picture) -> {
+                            if (rand.nextInt(20) == 0) {
+                                try {
+                                    Thread.sleep(100);
+                                } catch (InterruptedException e) {
+                                }
+                            }
+                            Canvas canvas = holder.lockCanvas();
+                            if (canvas == null) {
+                                return false;
+                            }
+                            canvas.drawPicture(picture);
+                            holder.unlockCanvasAndPost(canvas);
+                            picture.close();
+                            return true;
+                        });
+            }
+
+            @Override
+            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+
+            }
+
+            @Override
+            public void surfaceDestroyed(SurfaceHolder holder) {
+                if (mStopCapture != null) {
+                    try {
+                        mStopCapture.close();
+                    } catch (Exception e) {
+                    }
+                    mStopCapture = null;
+                }
+            }
+        });
+    }
+
+    ExecutorService mCaptureThread = Executors.newSingleThreadExecutor();
+    ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+
+    Picture deepCopy(Picture src) {
+        try {
+            PipedInputStream inputStream = new PipedInputStream();
+            PipedOutputStream outputStream = new PipedOutputStream(inputStream);
+            Future<Picture> future = mExecutor.submit(() -> Picture.createFromStream(inputStream));
+            src.writeToStream(outputStream);
+            outputStream.close();
+            return future.get();
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+}
diff --git a/tests/PackageWatchdog/Android.mk b/tests/PackageWatchdog/Android.mk
new file mode 100644
index 0000000..1c1c2a4
--- /dev/null
+++ b/tests/PackageWatchdog/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+# PackageWatchdogTest
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_PACKAGE_NAME := PackageWatchdogTest
+LOCAL_MODULE_TAGS := tests
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    junit \
+    frameworks-base-testutils \
+    android-support-test \
+    services.core
+
+LOCAL_JAVA_LIBRARIES := \
+    android.test.runner
+
+LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/PackageWatchdog/AndroidManifest.xml b/tests/PackageWatchdog/AndroidManifest.xml
new file mode 100644
index 0000000..fa89528
--- /dev/null
+++ b/tests/PackageWatchdog/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?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.tests.packagewatchdog" >
+
+    <application android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.tests.packagewatchdog"
+                     android:label="PackageWatchdog Test"/>
+</manifest>
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
new file mode 100644
index 0000000..ec07037
--- /dev/null
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static com.android.server.PackageWatchdog.TRIGGER_FAILURE_COUNT;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.test.TestLooper;
+import android.support.test.InstrumentationRegistry;
+
+import com.android.server.PackageWatchdog.PackageHealthObserver;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+// TODO(zezeozue): Write test without using PackageWatchdog#getPackages. Just rely on
+// behavior of observers receiving crash notifications or not to determine if it's registered
+/**
+ * Test PackageWatchdog.
+ */
+public class PackageWatchdogTest {
+    private static final String APP_A = "com.package.a";
+    private static final String APP_B = "com.package.b";
+    private static final String OBSERVER_NAME_1 = "observer1";
+    private static final String OBSERVER_NAME_2 = "observer2";
+    private static final String OBSERVER_NAME_3 = "observer3";
+    private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1);
+    private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(5);
+    private TestLooper mTestLooper;
+
+    @Before
+    public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
+        mTestLooper.startAutoDispatch();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        new File(InstrumentationRegistry.getContext().getFilesDir(),
+                "package-watchdog.xml").delete();
+    }
+
+    /**
+     * Test registration, unregistration, package expiry and duration reduction
+     */
+    @Test
+    public void testRegistration() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+        TestObserver observer3 = new TestObserver(OBSERVER_NAME_3);
+
+        // Start observing for observer1 which will be unregistered
+        watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+        // Start observing for observer2 which will expire
+        watchdog.startObservingHealth(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
+        // Start observing for observer3 which will have expiry duration reduced
+        watchdog.startObservingHealth(observer3, Arrays.asList(APP_A), LONG_DURATION);
+
+        // Verify packages observed at start
+        // 1
+        assertEquals(1, watchdog.getPackages(observer1).size());
+        assertTrue(watchdog.getPackages(observer1).contains(APP_A));
+        // 2
+        assertEquals(2, watchdog.getPackages(observer2).size());
+        assertTrue(watchdog.getPackages(observer2).contains(APP_A));
+        assertTrue(watchdog.getPackages(observer2).contains(APP_B));
+        // 3
+        assertEquals(1, watchdog.getPackages(observer3).size());
+        assertTrue(watchdog.getPackages(observer3).contains(APP_A));
+
+        // Then unregister observer1
+        watchdog.unregisterHealthObserver(observer1);
+
+        // Verify observer2 and observer3 left
+        // 1
+        assertNull(watchdog.getPackages(observer1));
+        // 2
+        assertEquals(2, watchdog.getPackages(observer2).size());
+        assertTrue(watchdog.getPackages(observer2).contains(APP_A));
+        assertTrue(watchdog.getPackages(observer2).contains(APP_B));
+        // 3
+        assertEquals(1, watchdog.getPackages(observer3).size());
+        assertTrue(watchdog.getPackages(observer3).contains(APP_A));
+
+        // Then advance time a little and run messages in Handlers so observer2 expires
+        Thread.sleep(SHORT_DURATION);
+        mTestLooper.dispatchAll();
+
+        // Verify observer3 left with reduced expiry duration
+        // 1
+        assertNull(watchdog.getPackages(observer1));
+        // 2
+        assertNull(watchdog.getPackages(observer2));
+        // 3
+        assertEquals(1, watchdog.getPackages(observer3).size());
+        assertTrue(watchdog.getPackages(observer3).contains(APP_A));
+
+        // Then advance time some more and run messages in Handlers so observer3 expires
+        Thread.sleep(LONG_DURATION);
+        mTestLooper.dispatchAll();
+
+        // Verify observer3 expired
+        // 1
+        assertNull(watchdog.getPackages(observer1));
+        // 2
+        assertNull(watchdog.getPackages(observer2));
+        // 3
+        assertNull(watchdog.getPackages(observer3));
+    }
+
+    /**
+     * Test package observers are persisted and loaded on startup
+     */
+    @Test
+    public void testPersistence() throws Exception {
+        PackageWatchdog watchdog1 = createWatchdog();
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+
+        watchdog1.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+        watchdog1.startObservingHealth(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
+
+        // Verify 2 observers are registered and saved internally
+        // 1
+        assertEquals(1, watchdog1.getPackages(observer1).size());
+        assertTrue(watchdog1.getPackages(observer1).contains(APP_A));
+        // 2
+        assertEquals(2, watchdog1.getPackages(observer2).size());
+        assertTrue(watchdog1.getPackages(observer2).contains(APP_A));
+        assertTrue(watchdog1.getPackages(observer2).contains(APP_B));
+
+
+        // Then advance time and run IO Handler so file is saved
+        mTestLooper.dispatchAll();
+
+        // Then start a new watchdog
+        PackageWatchdog watchdog2 = createWatchdog();
+
+        // Verify the new watchdog loads observers on startup but nothing registered
+        assertEquals(0, watchdog2.getPackages(observer1).size());
+        assertEquals(0, watchdog2.getPackages(observer2).size());
+        // Verify random observer not saved returns null
+        assertNull(watchdog2.getPackages(new TestObserver(OBSERVER_NAME_3)));
+
+        // Then regiser observer1
+        watchdog2.registerHealthObserver(observer1);
+        watchdog2.registerHealthObserver(observer2);
+
+        // Verify 2 observers are registered after reload
+        // 1
+        assertEquals(1, watchdog1.getPackages(observer1).size());
+        assertTrue(watchdog1.getPackages(observer1).contains(APP_A));
+        // 2
+        assertEquals(2, watchdog1.getPackages(observer2).size());
+        assertTrue(watchdog1.getPackages(observer2).contains(APP_A));
+        assertTrue(watchdog1.getPackages(observer2).contains(APP_B));
+    }
+
+    /**
+     * Test package failure under threshold does not notify observers
+     */
+    @Test
+    public void testNoPackageFailureBeforeThreshold() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+
+        watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+        watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+
+        // Then fail APP_A below the threshold
+        for (int i = 0; i < TRIGGER_FAILURE_COUNT - 1; i++) {
+            watchdog.onPackageFailure(new String[]{APP_A});
+        }
+
+        // Verify that observers are not notified
+        assertEquals(0, observer1.mFailedPackages.size());
+        assertEquals(0, observer2.mFailedPackages.size());
+    }
+
+    /**
+     * Test package failure and notifies all observer since none handles the failure
+     */
+    @Test
+    public void testPackageFailureNotifyAll() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+
+        // Start observing for observer1 and observer2 without handling failures
+        watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+        watchdog.startObservingHealth(observer1, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
+
+        // Then fail APP_A and APP_B above the threshold
+        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+            watchdog.onPackageFailure(new String[]{APP_A, APP_B});
+        }
+
+        // Verify all observers are notifed of all package failures
+        List<String> observer1Packages = observer1.mFailedPackages;
+        List<String> observer2Packages = observer2.mFailedPackages;
+        assertEquals(2, observer1Packages.size());
+        assertEquals(1, observer2Packages.size());
+        assertEquals(APP_A, observer1Packages.get(0));
+        assertEquals(APP_B, observer1Packages.get(1));
+        assertEquals(APP_A, observer2Packages.get(0));
+    }
+
+    /**
+     * Test package failure and notifies only one observer because it handles the failure
+     */
+    @Test
+    public void testPackageFailureNotifyOne() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1, true /* shouldHandle */);
+        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2, true /* shouldHandle */);
+
+        // Start observing for observer1 and observer2 with failure handling
+        watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+        watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+
+        // Then fail APP_A above the threshold
+        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+            watchdog.onPackageFailure(new String[]{APP_A});
+        }
+
+        // Verify only one observer is notifed
+        assertEquals(1, observer1.mFailedPackages.size());
+        assertEquals(APP_A, observer1.mFailedPackages.get(0));
+        assertEquals(0, observer2.mFailedPackages.size());
+    }
+
+    private PackageWatchdog createWatchdog() {
+        return new PackageWatchdog(InstrumentationRegistry.getContext(),
+                mTestLooper.getLooper());
+    }
+
+    private static class TestObserver implements PackageHealthObserver {
+        private final String mName;
+        private boolean mShouldHandle;
+        final List<String> mFailedPackages = new ArrayList<>();
+
+        TestObserver(String name) {
+            mName = name;
+        }
+
+        TestObserver(String name, boolean shouldHandle) {
+            mName = name;
+            mShouldHandle = shouldHandle;
+        }
+
+        public boolean onHealthCheckFailed(String packageName) {
+            mFailedPackages.add(packageName);
+            return mShouldHandle;
+        }
+
+        public String getName() {
+            return mName;
+        }
+    }
+}
diff --git a/tests/RcsTests/Android.mk b/tests/RcsTests/Android.mk
index adc7cab..7b348d7 100644
--- a/tests/RcsTests/Android.mk
+++ b/tests/RcsTests/Android.mk
@@ -11,7 +11,7 @@
 
 LOCAL_CERTIFICATE := platform
 LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_STATIC_JAVA_LIBRARIES := junit android-support-test mockito-target-minus-junit4
+LOCAL_STATIC_JAVA_LIBRARIES := junit android-support-test mockito-target-minus-junit4 truth-prebuilt
 
 include $(BUILD_PACKAGE)
 
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsMessageStoreTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsMessageStoreTest.java
new file mode 100644
index 0000000..44277ed
--- /dev/null
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsMessageStoreTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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.ims;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.ims.RcsMessageStore;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsMessageStoreTest {
+    //TODO(sahinc): Add meaningful tests once we have more of the implementation in place
+    @Test
+    public void testDeleteThreadDoesntCrash() {
+        RcsMessageStore mRcsMessageStore = new RcsMessageStore();
+        mRcsMessageStore.deleteThread(0);
+    }
+}
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantTest.java
new file mode 100644
index 0000000..c402dbf
--- /dev/null
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantTest.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.tests.ims;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Bundle;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.ims.RcsParticipant;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsParticipantTest {
+    private static final int ID = 123;
+    private static final String ALIAS = "alias";
+    private static final String CANONICAL_ADDRESS = "+1234567890";
+
+    @Test
+    public void testCanUnparcel() {
+        RcsParticipant rcsParticipant = new RcsParticipant(ID, CANONICAL_ADDRESS);
+        rcsParticipant.setAlias(ALIAS);
+
+        Bundle bundle = new Bundle();
+        bundle.putParcelable("Some key", rcsParticipant);
+        rcsParticipant = bundle.getParcelable("Some key");
+
+        assertThat(rcsParticipant.getId()).isEqualTo(ID);
+        assertThat(rcsParticipant.getAlias()).isEqualTo(ALIAS);
+        assertThat(rcsParticipant.getCanonicalAddress()).isEqualTo(CANONICAL_ADDRESS);
+    }
+}
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParametersTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParametersTest.java
new file mode 100644
index 0000000..a890a38
--- /dev/null
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParametersTest.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 com.android.tests.ims;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Bundle;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.ims.RcsParticipant;
+import android.telephony.ims.RcsThreadQueryParameters;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsThreadQueryParametersTest {
+    private RcsThreadQueryParameters mRcsThreadQueryParameters;
+    @Mock RcsParticipant mMockParticipant;
+
+    @Test
+    public void testUnparceling() {
+        String key = "some key";
+        mRcsThreadQueryParameters = RcsThreadQueryParameters.builder()
+                .isGroupThread(true)
+                .withParticipant(mMockParticipant)
+                .limitResultsTo(50)
+                .sort(true)
+                .build();
+
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(key, mRcsThreadQueryParameters);
+        mRcsThreadQueryParameters = bundle.getParcelable(key);
+
+        assertThat(mRcsThreadQueryParameters.isGroupThread()).isTrue();
+        assertThat(mRcsThreadQueryParameters.getRcsParticipants()).contains(mMockParticipant);
+        assertThat(mRcsThreadQueryParameters.getLimit()).isEqualTo(50);
+        assertThat(mRcsThreadQueryParameters.isAscending()).isTrue();
+    }
+}
diff --git a/tests/RcsTests/src/com/android/tests/rcs/RcsMessageStoreTest.java b/tests/RcsTests/src/com/android/tests/rcs/RcsMessageStoreTest.java
deleted file mode 100644
index 290e04c..0000000
--- a/tests/RcsTests/src/com/android/tests/rcs/RcsMessageStoreTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.tests.rcs;
-
-import android.support.test.runner.AndroidJUnit4;
-import android.telephony.ims.RcsMessageStore;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class RcsMessageStoreTest {
-    //TODO(sahinc): Add meaningful tests once we have more of the implementation in place
-    @Test
-    public void testDeleteThreadDoesntCrash() {
-        RcsMessageStore mRcsMessageStore = new RcsMessageStore();
-        mRcsMessageStore.deleteThread(0);
-    }
-}
diff --git a/tests/RollbackTest/Android.mk b/tests/RollbackTest/Android.mk
index f2bd407..34aa258 100644
--- a/tests/RollbackTest/Android.mk
+++ b/tests/RollbackTest/Android.mk
@@ -14,27 +14,49 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-# RollbackTestAppV1
+# RollbackTestAppAv1.apk
 include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_MANIFEST_FILE := TestApp/AndroidManifestV1.xml
-LOCAL_PACKAGE_NAME := RollbackTestAppV1
 LOCAL_SDK_VERSION := current
 LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
+LOCAL_MANIFEST_FILE := TestApp/Av1.xml
+LOCAL_PACKAGE_NAME := RollbackTestAppAv1
 include $(BUILD_PACKAGE)
-ROLLBACK_TEST_APP_V1 := $(LOCAL_INSTALLED_MODULE)
+ROLLBACK_TEST_APP_AV1 := $(LOCAL_INSTALLED_MODULE)
 
-# RollbackTestAppV2
+# RollbackTestAppAv2.apk
 include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_MANIFEST_FILE := TestApp/AndroidManifestV2.xml
-LOCAL_PACKAGE_NAME := RollbackTestAppV2
 LOCAL_SDK_VERSION := current
 LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
+LOCAL_MANIFEST_FILE := TestApp/Av2.xml
+LOCAL_PACKAGE_NAME := RollbackTestAppAv2
 include $(BUILD_PACKAGE)
-ROLLBACK_TEST_APP_V2 := $(LOCAL_INSTALLED_MODULE)
+ROLLBACK_TEST_APP_AV2 := $(LOCAL_INSTALLED_MODULE)
+
+# RollbackTestAppBv1.apk
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
+LOCAL_MANIFEST_FILE := TestApp/Bv1.xml
+LOCAL_PACKAGE_NAME := RollbackTestAppBv1
+include $(BUILD_PACKAGE)
+ROLLBACK_TEST_APP_BV1 := $(LOCAL_INSTALLED_MODULE)
+
+# RollbackTestAppBv2.apk
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
+LOCAL_MANIFEST_FILE := TestApp/Bv2.xml
+LOCAL_PACKAGE_NAME := RollbackTestAppBv2
+include $(BUILD_PACKAGE)
+ROLLBACK_TEST_APP_BV2 := $(LOCAL_INSTALLED_MODULE)
 
 # RollbackTest
 include $(CLEAR_VARS)
@@ -43,12 +65,17 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 LOCAL_COMPATIBILITY_SUITE := general-tests
-LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_RESOURCE_FILES := $(ROLLBACK_TEST_APP_V1) $(ROLLBACK_TEST_APP_V2)
-LOCAL_SDK_VERSION := test_current
+LOCAL_JAVA_RESOURCE_FILES := \
+  $(ROLLBACK_TEST_APP_AV1) \
+  $(ROLLBACK_TEST_APP_AV2) \
+  $(ROLLBACK_TEST_APP_BV1) \
+  $(ROLLBACK_TEST_APP_BV2)
+LOCAL_SDK_VERSION := system_current
 LOCAL_TEST_CONFIG := RollbackTest.xml
 include $(BUILD_PACKAGE)
 
 # Clean up local variables
-ROLLBACK_TEST_APP_V1 :=
-ROLLBACK_TEST_APP_V2 :=
+ROLLBACK_TEST_APP_AV1 :=
+ROLLBACK_TEST_APP_AV2 :=
+ROLLBACK_TEST_APP_BV1 :=
+ROLLBACK_TEST_APP_BV2 :=
diff --git a/tests/RollbackTest/AndroidManifest.xml b/tests/RollbackTest/AndroidManifest.xml
index d1535a3..e57a768 100644
--- a/tests/RollbackTest/AndroidManifest.xml
+++ b/tests/RollbackTest/AndroidManifest.xml
@@ -17,9 +17,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.tests.rollback" >
 
-    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
-    <uses-permission android:name="android.permission.DELETE_PACKAGES" />
-
     <application>
         <receiver android:name="com.android.tests.rollback.LocalIntentSender"
                   android:exported="true" />
diff --git a/tests/RollbackTest/TEST_MAPPING b/tests/RollbackTest/TEST_MAPPING
new file mode 100644
index 0000000..c1d95ac
--- /dev/null
+++ b/tests/RollbackTest/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "RollbackTest"
+    }
+  ]
+}
diff --git a/tests/RollbackTest/TestApp/AndroidManifestV1.xml b/tests/RollbackTest/TestApp/AndroidManifestV1.xml
deleted file mode 100644
index 45e9584..0000000
--- a/tests/RollbackTest/TestApp/AndroidManifestV1.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.tests.rollback.testapp"
-    android:versionCode="1"
-    android:versionName="1.0" >
-
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="Rollback Test App V1">
-        <activity android:name="com.android.tests.rollback.testapp.MainActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/AndroidManifestV2.xml b/tests/RollbackTest/TestApp/AndroidManifestV2.xml
deleted file mode 100644
index 0104086..0000000
--- a/tests/RollbackTest/TestApp/AndroidManifestV2.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.tests.rollback.testapp"
-    android:versionCode="2"
-    android:versionName="2.0" >
-
-
-    <uses-sdk android:minSdkVersion="19" />
-
-    <application android:label="Rollback Test App V2">
-        <activity android:name="com.android.tests.rollback.testapp.MainActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RollbackTest/TestApp/Av1.xml b/tests/RollbackTest/TestApp/Av1.xml
new file mode 100644
index 0000000..996d831
--- /dev/null
+++ b/tests/RollbackTest/TestApp/Av1.xml
@@ -0,0 +1,36 @@
+<?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.tests.rollback.testapp.A"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+
+    <uses-sdk android:minSdkVersion="19" />
+
+    <application android:label="Rollback Test App A v1">
+        <meta-data android:name="version" android:value="1" />
+        <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
+                  android:exported="true" />
+        <activity android:name="com.android.tests.rollback.testapp.MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RollbackTest/TestApp/Av2.xml b/tests/RollbackTest/TestApp/Av2.xml
new file mode 100644
index 0000000..21c7260
--- /dev/null
+++ b/tests/RollbackTest/TestApp/Av2.xml
@@ -0,0 +1,36 @@
+<?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.tests.rollback.testapp.A"
+    android:versionCode="2"
+    android:versionName="2.0" >
+
+
+    <uses-sdk android:minSdkVersion="19" />
+
+    <application android:label="Rollback Test App A v2">
+        <meta-data android:name="version" android:value="2" />
+        <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
+                  android:exported="true" />
+        <activity android:name="com.android.tests.rollback.testapp.MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RollbackTest/TestApp/Bv1.xml b/tests/RollbackTest/TestApp/Bv1.xml
new file mode 100644
index 0000000..de0fd0d
--- /dev/null
+++ b/tests/RollbackTest/TestApp/Bv1.xml
@@ -0,0 +1,36 @@
+<?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.tests.rollback.testapp.B"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+
+    <uses-sdk android:minSdkVersion="19" />
+
+    <application android:label="Rollback Test App B v1">
+        <meta-data android:name="version" android:value="1" />
+        <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
+                  android:exported="true" />
+        <activity android:name="com.android.tests.rollback.testapp.MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RollbackTest/TestApp/Bv2.xml b/tests/RollbackTest/TestApp/Bv2.xml
new file mode 100644
index 0000000..6c2e66a
--- /dev/null
+++ b/tests/RollbackTest/TestApp/Bv2.xml
@@ -0,0 +1,36 @@
+<?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.tests.rollback.testapp.B"
+    android:versionCode="2"
+    android:versionName="2.0" >
+
+
+    <uses-sdk android:minSdkVersion="19" />
+
+    <application android:label="Rollback Test App B v2">
+        <meta-data android:name="version" android:value="2" />
+        <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
+                  android:exported="true" />
+        <activity android:name="com.android.tests.rollback.testapp.MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java
index 1856bac..9f1a060 100644
--- a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java
+++ b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/MainActivity.java
@@ -27,5 +27,11 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+
+        try {
+            new ProcessUserData().processUserData(this);
+        } catch (ProcessUserData.UserDataException e) {
+            throw new AssertionError("Failed to process app user data", e);
+        }
     }
 }
diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java
new file mode 100644
index 0000000..fde6a83
--- /dev/null
+++ b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/ProcessUserData.java
@@ -0,0 +1,106 @@
+/*
+ * 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.rollback.testapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Scanner;
+
+/**
+ * A broadcast reciever to check for and update user app data version
+ * compatibility.
+ */
+public class ProcessUserData extends BroadcastReceiver {
+
+    /**
+     * Exception thrown in case of issue with user data.
+     */
+    public static class UserDataException extends Exception {
+        public UserDataException(String message) {
+            super(message);
+        }
+
+        public UserDataException(String message, Throwable cause) {
+           super(message, cause);
+        }
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        try {
+            processUserData(context);
+            setResultCode(1);
+        } catch (UserDataException e) {
+            setResultCode(0);
+            setResultData(e.getMessage());
+        }
+    }
+
+    /**
+     * Update the app's user data version to match the app version.
+     *
+     * @param context The application context.
+     * @throws UserDataException in case of problems with app user data.
+     */
+    public void processUserData(Context context) throws UserDataException {
+        int appVersion = 0;
+        try {
+            ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
+                    context.getPackageName(), PackageManager.GET_META_DATA);
+            Bundle bundle = appInfo.metaData;
+            appVersion = bundle.getInt("version");
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new UserDataException("Unable to get app version info", e);
+        }
+
+        // Read the version of the app's user data and ensure it is compatible
+        // with our version of the application.
+        File versionFile = new File(context.getFilesDir(), "version.txt");
+        try {
+            Scanner s = new Scanner(versionFile);
+            int userDataVersion = s.nextInt();
+            s.close();
+
+            if (userDataVersion > appVersion) {
+                throw new UserDataException("User data is from version " + userDataVersion
+                        + ", which is not compatible with this version " + appVersion
+                        + " of the RollbackTestApp");
+            }
+        } catch (FileNotFoundException e) {
+            // No problem. This is a fresh install of the app or the user data
+            // has been wiped.
+        }
+
+        // Record the current version of the app in the user data.
+        try {
+            PrintWriter pw = new PrintWriter(versionFile);
+            pw.println(appVersion);
+            pw.close();
+        } catch (IOException e) {
+            throw new UserDataException("Unable to write user data.", e);
+        }
+    }
+}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
index d3c39f0..030641b 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
@@ -44,7 +44,6 @@
     RollbackBroadcastReceiver() {
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
-        filter.addDataScheme("package");
         InstrumentationRegistry.getContext().registerReceiver(this, filter);
     }
 
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 02c1ce2..9d67cea 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -16,13 +16,17 @@
 
 package com.android.tests.rollback;
 
+import android.Manifest;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.rollback.PackageRollbackInfo;
 import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
-import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.support.test.InstrumentationRegistry;
 import android.util.Log;
 
@@ -38,6 +42,8 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -49,7 +55,8 @@
 
     private static final String TAG = "RollbackTest";
 
-    private static final String TEST_APP_PACKAGE_NAME = "com.android.tests.rollback.testapp";
+    private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
+    private static final String TEST_APP_B = "com.android.tests.rollback.testapp.B";
 
     /**
      * Test basic rollbacks.
@@ -71,151 +78,279 @@
         };
         context.registerReceiver(enableRollbackReceiver, enableRollbackFilter);
 
-        // Register a broadcast receiver for notification when the rollback is
-        // done executing.
-        RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
 
-        // Uninstall com.android.tests.rollback.testapp
-        RollbackTestUtils.uninstall("com.android.tests.rollback.testapp");
-        assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
+            // Register a broadcast receiver for notification when the rollback is
+            // done executing.
+            RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
-        // TODO: There is currently a race condition between when the app is
-        // uninstalled and when rollback manager deletes the rollback. Fix it
-        // so that's not the case!
-        for (int i = 0; i < 5; ++i) {
-            for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
-                if (TEST_APP_PACKAGE_NAME.equals(info.targetPackage.packageName)) {
-                    Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
-                    Thread.sleep(1000);
-                    break;
+            // Uninstall TEST_APP_A
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            // TODO: There is currently a race condition between when the app is
+            // uninstalled and when rollback manager deletes the rollback. Fix it
+            // so that's not the case!
+            for (int i = 0; i < 5; ++i) {
+                for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
+                    if (TEST_APP_A.equals(info.targetPackage.getPackageName())) {
+                        Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
+                        Thread.sleep(1000);
+                        break;
+                    }
                 }
             }
-        }
 
-        // The app should not be available for rollback.
-        assertNull(rm.getAvailableRollback(TEST_APP_PACKAGE_NAME));
-        assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
+            // The app should not be available for rollback.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is uninstalled and when the previously
+            // available rollback, if any, is removed.
+            Thread.sleep(1000);
+            assertNull(rm.getAvailableRollback(TEST_APP_A));
+            assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
 
-        // There should be no recently executed rollbacks for this package.
-        for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
-            assertNotEquals(TEST_APP_PACKAGE_NAME, info.targetPackage.packageName);
-        }
-
-        // Install v1 of the app (without rollbacks enabled).
-        RollbackTestUtils.install("RollbackTestAppV1.apk", false);
-        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
-
-        // Upgrade from v1 to v2, with rollbacks enabled.
-        RollbackTestUtils.install("RollbackTestAppV2.apk", true);
-        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
-
-        // The app should now be available for rollback.
-        assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
-        RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_PACKAGE_NAME);
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
-
-        // We should not have received any rollback requests yet.
-        // TODO: Possibly flaky if, by chance, some other app on device
-        // happens to be rolled back at the same time?
-        assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
-
-        // Roll back the app.
-        RollbackTestUtils.rollback(rollback);
-        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
-
-        // Verify we received a broadcast for the rollback.
-        // TODO: Race condition between the timeout and when the broadcast is
-        // received could lead to test flakiness.
-        Intent broadcast = broadcastReceiver.poll(5, TimeUnit.SECONDS);
-        assertNotNull(broadcast);
-        assertEquals(TEST_APP_PACKAGE_NAME, broadcast.getData().getSchemeSpecificPart());
-        assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
-
-        // Verify the recent rollback has been recorded.
-        rollback = null;
-        for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
-            if (TEST_APP_PACKAGE_NAME.equals(r.targetPackage.packageName)) {
-                assertNull(rollback);
-                rollback = r;
+            // There should be no recently executed rollbacks for this package.
+            for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
+                assertNotEquals(TEST_APP_A, info.targetPackage.getPackageName());
             }
-        }
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
 
-        broadcastReceiver.unregister();
-        context.unregisterReceiver(enableRollbackReceiver);
+            // Install v1 of the app (without rollbacks enabled).
+            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            // Upgrade from v1 to v2, with rollbacks enabled.
+            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            // The app should now be available for rollback.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // is made available.
+            Thread.sleep(1000);
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+            RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+            assertNotNull(rollback);
+            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+
+            // We should not have received any rollback requests yet.
+            // TODO: Possibly flaky if, by chance, some other app on device
+            // happens to be rolled back at the same time?
+            assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
+
+            // Roll back the app.
+            RollbackTestUtils.rollback(rollback);
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            // Verify we received a broadcast for the rollback.
+            // TODO: Race condition between the timeout and when the broadcast is
+            // received could lead to test flakiness.
+            Intent broadcast = broadcastReceiver.poll(5, TimeUnit.SECONDS);
+            assertNotNull(broadcast);
+            assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
+
+            // Verify the recent rollback has been recorded.
+            rollback = null;
+            for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
+                if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
+                    assertNull(rollback);
+                    rollback = r;
+                }
+            }
+            assertNotNull(rollback);
+            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+
+            broadcastReceiver.unregister();
+            context.unregisterReceiver(enableRollbackReceiver);
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
     }
 
     /**
-     * Test that rollback data is properly persisted.
+     * Test that multiple available rollbacks are properly persisted.
      */
     @Test
-    public void testRollbackDataPersistence() throws Exception {
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+    public void testAvailableRollbackPersistence() throws Exception {
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
 
-        // Prep installation of com.android.tests.rollback.testapp
-        RollbackTestUtils.uninstall("com.android.tests.rollback.testapp");
-        RollbackTestUtils.install("RollbackTestAppV1.apk", false);
-        RollbackTestUtils.install("RollbackTestAppV2.apk", true);
-        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
-        // The app should now be available for rollback.
-        assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
-        RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_PACKAGE_NAME);
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
-        // Reload the persisted data.
-        rm.reloadPersistedData();
+            RollbackTestUtils.uninstall(TEST_APP_B);
+            RollbackTestUtils.install("RollbackTestAppBv1.apk", false);
+            RollbackTestUtils.install("RollbackTestAppBv2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
 
-        // The app should still be available for rollback.
-        assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
-        rollback = rm.getAvailableRollback(TEST_APP_PACKAGE_NAME);
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+            // Both test apps should now be available for rollback.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // is made available.
+            Thread.sleep(1000);
 
-        // Roll back the app.
-        RollbackTestUtils.rollback(rollback);
-        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+            RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
+            assertNotNull(rollbackA);
+            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
 
-        // Verify the recent rollback has been recorded.
-        rollback = null;
-        for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
-            if (TEST_APP_PACKAGE_NAME.equals(r.targetPackage.packageName)) {
-                assertNull(rollback);
-                rollback = r;
-            }
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
+            RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
+            assertNotNull(rollbackB);
+            assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+
+            // Reload the persisted data.
+            rm.reloadPersistedData();
+
+            // The apps should still be available for rollback.
+            rollbackA = rm.getAvailableRollback(TEST_APP_A);
+            assertNotNull(rollbackA);
+            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
+            rollbackB = rm.getAvailableRollback(TEST_APP_B);
+            assertNotNull(rollbackB);
+            assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+
+            // Rollback of B should not rollback A
+            RollbackTestUtils.rollback(rollbackB);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
         }
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+    }
 
-        // Reload the persisted data.
-        rm.reloadPersistedData();
+    /**
+     * Test that available multi-package rollbacks are properly persisted.
+     */
+    @Test
+    public void testAvailableMultiPackageRollbackPersistence() throws Exception {
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
 
-        // Verify the recent rollback is still recorded.
-        rollback = null;
-        for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
-            if (TEST_APP_PACKAGE_NAME.equals(r.targetPackage.packageName)) {
-                assertNull(rollback);
-                rollback = r;
-            }
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.uninstall(TEST_APP_B);
+            RollbackTestUtils.installMultiPackage(false,
+                    "RollbackTestAppAv1.apk",
+                    "RollbackTestAppBv1.apk");
+            RollbackTestUtils.installMultiPackage(true,
+                    "RollbackTestAppAv2.apk",
+                    "RollbackTestAppBv2.apk");
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+
+            // The app should now be available for rollback.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // is made available.
+            Thread.sleep(1000);
+
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+            RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
+            assertNotNull(rollbackA);
+            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
+            RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
+            assertNotNull(rollbackB);
+            assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+
+            // Reload the persisted data.
+            rm.reloadPersistedData();
+
+            // The apps should still be available for rollback.
+            rollbackA = rm.getAvailableRollback(TEST_APP_A);
+            assertNotNull(rollbackA);
+            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
+            rollbackB = rm.getAvailableRollback(TEST_APP_B);
+            assertNotNull(rollbackB);
+            assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+
+            // Rollback of B should rollback A as well
+            RollbackTestUtils.rollback(rollbackB);
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
         }
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+    }
+
+    /**
+     * Test that recently executed rollback data is properly persisted.
+     */
+    @Test
+    public void testRecentlyExecutedRollbackPersistence() throws Exception {
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
+
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            // The app should now be available for rollback.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // is made available.
+            Thread.sleep(1000);
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+            RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+
+            // Roll back the app.
+            RollbackTestUtils.rollback(rollback);
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            // Verify the recent rollback has been recorded.
+            rollback = null;
+            for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
+                if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
+                    assertNull(rollback);
+                    rollback = r;
+                }
+            }
+            assertNotNull(rollback);
+            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+
+            // Reload the persisted data.
+            rm.reloadPersistedData();
+
+            // Verify the recent rollback is still recorded.
+            rollback = null;
+            for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
+                if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
+                    assertNull(rollback);
+                    rollback = r;
+                }
+            }
+            assertNotNull(rollback);
+            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
     }
 
     /**
@@ -224,26 +359,110 @@
      */
     @Test
     public void testRollbackExpiration() throws Exception {
-        RollbackManager rm = RollbackTestUtils.getRollbackManager();
-        RollbackTestUtils.uninstall("com.android.tests.rollback.testapp");
-        RollbackTestUtils.install("RollbackTestAppV1.apk", false);
-        RollbackTestUtils.install("RollbackTestAppV2.apk", true);
-        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_PACKAGE_NAME));
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
 
-        // The app should now be available for rollback.
-        assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
-        RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_PACKAGE_NAME);
-        assertNotNull(rollback);
-        assertEquals(TEST_APP_PACKAGE_NAME, rollback.targetPackage.packageName);
-        assertEquals(2, rollback.targetPackage.higherVersion.versionCode);
-        assertEquals(1, rollback.targetPackage.lowerVersion.versionCode);
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
-        // Expire the rollback.
-        rm.expireRollbackForPackage(TEST_APP_PACKAGE_NAME);
+            // The app should now be available for rollback.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // is made available.
+            Thread.sleep(1000);
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+            RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+            assertNotNull(rollback);
+            assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
 
-        // The rollback should no longer be available.
-        assertNull(rm.getAvailableRollback(TEST_APP_PACKAGE_NAME));
-        assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_PACKAGE_NAME));
+            // Expire the rollback.
+            rm.expireRollbackForPackage(TEST_APP_A);
+
+            // The rollback should no longer be available.
+            assertNull(rm.getAvailableRollback(TEST_APP_A));
+            assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
+    }
+
+    private static final String NO_RESPONSE = "NO RESPONSE";
+
+    // Calls into the test app to process user data.
+    // Asserts if the user data could not be processed or was version
+    // incompatible with the previously processed user data.
+    private void processUserData(String packageName) throws Exception {
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName(packageName,
+                    "com.android.tests.rollback.testapp.ProcessUserData"));
+        Context context = InstrumentationRegistry.getContext();
+
+        HandlerThread handlerThread = new HandlerThread("RollbackTestHandlerThread");
+        handlerThread.start();
+
+        // It can sometimes take a while after rollback before the app will
+        // receive this broadcast, so try a few times in a loop.
+        String result = NO_RESPONSE;
+        for (int i = 0; result.equals(NO_RESPONSE) && i < 5; ++i) {
+            BlockingQueue<String> resultQueue = new LinkedBlockingQueue<>();
+            context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (getResultCode() == 1) {
+                        resultQueue.add("OK");
+                    } else {
+                        // If the test app doesn't receive the broadcast or
+                        // fails to set the result data, then getResultData
+                        // here returns the initial NO_RESPONSE data passed to
+                        // the sendOrderedBroadcast call.
+                        resultQueue.add(getResultData());
+                    }
+                }
+            }, new Handler(handlerThread.getLooper()), 0, NO_RESPONSE, null);
+
+            result = resultQueue.poll(10, TimeUnit.SECONDS);
+            if (result == null) {
+                result = "ProcessUserData broadcast timed out";
+            }
+        }
+
+        handlerThread.quit();
+        if (!"OK".equals(result)) {
+            fail(result);
+        }
+    }
+
+    /**
+     * Test that app user data is rolled back.
+     * TODO: Stop ignoring this test once user data rollback is supported.
+     */
+    @Test
+    public void testUserDataRollback() throws Exception {
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
+
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+            processUserData(TEST_APP_A);
+            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+            processUserData(TEST_APP_A);
+
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+            RollbackTestUtils.rollback(rollback);
+            processUserData(TEST_APP_A);
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
     }
 
     /**
@@ -253,8 +472,7 @@
     @Test
     public void testRollbackBroadcastRestrictions() throws Exception {
         RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
-        Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED,
-                Uri.fromParts("package", "com.android.tests.rollback.bogus", null));
+        Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
         try {
             InstrumentationRegistry.getContext().sendBroadcast(broadcast);
             fail("Succeeded in sending restricted broadcast from app context.");
@@ -270,4 +488,179 @@
         // called, even when the test fails?
         broadcastReceiver.unregister();
     }
+
+    /**
+     * Regression test for rollback in the case when multiple apps are
+     * available for rollback at the same time.
+     */
+    @Test
+    public void testMultipleRollbackAvailable() throws Exception {
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+            // Prep installation of the test apps.
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            RollbackTestUtils.uninstall(TEST_APP_B);
+            RollbackTestUtils.install("RollbackTestAppBv1.apk", false);
+            RollbackTestUtils.install("RollbackTestAppBv2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+
+            // Both test apps should now be available for rollback, and the
+            // targetPackage returned for rollback should be correct.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // is made available.
+            Thread.sleep(1000);
+            RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
+            assertNotNull(rollbackA);
+            assertEquals(TEST_APP_A, rollbackA.targetPackage.getPackageName());
+
+            RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
+            assertNotNull(rollbackB);
+            assertEquals(TEST_APP_B, rollbackB.targetPackage.getPackageName());
+
+            // Executing rollback should roll back the correct package.
+            RollbackTestUtils.rollback(rollbackA);
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+            RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            RollbackTestUtils.rollback(rollbackB);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
+    }
+
+    /**
+     * Test that the MANAGE_ROLLBACKS permission is required to call
+     * RollbackManager APIs.
+     */
+    @Test
+    public void testManageRollbacksPermission() throws Exception {
+        // We shouldn't be allowed to call any of the RollbackManager APIs
+        // without the MANAGE_ROLLBACKS permission.
+        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+        try {
+            rm.getAvailableRollback(TEST_APP_A);
+            fail("expected SecurityException");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+
+        try {
+            rm.getPackagesWithAvailableRollbacks();
+            fail("expected SecurityException");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+
+        try {
+            rm.getRecentlyExecutedRollbacks();
+            fail("expected SecurityException");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+
+        try {
+            // TODO: What if the implementation checks arguments for non-null
+            // first? Then this test isn't valid.
+            rm.executeRollback(null, null);
+            fail("expected SecurityException");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+
+        try {
+            rm.reloadPersistedData();
+            fail("expected SecurityException");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+
+        try {
+            rm.expireRollbackForPackage(TEST_APP_A);
+            fail("expected SecurityException");
+        } catch (SecurityException e) {
+            // Expected.
+        }
+    }
+
+    /**
+     * Test rollback of multi-package installs.
+     * TODO: Stop ignoring this test once support for multi-package rollback
+     * is implemented.
+     */
+    @Test
+    public void testMultiPackage() throws Exception {
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+            // Prep installation of the test apps.
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.uninstall(TEST_APP_B);
+            RollbackTestUtils.installMultiPackage(false,
+                    "RollbackTestAppAv1.apk",
+                    "RollbackTestAppBv1.apk");
+            RollbackTestUtils.installMultiPackage(true,
+                    "RollbackTestAppAv2.apk",
+                    "RollbackTestAppBv2.apk");
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+
+            // TEST_APP_A should now be available for rollback.
+            assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+            RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+            assertNotNull(rollback);
+
+            // TODO: Test the dependent apps for rollback are correct once we
+            // support that in the RollbackInfo API.
+
+            // Rollback the app. It should cause both test apps to be rolled
+            // back.
+            RollbackTestUtils.rollback(rollback);
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+
+            // We should not see a recent rollback listed for TEST_APP_B
+            for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
+                assertNotEquals(TEST_APP_B, r.targetPackage.getPackageName());
+            }
+
+            // TODO: Test the listed dependent apps for the recently executed
+            // rollback are correct once we support that in the RollbackInfo
+            // API.
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
+    }
+
+    // Helper function to test the value of a PackageRollbackInfo
+    private void assertPackageRollbackInfoEquals(String packageName,
+            long versionRolledBackFrom, long versionRolledBackTo,
+            PackageRollbackInfo info) {
+        assertEquals(packageName, info.getPackageName());
+        assertEquals(packageName, info.getVersionRolledBackFrom().getPackageName());
+        assertEquals(versionRolledBackFrom, info.getVersionRolledBackFrom().getLongVersionCode());
+        assertEquals(packageName, info.getVersionRolledBackTo().getPackageName());
+        assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode());
+    }
 }
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index c5ce3fa..fbc3d8f 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -135,15 +135,64 @@
         assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
     }
 
-    // TODO: Unused
-    static void adoptShellPermissionIdentity() {
+    /**
+     * Installs the apks with the given resource names as an atomic set.
+     *
+     * @param enableRollback if rollback should be enabled.
+     * @param resourceNames names of the class loader resource for the apks to
+     *        install.
+     * @throws AssertionError if the installation fails.
+     */
+    static void installMultiPackage(boolean enableRollback, String... resourceNames)
+            throws InterruptedException, IOException {
+        Context context = InstrumentationRegistry.getContext();
+        PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
+
+        PackageInstaller.SessionParams multiPackageParams = new PackageInstaller.SessionParams(
+                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+        multiPackageParams.setMultiPackage();
+        if (enableRollback) {
+            // TODO: Do we set this on the parent params, the child params, or
+            // both?
+            multiPackageParams.setEnableRollback();
+        }
+        int multiPackageId = packageInstaller.createSession(multiPackageParams);
+        PackageInstaller.Session multiPackage = packageInstaller.openSession(multiPackageId);
+
+        for (String resourceName : resourceNames) {
+            PackageInstaller.Session session = null;
+            PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+                    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+            if (enableRollback) {
+                params.setEnableRollback();
+            }
+            int sessionId = packageInstaller.createSession(params);
+            session = packageInstaller.openSession(sessionId);
+
+            ClassLoader loader = RollbackTest.class.getClassLoader();
+            try (OutputStream packageInSession = session.openWrite("package", 0, -1);
+                 InputStream is = loader.getResourceAsStream(resourceName);) {
+                byte[] buffer = new byte[4096];
+                int n;
+                while ((n = is.read(buffer)) >= 0) {
+                    packageInSession.write(buffer, 0, n);
+                }
+            }
+            multiPackage.addChildSessionId(sessionId);
+        }
+
+        // Commit the session (this will start the installation workflow).
+        multiPackage.commit(LocalIntentSender.getIntentSender());
+        assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
+    }
+
+    static void adoptShellPermissionIdentity(String... permissions) {
         InstrumentationRegistry
             .getInstrumentation()
             .getUiAutomation()
-            .adoptShellPermissionIdentity();
+            .adoptShellPermissionIdentity(permissions);
     }
 
-    // TODO: Unused
     static void dropShellPermissionIdentity() {
         InstrumentationRegistry
             .getInstrumentation()
diff --git a/tests/UsageReportingTest/Android.mk b/tests/UsageReportingTest/Android.mk
new file mode 100644
index 0000000..afb6e16b1
--- /dev/null
+++ b/tests/UsageReportingTest/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_USE_AAPT2 := true
+LOCAL_STATIC_ANDROID_LIBRARIES := androidx.legacy_legacy-support-v4
+
+LOCAL_CERTIFICATE := platform
+
+LOCAL_PACKAGE_NAME := UsageReportingTest
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+include $(BUILD_PACKAGE)
diff --git a/tests/UsageReportingTest/AndroidManifest.xml b/tests/UsageReportingTest/AndroidManifest.xml
new file mode 100644
index 0000000..be0b09e
--- /dev/null
+++ b/tests/UsageReportingTest/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  Note: Add android:sharedUserId="android.uid.system" to the root element to simulate the system UID
+  caller case.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.tests.usagereporter"
+    >
+
+    <application android:label="@string/reporter_app">
+        <activity android:name="UsageReporterActivity"
+                  android:label="UsageReporter">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
diff --git a/tests/UsageReportingTest/res/layout/row_item.xml b/tests/UsageReportingTest/res/layout/row_item.xml
new file mode 100644
index 0000000..1eb2dab
--- /dev/null
+++ b/tests/UsageReportingTest/res/layout/row_item.xml
@@ -0,0 +1,36 @@
+<?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:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingLeft="16dp"
+    android:paddingRight="16dp"
+    android:background="@color/inactive_color">
+
+    <TextView android:id="@+id/token"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:textStyle="bold"/>
+
+    <Button android:id="@+id/start" style="@style/ActionButton"
+            android:text="@string/start" />
+
+    <Button android:id="@+id/stop" style="@style/ActionButton"
+            android:text="@string/stop" />
+</LinearLayout>
diff --git a/tests/UsageReportingTest/res/menu/main.xml b/tests/UsageReportingTest/res/menu/main.xml
new file mode 100644
index 0000000..9847c2d
--- /dev/null
+++ b/tests/UsageReportingTest/res/menu/main.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/add_token"
+          android:title="@string/add_token"/>
+    <item android:id="@+id/add_many_tokens"
+          android:title="@string/add_many_tokens"/>
+    <item android:id="@+id/stop_all"
+          android:title="@string/stop_all_tokens"/>
+    <group android:checkableBehavior="all">
+        <item android:id="@+id/restore_on_start"
+              android:title="@string/restore_tokens_on_start"/>
+    </group>
+</menu>
\ No newline at end of file
diff --git a/tests/UsageReportingTest/res/values/colors.xml b/tests/UsageReportingTest/res/values/colors.xml
new file mode 100644
index 0000000..03bcf8a
--- /dev/null
+++ b/tests/UsageReportingTest/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?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>
+    <color name="active_color">#FFF</color>
+    <color name="inactive_color">#AAA</color>
+</resources>
\ No newline at end of file
diff --git a/tests/UsageReportingTest/res/values/strings.xml b/tests/UsageReportingTest/res/values/strings.xml
new file mode 100644
index 0000000..015290e
--- /dev/null
+++ b/tests/UsageReportingTest/res/values/strings.xml
@@ -0,0 +1,47 @@
+<?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>
+    <!-- Do not translate -->
+    <string name="reporter_app">Usage Reporter App</string>
+    <!-- Do not translate -->
+    <string name="start">Start</string>
+    <!-- Do not translate -->
+    <string name="stop">Stop</string>
+    <!-- Do not translate -->
+    <string name="default_token">SuperSecretToken</string>
+
+    <!-- Do not translate -->
+    <string name="add_token">Add Token</string>
+    <!-- Do not translate -->
+    <string name="add_many_tokens">Add Many Tokens</string>
+    <!-- Do not translate -->
+    <string name="stop_all_tokens">Stop All</string>
+    <!-- Do not translate -->
+    <string name="restore_tokens_on_start">Readd Tokens on Start</string>
+
+
+    <!-- Do not translate -->
+    <string name="token_query">Enter token(s) (delimit tokens with commas)</string>
+    <!-- Do not translate -->
+    <string name="many_tokens_query">Generate how many tokens?</string>
+    <!-- Do not translate -->
+    <string name="stop_all_tokens_query">Stop all tokens?</string>
+    <!-- Do not translate -->
+    <string name="ok">OK</string>
+    <!-- Do not translate -->
+    <string name="cancel">Cancel</string>
+</resources>
\ No newline at end of file
diff --git a/tests/UsageReportingTest/res/values/styles.xml b/tests/UsageReportingTest/res/values/styles.xml
new file mode 100644
index 0000000..e5b86c5
--- /dev/null
+++ b/tests/UsageReportingTest/res/values/styles.xml
@@ -0,0 +1,31 @@
+<?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>
+    <style name="ActionButton">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:textAppearance">@style/TextAppearance.ActionButton</item>
+    </style>
+
+    <style name="TextAppearance" parent="android:TextAppearance">
+    </style>
+
+    <style name="TextAppearance.ActionButton">
+        <item name="android:textStyle">italic</item>
+    </style>
+
+</resources>
diff --git a/tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java b/tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java
new file mode 100644
index 0000000..946be8f
--- /dev/null
+++ b/tests/UsageReportingTest/src/com/android/tests/usagereporter/UsageReporterActivity.java
@@ -0,0 +1,320 @@
+/*
+ * 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.usagereporter;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ListActivity;
+import android.app.usage.UsageStatsManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+
+public class UsageReporterActivity extends ListActivity {
+
+    private Activity mActivity;
+    private final ArrayList<String> mTokens = new ArrayList();
+    private final ArraySet<String> mActives = new ArraySet();
+    private UsageStatsManager mUsageStatsManager;
+    private Adapter mAdapter;
+    private boolean mRestoreOnStart = false;
+    private static Context sContext;
+
+    /** Called with the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        sContext = getApplicationContext();
+
+        mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
+
+        mAdapter = new Adapter();
+        setListAdapter(mAdapter);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        mActivity = this;
+
+
+        if (mRestoreOnStart) {
+            ArrayList<String> removed = null;
+            for (String token : mActives) {
+                try {
+                    mUsageStatsManager.reportUsageStart(mActivity, token);
+                } catch (Exception e) {
+                    // Somthing went wrong, recover and move on
+                    if (removed == null) {
+                        removed = new ArrayList();
+                    }
+                    removed.add(token);
+                }
+            }
+            if (removed != null) {
+                for (String token : removed) {
+                    mActives.remove(token);
+                }
+            }
+        } else {
+            mActives.clear();
+        }
+    }
+
+    /**
+     * Called when the activity is about to start interacting with the user.
+     */
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mAdapter.notifyDataSetChanged();
+    }
+
+
+    /**
+     * Called when your activity's options menu needs to be created.
+     */
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.main, menu);
+        return super.onCreateOptionsMenu(menu);
+    }
+
+
+    /**
+     * Called when a menu item is selected.
+     */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.add_token:
+                callAddToken();
+                return true;
+            case R.id.add_many_tokens:
+                callAddManyTokens();
+                return true;
+            case R.id.stop_all:
+                callStopAll();
+                return true;
+            case R.id.restore_on_start:
+                mRestoreOnStart = !mRestoreOnStart;
+                item.setChecked(mRestoreOnStart);
+                return true;
+        }
+
+        return super.onOptionsItemSelected(item);
+    }
+
+    private void callAddToken() {
+        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        builder.setTitle(getString(R.string.token_query));
+        final EditText input = new EditText(this);
+        input.setInputType(InputType.TYPE_CLASS_TEXT);
+        input.setHint(getString(R.string.default_token));
+        builder.setView(input);
+
+        builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                String tokenNames = input.getText().toString().trim();
+                if (TextUtils.isEmpty(tokenNames)) {
+                    tokenNames = getString(R.string.default_token);
+                }
+                String[] tokens = tokenNames.split(",");
+                for (String token : tokens) {
+                    if (mTokens.contains(token)) continue;
+                    mTokens.add(token);
+                }
+                mAdapter.notifyDataSetChanged();
+
+            }
+        });
+        builder.setNegativeButton(getString(R.string.cancel),
+                                  new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                dialog.cancel();
+            }
+        });
+
+        builder.show();
+    }
+
+    private void callAddManyTokens() {
+        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        builder.setTitle(getString(R.string.many_tokens_query));
+        final EditText input = new EditText(this);
+        input.setInputType(InputType.TYPE_CLASS_NUMBER);
+        builder.setView(input);
+
+        builder.setPositiveButton(getString(R.string.ok),
+                new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                String val = input.getText().toString().trim();
+                if (TextUtils.isEmpty(val)) return;
+                int n = Integer.parseInt(val);
+                for (int i = 0; i < n; i++) {
+                    final String token = getString(R.string.default_token) + i;
+                    if (mTokens.contains(token)) continue;
+                    mTokens.add(token);
+                }
+                mAdapter.notifyDataSetChanged();
+
+            }
+        });
+        builder.setNegativeButton(getString(R.string.cancel),
+                new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                dialog.cancel();
+            }
+        });
+
+        builder.show();
+    }
+
+    private void callStopAll() {
+        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        builder.setTitle(getString(R.string.stop_all_tokens_query));
+
+        builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                for (String token : mActives) {
+                    mUsageStatsManager.reportUsageStop(mActivity, token);
+                }
+                mActives.clear();
+                mAdapter.notifyDataSetChanged();
+            }
+        });
+        builder.setNegativeButton(getString(R.string.cancel),
+                new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                dialog.cancel();
+            }
+        });
+        builder.show();
+    }
+
+    /**
+     * A call-back for when the user presses the back button.
+     */
+    OnClickListener mStartListener = new OnClickListener() {
+        public void onClick(View v) {
+            final View parent = (View) v.getParent();
+            final String token = ((TextView) parent.findViewById(R.id.token)).getText().toString();
+            try {
+                mUsageStatsManager.reportUsageStart(mActivity, token);
+            } catch (Exception e) {
+                Toast.makeText(sContext, e.toString(), Toast.LENGTH_LONG).show();
+            }
+            parent.setBackgroundColor(getColor(R.color.active_color));
+            mActives.add(token);
+        }
+    };
+
+    /**
+     * A call-back for when the user presses the clear button.
+     */
+    OnClickListener mStopListener = new OnClickListener() {
+        public void onClick(View v) {
+            final View parent = (View) v.getParent();
+
+            final String token = ((TextView) parent.findViewById(R.id.token)).getText().toString();
+            try {
+                mUsageStatsManager.reportUsageStop(mActivity, token);
+            } catch (Exception e) {
+                Toast.makeText(sContext, e.toString(), Toast.LENGTH_LONG).show();
+            }
+            parent.setBackgroundColor(getColor(R.color.inactive_color));
+            mActives.remove(token);
+        }
+    };
+
+
+    private class Adapter extends BaseAdapter {
+        @Override
+        public int getCount() {
+            return mTokens.size();
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return mTokens.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final ViewHolder holder;
+            if (convertView == null) {
+                convertView = LayoutInflater.from(UsageReporterActivity.this)
+                        .inflate(R.layout.row_item, parent, false);
+                holder = new ViewHolder();
+                holder.tokenName = (TextView) convertView.findViewById(R.id.token);
+
+                holder.startButton = ((Button) convertView.findViewById(R.id.start));
+                holder.startButton.setOnClickListener(mStartListener);
+                holder.stopButton = ((Button) convertView.findViewById(R.id.stop));
+                holder.stopButton.setOnClickListener(mStopListener);
+                convertView.setTag(holder);
+            } else {
+                holder = (ViewHolder) convertView.getTag();
+            }
+
+            final String token = mTokens.get(position);
+            holder.tokenName.setText(mTokens.get(position));
+            if (mActives.contains(token)) {
+                convertView.setBackgroundColor(getColor(R.color.active_color));
+            } else {
+                convertView.setBackgroundColor(getColor(R.color.inactive_color));
+            }
+            return convertView;
+        }
+    }
+
+    private static class ViewHolder {
+        public TextView tokenName;
+        public Button startButton;
+        public Button stopButton;
+    }
+}
diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
index 3d8ce21..3c628f6 100644
--- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
+++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
@@ -155,7 +155,7 @@
                     intent.setPackage(getPackageName());
                     intent.putExtra(EXTRA_KEY_TIMEOUT, true);
                     mUsageStatsManager.registerAppUsageObserver(1, packages,
-                            30, TimeUnit.SECONDS, PendingIntent.getActivity(UsageStatsActivity.this,
+                            60, TimeUnit.SECONDS, PendingIntent.getActivity(UsageStatsActivity.this,
                                     1, intent, 0));
                 }
             }
diff --git a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
index d5987a5..8564698 100644
--- a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
+++ b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
@@ -28,6 +28,7 @@
 import android.view.IWindowSession;
 import android.view.InsetsState;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
@@ -106,7 +107,7 @@
                                 window.mSeq, mLayoutParams, -1, -1, View.VISIBLE, 0, -1, mTmpRect,
                                 mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect,
                                 new DisplayCutout.ParcelableWrapper(), new MergedConfiguration(),
-                                new Surface(), new InsetsState());
+                                new SurfaceControl(), new InsetsState());
                     } catch (RemoteException e) {
                         e.printStackTrace();
                     }
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 9d1edbf..7e1b400 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -18,6 +18,7 @@
     mockito-target-minus-junit4 \
     platform-test-annotations \
     services.core \
+    services.ipmemorystore \
     services.net
 
 LOCAL_JAVA_LIBRARIES := \
@@ -31,73 +32,6 @@
 
 LOCAL_CERTIFICATE := platform
 
-# These are not normally accessible from apps so they must be explicitly included.
-LOCAL_JNI_SHARED_LIBRARIES := \
-    android.hidl.token@1.0 \
-    libartbase \
-    libbacktrace \
-    libbase \
-    libbinder \
-    libbinderthreadstate \
-    libc++ \
-    libcrypto \
-    libcutils \
-    libdexfile \
-    libframeworksnettestsjni \
-    libhidl-gen-utils \
-    libhidlbase \
-    libhidltransport \
-    libhwbinder \
-    liblog \
-    liblzma \
-    libnativehelper \
-    libpackagelistparser \
-    libpcre2 \
-    libselinux \
-    libui \
-    libutils \
-    libvintf \
-    libvndksupport \
-    libtinyxml2 \
-    libunwindstack \
-    libutilscallstack \
-    libziparchive \
-    libz \
-    netd_aidl_interface-cpp
-
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Wall -Wextra -Werror
-
-LOCAL_C_INCLUDES := \
-  libpcap \
-  hardware/google/apf
-
-LOCAL_SRC_FILES := $(call all-cpp-files-under)
-
-LOCAL_SHARED_LIBRARIES := \
-  libbinder \
-  liblog \
-  libcutils \
-  libnativehelper \
-  netd_aidl_interface-cpp
-
-LOCAL_STATIC_LIBRARIES := \
-  libpcap \
-  libapf
-
-LOCAL_MODULE := libframeworksnettestsjni
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/net/java/android/net/DnsPacketTest.java b/tests/net/java/android/net/DnsPacketTest.java
new file mode 100644
index 0000000..032e526
--- /dev/null
+++ b/tests/net/java/android/net/DnsPacketTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DnsPacketTest {
+    private void assertHeaderParses(DnsPacket.DnsHeader header, int id, int flag,
+            int qCount, int aCount, int nsCount, int arCount) {
+        assertEquals(header.id, id);
+        assertEquals(header.flags, flag);
+        assertEquals(header.getSectionCount(DnsPacket.QDSECTION), qCount);
+        assertEquals(header.getSectionCount(DnsPacket.ANSECTION), aCount);
+        assertEquals(header.getSectionCount(DnsPacket.NSSECTION), nsCount);
+        assertEquals(header.getSectionCount(DnsPacket.ARSECTION), arCount);
+    }
+
+    private void assertSectionParses(DnsPacket.DnsSection section, String dname,
+            int dtype, int dclass, int ttl, byte[] rr) {
+        assertEquals(section.dName, dname);
+        assertEquals(section.nsType, dtype);
+        assertEquals(section.nsClass, dclass);
+        assertEquals(section.ttl, ttl);
+        assertTrue(Arrays.equals(section.getRR(), rr));
+    }
+
+    class TestDnsPacket extends DnsPacket {
+        TestDnsPacket(byte[] data) throws ParseException {
+            super(data);
+        }
+
+        public DnsHeader getHeader() {
+            return mHeader;
+        }
+        public List<DnsSection> getSectionList(int secType) {
+            return mSections[secType];
+        }
+    }
+
+    @Test
+    public void testNullDisallowed() {
+        try {
+            new TestDnsPacket(null);
+            fail("Exception not thrown for null byte array");
+        } catch (DnsPacket.ParseException e) {
+        }
+    }
+
+    @Test
+    public void testV4Answer() throws Exception {
+        final byte[] v4blob = new byte[] {
+            /* Header */
+            0x55, 0x66, /* Transaction ID */
+            (byte) 0x81, (byte) 0x80, /* Flags */
+            0x00, 0x01, /* Questions */
+            0x00, 0x01, /* Answer RRs */
+            0x00, 0x00, /* Authority RRs */
+            0x00, 0x00, /* Additional RRs */
+            /* Queries */
+            0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
+            0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
+            0x00, 0x01, /* Type */
+            0x00, 0x01, /* Class */
+            /* Answers */
+            (byte) 0xc0, 0x0c, /* Name */
+            0x00, 0x01, /* Type */
+            0x00, 0x01, /* Class */
+            0x00, 0x00, 0x01, 0x2b, /* TTL */
+            0x00, 0x04, /* Data length */
+            (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 /* Address */
+        };
+        TestDnsPacket packet = new TestDnsPacket(v4blob);
+
+        // Header part
+        assertHeaderParses(packet.getHeader(), 0x5566, 0x8180, 1, 1, 0, 0);
+
+        // Section part
+        List<DnsPacket.DnsSection> qdSectionList =
+                packet.getSectionList(DnsPacket.QDSECTION);
+        assertEquals(qdSectionList.size(), 1);
+        assertSectionParses(qdSectionList.get(0), "www.google.com", 1, 1, 0, null);
+
+        List<DnsPacket.DnsSection> anSectionList =
+                packet.getSectionList(DnsPacket.ANSECTION);
+        assertEquals(anSectionList.size(), 1);
+        assertSectionParses(anSectionList.get(0), "www.google.com", 1, 1, 0x12b,
+                new byte[]{ (byte) 0xac, (byte) 0xd9, (byte) 0xa1, (byte) 0x84 });
+    }
+
+    @Test
+    public void testV6Answer() throws Exception {
+        final byte[] v6blob = new byte[] {
+            /* Header */
+            0x77, 0x22, /* Transaction ID */
+            (byte) 0x81, (byte) 0x80, /* Flags */
+            0x00, 0x01, /* Questions */
+            0x00, 0x01, /* Answer RRs */
+            0x00, 0x00, /* Authority RRs */
+            0x00, 0x00, /* Additional RRs */
+            /* Queries */
+            0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
+            0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
+            0x00, 0x1c, /* Type */
+            0x00, 0x01, /* Class */
+            /* Answers */
+            (byte) 0xc0, 0x0c, /* Name */
+            0x00, 0x1c, /* Type */
+            0x00, 0x01, /* Class */
+            0x00, 0x00, 0x00, 0x37, /* TTL */
+            0x00, 0x10, /* Data length */
+            0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 /* Address */
+        };
+        TestDnsPacket packet = new TestDnsPacket(v6blob);
+
+        // Header part
+        assertHeaderParses(packet.getHeader(), 0x7722, 0x8180, 1, 1, 0, 0);
+
+        // Section part
+        List<DnsPacket.DnsSection> qdSectionList =
+                packet.getSectionList(DnsPacket.QDSECTION);
+        assertEquals(qdSectionList.size(), 1);
+        assertSectionParses(qdSectionList.get(0), "www.google.com", 28, 1, 0, null);
+
+        List<DnsPacket.DnsSection> anSectionList =
+                packet.getSectionList(DnsPacket.ANSECTION);
+        assertEquals(anSectionList.size(), 1);
+        assertSectionParses(anSectionList.get(0), "www.google.com", 28, 1, 0x37,
+                new byte[]{ 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0x0d,
+                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04 });
+    }
+}
diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java
new file mode 100644
index 0000000..eae9710
--- /dev/null
+++ b/tests/net/java/android/net/IpMemoryStoreTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.content.Context;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpMemoryStoreTest {
+    @Mock
+    Context mMockContext;
+    @Mock
+    IIpMemoryStore mMockService;
+    IpMemoryStore mStore;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mStore = new IpMemoryStore(mMockContext, mMockService);
+    }
+
+    @Test
+    public void testNetworkAttributes() {
+        // TODO : implement this
+    }
+
+    @Test
+    public void testPrivateData() {
+        // TODO : implement this
+    }
+
+    @Test
+    public void testFindL2Key() {
+        // TODO : implement this
+    }
+
+    @Test
+    public void testIsSameNetwork() {
+        // TODO : implement this
+    }
+
+}
diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/java/android/net/LinkPropertiesTest.java
index 9695e9a..299fbef 100644
--- a/tests/net/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/java/android/net/LinkPropertiesTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -33,6 +34,9 @@
 import android.system.OsConstants;
 import android.util.ArraySet;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -41,9 +45,6 @@
 import java.util.List;
 import java.util.Set;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class LinkPropertiesTest {
@@ -53,6 +54,8 @@
     private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1");
     private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1");
     private static InetAddress DNS6 = NetworkUtils.numericToInetAddress("2001:4860:4860::8888");
+    private static InetAddress PCSCFV6 =  NetworkUtils.numericToInetAddress(
+            "2001:0db8:85a3:0000:0000:8a2e:0370:1");
     private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1");
     private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1");
     private static InetAddress GATEWAY61 = NetworkUtils.numericToInetAddress("fe80::6:0000:613");
@@ -86,6 +89,9 @@
         assertTrue(source.isIdenticalValidatedPrivateDnses(target));
         assertTrue(target.isIdenticalValidatedPrivateDnses(source));
 
+        assertTrue(source.isIdenticalPcscfs(target));
+        assertTrue(target.isIdenticalPcscfs(source));
+
         assertTrue(source.isIdenticalRoutes(target));
         assertTrue(target.isIdenticalRoutes(source));
 
@@ -128,6 +134,8 @@
         // set 2 dnses
         source.addDnsServer(DNS1);
         source.addDnsServer(DNS2);
+        // set 1 pcscf
+        source.addPcscfServer(PCSCFV6);
         // set 2 gateways
         source.addRoute(new RouteInfo(GATEWAY1));
         source.addRoute(new RouteInfo(GATEWAY2));
@@ -141,6 +149,7 @@
         target.addLinkAddress(LINKADDRV6);
         target.addDnsServer(DNS1);
         target.addDnsServer(DNS2);
+        target.addPcscfServer(PCSCFV6);
         target.addRoute(new RouteInfo(GATEWAY1));
         target.addRoute(new RouteInfo(GATEWAY2));
         target.setMtu(MTU);
@@ -154,6 +163,7 @@
         target.addLinkAddress(LINKADDRV6);
         target.addDnsServer(DNS1);
         target.addDnsServer(DNS2);
+        target.addPcscfServer(PCSCFV6);
         target.addRoute(new RouteInfo(GATEWAY1));
         target.addRoute(new RouteInfo(GATEWAY2));
         target.setMtu(MTU);
@@ -167,6 +177,7 @@
         target.addLinkAddress(LINKADDRV6);
         target.addDnsServer(DNS1);
         target.addDnsServer(DNS2);
+        target.addPcscfServer(PCSCFV6);
         target.addRoute(new RouteInfo(GATEWAY1));
         target.addRoute(new RouteInfo(GATEWAY2));
         target.setMtu(MTU);
@@ -179,6 +190,21 @@
         // change dnses
         target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2"));
         target.addDnsServer(DNS2);
+        target.addPcscfServer(PCSCFV6);
+        target.addRoute(new RouteInfo(GATEWAY1));
+        target.addRoute(new RouteInfo(GATEWAY2));
+        target.setMtu(MTU);
+        assertFalse(source.equals(target));
+
+        target.clear();
+        target.setInterfaceName(NAME);
+        target.addLinkAddress(LINKADDRV4);
+        target.addLinkAddress(LINKADDRV6);
+        target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2"));
+        target.addDnsServer(DNS2);
+        // change pcscf
+        target.addPcscfServer(NetworkUtils.numericToInetAddress(
+            "2001::1"));
         target.addRoute(new RouteInfo(GATEWAY1));
         target.addRoute(new RouteInfo(GATEWAY2));
         target.setMtu(MTU);
@@ -479,6 +505,40 @@
     }
 
     @Test
+    public void testNat64Prefix() throws Exception {
+        LinkProperties lp = new LinkProperties();
+        lp.addLinkAddress(LINKADDRV4);
+        lp.addLinkAddress(LINKADDRV6);
+
+        assertNull(lp.getNat64Prefix());
+
+        IpPrefix p = new IpPrefix("64:ff9b::/96");
+        lp.setNat64Prefix(p);
+        assertEquals(p, lp.getNat64Prefix());
+
+        p = new IpPrefix("2001:db8:a:b:1:2:3::/96");
+        lp.setNat64Prefix(p);
+        assertEquals(p, lp.getNat64Prefix());
+
+        p = new IpPrefix("2001:db8:a:b:1:2::/80");
+        try {
+            lp.setNat64Prefix(p);
+        } catch (IllegalArgumentException expected) {
+        }
+
+        p = new IpPrefix("64:ff9b::/64");
+        try {
+            lp.setNat64Prefix(p);
+        } catch (IllegalArgumentException expected) {
+        }
+
+        assertEquals(new IpPrefix("2001:db8:a:b:1:2:3::/96"), lp.getNat64Prefix());
+
+        lp.setNat64Prefix(null);
+        assertNull(lp.getNat64Prefix());
+    }
+
+    @Test
     public void testIsProvisioned() {
         LinkProperties lp4 = new LinkProperties();
         assertFalse("v4only:empty", lp4.isProvisioned());
@@ -789,8 +849,20 @@
         assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
     }
 
+    private void assertParcelingIsLossless(LinkProperties source) {
+        Parcel p = Parcel.obtain();
+        source.writeToParcel(p, /* flags */ 0);
+        p.setDataPosition(0);
+        final byte[] marshalled = p.marshall();
+        p = Parcel.obtain();
+        p.unmarshall(marshalled, 0, marshalled.length);
+        p.setDataPosition(0);
+        LinkProperties dest = LinkProperties.CREATOR.createFromParcel(p);
+        assertEquals(source, dest);
+    }
+
     @Test
-    public void testLinkPropertiesParcelable() {
+    public void testLinkPropertiesParcelable() throws Exception {
         LinkProperties source = new LinkProperties();
         source.setInterfaceName(NAME);
         // set 2 link addresses
@@ -808,15 +880,14 @@
 
         source.setMtu(MTU);
 
-        Parcel p = Parcel.obtain();
-        source.writeToParcel(p, /* flags */ 0);
-        p.setDataPosition(0);
-        final byte[] marshalled = p.marshall();
-        p = Parcel.obtain();
-        p.unmarshall(marshalled, 0, marshalled.length);
-        p.setDataPosition(0);
-        LinkProperties dest = LinkProperties.CREATOR.createFromParcel(p);
+        source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
 
-        assertEquals(source, dest);
+        assertParcelingIsLossless(source);
+    }
+
+    @Test
+    public void testParcelUninitialized() throws Exception {
+        LinkProperties empty = new LinkProperties();
+        assertParcelingIsLossless(empty);
     }
 }
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
index 1e3a49b..2c2afd4 100644
--- a/tests/net/java/android/net/NetworkStatsTest.java
+++ b/tests/net/java/android/net/NetworkStatsTest.java
@@ -832,25 +832,23 @@
                 0 /* operations */);
 
         // Traffic measured for the root uid on the base interface if eBPF is in use.
-        // Incorrectly includes appEntry's bytes and packets, plus IPv4-IPv6 translation
-        // overhead (20 bytes per packet), only for TX traffic.
         final NetworkStats.Entry ebpfRootUidEntry = new NetworkStats.Entry(
                 baseIface, rootUid, SET_DEFAULT, TAG_NONE,
                 163577 /* rxBytes */,
                 187 /* rxPackets */,
-                1169942 /* txBytes */,
-                13902 /* txPackets */,
+                17607 /* txBytes */,
+                97 /* txPackets */,
                 0 /* operations */);
 
         // Traffic measured for the root uid on the base interface if xt_qtaguid is in use.
         // Incorrectly includes appEntry's bytes and packets, plus IPv4-IPv6 translation
-        // overhead (20 bytes per packet), in both directions.
+        // overhead (20 bytes per packet), in rx direction.
         final NetworkStats.Entry xtRootUidEntry = new NetworkStats.Entry(
                 baseIface, rootUid, SET_DEFAULT, TAG_NONE,
                 31113087 /* rxBytes */,
                 22588 /* rxPackets */,
-                1169942 /* txBytes */,
-                13902 /* txPackets */,
+                17607 /* txBytes */,
+                97 /* txPackets */,
                 0 /* operations */);
 
         final NetworkStats.Entry otherEntry = new NetworkStats.Entry(
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
deleted file mode 100644
index 151b559..0000000
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ /dev/null
@@ -1,1779 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.apf;
-
-import static android.net.util.NetworkConstants.*;
-import static android.system.OsConstants.*;
-import static com.android.internal.util.BitUtils.bytesToBEInt;
-import static com.android.internal.util.BitUtils.put;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.apf.ApfFilter.ApfConfiguration;
-import android.net.apf.ApfGenerator.IllegalInstructionException;
-import android.net.apf.ApfGenerator.Register;
-import android.net.ip.IpClient;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.RaEvent;
-import android.net.util.InterfaceParams;
-import android.os.ConditionVariable;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.text.format.DateUtils;
-import android.util.Log;
-import com.android.frameworks.tests.net.R;
-import com.android.internal.util.HexDump;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.util.List;
-import java.util.Random;
-import libcore.io.IoUtils;
-import libcore.io.Streams;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for APF program generator and interpreter.
- *
- * Build, install and run with:
- *  runtest frameworks-net -c android.net.apf.ApfTest
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ApfTest {
-    private static final int TIMEOUT_MS = 500;
-    private static final int MIN_APF_VERSION = 2;
-
-    @Mock IpConnectivityLog mLog;
-    @Mock Context mContext;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        // Load up native shared library containing APF interpreter exposed via JNI.
-        System.loadLibrary("frameworksnettestsjni");
-    }
-
-    private static final String TAG = "ApfTest";
-    // Expected return codes from APF interpreter.
-    private static final int PASS = 1;
-    private static final int DROP = 0;
-    // Interpreter will just accept packets without link layer headers, so pad fake packet to at
-    // least the minimum packet size.
-    private static final int MIN_PKT_SIZE = 15;
-
-    private static final ApfCapabilities MOCK_APF_CAPABILITIES =
-      new ApfCapabilities(2, 1700, ARPHRD_ETHER);
-
-    private static final boolean DROP_MULTICAST = true;
-    private static final boolean ALLOW_MULTICAST = false;
-
-    private static final boolean DROP_802_3_FRAMES = true;
-    private static final boolean ALLOW_802_3_FRAMES = false;
-
-    // Constants for opcode encoding
-    private static final byte LI_OP   = (byte)(13 << 3);
-    private static final byte LDDW_OP = (byte)(22 << 3);
-    private static final byte STDW_OP = (byte)(23 << 3);
-    private static final byte SIZE0   = (byte)(0 << 1);
-    private static final byte SIZE8   = (byte)(1 << 1);
-    private static final byte SIZE16  = (byte)(2 << 1);
-    private static final byte SIZE32  = (byte)(3 << 1);
-    private static final byte R1 = 1;
-
-    private static ApfConfiguration getDefaultConfig() {
-        ApfFilter.ApfConfiguration config = new ApfConfiguration();
-        config.apfCapabilities = MOCK_APF_CAPABILITIES;
-        config.multicastFilter = ALLOW_MULTICAST;
-        config.ieee802_3Filter = ALLOW_802_3_FRAMES;
-        config.ethTypeBlackList = new int[0];
-        return config;
-    }
-
-    private static String label(int code) {
-        switch (code) {
-            case PASS: return "PASS";
-            case DROP: return "DROP";
-            default:   return "UNKNOWN";
-        }
-    }
-
-    private static void assertReturnCodesEqual(int expected, int got) {
-        assertEquals(label(expected), label(got));
-    }
-
-    private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
-        assertReturnCodesEqual(expected, apfSimulate(program, packet, null, filterAge));
-    }
-
-    private void assertVerdict(int expected, byte[] program, byte[] packet) {
-        assertReturnCodesEqual(expected, apfSimulate(program, packet, null, 0));
-    }
-
-    private void assertPass(byte[] program, byte[] packet, int filterAge) {
-        assertVerdict(PASS, program, packet, filterAge);
-    }
-
-    private void assertPass(byte[] program, byte[] packet) {
-        assertVerdict(PASS, program, packet);
-    }
-
-    private void assertDrop(byte[] program, byte[] packet, int filterAge) {
-        assertVerdict(DROP, program, packet, filterAge);
-    }
-
-    private void assertDrop(byte[] program, byte[] packet) {
-        assertVerdict(DROP, program, packet);
-    }
-
-    private void assertProgramEquals(byte[] expected, byte[] program) throws AssertionError {
-        // assertArrayEquals() would only print one byte, making debugging difficult.
-        if (!java.util.Arrays.equals(expected, program)) {
-            throw new AssertionError(
-                    "\nexpected: " + HexDump.toHexString(expected) +
-                    "\nactual:   " + HexDump.toHexString(program));
-        }
-    }
-
-    private void assertDataMemoryContents(
-            int expected, byte[] program, byte[] packet, byte[] data, byte[] expected_data)
-            throws IllegalInstructionException, Exception {
-        assertReturnCodesEqual(expected, apfSimulate(program, packet, data, 0 /* filterAge */));
-
-        // assertArrayEquals() would only print one byte, making debugging difficult.
-        if (!java.util.Arrays.equals(expected_data, data)) {
-            throw new Exception(
-                    "\nprogram:     " + HexDump.toHexString(program) +
-                    "\ndata memory: " + HexDump.toHexString(data) +
-                    "\nexpected:    " + HexDump.toHexString(expected_data));
-        }
-    }
-
-    private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
-            throws IllegalInstructionException {
-        assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, null,
-              filterAge));
-    }
-
-    private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
-            throws IllegalInstructionException {
-        assertVerdict(PASS, gen, packet, filterAge);
-    }
-
-    private void assertDrop(ApfGenerator gen, byte[] packet, int filterAge)
-            throws IllegalInstructionException {
-        assertVerdict(DROP, gen, packet, filterAge);
-    }
-
-    private void assertPass(ApfGenerator gen)
-            throws IllegalInstructionException {
-        assertVerdict(PASS, gen, new byte[MIN_PKT_SIZE], 0);
-    }
-
-    private void assertDrop(ApfGenerator gen)
-            throws IllegalInstructionException {
-        assertVerdict(DROP, gen, new byte[MIN_PKT_SIZE], 0);
-    }
-
-    /**
-     * Test each instruction by generating a program containing the instruction,
-     * generating bytecode for that program and running it through the
-     * interpreter to verify it functions correctly.
-     */
-    @Test
-    public void testApfInstructions() throws IllegalInstructionException {
-        // Empty program should pass because having the program counter reach the
-        // location immediately after the program indicates the packet should be
-        // passed to the AP.
-        ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
-        assertPass(gen);
-
-        // Test jumping to pass label.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJump(gen.PASS_LABEL);
-        byte[] program = gen.generate();
-        assertEquals(1, program.length);
-        assertEquals((14 << 3) | (0 << 1) | 0, program[0]);
-        assertPass(program, new byte[MIN_PKT_SIZE], 0);
-
-        // Test jumping to drop label.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJump(gen.DROP_LABEL);
-        program = gen.generate();
-        assertEquals(2, program.length);
-        assertEquals((14 << 3) | (1 << 1) | 0, program[0]);
-        assertEquals(1, program[1]);
-        assertDrop(program, new byte[15], 15);
-
-        // Test jumping if equal to 0.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if not equal to 0.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if registers equal.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0EqualsR1(gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if registers not equal.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test load immediate.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test add.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addAdd(1234567890);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test subtract.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addAdd(-1234567890);
-        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test or.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addOr(1234567890);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test and.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addAnd(123456789);
-        gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test left shift.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addLeftShift(1);
-        gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test right shift.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addRightShift(1);
-        gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test multiply.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 123456789);
-        gen.addMul(2);
-        gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test divide.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addDiv(2);
-        gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test divide by zero.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addDiv(0);
-        gen.addJump(gen.DROP_LABEL);
-        assertPass(gen);
-
-        // Test add.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1234567890);
-        gen.addAddR1();
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test subtract.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, -1234567890);
-        gen.addAddR1();
-        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test or.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1234567890);
-        gen.addOrR1();
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test and.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addLoadImmediate(Register.R1, 123456789);
-        gen.addAndR1();
-        gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test left shift.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addLoadImmediate(Register.R1, 1);
-        gen.addLeftShiftR1();
-        gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test right shift.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addLoadImmediate(Register.R1, -1);
-        gen.addLeftShiftR1();
-        gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test multiply.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 123456789);
-        gen.addLoadImmediate(Register.R1, 2);
-        gen.addMulR1();
-        gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test divide.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addLoadImmediate(Register.R1, 2);
-        gen.addDivR1();
-        gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test divide by zero.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addDivR1();
-        gen.addJump(gen.DROP_LABEL);
-        assertPass(gen);
-
-        // Test byte load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoad8(Register.R0, 1);
-        gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test out of bounds load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoad8(Register.R0, 16);
-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
-        assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test half-word load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoad16(Register.R0, 1);
-        gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test word load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoad32(Register.R0, 1);
-        gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test byte indexed load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1);
-        gen.addLoad8Indexed(Register.R0, 0);
-        gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test out of bounds indexed load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 8);
-        gen.addLoad8Indexed(Register.R0, 8);
-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
-        assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test half-word indexed load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1);
-        gen.addLoad16Indexed(Register.R0, 0);
-        gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test word indexed load.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1);
-        gen.addLoad32Indexed(Register.R0, 0);
-        gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
-
-        // Test jumping if greater than.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if less than.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0LessThan(0, gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0LessThan(1, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if any bits set.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
-        assertDrop(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 3);
-        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if register greater than.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 2);
-        gen.addLoadImmediate(Register.R1, 1);
-        gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if register less than.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1);
-        gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jumping if any bits set in register.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 3);
-        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
-        assertPass(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 3);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
-        assertDrop(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 3);
-        gen.addLoadImmediate(Register.R0, 3);
-        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test load from memory.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadFromMemory(Register.R0, 0);
-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test store to memory.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1234567890);
-        gen.addStoreToMemory(Register.R1, 12);
-        gen.addLoadFromMemory(Register.R0, 12);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test filter age pre-filled memory.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890);
-
-        // Test packet size pre-filled memory.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
-        gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test IPv4 header size pre-filled memory.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
-        gen.addJumpIfR0Equals(20, gen.DROP_LABEL);
-        assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0);
-
-        // Test not.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addNot(Register.R0);
-        gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test negate.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addNeg(Register.R0);
-        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test move.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1234567890);
-        gen.addMove(Register.R0);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addMove(Register.R1);
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test swap.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R1, 1234567890);
-        gen.addSwap();
-        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
-        assertDrop(gen);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1234567890);
-        gen.addSwap();
-        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
-        assertDrop(gen);
-
-        // Test jump if bytes not equal.
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
-        program = gen.generate();
-        assertEquals(6, program.length);
-        assertEquals((13 << 3) | (1 << 1) | 0, program[0]);
-        assertEquals(1, program[1]);
-        assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]);
-        assertEquals(1, program[3]);
-        assertEquals(1, program[4]);
-        assertEquals(123, program[5]);
-        assertDrop(program, new byte[MIN_PKT_SIZE], 0);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
-        byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
-        assertPass(gen, packet123, 0);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
-        assertDrop(gen, packet123, 0);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
-        byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
-        assertDrop(gen, packet12345, 0);
-        gen = new ApfGenerator(MIN_APF_VERSION);
-        gen.addLoadImmediate(Register.R0, 1);
-        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL);
-        assertPass(gen, packet12345, 0);
-    }
-
-    @Test(expected = ApfGenerator.IllegalInstructionException.class)
-    public void testApfGeneratorWantsV2OrGreater() throws Exception {
-        // The minimum supported APF version is 2.
-        new ApfGenerator(1);
-    }
-
-    @Test
-    public void testApfDataOpcodesWantApfV3() throws IllegalInstructionException, Exception {
-        ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
-        try {
-            gen.addStoreData(Register.R0, 0);
-            fail();
-        } catch (IllegalInstructionException expected) {
-            /* pass */
-        }
-        try {
-            gen.addLoadData(Register.R0, 0);
-            fail();
-        } catch (IllegalInstructionException expected) {
-            /* pass */
-        }
-    }
-
-    /**
-     * Test that the generator emits immediates using the shortest possible encoding.
-     */
-    @Test
-    public void testImmediateEncoding() throws IllegalInstructionException {
-        ApfGenerator gen;
-
-        // 0-byte immediate: li R0, 0
-        gen = new ApfGenerator(4);
-        gen.addLoadImmediate(Register.R0, 0);
-        assertProgramEquals(new byte[]{LI_OP | SIZE0}, gen.generate());
-
-        // 1-byte immediate: li R0, 42
-        gen = new ApfGenerator(4);
-        gen.addLoadImmediate(Register.R0, 42);
-        assertProgramEquals(new byte[]{LI_OP | SIZE8, 42}, gen.generate());
-
-        // 2-byte immediate: li R1, 0x1234
-        gen = new ApfGenerator(4);
-        gen.addLoadImmediate(Register.R1, 0x1234);
-        assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, 0x12, 0x34}, gen.generate());
-
-        // 4-byte immediate: li R0, 0x12345678
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 0x12345678);
-        assertProgramEquals(
-                new byte[]{LI_OP | SIZE32, 0x12, 0x34, 0x56, 0x78},
-                gen.generate());
-    }
-
-    /**
-     * Test that the generator emits negative immediates using the shortest possible encoding.
-     */
-    @Test
-    public void testNegativeImmediateEncoding() throws IllegalInstructionException {
-        ApfGenerator gen;
-
-        // 1-byte negative immediate: li R0, -42
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, -42);
-        assertProgramEquals(new byte[]{LI_OP | SIZE8, -42}, gen.generate());
-
-        // 2-byte negative immediate: li R1, -0x1122
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R1, -0x1122);
-        assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
-                gen.generate());
-
-        // 4-byte negative immediate: li R0, -0x11223344
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, -0x11223344);
-        assertProgramEquals(
-                new byte[]{LI_OP | SIZE32, (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC},
-                gen.generate());
-    }
-
-    /**
-     * Test that the generator correctly emits positive and negative immediates for LDDW/STDW.
-     */
-    @Test
-    public void testLoadStoreDataEncoding() throws IllegalInstructionException {
-        ApfGenerator gen;
-
-        // Load data with no offset: lddw R0, [0 + r1]
-        gen = new ApfGenerator(3);
-        gen.addLoadData(Register.R0, 0);
-        assertProgramEquals(new byte[]{LDDW_OP | SIZE0}, gen.generate());
-
-        // Store data with 8bit negative offset: lddw r0, [-42 + r1]
-        gen = new ApfGenerator(3);
-        gen.addStoreData(Register.R0, -42);
-        assertProgramEquals(new byte[]{STDW_OP | SIZE8, -42}, gen.generate());
-
-        // Store data to R1 with 16bit negative offset: stdw r1, [-0x1122 + r0]
-        gen = new ApfGenerator(3);
-        gen.addStoreData(Register.R1, -0x1122);
-        assertProgramEquals(new byte[]{STDW_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
-                gen.generate());
-
-        // Load data to R1 with 32bit negative offset: lddw r1, [0xDEADBEEF + r0]
-        gen = new ApfGenerator(3);
-        gen.addLoadData(Register.R1, 0xDEADBEEF);
-        assertProgramEquals(
-                new byte[]{LDDW_OP | SIZE32 | R1, (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF},
-                gen.generate());
-    }
-
-    /**
-     * Test that the interpreter correctly executes STDW with a negative 8bit offset
-     */
-    @Test
-    public void testApfDataWrite() throws IllegalInstructionException, Exception {
-        byte[] packet = new byte[MIN_PKT_SIZE];
-        byte[] data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
-        byte[] expected_data = data.clone();
-
-        // No memory access instructions: should leave the data segment untouched.
-        ApfGenerator gen = new ApfGenerator(3);
-        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
-
-        // Expect value 0x87654321 to be stored starting from address -11 from the end of the
-        // data buffer, in big-endian order.
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 0x87654321);
-        gen.addLoadImmediate(Register.R1, -5);
-        gen.addStoreData(Register.R0, -6);  // -5 + -6 = -11 (offset +5 with data_len=16)
-        expected_data[5] = (byte)0x87;
-        expected_data[6] = (byte)0x65;
-        expected_data[7] = (byte)0x43;
-        expected_data[8] = (byte)0x21;
-        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
-    }
-
-    /**
-     * Test that the interpreter correctly executes LDDW with a negative 16bit offset
-     */
-    @Test
-    public void testApfDataRead() throws IllegalInstructionException, Exception {
-        // Program that DROPs if address 10 (-6) contains 0x87654321.
-        ApfGenerator gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R1, 1000);
-        gen.addLoadData(Register.R0, -1006);  // 1000 + -1006 = -6 (offset +10 with data_len=16)
-        gen.addJumpIfR0Equals(0x87654321, gen.DROP_LABEL);
-        byte[] program = gen.generate();
-        byte[] packet = new byte[MIN_PKT_SIZE];
-
-        // Content is incorrect (last byte does not match) -> PASS
-        byte[] data = new byte[16];
-        data[10] = (byte)0x87;
-        data[11] = (byte)0x65;
-        data[12] = (byte)0x43;
-        data[13] = (byte)0x00;  // != 0x21
-        byte[] expected_data = data.clone();
-        assertDataMemoryContents(PASS, program, packet, data, expected_data);
-
-        // Fix the last byte -> conditional jump taken -> DROP
-        data[13] = (byte)0x21;
-        expected_data = data;
-        assertDataMemoryContents(DROP, program, packet, data, expected_data);
-    }
-
-    /**
-     * Test that the interpreter correctly executes LDDW followed by a STDW.
-     * To cover a few more edge cases, LDDW has a 0bit offset, while STDW has a positive 8bit
-     * offset.
-     */
-    @Test
-    public void testApfDataReadModifyWrite() throws IllegalInstructionException, Exception {
-        ApfGenerator gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R1, -22);
-        gen.addLoadData(Register.R0, 0);  // Load from address 32 -22 + 0 = 10
-        gen.addAdd(0x78453412);  // 87654321 + 78453412 = FFAA7733
-        gen.addStoreData(Register.R0, 4);  // Write back to address 32 -22 + 4 = 14
-
-        byte[] packet = new byte[MIN_PKT_SIZE];
-        byte[] data = new byte[32];
-        data[10] = (byte)0x87;
-        data[11] = (byte)0x65;
-        data[12] = (byte)0x43;
-        data[13] = (byte)0x21;
-        byte[] expected_data = data.clone();
-        expected_data[14] = (byte)0xFF;
-        expected_data[15] = (byte)0xAA;
-        expected_data[16] = (byte)0x77;
-        expected_data[17] = (byte)0x33;
-        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
-    }
-
-    @Test
-    public void testApfDataBoundChecking() throws IllegalInstructionException, Exception {
-        byte[] packet = new byte[MIN_PKT_SIZE];
-        byte[] data = new byte[32];
-        byte[] expected_data = data;
-
-        // Program that DROPs unconditionally. This is our the baseline.
-        ApfGenerator gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 3);
-        gen.addLoadData(Register.R1, 7);
-        gen.addJump(gen.DROP_LABEL);
-        assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
-
-        // Same program as before, but this time we're trying to load past the end of the data.
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 20);
-        gen.addLoadData(Register.R1, 15);  // 20 + 15 > 32
-        gen.addJump(gen.DROP_LABEL);  // Not reached.
-        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
-
-        // Subtracting an immediate should work...
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 20);
-        gen.addLoadData(Register.R1, -4);
-        gen.addJump(gen.DROP_LABEL);
-        assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
-
-        // ...and underflowing simply wraps around to the end of the buffer...
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 20);
-        gen.addLoadData(Register.R1, -30);
-        gen.addJump(gen.DROP_LABEL);
-        assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
-
-        // ...but doesn't allow accesses before the start of the buffer
-        gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R0, 20);
-        gen.addLoadData(Register.R1, -1000);
-        gen.addJump(gen.DROP_LABEL);  // Not reached.
-        assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
-    }
-
-    /**
-     * Generate some BPF programs, translate them to APF, then run APF and BPF programs
-     * over packet traces and verify both programs filter out the same packets.
-     */
-    @Test
-    public void testApfAgainstBpf() throws Exception {
-        String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53",
-                "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24",
-                "arp or icmp6 or portrange 53-54", "portrange 53-54 or portrange 100-50000",
-                "tcp[tcpflags] & (tcp-ack|tcp-fin) != 0 and (ip[2:2] > 57 or icmp)" };
-        String pcap_filename = stageFile(R.raw.apf);
-        for (String tcpdump_filter : tcpdump_filters) {
-            byte[] apf_program = Bpf2Apf.convert(compileToBpf(tcpdump_filter));
-            assertTrue("Failed to match for filter: " + tcpdump_filter,
-                    compareBpfApf(tcpdump_filter, pcap_filename, apf_program));
-        }
-    }
-
-    /**
-     * Generate APF program, run pcap file though APF filter, then check all the packets in the file
-     * should be dropped.
-     */
-    @Test
-    public void testApfFilterPcapFile() throws Exception {
-        final byte[] MOCK_PCAP_IPV4_ADDR = {(byte) 172, 16, 7, (byte) 151};
-        String pcapFilename = stageFile(R.raw.apfPcap);
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_PCAP_IPV4_ADDR), 16);
-        LinkProperties lp = new LinkProperties();
-        lp.addLinkAddress(link);
-
-        ApfConfiguration config = getDefaultConfig();
-        ApfCapabilities MOCK_APF_PCAP_CAPABILITIES = new ApfCapabilities(4, 1700, ARPHRD_ETHER);
-        config.apfCapabilities = MOCK_APF_PCAP_CAPABILITIES;
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        apfFilter.setLinkProperties(lp);
-        byte[] program = ipClientCallback.getApfProgram();
-        byte[] data = new byte[ApfFilter.Counter.totalSize()];
-        final boolean result;
-
-        result = dropsAllPackets(program, data, pcapFilename);
-        Log.i(TAG, "testApfFilterPcapFile(): Data counters: " + HexDump.toHexString(data, false));
-
-        assertTrue("Failed to drop all packets by filter. \nAPF counters:" +
-            HexDump.toHexString(data, false), result);
-    }
-
-    private class MockIpClientCallback extends IpClient.Callback {
-        private final ConditionVariable mGotApfProgram = new ConditionVariable();
-        private byte[] mLastApfProgram;
-
-        @Override
-        public void installPacketFilter(byte[] filter) {
-            mLastApfProgram = filter;
-            mGotApfProgram.open();
-        }
-
-        public void resetApfProgramWait() {
-            mGotApfProgram.close();
-        }
-
-        public byte[] getApfProgram() {
-            assertTrue(mGotApfProgram.block(TIMEOUT_MS));
-            return mLastApfProgram;
-        }
-
-        public void assertNoProgramUpdate() {
-            assertFalse(mGotApfProgram.block(TIMEOUT_MS));
-        }
-    }
-
-    private static class TestApfFilter extends ApfFilter {
-        public static final byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
-
-        private FileDescriptor mWriteSocket;
-        private final long mFixedTimeMs = SystemClock.elapsedRealtime();
-
-        public TestApfFilter(Context context, ApfConfiguration config,
-                IpClient.Callback ipClientCallback, IpConnectivityLog log) throws Exception {
-            super(context, config, InterfaceParams.getByName("lo"), ipClientCallback, log);
-        }
-
-        // Pretend an RA packet has been received and show it to ApfFilter.
-        public void pretendPacketReceived(byte[] packet) throws IOException, ErrnoException {
-            // ApfFilter's ReceiveThread will be waiting to read this.
-            Os.write(mWriteSocket, packet, 0, packet.length);
-        }
-
-        @Override
-        protected long currentTimeSeconds() {
-            return mFixedTimeMs / DateUtils.SECOND_IN_MILLIS;
-        }
-
-        @Override
-        void maybeStartFilter() {
-            mHardwareAddress = MOCK_MAC_ADDR;
-            installNewProgramLocked();
-
-            // Create two sockets, "readSocket" and "mWriteSocket" and connect them together.
-            FileDescriptor readSocket = new FileDescriptor();
-            mWriteSocket = new FileDescriptor();
-            try {
-                Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket);
-            } catch (ErrnoException e) {
-                fail();
-                return;
-            }
-            // Now pass readSocket to ReceiveThread as if it was setup to read raw RAs.
-            // This allows us to pretend RA packets have been recieved via pretendPacketReceived().
-            mReceiveThread = new ReceiveThread(readSocket);
-            mReceiveThread.start();
-        }
-
-        @Override
-        public void shutdown() {
-            super.shutdown();
-            IoUtils.closeQuietly(mWriteSocket);
-        }
-    }
-
-    private static final int ETH_HEADER_LEN = 14;
-    private static final int ETH_DEST_ADDR_OFFSET = 0;
-    private static final int ETH_ETHERTYPE_OFFSET = 12;
-    private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
-            {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
-
-    private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
-    private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
-    private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
-    private static final byte[] IPV4_BROADCAST_ADDRESS =
-            {(byte) 255, (byte) 255, (byte) 255, (byte) 255};
-
-    private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
-    private static final int IPV6_HEADER_LEN = 40;
-    private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
-    // The IPv6 all nodes address ff02::1
-    private static final byte[] IPV6_ALL_NODES_ADDRESS =
-            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
-    private static final byte[] IPV6_ALL_ROUTERS_ADDRESS =
-            { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
-
-    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
-    private static final int ICMP6_ROUTER_SOLICITATION = 133;
-    private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
-    private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
-    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
-
-    private static final int ICMP6_RA_HEADER_LEN = 16;
-    private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
-            ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
-    private static final int ICMP6_RA_CHECKSUM_OFFSET =
-            ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
-    private static final int ICMP6_RA_OPTION_OFFSET =
-            ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
-
-    private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
-    private static final int ICMP6_PREFIX_OPTION_LEN = 32;
-    private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
-    private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
-
-    // From RFC6106: Recursive DNS Server option
-    private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
-    // From RFC6106: DNS Search List option
-    private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
-
-    // From RFC4191: Route Information option
-    private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
-    // Above three options all have the same format:
-    private static final int ICMP6_4_BYTE_OPTION_LEN = 8;
-    private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
-    private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
-
-    private static final int UDP_HEADER_LEN = 8;
-    private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22;
-
-    private static final int DHCP_CLIENT_PORT = 68;
-    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
-
-    private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
-    private static final byte[] ARP_IPV4_REQUEST_HEADER = {
-            0, 1, // Hardware type: Ethernet (1)
-            8, 0, // Protocol type: IP (0x0800)
-            6,    // Hardware size: 6
-            4,    // Protocol size: 4
-            0, 1  // Opcode: request (1)
-    };
-    private static final byte[] ARP_IPV4_REPLY_HEADER = {
-            0, 1, // Hardware type: Ethernet (1)
-            8, 0, // Protocol type: IP (0x0800)
-            6,    // Hardware size: 6
-            4,    // Protocol size: 4
-            0, 2  // Opcode: reply (2)
-    };
-    private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
-    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
-
-    private static final byte[] MOCK_IPV4_ADDR           = {10, 0, 0, 1};
-    private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19
-    private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1};
-    private static final byte[] ANOTHER_IPV4_ADDR        = {10, 0, 0, 2};
-    private static final byte[] IPV4_SOURCE_ADDR         = {10, 0, 0, 3};
-    private static final byte[] ANOTHER_IPV4_SOURCE_ADDR = {(byte) 192, 0, 2, 1};
-    private static final byte[] BUG_PROBE_SOURCE_ADDR1   = {0, 0, 1, 2};
-    private static final byte[] BUG_PROBE_SOURCE_ADDR2   = {3, 4, 0, 0};
-    private static final byte[] IPV4_ANY_HOST_ADDR       = {0, 0, 0, 0};
-
-    // Helper to initialize a default apfFilter.
-    private ApfFilter setupApfFilter(IpClient.Callback ipClientCallback, ApfConfiguration config)
-            throws Exception {
-        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
-        LinkProperties lp = new LinkProperties();
-        lp.addLinkAddress(link);
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        apfFilter.setLinkProperties(lp);
-        return apfFilter;
-    }
-
-    @Test
-    public void testApfFilterIPv4() throws Exception {
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
-        LinkProperties lp = new LinkProperties();
-        lp.addLinkAddress(link);
-
-        ApfConfiguration config = getDefaultConfig();
-        config.multicastFilter = DROP_MULTICAST;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        apfFilter.setLinkProperties(lp);
-
-        byte[] program = ipClientCallback.getApfProgram();
-
-        // Verify empty packet of 100 zero bytes is passed
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        assertPass(program, packet.array());
-
-        // Verify unicast IPv4 packet is passed
-        put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR);
-        assertPass(program, packet.array());
-
-        // Verify L2 unicast to IPv4 broadcast addresses is dropped (b/30231088)
-        put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
-        assertDrop(program, packet.array());
-        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
-        assertDrop(program, packet.array());
-
-        // Verify multicast/broadcast IPv4, not DHCP to us, is dropped
-        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
-        assertDrop(program, packet.array());
-        packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
-        assertDrop(program, packet.array());
-        packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
-        assertDrop(program, packet.array());
-        packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
-        assertDrop(program, packet.array());
-        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_MULTICAST_IPV4_ADDR);
-        assertDrop(program, packet.array());
-        put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
-        assertDrop(program, packet.array());
-        put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
-        assertDrop(program, packet.array());
-
-        // Verify broadcast IPv4 DHCP to us is passed
-        put(packet, DHCP_CLIENT_MAC_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
-        assertPass(program, packet.array());
-
-        // Verify unicast IPv4 DHCP to us is passed
-        put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
-        assertPass(program, packet.array());
-
-        apfFilter.shutdown();
-    }
-
-    @Test
-    public void testApfFilterIPv6() throws Exception {
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        byte[] program = ipClientCallback.getApfProgram();
-
-        // Verify empty IPv6 packet is passed
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        assertPass(program, packet.array());
-
-        // Verify empty ICMPv6 packet is passed
-        packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
-        assertPass(program, packet.array());
-
-        // Verify empty ICMPv6 NA packet is passed
-        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
-        assertPass(program, packet.array());
-
-        // Verify ICMPv6 NA to ff02::1 is dropped
-        put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
-        assertDrop(program, packet.array());
-
-        // Verify ICMPv6 RS to any is dropped
-        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION);
-        assertDrop(program, packet.array());
-        put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS);
-        assertDrop(program, packet.array());
-
-        apfFilter.shutdown();
-    }
-
-    @Test
-    public void testApfFilterMulticast() throws Exception {
-        final byte[] unicastIpv4Addr   = {(byte)192,0,2,63};
-        final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
-        final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
-        final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
-
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
-        LinkProperties lp = new LinkProperties();
-        lp.addLinkAddress(link);
-
-        ApfConfiguration config = getDefaultConfig();
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        apfFilter.setLinkProperties(lp);
-
-        byte[] program = ipClientCallback.getApfProgram();
-
-        // Construct IPv4 and IPv6 multicast packets.
-        ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
-        mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
-
-        ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
-        mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
-        put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
-
-        // Construct IPv4 broadcast packet.
-        ByteBuffer bcastv4packet1 = ByteBuffer.wrap(new byte[100]);
-        bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS);
-        bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
-
-        ByteBuffer bcastv4packet2 = ByteBuffer.wrap(new byte[100]);
-        bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS);
-        bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
-
-        // Construct IPv4 broadcast with L2 unicast address packet (b/30231088).
-        ByteBuffer bcastv4unicastl2packet = ByteBuffer.wrap(new byte[100]);
-        bcastv4unicastl2packet.put(TestApfFilter.MOCK_MAC_ADDR);
-        bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr);
-
-        // Verify initially disabled multicast filter is off
-        assertPass(program, mcastv4packet.array());
-        assertPass(program, mcastv6packet.array());
-        assertPass(program, bcastv4packet1.array());
-        assertPass(program, bcastv4packet2.array());
-        assertPass(program, bcastv4unicastl2packet.array());
-
-        // Turn on multicast filter and verify it works
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.setMulticastFilter(true);
-        program = ipClientCallback.getApfProgram();
-        assertDrop(program, mcastv4packet.array());
-        assertDrop(program, mcastv6packet.array());
-        assertDrop(program, bcastv4packet1.array());
-        assertDrop(program, bcastv4packet2.array());
-        assertDrop(program, bcastv4unicastl2packet.array());
-
-        // Turn off multicast filter and verify it's off
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.setMulticastFilter(false);
-        program = ipClientCallback.getApfProgram();
-        assertPass(program, mcastv4packet.array());
-        assertPass(program, mcastv6packet.array());
-        assertPass(program, bcastv4packet1.array());
-        assertPass(program, bcastv4packet2.array());
-        assertPass(program, bcastv4unicastl2packet.array());
-
-        // Verify it can be initialized to on
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.shutdown();
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        apfFilter.setLinkProperties(lp);
-        program = ipClientCallback.getApfProgram();
-        assertDrop(program, mcastv4packet.array());
-        assertDrop(program, mcastv6packet.array());
-        assertDrop(program, bcastv4packet1.array());
-        assertDrop(program, bcastv4unicastl2packet.array());
-
-        // Verify that ICMPv6 multicast is not dropped.
-        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
-        assertPass(program, mcastv6packet.array());
-
-        apfFilter.shutdown();
-    }
-
-    @Test
-    public void testApfFilterMulticastPingWhileDozing() throws Exception {
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        ApfFilter apfFilter = setupApfFilter(ipClientCallback, getDefaultConfig());
-
-        // Construct a multicast ICMPv6 ECHO request.
-        final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
-        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ECHO_REQUEST_TYPE);
-        put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
-
-        // Normally, we let multicast pings alone...
-        assertPass(ipClientCallback.getApfProgram(), packet.array());
-
-        // ...and even while dozing...
-        apfFilter.setDozeMode(true);
-        assertPass(ipClientCallback.getApfProgram(), packet.array());
-
-        // ...but when the multicast filter is also enabled, drop the multicast pings to save power.
-        apfFilter.setMulticastFilter(true);
-        assertDrop(ipClientCallback.getApfProgram(), packet.array());
-
-        // However, we should still let through all other ICMPv6 types.
-        ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone());
-        raPacket.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ROUTER_ADVERTISEMENT);
-        assertPass(ipClientCallback.getApfProgram(), raPacket.array());
-
-        // Now wake up from doze mode to ensure that we no longer drop the packets.
-        // (The multicast filter is still enabled at this point).
-        apfFilter.setDozeMode(false);
-        assertPass(ipClientCallback.getApfProgram(), packet.array());
-
-        apfFilter.shutdown();
-    }
-
-    @Test
-    public void testApfFilter802_3() throws Exception {
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
-        byte[] program = ipClientCallback.getApfProgram();
-
-        // Verify empty packet of 100 zero bytes is passed
-        // Note that eth-type = 0 makes it an IEEE802.3 frame
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        assertPass(program, packet.array());
-
-        // Verify empty packet with IPv4 is passed
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        assertPass(program, packet.array());
-
-        // Verify empty IPv6 packet is passed
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        assertPass(program, packet.array());
-
-        // Now turn on the filter
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.shutdown();
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        apfFilter = setupApfFilter(ipClientCallback, config);
-        program = ipClientCallback.getApfProgram();
-
-        // Verify that IEEE802.3 frame is dropped
-        // In this case ethtype is used for payload length
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)(100 - 14));
-        assertDrop(program, packet.array());
-
-        // Verify that IPv4 (as example of Ethernet II) frame will pass
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        assertPass(program, packet.array());
-
-        // Verify that IPv6 (as example of Ethernet II) frame will pass
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        assertPass(program, packet.array());
-
-        apfFilter.shutdown();
-    }
-
-    @Test
-    public void testApfFilterEthTypeBL() throws Exception {
-        final int[] emptyBlackList = {};
-        final int[] ipv4BlackList = {ETH_P_IP};
-        final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
-
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
-        byte[] program = ipClientCallback.getApfProgram();
-
-        // Verify empty packet of 100 zero bytes is passed
-        // Note that eth-type = 0 makes it an IEEE802.3 frame
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        assertPass(program, packet.array());
-
-        // Verify empty packet with IPv4 is passed
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        assertPass(program, packet.array());
-
-        // Verify empty IPv6 packet is passed
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        assertPass(program, packet.array());
-
-        // Now add IPv4 to the black list
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.shutdown();
-        config.ethTypeBlackList = ipv4BlackList;
-        apfFilter = setupApfFilter(ipClientCallback, config);
-        program = ipClientCallback.getApfProgram();
-
-        // Verify that IPv4 frame will be dropped
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        assertDrop(program, packet.array());
-
-        // Verify that IPv6 frame will pass
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        assertPass(program, packet.array());
-
-        // Now let us have both IPv4 and IPv6 in the black list
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.shutdown();
-        config.ethTypeBlackList = ipv4Ipv6BlackList;
-        apfFilter = setupApfFilter(ipClientCallback, config);
-        program = ipClientCallback.getApfProgram();
-
-        // Verify that IPv4 frame will be dropped
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
-        assertDrop(program, packet.array());
-
-        // Verify that IPv6 frame will be dropped
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        assertDrop(program, packet.array());
-
-        apfFilter.shutdown();
-    }
-
-    private byte[] getProgram(MockIpClientCallback cb, ApfFilter filter, LinkProperties lp) {
-        cb.resetApfProgramWait();
-        filter.setLinkProperties(lp);
-        return cb.getApfProgram();
-    }
-
-    private void verifyArpFilter(byte[] program, int filterResult) {
-        // Verify ARP request packet
-        assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR));
-        assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR));
-        assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR));
-
-        // Verify ARP reply packets from different source ip
-        assertDrop(program, arpReply(IPV4_ANY_HOST_ADDR, IPV4_ANY_HOST_ADDR));
-        assertPass(program, arpReply(ANOTHER_IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
-        assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR1, IPV4_ANY_HOST_ADDR));
-        assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR2, IPV4_ANY_HOST_ADDR));
-
-        // Verify unicast ARP reply packet is always accepted.
-        assertPass(program, arpReply(IPV4_SOURCE_ADDR, MOCK_IPV4_ADDR));
-        assertPass(program, arpReply(IPV4_SOURCE_ADDR, ANOTHER_IPV4_ADDR));
-        assertPass(program, arpReply(IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
-
-        // Verify GARP reply packets are always filtered
-        assertDrop(program, garpReply());
-    }
-
-    @Test
-    public void testApfFilterArp() throws Exception {
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-
-        // Verify initially ARP request filter is off, and GARP filter is on.
-        verifyArpFilter(ipClientCallback.getApfProgram(), PASS);
-
-        // Inform ApfFilter of our address and verify ARP filtering is on
-        LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24);
-        LinkProperties lp = new LinkProperties();
-        assertTrue(lp.addLinkAddress(linkAddress));
-        verifyArpFilter(getProgram(ipClientCallback, apfFilter, lp), DROP);
-
-        // Inform ApfFilter of loss of IP and verify ARP filtering is off
-        verifyArpFilter(getProgram(ipClientCallback, apfFilter, new LinkProperties()), PASS);
-
-        apfFilter.shutdown();
-    }
-
-    private static byte[] arpReply(byte[] sip, byte[] tip) {
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
-        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
-        put(packet, ARP_SOURCE_IP_ADDRESS_OFFSET, sip);
-        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
-        return packet.array();
-    }
-
-    private static byte[] arpRequestBroadcast(byte[] tip) {
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
-        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
-        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REQUEST_HEADER);
-        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
-        return packet.array();
-    }
-
-    private static byte[] garpReply() {
-        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
-        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
-        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
-        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
-        put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR);
-        return packet.array();
-    }
-
-    // Verify that the last program pushed to the IpClient.Callback properly filters the
-    // given packet for the given lifetime.
-    private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) {
-        final int FRACTION_OF_LIFETIME = 6;
-        final int ageLimit = lifetime / FRACTION_OF_LIFETIME;
-
-        // Verify new program should drop RA for 1/6th its lifetime and pass afterwards.
-        assertDrop(program, packet.array());
-        assertDrop(program, packet.array(), ageLimit);
-        assertPass(program, packet.array(), ageLimit + 1);
-        assertPass(program, packet.array(), lifetime);
-        // Verify RA checksum is ignored
-        final short originalChecksum = packet.getShort(ICMP6_RA_CHECKSUM_OFFSET);
-        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
-        assertDrop(program, packet.array());
-        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
-        assertDrop(program, packet.array());
-        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, originalChecksum);
-
-        // Verify other changes to RA make it not match filter
-        final byte originalFirstByte = packet.get(0);
-        packet.put(0, (byte)-1);
-        assertPass(program, packet.array());
-        packet.put(0, (byte)0);
-        assertDrop(program, packet.array());
-        packet.put(0, originalFirstByte);
-    }
-
-    // Test that when ApfFilter is shown the given packet, it generates a program to filter it
-    // for the given lifetime.
-    private void verifyRaLifetime(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
-            ByteBuffer packet, int lifetime) throws IOException, ErrnoException {
-        // Verify new program generated if ApfFilter witnesses RA
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.pretendPacketReceived(packet.array());
-        byte[] program = ipClientCallback.getApfProgram();
-        verifyRaLifetime(program, packet, lifetime);
-    }
-
-    private void verifyRaEvent(RaEvent expected) {
-        ArgumentCaptor<Parcelable> captor = ArgumentCaptor.forClass(Parcelable.class);
-        verify(mLog, atLeastOnce()).log(captor.capture());
-        RaEvent got = lastRaEvent(captor.getAllValues());
-        if (!raEventEquals(expected, got)) {
-            assertEquals(expected, got);  // fail for printing an assertion error message.
-        }
-    }
-
-    private RaEvent lastRaEvent(List<Parcelable> events) {
-        RaEvent got = null;
-        for (Parcelable ev : events) {
-            if (ev instanceof RaEvent) {
-                got = (RaEvent) ev;
-            }
-        }
-        return got;
-    }
-
-    private boolean raEventEquals(RaEvent ev1, RaEvent ev2) {
-        return (ev1 != null) && (ev2 != null)
-                && (ev1.routerLifetime == ev2.routerLifetime)
-                && (ev1.prefixValidLifetime == ev2.prefixValidLifetime)
-                && (ev1.prefixPreferredLifetime == ev2.prefixPreferredLifetime)
-                && (ev1.routeInfoLifetime == ev2.routeInfoLifetime)
-                && (ev1.rdnssLifetime == ev2.rdnssLifetime)
-                && (ev1.dnsslLifetime == ev2.dnsslLifetime);
-    }
-
-    private void assertInvalidRa(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
-            ByteBuffer packet) throws IOException, ErrnoException {
-        ipClientCallback.resetApfProgramWait();
-        apfFilter.pretendPacketReceived(packet.array());
-        ipClientCallback.assertNoProgramUpdate();
-    }
-
-    @Test
-    public void testApfFilterRa() throws Exception {
-        MockIpClientCallback ipClientCallback = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-        byte[] program = ipClientCallback.getApfProgram();
-
-        final int ROUTER_LIFETIME = 1000;
-        final int PREFIX_VALID_LIFETIME = 200;
-        final int PREFIX_PREFERRED_LIFETIME = 100;
-        final int RDNSS_LIFETIME  = 300;
-        final int ROUTE_LIFETIME  = 400;
-        // Note that lifetime of 2000 will be ignored in favor of shorter route lifetime of 1000.
-        final int DNSSL_LIFETIME  = 2000;
-        final int VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET = ETH_HEADER_LEN;
-        // IPv6, traffic class = 0, flow label = 0x12345
-        final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345;
-
-        // Verify RA is passed the first time
-        ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
-        basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
-        basePacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
-                VERSION_TRAFFIC_CLASS_FLOW_LABEL);
-        basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
-        basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
-        basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)ROUTER_LIFETIME);
-        basePacket.position(IPV6_DEST_ADDR_OFFSET);
-        basePacket.put(IPV6_ALL_NODES_ADDRESS);
-        assertPass(program, basePacket.array());
-
-        verifyRaLifetime(apfFilter, ipClientCallback, basePacket, ROUTER_LIFETIME);
-        verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1));
-
-        ByteBuffer newFlowLabelPacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
-        basePacket.clear();
-        newFlowLabelPacket.put(basePacket);
-        // Check that changes are ignored in every byte of the flow label.
-        newFlowLabelPacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
-                VERSION_TRAFFIC_CLASS_FLOW_LABEL + 0x11111);
-
-        // Ensure zero-length options cause the packet to be silently skipped.
-        // Do this before we test other packets. http://b/29586253
-        ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap(
-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
-        basePacket.clear();
-        zeroLengthOptionPacket.put(basePacket);
-        zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
-        zeroLengthOptionPacket.put((byte)0);
-        assertInvalidRa(apfFilter, ipClientCallback, zeroLengthOptionPacket);
-
-        // Generate several RAs with different options and lifetimes, and verify when
-        // ApfFilter is shown these packets, it generates programs to filter them for the
-        // appropriate lifetime.
-        ByteBuffer prefixOptionPacket = ByteBuffer.wrap(
-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_LEN]);
-        basePacket.clear();
-        prefixOptionPacket.put(basePacket);
-        prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
-        prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8));
-        prefixOptionPacket.putInt(
-                ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
-                PREFIX_PREFERRED_LIFETIME);
-        prefixOptionPacket.putInt(
-                ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
-                PREFIX_VALID_LIFETIME);
-        verifyRaLifetime(
-                apfFilter, ipClientCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
-        verifyRaEvent(new RaEvent(
-                ROUTER_LIFETIME, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, -1, -1, -1));
-
-        ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(
-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
-        basePacket.clear();
-        rdnssOptionPacket.put(basePacket);
-        rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE);
-        rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
-        rdnssOptionPacket.putInt(
-                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, RDNSS_LIFETIME);
-        verifyRaLifetime(apfFilter, ipClientCallback, rdnssOptionPacket, RDNSS_LIFETIME);
-        verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1));
-
-        ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
-        basePacket.clear();
-        routeInfoOptionPacket.put(basePacket);
-        routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE);
-        routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
-        routeInfoOptionPacket.putInt(
-                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, ROUTE_LIFETIME);
-        verifyRaLifetime(apfFilter, ipClientCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
-        verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1));
-
-        ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
-                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
-        basePacket.clear();
-        dnsslOptionPacket.put(basePacket);
-        dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE);
-        dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
-        dnsslOptionPacket.putInt(
-                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, DNSSL_LIFETIME);
-        verifyRaLifetime(apfFilter, ipClientCallback, dnsslOptionPacket, ROUTER_LIFETIME);
-        verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, DNSSL_LIFETIME));
-
-        // Verify that current program filters all five RAs:
-        program = ipClientCallback.getApfProgram();
-        verifyRaLifetime(program, basePacket, ROUTER_LIFETIME);
-        verifyRaLifetime(program, newFlowLabelPacket, ROUTER_LIFETIME);
-        verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
-        verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME);
-        verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME);
-        verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME);
-
-        apfFilter.shutdown();
-    }
-
-    /**
-     * Stage a file for testing, i.e. make it native accessible. Given a resource ID,
-     * copy that resource into the app's data directory and return the path to it.
-     */
-    private String stageFile(int rawId) throws Exception {
-        File file = new File(InstrumentationRegistry.getContext().getFilesDir(), "staged_file");
-        new File(file.getParent()).mkdirs();
-        InputStream in = null;
-        OutputStream out = null;
-        try {
-            in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
-            out = new FileOutputStream(file);
-            Streams.copy(in, out);
-        } finally {
-            if (in != null) in.close();
-            if (out != null) out.close();
-        }
-        return file.getAbsolutePath();
-    }
-
-    private static void put(ByteBuffer buffer, int position, byte[] bytes) {
-        final int original = buffer.position();
-        buffer.position(position);
-        buffer.put(bytes);
-        buffer.position(original);
-    }
-
-    @Test
-    public void testRaParsing() throws Exception {
-        final int maxRandomPacketSize = 512;
-        final Random r = new Random();
-        MockIpClientCallback cb = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
-        for (int i = 0; i < 1000; i++) {
-            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
-            r.nextBytes(packet);
-            try {
-                apfFilter.new Ra(packet, packet.length);
-            } catch (ApfFilter.InvalidRaException e) {
-            } catch (Exception e) {
-                throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
-            }
-        }
-    }
-
-    @Test
-    public void testRaProcessing() throws Exception {
-        final int maxRandomPacketSize = 512;
-        final Random r = new Random();
-        MockIpClientCallback cb = new MockIpClientCallback();
-        ApfConfiguration config = getDefaultConfig();
-        config.multicastFilter = DROP_MULTICAST;
-        config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
-        for (int i = 0; i < 1000; i++) {
-            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
-            r.nextBytes(packet);
-            try {
-                apfFilter.processRa(packet, packet.length);
-            } catch (Exception e) {
-                throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
-            }
-        }
-    }
-
-    /**
-     * Call the APF interpreter to run {@code program} on {@code packet} with persistent memory
-     * segment {@data} pretending the filter was installed {@code filter_age} seconds ago.
-     */
-    private native static int apfSimulate(byte[] program, byte[] packet, byte[] data,
-        int filter_age);
-
-    /**
-     * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF
-     * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d".
-     */
-    private native static String compileToBpf(String filter);
-
-    /**
-     * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump
-     * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and
-     * at the same time using APF program {@code apf_program}.  Return {@code true} if
-     * both APF and BPF programs filter out exactly the same packets.
-     */
-    private native static boolean compareBpfApf(String filter, String pcap_filename,
-            byte[] apf_program);
-
-
-    /**
-     * Open packet capture file {@code pcapFilename} and run it through APF filter. Then
-     * checks whether all the packets are dropped and populates data[] {@code data} with
-     * the APF counters.
-     */
-    private native static boolean dropsAllPackets(byte[] program, byte[] data, String pcapFilename);
-
-    @Test
-    public void testBroadcastAddress() throws Exception {
-        assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
-        assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32));
-        assertEqualsIp("0.0.3.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 22));
-        assertEqualsIp("0.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 8));
-
-        assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 0));
-        assertEqualsIp("10.0.0.1", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 32));
-        assertEqualsIp("10.0.0.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 24));
-        assertEqualsIp("10.0.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 16));
-    }
-
-    public void assertEqualsIp(String expected, int got) throws Exception {
-        int want = bytesToBEInt(InetAddress.getByName(expected).getAddress());
-        assertEquals(want, got);
-    }
-}
diff --git a/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java b/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java
deleted file mode 100644
index 7f8e7b5..0000000
--- a/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java
+++ /dev/null
@@ -1,539 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dhcp;
-
-import static android.net.dhcp.DhcpLease.HOSTNAME_NONE;
-import static android.net.dhcp.DhcpLeaseRepository.CLIENTID_UNSPEC;
-import static android.net.dhcp.DhcpLeaseRepository.INETADDR_UNSPEC;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.when;
-
-import static java.lang.String.format;
-import static java.net.InetAddress.parseNumericAddress;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.IpPrefix;
-import android.net.MacAddress;
-import android.net.util.SharedLog;
-import android.net.dhcp.DhcpServer.Clock;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.net.Inet4Address;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DhcpLeaseRepositoryTest {
-    private static final Inet4Address INET4_ANY = (Inet4Address) Inet4Address.ANY;
-    private static final Inet4Address TEST_DEF_ROUTER = parseAddr4("192.168.42.247");
-    private static final Inet4Address TEST_SERVER_ADDR = parseAddr4("192.168.42.241");
-    private static final Inet4Address TEST_RESERVED_ADDR = parseAddr4("192.168.42.243");
-    private static final MacAddress TEST_MAC_1 = MacAddress.fromBytes(
-            new byte[] { 5, 4, 3, 2, 1, 0 });
-    private static final MacAddress TEST_MAC_2 = MacAddress.fromBytes(
-            new byte[] { 0, 1, 2, 3, 4, 5 });
-    private static final MacAddress TEST_MAC_3 = MacAddress.fromBytes(
-            new byte[] { 0, 1, 2, 3, 4, 6 });
-    private static final Inet4Address TEST_INETADDR_1 = parseAddr4("192.168.42.248");
-    private static final Inet4Address TEST_INETADDR_2 = parseAddr4("192.168.42.249");
-    private static final String TEST_HOSTNAME_1 = "hostname1";
-    private static final String TEST_HOSTNAME_2 = "hostname2";
-    private static final IpPrefix TEST_IP_PREFIX = new IpPrefix(TEST_SERVER_ADDR, 22);
-    private static final long TEST_TIME = 100L;
-    private static final int TEST_LEASE_TIME_MS = 3_600_000;
-    private static final Set<Inet4Address> TEST_EXCL_SET =
-            Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
-                TEST_SERVER_ADDR, TEST_DEF_ROUTER, TEST_RESERVED_ADDR)));
-
-    @NonNull
-    private SharedLog mLog;
-    @NonNull @Mock
-    private Clock mClock;
-    @NonNull
-    private DhcpLeaseRepository mRepo;
-
-    private static Inet4Address parseAddr4(String inet4Addr) {
-        return (Inet4Address) parseNumericAddress(inet4Addr);
-    }
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mLog = new SharedLog("DhcpLeaseRepositoryTest");
-        when(mClock.elapsedRealtime()).thenReturn(TEST_TIME);
-        mRepo = new DhcpLeaseRepository(
-                TEST_IP_PREFIX, TEST_EXCL_SET, TEST_LEASE_TIME_MS, mLog, mClock);
-    }
-
-    /**
-     * Request a number of addresses through offer/request. Useful to test address exhaustion.
-     * @param nAddr Number of addresses to request.
-     */
-    private void requestAddresses(byte nAddr) throws Exception {
-        final HashSet<Inet4Address> addrs = new HashSet<>();
-        byte[] hwAddrBytes = new byte[] { 8, 4, 3, 2, 1, 0 };
-        for (byte i = 0; i < nAddr; i++) {
-            hwAddrBytes[5] = i;
-            MacAddress newMac = MacAddress.fromBytes(hwAddrBytes);
-            final String hostname = "host_" + i;
-            final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, newMac,
-                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, hostname);
-
-            assertNotNull(lease);
-            assertEquals(newMac, lease.getHwAddr());
-            assertEquals(hostname, lease.getHostname());
-            assertTrue(format("Duplicate address allocated: %s in %s", lease.getNetAddr(), addrs),
-                    addrs.add(lease.getNetAddr()));
-
-            requestLeaseSelecting(newMac, lease.getNetAddr(), hostname);
-        }
-    }
-
-    @Test
-    public void testAddressExhaustion() throws Exception {
-        // Use a /28 to quickly run out of addresses
-        mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), TEST_EXCL_SET, TEST_LEASE_TIME_MS);
-
-        // /28 should have 16 addresses, 14 w/o the first/last, 11 w/o excluded addresses
-        requestAddresses((byte)11);
-
-        try {
-            mRepo.getOffer(null, TEST_MAC_2,
-                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-            fail("Should be out of addresses");
-        } catch (DhcpLeaseRepository.OutOfAddressesException e) {
-            // Expected
-        }
-    }
-
-    @Test
-    public void testUpdateParams_LeaseCleanup() throws Exception {
-        // Inside /28:
-        final Inet4Address reqAddrIn28 = parseAddr4("192.168.42.242");
-        final Inet4Address declinedAddrIn28 = parseAddr4("192.168.42.245");
-
-        // Inside /28, but not available there (first address of the range)
-        final Inet4Address declinedFirstAddrIn28 = parseAddr4("192.168.42.240");
-
-        final DhcpLease reqAddrIn28Lease = requestLeaseSelecting(TEST_MAC_1, reqAddrIn28);
-        mRepo.markLeaseDeclined(declinedAddrIn28);
-        mRepo.markLeaseDeclined(declinedFirstAddrIn28);
-
-        // Inside /22, but outside /28:
-        final Inet4Address reqAddrIn22 = parseAddr4("192.168.42.3");
-        final Inet4Address declinedAddrIn22 = parseAddr4("192.168.42.4");
-
-        final DhcpLease reqAddrIn22Lease = requestLeaseSelecting(TEST_MAC_3, reqAddrIn22);
-        mRepo.markLeaseDeclined(declinedAddrIn22);
-
-        // Address that will be reserved in the updateParams call below
-        final Inet4Address reservedAddr = parseAddr4("192.168.42.244");
-        final DhcpLease reservedAddrLease = requestLeaseSelecting(TEST_MAC_2, reservedAddr);
-
-        // Update from /22 to /28 and add another reserved address
-        Set<Inet4Address> newReserved = new HashSet<>(TEST_EXCL_SET);
-        newReserved.add(reservedAddr);
-        mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), newReserved, TEST_LEASE_TIME_MS);
-
-        assertHasLease(reqAddrIn28Lease);
-        assertDeclined(declinedAddrIn28);
-
-        assertNotDeclined(declinedFirstAddrIn28);
-
-        assertNoLease(reqAddrIn22Lease);
-        assertNotDeclined(declinedAddrIn22);
-
-        assertNoLease(reservedAddrLease);
-    }
-
-    @Test
-    public void testGetOffer_StableAddress() throws Exception {
-        for (final MacAddress macAddr : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) {
-            final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr,
-                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-
-            // Same lease is offered twice
-            final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr,
-                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-            assertEquals(lease, newLease);
-        }
-    }
-
-    @Test
-    public void testUpdateParams_UsesNewPrefix() throws Exception {
-        final IpPrefix newPrefix = new IpPrefix(parseAddr4("192.168.123.0"), 24);
-        mRepo.updateParams(newPrefix, TEST_EXCL_SET, TEST_LEASE_TIME_MS);
-
-        DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-        assertTrue(newPrefix.contains(lease.getNetAddr()));
-    }
-
-    @Test
-    public void testGetOffer_ExistingLease() throws Exception {
-        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1, TEST_HOSTNAME_1);
-
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-        assertEquals(TEST_INETADDR_1, offer.getNetAddr());
-        assertEquals(TEST_HOSTNAME_1, offer.getHostname());
-    }
-
-    @Test
-    public void testGetOffer_ClientIdHasExistingLease() throws Exception {
-        final byte[] clientId = new byte[] { 1, 2 };
-        mRepo.requestLease(clientId, TEST_MAC_1, INET4_ANY /* clientAddr */,
-                INET4_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false, TEST_HOSTNAME_1);
-
-        // Different MAC, but same clientId
-        DhcpLease offer = mRepo.getOffer(clientId, TEST_MAC_2,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-        assertEquals(TEST_INETADDR_1, offer.getNetAddr());
-        assertEquals(TEST_HOSTNAME_1, offer.getHostname());
-    }
-
-    @Test
-    public void testGetOffer_DifferentClientId() throws Exception {
-        final byte[] clientId1 = new byte[] { 1, 2 };
-        final byte[] clientId2 = new byte[] { 3, 4 };
-        mRepo.requestLease(clientId1, TEST_MAC_1, INET4_ANY /* clientAddr */,
-                INET4_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false, TEST_HOSTNAME_1);
-
-        // Same MAC, different client ID
-        DhcpLease offer = mRepo.getOffer(clientId2, TEST_MAC_1,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-        // Obtains a different address
-        assertNotEquals(TEST_INETADDR_1, offer.getNetAddr());
-        assertEquals(HOSTNAME_NONE, offer.getHostname());
-        assertEquals(TEST_MAC_1, offer.getHwAddr());
-    }
-
-    @Test
-    public void testGetOffer_RequestedAddress() throws Exception {
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
-                TEST_INETADDR_1 /* reqAddr */, TEST_HOSTNAME_1);
-        assertEquals(TEST_INETADDR_1, offer.getNetAddr());
-        assertEquals(TEST_HOSTNAME_1, offer.getHostname());
-    }
-
-    @Test
-    public void testGetOffer_RequestedAddressInUse() throws Exception {
-        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2, INET4_ANY /* relayAddr */,
-                TEST_INETADDR_1 /* reqAddr */, HOSTNAME_NONE);
-        assertNotEquals(TEST_INETADDR_1, offer.getNetAddr());
-    }
-
-    @Test
-    public void testGetOffer_RequestedAddressReserved() throws Exception {
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
-                TEST_RESERVED_ADDR /* reqAddr */, HOSTNAME_NONE);
-        assertNotEquals(TEST_RESERVED_ADDR, offer.getNetAddr());
-    }
-
-    @Test
-    public void testGetOffer_RequestedAddressInvalid() throws Exception {
-        final Inet4Address invalidAddr = parseAddr4("192.168.42.0");
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
-                invalidAddr /* reqAddr */, HOSTNAME_NONE);
-        assertNotEquals(invalidAddr, offer.getNetAddr());
-    }
-
-    @Test
-    public void testGetOffer_RequestedAddressOutsideSubnet() throws Exception {
-        final Inet4Address invalidAddr = parseAddr4("192.168.254.2");
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
-                invalidAddr /* reqAddr */, HOSTNAME_NONE);
-        assertNotEquals(invalidAddr, offer.getNetAddr());
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidSubnetException.class)
-    public void testGetOffer_RelayInInvalidSubnet() throws Exception {
-        mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, parseAddr4("192.168.254.2") /* relayAddr */,
-                INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-    }
-
-    @Test
-    public void testRequestLease_SelectingTwice() throws Exception {
-        final DhcpLease lease1 = requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1,
-                TEST_HOSTNAME_1);
-
-        // Second request from same client for a different address
-        final DhcpLease lease2 = requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_2,
-                TEST_HOSTNAME_2);
-
-        assertEquals(TEST_INETADDR_1, lease1.getNetAddr());
-        assertEquals(TEST_HOSTNAME_1, lease1.getHostname());
-
-        assertEquals(TEST_INETADDR_2, lease2.getNetAddr());
-        assertEquals(TEST_HOSTNAME_2, lease2.getHostname());
-
-        // First address freed when client requested a different one: another client can request it
-        final DhcpLease lease3 = requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1, HOSTNAME_NONE);
-        assertEquals(TEST_INETADDR_1, lease3.getNetAddr());
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_SelectingInvalid() throws Exception {
-        requestLeaseSelecting(TEST_MAC_1, parseAddr4("192.168.254.5"));
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_SelectingInUse() throws Exception {
-        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-        requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1);
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_SelectingReserved() throws Exception {
-        requestLeaseSelecting(TEST_MAC_1, TEST_RESERVED_ADDR);
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidSubnetException.class)
-    public void testRequestLease_SelectingRelayInInvalidSubnet() throws  Exception {
-        mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* clientAddr */,
-                parseAddr4("192.168.128.1") /* relayAddr */, TEST_INETADDR_1 /* reqAddr */,
-                true /* sidSet */, HOSTNAME_NONE);
-    }
-
-    @Test
-    public void testRequestLease_InitReboot() throws Exception {
-        // Request address once
-        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-
-        final long newTime = TEST_TIME + 100;
-        when(mClock.elapsedRealtime()).thenReturn(newTime);
-
-        // init-reboot (sidSet == false): verify configuration
-        final DhcpLease lease = requestLeaseInitReboot(TEST_MAC_1, TEST_INETADDR_1);
-        assertEquals(TEST_INETADDR_1, lease.getNetAddr());
-        assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime());
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_InitRebootWrongAddr() throws Exception {
-        // Request address once
-        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-        // init-reboot with different requested address
-        requestLeaseInitReboot(TEST_MAC_1, TEST_INETADDR_2);
-    }
-
-    @Test
-    public void testRequestLease_InitRebootUnknownAddr() throws Exception {
-        // init-reboot with unknown requested address
-        final DhcpLease lease = requestLeaseInitReboot(TEST_MAC_1, TEST_INETADDR_2);
-        // RFC2131 says we should not reply to accommodate other servers, but since we are
-        // authoritative we allow creating the lease to avoid issues with lost lease DB (same as
-        // dnsmasq behavior)
-        assertEquals(TEST_INETADDR_2, lease.getNetAddr());
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_InitRebootWrongSubnet() throws Exception {
-        requestLeaseInitReboot(TEST_MAC_1, parseAddr4("192.168.254.2"));
-    }
-
-    @Test
-    public void testRequestLease_Renewing() throws Exception {
-        requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-
-        final long newTime = TEST_TIME + 100;
-        when(mClock.elapsedRealtime()).thenReturn(newTime);
-
-        final DhcpLease lease = requestLeaseRenewing(TEST_MAC_1, TEST_INETADDR_1);
-
-        assertEquals(TEST_INETADDR_1, lease.getNetAddr());
-        assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime());
-    }
-
-    @Test
-    public void testRequestLease_RenewingUnknownAddr() throws Exception {
-        final long newTime = TEST_TIME + 100;
-        when(mClock.elapsedRealtime()).thenReturn(newTime);
-        final DhcpLease lease = requestLeaseRenewing(TEST_MAC_1, TEST_INETADDR_1);
-        // Allows renewing an unknown address if available
-        assertEquals(TEST_INETADDR_1, lease.getNetAddr());
-        assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime());
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_RenewingAddrInUse() throws Exception {
-        requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1);
-        requestLeaseRenewing(TEST_MAC_1, TEST_INETADDR_1);
-    }
-
-    @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
-    public void testRequestLease_RenewingInvalidAddr() throws Exception {
-        requestLeaseRenewing(TEST_MAC_1, parseAddr4("192.168.254.2"));
-    }
-
-    @Test
-    public void testReleaseLease() throws Exception {
-        final DhcpLease lease1 = requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-
-        assertHasLease(lease1);
-        assertTrue(mRepo.releaseLease(CLIENTID_UNSPEC, TEST_MAC_1, TEST_INETADDR_1));
-        assertNoLease(lease1);
-
-        final DhcpLease lease2 = requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1);
-        assertEquals(TEST_INETADDR_1, lease2.getNetAddr());
-    }
-
-    @Test
-    public void testReleaseLease_UnknownLease() {
-        assertFalse(mRepo.releaseLease(CLIENTID_UNSPEC, TEST_MAC_1, TEST_INETADDR_1));
-    }
-
-    @Test
-    public void testReleaseLease_StableOffer() throws Exception {
-        for (MacAddress mac : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) {
-            final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, mac,
-                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-
-            requestLeaseSelecting(mac, lease.getNetAddr());
-            mRepo.releaseLease(CLIENTID_UNSPEC, mac, lease.getNetAddr());
-
-            // Same lease is offered after it was released
-            final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, mac,
-                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-            assertEquals(lease.getNetAddr(), newLease.getNetAddr());
-        }
-    }
-
-    @Test
-    public void testMarkLeaseDeclined() throws Exception {
-        final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-
-        mRepo.markLeaseDeclined(lease.getNetAddr());
-
-        // Same lease is not offered again
-        final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-        assertNotEquals(lease.getNetAddr(), newLease.getNetAddr());
-    }
-
-    @Test
-    public void testMarkLeaseDeclined_UsedIfOutOfAddresses() throws Exception {
-        // Use a /28 to quickly run out of addresses
-        mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), TEST_EXCL_SET, TEST_LEASE_TIME_MS);
-
-        mRepo.markLeaseDeclined(TEST_INETADDR_1);
-        mRepo.markLeaseDeclined(TEST_INETADDR_2);
-
-        // /28 should have 16 addresses, 14 w/o the first/last, 11 w/o excluded addresses
-        requestAddresses((byte) 9);
-
-        // Last 2 addresses: addresses marked declined should be used
-        final DhcpLease firstLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_1);
-        requestLeaseSelecting(TEST_MAC_1, firstLease.getNetAddr());
-
-        final DhcpLease secondLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_2);
-        requestLeaseSelecting(TEST_MAC_2, secondLease.getNetAddr());
-
-        // Now out of addresses
-        try {
-            mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_3, INET4_ANY /* relayAddr */,
-                    INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-            fail("Repository should be out of addresses and throw");
-        } catch (DhcpLeaseRepository.OutOfAddressesException e) { /* expected */ }
-
-        assertEquals(TEST_INETADDR_1, firstLease.getNetAddr());
-        assertEquals(TEST_HOSTNAME_1, firstLease.getHostname());
-        assertEquals(TEST_INETADDR_2, secondLease.getNetAddr());
-        assertEquals(TEST_HOSTNAME_2, secondLease.getHostname());
-    }
-
-    private DhcpLease requestLease(@NonNull MacAddress macAddr, @NonNull Inet4Address clientAddr,
-            @Nullable Inet4Address reqAddr, @Nullable String hostname, boolean sidSet)
-            throws DhcpLeaseRepository.DhcpLeaseException {
-        return mRepo.requestLease(CLIENTID_UNSPEC, macAddr, clientAddr, INET4_ANY /* relayAddr */,
-                reqAddr, sidSet, hostname);
-    }
-
-    /**
-     * Request a lease simulating a client in the SELECTING state.
-     */
-    private DhcpLease requestLeaseSelecting(@NonNull MacAddress macAddr,
-            @NonNull Inet4Address reqAddr, @Nullable String hostname)
-            throws DhcpLeaseRepository.DhcpLeaseException {
-        return requestLease(macAddr, INET4_ANY /* clientAddr */, reqAddr, hostname,
-                true /* sidSet */);
-    }
-
-    /**
-     * Request a lease simulating a client in the SELECTING state.
-     */
-    private DhcpLease requestLeaseSelecting(@NonNull MacAddress macAddr,
-            @NonNull Inet4Address reqAddr) throws DhcpLeaseRepository.DhcpLeaseException {
-        return requestLeaseSelecting(macAddr, reqAddr, HOSTNAME_NONE);
-    }
-
-    /**
-     * Request a lease simulating a client in the INIT-REBOOT state.
-     */
-    private DhcpLease requestLeaseInitReboot(@NonNull MacAddress macAddr,
-            @NonNull Inet4Address reqAddr) throws DhcpLeaseRepository.DhcpLeaseException {
-        return requestLease(macAddr, INET4_ANY /* clientAddr */, reqAddr, HOSTNAME_NONE,
-                false /* sidSet */);
-    }
-
-    /**
-     * Request a lease simulating a client in the RENEWING state.
-     */
-    private DhcpLease requestLeaseRenewing(@NonNull MacAddress macAddr,
-            @NonNull Inet4Address clientAddr) throws DhcpLeaseRepository.DhcpLeaseException {
-        // Renewing: clientAddr filled in, no reqAddr
-        return requestLease(macAddr, clientAddr, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE,
-                true /* sidSet */);
-    }
-
-    private void assertNoLease(DhcpLease lease) {
-        assertFalse("Leases contain " + lease, mRepo.getCommittedLeases().contains(lease));
-    }
-
-    private void assertHasLease(DhcpLease lease) {
-        assertTrue("Leases do not contain " + lease, mRepo.getCommittedLeases().contains(lease));
-    }
-
-    private void assertNotDeclined(Inet4Address addr) {
-        assertFalse("Address is declined: " + addr, mRepo.getDeclinedAddresses().contains(addr));
-    }
-
-    private void assertDeclined(Inet4Address addr) {
-        assertTrue("Address is not declined: " + addr, mRepo.getDeclinedAddresses().contains(addr));
-    }
-}
diff --git a/tests/net/java/android/net/dhcp/DhcpServerTest.java b/tests/net/java/android/net/dhcp/DhcpServerTest.java
deleted file mode 100644
index ab9bd84..0000000
--- a/tests/net/java/android/net/dhcp/DhcpServerTest.java
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dhcp;
-
-import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
-import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
-import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
-import static android.net.dhcp.DhcpPacket.INADDR_ANY;
-import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST;
-
-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.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import static java.net.InetAddress.parseNumericAddress;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.LinkAddress;
-import android.net.MacAddress;
-import android.net.dhcp.DhcpLeaseRepository.InvalidAddressException;
-import android.net.dhcp.DhcpLeaseRepository.OutOfAddressesException;
-import android.net.dhcp.DhcpServer.Clock;
-import android.net.dhcp.DhcpServer.Dependencies;
-import android.net.util.SharedLog;
-import android.os.test.TestLooper;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DhcpServerTest {
-    private static final String PROP_DEXMAKER_SHARE_CLASSLOADER = "dexmaker.share_classloader";
-    private static final String TEST_IFACE = "testiface";
-
-    private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2");
-    private static final LinkAddress TEST_SERVER_LINKADDR = new LinkAddress(TEST_SERVER_ADDR, 20);
-    private static final Set<Inet4Address> TEST_DEFAULT_ROUTERS = new HashSet<>(
-            Arrays.asList(parseAddr("192.168.0.123"), parseAddr("192.168.0.124")));
-    private static final Set<Inet4Address> TEST_DNS_SERVERS = new HashSet<>(
-            Arrays.asList(parseAddr("192.168.0.126"), parseAddr("192.168.0.127")));
-    private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>(
-            Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201")));
-    private static final long TEST_LEASE_TIME_SECS = 3600L;
-    private static final int TEST_MTU = 1500;
-    private static final String TEST_HOSTNAME = "testhostname";
-
-    private static final int TEST_TRANSACTION_ID = 123;
-    private static final byte[] TEST_CLIENT_MAC_BYTES = new byte [] { 1, 2, 3, 4, 5, 6 };
-    private static final MacAddress TEST_CLIENT_MAC = MacAddress.fromBytes(TEST_CLIENT_MAC_BYTES);
-    private static final Inet4Address TEST_CLIENT_ADDR = parseAddr("192.168.0.42");
-
-    private static final long TEST_CLOCK_TIME = 1234L;
-    private static final int TEST_LEASE_EXPTIME_SECS = 3600;
-    private static final DhcpLease TEST_LEASE = new DhcpLease(null, TEST_CLIENT_MAC,
-            TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME,
-            null /* hostname */);
-    private static final DhcpLease TEST_LEASE_WITH_HOSTNAME = new DhcpLease(null, TEST_CLIENT_MAC,
-            TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, TEST_HOSTNAME);
-
-    @NonNull @Mock
-    private Dependencies mDeps;
-    @NonNull @Mock
-    private DhcpLeaseRepository mRepository;
-    @NonNull @Mock
-    private Clock mClock;
-    @NonNull @Mock
-    private DhcpPacketListener mPacketListener;
-
-    @NonNull @Captor
-    private ArgumentCaptor<ByteBuffer> mSentPacketCaptor;
-    @NonNull @Captor
-    private ArgumentCaptor<Inet4Address> mResponseDstAddrCaptor;
-
-    @NonNull
-    private TestLooper mLooper;
-    @NonNull
-    private DhcpServer mServer;
-
-    @Nullable
-    private String mPrevShareClassloaderProp;
-
-    @Before
-    public void setUp() throws Exception {
-        // Allow mocking package-private classes
-        mPrevShareClassloaderProp = System.getProperty(PROP_DEXMAKER_SHARE_CLASSLOADER);
-        System.setProperty(PROP_DEXMAKER_SHARE_CLASSLOADER, "true");
-        MockitoAnnotations.initMocks(this);
-
-        when(mDeps.makeLeaseRepository(any(), any(), any())).thenReturn(mRepository);
-        when(mDeps.makeClock()).thenReturn(mClock);
-        when(mDeps.makePacketListener()).thenReturn(mPacketListener);
-        doNothing().when(mDeps)
-                .sendPacket(any(), mSentPacketCaptor.capture(), mResponseDstAddrCaptor.capture());
-        when(mClock.elapsedRealtime()).thenReturn(TEST_CLOCK_TIME);
-
-        final DhcpServingParams servingParams = new DhcpServingParams.Builder()
-                .setDefaultRouters(TEST_DEFAULT_ROUTERS)
-                .setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS)
-                .setDnsServers(TEST_DNS_SERVERS)
-                .setServerAddr(TEST_SERVER_LINKADDR)
-                .setLinkMtu(TEST_MTU)
-                .setExcludedAddrs(TEST_EXCLUDED_ADDRS)
-                .build();
-
-        mLooper = new TestLooper();
-        mServer = new DhcpServer(mLooper.getLooper(), TEST_IFACE, servingParams,
-                new SharedLog(DhcpServerTest.class.getSimpleName()), mDeps);
-
-        mServer.start();
-        mLooper.dispatchAll();
-    }
-
-    @After
-    public void tearDown() {
-        // Calling stop() several times is not an issue
-        mServer.stop();
-        System.setProperty(PROP_DEXMAKER_SHARE_CLASSLOADER,
-                (mPrevShareClassloaderProp == null ? "" : mPrevShareClassloaderProp));
-    }
-
-    @Test
-    public void testStart() throws Exception {
-        verify(mPacketListener, times(1)).start();
-    }
-
-    @Test
-    public void testStop() throws Exception {
-        mServer.stop();
-        mLooper.dispatchAll();
-        verify(mPacketListener, times(1)).stop();
-    }
-
-    @Test
-    public void testDiscover() throws Exception {
-        // TODO: refactor packet construction to eliminate unnecessary/confusing/duplicate fields
-        when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
-                eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */))
-                .thenReturn(TEST_LEASE);
-
-        final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID,
-                (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES,
-                false /* broadcast */, INADDR_ANY /* srcIp */);
-        mServer.processPacket(discover, DHCP_CLIENT);
-
-        assertResponseSentTo(TEST_CLIENT_ADDR);
-        final DhcpOfferPacket packet = assertOffer(getPacket());
-        assertMatchesTestLease(packet);
-    }
-
-    @Test
-    public void testDiscover_OutOfAddresses() throws Exception {
-        when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
-                eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */))
-                .thenThrow(new OutOfAddressesException("Test exception"));
-
-        final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID,
-                (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES,
-                false /* broadcast */, INADDR_ANY /* srcIp */);
-        mServer.processPacket(discover, DHCP_CLIENT);
-
-        assertResponseSentTo(INADDR_BROADCAST);
-        final DhcpNakPacket packet = assertNak(getPacket());
-        assertMatchesClient(packet);
-    }
-
-    private DhcpRequestPacket makeRequestSelectingPacket() {
-        final DhcpRequestPacket request = new DhcpRequestPacket(TEST_TRANSACTION_ID,
-                (short) 0 /* secs */, INADDR_ANY /* clientIp */, INADDR_ANY /* relayIp */,
-                TEST_CLIENT_MAC_BYTES, false /* broadcast */);
-        request.mServerIdentifier = TEST_SERVER_ADDR;
-        request.mRequestedIp = TEST_CLIENT_ADDR;
-        return request;
-    }
-
-    @Test
-    public void testRequest_Selecting_Ack() throws Exception {
-        when(mRepository.requestLease(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
-                eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */,
-                eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, eq(TEST_HOSTNAME)))
-                .thenReturn(TEST_LEASE_WITH_HOSTNAME);
-
-        final DhcpRequestPacket request = makeRequestSelectingPacket();
-        request.mHostName = TEST_HOSTNAME;
-        request.mRequestedParams = new byte[] { DHCP_HOST_NAME };
-        mServer.processPacket(request, DHCP_CLIENT);
-
-        assertResponseSentTo(TEST_CLIENT_ADDR);
-        final DhcpAckPacket packet = assertAck(getPacket());
-        assertMatchesTestLease(packet, TEST_HOSTNAME);
-    }
-
-    @Test
-    public void testRequest_Selecting_Nak() throws Exception {
-        when(mRepository.requestLease(isNull(), eq(TEST_CLIENT_MAC),
-                eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */,
-                eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, isNull() /* hostname */))
-                .thenThrow(new InvalidAddressException("Test error"));
-
-        final DhcpRequestPacket request = makeRequestSelectingPacket();
-        mServer.processPacket(request, DHCP_CLIENT);
-
-        assertResponseSentTo(INADDR_BROADCAST);
-        final DhcpNakPacket packet = assertNak(getPacket());
-        assertMatchesClient(packet);
-    }
-
-    @Test
-    public void testRequest_Selecting_WrongClientPort() throws Exception {
-        final DhcpRequestPacket request = makeRequestSelectingPacket();
-        mServer.processPacket(request, 50000);
-
-        verify(mRepository, never())
-                .requestLease(any(), any(), any(), any(), any(), anyBoolean(), any());
-        verify(mDeps, never()).sendPacket(any(), any(), any());
-    }
-
-    @Test
-    public void testRelease() throws Exception {
-        final DhcpReleasePacket release = new DhcpReleasePacket(TEST_TRANSACTION_ID,
-                TEST_SERVER_ADDR, TEST_CLIENT_ADDR,
-                INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES);
-        mServer.processPacket(release, DHCP_CLIENT);
-
-        verify(mRepository, times(1))
-                .releaseLease(isNull(), eq(TEST_CLIENT_MAC), eq(TEST_CLIENT_ADDR));
-    }
-
-    /* TODO: add more tests once packet construction is refactored, including:
-     *  - usage of giaddr
-     *  - usage of broadcast bit
-     *  - other request states (init-reboot/renewing/rebinding)
-     */
-
-    private void assertMatchesTestLease(@NonNull DhcpPacket packet, @Nullable String hostname) {
-        assertMatchesClient(packet);
-        assertFalse(packet.hasExplicitClientId());
-        assertEquals(TEST_SERVER_ADDR, packet.mServerIdentifier);
-        assertEquals(TEST_CLIENT_ADDR, packet.mYourIp);
-        assertNotNull(packet.mLeaseTime);
-        assertEquals(TEST_LEASE_EXPTIME_SECS, (int) packet.mLeaseTime);
-        assertEquals(hostname, packet.mHostName);
-    }
-
-    private void assertMatchesTestLease(@NonNull DhcpPacket packet) {
-        assertMatchesTestLease(packet, null);
-    }
-
-    private void assertMatchesClient(@NonNull DhcpPacket packet) {
-        assertEquals(TEST_TRANSACTION_ID, packet.mTransId);
-        assertEquals(TEST_CLIENT_MAC, MacAddress.fromBytes(packet.mClientMac));
-    }
-
-    private void assertResponseSentTo(@NonNull Inet4Address addr) {
-        assertEquals(addr, mResponseDstAddrCaptor.getValue());
-    }
-
-    private static DhcpNakPacket assertNak(@Nullable DhcpPacket packet) {
-        assertTrue(packet instanceof DhcpNakPacket);
-        return (DhcpNakPacket) packet;
-    }
-
-    private static DhcpAckPacket assertAck(@Nullable DhcpPacket packet) {
-        assertTrue(packet instanceof DhcpAckPacket);
-        return (DhcpAckPacket) packet;
-    }
-
-    private static DhcpOfferPacket assertOffer(@Nullable DhcpPacket packet) {
-        assertTrue(packet instanceof DhcpOfferPacket);
-        return (DhcpOfferPacket) packet;
-    }
-
-    private DhcpPacket getPacket() throws Exception {
-        verify(mDeps, times(1)).sendPacket(any(), any(), any());
-        return DhcpPacket.decodeFullPacket(mSentPacketCaptor.getValue(), ENCAP_BOOTP);
-    }
-
-    private static Inet4Address parseAddr(@Nullable String inet4Addr) {
-        return (Inet4Address) parseNumericAddress(inet4Addr);
-    }
-}
diff --git a/tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java b/tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java
new file mode 100644
index 0000000..4a6f20a
--- /dev/null
+++ b/tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.dhcp;
+
+import static android.net.InetAddresses.parseNumericAddress;
+
+import static com.google.android.collect.Sets.newHashSet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.LinkAddress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DhcpServingParamsParcelExtTest {
+    private static final Inet4Address TEST_ADDRESS = inet4Addr("192.168.0.123");
+    private static final int TEST_ADDRESS_PARCELED = 0xc0a8007b;
+    private static final int TEST_PREFIX_LENGTH = 17;
+    private static final int TEST_LEASE_TIME_SECS = 120;
+    private static final int TEST_MTU = 1000;
+    private static final Set<Inet4Address> TEST_ADDRESS_SET =
+            newHashSet(inet4Addr("192.168.1.123"), inet4Addr("192.168.1.124"));
+    private static final Set<Integer> TEST_ADDRESS_SET_PARCELED =
+            newHashSet(0xc0a8017b, 0xc0a8017c);
+
+    private DhcpServingParamsParcelExt mParcel;
+
+    @Before
+    public void setUp() {
+        mParcel = new DhcpServingParamsParcelExt();
+    }
+
+    @Test
+    public void testSetServerAddr() {
+        mParcel.setServerAddr(new LinkAddress(TEST_ADDRESS, TEST_PREFIX_LENGTH));
+
+        assertEquals(TEST_ADDRESS_PARCELED, mParcel.serverAddr);
+        assertEquals(TEST_PREFIX_LENGTH, mParcel.serverAddrPrefixLength);
+    }
+
+    @Test
+    public void testSetDefaultRouters() {
+        mParcel.setDefaultRouters(TEST_ADDRESS_SET);
+        assertEquals(TEST_ADDRESS_SET_PARCELED, asSet(mParcel.defaultRouters));
+    }
+
+    @Test
+    public void testSetDnsServers() {
+        mParcel.setDnsServers(TEST_ADDRESS_SET);
+        assertEquals(TEST_ADDRESS_SET_PARCELED, asSet(mParcel.dnsServers));
+    }
+
+    @Test
+    public void testSetExcludedAddrs() {
+        mParcel.setExcludedAddrs(TEST_ADDRESS_SET);
+        assertEquals(TEST_ADDRESS_SET_PARCELED, asSet(mParcel.excludedAddrs));
+    }
+
+    @Test
+    public void testSetDhcpLeaseTimeSecs() {
+        mParcel.setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS);
+        assertEquals(TEST_LEASE_TIME_SECS, mParcel.dhcpLeaseTimeSecs);
+    }
+
+    @Test
+    public void testSetLinkMtu() {
+        mParcel.setLinkMtu(TEST_MTU);
+        assertEquals(TEST_MTU, mParcel.linkMtu);
+    }
+
+    @Test
+    public void testSetMetered() {
+        mParcel.setMetered(true);
+        assertTrue(mParcel.metered);
+        mParcel.setMetered(false);
+        assertFalse(mParcel.metered);
+    }
+
+    private static Inet4Address inet4Addr(String addr) {
+        return (Inet4Address) parseNumericAddress(addr);
+    }
+
+    private static Set<Integer> asSet(int[] ints) {
+        return IntStream.of(ints).boxed().collect(Collectors.toSet());
+    }
+}
diff --git a/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java b/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java
deleted file mode 100644
index b6a4073..0000000
--- a/tests/net/java/android/net/dhcp/DhcpServingParamsTest.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dhcp;
-
-import static android.net.dhcp.DhcpServingParams.MTU_UNSET;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import static java.net.InetAddress.parseNumericAddress;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.LinkAddress;
-import android.net.dhcp.DhcpServingParams.InvalidParameterException;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DhcpServingParamsTest {
-    @NonNull
-    private DhcpServingParams.Builder mBuilder;
-
-    private static final Set<Inet4Address> TEST_DEFAULT_ROUTERS = new HashSet<>(
-            Arrays.asList(parseAddr("192.168.0.123"), parseAddr("192.168.0.124")));
-    private static final long TEST_LEASE_TIME_SECS = 3600L;
-    private static final Set<Inet4Address> TEST_DNS_SERVERS = new HashSet<>(
-            Arrays.asList(parseAddr("192.168.0.126"), parseAddr("192.168.0.127")));
-    private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2");
-    private static final LinkAddress TEST_LINKADDR = new LinkAddress(TEST_SERVER_ADDR, 20);
-    private static final int TEST_MTU = 1500;
-    private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>(
-            Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201")));
-
-    @Before
-    public void setUp() {
-        mBuilder = new DhcpServingParams.Builder()
-                .setDefaultRouters(TEST_DEFAULT_ROUTERS)
-                .setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS)
-                .setDnsServers(TEST_DNS_SERVERS)
-                .setServerAddr(TEST_LINKADDR)
-                .setLinkMtu(TEST_MTU)
-                .setExcludedAddrs(TEST_EXCLUDED_ADDRS);
-    }
-
-    @Test
-    public void testBuild_Immutable() throws InvalidParameterException {
-        final Set<Inet4Address> routers = new HashSet<>(TEST_DEFAULT_ROUTERS);
-        final Set<Inet4Address> dnsServers = new HashSet<>(TEST_DNS_SERVERS);
-        final Set<Inet4Address> excludedAddrs = new HashSet<>(TEST_EXCLUDED_ADDRS);
-
-        final DhcpServingParams params = mBuilder
-                .setDefaultRouters(routers)
-                .setDnsServers(dnsServers)
-                .setExcludedAddrs(excludedAddrs)
-                .build();
-
-        // Modifications to source objects should not affect builder or final parameters
-        final Inet4Address addedAddr = parseAddr("192.168.0.223");
-        routers.add(addedAddr);
-        dnsServers.add(addedAddr);
-        excludedAddrs.add(addedAddr);
-
-        assertEquals(TEST_DEFAULT_ROUTERS, params.defaultRouters);
-        assertEquals(TEST_LEASE_TIME_SECS, params.dhcpLeaseTimeSecs);
-        assertEquals(TEST_DNS_SERVERS, params.dnsServers);
-        assertEquals(TEST_LINKADDR, params.serverAddr);
-        assertEquals(TEST_MTU, params.linkMtu);
-
-        assertContains(params.excludedAddrs, TEST_EXCLUDED_ADDRS);
-        assertContains(params.excludedAddrs, TEST_DEFAULT_ROUTERS);
-        assertContains(params.excludedAddrs, TEST_DNS_SERVERS);
-        assertContains(params.excludedAddrs, TEST_SERVER_ADDR);
-
-        assertFalse("excludedAddrs should not contain " + addedAddr,
-                params.excludedAddrs.contains(addedAddr));
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_NegativeLeaseTime() throws InvalidParameterException {
-        mBuilder.setDhcpLeaseTimeSecs(-1).build();
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_LeaseTimeTooLarge() throws InvalidParameterException {
-        // Set lease time larger than max value for uint32
-        mBuilder.setDhcpLeaseTimeSecs(1L << 32).build();
-    }
-
-    @Test
-    public void testBuild_InfiniteLeaseTime() throws InvalidParameterException {
-        final long infiniteLeaseTime = 0xffffffffL;
-        final DhcpServingParams params = mBuilder
-                .setDhcpLeaseTimeSecs(infiniteLeaseTime).build();
-        assertEquals(infiniteLeaseTime, params.dhcpLeaseTimeSecs);
-        assertTrue(params.dhcpLeaseTimeSecs > 0L);
-    }
-
-    @Test
-    public void testBuild_UnsetMtu() throws InvalidParameterException {
-        final DhcpServingParams params = mBuilder.setLinkMtu(MTU_UNSET).build();
-        assertEquals(MTU_UNSET, params.linkMtu);
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_MtuTooSmall() throws InvalidParameterException {
-        mBuilder.setLinkMtu(20).build();
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_MtuTooLarge() throws InvalidParameterException {
-        mBuilder.setLinkMtu(65_536).build();
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_IPv6Addr() throws InvalidParameterException {
-        mBuilder.setServerAddr(new LinkAddress(parseNumericAddress("fe80::1111"), 120)).build();
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_PrefixTooLarge() throws InvalidParameterException {
-        mBuilder.setServerAddr(new LinkAddress(TEST_SERVER_ADDR, 15)).build();
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_PrefixTooSmall() throws InvalidParameterException {
-        mBuilder.setDefaultRouters(parseAddr("192.168.0.254"))
-                .setServerAddr(new LinkAddress(TEST_SERVER_ADDR, 31))
-                .build();
-    }
-
-    @Test(expected = InvalidParameterException.class)
-    public void testBuild_RouterNotInPrefix() throws InvalidParameterException {
-        mBuilder.setDefaultRouters(parseAddr("192.168.254.254")).build();
-    }
-
-    private static <T> void assertContains(@NonNull Set<T> set, @NonNull Set<T> subset) {
-        for (final T elem : subset) {
-            assertContains(set, elem);
-        }
-    }
-
-    private static <T> void assertContains(@NonNull Set<T> set, @Nullable T elem) {
-        assertTrue("Set does not contain " + elem, set.contains(elem));
-    }
-
-    @NonNull
-    private static Inet4Address parseAddr(@NonNull String inet4Addr) {
-        return (Inet4Address) parseNumericAddress(inet4Addr);
-    }
-}
diff --git a/tests/net/java/android/net/ip/IpClientTest.java b/tests/net/java/android/net/ip/IpClientTest.java
deleted file mode 100644
index cba3c65..0000000
--- a/tests/net/java/android/net/ip/IpClientTest.java
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ip;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.AlarmManager;
-import android.content.Context;
-import android.content.res.Resources;
-import android.net.INetd;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.MacAddress;
-import android.net.RouteInfo;
-import android.net.ip.IpClient.Callback;
-import android.net.ip.IpClient.InitialConfiguration;
-import android.net.ip.IpClient.ProvisioningConfiguration;
-import android.net.util.InterfaceParams;
-import android.os.INetworkManagementService;
-import android.provider.Settings;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.mock.MockContentResolver;
-
-import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.internal.R;
-import com.android.server.net.BaseNetworkObserver;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.net.InetAddress;
-import java.util.Arrays;
-import java.util.List;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Tests for IpClient.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpClientTest {
-    private static final int DEFAULT_AVOIDBADWIFI_CONFIG_VALUE = 1;
-
-    private static final String VALID = "VALID";
-    private static final String INVALID = "INVALID";
-    private static final String TEST_IFNAME = "test_wlan0";
-    private static final int TEST_IFINDEX = 1001;
-    // See RFC 7042#section-2.1.2 for EUI-48 documentation values.
-    private static final MacAddress TEST_MAC = MacAddress.fromString("00:00:5E:00:53:01");
-    private static final int TEST_TIMEOUT_MS = 400;
-
-    @Mock private Context mContext;
-    @Mock private INetworkManagementService mNMService;
-    @Mock private INetd mNetd;
-    @Mock private Resources mResources;
-    @Mock private Callback mCb;
-    @Mock private AlarmManager mAlarm;
-    @Mock private IpClient.Dependencies mDependecies;
-    private MockContentResolver mContentResolver;
-
-    private BaseNetworkObserver mObserver;
-    private InterfaceParams mIfParams;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
-        when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
-        when(mContext.getResources()).thenReturn(mResources);
-        when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
-                .thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
-
-        mContentResolver = new MockContentResolver();
-        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
-        when(mContext.getContentResolver()).thenReturn(mContentResolver);
-
-        mIfParams = null;
-
-        when(mDependecies.getNMS()).thenReturn(mNMService);
-        when(mDependecies.getNetd()).thenReturn(mNetd);
-    }
-
-    private void setTestInterfaceParams(String ifname) {
-        mIfParams = (ifname != null)
-                ? new InterfaceParams(ifname, TEST_IFINDEX, TEST_MAC)
-                : null;
-        when(mDependecies.getInterfaceParams(anyString())).thenReturn(mIfParams);
-    }
-
-    private IpClient makeIpClient(String ifname) throws Exception {
-        setTestInterfaceParams(ifname);
-        final IpClient ipc = new IpClient(mContext, ifname, mCb, mDependecies);
-        verify(mNMService, timeout(TEST_TIMEOUT_MS).times(1)).disableIpv6(ifname);
-        verify(mNMService, timeout(TEST_TIMEOUT_MS).times(1)).clearInterfaceAddresses(ifname);
-        ArgumentCaptor<BaseNetworkObserver> arg =
-                ArgumentCaptor.forClass(BaseNetworkObserver.class);
-        verify(mNMService, times(1)).registerObserver(arg.capture());
-        mObserver = arg.getValue();
-        reset(mNMService);
-        // Verify IpClient doesn't call onLinkPropertiesChange() when it starts.
-        verify(mCb, never()).onLinkPropertiesChange(any());
-        reset(mCb);
-        return ipc;
-    }
-
-    private static LinkProperties makeEmptyLinkProperties(String iface) {
-        final LinkProperties empty = new LinkProperties();
-        empty.setInterfaceName(iface);
-        return empty;
-    }
-
-    @Test
-    public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
-        setTestInterfaceParams(null);
-        try {
-            final IpClient ipc = new IpClient(mContext, null, mCb, mDependecies);
-            ipc.shutdown();
-            fail();
-        } catch (NullPointerException npe) {
-            // Phew; null interface names not allowed.
-        }
-    }
-
-    @Test
-    public void testNullCallbackMostDefinitelyThrows() throws Exception {
-        final String ifname = "lo";
-        setTestInterfaceParams(ifname);
-        try {
-            final IpClient ipc = new IpClient(mContext, ifname, null, mDependecies);
-            ipc.shutdown();
-            fail();
-        } catch (NullPointerException npe) {
-            // Phew; null callbacks not allowed.
-        }
-    }
-
-    @Test
-    public void testInvalidInterfaceDoesNotThrow() throws Exception {
-        setTestInterfaceParams(TEST_IFNAME);
-        final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mDependecies);
-        ipc.shutdown();
-    }
-
-    @Test
-    public void testInterfaceNotFoundFailsImmediately() throws Exception {
-        setTestInterfaceParams(null);
-        final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mDependecies);
-        ipc.startProvisioning(new IpClient.ProvisioningConfiguration());
-        verify(mCb, times(1)).onProvisioningFailure(any());
-        ipc.shutdown();
-    }
-
-    @Test
-    public void testDefaultProvisioningConfiguration() throws Exception {
-        final String iface = TEST_IFNAME;
-        final IpClient ipc = makeIpClient(iface);
-
-        ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
-                .withoutIPv4()
-                // TODO: mock IpReachabilityMonitor's dependencies (NetworkInterface, PowerManager)
-                // and enable it in this test
-                .withoutIpReachabilityMonitor()
-                .build();
-
-        ipc.startProvisioning(config);
-        verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
-        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
-        verify(mCb, never()).onProvisioningFailure(any());
-
-        ipc.shutdown();
-        verify(mNMService, timeout(TEST_TIMEOUT_MS).times(1)).disableIpv6(iface);
-        verify(mNMService, timeout(TEST_TIMEOUT_MS).times(1)).clearInterfaceAddresses(iface);
-        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
-                .onLinkPropertiesChange(eq(makeEmptyLinkProperties(iface)));
-    }
-
-    @Test
-    public void testProvisioningWithInitialConfiguration() throws Exception {
-        final String iface = TEST_IFNAME;
-        final IpClient ipc = makeIpClient(iface);
-
-        String[] addresses = {
-            "fe80::a4be:f92:e1f7:22d1/64",
-            "fe80::f04a:8f6:6a32:d756/64",
-            "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"
-        };
-        String[] prefixes = { "fe80::/64", "fd2c:4e57:8e3c::/64" };
-
-        ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
-                .withoutIPv4()
-                .withoutIpReachabilityMonitor()
-                .withInitialConfiguration(conf(links(addresses), prefixes(prefixes), ips()))
-                .build();
-
-        ipc.startProvisioning(config);
-        verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
-        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
-        verify(mCb, never()).onProvisioningFailure(any());
-
-        for (String addr : addresses) {
-            String[] parts = addr.split("/");
-            verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1))
-                    .interfaceAddAddress(iface, parts[0], Integer.parseInt(parts[1]));
-        }
-
-        final int lastAddr = addresses.length - 1;
-
-        // Add N - 1 addresses
-        for (int i = 0; i < lastAddr; i++) {
-            mObserver.addressUpdated(iface, new LinkAddress(addresses[i]));
-            verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(any());
-            reset(mCb);
-        }
-
-        // Add Nth address
-        mObserver.addressUpdated(iface, new LinkAddress(addresses[lastAddr]));
-        LinkProperties want = linkproperties(links(addresses), routes(prefixes));
-        want.setInterfaceName(iface);
-        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(eq(want));
-
-        ipc.shutdown();
-        verify(mNMService, timeout(TEST_TIMEOUT_MS).times(1)).disableIpv6(iface);
-        verify(mNMService, timeout(TEST_TIMEOUT_MS).times(1)).clearInterfaceAddresses(iface);
-        verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
-                .onLinkPropertiesChange(eq(makeEmptyLinkProperties(iface)));
-    }
-
-    @Test
-    public void testIsProvisioned() throws Exception {
-        InitialConfiguration empty = conf(links(), prefixes());
-        IsProvisionedTestCase[] testcases = {
-            // nothing
-            notProvisionedCase(links(), routes(), dns(), null),
-            notProvisionedCase(links(), routes(), dns(), empty),
-
-            // IPv4
-            provisionedCase(links("192.0.2.12/24"), routes(), dns(), empty),
-
-            // IPv6
-            notProvisionedCase(
-                    links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
-                    routes(), dns(), empty),
-            notProvisionedCase(
-                    links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
-                    routes("fe80::/64", "fd2c:4e57:8e3c::/64"), dns("fd00:1234:5678::1000"), empty),
-            provisionedCase(
-                    links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
-                    routes("::/0"),
-                    dns("2001:db8:dead:beef:f00::02"), empty),
-
-            // Initial configuration
-            provisionedCase(
-                    links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
-                    routes("fe80::/64", "fd2c:4e57:8e3c::/64"),
-                    dns(),
-                    conf(links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
-                        prefixes( "fe80::/64", "fd2c:4e57:8e3c::/64"), ips()))
-        };
-
-        for (IsProvisionedTestCase testcase : testcases) {
-            if (IpClient.isProvisioned(testcase.lp, testcase.config) != testcase.isProvisioned) {
-                fail(testcase.errorMessage());
-            }
-        }
-    }
-
-    static class IsProvisionedTestCase {
-        boolean isProvisioned;
-        LinkProperties lp;
-        InitialConfiguration config;
-
-        String errorMessage() {
-            return String.format("expected %s with config %s to be %s, but was %s",
-                     lp, config, provisioned(isProvisioned), provisioned(!isProvisioned));
-        }
-
-        static String provisioned(boolean isProvisioned) {
-            return isProvisioned ? "provisioned" : "not provisioned";
-        }
-    }
-
-    static IsProvisionedTestCase provisionedCase(Set<LinkAddress> lpAddrs, Set<RouteInfo> lpRoutes,
-            Set<InetAddress> lpDns, InitialConfiguration config) {
-        return provisioningTest(true, lpAddrs, lpRoutes, lpDns, config);
-    }
-
-    static IsProvisionedTestCase notProvisionedCase(Set<LinkAddress> lpAddrs,
-            Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
-        return provisioningTest(false, lpAddrs, lpRoutes, lpDns, config);
-    }
-
-    static IsProvisionedTestCase provisioningTest(boolean isProvisioned, Set<LinkAddress> lpAddrs,
-            Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
-        IsProvisionedTestCase testcase = new IsProvisionedTestCase();
-        testcase.isProvisioned = isProvisioned;
-        testcase.lp = new LinkProperties();
-        testcase.lp.setLinkAddresses(lpAddrs);
-        for (RouteInfo route : lpRoutes) {
-            testcase.lp.addRoute(route);
-        }
-        for (InetAddress dns : lpDns) {
-            testcase.lp.addDnsServer(dns);
-        }
-        testcase.config = config;
-        return testcase;
-    }
-
-    @Test
-    public void testInitialConfigurations() throws Exception {
-        InitialConfigurationTestCase[] testcases = {
-            validConf("valid IPv4 configuration",
-                    links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("192.0.2.2")),
-            validConf("another valid IPv4 configuration",
-                    links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns()),
-            validConf("valid IPv6 configurations",
-                    links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
-                    prefixes("2001:db8:dead:beef::/64", "fe80::/64"),
-                    dns("2001:db8:dead:beef:f00::02")),
-            validConf("valid IPv6 configurations",
-                    links("fe80::1/64"), prefixes("fe80::/64"), dns()),
-            validConf("valid IPv6/v4 configuration",
-                    links("2001:db8:dead:beef:f00::a0/48", "192.0.2.12/24"),
-                    prefixes("2001:db8:dead:beef::/64", "192.0.2.0/24"),
-                    dns("192.0.2.2", "2001:db8:dead:beef:f00::02")),
-            validConf("valid IPv6 configuration without any GUA.",
-                    links("fd00:1234:5678::1/48"),
-                    prefixes("fd00:1234:5678::/48"),
-                    dns("fd00:1234:5678::1000")),
-
-            invalidConf("empty configuration", links(), prefixes(), dns()),
-            invalidConf("v4 addr and dns not in any prefix",
-                    links("192.0.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
-            invalidConf("v4 addr not in any prefix",
-                    links("198.51.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
-            invalidConf("v4 dns addr not in any prefix",
-                    links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("198.51.100.2")),
-            invalidConf("v6 addr not in any prefix",
-                    links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
-                    prefixes("2001:db8:dead:beef::/64"),
-                    dns("2001:db8:dead:beef:f00::02")),
-            invalidConf("v6 dns addr not in any prefix",
-                    links("fe80::1/64"), prefixes("fe80::/64"), dns("2001:db8:dead:beef:f00::02")),
-            invalidConf("default ipv6 route and no GUA",
-                    links("fd01:1111:2222:3333::a0/128"), prefixes("::/0"), dns()),
-            invalidConf("invalid v6 prefix length",
-                    links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/32"),
-                    dns()),
-            invalidConf("another invalid v6 prefix length",
-                    links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/72"),
-                    dns())
-        };
-
-        for (InitialConfigurationTestCase testcase : testcases) {
-            if (testcase.config.isValid() != testcase.isValid) {
-                fail(testcase.errorMessage());
-            }
-        }
-    }
-
-    static class InitialConfigurationTestCase {
-        String descr;
-        boolean isValid;
-        InitialConfiguration config;
-        public String errorMessage() {
-            return String.format("%s: expected configuration %s to be %s, but was %s",
-                    descr, config, validString(isValid), validString(!isValid));
-        }
-        static String validString(boolean isValid) {
-            return isValid ? VALID : INVALID;
-        }
-    }
-
-    static InitialConfigurationTestCase validConf(String descr, Set<LinkAddress> links,
-            Set<IpPrefix> prefixes, Set<InetAddress> dns) {
-        return confTestCase(descr, true, conf(links, prefixes, dns));
-    }
-
-    static InitialConfigurationTestCase invalidConf(String descr, Set<LinkAddress> links,
-            Set<IpPrefix> prefixes, Set<InetAddress> dns) {
-        return confTestCase(descr, false, conf(links, prefixes, dns));
-    }
-
-    static InitialConfigurationTestCase confTestCase(
-            String descr, boolean isValid, InitialConfiguration config) {
-        InitialConfigurationTestCase testcase = new InitialConfigurationTestCase();
-        testcase.descr = descr;
-        testcase.isValid = isValid;
-        testcase.config = config;
-        return testcase;
-    }
-
-    static LinkProperties linkproperties(Set<LinkAddress> addresses, Set<RouteInfo> routes) {
-        LinkProperties lp = new LinkProperties();
-        lp.setLinkAddresses(addresses);
-        for (RouteInfo route : routes) {
-            lp.addRoute(route);
-        }
-        return lp;
-    }
-
-    static InitialConfiguration conf(Set<LinkAddress> links, Set<IpPrefix> prefixes) {
-        return conf(links, prefixes, new HashSet<>());
-    }
-
-    static InitialConfiguration conf(
-            Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns) {
-        InitialConfiguration conf = new InitialConfiguration();
-        conf.ipAddresses.addAll(links);
-        conf.directlyConnectedRoutes.addAll(prefixes);
-        conf.dnsServers.addAll(dns);
-        return conf;
-    }
-
-    static Set<RouteInfo> routes(String... routes) {
-        return mapIntoSet(routes, (r) -> new RouteInfo(new IpPrefix(r)));
-    }
-
-    static Set<IpPrefix> prefixes(String... prefixes) {
-        return mapIntoSet(prefixes, IpPrefix::new);
-    }
-
-    static Set<LinkAddress> links(String... addresses) {
-        return mapIntoSet(addresses, LinkAddress::new);
-    }
-
-    static Set<InetAddress> ips(String... addresses) {
-        return mapIntoSet(addresses, InetAddress::getByName);
-    }
-
-    static Set<InetAddress> dns(String... addresses) {
-        return ips(addresses);
-    }
-
-    static <A, B> Set<B> mapIntoSet(A[] in, Fn<A, B> fn) {
-        Set<B> out = new HashSet<>(in.length);
-        for (A item : in) {
-            try {
-                out.add(fn.call(item));
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-        }
-        return out;
-    }
-
-    interface Fn<A,B> {
-        B call(A a) throws Exception;
-    }
-
-    @Test
-    public void testAll() {
-        List<String> list1 = Arrays.asList();
-        List<String> list2 = Arrays.asList("foo");
-        List<String> list3 = Arrays.asList("bar", "baz");
-        List<String> list4 = Arrays.asList("foo", "bar", "baz");
-
-        assertTrue(IpClient.all(list1, (x) -> false));
-        assertFalse(IpClient.all(list2, (x) -> false));
-        assertTrue(IpClient.all(list3, (x) -> true));
-        assertTrue(IpClient.all(list2, (x) -> x.charAt(0) == 'f'));
-        assertFalse(IpClient.all(list4, (x) -> x.charAt(0) == 'f'));
-    }
-
-    @Test
-    public void testAny() {
-        List<String> list1 = Arrays.asList();
-        List<String> list2 = Arrays.asList("foo");
-        List<String> list3 = Arrays.asList("bar", "baz");
-        List<String> list4 = Arrays.asList("foo", "bar", "baz");
-
-        assertFalse(IpClient.any(list1, (x) -> true));
-        assertTrue(IpClient.any(list2, (x) -> true));
-        assertTrue(IpClient.any(list2, (x) -> x.charAt(0) == 'f'));
-        assertFalse(IpClient.any(list3, (x) -> x.charAt(0) == 'f'));
-        assertTrue(IpClient.any(list4, (x) -> x.charAt(0) == 'f'));
-    }
-
-    @Test
-    public void testFindAll() {
-        List<String> list1 = Arrays.asList();
-        List<String> list2 = Arrays.asList("foo");
-        List<String> list3 = Arrays.asList("foo", "bar", "baz");
-
-        assertEquals(list1, IpClient.findAll(list1, (x) -> true));
-        assertEquals(list1, IpClient.findAll(list3, (x) -> false));
-        assertEquals(list3, IpClient.findAll(list3, (x) -> true));
-        assertEquals(list2, IpClient.findAll(list3, (x) -> x.charAt(0) == 'f'));
-    }
-}
diff --git a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
deleted file mode 100644
index e65585f..0000000
--- a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ip;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.when;
-
-import android.net.util.InterfaceParams;
-import android.net.util.SharedLog;
-import android.os.Handler;
-import android.os.Looper;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-
-/**
- * Tests for IpReachabilityMonitor.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpReachabilityMonitorTest {
-
-    @Mock IpReachabilityMonitor.Callback mCallback;
-    @Mock IpReachabilityMonitor.Dependencies mDependencies;
-    @Mock SharedLog mLog;
-    Handler mHandler;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        when(mLog.forSubComponent(anyString())).thenReturn(mLog);
-        mHandler = new Handler(Looper.getMainLooper());
-    }
-
-    IpReachabilityMonitor makeMonitor() {
-        final InterfaceParams ifParams = new InterfaceParams("fake0", 1, null);
-        return new IpReachabilityMonitor(ifParams, mHandler, mLog, mCallback, null, mDependencies);
-    }
-
-    @Test
-    public void testNothing() {
-        IpReachabilityMonitor monitor = makeMonitor();
-    }
-}
diff --git a/tests/net/java/android/net/ip/IpServerTest.java b/tests/net/java/android/net/ip/IpServerTest.java
index 2c675c6..80aac04 100644
--- a/tests/net/java/android/net/ip/IpServerTest.java
+++ b/tests/net/java/android/net/ip/IpServerTest.java
@@ -16,31 +16,39 @@
 
 package android.net.ip;
 
+import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
+import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TETHERING_WIFI;
+import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
+import static android.net.NetworkUtils.intToInet4AddressHTH;
+import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
+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 static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
-import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-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.INetd;
 import android.net.INetworkStatsService;
 import android.net.InterfaceConfiguration;
 import android.net.IpPrefix;
@@ -48,8 +56,9 @@
 import android.net.LinkProperties;
 import android.net.MacAddress;
 import android.net.RouteInfo;
-import android.net.dhcp.DhcpServer;
-import android.net.dhcp.DhcpServingParams;
+import android.net.dhcp.DhcpServingParamsParcel;
+import android.net.dhcp.IDhcpServer;
+import android.net.dhcp.IDhcpServerCallbacks;
 import android.net.util.InterfaceParams;
 import android.net.util.InterfaceSet;
 import android.net.util.SharedLog;
@@ -60,8 +69,6 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
 
-import java.net.Inet4Address;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -71,6 +78,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.net.Inet4Address;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class IpServerTest {
@@ -82,16 +91,19 @@
     private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams(
             IFACE_NAME, 42 /* index */, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);
 
+    private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000;
+
     @Mock private INetworkManagementService mNMService;
+    @Mock private INetd mNetd;
     @Mock private INetworkStatsService mStatsService;
     @Mock private IpServer.Callback mCallback;
     @Mock private InterfaceConfiguration mInterfaceConfiguration;
     @Mock private SharedLog mSharedLog;
-    @Mock private DhcpServer mDhcpServer;
+    @Mock private IDhcpServer mDhcpServer;
     @Mock private RouterAdvertisementDaemon mRaDaemon;
     @Mock private IpServer.Dependencies mDependencies;
 
-    @Captor private ArgumentCaptor<DhcpServingParams> mDhcpParamsCaptor;
+    @Captor private ArgumentCaptor<DhcpServingParamsParcel> mDhcpParamsCaptor;
 
     private final TestLooper mLooper = new TestLooper();
     private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
@@ -103,6 +115,21 @@
     }
 
     private void initStateMachine(int interfaceType, boolean usingLegacyDhcp) throws Exception {
+        doAnswer(inv -> {
+            final IDhcpServerCallbacks cb = inv.getArgument(2);
+            new Thread(() -> {
+                try {
+                    cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
+                } catch (RemoteException e) {
+                    fail(e.getMessage());
+                }
+            }).run();
+            return null;
+        }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any());
+        when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
+        when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
+        when(mDependencies.getNetdService()).thenReturn(mNetd);
+
         mIpServer = new IpServer(
                 IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
                 mNMService, mStatsService, mCallback, usingLegacyDhcp, mDependencies);
@@ -112,10 +139,6 @@
         mLooper.dispatchAll();
         reset(mNMService, mStatsService, mCallback);
         when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
-        when(mDependencies.makeDhcpServer(
-                any(), any(), mDhcpParamsCaptor.capture(), any())).thenReturn(mDhcpServer);
-        when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
-        when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
 
         when(mRaDaemon.start()).thenReturn(true);
     }
@@ -204,9 +227,9 @@
         initTetheredStateMachine(TETHERING_BLUETOOTH, null);
 
         dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
-        InOrder inOrder = inOrder(mNMService, mStatsService, mCallback);
+        InOrder inOrder = inOrder(mNMService, mNetd, mStatsService, mCallback);
         inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
-        inOrder.verify(mNMService).setInterfaceConfig(eq(IFACE_NAME), any());
+        inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
         inOrder.verify(mCallback).updateInterfaceState(
                 mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
         inOrder.verify(mCallback).updateLinkProperties(
@@ -299,12 +322,12 @@
         initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
 
         dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
-        InOrder inOrder = inOrder(mNMService, mStatsService, mCallback);
+        InOrder inOrder = inOrder(mNMService, mNetd, 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(mNetd).interfaceSetCfg(argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
         inOrder.verify(mCallback).updateInterfaceState(
                 mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
         inOrder.verify(mCallback).updateLinkProperties(
@@ -399,21 +422,20 @@
         initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */);
         dispatchTetherConnectionChanged(UPSTREAM_IFACE);
 
-        verify(mDependencies, never()).makeDhcpServer(any(), any(), any(), any());
+        verify(mDependencies, never()).makeDhcpServer(any(), any(), any());
     }
 
-    private void assertDhcpStarted(IpPrefix expectedPrefix) {
-        verify(mDependencies, times(1)).makeDhcpServer(
-                eq(mLooper.getLooper()), eq(IFACE_NAME), any(), eq(mSharedLog));
-        verify(mDhcpServer, times(1)).start();
-        final DhcpServingParams params = mDhcpParamsCaptor.getValue();
+    private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception {
+        verify(mDependencies, times(1)).makeDhcpServer(eq(IFACE_NAME), any(), any());
+        verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).start(any());
+        final DhcpServingParamsParcel params = mDhcpParamsCaptor.getValue();
         // Last address byte is random
-        assertTrue(expectedPrefix.contains(params.serverAddr.getAddress()));
-        assertEquals(expectedPrefix.getPrefixLength(), params.serverAddr.getPrefixLength());
-        assertEquals(1, params.defaultRouters.size());
-        assertEquals(params.serverAddr.getAddress(), params.defaultRouters.iterator().next());
-        assertEquals(1, params.dnsServers.size());
-        assertEquals(params.serverAddr.getAddress(), params.dnsServers.iterator().next());
+        assertTrue(expectedPrefix.contains(intToInet4AddressHTH(params.serverAddr)));
+        assertEquals(expectedPrefix.getPrefixLength(), params.serverAddrPrefixLength);
+        assertEquals(1, params.defaultRouters.length);
+        assertEquals(params.serverAddr, params.defaultRouters[0]);
+        assertEquals(1, params.dnsServers.length);
+        assertEquals(params.serverAddr, params.dnsServers[0]);
         assertEquals(DHCP_LEASE_TIME_SECS, params.dhcpLeaseTimeSecs);
     }
 
@@ -458,7 +480,7 @@
             addr4 = addr;
             break;
         }
-        assertTrue("missing IPv4 address", addr4 != null);
+        assertNotNull("missing IPv4 address", addr4);
 
         // Assert the presence of the associated directly connected route.
         final RouteInfo directlyConnected = new RouteInfo(addr4, null, lp.getInterfaceName());
diff --git a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
new file mode 100644
index 0000000..1fc67a8
--- /dev/null
+++ b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
@@ -0,0 +1,120 @@
+/*
+ * 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.ipmemorystore;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Modifier;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.Collections;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ParcelableTests {
+    @Test
+    public void testNetworkAttributesParceling() throws Exception {
+        final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
+        NetworkAttributes in = builder.build();
+        assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
+
+        builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
+        // groupHint stays null this time around
+        builder.setDnsAddresses(Collections.emptyList());
+        builder.setMtu(18);
+        in = builder.build();
+        assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
+
+        builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("6.7.8.9"));
+        builder.setGroupHint("groupHint");
+        builder.setDnsAddresses(Arrays.asList(
+                InetAddress.getByName("ACA1:652B:0911:DE8F:1200:115E:913B:AA2A"),
+                InetAddress.getByName("6.7.8.9")));
+        builder.setMtu(1_000_000);
+        in = builder.build();
+        assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
+
+        builder.setMtu(null);
+        in = builder.build();
+        assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
+
+        // Verify that this test does not miss any new field added later.
+        // If any field is added to NetworkAttributes it must be tested here for parceling
+        // roundtrip.
+        assertEquals(4, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
+                .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
+    }
+
+    @Test
+    public void testPrivateDataParceling() throws Exception {
+        final Blob in = new Blob();
+        in.data = new byte[] {89, 111, 108, 111};
+        final Blob out = parcelingRoundTrip(in);
+        // Object.equals on byte[] tests the references
+        assertEquals(in.data.length, out.data.length);
+        assertTrue(Arrays.equals(in.data, out.data));
+    }
+
+    @Test
+    public void testSameL3NetworkResponseParceling() throws Exception {
+        final SameL3NetworkResponseParcelable parcelable = new SameL3NetworkResponseParcelable();
+        parcelable.l2Key1 = "key 1";
+        parcelable.l2Key2 = "key 2";
+        parcelable.confidence = 0.43f;
+
+        final SameL3NetworkResponse in = new SameL3NetworkResponse(parcelable);
+        assertEquals("key 1", in.l2Key1);
+        assertEquals("key 2", in.l2Key2);
+        assertEquals(0.43f, in.confidence, 0.01f /* delta */);
+
+        final SameL3NetworkResponse out =
+                new SameL3NetworkResponse(parcelingRoundTrip(in.toParcelable()));
+
+        assertEquals(in, out);
+        assertEquals(in.l2Key1, out.l2Key1);
+        assertEquals(in.l2Key2, out.l2Key2);
+        assertEquals(in.confidence, out.confidence, 0.01f /* delta */);
+    }
+
+    private <T extends Parcelable> T parcelingRoundTrip(final T in) throws Exception {
+        final Parcel p = Parcel.obtain();
+        in.writeToParcel(p, /* flags */ 0);
+        p.setDataPosition(0);
+        final byte[] marshalledData = p.marshall();
+        p.recycle();
+
+        final Parcel q = Parcel.obtain();
+        q.unmarshall(marshalledData, 0, marshalledData.length);
+        q.setDataPosition(0);
+
+        final Parcelable.Creator<T> creator = (Parcelable.Creator<T>)
+                in.getClass().getField("CREATOR").get(null); // static object, so null receiver
+        final T unmarshalled = (T) creator.createFromParcel(q);
+        q.recycle();
+        return unmarshalled;
+    }
+}
diff --git a/tests/net/java/android/net/shared/InitialConfigurationTest.java b/tests/net/java/android/net/shared/InitialConfigurationTest.java
new file mode 100644
index 0000000..78792bd
--- /dev/null
+++ b/tests/net/java/android/net/shared/InitialConfigurationTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static android.net.InetAddresses.parseNumericAddress;
+import static android.net.shared.ParcelableTestUtil.assertFieldCountEquals;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.function.Consumer;
+
+/**
+ * Tests for {@link InitialConfiguration}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class InitialConfigurationTest {
+    private InitialConfiguration mConfig;
+
+    @Before
+    public void setUp() {
+        mConfig = new InitialConfiguration();
+        mConfig.ipAddresses.addAll(Arrays.asList(
+                new LinkAddress(parseNumericAddress("192.168.45.45"), 16),
+                new LinkAddress(parseNumericAddress("2001:db8::45"), 33)));
+        mConfig.directlyConnectedRoutes.addAll(Arrays.asList(
+                new IpPrefix(parseNumericAddress("192.168.46.46"), 17),
+                new IpPrefix(parseNumericAddress("2001:db8::46"), 34)));
+        mConfig.dnsServers.addAll(Arrays.asList(
+                parseNumericAddress("192.168.47.47"),
+                parseNumericAddress("2001:db8::47")));
+        // Any added InitialConfiguration field must be included in equals() to be tested properly
+        assertFieldCountEquals(3, InitialConfiguration.class);
+    }
+
+    @Test
+    public void testParcelUnparcelInitialConfiguration() {
+        final InitialConfiguration unparceled =
+                InitialConfiguration.fromStableParcelable(mConfig.toStableParcelable());
+        assertEquals(mConfig, unparceled);
+    }
+
+    @Test
+    public void testEquals() {
+        assertEquals(mConfig, InitialConfiguration.copy(mConfig));
+
+        assertNotEqualsAfterChange(c -> c.ipAddresses.add(
+                new LinkAddress(parseNumericAddress("192.168.47.47"), 24)));
+        assertNotEqualsAfterChange(c -> c.directlyConnectedRoutes.add(
+                new IpPrefix(parseNumericAddress("192.168.46.46"), 32)));
+        assertNotEqualsAfterChange(c -> c.dnsServers.add(parseNumericAddress("2001:db8::49")));
+        assertFieldCountEquals(3, InitialConfiguration.class);
+    }
+
+    private void assertNotEqualsAfterChange(Consumer<InitialConfiguration> mutator) {
+        final InitialConfiguration newConfig = InitialConfiguration.copy(mConfig);
+        mutator.accept(newConfig);
+        assertNotEquals(mConfig, newConfig);
+    }
+}
diff --git a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java b/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
new file mode 100644
index 0000000..14df392
--- /dev/null
+++ b/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static android.net.InetAddresses.parseNumericAddress;
+import static android.net.shared.IpConfigurationParcelableUtil.fromStableParcelable;
+import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable;
+import static android.net.shared.ParcelableTestUtil.assertFieldCountEquals;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.DhcpResults;
+import android.net.LinkAddress;
+import android.net.StaticIpConfiguration;
+import android.net.apf.ApfCapabilities;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+
+/**
+ * Tests for {@link IpConfigurationParcelableUtil}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpConfigurationParcelableUtilTest {
+    private StaticIpConfiguration mStaticIpConfiguration;
+    private DhcpResults mDhcpResults;
+
+    @Before
+    public void setUp() {
+        mStaticIpConfiguration = new StaticIpConfiguration();
+        mStaticIpConfiguration.ipAddress = new LinkAddress(parseNumericAddress("2001:db8::42"), 64);
+        mStaticIpConfiguration.gateway = parseNumericAddress("192.168.42.42");
+        mStaticIpConfiguration.dnsServers.add(parseNumericAddress("2001:db8::43"));
+        mStaticIpConfiguration.dnsServers.add(parseNumericAddress("192.168.43.43"));
+        mStaticIpConfiguration.domains = "example.com";
+        // Any added StaticIpConfiguration field must be included in equals() to be tested properly
+        assertFieldCountEquals(4, StaticIpConfiguration.class);
+
+        mDhcpResults = new DhcpResults(mStaticIpConfiguration);
+        mDhcpResults.serverAddress = (Inet4Address) parseNumericAddress("192.168.44.44");
+        mDhcpResults.vendorInfo = "TEST_VENDOR_INFO";
+        mDhcpResults.leaseDuration = 3600;
+        mDhcpResults.mtu = 1450;
+        // Any added DhcpResults field must be included in equals() to be tested properly
+        assertFieldCountEquals(4, DhcpResults.class);
+    }
+
+    @Test
+    public void testParcelUnparcelStaticConfiguration() {
+        doStaticConfigurationParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcelStaticConfiguration_NullIpAddress() {
+        mStaticIpConfiguration.ipAddress = null;
+        doStaticConfigurationParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcelStaticConfiguration_NullGateway() {
+        mStaticIpConfiguration.gateway = null;
+        doStaticConfigurationParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcelStaticConfiguration_NullDomains() {
+        mStaticIpConfiguration.domains = null;
+        doStaticConfigurationParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcelStaticConfiguration_EmptyDomains() {
+        mStaticIpConfiguration.domains = "";
+        doStaticConfigurationParcelUnparcelTest();
+    }
+
+    private void doStaticConfigurationParcelUnparcelTest() {
+        final StaticIpConfiguration unparceled =
+                fromStableParcelable(toStableParcelable(mStaticIpConfiguration));
+        assertEquals(mStaticIpConfiguration, unparceled);
+    }
+
+    @Test
+    public void testParcelUnparcelDhcpResults() {
+        doDhcpResultsParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcelDhcpResults_NullServerAddress() {
+        mDhcpResults.serverAddress = null;
+        doDhcpResultsParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcelDhcpResults_NullVendorInfo() {
+        mDhcpResults.vendorInfo = null;
+        doDhcpResultsParcelUnparcelTest();
+    }
+
+    private void doDhcpResultsParcelUnparcelTest() {
+        final DhcpResults unparceled = fromStableParcelable(toStableParcelable(mDhcpResults));
+        assertEquals(mDhcpResults, unparceled);
+    }
+
+    @Test
+    public void testParcelUnparcelApfCapabilities() {
+        final ApfCapabilities caps = new ApfCapabilities(123, 456, 789);
+        assertEquals(caps, fromStableParcelable(toStableParcelable(caps)));
+    }
+}
diff --git a/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
new file mode 100644
index 0000000..b6d01db
--- /dev/null
+++ b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
+import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable;
+import static android.net.shared.ParcelableTestUtil.assertFieldCountEquals;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.ProxyInfo;
+import android.net.RouteInfo;
+import android.net.Uri;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Tests for {@link LinkPropertiesParcelableUtil}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LinkPropertiesParcelableUtilTest {
+    private LinkProperties mLinkProperties;
+
+    private static final String TEST_LINKPROPS_IFACE = "TEST_IFACE";
+
+    @Before
+    public void setUp() {
+        mLinkProperties = new LinkProperties();
+        mLinkProperties.setInterfaceName(TEST_LINKPROPS_IFACE);
+        mLinkProperties.setLinkAddresses(Arrays.asList(
+                new LinkAddress(InetAddresses.parseNumericAddress("192.168.0.42"), 16),
+                new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::7"), 42)));
+        mLinkProperties.setDnsServers(Arrays.asList(
+                InetAddresses.parseNumericAddress("2001:db8::42"),
+                InetAddresses.parseNumericAddress("192.168.1.1")
+        ));
+        mLinkProperties.setValidatedPrivateDnsServers(Arrays.asList(
+                InetAddresses.parseNumericAddress("2001:db8::43"),
+                InetAddresses.parseNumericAddress("192.168.42.43")
+        ));
+        mLinkProperties.setPcscfServers(Arrays.asList(
+                InetAddresses.parseNumericAddress("2001:db8::47"),
+                InetAddresses.parseNumericAddress("192.168.42.47")
+        ));
+        mLinkProperties.setUsePrivateDns(true);
+        mLinkProperties.setPrivateDnsServerName("test.example.com");
+        mLinkProperties.setDomains("test1.example.com,test2.example.com");
+        mLinkProperties.addRoute(new RouteInfo(
+                new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::44"), 45),
+                InetAddresses.parseNumericAddress("2001:db8::45"),
+                TEST_LINKPROPS_IFACE,
+                RouteInfo.RTN_UNICAST
+        ));
+        mLinkProperties.addRoute(new RouteInfo(
+                new IpPrefix(InetAddresses.parseNumericAddress("192.168.44.45"), 16),
+                InetAddresses.parseNumericAddress("192.168.45.1"),
+                TEST_LINKPROPS_IFACE,
+                RouteInfo.RTN_THROW
+        ));
+        mLinkProperties.setHttpProxy(new ProxyInfo("test3.example.com", 8000,
+                "excl1.example.com,excl2.example.com"));
+        mLinkProperties.setMtu(5000);
+        mLinkProperties.setTcpBufferSizes("1,2,3,4,5,6");
+        mLinkProperties.setNat64Prefix(
+                new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::48"), 96));
+
+        // Verify that this test does not miss any new field added later.
+        // If any added field is not included in LinkProperties#equals, assertLinkPropertiesEquals
+        // must also be updated.
+        assertFieldCountEquals(14, LinkProperties.class);
+    }
+
+    @Test
+    public void testParcelUnparcel() {
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullInterface() {
+        mLinkProperties.setInterfaceName(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullPrivateDnsServer() {
+        mLinkProperties.setPrivateDnsServerName(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullDomains() {
+        mLinkProperties.setDomains(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullProxy() {
+        mLinkProperties.setHttpProxy(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullTcpBufferSizes() {
+        mLinkProperties.setTcpBufferSizes(null);
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyLinkAddresses() {
+        mLinkProperties.setLinkAddresses(Collections.emptyList());
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyDnses() {
+        mLinkProperties.setDnsServers(Collections.emptyList());
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyValidatedPrivateDnses() {
+        mLinkProperties.setValidatedPrivateDnsServers(Collections.emptyList());
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_EmptyRoutes() {
+        for (RouteInfo r : mLinkProperties.getAllRoutes()) {
+            mLinkProperties.removeRoute(r);
+        }
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_PacFileProxyInfo() {
+        mLinkProperties.setHttpProxy(new ProxyInfo(Uri.parse("http://pacfile.example.com")));
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullNat64Prefix() {
+        mLinkProperties.setNat64Prefix(null);
+        doParcelUnparcelTest();
+    }
+
+    private void doParcelUnparcelTest() {
+        final LinkProperties unparceled = fromStableParcelable(toStableParcelable(mLinkProperties));
+        assertLinkPropertiesEquals(mLinkProperties, unparceled);
+    }
+
+    private static void assertLinkPropertiesEquals(LinkProperties expected, LinkProperties actual) {
+        assertEquals(expected, actual);
+
+        // Equality on stacked links is not tested as they should not be passed to processes using
+        // LinkPropertiesParcelable.
+    }
+}
diff --git a/tests/net/java/android/net/shared/ParcelableTestUtil.java b/tests/net/java/android/net/shared/ParcelableTestUtil.java
new file mode 100644
index 0000000..088ea3c
--- /dev/null
+++ b/tests/net/java/android/net/shared/ParcelableTestUtil.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static org.junit.Assert.assertEquals;
+
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+
+/**
+ * Utility classes to write tests for stable AIDL parceling/unparceling
+ */
+public final class ParcelableTestUtil {
+
+    /**
+     * Verifies that the number of nonstatic fields in a class equals a given count.
+     *
+     * <p>This assertion serves as a reminder to update test code around it if fields are added
+     * after the test is written.
+     * @param count Expected number of nonstatic fields in the class.
+     * @param clazz Class to test.
+     */
+    public static <T> void assertFieldCountEquals(int count, Class<T> clazz) {
+        assertEquals(count, Arrays.stream(clazz.getDeclaredFields())
+                .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
+    }
+}
diff --git a/tests/net/java/android/net/shared/ProvisioningConfigurationTest.java b/tests/net/java/android/net/shared/ProvisioningConfigurationTest.java
new file mode 100644
index 0000000..6ea47d2
--- /dev/null
+++ b/tests/net/java/android/net/shared/ProvisioningConfigurationTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static android.net.InetAddresses.parseNumericAddress;
+import static android.net.shared.ParcelableTestUtil.assertFieldCountEquals;
+import static android.net.shared.ProvisioningConfiguration.fromStableParcelable;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.net.LinkAddress;
+import android.net.Network;
+import android.net.StaticIpConfiguration;
+import android.net.apf.ApfCapabilities;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.Consumer;
+
+/**
+ * Tests for {@link ProvisioningConfiguration}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ProvisioningConfigurationTest {
+    private ProvisioningConfiguration mConfig;
+
+    @Before
+    public void setUp() {
+        mConfig = new ProvisioningConfiguration();
+        mConfig.mEnableIPv4 = true;
+        mConfig.mEnableIPv6 = true;
+        mConfig.mUsingMultinetworkPolicyTracker = true;
+        mConfig.mUsingIpReachabilityMonitor = true;
+        mConfig.mRequestedPreDhcpActionMs = 42;
+        mConfig.mInitialConfig = new InitialConfiguration();
+        mConfig.mInitialConfig.ipAddresses.add(
+                new LinkAddress(parseNumericAddress("192.168.42.42"), 24));
+        mConfig.mStaticIpConfig = new StaticIpConfiguration();
+        mConfig.mStaticIpConfig.ipAddress =
+                new LinkAddress(parseNumericAddress("2001:db8::42"), 90);
+        // Not testing other InitialConfig or StaticIpConfig members: they have their own unit tests
+        mConfig.mApfCapabilities = new ApfCapabilities(1, 2, 3);
+        mConfig.mProvisioningTimeoutMs = 4200;
+        mConfig.mIPv6AddrGenMode = 123;
+        mConfig.mNetwork = new Network(321);
+        mConfig.mDisplayName = "test_config";
+        // Any added field must be included in equals() to be tested properly
+        assertFieldCountEquals(12, ProvisioningConfiguration.class);
+    }
+
+    @Test
+    public void testParcelUnparcel() {
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullInitialConfiguration() {
+        mConfig.mInitialConfig = null;
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullStaticConfiguration() {
+        mConfig.mStaticIpConfig = null;
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullApfCapabilities() {
+        mConfig.mApfCapabilities = null;
+        doParcelUnparcelTest();
+    }
+
+    @Test
+    public void testParcelUnparcel_NullNetwork() {
+        mConfig.mNetwork = null;
+        doParcelUnparcelTest();
+    }
+
+    private void doParcelUnparcelTest() {
+        final ProvisioningConfiguration unparceled =
+                fromStableParcelable(mConfig.toStableParcelable());
+        assertEquals(mConfig, unparceled);
+    }
+
+    @Test
+    public void testEquals() {
+        assertEquals(mConfig, new ProvisioningConfiguration(mConfig));
+
+        assertNotEqualsAfterChange(c -> c.mEnableIPv4 = false);
+        assertNotEqualsAfterChange(c -> c.mEnableIPv6 = false);
+        assertNotEqualsAfterChange(c -> c.mUsingMultinetworkPolicyTracker = false);
+        assertNotEqualsAfterChange(c -> c.mUsingIpReachabilityMonitor = false);
+        assertNotEqualsAfterChange(c -> c.mRequestedPreDhcpActionMs++);
+        assertNotEqualsAfterChange(c -> c.mInitialConfig.ipAddresses.add(
+                new LinkAddress(parseNumericAddress("192.168.47.47"), 16)));
+        assertNotEqualsAfterChange(c -> c.mInitialConfig = null);
+        assertNotEqualsAfterChange(c -> c.mStaticIpConfig.ipAddress =
+                new LinkAddress(parseNumericAddress("2001:db8::47"), 64));
+        assertNotEqualsAfterChange(c -> c.mStaticIpConfig = null);
+        assertNotEqualsAfterChange(c -> c.mApfCapabilities = new ApfCapabilities(4, 5, 6));
+        assertNotEqualsAfterChange(c -> c.mApfCapabilities = null);
+        assertNotEqualsAfterChange(c -> c.mProvisioningTimeoutMs++);
+        assertNotEqualsAfterChange(c -> c.mIPv6AddrGenMode++);
+        assertNotEqualsAfterChange(c -> c.mNetwork = new Network(123));
+        assertNotEqualsAfterChange(c -> c.mNetwork = null);
+        assertNotEqualsAfterChange(c -> c.mDisplayName = "other_test");
+        assertNotEqualsAfterChange(c -> c.mDisplayName = null);
+        assertFieldCountEquals(12, ProvisioningConfiguration.class);
+    }
+
+    private void assertNotEqualsAfterChange(Consumer<ProvisioningConfiguration> mutator) {
+        final ProvisioningConfiguration newConfig = new ProvisioningConfiguration(mConfig);
+        mutator.accept(newConfig);
+        assertNotEquals(mConfig, newConfig);
+    }
+}
diff --git a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java b/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java
deleted file mode 100644
index f9b7ec8..0000000
--- a/tests/net/java/android/net/util/ConnectivityPacketSummaryTest.java
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util;
-
-import static android.net.util.NetworkConstants.*;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.net.MacAddress;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.filters.SmallTest;
-
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
-import libcore.util.HexEncoding;
-
-/**
- * Tests for ConnectivityPacketSummary.
- *
- * @hide
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ConnectivityPacketSummaryTest {
-    private static final MacAddress MYHWADDR = MacAddress.fromString("80:7a:bf:6f:48:f3");
-
-    private String getSummary(String hexBytes) {
-        hexBytes = hexBytes.replaceAll("\\s+", "");
-        final byte[] bytes = HexEncoding.decode(hexBytes.toCharArray(), false);
-        return ConnectivityPacketSummary.summarize(MYHWADDR, bytes);
-    }
-
-    @Test
-    public void testParseICMPv6DADProbe() {
-        final String packet =
-                // Ethernet
-                "3333FF6F48F3 807ABF6F48F3 86DD" +
-                // IPv6
-                "600000000018 3A FF" +
-                "00000000000000000000000000000000" +
-                "FF0200000000000000000001FF6F48F3" +
-                // ICMPv6
-                "87 00 A8E7" +
-                "00000000" +
-                "FE80000000000000827ABFFFFE6F48F3";
-
-        final String expected =
-                "TX 80:7a:bf:6f:48:f3 > 33:33:ff:6f:48:f3 ipv6" +
-                " :: > ff02::1:ff6f:48f3 icmp6" +
-                " ns fe80::827a:bfff:fe6f:48f3";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseICMPv6RS() {
-        final String packet =
-                // Ethernet
-                "333300000002 807ABF6F48F3 86DD" +
-                // IPv6
-                "600000000010 3A FF" +
-                "FE80000000000000827ABFFFFE6F48F3" +
-                "FF020000000000000000000000000002" +
-                // ICMPv6 RS
-                "85 00 6973" +
-                "00000000" +
-                "01 01 807ABF6F48F3";
-
-        final String expected =
-                "TX 80:7a:bf:6f:48:f3 > 33:33:00:00:00:02 ipv6" +
-                " fe80::827a:bfff:fe6f:48f3 > ff02::2 icmp6" +
-                " rs slla 80:7a:bf:6f:48:f3";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseICMPv6RA() {
-        final String packet =
-                // Ethernet
-                "807ABF6F48F3 100E7E263FC1 86DD" +
-                // IPv6
-                "600000000068 3A FF" +
-                "FE80000000000000FA000004FD000001" +
-                "FE80000000000000827ABFFFFE6F48F3" +
-                // ICMPv6 RA
-                "86 00 8141" +
-                "40 00 0E10" +
-                "00000000" +
-                "00000000" +
-                "01 01 00005E000265" +
-                "05 01 0000000005DC" +
-                "19 05 000000000E10" +
-                "      20014860486000000000000000008844" +
-                "      20014860486000000000000000008888" +
-                "03 04 40 C0" +
-                "      00278D00" +
-                "      00093A80" +
-                "      00000000" +
-                "      2401FA000004FD000000000000000000";
-
-        final String expected =
-                "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
-                " fe80::fa00:4:fd00:1 > fe80::827a:bfff:fe6f:48f3 icmp6" +
-                " ra slla 00:00:5e:00:02:65 mtu 1500";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseICMPv6NS() {
-        final String packet =
-                // Ethernet
-                  "807ABF6F48F3 100E7E263FC1 86DD" +
-                  // IPv6
-                  "6C0000000020 3A FF" +
-                  "FE80000000000000FA000004FD000001" +
-                  "FF0200000000000000000001FF01C146" +
-                  // ICMPv6 NS
-                  "87 00 8AD4" +
-                  "00000000" +
-                  "2401FA000004FD0015EA6A5C7B01C146" +
-                  "01 01 00005E000265";
-
-        final String expected =
-                "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
-                " fe80::fa00:4:fd00:1 > ff02::1:ff01:c146 icmp6" +
-                " ns 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 slla 00:00:5e:00:02:65";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testInvalidICMPv6NDLength() {
-        final String packet =
-                // Ethernet
-                "807ABF6F48F3 100E7E263FC1 86DD" +
-                // IPv6
-                "600000000068 3A FF" +
-                "FE80000000000000FA000004FD000001" +
-                "FE80000000000000827ABFFFFE6F48F3" +
-                // ICMPv6 RA
-                "86 00 8141" +
-                "40 00 0E10" +
-                "00000000" +
-                "00000000" +
-                "01 01 00005E000265" +
-                "00 00 0102030405D6";
-
-        final String expected =
-                "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
-                " fe80::fa00:4:fd00:1 > fe80::827a:bfff:fe6f:48f3 icmp6" +
-                " ra slla 00:00:5e:00:02:65 <malformed>";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseICMPv6NA() {
-        final String packet =
-                // Ethernet
-                "00005E000265 807ABF6F48F3 86DD" +
-                "600000000020 3A FF" +
-                "2401FA000004FD0015EA6A5C7B01C146" +
-                "FE80000000000000FA000004FD000001" +
-                "88 00 E8126" +
-                "0000000" +
-                "2401FA000004FD0015EA6A5C7B01C146" +
-                "02 01 807ABF6F48F3";
-
-        final String expected =
-                "TX 80:7a:bf:6f:48:f3 > 00:00:5e:00:02:65 ipv6" +
-                " 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 > fe80::fa00:4:fd00:1 icmp6" +
-                " na 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 tlla 80:7a:bf:6f:48:f3";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseARPRequest() {
-        final String packet =
-                // Ethernet
-                  "FFFFFFFFFFFF 807ABF6F48F3 0806" +
-                  // ARP
-                  "0001 0800 06 04" +
-                  // Request
-                  "0001" +
-                  "807ABF6F48F3 64706ADB" +
-                  "000000000000 64706FFD";
-
-        final String expected =
-                "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff arp" +
-                " who-has 100.112.111.253";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseARPReply() {
-        final String packet =
-                // Ethernet
-                  "807ABF6F48F3 288A1CA8DFC1 0806" +
-                  // ARP
-                  "0001 0800 06 04" +
-                  // Reply
-                  "0002" +
-                  "288A1CA8DFC1 64706FFD"+
-                  "807ABF6F48F3 64706ADB" +
-                  // Ethernet padding to packet min size.
-                  "0000000000000000000000000000";
-
-        final String expected =
-                "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 arp" +
-                " reply 100.112.111.253 28:8a:1c:a8:df:c1";
-
-        assertEquals(expected, getSummary(packet));
-    }
-
-    @Test
-    public void testParseDHCPv4Discover() {
-        final String packet =
-                // Ethernet
-                "FFFFFFFFFFFF 807ABF6F48F3 0800" +
-                // IPv4
-                "451001580000400040113986" +
-                "00000000" +
-                "FFFFFFFF" +
-                // UDP
-                "0044 0043" +
-                "0144 5559" +
-                // DHCPv4
-                "01 01 06 00" +
-                "79F7ACA4" +
-                "0000 0000" +
-                "00000000" +
-                "00000000" +
-                "00000000" +
-                "00000000" +
-                "807ABF6F48F300000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "63 82 53 63" +
-                "35 01 01" +
-                "3D 07 01807ABF6F48F3" +
-                "39 02 05DC" +
-                "3C 12 616E64726F69642D646863702D372E312E32" +
-                "0C 18 616E64726F69642D36623030366333313333393835343139" +
-                "37 0A 01 03 06 0F 1A 1C 33 3A 3B 2B" +
-                "FF" +
-                "00";
-
-        final String expectedPrefix =
-                "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff ipv4" +
-                " 0.0.0.0 > 255.255.255.255 udp" +
-                " 68 > 67 dhcp4" +
-                " 80:7a:bf:6f:48:f3 DISCOVER";
-
-        assertTrue(getSummary(packet).startsWith(expectedPrefix));
-    }
-
-    @Test
-    public void testParseDHCPv4Offer() {
-        final String packet =
-                // Ethernet
-                "807ABF6F48F3 288A1CA8DFC1 0800" +
-                // IPv4
-                "4500013D4D2C0000401188CB" +
-                "64706FFD" +
-                "64706ADB" +
-                // UDP
-                "0043 0044" +
-                "0129 371D" +
-                // DHCPv4
-                "02 01 06 01" +
-                "79F7ACA4" +
-                "0000 0000" +
-                "00000000" +
-                "64706ADB" +
-                "00000000" +
-                "00000000" +
-                "807ABF6F48F300000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "63 82 53 63" +
-                "35 01 02" +
-                "36 04 AC188A0B" +
-                "33 04 00000708" +
-                "01 04 FFFFF000" +
-                "03 04 64706FFE" +
-                "06 08 08080808" +
-                "      08080404" +
-                "FF0001076165313A363636FF";
-
-        final String expectedPrefix =
-                "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 ipv4" +
-                " 100.112.111.253 > 100.112.106.219 udp" +
-                " 67 > 68 dhcp4" +
-                " 80:7a:bf:6f:48:f3 OFFER";
-
-        assertTrue(getSummary(packet).startsWith(expectedPrefix));
-    }
-
-    @Test
-    public void testParseDHCPv4Request() {
-        final String packet =
-                // Ethernet
-                "FFFFFFFFFFFF 807ABF6F48F3 0800" +
-                // IPv4
-                "45100164000040004011397A" +
-                "00000000" +
-                "FFFFFFFF" +
-                // UDP
-                "0044 0043" +
-                "0150 E5C7" +
-                // DHCPv4
-                "01 01 06 00" +
-                "79F7ACA4" +
-                "0001 0000" +
-                "00000000" +
-                "00000000" +
-                "00000000" +
-                "00000000" +
-                "807ABF6F48F300000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "63 82 53 63" +
-                "35 01 03" +
-                "3D 07 01807ABF6F48F3" +
-                "32 04 64706ADB" +
-                "36 04 AC188A0B" +
-                "39 02 05DC" +
-                "3C 12 616E64726F69642D646863702D372E312E32" +
-                "0C 18 616E64726F69642D36623030366333313333393835343139" +
-                "37 0A 01 03 06 0F 1A 1C 33 3A 3B 2B" +
-                "FF" +
-                "00";
-
-        final String expectedPrefix =
-                "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff ipv4" +
-                " 0.0.0.0 > 255.255.255.255 udp" +
-                " 68 > 67 dhcp4" +
-                " 80:7a:bf:6f:48:f3 REQUEST";
-
-        assertTrue(getSummary(packet).startsWith(expectedPrefix));
-    }
-
-    @Test
-    public void testParseDHCPv4Ack() {
-        final String packet =
-                // Ethernet
-                "807ABF6F48F3 288A1CA8DFC1 0800" +
-                // IPv4
-                "4500013D4D3B0000401188BC" +
-                "64706FFD" +
-                "64706ADB" +
-                // UDP
-                "0043 0044" +
-                "0129 341C" +
-                // DHCPv4
-                "02 01 06 01" +
-                "79F7ACA4" +
-                "0001 0000" +
-                "00000000" +
-                "64706ADB" +
-                "00000000" +
-                "00000000" +
-                "807ABF6F48F300000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "0000000000000000000000000000000000000000000000000000000000000000" +
-                "63 82 53 63" +
-                "35 01 05" +
-                "36 04 AC188A0B" +
-                "33 04 00000708" +
-                "01 04 FFFFF000" +
-                "03 04 64706FFE" +
-                "06 08 08080808" +
-                "      08080404" +
-                "FF0001076165313A363636FF";
-
-        final String expectedPrefix =
-                "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 ipv4" +
-                " 100.112.111.253 > 100.112.106.219 udp" +
-                " 67 > 68 dhcp4" +
-                " 80:7a:bf:6f:48:f3 ACK";
-
-        assertTrue(getSummary(packet).startsWith(expectedPrefix));
-    }
-}
diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
index 788924b..90bf7b1 100644
--- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -159,7 +159,7 @@
         assertStatsEntry(stats, "v4-wlan0", 1000, SET_DEFAULT, 0x0, 30812L, 2310L);
         assertStatsEntry(stats, "v4-wlan0", 10102, SET_DEFAULT, 0x0, 10022L, 3330L);
         assertStatsEntry(stats, "v4-wlan0", 10060, SET_DEFAULT, 0x0, 9532772L, 254112L);
-        assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 15229L, 5766L);
+        assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 15229L, 0L);
         assertStatsEntry(stats, "wlan0", 1000, SET_DEFAULT, 0x0, 6126L, 2013L);
         assertStatsEntry(stats, "wlan0", 10013, SET_DEFAULT, 0x0, 0L, 144L);
         assertStatsEntry(stats, "wlan0", 10018, SET_DEFAULT, 0x0, 5980263L, 167667L);
@@ -170,6 +170,8 @@
         assertStatsEntry(stats, "dummy0", 0, SET_DEFAULT, 0x0, 0L, 168L);
         assertStatsEntry(stats, "lo", 0, SET_DEFAULT, 0x0, 1288L, 1288L);
 
+        assertNoStatsEntry(stats, "wlan0", 1029, SET_DEFAULT, 0x0);
+
         NetworkStatsFactory.clearStackedIfaces();
     }
 
@@ -191,12 +193,12 @@
         // Stats snapshot before the download
         stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_before);
         assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesBefore, 5199872L);
-        assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesBefore, 647888L);
+        assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesBefore, 0L);
 
         // Stats snapshot after the download
         stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_after);
         assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesAfter, 7867488L);
-        assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesAfter, 647587L);
+        assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesAfter, 0L);
 
         NetworkStatsFactory.clearStackedIfaces();
     }
@@ -252,6 +254,15 @@
         assertEquals("unexpected txBytes", txBytes, entry.txBytes);
     }
 
+    private static void assertNoStatsEntry(NetworkStats stats, String iface, int uid, int set,
+            int tag) {
+        final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO,
+                DEFAULT_NETWORK_NO);
+        if (i >= 0) {
+            fail("unexpected NetworkStats entry at " + i);
+        }
+    }
+
     private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
             int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) {
         final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO,
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 71529fd..b5d5f61 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -26,6 +26,8 @@
 import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
 import static android.net.ConnectivityManager.TYPE_NONE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID;
+import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
@@ -69,17 +71,19 @@
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -89,7 +93,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Resources;
-import android.net.CaptivePortal;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.ConnectivityManager.PacketKeepalive;
@@ -97,11 +100,15 @@
 import android.net.ConnectivityManager.TooManyRequestsException;
 import android.net.ConnectivityThread;
 import android.net.INetd;
+import android.net.INetworkMonitor;
+import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkPolicyListener;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
 import android.net.InterfaceConfiguration;
 import android.net.IpPrefix;
+import android.net.IpSecManager;
+import android.net.IpSecManager.UdpEncapsulationSocket;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.MatchAllNetworkSpecifier;
@@ -114,12 +121,14 @@
 import android.net.NetworkMisc;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
+import android.net.NetworkStack;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
-import android.net.StringNetworkSpecifier;
+import android.net.SocketKeepalive;
 import android.net.UidRange;
-import android.net.captiveportal.CaptivePortalProbeResult;
 import android.net.metrics.IpConnectivityLog;
+import android.net.shared.NetworkMonitorUtils;
+import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
 import android.os.ConditionVariable;
 import android.os.Handler;
@@ -138,6 +147,7 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.mock.MockContentResolver;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -148,12 +158,9 @@
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.connectivity.ConnectivityConstants;
 import com.android.server.connectivity.DefaultNetworkMetrics;
-import com.android.server.connectivity.DnsManager;
 import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.MockableSystemProperties;
 import com.android.server.connectivity.Nat464Xlat;
-import com.android.server.connectivity.NetworkAgentInfo;
-import com.android.server.connectivity.NetworkMonitor;
 import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
 import com.android.server.net.NetworkPinner;
@@ -168,6 +175,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
+import org.mockito.stubbing.Answer;
 
 import java.net.Inet4Address;
 import java.net.InetAddress;
@@ -181,6 +189,8 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -230,6 +240,7 @@
     @Mock INetworkStatsService mStatsService;
     @Mock INetworkPolicyManager mNpm;
     @Mock INetd mMockNetd;
+    @Mock NetworkStack mNetworkStack;
 
     private ArgumentCaptor<String[]> mStringArrayCaptor = ArgumentCaptor.forClass(String[].class);
 
@@ -299,6 +310,7 @@
         public Object getSystemService(String name) {
             if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
             if (Context.NOTIFICATION_SERVICE.equals(name)) return mock(NotificationManager.class);
+            if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack;
             return super.getSystemService(name);
         }
 
@@ -386,7 +398,7 @@
     }
 
     private class MockNetworkAgent {
-        private final WrappedNetworkMonitor mWrappedNetworkMonitor;
+        private final INetworkMonitor mNetworkMonitor;
         private final NetworkInfo mNetworkInfo;
         private final NetworkCapabilities mNetworkCapabilities;
         private final HandlerThread mHandlerThread;
@@ -395,13 +407,33 @@
         private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
         private int mScore;
         private NetworkAgent mNetworkAgent;
-        private int mStartKeepaliveError = PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED;
-        private int mStopKeepaliveError = PacketKeepalive.NO_KEEPALIVE;
+        private int mStartKeepaliveError = SocketKeepalive.ERROR_HARDWARE_UNSUPPORTED;
+        private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
         private Integer mExpectedKeepaliveSlot = null;
         // Contains the redirectUrl from networkStatus(). Before reading, wait for
         // mNetworkStatusReceived.
         private String mRedirectUrl;
 
+        private INetworkMonitorCallbacks mNmCallbacks;
+        private int mNmValidationResult = NETWORK_TEST_RESULT_INVALID;
+        private String mNmValidationRedirectUrl = null;
+        private boolean mNmProvNotificationRequested = false;
+
+        void setNetworkValid() {
+            mNmValidationResult = NETWORK_TEST_RESULT_VALID;
+            mNmValidationRedirectUrl = null;
+        }
+
+        void setNetworkInvalid() {
+            mNmValidationResult = NETWORK_TEST_RESULT_INVALID;
+            mNmValidationRedirectUrl = null;
+        }
+
+        void setNetworkPortal(String redirectUrl) {
+            setNetworkInvalid();
+            mNmValidationRedirectUrl = redirectUrl;
+        }
+
         MockNetworkAgent(int transport) {
             this(transport, new LinkProperties());
         }
@@ -434,6 +466,29 @@
             }
             mHandlerThread = new HandlerThread("Mock-" + typeName);
             mHandlerThread.start();
+
+            mNetworkMonitor = mock(INetworkMonitor.class);
+            final Answer validateAnswer = inv -> {
+                new Thread(this::onValidationRequested).start();
+                return null;
+            };
+
+            try {
+                doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected();
+                doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt());
+            } catch (RemoteException e) {
+                fail(e.getMessage());
+            }
+
+            final ArgumentCaptor<Network> nmNetworkCaptor =
+                    ArgumentCaptor.forClass(Network.class);
+            final ArgumentCaptor<INetworkMonitorCallbacks> nmCbCaptor =
+                    ArgumentCaptor.forClass(INetworkMonitorCallbacks.class);
+            doNothing().when(mNetworkStack).makeNetworkMonitor(
+                    nmNetworkCaptor.capture(),
+                    any() /* name */,
+                    nmCbCaptor.capture());
+
             mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext,
                     "Mock-" + typeName, mNetworkInfo, mNetworkCapabilities,
                     linkProperties, mScore, new NetworkMisc()) {
@@ -465,10 +520,40 @@
                     mPreventReconnectReceived.open();
                 }
             };
+
+            assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId);
+            mNmCallbacks = nmCbCaptor.getValue();
+
+            try {
+                mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor);
+            } catch (RemoteException e) {
+                fail(e.getMessage());
+            }
+
             // Waits for the NetworkAgent to be registered, which includes the creation of the
             // NetworkMonitor.
             waitForIdle();
-            mWrappedNetworkMonitor = mService.getLastCreatedWrappedNetworkMonitor();
+        }
+
+        private void onValidationRequested() {
+            try {
+                if (mNmProvNotificationRequested
+                        && mNmValidationResult == NETWORK_TEST_RESULT_VALID) {
+                    mNmCallbacks.hideProvisioningNotification();
+                    mNmProvNotificationRequested = false;
+                }
+
+                mNmCallbacks.notifyNetworkTested(
+                        mNmValidationResult, mNmValidationRedirectUrl);
+
+                if (mNmValidationRedirectUrl != null) {
+                    mNmCallbacks.showProvisioningNotification(
+                            "test_provisioning_notif_action");
+                    mNmProvNotificationRequested = true;
+                }
+            } catch (RemoteException e) {
+                fail(e.getMessage());
+            }
         }
 
         public void adjustScore(int change) {
@@ -539,7 +624,7 @@
             NetworkCallback callback = null;
             final ConditionVariable validatedCv = new ConditionVariable();
             if (validated) {
-                mWrappedNetworkMonitor.gen204ProbeResult = 204;
+                setNetworkValid();
                 NetworkRequest request = new NetworkRequest.Builder()
                         .addTransportType(mNetworkCapabilities.getTransportTypes()[0])
                         .clearCapabilities()
@@ -564,15 +649,14 @@
             if (validated) {
                 // Wait for network to validate.
                 waitFor(validatedCv);
-                mWrappedNetworkMonitor.gen204ProbeResult = 500;
+                setNetworkInvalid();
             }
 
             if (callback != null) mCm.unregisterNetworkCallback(callback);
         }
 
         public void connectWithCaptivePortal(String redirectUrl) {
-            mWrappedNetworkMonitor.gen204ProbeResult = 200;
-            mWrappedNetworkMonitor.gen204ProbeRedirectUrl = redirectUrl;
+            setNetworkPortal(redirectUrl);
             connect(false);
         }
 
@@ -603,10 +687,6 @@
             return mDisconnected;
         }
 
-        public WrappedNetworkMonitor getWrappedNetworkMonitor() {
-            return mWrappedNetworkMonitor;
-        }
-
         public void sendLinkProperties(LinkProperties lp) {
             mNetworkAgent.sendLinkProperties(lp);
         }
@@ -880,28 +960,6 @@
         }
     }
 
-    // NetworkMonitor implementation allowing overriding of Internet connectivity probe result.
-    private class WrappedNetworkMonitor extends NetworkMonitor {
-        public final Handler connectivityHandler;
-        // HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
-        public int gen204ProbeResult = 500;
-        public String gen204ProbeRedirectUrl = null;
-
-        public WrappedNetworkMonitor(Context context, Handler handler,
-                NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest,
-                IpConnectivityLog log) {
-            super(context, handler, networkAgentInfo, defaultRequest, log,
-                    NetworkMonitor.Dependencies.DEFAULT);
-            connectivityHandler = handler;
-        }
-
-        @Override
-        protected CaptivePortalProbeResult isCaptivePortal() {
-            if (!mIsCaptivePortalCheckEnabled) { return new CaptivePortalProbeResult(204); }
-            return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null);
-        }
-    }
-
     private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
         public volatile boolean configRestrictsAvoidBadWifi;
         public volatile int configMeteredMultipathPreference;
@@ -923,7 +981,6 @@
 
     private class WrappedConnectivityService extends ConnectivityService {
         public WrappedMultinetworkPolicyTracker wrappedMultinetworkPolicyTracker;
-        private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
         private MockableSystemProperties mSystemProperties;
 
         public WrappedConnectivityService(Context context, INetworkManagementService netManager,
@@ -971,15 +1028,6 @@
             }
         }
 
-        @Override
-        public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
-                NetworkAgentInfo nai, NetworkRequest defaultRequest) {
-            final WrappedNetworkMonitor monitor = new WrappedNetworkMonitor(
-                    context, handler, nai, defaultRequest, mock(IpConnectivityLog.class));
-            mLastCreatedNetworkMonitor = monitor;
-            return monitor;
-        }
-
         public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) {
             return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
         }
@@ -1017,10 +1065,6 @@
         protected void registerNetdEventCallback() {
         }
 
-        public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
-            return mLastCreatedNetworkMonitor;
-        }
-
         public void mockVpn(int uid) {
             synchronized (mVpns) {
                 int userId = UserHandle.getUserId(uid);
@@ -1469,6 +1513,12 @@
         verifyActiveNetwork(TRANSPORT_WIFI);
     }
 
+    @Test
+    public void testRequiresValidation() {
+        assertTrue(NetworkMonitorUtils.isValidationRequired(
+                mCm.getDefaultRequest().networkCapabilities));
+    }
+
     enum CallbackState {
         NONE,
         AVAILABLE,
@@ -2439,7 +2489,7 @@
 
         // Make captive portal disappear then revalidate.
         // Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
-        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204;
+        mWiFiNetworkAgent.setNetworkValid();
         mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
         captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
@@ -2448,13 +2498,13 @@
 
         // Break network connectivity.
         // Expect NET_CAPABILITY_VALIDATED onLost callback.
-        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 500;
+        mWiFiNetworkAgent.setNetworkInvalid();
         mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
         validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
     }
 
     @Test
-    public void testCaptivePortalApp() {
+    public void testCaptivePortalApp() throws RemoteException {
         final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
         final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
                 .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
@@ -2477,21 +2527,19 @@
         mServiceContext.expectNoStartActivityIntent(fastTimeoutMs);
 
         // Turn into a captive portal.
-        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 302;
+        mWiFiNetworkAgent.setNetworkPortal("http://example.com");
         mCm.reportNetworkConnectivity(wifiNetwork, false);
         captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
-        // Check that startCaptivePortalApp sends the expected intent.
+        // Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
         mCm.startCaptivePortalApp(wifiNetwork);
-        Intent intent = mServiceContext.expectStartActivityIntent(TIMEOUT_MS);
-        assertEquals(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN, intent.getAction());
-        assertEquals(wifiNetwork, intent.getExtra(ConnectivityManager.EXTRA_NETWORK));
+        verify(mWiFiNetworkAgent.mNetworkMonitor, timeout(TIMEOUT_MS).times(1))
+                .launchCaptivePortalApp();
 
-        // Have the app report that the captive portal is dismissed, and check that we revalidate.
-        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204;
-        CaptivePortal c = (CaptivePortal) intent.getExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
-        c.reportCaptivePortalDismissed();
+        // Report that the captive portal is dismissed, and check that callbacks are fired
+        mWiFiNetworkAgent.setNetworkValid();
+        mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
         validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
         captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
 
@@ -2524,36 +2572,82 @@
         waitFor(avoidCv);
 
         assertNoCallbacks(captivePortalCallback, validatedCallback);
-
-        // Now test ignore mode.
-        setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE);
-
-        // Bring up a network with a captive portal.
-        // Since we're ignoring captive portals, the network will validate.
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
-        String secondRedirectUrl = "http://example.com/secondPath";
-        mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
-
-        // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
-        validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
-        // But there should be no CaptivePortal callback.
-        captivePortalCallback.assertNoCallback();
     }
 
     private NetworkRequest.Builder newWifiRequestBuilder() {
         return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
     }
 
+    /**
+     * Verify request matching behavior with network specifiers.
+     *
+     * Note: this test is somewhat problematic since it involves removing capabilities from
+     * agents - i.e. agents rejecting requests which they previously accepted. This is flagged
+     * as a WTF bug in
+     * {@link ConnectivityService#mixInCapabilities(NetworkAgentInfo, NetworkCapabilities)} but
+     * does work.
+     */
     @Test
     public void testNetworkSpecifier() {
+        // A NetworkSpecifier subclass that matches all networks but must not be visible to apps.
+        class ConfidentialMatchAllNetworkSpecifier extends NetworkSpecifier implements
+                Parcelable {
+            @Override
+            public boolean satisfiedBy(NetworkSpecifier other) {
+                return true;
+            }
+
+            @Override
+            public int describeContents() {
+                return 0;
+            }
+
+            @Override
+            public void writeToParcel(Parcel dest, int flags) {}
+
+            @Override
+            public NetworkSpecifier redact() {
+                return null;
+            }
+        }
+
+        // A network specifier that matches either another LocalNetworkSpecifier with the same
+        // string or a ConfidentialMatchAllNetworkSpecifier, and can be passed to apps as is.
+        class LocalStringNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+            private String mString;
+
+            LocalStringNetworkSpecifier(String string) {
+                mString = string;
+            }
+
+            @Override
+            public boolean satisfiedBy(NetworkSpecifier other) {
+                if (other instanceof LocalStringNetworkSpecifier) {
+                    return TextUtils.equals(mString,
+                            ((LocalStringNetworkSpecifier) other).mString);
+                }
+                if (other instanceof ConfidentialMatchAllNetworkSpecifier) return true;
+                return false;
+            }
+
+            @Override
+            public int describeContents() {
+                return 0;
+            }
+            @Override
+            public void writeToParcel(Parcel dest, int flags) {}
+        }
+
+
         NetworkRequest rEmpty1 = newWifiRequestBuilder().build();
         NetworkRequest rEmpty2 = newWifiRequestBuilder().setNetworkSpecifier((String) null).build();
         NetworkRequest rEmpty3 = newWifiRequestBuilder().setNetworkSpecifier("").build();
         NetworkRequest rEmpty4 = newWifiRequestBuilder().setNetworkSpecifier(
             (NetworkSpecifier) null).build();
-        NetworkRequest rFoo = newWifiRequestBuilder().setNetworkSpecifier("foo").build();
+        NetworkRequest rFoo = newWifiRequestBuilder().setNetworkSpecifier(
+                new LocalStringNetworkSpecifier("foo")).build();
         NetworkRequest rBar = newWifiRequestBuilder().setNetworkSpecifier(
-                new StringNetworkSpecifier("bar")).build();
+                new LocalStringNetworkSpecifier("bar")).build();
 
         TestNetworkCallback cEmpty1 = new TestNetworkCallback();
         TestNetworkCallback cEmpty2 = new TestNetworkCallback();
@@ -2562,7 +2656,7 @@
         TestNetworkCallback cFoo = new TestNetworkCallback();
         TestNetworkCallback cBar = new TestNetworkCallback();
         TestNetworkCallback[] emptyCallbacks = new TestNetworkCallback[] {
-                cEmpty1, cEmpty2, cEmpty3 };
+                cEmpty1, cEmpty2, cEmpty3, cEmpty4 };
 
         mCm.registerNetworkCallback(rEmpty1, cEmpty1);
         mCm.registerNetworkCallback(rEmpty2, cEmpty2);
@@ -2571,6 +2665,9 @@
         mCm.registerNetworkCallback(rFoo, cFoo);
         mCm.registerNetworkCallback(rBar, cBar);
 
+        LocalStringNetworkSpecifier nsFoo = new LocalStringNetworkSpecifier("foo");
+        LocalStringNetworkSpecifier nsBar = new LocalStringNetworkSpecifier("bar");
+
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         cEmpty1.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2579,30 +2676,54 @@
         cEmpty4.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertNoCallbacks(cFoo, cBar);
 
-        mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("foo"));
+        mWiFiNetworkAgent.setNetworkSpecifier(nsFoo);
         cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         for (TestNetworkCallback c: emptyCallbacks) {
-            c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
+            c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsFoo),
+                    mWiFiNetworkAgent);
         }
-        cFoo.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
+        cFoo.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsFoo),
+                mWiFiNetworkAgent);
+        assertEquals(nsFoo,
+                mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
         cFoo.assertNoCallback();
 
-        mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("bar"));
+        mWiFiNetworkAgent.setNetworkSpecifier(nsBar);
         cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         cBar.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         for (TestNetworkCallback c: emptyCallbacks) {
-            c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
+            c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsBar),
+                    mWiFiNetworkAgent);
         }
-        cBar.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
+        cBar.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsBar),
+                mWiFiNetworkAgent);
+        assertEquals(nsBar,
+                mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
+        cBar.assertNoCallback();
+
+        mWiFiNetworkAgent.setNetworkSpecifier(new ConfidentialMatchAllNetworkSpecifier());
+        cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        for (TestNetworkCallback c : emptyCallbacks) {
+            c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null,
+                    mWiFiNetworkAgent);
+        }
+        cFoo.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null,
+                mWiFiNetworkAgent);
+        cBar.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null,
+                mWiFiNetworkAgent);
+        assertNull(
+                mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
+        cFoo.assertNoCallback();
         cBar.assertNoCallback();
 
         mWiFiNetworkAgent.setNetworkSpecifier(null);
+        cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         cBar.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
         for (TestNetworkCallback c: emptyCallbacks) {
             c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
         }
 
-        assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cFoo, cBar);
+        assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar);
     }
 
     @Test
@@ -3169,7 +3290,7 @@
         Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
 
         // Fail validation on wifi.
-        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
+        mWiFiNetworkAgent.setNetworkInvalid();
         mCm.reportNetworkConnectivity(wifiNetwork, false);
         defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
@@ -3213,7 +3334,7 @@
         wifiNetwork = mWiFiNetworkAgent.getNetwork();
 
         // Fail validation on wifi and expect the dialog to appear.
-        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
+        mWiFiNetworkAgent.setNetworkInvalid();
         mCm.reportNetworkConnectivity(wifiNetwork, false);
         defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
@@ -3432,6 +3553,80 @@
         }
     }
 
+    private static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback {
+
+        public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
+
+        private class CallbackValue {
+            public CallbackType callbackType;
+            public int error;
+
+            CallbackValue(CallbackType type) {
+                this.callbackType = type;
+                this.error = SocketKeepalive.SUCCESS;
+                assertTrue("onError callback must have error", type != CallbackType.ON_ERROR);
+            }
+
+            CallbackValue(CallbackType type, int error) {
+                this.callbackType = type;
+                this.error = error;
+                assertEquals("error can only be set for onError", type, CallbackType.ON_ERROR);
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                return o instanceof CallbackValue
+                        && this.callbackType == ((CallbackValue) o).callbackType
+                        && this.error == ((CallbackValue) o).error;
+            }
+
+            @Override
+            public String toString() {
+                return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType,
+                        error);
+            }
+        }
+
+        private LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
+
+        @Override
+        public void onStarted() {
+            mCallbacks.add(new CallbackValue(CallbackType.ON_STARTED));
+        }
+
+        @Override
+        public void onStopped() {
+            mCallbacks.add(new CallbackValue(CallbackType.ON_STOPPED));
+        }
+
+        @Override
+        public void onError(int error) {
+            mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error));
+        }
+
+        private void expectCallback(CallbackValue callbackValue) {
+            try {
+                assertEquals(
+                        callbackValue,
+                        mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            } catch (InterruptedException e) {
+                fail(callbackValue.callbackType + " callback not seen after " + TIMEOUT_MS + " ms");
+            }
+        }
+
+        public void expectStarted() {
+            expectCallback(new CallbackValue(CallbackType.ON_STARTED));
+        }
+
+        public void expectStopped() {
+            expectCallback(new CallbackValue(CallbackType.ON_STOPPED));
+        }
+
+        public void expectError(int error) {
+            expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
+        }
+    }
+
     private Network connectKeepaliveNetwork(LinkProperties lp) {
         // Ensure the network is disconnected before we do anything.
         if (mWiFiNetworkAgent != null) {
@@ -3579,6 +3774,145 @@
     }
 
     @Test
+    public void testNattSocketKeepalives() throws Exception {
+        // TODO: 1. Move this outside of ConnectivityServiceTest.
+        //       2. Add helper function to test against newSingleThreadExecutor as well as inline
+        //          executor.
+        //       3. Make test to verify that Nat-T keepalive socket is created by IpSecService.
+        final int srcPort = 12345;
+        final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
+        final InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
+        final InetAddress myIPv6 = InetAddress.getByName("2001:db8::1");
+        final InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
+        final InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888");
+
+        final int validKaInterval = 15;
+        final int invalidKaInterval = 9;
+
+        final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
+        final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket(srcPort);
+
+        final Executor executor = Executors.newSingleThreadExecutor();
+
+        LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName("wlan12");
+        lp.addLinkAddress(new LinkAddress(myIPv6, 64));
+        lp.addLinkAddress(new LinkAddress(myIPv4, 25));
+        lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
+        lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
+
+        Network notMyNet = new Network(61234);
+        Network myNet = connectKeepaliveNetwork(lp);
+
+        TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
+        SocketKeepalive ka;
+
+        // Attempt to start keepalives with invalid parameters and check for errors.
+        // Invalid network.
+        ka = mCm.createSocketKeepalive(notMyNet, testSocket, myIPv4, dstIPv4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
+
+        // Invalid interval.
+        ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback);
+        ka.start(invalidKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_INTERVAL);
+
+        // Invalid destination.
+        ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv6, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
+
+        // Invalid source;
+        ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv6, dstIPv4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
+
+        // NAT-T is only supported for IPv4.
+        ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv6, dstIPv6, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
+
+        // Sanity check before testing started keepalive.
+        ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
+
+        // Check that a started keepalive can be stopped.
+        mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
+        ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectStarted();
+        mWiFiNetworkAgent.setStopKeepaliveError(SocketKeepalive.SUCCESS);
+        ka.stop();
+        callback.expectStopped();
+
+        // Check that deleting the IP address stops the keepalive.
+        LinkProperties bogusLp = new LinkProperties(lp);
+        ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectStarted();
+        bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25));
+        bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25));
+        mWiFiNetworkAgent.sendLinkProperties(bogusLp);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
+        mWiFiNetworkAgent.sendLinkProperties(lp);
+
+        // Check that a started keepalive is stopped correctly when the network disconnects.
+        ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectStarted();
+        mWiFiNetworkAgent.disconnect();
+        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
+
+        // ... and that stopping it after that has no adverse effects.
+        waitForIdle();
+        final Network myNetAlias = myNet;
+        assertNull(mCm.getNetworkCapabilities(myNetAlias));
+        ka.stop();
+
+        // Reconnect.
+        myNet = connectKeepaliveNetwork(lp);
+        mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
+
+        // Check things work as expected when the keepalive is stopped and the network disconnects.
+        ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectStarted();
+        ka.stop();
+        mWiFiNetworkAgent.disconnect();
+        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        waitForIdle();
+        callback.expectStopped();
+
+        // Reconnect.
+        myNet = connectKeepaliveNetwork(lp);
+        mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
+
+        // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
+        mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
+        ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectStarted();
+
+        // The second one gets slot 2.
+        mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
+        final UdpEncapsulationSocket testSocket2 = mIpSec.openUdpEncapsulationSocket(6789);
+        TestSocketKeepaliveCallback callback2 = new TestSocketKeepaliveCallback();
+        SocketKeepalive ka2 =
+                mCm.createSocketKeepalive(myNet, testSocket2, myIPv4, dstIPv4, executor, callback2);
+        ka2.start(validKaInterval);
+        callback2.expectStarted();
+
+        ka.stop();
+        callback.expectStopped();
+
+        ka2.stop();
+        callback2.expectStopped();
+    }
+
+    @Test
     public void testGetCaptivePortalServerUrl() throws Exception {
         String url = mCm.getCaptivePortalServerUrl();
         assertEquals("http://connectivitycheck.gstatic.com/generate_204", url);
@@ -4002,11 +4336,9 @@
         final String TLS_SERVER6 = "2001:db8:53::53";
         final InetAddress[] TLS_IPS = new InetAddress[]{ InetAddress.getByName(TLS_SERVER6) };
         final String[] TLS_SERVERS = new String[]{ TLS_SERVER6 };
-        final Handler h = mCellNetworkAgent.getWrappedNetworkMonitor().connectivityHandler;
-        h.sendMessage(h.obtainMessage(
-                NetworkMonitor.EVENT_PRIVATE_DNS_CONFIG_RESOLVED, 0,
-                mCellNetworkAgent.getNetwork().netId,
-                new DnsManager.PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS)));
+        mCellNetworkAgent.mNmCallbacks.notifyPrivateDnsConfigResolved(
+                new PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS).toParcel());
+
         waitForIdle();
         verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
@@ -4294,6 +4626,11 @@
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
         mMockVpn.setUids(ranges);
+        // VPN networks do not satisfy the default request and are automatically validated
+        // by NetworkMonitor
+        assertFalse(NetworkMonitorUtils.isValidationRequired(vpnNetworkAgent.mNetworkCapabilities));
+        vpnNetworkAgent.setNetworkValid();
+
         vpnNetworkAgent.connect(false);
         mMockVpn.connect();
 
@@ -4656,12 +4993,12 @@
         mCellNetworkAgent.sendLinkProperties(cellLp);
         mCellNetworkAgent.connect(true);
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        verify(mNetworkManagementService, times(1)).startClatd(MOBILE_IFNAME);
+        verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME);
         Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
 
         // Clat iface up, expect stack link updated.
         clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
-        waitForIdle();
+        networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
         List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
                 .getStackedLinks();
         assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
@@ -4669,7 +5006,6 @@
         // Change trivial linkproperties and see if stacked link is preserved.
         cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
         mCellNetworkAgent.sendLinkProperties(cellLp);
-        waitForIdle();
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
 
         List<LinkProperties> stackedLpsAfterChange =
@@ -4681,19 +5017,19 @@
         cellLp.addLinkAddress(myIpv4);
         cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
         mCellNetworkAgent.sendLinkProperties(cellLp);
-        waitForIdle();
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
-        verify(mNetworkManagementService, times(1)).stopClatd(MOBILE_IFNAME);
+        verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
 
         // Clat iface removed, expect linkproperties revert to original one
         clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
-        waitForIdle();
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
         LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
         assertEquals(cellLp, actualLpAfterIpv4);
 
         // Clean up
         mCellNetworkAgent.disconnect();
+        networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+        networkCallback.assertNoCallback();
         mCm.unregisterNetworkCallback(networkCallback);
     }
 
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index d8f9618..a844cfe 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -535,7 +535,10 @@
 
         IpSecTransformResponse createTransformResp =
                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
-        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
+
+        Socket socket = new Socket();
+        socket.bind(null);
+        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
 
         int resourceId = createTransformResp.resourceId;
         mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
@@ -552,7 +555,9 @@
 
     @Test
     public void testRemoveTransportModeTransform() throws Exception {
-        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
+        Socket socket = new Socket();
+        socket.bind(null);
+        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
         mIpSecService.removeTransportModeTransforms(pfd);
 
         verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 724446e..5be7c7b 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -422,7 +422,9 @@
 
     @Test
     public void testRemoveTransportModeTransform() throws Exception {
-        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
+        Socket socket = new Socket();
+        socket.bind(null);
+        ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
         mIpSecService.removeTransportModeTransforms(pfd);
 
         verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index 01b468a..38322e9 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -17,7 +17,6 @@
 package com.android.server.connectivity;
 
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
 import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
 import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
 import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
@@ -29,13 +28,13 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.when;
 
-import android.content.ContentResolver;
 import android.content.Context;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.RouteInfo;
+import android.net.shared.PrivateDnsConfig;
 import android.os.INetworkManagementService;
 import android.provider.Settings;
 import android.support.test.filters.SmallTest;
@@ -43,18 +42,16 @@
 import android.test.mock.MockContentResolver;
 
 import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.connectivity.DnsManager.PrivateDnsConfig;
-import com.android.server.connectivity.MockableSystemProperties;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.net.InetAddress;
 import java.util.Arrays;
 
-import org.junit.runner.RunWith;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
 /**
  * Tests for {@link DnsManager}.
  *
@@ -133,7 +130,7 @@
                 PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
         Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
         mDnsManager.updatePrivateDns(new Network(TEST_NETID),
-                new DnsManager.PrivateDnsConfig("strictmode.com", new InetAddress[] {
+                new PrivateDnsConfig("strictmode.com", new InetAddress[] {
                     InetAddress.parseNumericAddress("6.6.6.6"),
                     InetAddress.parseNumericAddress("2001:db8:66:66::1")
                     }));
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 8359fe2..1a0cb74 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -18,14 +18,15 @@
 
 import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO;
 import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
@@ -34,12 +35,11 @@
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
-import android.net.RouteInfo;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.net.RouteInfo;
 import android.net.metrics.ApfProgramEvent;
 import android.net.metrics.ApfStats;
-import android.net.metrics.DefaultNetworkEvent;
 import android.net.metrics.DhcpClientEvent;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.IpManagerEvent;
@@ -55,6 +55,13 @@
 import com.android.internal.util.BitUtils;
 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.Collections;
@@ -62,13 +69,6 @@
 import java.util.Iterator;
 import java.util.List;
 
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class IpConnectivityMetricsTest {
@@ -154,7 +154,7 @@
     @Test
     public void testRateLimiting() {
         final IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
-        final ApfProgramEvent ev = new ApfProgramEvent();
+        final ApfProgramEvent ev = new ApfProgramEvent.Builder().build();
         final long fakeTimestamp = 1;
 
         int attempt = 100; // More than burst quota, but less than buffer size.
@@ -304,26 +304,31 @@
         when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
         when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
 
-        ApfStats apfStats = new ApfStats();
-        apfStats.durationMs = 45000;
-        apfStats.receivedRas = 10;
-        apfStats.matchingRas = 2;
-        apfStats.droppedRas = 2;
-        apfStats.parseErrors = 2;
-        apfStats.zeroLifetimeRas = 1;
-        apfStats.programUpdates = 4;
-        apfStats.programUpdatesAll = 7;
-        apfStats.programUpdatesAllowingMulticast = 3;
-        apfStats.maxProgramSize = 2048;
+        ApfStats apfStats = new ApfStats.Builder()
+                .setDurationMs(45000)
+                .setReceivedRas(10)
+                .setMatchingRas(2)
+                .setDroppedRas(2)
+                .setParseErrors(2)
+                .setZeroLifetimeRas(1)
+                .setProgramUpdates(4)
+                .setProgramUpdatesAll(7)
+                .setProgramUpdatesAllowingMulticast(3)
+                .setMaxProgramSize(2048)
+                .build();
 
-        ValidationProbeEvent validationEv = new ValidationProbeEvent();
-        validationEv.durationMs = 40730;
-        validationEv.probeType = ValidationProbeEvent.PROBE_HTTP;
-        validationEv.returnCode = 204;
+        final ValidationProbeEvent validationEv = new ValidationProbeEvent.Builder()
+                .setDurationMs(40730)
+                .setProbeType(ValidationProbeEvent.PROBE_HTTP, true)
+                .setReturnCode(204)
+                .build();
 
+        final DhcpClientEvent event = new DhcpClientEvent.Builder()
+                .setMsg("SomeState")
+                .setDurationMs(192)
+                .build();
         Parcelable[] events = {
-            new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED),
-            new DhcpClientEvent("SomeState", 192),
+            new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED), event,
             new IpManagerEvent(IpManagerEvent.PROVISIONING_OK, 5678),
             validationEv,
             apfStats,
@@ -424,7 +429,7 @@
                 "  validation_probe_event <",
                 "    latency_ms: 40730",
                 "    probe_result: 204",
-                "    probe_type: 1",
+                "    probe_type: 257",
                 "  >",
                 ">",
                 "events <",
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 354cf2f..9578ded 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -23,31 +23,33 @@
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.reset;
 
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
+import android.net.INetd;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkMisc;
-import android.support.test.runner.AndroidJUnit4;
+import android.net.NetworkStack;
+import android.os.INetworkManagementService;
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.text.format.DateUtils;
 
 import com.android.internal.R;
 import com.android.server.ConnectivityService;
-import com.android.server.connectivity.NetworkNotificationManager;
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 
-import org.junit.runner.RunWith;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -66,17 +68,22 @@
     LingerMonitor mMonitor;
 
     @Mock ConnectivityService mConnService;
+    @Mock INetd mNetd;
+    @Mock INetworkManagementService mNMS;
     @Mock Context mCtx;
     @Mock NetworkMisc mMisc;
     @Mock NetworkNotificationManager mNotifier;
     @Mock Resources mResources;
+    @Mock NetworkStack mNetworkStack;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mCtx.getResources()).thenReturn(mResources);
         when(mCtx.getPackageName()).thenReturn("com.android.server.connectivity");
-        when(mConnService.createNetworkMonitor(any(), any(), any(), any())).thenReturn(null);
+        when(mCtx.getSystemServiceName(NetworkStack.class))
+                .thenReturn(Context.NETWORK_STACK_SERVICE);
+        when(mCtx.getSystemService(Context.NETWORK_STACK_SERVICE)).thenReturn(mNetworkStack);
 
         mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT);
     }
@@ -349,7 +356,7 @@
         caps.addCapability(0);
         caps.addTransportType(transport);
         NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
-                caps, 50, mCtx, null, mMisc, null, mConnService);
+                caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS);
         nai.everValidated = true;
         return nai;
     }
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index bf42412..07b1d05 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -17,9 +17,7 @@
 package com.android.server.connectivity;
 
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -27,6 +25,7 @@
 import static org.mockito.Mockito.when;
 
 import android.net.ConnectivityManager;
+import android.net.INetd;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -57,6 +56,7 @@
 
     @Mock ConnectivityService mConnectivity;
     @Mock NetworkMisc mMisc;
+    @Mock INetd mNetd;
     @Mock INetworkManagementService mNms;
     @Mock InterfaceConfiguration mConfig;
     @Mock NetworkAgentInfo mNai;
@@ -65,7 +65,7 @@
     Handler mHandler;
 
     Nat464Xlat makeNat464Xlat() {
-        return new Nat464Xlat(mNms, mNai);
+        return new Nat464Xlat(mNai, mNetd, mNms);
     }
 
     @Before
@@ -129,7 +129,7 @@
         nat.start();
 
         verify(mNms).registerObserver(eq(nat));
-        verify(mNms).startClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStart(eq(BASE_IFACE));
 
         // Stacked interface up notification arrives.
         nat.interfaceLinkStateChanged(STACKED_IFACE, true);
@@ -144,7 +144,7 @@
         // ConnectivityService stops clat (Network disconnects, IPv4 addr appears, ...).
         nat.stop();
 
-        verify(mNms).stopClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStop(eq(BASE_IFACE));
 
         // Stacked interface removed notification arrives.
         nat.interfaceRemoved(STACKED_IFACE);
@@ -156,7 +156,7 @@
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
         assertIdle(nat);
 
-        verifyNoMoreInteractions(mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
     }
 
     @Test
@@ -168,7 +168,7 @@
         nat.start();
 
         verify(mNms).registerObserver(eq(nat));
-        verify(mNms).startClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStart(eq(BASE_IFACE));
 
         // Stacked interface up notification arrives.
         nat.interfaceLinkStateChanged(STACKED_IFACE, true);
@@ -185,7 +185,7 @@
         mLooper.dispatchNext();
 
         verify(mNms).unregisterObserver(eq(nat));
-        verify(mNms).stopClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
         assertTrue(c.getValue().getStackedLinks().isEmpty());
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
@@ -194,7 +194,7 @@
         // ConnectivityService stops clat: no-op.
         nat.stop();
 
-        verifyNoMoreInteractions(mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
     }
 
     @Test
@@ -205,13 +205,13 @@
         nat.start();
 
         verify(mNms).registerObserver(eq(nat));
-        verify(mNms).startClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStart(eq(BASE_IFACE));
 
         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
         nat.stop();
 
         verify(mNms).unregisterObserver(eq(nat));
-        verify(mNms).stopClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStop(eq(BASE_IFACE));
         assertIdle(nat);
 
         // In-flight interface up notification arrives: no-op
@@ -225,7 +225,7 @@
 
         assertIdle(nat);
 
-        verifyNoMoreInteractions(mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
     }
 
     @Test
@@ -236,16 +236,16 @@
         nat.start();
 
         verify(mNms).registerObserver(eq(nat));
-        verify(mNms).startClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStart(eq(BASE_IFACE));
 
         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
         nat.stop();
 
         verify(mNms).unregisterObserver(eq(nat));
-        verify(mNms).stopClatd(eq(BASE_IFACE));
+        verify(mNetd).clatdStop(eq(BASE_IFACE));
         assertIdle(nat);
 
-        verifyNoMoreInteractions(mNms, mConnectivity);
+        verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
     }
 
     static void assertIdle(Nat464Xlat nat) {
diff --git a/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java
deleted file mode 100644
index 6e07b26..0000000
--- a/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static junit.framework.Assert.assertFalse;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkRequest;
-import android.net.captiveportal.CaptivePortalProbeResult;
-import android.net.metrics.IpConnectivityLog;
-import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.telephony.TelephonyManager;
-import android.util.ArrayMap;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.URL;
-import java.util.Random;
-
-import javax.net.ssl.SSLHandshakeException;
-
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkMonitorTest {
-    private static final String LOCATION_HEADER = "location";
-
-    private @Mock Context mContext;
-    private @Mock Handler mHandler;
-    private @Mock IpConnectivityLog mLogger;
-    private @Mock NetworkAgentInfo mAgent;
-    private @Mock NetworkAgentInfo mNotMeteredAgent;
-    private @Mock NetworkInfo mNetworkInfo;
-    private @Mock NetworkRequest mRequest;
-    private @Mock TelephonyManager mTelephony;
-    private @Mock WifiManager mWifi;
-    private @Mock Network mNetwork;
-    private @Mock HttpURLConnection mHttpConnection;
-    private @Mock HttpURLConnection mHttpsConnection;
-    private @Mock HttpURLConnection mFallbackConnection;
-    private @Mock HttpURLConnection mOtherFallbackConnection;
-    private @Mock Random mRandom;
-    private @Mock NetworkMonitor.Dependencies mDependencies;
-
-    private static final String TEST_HTTP_URL = "http://www.google.com/gen_204";
-    private static final String TEST_HTTPS_URL = "https://www.google.com/gen_204";
-    private static final String TEST_FALLBACK_URL = "http://fallback.google.com/gen_204";
-    private static final String TEST_OTHER_FALLBACK_URL = "http://otherfallback.google.com/gen_204";
-
-    private static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
-    private static final int RETURN_CODE_DNS_SUCCESS = 0;
-    private static final int RETURN_CODE_DNS_TIMEOUT = 255;
-
-    @Before
-    public void setUp() throws IOException {
-        MockitoAnnotations.initMocks(this);
-        mAgent.linkProperties = new LinkProperties();
-        mAgent.networkCapabilities = new NetworkCapabilities()
-                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-        mAgent.networkInfo = mNetworkInfo;
-
-        mNotMeteredAgent.linkProperties = new LinkProperties();
-        mNotMeteredAgent.networkCapabilities = new NetworkCapabilities()
-            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-            .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
-        mNotMeteredAgent.networkInfo = mNetworkInfo;
-
-        when(mAgent.network()).thenReturn(mNetwork);
-        when(mDependencies.getNetwork(any())).thenReturn(mNetwork);
-        when(mDependencies.getRandom()).thenReturn(mRandom);
-        when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt()))
-                .thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
-        when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_USE_HTTPS),
-                anyInt())).thenReturn(1);
-        when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTP_URL),
-                anyString())).thenReturn(TEST_HTTP_URL);
-        when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL),
-                anyString())).thenReturn(TEST_HTTPS_URL);
-        when(mNetwork.getPrivateDnsBypassingCopy()).thenReturn(mNetwork);
-
-        when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephony);
-        when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifi);
-
-        when(mNetworkInfo.getType()).thenReturn(ConnectivityManager.TYPE_WIFI);
-        setFallbackUrl(TEST_FALLBACK_URL);
-        setOtherFallbackUrls(TEST_OTHER_FALLBACK_URL);
-        setFallbackSpecs(null); // Test with no fallback spec by default
-        when(mRandom.nextInt()).thenReturn(0);
-
-        when(mNetwork.openConnection(any())).then((invocation) -> {
-            URL url = invocation.getArgument(0);
-            switch(url.toString()) {
-                case TEST_HTTP_URL:
-                    return mHttpConnection;
-                case TEST_HTTPS_URL:
-                    return mHttpsConnection;
-                case TEST_FALLBACK_URL:
-                    return mFallbackConnection;
-                case TEST_OTHER_FALLBACK_URL:
-                    return mOtherFallbackConnection;
-                default:
-                    fail("URL not mocked: " + url.toString());
-                    return null;
-            }
-        });
-        when(mHttpConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
-        when(mHttpsConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
-        when(mNetwork.getAllByName(any())).thenReturn(new InetAddress[] {
-            InetAddress.parseNumericAddress("192.168.0.0")
-        });
-
-        setMinDataStallEvaluateInterval(500);
-        setDataStallEvaluationType(1 << DATA_STALL_EVALUATION_TYPE_DNS);
-        setValidDataStallDnsTimeThreshold(500);
-        setConsecutiveDnsTimeoutThreshold(5);
-    }
-
-    private class WrappedNetworkMonitor extends NetworkMonitor {
-        private long mProbeTime = 0;
-
-        WrappedNetworkMonitor(Context context, Handler handler,
-                NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest,
-                IpConnectivityLog logger, Dependencies deps) {
-                super(context, handler, networkAgentInfo, defaultRequest, logger, deps);
-        }
-
-        @Override
-        protected long getLastProbeTime() {
-            return mProbeTime;
-        }
-
-        protected void setLastProbeTime(long time) {
-            mProbeTime = time;
-        }
-    }
-
-    WrappedNetworkMonitor makeMeteredWrappedNetworkMonitor() {
-        return new WrappedNetworkMonitor(
-                mContext, mHandler, mAgent, mRequest, mLogger, mDependencies);
-    }
-
-    WrappedNetworkMonitor makeNotMeteredWrappedNetworkMonitor() {
-        return new WrappedNetworkMonitor(
-                mContext, mHandler, mNotMeteredAgent, mRequest, mLogger, mDependencies);
-    }
-
-    NetworkMonitor makeMonitor() {
-        return new NetworkMonitor(
-                mContext, mHandler, mAgent, mRequest, mLogger, mDependencies);
-    }
-
-    @Test
-    public void testIsCaptivePortal_HttpProbeIsPortal() throws IOException {
-        setSslException(mHttpsConnection);
-        setPortal302(mHttpConnection);
-
-        assertPortal(makeMonitor().isCaptivePortal());
-    }
-
-    @Test
-    public void testIsCaptivePortal_HttpsProbeIsNotPortal() throws IOException {
-        setStatus(mHttpsConnection, 204);
-        setStatus(mHttpConnection, 500);
-
-        assertNotPortal(makeMonitor().isCaptivePortal());
-    }
-
-    @Test
-    public void testIsCaptivePortal_HttpsProbeFailedHttpSuccessNotUsed() throws IOException {
-        setSslException(mHttpsConnection);
-        // Even if HTTP returns a 204, do not use the result unless HTTPS succeeded
-        setStatus(mHttpConnection, 204);
-        setStatus(mFallbackConnection, 500);
-
-        assertFailed(makeMonitor().isCaptivePortal());
-    }
-
-    @Test
-    public void testIsCaptivePortal_FallbackProbeIsPortal() throws IOException {
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-        setPortal302(mFallbackConnection);
-
-        assertPortal(makeMonitor().isCaptivePortal());
-    }
-
-    @Test
-    public void testIsCaptivePortal_FallbackProbeIsNotPortal() throws IOException {
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-        setStatus(mFallbackConnection, 204);
-
-        // Fallback probe did not see portal, HTTPS failed -> inconclusive
-        assertFailed(makeMonitor().isCaptivePortal());
-    }
-
-    @Test
-    public void testIsCaptivePortal_OtherFallbackProbeIsPortal() throws IOException {
-        // Set all fallback probes but one to invalid URLs to verify they are being skipped
-        setFallbackUrl(TEST_FALLBACK_URL);
-        setOtherFallbackUrls(TEST_FALLBACK_URL + "," + TEST_OTHER_FALLBACK_URL);
-
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-        setStatus(mFallbackConnection, 500);
-        setPortal302(mOtherFallbackConnection);
-
-        // TEST_OTHER_FALLBACK_URL is third
-        when(mRandom.nextInt()).thenReturn(2);
-
-        final NetworkMonitor monitor = makeMonitor();
-
-        // First check always uses the first fallback URL: inconclusive
-        assertFailed(monitor.isCaptivePortal());
-        verify(mFallbackConnection, times(1)).getResponseCode();
-        verify(mOtherFallbackConnection, never()).getResponseCode();
-
-        // Second check uses the URL chosen by Random
-        assertPortal(monitor.isCaptivePortal());
-        verify(mOtherFallbackConnection, times(1)).getResponseCode();
-    }
-
-    @Test
-    public void testIsCaptivePortal_AllProbesFailed() throws IOException {
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-        setStatus(mFallbackConnection, 404);
-
-        assertFailed(makeMonitor().isCaptivePortal());
-        verify(mFallbackConnection, times(1)).getResponseCode();
-        verify(mOtherFallbackConnection, never()).getResponseCode();
-    }
-
-    @Test
-    public void testIsCaptivePortal_InvalidUrlSkipped() throws IOException {
-        setFallbackUrl("invalid");
-        setOtherFallbackUrls("otherinvalid," + TEST_OTHER_FALLBACK_URL + ",yetanotherinvalid");
-
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-        setPortal302(mOtherFallbackConnection);
-
-        assertPortal(makeMonitor().isCaptivePortal());
-        verify(mOtherFallbackConnection, times(1)).getResponseCode();
-        verify(mFallbackConnection, never()).getResponseCode();
-    }
-
-    private void setupFallbackSpec() throws IOException {
-        setFallbackSpecs("http://example.com@@/@@204@@/@@"
-                + "@@,@@"
-                + TEST_OTHER_FALLBACK_URL + "@@/@@30[12]@@/@@https://(www\\.)?google.com/?.*");
-
-        setSslException(mHttpsConnection);
-        setStatus(mHttpConnection, 500);
-
-        // Use the 2nd fallback spec
-        when(mRandom.nextInt()).thenReturn(1);
-    }
-
-    @Test
-    public void testIsCaptivePortal_FallbackSpecIsNotPortal() throws IOException {
-        setupFallbackSpec();
-        set302(mOtherFallbackConnection, "https://www.google.com/test?q=3");
-
-        // HTTPS failed, fallback spec did not see a portal -> inconclusive
-        assertFailed(makeMonitor().isCaptivePortal());
-        verify(mOtherFallbackConnection, times(1)).getResponseCode();
-        verify(mFallbackConnection, never()).getResponseCode();
-    }
-
-    @Test
-    public void testIsCaptivePortal_FallbackSpecIsPortal() throws IOException {
-        setupFallbackSpec();
-        set302(mOtherFallbackConnection, "http://login.portal.example.com");
-
-        assertPortal(makeMonitor().isCaptivePortal());
-    }
-
-    @Test
-    public void testIsDataStall_EvaluationDisabled() {
-        setDataStallEvaluationType(0);
-        WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
-        assertFalse(wrappedMonitor.isDataStall());
-    }
-
-    @Test
-    public void testIsDataStall_EvaluationDnsOnNotMeteredNetwork() {
-        WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
-        makeDnsTimeoutEvent(wrappedMonitor, 5);
-        assertTrue(wrappedMonitor.isDataStall());
-    }
-
-    @Test
-    public void testIsDataStall_EvaluationDnsOnMeteredNetwork() {
-        WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
-        assertFalse(wrappedMonitor.isDataStall());
-
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
-        makeDnsTimeoutEvent(wrappedMonitor, 5);
-        assertTrue(wrappedMonitor.isDataStall());
-    }
-
-    @Test
-    public void testIsDataStall_EvaluationDnsWithDnsTimeoutCount() {
-        WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
-        makeDnsTimeoutEvent(wrappedMonitor, 3);
-        assertFalse(wrappedMonitor.isDataStall());
-        // Reset consecutive timeout counts.
-        makeDnsSuccessEvent(wrappedMonitor, 1);
-        makeDnsTimeoutEvent(wrappedMonitor, 2);
-        assertFalse(wrappedMonitor.isDataStall());
-
-        makeDnsTimeoutEvent(wrappedMonitor, 3);
-        assertTrue(wrappedMonitor.isDataStall());
-
-        // Set the value to larger than the default dns log size.
-        setConsecutiveDnsTimeoutThreshold(51);
-        wrappedMonitor = makeMeteredWrappedNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
-        makeDnsTimeoutEvent(wrappedMonitor, 50);
-        assertFalse(wrappedMonitor.isDataStall());
-
-        makeDnsTimeoutEvent(wrappedMonitor, 1);
-        assertTrue(wrappedMonitor.isDataStall());
-    }
-
-    @Test
-    public void testIsDataStall_EvaluationDnsWithDnsTimeThreshold() {
-        // Test dns events happened in valid dns time threshold.
-        WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
-        makeDnsTimeoutEvent(wrappedMonitor, 5);
-        assertFalse(wrappedMonitor.isDataStall());
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
-        assertTrue(wrappedMonitor.isDataStall());
-
-        // Test dns events happened before valid dns time threshold.
-        setValidDataStallDnsTimeThreshold(0);
-        wrappedMonitor = makeMeteredWrappedNetworkMonitor();
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
-        makeDnsTimeoutEvent(wrappedMonitor, 5);
-        assertFalse(wrappedMonitor.isDataStall());
-        wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
-        assertFalse(wrappedMonitor.isDataStall());
-    }
-
-    private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
-        for (int i = 0; i < count; i++) {
-            wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
-                    RETURN_CODE_DNS_TIMEOUT);
-        }
-    }
-
-    private void makeDnsSuccessEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
-        for (int i = 0; i < count; i++) {
-            wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
-                    RETURN_CODE_DNS_SUCCESS);
-        }
-    }
-
-    private void setDataStallEvaluationType(int type) {
-        when(mDependencies.getSetting(any(),
-            eq(Settings.Global.DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type);
-    }
-
-    private void setMinDataStallEvaluateInterval(int time) {
-        when(mDependencies.getSetting(any(),
-            eq(Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time);
-    }
-
-    private void setValidDataStallDnsTimeThreshold(int time) {
-        when(mDependencies.getSetting(any(),
-            eq(Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time);
-    }
-
-    private void setConsecutiveDnsTimeoutThreshold(int num) {
-        when(mDependencies.getSetting(any(),
-            eq(Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt()))
-            .thenReturn(num);
-    }
-
-    private void setFallbackUrl(String url) {
-        when(mDependencies.getSetting(any(),
-                eq(Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL), any())).thenReturn(url);
-    }
-
-    private void setOtherFallbackUrls(String urls) {
-        when(mDependencies.getSetting(any(),
-                eq(Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS), any())).thenReturn(urls);
-    }
-
-    private void setFallbackSpecs(String specs) {
-        when(mDependencies.getSetting(any(),
-                eq(Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS), any())).thenReturn(specs);
-    }
-
-    private void assertPortal(CaptivePortalProbeResult result) {
-        assertTrue(result.isPortal());
-        assertFalse(result.isFailed());
-        assertFalse(result.isSuccessful());
-    }
-
-    private void assertNotPortal(CaptivePortalProbeResult result) {
-        assertFalse(result.isPortal());
-        assertFalse(result.isFailed());
-        assertTrue(result.isSuccessful());
-    }
-
-    private void assertFailed(CaptivePortalProbeResult result) {
-        assertFalse(result.isPortal());
-        assertTrue(result.isFailed());
-        assertFalse(result.isSuccessful());
-    }
-
-    private void setSslException(HttpURLConnection connection) throws IOException {
-        when(connection.getResponseCode()).thenThrow(new SSLHandshakeException("Invalid cert"));
-    }
-
-    private void set302(HttpURLConnection connection, String location) throws IOException {
-        setStatus(connection, 302);
-        when(connection.getHeaderField(LOCATION_HEADER)).thenReturn(location);
-    }
-
-    private void setPortal302(HttpURLConnection connection) throws IOException {
-        set302(connection, "http://login.example.com");
-    }
-
-    private void setStatus(HttpURLConnection connection, int status) throws IOException {
-        when(connection.getResponseCode()).thenReturn(status);
-    }
-}
-
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index e6b43d2..b635607 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -27,6 +27,7 @@
 import static android.net.ConnectivityManager.TETHERING_WIFI;
 import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
@@ -37,6 +38,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Matchers.anyInt;
@@ -47,6 +49,8 @@
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -74,8 +78,9 @@
 import android.net.NetworkState;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
-import android.net.dhcp.DhcpServer;
-import android.net.dhcp.DhcpServingParams;
+import android.net.dhcp.DhcpServerCallbacks;
+import android.net.dhcp.DhcpServingParamsParcel;
+import android.net.dhcp.IDhcpServer;
 import android.net.ip.IpServer;
 import android.net.ip.RouterAdvertisementDaemon;
 import android.net.util.InterfaceParams;
@@ -86,7 +91,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.INetworkManagementService;
-import android.os.Looper;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -129,6 +133,8 @@
     private static final String TEST_USB_IFNAME = "test_rndis0";
     private static final String TEST_WLAN_IFNAME = "test_wlan0";
 
+    private static final int DHCPSERVER_START_TIMEOUT_MS = 1000;
+
     @Mock private ApplicationInfo mApplicationInfo;
     @Mock private Context mContext;
     @Mock private INetworkManagementService mNMService;
@@ -143,9 +149,11 @@
     @Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
     @Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
     @Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
-    @Mock private DhcpServer mDhcpServer;
+    @Mock private IDhcpServer mDhcpServer;
     @Mock private INetd mNetd;
 
+    private final MockIpServerDependencies mIpServerDependencies =
+            spy(new MockIpServerDependencies());
     private final MockTetheringDependencies mTetheringDependencies =
             new MockTetheringDependencies();
 
@@ -185,6 +193,47 @@
         }
     }
 
+    public class MockIpServerDependencies extends IpServer.Dependencies {
+        MockIpServerDependencies() {
+            super(null);
+        }
+
+        @Override
+        public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
+                InterfaceParams ifParams) {
+            return mRouterAdvertisementDaemon;
+        }
+
+        @Override
+        public InterfaceParams getInterfaceParams(String ifName) {
+            assertTrue("Non-mocked interface " + ifName,
+                    ifName.equals(TEST_USB_IFNAME)
+                            || ifName.equals(TEST_WLAN_IFNAME)
+                            || ifName.equals(TEST_MOBILE_IFNAME));
+            final String[] ifaces = new String[] {
+                    TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME };
+            return new InterfaceParams(ifName, ArrayUtils.indexOf(ifaces, ifName) + IFINDEX_OFFSET,
+                    MacAddress.ALL_ZEROS_ADDRESS);
+        }
+
+        @Override
+        public INetd getNetdService() {
+            return mNetd;
+        }
+
+        @Override
+        public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
+                DhcpServerCallbacks cb) {
+            new Thread(() -> {
+                try {
+                    cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
+                } catch (RemoteException e) {
+                    fail(e.getMessage());
+                }
+            }).run();
+        }
+    }
+
     public class MockTetheringDependencies extends TetheringDependencies {
         StateMachine upstreamNetworkMonitorMasterSM;
         ArrayList<IpServer> ipv6CoordinatorNotifyList;
@@ -216,35 +265,8 @@
         }
 
         @Override
-        public IpServer.Dependencies getIpServerDependencies() {
-            return new IpServer.Dependencies() {
-                @Override
-                public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
-                        InterfaceParams ifParams) {
-                    return mRouterAdvertisementDaemon;
-                }
-
-                @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
-                public DhcpServer makeDhcpServer(Looper looper, String ifName,
-                        DhcpServingParams params, SharedLog log) {
-                    return mDhcpServer;
-                }
-            };
+        public IpServer.Dependencies getIpServerDependencies(Context context) {
+            return mIpServerDependencies;
         }
 
         @Override
@@ -546,7 +568,7 @@
 
         sendIPv6TetherUpdates(upstreamState);
         verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
-        verify(mDhcpServer, times(1)).start();
+        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
     }
 
     @Test
@@ -557,7 +579,7 @@
         runUsbTethering(upstreamState);
         sendIPv6TetherUpdates(upstreamState);
 
-        verify(mDhcpServer, never()).start();
+        verify(mIpServerDependencies, never()).makeDhcpServer(any(), any(), any());
     }
 
     @Test
@@ -581,7 +603,7 @@
         verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
         verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
         verify(mRouterAdvertisementDaemon, times(1)).start();
-        verify(mDhcpServer, times(1)).start();
+        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
 
         sendIPv6TetherUpdates(upstreamState);
         verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
@@ -595,7 +617,7 @@
 
         verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
         verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-        verify(mDhcpServer, times(1)).start();
+        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
         verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
         verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
                 TEST_XLAT_MOBILE_IFNAME);
@@ -612,7 +634,7 @@
         runUsbTethering(upstreamState);
 
         verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-        verify(mDhcpServer, times(1)).start();
+        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
         verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
 
         // Then 464xlat comes up
@@ -636,7 +658,7 @@
         verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
         verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
         // DHCP not restarted on downstream (still times(1))
-        verify(mDhcpServer, times(1)).start();
+        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
     }
 
     @Test
@@ -781,13 +803,14 @@
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
         mLooper.dispatchAll();
 
-        // We verify get/set called thrice here: once for setup and twice during
-        // teardown because all events happen over the course of the single
+        // We verify get/set called thrice here: twice for setup (on NMService) and once during
+        // teardown (on Netd) because all events happen over the course of the single
         // dispatchAll() above. Note that once the IpServer IPv4 address config
         // code is refactored the two calls during shutdown will revert to one.
         verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
-        verify(mNMService, times(3))
+        verify(mNMService, times(2))
                 .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
+        verify(mNetd, times(1)).interfaceSetCfg(argThat(p -> TEST_WLAN_IFNAME.equals(p.ifName)));
         verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
         verify(mWifiManager).updateInterfaceIpState(
                 TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 9bf7587..0b74d87 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -57,7 +57,6 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
-import android.net.IConnectivityManager;
 import android.net.IpPrefix;
 import android.net.LinkProperties;
 import android.net.Network;
@@ -97,7 +96,6 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 /**
@@ -240,6 +238,30 @@
     }
 
     @Test
+    public void testGetAlwaysAndOnGetLockDown() throws Exception {
+        final Vpn vpn = createVpn(primaryUser.id);
+
+        // Default state.
+        assertFalse(vpn.getAlwaysOn());
+        assertFalse(vpn.getLockdown());
+
+        // Set always-on without lockdown.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
+        assertTrue(vpn.getAlwaysOn());
+        assertFalse(vpn.getLockdown());
+
+        // Set always-on with lockdown.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
+        assertTrue(vpn.getAlwaysOn());
+        assertTrue(vpn.getLockdown());
+
+        // Remove always-on configuration.
+        assertTrue(vpn.setAlwaysOnPackage(null, false));
+        assertFalse(vpn.getAlwaysOn());
+        assertFalse(vpn.getLockdown());
+    }
+
+    @Test
     public void testLockdownChangingPackage() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRange user = UidRange.createForUser(primaryUser.id);
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
new file mode 100644
index 0000000..f2ecef9
--- /dev/null
+++ b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -0,0 +1,493 @@
+/*
+ * 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.net.ipmemorystore;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+
+import android.content.Context;
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.IOnBlobRetrievedListener;
+import android.net.ipmemorystore.IOnL2KeyResponseListener;
+import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
+import android.net.ipmemorystore.IOnSameNetworkResponseListener;
+import android.net.ipmemorystore.IOnStatusListener;
+import android.net.ipmemorystore.NetworkAttributes;
+import android.net.ipmemorystore.NetworkAttributesParcelable;
+import android.net.ipmemorystore.SameL3NetworkResponse;
+import android.net.ipmemorystore.SameL3NetworkResponseParcelable;
+import android.net.ipmemorystore.Status;
+import android.net.ipmemorystore.StatusParcelable;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.lang.reflect.Modifier;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/** Unit tests for {@link IpMemoryStoreService}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class IpMemoryStoreServiceTest {
+    private static final String TEST_CLIENT_ID = "testClientId";
+    private static final String TEST_DATA_NAME = "testData";
+
+    private static final int FAKE_KEY_COUNT = 20;
+    private static final String[] FAKE_KEYS;
+    static {
+        FAKE_KEYS = new String[FAKE_KEY_COUNT];
+        for (int i = 0; i < FAKE_KEYS.length; ++i) {
+            FAKE_KEYS[i] = "fakeKey" + i;
+        }
+    }
+
+    @Mock
+    private Context mMockContext;
+    private File mDbFile;
+
+    private IpMemoryStoreService mService;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        final Context context = InstrumentationRegistry.getContext();
+        final File dir = context.getFilesDir();
+        mDbFile = new File(dir, "test.db");
+        doReturn(mDbFile).when(mMockContext).getDatabasePath(anyString());
+        mService = new IpMemoryStoreService(mMockContext);
+    }
+
+    @After
+    public void tearDown() {
+        mService.shutdown();
+        mDbFile.delete();
+    }
+
+    /** Helper method to make a vanilla IOnStatusListener */
+    private IOnStatusListener onStatus(Consumer<Status> functor) {
+        return new IOnStatusListener() {
+            @Override
+            public void onComplete(final StatusParcelable statusParcelable) throws RemoteException {
+                functor.accept(new Status(statusParcelable));
+            }
+
+            @Override
+            public IBinder asBinder() {
+                return null;
+            }
+        };
+    }
+
+    /** Helper method to make an IOnBlobRetrievedListener */
+    private interface OnBlobRetrievedListener {
+        void onBlobRetrieved(Status status, String l2Key, String name, byte[] data);
+    }
+    private IOnBlobRetrievedListener onBlobRetrieved(final OnBlobRetrievedListener functor) {
+        return new IOnBlobRetrievedListener() {
+            @Override
+            public void onBlobRetrieved(final StatusParcelable statusParcelable,
+                    final String l2Key, final String name, final Blob blob) throws RemoteException {
+                functor.onBlobRetrieved(new Status(statusParcelable), l2Key, name,
+                        null == blob ? null : blob.data);
+            }
+
+            @Override
+            public IBinder asBinder() {
+                return null;
+            }
+        };
+    }
+
+    /** Helper method to make an IOnNetworkAttributesRetrievedListener */
+    private interface OnNetworkAttributesRetrievedListener  {
+        void onNetworkAttributesRetrieved(Status status, String l2Key, NetworkAttributes attr);
+    }
+    private IOnNetworkAttributesRetrieved onNetworkAttributesRetrieved(
+            final OnNetworkAttributesRetrievedListener functor) {
+        return new IOnNetworkAttributesRetrieved() {
+            @Override
+            public void onNetworkAttributesRetrieved(final StatusParcelable status,
+                    final String l2Key, final NetworkAttributesParcelable attributes)
+                    throws RemoteException {
+                functor.onNetworkAttributesRetrieved(new Status(status), l2Key,
+                        null == attributes ? null : new NetworkAttributes(attributes));
+            }
+
+            @Override
+            public IBinder asBinder() {
+                return null;
+            }
+        };
+    }
+
+    /** Helper method to make an IOnSameNetworkResponseListener */
+    private interface OnSameNetworkResponseListener {
+        void onSameNetworkResponse(Status status, SameL3NetworkResponse answer);
+    }
+    private IOnSameNetworkResponseListener onSameResponse(
+            final OnSameNetworkResponseListener functor) {
+        return new IOnSameNetworkResponseListener() {
+            @Override
+            public void onSameNetworkResponse(final StatusParcelable status,
+                    final SameL3NetworkResponseParcelable sameL3Network)
+                    throws RemoteException {
+                functor.onSameNetworkResponse(new Status(status),
+                        null == sameL3Network ? null : new SameL3NetworkResponse(sameL3Network));
+            }
+
+            @Override
+            public IBinder asBinder() {
+                return null;
+            }
+        };
+    }
+
+    /** Helper method to make an IOnL2KeyResponseListener */
+    private interface OnL2KeyResponseListener {
+        void onL2KeyResponse(Status status, String key);
+    }
+    private IOnL2KeyResponseListener onL2KeyResponse(final OnL2KeyResponseListener functor) {
+        return new IOnL2KeyResponseListener() {
+            @Override
+            public void onL2KeyResponse(final StatusParcelable status, final String key)
+                    throws RemoteException {
+                functor.onL2KeyResponse(new Status(status), key);
+            }
+
+            @Override
+            public IBinder asBinder() {
+                return null;
+            }
+        };
+    }
+
+    // Helper method to factorize some boilerplate
+    private void doLatched(final String timeoutMessage, final Consumer<CountDownLatch> functor) {
+        final CountDownLatch latch = new CountDownLatch(1);
+        functor.accept(latch);
+        try {
+            latch.await(5000, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail(timeoutMessage);
+        }
+    }
+
+    // Helper methods to factorize more boilerplate
+    private void storeAttributes(final String l2Key, final NetworkAttributes na) {
+        storeAttributes("Did not complete storing attributes", l2Key, na);
+    }
+    private void storeAttributes(final String timeoutMessage, final String l2Key,
+            final NetworkAttributes na) {
+        doLatched(timeoutMessage, latch -> mService.storeNetworkAttributes(l2Key, na.toParcelable(),
+                onStatus(status -> {
+                    assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
+                    latch.countDown();
+                })));
+    }
+
+    @Test
+    public void testNetworkAttributes() throws UnknownHostException {
+        final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
+        na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
+        na.setGroupHint("hint1");
+        na.setMtu(219);
+        final String l2Key = FAKE_KEYS[0];
+        NetworkAttributes attributes = na.build();
+        storeAttributes(l2Key, attributes);
+
+        doLatched("Did not complete retrieving attributes", latch ->
+                mService.retrieveNetworkAttributes(l2Key, onNetworkAttributesRetrieved(
+                        (status, key, attr) -> {
+                            assertTrue("Retrieve network attributes not successful : "
+                                    + status.resultCode, status.isSuccess());
+                            assertEquals(l2Key, key);
+                            assertEquals(attributes, attr);
+                            latch.countDown();
+                        })));
+
+        final NetworkAttributes.Builder na2 = new NetworkAttributes.Builder();
+        na.setDnsAddresses(Arrays.asList(
+                new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")}));
+        final NetworkAttributes attributes2 = na2.build();
+        storeAttributes("Did not complete storing attributes 2", l2Key, attributes2);
+
+        doLatched("Did not complete retrieving attributes 2", latch ->
+                mService.retrieveNetworkAttributes(l2Key, onNetworkAttributesRetrieved(
+                        (status, key, attr) -> {
+                            assertTrue("Retrieve network attributes not successful : "
+                                    + status.resultCode, status.isSuccess());
+                            assertEquals(l2Key, key);
+                            assertEquals(attributes.assignedV4Address, attr.assignedV4Address);
+                            assertEquals(attributes.groupHint, attr.groupHint);
+                            assertEquals(attributes.mtu, attr.mtu);
+                            assertEquals(attributes2.dnsAddresses, attr.dnsAddresses);
+                            latch.countDown();
+                        })));
+
+        doLatched("Did not complete retrieving attributes 3", latch ->
+                mService.retrieveNetworkAttributes(l2Key + "nonexistent",
+                        onNetworkAttributesRetrieved(
+                                (status, key, attr) -> {
+                                    assertTrue("Retrieve network attributes not successful : "
+                                            + status.resultCode, status.isSuccess());
+                                    assertEquals(l2Key + "nonexistent", key);
+                                    assertNull("Retrieved data not stored", attr);
+                                    latch.countDown();
+                                }
+                        )));
+
+        // Verify that this test does not miss any new field added later.
+        // If any field is added to NetworkAttributes it must be tested here for storing
+        // and retrieving.
+        assertEquals(4, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
+                .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
+    }
+
+    @Test
+    public void testInvalidAttributes() {
+        doLatched("Did not complete storing bad attributes", latch ->
+                mService.storeNetworkAttributes("key", null, onStatus(status -> {
+                    assertFalse("Success storing on a null key",
+                            status.isSuccess());
+                    assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
+                    latch.countDown();
+                })));
+
+        final NetworkAttributes na = new NetworkAttributes.Builder().setMtu(2).build();
+        doLatched("Did not complete storing bad attributes", latch ->
+                mService.storeNetworkAttributes(null, na.toParcelable(), onStatus(status -> {
+                    assertFalse("Success storing null attributes on a null key",
+                            status.isSuccess());
+                    assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
+                    latch.countDown();
+                })));
+
+        doLatched("Did not complete storing bad attributes", latch ->
+                mService.storeNetworkAttributes(null, null, onStatus(status -> {
+                    assertFalse("Success storing null attributes on a null key",
+                            status.isSuccess());
+                    assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
+                    latch.countDown();
+                })));
+
+        doLatched("Did not complete retrieving bad attributes", latch ->
+                mService.retrieveNetworkAttributes(null, onNetworkAttributesRetrieved(
+                        (status, key, attr) -> {
+                            assertFalse("Success retrieving attributes for a null key",
+                                    status.isSuccess());
+                            assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
+                            assertNull(key);
+                            assertNull(attr);
+                        })));
+    }
+
+    @Test
+    public void testPrivateData() {
+        final Blob b = new Blob();
+        b.data = new byte[] { -3, 6, 8, -9, 12, -128, 0, 89, 112, 91, -34 };
+        final String l2Key = FAKE_KEYS[0];
+        doLatched("Did not complete storing private data", latch ->
+                mService.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
+                        onStatus(status -> {
+                            assertTrue("Store status not successful : " + status.resultCode,
+                                    status.isSuccess());
+                            latch.countDown();
+                        })));
+
+        doLatched("Did not complete retrieving private data", latch ->
+                mService.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, onBlobRetrieved(
+                        (status, key, name, data) -> {
+                            assertTrue("Retrieve blob status not successful : " + status.resultCode,
+                                    status.isSuccess());
+                            assertEquals(l2Key, key);
+                            assertEquals(name, TEST_DATA_NAME);
+                            Arrays.equals(b.data, data);
+                            latch.countDown();
+                        })));
+
+        // Most puzzling error message ever
+        doLatched("Did not complete retrieving nothing", latch ->
+                mService.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME + "2", onBlobRetrieved(
+                        (status, key, name, data) -> {
+                            assertTrue("Retrieve blob status not successful : " + status.resultCode,
+                                    status.isSuccess());
+                            assertEquals(l2Key, key);
+                            assertEquals(name, TEST_DATA_NAME + "2");
+                            assertNull(data);
+                            latch.countDown();
+                        })));
+    }
+
+    @Test
+    public void testFindL2Key() throws UnknownHostException {
+        final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
+        na.setGroupHint("hint0");
+        storeAttributes(FAKE_KEYS[0], na.build());
+
+        na.setDnsAddresses(Arrays.asList(
+                new InetAddress[] {Inet6Address.getByName("8D56:9AF1::08EE:20F1")}));
+        na.setMtu(219);
+        storeAttributes(FAKE_KEYS[1], na.build());
+        na.setMtu(null);
+        na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
+        na.setDnsAddresses(Arrays.asList(
+                new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")}));
+        na.setGroupHint("hint1");
+        storeAttributes(FAKE_KEYS[2], na.build());
+        na.setMtu(219);
+        storeAttributes(FAKE_KEYS[3], na.build());
+        na.setMtu(240);
+        storeAttributes(FAKE_KEYS[4], na.build());
+        na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("5.6.7.8"));
+        storeAttributes(FAKE_KEYS[5], na.build());
+
+        // Matches key 5 exactly
+        doLatched("Did not finish finding L2Key", latch ->
+                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
+                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
+                            status.isSuccess());
+                    assertEquals(FAKE_KEYS[5], key);
+                })));
+
+        // MTU matches key 4 but v4 address matches key 5. The latter is stronger.
+        na.setMtu(240);
+        doLatched("Did not finish finding L2Key", latch ->
+                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
+                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
+                            status.isSuccess());
+                    assertEquals(FAKE_KEYS[5], key);
+                })));
+
+        // Closest to key 3 (indeed, identical)
+        na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
+        na.setMtu(219);
+        doLatched("Did not finish finding L2Key", latch ->
+                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
+                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
+                            status.isSuccess());
+                    assertEquals(FAKE_KEYS[3], key);
+                })));
+
+        // Group hint alone must not be strong enough to override the rest
+        na.setGroupHint("hint0");
+        doLatched("Did not finish finding L2Key", latch ->
+                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
+                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
+                            status.isSuccess());
+                    assertEquals(FAKE_KEYS[3], key);
+                })));
+
+        // Still closest to key 3, though confidence is lower
+        na.setGroupHint("hint1");
+        na.setDnsAddresses(null);
+        doLatched("Did not finish finding L2Key", latch ->
+                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
+                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
+                            status.isSuccess());
+                    assertEquals(FAKE_KEYS[3], key);
+                })));
+
+        // But changing the MTU makes this closer to key 4
+        na.setMtu(240);
+        doLatched("Did not finish finding L2Key", latch ->
+                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
+                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
+                            status.isSuccess());
+                    assertEquals(FAKE_KEYS[4], key);
+                })));
+
+        // MTU alone not strong enough to make this group-close
+        na.setGroupHint(null);
+        na.setDnsAddresses(null);
+        na.setAssignedV4Address(null);
+        doLatched("Did not finish finding L2Key", latch ->
+                mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
+                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
+                            status.isSuccess());
+                    assertNull(key);
+                })));
+    }
+
+    private void assertNetworksSameness(final String key1, final String key2, final int sameness) {
+        doLatched("Did not finish evaluating sameness", latch ->
+                mService.isSameNetwork(key1, key2, onSameResponse((status, answer) -> {
+                    assertTrue("Retrieve network sameness not successful : " + status.resultCode,
+                            status.isSuccess());
+                    assertEquals(sameness, answer.getNetworkSameness());
+                })));
+    }
+
+    @Test
+    public void testIsSameNetwork() throws UnknownHostException {
+        final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
+        na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
+        na.setGroupHint("hint1");
+        na.setMtu(219);
+        na.setDnsAddresses(Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")));
+
+        storeAttributes(FAKE_KEYS[0], na.build());
+        // 0 and 1 have identical attributes
+        storeAttributes(FAKE_KEYS[1], na.build());
+
+        // Hopefully only the MTU being different still means it's the same network
+        na.setMtu(200);
+        storeAttributes(FAKE_KEYS[2], na.build());
+
+        // Hopefully different MTU, assigned V4 address and grouphint make a different network,
+        // even with identical DNS addresses
+        na.setAssignedV4Address(null);
+        na.setGroupHint("hint2");
+        storeAttributes(FAKE_KEYS[3], na.build());
+
+        assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[1], SameL3NetworkResponse.NETWORK_SAME);
+        assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[2], SameL3NetworkResponse.NETWORK_SAME);
+        assertNetworksSameness(FAKE_KEYS[1], FAKE_KEYS[2], SameL3NetworkResponse.NETWORK_SAME);
+        assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[3], SameL3NetworkResponse.NETWORK_DIFFERENT);
+        assertNetworksSameness(FAKE_KEYS[0], "neverInsertedKey",
+                SameL3NetworkResponse.NETWORK_NEVER_CONNECTED);
+
+        doLatched("Did not finish evaluating sameness", latch ->
+                mService.isSameNetwork(null, null, onSameResponse((status, answer) -> {
+                    assertFalse("Retrieve network sameness suspiciously successful : "
+                            + status.resultCode, status.isSuccess());
+                    assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
+                    assertNull(answer);
+                })));
+    }
+}
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
new file mode 100644
index 0000000..fe19eee
--- /dev/null
+++ b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net.ipmemorystore;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.ipmemorystore.NetworkAttributes;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+import java.net.Inet4Address;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
+/** Unit tests for {@link NetworkAttributes}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NetworkAttributesTest {
+    private static final String WEIGHT_FIELD_NAME_PREFIX = "WEIGHT_";
+    private static final float EPSILON = 0.0001f;
+
+    // This is running two tests to make sure the total weight is the sum of all weights. To be
+    // sure this is not fireproof, but you'd kind of need to do it on purpose to pass.
+    @Test
+    public void testTotalWeight() throws IllegalAccessException, UnknownHostException {
+        // Make sure that TOTAL_WEIGHT is equal to the sum of the fields starting with WEIGHT_
+        float sum = 0f;
+        final Field[] fieldList = NetworkAttributes.class.getDeclaredFields();
+        for (final Field field : fieldList) {
+            if (!field.getName().startsWith(WEIGHT_FIELD_NAME_PREFIX)) continue;
+            field.setAccessible(true);
+            sum += (float) field.get(null);
+        }
+        assertEquals(sum, NetworkAttributes.TOTAL_WEIGHT, EPSILON);
+
+        // Use directly the constructor with all attributes, and make sure that when compared
+        // to itself the score is a clean 1.0f.
+        final NetworkAttributes na =
+                new NetworkAttributes(
+                        (Inet4Address) Inet4Address.getByAddress(new byte[] {1, 2, 3, 4}),
+                        "some hint",
+                        Arrays.asList(Inet4Address.getByAddress(new byte[] {5, 6, 7, 8}),
+                                Inet4Address.getByAddress(new byte[] {9, 0, 1, 2})),
+                        98);
+        assertEquals(1.0f, na.getNetworkGroupSamenessConfidence(na), EPSILON);
+    }
+}
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java b/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
new file mode 100644
index 0000000..8d367e2
--- /dev/null
+++ b/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.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.server.net.ipmemorystore;
+
+import static com.android.server.net.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link RelevanceUtils}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RelevanceUtilsTests {
+    @Test
+    public void testComputeRelevanceForTargetDate() {
+        final long dayInMillis = 24L * 60 * 60 * 1000;
+        final long base = 1_000_000L; // any given point in time
+        // Relevance when the network expires in 1000 years must be capped
+        assertEquals(CAPPED_RELEVANCE, RelevanceUtils.computeRelevanceForTargetDate(
+                base + 1000L * dayInMillis, base));
+        // Relevance when expiry is before the date must be 0
+        assertEquals(0, RelevanceUtils.computeRelevanceForTargetDate(base - 1, base));
+        // Make sure the relevance for a given target date is higher if the expiry is further
+        // in the future
+        assertTrue(RelevanceUtils.computeRelevanceForTargetDate(base + 100 * dayInMillis, base)
+                < RelevanceUtils.computeRelevanceForTargetDate(base + 150 * dayInMillis, base));
+
+        // Make sure the relevance falls slower as the expiry is closing in. This is to ensure
+        // the decay is indeed logarithmic.
+        final int relevanceAtExpiry = RelevanceUtils.computeRelevanceForTargetDate(base, base);
+        final int relevance50DaysBeforeExpiry =
+                RelevanceUtils.computeRelevanceForTargetDate(base + 50 * dayInMillis, base);
+        final int relevance100DaysBeforeExpiry =
+                RelevanceUtils.computeRelevanceForTargetDate(base + 100 * dayInMillis, base);
+        final int relevance150DaysBeforeExpiry =
+                RelevanceUtils.computeRelevanceForTargetDate(base + 150 * dayInMillis, base);
+        assertEquals(0, relevanceAtExpiry);
+        assertTrue(relevance50DaysBeforeExpiry - relevanceAtExpiry
+                < relevance100DaysBeforeExpiry - relevance50DaysBeforeExpiry);
+        assertTrue(relevance100DaysBeforeExpiry - relevance50DaysBeforeExpiry
+                < relevance150DaysBeforeExpiry - relevance100DaysBeforeExpiry);
+    }
+
+    @Test
+    public void testIncreaseRelevance() {
+        long expiry = System.currentTimeMillis();
+
+        final long firstBump = RelevanceUtils.bumpExpiryDate(expiry);
+        // Though a few milliseconds might have elapsed, the first bump should push the duration
+        // to days in the future, so unless this test takes literal days between these two lines,
+        // this should always pass.
+        assertTrue(firstBump > expiry);
+
+        expiry = 0;
+        long lastDifference = Long.MAX_VALUE;
+        // The relevance should be capped in at most this many steps. Otherwise, fail.
+        final int steps = 1000;
+        for (int i = 0; i < steps; ++i) {
+            final long newExpiry = RelevanceUtils.bumpExpiryDuration(expiry);
+            if (newExpiry == expiry) {
+                // The relevance should be capped. Make sure it is, then exit without failure.
+                assertEquals(newExpiry, RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS);
+                return;
+            }
+            // Make sure the new expiry is further in the future than last time.
+            assertTrue(newExpiry > expiry);
+            // Also check that it was not bumped as much as the last bump, because the
+            // decay must be exponential.
+            assertTrue(newExpiry - expiry < lastDifference);
+            lastDifference = newExpiry - expiry;
+            expiry = newExpiry;
+        }
+        fail("Relevance failed to go to the maximum value after " + steps + " bumps");
+    }
+
+    @Test
+    public void testContinuity() {
+        final long expiry = System.currentTimeMillis();
+
+        // Relevance at expiry and after expiry should be the cap.
+        final int relevanceBeforeMaxLifetime = RelevanceUtils.computeRelevanceForTargetDate(expiry,
+                expiry - (RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS + 1_000_000));
+        assertEquals(relevanceBeforeMaxLifetime, CAPPED_RELEVANCE);
+        final int relevanceForMaxLifetime = RelevanceUtils.computeRelevanceForTargetDate(expiry,
+                expiry - RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS);
+        assertEquals(relevanceForMaxLifetime, CAPPED_RELEVANCE);
+
+        // If the max relevance is reached at the cap lifetime, one millisecond less than this
+        // should be very close. Strictly speaking this is a bit brittle, but it should be
+        // good enough for the purposes of the memory store.
+        final int relevanceForOneMillisecLessThanCap = RelevanceUtils.computeRelevanceForTargetDate(
+                expiry, expiry - RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS + 1);
+        assertTrue(relevanceForOneMillisecLessThanCap <= CAPPED_RELEVANCE);
+        assertTrue(relevanceForOneMillisecLessThanCap >= CAPPED_RELEVANCE - 10);
+
+        // Likewise the relevance one millisecond before expiry should be very close to 0. It's
+        // fine if it rounds down to 0.
+        final int relevanceOneMillisecBeforeExpiry = RelevanceUtils.computeRelevanceForTargetDate(
+                expiry, expiry - 1);
+        assertTrue(relevanceOneMillisecBeforeExpiry <= 10);
+        assertTrue(relevanceOneMillisecBeforeExpiry >= 0);
+
+        final int relevanceAtExpiry = RelevanceUtils.computeRelevanceForTargetDate(expiry, expiry);
+        assertEquals(relevanceAtExpiry, 0);
+        final int relevanceAfterExpiry = RelevanceUtils.computeRelevanceForTargetDate(expiry,
+                expiry + 1_000_000);
+        assertEquals(relevanceAfterExpiry, 0);
+    }
+
+    // testIncreaseRelevance makes sure bumping the expiry continuously always yields a
+    // monotonically increasing date as a side effect, but this tests that the relevance (as
+    // opposed to the expiry date) increases monotonically with increasing periods.
+    @Test
+    public void testMonotonicity() {
+        // Hopefully the relevance is granular enough to give a different value for every one
+        // of this number of steps.
+        final int steps = 40;
+        final long expiry = System.currentTimeMillis();
+
+        int lastRelevance = -1;
+        for (int i = 0; i < steps; ++i) {
+            final long date = expiry - i * (RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS / steps);
+            final int relevance = RelevanceUtils.computeRelevanceForTargetDate(expiry, date);
+            assertTrue(relevance > lastRelevance);
+            lastRelevance = relevance;
+        }
+    }
+}
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat b/tests/net/res/raw/xt_qtaguid_with_clat
index 77e5c7b..6cd7499 100644
--- a/tests/net/res/raw/xt_qtaguid_with_clat
+++ b/tests/net/res/raw/xt_qtaguid_with_clat
@@ -7,7 +7,7 @@
 7 v4-wlan0 0x0 10060 1 1448660 1041 31192 753 1448660 1041 0 0 0 0 31192 753 0 0 0 0
 8 v4-wlan0 0x0 10102 0 9702 16 2870 23 9702 16 0 0 0 0 2870 23 0 0 0 0
 9 v4-wlan0 0x0 10102 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-10 wlan0 0x0 0 0 11058671 7892 312046 5113 11043898 7811 13117 61 1656 20 306544 5046 3230 38 2272 29
+10 wlan0 0x0 0 0 11058671 7892 0 0 11043898 7811 13117 61 1656 20 0 0 0 0 0 0
 11 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 12 wlan0 0x0 1000 0 6126 13 2013 16 5934 11 192 2 0 0 1821 14 192 2 0 0
 13 wlan0 0x0 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
@@ -41,3 +41,5 @@
 41 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 42 lo 0x0 0 0 1288 16 1288 16 0 0 532 8 756 8 0 0 532 8 756 8
 43 lo 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+44 wlan0 0x0 1029 0 0 0 312046 5113 0 0 0 0 0 0 306544 5046 3230 38 2272 29
+45 wlan0 0x0 1029 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after
index c78f84f..9f86153 100644
--- a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after
+++ b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after
@@ -9,7 +9,7 @@
 9 v4-wlan0 0x0 10057 1 728 7 392 7 0 0 728 7 0 0 0 0 392 7 0 0
 10 v4-wlan0 0x0 10106 0 2232 18 2232 18 0 0 2232 18 0 0 0 0 2232 18 0 0
 11 v4-wlan0 0x0 10106 1 432952718 314238 5442288 121260 432950238 314218 2480 20 0 0 5433900 121029 8388 231 0 0
-12 wlan0 0x0 0 0 440746376 329772 8524052 130894 439660007 315369 232001 1276 854368 13127 7871216 121284 108568 1325 544268 8285
+12 wlan0 0x0 0 0 440746376 329772 0 0 439660007 315369 232001 1276 854368 13127 0 0 0 0 0 0
 13 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 14 wlan0 0x0 1000 0 77113 272 56151 575 77113 272 0 0 0 0 19191 190 36960 385 0 0
 15 wlan0 0x0 1000 1 20227 80 8356 72 18539 74 1688 6 0 0 7562 66 794 6 0 0
@@ -185,3 +185,5 @@
 185 wlan0 0xffffff0900000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 186 dummy0 0x0 0 0 0 0 168 3 0 0 0 0 0 0 0 0 0 0 168 3
 187 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+188 wlan0 0x0 1029 0 0 0 8524052 130894 0 0 0 0 0 0 7871216 121284 108568 1325 544268 8285
+189 wlan0 0x0 1029 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before
index d035387..ce4bcc3 100644
--- a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before
+++ b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_before
@@ -9,7 +9,7 @@
 9 v4-wlan0 0x0 10057 1 728 7 392 7 0 0 728 7 0 0 0 0 392 7 0 0
 10 v4-wlan0 0x0 10106 0 1488 12 1488 12 0 0 1488 12 0 0 0 0 1488 12 0 0
 11 v4-wlan0 0x0 10106 1 323981189 235142 3509032 84542 323979453 235128 1736 14 0 0 3502676 84363 6356 179 0 0
-12 wlan0 0x0 0 0 330187296 250652 5855801 94173 329106990 236273 226202 1255 854104 13124 5208040 84634 103637 1256 544124 8283
+12 wlan0 0x0 0 0 330187296 250652 0 0 329106990 236273 226202 1255 854104 13124 0 0 0 0 0 0
 13 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 14 wlan0 0x0 1000 0 77113 272 56151 575 77113 272 0 0 0 0 19191 190 36960 385 0 0
 15 wlan0 0x0 1000 1 20227 80 8356 72 18539 74 1688 6 0 0 7562 66 794 6 0 0
@@ -183,3 +183,5 @@
 183 wlan0 0xffffff0900000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 184 dummy0 0x0 0 0 0 0 168 3 0 0 0 0 0 0 0 0 0 0 168 3
 185 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+186 wlan0 0x0 1029 0 0 0 5855801 94173 0 0 0 0 0 0 5208040 84634 103637 1256 544124 8283
+187 wlan0 0x0 1029 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_simple b/tests/net/res/raw/xt_qtaguid_with_clat_simple
index 7f0e56f..8c132e7 100644
--- a/tests/net/res/raw/xt_qtaguid_with_clat_simple
+++ b/tests/net/res/raw/xt_qtaguid_with_clat_simple
@@ -1,5 +1,6 @@
 idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 v4-wlan0 0x0 10060 0 42600 213 4100 41 42600 213 4100 41 0 0 0 0 0 0 0 0
+2 v4-wlan0 0x0 10060 0 42600 213 4100 41 42600 213 0 0 0 0 4100 41 0 0 0 0
 3 v4-wlan0 0x0 10060 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 wlan0 0x0 0 0 46860 213 4920 41 46860 213 4920 41 0 0 0 0 0 0 0 0
+4 wlan0 0x0 0 0 46860 213 0 0 46860 213 0 0 0 0 0 0 0 0 0 0
 5 wlan0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+6 wlan0 0x0 1029 0 0 0 4920 41 0 0 0 0 0 0 4920 41 0 0 0 0
diff --git a/tests/utils/SleepUtils/AlarmService/Android.mk b/tests/utils/SleepUtils/AlarmService/Android.mk
deleted file mode 100644
index 9022f03..0000000
--- a/tests/utils/SleepUtils/AlarmService/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SRC_FILES += \
-    src/com/android/testing/alarmservice/Alarm.aidl
-LOCAL_PACKAGE_NAME := SleepUtilsAlarmService
-LOCAL_SDK_VERSION := 7
-include $(BUILD_PACKAGE)
diff --git a/tests/utils/SleepUtils/AlarmService/AndroidManifest.xml b/tests/utils/SleepUtils/AlarmService/AndroidManifest.xml
deleted file mode 100644
index 1b6de39..0000000
--- a/tests/utils/SleepUtils/AlarmService/AndroidManifest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project Licensed under the
-    Apache License, Version 2.0 (the "License"); you may not use this file except
-    in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
-    Unless required by applicable law or agreed to in writing, software distributed
-    under the License is distributed on an "AS IS" BASIS, WITHOUT 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.testing.alarmservice" >
-
-    <uses-sdk android:minSdkVersion="7" />
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
-
-    <application android:label="Sleep Utils Alarm Service">
-        <service android:name=".AlarmService"
-            android:label="Sleep Utils Alarm Service"
-            android:exported="true"
-            android:enabled="true">
-            <intent-filter>
-                <action android:name="com.android.testing.ALARM_SERVICE" />
-            </intent-filter>
-        </service>
-        <receiver android:name=".WakeUpCall">
-            <intent-filter>
-                <action android:name="com.android.testing.alarmservice.WAKEUP" />
-            </intent-filter>
-        </receiver>
-    </application>
-</manifest>
diff --git a/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/Alarm.aidl b/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/Alarm.aidl
deleted file mode 100644
index 62a8c48..0000000
--- a/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/Alarm.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.testing.alarmservice;
-
-interface Alarm {
-    int prepare();
-    int setAlarmAndWait(long timeoutMills);
-    int done();
-}
\ No newline at end of file
diff --git a/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/AlarmImpl.java b/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/AlarmImpl.java
deleted file mode 100644
index 122d55d..0000000
--- a/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/AlarmImpl.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.testing.alarmservice;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.util.Log;
-
-import com.android.testing.alarmservice.Alarm.Stub;
-
-public class AlarmImpl extends Stub {
-
-    private static final String LOG_TAG = AlarmImpl.class.getSimpleName();
-
-    private Context mContext;
-
-    public AlarmImpl(Context context) {
-        super();
-        mContext = context;
-    }
-
-    @Override
-    public int prepare() throws RemoteException {
-        WakeUpController.getController().getWakeLock().acquire();
-        Log.d(LOG_TAG, "AlarmService prepared, wake lock acquired");
-        return 0;
-    }
-
-    @Override
-    public int setAlarmAndWait(long timeoutMills) throws RemoteException {
-        // calculate when device should be waken up
-        long atTime = SystemClock.elapsedRealtime() + timeoutMills;
-        AlarmManager am = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-        Intent wakupIntent = new Intent(WakeUpCall.WAKEUP_CALL);
-        PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, wakupIntent, 0);
-        // set alarm, which will be delivered in form of the wakeupIntent
-        am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, atTime, pi);
-        Log.d(LOG_TAG, String.format("Alarm set: %d, giving up wake lock", atTime));
-        Object lock = WakeUpController.getController().getWakeSync();
-        // release wakelock and wait for the lock to be poked from the broadcast receiver
-        WakeUpController.getController().getWakeLock().release();
-        // does not really matter if device enters suspend before we start waiting on lock
-        synchronized (lock) {
-            try {
-                lock.wait();
-            } catch (InterruptedException e) {
-            }
-        }
-        Log.d(LOG_TAG, String.format("Alarm triggered, done waiting"));
-        return 0;
-    }
-
-    @Override
-    public int done() throws RemoteException {
-        WakeUpController.getController().getWakeLock().release();
-        return 0;
-    }
-
-}
diff --git a/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/AlarmService.java b/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/AlarmService.java
deleted file mode 100644
index 576a1cf..0000000
--- a/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/AlarmService.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.testing.alarmservice;
-
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class AlarmService extends Service {
-
-    private AlarmImpl mAlarmImpl = null;
-    static Context sContext;
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        sContext = this;
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return getAlarmImpl();
-    }
-
-    private AlarmImpl getAlarmImpl() {
-        if (mAlarmImpl == null) {
-            mAlarmImpl = new AlarmImpl(this);
-        }
-        return mAlarmImpl;
-    }
-
-    @Override
-    public void onDestroy() {
-        sContext = null;
-        super.onDestroy();
-    }
-}
diff --git a/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/WakeUpCall.java b/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/WakeUpCall.java
deleted file mode 100644
index f4bb4db..0000000
--- a/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/WakeUpCall.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.testing.alarmservice;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-/**
- * The receiver for the alarm we set
- *
- */
-public class WakeUpCall extends BroadcastReceiver {
-
-    public static final String WAKEUP_CALL = "com.android.testing.alarmservice.WAKEUP";
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        // we acquire wakelock without release because user is supposed to manually release it
-        WakeUpController.getController().getWakeLock().acquire();
-        Object lock = WakeUpController.getController().getWakeSync();
-        synchronized (lock) {
-            // poke the lock so the service side can be woken from waiting on the lock
-            lock.notifyAll();
-        }
-    }
-
-}
diff --git a/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/WakeUpController.java b/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/WakeUpController.java
deleted file mode 100644
index 478371f..0000000
--- a/tests/utils/SleepUtils/AlarmService/src/com/android/testing/alarmservice/WakeUpController.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.testing.alarmservice;
-
-import android.content.Context;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.util.Log;
-
-/**
- * A singleton used for controlling and sharing of states/wakelocks
- *
- */
-public class WakeUpController {
-
-    private static final String LOG_TAG = WakeUpController.class.getName();
-    private static WakeUpController mController = null;
-    private WakeLock mWakeLock = null;
-    private Object mWakeSync = new Object();
-
-    private WakeUpController() {
-        Log.i(LOG_TAG, "Created instance: 0x" + Integer.toHexString(this.hashCode()));
-    }
-
-    public static synchronized WakeUpController getController() {
-        if (mController == null) {
-            mController = new WakeUpController();
-        }
-        return mController;
-    }
-
-    public WakeLock getWakeLock() {
-        if (mWakeLock == null) {
-            PowerManager pm =
-                    (PowerManager) AlarmService.sContext.getSystemService(Context.POWER_SERVICE);
-            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "testing-alarmservice");
-            Log.i(LOG_TAG, "Create wakelock: 0x" + Integer.toHexString(mWakeLock.hashCode()));
-        }
-        return mWakeLock;
-    }
-
-    public Object getWakeSync() {
-        return mWakeSync;
-    }
-}
diff --git a/tests/utils/SleepUtils/Android.mk b/tests/utils/SleepUtils/Android.mk
deleted file mode 100644
index 0e65e22..0000000
--- a/tests/utils/SleepUtils/Android.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/tests/utils/SleepUtils/README b/tests/utils/SleepUtils/README
deleted file mode 100644
index bfe07da..0000000
--- a/tests/utils/SleepUtils/README
+++ /dev/null
@@ -1,23 +0,0 @@
-This folder contains utils to properly perform timed suspend and wakeup.
-
-AlarmService - a service that client can bind to and perform:
-1) holding wakelock (singleton to this service)
-2) setting alarm for a specified period and releasing the wakelock; service
-   call will block until alarm has been triggered and the wakelock is held
-3) releasing the wakelock
-
-SleepHelper - a self instrumentation meant as a convenient way to trigger
-the service functions from command line. Corresponding to service function
-above, supported operations are:
-1) holding wakelock
-am instrument -w -e command prepare \
-  com.android.testing.sleephelper/.SetAlarm
-
-2) setting alarm and wait til triggered
-am instrument -w -e command set_wait \
-  -e param <time in ms> com.android.testing.sleephelper/.SetAlarm
-Note: for the function to work properly, "-w" parameter is required
-
-3) releasing wakelock
-am instrument -w -e command done \
-  com.android.testing.sleephelper/.SetAlarm
diff --git a/tests/utils/SleepUtils/SleepHelper/Android.mk b/tests/utils/SleepUtils/SleepHelper/Android.mk
deleted file mode 100644
index f8267fd..0000000
--- a/tests/utils/SleepUtils/SleepHelper/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SRC_FILES += \
-    ../AlarmService/src/com/android/testing/alarmservice/Alarm.aidl
-LOCAL_SDK_VERSION := 7
-LOCAL_PACKAGE_NAME := SleepUtilsSleepHelper
-
-include $(BUILD_PACKAGE)
diff --git a/tests/utils/SleepUtils/SleepHelper/AndroidManifest.xml b/tests/utils/SleepUtils/SleepHelper/AndroidManifest.xml
deleted file mode 100644
index 0f1d491..0000000
--- a/tests/utils/SleepUtils/SleepHelper/AndroidManifest.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project Licensed under the
-    Apache License, Version 2.0 (the "License"); you may not use this file except
-    in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
-    Unless required by applicable law or agreed to in writing, software distributed
-    under the License is distributed on an "AS IS" BASIS, WITHOUT 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.testing.sleephelper">
-
-    <uses-sdk android:minSdkVersion="7" />
-    <instrumentation android:label="Sleep Helper"
-                     android:name="com.android.testing.sleephelper.SetAlarm"
-                     android:targetPackage="com.android.testing.sleephelper" />
-
-    <application android:label="Sleep Utils Sleep Helper">
-        <uses-library android:name="android.test.runner" />
-    </application>
-</manifest>
diff --git a/tests/utils/SleepUtils/SleepHelper/src/com/android/testing/sleephelper/SetAlarm.java b/tests/utils/SleepUtils/SleepHelper/src/com/android/testing/sleephelper/SetAlarm.java
deleted file mode 100644
index b558741..0000000
--- a/tests/utils/SleepUtils/SleepHelper/src/com/android/testing/sleephelper/SetAlarm.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.testing.sleephelper;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Bundle;
-import android.os.Debug;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.testing.alarmservice.Alarm;
-
-public class SetAlarm extends Instrumentation {
-
-    private static final String COMMAND = "command";
-    private static final String PARAM = "param";
-    private static final String CMD_PREPARE = "prepare";
-    private static final String CMD_SET = "set_wait";
-    private static final String CMD_DONE = "done";
-    private static final String SERVICE_ACTION = "com.android.testing.ALARM_SERVICE";
-    private static final String SERVICE_PKG = "com.android.testing.alarmservice";
-    private static final String LOG_TAG = SetAlarm.class.getSimpleName();
-
-    private Alarm mAlarmService = null;
-    private Bundle mArgs = null;
-    private String mCommand = null;
-    private Intent mServceIntent = new Intent(SERVICE_ACTION).setPackage(SERVICE_PKG);
-
-    private ServiceConnection mConn = new ServiceConnection() {
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            Log.d(LOG_TAG, "Service disconnected.");
-            mAlarmService = null;
-            errorFinish("service disconnected");
-        }
-
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            Log.d(LOG_TAG, "Service connected.");
-            mAlarmService = Alarm.Stub.asInterface(service);
-            handleCommands();
-        }
-    };
-
-
-    private void handleCommands() {
-        if (CMD_PREPARE.equals(mCommand)) {
-            callPrepare();
-        } else if (CMD_SET.equals(mCommand)) {
-            String paramString = mArgs.getString(PARAM);
-            if (paramString == null) {
-                errorFinish("argument expected for alarm time");
-            }
-            long timeout = -1;
-            try {
-                timeout = Long.parseLong(paramString);
-            } catch (NumberFormatException nfe) {
-                errorFinish("a number argument is expected");
-            }
-            callSetAndWait(timeout);
-        } else if (CMD_DONE.equals(mCommand)) {
-            callDone();
-        } else {
-            errorFinish("Unrecognized command: " + mCommand);
-        }
-        finish(Activity.RESULT_OK, new Bundle());
-    }
-
-    @Override
-    public void onCreate(Bundle arguments) {
-        super.onCreate(arguments);
-        mCommand = arguments.getString(COMMAND);
-        if ("true".equals(arguments.getString("debug"))) {
-            Debug.waitForDebugger();
-        }
-        if (mCommand == null) {
-            errorFinish("No command specified");
-        }
-        mArgs = arguments;
-        connectToAlarmService();
-    }
-
-    private void errorFinish(String msg) {
-        Bundle ret = new Bundle();
-        ret.putString("error", msg);
-        finish(Activity.RESULT_CANCELED, ret);
-    }
-
-    private void connectToAlarmService() {
-        // start the service with an intent, this ensures the service keeps running after unbind
-        ComponentName cn = getContext().startService(mServceIntent);
-        if (cn == null) {
-            errorFinish("failed to start service");
-        }
-        if (!getContext().bindService(mServceIntent, mConn, Context.BIND_AUTO_CREATE)) {
-            errorFinish("failed to bind service");
-        }
-    }
-
-    private void callPrepare() {
-        try {
-            mAlarmService.prepare();
-        } catch (RemoteException e) {
-            errorFinish("RemoteExeption in prepare()");
-        } finally {
-            getContext().unbindService(mConn);
-        }
-    }
-
-    private void callDone() {
-        try {
-            mAlarmService.done();
-        } catch (RemoteException e) {
-            errorFinish("RemoteExeption in prepare()");
-        } finally {
-            getContext().unbindService(mConn);
-        }
-        // explicitly stop the service (started in prepare()) so that the service is now free
-        // to be reclaimed
-        getContext().stopService(mServceIntent);
-    }
-
-    private void callSetAndWait(long timeoutMills) {
-        try {
-            mAlarmService.setAlarmAndWait(timeoutMills);
-        } catch (RemoteException e) {
-            errorFinish("RemoteExeption in setAlarmAndWait()");
-        } finally {
-            getContext().unbindService(mConn);
-        }
-    }
-}
diff --git a/tests/utils/SleepUtils/WakeLoopService/Android.mk b/tests/utils/SleepUtils/WakeLoopService/Android.mk
deleted file mode 100644
index a8a944b..0000000
--- a/tests/utils/SleepUtils/WakeLoopService/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_PACKAGE_NAME := WakeupLoopService
-LOCAL_SDK_VERSION := 7
-include $(BUILD_PACKAGE)
diff --git a/tests/utils/SleepUtils/WakeLoopService/AndroidManifest.xml b/tests/utils/SleepUtils/WakeLoopService/AndroidManifest.xml
deleted file mode 100644
index a7028c4..0000000
--- a/tests/utils/SleepUtils/WakeLoopService/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project Licensed under the
-    Apache License, Version 2.0 (the "License"); you may not use this file except
-    in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
-    Unless required by applicable law or agreed to in writing, software distributed
-    under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
-    OR CONDITIONS OF ANY KIND, either express or implied. See the License for
-    the specific language governing permissions and limitations under the License. -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.test.wakeuploop" >
-
-    <uses-sdk android:minSdkVersion="7" />
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
-    <application android:label="Auto Wakeup Loop">
-        <service android:name=".WakeLoopService"
-            android:label="Wakup Loop Service"
-            android:exported="true"
-            android:enabled="true">
-            <intent-filter>
-                <action android:name="android.test.wakeuploop.WAKEUP_SERVICE" />
-            </intent-filter>
-        </service>
-        <receiver android:name=".WakeUpCall">
-            <intent-filter>
-                <action android:name="android.test.wakeuploop.WAKEUP" />
-            </intent-filter>
-        </receiver>
-    </application>
-</manifest>
diff --git a/tests/utils/SleepUtils/WakeLoopService/src/android/test/wakeuploop/FileUtil.java b/tests/utils/SleepUtils/WakeLoopService/src/android/test/wakeuploop/FileUtil.java
deleted file mode 100644
index c8b075b..0000000
--- a/tests/utils/SleepUtils/WakeLoopService/src/android/test/wakeuploop/FileUtil.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.test.wakeuploop;
-
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-public class FileUtil {
-
-    private static FileUtil sInst = null;
-    private static DateFormat sDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
-
-    private FileUtil() {};
-
-    public static FileUtil get() {
-        if (sInst == null) {
-            sInst = new FileUtil();
-        }
-        return sInst;
-    }
-
-    public void writeDateToFile(File file) {
-        try {
-            FileOutputStream fos = new FileOutputStream(file);
-            fos.write(sDateFormat.format(new Date()).getBytes());
-            fos.write('\n');
-            fos.flush();
-            fos.close();
-        } catch (IOException ioe) {
-            Log.e("FileUtil", "exception writing date to file", ioe);
-        }
-    }
-}
diff --git a/tests/utils/SleepUtils/WakeLoopService/src/android/test/wakeuploop/WakeLoopService.java b/tests/utils/SleepUtils/WakeLoopService/src/android/test/wakeuploop/WakeLoopService.java
deleted file mode 100644
index 4f557b8..0000000
--- a/tests/utils/SleepUtils/WakeLoopService/src/android/test/wakeuploop/WakeLoopService.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.test.wakeuploop;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.io.File;
-
-public class WakeLoopService extends Service {
-
-    private static final String LOG_TAG = WakeLoopService.class.getSimpleName();
-    static final String WAKEUP_INTERNAL = "WAKEUP_INTERVAL";
-    static final String MAX_LOOP = "MAX_LOOP";
-    static final String STOP_CALLBACK = "STOP_CALLBACK";
-    static final String THIS_LOOP = "THIS_LOOP";
-    static final int MSG_STOP_SERVICE = 0xd1ed1e;
-
-    private final Handler mHandler = new Handler() {
-        public void handleMessage(Message msg) {
-            if (msg.what == MSG_STOP_SERVICE) {
-                stopSelf();
-            } else {
-                super.handleMessage(msg);
-            }
-        };
-    };
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        // no binding, just start via intent
-        return null;
-    }
-
-    @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        // get wakeup interval from intent
-        long wakeupInterval = intent.getLongExtra(WAKEUP_INTERNAL, 0);
-        long maxLoop = intent.getLongExtra(MAX_LOOP, 0);
-
-        if (wakeupInterval == 0) {
-            // stop and error
-            Log.e(LOG_TAG, "No wakeup interval specified, not starting the service");
-            stopSelf();
-            return START_NOT_STICKY;
-        }
-        FileUtil.get().writeDateToFile(new File(Environment.getExternalStorageDirectory(),
-                "wakeup-loop-start.txt"));
-        Log.d(LOG_TAG, String.format("WakeLoop: STARTED interval = %d, total loop = %d",
-                wakeupInterval, maxLoop));
-        // calculate when device should be waken up
-        long atTime = SystemClock.elapsedRealtime() + wakeupInterval;
-        AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
-        Intent wakupIntent = new Intent(WakeUpCall.WAKEUP_CALL)
-            .putExtra(WAKEUP_INTERNAL, wakeupInterval)
-            .putExtra(MAX_LOOP, maxLoop)
-            .putExtra(THIS_LOOP, 0L)
-            .putExtra(STOP_CALLBACK, new Messenger(mHandler));
-        PendingIntent pi = PendingIntent.getBroadcast(this, 0, wakupIntent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
-        // set alarm, which will be delivered in form of the wakeupIntent
-        am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, atTime, pi);
-        return START_NOT_STICKY;
-    }
-
-    @Override
-    public void onDestroy() {
-        Log.d(LOG_TAG, "WakeLoop: STOPPED");
-        // cancel alarms first
-        Intent intent = new Intent(WakeUpCall.WAKEUP_CALL)
-            .putExtra(WakeUpCall.CANCEL, "true");
-        sendBroadcast(intent);
-    }
-}
diff --git a/tests/utils/SleepUtils/WakeLoopService/src/android/test/wakeuploop/WakeUpCall.java b/tests/utils/SleepUtils/WakeLoopService/src/android/test/wakeuploop/WakeUpCall.java
deleted file mode 100644
index 8347bbf0..0000000
--- a/tests/utils/SleepUtils/WakeLoopService/src/android/test/wakeuploop/WakeUpCall.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.test.wakeuploop;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Environment;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.io.File;
-
-/**
- * The receiver for the alarm we set
- *
- */
-public class WakeUpCall extends BroadcastReceiver {
-    private static final String LOG_TAG = WakeUpCall.class.getSimpleName();
-    static final String WAKEUP_CALL = "android.test.wakeuploop.WAKEUP";
-    static final String CANCEL = "CANCEL";
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-        boolean cancel = intent.hasExtra(CANCEL);
-        if (!cancel) {
-            long maxLoop = intent.getLongExtra(WakeLoopService.MAX_LOOP, 0);
-            long wakeupInterval = intent.getLongExtra(WakeLoopService.WAKEUP_INTERNAL, 0);
-            long thisLoop = intent.getLongExtra(WakeLoopService.THIS_LOOP, -1);
-            Log.d(LOG_TAG, String.format("incoming: interval = %d, max loop = %d, this loop = %d",
-                    wakeupInterval, maxLoop, thisLoop));
-            if (thisLoop == -1) {
-                Log.e(LOG_TAG, "no valid loop count received, trying to stop service");
-                stopService(intent);
-                return;
-            }
-            if (wakeupInterval == 0) {
-                Log.e(LOG_TAG, "no valid wakeup interval received, trying to stop service");
-                stopService(intent);
-                return;
-            }
-            thisLoop++;
-            Log.d(LOG_TAG, String.format("WakeLoop - iteration %d of %d", thisLoop, maxLoop));
-            if (thisLoop == maxLoop) {
-                // when maxLoop is 0, we loop forever, so not checking that case
-                // here
-                Log.d(LOG_TAG, "reached max loop count, stopping service");
-                stopService(intent);
-                return;
-            }
-            screenOn(context);
-            FileUtil.get().writeDateToFile(
-                    new File(Environment.getExternalStorageDirectory(), "wakeup-loop.txt"));
-            // calculate when device should be waken up
-            long atTime = SystemClock.elapsedRealtime() + wakeupInterval;
-            intent.putExtra(WakeLoopService.THIS_LOOP, thisLoop);
-            PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent,
-                    PendingIntent.FLAG_UPDATE_CURRENT);
-            // set alarm, which will be delivered in form of the wakeupIntent
-            am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, atTime, pi);
-        } else {
-            // cancel alarms
-            Log.d(LOG_TAG, "cancelling future alarms on request");
-            am.cancel(PendingIntent.getBroadcast(context, 0, intent, 0));
-        }
-    }
-
-    private void stopService(Intent i) {
-        Messenger msgr = i.getParcelableExtra(WakeLoopService.STOP_CALLBACK);
-        if (msgr == null) {
-            Log.e(LOG_TAG, "no stop service callback found, cannot stop");
-        } else {
-            Message msg = new Message();
-            msg.what = WakeLoopService.MSG_STOP_SERVICE;
-            try {
-                msgr.send(msg);
-            } catch (RemoteException e) {
-                Log.e(LOG_TAG, "ignored remoted exception while attempting to stop service", e);
-            }
-        }
-    }
-
-    private void screenOn(Context context) {
-        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        @SuppressWarnings("deprecation")
-        WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK |
-                PowerManager.ACQUIRE_CAUSES_WAKEUP, LOG_TAG);
-        wl.acquire(500);
-    }
-}
diff --git a/tests/utils/testutils/java/com/android/test/filters/SelectTest.java b/tests/utils/testutils/java/com/android/test/filters/SelectTest.java
new file mode 100644
index 0000000..d0350af
--- /dev/null
+++ b/tests/utils/testutils/java/com/android/test/filters/SelectTest.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.filters;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import org.junit.runner.Description;
+import org.junit.runner.manipulation.Filter;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringJoiner;
+
+/**
+ * JUnit filter to select tests.
+ *
+ * <p>This filter selects tests specified by package name, class name, and method name. With this
+ * filter, the package and the class options of AndroidJUnitRunner can be superseded. Also the
+ * restriction that prevents using the package and the class options can be mitigated.
+ *
+ * <p><b>Select out tests from Java packages:</b> this option supersedes {@code -e package} option.
+ * <pre>
+ * adb shell am instrument -w \
+ *     -e filter com.android.test.filters.SelectTest \
+ *     -e selectTest package1.,package2. \
+ *     com.tests.pkg/androidx.test.runner.AndroidJUnitRunner
+ * </pre>
+ * Note that the ending {@code .} in package name is mandatory.
+ *
+ * <p><b>Select out test classes:</b> this option supersedes {@code -e class} option.
+ * <pre>
+ * adb shell am instrument -w \
+ *     -e filter com.android.test.filters.SelectTest      \
+ *     -e selectTest package1.ClassA,package2.ClassB \
+ *     com.tests.pkg/androidx.test.runner.AndroidJUnitRunner
+ * </pre>
+ *
+ * <p><b>Select out test methods from Java classes:</b>
+ * <pre>
+ * adb shell am instrument -w \
+ *     -e filter com.android.test.filters.SelectTest                      \
+ *     -e selectTest package1.ClassA#methodX,package2.ClassB#methodY \
+ *     com.tests.pkg/androidx.test.runner.AndroidJUnitRunner
+ * </pre>
+ *
+ * Those options can be used simultaneously. For example
+ * <pre>
+ * adb shell am instrument -w \
+ *     -e filter com.android.test.filters.SelectTest                        \
+ *     -e selectTest package1.,package2.classA,package3.ClassB#methodZ \
+ *     com.tests.pkg/androidx.test.runner.AndroidJUnitRunner
+ * </pre>
+ * will select out all tests in package1, all tests in classA, and ClassB#methodZ test.
+ *
+ * <p>Note that when this option is specified with either {@code -e package} or {@code -e class}
+ * option, filtering behaves as logically conjunction. Other options, such as {@code -e notPackage},
+ * {@code -e notClass}, {@code -e annotation}, and {@code -e notAnnotation}, should work as expected
+ * with this SelectTest option.
+ *
+ * <p>When specified with {@code -e selectTest_verbose true} option, {@link SelectTest} verbosely
+ * logs to logcat while parsing {@code -e selectTest} option.
+ */
+public class SelectTest extends Filter {
+
+    private static final String TAG = SelectTest.class.getSimpleName();
+
+    @VisibleForTesting
+    static final String OPTION_SELECT_TEST = "selectTest";
+    @VisibleForTesting
+    static final String OPTION_SELECT_TEST_VERBOSE = OPTION_SELECT_TEST + "_verbose";
+
+    private static final String ARGUMENT_ITEM_SEPARATOR = ",";
+    private static final String PACKAGE_NAME_SEPARATOR = ".";
+    private static final String METHOD_SEPARATOR = "#";
+
+    @Nullable
+    private final PackageSet mPackageSet;
+
+    /**
+     * Construct {@link SelectTest} filter from instrumentation arguments in {@link Bundle}.
+     *
+     * @param testArgs instrumentation test arguments.
+     */
+    public SelectTest(@NonNull Bundle testArgs) {
+        mPackageSet = parseSelectTest(testArgs);
+    }
+
+    @Override
+    public boolean shouldRun(Description description) {
+        if (mPackageSet == null) {
+            // Accept all tests because this filter is disabled.
+            return true;
+        }
+        String testClassName = description.getClassName();
+        String testMethodName = description.getMethodName();
+        return mPackageSet.accept(testClassName, testMethodName);
+    }
+
+    @Override
+    public String describe() {
+        return OPTION_SELECT_TEST + "=" + mPackageSet;
+    }
+
+    /**
+     * Create {@link #OPTION_SELECT_TEST} argument and add it to {@code testArgs}.
+     *
+     * <p>This method is intended to be used at constructor of extended {@link Filter} class.
+     *
+     * @param testArgs instrumentation test arguments.
+     * @param selectTests array of class name to be selected to run.
+     * @return modified instrumentation test arguments.
+     */
+    @NonNull
+    protected static Bundle addSelectTest(
+            @NonNull Bundle testArgs, @NonNull String... selectTests) {
+        if (selectTests.length == 0) {
+            return testArgs;
+        }
+        testArgs.putString(OPTION_SELECT_TEST, join(Arrays.asList(selectTests)));
+        return testArgs;
+    }
+
+    /**
+     * Parse {@code -e selectTest} argument.
+     * @param testArgs instrumentation test arguments.
+     * @return {@link PackageSet} that will filter tests. Returns {@code null} when no
+     *     {@code -e selectTest} option is specified, thus this filter gets disabled.
+     */
+    @Nullable
+    private static PackageSet parseSelectTest(Bundle testArgs) {
+        final String selectTestArgs = testArgs.getString(OPTION_SELECT_TEST);
+        if (selectTestArgs == null) {
+            Log.w(TAG, "Disabled because no " + OPTION_SELECT_TEST + " option specified");
+            return null;
+        }
+
+        final boolean verbose = new Boolean(testArgs.getString(OPTION_SELECT_TEST_VERBOSE));
+        final PackageSet packageSet = new PackageSet(verbose);
+        for (String selectTestArg : selectTestArgs.split(ARGUMENT_ITEM_SEPARATOR)) {
+            packageSet.add(selectTestArg);
+        }
+        return packageSet;
+    }
+
+    private static String getPackageName(String selectTestArg) {
+        int endPackagePos = selectTestArg.lastIndexOf(PACKAGE_NAME_SEPARATOR);
+        return (endPackagePos < 0) ? "" : selectTestArg.substring(0, endPackagePos);
+    }
+
+    @Nullable
+    private static String getClassName(String selectTestArg) {
+        if (selectTestArg.endsWith(PACKAGE_NAME_SEPARATOR)) {
+            return null;
+        }
+        int methodSepPos = selectTestArg.indexOf(METHOD_SEPARATOR);
+        return (methodSepPos < 0) ? selectTestArg : selectTestArg.substring(0, methodSepPos);
+    }
+
+    @Nullable
+    private static String getMethodName(String selectTestArg) {
+        int methodSepPos = selectTestArg.indexOf(METHOD_SEPARATOR);
+        return (methodSepPos < 0) ? null : selectTestArg.substring(methodSepPos + 1);
+    }
+
+    /** Package level filter */
+    private static class PackageSet {
+        private final boolean mVerbose;
+        /**
+         * Java package name to {@link ClassSet} map. To represent package filtering, a map value
+         * can be {@code null}.
+         */
+        private final Map<String, ClassSet> mClassSetMap = new LinkedHashMap<>();
+
+        PackageSet(boolean verbose) {
+            mVerbose = verbose;
+        }
+
+        void add(final String selectTestArg) {
+            final String packageName = getPackageName(selectTestArg);
+            final String className = getClassName(selectTestArg);
+
+            if (className == null) {
+                ClassSet classSet = mClassSetMap.put(packageName, null); // package filtering.
+                if (mVerbose) {
+                    logging("Select package " + selectTestArg, classSet != null,
+                            "; supersede " + classSet);
+                }
+                return;
+            }
+
+            ClassSet classSet = mClassSetMap.get(packageName);
+            if (classSet == null) {
+                if (mClassSetMap.containsKey(packageName)) {
+                    if (mVerbose) {
+                        logging("Select package " + packageName + PACKAGE_NAME_SEPARATOR, true,
+                                " ignore " + selectTestArg);
+                    }
+                    return;
+                }
+                classSet = new ClassSet(mVerbose);
+                mClassSetMap.put(packageName, classSet);
+            }
+            classSet.add(selectTestArg);
+        }
+
+        boolean accept(String className, @Nullable String methodName) {
+            String packageName = getPackageName(className);
+            if (!mClassSetMap.containsKey(packageName)) {
+                return false;
+            }
+            ClassSet classSet = mClassSetMap.get(packageName);
+            return classSet == null || classSet.accept(className, methodName);
+        }
+
+        @Override
+        public String toString() {
+            StringJoiner joiner = new StringJoiner(ARGUMENT_ITEM_SEPARATOR);
+            for (String packageName : mClassSetMap.keySet()) {
+                ClassSet classSet = mClassSetMap.get(packageName);
+                joiner.add(classSet == null
+                        ? packageName + PACKAGE_NAME_SEPARATOR : classSet.toString());
+            }
+            return joiner.toString();
+        }
+    }
+
+    /** Class level filter */
+    private static class ClassSet {
+        private final boolean mVerbose;
+        /**
+         * Java class name to set of method names map. To represent class filtering, a map value
+         * can be {@code null}.
+         */
+        private final Map<String, Set<String>> mMethodSetMap = new LinkedHashMap<>();
+
+        ClassSet(boolean verbose) {
+            mVerbose = verbose;
+        }
+
+        void add(String selectTestArg) {
+            final String className = getClassName(selectTestArg);
+            final String methodName = getMethodName(selectTestArg);
+
+            if (methodName == null) {
+                Set<String> methodSet = mMethodSetMap.put(className, null); // class filtering.
+                if (mVerbose) {
+                    logging("Select class " + selectTestArg, methodSet != null,
+                            "; supersede " + toString(className, methodSet));
+                }
+                return;
+            }
+
+            Set<String> methodSet = mMethodSetMap.get(className);
+            if (methodSet == null) {
+                if (mMethodSetMap.containsKey(className)) {
+                    if (mVerbose) {
+                        logging("Select class " + className, true, "; ignore " + selectTestArg);
+                    }
+                    return;
+                }
+                methodSet = new LinkedHashSet<>();
+                mMethodSetMap.put(className, methodSet);
+            }
+
+            methodSet.add(methodName);
+            if (mVerbose) {
+                logging("Select method " + selectTestArg, false, null);
+            }
+        }
+
+        boolean accept(String className, @Nullable String methodName) {
+            if (!mMethodSetMap.containsKey(className)) {
+                return false;
+            }
+            Set<String> methodSet = mMethodSetMap.get(className);
+            return methodName == null || methodSet == null || methodSet.contains(methodName);
+        }
+
+        @Override
+        public String toString() {
+            StringJoiner joiner = new StringJoiner(ARGUMENT_ITEM_SEPARATOR);
+            for (String className : mMethodSetMap.keySet()) {
+                joiner.add(toString(className, mMethodSetMap.get(className)));
+            }
+            return joiner.toString();
+        }
+
+        private static String toString(String className, @Nullable Set<String> methodSet) {
+            if (methodSet == null) {
+                return className;
+            }
+            StringJoiner joiner = new StringJoiner(ARGUMENT_ITEM_SEPARATOR);
+            for (String methodName : methodSet) {
+                joiner.add(className + METHOD_SEPARATOR + methodName);
+            }
+            return joiner.toString();
+        }
+    }
+
+    private static void logging(String infoLog, boolean isWarning, String warningLog) {
+        if (isWarning) {
+            Log.w(TAG, infoLog + warningLog);
+        } else {
+            Log.i(TAG, infoLog);
+        }
+    }
+
+    private static String join(Collection<String> list) {
+        StringJoiner joiner = new StringJoiner(ARGUMENT_ITEM_SEPARATOR);
+        for (String text : list) {
+            joiner.add(text);
+        }
+        return joiner.toString();
+    }
+}
diff --git a/tests/utils/testutils/java/com/android/test/filters/SelectTestTests.java b/tests/utils/testutils/java/com/android/test/filters/SelectTestTests.java
new file mode 100644
index 0000000..163b00a
--- /dev/null
+++ b/tests/utils/testutils/java/com/android/test/filters/SelectTestTests.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.filters;
+
+import static com.android.test.filters.SelectTest.OPTION_SELECT_TEST;
+import static com.android.test.filters.SelectTest.OPTION_SELECT_TEST_VERBOSE;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Bundle;
+import android.util.ArraySet;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.manipulation.Filter;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.StringJoiner;
+
+public class SelectTestTests {
+
+    private static final String PACKAGE_A = "packageA.";
+    private static final String PACKAGE_B = "packageB.";
+    private static final String PACKAGE_C = "packageC.";
+    private static final String CLASS_A1 = PACKAGE_A + "Class1";
+    private static final String CLASS_A2 = PACKAGE_A + "Class2";
+    private static final String CLASS_B3 = PACKAGE_B + "Class3";
+    private static final String CLASS_B4 = PACKAGE_B + "Class4";
+    private static final String CLASS_C5 = PACKAGE_C + "Class5";
+    private static final String CLASS_C6 = PACKAGE_C + "Class6";
+    private static final String METHOD_A1K = CLASS_A1 + "#methodK";
+    private static final String METHOD_A1L = CLASS_A1 + "#methodL";
+    private static final String METHOD_A2M = CLASS_A2 + "#methodM";
+    private static final String METHOD_A2N = CLASS_A2 + "#methodN";
+    private static final String METHOD_B3P = CLASS_B3 + "#methodP";
+    private static final String METHOD_B3Q = CLASS_B3 + "#methodQ";
+    private static final String METHOD_B4R = CLASS_B4 + "#methodR";
+    private static final String METHOD_B4S = CLASS_B4 + "#methodS";
+    private static final String METHOD_C5W = CLASS_C5 + "#methodW";
+    private static final String METHOD_C5X = CLASS_C5 + "#methodX";
+    private static final String METHOD_C6Y = CLASS_C6 + "#methodY";
+    private static final String METHOD_C6Z = CLASS_C6 + "#methodZ";
+
+    private static final Set<Description> TEST_METHOD_A1K = methodTest(METHOD_A1K);
+    private static final Set<Description> TEST_METHOD_A1L = methodTest(METHOD_A1L);
+    private static final Set<Description> TEST_METHOD_A2M = methodTest(METHOD_A2M);
+    private static final Set<Description> TEST_METHOD_A2N = methodTest(METHOD_A2N);
+    private static final Set<Description> TEST_METHOD_B3P = methodTest(METHOD_B3P);
+    private static final Set<Description> TEST_METHOD_B3Q = methodTest(METHOD_B3Q);
+    private static final Set<Description> TEST_METHOD_B4R = methodTest(METHOD_B4R);
+    private static final Set<Description> TEST_METHOD_B4S = methodTest(METHOD_B4S);
+    private static final Set<Description> TEST_METHOD_C5W = methodTest(METHOD_C5W);
+    private static final Set<Description> TEST_METHOD_C5X = methodTest(METHOD_C5X);
+    private static final Set<Description> TEST_METHOD_C6Y = methodTest(METHOD_C6Y);
+    private static final Set<Description> TEST_METHOD_C6Z = methodTest(METHOD_C6Z);
+    private static final Set<Description> TEST_CLASS_A1 = merge(TEST_METHOD_A1K, TEST_METHOD_A1L);
+    private static final Set<Description> TEST_CLASS_A2 = merge(TEST_METHOD_A2M, TEST_METHOD_A2N);
+    private static final Set<Description> TEST_CLASS_B3 = merge(TEST_METHOD_B3P, TEST_METHOD_B3Q);
+    private static final Set<Description> TEST_CLASS_B4 = merge(TEST_METHOD_B4R, TEST_METHOD_B4S);
+    private static final Set<Description> TEST_CLASS_C5 = merge(TEST_METHOD_C5W, TEST_METHOD_C5X);
+    private static final Set<Description> TEST_CLASS_C6 = merge(TEST_METHOD_C6Y, TEST_METHOD_C6Z);
+    private static final Set<Description> TEST_PACKAGE_A = merge(TEST_CLASS_A1, TEST_CLASS_A2);
+    private static final Set<Description> TEST_PACKAGE_B = merge(TEST_CLASS_B3, TEST_CLASS_B4);
+    private static final Set<Description> TEST_PACKAGE_C = merge(TEST_CLASS_C5, TEST_CLASS_C6);
+    private static final Set<Description> TEST_ALL =
+            merge(TEST_PACKAGE_A, TEST_PACKAGE_B, TEST_PACKAGE_C);
+
+    private SelectTestBuilder mBuilder;
+
+    @Before
+    public void setUp() {
+        mBuilder = new SelectTestBuilder();
+    }
+
+    private static class SelectTestBuilder {
+        private final Bundle mTestArgs = new Bundle();
+
+        Filter build() {
+            mTestArgs.putString(OPTION_SELECT_TEST_VERBOSE, Boolean.TRUE.toString());
+            return new SelectTest(mTestArgs);
+        }
+
+        SelectTestBuilder withSelectTest(String... selectTestArgs) {
+            putTestOption(OPTION_SELECT_TEST, selectTestArgs);
+            return this;
+        }
+
+        private void putTestOption(String option, String... args) {
+            if (args.length > 0) {
+                StringJoiner joiner = new StringJoiner(",");
+                for (String arg : args) {
+                    joiner.add(arg);
+                }
+                mTestArgs.putString(option, joiner.toString());
+            }
+        }
+    }
+
+    private static Set<Description> methodTest(String testName) {
+        int methodSep = testName.indexOf("#");
+        String className = testName.substring(0, methodSep);
+        String methodName = testName.substring(methodSep + 1);
+        final Set<Description> tests = new ArraySet<>();
+        tests.add(Description.createSuiteDescription(className));
+        tests.add(Description.createTestDescription(className, methodName));
+        return Collections.unmodifiableSet(tests);
+    }
+
+    @SafeVarargs
+    private static Set<Description> merge(Set<Description>... testSpecs) {
+        final Set<Description> merged = new LinkedHashSet<>();
+        for (Set<Description> testSet : testSpecs) {
+            merged.addAll(testSet);
+        }
+        return Collections.unmodifiableSet(merged);
+    }
+
+    @SafeVarargs
+    private static void acceptTests(Filter filter, Set<Description>... testSpecs) {
+        final Set<Description> accepts = merge(testSpecs);
+        for (Description test : TEST_ALL) {
+            if (accepts.contains(test)) {
+                assertTrue("accept " + test, filter.shouldRun(test));
+            } else {
+                assertFalse("reject " + test, filter.shouldRun(test));
+            }
+        }
+    }
+
+    @Test
+    public void testFilterDisabled() {
+        final Filter filter = mBuilder.build();
+        acceptTests(filter, TEST_ALL);
+    }
+
+    @Test
+    public void testSelectPackage() {
+        final Filter filter = mBuilder.withSelectTest(PACKAGE_A, PACKAGE_B).build();
+        acceptTests(filter, TEST_PACKAGE_A, TEST_PACKAGE_B);
+    }
+
+    @Test
+    public void testSelectClass() {
+        final Filter filter = mBuilder.withSelectTest(CLASS_A1, CLASS_A2, CLASS_B3).build();
+        acceptTests(filter, TEST_CLASS_A1, TEST_CLASS_A2, TEST_CLASS_B3);
+    }
+
+    @Test
+    public void testSelectMethod() {
+        final Filter filter = mBuilder
+                .withSelectTest(METHOD_A1K, METHOD_A2M, METHOD_A2N, METHOD_B3P).build();
+        acceptTests(filter, TEST_METHOD_A1K, TEST_METHOD_A2M, TEST_METHOD_A2N, TEST_METHOD_B3P);
+    }
+
+    @Test
+    public void testSelectClassAndPackage() {
+        final Filter filter = mBuilder.withSelectTest(CLASS_A1, PACKAGE_B, CLASS_C5).build();
+        acceptTests(filter, TEST_CLASS_A1, TEST_PACKAGE_B, TEST_CLASS_C5);
+    }
+
+    @Test
+    public void testSelectMethodAndPackage() {
+        final Filter filter = mBuilder.withSelectTest(METHOD_A1K, PACKAGE_B, METHOD_C5W).build();
+        acceptTests(filter, TEST_METHOD_A1K, TEST_PACKAGE_B, TEST_METHOD_C5W);
+    }
+
+    @Test
+    public void testSelectMethodAndClass() {
+        final Filter filter = mBuilder.withSelectTest(METHOD_A1K, CLASS_C5, METHOD_B3P).build();
+        acceptTests(filter, TEST_METHOD_A1K, TEST_CLASS_C5, TEST_METHOD_B3P);
+    }
+
+    @Test
+    public void testSelectClassAndSamePackage() {
+        final Filter filter = mBuilder.withSelectTest(
+                CLASS_A1, PACKAGE_A, CLASS_B3, PACKAGE_C, CLASS_C5).build();
+        acceptTests(filter, TEST_PACKAGE_A, TEST_CLASS_B3, TEST_PACKAGE_C);
+    }
+
+    @Test
+    public void testSelectMethodAndSameClass() {
+        final Filter filter = mBuilder.withSelectTest(
+                METHOD_A1K, METHOD_A2M, CLASS_A1, CLASS_B3, METHOD_B3P, METHOD_B4R).build();
+        acceptTests(filter, TEST_CLASS_A1, TEST_METHOD_A2M, TEST_CLASS_B3, TEST_METHOD_B4R);
+    }
+
+    @Test
+    public void testSelectMethodAndSamePackage() {
+        final Filter filter = mBuilder.withSelectTest(
+                METHOD_A1K, METHOD_A1L, METHOD_A2M, PACKAGE_A,
+                PACKAGE_C, METHOD_C5W, METHOD_C5X, METHOD_C6Y).build();
+        acceptTests(filter, TEST_PACKAGE_A, TEST_PACKAGE_C);
+    }
+
+    @Test
+    public void testSelectMethodAndClassAndPackage() {
+        final Filter filter = mBuilder.withSelectTest(
+                METHOD_A1K, CLASS_A1, METHOD_A1L, METHOD_A2M, PACKAGE_A,
+                PACKAGE_B, METHOD_B3Q, CLASS_B3, METHOD_B4R, METHOD_B3P).build();
+        acceptTests(filter, TEST_PACKAGE_A, TEST_PACKAGE_B);
+    }
+}
diff --git a/tools/aapt/ConfigDescription.h b/tools/aapt/ConfigDescription.h
index 09430f2..b4ea624 100644
--- a/tools/aapt/ConfigDescription.h
+++ b/tools/aapt/ConfigDescription.h
@@ -29,7 +29,7 @@
         size = sizeof(android::ResTable_config);
     }
 
-    ConfigDescription(const android::ResTable_config&o) {  // NOLINT(implicit)
+    ConfigDescription(const android::ResTable_config&o) {  // NOLINT(google-explicit-constructor)
         *static_cast<android::ResTable_config*>(this) = o;
         size = sizeof(android::ResTable_config);
     }
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index ba498e1..7783e10 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -58,6 +58,7 @@
         "libprotobuf-cpp-lite",
         "libz",
     ],
+    stl: "libc++_static",
     group_static_libs: true,
 }
 
@@ -114,6 +115,7 @@
         "optimize/MultiApkGenerator.cpp",
         "optimize/ResourceDeduper.cpp",
         "optimize/ResourceFilter.cpp",
+        "optimize/ResourcePathShortener.cpp",
         "optimize/VersionCollapser.cpp",
         "process/SymbolTable.cpp",
         "split/TableSplitter.cpp",
@@ -170,6 +172,7 @@
     srcs: [
         "test/Builders.cpp",
         "test/Common.cpp",
+        "test/Fixture.cpp",
         "**/*_test.cpp",
     ] + toolSources,
     static_libs: [
@@ -177,7 +180,10 @@
         "libgmock",
     ],
     defaults: ["aapt2_defaults"],
-    data: ["integration-tests/CompileTest/**/*"],
+    data: [
+         "integration-tests/CompileTest/**/*",
+         "integration-tests/CommandTests/**/*"
+    ],
 }
 
 // ==========================================================
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 9460c9e..5f664f5 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -445,7 +445,7 @@
  public:
   using xml::ConstVisitor::Visit;
 
-  XmlPrinter(Printer* printer) : printer_(printer) {
+  explicit XmlPrinter(Printer* printer) : printer_(printer) {
   }
 
   void Visit(const xml::Element* el) override {
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index b353ff0..45719ef 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -223,8 +223,17 @@
     io::IFile* file = iterator->Next();
     std::string path = file->GetSource().path;
 
+    std::string output_path = path;
+    bool is_resource = path.find("res/") == 0;
+    if (is_resource) {
+      auto it = options.shortened_path_map.find(path);
+      if (it != options.shortened_path_map.end()) {
+        output_path = it->second;
+      }
+    }
+
     // Skip resources that are not referenced if requested.
-    if (path.find("res/") == 0 && referenced_resources.find(path) == referenced_resources.end()) {
+    if (is_resource && referenced_resources.find(output_path) == referenced_resources.end()) {
       if (context->IsVerbose()) {
         context->GetDiagnostics()->Note(DiagMessage()
                                         << "Removing resource '" << path << "' from APK.");
@@ -283,7 +292,8 @@
         return false;
       }
     } else {
-      if (!io::CopyFileToArchivePreserveCompression(context, file, path, writer)) {
+      if (!io::CopyFileToArchivePreserveCompression(
+              context, file, output_path, writer)) {
         return false;
       }
     }
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index dd5c751..67ba895 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -113,7 +113,7 @@
   ResourceNameRef() = default;
   ResourceNameRef(const ResourceNameRef&) = default;
   ResourceNameRef(ResourceNameRef&&) = default;
-  ResourceNameRef(const ResourceName& rhs);  // NOLINT(implicit)
+  ResourceNameRef(const ResourceName& rhs);  // NOLINT(google-explicit-constructor)
   ResourceNameRef(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
   ResourceNameRef& operator=(const ResourceNameRef& rhs) = default;
   ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
@@ -144,7 +144,7 @@
 
   ResourceId();
   ResourceId(const ResourceId& rhs);
-  ResourceId(uint32_t res_id);  // NOLINT(implicit)
+  ResourceId(uint32_t res_id);  // NOLINT(google-explicit-constructor)
   ResourceId(uint8_t p, uint8_t t, uint16_t e);
 
   bool is_valid() const;
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 58702dc..2f8ca2d 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -714,7 +714,8 @@
     }
   }
 
-  diag_->Warn(DiagMessage(out_resource->source)
+  // If the resource type was not recognized, write the error and return false.
+  diag_->Error(DiagMessage(out_resource->source)
               << "unknown resource type '" << parser->element_name() << "'");
   return false;
 }
@@ -1164,8 +1165,6 @@
             current_policies |= OverlayableItem::Policy::kPublic;
           } else if (trimmed_part == "product") {
             current_policies |= OverlayableItem::Policy::kProduct;
-          } else if (trimmed_part == "product_services") {
-            current_policies |= OverlayableItem::Policy::kProductServices;
           } else if (trimmed_part == "system") {
             current_policies |= OverlayableItem::Policy::kSystem;
           } else if (trimmed_part == "vendor") {
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index debca9c..827c7de 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -935,9 +935,6 @@
         <policy type="product">
           <item type="string" name="bar" />
         </policy>
-        <policy type="product_services">
-          <item type="string" name="baz" />
-        </policy>
         <policy type="system">
           <item type="string" name="fiz" />
         </policy>
@@ -966,14 +963,6 @@
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
   EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct));
 
-  search_result = table_.FindResource(test::ParseNameOrDie("string/baz"));
-  ASSERT_TRUE(search_result);
-  ASSERT_THAT(search_result.value().entry, NotNull());
-  ASSERT_TRUE(search_result.value().entry->overlayable_item);
-  result_overlayable_item = search_result.value().entry->overlayable_item.value();
-  EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
-  EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProductServices));
-
   search_result = table_.FindResource(test::ParseNameOrDie("string/fiz"));
   ASSERT_TRUE(search_result);
   ASSERT_THAT(search_result.value().entry, NotNull());
@@ -1028,7 +1017,7 @@
 TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) {
   std::string input = R"(
       <overlayable name="Name">
-        <policy type="vendor|product_services">
+        <policy type="vendor|public">
           <item type="string" name="foo" />
         </policy>
         <policy type="product|system">
@@ -1044,7 +1033,7 @@
   OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
   EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kVendor
-                                                   | OverlayableItem::Policy::kProductServices));
+                                                   | OverlayableItem::Policy::kPublic));
 
   search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
   ASSERT_TRUE(search_result);
@@ -1139,7 +1128,7 @@
   std::string input = R"(
       <overlayable name="Name">
         <policy type="vendor|product">
-          <policy type="product_services">
+          <policy type="public">
             <item type="string" name="foo" />
           </policy>
         </policy>
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index eaf6a47..7ca99ea 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -92,9 +92,6 @@
 
     // The resource can be overlaid by any overlay on the product partition.
     kProduct = 0x08,
-
-    // The resource can be overlaid by any overlay on the product services partition.
-    kProductServices = 0x10
   };
 
   std::shared_ptr<Overlayable> overlayable;
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index a733134..b97dc6b 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -248,7 +248,7 @@
                                                    Source("res/values/overlayable.xml", 40));
   OverlayableItem overlayable_item(overlayable);
   overlayable_item.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_item.policies |= OverlayableItem::Policy::kProductServices;
+  overlayable_item.policies |= OverlayableItem::Policy::kVendor;
   overlayable_item.comment = "comment";
   overlayable_item.source = Source("res/values/overlayable.xml", 42);
 
@@ -265,7 +265,7 @@
   EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml"));
   EXPECT_THAT(result_overlayable_item.overlayable->source.line, 40);
   EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct
-                                                   | OverlayableItem::Policy::kProductServices));
+                                                   | OverlayableItem::Policy::kVendor));
   ASSERT_THAT(result_overlayable_item.comment, StrEq("comment"));
   EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml"));
   EXPECT_THAT(result_overlayable_item.source.line, 42);
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index c6f9152..ab4805f 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -16,6 +16,7 @@
 
 #include "ResourceUtils.h"
 
+#include <algorithm>
 #include <sstream>
 
 #include "android-base/stringprintf.h"
@@ -503,6 +504,14 @@
   if (entry.first == trimmed_str) {
     return entry.second;
   }
+
+  // Try parsing codename from "[codename].[preview_sdk_fingerprint]" value.
+  const StringPiece::const_iterator begin = std::begin(trimmed_str);
+  const StringPiece::const_iterator end = std::end(trimmed_str);
+  const StringPiece::const_iterator codename_end = std::find(begin, end, '.');
+  if (codename_end != end && entry.first == trimmed_str.substr(begin, codename_end)) {
+    return entry.second;
+  }
   return {};
 }
 
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index 5ce4640..9018b0f 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -16,6 +16,7 @@
 
 #include "ResourceUtils.h"
 
+#include "SdkConstants.h"
 #include "Resource.h"
 #include "test/Test.h"
 
@@ -212,6 +213,17 @@
               Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, expected_float_flattened))));
 }
 
+TEST(ResourceUtilsTest, ParseSdkVersionWithCodename) {
+  const android::StringPiece codename =
+      GetDevelopmentSdkCodeNameAndVersion().first;
+  const int version = GetDevelopmentSdkCodeNameAndVersion().second;
+
+  EXPECT_THAT(ResourceUtils::ParseSdkVersion(codename), Eq(Maybe<int>(version)));
+  EXPECT_THAT(
+      ResourceUtils::ParseSdkVersion(codename.to_string() + ".fingerprint"),
+      Eq(Maybe<int>(version)));
+}
+
 TEST(ResourceUtilsTest, StringBuilderWhitespaceRemoval) {
   EXPECT_THAT(ResourceUtils::StringBuilder()
                   .AppendText("    hey guys ")
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index da541be..73b568e 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -155,7 +155,6 @@
     SYSTEM = 1;
     VENDOR = 2;
     PRODUCT = 3;
-    PRODUCT_SERVICES = 4;
   }
 
   // The location of the <item> declaration in source.
diff --git a/tools/aapt2/cmd/Command.cpp b/tools/aapt2/cmd/Command.cpp
index bdee5c9..4424a35 100644
--- a/tools/aapt2/cmd/Command.cpp
+++ b/tools/aapt2/cmd/Command.cpp
@@ -21,80 +21,97 @@
 #include <string>
 #include <vector>
 
+#include "android-base/stringprintf.h"
+#include "android-base/utf8.h"
 #include "androidfw/StringPiece.h"
 
 #include "util/Util.h"
 
+using android::base::StringPrintf;
 using android::StringPiece;
 
 namespace aapt {
 
-void Command::AddRequiredFlag(const StringPiece& name,
-    const StringPiece& description, std::string* value) {
-  auto func = [value](const StringPiece& arg) -> bool {
-    *value = arg.to_string();
+std::string GetSafePath(const StringPiece& arg) {
+#ifdef _WIN32
+  // If the path exceeds the maximum path length for Windows, encode the path using the
+  // extended-length prefix
+  std::wstring path16;
+  CHECK(android::base::UTF8PathToWindowsLongPath(arg.data(), &path16))
+      << "Failed to convert file path to UTF-16: file path " << arg.data();
+
+  std::string path8;
+  CHECK(android::base::WideToUTF8(path16, &path8))
+      << "Failed to convert file path back to UTF-8: file path " << arg.data();
+
+  return path8;
+#else
+  return arg.to_string();
+#endif
+}
+
+void Command::AddRequiredFlag(const StringPiece& name, const StringPiece& description,
+                              std::string* value, uint32_t flags) {
+  auto func = [value, flags](const StringPiece& arg) -> bool {
+    *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string();
     return true;
   };
 
-  flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false});
+  flags_.emplace_back(Flag(name, description, /* required */ true, /* num_args */ 1, func));
 }
 
-void Command::AddRequiredFlagList(const StringPiece& name,
-    const StringPiece& description,
-    std::vector<std::string>* value) {
-  auto func = [value](const StringPiece& arg) -> bool {
-    value->push_back(arg.to_string());
+void Command::AddRequiredFlagList(const StringPiece& name, const StringPiece& description,
+                                  std::vector<std::string>* value, uint32_t flags) {
+  auto func = [value, flags](const StringPiece& arg) -> bool {
+    value->push_back((flags & Command::kPath) ? GetSafePath(arg) : arg.to_string());
     return true;
   };
 
-  flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false});
+  flags_.emplace_back(Flag(name, description, /* required */ true, /* num_args */ 1, func));
 }
 
-void Command::AddOptionalFlag(const StringPiece& name,
-    const StringPiece& description,
-    Maybe<std::string>* value) {
-  auto func = [value](const StringPiece& arg) -> bool {
-    *value = arg.to_string();
+void Command::AddOptionalFlag(const StringPiece& name, const StringPiece& description,
+                              Maybe<std::string>* value, uint32_t flags) {
+  auto func = [value, flags](const StringPiece& arg) -> bool {
+    *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string();
     return true;
   };
 
-  flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
+  flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func));
 }
 
-void Command::AddOptionalFlagList(const StringPiece& name,
-    const StringPiece& description,
-    std::vector<std::string>* value) {
-  auto func = [value](const StringPiece& arg) -> bool {
-    value->push_back(arg.to_string());
+void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description,
+                                  std::vector<std::string>* value, uint32_t flags) {
+  auto func = [value, flags](const StringPiece& arg) -> bool {
+    value->push_back((flags & Command::kPath) ? GetSafePath(arg) : arg.to_string());
     return true;
   };
 
-  flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
+  flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func));
 }
 
-void Command::AddOptionalFlagList(const StringPiece& name,
-    const StringPiece& description,
-    std::unordered_set<std::string>* value) {
+void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description,
+                                  std::unordered_set<std::string>* value) {
   auto func = [value](const StringPiece& arg) -> bool {
     value->insert(arg.to_string());
     return true;
   };
 
-  flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
+  flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func));
 }
 
-void Command::AddOptionalSwitch(const StringPiece& name,
-    const StringPiece& description, bool* value) {
+void Command::AddOptionalSwitch(const StringPiece& name, const StringPiece& description,
+                                bool* value) {
   auto func = [value](const StringPiece& arg) -> bool {
     *value = true;
     return true;
   };
 
-  flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 0, false});
+  flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 0, func));
 }
 
 void Command::AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental) {
-  subcommand->fullname_ = name_ + " " + subcommand->name_;
+  subcommand->full_subcommand_name_ = StringPrintf("%s %s", name_.data(), subcommand->name_.data());
   if (experimental) {
     experimental_subcommands_.push_back(std::move(subcommand));
   } else {
@@ -102,14 +119,14 @@
   }
 }
 
-void Command::SetDescription(const android::StringPiece& description) {
+void Command::SetDescription(const StringPiece& description) {
   description_ = description.to_string();
 }
 
 void Command::Usage(std::ostream* out) {
   constexpr size_t kWidth = 50;
 
-  *out << fullname_;
+  *out << full_subcommand_name_;
 
   if (!subcommands_.empty()) {
     *out << " [subcommand]";
@@ -117,7 +134,7 @@
 
   *out << " [options]";
   for (const Flag& flag : flags_) {
-    if (flag.required) {
+    if (flag.is_required) {
       *out << " " << flag.name << " arg";
     }
   }
@@ -160,29 +177,31 @@
   out->flush();
 }
 
-int Command::Execute(const std::vector<android::StringPiece>& args, std::ostream* out_error) {
+int Command::Execute(const std::vector<StringPiece>& args, std::ostream* out_error) {
   std::vector<std::string> file_args;
 
   for (size_t i = 0; i < args.size(); i++) {
-    StringPiece arg = args[i];
+    const StringPiece& arg = args[i];
     if (*(arg.data()) != '-') {
       // Continue parsing as the subcommand if the first argument matches one of the subcommands
       if (i == 0) {
         for (auto& subcommand : subcommands_) {
-          if (arg == subcommand->name_ || arg==subcommand->short_name_) {
+          if (arg == subcommand->name_ || (!subcommand->short_name_.empty()
+                                           && arg == subcommand->short_name_)) {
             return subcommand->Execute(
-                std::vector<android::StringPiece>(args.begin() + 1, args.end()), out_error);
+                std::vector<StringPiece>(args.begin() + 1, args.end()), out_error);
           }
         }
         for (auto& subcommand : experimental_subcommands_) {
-          if (arg == subcommand->name_ || arg==subcommand->short_name_) {
+          if (arg == subcommand->name_ || (!subcommand->short_name_.empty()
+                                           && arg == subcommand->short_name_)) {
             return subcommand->Execute(
-              std::vector<android::StringPiece>(args.begin() + 1, args.end()), out_error);
+              std::vector<StringPiece>(args.begin() + 1, args.end()), out_error);
           }
         }
       }
 
-      file_args.push_back(arg.to_string());
+      file_args.push_back(GetSafePath(arg));
       continue;
     }
 
@@ -205,7 +224,7 @@
         } else {
           flag.action({});
         }
-        flag.parsed = true;
+        flag.found = true;
         match = true;
         break;
       }
@@ -219,7 +238,7 @@
   }
 
   for (const Flag& flag : flags_) {
-    if (flag.required && !flag.parsed) {
+    if (flag.is_required && !flag.found) {
       *out_error << "missing required flag " << flag.name << "\n\n";
       Usage(out_error);
       return 1;
diff --git a/tools/aapt2/cmd/Command.h b/tools/aapt2/cmd/Command.h
index 1694988..d21571d 100644
--- a/tools/aapt2/cmd/Command.h
+++ b/tools/aapt2/cmd/Command.h
@@ -32,55 +32,83 @@
 class Command {
  public:
   explicit Command(const android::StringPiece& name) : name_(name.to_string()),
-                                                       fullname_(name.to_string()) { }
+                                                       short_name_(""),
+                                                       full_subcommand_name_(name.to_string()) {}
+
   explicit Command(const android::StringPiece& name, const android::StringPiece& short_name)
-      : name_(name.to_string()), short_name_(short_name.to_string()), fullname_(name.to_string()) {}
+      : name_(name.to_string()), short_name_(short_name.to_string()),
+        full_subcommand_name_(name.to_string()) {}
+
   virtual ~Command() = default;
 
+  // Behavior flags used with the following functions that change how the command flags are parsed
+  // displayed.
+  enum : uint32_t {
+    // Indicates the arguments are file or folder paths. On Windows, paths that exceed the maximum
+    // path length will be converted to use the extended path prefix '//?/'. Without this
+    // conversion, files with long paths cannot be opened.
+    kPath = 1 << 0,
+  };
+
   void AddRequiredFlag(const android::StringPiece& name, const android::StringPiece& description,
-      std::string* value);
-  void AddRequiredFlagList(const android::StringPiece& name, const android::StringPiece&
-      description, std::vector<std::string>* value);
+                       std::string* value, uint32_t flags = 0);
+
+  void AddRequiredFlagList(const android::StringPiece& name,
+                           const android::StringPiece& description, std::vector<std::string>* value,
+                           uint32_t flags = 0);
+
   void AddOptionalFlag(const android::StringPiece& name, const android::StringPiece& description,
-      Maybe<std::string>* value);
+                       Maybe<std::string>* value, uint32_t flags = 0);
+
   void AddOptionalFlagList(const android::StringPiece& name,
-      const android::StringPiece& description, std::vector<std::string>* value);
+                           const android::StringPiece& description, std::vector<std::string>* value,
+                           uint32_t flags = 0);
+
   void AddOptionalFlagList(const android::StringPiece& name,
-      const android::StringPiece& description, std::unordered_set<std::string>* value);
+                           const android::StringPiece& description,
+                           std::unordered_set<std::string>* value);
+
   void AddOptionalSwitch(const android::StringPiece& name, const android::StringPiece& description,
-      bool* value);
+                         bool* value);
+
   void AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental = false);
 
   void SetDescription(const android::StringPiece& name);
 
-  /** Prints the help menu of the command. */
+  // Prints the help menu of the command.
   void Usage(std::ostream* out);
 
-  /**
-   * Parses the command line arguments, sets the flag variable values, and runs the action of
-   * the command. If the arguments fail to parse to the command and its subcommands, then the action
-   * will not be run and the usage will be printed instead.
-   **/
+  // Parses the command line arguments, sets the flag variable values, and runs the action of
+  // the command. If the arguments fail to parse to the command and its subcommands, then the action
+  // will not be run and the usage will be printed instead.
   int Execute(const std::vector<android::StringPiece>& args, std::ostream* outError);
 
-  /** The action to preform when the command is executed. */
+  // The action to preform when the command is executed.
   virtual int Action(const std::vector<std::string>& args) = 0;
 
  private:
-  struct Flag {
-    std::string name;
-    std::string description;
-    std::function<bool(const android::StringPiece& value)> action;
-    bool required;
-    size_t num_args;
+  DISALLOW_COPY_AND_ASSIGN(Command);
 
-    bool parsed;
+  struct Flag {
+    explicit Flag(const android::StringPiece& name, const android::StringPiece& description,
+                  const bool is_required, const size_t num_args,
+                  std::function<bool(const android::StringPiece& value)>&& action)
+        : name(name.to_string()), description(description.to_string()), is_required(is_required),
+          num_args(num_args), action(std::move(action)) {}
+
+    const std::string name;
+    const std::string description;
+    const bool is_required;
+    const size_t num_args;
+    const std::function<bool(const android::StringPiece& value)> action;
+    bool found = false;
   };
 
-  std::string description_;
-  std::string name_;
-  std::string short_name_;
-  std::string fullname_;
+  const std::string name_;
+  const std::string short_name_;
+  std::string description_ = "";
+  std::string full_subcommand_name_;
+
   std::vector<Flag> flags_;
   std::vector<std::unique_ptr<Command>> subcommands_;
   std::vector<std::unique_ptr<Command>> experimental_subcommands_;
diff --git a/tools/aapt2/cmd/Command_test.cpp b/tools/aapt2/cmd/Command_test.cpp
new file mode 100644
index 0000000..65608fd
--- /dev/null
+++ b/tools/aapt2/cmd/Command_test.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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 "Command.h"
+
+#include "test/Test.h"
+
+using ::testing::Eq;
+
+namespace aapt {
+
+class TestCommand : public Command {
+ public:
+  explicit TestCommand() : Command("command") {}
+  int Action(const std::vector<std::string>& args) override {
+    args_ = args;
+    return 0;
+  }
+
+  std::vector<std::string> args_;
+};
+
+#ifdef _WIN32
+TEST(CommandTest, LongFullyQualifiedPathWindows) {
+  TestCommand command;
+  std::string required_flag;
+  command.AddRequiredFlag("--rflag", "", &required_flag, Command::kPath);
+  Maybe<std::string> optional_flag;
+  command.AddOptionalFlag("--oflag", "", &optional_flag, Command::kPath);
+  std::vector<std::string> required_flag_list;
+  command.AddRequiredFlagList("--rlflag", "", &required_flag_list, Command::kPath);
+  std::vector<std::string> optional_flag_list;
+  command.AddOptionalFlagList("--olflag", "", &optional_flag_list, Command::kPath);
+  std::string non_path_flag;
+  command.AddRequiredFlag("--nflag", "", &non_path_flag);
+
+  const std::string kLongPath =
+      "C:\\Users\\jedo\\_bazel_jedo\\vcmdctjv\\execroot\\__main__\\_tmp"
+      "\\6767b4778f8798efc0f784ee74fa70ee\\tests\\testApksAr8c7560a9a65"
+      "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build"
+      "\\intermediates\\processed_res\\minified\\processMinifiedResources"
+      "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build"
+      "\\intermediates\\processed_res\\minified\\processMinifiedResources"
+      "\\out\\resources-minified.ap_";
+
+  const std::string kExpected =
+      "\\\\?\\C:\\Users\\jedo\\_bazel_jedo\\vcmdctjv\\execroot\\__main__\\_tmp"
+      "\\6767b4778f8798efc0f784ee74fa70ee\\tests\\testApksAr8c7560a9a65"
+      "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build"
+      "\\intermediates\\processed_res\\minified\\processMinifiedResources"
+      "\\1346ee7c014a089fb55d8c46cf3d9\\project\\baseModule\\build"
+      "\\intermediates\\processed_res\\minified\\processMinifiedResources"
+      "\\out\\resources-minified.ap_";
+
+
+  ASSERT_THAT(command.Execute({"--rflag", kLongPath,
+                               "--oflag", kLongPath,
+                               "--rlflag", kLongPath,
+                               "--rlflag", kLongPath,
+                               "--olflag", kLongPath,
+                               "--olflag", kLongPath,
+                               "--nflag", kLongPath,
+                               kLongPath, kLongPath}, &std::cerr), Eq(0));
+
+  ASSERT_THAT(required_flag, Eq(kExpected));
+  ASSERT_THAT(optional_flag, Eq(kExpected));
+  ASSERT_THAT(required_flag_list.size(), Eq(2));
+  ASSERT_THAT(required_flag_list[0], Eq(kExpected));
+  ASSERT_THAT(required_flag_list[1], Eq(kExpected));
+  ASSERT_THAT(optional_flag_list.size(), Eq(2));
+  ASSERT_THAT(optional_flag_list[0], Eq(kExpected));
+  ASSERT_THAT(optional_flag_list[1], Eq(kExpected));
+
+  // File arguments should also be converted to use the long path prefix
+  ASSERT_THAT(command.args_.size(), Eq(2));
+  ASSERT_THAT(command.args_[0], Eq(kExpected));
+  ASSERT_THAT(command.args_[1], Eq(kExpected));
+
+  // Do not convert flags that are not marged as paths
+  ASSERT_THAT(non_path_flag, Eq(kLongPath));
+}
+#endif
+
+}  // namespace aapt
\ No newline at end of file
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index f63a074..0512bdc 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -469,16 +469,12 @@
       return false;
     }
 
-    // Read the file as a string
-    char buffer_2[data->size()];
-    memcpy(&buffer_2, data->data(), data->size());
-    StringPiece content(buffer_2, data->size());
-
     BigBuffer crunched_png_buffer(4096);
     io::BigBufferOutputStream crunched_png_buffer_out(&crunched_png_buffer);
 
     // Ensure that we only keep the chunks we care about if we end up
     // using the original PNG instead of the crunched one.
+    const StringPiece content(reinterpret_cast<const char*>(data->data()), data->size());
     PngChunkFilter png_chunk_filter(content);
     std::unique_ptr<Image> image = ReadPng(context, path_data.source, &png_chunk_filter);
     if (!image) {
@@ -584,7 +580,7 @@
 
 class CompileContext : public IAaptContext {
  public:
-  CompileContext(IDiagnostics* diagnostics) : diagnostics_(diagnostics) {
+  explicit CompileContext(IDiagnostics* diagnostics) : diagnostics_(diagnostics) {
   }
 
   PackageType GetPackageType() override {
@@ -701,7 +697,10 @@
     }
 
     const std::string out_path = BuildIntermediateContainerFilename(path_data);
-    error |= !compile_func(context, options, path_data, file, output_writer, out_path);
+    if (!compile_func(context, options, path_data, file, output_writer, out_path)) {
+      context->GetDiagnostics()->Error(DiagMessage(file->GetSource()) << "file failed to compile");
+      error = true;
+    }
   }
 
   return error ? 1 : 0;
diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h
index c429d5f..9b32cb3 100644
--- a/tools/aapt2/cmd/Compile.h
+++ b/tools/aapt2/cmd/Compile.h
@@ -44,13 +44,13 @@
   explicit CompileCommand(IDiagnostics* diagnostic) : Command("compile", "c"),
                                                       diagnostic_(diagnostic) {
     SetDescription("Compiles resources to be linked into an apk.");
-    AddRequiredFlag("-o", "Output path", &options_.output_path);
-    AddOptionalFlag("--dir", "Directory to scan for resources", &options_.res_dir);
+    AddRequiredFlag("-o", "Output path", &options_.output_path, Command::kPath);
+    AddOptionalFlag("--dir", "Directory to scan for resources", &options_.res_dir, Command::kPath);
     AddOptionalFlag("--zip", "Zip file containing the res directory to scan for resources",
-        &options_.res_zip);
+        &options_.res_zip, Command::kPath);
     AddOptionalFlag("--output-text-symbols",
         "Generates a text file containing the resource symbols in the\n"
-            "specified file", &options_.generate_text_symbols_path);
+            "specified file", &options_.generate_text_symbols_path, Command::kPath);
     AddOptionalSwitch("--pseudo-localize", "Generate resources for pseudo-locales "
         "(en-XA and ar-XB)", &options_.pseudolocalize);
     AddOptionalSwitch("--no-crunch", "Disables PNG processing", &options_.no_png_crunch);
@@ -70,8 +70,9 @@
   Maybe<std::string> visibility_;
 };
 
-int Compile(IAaptContext* context, io::IFileCollection* inputs,
-             IArchiveWriter* output_writer, CompileOptions& options);
+int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* output_writer,
+            CompileOptions& options);
+
 }// namespace aapt
 
 #endif //AAPT2_COMPILE_H
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 4492f6b..85f9080 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -60,16 +60,17 @@
 class BinaryApkSerializer : public IApkSerializer {
  public:
   BinaryApkSerializer(IAaptContext* context, const Source& source,
-                   const TableFlattenerOptions& options)
-      : IApkSerializer(context, source), tableFlattenerOptions_(options) {}
+                      const TableFlattenerOptions& table_flattener_options,
+                      const XmlFlattenerOptions& xml_flattener_options)
+      : IApkSerializer(context, source),
+        table_flattener_options_(table_flattener_options),
+        xml_flattener_options_(xml_flattener_options) {}
 
   bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
                     IArchiveWriter* writer, uint32_t compression_flags) override {
     BigBuffer buffer(4096);
-    XmlFlattenerOptions options = {};
-    options.use_utf16 = utf16;
-    options.keep_raw_values = true;
-    XmlFlattener flattener(&buffer, options);
+    xml_flattener_options_.use_utf16 = utf16;
+    XmlFlattener flattener(&buffer, xml_flattener_options_);
     if (!flattener.Consume(context_, xml)) {
       return false;
     }
@@ -80,7 +81,7 @@
 
   bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
     BigBuffer buffer(4096);
-    TableFlattener table_flattener(tableFlattenerOptions_, &buffer);
+    TableFlattener table_flattener(table_flattener_options_, &buffer);
     if (!table_flattener.Consume(context_, table)) {
       return false;
     }
@@ -136,7 +137,8 @@
   }
 
  private:
-  TableFlattenerOptions tableFlattenerOptions_;
+  TableFlattenerOptions table_flattener_options_;
+  XmlFlattenerOptions xml_flattener_options_;
 
   DISALLOW_COPY_AND_ASSIGN(BinaryApkSerializer);
 };
@@ -252,13 +254,15 @@
 };
 
 int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer,
-            ApkFormat output_format, TableFlattenerOptions& options) {
+            ApkFormat output_format, TableFlattenerOptions table_flattener_options,
+            XmlFlattenerOptions xml_flattener_options) {
   // Do not change the ordering of strings in the values string pool
-  options.sort_stringpool_entries = false;
+  table_flattener_options.sort_stringpool_entries = false;
 
   unique_ptr<IApkSerializer> serializer;
   if (output_format == ApkFormat::kBinary) {
-    serializer.reset(new BinaryApkSerializer(context, apk->GetSource(), options));
+    serializer.reset(new BinaryApkSerializer(context, apk->GetSource(), table_flattener_options,
+                                             xml_flattener_options));
   } else if (output_format == ApkFormat::kProto) {
     serializer.reset(new ProtoApkSerializer(context, apk->GetSource()));
   } else {
@@ -378,7 +382,8 @@
     return 1;
   }
 
-  return Convert(&context, apk.get(), writer.get(), format, options_);
+  return Convert(&context, apk.get(), writer.get(), format, table_flattener_options_,
+                 xml_flattener_options_);
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/cmd/Convert.h b/tools/aapt2/cmd/Convert.h
index 6a6719c..7e2029d 100644
--- a/tools/aapt2/cmd/Convert.h
+++ b/tools/aapt2/cmd/Convert.h
@@ -20,6 +20,7 @@
 #include "Command.h"
 #include "LoadedApk.h"
 #include "format/binary/TableFlattener.h"
+#include "format/binary/XmlFlattener.h"
 
 namespace aapt {
 
@@ -27,14 +28,18 @@
  public:
   explicit ConvertCommand() : Command("convert") {
     SetDescription("Converts an apk between binary and proto formats.");
-    AddRequiredFlag("-o", "Output path", &output_path_);
+    AddRequiredFlag("-o", "Output path", &output_path_, Command::kPath);
     AddOptionalFlag("--output-format", android::base::StringPrintf("Format of the output. "
             "Accepted values are '%s' and '%s'. When not set, defaults to '%s'.",
         kOutputFormatProto, kOutputFormatBinary, kOutputFormatBinary), &output_format_);
     AddOptionalSwitch("--enable-sparse-encoding",
         "Enables encoding sparse entries using a binary search tree.\n"
-            "This decreases APK size at the cost of resource retrieval performance.",
-        &options_.use_sparse_entries);
+        "This decreases APK size at the cost of resource retrieval performance.",
+         &table_flattener_options_.use_sparse_entries);
+    AddOptionalSwitch("--keep-raw-values",
+        android::base::StringPrintf("Preserve raw attribute values in xml files when using the"
+            " '%s' output format", kOutputFormatBinary),
+        &xml_flattener_options_.keep_raw_values);
     AddOptionalSwitch("-v", "Enables verbose logging", &verbose_);
   }
 
@@ -44,14 +49,16 @@
   const static char* kOutputFormatProto;
   const static char* kOutputFormatBinary;
 
-  TableFlattenerOptions options_;
+  TableFlattenerOptions table_flattener_options_;
+  XmlFlattenerOptions xml_flattener_options_;
   std::string output_path_;
   Maybe<std::string> output_format_;
   bool verbose_ = false;
 };
 
 int Convert(IAaptContext* context, LoadedApk* input, IArchiveWriter* output_writer,
-            ApkFormat output_format, TableFlattenerOptions& options);
+            ApkFormat output_format,TableFlattenerOptions table_flattener_options,
+            XmlFlattenerOptions xml_flattener_options);
 
 }  // namespace aapt
 
diff --git a/tools/aapt2/cmd/Convert_test.cpp b/tools/aapt2/cmd/Convert_test.cpp
new file mode 100644
index 0000000..8da5bb8
--- /dev/null
+++ b/tools/aapt2/cmd/Convert_test.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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 "Convert.h"
+
+#include "LoadedApk.h"
+#include "test/Test.h"
+
+using testing::Eq;
+using testing::Ne;
+
+namespace aapt {
+
+using ConvertTest = CommandTestFixture;
+
+TEST_F(ConvertTest, RemoveRawXmlStrings) {
+  StdErrDiagnostics diag;
+  const std::string compiled_files_dir = GetTestPath("compiled");
+  ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
+                          compiled_files_dir, &diag));
+
+  const std::string out_apk = GetTestPath("out.apk");
+  std::vector<std::string> link_args = {
+      "--manifest", GetDefaultManifest(),
+      "-o", out_apk,
+      "--keep-raw-values",
+      "--proto-format"
+  };
+
+  ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
+
+  const std::string out_convert_apk = GetTestPath("out_convert.apk");
+  std::vector<android::StringPiece> convert_args = {
+      "-o", out_convert_apk,
+      "--output-format", "binary",
+      out_apk,
+  };
+  ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));
+
+  // Load the binary xml tree
+  android::ResXMLTree tree;
+  std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_convert_apk, &diag);
+
+  std::unique_ptr<io::IData> data = OpenFileAsData(apk.get(), "res/xml/test.xml");
+  ASSERT_THAT(data, Ne(nullptr));
+
+  AssertLoadXml(apk.get(), data.get(), &tree);
+
+  // Check that the raw string index has not been assigned
+  EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(-1));
+}
+
+TEST_F(ConvertTest, KeepRawXmlStrings) {
+  StdErrDiagnostics diag;
+  const std::string compiled_files_dir = GetTestPath("compiled");
+  ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
+                          compiled_files_dir, &diag));
+
+  const std::string out_apk = GetTestPath("out.apk");
+  std::vector<std::string> link_args = {
+      "--manifest", GetDefaultManifest(),
+      "-o", out_apk,
+      "--keep-raw-values",
+      "--proto-format"
+  };
+
+  ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
+
+  const std::string out_convert_apk = GetTestPath("out_convert.apk");
+  std::vector<android::StringPiece> convert_args = {
+      "-o", out_convert_apk,
+      "--output-format", "binary",
+      "--keep-raw-values",
+      out_apk,
+  };
+  ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));
+
+  // Load the binary xml tree
+  android::ResXMLTree tree;
+  std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_convert_apk, &diag);
+
+  std::unique_ptr<io::IData> data = OpenFileAsData(apk.get(), "res/xml/test.xml");
+  ASSERT_THAT(data, Ne(nullptr));
+
+  AssertLoadXml(apk.get(), data.get(), &tree);
+
+  // Check that the raw string index has been set to the correct string pool entry
+  int32_t raw_index = tree.getAttributeValueStringID(0);
+  ASSERT_THAT(raw_index, Ne(-1));
+  EXPECT_THAT(util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)), Eq("007"));
+}
+
+}  // namespace aapt
\ No newline at end of file
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 1b5601d..729447e 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -78,7 +78,7 @@
 
 class LinkContext : public IAaptContext {
  public:
-  LinkContext(IDiagnostics* diagnostics)
+  explicit LinkContext(IDiagnostics* diagnostics)
       : diagnostics_(diagnostics), name_mangler_({}), symbols_(&name_mangler_) {
   }
 
@@ -163,7 +163,7 @@
 // See b/37498913.
 class FeatureSplitSymbolTableDelegate : public DefaultSymbolTableDelegate {
  public:
-  FeatureSplitSymbolTableDelegate(IAaptContext* context) : context_(context) {
+  explicit FeatureSplitSymbolTableDelegate(IAaptContext* context) : context_(context) {
   }
 
   virtual ~FeatureSplitSymbolTableDelegate() = default;
@@ -1545,7 +1545,8 @@
   // to the IArchiveWriter.
   bool WriteApk(IArchiveWriter* writer, proguard::KeepSet* keep_set, xml::XmlResource* manifest,
                 ResourceTable* table) {
-    const bool keep_raw_values = context_->GetPackageType() == PackageType::kStaticLib;
+    const bool keep_raw_values = (context_->GetPackageType() == PackageType::kStaticLib)
+                                 || options_.keep_raw_values;
     bool result = FlattenXml(context_, *manifest, kAndroidManifestPath, keep_raw_values,
                              true /*utf16*/, options_.output_format, writer);
     if (!result) {
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index 950dac2..f70470a 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -75,6 +75,7 @@
 
   // Flattening options.
   TableFlattenerOptions table_flattener_options;
+  bool keep_raw_values = false;
 
   // Split APK options.
   TableSplitterOptions table_splitter_options;
@@ -100,24 +101,26 @@
   explicit LinkCommand(IDiagnostics* diag) : Command("link", "l"),
                                              diag_(diag) {
     SetDescription("Links resources into an apk.");
-    AddRequiredFlag("-o", "Output path.", &options_.output_path);
+    AddRequiredFlag("-o", "Output path.", &options_.output_path, Command::kPath);
     AddRequiredFlag("--manifest", "Path to the Android manifest to build.",
-        &options_.manifest_path);
-    AddOptionalFlagList("-I", "Adds an Android APK to link against.", &options_.include_paths);
+        &options_.manifest_path, Command::kPath);
+    AddOptionalFlagList("-I", "Adds an Android APK to link against.", &options_.include_paths,
+         Command::kPath);
     AddOptionalFlagList("-A", "An assets directory to include in the APK. These are unprocessed.",
-        &options_.assets_dirs);
+        &options_.assets_dirs, Command::kPath);
     AddOptionalFlagList("-R", "Compilation unit to link, using `overlay` semantics.\n"
-        "The last conflicting resource given takes precedence.", &overlay_arg_list_);
+        "The last conflicting resource given takes precedence.", &overlay_arg_list_,
+        Command::kPath);
     AddOptionalFlag("--package-id",
         "Specify the package ID to use for this app. Must be greater or equal to\n"
             "0x7f and can't be used with --static-lib or --shared-lib.", &package_id_);
     AddOptionalFlag("--java", "Directory in which to generate R.java.",
-        &options_.generate_java_class_path);
+        &options_.generate_java_class_path, Command::kPath);
     AddOptionalFlag("--proguard", "Output file for generated Proguard rules.",
-        &options_.generate_proguard_rules_path);
+        &options_.generate_proguard_rules_path, Command::kPath);
     AddOptionalFlag("--proguard-main-dex",
         "Output file for generated Proguard rules for the main dex.",
-        &options_.generate_main_dex_proguard_rules_path);
+        &options_.generate_main_dex_proguard_rules_path, Command::kPath);
     AddOptionalSwitch("--proguard-conditional-keep-rules",
         "Generate conditional Proguard keep rules.",
         &options_.generate_conditional_proguard_rules);
@@ -242,6 +245,8 @@
         &options_.extensions_to_not_compress);
     AddOptionalSwitch("--no-compress", "Do not compress any resources.",
         &options_.do_not_compress_anything);
+    AddOptionalSwitch("--keep-raw-values", "Preserve raw attribute values in xml files.",
+        &options_.keep_raw_values);
     AddOptionalSwitch("--warn-manifest-validation",
         "Treat manifest validation errors as warnings.",
         &options_.manifest_fixer_options.warn_validation);
@@ -250,7 +255,6 @@
             "Syntax: path/to/output.apk:<config>[,<config>[...]].\n"
             "On Windows, use a semicolon ';' separator instead.",
         &split_args_);
-    AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
     AddOptionalSwitch("--debug-mode",
         "Inserts android:debuggable=\"true\" in to the application node of the\n"
             "manifest, making the application debuggable even on production devices.",
@@ -258,6 +262,7 @@
     AddOptionalSwitch("--strict-visibility",
         "Do not allow overlays with different visibility levels.",
         &options_.strict_visibility);
+    AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
   }
 
   int Action(const std::vector<std::string>& args) override;
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
new file mode 100644
index 0000000..9ea93f6
--- /dev/null
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -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.
+ */
+
+#include "Link.h"
+
+#include "LoadedApk.h"
+#include "test/Test.h"
+
+using testing::Eq;
+using testing::Ne;
+
+namespace aapt {
+
+using LinkTest = CommandTestFixture;
+
+TEST_F(LinkTest, RemoveRawXmlStrings) {
+  StdErrDiagnostics diag;
+  const std::string compiled_files_dir = GetTestPath("compiled");
+  ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
+                          compiled_files_dir, &diag));
+
+  const std::string out_apk = GetTestPath("out.apk");
+  std::vector<std::string> link_args = {
+      "--manifest", GetDefaultManifest(),
+      "-o", out_apk,
+  };
+
+  ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
+
+  // Load the binary xml tree
+  android::ResXMLTree tree;
+  std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_apk, &diag);
+
+  std::unique_ptr<io::IData> data = OpenFileAsData(apk.get(), "res/xml/test.xml");
+  ASSERT_THAT(data, Ne(nullptr));
+
+  AssertLoadXml(apk.get(), data.get(), &tree);
+
+  // Check that the raw string index has not been assigned
+  EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(-1));
+}
+
+TEST_F(LinkTest, KeepRawXmlStrings) {
+  StdErrDiagnostics diag;
+  const std::string compiled_files_dir = GetTestPath("compiled");
+  ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
+                          compiled_files_dir, &diag));
+
+  const std::string out_apk = GetTestPath("out.apk");
+  std::vector<std::string> link_args = {
+      "--manifest", GetDefaultManifest(),
+      "-o", out_apk,
+      "--keep-raw-values"
+  };
+
+  ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
+
+  // Load the binary xml tree
+  android::ResXMLTree tree;
+  std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_apk, &diag);
+
+  std::unique_ptr<io::IData> data = OpenFileAsData(apk.get(), "res/xml/test.xml");
+  ASSERT_THAT(data, Ne(nullptr));
+
+  AssertLoadXml(apk.get(), data.get(), &tree);
+
+  // Check that the raw string index has been set to the correct string pool entry
+  int32_t raw_index = tree.getAttributeValueStringID(0);
+  ASSERT_THAT(raw_index, Ne(-1));
+  EXPECT_THAT(util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)), Eq("007"));
+}
+
+}  // namespace aapt
\ No newline at end of file
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 328b0be..2e6af18 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -41,6 +41,7 @@
 #include "optimize/MultiApkGenerator.h"
 #include "optimize/ResourceDeduper.h"
 #include "optimize/ResourceFilter.h"
+#include "optimize/ResourcePathShortener.h"
 #include "optimize/VersionCollapser.h"
 #include "split/TableSplitter.h"
 #include "util/Files.h"
@@ -52,6 +53,7 @@
 using ::android::ResTable_config;
 using ::android::StringPiece;
 using ::android::base::ReadFileToString;
+using ::android::base::WriteStringToFile;
 using ::android::base::StringAppendF;
 using ::android::base::StringPrintf;
 
@@ -143,6 +145,21 @@
       return 1;
     }
 
+    if (options_.shorten_resource_paths) {
+      ResourcePathShortener shortener(options_.table_flattener_options.shortened_path_map);
+      if (!shortener.Consume(context_, apk->GetResourceTable())) {
+        context_->GetDiagnostics()->Error(DiagMessage() << "failed shortening resource paths");
+        return 1;
+      }
+      if (options_.shortened_paths_map_path
+          && !WriteShortenedPathsMap(options_.table_flattener_options.shortened_path_map,
+                                      options_.shortened_paths_map_path.value())) {
+        context_->GetDiagnostics()->Error(DiagMessage()
+                                          << "failed to write shortened resource paths to file");
+        return 1;
+      }
+    }
+
     // Adjust the SplitConstraints so that their SDK version is stripped if it is less than or
     // equal to the minSdk.
     options_.split_constraints =
@@ -264,6 +281,15 @@
                                         ArchiveEntry::kAlign, writer);
   }
 
+  bool WriteShortenedPathsMap(const std::map<std::string, std::string> &path_map,
+                               const std::string &file_path) {
+    std::stringstream ss;
+    for (auto it = path_map.cbegin(); it != path_map.cend(); ++it) {
+      ss << it->first << " -> " << it->second << "\n";
+    }
+    return WriteStringToFile(ss.str(), file_path);
+  }
+
   OptimizeOptions options_;
   OptimizeContext* context_;
 };
diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h
index 43bc216..7f4a3ed 100644
--- a/tools/aapt2/cmd/Optimize.h
+++ b/tools/aapt2/cmd/Optimize.h
@@ -55,15 +55,22 @@
   // Set of artifacts to keep when generating multi-APK splits. If the list is empty, all artifacts
   // are kept and will be written as output.
   std::unordered_set<std::string> kept_artifacts;
+
+  // Whether or not to shorten resource paths in the APK.
+  bool shorten_resource_paths;
+
+  // Path to the output map of original resource paths to shortened paths.
+  Maybe<std::string> shortened_paths_map_path;
 };
 
 class OptimizeCommand : public Command {
  public:
   explicit OptimizeCommand() : Command("optimize") {
     SetDescription("Preforms resource optimizations on an apk.");
-    AddOptionalFlag("-o", "Path to the output APK.", &options_.output_path);
-    AddOptionalFlag("-d", "Path to the output directory (for splits).", &options_.output_dir);
-    AddOptionalFlag("-x", "Path to XML configuration file.", &config_path_);
+    AddOptionalFlag("-o", "Path to the output APK.", &options_.output_path, Command::kPath);
+    AddOptionalFlag("-d", "Path to the output directory (for splits).", &options_.output_dir,
+        Command::kPath);
+    AddOptionalFlag("-x", "Path to XML configuration file.", &config_path_, Command::kPath);
     AddOptionalSwitch("-p", "Print the multi APK artifacts and exit.", &print_only_);
     AddOptionalFlag(
         "--target-densities",
@@ -100,6 +107,12 @@
     AddOptionalSwitch("--enable-resource-obfuscation",
         "Enables obfuscation of key string pool to single value",
         &options_.table_flattener_options.collapse_key_stringpool);
+    AddOptionalSwitch("--enable-resource-path-shortening",
+        "Enables shortening of the path of the resources inside the APK.",
+        &options_.shorten_resource_paths);
+    AddOptionalFlag("--resource-path-shortening-map",
+        "Path to output the map of old resource paths to shortened paths.",
+        &options_.shortened_paths_map_path);
     AddOptionalSwitch("-v", "Enables verbose logging", &verbose_);
   }
 
@@ -108,6 +121,9 @@
  private:
   OptimizeOptions options_;
 
+  bool WriteObfuscatedPathsMap(const std::map<std::string, std::string> &path_map,
+                               const std::string &file_path);
+
   Maybe<std::string> config_path_;
   Maybe<std::string> whitelist_path_;
   Maybe<std::string> resources_config_path_;
@@ -121,4 +137,4 @@
 
 }// namespace aapt
 
-#endif //AAPT2_OPTIMIZE_H
\ No newline at end of file
+#endif //AAPT2_OPTIMIZE_H
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index c496ff0..40aaa05 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -42,6 +42,19 @@
 
 namespace {
 
+static std::u16string strcpy16_dtoh(const char16_t* src, size_t len) {
+  size_t utf16_len = strnlen16(src, len);
+  if (utf16_len == 0) {
+    return {};
+  }
+  std::u16string dst;
+  dst.resize(utf16_len);
+  for (size_t i = 0; i < utf16_len; i++) {
+    dst[i] = util::DeviceToHost16(src[i]);
+  }
+  return dst;
+}
+
 // Visitor that converts a reference's resource ID to a resource name, given a mapping from
 // resource ID to resource name.
 class ReferenceIdToNameVisitor : public DescendingValueVisitor {
@@ -176,12 +189,8 @@
   }
 
   // Extract the package name.
-  size_t len = strnlen16((const char16_t*)package_header->name, arraysize(package_header->name));
-  std::u16string package_name;
-  package_name.resize(len);
-  for (size_t i = 0; i < len; i++) {
-    package_name[i] = util::DeviceToHost16(package_header->name[i]);
-  }
+  std::u16string package_name = strcpy16_dtoh((const char16_t*)package_header->name,
+                                              arraysize(package_header->name));
 
   ResourceTablePackage* package =
       table_->CreatePackage(util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
@@ -435,6 +444,11 @@
   }
 
   auto overlayable = std::make_shared<Overlayable>();
+  overlayable->name = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->name,
+                                                      arraysize(header->name)));
+  overlayable->actor = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->actor,
+                                                       arraysize(header->name)));
+  overlayable->source = source_.WithLine(0);
 
   ResChunkPullParser parser(GetChunkData(chunk),
                             GetChunkDataLen(chunk));
@@ -459,10 +473,6 @@
           & ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) {
         policies |= OverlayableItem::Policy::kProduct;
       }
-      if (policy_header->policy_flags
-          & ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION) {
-        policies |= OverlayableItem::Policy::kProductServices;
-      }
 
       const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>(
           ((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize));
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 931d57b..9d341cc 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -217,9 +217,10 @@
   size_t entry_count_ = 0;
 };
 
-struct PolicyChunk {
-  uint32_t policy_flags;
-  std::set<ResourceId> ids;
+struct OverlayableChunk {
+  std::string actor;
+  Source source;
+  std::map<OverlayableItem::PolicyFlags, std::set<ResourceId>> policy_ids;
 };
 
 class PackageFlattener {
@@ -421,8 +422,9 @@
     return sorted_entries;
   }
 
-  void FlattenOverlayable(BigBuffer* buffer) {
-    std::vector<PolicyChunk> policies;
+  bool FlattenOverlayable(BigBuffer* buffer) {
+    std::set<ResourceId> seen_ids;
+    std::map<std::string, OverlayableChunk> overlayable_chunks;
 
     CHECK(bool(package_->id)) << "package must have an ID set when flattening <overlayable>";
     for (auto& type : package_->types) {
@@ -433,79 +435,116 @@
           continue;
         }
 
-        OverlayableItem& overlayable = entry->overlayable_item.value();
-        uint32_t policy_flags = OverlayableItem::Policy::kNone;
-        if (overlayable.policies & OverlayableItem::Policy::kPublic) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
-        }
-        if (overlayable.policies & OverlayableItem::Policy::kSystem) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
-        }
-        if (overlayable.policies & OverlayableItem::Policy::kVendor) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
-        }
-        if (overlayable.policies & OverlayableItem::Policy::kProduct) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
-        }
-        if (overlayable.policies & OverlayableItem::Policy::kProductServices) {
-          policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION;
+        OverlayableItem& item = entry->overlayable_item.value();
+
+        // Resource ids should only appear once in the resource table
+        ResourceId id = android::make_resid(package_->id.value(), type->id.value(),
+                                            entry->id.value());
+        CHECK(seen_ids.find(id) == seen_ids.end())
+            << "multiple overlayable definitions found for resource "
+            << ResourceName(package_->name, type->type, entry->name).to_string();
+        seen_ids.insert(id);
+
+        // Find the overlayable chunk with the specified name
+        OverlayableChunk* overlayable_chunk = nullptr;
+        auto iter = overlayable_chunks.find(item.overlayable->name);
+        if (iter == overlayable_chunks.end()) {
+          OverlayableChunk chunk{item.overlayable->actor, item.overlayable->source};
+          overlayable_chunk =
+              &overlayable_chunks.insert({item.overlayable->name, chunk}).first->second;
+        } else {
+          OverlayableChunk& chunk = iter->second;
+          if (!(chunk.source == item.overlayable->source)) {
+            // The name of an overlayable set of resources must be unique
+            context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source)
+                                                  << "duplicate overlayable name"
+                                                  << item.overlayable->name << "'");
+            context_->GetDiagnostics()->Error(DiagMessage(chunk.source)
+                                                  << "previous declaration here");
+            return false;
+          }
+
+          CHECK(chunk.actor == item.overlayable->actor);
+          overlayable_chunk = &chunk;
         }
 
-        if (overlayable.policies == OverlayableItem::Policy::kNone) {
+        uint32_t policy_flags = 0;
+        if (item.policies == OverlayableItem::Policy::kNone) {
           // Encode overlayable entries defined without a policy as publicly overlayable
           policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
-        }
-
-        // Find the overlayable policy chunk with the same policies as the entry
-        PolicyChunk* policy_chunk = nullptr;
-        for (PolicyChunk& policy : policies) {
-          if (policy.policy_flags == policy_flags) {
-            policy_chunk = &policy;
-            break;
+        } else {
+          if (item.policies & OverlayableItem::Policy::kPublic) {
+            policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
+          }
+          if (item.policies & OverlayableItem::Policy::kSystem) {
+            policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
+          }
+          if (item.policies & OverlayableItem::Policy::kVendor) {
+            policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
+          }
+          if (item.policies & OverlayableItem::Policy::kProduct) {
+            policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
           }
         }
 
-        // Create a new policy chunk if an existing one with the same policy cannot be found
-        if (policy_chunk == nullptr) {
-          PolicyChunk p;
-          p.policy_flags = policy_flags;
-          policies.push_back(p);
-          policy_chunk = &policies.back();
+        auto policy = overlayable_chunk->policy_ids.find(policy_flags);
+        if (policy != overlayable_chunk->policy_ids.end()) {
+          policy->second.insert(id);
+        } else {
+          overlayable_chunk->policy_ids.insert(
+              std::make_pair(policy_flags, std::set<ResourceId>{id}));
         }
-
-        policy_chunk->ids.insert(android::make_resid(package_->id.value(), type->id.value(),
-                                                     entry->id.value()));
       }
     }
 
-    if (policies.empty()) {
-      // Only write the overlayable chunk if the APK has overlayable entries
-      return;
-    }
+    for (auto& overlayable_pair : overlayable_chunks) {
+      std::string name = overlayable_pair.first;
+      OverlayableChunk& overlayable = overlayable_pair.second;
 
-    ChunkWriter writer(buffer);
-    writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE);
-
-    // Write each policy block for the overlayable
-    for (PolicyChunk& policy : policies) {
-      ChunkWriter policy_writer(buffer);
-      ResTable_overlayable_policy_header* policy_type =
-          policy_writer.StartChunk<ResTable_overlayable_policy_header>(
-              RES_TABLE_OVERLAYABLE_POLICY_TYPE);
-      policy_type->policy_flags = util::HostToDevice32(policy.policy_flags);
-      policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(policy.ids.size()));
-
-      // Write the ids after the policy header
-      ResTable_ref* id_block = policy_writer.NextBlock<ResTable_ref>(policy.ids.size());
-      for (const ResourceId& id : policy.ids) {
-        id_block->ident = util::HostToDevice32(id.id);
-        id_block++;
+      // Write the header of the overlayable chunk
+      ChunkWriter overlayable_writer(buffer);
+      auto* overlayable_type =
+          overlayable_writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE);
+      if (name.size() >= arraysize(overlayable_type->name)) {
+        diag_->Error(DiagMessage() << "overlayable name '" << name
+                                   << "' exceeds maximum length ("
+                                   << arraysize(overlayable_type->name)
+                                   << " utf16 characters)");
+        return false;
       }
+      strcpy16_htod(overlayable_type->name, arraysize(overlayable_type->name),
+                    util::Utf8ToUtf16(name));
 
-      policy_writer.Finish();
+      if (overlayable.actor.size() >= arraysize(overlayable_type->actor)) {
+        diag_->Error(DiagMessage() << "overlayable name '" << overlayable.actor
+                                   << "' exceeds maximum length ("
+                                   << arraysize(overlayable_type->actor)
+                                   << " utf16 characters)");
+        return false;
+      }
+      strcpy16_htod(overlayable_type->actor, arraysize(overlayable_type->actor),
+                    util::Utf8ToUtf16(overlayable.actor));
+
+      // Write each policy block for the overlayable
+      for (auto& policy_ids : overlayable.policy_ids) {
+        ChunkWriter policy_writer(buffer);
+        auto* policy_type = policy_writer.StartChunk<ResTable_overlayable_policy_header>(
+            RES_TABLE_OVERLAYABLE_POLICY_TYPE);
+        policy_type->policy_flags = util::HostToDevice32(static_cast<uint32_t>(policy_ids.first));
+        policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(
+                                                            policy_ids.second.size()));
+        // Write the ids after the policy header
+        auto* id_block = policy_writer.NextBlock<ResTable_ref>(policy_ids.second.size());
+        for (const ResourceId& id : policy_ids.second) {
+          id_block->ident = util::HostToDevice32(id.id);
+          id_block++;
+        }
+        policy_writer.Finish();
+      }
+      overlayable_writer.Finish();
     }
 
-    writer.Finish();
+    return true;
   }
 
   bool FlattenTypeSpec(ResourceTableType* type, std::vector<ResourceEntry*>* sorted_entries,
diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h
index 635cb21..71330e3 100644
--- a/tools/aapt2/format/binary/TableFlattener.h
+++ b/tools/aapt2/format/binary/TableFlattener.h
@@ -46,6 +46,9 @@
 
   // When true, sort the entries in the values string pool by priority and configuration.
   bool sort_stringpool_entries = true;
+
+  // Map from original resource paths to shortened resource paths.
+  std::map<std::string, std::string> shortened_path_map;
 };
 
 class TableFlattener : public IResourceTableConsumer {
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index a5fb6fd..ddc1173 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -657,36 +657,34 @@
 TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) {
   auto overlayable = std::make_shared<Overlayable>("TestName", "overlay://theme");
   std::string name_zero = "com.app.test:integer/overlayable_zero_item";
-  OverlayableItem overlayable_zero_item(overlayable);
-  overlayable_zero_item.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_zero_item.policies |= OverlayableItem::Policy::kSystem;
-  overlayable_zero_item.policies |= OverlayableItem::Policy::kProductServices;
+  OverlayableItem overlayable_item_zero(overlayable);
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
 
   std::string name_one = "com.app.test:integer/overlayable_one_item";
-  OverlayableItem overlayable_one_item(overlayable);
-  overlayable_one_item.policies |= OverlayableItem::Policy::kPublic;
-  overlayable_one_item.policies |= OverlayableItem::Policy::kProductServices;
+  OverlayableItem overlayable_item_one(overlayable);
+  overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
 
   std::string name_two = "com.app.test:integer/overlayable_two_item";
-  OverlayableItem overlayable_two_item(overlayable);
-  overlayable_two_item.policies |= OverlayableItem::Policy::kProduct;
-  overlayable_two_item.policies |= OverlayableItem::Policy::kSystem;
-  overlayable_two_item.policies |= OverlayableItem::Policy::kVendor;
+  OverlayableItem overlayable_item_two(overlayable);
+  overlayable_item_two.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
 
   std::string name_three = "com.app.test:integer/overlayable_three_item";
-  OverlayableItem overlayable_three_item(overlayable);
+  OverlayableItem overlayable_item_three(overlayable);
 
   std::unique_ptr<ResourceTable> table =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.test", 0x7f)
           .AddSimple(name_zero, ResourceId(0x7f020000))
-          .SetOverlayable(name_zero, overlayable_zero_item)
+          .SetOverlayable(name_zero, overlayable_item_zero)
           .AddSimple(name_one, ResourceId(0x7f020001))
-          .SetOverlayable(name_one, overlayable_one_item)
+          .SetOverlayable(name_one, overlayable_item_one)
           .AddSimple(name_two, ResourceId(0x7f020002))
-          .SetOverlayable(name_two, overlayable_two_item)
+          .SetOverlayable(name_two, overlayable_item_two)
           .AddSimple(name_three, ResourceId(0x7f020003))
-          .SetOverlayable(name_three, overlayable_three_item)
+          .SetOverlayable(name_three, overlayable_item_three)
           .Build();
 
   ResourceTable output_table;
@@ -698,16 +696,14 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem
-                                       | OverlayableItem::Policy::kProduct
-                                       | OverlayableItem::Policy::kProductServices);
+                                       | OverlayableItem::Policy::kProduct);
 
   search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
   ASSERT_TRUE(search_result);
   ASSERT_THAT(search_result.value().entry, NotNull());
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   overlayable_item = search_result.value().entry->overlayable_item.value();
-  EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic
-                                       | OverlayableItem::Policy::kProductServices);
+  EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
 
   search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
   ASSERT_TRUE(search_result);
@@ -724,6 +720,80 @@
   ASSERT_TRUE(search_result.value().entry->overlayable_item);
   overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
+  EXPECT_EQ(overlayable_item.overlayable->name, "TestName");
+  EXPECT_EQ(overlayable_item.overlayable->actor, "overlay://theme");
+  EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
+}
+
+TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) {
+  auto group = std::make_shared<Overlayable>("TestName", "overlay://theme");
+  std::string name_zero = "com.app.test:integer/overlayable_zero";
+  OverlayableItem overlayable_item_zero(group);
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
+
+  auto group_one = std::make_shared<Overlayable>("OtherName", "overlay://customization");
+  std::string name_one = "com.app.test:integer/overlayable_one";
+  OverlayableItem overlayable_item_one(group_one);
+  overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
+
+  std::string name_two = "com.app.test:integer/overlayable_two";
+  OverlayableItem overlayable_item_two(group);
+  overlayable_item_two.policies |= OverlayableItem::Policy::kProduct;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
+  overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
+
+  std::string name_three = "com.app.test:integer/overlayable_three";
+  OverlayableItem overlayable_item_three(group_one);
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .SetPackageId("com.app.test", 0x7f)
+          .AddSimple(name_zero, ResourceId(0x7f020000))
+          .SetOverlayable(name_zero, overlayable_item_zero)
+          .AddSimple(name_one, ResourceId(0x7f020001))
+          .SetOverlayable(name_one, overlayable_item_one)
+          .AddSimple(name_two, ResourceId(0x7f020002))
+          .SetOverlayable(name_two, overlayable_item_two)
+          .AddSimple(name_three, ResourceId(0x7f020003))
+          .SetOverlayable(name_three, overlayable_item_three)
+          .Build();
+  ResourceTable output_table;
+  ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &output_table));
+  auto search_result = output_table.FindResource(test::ParseNameOrDie(name_zero));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  OverlayableItem& result_overlayable = search_result.value().entry->overlayable_item.value();
+  EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
+  EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
+                                         | OverlayableItem::Policy::kProduct);
+  search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  result_overlayable = search_result.value().entry->overlayable_item.value();
+  EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
+  EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic);
+  search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  result_overlayable = search_result.value().entry->overlayable_item.value();
+  EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
+  EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
+                                         | OverlayableItem::Policy::kProduct
+                                         | OverlayableItem::Policy::kVendor);
+  search_result = output_table.FindResource(test::ParseNameOrDie(name_three));
+  ASSERT_TRUE(search_result);
+  ASSERT_THAT(search_result.value().entry, NotNull());
+  ASSERT_TRUE(search_result.value().entry->overlayable_item);
+  result_overlayable = search_result.value().entry->overlayable_item.value();
+  EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
+  EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
+  EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic);
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 6b5746d..aff1b39 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -390,9 +390,6 @@
       case pb::OverlayableItem::PRODUCT:
         out_overlayable->policies |= OverlayableItem::Policy::kProduct;
         break;
-      case pb::OverlayableItem::PRODUCT_SERVICES:
-        out_overlayable->policies |= OverlayableItem::Policy::kProductServices;
-        break;
       default:
         *out_error = "unknown overlayable policy";
         return false;
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index 76fbb46..b549e23 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -303,9 +303,6 @@
   if (overlayable_item.policies & OverlayableItem::Policy::kProduct) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT);
   }
-  if (overlayable_item.policies & OverlayableItem::Policy::kProductServices) {
-    pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT_SERVICES);
-  }
   if (overlayable_item.policies & OverlayableItem::Policy::kSystem) {
     pb_overlayable_item->add_policy(pb::OverlayableItem::SYSTEM);
   }
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 4a3c1b8..cce3939 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -519,7 +519,7 @@
 
   OverlayableItem overlayable_item_bar(std::make_shared<Overlayable>(
       "TaskBar", "overlay://theme"));
-  overlayable_item_bar.policies |= OverlayableItem::Policy::kProductServices;
+  overlayable_item_bar.policies |= OverlayableItem::Policy::kPublic;
   overlayable_item_bar.policies |= OverlayableItem::Policy::kVendor;
 
   OverlayableItem overlayable_item_baz(std::make_shared<Overlayable>(
@@ -565,7 +565,7 @@
   overlayable_item = search_result.value().entry->overlayable_item.value();
   EXPECT_THAT(overlayable_item.overlayable->name, Eq("TaskBar"));
   EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
-  EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kProductServices
+  EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic
                                               | OverlayableItem::Policy::kVendor));
 
   search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz"));
diff --git a/tools/aapt2/integration-tests/CommandTests/android-28.jar b/tools/aapt2/integration-tests/CommandTests/android-28.jar
new file mode 100644
index 0000000..ef7576d
--- /dev/null
+++ b/tools/aapt2/integration-tests/CommandTests/android-28.jar
Binary files differ
diff --git a/tools/aapt2/java/ProguardRules.h b/tools/aapt2/java/ProguardRules.h
index 38b4860..f9656d1 100644
--- a/tools/aapt2/java/ProguardRules.h
+++ b/tools/aapt2/java/ProguardRules.h
@@ -49,7 +49,7 @@
  public:
   KeepSet() = default;
 
-  KeepSet(bool conditional_keep_rules) : conditional_keep_rules_(conditional_keep_rules) {
+  explicit KeepSet(bool conditional_keep_rules) : conditional_keep_rules_(conditional_keep_rules) {
   }
 
   inline void AddManifestClass(const UsageLocation& file, const std::string& class_name) {
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 85bf6f2..5812ec4 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -213,6 +213,27 @@
   return true;
 }
 
+static bool AddDeprecatedUsesFeatures(xml::Element* el, SourcePathDiagnostics* diag) {
+  if (xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, "name")) {
+    if (attr->value.empty()) {
+      return true;
+    }
+
+    // Add "android.hardware.fingerprint" when "android.hardware.biometric.fingerprint" is found,
+    // since the former is deprecated in Q and the latter is not present pre-Q. (see b/115639644)
+    if (attr->value == "android.hardware.biometrics.fingerprint") {
+      auto element = el->CloneElement([&](const xml::Element& el, xml::Element* out_el) {
+        xml::Attribute* cloned_attr = out_el->FindOrCreateAttribute(xml::kSchemaAndroid, "name");
+        cloned_attr->value = "android.hardware.fingerprint";
+      });
+
+      el->parent->AppendChild(std::move(element));
+    }
+  }
+
+  return true;
+}
+
 bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
                                IDiagnostics* diag) {
   // First verify some options.
@@ -247,6 +268,7 @@
   // Common <uses-feature> actions.
   xml::XmlNodeAction uses_feature_action;
   uses_feature_action.Action(VerifyUsesFeature);
+  uses_feature_action.Action(AddDeprecatedUsesFeatures);
 
   // Common component actions.
   xml::XmlNodeAction component_action;
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index adea627..fcc9f55 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -832,4 +832,36 @@
   EXPECT_THAT(Verify(input), NotNull());
 }
 
+TEST_F(ManifestFixerTest, UsesFeatureAddDeprecated) {
+  std::string input = R"(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android">
+        <uses-feature android:name="android.hardware.biometrics.fingerprint" />
+        <feature-group>
+          <uses-feature android:name="android.hardware.biometrics.fingerprint" />
+        </feature-group>
+      </manifest>)";
+
+  std::unique_ptr<xml::XmlResource> manifest = Verify(input);
+  ASSERT_THAT(manifest, NotNull());
+  EXPECT_THAT(manifest->root->FindChildWithAttribute("", "uses-feature",
+                                                     xml::kSchemaAndroid, "name",
+                                                     "android.hardware.biometrics.fingerprint"),
+              Ne(nullptr));
+  EXPECT_THAT(manifest->root->FindChildWithAttribute("", "uses-feature",
+                                                     xml::kSchemaAndroid, "name",
+                                                     "android.hardware.fingerprint"),
+              Ne(nullptr));
+
+  xml::Element* feature_group = manifest->root->FindChild("", "feature-group");
+  ASSERT_THAT(feature_group, Ne(nullptr));
+
+  EXPECT_THAT(feature_group->FindChildWithAttribute("", "uses-feature", xml::kSchemaAndroid, "name",
+                                                    "android.hardware.biometrics.fingerprint"),
+              Ne(nullptr));
+  EXPECT_THAT(feature_group->FindChildWithAttribute("", "uses-feature", xml::kSchemaAndroid, "name",
+                                                    "android.hardware.fingerprint"),
+              Ne(nullptr));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 921d634..ad3674e 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -484,7 +484,7 @@
 
   OverlayableItem overlayable_item(overlayable);
   overlayable_item.policies |= OverlayableItem::Policy::kPublic;
-  overlayable_item.policies |= OverlayableItem::Policy::kProductServices;
+  overlayable_item.policies |= OverlayableItem::Policy::kSystem;
   std::unique_ptr<ResourceTable> table_b =
       test::ResourceTableBuilder()
           .SetPackageId("com.app.a", 0x7f)
@@ -506,7 +506,7 @@
   EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources"));
   EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization"));
   EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic
-                                                   | OverlayableItem::Policy::kProductServices));
+                                                   | OverlayableItem::Policy::kSystem));
 }
 
 TEST_F(TableMergerTest, SameResourceDifferentNameFail) {
diff --git a/tools/aapt2/link/XmlCompatVersioner.h b/tools/aapt2/link/XmlCompatVersioner.h
index 099e23c..9980618 100644
--- a/tools/aapt2/link/XmlCompatVersioner.h
+++ b/tools/aapt2/link/XmlCompatVersioner.h
@@ -55,7 +55,7 @@
  public:
   using Rules = std::unordered_map<ResourceId, std::unique_ptr<IDegradeRule>>;
 
-  XmlCompatVersioner(const Rules* rules);
+  explicit XmlCompatVersioner(const Rules* rules);
 
   std::vector<std::unique_ptr<xml::XmlResource>> Process(IAaptContext* context,
                                                          xml::XmlResource* doc,
@@ -83,7 +83,7 @@
 
 class DegradeToManyRule : public IDegradeRule {
  public:
-  DegradeToManyRule(std::vector<ReplacementAttr> attrs);
+  explicit DegradeToManyRule(std::vector<ReplacementAttr> attrs);
   virtual ~DegradeToManyRule() = default;
 
   std::vector<DegradeResult> Degrade(const xml::Element& src_el, const xml::Attribute& src_attr,
diff --git a/tools/aapt2/optimize/ResourcePathShortener.cpp b/tools/aapt2/optimize/ResourcePathShortener.cpp
new file mode 100644
index 0000000..c5df3dd
--- /dev/null
+++ b/tools/aapt2/optimize/ResourcePathShortener.cpp
@@ -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.
+ */
+
+#include "optimize/ResourcePathShortener.h"
+
+#include <math.h>
+#include <unordered_set>
+
+#include "androidfw/StringPiece.h"
+
+#include "ResourceTable.h"
+#include "ValueVisitor.h"
+
+
+static const std::string base64_chars =
+             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+             "abcdefghijklmnopqrstuvwxyz"
+             "0123456789-_";
+
+namespace aapt {
+
+ResourcePathShortener::ResourcePathShortener(
+    std::map<std::string, std::string>& path_map_out)
+    : path_map_(path_map_out) {
+}
+
+std::string ShortenFileName(const android::StringPiece& file_path, int output_length) {
+  std::size_t hash_num = std::hash<android::StringPiece>{}(file_path);
+  std::string result = "";
+  // Convert to (modified) base64 so that it is a proper file path.
+  for (int i = 0; i < output_length; i++) {
+    uint8_t sextet = hash_num & 0x3f;
+    hash_num >>= 6;
+    result += base64_chars[sextet];
+  }
+  return result;
+}
+
+
+// Calculate the optimal hash length such that an average of 10% of resources
+// collide in their shortened path.
+// Reference: http://matt.might.net/articles/counting-hash-collisions/
+int OptimalShortenedLength(int num_resources) {
+  int num_chars = 2;
+  double N = 64*64; // hash space when hash is 2 chars long
+  double max_collisions = num_resources * 0.1;
+  while (num_resources - N + N * pow((N - 1) / N, num_resources) > max_collisions) {
+    N *= 64;
+    num_chars++;
+  }
+  return num_chars;
+}
+
+std::string GetShortenedPath(const android::StringPiece& shortened_filename,
+    const android::StringPiece& extension, int collision_count) {
+  std::string shortened_path = "res/" + shortened_filename.to_string();
+  if (collision_count > 0) {
+    shortened_path += std::to_string(collision_count);
+  }
+  shortened_path += extension;
+  return shortened_path;
+}
+
+bool ResourcePathShortener::Consume(IAaptContext* context, ResourceTable* table) {
+  // used to detect collisions
+  std::unordered_set<std::string> shortened_paths;
+  std::unordered_set<FileReference*> file_refs;
+  for (auto& package : table->packages) {
+    for (auto& type : package->types) {
+      for (auto& entry : type->entries) {
+        for (auto& config_value : entry->values) {
+          FileReference* file_ref = ValueCast<FileReference>(config_value->value.get());
+          if (file_ref) {
+            file_refs.insert(file_ref);
+          }
+        }
+      }
+    }
+  }
+  int num_chars = OptimalShortenedLength(file_refs.size());
+  for (auto& file_ref : file_refs) {
+    android::StringPiece res_subdir, actual_filename, extension;
+    util::ExtractResFilePathParts(*file_ref->path, &res_subdir, &actual_filename, &extension);
+
+    std::string shortened_filename = ShortenFileName(*file_ref->path, num_chars);
+    int collision_count = 0;
+    std::string shortened_path = GetShortenedPath(shortened_filename, extension, collision_count);
+    while (shortened_paths.find(shortened_path) != shortened_paths.end()) {
+      collision_count++;
+      shortened_path = GetShortenedPath(shortened_filename, extension, collision_count);
+    }
+    shortened_paths.insert(shortened_path);
+    path_map_.insert({*file_ref->path, shortened_path});
+    file_ref->path = table->string_pool.MakeRef(shortened_path, file_ref->path.GetContext());
+  }
+  return true;
+}
+
+}  // namespace aapt
diff --git a/tools/aapt2/optimize/ResourcePathShortener.h b/tools/aapt2/optimize/ResourcePathShortener.h
new file mode 100644
index 0000000..f1074ef
--- /dev/null
+++ b/tools/aapt2/optimize/ResourcePathShortener.h
@@ -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.
+ */
+
+#ifndef AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H
+#define AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H
+
+#include <map>
+
+#include "android-base/macros.h"
+
+#include "process/IResourceTableConsumer.h"
+
+namespace aapt {
+
+class ResourceTable;
+
+// Maps resources in the apk to shortened paths.
+class ResourcePathShortener : public IResourceTableConsumer {
+ public:
+  explicit ResourcePathShortener(std::map<std::string, std::string>& path_map_out);
+
+  bool Consume(IAaptContext* context, ResourceTable* table) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ResourcePathShortener);
+  std::map<std::string, std::string>& path_map_;
+};
+
+} // namespace aapt
+
+#endif  // AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H
diff --git a/tools/aapt2/optimize/ResourcePathShortener_test.cpp b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
new file mode 100644
index 0000000..88cadc7
--- /dev/null
+++ b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
@@ -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.
+ */
+
+#include "optimize/ResourcePathShortener.h"
+
+#include "ResourceTable.h"
+#include "test/Test.h"
+
+using ::aapt::test::GetValue;
+using ::testing::Not;
+using ::testing::NotNull;
+using ::testing::Eq;
+
+namespace aapt {
+
+TEST(ResourcePathShortenerTest, FileRefPathsChangedInResourceTable) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .AddFileReference("android:drawable/xmlfile", "res/drawables/xmlfile.xml")
+          .AddFileReference("android:drawable/xmlfile2", "res/drawables/xmlfile2.xml")
+          .AddString("android:string/string", "res/should/still/be/the/same.png")
+          .Build();
+
+  std::map<std::string, std::string> path_map;
+  ASSERT_TRUE(ResourcePathShortener(path_map).Consume(context.get(), table.get()));
+
+  // Expect that the path map is populated
+  ASSERT_THAT(path_map.find("res/drawables/xmlfile.xml"), Not(Eq(path_map.end())));
+  ASSERT_THAT(path_map.find("res/drawables/xmlfile2.xml"), Not(Eq(path_map.end())));
+
+  // The file paths were changed
+  EXPECT_THAT(path_map.at("res/drawables/xmlfile.xml"), Not(Eq("res/drawables/xmlfile.xml")));
+  EXPECT_THAT(path_map.at("res/drawables/xmlfile2.xml"), Not(Eq("res/drawables/xmlfile2.xml")));
+
+  // Different file paths should remain different
+  EXPECT_THAT(path_map["res/drawables/xmlfile.xml"],
+              Not(Eq(path_map["res/drawables/xmlfile2.xml"])));
+
+  FileReference* ref =
+      GetValue<FileReference>(table.get(), "android:drawable/xmlfile");
+  ASSERT_THAT(ref, NotNull());
+  // The map correctly points to the new location of the file
+  EXPECT_THAT(path_map["res/drawables/xmlfile.xml"], Eq(*ref->path));
+
+  // Strings should not be affected, only file paths
+  EXPECT_THAT(
+      *GetValue<String>(table.get(), "android:string/string")->value,
+              Eq("res/should/still/be/the/same.png"));
+  EXPECT_THAT(path_map.find("res/should/still/be/the/same.png"), Eq(path_map.end()));
+}
+
+}   // namespace aapt
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index 51a2e37..2d8bd02 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -71,7 +71,7 @@
     bool is_dynamic = false;
   };
 
-  SymbolTable(NameMangler* mangler);
+  explicit SymbolTable(NameMangler* mangler);
 
   // Overrides the default ISymbolTableDelegate, which allows a custom defined strategy for
   // looking up resources from a set of sources.
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 50b41f1..777ca5c 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -173,10 +173,12 @@
 template <typename TValue>
 class ValueEqMatcher {
  public:
+  // NOLINTNEXTLINE(google-explicit-constructor)
   ValueEqMatcher(TValue expected) : expected_(std::move(expected)) {
   }
 
   template <typename T>
+  // NOLINTNEXTLINE(google-explicit-constructor)
   operator ::testing::Matcher<T>() const {
     return ::testing::Matcher<T>(new ValueEqImpl<T>(&expected_));
   }
@@ -188,10 +190,12 @@
 template <typename TValue>
 class ValueEqPointerMatcher {
  public:
+  // NOLINTNEXTLINE(google-explicit-constructor)
   ValueEqPointerMatcher(const TValue* expected) : expected_(expected) {
   }
 
   template <typename T>
+  // NOLINTNEXTLINE(google-explicit-constructor)
   operator ::testing::Matcher<T>() const {
     return ::testing::Matcher<T>(new ValueEqImpl<T>(expected_));
   }
diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp
new file mode 100644
index 0000000..3fcdfb7
--- /dev/null
+++ b/tools/aapt2/test/Fixture.cpp
@@ -0,0 +1,156 @@
+/*
+ * 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 "test/Fixture.h"
+
+#include <dirent.h>
+
+#include "android-base/errors.h"
+#include "android-base/file.h"
+#include "android-base/stringprintf.h"
+#include "android-base/utf8.h"
+#include "androidfw/StringPiece.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "cmd/Compile.h"
+#include "cmd/Link.h"
+#include "io/FileStream.h"
+#include "io/Util.h"
+#include "util/Files.h"
+
+using testing::Eq;
+using testing::Ne;
+
+namespace aapt {
+
+void ClearDirectory(const android::StringPiece& path) {
+  const std::string root_dir = path.to_string();
+  std::unique_ptr<DIR, decltype(closedir)*> dir(opendir(root_dir.data()), closedir);
+  if (!dir) {
+    StdErrDiagnostics().Error(DiagMessage() << android::base::SystemErrorCodeToString(errno));
+    return;
+  }
+
+  while (struct dirent* entry = readdir(dir.get())) {
+    // Do not delete hidden files and do not recurse to the parent of this directory
+    if (util::StartsWith(entry->d_name, ".")) {
+      continue;
+    }
+
+    std::string full_path = file::BuildPath({root_dir, entry->d_name});
+    if (file::GetFileType(full_path) == file::FileType::kDirectory) {
+      ClearDirectory(full_path);
+#ifdef _WIN32
+      _rmdir(full_path.c_str());
+#else
+      rmdir(full_path.c_str());
+#endif
+    } else {
+      android::base::utf8::unlink(full_path.c_str());
+    }
+  }
+}
+
+void TestDirectoryFixture::SetUp() {
+  temp_dir_ = file::BuildPath({android::base::GetExecutableDirectory(),
+                               "_temp",
+                               testing::UnitTest::GetInstance()->current_test_case()->name(),
+                               testing::UnitTest::GetInstance()->current_test_info()->name()});
+  ASSERT_TRUE(file::mkdirs(temp_dir_));
+  ClearDirectory(temp_dir_);
+}
+
+void TestDirectoryFixture::TearDown() {
+  ClearDirectory(temp_dir_);
+}
+
+bool TestDirectoryFixture::WriteFile(const std::string& path, const std::string& contents) {
+  CHECK(util::StartsWith(path, temp_dir_))
+      << "Attempting to create a file outside of test temporary directory.";
+
+  // Create any intermediate directories specified in the path
+  auto pos = std::find(path.rbegin(), path.rend(), file::sDirSep);
+  if (pos != path.rend()) {
+    std::string dirs = path.substr(0, (&*pos - path.data()));
+    file::mkdirs(dirs);
+  }
+
+  return android::base::WriteStringToFile(contents, path);
+}
+
+bool CommandTestFixture::CompileFile(const std::string& path, const std::string& contents,
+                                     const android::StringPiece& out_dir, IDiagnostics* diag) {
+  CHECK(WriteFile(path, contents));
+  CHECK(file::mkdirs(out_dir.data()));
+  return CompileCommand(diag).Execute({path, "-o", out_dir, "-v"}, &std::cerr) == 0;
+}
+
+bool CommandTestFixture::Link(const std::vector<std::string>& args,
+                              const android::StringPiece& flat_dir, IDiagnostics* diag) {
+  std::vector<android::StringPiece> link_args;
+  for(const std::string& arg : args) {
+    link_args.emplace_back(arg);
+  }
+
+  // Link against the android SDK
+  std::string android_sdk = file::BuildPath({android::base::GetExecutableDirectory(),
+                                             "integration-tests", "CommandTests",
+                                             "android-28.jar"});
+  link_args.insert(link_args.end(), {"-I", android_sdk});
+
+  // Add the files from the compiled resources directory to the link file arguments
+  Maybe<std::vector<std::string>> compiled_files = file::FindFiles(flat_dir, diag);
+  if (compiled_files) {
+    for (std::string& compile_file : compiled_files.value()) {
+      compile_file = file::BuildPath({flat_dir, compile_file});
+      link_args.emplace_back(std::move(compile_file));
+    }
+  }
+
+  return LinkCommand(diag).Execute(link_args, &std::cerr) == 0;
+}
+
+std::string CommandTestFixture::GetDefaultManifest() {
+  const std::string manifest_file = GetTestPath("AndroidManifest.xml");
+  CHECK(WriteFile(manifest_file, R"(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.aapt.command.test">
+      </manifest>)"));
+  return manifest_file;
+}
+
+std::unique_ptr<io::IData> CommandTestFixture::OpenFileAsData(LoadedApk* apk,
+                                                              const android::StringPiece& path) {
+  return apk
+      ->GetFileCollection()
+      ->FindFile(path)
+      ->OpenAsData();
+}
+
+void CommandTestFixture::AssertLoadXml(LoadedApk* apk, const io::IData* data,
+                                       android::ResXMLTree *out_tree) {
+  ASSERT_THAT(apk, Ne(nullptr));
+
+  out_tree->setTo(data->data(), data->size());
+  ASSERT_THAT(out_tree->getError(), Eq(android::OK));
+  while (out_tree->next() != android::ResXMLTree::START_TAG) {
+    ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
+    ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
+  }
+}
+
+} // namespace aapt
\ No newline at end of file
diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h
new file mode 100644
index 0000000..3079c75
--- /dev/null
+++ b/tools/aapt2/test/Fixture.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.
+ */
+
+#ifndef AAPT_TEST_FIXTURE_H
+#define AAPT_TEST_FIXTURE_H
+
+#include "android-base/file.h"
+#include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "io/Util.h"
+#include "util/Files.h"
+#include "LoadedApk.h"
+
+namespace aapt {
+
+class TestDirectoryFixture : public ::testing::Test {
+ public:
+  TestDirectoryFixture() = default;
+  virtual ~TestDirectoryFixture() = default;
+
+  // Creates the test directory or clears its contents if it contains previously created files.
+  void SetUp() override;
+
+  // Clears the contents of the test directory.
+  void TearDown() override;
+
+  // Retrieve the test directory of the fixture.
+  const android::StringPiece GetTestDirectory() {
+    return temp_dir_;
+  }
+
+  // Retrieves the absolute path of the specified relative path in the test directory. Directories
+  // should be separated using forward slashes ('/'), and these slashes will be translated to
+  // backslashes when running Windows tests.
+  const std::string GetTestPath(const android::StringPiece& path) {
+    std::string base = temp_dir_;
+    for (android::StringPiece part : util::Split(path, '/')) {
+      file::AppendPath(&base, part);
+    }
+    return base;
+  }
+
+  // Creates a file with the specified contents, creates any intermediate directories in the
+  // process. The file path must be an absolute path within the test directory.
+  bool WriteFile(const std::string& path, const std::string& contents);
+
+ private:
+  std::string temp_dir_;
+  DISALLOW_COPY_AND_ASSIGN(TestDirectoryFixture);
+};
+
+class CommandTestFixture : public TestDirectoryFixture {
+ public:
+  CommandTestFixture() = default;
+  virtual ~CommandTestFixture() = default;
+
+  // Wries the contents of the file to the specified path. The file is compiled and the flattened
+  // file is written to the out directory.
+  bool CompileFile(const std::string& path, const std::string& contents,
+                   const android::StringPiece& flat_out_dir, IDiagnostics* diag);
+
+  // Executes the link command with the specified arguments. The flattened files residing in the
+  // flat directory will be added to the link command as file arguments.
+  bool Link(const std::vector<std::string>& args, const android::StringPiece& flat_dir,
+            IDiagnostics* diag);
+
+  // Creates a minimal android manifest within the test directory and returns the file path.
+  std::string GetDefaultManifest();
+
+  // Returns pointer to data inside APK files
+  std::unique_ptr<io::IData> OpenFileAsData(LoadedApk* apk,
+                                            const android::StringPiece& path);
+
+  // Asserts that loading the tree from the specified file in the apk succeeds.
+  void AssertLoadXml(LoadedApk* apk, const io::IData* data,
+                     android::ResXMLTree* out_tree);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CommandTestFixture);
+};
+
+} // namespace aapt
+
+#endif  // AAPT_TEST_FIXTURE_H
\ No newline at end of file
diff --git a/tools/aapt2/test/Test.h b/tools/aapt2/test/Test.h
index a24c01c..7d96d1f 100644
--- a/tools/aapt2/test/Test.h
+++ b/tools/aapt2/test/Test.h
@@ -23,5 +23,6 @@
 #include "test/Builders.h"
 #include "test/Common.h"
 #include "test/Context.h"
+#include "test/Fixture.h"
 
 #endif  // AAPT_TEST_TEST_H
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 5cfbbf2..7b268bb 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -180,6 +180,17 @@
   base->append(part.data(), part.size());
 }
 
+std::string BuildPath(std::vector<const StringPiece>&& args) {
+  if (args.empty()) {
+    return "";
+  }
+  std::string out = args[0].to_string();
+  for (int i = 1; i < args.size(); i++) {
+    file::AppendPath(&out, args[i]);
+  }
+  return out;
+}
+
 std::string PackageToPath(const StringPiece& package) {
   std::string out_path;
   for (const StringPiece& part : util::Tokenize(package, '.')) {
diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h
index 219e1a0..5839552 100644
--- a/tools/aapt2/util/Files.h
+++ b/tools/aapt2/util/Files.h
@@ -57,6 +57,9 @@
 // Appends a path to `base`, separated by the directory separator.
 void AppendPath(std::string* base, android::StringPiece part);
 
+// Concatenates the list of paths and separates each part with the directory separator.
+std::string BuildPath(std::vector<const android::StringPiece>&& args);
+
 // Makes all the directories in `path`. The last element in the path is interpreted as a directory.
 bool mkdirs(const std::string& path);
 
diff --git a/tools/aapt2/util/Maybe.h b/tools/aapt2/util/Maybe.h
index 031276c..047e1a5 100644
--- a/tools/aapt2/util/Maybe.h
+++ b/tools/aapt2/util/Maybe.h
@@ -44,12 +44,12 @@
   Maybe(const Maybe& rhs);
 
   template <typename U>
-  Maybe(const Maybe<U>& rhs);  // NOLINT(implicit)
+  Maybe(const Maybe<U>& rhs);  // NOLINT(google-explicit-constructor)
 
   Maybe(Maybe&& rhs) noexcept;
 
   template <typename U>
-  Maybe(Maybe<U>&& rhs);  // NOLINT(implicit)
+  Maybe(Maybe<U>&& rhs);  // NOLINT(google-explicit-constructor)
 
   Maybe& operator=(const Maybe& rhs);
 
@@ -64,12 +64,12 @@
   /**
    * Construct a Maybe holding a value.
    */
-  Maybe(const T& value);  // NOLINT(implicit)
+  Maybe(const T& value);  // NOLINT(google-explicit-constructor)
 
   /**
    * Construct a Maybe holding a value.
    */
-  Maybe(T&& value);  // NOLINT(implicit)
+  Maybe(T&& value);  // NOLINT(google-explicit-constructor)
 
   /**
    * True if this holds a value, false if
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 6476abd..75c3eba 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -26,7 +26,7 @@
 $ apilint.py /tmp/currentblame.txt previous.txt --no-color
 """
 
-import re, sys, collections, traceback, argparse
+import re, sys, collections, traceback, argparse, itertools
 
 
 BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
@@ -50,45 +50,37 @@
     return "\033[%sm" % (";".join(codes))
 
 
-def ident(raw):
-    """Strips superficial signature changes, giving us a strong key that
-    can be used to identify members across API levels."""
-    raw = raw.replace(" deprecated ", " ")
-    raw = raw.replace(" synchronized ", " ")
-    raw = raw.replace(" final ", " ")
-    raw = re.sub("<.+?>", "", raw)
-    if " throws " in raw:
-        raw = raw[:raw.index(" throws ")]
-    return raw
-
-
 class Field():
-    def __init__(self, clazz, line, raw, blame):
+    def __init__(self, clazz, line, raw, blame, sig_format = 1):
         self.clazz = clazz
         self.line = line
         self.raw = raw.strip(" {;")
         self.blame = blame
 
-        # drop generics for now; may need multiple passes
-        raw = re.sub("<[^<]+?>", "", raw)
-        raw = re.sub("<[^<]+?>", "", raw)
+        if sig_format == 2:
+            V2LineParser(raw).parse_into_field(self)
+        elif sig_format == 1:
+            # drop generics for now; may need multiple passes
+            raw = re.sub("<[^<]+?>", "", raw)
+            raw = re.sub("<[^<]+?>", "", raw)
 
-        raw = raw.split()
-        self.split = list(raw)
+            raw = raw.split()
+            self.split = list(raw)
 
-        for r in ["field", "volatile", "transient", "public", "protected", "static", "final", "deprecated"]:
-            while r in raw: raw.remove(r)
+            for r in ["field", "volatile", "transient", "public", "protected", "static", "final", "deprecated"]:
+                while r in raw: raw.remove(r)
 
-        # ignore annotations for now
-        raw = [ r for r in raw if not r.startswith("@") ]
+            # ignore annotations for now
+            raw = [ r for r in raw if not r.startswith("@") ]
 
-        self.typ = raw[0]
-        self.name = raw[1].strip(";")
-        if len(raw) >= 4 and raw[2] == "=":
-            self.value = raw[3].strip(';"')
-        else:
-            self.value = None
-        self.ident = ident(self.raw)
+            self.typ = raw[0]
+            self.name = raw[1].strip(";")
+            if len(raw) >= 4 and raw[2] == "=":
+                self.value = raw[3].strip(';"')
+            else:
+                self.value = None
+
+        self.ident = "-".join((self.typ, self.name, self.value or ""))
 
     def __hash__(self):
         return hash(self.raw)
@@ -96,48 +88,55 @@
     def __repr__(self):
         return self.raw
 
-
 class Method():
-    def __init__(self, clazz, line, raw, blame):
+    def __init__(self, clazz, line, raw, blame, sig_format = 1):
         self.clazz = clazz
         self.line = line
         self.raw = raw.strip(" {;")
         self.blame = blame
 
-        # drop generics for now; may need multiple passes
-        raw = re.sub("<[^<]+?>", "", raw)
-        raw = re.sub("<[^<]+?>", "", raw)
+        if sig_format == 2:
+            V2LineParser(raw).parse_into_method(self)
+        elif sig_format == 1:
+            # drop generics for now; may need multiple passes
+            raw = re.sub("<[^<]+?>", "", raw)
+            raw = re.sub("<[^<]+?>", "", raw)
 
-        # handle each clause differently
-        raw_prefix, raw_args, _, raw_throws = re.match(r"(.*?)\((.*?)\)( throws )?(.*?);$", raw).groups()
+            # handle each clause differently
+            raw_prefix, raw_args, _, raw_throws = re.match(r"(.*?)\((.*?)\)( throws )?(.*?);$", raw).groups()
 
-        # parse prefixes
-        raw = re.split("[\s]+", raw_prefix)
-        for r in ["", ";"]:
-            while r in raw: raw.remove(r)
-        self.split = list(raw)
+            # parse prefixes
+            raw = re.split("[\s]+", raw_prefix)
+            for r in ["", ";"]:
+                while r in raw: raw.remove(r)
+            self.split = list(raw)
 
-        for r in ["method", "public", "protected", "static", "final", "deprecated", "abstract", "default", "operator"]:
-            while r in raw: raw.remove(r)
+            for r in ["method", "public", "protected", "static", "final", "deprecated", "abstract", "default", "operator", "synchronized"]:
+                while r in raw: raw.remove(r)
 
-        self.typ = raw[0]
-        self.name = raw[1]
+            self.typ = raw[0]
+            self.name = raw[1]
 
-        # parse args
-        self.args = []
-        for arg in re.split(",\s*", raw_args):
-            arg = re.split("\s", arg)
-            # ignore annotations for now
-            arg = [ a for a in arg if not a.startswith("@") ]
-            if len(arg[0]) > 0:
-                self.args.append(arg[0])
+            # parse args
+            self.args = []
+            for arg in re.split(",\s*", raw_args):
+                arg = re.split("\s", arg)
+                # ignore annotations for now
+                arg = [ a for a in arg if not a.startswith("@") ]
+                if len(arg[0]) > 0:
+                    self.args.append(arg[0])
 
-        # parse throws
-        self.throws = []
-        for throw in re.split(",\s*", raw_throws):
-            self.throws.append(throw)
+            # parse throws
+            self.throws = []
+            for throw in re.split(",\s*", raw_throws):
+                self.throws.append(throw)
+        else:
+            raise ValueError("Unknown signature format: " + sig_format)
 
-        self.ident = ident(self.raw)
+        self.ident = "-".join((self.typ, self.name, "-".join(self.args)))
+
+    def sig_matches(self, typ, name, args):
+        return typ == self.typ and name == self.name and args == self.args
 
     def __hash__(self):
         return hash(self.raw)
@@ -147,7 +146,7 @@
 
 
 class Class():
-    def __init__(self, pkg, line, raw, blame):
+    def __init__(self, pkg, line, raw, blame, sig_format = 1):
         self.pkg = pkg
         self.line = line
         self.raw = raw.strip(" {;")
@@ -156,31 +155,44 @@
         self.fields = []
         self.methods = []
 
-        # drop generics for now; may need multiple passes
-        raw = re.sub("<[^<]+?>", "", raw)
-        raw = re.sub("<[^<]+?>", "", raw)
+        if sig_format == 2:
+            V2LineParser(raw).parse_into_class(self)
+        elif sig_format == 1:
+            # drop generics for now; may need multiple passes
+            raw = re.sub("<[^<]+?>", "", raw)
+            raw = re.sub("<[^<]+?>", "", raw)
 
-        raw = raw.split()
-        self.split = list(raw)
-        if "class" in raw:
-            self.fullname = raw[raw.index("class")+1]
-        elif "interface" in raw:
-            self.fullname = raw[raw.index("interface")+1]
-        elif "@interface" in raw:
-            self.fullname = raw[raw.index("@interface")+1]
-        else:
-            raise ValueError("Funky class type %s" % (self.raw))
+            raw = raw.split()
+            self.split = list(raw)
+            if "class" in raw:
+                self.fullname = raw[raw.index("class")+1]
+            elif "interface" in raw:
+                self.fullname = raw[raw.index("interface")+1]
+            elif "@interface" in raw:
+                self.fullname = raw[raw.index("@interface")+1]
+            else:
+                raise ValueError("Funky class type %s" % (self.raw))
 
-        if "extends" in raw:
-            self.extends = raw[raw.index("extends")+1]
-            self.extends_path = self.extends.split(".")
+            if "extends" in raw:
+                self.extends = raw[raw.index("extends")+1]
+            else:
+                self.extends = None
+
+            if "implements" in raw:
+                self.implements = raw[raw.index("implements")+1]
+            else:
+                self.implements = None
         else:
-            self.extends = None
-            self.extends_path = []
+            raise ValueError("Unknown signature format: " + sig_format)
 
         self.fullname = self.pkg.name + "." + self.fullname
         self.fullname_path = self.fullname.split(".")
 
+        if self.extends is not None:
+            self.extends_path = self.extends.split(".")
+        else:
+            self.extends_path = []
+
         self.name = self.fullname[self.fullname.rindex(".")+1:]
 
     def merge_from(self, other):
@@ -208,6 +220,331 @@
     def __repr__(self):
         return self.raw
 
+class V2Tokenizer(object):
+    __slots__ = ["raw"]
+
+    DELIMITER = re.compile(r'\s+|[()@<>;,={}/"!?]|\[\]|\.\.\.')
+    STRING_SPECIAL = re.compile(r'["\\]')
+
+    def __init__(self, raw):
+        self.raw = raw
+
+    def tokenize(self):
+        tokens = []
+        current = 0
+        raw = self.raw
+        length = len(raw)
+
+        while current < length:
+            while current < length:
+                start = current
+                match = V2Tokenizer.DELIMITER.search(raw, start)
+                if match is not None:
+                    match_start = match.start()
+                    if match_start == current:
+                        end = match.end()
+                    else:
+                        end = match_start
+                else:
+                    end = length
+
+                token = raw[start:end]
+                current = end
+
+                if token == "" or token[0] == " ":
+                    continue
+                else:
+                    break
+
+            if token == "@":
+                if raw[start:start+11] == "@interface ":
+                    current = start + 11
+                    tokens.append("@interface")
+                    continue
+            elif token == '/':
+                if raw[start:start+2] == "//":
+                    current = length
+                    continue
+            elif token == '"':
+                current, string_token = self.tokenize_string(raw, length, current)
+                tokens.append(token + string_token)
+                continue
+
+            tokens.append(token)
+
+        return tokens
+
+    def tokenize_string(self, raw, length, current):
+        start = current
+        end = length
+        while start < end:
+            match = V2Tokenizer.STRING_SPECIAL.search(raw, start)
+            if match:
+                if match.group() == '"':
+                    end = match.end()
+                    break
+                elif match.group() == '\\':
+                    # ignore whatever is after the slash
+                    start += 2
+                else:
+                    raise ValueError("Unexpected match: `%s`" % (match.group()))
+            else:
+                raise ValueError("Unexpected EOF tokenizing string: `%s`" % (raw[current - 1:],))
+
+        token = raw[current:end]
+        return end, token
+
+class V2LineParser(object):
+    __slots__ = ["tokenized", "current", "len"]
+
+    FIELD_KINDS = ("field", "property", "enum_constant")
+    MODIFIERS = set("public protected internal private abstract default static final transient volatile synchronized native operator sealed strictfp infix inline suspend vararg".split())
+    JAVA_LANG_TYPES = set("AbstractMethodError AbstractStringBuilder Appendable ArithmeticException ArrayIndexOutOfBoundsException ArrayStoreException AssertionError AutoCloseable Boolean BootstrapMethodError Byte Character CharSequence Class ClassCastException ClassCircularityError ClassFormatError ClassLoader ClassNotFoundException Cloneable CloneNotSupportedException Comparable Compiler Deprecated Double Enum EnumConstantNotPresentException Error Exception ExceptionInInitializerError Float FunctionalInterface IllegalAccessError IllegalAccessException IllegalArgumentException IllegalMonitorStateException IllegalStateException IllegalThreadStateException IncompatibleClassChangeError IndexOutOfBoundsException InheritableThreadLocal InstantiationError InstantiationException Integer InternalError InterruptedException Iterable LinkageError Long Math NegativeArraySizeException NoClassDefFoundError NoSuchFieldError NoSuchFieldException NoSuchMethodError NoSuchMethodException NullPointerException Number NumberFormatException Object OutOfMemoryError Override Package package-info.java Process ProcessBuilder ProcessEnvironment ProcessImpl Readable ReflectiveOperationException Runnable Runtime RuntimeException RuntimePermission SafeVarargs SecurityException SecurityManager Short StackOverflowError StackTraceElement StrictMath String StringBuffer StringBuilder StringIndexOutOfBoundsException SuppressWarnings System Thread ThreadDeath ThreadGroup ThreadLocal Throwable TypeNotPresentException UNIXProcess UnknownError UnsatisfiedLinkError UnsupportedClassVersionError UnsupportedOperationException VerifyError VirtualMachineError Void".split())
+
+    def __init__(self, raw):
+        self.tokenized = V2Tokenizer(raw).tokenize()
+        self.current = 0
+        self.len = len(self.tokenized)
+
+    def parse_into_method(self, method):
+        method.split = []
+        kind = self.parse_one_of("ctor", "method")
+        method.split.append(kind)
+        annotations = self.parse_annotations()
+        method.split.extend(self.parse_modifiers())
+        self.parse_matching_paren("<", ">")
+        if "@Deprecated" in annotations:
+            method.split.append("deprecated")
+        if kind == "ctor":
+            method.typ = "ctor"
+        else:
+            method.typ = self.parse_type()
+            method.split.append(method.typ)
+        method.name = self.parse_name()
+        method.split.append(method.name)
+        self.parse_token("(")
+        method.args = self.parse_args()
+        self.parse_token(")")
+        method.throws = self.parse_throws()
+        if "@interface" in method.clazz.split:
+            self.parse_annotation_default()
+        self.parse_token(";")
+        self.parse_eof()
+
+    def parse_into_class(self, clazz):
+        clazz.split = []
+        annotations = self.parse_annotations()
+        if "@Deprecated" in annotations:
+            clazz.split.append("deprecated")
+        clazz.split.extend(self.parse_modifiers())
+        kind = self.parse_one_of("class", "interface", "@interface", "enum")
+        if kind == "enum":
+            # enums are implicitly final
+            clazz.split.append("final")
+        clazz.split.append(kind)
+        clazz.fullname = self.parse_name()
+        self.parse_matching_paren("<", ">")
+        extends = self.parse_extends()
+        clazz.extends = extends[0] if extends else None
+        implements = self.parse_implements()
+        clazz.implements = implements[0] if implements else None
+        # The checks assume that interfaces are always found in implements, which isn't true for
+        # subinterfaces.
+        if not implements and "interface" in clazz.split:
+            clazz.implements = clazz.extends
+        self.parse_token("{")
+        self.parse_eof()
+
+    def parse_into_field(self, field):
+        kind = self.parse_one_of(*V2LineParser.FIELD_KINDS)
+        field.split = [kind]
+        annotations = self.parse_annotations()
+        if "@Deprecated" in annotations:
+            field.split.append("deprecated")
+        field.split.extend(self.parse_modifiers())
+        field.typ = self.parse_type()
+        field.split.append(field.typ)
+        field.name = self.parse_name()
+        field.split.append(field.name)
+        if self.parse_if("="):
+            field.value = self.parse_value_stripped()
+        else:
+            field.value = None
+
+        self.parse_token(";")
+        self.parse_eof()
+
+    def lookahead(self):
+        return self.tokenized[self.current]
+
+    def parse_one_of(self, *options):
+        found = self.lookahead()
+        if found not in options:
+            raise ValueError("Parsing failed, expected one of `%s` but found `%s` in %s" % (options, found, repr(self.tokenized)))
+        return self.parse_token()
+
+    def parse_token(self, tok = None):
+        found = self.lookahead()
+        if tok is not None and found != tok:
+            raise ValueError("Parsing failed, expected `%s` but found `%s` in %s" % (tok, found, repr(self.tokenized)))
+        self.current += 1
+        return found
+
+    def eof(self):
+        return self.current == self.len
+
+    def parse_eof(self):
+        if not self.eof():
+            raise ValueError("Parsing failed, expected EOF, but %s has not been parsed in %s" % (self.tokenized[self.current:], self.tokenized))
+
+    def parse_if(self, tok):
+        if not self.eof() and self.lookahead() == tok:
+            self.parse_token()
+            return True
+        return False
+
+    def parse_annotations(self):
+        ret = []
+        while self.lookahead() == "@":
+            ret.append(self.parse_annotation())
+        return ret
+
+    def parse_annotation(self):
+        ret = self.parse_token("@") + self.parse_token()
+        self.parse_matching_paren("(", ")")
+        return ret
+
+    def parse_matching_paren(self, open, close):
+        start = self.current
+        if not self.parse_if(open):
+            return
+        length = len(self.tokenized)
+        count = 1
+        while count > 0:
+            if self.current == length:
+                raise ValueError("Unexpected EOF looking for closing paren: `%s`" % (self.tokenized[start:],))
+            t = self.parse_token()
+            if t == open:
+                count += 1
+            elif t == close:
+                count -= 1
+        return self.tokenized[start:self.current]
+
+    def parse_modifiers(self):
+        ret = []
+        while self.lookahead() in V2LineParser.MODIFIERS:
+            ret.append(self.parse_token())
+        return ret
+
+    def parse_kotlin_nullability(self):
+        t = self.lookahead()
+        if t == "?" or t == "!":
+            return self.parse_token()
+        return None
+
+    def parse_type(self):
+        self.parse_annotations()
+        type = self.parse_token()
+        if type[-1] == '.':
+            self.parse_annotations()
+            type += self.parse_token()
+        if type in V2LineParser.JAVA_LANG_TYPES:
+            type = "java.lang." + type
+        self.parse_matching_paren("<", ">")
+        while True:
+            t = self.lookahead()
+            if t == "@":
+                self.parse_annotation()
+            elif t == "[]":
+                type += self.parse_token()
+            elif self.parse_kotlin_nullability() is not None:
+                pass  # discard nullability for now
+            else:
+                break
+        return type
+
+    def parse_arg_type(self):
+        type = self.parse_type()
+        if self.parse_if("..."):
+            type += "..."
+        self.parse_kotlin_nullability() # discard nullability for now
+        return type
+
+    def parse_name(self):
+        return self.parse_token()
+
+    def parse_args(self):
+        args = []
+        if self.lookahead() == ")":
+            return args
+
+        while True:
+            args.append(self.parse_arg())
+            if self.lookahead() == ")":
+                return args
+            self.parse_token(",")
+
+    def parse_arg(self):
+        self.parse_if("vararg")  # kotlin vararg
+        self.parse_annotations()
+        type = self.parse_arg_type()
+        l = self.lookahead()
+        if l != "," and l != ")":
+            if self.lookahead() != '=':
+                self.parse_token()  # kotlin argument name
+            if self.parse_if('='): # kotlin default value
+                self.parse_expression()
+        return type
+
+    def parse_expression(self):
+        while not self.lookahead() in [')', ',', ';']:
+            (self.parse_matching_paren('(', ')') or
+            self.parse_matching_paren('{', '}') or
+            self.parse_token())
+
+    def parse_throws(self):
+        ret = []
+        if self.parse_if("throws"):
+            ret.append(self.parse_type())
+            while self.parse_if(","):
+                ret.append(self.parse_type())
+        return ret
+
+    def parse_extends(self):
+        if self.parse_if("extends"):
+            return self.parse_space_delimited_type_list()
+        return []
+
+    def parse_implements(self):
+        if self.parse_if("implements"):
+            return self.parse_space_delimited_type_list()
+        return []
+
+    def parse_space_delimited_type_list(self, terminals = ["implements", "{"]):
+        types = []
+        while True:
+            types.append(self.parse_type())
+            if self.lookahead() in terminals:
+                return types
+
+    def parse_annotation_default(self):
+        if self.parse_if("default"):
+            self.parse_expression()
+
+    def parse_value(self):
+        if self.lookahead() == "{":
+            return " ".join(self.parse_matching_paren("{", "}"))
+        elif self.lookahead() == "(":
+            return " ".join(self.parse_matching_paren("(", ")"))
+        else:
+            return self.parse_token()
+
+    def parse_value_stripped(self):
+        value = self.parse_value()
+        if value[0] == '"':
+            return value[1:-1]
+        return value
+
 
 def _parse_stream(f, clazz_cb=None, base_f=None, out_classes_with_base=None,
                   in_classes_with_base=[]):
@@ -252,8 +589,17 @@
     pkg = None
     clazz = None
     blame = None
+    sig_format = 1
 
     re_blame = re.compile("^([a-z0-9]{7,}) \(<([^>]+)>.+?\) (.+?)$")
+
+    field_prefixes = map(lambda kind: "    %s" % (kind,), V2LineParser.FIELD_KINDS)
+    def startsWithFieldPrefix(raw):
+        for prefix in field_prefixes:
+            if raw.startswith(prefix):
+                return True
+        return False
+
     for raw in f:
         line += 1
         raw = raw.rstrip()
@@ -264,16 +610,18 @@
         else:
             blame = None
 
-        if raw.startswith("package"):
+        if line == 1 and raw == "// Signature format: 2.0":
+            sig_format = 2
+        elif raw.startswith("package"):
             pkg = Package(line, raw, blame)
         elif raw.startswith("  ") and raw.endswith("{"):
-            clazz = Class(pkg, line, raw, blame)
+            clazz = Class(pkg, line, raw, blame, sig_format=sig_format)
         elif raw.startswith("    ctor"):
-            clazz.ctors.append(Method(clazz, line, raw, blame))
+            clazz.ctors.append(Method(clazz, line, raw, blame, sig_format=sig_format))
         elif raw.startswith("    method"):
-            clazz.methods.append(Method(clazz, line, raw, blame))
-        elif raw.startswith("    field"):
-            clazz.fields.append(Field(clazz, line, raw, blame))
+            clazz.methods.append(Method(clazz, line, raw, blame, sig_format=sig_format))
+        elif startsWithFieldPrefix(raw):
+            clazz.fields.append(Field(clazz, line, raw, blame, sig_format=sig_format))
         elif raw.startswith("  }") and clazz:
             yield clazz
 
@@ -367,7 +715,7 @@
     """Records an API failure to be processed later."""
     global failures
 
-    sig = "%s-%s-%s" % (clazz.fullname, repr(detail), msg)
+    sig = "%s-%s-%s" % (clazz.fullname, detail.ident if detail else None, msg)
     sig = sig.replace(" deprecated ", " ")
 
     failures[sig] = Failure(sig, clazz, detail, error, rule, msg)
@@ -408,7 +756,7 @@
 
 def verify_enums(clazz):
     """Enums are bad, mmkay?"""
-    if "extends java.lang.Enum" in clazz.raw:
+    if clazz.extends == "java.lang.Enum" or "enum" in clazz.split:
         error(clazz, None, "F5", "Enums are not allowed")
 
 
@@ -467,7 +815,7 @@
         interface OnFooListener { void onFoo() }"""
 
     if clazz.name.endswith("Listener"):
-        if " abstract class " in clazz.raw:
+        if "abstract" in clazz.split and "class" in clazz.split:
             error(clazz, None, "L1", "Listeners should be an interface, or otherwise renamed Callback")
 
         for m in clazz.methods:
@@ -546,16 +894,16 @@
     eq = False
     hc = False
     for m in clazz.methods:
-        if " static " in m.raw: continue
-        if "boolean equals(java.lang.Object)" in m.raw: eq = True
-        if "int hashCode()" in m.raw: hc = True
+        if "static" in m.split: continue
+        if m.sig_matches("boolean", "equals", ["java.lang.Object"]): eq = True
+        if m.sig_matches("int", "hashCode", []): hc = True
     if eq != hc:
         error(clazz, None, "M8", "Must override both equals and hashCode; missing one")
 
 
 def verify_parcelable(clazz):
     """Verify that Parcelable objects aren't hiding required bits."""
-    if "implements android.os.Parcelable" in clazz.raw:
+    if clazz.implements == "android.os.Parcelable":
         creator = [ i for i in clazz.fields if i.name == "CREATOR" ]
         write = [ i for i in clazz.methods if i.name == "writeToParcel" ]
         describe = [ i for i in clazz.methods if i.name == "describeContents" ]
@@ -563,8 +911,7 @@
         if len(creator) == 0 or len(write) == 0 or len(describe) == 0:
             error(clazz, None, "FW3", "Parcelable requires CREATOR, writeToParcel, and describeContents; missing one")
 
-        if ((" final class " not in clazz.raw) and
-            (" final deprecated class " not in clazz.raw)):
+        if "final" not in clazz.split:
             error(clazz, None, "FW8", "Parcelable classes must be final")
 
         for c in clazz.ctors:
@@ -616,7 +963,7 @@
             else:
                 error(clazz, f, "F2", "Bare fields must be marked final, or add accessors if mutable")
 
-        if not "static" in f.split:
+        if "static" not in f.split and "property" not in f.split:
             if not re.match("[a-z]([a-zA-Z]+)?", f.name):
                 error(clazz, f, "S1", "Non-static fields must be named using myField style")
 
@@ -684,7 +1031,7 @@
     """Verify that helper classes are named consistently with what they extend.
     All developer extendable methods should be named onFoo()."""
     test_methods = False
-    if "extends android.app.Service" in clazz.raw:
+    if clazz.extends == "android.app.Service":
         test_methods = True
         if not clazz.name.endswith("Service"):
             error(clazz, None, "CL4", "Inconsistent class name; should be FooService")
@@ -696,7 +1043,7 @@
                 if f.value != clazz.fullname:
                     error(clazz, f, "C4", "Inconsistent interface constant; expected '%s'" % (clazz.fullname))
 
-    if "extends android.content.ContentProvider" in clazz.raw:
+    if clazz.extends == "android.content.ContentProvider":
         test_methods = True
         if not clazz.name.endswith("Provider"):
             error(clazz, None, "CL4", "Inconsistent class name; should be FooProvider")
@@ -708,12 +1055,12 @@
                 if f.value != clazz.fullname:
                     error(clazz, f, "C4", "Inconsistent interface constant; expected '%s'" % (clazz.fullname))
 
-    if "extends android.content.BroadcastReceiver" in clazz.raw:
+    if clazz.extends == "android.content.BroadcastReceiver":
         test_methods = True
         if not clazz.name.endswith("Receiver"):
             error(clazz, None, "CL4", "Inconsistent class name; should be FooReceiver")
 
-    if "extends android.app.Activity" in clazz.raw:
+    if clazz.extends == "android.app.Activity":
         test_methods = True
         if not clazz.name.endswith("Activity"):
             error(clazz, None, "CL4", "Inconsistent class name; should be FooActivity")
@@ -731,7 +1078,7 @@
 def verify_builder(clazz):
     """Verify builder classes.
     Methods should return the builder to enable chaining."""
-    if " extends " in clazz.raw: return
+    if clazz.extends: return
     if not clazz.name.endswith("Builder"): return
 
     if clazz.name != "Builder":
@@ -759,7 +1106,7 @@
 
 def verify_aidl(clazz):
     """Catch people exposing raw AIDL."""
-    if "extends android.os.Binder" in clazz.raw or "implements android.os.IInterface" in clazz.raw:
+    if clazz.extends == "android.os.Binder" or clazz.implements == "android.os.IInterface":
         error(clazz, None, None, "Raw AIDL interfaces must not be exposed")
 
 
@@ -768,48 +1115,66 @@
     if clazz.pkg.name.startswith("com.android"):
         error(clazz, None, None, "Internal classes must not be exposed")
 
+def layering_build_ranking(ranking_list):
+    r = {}
+    for rank, ps in enumerate(ranking_list):
+        if not isinstance(ps, list):
+            ps = [ps]
+        for p in ps:
+            rs = r
+            for n in p.split('.'):
+                if n not in rs:
+                    rs[n] = {}
+                rs = rs[n]
+            rs['-rank'] = rank
+    return r
+
+LAYERING_PACKAGE_RANKING = layering_build_ranking([
+    ["android.service","android.accessibilityservice","android.inputmethodservice","android.printservice","android.appwidget","android.webkit","android.preference","android.gesture","android.print"],
+    "android.app",
+    "android.widget",
+    "android.view",
+    "android.animation",
+    "android.provider",
+    ["android.content","android.graphics.drawable"],
+    "android.database",
+    "android.text",
+    "android.graphics",
+    "android.os",
+    "android.util"
+])
 
 def verify_layering(clazz):
     """Catch package layering violations.
     For example, something in android.os depending on android.app."""
-    ranking = [
-        ["android.service","android.accessibilityservice","android.inputmethodservice","android.printservice","android.appwidget","android.webkit","android.preference","android.gesture","android.print"],
-        "android.app",
-        "android.widget",
-        "android.view",
-        "android.animation",
-        "android.provider",
-        ["android.content","android.graphics.drawable"],
-        "android.database",
-        "android.text",
-        "android.graphics",
-        "android.os",
-        "android.util"
-    ]
 
     def rank(p):
-        for i in range(len(ranking)):
-            if isinstance(ranking[i], list):
-                for j in ranking[i]:
-                    if p.startswith(j): return i
+        r = None
+        l = LAYERING_PACKAGE_RANKING
+        for n in p.split('.'):
+            if n in l:
+                l = l[n]
+                if '-rank' in l:
+                    r = l['-rank']
             else:
-                if p.startswith(ranking[i]): return i
+                break
+        return r
 
     cr = rank(clazz.pkg.name)
     if cr is None: return
 
     for f in clazz.fields:
         ir = rank(f.typ)
-        if ir and ir < cr:
+        if ir is not None and ir < cr:
             warn(clazz, f, "FW6", "Field type violates package layering")
 
-    for m in clazz.methods:
+    for m in itertools.chain(clazz.methods, clazz.ctors):
         ir = rank(m.typ)
-        if ir and ir < cr:
+        if ir is not None and ir < cr:
             warn(clazz, m, "FW6", "Method return type violates package layering")
         for arg in m.args:
             ir = rank(arg)
-            if ir and ir < cr:
+            if ir is not None and ir < cr:
                 warn(clazz, m, "FW6", "Method argument type violates package layering")
 
 
@@ -900,21 +1265,18 @@
             if len(m.args) == 0 and t in ["java.lang.IllegalArgumentException", "java.lang.NullPointerException"]:
                 warn(clazz, m, "S1", "Methods taking no arguments should throw IllegalStateException")
 
+GOOGLE_IGNORECASE = re.compile("google", re.IGNORECASE)
 
 def verify_google(clazz):
     """Verifies that APIs never reference Google."""
 
-    if re.search("google", clazz.raw, re.IGNORECASE):
+    if GOOGLE_IGNORECASE.search(clazz.raw) is not None:
         error(clazz, None, None, "Must never reference Google")
 
-    test = []
-    test.extend(clazz.ctors)
-    test.extend(clazz.fields)
-    test.extend(clazz.methods)
-
-    for t in test:
-        if re.search("google", t.raw, re.IGNORECASE):
-            error(clazz, t, None, "Must never reference Google")
+    for test in clazz.ctors, clazz.fields, clazz.methods:
+        for t in test:
+            if GOOGLE_IGNORECASE.search(t.raw) is not None:
+                error(clazz, t, None, "Must never reference Google")
 
 
 def verify_bitset(clazz):
@@ -1168,7 +1530,7 @@
     """Verifies that abstract inner classes are static."""
 
     if re.match(".+?\.[A-Z][^\.]+\.[A-Z]", clazz.fullname):
-        if " abstract " in clazz.raw and " static " not in clazz.raw:
+        if "abstract" in clazz.split and "static" not in clazz.split:
             warn(clazz, None, None, "Abstract inner classes should be static to improve testability")
 
 
@@ -1263,8 +1625,8 @@
 
 def verify_closable(clazz):
     """Verifies that classes are AutoClosable."""
-    if "implements java.lang.AutoCloseable" in clazz.raw: return
-    if "implements java.io.Closeable" in clazz.raw: return
+    if clazz.implements == "java.lang.AutoCloseable": return
+    if clazz.implements == "java.io.Closeable": return
 
     for m in clazz.methods:
         if len(m.args) > 0: continue
@@ -1309,7 +1671,7 @@
         binary.add(op)
 
     for m in clazz.methods:
-        if 'static' in m.split:
+        if 'static' in m.split or 'operator' in m.split:
             continue
 
         # https://kotlinlang.org/docs/reference/operator-overloading.html#unary-prefix-operators
@@ -1350,6 +1712,9 @@
 def verify_collections_over_arrays(clazz):
     """Warn that [] should be Collections."""
 
+    if "@interface" in clazz.split:
+        return
+
     safe = ["java.lang.String[]","byte[]","short[]","int[]","long[]","float[]","double[]","boolean[]","char[]"]
     for m in clazz.methods:
         if m.typ.endswith("[]") and m.typ not in safe:
@@ -1683,11 +2048,11 @@
             del cur[prev_clazz.fullname]
 
     for clazz in cur.values():
-        if " deprecated " in clazz.raw and not clazz.fullname in prev:
+        if "deprecated" in clazz.split and not clazz.fullname in prev:
             error(clazz, None, None, "Found API deprecation at birth")
 
         for i in clazz.ctors + clazz.methods + clazz.fields:
-            if " deprecated " in i.raw:
+            if "deprecated" in i.split:
                 error(clazz, i, None, "Found API deprecation at birth")
 
     print "%s Deprecated at birth %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True),
diff --git a/tools/apilint/apilint_test.py b/tools/apilint/apilint_test.py
index ece69a9..9c261d5 100644
--- a/tools/apilint/apilint_test.py
+++ b/tools/apilint/apilint_test.py
@@ -143,5 +143,214 @@
                                       out_classes_with_base=classes_with_base)
         self.assertEquals(map(lambda x: x.fullname, classes_with_base), ["android.app.WallpaperColors"])
 
+class ParseV2Stream(unittest.TestCase):
+    def test_field_kinds(self):
+        api = apilint._parse_stream("""
+// Signature format: 2.0
+package android {
+  public enum SomeEnum {
+    enum_constant public static final android.SomeEnum ENUM_CONST;
+    field public static final int FIELD_CONST;
+    property public final int someProperty;
+    ctor public SomeEnum();
+    method public Object? getObject();
+  }
+}
+        """.strip().split('\n'))
+
+        self.assertEquals(api['android.SomeEnum'].fields[0].split[0], 'enum_constant')
+        self.assertEquals(api['android.SomeEnum'].fields[1].split[0], 'field')
+        self.assertEquals(api['android.SomeEnum'].fields[2].split[0], 'property')
+        self.assertEquals(api['android.SomeEnum'].ctors[0].split[0], 'ctor')
+        self.assertEquals(api['android.SomeEnum'].methods[0].split[0], 'method')
+
+class V2TokenizerTests(unittest.TestCase):
+    def _test(self, raw, expected):
+        self.assertEquals(apilint.V2Tokenizer(raw).tokenize(), expected)
+
+    def test_simple(self):
+        self._test("  method public some.Type someName(some.Argument arg, int arg);",
+                   ['method', 'public', 'some.Type', 'someName', '(', 'some.Argument',
+                    'arg', ',', 'int', 'arg', ')', ';'])
+        self._test("class Some.Class extends SomeOther {",
+                   ['class', 'Some.Class', 'extends', 'SomeOther', '{'])
+
+    def test_varargs(self):
+        self._test("name(String...)",
+                   ['name', '(', 'String', '...', ')'])
+
+    def test_kotlin(self):
+        self._test("String? name(String!...)",
+                   ['String', '?', 'name', '(', 'String', '!',  '...', ')'])
+
+    def test_annotation(self):
+        self._test("method @Nullable public void name();",
+                   ['method', '@', 'Nullable', 'public', 'void', 'name', '(', ')', ';'])
+
+    def test_annotation_args(self):
+        self._test("@Some(val=1, other=2) class Class {",
+                   ['@', 'Some', '(', 'val', '=', '1', ',', 'other', '=', '2', ')',
+                    'class', 'Class', '{'])
+    def test_comment(self):
+        self._test("some //comment", ['some'])
+
+    def test_strings(self):
+        self._test(r'"" "foo" "\"" "\\"', ['""', '"foo"', r'"\""', r'"\\"'])
+
+    def test_at_interface(self):
+        self._test("public @interface Annotation {",
+                   ['public', '@interface', 'Annotation', '{'])
+
+    def test_array_type(self):
+        self._test("int[][]", ['int', '[]', '[]'])
+
+    def test_generics(self):
+        self._test("<>foobar<A extends Object>",
+                   ['<', '>', 'foobar', '<', 'A', 'extends', 'Object', '>'])
+
+class V2ParserTests(unittest.TestCase):
+    def _cls(self, raw):
+        pkg = apilint.Package(999, "package pkg {", None)
+        return apilint.Class(pkg, 1, raw, '', sig_format=2)
+
+    def _method(self, raw, cls=None):
+        if not cls:
+            cls = self._cls("class Class {")
+        return apilint.Method(cls, 1, raw, '', sig_format=2)
+
+    def _field(self, raw):
+        cls = self._cls("class Class {")
+        return apilint.Field(cls, 1, raw, '', sig_format=2)
+
+    def test_class(self):
+        cls = self._cls("@Deprecated @IntRange(from=1, to=2) public static abstract class Some.Name extends Super<Class> implements Interface<Class> {")
+        self.assertTrue('deprecated' in cls.split)
+        self.assertTrue('static' in cls.split)
+        self.assertTrue('abstract' in cls.split)
+        self.assertTrue('class' in cls.split)
+        self.assertEquals('Super', cls.extends)
+        self.assertEquals('Interface', cls.implements)
+        self.assertEquals('pkg.Some.Name', cls.fullname)
+
+    def test_enum(self):
+        cls = self._cls("public enum Some.Name {")
+        self._field("enum_constant public static final android.ValueType COLOR;")
+
+    def test_interface(self):
+        cls = self._cls("@Deprecated @IntRange(from=1, to=2) public interface Some.Name extends Interface<Class> {")
+        self.assertTrue('deprecated' in cls.split)
+        self.assertTrue('interface' in cls.split)
+        self.assertEquals('Interface', cls.extends)
+        self.assertEquals('Interface', cls.implements)
+        self.assertEquals('pkg.Some.Name', cls.fullname)
+
+    def test_at_interface(self):
+        cls = self._cls("@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface SuppressLint {")
+        self.assertTrue('@interface' in cls.split)
+        self.assertEquals('pkg.SuppressLint', cls.fullname)
+
+    def test_parse_method(self):
+        m = self._method("method @Deprecated public static native <T> Class<T>[][] name("
+                         + "Class<T[]>[][], Class<T[][][]>[][]...) throws Exception, T;")
+        self.assertTrue('static' in m.split)
+        self.assertTrue('public' in m.split)
+        self.assertTrue('method' in m.split)
+        self.assertTrue('native' in m.split)
+        self.assertTrue('deprecated' in m.split)
+        self.assertEquals('java.lang.Class[][]', m.typ)
+        self.assertEquals('name', m.name)
+        self.assertEquals(['java.lang.Class[][]', 'java.lang.Class[][]...'], m.args)
+        self.assertEquals(['java.lang.Exception', 'T'], m.throws)
+
+    def test_ctor(self):
+        m = self._method("ctor @Deprecated <T> ClassName();")
+        self.assertTrue('ctor' in m.split)
+        self.assertTrue('deprecated' in m.split)
+        self.assertEquals('ctor', m.typ)
+        self.assertEquals('ClassName', m.name)
+
+    def test_parse_annotation_method(self):
+        cls = self._cls("@interface Annotation {")
+        self._method('method abstract String category() default "";', cls=cls)
+        self._method('method abstract boolean deepExport() default false;', cls=cls)
+        self._method('method abstract ViewDebug.FlagToString[] flagMapping() default {};', cls=cls)
+        self._method('method abstract ViewDebug.FlagToString[] flagMapping() default (double)java.lang.Float.NEGATIVE_INFINITY;', cls=cls)
+
+    def test_parse_string_field(self):
+        f = self._field('field @Deprecated public final String SOME_NAME = "value";')
+        self.assertTrue('field' in f.split)
+        self.assertTrue('deprecated' in f.split)
+        self.assertTrue('final' in f.split)
+        self.assertEquals('java.lang.String', f.typ)
+        self.assertEquals('SOME_NAME', f.name)
+        self.assertEquals('value', f.value)
+
+    def test_parse_field(self):
+        f = self._field('field public Object SOME_NAME;')
+        self.assertTrue('field' in f.split)
+        self.assertEquals('java.lang.Object', f.typ)
+        self.assertEquals('SOME_NAME', f.name)
+        self.assertEquals(None, f.value)
+
+    def test_parse_int_field(self):
+        f = self._field('field public int NAME = 123;')
+        self.assertTrue('field' in f.split)
+        self.assertEquals('int', f.typ)
+        self.assertEquals('NAME', f.name)
+        self.assertEquals('123', f.value)
+
+    def test_parse_quotient_field(self):
+        f = self._field('field public int NAME = (0.0/0.0);')
+        self.assertTrue('field' in f.split)
+        self.assertEquals('int', f.typ)
+        self.assertEquals('NAME', f.name)
+        self.assertEquals('( 0.0 / 0.0 )', f.value)
+
+    def test_kotlin_types(self):
+        self._field('field public List<Integer[]?[]!>?[]![]? NAME;')
+        self._method("method <T?> Class<T!>?[]![][]? name(Type!, Type argname,"
+                         + "Class<T?>[][]?[]!...!) throws Exception, T;")
+        self._method("method <T> T name(T a = 1, T b = A(1), Lambda f = { false }, N? n = null, "
+                         + """double c = (1/0), float d = 1.0f, String s = "heyo", char c = 'a');""")
+
+    def test_kotlin_operator(self):
+        self._method('method public operator void unaryPlus(androidx.navigation.NavDestination);')
+        self._method('method public static operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, @IdRes int id);')
+        self._method('method public static operator <T> T get(androidx.navigation.NavigatorProvider, kotlin.reflect.KClass<T> clazz);')
+
+    def test_kotlin_property(self):
+        self._field('property public VM value;')
+        self._field('property public final String? action;')
+
+    def test_kotlin_varargs(self):
+        self._method('method public void error(int p = "42", Integer int2 = "null", int p1 = "42", vararg String args);')
+
+    def test_kotlin_default_values(self):
+        self._method('method public void foo(String! = null, String! = "Hello World", int = 42);')
+        self._method('method void method(String, String firstArg = "hello", int secondArg = "42", String thirdArg = "world");')
+        self._method('method void method(String, String firstArg = "hello", int secondArg = "42");')
+        self._method('method void method(String, String firstArg = "hello");')
+        self._method('method void edit(android.Type, boolean commit = false, Function1<? super Editor,kotlin.Unit> action);')
+        self._method('method <K, V> LruCache<K,V> lruCache(int maxSize, Function2<? super K,? super V,java.lang.Integer> sizeOf = { _, _ -> 1 }, Function1<? extends V> create = { (V)null }, Function4<kotlin.Unit> onEntryRemoved = { _, _, _, _ ->  });')
+        self._method('method android.Bitmap? drawToBitmap(android.View, android.Config config = android.graphics.Bitmap.Config.ARGB_8888);')
+        self._method('method void emptyLambda(Function0<kotlin.Unit> sizeOf = {});')
+        self._method('method void method1(int p = 42, Integer? int2 = null, int p1 = 42, String str = "hello world", java.lang.String... args);')
+        self._method('method void method2(int p, int int2 = (2 * int) * some.other.pkg.Constants.Misc.SIZE);')
+        self._method('method void method3(String str, int p, int int2 = double(int) + str.length);')
+        self._method('method void print(test.pkg.Foo foo = test.pkg.Foo());')
+
+    def test_type_use_annotation(self):
+        self._method('method public static int codePointAt(char @NonNull [], int);')
+        self._method('method @NonNull public java.util.Set<java.util.Map.@NonNull Entry<K,V>> entrySet();')
+
+        m = self._method('method @NonNull public java.lang.annotation.@NonNull Annotation @NonNull [] getAnnotations();')
+        self.assertEquals('java.lang.annotation.Annotation[]', m.typ)
+
+        m = self._method('method @NonNull public abstract java.lang.annotation.@NonNull Annotation @NonNull [] @NonNull [] getParameterAnnotations();')
+        self.assertEquals('java.lang.annotation.Annotation[][]', m.typ)
+
+        m = self._method('method @NonNull public @NonNull String @NonNull [] split(@NonNull String, int);')
+        self.assertEquals('java.lang.String[]', m.typ)
+
 if __name__ == "__main__":
-    unittest.main()
\ No newline at end of file
+    unittest.main()
diff --git a/tools/bit/command.h b/tools/bit/command.h
index fb44900..dd7103e 100644
--- a/tools/bit/command.h
+++ b/tools/bit/command.h
@@ -25,7 +25,7 @@
 
 struct Command
 {
-    Command(const string& prog);
+    explicit Command(const string& prog);
     ~Command();
 
     void AddArg(const string& arg);
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
index 01728fa1..2a8f695 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists.py
@@ -17,6 +17,7 @@
 Generate API lists for non-SDK API enforcement.
 """
 import argparse
+from collections import defaultdict
 import os
 import sys
 import re
@@ -27,16 +28,20 @@
 FLAG_BLACKLIST = "blacklist"
 FLAG_GREYLIST_MAX_O = "greylist-max-o"
 FLAG_GREYLIST_MAX_P = "greylist-max-p"
+FLAG_CORE_PLATFORM_API = "core-platform-api"
 
 # List of all known flags.
-FLAGS = [
+FLAGS_API_LIST = [
     FLAG_WHITELIST,
     FLAG_GREYLIST,
     FLAG_BLACKLIST,
     FLAG_GREYLIST_MAX_O,
     FLAG_GREYLIST_MAX_P,
 ]
-FLAGS_SET = set(FLAGS)
+ALL_FLAGS = FLAGS_API_LIST + [ FLAG_CORE_PLATFORM_API ]
+
+FLAGS_API_LIST_SET = set(FLAGS_API_LIST)
+ALL_FLAGS_SET = set(ALL_FLAGS)
 
 # Suffix used in command line args to express that only known and
 # otherwise unassigned entries should be assign the given flag.
@@ -62,7 +67,7 @@
 SERIALIZATION_REGEX = re.compile(r'.*->(' + '|'.join(SERIALIZATION_PATTERNS) + r')$')
 
 # Predicates to be used with filter_apis.
-IS_UNASSIGNED = lambda api, flags: not flags
+HAS_NO_API_LIST_ASSIGNED = lambda api, flags: not FLAGS_API_LIST_SET.intersection(flags)
 IS_SERIALIZATION = lambda api, flags: SERIALIZATION_REGEX.match(api)
 
 def get_args():
@@ -73,12 +78,10 @@
     """
     parser = argparse.ArgumentParser()
     parser.add_argument('--output', required=True)
-    parser.add_argument('--public', required=True, help='list of all public entries')
-    parser.add_argument('--private', required=True, help='list of all private entries')
     parser.add_argument('--csv', nargs='*', default=[], metavar='CSV_FILE',
         help='CSV files to be merged into output')
 
-    for flag in FLAGS:
+    for flag in ALL_FLAGS:
         ignore_conflicts_flag = flag + FLAG_IGNORE_CONFLICTS_SUFFIX
         parser.add_argument('--' + flag, dest=flag, nargs='*', default=[], metavar='TXT_FILE',
             help='lists of entries with flag "' + flag + '"')
@@ -118,26 +121,9 @@
         f.writelines(lines)
 
 class FlagsDict:
-    def __init__(self, public_api, private_api):
-        # Bootstrap the entries dictionary.
-
-        # Check that the two sets do not overlap.
-        public_api_set = set(public_api)
-        private_api_set = set(private_api)
-        assert public_api_set.isdisjoint(private_api_set), (
-            "Lists of public and private API overlap. " +
-            "This suggests an issue with the `hiddenapi` build tool.")
-
-        # Compute the whole key set
-        self._dict_keyset = public_api_set.union(private_api_set)
-
-        # Create a dict that creates entries for both public and private API,
-        # and assigns public API to the whitelist.
-        self._dict = {}
-        for api in public_api:
-            self._dict[api] = set([ FLAG_WHITELIST ])
-        for api in private_api:
-            self._dict[api] = set()
+    def __init__(self):
+        self._dict_keyset = set()
+        self._dict = defaultdict(set)
 
     def _check_entries_set(self, keys_subset, source):
         assert isinstance(keys_subset, set)
@@ -150,12 +136,12 @@
 
     def _check_flags_set(self, flags_subset, source):
         assert isinstance(flags_subset, set)
-        assert flags_subset.issubset(FLAGS_SET), (
+        assert flags_subset.issubset(ALL_FLAGS_SET), (
             "Error processing: {}\n"
             "The following flags were not recognized: \n"
             "{}\n"
             "Please visit go/hiddenapi for more information.").format(
-                source, "\n".join(flags_subset - FLAGS_SET))
+                source, "\n".join(flags_subset - ALL_FLAGS_SET))
 
     def filter_apis(self, filter_fn):
         """Returns APIs which match a given predicate.
@@ -173,7 +159,7 @@
 
     def get_valid_subset_of_unassigned_apis(self, api_subset):
         """Sanitizes a key set input to only include keys which exist in the dictionary
-        and have not been assigned any flags.
+        and have not been assigned any API list flags.
 
         Args:
             entries_subset (set/list): Key set to be sanitized.
@@ -182,7 +168,7 @@
             Sanitized key set.
         """
         assert isinstance(api_subset, set)
-        return api_subset.intersection(self.filter_apis(IS_UNASSIGNED))
+        return api_subset.intersection(self.filter_apis(HAS_NO_API_LIST_ASSIGNED))
 
     def generate_csv(self):
         """Constructs CSV entries from a dictionary.
@@ -203,14 +189,13 @@
             source (string): Origin of `csv_lines`. Will be printed in error messages.
 
         Throws:
-            AssertionError if parsed API signatures of flags are invalid.
+            AssertionError if parsed flags are invalid.
         """
         # Split CSV lines into arrays of values.
         csv_values = [ line.split(',') for line in csv_lines ]
 
-        # Check that all entries exist in the dict.
-        csv_keys = set([ csv[0] for csv in csv_values ])
-        self._check_entries_set(csv_keys, source)
+        # Update the full set of API signatures.
+        self._dict_keyset.update([ csv[0] for csv in csv_values ])
 
         # Check that all flags are known.
         csv_flags = set(reduce(lambda x, y: set(x).union(y), [ csv[1:] for csv in csv_values ], []))
@@ -224,7 +209,7 @@
         """Assigns a flag to given subset of entries.
 
         Args:
-            flag (string): One of FLAGS.
+            flag (string): One of ALL_FLAGS.
             apis (set): Subset of APIs to recieve the flag.
             source (string): Origin of `entries_subset`. Will be printed in error messages.
 
@@ -245,18 +230,23 @@
     # Parse arguments.
     args = vars(get_args())
 
-    flags = FlagsDict(read_lines(args["public"]), read_lines(args["private"]))
+    # Initialize API->flags dictionary.
+    flags = FlagsDict()
+
+    # Merge input CSV files into the dictionary.
+    # Do this first because CSV files produced by parsing API stubs will
+    # contain the full set of APIs. Subsequent additions from text files
+    # will be able to detect invalid entries, and/or filter all as-yet
+    # unassigned entries.
+    for filename in args["csv"]:
+        flags.parse_and_merge_csv(read_lines(filename), filename)
 
     # Combine inputs which do not require any particular order.
     # (1) Assign serialization API to whitelist.
     flags.assign_flag(FLAG_WHITELIST, flags.filter_apis(IS_SERIALIZATION))
 
-    # (2) Merge input CSV files into the dictionary.
-    for filename in args["csv"]:
-        flags.parse_and_merge_csv(read_lines(filename), filename)
-
-    # (3) Merge text files with a known flag into the dictionary.
-    for flag in FLAGS:
+    # (2) Merge text files with a known flag into the dictionary.
+    for flag in ALL_FLAGS:
         for filename in args[flag]:
             flags.assign_flag(flag, read_lines(filename), filename)
 
@@ -265,13 +255,13 @@
     # (a) the entry exists, and
     # (b) it has not been assigned any other flag.
     # Because of (b), this must run after all strict assignments have been performed.
-    for flag in FLAGS:
+    for flag in ALL_FLAGS:
         for filename in args[flag + FLAG_IGNORE_CONFLICTS_SUFFIX]:
             valid_entries = flags.get_valid_subset_of_unassigned_apis(read_lines(filename))
             flags.assign_flag(flag, valid_entries, filename)
 
     # Assign all remaining entries to the blacklist.
-    flags.assign_flag(FLAG_BLACKLIST, flags.filter_apis(IS_UNASSIGNED))
+    flags.assign_flag(FLAG_BLACKLIST, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
 
     # Write output.
     write_lines(args["output"], flags.generate_csv())
diff --git a/tools/processors/unsupportedappusage/Android.bp b/tools/processors/unsupportedappusage/Android.bp
index 1aca3ed..0e33fdd 100644
--- a/tools/processors/unsupportedappusage/Android.bp
+++ b/tools/processors/unsupportedappusage/Android.bp
@@ -1,6 +1,8 @@
 
-java_library_host {
+java_plugin {
     name: "unsupportedappusage-annotation-processor",
+    processor_class: "android.processor.unsupportedappusage.UnsupportedAppUsageProcessor",
+
     java_resources: [
         "META-INF/**/*",
     ],
diff --git a/tools/processors/view_inspector/Android.bp b/tools/processors/view_inspector/Android.bp
index ca6b3c4..9b5df56 100644
--- a/tools/processors/view_inspector/Android.bp
+++ b/tools/processors/view_inspector/Android.bp
@@ -5,7 +5,7 @@
     java_resource_dirs: ["src/resources"],
 
     static_libs: [
-    	"javapoet",
+        "javapoet",
     ],
 
     use_tools_jar: true,
@@ -18,9 +18,9 @@
     java_resource_dirs: ["test/resources"],
 
     static_libs: [
-        "guava",
         "junit",
-        "view-inspector-annotation-processor",
+        "guava",
+        "view-inspector-annotation-processor"
     ],
 
     test_suites: ["general-tests"],
diff --git a/tools/processors/view_inspector/TEST_MAPPING b/tools/processors/view_inspector/TEST_MAPPING
index a91b5b4..b4c9cab 100644
--- a/tools/processors/view_inspector/TEST_MAPPING
+++ b/tools/processors/view_inspector/TEST_MAPPING
@@ -2,6 +2,8 @@
   "presubmit": [
     {
       "name": "view-inspector-annotation-processor-test"
+    }, {
+      "name": "CtsViewInspectorAnnotationProcessorTestCases"
     }
   ]
 }
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
index f157949..fc4cd01 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
 import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.Elements;
 import javax.lang.model.util.Types;
@@ -78,40 +79,126 @@
     }
 
     /**
-     * Extract a string-valued property from an {@link AnnotationMirror}.
+     * Determine if an annotation with the supplied qualified name is present on the element.
      *
-     * @param propertyName The name of the requested property
-     * @param annotationMirror The mirror to search for the property
-     * @return The String value of the annotation or null
+     * @param element The element to check for the presence of an annotation
+     * @param annotationQualifiedName The name of the annotation to check for
+     * @return True if the annotation is present, false otherwise
      */
-    Optional<String> stringProperty(String propertyName, AnnotationMirror annotationMirror) {
-        final AnnotationValue value = valueByName(propertyName, annotationMirror);
-        if (value != null) {
-            return Optional.of((String) value.getValue());
-        } else {
-            return Optional.empty();
+    boolean hasAnnotation(Element element, String annotationQualifiedName) {
+        final TypeElement namedElement = mElementUtils.getTypeElement(annotationQualifiedName);
+
+        if (namedElement != null) {
+            final TypeMirror annotationType = namedElement.asType();
+
+            for (AnnotationMirror annotation : element.getAnnotationMirrors()) {
+                if (mTypeUtils.isSubtype(annotation.getAnnotationType(), annotationType)) {
+                    return true;
+                }
+            }
         }
+
+        return false;
     }
 
+    /**
+     * Get the typed value of an annotation property by name.
+     *
+     * The returned optional will be empty if the value was left at the default, or if the value
+     * of the property is null.
+     *
+     * @param propertyName The name of the property to search for
+     * @param valueClass The expected class of the property value
+     * @param element The element the annotation is on, used for exceptions
+     * @param annotationMirror An annotation mirror to search for the property
+     * @param <T> The type of the value
+     * @return An optional containing the typed value of the named property
+     */
+    <T> Optional<T> typedValueByName(
+            String propertyName,
+            Class<T> valueClass,
+            Element element,
+            AnnotationMirror annotationMirror) {
+        return valueByName(propertyName, annotationMirror).map(annotationValue -> {
+            final Object value = annotationValue.getValue();
+
+            if (value == null) {
+                throw new ProcessingException(
+                        String.format(
+                                "Unexpected null value for annotation property \"%s\".",
+                                propertyName),
+                        element,
+                        annotationMirror,
+                        annotationValue);
+            }
+
+            if (valueClass.isAssignableFrom(value.getClass())) {
+                return valueClass.cast(value);
+            } else {
+                throw new ProcessingException(
+                        String.format(
+                                "Expected annotation property \"%s\" to have type %s, but got %s.",
+                                propertyName,
+                                valueClass.getCanonicalName(),
+                                value.getClass().getCanonicalName()),
+                        element,
+                        annotationMirror,
+                        annotationValue);
+            }
+        });
+    }
+
+    /**
+     * Get the untyped value of an annotation property by name.
+     *
+     * The returned optional will be empty if the value was left at the default, or if the value
+     * of the property is null.
+     *
+     * @param propertyName The name of the property to search for
+     * @param element The element the annotation is on, used for exceptions
+     * @param annotationMirror An annotation mirror to search for the property
+     * @return An optional containing the untyped value of the named property
+     * @see AnnotationValue#getValue()
+     */
+    Optional<Object> untypedValueByName(
+            String propertyName,
+            Element element,
+            AnnotationMirror annotationMirror) {
+        return valueByName(propertyName, annotationMirror).map(annotationValue -> {
+            final Object value = annotationValue.getValue();
+
+            if (value == null) {
+                throw new ProcessingException(
+                        String.format(
+                                "Unexpected null value for annotation property \"%s\".",
+                                propertyName),
+                        element,
+                        annotationMirror,
+                        annotationValue);
+            }
+
+            return value;
+        });
+    }
 
     /**
      * Extract a {@link AnnotationValue} from a mirror by string property name.
      *
      * @param propertyName The name of the property requested property
-     * @param annotationMirror
-     * @return
+     * @param annotationMirror The mirror to search for the property
+     * @return The value of the property
      */
-    AnnotationValue valueByName(String propertyName, AnnotationMirror annotationMirror) {
+    Optional<AnnotationValue> valueByName(String propertyName, AnnotationMirror annotationMirror) {
         final Map<? extends ExecutableElement, ? extends AnnotationValue> valueMap =
                 annotationMirror.getElementValues();
 
         for (ExecutableElement method : valueMap.keySet()) {
             if (method.getSimpleName().contentEquals(propertyName)) {
-                return valueMap.get(method);
+                return Optional.ofNullable(valueMap.get(method));
             }
         }
 
-        return null;
+        // Property not explicitly defined, use default value.
+        return Optional.empty();
     }
-
 }
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
index 579745d..f1ebb87 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 
 /**
@@ -70,7 +71,7 @@
      * @return The property or an empty optional
      */
     public Optional<Property> getProperty(String name) {
-        return Optional.of(mPropertyMap.get(name));
+        return Optional.ofNullable(mPropertyMap.get(name));
     }
 
     /**
@@ -87,13 +88,15 @@
      */
     public static final class Property {
         private final String mName;
-        private String mGetter;
-        private Type mType;
+        private final String mGetter;
+        private final Type mType;
         private boolean mAttributeIdInferrableFromR = true;
         private int mAttributeId = 0;
 
-        public Property(String name) {
-            mName = name;
+        public Property(String name, String getter, Type type) {
+            mName = Objects.requireNonNull(name, "Name must not be null");
+            mGetter = Objects.requireNonNull(getter, "Getter must not be null");
+            mType = Objects.requireNonNull(type, "Type must not be null");
         }
 
         public int getAttributeId() {
@@ -126,18 +129,10 @@
             return mGetter;
         }
 
-        public void setGetter(String getter) {
-            mGetter = getter;
-        }
-
         public Type getType() {
             return mType;
         }
 
-        public void setType(Type type) {
-            mType = type;
-        }
-
         public enum Type {
             /** Primitive or boxed {@code boolean} */
             BOOLEAN,
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
index a186a82..46819b2 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
 import javax.lang.model.element.Element;
 
 /**
- * Process {InspectableNodeName} annotations
+ * Process {@code @InspectableNodeName} annotations.
  *
  * @see android.view.inspector.InspectableNodeName
  */
@@ -58,7 +58,8 @@
         try {
             final AnnotationMirror mirror =
                     mAnnotationUtils.exactlyOneMirror(mQualifiedName, element);
-            final Optional<String> nodeName = mAnnotationUtils.stringProperty("value", mirror);
+            final Optional<String> nodeName = mAnnotationUtils
+                    .typedValueByName("value", String.class, element, mirror);
 
             if (!model.getNodeName().isPresent() || model.getNodeName().equals(nodeName)) {
                 model.setNodeName(nodeName);
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
new file mode 100644
index 0000000..f666be7
--- /dev/null
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.processor.view.inspector;
+
+import android.processor.view.inspector.InspectableClassModel.Property;
+
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.NoType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Process {@code @InspectableProperty} annotations.
+ *
+ * @see android.view.inspector.InspectableProperty
+ */
+public final class InspectablePropertyProcessor implements ModelProcessor {
+    private final String mQualifiedName;
+    private final ProcessingEnvironment mProcessingEnv;
+    private final AnnotationUtils mAnnotationUtils;
+
+    /**
+     * Regex that matches methods names of the form {@code #getValue()}.
+     */
+    private static final Pattern GETTER_GET_PREFIX = Pattern.compile("\\Aget[A-Z]");
+
+    /**
+     * Regex that matches method name of the form {@code #isPredicate()}.
+     */
+    private static final Pattern GETTER_IS_PREFIX = Pattern.compile("\\Ais[A-Z]");
+
+    /**
+     * Set of android and androidx annotation qualified names for colors packed into {@code int}.
+     *
+     * @see android.annotation.ColorInt
+     */
+    private static final String[] COLOR_INT_ANNOTATION_NAMES = {
+            "android.annotation.ColorInt",
+            "androidx.annotation.ColorInt"};
+
+    /**
+     * Set of android and androidx annotation qualified names for colors packed into {@code long}.
+     * @see android.annotation.ColorLong
+     */
+    private static final String[] COLOR_LONG_ANNOTATION_NAMES = {
+            "android.annotation.ColorLong",
+            "androidx.annotation.ColorLong"};
+
+    /**
+     * @param annotationQualifiedName The qualified name of the annotation to process
+     * @param processingEnv The processing environment from the parent processor
+     */
+    public InspectablePropertyProcessor(
+            String annotationQualifiedName,
+            ProcessingEnvironment processingEnv) {
+        mQualifiedName = annotationQualifiedName;
+        mProcessingEnv = processingEnv;
+        mAnnotationUtils = new AnnotationUtils(processingEnv);
+    }
+
+    @Override
+    public void process(Element element, InspectableClassModel model) {
+        try {
+            final AnnotationMirror annotation =
+                    mAnnotationUtils.exactlyOneMirror(mQualifiedName, element);
+            final ExecutableElement getter = ensureGetter(element);
+            final Property property = buildProperty(getter, annotation);
+
+            model.getProperty(property.getName()).ifPresent(p -> {
+                throw new ProcessingException(
+                        String.format(
+                                "Property \"%s\" is already defined on #%s().",
+                                p.getName(),
+                                p.getGetter()),
+                        getter,
+                        annotation);
+            });
+
+            model.putProperty(property);
+        } catch (ProcessingException processingException) {
+            processingException.print(mProcessingEnv.getMessager());
+        }
+    }
+
+    /**
+     * Check that an element is shaped like a getter.
+     *
+     * @param element An element that hopefully represents a getter
+     * @throws ProcessingException if the element isn't a getter
+     * @return An {@link ExecutableElement} that represents a getter method.
+     */
+    private ExecutableElement ensureGetter(Element element) {
+        if (element.getKind() != ElementKind.METHOD) {
+            throw new ProcessingException(
+                    String.format("Expected a method, got a %s", element.getKind()),
+                    element);
+        }
+
+        final ExecutableElement method = (ExecutableElement) element;
+        final Set<Modifier> modifiers = method.getModifiers();
+
+        if (modifiers.contains(Modifier.PRIVATE)) {
+            throw new ProcessingException(
+                    "Property getter methods must not be private.",
+                    element);
+        }
+
+        if (modifiers.contains(Modifier.ABSTRACT)) {
+            throw new ProcessingException(
+                    "Property getter methods must not be abstract.",
+                    element);
+        }
+
+        if (modifiers.contains(Modifier.STATIC)) {
+            throw new ProcessingException(
+                    "Property getter methods must not be static.",
+                    element);
+        }
+
+        if (!method.getParameters().isEmpty()) {
+            throw new ProcessingException(
+                    String.format(
+                            "Expected a getter method to take no parameters, "
+                            + "but got %d parameters.",
+                            method.getParameters().size()),
+                    element);
+        }
+
+        if (method.isVarArgs()) {
+            throw new ProcessingException(
+                    "Expected a getter method to take no arguments, but got a var args method.",
+                    element);
+        }
+
+        if (method.getReturnType() instanceof NoType) {
+            throw new ProcessingException(
+                    "Expected a getter to have a return type, got void.",
+                    element);
+        }
+
+        return method;
+    }
+
+    /**
+     * Build a {@link Property} from a getter and an inspectable property annotation.
+     *
+     * @param getter An element representing the getter to build from
+     * @param annotation A mirror of an inspectable property-shaped annotation
+     * @throws ProcessingException If the supplied data is invalid and a property cannot be modeled
+     * @return A property for the getter and annotation
+     */
+    private Property buildProperty(ExecutableElement getter, AnnotationMirror annotation) {
+        final String name = mAnnotationUtils
+                .typedValueByName("name", String.class, getter, annotation)
+                .orElseGet(() -> inferPropertyNameFromGetter(getter));
+
+        final Property property = new Property(
+                name,
+                getter.getSimpleName().toString(),
+                determinePropertyType(getter, annotation));
+
+        mAnnotationUtils
+                .typedValueByName("hasAttributeId", Boolean.class, getter, annotation)
+                .ifPresent(property::setAttributeIdInferrableFromR);
+
+        mAnnotationUtils
+                .typedValueByName("attributeId", Integer.class, getter, annotation)
+                .ifPresent(property::setAttributeId);
+
+        return property;
+    }
+
+    /**
+     * Determine the property type from the annotation, return type, or context clues.
+     *
+     * @param getter An element representing the getter to build from
+     * @param annotation A mirror of an inspectable property-shaped annotation
+     * @return The resolved property type
+     * @throws ProcessingException If the property type cannot be resolved
+     * @see android.view.inspector.InspectableProperty#valueType()
+     */
+    private Property.Type determinePropertyType(
+            ExecutableElement getter,
+            AnnotationMirror annotation) {
+
+        final String valueType = mAnnotationUtils
+                .untypedValueByName("valueType", getter, annotation)
+                .map(Object::toString)
+                .orElse("INFERRED");
+
+        final Property.Type returnType = convertReturnTypeToPropertyType(getter);
+
+        switch (valueType) {
+            case "INFERRED":
+                if (hasColorAnnotation(getter)) {
+                    return Property.Type.COLOR;
+                } else {
+                    return returnType;
+                }
+            case "NONE":
+                return returnType;
+            case "COLOR":
+                switch (returnType) {
+                    case COLOR:
+                    case INT:
+                    case LONG:
+                        return Property.Type.COLOR;
+                    default:
+                        throw new ProcessingException(
+                                "Color must be a long, integer, or android.graphics.Color",
+                                getter,
+                                annotation);
+                }
+            case "GRAVITY":
+                if (returnType == Property.Type.INT) {
+                    return Property.Type.GRAVITY;
+                } else {
+                    throw new ProcessingException(
+                            String.format("Gravity must be an integer, got %s", returnType),
+                            getter,
+                            annotation);
+                }
+            case "INT_ENUM":
+            case "INT_FLAG":
+                throw new ProcessingException("Not implemented", getter, annotation);
+            default:
+                throw new ProcessingException(
+                        String.format("Unknown value type enumeration value: %s", valueType),
+                        getter,
+                        annotation);
+        }
+    }
+
+    /**
+     * Get a property type from the return type of a getter.
+     *
+     * @param getter The getter to extract the return type of
+     * @throws ProcessingException If the return type is not a primitive or an object
+     * @return The property type returned by the getter
+     */
+    private Property.Type convertReturnTypeToPropertyType(ExecutableElement getter) {
+        final TypeMirror returnType = getter.getReturnType();
+
+        switch (unboxType(returnType)) {
+            case BOOLEAN:
+                return Property.Type.BOOLEAN;
+            case BYTE:
+                return Property.Type.BYTE;
+            case CHAR:
+                return Property.Type.CHAR;
+            case DOUBLE:
+                return Property.Type.DOUBLE;
+            case FLOAT:
+                return Property.Type.FLOAT;
+            case INT:
+                return Property.Type.INT;
+            case LONG:
+                return Property.Type.LONG;
+            case SHORT:
+                return Property.Type.SHORT;
+            case DECLARED:
+                if (isColorType(returnType)) {
+                    return Property.Type.COLOR;
+                } else {
+                    return Property.Type.OBJECT;
+                }
+            default:
+                throw new ProcessingException(
+                        String.format("Unsupported return type %s.", returnType),
+                        getter);
+        }
+    }
+
+    /**
+     * Determine if a getter is annotated with color annotation matching its return type.
+     *
+     * Note that an {@code int} return value annotated with {@link android.annotation.ColorLong} is
+     * not considered to be annotated, nor is a {@code long} annotated with
+     * {@link android.annotation.ColorInt}.
+     *
+     * @param getter The getter to query
+     * @return True if the getter has a color annotation, false otherwise
+     *
+     */
+    private boolean hasColorAnnotation(ExecutableElement getter) {
+        switch (unboxType(getter.getReturnType())) {
+            case INT:
+                for (String name : COLOR_INT_ANNOTATION_NAMES) {
+                    if (mAnnotationUtils.hasAnnotation(getter, name)) {
+                        return true;
+                    }
+                }
+                return false;
+            case LONG:
+                for (String name : COLOR_LONG_ANNOTATION_NAMES) {
+                    if (mAnnotationUtils.hasAnnotation(getter, name)) {
+                        return true;
+                    }
+                }
+                return false;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Infer a property name from a getter method.
+     *
+     * If the method is prefixed with {@code get}, the prefix will be stripped, and the
+     * capitalization fixed. E.g.: {@code getSomeProperty} to {@code someProperty}.
+     *
+     * Additionally, if the method's return type is a boolean, an {@code is} prefix will also be
+     * stripped. E.g.: {@code isPropertyEnabled} to {@code propertyEnabled}.
+     *
+     * Failing that, this method will just return the full name of the getter.
+     *
+     * @param getter An element representing a getter
+     * @return A string property name
+     */
+    private String inferPropertyNameFromGetter(ExecutableElement getter) {
+        final String name = getter.getSimpleName().toString();
+
+        if (GETTER_GET_PREFIX.matcher(name).find()) {
+            return name.substring(3, 4).toLowerCase() + name.substring(4);
+        } else if (isBoolean(getter.getReturnType()) && GETTER_IS_PREFIX.matcher(name).find()) {
+            return name.substring(2, 3).toLowerCase() + name.substring(3);
+        } else {
+            return name;
+        }
+    }
+
+    /**
+     * Determine if a {@link TypeMirror} is a boxed or unboxed boolean.
+     *
+     * @param type The type mirror to check
+     * @return True if the type is a boolean
+     */
+    private boolean isBoolean(TypeMirror type) {
+        if (type.getKind() == TypeKind.DECLARED) {
+            return mProcessingEnv.getTypeUtils().unboxedType(type).getKind() == TypeKind.BOOLEAN;
+        } else {
+            return type.getKind() == TypeKind.BOOLEAN;
+        }
+    }
+
+    /**
+     * Unbox a type mirror if it represents a boxed type, otherwise pass it through.
+     *
+     * @param typeMirror The type mirror to unbox
+     * @return The same type mirror, or an unboxed primitive version
+     */
+    private TypeKind unboxType(TypeMirror typeMirror) {
+        final TypeKind typeKind = typeMirror.getKind();
+
+        if (typeKind.isPrimitive()) {
+            return typeKind;
+        } else if (typeKind == TypeKind.DECLARED) {
+            try {
+                return mProcessingEnv.getTypeUtils().unboxedType(typeMirror).getKind();
+            } catch (IllegalArgumentException e) {
+                return typeKind;
+            }
+        } else {
+            return typeKind;
+        }
+    }
+
+    /**
+     * Determine if a type mirror represents a subtype of {@link android.graphics.Color}.
+     *
+     * @param typeMirror The type mirror to test
+     * @return True if it represents a subclass of color, false otherwise
+     */
+    private boolean isColorType(TypeMirror typeMirror) {
+        final TypeElement colorType = mProcessingEnv
+                .getElementUtils()
+                .getTypeElement("android.graphics.Color");
+
+        if (colorType == null) {
+            return false;
+        } else {
+            return mProcessingEnv.getTypeUtils().isSubtype(typeMirror, colorType.asType());
+        }
+    }
+}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
index 3b85dbb..dd4d8f5 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -51,12 +51,6 @@
     private static final ClassName R_CLASS_NAME = ClassName.get("android", "R");
 
     /**
-     * The class name of {@link android.content.res.ResourceId}.
-     */
-    private static final ClassName RESOURCE_ID_CLASS_NAME = ClassName.get(
-            "android.content.res", "ResourceId");
-
-    /**
      * The class name of {@link android.view.inspector.InspectionCompanion}.
      */
     private static final ClassName INSPECTION_COMPANION = ClassName.get(
@@ -91,11 +85,11 @@
     private static final String GENERATED_CLASS_SUFFIX = "$$InspectionCompanion";
 
     /**
-     * The null resource ID.
+     * The null resource ID, copied to avoid a host dependency on platform code.
      *
-     * @see android.content.res.ResourceId#ID_NULL
+     * @see android.content.res.Resources#ID_NULL
      */
-    private static final int NO_ID = 0;
+    private static final int ID_NULL = 0;
 
     /**
      * @param filer A filer to write the generated source to
@@ -289,8 +283,8 @@
         if (property.isAttributeIdInferrableFromR()) {
             builder.add("$T.attr.$L", R_CLASS_NAME, property.getName());
         } else {
-            if (property.getAttributeId() == NO_ID) {
-                builder.add("$T.ID_NULL", RESOURCE_ID_CLASS_NAME);
+            if (property.getAttributeId() == ID_NULL) {
+                builder.add("$L", ID_NULL);
             } else {
                 builder.add("$L", String.format("0x%08x", property.getAttributeId()));
             }
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
index 3ffcff8..6f52260 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
index e531b67..455f5b0 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -46,11 +46,14 @@
  * @see android.view.inspector.InspectableProperty
  */
 @SupportedAnnotationTypes({
-        PlatformInspectableProcessor.NODE_NAME_QUALIFIED_NAME
+        PlatformInspectableProcessor.NODE_NAME_QUALIFIED_NAME,
+        PlatformInspectableProcessor.PROPERTY_QUALIFIED_NAME
 })
 public final class PlatformInspectableProcessor extends AbstractProcessor {
     static final String NODE_NAME_QUALIFIED_NAME =
             "android.view.inspector.InspectableNodeName";
+    static final String PROPERTY_QUALIFIED_NAME =
+            "android.view.inspector.InspectableProperty";
 
     @Override
     public SourceVersion getSupportedSourceVersion() {
@@ -68,6 +71,11 @@
                         new InspectableNodeNameProcessor(NODE_NAME_QUALIFIED_NAME, processingEnv),
                         modelMap);
 
+            } else if (annotation.getQualifiedName().contentEquals(PROPERTY_QUALIFIED_NAME)) {
+                runModelProcessor(
+                        roundEnv.getElementsAnnotatedWith(annotation),
+                        new InspectablePropertyProcessor(PROPERTY_QUALIFIED_NAME, processingEnv),
+                        modelMap);
 
             } else {
                 fail("Unexpected annotation type", annotation);
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
index 6360e0a..b4c6466 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/tools/processors/view_inspector/src/resources/META-INF/services/javax.annotation.processing.Processor b/tools/processors/view_inspector/src/resources/META-INF/services/javax.annotation.processing.Processor
index fa4f71f..79185cc 100644
--- a/tools/processors/view_inspector/src/resources/META-INF/services/javax.annotation.processing.Processor
+++ b/tools/processors/view_inspector/src/resources/META-INF/services/javax.annotation.processing.Processor
@@ -1 +1 @@
-android.processor.inspector.view.PlatformInspectableProcessor
+android.processor.view.inspector.PlatformInspectableProcessor
diff --git a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
index f639719..b0775dc 100644
--- a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
+++ b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNotNull;
-import static junit.framework.TestCase.fail;
+import static junit.framework.Assert.fail;
 
 import com.google.common.base.Charsets;
 import com.google.common.io.Resources;
@@ -65,27 +65,28 @@
 
     @Test
     public void testSimpleProperties() {
-        addProperty("boolean", Property.Type.BOOLEAN, "getBoolean");
-        addProperty("byte", Property.Type.BYTE, "getByte");
-        addProperty("char", Property.Type.CHAR, "getChar");
-        addProperty("double", Property.Type.DOUBLE, "getDouble");
-        addProperty("float", Property.Type.FLOAT, "getFloat");
-        addProperty("int", Property.Type.INT, "getInt");
-        addProperty("long", Property.Type.LONG, "getLong");
-        addProperty("short", Property.Type.SHORT, "getShort");
+        addProperty("boolean", "getBoolean", Property.Type.BOOLEAN);
+        addProperty("byte", "getByte", Property.Type.BYTE);
+        addProperty("char", "getChar", Property.Type.CHAR);
+        addProperty("double", "getDouble", Property.Type.DOUBLE);
+        addProperty("float", "getFloat", Property.Type.FLOAT);
+        addProperty("int", "getInt", Property.Type.INT);
+        addProperty("long", "getLong", Property.Type.LONG);
+        addProperty("short", "getShort", Property.Type.SHORT);
 
-        addProperty("object", Property.Type.OBJECT, "getObject");
-        addProperty("color", Property.Type.COLOR, "getColor");
-        addProperty("gravity", Property.Type.GRAVITY, "getGravity");
+        addProperty("object", "getObject", Property.Type.OBJECT);
+        addProperty("color", "getColor", Property.Type.COLOR);
+        addProperty("gravity", "getGravity", Property.Type.GRAVITY);
 
         assertGeneratedFileEquals("SimpleProperties");
     }
 
     @Test
     public void testNoAttributeId() {
-        final Property property = new Property("noAttributeProperty");
-        property.setType(Property.Type.INT);
-        property.setGetter("getNoAttributeProperty");
+        final Property property = new Property(
+                "noAttributeProperty",
+                "getNoAttributeProperty",
+                Property.Type.INT);
         property.setAttributeIdInferrableFromR(false);
         mModel.putProperty(property);
 
@@ -94,19 +95,18 @@
 
     @Test
     public void testSuppliedAttributeId() {
-        final Property property = new Property("suppliedAttributeProperty");
-        property.setType(Property.Type.INT);
-        property.setGetter("getSuppliedAttributeProperty");
+        final Property property = new Property(
+                "suppliedAttributeProperty",
+                "getSuppliedAttributeProperty",
+                Property.Type.INT);
         property.setAttributeId(0xdecafbad);
         mModel.putProperty(property);
 
         assertGeneratedFileEquals("SuppliedAttributeId");
     }
 
-    private Property addProperty(String name, Property.Type type, String getter) {
-        final Property property = new Property(name);
-        property.setType(type);
-        property.setGetter(getter);
+    private Property addProperty(String name, String getter, Property.Type type) {
+        final Property property = new Property(name, getter, type);
         mModel.putProperty(property);
         return property;
     }
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
index 277e840..23d0f78 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
@@ -1,6 +1,5 @@
 package com.android.inspectable;
 
-import android.content.res.ResourceId;
 import android.view.inspector.InspectionCompanion;
 import android.view.inspector.PropertyMapper;
 import android.view.inspector.PropertyReader;
@@ -25,7 +24,7 @@
 
     @Override
     public void mapProperties(PropertyMapper propertyMapper) {
-        mNoAttributePropertyId = propertyMapper.mapInt("noAttributeProperty", ResourceId.ID_NULL);
+        mNoAttributePropertyId = propertyMapper.mapInt("noAttributeProperty", 0);
         mPropertiesMapped = true;
     }
 
diff --git a/tools/signedconfig/prod_public.pem b/tools/signedconfig/prod_public.pem
new file mode 100644
index 0000000..8c10215
--- /dev/null
+++ b/tools/signedconfig/prod_public.pem
@@ -0,0 +1,5 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+lky6wKyGL6lE1VrD0YTMHwb0Xwc
++tzC8MvnrzVxodvTpVY/jV7V+Zktcx+pry43XPABFRXtbhTo+qykhyBA1g==
+-----END PUBLIC KEY-----
+
diff --git a/tools/signedconfig/verify_b64.sh b/tools/signedconfig/verify_b64.sh
index 8e1f58c..a4ac6a8 100755
--- a/tools/signedconfig/verify_b64.sh
+++ b/tools/signedconfig/verify_b64.sh
@@ -7,4 +7,30 @@
 # The arg values can be taken from the debug log for SignedConfigService when verbose logging is
 # enabled.
 
-openssl dgst -sha256 -verify $(dirname $0)/debug_public.pem -signature <(echo $2 | base64 -d) <(echo $1 | base64 -d)
+function verify() {
+  D=${1}
+  S=${2}
+  K=${3}
+  echo Trying ${K}
+  openssl dgst -sha256 -verify $(dirname $0)/${K} -signature <(echo ${S} | base64 -d) <(echo ${D} | base64 -d)
+}
+
+
+PROD_KEY_NAME=prod_public.pem
+DEBUG_KEY_NAME=debug_public.pem
+SIGNATURE="$2"
+DATA="$1"
+
+echo DATA: ${DATA}
+echo SIGNATURE: ${SIGNATURE}
+
+if verify "${DATA}" "${SIGNATURE}" "${PROD_KEY_NAME}"; then
+  echo Verified with ${PROD_KEY_NAME}
+  exit 0
+fi
+
+if verify "${DATA}" "${SIGNATURE}" "${DEBUG_KEY_NAME}"; then
+  echo Verified with ${DEBUG_KEY_NAME}
+  exit 0
+fi
+exit 1
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 11b408f..4491a85 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -67,7 +67,7 @@
         case JAVA_TYPE_STRING:
             return "char const*";
         case JAVA_TYPE_BYTE_ARRAY:
-            return "char const*";
+            return "const BytesField&";
         default:
             return "UNKNOWN";
     }
@@ -270,10 +270,6 @@
                                  chainField.name.c_str(), chainField.name.c_str());
                     }
                 }
-            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-                fprintf(out, ", %s arg%d, size_t arg%d_length",
-                        cpp_type_name(*arg), argIndex, argIndex);
-
             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                 fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
                              "const std::map<int, int64_t>& arg%d_2, "
@@ -355,7 +351,8 @@
                     fprintf(out, "    event.end();\n\n");
             } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
                 fprintf(out,
-                        "    event.AppendCharArray(arg%d, arg%d_length);\n",
+                        "    event.AppendCharArray(arg%d.arg, "
+                        "arg%d.arg_length);\n",
                         argIndex, argIndex);
             } else {
                 if (*arg == JAVA_TYPE_STRING) {
@@ -397,10 +394,6 @@
                                 chainField.name.c_str(), chainField.name.c_str());
                    }
                }
-           } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-               fprintf(out, ", %s arg%d, size_t arg%d_length",
-                       cpp_type_name(*arg), argIndex, argIndex);
-
            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                fprintf(out,
                        ", const std::map<int, int32_t>& arg%d_1, "
@@ -434,8 +427,6 @@
                                 chainField.name.c_str(), chainField.name.c_str());
                    }
                }
-           } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-               fprintf(out, ", arg%d, arg%d_length", argIndex, argIndex);
            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex,
                        argIndex, argIndex, argIndex);
@@ -494,7 +485,14 @@
                 fprintf(out, "        arg%d = \"\";\n", argIndex);
                 fprintf(out, "    }\n");
             }
-            fprintf(out, "    event << arg%d;\n", argIndex);
+            if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+                fprintf(out,
+                        "    event.AppendCharArray(arg%d.arg, "
+                        "arg%d.arg_length);",
+                        argIndex, argIndex);
+            } else {
+                fprintf(out, "    event << arg%d;\n", argIndex);
+            }
             if (argIndex == 2) {
                 fprintf(out, "    event.end();\n\n");
                 fprintf(out, "    event.end();\n\n");
@@ -577,7 +575,9 @@
 static void write_cpp_usage(
     FILE* out, const string& method_name, const string& atom_code_name,
     const AtomDecl& atom, const AtomDecl &attributionDecl) {
-    fprintf(out, "     * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str());
+    fprintf(out, "     * Usage: %s(StatsLog.%s", method_name.c_str(),
+            atom_code_name.c_str());
+
     for (vector<AtomField>::const_iterator field = atom.fields.begin();
             field != atom.fields.end(); field++) {
         if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -601,11 +601,6 @@
                          field->name.c_str(),
                          field->name.c_str(),
                          field->name.c_str());
-        } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) {
-            fprintf(out, ", %s %s, size_t %s_length",
-                    cpp_type_name(field->javaType), field->name.c_str(),
-                    field->name.c_str());
-
         } else {
             fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
         }
@@ -639,9 +634,6 @@
                              "const std::map<int, char const*>& arg%d_3, "
                              "const std::map<int, float>& arg%d_4",
                              argIndex, argIndex, argIndex, argIndex);
-            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-                fprintf(out, ", %s arg%d, size_t arg%d_length",
-                        cpp_type_name(*arg), argIndex, argIndex);
             } else {
                 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
             }
@@ -708,6 +700,15 @@
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
+    fprintf(out, "struct BytesField {\n");
+    fprintf(out,
+            "  BytesField(char const* array, size_t len) : arg(array), "
+            "arg_length(len) {}\n");
+    fprintf(out, "  char const* arg;\n");
+    fprintf(out, "  size_t arg_length;\n");
+    fprintf(out, "};\n");
+    fprintf(out, "\n");
+
     fprintf(out, "struct StateAtomFieldOptions {\n");
     fprintf(out, "  std::vector<int> primaryFields;\n");
     fprintf(out, "  int exclusiveField;\n");
@@ -775,6 +776,7 @@
     const AtomDecl &attributionDecl) {
     for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
         signature != signatures.end(); signature++) {
+        fprintf(out, "    /** @hide */\n");
         fprintf(out, "    public static native int %s(int code", method_name.c_str());
         int argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
@@ -820,6 +822,7 @@
         }
 
         // Method header (signature)
+        fprintf(out, "    /** @hide */\n");
         fprintf(out, "    public static void write(int code");
         int argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
@@ -900,6 +903,7 @@
         if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
             write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second);
         }
+        fprintf(out, "     * @hide\n");
         fprintf(out, "     */\n");
         fprintf(out, "    public static final int %s = %d;\n", constant.c_str(), atom->code);
     }
@@ -916,6 +920,7 @@
                     field->name.c_str());
                 for (map<int, string>::const_iterator value = field->enumValues.begin();
                     value != field->enumValues.end(); value++) {
+                    fprintf(out, "    /** @hide */\n");
                     fprintf(out, "    public static final int %s__%s__%s = %d;\n",
                         make_constant_name(atom->message).c_str(),
                         make_constant_name(field->name).c_str(),
@@ -1179,6 +1184,11 @@
                 fprintf(out, "        str%d = NULL;\n", argIndex);
                 fprintf(out, "    }\n");
 
+                fprintf(out,
+                        "    android::util::BytesField bytesField%d(str%d, "
+                        "str%d_length);",
+                        argIndex, argIndex, argIndex);
+
             } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 hadStringOrChain = true;
                 for (auto chainField : attributionDecl.fields) {
@@ -1236,7 +1246,8 @@
 
         // stats_write call
         argIndex = 1;
-        fprintf(out, "\n    int ret =  android::util::%s(code", cpp_method_name.c_str());
+        fprintf(out, "\n    int ret =  android::util::%s(code",
+                cpp_method_name.c_str());
         for (vector<java_type_t>::const_iterator arg = signature->begin();
                 arg != signature->end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -1251,16 +1262,12 @@
                 }
             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                 fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map");
+            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+                fprintf(out, ", bytesField%d", argIndex);
             } else {
-                const char* argName = (*arg == JAVA_TYPE_STRING ||
-                                       *arg == JAVA_TYPE_BYTE_ARRAY)
-                                              ? "str"
-                                              : "arg";
+                const char* argName =
+                        (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
                 fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
-
-                if (*arg == JAVA_TYPE_BYTE_ARRAY) {
-                    fprintf(out, ", %s%d_length", argName, argIndex);
-                }
             }
             argIndex++;
         }
diff --git a/tools/streaming_proto/Errors.h b/tools/streaming_proto/Errors.h
index f14bbfd..bddd981 100644
--- a/tools/streaming_proto/Errors.h
+++ b/tools/streaming_proto/Errors.h
@@ -11,7 +11,7 @@
 struct Error
 {
     Error();
-    explicit Error(const Error& that);
+    Error(const Error& that);
     Error(const string& filename, int lineno, const char* message);
 
     string filename;
diff --git a/wifi/java/android/net/wifi/DppStatusCallback.java b/wifi/java/android/net/wifi/DppStatusCallback.java
deleted file mode 100644
index fa2ab30..0000000
--- a/wifi/java/android/net/wifi/DppStatusCallback.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.annotation.IntDef;
-import android.annotation.SystemApi;
-import android.os.Handler;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * DPP Status Callback. Use this callback to get status updates (success, failure, progress)
- * from the DPP operation started with {@link WifiManager#startDppAsConfiguratorInitiator(String,
- * int, int, Handler, DppStatusCallback)} or {@link WifiManager#startDppAsEnrolleeInitiator(String,
- * Handler, DppStatusCallback)}
- * @hide
- */
-@SystemApi
-public abstract class DppStatusCallback {
-    /**
-     * DPP Success event: Configuration sent (Configurator mode).
-     */
-    public static final int DPP_EVENT_SUCCESS_CONFIGURATION_SENT = 0;
-
-    /** @hide */
-    @IntDef(prefix = { "DPP_EVENT_SUCCESS_" }, value = {
-            DPP_EVENT_SUCCESS_CONFIGURATION_SENT,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface DppSuccessStatusCode {}
-
-    /**
-     * DPP Progress event: Initial authentication with peer succeeded.
-     */
-    public static final int DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0;
-
-    /**
-     * DPP Progress event: Peer requires more time to process bootstrapping.
-     */
-    public static final int DPP_EVENT_PROGRESS_RESPONSE_PENDING = 1;
-
-    /** @hide */
-    @IntDef(prefix = { "DPP_EVENT_PROGRESS_" }, value = {
-            DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS,
-            DPP_EVENT_PROGRESS_RESPONSE_PENDING,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface DppProgressStatusCode {}
-
-    /**
-     * DPP Failure event: Scanned QR code is either not a DPP URI, or the DPP URI has errors.
-     */
-    public static final int DPP_EVENT_FAILURE_INVALID_URI = -1;
-
-    /**
-     * DPP Failure event: Bootstrapping/Authentication initialization process failure.
-     */
-    public static final int DPP_EVENT_FAILURE_AUTHENTICATION = -2;
-
-    /**
-     * DPP Failure event: Both devices are implementing the same role and are incompatible.
-     */
-    public static final int DPP_EVENT_FAILURE_NOT_COMPATIBLE = -3;
-
-    /**
-     * DPP Failure event: Configuration process has failed due to malformed message.
-     */
-    public static final int DPP_EVENT_FAILURE_CONFIGURATION = -4;
-
-    /**
-     * DPP Failure event: DPP request while in another DPP exchange.
-     */
-    public static final int DPP_EVENT_FAILURE_BUSY = -5;
-
-    /**
-     * DPP Failure event: No response from the peer.
-     */
-    public static final int DPP_EVENT_FAILURE_TIMEOUT = -6;
-
-    /**
-     * DPP Failure event: General protocol failure.
-     */
-    public static final int DPP_EVENT_FAILURE = -7;
-
-    /**
-     * DPP Failure event: Feature or option is not supported.
-     */
-    public static final int DPP_EVENT_FAILURE_NOT_SUPPORTED = -8;
-
-    /**
-     * DPP Failure event: Invalid network provided to DPP configurator.
-     * Network must either be WPA3-Personal (SAE) or WPA2-Personal (PSK).
-     */
-    public static final int DPP_EVENT_FAILURE_INVALID_NETWORK = -9;
-
-
-    /** @hide */
-    @IntDef(prefix = {"DPP_EVENT_FAILURE_"}, value = {
-            DPP_EVENT_FAILURE_INVALID_URI,
-            DPP_EVENT_FAILURE_AUTHENTICATION,
-            DPP_EVENT_FAILURE_NOT_COMPATIBLE,
-            DPP_EVENT_FAILURE_CONFIGURATION,
-            DPP_EVENT_FAILURE_BUSY,
-            DPP_EVENT_FAILURE_TIMEOUT,
-            DPP_EVENT_FAILURE,
-            DPP_EVENT_FAILURE_NOT_SUPPORTED,
-            DPP_EVENT_FAILURE_INVALID_NETWORK,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface DppFailureStatusCode {
-    }
-
-    /**
-     * Called when local DPP Enrollee successfully receives a new Wi-Fi configuration from the
-     * peer DPP configurator. This callback marks the successful end of the DPP current DPP
-     * session, and no further callbacks will be called. This callback is the successful outcome
-     * of a DPP flow starting with {@link WifiManager#startDppAsEnrolleeInitiator(String, Handler,
-     * DppStatusCallback)}.
-     *
-     * @param newNetworkId New Wi-Fi configuration with a network ID received from the configurator
-     */
-    public abstract void onEnrolleeSuccess(int newNetworkId);
-
-    /**
-     * Called when a DPP success event takes place, except for when configuration is received from
-     * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
-     * This callback marks the successful end of the current DPP session, and no further
-     * callbacks will be called. This callback is the successful outcome of a DPP flow starting with
-     * {@link WifiManager#startDppAsConfiguratorInitiator(String, int, int, Handler,
-     * DppStatusCallback)}.
-     *
-     * @param code DPP success status code.
-     */
-    public abstract void onConfiguratorSuccess(@DppSuccessStatusCode int code);
-
-    /**
-     * Called when a DPP Failure event takes place. This callback marks the unsuccessful end of the
-     * current DPP session, and no further callbacks will be called.
-     *
-     * @param code DPP failure status code.
-     */
-    public abstract void onFailure(@DppFailureStatusCode int code);
-
-    /**
-     * Called when DPP events that indicate progress take place. Can be used by UI elements
-     * to show progress.
-     *
-     * @param code DPP progress status code.
-     */
-    public abstract void onProgress(@DppProgressStatusCode int code);
-}
diff --git a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
new file mode 100644
index 0000000..b8c82fd
--- /dev/null
+++ b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
@@ -0,0 +1,179 @@
+/*
+ * 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.wifi;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.Handler;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Easy Connect (DPP) Status Callback. Use this callback to get status updates (success, failure,
+ * progress) from the Easy Connect operation started with
+ * {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String,
+ * int, int, Handler, EasyConnectStatusCallback)} or
+ * {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
+ * Handler, EasyConnectStatusCallback)}
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class EasyConnectStatusCallback {
+    /**
+     * Easy Connect Success event: Configuration sent (Configurator mode).
+     */
+    public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0;
+
+    /** @hide */
+    @IntDef(prefix = {"EASY_CONNECT_EVENT_SUCCESS_"}, value = {
+            EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EasyConnectSuccessStatusCode {
+    }
+
+    /**
+     * Easy Connect Progress event: Initial authentication with peer succeeded.
+     */
+    public static final int EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0;
+
+    /**
+     * Easy Connect Progress event: Peer requires more time to process bootstrapping.
+     */
+    public static final int EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING = 1;
+
+    /** @hide */
+    @IntDef(prefix = {"EASY_CONNECT_EVENT_PROGRESS_"}, value = {
+            EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS,
+            EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EasyConnectProgressStatusCode {
+    }
+
+    /**
+     * Easy Connect Failure event: Scanned QR code is either not a Easy Connect URI, or the Easy
+     * Connect URI has errors.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_URI = -1;
+
+    /**
+     * Easy Connect Failure event: Bootstrapping/Authentication initialization process failure.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION = -2;
+
+    /**
+     * Easy Connect Failure event: Both devices are implementing the same role and are incompatible.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE = -3;
+
+    /**
+     * Easy Connect Failure event: Configuration process has failed due to malformed message.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_CONFIGURATION = -4;
+
+    /**
+     * Easy Connect Failure event: Easy Connect request while in another Easy Connect exchange.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_BUSY = -5;
+
+    /**
+     * Easy Connect Failure event: No response from the peer.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_TIMEOUT = -6;
+
+    /**
+     * Easy Connect Failure event: General protocol failure.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_GENERIC = -7;
+
+    /**
+     * Easy Connect Failure event: Feature or option is not supported.
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED = -8;
+
+    /**
+     * Easy Connect Failure event: Invalid network provided to Easy Connect configurator.
+     * Network must either be WPA3-Personal (SAE) or WPA2-Personal (PSK).
+     */
+    public static final int EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = -9;
+
+
+    /** @hide */
+    @IntDef(prefix = {"EASY_CONNECT_EVENT_FAILURE_"}, value = {
+            EASY_CONNECT_EVENT_FAILURE_INVALID_URI,
+            EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION,
+            EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE,
+            EASY_CONNECT_EVENT_FAILURE_CONFIGURATION,
+            EASY_CONNECT_EVENT_FAILURE_BUSY,
+            EASY_CONNECT_EVENT_FAILURE_TIMEOUT,
+            EASY_CONNECT_EVENT_FAILURE_GENERIC,
+            EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED,
+            EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EasyConnectFailureStatusCode {
+    }
+
+    /**
+     * Called when local Easy Connect Enrollee successfully receives a new Wi-Fi configuration from
+     * the
+     * peer Easy Connect configurator. This callback marks the successful end of the Easy Connect
+     * current Easy Connect
+     * session, and no further callbacks will be called. This callback is the successful outcome
+     * of a Easy Connect flow starting with
+     * {@link WifiManager#startEasyConnectAsEnrolleeInitiator(String,
+     * Handler,
+     * EasyConnectStatusCallback)}.
+     *
+     * @param newNetworkId New Wi-Fi configuration with a network ID received from the configurator
+     */
+    public abstract void onEnrolleeSuccess(int newNetworkId);
+
+    /**
+     * Called when a Easy Connect success event takes place, except for when configuration is
+     * received from
+     * an external Configurator. The callback onSuccessConfigReceived will be used in this case.
+     * This callback marks the successful end of the current Easy Connect session, and no further
+     * callbacks will be called. This callback is the successful outcome of a Easy Connect flow
+     * starting with
+     * {@link WifiManager#startEasyConnectAsConfiguratorInitiator(String, int, int, Handler,
+     * EasyConnectStatusCallback)}.
+     *
+     * @param code Easy Connect success status code.
+     */
+    public abstract void onConfiguratorSuccess(@EasyConnectSuccessStatusCode int code);
+
+    /**
+     * Called when a Easy Connect Failure event takes place. This callback marks the unsuccessful
+     * end of the
+     * current Easy Connect session, and no further callbacks will be called.
+     *
+     * @param code Easy Connect failure status code.
+     */
+    public abstract void onFailure(@EasyConnectFailureStatusCode int code);
+
+    /**
+     * Called when Easy Connect events that indicate progress take place. Can be used by UI elements
+     * to show progress.
+     *
+     * @param code Easy Connect progress status code.
+     */
+    public abstract void onProgress(@EasyConnectProgressStatusCode int code);
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 1700006..a0ce9dd 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -16,7 +16,6 @@
 
 package android.net.wifi;
 
-
 import android.content.pm.ParceledListSlice;
 
 import android.net.wifi.hotspot2.OsuProvider;
@@ -29,6 +28,7 @@
 import android.net.wifi.INetworkRequestMatchCallback;
 import android.net.wifi.ISoftApCallback;
 import android.net.wifi.ITrafficStateCallback;
+import android.net.wifi.IWifiUsabilityStatsListener;
 import android.net.wifi.PasspointManagementObjectDefinition;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiActivityEnergyInfo;
@@ -47,7 +47,7 @@
  */
 interface IWifiManager
 {
-    int getSupportedFeatures();
+    long getSupportedFeatures();
 
     WifiActivityEnergyInfo reportActivityInfo();
 
@@ -61,11 +61,11 @@
 
     ParceledListSlice getConfiguredNetworks(String packageName);
 
-    ParceledListSlice getPrivilegedConfiguredNetworks();
+    ParceledListSlice getPrivilegedConfiguredNetworks(String packageName);
 
-    List<WifiConfiguration> getAllMatchingWifiConfigs(in List<ScanResult> scanResult);
+    Map getAllMatchingFqdnsForScanResults(in List<ScanResult> scanResult);
 
-    List<OsuProvider> getMatchingOsuProviders(in List<ScanResult> scanResult);
+    Map getMatchingOsuProviders(in List<ScanResult> scanResult);
 
     Map getMatchingPasspointConfigsForOsuProviders(in List<OsuProvider> osuProviders);
 
@@ -77,6 +77,8 @@
 
     List<PasspointConfiguration> getPasspointConfigurations();
 
+    List<WifiConfiguration> getWifiConfigsForPasspointProfiles(in List<String> fqdnList);
+
     void queryPasspointIcon(long bssid, String fileName);
 
     int matchProviderWithCurrentNetwork(String fqdn);
@@ -185,6 +187,10 @@
 
     void unregisterSoftApCallback(int callbackIdentifier);
 
+    void addWifiUsabilityStatsListener(in IBinder binder, in IWifiUsabilityStatsListener listener, int listenerIdentifier);
+
+    void removeWifiUsabilityStatsListener(int listenerIdentifier);
+
     void registerTrafficStateCallback(in IBinder binder, in ITrafficStateCallback callback, int callbackIdentifier);
 
     void unregisterTrafficStateCallback(int callbackIdentifier);
@@ -209,4 +215,3 @@
 
     void stopDppSession();
 }
-
diff --git a/wifi/java/android/net/wifi/IWifiUsabilityStatsListener.aidl b/wifi/java/android/net/wifi/IWifiUsabilityStatsListener.aidl
new file mode 100644
index 0000000..284ffaa
--- /dev/null
+++ b/wifi/java/android/net/wifi/IWifiUsabilityStatsListener.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.net.wifi.WifiUsabilityStatsEntry;
+
+/**
+ * Interface for Wi-Fi usability stats listener.
+ *
+ * @hide
+ */
+oneway interface IWifiUsabilityStatsListener
+{
+    /**
+     * Service to manager callback providing current Wi-Fi usability stats.
+     *
+     * @param seqNum The sequence number of stats, used to derive the timing of updated Wi-Fi
+     *               usability statistics, set by framework and shall be incremented by one
+     *               after each update.
+     * @param isSameBssidAndFreq The flag to indicate whether the BSSID and the frequency of
+     *                           network stays the same or not relative to the last update of
+     *                           Wi-Fi usability stats.
+     * @param stats The updated Wi-Fi usability statistics.
+     */
+    void onStatsUpdated(int seqNum, boolean isSameBssidAndFreq,
+            in WifiUsabilityStatsEntry stats);
+}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a809cad..d2d711f 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -27,7 +27,6 @@
 import android.net.ProxyInfo;
 import android.net.StaticIpConfiguration;
 import android.net.Uri;
-import android.net.wifi.WifiInfo;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -146,11 +145,23 @@
          */
         public static final int SUITE_B_192 = 10;
 
+        /**
+         * WPA pre-shared key with stronger SHA256-based algorithms.
+         * @hide
+         */
+        public static final int WPA_PSK_SHA256 = 11;
+
+        /**
+         * WPA using EAP authentication with stronger SHA256-based algorithms.
+         * @hide
+         */
+        public static final int WPA_EAP_SHA256 = 12;
+
         public static final String varName = "key_mgmt";
 
         public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP",
                 "IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP",
-                "SAE", "OWE", "SUITE_B_192"};
+                "SAE", "OWE", "SUITE_B_192", "WPA_PSK_SHA256", "WPA_EAP_SHA256" };
     }
 
     /**
@@ -491,7 +502,7 @@
      * The set of group management ciphers supported by this configuration.
      * See {@link GroupMgmtCipher} for descriptions of the values.
      */
-    public BitSet allowedGroupMgmtCiphers;
+    public BitSet allowedGroupManagementCiphers;
     /**
      * The set of SuiteB ciphers supported by this configuration.
      * To be used for WPA3-Enterprise mode.
@@ -944,9 +955,12 @@
     }
 
     /**
-     * @hide
      * Returns MAC address set to be the local randomized MAC address.
      * Does not guarantee that the returned address is valid for use.
+     * <p>
+     * Information is restricted to Device Owner, Profile Owner, and Carrier apps
+     * (which will only obtain addresses for configurations which they create). Other callers
+     * will receive a default "02:00:00:00:00:00" MAC address.
      */
     public @NonNull MacAddress getRandomizedMacAddress() {
         return mRandomizedMacAddress;
@@ -1642,7 +1656,7 @@
         allowedAuthAlgorithms = new BitSet();
         allowedPairwiseCiphers = new BitSet();
         allowedGroupCiphers = new BitSet();
-        allowedGroupMgmtCiphers = new BitSet();
+        allowedGroupManagementCiphers = new BitSet();
         allowedSuiteBCiphers = new BitSet();
         wepKeys = new String[4];
         for (int i = 0; i < wepKeys.length; i++) {
@@ -1835,8 +1849,8 @@
         }
         sbuf.append('\n');
         sbuf.append(" GroupMgmtCiphers:");
-        for (int gmc = 0; gmc < this.allowedGroupMgmtCiphers.size(); gmc++) {
-            if (this.allowedGroupMgmtCiphers.get(gmc)) {
+        for (int gmc = 0; gmc < this.allowedGroupManagementCiphers.size(); gmc++) {
+            if (this.allowedGroupManagementCiphers.get(gmc)) {
                 sbuf.append(" ");
                 if (gmc < GroupMgmtCipher.strings.length) {
                     sbuf.append(GroupMgmtCipher.strings[gmc]);
@@ -1887,6 +1901,7 @@
         if (creatorName != null) sbuf.append(" cname=" + creatorName);
         if (lastUpdateUid != 0) sbuf.append(" luid=" + lastUpdateUid);
         if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName);
+        if (updateIdentifier != null) sbuf.append(" updateIdentifier=" + updateIdentifier);
         sbuf.append(" lcuid=" + lastConnectUid);
         sbuf.append(" userApproved=" + userApprovedAsString(userApproved));
         sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected);
@@ -2235,7 +2250,7 @@
             allowedAuthAlgorithms  = (BitSet) source.allowedAuthAlgorithms.clone();
             allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone();
             allowedGroupCiphers    = (BitSet) source.allowedGroupCiphers.clone();
-            allowedGroupMgmtCiphers    = (BitSet) source.allowedGroupMgmtCiphers.clone();
+            allowedGroupManagementCiphers = (BitSet) source.allowedGroupManagementCiphers.clone();
             allowedSuiteBCiphers    = (BitSet) source.allowedSuiteBCiphers.clone();
             enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
 
@@ -2282,6 +2297,7 @@
             mRandomizedMacAddress = source.mRandomizedMacAddress;
             macRandomizationSetting = source.macRandomizationSetting;
             requirePMF = source.requirePMF;
+            updateIdentifier = source.updateIdentifier;
         }
     }
 
@@ -2317,7 +2333,7 @@
         writeBitSet(dest, allowedAuthAlgorithms);
         writeBitSet(dest, allowedPairwiseCiphers);
         writeBitSet(dest, allowedGroupCiphers);
-        writeBitSet(dest, allowedGroupMgmtCiphers);
+        writeBitSet(dest, allowedGroupManagementCiphers);
         writeBitSet(dest, allowedSuiteBCiphers);
 
         dest.writeParcelable(enterpriseConfig, flags);
@@ -2389,7 +2405,7 @@
                 config.allowedAuthAlgorithms  = readBitSet(in);
                 config.allowedPairwiseCiphers = readBitSet(in);
                 config.allowedGroupCiphers    = readBitSet(in);
-                config.allowedGroupMgmtCiphers = readBitSet(in);
+                config.allowedGroupManagementCiphers = readBitSet(in);
                 config.allowedSuiteBCiphers   = readBitSet(in);
 
                 config.enterpriseConfig = in.readParcelable(null);
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 7cdd16a..35fba3d 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi;
 
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkUtils;
@@ -93,12 +94,22 @@
     private int mRssi;
 
     /**
-     * Link speed in Mbps
+     * The unit in which links speeds are expressed.
      */
     public static final String LINK_SPEED_UNITS = "Mbps";
     private int mLinkSpeed;
 
     /**
+     * Tx(transmit) Link speed in Mbps
+     */
+    private int mTxLinkSpeed;
+
+    /**
+     * Rx(receive) Link speed in Mbps
+     */
+    private int mRxLinkSpeed;
+
+    /**
      * Frequency in MHz
      */
     public static final String FREQUENCY_UNITS = "MHz";
@@ -114,6 +125,11 @@
     private boolean mTrusted;
 
     /**
+     * OSU (Online Sign Up) AP for Passpoint R2.
+     */
+    private boolean mOsuAp;
+
+    /**
      * Running total count of lost (not ACKed) transmitted unicast data packets.
      * @hide
      */
@@ -187,9 +203,12 @@
         setNetworkId(-1);
         setRssi(INVALID_RSSI);
         setLinkSpeed(-1);
+        setTxLinkSpeedMbps(-1);
+        setRxLinkSpeedMbps(-1);
         setFrequency(-1);
         setMeteredHint(false);
         setEphemeral(false);
+        setOsuAp(false);
         txBad = 0;
         txSuccess = 0;
         rxSuccess = 0;
@@ -213,12 +232,15 @@
             mNetworkId = source.mNetworkId;
             mRssi = source.mRssi;
             mLinkSpeed = source.mLinkSpeed;
+            mTxLinkSpeed = source.mTxLinkSpeed;
+            mRxLinkSpeed = source.mRxLinkSpeed;
             mFrequency = source.mFrequency;
             mIpAddress = source.mIpAddress;
             mMacAddress = source.mMacAddress;
             mMeteredHint = source.mMeteredHint;
             mEphemeral = source.mEphemeral;
             mTrusted = source.mTrusted;
+            mOsuAp = source.mOsuAp;
             txBad = source.txBad;
             txRetries = source.txRetries;
             txSuccess = source.txSuccess;
@@ -306,7 +328,7 @@
 
     /**
      * Returns the current link speed in {@link #LINK_SPEED_UNITS}.
-     * @return the link speed.
+     * @return the link speed or -1 if there is no valid value.
      * @see #LINK_SPEED_UNITS
      */
     public int getLinkSpeed() {
@@ -316,7 +338,39 @@
     /** @hide */
     @UnsupportedAppUsage
     public void setLinkSpeed(int linkSpeed) {
-        this.mLinkSpeed = linkSpeed;
+        mLinkSpeed = linkSpeed;
+    }
+
+    /**
+     * Returns the current transmit link speed in Mbps.
+     * @return the Tx link speed or -1 if there is no valid value.
+     */
+    public int getTxLinkSpeedMbps() {
+        return mTxLinkSpeed;
+    }
+
+    /**
+     * Update the last transmitted packet bit rate in Mbps.
+     * @hide
+     */
+    public void setTxLinkSpeedMbps(int txLinkSpeed) {
+        mTxLinkSpeed = txLinkSpeed;
+    }
+
+    /**
+     * Returns the current receive link speed in Mbps.
+     * @return the Rx link speed or -1 if there is no valid value.
+     */
+    public int getRxLinkSpeedMbps() {
+        return mRxLinkSpeed;
+    }
+
+    /**
+     * Update the last received packet bit rate in Mbps.
+     * @hide
+     */
+    public void setRxLinkSpeedMbps(int rxLinkSpeed) {
+        mRxLinkSpeed = rxLinkSpeed;
     }
 
     /**
@@ -411,6 +465,16 @@
         return mTrusted;
     }
 
+    /** {@hide} */
+    public void setOsuAp(boolean osuAp) {
+        mOsuAp = osuAp;
+    }
+
+    /** {@hide} */
+    @SystemApi
+    public boolean isOsuAp() {
+        return mOsuAp;
+    }
 
     /** @hide */
     @UnsupportedAppUsage
@@ -513,17 +577,19 @@
         StringBuffer sb = new StringBuffer();
         String none = "<none>";
 
-        sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid).
-            append(", BSSID: ").append(mBSSID == null ? none : mBSSID).
-            append(", MAC: ").append(mMacAddress == null ? none : mMacAddress).
-            append(", Supplicant state: ").
-            append(mSupplicantState == null ? none : mSupplicantState).
-            append(", RSSI: ").append(mRssi).
-            append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS).
-            append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS).
-            append(", Net ID: ").append(mNetworkId).
-            append(", Metered hint: ").append(mMeteredHint).
-            append(", score: ").append(Integer.toString(score));
+        sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid)
+                .append(", BSSID: ").append(mBSSID == null ? none : mBSSID)
+                .append(", MAC: ").append(mMacAddress == null ? none : mMacAddress)
+                .append(", Supplicant state: ")
+                .append(mSupplicantState == null ? none : mSupplicantState)
+                .append(", RSSI: ").append(mRssi)
+                .append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS)
+                .append(", Tx Link speed: ").append(mTxLinkSpeed).append(LINK_SPEED_UNITS)
+                .append(", Rx Link speed: ").append(mRxLinkSpeed).append(LINK_SPEED_UNITS)
+                .append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS)
+                .append(", Net ID: ").append(mNetworkId)
+                .append(", Metered hint: ").append(mMeteredHint)
+                .append(", score: ").append(Integer.toString(score));
         return sb.toString();
     }
 
@@ -537,6 +603,8 @@
         dest.writeInt(mNetworkId);
         dest.writeInt(mRssi);
         dest.writeInt(mLinkSpeed);
+        dest.writeInt(mTxLinkSpeed);
+        dest.writeInt(mRxLinkSpeed);
         dest.writeInt(mFrequency);
         if (mIpAddress != null) {
             dest.writeByte((byte)1);
@@ -565,6 +633,7 @@
         dest.writeLong(rxSuccess);
         dest.writeDouble(rxSuccessRate);
         mSupplicantState.writeToParcel(dest, flags);
+        dest.writeInt(mOsuAp ? 1 : 0);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -576,6 +645,8 @@
                 info.setNetworkId(in.readInt());
                 info.setRssi(in.readInt());
                 info.setLinkSpeed(in.readInt());
+                info.setTxLinkSpeedMbps(in.readInt());
+                info.setRxLinkSpeedMbps(in.readInt());
                 info.setFrequency(in.readInt());
                 if (in.readByte() == 1) {
                     try {
@@ -600,6 +671,7 @@
                 info.rxSuccess = in.readLong();
                 info.rxSuccessRate = in.readDouble();
                 info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
+                info.mOsuAp = in.readInt() != 0;
                 return info;
             }
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index e67e8ea..084bd09 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -16,6 +16,11 @@
 
 package android.net.wifi;
 
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_WIFI_STATE;
+import static android.Manifest.permission.READ_WIFI_CREDENTIAL;
+
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -44,6 +49,7 @@
 import android.os.RemoteException;
 import android.os.WorkSource;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -63,6 +69,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
 
 /**
  * This class provides the primary API for managing all aspects of Wi-Fi
@@ -184,6 +191,7 @@
      */
     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5;
 
+    /** @hide */
     @IntDef(prefix = { "STATUS_NETWORK_SUGGESTIONS_" }, value = {
             STATUS_NETWORK_SUGGESTIONS_SUCCESS,
             STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL,
@@ -229,6 +237,14 @@
     @SystemApi
     public static final int WIFI_CREDENTIAL_FORGOT = 1;
 
+    /** @hide */
+    @SystemApi
+    public static final int PASSPOINT_HOME_NETWORK = 0;
+
+    /** @hide */
+    @SystemApi
+    public static final int PASSPOINT_ROAMING_NETWORK = 1;
+
     /**
      * Broadcast intent action indicating that a Passpoint provider icon has been received.
      *
@@ -1135,6 +1151,10 @@
     /**
      * Return a list of all the networks configured for the current foreground
      * user.
+     *
+     * Requires the same permissions as {@link #getScanResults}.
+     * If such access is not allowed, this API will always return an empty list.
+     *
      * Not all fields of WifiConfiguration are returned. Only the following
      * fields are filled in:
      * <ul>
@@ -1158,9 +1178,12 @@
      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
      * when auto-connecting to wifi.
      * <b>Compatibility Note:</b> For applications targeting
-     * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return an empty list.
+     * {@link android.os.Build.VERSION_CODES#Q} or above, this API will return an empty list,
+     * except to callers with Carrier privilege which will receive a restricted list only
+     * containing configurations which they created.
      */
     @Deprecated
+    @RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, ACCESS_WIFI_STATE})
     public List<WifiConfiguration> getConfiguredNetworks() {
         try {
             ParceledListSlice<WifiConfiguration> parceledList =
@@ -1176,11 +1199,11 @@
 
     /** @hide */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL)
+    @RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, ACCESS_WIFI_STATE, READ_WIFI_CREDENTIAL})
     public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
         try {
             ParceledListSlice<WifiConfiguration> parceledList =
-                mService.getPrivilegedConfiguredNetworks();
+                    mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName());
             if (parceledList == null) {
                 return Collections.emptyList();
             }
@@ -1191,25 +1214,47 @@
     }
 
     /**
-     * Returns all matching WifiConfigurations for a given list of ScanResult.
+     * Returns a list of all matching WifiConfigurations for a given list of ScanResult.
      *
      * An empty list will be returned when no configurations are installed or if no configurations
      * match the ScanResult.
-
+     *
      * @param scanResults a list of scanResult that represents the BSSID
-     * @return A list of {@link WifiConfiguration} that can have duplicate entries.
+     * @return List that consists of {@link WifiConfiguration} and corresponding scanResults per
+     * network type({@link #PASSPOINT_HOME_NETWORK} and {@link #PASSPOINT_ROAMING_NETWORK}).
      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
-    public List<WifiConfiguration> getAllMatchingWifiConfigs(
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD
+    })
+    public List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> getAllMatchingWifiConfigs(
             @NonNull List<ScanResult> scanResults) {
+        List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
         try {
-            return mService.getAllMatchingWifiConfigs(scanResults);
+            Map<String, Map<Integer, List<ScanResult>>> results =
+                    mService.getAllMatchingFqdnsForScanResults(
+                            scanResults);
+            if (results.isEmpty()) {
+                return configs;
+            }
+            List<WifiConfiguration> wifiConfigurations =
+                    mService.getWifiConfigsForPasspointProfiles(
+                            new ArrayList<>(results.keySet()));
+            for (WifiConfiguration configuration : wifiConfigurations) {
+                Map<Integer, List<ScanResult>> scanResultsPerNetworkType = results.get(
+                        configuration.FQDN);
+                if (scanResultsPerNetworkType != null) {
+                    configs.add(Pair.create(configuration, scanResultsPerNetworkType));
+                }
+            }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
+
+        return configs;
     }
 
     /**
@@ -1219,12 +1264,17 @@
      * An empty list will be returned if no match is found.
      *
      * @param scanResults a list of ScanResult
-     * @return A list of {@link OsuProvider} that does not contain duplicate entries.
+     * @return Map that consists {@link OsuProvider} and a list of matching {@link ScanResult}
      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
-    public List<OsuProvider> getMatchingOsuProviders(List<ScanResult> scanResults) {
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD
+    })
+    public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
+            List<ScanResult> scanResults) {
         try {
             return mService.getMatchingOsuProviders(scanResults);
         } catch (RemoteException e) {
@@ -1245,7 +1295,11 @@
      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD
+    })
     public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
             @NonNull Set<OsuProvider> osuProviders) {
         try {
@@ -1617,7 +1671,7 @@
      * suggestion back using this API.</li>
      *
      * @param networkSuggestions List of network suggestions provided by the app.
-     * @return Status code corresponding to the values in {@link NetworkSuggestionsStatusCode}.
+     * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
      * {@link WifiNetworkSuggestion#equals(Object)} any previously provided suggestions by the app.
      * @throws {@link SecurityException} if the caller is missing required permissions.
      */
@@ -1638,8 +1692,7 @@
      *
      * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
      *                           to remove all the previous suggestions provided by the app.
-     * @return Status code corresponding to the values in
-     * {@link NetworkSuggestionsStatusCode}.
+     * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
      * Any matching suggestions are removed from the device and will not be considered for any
      * further connection attempts.
      */
@@ -1692,7 +1745,13 @@
      * @param fqdn The FQDN of the Passpoint configuration to be removed
      * @throws IllegalArgumentException if no configuration is associated with the given FQDN.
      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
+     * @deprecated This is no longer supported.
      */
+    @Deprecated
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD
+    })
     public void removePasspointConfiguration(String fqdn) {
         try {
             if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
@@ -1710,7 +1769,13 @@
      *
      * @return A list of {@link PasspointConfiguration}
      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
+     * @deprecated This is no longer supported.
      */
+    @Deprecated
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD
+    })
     public List<PasspointConfiguration> getPasspointConfigurations() {
         try {
             return mService.getPasspointConfigurations();
@@ -2019,8 +2084,10 @@
     public static final int WIFI_FEATURE_LOW_LATENCY      = 0x40000000; // Low Latency modes
     /** @hide */
     public static final int WIFI_FEATURE_DPP              = 0x80000000; // DPP (Easy-Connect)
+    /** @hide */
+    public static final long WIFI_FEATURE_P2P_RAND_MAC    = 0x100000000L; // Random P2P MAC
 
-    private int getSupportedFeatures() {
+    private long getSupportedFeatures() {
         try {
             return mService.getSupportedFeatures();
         } catch (RemoteException e) {
@@ -2028,7 +2095,7 @@
         }
     }
 
-    private boolean isFeatureSupported(int feature) {
+    private boolean isFeatureSupported(long feature) {
         return (getSupportedFeatures() & feature) == feature;
     }
     /**
@@ -3652,10 +3719,8 @@
      * @param SSID, in the format of WifiConfiguration's SSID.
      * @hide
      */
-    @SystemApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.NETWORK_SETTINGS,
-            android.Manifest.permission.NETWORK_SETUP_WIZARD,
             android.Manifest.permission.NETWORK_STACK
     })
     public void disableEphemeralNetwork(String SSID) {
@@ -4288,6 +4353,11 @@
      * @param callback {@link ProvisioningCallback} for updates regarding provisioning flow
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD
+    })
     public void startSubscriptionProvisioning(OsuProvider provider, ProvisioningCallback callback,
             @Nullable Handler handler) {
         Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
@@ -4465,9 +4535,14 @@
     }
 
     /**
-     * @return true if this device supports Wi-Fi Device Provisioning Protocol (Easy-connect)
+     * Wi-Fi Easy Connect (DPP) introduces standardized mechanisms to simplify the provisioning and
+     * configuration of Wi-Fi devices.
+     * For more details, visit <a href="https://www.wi-fi.org/">https://www.wi-fi.org/</a> and
+     * search for "Easy Connect" or "Device Provisioning Protocol specification".
+     *
+     * @return true if this device supports Wi-Fi Easy-connect (Device Provisioning Protocol)
      */
-    public boolean isDppSupported() {
+    public boolean isEasyConnectSupported() {
         return isFeatureSupported(WIFI_FEATURE_DPP);
     }
 
@@ -4551,93 +4626,101 @@
         }
     }
 
-    /* DPP - Device Provisioning Protocol AKA "Easy Connect" */
+    /* Easy Connect - AKA Device Provisioning Protocol (DPP) */
 
     /**
-     * DPP Network role: Station.
+     * Easy Connect Network role: Station.
+     *
      * @hide
      */
     @SystemApi
-    public static final int DPP_NETWORK_ROLE_STA = 0;
+    public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0;
 
     /**
-     * DPP Network role: Access Point.
+     * Easy Connect Network role: Access Point.
+     *
      * @hide
      */
     @SystemApi
-    public static final int DPP_NETWORK_ROLE_AP = 1;
+    public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1;
 
     /** @hide */
-    @IntDef(prefix = {"DPP_NETWORK_ROLE_"}, value = {
-            DPP_NETWORK_ROLE_STA,
-            DPP_NETWORK_ROLE_AP,
+    @IntDef(prefix = {"EASY_CONNECT_NETWORK_ROLE_"}, value = {
+            EASY_CONNECT_NETWORK_ROLE_STA,
+            EASY_CONNECT_NETWORK_ROLE_AP,
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface DppNetworkRole {}
+    public @interface EasyConnectNetworkRole {
+    }
 
     /**
-     * Start DPP in Configurator-Initiator role. The current device will initiate DPP bootstrapping
-     * with a peer, and configure the peer with the SSID and password of the specified network using
-     * the DPP protocol on an encrypted link.
+     * Start Easy Connect (DPP) in Configurator-Initiator role. The current device will initiate
+     * Easy Connect bootstrapping with a peer, and configure the peer with the SSID and password of
+     * the specified network using the Easy Connect protocol on an encrypted link.
      *
-     * @param enrolleeUri URI of the Enrollee obtained separately (e.g. QR code scanning)
-     * @param selectedNetworkId Selected network ID to be sent to the peer
+     * @param enrolleeUri         URI of the Enrollee obtained separately (e.g. QR code scanning)
+     * @param selectedNetworkId   Selected network ID to be sent to the peer
      * @param enrolleeNetworkRole The network role of the enrollee
-     * @param callback Callback for status updates
-     * @param handler The handler on whose thread to execute the callbacks. Null for main thread.
+     * @param callback            Callback for status updates
+     * @param executor            The Executor on which to run the callback.
      * @hide
      */
     @SystemApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.NETWORK_SETTINGS,
             android.Manifest.permission.NETWORK_SETUP_WIZARD})
-    public void startDppAsConfiguratorInitiator(@NonNull String enrolleeUri,
-            int selectedNetworkId, @DppNetworkRole int enrolleeNetworkRole,
-            @Nullable Handler handler, @NonNull DppStatusCallback callback) {
-        Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
+    public void startEasyConnectAsConfiguratorInitiator(@NonNull String enrolleeUri,
+            int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull EasyConnectStatusCallback callback) {
         Binder binder = new Binder();
         try {
             mService.startDppAsConfiguratorInitiator(binder, enrolleeUri, selectedNetworkId,
-                    enrolleeNetworkRole, new DppCallbackProxy(looper, callback));
+                    enrolleeNetworkRole, new EasyConnectCallbackProxy(executor, callback));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Start DPP in Enrollee-Initiator role. The current device will initiate DPP bootstrapping
-     * with a peer, and receive the SSID and password from the peer configurator.
+     * Start Easy Connect (DPP) in Enrollee-Initiator role. The current device will initiate Easy
+     * Connect bootstrapping with a peer, and receive the SSID and password from the peer
+     * configurator.
      *
      * @param configuratorUri URI of the Configurator obtained separately (e.g. QR code scanning)
-     * @param callback Callback for status updates
-     * @param handler The handler on whose thread to execute the callbacks. Null for main thread.
+     * @param callback        Callback for status updates
+     * @param executor        The Executor on which to run the callback.
      * @hide
      */
     @SystemApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.NETWORK_SETTINGS,
             android.Manifest.permission.NETWORK_SETUP_WIZARD})
-    public void startDppAsEnrolleeInitiator(@NonNull String configuratorUri,
-            @Nullable Handler handler, @NonNull DppStatusCallback callback) {
-        Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
+    public void startEasyConnectAsEnrolleeInitiator(@NonNull String configuratorUri,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull EasyConnectStatusCallback callback) {
         Binder binder = new Binder();
         try {
             mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
-                     new DppCallbackProxy(looper, callback));
+                    new EasyConnectCallbackProxy(executor, callback));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Stop or abort a current DPP session.
+     * Stop or abort a current Easy Connect (DPP) session. This call, once processed, will
+     * terminate any ongoing transaction, and clean up all associated resources. Caller should not
+     * expect any callbacks once this call is made. However, due to the asynchronous nature of
+     * this call, a callback may be fired if it was already pending in the queue.
+     *
      * @hide
      */
     @SystemApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.NETWORK_SETTINGS,
             android.Manifest.permission.NETWORK_SETUP_WIZARD})
-    public void stopDppSession() {
+    public void stopEasyConnectSession() {
         try {
             /* Request lower layers to stop/abort and clear resources */
             mService.stopDppSession();
@@ -4647,49 +4730,139 @@
     }
 
     /**
-     * Helper class to support DPP callbacks
+     * Helper class to support Easy Connect (DPP) callbacks
+     *
      * @hide
      */
     @SystemApi
-    private static class DppCallbackProxy extends IDppCallback.Stub {
-        private final Handler mHandler;
-        private final DppStatusCallback mDppStatusCallback;
+    private static class EasyConnectCallbackProxy extends IDppCallback.Stub {
+        private final Executor mExecutor;
+        private final EasyConnectStatusCallback mEasyConnectStatusCallback;
 
-        DppCallbackProxy(Looper looper, DppStatusCallback dppStatusCallback) {
-            mHandler = new Handler(looper);
-            mDppStatusCallback = dppStatusCallback;
+        EasyConnectCallbackProxy(Executor executor,
+                EasyConnectStatusCallback easyConnectStatusCallback) {
+            mExecutor = executor;
+            mEasyConnectStatusCallback = easyConnectStatusCallback;
         }
 
         @Override
         public void onSuccessConfigReceived(int newNetworkId) {
-            Log.d(TAG, "DPP onSuccessConfigReceived callback");
-            mHandler.post(() -> {
-                mDppStatusCallback.onEnrolleeSuccess(newNetworkId);
+            Log.d(TAG, "Easy Connect onSuccessConfigReceived callback");
+            mExecutor.execute(() -> {
+                mEasyConnectStatusCallback.onEnrolleeSuccess(newNetworkId);
             });
         }
 
         @Override
         public void onSuccess(int status) {
-            Log.d(TAG, "DPP onSuccess callback");
-            mHandler.post(() -> {
-                mDppStatusCallback.onConfiguratorSuccess(status);
+            Log.d(TAG, "Easy Connect onSuccess callback");
+            mExecutor.execute(() -> {
+                mEasyConnectStatusCallback.onConfiguratorSuccess(status);
             });
         }
 
         @Override
         public void onFailure(int status) {
-            Log.d(TAG, "DPP onFailure callback");
-            mHandler.post(() -> {
-                mDppStatusCallback.onFailure(status);
+            Log.d(TAG, "Easy Connect onFailure callback");
+            mExecutor.execute(() -> {
+                mEasyConnectStatusCallback.onFailure(status);
             });
         }
 
         @Override
         public void onProgress(int status) {
-            Log.d(TAG, "DPP onProgress callback");
-            mHandler.post(() -> {
-                mDppStatusCallback.onProgress(status);
+            Log.d(TAG, "Easy Connect onProgress callback");
+            mExecutor.execute(() -> {
+                mEasyConnectStatusCallback.onProgress(status);
             });
         }
     }
+
+    /**
+     * Interface for Wi-Fi usability statistics listener. Should be implemented by applications and
+     * set when calling {@link WifiManager#addWifiUsabilityStatsListener(Executor,
+     * WifiUsabilityStatsListener)}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface WifiUsabilityStatsListener {
+        /**
+         * Called when Wi-Fi usability statistics is updated.
+         *
+         * @param seqNum The sequence number of statistics, used to derive the timing of updated
+         *               Wi-Fi usability statistics, set by framework and incremented by one after
+         *               each update.
+         * @param isSameBssidAndFreq The flag to indicate whether the BSSID and the frequency of
+         *                           network stays the same or not relative to the last update of
+         *                           Wi-Fi usability stats.
+         * @param stats The updated Wi-Fi usability statistics.
+         */
+        void onStatsUpdated(int seqNum, boolean isSameBssidAndFreq,
+                WifiUsabilityStatsEntry stats);
+    }
+
+    /**
+     * Adds a listener for Wi-Fi usability statistics. See {@link WifiUsabilityStatsListener}.
+     * Multiple listeners can be added. Callers will be invoked periodically by framework to
+     * inform clients about the current Wi-Fi usability statistics. Callers can remove a previously
+     * added listener using {@link removeWifiUsabilityStatsListener}.
+     *
+     * @param executor The executor on which callback will be invoked.
+     * @param listener Listener for Wifi usability statistics.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
+    public void addWifiUsabilityStatsListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull WifiUsabilityStatsListener listener) {
+        if (executor == null) throw new IllegalArgumentException("executor cannot be null");
+        if (listener == null) throw new IllegalArgumentException("listener cannot be null");
+        if (mVerboseLoggingEnabled) {
+            Log.v(TAG, "addWifiUsabilityStatsListener: listener=" + listener);
+        }
+        try {
+            mService.addWifiUsabilityStatsListener(new Binder(),
+                    new IWifiUsabilityStatsListener.Stub() {
+                        @Override
+                        public void onStatsUpdated(int seqNum, boolean isSameBssidAndFreq,
+                                WifiUsabilityStatsEntry stats) {
+                            if (mVerboseLoggingEnabled) {
+                                Log.v(TAG, "WifiUsabilityStatsListener: onStatsUpdated: seqNum="
+                                        + seqNum);
+                            }
+                            Binder.withCleanCallingIdentity(() ->
+                                    executor.execute(() -> listener.onStatsUpdated(seqNum,
+                                            isSameBssidAndFreq, stats)));
+                        }
+                    },
+                    listener.hashCode()
+            );
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Allow callers to remove a previously registered listener. After calling this method,
+     * applications will no longer receive Wi-Fi usability statistics.
+     *
+     * @param listener Listener to remove the Wi-Fi usability statistics.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
+    public void removeWifiUsabilityStatsListener(@NonNull WifiUsabilityStatsListener listener) {
+        if (listener == null) throw new IllegalArgumentException("listener cannot be null");
+        if (mVerboseLoggingEnabled) {
+            Log.v(TAG, "removeWifiUsabilityStatsListener: listener=" + listener);
+        }
+        try {
+            mService.removeWifiUsabilityStatsListener(listener.hashCode());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
index 955e040..52ee742 100644
--- a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
@@ -28,6 +28,7 @@
 import android.net.NetworkSpecifier;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 
 import java.util.Objects;
 
@@ -50,12 +51,24 @@
      */
     private final int mOriginalRequestorUid;
 
+    /**
+     * The package name of the app that requested a specific wifi network using
+     * {@link WifiNetworkSpecifier}.
+     *
+     * Will only be filled when the device connects to a wifi network as a result of a
+     * {@link NetworkRequest} with {@link WifiNetworkSpecifier}. Will be set to null if the device
+     * auto-connected to a wifi network.
+     */
+    private final String mOriginalRequestorPackageName;
+
     public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration,
-                                     int originalRequestorUid) {
+                                     int originalRequestorUid,
+                                     @Nullable String originalRequestorPackageName) {
         checkNotNull(wifiConfiguration);
 
         mWifiConfiguration = wifiConfiguration;
         mOriginalRequestorUid = originalRequestorUid;
+        mOriginalRequestorPackageName = originalRequestorPackageName;
     }
 
     /**
@@ -67,7 +80,9 @@
                 public WifiNetworkAgentSpecifier createFromParcel(@NonNull Parcel in) {
                     WifiConfiguration wifiConfiguration = in.readParcelable(null);
                     int originalRequestorUid = in.readInt();
-                    return new WifiNetworkAgentSpecifier(wifiConfiguration, originalRequestorUid);
+                    String originalRequestorPackageName = in.readString();
+                    return new WifiNetworkAgentSpecifier(
+                            wifiConfiguration, originalRequestorUid, originalRequestorPackageName);
                 }
 
                 @Override
@@ -85,6 +100,7 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeParcelable(mWifiConfiguration, flags);
         dest.writeInt(mOriginalRequestorUid);
+        dest.writeString(mOriginalRequestorPackageName);
     }
 
     @Override
@@ -137,6 +153,9 @@
         if (ns.requestorUid != this.mOriginalRequestorUid) {
             return false;
         }
+        if (!TextUtils.equals(ns.requestorPackageName, this.mOriginalRequestorPackageName)) {
+            return false;
+        }
         return true;
     }
 
@@ -146,7 +165,8 @@
                 mWifiConfiguration.SSID,
                 mWifiConfiguration.BSSID,
                 mWifiConfiguration.allowedKeyManagement,
-                mOriginalRequestorUid);
+                mOriginalRequestorUid,
+                mOriginalRequestorPackageName);
     }
 
     @Override
@@ -162,15 +182,19 @@
                 && Objects.equals(this.mWifiConfiguration.BSSID, lhs.mWifiConfiguration.BSSID)
                 && Objects.equals(this.mWifiConfiguration.allowedKeyManagement,
                     lhs.mWifiConfiguration.allowedKeyManagement)
-                && mOriginalRequestorUid == lhs.mOriginalRequestorUid;
+                && mOriginalRequestorUid == lhs.mOriginalRequestorUid
+                && TextUtils.equals(mOriginalRequestorPackageName,
+                lhs.mOriginalRequestorPackageName);
     }
 
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder("WifiNetworkAgentSpecifier [");
-        sb.append("WifiConfiguration=").append(
-                mWifiConfiguration == null ? null : mWifiConfiguration.configKey())
+        sb.append("WifiConfiguration=")
+                .append(", SSID=").append(mWifiConfiguration.SSID)
+                .append(", BSSID=").append(mWifiConfiguration.BSSID)
                 .append(", mOriginalRequestorUid=").append(mOriginalRequestorUid)
+                .append(", mOriginalRequestorPackageName=").append(mOriginalRequestorPackageName)
                 .append("]");
         return sb.toString();
     }
@@ -180,4 +204,9 @@
         throw new IllegalStateException("WifiNetworkAgentSpecifier should never be used "
                 + "for requests.");
     }
+
+    @Override
+    public NetworkSpecifier redact() {
+        return null;
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
index f73b9e5..42d4393 100644
--- a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
+++ b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
@@ -20,6 +20,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityThread;
 import android.net.MacAddress;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
@@ -412,7 +413,7 @@
             configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
             configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
             // TODO (b/113878056): Verify these params once we verify SuiteB configuration.
-            configuration.allowedGroupMgmtCiphers.set(
+            configuration.allowedGroupManagementCiphers.set(
                     WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
             configuration.allowedSuiteBCiphers.set(
                     WifiConfiguration.SuiteBCipher.ECDHE_ECDSA);
@@ -586,7 +587,8 @@
                 mSsidPatternMatcher,
                 mBssidPatternMatcher,
                 buildWifiConfiguration(),
-                Process.myUid());
+                Process.myUid(),
+                ActivityThread.currentApplication().getApplicationContext().getOpPackageName());
     }
 
     /**
@@ -648,7 +650,8 @@
                 buildWifiConfiguration(),
                 mIsAppInteractionRequired,
                 mIsUserInteractionRequired,
-                Process.myUid());
+                Process.myUid(),
+                ActivityThread.currentApplication().getApplicationContext().getOpPackageName());
 
     }
 }
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
index 4348399..a5f4675 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -25,6 +25,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PatternMatcher;
+import android.text.TextUtils;
 import android.util.Pair;
 
 import java.util.Objects;
@@ -63,18 +64,25 @@
      */
     public final int requestorUid;
 
+    /**
+     * The package name of the app initializing this network specifier.
+     */
+    public final String requestorPackageName;
+
     public WifiNetworkSpecifier(@NonNull PatternMatcher ssidPatternMatcher,
                  @NonNull Pair<MacAddress, MacAddress> bssidPatternMatcher,
                  @NonNull WifiConfiguration wifiConfiguration,
-                 int requestorUid) {
+                 int requestorUid, @NonNull String requestorPackageName) {
         checkNotNull(ssidPatternMatcher);
         checkNotNull(bssidPatternMatcher);
         checkNotNull(wifiConfiguration);
+        checkNotNull(requestorPackageName);
 
         this.ssidPatternMatcher = ssidPatternMatcher;
         this.bssidPatternMatcher = bssidPatternMatcher;
         this.wifiConfiguration = wifiConfiguration;
         this.requestorUid = requestorUid;
+        this.requestorPackageName = requestorPackageName;
     }
 
     public static final Creator<WifiNetworkSpecifier> CREATOR =
@@ -88,8 +96,9 @@
                             Pair.create(baseAddress, mask);
                     WifiConfiguration wifiConfiguration = in.readParcelable(null);
                     int requestorUid = in.readInt();
+                    String requestorPackageName = in.readString();
                     return new WifiNetworkSpecifier(ssidPatternMatcher, bssidPatternMatcher,
-                            wifiConfiguration, requestorUid);
+                            wifiConfiguration, requestorUid, requestorPackageName);
                 }
 
                 @Override
@@ -110,6 +119,7 @@
         dest.writeParcelable(bssidPatternMatcher.second, flags);
         dest.writeParcelable(wifiConfiguration, flags);
         dest.writeInt(requestorUid);
+        dest.writeString(requestorPackageName);
     }
 
     @Override
@@ -136,7 +146,7 @@
                 ssidPatternMatcher.getType(),
                 bssidPatternMatcher,
                 wifiConfiguration.allowedKeyManagement,
-                requestorUid);
+                requestorUid, requestorPackageName);
     }
 
     @Override
@@ -156,18 +166,20 @@
                     lhs.bssidPatternMatcher)
                 && Objects.equals(this.wifiConfiguration.allowedKeyManagement,
                     lhs.wifiConfiguration.allowedKeyManagement)
-                && requestorUid == lhs.requestorUid;
+                && requestorUid == lhs.requestorUid
+                && TextUtils.equals(requestorPackageName, lhs.requestorPackageName);
     }
 
     @Override
     public String toString() {
         return new StringBuilder()
-                .append("WifiNetworkSpecifierWifiNetworkSpecifier [")
+                .append("WifiNetworkSpecifier [")
                 .append(", SSID Match pattern=").append(ssidPatternMatcher)
                 .append(", BSSID Match pattern=").append(bssidPatternMatcher)
-                .append(", WifiConfiguration=").append(
-                wifiConfiguration == null ? null : wifiConfiguration.configKey())
+                .append(", SSID=").append(wifiConfiguration.SSID)
+                .append(", BSSID=").append(wifiConfiguration.BSSID)
                 .append(", requestorUid=").append(requestorUid)
+                .append(", requestorPackageName=").append(requestorPackageName)
                 .append("]")
                 .toString();
     }
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 760f1e6..6b05dfc 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -18,8 +18,10 @@
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 
 import java.util.List;
 import java.util.Objects;
@@ -58,17 +60,25 @@
      */
     public final int suggestorUid;
 
+    /**
+     * The package name of the process initializing this network suggestion.
+     * @hide
+     */
+    public final String suggestorPackageName;
+
     /** @hide */
-    public WifiNetworkSuggestion(WifiConfiguration wifiConfiguration,
+    public WifiNetworkSuggestion(@NonNull WifiConfiguration wifiConfiguration,
                                  boolean isAppInteractionRequired,
                                  boolean isUserInteractionRequired,
-                                 int suggestorUid) {
+                                 int suggestorUid, @NonNull String suggestorPackageName) {
         checkNotNull(wifiConfiguration);
+        checkNotNull(suggestorPackageName);
 
         this.wifiConfiguration = wifiConfiguration;
         this.isAppInteractionRequired = isAppInteractionRequired;
         this.isUserInteractionRequired = isUserInteractionRequired;
         this.suggestorUid = suggestorUid;
+        this.suggestorPackageName = suggestorPackageName;
     }
 
     public static final Creator<WifiNetworkSuggestion> CREATOR =
@@ -79,7 +89,8 @@
                             in.readParcelable(null), // wifiConfiguration
                             in.readBoolean(), // isAppInteractionRequired
                             in.readBoolean(), // isUserInteractionRequired
-                            in.readInt() // suggestorUid
+                            in.readInt(), // suggestorUid
+                            in.readString() // suggestorPackageName
                     );
                 }
 
@@ -100,12 +111,13 @@
         dest.writeBoolean(isAppInteractionRequired);
         dest.writeBoolean(isUserInteractionRequired);
         dest.writeInt(suggestorUid);
+        dest.writeString(suggestorPackageName);
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.BSSID,
-                wifiConfiguration.allowedKeyManagement, suggestorUid);
+                wifiConfiguration.allowedKeyManagement, suggestorUid, suggestorPackageName);
     }
 
     /**
@@ -124,16 +136,19 @@
                 && Objects.equals(this.wifiConfiguration.BSSID, lhs.wifiConfiguration.BSSID)
                 && Objects.equals(this.wifiConfiguration.allowedKeyManagement,
                                   lhs.wifiConfiguration.allowedKeyManagement)
-                && suggestorUid == lhs.suggestorUid;
+                && suggestorUid == lhs.suggestorUid
+                && TextUtils.equals(suggestorPackageName, lhs.suggestorPackageName);
     }
 
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder("WifiNetworkSuggestion [")
-                .append(", WifiConfiguration=").append(wifiConfiguration)
+                .append(", SSID=").append(wifiConfiguration.SSID)
+                .append(", BSSID=").append(wifiConfiguration.BSSID)
                 .append(", isAppInteractionRequired=").append(isAppInteractionRequired)
                 .append(", isUserInteractionRequired=").append(isUserInteractionRequired)
                 .append(", suggestorUid=").append(suggestorUid)
+                .append(", suggestorPackageName=").append(suggestorPackageName)
                 .append("]");
         return sb.toString();
     }
diff --git a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.aidl b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.aidl
new file mode 100644
index 0000000..839af54
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+parcelable WifiUsabilityStatsEntry;
diff --git a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
new file mode 100644
index 0000000..c796e29
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class makes a subset of
+ * com.android.server.wifi.nano.WifiMetricsProto.WifiUsabilityStatsEntry parcelable.
+ *
+ * @hide
+ */
+@SystemApi
+public final class WifiUsabilityStatsEntry implements Parcelable {
+    /** Absolute milliseconds from device boot when these stats were sampled */
+    public final long timeStampMs;
+    /** The RSSI (in dBm) at the sample time */
+    public final int rssi;
+    /** Link speed at the sample time in Mbps */
+    public final int linkSpeedMbps;
+    /** The total number of tx success counted from the last radio chip reset */
+    public final long totalTxSuccess;
+    /** The total number of MPDU data packet retries counted from the last radio chip reset */
+    public final long totalTxRetries;
+    /** The total number of tx bad counted from the last radio chip reset */
+    public final long totalTxBad;
+    /** The total number of rx success counted from the last radio chip reset */
+    public final long totalRxSuccess;
+    /** The total time the wifi radio is on in ms counted from the last radio chip reset */
+    public final long totalRadioOnTimeMs;
+    /** The total time the wifi radio is doing tx in ms counted from the last radio chip reset */
+    public final long totalRadioTxTimeMs;
+    /** The total time the wifi radio is doing rx in ms counted from the last radio chip reset */
+    public final long totalRadioRxTimeMs;
+    /** The total time spent on all types of scans in ms counted from the last radio chip reset */
+    public final long totalScanTimeMs;
+    /** The total time spent on nan scans in ms counted from the last radio chip reset */
+    public final long totalNanScanTimeMs;
+    /** The total time spent on background scans in ms counted from the last radio chip reset */
+    public final long totalBackgroundScanTimeMs;
+    /** The total time spent on roam scans in ms counted from the last radio chip reset */
+    public final long totalRoamScanTimeMs;
+    /** The total time spent on pno scans in ms counted from the last radio chip reset */
+    public final long totalPnoScanTimeMs;
+    /** The total time spent on hotspot2.0 scans and GAS exchange in ms counted from the last radio
+     * chip reset */
+    public final long totalHotspot2ScanTimeMs;
+    /** The total time CCA is on busy status on the current frequency in ms counted from the last
+     * radio chip reset */
+    public final long totalCcaBusyFreqTimeMs;
+    /** The total radio on time of the current frequency from the last radio chip reset */
+    public final long totalRadioOnFreqTimeMs;
+    /** The total number of beacons received from the last radio chip reset */
+    public final long totalBeaconRx;
+
+    /** Constructor function {@hide} */
+    public WifiUsabilityStatsEntry(long timeStampMs, int rssi,
+            int linkSpeedMbps, long totalTxSuccess, long totalTxRetries,
+            long totalTxBad, long totalRxSuccess, long totalRadioOnTimeMs,
+            long totalRadioTxTimeMs, long totalRadioRxTimeMs, long totalScanTimeMs,
+            long totalNanScanTimeMs, long totalBackgroundScanTimeMs, long totalRoamScanTimeMs,
+            long totalPnoScanTimeMs, long totalHotspot2ScanTimeMs, long totalCcaBusyFreqTimeMs,
+            long totalRadioOnFreqTimeMs, long totalBeaconRx) {
+        this.timeStampMs = timeStampMs;
+        this.rssi = rssi;
+        this.linkSpeedMbps = linkSpeedMbps;
+        this.totalTxSuccess = totalTxSuccess;
+        this.totalTxRetries = totalTxRetries;
+        this.totalTxBad = totalTxBad;
+        this.totalRxSuccess = totalRxSuccess;
+        this.totalRadioOnTimeMs = totalRadioOnTimeMs;
+        this.totalRadioTxTimeMs = totalRadioTxTimeMs;
+        this.totalRadioRxTimeMs = totalRadioRxTimeMs;
+        this.totalScanTimeMs = totalScanTimeMs;
+        this.totalNanScanTimeMs = totalNanScanTimeMs;
+        this.totalBackgroundScanTimeMs = totalBackgroundScanTimeMs;
+        this.totalRoamScanTimeMs = totalRoamScanTimeMs;
+        this.totalPnoScanTimeMs = totalPnoScanTimeMs;
+        this.totalHotspot2ScanTimeMs = totalHotspot2ScanTimeMs;
+        this.totalCcaBusyFreqTimeMs = totalCcaBusyFreqTimeMs;
+        this.totalRadioOnFreqTimeMs = totalRadioOnFreqTimeMs;
+        this.totalBeaconRx = totalBeaconRx;
+    }
+
+    /** Implement the Parcelable interface */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(timeStampMs);
+        dest.writeInt(rssi);
+        dest.writeInt(linkSpeedMbps);
+        dest.writeLong(totalTxSuccess);
+        dest.writeLong(totalTxRetries);
+        dest.writeLong(totalTxBad);
+        dest.writeLong(totalRxSuccess);
+        dest.writeLong(totalRadioOnTimeMs);
+        dest.writeLong(totalRadioTxTimeMs);
+        dest.writeLong(totalRadioRxTimeMs);
+        dest.writeLong(totalScanTimeMs);
+        dest.writeLong(totalNanScanTimeMs);
+        dest.writeLong(totalBackgroundScanTimeMs);
+        dest.writeLong(totalRoamScanTimeMs);
+        dest.writeLong(totalPnoScanTimeMs);
+        dest.writeLong(totalHotspot2ScanTimeMs);
+        dest.writeLong(totalCcaBusyFreqTimeMs);
+        dest.writeLong(totalRadioOnFreqTimeMs);
+        dest.writeLong(totalBeaconRx);
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Creator<WifiUsabilityStatsEntry> CREATOR =
+            new Creator<WifiUsabilityStatsEntry>() {
+        public WifiUsabilityStatsEntry createFromParcel(Parcel in) {
+            return new WifiUsabilityStatsEntry(
+                    in.readLong(), in.readInt(),
+                    in.readInt(), in.readLong(), in.readLong(),
+                    in.readLong(), in.readLong(), in.readLong(),
+                    in.readLong(), in.readLong(), in.readLong(),
+                    in.readLong(), in.readLong(), in.readLong(),
+                    in.readLong(), in.readLong(), in.readLong(),
+                    in.readLong(), in.readLong()
+            );
+        }
+
+        public WifiUsabilityStatsEntry[] newArray(int size) {
+            return new WifiUsabilityStatsEntry[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/aware/PeerHandle.java b/wifi/java/android/net/wifi/aware/PeerHandle.java
index 8ae4b5a..1603d00 100644
--- a/wifi/java/android/net/wifi/aware/PeerHandle.java
+++ b/wifi/java/android/net/wifi/aware/PeerHandle.java
@@ -16,6 +16,9 @@
 
 package android.net.wifi.aware;
 
+import android.os.Parcel;
+import android.os.Parcelable;
+
 /**
  * Opaque object used to represent a Wi-Fi Aware peer. Obtained from discovery sessions in
  * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)} or
@@ -33,7 +36,7 @@
  * {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])}, or match filter,
  * {@link PublishConfig.Builder#setMatchFilter(java.util.List)}.
  */
-public class PeerHandle {
+public final class PeerHandle implements Parcelable {
     /** @hide */
     public PeerHandle(int peerId) {
         this.peerId = peerId;
@@ -59,4 +62,29 @@
     public int hashCode() {
         return peerId;
     }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(peerId);
+    }
+
+    public static final Creator<PeerHandle> CREATOR = new Creator<PeerHandle>() {
+        @Override
+        public PeerHandle[] newArray(int size) {
+            return new PeerHandle[size];
+        }
+
+        @Override
+        public PeerHandle createFromParcel(Parcel in) {
+            int peerHandle = in.readInt();
+
+            return new PeerHandle(peerHandle);
+        }
+    };
+
 }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
index 1426383..4bee837 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
@@ -149,6 +149,11 @@
                 "WifiAwareAgentNetworkSpecifier should not be used in network requests");
     }
 
+    @Override
+    public NetworkSpecifier redact() {
+        return null;
+    }
+
     private void initialize() {
         try {
             mDigester = MessageDigest.getInstance("SHA-256");
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 26a6c08..1fa1fd5 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -35,6 +35,7 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
+import android.text.TextUtils;
 import android.util.Log;
 
 import libcore.util.HexEncoding;
@@ -434,6 +435,8 @@
                 null, // peerMac (not used in this method)
                 pmk,
                 passphrase,
+                0, // no port info for deprecated IB APIs
+                -1, // no transport info for deprecated IB APIs
                 Process.myUid());
     }
 
@@ -473,6 +476,8 @@
                 peer,
                 pmk,
                 passphrase,
+                0, // no port info for OOB APIs
+                -1, // no transport protocol info for OOB APIs
                 Process.myUid());
     }
 
@@ -824,6 +829,8 @@
         private PeerHandle mPeerHandle;
         private String mPskPassphrase;
         private byte[] mPmk;
+        private int mPort = 0; // invalid value
+        private int mTransportProtocol = -1; // invalid value
 
         /**
          * Configure the {@link PublishDiscoverySession} or {@link SubscribeDiscoverySession}
@@ -902,6 +909,55 @@
         }
 
         /**
+         * Configure the port number which will be used to create a connection over this link. This
+         * configuration should only be done on the server device, e.g. the device creating the
+         * {@link java.net.ServerSocket}.
+         * <p>Notes:
+         * <ul>
+         *     <li>The server device must be the Publisher device!
+         *     <li>The port information can only be specified on secure links, specified using
+         *     {@link #setPskPassphrase(String)}.
+         * </ul>
+         *
+         * @param port A positive integer indicating the port to be used for communication.
+         * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
+         *         methods.
+         */
+        public @NonNull NetworkSpecifierBuilder setPort(int port) {
+            if (port <= 0 || port > 65535) {
+                throw new IllegalArgumentException("The port must be a positive value (0, 65535]");
+            }
+            mPort = port;
+            return this;
+        }
+
+        /**
+         * Configure the transport protocol which will be used to create a connection over this
+         * link. This configuration should only be done on the server device, e.g. the device
+         * creating the {@link java.net.ServerSocket} for TCP.
+         * <p>Notes:
+         * <ul>
+         *     <li>The server device must be the Publisher device!
+         *     <li>The transport protocol information can only be specified on secure links,
+         *     specified using {@link #setPskPassphrase(String)}.
+         * </ul>
+         * The transport protocol number is assigned by the Internet Assigned Numbers Authority
+         * (IANA) https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml.
+         *
+         * @param transportProtocol The transport protocol to be used for communication.
+         * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
+         *         methods.
+         */
+        public @NonNull NetworkSpecifierBuilder setTransportProtocol(int transportProtocol) {
+            if (transportProtocol < 0 || transportProtocol > 255) {
+                throw new IllegalArgumentException(
+                        "The transport protocol must be in range [0, 255]");
+            }
+            mTransportProtocol = transportProtocol;
+            return this;
+        }
+
+        /**
          * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)}
          * for a WiFi Aware connection (link) to the specified peer. The
          * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
@@ -929,6 +985,18 @@
                     ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
                     : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
 
+            if (mPort != 0 || mTransportProtocol != -1) {
+                if (role != WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
+                    throw new IllegalStateException(
+                            "Port and transport protocol information can only "
+                                    + "be specified on the Publisher device (which is the server");
+                }
+                if (TextUtils.isEmpty(mPskPassphrase) && mPmk == null) {
+                    throw new IllegalStateException("Port and transport protocol information can "
+                            + "only be specified on a secure link");
+                }
+            }
+
             if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR && mPeerHandle == null) {
                 throw new IllegalStateException("Null peerHandle!?");
             }
@@ -936,7 +1004,7 @@
             return new WifiAwareNetworkSpecifier(
                     WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, role,
                     mDiscoverySession.mClientId, mDiscoverySession.mSessionId, mPeerHandle.peerId,
-                    null, mPmk, mPskPassphrase, Process.myUid());
+                    null, mPmk, mPskPassphrase, mPort, mTransportProtocol, Process.myUid());
         }
     }
 }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
index 0f29e08..b258906 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
@@ -38,17 +38,30 @@
  * android.net.NetworkCapabilities)} callback.
  * <p>
  * The Wi-Fi Aware-specific network information include the peer's scoped link-local IPv6 address
- * for the Wi-Fi Aware link. The scoped link-local IPv6 can then be used to create a
+ * for the Wi-Fi Aware link, as well as (optionally) the port and transport protocol specified by
+ * the peer.
+ * The scoped link-local IPv6, port, and transport protocol can then be used to create a
  * {@link java.net.Socket} connection to the peer.
+ * <p>
+ * Note: these are the peer's IPv6 and port information - not the local device's!
  */
 public final class WifiAwareNetworkInfo implements TransportInfo, Parcelable {
     private Inet6Address mIpv6Addr;
+    private int mPort = 0; // a value of 0 is considered invalid
+    private int mTransportProtocol = -1; // a value of -1 is considered invalid
 
     /** @hide */
     public WifiAwareNetworkInfo(Inet6Address ipv6Addr) {
         mIpv6Addr = ipv6Addr;
     }
 
+    /** @hide */
+    public WifiAwareNetworkInfo(Inet6Address ipv6Addr, int port, int transportProtocol) {
+        mIpv6Addr = ipv6Addr;
+        mPort = port;
+        mTransportProtocol = transportProtocol;
+    }
+
     /**
      * Get the scoped link-local IPv6 address of the Wi-Fi Aware peer (not of the local device!).
      *
@@ -59,6 +72,34 @@
         return mIpv6Addr;
     }
 
+    /**
+     * Get the port number to be used to create a network connection to the Wi-Fi Aware peer.
+     * The port information is provided by the app running on the peer which requested the
+     * connection, using the {@link WifiAwareManager.NetworkSpecifierBuilder#setPort(int)}.
+     *
+     * @return A port number on the peer. A value of 0 indicates that no port was specified by the
+     *         peer.
+     */
+    public int getPort() {
+        return mPort;
+    }
+
+    /**
+     * Get the transport protocol to be used to communicate over a network connection to the Wi-Fi
+     * Aware peer. The transport protocol is provided by the app running on the peer which requested
+     * the connection, using the
+     * {@link WifiAwareManager.NetworkSpecifierBuilder#setTransportProtocol(int)}.
+     * <p>
+     * The transport protocol number is assigned by the Internet Assigned Numbers Authority
+     * (IANA) https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml.
+     *
+     * @return A transport protocol id. A value of -1 indicates that no transport protocol was
+     *         specified by the peer.
+     */
+    public int getTransportProtocol() {
+        return mTransportProtocol;
+    }
+
     // parcelable methods
 
     @Override
@@ -71,6 +112,8 @@
         dest.writeByteArray(mIpv6Addr.getAddress());
         NetworkInterface ni = mIpv6Addr.getScopedInterface();
         dest.writeString(ni == null ? null : ni.getName());
+        dest.writeInt(mPort);
+        dest.writeInt(mTransportProtocol);
     }
 
     public static final Creator<WifiAwareNetworkInfo> CREATOR =
@@ -94,8 +137,10 @@
                         e.printStackTrace();
                         return null;
                     }
+                    int port = in.readInt();
+                    int transportProtocol = in.readInt();
 
-                    return new WifiAwareNetworkInfo(ipv6Addr);
+                    return new WifiAwareNetworkInfo(ipv6Addr, port, transportProtocol);
                 }
 
                 @Override
@@ -109,7 +154,9 @@
 
     @Override
     public String toString() {
-        return new StringBuilder("AwareNetworkInfo: IPv6=").append(mIpv6Addr).toString();
+        return new StringBuilder("AwareNetworkInfo: IPv6=").append(mIpv6Addr).append(
+                ", port=").append(mPort).append(", transportProtocol=").append(
+                mTransportProtocol).toString();
     }
 
     /** @hide */
@@ -124,12 +171,13 @@
         }
 
         WifiAwareNetworkInfo lhs = (WifiAwareNetworkInfo) obj;
-        return Objects.equals(mIpv6Addr, lhs.mIpv6Addr);
+        return Objects.equals(mIpv6Addr, lhs.mIpv6Addr) && mPort == lhs.mPort
+                && mTransportProtocol == lhs.mTransportProtocol;
     }
 
     /** @hide */
     @Override
     public int hashCode() {
-        return Objects.hash(mIpv6Addr);
+        return Objects.hash(mIpv6Addr, mPort, mTransportProtocol);
     }
 }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
index 6e37fcf..a93a6d5 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
@@ -19,7 +19,6 @@
 import android.net.NetworkSpecifier;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Log;
 
 import java.util.Arrays;
 import java.util.Objects;
@@ -117,6 +116,32 @@
     public final String passphrase;
 
     /**
+     * The port information to be used for this link. This information will be communicated to the
+     * peer as part of the layer 2 link setup.
+     *
+     * Information only allowed on secure links since a single layer-2 link is set up for all
+     * requestors. Therefore if multiple apps on a single device request links to the same peer
+     * device they all get the same link. However, the link is only set up on the first request -
+     * hence only the first can transmit the port information. But we don't want to expose that
+     * information to other apps. Limiting to secure links would (usually) imply single app usage.
+     *
+     * @hide
+     */
+    public final int port;
+
+    /**
+     * The transport protocol information to be used for this link. This information will be
+     * communicated to the peer as part of the layer 2 link setup.
+     *
+     * Information only allowed on secure links since a single layer-2 link is set up for all
+     * requestors. Therefore if multiple apps on a single device request links to the same peer
+     * device they all get the same link. However, the link is only set up on the first request -
+     * hence only the first can transmit the port information. But we don't want to expose that
+     * information to other apps. Limiting to secure links would (usually) imply single app usage.
+     */
+    public final int transportProtocol;
+
+    /**
      * The UID of the process initializing this network specifier. Validated by receiver using
      * checkUidIfNecessary() and is used by satisfiedBy() to determine whether matches the
      * offered network.
@@ -127,7 +152,8 @@
 
     /** @hide */
     public WifiAwareNetworkSpecifier(int type, int role, int clientId, int sessionId, int peerId,
-            byte[] peerMac, byte[] pmk, String passphrase, int requestorUid) {
+            byte[] peerMac, byte[] pmk, String passphrase, int port, int transportProtocol,
+            int requestorUid) {
         this.type = type;
         this.role = role;
         this.clientId = clientId;
@@ -136,6 +162,8 @@
         this.peerMac = peerMac;
         this.pmk = pmk;
         this.passphrase = passphrase;
+        this.port = port;
+        this.transportProtocol = transportProtocol;
         this.requestorUid = requestorUid;
     }
 
@@ -152,6 +180,8 @@
                         in.createByteArray(), // peerMac
                         in.createByteArray(), // pmk
                         in.readString(), // passphrase
+                        in.readInt(), // port
+                        in.readInt(), // transportProtocol
                         in.readInt()); // requestorUid
                 }
 
@@ -186,6 +216,8 @@
         dest.writeByteArray(peerMac);
         dest.writeByteArray(pmk);
         dest.writeString(passphrase);
+        dest.writeInt(port);
+        dest.writeInt(transportProtocol);
         dest.writeInt(requestorUid);
     }
 
@@ -202,19 +234,8 @@
     /** @hide */
     @Override
     public int hashCode() {
-        int result = 17;
-
-        result = 31 * result + type;
-        result = 31 * result + role;
-        result = 31 * result + clientId;
-        result = 31 * result + sessionId;
-        result = 31 * result + peerId;
-        result = 31 * result + Arrays.hashCode(peerMac);
-        result = 31 * result + Arrays.hashCode(pmk);
-        result = 31 * result + Objects.hashCode(passphrase);
-        result = 31 * result + requestorUid;
-
-        return result;
+        return Objects.hash(type, role, clientId, sessionId, peerId, Arrays.hashCode(peerMac),
+                Arrays.hashCode(pmk), passphrase, port, transportProtocol, requestorUid);
     }
 
     /** @hide */
@@ -238,6 +259,8 @@
                 && Arrays.equals(peerMac, lhs.peerMac)
                 && Arrays.equals(pmk, lhs.pmk)
                 && Objects.equals(passphrase, lhs.passphrase)
+                && port == lhs.port
+                && transportProtocol == lhs.transportProtocol
                 && requestorUid == lhs.requestorUid;
     }
 
@@ -256,7 +279,8 @@
                 .append(", pmk=").append((pmk == null) ? "<null>" : "<non-null>")
                 // masking PII
                 .append(", passphrase=").append((passphrase == null) ? "<null>" : "<non-null>")
-                .append(", requestorUid=").append(requestorUid)
+                .append(", port=").append(port).append(", transportProtocol=")
+                .append(transportProtocol).append(", requestorUid=").append(requestorUid)
                 .append("]");
         return sb.toString();
     }
diff --git a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
index 6d82ca1..f91790f 100644
--- a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
+++ b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi.hotspot2;
 
+import android.annotation.SystemApi;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.net.wifi.WifiSsid;
@@ -36,16 +37,19 @@
  *
  * @hide
  */
+@SystemApi
 public final class OsuProvider implements Parcelable {
     /**
      * OSU (Online Sign-Up) method: OMA DM (Open Mobile Alliance Device Management).
      * For more info, refer to Section 8.3 of the Hotspot 2.0 Release 2 Technical Specification.
+     * @hide
      */
     public static final int METHOD_OMA_DM = 0;
 
     /**
      * OSU (Online Sign-Up) method: SOAP XML SPP (Subscription Provisioning Protocol).
      * For more info, refer to Section 8.4 of the Hotspot 2.0 Release 2 Technical Specification.
+     * @hide
      */
     public static final int METHOD_SOAP_XML_SPP = 1;
 
@@ -84,6 +88,7 @@
      */
     private final Icon mIcon;
 
+    /** @hide */
     public OsuProvider(WifiSsid osuSsid, Map<String, String> friendlyNames,
             String serviceDescription, Uri serverUri, String nai, List<Integer> methodList,
             Icon icon) {
@@ -104,6 +109,7 @@
      * Copy constructor.
      *
      * @param source The source to copy from
+     * @hide
      */
     public OsuProvider(OsuProvider source) {
         if (source == null) {
@@ -130,10 +136,12 @@
         mIcon = source.mIcon;
     }
 
+    /** @hide */
     public WifiSsid getOsuSsid() {
         return mOsuSsid;
     }
 
+    /** @hide */
     public void setOsuSsid(WifiSsid osuSsid) {
         mOsuSsid = osuSsid;
     }
@@ -162,10 +170,12 @@
         return mFriendlyNames.get(mFriendlyNames.keySet().stream().findFirst().get());
     }
 
+    /** @hide */
     public Map<String, String> getFriendlyNameList() {
         return mFriendlyNames;
     }
 
+    /** @hide */
     public String getServiceDescription() {
         return mServiceDescription;
     }
@@ -174,14 +184,17 @@
         return mServerUri;
     }
 
+    /** @hide */
     public String getNetworkAccessIdentifier() {
         return mNetworkAccessIdentifier;
     }
 
+    /** @hide */
     public List<Integer> getMethodList() {
         return mMethodList;
     }
 
+    /** @hide */
     public Icon getIcon() {
         return mIcon;
     }
diff --git a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
index a62d63c..1d499b6 100644
--- a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
+++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi.hotspot2;
 
+import android.annotation.SystemApi;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 
@@ -25,6 +26,7 @@
  *
  * @hide
  */
+@SystemApi
 public abstract class ProvisioningCallback {
 
     /**
@@ -63,9 +65,9 @@
     public static final int OSU_FAILURE_PROVISIONING_NOT_AVAILABLE = 7;
 
     /**
-     * The reason code for provisioning failure due to invalid server url.
+     * The reason code for provisioning failure due to invalid web url format for an OSU web page.
      */
-    public static final int OSU_FAILURE_INVALID_SERVER_URL = 8;
+    public static final int OSU_FAILURE_INVALID_URL_FORMAT_FOR_OSU = 8;
 
     /**
      * The reason code for provisioning failure when a command received is not the expected command
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 7689fc3..59a7290 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -572,7 +572,7 @@
 
         @Override
         public int hashCode() {
-            return Objects.hash(mCertType, mCertSha256Fingerprint);
+            return Objects.hash(mCertType, Arrays.hashCode(mCertSha256Fingerprint));
         }
 
         @Override
@@ -842,24 +842,50 @@
     }
 
     /**
-     * CA (Certificate Authority) X509 certificate.
+     * CA (Certificate Authority) X509 certificates.
      */
-    private X509Certificate mCaCertificate = null;
+    private X509Certificate[] mCaCertificates = null;
+
     /**
      * Set the CA (Certification Authority) certificate associated with this credential.
      *
      * @param caCertificate The CA certificate to set to
      */
     public void setCaCertificate(X509Certificate caCertificate) {
-        mCaCertificate = caCertificate;
+        mCaCertificates = null;
+        if (caCertificate != null) {
+            mCaCertificates = new X509Certificate[] {caCertificate};
+        }
     }
+
+    /**
+     * Set the CA (Certification Authority) certificates associated with this credential.
+     *
+     * @param caCertificates The list of CA certificates to set to
+     * @hide
+     */
+    public void setCaCertificates(X509Certificate[] caCertificates) {
+        mCaCertificates = caCertificates;
+    }
+
     /**
      * Get the CA (Certification Authority) certificate associated with this credential.
      *
-     * @return CA certificate associated with this credential
+     * @return CA certificate associated with this credential, {@code null} if certificate is not
+     * set or certificate is more than one.
      */
     public X509Certificate getCaCertificate() {
-        return mCaCertificate;
+        return mCaCertificates == null || mCaCertificates.length > 1 ? null : mCaCertificates[0];
+    }
+
+    /**
+     * Get the CA (Certification Authority) certificates associated with this credential.
+     *
+     * @return The list of CA certificates associated with this credential
+     * @hide
+     */
+    public X509Certificate[] getCaCertificates() {
+        return mCaCertificates;
     }
 
     /**
@@ -933,7 +959,11 @@
                 mClientCertificateChain = Arrays.copyOf(source.mClientCertificateChain,
                                                         source.mClientCertificateChain.length);
             }
-            mCaCertificate = source.mCaCertificate;
+            if (source.mCaCertificates != null) {
+                mCaCertificates = Arrays.copyOf(source.mCaCertificates,
+                        source.mCaCertificates.length);
+            }
+
             mClientPrivateKey = source.mClientPrivateKey;
         }
     }
@@ -952,7 +982,7 @@
         dest.writeParcelable(mUserCredential, flags);
         dest.writeParcelable(mCertCredential, flags);
         dest.writeParcelable(mSimCredential, flags);
-        ParcelUtil.writeCertificate(dest, mCaCertificate);
+        ParcelUtil.writeCertificates(dest, mCaCertificates);
         ParcelUtil.writeCertificates(dest, mClientCertificateChain);
         ParcelUtil.writePrivateKey(dest, mClientPrivateKey);
     }
@@ -977,16 +1007,17 @@
                     : mCertCredential.equals(that.mCertCredential))
                 && (mSimCredential == null ? that.mSimCredential == null
                     : mSimCredential.equals(that.mSimCredential))
-                && isX509CertificateEquals(mCaCertificate, that.mCaCertificate)
+                && isX509CertificatesEquals(mCaCertificates, that.mCaCertificates)
                 && isX509CertificatesEquals(mClientCertificateChain, that.mClientCertificateChain)
                 && isPrivateKeyEquals(mClientPrivateKey, that.mClientPrivateKey);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mRealm, mCreationTimeInMillis, mExpirationTimeInMillis,
+        return Objects.hash(mCreationTimeInMillis, mExpirationTimeInMillis, mRealm,
                 mCheckAaaServerCertStatus, mUserCredential, mCertCredential, mSimCredential,
-                mCaCertificate, mClientCertificateChain, mClientPrivateKey);
+                mClientPrivateKey, Arrays.hashCode(mCaCertificates),
+                Arrays.hashCode(mClientCertificateChain));
     }
 
     @Override
@@ -1067,7 +1098,7 @@
                 credential.setUserCredential(in.readParcelable(null));
                 credential.setCertCredential(in.readParcelable(null));
                 credential.setSimCredential(in.readParcelable(null));
-                credential.setCaCertificate(ParcelUtil.readCertificate(in));
+                credential.setCaCertificates(ParcelUtil.readCertificates(in));
                 credential.setClientCertificateChain(ParcelUtil.readCertificates(in));
                 credential.setClientPrivateKey(ParcelUtil.readPrivateKey(in));
                 return credential;
@@ -1100,7 +1131,7 @@
 
         // CA certificate is required for R1 Passpoint profile.
         // For R2, it is downloaded using cert URL provided in PPS MO after validation completes.
-        if (isR1 && mCaCertificate == null) {
+        if (isR1 && mCaCertificates == null) {
             Log.d(TAG, "Missing CA Certificate for user credential");
             return false;
         }
@@ -1131,7 +1162,7 @@
         // Verify required key and certificates for certificate credential.
         // CA certificate is required for R1 Passpoint profile.
         // For R2, it is downloaded using cert URL provided in PPS MO after validation completes.
-        if (isR1 && mCaCertificate == null) {
+        if (isR1 && mCaCertificates == null) {
             Log.d(TAG, "Missing CA Certificate for certificate credential");
             return false;
         }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index 6631fa8..f931ad2 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -223,7 +223,8 @@
         private MacAddress mDeviceAddress = MAC_ANY_ADDRESS;
         private String mNetworkName = "";
         private String mPassphrase = "";
-        private int mGroupOwnerBand = GROUP_OWNER_BAND_AUTO;
+        private int mGroupOperatingBand = GROUP_OWNER_BAND_AUTO;
+        private int mGroupOperatingFrequency = GROUP_OWNER_BAND_AUTO;
         private int mNetId = WifiP2pGroup.TEMPORARY_NET_ID;
 
         /**
@@ -285,22 +286,84 @@
         }
 
         /**
-         * Specify the band to use for creating the group. This method only applies when
-         * creating a group as Group Owner using {@link WifiP2pManager#createGroup}.
-         * The band should be {@link #GROUP_OWNER_BAND_2GHZ} or {@link #GROUP_OWNER_BAND_5GHZ},
-         * or allow the system to pick the band by specifying {@link #GROUP_OWNER_BAND_AUTO}.
+         * Specify the band to use for creating the group or joining the group. The band should
+         * be {@link #GROUP_OWNER_BAND_2GHZ}, {@link #GROUP_OWNER_BAND_5GHZ} or
+         * {@link #GROUP_OWNER_BAND_AUTO}.
+         * <p>
+         * When creating a group as Group Owner using {@link
+         * WifiP2pManager#createGroup(WifiP2pManager.Channel,
+         * WifiP2pConfig, WifiP2pManager.ActionListener)},
+         * specifying {@link #GROUP_OWNER_BAND_AUTO} allows the system to pick the operating
+         * frequency from all supported bands.
+         * Specifying {@link #GROUP_OWNER_BAND_2GHZ} or {@link #GROUP_OWNER_BAND_5GHZ}
+         * only allows the system to pick the operating frequency in the specified band.
          * If the Group Owner cannot create a group in the specified band, the operation will fail.
          * <p>
+         * When joining a group as Group Client using {@link
+         * WifiP2pManager#connect(WifiP2pManager.Channel, WifiP2pConfig,
+         * WifiP2pManager.ActionListener)},
+         * specifying {@link #GROUP_OWNER_BAND_AUTO} allows the system to scan all supported
+         * frequencies to find the desired group. Specifying {@link #GROUP_OWNER_BAND_2GHZ} or
+         * {@link #GROUP_OWNER_BAND_5GHZ} only allows the system to scan the specified band.
+         * <p>
+         *     {@link #setGroupOperatingBand(int)} and {@link #setGroupOperatingFrequency(int)} are
+         *     mutually exclusive. Setting operating band and frequency both is invalid.
+         * <p>
          *     Optional. {@link #GROUP_OWNER_BAND_AUTO} by default.
          *
-         * @param band the required band of group owner.
+         * @param band the operating band of the group.
          *             This should be one of {@link #GROUP_OWNER_BAND_AUTO},
          *             {@link #GROUP_OWNER_BAND_2GHZ}, {@link #GROUP_OWNER_BAND_5GHZ}.
          * @return The builder to facilitate chaining
          *         {@code builder.setXXX(..).setXXX(..)}.
          */
-        public Builder setGroupOwnerBand(int band) {
-            mGroupOwnerBand = band;
+        public Builder setGroupOperatingBand(@GroupOwnerBandType int band) {
+            switch (band) {
+                case GROUP_OWNER_BAND_AUTO:
+                case GROUP_OWNER_BAND_2GHZ:
+                case GROUP_OWNER_BAND_5GHZ:
+                    mGroupOperatingBand = band;
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                        "Invalid constant for the group operating band!");
+            }
+            return this;
+        }
+
+        /**
+         * Specify the frequency to use for creating the group or joining the group.
+         * <p>
+         * When creating a group as Group Owner using {@link WifiP2pManager#createGroup(
+         * WifiP2pManager.Channel, WifiP2pConfig, WifiP2pManager.ActionListener)},
+         * specifying a frequency only allows the system to pick the specified frequency.
+         * If the Group Owner cannot create a group at the specified frequency,
+         * the operation will fail.
+         * When not specifying a frequency, it allows the system to pick operating frequency
+         * from all supported bands.
+         * <p>
+         * When joining a group as Group Client using {@link WifiP2pManager#connect(
+         * WifiP2pManager.Channel, WifiP2pConfig, WifiP2pManager.ActionListener)},
+         * specifying a frequency only allows the system to scan the specified frequency.
+         * If the frequency is not supported or invalid, the operation will fail.
+         * When not specifying a frequency, it allows the system to scan all supported
+         * frequencies to find the desired group.
+         * <p>
+         *     {@link #setGroupOperatingBand(int)} and {@link #setGroupOperatingFrequency(int)} are
+         *     mutually exclusive. Setting operating band and frequency both is invalid.
+         * <p>
+         *     Optional. 0 by default.
+         *
+         * @param frequency the operating frequency of the group.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setGroupOperatingFrequency(int frequency) {
+            if (frequency < 0) {
+                throw new IllegalArgumentException(
+                    "Invalid group operating frequency!");
+            }
+            mGroupOperatingFrequency = frequency;
             return this;
         }
 
@@ -337,11 +400,21 @@
                         "passphrase must be non-empty.");
             }
 
+            if (mGroupOperatingFrequency > 0 && mGroupOperatingBand > 0) {
+                throw new IllegalStateException(
+                        "Preferred frequency and band are mutually exclusive.");
+            }
+
             WifiP2pConfig config = new WifiP2pConfig();
             config.deviceAddress = mDeviceAddress.toString();
             config.networkName = mNetworkName;
             config.passphrase = mPassphrase;
-            config.groupOwnerBand = mGroupOwnerBand;
+            config.groupOwnerBand = GROUP_OWNER_BAND_AUTO;
+            if (mGroupOperatingFrequency > 0) {
+                config.groupOwnerBand = mGroupOperatingFrequency;
+            } else if (mGroupOperatingBand > 0) {
+                config.groupOwnerBand = mGroupOperatingBand;
+            }
             config.netId = mNetId;
             return config;
         }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index 01feb1e..72e57a1 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -17,15 +17,15 @@
 package android.net.wifi.p2p;
 
 import android.annotation.UnsupportedAppUsage;
-import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.Parcelable;
 
 import java.util.ArrayList;
-import java.util.List;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.regex.Pattern;
+import java.util.List;
 import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * A class representing a Wi-Fi P2p group. A p2p group consists of a single group
@@ -67,6 +67,9 @@
     /** The network id in the wpa_supplicant */
     private int mNetId;
 
+    /** The frequency used by this group */
+    private int mFrequency;
+
     /** P2P group started string pattern */
     private static final Pattern groupStartedPattern = Pattern.compile(
         "ssid=\"(.+)\" " +
@@ -116,8 +119,9 @@
             }
 
             mNetworkName = match.group(1);
-            //freq and psk are unused right now
-            //int freq = Integer.parseInt(match.group(2));
+            // It throws NumberFormatException if the string cannot be parsed as an integer.
+            mFrequency = Integer.parseInt(match.group(2));
+            // psk is unused right now
             //String psk = match.group(3);
             mPassphrase = match.group(4);
             mOwner = new WifiP2pDevice(match.group(5));
@@ -269,6 +273,16 @@
         this.mNetId = netId;
     }
 
+    /** Get the operating frequency of the p2p group */
+    public int getFrequency() {
+        return mFrequency;
+    }
+
+    /** @hide */
+    public void setFrequency(int freq) {
+        this.mFrequency = freq;
+    }
+
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
         sbuf.append("network: ").append(mNetworkName);
@@ -279,6 +293,7 @@
         }
         sbuf.append("\n interface: ").append(mInterface);
         sbuf.append("\n networkId: ").append(mNetId);
+        sbuf.append("\n frequency: ").append(mFrequency);
         return sbuf.toString();
     }
 
@@ -297,6 +312,7 @@
             mPassphrase = source.getPassphrase();
             mInterface = source.getInterface();
             mNetId = source.getNetworkId();
+            mFrequency = source.getFrequency();
         }
     }
 
@@ -312,6 +328,7 @@
         dest.writeString(mPassphrase);
         dest.writeString(mInterface);
         dest.writeInt(mNetId);
+        dest.writeInt(mFrequency);
     }
 
     /** Implement the Parcelable interface */
@@ -329,6 +346,7 @@
                 group.setPassphrase(in.readString());
                 group.setInterface(in.readString());
                 group.setNetworkId(in.readInt());
+                group.setFrequency(in.readInt());
                 return group;
             }
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 068b959..1bed914 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1281,7 +1281,16 @@
         c.mAsyncChannel.sendMessage(REMOVE_GROUP, 0, c.putListener(listener));
     }
 
-    /** @hide */
+    /**
+     * Force p2p to enter or exit listen state
+     *
+     * @param c is the channel created at {@link #initialize(Context, Looper, ChannelListener)}
+     * @param enable enables or disables listening
+     * @param listener for callbacks on success or failure. Can be null.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public void listen(Channel c, boolean enable, ActionListener listener) {
         checkChannel(c);
         c.mAsyncChannel.sendMessage(enable ? START_LISTEN : STOP_LISTEN,
diff --git a/wifi/java/com/android/server/wifi/AbstractWifiService.java b/wifi/java/com/android/server/wifi/AbstractWifiService.java
deleted file mode 100644
index e94b9e6..0000000
--- a/wifi/java/com/android/server/wifi/AbstractWifiService.java
+++ /dev/null
@@ -1,467 +0,0 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License") {
- *  throw new UnsupportedOperationException();
- }
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.wifi;
-
-import android.content.pm.ParceledListSlice;
-import android.net.DhcpInfo;
-import android.net.Network;
-import android.net.wifi.INetworkRequestMatchCallback;
-import android.net.wifi.ISoftApCallback;
-import android.net.wifi.ITrafficStateCallback;
-import android.net.wifi.IWifiManager;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiActivityEnergyInfo;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiNetworkSuggestion;
-import android.net.wifi.hotspot2.IProvisioningCallback;
-import android.net.wifi.hotspot2.OsuProvider;
-import android.net.wifi.hotspot2.PasspointConfiguration;
-import android.os.IBinder;
-import android.os.Messenger;
-import android.os.ResultReceiver;
-import android.os.WorkSource;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * Abstract class implementing IWifiManager with stub methods throwing runtime exceptions.
- *
- * This class is meant to be extended by real implementations of IWifiManager in order to facilitate
- * cross-repo changes to WiFi internal APIs, including the introduction of new APIs, the removal of
- * deprecated APIs, or the migration of existing API signatures.
- *
- * When an existing API is scheduled for removal, it can be removed from IWifiManager.aidl
- * immediately and marked as @Deprecated first in this class. Children inheriting this class are
- * then given a short grace period to update themselves before the @Deprecated stub is removed for
- * good. If the API scheduled for removal has a replacement or an overload (signature change),
- * these should be introduced before the stub is removed to allow children to migrate.
- */
-public abstract class AbstractWifiService extends IWifiManager.Stub {
-
-    private static final String TAG = AbstractWifiService.class.getSimpleName();
-
-    @Override
-    public int getSupportedFeatures() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public WifiActivityEnergyInfo reportActivityInfo() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void requestActivityInfo(ResultReceiver result) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public ParceledListSlice getConfiguredNetworks(String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public ParceledListSlice getPrivilegedConfiguredNetworks() {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Returns a WifiConfiguration matching this ScanResult
-     * @param scanResult a single ScanResult Object
-     * @return
-     * @deprecated use {@link #getAllMatchingWifiConfigs(List)} instead.
-     */
-    @Deprecated
-    public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Returns all matching WifiConfigurations for this ScanResult.
-     * @param scanResult a single ScanResult Object
-     * @return
-     * @deprecated use {@link #getAllMatchingWifiConfigs(List)} instead.
-     */
-    @Deprecated
-    public List<WifiConfiguration> getAllMatchingWifiConfigs(ScanResult scanResult) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public List<WifiConfiguration> getAllMatchingWifiConfigs(List<ScanResult> scanResults) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Returns a list of Hotspot 2.0 OSU (Online Sign-Up) providers associated with the given AP.
-     *
-     * @param scanResult a single ScanResult Object
-     * @return
-     * @deprecated use {@link #getMatchingOsuProviders(List)} instead.
-     */
-    @Deprecated
-    public List<OsuProvider> getMatchingOsuProviders(ScanResult scanResult) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public List<OsuProvider> getMatchingOsuProviders(List<ScanResult> scanResults) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
-            List<OsuProvider> osuProviders) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public int addOrUpdateNetwork(WifiConfiguration config, String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean addOrUpdatePasspointConfiguration(
-            PasspointConfiguration config, String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean removePasspointConfiguration(String fqdn, String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public List<PasspointConfiguration> getPasspointConfigurations() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void queryPasspointIcon(long bssid, String fileName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public int matchProviderWithCurrentNetwork(String fqdn) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void deauthenticateNetwork(long holdoff, boolean ess) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean removeNetwork(int netId, String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean enableNetwork(int netId, boolean disableOthers, String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean disableNetwork(int netId, String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean startScan(String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public List<ScanResult> getScanResults(String callingPackage) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean disconnect(String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean reconnect(String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean reassociate(String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public WifiInfo getConnectionInfo(String callingPackage) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean setWifiEnabled(String packageName, boolean enable) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public int getWifiEnabledState() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void setCountryCode(String country) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String getCountryCode() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean isDualBandSupported() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean needs5GHzToAnyApBandConversion() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public DhcpInfo getDhcpInfo() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean isScanAlwaysAvailable() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean acquireWifiLock(IBinder lock, int lockType, String tag, WorkSource ws) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean releaseWifiLock(IBinder lock) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void initializeMulticastFiltering() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean isMulticastEnabled() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void acquireMulticastLock(IBinder binder, String tag) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void releaseMulticastLock(String tag) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void updateInterfaceIpState(String ifaceName, int mode) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean startSoftAp(WifiConfiguration wifiConfig) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean stopSoftAp() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public int startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void stopLocalOnlyHotspot() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void stopWatchLocalOnlyHotspot() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public int getWifiApEnabledState() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public WifiConfiguration getWifiApConfiguration() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void notifyUserOfApBandConversion(String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Messenger getWifiServiceMessenger(String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void enableTdls(String remoteIPAddress, boolean enable) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String getCurrentNetworkWpsNfcConfigurationToken() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void enableVerboseLogging(int verbose) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public int getVerboseLoggingLevel() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void enableWifiConnectivityManager(boolean enabled) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void disableEphemeralNetwork(String SSID, String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void factoryReset(String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Network getCurrentNetwork() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public byte[] retrieveBackupData() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void restoreBackupData(byte[] data) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void startSubscriptionProvisioning(
-            OsuProvider provider, IProvisioningCallback callback) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void registerSoftApCallback(
-            IBinder binder, ISoftApCallback callback, int callbackIdentifier) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void unregisterSoftApCallback(int callbackIdentifier) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void registerTrafficStateCallback(
-            IBinder binder, ITrafficStateCallback callback, int callbackIdentifier) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void unregisterTrafficStateCallback(int callbackIdentifier) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void registerNetworkRequestMatchCallback(
-            IBinder binder, INetworkRequestMatchCallback callback, int callbackIdentifier) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void unregisterNetworkRequestMatchCallback(int callbackIdentifier) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public int addNetworkSuggestions(
-            List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public int removeNetworkSuggestions(
-            List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public String[] getFactoryMacAddresses() {
-        throw new UnsupportedOperationException();
-    }
-}
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
new file mode 100644
index 0000000..226c7c48
--- /dev/null
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -0,0 +1,479 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License") {
+ *  throw new UnsupportedOperationException();
+ }
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.wifi;
+
+import android.content.pm.ParceledListSlice;
+import android.net.DhcpInfo;
+import android.net.Network;
+import android.net.wifi.IDppCallback;
+import android.net.wifi.INetworkRequestMatchCallback;
+import android.net.wifi.ISoftApCallback;
+import android.net.wifi.ITrafficStateCallback;
+import android.net.wifi.IWifiManager;
+import android.net.wifi.IWifiUsabilityStatsListener;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiActivityEnergyInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiNetworkSuggestion;
+import android.net.wifi.hotspot2.IProvisioningCallback;
+import android.net.wifi.hotspot2.OsuProvider;
+import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.os.IBinder;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.WorkSource;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Empty concrete class implementing IWifiManager with stub methods throwing runtime exceptions.
+ *
+ * This class is meant to be extended by real implementations of IWifiManager in order to facilitate
+ * cross-repo changes to WiFi internal APIs, including the introduction of new APIs, the removal of
+ * deprecated APIs, or the migration of existing API signatures.
+ *
+ * When an existing API is scheduled for removal, it can be removed from IWifiManager.aidl
+ * immediately and marked as @Deprecated first in this class. Children inheriting this class are
+ * then given a short grace period to update themselves before the @Deprecated stub is removed for
+ * good. If the API scheduled for removal has a replacement or an overload (signature change),
+ * these should be introduced before the stub is removed to allow children to migrate.
+ *
+ * When a new API is added to IWifiManager.aidl, a stub should be added in BaseWifiService as
+ * well otherwise compilation will fail.
+ */
+public class BaseWifiService extends IWifiManager.Stub {
+
+    private static final String TAG = BaseWifiService.class.getSimpleName();
+
+    @Override
+    public long getSupportedFeatures() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public WifiActivityEnergyInfo reportActivityInfo() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void requestActivityInfo(ResultReceiver result) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ParceledListSlice getConfiguredNetworks(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ParceledListSlice getPrivilegedConfiguredNetworks(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<String, Map<Integer, List<ScanResult>>> getAllMatchingFqdnsForScanResults(
+            List<ScanResult> scanResults) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
+            List<ScanResult> scanResults) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
+            List<OsuProvider> osuProviders) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int addOrUpdateNetwork(WifiConfiguration config, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean addOrUpdatePasspointConfiguration(
+            PasspointConfiguration config, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removePasspointConfiguration(String fqdn, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<PasspointConfiguration> getPasspointConfigurations() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<WifiConfiguration> getWifiConfigsForPasspointProfiles(List<String> fqdnList) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void queryPasspointIcon(long bssid, String fileName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int matchProviderWithCurrentNetwork(String fqdn) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void deauthenticateNetwork(long holdoff, boolean ess) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removeNetwork(int netId, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean enableNetwork(int netId, boolean disableOthers, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean disableNetwork(int netId, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean startScan(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<ScanResult> getScanResults(String callingPackage) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean disconnect(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean reconnect(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean reassociate(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public WifiInfo getConnectionInfo(String callingPackage) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean setWifiEnabled(String packageName, boolean enable) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getWifiEnabledState() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setCountryCode(String country) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCountryCode() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isDualBandSupported() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean needs5GHzToAnyApBandConversion() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DhcpInfo getDhcpInfo() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isScanAlwaysAvailable() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean acquireWifiLock(IBinder lock, int lockType, String tag, WorkSource ws) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean releaseWifiLock(IBinder lock) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void initializeMulticastFiltering() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isMulticastEnabled() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void acquireMulticastLock(IBinder binder, String tag) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void releaseMulticastLock(String tag) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void updateInterfaceIpState(String ifaceName, int mode) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean startSoftAp(WifiConfiguration wifiConfig) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean stopSoftAp() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void stopLocalOnlyHotspot() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void stopWatchLocalOnlyHotspot() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getWifiApEnabledState() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public WifiConfiguration getWifiApConfiguration() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void notifyUserOfApBandConversion(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Messenger getWifiServiceMessenger(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enableTdls(String remoteIPAddress, boolean enable) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCurrentNetworkWpsNfcConfigurationToken() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enableVerboseLogging(int verbose) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getVerboseLoggingLevel() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void enableWifiConnectivityManager(boolean enabled) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void disableEphemeralNetwork(String SSID, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void factoryReset(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Network getCurrentNetwork() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public byte[] retrieveBackupData() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void restoreBackupData(byte[] data) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void startSubscriptionProvisioning(
+            OsuProvider provider, IProvisioningCallback callback) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void registerSoftApCallback(
+            IBinder binder, ISoftApCallback callback, int callbackIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void unregisterSoftApCallback(int callbackIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void registerTrafficStateCallback(
+            IBinder binder, ITrafficStateCallback callback, int callbackIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void unregisterTrafficStateCallback(int callbackIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void registerNetworkRequestMatchCallback(
+            IBinder binder, INetworkRequestMatchCallback callback, int callbackIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void unregisterNetworkRequestMatchCallback(int callbackIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int addNetworkSuggestions(
+            List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int removeNetworkSuggestions(
+            List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String[] getFactoryMacAddresses() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setDeviceMobilityState(int state) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void startDppAsConfiguratorInitiator(IBinder binder, String enrolleeUri,
+            int selectedNetworkId, int netRole, IDppCallback callback) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void startDppAsEnrolleeInitiator(IBinder binder, String configuratorUri,
+            IDppCallback callback) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void stopDppSession() throws RemoteException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addWifiUsabilityStatsListener(
+            IBinder binder, IWifiUsabilityStatsListener listener, int listenerIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeWifiUsabilityStatsListener(int listenerIdentifier) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index c744f18..7bff68a 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -59,6 +59,7 @@
         WifiConfiguration config = new WifiConfiguration();
         config.setPasspointManagementObjectTree(cookie);
         config.trusted = false;
+        config.updateIdentifier = "1234";
         MacAddress macBeforeParcel = config.getOrCreateRandomizedMacAddress();
         Parcel parcelW = Parcel.obtain();
         config.writeToParcel(parcelW, 0);
@@ -73,6 +74,7 @@
         // lacking a useful config.equals, check two fields near the end.
         assertEquals(cookie, reconfig.getMoTree());
         assertEquals(macBeforeParcel, reconfig.getOrCreateRandomizedMacAddress());
+        assertEquals(config.updateIdentifier, reconfig.updateIdentifier);
         assertFalse(reconfig.trusted);
 
         Parcel parcelWW = Parcel.obtain();
@@ -251,6 +253,18 @@
     }
 
     /**
+     * Verifies that updateIdentifier should be copied for copy constructor.
+     */
+    @Test
+    public void testUpdateIdentifierForCopyConstructor() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.updateIdentifier = "1234";
+        WifiConfiguration copyConfig = new WifiConfiguration(config);
+
+        assertEquals(config.updateIdentifier, copyConfig.updateIdentifier);
+    }
+
+    /**
      * Verifies that the serialization/de-serialization for softap config works.
      */
     @Test
diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
index fb0af5f..677bf37 100644
--- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
@@ -47,6 +47,7 @@
         writeWifiInfo.txBad = TEST_TX_BAD;
         writeWifiInfo.rxSuccess = TEST_RX_SUCCESS;
         writeWifiInfo.setTrusted(true);
+        writeWifiInfo.setOsuAp(true);
 
         Parcel parcel = Parcel.obtain();
         writeWifiInfo.writeToParcel(parcel, 0);
@@ -60,5 +61,6 @@
         assertEquals(TEST_TX_BAD, readWifiInfo.txBad);
         assertEquals(TEST_RX_SUCCESS, readWifiInfo.rxSuccess);
         assertTrue(readWifiInfo.isTrusted());
+        assertTrue(readWifiInfo.isOsuAp());
     }
 }
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index c43948b..5c2f626 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -61,6 +61,7 @@
 import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
 import android.net.wifi.WifiManager.SoftApCallback;
 import android.net.wifi.WifiManager.TrafficStateCallback;
+import android.net.wifi.WifiManager.WifiUsabilityStatsListener;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -77,7 +78,10 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
 
 /**
  * Unit tests for {@link android.net.wifi.WifiManager}.
@@ -101,7 +105,9 @@
     @Mock SoftApCallback mSoftApCallback;
     @Mock TrafficStateCallback mTrafficStateCallback;
     @Mock NetworkRequestMatchCallback mNetworkRequestMatchCallback;
+    @Mock WifiUsabilityStatsListener mWifiUsabilityStatsListener;
 
+    private Executor mExecutor;
     private Handler mHandler;
     private TestLooper mLooper;
     private WifiManager mWifiManager;
@@ -1274,14 +1280,20 @@
     }
 
     /**
-     * Check the call to getAllMatchingWifiConfigs calls getAllMatchingWifiConfigs of WifiService
-     * with the provided a list of ScanResult.
+     * Check the call to getAllMatchingWifiConfigs calls getAllMatchingFqdnsForScanResults and
+     * getWifiConfigsForPasspointProfiles of WifiService in order.
      */
     @Test
     public void testGetAllMatchingWifiConfigs() throws Exception {
+        Map<String, List<ScanResult>> fqdns = new HashMap<>();
+        fqdns.put("www.test.com", new ArrayList<>());
+        when(mWifiService.getAllMatchingFqdnsForScanResults(any(List.class))).thenReturn(fqdns);
+        InOrder inOrder = inOrder(mWifiService);
+
         mWifiManager.getAllMatchingWifiConfigs(new ArrayList<>());
 
-        verify(mWifiService).getAllMatchingWifiConfigs(any(List.class));
+        inOrder.verify(mWifiService).getAllMatchingFqdnsForScanResults(any(List.class));
+        inOrder.verify(mWifiService).getWifiConfigsForPasspointProfiles(any(List.class));
     }
 
     /**
@@ -1334,4 +1346,40 @@
         assertArrayEquals(TEST_MAC_ADDRESSES, mWifiManager.getFactoryMacAddresses());
         verify(mWifiService).getFactoryMacAddresses();
     }
+
+    /**
+     * Verify the call to addWifiUsabilityStatsListener goes to WifiServiceImpl.
+     */
+    @Test
+    public void addWifiUsabilityStatsListeneroesToWifiServiceImpl() throws Exception {
+        mExecutor = new SynchronousExecutor();
+        mWifiManager.addWifiUsabilityStatsListener(mExecutor, mWifiUsabilityStatsListener);
+        verify(mWifiService).addWifiUsabilityStatsListener(any(IBinder.class),
+                any(IWifiUsabilityStatsListener.Stub.class), anyInt());
+    }
+
+    /**
+     * Verify the call to removeWifiUsabilityStatsListener goes to WifiServiceImpl.
+     */
+    @Test
+    public void removeWifiUsabilityListenerGoesToWifiServiceImpl() throws Exception {
+        ArgumentCaptor<Integer> listenerIdentifier = ArgumentCaptor.forClass(Integer.class);
+        mExecutor = new SynchronousExecutor();
+        mWifiManager.addWifiUsabilityStatsListener(mExecutor, mWifiUsabilityStatsListener);
+        verify(mWifiService).addWifiUsabilityStatsListener(any(IBinder.class),
+                any(IWifiUsabilityStatsListener.Stub.class), listenerIdentifier.capture());
+
+        mWifiManager.removeWifiUsabilityStatsListener(mWifiUsabilityStatsListener);
+        verify(mWifiService).removeWifiUsabilityStatsListener(
+                eq((int) listenerIdentifier.getValue()));
+    }
+
+    /**
+     * Defined for testing purpose.
+     */
+    class SynchronousExecutor implements Executor {
+        public void execute(Runnable r) {
+            r.run();
+        }
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
index 2258e4d..e6eece8 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
@@ -38,6 +38,8 @@
 public class WifiNetworkAgentSpecifierTest {
     private static final int TEST_UID = 5;
     private static final int TEST_UID_1 = 8;
+    private static final String TEST_PACKAGE = "com.test";
+    private static final String TEST_PACKAGE_1 = "com.test.1";
     private static final String TEST_SSID = "Test123";
     private static final String TEST_SSID_PATTERN = "Test";
     private static final String TEST_SSID_1 = "456test";
@@ -104,14 +106,14 @@
         WifiNetworkAgentSpecifier specifier1 =
                 new WifiNetworkAgentSpecifier(
                         wifiConfiguration1,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE);
 
         WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
         wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkAgentSpecifier specifier2 =
                 new WifiNetworkAgentSpecifier(
                         wifiConfiguration2,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE);
 
         assertFalse(specifier2.equals(specifier1));
     }
@@ -128,14 +130,14 @@
         WifiNetworkAgentSpecifier specifier1 =
                 new WifiNetworkAgentSpecifier(
                         wifiConfiguration1,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE);
 
         WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
         wifiConfiguration2.SSID = TEST_SSID_1;
         WifiNetworkAgentSpecifier specifier2 =
                 new WifiNetworkAgentSpecifier(
                         wifiConfiguration2,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE);
 
         assertFalse(specifier2.equals(specifier1));
     }
@@ -152,14 +154,14 @@
         WifiNetworkAgentSpecifier specifier1 =
                 new WifiNetworkAgentSpecifier(
                         wifiConfiguration1,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE);
 
         WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
         wifiConfiguration2.BSSID = TEST_BSSID_1;
         WifiNetworkAgentSpecifier specifier2 =
                 new WifiNetworkAgentSpecifier(
                         wifiConfiguration2,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE);
 
         assertFalse(specifier2.equals(specifier1));
     }
@@ -214,7 +216,7 @@
                 ssidPattern,
                 bssidPattern,
                 wificonfigurationNetworkSpecifier,
-                TEST_UID);
+                TEST_UID, TEST_PACKAGE);
 
         assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
         assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -243,7 +245,7 @@
                 ssidPattern,
                 bssidPattern,
                 wificonfigurationNetworkSpecifier,
-                TEST_UID);
+                TEST_UID, TEST_PACKAGE);
 
         assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
         assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -272,7 +274,7 @@
                 ssidPattern,
                 bssidPattern,
                 wificonfigurationNetworkSpecifier,
-                TEST_UID);
+                TEST_UID, TEST_PACKAGE);
 
         assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
         assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -292,7 +294,7 @@
         WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
                 new WifiNetworkAgentSpecifier(
                         wifiConfigurationNetworkAgent,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE);
 
         PatternMatcher ssidPattern =
                 new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
@@ -305,7 +307,7 @@
                 ssidPattern,
                 bssidPattern,
                 wificonfigurationNetworkSpecifier,
-                TEST_UID);
+                TEST_UID, TEST_PACKAGE);
 
         assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
         assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -325,7 +327,7 @@
         WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
                 new WifiNetworkAgentSpecifier(
                         wifiConfigurationNetworkAgent,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE);
 
         PatternMatcher ssidPattern =
                 new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB);
@@ -339,7 +341,7 @@
                 ssidPattern,
                 bssidPattern,
                 wificonfigurationNetworkSpecifier,
-                TEST_UID);
+                TEST_UID, TEST_PACKAGE);
 
         assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
         assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -359,7 +361,7 @@
         WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
                 new WifiNetworkAgentSpecifier(
                         wifiConfigurationNetworkAgent,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE);
 
         PatternMatcher ssidPattern =
                 new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
@@ -373,7 +375,7 @@
                 ssidPattern,
                 bssidPattern,
                 wificonfigurationNetworkSpecifier,
-                TEST_UID);
+                TEST_UID, TEST_PACKAGE);
 
         assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
         assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -401,7 +403,7 @@
                 ssidPattern,
                 bssidPattern,
                 wificonfigurationNetworkSpecifier,
-                TEST_UID);
+                TEST_UID, TEST_PACKAGE);
 
         assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
         assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -430,7 +432,7 @@
                 ssidPattern,
                 bssidPattern,
                 wificonfigurationNetworkSpecifier,
-                TEST_UID_1);
+                TEST_UID_1, TEST_PACKAGE_1);
 
         assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
         assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
@@ -446,7 +448,8 @@
     }
 
     private WifiNetworkAgentSpecifier createDefaultNetworkAgentSpecifier() {
-        return new WifiNetworkAgentSpecifier(createDefaultWifiConfiguration(), TEST_UID);
+        return new WifiNetworkAgentSpecifier(createDefaultWifiConfiguration(), TEST_UID,
+                TEST_PACKAGE);
     }
 
 }
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
index 83627ad..dd6e2c9 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
@@ -518,7 +518,7 @@
                 .get(WifiConfiguration.KeyMgmt.SUITE_B_192));
         assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
                 .get(WifiConfiguration.GroupCipher.GCMP_256));
-        assertTrue(suggestion.wifiConfiguration.allowedGroupMgmtCiphers
+        assertTrue(suggestion.wifiConfiguration.allowedGroupManagementCiphers
                 .get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256));
         assertTrue(suggestion.wifiConfiguration.allowedSuiteBCiphers
                 .get(WifiConfiguration.SuiteBCipher.ECDHE_ECDSA));
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
index 2a8df8d..fce247f 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -38,6 +38,7 @@
 @SmallTest
 public class WifiNetworkSpecifierTest {
     private static final int TEST_UID = 5;
+    private static final String TEST_PACKAGE_NAME = "com.test";
     private static final String TEST_SSID = "Test123";
     private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
     private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
@@ -56,7 +57,7 @@
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
                         wifiConfiguration,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE_NAME);
 
         Parcel parcelW = Parcel.obtain();
         specifier.writeToParcel(parcelW, 0);
@@ -88,7 +89,7 @@
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
                         wifiConfiguration,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE_NAME);
 
         assertTrue(specifier.satisfiedBy(null));
         assertTrue(specifier.satisfiedBy(new MatchAllNetworkSpecifier()));
@@ -111,14 +112,14 @@
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
                         wifiConfiguration,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE_NAME);
 
         WifiNetworkSpecifier specifier2 =
                 new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
                         wifiConfiguration,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE_NAME);
 
         assertTrue(specifier2.satisfiedBy(specifier1));
     }
@@ -140,7 +141,7 @@
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
                         wifiConfiguration1,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE_NAME);
 
         WifiConfiguration wifiConfiguration2 = new WifiConfiguration();
         wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
@@ -149,7 +150,7 @@
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
                         wifiConfiguration2,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE_NAME);
 
         assertFalse(specifier2.satisfiedBy(specifier1));
     }
@@ -171,14 +172,14 @@
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
                         wifiConfiguration,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE_NAME);
 
         WifiNetworkSpecifier specifier2 =
                 new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
                         wifiConfiguration,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE_NAME);
 
         assertFalse(specifier2.satisfiedBy(specifier1));
     }
@@ -200,13 +201,42 @@
                         Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                                 MacAddress.fromString(TEST_BSSID_OUI_MASK)),
                         wifiConfiguration,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE_NAME);
 
         WifiNetworkSpecifier specifier2 =
                 new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
                         Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS),
                         wifiConfiguration,
-                        TEST_UID);
+                        TEST_UID, TEST_PACKAGE_NAME);
+
+        assertFalse(specifier2.satisfiedBy(specifier1));
+    }
+
+    /**
+     * Validate NetworkSpecifier matching.
+     * a) Create network specifier 1 for WPA_PSK network
+     * b) Create network specifier 2 with different package name .
+     * c) Ensure that the specifier 2 is not satisfied by specifier 1.
+     */
+    @Test
+    public void testWifiNetworkSpecifierDoesNotSatisfyWhenPackageNameDifferent() {
+        WifiConfiguration wifiConfiguration = new WifiConfiguration();
+        wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+
+        WifiNetworkSpecifier specifier1 =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                                MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        wifiConfiguration,
+                        TEST_UID, TEST_PACKAGE_NAME);
+
+        WifiNetworkSpecifier specifier2 =
+                new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+                        Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+                                MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+                        wifiConfiguration,
+                        TEST_UID, TEST_PACKAGE_NAME + "blah");
 
         assertFalse(specifier2.satisfiedBy(specifier1));
     }
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 31f501f..5f76055 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -29,6 +29,10 @@
  */
 @SmallTest
 public class WifiNetworkSuggestionTest {
+    private static final int TEST_UID = 45677;
+    private static final int TEST_UID_OTHER = 45673;
+    private static final String TEST_PACKAGE_NAME = "com.test.packagename";
+    private static final String TEST_PACKAGE_NAME_OTHER = "com.test.packagenameother";
     private static final String TEST_SSID = "\"Test123\"";
     private static final String TEST_BSSID = "12:12:12:12:12:12";
     private static final String TEST_SSID_1 = "\"Test1234\"";
@@ -43,7 +47,7 @@
         configuration.BSSID = TEST_BSSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, false, true, 0);
+                new WifiNetworkSuggestion(configuration, false, true, TEST_UID, TEST_PACKAGE_NAME);
 
         Parcel parcelW = Parcel.obtain();
         suggestion.writeToParcel(parcelW, 0);
@@ -77,14 +81,16 @@
         configuration.BSSID = TEST_BSSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, true, false, 0);
+                new WifiNetworkSuggestion(configuration, true, false, TEST_UID,
+                        TEST_PACKAGE_NAME);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID;
         configuration1.BSSID = TEST_BSSID;
         configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, false, true, 0);
+                new WifiNetworkSuggestion(configuration1, false, true, TEST_UID,
+                        TEST_PACKAGE_NAME);
 
         assertEquals(suggestion, suggestion1);
     }
@@ -99,13 +105,15 @@
         configuration.SSID = TEST_SSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, false, false, 0);
+                new WifiNetworkSuggestion(configuration, false, false, TEST_UID,
+                        TEST_PACKAGE_NAME);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID_1;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, false, false, 0);
+                new WifiNetworkSuggestion(configuration1, false, false, TEST_UID,
+                        TEST_PACKAGE_NAME);
 
         assertNotEquals(suggestion, suggestion1);
     }
@@ -121,13 +129,15 @@
         configuration.BSSID = TEST_BSSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, false, false, 0);
+                new WifiNetworkSuggestion(configuration, false, false, TEST_UID,
+                        TEST_PACKAGE_NAME);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID;
         configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, false, false, 0);
+                new WifiNetworkSuggestion(configuration1, false, false, TEST_UID,
+                        TEST_PACKAGE_NAME);
 
         assertNotEquals(suggestion, suggestion1);
     }
@@ -142,13 +152,15 @@
         configuration.SSID = TEST_SSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, false, false, 0);
+                new WifiNetworkSuggestion(configuration, false, false, TEST_UID,
+                        TEST_PACKAGE_NAME);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID;
         configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, false, false, 0);
+                new WifiNetworkSuggestion(configuration1, false, false, TEST_UID,
+                        TEST_PACKAGE_NAME);
 
         assertNotEquals(suggestion, suggestion1);
     }
@@ -163,10 +175,31 @@
         configuration.SSID = TEST_SSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, false, false, 0);
+                new WifiNetworkSuggestion(configuration, false, false, TEST_UID,
+                        TEST_PACKAGE_NAME);
 
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration, false, false, 1);
+                new WifiNetworkSuggestion(configuration, false, false, TEST_UID_OTHER,
+                        TEST_PACKAGE_NAME);
+
+        assertNotEquals(suggestion, suggestion1);
+    }
+
+    /**
+     * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
+     * SSID, BSSID and key mgmt, but different package name.
+     */
+    @Test
+    public void testWifiNetworkSuggestionEqualsFailsWhenPackageNameIsDifferent() {
+        WifiConfiguration configuration = new WifiConfiguration();
+        configuration.SSID = TEST_SSID;
+        configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+        WifiNetworkSuggestion suggestion =
+                new WifiNetworkSuggestion(configuration, false, false, TEST_UID, TEST_PACKAGE_NAME);
+
+        WifiNetworkSuggestion suggestion1 =
+                new WifiNetworkSuggestion(configuration, false, false, TEST_UID,
+                        TEST_PACKAGE_NAME_OTHER);
 
         assertNotEquals(suggestion, suggestion1);
     }
diff --git a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
new file mode 100644
index 0000000..a947b55
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.validateMockitoUsage;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiUsabilityStatsEntry}.
+ */
+@SmallTest
+public class WifiUsabilityStatsEntryTest {
+
+    /**
+     * Setup before tests.
+     */
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    /**
+     * Clean up after tests.
+     */
+    @After
+    public void cleanup() {
+        validateMockitoUsage();
+    }
+
+    /**
+     * Verify parcel read/write for Wifi usability stats result.
+     */
+    @Test
+    public void verifyStatsResultWriteAndThenRead() throws Exception {
+        WifiUsabilityStatsEntry writeResult = createResult();
+        WifiUsabilityStatsEntry readResult = parcelWriteRead(writeResult);
+        assertWifiUsabilityStatsEntryEquals(writeResult, readResult);
+    }
+
+    /**
+     * Write the provided {@link WifiUsabilityStatsEntry} to a parcel and deserialize it.
+     */
+    private static WifiUsabilityStatsEntry parcelWriteRead(
+            WifiUsabilityStatsEntry writeResult) throws Exception {
+        Parcel parcel = Parcel.obtain();
+        writeResult.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
+        return WifiUsabilityStatsEntry.CREATOR.createFromParcel(parcel);
+    }
+
+    private static WifiUsabilityStatsEntry createResult() {
+        return new WifiUsabilityStatsEntry(
+                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18
+        );
+    }
+
+    private static void assertWifiUsabilityStatsEntryEquals(
+            WifiUsabilityStatsEntry expected,
+            WifiUsabilityStatsEntry actual) {
+        assertEquals(expected.timeStampMs, actual.timeStampMs);
+        assertEquals(expected.rssi, actual.rssi);
+        assertEquals(expected.linkSpeedMbps, actual.linkSpeedMbps);
+        assertEquals(expected.totalTxSuccess, actual.totalTxSuccess);
+        assertEquals(expected.totalTxRetries, actual.totalTxRetries);
+        assertEquals(expected.totalTxBad, actual.totalTxBad);
+        assertEquals(expected.totalRxSuccess, actual.totalRxSuccess);
+        assertEquals(expected.totalRadioOnTimeMs, actual.totalRadioOnTimeMs);
+        assertEquals(expected.totalRadioTxTimeMs, actual.totalRadioTxTimeMs);
+        assertEquals(expected.totalRadioRxTimeMs, actual.totalRadioRxTimeMs);
+        assertEquals(expected.totalScanTimeMs, actual.totalScanTimeMs);
+        assertEquals(expected.totalNanScanTimeMs, actual.totalNanScanTimeMs);
+        assertEquals(expected.totalBackgroundScanTimeMs, actual.totalBackgroundScanTimeMs);
+        assertEquals(expected.totalRoamScanTimeMs, actual.totalRoamScanTimeMs);
+        assertEquals(expected.totalPnoScanTimeMs, actual.totalPnoScanTimeMs);
+        assertEquals(expected.totalHotspot2ScanTimeMs, actual.totalHotspot2ScanTimeMs);
+        assertEquals(expected.totalCcaBusyFreqTimeMs, actual.totalCcaBusyFreqTimeMs);
+        assertEquals(expected.totalRadioOnFreqTimeMs, actual.totalRadioOnFreqTimeMs);
+        assertEquals(expected.totalBeaconRx, actual.totalBeaconRx);
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
index 4189e40..c3b6285 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
@@ -62,6 +62,7 @@
                 WifiAwareAgentNetworkSpecifier.CREATOR.createFromParcel(parcelR);
 
         assertEquals(dut, rereadDut);
+        assertEquals(dut.hashCode(), rereadDut.hashCode());
 
         // Ensure that individual network specifiers are satisfied by both the original & marshaled
         // |WifiAwareNetworkAgentSpecifier instances.
@@ -181,6 +182,6 @@
     WifiAwareNetworkSpecifier getDummyNetworkSpecifier(int clientId) {
         return new WifiAwareNetworkSpecifier(WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB,
                 WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, clientId, 0, 0, new byte[6],
-                null, null, 0);
+                null, null, 10, 5, 0);
     }
 }
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index e882b6b..6da6d4a 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -16,8 +16,11 @@
 
 package android.net.wifi.aware;
 
+import static android.net.wifi.aware.WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB;
+
 import static org.hamcrest.core.IsEqual.equalTo;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -913,9 +916,10 @@
         final int clientId = 4565;
         final int sessionId = 123;
         final PeerHandle peerHandle = new PeerHandle(123412);
-        final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
         final byte[] pmk = PMK_VALID;
         final String passphrase = PASSPHRASE_VALID;
+        final int port = 5;
+        final int transportProtocol = 10;
         final ConfigRequest configRequest = new ConfigRequest.Builder().build();
         final PublishConfig publishConfig = new PublishConfig.Builder().build();
 
@@ -959,56 +963,70 @@
                 .setPeerHandle(peerHandle).build();
 
         // validate format
-        collector.checkThat("role", role, equalTo(ns.role));
+        collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
+                equalTo(ns.role));
         collector.checkThat("client_id", clientId, equalTo(ns.clientId));
         collector.checkThat("session_id", sessionId, equalTo(ns.sessionId));
         collector.checkThat("peer_id", peerHandle.peerId, equalTo(ns.peerId));
 
-        collector.checkThat("role", role, equalTo(nsb.role));
+        collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
+                equalTo(nsb.role));
         collector.checkThat("client_id", clientId, equalTo(nsb.clientId));
         collector.checkThat("session_id", sessionId, equalTo(nsb.sessionId));
         collector.checkThat("peer_id", peerHandle.peerId, equalTo(nsb.peerId));
+        collector.checkThat("port", 0, equalTo(nsb.port));
+        collector.checkThat("transportProtocol", -1, equalTo(nsb.transportProtocol));
 
         // (4) request an encrypted (PMK) network specifier from the session
         ns = (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierPmk(
                 peerHandle, pmk);
-        nsb =
-                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
-                        .setDiscoverySession(
-                        publishSession.getValue()).setPeerHandle(peerHandle).setPmk(pmk).build();
+        nsb = (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+                .setDiscoverySession(publishSession.getValue()).setPeerHandle(peerHandle)
+                .setPmk(pmk).setPort(port).setTransportProtocol(transportProtocol).build();
 
         // validate format
-        collector.checkThat("role", role, equalTo(ns.role));
+        collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
+                equalTo(ns.role));
         collector.checkThat("client_id", clientId, equalTo(ns.clientId));
         collector.checkThat("session_id", sessionId, equalTo(ns.sessionId));
         collector.checkThat("peer_id", peerHandle.peerId, equalTo(ns.peerId));
         collector.checkThat("pmk", pmk , equalTo(ns.pmk));
 
-        collector.checkThat("role", role, equalTo(nsb.role));
+        collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
+                equalTo(nsb.role));
         collector.checkThat("client_id", clientId, equalTo(nsb.clientId));
         collector.checkThat("session_id", sessionId, equalTo(nsb.sessionId));
         collector.checkThat("peer_id", peerHandle.peerId, equalTo(nsb.peerId));
         collector.checkThat("pmk", pmk , equalTo(nsb.pmk));
+        collector.checkThat("port", port, equalTo(nsb.port));
+        collector.checkThat("transportProtocol", transportProtocol, equalTo(nsb.transportProtocol));
 
         // (5) request an encrypted (Passphrase) network specifier from the session
-        ns = (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierPassphrase(
-                peerHandle, passphrase);
+        ns =
+                (WifiAwareNetworkSpecifier) publishSession.getValue()
+                        .createNetworkSpecifierPassphrase(
+                        peerHandle, passphrase);
         nsb = (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
                 .setDiscoverySession(publishSession.getValue()).setPeerHandle(peerHandle)
-                .setPskPassphrase(passphrase).build();
+                .setPskPassphrase(passphrase).setPort(port).setTransportProtocol(transportProtocol)
+                .build();
 
         // validate format
-        collector.checkThat("role", role, equalTo(ns.role));
+        collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
+                equalTo(ns.role));
         collector.checkThat("client_id", clientId, equalTo(ns.clientId));
         collector.checkThat("session_id", sessionId, equalTo(ns.sessionId));
         collector.checkThat("peer_id", peerHandle.peerId, equalTo(ns.peerId));
         collector.checkThat("passphrase", passphrase, equalTo(ns.passphrase));
 
-        collector.checkThat("role", role, equalTo(nsb.role));
+        collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
+                equalTo(nsb.role));
         collector.checkThat("client_id", clientId, equalTo(nsb.clientId));
         collector.checkThat("session_id", sessionId, equalTo(nsb.sessionId));
         collector.checkThat("peer_id", peerHandle.peerId, equalTo(nsb.peerId));
         collector.checkThat("passphrase", passphrase, equalTo(nsb.passphrase));
+        collector.checkThat("port", port, equalTo(nsb.port));
+        collector.checkThat("transportProtocol", transportProtocol, equalTo(nsb.transportProtocol));
 
         verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
                 mockPublishSession, mockRttListener);
@@ -1325,6 +1343,140 @@
         executeNetworkSpecifierDirect(null, false, null, PASSPHRASE_VALID, false);
     }
 
+    /**
+     * Validate that get an exception when creating a network specifier with an invalid port number
+     * (<=0).
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testNetworkSpecifierBuilderInvalidPortNumber() throws Exception {
+        final PeerHandle peerHandle = new PeerHandle(123412);
+        final byte[] pmk = PMK_VALID;
+        final int port = 0;
+
+        DiscoverySession publishSession = executeSessionStartup(true);
+
+        WifiAwareNetworkSpecifier nsb =
+                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+                        .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
+                        .setPmk(pmk).setPort(port).build();
+    }
+
+    /**
+     * Validate that get an exception when creating a network specifier with port information
+     * without also requesting a secure link.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testNetworkSpecifierBuilderInvalidPortOnInsecure() throws Exception {
+        final PeerHandle peerHandle = new PeerHandle(123412);
+        final int port = 5;
+
+        DiscoverySession publishSession = executeSessionStartup(true);
+
+        WifiAwareNetworkSpecifier nsb =
+                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+                        .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
+                        .setPort(port).build();
+    }
+
+    /**
+     * Validate that get an exception when creating a network specifier with port information on
+     * a responder.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testNetworkSpecifierBuilderInvalidPortOnResponder() throws Exception {
+        final PeerHandle peerHandle = new PeerHandle(123412);
+        final int port = 5;
+
+        DiscoverySession subscribeSession = executeSessionStartup(false);
+
+        WifiAwareNetworkSpecifier nsb =
+                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+                        .setDiscoverySession(subscribeSession).setPeerHandle(peerHandle)
+                        .setPort(port).build();
+    }
+
+    /**
+     * Validate that get an exception when creating a network specifier with an invalid transport
+     * protocol number (not in [0, 255]).
+     */
+    @Test
+    public void testNetworkSpecifierBuilderInvalidTransportProtocolNumber() throws Exception {
+        final PeerHandle peerHandle = new PeerHandle(123412);
+        final byte[] pmk = PMK_VALID;
+        final int tpNegative = -1;
+        final int tpTooLarge = 256;
+        final int tpSmallest = 0;
+        final int tpLargest = 255;
+
+        DiscoverySession publishSession = executeSessionStartup(true);
+
+        try {
+            WifiAwareNetworkSpecifier nsb =
+                    (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+                            .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
+                            .setPmk(pmk).setTransportProtocol(tpNegative).build();
+            assertTrue("No exception on negative transport protocol!", false);
+        } catch (IllegalArgumentException e) {
+            // nop - exception is correct!
+        }
+        try {
+            WifiAwareNetworkSpecifier nsb =
+                    (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+                            .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
+                            .setPmk(pmk).setTransportProtocol(tpTooLarge).build();
+            assertTrue("No exception on >255 transport protocol!", false);
+        } catch (IllegalArgumentException e) {
+            // nop - exception is correct!
+        }
+        WifiAwareNetworkSpecifier nsb =
+                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+                        .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
+                        .setPmk(pmk).setTransportProtocol(tpSmallest).build();
+        nsb =
+                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+                        .setDiscoverySession(
+                                publishSession).setPeerHandle(peerHandle).setPmk(
+                        pmk).setTransportProtocol(tpLargest).build();
+    }
+
+    /**
+     * Validate that get an exception when creating a network specifier with transport protocol
+     * information without also requesting a secure link.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testNetworkSpecifierBuilderInvalidTransportProtocolOnInsecure() throws Exception {
+        final PeerHandle peerHandle = new PeerHandle(123412);
+        final int transportProtocol = 5;
+
+        DiscoverySession publishSession = executeSessionStartup(true);
+
+        WifiAwareNetworkSpecifier nsb =
+                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+                        .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
+                        .setTransportProtocol(transportProtocol).build();
+    }
+
+    /**
+     * Validate that get an exception when creating a network specifier with transport protocol
+     * information on a responder.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testNetworkSpecifierBuilderInvalidTransportProtocolOnResponder() throws Exception {
+        final PeerHandle peerHandle = new PeerHandle(123412);
+        final int transportProtocol = 5;
+
+        DiscoverySession subscribeSession = executeSessionStartup(false);
+
+        WifiAwareNetworkSpecifier nsb =
+                (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+                        .setDiscoverySession(subscribeSession).setPeerHandle(peerHandle)
+                        .setTransportProtocol(transportProtocol).build();
+    }
+
+    /*
+     * Utilities
+     */
+
     private void executeNetworkSpecifierDirect(byte[] someMac, boolean doPmk, byte[] pmk,
             String passphrase, boolean doInitiator) throws Exception {
         final int clientId = 134;
@@ -1356,7 +1508,83 @@
         }
     }
 
-    // WifiAwareNetworkInfo tests
+    private DiscoverySession executeSessionStartup(boolean isPublish) throws Exception {
+        final int clientId = 4565;
+        final int sessionId = 123;
+        final PeerHandle peerHandle = new PeerHandle(123412);
+        final int port = 5;
+        final ConfigRequest configRequest = new ConfigRequest.Builder().build();
+        final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
+        final PublishConfig publishConfig = new PublishConfig.Builder().build();
+
+        ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
+                WifiAwareSession.class);
+        ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareEventCallback.class);
+        ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
+                .forClass(IWifiAwareDiscoverySessionCallback.class);
+        ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+                .forClass(PublishDiscoverySession.class);
+        ArgumentCaptor<SubscribeDiscoverySession> subscribeSession = ArgumentCaptor
+                .forClass(SubscribeDiscoverySession.class);
+
+
+        InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
+                mockPublishSession, mockRttListener);
+
+        // (1) connect successfully
+        mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
+        clientProxyCallback.getValue().onConnectSuccess(clientId);
+        mMockLooper.dispatchAll();
+        inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
+        WifiAwareSession session = sessionCaptor.getValue();
+
+        if (isPublish) {
+            // (2) publish successfully
+            session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
+            inOrder.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig),
+                    sessionProxyCallback.capture());
+            sessionProxyCallback.getValue().onSessionStarted(sessionId);
+            mMockLooper.dispatchAll();
+            inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
+            return publishSession.getValue();
+        } else {
+            // (2) subscribe successfully
+            session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
+            inOrder.verify(mockAwareService).subscribe(any(), eq(clientId), eq(subscribeConfig),
+                    sessionProxyCallback.capture());
+            sessionProxyCallback.getValue().onSessionStarted(sessionId);
+            mMockLooper.dispatchAll();
+            inOrder.verify(mockSessionCallback).onSubscribeStarted(subscribeSession.capture());
+            return subscribeSession.getValue();
+        }
+    }
+
+    // WifiAwareNetworkSpecifier && WifiAwareNetworkInfo tests
+
+    @Test
+    public void testWifiAwareNetworkSpecifierParcel() {
+        WifiAwareNetworkSpecifier ns = new WifiAwareNetworkSpecifier(NETWORK_SPECIFIER_TYPE_IB,
+                WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER, 5, 568, 334,
+                HexEncoding.decode("000102030405".toCharArray(), false),
+                "01234567890123456789012345678901".getBytes(), "blah blah", 666, 4, 10001);
+
+        Parcel parcelW = Parcel.obtain();
+        ns.writeToParcel(parcelW, 0);
+        byte[] bytes = parcelW.marshall();
+        parcelW.recycle();
+
+        Parcel parcelR = Parcel.obtain();
+        parcelR.unmarshall(bytes, 0, bytes.length);
+        parcelR.setDataPosition(0);
+        WifiAwareNetworkSpecifier rereadNs =
+                WifiAwareNetworkSpecifier.CREATOR.createFromParcel(parcelR);
+
+        assertEquals(ns, rereadNs);
+        assertEquals(ns.hashCode(), rereadNs.hashCode());
+    }
 
     @Test
     public void testWifiAwareNetworkCapabilitiesParcel() throws UnknownHostException {
@@ -1364,9 +1592,11 @@
                 "11:22:33:44:55:66").getLinkLocalIpv6FromEui48Mac();
         // note: dummy scope = 5
         final Inet6Address inet6Scoped = Inet6Address.getByAddress(null, inet6.getAddress(), 5);
+        final int port = 5;
+        final int transportProtocol = 6;
 
         assertEquals(inet6Scoped.toString(), "/fe80::1322:33ff:fe44:5566%5");
-        WifiAwareNetworkInfo cap = new WifiAwareNetworkInfo(inet6Scoped);
+        WifiAwareNetworkInfo cap = new WifiAwareNetworkInfo(inet6Scoped, port, transportProtocol);
 
         Parcel parcelW = Parcel.obtain();
         cap.writeToParcel(parcelW, 0);
@@ -1380,6 +1610,27 @@
                 WifiAwareNetworkInfo.CREATOR.createFromParcel(parcelR);
 
         assertEquals(cap.getPeerIpv6Addr().toString(), "/fe80::1322:33ff:fe44:5566%5");
+        assertEquals(cap, rereadCap);
         assertEquals(cap.hashCode(), rereadCap.hashCode());
     }
+
+    // PeerHandle tests
+
+    @Test
+    public void testPeerHandleParcel() {
+        final PeerHandle peerHandle = new PeerHandle(5);
+
+        Parcel parcelW = Parcel.obtain();
+        peerHandle.writeToParcel(parcelW, 0);
+        byte[] bytes = parcelW.marshall();
+        parcelW.recycle();
+
+        Parcel parcelR = Parcel.obtain();
+        parcelR.unmarshall(bytes, 0, bytes.length);
+        parcelR.setDataPosition(0);
+        PeerHandle rereadPeerHandle = PeerHandle.CREATOR.createFromParcel(parcelR);
+
+        assertEquals(peerHandle, rereadPeerHandle);
+        assertEquals(peerHandle.hashCode(), rereadPeerHandle.hashCode());
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index a9d4b8f..1ecc3fe 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi.hotspot2.pps;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
@@ -44,17 +45,16 @@
      * @param userCred Instance of UserCredential
      * @param certCred Instance of CertificateCredential
      * @param simCred Instance of SimCredential
-     * @param caCert CA certificate
      * @param clientCertificateChain Chain of client certificates
      * @param clientPrivateKey Client private key
+     * @param caCerts CA certificates
      * @return {@link Credential}
      */
     private static Credential createCredential(Credential.UserCredential userCred,
-                                               Credential.CertificateCredential certCred,
-                                               Credential.SimCredential simCred,
-                                               X509Certificate caCert,
-                                               X509Certificate[] clientCertificateChain,
-                                               PrivateKey clientPrivateKey) {
+            Credential.CertificateCredential certCred,
+            Credential.SimCredential simCred,
+            X509Certificate[] clientCertificateChain, PrivateKey clientPrivateKey,
+            X509Certificate... caCerts) {
         Credential cred = new Credential();
         cred.setCreationTimeInMillis(123455L);
         cred.setExpirationTimeInMillis(2310093L);
@@ -63,7 +63,11 @@
         cred.setUserCredential(userCred);
         cred.setCertCredential(certCred);
         cred.setSimCredential(simCred);
-        cred.setCaCertificate(caCert);
+        if (caCerts != null && caCerts.length == 1) {
+            cred.setCaCertificate(caCerts[0]);
+        } else {
+            cred.setCaCertificates(caCerts);
+        }
         cred.setClientCertificateChain(clientCertificateChain);
         cred.setClientPrivateKey(clientPrivateKey);
         return cred;
@@ -80,8 +84,8 @@
         certCred.setCertType("x509v3");
         certCred.setCertSha256Fingerprint(
                 MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded()));
-        return createCredential(null, certCred, null, FakeKeys.CA_CERT0,
-                new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1);
+        return createCredential(null, certCred, null, new X509Certificate[] {FakeKeys.CLIENT_CERT},
+                FakeKeys.RSA_KEY1, FakeKeys.CA_CERT0, FakeKeys.CA_CERT1);
     }
 
     /**
@@ -93,7 +97,7 @@
         Credential.SimCredential simCred = new Credential.SimCredential();
         simCred.setImsi("1234*");
         simCred.setEapType(EAPConstants.EAP_SIM);
-        return createCredential(null, null, simCred, null, null, null);
+        return createCredential(null, null, simCred, null, null, (X509Certificate[]) null);
     }
 
     /**
@@ -110,7 +114,7 @@
         userCred.setSoftTokenApp("TestApp");
         userCred.setEapType(EAPConstants.EAP_TTLS);
         userCred.setNonEapInnerMethod("MS-CHAP");
-        return createCredential(userCred, null, null, FakeKeys.CA_CERT0, null, null);
+        return createCredential(userCred, null, null, null, null, FakeKeys.CA_CERT0);
     }
 
     private static void verifyParcel(Credential writeCred) {
@@ -120,6 +124,7 @@
         parcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
         Credential readCred = Credential.CREATOR.createFromParcel(parcel);
         assertTrue(readCred.equals(writeCred));
+        assertEquals(writeCred.hashCode(), readCred.hashCode());
     }
 
     /**